[
  {
    "path": ".gitattributes",
    "content": "*.pdf binary\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/bug_report.yml",
    "content": "name: Bug Report\ndescription: Create a bug report for PyMuPDF\n\n# We omit `title: \"...\"` so that the field defaults to blank. If we set it to\n# empty string, Github seems to reject this .yml file.\n\nbody:\n\n  - type: textarea\n    id: description\n    attributes:\n      label: Description of the bug\n      description: |\n        A clear and concise description of the bug.\n        \n    validations:\n      required: true\n  \n  - type: textarea\n    id: reproduce\n    attributes:\n      label: How to reproduce the bug\n      \n      # Should not word-wrap this description here.\n      description: |\n        * Explain the steps required to reproduce the bug.\n        * Include required code snippets, example files, etc.\n        * Describe what you expected to happen (if not obvious).\n        * If applicable, add screenshots to help explain the problem.\n        * Include any other information that could be relevant, for example information about the Python environment.\n        \n        For problems when building or installing PyMuPDF:\n        * Give the **exact** build/install commands that were run.\n        * Give the **complete** output from these commands.\n  \n    validations:\n      required: true\n\n#  - type: markdown\n#    attributes:\n#      value: |\n#        # The information below is required.\n    \n  - type: dropdown\n    id: version\n    attributes:\n      label: PyMuPDF version\n      options:\n        - 1.27.2.3\n        - 1.27.2.2\n        - 1.27.2\n        - 1.27.1\n        - 1.27.0\n        - 1.26.x or earlier\n        - Built from source\n      description: |\n        * For example from `pymupdf.pymupdf_version`.\n        * We generally only look at bugs in the most recent release of PyMuPDF.\n    validations:\n      required: true\n\n  - type: dropdown\n    id: os_name\n    attributes:\n      label: Operating system\n      #multiple: true\n      options:\n        -\n        - Windows\n        - Linux\n        - MacOS\n        - OpenBSD\n        - Other\n    validations:\n      required: true\n\n  - type: dropdown\n    id: python_version\n    attributes:\n      label: Python version\n      #multiple: true\n      # Need quotes around `3.10` otherwise it is treated as a number and shows as `3.1`.\n      options:\n        -\n        - \"3.14\"\n        - \"3.13\"\n        - \"3.12\"\n        - \"3.11\"\n        - \"3.10\"\n        - \"3.9\"\n    validations:\n      required: true\n"
  },
  {
    "path": ".github/ISSUE_TEMPLATE/feature_request.md",
    "content": "---\nname: Feature request\nabout: Suggest an idea for this project\ntitle: ''\nlabels: enhancement\nassignees:\n\n---\n\n**Is your feature request related to a problem? Please describe.**\nA clear and concise description of what the problem is. Potentially add an issue reference.\n\n**Describe the solution you'd like**\nA clear and concise description of what you want to happen.\n\n**Describe alternatives you've considered**\nAre there several options for how your request could be met?\n\n**Additional context**\nAdd any other context or screenshots about the feature request here.\n"
  },
  {
    "path": ".github/workflows/build_wheels.yml",
    "content": "name: Build wheels\n\non:\n  workflow_dispatch:\n    inputs:\n      \n      flavours:\n        description: 'If set, we build separate PyMuPDF and PyMuPDFb wheels.'\n        type: boolean\n        default: false\n      \n      sdist:\n        type: boolean\n        default: true\n    \n      wheels_linux_aarch64:\n        type: boolean\n        default: true\n      \n      wheels_linux_auto:\n        type: boolean\n        default: true\n      \n      wheels_linux_pyodide:\n        type: boolean\n        default: false\n      \n      wheels_windows_auto:\n        type: boolean\n        default: true\n        \n      wheels_macos_auto:\n        type: boolean\n        default: true\n      \n      wheels_cps:\n        description: 'wheels_cps: sets $CIBW_BUILD, E.g. \"cp310* cp311*\".'\n        type: string\n    \n      PYMUPDF_SETUP_MUPDF_BUILD:\n        description: 'Value for PYMUPDF_SETUP_MUPDF_BUILD, e.g.: git:--branch master https://github.com/ArtifexSoftware/mupdf.git'\n        type: string\n        default: '-'\n      \n      #PYMUPDF_SETUP_MUPDF_BUILD_TYPE:\n      #  description: 'Value for PYMUPDF_SETUP_MUPDF_BUILD, e.g. debug.'\n      #  type: string\n      #  default: '-'\n      # We can't currently have more than 10 inputs\n      \n      PYMUPDF_SETUP_PY_LIMITED_API:\n        description: 'If not \"0\", we build a single wheel for each platform.'\n        type: string\n        default: ''\n\njobs:\n\n  build_sdist:\n    if: ${{ inputs.sdist }}\n    name: Build sdist\n    runs-on: ubuntu-latest\n    \n    steps:\n    - uses: actions/checkout@v4\n\n    - name: Build sdist\n      env:\n            inputs_wheels_default: 0\n            inputs_sdist: 1\n            inputs_flavours: ${{inputs.flavours}}\n            inputs_PYMUPDF_SETUP_MUPDF_BUILD: ${{inputs.PYMUPDF_SETUP_MUPDF_BUILD}}\n      run:\n        python scripts/gh_release.py\n\n    - uses: actions/upload-artifact@v4\n      with:\n        name: sdist-${{ matrix.os }}\n        path: dist/*.tar.gz    \n\n\n  build_wheels:\n    #if: ${{ inputs.wheels }}\n    name: Build wheels on ${{ matrix.os }}\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        # 2024-05-08: Need to specify macos-15-intel/14 to get x86_64/arm64.\n        os: [ubuntu-latest, windows-2019, macos-15-intel, macos-14]\n\n      # Avoid cancelling of all cibuildwheel runs after a single failure.\n      fail-fast: false\n    \n    steps:\n\n      - uses: actions/checkout@v4\n\n      # Get Python 3.12 x32 and x64 on Windows. (As of 2023-10-12 these are not\n      # always available by default.)\n      #\n      - name: Install Python 3.12 x32 on Windows.\n        if: runner.os == 'Windows'\n        uses: actions/setup-python@v5\n        with:\n          python-version: '3.12'\n          architecture: x86\n      - name: Install Python 3.12 x64 on Windows.\n        if: runner.os == 'Windows'\n        uses: actions/setup-python@v5\n        with:\n          python-version: '3.12'\n\n      # Get Python for running cibuildwheel. This also ensures that 'python'\n      # works on MacOS, where it seems only 'python3' is available by default.\n      #\n      # Note that it seem to be important on MacOS not to specify a\n      # Python version here with `python-version: '3.12'` - this makes\n      # `python-config3` return settings for Python-3.12, instead of for\n      # whatever Python is being used by cibuildwheel.\n      #\n      - uses: actions/setup-python@v5\n\n      # On Linux, get qemu so we can build for aarch64.\n      #\n      - name: Set up QEMU\n        if: runner.os == 'Linux'\n        uses: docker/setup-qemu-action@v1\n        with:\n          platforms: all\n\n      - name: gh_release\n        # Doesn't seem to be a way to passing inputs.* on command\n        # line, so we set environment instead.  E.g. see:\n        # https://github.com/orgs/community/discussions/27088\n        #\n        env:\n            inputs_flavours: ${{inputs.flavours}}\n            inputs_sdist: ${{inputs.sdist}}\n            \n            inputs_wheels_linux_aarch64: ${{inputs.wheels_linux_aarch64}}\n            inputs_wheels_linux_auto: ${{inputs.wheels_linux_auto}}\n            inputs_wheels_linux_pyodide: ${{inputs.wheels_linux_pyodide}}\n            #inputs_wheels_macos_arm64: ${{inputs.wheels_macos_arm64}}\n            inputs_wheels_macos_auto: ${{inputs.wheels_macos_auto}}\n            inputs_wheels_windows_auto: ${{inputs.wheels_windows_auto}}\n            \n            inputs_PYMUPDF_SETUP_MUPDF_BUILD: ${{inputs.PYMUPDF_SETUP_MUPDF_BUILD}}\n            #inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE: ${{inputs.PYMUPDF_SETUP_MUPDF_BUILD_TYPE}}\n            \n            inputs_wheels_cps: ${{inputs.wheels_cps}}\n            \n            PYMUPDF_SETUP_PY_LIMITED_API: ${{inputs.PYMUPDF_SETUP_PY_LIMITED_API}}\n            \n        run:\n          python scripts/gh_release.py\n      \n\n      # Upload generated wheels, to be accessible from github Actions page.\n      #\n      - uses: actions/upload-artifact@v4\n        with:\n          name: wheels-${{ matrix.os }}\n          path: ./wheelhouse/*.whl\n"
  },
  {
    "path": ".github/workflows/cla.yml",
    "content": "name: \"CLA Assistant\"\non:\n  pull_request_target:\n    types: [opened,closed,synchronize]\n\njobs:\n  CLAAssistant:\n    runs-on: ubuntu-latest\n    steps:\n      - name: \"CLA Assistant\"\n        if: (github.event.comment.body == 'recheck' || github.event.comment.body == 'I have read the CLA Document and I hereby sign the CLA') || github.event_name == 'pull_request_target'\n        # Beta Release\n        uses: contributor-assistant/github-action@v2.4.0\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n          # the below token should have repo scope and must be manually added by you in the repository's secret\n          PERSONAL_ACCESS_TOKEN: ${{ secrets.PERSONAL_ACCESS_TOKEN }}\n        with:\n          path-to-signatures: 'signatures/version1/cla.json'\n          path-to-document: 'https://artifex.com/documents/Artifex%20Contributor%20License%20Agreement.pdf'\n          # branch should not be protected\n          branch: 'CLA'\n          allowlist: \n\n         # the following are the optional inputs - If the optional inputs are not given, then default values will be taken\n          #remote-organization-name: enter the remote organization name where the signatures should be stored (Default is storing the signatures in the same repository)\n          #remote-repository-name: enter the  remote repository name where the signatures should be stored (Default is storing the signatures in the same repository)\n          #create-file-commit-message: 'For example: Creating file for storing CLA Signatures'\n          #signed-commit-message: 'For example: $contributorName has signed the CLA in #$pullRequestNo'\n          #custom-notsigned-prcomment: 'pull request comment with Introductory message to ask new contributors to sign'\n          #custom-pr-sign-comment: 'The signature to be committed in order to sign the CLA'\n          #custom-allsigned-prcomment: 'pull request comment when all contributors has signed, defaults to **CLA Assistant Lite bot** All Contributors have signed the CLA.'\n          #lock-pullrequest-aftermerge: false - if you don't want this bot to automatically lock the pull request after merging (default - true)\n          #use-dco-flag: true - If you are using DCO instead of CLA\n"
  },
  {
    "path": ".github/workflows/test-valgrind.yml",
    "content": "name: Test valgrind\n\non:\n  workflow_dispatch:\n  schedule:\n    - cron: '13 6 * * *'\n\njobs:\n\n  valgrind:\n    name: valgrind\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        args: [\n            '',\n            '-m \"git:--branch master https://github.com/ArtifexSoftware/mupdf\"', \n            '-m \"git:--branch 1.27.x https://github.com/ArtifexSoftware/mupdf\"',\n            ]\n      fail-fast: false\n    \n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n      - name: valgrind\n        run:\n          python scripts/test.py ${{matrix.args}} -P 1 -T valgrind build test\n"
  },
  {
    "path": ".github/workflows/test.yml",
    "content": "# Run scripts/test.py directly on multiple Github servers.  Instead of\n# specifying individual inputs, we support a single string input which is used\n# for the command line directly.\n#\n# This ensures we behave exactly like scripts/test.py, without confusion caused\n# by having to translate between differing APIs.\n\nname: Tests\n\non:\n  #schedule:\n  #  - cron: '47 4 * * *'\n  #pull_request:\n  #  branches: [main]\n  workflow_dispatch:\n    inputs:\n      args:\n        type: string\n        default: ''\n        description: 'Arguments to pass to scripts/test.py'\n\njobs:\n\n  test:\n    name: Test\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-2022, macos-15-intel, macos-14]\n\n      # Avoid cancelling of all runs after a single failure.\n      fail-fast: false\n\n    steps:\n\n      - uses: actions/checkout@v4\n\n      - uses: actions/setup-python@v5\n        with:\n          python-version: '3.12'\n\n      # https://github.com/pypa/cibuildwheel/issues/2114\n      # https://cibuildwheel.pypa.io/en/stable/faq/#emulation\n      #\n      - name: Set up QEMU\n        if: runner.os == 'Linux' && runner.arch == 'X64'\n        uses: docker/setup-qemu-action@v3\n        with:\n          platforms: all\n      \n      - name: test\n        env:\n          PYMUPDF_test_args: ${{inputs.args}}\n        run:\n          python scripts/test.py -a PYMUPDF_test_args\n      \n      # Upload generated wheels, to be accessible from github Actions page.\n      #\n      - uses: actions/upload-artifact@v4\n        with:\n          path: |\n              wheelhouse/pymupdf*.whl\n              wheelhouse/pymupdf*.tar.gz\n          name: artifact-${{ matrix.os }}\n"
  },
  {
    "path": ".github/workflows/test_multiple.yml",
    "content": "# Run scripts/test.py on multiple OS's (Windows, Linux, MacOS x64, MacOS arm64)\n# and with multiple specifications of MuPDF (PyMuPDF's hard-coded default,\n# master branch, release branch).\n\nname: multiple\n\non:\n  workflow_dispatch:\n    inputs:\n      args:\n        type: string\n        default: ''\n        description: 'Additional arguments to scripts/test.py'\n  schedule:\n    - cron: '13 6 * * *'\n\njobs:\n\n  multiple:\n    name: multiple\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest, windows-2022, macos-15-intel, macos-14]\n        args: [\n            '',\n            '-m \"git:--branch master https://github.com/ArtifexSoftware/mupdf\"', \n            '-m \"git:--branch 1.27.x https://github.com/ArtifexSoftware/mupdf\"',\n            ]\n      fail-fast: false\n    \n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n      - name: multiple\n        env:\n          PYMUPDF_test_args: ${{inputs.args}}\n        run:\n          python scripts/test.py ${{matrix.args}} wheel test -a PYMUPDF_test_args\n"
  },
  {
    "path": ".github/workflows/test_pyodide.yml",
    "content": "name: Test pyodide\n\n# Build and test pyodide wheels using cibuildwheel.\n\non:\n  workflow_dispatch:\n  \n  schedule:\n    - cron: '13 5 * * *'\n\njobs:\n\n  pyodide:\n    name: pyodide\n    runs-on: ubuntu-latest\n    strategy:\n      matrix:\n        # 2025-09-05: We don't test with default mupdf because mupdf-1.26.7\n        # does not have the required pyodide rpath changes.\n        args: [\n            # '',\n            '-m \"git:--branch master https://github.com/ArtifexSoftware/mupdf\"', \n            '-m \"git:--branch 1.27.x https://github.com/ArtifexSoftware/mupdf\"',\n            ]\n      fail-fast: false\n    \n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n        with:\n          python-version: 3.12\n      \n      - name: pyodide\n        run:\n          python scripts/test.py ${{matrix.args}} --cibw-pyodide 1 cibw\n      \n      # We do not use upload-artifact@v4 because it fails due to us creating\n      # identically-named wheels.\n      #- uses: actions/upload-artifact@v4\n      #  with:\n      #    path: ./wheelhouse/*.whl\n"
  },
  {
    "path": ".github/workflows/test_quick.yml",
    "content": "name: test_quick\n\non:\n  pull_request:\n    branches: [main]\n    \n  workflow_dispatch:\n    inputs:\n      args:\n        type: string\n        default: ''\n        description: 'Additional arguments to scripts/test.py'\n\njobs:\n\n  master:\n    name: mupdf master\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n      - name: mupdf master\n        env:\n          PYMUPDF_test_args: ${{inputs.args}}\n        run:\n          python scripts/test.py build test -m 'git:--branch master https://github.com/ArtifexSoftware/mupdf.git' -a PYMUPDF_test_args\n\n  release:\n    name: mupdf release\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n      fail-fast: false\n    steps:\n      - uses: actions/checkout@v4\n      - uses: actions/setup-python@v5\n      - name: mupdf release\n        env:\n          PYMUPDF_test_args: ${{inputs.args}}\n        run:\n          python scripts/test.py build test -m 'git:--branch 1.27.x https://github.com/ArtifexSoftware/mupdf.git' -a PYMUPDF_test_args\n"
  },
  {
    "path": ".github/workflows/test_sysinstall.yml",
    "content": "name: Test sysinstall\n\non:\n  schedule:\n    - cron: '13 4 * * *'\n  workflow_dispatch:\n    inputs:\n      args:\n        description: 'Extra args for scripts/sysinstall.py.'\n\njobs:\n\n  sysinstall:\n    name: Test sysinstall\n    runs-on: ${{ matrix.os }}\n    strategy:\n      matrix:\n        os: [ubuntu-latest]\n\n    steps:\n\n      - uses: actions/checkout@v4\n      \n      # It seems to be important not to install a custom python here,\n      # because `sudo` (which we need to use when installing to /usr/local\n      # etc) always ends up running the default python, even if we set\n      # $PATH etc. So for example we can end up with mupdf files and\n      # pymupdf files being installed into .../python3.11/site-packages and\n      # .../python3.10/site-packages, and tests all fail to import pymupdf.\n      #\n      #- uses: actions/setup-python@v5\n        #with:\n        #  # 3.12 doesn't have setuptools. As of 2024-01-03, MuPDF build requires setuptools before it\n        #  # sees `--venv` and defers to a venv, so we currently have to force use of python 3.11.\n        #  python-version: '3.11'\n\n      \n      - name: sysinstall_venv\n        env:\n            PYMUDF_SCRIPTS_SYSINSTALL_ARGS_POST: ${{inputs.args}}\n        run:\n          # Use venv.\n          python3 scripts/sysinstall.py --mupdf-git '--branch master https://github.com/ArtifexSoftware/mupdf.git'\n          \n      - name: sysinstall_sudo\n        env:\n            PYMUDF_SCRIPTS_SYSINSTALL_ARGS_POST: ${{inputs.args}}\n        run:\n          # Do not use a venv, instead install required packages with sudo.\n          python3 scripts/sysinstall.py --mupdf-git '--branch master https://github.com/ArtifexSoftware/mupdf.git' --pip sudo --root /\n"
  },
  {
    "path": ".gitignore",
    "content": "*.pyc\n*.so\n*.o\n*.swp\nbuild/\ndemo/README.rst\ndocs/build\ndocs/_build\n"
  },
  {
    "path": ".python-version",
    "content": "3.12\n"
  },
  {
    "path": ".readthedocs.yaml",
    "content": "# .readthedocs.yaml\r\n# Read the Docs configuration file\r\n# See https://docs.readthedocs.io/en/stable/config-file/v2.html for details\r\n\r\n# Required\r\nversion: 2\r\n\r\n# Set the version of Python and other tools you might need\r\nbuild:\r\n  os: ubuntu-20.04\r\n  tools:\r\n    python: \"3.13\" # let's use the default Python version provided by Read the Docs\r\n    # You can also specify other tool versions:\r\n    # nodejs: \"16\"\r\n    # rust: \"1.55\"\r\n    # golang: \"1.17\"\r\n\r\n# Build documentation in the docs/ directory with Sphinx\r\nsphinx:\r\n   configuration: docs/conf.py\r\n\r\n# If using Sphinx, optionally build your docs in additional formats such as PDF\r\nformats: all\r\n\r\n# Optionally declare the Python requirements required to build your docs\r\npython:\r\n   install:\r\n   - requirements: docs/requirements.txt\r\n"
  },
  {
    "path": ".vs/ProjectSettings.json",
    "content": "{\n  \"CurrentProjectSetting\": \"\"\n}\n"
  },
  {
    "path": ".vs/VSWorkspaceState.json",
    "content": "{\n  \"ExpandedNodes\": [\n    \"\"\n  ],\n  \"SelectedNode\": \"\",\n  \"PreviewInSolutionExplorer\": false\n}\n"
  },
  {
    "path": "COPYING",
    "content": "                    GNU AFFERO GENERAL PUBLIC LICENSE\n                       Version 3, 19 November 2007\n\n Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>\n Everyone is permitted to copy and distribute verbatim copies\n of this license document, but changing it is not allowed.\n\n                            Preamble\n\n  The GNU Affero General Public License is a free, copyleft license for\nsoftware and other kinds of works, specifically designed to ensure\ncooperation with the community in the case of network server software.\n\n  The licenses for most software and other practical works are designed\nto take away your freedom to share and change the works.  By contrast,\nour General Public Licenses are intended to guarantee your freedom to\nshare and change all versions of a program--to make sure it remains free\nsoftware for all its users.\n\n  When we speak of free software, we are referring to freedom, not\nprice.  Our General Public Licenses are designed to make sure that you\nhave the freedom to distribute copies of free software (and charge for\nthem if you wish), that you receive source code or can get it if you\nwant it, that you can change the software or use pieces of it in new\nfree programs, and that you know you can do these things.\n\n  Developers that use our General Public Licenses protect your rights\nwith two steps: (1) assert copyright on the software, and (2) offer\nyou this License which gives you legal permission to copy, distribute\nand/or modify the software.\n\n  A secondary benefit of defending all users' freedom is that\nimprovements made in alternate versions of the program, if they\nreceive widespread use, become available for other developers to\nincorporate.  Many developers of free software are heartened and\nencouraged by the resulting cooperation.  However, in the case of\nsoftware used on network servers, this result may fail to come about.\nThe GNU General Public License permits making a modified version and\nletting the public access it on a server without ever releasing its\nsource code to the public.\n\n  The GNU Affero General Public License is designed specifically to\nensure that, in such cases, the modified source code becomes available\nto the community.  It requires the operator of a network server to\nprovide the source code of the modified version running there to the\nusers of that server.  Therefore, public use of a modified version, on\na publicly accessible server, gives the public access to the source\ncode of the modified version.\n\n  An older license, called the Affero General Public License and\npublished by Affero, was designed to accomplish similar goals.  This is\na different license, not a version of the Affero GPL, but Affero has\nreleased a new version of the Affero GPL which permits relicensing under\nthis license.\n\n  The precise terms and conditions for copying, distribution and\nmodification follow.\n\n                       TERMS AND CONDITIONS\n\n  0. Definitions.\n\n  \"This License\" refers to version 3 of the GNU Affero General Public License.\n\n  \"Copyright\" also means copyright-like laws that apply to other kinds of\nworks, such as semiconductor masks.\n\n  \"The Program\" refers to any copyrightable work licensed under this\nLicense.  Each licensee is addressed as \"you\".  \"Licensees\" and\n\"recipients\" may be individuals or organizations.\n\n  To \"modify\" a work means to copy from or adapt all or part of the work\nin a fashion requiring copyright permission, other than the making of an\nexact copy.  The resulting work is called a \"modified version\" of the\nearlier work or a work \"based on\" the earlier work.\n\n  A \"covered work\" means either the unmodified Program or a work based\non the Program.\n\n  To \"propagate\" a work means to do anything with it that, without\npermission, would make you directly or secondarily liable for\ninfringement under applicable copyright law, except executing it on a\ncomputer or modifying a private copy.  Propagation includes copying,\ndistribution (with or without modification), making available to the\npublic, and in some countries other activities as well.\n\n  To \"convey\" a work means any kind of propagation that enables other\nparties to make or receive copies.  Mere interaction with a user through\na computer network, with no transfer of a copy, is not conveying.\n\n  An interactive user interface displays \"Appropriate Legal Notices\"\nto the extent that it includes a convenient and prominently visible\nfeature that (1) displays an appropriate copyright notice, and (2)\ntells the user that there is no warranty for the work (except to the\nextent that warranties are provided), that licensees may convey the\nwork under this License, and how to view a copy of this License.  If\nthe interface presents a list of user commands or options, such as a\nmenu, a prominent item in the list meets this criterion.\n\n  1. Source Code.\n\n  The \"source code\" for a work means the preferred form of the work\nfor making modifications to it.  \"Object code\" means any non-source\nform of a work.\n\n  A \"Standard Interface\" means an interface that either is an official\nstandard defined by a recognized standards body, or, in the case of\ninterfaces specified for a particular programming language, one that\nis widely used among developers working in that language.\n\n  The \"System Libraries\" of an executable work include anything, other\nthan the work as a whole, that (a) is included in the normal form of\npackaging a Major Component, but which is not part of that Major\nComponent, and (b) serves only to enable use of the work with that\nMajor Component, or to implement a Standard Interface for which an\nimplementation is available to the public in source code form.  A\n\"Major Component\", in this context, means a major essential component\n(kernel, window system, and so on) of the specific operating system\n(if any) on which the executable work runs, or a compiler used to\nproduce the work, or an object code interpreter used to run it.\n\n  The \"Corresponding Source\" for a work in object code form means all\nthe source code needed to generate, install, and (for an executable\nwork) run the object code and to modify the work, including scripts to\ncontrol those activities.  However, it does not include the work's\nSystem Libraries, or general-purpose tools or generally available free\nprograms which are used unmodified in performing those activities but\nwhich are not part of the work.  For example, Corresponding Source\nincludes interface definition files associated with source files for\nthe work, and the source code for shared libraries and dynamically\nlinked subprograms that the work is specifically designed to require,\nsuch as by intimate data communication or control flow between those\nsubprograms and other parts of the work.\n\n  The Corresponding Source need not include anything that users\ncan regenerate automatically from other parts of the Corresponding\nSource.\n\n  The Corresponding Source for a work in source code form is that\nsame work.\n\n  2. Basic Permissions.\n\n  All rights granted under this License are granted for the term of\ncopyright on the Program, and are irrevocable provided the stated\nconditions are met.  This License explicitly affirms your unlimited\npermission to run the unmodified Program.  The output from running a\ncovered work is covered by this License only if the output, given its\ncontent, constitutes a covered work.  This License acknowledges your\nrights of fair use or other equivalent, as provided by copyright law.\n\n  You may make, run and propagate covered works that you do not\nconvey, without conditions so long as your license otherwise remains\nin force.  You may convey covered works to others for the sole purpose\nof having them make modifications exclusively for you, or provide you\nwith facilities for running those works, provided that you comply with\nthe terms of this License in conveying all material for which you do\nnot control copyright.  Those thus making or running the covered works\nfor you must do so exclusively on your behalf, under your direction\nand control, on terms that prohibit them from making any copies of\nyour copyrighted material outside their relationship with you.\n\n  Conveying under any other circumstances is permitted solely under\nthe conditions stated below.  Sublicensing is not allowed; section 10\nmakes it unnecessary.\n\n  3. Protecting Users' Legal Rights From Anti-Circumvention Law.\n\n  No covered work shall be deemed part of an effective technological\nmeasure under any applicable law fulfilling obligations under article\n11 of the WIPO copyright treaty adopted on 20 December 1996, or\nsimilar laws prohibiting or restricting circumvention of such\nmeasures.\n\n  When you convey a covered work, you waive any legal power to forbid\ncircumvention of technological measures to the extent such circumvention\nis effected by exercising rights under this License with respect to\nthe covered work, and you disclaim any intention to limit operation or\nmodification of the work as a means of enforcing, against the work's\nusers, your or third parties' legal rights to forbid circumvention of\ntechnological measures.\n\n  4. Conveying Verbatim Copies.\n\n  You may convey verbatim copies of the Program's source code as you\nreceive it, in any medium, provided that you conspicuously and\nappropriately publish on each copy an appropriate copyright notice;\nkeep intact all notices stating that this License and any\nnon-permissive terms added in accord with section 7 apply to the code;\nkeep intact all notices of the absence of any warranty; and give all\nrecipients a copy of this License along with the Program.\n\n  You may charge any price or no price for each copy that you convey,\nand you may offer support or warranty protection for a fee.\n\n  5. Conveying Modified Source Versions.\n\n  You may convey a work based on the Program, or the modifications to\nproduce it from the Program, in the form of source code under the\nterms of section 4, provided that you also meet all of these conditions:\n\n    a) The work must carry prominent notices stating that you modified\n    it, and giving a relevant date.\n\n    b) The work must carry prominent notices stating that it is\n    released under this License and any conditions added under section\n    7.  This requirement modifies the requirement in section 4 to\n    \"keep intact all notices\".\n\n    c) You must license the entire work, as a whole, under this\n    License to anyone who comes into possession of a copy.  This\n    License will therefore apply, along with any applicable section 7\n    additional terms, to the whole of the work, and all its parts,\n    regardless of how they are packaged.  This License gives no\n    permission to license the work in any other way, but it does not\n    invalidate such permission if you have separately received it.\n\n    d) If the work has interactive user interfaces, each must display\n    Appropriate Legal Notices; however, if the Program has interactive\n    interfaces that do not display Appropriate Legal Notices, your\n    work need not make them do so.\n\n  A compilation of a covered work with other separate and independent\nworks, which are not by their nature extensions of the covered work,\nand which are not combined with it such as to form a larger program,\nin or on a volume of a storage or distribution medium, is called an\n\"aggregate\" if the compilation and its resulting copyright are not\nused to limit the access or legal rights of the compilation's users\nbeyond what the individual works permit.  Inclusion of a covered work\nin an aggregate does not cause this License to apply to the other\nparts of the aggregate.\n\n  6. Conveying Non-Source Forms.\n\n  You may convey a covered work in object code form under the terms\nof sections 4 and 5, provided that you also convey the\nmachine-readable Corresponding Source under the terms of this License,\nin one of these ways:\n\n    a) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by the\n    Corresponding Source fixed on a durable physical medium\n    customarily used for software interchange.\n\n    b) Convey the object code in, or embodied in, a physical product\n    (including a physical distribution medium), accompanied by a\n    written offer, valid for at least three years and valid for as\n    long as you offer spare parts or customer support for that product\n    model, to give anyone who possesses the object code either (1) a\n    copy of the Corresponding Source for all the software in the\n    product that is covered by this License, on a durable physical\n    medium customarily used for software interchange, for a price no\n    more than your reasonable cost of physically performing this\n    conveying of source, or (2) access to copy the\n    Corresponding Source from a network server at no charge.\n\n    c) Convey individual copies of the object code with a copy of the\n    written offer to provide the Corresponding Source.  This\n    alternative is allowed only occasionally and noncommercially, and\n    only if you received the object code with such an offer, in accord\n    with subsection 6b.\n\n    d) Convey the object code by offering access from a designated\n    place (gratis or for a charge), and offer equivalent access to the\n    Corresponding Source in the same way through the same place at no\n    further charge.  You need not require recipients to copy the\n    Corresponding Source along with the object code.  If the place to\n    copy the object code is a network server, the Corresponding Source\n    may be on a different server (operated by you or a third party)\n    that supports equivalent copying facilities, provided you maintain\n    clear directions next to the object code saying where to find the\n    Corresponding Source.  Regardless of what server hosts the\n    Corresponding Source, you remain obligated to ensure that it is\n    available for as long as needed to satisfy these requirements.\n\n    e) Convey the object code using peer-to-peer transmission, provided\n    you inform other peers where the object code and Corresponding\n    Source of the work are being offered to the general public at no\n    charge under subsection 6d.\n\n  A separable portion of the object code, whose source code is excluded\nfrom the Corresponding Source as a System Library, need not be\nincluded in conveying the object code work.\n\n  A \"User Product\" is either (1) a \"consumer product\", which means any\ntangible personal property which is normally used for personal, family,\nor household purposes, or (2) anything designed or sold for incorporation\ninto a dwelling.  In determining whether a product is a consumer product,\ndoubtful cases shall be resolved in favor of coverage.  For a particular\nproduct received by a particular user, \"normally used\" refers to a\ntypical or common use of that class of product, regardless of the status\nof the particular user or of the way in which the particular user\nactually uses, or expects or is expected to use, the product.  A product\nis a consumer product regardless of whether the product has substantial\ncommercial, industrial or non-consumer uses, unless such uses represent\nthe only significant mode of use of the product.\n\n  \"Installation Information\" for a User Product means any methods,\nprocedures, authorization keys, or other information required to install\nand execute modified versions of a covered work in that User Product from\na modified version of its Corresponding Source.  The information must\nsuffice to ensure that the continued functioning of the modified object\ncode is in no case prevented or interfered with solely because\nmodification has been made.\n\n  If you convey an object code work under this section in, or with, or\nspecifically for use in, a User Product, and the conveying occurs as\npart of a transaction in which the right of possession and use of the\nUser Product is transferred to the recipient in perpetuity or for a\nfixed term (regardless of how the transaction is characterized), the\nCorresponding Source conveyed under this section must be accompanied\nby the Installation Information.  But this requirement does not apply\nif neither you nor any third party retains the ability to install\nmodified object code on the User Product (for example, the work has\nbeen installed in ROM).\n\n  The requirement to provide Installation Information does not include a\nrequirement to continue to provide support service, warranty, or updates\nfor a work that has been modified or installed by the recipient, or for\nthe User Product in which it has been modified or installed.  Access to a\nnetwork may be denied when the modification itself materially and\nadversely affects the operation of the network or violates the rules and\nprotocols for communication across the network.\n\n  Corresponding Source conveyed, and Installation Information provided,\nin accord with this section must be in a format that is publicly\ndocumented (and with an implementation available to the public in\nsource code form), and must require no special password or key for\nunpacking, reading or copying.\n\n  7. Additional Terms.\n\n  \"Additional permissions\" are terms that supplement the terms of this\nLicense by making exceptions from one or more of its conditions.\nAdditional permissions that are applicable to the entire Program shall\nbe treated as though they were included in this License, to the extent\nthat they are valid under applicable law.  If additional permissions\napply only to part of the Program, that part may be used separately\nunder those permissions, but the entire Program remains governed by\nthis License without regard to the additional permissions.\n\n  When you convey a copy of a covered work, you may at your option\nremove any additional permissions from that copy, or from any part of\nit.  (Additional permissions may be written to require their own\nremoval in certain cases when you modify the work.)  You may place\nadditional permissions on material, added by you to a covered work,\nfor which you have or can give appropriate copyright permission.\n\n  Notwithstanding any other provision of this License, for material you\nadd to a covered work, you may (if authorized by the copyright holders of\nthat material) supplement the terms of this License with terms:\n\n    a) Disclaiming warranty or limiting liability differently from the\n    terms of sections 15 and 16 of this License; or\n\n    b) Requiring preservation of specified reasonable legal notices or\n    author attributions in that material or in the Appropriate Legal\n    Notices displayed by works containing it; or\n\n    c) Prohibiting misrepresentation of the origin of that material, or\n    requiring that modified versions of such material be marked in\n    reasonable ways as different from the original version; or\n\n    d) Limiting the use for publicity purposes of names of licensors or\n    authors of the material; or\n\n    e) Declining to grant rights under trademark law for use of some\n    trade names, trademarks, or service marks; or\n\n    f) Requiring indemnification of licensors and authors of that\n    material by anyone who conveys the material (or modified versions of\n    it) with contractual assumptions of liability to the recipient, for\n    any liability that these contractual assumptions directly impose on\n    those licensors and authors.\n\n  All other non-permissive additional terms are considered \"further\nrestrictions\" within the meaning of section 10.  If the Program as you\nreceived it, or any part of it, contains a notice stating that it is\ngoverned by this License along with a term that is a further\nrestriction, you may remove that term.  If a license document contains\na further restriction but permits relicensing or conveying under this\nLicense, you may add to a covered work material governed by the terms\nof that license document, provided that the further restriction does\nnot survive such relicensing or conveying.\n\n  If you add terms to a covered work in accord with this section, you\nmust place, in the relevant source files, a statement of the\nadditional terms that apply to those files, or a notice indicating\nwhere to find the applicable terms.\n\n  Additional terms, permissive or non-permissive, may be stated in the\nform of a separately written license, or stated as exceptions;\nthe above requirements apply either way.\n\n  8. Termination.\n\n  You may not propagate or modify a covered work except as expressly\nprovided under this License.  Any attempt otherwise to propagate or\nmodify it is void, and will automatically terminate your rights under\nthis License (including any patent licenses granted under the third\nparagraph of section 11).\n\n  However, if you cease all violation of this License, then your\nlicense from a particular copyright holder is reinstated (a)\nprovisionally, unless and until the copyright holder explicitly and\nfinally terminates your license, and (b) permanently, if the copyright\nholder fails to notify you of the violation by some reasonable means\nprior to 60 days after the cessation.\n\n  Moreover, your license from a particular copyright holder is\nreinstated permanently if the copyright holder notifies you of the\nviolation by some reasonable means, this is the first time you have\nreceived notice of violation of this License (for any work) from that\ncopyright holder, and you cure the violation prior to 30 days after\nyour receipt of the notice.\n\n  Termination of your rights under this section does not terminate the\nlicenses of parties who have received copies or rights from you under\nthis License.  If your rights have been terminated and not permanently\nreinstated, you do not qualify to receive new licenses for the same\nmaterial under section 10.\n\n  9. Acceptance Not Required for Having Copies.\n\n  You are not required to accept this License in order to receive or\nrun a copy of the Program.  Ancillary propagation of a covered work\noccurring solely as a consequence of using peer-to-peer transmission\nto receive a copy likewise does not require acceptance.  However,\nnothing other than this License grants you permission to propagate or\nmodify any covered work.  These actions infringe copyright if you do\nnot accept this License.  Therefore, by modifying or propagating a\ncovered work, you indicate your acceptance of this License to do so.\n\n  10. Automatic Licensing of Downstream Recipients.\n\n  Each time you convey a covered work, the recipient automatically\nreceives a license from the original licensors, to run, modify and\npropagate that work, subject to this License.  You are not responsible\nfor enforcing compliance by third parties with this License.\n\n  An \"entity transaction\" is a transaction transferring control of an\norganization, or substantially all assets of one, or subdividing an\norganization, or merging organizations.  If propagation of a covered\nwork results from an entity transaction, each party to that\ntransaction who receives a copy of the work also receives whatever\nlicenses to the work the party's predecessor in interest had or could\ngive under the previous paragraph, plus a right to possession of the\nCorresponding Source of the work from the predecessor in interest, if\nthe predecessor has it or can get it with reasonable efforts.\n\n  You may not impose any further restrictions on the exercise of the\nrights granted or affirmed under this License.  For example, you may\nnot impose a license fee, royalty, or other charge for exercise of\nrights granted under this License, and you may not initiate litigation\n(including a cross-claim or counterclaim in a lawsuit) alleging that\nany patent claim is infringed by making, using, selling, offering for\nsale, or importing the Program or any portion of it.\n\n  11. Patents.\n\n  A \"contributor\" is a copyright holder who authorizes use under this\nLicense of the Program or a work on which the Program is based.  The\nwork thus licensed is called the contributor's \"contributor version\".\n\n  A contributor's \"essential patent claims\" are all patent claims\nowned or controlled by the contributor, whether already acquired or\nhereafter acquired, that would be infringed by some manner, permitted\nby this License, of making, using, or selling its contributor version,\nbut do not include claims that would be infringed only as a\nconsequence of further modification of the contributor version.  For\npurposes of this definition, \"control\" includes the right to grant\npatent sublicenses in a manner consistent with the requirements of\nthis License.\n\n  Each contributor grants you a non-exclusive, worldwide, royalty-free\npatent license under the contributor's essential patent claims, to\nmake, use, sell, offer for sale, import and otherwise run, modify and\npropagate the contents of its contributor version.\n\n  In the following three paragraphs, a \"patent license\" is any express\nagreement or commitment, however denominated, not to enforce a patent\n(such as an express permission to practice a patent or covenant not to\nsue for patent infringement).  To \"grant\" such a patent license to a\nparty means to make such an agreement or commitment not to enforce a\npatent against the party.\n\n  If you convey a covered work, knowingly relying on a patent license,\nand the Corresponding Source of the work is not available for anyone\nto copy, free of charge and under the terms of this License, through a\npublicly available network server or other readily accessible means,\nthen you must either (1) cause the Corresponding Source to be so\navailable, or (2) arrange to deprive yourself of the benefit of the\npatent license for this particular work, or (3) arrange, in a manner\nconsistent with the requirements of this License, to extend the patent\nlicense to downstream recipients.  \"Knowingly relying\" means you have\nactual knowledge that, but for the patent license, your conveying the\ncovered work in a country, or your recipient's use of the covered work\nin a country, would infringe one or more identifiable patents in that\ncountry that you have reason to believe are valid.\n\n  If, pursuant to or in connection with a single transaction or\narrangement, you convey, or propagate by procuring conveyance of, a\ncovered work, and grant a patent license to some of the parties\nreceiving the covered work authorizing them to use, propagate, modify\nor convey a specific copy of the covered work, then the patent license\nyou grant is automatically extended to all recipients of the covered\nwork and works based on it.\n\n  A patent license is \"discriminatory\" if it does not include within\nthe scope of its coverage, prohibits the exercise of, or is\nconditioned on the non-exercise of one or more of the rights that are\nspecifically granted under this License.  You may not convey a covered\nwork if you are a party to an arrangement with a third party that is\nin the business of distributing software, under which you make payment\nto the third party based on the extent of your activity of conveying\nthe work, and under which the third party grants, to any of the\nparties who would receive the covered work from you, a discriminatory\npatent license (a) in connection with copies of the covered work\nconveyed by you (or copies made from those copies), or (b) primarily\nfor and in connection with specific products or compilations that\ncontain the covered work, unless you entered into that arrangement,\nor that patent license was granted, prior to 28 March 2007.\n\n  Nothing in this License shall be construed as excluding or limiting\nany implied license or other defenses to infringement that may\notherwise be available to you under applicable patent law.\n\n  12. No Surrender of Others' Freedom.\n\n  If conditions are imposed on you (whether by court order, agreement or\notherwise) that contradict the conditions of this License, they do not\nexcuse you from the conditions of this License.  If you cannot convey a\ncovered work so as to satisfy simultaneously your obligations under this\nLicense and any other pertinent obligations, then as a consequence you may\nnot convey it at all.  For example, if you agree to terms that obligate you\nto collect a royalty for further conveying from those to whom you convey\nthe Program, the only way you could satisfy both those terms and this\nLicense would be to refrain entirely from conveying the Program.\n\n  13. Remote Network Interaction; Use with the GNU General Public License.\n\n  Notwithstanding any other provision of this License, if you modify the\nProgram, your modified version must prominently offer all users\ninteracting with it remotely through a computer network (if your version\nsupports such interaction) an opportunity to receive the Corresponding\nSource of your version by providing access to the Corresponding Source\nfrom a network server at no charge, through some standard or customary\nmeans of facilitating copying of software.  This Corresponding Source\nshall include the Corresponding Source for any work covered by version 3\nof the GNU General Public License that is incorporated pursuant to the\nfollowing paragraph.\n\n  Notwithstanding any other provision of this License, you have\npermission to link or combine any covered work with a work licensed\nunder version 3 of the GNU General Public License into a single\ncombined work, and to convey the resulting work.  The terms of this\nLicense will continue to apply to the part which is the covered work,\nbut the work with which it is combined will remain governed by version\n3 of the GNU General Public License.\n\n  14. Revised Versions of this License.\n\n  The Free Software Foundation may publish revised and/or new versions of\nthe GNU Affero General Public License from time to time.  Such new versions\nwill be similar in spirit to the present version, but may differ in detail to\naddress new problems or concerns.\n\n  Each version is given a distinguishing version number.  If the\nProgram specifies that a certain numbered version of the GNU Affero General\nPublic License \"or any later version\" applies to it, you have the\noption of following the terms and conditions either of that numbered\nversion or of any later version published by the Free Software\nFoundation.  If the Program does not specify a version number of the\nGNU Affero General Public License, you may choose any version ever published\nby the Free Software Foundation.\n\n  If the Program specifies that a proxy can decide which future\nversions of the GNU Affero General Public License can be used, that proxy's\npublic statement of acceptance of a version permanently authorizes you\nto choose that version for the Program.\n\n  Later license versions may give you additional or different\npermissions.  However, no additional obligations are imposed on any\nauthor or copyright holder as a result of your choosing to follow a\nlater version.\n\n  15. Disclaimer of Warranty.\n\n  THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY\nAPPLICABLE LAW.  EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT\nHOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM \"AS IS\" WITHOUT WARRANTY\nOF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO,\nTHE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\nPURPOSE.  THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM\nIS WITH YOU.  SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF\nALL NECESSARY SERVICING, REPAIR OR CORRECTION.\n\n  16. Limitation of Liability.\n\n  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING\nWILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS\nTHE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY\nGENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE\nUSE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF\nDATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD\nPARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS),\nEVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF\nSUCH DAMAGES.\n\n  17. Interpretation of Sections 15 and 16.\n\n  If the disclaimer of warranty and limitation of liability provided\nabove cannot be given local legal effect according to their terms,\nreviewing courts shall apply local law that most closely approximates\nan absolute waiver of all civil liability in connection with the\nProgram, unless a warranty or assumption of liability accompanies a\ncopy of the Program in return for a fee.\n\n                     END OF TERMS AND CONDITIONS\n\n            How to Apply These Terms to Your New Programs\n\n  If you develop a new program, and you want it to be of the greatest\npossible use to the public, the best way to achieve this is to make it\nfree software which everyone can redistribute and change under these terms.\n\n  To do so, attach the following notices to the program.  It is safest\nto attach them to the start of each source file to most effectively\nstate the exclusion of warranty; and each file should have at least\nthe \"copyright\" line and a pointer to where the full notice is found.\n\n    <one line to give the program's name and a brief idea of what it does.>\n    Copyright (C) <year>  <name of author>\n\n    This program is free software: you can redistribute it and/or modify\n    it under the terms of the GNU Affero General Public License as published by\n    the Free Software Foundation, either version 3 of the License, or\n    (at your option) any later version.\n\n    This program is distributed in the hope that it will be useful,\n    but WITHOUT ANY WARRANTY; without even the implied warranty of\n    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the\n    GNU Affero General Public License for more details.\n\n    You should have received a copy of the GNU Affero General Public License\n    along with this program.  If not, see <http://www.gnu.org/licenses/>.\n\nAlso add information on how to contact you by electronic and paper mail.\n\n  If your software can interact with users remotely through a computer\nnetwork, you should also make sure that it provides a way for users to\nget its source.  For example, if your program is a web application, its\ninterface could display a \"Source\" link that leads users to an archive\nof the code.  There are many ways you could offer source, and different\nsolutions will be better for different programs; see section 13 for the\nspecific requirements.\n\n  You should also get your employer (if you work as a programmer) or school,\nif any, to sign a \"copyright disclaimer\" for the program, if necessary.\nFor more information on this, and how to apply and follow the GNU AGPL, see\n<http://www.gnu.org/licenses/>.\n"
  },
  {
    "path": "README.md",
    "content": "<p align=\"center\">\n  <a href=\"https://github.com/pymupdf/PyMuPDF/\">\n    <img loading=\"lazy\" alt=\"PyMuPDF\" src=\"https://pymupdf.pro/images/py-mupdf-github-icon.png\" width=\"100px\"/>\n  </a>\n</p>\n\n# PyMuPDF\n\n<p align=\"center\">\n <a href=\"https://trendshift.io/repositories/11536\" target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/11536\" alt=\"pymupdf%2FPyMuPDF | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a>\n</p>\n\n[![Docs](https://img.shields.io/badge/docs-live-brightgreen)](https://pymupdf.readthedocs.io)\n[![PyPI Version](https://img.shields.io/pypi/v/pymupdf?color=blue&label=PyPI)](https://pypi.org/project/PyMuPDF/)\n[![PyPI - Python Version](https://img.shields.io/pypi/pyversions/pymupdf)](https://pypi.org/project/pymupdf/)\n[![License AGPL](https://img.shields.io/github/license/pymupdf/pymupdf)](https://github.com/pymupdf/PyMuPDF/blob/master/COPYING)\n[![PyPI Downloads](https://static.pepy.tech/badge/pymupdf/month)](https://pepy.tech/projects/pymupdf)\n[![Github Stars](https://img.shields.io/github/stars/pymupdf/PyMuPDF?style=social)](https://github.com/pymupdf/PyMuPDF/stargazers)\n[![Discord](https://img.shields.io/discord/770681584617652264?color=6A7EC2&logo=discord&logoColor=ffffff)](https://pymupdf.io/discord/artifex/)\n[![Forum](https://img.shields.io/badge/Forum-ff6600?logo=python&logoColor=ffffff)](https://forum.mupdf.com/c/general/4)\n[![Twitter](https://img.shields.io/twitter/follow/pymupdf4llm)](https://x.com/pymupdf4llm)\n[![Hugging Face](https://img.shields.io/badge/%F0%9F%A4%97_Hugging_Face-007ec6)](https://huggingface.co/artifex-software)\n[![Demo](https://img.shields.io/badge/PyMuPDF4LLM-live?badge&label=DEMO&logo=python&logoColor=ffffff)](https://demo.pymupdf.io)\n\n**The PDF engine behind over 50 million monthly downloads, powering AI pipelines worldwide.**\n\n**PyMuPDF is a high-performance Python library for data extraction, analysis, conversion, rendering and manipulation of PDF (and other) documents.** Built on top of MuPDF — a lightweight, fast C engine — PyMuPDF gives you precise, low-level control over documents alongside high-level convenience APIs. No mandatory external dependencies.\n\n[![Star on GitHub](https://img.shields.io/github/stars/pymupdf/PyMuPDF.svg?style=for-the-badge&label=Star&logo=github)](https://github.com/pymupdf/PyMuPDF/)\n\n---\n\n## Why PyMuPDF?\n\n- **Fast** — powered by [MuPDF](https://mupdf.com/), a best-in-class C rendering engine\n- **Accurate** — pixel-perfect text extraction with font, color, and position metadata\n- **Versatile** — read, write, annotate, redact, merge, split, and convert documents\n- **LLM-ready** — native Markdown output via [PyMuPDF4LLM](https://pypi.org/project/pymupdf4llm/) for RAG and AI pipelines\n- **No mandatory dependencies** — `pip install pymupdf` and you're done\n\n---\n\n## Installation\n\n```bash\npip install pymupdf\n```\n\nWheels are available for **Windows**, **macOS**, and **Linux** on Python 3.10–3.14. If no pre-built wheel exists for your platform, pip will compile from source (requires a C/C++ toolchain).\n\n### Optional extras\n\n| Package | Purpose |\n|---|---|\n| `pymupdf-fonts` | Extended font collection for text output |\n| `pymupdf4llm` | LLM/RAG-optimised Markdown and JSON extraction |\n| `pymupdfpro` | Adds Office document support |\n| `tesseract-ocr` | OCR for scanned pages and images (separate install) |\n\n```bash\n# More fonts\npip install pymupdf-fonts\n\n# LLM-ready extraction\npip install pymupdf4llm\n\n# Office support\npip install pymupdfpro\n\n# OCR (Tesseract must be installed separately)\n# macOS\nbrew install tesseract\n\n# Ubuntu / Debian\nsudo apt install tesseract-ocr\n```\n\n---\n\n## Supported File Formats\n\n### Input\n\n| Category | Formats |\n|---|---|\n| PDF & derivatives | PDF, XPS, EPUB, CBZ, MOBI, FB2, SVG, TXT |\n| Images | PNG, JPEG, BMP, TIFF, GIF, and more |\n| Microsoft Office *(Pro)* | DOC, DOCX, XLS, XLSX, PPT, PPTX |\n| Korean Office *(Pro)* | HWP, HWPX |\n\n### Output\n\n| Format | Notes |\n|---|---|\n| PDF | Full fidelity conversion from Office formats |\n| SVG | Vector page rendering |\n| Image (PNG, JPEG, …) | Page rasterisation at any DPI |\n| Markdown | Structure-aware, LLM-ready |\n| JSON | Bounding boxes, layout data, per-element detail |\n| Plain text | Fast, lightweight extraction |\n\n---\n\n\n## Quick start\n\n### Extract text\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"document.pdf\")\nfor page in doc:\n    print(page.get_text())\n```\n\n### Extract text with layout metadata\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"document.pdf\")\npage = doc[0]\n\nblocks = page.get_text(\"dict\")[\"blocks\"]\nfor block in blocks:\n    if block[\"type\"] == 0:  # text block\n        for line in block[\"lines\"]:\n            for span in line[\"spans\"]:\n                print(f\"{span['text']!r}  font={span['font']}  size={span['size']:.1f}\")\n```\n\n### Extract tables\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"spreadsheet.pdf\")\npage = doc[0]\n\ntables = page.find_tables()\nfor table in tables:\n    print(table.to_markdown())\n\n    # or get as Pandas DataFrame\n    df = table.to_pandas()\n```\n\n### Render a page to an image\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"document.pdf\")\npage = doc[0]\n\npixmap = page.get_pixmap(dpi=150)\npixmap.save(\"page_0.png\")\n```\n\n### OCR a scanned document\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"scanned.pdf\")\npage = doc[0]\n\n# Requires Tesseract installed and on PATH\ntext = page.get_textpage_ocr(language=\"eng\").extractText()\nprint(text)\n```\n\n### Convert to Markdown for LLMs\n\n```python\nimport pymupdf4llm\n\nmd = pymupdf4llm.to_markdown(\"report.pdf\")\n# Pass directly to your LLM or vector store\nprint(md)\n```\n\n### Annotate and redact\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"contract.pdf\")\npage = doc[0]\n\n# Add a highlight annotation\nrect = pymupdf.Rect(72, 100, 400, 120)\npage.add_highlight_annot(rect)\n\n# Add a redaction and apply it\npage.add_redact_annot(rect)\npage.apply_redactions()\n\ndoc.save(\"contract_redacted.pdf\")\n```\n\n### Merge PDFs\n\n```python\nimport pymupdf\n\nmerger = pymupdf.open()\nfor path in [\"part1.pdf\", \"part2.pdf\", \"part3.pdf\"]:\n    merger.insert_pdf(pymupdf.open(path))\n\nmerger.save(\"merged.pdf\")\n```\n\n### Convert an Office document to PDF\n\n```python\nimport pymupdf.pro\n\npymupdf.pro.unlock(\"YOUR-LICENSE-KEY\")\n\ndoc = pymupdf.open(\"presentation.pptx\")\npdf_bytes = doc.convert_to_pdf()\n\nwith open(\"output.pdf\", \"wb\") as f:\n    f.write(pdf_bytes)\n```\n\n### Extract LLM-ready Markdown from a Word document\n\n```python\nimport pymupdf4llm\nimport pymupdf.pro\n\npymupdf.pro.unlock(\"YOUR-LICENSE-KEY\")\n\nmd = pymupdf4llm.to_markdown(\"document.docx\")\nprint(md)\n```\n\n---\n\n## Features\n\n### Core capabilities\n\n| Feature | Description |\n|---|---|\n| **Text extraction** | Plain text, rich dict (font, size, color, bbox), HTML, XML, raw blocks |\n| **Table detection** | `find_tables()` — locate, extract, and export tables as Markdown or structured data |\n| **Image extraction** | Extract embedded images and render any page to a high-resolution `Pixmap` |\n| **Rendering** | Render PDF pages to images or `Pixmap` data for use in UI or other workflows |\n| **OCR** | Tesseract integration — full-page or partial OCR, configurable language |\n| **Annotations** | Read and write highlights, underlines, squiggly lines, sticky notes, free text, ink, stamps |\n| **Redaction** | Add and permanently apply redaction annotations |\n| **Forms** | Read and fill PDF AcroForm fields |\n| **PDF editing** | Insert, delete, and reorder pages; set metadata; merge and split documents |\n| **Drawing** | Draw lines, curves, rectangles, and circles; insert HTML boxes |\n| **Encryption** | Open password-protected PDFs; save with RC4 or AES encryption |\n| **Links** | Extract hyperlinks, internal cross-references, and URI targets |\n| **Bookmarks** | Read and write the outline / table of contents tree |\n| **Metadata** | Title, author, creation date, producer, subject, and custom entries |\n| **Color spaces** | RGB, CMYK, greyscale; color space conversion |\n\n### LLM & AI output (via PyMuPDF4LLM)\n\n| Output | API |\n|---|---|\n| Markdown | `pymupdf4llm.to_markdown(path)` |\n| JSON | `pymupdf4llm.to_json(path)` |\n| Plain text | `pymupdf4llm.to_text(path)` |\n\nSupports multi-column layouts, natural reading order and page chunking.\n\n\n[![Demo](https://img.shields.io/badge/Pymupdf4llm-live?style=for-the-badge&label=DEMO&logo=python&logoColor=ffffff)](https://demo.pymupdf.io)\n\n---\n\n## Supported Python versions\n\nPython **3.10 – 3.14** (as of v1.27.x). Wheels ship for:\n\n- `manylinux` x86\\_64 and aarch64\n- `musllinux` x86\\_64\n- macOS x86\\_64 and arm64\n- Windows x86 and x86\\_64\n\n---\n\n## Performance\n\nPyMuPDF is built on MuPDF — one of the fastest PDF rendering engines available. Typical benchmarks against pure-Python PDF libraries show **10–50× speed improvements** for text extraction and **100× or more** for page rendering, with a minimal memory footprint.\n\nFor AI workloads, PyMuPDF4LLM processes documents **without a GPU**, cutting infrastructure costs significantly compared to vision-based LLM approaches.\n\n---\n\n## Recipes\n\n<details>\n<summary>Extract all images from a PDF</summary>\n\n```python\nimport pymupdf\nfrom pathlib import Path\n\ndoc = pymupdf.open(\"document.pdf\")\nout = Path(\"images\")\nout.mkdir(exist_ok=True)\n\nfor page_index, page in enumerate(doc):\n    for img_index, img in enumerate(page.get_images()):\n        xref = img[0]\n        pix = pymupdf.Pixmap(doc, xref)\n        if pix.n > 4:  # convert CMYK\n            pix = pymupdf.Pixmap(pymupdf.csRGB, pix)\n        pix.save(out / f\"page{page_index}_img{img_index}.png\")\n```\n</details>\n\n<details>\n<summary>Search for text across a document</summary>\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"document.pdf\")\nneedle = \"confidential\"\n\nfor page in doc:\n    hits = page.search_for(needle)\n    if hits:\n        print(f\"Page {page.number}: {len(hits)} occurrence(s)\")\n        for rect in hits:\n            page.add_highlight_annot(rect)\n\ndoc.save(\"highlighted.pdf\")\n```\n</details>\n\n<details>\n<summary>Split a PDF into individual pages</summary>\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"document.pdf\")\nfor i, page in enumerate(doc):\n    out = pymupdf.open()\n    out.insert_pdf(doc, from_page=i, to_page=i)\n    out.save(f\"page_{i + 1}.pdf\")\n```\n</details>\n\n<details>\n<summary>Insert a watermark on every page</summary>\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"document.pdf\")\nfor page in doc:\n    page.insert_text(\n        point=pymupdf.Point(72, page.rect.height / 2),\n        text=\"DRAFT\",\n        fontsize=72,\n        color=(0.8, 0.8, 0.8),\n        rotate=45,\n    )\n\ndoc.save(\"watermarked.pdf\")\n```\n</details>\n\n---\n\n## Office Document Processing\n\nPyMuPDF can be extended with PyMuPDF Pro. This adds a conversion layer that handles Microsoft and Korean Office formats natively — no Office installation, no COM interop, no LibreOffice subprocess.\n\nOnce unlocked, `pymupdf.open()` accepts Office files exactly like PDFs:\n\n```python\nimport pymupdf.pro\npymupdf.pro.unlock(\"YOUR-LICENSE-KEY\")\n\n# Works identically regardless of format\nfor fmt in [\"contract.docx\", \"data.xlsx\", \"deck.pptx\", \"report.hwpx\"]:\n    doc = pymupdf.open(fmt)\n    for page in doc:\n        print(page.get_text())\n```\n\n[Get a trial license key for PyMuPDF Pro](https://pymupdf.pro/try-pro) \n\n**What you can do with Office documents:**\n\n- Extract text and images page-by-page\n- Convert to PDF with `doc.convert_to_pdf()`\n- Rasterise pages to PNG/JPEG for visual inspection\n- Feed directly into PyMuPDF4LLM for AI-ready output\n\n\n\n### Restrictions Without a License Key\n\nWhen `pymupdf.pro.unlock()` is called **without** a key, the following restrictions apply:\n\n| Restriction | Detail |\n|---|---|\n| Page limit | Only the **first 3 pages** of any document are accessible |\n| Time limit | Evaluation period — functionality expires after a set duration |\n\nAll other Pro features work normally within these constraints, making it straightforward to prototype before purchasing a license.\n\n\n---\n\n\n\n## Frequently Asked Questions\n\n### Can I use PyMuPDF, PyMuPDF4LLM and PyMuPDF Pro without sending data to the cloud?\n\nYes, absolutely — and this is one of PyMuPDF's most significant advantages.\n\nPyMuPDF runs entirely locally. It is a native Python library built on top of the MuPDF C engine. When you call `pymupdf.open()`, `page.get_text()`, `page.find_tables()`, or any other method, everything executes in-process on your own machine. No data is transmitted anywhere.\n\n\nThere are no telemetry calls, no licence validation callbacks, no cloud dependencies of any kind in the open-source AGPL build or the commercial build. Once the package is installed, it works fully air-gapped.\n\nThis makes PyMuPDF well-suited for:\n\n- Regulated industries — healthcare (HIPAA), finance, legal, government, where documents cannot leave a controlled environment\n- On-premise deployments — servers with no outbound internet access\n- Air-gapped systems — classified or sensitive environments\n- Self-hosted RAG pipelines — processing confidential documents locally before feeding an on-premise LLM\n- Saving on token costs for document pre-processing before sending data to your LLM\n\nThe only thing you need an internet connection for is the initial `pip install`. After that, the package and all its capabilities are entirely self-contained.\n\n\n### Should I `import pymupdf` or `import fitz`?\n\nUse `import pymupdf`. The `fitz` name is a legacy alias that still works as of v1.24.0+, but `import pymupdf` is the recommended and future-proof approach. The two are interchangeable in existing code:\n\n```python\nimport pymupdf          # recommended\n# import fitz           # legacy alias — still works but avoid for new code\n```\n\n### Does PyMuPDF work with Korean, Japanese, or Chinese documents?\n\nYes — PyMuPDF has solid CJK support\n\n### How do I extract Markdown from PDF for LLM?\n\nLet PyMuPDF4LLM do everything (recommended for RAG).\n\nPyMuPDF4LLM is a high-level wrapper that outputs standard text and table content together in an integrated Markdown-formatted string across all document pages PyMuPDF — tables are detected, converted to GitHub-compatible Markdown, and interleaved with surrounding text in the correct reading order. This is the best starting point for feeding an LLM or building a RAG pipeline.\n\n```python\nimport pymupdf4llm\n\nmd = pymupdf4llm.to_markdown(\"report.pdf\")\nprint(md)\n# Tables appear as Markdown | col1 | col2 | ... inline with the text\n```\n\n\n### Text extraction returns garbled characters or empty output. Why?\n\nThis usually means the PDF uses custom font encodings without a proper character map (CMAP). The font's glyphs are present but cannot be mapped back to Unicode. In these cases:\n\n- Use OCR as a fallback (`page.get_textpage_ocr()`)\n- Consider that scanned PDFs will always need OCR — text extraction on scans returns nothing\n\n\n\n### How do I extract text from a specific area of a page?\n\nPass a `clip` rectangle to `get_text()`:\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"input.pdf\")\npage = doc[0]\n\n# Define the area you want (x0, y0, x1, y1) in points\nclip = pymupdf.Rect(50, 100, 400, 300)\ntext = page.get_text(\"text\", clip=clip)\n```\n\n\n\n### How do I search for text and find its location on the page?\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"input.pdf\")\npage = doc[0]\n\n# Returns a list of Rect objects surrounding each match\nlocations = page.search_for(\"invoice number\")\nfor rect in locations:\n    print(rect)  # e.g. Rect(72.0, 120.5, 210.0, 134.0)\n```\n\n\n\n### `get_images` shows no images but I can clearly see charts in the PDF. Why?\n\nCharts and diagrams created by tools like matplotlib, Excel, or R are typically rendered as vector graphics (PDF drawing commands), not raster images. `get_images` only lists embedded raster image objects and will not detect vector graphics. To capture these, rasterise the entire page with `page.get_pixmap()`.\n\n\n\n### How does OCR work in PyMuPDF? Does it require a separate Tesseract installation?\n\nPyMuPDF uses MuPDF's built-in Tesseract-based OCR support, so there is no Python-level `pytesseract` dependency. However, PyMuPDF still needs access to the **Tesseract language data files** (`tessdata`), and automatic tessdata discovery may invoke the `tesseract` executable (for example, to list available languages) if you do not explicitly provide a tessdata path. In practice, the recommended setup is to either install Tesseract so discovery works automatically, or configure the tessdata location yourself via the `tessdata` parameter or the `TESSDATA_PREFIX` environment variable. Over 100 languages are supported.\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"scanned.pdf\")\npage = doc[0]\n\n# Get a text page using OCR\ntp = page.get_textpage_ocr(language=\"eng\")\ntext = page.get_text(textpage=tp)\nprint(text)\n```\n\n\n### How do I run OCR on a standalone image file (not a PDF)?\n\n```python\nimport pymupdf\n\npix = pymupdf.Pixmap(\"image.png\")\nif pix.alpha:\n    pix = pymupdf.Pixmap(pix, 0)  # remove alpha channel — required for OCR\n\n# Wrap in a 1-page PDF and OCR it\ndoc = pymupdf.open()\npage = doc.new_page(width=pix.width, height=pix.height)\npage.insert_image(page.rect, pixmap=pix)\ntp = page.get_textpage_ocr()\ntext = page.get_text(textpage=tp)\n```\n\n\n### How do I highlight text in a PDF?\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"input.pdf\")\npage = doc[0]\n\n# Use quads=True for accurate highlights on non-horizontal text\nquads = page.search_for(\"important term\", quads=True)\npage.add_highlight_annot(quads)\n\ndoc.save(\"highlighted.pdf\")\n```\n\nPyMuPDF supports all standard PDF text markers: highlight, underline, strikeout, and squiggly.\n\n\n\n### How do I permanently redact (remove) content from a PDF?\n\nRedaction is a deliberate two-step process so you can review before committing:\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"input.pdf\")\npage = doc[0]\n\n# Step 1: Mark the area(s) to redact\nrect = page.search_for(\"confidential\")[0]\npage.add_redact_annot(rect, fill=(1, 1, 1))  # white fill\n\n# Step 2: Apply — permanently removes the underlying content\npage.apply_redactions()\n\ndoc.save(\"redacted.pdf\")\n```\n\nAfter `apply_redactions()`, the original content is gone. It cannot be recovered from the saved file.\n\n\n\n\n\n### How do I read form field values from a PDF?\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"form.pdf\")\npage = doc[0]\n\nfor field in page.widgets():\n    print(f\"{field.field_name}: {field.field_value}\")\n```\n\n\n\n### How do I fill in a PDF form programmatically?\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"form.pdf\")\npage = doc[0]\n\nfor field in page.widgets():\n    if field.field_name == \"First Name\":\n        field.field_value = \"Ada\"\n        field.update()\n\ndoc.save(\"filled_form.pdf\")\n```\n\n\n\n### Can I use multithreading with PyMuPDF?\n\nNo. PyMuPDF does not support multithreaded use, even with Python's newer free-threading mode. The underlying MuPDF library only provides partial thread safety, and a fully thread-safe PyMuPDF implementation would still impose a single-threaded overhead — negating the benefit.\n\n**Use multiprocessing instead.** Each process opens the file independently and works on its own page range:\n\n```python\nfrom multiprocessing import Pool\nimport pymupdf\n\ndef process_pages(args):\n    path, start, end = args\n    doc = pymupdf.open(path)  # each process opens its own handle\n    results = []\n    for i in range(start, end):\n        results.append(doc[i].get_text())\n    return results\n\nwith Pool(4) as pool:\n    chunks = [(\"input.pdf\", 0, 25), (\"input.pdf\", 25, 50), ...]\n    all_results = pool.map(process_pages, chunks)\n```\n\n\n\n### How can I speed up repeated text extraction on the same page?\n\nReuse a `TextPage` object. Creating a `TextPage` is the expensive part — once created, switching between extraction formats is cheap:\n\n```python\nimport pymupdf\n\npage = doc[0]\ntp = page.get_textpage()  # create once\n\ntext  = page.get_text(\"text\",    textpage=tp)\nwords = page.get_text(\"words\",   textpage=tp)\ndata  = page.get_text(\"dict\",    textpage=tp)\n```\n\nThis can reduce execution time by 50–95% for repeated extractions on the same page.\n\n\n\n\n### How do I read and write PDF metadata?\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"input.pdf\")\n\n# Read\nprint(doc.metadata)\n# {'title': '...', 'author': '...', 'subject': '...', 'keywords': '...', ...}\n\n# Write\ndoc.set_metadata({\n    \"title\": \"Annual Report 2025\",\n    \"author\": \"Finance Team\",\n    \"keywords\": \"annual, finance, 2025\"\n})\ndoc.save(\"output.pdf\")\n```\n\n\n### How do I read or set the table of contents / bookmarks?\n\n```python\nimport pymupdf\n\ndoc = pymupdf.open(\"input.pdf\")\n\n# Read — returns a list of [level, title, page_number] entries\ntoc = doc.get_toc()\nfor level, title, page in toc:\n    print(\" \" * level, title, \"→ page\", page)\n\n# Write\nnew_toc = [\n    [1, \"Introduction\",  1],\n    [1, \"Methods\",       5],\n    [2, \"Data sources\",  6],\n]\ndoc.set_toc(new_toc)\ndoc.save(\"output.pdf\")\n```\n\n\n\n---\n\n## Documentation\n\nFull installation guide, API reference, cookbook, and tutorial at **[pymupdf.readthedocs.io](https://pymupdf.readthedocs.io)**.\n\n- [Installation guide](https://pymupdf.readthedocs.io/en/latest/installation.html)\n- [API reference](https://pymupdf.readthedocs.io/en/latest/classes.html)\n- [Cookbook](https://pymupdf.readthedocs.io/en/latest/the-basics.html)\n- [Tutorial](https://pymupdf.readthedocs.io/en/latest/tutorial.html)\n- [Changelog](https://pymupdf.readthedocs.io/en/latest/changes.html)\n- [PyMuPDF4LLM docs](https://pymupdf.readthedocs.io/en/latest/pymupdf4llm/)\n- [PyMuPDF Pro docs](https://pymupdf.readthedocs.io/en/latest/pymupdf-pro/index.html)\n\n---\n\n\n## Related projects\n\n| Project | Description |\n|---|---|\n| [PyMuPDF4LLM](https://github.com/pymupdf/pymupdf4llm) | LLM/RAG-optimised Markdown and JSON extraction |\n| [PyMuPDF Pro](https://pymupdf.io/pro) | Adds Office and HWP document support |\n| [pymupdf-fonts](https://pypi.org/project/pymupdf-fonts/) | Extended font collection for PyMuPDF text output |\n\n---\n\n## Licensing\n\nPyMuPDF and MuPDF are maintained by [Artifex Software, Inc.](https://artifex.com)\n\n- **Open source** — [GNU AGPL v3](https://www.gnu.org/licenses/agpl-3.0.html). Free for open-source projects.\n- **Commercial** — separate commercial licences available from [Artifex](https://artifex.com/licensing) for proprietary applications.\n\n---\n\n## Contributing\n\nContributions are welcome. Please open an issue before submitting large pull requests.\n\n- [Issue tracker](https://github.com/pymupdf/PyMuPDF/issues)\n- [Discord community](https://pymupdf.pro/discord/artifex/)\n\n## ⭐ Support this project\n\nIf you find this useful, please consider giving it a star — it helps others discover it!\n\n[![Star on GitHub](https://img.shields.io/github/stars/pymupdf/PyMuPDF.svg?style=for-the-badge&label=Star&logo=github)](https://github.com/pymupdf/PyMuPDF/)\n"
  },
  {
    "path": "READMEb.md",
    "content": "# PyMuPDFb\n\nThis wheel contains [MuPDF](https://mupdf.readthedocs.io/) shared libraries for\nuse by [PyMuPDF](https://pymupdf.readthedocs.io/).\n\nThis wheel is shared by PyMuPDF wheels that are specific to different Python\nversions, significantly reducing the total size of a release.\n"
  },
  {
    "path": "READMEd.md",
    "content": "# PyMuPDFd\n\nThis wheel contains [MuPDF](https://mupdf.readthedocs.io/) build-time files\nthat were used to build [PyMuPDF](https://pymupdf.readthedocs.io/).\n"
  },
  {
    "path": "changes.txt",
    "content": "Change Log\n==========\n\n\n**Changes in version 1.27.2.3** (2026-04-24)\n\n* Fixed issues:\n\n  * **Fixed** `4928 <https://github.com/pymupdf/PyMuPDF/issues/4928>`_: pymupdf.Document.scrub raises AttributeError for a document with annotations\n  * **Fixed** `4942 <https://github.com/pymupdf/PyMuPDF/issues/4942>`_: bug: IndexError for Page.get_links after Page.clip_to_rect\n  * **Fixed** `4954 <https://github.com/pymupdf/PyMuPDF/issues/4954>`_: get_drawings() returns incorrect lineJoin and width\n  * **Fixed** `4958 <https://github.com/pymupdf/PyMuPDF/issues/4958>`_: bug: inserting rotated pages to another document messes up link coordinates\n\n* Other:\n\n  * Fixed incorrect generation of `lineJoin j` in PDF content, introduced in 1.27.2.2.\n  * Allow build to (incorrectly) claim to be thread-safe, for #4760. See setup.py for details.\n  * Use pypi.org's pipcl package instead of our own pipcl.py file.\n\n\n**Changes in version 1.27.2.2** (2026-03-20)\n\n* Fixed issues:\n\n  * **Fixed** `4902 <https://github.com/pymupdf/PyMuPDF/issues/4902>`_: Incorrect linewidth in elements returned by Page.get_texttrace()\n  * **Fixed** `4932 <https://github.com/pymupdf/PyMuPDF/issues/4932>`_: \"Page\" has no attribute \"find_tables\" in PyMuPDF 1.27\n\n* Other:\n\n  * Added `Annot.__bool__()`.\n\n\n**Changes in version 1.27.2.** (2026-03-10)\n\n* Use MuPDF-1.27.2.\n\n* Fixed issues:\n\n  * **Fixed** `4903 <https://github.com/pymupdf/PyMuPDF/issues/4903>`_: Typing broken because of `*_forward_decl`\n  \n* Other:\n\n  * Retrospectively marked #4907 as fixed in pymupdf-1.27.1.\n  * Improved `get_textpage_ocr()`.\n  \n    For partial OCR, **all** page areas outside legible text are now OCRed, not\n    just those within images. This means that OCR will now also be performed\n    for vector graphics, and for text containing illegible characters.\n\n  * Provide a Linux wheel for free-threading python,\n    specifically cp314-cp314t-manylinux_2_28_x86_64.\n\n\n**Changes in version 1.27.1** (2026-02-11)\n\n* Use MuPDF-1.27.1.\n\n* Fixed issues:\n\n  * **Fixed** `4599 <https://github.com/pymupdf/PyMuPDF/issues/4599>`_: page.cluster_drawings extract a lot of small clusters once upgraded to 1.26\n  * **Fixed** `4751 <https://github.com/pymupdf/PyMuPDF/issues/4751>`_: Memory leaking in page.widgets()\n  * **Fixed** `4762 <https://github.com/pymupdf/PyMuPDF/issues/4762>`_: Importing pymupdf make pillow segmentation fault for converting jp2 file on ArchLinux\n  * **Fixed** `4790 <https://github.com/pymupdf/PyMuPDF/issues/4790>`_: Problem to delete pages on PDF\n  * **Fixed** `4857 <https://github.com/pymupdf/PyMuPDF/issues/4857>`_: Package is missing py.typed file required for type checking\n  * **Fixed** `4886 <https://github.com/pymupdf/PyMuPDF/issues/4886>`_: <IMG> width attribute behaviour seems wrong\n  * **Fixed** `4907 <https://github.com/pymupdf/PyMuPDF/issues/4907>`_: signal 11:SIGSEGV while using display_list.get_textpage()\n\n* Other:\n\n  * Added `pymupdf.TEXT_CLIP`.\n  * Removed support for mupdf < 1.26.\n  * New arg `raise_on_repair` in `Document.save()`.\n  * New method `Document.repair()`.\n\n\n**Changes in version 1.26.7** (2025-12-11)\n\n* Use MuPDF-1.26.12.\n\n  * **Fixed** `4801 <https://github.com/pymupdf/PyMuPDF/issues/4801>`_: Build failure dumping all environment variables\n\nOther:\n\n  * Retrospectively mark `4756 <https://github.com/pymupdf/PyMuPDF/issues/4756>`_ as fixed in 1.26.6.\n  * Improved safety of `pymupdf embed-extract`. This now refuses to write to\n    an existing file or outside current directory, unless `-output` or new flag\n    `-unsafe` is specified.\n\n\n**Changes in version 1.26.6** (2025-11-05)\n\n* Use MuPDF-1.26.11.\n\n* Supported Python versions are now 3.10-3.14.\n\n* Fixed issues:\n\n  * **Fixed** `4699 <https://github.com/pymupdf/PyMuPDF/issues/4699>`_: cannot find ExtGState resource\n  * **Fixed** `4712 <https://github.com/pymupdf/PyMuPDF/issues/4712>`_: Crash with \"corrupted double-linked list\"\n  * **Fixed** `4720 <https://github.com/pymupdf/PyMuPDF/issues/4720>`_: Memory leaking in rewrite_images?\n  * **Fixed** `4742 <https://github.com/pymupdf/PyMuPDF/issues/4742>`_: 'Rect' object has no attribute 'get_area'\n  * **Fixed** `4746 <https://github.com/pymupdf/PyMuPDF/issues/4746>`_: Document.__init__() got an unexpected keyword argument 'encoding'\n  * **Fixed** `4756 <https://github.com/pymupdf/PyMuPDF/issues/4756>`_: swig --version doesn't work in all versions of swig; -version should be used instead\n\n\n**Changes in version 1.26.5** (2025-10-10)\n\n* Use MuPDF-1.26.10.\n\n* Fixed issues:\n\n  * **Fixed** `2883 <https://github.com/pymupdf/PyMuPDF/issues/2883>`_: Improve the Python type annotations for fitz_new\n  * **Fixed** `4507 <https://github.com/pymupdf/PyMuPDF/issues/4507>`_: Bugs in pyodide\n  * **Fixed** `4613 <https://github.com/pymupdf/PyMuPDF/issues/4613>`_: Thai and number blocks are not auto-scaled and get wrong hyphen when using in insert_htmlbox\n  * **Fixed** `4700 <https://github.com/pymupdf/PyMuPDF/issues/4700>`_: pymupdf.open() processes .zip file without raising\n  * **Fixed** `4716 <https://github.com/pymupdf/PyMuPDF/issues/4716>`_: Problems with unreadable characters\n\n* Other:\n\n  * Supported Python versions are now 3.9-3.14.\n  * We now define all class methods explicitly instead of with dynamic assignment; this improves type hints.\n  * Removed `pymupdf.utils.Shape` class, was duplicate of `pymupdf.Shape`.\n  * Allow use of cibuildwheel to build and test on Pyodide.\n  * Fixed various Pyodide bugs.\n  * In documentation, added section about Linux wheels and glibc compatibility.\n  * Improved documentation of pymupdf.open()'s <filetype> arg.\n  * Retrospectively mark `4544 <https://github.com/pymupdf/PyMuPDF/issues/4544>`_ as fixed in 1.26.4.\n\n\n**Changes in version 1.26.4 (2025-08-25)**\n\n* Use MuPDF-1.26.7.\n\n* Fixed issues:\n\n  * **Fixed** `3806 <https://github.com/pymupdf/PyMuPDF/issues/3806>`_: pdf to image rendering ignore optional content offs\n  * **Fixed** `4388 <https://github.com/pymupdf/PyMuPDF/issues/4388>`_: Incorrect PixMap from page due to cached data from other PDF\n  * **Fixed** `4457 <https://github.com/pymupdf/PyMuPDF/issues/4457>`_: Wrong characters displayed after font subsetting (w/ native method)\n  * **Fixed** `4462 <https://github.com/pymupdf/PyMuPDF/issues/4462>`_: delete_pages() does not accept a single int\n  * **Fixed** `4533 <https://github.com/pymupdf/PyMuPDF/issues/4533>`_: Open PDF error segmentation fault\n  * **Fixed** `4544 <https://github.com/pymupdf/PyMuPDF/issues/4544>`_: About pdf_clip_page\n  * **Fixed** `4565 <https://github.com/pymupdf/PyMuPDF/issues/4565>`_: MacOS uses Tesseract and not Tesseract-OCR\n  * **Fixed** `4571 <https://github.com/pymupdf/PyMuPDF/issues/4571>`_: Broken merged pdfs.\n  * **Fixed** `4590 <https://github.com/pymupdf/PyMuPDF/issues/4590>`_: TypeError in utils.py scrub(): annot.update_file(buffer=...) is invalid\n  * **Fixed** `4614 <https://github.com/pymupdf/PyMuPDF/issues/4614>`_: Intercept bad widgets when inserting to another PDF\n  * **Fixed** `4639 <https://github.com/pymupdf/PyMuPDF/issues/4639>`_: pymupdf.mupdf.FzErrorGeneric: code=1: Director error: <class 'AttributeError'>: 'JM_new_bbox_device_Device' object has no attribute 'layer_name'\n\n* Other:\n  \n  * Check that #4392 `Segfault when running with pytest and -Werror` is fixed if PyMuPDF is built with swig>=4.4.\n  * Add `Page.clip_to_rect()`.\n  * Improved search for Tesseract data.\n  * Retrospectively mark #4496 as fixed in 1.26.1.\n  * Retrospectively mark #4503 as fixed in 1.26.3.\n  * Added experimental support for Graal.\n\n\n**Changes in version 1.26.3 (2025-07-02)**\n\n* Use MuPDF-1.26.3.\n\n* Fixed issues:\n\n  * **Fixed** `4462 <https://github.com/pymupdf/PyMuPDF/issues/4462>`_: delete_pages() does not accept a single int\n  * **Fixed** `4503 <https://github.com/pymupdf/PyMuPDF/issues/4503>`_: Undetected character styles\n  * **Fixed** `4527 <https://github.com/pymupdf/PyMuPDF/issues/4527>`_: Rect.intersects() is much slower than necessary\n  * **Fixed** `4564 <https://github.com/pymupdf/PyMuPDF/issues/4564>`_: Possible encoding issue in PDF metadata\n  * **Fixed** `4575 <https://github.com/pymupdf/PyMuPDF/issues/4575>`_: Bug with IRect contains method\n\n* Other:\n\n  * Class Shape is now available as pymupdf.Shape.\n  * Added table cell markdown support.\n\n\n**Changes in version 1.26.2**\n\n[Skipped.]\n\n\n**Changes in version 1.26.1 (2025-06-11)**\n\n* Use MuPDF-1.26.2.\n\n* Fixed issues:\n\n  * **Fixed** `4520 <https://github.com/pymupdf/PyMuPDF/issues/4520>`_: show_pdf_page does not like empty pages created by new_page\n  * **Fixed** `4524 <https://github.com/pymupdf/PyMuPDF/issues/4524>`_: fitz.get_text ignores 'pages' kwarg\n  * **Fixed** `4412 <https://github.com/pymupdf/PyMuPDF/issues/4412>`_: Regression? Spurious error? in insert_pdf in v1.25.4\n  * **Fixed** `4496 <https://github.com/pymupdf/PyMuPDF/issues/4496>`_: pymupdf4llm with pymupdfpro\n\n* Other:\n\n  * Partial fix for `4503 <https://github.com/pymupdf/PyMuPDF/issues/4503>`_: Undetected character styles\n  * New method `Document.rewrite_images()`, useful for reducing file size, changing image formats, or converting color spaces.\n  * `Page.get_text()`: restrict positional args to match docs.\n  * Removed bogus definition of class `Shape`.\n  * Removed release date from module, docs and changelog.\n    * `pymupdf.pymupdf_date` and `pymupdf.VersionDate` are now both None.\n    * They will be removed in a future release.\n\n\n**Changes in version 1.26.0 (2025-05-22)**\n\n* Use MuPDF-1.26.1.\n\n* Fixed issues:\n\n  * **Fixed** `4324 <https://github.com/pymupdf/PyMuPDF/issues/4324>`_: cluster_drawings() fails to cluster horizontal and vertical thin lines\n  * **Fixed** `4363 <https://github.com/pymupdf/PyMuPDF/issues/4363>`_: Trouble with searching\n  * **Fixed** `4404 <https://github.com/pymupdf/PyMuPDF/issues/4404>`_: IndexError in page.get_links()\n  * **Fixed** `4412 <https://github.com/pymupdf/PyMuPDF/issues/4412>`_: Regression? Spurious error? in insert_pdf in v1.25.4\n  * **Fixed** `4423 <https://github.com/pymupdf/PyMuPDF/issues/4423>`_: pymupdf.mupdf.FzErrorFormat: code=7: cannot find object in xref error encountered after version 1.25.3\n  * **Fixed** `4435 <https://github.com/pymupdf/PyMuPDF/issues/4435>`_: get_pixmap method stuck on one page\n  * **Fixed** `4439 <https://github.com/pymupdf/PyMuPDF/issues/4439>`_: New Xml class from data does not work - bug in code\n  * **Fixed** `4445 <https://github.com/pymupdf/PyMuPDF/issues/4445>`_: Broken XREF table incorrectly repaired\n  * **Fixed** `4447 <https://github.com/pymupdf/PyMuPDF/issues/4447>`_: Stroke color of annotations cannot be correctly set\n  * **Fixed** `4479 <https://github.com/pymupdf/PyMuPDF/issues/4479>`_: set_layer_ui_config() toggles all layers rather than just one\n  * **Fixed** `4505 <https://github.com/pymupdf/PyMuPDF/issues/4505>`_: Follow Widget flag values up its parent structure\n\n* Other:\n\n  * Partial fixed for `4457 <https://github.com/pymupdf/PyMuPDF/issues/4457>`_: Wrong characters displayed after font subsetting (w/ native method)\n  * Support image stamp annotations.\n  * Support recoloring pages.\n  * Added example of using Django's file storage API to open files with pymupdf.\n  * Clarified FreeText annotation color options.\n    We now raise an exception if an attempt is made to set attributes that can not be supported.\n  * Fixed potential segv in Pixmap.is_unicolor().\n  * Added runtime assert that that PyMuPDF and MuPDF were built with compatible\n    NDEBUG settings (related to `4390 <https://github.com/pymupdf/PyMuPDF/issues/4390>`_).\n  * Simplified handling of filename/filetype when opening documents.\n  * Removed PDF linearization support.\n    * Calls to `Document.save()` with `linear` set to true will now raise an exception.\n    * See https://artifex.com/blog/mupdf-removes-linearisation for more information.\n\n**Changes in version 1.25.5 (2025-03-31)**\n\n* Fixed issues:\n\n  * **Fixed** `4372 <https://github.com/pymupdf/PyMuPDF/issues/4372>`_: Text insertion fails due to missing /Resources object\n  * **Fixed** `4400 <https://github.com/pymupdf/PyMuPDF/issues/4400>`_: Infinite loop in fill_textbox\n  * **Fixed** `4403 <https://github.com/pymupdf/PyMuPDF/issues/4403>`_: Unable to get_text() - layer/clip nesting too deep\n  * **Fixed** `4415 <https://github.com/pymupdf/PyMuPDF/issues/4415>`_: PDF page is mirrored, origin is at bottom-left\n\n* Other:\n\n  * Use MuPDF-1.25.6.\n  * Fixed MuPDF SEGV on MacOS with particular fonts.\n  * Fixed `Annot.get_textpage()`'s `clip` arg.\n  * Fixed Python-3.14 (pre-release) build error.\n\n\n**Changes in version 1.25.4 (2025-03-14)**\n\n* Use MuPDF-1.25.5.\n\n* Fixed issues:\n\n  * **Fixed** `4079 <https://github.com/pymupdf/PyMuPDF/issues/4079>`_: Unexpected result for apply_redactions()\n  * **Fixed** `4224 <https://github.com/pymupdf/PyMuPDF/issues/4224>`_: MuPDF error: format error: negative code in 1d faxd\n  * **Fixed** `4303 <https://github.com/pymupdf/PyMuPDF/issues/4303>`_: page.get_image_info() returns outdated cached results after replacing image\n  * **Fixed** `4309 <https://github.com/pymupdf/PyMuPDF/issues/4309>`_: FzErrorFormat Error When Deleting First Page\n  * **Fixed** `4336 <https://github.com/pymupdf/PyMuPDF/issues/4336>`_: Major Performance Regression: pix.color_count is 150x slower in version 1.25.3 compared to 1.23.8\n  * **Fixed** `4341 <https://github.com/pymupdf/PyMuPDF/issues/4341>`_: Invalid label retrieval when /Kids is an array of multiple /Nums\n\n* Other:\n\n  * Fixed handling of duplicate widget names when joining PDFs (PR #4347).\n  * Improved Pyodide build.\n  * Avoid SWIG-related build errors with Python-3.13 by disabling PY_LIMITED_API.\n\n\n**Changes in version 1.25.3 (2025-02-06)**\n\n* Use MuPDF-1.25.4.\n\n* Fixed issues:\n\n  * **Fixed** `4139 <https://github.com/pymupdf/PyMuPDF/issues/4139>`_: Text color numbers change between 1.24.14 and 1.25.0\n  * **Fixed** `4141 <https://github.com/pymupdf/PyMuPDF/issues/4141>`_: Some insertion methods fails for pages without a /Resources object\n  * **Fixed** `4180 <https://github.com/pymupdf/PyMuPDF/issues/4180>`_: Search problems\n  * **Fixed** `4182 <https://github.com/pymupdf/PyMuPDF/issues/4182>`_: Text coordinate extraction error\n  * **Fixed** `4245 <https://github.com/pymupdf/PyMuPDF/issues/4245>`_: Highlighting issue distorted on recent versions\n  * **Fixed** `4254 <https://github.com/pymupdf/PyMuPDF/issues/4254>`_: add_freetext_annot is drawing text outside the annotation box\n\n* Other:\n\n  * In annotations:\n    * Added support for subtype FreeTextCallout.\n    * Added support for rich text.\n  * Added miter_limit arg to insert_text*() to allow suppression of spikes caused by long miters.\n  * Add Widget Support to `Document.insert_pdf()`.\n  * Add `bibi` to span dicts.\n  * Add `synthetic' to char dict.\n  * Fixed Pyodide builds.\n\n\n**Changes in version 1.25.2 (2025-01-17)**\n\n* Fixed issues:\n\n  * **Fixed** `4055 <https://github.com/pymupdf/PyMuPDF/issues/4055>`_: \"Yes\" for all checkboxes does not work for all PDF rendering engines.\n  * **Fixed** `4155 <https://github.com/pymupdf/PyMuPDF/issues/4155>`_: samples_mv is unsafe\n  * **Fixed** `4162 <https://github.com/pymupdf/PyMuPDF/issues/4162>`_: Got AttributeError, when tried to add Signature field\n  * **Fixed** `4186 <https://github.com/pymupdf/PyMuPDF/issues/4186>`_: Incorrect handling of JPEG with color space CMYK image extraction\n  * **Fixed** `4195 <https://github.com/pymupdf/PyMuPDF/issues/4195>`_: Pixmaps that are inverted and have an alpha channel are not rendered properly\n  * **Fixed** `4225 <https://github.com/pymupdf/PyMuPDF/issues/4225>`_: pixmap.pil_save() fails due to colorspace definition\n  * **Fixed** `4232 <https://github.com/pymupdf/PyMuPDF/issues/4232>`_: Incorrect Font style and Size\n\n* Other:\n\n  * Use Python's built-in glyphname <> unicode conversion.\n  * Improve speed of pixmap color inversion.\n  * Add new `char_flags` member to span dictionary, for example allows detection of invisible text.\n  * Detect image masks in TextPage output.\n  * Added `Pixmap.pil_image()`.\n\n\n**Changes in version 1.25.1 (2024-12-11)**\n\n* Use MuPDF-1.25.2.\n\n* Fixed issues:\n\n  * **Fixed** `4125 <https://github.com/pymupdf/PyMuPDF/issues/4125>`_: memory leak while convert Pixmap's colorspace\n  * **Fixed** `4034 <https://github.com/pymupdf/PyMuPDF/issues/4034>`_: Possible regression in pdf cleaning during save.\n\n\n**Changes in version 1.25.0 (2024-12-05)**\n\n* Use MuPDF-1.25.1.\n\n* Fixed issues:\n\n  * **Fixed** `4026 <https://github.com/pymupdf/PyMuPDF/issues/4026>`_: page.get_text('blocks') output two piece of very similar text with different bbox\n  * **Fixed** `4004 <https://github.com/pymupdf/PyMuPDF/issues/4004>`_: Segmentation Fault When Updating PDF Form Field Value\n  * **Fixed** `3887 <https://github.com/pymupdf/PyMuPDF/issues/3887>`_: Subset Fonts problem using Fallback Font\n  * **Fixed** `3886 <https://github.com/pymupdf/PyMuPDF/issues/3886>`_: Another issue with destroying PDF when inserting html\n  * **Fixed** `3751 <https://github.com/pymupdf/PyMuPDF/issues/3751>`_: apply_redactions causes part of the page content to be hidden / transparent\n\n\n.. codespell:ignore-begin\n\n**Changes in version 1.24.14 (2024-11-19)**\n\n* Use MuPDF-1.24.11.\n\n* Fixed issues:\n\n  * **Fixed** `3448 <https://github.com/pymupdf/PyMuPDF/issues/3448>`_: get_pixmap function removes the table and leaves just the content behind\n  * **Fixed** `3758 <https://github.com/pymupdf/PyMuPDF/issues/3758>`_: Got \"malloc(): unaligned tcache chunk detected Aborted (core dumped)\" while using add_redact_annot/apply_redactions\n  * **Fixed** `3813 <https://github.com/pymupdf/PyMuPDF/issues/3813>`_: Stories: Ordered list count broken with nested unordered list\n  * **Fixed** `3933 <https://github.com/pymupdf/PyMuPDF/issues/3933>`_: font.valid_codepoints() - malfunction\n  * **Fixed** `4018 <https://github.com/pymupdf/PyMuPDF/issues/4018>`_: PyMuPDF hangs when iterating over zero page PDF pages backwards\n  * **Fixed** `4043 <https://github.com/pymupdf/PyMuPDF/issues/4043>`_: fullcopypage bug\n  * **Fixed** `4047 <https://github.com/pymupdf/PyMuPDF/issues/4047>`_: Segmentation Fault in add_redact_annot\n  * **Fixed** `4050 <https://github.com/pymupdf/PyMuPDF/issues/4050>`_: Content of dict returned by doc.embfile_info() does not fit to documentation\n\n* Other:\n\n  * Ensure that words from `Page.get_text()` never contain RTL/LTR char mixtures.\n  * Fix building with system MuPDF.\n  * Add dot product for points and vectors.\n\n\n**Changes in version 1.24.13 (2024-10-29)**\n\n* Fixed issues:\n\n  * **Fixed** `3848 <https://github.com/pymupdf/PyMuPDF/issues/3848>`_:  Piximap program crash\n  * **Fixed** `3950 <https://github.com/pymupdf/PyMuPDF/issues/3950>`_:  Unable to consistently extract field labels from PDFs\n  * **Fixed** `3981 <https://github.com/pymupdf/PyMuPDF/issues/3981>`_:  PyMuPDF 1.24.12 with pyinstaller throws error.\n  * **Fixed** `3994 <https://github.com/pymupdf/PyMuPDF/issues/3994>`_:  pix.color_topusage raise Segmentation fault (core dumped)\n\n\n**Changes in version 1.24.12 (2024-10-21)**\n\n* Fixed issues:\n\n  * **Fixed** `3914 <https://github.com/pymupdf/PyMuPDF/issues/3914>`_:  Ability to print MuPDF errors to logging instead of stdout\n  * **Fixed** `3916 <https://github.com/pymupdf/PyMuPDF/issues/3916>`_:  insert_htmlbox error: int too large to convert to float\n  * **Fixed** `3950 <https://github.com/pymupdf/PyMuPDF/issues/3950>`_:  Unable to consistently extract field labels from PDFs\n\n* Supported Python versions are now 3.9-3.13.\n\n  * Dropped support for Python-3.8 because end-of-life.\n  * Added support for Python-3.13 because now released.\n  * See: https://devguide.python.org/versions/\n\n\n**Changes in version 1.24.11 (2024-10-03)**\n\n* Use MuPDF-1.24.10.\n\n* Fixed issues:\n\n  * **Fixed** `3624 <https://github.com/pymupdf/PyMuPDF/issues/3624>`_: Pdf file transform to image have a black block\n  * **Fixed** `3859 <https://github.com/pymupdf/PyMuPDF/issues/3859>`_: doc.need_appearances() fails with \"AttributeError: module 'pymupdf.mupdf' has no attribute 'PDF_TRUE' \"\n  * **Fixed** `3863 <https://github.com/pymupdf/PyMuPDF/issues/3863>`_: apply_redactions() does not work as expected\n  * **Fixed** `3905 <https://github.com/pymupdf/PyMuPDF/issues/3905>`_: open stream can raise a FzErrorFormat error instead of FileDataError\n\n* Wheels now use the Python Stable ABI:\n\n  * There is one PyMuPDF wheel for each platform.\n  * Each wheel works with all supported Python versions.\n  * Each wheel is built using the oldest supported Python version (currently 3.8).\n  * There is no PyMuPDFb wheel.\n\n* Other:\n\n  * Improvements to get_text_words() with sort=True.\n  * Tests now always get the latest versions of required Python packages.\n  * Removed dependency on setuptools.\n  * Added item to PyMuPDF-1.24.10 changes below - fix of #3630.\n\n\n**Changes in version 1.24.10 (2024-09-02)**\n\n* Use MuPDF-1.24.9.\n\n* Fixed issues:\n\n  * **Fixed** `3450 <https://github.com/pymupdf/PyMuPDF/issues/3450>`_: get_pixmap function takes too long to process\n  * **Fixed** `3569 <https://github.com/pymupdf/PyMuPDF/issues/3569>`_: Invalid OCGs not ignored by SVG image creation\n  * **Fixed** `3603 <https://github.com/pymupdf/PyMuPDF/issues/3603>`_: ObjStm compression and PDF linearization doesn't work together\n  * **Fixed** `3650 <https://github.com/pymupdf/PyMuPDF/issues/3650>`_: Linebreak inserted between each letter\n  * **Fixed** `3661 <https://github.com/pymupdf/PyMuPDF/issues/3661>`_: Update Document to check the /XYZ len\n  * **Fixed** `3698 <https://github.com/pymupdf/PyMuPDF/issues/3698>`_: documentation issue - old code in the annotations documentation\n  * **Fixed** `3705 <https://github.com/pymupdf/PyMuPDF/issues/3705>`_: Document.select() behaves weirdly in some particular kind of pdf files\n  * **Fixed** `3706 <https://github.com/pymupdf/PyMuPDF/issues/3706>`_: extend Document.__getitem__ type annotation to reflect that the method also accepts slices\n  * **Fixed** `3727 <https://github.com/pymupdf/PyMuPDF/issues/3727>`_: Method get_pixmap() make the program exit without any exceptions or messages\n  * **Fixed** `3767 <https://github.com/pymupdf/PyMuPDF/issues/3767>`_: Cannot get Tessdata with Tesseract-OCR 5\n  * **Fixed** `3773 <https://github.com/pymupdf/PyMuPDF/issues/3773>`_: Link.set_border gives TypeError: '<' not supported between instances of 'NoneType' and 'int'\n  * **Fixed** `3774 <https://github.com/pymupdf/PyMuPDF/issues/3774>`_: fitz.__version__` does not work anymore\n  * **Fixed** `3789 <https://github.com/pymupdf/PyMuPDF/issues/3789>`_: ValueError: not enough values to unpack (expected 3, got 2) is thrown when call insert_pdf\n  * **Fixed** `3820 <https://github.com/pymupdf/PyMuPDF/issues/3820>`_: class improves namedDest handling\n\n  * **Fixed** `3630 <https://github.com/pymupdf/PyMuPDF/issues/3630>`_: page.apply_redactions gives unwanted black rectangle\n\n* Other:\n\n  * Object streams and linearization cannot be used together; attempting to do\n    so will raise an exception. (#3603)\n  * Fixed handling of non-existing /Contents object.\n\n \n**Changes in version 1.24.9 (2024-07-24)**\n\n* Use MuPDF-1.24.8.\n\n\n**Changes in version 1.24.8 (2024-07-22)**\n\n* Fixed issues:\n\n  * **Fixed** `3636 <https://github.com/pymupdf/PyMuPDF/issues/3636>`_: API documentation for the open function is not obvious to find.\n  * **Fixed** `3654 <https://github.com/pymupdf/PyMuPDF/issues/3654>`_: docx parsing was broken in 1.24.7\n  * **Fixed** `3677 <https://github.com/pymupdf/PyMuPDF/issues/3677>`_: Unable to extract subset font name using the newer versions of PyMuPDF : 1.24.6 and 1.24.7.\n  * **Fixed** `3687 <https://github.com/pymupdf/PyMuPDF/issues/3687>`_: Page.get_text results in AssertionError for epub files\n\nOther:\n\n* Fixed various spelling mistakes spotted by codespell.\n* Improved how we modify MuPDF's default configuration on Windows.\n* Make text search to work with ligatures.\n\n\n**Changes in version 1.24.7 (2024-06-26)**\n\n* Fixed issues:\n\n  * **Fixed** `3615 <https://github.com/pymupdf/PyMuPDF/issues/3615>`_: Document.pagemode or Document.pagelayout crashes for epub files\n  * **Fixed** `3616 <https://github.com/pymupdf/PyMuPDF/issues/3616>`_: not last version reported\n\n\n**Changes in version 1.24.6 (2024-06-25)**\n\n* Use MuPDF-1.24.4\n\n* Fixed issues:\n\n  * **Fixed** `3599 <https://github.com/pymupdf/PyMuPDF/issues/3599>`_: Story.fit_width() has a weird line\n  * **Fixed** `3594 <https://github.com/pymupdf/PyMuPDF/issues/3594>`_: Garbled extraction for Amazon Sustainability Report\n  * **Fixed** `3591 <https://github.com/pymupdf/PyMuPDF/issues/3591>`_: 'width' in Page.get_drawings() returns width equal as 0\n  * **Fixed** `3561 <https://github.com/pymupdf/PyMuPDF/issues/3561>`_: ZeroDivisionError: float division by zero with page.apply_redactions()\n  * **Fixed** `3559 <https://github.com/pymupdf/PyMuPDF/issues/3559>`_: SegFault 11 when empty H1 H2 H3 H4 etc element is used in insert_htmlbox\n  * **Fixed** `3539 <https://github.com/pymupdf/PyMuPDF/issues/3539>`_: Add dotted gridline detection to table recognition\n  * **Fixed** `3519 <https://github.com/pymupdf/PyMuPDF/issues/3519>`_: get_toc(simple=False) AttributeError: 'Outline' object has no attribute 'rect'\n  * **Fixed** `3510 <https://github.com/pymupdf/PyMuPDF/issues/3510>`_: page.get_label() gets wrong label on the first page of doc\n  * **Fixed** `3494 <https://github.com/pymupdf/PyMuPDF/issues/3494>`_: 1.24.2/1.24.3: spurious characters introduced when using subset_fonts and insert_pdf\n  * **Fixed** `3470 <https://github.com/pymupdf/PyMuPDF/issues/3470>`_: subset_fonts error exit without exception/warning\n  * **Fixed** `3400 <https://github.com/pymupdf/PyMuPDF/issues/3400>`_: set_toc alters link coordinates for some rotated pages on pymupdf 1.24.2\n  * **Fixed** `3347 <https://github.com/pymupdf/PyMuPDF/issues/3347>`_: Incorrect links to points on pages having different heights\n  * **Fixed** `3237 <https://github.com/pymupdf/PyMuPDF/issues/3237>`_: Set_metadata() does not work\n  * **Fixed** `3493 <https://github.com/pymupdf/PyMuPDF/discussions/3493>`_: Isolate PyMuPDF from other libraries; issues when PyMuPDF is loaded with other libraries like GdkPixbuf\n\n* Other:\n\n  * Fixed concurrent use of PyMuPDF caused by use of constant temporary filenames.\n  \n  * Add musllinux x86_64 wheels to release.\n\n  * Added clearer version information:\n    \n    * `pymupdf.pymupdf_version`.\n    * `pymupdf.mupdf_version`.\n    * `pymupdf.pymupdf_date`.\n\n\n**Changes in version 1.24.5 (2024-05-30)**\n\n* Fixed issues:\n\n  * **Fixed** `3479 <https://github.com/pymupdf/PyMuPDF/issues/3479>`_: regression: fill_textbox: IndexError: pop from empty list\n  * **Fixed** `3488 <https://github.com/pymupdf/PyMuPDF/issues/3488>`_: set_toc method error\n\n* Other:\n\n  * Some more fixes to use MuPDF floating formatting.\n  * Removed/disabled some unnecessary diagnostics.\n  * Fixed utils.do_links() crash.\n  * Experimental new functions `pymupdf.apply_pages()` and `pymupdf.get_text()`.\n  * Addresses wrong label generation for label styles \"a\" and \"A\".\n\n\n**Changes in version 1.24.4 (2024-05-16)**\n\n  * **Fixed** `3418 <https://github.com/pymupdf/PyMuPDF/issues/3418>`_: Re-introduced bug, text align add_redact_annot\n  * **Fixed** `3472 <https://github.com/pymupdf/PyMuPDF/issues/3472>`_: insert_pdf gives SystemError\n\n* Other:\n\n  * Fixed sysinstall test failing to remove all of prior installation before\n    new install.\n  * Fixed `utils.do_links()` crash.\n  * Correct `TextPage` creation Code.\n  * Unified various diagnostics.\n  * Fix bug in `page_merge()`.\n\n\n**Changes in version 1.24.3 (2024-05-09)**\n\n*\n  The Python module is now called `pymupdf`. `fitz` is still supported for\n  backwards compatibility.\n\n* Use MuPDF-1.24.2.\n\n* Fixed issues:\n\n  * **Fixed** `3357 <https://github.com/pymupdf/PyMuPDF/issues/3357>`_: PyMuPDF==1.24.0 will hanging when using page.get_text(\"text\")\n  * **Fixed** `3376 <https://github.com/pymupdf/PyMuPDF/issues/3376>`_: Redacting results are not as expected in 1.24.x.\n  * **Fixed** `3379 <https://github.com/pymupdf/PyMuPDF/issues/3379>`_: Documentation mismatch for get_text_blocks return value order.\n  * **Fixed** `3381 <https://github.com/pymupdf/PyMuPDF/issues/3381>`_: Contents stream contains floats in scientific notation\n  * **Fixed** `3402 <https://github.com/pymupdf/PyMuPDF/issues/3402>`_: Cannot add Widgets containing inter-field-calculation JavaScript\n  * **Fixed** `3414 <https://github.com/pymupdf/PyMuPDF/issues/3414>`_: missing attribute set_dpi()\n  * **Fixed** `3430 <https://github.com/pymupdf/PyMuPDF/issues/3430>`_: page.get_text() cause process freeze with certain pdf on v1.24.2\n\n* Other:\n\n  * New/modified methods:\n\n    * `Page.remove_rotation()`: new, set page rotation to zero while keeping appearance.\n\n  * Fixed some problems when checking for PDF properties.\n  * Fixed pip builds from sdist\n    (see discussion `3360 <https://github.com/pymupdf/PyMuPDF/discussions/3360>`_:\n    Alpine linux docker build failing \"No matching distribution found for pymupdfb==1.24.1\").\n\n\n**Changes in version 1.24.2 (2024-04-17)**\n\n* Removed obsolete classic implementation from releases\n  (previously available as module `fitz_old`).\n\n* Fixed issues:\n\n  * **Fixed** `3331 <https://github.com/pymupdf/PyMuPDF/issues/3331>`_: Document.pages() is incorrectly type-hinted\n  * **Fixed** `3354 <https://github.com/pymupdf/PyMuPDF/issues/3354>`_: PyMuPDF==1.24.1: AttributeError: property 'metadata' of 'Document' object has no setter\n\n* Other:\n\n  * New/modified methods:\n  \n    * `Document.bake()`: new, make annotations / fields permanent content.\n    * `Page.cluster_drawings()`: new, identifies drawing items\n      (i.e. vector graphics or line-art)\n      that belong together based on their geometrical vicinity.\n    * `Page.apply_redactions()`: added new parameter `text`.\n    * `Document.subset_fonts()`: use MuPDF's `pdf_subset_fonts()` instead of PyMuPDF code.\n    \n  * The `Document` class now supports page numbers specified as slices.\n  * Avoid causing MuPDF warnings.\n\n\n**Changes in version 1.24.1 (2024-04-02)**\n\n* Fixed issues:\n\n  * **Fixed** `3278 <https://github.com/pymupdf/PyMuPDF/issues/3278>`_: apply_redactions moves some unredacted text\n  * **Fixed** `3301 <https://github.com/pymupdf/PyMuPDF/issues/3301>`_: Be more permissive when classifying links as kind LINK_URI\n  * **Fixed** `3306 <https://github.com/pymupdf/PyMuPDF/issues/3306>`_: Text containing capital 'ET' not appearing as annotation\n\n* Other:\n\n  * Use MuPDF-1.24.1.\n  * Support ObjStm Compression.\n    Methods `Document.save()`, `Document.ez_save()` and `Document.write()`\n    now support new parameters `use_objstm`, compression_effort` and\n    `preserve_metadata`.\n\n\n**Changes in version 1.24.0 (2024-03-21)**\n\n* Fixed issues:\n\n  * **Fixed** `3281 <https://github.com/pymupdf/PyMuPDF/issues/3281>`_: Preparing metadata (pyproject.toml) did not run successfully\n  * **Fixed** `3279 <https://github.com/pymupdf/PyMuPDF/issues/3279>`_: PyMuPDF no longer builds in Alpine Linux\n  * **Fixed** `3257 <https://github.com/pymupdf/PyMuPDF/issues/3257>`_: apply_redactions() deleting text outside of annotated box\n  * **Fixed** `3216 <https://github.com/pymupdf/PyMuPDF/issues/3216>`_: AttributeError: 'Annot' object has no attribute '__del__'\n  * **Fixed** `3207 <https://github.com/pymupdf/PyMuPDF/issues/3207>`_: get_drawings's items is missing line from h path operator\n  * **Fixed** `3201 <https://github.com/pymupdf/PyMuPDF/issues/3201>`_: Memory leaks when merging PDFs\n  * **Fixed** `3197 <https://github.com/pymupdf/PyMuPDF/issues/3197>`_: page.get_text() returns hexadecimal text for some characters\n  * **Fixed** `3196 <https://github.com/pymupdf/PyMuPDF/issues/3196>`_: Remove text not working in 1.23.25 version vs 1.20.2\n  * **Fixed** `3172 <https://github.com/pymupdf/PyMuPDF/issues/3172>`_: PDF's 45º lines disappearing in png conversion\n  * **Fixed** `3135 <https://github.com/pymupdf/PyMuPDF/issues/3135>`_: Do not log warnings to stdout\n  * **Fixed** `3125 <https://github.com/pymupdf/PyMuPDF/issues/3125>`_: get_pixmap method stuck on one page and runs forever\n  * **Fixed** `2964 <https://github.com/pymupdf/PyMuPDF/issues/2964>`_: There is an issue with the image generated by the page.get_pixmap() function\n\n* Other:\n\n  * Use MuPDF-1.24.0.\n  * Add support for redacting vector graphics.\n  * Several fixes for table module\n    \n    * Add new method for outputting the table as a markdown string.\n    \n    * Address errors in computing the table header object:\n    \n      We now allow None as the cell value, because this will be resolved where\n      needed (e.g. in the pandas DataFrame).\n\n      We previously tried to enforce rect-like tuples in all header cell\n      bboxes, however this fails for tables with all-None columns.  This fix\n      enables this and constructs an empty string in the corresponding cell\n      string.\n\n      We now correctly include start / stop points of lines in the bbox of the\n      clustered graphic.  We previously joined the line's rectangle - which had\n      no effect because this is always empty.\n\n  * Improved exception text if we fail to open document.\n  * Fixed build with new libclang 18.\n  \n\n**Changes in version 1.23.26 (2024-02-29)**\n\n* Fixed issues:\n\n  * **Fixed** `3199 <https://github.com/pymupdf/PyMuPDF/issues/3199>`_: Add entry_points to setuptools configuration to provide command-line console scripts\n  * **Fixed** `3209 <https://github.com/pymupdf/PyMuPDF/issues/3209>`_: Empty vertices in ink annotation\n\n* Other:\n\n  * Improvements to table detection:\n  \n    * Improved check for empty tables, fixes bugs when determining table headers.\n    * Improved computation of enveloping vector graphic rectangles.\n    * Ignore more meaningless \"pseudo\" tables\n\n  * Install command-line 'pymupdf' command that runs fitz/__main__.py.\n  * Don't overwrite MuPDF's config.h when building on non-Windows.\n  * Fix `Story` constructor's `archive` arg to match docs - now accepts a single `Archive` constructor arg.\n  * Do not include MuPDF source in sdist; will be downloaded automatically when building.\n\n\n**Changes in version 1.23.25 (2024-02-20)**\n\n* Fixed issues:\n\n  * **Fixed** `3182 <https://github.com/pymupdf/PyMuPDF/issues/3182>`_: Pixmap.invert_irect argument type error\n  * **Fixed** `3186 <https://github.com/pymupdf/PyMuPDF/issues/3186>`_: extractText() extracts broken text from pdf\n  * **Fixed** `3191 <https://github.com/pymupdf/PyMuPDF/issues/3191>`_: Error on .find_tables()\n\n* Other:\n\n  * When building, be able to specify python-config directly, with environment\n    variable `PIPCL_PYTHON_CONFIG`.\n\n\n**Changes in version 1.23.24 (2024-02-19)**\n\n* Fixed issues:\n\n  * **Fixed** `3148 <https://github.com/pymupdf/PyMuPDF/issues/3148>`_: Table extraction - vertical text not handled correctly\n  * **Fixed** `3179 <https://github.com/pymupdf/PyMuPDF/issues/3179>`_: Table Detection: Incorrect Separation of Vector Graphics Clusters\n  * **Fixed** `3180 <https://github.com/pymupdf/PyMuPDF/issues/3180>`_: Cannot show optional content group: AttributeError: module 'fitz.mupdf' has no attribute 'pdf_array_push_drop'\n\n* Other:\n\n  * Be able to test system install using `sudo pip install` instead of a venv.\n\n\n**Changes in version 1.23.23 (2024-02-18)**\n\n* Fixed issues:\n\n  * **Fixed** `3126 <https://github.com/pymupdf/PyMuPDF/issues/3126>`_: Initialising Archive with a pathlib.Path fails.\n  * **Fixed** `3131 <https://github.com/pymupdf/PyMuPDF/issues/3131>`_: Calling the next attribute of an Annot raises a \"No attribute .parent\" warning\n  * **Fixed** `3134 <https://github.com/pymupdf/PyMuPDF/issues/3134>`_: Using an IRect as clip parameter in Page.get_pixmap no longer works since 1.23.9\n  * **Fixed** `3140 <https://github.com/pymupdf/PyMuPDF/issues/3140>`_: PDF document stays in use after closing\n  * **Fixed** `3150 <https://github.com/pymupdf/PyMuPDF/issues/3150>`_: doc.select() hangs on this doc.\n  * **Fixed** `3163 <https://github.com/pymupdf/PyMuPDF/issues/3163>`_: AssertionError on using fitz.IRect\n  * **Fixed** `3177 <https://github.com/pymupdf/PyMuPDF/issues/3177>`_: fitz.Pixmap(None, pix) Unrecognised args for constructing Pixmap\n\n* Other:\n\n  *\n    Improved `Document.select() by using new MuPDF function\n    `pdf_rearrange_pages()`. This is a more complete (and faster)\n    implementation of what needs to be done here in that not only pages will\n    be rearranged, but also consequential changes will be made to the table\n    of contents, links to removed pages and affected entries in the Optional\n    Content definitions.\n  * `TextWriter.appendv()`: added `small_caps` arg.\n  * Fixed some valgrind errors with MuPDF master.\n  * Fixed `Document.insert_image()` when build with MuPDF master.\n\n\n**Changes in version 1.23.22 (2024-02-12)**\n\n* Fixed issues:\n\n  * **Fixed** `3143 <https://github.com/pymupdf/PyMuPDF/issues/3143>`_: Difference in decoding of OCGs names between doc.get_ocgs() and page.get_drawings()\n\n  * **Fixed** `3139 <https://github.com/pymupdf/PyMuPDF/issues/3139>`_: Pixmap resizing needs positional arg \"clip\" - even if None.\n\n* Other:\n\n  * Removed the use of MuPDF function `fz_image_size()` from PyMuPDF.\n\n\n**Changes in version 1.23.21 (2024-02-01)**\n\n* Fixed issues:\n\n* Other:\n\n  * Fixed bug in set_xml_metadata(), PR `3112 <https://github.com/pymupdf/PyMuPDF/pull/3112>`_: Fix pdf_add_stream metadata error\n  * Fixed lack of `.parent` member in `TextPage` from `Annot.get_textpage()`.\n  * Fixed bug in `Page.add_widget()`.\n\n\n**Changes in version 1.23.20 (2024-01-29)**\n\n* Bug fixes:\n\n  * **Fixed** `3100 <https://github.com/pymupdf/PyMuPDF/issues/3100>`_: Wrong internal property accessed in get_xml_metadata\n\n* Other:\n\n  * Significantly improved speed of `Document.get_toc()`.\n\n\n**Changes in version 1.23.19 (2024-01-25)**\n\n* Bug fixes:\n\n  * **Fixed** `3087 <https://github.com/pymupdf/PyMuPDF/issues/3087>`_: Exception in insert_image with mask specified\n  * **Fixed** `3094 <https://github.com/pymupdf/PyMuPDF/issues/3094>`_: TypeError: '<' not supported between instances of 'FzLocation' and 'int' in doc.delete_pages\n\n* Other:\n\n  * When finding tables:\n  \n    * Allow addition of user-defined \"virtual\" vector graphics when finding tables.\n    * Confirm that the enveloping bboxes of vector graphics are inside the clip rectangle.\n    * Avoid slow finding of rectangle intersections.\n\n  * Added `Font.bbox` property.\n\n\n**Changes in version 1.23.18 (2024-01-23)**\n\n* Bug fixes:\n\n  * **Fixed** `3081 <https://github.com/pymupdf/PyMuPDF/issues/3081>`_: doc.close() not closing the document\n\n* Other:\n\n  * Reduced size of sdist to fit on pypi.org (by reducing size of two test files).\n  * Fix `Annot.file_info()` if no `Desc` item.\n\n\n**Changes in version 1.23.17 (2024-01-22)**\n\n* Bug fixes:\n\n  * **Fixed** `3062 <https://github.com/pymupdf/PyMuPDF/issues/3062>`_: page_rotation_reset does not return page to original rotation\n  * **Fixed** `3070 <https://github.com/pymupdf/PyMuPDF/issues/3070>`_: update_link(): AttributeError: 'Page' object has no attribute 'super'\n\n* Other:\n\n  * Fixed bug in `Page.links()` (PR #3075).\n  * Fixed bug in `Page.get_bboxlog()` with layers.\n  * Add support for timeouts in scripts/ and tests/run_compound.py.\n\n\n**Changes in version 1.23.16 (2024-01-18)**\n\n* Bug fixes:\n\n  * **Fixed** `3058 <https://github.com/pymupdf/PyMuPDF/issues/3058>`_: Pixmap created from CMYK JPEG delivers RGB format\n\n* Other:\n\n  * In table detection strategy \"lines_strict\", exclude fill-only vector graphics.\n  * Fixed sysinstall test failure.\n  * In documentation, update feature matrix with item about text writing.\n\n\n**Changes in version 1.23.15 (2024-01-16)**\n\n* Bug fixes:\n\n  * **Fixed** `3050 <https://github.com/pymupdf/PyMuPDF/issues/3050>`_: python3.9 pix.set_pixel has something wrong in c.append( ord(i))\n\n* Other:\n\n  * Improved docs for Page.find_tables().\n\n\n**Changes in version 1.23.14 (2024-01-15)**\n\n* Bug fixes:\n\n  * **Fixed** `3038 <https://github.com/pymupdf/PyMuPDF/issues/3038>`_: JM_pixmap_from_display_list > Assertion Error : Checking for wrong type\n  * **Fixed** `3039 <https://github.com/pymupdf/PyMuPDF/issues/3039>`_: Issue with doc.close() not closing the document in PyMuPDF\n\n* Other:\n\n  * Ensure valid \"re\" rectangles in `Page.get_drawings()` with derotated pages.\n\n\n**Changes in version 1.23.13 (2024-01-15)**\n\n* Bug fixes:\n\n  * **Fixed** `2979 <https://github.com/pymupdf/PyMuPDF/issues/2979>`_: list index out of range in to_pandas()\n  * **Fixed** `3001 <https://github.com/pymupdf/PyMuPDF/issues/3001>`_: Calling find_tables() on one document alters the bounding boxes of a subsequent document\n\n* Other:\n\n  * Fixed `Rect.height` and `Rect.width` to never return negative values.\n  * Fixed `TextPage.extractIMGINFO()`'s returned `dictkey_yres` value.\n\n\n**Changes in version 1.23.12 (2024-01-12)**\n\n* * **Fixed** `3027 <https://github.com/pymupdf/PyMuPDF/issues/3027>`_: Page.get_text throws Attribute Error for 'parent'\n\n\n**Changes in version 1.23.11 (2024-01-12)**\n\n* Fixed some Pixmap construction bugs.\n* Fixed Pixmap.yres().\n\n\n**Changes in version 1.23.10 (2024-01-12)**\n\n* Bug fixes:\n\n  * **Fixed** `3020 <https://github.com/pymupdf/PyMuPDF/issues/3020>`_: Can't resize a PixMap\n\n* Other:\n\n  * Fixed Page.delete_image().\n\n\n**Changes in version 1.23.9 (2024-01-11)**\n\n* Default to new \"rebased\" implementation.\n\n  * The old \"classic\" implementation is available with `import fitz_old as fitz`.\n  * For more information about why we are changing to the rebased implementation,\n    see: https://github.com/pymupdf/PyMuPDF/discussions/2680\n\n* Use MuPDF-1.23.9.\n\n* Bug fixes (rebased implementation only):\n\n  * **Fixed** `2911 <https://github.com/pymupdf/PyMuPDF/issues/2911>`_: Page.derotation_matrix returns a tuple instead of a Matrix with rebased implementation\n  * **Fixed** `2919 <https://github.com/pymupdf/PyMuPDF/issues/2919>`_: Rebased version: KeyError in resolve_names when merging pdfs\n  * **Fixed** `2922 <https://github.com/pymupdf/PyMuPDF/issues/2922>`_: New feature that allows inserting named-destination links doesn't work\n  * **Fixed** `2943 <https://github.com/pymupdf/PyMuPDF/issues/2943>`_: ZeroDivisionError: float division by zero when use apply_redactions()\n  * **Fixed** `2950 <https://github.com/pymupdf/PyMuPDF/issues/2950>`_: Shelling out to pip during tests is problematic\n  * **Fixed** `2954 <https://github.com/pymupdf/PyMuPDF/issues/2954>`_: Replacement unicode character in text extraction\n  * **Fixed** `2957 <https://github.com/pymupdf/PyMuPDF/issues/2957>`_: apply_redactions() moving text\n  * **Fixed** `2961 <https://github.com/pymupdf/PyMuPDF/issues/2961>`_: Passing a string as a page number raises IndexError instead of TypeError.\n  * **Fixed** `2969 <https://github.com/pymupdf/PyMuPDF/issues/2969>`_: annot.next throws AttributeError\n  * **Fixed** `2978 <https://github.com/pymupdf/PyMuPDF/issues/2978>`_: 1.23.9rc1: module 'fitz.mupdf' has no attribute 'fz_copy_pixmap_rect'\n\n  * **Fixed** `2907 <https://github.com/pymupdf/PyMuPDF/issues/2907>`_: segfault trying to call clean_contents on certain pdfs with python 3.12\n  * **Fixed** `2905 <https://github.com/pymupdf/PyMuPDF/issues/2905>`_: SystemError: <built-in function TextPage_extractIMGINFO> returned a result with an exception set\n  * **Fixed** `2742 <https://github.com/pymupdf/PyMuPDF/issues/2742>`_: Segmentation Fault when inserting three (but not two) copies of the same source page into one destination page\n\n* Other:\n\n  * Add optional setting of opacity to `Page.insert_htmlbox()`.\n  * Fixed issue with add_redact_annot() mentioned in #2934.\n  * Fixed `Page.rotation()` to return 0 for non-PDF documents instead of raising an exception.\n  * Fixed internal quad detection to cope with any Python sequence.\n  * Fixed rebased `fitz.pymupdf_version_tuple` - was previously set to mupdf version.\n  * Improved support for Linux system installs, including adding regular testing on Github.\n  * Add missing `flake8` to `scripts/gh_release.py:test_packages`.\n  * Use newly public functions in MuPDF-1.23.8.\n  * Improved `scripts/test.py` to help investigation of MuPDF issues.\n\n\n**Changes in version 1.23.8 (2023-12-19)**\n\n* Bug fixes (rebased implementation only):\n\n  * **Fixed** `2634 <https://github.com/pymupdf/PyMuPDF/issues/2634>`_: get_toc and set_toc do not behave consistently for rotated pages\n  * **Fixed** `2861 <https://github.com/pymupdf/PyMuPDF/issues/2861>`_: AttributeError in getLinkDict during PDF Merge\n  * **Fixed** `2871 <https://github.com/pymupdf/PyMuPDF/issues/2871>`_: KeyError in getLinkDict during PDF merge\n  * **Fixed** `2886 <https://github.com/pymupdf/PyMuPDF/issues/2886>`_: Error in Skeleton for Named Link Destinations\n\n* Bug fixes (rebased and classic implementations):\n  \n  * **Fixed** `2885 <https://github.com/pymupdf/PyMuPDF/issues/2885>`_: pymupdf find tables too slow\n\n* Other:\n\n  * Rebased implementation:\n  \n    * `Page.insert_htmlbox()`: new, much more powerful alternative to `Page.insert_textbox()` or `TextWriter.fill_textbox()`, using `Story`.\n    * `Story.fit*()`: new methods for fitting a Story into an expanded rect.\n    * `Story.write_with_links()`: add support for external links.\n    * `Document.language()`: fixed to use MuPDF's new `mupdf.fz_string_from_text_language2()`.\n    * `Document.subset_fonts()` - fixed.\n    * Fixed internal `Archive._add_treeitem()` method.\n    * Fixed `fitz_new.__doc__` to contain PyMuPDF and Python version information, and OS name.\n    * Removed use of `(*args, **kwargs)` in API, we now specify keyword args explicitly.\n    * Work with new MuPDF Python exception classes.\n\n  * Fixed bug where `button_states()` returns None when `/AP` points to an indirect object.\n  * Fixed pillow test to not ignore all errors, and install pillow when testing.\n  * Added test for `fitz.css_for_pymupdf_font()` (uses package `pymupdf-fonts`).\n  * Simplified Github Actions test specifications.\n  * Updated `tests/README.md`.\n\n\n**Changes in version 1.23.7 (2023-11-30)**\n\n* Bug fixes in rebased implementation, not fixed in classic implementation:\n\n  * **Fixed** `2232 <https://github.com/pymupdf/PyMuPDF/issues/2232>`_: Geometry helper classes should support keyword arguments\n  * **Fixed** `2788 <https://github.com/pymupdf/PyMuPDF/issues/2788>`_: Problem with get_toc in pymupdf 1.23.6\n  * **Fixed** `2791 <https://github.com/pymupdf/PyMuPDF/issues/2791>`_: Experiencing small memory leak in save()\n\n* Bug fixes (rebased and classic implementations):\n\n  * **Fixed** `2736 <https://github.com/pymupdf/PyMuPDF/issues/2736>`_: Failure when set cropbox with mediabox negative value\n  * **Fixed** `2749 <https://github.com/pymupdf/PyMuPDF/issues/2749>`_: RuntimeError: cycle in structure tree\n  * **Fixed** `2753 <https://github.com/pymupdf/PyMuPDF/issues/2753>`_: Story.write_with_links will ignore everything after the first \"page break\" in the HTML.\n  * **Fixed** `2812 <https://github.com/pymupdf/PyMuPDF/issues/2812>`_: find_tables on landscape page generates reversed text\n  * **Fixed** `2829 <https://github.com/pymupdf/PyMuPDF/issues/2829>`_: [cannot create /Annot for kind] is still printed despite #2345 is closed.\n  * **Fixed** `2841 <https://github.com/pymupdf/PyMuPDF/issues/2841>`_: Unexpected KeyError when using scrub with fitz_new\n\n* Use MuPDF-1.23.7.\n\n* Other:\n\n  * Rebased implementation:\n  \n    * Added flake8 code checking to test suite, and made various fixes.\n    * Disable diagnostics during Document constructor to match classic implementation.\n  \n  * Additional fix to `2553 <https://github.com/pymupdf/PyMuPDF/issues/2553>`_: Invalid characters in versions >= 1.22\n  * Fixed `MuPDF Bug 707324 <https://bugs.ghostscript.com/show_bug.cgi?id=707324>`_: Story: HTML table row background color repeated incorrectly\n  * Added `scripts/test.py`, for simple build+test of PyMuPDF git checkout.\n  * Added `fitz.pymupdf_version_tuple`, e.g. `(1, 23, 6)`.\n  * Restored mistakenly-reverted fix for `2345 <https://github.com/pymupdf/PyMuPDF/issues/2345>`_: Turn off print statements in utils.py\n  * Include any trailing `... repeated <N> times...` text in warnings returned by `mupdf_warnings()` (rebased only).\n  \n\n\n**Changes in version 1.23.6 (2023-11-06)**\n\n* Bug fixes:\n\n  * **Fixed** `2553 <https://github.com/pymupdf/PyMuPDF/issues/2553>`_: Invalid characters in versions >= 1.22\n  * **Fixed** `2608 <https://github.com/pymupdf/PyMuPDF/issues/2608>`_: Incorrect utf32 text extraction (high & low surrogates are split)\n  * **Fixed** `2710 <https://github.com/pymupdf/PyMuPDF/issues/2710>`_: page.rect and text location wrong / differing from older version\n  * **Fixed** `2774 <https://github.com/pymupdf/PyMuPDF/issues/2774>`_: wrong encoding for \"\\?\" character when sort=True\n  * **Fixed** `2775 <https://github.com/pymupdf/PyMuPDF/issues/2775>`_: fitz_new does not work with python3.10 or earlier\n  * **Fixed** `2777 <https://github.com/pymupdf/PyMuPDF/issues/2777>`_: With fitz_new, wrong type for Page.mediabox\n\n* Other:\n\n  * Use MuPDF-1.23.5.\n  * Added Document.resolve_names() (rebased implementation only).\n\n\n**Changes in version 1.23.5 (2023-10-11)**\n\n* Bug fixes:\n\n  * **Fixed** `2341 <https://github.com/pymupdf/PyMuPDF/issues/2341>`_: Handling negative values in the zoom section for LINK_GOTO in linkDest\n  * **Fixed** `2522 <https://github.com/pymupdf/PyMuPDF/issues/2522>`_: Typo in set_layer() - NameError: name 'f' is not defined\n  * **Fixed** `2548 <https://github.com/pymupdf/PyMuPDF/issues/2548>`_: Fitz freezes on some PDFs when calling the fitz.Page.get_text_blocks method.\n  * **Fixed** `2596 <https://github.com/pymupdf/PyMuPDF/issues/2596>`_: save(garbage=3) breaks get_pixmap() with side effect\n  * **Fixed** `2635 <https://github.com/pymupdf/PyMuPDF/issues/2635>`_: \"clean=True\" makes objects invisible in the pdf\n  * **Fixed** `2637 <https://github.com/pymupdf/PyMuPDF/issues/2637>`_: Page.insert_textbox incorrectly handles the last word if it starts a new line\n  * **Fixed** `2699 <https://github.com/pymupdf/PyMuPDF/issues/2699>`_: extract paragraph with below table\n  * **Fixed** `2703 <https://github.com/pymupdf/PyMuPDF/issues/2703>`_: Wrong fontsize calculation in corner cases (\"page.get_texttrace()\")\n  * **Fixed** `2710 <https://github.com/pymupdf/PyMuPDF/issues/2710>`_: page.rect and text location wrong / differing from older version\n  * **Fixed** `2723 <https://github.com/pymupdf/PyMuPDF/issues/2723>`_: When will a Python 3.12 wheel be available?\n  * **Fixed** `2730 <https://github.com/pymupdf/PyMuPDF/issues/2730>`_: persistent get_text() formatting\n\n* Other:\n\n  * Use MuPDF-1.23.4.\n  * Fix optimisation flags with system installs.\n  * Fixed the problem that the clip parameter does not take effect during table recognition\n  * Support Pillow mode \"RGBa\"\n  * Support extra word delimiters\n  * Support checking valid PDF name objects\n\n\n**Changes in version 1.23.4 (2023-09-26)**\n\n* Improved build instructions.\n* Fixed Tesseract in rebased implementation.\n* Improvements to build/install with system MuPDF.\n* Fixed Pyodide builds.\n* Fixed rebased bug in _insert_image().\n\n* Bug fixes:\n\n  * **Fixed** `2556 <https://github.com/pymupdf/PyMuPDF/issues/2556>`_: Segmentation fault at calling get_cdrawings(extended=True)\n  * **Fixed** `2637 <https://github.com/pymupdf/PyMuPDF/issues/2637>`_: Page.insert_textbox incorrectly handles the last word if it starts a new line\n  * **Fixed** `2683 <https://github.com/pymupdf/PyMuPDF/issues/2683>`_: Windows sdist build failure - non-quoting of path and using UNIX which command\n  * **Fixed** `2691 <https://github.com/pymupdf/PyMuPDF/issues/2691>`_: Page.get_textpage_ocr() bug in rebased fitz_new version\n  * **Fixed** `2692 <https://github.com/pymupdf/PyMuPDF/issues/2692>`_: Page.get_pixmap(clip=Rect()) bug in rebased fitz_new version\n\n\n**Changes in version 1.23.3 (2023-08-31)**\n\n* Fixed use of Tesseract for OCR.\n\n\n**Changes in version 1.23.2 (2023-08-28)**\n\n* **Fixed** `#2613 <https://github.com/pymupdf/PyMuPDF/issues/2613>`_: release 1.23.0 not MacOS-arm64 compatible\n\n\n**Changes in version 1.23.1 (2023-08-24)**\n\n* Updated README and package summary description.\n\n*\n  Fixed a problem on some Linux installations with Python-3.10\n  (and possibly earlier versions) where `import fitz` failed with\n  `ImportError: libcrypt.so.2: cannot open shared object file: No such\n  file or directory`.\n\n*\n  Fixed `incompatible architecture` error on MacOS arm64.\n\n*\n  Fixed installation warning from Poetry about missing entry in wheels'\n  RECORD files.\n\n\n**Changes in version 1.23.0 (2023-08-22)**\n\n* Add method `find_tables()` to the `Page` object.\n\n  This allows locating tables on any supported document page, and\n  extracting table content by cell.\n\n* New \"rebased\" implementation of PyMuPDF.\n\n  The rebased implementation is available as Python module\n  `fitz_new`. It can be used as a drop-in replacement with `import\n  fitz_new as fitz`.\n\n*\n  Python-independent MuPDF libraries are now in a second wheel called\n  `PyMuPDFb` that will be automatically installed by pip.\n\n  This is to save space on pypi.org - a full release only needs one\n  `PyMuPDFb` wheel for each OS.\n\n* Bug fixes:\n\n  * **Fixed** `#2542 <https://github.com/pymupdf/PyMuPDF/issues/2542>`_: fitz.utils.scrub AttributeError Annot object has no attribute fileUpd inside\n  * **Fixed** `#2533 <https://github.com/pymupdf/PyMuPDF/issues/2533>`_: get_texttrace returned a incorrect character bbox\n  * **Fixed** `#2537 <https://github.com/pymupdf/PyMuPDF/issues/2537>`_: Validation when setting a grouped RadioButton throws a RuntimeError: path to 'V' has indirects\n\n* Other changes:\n\n  * Dropped support for Python-3.7.\n\n  * Fix for wrong page / annot `/Contents` cleaning.\n    \n    We need to set `pdf_filter_options::no_update` to zero.\n\n  * Added new function get_tessdata().\n\n  * Cope with problem `/Annot` arrays.\n  \n    When copying page annotations in method Document.insert_pdf we\n    previously did not check the validity of members of the `/Annots`\n    array.  For faulty members (like null or non-dictionary items) this\n    could cause unnecessary exceptions. This fix implements more checks\n    and skips such array items.\n\n  * Additional annotation type checks.\n\n    We did not previously check for annotation type when getting /\n    setting annotation border properties. This is now checked in\n    accordance with MuPDF.\n\n  * Increase fault tolerance.\n    \n    Avoid exceptions in method `insert_pdf()` when source pages contains\n    invalid items in the `/Annots` array.\n\n  * Return empty border dict for applicable annots.\n    \n    We previously were returning a non-empty border dictionary even for\n    non-applicable annotation types.  We now return the empty dictionary\n    `{}` in these cases. This requires some corresponding changes in the\n    annotation `.update()` method, namely for dashes and border width.\n\n  * Restrict `set_rect` to applicable annot types.\n\n    We were insufficiently excluding non-applicable annotation types\n    from `set_rect()` method.  We now let MuPDF catch unsupported\n    annotations and return `False` in these cases.\n\n  * Wrong fontsize computation in `page.get_texttrace()`.\n    \n    When computing the font size we were using the final text\n    transformation matrix, where we should have taken `span->trm`\n    instead.  This is corrected here.\n\n  * Updates to cope with changes to latest MuPDF.\n  \n    `pdf_lookup_anchor()` has been removed.\n\n  * Update fill_textbox to better respect rect.width\n\n    The function norm_words in fill_textbox had a bug in its last\n    loop, appending n+1 characters when actually measuring width of n\n    characters.  It led to a bug in fill_texbox when you tried to write\n    a single word mostly composed of \"wide\" letters (M,m, W, w...),\n    causing the written text to exceed the given rect.\n\n    The fix was just to replace n+1 by n.\n\n  * Add `script_focus` and `script_blur` options to widget.\n\n\n\n**Changes in version 1.22.5 (2023-06-21)**\n\n* This release uses ``MuPDF-1.22.2``.\n\n* Bug fixes:\n\n  * **Fixed** `#2365 <https://github.com/pymupdf/PyMuPDF/issues/2365>`_: Incorrect dictionary values for type \"fs\" drawings.\n  * **Fixed** `#2391 <https://github.com/pymupdf/PyMuPDF/issues/2391>`_: Check box automatically uncheck when we update same checkbox more than 1 times.\n  * **Fixed** `#2400 <https://github.com/pymupdf/PyMuPDF/issues/2400>`_: Gaps within text of same line not filled with spaces.\n  * **Fixed** `#2404 <https://github.com/pymupdf/PyMuPDF/issues/2404>`_: Blacklining an image in PDF won't remove underlying content in version 1.22.X.\n  * **Fixed** `#2430 <https://github.com/pymupdf/PyMuPDF/issues/2430>`_: Incorrectly reducing ref count of Py_None.\n  * **Fixed** `#2450 <https://github.com/pymupdf/PyMuPDF/issues/2450>`_: Empty fill color and fill opacity for paths with fill and stroke operations with 1.22.*\n  * **Fixed** `#2462 <https://github.com/pymupdf/PyMuPDF/issues/2462>`_: Error at \"get_drawing(extended=True )\"\n  * **Fixed** `#2468 <https://github.com/pymupdf/PyMuPDF/issues/2468>`_: Decode error when trying to get drawings  \n  * **Fixed** `#2710 <https://github.com/pymupdf/PyMuPDF/issues/2710>`_: page.rect and text location wrong / differing from older version\n  * **Fixed** `#2723 <https://github.com/pymupdf/PyMuPDF/issues/2723>`_: When will a Python 3.12 wheel be available?\n\n* New features:\n\n  * **Changed** Annotations now support \"cloudy\" borders.\n    The :attr:`Annot.border` property has the new item `clouds`,\n    and method :meth:`Annot.set_border` supports the corresponding `clouds` argument.\n\n  * **Changed** Radio button widgets in the same RB group\n    are now consistently updated **if the group is defined in the standard way**.\n\n  * **Added** Support for the `/Locked` key in PDF Optional Content.\n    This array inside the catalog entry `/OCProperties` can now be extracted and set.\n\n  * **Added** Support for new parameter `tessdata` in OCR functions.\n    New function :meth:`get_tessdata` locates the language support folder if Tesseract is installed.\n\n\n\n**Changes in version 1.22.3 (2023-05-10)**\n\n* This release uses ``MuPDF-1.22.0``.\n\n* Bug fixes:\n\n  * **Fixed** `#2333 <https://github.com/pymupdf/PyMuPDF/issues/2333>`_: Unable to set any of button radio group in form\n\n\n**Changes in version 1.22.2 (2023-04-26)**\n\n* This release uses ``MuPDF-1.22.0``.\n\n* Bug fixes:\n\n  * **Fixed** `#2369 <https://github.com/pymupdf/PyMuPDF/issues/2369>`_: Image extraction bugs with newer versions\n\n\n**Changes in version 1.22.1 (2023-04-18)**\n\n* This release uses ``MuPDF-1.22.0``.\n\n* Bug fixes:\n\n  * **Fixed** `#2345 <https://github.com/pymupdf/PyMuPDF/issues/2345>`_: Turn off print statements in utils.py\n  * **Fixed** `#2348 <https://github.com/pymupdf/PyMuPDF/issues/2348>`_: extract_image returns an extension \"flate\" instead of \"png\"\n  * **Fixed** `#2350 <https://github.com/pymupdf/PyMuPDF/issues/2350>`_: Can not make widget (checkbox) to read-only by adding flags PDF_FIELD_IS_READ_ONLY\n  * **Fixed** `#2355 <https://github.com/pymupdf/PyMuPDF/issues/2355>`_: 1.22.0 error when using get_toc (AttributeError: 'SwigPyObject' object has no attribute)\n\n\n**Changes in version 1.22.0 (2023-04-14)**\n\n* This release uses ``MuPDF-1.22.0``.\n\n* Behavioural changes:\n\n  * Text extraction now includes glyphs that overlap with clip rect; previously\n    they were included only if they were entirely contained within the clip\n    rect.\n\n* Bug fixes:\n\n  * **Fixed** `#1763 <https://github.com/pymupdf/PyMuPDF/issues/1763>`_: Interactive(smartform) form PDF calculation not working in pymupdf\n  * **Fixed** `#1995 <https://github.com/pymupdf/PyMuPDF/issues/1995>`_: RuntimeError: image is too high for a long paged pdf file when trying\n  * **Fixed** `#2093 <https://github.com/pymupdf/PyMuPDF/issues/2093>`_: Image in pdf changes color after applying redactions\n  * **Fixed** `#2108 <https://github.com/pymupdf/PyMuPDF/issues/2108>`_: Redaction removing more text than expected\n  * **Fixed** `#2141 <https://github.com/pymupdf/PyMuPDF/issues/2141>`_: Failed to read JPX header when trying to get blocks\n  * **Fixed** `#2144 <https://github.com/pymupdf/PyMuPDF/issues/2144>`_: Replace image throws an error\n  * **Fixed** `#2146 <https://github.com/pymupdf/PyMuPDF/issues/2146>`_: Wrong Handling of Reference Count of \"None\" Object\n  * **Fixed** `#2161 <https://github.com/pymupdf/PyMuPDF/issues/2161>`_: Support adding images as pages directly\n  * **Fixed** `#2168 <https://github.com/pymupdf/PyMuPDF/issues/2168>`_: ``page.add_highlight_annot(start=pointa, stop=pointb)`` not working\n  * **Fixed** `#2173 <https://github.com/pymupdf/PyMuPDF/issues/2173>`_: Double free of ``Colorspace`` used in ``Pixmap``\n  * **Fixed** `#2179 <https://github.com/pymupdf/PyMuPDF/issues/2179>`_: Incorrect documentation for ``pixmap.tint_with()``\n  * **Fixed** `#2208 <https://github.com/pymupdf/PyMuPDF/issues/2208>`_: Pushbutton widget appears as check box\n  * **Fixed** `#2210 <https://github.com/pymupdf/PyMuPDF/issues/2210>`_: ``apply_redactions()`` move pdf text to right after redaction\n  * **Fixed** `#2220 <https://github.com/pymupdf/PyMuPDF/issues/2220>`_: ``Page.delete_image()`` | object has no attribute ``is_image``\n  * **Fixed** `#2228 <https://github.com/pymupdf/PyMuPDF/issues/2228>`_: open some pdf cost too much time\n  * **Fixed** `#2238 <https://github.com/pymupdf/PyMuPDF/issues/2238>`_: Bug - can not extract data from file in the newest version 1.21.1\n  * **Fixed** `#2242 <https://github.com/pymupdf/PyMuPDF/issues/2242>`_: Python quits silently in ``Story.element_positions()`` if callback function prototype is wrong\n  * **Fixed** `#2246 <https://github.com/pymupdf/PyMuPDF/issues/2246>`_: TextWriter write text in a wrong position\n  * **Fixed** `#2248 <https://github.com/pymupdf/PyMuPDF/issues/2248>`_: After redacting the content, the position of the remaining text changes\n  * **Fixed** `#2250 <https://github.com/pymupdf/PyMuPDF/issues/2250>`_: docs: unclear or broken link in page.rst\n  * **Fixed** `#2251 <https://github.com/pymupdf/PyMuPDF/issues/2251>`_: mupdf_display_errors does not apply to Pixmap when loading broken image\n  * **Fixed** `#2270 <https://github.com/pymupdf/PyMuPDF/issues/2270>`_: ``Annot.get_text(\"words\")`` - doesn't return the first line of words\n  * **Fixed** `#2275 <https://github.com/pymupdf/PyMuPDF/issues/2275>`_: insert_image: document that rotations are counterclockwise\n  * **Fixed** `#2278 <https://github.com/pymupdf/PyMuPDF/issues/2278>`_: Can not make widget (checkbox) to read-only by adding flags PDF_FIELD_IS_READ_ONLY\n  * **Fixed** `#2290 <https://github.com/pymupdf/PyMuPDF/issues/2290>`_: Different image format/data from Page.get_text(\"dict\") and Fitz.get_page_images()\n  * **Fixed** `#2293 <https://github.com/pymupdf/PyMuPDF/issues/2293>`_: 68 failed tests when installing from sdist on my box\n  * **Fixed** `#2300 <https://github.com/pymupdf/PyMuPDF/issues/2300>`_: Too much recursion in tree (parents), makes program terminate\n  * **Fixed** `#2322 <https://github.com/pymupdf/PyMuPDF/issues/2322>`_: add_highlight_annot using clip generates \"A Number is Out of Range\" error in PDF\n\n* Other:\n\n  * Add key \"/AS (Yes)\" to the underlying annot object of a selected button form field.\n\n  * Remove unused ``Document`` methods ``has_xref_streams()`` and\n    ``has_old_style_xrefs()`` as MuPDF equivalents have been removed.\n\n  * Add new ``Document`` methods and properties for getting/setting\n    ``/PageMode``, ``/PageLayout`` and ``/MarkInfo``.\n\n  * New ``Document`` property ``version_count``, which contains the number of\n    incremental saves plus one.\n\n  * New ``Document`` property ``is_fast_webaccess`` which tells whether the\n    document is linearized.\n\n  * ``DocumentWriter`` is now a context manager.\n\n  * Add support for ``Pixmap`` JPEG output.\n\n  * Add support for drawing rectangles with rounded corners.\n\n  * ``get_drawings()``: added optional ``extended`` arg.\n\n  * Fixed issue where trace devices' state was not being initialised\n    correctly; data returned from things like ``fitz.Page.get_texttrace()``\n    might be slightly altered, e.g. ``linewidth`` values.\n\n  * Output warning to ``stderr`` if it looks like we are being used with\n    current directory containing an invalid ``fitz/`` directory, because\n    this can break import of ``fitz`` module. For example this happens\n    if one attempts to use ``fitz`` when current directory is a PyMuPDF\n    checkout.\n\n* Documentation:\n\n  * General rework:\n\n    * Introduces a new home page and new table of contents.\n    * Structural update to include new About section.\n    * Comparison & performance graphing.\n    * Includes performance methodology in appendix.\n    * Updates conf.py to understand single back-ticks as code.\n    * Converts double back-ticks to single back-ticks.\n    * Removes redundant files.\n\n  * Improve ``insert_file()`` documentation.\n\n  * ``get_bboxlog()``: added optional ``layers`` to ``get_bboxlog()``.\n  * ``Page.get_texttrace()``: add new dictionary key ``layer``, name of Optional Content Group.\n\n  * Mention use of Python venv in installation documentation.\n\n  * Added missing fix for #2057 to release 1.21.1's changelog.\n\n  * Fixes many links to the PyMuPDF-Utilities repo scripts.\n\n  * Avoid duplication of ``changes.txt`` and ``docs/changes.rst``.\n\n* Build\n\n  * Added ``pyproject.toml`` file to improve builds using pip etc.\n\n\n\n**Changes in Version 1.21.1 (2022-12-13)**\n\n* This release uses ``MuPDF-1.21.1``.\n\n* Bug fixes:\n\n  * **Fixed** `#2110 <https://github.com/pymupdf/PyMuPDF/issues/2110>`_: Fully embedded font is extracted only partially if it occupies more than one object\n  * **Fixed** `#2094 <https://github.com/pymupdf/PyMuPDF/issues/2094>`_: Rectangle Detection Logic\n  * **Fixed** `#2088 <https://github.com/pymupdf/PyMuPDF/issues/2088>`_: Destination point not set for named links in toc\n  * **Fixed** `#2087 <https://github.com/pymupdf/PyMuPDF/issues/2087>`_: Image with Filter \"[/FlateDecode/JPXDecode]\" not extracted\n  * **Fixed** `#2086 <https://github.com/pymupdf/PyMuPDF/issues/2086>`_: Document.save() owner_pw & user_pw has buffer overflow bug\n  * **Fixed** `#2076 <https://github.com/pymupdf/PyMuPDF/issues/2076>`_: Segfault in fitz.py\n  * **Fixed** `#2057 <https://github.com/pymupdf/PyMuPDF/issues/2057>`_: Document.save garbage parameter not working in PyMuPDF 1.21.0\n  * **Fixed** `#2051 <https://github.com/pymupdf/PyMuPDF/issues/2051>`_: Missing DPI Parameter\n  * **Fixed** `#2048 <https://github.com/pymupdf/PyMuPDF/issues/2048>`_: Invalid size of TextPage and bbox with newest version 1.21.0\n  * **Fixed** `#2045 <https://github.com/pymupdf/PyMuPDF/issues/2045>`_: SystemError: <built-in function Page_get_texttrace> returned a result with an error set\n  * **Fixed** `#2039 <https://github.com/pymupdf/PyMuPDF/issues/2039>`_: 1.21.0 fails to build against system libmupdf\n  * **Fixed** `#2036 <https://github.com/pymupdf/PyMuPDF/issues/2036>`_: Archive::Archive defined twice\n\n* Other\n\n  * Swallow \"&zoom=nan\" in link uri strings.\n  * Add new Page utility methods ``Page.replace_image()`` and ``Page.delete_image()``.\n\n* Documentation:\n\n  * `#2040 <https://github.com/pymupdf/PyMuPDF/issues/2040>`_: Added note about test failure with non-default build of MuPDF, to ``tests/README.md``.\n  * `#2037 <https://github.com/pymupdf/PyMuPDF/issues/2037>`_: In ``docs/installation.rst``, mention incompatibility with chocolatey.org on Windows.\n  * `#2061 <https://github.com/pymupdf/PyMuPDF/issues/2061>`_: Fixed description of ``Annot.file_info``.\n  * `#2065 <https://github.com/pymupdf/PyMuPDF/issues/2065>`_: Show how to insert internal PDF link.\n  * Improved description of building from source without an sdist.\n  * Added information about running tests.\n  * `#2084 <https://github.com/pymupdf/PyMuPDF/issues/2084>`_: Fixed broken link to PyMuPDF-Utilities.\n\n\n**Changes in Version 1.21.0 (2022-11-8)**\n\n* This release uses ``MuPDF-1.21.0``.\n\n* New feature: Stories.\n\n* Added wheels for Python-3.11.\n\n* Bug fixes:\n\n  * **Fixed** `#1701 <https://github.com/pymupdf/PyMuPDF/issues/1701>`_: Broken custom image insertion.\n  * **Fixed** `#1854 <https://github.com/pymupdf/PyMuPDF/issues/1854>`_: `Document.delete_pages()` declines keyword arguments.\n  * **Fixed** `#1868 <https://github.com/pymupdf/PyMuPDF/issues/1868>`_: Access Violation Error at `page.apply_redactions()`.\n  * **Fixed** `#1909 <https://github.com/pymupdf/PyMuPDF/issues/1909>`_: Adding text with `fontname=\"Helvetica\"` can silently fail.\n  * **Fixed** `#1913 <https://github.com/pymupdf/PyMuPDF/issues/1913>`_: `draw_rect()`: does not respect width if color is not specified.\n  * **Fixed** `#1917 <https://github.com/pymupdf/PyMuPDF/issues/1917>`_: `subset_fonts()`: make it possible to silence the stdout.\n  * **Fixed** `#1936 <https://github.com/pymupdf/PyMuPDF/issues/1936>`_: Rectangle detection can be incorrect producing wrong output.\n  * **Fixed** `#1945 <https://github.com/pymupdf/PyMuPDF/issues/1945>`_: Segmentation fault when saving with `clean=True`.\n  * **Fixed** `#1965 <https://github.com/pymupdf/PyMuPDF/issues/1965>`_: `pdfocr_save()` Hard Crash.\n  * **Fixed** `#1971 <https://github.com/pymupdf/PyMuPDF/issues/1971>`_: Segmentation fault when using `get_drawings()`.\n  * **Fixed** `#1946 <https://github.com/pymupdf/PyMuPDF/issues/1946>`_: `block_no` and `block_type` switched in `get_text()` docs.\n  * **Fixed** `#2013 <https://github.com/pymupdf/PyMuPDF/issues/2013>`_: AttributeError: 'Widget' object has no attribute '_annot' in delete widget.\n\n* Misc changes to core code:\n\n  * Fixed various compiler warnings and a sequence-point bug.\n  * Added support for Memento builds.\n  * Fixed leaks detected by Memento in test suite.\n  * Fixed handling of exceptions in set_name() and set_rect().\n  * Allow build with latest MuPDF, for regular testing of PyMuPDF master.\n  * Cope with new MuPDF exceptions when setting rect for some Annot types.\n  * Reduced cosmetic differences between MuPDF's config.h and PyMuPDF's _config.h.\n  * Cope with various changes to MuPDF API.\n\n* Other:\n\n  * Fixed various broken links and typos in docs.\n  * Mention install of `swig-python` on MacOS for #875.\n  * Added (untested) wheels for macos-arm64.\n  \n\n\n\n**Changes in Version 1.20.2**\n\n* This release uses ``MuPDF-1.20.3``.\n\n* **Fixed** `#1787 <https://github.com/pymupdf/PyMuPDF/issues/1787>`_.\n  Fix linking issues on Unix systems.\n\n* **Fixed** `#1824 <https://github.com/pymupdf/PyMuPDF/issues/1824>`_.\n  SegFault when applying redactions overlapping a transparent image. (Fixed\n  in ``MuPDF-1.20.3``.)\n\n* Improvements to documentation:\n\n  * Improved information about building from source in ``docs/installation.rst``.\n  * Clarified memory allocation setting ``JM_MEMORY` in ``docs/tools.rst``.\n  * Fixed link to PDF Reference manual in ``docs/app3.rst``.\n  * Fixed building of html documentation on OpenBSD.\n  * Moved old ``docs/faq.rst`` into separate ``docs/recipes-*`` files.\n\n* Removed some unused files and directories:\n\n  * ``installation/``\n  * ``docs/wheelnames.txt``\n\n\n**Changes in Version 1.20.1**\n\n* **Fixed** `#1724 <https://github.com/pymupdf/PyMuPDF/issues/1724>`_.\n  Fix for building on FreeBSD.\n\n* **Fixed** `#1771 <https://github.com/pymupdf/PyMuPDF/issues/1771>`_.\n  `linkDest()` had a broken call to `re.match()`, introduced in 1.20.0.\n\n* **Fixed** `#1751 <https://github.com/pymupdf/PyMuPDF/issues/1751>`_.\n  `get_drawings()` and `get_cdrawings()` previously always returned with `closePath=False`.\n\n* **Fixed** `#1645 <https://github.com/pymupdf/PyMuPDF/issues/1645>`_.\n  Default FreeText annotation text color is now black.\n\n* Improvements to sphinx-generated documentation:\n\n  * Use readthedocs theme with enhancements.\n  * Renamed the `.txt` files to have `.rst` suffixes.\n\n------\n\n**Changes in Version 1.20.0**\n\nThis release uses ``MuPDF-1.20.0``, released 2022-06-15.\n\n* Cope with new MuPDF link uri format, changed from ``#<int>,<int>,<int>`` to ``#page=<int>&zoom=<float>,<float>,<float>``.\n\n * In ``tests/test_insertpdf.py``, use new reference output ``joined-1.20.pdf``. We also check that new output values are approximately the same as the old ones.\n\n* **Fixed** `#1738 <https://github.com/pymupdf/PyMuPDF/issues/1738>`_. Leak of `pdf_graft_map`.\n  Also fixed a SEGV issue that this seemed to expose, caused by incorrect freeing of underlying fz_document.\n\n* **Fixed** `#1733 <https://github.com/pymupdf/PyMuPDF/issues/1733>`_. Fixed ownership of `Annotation.get_pixmap()`.\n\nChanges to build/release process:\n\n* If pip builds from source because an appropriate wheel is not available, we no longer require MuPDF to be pre-installed. Instead the required MuPDF source is embedded in the sdist and automatically built into PyMuPDF.\n\n* Various changes to ``setup.py`` to download the required MuPDF release as required. See comments at start of setup.py for details.\n\n* Added ``.github/workflows/build_wheels.yml`` to control building of wheels on Github.\n\n------\n\n**Changes in Version 1.19.6**\n\n* **Fixed** `#1620 <https://github.com/pymupdf/PyMuPDF/issues/1620>`_. The :ref:`TextPage` created by :meth:`Page.get_textpage` will now be freed correctly (removed memory leak).\n* **Fixed** `#1601 <https://github.com/pymupdf/PyMuPDF/issues/1601>`_. Document open errors should now be more concise and easier to interpret. In the course of this, two PyMuPDF-specific Python exceptions have been **added:**\n\n    - ``EmptyFileError`` -- raised when trying to create a :ref:`Document` (``fitz.open()``) from an empty file or zero-length memory.\n    - ``FileDataError`` -- raised when MuPDF encounters irrecoverable document structure issues.\n\n* **Added** :meth:`Page.load_widget` given a PDF field's xref.\n\n* **Added** Dictionary :attr:`pdfcolor` which provide the about 500 colors defined as PDF color values with the lower case color name as key.\n\n* **Added** algebra functionality to the :ref:`Quad` class. These objects can now also be added and subtracted among themselves, and be multiplied by numbers and matrices.\n\n* **Added** new constants defining the default text extraction flags for more comfortable handling. Their naming convention is like :data:`TEXTFLAGS_WORDS` for ``page.get_text(\"words\")``. See :ref:`text_extraction_flags`.\n\n* **Changed** :meth:`Page.annots` and :meth:`Page.widgets` to detect and prevent reloading the page (illegally) inside the iterator loops via :meth:`Document.reload_page`. Doing this brings down the interpreter. Documented clean ways to do annotation and widget mass updates within properly designed loops.\n\n* **Changed** several internal utility functions to become standalone (\"SWIG inline\") as opposed to be part of the :ref:`Tools` class. This, among other things, increases the performance of geometry object creation.\n\n* **Changed** :meth:`Document.update_stream` to always accept stream updates - whether or not the dictionary object behind the xref already is a stream. Thus the former ``new`` parameter is now ignored and will be removed in v1.20.0.\n\n\n------\n\n**Changes in Version 1.19.5**\n\n* **Fixed** `#1518 <https://github.com/pymupdf/PyMuPDF/issues/1518>`_. A limited \"fix\": in some cases, rectangles and quadrupels were not correctly encoded to support re-drawing by :ref:`Shape`.\n\n* **Fixed** `#1521 <https://github.com/pymupdf/PyMuPDF/issues/1521>`_. This had the same ultimate reason behind issue #1510.\n\n* **Fixed** `#1513 <https://github.com/pymupdf/PyMuPDF/issues/1513>`_. Some Optional Content functions did not support non-ASCII characters.\n\n* **Fixed** `#1510 <https://github.com/pymupdf/PyMuPDF/issues/1510>`_. Support more soft-mask image subtypes.\n\n* **Fixed** `#1507 <https://github.com/pymupdf/PyMuPDF/issues/1507>`_. Immunize against items in the outlines chain, that are ``\"null\"`` objects.\n\n* **Fixed** re-opened `#1417 <https://github.com/pymupdf/PyMuPDF/issues/1417>`_. (\"too many open files\"). This was due to insufficient calls to MuPDF's ``fz_drop_document()``. This also fixes `#1550 <https://github.com/pymupdf/PyMuPDF/issues/1550>`_.\n\n* **Fixed** several undocumented issues in relation to incorrectly setting the text span origin :data:`point_like`.\n\n* **Fixed** undocumented error computing the character bbox in method :meth:`Page.get_texttrace` when text is **flipped** (as opposed to just rotated).\n\n* **Added** items to the dictionary returned by :meth:`image_properties`: ``orientation`` and ``transform`` report the natural image orientation (EXIF data).\n\n* **Added** method :meth:`Document.xref_copy`. It will make a given target PDF object an exact copy of a source object.\n\n\n------\n\n**Changes in Version 1.19.4**\n\n\n* **Fixed** `#1505 <https://github.com/pymupdf/PyMuPDF/issues/1505>`_. Immunize against circular outline items.\n\n* **Fixed** `#1484 <https://github.com/pymupdf/PyMuPDF/issues/1484>`_. Correct CropBox coordinates are now returned in all situations.\n\n* **Fixed** `#1479 <https://github.com/pymupdf/PyMuPDF/issues/1479>`_.\n\n* **Fixed** `#1474 <https://github.com/pymupdf/PyMuPDF/issues/1474>`_. TextPage objects are now properly deleted again.\n\n* **Added** :ref:`Page` methods and attributes for PDF ``/ArtBox``, ``/BleedBox``, ``/TrimBox``.\n\n* **Added** global attribute :attr:`TESSDATA_PREFIX` for easy checking of OCR support.\n\n* **Changed** :meth:`Document.xref_set_key` such that dictionary keys will physically be removed if set to value ``\"null\"``.\n\n* **Changed** :meth:`Document.extract_font` to optionally return a dictionary (instead of a tuple).\n\n------\n\n**Changes in Version 1.19.3**\n\nThis patch version implements minor improvements for :ref:`Pixmap` and also some important fixes.\n\n* **Fixed** `#1351 <https://github.com/pymupdf/PyMuPDF/discussions/1351>`_. Reverted code that introduced the memory growth in v1.18.15.\n\n* **Fixed** `#1417 <https://github.com/pymupdf/PyMuPDF/discussions/1417>`_. Developed circumvention for growth of open file handles using :meth:`Document.insert_pdf`.\n\n* **Fixed** `#1418 <https://github.com/pymupdf/PyMuPDF/discussions/1418>`_. Developed circumvention for memory growth using :meth:`Document.insert_pdf`.\n\n* **Fixed** `#1430 <https://github.com/pymupdf/PyMuPDF/discussions/1430>`_. Developed circumvention for mass pixmap generations of document pages.\n\n* **Fixed** `#1433 <https://github.com/pymupdf/PyMuPDF/discussions/1433>`_. Solves a bbox error for some Type 3 font in PyMuPDF text processing.\n\n* **Added** :meth:`Pixmap.color_topusage` to determine the share of the most frequently used color. Solves `#1397 <https://github.com/pymupdf/PyMuPDF/discussions/1397>`_.\n\n* **Added** :meth:`Pixmap.warp` which makes a new pixmap from a given arbitrary convex quad inside the pixmap.\n\n* **Added** :attr:`Annot.irt_xref` and :meth:`Annot.set_irt_xref` to inquire or set the `/IRT` (\"In Response To\") property of an annotation. Implements `#1450 <https://github.com/pymupdf/PyMuPDF/discussions/1450>`_.\n\n* **Added** :meth:`Rect.torect` and :meth:`IRect.torect` which compute a matrix that transforms to a given other rectangle.\n\n* **Changed** :meth:`Pixmap.color_count` to also return the count of each color.\n* **Changed** :meth:`Page.get_texttrace` to also return correct span and character bboxes if ``span[\"dir\"] != (1, 0)``.\n\n------\n\n**Changes in Version 1.19.2**\n\nThis patch version implements minor improvements for :meth:`Page.get_drawings` and also some important fixes.\n\n* **Fixed** `#1388 <https://github.com/pymupdf/PyMuPDF/discussions/1388>`_. Fixed intermittent memory corruption when insert or updating annotations.\n\n* **Fixed** `#1375 <https://github.com/pymupdf/PyMuPDF/discussions/1375>`_. Inconsistencies between line numbers as returned by the \"words\" and the \"dict\" options of :meth:`Page.get_text` have been corrected.\n\n* **Fixed** `#1364 <https://github.com/pymupdf/PyMuPDF/issues/1342>`_. The check for being a ``\"rawdict\"`` span in :meth:`recover_span_quad` now works correctly.\n\n* **Fixed** `#1342 <https://github.com/pymupdf/PyMuPDF/issues/1364>`_. Corrected the check for rectangle infiniteness in :meth:`Page.show_pdf_page`.\n\n* **Changed** :meth:`Page.get_drawings`, :meth:`Page.get_cdrawings` to return an indicator on the area orientation covered by a rectangle. This implements `#1355 <https://github.com/pymupdf/PyMuPDF/issues/1355>`_. Also, the recognition rate for rectangles and quads has been significantly improved.\n\n* **Changed** all text search and extraction methods to set the new ``flags`` option ``TEXT_MEDIABOX_CLIP`` to ON by default. That bit causes the automatic suppression of all characters that are completely outside a page's mediabox (in as far as that notion is supported for a document type). This eliminates the need for using ``clip=page.rect`` or similar for omitting text outside the visible area.\n\n* **Added** parameter ``\"dpi\"`` to :meth:`Page.get_pixmap` and :meth:`Annot.get_pixmap`. When given, parameter ``\"matrix\"`` is ignored, and a :ref:`Pixmap` with the desired dots per inch is created.\n\n* **Added** attributes :attr:`Pixmap.is_monochrome` and :attr:`Pixmap.is_unicolor` allowing fast checks of pixmap properties. Addresses `#1397 <https://github.com/pymupdf/PyMuPDF/discussions/1397>`_.\n\n* **Added** method :meth:`Pixmap.color_count` to determine the unique colors in the pixmap.\n\n* **Added** boolean parameter ``\"compress\"`` to PDF document method :meth:`Document.update_stream`. Addresses / enables solution for `#1408 <https://github.com/pymupdf/PyMuPDF/discussions/1408>`_.\n\n------\n\n**Changes in Version 1.19.1**\n\nThis is the first patch version to support MuPDF v1.19.0. Apart from one bug fix, it includes important improvements for OCR support and the option to **sort extracted text** to the standard reading order \"from top-left to bottom-right\".\n\n* **Fixed** `#1328 <https://github.com/pymupdf/PyMuPDF/issues/1328>`_. \"words\" text extraction again returns correct ``(x0, y0)`` coordinates.\n\n* **Changed** :meth:`Page.get_textpage_ocr`: it now supports parameter ``dpi`` to control OCR quality. It is also possible to choose whether the **full page** should be OCRed or **only the images displayed** by the page.\n\n* **Changed** :meth:`Page.get_drawings` and :meth:`Page.get_cdrawings` to automatically convert colors to RGB color tuples. Implements `#1332 <https://github.com/pymupdf/PyMuPDF/discussions/1332>`_. Similar change was applied to :meth:`Page.get_texttrace`.\n\n* **Changed** :meth:`Page.get_text` to support a parameter ``sort``. If set to ``True`` the output is conveniently sorted.\n\n\n------\n\n**Changes in Version 1.19.0**\n\nThis is the first version supporting MuPDF 1.19.*, published 2021-10-05. It introduces many new features compared to the previous version 1.18.*.\n\nPyMuPDF has now picked up integrated Tesseract OCR support, which was already present in MuPDF v1.18.0.\n\n* Supported images can be OCRed via their :ref:`Pixmap` which results in a 1-page PDF with a text layer.\n* All supported document pages (i.e. not only PDFs), can be OCRed using specialized text extraction methods. The result is a mixture of standard and OCR text (depending on which part of the page was deemed to require OCRing) that can be searched and extracted without restrictions.\n* All this requires an independent installation of Tesseract. MuPDF actually (only) needs the location of Tesseract's ``\"tessdata\"`` folder, where its language support data are stored. This location must be available as environment variable ``TESSDATA_PREFIX``.\n\nA new MuPDF feature is **journalling PDF updates**, which is also supported by this PyMuPDF version. Changes may be logged, rolled back or replayed, allowing to implement a whole new level of control over PDF document integrity -- similar to functions present in modern database systems.\n\nA third feature (unrelated to the new MuPDF version) includes the ability to detect when page **objects cover or hide each other**. It is now e.g. possible to see that text is covered by a drawing or an image.\n\n* **Changed** terminology and meaning of important geometry concepts: Rectangles are now characterized as *finite*, *valid* or *empty*, while the definitions of these terms have also changed. Rectangles specifically are now thought of being \"open\": not all corners and sides are considered part of the rectangle. Please do read the :ref:`Rect` section for details.\n\n* **Added** new parameter `\"no_new_id\"` to :meth:`Document.save` / :meth:`Document.tobytes` methods. Use it to suppress updating the second item of the document ``/ID`` which in PDF indicates that the original file has been updated. If the PDF has no ``/ID`` at all yet, then no new one will be created either.\n\n* **Added** a **journalling facility** for PDF updates. This allows logging changes, undoing or redoing them, or saving the journal for later use. Refer to :meth:`Document.journal_enable` and friends.\n\n* **Added** new :ref:`Pixmap` methods :meth:`Pixmap.pdfocr_save` and :meth:`Pixmap.pdfocr_tobytes`, which generate a 1-page PDF containing the pixmap as PNG image with OCR text layer.\n\n* **Added** :meth:`Page.get_textpage_ocr` which executes optical character recognition for the page, then extracts the results and stores them together with \"normal\" page content in a :ref:`TextPage`. Use or reuse this object in subsequent text extractions and text searches to avoid multiple efforts. The existing text search and text extraction methods have been extended to support a separately created textpage -- see next item.\n\n* **Added** a new parameter ``textpage`` to text extraction and text search methods. This allows reuse of a previously created :ref:`TextPage` and thus achieves significant runtime benefits -- which is especially important for the new OCR features. But \"normal\" text extractions can definitely also benefit.\n\n* **Added** :meth:`Page.get_texttrace`, a technical method delivering low-level text character properties. It was present before as a private method, but the author felt it now is mature enough to be officially available. It specifically includes a \"sequence number\" which indicates the page appearance build operation that painted the text.\n\n* **Added** :meth:`Page.get_bboxlog` which delivers the list of rectangles of page objects like text, images or drawings. Its significance lies in its sequence: rectangles intersecting areas with a lower index are covering or hiding them.\n\n* **Changed** methods :meth:`Page.get_drawings` and :meth:`Page.get_cdrawings` to include a \"sequence number\" indicating the page appearance build operation that created the drawing.\n\n* **Fixed** `#1311 <https://github.com/pymupdf/PyMuPDF/issues/1311>`_. Field values in comboboxes should now be handled correctly.\n* **Fixed** `#1290 <https://github.com/pymupdf/PyMuPDF/issues/1290>`_. Error was caused by incorrect rectangle emptiness check, which is fixed due to new geometry logic of this version.\n* **Fixed** `#1286 <https://github.com/pymupdf/PyMuPDF/issues/1286>`_. Text alignment for redact annotations is working again.\n* **Fixed** `#1287 <https://github.com/pymupdf/PyMuPDF/issues/1287>`_. Infinite loop issue for non-Windows systems when applying some redactions has been resolved.\n* **Fixed** `#1284 <https://github.com/pymupdf/PyMuPDF/issues/1284>`_. Text layout destruction after applying redactions in some cases has been resolved.\n\n------\n\n**Changes in Version 1.18.18 / 1.18.19**\n\n* **Fixed** issue `#1266 <https://github.com/pymupdf/PyMuPDF/issues/1266>`_. Failure to set :attr:`Pixmap.samples` in important cases, was hotfixed in a new version 1.18.19.\n\n* **Fixed** issue `#1257 <https://github.com/pymupdf/PyMuPDF/issues/1257>`_. Removing the read-only flag from PDF fields is now possible.\n\n* **Fixed** issue `#1252 <https://github.com/pymupdf/PyMuPDF/issues/1252>`_. Now correctly specifying the ``zoom`` value for PDF link annotations.\n\n* **Fixed** issue `#1244 <https://github.com/pymupdf/PyMuPDF/issues/1244>`_. Now correctly computing the transform matrix in :meth:`Page.get_image__bbox`.\n\n* **Fixed** issue `#1241 <https://github.com/pymupdf/PyMuPDF/issues/1241>`_. Prevent returning artifact characters in :meth:`Page.get_textbox`, which happened in certain constellations.\n\n* **Fixed** issue `#1234 <https://github.com/pymupdf/PyMuPDF/issues/1234>`_. Avoid creating infinite rectangles in corner cases -- :meth:`Page.get_drawings`, :meth:`Page.get_cdrawings`.\n\n* **Added** test data and test scripts to the source PyPI source distribution.\n\n------\n\n**Changes in Version 1.18.17**\n\nFocus of this version are major performance improvements of selected functions.\n\n* **Fixed** issue `#1199 <https://github.com/pymupdf/PyMuPDF/issues/1199>`_. Using a non-existing page number in :meth:`Document.get_page_images` and friends will no longer lead to segfaults.\n\n* **Changed** :meth:`Page.get_drawings` to now differentiate between \"stroke\", \"fill\" and combined paths. Paths containing more than one rectangle (i.e. \"re\" items) are now supported. Extracting \"clipped\" paths is now available as an option.\n\n* **Added** :meth:`Page.get_cdrawings`, performance-optimized version of :meth:`Page.get_drawings`.\n\n* **Added** :attr:`Pixmap.samples_mv`, *memoryview* of a pixmap's pixel area. Does not copy and thus always accesses the current state of that area.\n\n* **Added** :attr:`Pixmap.samples_ptr`, Python \"pointer\" to a pixmap's pixel area. Allows much faster creation (factor 800+) of Qt images.\n\n\n\n------\n\n**Changes in Version 1.18.16**\n\n* **Fixed** issue `#1184 <https://github.com/pymupdf/PyMuPDF/issues/1184>`_. Existing PDF widget fonts in a PDF are now accepted (i.e. not forcedly changed to a Base-14 font).\n\n* **Fixed** issue `#1154 <https://github.com/pymupdf/PyMuPDF/issues/1154>`_. Text search hits should now be correct when ``clip`` is specified.\n\n* **Fixed** issue `#1152 <https://github.com/pymupdf/PyMuPDF/issues/1152>`_.\n\n* **Fixed** issue `#1146 <https://github.com/pymupdf/PyMuPDF/issues/1146>`_.\n\n* **Added** :attr:`Link.flags` and :meth:`Link.set_flags` to the :ref:`Link` class. Implements enhancement requests `#1187 <https://github.com/pymupdf/PyMuPDF/issues/1187>`_.\n\n* **Added** option to *simulate* :meth:`TextWriter.fill_textbox` output for predicting the number of lines, that a given text would occupy in the textbox.\n\n* **Added** text output support as subcommand `gettext` to the ``fitz`` CLI module. Most importantly, original **physical text layout** reproduction is now supported.\n\n\n------\n\n**Changes in Version 1.18.15**\n\n* **Fixed** issue `#1088 <https://github.com/pymupdf/PyMuPDF/issues/1088>`_. Removing an annotation's fill color should now work again both ways, using the ``fill_color=[]`` argument in :meth:`Annot.update` as well as ``fill=[]`` in :meth:`Annot.set_colors`.\n\n* **Fixed** issue `#1081 <https://github.com/pymupdf/PyMuPDF/issues/1081>`_. :meth:`Document.subset_fonts`: fixed an error which created wrong character widths for some fonts.\n\n* **Fixed** issue `#1078 <https://github.com/pymupdf/PyMuPDF/issues/1078>`_. :meth:`Page.get_text` and other methods related to text extraction: changed the default value of the :ref:`TextPage` ``flags`` parameter. All whitespace and :data:`ligatures` are now preserved.\n\n* **Fixed** issue `#1085 <https://github.com/pymupdf/PyMuPDF/issues/1085>`_. The old *snake_cased* alias of ``fitz.detTextlength`` is now defined correctly.\n\n* **Changed** :meth:`Document.subset_fonts` will now correctly prefix font subsets with an appropriate six letter uppercase tag, complying with the PDF specification.\n\n* **Added** new method :meth:`Widget.button_states` which returns the possible values that a button-type field can have when being set to \"on\" or \"off\".\n\n* **Added** support of text with **Small Capital** letters to the :ref:`Font` and :ref:`TextWriter` classes. This is reflected by an additional bool parameter ``small_caps`` in various of their methods.\n\n\n------\n\n**Changes in Version 1.18.14**\n\n* **Finished** implementing new, \"snake_cased\" names for methods and properties, that were \"camelCased\" and awkward in many aspects. At the end of this documentation, there is section :ref:`Deprecated` with more background and a mapping of old to new names.\n\n* **Fixed** issue `#1053 <https://github.com/pymupdf/PyMuPDF/issues/1053>`_. :meth:`Page.insert_image`: when given, include image mask in the hash computation.\n\n* **Fixed** issue `#1043 <https://github.com/pymupdf/PyMuPDF/issues/1043>`_. Added ``Pixmap.getPNGdata`` to the aliases of :meth:`Pixmap.tobytes`.\n\n* **Fixed** an internal error when computing the enveloping rectangle of drawn paths as returned by :meth:`Page.get_drawings`.\n\n* **Fixed** an internal error occasionally causing loops when outputting text via :meth:`TextWriter.fill_textbox`.\n\n* **Added** :meth:`Font.char_lengths`, which returns a tuple of character widths of a string.\n\n* **Added** more ways to specify pages in :meth:`Document.delete_pages`. Now a sequence (list, tuple or range) can be specified, and the Python ``del`` statement can be used. In the latter case, Python ``slices`` are also accepted.\n\n* **Changed** :meth:`Document.del_toc_item`, which disables a single item of the TOC: previously, the title text was removed. Instead, now the complete item will be shown grayed-out by supporting viewers.\n\n\n------\n\n**Changes in Version 1.18.13**\n\n* **Fixed** issue `#1014 <https://github.com/pymupdf/PyMuPDF/issues/1014>`_.\n* **Fixed** an internal memory leak when computing image bboxes -- :meth:`Page.get_image_bbox`.\n* **Added** support for low-level access and modification of the PDF trailer. Applies to :meth:`Document.xref_get_keys`, :meth:`Document.xref_get_key`, and :meth:`Document.xref_set_key`.\n* **Added** documentation for maintaining private entries in PDF metadata.\n* **Added** documentation for handling transparent image insertions, :meth:`Page.insert_image`.\n* **Added** :meth:`Page.get_image_rects`, an improved version of :meth:`Page.get_image_bbox`.\n* **Changed** :meth:`Document.delete_pages` to support various ways of specifying pages to delete. Implements `#1042 <https://github.com/pymupdf/PyMuPDF/issues/1042>`_.\n* **Changed** :meth:`Page.insert_image` to also accept the xref of an existing image in the file. This allows \"copying\" images between pages, and extremely fast multiple insertions.\n* **Changed** :meth:`Page.insert_image` to also accept the integer parameter ``alpha``. To be used for performance improvements.\n* **Changed** :meth:`Pixmap.set_alpha` to support new parameters for pre-multiplying colors with their alpha values and setting a specific color to fully transparent (e.g. white).\n* **Changed** :meth:`Document.embfile_add` to automatically set creation and modification date-time. Correspondingly, :meth:`Document.embfile_upd` automatically maintains modification date-time (``/ModDate`` PDF key), and :meth:`Document.embfile_info` correspondingly reports these data. In addition, the embedded file's associated \"collection item\" is included via its :data:`xref`. This supports the development of PDF portfolio applications.\n\n------\n\n**Changes in Version 1.18.11 / 1.18.12**\n\n* **Fixed** issue `#972 <https://github.com/pymupdf/PyMuPDF/issues/972>`_. Improved layout of source distribution material.\n* **Fixed** issue `#962 <https://github.com/pymupdf/PyMuPDF/issues/962>`_. Stabilized Linux distribution detection for generating PyMuPDF from sources.\n* **Added:** :meth:`Page.get_xobjects` delivers the result of :meth:`Document.get_page_xobjects`.\n* **Added:** :meth:`Page.get_image_info` delivers meta information for all images shown on the page.\n* **Added:** :meth:`Tools.mupdf_display_warnings` allows setting on / off the display of MuPDF-generated warnings. The default is off.\n* **Added:** :meth:`Document.ez_save` convenience alias of :meth:`Document.save` with some different defaults.\n* **Changed:** Image extractions of document pages now also contain the image's **transformation matrix**. This concerns :meth:`Page.get_image_bbox` and the DICT, JSON, RAWDICT, and RAWJSON variants of :meth:`Page.get_text`.\n\n\n------\n\n**Changes in Version 1.18.10**\n\n* **Fixed** issue `#941 <https://github.com/pymupdf/PyMuPDF/issues/941>`_. Added old aliases for :meth:`DisplayList.get_pixmap` and :meth:`DisplayList.get_textpage`.\n* **Fixed** issue `#929 <https://github.com/pymupdf/PyMuPDF/issues/929>`_. Stabilized removal of JavaScript objects with :meth:`Document.scrub`.\n* **Fixed** issue `#927 <https://github.com/pymupdf/PyMuPDF/issues/927>`_. Removed a loop in the reworked :meth:`TextWriter.fill_textbox`.\n* **Changed** :meth:`Document.xref_get_keys` and :meth:`Document.xref_get_key` to also allow accessing the PDF trailer dictionary. This can be done by using `-1` as the xref number argument.\n* **Added** a number of functions for reconstructing the quads for text lines, spans and characters extracted by :meth:`Page.get_text` options \"dict\" and \"rawdict\". See :meth:`recover_quad` and friends.\n* **Added** :meth:`Tools.unset_quad_corrections` to suppress character quad corrections (occasionally required for erroneous fonts).\n\n------\n\n**Changes in Version 1.18.9**\n\n\n* **Fixed** issue `#888 <https://github.com/pymupdf/PyMuPDF/issues/888>`_. Removed ambiguous statements concerning PyMuPDF's license, which is now clearly stated to be GNU AGPL V3.\n* **Fixed** issue `#895 <https://github.com/pymupdf/PyMuPDF/issues/895>`_.\n* **Fixed** issue `#896 <https://github.com/pymupdf/PyMuPDF/issues/896>`_. Since v1.17.6 PyMuPDF suppresses the font subset tags and only reports the base fontname in text extraction outputs \"dict\" / \"json\" / \"rawdict\" / \"rawjson\". Now a new global parameter can request the old behaviour, :meth:`Tools.set_subset_fontnames`.\n* **Fixed** issue `#885 <https://github.com/pymupdf/PyMuPDF/issues/885>`_. Pixmap creation now also works with filenames given as ``pathlib.Paths``.\n* **Changed** :meth:`Document.subset_fonts`: Text is **not rewritten** any more and should therefore **retain all its original properties** -- like being hidden or being controlled by Optional Content mechanisms.\n* **Changed** :ref:`TextWriter` output to also accept text in right to left mode (Arabian, Hebrew): :meth:`TextWriter.fill_textbox`, :meth:`TextWriter.append`. These methods now accept a new boolean parameter `right_to_left`, which is *False* by default. Implements `#897 <https://github.com/pymupdf/PyMuPDF/issues/897>`_.\n* **Changed** :meth:`TextWriter.fill_textbox` to return all lines of text, that did not fit in the given rectangle. Also changed the default of the ``warn`` parameter to no longer print a warning message in overflow situations.\n* **Added** a utility function :meth:`recover_quad`, which computes the quadrilateral of a span. This function can be used for correctly marking text extracted with the \"dict\" or \"rawdict\" options of :meth:`Page.get_text`.\n\n------\n\n**Changes in Version 1.18.8**\n\n\nThis is a bug fix version only. We are publishing early because of the potentially widely used functions.\n\n* **Fixed** issue `#881 <https://github.com/pymupdf/PyMuPDF/issues/881>`_. Fixed a memory leak in :meth:`Page.insert_image` when inserting images from files or memory.\n* **Fixed** issue `#878 <https://github.com/pymupdf/PyMuPDF/issues/878>`_. ``pathlib.Path`` objects should now correctly handle file path hierarchies.\n\n\n------\n\n**Changes in Version 1.18.7**\n\n\n* **Added** an experimental :meth:`Document.subset_fonts` which reduces the size of eligible fonts based on their use by text in the PDF. Implements `#855 <https://github.com/pymupdf/PyMuPDF/discussions/855>`_.\n* **Implemented** request `#870 <https://github.com/pymupdf/PyMuPDF/pull/870>`_: :meth:`Document.convert_to_pdf` now also supports PDF documents.\n* **Renamed** ``Document.write`` to :meth:`Document.tobytes` for greater clarity. But the deprecated name remains available for some time.\n* **Implemented** request `#843 <https://github.com/pymupdf/PyMuPDF/Discussions/843>`_: :meth:`Document.tobytes` now supports linearized PDF output. :meth:`Document.save` now also supports writing to Python **file objects**. In addition, the open function now also supports Python file objects.\n* **Fixed** issue `#844 <https://github.com/pymupdf/PyMuPDF/issues/844>`_.\n* **Fixed** issue `#838 <https://github.com/pymupdf/PyMuPDF/issues/838>`_.\n* **Fixed** issue `#823 <https://github.com/pymupdf/PyMuPDF/issues/823>`_. More logic for better support of OCRed text output (Tesseract, ABBYY).\n* **Fixed** issue `#818 <https://github.com/pymupdf/PyMuPDF/issues/818>`_.\n* **Fixed** issue `#814 <https://github.com/pymupdf/PyMuPDF/issues/814>`_.\n* **Added** :meth:`Document.get_page_labels` which returns a list of page label definitions of a PDF.\n* **Added** :meth:`Document.has_annots` and :meth:`Document.has_links` to check whether these object types are present anywhere in a PDF.\n* **Added** expert low-level functions to simplify inquiry and modification of PDF object sources: :meth:`Document.xref_get_keys` lists the keys of object :data:`xref`, :meth:`Document.xref_get_key` returns type and content of a key, and :meth:`Document.xref_set_key` modifies the key's value.\n* **Added** parameter ``thumbnails`` to :meth:`Document.scrub` to also allow removing page thumbnail images.\n* **Improved** documentation for how to add valid text marker annotations for non-horizontal text.\n\nWe continued the process of renaming methods and properties from *\"mixedCase\"* to *\"snake_case\"*. Documentation usually mentions the new names only, but old, deprecated names remain available for some time.\n\n\n\n------\n\n**Changes in Version 1.18.6**\n\n* **Fixed** issue `#812 <https://github.com/pymupdf/PyMuPDF/issues/812>`_.\n* **Fixed** issue `#793 <https://github.com/pymupdf/PyMuPDF/issues/793>`_. Invalid document metadata previously prevented opening some documents at all. This error has been removed.\n* **Fixed** issue `#792 <https://github.com/pymupdf/PyMuPDF/issues/792>`_. Text search and text extraction will make no rectangle containment checks at all if the default ``clip=None`` is used.\n* **Fixed** issue `#785 <https://github.com/pymupdf/PyMuPDF/issues/785>`_.\n* **Fixed** issue `#780 <https://github.com/pymupdf/PyMuPDF/issues/780>`_. Corrected a parameter check error.\n* **Fixed** issue `#779 <https://github.com/pymupdf/PyMuPDF/issues/779>`_. Fixed typo\n* **Added** an option to set the desired line height for text boxes. Implements `#804 <https://github.com/pymupdf/PyMuPDF/issues/804>`_.\n* **Changed** text position retrieval to better cope with Tesseract's glyphless font. Implements `#803 <https://github.com/pymupdf/PyMuPDF/issues/803>`_.\n* **Added** an option to choose the prefix of new annotations, fields and links for providing unique annotation ids. Implements request `#807 <https://github.com/pymupdf/PyMuPDF/issues/807>`_.\n* **Added** getting and setting color and text properties for Table of Contents items for PDFs. Implements `#779 <https://github.com/pymupdf/PyMuPDF/issues/779>`_.\n* **Added** PDF page label handling: :meth:`Page.get_label()` returns the page label, :meth:`Document.get_page_numbers` return all page numbers having a specified label, and :meth:`Document.set_page_labels` adds or updates a PDF's page label definition.\n\n\n\n.. note::\n   This version introduces **Python type hinting**. The goal is to provide each parameter and the return value of all functions and methods with type information. This still is work in progress although the majority of functions has already been handled.\n\n\n------\n\n**Changes in Version 1.18.5**\n\nApart from several fixes, this version also focusses on several minor, but important feature improvements. Among the latter is a more precise computation of proper line heights and insertion points for writing / inserting text. As opposed to using font-agnostic constants, these values are now taken from the font's properties.\n\nAlso note that this is the first version which does no longer provide pregenerated wheels for Python versions older than 3.6. PIP also discontinues support for these by end of this year 2020.\n\n* **Fixed** issue `#771 <https://github.com/pymupdf/PyMuPDF/issues/771>`_. By using \"small glyph heights\" option, the full page text can be extracted.\n* **Fixed** issue `#768 <https://github.com/pymupdf/PyMuPDF/issues/768>`_.\n* **Fixed** issue `#750 <https://github.com/pymupdf/PyMuPDF/issues/750>`_.\n* **Fixed** issue `#739 <https://github.com/pymupdf/PyMuPDF/issues/739>`_. The \"dict\", \"rawdict\" and corresponding JSON output variants now have two new *span* keys: ``\"ascender\"`` and ``\"descender\"``. These floats represent special font properties which can be used to compute bboxes of spans or characters of **exactly fontsize height** (as opposed to the default line height). An example algorithm is shown in section \"Span Dictionary\" `here <https://pymupdf.readthedocs.io/en/latest/textpage.html#dictionary-structure-of-extractdict-and-extractrawdict>`_. Also improved the detection and correction of ill-specified ascender / descender values encountered in some fonts.\n* **Added** a new, experimental :meth:`Tools.set_small_glyph_heights` -- also in response to issue `#739 <https://github.com/pymupdf/PyMuPDF/issues/739>`_. This method sets or unsets a global parameter to **always compute bboxes with fontsize height**. If \"on\", text searching and all text extractions will returned rectangles, bboxes and quads with a smaller height.\n* **Fixed** issue `#728 <https://github.com/pymupdf/PyMuPDF/issues/728>`_.\n* **Changed** fill color logic of 'Polyline' annotations: this parameter now only pertains to line end symbols -- the annotation itself can no longer have a fill color. Also addresses issue `#727 <https://github.com/pymupdf/PyMuPDF/issues/727>`_.\n* **Changed** :meth:`Page.getImageBbox` to also compute the bbox if the image is contained in an XObject.\n* **Changed** :meth:`Shape.insertTextbox`, resp. :meth:`Page.insertTextbox`, resp. :meth:`TextWriter.fillTextbox` to respect font's properties \"ascender\" / \"descender\" when computing line height and insertion point. This should no longer lead to line overlaps for multi-line output. These methods used to ignore font specifics and used constant values instead.\n\n\n------\n\n**Changes in Version 1.18.4**\n\nThis version adds several features to support PDF Optional Content. Among other things, this includes OCMDs (Optional Content Membership Dictionaries) with the full scope of *\"visibility expressions\"* (PDF key ``/VE``), text insertions (including the :ref:`TextWriter` class) and drawings.\n\n* **Fixed** issue `#727 <https://github.com/pymupdf/PyMuPDF/issues/727>`_. Freetext annotations now support an uncolored rectangle when ``fill_color=None``.\n* **Fixed** issue `#726 <https://github.com/pymupdf/PyMuPDF/issues/726>`_. UTF-8 encoding errors are now handled for HTML / XML :meth:`Page.getText` output.\n* **Fixed** issue `#724 <https://github.com/pymupdf/PyMuPDF/issues/724>`_. Empty values are no longer stored in the PDF /Info metadata dictionary.\n* **Added** new methods :meth:`Document.set_oc` and :meth:`Document.get_oc` to set or get optional content references for **existing** image and form XObjects. These methods are similar to the same-named methods of :ref:`Annot`.\n* **Added** :meth:`Document.set_ocmd`, :meth:`Document.get_ocmd` for handling OCMDs.\n* **Added** **Optional Content** support for text insertion and drawing.\n* **Added** new method :meth:`Page.deleteWidget`, which deletes a form field from a page. This is analogous to deleting annotations.\n* **Added** support for Popup annotations. This includes defining the Popup rectangle and setting the Popup to open or closed. Methods / attributes :meth:`Annot.set_popup`, :meth:`Annot.set_open`, :attr:`Annot.has_popup`, :attr:`Annot.is_open`, :attr:`Annot.popup_rect`, :attr:`Annot.popup_xref`.\n\nOther changes:\n\n* The **naming of methods and attributes** in PyMuPDF is far from being satisfactory: we have *CamelCases*, *mixedCases* and *lower_case_with_underscores* all over the place. With the :ref:`Annot` as the first candidate, we have started an activity to clean this up step by step, converting to lower case with underscores for methods and attributes while keeping UPPERCASE for the constants.\n\n   - Old names will remain available to prevent code breaks, but they will no longer be mentioned in the documentation.\n   - New methods and attributes of all classes will be named according to the new standard.\n\n------\n\n**Changes in Version 1.18.3**\n\nAs a major new feature, this version introduces support for PDF's **Optional Content** concept.\n\n* **Fixed** issue `#714 <https://github.com/pymupdf/PyMuPDF/issues/714>`_.\n* **Fixed** issue `#711 <https://github.com/pymupdf/PyMuPDF/issues/711>`_.\n* **Fixed** issue `#707 <https://github.com/pymupdf/PyMuPDF/issues/707>`_: if a PDF user password, but no owner password is supplied nor present, then the user password is also used as the owner password.\n* **Fixed** ``expand`` and ``deflate`` parameters of methods :meth:`Document.save` and :meth:`Document.write`. Individual image and font compression should now finally work. Addresses issue `#713 <https://github.com/pymupdf/PyMuPDF/issues/713>`_.\n* **Added** a support of PDF optional content. This includes several new :ref:`Document` methods for inquiring and setting optional content status and adding optional content configurations and groups. In addition, images, form XObjects and annotations now can be bound to optional content specifications. **Resolved** issue `#709 <https://github.com/pymupdf/PyMuPDF/issues/709>`_.\n\n\n\n------\n\n**Changes in Version 1.18.2**\n\nThis version contains some interesting improvements for text searching: any number of search hits is now returned and the **hit_max** parameter was removed. The new **clip** parameter in addition allows to restrict the search area. Searching now detects hyphenations at line breaks and accordingly finds hyphenated words.\n\n* **Fixed** issue `#575 <https://github.com/pymupdf/PyMuPDF/issues/575>`_: if using ``quads=False`` in text searching, then overlapping rectangles on the same line are joined. Previously, parts of the search string, which belonged to different \"marked content\" items, each generated their own rectangle -- just as if occurring on separate lines.\n* **Added** :attr:`Document.isRepaired`, which is true if the PDF was repaired on open.\n* **Added** :meth:`Document.setXmlMetadata` which either updates or creates PDF XML metadata. Implements issue `#691 <https://github.com/pymupdf/PyMuPDF/issues/691>`_.\n* **Added** :meth:`Document.getXmlMetadata` returns PDF XML metadata.\n* **Changed** creation of PDF documents: they will now always carry a PDF identification (``/ID`` field) in the document trailer. Implements issue `#691 <https://github.com/pymupdf/PyMuPDF/issues/691>`_.\n* **Changed** :meth:`Page.searchFor`: a new parameter ``clip`` is accepted to restrict the search to this rectangle. Correspondingly, the attribute :attr:`TextPage.rect` is now respected by :meth:`TextPage.search`.\n* **Changed** parameter ``hit_max`` in :meth:`Page.searchFor` and :meth:`TextPage.search` is now obsolete: methods will return all hits.\n* **Changed** character **selection criteria** in :meth:`Page.getText`: a character is now considered to be part of a ``clip`` if its bbox is fully contained. Before this, a non-empty intersection was sufficient.\n* **Changed** :meth:`Document.scrub` to support a new option `redact_images`. This addresses issue `#697 <https://github.com/pymupdf/PyMuPDF/issues/697>`_.\n\n\n------\n\n**Changes in Version 1.18.1**\n\n* **Fixed** issue `#692 <https://github.com/pymupdf/PyMuPDF/issues/692>`_. PyMuPDF now detects and recovers from more cyclic resource dependencies in PDF pages and for the first time reports them in the MuPDF warnings store.\n* **Fixed** issue `#686 <https://github.com/pymupdf/PyMuPDF/issues/686>`_.\n* **Added** opacity options for the :ref:`Shape` class: Stroke and fill colors can now be set to some transparency value. This means that all :ref:`Page` draw methods, methods :meth:`Page.insertText`, :meth:`Page.insertTextbox`, :meth:`Shape.finish`, :meth:`Shape.insertText`, and :meth:`Shape.insertTextbox` support two new parameters: *stroke_opacity* and *fill_opacity*.\n* **Added** new parameter ``mask`` to :meth:`Page.insertImage` for optionally providing an external image mask. Resolves issue `#685 <https://github.com/pymupdf/PyMuPDF/issues/685>`_.\n* **Added** :meth:`Annot.soundGet` for extracting the sound of an audio annotation.\n\n------\n\n**Changes in Version 1.18.0**\n\nThis is the first PyMuPDF version supporting MuPDF v1.18. The focus here is on extending PyMuPDF's own functionality -- apart from bug fixing. Subsequent PyMuPDF patches may address features new in MuPDF.\n\n* **Fixed** issue `#519 <https://github.com/pymupdf/PyMuPDF/issues/519>`_. This upstream bug occurred occasionally for some pages only and seems to be fixed now: page layout should no longer be ruined in these cases.\n\n* **Fixed** issue `#675 <https://github.com/pymupdf/PyMuPDF/issues/675>`_.\n\n  - Unsuccessful storage allocations should now always lead to exceptions (circumvention of an upstream bug intermittently crashing the interpreter).\n  - :ref:`Pixmap` size is now based on ``size_t`` instead of ``int`` in C and should be correct even for extremely large pixmaps.\n\n* **Fixed** issue `#668 <https://github.com/pymupdf/PyMuPDF/issues/668>`_. Specification of dashes for PDF drawing insertion should now correctly reflect the PDF spec.\n* **Fixed** issue `#669 <https://github.com/pymupdf/PyMuPDF/issues/669>`_. A major source of memory leakage in :meth:`Page.insert_pdf` has been removed.\n* **Added** keyword *\"images\"* to :meth:`Page.apply_redactions` for fine-controlling the handling of images.\n* **Added** :meth:`Annot.getText` and :meth:`Annot.getTextbox`, which offer the same functionality as the :ref:`Page` versions.\n* **Added** key *\"number\"* to the block dictionaries of :meth:`Page.getText` / :meth:`Annot.getText` for options \"dict\" and \"rawdict\".\n* **Added** :meth:`glyph_name_to_unicode` and :meth:`unicode_to_glyph_name`. Both functions do not really connect to a specific font and are now independently available, too. The data are now based on the `Adobe Glyph List <https://github.com/adobe-type-tools/agl-aglfn/blob/master/glyphlist.txt>`_.\n* **Added** convenience functions :meth:`adobe_glyph_names` and :meth:`adobe_glyph_unicodes` which return the respective available data.\n* **Added** :meth:`Page.getDrawings` which returns details of drawing operations on a document page. Works for all document types.\n* Improved performance of :meth:`Document.insert_pdf`. Multiple object copies are now also suppressed across multiple separate insertions from the same source. This saves time, memory and target file size. Previously this mechanism was only active within each single method execution. The feature can also be suppressed with the new method bool parameter *final=1*, which is the default.\n* For PNG images created from pixmaps, the resolution (dpi) is now automatically set from the respective :attr:`Pixmap.xres` and :attr:`Pixmap.yres` values.\n\n\n------\n\n**Changes in Version 1.17.7**\n\n* **Fixed** issue `#651 <https://github.com/pymupdf/PyMuPDF/issues/651>`_. An upstream bug causing interpreter crashes in corner case redaction processings was fixed by backporting MuPDF changes from their development repo.\n* **Fixed** issue `#645 <https://github.com/pymupdf/PyMuPDF/issues/645>`_. Pixmap top-left coordinates can be set (again) by their own method, :meth:`Pixmap.set_origin`.\n* **Fixed** issue `#622 <https://github.com/pymupdf/PyMuPDF/issues/622>`_. :meth:`Page.insertImage` again accepts a :data:`rect_like` parameter.\n* **Added** several new methods to improve and speed-up table of contents (TOC) handling. Among other things, TOC items can now changed or deleted individually -- without always replacing the complete TOC. Furthermore, access to some PDF page attributes is now possible without first **loading** the page. This has a very significant impact on the performance of TOC manipulation.\n* **Added** an option to :meth:`Document.insert_pdf` which allows displaying progress messages. Addresses `#640 <https://github.com/pymupdf/PyMuPDF/issues/640>`_.\n* **Added** :meth:`Page.getTextbox` which extracts text contained in a rectangle. In many cases, this should obsolete writing your own script for this type of thing.\n* **Added** new ``clip`` parameter to :meth:`Page.getText` to simplify and speed up text extraction of page sub areas.\n* **Added** :meth:`TextWriter.appendv` to add text in **vertical write mode**. Addresses issue `#653 <https://github.com/pymupdf/PyMuPDF/issues/653>`_\n\n\n------\n\n**Changes in Version 1.17.6**\n\n* **Fixed** issue `#605 <https://github.com/pymupdf/PyMuPDF/issues/605>`_\n* **Fixed** issue `#600 <https://github.com/pymupdf/PyMuPDF/issues/600>`_ -- text should now be correctly positioned also for pages with a CropBox smaller than MediaBox.\n* **Added** text span dictionary key ``origin`` which contains the lower left coordinate of the first character in that span.\n* **Added** attribute :attr:`Font.buffer`, a *bytes* copy of the font file.\n* **Added** parameter *sanitize* to :meth:`Page.cleanContents`. Allows switching of sanitization, so only syntax cleaning will be done.\n\n------\n\n**Changes in Version 1.17.5**\n\n* **Fixed** issue `#561 <https://github.com/pymupdf/PyMuPDF/issues/561>`_ -- second go: certain :ref:`TextWriter` usages with many alternating fonts did not work correctly.\n* **Fixed** issue `#566 <https://github.com/pymupdf/PyMuPDF/issues/566>`_.\n* **Fixed** issue `#568 <https://github.com/pymupdf/PyMuPDF/issues/568>`_.\n* **Fixed** -- opacity is now correctly taken from the :ref:`TextWriter` object, if not given in :meth:`TextWriter.writeText`.\n* **Added** a new global attribute :attr:`fitz_fontdescriptors`. Contains information about usable fonts from repository `pymupdf-fonts <https://github.com/pymupdf/pymupdf-fonts>`_.\n* **Added** :meth:`Font.valid_codepoints` which returns an array of unicode codepoints for which the font has a glyph.\n* **Added** option ``text_as_path`` to :meth:`Page.getSVGimage`. this implements `#580 <https://github.com/pymupdf/PyMuPDF/issues/580>`_. Generates much smaller SVG files with parseable text if set to *False*.\n\n\n------\n\n**Changes in Version 1.17.4**\n\n* **Fixed** issue `#561 <https://github.com/pymupdf/PyMuPDF/issues/561>`_. Handling of more than 10 :ref:`Font` objects on one page should now work correctly.\n* **Fixed** issue `#562 <https://github.com/pymupdf/PyMuPDF/issues/562>`_. Annotation pixmaps are no longer derived from the page pixmap, thus avoiding unintended inclusion of page content.\n* **Fixed** issue `#559 <https://github.com/pymupdf/PyMuPDF/issues/559>`_. This **MuPDF** bug is being temporarily fixed with a pre-version of MuPDF's next release.\n* **Added** utility function :meth:`repair_mono_font` for correcting displayed character spacing for some mono-spaced fonts.\n* **Added** utility method :meth:`Document.need_appearances` for fine-controlling Form PDF behavior. Addresses issue `#563 <https://github.com/pymupdf/PyMuPDF/issues/563>`_.\n* **Added** utility function :meth:`sRGB_to_pdf` to recover the PDF color triple for a given color integer in sRGB format.\n* **Added** utility function :meth:`sRGB_to_rgb` to recover the (R, G, B) color triple for a given color integer in sRGB format.\n* **Added** utility function :meth:`make_table` which delivers table cells for a given rectangle and desired numbers of columns and rows.\n* **Added** support for optional fonts in repository `pymupdf-fonts <https://github.com/pymupdf/pymupdf-fonts>`_.\n\n------\n\n**Changes in Version 1.17.3**\n\n* **Fixed** an undocumented issue, which prevented fully cleaning a PDF page when using :meth:`Page.cleanContents`.\n* **Fixed** issue `#540 <https://github.com/pymupdf/PyMuPDF/issues/540>`_. Text extraction for EPUB should again work correctly.\n* **Fixed** issue `#548 <https://github.com/pymupdf/PyMuPDF/issues/548>`_. Documentation now includes ``LINK_NAMED``.\n* **Added** new parameter to control start of text in :meth:`TextWriter.fillTextbox`. Implements `#549 <https://github.com/pymupdf/PyMuPDF/issues/549>`_.\n* **Changed** documentation of :meth:`Page.add_redact_annot` to explain the usage of non-builtin fonts.\n\n------\n\n**Changes in Version 1.17.2**\n\n* **Fixed** issue `#533 <https://github.com/pymupdf/PyMuPDF/issues/533>`_.\n* **Added** options to modify 'Redact' annotation appearance. Implements `#535 <https://github.com/pymupdf/PyMuPDF/issues/535>`_.\n\n\n------\n\n**Changes in Version 1.17.1**\n\n* **Fixed** issue `#520 <https://github.com/pymupdf/PyMuPDF/issues/520>`_.\n* **Fixed** issue `#525 <https://github.com/pymupdf/PyMuPDF/issues/525>`_. Vertices for 'Ink' annots should now be correct.\n* **Fixed** issue `#524 <https://github.com/pymupdf/PyMuPDF/issues/524>`_. It is now possible to query and set rotation for applicable annotation types.\n\nAlso significantly improved inline documentation for better support of interactive help.\n\n------\n\n**Changes in Version 1.17.0**\n\nThis version is based on MuPDF v1.17. Following are highlights of new and changed features:\n\n* **Added** extended language support for annotations and widgets: a mixture of Latin, Greece, Russian, Chinese, Japanese and Korean characters can now be used in 'FreeText' annotations and text widgets. No special arrangement is required to use it.\n\n* Faster page access is implemented for documents supporting a \"chapter\" structure. This applies to EPUB documents currently. This comes with several new :ref:`Document` methods and changes for :meth:`Document.loadPage` and the \"indexed\" page access *doc[n]*: In addition to specifying a page number as before, a tuple *(chapter, pno)* can be specified to identify the desired page.\n\n* **Changed:** Improved support of redaction annotations: images overlapped by redactions are **permanently modified** by erasing the overlap areas. Also links are removed if overlapped by redactions. This is now fully in sync with PDF specifications.\n\nOther changes:\n\n* **Changed** :meth:`TextWriter.writeText` to support the *\"morph\"* parameter.\n* **Added** methods :meth:`Rect.morph`, :meth:`IRect.morph`, and :meth:`Quad.morph`, which return a new :ref:`Quad`.\n* **Changed** :meth:`Page.add_freetext_annot` to support text alignment via a new *\"align\"* parameter.\n* **Fixed** issue `#508 <https://github.com/pymupdf/PyMuPDF/issues/508>`_. Improved image rectangle calculation to hopefully deliver correct values in most if not all cases.\n* **Fixed** issue `#502 <https://github.com/pymupdf/PyMuPDF/issues/502>`_.\n* **Fixed** issue `#500 <https://github.com/pymupdf/PyMuPDF/issues/500>`_. :meth:`Document.convertToPDF` should no longer cause memory leaks.\n* **Fixed** issue `#496 <https://github.com/pymupdf/PyMuPDF/issues/496>`_. Annotations and widgets / fields are now added or modified using the coordinates of the **unrotated page**. This behavior is now in sync with other methods modifying PDF pages.\n* **Added** :attr:`Page.rotationMatrix` and :attr:`Page.derotationMatrix` to support coordinate transformations between the rotated and the original versions of a PDF page.\n\nPotential code breaking changes:\n\n* The private method ``Page._getTransformation()`` has been removed. Use the public :attr:`Page.transformationMattrix` instead.\n\n\n------\n\n**Changes in Version 1.16.18**\n\nThis version introduces several new features around PDF text output. The motivation is to simplify this task, while at the same time offering extending features.\n\nOne major achievement is using MuPDF's capabilities to dynamically choosing fallback fonts whenever a character cannot be found in the current one. This seamlessly works for Base-14 fonts in combination with CJK fonts (China, Japan, Korea). So a text may contain **any combination of characters** from the Latin, Greek, Russian, Chinese, Japanese and Korean languages.\n\n* **Fixed** issue `#493 <https://github.com/pymupdf/PyMuPDF/issues/493>`_. ``Pixmap(doc, xref)`` should now again correctly resemble the loaded image object.\n* **Fixed** issue `#488 <https://github.com/pymupdf/PyMuPDF/issues/488>`_. Widget names are now modifiable.\n* **Added** new class :ref:`Font` which represents a font.\n* **Added** new class :ref:`TextWriter` which serves as a container for text to be written on a page.\n* **Added** :meth:`Page.writeText` to write one or more :ref:`TextWriter` objects to the page.\n\n\n------\n\n**Changes in Version 1.16.17**\n\n\n* **Fixed** issue `#479 <https://github.com/pymupdf/PyMuPDF/issues/479>`_. PyMuPDF should now more correctly report image resolutions. This applies to both, images (either from images files or extracted from PDF documents) and pixmaps created from images.\n* **Added** :meth:`Pixmap.set_dpi` which sets the image resolution in x and y directions.\n\n------\n\n**Changes in Version 1.16.16**\n\n\n* **Fixed** issue `#477 <https://github.com/pymupdf/PyMuPDF/issues/477>`_.\n* **Fixed** issue `#476 <https://github.com/pymupdf/PyMuPDF/issues/476>`_.\n* **Changed** annotation line end symbol coloring and fixed an error coloring the interior of 'Polyline' /'Polygon' annotations.\n\n------\n\n**Changes in Version 1.16.14**\n\n\n* **Changed** text marker annotations to accept parameters beyond just quadrilaterals such that now **text lines between two given points can be marked**.\n\n* **Added** :meth:`Document.scrub` which **removes potentially sensitive data** from a PDF. Implements `#453 <https://github.com/pymupdf/PyMuPDF/issues/453>`_.\n\n* **Added** :meth:`Annot.blendMode` which returns the **blend mode** of annotations.\n\n* **Added** :meth:`Annot.setBlendMode` to set the annotation's blend mode. This resolves issue `#416 <https://github.com/pymupdf/PyMuPDF/issues/416>`_.\n* **Changed** :meth:`Annot.update` to accept additional parameters for setting blend mode and opacity.\n* **Added** advanced graphics features to **control the anti-aliasing values**, :meth:`Tools.set_aa_level`. Resolves `#467 <https://github.com/pymupdf/PyMuPDF/issues/467>`_\n\n* **Fixed** issue `#474 <https://github.com/pymupdf/PyMuPDF/issues/474>`_.\n* **Fixed** issue `#466 <https://github.com/pymupdf/PyMuPDF/issues/466>`_.\n\n\n\n------\n\n**Changes in Version 1.16.13**\n\n\n* **Added** :meth:`Document.getPageXObjectList` which returns a list of **Form XObjects** of the page.\n* **Added** :meth:`Page.setMediaBox` for changing the physical PDF page size.\n* **Added** :ref:`Page` methods which have been internal before: :meth:`Page.cleanContents` (= :meth:`Page._cleanContents`), :meth:`Page.getContents` (= :meth:`Page._getContents`), :meth:`Page.getTransformation` (= :meth:`Page._getTransformation`).\n\n\n\n------\n\n**Changes in Version 1.16.12**\n\n* **Fixed** issue `#447 <https://github.com/pymupdf/PyMuPDF/issues/447>`_\n* **Fixed** issue `#461 <https://github.com/pymupdf/PyMuPDF/issues/461>`_.\n* **Fixed** issue `#397 <https://github.com/pymupdf/PyMuPDF/issues/397>`_.\n* **Fixed** issue `#463 <https://github.com/pymupdf/PyMuPDF/issues/463>`_.\n* **Added** JavaScript support to PDF form fields, thereby fixing `#454 <https://github.com/pymupdf/PyMuPDF/issues/454>`_.\n* **Added** a new annotation method :meth:`Annot.delete_responses`, which removes 'Popup' and response annotations referring to the current one. Mainly serves data protection purposes.\n* **Added** a new form field method :meth:`Widget.reset`, which resets the field value to its default.\n* **Changed** and extended handling of redactions: images and XObjects are removed if *contained* in a redaction rectangle. Any partial only overlaps will just be covered by the redaction background color. Now an *overlay* text can be specified to be inserted in the rectangle area to **take the place the deleted original** text. This resolves `#434 <https://github.com/pymupdf/PyMuPDF/issues/434>`_.\n\n------\n\n**Changes in Version 1.16.11**\n\n* **Added** Support for redaction annotations via method :meth:`Page.add_redact_annot` and :meth:`Page.apply_redactions`.\n* **Fixed** issue #426 (\"PolygonAnnotation in 1.16.10 version\").\n* **Fixed** documentation only issues `#443 <https://github.com/pymupdf/PyMuPDF/issues/443>`_ and `#444 <https://github.com/pymupdf/PyMuPDF/issues/444>`_.\n\n------\n\n**Changes in Version 1.16.10**\n\n* **Fixed** issue #421 (\"annot.set_rect(rect) has no effect on text Annotation\")\n* **Fixed** issue #417 (\"Strange behavior for page.deleteAnnot on 1.16.9 compare to 1.13.20\")\n* **Fixed** issue #415 (\"Annot.setOpacity throws mupdf warnings\")\n* **Changed** all \"add annotation / widget\" methods to store a unique name in the */NM* PDF key.\n* **Changed** :meth:`Annot.setInfo` to also accept direct parameters in addition to a dictionary.\n* **Changed** :attr:`Annot.info` to now also show the annotation's unique id (*/NM* PDF key) if present.\n* **Added** :meth:`Page.annot_names` which returns a list of all annotation names (*/NM* keys).\n* **Added** :meth:`Page.load_annot` which loads an annotation given its unique id (*/NM* key).\n* **Added** :meth:`Document.reload_page` which provides a new copy of a page after finishing any pending updates to it.\n\n\n------\n\n**Changes in Version 1.16.9**\n\n* **Fixed** #412 (\"Feature Request: Allow controlling whether TOC entries should be collapsed\")\n* **Fixed** #411 (\"Seg Fault with page.firstWidget\")\n* **Fixed** #407 (\"Annot.setOpacity trouble\")\n* **Changed** methods :meth:`Annot.setBorder`, :meth:`Annot.setColors`, :meth:`Link.setBorder`, and :meth:`Link.setColors` to also accept direct parameters, and not just cumbersome dictionaries.\n\n------\n\n**Changes in Version 1.16.8**\n\n* **Added** several new methods to the :ref:`Document` class, which make dealing with PDF low-level structures easier. I also decided to provide them as \"normal\" methods (as opposed to private ones starting with an underscore \"_\"). These are :meth:`Document.xrefObject`, :meth:`Document.xrefStream`, :meth:`Document.xrefStreamRaw`, :meth:`Document.PDFTrailer`, :meth:`Document.PDFCatalog`, :meth:`Document.metadataXML`, :meth:`Document.updateObject`, :meth:`Document.updateStream`.\n* **Added** :meth:`Tools.mupdf_disply_errors` which sets the display of mupdf errors on *sys.stderr*.\n* **Added** a commandline facility. This a major new feature: you can now invoke several utility functions via *\"python -m fitz ...\"*. It should obsolete the need for many of the most trivial scripts. Please refer to :ref:`Module`.\n\n\n------\n\n**Changes in Version 1.16.7**\n\nMinor changes to better synchronize the binary image streams of :ref:`TextPage` image blocks and :meth:`Document.extractImage` images.\n\n* **Fixed** issue #394 (\"PyMuPDF Segfaults when using TOOLS.mupdf_warnings()\").\n* **Changed** redirection of MuPDF error messages: apart from writing them to Python *sys.stderr*, they are now also stored with the MuPDF warnings.\n* **Changed** :meth:`Tools.mupdf_warnings` to automatically empty the store (if not deactivated via a parameter).\n* **Changed** :meth:`Page.getImageBbox` to return an **infinite rectangle** if the image could not be located on the page -- instead of raising an exception.\n\n\n------\n\n**Changes in Version 1.16.6**\n\n* **Fixed** issue #390 (\"Incomplete deletion of annotations\").\n* **Changed** :meth:`Page.searchFor` / :meth:`Document.searchPageFor` to also support the *flags* parameter, which controls the data included in a :ref:`TextPage`.\n* **Changed** :meth:`Document.getPageImageList`, :meth:`Document.getPageFontList` and their :ref:`Page` counterparts to support a new parameter *full*. If true, the returned items will contain the :data:`xref` of the *Form XObject* where the font or image is referenced.\n\n------\n\n**Changes in Version 1.16.5**\n\nMore performance improvements for text extraction.\n\n* **Fixed** second part of issue #381 (see item in v1.16.4).\n* **Added** :meth:`Page.getTextPage`, so it is no longer required to create an intermediate display list for text extractions. Page level wrappers for text extraction and text searching are now based on this, which should improve performance by ca. 5%.\n\n------\n\n**Changes in Version 1.16.4**\n\n\n* **Fixed** issue #381 (\"TextPage.extractDICT ... failed ... after upgrading ... to 1.16.3\")\n* **Added** method :meth:`Document.pages` which delivers a generator iterator over a page range.\n* **Added** method :meth:`Page.links` which delivers a generator iterator over the links of a page.\n* **Added** method :meth:`Page.annots` which delivers a generator iterator over the annotations of a page.\n* **Added** method :meth:`Page.widgets` which delivers a generator iterator over the form fields of a page.\n* **Changed** :attr:`Document.is_form_pdf` to now contain the number of widgets, and *False* if not a PDF or this number is zero.\n\n\n------\n\n**Changes in Version 1.16.3**\n\nMinor changes compared to version 1.16.2. The code of the \"dict\" and \"rawdict\" variants of :meth:`Page.getText` has been ported to C which has greatly improved their performance. This improvement is mostly noticeable with text-oriented documents, where they now should execute almost two times faster.\n\n* **Fixed** issue #369 (\"mupdf: cmsCreateTransform failed\") by removing ICC colorspace support.\n* **Changed** :meth:`Page.getText` to accept additional keywords \"blocks\" and \"words\". These will deliver the results of :meth:`Page.getTextBlocks` and :meth:`Page.getTextWords`, respectively. So all text extraction methods are now available via a uniform API. Correspondingly, there are now new methods :meth:`TextPage.extractBLOCKS` and :meth:`TextPage.extractWords`.\n* **Changed** :meth:`Page.getText` to default bit indicator *TEXT_INHIBIT_SPACES* to **off**. Insertion of additional spaces is **not suppressed** by default.\n\n------\n\n**Changes in Version 1.16.2**\n\n* **Changed** text extraction methods of :ref:`Page` to allow detail control of the amount of extracted data.\n* **Added** :meth:`planish_line` which maps a given line (defined as a pair of points) to the x-axis.\n* **Fixed** an issue (w/o Github number) which brought down the interpreter when encountering certain non-UTF-8 encodable characters while using :meth:`Page.getText` with the \"dict\" option.\n* **Fixed** issue #362 (\"Memory Leak with getText('rawDICT')\").\n\n------\n\n**Changes in Version 1.16.1**\n\n* **Added** property :attr:`Quad.is_convex` which checks whether a line is contained in the quad if it connects two points of it.\n* **Changed** :meth:`Document.insert_pdf` to now allow dropping or including links and annotations independently during the copy. Fixes issue #352 (\"Corrupt PDF data and ...\"), which seemed to intermittently occur when using the method for some problematic PDF files.\n* **Fixed** a bug which, in matrix division using the syntax *\"m1/m2\"*, caused matrix *\"m1\"* to be **replaced** by the result instead of delivering a new matrix.\n* **Fixed** issue #354 (\"SyntaxWarning with Python 3.8\"). We now always use *\"==\"* for literals (instead of the *\"is\"* Python keyword).\n* **Fixed** issue #353 (\"mupdf version check\"), to no longer refuse the import when there are only patch level deviations from MuPDF.\n\n\n\n------\n\n**Changes in Version 1.16.0**\n\nThis major new version of MuPDF comes with several nice new or changed features. Some of them imply programming API changes, however. This is a synopsis of what has changed:\n\n* PDF document encryption and decryption is now **fully supported**. This includes setting **permissions**, **passwords** (user and owner passwords) and the desired encryption method.\n* In response to the new encryption features, PyMuPDF returns an integer (ie. a combination of bits) for document permissions, and no longer a dictionary.\n* Redirection of MuPDF errors and warnings is now natively supported. PyMuPDF redirects error messages from MuPDF to *sys.stderr* and no longer buffers them. Warnings continue to be buffered and will not be displayed. Functions exist to access and reset the warnings buffer.\n* Annotations are now **only supported for PDF**.\n* Annotations and widgets (form fields) are now **separate object chains** on a page (although widgets technically still **are** PDF annotations). This means, that you will **never encounter widgets** when using :attr:`Page.firstAnnot` or :meth:`Annot.next`. You must use :attr:`Page.firstWidget` and :meth:`Widget.next` to access form fields.\n* As part of MuPDF's changes regarding widgets, only the following four fonts are supported, when **adding** or **changing** form fields: **Courier, Helvetica, Times-Roman** and **ZapfDingBats**.\n\nList of change details:\n\n* **Added** :meth:`Document.can_save_incrementally` which checks conditions that are preventing use of option *incremental=True* of :meth:`Document.save`.\n* **Added** :attr:`Page.firstWidget` which points to the first field on a page.\n* **Added** :meth:`Page.getImageBbox` which returns the rectangle occupied by an image shown on the page.\n* **Added** :meth:`Annot.setName` which lets you change the (icon) name field.\n* **Added** outputting the text color in :meth:`Page.getText`: the *\"dict\"*, *\"rawdict\"* and *\"xml\"* options now also show the color in sRGB format.\n* **Changed** :attr:`Document.permissions` to now contain an integer of bool indicators -- was a dictionary before.\n* **Changed** :meth:`Document.save`, :meth:`Document.write`, which now fully support password-based decryption and encryption of PDF files.\n* **Changed the names of all Python constants** related to annotations and widgets. Please make sure to consult the **Constants and Enumerations** chapter if your script is dealing with these two classes. This decision goes back to the dropped support for non-PDF annotations. The **old names** (starting with \"ANNOT_*\" or \"WIDGET_*\") will be available as deprecated synonyms.\n* **Changed** font support for widgets: only *Cour* (Courier), *Helv* (Helvetica, default), *TiRo* (Times-Roman) and *ZaDb* (ZapfDingBats) are accepted when **adding or changing** form fields. Only the plain versions are possible -- not their italic or bold variations. **Reading** widgets, however will show its original font.\n* **Changed** the name of the warnings buffer to :meth:`Tools.mupdf_warnings` and the function to empty this buffer is now called :meth:`Tools.reset_mupdf_warnings`.\n* **Changed** :meth:`Page.getPixmap`, :meth:`Document.get_page_pixmap`: a new bool argument *annots* can now be used to **suppress the rendering of annotations** on the page.\n* **Changed** :meth:`Page.add_file_annot` and :meth:`Page.add_text_annot` to enable setting an icon.\n* **Removed** widget-related methods and attributes from the :ref:`Annot` object.\n* **Removed** :ref:`Document` attributes *openErrCode*, *openErrMsg*, and :ref:`Tools` attributes / methods *stderr*, *reset_stderr*, *stdout*, and *reset_stdout*.\n* **Removed** **thirdparty zlib** dependency in PyMuPDF: there are now compression functions available in MuPDF. Source installers of PyMuPDF may now omit this extra installation step.\n\n**No version published for MuPDF v1.15.0**\n\n\n------\n\n**Changes in Version 1.14.20 / 1.14.21**\n\n* **Changed** text marker annotations to support multiple rectangles / quadrilaterals. This fixes issue #341 (\"Question : How to addhighlight so that a string spread across more than a line is covered by one highlight?\") and similar (#285).\n* **Fixed** issue #331 (\"Importing PyMuPDF changes warning filtering behaviour globally\").\n\n\n------\n\n**Changes in Version 1.14.19**\n\n* **Fixed** issue #319 (\"InsertText function error when use custom font\").\n* **Added** new method :meth:`Document.get_sigflags` which returns information on whether a PDF is signed. Resolves issue #326 (\"How to detect signature in a form pdf?\").\n\n\n------\n\n**Changes in Version 1.14.17**\n\n* **Added** :meth:`Document.fullcopyPage` to make full page copies within a PDF (not just copied references as :meth:`Document.copyPage` does).\n* **Changed** :meth:`Page.getPixmap`, :meth:`Document.get_page_pixmap` now use *alpha=False* as default.\n* **Changed** text extraction: the span dictionary now (again) contains its rectangle under the *bbox* key.\n* **Changed** :meth:`Document.movePage` and :meth:`Document.copyPage` to use direct functions instead of wrapping :meth:`Document.select` -- similar to :meth:`Document.delete_page` in v1.14.16.\n\n------\n\n**Changes in Version 1.14.16**\n\n* **Changed** :ref:`Document` methods around PDF */EmbeddedFiles* to no longer use MuPDF's \"portfolio\" functions. That support will be dropped in MuPDF v1.15 -- therefore another solution was required.\n* **Changed** :meth:`Document.embfile_Count` to be a function (was an attribute).\n* **Added** new method :meth:`Document.embfile_Names` which returns a list of names of embedded files.\n* **Changed** :meth:`Document.delete_page` and :meth:`Document.delete_pages` to internally no longer use :meth:`Document.select`, but instead use functions to perform the deletion directly. As it has turned out, the :meth:`Document.select` method yields invalid outline trees (tables of content) for very complex PDFs and sophisticated use of annotations.\n\n\n------\n\n**Changes in Version 1.14.15**\n\n* **Fixed** issues #301 (\"Line cap and Line join\"), #300 (\"How to draw a shape without outlines\") and #298 (\"utils.updateRect exception\"). These bugs pertain to drawing shapes with PyMuPDF. Drawing shapes without any border is fully supported. Line cap styles and line line join style are now differentiated and support all possible PDF values (0, 1, 2) instead of just being a bool. The previous parameter *roundCap* is deprecated in favor of *lineCap* and *lineJoin* and will be deleted in the next release.\n* **Fixed** issue #290 (\"Memory Leak with getText('rawDICT')\"). This bug caused memory not being (completely) freed after invoking the \"dict\", \"rawdict\" and \"json\" versions of :meth:`Page.getText`.\n\n\n------\n\n**Changes in Version 1.14.14**\n\n* **Added** new low-level function :meth:`ImageProperties` to determine a number of characteristics for an image.\n* **Added** new low-level function :meth:`Document.is_stream`, which checks whether an object is of stream type.\n* **Changed** low-level functions :meth:`Document._getXrefString` and :meth:`Document._getTrailerString` now by default return object definitions in a formatted form which makes parsing easy.\n\n------\n\n**Changes in Version 1.14.13**\n\n* **Changed** methods working with binary input: while ever supporting bytes and bytearray objects, they now also accept *io.BytesIO* input, using their *getvalue()* method. This pertains to document creation, embedded files, FileAttachment annotations, pixmap creation and others. Fixes issue #274 (\"Segfault when using BytesIO as a stream for insertImage\").\n* **Fixed** issue #278 (\"Is insertImage(keep_proportion=True) broken?\"). Images are now correctly presented when keeping aspect ratio.\n\n\n------\n\n**Changes in Version 1.14.12**\n\n* **Changed** the draw methods of :ref:`Page` and :ref:`Shape` to support not only RGB, but also GRAY and CMYK colorspaces. This solves issue #270 (\"Is there a way to use CMYK color to draw shapes?\"). This change also applies to text insertion methods of :ref:`Shape`, resp. :ref:`Page`.\n* **Fixed** issue #269 (\"AttributeError in Document.insert_page()\"), which occurred when using :meth:`Document.insert_page` with text insertion.\n\n\n------\n\n**Changes in Version 1.14.11**\n\n* **Changed** :meth:`Page.show_pdf_page` to always position the source rectangle centered in the target. This method now also supports **rotation by arbitrary angles**. The argument *reuse_xref* has been deprecated: prevention of duplicates is now **handled internally**.\n* **Changed** :meth:`Page.insertImage` to support rotated display of the image and keeping the aspect ratio. Only rotations by multiples of 90 degrees are supported here.\n* **Fixed** issue #265 (\"TypeError: insertText() got an unexpected keyword argument 'idx'\"). This issue only occurred when using :meth:`Document.insert_page` with also inserting text.\n\n------\n\n**Changes in Version 1.14.10**\n\n* **Changed** :meth:`Page.show_pdf_page` to support rotation of the source rectangle. Fixes #261 (\"Cannot rotate inserted pages\").\n* **Fixed** a bug in :meth:`Page.insertImage` which prevented insertion of multiple images provided as streams.\n\n\n------\n\n**Changes in Version 1.14.9**\n\n* **Added** new low-level method :meth:`Document._getTrailerString`, which returns the trailer object of a PDF. This is much like :meth:`Document._getXrefString` except that the PDF trailer has no / needs no :data:`xref` to identify it.\n* **Added** new parameters for text insertion methods. You can now set stroke and fill colors of glyphs (text characters) independently, as well as the thickness of the glyph border. A new parameter *render_mode* controls the use of these colors, and whether the text should be visible at all.\n* **Fixed** issue #258 (\"Copying image streams to new PDF without size increase\"): For JPX images embedded in a PDF, :meth:`Document.extractImage` will now return them in their original format. Previously, the MuPDF base library was used, which returns them in PNG format (entailing a massive size increase).\n* **Fixed** issue #259 (\"Morphing text to fit inside rect\"). Clarified use of :meth:`get_text_length` and removed extra line breaks for long words.\n\n------\n\n**Changes in Version 1.14.8**\n\n* **Added** :meth:`Pixmap.set_rect` to change the pixel values in a rectangle. This is also an alternative to setting the color of a complete pixmap (:meth:`Pixmap.clear_with`).\n* **Fixed** an image extraction issue with JBIG2 (monochrome) encoded PDF images. The issue occurred in :meth:`Page.getText` (parameters \"dict\" and \"rawdict\") and in :meth:`Document.extractImage` methods.\n* **Fixed** an issue with not correctly clearing a non-alpha :ref:`Pixmap` (:meth:`Pixmap.clear_with`).\n* **Fixed** an issue with not correctly inverting colors of a non-alpha :ref:`Pixmap` (:meth:`Pixmap.invert_irect`).\n\n------\n\n**Changes in Version 1.14.7**\n\n* **Added** :meth:`Pixmap.set_pixel` to change one pixel value.\n* **Added** documentation for image conversion in the :ref:`FAQ`.\n* **Added** new function :meth:`get_text_length` to determine the string length for a given font.\n* **Added** Postscript image output (changed :meth:`Pixmap.save` and :meth:`Pixmap.tobytes`).\n* **Changed** :meth:`Pixmap.save` and :meth:`Pixmap.tobytes` to ensure valid combinations of colorspace, alpha and output format.\n* **Changed** :meth:`Pixmap.save`: the desired format is now inferred from the filename.\n* **Changed** FreeText annotations can now have a transparent background - see :meth:`Annot.update`.\n\n------\n\n**Changes in Version 1.14.5**\n\n* **Changed:** :ref:`Shape` methods now strictly use the transformation matrix of the :ref:`Page` -- instead of \"manually\" calculating locations.\n* **Added** method :meth:`Pixmap.pixel` which returns the pixel value (a list) for given pixel coordinates.\n* **Added** method :meth:`Pixmap.tobytes` which returns a bytes object representing the pixmap in a variety of formats. Previously, this could be done for PNG outputs only (:meth:`Pixmap.tobytes`).\n* **Changed:** output of methods :meth:`Pixmap.save` and (the new) :meth:`Pixmap.tobytes` may now also be PSD (Adobe Photoshop Document).\n* **Added** method :meth:`Shape.drawQuad` which draws a :ref:`Quad`. This actually is a shorthand for a :meth:`Shape.drawPolyline` with the edges of the quad.\n* **Changed** method :meth:`Shape.drawOval`: the argument can now be **either** a rectangle (:data:`rect_like`) **or** a quadrilateral (:data:`quad_like`).\n\n------\n\n**Changes in Version 1.14.4**\n\n* **Fixes** issue #239 \"Annotation coordinate consistency\".\n\n\n------\n\n**Changes in Version 1.14.3**\n\nThis patch version contains minor bug fixes and CJK font output support.\n\n* **Added** support for the four CJK fonts as PyMuPDF generated text output. This pertains to methods :meth:`Page.insertFont`, :meth:`Shape.insertText`, :meth:`Shape.insertTextbox`, and corresponding :ref:`Page` methods. The new fonts are available under \"reserved\" fontnames \"china-t\" (traditional Chinese), \"china-s\" (simplified Chinese), \"japan\" (Japanese), and \"korea\" (Korean).\n* **Added** full support for the built-in fonts 'Symbol' and 'Zapfdingbats'.\n* **Changed:** The 14 standard fonts can now each be referenced by a 4-letter abbreviation.\n\n------\n\n**Changes in Version 1.14.1**\n\nThis patch version contains minor performance improvements.\n\n* **Added** support for :ref:`Document` filenames given as *pathlib* object by using the Python *str()* function.\n\n\n------\n\n**Changes in Version 1.14.0**\n\nTo support MuPDF v1.14.0, massive changes were required in PyMuPDF -- most of them purely technical, with little visibility to developers. But there are also quite a lot of interesting new and improved features. Following are the details:\n\n* **Added** \"ink\" annotation.\n* **Added** \"rubber stamp\" annotation.\n* **Added** \"squiggly\" text marker annotation.\n* **Added** new class :ref:`Quad` (quadrilateral or tetragon) -- which represents a general four-sided shape in the plane. The special subtype of rectangular, non-empty tetragons is used in text marker annotations and as returned objects in text search methods.\n* **Added** a new option \"decrypt\" to :meth:`Document.save` and :meth:`Document.write`. Now you can **keep encryption** when saving a password protected PDF.\n* **Added** suppression and redirection of unsolicited messages issued by the underlying C-library MuPDF. Consult :ref:`RedirectMessages` for details.\n* **Changed:** Changes to annotations now **always require** :meth:`Annot.update` to become effective.\n* **Changed** free text annotations to support the full Latin character set and range of appearance options.\n* **Changed** text searching, :meth:`Page.searchFor`, to optionally return :ref:`Quad` instead :ref:`Rect` objects surrounding each search hit.\n* **Changed** plain text output: we now add a *\\n* to each line if it does not itself end with this character.\n* **Fixed** issue 211 (\"Something wrong in the doc\").\n* **Fixed** issue 213 (\"Rewritten outline is displayed only by mupdf-based applications\").\n* **Fixed** issue 214 (\"PDF decryption GONE!\").\n* **Fixed** issue 215 (\"Formatting of links added with pyMuPDF\").\n* **Fixed** issue 217 (\"extraction through json is failing for my pdf\").\n\nBehind the curtain, we have changed the implementation of geometry objects: they now purely exist in Python and no longer have \"shadow\" twins on the C-level (in MuPDF). This has improved processing speed in that area by more than a factor of two.\n\nBecause of the same reason, most methods involving geometry parameters now also accept the corresponding Python sequence. For example, in method *\"page.show_pdf_page(rect, ...)\"* parameter *rect* may now be any :data:`rect_like` sequence.\n\nWe also invested considerable effort to further extend and improve the :ref:`FAQ` chapter.\n\n\n------\n\n**Changes in Version 1.13.19**\n\nThis version contains some technical / performance improvements and bug fixes.\n\n* **Changed** memory management: for Python 3 builds, Python memory management is exclusively used across all C-level code (i.e. no more native *malloc()* in MuPDF code or PyMuPDF interface code). This leads to improved memory usage profiles and also some runtime improvements: we have seen > 2% shorter runtimes for text extractions and pixmap creations (on Windows machines only to date).\n* **Fixed** an error occurring in Python 2.7, which crashed the interpreter when using :meth:`TextPage.extractRAWDICT` (= *Page.getText(\"rawdict\")*).\n* **Fixed** an error occurring in Python 2.7, when creating link destinations.\n* **Extended** the :ref:`FAQ` chapter with more examples.\n\n------\n\n**Changes in Version 1.13.18**\n\n* **Added** method :meth:`TextPage.extractRAWDICT`, and a corresponding new string parameter \"rawdict\" to method :meth:`Page.getText`. It extracts text and images from a page in Python *dict* form like :meth:`TextPage.extractDICT`, but with the detail level of :meth:`TextPage.extractXML`, which is position information down to each single character.\n\n------\n\n**Changes in Version 1.13.17**\n\n* **Fixed** an error that intermittently caused an exception in :meth:`Page.show_pdf_page`, when pages from many different source PDFs were shown.\n* **Changed** method :meth:`Document.extractImage` to now return more meta information about the extracted image. Also, its performance has been greatly improved. Several demo scripts have been changed to make use of this method.\n* **Changed** method :meth:`Document._getXrefStream` to now return *None* if the object is no stream and no longer raise an exception if otherwise.\n* **Added** method :meth:`Document._deleteObject` which deletes a PDF object identified by its :data:`xref`. Only to be used by the experienced PDF expert.\n* **Added** a method :meth:`paper_rect` which returns a :ref:`Rect` for a supplied paper format string. Example: *fitz.paper_rect(\"letter\") = fitz.Rect(0.0, 0.0, 612.0, 792.0)*.\n* **Added** a :ref:`FAQ` chapter to this document.\n\n------\n\n**Changes in Version 1.13.16**\n\n* **Added** support for correctly setting transparency (opacity) for certain annotation types.\n* **Added** a tool property (:attr:`Tools.fitz_config`) showing the configuration of this PyMuPDF version.\n* **Fixed** issue #193 ('insertText(overlay=False) gives \"cannot resize a buffer with shared storage\" error') by avoiding read-only buffers.\n\n------\n\n**Changes in Version 1.13.15**\n\n* **Fixed** issue #189 (\"cannot find builtin CJK font\"), so we are supporting builtin CJK fonts now (CJK = China, Japan, Korea). This should lead to correctly generated pixmaps for documents using these languages. This change has consequences for our binary file size: it will now range between 8 and 10 MB, depending on the OS.\n* **Fixed** issue #191 (\"Jupyter notebook kernel dies after ca. 40 pages\"), which occurred when modifying the contents of an annotation.\n\n------\n\n**Changes in Version 1.13.14**\n\nThis patch version contains several improvements, mainly for annotations.\n\n* **Changed** :attr:`Annot.lineEnds` is now a list of two integers representing the line end symbols. Previously was a *dict* of strings.\n* **Added** support of line end symbols for applicable annotations. PyMuPDF now can generate these annotations including the line end symbols.\n* **Added** :meth:`Annot.setLineEnds` adds line end symbols to applicable annotation types ('Line', 'PolyLine', 'Polygon').\n* **Changed** technical implementation of :meth:`Page.insertImage` and :meth:`Page.show_pdf_page`: they now create there own contents objects, thereby avoiding changes of potentially large streams with consequential compression / decompression efforts and high change volumes with incremental updates.\n\n------\n\n**Changes in Version 1.13.13**\n\nThis patch version contains several improvements for embedded files and file attachment annotations.\n\n* **Added** :meth:`Document.embfile_Upd` which allows changing **file content and metadata** of an embedded file. It supersedes the old method :meth:`Document.embfile_SetInfo` (which will be deleted in a future version). Content is automatically compressed and metadata may be unicode.\n* **Changed** :meth:`Document.embfile_Add` to now automatically compress file content. Accompanying metadata can now be unicode (had to be ASCII in the past).\n* **Changed** :meth:`Document.embfile_Del` to now automatically delete **all entries** having the supplied identifying name. The return code is now an integer count of the removed entries (was *None* previously).\n* **Changed** embedded file methods to now also accept or show the PDF unicode filename as additional parameter *ufilename*.\n* **Added** :meth:`Page.add_file_annot` which adds a new file attachment annotation.\n* **Changed** :meth:`Annot.fileUpd` (file attachment annot) to now also accept the PDF unicode *ufilename* parameter. The description parameter *desc* correctly works with unicode. Furthermore, **all** parameters are optional, so metadata may be changed without also replacing the file content.\n* **Changed** :meth:`Annot.fileInfo` (file attachment annot) to now also show the PDF unicode filename as parameter *ufilename*.\n* **Fixed** issue #180 (\"page.getText(output='dict') return invalid bbox\") to now also work for vertical text.\n* **Fixed** issue #185 (\"Can't render the annotations created by PyMuPDF\"). The issue's cause was the minimalistic MuPDF approach when creating annotations. Several annotation types have no */AP* (\"appearance\") object when created by MuPDF functions. MuPDF, SumatraPDF and hence also PyMuPDF cannot render annotations without such an object. This fix now ensures, that an appearance object is always created together with the annotation itself. We still do not support line end styles.\n\n------\n\n**Changes in Version 1.13.12**\n\n* **Fixed** issue #180 (\"page.getText(output='dict') return invalid bbox\"). Note that this is a circumvention of an MuPDF error, which generates zero-height character rectangles in some cases. When this happens, this fix ensures a bbox height of at least fontsize.\n* **Changed** for ListBox and ComboBox widgets, the attribute list of selectable values has been renamed to :attr:`Widget.choice_values`.\n* **Changed** when adding widgets, any missing of the :ref:`Base-14-Fonts` is automatically added to the PDF. Widget text fonts can now also be chosen from existing widget fonts. Any specified field values are now honored and lead to a field with a preset value.\n* **Added** :meth:`Annot.updateWidget` which allows changing existing form fields -- including the field value.\n\n------\n\n**Changes in Version 1.13.11**\n\nWhile the preceding patch subversions only contained various fixes, this version again introduces major new features:\n\n* **Added** basic support for PDF widget annotations. You can now add PDF form fields of types Text, CheckBox, ListBox and ComboBox. Where necessary, the PDF is transformed to a Form PDF with the first added widget.\n* **Fixed** issues #176 (\"wrong file embedding\"), #177 (\"segment fault when invoking page.getText()\")and #179 (\"Segmentation fault using page.getLinks() on encrypted PDF\").\n\n\n------\n\n**Changes in Version 1.13.7**\n\n* **Added** support of variable page sizes for reflowable documents (e-books, HTML, etc.): new parameters *rect* and *fontsize* in :ref:`Document` creation (open), and as a separate method :meth:`Document.layout`.\n* **Added** :ref:`Annot` creation of many annotations types: sticky notes, free text, circle, rectangle, line, polygon, polyline and text markers.\n* **Added** support of annotation transparency (:attr:`Annot.opacity`, :meth:`Annot.setOpacity`).\n* **Changed** :attr:`Annot.vertices`: point coordinates are now grouped as pairs of floats (no longer as separate floats).\n* **Changed** annotation colors dictionary: the two keys are now named *\"stroke\"* (formerly *\"common\"*) and *\"fill\"*.\n* **Added** :attr:`Document.isDirty` which is *True* if a PDF has been changed in this session. Reset to *False* on each :meth:`Document.save` or :meth:`Document.write`.\n\n------\n\n**Changes in Version 1.13.6**\n\n* Fix #173: for memory-resident documents, ensure the stream object will not be garbage-collected by Python before document is closed.\n\n------\n\n**Changes in Version 1.13.5**\n\n* New low-level method :meth:`Page._setContents` defines an object given by its :data:`xref` to serve as the :data:`contents` object.\n* Changed and extended PDF form field support: the attribute *widget_text* has been renamed to :attr:`Annot.widget_value`. Values of all form field types (except signatures) are now supported. A new attribute :attr:`Annot.widget_choices` contains the selectable values of listboxes and comboboxes. All these attributes now contain *None* if no value is present.\n\n------\n\n**Changes in Version 1.13.4**\n\n* :meth:`Document.convertToPDF` now supports page ranges, reverted page sequences and page rotation. If the document already is a PDF, an exception is raised.\n* Fixed a bug (introduced with v1.13.0) that prevented :meth:`Page.insertImage` for transparent images.\n\n------\n\n**Changes in Version 1.13.3**\n\nIntroduces a way to convert **any MuPDF supported document** to a PDF. If you ever wanted PDF versions of your XPS, EPUB, CBZ or FB2 files -- here is a way to do this.\n\n* :meth:`Document.convertToPDF` returns a Python *bytes* object in PDF format. Can be opened like normal in PyMuPDF, or be written to disk with the *\".pdf\"* extension.\n\n------\n\n**Changes in Version 1.13.2**\n\nThe major enhancement is PDF form field support. Form fields are annotations of type *(19, 'Widget')*. There is a new document method to check whether a PDF is a form. The :ref:`Annot` class has new properties describing field details.\n\n* :attr:`Document.is_form_pdf` is true if object type */AcroForm* and at least one form field exists.\n* :attr:`Annot.widget_type`, :attr:`Annot.widget_text` and :attr:`Annot.widget_name` contain the details of a form field (i.e. a \"Widget\" annotation).\n\n------\n\n**Changes in Version 1.13.1**\n\n* :meth:`TextPage.extractDICT` is a new method to extract the contents of a document page (text and images). All document types are supported as with the other :ref:`TextPage` *extract*()* methods. The returned object is a dictionary of nested lists and other dictionaries, and **exactly equal** to the JSON-deserialization of the old :meth:`TextPage.extractJSON`. The difference is that the result is created directly -- no JSON module is used. Because the user needs no JSON module to interpret the information, it should be easier to use, and also have a better performance, because it contains images in their original **binary format** -- they need not be base64-decoded.\n* :meth:`Page.getText` correspondingly supports the new parameter value *\"dict\"* to invoke the above method.\n* :meth:`TextPage.extractJSON` (resp. *Page.getText(\"json\")*) is still supported for convenience, but its use is expected to decline.\n\n------\n\n**Changes in Version 1.13.0**\n\nThis version is based on MuPDF v1.13.0. This release is \"primarily a bug fix release\".\n\nIn PyMuPDF, we are also doing some bug fixes while introducing minor enhancements. There only very minimal changes to the user's API.\n\n* :ref:`Document` construction is more flexible: the new *filetype* parameter allows setting the document type. If specified, any extension in the filename will be ignored. More completely addresses `issue #156 <https://github.com/pymupdf/PyMuPDF/issues/156>`_. As part of this, the documentation has been reworked.\n\n* Changes to :ref:`Pixmap` constructors:\n    - Colorspace conversion no longer allows dropping the alpha channel: source and target **alpha will now always be the same**. We have seen exceptions and even interpreter crashes when using *alpha = 0*.\n    - As a replacement, the simple pixmap copy lets you choose the target alpha.\n\n* :meth:`Document.save` again offers the full garbage collection range 0 thru 4. Because of a bug in :data:`xref` maintenance, we had to temporarily enforce *garbage > 1*. Finally resolves `issue #148 <https://github.com/pymupdf/PyMuPDF/issues/148>`_.\n\n* :meth:`Document.save` now offers to \"prettify\" PDF source via an additional argument.\n* :meth:`Page.insertImage` has the additional *stream* \\-parameter, specifying a memory area holding an image.\n\n* Issue with garbled PNGs on Linux systems has been resolved (`\"Problem writing PNG\" #133) <https://github.com/pymupdf/PyMuPDF/issues/133>`_.\n\n\n------\n\n**Changes in Version 1.12.4**\n\nThis is an extension of 1.12.3.\n\n* Fix of `issue #147 <https://github.com/pymupdf/PyMuPDF/issues/147>`_: methods :meth:`Document.getPageFontlist` and :meth:`Document.getPageImagelist` now also show fonts and images contained in :data:`resources` nested via \"Form XObjects\".\n* Temporary fix of `issue #148 <https://github.com/pymupdf/PyMuPDF/issues/148>`_: Saving to new PDF files will now automatically use *garbage = 2* if a lower value is given. Final fix is to be expected with MuPDF's next version. At that point we will remove this circumvention.\n* Preventive fix of illegally using stencil / image mask pixmaps in some methods.\n* Method :meth:`Document.getPageFontlist` now includes the encoding name for each font in the list.\n* Method :meth:`Document.getPageImagelist` now includes the decode method name for each image in the list.\n\n------\n\n**Changes in Version 1.12.3**\n\nThis is an extension of 1.12.2.\n\n* Many functions now return *None* instead of *0*, if the result has no other meaning than just indicating successful execution (:meth:`Document.close`, :meth:`Document.save`, :meth:`Document.select`, :meth:`Pixmap.save` and many others).\n\n------\n\n**Changes in Version 1.12.2**\n\nThis is an extension of 1.12.1.\n\n* Method :meth:`Page.show_pdf_page` now accepts the new *clip* argument. This specifies an area of the source page to which the display should be restricted.\n\n* New :attr:`Page.CropBox` and :attr:`Page.MediaBox` have been included for convenience.\n\n\n------\n\n**Changes in Version 1.12.1**\n\nThis is an extension of version 1.12.0.\n\n* New method :meth:`Page.show_pdf_page` displays another's PDF page. This is a **vector** image and therefore remains precise across zooming. Both involved documents must be PDF.\n\n* New method :meth:`Page.getSVGimage` creates an SVG image from the page. In contrast to the raster image of a pixmap, this is a vector image format. The return is a unicode text string, which can be saved in a *.svg* file.\n\n* Method :meth:`Page.getTextBlocks` now accepts an additional bool parameter \"images\". If set to true (default is false), image blocks (metadata only) are included in the produced list and thus allow detecting areas with rendered images.\n\n* Minor bug fixes.\n\n* \"text\" result of :meth:`Page.getText` concatenates all lines within a block using a single space character. MuPDF's original uses \"\\\\n\" instead, producing a rather ragged output.\n\n* New properties of :ref:`Page` objects :attr:`Page.MediaBoxSize` and :attr:`Page.CropBoxPosition` provide more information about a page's dimensions. For non-PDF files (and for most PDF files, too) these will be equal to :attr:`Page.rect.bottom_right`, resp. :attr:`Page.rect.top_left`. For example, class :ref:`Shape` makes use of them to correctly position its items.\n\n------\n\n**Changes in Version 1.12.0**\n\nThis version is based on and requires MuPDF v1.12.0. The new MuPDF version contains quite a number of changes -- most of them around text extraction. Some of the changes impact the programmer's API.\n\n* :meth:`Outline.saveText` and :meth:`Outline.saveXML` have been deleted without replacement. You probably haven't used them much anyway. But if you are looking for a replacement: the output of :meth:`Document.get_toc` can easily be used to produce something equivalent.\n\n* Class *TextSheet* does no longer exist.\n\n* Text \"spans\" (one of the hierarchy levels of :ref:`TextPage`) no longer contain positioning information (i.e. no \"bbox\" key). Instead, spans now provide the font information for its text. This impacts our JSON output variant.\n\n* HTML output has improved very much: it now creates valid documents which can be displayed by browsers to produce a similar view as the original document.\n\n* There is a new output format XHTML, which provides text and images in a browser-readable format. The difference to HTML output is, that no effort is made to reproduce the original layout.\n\n* All output formats of :meth:`Page.getText` now support creating complete, valid documents, by wrapping them with appropriate header and trailer information. If you are interested in using the HTML output, please make sure to read :ref:`HTMLQuality`.\n\n* To support finding text positions, we have added special methods that don't need detours like :meth:`TextPage.extractJSON` or :meth:`TextPage.extractXML`: use :meth:`Page.getTextBlocks` or resp. :meth:`Page.getTextWords` to create lists of text blocks or resp. words, which are accompanied by their rectangles. This should be much faster than the standard text extraction methods and also avoids using additional packages for interpreting their output.\n\n\n------\n\n**Changes in Version 1.11.2**\n\nThis is an extension of v1.11.1.\n\n* New :meth:`Page.insertFont` creates a PDF */Font* object and returns its object number.\n\n* New :meth:`Document.extractFont` extracts the content of an embedded font given its object number.\n\n* Methods **FontList(...)** items no longer contain the PDF generation number. This value never had any significance. Instead, the font file extension is included (e.g. \"pfa\" for a \"PostScript Font for ASCII\"), which is more valuable information.\n\n* Fonts other than \"simple fonts\" (Type1) are now also supported.\n\n* New options to change :ref:`Pixmap` size:\n\n    * Method :meth:`Pixmap.shrink` reduces the pixmap proportionally in place.\n\n    * A new :ref:`Pixmap` copy constructor allows scaling via setting target width and height.\n\n\n------\n\n**Changes in Version 1.11.1**\n\nThis is an extension of v1.11.0.\n\n* New class *Shape*. It facilitates and extends the creation of image shapes on PDF pages. It contains multiple methods for creating elementary shapes like lines, rectangles or circles, which can be combined into more complex ones and be given common properties like line width or colors. Combined shapes are handled as a unit and e.g. be \"morphed\" together. The class can accumulate multiple complex shapes and put them all in the page's foreground or background -- thus also reducing the number of updates to the page's :data:`contents` object.\n\n* All *Page* draw methods now use the new *Shape* class.\n\n* Text insertion methods *insertText()* and *insertTextBox()* now support morphing in addition to text rotation. They have become part of the *Shape* class and thus allow text to be freely combined with graphics.\n\n* A new *Pixmap* constructor allows creating pixmap copies with an added alpha channel. A new method also allows directly manipulating alpha values.\n\n* Binary algebraic operations with geometry objects (matrices, rectangles and points) now generally also support lists or tuples as the second operand. You can add a tuple *(x, y)* of numbers to a :ref:`Point`. In this context, such sequences are called \":data:`point_like`\" (resp. :data:`matrix_like`, :data:`rect_like`).\n\n* Geometry objects now fully support in-place operators. For example, *p /= m* replaces point p with *p * 1/m* for a number, or *p * ~m* for a :data:`matrix_like` object *m*. Similarly, if *r* is a rectangle, then *r |= (3, 4)* is the new rectangle that also includes *fitz.Point(3, 4)*, and *r &= (1, 2, 3, 4)* is its intersection with *fitz.Rect(1, 2, 3, 4)*.\n\n------\n\n**Changes in Version 1.11.0**\n\nThis version is based on and requires MuPDF v1.11.\n\nThough MuPDF has declared it as being mostly a bug fix version, one major new feature is indeed contained: support of embedded files -- also called portfolios or collections. We have extended PyMuPDF functionality to embrace this up to an extent just a little beyond the *mutool* utility as follows.\n\n* The *Document* class now support embedded files with several new methods and one new property:\n\n    - *embfile_Info()* returns metadata information about an entry in the list of embedded files. This is more than *mutool* currently provides: it shows all the information that was used to embed the file (not just the entry's name).\n    - *embfile_Get()* retrieves the (decompressed) content of an entry into a *bytes* buffer.\n    - *embfile_Add(...)* inserts new content into the PDF portfolio. We (in contrast to *mutool*) **restrict** this to entries with a **new name** (no duplicate names allowed).\n    - *embfile_Del(...)* deletes an entry from the portfolio (function not offered in MuPDF).\n    - *embfile_SetInfo()* -- changes filename or description of an embedded file.\n    - *embfile_Count* -- contains the number of embedded files.\n\n* Several enhancements deal with streamlining geometry objects. These are not connected to the new MuPDF version and most of them are also reflected in PyMuPDF v1.10.0. Among them are new properties to identify the corners of rectangles by name (e.g. *Rect.bottom_right*) and new methods to deal with set-theoretic questions like *Rect.contains(x)* or *IRect.intersects(x)*. Special effort focussed on supporting more \"Pythonic\" language constructs: *if x in rect ...* is equivalent to *rect.contains(x)*.\n\n* The :ref:`Rect` chapter now has more background on empty amd infinite rectangles and how we handle them. The handling itself was also updated for more consistency in this area.\n\n* We have started basic support for **generation** of PDF content:\n\n    - *Document.insert_page()* adds a new page into a PDF, optionally containing some text.\n    - *Page.insertImage()* places a new image on a PDF page.\n    - *Page.insertText()* puts new text on an existing page\n\n* For **FileAttachment** annotations, content and name of the attached file can extracted and changed.\n\n------\n\n**Changes in Version 1.10.0**\n\n**MuPDF v1.10 Impact**\n\nMuPDF version 1.10 has a significant impact on our bindings. Some of the changes also affect the API -- in other words, **you** as a PyMuPDF user.\n\n* Link destination information has been reduced. Several properties of the *linkDest* class no longer contain valuable information. In fact, this class as a whole has been deleted from MuPDF's library and we in PyMuPDF only maintain it to provide compatibility to existing code.\n\n* In an effort to minimize memory requirements, several improvements have been built into MuPDF v1.10:\n\n    - A new *config.h* file can be used to de-select unwanted features in the C base code. Using this feature we have been able to reduce the size of our binary *_fitz.o* / *_fitz.pyd* by about 50% (from 9 MB to 4.5 MB). When UPX-ing this, the size goes even further down to a very handy 2.3 MB.\n\n    - The alpha (transparency) channel for pixmaps is now optional. Letting alpha default to *False* significantly reduces pixmap sizes (by 20% -- CMYK, 25% -- RGB, 50% -- GRAY). Many *Pixmap* constructors therefore now accept an *alpha* boolean to control inclusion of this channel. Other pixmap constructors (e.g. those for file and image input) create pixmaps with no alpha altogether. On the downside, save methods for pixmaps no longer accept a *savealpha* option: this channel will always be saved when present. To minimize code breaks, we have left this parameter in the call patterns -- it will just be ignored.\n\n* *DisplayList* and *TextPage* class constructors now **require the mediabox** of the page they are referring to (i.e. the *page.bound()* rectangle). There is no way to construct this information from other sources, therefore a source code change cannot be avoided in these cases. We assume however, that not many users are actually employing these rather low level classes explicitly. So the impact of that change should be minor.\n\n**Other Changes compared to Version 1.9.3**\n\n* The new :ref:`Document` method *write()* writes an opened PDF to memory (as opposed to a file, like *save()* does).\n* An annotation can now be scaled and moved around on its page. This is done by modifying its rectangle.\n* Annotations can now be deleted. :ref:`Page` contains the new method *deleteAnnot()*.\n* Various annotation attributes can now be modified, e.g. content, dates, title (= author), border, colors.\n* Method *Document.insert_pdf()* now also copies annotations of source pages.\n* The *Pages* class has been deleted. As documents can now be accessed with page numbers as indices (like *doc[n] = doc.loadPage(n)*), and document object can be used as iterators, the benefit of this class was too low to maintain it. See the following comments.\n* *loadPage(n)* / *doc[n]* now accept arbitrary integers to specify a page number, as long as *n < pageCount*. So, e.g. *doc[-500]* is always valid and will load page *(-500) % pageCount*.\n* A document can now also be used as an iterator like this: *for page in doc: ...<do something with \"page\"> ...*. This will yield all pages of *doc* as *page*.\n* The :ref:`Pixmap` method *getSize()* has been replaced with property *size*. As before *Pixmap.size == len(Pixmap)* is true.\n* In response to transparency (alpha) being optional, several new parameters and properties have been added to :ref:`Pixmap` and :ref:`Colorspace` classes to support determining their characteristics.\n* The :ref:`Page` class now contains new properties *firstAnnot* and *firstLink* to provide starting points to the respective class chains, where *firstLink* is just a mnemonic synonym to method *loadLinks()* which continues to exist. Similarly, the new property *rect* is a synonym for method *bound()*, which also continues to exist.\n* :ref:`Pixmap` methods *samplesRGB()* and *samplesAlpha()* have been deleted because pixmaps can now be created without transparency.\n* :ref:`Rect` now has a property *irect* which is a synonym of method *round()*. Likewise, :ref:`IRect` now has property *rect* to deliver a :ref:`Rect` which has the same coordinates as floats values.\n* Document has the new method *searchPageFor()* to search for a text string. It works exactly like the corresponding *Page.searchFor()* with page number as additional parameter.\n\n\n------\n\n**Changes in Version 1.9.3**\n\nThis version is also based on MuPDF v1.9a. Changes compared to version 1.9.2:\n\n* As a major enhancement, annotations are now supported in a similar way as links. Annotations can be displayed (as pixmaps) and their properties can be accessed.\n* In addition to the document *select()* method, some simpler methods can now be used to manipulate a PDF:\n\n    - *copyPage()* copies a page within a document.\n    - *movePage()* is similar, but deletes the original.\n    - *delete_page()* deletes a page\n    - *delete_pages()* deletes a page range\n\n* *rotation* or *setRotation()* access or change a PDF page's rotation, respectively.\n* Available but undocumented before, :ref:`IRect`, :ref:`Rect`, :ref:`Point` and :ref:`Matrix` support the *len()* method and their coordinate properties can be accessed via indices, e.g. *IRect.x1 == IRect[2]*.\n* For convenience, documents now support simple indexing: *doc.loadPage(n) == doc[n]*. The index may however be in range *-pageCount < n < pageCount*, such that *doc[-1]* is the last page of the document.\n\n------\n\n**Changes in Version 1.9.2**\n\nThis version is also based on MuPDF v1.9a. Changes compared to version 1.9.1:\n\n* *fitz.open()* (no parameters) creates a new empty **PDF** document, i.e. if saved afterwards, it must be given a *.pdf* extension.\n* :ref:`Document` now accepts all of the following formats (*Document* and *open* are synonyms):\n\n  - *open()*,\n  - *open(filename)* (equivalent to *open(filename, None)*),\n  - *open(filetype, area)* (equivalent to *open(filetype, stream = area)*).\n\n  Type of memory area *stream* may be *bytes* or *bytearray*. Thus, e.g. *area = open(\"file.pdf\", \"rb\").read()* may be used directly (without first converting it to bytearray).\n* New method *Document.insert_pdf()* (PDFs only) inserts a range of pages from another PDF.\n* *Document* objects doc now support the *len()* function: ``len(doc) == doc.pageCount``.\n* New method *Document.getPageImageList()* creates a list of images used on a page.\n* New method *Document.getPageFontList()* creates a list of fonts referenced by a page.\n* New pixmap constructor *fitz.Pixmap(doc, xref)* creates a pixmap based on an opened PDF document and an :data:`xref` number of the image.\n* New pixmap constructor *fitz.Pixmap(cspace, spix)* creates a pixmap as a copy of another one *spix* with the colorspace converted to *cspace*. This works for all colorspace combinations.\n* Pixmap constructor *fitz.Pixmap(colorspace, width, height, samples)* now allows *samples* to also be *bytes*, not only *bytearray*.\n\n\n------\n\n**Changes in Version 1.9.1**\n\nThis version of PyMuPDF is based on MuPDF library source code version 1.9a published on April 21, 2016.\n\nPlease have a look at MuPDF's website to see which changes and enhancements are contained herein.\n\nChanges in version 1.9.1 compared to version 1.8.0 are the following:\n\n* New methods *get_area()* for both *fitz.Rect* and *fitz.IRect*\n* Pixmaps can now be created directly from files using the new constructor *fitz.Pixmap(filename)*.\n* The Pixmap constructor *fitz.Pixmap(image)* has been extended accordingly.\n* *fitz.Rect* can now be created with all possible combinations of points and coordinates.\n* PyMuPDF classes and methods now all contain  __doc__ strings,  most of them created by SWIG automatically. While the PyMuPDF documentation certainly is more detailed, this feature should help a lot when programming in Python-aware IDEs.\n* A new document method of *getPermits()* returns the permissions associated with the current access to the document (print, edit, annotate, copy), as a Python dictionary.\n* The identity matrix *fitz.Identity* is now **immutable**.\n* The new document method *select(list)* removes all pages from a document that are not contained in the list. Pages can also be duplicated and re-arranged.\n* Various improvements and new members in our demo and examples collections. Perhaps most prominently: *PDF_display* now supports scrolling with the mouse wheel, and there is a new example program *wxTableExtract* which allows to graphically identify and extract table data in documents.\n* *fitz.open()* is now an alias of *fitz.Document()*.\n* New pixmap method *tobytes()* which will return a bytearray formatted as a PNG image of the pixmap.\n* New pixmap method *samplesRGB()* providing a *samples* version with alpha bytes stripped off (RGB colorspaces only).\n* New pixmap method *samplesAlpha()* providing the alpha bytes only of the *samples* area.\n* New iterator *fitz.Pages(doc)* over a document's set of pages.\n* New matrix methods *invert()* (calculate inverted matrix), *concat()* (calculate matrix product), *pretranslate()* (perform a shift operation).\n* New *IRect* methods *intersect()* (intersection with another rectangle), *translate()* (perform a shift operation).\n* New *Rect* methods *intersect()* (intersection with another rectangle), *transform()* (transformation with a matrix), *include_point()* (enlarge rectangle to also contain a point), *include_rect()* (enlarge rectangle to also contain another one).\n* Documented *Point.transform()* (transform a point with a matrix).\n* *Matrix*, *IRect*, *Rect* and *Point* classes now support compact, algebraic formulations for manipulating such objects.\n* Incremental saves for changes are possible now using the call pattern *doc.save(doc.name, incremental=True)*.\n* A PDF's metadata can now be deleted, set or changed by document method *set_metadata()*. Supports incremental saves.\n* A PDF's bookmarks (or table of contents) can now be deleted, set or changed with the entries of a list using document method *set_toc(list)*. Supports incremental saves.\n\n.. codespell:ignore-end\n"
  },
  {
    "path": "docs/404.rst",
    "content": ".. include:: header-404.rst\n\n404!\n======\n\n\n**This page is not available.**\n\n\nPlease use the menu or search to find what you are looking for.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/README.md",
    "content": "# PyMuPDF documentation\n\nWelcome to the PyMuPDF documentation. This documentation relies on [Sphinx](https://www.sphinx-doc.org/en/master/) to publish HTML docs from markdown files written with [restructured text](https://en.wikipedia.org/wiki/ReStructuredText) (RST).\n\n\n## Sphinx version\n\nThis README assumes you have [Sphinx v5.0.2 installed](https://www.sphinx-doc.org/en/master/usage/installation.html) on your system.\n\n\n## Dependencies\n\npip install sphinxcontrib-googleanalytics\npip install sphinx-notfound-page\npip install sphinx-copybutton\npip install sphinx-autobuild\npip install furo\n\n## Updating the documentation\n\nWithin `docs` update the associated restructured text (`.rst`) files. These files represent the corresponding document pages.\n\n### Conventions\n\n- Code parameters and referenced code objects should be referenced within backticks, not italics, double backtick is better for safety\n- When referencing names of some of our products surround with | , e.g. |PyMuPDF| , not PyMuPDF, see `header.rst` for products names listing\n- When hyperlinking, avoid inline hyperlinks and try to references link from common location at page bottom, also avoid the use of \"here\" or \"click here\" as this provides little information about the link content. e.g.\n\n\"`Click here <link>` for our Story class\". Should be re-written to something more like \"Find out more `on our Story class <link>`\"\n\n## Building HTML documentation\n\n- Ensure you have the `furo` theme installed:\n\n`pip install furo`\n\nFuro theme, Copyright (c) 2020 Pradyun Gedam <mail@pradyunsg.me>, thank you to:\n\nhttps://github.com/pradyunsg/furo/blob/main/LICENSE\n\n\n- From the \"docs\" location run:\n\n`sphinx-build -b html . build/html`\n\nThis then creates the HTML documentation within `build/html`. \n\n> Use: `sphinx-build -a -b html . build/html` to build all, including the assets in `_static` (important if you have updated CSS).\n\n\n### Using Sphinx Autobuild\n\nA better way of building the documentation if you are actively working on updates is to run:\n\n`sphinx-autobuild . _build/html`\n\nThis will serve the docs on a localhost and auto-update the pages live as you make edits.\n\n\n\n## Internationalization\n\nPyMuPDF docs can be delivered in multiple languages - English, Japanese & Korean.\n\nTo add a new language, e.g. Korean, use:\n\n`sphinx-build -b gettext . _build/gettext`\n`sphinx-intl update -p _build/gettext -l ko`\n\n\n### Building the Localiized documentation\n\n- From the \"docs\" location run:\n\n#### Japanese:\n`sphinx-build -a -b html -D language=ja . _build/html/ja`\n\n\nOnce built HTML docs HTML pages are in `_build/html/ja`.\n\n#### Korean:\n`sphinx-build -a -b html -D language=ko . _build/html/ko`\n\n\nOnce built HTML docs HTML pages are in `_build/html/ko`.\n\nNote: subsequent runs can omit the `-a` parameter to speed up builds (it will just build what has changed).\n\n\nNote: When build the corresponding `.mo` binary files will also be generated - these updated binaries should also be committed to Git.\n\n### Depoloying\n\nDocs will be automatically deployed to RTD once pushes are made to relevant branches.\n\n\n### Updating\n\n- Updating, after changes on the `main` branch and a sync with the main `en` .rst files, from the \"docs\" location, do:\n\n`sphinx-build -b gettext . _build/gettext`\n\nthen:\n\n`sphinx-intl update -p _build/gettext -l ja`\n`sphinx-intl update -p _build/gettext -l ko`\n\nThis will update the corresponding `po` files for further edits. Then check these files for \"#, fuzzy\" entries as the new stuff might exist there and requires editing.\n\n\n\n\n\n\n\n## Building PDF documentation\n\n- First ensure you have [rst2pdf](https://pypi.org/project/rst2pdf/) installed:\n\n`python -m pip install rst2pdf`\n\n- Then run:\n\n`sphinx-build -b pdf . build/pdf`\n\nThis will then generate a single PDF for all of the documentation within `build/pdf`.\n\n\n---\n\n\nFor full details see: [Using Sphinx](https://www.sphinx-doc.org/en/master/usage/index.html) \n\n\n\n"
  },
  {
    "path": "docs/_static/custom.css",
    "content": "/* main document page: ensures pages fit to the available width and height */\n.wy-nav-content {\n    min-width: 100%;\n    min-height: 100vh;\n}\n\n/* Accessibility: Artifex color for main document links */\n.wy-nav-content a {\n    color: #007aff;\n}\n\n/* Artifex blue color for background elements */\n.wy-side-nav-search, .wy-nav-top {\n    background-color: #007aff;\n}\n\n/* Accessibility: ensures that the version number is readable against the background color */\n.wy-side-nav-search>div.version {\n    color:hsla(0,0%,100%,1);\n}\n\n.htmltag {\n    padding: 2px 5px;\n    background-color: #fbff68;\n    border-radius: 4px;\n    border: 1px solid #222;\n    color:#000;\n}\n\n.discordLink {\n    display:flex;\n    justify-content:flex-end;\n    margin:0;\n    padding:0;\n    font-size: 13px;\n}\n\n.discordLink img {\n    width: 30px;\n    height: 30px;\n    margin-left: 8px;\n}\n\n.feedbackLink {\n    display:flex;\n    justify-content:flex-end;\n    margin:0 0 10px;\n    padding:0;\n    font-size: 13px;\n}\n\n.intro-title {\n    font-size: 22px;\n    margin: 0 0 20px 0;\n}\n\nh1 {\n    padding: 10px !important;\n    background-color: #007aff !important;\n    color: #fff !important;\n    border-radius: 5px !important;\n    margin-top: 20px !important;\n    margin-left: -10px !important;\n}\n\ncite {\n    font-weight: bold;\n    font-style: normal;\n}\n\n.red-color {\n    color: #cc0000;\n}\n\n.orange-color {\n    color: #ff6600;\n}\n\n.green-color {\n    color: #00cc00;\n}\n\nbutton.cta {\n    -webkit-appearance: none;\n    -moz-appearance: none;\n    border:0;\n    text-transform:uppercase;\n    border-radius:5px;\n    font-size:16px;\n    font-weight:500;\n    min-height:40px;\n    line-height:40px;\n    padding: 0 15px;\n    color:#fff;\n    cursor:pointer;\n}\n\nbutton.cta.orange {\n    width:auto;\n    background-image: linear-gradient(to right, #ea5842, #ec6343, #ed6d45, #ef7747, #f0804a) !important;\n}\n\nbutton.cta.orange:hover {\n    background:#ea5842 !important;\n}\n\nbutton.cta a {\n    color:#fff !important;\n}\n\n.footer-version {\n    font-weight: bold;\n    font-size: 12px;\n    color: #999;\n}\n\n\n/*** Furo theme overrides ***/\n/* This is to do with hiding the Furo link text and the \"Made with\" text */\n.bottom-of-page .left-details {\n    font-size:0;\n}\n\n.bottom-of-page .left-details a {\n    display:none;\n}\n\n/* Now ensure that the other copyright text is visible here */\n.bottom-of-page .left-details > * {\n    font-size:12px;\n}\n\n.sidebar-brand-text {\n    font-size: 13px;\n    padding: 0;\n    margin: 0;\n}\n\n.sidebar-logo {\n    width: auto;\n    height: 60px;\n}\n\n.sidebar-container {\n    margin: 0;\n    padding: 0;\n}\n\n\n.sidebar-search-container.top {\n    /*position:sticky;\n    top:10px;*/\n    border-radius: 20px;\n    border: solid #333 1px;\n    /*background-color: #fff;*/\n}\n\n.sidebar-search-container.top .sidebar-search {\n    border-top: 0 !important;\n    border-bottom: 0 !important;\n}\n\n.sidebar-drawer .sidebar-search-container {\n    width: 95%;\n}\n\n.toc-drawer .toc-title {\n    font-weight: bold;\n    text-decoration: underline;\n}\n\n:target>h1:first-of-type, span:target~h1:first-of-type {\n    background-color: #007aff !important;\n    color: #fff !important;\n    padding-top: 40px; /* accommodates header search blocking target */\n    margin-top: -40px;\n}\n\n\n:target>h2:first-of-type, :target>h3:first-of-type,\n:target>h4:first-of-type, :target>h5:first-of-type, :target>h6:first-of-type,\nspan:target~h2:first-of-type, span:target~h3:first-of-type,\nspan:target~h4:first-of-type, span:target~h5:first-of-type, span:target~h6:first-of-type {\n    background-color: transparent !important;\n    padding-top: 40px; /* accommodates header search blocking target */\n    margin-top: -40px;\n    text-decoration: underline;\n}\n\n\n/* small screens */\n@media all and (max-width : 550px)  {\n    .discordLink img {\n        display: none;\n    }\n}\n"
  },
  {
    "path": "docs/_static/prism/prism.css",
    "content": "/* PrismJS 1.29.0\nhttps://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+csharp+cpp+java+kotlin+objectivec+python+shell-session+swift&plugins=normalize-whitespace+toolbar+copy-to-clipboard */\ncode[class*=language-],pre[class*=language-]{color:#000;background:0 0;text-shadow:0 1px #fff;font-family:Consolas,Monaco,'Andale Mono','Ubuntu Mono',monospace;font-size:14px;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-moz-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-] ::-moz-selection,code[class*=language-]::-moz-selection,pre[class*=language-] ::-moz-selection,pre[class*=language-]::-moz-selection{text-shadow:none;background:#b3d4fc}code[class*=language-] ::selection,code[class*=language-]::selection,pre[class*=language-] ::selection,pre[class*=language-]::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}\ndiv.code-toolbar{position:relative}div.code-toolbar>.toolbar{position:absolute;z-index:10;top:.3em;right:.2em;transition:opacity .3s ease-in-out;opacity:0}div.code-toolbar:hover>.toolbar{opacity:1}div.code-toolbar:focus-within>.toolbar{opacity:1}div.code-toolbar>.toolbar>.toolbar-item{display:inline-block}div.code-toolbar>.toolbar>.toolbar-item>a{cursor:pointer}div.code-toolbar>.toolbar>.toolbar-item>button{background:0 0;border:0;color:inherit;font:inherit;line-height:normal;overflow:visible;padding:0;-webkit-user-select:none;-moz-user-select:none;-ms-user-select:none}div.code-toolbar>.toolbar>.toolbar-item>a,div.code-toolbar>.toolbar>.toolbar-item>button,div.code-toolbar>.toolbar>.toolbar-item>span{color:#bbb;font-size:.8em;padding:0 .5em;background:#f5f2f0;background:rgba(224,224,224,.2);box-shadow:0 2px 0 0 rgba(0,0,0,.2);border-radius:.5em}div.code-toolbar>.toolbar>.toolbar-item>a:focus,div.code-toolbar>.toolbar>.toolbar-item>a:hover,div.code-toolbar>.toolbar>.toolbar-item>button:focus,div.code-toolbar>.toolbar>.toolbar-item>button:hover,div.code-toolbar>.toolbar>.toolbar-item>span:focus,div.code-toolbar>.toolbar>.toolbar-item>span:hover{color:inherit;text-decoration:none}\n"
  },
  {
    "path": "docs/_static/prism/prism.html",
    "content": "<html>\n\n    <head>\n\n        <link rel=\"stylesheet\" type=\"text/css\" href=\"prism.css\">\n\n        <style>\n\n            .copy-to-clipboard-button {\n                background: #007aff !important;\n                color: white !important;\n                padding: 10px !important;\n                border-radius: 5px !important;\n                font-family: Arial !important;\n            }\n\n        </style>\n\n        <script type=\"text/javascript\" src=\"prism.js\"></script>\n\n    </head>\n\n\n    <body>\n        See: https://prismjs.com/download.html\n\n\n            <pre style=\"background: white;\">\n                <code class=\"language-python line-numbers\" data-prismjs-copy=\"Copy\">\n                import fitz\n\n                MEDIABOX = fitz.paper_rect(\"letter\")\n                WHERE = MEDIABOX + (36, 36, -36, -36)\n\n                # create story, let it look at script folder for resources\n                story = fitz.Story(archive=\".\")\n                body = story.body  # access the body of its DOM\n\n                with body.add_paragraph() as para:\n                    # store desired content\n                    para.set_font(\"sans-serif\").set_color(\"blue\").add_text(\"Hello World!\")\n\n                # another paragraph for our image:\n                with body.add_paragraph() as para:\n                    # store image in another paragraph\n                    para.add_image(\"world.jpg\")\n\n                writer = fitz.DocumentWriter(\"output.pdf\")\n\n                more = 1\n\n                while more:\n                    device = writer.begin_page(MEDIABOX)\n                    more, _ = story.place(WHERE)\n                    story.draw(device)\n                    writer.end_page()\n\n                writer.close()\n            </code>\n            </pre>\n\n    </body>\n\n    <script>\n        Prism.plugins.NormalizeWhitespace.setDefaults({\n    'remove-trailing': true,\n    'remove-indent': true,\n    'left-trim': true,\n    'right-trim': true,\n    'break-lines': 100,\n    'indent': 0,\n    'remove-initial-line-feed': false,\n    'tabs-to-spaces': 4,\n    'spaces-to-tabs': 4\n});\n</script>\n\nHere is some <code>inline code</code> ok...\n\n</html>"
  },
  {
    "path": "docs/_static/prism/prism.js",
    "content": "/* PrismJS 1.29.0\nhttps://prismjs.com/download.html#themes=prism&languages=markup+css+clike+javascript+bash+c+csharp+cpp+java+kotlin+objectivec+python+shell-session+swift&plugins=normalize-whitespace+toolbar+copy-to-clipboard */\nvar _self=\"undefined\"!=typeof window?window:\"undefined\"!=typeof WorkerGlobalScope&&self instanceof WorkerGlobalScope?self:{},Prism=function(e){var n=/(?:^|\\s)lang(?:uage)?-([\\w-]+)(?=\\s|$)/i,t=0,r={},a={manual:e.Prism&&e.Prism.manual,disableWorkerMessageHandler:e.Prism&&e.Prism.disableWorkerMessageHandler,util:{encode:function e(n){return n instanceof i?new i(n.type,e(n.content),n.alias):Array.isArray(n)?n.map(e):n.replace(/&/g,\"&amp;\").replace(/</g,\"&lt;\").replace(/\\u00a0/g,\" \")},type:function(e){return Object.prototype.toString.call(e).slice(8,-1)},objId:function(e){return e.__id||Object.defineProperty(e,\"__id\",{value:++t}),e.__id},clone:function e(n,t){var r,i;switch(t=t||{},a.util.type(n)){case\"Object\":if(i=a.util.objId(n),t[i])return t[i];for(var l in r={},t[i]=r,n)n.hasOwnProperty(l)&&(r[l]=e(n[l],t));return r;case\"Array\":return i=a.util.objId(n),t[i]?t[i]:(r=[],t[i]=r,n.forEach((function(n,a){r[a]=e(n,t)})),r);default:return n}},getLanguage:function(e){for(;e;){var t=n.exec(e.className);if(t)return t[1].toLowerCase();e=e.parentElement}return\"none\"},setLanguage:function(e,t){e.className=e.className.replace(RegExp(n,\"gi\"),\"\"),e.classList.add(\"language-\"+t)},currentScript:function(){if(\"undefined\"==typeof document)return null;if(\"currentScript\"in document)return document.currentScript;try{throw new Error}catch(r){var e=(/at [^(\\r\\n]*\\((.*):[^:]+:[^:]+\\)$/i.exec(r.stack)||[])[1];if(e){var n=document.getElementsByTagName(\"script\");for(var t in n)if(n[t].src==e)return n[t]}return null}},isActive:function(e,n,t){for(var r=\"no-\"+n;e;){var a=e.classList;if(a.contains(n))return!0;if(a.contains(r))return!1;e=e.parentElement}return!!t}},languages:{plain:r,plaintext:r,text:r,txt:r,extend:function(e,n){var t=a.util.clone(a.languages[e]);for(var r in n)t[r]=n[r];return t},insertBefore:function(e,n,t,r){var i=(r=r||a.languages)[e],l={};for(var o in i)if(i.hasOwnProperty(o)){if(o==n)for(var s in t)t.hasOwnProperty(s)&&(l[s]=t[s]);t.hasOwnProperty(o)||(l[o]=i[o])}var u=r[e];return r[e]=l,a.languages.DFS(a.languages,(function(n,t){t===u&&n!=e&&(this[n]=l)})),l},DFS:function e(n,t,r,i){i=i||{};var l=a.util.objId;for(var o in n)if(n.hasOwnProperty(o)){t.call(n,o,n[o],r||o);var s=n[o],u=a.util.type(s);\"Object\"!==u||i[l(s)]?\"Array\"!==u||i[l(s)]||(i[l(s)]=!0,e(s,t,o,i)):(i[l(s)]=!0,e(s,t,null,i))}}},plugins:{},highlightAll:function(e,n){a.highlightAllUnder(document,e,n)},highlightAllUnder:function(e,n,t){var r={callback:t,container:e,selector:'code[class*=\"language-\"], [class*=\"language-\"] code, code[class*=\"lang-\"], [class*=\"lang-\"] code'};a.hooks.run(\"before-highlightall\",r),r.elements=Array.prototype.slice.apply(r.container.querySelectorAll(r.selector)),a.hooks.run(\"before-all-elements-highlight\",r);for(var i,l=0;i=r.elements[l++];)a.highlightElement(i,!0===n,r.callback)},highlightElement:function(n,t,r){var i=a.util.getLanguage(n),l=a.languages[i];a.util.setLanguage(n,i);var o=n.parentElement;o&&\"pre\"===o.nodeName.toLowerCase()&&a.util.setLanguage(o,i);var s={element:n,language:i,grammar:l,code:n.textContent};function u(e){s.highlightedCode=e,a.hooks.run(\"before-insert\",s),s.element.innerHTML=s.highlightedCode,a.hooks.run(\"after-highlight\",s),a.hooks.run(\"complete\",s),r&&r.call(s.element)}if(a.hooks.run(\"before-sanity-check\",s),(o=s.element.parentElement)&&\"pre\"===o.nodeName.toLowerCase()&&!o.hasAttribute(\"tabindex\")&&o.setAttribute(\"tabindex\",\"0\"),!s.code)return a.hooks.run(\"complete\",s),void(r&&r.call(s.element));if(a.hooks.run(\"before-highlight\",s),s.grammar)if(t&&e.Worker){var c=new Worker(a.filename);c.onmessage=function(e){u(e.data)},c.postMessage(JSON.stringify({language:s.language,code:s.code,immediateClose:!0}))}else u(a.highlight(s.code,s.grammar,s.language));else u(a.util.encode(s.code))},highlight:function(e,n,t){var r={code:e,grammar:n,language:t};if(a.hooks.run(\"before-tokenize\",r),!r.grammar)throw new Error('The language \"'+r.language+'\" has no grammar.');return r.tokens=a.tokenize(r.code,r.grammar),a.hooks.run(\"after-tokenize\",r),i.stringify(a.util.encode(r.tokens),r.language)},tokenize:function(e,n){var t=n.rest;if(t){for(var r in t)n[r]=t[r];delete n.rest}var a=new s;return u(a,a.head,e),o(e,a,n,a.head,0),function(e){for(var n=[],t=e.head.next;t!==e.tail;)n.push(t.value),t=t.next;return n}(a)},hooks:{all:{},add:function(e,n){var t=a.hooks.all;t[e]=t[e]||[],t[e].push(n)},run:function(e,n){var t=a.hooks.all[e];if(t&&t.length)for(var r,i=0;r=t[i++];)r(n)}},Token:i};function i(e,n,t,r){this.type=e,this.content=n,this.alias=t,this.length=0|(r||\"\").length}function l(e,n,t,r){e.lastIndex=n;var a=e.exec(t);if(a&&r&&a[1]){var i=a[1].length;a.index+=i,a[0]=a[0].slice(i)}return a}function o(e,n,t,r,s,g){for(var f in t)if(t.hasOwnProperty(f)&&t[f]){var h=t[f];h=Array.isArray(h)?h:[h];for(var d=0;d<h.length;++d){if(g&&g.cause==f+\",\"+d)return;var v=h[d],p=v.inside,m=!!v.lookbehind,y=!!v.greedy,k=v.alias;if(y&&!v.pattern.global){var x=v.pattern.toString().match(/[imsuy]*$/)[0];v.pattern=RegExp(v.pattern.source,x+\"g\")}for(var b=v.pattern||v,w=r.next,A=s;w!==n.tail&&!(g&&A>=g.reach);A+=w.value.length,w=w.next){var E=w.value;if(n.length>e.length)return;if(!(E instanceof i)){var P,L=1;if(y){if(!(P=l(b,A,e,m))||P.index>=e.length)break;var S=P.index,O=P.index+P[0].length,j=A;for(j+=w.value.length;S>=j;)j+=(w=w.next).value.length;if(A=j-=w.value.length,w.value instanceof i)continue;for(var C=w;C!==n.tail&&(j<O||\"string\"==typeof C.value);C=C.next)L++,j+=C.value.length;L--,E=e.slice(A,j),P.index-=A}else if(!(P=l(b,0,E,m)))continue;S=P.index;var N=P[0],_=E.slice(0,S),M=E.slice(S+N.length),W=A+E.length;g&&W>g.reach&&(g.reach=W);var z=w.prev;if(_&&(z=u(n,z,_),A+=_.length),c(n,z,L),w=u(n,z,new i(f,p?a.tokenize(N,p):N,k,N)),M&&u(n,w,M),L>1){var I={cause:f+\",\"+d,reach:W};o(e,n,t,w.prev,A,I),g&&I.reach>g.reach&&(g.reach=I.reach)}}}}}}function s(){var e={value:null,prev:null,next:null},n={value:null,prev:e,next:null};e.next=n,this.head=e,this.tail=n,this.length=0}function u(e,n,t){var r=n.next,a={value:t,prev:n,next:r};return n.next=a,r.prev=a,e.length++,a}function c(e,n,t){for(var r=n.next,a=0;a<t&&r!==e.tail;a++)r=r.next;n.next=r,r.prev=n,e.length-=a}if(e.Prism=a,i.stringify=function e(n,t){if(\"string\"==typeof n)return n;if(Array.isArray(n)){var r=\"\";return n.forEach((function(n){r+=e(n,t)})),r}var i={type:n.type,content:e(n.content,t),tag:\"span\",classes:[\"token\",n.type],attributes:{},language:t},l=n.alias;l&&(Array.isArray(l)?Array.prototype.push.apply(i.classes,l):i.classes.push(l)),a.hooks.run(\"wrap\",i);var o=\"\";for(var s in i.attributes)o+=\" \"+s+'=\"'+(i.attributes[s]||\"\").replace(/\"/g,\"&quot;\")+'\"';return\"<\"+i.tag+' class=\"'+i.classes.join(\" \")+'\"'+o+\">\"+i.content+\"</\"+i.tag+\">\"},!e.document)return e.addEventListener?(a.disableWorkerMessageHandler||e.addEventListener(\"message\",(function(n){var t=JSON.parse(n.data),r=t.language,i=t.code,l=t.immediateClose;e.postMessage(a.highlight(i,a.languages[r],r)),l&&e.close()}),!1),a):a;var g=a.util.currentScript();function f(){a.manual||a.highlightAll()}if(g&&(a.filename=g.src,g.hasAttribute(\"data-manual\")&&(a.manual=!0)),!a.manual){var h=document.readyState;\"loading\"===h||\"interactive\"===h&&g&&g.defer?document.addEventListener(\"DOMContentLoaded\",f):window.requestAnimationFrame?window.requestAnimationFrame(f):window.setTimeout(f,16)}return a}(_self);\"undefined\"!=typeof module&&module.exports&&(module.exports=Prism),\"undefined\"!=typeof global&&(global.Prism=Prism);\nPrism.languages.markup={comment:{pattern:/<!--(?:(?!<!--)[\\s\\S])*?-->/,greedy:!0},prolog:{pattern:/<\\?[\\s\\S]+?\\?>/,greedy:!0},doctype:{pattern:/<!DOCTYPE(?:[^>\"'[\\]]|\"[^\"]*\"|'[^']*')+(?:\\[(?:[^<\"'\\]]|\"[^\"]*\"|'[^']*'|<(?!!--)|<!--(?:[^-]|-(?!->))*-->)*\\]\\s*)?>/i,greedy:!0,inside:{\"internal-subset\":{pattern:/(^[^\\[]*\\[)[\\s\\S]+(?=\\]>$)/,lookbehind:!0,greedy:!0,inside:null},string:{pattern:/\"[^\"]*\"|'[^']*'/,greedy:!0},punctuation:/^<!|>$|[[\\]]/,\"doctype-tag\":/^DOCTYPE/i,name:/[^\\s<>'\"]+/}},cdata:{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,greedy:!0},tag:{pattern:/<\\/?(?!\\d)[^\\s>\\/=$<%]+(?:\\s(?:\\s*[^\\s>\\/=]+(?:\\s*=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+(?=[\\s>]))|(?=[\\s/>])))+)?\\s*\\/?>/,greedy:!0,inside:{tag:{pattern:/^<\\/?[^\\s>\\/]+/,inside:{punctuation:/^<\\/?/,namespace:/^[^\\s>\\/:]+:/}},\"special-attr\":[],\"attr-value\":{pattern:/=\\s*(?:\"[^\"]*\"|'[^']*'|[^\\s'\">=]+)/,inside:{punctuation:[{pattern:/^=/,alias:\"attr-equals\"},{pattern:/^(\\s*)[\"']|[\"']$/,lookbehind:!0}]}},punctuation:/\\/?>/,\"attr-name\":{pattern:/[^\\s>\\/]+/,inside:{namespace:/^[^\\s>\\/:]+:/}}}},entity:[{pattern:/&[\\da-z]{1,8};/i,alias:\"named-entity\"},/&#x?[\\da-f]{1,8};/i]},Prism.languages.markup.tag.inside[\"attr-value\"].inside.entity=Prism.languages.markup.entity,Prism.languages.markup.doctype.inside[\"internal-subset\"].inside=Prism.languages.markup,Prism.hooks.add(\"wrap\",(function(a){\"entity\"===a.type&&(a.attributes.title=a.content.replace(/&amp;/,\"&\"))})),Object.defineProperty(Prism.languages.markup.tag,\"addInlined\",{value:function(a,e){var s={};s[\"language-\"+e]={pattern:/(^<!\\[CDATA\\[)[\\s\\S]+?(?=\\]\\]>$)/i,lookbehind:!0,inside:Prism.languages[e]},s.cdata=/^<!\\[CDATA\\[|\\]\\]>$/i;var t={\"included-cdata\":{pattern:/<!\\[CDATA\\[[\\s\\S]*?\\]\\]>/i,inside:s}};t[\"language-\"+e]={pattern:/[\\s\\S]+/,inside:Prism.languages[e]};var n={};n[a]={pattern:RegExp(\"(<__[^>]*>)(?:<!\\\\[CDATA\\\\[(?:[^\\\\]]|\\\\](?!\\\\]>))*\\\\]\\\\]>|(?!<!\\\\[CDATA\\\\[)[^])*?(?=</__>)\".replace(/__/g,(function(){return a})),\"i\"),lookbehind:!0,greedy:!0,inside:t},Prism.languages.insertBefore(\"markup\",\"cdata\",n)}}),Object.defineProperty(Prism.languages.markup.tag,\"addAttribute\",{value:function(a,e){Prism.languages.markup.tag.inside[\"special-attr\"].push({pattern:RegExp(\"(^|[\\\"'\\\\s])(?:\"+a+\")\\\\s*=\\\\s*(?:\\\"[^\\\"]*\\\"|'[^']*'|[^\\\\s'\\\">=]+(?=[\\\\s>]))\",\"i\"),lookbehind:!0,inside:{\"attr-name\":/^[^\\s=]+/,\"attr-value\":{pattern:/=[\\s\\S]+/,inside:{value:{pattern:/(^=\\s*([\"']|(?![\"'])))\\S[\\s\\S]*(?=\\2$)/,lookbehind:!0,alias:[e,\"language-\"+e],inside:Prism.languages[e]},punctuation:[{pattern:/^=/,alias:\"attr-equals\"},/\"|'/]}}}})}}),Prism.languages.html=Prism.languages.markup,Prism.languages.mathml=Prism.languages.markup,Prism.languages.svg=Prism.languages.markup,Prism.languages.xml=Prism.languages.extend(\"markup\",{}),Prism.languages.ssml=Prism.languages.xml,Prism.languages.atom=Prism.languages.xml,Prism.languages.rss=Prism.languages.xml;\n!function(s){var e=/(?:\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\"\\\\\\r\\n])*\"|'(?:\\\\(?:\\r\\n|[\\s\\S])|[^'\\\\\\r\\n])*')/;s.languages.css={comment:/\\/\\*[\\s\\S]*?\\*\\//,atrule:{pattern:RegExp(\"@[\\\\w-](?:[^;{\\\\s\\\"']|\\\\s+(?!\\\\s)|\"+e.source+\")*?(?:;|(?=\\\\s*\\\\{))\"),inside:{rule:/^@[\\w-]+/,\"selector-function-argument\":{pattern:/(\\bselector\\s*\\(\\s*(?![\\s)]))(?:[^()\\s]|\\s+(?![\\s)])|\\((?:[^()]|\\([^()]*\\))*\\))+(?=\\s*\\))/,lookbehind:!0,alias:\"selector\"},keyword:{pattern:/(^|[^\\w-])(?:and|not|only|or)(?![\\w-])/,lookbehind:!0}}},url:{pattern:RegExp(\"\\\\burl\\\\((?:\"+e.source+\"|(?:[^\\\\\\\\\\r\\n()\\\"']|\\\\\\\\[^])*)\\\\)\",\"i\"),greedy:!0,inside:{function:/^url/i,punctuation:/^\\(|\\)$/,string:{pattern:RegExp(\"^\"+e.source+\"$\"),alias:\"url\"}}},selector:{pattern:RegExp(\"(^|[{}\\\\s])[^{}\\\\s](?:[^{};\\\"'\\\\s]|\\\\s+(?![\\\\s{])|\"+e.source+\")*(?=\\\\s*\\\\{)\"),lookbehind:!0},string:{pattern:e,greedy:!0},property:{pattern:/(^|[^-\\w\\xA0-\\uFFFF])(?!\\s)[-_a-z\\xA0-\\uFFFF](?:(?!\\s)[-\\w\\xA0-\\uFFFF])*(?=\\s*:)/i,lookbehind:!0},important:/!important\\b/i,function:{pattern:/(^|[^-a-z0-9])[-a-z0-9]+(?=\\()/i,lookbehind:!0},punctuation:/[(){};:,]/},s.languages.css.atrule.inside.rest=s.languages.css;var t=s.languages.markup;t&&(t.tag.addInlined(\"style\",\"css\"),t.tag.addAttribute(\"style\",\"css\"))}(Prism);\nPrism.languages.clike={comment:[{pattern:/(^|[^\\\\])\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,lookbehind:!0,greedy:!0},{pattern:/(^|[^\\\\:])\\/\\/.*/,lookbehind:!0,greedy:!0}],string:{pattern:/([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\1)[^\\\\\\r\\n])*\\1/,greedy:!0},\"class-name\":{pattern:/(\\b(?:class|extends|implements|instanceof|interface|new|trait)\\s+|\\bcatch\\s+\\()[\\w.\\\\]+/i,lookbehind:!0,inside:{punctuation:/[.\\\\]/}},keyword:/\\b(?:break|catch|continue|do|else|finally|for|function|if|in|instanceof|new|null|return|throw|try|while)\\b/,boolean:/\\b(?:false|true)\\b/,function:/\\b\\w+(?=\\()/,number:/\\b0x[\\da-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?/i,operator:/[<>]=?|[!=]=?=?|--?|\\+\\+?|&&?|\\|\\|?|[?*/~^%]/,punctuation:/[{}[\\];(),.:]/};\nPrism.languages.javascript=Prism.languages.extend(\"clike\",{\"class-name\":[Prism.languages.clike[\"class-name\"],{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$A-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\.(?:constructor|prototype))/,lookbehind:!0}],keyword:[{pattern:/((?:^|\\})\\s*)catch\\b/,lookbehind:!0},{pattern:/(^|[^.]|\\.\\.\\.\\s*)\\b(?:as|assert(?=\\s*\\{)|async(?=\\s*(?:function\\b|\\(|[$\\w\\xA0-\\uFFFF]|$))|await|break|case|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally(?=\\s*(?:\\{|$))|for|from(?=\\s*(?:['\"]|$))|function|(?:get|set)(?=\\s*(?:[#\\[$\\w\\xA0-\\uFFFF]|$))|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)\\b/,lookbehind:!0}],function:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*(?:\\.\\s*(?:apply|bind|call)\\s*)?\\()/,number:{pattern:RegExp(\"(^|[^\\\\w$])(?:NaN|Infinity|0[bB][01]+(?:_[01]+)*n?|0[oO][0-7]+(?:_[0-7]+)*n?|0[xX][\\\\dA-Fa-f]+(?:_[\\\\dA-Fa-f]+)*n?|\\\\d+(?:_\\\\d+)*n|(?:\\\\d+(?:_\\\\d+)*(?:\\\\.(?:\\\\d+(?:_\\\\d+)*)?)?|\\\\.\\\\d+(?:_\\\\d+)*)(?:[Ee][+-]?\\\\d+(?:_\\\\d+)*)?)(?![\\\\w$])\"),lookbehind:!0},operator:/--|\\+\\+|\\*\\*=?|=>|&&=?|\\|\\|=?|[!=]==|<<=?|>>>?=?|[-+*/%&|^!=<>]=?|\\.{3}|\\?\\?=?|\\?\\.?|[~:]/}),Prism.languages.javascript[\"class-name\"][0].pattern=/(\\b(?:class|extends|implements|instanceof|interface|new)\\s+)[\\w.\\\\]+/,Prism.languages.insertBefore(\"javascript\",\"keyword\",{regex:{pattern:RegExp(\"((?:^|[^$\\\\w\\\\xA0-\\\\uFFFF.\\\"'\\\\])\\\\s]|\\\\b(?:return|yield))\\\\s*)/(?:(?:\\\\[(?:[^\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.)*\\\\]|\\\\\\\\.|[^/\\\\\\\\\\\\[\\r\\n])+/[dgimyus]{0,7}|(?:\\\\[(?:[^[\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.|\\\\[(?:[^[\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.|\\\\[(?:[^[\\\\]\\\\\\\\\\r\\n]|\\\\\\\\.)*\\\\])*\\\\])*\\\\]|\\\\\\\\.|[^/\\\\\\\\\\\\[\\r\\n])+/[dgimyus]{0,7}v[dgimyus]{0,7})(?=(?:\\\\s|/\\\\*(?:[^*]|\\\\*(?!/))*\\\\*/)*(?:$|[\\r\\n,.;:})\\\\]]|//))\"),lookbehind:!0,greedy:!0,inside:{\"regex-source\":{pattern:/^(\\/)[\\s\\S]+(?=\\/[a-z]*$)/,lookbehind:!0,alias:\"language-regex\",inside:Prism.languages.regex},\"regex-delimiter\":/^\\/|\\/$/,\"regex-flags\":/^[a-z]+$/}},\"function-variable\":{pattern:/#?(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*[=:]\\s*(?:async\\s*)?(?:\\bfunction\\b|(?:\\((?:[^()]|\\([^()]*\\))*\\)|(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)\\s*=>))/,alias:\"function\"},parameter:[{pattern:/(function(?:\\s+(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*)?\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\))/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(^|[^$\\w\\xA0-\\uFFFF])(?!\\s)[_$a-z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*=>)/i,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/(\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*=>)/,lookbehind:!0,inside:Prism.languages.javascript},{pattern:/((?:\\b|\\s|^)(?!(?:as|async|await|break|case|catch|class|const|continue|debugger|default|delete|do|else|enum|export|extends|finally|for|from|function|get|if|implements|import|in|instanceof|interface|let|new|null|of|package|private|protected|public|return|set|static|super|switch|this|throw|try|typeof|undefined|var|void|while|with|yield)(?![$\\w\\xA0-\\uFFFF]))(?:(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*\\s*)\\(\\s*|\\]\\s*\\(\\s*)(?!\\s)(?:[^()\\s]|\\s+(?![\\s)])|\\([^()]*\\))+(?=\\s*\\)\\s*\\{)/,lookbehind:!0,inside:Prism.languages.javascript}],constant:/\\b[A-Z](?:[A-Z_]|\\dx?)*\\b/}),Prism.languages.insertBefore(\"javascript\",\"string\",{hashbang:{pattern:/^#!.*/,greedy:!0,alias:\"comment\"},\"template-string\":{pattern:/`(?:\\\\[\\s\\S]|\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}|(?!\\$\\{)[^\\\\`])*`/,greedy:!0,inside:{\"template-punctuation\":{pattern:/^`|`$/,alias:\"string\"},interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\$\\{(?:[^{}]|\\{(?:[^{}]|\\{[^}]*\\})*\\})+\\}/,lookbehind:!0,inside:{\"interpolation-punctuation\":{pattern:/^\\$\\{|\\}$/,alias:\"punctuation\"},rest:Prism.languages.javascript}},string:/[\\s\\S]+/}},\"string-property\":{pattern:/((?:^|[,{])[ \\t]*)([\"'])(?:\\\\(?:\\r\\n|[\\s\\S])|(?!\\2)[^\\\\\\r\\n])*\\2(?=\\s*:)/m,lookbehind:!0,greedy:!0,alias:\"property\"}}),Prism.languages.insertBefore(\"javascript\",\"operator\",{\"literal-property\":{pattern:/((?:^|[,{])[ \\t]*)(?!\\s)[_$a-zA-Z\\xA0-\\uFFFF](?:(?!\\s)[$\\w\\xA0-\\uFFFF])*(?=\\s*:)/m,lookbehind:!0,alias:\"property\"}}),Prism.languages.markup&&(Prism.languages.markup.tag.addInlined(\"script\",\"javascript\"),Prism.languages.markup.tag.addAttribute(\"on(?:abort|blur|change|click|composition(?:end|start|update)|dblclick|error|focus(?:in|out)?|key(?:down|up)|load|mouse(?:down|enter|leave|move|out|over|up)|reset|resize|scroll|select|slotchange|submit|unload|wheel)\",\"javascript\")),Prism.languages.js=Prism.languages.javascript;\n!function(e){var t=\"\\\\b(?:BASH|BASHOPTS|BASH_ALIASES|BASH_ARGC|BASH_ARGV|BASH_CMDS|BASH_COMPLETION_COMPAT_DIR|BASH_LINENO|BASH_REMATCH|BASH_SOURCE|BASH_VERSINFO|BASH_VERSION|COLORTERM|COLUMNS|COMP_WORDBREAKS|DBUS_SESSION_BUS_ADDRESS|DEFAULTS_PATH|DESKTOP_SESSION|DIRSTACK|DISPLAY|EUID|GDMSESSION|GDM_LANG|GNOME_KEYRING_CONTROL|GNOME_KEYRING_PID|GPG_AGENT_INFO|GROUPS|HISTCONTROL|HISTFILE|HISTFILESIZE|HISTSIZE|HOME|HOSTNAME|HOSTTYPE|IFS|INSTANCE|JOB|LANG|LANGUAGE|LC_ADDRESS|LC_ALL|LC_IDENTIFICATION|LC_MEASUREMENT|LC_MONETARY|LC_NAME|LC_NUMERIC|LC_PAPER|LC_TELEPHONE|LC_TIME|LESSCLOSE|LESSOPEN|LINES|LOGNAME|LS_COLORS|MACHTYPE|MAILCHECK|MANDATORY_PATH|NO_AT_BRIDGE|OLDPWD|OPTERR|OPTIND|ORBIT_SOCKETDIR|OSTYPE|PAPERSIZE|PATH|PIPESTATUS|PPID|PS1|PS2|PS3|PS4|PWD|RANDOM|REPLY|SECONDS|SELINUX_INIT|SESSION|SESSIONTYPE|SESSION_MANAGER|SHELL|SHELLOPTS|SHLVL|SSH_AUTH_SOCK|TERM|UID|UPSTART_EVENTS|UPSTART_INSTANCE|UPSTART_JOB|UPSTART_SESSION|USER|WINDOWID|XAUTHORITY|XDG_CONFIG_DIRS|XDG_CURRENT_DESKTOP|XDG_DATA_DIRS|XDG_GREETER_DATA_DIR|XDG_MENU_PREFIX|XDG_RUNTIME_DIR|XDG_SEAT|XDG_SEAT_PATH|XDG_SESSION_DESKTOP|XDG_SESSION_ID|XDG_SESSION_PATH|XDG_SESSION_TYPE|XDG_VTNR|XMODIFIERS)\\\\b\",a={pattern:/(^([\"']?)\\w+\\2)[ \\t]+\\S.*/,lookbehind:!0,alias:\"punctuation\",inside:null},n={bash:a,environment:{pattern:RegExp(\"\\\\$\"+t),alias:\"constant\"},variable:[{pattern:/\\$?\\(\\([\\s\\S]+?\\)\\)/,greedy:!0,inside:{variable:[{pattern:/(^\\$\\(\\([\\s\\S]+)\\)\\)/,lookbehind:!0},/^\\$\\(\\(/],number:/\\b0x[\\dA-Fa-f]+\\b|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:[Ee]-?\\d+)?/,operator:/--|\\+\\+|\\*\\*=?|<<=?|>>=?|&&|\\|\\||[=!+\\-*/%<>^&|]=?|[?~:]/,punctuation:/\\(\\(?|\\)\\)?|,|;/}},{pattern:/\\$\\((?:\\([^)]+\\)|[^()])+\\)|`[^`]+`/,greedy:!0,inside:{variable:/^\\$\\(|^`|\\)$|`$/}},{pattern:/\\$\\{[^}]+\\}/,greedy:!0,inside:{operator:/:[-=?+]?|[!\\/]|##?|%%?|\\^\\^?|,,?/,punctuation:/[\\[\\]]/,environment:{pattern:RegExp(\"(\\\\{)\"+t),lookbehind:!0,alias:\"constant\"}}},/\\$(?:\\w+|[#?*!@$])/],entity:/\\\\(?:[abceEfnrtv\\\\\"]|O?[0-7]{1,3}|U[0-9a-fA-F]{8}|u[0-9a-fA-F]{4}|x[0-9a-fA-F]{1,2})/};e.languages.bash={shebang:{pattern:/^#!\\s*\\/.*/,alias:\"important\"},comment:{pattern:/(^|[^\"{\\\\$])#.*/,lookbehind:!0},\"function-name\":[{pattern:/(\\bfunction\\s+)[\\w-]+(?=(?:\\s*\\(?:\\s*\\))?\\s*\\{)/,lookbehind:!0,alias:\"function\"},{pattern:/\\b[\\w-]+(?=\\s*\\(\\s*\\)\\s*\\{)/,alias:\"function\"}],\"for-or-select\":{pattern:/(\\b(?:for|select)\\s+)\\w+(?=\\s+in\\s)/,alias:\"variable\",lookbehind:!0},\"assign-left\":{pattern:/(^|[\\s;|&]|[<>]\\()\\w+(?:\\.\\w+)*(?=\\+?=)/,inside:{environment:{pattern:RegExp(\"(^|[\\\\s;|&]|[<>]\\\\()\"+t),lookbehind:!0,alias:\"constant\"}},alias:\"variable\",lookbehind:!0},parameter:{pattern:/(^|\\s)-{1,2}(?:\\w+:[+-]?)?\\w+(?:\\.\\w+)*(?=[=\\s]|$)/,alias:\"variable\",lookbehind:!0},string:[{pattern:/((?:^|[^<])<<-?\\s*)(\\w+)\\s[\\s\\S]*?(?:\\r?\\n|\\r)\\2/,lookbehind:!0,greedy:!0,inside:n},{pattern:/((?:^|[^<])<<-?\\s*)([\"'])(\\w+)\\2\\s[\\s\\S]*?(?:\\r?\\n|\\r)\\3/,lookbehind:!0,greedy:!0,inside:{bash:a}},{pattern:/(^|[^\\\\](?:\\\\\\\\)*)\"(?:\\\\[\\s\\S]|\\$\\([^)]+\\)|\\$(?!\\()|`[^`]+`|[^\"\\\\`$])*\"/,lookbehind:!0,greedy:!0,inside:n},{pattern:/(^|[^$\\\\])'[^']*'/,lookbehind:!0,greedy:!0},{pattern:/\\$'(?:[^'\\\\]|\\\\[\\s\\S])*'/,greedy:!0,inside:{entity:n.entity}}],environment:{pattern:RegExp(\"\\\\$?\"+t),alias:\"constant\"},variable:n.variable,function:{pattern:/(^|[\\s;|&]|[<>]\\()(?:add|apropos|apt|apt-cache|apt-get|aptitude|aspell|automysqlbackup|awk|basename|bash|bc|bconsole|bg|bzip2|cal|cargo|cat|cfdisk|chgrp|chkconfig|chmod|chown|chroot|cksum|clear|cmp|column|comm|composer|cp|cron|crontab|csplit|curl|cut|date|dc|dd|ddrescue|debootstrap|df|diff|diff3|dig|dir|dircolors|dirname|dirs|dmesg|docker|docker-compose|du|egrep|eject|env|ethtool|expand|expect|expr|fdformat|fdisk|fg|fgrep|file|find|fmt|fold|format|free|fsck|ftp|fuser|gawk|git|gparted|grep|groupadd|groupdel|groupmod|groups|grub-mkconfig|gzip|halt|head|hg|history|host|hostname|htop|iconv|id|ifconfig|ifdown|ifup|import|install|ip|java|jobs|join|kill|killall|less|link|ln|locate|logname|logrotate|look|lpc|lpr|lprint|lprintd|lprintq|lprm|ls|lsof|lynx|make|man|mc|mdadm|mkconfig|mkdir|mke2fs|mkfifo|mkfs|mkisofs|mknod|mkswap|mmv|more|most|mount|mtools|mtr|mutt|mv|nano|nc|netstat|nice|nl|node|nohup|notify-send|npm|nslookup|op|open|parted|passwd|paste|pathchk|ping|pkill|pnpm|podman|podman-compose|popd|pr|printcap|printenv|ps|pushd|pv|quota|quotacheck|quotactl|ram|rar|rcp|reboot|remsync|rename|renice|rev|rm|rmdir|rpm|rsync|scp|screen|sdiff|sed|sendmail|seq|service|sftp|sh|shellcheck|shuf|shutdown|sleep|slocate|sort|split|ssh|stat|strace|su|sudo|sum|suspend|swapon|sync|sysctl|tac|tail|tar|tee|time|timeout|top|touch|tr|traceroute|tsort|tty|umount|uname|unexpand|uniq|units|unrar|unshar|unzip|update-grub|uptime|useradd|userdel|usermod|users|uudecode|uuencode|v|vcpkg|vdir|vi|vim|virsh|vmstat|wait|watch|wc|wget|whereis|which|who|whoami|write|xargs|xdg-open|yarn|yes|zenity|zip|zsh|zypper)(?=$|[)\\s;|&])/,lookbehind:!0},keyword:{pattern:/(^|[\\s;|&]|[<>]\\()(?:case|do|done|elif|else|esac|fi|for|function|if|in|select|then|until|while)(?=$|[)\\s;|&])/,lookbehind:!0},builtin:{pattern:/(^|[\\s;|&]|[<>]\\()(?:\\.|:|alias|bind|break|builtin|caller|cd|command|continue|declare|echo|enable|eval|exec|exit|export|getopts|hash|help|let|local|logout|mapfile|printf|pwd|read|readarray|readonly|return|set|shift|shopt|source|test|times|trap|type|typeset|ulimit|umask|unalias|unset)(?=$|[)\\s;|&])/,lookbehind:!0,alias:\"class-name\"},boolean:{pattern:/(^|[\\s;|&]|[<>]\\()(?:false|true)(?=$|[)\\s;|&])/,lookbehind:!0},\"file-descriptor\":{pattern:/\\B&\\d\\b/,alias:\"important\"},operator:{pattern:/\\d?<>|>\\||\\+=|=[=~]?|!=?|<<[<-]?|[&\\d]?>>|\\d[<>]&?|[<>][&=]?|&[>&]?|\\|[&|]?/,inside:{\"file-descriptor\":{pattern:/^\\d/,alias:\"important\"}}},punctuation:/\\$?\\(\\(?|\\)\\)?|\\.\\.|[{}[\\];\\\\]/,number:{pattern:/(^|\\s)(?:[1-9]\\d*|0)(?:[.,]\\d+)?\\b/,lookbehind:!0}},a.inside=e.languages.bash;for(var s=[\"comment\",\"function-name\",\"for-or-select\",\"assign-left\",\"parameter\",\"string\",\"environment\",\"function\",\"keyword\",\"builtin\",\"boolean\",\"file-descriptor\",\"operator\",\"punctuation\",\"number\"],o=n.variable[1].inside,i=0;i<s.length;i++)o[s[i]]=e.languages.bash[s[i]];e.languages.sh=e.languages.bash,e.languages.shell=e.languages.bash}(Prism);\nPrism.languages.c=Prism.languages.extend(\"clike\",{comment:{pattern:/\\/\\/(?:[^\\r\\n\\\\]|\\\\(?:\\r\\n?|\\n|(?![\\r\\n])))*|\\/\\*[\\s\\S]*?(?:\\*\\/|$)/,greedy:!0},string:{pattern:/\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\"\\\\\\r\\n])*\"/,greedy:!0},\"class-name\":{pattern:/(\\b(?:enum|struct)\\s+(?:__attribute__\\s*\\(\\([\\s\\S]*?\\)\\)\\s*)?)\\w+|\\b[a-z]\\w*_t\\b/,lookbehind:!0},keyword:/\\b(?:_Alignas|_Alignof|_Atomic|_Bool|_Complex|_Generic|_Imaginary|_Noreturn|_Static_assert|_Thread_local|__attribute__|asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|inline|int|long|register|return|short|signed|sizeof|static|struct|switch|typedef|typeof|union|unsigned|void|volatile|while)\\b/,function:/\\b[a-z_]\\w*(?=\\s*\\()/i,number:/(?:\\b0x(?:[\\da-f]+(?:\\.[\\da-f]*)?|\\.[\\da-f]+)(?:p[+-]?\\d+)?|(?:\\b\\d+(?:\\.\\d*)?|\\B\\.\\d+)(?:e[+-]?\\d+)?)[ful]{0,4}/i,operator:/>>=?|<<=?|->|([-+&|:])\\1|[?:~]|[-+*/%&|^!=<>]=?/}),Prism.languages.insertBefore(\"c\",\"string\",{char:{pattern:/'(?:\\\\(?:\\r\\n|[\\s\\S])|[^'\\\\\\r\\n]){0,32}'/,greedy:!0}}),Prism.languages.insertBefore(\"c\",\"string\",{macro:{pattern:/(^[\\t ]*)#\\s*[a-z](?:[^\\r\\n\\\\/]|\\/(?!\\*)|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/|\\\\(?:\\r\\n|[\\s\\S]))*/im,lookbehind:!0,greedy:!0,alias:\"property\",inside:{string:[{pattern:/^(#\\s*include\\s*)<[^>]+>/,lookbehind:!0},Prism.languages.c.string],char:Prism.languages.c.char,comment:Prism.languages.c.comment,\"macro-name\":[{pattern:/(^#\\s*define\\s+)\\w+\\b(?!\\()/i,lookbehind:!0},{pattern:/(^#\\s*define\\s+)\\w+\\b(?=\\()/i,lookbehind:!0,alias:\"function\"}],directive:{pattern:/^(#\\s*)[a-z]+/,lookbehind:!0,alias:\"keyword\"},\"directive-hash\":/^#/,punctuation:/##|\\\\(?=[\\r\\n])/,expression:{pattern:/\\S[\\s\\S]*/,inside:Prism.languages.c}}}}),Prism.languages.insertBefore(\"c\",\"function\",{constant:/\\b(?:EOF|NULL|SEEK_CUR|SEEK_END|SEEK_SET|__DATE__|__FILE__|__LINE__|__TIMESTAMP__|__TIME__|__func__|stderr|stdin|stdout)\\b/}),delete Prism.languages.c.boolean;\n!function(e){function n(e,n){return e.replace(/<<(\\d+)>>/g,(function(e,s){return\"(?:\"+n[+s]+\")\"}))}function s(e,s,a){return RegExp(n(e,s),a||\"\")}function a(e,n){for(var s=0;s<n;s++)e=e.replace(/<<self>>/g,(function(){return\"(?:\"+e+\")\"}));return e.replace(/<<self>>/g,\"[^\\\\s\\\\S]\")}var t=\"bool byte char decimal double dynamic float int long object sbyte short string uint ulong ushort var void\",r=\"class enum interface record struct\",i=\"add alias and ascending async await by descending from(?=\\\\s*(?:\\\\w|$)) get global group into init(?=\\\\s*;) join let nameof not notnull on or orderby partial remove select set unmanaged value when where with(?=\\\\s*{)\",o=\"abstract as base break case catch checked const continue default delegate do else event explicit extern finally fixed for foreach goto if implicit in internal is lock namespace new null operator out override params private protected public readonly ref return sealed sizeof stackalloc static switch this throw try typeof unchecked unsafe using virtual volatile while yield\";function l(e){return\"\\\\b(?:\"+e.trim().replace(/ /g,\"|\")+\")\\\\b\"}var d=l(r),p=RegExp(l(t+\" \"+r+\" \"+i+\" \"+o)),c=l(r+\" \"+i+\" \"+o),u=l(t+\" \"+r+\" \"+o),g=a(\"<(?:[^<>;=+\\\\-*/%&|^]|<<self>>)*>\",2),b=a(\"\\\\((?:[^()]|<<self>>)*\\\\)\",2),h=\"@?\\\\b[A-Za-z_]\\\\w*\\\\b\",f=n(\"<<0>>(?:\\\\s*<<1>>)?\",[h,g]),m=n(\"(?!<<0>>)<<1>>(?:\\\\s*\\\\.\\\\s*<<1>>)*\",[c,f]),k=\"\\\\[\\\\s*(?:,\\\\s*)*\\\\]\",y=n(\"<<0>>(?:\\\\s*(?:\\\\?\\\\s*)?<<1>>)*(?:\\\\s*\\\\?)?\",[m,k]),w=n(\"[^,()<>[\\\\];=+\\\\-*/%&|^]|<<0>>|<<1>>|<<2>>\",[g,b,k]),v=n(\"\\\\(<<0>>+(?:,<<0>>+)+\\\\)\",[w]),x=n(\"(?:<<0>>|<<1>>)(?:\\\\s*(?:\\\\?\\\\s*)?<<2>>)*(?:\\\\s*\\\\?)?\",[v,m,k]),$={keyword:p,punctuation:/[<>()?,.:[\\]]/},_=\"'(?:[^\\r\\n'\\\\\\\\]|\\\\\\\\.|\\\\\\\\[Uux][\\\\da-fA-F]{1,8})'\",B='\"(?:\\\\\\\\.|[^\\\\\\\\\"\\r\\n])*\"';e.languages.csharp=e.languages.extend(\"clike\",{string:[{pattern:s(\"(^|[^$\\\\\\\\])<<0>>\",['@\"(?:\"\"|\\\\\\\\[^]|[^\\\\\\\\\"])*\"(?!\")']),lookbehind:!0,greedy:!0},{pattern:s(\"(^|[^@$\\\\\\\\])<<0>>\",[B]),lookbehind:!0,greedy:!0}],\"class-name\":[{pattern:s(\"(\\\\busing\\\\s+static\\\\s+)<<0>>(?=\\\\s*;)\",[m]),lookbehind:!0,inside:$},{pattern:s(\"(\\\\busing\\\\s+<<0>>\\\\s*=\\\\s*)<<1>>(?=\\\\s*;)\",[h,x]),lookbehind:!0,inside:$},{pattern:s(\"(\\\\busing\\\\s+)<<0>>(?=\\\\s*=)\",[h]),lookbehind:!0},{pattern:s(\"(\\\\b<<0>>\\\\s+)<<1>>\",[d,f]),lookbehind:!0,inside:$},{pattern:s(\"(\\\\bcatch\\\\s*\\\\(\\\\s*)<<0>>\",[m]),lookbehind:!0,inside:$},{pattern:s(\"(\\\\bwhere\\\\s+)<<0>>\",[h]),lookbehind:!0},{pattern:s(\"(\\\\b(?:is(?:\\\\s+not)?|as)\\\\s+)<<0>>\",[y]),lookbehind:!0,inside:$},{pattern:s(\"\\\\b<<0>>(?=\\\\s+(?!<<1>>|with\\\\s*\\\\{)<<2>>(?:\\\\s*[=,;:{)\\\\]]|\\\\s+(?:in|when)\\\\b))\",[x,u,h]),inside:$}],keyword:p,number:/(?:\\b0(?:x[\\da-f_]*[\\da-f]|b[01_]*[01])|(?:\\B\\.\\d+(?:_+\\d+)*|\\b\\d+(?:_+\\d+)*(?:\\.\\d+(?:_+\\d+)*)?)(?:e[-+]?\\d+(?:_+\\d+)*)?)(?:[dflmu]|lu|ul)?\\b/i,operator:/>>=?|<<=?|[-=]>|([-+&|])\\1|~|\\?\\?=?|[-+*/%&|^!=<>]=?/,punctuation:/\\?\\.?|::|[{}[\\];(),.:]/}),e.languages.insertBefore(\"csharp\",\"number\",{range:{pattern:/\\.\\./,alias:\"operator\"}}),e.languages.insertBefore(\"csharp\",\"punctuation\",{\"named-parameter\":{pattern:s(\"([(,]\\\\s*)<<0>>(?=\\\\s*:)\",[h]),lookbehind:!0,alias:\"punctuation\"}}),e.languages.insertBefore(\"csharp\",\"class-name\",{namespace:{pattern:s(\"(\\\\b(?:namespace|using)\\\\s+)<<0>>(?:\\\\s*\\\\.\\\\s*<<0>>)*(?=\\\\s*[;{])\",[h]),lookbehind:!0,inside:{punctuation:/\\./}},\"type-expression\":{pattern:s(\"(\\\\b(?:default|sizeof|typeof)\\\\s*\\\\(\\\\s*(?!\\\\s))(?:[^()\\\\s]|\\\\s(?!\\\\s)|<<0>>)*(?=\\\\s*\\\\))\",[b]),lookbehind:!0,alias:\"class-name\",inside:$},\"return-type\":{pattern:s(\"<<0>>(?=\\\\s+(?:<<1>>\\\\s*(?:=>|[({]|\\\\.\\\\s*this\\\\s*\\\\[)|this\\\\s*\\\\[))\",[x,m]),inside:$,alias:\"class-name\"},\"constructor-invocation\":{pattern:s(\"(\\\\bnew\\\\s+)<<0>>(?=\\\\s*[[({])\",[x]),lookbehind:!0,inside:$,alias:\"class-name\"},\"generic-method\":{pattern:s(\"<<0>>\\\\s*<<1>>(?=\\\\s*\\\\()\",[h,g]),inside:{function:s(\"^<<0>>\",[h]),generic:{pattern:RegExp(g),alias:\"class-name\",inside:$}}},\"type-list\":{pattern:s(\"\\\\b((?:<<0>>\\\\s+<<1>>|record\\\\s+<<1>>\\\\s*<<5>>|where\\\\s+<<2>>)\\\\s*:\\\\s*)(?:<<3>>|<<4>>|<<1>>\\\\s*<<5>>|<<6>>)(?:\\\\s*,\\\\s*(?:<<3>>|<<4>>|<<6>>))*(?=\\\\s*(?:where|[{;]|=>|$))\",[d,f,h,x,p.source,b,\"\\\\bnew\\\\s*\\\\(\\\\s*\\\\)\"]),lookbehind:!0,inside:{\"record-arguments\":{pattern:s(\"(^(?!new\\\\s*\\\\()<<0>>\\\\s*)<<1>>\",[f,b]),lookbehind:!0,greedy:!0,inside:e.languages.csharp},keyword:p,\"class-name\":{pattern:RegExp(x),greedy:!0,inside:$},punctuation:/[,()]/}},preprocessor:{pattern:/(^[\\t ]*)#.*/m,lookbehind:!0,alias:\"property\",inside:{directive:{pattern:/(#)\\b(?:define|elif|else|endif|endregion|error|if|line|nullable|pragma|region|undef|warning)\\b/,lookbehind:!0,alias:\"keyword\"}}}});var E=B+\"|\"+_,R=n(\"/(?![*/])|//[^\\r\\n]*[\\r\\n]|/\\\\*(?:[^*]|\\\\*(?!/))*\\\\*/|<<0>>\",[E]),z=a(n(\"[^\\\"'/()]|<<0>>|\\\\(<<self>>*\\\\)\",[R]),2),S=\"\\\\b(?:assembly|event|field|method|module|param|property|return|type)\\\\b\",j=n(\"<<0>>(?:\\\\s*\\\\(<<1>>*\\\\))?\",[m,z]);e.languages.insertBefore(\"csharp\",\"class-name\",{attribute:{pattern:s(\"((?:^|[^\\\\s\\\\w>)?])\\\\s*\\\\[\\\\s*)(?:<<0>>\\\\s*:\\\\s*)?<<1>>(?:\\\\s*,\\\\s*<<1>>)*(?=\\\\s*\\\\])\",[S,j]),lookbehind:!0,greedy:!0,inside:{target:{pattern:s(\"^<<0>>(?=\\\\s*:)\",[S]),alias:\"keyword\"},\"attribute-arguments\":{pattern:s(\"\\\\(<<0>>*\\\\)\",[z]),inside:e.languages.csharp},\"class-name\":{pattern:RegExp(m),inside:{punctuation:/\\./}},punctuation:/[:,]/}}});var A=\":[^}\\r\\n]+\",F=a(n(\"[^\\\"'/()]|<<0>>|\\\\(<<self>>*\\\\)\",[R]),2),P=n(\"\\\\{(?!\\\\{)(?:(?![}:])<<0>>)*<<1>>?\\\\}\",[F,A]),U=a(n(\"[^\\\"'/()]|/(?!\\\\*)|/\\\\*(?:[^*]|\\\\*(?!/))*\\\\*/|<<0>>|\\\\(<<self>>*\\\\)\",[E]),2),Z=n(\"\\\\{(?!\\\\{)(?:(?![}:])<<0>>)*<<1>>?\\\\}\",[U,A]);function q(n,a){return{interpolation:{pattern:s(\"((?:^|[^{])(?:\\\\{\\\\{)*)<<0>>\",[n]),lookbehind:!0,inside:{\"format-string\":{pattern:s(\"(^\\\\{(?:(?![}:])<<0>>)*)<<1>>(?=\\\\}$)\",[a,A]),lookbehind:!0,inside:{punctuation:/^:/}},punctuation:/^\\{|\\}$/,expression:{pattern:/[\\s\\S]+/,alias:\"language-csharp\",inside:e.languages.csharp}}},string:/[\\s\\S]+/}}e.languages.insertBefore(\"csharp\",\"string\",{\"interpolation-string\":[{pattern:s('(^|[^\\\\\\\\])(?:\\\\$@|@\\\\$)\"(?:\"\"|\\\\\\\\[^]|\\\\{\\\\{|<<0>>|[^\\\\\\\\{\"])*\"',[P]),lookbehind:!0,greedy:!0,inside:q(P,F)},{pattern:s('(^|[^@\\\\\\\\])\\\\$\"(?:\\\\\\\\.|\\\\{\\\\{|<<0>>|[^\\\\\\\\\"{])*\"',[Z]),lookbehind:!0,greedy:!0,inside:q(Z,U)}],char:{pattern:RegExp(_),greedy:!0}}),e.languages.dotnet=e.languages.cs=e.languages.csharp}(Prism);\n!function(e){var t=/\\b(?:alignas|alignof|asm|auto|bool|break|case|catch|char|char16_t|char32_t|char8_t|class|co_await|co_return|co_yield|compl|concept|const|const_cast|consteval|constexpr|constinit|continue|decltype|default|delete|do|double|dynamic_cast|else|enum|explicit|export|extern|final|float|for|friend|goto|if|import|inline|int|int16_t|int32_t|int64_t|int8_t|long|module|mutable|namespace|new|noexcept|nullptr|operator|override|private|protected|public|register|reinterpret_cast|requires|return|short|signed|sizeof|static|static_assert|static_cast|struct|switch|template|this|thread_local|throw|try|typedef|typeid|typename|uint16_t|uint32_t|uint64_t|uint8_t|union|unsigned|using|virtual|void|volatile|wchar_t|while)\\b/,n=\"\\\\b(?!<keyword>)\\\\w+(?:\\\\s*\\\\.\\\\s*\\\\w+)*\\\\b\".replace(/<keyword>/g,(function(){return t.source}));e.languages.cpp=e.languages.extend(\"c\",{\"class-name\":[{pattern:RegExp(\"(\\\\b(?:class|concept|enum|struct|typename)\\\\s+)(?!<keyword>)\\\\w+\".replace(/<keyword>/g,(function(){return t.source}))),lookbehind:!0},/\\b[A-Z]\\w*(?=\\s*::\\s*\\w+\\s*\\()/,/\\b[A-Z_]\\w*(?=\\s*::\\s*~\\w+\\s*\\()/i,/\\b\\w+(?=\\s*<(?:[^<>]|<(?:[^<>]|<[^<>]*>)*>)*>\\s*::\\s*\\w+\\s*\\()/],keyword:t,number:{pattern:/(?:\\b0b[01']+|\\b0x(?:[\\da-f']+(?:\\.[\\da-f']*)?|\\.[\\da-f']+)(?:p[+-]?[\\d']+)?|(?:\\b[\\d']+(?:\\.[\\d']*)?|\\B\\.[\\d']+)(?:e[+-]?[\\d']+)?)[ful]{0,4}/i,greedy:!0},operator:/>>=?|<<=?|->|--|\\+\\+|&&|\\|\\||[?:~]|<=>|[-+*/%&|^!=<>]=?|\\b(?:and|and_eq|bitand|bitor|not|not_eq|or|or_eq|xor|xor_eq)\\b/,boolean:/\\b(?:false|true)\\b/}),e.languages.insertBefore(\"cpp\",\"string\",{module:{pattern:RegExp('(\\\\b(?:import|module)\\\\s+)(?:\"(?:\\\\\\\\(?:\\r\\n|[^])|[^\"\\\\\\\\\\r\\n])*\"|<[^<>\\r\\n]*>|'+\"<mod-name>(?:\\\\s*:\\\\s*<mod-name>)?|:\\\\s*<mod-name>\".replace(/<mod-name>/g,(function(){return n}))+\")\"),lookbehind:!0,greedy:!0,inside:{string:/^[<\"][\\s\\S]+/,operator:/:/,punctuation:/\\./}},\"raw-string\":{pattern:/R\"([^()\\\\ ]{0,16})\\([\\s\\S]*?\\)\\1\"/,alias:\"string\",greedy:!0}}),e.languages.insertBefore(\"cpp\",\"keyword\",{\"generic-function\":{pattern:/\\b(?!operator\\b)[a-z_]\\w*\\s*<(?:[^<>]|<[^<>]*>)*>(?=\\s*\\()/i,inside:{function:/^\\w+/,generic:{pattern:/<[\\s\\S]+/,alias:\"class-name\",inside:e.languages.cpp}}}}),e.languages.insertBefore(\"cpp\",\"operator\",{\"double-colon\":{pattern:/::/,alias:\"punctuation\"}}),e.languages.insertBefore(\"cpp\",\"class-name\",{\"base-clause\":{pattern:/(\\b(?:class|struct)\\s+\\w+\\s*:\\s*)[^;{}\"'\\s]+(?:\\s+[^;{}\"'\\s]+)*(?=\\s*[;{])/,lookbehind:!0,greedy:!0,inside:e.languages.extend(\"cpp\",{})}}),e.languages.insertBefore(\"inside\",\"double-colon\",{\"class-name\":/\\b[a-z_]\\w*\\b(?!\\s*::)/i},e.languages.cpp[\"base-clause\"])}(Prism);\n!function(e){var n=/\\b(?:abstract|assert|boolean|break|byte|case|catch|char|class|const|continue|default|do|double|else|enum|exports|extends|final|finally|float|for|goto|if|implements|import|instanceof|int|interface|long|module|native|new|non-sealed|null|open|opens|package|permits|private|protected|provides|public|record(?!\\s*[(){}[\\]<>=%~.:,;?+\\-*/&|^])|requires|return|sealed|short|static|strictfp|super|switch|synchronized|this|throw|throws|to|transient|transitive|try|uses|var|void|volatile|while|with|yield)\\b/,t=\"(?:[a-z]\\\\w*\\\\s*\\\\.\\\\s*)*(?:[A-Z]\\\\w*\\\\s*\\\\.\\\\s*)*\",s={pattern:RegExp(\"(^|[^\\\\w.])\"+t+\"[A-Z](?:[\\\\d_A-Z]*[a-z]\\\\w*)?\\\\b\"),lookbehind:!0,inside:{namespace:{pattern:/^[a-z]\\w*(?:\\s*\\.\\s*[a-z]\\w*)*(?:\\s*\\.)?/,inside:{punctuation:/\\./}},punctuation:/\\./}};e.languages.java=e.languages.extend(\"clike\",{string:{pattern:/(^|[^\\\\])\"(?:\\\\.|[^\"\\\\\\r\\n])*\"/,lookbehind:!0,greedy:!0},\"class-name\":[s,{pattern:RegExp(\"(^|[^\\\\w.])\"+t+\"[A-Z]\\\\w*(?=\\\\s+\\\\w+\\\\s*[;,=()]|\\\\s*(?:\\\\[[\\\\s,]*\\\\]\\\\s*)?::\\\\s*new\\\\b)\"),lookbehind:!0,inside:s.inside},{pattern:RegExp(\"(\\\\b(?:class|enum|extends|implements|instanceof|interface|new|record|throws)\\\\s+)\"+t+\"[A-Z]\\\\w*\\\\b\"),lookbehind:!0,inside:s.inside}],keyword:n,function:[e.languages.clike.function,{pattern:/(::\\s*)[a-z_]\\w*/,lookbehind:!0}],number:/\\b0b[01][01_]*L?\\b|\\b0x(?:\\.[\\da-f_p+-]+|[\\da-f_]+(?:\\.[\\da-f_p+-]+)?)\\b|(?:\\b\\d[\\d_]*(?:\\.[\\d_]*)?|\\B\\.\\d[\\d_]*)(?:e[+-]?\\d[\\d_]*)?[dfl]?/i,operator:{pattern:/(^|[^.])(?:<<=?|>>>?=?|->|--|\\+\\+|&&|\\|\\||::|[?:~]|[-+*/%&|^!=<>]=?)/m,lookbehind:!0},constant:/\\b[A-Z][A-Z_\\d]+\\b/}),e.languages.insertBefore(\"java\",\"string\",{\"triple-quoted-string\":{pattern:/\"\"\"[ \\t]*[\\r\\n](?:(?:\"|\"\")?(?:\\\\.|[^\"\\\\]))*\"\"\"/,greedy:!0,alias:\"string\"},char:{pattern:/'(?:\\\\.|[^'\\\\\\r\\n]){1,6}'/,greedy:!0}}),e.languages.insertBefore(\"java\",\"class-name\",{annotation:{pattern:/(^|[^.])@\\w+(?:\\s*\\.\\s*\\w+)*/,lookbehind:!0,alias:\"punctuation\"},generics:{pattern:/<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&)|<(?:[\\w\\s,.?]|&(?!&))*>)*>)*>)*>/,inside:{\"class-name\":s,keyword:n,punctuation:/[<>(),.:]/,operator:/[?&|]/}},import:[{pattern:RegExp(\"(\\\\bimport\\\\s+)\"+t+\"(?:[A-Z]\\\\w*|\\\\*)(?=\\\\s*;)\"),lookbehind:!0,inside:{namespace:s.inside.namespace,punctuation:/\\./,operator:/\\*/,\"class-name\":/\\w+/}},{pattern:RegExp(\"(\\\\bimport\\\\s+static\\\\s+)\"+t+\"(?:\\\\w+|\\\\*)(?=\\\\s*;)\"),lookbehind:!0,alias:\"static\",inside:{namespace:s.inside.namespace,static:/\\b\\w+$/,punctuation:/\\./,operator:/\\*/,\"class-name\":/\\w+/}}],namespace:{pattern:RegExp(\"(\\\\b(?:exports|import(?:\\\\s+static)?|module|open|opens|package|provides|requires|to|transitive|uses|with)\\\\s+)(?!<keyword>)[a-z]\\\\w*(?:\\\\.[a-z]\\\\w*)*\\\\.?\".replace(/<keyword>/g,(function(){return n.source}))),lookbehind:!0,inside:{punctuation:/\\./}}})}(Prism);\n!function(n){n.languages.kotlin=n.languages.extend(\"clike\",{keyword:{pattern:/(^|[^.])\\b(?:abstract|actual|annotation|as|break|by|catch|class|companion|const|constructor|continue|crossinline|data|do|dynamic|else|enum|expect|external|final|finally|for|fun|get|if|import|in|infix|init|inline|inner|interface|internal|is|lateinit|noinline|null|object|open|operator|out|override|package|private|protected|public|reified|return|sealed|set|super|suspend|tailrec|this|throw|to|try|typealias|val|var|vararg|when|where|while)\\b/,lookbehind:!0},function:[{pattern:/(?:`[^\\r\\n`]+`|\\b\\w+)(?=\\s*\\()/,greedy:!0},{pattern:/(\\.)(?:`[^\\r\\n`]+`|\\w+)(?=\\s*\\{)/,lookbehind:!0,greedy:!0}],number:/\\b(?:0[xX][\\da-fA-F]+(?:_[\\da-fA-F]+)*|0[bB][01]+(?:_[01]+)*|\\d+(?:_\\d+)*(?:\\.\\d+(?:_\\d+)*)?(?:[eE][+-]?\\d+(?:_\\d+)*)?[fFL]?)\\b/,operator:/\\+[+=]?|-[-=>]?|==?=?|!(?:!|==?)?|[\\/*%<>]=?|[?:]:?|\\.\\.|&&|\\|\\||\\b(?:and|inv|or|shl|shr|ushr|xor)\\b/}),delete n.languages.kotlin[\"class-name\"];var e={\"interpolation-punctuation\":{pattern:/^\\$\\{?|\\}$/,alias:\"punctuation\"},expression:{pattern:/[\\s\\S]+/,inside:n.languages.kotlin}};n.languages.insertBefore(\"kotlin\",\"string\",{\"string-literal\":[{pattern:/\"\"\"(?:[^$]|\\$(?:(?!\\{)|\\{[^{}]*\\}))*?\"\"\"/,alias:\"multiline\",inside:{interpolation:{pattern:/\\$(?:[a-z_]\\w*|\\{[^{}]*\\})/i,inside:e},string:/[\\s\\S]+/}},{pattern:/\"(?:[^\"\\\\\\r\\n$]|\\\\.|\\$(?:(?!\\{)|\\{[^{}]*\\}))*\"/,alias:\"singleline\",inside:{interpolation:{pattern:/((?:^|[^\\\\])(?:\\\\{2})*)\\$(?:[a-z_]\\w*|\\{[^{}]*\\})/i,lookbehind:!0,inside:e},string:/[\\s\\S]+/}}],char:{pattern:/'(?:[^'\\\\\\r\\n]|\\\\(?:.|u[a-fA-F0-9]{0,4}))'/,greedy:!0}}),delete n.languages.kotlin.string,n.languages.insertBefore(\"kotlin\",\"keyword\",{annotation:{pattern:/\\B@(?:\\w+:)?(?:[A-Z]\\w*|\\[[^\\]]+\\])/,alias:\"builtin\"}}),n.languages.insertBefore(\"kotlin\",\"function\",{label:{pattern:/\\b\\w+@|@\\w+\\b/,alias:\"symbol\"}}),n.languages.kt=n.languages.kotlin,n.languages.kts=n.languages.kotlin}(Prism);\nPrism.languages.objectivec=Prism.languages.extend(\"c\",{string:{pattern:/@?\"(?:\\\\(?:\\r\\n|[\\s\\S])|[^\"\\\\\\r\\n])*\"/,greedy:!0},keyword:/\\b(?:asm|auto|break|case|char|const|continue|default|do|double|else|enum|extern|float|for|goto|if|in|inline|int|long|register|return|self|short|signed|sizeof|static|struct|super|switch|typedef|typeof|union|unsigned|void|volatile|while)\\b|(?:@interface|@end|@implementation|@protocol|@class|@public|@protected|@private|@property|@try|@catch|@finally|@throw|@synthesize|@dynamic|@selector)\\b/,operator:/-[->]?|\\+\\+?|!=?|<<?=?|>>?=?|==?|&&?|\\|\\|?|[~^%?*\\/@]/}),delete Prism.languages.objectivec[\"class-name\"],Prism.languages.objc=Prism.languages.objectivec;\nPrism.languages.python={comment:{pattern:/(^|[^\\\\])#.*/,lookbehind:!0,greedy:!0},\"string-interpolation\":{pattern:/(?:f|fr|rf)(?:(\"\"\"|''')[\\s\\S]*?\\1|(\"|')(?:\\\\.|(?!\\2)[^\\\\\\r\\n])*\\2)/i,greedy:!0,inside:{interpolation:{pattern:/((?:^|[^{])(?:\\{\\{)*)\\{(?!\\{)(?:[^{}]|\\{(?!\\{)(?:[^{}]|\\{(?!\\{)(?:[^{}])+\\})+\\})+\\}/,lookbehind:!0,inside:{\"format-spec\":{pattern:/(:)[^:(){}]+(?=\\}$)/,lookbehind:!0},\"conversion-option\":{pattern:/![sra](?=[:}]$)/,alias:\"punctuation\"},rest:null}},string:/[\\s\\S]+/}},\"triple-quoted-string\":{pattern:/(?:[rub]|br|rb)?(\"\"\"|''')[\\s\\S]*?\\1/i,greedy:!0,alias:\"string\"},string:{pattern:/(?:[rub]|br|rb)?(\"|')(?:\\\\.|(?!\\1)[^\\\\\\r\\n])*\\1/i,greedy:!0},function:{pattern:/((?:^|\\s)def[ \\t]+)[a-zA-Z_]\\w*(?=\\s*\\()/g,lookbehind:!0},\"class-name\":{pattern:/(\\bclass\\s+)\\w+/i,lookbehind:!0},decorator:{pattern:/(^[\\t ]*)@\\w+(?:\\.\\w+)*/m,lookbehind:!0,alias:[\"annotation\",\"punctuation\"],inside:{punctuation:/\\./}},keyword:/\\b(?:_(?=\\s*:)|and|as|assert|async|await|break|case|class|continue|def|del|elif|else|except|exec|finally|for|from|global|if|import|in|is|lambda|match|nonlocal|not|or|pass|print|raise|return|try|while|with|yield)\\b/,builtin:/\\b(?:__import__|abs|all|any|apply|ascii|basestring|bin|bool|buffer|bytearray|bytes|callable|chr|classmethod|cmp|coerce|compile|complex|delattr|dict|dir|divmod|enumerate|eval|execfile|file|filter|float|format|frozenset|getattr|globals|hasattr|hash|help|hex|id|input|int|intern|isinstance|issubclass|iter|len|list|locals|long|map|max|memoryview|min|next|object|oct|open|ord|pow|property|range|raw_input|reduce|reload|repr|reversed|round|set|setattr|slice|sorted|staticmethod|str|sum|super|tuple|type|unichr|unicode|vars|xrange|zip)\\b/,boolean:/\\b(?:False|None|True)\\b/,number:/\\b0(?:b(?:_?[01])+|o(?:_?[0-7])+|x(?:_?[a-f0-9])+)\\b|(?:\\b\\d+(?:_\\d+)*(?:\\.(?:\\d+(?:_\\d+)*)?)?|\\B\\.\\d+(?:_\\d+)*)(?:e[+-]?\\d+(?:_\\d+)*)?j?(?!\\w)/i,operator:/[-+%=]=?|!=|:=|\\*\\*?=?|\\/\\/?=?|<[<=>]?|>[=>]?|[&|^~]/,punctuation:/[{}[\\];(),.:]/},Prism.languages.python[\"string-interpolation\"].inside.interpolation.inside.rest=Prism.languages.python,Prism.languages.py=Prism.languages.python;\n!function(s){var n=['\"(?:\\\\\\\\[^]|\\\\$\\\\([^)]+\\\\)|\\\\$(?!\\\\()|`[^`]+`|[^\"\\\\\\\\`$])*\"',\"'[^']*'\",\"\\\\$'(?:[^'\\\\\\\\]|\\\\\\\\[^])*'\",\"<<-?\\\\s*([\\\"']?)(\\\\w+)\\\\1\\\\s[^]*?[\\r\\n]\\\\2\"].join(\"|\");s.languages[\"shell-session\"]={command:{pattern:RegExp('^(?:[^\\\\s@:$#%*!/\\\\\\\\]+@[^\\r\\n@:$#%*!/\\\\\\\\]+(?::[^\\0-\\\\x1F$#%*?\"<>:;|]+)?|[/~.][^\\0-\\\\x1F$#%*?\"<>@:;|]*)?[$#%](?=\\\\s)'+\"(?:[^\\\\\\\\\\r\\n \\t'\\\"<$]|[ \\t](?:(?!#)|#.*$)|\\\\\\\\(?:[^\\r]|\\r\\n?)|\\\\$(?!')|<(?!<)|<<str>>)+\".replace(/<<str>>/g,(function(){return n})),\"m\"),greedy:!0,inside:{info:{pattern:/^[^#$%]+/,alias:\"punctuation\",inside:{user:/^[^\\s@:$#%*!/\\\\]+@[^\\r\\n@:$#%*!/\\\\]+/,punctuation:/:/,path:/[\\s\\S]+/}},bash:{pattern:/(^[$#%]\\s*)\\S[\\s\\S]*/,lookbehind:!0,alias:\"language-bash\",inside:s.languages.bash},\"shell-symbol\":{pattern:/^[$#%]/,alias:\"important\"}}},output:/.(?:.*(?:[\\r\\n]|.$))*/},s.languages[\"sh-session\"]=s.languages.shellsession=s.languages[\"shell-session\"]}(Prism);\nPrism.languages.swift={comment:{pattern:/(^|[^\\\\:])(?:\\/\\/.*|\\/\\*(?:[^/*]|\\/(?!\\*)|\\*(?!\\/)|\\/\\*(?:[^*]|\\*(?!\\/))*\\*\\/)*\\*\\/)/,lookbehind:!0,greedy:!0},\"string-literal\":[{pattern:RegExp('(^|[^\"#])(?:\"(?:\\\\\\\\(?:\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\)|\\r\\n|[^(])|[^\\\\\\\\\\r\\n\"])*\"|\"\"\"(?:\\\\\\\\(?:\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\)|[^(])|[^\\\\\\\\\"]|\"(?!\"\"))*\"\"\")(?![\"#])'),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\\\\\()(?:[^()]|\\([^()]*\\))*(?=\\))/,lookbehind:!0,inside:null},\"interpolation-punctuation\":{pattern:/^\\)|\\\\\\($/,alias:\"punctuation\"},punctuation:/\\\\(?=[\\r\\n])/,string:/[\\s\\S]+/}},{pattern:RegExp('(^|[^\"#])(#+)(?:\"(?:\\\\\\\\(?:#+\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\)|\\r\\n|[^#])|[^\\\\\\\\\\r\\n])*?\"|\"\"\"(?:\\\\\\\\(?:#+\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\)|[^#])|[^\\\\\\\\])*?\"\"\")\\\\2'),lookbehind:!0,greedy:!0,inside:{interpolation:{pattern:/(\\\\#+\\()(?:[^()]|\\([^()]*\\))*(?=\\))/,lookbehind:!0,inside:null},\"interpolation-punctuation\":{pattern:/^\\)|\\\\#+\\($/,alias:\"punctuation\"},string:/[\\s\\S]+/}}],directive:{pattern:RegExp(\"#(?:(?:elseif|if)\\\\b(?:[ \\t]*(?:![ \\t]*)?(?:\\\\b\\\\w+\\\\b(?:[ \\t]*\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\))?|\\\\((?:[^()]|\\\\([^()]*\\\\))*\\\\))(?:[ \\t]*(?:&&|\\\\|\\\\|))?)+|(?:else|endif)\\\\b)\"),alias:\"property\",inside:{\"directive-name\":/^#\\w+/,boolean:/\\b(?:false|true)\\b/,number:/\\b\\d+(?:\\.\\d+)*\\b/,operator:/!|&&|\\|\\||[<>]=?/,punctuation:/[(),]/}},literal:{pattern:/#(?:colorLiteral|column|dsohandle|file(?:ID|Literal|Path)?|function|imageLiteral|line)\\b/,alias:\"constant\"},\"other-directive\":{pattern:/#\\w+\\b/,alias:\"property\"},attribute:{pattern:/@\\w+/,alias:\"atrule\"},\"function-definition\":{pattern:/(\\bfunc\\s+)\\w+/,lookbehind:!0,alias:\"function\"},label:{pattern:/\\b(break|continue)\\s+\\w+|\\b[a-zA-Z_]\\w*(?=\\s*:\\s*(?:for|repeat|while)\\b)/,lookbehind:!0,alias:\"important\"},keyword:/\\b(?:Any|Protocol|Self|Type|actor|as|assignment|associatedtype|associativity|async|await|break|case|catch|class|continue|convenience|default|defer|deinit|didSet|do|dynamic|else|enum|extension|fallthrough|fileprivate|final|for|func|get|guard|higherThan|if|import|in|indirect|infix|init|inout|internal|is|isolated|lazy|left|let|lowerThan|mutating|none|nonisolated|nonmutating|open|operator|optional|override|postfix|precedencegroup|prefix|private|protocol|public|repeat|required|rethrows|return|right|safe|self|set|some|static|struct|subscript|super|switch|throw|throws|try|typealias|unowned|unsafe|var|weak|where|while|willSet)\\b/,boolean:/\\b(?:false|true)\\b/,nil:{pattern:/\\bnil\\b/,alias:\"constant\"},\"short-argument\":/\\$\\d+\\b/,omit:{pattern:/\\b_\\b/,alias:\"keyword\"},number:/\\b(?:[\\d_]+(?:\\.[\\de_]+)?|0x[a-f0-9_]+(?:\\.[a-f0-9p_]+)?|0b[01_]+|0o[0-7_]+)\\b/i,\"class-name\":/\\b[A-Z](?:[A-Z_\\d]*[a-z]\\w*)?\\b/,function:/\\b[a-z_]\\w*(?=\\s*\\()/i,constant:/\\b(?:[A-Z_]{2,}|k[A-Z][A-Za-z_]+)\\b/,operator:/[-+*/%=!<>&|^~?]+|\\.[.\\-+*/%=!<>&|^~?]+/,punctuation:/[{}[\\]();,.:\\\\]/},Prism.languages.swift[\"string-literal\"].forEach((function(e){e.inside.interpolation.inside=Prism.languages.swift}));\n!function(){if(\"undefined\"!=typeof Prism){var e=Object.assign||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n]);return e},t={\"remove-trailing\":\"boolean\",\"remove-indent\":\"boolean\",\"left-trim\":\"boolean\",\"right-trim\":\"boolean\",\"break-lines\":\"number\",indent:\"number\",\"remove-initial-line-feed\":\"boolean\",\"tabs-to-spaces\":\"number\",\"spaces-to-tabs\":\"number\"};n.prototype={setDefaults:function(t){this.defaults=e(this.defaults,t)},normalize:function(t,n){for(var r in n=e(this.defaults,n)){var i=r.replace(/-(\\w)/g,(function(e,t){return t.toUpperCase()}));\"normalize\"!==r&&\"setDefaults\"!==i&&n[r]&&this[i]&&(t=this[i].call(this,t,n[r]))}return t},leftTrim:function(e){return e.replace(/^\\s+/,\"\")},rightTrim:function(e){return e.replace(/\\s+$/,\"\")},tabsToSpaces:function(e,t){return t=0|t||4,e.replace(/\\t/g,new Array(++t).join(\" \"))},spacesToTabs:function(e,t){return t=0|t||4,e.replace(RegExp(\" {\"+t+\"}\",\"g\"),\"\\t\")},removeTrailing:function(e){return e.replace(/\\s*?$/gm,\"\")},removeInitialLineFeed:function(e){return e.replace(/^(?:\\r?\\n|\\r)/,\"\")},removeIndent:function(e){var t=e.match(/^[^\\S\\n\\r]*(?=\\S)/gm);return t&&t[0].length?(t.sort((function(e,t){return e.length-t.length})),t[0].length?e.replace(RegExp(\"^\"+t[0],\"gm\"),\"\"):e):e},indent:function(e,t){return e.replace(/^[^\\S\\n\\r]*(?=\\S)/gm,new Array(++t).join(\"\\t\")+\"$&\")},breakLines:function(e,t){t=!0===t?80:0|t||80;for(var n=e.split(\"\\n\"),i=0;i<n.length;++i)if(!(r(n[i])<=t)){for(var o=n[i].split(/(\\s+)/g),a=0,l=0;l<o.length;++l){var s=r(o[l]);(a+=s)>t&&(o[l]=\"\\n\"+o[l],a=s)}n[i]=o.join(\"\")}return n.join(\"\\n\")}},\"undefined\"!=typeof module&&module.exports&&(module.exports=n),Prism.plugins.NormalizeWhitespace=new n({\"remove-trailing\":!0,\"remove-indent\":!0,\"left-trim\":!0,\"right-trim\":!0}),Prism.hooks.add(\"before-sanity-check\",(function(e){var n=Prism.plugins.NormalizeWhitespace;if((!e.settings||!1!==e.settings[\"whitespace-normalization\"])&&Prism.util.isActive(e.element,\"whitespace-normalization\",!0))if(e.element&&e.element.parentNode||!e.code){var r=e.element.parentNode;if(e.code&&r&&\"pre\"===r.nodeName.toLowerCase()){for(var i in null==e.settings&&(e.settings={}),t)if(Object.hasOwnProperty.call(t,i)){var o=t[i];if(r.hasAttribute(\"data-\"+i))try{var a=JSON.parse(r.getAttribute(\"data-\"+i)||\"true\");typeof a===o&&(e.settings[i]=a)}catch(e){}}for(var l=r.childNodes,s=\"\",c=\"\",u=!1,m=0;m<l.length;++m){var f=l[m];f==e.element?u=!0:\"#text\"===f.nodeName&&(u?c+=f.nodeValue:s+=f.nodeValue,r.removeChild(f),--m)}if(e.element.children.length&&Prism.plugins.KeepMarkup){var d=s+e.element.innerHTML+c;e.element.innerHTML=n.normalize(d,e.settings),e.code=e.element.textContent}else e.code=s+e.code+c,e.code=n.normalize(e.code,e.settings)}}else e.code=n.normalize(e.code,e.settings)}))}function n(t){this.defaults=e({},t)}function r(e){for(var t=0,n=0;n<e.length;++n)e.charCodeAt(n)==\"\\t\".charCodeAt(0)&&(t+=3);return e.length+t}}();\n!function(){if(\"undefined\"!=typeof Prism&&\"undefined\"!=typeof document){var e=[],t={},n=function(){};Prism.plugins.toolbar={};var a=Prism.plugins.toolbar.registerButton=function(n,a){var r;r=\"function\"==typeof a?a:function(e){var t;return\"function\"==typeof a.onClick?((t=document.createElement(\"button\")).type=\"button\",t.addEventListener(\"click\",(function(){a.onClick.call(this,e)}))):\"string\"==typeof a.url?(t=document.createElement(\"a\")).href=a.url:t=document.createElement(\"span\"),a.className&&t.classList.add(a.className),t.textContent=a.text,t},n in t?console.warn('There is a button with the key \"'+n+'\" registered already.'):e.push(t[n]=r)},r=Prism.plugins.toolbar.hook=function(a){var r=a.element.parentNode;if(r&&/pre/i.test(r.nodeName)&&!r.parentNode.classList.contains(\"code-toolbar\")){var o=document.createElement(\"div\");o.classList.add(\"code-toolbar\"),r.parentNode.insertBefore(o,r),o.appendChild(r);var i=document.createElement(\"div\");i.classList.add(\"toolbar\");var l=e,d=function(e){for(;e;){var t=e.getAttribute(\"data-toolbar-order\");if(null!=t)return(t=t.trim()).length?t.split(/\\s*,\\s*/g):[];e=e.parentElement}}(a.element);d&&(l=d.map((function(e){return t[e]||n}))),l.forEach((function(e){var t=e(a);if(t){var n=document.createElement(\"div\");n.classList.add(\"toolbar-item\"),n.appendChild(t),i.appendChild(n)}})),o.appendChild(i)}};a(\"label\",(function(e){var t=e.element.parentNode;if(t&&/pre/i.test(t.nodeName)&&t.hasAttribute(\"data-label\")){var n,a,r=t.getAttribute(\"data-label\");try{a=document.querySelector(\"template#\"+r)}catch(e){}return a?n=a.content:(t.hasAttribute(\"data-url\")?(n=document.createElement(\"a\")).href=t.getAttribute(\"data-url\"):n=document.createElement(\"span\"),n.textContent=r),n}})),Prism.hooks.add(\"complete\",r)}}();\n!function(){function t(t){var e=document.createElement(\"textarea\");e.value=t.getText(),e.style.top=\"0\",e.style.left=\"0\",e.style.position=\"fixed\",document.body.appendChild(e),e.focus(),e.select();try{var o=document.execCommand(\"copy\");setTimeout((function(){o?t.success():t.error()}),1)}catch(e){setTimeout((function(){t.error(e)}),1)}document.body.removeChild(e)}\"undefined\"!=typeof Prism&&\"undefined\"!=typeof document&&(Prism.plugins.toolbar?Prism.plugins.toolbar.registerButton(\"copy-to-clipboard\",(function(e){var o=e.element,n=function(t){var e={copy:\"Copy\",\"copy-error\":\"Press Ctrl+C to copy\",\"copy-success\":\"Copied!\",\"copy-timeout\":5e3};for(var o in e){for(var n=\"data-prismjs-\"+o,c=t;c&&!c.hasAttribute(n);)c=c.parentElement;c&&(e[o]=c.getAttribute(n))}return e}(o),c=document.createElement(\"button\");c.className=\"copy-to-clipboard-button\",c.setAttribute(\"type\",\"button\");var r=document.createElement(\"span\");return c.appendChild(r),u(\"copy\"),function(e,o){e.addEventListener(\"click\",(function(){!function(e){navigator.clipboard?navigator.clipboard.writeText(e.getText()).then(e.success,(function(){t(e)})):t(e)}(o)}))}(c,{getText:function(){return o.textContent},success:function(){u(\"copy-success\"),i()},error:function(){u(\"copy-error\"),setTimeout((function(){!function(t){window.getSelection().selectAllChildren(t)}(o)}),1),i()}}),c;function i(){setTimeout((function(){u(\"copy\")}),n[\"copy-timeout\"])}function u(t){r.textContent=n[t],c.setAttribute(\"data-copy-state\",t)}})):console.warn(\"Copy to Clipboard plugin loaded before Toolbar plugin.\"))}();\n"
  },
  {
    "path": "docs/about-feature-matrix.rst",
    "content": "\n\n.. required image embeds for HTML to reference\n\n\n.. image:: images/icons/icon-pdf.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-svg.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-xps.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-cbz.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-mobi.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-epub.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-image.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-fb2.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-txt.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-docx.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-pptx.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-xlsx.svg\n          :width: 0\n          :height: 0\n\n.. image:: images/icons/icon-hangul.svg\n          :width: 0\n          :height: 0\n\n.. raw:: html\n\n\n    <style>\n\n        table {\n            border-style: hidden;\n        }\n\n        #feature-matrix th {\n            border: 1px #999 solid;\n            padding: 10px 2px;\n            background-color: #007aff;\n            color: white;\n            text-align: center;\n        }\n\n        #feature-matrix tr {\n\n        }\n\n        #feature-matrix td {\n            border: 1px #999 solid;\n            padding: 10px 2px;\n            text-align: center;\n        }\n\n        #feature-matrix tr td.yes {\n            background-color: #83e57c !important;\n            color: #000;\n        }\n\n        #feature-matrix tr td.yes::before {\n            content: \"✔︎ \";\n        }\n\n        #feature-matrix tr td.no {\n            background-color: #e5887c !important;\n            color: #000;\n        }\n\n        #feature-matrix tr td.no::before {\n            content: \"✕ \";\n        }\n\n        #feature-matrix tr td.limited {\n            background-color: #e4c07b !important;\n            color: #000;\n        }\n\n        #feature-matrix .icon-holder {\n            line-height: 40px;\n        }\n\n        #feature-matrix .icon {\n            text-indent: 45px;\n            line-height: 40px;\n            width: 100px;\n            height: 40px;\n        }\n\n        #feature-matrix .icon.pdf {\n            background: url(\"_images/icon-pdf.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.xps {\n            background: url(\"_images/icon-xps.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.epub {\n            background: url(\"_images/icon-epub.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.mobi {\n            background: url(\"_images/icon-mobi.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.fb2 {\n            background: url(\"_images/icon-fb2.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.cbz {\n            background: url(\"_images/icon-cbz.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.svg {\n            background: url(\"_images/icon-svg.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.image {\n            background: url(\"_images/icon-image.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.txt {\n            background: url(\"_images/icon-txt.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.docx {\n            background: url(\"_images/icon-docx.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.pptx {\n            background: url(\"_images/icon-pptx.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.xlsx {\n            background: url(\"_images/icon-xlsx.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.hangul {\n            background: url(\"_images/icon-hangul.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n    </style>\n\n\n    <table id=\"feature-matrix\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n        <tr>\n            <th id=\"transFM1\">Feature</th>\n            <th>PyMuPDF</th>\n            <th>pikepdf</th>\n            <th>PyPDF2</th>\n            <th>pdfrw</th>\n            <th>pdfplumber / pdfminer</th>\n        </tr>\n\n\n        <tr id=\"PyMuPDFFileSupport\">\n            <td><cite id=\"transFM2\">Supports Multiple Document Formats</cite></td>\n\n            <td>\n                <span class=\"icon pdf\"><cite>PDF</cite></span>\n                <span class=\"icon xps\"><cite>XPS</cite></span>\n                <span class=\"icon epub\"><cite>EPUB</cite></span>\n                <span class=\"icon mobi\"><cite>MOBI</cite></span>\n                <span class=\"icon fb2\"><cite>FB2</cite></span>\n                <span class=\"icon cbz\"><cite>CBZ</cite></span>\n                <span class=\"icon svg\"><cite>SVG</cite></span>\n                <span class=\"icon txt\"><cite>TXT</cite></span>\n                <span class=\"icon image\"><cite id=\"transFM3\">Image</cite></span>\n                <hr/>\n                <span class=\"icon docx\"><cite>DOCX</cite></span>\n                <span class=\"icon xlsx\"><cite>XLSX</cite></span>\n                <span class=\"icon pptx\"><cite>PPTX</cite></span>\n                <span class=\"icon hangul\"><cite>HWPX</cite></span>\n                <span class=\"\"><cite>See <a href=\"#note\">note</a></cite></span>\n            </td>\n            <td>\n                <span class=\"icon pdf\"><cite>PDF</cite></span>\n            </td>\n            <td>\n                <span class=\"icon pdf\"><cite>PDF</cite></span>\n            </td>\n            <td>\n                <span class=\"icon pdf\"><cite>PDF</cite></span>\n            </td>\n            <td>\n                <span class=\"icon pdf\"><cite>PDF</cite></span>\n            </td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM4\">Implementation</cite></td>\n            <td><cite>Python</cite> <span id=\"transFM5\">and</span> <cite>C</cite></td>\n            <td><cite>Python</cite> <span id=\"transFM6\">and</span> <cite>C++</cite></td>\n            <td><cite>Python</cite></td>\n            <td><cite>Python</cite></td>\n            <td><cite>Python</cite></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM7\">Render Document Pages</cite></td>\n            <td class=\"yes\" id=\"transFM8\">All document types</td>\n            <td class=\"no\" id=\"transFM9\">No rendering</td>\n            <td class=\"no\" id=\"transFM10\">No rendering</td>\n            <td class=\"no\" id=\"transFM11\">No rendering</td>\n            <td class=\"no\" id=\"transFM11x\">No rendering</td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM7x\">Write Text to PDF Page</cite></td>\n            <td class=\"yes\">\n                <br/>\n                <small>See:\n                    <a style=\"color:black;\" href=\"page.html#Page.insert_htmlbox\">Page.insert_htmlbox</a>\n                    <br/>or:<br/>\n                    <a style=\"color:black;\" href=\"page.html#Page.insert_textbox \">Page.insert_textbox</a>\n                    <br/>or:<br/>\n                    <a style=\"color:black;\" href=\"textwriter.html\">TextWriter</a>\n                <small>\n            </td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFMSupportsCJK\">Supports CJK characters</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"yes\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM12\">Extract Text</cite></td>\n            <td class=\"yes\" id=\"transFM13\">All document types</td>\n            <td class=\"no\"></td>\n            <td class=\"yes\"><cite>PDF</cite> <span id=\"transFM14\">only</span></td>\n            <td class=\"no\"></td>\n            <td class=\"yes\"><cite>PDF</cite> <span id=\"transFM14x\">only</span></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFMSupportsMarkdown\">Extract Text as Markdown (.md)</cite></td>\n            <td class=\"yes\" id=\"transFM13x\">All document types</td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td style=\"padding:20px 0;\"><cite id=\"transFMExtractTables\">Extract Tables</cite></td>\n            <td class=\"yes\" id=\"transFM13xx\">All document types</td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"yes\"><cite>PDF</cite> <span id=\"transFM14xx\">only</span></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM15\">Extract Vector Graphics</cite></td>\n            <td class=\"yes\" id=\"transFM16\">All document types</td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"limited\" id=\"transFM16x\">Limited</td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM17\">Draw Vector Graphics (PDF)</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM18\">Based on Existing, Mature Library</cite></td>\n            <td class=\"yes\"><cite>MuPDF</cite></td>\n            <td class=\"yes\"><cite>QPDF</cite></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM19\">Automatic Repair of Damaged PDFs</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM20\">Encrypted PDFs</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"yes\"></td>\n            <td class=\"limited\" id=\"transFM21\">Limited</td>\n            <td class=\"no\"></td>\n            <td class=\"limited\" id=\"transFM21x\">Limited</td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM22\">Linerarized PDFs</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM23\">Incremental Updates</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM24\">Integrates with Jupyter and IPython Notebooks</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"yes\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM25\">Joining / Merging PDF with other Document Types</cite></td>\n            <td class=\"yes\" id=\"transFM26\">All document types</td>\n            <td class=\"yes\"><cite>PDF</cite> <span id=\"transFM27\">only</span> </td>\n            <td class=\"yes\"><cite>PDF</cite> <span id=\"transFM28\">only</span> </td>\n            <td class=\"yes\"><cite>PDF</cite> <span id=\"transFM29\">only</span> </td>\n            <td class=\"yes\"><cite>PDF</cite> <span id=\"transFM29x\">only</span> </td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM30\">OCR API for Seamless Integration with Tesseract</cite></td>\n            <td class=\"yes\" id=\"transFM31\">All document types</td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM32\">Integrated Checkpoint / Restart Feature (PDF)</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM33\">PDF Optional Content</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM34\">PDF Embedded Files</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"yes\"></td>\n            <td class=\"limited\" id=\"transFM35\">Limited</td>\n            <td class=\"no\"></td>\n            <td class=\"limited\" id=\"transFM35x\">Limited</td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM36\">PDF Redactions</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM37\">PDF Annotations</cite></td>\n            <td class=\"yes\" id=\"transFM38\">Full</td>\n            <td class=\"no\"></td>\n            <td class=\"limited\" id=\"transFM39\">Limited</td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM40\">PDF Form Fields</cite></td>\n            <td class=\"yes\" id=\"transFM41\">Create, read, update</td>\n            <td class=\"no\"></td>\n            <td class=\"limited\" id=\"transFM42\">Limited, no creation</td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM43\">PDF Page Labels</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"limited\">Read-only</td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n        <tr>\n            <td><cite id=\"transFM44\">Support Font Sub-Setting</cite></td>\n            <td class=\"yes\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n            <td class=\"no\"></td>\n        </tr>\n\n\n    </table>\n\n    <script>\n\n        let lang = document.getElementsByTagName('html')[0].getAttribute('lang');\n\n        function getTranslation(str) {\n            if (lang == \"ja\") {\n                if (str==\"Feature\") {\n                    return \"特徴\";\n                } else if (str==\"Supports Multiple Document Formats\") {\n                    return \"複数の文書形式に対応\";\n                } else if (str==\"Image\") {\n                    return \"画像\";\n                } else if (str==\"Implementation\") {\n                    return \"実装\";\n                } else if (str==\"and\") {\n                    return \"と\";\n                } else if (str==\"Render Document Pages\") {\n                    return \"文書ページの表示\";\n                } else if (str==\"All document types\") {\n                    return \"すべてのドキュメントタイプ\";\n                } else if (str==\"No rendering\") {\n                    return \"レンダリングなし\";\n                } else if (str==\"Extract Text\") {\n                    return \"テキストを抽出する\";\n                } else if (str==\"Write Text to PDF Page\") {\n                    return \"PDF ページにテキストを書き込む\";\n                } else if (str==\"only\") {\n                    return \"のみ\";\n                } else if (str==\"Extract Vector Graphics\") {\n                    return \"ベクターグラフィックスを抽出する\";\n                } else if (str==\"Draw Vector Graphics (PDF)\") {\n                    return \"ベクターグラフィックスを描(PDF)\";\n                } else if (str==\"Based on Existing, Mature Library\") {\n                    return \"既存で成熟したライブラリに基づいています\";\n                } else if (str==\"Automatic Repair of Damaged PDFs\") {\n                    return \"PDFファイルの自動修復\";\n                } else if (str==\"Encrypted PDFs\") {\n                    return \"暗号化されたPDFファイル\";\n                } else if (str==\"Limited\") {\n                    return \"一部対応\";\n                } else if (str==\"Linerarized PDFs\") {\n                    return \"リニアライズされたPDFファイル\";\n                } else if (str==\"Incremental Updates\") {\n                    return \"インクリメンタル更新\";\n                } else if (str==\"Integrates with Jupyter and IPython Notebooks\") {\n                    return \"JupyterおよびIPython Notebooksと統合\";\n                } else if (str==\"Joining / Merging PDF with other Document Types\") {\n                    return \"他のドキュメントタイプとPDFの結合 / マージ\";\n                } else if (str==\"OCR API for Seamless Integration with Tesseract\") {\n                    return \"Tesseractとのシームレスな統合のためのOCR API\";\n                } else if (str==\"Integrated Checkpoint / Restart Feature (PDF)\") {\n                    return \"統合されたチェックポイント / リスタート機能(PDF)\";\n                } else if (str==\"PDF Optional Content\") {\n                    return \"PDF オプションコンテンツ\";\n                } else if (str==\"PDF Embedded Files\") {\n                    return \"PDF 埋め込みファイル\";\n                } else if (str==\"PDF Redactions\") {\n                    return \"PDFの隠蔽\";\n                } else if (str==\"PDF Annotations\") {\n                    return \"PDFの注釈\";\n                } else if (str==\"Full\") {\n                    return \"すべて\";\n                } else if (str==\"PDF Form Fields\") {\n                    return \"PDFフォームフィールド\";\n                } else if (str==\"Create, read, update\") {\n                    return \"作成、読み取り、更新\";\n                } else if (str==\"Limited, no creation\") {\n                    return \"一部対応、作成不可\";\n                } else if (str==\"PDF Page Labels\") {\n                    return \"PDFページラベル\";\n                } else if (str==\"Support Font Sub-Setting\") {\n                    return \"フォントのサブセット化をサポートする\";\n                } else if (str==\"Extract Tables\") {\n                    return \"ページからのテーブルの抽出\";\n                } else if (str==\"Supports CJK characters\") {\n                    return \"CJK 文字をサポートしています\";\n                } else if (str == \"Extract Text as Markdown (.md)\") {\n                    return \"テキストを Markdown (.md) として抽出\";\n                }\n\n\n\n\n            } else if (lang == \"ko\") {\n                if (str==\"Feature\") {\n                    return \"기능\";\n                } else if (str==\"Supports Multiple Document Formats\") {\n                    return \"다중 문서 형식 지원\";\n                } else if (str==\"Image\") {\n                    return \"이미지\";\n                } else if (str==\"Implementation\") {\n                    return \"구현\";\n                } else if (str==\"and\") {\n                    return \"및\";\n                } else if (str==\"Render Document Pages\") {\n                    return \"문서 페이지 렌더링\";\n                } else if (str==\"All document types\") {\n                    return \"모든 문서 유형\";\n                } else if (str==\"No rendering\") {\n                    return \"렌더링 없음\";\n                } else if (str==\"Extract Text\") {\n                    return \"텍스트 추출\";\n                } else if (str==\"Write Text to PDF Page\") {\n                    return \"PDF 페이지에 텍스트 쓰기\";\n                } else if (str==\"only\") {\n                    return \"만\";\n                } else if (str==\"Extract Vector Graphics\") {\n                    return \"벡터 그래픽 추출\";\n                } else if (str==\"Draw Vector Graphics (PDF)\") {\n                    return \"벡터 그래픽 그리기 (PDF)\";\n                } else if (str==\"Based on Existing, Mature Library\") {\n                    return \"기존의 성숙한 라이브러리 기반\";\n                } else if (str==\"Automatic Repair of Damaged PDFs\") {\n                    return \"손상된 PDF 자동 복구\";\n                } else if (str==\"Encrypted PDFs\") {\n                    return \"암호화된 PDF\";\n                } else if (str==\"Limited\") {\n                    return \"제한적\";\n                } else if (str==\"Linerarized PDFs\") {\n                    return \"선형화된 PDF\";\n                } else if (str==\"Incremental Updates\") {\n                    return \"증분 업데이트\";\n                } else if (str==\"Integrates with Jupyter and IPython Notebooks\") {\n                    return \"Jupyter 및 IPython Notebooks 통합\";\n                } else if (str==\"Joining / Merging PDF with other Document Types\") {\n                    return \"다른 문서 유형과 PDF 결합 / 병합\";\n                } else if (str==\"OCR API for Seamless Integration with Tesseract\") {\n                    return \"Tesseract와의 원활한 통합을 위한 OCR API\";\n                } else if (str==\"Integrated Checkpoint / Restart Feature (PDF)\") {\n                    return \"통합 체크포인트 / 재시작 기능 (PDF)\";\n                } else if (str==\"PDF Optional Content\") {\n                    return \"PDF 선택적 콘텐츠\";\n                } else if (str==\"PDF Embedded Files\") {\n                    return \"PDF 임베디드 파일\";\n                } else if (str==\"PDF Redactions\") {\n                    return \"PDF 편집\";\n                } else if (str==\"PDF Annotations\") {\n                    return \"PDF 주석\";\n                } else if (str==\"Full\") {\n                    return \"전체\";\n                } else if (str==\"PDF Form Fields\") {\n                    return \"PDF 양식 필드\";\n                } else if (str==\"Create, read, update\") {\n                    return \"생성, 읽기, 업데이트\";\n                } else if (str==\"Limited, no creation\") {\n                    return \"제한적, 생성 불가\";\n                } else if (str==\"PDF Page Labels\") {\n                    return \"PDF 페이지 레이블\";\n                } else if (str==\"Support Font Sub-Setting\") {\n                    return \"폰트 서브셋 지원\";\n                } else if (str==\"Extract Tables\") {\n                    return \"테이블 추출\";\n                } else if (str==\"Supports CJK characters\") {\n                    return \"CJK 문자 지원\";\n                } else if (str == \"Extract Text as Markdown (.md)\") {\n                    return \"텍스트를 Markdown (.md) 으로 추출\";\n                }\n            }\n\n            return str;\n        }\n\n        document.getElementById(\"transFM1\").innerHTML = getTranslation(\"Feature\");\n        document.getElementById(\"transFM2\").innerHTML = getTranslation(\"Supports Multiple Document Formats\");\n        document.getElementById(\"transFM3\").innerHTML = getTranslation(\"Image\");\n        document.getElementById(\"transFM4\").innerHTML = getTranslation(\"Implementation\");\n        document.getElementById(\"transFM5\").innerHTML = getTranslation(\"and\");\n        document.getElementById(\"transFM6\").innerHTML = getTranslation(\"and\");\n        document.getElementById(\"transFM7\").innerHTML = getTranslation(\"Render Document Pages\");\n        document.getElementById(\"transFM7x\").innerHTML = getTranslation(\"Write Text to PDF Page\");\n        document.getElementById(\"transFM8\").innerHTML = getTranslation(\"All document types\");\n        document.getElementById(\"transFM9\").innerHTML = getTranslation(\"No rendering\");\n        document.getElementById(\"transFM10\").innerHTML = getTranslation(\"No rendering\");\n        document.getElementById(\"transFM11\").innerHTML = getTranslation(\"No rendering\");\n        document.getElementById(\"transFM11x\").innerHTML = getTranslation(\"No rendering\");\n        document.getElementById(\"transFM12\").innerHTML = getTranslation(\"Extract Text\");\n        document.getElementById(\"transFM13\").innerHTML = getTranslation(\"All document types\");\n        document.getElementById(\"transFM13x\").innerHTML = getTranslation(\"All document types\");\n        document.getElementById(\"transFM13xx\").innerHTML = getTranslation(\"All document types\");\n        document.getElementById(\"transFM14\").innerHTML = getTranslation(\"only\");\n        document.getElementById(\"transFM14x\").innerHTML = getTranslation(\"only\");\n        document.getElementById(\"transFM14xx\").innerHTML = getTranslation(\"only\");\n        document.getElementById(\"transFM15\").innerHTML = getTranslation(\"Extract Vector Graphics\");\n        document.getElementById(\"transFM16\").innerHTML = getTranslation(\"All document types\");\n        document.getElementById(\"transFM16x\").innerHTML = getTranslation(\"Limited\");\n        document.getElementById(\"transFM17\").innerHTML = getTranslation(\"Draw Vector Graphics (PDF)\");\n        document.getElementById(\"transFM18\").innerHTML = getTranslation(\"Based on Existing, Mature Library\");\n        document.getElementById(\"transFM19\").innerHTML = getTranslation(\"Automatic Repair of Damaged PDFs\");\n        document.getElementById(\"transFM20\").innerHTML = getTranslation(\"Encrypted PDFs\");\n        document.getElementById(\"transFM21\").innerHTML = getTranslation(\"Limited\");\n        document.getElementById(\"transFM21x\").innerHTML = getTranslation(\"Limited\");\n        document.getElementById(\"transFM22\").innerHTML = getTranslation(\"Linerarized PDFs\");\n        document.getElementById(\"transFM23\").innerHTML = getTranslation(\"Incremental Updates\");\n        document.getElementById(\"transFM24\").innerHTML = getTranslation(\"Integrates with Jupyter and IPython Notebooks\");\n        document.getElementById(\"transFM25\").innerHTML = getTranslation(\"Joining / Merging PDF with other Document Types\");\n        document.getElementById(\"transFM26\").innerHTML = getTranslation(\"All document types\");\n        document.getElementById(\"transFM27\").innerHTML = getTranslation(\"only\");\n        document.getElementById(\"transFM28\").innerHTML = getTranslation(\"only\");\n        document.getElementById(\"transFM29\").innerHTML = getTranslation(\"only\");\n        document.getElementById(\"transFM29x\").innerHTML = getTranslation(\"only\");\n        document.getElementById(\"transFM30\").innerHTML = getTranslation(\"OCR API for Seamless Integration with Tesseract\");\n        document.getElementById(\"transFM31\").innerHTML = getTranslation(\"All document types\");\n        document.getElementById(\"transFM32\").innerHTML = getTranslation(\"Integrated Checkpoint / Restart Feature (PDF)\");\n        document.getElementById(\"transFM33\").innerHTML = getTranslation(\"PDF Optional Content\");\n        document.getElementById(\"transFM34\").innerHTML = getTranslation(\"PDF Embedded Files\");\n        document.getElementById(\"transFM35\").innerHTML = getTranslation(\"Limited\");\n        document.getElementById(\"transFM35x\").innerHTML = getTranslation(\"Limited\");\n        document.getElementById(\"transFM36\").innerHTML = getTranslation(\"PDF Redactions\");\n        document.getElementById(\"transFM37\").innerHTML = getTranslation(\"PDF Annotations\");\n        document.getElementById(\"transFM38\").innerHTML = getTranslation(\"Full\");\n        document.getElementById(\"transFM39\").innerHTML = getTranslation(\"Limited\");\n\n        document.getElementById(\"transFM40\").innerHTML = getTranslation(\"PDF Form Fields\");\n        document.getElementById(\"transFM41\").innerHTML = getTranslation(\"Create, read, update\");\n        document.getElementById(\"transFM42\").innerHTML = getTranslation(\"Limited, no creation\");\n\n        document.getElementById(\"transFM43\").innerHTML = getTranslation(\"PDF Page Labels\");\n        document.getElementById(\"transFM44\").innerHTML = getTranslation(\"Support Font Sub-Setting\");\n\n\n        document.getElementById(\"transFMSupportsCJK\").innerHTML = getTranslation(\"Supports CJK characters\");\n        document.getElementById(\"transFMSupportsMarkdown\").innerHTML = getTranslation(\"Extract Text as Markdown (.md)\");\n        document.getElementById(\"transFMExtractTables\").innerHTML = getTranslation(\"Extract Tables\");\n\n\n    </script>\n\n\n    <br/>\n\n    <div id=\"note\"></div>\n"
  },
  {
    "path": "docs/about-performance.rst",
    "content": ".. raw:: html\n\n    <style>\n\n        * {\n            -webkit-tap-highlight-color: rgba(0,0,0,0); /* make transparent link selection, adjust last value opacity 0 to 1.0 */\n            -moz-box-sizing: border-box; -webkit-box-sizing: border-box; box-sizing: border-box;\n        }\n\n        .graph {\n            font-family: arial;\n        }\n\n        .central-graph {\n            display: flex;\n        }\n\n        .about-graph-y-axis {\n            border-right: 1px solid #999;\n        }\n\n        .about-graph-y-axis-text .segment {\n            height: 50px;\n            width: 30px;\n            text-align: right;\n            font-size: 14px;\n        }\n\n        .about-graph-y-axis {\n            margin-left: 5px;\n            margin-top: 5px;\n        }\n\n        .about-graph-y-axis .segment {\n            height: 50px;\n            width: 10px;\n            border-top: 1px solid #999;\n            border-right: 1px solid #999;\n        }\n\n        .about-graph-area {\n            margin-top: 5px;\n            width: 80px;\n        }\n\n        .about-column {\n            display: flex;\n            margin: 0 4px 1px;\n            flex-direction: column-reverse;\n        }\n\n        .about-column .text {\n            font-size: 12px;\n            color: #666;\n            text-align: center;\n            padding: 6px;\n        }\n\n        .about-graph-area {\n            border-top: 1px solid #aaa;\n            border-left: 1px solid #aaa;\n            border-right: 1px solid #aaa;\n        }\n\n\n\n        /* scale on this is 1 pixel = 2 seconds */\n        /* 3.05 seconds = 2 pixels */\n        #copying-graph .about-graph-area.a {\n            height: 2px;\n            background: #5465FF;\n        }\n\n        /* 10.54 seconds = 5 pixels */\n        #copying-graph .about-graph-area.b {\n            height: 5px;\n            background: #788BFF;\n        }\n\n        /* 33.57 seconds = 16 pixels */\n        #copying-graph .about-graph-area.c {\n            height: 16px;\n            background: #9BB1FF;\n        }\n\n        /* 494.04 seconds = 247 pixels */\n        #copying-graph .about-graph-area.d {\n            height: 247px;\n            background: #E2FDFF;\n        }\n\n\n        /* scale on this is 1 pixel = 2 seconds */\n        /* 8.01 seconds = 4 pixels */\n        #text-graph .about-graph-area.a {\n            height: 4px;\n            background: #5465FF;\n        }\n\n        /* 27.42 seconds = 13 pixels */\n        #text-graph .about-graph-area.b {\n            height: 13px;\n            background: #788BFF;\n        }\n\n        /* 101.64 seconds = 50 pixels */\n        #text-graph .about-graph-area.c {\n            height: 50px;\n            background: #9BB1FF;\n        }\n\n        /* 227.27 seconds = 113 pixels */\n        #text-graph .about-graph-area.d {\n            height: 113px;\n            background: #BFD7FF;\n        }\n\n\n        /* scale on this is 1 pixel = 4 seconds */\n        /* 367.04 seconds = 92 pixels */\n        #rendering-graph .about-graph-area.a {\n            height: 92px;\n            background: #5465FF;\n        }\n\n        /* 646 seconds = 161 pixels */\n        #rendering-graph .about-graph-area.b {\n            height: 161px;\n            background: #788BFF;\n        }\n\n        /* 851.52 seconds = 212 pixels */\n        #rendering-graph .about-graph-area.c {\n            height: 212px;\n            background: #9BB1FF;\n        }\n\n\n        .about-graph-x-axis {\n            display: flex;\n            width: 480px;\n            height: 20px;\n            margin-left: 45px;\n            border-top: 1px solid #999;\n        }\n\n        .about-graph-x-axis .segment {\n            margin-top: 4px;\n            width: 88px;\n            text-align: center;\n        }\n\n        .about-graph-x-axis.speed {\n            margin-top: 4px;\n        }\n\n\n        /* Dark mode colors */\n        @media (prefers-color-scheme: dark) {\n\n\n\n        }\n\n    </style>\n\n    <br/>\n    <dl class=\"simple\">\n    <dt><strong id=\"transP1\">Copying</strong></dt><dd><p id=\"transP2\">This refers to opening a document and then saving it to a new file. This test measures the speed of reading a <cite>PDF</cite> and re-writing as a new <cite>PDF</cite>. This process is also at the core of functions like merging / joining multiple documents. The numbers below therefore apply to <cite>PDF</cite> joining and merging.</p>\n\n    <p id=\"transP3\">The results for all 7,031 pages are:</p>\n    </dd>\n    </dl>\n\n\n    <div class=\"graph\">\n\n        <div class=\"central-graph\" id=\"copying-graph\">\n\n            <div class=\"about-graph-y-axis-text\">\n                <div class=\"segment\">600</div>\n                <div class=\"segment\">500</div>\n                <div class=\"segment\">400</div>\n                <div class=\"segment\">300</div>\n                <div class=\"segment\">200</div>\n                <div class=\"segment\">100<p>&#9201;</p><div style=\"font-size:10px;margin-top:-20px;\" id=\"transP4\">seconds</div></div>\n            </div>\n\n            <div class=\"about-graph-y-axis\">\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n            </div>\n\n            <div class=\"about-column\"><div class=\"about-graph-area a\"></div><div class=\"text\">3.05</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area b\"></div><div class=\"text\">10.54</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area c\"></div><div class=\"text\">33.57</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area d\"></div><div class=\"text\">494.04</div></div>\n\n        </div>\n\n        <div class=\"about-graph-x-axis\">\n            <div class=\"segment\">PyMuPDF</div>\n            <div class=\"segment\">PDFrw</div>\n            <div class=\"segment\">PikePDF</div>\n            <div class=\"segment\">PyPDF2</div>\n        </div>\n\n        <div class=\"about-graph-x-axis speed\">\n            <div class=\"segment\"><i id=\"transP5\">fastest</i></div>\n            <div class=\"segment\">&#8592;</div>\n            <div class=\"segment\">&#8592;</div>\n            <div class=\"segment\"><i id=\"transP6\">slowest</i></div>\n        </div>\n\n    </div>\n\n    <br/>\n    <dl class=\"simple\">\n    <dt><strong id=\"transP7\">Text Extraction</strong></dt><dd><p id=\"transP8\">This refers to extracting simple, plain text from every page of the document and storing it in a text file.</p>\n\n    <p id=\"transP9\">The results for all 7,031 pages are:</p>\n    </dd>\n    </dl>\n\n    <div class=\"graph\">\n\n        <div class=\"central-graph\" id=\"text-graph\">\n\n            <div class=\"about-graph-y-axis-text\">\n\n                <div class=\"segment\">400</div>\n                <div class=\"segment\">300</div>\n                <div class=\"segment\">200</div>\n                <div class=\"segment\">100<p>&#9201;</p><div style=\"font-size:10px;margin-top:-20px;\" id=\"transP10\">seconds</div></div>\n            </div>\n\n            <div class=\"about-graph-y-axis\">\n\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n            </div>\n\n            <div class=\"about-column\"><div class=\"about-graph-area a\"></div><div class=\"text\">8.01</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area b\"></div><div class=\"text\">27.42</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area c\"></div><div class=\"text\">101.64</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area d\"></div><div class=\"text\">227.27</div></div>\n\n        </div>\n\n        <div class=\"about-graph-x-axis\">\n            <div class=\"segment\">PyMuPDF</div>\n            <div class=\"segment\">XPDF</div>\n            <div class=\"segment\">PyPDF2</div>\n            <div class=\"segment\">PDFMiner</div>\n        </div>\n\n        <div class=\"about-graph-x-axis speed\">\n            <div class=\"segment\"><i id=\"transP11\">fastest</i></div>\n            <div class=\"segment\">&#8592;</div>\n            <div class=\"segment\">&#8592;</div>\n            <div class=\"segment\"><i id=\"transP12\">slowest</i></div>\n        </div>\n\n    </div>\n\n\n    <br/>\n\n    <dl class=\"simple\">\n    <dt><strong id=\"transP13\">Rendering</strong></dt><dd><p id=\"transP14\">This refers to making an image (like PNG) from every page of a document at a given DPI resolution. This feature is the basis for displaying a document in a GUI window.</p>\n\n    <p id=\"transP15\">The results for all 7,031 pages are:</p>\n\n    </dd>\n    </dl>\n\n\n    <div class=\"graph\">\n\n        <div class=\"central-graph\" id=\"rendering-graph\">\n\n            <div class=\"about-graph-y-axis-text\">\n                <div class=\"segment\">1000</div>\n                <div class=\"segment\">800</div>\n                <div class=\"segment\">600</div>\n                <div class=\"segment\">400</div>\n                <div class=\"segment\">200<p>&#9201;</p><div style=\"font-size:10px;margin-top:-20px;\" id=\"transP16\">seconds</div></div>\n            </div>\n\n            <div class=\"about-graph-y-axis\">\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n                <div class=\"segment\"></div>\n            </div>\n\n            <div class=\"about-column\"><div class=\"about-graph-area a\"></div><div class=\"text\">367.04</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area b\"></div><div class=\"text\">646</div></div>\n            <div class=\"about-column\"><div class=\"about-graph-area c\"></div><div class=\"text\">851.52</div></div>\n\n        </div>\n\n        <div class=\"about-graph-x-axis\">\n            <div class=\"segment\">PyMuPDF</div>\n            <div class=\"segment\">XPDF</div>\n            <div class=\"segment\">PDF2JPG</div>\n        </div>\n\n        <div class=\"about-graph-x-axis speed\">\n            <div class=\"segment\"><i id=\"transP17\">fastest</i></div>\n            <div class=\"segment\">&#8592;</div>\n            <div class=\"segment\"><i id=\"transP18\">slowest</i></div>\n        </div>\n\n    </div>\n\n\n    <br/>\n\n    <script>\n\n        let langB = document.getElementsByTagName('html')[0].getAttribute('lang');\n\n        function getTranslationB(str) {\n            if (langB == \"ja\") {\n                if (str==\"Copying\") {\n                    return \"コピー\";\n                } else if (str == \"This refers to opening a document and then saving it to a new file. This test measures the speed of reading a <cite>PDF</cite> and re-writing as a new <cite>PDF</cite>. This process is also at the core of functions like merging / joining multiple documents. The numbers below therefore apply to <cite>PDF</cite> joining and merging.\") {\n                    return \"以下は、ドキュメントを開いてから新しいファイルとして保存することを指します。このテストは、PDFを読み込み、新しいPDFとして再書き込む速度を測定します。このプロセスは、複数のドキュメントを結合するなどの機能の中核でもあります。したがって、以下の数字はPDFの結合とマージにも適用されます。\";\n                } else if (str == \"The results for all 7,031 pages are:\") {\n                    return \"全7,031ページの結果は次のとおりです：\";\n                } else if (str == \"seconds\") {\n                    return \"秒\";\n                } else if (str == \"fastest\") {\n                    return \"最速\";\n                } else if (str == \"slowest\") {\n                    return \"最遅\";\n                } else if (str == \"Text Extraction\") {\n                    return \"テキスト抽出\";\n                } else if (str == \"This refers to extracting simple, plain text from every page of the document and storing it in a text file.\") {\n                    return \"以下は、ドキュメントの各ページから簡単なプレーンテキストを抽出し、テキストファイルに保存することを指します。\";\n                } else if (str == \"Rendering\") {\n                    return \"レンダリング\";\n                } else if (str == \"This refers to making an image (like PNG) from every page of a document at a given DPI resolution. This feature is the basis for displaying a document in a GUI window.\") {\n                    return \"この場合、\\\"レンダリング\\\" は、指定されたDPI解像度でドキュメントの各ページから画像（PNGなど）を作成することを指します。この機能は、GUIウィンドウでドキュメントを表示するための基本となります。\";\n                }\n\n\n\n            } else if (langB == \"ko\") {\n                if (str==\"Copying\") {\n                    return \"복사\";\n                } else if (str == \"This refers to opening a document and then saving it to a new file. This test measures the speed of reading a <cite>PDF</cite> and re-writing as a new <cite>PDF</cite>. This process is also at the core of functions like merging / joining multiple documents. The numbers below therefore apply to <cite>PDF</cite> joining and merging.\") {\n                    return \"이것은 문서를 열고 새 파일로 저장하는 것을 의미합니다. 이 테스트는 <cite>PDF</cite> 를 읽고 새 <cite>PDF</cite> 로 다시 쓰는 속도를 측정합니다. 이 프로세스는 여러 문서를 병합 / 결합하는 기능의 핵심이기도 합니다. 따라서 아래 숫자는 <cite>PDF</cite> 결합 및 병합에도 적용됩니다.\";\n                } else if (str == \"The results for all 7,031 pages are:\") {\n                    return \"모든 7,031 페이지에 대한 결과:\";\n                } else if (str == \"seconds\") {\n                    return \"초\";\n                } else if (str == \"fastest\") {\n                    return \"가장 빠름\";\n                } else if (str == \"slowest\") {\n                    return \"가장 느림\";\n                } else if (str == \"Text Extraction\") {\n                    return \"텍스트 추출\";\n                } else if (str == \"This refers to extracting simple, plain text from every page of the document and storing it in a text file.\") {\n                    return \"이것은 문서의 모든 페이지에서 간단한 일반 텍스트를 추출하여 텍스트 파일에 저장하는 것을 의미합니다.\";\n                } else if (str == \"Rendering\") {\n                    return \"렌더링\";\n                } else if (str == \"This refers to making an image (like PNG) from every page of a document at a given DPI resolution. This feature is the basis for displaying a document in a GUI window.\") {\n                    return \"이것은 주어진 DPI 해상도로 문서의 모든 페이지에서 이미지 (예: PNG)를 만드는 것을 의미합니다. 이 기능은 GUI 창에서 문서를 표시하는 기반입니다.\";\n                }\n            }\n\n            return str;\n\n        }\n\n        document.getElementById(\"transP1\").innerHTML = getTranslationB(\"Copying\");\n        document.getElementById(\"transP2\").innerHTML = getTranslationB(\"This refers to opening a document and then saving it to a new file. This test measures the speed of reading a <cite>PDF</cite> and re-writing as a new <cite>PDF</cite>. This process is also at the core of functions like merging / joining multiple documents. The numbers below therefore apply to <cite>PDF</cite> joining and merging.\");\n\n        document.getElementById(\"transP3\").innerHTML = getTranslationB(\"The results for all 7,031 pages are:\");\n        document.getElementById(\"transP4\").innerHTML = getTranslationB(\"seconds\");\n        document.getElementById(\"transP5\").innerHTML = getTranslationB(\"fastest\");\n        document.getElementById(\"transP6\").innerHTML = getTranslationB(\"slowest\");\n        document.getElementById(\"transP7\").innerHTML = getTranslationB(\"Text Extraction\");\n        document.getElementById(\"transP8\").innerHTML = getTranslationB(\"This refers to extracting simple, plain text from every page of the document and storing it in a text file.\");\n        document.getElementById(\"transP9\").innerHTML = getTranslationB(\"The results for all 7,031 pages are:\");\n        document.getElementById(\"transP10\").innerHTML = getTranslationB(\"seconds\");\n        document.getElementById(\"transP11\").innerHTML = getTranslationB(\"fastest\");\n        document.getElementById(\"transP12\").innerHTML = getTranslationB(\"slowest\");\n        document.getElementById(\"transP13\").innerHTML = getTranslationB(\"Rendering\");\n        document.getElementById(\"transP14\").innerHTML = getTranslationB(\"This refers to making an image (like PNG) from every page of a document at a given DPI resolution. This feature is the basis for displaying a document in a GUI window.\");\n        document.getElementById(\"transP15\").innerHTML = getTranslationB(\"The results for all 7,031 pages are:\");\n        document.getElementById(\"transP16\").innerHTML = getTranslationB(\"seconds\");\n        document.getElementById(\"transP17\").innerHTML = getTranslationB(\"fastest\");\n        document.getElementById(\"transP18\").innerHTML = getTranslationB(\"slowest\");\n\n\n\n    </script>\n\n\n\n\n\n"
  },
  {
    "path": "docs/about.rst",
    "content": ".. include:: header.rst\n\n.. _About:\n\n\n\n.. _About_Features:\n\nFeatures Comparison\n-----------------------------------------------\n\n\n.. _About_Feature_Matrix:\n\nFeature Matrix\n~~~~~~~~~~~~~~~~~~~\n\nThe following table illustrates how |PyMuPDF| compares with other typical solutions.\n\n\n.. include:: about-feature-matrix.rst\n\n\n----\n\n\n\n\n\n.. note::\n\n    .. image:: images/icons/icon-docx.svg\n        :width: 40\n        :height: 40\n        :alt: DOCX icon\n\n    .. image:: images/icons/icon-xlsx.svg\n            :width: 40\n            :height: 40\n            :alt: XLSX icon\n\n    .. image:: images/icons/icon-pptx.svg\n            :width: 40\n            :height: 40\n            :alt: PPTX icon \n\n    .. image:: images/icons/icon-hangul.svg\n            :width: 40\n            :height: 40\n            :alt: HWPX icon\n\n    A note about **Office** document types (DOCX, XLXS, PPTX) and **Hangul** documents (HWPX). These documents can be loaded into |PyMuPDF| and you will receive a :ref:`Document <Document>` object.\n\n    There are some caveats:\n\n    - we convert the input to **HTML** to layout the content.\n    - because of this the original page separation has gone.\n\n    When saving out the result any faithful representation of the original layout cannot be expected.\n\n    Therefore input files are mostly in a form that's useful for text extraction.\n\n\n----\n\n.. _About_PyMuPDF_Product_Suite:\n\nPyMuPDF Product Suite\n-----------------------------------------------\n\n|PyMuPDF| is the standard version of the library, however there are a family of additional products each with different features and functionality. \n\n**Additional products** in the |PyMuPDF| product suite are:\n   \n- |PyMuPDF Pro| adds support for Office document formats.\n- |PyMuPDF4LLM| is optimized for large language model (LLM) applications, providing enhanced text extraction and processing capabilities. \n It focuses on layout analysis and semantic understanding, ideal for document conversion and formatting tasks with enhanced results.\n\n.. note::\n    All of the products above depend on the same core product - |PyMuPDF| and therefore have full access to all of its features.\n    These additional products can be seen as optional extras to the enhance the core |PyMuPDF| library.\n\n\n.. _About_PyMuPDF_Products_Comparison:\n\nPyMuPDF Products Comparison\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe following table illustrates what features the products offer:\n\n.. list-table:: PyMuPDF Products Comparison\n   :widths: 10 30 30 30 \n   :header-rows: 1\n\n   * - \n     - PyMuPDF\n     - PyMuPDF Pro\n     - PyMuPDF4LLM\n   * - **Input Documents**\n     - `PDF`, `XPS`, `EPUB`, `CBZ`, `MOBI`, `FB2`, `SVG`, `TXT`, Images (*standard document types*)\n     - *as PyMuPDF* and:\n       `DOC`/`DOCX`, `XLS`/`XLSX`, `PPT`/`PPTX`, `HWP`/`HWPX`\n     - *as PyMuPDF*\n   * - **Output Documents**\n     - Can convert any input document to `PDF`, `SVG` or Image\n     - *as PyMuPDF*\n     - *as PyMuPDF* and: \n       Markdown (`MD`), `JSON` or `TXT`\n   * - **Page Analysis**\n     - Basic page analysis to return document structure\n     - *as PyMuPDF*\n     - Advanced Page Analysis with trained data for enhanced results\n   * - **Data extraction**\n     - Basic data extraction with structured layout information and bounding box data\n     - *as PyMuPDF*\n     - Advanced data extraction including layout analysis with semantic understanding and enhanced bounding box data\n   * - **Table extraction**\n     - Basic table extraction as part of text extraction\n     - *as PyMuPDF*\n     - Advanced table extraction with cell structure, including support for merged cells and complex layouts\n   * - **Image extraction**\n     - Basic image extraction\n     - *as PyMuPDF*\n     - Advanced detection and rendering of image areas on page saving them to disk or embedding in MD output\n   * - **Vector extraction**\n     - Vector extraction and clustering\n     - *as PyMuPDF*\n     - Superior detection of \"picture\" areas \n   * - **Popular RAG Integrations** \n     - Langchain, LlamaIndex\n     - *as PyMuPDF*\n     - *as PyMuPDF* and with some additional help methods for RAG workflows\n   * - **OCR**\n     - On-demand invocation of built-in Tesseract for text detection on pages or images\n     - *as PyMuPDF*\n     - Automatic OCR based on page content analysis. OCR adapators for popular OCR engines available\n\n----\n\n.. _About_Performance:\n\nPerformance\n-----------------------------------------------\n\n\n\nTo benchmark |PyMuPDF| performance against a range of tasks a test suite with a fixed set of :ref:`8 PDFs with a total of 7,031 pages<Appendix4_Files_Used>` containing text & images is used to obtain performance timings.\n\n\nHere are current results, grouped by task:\n\n\n\n.. include:: about-performance.rst\n\n\n.. note::\n\n   For more detail regarding the methodology for these performance timings see: :ref:`Performance Comparison Methodology<Appendix4>`.\n\n\n\n\n.. _About_License:\n\nLicense and Copyright\n----------------------\n\n\n\n|PyMuPDF| and |MuPDF| are now available under both, open-source |AGPL| and commercial license agreements. Please read the full text of the |AGPL| license agreement, available in the distribution material (file COPYING) and `on the GNU license page <https://www.gnu.org/licenses/agpl-3.0.html>`_, to ensure that your use case complies with the guidelines of the license. If you determine you cannot meet the requirements of the |AGPL|, please contact `Artifex <https://artifex.com/contact/pymupdf-inquiry.php?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=inline-link>`_ for more information regarding a commercial license.\n\n.. raw:: html\n\n   <button id=\"licenseButton\" class=\"cta orange\" onclick=\"window.location='https://artifex.com/licensing?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=cta-button'\">Find out more about Licensing</button>\n   <p></p>\n\n   <script>\n      let langC = document.getElementsByTagName('html')[0].getAttribute('lang');\n\n      if (langC==\"ja\") {\n         document.getElementById(\"licenseButton\").innerHTML = \"さらに詳しく\";\n      }\n\n   </script>\n\n\n\n:title:`Artifex` is the exclusive commercial licensing agent for :title:`MuPDF`.\n\n:title:`Artifex`, the :title:`Artifex` logo, :title:`MuPDF`, and the :title:`MuPDF` logo are registered trademarks of :title:`Artifex Software Inc.`\n\n\n.. include:: version.rst\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/algebra.rst",
    "content": ".. include:: header.rst\n\n.. _Algebra:\n\nOperator Algebra for Geometry Objects\n======================================\n\n.. highlight:: python\n\nInstances of classes :ref:`Point`, :ref:`IRect`, :ref:`Rect`, :ref:`Quad` and :ref:`Matrix` are collectively also called \"geometry\" objects.\n\nThey all are special cases of Python sequences, see :ref:`SequenceTypes` for more background.\n\nWe have defined operators for these classes that allow dealing with them (almost) like ordinary numbers in terms of addition, subtraction, multiplication, division, and some others.\n\nThis chapter is a synopsis of what is possible.\n\nGeneral Remarks\n-----------------\n1. Operators can be either **binary** (i.e. involving two objects) or **unary**.\n\n2. The resulting type of **binary** operations is either a **new object of the left operand's class,** a bool or (for dot products) a float.\n\n3. The result of **unary** operations is either a **new object** of the same class, a bool or a float.\n\n4. The binary operators `+, -, *, /` are defined for all classes. They *roughly* do what you would expect -- **except, that the second operand ...**\n\n    - may always be a number which then performs the operation on every component of the first one,\n    - may always be a numeric sequence of the same length (2, 4 or 6) -- we call such sequences :data:`point_like`, :data:`rect_like`, :data:`quad_like` or :data:`matrix_like`, respectively.\n\n5. Rectangles support **additional binary** operations: **intersection** (operator `\"&\"`), **union** (operator `\"|\"`) and **containment** checking.\n\n6. Binary operators fully support in-place operations. So if \"°\" is a binary operator then the expression `a °= b` is always valid and the same as `a = a ° b`. Therefore, be careful and do **not** do `p1 *= p2` for two points, because thereafter \"p1\" is a **float**.\n\n\nUnary Operations\n------------------\n\n=========== ===================================================================\nOper.       Result\n=========== ===================================================================\n bool(OBJ)  is false exactly if all components of OBJ are zero\n abs(OBJ)   the rectangle area -- equal to norm(OBJ) for the other types\n norm(OBJ)  square root of the component squares (Euclidean norm)\n +OBJ       new copy of OBJ\n -OBJ       new copy of OBJ with negated components\n ~m         inverse of matrix \"m\", or the null matrix if not invertible\n=========== ===================================================================\n\n\nBinary Operations\n------------------\nThese are expressions like `a ° b` where \"°\" is any of the operators `+, -, *, /`. Also binary operations are expressions of the form `a == b` and `b in a`.\n\nIf \"b\" is a number, then the respective operation is executed for each component of \"a\". Otherwise, if \"b\" is **not a number,** then the following happens:\n\n\n========= ===========================================================================\nOper.     Result\n========= ===========================================================================\na+b, a-b  component-wise execution, \"b\" must be \"a-like\".\na*m, a/m  \"a\" can be a point, rectangle or matrix and \"m\" is a\n          :data:`matrix_like`. *\"a/m\"* is treated as *\"a*~m\"* (see note below\n          for non-invertible matrices). If \"a\" is a **point** or a **rectangle**,\n          then *\"a.transform(m)\"* is executed. If \"a\" is a matrix, then\n          matrix concatenation takes place.\na*b       returns the **vector dot product** for a point \"a\" and point-like \"b\".\na&b       **intersection rectangle:** \"a\" must be a rectangle and\n          \"b\" :data:`rect_like`. Delivers the **largest rectangle**\n          contained in both operands.\na|b       **union rectangle:** \"a\" must be a rectangle, and \"b\" may be\n          :data:`point_like` or :data:`rect_like`.\n          Delivers the **smallest rectangle** containing both operands.\nb in a    if \"b\" is a number, then `b in tuple(a)` is returned.\n          If \"b\" is :data:`point_like`, :data:`rect_like` or :data:`quad_like`,\n          then \"a\" must be a rectangle, and `a.contains(b)` is returned.\na == b    ``True`` if *bool(a-b)* is ``False`` (\"b\" may be \"a-like\").\n========= ===========================================================================\n\n\n.. note:: Please note an important difference to usual arithmetic:\n\n        Matrix multiplication is **not commutative**, i.e. in general we have `m*n != n*m` for two matrices. Also, there are non-zero matrices which have no inverse, for example `m = Matrix(1, 0, 1, 0, 1, 0)`. If you try to divide by any of these, you will receive a `ZeroDivisionError` exception using operator *\"/\"*, e.g. for the expression `pymupdf.Identity / m`. But if you formulate `pymupdf.Identity * ~m`, the result will be `pymupdf.Matrix()` (the null matrix).\n\n        Admittedly, this represents an inconsistency, and we are considering to remove it. For the time being, you can choose to avoid an exception and check whether ~m is the null matrix, or accept a potential *ZeroDivisionError* by using `pymupdf.Identity / m`.\n\n.. note::\n\n  * With these conventions, all the usual algebra rules apply. For example, arbitrarily using brackets **(among objects of the same class!)** is possible: if r1, r2 are rectangles and m1, m2 are matrices, you can do this `(r1 + r2) * m1 * m2`.\n  * For all objects of the same class, `a + b + c == (a + b) + c == a + (b + c)` is true.\n  * For matrices in addition the following is true: `(m1 + m2) * m3 == m1 * m3 + m2 * m3` (distributivity property).\n  * **But the sequence of applying matrices is important:** If r is a rectangle and m1, m2 are matrices, then -- **caution!:**\n     - `r * m1 * m2 == (r * m1) * m2 != r * (m1 * m2)`\n\nSome Examples\n--------------\n\nManipulation with numbers\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nFor the usual arithmetic operations, numbers are always allowed as second operand. In addition, you can formulate `\"x in OBJ\"`, where x is a number. It is implemented as `\"x in tuple(OBJ)\"`::\n\n  >>> pymupdf.Rect(1, 2, 3, 4) + 5\n  pymupdf.Rect(6.0, 7.0, 8.0, 9.0)\n  >>> 3 in pymupdf.Rect(1, 2, 3, 4)\n  True\n  >>> \n\nThe following will create the upper left quarter of a document page rectangle::\n\n  >>> page.rect\n  Rect(0.0, 0.0, 595.0, 842.0)\n  >>> page.rect / 2\n  Rect(0.0, 0.0, 297.5, 421.0)\n  >>> \n\nThe following will deliver the **middle point of a line** that connects two points **p1** and **p2**::\n\n  >>> p1 = pymupdf.Point(1, 2)\n  >>> p2 = pymupdf.Point(4711, 3141)\n  >>> mp = (p1 + p2) / 2\n  >>> mp\n  Point(2356.0, 1571.5)\n  >>> \n\nCompute the **vector dot product** of two points. You can compute the **cosine of angles** and check orthogonality.\n\n  >>> p1 = pymupdf.Point(1, 0)\n  >>> p2 = pymupdf.Point(1, 1)\n  >>> dot = p1 * p2\n  >>> dot\n  1.0\n\n  >>> # compute the cosine of the angle between p1 and p2:\n  >>> cosine = dot / (abs(p1) * abs(p2))\n  >>> cosine  # cosine of 45 degrees\n  0.7071067811865475\n\n  >>> math.cos(mat.radians(45))  # verify:\n  0.7071067811865476\n\n  >>> # check orhogonality\n  >>> p3 = pymupdf.Point(0, 1)\n  >>> # p1 and p3 are orthogonal so, as expected:\n  >>> p1 * p3  \n  0.0\n\n\nManipulation with \"like\" Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe second operand of a binary operation can always be \"like\" the left operand. \"Like\" in this context means \"a sequence of numbers of the same length\". With the above examples::\n\n  >>> p1 + p2\n  Point(4712.0, 3143.0)\n  >>> p1 + (4711, 3141)\n  Point(4712.0, 3143.0)\n  >>> p1 += (4711, 3141)\n  >>> p1\n  Point(4712.0, 3143.0)\n  >>> \n\nTo shift a rectangle for 5 pixels to the right, do this::\n\n  >>> pymupdf.Rect(100, 100, 200, 200) + (5, 0, 5, 0)  # add 5 to the x coordinates\n  Rect(105.0, 100.0, 205.0, 200.0)\n  >>>\n\nPoints, rectangles and matrices can be *transformed* with matrices. In PyMuPDF, we treat this like a **\"multiplication\"** (or resp. **\"division\"**), where the second operand may be \"like\" a matrix. Division in this context means \"multiplication with the inverted matrix\"::\n\n  >>> m = pymupdf.Matrix(1, 2, 3, 4, 5, 6)\n  >>> n = pymupdf.Matrix(6, 5, 4, 3, 2, 1)\n  >>> p = pymupdf.Point(1, 2)\n  >>> p * m\n  Point(12.0, 16.0)\n  >>> p * (1, 2, 3, 4, 5, 6)\n  Point(12.0, 16.0)\n  >>> p / m\n  Point(2.0, -2.0)\n  >>> p / (1, 2, 3, 4, 5, 6)\n  Point(2.0, -2.0)\n  >>>\n  >>> m * n  # matrix multiplication\n  Matrix(14.0, 11.0, 34.0, 27.0, 56.0, 44.0)\n  >>> m / n  # matrix division\n  Matrix(2.5, -3.5, 3.5, -4.5, 5.5, -7.5)\n  >>>\n  >>> m / m  # result is equal to the Identity matrix\n  Matrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)\n  >>>\n  >>> # look at this non-invertible matrix:\n  >>> m = pymupdf.Matrix(1, 0, 1, 0, 1, 0)\n  >>> ~m\n  Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)\n  >>> # we try dividing by it in two ways:\n  >>> p = pymupdf.Point(1, 2)\n  >>> p * ~m  # this delivers point (0, 0):\n  Point(0.0, 0.0)\n  >>> p / m  # but this is an exception:\n  Traceback (most recent call last):\n    File \"<pyshell#6>\", line 1, in <module>\n      p / m\n    File \"... /site-packages/fitz/pymupdf.py\", line 869, in __truediv__\n      raise ZeroDivisionError(\"matrix not invertible\")\n  ZeroDivisionError: matrix not invertible\n  >>>\n\n\nAs a specialty, rectangles support additional binary operations:\n\n* **intersection** -- the common area of rectangle-likes, operator *\"&\"*\n* **inclusion** -- enlarge to include a point-like or rect-like, operator *\"|\"*\n* **containment** check -- whether a point-like or rect-like is inside\n\nHere is an example for creating the smallest rectangle enclosing given points::\n\n  >>> # first define some point-likes\n  >>> points = []\n  >>> for i in range(10):\n          for j in range(10):\n              points.append((i, j))\n  >>>\n  >>> # now create a rectangle containing all these 100 points\n  >>> # start with an empty rectangle\n  >>> r = pymupdf.Rect(points[0], points[0])\n  >>> for p in points[1:]:  # and include remaining points one by one\n          r |= p\n  >>> r  # here is the to be expected result:\n  Rect(0.0, 0.0, 9.0, 9.0)\n  >>> (4, 5) in r  # this point-like lies inside the rectangle\n  True\n  >>> # and this rect-like is also inside\n  >>> (4, 4, 5, 5) in r\n  True\n  >>>\n\n.. include:: footer.rst"
  },
  {
    "path": "docs/annot.rst",
    "content": ".. include:: header.rst\n\n.. _Annot:\n\n================\nAnnot\n================\n\n|pdf_only_class|\n\nQuote from the :ref:`AdobeManual`:\n\n   *\"An annotation associates an object such as a note, sound, or movie with a location on a page of a PDF document, or provides a way to interact with the user by means of the mouse and keyboard.\"*\n\nThere is a parent-child relationship between an annotation and its page. If the page object becomes unusable (closed document, any document structure change, etc.), then so does every of its existing annotation objects -- an exception is raised saying that the object is \"orphaned\", whenever an annotation property or method is accessed.\n\n================================== ==============================================================\n**Attribute**                      **Short Description**\n================================== ==============================================================\n:meth:`Annot.delete_responses`     delete all responding annotations\n:meth:`Annot.get_file`             get attached file content\n:meth:`Annot.get_oc`               get :data:`xref` of an :data:`OCG` / :data:`OCMD`\n:meth:`Annot.get_pixmap`           image of the annotation as a pixmap\n:meth:`Annot.get_sound`            get the sound of an audio annotation\n:meth:`Annot.get_text`             extract annotation text\n:meth:`Annot.get_textbox`          extract annotation text\n:meth:`Annot.get_textpage`         create a TextPage for the annotation\n:meth:`Annot.set_border`           set annotation's border properties\n:meth:`Annot.set_blendmode`        set annotation's blend mode\n:meth:`Annot.set_colors`           set annotation's colors\n:meth:`Annot.set_flags`            set annotation's flags field\n:meth:`Annot.set_irt_xref`         define the annotation to being \"In Response To\"\n:meth:`Annot.set_name`             set annotation's name field\n:meth:`Annot.set_oc`               set :data:`xref` to an :data:`OCG` / :data:`OCMD`\n:meth:`Annot.set_opacity`          change transparency\n:meth:`Annot.set_open`             open / close annotation or its Popup\n:meth:`Annot.set_popup`            create a Popup for the annotation\n:meth:`Annot.set_rect`             change annotation rectangle\n:meth:`Annot.set_rotation`         change rotation\n:meth:`Annot.update_file`          update attached file content\n:meth:`Annot.update`               apply accumulated annot changes\n:attr:`Annot.blendmode`            annotation BlendMode\n:attr:`Annot.border`               border details\n:attr:`Annot.colors`               border / background and fill colors\n:attr:`Annot.file_info`            get attached file information\n:attr:`Annot.flags`                annotation flags\n:attr:`Annot.has_popup`            whether annotation has a Popup\n:attr:`Annot.irt_xref`             annotation to which this one responds\n:attr:`Annot.info`                 various information\n:attr:`Annot.is_open`              whether annotation or its Popup is open\n:attr:`Annot.line_ends`            start / end appearance of line-type annotations\n:attr:`Annot.next`                 link to the next annotation\n:attr:`Annot.opacity`              the annot's transparency\n:attr:`Annot.parent`               page object of the annotation\n:attr:`Annot.popup_rect`           rectangle of the annotation's Popup\n:attr:`Annot.popup_xref`           the PDF :data:`xref` number of the annotation's Popup\n:attr:`Annot.rect`                 rectangle containing the annotation\n:attr:`Annot.type`                 type of the annotation\n:attr:`Annot.vertices`             point coordinates of Polygons, PolyLines, etc.\n:attr:`Annot.xref`                 the PDF :data:`xref` number\n================================== ==============================================================\n\n**Class API**\n\n.. class:: Annot\n\n   .. index::\n      pair: matrix; Annot.get_pixmap\n      pair: colorspace; Annot.get_pixmap\n      pair: alpha; Annot.get_pixmap\n      pair: dpi; Annot.get_pixmap\n\n   .. method:: get_pixmap(matrix=pymupdf.Identity, dpi=None, colorspace=pymupdf.csRGB, alpha=False)\n\n      * Changed in v1.19.2: added support of dpi parameter.\n\n      Creates a pixmap from the annotation as it appears on the page in untransformed coordinates. The pixmap's :ref:`IRect` equals *Annot.rect.irect* (see below). **All parameters are keyword only.**\n\n      :arg matrix_like matrix: a matrix to be used for image creation. Default is :ref:`Identity`.\n\n      :arg int dpi: (new in v1.19.2) desired resolution in dots per inch. If not `None`, the matrix parameter is ignored.\n\n      :arg colorspace: a colorspace to be used for image creation. Default is ``pymupdf.csRGB``.\n      :type colorspace: :ref:`Colorspace`\n\n      :arg bool alpha: whether to include transparency information. Default is ``False``.\n\n      :rtype: :ref:`Pixmap`\n\n      .. note::\n         \n         * If the annotation has just been created or modified, you should :meth:`Document.reload_page` the page first via `page = doc.reload_page(page)`.\n\n         * The pixmap will have *\"premultiplied\"* pixels if `alpha=True`. To learn about some background, e.g. look for \"Premultiplied alpha\" `in this online glossary <https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\n\n\n   .. index::\n      pair: blocks; Annot.get_text\n      pair: dict; Annot.get_text\n      pair: clip; Annot.get_text\n      pair: flags; Annot.get_text\n      pair: html; Annot.get_text\n      pair: json; Annot.get_text\n      pair: rawdict; Annot.get_text\n      pair: text; Annot.get_text\n      pair: words; Annot.get_text\n      pair: xhtml; Annot.get_text\n      pair: xml; Annot.get_text\n\n   .. method:: get_text(opt, clip=None, flags=None)\n\n      * New in 1.18.0\n\n      Retrieves the content of the annotation in a variety of formats -- much like the same method for :ref:`Page`.. This currently only delivers relevant data for annotation types 'FreeText' and 'Stamp'. Other types return an empty string (or equivalent objects).\n\n      :arg str opt: (positional only) the desired format - one of the following values. Please note that this method works exactly like the same-named method of :ref:`Page`.\n\n         * \"text\" -- :meth:`TextPage.extractTEXT`, default\n         * \"blocks\" -- :meth:`TextPage.extractBLOCKS`\n         * \"words\" -- :meth:`TextPage.extractWORDS`\n         * \"html\" -- :meth:`TextPage.extractHTML`\n         * \"xhtml\" -- :meth:`TextPage.extractXHTML`\n         * \"xml\" -- :meth:`TextPage.extractXML`\n         * \"dict\" -- :meth:`TextPage.extractDICT`\n         * \"json\" -- :meth:`TextPage.extractJSON`\n         * \"rawdict\" -- :meth:`TextPage.extractRAWDICT`\n\n      :arg rect-like clip: (keyword only) restrict the extraction to this area. Should hardly ever be required, defaults to :attr:`Annot.rect`.\n      :arg int flags: (keyword only) control the amount of data returned. Defaults to simple text extraction.\n\n   .. method:: get_textbox(rect)\n\n      * New in 1.18.0\n\n      Return the annotation text. Mostly (except line breaks) equal to :meth:`Annot.get_text` with the \"text\" option.\n\n      :arg rect-like rect: the area to consider, defaults to :attr:`Annot.rect`.\n\n\n   .. method:: get_textpage(clip=None, flags=3)\n\n      Create a :ref:`TextPage` for the annotation.\n\n      :arg int flags: indicator bits controlling the content available for subsequent text extractions and searches -- see the parameter of :meth:`Annot.get_text`.\n\n      :arg rect-like clip: restrict extracted text to this area.\n\n      :returns: :ref:`TextPage`\n\n      |history_begin|\n\n      * v1.25.5: fixed `clip` arg.\n\n      |history_end|\n\n   .. method:: set_info(info=None, content=None, title=None, creationDate=None, modDate=None, subject=None)\n\n      * Changed in version 1.16.10\n\n      Changes annotation properties. These include dates, contents, subject and author (title). Changes for *name* and *id* will be ignored. The update happens selectively: To leave a property unchanged, set it to ``None``. To delete existing data, use an empty string.\n\n      :arg dict info: a dictionary compatible with the *info* property (see below). All entries must be strings. If this argument is not a dictionary, the other arguments are used instead -- else they are ignored.\n      :arg str content: *(new in v1.16.10)* see description in :attr:`info`.\n      :arg str title: *(new in v1.16.10)* see description in :attr:`info`.\n      :arg str creationDate: *(new in v1.16.10)* date of annot creation. If given, should be in PDF datetime format.\n      :arg str modDate: *(new in v1.16.10)* date of last modification. If given, should be in PDF datetime format.\n      :arg str subject: *(new in v1.16.10)* see description in :attr:`info`.\n\n   .. method:: set_line_ends(start, end)\n\n      Sets an annotation's line ending styles. Each of these annotation types is defined by a list of points which are connected by lines. The symbol identified by *start* is attached to the first point, and *end* to the last point of this list. For unsupported annotation types, a no-operation with a warning message results.\n\n      .. note::\n\n         * Some symbols have an interior area (diamonds, circles, squares, etc.). These areas are filled with the fill color or the stroke color, depending on the annotation type.\n\n      :arg int start: The symbol number for the first point.\n      :arg int end: The symbol number for the last point.\n\n   .. method:: set_oc(xref)\n\n      Set the annotation's visibility using PDF optional content mechanisms. This visibility is controlled by the user interface of supporting PDF viewers. It is independent from other attributes like :attr:`Annot.flags`.\n\n      :arg int xref: the :data:`xref` of an optional contents group (OCG or OCMD). Any previous xref will be overwritten. If zero, a previous entry will be removed. An exception occurs if the xref is not zero and does not point to a valid PDF object.\n\n      .. note:: This does **not require executing** :meth:`Annot.update` to take effect.\n\n   .. method:: get_oc()\n\n      Return the :data:`xref` of an optional content object, or zero if there is none.\n\n      :returns: zero or the xref of an OCG (or OCMD).\n\n\n   .. method:: set_irt_xref(xref)\n\n      * New in v1.19.3\n\n      Set annotation to be \"In Response To\" another one.\n\n      :arg int xref: The :data:`xref` of another annotation.\n\n         .. note:: Must refer to an existing annotation on this page. Setting this property requires no subsequent `update()`.\n\n\n   .. method:: set_open(value)\n\n      * New in v1.18.4\n\n      Set the annotation's Popup annotation to open or closed -- **or** the annotation itself, if its type is 'Text' (\"sticky note\").\n\n      :arg bool value: the desired open state.\n\n\n   .. method:: set_popup(rect)\n\n      * New in v1.18.4\n\n      Create a Popup annotation for the annotation and specify its rectangle. If the Popup already exists, only its rectangle is updated.\n\n      :arg rect_like rect: the desired rectangle.\n\n\n\n   .. method:: set_opacity(value)\n\n      Set the annotation's transparency. Opacity can also be set in :meth:`Annot.update`.\n\n      :arg float value: a float in range *[0, 1]*. Any value outside is assumed to be 1. E.g. a value of 0.5 sets the transparency to 50%.\n\n      Three overlapping 'Circle' annotations with each opacity set to 0.5:\n\n      .. image:: images/img-opacity.*\n\n   .. attribute:: blendmode\n\n      * New in v1.18.4\n\n      The annotation's blend mode. See :ref:`AdobeManual`, page 324 for explanations.\n\n      :rtype: str\n      :returns: the blend mode or ``None``.\n\n\n   .. method:: set_blendmode(blendmode)\n\n      * New in v1.16.14\n      \n      Set the annotation's blend mode. See :ref:`AdobeManual`, page 324 for explanations. The blend mode can also be set in :meth:`Annot.update`.\n\n      :arg str blendmode: set the blend mode. Use :meth:`Annot.update` to reflect this in the visual appearance. For predefined values see :ref:`BlendModes`. Use `PDF_BM_Normal` to **remove** a blend mode.\n\n\n   .. method:: set_name(name)\n\n      * New in version 1.16.0\n      \n      Change the name field of any annotation type. For 'FileAttachment' and 'Text' annotations, this is the icon name, for 'Stamp' annotations the text in the stamp. The visual result (if any) depends on your PDF viewer. See also :ref:`mupdficons`.\n\n      :arg str name: the new name.\n\n      .. caution:: If you set the name of a 'Stamp' annotation, then this will **not change** the rectangle, nor will the text be layouted in any way. If you choose a standard text from :ref:`StampIcons` (the **exact** name piece after `\"STAMP_\"`), you should receive the original layout. An **arbitrary text** will not be changed to upper case, but be written in font \"Times-Bold\" as is, horizontally centered in **one line** and be shortened to fit. To get your text fully displayed, its length using :data:`fontsize` 20 must not exceed 190 points. So please make sure that the following inequality is true: `pymupdf.get_text_length(text, fontname=\"tibo\", fontsize=20) <= 190`.\n\n   .. method:: set_rect(rect)\n\n      Change the rectangle of an annotation. The annotation can be moved around and both sides of the rectangle can be independently scaled. However, the annotation appearance will never get rotated, flipped or sheared. This method only affects certain annotation types [#f2]_ and will lead to a message on Python's `sys.stderr` in other cases. No exception will be raised, but `False` will be returned.\n\n      :arg rect_like rect: the new rectangle of the annotation (finite and not empty). E.g. using a value of *annot.rect + (5, 5, 5, 5)* will shift the annot position 5 pixels to the right and downwards.\n\n      .. note:: You **need not** invoke :meth:`Annot.update` for activation of the effect.\n\n\n   .. method:: set_rotation(angle)\n\n      Set the rotation of an annotation. This rotates the annotation rectangle around its center point. Then a **new annotation rectangle** is calculated from the resulting quad.\n\n      :arg int angle: rotation angle in degrees. Arbitrary values are possible, but will be clamped to the interval `[0, 360)`.\n\n      .. note::\n        * You **must invoke** :meth:`Annot.update` to activate the effect.\n        * For PDF_ANNOT_FREE_TEXT, only one of the values 0, 90, 180 and 270 is possible and will **rotate the text** inside the current rectangle (which remains unchanged). Other values are silently ignored and replaced by 0.\n        * Otherwise, only the following :ref:`AnnotationTypes` can be rotated: 'Square', 'Circle', 'Caret', 'Text', 'FileAttachment', 'Ink', 'Line', 'Polyline', 'Polygon', and 'Stamp'. For all others the method is a no-op.\n\n\n   .. method:: set_border(border=None, width=None, style=None, dashes=None, clouds=None)\n\n      * Changed in version 1.16.9: Allow specification without using a dictionary. The direct parameters are used if *border* is not a dictionary.\n\n      * Changed in version 1.22.5: Support of the \"cloudy\" border effect.\n\n      PDF only: Change border width, dashing, style and cloud effect. See the :attr:`Annot.border` attribute for more details.\n\n\n      :arg dict border: a dictionary as returned by the :attr:`border` property, with keys *\"width\"* (*float*), *\"style\"* (*str*),  *\"dashes\"* (*sequence*) and *clouds* (*int*). Omitted keys will leave the resp. property unchanged. Set the border argument to `None` (the default) to use the other arguments.\n\n      :arg float width: A non-negative value will change the border line width.\n      :arg str style: A value other than `None` will change this border property.\n      :arg sequence dashes: All items of the sequence must be integers, otherwise the parameter is ignored. To remove dashing use: `dashes=[]`. If dashes is a non-empty sequence, \"style\" will automatically be set to \"D\" (dashed). \n      :arg int clouds: A value >= 0 will change this property. Use `clouds=0` to remove the cloudy appearance completely. Only annotation types 'Square', 'Circle', and 'Polygon' are supported with this property.\n\n   .. method:: set_flags(flags)\n\n      Changes the annotation flags. Use the `|` operator to combine several.\n\n      :arg int flags: an integer specifying the required flags.\n\n   .. method:: set_colors(colors=None, stroke=None, fill=None)\n\n      Changes the \"stroke\" and \"fill\" colors for supported annotation types -- not all annotation types accept both. **Do not use this method at all for FreeText annotations** because it has its special conventions to deal with up to three colors (border, fill, text).\n\n      :arg dict colors: a dictionary containing color specifications. For accepted dictionary keys and values see below. The most practical way should be to first make a copy of the *colors* property and then modify this dictionary as required.\n      :arg sequence stroke: see above.\n      :arg sequence fill: see above.\n\n      To completely remove a color specification, use an empty sequence like `[]`. If you specify `None`, an existing specification will not be changed.\n\n\n   .. method:: delete_responses()\n\n      * New in version 1.16.12\n      \n      Delete annotations referring to this one. This includes any 'Popup' annotations and all annotations responding to it.\n\n\n   .. index::\n      pair: blend_mode; Annot.update\n      pair: fontsize; Annot.update\n      pair: text_color; Annot.update\n      pair: border_color; Annot.update\n      pair: fill_color; Annot.update\n      pair: cross_out; Annot.update\n      pair: rotate; Annot.update\n\n   .. method:: update(opacity=None, blend_mode=None, fontsize=0, text_color=None, border_color=None, fill_color=None, cross_out=True, rotate=-1)\n\n      Synchronize the appearance of an annotation with its properties after relevant changes. \n\n      You can safely **omit** this method **only** for the following changes:\n\n         * :meth:`Annot.set_rect`\n         * :meth:`Annot.set_flags`\n         * :meth:`Annot.set_oc`\n         * :meth:`Annot.update_file`\n         * :meth:`Annot.set_info` (except any changes to *\"content\"*)\n\n      All arguments are optional. *(Changed in v1.16.14)* Blend mode and opacity are applicable to **all annotation types**. The other arguments are mostly special use, as described below.\n\n      Color specifications may be made in the usual format used in PuMuPDF as sequences of floats ranging from 0.0 to 1.0 (including both). The sequence length must be 1, 3 or 4 (supporting GRAY, RGB and CMYK colorspaces respectively). For GRAY, just a float is also acceptable.\n\n      :arg float opacity: *(new in v1.16.14)* **valid for all annotation types:** change or set the annotation's transparency. Valid values are *0 <= opacity < 1*.\n\n      :arg str blend_mode: *(new in v1.16.14)* **valid for all annotation types:** change or set the annotation's blend mode. For valid values see :ref:`BlendModes`.\n\n      :arg float fontsize: change :data:`fontsize` of the text. 'FreeText' annotations only.\n\n      :arg sequence,float text_color: change the text color. 'FreeText' annotations only. This has the same effect as ``border_color``. Note that the text color of rich-text annotations cannot be changed at all because it is set by HTML / CSS syntax and part of the text itself.\n\n      :arg sequence,float border_color: change the border color. 'FreeText' annotations only. This has the same effect as ``text_color``.\n\n      :arg sequence,float fill_color: the fill color.\n\n      :arg bool cross_out: *(new in v1.17.2)* add two diagonal lines to the annotation rectangle. 'Redact' annotations only. If not desired, ``False`` must be specified even if the annotation was created with ``False``.\n\n      :arg int rotate: new rotation value. Default (-1) means no change. Supports 'FreeText' and several other annotation types (see :meth:`Annot.set_rotation`), [#f1]_. Only choose 0, 90, 180, or 270 degrees for 'FreeText'. Otherwise any integer is acceptable.\n\n      :rtype: bool\n\n      This method is the only way to change the colors of a FreeText annotation. You cannot use :meth:`Annot.set_colors` for this purpose. But be aware that for rich-text annotations, the text color is never changed. The text color is set by the ``text_color`` entry of the ``info`` dictionary. This is a limitation of |MuPDF| and not a bug.\n\n      .. caution:: Using this method inside a :meth:`Page.annots` loop is **not recommended!** This is because most annotation updates require the owning page to be reloaded -- which cannot be done inside this loop. Please use the example coding pattern given in the documentation of this generator.\n\n\n   .. attribute:: file_info\n\n      Basic information of the annot's attached file.\n\n      :rtype: dict\n      :returns: a dictionary with keys *filename*, *ufilename*, *desc* (description), *size* (uncompressed file size), *length* (compressed length) for FileAttachment annot types, else ``None``.\n\n   .. method:: get_file()\n\n      Returns attached file content.\n\n      :rtype: bytes\n      :returns: the content of the attached file.\n\n   .. index::\n      pair: buffer; Annot.update_file\n      pair: filename; Annot.update_file\n      pair: ufilename; Annot.update_file\n      pair: desc; Annot.update_file\n\n   .. method:: update_file(buffer=None, filename=None, ufilename=None, desc=None)\n\n      Updates the content of an attached file. All arguments are optional. No arguments lead to a no-op.\n\n      :arg bytes|bytearray|BytesIO buffer: the new file content. Omit to only change meta-information.\n\n         *(Changed in version 1.14.13)* *io.BytesIO* is now also supported.\n\n      :arg str filename: new filename to associate with the file.\n\n      :arg str ufilename: new unicode filename to associate with the file.\n\n      :arg str desc: new description of the file content.\n\n   .. method:: get_sound()\n\n      Return the embedded sound of an audio annotation.\n\n      :rtype: dict\n      :returns: the sound audio file and accompanying properties. These are the possible dictionary keys, of which only \"rate\" and \"stream\" are always present.\n\n        =========== =======================================================\n        Key         Description\n        =========== =======================================================\n        rate        (float, requ.) samples per second\n        channels    (int, opt.) number of sound channels\n        bps         (int, opt.) bits per sample value per channel\n        encoding    (str, opt.) encoding format: Raw, Signed, muLaw, ALaw\n        compression (str, opt.) name of compression filter\n        stream      (bytes, requ.) the sound file content\n        =========== =======================================================\n\n\n   .. attribute:: opacity\n\n      The annotation's transparency. If set, it is a value in range *[0, 1]*. The PDF default is 1. However, in an effort to tell the difference, we return *-1.0* if not set.\n\n      :rtype: float\n\n   .. attribute:: parent\n\n      The owning page object of the annotation.\n\n      :rtype: :ref:`Page`\n\n   .. attribute:: rotation\n\n      The annot rotation.\n\n      :rtype: int\n      :returns: a value [-1, 359]. If rotation is not at all, -1 is returned (and implies a rotation angle of 0). Other possible values are normalized to some value value 0 <= angle < 360.\n\n   .. attribute:: rect\n\n      The rectangle containing the annotation.\n\n      :rtype: :ref:`Rect`\n\n   .. attribute:: next\n\n      The next annotation on this page or None.\n\n      :rtype: *Annot*\n\n   .. attribute:: type\n\n      A number and one or two strings describing the annotation type, like **[2, 'FreeText', 'FreeTextCallout']**. The second string entry is optional and may be empty. See the appendix :ref:`AnnotationTypes` for a list of possible values and their meanings.\n\n      :rtype: list\n\n   .. attribute:: info\n\n      A dictionary containing various information. All fields are optional strings. For information items not provided, an empty string is returned.\n\n      * *name* -- e.g. for 'Stamp' annotations it will contain the stamp text like \"Sold\" or \"Experimental\", for other annot types you will see the name of the annot's icon here (\"PushPin\" for FileAttachment).\n\n      * *content* -- a string containing the text for type *Text* and *FreeText* annotations. Commonly used for filling the text field of annotation pop-up windows.\n\n      * *title* -- a string containing the title of the annotation pop-up window. By convention, this is used for the **annotation author**.\n\n      * *creationDate* -- creation timestamp.\n      * *modDate* -- last modified timestamp.\n      * *subject* -- subject.\n      * *id* -- *(new in version 1.16.10)* a unique identification of the annotation. This is taken from PDF key */NM*. Annotations added by PyMuPDF will have a unique name, which appears here.\n\n      :rtype: dict\n\n\n   .. attribute:: flags\n\n      An integer whose low order bits contain flags for how the annotation should be presented.\n\n      :rtype: int\n\n   .. attribute:: line_ends\n\n      A pair of integers specifying start and end symbol of annotations types 'FreeText', 'Line', 'PolyLine', and 'Polygon'. ``None`` if not applicable. For possible values and descriptions in this list, see the :ref:`AdobeManual`, table 1.76 on page 400.\n\n      :rtype: tuple\n\n   .. attribute:: vertices\n\n      A list containing a variable number of point (\"vertices\") coordinates (each given by a pair of floats) for various types of annotations:\n\n      * 'Line' -- the starting and ending coordinates (2 float pairs).\n      * 'FreeText' -- 2 or 3 float pairs designating the starting, the (optional) knee point, and the ending coordinates.\n      * 'PolyLine' / 'Polygon' -- the coordinates of the edges connected by line pieces (n float pairs for n points).\n      * text markup annotations -- 4 float pairs specifying the *QuadPoints* of the marked text span (see :ref:`AdobeManual`, page 403).\n      * 'Ink' -- list of one to many sublists of vertex coordinates. Each such sublist represents a separate line in the drawing.\n\n      :rtype: list\n\n\n   .. attribute:: colors\n\n      dictionary of two lists of floats in range *0 <= float <= 1* specifying the \"stroke\" and the interior (\"fill\") colors. The stroke color is used for borders and everything that is actively painted or written (\"stroked\"). The fill color is used for the interior of objects like line ends, circles and squares. The lengths of these lists implicitly determine the colorspaces used: 1 = GRAY, 3 = RGB, 4 = CMYK. So \"[1.0, 0.0, 0.0]\" stands for RGB color red. Both lists can be empty if no color is specified. Be aware about some potentially unexpected cases:\n\n      * The color of Highlight annotations is a **stroke** color, contrary to intuition.\n      * The color if FreeText annotations is a **stroke** color, but appears as the color that fills the rectangle and any applicable line end symbols. Text color and border color cannot be accessed at all.\n\n      :rtype: dict\n\n   .. attribute:: xref\n\n      The PDF :data:`xref`.\n\n      :rtype: int\n\n   .. attribute:: irt_xref\n\n      The PDF :data:`xref` of an annotation to which this one responds. Return zero if this is no response annotation.\n\n      :rtype: int\n\n   .. attribute:: popup_xref\n\n      The PDF :data:`xref` of the associated Popup annotation. Zero if non-existent.\n\n      :rtype: int\n\n   .. attribute:: has_popup\n\n      Whether the annotation has a Popup annotation.\n\n      :rtype: bool\n\n   .. attribute:: is_open\n\n      Whether the annotation's Popup is open -- **or** the annotation itself ('Text' annotations only).\n\n      :rtype: bool\n\n   .. attribute:: popup_rect\n\n      The rectangle of the associated Popup annotation. Infinite rectangle if non-existent.\n\n      :rtype: :ref:`Rect`\n\n   .. attribute:: rect_delta\n\n      A tuple of four floats representing the `/RD` entry of the annotation. The four numbers describe the numerical differences (left, top, -right, -bottom) between two rectangles: the :attr:`rect` of the annotation and a rectangle contained within that rectangle. If the entry is missing, this property is `(0, 0, 0, 0)`. If the annotation border is a normal, straight line, these numbers are typically border width divided by 2. If the annotation has a \"cloudy\" border, you will see the breadth of the cloud semi-circles here. In general, the numbers need not be identical. To compute the inner rectangle do `a.rect + a.rect_delta`.\n\n   .. attribute:: border\n\n      A dictionary containing border characteristics. Empty if no border information exists. The following keys may be present:\n\n      * *width* -- a float indicating the border thickness in points. The value is -1.0 if no width is specified.\n\n      * *dashes* -- a sequence of integers specifying a line dashing pattern. *[]* means no dashes, *[n]* means equal on-off lengths of *n* points, longer lists will be interpreted as specifying alternating on-off length values. See the :ref:`AdobeManual` page 126 for more details.\n\n      * *style* -- 1-byte border style: **\"S\"** (Solid) = solid line surrounding the annotation, **\"D\"** (Dashed) = dashed line surrounding the annotation, the dash pattern is specified by the *dashes* entry, **\"B\"** (Beveled) = a simulated embossed rectangle that appears to be raised above the surface of the page, **\"I\"** (Inset) = a simulated engraved rectangle that appears to be recessed below the surface of the page, **\"U\"** (Underline) = a single line along the bottom of the annotation rectangle.\n\n      * *clouds* -- an integer indicating a \"cloudy\" border, where ``n`` is an integer `-1 <= n <= 2`. A value `n = 0` indicates a straight line (no clouds), 1 means small and 2 means large semi-circles, mimicking the cloudy appearance. If -1, then no specification is present.\n\n      :rtype: dict\n\n\n.. _mupdficons:\n\nAnnotation Icons in MuPDF\n-------------------------\nThis is a list of icons referenceable by name for annotation types 'Text' and 'FileAttachment'. You can use them via the *icon* parameter when adding an annotation, or use the as argument in :meth:`Annot.set_name`. It is left to your discretion which item to choose when -- no mechanism will keep you from using e.g. the \"Speaker\" icon for a 'FileAttachment'.\n\n.. image:: images/mupdf-icons.*\n\n\nExample\n--------\nChange the graphical image of an annotation. Also update the \"author\" and the text to be shown in the popup window::\n\n doc = pymupdf.open(\"circle-in.pdf\")\n page = doc[0]                          # page 0\n annot = page.first_annot                # get the annotation\n annot.set_border(dashes=[3])           # set dashes to \"3 on, 3 off ...\"\n\n # set stroke and fill color to some blue\n annot.set_colors({\"stroke\":(0, 0, 1), \"fill\":(0.75, 0.8, 0.95)})\n info = annot.info                      # get info dict\n info[\"title\"] = \"Jorj X. McKie\"        # set author\n\n # text in popup window ...\n info[\"content\"] = \"I changed border and colors and enlarged the image by 20%.\"\n info[\"subject\"] = \"Demonstration of PyMuPDF\"     # some PDF viewers also show this\n annot.set_info(info)                   # update info dict\n r = annot.rect                         # take annot rect\n r.x1 = r.x0 + r.width  * 1.2           # new location has same top-left\n r.y1 = r.y0 + r.height * 1.2           # but 20% longer sides\n annot.set_rect(r)                      # update rectangle\n annot.update()                         # update the annot's appearance\n doc.save(\"circle-out.pdf\")             # save\n\nThis is how the circle annotation looks like before and after the change (pop-up windows displayed using Nitro PDF viewer):\n\n|circle|\n\n.. |circle| image:: images/img-circle.*\n\n\n.. rubric:: Footnotes\n\n.. [#f1] Rotating an annotation also changes its rectangle. Depending on how the annotation was defined, the original rectangle is **cannot be reconstructed** by setting the rotation value to zero again and will be lost.\n\n.. [#f2] Only the following annotation types support method :meth:`Annot.set_rect`: Text, FreeText, Square, Circle, Redact, Stamp, Caret, FileAttachment, Sound, and Movie.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/app1.rst",
    "content": ".. include:: header.rst\n\n.. _Appendix1:\n\n======================================\nAppendix 1: Details on Text Extraction\n======================================\nThis chapter provides background on the text extraction methods of PyMuPDF.\n\nInformation of interest are\n\n* what do they provide?\n* what do they imply (processing time / data sizes)?\n\nGeneral structure of a TextPage\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n:ref:`TextPage` is one of (Py-) MuPDF's classes. It is normally created (and destroyed again) behind the curtain, when :ref:`Page` text extraction methods are used, but it is also available directly and can be used as a persistent object. Other than its name suggests, images may optionally also be part of a text page::\n\n <page>\n     <text block>\n         <line>\n             <span>\n                 <char>\n     <image block>\n         <img>\n\nA **text page** consists of blocks (= roughly paragraphs).\n\nA **block** consists of either lines and their characters, or an image.\n\nA **line** consists of spans.\n\nA **span** consists of adjacent characters with identical font properties: name, size, flags and color.\n\nPlain Text\n~~~~~~~~~~\n\nFunction :meth:`TextPage.extractText` (or *Page.get_text(\"text\")*) extracts a page's plain **text in original order** as specified by the creator of the document.\n\nAn example output::\n\n    >>> print(page.get_text(\"text\"))\n    Some text on first page.\n\n.. note:: The output may not equal an accustomed \"natural\" reading order. However, you can request a reordering following the scheme \"top-left to bottom-right\" by executing `page.get_text(\"text\", sort=True)`.\n\n\nBLOCKS\n~~~~~~~~~~\n\nFunction :meth:`TextPage.extractBLOCKS` (or *Page.get_text(\"blocks\")*) extracts a page's text blocks as a list of items like::\n\n    (x0, y0, x1, y1, \"lines in block\", block_no, block_type)\n\nWhere the first 4 items are the float coordinates of the block's bbox. The lines within each block are concatenated by a new-line character.\n\nThis is a high-speed method, which by default also extracts image meta information: Each image appears as a block with one text line, which contains meta information. The image itself is not shown.\n\nAs with simple text output above, the `sort` argument can be used as well to obtain a reading order.\n\nExample output::\n\n    >>> print(page.get_text(\"blocks\", sort=False))\n    [(50.0, 88.17500305175781, 166.1709747314453, 103.28900146484375,\n    'Some text on first page.', 0, 0)]\n\n\nWORDS\n~~~~~~~~~~\n\nFunction :meth:`TextPage.extractWORDS` (or *Page.get_text(\"words\")*) extracts a page's text **words** as a list of items like::\n\n    (x0, y0, x1, y1, \"word\", block_no, line_no, word_no)\n\nWhere the first 4 items are the float coordinates of the words's bbox. The last three integers provide some more information on the word's whereabouts.\n\nThis is a high-speed method. As with the previous methods, argument `sort=True` will reorder the words.\n\nExample output::\n\n    >>> for word in page.get_text(\"words\", sort=False):\n            print(word)\n    (50.0, 88.17500305175781, 78.73200225830078, 103.28900146484375,\n    'Some', 0, 0, 0)\n    (81.79000091552734, 88.17500305175781, 99.5219955444336, 103.28900146484375,\n    'text', 0, 0, 1)\n    (102.57999420166016, 88.17500305175781, 114.8119888305664, 103.28900146484375,\n    'on', 0, 0, 2)\n    (117.86998748779297, 88.17500305175781, 135.5909881591797, 103.28900146484375,\n    'first', 0, 0, 3)\n    (138.64898681640625, 88.17500305175781, 166.1709747314453, 103.28900146484375,\n    'page.', 0, 0, 4)\n\nHTML\n~~~~\n\n:meth:`TextPage.extractHTML` (or *Page.get_text(\"html\")* output fully reflects the structure of the page's ``TextPage`` -- much like DICT / JSON below. This includes images, font information and text positions. If wrapped in HTML header and trailer code, it can readily be displayed by an internet browser. Our above example::\n\n    >>> for line in page.get_text(\"html\").splitlines():\n            print(line)\n\n    <div id=\"page0\" style=\"position:relative;width:300pt;height:350pt;\n    background-color:white\">\n    <p style=\"position:absolute;white-space:pre;margin:0;padding:0;top:88pt;\n    left:50pt\"><span style=\"font-family:Helvetica,sans-serif;\n    font-size:11pt\">Some text on first page.</span></p>\n    </div>\n\n\n.. _HTMLQuality:\n\nControlling Quality of HTML Output\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWhile HTML output has improved a lot in MuPDF v1.12.0, it is not yet bug-free: we have found problems in the areas **font support** and **image positioning**.\n\n* HTML text contains references to the fonts used of the original document. If these are not known to the browser (a fat chance!), it will replace them with others; the results will probably look awkward. This issue varies greatly by browser -- on my Windows machine, MS Edge worked just fine, whereas Firefox looked horrible.\n\n* For PDFs with a complex structure, images may not be positioned and / or sized correctly. This seems to be the case for rotated pages and pages, where the various possible page bbox variants do not coincide (e.g. *MediaBox != CropBox*). We do not know yet, how to address this -- we filed a bug at MuPDF's site.\n\nTo address the font issue, you can use a simple utility script to scan through the HTML file and replace font references. Here is a little example that replaces all fonts with one of the :ref:`Base-14-Fonts`: serifed fonts will become \"Times\", non-serifed \"Helvetica\" and monospaced will become \"Courier\". Their respective variations for \"bold\", \"italic\", etc. are hopefully done correctly by your browser::\n\n import sys\n filename = sys.argv[1]\n otext = open(filename).read()                 # original html text string\n pos1 = 0                                      # search start poition\n font_serif = \"font-family:Times\"              # enter ...\n font_sans  = \"font-family:Helvetica\"          # ... your choices ...\n font_mono  = \"font-family:Courier\"            # ... here\n found_one  = False                            # true if search successful\n\n while True:\n     pos0 = otext.find(\"font-family:\", pos1)   # start of a font spec\n     if pos0 < 0:                              # none found - we are done\n         break\n     pos1 = otext.find(\";\", pos0)              # end of font spec\n     test = otext[pos0 : pos1]                 # complete font spec string\n     testn = \"\"                                # the new font spec string\n     if test.endswith(\",serif\"):               # font with serifs?\n         testn = font_serif                    # use Times instead\n     elif test.endswith(\",sans-serif\"):        # sans serifs font?\n         testn = font_sans                     # use Helvetica\n     elif test.endswith(\",monospace\"):         # monospaced font?\n         testn = font_mono                     # becomes Courier\n\n     if testn != \"\":                           # any of the above found?\n         otext = otext.replace(test, testn)    # change the source\n         found_one = True\n         pos1 = 0                              # start over\n\n if found_one:\n     ofile = open(filename + \".html\", \"w\")\n     ofile.write(otext)\n     ofile.close()\n else:\n     print(\"Warning: could not find any font specs!\")\n\n\n\nDICT (or JSON)\n~~~~~~~~~~~~~~~~\n\n:meth:`TextPage.extractDICT` (or *Page.get_text(\"dict\", sort=False)*) output fully reflects the structure of a ``TextPage`` and provides image content and position detail (*bbox* -- boundary boxes in pixel units) for every block, line and span. Images are stored as *bytes* for DICT output and base64 encoded strings for JSON output.\n\nFor a visualization of the dictionary structure have a look at :ref:`textpagedict`.\n\nHere is how this looks like::\n\n    {\n        \"width\": 300.0,\n        \"height\": 350.0,\n        \"blocks\": [{\n            \"type\": 0,\n            \"bbox\": (50.0, 88.17500305175781, 166.1709747314453, 103.28900146484375),\n            \"lines\": ({\n                \"wmode\": 0,\n                \"dir\": (1.0, 0.0),\n                \"bbox\": (50.0, 88.17500305175781, 166.1709747314453, 103.28900146484375),\n                \"spans\": ({\n                    \"size\": 11.0,\n                    \"flags\": 0,\n                    \"font\": \"Helvetica\",\n                    \"color\": 0,\n                    \"origin\": (50.0, 100.0),\n                    \"text\": \"Some text on first page.\",\n                    \"bbox\": (50.0, 88.17500305175781, 166.1709747314453, 103.28900146484375)\n                })\n            }]\n        }]\n    }\n\nRAWDICT (or RAWJSON)\n~~~~~~~~~~~~~~~~~~~~~\n:meth:`TextPage.extractRAWDICT` (or *Page.get_text(\"rawdict\", sort=False)*) is an **information superset of DICT** and takes the detail level one step deeper. It looks exactly like the above, except that the *\"text\"* items (*string*) in the spans are replaced by the list *\"chars\"*. Each *\"chars\"* entry is a character *dict*. For example, here is what you would see in place of item *\"text\": \"Text in black color.\"* above::\n\n    \"chars\": [{\n        \"origin\": (50.0, 100.0),\n        \"bbox\": (50.0, 88.17500305175781, 57.336997985839844, 103.28900146484375),\n        \"c\": \"S\"\n    }, {\n        \"origin\": (57.33700180053711, 100.0),\n        \"bbox\": (57.33700180053711, 88.17500305175781, 63.4530029296875, 103.28900146484375),\n        \"c\": \"o\"\n    }, {\n        \"origin\": (63.4530029296875, 100.0),\n        \"bbox\": (63.4530029296875, 88.17500305175781, 72.61600494384766, 103.28900146484375),\n        \"c\": \"m\"\n    }, {\n        \"origin\": (72.61600494384766, 100.0),\n        \"bbox\": (72.61600494384766, 88.17500305175781, 78.73200225830078, 103.28900146484375),\n        \"c\": \"e\"\n    }, {\n        \"origin\": (78.73200225830078, 100.0),\n        \"bbox\": (78.73200225830078, 88.17500305175781, 81.79000091552734, 103.28900146484375),\n        \"c\": \" \"\n    < ... deleted ... >\n    }, {\n        \"origin\": (163.11297607421875, 100.0),\n        \"bbox\": (163.11297607421875, 88.17500305175781, 166.1709747314453, 103.28900146484375),\n        \"c\": \".\"\n    }],\n\n\nXML\n~~~\n\nThe :meth:`TextPage.extractXML` (or *Page.get_text(\"xml\")*) version extracts text (no images) with the detail level of RAWDICT::\n\n    >>> for line in page.get_text(\"xml\").splitlines():\n        print(line)\n\n    <page id=\"page0\" width=\"300\" height=\"350\">\n    <block bbox=\"50 88.175 166.17098 103.289\">\n    <line bbox=\"50 88.175 166.17098 103.289\" wmode=\"0\" dir=\"1 0\">\n    <font name=\"Helvetica\" size=\"11\">\n    <char quad=\"50 88.175 57.336999 88.175 50 103.289 57.336999 103.289\" x=\"50\"\n    y=\"100\" color=\"#000000\" c=\"S\"/>\n    <char quad=\"57.337 88.175 63.453004 88.175 57.337 103.289 63.453004 103.289\" x=\"57.337\"\n    y=\"100\" color=\"#000000\" c=\"o\"/>\n    <char quad=\"63.453004 88.175 72.616008 88.175 63.453004 103.289 72.616008 103.289\" x=\"63.453004\"\n    y=\"100\" color=\"#000000\" c=\"m\"/>\n    <char quad=\"72.616008 88.175 78.732 88.175 72.616008 103.289 78.732 103.289\" x=\"72.616008\"\n    y=\"100\" color=\"#000000\" c=\"e\"/>\n    <char quad=\"78.732 88.175 81.79 88.175 78.732 103.289 81.79 103.289\" x=\"78.732\"\n    y=\"100\" color=\"#000000\" c=\" \"/>\n\n    ... deleted ...\n\n    <char quad=\"163.11298 88.175 166.17098 88.175 163.11298 103.289 166.17098 103.289\" x=\"163.11298\"\n    y=\"100\" color=\"#000000\" c=\".\"/>\n    </font>\n    </line>\n    </block>\n    </page>\n\n.. note:: We have successfully tested `lxml <https://pypi.org/project/lxml/>`_ to interpret this output.\n\nXHTML\n~~~~~\n:meth:`TextPage.extractXHTML` (or *Page.get_text(\"xhtml\")*) is a variation of TEXT but in HTML format, containing the bare text and images (\"semantic\" output)::\n\n    <div id=\"page0\">\n    <p>Some text on first page.</p>\n    </div>\n\n.. _text_extraction_flags:\n\nText Extraction Flags Defaults\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n* New in version 1.16.2: Method :meth:`Page.get_text` supports a keyword parameter *flags* *(int)* to control the amount and the quality of extracted data. The following table shows the defaults settings (flags parameter omitted or None) for each extraction variant. If you specify flags with a value other than ``None``, be aware that you must set **all desired** options. A description of the respective bit settings can be found in :ref:`TextPreserve`.\n\n* New in v1.19.6: The default combinations in the following table are now available as Python constants: :data:`TEXTFLAGS_TEXT`, :data:`TEXTFLAGS_WORDS`, :data:`TEXTFLAGS_BLOCKS`, :data:`TEXTFLAGS_DICT`, :data:`TEXTFLAGS_RAWDICT`, :data:`TEXTFLAGS_HTML`, :data:`TEXTFLAGS_XHTML`, :data:`TEXTFLAGS_XML`, and :data:`TEXTFLAGS_SEARCH`. You can now easily modify a default flag, e.g.\n\n    - **include** images in a \"blocks\" output:\n    \n    `flags = TEXTFLAGS_BLOCKS | TEXT_PRESERVE_IMAGES`\n    \n    - **exclude** images from a \"dict\" output:\n    \n    `flags = TEXTFLAGS_DICT & ~TEXT_PRESERVE_IMAGES`\n    \n    - set **dehyphenation off** in text searches:\n    \n    `flags = TEXTFLAGS_SEARCH & ~TEXT_DEHYPHENATE`\n\n\n========================= ==== ==== ===== === ==== ======= ===== ====== ======\nIndicator                 text html xhtml xml dict rawdict words blocks search\n========================= ==== ==== ===== === ==== ======= ===== ====== ======\npreserve ligatures        1    1    1     1   1    1       1     1       0\npreserve whitespace       1    1    1     1   1    1       1     1       1\npreserve images           n/a  1    1     n/a 1    1       n/a   0       0\ninhibit spaces            0    0    0     0   0    0       0     0       0\ndehyphenate               0    0    0     0   0    0       0     0       1\nclip to mediabox          1    1    1     1   1    1       1     1       1\nuse CID instead of U+FFFD 1    1    1     1   1    1       1     1       0\n========================= ==== ==== ===== === ==== ======= ===== ====== ======\n\n* **search** refers to the text search function.\n* **\"json\"** is handled exactly like **\"dict\"** and is hence left out.\n* **\"rawjson\"** is handled exactly like **\"rawdict\"** and is hence left out.\n* An \"n/a\" specification means a value of 0 and setting this bit never has any effect on the output (but an adverse effect on performance).\n* If you are not interested in images when using an output variant which includes them by default, then by all means set the respective bit off: You will experience a better performance and much lower space requirements.\n\nTo show the effect of `TEXT_INHIBIT_SPACES` have a look at this example::\n\n    >>> print(page.get_text(\"text\"))\n    H a l l o !\n    Mo r e  t e x t\n    i s  f o l l o w i n g\n    i n  E n g l i s h\n    . . .  l e t ' s  s e e\n    w h a t  h a p p e n s .\n    >>> print(page.get_text(\"text\", flags=pymupdf.TEXT_INHIBIT_SPACES))\n    Hallo!\n    More text\n    is following\n    in English\n    ... let's see\n    what happens.\n    >>>\n\n\nPerformance\n~~~~~~~~~~~~\nThe text extraction methods differ significantly both: in terms of information they supply, and in terms of resource requirements and runtimes. Generally, more information of course means, that more processing is required and a higher data volume is generated.\n\n.. note:: Especially images have a **very significant** impact. Make sure to exclude them (via the *flags* parameter) whenever you do not need them. To process the below mentioned 2'700 total pages with default flags settings required 160 seconds across all extraction methods. When all images where excluded, less than 50% of that time (77 seconds) were needed.\n\nTo begin with, all methods are **very fast** in relation to other products out there in the market. In terms of processing speed, we are not aware of a faster (free) tool. Even the most detailed method, RAWDICT, processes all 1'310 pages of the :ref:`AdobeManual` in less than 5 seconds (simple text needs less than 2 seconds here).\n\nThe following table shows average relative speeds (\"RSpeed\", baseline 1.00 is TEXT), taken across ca. 1400 text-heavy and 1300 image-heavy pages.\n\n======= ====== ===================================================================== ==========\nMethod  RSpeed Comments                                                               no images\n======= ====== ===================================================================== ==========\nTEXT     1.00  no images, **plain** text, line breaks                                 1.00\nBLOCKS   1.00  image bboxes (only), **block** level text with bboxes, line breaks     1.00\nWORDS    1.02  no images, **word** level text with bboxes                             1.02\nXML      2.72  no images, **char** level text, layout and font details                2.72\nXHTML    3.32  **base64** images, **span** level text, no layout info                 1.00\nHTML     3.54  **base64** images, **span** level text, layout and font details        1.01\nDICT     3.93  **binary** images, **span** level text, layout and font details        1.04\nRAWDICT  4.50  **binary** images, **char** level text, layout and font details        1.68\n======= ====== ===================================================================== ==========\n\nAs mentioned: when excluding image extraction (last column), the relative speeds are changing drastically: except RAWDICT and XML, the other methods are almost equally fast, and RAWDICT requires 40% less execution time than the **now slowest XML**.\n\nLook at chapter **Appendix 1** for more performance information.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/app2.rst",
    "content": ".. include:: header.rst\n\n.. _Appendix2:\n\n================================================\nAppendix 2: Considerations on Embedded Files\n================================================\nThis chapter provides some background on embedded files support in PyMuPDF.\n\nGeneral\n----------\nStarting with version 1.4, PDF supports embedding arbitrary files as part (\"Embedded File Streams\") of a PDF document file (see chapter \"7.11.4\nEmbedded File Streams\", pp. 103 of the :ref:`AdobeManual`).\n\nIn many aspects, this is comparable to concepts also found in ZIP files or the OLE technique in MS Windows. PDF embedded files do, however, *not* support directory structures as does the ZIP format. An embedded file can in turn contain embedded files itself.\n\nAdvantages of this concept are that embedded files are under the PDF umbrella, benefitting from its permissions / password protection and integrity aspects: all data, which a PDF may reference or even may be dependent on, can be bundled into it and so form a single, consistent unit of information.\n\nIn addition to embedded files, PDF 1.7 adds *collections* to its support range. This is an advanced way of storing and presenting meta information (i.e. arbitrary and extensible properties) of embedded files.\n\nMuPDF Support\n--------------\nAfter adding initial support for collections (portfolios) and */EmbeddedFiles* in MuPDF version 1.11, this support was dropped again in version 1.15.\n\nAs a consequence, the cli utility *mutool* no longer offers access to embedded files.\n\nPyMuPDF -- having implemented an */EmbeddedFiles* API in response in its version 1.11.0 -- was therefore forced to change gears starting with its version 1.16.0 (we never published a MuPDF v1.15.x compatible PyMuPDF).\n\nWe are now maintaining our own code basis supporting embedded files. This code makes use of basic MuPDF dictionary and array functions only.\n\nPyMuPDF Support\n------------------\nWe continue to support the full old API with respect to embedded files -- with only minor, cosmetic changes.\n\nThere even also is a new function, which delivers a list of all names under which embedded data are registered in a PDF, :meth:`Document.embfile_names`.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/app3.rst",
    "content": ".. include:: header.rst\n\n.. _Appendix3:\n\n================================================\nAppendix 3: Assorted Technical Information\n================================================\nThis section deals with various technical topics, that are not necessarily related to each other.\n\n------------\n\n.. _ImageTransformation:\n\nImage Transformation Matrix\n----------------------------\nStarting with version 1.18.11, the image transformation matrix is returned by some methods for text and image extraction: :meth:`Page.get_text` and :meth:`Page.get_image_bbox`.\n\nThe transformation matrix contains information about how an image was transformed to fit into the rectangle (its \"boundary box\" = \"bbox\") on some document page. By inspecting the image's bbox on the page and this matrix, one can determine for example, whether and how the image is displayed scaled or rotated on a page.\n\nThe relationship between image dimension and its bbox on a page is the following:\n\n1. Using the original image's width and height,\n    - define the image rectangle `imgrect = pymupdf.Rect(0, 0, width, height)`\n    - define the \"shrink matrix\" `shrink = pymupdf.Matrix(1/width, 0, 0, 1/height, 0, 0)`.\n\n2. Transforming the image rectangle with its shrink matrix, will result in the unit rectangle: `imgrect * shrink = pymupdf.Rect(0, 0, 1, 1)`.\n\n3. Using the image **transformation matrix** \"transform\", the following steps will compute the bbox::\n\n    imgrect = pymupdf.Rect(0, 0, width, height)\n    shrink = pymupdf.Matrix(1/width, 0, 0, 1/height, 0, 0)\n    bbox = imgrect * shrink * transform\n\n4. Inspecting the matrix product `shrink * transform` will reveal all information about what happened to the image rectangle to make it fit into the bbox on the page: rotation, scaling of its sides and translation of its origin. Let us look at an example:\n\n    >>> imginfo = page.get_images()[0]  # get an image item on a page\n    >>> imginfo\n    (5, 0, 439, 501, 8, 'DeviceRGB', '', 'fzImg0', 'DCTDecode')\n    >>> #------------------------------------------------\n    >>> # define image shrink matrix and rectangle\n    >>> #------------------------------------------------\n    >>> shrink = pymupdf.Matrix(1 / 439, 0, 0, 1 / 501, 0, 0)\n    >>> imgrect = pymupdf.Rect(0, 0, 439, 501)\n    >>> #------------------------------------------------\n    >>> # determine image bbox and transformation matrix:\n    >>> #------------------------------------------------\n    >>> bbox, transform = page.get_image_bbox(\"fzImg0\", transform=True)\n    >>> #------------------------------------------------\n    >>> # confirm equality - permitting rounding errors\n    >>> #------------------------------------------------\n    >>> bbox\n    Rect(100.0, 112.37525939941406, 300.0, 287.624755859375)\n    >>> imgrect * shrink * transform\n    Rect(100.0, 112.375244140625, 300.0, 287.6247253417969)\n    >>> #------------------------------------------------\n    >>> shrink * transform\n    Matrix(0.0, -0.39920157194137573, 0.3992016017436981, 0.0, 100.0, 287.6247253417969)\n    >>> #------------------------------------------------\n    >>> # the above shows:\n    >>> # image sides are scaled by same factor ~0.4,\n    >>> # and the image is rotated by 90 degrees clockwise\n    >>> # compare this with pymupdf.Matrix(-90) * 0.4\n    >>> #------------------------------------------------\n\n\n------------\n\n.. _Base-14-Fonts:\n\nPDF Base 14 Fonts\n---------------------\nThe following 14 builtin font names **must be supported by every PDF viewer** application. They are available as a dictionary, which maps their full names amd their abbreviations in lower case to the full font basename. Wherever a **fontname** must be provided in PyMuPDF, any **key or value** from the dictionary may be used::\n\n    In [2]: pymupdf.Base14_fontdict\n    Out[2]:\n    {'courier': 'Courier',\n    'courier-oblique': 'Courier-Oblique',\n    'courier-bold': 'Courier-Bold',\n    'courier-boldoblique': 'Courier-BoldOblique',\n    'helvetica': 'Helvetica',\n    'helvetica-oblique': 'Helvetica-Oblique',\n    'helvetica-bold': 'Helvetica-Bold',\n    'helvetica-boldoblique': 'Helvetica-BoldOblique',\n    'times-roman': 'Times-Roman',\n    'times-italic': 'Times-Italic',\n    'times-bold': 'Times-Bold',\n    'times-bolditalic': 'Times-BoldItalic',\n    'symbol': 'Symbol',\n    'zapfdingbats': 'ZapfDingbats',\n    'helv': 'Helvetica',\n    'heit': 'Helvetica-Oblique',\n    'hebo': 'Helvetica-Bold',\n    'hebi': 'Helvetica-BoldOblique',\n    'cour': 'Courier',\n    'coit': 'Courier-Oblique',\n    'cobo': 'Courier-Bold',\n    'cobi': 'Courier-BoldOblique',\n    'tiro': 'Times-Roman',\n    'tibo': 'Times-Bold',\n    'tiit': 'Times-Italic',\n    'tibi': 'Times-BoldItalic',\n    'symb': 'Symbol',\n    'zadb': 'ZapfDingbats'}\n\nIn contrast to their obligation, not all PDF viewers support these fonts correctly and completely -- this is especially true for Symbol and ZapfDingbats. Also, the glyph (visual) images will be specific to every reader.\n\nTo see how these fonts can be used -- including the **CJK built-in** fonts -- look at the table in :meth:`Page.insert_font`.\n\n------------\n\n.. _AdobeManual:\n\nAdobe PDF References\n---------------------------\n\nThis PDF Reference manual published by Adobe is frequently quoted throughout this documentation. It can be viewed and downloaded from `opensource.adobe.com <https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_.\n\n\n------------\n\n\n.. _SequenceTypes:\n\nUsing Python Sequences as Arguments in PyMuPDF\n------------------------------------------------\nWhen PyMuPDF objects and methods require a Python **list** of numerical values, other Python **sequence types** are also allowed. Python classes are said to implement the **sequence protocol**, if they have a `__getitem__()` method.\n\nThis basically means, you can interchangeably use Python *list* or *tuple* or even *array.array*, *numpy.array* and *bytearray* types in these cases.\n\nFor example, specifying a sequence `\"s\"` in any of the following ways\n\n* `s = [1, 2]` -- a list\n* `s = (1, 2)` -- a tuple\n* `s = array.array(\"i\", (1, 2))` -- an array.array\n* `s = numpy.array((1, 2))` -- a numpy array\n* `s = bytearray((1, 2))` -- a bytearray\n\nwill make it usable in the following example expressions:\n\n* `pymupdf.Point(s)`\n* `pymupdf.Point(x, y) + s`\n* `doc.select(s)`\n\nSimilarly with all geometry objects :ref:`Rect`, :ref:`IRect`, :ref:`Matrix` and :ref:`Point`.\n\nBecause all PyMuPDF geometry classes themselves are special cases of sequences, they (with the exception of :ref:`Quad` -- see below) can be freely used where numerical sequences can be used, e.g. as arguments for functions like *list()*, *tuple()*, *array.array()* or *numpy.array()*. Look at the following snippet to see this work.\n\n>>> import pymupdf, array, numpy as np\n>>> m = pymupdf.Matrix(1, 2, 3, 4, 5, 6)\n>>>\n>>> list(m)\n[1.0, 2.0, 3.0, 4.0, 5.0, 6.0]\n>>>\n>>> tuple(m)\n(1.0, 2.0, 3.0, 4.0, 5.0, 6.0)\n>>>\n>>> array.array(\"f\", m)\narray('f', [1.0, 2.0, 3.0, 4.0, 5.0, 6.0])\n>>>\n>>> np.array(m)\narray([1., 2., 3., 4., 5., 6.])\n\n.. note:: :ref:`Quad` is a Python sequence object as well and has a length of 4. Its items however are :data:`point_like` -- not numbers. Therefore, the above remarks do not apply.\n\n------------\n\n.. _ReferenialIntegrity:\n\nEnsuring Consistency of Important Objects in PyMuPDF\n------------------------------------------------------------\nPyMuPDF is a Python binding for the C library MuPDF. While a lot of effort has been invested by MuPDF's creators to approximate some sort of an object-oriented behavior, they certainly could not overcome basic shortcomings of the C language in that respect.\n\nPython on the other hand implements the OO-model in a very clean way. The interface code between PyMuPDF and MuPDF consists of two basic files: *pymupdf.py* and *fitz_wrap.c*. They are created by the excellent SWIG tool for each new version.\n\nWhen you use one of PyMuPDF's objects or methods, this will result in execution of some code in *pymupdf.py*, which in turn will call some C code compiled with *fitz_wrap.c*.\n\nBecause SWIG goes a long way to keep the Python and the C level in sync, everything works fine, if a certain set of rules is being strictly followed. For example: **never access** a :ref:`Page` object, after you have closed (or deleted or set to ``None``) the owning :ref:`Document`. Or, less obvious: **never access** a page or any of its children (links or annotations) after you have executed one of the document methods *select()*, *delete_page()*, *insert_page()* ... and more.\n\nBut just no longer accessing invalidated objects is actually not enough: They should rather be actively deleted entirely, to also free C-level resources (meaning allocated memory).\n\nThe reason for these rules lies in the fact that there is a hierarchical 2-level one-to-many relationship between a document and its pages and also between a page and its links / annotations. To maintain a consistent situation, any of the above actions must lead to a complete reset -- in **Python and, synchronously, in C**.\n\nSWIG cannot know about this and consequently does not do it.\n\nThe required logic has therefore been built into PyMuPDF itself in the following way.\n\n1. If a page \"loses\" its owning document or is being deleted itself, all of its currently existing annotations and links will be made unusable in Python, and their C-level counterparts will be deleted and deallocated.\n\n2. If a document is closed (or deleted or set to ``None``) or if its structure has changed, then similarly all currently existing pages and their children will be made unusable, and corresponding C-level deletions will take place. \"Structure changes\" include methods like *select()*, *delePage()*, *insert_page()*, *insert_pdf()* and so on: all of these will result in a cascade of object deletions.\n\nThe programmer will normally not realize any of this. If he, however, tries to access invalidated objects, exceptions will be raised.\n\nInvalidated objects cannot be directly deleted as with Python statements like *del page* or *page = None*, etc. Instead, their *__del__* method must be invoked.\n\nAll pages, links and annotations have the property *parent*, which points to the owning object. This is the property that can be checked on the application level: if *obj.parent == None* then the object's parent is gone, and any reference to its properties or methods will raise an exception informing about this \"orphaned\" state.\n\nA sample session:\n\n>>> page = doc[n]\n>>> annot = page.first_annot\n>>> annot.type                    # everything works fine\n[5, 'Circle']\n>>> page = None                   # this turns 'annot' into an orphan\n>>> annot.type\n<... omitted lines ...>\nRuntimeError: orphaned object: parent is None\n>>>\n>>> # same happens, if you do this:\n>>> annot = doc[n].first_annot     # deletes the page again immediately!\n>>> annot.type                    # so, 'annot' is 'born' orphaned\n<... omitted lines ...>\nRuntimeError: orphaned object: parent is None\n\nThis shows the cascading effect:\n\n>>> doc = pymupdf.open(\"some.pdf\")\n>>> page = doc[n]\n>>> annot = page.first_annot\n>>> page.rect\npymupdf.Rect(0.0, 0.0, 595.0, 842.0)\n>>> annot.type\n[5, 'Circle']\n>>> del doc                       # or doc = None or doc.close()\n>>> page.rect\n<... omitted lines ...>\nRuntimeError: orphaned object: parent is None\n>>> annot.type\n<... omitted lines ...>\nRuntimeError: orphaned object: parent is None\n\n.. note:: Objects outside the above relationship are not included in this mechanism. If you e.g. created a table of contents by *toc = doc.get_toc()*, and later close or change the document, then this cannot and does not change variable *toc* in any way. It is your responsibility to refresh such variables as required.\n\n------------\n\n.. _FormXObject:\n\nDesign of Method :meth:`Page.show_pdf_page`\n--------------------------------------------\n\nPurpose and Capabilities\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe method displays an image of a (\"source\") page of another PDF document within a specified rectangle of the current (\"containing\", \"target\") page.\n\n* **In contrast** to :meth:`Page.insert_image`, this display is vector-based and hence remains accurate across zooming levels.\n* **Just like** :meth:`Page.insert_image`, the size of the display is adjusted to the given rectangle.\n\nThe following variations of the display are currently supported:\n\n* Bool parameter `\"keep_proportion\"` controls whether to maintain the aspect ratio (default) or not.\n    * Rectangle parameter `\"clip\"` restricts the visible part of the source page rectangle. Default is the full page.\n* float `\"rotation\"` rotates the display by an arbitrary angle (degrees). If the angle is not an integer multiple of 90, only 2 of the 4 corners may be positioned on the target border if also `\"keep_proportion\"` is true.\n* Bool parameter `\"overlay\"` controls whether to put the image on top (foreground, default) of current page content or not (background).\n\nUse cases include (but are not limited to) the following:\n\n1. \"Stamp\" a series of pages of the current document with the same image, like a company logo or a watermark.\n2. Combine arbitrary input pages into one output page to support “booklet” or double-sided printing (known as \"4-up\", \"n-up\").\n3. Split up (large) input pages into several arbitrary pieces. This is also called “posterization”, because you e.g. can split an A4 page horizontally and vertically, print the 4 pieces enlarged to separate A4 pages, and end up with an A2 version of your original page.\n\nTechnical Implementation\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis is done using PDF **\"Form XObjects\"**, see section 8.10 on page 217 of :ref:`AdobeManual`. On execution of a :meth:`Page.show_pdf_page`, the following things happen:\n\n    1. The :data:`resources` and :data:`contents` objects of source page in source document are copied over to the target document, jointly creating a new **Form XObject** with the following properties. The PDF :data:`xref` number of this object is returned by the method.\n\n        a. `/BBox` equals `/Mediabox` of the source page\n        b. `/Matrix` equals the identity matrix.\n        c. `/Resources` equals that of the source page. This involves a “deep-copy” of hierarchically nested other objects (including fonts, images, etc.). The complexity involved here is covered by MuPDF's grafting [#f1]_ technique functions.\n        d. This is a stream object type, and its stream is an exact copy of the combined data of the source page's :data:`contents` objects.\n\n        This Form XObject is only executed once per shown source page. Subsequent displays of the same source page will skip this step and only create \"pointer\" Form XObjects (done in next step) to this object.\n\n    2. A second **Form XObject** is then created which the target page uses to invoke the display. This object has the following properties:\n\n        a. `/BBox` equals the `/CropBox` of the source page (or `\"clip\"`).\n        b. `/Matrix` represents the mapping of `/BBox` to the target rectangle.\n        c. `/XObject` references the previous Form XObject via the fixed name `fullpage`.\n        d. The stream of this object contains exactly one fixed statement: `/fullpage Do`.\n        e. If the method's `\"oc\"` argument is given, its value is assigned to this Form XObject as `/OC`.\n\n    3. The :data:`resources` and :data:`contents` objects of the target page are now modified as follows.\n\n        a. Add an entry to the `/XObject` dictionary of `/Resources` with the name `fzFrm<n>` (with n chosen such that this entry is unique on the page).\n        b. Depending on `\"overlay\"`, prepend or append a new object to the page's `/Contents` array, containing the statement `q /fzFrm<n> Do Q`.\n\nThis design approach ensures that:\n\n1. The (potentially large) source page is only copied once to the target PDF. Only small \"pointer\" Form XObjects objects are created per each target page to show the source page.\n2. Each referring target page can have its own `\"oc\"` parameter to control the source page's visibility individually.\n\n\n\n.. _RedirectMessages:\n\nDiagnostics\n----------------------------\n\n.. _Messages:\n\n|PyMuPDF| messages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n|PyMuPDF| has a Message system for showing text diagnostics.\n\nBy default messages are written to `sys.stdout`. This can be controlled in\ntwo ways:\n\n*\n  Set environment variable `PYMUPDF_MESSAGE` before |PyMuPDF| is imported.\n\n*\n  Call `set_messages()`:\n\n\n|MuPDF| errors and warnings\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n|MuPDF| generates text errors and warnings.\n\n*\n  These errors and warnings are appended to an internal list, accessible with\n  `Tools.mupdf_warnings()`. Also see `Tools.reset_mupdf_warnings()`.\n\n*\n  By default these errors and warnings are also sent to the |PyMuPDF| message\n  system.\n  \n  * This can be controlled with `mupdf_display_errors()` and\n    `mupdf_display_warnings()`.\n  \n  *\n    These messages are prefixed with `MuPDF error:` and `MuPDF warning:`\n    respectively.\n  \nSome |MuPDF| errors may lead to Python exceptions.\n\nExample output for a **recoverable error**. We are opening a damaged PDF, but MuPDF is able to repair it and gives us a little information on what happened. Then we illustrate how to find out whether the document can later be saved incrementally. Checking the :attr:`Document.is_dirty` attribute at this point also indicates that during `pymupdf.open` the document had to be repaired:\n\n>>> import pymupdf\n>>> doc = pymupdf.open(\"damaged-file.pdf\")  # leads to a sys.stderr message:\nmupdf: cannot find startxref\n>>> print(pymupdf.TOOLS.mupdf_warnings())  # check if there is more info:\ncannot find startxref\ntrying to repair broken xref\nrepairing PDF document\nobject missing 'endobj' token\n>>> doc.can_save_incrementally()  # this is to be expected:\nFalse\n>>> # the following indicates whether there are updates so far\n>>> # this is the case because of the repair actions:\n>>> doc.is_dirty\nTrue\n>>> # the document has nevertheless been created:\n>>> doc\npymupdf.Document('damaged-file.pdf')\n>>> # we now know that any save must occur to a new file\n\nExample output for an **unrecoverable error**:\n\n>>> import pymupdf\n>>> doc = pymupdf.open(\"does-not-exist.pdf\")\nmupdf: cannot open does-not-exist.pdf: No such file or directory\nTraceback (most recent call last):\n  File \"<pyshell#1>\", line 1, in <module>\n    doc = pymupdf.open(\"does-not-exist.pdf\")\n  File \"C:\\Users\\Jorj\\AppData\\Local\\Programs\\Python\\Python37\\lib\\site-packages\\fitz\\pymupdf.py\", line 2200, in __init__\n    _pymupdf.Document_swiginit(self, _pymupdf.new_Document(filename, stream, filetype, rect, width, height, fontsize))\nRuntimeError: cannot open does-not-exist.pdf: No such file or directory\n>>>\n\n\n\n.. _Coordinates:\n\nCoordinates\n--------------------------------------------\n\n\nThis is one of the most frequently used terms in this documentation. A **coordinate** generally means a pair of numbers `(x, y)` referring to some location, like a corner of a rectangle (:ref:`Rect`), a :ref:`Point` and so forth. The two values usually are floats, but there a objects like images which only allow them to be integers.\n\nTo actually *find* a coordinate's location, we also need to know the *reference* point for ``x`` and ``y`` - in other words, we must know where location `(0, 0)` is positioned. Once `(0, 0)` (the \"origin\") is known, we speak of a \"coordinate system\".\n\nSeveral coordinate systems exist in document processing. For instance, the coordinate systems of a PDF page and the image created from it are **different**. We therefore need ways to *transform* coordinates from one system to another (and also back occasionally). This is the task of a :ref:`Matrix`. It is a mathematical function which works much like a factor that can be \"multiplied\" with a point or rectangle to give us the corresponding point / rectangle in another coordinate system. The inverse of a transformation matrix can be used to revert the transformation. Much like multiplying by some factor, say 3, can be reverted by dividing the result by 3 (or multiplying it with 1/3).\n\nCoordinates and Images\n~~~~~~~~~~~~~~~~~~~~~~~\n\nImages have a coordinate system with integer coordinates. Origin `(0, 0)` is the top-left point. ``x`` values must be in `range(width)`, and ``y`` values in `range(height)`. Therefore, ``y`` values *increase* if we go *downwards*. For every image, there is only a **finite number** of coordinates, namely `width * height`. A location in an image is also called a \"pixel\".\n\n- How **large** an image will be (in centimeters or inches) when e.g. printed, depends on additional information: the \"resolution\". This is measured in **DPI** (dots per inch, or pixels per inch). To find the printed size of some image, we therefore must divide its width and its height by the corresponding DPI values (there may separate ones for width and for height) and will get the respective number of inches.\n\n\nOrigin Point, Point Size and Y-Axis\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIn |PDF|, the origin `(0, 0)` of a page is located at its **bottom-left point**. In |MuPDF|, the origin `(0, 0)` of a page is located at its **top-left point**.\n\n\n.. image:: images/img-coordinate-space.png\n\nCoordinates are float numbers and measured in **points**, where:\n\n- **one point equals 1/72 inches**.\n\nTypical document page sizes are **ISO A4** and **Letter**. A **Letter** page has a size of **8.5 x 11 inches**, corresponding to **612 x 792 points**. In the |PDF| coordinate system, the top-left point of a **Letter** page hence has the coordinate `(0, 792)` as **the y-axis points upwards**. Now we know our document size the |MuPDF| coordinate system for the bottom right would be coordinate `(612, 792)` (and for |PDF| this coordinate would then be `(612,0)`).\n\n- Theoretically, there are **infinitely many** coordinate positions on a |PDF| page. In practice however, at most the first 5 decimal places are sufficient for a reasonable precision.\n\n\n- In |MuPDF|, multiple document formats are supported - |PDF| just being one among **over a dozen others**. Images are also supported as documents in |MuPDF| (therefore having one page usually). This is one of the reasons why |MuPDF| uses a coordinate system with the origin `(0, 0)` being the **top-left** point of any document page. **The y-axis points downwards**, like with images. Coordinates in |MuPDF| in any case are floats, like in |PDF|.\n\n- A rectangle `Rect(0, 0, 100, 100)` for instance in |MuPDF| (and thus |PyMuPDF|) therefore is a square with edges of length 100 points (= 1.39 inches or 3.53 centimeters). Its top-left corner is the origin. To switch between the two coordinate systems |PDF| to |MuPDF|, every :ref:`Page` object has a :attr:`Page.transformation_matrix`. Its inverse can be used to compute a rectangle's PDF coordinates. In this way we can conveniently find that `Rect(0, 0, 100, 100)` in |MuPDF| is the same as `Rect(0, 692, 100, 792)` in |PDF|. See this code snippet::\n\n    >>> page = doc.new_page(width=612, height=792)  # make new Letter page\n    >>> ptm = page.transformation_matrix\n    >>> # the inverse matrix of ptm is ~ptm\n    >>> pymupdf.Rect(0, 0, 100, 100) * ~ptm\n    Rect(0.0, 692.0, 100.0, 792.0)\n\n\n\n.. rubric:: Footnotes\n\n.. [#f1] MuPDF supports \"deep-copying\" objects between PDF documents. To avoid duplicate data in the target, it uses so-called \"graftmaps\", like a form of scratchpad: for each object to be copied, its :data:`xref` number is looked up in the graftmap. If found, copying is skipped. Otherwise, the new :data:`xref` is recorded and the copy takes place. PyMuPDF makes use of this technique in two places so far: :meth:`Document.insert_pdf` and :meth:`Page.show_pdf_page`. This process is fast and very efficient, because it prevents multiple copies of typically large and frequently referenced data, like images and fonts. However, you may still want to consider using garbage collection (option 4) in any of the following cases:\n\n    1. The target PDF is not new / empty: grafting does not check for resources that already existed (e.g. images, fonts) in the target document before opening it.\n    2. Using :meth:`Page.show_pdf_page` for more than one source document: each grafting occurs **within one source** PDF only, not across multiple. So if e.g. the same image exists in pages from different source PDFs, then this will not be detected until garbage collection.\n\n\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/app4.rst",
    "content": ".. include:: header.rst\n\n\n.. role:: red-color\n.. role:: orange-color\n.. role:: green-color\n\n\n\n.. _Appendix4:\n\n================================================\nAppendix 4: Performance Comparison Methodology\n================================================\n\nThis article documents the approach to measure :title:`PyMuPDF's` performance and the tools and example files used to do comparisons.\n\nThe following three sections deal with different performance aspects:\n\n* :ref:`Document Copying<app4_copying>` - This includes opening and parsing :title:`PDFs`, then writing them to an output file. Because the same basic activities are also used for joining (merging) :title:`PDFs`, the results also apply to these use cases.\n* :ref:`Text Extraction<app4_text_extraction>` - This extracts plain text from :title:`PDFs` and writes it to an output text file.\n* :ref:`Page Rendering<app4_page_rendering>` - This converts |PDF| pages to image files looking identical to the pages. This ability is the basic prerequisite for using a tool in :title:`Python GUI` scripts to scroll through documents. We have chosen a medium-quality (resolution 150 DPI) version.\n\nPlease note that in all cases the actual speed in dealing with |PDF| structures is not directly measured: instead, the timings also include the durations of writing files to the operating system's file system. This cannot be avoided because tools other than |PyMuPDF| do not offer the option to e.g., separate the image **creation** step from the following step, which **writes** the image into a file.\n\nSo all timings documented include a common, OS-oriented base effort. Therefore, performance **differences per tool are actually larger** than the numbers suggest.\n\n\n\n.. _Appendix4_Files_Used:\n\nFiles used\n------------\n\nA set of eight files is used for the performance testing. With each file we have the following information:\n\n- **Name** of the file and download **link**.\n- **Size** in bytes.\n- Total number of **pages** in file.\n- Total number of bookmarks (**Table of Contents** entries).\n- Total number of **links**.\n- **KB size** per page.\n- **Textsize per page** is the amount text in the whole file in KB, divided by the number of pages.\n- Any **notes** to generally describe the type of file.\n\n\n.. list-table::\n   :header-rows: 1\n\n   * - **Name**\n     - **Size (bytes)**\n     - **Pages**\n     - **TOC size**\n     - **Links**\n     - **KB/page**\n     - **Textsize/page**\n     - **Notes**\n   * - `adobe.pdf`\n     - 32,472,771\n     - 1,310\n     - 794\n     - 32,096\n     - 24\n     - 1,942\n     - linearized, many links / bookmarks\n   * - `artifex-website.pdf`\n     - 31,570,732\n     - 47\n     - 46\n     - 2,035\n     - 656\n     - 3,538\n     - graphics oriented\n   * - `db-systems.pdf`\n     - 29,326,355\n     - 1,241\n     - 0\n     - 0\n     - 23\n     - 2,142\n     -\n   * - `fontforge.pdf`\n     - 8,222,384\n     - 214\n     - 31\n     - 242\n     - 38\n     - 1,058\n     - mix of text & graphics\n   * - `pandas.pdf`\n     - 10,585,962\n     - 3,071\n     - 536\n     - 16,554\n     - 3\n     - 1,539\n     - many pages\n   * - `pymupdf.pdf`\n     - 6,805,176\n     - 478\n     - 276\n     - 5,277\n     - 14\n     - 1,937\n     - text oriented\n   * - `pythonbook.pdf`\n     - 9,983,856\n     - 669\n     - 198\n     - 1,953\n     - 15\n     - 1,929\n     -\n   * - `sample-50-MB-pdf-file.pdf`\n     - 52,521,850\n     - 1\n     - 0\n     - 0\n     - 51,291\n     - 23,860\n     - single page, graphics oriented, large file size\n\n\n\n.. note::\n\n     **adobe.pdf** and **pymupdf.pdf** are clearly text oriented, **artifex-website.pdf** and **sample-50-MB-pdf-file.pdf** are graphics oriented. Other files are a mix of both.\n\n\nTools used\n-------------\n\nIn each section, the same fixed set of |PDF| files is being processed by a set of tools. The set of tools used per performance aspect however varies, depending on the supported tool features.\n\nAll tools are either platform independent, or at least can run on both, :title:`Windows` and :title:`Unix` / :title:`Linux`.\n\n\n.. list-table::\n   :header-rows: 1\n\n   * - **Tool**\n     - **Description**\n   * - |PyMuPDF|\n     - The tool of this manual.\n   * - PDFrw_\n     - A pure :title:`Python` tool, being used by :title:`rst2pdf`, has interface to :title:`ReportLab`.\n   * - PyPDF2_\n     - A pure :title:`Python` tool with a large function set.\n   * - PDFMiner_\n     - A pure :title:`Python` to extract text and other data from |PDF|.\n   * - XPDF_\n     - A command line utility with multiple functions.\n   * - PikePDF_\n     - A :title:`Python` package similar to :title:`PDFrw`, but based on :title:`C++` library :title:`QPDF`.\n   * - PDF2JPG_\n     - A :title:`Python` package specialized on rendering |PDF| pages to :title:`JPG` images.\n\n\n\n.. _app4_copying:\n\n\nCopying / Joining / Merging\n----------------------------------\n\nHow fast is a |PDF| file read and its content parsed for further processing? The sheer parsing performance cannot directly be compared, because batch utilities always execute a requested task completely, in one go, front to end. :title:`PDFrw` too, has a *lazy* strategy for parsing, meaning it only parses those parts of a document that are required in any moment.\n\nTo find an answer to the question, we therefore measure the time to copy a |PDF| file to an output file with each tool, and do nothing else.\n\nThese are the :title:`Python` commands for how each tool is used:\n\n|PyMuPDF|\n\n.. code-block:: python\n\n    import pymupdf\n    doc = pymupdf.open(\"input.pdf\")\n    doc.save(\"output.pdf\")\n\n:title:`PDFrw`\n\n\n.. code-block:: python\n\n    doc = PdfReader(\"input.pdf\")\n    writer = PdfWriter()\n    writer.trailer = doc\n    writer.write(\"output.pdf\")\n\n:title:`PikePDF`\n\n.. code-block:: python\n\n    from pikepdf import Pdf\n    doc = Pdf.open(\"input.pdf\")\n    doc.save(\"output.pdf\")\n\n:title:`PyPDF2`\n\n.. code-block:: python\n\n    pdfmerge = PyPDF2.PdfMerger()\n    pdfmerge.append(\"input.pdf\")\n    pdfmerge.write(\"output.pdf\")\n    pdfmerge.close()\n\n\n\n\n**Observations**\n\nThese are our run time findings in **seconds** along with a base rate summary compared to |PyMuPDF|:\n\n.. list-table::\n   :header-rows: 1\n\n   * - **Name**\n     - |PyMuPDF|\n     - **PDFrw**\n     - **PikePDF**\n     - **PyPDF2**\n   * - adobe.pdf\n     - 1.75\n     - 5.15\n     - 22.37\n     - 374.05\n   * - artifex-website.pdf\n     - 0.26\n     - 0.38\n     - 1.41\n     - 2.81\n   * - db-systems.pdf\n     - 0.15\n     - 0.8\n     - 1.68\n     - 2.46\n   * - fontforge.pdf\n     - 0.09\n     - 0.14\n     - 0.28\n     - 1.1\n   * - pandas.pdf\n     - 0.38\n     - 2.21\n     - 2.73\n     - 70.3\n   * - pymupdf.pdf\n     - 0.11\n     - 0.56\n     - 0.83\n     - 6.05\n   * - pythonbook.pdf\n     - 0.19\n     - 1.2\n     - 1.34\n     - 37.19\n   * - sample-50-MB-pdf-file.pdf\n     - 0.12\n     - 0.1\n     - 2.93\n     - 0.08\n   * - **Total**\n     - **3.05**\n     - **10.54**\n     - **33.57**\n     - **494.04**\n   * -\n     -\n     -\n     -\n     -\n   * - **Rate compared to PyMuPDF**\n     - :green-color:`1.0`\n     - :orange-color:`3.5`\n     - :orange-color:`11.0`\n     - :red-color:`162`\n\n\n\n.. _app4_text_extraction:\n\nText Extraction\n----------------------------------\n\nThe following table shows plain text extraction durations. All tools have been used with their most basic functionality - i.e. no layout re-arrangements, etc.\n\n\n**Observations**\n\nThese are our run time findings in **seconds** along with a base rate summary compared to |PyMuPDF|:\n\n.. list-table::\n   :header-rows: 1\n\n   * - **Name**\n     - |PyMuPDF|\n     - **XPDF**\n     - **PyPDF2**\n     - **PDFMiner**\n   * - adobe.pdf\n     - 2.01\n     - 6.19\n     - 22.2\n     - 49.15\n   * - artifex-website.pdf\n     - 0.18\n     - 0.3\n     - 1.1\n     - 4.06\n   * - db-systems.pdf\n     - 1.57\n     - 4.26\n     - 25.75\n     - 42.19\n   * - fontforge.pdf\n     - 0.24\n     - 0.47\n     - 2.69\n     - 4.2\n   * - pandas.pdf\n     - 2.41\n     - 10.54\n     - 25.38\n     - 76.56\n   * - pymupdf.pdf\n     - 0.49\n     - 2.34\n     - 6.44\n     - 13.55\n   * - pythonbook.pdf\n     - 0.84\n     - 2.88\n     - 9.28\n     - 24.27\n   * - sample-50-MB-pdf-file.pdf\n     - 0.27\n     - 0.44\n     - 8.8\n     - 13.29\n   * - **Total**\n     - **8.01**\n     - **27.42**\n     - **101.64**\n     - **227.27**\n   * -\n     -\n     -\n     -\n     -\n   * - **Rate compared to PyMuPDF**\n     - :green-color:`1.0`\n     - :orange-color:`3.42`\n     - :orange-color:`12.69`\n     - :red-color:`28.37`\n\n\n.. _app4_page_rendering:\n\nPage Rendering\n--------------------------\n\nWe have tested rendering speed of |PyMuPDF| against :title:`pdf2jpg` and :title:`XPDF` at a resolution of 150 DPI,\n\n\nThese are the :title:`Python` commands for how each tool is used:\n\n\n|PyMuPDF|\n\n.. code-block:: python\n\n    def ProcessFile(datei):\n    print \"processing:\", datei\n    doc=pymupdf.open(datei)\n    for p in pymupdf.Pages(doc):\n        pix = p.get_pixmap(dpi=150)\n        pix.save(f\"t-{p.number}.png\")\n        pix = None\n    doc.close()\n    return\n\n:title:`XPDF`\n\n.. code-block:: python\n\n    pdftopng.exe -r 150 file.pdf ./\n\n\n:title:`PDF2JPG`\n\n.. code-block:: python\n\n    def ProcessFile(datei):\n        print(\"processing:\", datei)\n        pdf2jpg.convert_pdf2jpg(datei, \"images\", pages=\"ALL\", dpi=150)\n        return\n\n\n**Observations**\n\nThese are our run time findings in **seconds** along with a base rate summary compared to |PyMuPDF|:\n\n\n.. list-table::\n   :header-rows: 1\n\n   * - **Name**\n     - |PyMuPDF|\n     - **XPDF**\n     - **PDF2JPG**\n   * - adobe.pdf\n     - 51.33\n     - 98.16\n     - 75.71\n   * - artifex-website.pdf\n     - 26.35\n     - 51.28\n     - 54.11\n   * - db-systems.pdf\n     - 84.59\n     - 143.16\n     - 405.22\n   * - fontforge.pdf\n     - 12.23\n     - 22.18\n     - 20.14\n   * - pandas.pdf\n     - 138.74\n     - 241.67\n     - 202.06\n   * - pymupdf.pdf\n     - 22.35\n     - 39.11\n     - 33.38\n   * - pythonbook.pdf\n     - 30.44\n     - 49.12\n     - 55.68\n   * - sample-50-MB-pdf-file.pdf\n     - 1.01\n     - 1.32\n     - 5.22\n   * - **Total**\n     - **367.04**\n     - **646**\n     - **851.52**\n   * -\n     -\n     -\n     -\n   * - **Rate compared to PyMuPDF**\n     - :green-color:`1.0`\n     - :orange-color:`1.76`\n     - :red-color:`2.32`\n\n\n.. include:: footer.rst\n\n\n.. External links\n\n.. _PDFrw : https://pypi.org/project/pdfrw/\n.. _PyPDF2 : https://pypi.org/project/pypdf/\n.. _PDFMiner : https://pypi.org/project/pdfminer.six/\n.. _PDFtk : https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/\n.. _XPDF : https://www.xpdfreader.com/\n.. _PikePDF : https://pypi.org/search/?q=pikepdf\n.. _PDF2JPG : https://pypi.org/project/pdf2jpg/\n\n.. _adobe.pdf : https://artifex.com/samples/pdf/adobe.pdf\n.. _artifex-website.pdf : https://artifex.com/samples/pdf/artifex-website.pdf\n.. _db-systems.pdf : https://artifex.com/samples/pdf/db-systems.pdf\n.. _fontforge.pdf : https://artifex.com/samples/pdf/fontforge.pdf\n.. _pandas.pdf : https://artifex.com/samples/pdf/pandas.pdf\n.. _pymupdf.pdf : https://artifex.com/samples/pdf/pymupdf.pdf\n.. _pythonbook.pdf : https://artifex.com/samples/pdf/pythonbook.pdf\n.. _sample-50-MB-pdf-file.pdf : https://artifex.com/samples/pdf/sample-50-MB-pdf-file.pdf\n"
  },
  {
    "path": "docs/archive-class.rst",
    "content": ".. include:: header.rst\n\n.. _Archive:\n\n================\nArchive\n================\n\n* New in v1.21.0\n\nThis class represents a generalization of file folders and container files like ZIP and TAR archives. Archives allow accessing arbitrary collections of file folders, ZIP / TAR files and single binary data elements as if they all were part of one hierarchical tree of folders.\n\nIn PyMuPDF, archives are currently only used by :ref:`Story` objects to specify where to look for fonts, images and other resources.\n\n================================ ===================================================\n**Method / Attribute**           **Short Description**\n================================ ===================================================\n:meth:`Archive.add`              add new data to the archive\n:meth:`Archive.has_entry`        check if given name is a member\n:meth:`Archive.read_entry`       read the data given by the name\n:attr:`Archive.entry_list`       list[dict] of archive items\n================================ ===================================================\n\n**Class API**\n\n.. class:: Archive\n\n   .. method:: __init__(self [, content [, path]])\n\n      Creates a new archive. Without parameters, an empty archive is created.\n\n      If provided, `content` may be one of the following:\n\n      * another Archive: the archive is being made a sub-archive of the new one.\n\n      * a string: this must be the name of a local folder or file. `pathlib.Path` objects are also supported.\n\n         - A **folder** will be converted to a sub-archive, so its files (and any sub-folders) can be accessed by their names.\n         - A **file** will be read with mode `\"rb\"` and these binary data (a `bytes` object) be treated as a single-member sub-archive. In this case, the `path` parameter is **mandatory** and should be the member name under which this item can be found / retrieved.\n\n      * a `zipfile.ZipFile` or `tarfile.TarFile` object: Will be added as a sub-archive.\n\n      * a Python binary object (`bytes`, `bytearray`, `io.BytesIO`): this will add a single-member sub-archive. In this case, the `path` parameter is **mandatory** and should be the member name under which this item can be found / retrieved.\n\n      * a tuple `(data, name)`: This will add a single-member sub-archive with the member name ``name``. ``data`` may be a Python binary object or a local file name (in which case its binary file content is used). Use this format if you need to specify `path`.\n\n      * a Python sequence: This is a convenience format to specify any combination of the above.\n\n      If provided, `path` must be a string.\n      \n      * If `content` is either binary data or a file name, this parameter is mandatory and must be the name under which the data can be found.\n\n      * Otherwise this parameter is optional. It can be used to simulate a folder name or a mount point, under which this sub-archive's elements can be found. For example this specification `Archive((data, \"name\"), \"path\")` means that `data` will be found using the element name `\"path/name\"`. Similar is true for other sub-archives: to retrieve members of a ZIP sub-archive, their names must be prefixed with `\"path/\"`. The main purpose of this parameter probably is to differentiate between duplicate names.\n\n      .. note:: If duplicate entry names exist in the archive, always the last entry with that name will be found / retrieved. During archive creation, or appending more data to an archive (see :meth:`Archive.add`) no check for duplicates will be made. Use the `path` parameter to prevent this from happening.\n\n   .. method:: add(content [,path])\n\n      Append a sub-archive. The meaning of the parameters are exactly the same as explained above. Of course, parameter `content` is not optional here.\n\n   .. method:: has_entry(name)\n\n      Checks whether an entry exists in any of the sub-archives.\n\n      :arg str name: The fully qualified name of the entry. So must include any `path` prefix under which the entry's sub-archive has been added.\n\n      :returns: `True` or `False`.\n\n   .. method:: read_entry(name)\n\n      Retrieve the data of an entry.\n\n      :arg str name: The fully qualified name of the entry. So must include any `path` prefix under which the entry's sub-archive has been added.\n\n      :returns: The binary data (`bytes`) of the entry. If not found, an exception is raised.\n\n   .. attribute:: entry_list\n\n      A list of the archive's sub-archives. Each list item is a dictionary with the following keys:\n\n      * `entries` -- a list of (top-level) entry names in this sub-archive.\n      * `fmt` -- the format of the sub-archive. This is one of the strings \"dir\" (file folder), \"zip\" (ZIP archive), \"tar\" (TAR archive), or \"tree\" for single binary entries or file content.\n      * `path` -- the value of the `path` parameter under which this sub-archive was added.\n\n      **Example:**\n\n      >>> from pprint import pprint\n      >>> import pymupdf\n      >>> dir1 = \"fitz-32\"  # a folder name\n      >>> dir2 = \"fitz-64\"  # a folder name\n      >>> img = (\"nur-ruhig.jpg\", \"img\")  # an image file\n      >>> members = (dir1, img, dir2)  # we want to append these in one go\n      >>> arch = pymupdf.Archive()\n      >>> arch.add(members, path=\"mypath\")\n      >>> pprint(arch.entry_list)\n      [{'entries': ['310', '37', '38', '39'], 'fmt': 'dir', 'path': 'mypath'},\n      {'entries': ['img'], 'fmt': 'tree', 'path': 'mypath'},\n      {'entries': ['310', '311', '37', '38', '39', 'pypy'],\n      'fmt': 'dir',\n      'path': 'mypath'}]\n      >>> \n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/changes.rst",
    "content": ".. include:: header.rst\n\n.. include:: ../changes.txt\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/classes.rst",
    "content": ".. include:: header.rst\n\n============\nClasses\n============\n\n.. toctree::\n   :maxdepth: 2\n\n   annot.rst\n   archive-class.rst\n   colorspace.rst\n   displaylist.rst\n   document.rst\n   document-writer-class.rst\n   font.rst\n   identity.rst\n   irect.rst\n   link.rst\n   linkdest.rst\n   matrix.rst\n   outline.rst\n   page.rst\n   pixmap.rst\n   point.rst\n   quad.rst\n   rect.rst\n   shape.rst\n   story-class.rst\n   textpage.rst\n   textwriter.rst\n   tools.rst\n   widget.rst\n   xml-class.rst\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/colors.rst",
    "content": ".. include:: header.rst\n\n.. _ColorDatabase:\n\n================\nColor Database\n================\nSince the introduction of methods involving colors (like :meth:`Page.draw_circle`), a requirement may be to have access to predefined colors.\n\nThe fabulous GUI package `wxPython <https://wxpython.org/>`_ has a database of over 540 predefined RGB colors, which are given more or less memorizable names. Among them are not only standard names like \"green\" or \"blue\", but also \"turquoise\", \"skyblue\", and 100 (not only 50 ...) shades of \"gray\", etc.\n\nWe have taken the liberty to copy this database (a list of tuples) modified into PyMuPDF and make its colors available as PDF compatible float triples: for wxPython's *(\"WHITE\", 255, 255, 255)* we return *(1, 1, 1)*, which can be directly used in *color* and *fill* parameters. We also accept any mixed case of \"wHiTe\" to find a color.\n\nFunction *getColor()*\n------------------------\nAs the color database may not be needed very often, one additional import statement seems acceptable to get access to it::\n\n    >>> # \"getColor\" is the only method you really need\n    >>> from pymupdf.utils import getColor\n    >>> getColor(\"aliceblue\")\n    (0.9411764705882353, 0.9725490196078431, 1.0)\n    >>> #\n    >>> # to get a list of all existing names\n    >>> from pymupdf.utils import getColorList\n    >>> cl = getColorList()\n    >>> cl\n    ['ALICEBLUE', 'ANTIQUEWHITE', 'ANTIQUEWHITE1', 'ANTIQUEWHITE2', 'ANTIQUEWHITE3',\n    'ANTIQUEWHITE4', 'AQUAMARINE', 'AQUAMARINE1'] ...\n    >>> #\n    >>> # to see the full integer color coding\n    >>> from pymupdf.utils import getColorInfoList\n    >>> il = getColorInfoList()\n    >>> il\n    [('ALICEBLUE', 240, 248, 255), ('ANTIQUEWHITE', 250, 235, 215),\n    ('ANTIQUEWHITE1', 255, 239, 219), ('ANTIQUEWHITE2', 238, 223, 204),\n    ('ANTIQUEWHITE3', 205, 192, 176), ('ANTIQUEWHITE4', 139, 131, 120),\n    ('AQUAMARINE', 127, 255, 212), ('AQUAMARINE1', 127, 255, 212)] ...\n\n\nPrinting the Color Database\n----------------------------\nIf you want to actually see how the many available colors look like, use scripts `print by RGB <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/print-rgb/print.py>`_ or `print by HSV <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/print-hsv/print.py>`_ in the examples directory. They create PDFs (already existing in the same directory) with all these colors. Their only difference is sorting order: one takes the RGB values, the other one the Hue-Saturation-Values as sort criteria.\nThis is a screen print of what these files look like.\n\n.. image:: images/img-colordb.*\n\n.. include:: footer.rst"
  },
  {
    "path": "docs/colorspace.rst",
    "content": ".. include:: header.rst\n\n.. _Colorspace:\n\n================\nColorspace\n================\n\nRepresents the color space of a :ref:`Pixmap`.\n\n\n**Class API**\n\n.. class:: Colorspace\n\n   .. method:: __init__(self, n)\n\n      Constructor\n\n      :arg int n: A number identifying the colorspace. Possible values are :data:`CS_RGB`, :data:`CS_GRAY` and :data:`CS_CMYK`.\n\n   .. attribute:: name\n\n      The name identifying the colorspace. Example: *pymupdf.csCMYK.name = 'DeviceCMYK'*.\n\n      :type: str\n\n   .. attribute:: n\n\n      The number of bytes required to define the color of one pixel. Example: *pymupdf.csCMYK.n == 4*.\n\n      :type: int\n\n\n    **Predefined Colorspaces**\n\n    For saving some typing effort, there exist predefined colorspace objects for the three available cases.\n\n    * :data:`csRGB`  = *pymupdf.Colorspace(pymupdf.CS_RGB)*\n    * :data:`csGRAY` = *pymupdf.Colorspace(pymupdf.CS_GRAY)*\n    * :data:`csCMYK` = *pymupdf.Colorspace(pymupdf.CS_CMYK)*\n\n.. include:: footer.rst"
  },
  {
    "path": "docs/conf.py",
    "content": "# -*- coding: utf-8 -*-\n#\nimport re\nimport sys\nimport os\nimport datetime\n\n# If extensions (or modules to document with autodoc) are in another directory,\n# add these directories to sys.path here. If the directory is relative to the\n# documentation root, use os.path.abspath to make it absolute, like shown here.\nsys.path.insert(0, os.path.abspath(\".\"))\n\n# -- General configuration ------------------------------------------------\n\n# If your documentation needs a minimal Sphinx version, state it here.\n# needs_sphinx = \"4.2.0\"\n\n# Add any Sphinx extension module names here, as strings. They can be\n# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom\n# ones.\n# extensions = [\"sphinx.ext.autodoc\", \"sphinx.ext.coverage\", \"sphinx.ext.ifconfig\"]\nextensions = ['sphinx_copybutton','notfound.extension','sphinxcontrib.googleanalytics']\n# rst2pdf is not available on OpenBSD.\nif hasattr(os, \"uname\") and os.uname()[0] != \"OpenBSD\":\n    extensions.append(\"rst2pdf.pdfbuilder\")\n\n# Add any paths that contain templates here, relative to this directory.\ntemplates_path = [\"_templates\"]\n\n# The suffix of source filenames.\nsource_suffix = \".rst\"\n\n# from: pip install sphinxcontrib-googleanalytics\ngoogleanalytics_id = \"G-JZTN4VTL9M\"\n\n# The encoding of source files.\n# source_encoding = 'utf-8-sig'\n\n# The master toctree document.\nroot_doc = \"index\"\n\nrst_epilog = ''\n\n# General information about the project.\nproject = \"PyMuPDF\"\nthisday = datetime.date.today()\ncopyright = \"2015-\" + str(thisday.year) + \", Artifex\"\n\n# The version info for the project you're documenting, acts as replacement for\n# |version| and |release|, also used in various other places throughout the\n# built documents.\n#\n# The full version, including alpha/beta/rc tags.\n\nif 1:\n    # Importing setup.py requires pipcl etc so instead of importing, we grep\n    # for the version info in setup.py and scripts/test.py.\n    setup_py_path = os.path.normpath(f'{__file__}/../../setup.py')\n    with open(setup_py_path) as f:\n        setup_py_text = f.read()\n    regex = \"\\nversion_p = '([0-9.]+)'\\n\"\n    m = re.search(regex, setup_py_text)\n    assert m, f'Cannot find version number in {setup_py_path!r} with {regex=}.'\n    version = m.group(1)\n    \n    test_py_path = os.path.normpath(f'{__file__}/../../scripts/test.py')\n    with open(test_py_path) as f:\n        test_py_text = f.read()\n    regex = '\\npython_versions_minor = (.+)\\n'\n    m = re.search(regex, test_py_text)\n    assert m, f'Cannot find python_versions_minor in {test_py_path!r} with {regex=}.'\n    python_versions_minor = m.group(1)\n    python_versions_minor = eval(m.group(1))\nelse:\n    # PyMuPDF version is set in setup.py, so we import it here.\n    sys.path.insert(0, os.path.abspath(f'{__file__}/../..'))\n    try:\n        import setup\n    finally:\n        del sys.path[0]\n    version = setup.version_p\n    del setup   # Necessary otherwise sphinx seems to do `setup()`.\n\n    # Supported Python versions are set in scripts.test.py.\n    sys.path.insert(0, os.path.abspath(f'{__file__}/../../scripts'))\n    try:\n        import test\n    finally:\n        del sys.path[0]\n    python_versions_minor = test.python_versions_minor\n    del test\npython_versions_list = [f'3.{i}' for i in python_versions_minor]\npython_versions = ', '.join(python_versions_list[:-1]) + f' and {python_versions_list[-1]}'\n# Make `|python_versions|` available in .rst files.\nrst_epilog += f'.. |python_versions| replace:: {python_versions}\\n'\n\n# The language for content autogenerated by Sphinx. Refer to documentation\n# for a list of supported languages.\n# language = None\n\n# There are two options for replacing |today|: either, you set today to some\n# non-false value, then it is used:\n# today = ''\n# Else, today_fmt is used as the format for a strftime call.\n# today_fmt = '%B %d, %Y'\n\n# List of patterns, relative to source directory, that match files and\n# directories to ignore when looking for source files.\nexclude_patterns = [\"_build\", \"build\"]\n\n# The reST default role (used for this markup: `text`) to use for all\n# documents.\ndefault_role = \"any\"\n\n# If true, '()' will be appended to :func: etc. cross-reference text.\nadd_function_parentheses = True\n\n# If true, the current module name will be prepended to all description\n# unit titles (such as .. function::).\nadd_module_names = True\n\n# If true, sectionauthor and moduleauthor directives will be shown in the\n# output. They are ignored by default.\nshow_authors = False\n\n# The name of the Pygments (syntax highlighting) style to use.\npygments_style = \"sphinx\"\n\n# A list of ignored prefixes for module index sorting.\nmodindex_common_prefix = []\n\n# If true, keep warnings as \"system message\" paragraphs in the built documents.\nkeep_warnings = False\n\n# Localization vars\n\ngettext_uuid = True\n\ngettext_compact = False\n\nlocale_dirs = [\"locales\"]\n\n\n\n# -- Options for HTML output ----------------------------------------------\n\n# The theme to use for HTML and HTML Help pages.  See the documentation for\n# a list of builtin themes.\nhtml_theme = \"furo\"\n\n# Theme options are theme-specific and customize the look and feel of a theme\n# further.  For a list of options available for each theme, see the\n# documentation.\nhtml_theme_options = {\n    \"canonical_url\": \"\",\n    \"logo_only\": False,\n    \"display_version\": True,\n    \"prev_next_buttons_location\": None,\n    # Toc options\n    \"collapse_navigation\": True,\n    \"sticky_navigation\": True,\n    \"navigation_depth\": 4,\n    \"includehidden\": True,\n    \"titles_only\": False,\n}\n\n# Add any paths that contain custom themes here, relative to this directory.\n# html_theme_path = []\n# html_theme_path = [sphinx_rtd_theme.get_html_theme_path()]\n\n# The name for this set of Sphinx documents.  If None, it defaults to\n# \"<project> v<release> documentation\".\n# html_title = None\n\n# A shorter title for the navigation bar.  Default is the same as html_title.\n# html_short_title = None\n\n# The name of an image file (relative to this directory) to place at the top\n# of the sidebar.\n\n\n# The name of an image file (within the static path) to use as favicon of the\n# docs.  This file should be a Windows icon file (.ico) being 16x16 or 32x32\n# pixels large.\nhtml_favicon = \"_static/PyMuPDF.ico\"\n\n# Add any paths that contain custom static files (such as style sheets) here,\n# relative to this directory. They are copied after the builtin static files,\n# so a file named \"default.css\" will overwrite the builtin \"default.css\".\nhtml_static_path = [\"_static\"]\nhtml_theme_options = {\n    \"light_logo\": \"sidebar-logo-dark.svg\",\n    \"dark_logo\": \"sidebar-logo-light.svg\",\n}\n\n# A list of CSS files. The entry must be a filename string or a tuple containing\n# the filename string and the attributes dictionary. The filename must be\n# relative to the html_static_path, or a full URI\nhtml_css_files = [\"custom.css\"]\n\n# Add any extra paths that contain custom files (such as robots.txt or\n# .htaccess) here, relative to this directory. These files are copied\n# directly to the root of the documentation.\n# html_extra_path = []\n\n# If not '', a 'Last updated on:' timestamp is inserted at every page bottom,\n# using the given strftime format.\nhtml_last_updated_fmt = \"%d. %b %Y\"\n\n# If true, SmartyPants will be used to convert quotes and dashes to\n# typographically correct entities.\n# html_use_smartypants = False\n\n# Custom sidebar templates, maps document names to template names.\n# html_sidebars = {}\n\n# Additional templates that should be rendered to pages, maps page names to\n# template names.\nhtml_additional_pages = {}\n\n# If false, no module index is generated.\nhtml_domain_indices = True\n\n# If false, no index is generated.\nhtml_use_index = True\n\n# If true, the index is split into individual pages for each letter.\nhtml_split_index = True\n\n# If true, links to the reST sources are added to the pages.\nhtml_show_sourcelink = True\nhtml_sourcelink_suffix = \".rst\"\n# If true, \"Created using Sphinx\" is shown in the HTML footer. Default is True.\nhtml_show_sphinx = False\n\n# If true, \"(C) Copyright ...\" is shown in the HTML footer. Default is True.\nhtml_show_copyright = True\n\n# If true, an OpenSearch description file will be output, and all pages will\n# contain a <link> tag referring to it.  The value of this option must be the\n# base URL from which the finished HTML is served.\nhtml_use_opensearch = \"\"\n\n# This is the file name suffix for HTML files (e.g. \".xhtml\").\nhtml_file_suffix = None\n\n# Output file base name for HTML help builder.\nhtmlhelp_basename = \"PyMuPDF\"\n\n\n# -- Options for LaTeX output ---------------------------------------------\nlatex_elements = {\n    # \"fontpkg\": r\"\\usepackage[sfdefault]{ClearSans} \\usepackage[T1]{fontenc}\"\n}\n# Grouping the document tree into LaTeX files. List of tuples\n# (source start file, target name, title,\n#  author, documentclass [howto, manual, or own class]).\nlatex_documents = [(\"index\", \"PyMuPDF.tex\", \"PyMuPDF Documentation\", \"Artifex\", \"manual\")]\n# The name of an image file (relative to this directory) to place at the top of\n# the title page.\nlatex_logo = \"images/pymupdf-logo.png\"\n\n# For \"manual\" documents, if this is true, then toplevel headings are parts,\n# not chapters.\n# latex_use_parts = False\n\n# If true, show page references after internal links.\nlatex_show_pagerefs = False\n\n# If true, show URL addresses after external links.\n# latex_show_urls = True\n# latex_use_xindy = True\n# Documents to append as an appendix to all manuals.\n# latex_appendices = []\n\n# If false, no module index is generated.\nlatex_domain_indices = True\n\n# -- Options for PDF output --------------------------------------------------\n# Grouping the document tree into PDF files. List of tuples\n# (source start file, target name, title, author).\n\npdf_documents = [(\"index\", \"PyMuPDF\", \"PyMuPDF Manual\", \"Artifex\")]\n\n# A comma-separated list of custom stylesheets. Example:\n# pdf_stylesheets = [\"sphinx\", \"bahnschrift\", \"a4\"]\n\n# Create a compressed PDF\npdf_compressed = True\n\n# A colon-separated list of folders to search for fonts. Example:\n# pdf_font_path=['/usr/share/fonts', '/usr/share/texmf-dist/fonts/']\n\n# Language to be used for hyphenation support\npdf_language = \"en_US\"\n\n# If false, no index is generated.\npdf_use_index = True\n\n# If false, no modindex is generated.\npdf_use_modindex = True\n\n# If false, no coverpage is generated.\npdf_use_coverpage = True\n\npdf_break_level = 2\n\npdf_verbosity = 0\npdf_invariant = True\n"
  },
  {
    "path": "docs/converting-files.rst",
    "content": ".. include:: header.rst\n\n.. _ConvertingFiles:\n\n==============================\nConverting Files\n==============================\n\n\n\nFiles to PDF\n~~~~~~~~~~~~~~~~~~\n\n:ref:`Document types supported by PyMuPDF<HowToOpenAFile>` can easily be converted to |PDF| by using the :meth:`Document.convert_to_pdf` method. This method returns a buffer of data which can then be utilized by |PyMuPDF| to create a new |PDF|.\n\n\n\n**Example**\n\n.. code-block:: python\n\n    import pymupdf\n\n    xps = pymupdf.open(\"input.xps\")\n    pdfbytes = xps.convert_to_pdf()\n    pdf = pymupdf.open(\"pdf\", pdfbytes)\n    pdf.save(\"output.pdf\")\n\n\n\nPDF to SVG\n~~~~~~~~~~~~~~~~~~\n\nTechnically, as SVG files cannot be multipage, we must export each page as an SVG.\n\nTo get an SVG representation of a page use the :meth:`Page.get_svg_image` method.\n\n**Example**\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"input.pdf\")\n    page = doc[0]\n\n    # Convert page to SVG\n    svg_content = page.get_svg_image()\n\n    # Save to file\n    with open(\"output.svg\", \"w\", encoding=\"utf-8\") as f:\n        f.write(svg_content)\n\n    doc.close()\n\n\nPDF to Markdown\n~~~~~~~~~~~~~~~~~\n\nBy utlilizing the :doc:`PyMuPDF4LLM API <pymupdf4llm/api>` we are able to convert PDF to a Markdown representation.\n\n**Example**\n\n.. code-block:: python\n\n    import pymupdf4llm\n    import pathlib\n\n    md_text = pymupdf4llm.to_markdown(\"test.pdf\")\n    print(md_text)\n\n    pathlib.Path(\"4llm-output.md\").write_bytes(md_text.encode())\n\n\nPDF to DOCX\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nUse the pdf2docx_ library which uses |PyMuPDF| to provide document conversion from |PDF| to **DOCX** format.\n\n\n\n**Example**\n\n.. code-block:: python\n\n    from pdf2docx import Converter\n\n    pdf_file = 'input.pdf'\n    docx_file = 'output.docx'\n\n    # convert pdf to docx\n    cv = Converter(pdf_file)\n    cv.convert(docx_file) # all pages by default\n    cv.close()\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/coop_low.rst",
    "content": ".. include:: header.rst\n\n.. _cooperation:\n\n===============================================================\nWorking together: DisplayList and TextPage\n===============================================================\nHere are some instructions on how to use these classes together.\n\nIn some situations, performance improvements may be achievable, when you fall back to the detail level explained here.\n\nCreate a DisplayList\n---------------------\nA :ref:`DisplayList` represents an interpreted document page. Methods for pixmap creation, text extraction and text search are  -- behind the curtain -- all using the page's display list to perform their tasks. If a page must be rendered several times (e.g. because of changed zoom levels), or if text search and text extraction should both be performed, overhead can be saved, if the display list is created only once and then used for all other tasks.\n\n>>> dl = page.get_displaylist()              # create the display list\n\nYou can also create display lists for many pages \"on stack\" (in a list), may be during document open, during idling times, or you store it when a page is visited for the first time (e.g. in GUI scripts).\n\nNote, that for everything what follows, only the display list is needed -- the corresponding :ref:`Page` object could have been deleted.\n\nGenerate Pixmap\n------------------\nThe following creates a Pixmap from a :ref:`DisplayList`. Parameters are the same as for :meth:`Page.get_pixmap`.\n\n>>> pix = dl.get_pixmap()                    # create the page's pixmap\n\nThe execution time of this statement may be up to 50% shorter than that of :meth:`Page.get_pixmap`.\n\nPerform Text Search\n---------------------\nWith the display list from above, we can also search for text.\n\nFor this we need to create a :ref:`TextPage`.\n\n>>> tp = dl.get_textpage()                    # display list from above\n>>> rlist = tp.search(\"needle\")              # look up \"needle\" locations\n>>> for r in rlist:                          # work with the found locations, e.g.\n        pix.invert_irect(r.irect)             # invert colors in the rectangles\n\nExtract Text\n----------------\nWith the same :ref:`TextPage` object from above, we can now immediately use any or all of the 5 text extraction methods.\n\n.. note:: Above, we have created our text page without argument. This leads to a default argument of 3 (:data:`ligatures` and white-space are preserved), IAW images will **not** be extracted -- see below.\n\n>>> txt  = tp.extractText()                  # plain text format\n>>> json = tp.extractJSON()                  # json format\n>>> html = tp.extractHTML()                  # HTML format\n>>> xml  = tp.extractXML()                   # XML format\n>>> xml  = tp.extractXHTML()                 # XHTML format\n\nFurther Performance improvements\n---------------------------------\nPixmap\n~~~~~~~\nAs explained in the :ref:`Page` chapter:\n\nIf you do not need transparency set *alpha = 0* when creating pixmaps. This will save 25% memory (if RGB, the most common case) and possibly 5% execution time (depending on the GUI software).\n\nTextPage\n~~~~~~~~~\nIf you do not need images extracted alongside the text of a page, you can set the following option:\n\n>>> flags = pymupdf.TEXT_PRESERVE_LIGATURES | pymupdf.TEXT_PRESERVE_WHITESPACE\n>>> tp = dl.get_textpage(flags)\n\nThis will save ca. 25% overall execution time for the HTML, XHTML and JSON text extractions and **hugely** reduce the amount of storage (both, memory and disk space) if the document is graphics oriented.\n\nIf you however do need images, use a value of 7 for flags:\n\n>>> flags = pymupdf.TEXT_PRESERVE_LIGATURES | pymupdf.TEXT_PRESERVE_WHITESPACE | pymupdf.TEXT_PRESERVE_IMAGES\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/device.rst",
    "content": ".. include:: header.rst\n\n.. _Device:\n\n================\nDevice\n================\n\nThe different format handlers (pdf, xps, etc.) interpret pages to a \"device\". Devices are the basis for everything that can be done with a page: rendering, text extraction and searching. The device type is determined by the selected construction method.\n\n**Class API**\n\n.. class:: Device\n\n   .. method:: __init__(self, object, clip)\n\n      Constructor for either a pixel map or a display list device.\n\n      :arg object: either a ``Pixmap`` or  a ``DisplayList``.\n      :type object: :ref:`Pixmap` or :ref:`DisplayList`\n\n      :arg clip: An optional `IRect` for ``Pixmap`` devices to restrict rendering to a certain area of the page. If the complete page is required, specify ``None``. For display list devices, this parameter must be omitted.\n      :type clip: :ref:`IRect`\n\n   .. method:: __init__(self, textpage, flags=0)\n\n      Constructor for a text page device.\n\n      :arg textpage: ``TextPage`` object\n      :type textpage: :ref:`TextPage`\n\n      :arg int flags: control the way how text is parsed into the text page. Currently 3 options can be coded into this parameter, see :ref:`TextPreserve`. To set these options use something like `flags=0 | TEXT_PRESERVE_LIGATURES | ...`.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/displaylist.rst",
    "content": ".. include:: header.rst\n\n.. _DisplayList:\n\n================\nDisplayList\n================\n\nDisplayList is a list containing drawing commands (text, images, etc.). The intent is two-fold:\n\n1. as a caching-mechanism to reduce parsing of a page\n2. as a data structure in multi-threading setups, where one thread parses the page and another one renders pages. This aspect is currently not supported by PyMuPDF.\n\nA display list is populated with objects from a page, usually by executing :meth:`Page.get_displaylist`. There also exists an independent constructor.\n\n\"Replay\" the list (once or many times) by invoking one of its methods :meth:`~DisplayList.run`, :meth:`~DisplayList.get_pixmap` or :meth:`~DisplayList.get_textpage`.\n\n\n================================= ============================================\n**Method**                        **Short Description**\n================================= ============================================\n:meth:`~DisplayList.run`          Run a display list through a device.\n:meth:`~DisplayList.get_pixmap`   generate a pixmap\n:meth:`~DisplayList.get_textpage` generate a text page\n:attr:`~DisplayList.rect`         mediabox of the display list\n================================= ============================================\n\n\n**Class API**\n\n.. class:: DisplayList\n\n   .. method:: __init__(self, mediabox)\n\n      Create a new display list.\n\n      :arg mediabox: The page's rectangle.\n      :type mediabox: :ref:`Rect`\n\n      :rtype: ``DisplayList``\n\n   .. method:: run(device, matrix, area)\n    \n      Run the display list through a device. The device will populate the display list with its \"commands\" (i.e. text extraction or image creation). The display list can later be used to \"read\" a page many times without having to re-interpret it from the document file.\n\n      You will most probably instead use one of the specialized run methods below -- :meth:`get_pixmap` or :meth:`get_textpage`.\n\n      :arg device: Device\n      :type device: :ref:`Device`\n\n      :arg matrix: Transformation matrix to apply to the display list contents.\n      :type matrix: :ref:`Matrix`\n\n      :arg area: Only the part visible within this area will be considered when the list is run through the device.\n      :type area: :ref:`Rect`\n\n   .. index::\n      pair: matrix; DisplayList.get_pixmap\n      pair: colorspace; DisplayList.get_pixmap\n      pair: clip; DisplayList.get_pixmap\n      pair: alpha; DisplayList.get_pixmap\n\n   .. method:: get_pixmap(matrix=pymupdf.Identity, colorspace=pymupdf.csRGB, alpha=0, clip=None)\n\n      Run the display list through a draw device and return a pixmap.\n\n      :arg matrix: matrix to use. Default is the identity matrix.\n      :type matrix: :ref:`Matrix`\n\n      :arg colorspace: the desired colorspace. Default is RGB.\n      :type colorspace: :ref:`Colorspace`\n\n      :arg int alpha: determine whether or not (0, default) to include a transparency channel.\n\n      :arg irect_like clip: restrict rendering to the intersection of this area with :attr:`DisplayList.rect`.\n\n      :rtype: :ref:`Pixmap`\n      :returns: pixmap of the display list.\n\n   .. method:: get_textpage(flags)\n\n      Run the display list through a text device and return a text page.\n\n      :arg int flags: control which information is parsed into a text page. Default value in PyMuPDF is `3 = TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE`, i.e. :data:`ligatures` are **passed through**, white spaces are **passed through** (not translated to spaces), and images are **not included**. See :ref:`TextPreserve`.\n\n      :rtype: :ref:`TextPage`\n      :returns: text page of the display list.\n\n   .. attribute:: rect\n\n      Contains the display list's mediabox. This will equal the page's rectangle if it was created via :meth:`Page.get_displaylist`.\n\n      :type: :ref:`Rect`\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/document-writer-class.rst",
    "content": ".. include:: header.rst\n\n.. _DocumentWriter:\n\n================\nDocumentWriter\n================\n\n|pdf_only_class|\n\n\n* New in v1.21.0\n\nThis class represents a utility which can output various :ref:`document types supported by PyMuPDF<Supported_File_Types>`.\n\nIn |PyMuPDF| only used for outputting PDF documents whose pages are populated by :ref:`Story` DOMs.\n\nUsing DocumentWriter_ also for other document types might happen in the future.\n\n================================= ===================================================\n**Method / Attribute**            **Short Description**\n================================= ===================================================\n:meth:`DocumentWriter.begin_page` start a new output page\n:meth:`DocumentWriter.end_page`   finish the current output page\n:meth:`DocumentWriter.close`      flush pending output and close the file\n================================= ===================================================\n\n**Class API**\n\n.. class:: DocumentWriter\n\n   .. method:: __init__(self, path, options=None)\n\n      Create a document writer object, passing a Python file pointer or a file path. Options to use when saving the file may also be passed.\n\n      This class can also be used as a Python context manager.\n\n      :arg path: the output file. This may be a string file name, or any Python file pointer.\n      \n         .. note:: By using a `io.BytesIO()` object as file pointer, a document writer can create a PDF in memory. Subsequently, this PDF can be re-opened for input and be further manipulated. This technique is used by several example scripts in :ref:`Stories recipes<RecipesStories>`.\n\n      :arg str options: specify saving options for the output PDF. Typical are \"compress\" or \"clean\". More possible values may be taken from help output of the `mutool convert` CLI utility.\n\n   .. method:: begin_page(mediabox)\n\n      Start a new output page of a given dimension.\n\n      :arg rect_like mediabox: a rectangle specifying the page size. After this method, output operations may write content to the page.\n\n   .. method:: end_page()\n\n      Finish a page. This flushes any pending data and appends the page to the output document.\n\n   .. method:: close()\n\n      Close the output file. This method is required for writing any pending data.\n\n   For usage examples consult the section of :ref:`Story`.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/document.rst",
    "content": ".. include:: header.rst\n\n.. _Document:\n\n================\nDocument\n================\n\n.. highlight:: python\n\nThis class represents a document. It can be constructed from a file or from memory.\n\nThere exists the alias *open* for this class, i.e. `pymupdf.Document(...)` and `pymupdf.open(...)` do exactly the same thing.\n\nFor details on **embedded files** refer to Appendix 3.\n\n.. note::\n\n  Starting with v1.17.0, a new page addressing mechanism for **EPUB files only** is supported. This document type is internally organized in chapters such that pages can most efficiently be found by their so-called \"location\". The location is a tuple *(chapter, pno)* consisting of the chapter number and the page number **in that chapter**. Both numbers are zero-based.\n\n  While it is still possible to locate a page via its (absolute) number, doing so may mean that the complete EPUB document must be laid out before the page can be addressed. This may have a significant performance impact if the document is very large. Using the page's *(chapter, pno)* prevents this from happening.\n\n  To maintain a consistent API, PyMuPDF supports the page *location* syntax for **all file types** -- documents without this feature simply have just one chapter. :meth:`Document.load_page` and the equivalent index access now also support a *location* argument.\n\n  There are a number of methods for converting between page numbers and locations, for determining the chapter count, the page count per chapter, for computing the next and the previous locations, and the last page location of a document.\n\n======================================= ==========================================================\n**Method / Attribute**                  **Short Description**\n======================================= ==========================================================\n:meth:`Document.add_layer`              PDF only: make new optional content configuration\n:meth:`Document.add_ocg`                PDF only: add new optional content group\n:meth:`Document.authenticate`           gain access to an encrypted document\n:meth:`Document.bake`                   PDF only: make annotations / fields permanent content\n:meth:`Document.can_save_incrementally` check if incremental save is possible\n:meth:`Document.chapter_page_count`     number of pages in chapter\n:meth:`Document.close`                  close the document\n:meth:`Document.convert_to_pdf`         write a PDF version to memory\n:meth:`Document.copy_page`              PDF only: copy a page reference\n:meth:`Document.del_toc_item`           PDF only: remove a single TOC item\n:meth:`Document.delete_page`            PDF only: delete a page\n:meth:`Document.delete_pages`           PDF only: delete multiple pages\n:meth:`Document.embfile_add`            PDF only: add a new embedded file from buffer\n:meth:`Document.embfile_count`          PDF only: number of embedded files\n:meth:`Document.embfile_del`            PDF only: delete an embedded file entry\n:meth:`Document.embfile_get`            PDF only: extract an embedded file buffer\n:meth:`Document.embfile_info`           PDF only: metadata of an embedded file\n:meth:`Document.embfile_names`          PDF only: list of embedded files\n:meth:`Document.embfile_upd`            PDF only: change an embedded file\n:meth:`Document.extract_font`           PDF only: extract a font by :data:`xref`\n:meth:`Document.extract_image`          PDF only: extract an embedded image by :data:`xref`\n:meth:`Document.ez_save`                PDF only: :meth:`Document.save` with different defaults\n:meth:`Document.find_bookmark`          retrieve page location after laid out document\n:meth:`Document.fullcopy_page`          PDF only: duplicate a page\n:meth:`Document.get_layer`              PDF only: lists of OCGs in ON, OFF, RBGroups\n:meth:`Document.get_layers`             PDF only: list of optional content configurations\n:meth:`Document.get_oc`                 PDF only: get OCG /OCMD xref of image / form xobject\n:meth:`Document.get_ocgs`               PDF only: info on all optional content groups\n:meth:`Document.get_ocmd`               PDF only: retrieve definition of an :data:`OCMD`\n:meth:`Document.get_page_fonts`         PDF only: list of fonts referenced by a page\n:meth:`Document.get_page_images`        PDF only: list of images referenced by a page\n:meth:`Document.get_page_labels`        PDF only: list of page label definitions\n:meth:`Document.get_page_numbers`       PDF only: get page numbers having a given label\n:meth:`Document.get_page_pixmap`        create a pixmap of a page by page number\n:meth:`Document.get_page_text`          extract the text of a page by page number\n:meth:`Document.get_page_xobjects`      PDF only: list of XObjects referenced by a page\n:meth:`Document.get_sigflags`           PDF only: determine signature state\n:meth:`Document.get_toc`                extract the table of contents\n:meth:`Document.get_xml_metadata`       PDF only: read the XML metadata\n:meth:`Document.has_annots`             PDF only: check if PDF contains any annots\n:meth:`Document.has_links`              PDF only: check if PDF contains any links\n:meth:`Document.insert_page`            PDF only: insert a new page\n:meth:`Document.insert_pdf`             PDF only: insert pages from another PDF\n:meth:`Document.insert_file`            PDF only: insert pages from arbitrary document\n:meth:`Document.journal_can_do`         PDF only: which journal actions are possible\n:meth:`Document.journal_enable`         PDF only: enables journalling for the document\n:meth:`Document.journal_load`           PDF only: load journal from a file\n:meth:`Document.journal_op_name`        PDF only: return name of a journalling step\n:meth:`Document.journal_position`       PDF only: return journalling status\n:meth:`Document.journal_redo`           PDF only: redo current operation\n:meth:`Document.journal_save`           PDF only: save journal to a file\n:meth:`Document.journal_start_op`       PDF only: start an \"operation\" giving it a name\n:meth:`Document.journal_stop_op`        PDF only: end current operation\n:meth:`Document.journal_undo`           PDF only: undo current operation\n:meth:`Document.layer_ui_configs`       PDF only: list of optional content intents\n:meth:`Document.layout`                 re-paginate the document (if supported)\n:meth:`Document.load_page`              read a page\n:meth:`Document.make_bookmark`          create a page pointer in reflowable documents\n:meth:`Document.move_page`              PDF only: move a page to different location in doc\n:meth:`Document.need_appearances`       PDF only: get/set `/NeedAppearances` property\n:meth:`Document.new_page`               PDF only: insert a new empty page\n:meth:`Document.next_location`          return (chapter, pno) of following page\n:meth:`Document.outline_xref`           PDF only: :data:`xref` a TOC item\n:meth:`Document.page_cropbox`           PDF only: the unrotated page rectangle\n:meth:`Document.page_xref`              PDF only: :data:`xref` of a page number\n:meth:`Document.pages`                  iterator over a page range\n:meth:`Document.pdf_catalog`            PDF only: :data:`xref` of catalog (root)\n:meth:`Document.pdf_trailer`            PDF only: trailer source\n:meth:`Document.prev_location`          return (chapter, pno) of preceding page\n:meth:`Document.rewrite_images`         PDF only: rewrite / extra compression for images\n:meth:`Document.recolor`                PDF only: execute :meth:`Page.recolor` for all pages\n:meth:`Document.reload_page`            PDF only: provide a new copy of a page\n:meth:`Document.resolve_names`          PDF only: Convert destination names into a Python dict\n:meth:`Document.save`                   PDF only: save the document\n:meth:`Document.saveIncr`               PDF only: save the document incrementally\n:meth:`Document.scrub`                  PDF only: remove sensitive data\n:meth:`Document.search_page_for`        search for a string on a page\n:meth:`Document.select`                 PDF only: select a subset of pages\n:meth:`Document.set_layer_ui_config`    PDF only: set OCG visibility temporarily\n:meth:`Document.set_layer`              PDF only: mass changing OCG states\n:meth:`Document.set_markinfo`           PDF only: set the MarkInfo values\n:meth:`Document.set_metadata`           PDF only: set the metadata\n:meth:`Document.set_oc`                 PDF only: attach OCG/OCMD to image / form xobject\n:meth:`Document.set_ocmd`               PDF only: create or update an :data:`OCMD`\n:meth:`Document.set_page_labels`        PDF only: add/update page label definitions\n:meth:`Document.set_pagemode`           PDF only: set the PageMode\n:meth:`Document.set_pagelayout`         PDF only: set the PageLayout\n:meth:`Document.set_toc_item`           PDF only: change a single TOC item\n:meth:`Document.set_toc`                PDF only: set the table of contents (TOC)\n:meth:`Document.set_xml_metadata`       PDF only: create or update document XML metadata\n:meth:`Document.subset_fonts`           PDF only: create font subsets\n:meth:`Document.switch_layer`           PDF only: activate OC configuration\n:meth:`Document.tobytes`                PDF only: writes document to memory\n:meth:`Document.xref_copy`              PDF only: copy a PDF dictionary to another :data:`xref`\n:meth:`Document.xref_get_key`           PDF only: get the value of a dictionary key\n:meth:`Document.xref_get_keys`          PDF only: list the keys of object at :data:`xref`\n:meth:`Document.xref_object`            PDF only: get the definition source of :data:`xref`\n:meth:`Document.xref_set_key`           PDF only: set the value of a dictionary key\n:meth:`Document.xref_stream_raw`        PDF only: raw stream source at :data:`xref`\n:meth:`Document.xref_xml_metadata`      PDF only: :data:`xref` of XML metadata\n:attr:`Document.chapter_count`          number of chapters\n:attr:`Document.FormFonts`              PDF only: list of global widget fonts\n:attr:`Document.is_closed`              has document been closed?\n:attr:`Document.is_dirty`               PDF only: has document been changed yet?\n:attr:`Document.is_encrypted`           document (still) encrypted?\n:attr:`Document.is_fast_webaccess`      is PDF linearized?\n:attr:`Document.is_form_pdf`            is this a Form PDF?\n:attr:`Document.is_pdf`                 is this a PDF?\n:attr:`Document.is_reflowable`          is this a reflowable document?\n:attr:`Document.is_repaired`            PDF only: has this PDF been repaired during open?\n:attr:`Document.last_location`          (chapter, pno) of last page\n:attr:`Document.metadata`               metadata\n:attr:`Document.markinfo`               PDF MarkInfo value\n:attr:`Document.name`                   filename of document\n:attr:`Document.needs_pass`             require password to access data?\n:attr:`Document.outline`                first `Outline` item\n:attr:`Document.page_count`             number of pages\n:attr:`Document.permissions`            permissions to access the document\n:attr:`Document.pagemode`               PDF PageMode value\n:attr:`Document.pagelayout`             PDF PageLayout value\n:attr:`Document.version_count`          PDF count of versions\n======================================= ==========================================================\n\n**Class API**\n\n.. class:: Document\n\n  .. index::\n    pair: filename; open\n    pair: stream; open\n    pair: filetype; open\n    pair: rect; open\n    pair: width; open\n    pair: height; open\n    pair: fontsize; open\n    pair: open; Document\n    pair: filename; Document\n    pair: stream; Document\n    pair: filetype; Document\n    pair: rect; Document\n    pair: fontsize; Document\n\n  .. method:: __init__(self, filename=None, stream=None, *, filetype=None, rect=None, width=0, height=0, fontsize=11)\n\n    Create a ``Document`` object.\n\n    * With default parameters, a **new empty PDF** document will be created.\n    * If ``stream`` is given, then the document is created from memory.\n    * If ``stream`` is `None`, then a document is created from the file given by ``filename``. \n\n    :arg str,pathlib filename: A UTF-8 string or ``pathlib.Path`` object containing a file path. The document type is always determined from the file content.  The ``filetype`` parameter is ignored, except when content inspection was unsuccessful. This is regularly the case for plain text types like \"txt\", \"html\", \"xml\" etc. with a wrong or missing file extension.\n\n    :arg bytes,bytearray,BytesIO stream: A memory area containing file data. The document type is always detected from the data content. The ``filetype`` parameter is ignored, except when content inspection was unsuccessful. This is regularly the case for plain text types like \"txt\", \"html\", \"xml\" etc.\n\n    :arg str filetype: A string specifying the type of document. This is only ever needed when file content inspection fails. Text types like \"txt\", \"html\", \"xml\" etc. cannot be disambiguated by their content. When such files are provided in memory or being provided with the wrong file extension, this parameter **must** be used.\n\n    :arg rect_like rect: a rectangle specifying the desired page size. This parameter is only meaningful for documents with a variable page layout (\"reflowable\" documents), like e-books or HTML, and ignored otherwise. If specified, it must be a non-empty, finite rectangle with top-left coordinates (0, 0). Together with parameter :data:`fontsize`, each page will be accordingly laid out and hence also determine the number of pages.\n\n    :arg float width: may used together with ``height`` as an alternative to ``rect`` to specify layout information.\n\n    :arg float height: may used together with ``width`` as an alternative to ``rect`` to specify layout information.\n\n    :arg float fontsize: the default :data:`fontsize` for reflowable document types. This parameter is ignored if none of the parameters ``rect`` or ``width`` and ``height`` are specified. Will be used to calculate the page layout.\n\n    :raises TypeError: if the *type* of any parameter does not conform.\n    :raises FileNotFoundError: if the file / path cannot be found. Re-implemented as subclass of `RuntimeError`.\n    :raises EmptyFileError: if the file / path is empty or the `bytes` object in memory has zero length. A subclass of `FileDataError` and `RuntimeError`.\n    :raises ValueError: if an unknown file type is explicitly specified.\n    :raises FileDataError: if the document has an invalid structure for the given type -- or is no file at all (but e.g. a folder). A subclass of `RuntimeError`.\n\n    :return: A document object. If the document cannot be created, an exception is raised in the above sequence. Note that PyMuPDF-specific exceptions, `FileNotFoundError`, `EmptyFileError` and `FileDataError` are intercepted if you check for `RuntimeError`.\n\n      In case of problems you can see more detail in the internal messages store: `print(pymupdf.TOOLS.mupdf_warnings())` (which will be emptied by this call, but you can also prevent this -- consult :meth:`Tools.mupdf_warnings`).\n\n    Overview of possible forms, note: `open` is a synonym of `Document`::\n\n        >>> # from a file\n        >>> doc = pymupdf.open(\"some.xps\")\n        >>> # handle wrong extension\n        >>> doc = pymupdf.open(\"some.file\", filetype=\"xps\")  # assert expected type\n        >>> doc = pymupdf.open(\"some.file\", filetype=\"txt\")  # treat as plain text\n        >>>\n        >>> # from memory\n        >>> doc = pymupdf.open(stream=mem_area)  # works for any supported type\n        >>> doc = pymupdf.open(stream=unknown-type, filetype=\"txt\")  # treat as plain text\n        >>>\n        >>> # new empty PDF\n        >>> doc = pymupdf.open()\n        >>> doc = pymupdf.open(None)\n        >>> doc = pymupdf.open(\"\")\n\n    .. note:: Raster images with a wrong (but supported) file extension **are no problem**. MuPDF will determine the correct image type when file **content** is actually accessed and will process it without complaint.\n\n    The Document class can be also be used as a **context manager**. Exiting the content manager will close the document automatically.\n\n        >>> import pymupdf\n        >>> with pymupdf.open(...) as doc:\n                for page in doc: print(f\"page {page.number}\")\n        page 0\n        page 1\n        page 2\n        page 3\n        >>> doc.is_closed\n        True\n        >>>\n\n\n  .. method:: get_oc(xref)\n\n    * New in v1.18.4\n\n    Return the cross reference number of an :data:`OCG` or :data:`OCMD` attached to an image or form xobject.\n\n    :arg int xref: the :data:`xref` of an image or form xobject. Valid such cross reference numbers are returned by :meth:`Document.get_page_images`, resp. :meth:`Document.get_page_xobjects`. For invalid numbers, an exception is raised.\n    :rtype: int\n    :returns: the cross reference number of an optional contents object or zero if there is none.\n\n  .. method:: set_oc(xref, ocxref)\n\n    * New in v1.18.4\n\n    If :data:`xref` represents an image or form xobject, set or remove the cross reference number *ocxref* of an optional contents object.\n\n    :arg int xref: the :data:`xref` of an image or form xobject [#f5]_. Valid such cross reference numbers are returned by :meth:`Document.get_page_images`, resp. :meth:`Document.get_page_xobjects`. For invalid numbers, an exception is raised.\n    :arg int ocxref: the :data:`xref` number of an :data:`OCG` / :data:`OCMD`. If not zero, an invalid reference raises an exception. If zero, any OC reference is removed.\n\n\n  .. method:: get_layers()\n\n    * New in v1.18.3\n\n    Show optional layer configurations. There always is a standard one, which is not included in the response.\n\n      >>> for item in doc.get_layers(): print(item)\n      {'number': 0, 'name': 'my-config', 'creator': ''}\n      >>> # use 'number' as config identifier in add_ocg\n\n  .. method:: add_layer(name, creator=None, on=None)\n\n    * New in v1.18.3\n\n    Add an optional content configuration. Layers serve as a collection of ON / OFF states for optional content groups and allow fast visibility switches between different views on the same document.\n\n    :arg str name: arbitrary name.\n    :arg str creator: (optional) creating software.\n    :arg sequ on: a sequence of OCG :data:`xref` numbers which should be set to ON when this layer gets activated. All OCGs not listed here will be set to OFF.\n\n\n  .. method:: switch_layer(number, as_default=False)\n\n    * New in v1.18.3\n\n    Switch to a document view as defined by the optional layer's configuration number. This is temporary, except if established as default.\n\n    :arg int number: config number as returned by :meth:`Document.layer_configs`.\n    :arg bool as_default: make this the default configuration.\n\n    Activates the ON / OFF states of OCGs as defined in the identified layer. If ``as_default=True``, then additionally all layers, including the standard one, are merged and the result is written back to the standard layer, and **all optional layers are deleted**.\n\n\n  .. method:: add_ocg(name, config=-1, on=True, intent=\"View\", usage=\"Artwork\")\n\n    * New in v1.18.3\n\n    Add an optional content group. An OCG is the most important unit of information to determine object visibility. For a PDF, in order to be regarded as having optional content, at least one OCG must exist.\n\n    :arg str name: arbitrary name. Will show up in supporting PDF viewers.\n    :arg int config: layer configuration number. Default -1 is the standard configuration.\n    :arg bool on: standard visibility status for objects pointing to this OCG.\n    :arg str,list intent: a string or list of strings declaring the visibility intents. There are two PDF standard values to choose from: \"View\" and \"Design\". Default is \"View\". Correct **spelling is important**.\n    :arg str usage: another influencer for OCG visibility. This will become part of the OCG's `/Usage` key. There are two PDF standard values to choose from: \"Artwork\" and \"Technical\". Default is \"Artwork\". Please only change when required.\n\n    :returns: :data:`xref` of the created OCG. Use as entry for `oc` parameter in supporting objects.\n\n    .. note:: Multiple OCGs with identical parameters may be created. This will not cause problems. Garbage option 3 of :meth:`Document.save` will get rid of any duplicates.\n\n\n  .. method:: set_ocmd(xref=0, ocgs=None, policy=\"AnyOn\", ve=None)\n\n    * New in v1.18.4\n\n    Create or update an :data:`OCMD`, **Optional Content Membership Dictionary.**\n\n    :arg int xref: :data:`xref` of the OCMD to be updated, or 0 for a new OCMD.\n    :arg list ocgs: a sequence of :data:`xref` numbers of existing :data:`OCG` PDF objects.\n    :arg str policy: one of \"AnyOn\" (default), \"AnyOff\", \"AllOn\", \"AllOff\" (mixed or lower case).\n    :arg list ve: a \"visibility expression\". This is a list of arbitrarily nested other lists -- see explanation below. Use as an alternative to the combination *ocgs* / *policy* if you need to formulate more complex conditions.\n    :rtype: int\n    :returns: :data:`xref` of the OCMD. Use as `oc=xref` parameter in supporting objects, and respectively in :meth:`Document.set_oc` or :meth:`Annot.set_oc`.\n\n    .. note::\n\n      Like an OCG, an OCMD has a visibility state ON or OFF, and it can be used like an OCG. In contrast to an OCG, the OCMD state is determined by evaluating the state of one or more OCGs via special forms of **boolean expressions.** If the expression evaluates to true, the OCMD state is ON and OFF for false.\n\n      There are two ways to formulate OCMD visibility:\n\n      1. Use the combination of *ocgs* and *policy*: The *policy* value is interpreted as follows:\n\n        - AnyOn -- (default) true if at least one OCG is ON.\n        - AnyOff -- true if at least one OCG is OFF.\n        - AllOn -- true if all OCGs are ON.\n        - AllOff -- true if all OCGs are OFF.\n\n        Suppose you want two PDF objects be displayed exactly one at a time (if one is ON, then the other one must be OFF):\n\n        Solution: use an **OCG** for object 1 and an **OCMD** for object 2. Create the OCMD via `set_ocmd(ocgs=[xref], policy=\"AllOff\")`, with the :data:`xref` of the OCG.\n\n      2. Use the **visibility expression** *ve*: This is a list of two or more items. The **first item** is a logical keyword: one of the strings **\"and\"**, **\"or\"**, or **\"not\"**. The **second** and all subsequent items must either be an integer or another list. An integer must be the :data:`xref` number of an OCG. A list must again have at least two items starting with one of the boolean keywords. This syntax is a bit awkward, but quite powerful:\n\n        - Each list must start with a logical keyword.\n        - If the keyword is a **\"not\"**, then the list must have exactly two items. If it is **\"and\"** or **\"or\"**, any number of other items may follow.\n        - Items following the logical keyword may be either integers or again a list. An *integer* must be the xref of an OCG. A *list* must conform to the previous rules.\n\n        **Examples:**\n\n        - `set_ocmd(ve=[\"or\", 4, [\"not\", 5], [\"and\", 6, 7]])`. This delivers ON if the following is true: **\"4 is ON, or 5 is OFF, or 6 and 7 are both ON\"**.\n        - `set_ocmd(ve=[\"not\", xref])`. This has the same effect as the OCMD example created under 1.\n\n        For more details and examples see page 224 of :ref:`AdobeManual`. Also do have a look at example scripts `here <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/optional-content>`_.\n\n        Visibility expressions, `/VE`, are part of PDF specification version 1.6. So not all PDF viewers / readers may already support this feature and hence will react in some standard way for those cases.\n\n\n  .. method:: get_ocmd(xref)\n\n    * New in v1.18.4\n\n    Retrieve the definition of an :data:`OCMD`.\n\n    :arg int xref: the :data:`xref` of the OCMD.\n    :rtype: dict\n    :returns: a dictionary with the keys :data:`xref`, *ocgs*, *policy* and *ve*.\n\n\n  .. method:: get_layer(config=-1)\n\n    * New in v1.18.3\n\n    List of optional content groups by status in the specified configuration. This is a dictionary with lists of cross reference numbers for OCGs that occur in the arrays `/ON`, `/OFF` or in some radio button group (`/RBGroups`).\n\n    :arg int config: the configuration layer (default is the standard config layer).\n\n    >>> pprint(doc.get_layer())\n    {'off': [8, 9, 10], 'on': [5, 6, 7], 'rbgroups': [[7, 10]]}\n    >>>\n\n  .. method:: set_layer(config, *, on=None, off=None, basestate=None, rbgroups=None, locked=None)\n\n    * New in v1.18.3\n\n    * Changed in v1.22.5: Support list of *locked* OCGs.\n\n    Mass status changes of optional content groups. **Permanently** sets the status of OCGs.\n\n    :arg int config: desired configuration layer, choose -1 for the default one.\n    :arg list on: list of :data:`xref` of OCGs to set ON. Replaces previous values. An empty list will cause no OCG being set to ON anymore. Should be specified if `basestate=\"ON\"` is used.\n    :arg list off: list of :data:`xref` of OCGs to set OFF. Replaces previous values. An empty list will cause no OCG being set to OFF anymore. Should be specified if `basestate=\"OFF\"` is used.\n    :arg str basestate: state of OCGs that are not mentioned in *on* or *off*. Possible values are \"ON\", \"OFF\" or \"Unchanged\". Upper / lower case possible.\n    :arg list rbgroups: a list of lists. Replaces previous values. Each sublist should contain two or more OCG xrefs. OCGs in the same sublist are handled like buttons in a radio button group: setting one to ON automatically sets all other group members to OFF.\n    :arg list locked: a list of OCG xref number that cannot be changed by the user interface.\n\n    Values `None` will not change the corresponding PDF array.\n\n      >>> doc.set_layer(-1, basestate=\"OFF\")  # only changes the base state\n      >>> pprint(doc.get_layer())\n      {'basestate': 'OFF', 'off': [8, 9, 10], 'on': [5, 6, 7], 'rbgroups': [[7, 10]]}\n\n\n  .. method:: get_ocgs()\n\n    * New in v1.18.3\n\n    Details of all optional content groups. This is a dictionary of dictionaries like this (key is the OCG's :data:`xref`):\n\n      >>> pprint(doc.get_ocgs())\n      {13: {'on': True,\n            'intent': ['View', 'Design'],\n            'name': 'Circle',\n            'usage': 'Artwork'},\n      14: {'on': True,\n            'intent': ['View', 'Design'],\n            'name': 'Square',\n            'usage': 'Artwork'},\n      15: {'on': False, 'intent': ['View'], 'name': 'Square', 'usage': 'Artwork'}}\n      >>>\n\n  .. method:: layer_ui_configs()\n\n    * New in v1.18.3\n\n    Show the visibility status of optional content that is modifiable by the user interface of supporting PDF viewers.\n\n        * Only reports items contained in the currently selected layer configuration.\n\n        * The meaning of the dictionary keys is as follows:\n           - *depth:* item's nesting level in the `/Order` array\n           - *locked:* true if cannot be changed via user interfaces\n           - *number:* running sequence number\n           - *on:* item state\n           - *text:* text string or name field of the originating OCG\n           - *type:* one of \"label\" (set by a text string), \"checkbox\" (set by a single OCG) or \"radiobox\" (set by a set of connected OCGs)\n\n  .. method:: set_layer_ui_config(number, action=0)\n\n    * New in v1.18.3\n\n    Modify OC visibility status of content groups. This is analog to what supporting PDF viewers would offer.\n\n      Please note that visibility is **not** a property stored with the OCG. It is not even information necessarily present in the PDF document at all. Instead, the current visibility is **temporarily** set using the user interface of some supporting PDF consumer software. The same type of functionality is offered by this method.\n\n      To make **permanent** changes, use :meth:`Document.set_layer`.\n\n    :arg int,str number: either the sequence number of the item in list :meth:`Document.layer_configs` or the \"text\" of one of these items.\n    :arg int action: `PDF_OC_ON` = set on (default), `PDF_OC_TOGGLE` = toggle on/off, `PDF_OC_OFF` = set off.\n\n\n  .. method:: authenticate(password)\n\n    Decrypts the document with the string *password*. If successful, document data can be accessed. For PDF documents, the \"owner\" and the \"user\" have different privileges, and hence different passwords may exist for these authorization levels. The method will automatically establish the appropriate (owner or user) access rights for the provided password.\n\n    :arg str password: owner or user password.\n\n    :rtype: int\n    :returns: a positive value if successful, zero otherwise (the string does not match either password). If positive, the indicator :attr:`Document.is_encrypted` is set to ``False``. **Positive** return codes carry the following information detail:\n\n      * 1 => authenticated, but the PDF has neither owner nor user passwords.\n      * 2 => authenticated with the **user** password.\n      * 4 => authenticated with the **owner** password.\n      * 6 => authenticated and both passwords are equal -- probably a rare situation.\n\n      .. note::\n\n        The document may be protected by an owner, but **not** by a user password. Detect this situation via `doc.authenticate(\"\") == 2`. This allows opening and reading the document without authentication, but, depending on the :attr:`Document.permissions` value, other actions may be prohibited. PyMuPDF (like MuPDF) in this case **ignores those restrictions**. So, -- in contrast to any PDF viewers -- you can for example extract text and add or modify content, even if the respective permission flags `PDF_PERM_COPY`, `PDF_PERM_MODIFY`, `PDF_PERM_ANNOTATE`, etc. are set off! It is your responsibility building a legally compliant application where applicable.\n\n  .. method:: get_page_numbers(label, only_one=False)\n\n     * New in v 1.18.6\n\n     PDF only: Return a list of page numbers that have the specified label -- note that labels may not be unique in a PDF. This implies a sequential search through **all page numbers** to compare their labels.\n\n     .. note:: Implementation detail -- pages are **not loaded** for this purpose.\n\n     :arg str label: the label to look for, e.g. \"vii\" (Roman number 7).\n     :arg bool only_one: stop after first hit. Useful e.g. if labelling is known to be unique, or there are many pages, etc. The default will check every page number.\n     :rtype: list\n     :returns: list of page numbers that have this label. Empty if none found, no labels defined, etc.\n\n\n  .. method:: get_page_labels()\n\n     * New in v1.18.7\n\n     PDF only: Extract the list of page label definitions. Typically used for modifications before feeding it into :meth:`Document.set_page_labels`.\n\n     :returns: a list of dictionaries as defined in :meth:`Document.set_page_labels`.\n\n  .. method:: set_page_labels(labels)\n\n     * New in v1.18.6\n\n     PDF only: Add or update the page label definitions of the PDF.\n\n     :arg list labels: a list of dictionaries. Each dictionary defines a label building rule and a 0-based \"start\" page number. That start page is the first for which the label definition is valid. Each dictionary has up to 4 items and looks like `{'startpage': int, 'prefix': str, 'style': str, 'firstpagenum': int}` and has the following items.\n\n        - `startpage`: (int) the first page number (0-based) to apply the label rule. This key **must be present**. The rule is applied to all subsequent pages until either end of document or superseded by the rule with the next larger page number.\n        - `prefix`: (str) an arbitrary string to start the label with, e.g. \"A-\". Default is \"\".\n        - `style`: (str) the numbering style. Available are \"D\" (decimal), \"r\"/\"R\" (Roman numbers, lower / upper case), and \"a\"/\"A\" (lower / upper case alphabetical numbering: \"a\" through \"z\", then \"aa\" through \"zz\", etc.). Default is \"\". If \"\", no numbering will take place and the pages in that range will receive the same label consisting of the `prefix` value. If prefix is also omitted, then the label will be \"\".\n        - `firstpagenum`: (int) start numbering with this value. Default is 1, smaller values are ignored.\n\n     For example::\n\n      [{'startpage': 6, 'prefix': 'A-', 'style': 'D', 'firstpagenum': 10},\n       {'startpage': 10, 'prefix': '', 'style': 'D', 'firstpagenum': 1}]\n\n     will generate the labels \"A-10\", \"A-11\", \"A-12\", \"A-13\", \"1\", \"2\", \"3\", ... for pages 6, 7 and so on until end of document. Pages 0 through 5 will have the label \"\".\n\n\n  .. method:: make_bookmark(loc)\n\n    * New in v.1.17.3\n\n    Return a page pointer in a reflowable document. After re-layouting the document, the result of this method can be used to find the new location of the page.\n\n    .. note:: Do not confuse with items of a table of contents, TOC.\n\n    :arg list,tuple loc: page location. Must be a valid *(chapter, pno)*.\n\n    :rtype: pointer\n    :returns: a long integer in pointer format. To be used for finding the new location of the page after re-layouting the document. Do not touch or re-assign.\n\n\n  .. method:: find_bookmark(bookmark)\n\n    * New in v.1.17.3\n\n    Return the new page location after re-layouting the document.\n\n    :arg pointer bookmark: created by :meth:`Document.make_bookmark`.\n\n    :rtype: tuple\n    :returns: the new (chapter, pno) of the page.\n\n\n  .. method:: chapter_page_count(chapter)\n\n    * New in v.1.17.0\n\n    Return the number of pages of a chapter.\n\n    :arg int chapter: the 0-based chapter number.\n\n    :rtype: int\n    :returns: number of pages in chapter. Relevant only for document types with chapter support (EPUB currently).\n\n\n  .. method:: next_location(page_id)\n\n    * New in v.1.17.0\n\n    Return the location of the following page.\n\n    :arg tuple page_id: the current page id. This must be a tuple *(chapter, pno)* identifying an existing page.\n\n    :returns: The tuple of the following page, i.e. either *(chapter, pno + 1)* or *(chapter + 1, 0)*, **or** the empty tuple *()* if the argument was the last page. Relevant only for document types with chapter support (EPUB currently).\n\n\n  .. method:: prev_location(page_id)\n\n    * New in v.1.17.0\n\n    Return the locator of the preceding page.\n\n    :arg tuple page_id: the current page id. This must be a tuple *(chapter, pno)* identifying an existing page.\n\n    :returns: The tuple of the preceding page, i.e. either *(chapter, pno - 1)* or the last page of the preceding chapter, **or** the empty tuple *()* if the argument was the first page. Relevant only for document types with chapter support (EPUB currently).\n\n\n  .. method:: load_page(page_id=0)\n\n    * Changed in v1.17.0: For document types supporting a so-called \"chapter structure\" (like EPUB), pages can also be loaded via the combination of chapter number and relative page number, instead of the absolute page number. This should **significantly speed up access** for large documents.\n\n    Create a :ref:`Page` object for further processing (like rendering, text searching, etc.).\n\n    :arg int,tuple page_id: *(Changed in v1.17.0)*\n\n        Either a 0-based page number, or a tuple *(chapter, pno)*. For an **integer**, any `-∞ < page_id < page_count` is acceptable. While page_id is negative, :attr:`page_count` will be added to it. For example: to load the last page, you can use *doc.load_page(-1)*. After this you have page.number = doc.page_count - 1.\n\n        For a tuple, *chapter* must be in range :attr:`Document.chapter_count`, and *pno* must be in range :meth:`Document.chapter_page_count` of that chapter. Both values are 0-based. Using this notation, :attr:`Page.number` will equal the given tuple. Relevant only for document types with chapter support (EPUB currently).\n\n    :rtype: :ref:`Page`\n\n  .. note::\n\n     Documents also follow the Python sequence protocol with page numbers as indices: *doc.load_page(n) == doc[n]*.\n\n     For **absolute page numbers** only, expressions like *\"for page in doc: ...\"* and *\"for page in reversed(doc): ...\"* will successively yield the document's pages. Refer to :meth:`Document.pages` which allows processing pages as with slicing.\n\n     You can also use index notation with the new chapter-based page identification: use *page = doc[(5, 2)]* to load the third page of the sixth chapter.\n\n     To maintain a consistent API, for document types not supporting a chapter structure (like PDFs), :attr:`Document.chapter_count` is 1, and pages can also be loaded via tuples *(0, pno)*. See this [#f3]_ footnote for comments on performance improvements.\n\n\n  .. method:: rewrite_images(dpi_threshold=None, dpi_target=0, quality=0, lossy=True, lossless=True, bitonal=True, color=True, gray=True, set_to_gray=False, options=None)\n\n    PDF only: Walk through all images and rewrite them according to the specified parameters. This is useful for reducing file size, changing image formats, or converting color spaces.\n\n    The typical usage is extra compression of images for significantly reducing the file size of the PDF. When setting quality and the dpi parameters to positive values and accepting defaults for the rest, the following will happen:\n\n    * Lossy and lossless images will be rewritten as JPEG images (FZ_RECOMPRESS_JPEG) as far as technically possible.\n\n    * Bitonal (monochrome) images will be rewritten in FAX format (FZ_RECOMPRESS_FAX).\n\n    * Subsampling method is **FZ_SUBSAMPLE_AVERAGE** (see below).\n\n    :arg int dpi_target: target DPI value for the resampled images. Ignored if `dpi_threshold` is `None`, otherwise must be less than `dpi_threshold` and positive.\n\n    :arg int dpi_threshold: If None (the default) no resampling takes place. Otherwise images with a DPI value larger than this will be resampled to `dpi_target` (which must be less than `dpi_threshold`).\n\n    :arg int quality: desired target JPEG quality, a value between 0 and 100. 0 means no quality change, 100 means best quality.\n\n    :arg bool lossy: include lossy image types (e.g. JPEG).\n\n    :arg bool lossless: include lossless image types (e.g. PNG).\n\n    :arg bool bitonal: include black-and-white images (e.g. FAX).\n\n    :arg bool color: include colored images.\n\n    :arg bool gray: include grayscale images.\n\n    :arg bool set_to_gray: if True, the PDF will be converted to grayscale by executing :meth:`Document.recolor` before all image processing. Please note that this will also change text and vector graphics to grayscale -- not just the images.\n\n    :arg dict options: This parameter is intended for expert users. Except ``set_to_gray``, all other parameters are ignored. It must be an object prepared in the following way: ``options = pymupdf.mupdf.PdfImageRewriterOptions()``. Then attributes of this object can be set to achieve fine-grained control. Following are the adjustable attributes of the ``options`` object and their default (do nothing) values.\n\n    ::\n  \n      options.bitonal_image_recompress_method = FZ_RECOMPRESS_NEVER\n      options.bitonal_image_recompress_quality = None\n      options.bitonal_image_subsample_method = FZ_SUBSAMPLE_AVERAGE\n      options.bitonal_image_subsample_threshold = 0\n      options.bitonal_image_subsample_to = 0\n      options.color_lossless_image_recompress_method = FZ_RECOMPRESS_NEVER\n      options.color_lossless_image_recompress_quality = None\n      options.color_lossless_image_subsample_method = FZ_SUBSAMPLE_AVERAGE\n      options.color_lossless_image_subsample_threshold = 0\n      options.color_lossless_image_subsample_to = 0\n      options.color_lossy_image_recompress_method = FZ_RECOMPRESS_NEVER\n      options.color_lossy_image_recompress_quality = None\n      options.color_lossy_image_subsample_method = FZ_SUBSAMPLE_AVERAGE\n      options.color_lossy_image_subsample_threshold = 0\n      options.color_lossy_image_subsample_to = 0\n      options.gray_lossless_image_recompress_method = FZ_RECOMPRESS_NEVER\n      options.gray_lossless_image_recompress_quality = None\n      options.gray_lossless_image_subsample_method = FZ_SUBSAMPLE_AVERAGE\n      options.gray_lossless_image_subsample_threshold = 0\n      options.gray_lossless_image_subsample_to = 0\n      options.gray_lossy_image_recompress_method = FZ_RECOMPRESS_NEVER\n      options.gray_lossy_image_recompress_quality = None\n      options.gray_lossy_image_subsample_method = FZ_SUBSAMPLE_AVERAGE\n      options.gray_lossy_image_subsample_threshold = 0\n      options.gray_lossy_image_subsample_to = 0\n\n    The ``*_recompress_method`` attributes may be one of the values **FZ_RECOMPRESS_NEVER (0), FZ_RECOMPRESS_SAME (1), FZ_RECOMPRESS_LOSSLESS (2), FZ_RECOMPRESS_JPEG (3), FZ_RECOMPRESS_J2K (4), FZ_RECOMPRESS_FAX (5)**. Value FZ_RECOMPRESS_NEVER will skip this image type altogether and FZ_RECOMPRESS_SAME will not change the type. The other values will execute type conversions (as far as technically possible).\n    \n    The ``*_quality`` values are strings of integers from \"0\" to \"100\" or ``None``.\n    \n    The ``*_subsample_method`` attributes are either **FZ_SUBSAMPLE_AVERAGE (0)** or **FZ_SUBSAMPLE_BICUBIC (1)** and refer to how a pixel value is derived from its neighboring pixels during subsampling. For some background see `this Wikipedia article about bicubic interpolation <https://en.wikipedia.org/wiki/Bicubic_interpolation>`_.\n    \n    Attributes ``*_subsample_threshold`` excludes images from subsampling which have a lower DPI. Participating images will be subsampled to the DPI values given by the ``*_subsample_to`` values. Values of 0 mean that no subsampling will take place.\n    \n    The ``*_subsample_threshold`` values should be chosen notably larger than the ``*_subsample_to`` values to ensure that there are enough size savings. After all, every subsampling inevitably incurs quality losses.\n    \n    An example for a good choice is ``threshold=100`` and ``to=72``.\n\n\n  .. method:: recolor(components=1)\n\n    PDF only: Change the color component counts for all object types text, images and vector graphics for all pages.\n\n    :arg int components: desired color space indicated by the number of color components: 1 = DeviceGRAY, 3 = DeviceRGB, 4 = DeviceCMYK.\n\n    The typical use case is 1 (DeviceGRAY) which converts the PDF to grayscale.\n\n\n  .. method:: reload_page(page)\n\n    * New in v1.16.10\n\n    PDF only: Provide a new copy of a page after finishing and updating all pending changes.\n\n    :arg page: page object.\n    :type page: :ref:`Page`\n\n    :rtype: :ref:`Page`\n\n    :returns: a new copy of the same page. All pending updates (e.g. to annotations or widgets) will be finalized and a fresh copy of the page will be loaded.\n\n      .. note:: In a typical use case, a page :ref:`Pixmap` should be taken after annotations / widgets have been added or changed. To force all those changes being reflected in the page structure, this method re-instates a fresh copy while keeping the object hierarchy \"document -> page -> annotations/widgets\" intact.\n\n\n  .. method:: resolve_names()\n\n    PDF only: Convert destination names into a Python dict.\n\n    :returns:\n        A dictionary with the following layout:\n\n        * *key*: (str) the name.\n        * *value*: (dict) with the following layout:\n            * \"page\":  target page number (0-based). If no page number found -1.\n            * \"to\": (x, y) target point on page. Currently in PDF coordinates,\n              i.e. point (0,0) is the bottom-left of the page.\n            * \"zoom\": (float) the zoom factor.\n            * \"dest\": (str) only present if the target location on the page has\n              not been provided as \"/XYZ\" or if no page number was found.\n        Examples::\n\n            {\n                '__bookmark_1': {'page': 0, 'to': (0.0, 541.0), 'zoom': 0.0},\n                '__bookmark_2': {'page': 0, 'to': (0.0, 481.45), 'zoom': 0.0},\n            }\n\n        or::\n\n            {\n                '21154a7c20684ceb91f9c9adc3b677c40': {'page': -1, 'dest': '/XYZ 15.75 1486 0'},\n                ...\n            }\n\n    All names found in the catalog under keys \"/Dests\" and \"/Names/Dests\" are\n    included.\n\n    * New in v1.23.6\n\n\n  .. method:: page_cropbox(pno)\n\n    * New in v1.17.7\n\n    PDF only: Return the unrotated page rectangle -- **without loading the page** (via :meth:`Document.load_page`). This is meant for internal purpose requiring best possible performance.\n\n    :arg int pno: 0-based page number.\n\n    :returns: :ref:`Rect` of the page like :meth:`Page.rect`, but ignoring any rotation.\n\n  .. method:: page_xref(pno)\n\n    * New in v1.17.7\n\n    PDF only: Return the :data:`xref` of the page -- **without loading the page** (via :meth:`Document.load_page`). This is meant for internal purpose requiring best possible performance.\n\n    :arg int pno: 0-based page number.\n\n    :returns: :data:`xref` of the page like :attr:`Page.xref`.\n\n  .. method:: pages(start=None, [stop=None, [step=None]])\n\n    * New in v1.16.4\n\n    A generator for a range of pages. Parameters have the same meaning as in the built-in function *range()*. Intended for expressions of the form *\"for page in doc.pages(start, stop, step): ...\"*.\n\n    :arg int start: start iteration with this page number. Default is zero, allowed values are `-∞ < start < page_count`. While this is negative, :attr:`page_count` is added **before** starting the iteration.\n    :arg int stop: stop iteration at this page number. Default is :attr:`page_count`, possible are `-∞ < stop <= page_count`. Larger values are **silently replaced** by the default. Negative values will cyclically emit the pages in reversed order. As with the built-in *range()*, this is the first page **not** returned.\n    :arg int step: stepping value. Defaults are 1 if start < stop and -1 if start > stop. Zero is not allowed.\n\n    :returns: a generator iterator over the document's pages. Some examples:\n\n        * \"doc.pages()\" emits all pages.\n        * \"doc.pages(4, 9, 2)\" emits pages 4, 6, 8.\n        * \"doc.pages(0, None, 2)\" emits all pages with even numbers.\n        * \"doc.pages(-2)\" emits the last two pages.\n        * \"doc.pages(-1, -1)\" emits all pages in reversed order.\n        * \"doc.pages(-1, -10)\" always emits 10 pages in reversed order, starting with the last page -- **repeatedly** if the document has less than 10 pages. So for a 4-page document the following page numbers are emitted: 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3.\n\n  .. index::\n     pair: from_page; Document.convert_to_pdf\n     pair: to_page; Document.convert_to_pdf\n     pair: rotate; Document.convert_to_pdf\n\n  .. method:: convert_to_pdf(from_page=-1, to_page=-1, rotate=0)\n\n    Create a PDF version of the current document and write it to memory. **All document types** are supported. The parameters have the same meaning as in :meth:`insert_pdf`. In essence, you can restrict the conversion to a page subset, specify page rotation, and revert page sequence.\n\n    :arg int from_page: first page to copy (0-based). Default is first page.\n\n    :arg int to_page: last page to copy (0-based). Default is last page.\n\n    :arg int rotate: rotation angle. Default is 0 (no rotation). Should be *n * 90* with an integer n (not checked).\n\n    :rtype: bytes\n    :returns: a Python *bytes* object containing a PDF file image. It is created by internally using `tobytes(garbage=4, deflate=True)`. See :meth:`tobytes`. You can output it directly to disk or open it as a PDF. Here are some examples::\n\n        >>> # convert an XPS file to PDF\n        >>> xps = pymupdf.open(\"some.xps\")\n        >>> pdfbytes = xps.convert_to_pdf()\n        >>>\n        >>> # either do this -->\n        >>> pdf = pymupdf.open(\"pdf\", pdfbytes)\n        >>> pdf.save(\"some.pdf\")\n        >>>\n        >>> # or this -->\n        >>> pdfout = open(\"some.pdf\", \"wb\")\n        >>> pdfout.tobytes(pdfbytes)\n        >>> pdfout.close()\n\n        >>> # copy image files to PDF pages\n        >>> # each page will have image dimensions\n        >>> doc = pymupdf.open()                     # new PDF\n        >>> imglist = [ ... image file names ...] # e.g. a directory listing\n        >>> for img in imglist:\n                imgdoc=pymupdf.open(img)           # open image as a document\n                pdfbytes=imgdoc.convert_to_pdf()  # make a 1-page PDF of it\n                imgpdf=pymupdf.open(\"pdf\", pdfbytes)\n                doc.insert_pdf(imgpdf)             # insert the image PDF\n        >>> doc.save(\"allmyimages.pdf\")\n\n    .. note:: The method uses the same logic as the *mutool convert* CLI. This works very well in most cases -- however, beware of the following limitations.\n\n      * Image files: perfect, no issues detected. However, image transparency is ignored. If you need that (like for a watermark), use :meth:`Page.insert_image` instead. Otherwise, this method is recommended for its much better performance.\n      * XPS: appearance very good. Links work fine, outlines (bookmarks) are lost, but can easily be recovered [#f2]_.\n      * EPUB, CBZ, FB2: similar to XPS.\n      * SVG: medium. Roughly comparable to `svglib <https://github.com/deeplook/svglib>`_.\n\n  .. method:: get_toc(simple=True)\n\n    Creates a table of contents (TOC) out of the document's outline chain.\n\n    :arg bool simple: Indicates whether a simple or a detailed TOC is required. If ``False``, each item of the list also contains a dictionary with :ref:`linkDest` details for each outline entry.\n\n    :rtype: list\n\n    :returns: a list of lists. Each entry has the form *[lvl, title, page, dest]*. Its entries have the following meanings:\n\n      * *lvl* -- hierarchy level (positive *int*). The first entry is always 1. Entries in a row are either **equal**, **increase** by 1, or **decrease** by any number.\n      * *title* -- title (*str*)\n      * *page* -- 1-based source page number (*int*). `-1` if no destination or outside document.\n      * *dest* -- (*dict*) included only if *simple=False*. Contains details of the TOC item as follows:\n\n        - kind: destination kind, see :ref:`linkDest Kinds`.\n        - file: filename if kind is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.\n        - page: target page, 0-based, :data:`LINK_GOTOR` or :data:`LINK_GOTO` only.\n        - to: position on target page (:ref:`Point`).\n        - zoom: (float) zoom factor on target page.\n        - xref: :data:`xref` of the item (0 if no PDF).\n        - color: item color in PDF RGB format `(red, green, blue)`, or omitted (always omitted if no PDF).\n        - bold: true if bold item text or omitted. PDF only.\n        - italic: true if italic item text, or omitted. PDF only.\n        - collapse: true if sub-items are folded, or omitted. PDF only.\n        - nameddest: target name if kind=4. PDF only. (New in 1.23.7.)\n\n\n  .. method:: xref_get_keys(xref)\n\n    * New in v1.18.7\n\n    PDF only: Return the PDF dictionary keys of the :data:`dictionary` object provided by its xref number.\n\n    :arg int xref: the :data:`xref`. *(Changed in v1.18.10)* Use `-1` to access the special dictionary \"PDF trailer\".\n\n    :returns: a tuple of dictionary keys present in object :data:`xref`. Examples:\n\n      >>> from pprint import pprint\n      >>> import pymupdf\n      >>> doc=pymupdf.open(\"pymupdf.pdf\")\n      >>> xref = doc.page_xref(0)  # xref of page 0\n      >>> pprint(doc.xref_get_keys(xref))  # primary level keys of a page\n      ('Type', 'Contents', 'Resources', 'MediaBox', 'Parent')\n      >>> pprint(doc.xref_get_keys(-1))  # primary level keys of the trailer\n      ('Type', 'Index', 'Size', 'W', 'Root', 'Info', 'ID', 'Length', 'Filter')\n      >>>\n\n\n  .. method:: xref_get_key(xref, key)\n\n    * New in v1.18.7\n\n    PDF only: Return type and value of a PDF dictionary key of a :data:`dictionary` object given by its xref.\n\n    :arg int xref: the :data:`xref`. *Changed in v1.18.10:* Use `-1` to access the special dictionary \"PDF trailer\".\n\n    :arg str key: the desired PDF key. Must **exactly** match (case-sensitive) one of the keys contained in :meth:`Document.xref_get_keys`.\n\n    :rtype: tuple\n\n    :returns: A tuple (type, value) of strings, where type is one of \"xref\", \"array\", \"dict\", \"int\", \"float\", \"null\", \"bool\", \"name\", \"string\" or \"unknown\" (should not occur). Independent of \"type\", the value of the key is **always** formatted as a string -- see the following example -- and (almost always) a faithful reflection of what is stored in the PDF. In most cases, the format of the value string also gives a clue about the key type:\n\n    * A \"name\" always starts with a \"/\" slash.\n    * An \"xref\" always ends with \" 0 R\".\n    * An \"array\" is always enclosed in \"[...]\" brackets.\n    * A \"dict\" is always enclosed in \"<<...>>\" brackets.\n    * A \"bool\", resp. \"null\" always equal either \"true\", \"false\", resp. \"null\".\n    * \"float\" and \"int\" are represented by their string format -- and are thus not always distinguishable.\n    * A \"string\" is converted to UTF-8 and may therefore deviate from what is stored in the PDF. For example, the PDF key \"Author\" may have a value of \"<FEFF004A006F0072006A00200058002E0020004D0063004B00690065>\" in the file, but the method will return `('string', 'Jorj X. McKie')`.\n\n      >>> for key in doc.xref_get_keys(xref):\n              print(key, \"=\" , doc.xref_get_key(xref, key))\n      Type = ('name', '/Page')\n      Contents = ('xref', '1297 0 R')\n      Resources = ('xref', '1296 0 R')\n      MediaBox = ('array', '[0 0 612 792]')\n      Parent = ('xref', '1301 0 R')\n      >>> #\n      >>> # Now same thing for the PDF trailer.\n      >>> # It has no xref, so -1 must be used instead.\n      >>> #\n      >>> for key in doc.xref_get_keys(-1):\n              print(key, \"=\", doc.xref_get_key(-1, key))\n      Type = ('name', '/XRef')\n      Index = ('array', '[0 8802]')\n      Size = ('int', '8802')\n      W = ('array', '[1 3 1]')\n      Root = ('xref', '8799 0 R')\n      Info = ('xref', '8800 0 R')\n      ID = ('array', '[<DC9D56A6277EFFD82084E64F9441E18C><DC9D56A6277EFFD82084E64F9441E18C>]')\n      Length = ('int', '21111')\n      Filter = ('name', '/FlateDecode')\n      >>>\n\n\n  .. method:: xref_set_key(xref, key, value)\n\n    * New in v1.18.7, changed in v 1.18.13\n    * Changed in v1.19.4: remove a key \"physically\" if set to \"null\".\n\n    PDF only: Set (add, update, delete) the value of a PDF key for the :data:`dictionary` object given by its xref.\n\n    .. caution:: This is an expert function: if you do not know what you are doing, there is a high risk to render (parts of) the PDF unusable. Please do consult :ref:`AdobeManual` about object specification formats (page 18) and the structure of special dictionary types like page objects.\n\n    :arg int xref: the :data:`xref`. *Changed in v1.18.13:* To update the PDF trailer, specify -1.\n    :arg str key: the desired PDF key (without leading \"/\"). Must not be empty. Any valid PDF key -- whether already present in the object (which will be overwritten) -- or new. It is possible to use PDF path notation like `\"Resources/ExtGState\"` -- which sets the value for key `\"/ExtGState\"` as a sub-object of `\"/Resources\"`.\n    :arg str value: the value for the key. It must be a non-empty string and, depending on the desired PDF object type, the following rules must be observed. There is some syntax checking, but **no type checking** and no checking if it makes sense PDF-wise, i.e. **no semantics checking**. Upper / lower case is important!\n\n    * *:data:`xref`* -- must be provided as `\"nnn 0 R\"` with a valid :data:`xref` number nnn of the PDF. The suffix \"`0 R`\" is required to be recognizable as an xref by PDF applications.\n    * **array** -- a string like `\"[a b c d e f]\"`. The brackets are required. Array items must be separated by at least one space (not commas like in Python). An empty array `\"[]\"` is possible and *equivalent* to removing the key. Array items may be any PDF objects, like dictionaries, xrefs, other arrays, etc. Like in Python, array items may be of different types.\n    * **dict** -- a string like `\"<< ... >>\"`. The brackets are required and must enclose a valid PDF dictionary definition. The empty dictionary `\"<<>>\"` is possible and *equivalent* to removing the key.\n    * **int** -- an integer formatted **as a string**.\n    * **float** -- a float formatted **as a string**. Scientific notation (with exponents) is **not allowed by PDF**.\n    * **null** -- the string `\"null\"`. This is the PDF equivalent to Python's `None` and causes the key to be ignored -- however not necessarily removed, resp. removed on saves with garbage collection. *Changed in v1.19.4:* If the key is no path hierarchy (i.e. contains no slash \"/\"), then it will be completely removed.\n    * **bool** -- one of the strings `\"true\"` or `\"false\"`.\n    * **name** -- a valid PDF name with a leading slash like this: `\"/PageLayout\"`. See page 16 of the :ref:`AdobeManual`.\n    * **string** -- a valid PDF string. **All PDF strings must be enclosed by brackets**. Denote the empty string as `\"()\"`. Depending on its content, the possible brackets are\n\n      - \"(...)\" for ASCII-only text. Reserved PDF characters must be backslash-escaped and non-ASCII characters must be provided as 3-digit backslash-escaped octals -- including leading zeros. Example: 12 = 0x0C must be encoded as `\\014`.\n      - \"<...>\" for hex-encoded text. Every character must be represented by two hex-digits (lower or upper case).\n\n      - If in doubt, we **strongly recommend** to use :meth:`get_pdf_str`! This function automatically generates the right brackets, escapes, and overall format. It will for example do conversions like these:\n\n        >>> # because of the € symbol, the following yields UTF-16BE BOM\n        >>> pymupdf.get_pdf_str(\"Pay in $ or €.\")\n        '<feff00500061007900200069006e002000240020006f0072002020ac002e>'\n        >>> # escapes for brackets and non-ASCII\n        >>> pymupdf.get_pdf_str(\"Prices in EUR (USD also accepted). Areas are in m².\")\n        '(Prices in EUR \\\\(USD also accepted\\\\). Areas are in m\\\\262.)'\n\n\n  .. method:: get_page_pixmap(pno: int, *, matrix: matrix_like = Identity, dpi=None, colorspace: Colorspace = csRGB, clip: rect_like = None, alpha: bool = False, annots: bool = True)\n\n    Creates a pixmap from page *pno* (zero-based). Invokes :meth:`Page.get_pixmap`.\n\n    All parameters except `pno` are *keyword-only.*\n\n    :arg int pno: page number, 0-based in `-∞ < pno < page_count`.\n\n    :rtype: :ref:`Pixmap`\n\n  .. method:: get_page_xobjects(pno)\n\n    * New in v1.16.13\n    * Changed in v1.18.11\n\n    PDF only: Return a list of all XObjects referenced by a page.\n\n    :arg int pno: page number, 0-based, `-∞ < pno < page_count`.\n\n    :rtype: list\n    :returns: a list of (non-image) XObjects. These objects typically represent pages *embedded* (not copied) from other PDFs. For example, :meth:`Page.show_pdf_page` will create this type of object. An item of this list has the following layout: `(xref, name, invoker, bbox)`, where\n\n      * *:data:`xref`* (*int*) is the XObject's :data:`xref`.\n      * **name** (*str*) is the symbolic name to reference the XObject.\n      * **invoker** (*int*) the :data:`xref` of the invoking XObject or zero if the page directly invokes it.\n      * **bbox** (:ref:`Rect`) the boundary box of the XObject's location on the page **in untransformed coordinates**. To get actual, non-rotated page coordinates, multiply with the page's transformation matrix :attr:`Page.transformation_matrix`. *Changed in v.18.11:* the bbox is now formatted as :ref:`Rect`.\n\n\n  .. method:: get_page_images(pno, full=False)\n\n    PDF only: Return a list of all images (directly or indirectly) referenced by the page.\n\n    :arg int pno: page number, 0-based, `-∞ < pno < page_count`.\n    :arg bool full: whether to also include the referencer's :data:`xref` (which is zero if this is the page).\n\n    :rtype: list\n\n    :returns: a list of images **referenced** by this page. Each item looks like:\n\n        `(xref, smask, width, height, bpc, colorspace, alt_colorspace, name, filter, referencer)`\n\n          * ``xref`` (*int*) is the image object number\n          * ``smask`` (*int*) is the object number of its soft-mask image\n          * ``width`` (*int*) is the image width\n          * ``height`` (*int*) is the image height\n          * ``bpc`` (*int*) denotes the number of bits per component (normally 8)\n          * ``colorspace`` (*str*) a string naming the colorspace (like **DeviceRGB**)\n          * ``alt_colorspace`` (*str*) is any alternate colorspace depending on the value of **colorspace**\n          * ``name`` (*str*) is the symbolic name by which the image is referenced\n          * ``filter`` (*str*) is the decode filter of the image (:ref:`AdobeManual`, pp. 22).\n          * ``referencer`` (*int*) the :data:`xref` of the referencer. Zero if directly referenced by the page. Only present if *full=True*.\n\n    .. note:: In general, this is not the list of images that are **actually displayed**. This method only parses several PDF objects to collect references to embedded images. It does not analyse the page's :data:`contents`, where all the actual image display commands are defined. To get this information, please use :meth:`Page.get_image_info`. Also have a look at the discussion in section :ref:`textpagedict`.\n\n\n  .. method:: get_page_fonts(pno, full=False)\n\n    PDF only: Return a list of all fonts (directly or indirectly) referenced by the page object definition.\n\n    :arg int pno: page number, 0-based, `-∞ < pno < page_count`.\n    :arg bool full: whether to also include the referencer's :data:`xref`. If ``True``, the returned items are one entry longer. Use this option if you need to know, whether the page directly references the font. In this case the last entry is 0. If the font is referenced by an `/XObject` of the page, you will find its :data:`xref` here.\n\n    :rtype: list\n\n    :returns: a list of fonts referenced by the object definition of the page. Each entry looks like:\n\n      `(xref, ext, type, basefont, name, encoding, referencer)`\n\n          * ``xref`` (*int*) is the font object number (may be zero if the PDF uses one of the builtin fonts directly)\n          * ``ext`` (*str*) font file extension (e.g. \"ttf\", see :ref:`FontExtensions`)\n          * ``type`` (*str*) is the font type (like \"Type1\" or \"TrueType\" etc.)\n          * ``basefont`` (*str*) is the base font name,\n          * ``name`` (*str*) is the symbolic name, by which the font is referenced\n          * ``encoding`` (*str*) the font's character encoding if different from its built-in encoding (:ref:`AdobeManual`, p. 254):\n          * ``referencer`` (*int* optional) the :data:`xref` of the referencer. Zero if directly referenced by the page, otherwise the xref of an XObject. Only present if *full=True*.\n\n    Example::\n\n        >>> pprint(doc.get_page_fonts(0, full=False))\n        [(12, 'ttf', 'TrueType', 'FNUUTH+Calibri-Bold', 'R8', ''),\n         (13, 'ttf', 'TrueType', 'DOKBTG+Calibri', 'R10', ''),\n         (14, 'ttf', 'TrueType', 'NOHSJV+Calibri-Light', 'R12', ''),\n         (15, 'ttf', 'TrueType', 'NZNDCL+CourierNewPSMT', 'R14', ''),\n         (16, 'ttf', 'Type0', 'MNCSJY+SymbolMT', 'R17', 'Identity-H'),\n         (17, 'cff', 'Type1', 'UAEUYH+Helvetica', 'R20', 'WinAnsiEncoding'),\n         (18, 'ttf', 'Type0', 'ECPLRU+Calibri', 'R23', 'Identity-H'),\n         (19, 'ttf', 'Type0', 'TONAYT+CourierNewPSMT', 'R27', 'Identity-H')]\n\n    .. note::\n        * This list has no duplicate entries: the combination of :data:`xref`, *name* and *referencer* is unique.\n        * In general, this is a true superset of the fonts actually in use by this page. The PDF creator may e.g. have specified some global list, of which each page make only partial use.\n        * Be aware that font names returned by some variants of :meth:`Page.get_text` (respectively :ref:`TextPage` methods) need not (exactly) equal the base font name shown here. Reasons for any differences include:\n\n           - This method always shows any subset prefixes (the pattern ``ABCDEF+``), whereas text extractions do not do this by default.\n           - Text extractions use the base library to access the font name, which has a length cap of 31 bytes and generally interrogates the font file binary to access the name. Method ``get_page_fonts()`` however looks at the PDF definition source.\n           - Text extractions work for all supported document types in exactly the same way -- not just for PDFs. Consequently they do not contain PDF-specifics.\n\n  .. method:: get_page_text(pno, output=\"text\", flags=3, textpage=None, sort=False)\n\n    Extracts the text of a page given its page number *pno* (zero-based). Invokes :meth:`Page.get_text`.\n\n    :arg int pno: page number, 0-based, any value `-∞ < pno < page_count`.\n\n    For other parameter refer to the page method.\n\n    :rtype: str\n\n  .. index::\n     pair: fontsize; Document.layout\n     pair: rect; Document.layout\n     pair: width; Document.layout\n     pair: height; Document.layout\n\n  .. method:: layout(rect=None, width=0, height=0, fontsize=11)\n\n    Re-paginate (\"reflow\") the document based on the given page dimension and fontsize. This only affects some document types like e-books and HTML. Ignored if not supported. Supported documents have ``True`` in property :attr:`is_reflowable`.\n\n    :arg rect_like rect: desired page size. Must be finite, not empty and start at point (0, 0).\n    :arg float width: use it together with ``height`` as alternative to ``rect``.\n    :arg float height: use it together with ``width`` as alternative to ``rect``.\n    :arg float fontsize: the desired default fontsize.\n\n  .. method:: select(s)\n\n    PDF only: Keeps only those pages of the document whose numbers occur in the list. Empty sequences or elements outside `range(doc.page_count)` will cause a *ValueError*. For more details see remarks at the bottom or this chapter.\n\n    :arg sequence s: The sequence (see :ref:`SequenceTypes`) of page numbers (zero-based) to be included. Pages not in the sequence will be deleted (from memory) and become unavailable until the document is reopened. **Page numbers can occur multiple times and in any order:** the resulting document will reflect the sequence exactly as specified.\n\n    .. note::\n\n        * Page numbers in the sequence need not be unique nor be in any particular order. This makes the method a versatile utility to e.g. select only the even or the odd pages or meeting some other criteria and so forth.\n\n        * On a technical level, the method will always create a new :data:`pagetree`.\n\n        * When dealing with only a few pages, methods :meth:`copy_page`, :meth:`move_page`, :meth:`delete_page` are easier to use. In fact, they are also **much faster** -- by at least one order of magnitude when the document has many pages.\n\n\n  .. method:: set_metadata(m)\n\n    PDF only: Sets or updates the metadata of the document as specified in *m*, a Python dictionary.\n\n    :arg dict m: A dictionary with the same keys as *metadata* (see below). All keys are optional. A PDF's format and encryption method cannot be set or changed and will be ignored. If any value should not contain data, do not specify its key or set the value to `None`. If you use *{}* all metadata information will be cleared to the string *\"none\"*. If you want to selectively change only some values, modify a copy of *doc.metadata* and use it as the argument. Arbitrary unicode values are possible if specified as UTF-8-encoded.\n\n    *(Changed in v1.18.4)* Empty values or \"none\" are no longer written, but completely omitted.\n\n  .. method:: get_xml_metadata()\n\n    PDF only: Get the document XML metadata.\n\n    :rtype: str\n    :returns: XML metadata of the document. Empty string if not present or not a PDF.\n\n  .. method:: set_xml_metadata(xml)\n\n    PDF only: Sets or updates XML metadata of the document.\n\n    :arg str xml: the new XML metadata. Should be XML syntax, however no checking is done by this method and any string is accepted.\n\n\n  .. method:: set_pagelayout(value)\n\n    * New in v1.22.2\n\n    PDF only: Set the `/PageLayout`.\n\n    :arg str value: one of the strings \"SinglePage\", \"OneColumn\", \"TwoColumnLeft\", \"TwoColumnRight\", \"TwoPageLeft\", \"TwoPageRight\". Lower case is supported.\n\n\n  .. method:: set_pagemode(value)\n\n    * New in v1.22.2\n\n    PDF only: Set the `/PageMode`.\n\n    :arg str value: one of the strings \"UseNone\", \"UseOutlines\", \"UseThumbs\", \"FullScreen\", \"UseOC\", \"UseAttachments\". Lower case is supported.\n\n\n  .. method:: set_markinfo(value)\n\n    * New in v1.22.2\n\n    PDF only: Set the `/MarkInfo` values.\n\n    :arg dict value: a dictionary like this one: `{\"Marked\": False, \"UserProperties\": False, \"Suspects\": False}`. This dictionary contains information about the usage of Tagged PDF conventions. For details please see the `PDF specifications <https://opensource.adobe.com/dc-acrobat-sdk-docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_.\n\n\n  .. method:: set_toc(toc, collapse=1)\n\n    PDF only: Replaces the **complete current outline** tree (table of contents) with the one provided as the argument. After successful execution, the new outline tree can be accessed as usual via :meth:`Document.get_toc` or via :attr:`Document.outline`. Like with other output-oriented methods, changes become permanent only via :meth:`save` (incremental save supported). Internally, this method consists of the following two steps. For a demonstration see example below.\n\n    - Step 1 deletes all existing bookmarks.\n\n    - Step 2 creates a new TOC from the entries contained in *toc*.\n\n    :arg sequence toc:\n\n        A list / tuple with **all bookmark entries** that should form the new table of contents. Output variants of :meth:`get_toc` are acceptable. To completely remove the table of contents specify an empty sequence or None. Each item must be a list with the following format.\n\n        * [lvl, title, page [, dest]] where\n\n          - **lvl** is the hierarchy level (int > 0) of the item, which **must be 1** for the first item and at most 1 larger than the previous one.\n\n          - **title** (str) is the title to be displayed. It is assumed to be UTF-8-encoded (relevant for multibyte code points only).\n\n          - **page** (int) is the target page number **(attention: 1-based)**. Must be in valid range if positive. Set it to -1 if there is no target, or the target is external.\n\n          - **dest** (optional) is a dictionary or a number. If a number, it will be interpreted as the desired height (in points) this entry should point to on the page. Use a dictionary (like the one given as output by `get_toc(False)`) for a detailed control of the bookmark's properties, see :meth:`Document.get_toc` for a description.\n\n    :arg int collapse: *(new in v1.16.9)* controls the hierarchy level beyond which outline entries should initially show up collapsed. The default 1 will hence only display level 1, higher levels must be unfolded using the PDF viewer. To unfold everything, specify either a large integer, 0 or None.\n\n    :rtype: int\n    :returns: the number of inserted, resp. deleted items.\n\n    Changed in v1.23.8: Destination 'to' coordinates should now be in the\n    same coordinate system as those returned by `get_toc()` (internally they\n    are now transformed with `page.cropbox` and `page.rotation_matrix`). So\n    for example `set_toc(get_toc())` now gives unchanged destination 'to'\n    coordinates.\n\n  .. method:: outline_xref(idx)\n\n    * New in v1.17.7\n\n    PDF only: Return the :data:`xref` of the outline item. This is mainly used for internal purposes.\n\n    :arg int idx: index of the item in list :meth:`Document.get_toc`.\n\n    :returns: :data:`xref`.\n\n  .. method:: del_toc_item(idx)\n\n    * New in v1.17.7\n    * Changed in v1.18.14: no longer remove the item's text, but show it grayed-out.\n\n    PDF only: Remove this TOC item. This is a high-speed method, which **disables** the respective item, but leaves the overall TOC structure intact. Physically, the item still exists in the TOC tree, but is shown grayed-out and will no longer point to any destination.\n\n    This also implies that you can reassign the item to a new destination using :meth:`Document.set_toc_item`, when required.\n\n    :arg int idx: the index of the item in list :meth:`Document.get_toc`.\n\n\n  .. method:: set_toc_item(idx, dest_dict=None, kind=None, pno=None, uri=None, title=None, to=None, filename=None, zoom=0)\n\n    * New in v1.17.7\n    * Changed in v1.18.6\n\n    PDF only: Changes the TOC item identified by its index. Change the item **title**, **destination**, **appearance** (color, bold, italic) or collapsing sub-items -- or to remove the item altogether.\n\n    Use this method if you need specific changes for selected entries only and want to avoid replacing the complete TOC. This is beneficial especially when dealing with large table of contents.\n\n    :arg int idx: the index of the entry in the list created by :meth:`Document.get_toc`.\n    :arg dict dest_dict: the new destination. A dictionary like the last entry of an item in `doc.get_toc(False)`. Using this as a template is recommended. When given, **all other parameters are ignored** -- except title.\n    :arg int kind: the link kind, see :ref:`linkDest Kinds`. If :data:`LINK_NONE`, then all remaining parameter will be ignored, and the TOC item will be removed -- same as :meth:`Document.del_toc_item`. If None, then only the title is modified and the remaining parameters are ignored. All other values will lead to making a new destination dictionary using the subsequent arguments.\n    :arg int pno: the 1-based page number, i.e. a value 1 <= pno <= doc.page_count. Required for LINK_GOTO.\n    :arg str uri: the URL text. Required for LINK_URI.\n    :arg str title: the desired new title. None if no change.\n    :arg point_like to: (optional) points to a coordinate on the target page. Relevant for LINK_GOTO. If omitted, a point near the page's top is chosen.\n    :arg str filename: required for LINK_GOTOR and LINK_LAUNCH.\n    :arg float zoom: use this zoom factor when showing the target page.\n\n    **Example use:** Change the TOC of the SWIG manual to achieve this:\n\n    Collapse everything below top level and show the chapter on Python support in red, bold and italic::\n\n      >>> import pymupdf\n      >>> doc=pymupdf.open(\"SWIGDocumentation.pdf\")\n      >>> toc = doc.get_toc(False)  # we need the detailed TOC\n      >>> # list of level 1 indices and their titles\n      >>> lvl1 = [(i, item[1]) for i, item in enumerate(toc) if item[0] == 1]\n      >>> for i, title in lvl1:\n              d = toc[i][3]  # get the destination dict\n              d[\"collapse\"] = True  # collapse items underneath\n              if \"Python\" in title:  # show the 'Python' chapter\n                  d[\"color\"] = (1, 0, 0)  # in red,\n                  d[\"bold\"] = True  # bold and\n                  d[\"italic\"] = True  # italic\n              doc.set_toc_item(i, dest_dict=d)  # update this toc item\n      >>> doc.save(\"NEWSWIG.pdf\",garbage=3,deflate=True)\n\n    In the previous example, we have changed only 42 of the 1240 TOC items of the file.\n\n  .. method:: bake(*, annots=True, widgets=True)\n\n    PDF only: Convert annotations and / or widgets to become permanent parts of the pages. The PDF **will be changed** by this method. If `widgets` is `True`, the document will also no longer be a \"Form PDF\".\n    \n    All pages will look the same, but will no longer have annotations, respectively fields. The visible parts will be converted to standard text, vector graphics or images as required.\n\n    The method may thus be a viable **alternative for PDF-to-PDF conversions** using :meth:`Document.convert_to_pdf`.\n\n    Please consider that annotations are complex objects and may consist of more data \"underneath\" their visual appearance. Examples are \"Text\" and \"FileAttachment\" annotations. When \"baking in\" annotations / widgets with this method, all this underlying information (attached files, comments, associated PopUp annotations, etc.) will be lost and be removed on next garbage collection.\n\n    Use this feature for instance for :meth:`Page.show_pdf_page` (which supports neither annotations nor widgets) when the source pages should look exactly the same in the target.\n\n\n    :arg bool annots: convert annotations.\n    :arg bool widgets: convert fields / widgets. After execution, the document will no longer be a \"Form PDF\".\n\n\n  .. method:: can_save_incrementally()\n\n    * New in v1.16.0\n\n    Check whether the document can be saved incrementally. Use it to choose the right option without encountering exceptions.\n\n  .. method:: repair()\n  \n    Repair document.\n    \n    * Slow for large documents.\n    * Does nothing on non-PDF documents.\n    * New in v1.27.0\n  \n  .. method:: scrub(attached_files=True, clean_pages=True, embedded_files=True, hidden_text=True, javascript=True, metadata=True, redactions=True, redact_images=0, remove_links=True, reset_fields=True, reset_responses=True, thumbnails=True, xml_metadata=True)\n\n    * New in v1.16.14\n\n    PDF only: Remove potentially sensitive data from the PDF. This function is inspired by the similar \"Sanitize\" function in Adobe Acrobat products. The process is configurable by a number of options.\n\n    :arg bool attached_files: Search for 'FileAttachment' annotations and remove the file content.\n    :arg bool clean_pages: Remove any comments from page painting sources. If this option is set to ``False``, then this is also done for *hidden_text* and *redactions*.\n    :arg bool embedded_files: Remove embedded files.\n    :arg bool hidden_text: Remove OCRed text and invisible text [#f7]_.\n    :arg bool javascript: Remove JavaScript sources.\n    :arg bool metadata: Remove PDF standard metadata.\n    :arg bool redactions: Apply redaction annotations.\n    :arg int redact_images: how to handle images if applying redactions. One of 0 (ignore), 1 (blank out overlaps) or 2 (remove).\n    :arg bool remove_links: Remove all links.\n    :arg bool reset_fields: Reset all form fields to their defaults.\n    :arg bool reset_responses: Remove all responses from all annotations.\n    :arg bool thumbnails: Remove thumbnail images from pages.\n    :arg bool xml_metadata: Remove XML metadata.\n\n\n  .. method:: save(outfile, garbage=0, clean=False, deflate=False, deflate_images=False, deflate_fonts=False, incremental=False, ascii=False, expand=0, linear=False, pretty=False, no_new_id=False, encryption=PDF_ENCRYPT_NONE, permissions=-1, owner_pw=None, user_pw=None, use_objstms=0, compression_effort=0, raise_on_repair=False)\n\n    * Changed in v1.18.7\n    * Changed in v1.19.0\n    * Changed in v1.24.1\n\n    PDF only: Saves the document in its **current state**.\n\n    :arg str,Path,fp outfile: The file path, `pathlib.Path` or file object to save to. A file object must have been created before via `open(...)` or `io.BytesIO()`. Choosing `io.BytesIO()` is similar to :meth:`Document.tobytes` below, which equals the `getvalue()` output of an internally created `io.BytesIO()`.\n\n    :arg int garbage: Do garbage collection. Positive values exclude \"incremental\".\n\n     * 0 = none\n     * 1 = remove unused (unreferenced) objects.\n     * 2 = in addition to 1, compact the :data:`xref` table.\n     * 3 = in addition to 2, merge duplicate objects.\n     * 4 = in addition to 3, check :data:`stream` objects for duplication. This may be slow because such data are typically large.\n\n    :arg bool clean: Clean and sanitize content streams [#f1]_. Corresponds to \"mutool clean -sc\".\n\n    :arg bool deflate: Deflate (compress) uncompressed streams.\n    :arg bool deflate_images: *(new in v1.18.3)* Deflate (compress) uncompressed image streams [#f4]_.\n    :arg bool deflate_fonts: *(new in v1.18.3)* Deflate (compress) uncompressed fontfile streams [#f4]_.\n\n    :arg bool incremental: Only save changes to the PDF. Excludes \"garbage\" and \"linear\". Can only be used if *outfile* is a string or a `pathlib.Path` and equal to :attr:`Document.name`. Cannot be used for files that are decrypted or repaired and also in some other cases. To be sure, check :meth:`Document.can_save_incrementally`. If this is false, saving to a new file is required.\n\n    :arg bool ascii: convert binary data to ASCII.\n\n    :arg int expand: Decompress objects. Generates versions that can be better read by some other programs and will lead to larger files.\n\n     * 0 = none\n     * 1 = images\n     * 2 = fonts\n     * 255 = all\n\n    :arg bool linear: Save a linearised version of the document. This option creates a file format for improved performance for Internet access. Excludes \"incremental\" and \"use_objstms\".\n\n    :arg bool pretty: Prettify the document source for better readability. PDF objects will be reformatted to look like the default output of :meth:`Document.xref_object`.\n\n    :arg bool no_new_id: Suppress the update of the file's `/ID` field. If the file happens to have no such field at all, also suppress creation of a new one. Default is `False`, so every save will lead to an updated file identification.\n\n    :arg int permissions: *(new in v1.16.0)* Set the desired permission levels. See :ref:`PermissionCodes` for possible values. Default is granting all.\n\n    :arg int encryption: *(new in v1.16.0)* set the desired encryption method. See :ref:`EncryptionMethods` for possible values.\n\n    :arg str owner_pw: *(new in v1.16.0)* set the document's owner password. *(Changed in v1.18.3)* If not provided, the user password is taken if provided. The string length must not exceed 40 characters.\n\n    :arg str user_pw: *(new in v1.16.0)* set the document's user password. The string length must not exceed 40 characters.\n\n    :arg int use_objstms: *(new in v1.24.0)* compression option that converts eligible PDF object definitions to information that is stored in some other object's :data:`stream` data. Depending on the `deflate` parameter value, the converted object definitions will be compressed -- which can lead to very significant file size reductions.\n\n     .. warning:: The method does not check, whether a file of that name already exists, will hence not ask for confirmation, and overwrite the file. It is your responsibility as a programmer to handle this.\n\n    :arg int compression_effort:\n    \n      * 0 for default\n      * 1 for minimum effort.\n      * 100 for maximum effort.\n    \n    :arg bool raise_on_repair: *(new in v1.27.0)* If true we raise an exception if the save caused a repair.\n      This is useful because repairs can cause changes to be lost.\n      \n      Also see `Document.repair()`.\n    \n    .. note::\n\n      **File size reduction**\n\n      1. Use the save options like `garbage=3|4, deflate=True, use_objstms=True|1`. Do not touch the default values `expand=False|0, clean=False|0, incremental=False|0, linear=False|0`.\n      This is a \"lossless\" file size reduction. There is a convenience version of this method with these values set by default, :meth:`Document.ez_save` -- please see below. \n\n      2. \"Lossy\" file size reduction in essence must give up something with respect to images, like (a) remove all images (b) replace images by their grayscale versions (c) reduce image resolutions. Find examples in the `PyMuPDF Utilities \"replace-image\" folder <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/replace-image>`_.\n\n  .. method:: ez_save(*args, **kwargs)\n\n    * New in v1.18.11\n\n    PDF only: The same as :meth:`Document.save` but with changed defaults `deflate=True, garbage=3, use_objstms=1`.\n\n  .. method:: saveIncr()\n\n    PDF only: saves the document incrementally. This is a convenience abbreviation for ``doc.save(doc.name, incremental=True, encryption=PDF_ENCRYPT_KEEP)``.\n\n  .. note::\n\n      Saving incrementally may be required if the document contains verified signatures which would be invalidated by saving to a new file.\n\n\n  .. method:: tobytes(garbage=0, clean=False, deflate=False, deflate_images=False, deflate_fonts=False, ascii=False, expand=0, linear=False, pretty=False, no_new_id=False, encryption=PDF_ENCRYPT_NONE, permissions=-1, owner_pw=None, user_pw=None, use_objstms=0)\n\n    * Changed in v1.18.7\n    * Changed in v1.19.0\n    * Changed in v1.24.1\n\n    PDF only: Writes the **current content of the document** to a bytes object instead of to a file. Obviously, you should be wary about memory requirements. The meanings of the parameters exactly equal those in :meth:`save`. Chapter :ref:`FAQ` contains an example for using this method as a pre-processor to `pdfrw <https://pypi.python.org/pypi/pdfrw/0.3>`_.\n\n    *(Changed in v1.16.0)* for extended encryption support.\n\n    :rtype: bytes\n    :returns: a bytes object containing the complete document.\n\n  .. method:: search_page_for(pno, text, quads=False)\n\n     Search for \"text\" on page number \"pno\". Works exactly like the corresponding :meth:`Page.search_for`. Any integer `-∞ < pno < page_count` is acceptable.\n\n  .. index::\n     pair: append; Document.insert_pdf\n     pair: join; Document.insert_pdf\n     pair: merge; Document.insert_pdf\n     pair: from_page; Document.insert_pdf\n     pair: to_page; Document.insert_pdf\n     pair: start_at; Document.insert_pdf\n     pair: rotate; Document.insert_pdf\n     pair: links; Document.insert_pdf\n     pair: annots; Document.insert_pdf\n     pair: widgets; Document.insert_pdf\n     pair: join_duplicates; Document.insert_pdf\n     pair: show_progress; Document.insert_pdf\n\n  .. method:: insert_pdf(docsrc, *, from_page=-1, to_page=-1, start_at=-1, rotate=-1, links=True, annots=True, widgets=True, join_duplicates=False, show_progress=0, final=1)\n\n    PDF only: Copy the page range **[from_page, to_page]** (including both) of PDF document *docsrc* into the current one. Inserts will start with page number *start_at*. Value -1 indicates default values. All pages thus copied will be rotated as specified. Links, annotations and widgets can be excluded in the target, see below. All page numbers are 0-based.\n\n    :arg docsrc: An opened PDF *Document* which must not be the current document. However, it may refer to the same underlying file.\n    :type docsrc: *Document*\n\n    :arg int from_page: First page number in *docsrc*. Default is zero.\n\n    :arg int to_page: Last page number in *docsrc* to copy. Defaults to last page.\n\n    :arg int start_at: First copied page, will become page number *start_at* in the target. Default -1 appends the page range to the end. If zero, the page range will be inserted before current first page.\n\n    :arg int rotate: All copied pages will be rotated by the provided value (degrees, integer multiple of 90).\n\n    :arg bool links: Choose whether (internal and external) links should be included in the copy. Default is `True`. *Named* links (:data:`LINK_NAMED`) and internal links to outside the copied page range are **always excluded**. \n    \n    :arg bool annots: choose whether annotations should be included in the copy.\n    \n    :arg bool widgets: choose whether annotations should be included in the copy. If `True` and at least one of the source pages contains form fields, the target PDF will be turned into a Form PDF (if not already being one).\n    \n    :arg bool join_duplicates: *(New in version 1.25.5)* Choose how to handle duplicate root field names in the source pages. This parameter is ignored if `widgets=False`.\n    \n      Default is ``False`` which will add unifying strings to the name of those source root fields which have a duplicate in the target. For instance, if \"name\" already occurs in the target, the source widget's name will be changed to \"name [text]\" with a suitably chosen string \"text\".\n\n      If ``True``, root fields with duplicate names in source and target will be converted to so-called \"Kids\" of a \"Parent\" object (which lists all kid widgets in a PDF array). This will effectively turn those kids into instances of the \"same\" widget: if e.g. one of the kids is changed, then all its instances will automatically inherit this change -- no matter on which page they happen to be displayed.\n    \n    :arg int show_progress: *(new in v1.17.7)* specify an interval size greater zero to see progress messages on `sys.stdout`. After each interval, a message like `Inserted 30 of 47 pages.` will be printed.\n    \n    :arg int final: *(new in v1.18.0)* controls whether the list of already copied objects should be **dropped** after this method, default ``True``. Set it to 0 except for the last one of multiple insertions from the same source PDF. This saves target file size and speeds up execution considerably.\n\n  .. note::\n\n     1. This is a page-based method. Document-level information of source documents is therefore mostly ignored. Examples include Optional Content, Embedded Files, `StructureElem`, table of contents, page labels, metadata, named destinations (and other named entries) and some more.\n\n     2. If `from_page > to_page`, pages will be **copied in reverse order**. If `0 <= from_page == to_page`, then one page will be copied.\n\n     3. `docsrc` TOC entries **will not be copied**. It is easy however, to recover a table of contents for the resulting document. Look at the examples below and at program `join.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py>`_ in the *examples* directory: it can join PDF documents and at the same time piece together respective parts of the tables of contents.\n\n\n  .. index::\n     pair: append; Document.insert_file\n     pair: join; Document.insert_file\n     pair: merge; Document.insert_file\n     pair: from_page; Document.insert_file\n     pair: to_page; Document.insert_file\n     pair: start_at; Document.insert_file\n     pair: rotate; Document.insert_file\n     pair: links; Document.insert_file\n     pair: annots; Document.insert_file\n     pair: show_progress; Document.insert_file\n\n  .. method:: insert_file(infile, from_page=-1, to_page=-1, start_at=-1, rotate=-1, links=True, annots=True, show_progress=0, final=1)\n\n    * New in v1.22.0\n\n    PDF only: Add an arbitrary supported document to the current PDF. Opens \"infile\" as a document, converts it to a PDF and then invokes :meth:`Document.insert_pdf`. Parameters are the same as for that method. Among other things, this features an easy way to append images as full pages to an output PDF.\n\n    :arg multiple infile: the input document to insert. May be a filename specification as is valid for creating a :ref:`Document` or a :ref:`Pixmap`.\n\n\n  .. index::\n     pair: width; Document.new_page\n     pair: height; Document.new_page\n\n  .. method:: new_page(pno=-1, width=595, height=842)\n\n    PDF only: Insert an empty page.\n\n    :arg int pno: page number index (zero-indexed) at which to insert page. Special values -1 and *doc.page_count* insert **after** the last page.\n\n    :arg float width: page width.\n    :arg float height: page height.\n\n    :rtype: :ref:`Page`\n    :returns: the created page object. Be aware that the page numbers of pages after the inserted one will have changed after method execution. For the same reason, **all existing page objects will be invalidated.** Using them will lead to exceptions.\n\n  .. index::\n     pair: fontsize; Document.insert_page\n     pair: width; Document.insert_page\n     pair: height; Document.insert_page\n     pair: fontname; Document.insert_page\n     pair: fontfile; Document.insert_page\n     pair: color; Document.insert_page\n\n  .. method:: insert_page(pno, text=None, fontsize=11, width=595, height=842, fontname=\"helv\", fontfile=None, color=None)\n\n    PDF only: Insert a new page and insert some text. Convenience function which combines :meth:`Document.new_page` and (parts of) :meth:`Page.insert_text`.\n\n    :arg int pno: page number index (zero-indexed) at which to insert page. Special values -1 and `doc.page_count` insert **after** the last page.\n\n        Changed in v1.14.12\n           This is now a positional parameter\n\n    For the other parameters, please consult the aforementioned methods.\n\n    :rtype: int\n    :returns: the result of :meth:`Page.insert_text` (number of successfully inserted lines).\n\n  .. method:: delete_page(pno=-1)\n\n    PDF only: Delete a page given by its 0-based number in `-∞ < pno < page_count`.\n\n    * Changed in v1.18.14: support Python's `del` statement.\n\n    :arg int pno: the page to be deleted. Negative number count backwards from the end of the document (like with indices). Default is the last page.\n\n  .. method:: delete_pages(*args, **kwds)\n\n    * Changed in v1.18.13: more flexibility specifying pages to delete.\n    * Changed in v1.18.14: support Python's `del` statement.\n\n    PDF only: Delete multiple pages given as 0-based numbers.\n\n    **Format 1:** Use keywords. Represents the old format. A contiguous range of pages is removed.\n      * \"from_page\": first page to delete. Zero if omitted.\n      * \"to_page\": last page to delete. Last page in document if omitted. Must not be less then \"from_page\".\n\n    **Format 2:** Two page numbers as positional parameters. Handled like Format 1.\n\n    **Format 3:** One positional integer parameter. Equivalent to :meth:`Page.delete_page`.\n\n    **Format 4:** One positional parameter of type *list*, *tuple* or *range()* of page numbers. The items of this sequence may be in any order and may contain duplicates.\n\n    **Format 5:** *(New in v1.18.14)* Using the Python `del` statement and index / slice notation is now possible.\n\n    .. note::\n\n      *(Changed in v1.14.17, optimized in v1.17.7)* In an effort to maintain a valid PDF structure, this method and :meth:`delete_page` will also deactivate items in the table of contents which point to deleted pages. \"Deactivation\" here means, that the bookmark will point to nowhere and the title will be shown grayed-out by supporting PDF viewers. The overall TOC structure is left intact.\n\n      It will also remove any **links on remaining pages** which point to a deleted one. This action may have an extended response time for documents with many pages.\n\n      Following examples will all delete pages 500 through 519:\n\n      * `doc.delete_pages(500, 519)`\n      * `doc.delete_pages(from_page=500, to_page=519)`\n      * `doc.delete_pages((500, 501, 502, ... , 519))`\n      * `doc.delete_pages(range(500, 520))`\n      * `del doc[500:520]`\n      * `del doc[(500, 501, 502, ... , 519)]`\n      * `del doc[range(500, 520)]`\n\n      For the :ref:`AdobeManual` the above takes about 0.6 seconds, because the remaining 1290 pages must be cleaned from invalid links.\n\n      In general, the performance of this method is dependent on the number of remaining pages -- **not** on the number of deleted pages: in the above example, **deleting all pages except** those 20, will need much less time.\n\n\n  .. method:: copy_page(pno, to=-1)\n\n    PDF only: Copy a page reference within the document.\n\n    :arg int pno: the page to be copied. Must be in range `0 <= pno < page_count`.\n\n    :arg int to: the page number in front of which to copy. The default inserts **after** the last page.\n\n    .. note:: Only a new **reference** to the page object will be created -- not a new page object, all copied pages will have identical attribute values, including the :attr:`Page.xref`. This implies that any changes to one of these copies will appear on all of them.\n\n  .. method:: fullcopy_page(pno, to=-1)\n\n    * New in v1.14.17\n\n    PDF only: Make a full copy (duplicate) of a page.\n\n    :arg int pno: the page to be duplicated. Must be in range `0 <= pno < page_count`.\n\n    :arg int to: the page number in front of which to copy. The default inserts **after** the last page.\n\n    .. note::\n\n        * In contrast to :meth:`copy_page`, this method creates a new page object (with a new :data:`xref`), which can be changed independently from the original.\n\n        * Any Popup and \"IRT\" (\"in response to\") annotations are **not copied** to avoid potentially incorrect situations.\n\n  .. method:: move_page(pno, to=-1)\n\n    PDF only: Move (copy and then delete original) a page within the document.\n\n    :arg int pno: the page to be moved. Must be in range `0 <= pno < page_count`.\n\n    :arg int to: the page number in front of which to insert the moved page. The default moves **after** the last page.\n\n\n  .. method:: need_appearances(value=None)\n\n    * New in v1.17.4\n\n    PDF only: Get or set the */NeedAppearances* property of Form PDFs. Quote: *\"(Optional) A flag specifying whether to construct appearance streams and appearance dictionaries for all widget annotations in the document ... Default value: false.\"* This may help controlling the behavior of some readers / viewers.\n\n    :arg bool value: set the property to this value. If omitted or `None`, inquire the current value.\n\n    :rtype: bool\n    :returns:\n       * None: not a Form PDF, or property not defined.\n       * True / False: the value of the property (either just set or existing for inquiries). Has no effect if no Form PDF.\n\n\n\n  .. method:: get_sigflags()\n\n    PDF only: Return whether the document contains signature fields. This is an optional PDF property: if not present (return value -1), no conclusions can be drawn -- the PDF creator may just not have bothered using it.\n\n    :rtype: int\n    :returns:\n       * -1: not a Form PDF / no signature fields recorded / no *SigFlags* found.\n       * 1: at least one signature field exists.\n       * 3:  contains signatures that may be invalidated if the file is saved (written) in a way that alters its previous contents, as opposed to an incremental update.\n\n  .. index::\n     pair: filename; Document.embfile_add\n     pair: ufilename; Document.embfile_add\n     pair: desc; Document.embfile_add\n\n  .. method:: embfile_add(name, buffer, filename=None, ufilename=None, desc=None)\n\n    * Changed in v1.14.16: The sequence of positional parameters \"name\" and \"buffer\" has been changed to comply with the call pattern of other functions.\n\n    PDF only: Embed a new file. All string parameters except the name may be unicode (in previous versions, only ASCII worked correctly). File contents will be compressed (where beneficial).\n\n    :arg str name: entry identifier, **must not already exist**.\n    :arg bytes,bytearray,BytesIO buffer: file contents.\n\n       *(Changed in v1.14.13)* *io.BytesIO* is now also supported.\n\n    :arg str filename: optional filename. Documentation only, will be set to *name* if `None`.\n    :arg str ufilename: optional unicode filename. Documentation only, will be set to *filename* if `None`.\n    :arg str desc: optional description. Documentation only, will be set to *name* if `None`.\n\n    :rtype: int\n    :returns: *(Changed in v1.18.13)* The method now returns the :data:`xref` of the inserted file. In addition, the file object now will be automatically given the PDF keys `/CreationDate` and `/ModDate` based on the current date-time.\n\n\n  .. method:: embfile_count()\n\n    * Changed in v1.14.16: This is now a method. In previous versions, this was a property.\n\n    PDF only: Return the number of embedded files.\n\n  .. method:: embfile_get(item)\n\n    PDF only: Retrieve the content of embedded file by its entry number or name. If the document is not a PDF, or entry cannot be found, an exception is raised.\n\n    :arg int,str item: index or name of entry. An integer must be in `range(embfile_count())`.\n\n    :rtype: bytes\n\n  .. method:: embfile_del(item)\n\n    * Changed in v1.14.16: Items can now be deleted by index, too.\n\n    PDF only: Remove an entry from `/EmbeddedFiles`. As always, physical deletion of the embedded file content (and file space regain) will occur only when the document is saved to a new file with a suitable garbage option.\n\n    :arg int/str item: index or name of entry.\n\n    .. warning:: When specifying an entry name, this function will only **delete the first item** with that name. Be aware that PDFs not created with PyMuPDF may contain duplicate names. So you may want to take appropriate precautions.\n\n  .. method:: embfile_info(item)\n\n    * Changed in v1.18.13\n\n    PDF only: Retrieve information of an embedded file given by its number or by its name.\n\n    :arg int/str item: index or name of entry. An integer must be in `range(embfile_count())`.\n\n    :rtype: dict\n    :returns: a dictionary with the following keys:\n\n        * ``name`` -- (*str*) name under which this entry is stored\n        * ``filename`` -- (*str*) filename\n        * ``ufilename`` -- (*unicode*) filename\n        * ``description`` -- (*str*) description\n        * ``size`` -- (*int*) original file size\n        * ``length`` -- (*int*) compressed file length\n        * ``creationDate`` -- (*str*) date-time of item creation in PDF format\n        * ``modDate`` -- (*str*) date-time of last change in PDF format\n        * ``collection`` -- (*int*) :data:`xref` of the associated PDF portfolio item if any, else zero.\n        * ``checksum`` -- (*str*) a hashcode of the stored file content as a hexadecimal string. Should be MD5 according to PDF specifications, but be prepared to see other hashing algorithms.\n\n  .. method:: embfile_names()\n\n    PDF only: Return a list of embedded file names. The sequence of the names equals the physical sequence in the document.\n\n    :rtype: list\n\n  .. index::\n     pair: filename; Document.embfile_upd\n     pair: ufilename; Document.embfile_upd\n     pair: desc; Document.embfile_upd\n\n  .. method:: embfile_upd(item, buffer=None, filename=None, ufilename=None, desc=None)\n\n    PDF only: Change an embedded file given its entry number or name. All parameters are optional. Letting them default leads to a no-operation.\n\n    :arg int/str item: index or name of entry. An integer must be in `range(embfile_count())`.\n    :arg bytes,bytearray,BytesIO buffer: the new file content.\n\n       *(Changed in v1.14.13)* *io.BytesIO* is now also supported.\n\n    :arg str filename: the new filename.\n    :arg str ufilename: the new unicode filename.\n    :arg str desc: the new description.\n\n    *(Changed in v1.18.13)*  The method now returns the :data:`xref` of the file object.\n\n    :rtype: int\n    :returns: xref of the file object. Automatically, its `/ModDate` PDF key will be updated with the current date-time.\n\n\n  .. method:: close()\n\n    Release objects and space allocations associated with the document. If created from a file, also closes *filename* (releasing control to the OS). Explicitly closing a document is equivalent to deleting it, `del doc`, or assigning it to something else like `doc = None`.\n\n  .. method:: xref_object(xref, compressed=False, ascii=False)\n\n    * New in v1.16.8\n    * Changed in v1.18.10\n\n    PDF only: Return the definition source of a PDF object.\n\n    :arg int xref: the object's :data:`xref`. *Changed in v1.18.10:* A value of `-1` returns the PDF trailer source.\n    :arg bool compressed: whether to generate a compact output with no line breaks or spaces.\n    :arg bool ascii: whether to ASCII-encode binary data.\n\n    :rtype: str\n    :returns: The object definition source.\n\n  .. method:: pdf_catalog()\n\n    * New in v1.16.8\n\n    PDF only: Return the :data:`xref` number of the PDF catalog (or root) object. Use that number with :meth:`Document.xref_object` to see its source.\n\n\n  .. method:: pdf_trailer(compressed=False)\n\n    * New in v1.16.8\n\n    PDF only: Return the trailer source of the PDF,  which is usually located at the PDF file's end. This is :meth:`Document.xref_object` with an :data:`xref` argument of -1.\n\n\n  .. method:: xref_stream(xref)\n\n    * New in v1.16.8\n\n    PDF only: Return the **decompressed** contents of the :data:`xref` stream object.\n\n    :arg int xref: :data:`xref` number.\n\n    :rtype: bytes\n    :returns: the (decompressed) stream of the object.\n\n  .. method:: xref_stream_raw(xref)\n\n    * New in v1.16.8\n\n    PDF only: Return the **unmodified** (esp. **not decompressed**) contents of the :data:`xref` stream object. Otherwise equal to :meth:`Document.xref_stream`.\n\n    :rtype: bytes\n    :returns: the (original, unmodified) stream of the object.\n\n  .. method:: update_object(xref, obj_str, page=None)\n\n    * New in v1.16.8\n\n    PDF only: Replace object definition of :data:`xref` with the provided string. The xref may also be new, in which case this instruction completes the object definition. If a page object is also given, its links and annotations will be reloaded afterwards.\n\n    :arg int xref: :data:`xref` number.\n\n    :arg str obj_str: a string containing a valid PDF object definition.\n\n    :arg page: a page object. If provided, indicates, that annotations of this page should be refreshed (reloaded) to reflect changes incurred with links and / or annotations.\n    :type page: :ref:`Page`\n\n    :rtype: int\n    :returns: zero if successful, otherwise an exception will be raised.\n\n\n  .. method:: update_stream(xref, data, new=False, compress=True)\n\n    * New in v.1.16.8\n    * Changed in v1.19.2: added parameter \"compress\"\n    * Changed in v1.19.6: deprecated parameter \"new\". Now confirms that the object is a PDF dictionary object.\n\n    Replace the stream of an object identified by :data:`xref`, which must be a PDF dictionary. If the object is no :data:`stream`, it will be turned into one. The function automatically performs a compress operation (\"deflate\") where beneficial.\n\n    :arg int xref: :data:`xref` number.\n\n    :arg bytes|bytearray|BytesIO stream: the new content of the stream.\n\n       *(Changed in v1.14.13:)* *io.BytesIO* objects are now also supported.\n\n    :arg bool new: *deprecated* and ignored. Will be removed some time after v1.20.0.\n    :arg bool compress: whether to compress the inserted stream. If `True` (default), the stream will be inserted using `/FlateDecode` compression (if beneficial), otherwise the stream will inserted as is.\n\n    :raises ValueError: if :data:`xref` does not represent a PDF :data:`dict`. An empty dictionary ``<<>>`` is accepted. So if you just created the xref and want to give it a stream, first execute `doc.update_object(xref, \"<<>>\")`, and then insert the stream data with this method.\n\n    The method is primarily (but not exclusively) intended to manipulate streams containing PDF operator syntax (see pp. 643 of the :ref:`AdobeManual`) as it is the case for e.g. page content streams.\n\n    If you update a contents stream, consider using save parameter *clean=True* to ensure consistency between PDF operator source and the object structure.\n\n    Example: Let us assume that you no longer want a certain image appear on a page. This can be achieved by deleting the respective reference in its contents source(s) -- and indeed: the image will be gone after reloading the page. But the page's :data:`resources` object would still show the image as being referenced by the page. This save option will clean up any such mismatches.\n\n\n  .. method:: Document.xref_copy(source, target, *, keep=None)\n\n    * New in v1.19.5\n\n    PDF Only: Make ``target`` xref an exact copy of ``source``. If ``source`` is a :data:`stream`, then this data is also copied.\n\n    :arg int source: the source :data:`xref`. It must be an existing **dictionary** object.\n    :arg int target: the target xref. Must be an existing **dictionary** object. If the xref has just been created, make sure to initialize it as a PDF dictionary with the minimum specification ``<<>>``.\n    :arg list keep: an optional list of top-level keys in ``target``, that should not be removed in preparation of the copy process.\n\n    .. note::\n\n        * This method has much in common with Python's *dict* method `copy()`.\n        * Both xref numbers must represent existing dictionaries.\n        * Before data is copied from *source*, all *target* dictionary keys are deleted. You can specify exceptions from this in the ``keep`` list. If *source* however has a same-named key, its value will still replace the target.\n        * If ``source`` is a :data:`stream` object, then these data will also be copied over, and ``target`` will be converted to a stream object.\n        * A typical use case is to replace or remove an existing image without using redaction annotations. Example scripts can be seen `in this PyMuPDF Utilities example <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/replace-image>`_.\n\n  .. method:: Document.extract_image(xref)\n\n    PDF Only: Extract data and meta information of an image stored in the document. The output can directly be used to be stored as an image file, as input for PIL, :ref:`Pixmap` creation, etc. This method avoids using pixmaps wherever possible to present the image in its original format (e.g. as JPEG).\n\n    :arg int xref: :data:`xref` of an image object. If this is not in `range(1, doc.xref_length())`, or the object is no image or other errors occur, `None` is returned and no exception is raised.\n\n    :rtype: dict\n    :returns: a dictionary with the following keys\n\n      * *ext* (*str*) image type (e.g. *'jpeg'*), usable as image file extension\n      * *smask* (*int*) :data:`xref` number of a stencil (/SMask) image or zero\n      * ``width`` (*int*) image width\n      * ``height`` (*int*) image height\n      * *colorspace* (*int*) the image's *colorspace.n* number.\n      * *cs-name* (*str*) the image's *colorspace.name*.\n      * *xres* (*int*) resolution in x direction. Please also see :data:`resolution`.\n      * *yres* (*int*) resolution in y direction. Please also see :data:`resolution`.\n      * *image* (*bytes*) image data, usable as image file content\n\n    >>> d = doc.extract_image(1373)\n    >>> d\n    {'ext': 'png', 'smask': 2934, 'width': 5, 'height': 629, 'colorspace': 3, 'xres': 96,\n    'yres': 96, 'cs-name': 'DeviceRGB',\n    'image': b'\\x89PNG\\r\\n\\x1a\\n\\x00\\x00\\x00\\rIHDR\\x00\\x00\\x00\\x05\\ ...'}\n    >>> imgout = open(f\"image.{d['ext']}\", \"wb\")\n    >>> imgout.write(d[\"image\"])\n    102\n    >>> imgout.close()\n\n    .. note:: There is a functional overlap with *pix = pymupdf.Pixmap(doc, xref)*, followed by a *pix.tobytes()*. Main differences are that extract_image, **(1)** does not always deliver PNG image formats, **(2)** is **very** much faster with non-PNG images, **(3)** usually results in much less disk storage for extracted images, **(4)** returns `None` in error cases (generates no exception). Look at the following example images within the same PDF.\n\n       * xref 1268 is a PNG -- Comparable execution time and identical output::\n\n          In [23]: %timeit pix = pymupdf.Pixmap(doc, 1268);pix.tobytes()\n          10.8 ms ± 52.4 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n          In [24]: len(pix.tobytes())\n          Out[24]: 21462\n\n          In [25]: %timeit img = doc.extract_image(1268)\n          10.8 ms ± 86 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n          In [26]: len(img[\"image\"])\n          Out[26]: 21462\n\n       * xref 1186 is a JPEG -- :meth:`Document.extract_image` is **many times faster** and produces a **much smaller** output (2.48 MB vs. 0.35 MB)::\n\n          In [27]: %timeit pix = pymupdf.Pixmap(doc, 1186);pix.tobytes()\n          341 ms ± 2.86 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)\n          In [28]: len(pix.tobytes())\n          Out[28]: 2599433\n\n          In [29]: %timeit img = doc.extract_image(1186)\n          15.7 µs ± 116 ns per loop (mean ± std. dev. of 7 runs, 100000 loops each)\n          In [30]: len(img[\"image\"])\n          Out[30]: 371177\n\n\n  .. method:: Document.extract_font(xref, info_only=False, named=None)\n\n    * Changed in v1.19.4: return a dictionary if `named == True`.\n\n    PDF Only: Return an embedded font file's data and appropriate file extension. This can be used to store the font as an external file. The method does not throw exceptions (other than via checking for PDF and valid :data:`xref`).\n\n    :arg int xref: PDF object number of the font to extract.\n    :arg bool info_only: only return font information, not the buffer. To be used for information-only purposes, avoids allocation of large buffer areas.\n    :arg bool named: If true, a dictionary with the following keys is returned: 'name' (font base name), 'ext' (font file extension), 'type' (font type), 'content' (font file content).\n\n    :rtype: tuple,dict\n    :returns: a tuple `(basename, ext, type, content)`, where *ext* is a 3-byte suggested file extension (*str*), *basename* is the font's name (*str*), *type* is the font's type (e.g. \"Type1\") and *content* is a bytes object containing the font file's content (or *b\"\"*). For possible extension values and their meaning see :ref:`FontExtensions`. Return details on error:\n\n          * `(\"\", \"\", \"\", b\"\")` -- invalid xref or xref is not a (valid) font object.\n          * `(basename, \"n/a\", \"Type1\", b\"\")` -- *basename* is not embedded and thus cannot be extracted. This is the case for e.g. the :ref:`Base-14-Fonts` and Type 3 fonts.\n\n    Example:\n\n    >>> # store font as an external file\n    >>> name, ext, _, content = doc.extract_font(4711)\n    >>> # assuming content is not None:\n    >>> ofile = open(name + \".\" + ext, \"wb\")\n    >>> ofile.write(content)\n    >>> ofile.close()\n\n    .. warning:: The basename is returned unchanged from the PDF. So it may contain characters (such as blanks) which may disqualify it as a filename for your operating system. Take appropriate action.\n\n    .. note::\n       * The returned *basename* in general is **not** the original file name, but it probably has some similarity.\n       * If parameter `named == True`, a dictionary with the following keys is returned: `{'name': 'T1', 'ext': 'n/a', 'type': 'Type3', 'content': b''}`.\n\n\n  .. method:: xref_xml_metadata()\n\n    * New in v1.16.8\n\n    PDF only: Return the :data:`xref` of the document's XML metadata.\n\n\n  .. method:: has_links()\n\n  .. method:: has_annots()\n\n    * New in v1.18.7\n\n    PDF only: Check whether there are links, resp. annotations anywhere in the document.\n\n    :returns: ``True`` / ``False``. As opposed to fields, which are also stored in a central place of a PDF document, the existence of links / annotations can only be detected by parsing each page. These methods are tuned to do this efficiently and will immediately return, if the answer is ``True`` for a page. For PDFs with many thousand pages however, an answer may take some time [#f6]_ if no link, resp. no annotation is found.\n\n\n  .. method:: subset_fonts(verbose=False, fallback=False)\n\n    PDF only: Investigate eligible fonts for their use by text in the document. If a font is supported and a size reduction is possible, that font is replaced by a version with a subset of its characters.\n\n    Use this method immediately before saving the document.\n\n    :arg bool verbose: write various progress information to sysout. This currently only has an effect if `fallback` is `True`.\n    :arg bool fallback: if `True` use the deprecated algorithm that makes use of package `fontTools <https://pypi.org/project/fonttools/>`_ (which hence must be installed). If using the recommended value `False` (default), MuPDF's native function is used -- which is **very much faster** and can subset a broader range of font types. Package fontTools is not required then.\n\n    The greatest benefit can be achieved when creating new PDFs using large fonts like is typical for Asian scripts. When using the :ref:`Story` class or method :meth:`Page.insert_htmlbox`, multiple fonts may automatically be included -- without the programmer becoming aware of it.\n    \n    In all these cases, the set of actually used unicodes mostly is very small compared to the number of glyphs available in the used fonts. Using this method can easily reduce the embedded font binaries by two orders of magnitude -- from several megabytes down to a low two-digit kilobyte amount.\n\n    Creating font subsets leaves behind a large number of large, now unused PDF objects (\"ghosts\"). Therefore, make sure to compress and garbage-collect when saving the file. We recommend to use :meth:`Document.ez_save`.\n\n    |history_begin|\n\n    * New in v1.18.7\n    * Changed in v1.18.9\n    * Changed in v1.24.2 use native function of MuPDF.\n\n    |history_end|\n\n\n  .. method:: journal_enable()\n\n    * New in v1.19.0\n\n    PDF only: Enable journalling. Use this before you start logging operations.\n\n  .. method:: journal_start_op(name)\n\n    * New in v1.19.0\n\n    PDF only: Start journalling an *\"operation\"* identified by a string \"name\". Updates will fail for a journal-enabled PDF, if no operation has been started.\n\n\n  .. method:: journal_stop_op()\n\n    * New in v1.19.0\n\n    PDF only: Stop the current operation. The updates between start and stop of an operation belong to the same unit of work and will be undone / redone together.\n\n\n  .. method:: journal_position()\n\n    * New in v1.19.0\n\n    PDF only: Return the numbers of the current operation and the total operation count.\n\n    :returns: a tuple `(step, steps)` containing the current operation number and the total number of operations in the journal. If **step** is 0, we are at the top of the journal. If **step** equals **steps**, we are at the bottom. Updating the PDF with anything other than undo or redo will automatically remove all journal entries after the current one and the new update will become the new last entry in the journal. The updates corresponding to the removed journal entries will be permanently lost.\n\n\n  .. method:: journal_op_name(step)\n\n    * New in v1.19.0\n\n    PDF only: Return the name of operation number *step.*\n\n\n  .. method:: journal_can_do()\n\n    * New in v1.19.0\n\n    PDF only: Show whether forward (\"redo\") and / or backward (\"undo\") executions are possible from the current journal position.\n\n    :returns: a dictionary `{\"undo\": bool, \"redo\": bool}`. The respective method is available if its value is `True`.\n\n\n  .. method:: journal_undo()\n\n    * New in v1.19.0\n\n    PDF only: Revert (undo) the current step in the journal. This moves towards the journal's top.\n\n\n  .. method:: journal_redo()\n\n    * New in v1.19.0\n\n    PDF only: Re-apply (redo) the current step in the journal. This moves towards the journal's bottom.\n\n\n  .. method:: journal_save(filename)\n\n    * New in v1.19.0\n\n    PDF only: Save the journal to a file.\n\n    :arg str,fp filename: either a filename as string or a file object opened as \"wb\" (or an `io.BytesIO()` object).\n\n\n  .. method:: journal_load(filename)\n\n    * New in v1.19.0\n\n    PDF only: Load journal from a file. Enables journalling for the document. If journalling is already enabled, an exception is raised.\n\n    :arg str,fp filename: the filename (str) of the journal or a file object opened as \"rb\" (or an `io.BytesIO()` object).\n\n\n  .. method:: save_snapshot()\n\n    * New in v1.19.0\n\n    PDF only: Saves a \"snapshot\" of the document. This is a PDF document with a special, incremental-save format compatible with journalling -- therefore no save options are available. Saving a snapshot is not possible for new documents.\n\n    This is a normal PDF document with no usage restrictions whatsoever. If it is not being changed in any way, it can be used together with its journal to undo / redo operations or continue updating.\n\n\n  .. attribute:: outline\n\n    Contains the first :ref:`Outline` entry of the document (or `None`). Can be used as a starting point to walk through all outline items. Accessing this property for encrypted, not authenticated documents will raise an *AttributeError*.\n\n    :type: :ref:`Outline`\n\n  .. attribute:: is_closed\n\n    ``False`` if document is still open. If closed, most other attributes and methods will have been deleted / disabled. In addition, :ref:`Page` objects referring to this document (i.e. created with :meth:`Document.load_page`) and their dependent objects will no longer be usable. For reference purposes, :attr:`Document.name` still exists and will contain the filename of the original document (if applicable).\n\n    :type: bool\n\n  .. attribute:: is_dirty\n\n    ``True`` if this is a PDF document and contains unsaved changes, else ``False``.\n\n    :type: bool\n\n  .. attribute:: is_pdf\n\n    ``True`` if this is a PDF document, else ``False``.\n\n    :type: bool\n\n  .. attribute:: is_form_pdf\n\n    ``False`` if this is not a PDF or has no form fields, otherwise the number of root form fields (fields with no ancestors).\n\n    *(Changed in v1.16.4)* Returns the total number of (root) form fields.\n\n    :type: bool,int\n\n  .. attribute:: is_reflowable\n\n    ``True`` if document has a variable page layout (like e-books or HTML). In this case you can set the desired page dimensions during document creation (open) or via method :meth:`layout`.\n\n    :type: bool\n\n  .. attribute:: is_repaired\n\n    * New in v1.18.2\n\n    ``True`` if PDF has been repaired during open (because of major structure issues). Always ``False`` for non-PDF documents. If true, more details have been stored in `TOOLS.mupdf_warnings()`, and :meth:`Document.can_save_incrementally` will return ``False``.\n\n    :type: bool\n\n  .. attribute:: is_fast_webaccess\n\n    * New in v1.22.2\n\n    ``True`` if PDF is in linearized format. ``False`` for non-PDF documents.\n\n    :type: bool\n\n  .. attribute:: markinfo\n\n    * New in v1.22.2\n\n    A dictionary indicating the `/MarkInfo` value. If not specified, the empty dictionary is returned. If not a PDF, `None` is returned.\n\n    :type: dict\n\n  .. attribute:: pagemode\n\n    * New in v1.22.2\n\n    A string containing the `/PageMode` value. If not specified, the default \"UseNone\" is returned. If not a PDF, `None` is returned.\n\n    :type: str\n\n  .. attribute:: pagelayout\n\n    * New in v1.22.2\n\n    A string containing the `/PageLayout` value. If not specified, the default \"SinglePage\" is returned. If not a PDF, `None` is returned.\n\n    :type: str\n\n  .. attribute:: version_count\n\n    * New in v1.22.2\n\n    An integer counting the number of versions present in the document. Zero if not a PDF, otherwise the number of incremental saves plus one.\n\n    :type: int\n\n  .. attribute:: needs_pass\n\n    Indicates whether the document is password-protected against access. This indicator remains unchanged -- **even after the document has been authenticated**. Precludes incremental saves if true.\n\n    :type: bool\n\n  .. attribute:: is_encrypted\n\n    This indicator initially equals :attr:`Document.needs_pass`. After successful authentication, it is set to ``False`` to reflect the situation.\n\n    :type: bool\n\n  .. attribute:: permissions\n\n    * Changed in v1.16.0: This is now an integer comprised of bit indicators. Was a dictionary previously.\n\n    Contains the permissions to access the document. This is an integer containing bool values in respective bit positions. For example, if *doc.permissions & pymupdf.PDF_PERM_MODIFY > 0*, you may change the document. See :ref:`PermissionCodes` for details.\n\n    :type: int\n\n  .. attribute:: metadata\n\n    Contains the document's meta data as a Python dictionary or `None` (if *is_encrypted=True* and *needPass=True*). Keys are *format*, *encryption*, *title*, *author*, *subject*, *keywords*, *creator*, *producer*, *creationDate*, *modDate*, *trapped*. All item values are strings or `None`.\n\n    Except *format* and *encryption*, for PDF documents, the key names correspond in an obvious way to the PDF keys */Creator*, */Producer*, */CreationDate*, */ModDate*, */Title*, */Author*, */Subject*, */Trapped* and */Keywords* respectively.\n\n    - *format* contains the document format (e.g. 'PDF-1.6', 'XPS', 'EPUB').\n\n    - *encryption* either contains `None` (no encryption), or a string naming an encryption method (e.g. *'Standard V4 R4 128-bit RC4'*). Note that an encryption method may be specified **even if** *needs_pass=False*. In such cases not all permissions will probably have been granted. Check :attr:`Document.permissions` for details.\n\n    - If the date fields contain valid data (which need not be the case at all!), they are strings in the PDF-specific timestamp format \"D:<TS><TZ>\", where\n\n        - <TS> is the 12 character ISO timestamp *YYYYMMDDhhmmss* (*YYYY* - year, *MM* - month, *DD* - day, *hh* - hour, *mm* - minute, *ss* - second), and\n\n        - <TZ> is a time zone value (time interval relative to GMT) containing a sign ('+' or '-'), the hour (*hh*), and the minute (*'mm'*, note the apostrophes!).\n\n    - A Paraguayan value might hence look like *D:20150415131602-04'00'*, which corresponds to the timestamp April 15, 2015, at 1:16:02 pm local time Asuncion.\n\n    :type: dict\n\n  .. Attribute:: name\n\n    Contains the *filename* or *filetype* value with which *Document* was created.\n\n    :type: str\n\n  .. Attribute:: page_count\n\n    Contains the number of pages of the document. May return 0 for documents with no pages. Function `len(doc)` will also deliver this result.\n\n    :type: int\n\n  .. Attribute:: chapter_count\n\n    * New in v1.17.0\n\n    Contains the number of chapters in the document. Always at least 1. Relevant only for document types with chapter support (EPUB currently). Other documents will return 1.\n\n    :type: int\n\n  .. Attribute:: last_location\n\n    * New in v1.17.0\n\n    Contains (chapter, pno) of the document's last page. Relevant only for document types with chapter support (EPUB currently). Other documents will return `(0, page_count - 1)` and `(0, -1)` if it has no pages.\n\n    :type: int\n\n  .. Attribute:: FormFonts\n\n    A list of form field font names defined in the */AcroForm* object. `None` if not a PDF.\n\n    :type: list\n\n.. NOTE:: For methods that change the structure of a PDF (:meth:`insert_pdf`, :meth:`select`, :meth:`copy_page`, :meth:`delete_page` and others), be aware that objects or properties in your program may have been invalidated or orphaned. Examples are :ref:`Page` objects and their children (links, annotations, widgets), variables holding old page counts, tables of content and the like. Remember to keep such variables up to date or delete orphaned objects. Also refer to :ref:`ReferenialIntegrity`.\n\n:meth:`set_metadata` Example\n-------------------------------\nClear metadata information. If you do this out of privacy / data protection concerns, make sure you save the document as a new file with *garbage > 0*. Only then the old */Info* object will also be physically removed from the file. In this case, you may also want to clear any XML metadata inserted by several PDF editors:\n\n>>> import pymupdf\n>>> doc=pymupdf.open(\"pymupdf.pdf\")\n>>> doc.metadata             # look at what we currently have\n{'producer': 'rst2pdf, reportlab', 'format': 'PDF 1.4', 'encryption': None, 'author':\n'Jorj X. McKie', 'modDate': \"D:20160611145816-04'00'\", 'keywords': 'PDF, XPS, EPUB, CBZ',\n'title': 'The PyMuPDF Documentation', 'creationDate': \"D:20160611145816-04'00'\",\n'creator': 'sphinx', 'subject': 'PyMuPDF 1.9.1'}\n>>> doc.set_metadata({})      # clear all fields\n>>> doc.metadata             # look again to show what happened\n{'producer': 'none', 'format': 'PDF 1.4', 'encryption': None, 'author': 'none',\n'modDate': 'none', 'keywords': 'none', 'title': 'none', 'creationDate': 'none',\n'creator': 'none', 'subject': 'none'}\n>>> doc.del_xml_metadata()    # clear any XML metadata\n>>> doc.save(\"anonymous.pdf\", garbage = 4)       # save anonymized doc\n\n:meth:`set_toc` Demonstration\n----------------------------------\nThis shows how to modify or add a table of contents. Also have a look at `import.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/import-toc/import.py>`_ and `export.py <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/export-toc/export.py>`_ in the examples directory.\n\n>>> import pymupdf\n>>> doc = pymupdf.open(\"test.pdf\")\n>>> toc = doc.get_toc()\n>>> for t in toc: print(t)                           # show what we have\n[1, 'The PyMuPDF Documentation', 1]\n[2, 'Introduction', 1]\n[3, 'Note on the Name fitz', 1]\n[3, 'License', 1]\n>>> toc[1][1] += \" modified by set_toc\"               # modify something\n>>> doc.set_toc(toc)                                  # replace outline tree\n3                                                    # number of bookmarks inserted\n>>> for t in doc.get_toc(): print(t)                  # demonstrate it worked\n[1, 'The PyMuPDF Documentation', 1]\n[2, 'Introduction modified by set_toc', 1]            # <<< this has changed\n[3, 'Note on the Name fitz', 1]\n[3, 'License', 1]\n\n:meth:`insert_pdf` Examples\n----------------------------\n**(1) Concatenate two documents including their TOCs:**\n\n>>> doc1 = pymupdf.open(\"file1.pdf\")          # must be a PDF\n>>> doc2 = pymupdf.open(\"file2.pdf\")          # must be a PDF\n>>> pages1 = len(doc1)                     # save doc1's page count\n>>> toc1 = doc1.get_toc(False)     # save TOC 1\n>>> toc2 = doc2.get_toc(False)     # save TOC 2\n>>> doc1.insert_pdf(doc2)                   # doc2 at end of doc1\n>>> for t in toc2:                         # increase toc2 page numbers\n        t[2] += pages1                     # by old len(doc1)\n>>> doc1.set_toc(toc1 + toc2)               # now result has total TOC\n\nObviously, similar ways can be found in more general situations. Just make sure that hierarchy levels in a row do not increase by more than one. Inserting dummy bookmarks before and after *toc2* segments would heal such cases. A ready-to-use GUI (wxPython) solution can be found in script `join.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py>`_ of the examples directory.\n\n**(2) More examples:**\n\n>>> # insert 5 pages of doc2, where its page 21 becomes page 15 in doc1\n>>> doc1.insert_pdf(doc2, from_page=21, to_page=25, start_at=15)\n\n>>> # same example, but pages are rotated and copied in reverse order\n>>> doc1.insert_pdf(doc2, from_page=25, to_page=21, start_at=15, rotate=90)\n\n>>> # put copied pages in front of doc1\n>>> doc1.insert_pdf(doc2, from_page=21, to_page=25, start_at=0)\n\nOther Examples\n----------------\n**Extract all page-referenced images of a PDF into separate PNG files**::\n\n for i in range(doc.page_count):\n     imglist = doc.get_page_images(i)\n     for img in imglist:\n         xref = img[0]                  # xref number\n         pix = pymupdf.Pixmap(doc, xref)   # make pixmap from image\n         if pix.n - pix.alpha < 4:      # can be saved as PNG\n             pix.save(f\"p{i}-{xref}.png\")\n         else:                          # CMYK: must convert first\n             pix0 = pymupdf.Pixmap(pymupdf.csRGB, pix)\n             pix0.save(f\"p{i}-{xref}.png\")\n             pix0 = None                # free Pixmap resources\n         pix = None                     # free Pixmap resources\n\n**Rotate all pages of a PDF:**\n\n>>> for page in doc: page.set_rotation(90)\n\n.. rubric:: Footnotes\n\n.. [#f1] Content streams describe what (e.g. text or images) appears where and how on a page. PDF uses a specialized mini language similar to PostScript to do this (pp. 643 in :ref:`AdobeManual`), which gets interpreted when a page is loaded.\n\n.. [#f2] However, you **can** use :meth:`Document.get_toc` and :meth:`Page.get_links` (which are available for all document types) and copy this information over to the output PDF. See demo `convert.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/convert-document/convert.py>`_.\n\n.. [#f3] For applicable (EPUB) document types, loading a page via its absolute number may result in layouting a large part of the document, before the page can be accessed. To avoid this performance impact, prefer chapter-based access. Use convenience methods and attributes :meth:`Document.next_location`, :meth:`Document.prev_location` and :attr:`Document.last_location` for maintaining a high level of coding efficiency.\n\n.. [#f4] These parameters cause separate handling of stream categories: use it together with `expand` to restrict decompression to streams other than images / fontfiles.\n\n.. [#f5] Examples for \"Form XObjects\" are created by :meth:`Page.show_pdf_page`.\n\n.. [#f6] For a ``False`` the **complete document** must be scanned. Both methods **do not load pages,** but only scan object definitions. This makes them at least 10 times faster than application-level loops (where total response time roughly equals the time for loading all pages). For the :ref:`AdobeManual` (756 pages) and the Pandas documentation (over 3070 pages) -- both have no annotations -- the method needs about 11 ms for the answer ``False``. So response times will probably become significant only well beyond this order of magnitude.\n\n.. [#f7] This only works under certain conditions. For example, if there is normal text covered by some image on top of it, then this is undetectable and the respective text is **not** removed. Similar is true for white text on white background, and so on.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/extensions/__init__.py",
    "content": ""
  },
  {
    "path": "docs/extensions/fulltoc.py",
    "content": "# -*- encoding: utf-8 -*-\n#\n# Copyright © 2012 New Dream Network, LLC (DreamHost)\n#\n# Author: Doug Hellmann <doug.hellmann@dreamhost.com>\n#\n# Licensed under the Apache License, Version 2.0 (the \"License\"); you may\n# not use this file except in compliance with the License. You may obtain\n# a copy of the License at\n#\n#      http://www.apache.org/licenses/LICENSE-2.0\n#\n# Unless required by applicable law or agreed to in writing, software\n# distributed under the License is distributed on an \"AS IS\" BASIS, WITHOUT\n# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the\n# License for the specific language governing permissions and limitations\n# under the License.\n\n\nfrom sphinx import addnodes\n\n\ndef html_page_context(app, pagename, templatename, context, doctree):\n    \"\"\"Event handler for the html-page-context signal.\n    Modifies the context directly.\n     - Replaces the 'toc' value created by the HTML builder with one\n       that shows all document titles and the local table of contents.\n     - Sets display_toc to True so the table of contents is always\n       displayed, even on empty pages.\n     - Replaces the 'toctree' function with one that uses the entire\n       document structure, ignores the maxdepth argument, and uses\n       only prune and collapse.\n    \"\"\"\n    rendered_toc = get_rendered_toctree(app.builder, pagename)\n    context[\"toc\"] = rendered_toc\n    context[\"display_toc\"] = True  # force toctree to display\n\n    if \"toctree\" not in context:\n        # json builder doesn't use toctree func, so nothing to replace\n        return\n\n    def make_toctree(collapse=True, maxdepth=-1, includehidden=True):\n        return get_rendered_toctree(\n            app.builder,\n            pagename,\n            prune=False,\n            collapse=collapse,\n        )\n\n    context[\"toctree\"] = make_toctree\n\n\ndef get_rendered_toctree(builder, docname, prune=False, collapse=True):\n    \"\"\"Build the toctree relative to the named document,\n    with the given parameters, and then return the rendered\n    HTML fragment.\n    \"\"\"\n    fulltoc = build_full_toctree(\n        builder,\n        docname,\n        prune=prune,\n        collapse=collapse,\n    )\n    rendered_toc = builder.render_partial(fulltoc)[\"fragment\"]\n    return rendered_toc\n\n\ndef build_full_toctree(builder, docname, prune, collapse):\n    \"\"\"Return a single toctree starting from docname containing all\n    sub-document doctrees.\n    \"\"\"\n    env = builder.env\n    doctree = env.get_doctree(env.config.master_doc)\n    toctrees = []\n    for toctreenode in doctree.traverse(addnodes.toctree):\n        toctree = env.resolve_toctree(\n            docname,\n            builder,\n            toctreenode,\n            collapse=collapse,\n            prune=prune,\n            includehidden=True,\n        )\n        if toctree is not None:\n            toctrees.append(toctree)\n\n    if not toctrees:\n        return None\n    result = toctrees[0]\n    for toctree in toctrees[1:]:\n        if toctree:\n            result.extend(toctree.children)\n    env.resolve_references(result, docname, builder)\n    return result\n\n\ndef setup(app):\n    app.connect(\"html-page-context\", html_page_context)\n"
  },
  {
    "path": "docs/extensions/searchrepair.py",
    "content": "import os\r\n\r\n\r\ndef modify_search_index(app, exception):\r\n    if exception is None:  # build succeeded\r\n        filename = os.path.join(app.outdir, \"searchindex.js\")\r\n        if os.path.exists(filename):\r\n            searchfile = open(filename)\r\n            data1 = searchfile.read()\r\n            searchfile.close()\r\n            p1 = data1.find(\"filenames:[\")\r\n            p2 = data1.find(\"]\", p1)\r\n            s = data1[p1:p2].replace(\".txt\", \"\")\r\n            data2 = data1[:p1]\r\n            data2 += s\r\n            data2 += data1[p2:]\r\n            searchfile = open(filename, \"w\")\r\n            searchfile.write(data2)\r\n            searchfile.close()\r\n\r\n\r\ndef setup(app):\r\n    app.connect(\"build-finished\", modify_search_index)\r\n"
  },
  {
    "path": "docs/faq/index.rst",
    "content": "\n.. include:: ../header.rst\n\n\n\nFAQ\n=============\n\n\n.. raw:: html\n\n    <script>\n        document.getElementById(\"headerSearchWidget\").action = '../search.html';\n    </script>\n\n\n\n.. raw:: html\n\n    <link href=\"https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=JetBrains+Mono:wght@400;500&display=swap\" rel=\"stylesheet\">\n    <style>\n\n    :root {\n        --bg: #fff;\n        --surface: #f8f9fa;\n        --surface-hover: #e9ecef;\n        --border: #dee2e6;\n        --text: #0f1117;\n        --muted: #6c757d;\n        --accent: #d97706;\n        --accent-dim: rgba(217,119,6,0.08);\n        --code-bg: #f5f5f5;\n        --green: #16a34a;\n        --blue: #2563eb;\n        --red: #dc2626;\n        --purple: #9333ea;\n        --bgTransparent: rgba(255, 255, 255, 0.95);\n    }\n\n    @media (prefers-color-scheme: dark) {\n        :root {\n            --bg: #0f1117;\n            --surface: #181a24;\n            --surface-hover: #1e2130;\n            --border: #2a2d3e;\n            --text: #d8d8e0;\n            --muted: #9898a8;\n            --accent: #e8943a;\n            --accent-dim: rgba(232,148,58,0.12);\n            --code-bg: #141620;\n            --green: #4ade80;\n            --blue: #60a5fa;\n            --red: #f87171;\n            --purple: #c084fc;\n            --bgTransparent: rgba(15,17,23,0.95);\n        }\n    }\n\n    body[data-theme=\"light\"] {\n        --bg: #fff;\n        --surface: #f8f9fa;\n        --surface-hover: #e9ecef;\n        --border: #dee2e6;\n        --text: #0f1117;\n        --muted: #6c757d;\n        --accent: #d97706;\n        --accent-dim: rgba(217,119,6,0.08);\n        --code-bg: #f5f5f5;\n        --green: #16a34a;\n        --blue: #2563eb;\n        --red: #dc2626;\n        --purple: #9333ea;\n        --bgTransparent: rgba(255, 255, 255, 0.95);\n    }\n    \n    body[data-theme=\"dark\"] {\n        --bg: #0f1117;\n        --surface: #181a24;\n        --surface-hover: #1e2130;\n        --border: #2a2d3e;\n        --text: #d8d8e0;\n        --muted: #9898a8;\n        --accent: #e8943a;\n        --accent-dim: rgba(232,148,58,0.12);\n        --code-bg: #141620;\n        --green: #4ade80;\n        --blue: #60a5fa;\n        --red: #f87171;\n        --purple: #c084fc;\n        --bgTransparent: rgba(15,17,23,0.95);\n    }\n\n    \n\n    .toc-drawer {\n        display: none !important;\n    }\n\n    .main .content { \n        width:100% !important;\n    }\n\n    .main .content .container {\n        padding-top:0 !important;\n        margin-top:0 !important;\n    } \n\n    #nav {\n        position: sticky;\n        top: 0;\n        background: var(--bgTransparent);\n        padding-bottom: 12px;\n        border-bottom: 1px solid var(--border);\n    }\n\n    * { margin: 0; padding: 0; box-sizing: border-box; }\n\n    body {\n        font-family: 'IBM Plex Sans', -apple-system, sans-serif;\n        background: var(--bg);\n        color: var(--text);\n        font-size: 15px;\n        line-height: 1.75;\n        -webkit-font-smoothing: antialiased;\n    }\n\n    \n\n    .container {\n        max-width: 900px;\n        margin: 0 auto;\n        padding: 60px 24px;\n    }\n\n    /* Header */\n    .header {\n        margin-bottom: 56px;\n        padding-bottom: 40px;\n        border-bottom: 1px solid var(--border);\n    }\n\n    .header h1 {\n        font-size: 32px;\n        font-weight: 600;\n        letter-spacing: -0.5px;\n        margin-bottom: 12px;\n    }\n\n    .header .subtitle {\n        font-size: 16px;\n        color: var(--muted);\n        line-height: 1.7;\n        max-width: 700px;\n    }\n\n    .header .meta {\n        margin-top: 16px;\n        display: flex;\n        gap: 24px;\n        font-size: 13px;\n        color: var(--muted);\n    }\n\n    .header .meta .stat {\n        display: flex;\n        align-items: center;\n        gap: 6px;\n    }\n\n    .header .meta .stat strong {\n        color: var(--accent);\n        font-weight: 600;\n    }\n\n    /* Navigation */\n    .nav {\n        display: flex;\n        flex-wrap: wrap;\n        gap: 8px;\n        margin-bottom: 48px;\n    }\n\n    .nav a {\n        display: inline-block;\n        padding: 6px 14px;\n        background: var(--surface);\n        border: 1px solid var(--border);\n        border-radius: 6px;\n        color: var(--muted);\n        text-decoration: none;\n        font-size: 13px;\n        font-weight: 500;\n        transition: all 0.15s;\n    }\n\n    .nav a:hover {\n        color: var(--text);\n        border-color: var(--accent);\n        background: var(--accent-dim);\n    }\n\n    /* Section */\n    .section {\n        margin-bottom: 56px;\n    }\n\n    .section-header {\n        display: flex;\n        align-items: center;\n        gap: 12px;\n        margin-bottom: 28px;\n        padding-bottom: 12px;\n        border-bottom: 1px solid var(--border);\n    }\n\n    .section-header h2 {\n        font-size: 22px;\n        font-weight: 600;\n        letter-spacing: -0.3px;\n    }\n\n    .section-header .count {\n        font-size: 12px;\n        color: var(--accent);\n        background: var(--accent-dim);\n        padding: 2px 10px;\n        border-radius: 12px;\n        font-weight: 600;\n    }\n\n    /* FAQ Item */\n    .faq {\n        margin-bottom: 20px;\n        border: 1px solid var(--border);\n        border-radius: 10px;\n        overflow: hidden;\n        transition: border-color 0.15s;\n    }\n\n    .faq:hover { border-color: #3a3d52; }\n\n    .faq-q {\n        padding: 18px 22px;\n        background: var(--surface);\n        cursor: pointer;\n        display: flex;\n        align-items: flex-start;\n        gap: 12px;\n        user-select: none;\n    }\n\n    .faq-q:hover { background: var(--surface-hover); }\n\n    .faq-q .marker {\n        color: var(--accent);\n        font-weight: 600;\n        font-size: 15px;\n        flex-shrink: 0;\n        margin-top: 1px;\n    }\n\n    .faq-q .question {\n        font-weight: 500;\n        font-size: 15px;\n        line-height: 1.6;\n        flex: 1;\n    }\n\n    .faq-q .toggle {\n        color: var(--muted);\n        font-size: 18px;\n        flex-shrink: 0;\n        transition: transform 0.2s;\n        margin-top: 1px;\n    }\n\n    .faq.open .faq-q .toggle { transform: rotate(45deg); }\n\n    .faq-a {\n        display: none;\n        padding: 20px 22px 22px 48px;\n        border-top: 1px solid var(--border);\n        background: var(--bg);\n    }\n\n    .faq.open .faq-a { display: block; }\n\n    .faq-a p {\n        margin-bottom: 14px;\n        color: var(--text);\n        line-height: 1.8;\n    }\n\n    .faq-a p:last-child { margin-bottom: 0; }\n\n    .faq-a code {\n        font-family: 'JetBrains Mono', monospace;\n        font-size: 13px;\n        background: var(--code-bg);\n        border: 1px solid var(--border);\n        padding: 2px 6px;\n        border-radius: 4px;\n        color: var(--accent);\n    }\n\n    .faq-a pre {\n        background: var(--code-bg);\n        border: 1px solid var(--border);\n        border-radius: 8px;\n        padding: 16px 18px;\n        margin: 14px 0;\n        overflow-x: auto;\n    }\n\n    .faq-a pre code {\n        background: none;\n        border: none;\n        padding: 0;\n        font-size: 13px;\n        line-height: 1.7;\n        color: var(--text);\n    }\n\n    .faq-a .tip {\n        background: var(--accent-dim);\n        border-left: 3px solid var(--accent);\n        padding: 12px 16px;\n        border-radius: 0 6px 6px 0;\n        margin: 14px 0;\n        font-size: 14px;\n        color: var(--text);\n    }\n\n    .faq-a .tip strong { color: var(--accent); }\n\n    .faq-a a {\n        color: var(--blue);\n        text-decoration: none;\n        border-bottom: 1px solid transparent;\n    }\n\n    .faq-a a:hover { border-bottom-color: var(--blue); }\n\n    .faq-a .source {\n        font-size: 12px;\n        color: var(--muted);\n        margin-top: 12px;\n        font-style: italic;\n    }\n\n  \n\n    @media (max-width: 640px) {\n        .container { padding: 32px 16px; }\n        .header h1 { font-size: 24px; }\n        .nav { gap: 6px; }\n        .nav a { font-size: 12px; padding: 5px 10px; }\n    }\n\n\n \n    \n\n\n    </style>\n\n    <div class=\"container\">\n\n\n\n    <div class=\"nav\" id=\"nav\">\n    <a href=\"#installation\">Installation</a>\n    <a href=\"#text-extraction\">Text Extraction</a>\n    <a href=\"#table-extraction\">Tables</a>\n    <a href=\"#ocr\">OCR</a>\n    <a href=\"#pymupdf4llm\">PyMuPDF4LLM</a>\n    <a href=\"#images\">Images</a>\n    <a href=\"#text-insertion\">Text Insertion</a>\n    <a href=\"#annotations\">Annotations</a>\n    <a href=\"#forms\">Forms & Widgets</a>\n    <a href=\"#fonts\">Fonts</a>\n    <a href=\"#merge-split\">Merge & Split</a>\n    <a href=\"#geometry\">Geometry & Coordinates</a>\n    <a href=\"#performance\">Performance</a>\n    <a href=\"#conversion\">Conversion</a>\n    </div>\n\n    <!-- ===== INSTALLATION ===== -->\n    <div class=\"section\" id=\"installation\">\n    <div class=\"section-header\">\n    <h2>Installation & Setup</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">I installed PyMuPDF but <code>import pymupdf</code> says \"no module named pymupdf\". What's wrong?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>This is the single most common installation issue. A few things to check:</p>\n        <p>First, make sure you installed <code>pymupdf</code> (not <code>pymypdf</code> or <code>mupdf</code>):</p>\n        <pre><code>pip install pymupdf</code></pre>\n        <p>Second, verify your IDE (PyCharm, VS Code, etc.) is using the same Python interpreter and virtual environment where you installed it. Try running <code>python -c \"import pymupdf; print(pymupdf.__doc__)\"</code> directly in a terminal to isolate IDE issues.</p>\n        <p>Third, there is a separate PyPI package literally named <code>fitz</code> that has nothing to do with PyMuPDF. These two packages cannot coexist in the same environment. If you installed both, uninstall <code>fitz</code> and reinstall <code>pymupdf</code>.</p>\n    <div class=\"tip\"><strong>Note:</strong><code>import fitz</code> still works as a legacy alias, but <code>import pymupdf</code> is the recommended import since version 1.24.0.</div>\n    \n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I install PyMuPDF on Apple Silicon (M1/M2/M3/M4/M5)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>PyMuPDF now ships pre-built wheels for Apple Silicon. A simple <code>pip install pymupdf</code> should work. </p>\n        <pre><code>pip install pymupdf</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">When will PyMuPDF support the latest MuPDF version?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>PyMuPDF releases typically follow MuPDF releases by a few days. When a new MuPDF version is released, the PyMuPDF team updates bindings and pushes a new release within 1-2 days. Check the <a href=\"https://pymupdf.readthedocs.io/en/latest/changes.html\">changelog</a> for the latest version mapping.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I install PyMuPDF in a Docker container?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Standard <code>pip install pymupdf</code> works in most Linux containers. For OCR support, you also need Tesseract language data files. A typical Dockerfile:</p>\n        <pre><code>FROM python:3.11-slim\n    RUN apt-get update && apt-get install -y tesseract-ocr tesseract-ocr-eng\n    RUN pip install pymupdf</code></pre>\n        <div class=\"tip\"><strong>Performance note:</strong> OCR in Docker may be slower than on bare metal due to thread detection differences. Explicitly setting <code>OMP_THREAD_LIMIT</code> can help.</div>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== TEXT EXTRACTION ===== -->\n    <div class=\"section\" id=\"text-extraction\">\n    <div class=\"section-header\">\n    <h2>Text Extraction</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What are the different text extraction modes and when should I use each?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p><code>page.get_text()</code> accepts several output format options:</p>\n        <p><code>\"text\"</code> — Plain text. Good for simple extraction where layout doesn't matter.</p>\n        <p><code>\"blocks\"</code> — Returns a list of text blocks with bounding boxes. Useful for identifying paragraphs.</p>\n        <p><code>\"words\"</code> — Individual words with positions. Good for spatial analysis.</p>\n        <p><code>\"dict\"</code> — Structured dictionary with blocks, lines, and spans including font information. Use this when you need font names, sizes, and colors.</p>\n        <p><code>\"rawdict\"</code> — Like \"dict\" but with individual character-level positions. The most detailed but largest output. Use when you need exact character placement.</p>\n        <p><code>\"json\"</code> / <code>\"rawjson\"</code> — Same as dict/rawdict but as JSON strings. Easier to save to a file for inspection.</p>\n        <div class=\"tip\"><strong>Tip:</strong> If you want to inspect the output structure, use <code>\"json\"</code> or <code>\"rawjson\"</code> and save to a file rather than trying to dump a deeply nested dict to CSV.</div>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">I can see text in the PDF but <code>get_text()</code> returns empty or garbled characters. Why?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Several possible causes:</p>\n        <p><strong>Scanned PDF:</strong> The page is an image, not real text. You need OCR. See the <a href=\"#ocr\">OCR section</a>.</p>\n        <p><strong>Scrambled encoding:</strong> Some PDF creators intentionally scramble character sequences as copy-protection. The text looks correct visually but the internal encoding is randomized. There is no reliable way to detect this programmatically. If you see lots of <code>U+FFFD</code> (replacement characters), this is likely the cause.</p>\n        <p><strong>Custom font encoding:</strong> The font does not provide a back-translation to Unicode. If the font's internal <code>/ToUnicode</code> map is missing, the information simply cannot be recovered. OCR is your fallback here.</p>\n        <div class=\"tip\"><strong>Diagnostic:</strong> Try <code>page.get_text(\"rawdict\")</code> and inspect the character codes. If they're all <code>0xFFFD</code> or nonsensical, the encoding is broken at the PDF level, not a PyMuPDF issue.</div>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I extract text from a specific rectangular area of a page?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use the <code>clip</code> parameter:</p>\n        <pre><code>rect = pymupdf.Rect(100, 100, 400, 300)\n    text = page.get_text(clip=rect)\n\n    # With full detail:\n    data = page.get_text(\"rawdict\", clip=rect)</code></pre>\n        <p>This works with all output formats (\"text\", \"dict\", \"rawdict\", etc.).</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Text extraction doesn't follow reading order. Columns are mixed up. How do I fix this?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Text extraction order depends entirely on how the PDF was created. The internal order may not match visual reading order. Use <code>sort=True</code> to sort blocks by position (top-left to bottom-right):</p>\n        <pre><code>text = page.get_text(sort=True)</code></pre>\n        <p>For multi-column layouts, this helps but isn't perfect. You may need to identify column boundaries yourself using block bounding boxes and split text accordingly. There is no universal solution because PDF creators can store text in arbitrary order.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I extract only bold (or italic) text from a PDF?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use <code>\"dict\"</code> output and filter by span flags:</p>\n        <pre><code>data = page.get_text(\"dict\")\n    for block in data[\"blocks\"]:\n        if \"lines\" not in block:\n            continue\n        for line in block[\"lines\"]:\n            for span in line[\"spans\"]:\n                # flags: bit 0 = superscript, bit 1 = italic, \n                # bit 2 = serif, bit 3 = monospace, bit 4 = bold\n                if span[\"flags\"] & (1 << 4):  # bold\n                    print(span[\"text\"])</code></pre>\n        <p>You can also check the font name. Bold fonts typically have \"Bold\", \"Bd\", or \"Heavy\" in their name.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I find and locate specific text on a page?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use <code>page.search_for()</code>:</p>\n        <pre><code>areas = page.search_for(\"your search term\")\n    for rect in areas:\n        print(rect)  # pymupdf.Rect with coordinates</code></pre>\n        <p>This returns a list of <code>Rect</code> objects showing where each occurrence appears. Note: regular expressions are not supported. If you need regex matching, first extract the full text with <code>get_text()</code>, find matches, then use <code>search_for()</code> to locate each match on the page.</p>\n        <div class=\"tip\"><strong>Performance note:</strong> Adding <code>quads=True</code> is actually slightly faster than the default, because rects are internally converted from quads.</div>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Can I render specific spans from rawdict back onto a blank page?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Yes, but it requires manual work. You need to: (1) extract the font(s) used in the spans, (2) write your own positioning code using the character-level data from <code>\"rawdict\"</code>, and (3) use <code>TextWriter</code> or <code>insert_text()</code> to place each character. This is an advanced use case where you're essentially re-rendering specific text elements.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== TABLE EXTRACTION ===== -->\n    <div class=\"section\" id=\"table-extraction\">\n    <div class=\"section-header\">\n    <h2>Table Extraction</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I extract tables from a PDF into a pandas DataFrame?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code>import pymupdf\n    import pandas as pd\n\n    doc = pymupdf.open(\"input.pdf\")\n    page = doc[0]  # first page\n    tables = page.find_tables()\n\n    for table in tables:\n        df = table.to_pandas()\n        print(df)</code></pre>\n        <p>The <code>find_tables()</code> method detects tables using vector graphics (lines and rectangles). No intermediate image conversion is involved.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">find_tables() isn't detecting my table. What can I do?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Table detection depends on how the table was constructed in the PDF. Common issues:</p>\n        <p><strong>No visible borders:</strong> If the table has no drawn lines or rectangles, the detection may fail. Try the <code>strategy=\"text\"</code> parameter for text-based detection.</p>\n        <p><strong>Background colors only:</strong> Some tables use cell background colors without borders. These are harder to detect reliably.</p>\n        <p>PyMuPDF's table extraction is ported from pdfplumber (chosen over alternatives like tabula for its pure-Python implementation and better accuracy). For extremely unusual table structures, you may need to combine <code>get_text(\"dict\")</code> with your own spatial logic.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Can I extract a table, modify it, and write it back to the same location in the PDF?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>This has a very high probability of failure. You can extract and store table content, structure, and location, but writing it back only works if there are zero structural changes: no new cells, no removed cells, no cell size changes, no merged cells. Even then, there is no native \"replace table\" function. You would need to redact the original area and rebuild the table from scratch using text insertion and drawing commands.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== OCR ===== -->\n    <div class=\"section\" id=\"ocr\">\n    <div class=\"section-header\">\n    <h2>OCR</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How does OCR work in PyMuPDF? Does it use Tesseract?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Yes. MuPDF contains the Tesseract C++ code directly (it's compiled in, not called as an external process). PyMuPDF calls MuPDF functions to invoke Tesseract. The only external requirement is Tesseract language data files (tessdata). Over 100 languages are supported.</p>\n        <p>There is no Python-level Tesseract dependency. Everything runs through the C/C++ layer.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I OCR an image file (not a PDF)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code>import pymupdf\n\n    pix = pymupdf.Pixmap(\"image.png\")\n\n    # Remove alpha channel if present (required for OCR)\n    if pix.alpha:\n        pix = pymupdf.Pixmap(pix, 0)\n\n    # Create a 1-page PDF with OCR text layer\n    doc = pymupdf.open(\"pdf\", pix.pdfocr_tobytes())\n\n    # Now extract the text\n    text = doc[0].get_text()</code></pre>\n        <div class=\"tip\"><strong>Common error:</strong> If your image has a transparency (alpha) channel, OCR will fail. Always check and remove it with <code>pymupdf.Pixmap(pix, 0)</code> first.</div>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I OCR a specific language (e.g., Ukrainian, Chinese)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Install the Tesseract language data file for your language, then specify it:</p>\n        <pre><code># For a full page OCR:\n    tp = page.get_textpage_ocr(language=\"ukr\")  # Ukrainian\n    text = page.get_text(textpage=tp)\n\n    # For image-to-PDF OCR:\n    doc = pymupdf.open(\"pdf\", pix.pdfocr_tobytes(language=\"chi_sim\"))  # Chinese Simplified</code></pre>\n        <p>Make sure the corresponding <code>.traineddata</code> file exists in your Tesseract data directory.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">OCR is very slow in my Docker container compared to running locally. Why?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Tesseract uses OpenMP for parallelism. In Docker, thread detection may not work correctly, causing it to use fewer threads than available. Try setting <code>OMP_THREAD_LIMIT</code> environment variable explicitly. Also ensure your container has adequate CPU resources allocated.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I determine if a page needs OCR or already has extractable text?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>There's no silver bullet. A reasonable heuristic:</p>\n        <pre><code>text = page.get_text().strip()\n    if not text or len(text) < 10:\n        # Probably needs OCR\n        tp = page.get_textpage_ocr()\n        text = page.get_text(textpage=tp)</code></pre>\n        <p>For scrambled text (copy-protection), you might get text that looks like random characters. Checking for high rates of <code>U+FFFD</code> replacement characters can help detect this. But detecting scrambled text reliably is fundamentally difficult.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== PYMUPDF4LLM ===== -->\n    <div class=\"section\" id=\"pymupdf4llm\">\n    <div class=\"section-header\">\n    <h2>PyMuPDF4LLM & AI Pipelines</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Does PyMuPDF4LLM send my data to any external service or API?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p><strong>No.</strong> PyMuPDF4LLM is completely derived from PyMuPDF. There is no access to anything beyond your local machine. No calls to any AI, LLM, RAG, or cloud service. Everything works exactly the same when all internet access is blocked. It is fully GDPR-compatible in terms of data processing.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I get page-level metadata (like LlamaIndex documents) from PyMuPDF4LLM?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use the <code>page_chunks</code> option:</p>\n        <pre><code>import pymupdf4llm\n\n    # Returns a list of page dictionaries (similar to LlamaIndex Document objects)\n    result = pymupdf4llm.to_markdown(\"input.pdf\", page_chunks=True)\n\n    for page in result:\n        print(page[\"metadata\"])  # page number, etc.\n        print(page[\"text\"][:200])  # markdown content</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">PyMuPDF4LLM merges my tables into plain text instead of markdown tables. Why?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Table detection depends on the PDF structure. Some tables are defined in unusual ways (partial borders, background colors only on some cells, inconsistent cell structures). There's a limit to how creatively a table might have been defined.</p>\n        <p>Try adjusting table detection parameters. If the table structure is truly unconventional, you may need to fall back to <code>page.find_tables()</code> with custom parameters and handle table conversion to markdown separately.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What is the licensing situation for PyMuPDF4LLM in a commercial product?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>PyMuPDF4LLM has the same license as PyMuPDF and MuPDF: either GNU AGPL or a commercial license from Artifex. If you're using it as part of a commercial product's data pipeline (even if it's just parsing PDFs for a RAG system), the AGPL obligations apply. Contact <a href=\"https://artifex.com/contact/\">Artifex</a> to evaluate your situation and discuss commercial licensing.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Can I process multiple PDFs at once with PyMuPDF4LLM?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>The API processes one PDF at a time. For batch processing, loop over your files:</p>\n        <pre><code>import pymupdf4llm\n    from pathlib import Path\n\n    for pdf in Path(\"./docs\").glob(\"*.pdf\"):\n        md = pymupdf4llm.to_markdown(str(pdf), page_chunks=True)\n        # process each result</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Which AI frameworks use PyMuPDF for PDF parsing?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>LlamaIndex uses PyMuPDF. LangChain includes PyMuPDF as one of its PDF loader alternatives. Many RAG pipeline implementations in the ecosystem rely on PyMuPDF for the extraction layer.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== IMAGES ===== -->\n    <div class=\"section\" id=\"images\">\n    <div class=\"section-header\">\n    <h2>Images & Pixmaps</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Extracted images have a black background where transparency should be. How do I preserve transparency?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>When extracting images, check for an SMask (soft mask). The <code>page.extract_image(xref)</code> result dictionary has an <code>\"smask\"</code> key. If its value is > 0, that's the xref of the transparency mask. You need to extract both and combine them:</p>\n        <pre><code>img = page.extract_image(xref)\n    if img[\"smask\"] > 0:\n        mask_pix = pymupdf.Pixmap(doc, img[\"smask\"])\n        main_pix = pymupdf.Pixmap(doc, xref)\n        # Combine image with its mask\n        pix = pymupdf.Pixmap(main_pix, mask_pix)\n    else:\n        pix = pymupdf.Pixmap(doc, xref)</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I insert an image into a page?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use <code>page.insert_image()</code> with a target rectangle:</p>\n        <pre><code># Insert from file\n    rect = pymupdf.Rect(100, 100, 300, 250)\n    page.insert_image(rect, filename=\"logo.png\")\n\n    # Use page.rect for full-page:\n    page.insert_image(page.rect, filename=\"background.jpg\")</code></pre>\n        <div class=\"tip\"><strong>Common mistake:</strong> Don't pass the filename as a positional argument. Use <code>filename=</code> explicitly. The call pattern is <code>insert_image(rect, filename=None, pixmap=None, stream=None, ...)</code>.</div>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I render a page to an image (screenshot)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code>page = doc[0]\n    pix = page.get_pixmap(dpi=150)  # default is 72 dpi\n    pix.save(\"page.png\")\n\n    # Higher resolution:\n    pix = page.get_pixmap(dpi=300)</code></pre>\n        <p>You can also use a <code>Matrix</code> for more control over scaling and rotation.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Can I extract vector graphics (logos, diagrams) as images?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Vector graphics (line art) cannot be extracted as images directly because they aren't images in the PDF. PyMuPDF can extract vector drawings as path data via <code>page.get_drawings()</code>, which returns elementary drawing commands (lines, curves, rectangles). To get a visual representation, render the relevant area to a Pixmap using a clip rectangle.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== TEXT INSERTION ===== -->\n    <div class=\"section\" id=\"text-insertion\">\n    <div class=\"section-header\">\n    <h2>Text Insertion</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What's the difference between <code>insert_text</code>, <code>insert_textbox</code>, and <code>insert_htmlbox</code>?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p><code>page.insert_text(point, text)</code> — Places text starting at a single point. No wrapping. You control exact position.</p>\n        <p><code>page.insert_textbox(rect, text)</code> — Fills text into a rectangle with automatic line breaks. Returns a value indicating overflow (negative = text didn't fit).</p>\n        <p><code>page.insert_htmlbox(rect, html)</code> — Like textbox but accepts HTML/CSS for rich formatting. Tremendously more flexible: supports mixed fonts, colors, alignment, etc. This is generally the recommended approach for complex text insertion.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">My inserted text is white (invisible). How do I make it black?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Black is the default color. If text appears white, you may be inserting on a dark background or there's a color space issue. Explicitly set color:</p>\n        <pre><code>page.insert_text((100, 100), \"Hello\", color=pymupdf.pdfcolor[\"black\"])\n\n    # Or using RGB tuple (0-1 range):\n    page.insert_text((100, 100), \"Hello\", color=(0, 0, 0))</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I create a landscape page?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code># Use paper size with \"-l\" suffix for landscape\n    mediabox = pymupdf.paper_rect(\"a4-l\")\n    page = doc.new_page(width=mediabox.width, height=mediabox.height)\n\n    # See all available paper sizes:\n    print(pymupdf.paper_sizes())</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I set margins when inserting text on a new page?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Create a fill rectangle with margins subtracted from the page rectangle:</p>\n        <pre><code>page = doc.new_page()\n    left, top, right, bottom = 72, 72, 72, 72  # 1 inch margins\n    fill_rect = page.rect + (left, top, -right, -bottom)\n    page.insert_textbox(fill_rect, text, fontname=\"helv\", fontsize=11)</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">The Euro sign (€) and other special characters show as \"?\" in my text. Why?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>The built-in Base-14 fonts (like \"helv\") only support characters up to Unicode 256. The Euro sign is at <code>0x80</code> in this range. Either replace <code>€</code> with <code>chr(0x80)</code> in your text, or use a proper Unicode font file:</p>\n        <pre><code>page.insert_text((100, 100), \"Price: 50€\",\n        fontfile=\"/path/to/arial.ttf\",\n        fontname=\"arial\")</code></pre>\n        <p>For CJK and extended characters, use the <code>pymupdf-fonts</code> package which includes FiraGO and CJK fallback fonts.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I dynamically fit text to a rectangle (auto font size)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Two approaches:</p>\n        <p>Option 1: Reduce font size until it fits:</p>\n        <pre><code>fontsize = 20\n    while True:\n        rc = page.insert_textbox(rect, text, fontsize=fontsize)\n        if rc >= 0:  # positive = text fit\n            break\n        fontsize -= 0.5  # shrink and retry</code></pre>\n        <p>Option 2: Use <code>insert_htmlbox()</code> which handles overflow more gracefully and gives you CSS-level control.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I add text on top of an image (with a background rectangle)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Draw the background rectangle first, then insert text on top:</p>\n        <pre><code>shape = page.new_shape()\n    shape.draw_rect(rect)\n    shape.finish(fill=(1, 1, 0.8))  # light yellow fill\n    shape.commit()\n\n    page.insert_textbox(rect, text, fontsize=12)</code></pre>\n        <p>Order matters: shapes drawn first appear behind text inserted later.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== ANNOTATIONS ===== -->\n    <div class=\"section\" id=\"annotations\">\n    <div class=\"section-header\">\n    <h2>Annotations</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Does PyMuPDF support \"cloudy\" border style for annotations?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>No. The cloudy border effect (common in Adobe PDF annotations) is not implemented in MuPDF's C core, so it's not available through PyMuPDF either.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I redact (permanently remove) content from a PDF?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code># Step 1: Mark areas for redaction\n    rect = page.search_for(\"confidential\")[0]\n    page.add_redact_annot(rect, fill=(1, 1, 1))  # white fill\n\n    # Step 2: Apply redactions (permanently removes content)\n    page.apply_redactions()\n\n    doc.save(\"redacted.pdf\")</code></pre>\n        <p>After applying redactions, the original content is permanently removed from the PDF. This is a two-step process by design, so you can review before committing.</p>\n        <div class=\"tip\"><strong>Replacement text:</strong> You can also insert replacement text during redaction, but the formatting options are limited. For more control, apply the redaction to clear the area, then use <code>insert_text()</code> or <code>insert_htmlbox()</code> in a separate step.</div>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Can I \"flatten\" annotations so they become part of the page content?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>MuPDF has work-in-progress support for this. If you flatten annotations, they become part of the page content stream and can no longer be edited, moved, or recognized as annotations by other PDF viewers. For form fields, this means they lose interactivity.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I add a highlight annotation to found text?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code>quads = page.search_for(\"important text\", quads=True)\n    for quad in quads:\n        annot = page.add_highlight_annot(quad)\n        annot.set_colors(stroke=(1, 1, 0))  # yellow\n        annot.update()</code></pre>\n        <p>Using <code>quads=True</code> gives more precise highlighting, especially for rotated or non-horizontal text.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== FORMS ===== -->\n    <div class=\"section\" id=\"forms\">\n    <div class=\"section-header\">\n    <h2>Forms & Widgets</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I create a fillable form field (widget) in a PDF?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code>import pymupdf\n\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    # Create a text input field\n    widget = pymupdf.Widget()\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT\n    widget.rect = pymupdf.Rect(50, 50, 250, 80)\n    widget.field_name = \"name\"\n    widget.field_value = \"Enter name\"\n\n    annot = page.add_widget(widget)\n    doc.save(\"form.pdf\")</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I create a date field widget?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code>widget = pymupdf.Widget()\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT\n    widget.field_flags |= pymupdf.PDF_WIDGET_TX_FORMAT_DATE\n    widget.rect = pymupdf.Rect(20, 20, 160, 80)\n    widget.field_name = \"Date\"\n    widget.field_value = \"12/12/2024\"\n    annot = page.add_widget(widget)</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Fonts in my form fields don't render correctly on mobile devices or non-Adobe readers.</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>This is a common problem. PDF viewers that don't have the specified font will substitute or fail to render. The solution is to embed fonts in the PDF. Note that new form fields created by PyMuPDF have certain font restrictions. If you need specific fonts embedded, you may need to work at the xref level:</p>\n        <pre><code># After adding a widget:\n    annot = page.add_widget(widget)\n    xref = annot.xref  # use this to access low-level PDF objects</code></pre>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== FONTS ===== -->\n    <div class=\"section\" id=\"fonts\">\n    <div class=\"section-header\">\n    <h2>Fonts</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What fonts are available by default without loading external font files?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>The PDF Base-14 fonts are always available:</p>\n        <p><code>\"helv\"</code> (Helvetica), <code>\"heit\"</code> (Helvetica Italic), <code>\"hebo\"</code> (Helvetica Bold), <code>\"hebi\"</code> (Helvetica Bold Italic)</p>\n        <p><code>\"tiro\"</code> (Times Roman), <code>\"tiit\"</code>, <code>\"tibo\"</code>, <code>\"tibi\"</code></p>\n        <p><code>\"cour\"</code> (Courier), <code>\"coit\"</code>, <code>\"cobo\"</code>, <code>\"cobi\"</code></p>\n        <p><code>\"symb\"</code> (Symbol), <code>\"zadb\"</code> (ZapfDingbats)</p>\n        <p>These only support characters up to about Unicode 256. For CJK, extended Latin, Arabic, etc., install <code>pymupdf-fonts</code> or provide your own font files.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I get the font name of extracted text?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use <code>\"dict\"</code> output format. Each span includes font information:</p>\n        <pre><code>data = page.get_text(\"dict\")\n    for block in data[\"blocks\"]:\n        if \"lines\" not in block:\n            continue\n        for line in block[\"lines\"]:\n            for span in line[\"spans\"]:\n                print(f\"Font: {span['font']}, Size: {span['size']}\")</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Is there a universal fallback font that can render any character?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>No single font covers everything including emojis. FiraGO (available in <code>pymupdf-fonts</code>) covers extended Latin and many scripts not in CJK. The CJK fallback font (\"Droid Sans Fallback Regular\") covers Chinese, Japanese, and Korean. But you cannot change or extend the fallback font chain. For maximum coverage, use a rich font like FiraGO as your primary and accept that some exotic characters may not render.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== MERGE & SPLIT ===== -->\n    <div class=\"section\" id=\"merge-split\">\n    <div class=\"section-header\">\n    <h2>Merging & Splitting PDFs</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I extract specific pages from one PDF into a new PDF?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <pre><code>src = pymupdf.open(\"input.pdf\")\n    doc = pymupdf.open()  # new empty PDF\n    doc.insert_pdf(src, from_page=0, to_page=4)  # pages 1-5 (0-based)\n    doc.save(\"output.pdf\")</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">My output PDF is the same size as the original even though I only extracted 2 pages from 20. Why?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Different pages often share resources (fonts, images, etc.) that are referenced but not deduplicated on save. Use <code>ez_save()</code> instead of <code>save()</code>, or use save with garbage collection and deflation:</p>\n        <pre><code># Best option for size reduction:\n    doc.ez_save(\"output.pdf\")\n\n    # Or with explicit options:\n    doc.save(\"output.pdf\", garbage=4, deflate=True, clean=True)</code></pre>\n        <p><code>clean=True</code> can also help by cleaning content streams, but note this may increase file size for some PDFs (due to decompression of already-compressed streams).</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I overlay one page on top of another (watermark / stamp)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use <code>page.show_pdf_page()</code> to render a source page onto a target page:</p>\n        <pre><code>src = pymupdf.open(\"watermark.pdf\")\n    doc = pymupdf.open(\"document.pdf\")\n\n    for page in doc:\n        page.show_pdf_page(page.rect, src, 0)  # overlay page 0 of watermark\n\n    doc.save(\"stamped.pdf\")</code></pre>\n        <div class=\"tip\"><strong>Note:</strong> <code>insert_pdf()</code> adds new pages. <code>show_pdf_page()</code> overlays content onto an existing page. These are different operations.</div>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== GEOMETRY ===== -->\n    <div class=\"section\" id=\"geometry\">\n    <div class=\"section-header\">\n    <h2>Geometry & Coordinates</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What is the coordinate system in PyMuPDF? Where is (0,0)?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>The origin (0,0) is at the <strong>top-left</strong> of the page. X increases to the right, Y increases downward. This matches screen coordinates but differs from the PDF specification (which uses bottom-left origin). PyMuPDF handles the transformation internally.</p>\n        <p>An A4 page in portrait has dimensions approximately (0, 0, 595, 842) in points (1 point = 1/72 inch).</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What's the difference between <code>page.rect</code>, <code>page.mediabox</code>, and <code>page.cropbox</code>?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p><code>page.mediabox</code> — The physical page size as defined in the PDF. This is the largest boundary.</p>\n        <p><code>page.cropbox</code> — The visible area when displayed. May be smaller than mediabox. This is what viewers typically show.</p>\n        <p><code>page.rect</code> — The effective page rectangle considering rotation. Use this for most operations as it reflects what you actually see.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What does bbox mean and what order are the coordinates?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>A bounding box (bbox) is defined as <code>(x0, y0, x1, y1)</code> where <code>(x0, y0)</code> is the top-left corner and <code>(x1, y1)</code> is the bottom-right corner. This forms a <code>pymupdf.Rect</code>:</p>\n        <pre><code>rect = pymupdf.Rect(x0, y0, x1, y1)\n    print(rect.width)   # x1 - x0\n    print(rect.height)  # y1 - y0\n    print(rect.tl)      # top-left Point(x0, y0)\n    print(rect.br)      # bottom-right Point(x1, y1)</code></pre>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I check if a word/block is inside a given rectangle?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use rectangle containment or intersection:</p>\n        <pre><code>region = pymupdf.Rect(100, 100, 400, 300)\n    word_rect = pymupdf.Rect(word[:4])  # first 4 elements of a \"words\" tuple\n\n    if word_rect in region:        # fully contained\n        print(\"inside\")\n    if word_rect.intersects(region):  # overlaps\n        print(\"overlaps\")</code></pre>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== PERFORMANCE ===== -->\n    <div class=\"section\" id=\"performance\">\n    <div class=\"section-header\">\n    <h2>Performance & Large Files</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I handle very large PDFs without running out of memory?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Close input/output documents at intervals to free resources. You can also shrink MuPDF's internal cache:</p>\n        <pre><code>import pymupdf\n\n    # Process in batches\n    for i in range(0, total_pages, 50):\n        src = pymupdf.open(\"huge.pdf\")\n        doc = pymupdf.open()\n        doc.insert_pdf(src, from_page=i, to_page=min(i+49, total_pages-1))\n        doc.save(f\"batch_{i}.pdf\")\n        doc.close()\n        src.close()\n        pymupdf.TOOLS.store_shrink(100)  # free MuPDF cache</code></pre>\n        <p>The major memory consumer is shared resources (fonts, images) that are referenced across pages. Batch processing with intermediate saves helps.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Can I use multiprocessing with PyMuPDF?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Yes, but each process needs its own document objects. Don't share <code>pymupdf.Document</code> objects across processes. A common pattern is to split work by page ranges, let each process open the file independently, and combine results afterward.</p>\n        <div class=\"tip\"><strong>Note:</strong> Threading with GIL release was tested but found to have intolerable overhead. Multiprocessing is the better approach for parallelism.</div>\n    </div>\n    </div>\n    \n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">Can I use multithreading with PyMuPDF, perhaps with <a href=\"https://docs.python.org/3/howto/free-threading-python.html\">free-threading Python</a>?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>No, PyMuPDF does not support multithreaded use,\n        even with newer free-thread Python.\n\n        <p>Making PyMuPDF work with threads is a tricky problem.\n        The underlying MuPDF library only provides partial thread safety so the results would not be as performant as might be naively assumed,\n        and the implementation would inevitably introduce and expose subtle bugs.\n\n        <p>Any thread-safe implementation of PyMuPDF would also necessarily impose a single-threaded overhead.\n\n        <p>The preferred approach is to <a href=\"../recipes-multiprocessing.html\">use multiple processes instead of multiple threads</a>.\n        This gives most of what is generally required,\n        with simplicity and guaranteed correctness.\n    </div>\n    </div>\n\n    </div>\n\n    <!-- ===== CONVERSION ===== -->\n    <div class=\"section\" id=\"conversion\">\n    <div class=\"section-header\">\n    <h2>Format Conversion</h2>\n\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">How do I convert HTML to PDF?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>Use the <code>Story</code> class:</p>\n        <pre><code>import pymupdf\n\n    html = \"\"\"\n    &lt;h1&gt;Hello World&lt;/h1&gt;\n    &lt;p&gt;This is a &lt;b&gt;bold&lt;/b&gt; paragraph.&lt;/p&gt;\n    \"\"\"\n\n    story = pymupdf.Story(html)\n    writer = pymupdf.DocumentWriter(\"output.pdf\")\n    mediabox = pymupdf.paper_rect(\"a4\")\n\n    while True:\n        device = writer.begin_page(mediabox)\n        more, filled = story.place(mediabox + (36, 36, -36, -36))\n        story.draw(device)\n        writer.end_page()\n        if not more:\n            break\n\n    writer.close()</code></pre>\n        <p>The Story class supports HTML and CSS for layout, including fonts, colors, and basic page flow.</p>\n    </div>\n    </div>\n\n    <div class=\"faq\">\n    <div class=\"faq-q\"><span class=\"marker\">Q</span><span class=\"question\">What document formats can PyMuPDF open?</span><span class=\"toggle\">+</span></div>\n    <div class=\"faq-a\">\n        <p>PDF, XPS, EPUB, MOBI, FB2, CBZ, SVG, and various image formats (PNG, JPEG, BMP, TIFF, etc.). All are opened with <code>pymupdf.open()</code>. For image formats, the result is a single-page document.</p>\n    </div>\n    </div>\n\n    </div>\n\n    <!-- Footer -->\n\n\n    </div>\n\n    <script>\n    document.querySelectorAll('.faq-q').forEach(q => {\n    q.addEventListener('click', () => {\n        q.parentElement.classList.toggle('open');\n    });\n    });\n    </script>\n\n"
  },
  {
    "path": "docs/faq.rst",
    "content": ".. include:: header.rst\n\n.. _FAQ:\n\n==============================\nFAQ\n==============================\n\nA collection of recipes in “How-To” format for using PyMuPDF.\n\n\nPlease see:\n\n:ref:`Recipes: Table of Contents<RecipesTOC>`\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/font.rst",
    "content": ".. include:: header.rst\n\n.. _Font:\n\n================\nFont\n================\n\n* New in v1.16.18\n\nThis class represents a font as defined in |MuPDF| (``fz_font_s`` structure). It is required for the new class :ref:`TextWriter` and the new :meth:`Page.write_text`. Currently, it has no connection to how fonts are used in methods :meth:`Page.insert_text` or :meth:`Page.insert_textbox`, respectively.\n\nA ``Font`` object also contains useful general information, like the font bbox, the number of defined glyphs, glyph names or the ``bbox`` of a single glyph.\n\n\n==================================== ============================================\n**Method / Attribute**               **Short Description**\n==================================== ============================================\n:meth:`~Font.glyph_advance`          Width of a character\n:meth:`~Font.glyph_bbox`             Glyph rectangle\n:meth:`~Font.glyph_name_to_unicode`  Get unicode from glyph name\n:meth:`~Font.has_glyph`              Return glyph id of unicode\n:meth:`~Font.text_length`            Compute string length\n:meth:`~Font.char_lengths`           Tuple of char widths of a string\n:meth:`~Font.unicode_to_glyph_name`  Get glyph name of a unicode\n:meth:`~Font.valid_codepoints`       Array of supported unicodes\n:attr:`~Font.ascender`               Font ascender\n:attr:`~Font.descender`              Font descender\n:attr:`~Font.bbox`                   Font rectangle\n:attr:`~Font.buffer`                 Copy of the font's binary image\n:attr:`~Font.flags`                  Collection of font properties\n:attr:`~Font.glyph_count`            Number of supported glyphs\n:attr:`~Font.name`                   Name of font\n:attr:`~Font.is_bold`                `True` if bold\n:attr:`~Font.is_monospaced`          `True` if mono-spaced\n:attr:`~Font.is_serif`               `True` if serif, `False` if sans-serif\n:attr:`~Font.is_italic`              `True` if italic\n==================================== ============================================\n\n\n**Class API**\n\n.. class:: Font\n\n   .. index::\n      pair: Font, fontfile\n      pair: Font, fontbuffer\n      pair: Font, script\n      pair: Font, ordering\n      pair: Font, is_bold\n      pair: Font, is_italic\n      pair: Font, is_serif\n      pair: Font, fontname\n      pair: Font, language\n\n   .. method:: __init__(self, fontname=None, fontfile=None,\n                  fontbuffer=None, script=0, language=None, ordering=-1, is_bold=0,\n                  is_italic=0, is_serif=0)\n\n      Font constructor. The large number of parameters are used to locate font, which most closely resembles the requirements. Not all parameters are ever required -- see the below pseudo code explaining the logic how the parameters are evaluated.\n\n      :arg str fontname: one of the :ref:`Base-14-Fonts` or CJK fontnames. Also possible are a select few other names like (watch the correct spelling): \"Arial\", \"Times\", \"Times Roman\".\n      \n         *(Changed in v1.17.5)*\n\n         If you have installed `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_, there are also new \"reserved\" fontnames available, which are listed in :attr:`fitz_fonts` and in the table further down.\n\n      :arg str fontfile: the filename of a fontfile somewhere on your system [#f1]_.\n      :arg bytes,bytearray,io.BytesIO fontbuffer: a fontfile loaded in memory [#f1]_.\n      :arg in script: the number of a UCDN script. Currently supported in PyMuPDF are numbers 24, and 32 through 35.\n      :arg str language: one of the values \"zh-Hant\" (traditional Chinese), \"zh-Hans\" (simplified Chinese), \"ja\" (Japanese) and \"ko\" (Korean). Otherwise, all ISO 639 codes from the subsets 1, 2, 3 and 5 are also possible, but are currently documentary only.\n      :arg int ordering: an alternative selector for one of the CJK fonts.\n      :arg bool is_bold: look for a bold font.\n      :arg bool is_italic: look for an italic font.\n      :arg bool is_serif: look for a serifed font.\n\n      :returns: a |MuPDF| font if successful. This is the overall sequence of checks to determine an appropriate font:\n\n         =========== ============================================================\n         Argument    Action\n         =========== ============================================================\n         fontfile?   Create font from file, exception if failure.\n         fontbuffer? Create font from buffer, exception if failure.\n         ordering>=0 Create universal font, always succeeds.\n         fontname?   Create a Base-14 font, universal font, or font\n                     provided by `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_. See table below.\n         =========== ============================================================\n\n\n      .. note::\n\n        With the usual reserved names \"helv\", \"tiro\", etc., you will create fonts with the expected names \"Helvetica\", \"Times-Roman\" and so on. **However**, and in contrast to :meth:`Page.insert_font` and friends,\n\n         * a font file will **always** be embedded in your PDF,\n         * Greek and Cyrillic characters are supported without needing the *encoding* parameter.\n\n        Using *ordering >= 0*, or fontnames \"cjk\", \"china-t\", \"china-s\", \"japan\" or \"korea\" will **always create the same \"universal\"** font **\"Droid Sans Fallback Regular\"**. This font supports **all Chinese, Japanese, Korean and Latin characters**, including Greek and Cyrillic. This is a sans-serif font.\n\n        Actually, you would rarely ever need another sans-serif font than **\"Droid Sans Fallback Regular\"**. **Except** that this font file is relatively large and adds about 1.65 MB (compressed) to your PDF file size. If you do not need CJK support, stick with specifying \"helv\", \"tiro\" etc., and you will get away with about 35 KB compressed.\n\n        If you **know** you have a mixture of CJK and Latin text, consider just using `Font(\"cjk\")` because this supports everything and also significantly (by a factor of up to three) speeds up execution: MuPDF will always find any character in this single font and never needs to check fallbacks.\n\n        But if you do use some other font, you will still automatically be able to also write CJK characters: MuPDF detects this situation and silently falls back to the universal font (which will then of course also be embedded in your PDF).\n\n        *(New in v1.17.5)* Optionally, some new \"reserved\" fontname codes become available if you install `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_, `pip install pymupdf-fonts`. **\"Fira Mono\"** is a mono-spaced sans font set and **FiraGO** is another non-serifed \"universal\" font set which supports all Latin (including Cyrillic and Greek) plus Thai, Arabian, Hewbrew and Devanagari -- but none of the CJK languages. The size of a FiraGO font is only a quarter of the \"Droid Sans Fallback\" size (compressed 400 KB vs. 1.65 MB) -- **and** it provides the weights bold, italic, bold-italic -- which the universal font doesn't.\n\n        **\"Space Mono\"** is another nice and small mono-spaced font from Google Fonts, which supports Latin Extended characters and comes with all 4 important weights.\n\n        The following table maps a fontname code to the corresponding font. For the current content of the package please see its documentation:\n\n            =========== =========================== ======= =============================\n            Code        Fontname                    New in  Comment\n            =========== =========================== ======= =============================\n            figo        FiraGO Regular              v1.0.0  narrower than Helvetica\n            figbo       FiraGO Bold                 v1.0.0\n            figit       FiraGO Italic               v1.0.0\n            figbi       FiraGO Bold Italic          v1.0.0\n            fimo        Fira Mono Regular           v1.0.0\n            fimbo       Fira Mono Bold              v1.0.0\n            spacemo     Space Mono Regular          v1.0.1\n            spacembo    Space Mono Bold             v1.0.1\n            spacemit    Space Mono Italic           v1.0.1\n            spacembi    Space Mono Bold-Italic      v1.0.1\n            math        Noto Sans Math Regular      v1.0.2  math symbols\n            music       Noto Music Regular          v1.0.2  musical symbols\n            symbol1     Noto Sans Symbols Regular   v1.0.2  replacement for \"symb\"\n            symbol2     Noto Sans Symbols2 Regular  v1.0.2  extended symbol set\n            notos       Noto Sans Regular           v1.0.3  alternative to Helvetica\n            notosit     Noto Sans Italic            v1.0.3\n            notosbo     Noto Sans Bold              v1.0.3\n            notosbi     Noto Sans BoldItalic        v1.0.3\n            =========== =========================== ======= =============================\n\n   .. index::\n      pair: Font.has_glyph, language\n      pair: Font.has_glyph, script\n      pair: Font.has_glyph, fallback\n\n   .. method:: has_glyph(chr, language=None, script=0, fallback=False)\n\n      Check whether the unicode ``chr`` exists in the font or (option) some fallback font. May be used to check whether any \"TOFU\" symbols will appear on output.\n\n      :arg int chr: the unicode of the character (i.e. ``ord()``).\n      :arg str language: the language -- currently unused.\n      :arg int script: the UCDN script number.\n      :arg bool fallback: *(new in v1.17.5)* perform an extended search in fallback fonts or restrict to current font (default).\n      :returns: *(changed in 1.17.7)* the glyph number. Zero indicates no glyph found.\n\n   .. method:: valid_codepoints()\n\n      * New in v1.17.5\n\n      Return an array of unicodes supported by this font.\n\n      :returns: an ``array.array`` [#f2]_ of length at most :attr:`Font.glyph_count`. I.e. ``chr()`` of every item in this array has a glyph in the font without using fallbacks. This is an example display of the supported glyphs:\n\n         >>> import pymupdf\n         >>> font = pymupdf.Font(\"math\")\n         >>> vuc = font.valid_codepoints()\n         >>> for i in vuc:\n         >>>     print(f\"{i:04X} {chr(i)} ({font.unicode_to_glyph_name(i)})\")\n         0000\n         000D   (CR)\n         0020   (space)\n         0021 ! (exclam)\n         0022 \" (quotedbl)\n         0023 # (numbersign)\n         0024 $ (dollar)\n         0025 % (percent)\n         ...\n         00AC ¬ (logicalnot)\n         00B1 ± (plusminus)\n         ...\n         21D0 ⇐ (arrowdblleft)\n         21D1 ⇑ (arrowdblup)\n         21D2 ⇒ (arrowdblright)\n         21D3 ⇓ (arrowdbldown)\n         21D4 ⇔ (arrowdblboth)\n         ...\n         221E ∞ (infinity)\n         ...\n\n      .. note:: This method only returns meaningful data for fonts having a CMAP (character map, charmap, the `/ToUnicode` PDF key). Otherwise, this array will have length 1 and contain zero only.\n\n   .. index::\n      pair: Font.glyph_advance, language\n      pair: Font.glyph_advance, script\n      pair: Font.glyph_advance, wmode\n\n   .. method:: glyph_advance(chr, language=None, script=0, wmode=0)\n\n      Calculate the \"width\" of the character's glyph (visual representation).\n\n      :arg int chr: the unicode number of the character. Use ``ord()``, not the character itself. Again, this should normally work even if a character is not supported by that font, because fallback fonts will be checked where necessary.\n      :arg int wmode: write mode, ``0`` = horizontal, ``1`` = vertical.\n\n      The other parameters are not in use currently.\n\n      :returns: a float representing the glyph's width relative to **fontsize 1**.\n\n   .. method:: glyph_name_to_unicode(name)\n\n      Return the unicode value for a given glyph name. Use it in conjunction with `chr()` if you want to output e.g. a certain symbol.\n\n      :arg str name: The name of the glyph.\n\n      :returns: The unicode integer, or 65533 = 0xFFFD if the name is unknown. Examples: `font.glyph_name_to_unicode(\"Sigma\") = 931`, `font.glyph_name_to_unicode(\"sigma\") = 963`. Refer to the `Adobe Glyph List <https://github.com/adobe-type-tools/agl-aglfn/blob/master/glyphlist.txt>`_ publication for a list of glyph names and their unicode numbers. Example:\n\n         >>> font = pymupdf.Font(\"helv\")\n         >>> font.has_glyph(font.glyph_name_to_unicode(\"infinity\"))\n         True\n\n   .. index::\n      pair: Font.glyph_bbox, language\n      pair: Font.glyph_bbox, script\n\n   .. method:: glyph_bbox(chr, language=None, script=0)\n\n      The glyph rectangle relative to :data:`fontsize` 1.\n\n      :arg int chr: ``ord()`` of the character.\n\n      :returns: a :ref:`Rect`.\n\n\n   .. method:: unicode_to_glyph_name(ch)\n\n      Show the name of the character's glyph.\n\n      :arg int ch: the unicode number of the character. Use ``ord()``, not the character itself.\n\n      :returns: a string representing the glyph's name. E.g. `font.glyph_name(ord(\"#\")) = \"numbersign\"`. For an invalid code \".notfound\" is returned.\n      \n        .. note:: *(Changed in v1.18.0)* This method and :meth:`Font.glyph_name_to_unicode` no longer depend on a font and instead retrieve information from the **Adobe Glyph List**. Also available as `pymupdf.unicode_to_glyph_name()` and resp. `pymupdf.glyph_name_to_unicode()`.\n\n   .. index::\n      pair: text_length, fontsize\n\n   .. method:: text_length(text, fontsize=11)\n\n      Calculate the length in points of a unicode string.\n\n      .. note:: There is a functional overlap with :meth:`get_text_length` for Base-14 fonts only.\n\n      :arg str text: a text string, UTF-8 encoded.\n\n      :arg float fontsize: the :data:`fontsize`.\n\n      :rtype: float\n\n      :returns: the length of the string in points when stored in the PDF. If a character is not contained in the font, it will automatically be looked up in a fallback font.\n\n         .. note:: This method was originally implemented in Python, based on calling :meth:`Font.glyph_advance`. For performance reasons, it has been rewritten in C for v1.18.14. To compute the width of a single character, you can now use either of the following without performance penalty:\n\n            1. `font.glyph_advance(ord(\"Ä\")) * fontsize`\n            2. `font.text_length(\"Ä\", fontsize=fontsize)`\n\n            For multi-character strings, the method offers a huge performance advantage compared to the previous implementation: instead of about 0.5 microseconds for each character, only 12.5 nanoseconds are required for the second and subsequent ones.\n\n   .. index::\n      pair: char_lengths, fontsize\n\n   .. method:: char_lengths(text, fontsize=11)\n\n      *New in v1.18.14*\n\n      Sequence of character lengths in points of a unicode string.\n\n      :arg str text: a text string, UTF-8 encoded.\n\n      :arg float fontsize: the :data:`fontsize`.\n\n      :rtype: tuple\n\n      :returns: the lengths in points of the characters of a string when stored in the PDF. It works like :meth:`Font.text_length` broken down to single characters. This is a high speed method, used e.g. in :meth:`TextWriter.fill_textbox`. The following is true (allowing rounding errors): `font.text_length(text) == sum(font.char_lengths(text))`.\n\n         >>> font = pymupdf.Font(\"helv\")\n         >>> text = \"PyMuPDF\"\n         >>> font.text_length(text)\n         50.115999937057495\n         >>> pymupdf.get_text_length(text, fontname=\"helv\")\n         50.115999937057495\n         >>> sum(font.char_lengths(text))\n         50.115999937057495\n         >>> pprint(font.char_lengths(text))\n         (7.336999952793121,  # P\n         5.5,                 # y\n         9.163000047206879,   # M\n         6.115999937057495,   # u\n         7.336999952793121,   # P\n         7.942000031471252,   # D\n         6.721000015735626)   # F\n\n\n   .. attribute:: buffer\n\n      * New in v1.17.6\n\n      Copy of the binary font file content.\n      \n      :rtype: bytes\n\n   .. attribute:: flags\n\n      A dictionary with various font properties, each represented as bools. Example for Helvetica::\n\n         >>> pprint(font.flags)\n         {'bold': 0,\n         'fake-bold': 0,\n         'fake-italic': 0,\n         'invalid-bbox': 0,\n         'italic': 0,\n         'mono': 0,\n         'opentype': 0,\n         'serif': 1,\n         'stretch': 0,\n         'substitute': 0}\n\n      :rtype: dict\n\n   .. attribute:: name\n\n      :rtype: str\n\n      Name of the font. May be \"\" or \"(null)\".\n\n   .. attribute:: bbox\n\n      The font bbox. This is the maximum of its glyph bboxes.\n\n      :rtype: :ref:`Rect`\n\n   .. attribute:: glyph_count\n\n      :rtype: int\n\n      The number of glyphs defined in the font.\n\n   .. attribute:: ascender\n\n      * New in v1.18.0\n\n      The ascender value of the font, see `ascender typography <https://en.wikipedia.org/wiki/Ascender_(typography)>`_ for details. Please note that there is a difference to the strict definition: our value includes everything above the baseline -- not just the height difference between upper case \"A\" and and lower case \"a\".\n\n      :rtype: float\n\n   .. attribute:: descender\n\n      * New in v1.18.0\n\n      The descender value of the font, see `descender typography <https://en.wikipedia.org/wiki/Descender>`_ for details. This value always is negative and is the portion that some glyphs descend below the base line, for example \"g\" or \"y\". As a consequence, the value `ascender - descender` is the total height, that every glyph of the font fits into. This is true at least for most fonts -- as always, there are exceptions, especially for calligraphic fonts, etc.\n\n      :rtype: float\n\n   .. attribute:: is_bold\n\n   .. attribute:: is_italic\n\n   .. attribute:: is_monospaced\n\n   .. attribute:: is_serif\n\n      A number of attributes with obvious meanings. Reflect some values of the :attr:`Font.flags` dictionary.\n\n      :rtype: bool\n\n.. rubric:: Footnotes\n\n.. [#f1] MuPDF does not support all fontfiles with this feature and will raise exceptions like *\"mupdf: FT_New_Memory_Face((null)): unknown file format\"*, if it encounters issues.\n\n.. [#f2] The built-in Python module `array` has been chosen for its speed and low memory requirement.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/footer.rst",
    "content": ".. _documentation_footer:\n\n----\n\n.. raw:: html\n\n   <p style=\"color:#999\" id=\"footerDisclaimer\">This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of that license. Refer to licensing information at <a href=\"https://www.artifex.com?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=footer-link\">artifex.com</a> or contact Artifex Software Inc., 39 Mesa Street, Suite 108A, San Francisco CA 94129, United States for further information.</p>\n\n   <script>\n\n      let docLanguage = document.getElementsByTagName('html')[0].getAttribute('lang');\n\n      function getHeaderAndFooterTranslation(str) {\n          if (docLanguage == \"ja\") {\n              if (str == \"Find <b>#pymupdf</b> on <b>Discord</b>\") {\n                  return \"<b>Discord</b>の <b>#pymupdf</b> を見つける\";\n              } else if (str == \"Have a <b>&nbsp;question</b>? Need some <b>&nbsp;answers</b>?&nbsp;\") {\n                  return \"質問がありますか？答えが必要ですか？\";\n              }\n              else if (str == \"This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of that license. Refer to licensing information at <a href='https://www.artifex.com?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=footer-link'>artifex.com</a> or contact Artifex Software Inc., 39 Mesa Street, Suite 108A, San Francisco CA 94129, United States for further information.\") {\n\n                  return \"このソフトウェアは無保証で提供されており、明示または黙示を問わず、いかなる保証もありません。このソフトウェアはライセンスの下で配布され、ライセンスの条件に明示的に許可されている場合を除き、コピー、変更、または配布してはなりません。ライセンシング情報については、<a href='https://www.artifex.com?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=footer-link'>artifex.com</a>でライセンス情報を参照するか、アメリカ合衆国カリフォルニア州サンフランシスコのArtifex Software Inc. までお問い合わせください。\"\n\n              }\n          } else if (docLanguage == \"ko\") {\n              if (str == \"Find <b>#pymupdf</b> on <b>Discord</b>\") {\n                  return \"<b>Discord</b> 에서 <b>#pymupdf</b> 찾기\";\n              } else if (str == \"Have a <b>&nbsp;question</b>? Need some <b>&nbsp;answers</b>?&nbsp;\") {\n                  return \"<b>&nbsp;질문</b>이 있으신가요? <b>&nbsp;답변</b>이 필요하신가요?&nbsp;\";\n              }\n              else if (str == \"This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of that license. Refer to licensing information at <a href='https://www.artifex.com?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=footer-link'>artifex.com</a> or contact Artifex Software Inc., 39 Mesa Street, Suite 108A, San Francisco CA 94129, United States for further information.\") {\n                  return \"이 소프트웨어는 명시적이든 묵시적이든 어떠한 보증도 없이 있는 그대로 제공됩니다. 이 소프트웨어는 라이선스에 따라 배포되며, 해당 라이선스 조건에 명시적으로 승인된 경우를 제외하고는 복사, 수정 또는 배포할 수 없습니다. 라이선스 정보는 <a href='https://www.artifex.com?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=footer-link'>artifex.com</a> 에서 참조하거나, 미국 캘리포니아주 샌프란시스코 Mesa Street 39, Suite 108A 소재 Artifex Software Inc. 에 문의하시기 바랍니다.\"\n              }\n          }\n\n          return str;\n      }\n\n      document.getElementById(\"findOnDiscord\").innerHTML = getHeaderAndFooterTranslation(\"Find <b>#pymupdf</b> on <b>Discord</b>\");\n      document.getElementById(\"forumCTAText\").innerHTML = getHeaderAndFooterTranslation(\"Have a <b>&nbsp;question</b>? Need some <b>&nbsp;answers</b>?&nbsp;\");\n      document.getElementById(\"footerDisclaimer\").innerHTML = getHeaderAndFooterTranslation(\"This software is provided AS-IS with no warranty, either express or implied. This software is distributed under license and may not be copied, modified or distributed except as expressly authorized under the terms of that license. Refer to licensing information at <a href='https://www.artifex.com?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=footer-link'>artifex.com</a> or contact Artifex Software Inc., 39 Mesa Street, Suite 108A, San Francisco CA 94129, United States for further information.\");\n\n\n      // more translation for admonition-title as the in-built translation isn't great, needs: 注釈 -> 注\n      if (docLanguage == \"ja\") {\n          const collection = document.getElementsByClassName(\"admonition-title\");\n          for (var i=0;i<collection.length;i++) {\n              collection[i].innerHTML = \"注\";\n          }\n      }\n\n\n   </script>\n\n.. rst-class:: footer-version\n\n  This documentation covers all versions up to |version|.\n\n\n.. External Links:\n\n.. _pdf2docx: https://pdf2docx.readthedocs.io/en/latest/\n.. _pdf2docx extract tables method: https://pdf2docx.readthedocs.io/en/latest/quickstart.table.html\n\n"
  },
  {
    "path": "docs/functions.rst",
    "content": ".. include:: header.rst\n\n============\nFunctions\n============\nThe following are miscellaneous functions and attributes on a fairly low-level technical detail.\n\nSome functions provide detail access to PDF structures. Others are stripped-down, high performance versions of other functions which provide more information.\n\nYet others are handy, general-purpose utilities.\n\n\n==================================== ==============================================================\n**Function**                         **Short Description**\n==================================== ==============================================================\n:attr:`Annot.apn_bbox`               PDF only: bbox of the appearance object\n:attr:`Annot.apn_matrix`             PDF only: the matrix of the appearance object\n:attr:`Page.is_wrapped`              check whether contents wrapping is present\n:meth:`adobe_glyph_names`            list of glyph names defined in **Adobe Glyph List**\n:meth:`adobe_glyph_unicodes`         list of unicodes defined in **Adobe Glyph List**\n:meth:`Annot.clean_contents`         PDF only: clean the annot's :data:`contents` object\n:meth:`Annot.set_apn_bbox`           PDF only: set the bbox of the appearance object\n:meth:`Annot.set_apn_matrix`         PDF only: set the matrix of the appearance object\n:meth:`ConversionHeader`             return header string for *get_text* methods\n:meth:`ConversionTrailer`            return trailer string for *get_text* methods\n:meth:`Document.del_xml_metadata`    PDF only: remove XML metadata\n:meth:`Document.get_char_widths`     PDF only: return a list of glyph widths of a font\n:meth:`Document.get_new_xref`        PDF only: create and return a new :data:`xref` entry\n:meth:`Document.is_stream`           PDF only: check whether an :data:`xref` is a stream object\n:meth:`Document.xml_metadata_xref`   PDF only: return XML metadata :data:`xref` number\n:meth:`Document.xref_length`         PDF only: return length of :data:`xref` table\n:meth:`EMPTY_IRECT`                  return the (standard) empty / invalid rectangle\n:meth:`EMPTY_QUAD`                   return the (standard) empty / invalid quad\n:meth:`EMPTY_RECT`                   return the (standard) empty / invalid rectangle\n:meth:`get_pdf_now`                  return the current timestamp in PDF format\n:meth:`get_pdf_str`                  return PDF-compatible string\n:meth:`get_text_length`              return string length for a given font & :data:`fontsize`\n:meth:`glyph_name_to_unicode`        return unicode from a glyph name\n:meth:`image_profile`                return a dictionary of basic image properties\n:meth:`INFINITE_IRECT`               return the (only existing) infinite rectangle\n:meth:`INFINITE_QUAD`                return the (only existing) infinite quad\n:meth:`INFINITE_RECT`                return the (only existing) infinite rectangle\n:meth:`make_table`                   split rectangle in sub-rectangles\n:meth:`Page.clean_contents`          PDF only: clean the page's :data:`contents` objects\n:meth:`Page.get_bboxlog`             list of rectangles that envelop text, drawing or image objects\n:meth:`Page.get_contents`            PDF only: return a list of content :data:`xref` numbers\n:meth:`Page.get_displaylist`         create the page's display list\n:meth:`Page.get_text_blocks`         extract text blocks as a Python list\n:meth:`Page.get_text_words`          extract text words as a Python list\n:meth:`Page.get_texttrace`           low-level text information\n:meth:`Page.read_contents`           PDF only: get complete, concatenated /Contents source\n:meth:`Page.run`                     run a page through a device\n:meth:`Page.set_contents`            PDF only: set page's :data:`contents` to some :data:`xref`\n:meth:`Page.wrap_contents`           wrap contents with stacking commands\n:meth:`css_for_pymupdf_font`         create CSS source for a font in package pymupdf_fonts\n:meth:`paper_rect`                   return rectangle for a known paper format\n:meth:`paper_size`                   return width, height for a known paper format\n:meth:`paper_sizes`                  dictionary of pre-defined paper formats\n:meth:`planish_line`                 matrix to map a line to the x-axis\n:meth:`recover_char_quad`            compute the quad of a char (\"rawdict\")\n:meth:`recover_line_quad`            compute the quad of a subset of line spans\n:meth:`recover_quad`                 compute the quad of a span (\"dict\", \"rawdict\")\n:meth:`recover_span_quad`            compute the quad of a subset of span characters\n:meth:`set_messages`                 set destination of |PyMuPDF| messages.\n:meth:`sRGB_to_pdf`                  return PDF RGB color tuple from an sRGB integer\n:meth:`sRGB_to_rgb`                  return (R, G, B) color tuple from an sRGB integer\n:meth:`unicode_to_glyph_name`        return glyph name from a unicode\n:meth:`get_tessdata`                 locates the language support of the Tesseract-OCR installation\n:meth:`colors_pdf_dict`              return dict of color names.\n:meth:`colors_wx_list`               return list of color names.\n:attr:`fitz_fontdescriptors`         dictionary of available supplement fonts\n:attr:`PYMUPDF_MESSAGE`              destination of |PyMuPDF| messages.\n:attr:`pdfcolor`                     dictionary of almost 500 RGB colors in PDF format.\n==================================== ==============================================================\n\n   .. method:: paper_size(s)\n\n      Convenience function to return width and height of a known paper format code. These values are given in pixels for the standard resolution 72 pixels = 1 inch.\n\n      Currently defined formats include **'A0'** through **'A10'**, **'B0'** through **'B10'**, **'C0'** through **'C10'**, **'Card-4x6'**, **'Card-5x7'**, **'Commercial'**, **'Executive'**, **'Invoice'**, **'Ledger'**, **'Legal'**, **'Legal-13'**, **'Letter'**, **'Monarch'** and **'Tabloid-Extra'**, each in either portrait or landscape format.\n\n      A format name must be supplied as a string (case **in** \\sensitive), optionally suffixed with \"-L\" (landscape) or \"-P\" (portrait). No suffix defaults to portrait.\n\n      :arg str s: any format name from above in upper or lower case, like *\"A4\"* or *\"letter-l\"*.\n\n      :rtype: tuple\n      :returns: *(width, height)* of the paper format. For an unknown format *(-1, -1)* is returned. Examples: *pymupdf.paper_size(\"A4\")* returns *(595, 842)* and *pymupdf.paper_size(\"letter-l\")* delivers *(792, 612)*.\n\n-----\n\n   .. method:: paper_rect(s)\n\n      Convenience function to return a :ref:`Rect` for a known paper format.\n\n      :arg str s: any format name supported by :meth:`paper_size`.\n\n      :rtype: :ref:`Rect`\n      :returns: *pymupdf.Rect(0, 0, width, height)* with *width, height=pymupdf.paper_size(s)*.\n\n      >>> import pymupdf\n      >>> pymupdf.paper_rect(\"letter-l\")\n      pymupdf.Rect(0.0, 0.0, 792.0, 612.0)\n      >>>\n\n-----\n\n   .. method:: set_messages(*, text=None, fd=None, stream=None, path=None, path_append=None, pylogging=None, pylogging_logger=None, pylogging_level=None, pylogging_name=None, )\n\n      Sets destination of |PyMuPDF| messages to a file descriptor,\n      a file, an existing stream or `Python's logging system\n      <https://docs.python.org/3/library/logging.html>`_.\n\n      Usually one would only set one arg, or one or more `pylogging*` args.\n\n      :arg str text:\n          A text specification of destination; for details see description of\n          environmental variable `PYMUPDF_MESSAGE`.\n      :arg int fd:\n          Write to file descriptor.\n      :arg stream:\n          Write to existing stream, which must have methods `.write(text)` and\n          `.flush()`.\n      :arg str path:\n          Write to a file.\n      :arg str path_append:\n          Append to a file.\n      :arg pylogging:\n          Write to Python's `logging` system.\n      :arg logging.Logger pylogging_logger:\n          Write to Python's `logging` system using specified Logger.\n      :arg int pylogging_level:\n          Write to Python's `logging` system using specified level.\n      :arg str pylogging_name:\n          Write to Python's `logging` system using specified logger name.\n          Only used if `pylogging_logger` is ``None``. Default is `pymupdf`.\n\n      If any `pylogging*` arg is not ``None``, we write to `Python's logging system\n      <https://docs.python.org/3/library/logging.html>`_.\n\n-----\n\n   .. method:: sRGB_to_pdf(srgb)\n\n      *New in v1.17.4*\n\n      Convenience function returning a PDF color triple (red, green, blue) for a given sRGB color integer as it occurs in :meth:`Page.get_text` dictionaries \"dict\" and \"rawdict\".\n\n      :arg int srgb: an integer of format RRGGBB, where each color component is an integer in range(255).\n\n      :returns: a tuple (red, green, blue) with float items in interval *0 <= item <= 1* representing the same color. Example `sRGB_to_pdf(0xff0000) = (1, 0, 0)` (red).\n\n-----\n\n   .. method:: sRGB_to_rgb(srgb)\n\n      *New in v1.17.4*\n\n      Convenience function returning a color (red, green, blue) for a given *sRGB* color integer.\n\n      :arg int srgb: an integer of format RRGGBB, where each color component is an integer in range(255).\n\n      :returns: a tuple (red, green, blue) with integer items in `range(256)` representing the same color. Example `sRGB_to_pdf(0xff0000) = (255, 0, 0)` (red).\n\n-----\n\n   .. method:: glyph_name_to_unicode(name)\n\n      *New in v1.18.0*\n\n      Return the unicode number of a glyph name based on the **Adobe Glyph List**.\n\n      :arg str name: the name of some glyph. The function is based on the `Adobe Glyph List <https://github.com/adobe-type-tools/agl-aglfn/blob/master/glyphlist.txt>`_.\n\n      :rtype: int\n      :returns: the unicode. Invalid ``name`` entries return `0xfffd (65533)`.\n\n      .. note:: A similar functionality is provided by package `fontTools <https://pypi.org/project/fonttools/>`_ in its *agl* sub-package.\n\n-----\n\n   .. method:: unicode_to_glyph_name(ch)\n\n      *New in v1.18.0*\n\n      Return the glyph name of a unicode number, based on the **Adobe Glyph List**.\n\n      :arg int ch: the unicode given by e.g. `ord(\"ß\")`. The function is based on the `Adobe Glyph List <https://github.com/adobe-type-tools/agl-aglfn/blob/master/glyphlist.txt>`_.\n\n      :rtype: str\n      :returns: the glyph name. E.g. `pymupdf.unicode_to_glyph_name(ord(\"Ä\"))` returns `'Adieresis'`.\n\n      .. note:: A similar functionality is provided by package `fontTools <https://pypi.org/project/fonttools/>`_: in its *agl* sub-package.\n\n-----\n\n   .. method:: adobe_glyph_names()\n\n      *New in v1.18.0*\n\n      Return a list of glyph names defined in the **Adobe Glyph List**.\n\n      :rtype: list\n      :returns: list of strings.\n\n      .. note:: A similar functionality is provided by package `fontTools <https://pypi.org/project/fonttools/>`_ in its *agl* sub-package.\n\n-----\n\n   .. method:: adobe_glyph_unicodes()\n\n      *New in v1.18.0*\n\n      Return a list of unicodes for there exists a glyph name in the **Adobe Glyph List**.\n\n      :rtype: list\n      :returns: list of integers.\n\n      .. note:: A similar functionality is provided by package `fontTools <https://pypi.org/project/fonttools/>`_ in its *agl* sub-package.\n\n-----\n\n   .. method:: css_for_pymupdf_font(fontcode, *, CSS=None, archive=None, name=None)\n\n      *New in v1.21.0*\n\n      **Utility function for use with \"Story\" applications.**\n\n      Create CSS `@font-face` items for the given fontcode in pymupdf-fonts. Creates a CSS font-family for all fonts starting with string \"fontcode\".\n\n      The font naming convention in package pymupdf-fonts is \"fontcode<sf>\", where the suffix \"sf\" is one of \"\" (empty), \"it\"/\"i\", \"bo\"/\"b\" or \"bi\". These suffixes thus represent the regular, italic, bold or bold-italic variants of that font.\n\n      For example, font code \"notos\" refers to fonts\n\n      *  \"notos\" - \"Noto Sans Regular\"\n      *  \"notosit\" - \"Noto Sans Italic\"\n      *  \"notosbo\" - \"Noto Sans Bold\"\n      *  \"notosbi\" - \"Noto Sans Bold Italic\"\n\n      The function creates (up to) four CSS `@font-face` definitions and collectively assigns the `font-family` name \"notos\" to them (or the \"name\" value if provided). Associated font buffers are placed / added to the provided archive.\n\n      To use the font in the Python API for :ref:`Story`, execute `.set_font(fontcode)` (or \"name\" if given). The correct font weight or style will automatically be selected as required.\n\n      For example to replace the \"sans-serif\" HTML standard (i.e. Helvetica) with the above \"notos\", execute the following. Whenever \"sans-serif\" is used (whether explicitly or implicitly), the Noto Sans fonts will be selected.\n\n      `CSS = pymupdf.css_for_pymupdf_font(\"notos\", name=\"sans-serif\", archive=...)`\n\n      Expects and returns the CSS source, with the new CSS definitions appended.\n\n      :arg str fontcode: one of the font codes present in package `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ (usually) representing the regular version of the font family.\n      :arg str CSS: any already existing CSS source, or `None`. The function will append its new definitions to this. This is the string that **must be used** as `user_css` when creating the :ref:`Story`.\n      :arg archive: :ref:`Archive`, **mandatory**. All font binaries (i.e. up to four) found for \"fontcode\" will be added to the archive. This is the archive that **must be used** as `archive` when creating the :ref:`Story`.\n      :arg str name: the name under which the \"fontcode\" fonts should be found. If omitted, \"fontcode\" will be used.\n\n      :rtype: str\n      :returns: Modified CSS, with appended `@font-face` statements for each font variant of fontcode. Fontbuffers associated with \"fontcode\" will have been added to 'archive'. The function will automatically find up to 4 font variants. All pymupdf-fonts (that are no special purpose like math or music, etc.) have regular, bold, italic and bold-italic variants. To see currently available font codes check `pymupdf.fitz_fontdescriptors.keys()`. This will show something like `dict_keys(['cascadia', 'cascadiai', 'cascadiab', 'cascadiabi', 'figbo', 'figo', 'figbi', 'figit', 'fimbo', 'fimo', 'spacembo', 'spacembi', 'spacemit', 'spacemo', 'math', 'music', 'symbol1', 'symbol2', 'notosbo', 'notosbi', 'notosit', 'notos', 'ubuntu', 'ubuntubo', 'ubuntubi', 'ubuntuit', 'ubuntm', 'ubuntmbo', 'ubuntmbi', 'ubuntmit'])`.\n\n      Here is a complete snippet for using the \"Noto Sans\" font instead of \"Helvetica\"::\n\n         arch = pymupdf.Archive()\n         CSS = pymupdf.css_for_pymupdf_font(\"notos\", name=\"sans-serif\", archive=arch)\n         story = pymupdf.Story(user_css=CSS, archive=arch)\n\n\n-----\n\n.. _Functions_make_table:\n\n   .. method:: make_table(rect, cols=1, rows=1)\n\n      *New in v1.17.4*\n\n      Convenience function to split a rectangle into sub-rectangles of equal size. Returns a list of `rows` lists, each containing `cols` :ref:`Rect` items. Each sub-rectangle can then be addressed by its row and column index.\n\n      :arg rect_like rect: the rectangle to split.\n      :arg int cols: the desired number of columns.\n      :arg int rows: the desired number of rows.\n      :returns: a list of :ref:`Rect` objects of equal size, whose union equals *rect*. Here is the layout of a 3x4 table created by `cell = pymupdf.make_table(rect, cols=4, rows=3)`:\n\n      .. image:: images/img-make-table.*\n         :scale: 60\n\n\n-----\n\n   .. method:: planish_line(p1, p2)\n\n      * New in version 1.16.2)*\n\n      Return a matrix which maps the line from p1 to p2 to the x-axis such that p1 will become (0,0) and p2 a point with the same distance to (0,0).\n\n      :arg point_like p1: starting point of the line.\n      :arg point_like p2: end point of the line.\n\n      :rtype: :ref:`Matrix`\n      :returns: a matrix which combines a rotation and a translation::\n\n            >>> p1 = pymupdf.Point(1, 1)\n            >>> p2 = pymupdf.Point(4, 5)\n            >>> abs(p2 - p1)  # distance of points\n            5.0\n            >>> m = pymupdf.planish_line(p1, p2)\n            >>> p1 * m\n            Point(0.0, 0.0)\n            >>> p2 * m\n            Point(5.0, -5.960464477539063e-08)\n            >>> # distance of the resulting points\n            >>> abs(p2 * m - p1 * m)\n            5.0\n\n\n         .. image:: images/img-planish.png\n            :scale: 40\n\n\n-----\n\n   .. method:: paper_sizes\n\n      A dictionary of pre-defines paper formats. Used as basis for :meth:`paper_size`.\n\n-----\n\n   .. attribute:: fitz_fontdescriptors\n\n      * New in v1.17.5\n\n      A dictionary of usable fonts from repository `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_. Items are keyed by their reserved fontname and provide information like this::\n\n         In [2]: pymupdf.fitz_fontdescriptors.keys()\n         Out[2]: dict_keys(['figbo', 'figo', 'figbi', 'figit', 'fimbo', 'fimo',\n         'spacembo', 'spacembi', 'spacemit', 'spacemo', 'math', 'music', 'symbol1',\n         'symbol2'])\n         In [3]: pymupdf.fitz_fontdescriptors[\"fimo\"]\n         Out[3]:\n         {'name': 'Fira Mono Regular',\n         'size': 125712,\n         'mono': True,\n         'bold': False,\n         'italic': False,\n         'serif': True,\n         'glyphs': 1485}\n\n      If `pymupdf-fonts` is not installed, the dictionary is empty.\n\n      The dictionary keys can be used to define a :ref:`Font` via e.g. `font = pymupdf.Font(\"fimo\")` -- just like you can do it with the builtin fonts \"Helvetica\" and friends.\n\n-----\n\n   .. attribute:: PYMUPDF_MESSAGE\n   \n      If in `os.environ` when |PyMuPDF| is imported, sets destination of\n      |PyMuPDF| messages. Otherwise messages are sent to `sys.stdout`.\n      \n      *\n        If the value starts with `fd:`, the remaining text should be an integer\n        file descriptor to which messages are written.\n    \n        * For example `PYMUPDF_MESSAGE=fd:2` will send messages to stderr.\n      *\n        If the value starts with `path:`, the remaining text is the path of a\n        file to which messages are written. If the file already exists, it is\n        truncated.\n      *\n        If the value starts with `path+:`, the remaining text is the path of\n        file to which messages are written. If the file already exists, we\n        append output.\n\n      *\n        If the value starts with `logging:`, messages are written to `Python's\n        logging system <https://docs.python.org/3/library/logging.html>`_. The\n        remaining text can contain comma-separated name=value items:\n    \n        * `level=<int>` sets the logging level.\n        * `name=<str>` sets the logger name (default is `pymupdf`).\n    \n        Other items are ignored.\n    \n      * Other prefixes will cause an error.\n      \n      Also see `set_messages()`.\n\n\n-----\n\n   .. attribute:: pdfcolor\n\n      * New in v1.19.6\n\n      Contains about 500 RGB colors in PDF format with the color name as key. To see what is there, you can obviously look at `pymupdf.pdfcolor.keys()`.\n\n      Examples:\n\n        * `pymupdf.pdfcolor[\"red\"] = (1.0, 0.0, 0.0)`\n        * `pymupdf.pdfcolor[\"skyblue\"] = (0.5294117647058824, 0.807843137254902, 0.9215686274509803)`\n        * `pymupdf.pdfcolor[\"wheat\"] = (0.9607843137254902, 0.8705882352941177, 0.7019607843137254)`\n\n-----\n\n   .. method:: get_pdf_now()\n\n      Convenience function to return the current local timestamp in PDF compatible format, e.g. *D:20170501121525-04'00'* for local datetime May 1, 2017, 12:15:25 in a timezone 4 hours westward of the UTC meridian.\n\n      :rtype: str\n      :returns: current local PDF timestamp.\n\n-----\n\n   .. method:: get_text_length(text, fontname=\"helv\", fontsize=11, encoding=TEXT_ENCODING_LATIN)\n\n      * New in version 1.14.7\n\n      Calculate the length of text on output with a given **builtin** font, :data:`fontsize` and encoding.\n\n      :arg str text: the text string.\n      :arg str fontname: the font name. Must be one of either the :ref:`Base-14-Fonts` or the CJK fonts, identified by their \"reserved\" fontnames (see table in :meth:`Page.insert_font`).\n      :arg float fontsize: the :data:`fontsize`.\n      :arg int encoding: the encoding to use. Besides 0 = Latin, 1 = Greek and 2 = Cyrillic (Russian) are available. Relevant for Base-14 fonts \"Helvetica\", \"Courier\" and \"Times\" and their variants only. Make sure to use the same value as in the corresponding text insertion.\n      :rtype: float\n      :returns: the length in points the string will have (e.g. when used in :meth:`Page.insert_text`).\n\n      .. note:: This function will only do the calculation -- it won't insert font nor text.\n\n      .. note:: The :ref:`Font` class offers a similar method, :meth:`Font.text_length`, which supports Base-14 fonts and any font with a character map (CMap, Type 0 fonts).\n\n      .. warning:: If you use this function to determine the required rectangle width for the (:ref:`Page` or :ref:`Shape`) *insert_textbox* methods, be aware that they calculate on a **by-character level**. Because of rounding effects, this will mostly lead to a slightly larger number: *sum([pymupdf.get_text_length(c) for c in text]) > pymupdf.get_text_length(text)*. So either (1) do the same, or (2) use something like *pymupdf.get_text_length(text + \"'\")* for your calculation.\n\n-----\n\n   .. method:: get_pdf_str(text)\n\n      Make a PDF-compatible string: if the text contains code points *ord(c) > 255*, then it will be converted to UTF-16BE with BOM as a hexadecimal character string enclosed in \"<>\" brackets like *<feff...>*. Otherwise, it will return the string enclosed in (round) brackets, replacing any characters outside the ASCII range with some special code. Also, every \"(\", \")\" or backslash is escaped with a backslash.\n\n      :arg str text: the object to convert\n\n      :rtype: str\n      :returns: PDF-compatible string enclosed in either *()* or *<>*.\n\n-----\n\n   .. method:: image_profile(stream)\n\n      * New in v1.16.7\n      * Changed in v1.19.5: also return natural image orientation extracted from EXIF data if present.\n      * Changed in v1.22.5: always return `None` in error cases instead of an empty dictionary.\n\n      Show important properties of an image provided as a memory area. Its main purpose is to avoid using other Python packages just to determine them.\n\n      :arg bytes|bytearray|BytesIO|file stream: either an image in memory or an **opened** file. An image in memory may be any of the formats `bytes`, `bytearray` or `io.BytesIO`.\n\n      :rtype: dict\n      :returns:\n         No exception is ever raised. In case of an error, `None` is returned. Otherwise, there are the following items::\n\n            In [2]: pymupdf.image_profile(open(\"nur-ruhig.jpg\", \"rb\").read())\n            Out[2]:\n            {'width': 439,\n            'height': 501,\n            'orientation': 0,  # natural orientation (from EXIF)\n            'transform': (1.0, 0.0, 0.0, 1.0, 0.0, 0.0),  # orientation matrix\n            'xres': 96,\n            'yres': 96,\n            'colorspace': 3,\n            'bpc': 8,\n            'ext': 'jpeg',\n            'cs-name': 'DeviceRGB'}\n\n         There is the following relation to **Exif** information encoded in `orientation`, and correspondingly in the `transform` matrix-like (quoted from MuPDF documentation, *ccw* = counter-clockwise):\n\n            0. Undefined\n            1. 0 degree ccw rotation. (Exif = 1)\n            2. 90 degree ccw rotation. (Exif = 8)\n            3. 180 degree ccw rotation. (Exif = 3)\n            4. 270 degree ccw rotation. (Exif = 6)\n            5. flip on X. (Exif = 2)\n            6. flip on X, then rotate ccw by 90 degrees. (Exif = 5)\n            7. flip on X, then rotate ccw by 180 degrees. (Exif = 4)\n            8. flip on X, then rotate ccw by 270 degrees. (Exif = 7)\n\n\n         .. note::\n\n            * For some \"exotic\" images (FAX encodings, RAW formats and the like), this method will not work. You can however still work with such images in PyMuPDF, e.g. by using :meth:`Document.extract_image` or create pixmaps via `Pixmap(doc, xref)`. These methods will automatically convert exotic images to the PNG format before returning results.\n            * You can also get the properties of images embedded in a PDF, via their :data:`xref`. In this case make sure to extract the raw stream: `pymupdf.image_profile(doc.xref_stream_raw(xref))`.\n            * Images as returned by the image blocks of :meth:`Page.get_text` using \"dict\" or \"rawdict\" options are also supported.\n\n\n-----\n\n   .. method:: ConversionHeader(\"text\", filename=\"UNKNOWN\")\n\n      Return the header string required to make a valid document out of page text outputs.\n\n      :arg str output: type of document. Use the same as the output parameter of *get_text()*.\n\n      :arg str filename: optional arbitrary name to use in output types \"json\" and \"xml\".\n\n      :rtype: str\n\n-----\n\n   .. method:: ConversionTrailer(output)\n\n      Return the trailer string required to make a valid document out of page text outputs. See :meth:`Page.get_text` for an example.\n\n      :arg str output: type of document. Use the same as the output parameter of *get_text()*.\n\n      :rtype: str\n\n-----\n\n   .. method:: Document.del_xml_metadata()\n\n      Delete an object containing XML-based metadata from the PDF. (Py-) MuPDF does not support XML-based metadata. Use this if you want to make sure that the conventional metadata dictionary will be used exclusively. Many thirdparty PDF programs insert their own metadata in XML format and thus may override what you store in the conventional dictionary. This method deletes any such reference, and the corresponding PDF object will be deleted during next garbage collection of the file.\n\n-----\n\n   .. method:: Document.xml_metadata_xref()\n\n      Return the XML-based metadata :data:`xref` of the PDF if present -- also refer to :meth:`Document.del_xml_metadata`. You can use it to retrieve the content via :meth:`Document.xref_stream` and then work with it using some XML software.\n\n      :rtype: int\n      :returns: :data:`xref` of PDF file level XML metadata -- or 0 if none exists.\n\n-----\n\n   .. method:: Page.run(dev, transform)\n\n      Run a page through a device.\n\n      :arg dev: Device, obtained from one of the :ref:`Device` constructors.\n      :type dev: :ref:`Device`\n\n      :arg transform: Transformation to apply to the page. Set it to :ref:`Identity` if no transformation is desired.\n      :type transform: :ref:`Matrix`\n\n-----\n\n   .. method:: Page.get_bboxlog(layers=False)\n\n      * New in v1.19.0\n      * Changed in v1.22.0: optionally also return the OCG name applicable to the boundary box.\n\n      :returns: a list of rectangles that envelop text, image or drawing objects. Each item is a tuple `(type, (x0, y0, x1, y1))` where the second tuple consists of rectangle coordinates, and *type* is one of the following values. If `layers=True`, there is a third item containing the OCG name or `None`: `(type, (x0, y0, x1, y1), None)`.\n\n         * `\"fill-text\"` -- normal text (painted without character borders)\n         * `\"stroke-text\"` -- text showing character borders only\n         * `\"ignore-text\"` -- text that should not be displayed (e.g. as used by OCR text layers)\n         * `\"fill-path\"` -- drawing with fill color (and no border)\n         * `\"stroke-path\"` -- drawing with border (and no fill color)\n         * `\"fill-image\"` -- displays an image\n         * `\"fill-shade\"` -- display a shading\n\n         The item sequence represents the **sequence in which these commands are executed** to build the page's appearance. Therefore, if an item's bbox intersects or contains that of a previous item, then the previous item may be (partially) covered / hidden.\n\n\n         So this list can be used to detect such situations. An item's index in this list equals the value of a `\"seqno\"` in dictionaries as returned by :meth:`Page.get_drawings` and :meth:`Page.get_texttrace`.\n\n\n-----\n\n   .. method:: Page.get_texttrace()\n\n      * New in v1.18.16\n      * Changed in v1.19.0: added key \"seqno\".\n      * Changed in v1.19.1: stroke and fill colors now always are either RGB or GRAY\n      * Changed in v1.19.3: span and character bboxes are now also correct if `dir != (1, 0)`.\n      * Changed in v1.22.0: add new dictionary key \"layer\".\n\n\n      Return low-level text information of the page. The method is available for **all** document types. The result is a list of Python dictionaries with the following content::\n\n         {\n            'ascender': 0.83251953125,          # font ascender (1)\n            'bbox': (458.14019775390625,        # span bbox x0 (7)\n                     749.4671630859375,         # span bbox y0\n                     467.76458740234375,        # span bbox x1\n                     757.5071411132812),        # span bbox y1\n            'bidi': 0,                          # bidirectional level (1)\n            'chars': (                          # char information, tuple[tuple]\n                        (45,                    # unicode (4)\n                        16,                     # glyph id (font dependent)\n                        (458.14019775390625,    # origin.x (1)\n                        755.3758544921875),     # origin.y (1)\n                        (458.14019775390625,    # char bbox x0 (6)\n                        749.4671630859375,      # char bbox y0\n                        462.9649963378906,      # char bbox x1\n                        757.5071411132812)),    # char bbox y1\n                        ( ... ),                # more characters\n                     ),\n            'color': (0.0,),                    # text color, tuple[float] (1)\n            'colorspace': 1,                    # number of colorspace components (1)\n            'descender': -0.30029296875,        # font descender (1)\n            'dir': (1.0, 0.0),                  # writing direction (1)\n            'flags': 12,                        # font flags (1)\n            'font': 'CourierNewPSMT',           # font name (1)\n            'linewidth': 0.4019999980926514,    # current line width value (3)\n            'opacity': 1.0,                     # alpha value of the text (5)\n            'layer': None,                      # name of Optional Content Group (9)\n            'seqno': 246,                       # sequence number (8)\n            'size': 8.039999961853027,          # font size (1)\n            'spacewidth': 4.824785133358091,    # width of space char\n            'type': 0,                          # span type (2)\n            'wmode': 0                          # writing mode (1)\n         }\n\n      Details:\n\n      1. Information above tagged with \"(1)\" has the same meaning and value as explained in :ref:`TextPage`.\n\n         - Please note that the font ``flags`` value will never contain a *superscript* flag bit: the detection of superscripts is done within MuPDF :ref:`TextPage` code -- it is not a property of any font.\n         - Also note, that the text *color* is encoded as the usual tuple of floats 0 <= f <= 1 -- not in sRGB format. Depending on `span[\"type\"]`, interpret this as fill color or stroke color.\n\n      2. There are 3 text span types:\n\n         - 0: Filled text -- equivalent to PDF text rendering mode 0 (`0 Tr`, the default in PDF), only each character's \"inside\" is shown.\n         - 1: Stroked text -- equivalent to `1 Tr`, only the character borders are shown.\n         - 3: Ignored text -- equivalent to `3 Tr` (hidden text).\n\n      3. Line width in this context is important only for processing `span[\"type\"] != 0`: it determines the thickness of the character's border line. This value may not be provided at all with the text data. In this case, a value of 5% of the :data:`fontsize` (`span[\"size\"] * 0,05`) is generated. Often, an \"artificial\" bold text in PDF is created by `2 Tr`. There is no equivalent span type for this case. Instead, respective text is represented by two consecutive spans -- which are identical in every aspect, except for their types, which are 0, resp 1. It is your responsibility to handle this type of situation - in :meth:`Page.get_text`, MuPDF is doing this for you.\n      4. For data compactness, the character's unicode is provided here. Use built-in function `chr()` for the character itself.\n      5. The alpha / opacity value of the span's text, `0 <= opacity <= 1`, 0 is invisible text, 1 (100%) is intransparent. Depending on `span[\"type\"]`, interpret this value as *fill* opacity or, resp. *stroke* opacity.\n      6. *(Changed in v1.19.0)* This value is equal or close to `char[\"bbox\"]` of \"rawdict\". In particular, the bbox **height** value is always computed as if **\"small glyph heights\"** had been requested.\n      7. *(New in v1.19.0)* This is the union of all character bboxes.\n      8. *(New in v1.19.0)* Enumerates the commands that build up the page's appearance. Can be used to find out whether text is effectively hidden by objects, which are painted \"later\", or *over* some object. So if there is a drawing or image with a higher sequence number, whose bbox overlaps (parts of) this text span, one may assume that such an object hides the resp. text. Different text spans have identical sequence numbers if they were created in one go.\n      9. *(New in v1.22.0)* The name of the Optional Content Group (OCG) if applicable or `None`.\n\n      Here is a list of similarities and differences of `page.get_texttrace()` compared to `page.get_text(\"rawdict\")`:\n\n      * The method is up to **twice as fast,** compared to \"rawdict\" extraction. Depends on the amount of text.\n      * The returned data is very **much smaller in size** -- although it provides more information.\n      * Additional types of text **invisibility can be detected**: opacity = 0 or type > 1 or overlapping bbox of an object with a higher sequence number.\n      * If MuPDF returns unicode 0xFFFD (65533) for unrecognized characters, you may still be able to deduct desired information from the glyph id.\n      * The `span[\"chars\"]` **contains no spaces**, **except** the document creator has explicitly coded them. They **will never be generated** like it happens in :meth:`Page.get_text` methods. To provide some help for doing your own computations here, the width of a space character is given. This value is derived from the font where possible. Otherwise the value of a fallback font is taken.\n      * There is no effort to organize text like it happens for a :ref:`TextPage` (the hierarchy of blocks, lines, spans, and characters). Characters are simply extracted in sequence, one by one, and put in a span. Whenever any of the span's characteristics changes, a new span is started. So you may find characters with different `origin.y` values in the same span (which means they would appear in different lines). You cannot assume, that span characters are sorted in any particular order -- you must make sense of the info yourself, taking `span[\"dir\"]`, `span[\"wmode\"]`, etc. into account.\n      * Ligatures are represented like this:\n         - MuPDF handles the following ligatures: \"fi\", \"ff\", \"fl\", \"ft\", \"st\", \"ffi\", and \"ffl\" (only the first 3 are mostly ever used). If the page contains e.g. ligature \"fi\", you will find the following two character items subsequent to each other::\n\n            (102, glyph, (x, y), (x0, y0, x1, y1))  # 102 = ord(\"f\")\n            (105, -1, (x, y), (x0, y0, x0, y1))     # 105 = ord(\"i\"), empty bbox!\n\n         - This means that the bbox of the first ligature character is the area containing the complete, compound glyph. Subsequent ligature components are recognizable by their glyph value -1 and a bbox of width zero.\n         - You may want to replace those 2 or 3 char tuples by one, that represents the ligature itself. Use the following mapping of ligatures to unicodes:\n\n            + `\"ff\" -> 0xFB00`\n            + `\"fi\" -> 0xFB01`\n            + `\"fl\" -> 0xFB02`\n            + `\"ffi\" -> 0xFB03`\n            + `\"ffl\" -> 0xFB04`\n            + `\"ft\" -> 0xFB05`\n            + `\"st\" -> 0xFB06`\n\n            So you may want to replace the two example tuples above by the following single one: `(0xFB01, glyph, (x, y), (x0, y0, x1, y1))` (there is usually no need to lookup the correct glyph id for 0xFB01 in the resp. font, but you may execute `font.has_glyph(0xFB01)` and use its return value).\n\n      * **Changed in v1.19.3:** Similar to other text extraction methods, the character and span bboxes envelop the character quads. To recover the quads, follow the same methods :meth:`recover_quad`, :meth:`recover_char_quad` or :meth:`recover_span_quad` as explained in :ref:`textpagedict`. Use either `None` or `span[\"dir\"]` for the writing direction.\n\n      * **Changed in v1.21.1:** If applicable, the name of the OCG is shown in `\"layer\"`.\n\n-----\n\n   .. method:: Page.wrap_contents()\n\n      Ensures that the page's so-called graphics state is balanced and new content can be inserted correctly.\n      \n      In versions 1.24.1+ of PyMuPDF the method was improved and is being executed automatically as required, so you should no longer need to concern yourself with it.\n\n      We discourage using :meth:`Page.clean_contents` to achieve this.\n\n-----\n\n   .. attribute:: Page.is_wrapped\n\n      Indicate whether the page's so-called graphic state is balanced. If `False`, :meth:`Page.wrap_contents` should be executed if new content is inserted (only relevant in `overlay=True` mode). In newer versions (1.24.1+), this check and corresponding adjustments are automatically executed -- you therefore should not be concerned about this anymore.\n\n      :rtype: bool\n\n-----\n\n   .. method:: Page.get_text_blocks(flags=None)\n\n      Deprecated wrapper for :meth:`TextPage.extractBLOCKS`.  Use :meth:`Page.get_text` with the \"blocks\" option instead.\n\n      :rtype: list[tuple]\n\n-----\n\n   .. method:: Page.get_text_words(flags=None, delimiters=None)\n\n      Deprecated wrapper for :meth:`TextPage.extractWORDS`. Use :meth:`Page.get_text` with the \"words\" option instead.\n\n      :rtype: list[tuple]\n\n-----\n\n   .. method:: Page.get_displaylist()\n\n      Run a page through a list device and return its display list.\n\n      :rtype: :ref:`DisplayList`\n      :returns: the display list of the page.\n\n-----\n\n   .. method:: Page.get_contents()\n\n      PDF only: Retrieve a list of :data:`xref` of :data:`contents` objects of a page. May be empty or contain multiple integers. If the page is cleaned (:meth:`Page.clean_contents`), it will be no more than one entry. The \"source\" of each `/Contents` object can be individually read by :meth:`Document.xref_stream` using an item of this list. Method :meth:`Page.read_contents` in contrast walks through this list and concatenates the corresponding sources into one `bytes` object.\n\n      :rtype: list[int]\n\n-----\n\n   .. method:: Page.set_contents(xref)\n\n      PDF only: Let the page's `/Contents` key point to this xref. Any previously used contents objects will be ignored and can be removed via garbage collection.\n\n-----\n\n   .. method:: Page.clean_contents(sanitize=True)\n\n      * Changed in v1.17.6\n\n      PDF only: Clean and concatenate all :data:`contents` objects associated with this page. \"Cleaning\" includes syntactical corrections, standardizations and \"pretty printing\" of the contents stream. Discrepancies between :data:`contents` and :data:`resources` objects will also be corrected if sanitize is true. See :meth:`Page.get_contents` for more details.\n\n      Changed in version 1.16.0 Annotations are no longer implicitly cleaned by this method. Use :meth:`Annot.clean_contents` separately.\n\n      :arg bool sanitize: *(new in v1.17.6)* if true, synchronization between resources and their actual use in the contents object is snychronized. For example, if a font is not actually used for any text of the page, then it will be deleted from the `/Resources/Font` object.\n\n      .. warning:: This is a complex function which may generate large amounts of new data and render old data unused. It is **not recommended** using it together with the **incremental save** option. Also note that the resulting singleton new */Contents* object is **uncompressed**. So you should save to a **new file** using options *\"deflate=True, garbage=3\"*.\n\n         Do not any longer use this method to ensure correct insertions on PDF pages. Since PyMuPDF version 1.24.2 this is taken care of automatically.\n\n-----\n\n   .. method:: Page.read_contents()\n\n      *New in version 1.17.0.*\n      Return the concatenation of all :data:`contents` objects associated with the page -- without cleaning or otherwise modifying them. Use this method whenever you need to parse this source in its entirety without having to bother how many separate contents objects exist.\n\n      :rtype: bytes\n\n-----\n\n   .. method:: Annot.clean_contents(sanitize=True)\n\n      Clean the :data:`contents` streams associated with the annotation. This is the same type of action which :meth:`Page.clean_contents` performs -- just restricted to this annotation.\n\n\n-----\n\n   .. method:: Document.get_char_widths(xref=0, limit=256)\n\n      Return a list of character glyphs and their widths for a font that is present in the document. A font must be specified by its PDF cross reference number :data:`xref`. This function is called automatically from :meth:`Page.insert_text` and :meth:`Page.insert_textbox`. So you should rarely need to do this yourself.\n\n      :arg int xref: cross reference number of a font embedded in the PDF. To find a font :data:`xref`, use e.g. *doc.get_page_fonts(pno)* of page number *pno* and take the first entry of one of the returned list entries.\n\n      :arg int limit: limits the number of returned entries. The default of 256 is enforced for all fonts that only support 1-byte characters, so-called \"simple fonts\" (checked by this method). All :ref:`Base-14-Fonts` are simple fonts.\n\n      :rtype: list\n      :returns: a list of *limit* tuples. Each character *c* has an entry  *(g, w)* in this list with an index of *ord(c)*. Entry *g* (integer) of the tuple is the glyph id of the character, and float *w* is its normalized width. The actual width for some :data:`fontsize` can be calculated as *w * fontsize*. For simple fonts, the *g* entry can always be safely ignored. In all other cases *g* is the basis for graphically representing *c*.\n\n      This function calculates the pixel width of a string called *text*::\n\n       def pixlen(text, widthlist, fontsize):\n           try:\n               return sum([widthlist[ord(c)] for c in text]) * fontsize\n           except IndexError:\n               raise ValueError(f\"max. code point found: {ord(max(text))}, increase limit\")\n\n-----\n\n   .. method:: Document.is_stream(xref)\n\n      * New in version 1.14.14\n\n      PDF only: Check whether the object represented by :data:`xref` is a :data:`stream` type. Return is ``False`` if not a PDF or if the number is outside the valid xref range.\n\n      :arg int xref: :data:`xref` number.\n\n      :returns: ``True`` if the object definition is followed by data wrapped in keyword pair *stream*, *endstream*.\n\n-----\n\n   .. method:: Document.get_new_xref()\n\n      Increase the :data:`xref` by one entry and return that number. This can then be used to insert a new object.\n\n      :rtype: int\n            :returns: the number of the new :data:`xref` entry. Please note, that only a new entry in the PDF's cross reference table is created. At this point, there will not yet exist a PDF object associated with it. To create an (empty) object with this number use `doc.update_xref(xref, \"<<>>\")`.\n\n-----\n\n   .. method:: Document.xref_length()\n\n      Return length of :data:`xref` table.\n\n      :rtype: int\n      :returns: the number of entries in the :data:`xref` table.\n\n-----\n\n   .. method:: recover_quad(line_dir, span)\n\n      Compute the quadrilateral of a text span extracted via options \"dict\" or \"rawdict\" of :meth:`Page.get_text`.\n\n      :arg tuple line_dir: `line[\"dir\"]` of the owning line.  Use `None` for a span from :meth:`Page.get_texttrace`.\n      :arg dict span: the span.\n      :returns: the :ref:`Quad` of the span, usable for text marker annotations ('Highlight', etc.).\n\n-----\n\n   .. method:: recover_char_quad(line_dir, span, char)\n\n      Compute the quadrilateral of a text character extracted via option \"rawdict\" of :meth:`Page.get_text`.\n\n      :arg tuple line_dir: `line[\"dir\"]` of the owning line. Use `None` for a span from :meth:`Page.get_texttrace`.\n      :arg dict span: the span.\n      :arg dict char: the character.\n      :returns: the :ref:`Quad` of the character, usable for text marker annotations ('Highlight', etc.).\n\n-----\n\n   .. method:: recover_span_quad(line_dir, span, chars=None)\n\n      Compute the quadrilateral of a subset of characters of a span extracted via option \"rawdict\" of :meth:`Page.get_text`.\n\n      :arg tuple line_dir: `line[\"dir\"]` of the owning line. Use `None` for a span from :meth:`Page.get_texttrace`.\n      :arg dict span: the span.\n      :arg list chars: the characters to consider. If given, the selected extraction option must be \"rawdict\".\n      :returns: the :ref:`Quad` of the selected characters, usable for text marker annotations ('Highlight', etc.).\n\n-----\n\n   .. method:: recover_line_quad(line, spans=None)\n\n      Compute the quadrilateral of a subset of spans of a text line extracted via options \"dict\" or \"rawdict\" of :meth:`Page.get_text`.\n\n      :arg dict line: the line.\n      :arg list spans: a sub-list of `line[\"spans\"]`. If omitted, the full line quad will be returned.\n      :returns: the :ref:`Quad` of the selected line spans, usable for text marker annotations ('Highlight', etc.).\n\n-----\n\n   .. method:: get_tessdata(tessdata=None)\n    \n    Detect Tesseract language support folder.\n\n    This function is used to enable OCR via Tesseract even if the language\n    support folder is not specified directly or in environment variable\n    TESSDATA_PREFIX.\n\n    * If <tessdata> is set we return it directly.\n    \n    * Otherwise we return `os.environ['TESSDATA_PREFIX']` if set.\n    \n    * Otherwise we search for a Tesseract installation and return its language\n      support folder.\n\n    * Otherwise we raise an exception.\n\n-----\n\n   .. method:: INFINITE_QUAD()\n\n   .. method:: INFINITE_RECT()\n\n   .. method:: INFINITE_IRECT()\n\n      Return the (unique) infinite rectangle `Rect(-2147483648.0, -2147483648.0, 2147483520.0, 2147483520.0)`, resp. the :ref:`IRect` and :ref:`Quad` counterparts. It is the largest possible rectangle: all valid rectangles are contained in it.\n\n-----\n\n   .. method:: EMPTY_QUAD()\n\n   .. method:: EMPTY_RECT()\n\n   .. method:: EMPTY_IRECT()\n\n      Return the \"standard\" empty and invalid rectangle `Rect(2147483520.0, 2147483520.0, -2147483648.0, -2147483648.0)` resp. quad. Its top-left and bottom-right point values are reversed compared to the infinite rectangle. It will e.g. be used to indicate empty bboxes in `page.get_text(\"dict\")` dictionaries. There are however infinitely many empty or invalid rectangles.\n\n-----\n\n   .. method:: colors_pdf_dict()\n   \n      Returns a dict mapping lower-case color name to `(red, green, blue)`\n      tuple, and `red`, `green`, `blue` are floats in range 0..1.\n\n   .. method:: colors_wx_list()\n   \n      Returns a list of `(colorname, red, green, blue)` tuples, where\n      `colorname` is upper case and `red`, `green`, `blue` are integers in\n      range 0..255.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/glossary.rst",
    "content": ".. include:: header.rst\n\n.. _Glossary:\n\n==============\nGlossary\n==============\n\n.. data:: coordinate\n\n        This is an essential general mathematical / geometrical term for understanding this documentation. Please see this section for a more detailed discussion: :ref:`Coordinates`.\n\n.. data:: matrix_like\n\n        A Python sequence of 6 numbers.\n\n.. data:: rect_like\n\n        A Python sequence of 4 numbers.\n\n.. data:: irect_like\n\n        A Python sequence of 4 integers.\n\n.. data:: point_like\n\n        A Python sequence of 2 numbers.\n\n.. data:: quad_like\n\n        A Python sequence of 4 :data:`point_like` items.\n\n.. data:: inheritable\n\n        A number of values in a PDF can inherited by objects further down in a parent-child relationship. The mediabox (physical size) of pages may for example be specified only once or in some node(s) of the :data:`pagetree` and will then be taken as value for all *kids*, that do not specify their own value.\n\n.. _Glossary_MediaBox:\n\n.. data:: MediaBox\n\n        A PDF array of 4 floats specifying a physical page size -- (:data:`inheritable`, mandatory). This rectangle should contain all other PDF  -- optional -- page rectangles, which may be specified in addition: CropBox, TrimBox, ArtBox and BleedBox. Please consult :ref:`AdobeManual` for details. The MediaBox is the only rectangle, for which there is no difference between MuPDF and PDF coordinate systems: :attr:`Page.mediabox` will always show the same coordinates as the `/MediaBox` key in a page's object definition. For all other rectangles, MuPDF transforms y coordinates such that the **top** border is the point of reference. This can sometimes be confusing -- you may for example encounter a situation like this one:\n\n        * The page definition contains the following identical values: `/MediaBox [ 36 45 607.5 765 ]`, `/CropBox [ 36 45 607.5 765 ]`.\n        * PyMuPDF accordingly shows `page.mediabox = Rect(36.0, 45.0, 607.5, 765.0)`.\n        * **BUT:** `page.cropbox = Rect(36.0, 0.0, 607.5, 720.0)`, because the two y-coordinates have been transformed (45 subtracted from both of them).\n\n.. data:: CropBox\n\n        A PDF array of 4 floats specifying a page's visible area -- (:data:`inheritable`, optional). It is the default for TrimBox, ArtBox and BleedBox. If not present, it defaults to MediaBox. This value is **not affected** if the page is rotated -- in contrast to :attr:`Page.rect`. Also, other than the page rectangle, the top-left corner of the cropbox may or may not be *(0, 0)*.\n\n\n.. data:: catalog\n\n        A central PDF :data:`dictionary` -- also called the \"root\" -- containing document-wide parameters and pointers to many other information. Its :data:`xref` is returned by :meth:`Document.pdf_catalog`.\n\n.. data:: trailer\n\n        More precisely, the **PDF trailer** contains information in :data:`dictionary` format. It is usually located at the file's end. In this dictionary, you will find things like the xrefs of the catalog and the metadata, the number of :data:`xref` numbers, etc. Here is the definition of the PDF spec:\n        \n        *\"The trailer of a PDF file enables an application reading the file to quickly find the cross-reference table and certain special objects. Applications should read a PDF file from its end.\"*\n\n        To access the trailer in PyMuPDF, use the usual methods :meth:`Document.xref_object`, :meth:`Document.xref_get_key` and :meth:`Document.xref_get_keys` with `-1` instead of a positive xref number.\n\n.. data:: contents\n\n        A **content stream** is a PDF :data:`object` with an attached :data:`stream`, whose data consists of a sequence of instructions describing the graphical elements to be painted on a page, see \"Stream Objects\" on page 19 of :ref:`AdobeManual`. For an overview of the mini-language used in these streams, see chapter \"Operator Summary\" on page 643 of the :ref:`AdobeManual`. A PDF :data:`page` can have none to many contents objects. If it has none, the page is empty (but still may show annotations). If it has several, they will be interpreted in sequence as if their instructions had been present in one such object (i.e. like in a concatenated string). It should be noted that there are more stream object types which use the same syntax: e.g. appearance dictionaries associated with annotations and Form XObjects.\n\n        PyMuPDF provides a number of methods to deal with contents of PDF pages:\n\n        * :meth:`Page.read_contents()` -- reads and concatenates all page contents into one `bytes` object.\n        * :meth:`Page.clean_contents()` -- a wrapper of a MuPDF function that reads, concatenates and syntax-cleans all page contents. After this, only one `/Contents` object will exist. In addition, page :data:`resources` will have been synchronized with it such that it will contain exactly those images, fonts and other objects that the page actually references.\n        * :meth:`Page.get_contents()` -- return a list of :data:`xref` numbers of a page's :data:`contents` objects. May be empty. Use :meth:`Document.xref_stream()` with one of these xrefs to read the resp. contents section.\n        * :meth:`Page.set_contents()` -- set a page's `/Contents` key to the provided :data:`xref` number.\n\n.. data:: resources\n\n        A :data:`dictionary` containing references to any resources (like images or fonts) required by a PDF :data:`page` (required, inheritable, :ref:`AdobeManual` p. 81) and certain other objects (Form XObjects). This dictionary appears as a sub-dictionary in the object definition under the key */Resources*. Being an inheritable object type, there may exist \"parent\" resources for all pages or certain subsets of pages.\n\n.. data:: dictionary\n\n        A PDF :data:`object` type, which is somewhat comparable to the same-named Python notion: \"A dictionary object is an associative table containing pairs of objects, known as the dictionary's entries. The first element of each entry is the key and the second element is the value. The key must be a name (...). The value can be any kind of object, including another dictionary. A dictionary entry whose value is null (...) is equivalent to an absent entry.\" (:ref:`AdobeManual` p. 18).\n\n        Dictionaries are the most important :data:`object` type in PDF. Here is an example (describing a :data:`page`)::\n\n            <<\n            /Contents 40 0 R                  % value: an indirect object\n            /Type/Page                        % value: a name object\n            /MediaBox[0 0 595.32 841.92]      % value: an array object\n            /Rotate 0                         % value: a number object\n            /Parent 12 0 R                    % value: an indirect object\n            /Resources<<                      % value: a dictionary object\n                /ExtGState<</R7 26 0 R>>\n                /Font<<\n                     /R8 27 0 R/R10 21 0 R/R12 24 0 R/R14 15 0 R\n                     /R17 4 0 R/R20 30 0 R/R23 7 0 R /R27 20 0 R\n                     >>\n                /ProcSet[/PDF/Text]           % value: array of two name objects\n                >>\n            /Annots[55 0 R]                   % value: array, one entry (indirect object)\n            >>\n\n        *Contents*, *Type*, *MediaBox*, etc. are **keys**, *40 0 R*, *Page*, *[0 0 595.32 841.92]*, etc. are the respective **values**. The strings *\"<<\"* and *\">>\"* are used to enclose object definitions.\n\n        This example also shows the syntax of **nested** dictionary values: *Resources* has an object as its value, which in turn is a dictionary with keys like *ExtGState* (with the value *<</R7 26 0 R>>*, which is another dictionary), etc.\n\n.. data:: page\n\n        A PDF page is a :data:`dictionary` object which defines one page in a PDF, see :ref:`AdobeManual` p. 71.\n\n.. data:: pagetree\n\n        The pages of a document are accessed through a structure known as the page tree, which defines the ordering of pages in the document. The tree structure allows PDF consumer applications, using only limited memory, to quickly open a document containing thousands of pages. The tree contains nodes of two types: intermediate nodes, called page tree nodes, and leaf nodes, called page objects. (:ref:`AdobeManual` p. 75).\n\n        While it is possible to list all page references in just one array, PDFs with many pages are often created using *balanced tree* structures (\"page trees\") for faster access to any single page. In relation to the total number of pages, this can reduce the average page access time by page number from a linear to some logarithmic order of magnitude.\n\n        For fast page access, MuPDF can use its own array in memory -- independently from what may or may not be present in the document file. This array is indexed by page number and therefore much faster than even the access via a perfectly balanced page tree.\n\n.. data:: object\n\n        Similar to Python, PDF supports the notion *object*, which can come in eight basic types: boolean values (\"true\" or \"false\"), integer and real numbers, strings (**always** enclosed in brackets -- either \"()\", or \"<>\" to indicate hexadecimal), names (must always start with a \"/\", e.g. `/Contents`), arrays (enclosed in brackets \"[]\"), dictionaries (enclosed in brackets \"<<>>\"), streams (enclosed by keywords \"stream\" / \"endstream\"), and the null object (\"null\") (:ref:`AdobeManual` p. 13). Objects can be made identifiable by assigning a label. This label is then called *indirect* object. PyMuPDF supports retrieving definitions of indirect objects via their cross reference number via :meth:`Document.xref_object`.\n\n.. data:: stream\n\n        A PDF :data:`dictionary` :data:`object` type which is followed by a sequence of bytes, similar to Python *bytes*. \"However, a PDF application can read a stream incrementally, while a string must be read in its entirety. Furthermore, a stream can be of unlimited length, whereas a string is subject to an implementation limit. For this reason, objects with potentially large amounts of data, such as images and page descriptions, are represented as streams.\" \"A stream consists of a :data:`dictionary` followed by zero or more bytes bracketed between the keywords *stream* and *endstream*\"::\n\n            nnn 0 obj\n            <<\n               dictionary definition\n            >>\n            stream\n            (zero or more bytes)\n            endstream\n            endobj\n\n        See :ref:`AdobeManual` p. 19. PyMuPDF supports retrieving stream content via :meth:`Document.xref_stream`. Use :meth:`Document.is_stream` to determine whether an object is of stream type.\n\n.. data:: unitvector\n\n        A mathematical notion meaning a vector of norm (\"length\") 1 -- usually the Euclidean norm is implied. In PyMuPDF, this term is restricted to :ref:`Point` objects, see :attr:`Point.unit`.\n\n.. data:: xref\n\n        Abbreviation for cross-reference number: this is an integer unique identification for objects in a PDF. There exists a cross-reference table (which may physically consist of several separate segments) in each PDF, which stores the relative position of each object for quick lookup. The cross-reference table is one entry longer than the number of existing object: item zero is reserved and must not be used in any way. Many PyMuPDF classes have an :data:`xref` attribute (which is zero for non-PDFs), and one can find out the total number of objects in a PDF via :meth:`Document.xref_length` *- 1*.\n\n\n.. data:: fontsize\n\n        When referring to font size this metric is measured in points where 1 inch = 72 points.\n\n.. data:: resolution\n\n        Images and :ref:`Pixmap` objects may contain resolution information provided as \"dots per inch\", dpi, in each direction (horizontal and vertical). When MuPDF reads an image from a file or from a PDF object, it will parse this information and put it in :attr:`Pixmap.xres`, :attr:`Pixmap.yres`, respectively. If it finds no meaningful information in the input (like non-positive values or values exceeding 4800), it will use \"sane\" defaults instead. The usual default value is 96, but it may also be 72 in some cases (e.g. for JPX images).\n\n.. data:: OCPD\n\n        Optional content properties dictionary - a sub :data:`dictionary` of the PDF :data:`catalog`. The central place to store optional content information, which is identified by the key `/OCProperties`. This dictionary has two required and one optional entry: (1) `/OCGs`, required, an array listing all optional content groups, (2) `/D`, required, the default optional content configuration dictionary (OCCD), (3) `/Configs`, optional, an array of alternative OCCDs.\n\n\n.. data:: OCCD\n\n        Optional content configuration dictionary - a PDF :data:`dictionary` inside the PDF :data:`OCPD`. It stores a setting of ON / OFF states of OCGs and how they are presented to a PDF viewer program. Selecting a configuration is quick way to achieve temporary mass visibility state changes. After opening a PDF, the `/D` configuration of the :data:`OCPD` is always activated. Viewer should offer a way to switch between the `/D`, or one of the optional configurations contained in array `/Configs`.\n\n\n.. data:: OCG\n\n        Optional content group -- a :data:`dictionary` object used to control the visibility of other PDF objects like images or annotations. Independently on which page they are defined, objects with the same OCG can simultaneously be shown or hidden by setting their OCG to ON or OFF. This can be achieved via the user interface provided by many PDF viewers (Adobe Acrobat), or programmatically.\n\n.. data:: OCMD\n        \n        Optional content membership dictionary -- a :data:`dictionary` object which can be used like an :data:`OCG`: it has a visibility state. The visibility of an OCMD is **computed:** it is a logical expression, which uses the state of one or more OCGs to produce a boolean value. The expression's result is interpreted as ON (true) or OFF (false).\n\n.. data:: ligature\n        \n        Some frequent character combinations are represented by their own special glyphs in more advanced fonts. Typical examples are \"fi\", \"fl\", \"ffi\" and \"ffl\". These compounds are called *ligatures*. In PyMuPDF text extractions, there is the option to either return the corresponding unicode unchanged, or split ligatures up into their constituent parts: \"fi\" ==> \"f\" + \"i\", etc.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/header-404.rst",
    "content": ".. meta::\n   :author: Artifex\n   :description: PyMuPDF is a high-performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.\n   :keywords: PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, PDF Splitting, PDF Creation, Pyodide, PyScript\n\n\n.. raw:: html\n\n\n    <div style=\"display:flex;justify-content:space-between;align-items: center;\">\n        <form class=\"sidebar-search-container top\" method=\"get\" action=\"/en/latest/search.html\" role=\"search\" style=\"width:100%\">\n          <input class=\"sidebar-search\" placeholder=\"Search\" name=\"q\" aria-label=\"Search\">\n          <input type=\"hidden\" name=\"check_keywords\" value=\"yes\">\n          <input type=\"hidden\" name=\"area\" value=\"default\">\n        </form>\n    </div>\n"
  },
  {
    "path": "docs/header.rst",
    "content": ".. meta::\n   :author: Artifex\n   :description: PyMuPDF is a high-performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.\n   :keywords: PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, PDF Splitting, PDF Creation, Pyodide, PyScript\n\n\n.. |history_begin| raw:: html\n\n    <details>\n    <summary><small style=\"cursor:pointer;\">Show/hide history</small></summary><small>\n\n.. |history_end| raw:: html\n\n    </small></details>\n\n.. |pdf_only_class| raw:: html\n\n    <div style=\"width:100%; text-align:right\"><b>This class is for PDF only.</b></div>\n\n\n.. names of common things\n\n.. |PyMuPDF| raw:: html\n\n    <cite>PyMuPDF</cite>\n\n.. |PyMuPDF Pro| raw:: html\n\n    <cite>PyMuPDF Pro</cite>\n\n.. |PyMuPDF4LLM| raw:: html\n\n    <cite>PyMuPDF4LLM</cite>\n\n.. |PyMuPDF Layout| raw:: html\n\n    <cite>PyMuPDF Layout</cite>\n\n.. |MuPDF| raw:: html\n\n    <cite>MuPDF</cite>\n\n.. |PDF| raw:: html\n\n    <cite>PDF</cite>\n\n.. |Markdown| raw:: html\n\n    <cite>Markdown</cite>\n\n.. |JSON| raw:: html\n\n    <cite>JSON</cite>\n\n.. |TXT| raw:: html\n\n    <cite>TXT</cite>\n\n.. |AGPL| raw:: html\n\n    <cite>AGPL</cite>\n\n.. |PyPI| raw:: html\n\n    <cite>PyPI</cite>\n\n.. raw:: html\n\n    <style>\n\n        #searchAndLangugeHolder {\n            display:flex;\n            justify-content:space-between;\n            align-items: center;\n        }\n\n        #discordAndForumHolder {\n            display:flex;\n            justify-content:space-between;\n            align-items:center;\n            margin-top:20px;\n        }\n\n        #languageToggle {\n            display: flex;\n            width:35%;\n            margin:8px 10px 0;\n        }\n\n        .forumLink {\n            display:flex;\n            align-items:baseline;\n            margin-top: -5px;\n            margin-left:10px;\n        }\n\n        #visit-pymupdf-io {\n            width:23%;\n            min-width:130px;\n            margin:8px 2% 0 0; \n        }\n\n        .sidebar-search-container.top {\n            width: 40%;\n        }\n\n        #button-select-en {\n            padding: 5px 10px;\n            background-color: #fff;\n            border: 1px solid #000;\n            border-radius: 10px 0 0 10px;\n            font-size: 14px;\n        }\n\n        #button-select-ja {\n            padding: 5px 10px;\n            background-color: #fff;\n            border: 1px solid #000;\n            border-radius: 0px;\n            border-left: 0;\n            font-size: 14px;\n        }\n\n        #button-select-ko {\n            padding: 5px 10px;\n            background-color: #fff;\n            border: 1px solid #000;\n            border-radius: 0px 10px 10px 0;\n            border-left: 0;\n            font-size: 14px;\n        }\n\n        #button-select-en, #button-select-ja, #button-select-ko, #button-select-en:hover, #button-select-ja:hover, #button-select-ko:hover   {\n            color: #fff;\n            text-decoration: none;\n        }\n\n        /* small screens */\n        @media all and (max-width : 768px)  {\n            #languageToggle {\n                width:50%;\n            }\n\n            .sidebar-search-container.top {\n                width: 50%;\n            }\n        }\n\n        @media all and (max-width : 700px)  {\n\n            #searchAndLangugeHolder, #discordAndForumHolder {\n                flex-direction: column;\n            }\n\n            #languageToggle {\n                width:100%;\n            }\n\n            .sidebar-search-container.top {\n                width: 100%;\n            }\n\n            .forumLink {\n                flex-direction: column;\n                justify-content:space-between;\n                align-items:center;\n            }\n\n        }\n\n    </style>\n\n    <div id=\"searchAndLangugeHolder\">\n        <button id=\"visit-pymupdf-io\" class=\"cta orange\" onclick=\"window.location='https://pymupdf.io?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=cta-button'\">pymupdf.io</button>\n        <form id=\"headerSearchWidget\" class=\"sidebar-search-container top\" method=\"get\" action=\"search.html\" role=\"search\">\n          <input class=\"sidebar-search\" placeholder=\"Search\" name=\"q\" aria-label=\"Search\">\n          <input type=\"hidden\" name=\"check_keywords\" value=\"yes\">\n          <input type=\"hidden\" name=\"area\" value=\"default\">\n        </form>\n        <div id=\"languageToggle\">\n            <span><a id=\"button-select-en\" href=\"javaScript:changeLanguage('en')\">English</a></span>\n            <span><a id=\"button-select-ja\" href=\"javaScript:changeLanguage('ja')\">日本語</a></span>\n            <span><a id=\"button-select-ko\" href=\"javaScript:changeLanguage('ko')\">한국어</a></span>\n        </div>\n    </div>\n\n    <div id=\"discordAndForumHolder\">\n        <div class=\"discordLink\" style=\"display:flex;align-items:center;margin-top: 5px;\">\n            <a href=\"https://discord.gg/TSpYGBW4eq\" id=\"findOnDiscord\" target=_blank>Find <b>#pymupdf</b> on <b>Discord</b></a>\n            <a href=\"https://discord.gg/TSpYGBW4eq\" target=_blank>\n                <div style=\"width:30px;height:30px;margin-left:5px;\">\n                    <svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 127.14 96.36\">\n                        <defs>\n                            <style>.discordLogoFill{fill:#5865f2;}</style>\n                        </defs>\n                        <g id=\"Discord_Logo\" data-name=\"Discord Logo\">\n                            <path class=\"discordLogoFill\" d=\"M107.7,8.07A105.15,105.15,0,0,0,81.47,0a72.06,72.06,0,0,0-3.36,6.83A97.68,97.68,0,0,0,49,6.83,72.37,72.37,0,0,0,45.64,0,105.89,105.89,0,0,0,19.39,8.09C2.79,32.65-1.71,56.6.54,80.21h0A105.73,105.73,0,0,0,32.71,96.36,77.7,77.7,0,0,0,39.6,85.25a68.42,68.42,0,0,1-10.85-5.18c.91-.66,1.8-1.34,2.66-2a75.57,75.57,0,0,0,64.32,0c.87.71,1.76,1.39,2.66,2a68.68,68.68,0,0,1-10.87,5.19,77,77,0,0,0,6.89,11.1A105.25,105.25,0,0,0,126.6,80.22h0C129.24,52.84,122.09,29.11,107.7,8.07ZM42.45,65.69C36.18,65.69,31,60,31,53s5-12.74,11.43-12.74S54,46,53.89,53,48.84,65.69,42.45,65.69Zm42.24,0C78.41,65.69,73.25,60,73.25,53s5-12.74,11.44-12.74S96.23,46,96.12,53,91.08,65.69,84.69,65.69Z\"/>\n                        </g>\n                    </svg>\n                </div>\n            </a>\n        </div>\n        <div class=\"forumLink\">\n            <div id=\"forumCTAText\"></div><a id=\"winking-cow-link\" style=\"font-weight: bold;\" href=\"https://forum.mupdf.com\">Try our forum! <img alt=\"MuPDF Forum link logo\" id=\"winking-cow-image\" src=\"https://pymupdf.readthedocs.io/en/latest/_static/forum-logo.gif\" width=38px height=auto /></a>\n        </div>\n    </div>\n\n    <script>\n        // highlightSelectedLanguage\n        var url_string = window.location.href;\n\n        if (document.getElementsByTagName('html')[0].getAttribute('lang')==\"en\") {\n            document.getElementById(\"button-select-en\").style.backgroundColor = \"#ff6600\";\n            document.getElementById(\"button-select-ja\").style.color = \"#000\";\n            document.getElementById(\"button-select-ko\").style.color = \"#000\";\n        } else if (document.getElementsByTagName('html')[0].getAttribute('lang')==\"ja\") {\n            document.getElementById(\"button-select-ja\").style.backgroundColor = \"#ff6600\";\n            document.getElementById(\"button-select-en\").style.color = \"#000\";\n            document.getElementById(\"button-select-ko\").style.color = \"#000\";\n        } else if (document.getElementsByTagName('html')[0].getAttribute('lang')==\"ko\") {\n            document.getElementById(\"button-select-ko\").style.backgroundColor = \"#ff6600\";\n            document.getElementById(\"button-select-en\").style.color = \"#000\";\n            document.getElementById(\"button-select-ja\").style.color = \"#000\";\n        }\n\n\n        function changeLanguage(lang) {\n            var new_url;\n\n            if (lang == \"en\") {\n                new_url = url_string.replace(/\\/(ko|ja)\\//, \"/en/\");\n            } else if (lang == \"ja\") {\n                new_url = url_string.replace(/\\/(ko|en)\\//, \"/ja/\");\n            } else if (lang == \"ko\") {\n                new_url = url_string.replace(/\\/(ja|en)\\//, \"/ko/\");\n            }\n\n            window.location.replace(new_url);\n        }\n\n        // winking cow\n        const link = document.getElementById('winking-cow-link');\n        const img = document.getElementById('winking-cow-image');\n\n        link.addEventListener('mouseenter', function() {\n            img.src = 'https://pymupdf.readthedocs.io/en/latest/_static/forum-logo-wink.png';\n        });\n\n        link.addEventListener('mouseleave', function() {\n            img.src = 'https://pymupdf.readthedocs.io/en/latest/_static/forum-logo.gif';\n        });\n\n    </script>\n\n"
  },
  {
    "path": "docs/how-to-open-a-file.rst",
    "content": ".. include:: header.rst\n\n.. _HowToOpenAFile:\n\n==============================\nOpening Files\n==============================\n\n\n\n\n.. _Supported_File_Types:\n\n\nSupported File Types\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n|\n\nPyMuPDF\n\"\"\"\"\"\"\"\"\"\n\n|PyMuPDF| can open files other than just |PDF|.\n\nThe following file types are supported:\n\n.. include:: supported-files-table.rst\n\n\n----\n\n\nPyMuPDF Pro\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\n|PyMuPDF Pro| can open Office files.\n\nThe following file types are supported:\n\n.. list-table::\n   :header-rows: 1\n\n   * - **DOC/DOCX**\n     - **XLS/XLSX**\n     - **PPT/PPTX**\n     - **HWP/HWPX**\n   * - .. image:: images/icons/icon-docx.svg\n          :width: 40\n          :height: 40\n     - .. image:: images/icons/icon-xlsx.svg\n          :width: 40\n          :height: 40\n     - .. image:: images/icons/icon-pptx.svg\n          :width: 40\n          :height: 40\n     - .. image:: images/icons/icon-hangul.svg\n          :width: 40\n          :height: 40\n\n\n\nHow to Open a File\n~~~~~~~~~~~~~~~~~~~~~\n\nTo open a file, do the following:\n\n.. code-block:: python\n\n    doc = pymupdf.open(\"a.pdf\")\n\n\n.. note:: The above creates a :ref:`Document`. The instruction `doc = pymupdf.Document(\"a.pdf\")` does exactly the same. So, `open` is just a convenient alias and you can find its full API documented in that chapter.\n\n\nFile Recognizer: Opening with :index:`a Wrong File Extension <pair: wrong; file extension>`\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nIf you have a document with a wrong file extension for its type, do not worry: it will still be opened correctly, thanks to the integrated file \"content recognizer\".\n\nThis component looks at the actual data in the file using a number of heuristics -- independent of the file extension. This of course is also true for file names **without** an extension.\n\nHere is a list of details about how the file content recognizer works:\n\n* When opening from a file name, use the ``filetype`` parameter if your file format cannot be determined by content inspection. This is for instance the case for all text files: \"txt\", \"html\", \"xml\" or source files. If the file extension is missing or wrong or the file resides in memory, the ``filetype`` must be used. File formats that can successfully be recognized will be opened even without or wrong extensions, and the ``filetype`` paraneter will be ignored.\n\n* Files based on text content do not contain unambiguously recognizable internal structures. This is true for source files (Python, C, etc.) but also HTML, XML and so on. Here, the file extensions and the ``filetype`` parameter continue to play a role and are used to create a \"Tex\" / \"HTML\" / ... document. Correspondingly, text files with other / no extensions, can successfully be opened using ``filetype``.\n\n----------\n\n\nOpening Remote Files\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\nFor remote files on a server (i.e. non-local files), you will need to *stream* the file data to |PyMuPDF|.\n\nFor example use the `requests <https://requests.readthedocs.io/en/latest/>`_ library as follows:\n\n.. code-block:: python\n\n    import pymupdf\n    import requests\n\n    r = requests.get('https://mupdf.com/docs/mupdf_explored.pdf')\n    data = r.content\n    doc = pymupdf.Document(stream=data)\n\n\nOpening Files from Cloud Services\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nFor further examples which deal with files held on typical cloud services please see these `Cloud Interactions code snippets <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/cloud-interactions>`_.\n\n\n\n----------\n\n\nOpening Django Files\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDjango implements a `File Storage API <https://docs.djangoproject.com/en/5.1/ref/files/storage/>`_ to store files. The default is the `FileSystemStorage <https://docs.djangoproject.com/en/5.1/ref/files/storage/#the-filesystemstorage-class>`_, but the `django-storages <https://django-storages.readthedocs.io/en/latest/index.html>`_ library provides a number of other storage backends.\n\nYou can open the file, move the contents into memory, then pass the contents to |PyMuPDF| as a stream.\n\n.. code-block:: python\n\n    import pymupdf\n    from django.core.files.storage import default_storage\n\n    from .models import MyModel\n\n    obj = MyModel.objects.get(id=1)\n    with default_storage.open(obj.file.name) as f:\n        data = f.read()\n\n    doc = pymupdf.Document(stream=data)\n\nPlease note that if the file you open is large, you may run out of memory.\n\nThe File Storage API works well if you're using different storage backends in different environments. If you're only using the `FileSystemStorage`, you can simply use the `obj.file.name` to open the file directly with |PyMuPDF| as shown in an earlier example.\n\n\n----------\n\n\n\nOpening Files as Text\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\n|PyMuPDF| has the capability to open any plain text file as a document. In order to do this you should provide the `filetype` parameter for the `pymupdf.open` function as `\"txt\"`.\n\n.. code-block:: python\n\n    doc = pymupdf.open(\"my_program.py\", filetype=\"txt\")\n\n\nIn this way you are able to open a variety of file types and perform the typical **non-PDF** specific features like text searching, text extracting and page rendering. Obviously, once you have rendered your `txt` content, then saving as |PDF| or merging with other |PDF| files is no problem.\n\n\nExamples\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\n\nOpening a `C#` file\n...........................\n\n\n.. code-block:: python\n\n    doc = pymupdf.open(\"MyClass.cs\", filetype=\"txt\")\n\n\nOpening an ``XML`` file\n...........................\n\n.. code-block:: python\n\n    doc = pymupdf.open(\"my_data.xml\", filetype=\"txt\")\n\n\nOpening a `JSON` file\n...........................\n\n.. code-block:: python\n\n    doc = pymupdf.open(\"more_of_my_data.json\", filetype=\"txt\")\n\n\nAnd so on!\n\nAs you can imagine many text based file formats can be *very simply opened* and *interpreted* by |PyMuPDF|. This can make data analysis and extraction for a wide range of previously unavailable files possible.\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/identity.rst",
    "content": ".. include:: header.rst\n\n.. _Identity:\n\n============\nIdentity\n============\n\nIdentity is a :ref:`Matrix` that performs no action -- to be used whenever the syntax requires a matrix, but no actual transformation should take place. It has the form *pymupdf.Matrix(1, 0, 0, 1, 0, 0)*.\n\nIdentity is a constant, an \"immutable\" object. So, all of its matrix properties are read-only and its methods are disabled.\n\nIf you need a **mutable** identity matrix as a starting point, use one of the following statements::\n\n    >>> m = pymupdf.Matrix(1, 0, 0, 1, 0, 0)  # specify the values\n    >>> m = pymupdf.Matrix(1, 1)              # use scaling by factor 1\n    >>> m = pymupdf.Matrix(0)                 # use rotation by zero degrees\n    >>> m = pymupdf.Matrix(pymupdf.Identity)     # make a copy of Identity\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/index.rst",
    "content": ".. include:: header.rst\n\n.. This is the TOC in the sidebar!\n\n.. raw:: html\n\n   <style>\n\n      .toc-drawer {\n         display: none;\n      }\n\n      .main .content {\n         width:  100% !important;\n      }\n\n   </style>\n\nWelcome to |PyMuPDF|\n================================\n\n|PyMuPDF| is a high-performance **Python** library for data extraction, analysis, conversion & manipulation of |PDF| (and other) documents.\n\n|PyMuPDF| is hosted on `GitHub <https://github.com/pymupdf/PyMuPDF>`_ and registered on `PyPI <https://pypi.org/project/PyMuPDF/>`_.\n\n.. if we want a Github repo badge\n\n   .. raw:: html\n\n      <a href=\"https://trendshift.io/repositories/11536\" target=\"_blank\"><img src=\"https://trendshift.io/api/badge/repositories/11536\" alt=\"pymupdf%2FPyMuPDF | Trendshift\" style=\"width: 250px; height: 55px;\" width=\"250\" height=\"55\"/></a>\n\n\n----\n\nThis documentation covers all versions up to |version|.\n\n----\n\n.. toctree::\n   :caption: About\n   :maxdepth: 1\n\n   about.rst\n   pymupdf4llm/index.rst\n   pymupdf-pro/index.rst\n\n\n\n.. toctree::\n   :caption: User Guide\n   :maxdepth: 1\n\n   installation.rst\n   the-basics.rst\n   tutorial.rst\n   rag.rst\n   resources.rst\n   faq/index.rst\n\n\n\n.. toctree::\n   :caption: How to Guide\n   :maxdepth: 3\n\n   recipes.rst\n\n\n.. toctree::\n   :caption: API Reference\n   :maxdepth: 2\n\n   module.rst\n   classes.rst\n   pymupdf4llm/api.rst\n   algebra.rst\n   lowlevel.rst\n   glossary.rst\n   vars.rst\n   colors.rst\n\n\n.. toctree::\n   :caption: Other\n   :maxdepth: 2\n\n   app1.rst\n   app2.rst\n   app3.rst\n   app4.rst\n   changes.rst\n   znames.rst\n\n|\n----\n\n\n\n.. include:: footer.rst\n\n\n\n"
  },
  {
    "path": "docs/installation.rst",
    "content": ".. include:: header.rst\n\n\n\nInstallation\n=============\n\nRequirements\n---------------------------------------------------------\n\nAll the examples below assume that you are running inside a Python virtual\nenvironment. See: https://docs.python.org/3/library/venv.html for details.\nWe also assume that `pip` is up to date.\n\nFor example:\n\n* Windows::\n\n    py -m venv pymupdf-venv\n    .\\pymupdf-venv\\Scripts\\activate\n    python -m pip install --upgrade pip\n\n* Linux, MacOS::\n\n    python -m venv pymupdf-venv\n    . pymupdf-venv/bin/activate\n    python -m pip install --upgrade pip\n\n\nInstallation\n---------------------------------------------------------\n\n|PyMuPDF| should be installed using pip with::\n\n  pip install --upgrade pymupdf\n\nThis will install from a Python wheel if one is available for your platform.\n\n\nInstallation when a suitable wheel is not available\n---------------------------------------------------------\n\nIf a suitable Python wheel is not available, pip will automatically build from\nsource using a Python sdist.\n\n**This requires C/C++ development tools to be installed**:\n\n* On Windows:\n\n  *\n    Install Visual Studio 2019. If not installed in a standard location, set\n    environmental variable `PYMUPDF_SETUP_DEVENV` to the location of the\n    `devenv.com` binary.\n\n  *\n    Having other installed versions of Visual Studio, for example Visual Studio\n    2022, can cause problems because one can end up with MuPDF and PyMuPDF code\n    being compiled with different compiler versions.\n\nThe build will automatically download and build MuPDF.\n\n\n.. _problems-after-installation:\n\nProblems after installation\n---------------------------------------------------------\n\n* On Windows, Python error::\n\n      ImportError: DLL load failed while importing _extra\n\n  This has been occasionally seen if `MSVCP140.dll` is missing, and appears\n  to be caused by a bug in some versions (2015-2017) of `Microsoft Visual C++\n  Redistributables`.\n\n  It is recommended to search for `MSVCP140.dll` in https://msdn.com\n  to find instructions for how to reinstall it. For example\n  https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist has\n  permalinks to the latest supported versions.\n\n  See https://github.com/pymupdf/PyMuPDF/issues/2678 for more details.\n\n*\n  Python error::\n\n      ModuleNotFoundError: No module named 'frontend'\n  \n  This can happen if PyMuPDF's legacy name `fitz` is used (for example `import\n  fitz` instead of `import pymupdf`), and an unrelated Python package called\n  `fitz` (https://pypi.org/project/fitz/) is installed.\n\n  The fitz package appears to be no longer maintained (the latest release is\n  from 2017), but unfortunately it does not seem possible to remove it from\n  pypi.org. It does not even work on its own, as well as breaking the use of\n  PyMuPDF's legacy name.\n\n  There are a few ways to avoid this problem:\n\n  *\n    Use `import pymupdf` instead of `import fitz`, and update one's code to\n    match.\n\n  * Or uninstall the `fitz` package and reinstall PyMuPDF::\n  \n        pip uninstall fitz\n        pip install --force-reinstall pymupdf\n\n  * Or use `import pymupdf as fitz`. However this has not been well tested.\n\n* With Jupyter labs on Apple Silicon (arm64), Python error::\n\n      ImportError: /opt/conda/lib/python3.11/site-packages/pymupdf/libmupdf.so.24.4: undefined symbol: fz_pclm_write_options_usage\n\n  This appears to be a problem in Jupyter labs; see:\n  https://github.com/pymupdf/PyMuPDF/issues/3643#issuecomment-2210588778.\n\n* On Windows, Python error::\n    \n    ImportError: dynamic module does not define module export function (PyInit__extra)\n\n  This was reported 2025-03-26 in https://github.com/pymupdf/PyMuPDF/issues/4405.\n  \n  The fix appears to be to install the latest `VC_redist.x64.exe`.\n\n\nNotes\n---------------------------------------------------------\n\n*\n  Wheels are available for the following platforms:\n  \n   * Windows 32-bit Intel.\n   * Windows 64-bit Intel.\n   * Linux 64-bit Intel.\n   * Linux 64-bit ARM.\n   * MacOS 64-bit Intel.\n   * MacOS 64-bit ARM.\n  \n  Details:\n  \n  * We release a single wheel for each of the above platforms.\n  \n  *\n    Each wheel uses the Python Stable ABI of the current oldest supported\n    Python version (currently 3.10), and so works with all later Python\n    versions, including new Python releases.\n  \n  *\n    Wheels are tested on all Python versions currently marked as \"Supported\"\n    on https://devguide.python.org/versions/, currently |python_versions|.\n\n*\n  Wheels are not available for Python installed with `Chocolatey\n  <https://chocolatey.org/>`_ on Windows. Instead install Python\n  using the Windows installer from the python.org website, see:\n  http://www.python.org/downloads\n\n*\n  Wheels are not available for Linux-aarch64 with `Musl libc\n  <https://musl.libc.org/>`_ (For example `Alpine Linux\n  <https://alpinelinux.org/>`_ on aarch64), and building from source is known\n  to fail.\n\n* There are no **mandatory** external dependencies. However, some optional feature are available only if additional components are installed:\n\n  * `Pillow <https://pypi.org/project/Pillow/>`_ is required for :meth:`Pixmap.pil_save` and :meth:`Pixmap.pil_tobytes`.\n  * `fontTools <https://pypi.org/project/fonttools/>`_ is required for :meth:`Document.subset_fonts`.\n  * `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ is a collection of nice fonts to be used for text output methods.\n  * \n    `Tesseract-OCR <https://github.com/tesseract-ocr/tesseract>`_ for optical\n    character recognition in images and document pages. Tesseract is separate\n    software, not a Python package. To enable OCR functions in PyMuPDF,\n    Tesseract must be installed and the `tessdata` folder name specified; see\n    below.\n\n  .. note:: You can install these additional components at any time -- before or after installing PyMuPDF. PyMuPDF will detect their presence during import or when the respective functions are being used.\n\n\nBuild and install from a local PyMuPDF source tree\n---------------------------------------------------------\n\nInitial setup:\n\n* Install C/C++ development tools as described above.\n* Enter a Python venv and update pip, as described above.\n\n* Get a PyMuPDF source tree:\n\n  * Clone the PyMuPDF git repository::\n\n        git clone https://github.com/pymupdf/PyMuPDF.git\n\n  *\n    Or download and extract a `.zip` or `.tar.gz` source release from\n    https://github.com/pymupdf/PyMuPDF/releases.\n\nThen one can build PyMuPDF in two ways:\n\n* Build and install PyMuPDF with default MuPDF version::\n\n      cd PyMuPDF && pip install .\n\n  This will automatically download a specific hard-coded MuPDF source\n  release, and build it into PyMuPDF.\n\n* Or build and install PyMuPDF using a local MuPDF source tree:\n\n  * Clone the MuPDF git repository::\n\n      git clone --recursive https://git.ghostscript.com/mupdf.git\n\n  *\n    Build PyMuPDF, specifying the location of the local MuPDF tree with the\n    environmental variables `PYMUPDF_SETUP_MUPDF_BUILD`::\n\n      cd PyMuPDF && PYMUPDF_SETUP_MUPDF_BUILD=../mupdf pip install .\n\nAlso, one can build for different Python versions in the same PyMuPDF tree:\n\n*\n  PyMuPDF will build for the version of Python that is being used to run\n  `pip`. To run `pip` with a specific Python version, use `python -m pip`\n  instead of `pip`.\n\n  So for example on Windows one can build different versions with::\n\n    cd PyMuPDF && py -3.10 -m pip install .\n\n  or::\n\n    cd PyMuPDF && py -3.10-32 -m pip install .\n\n\nRunning tests\n---------------------------------------------------------\n\nHaving a PyMuPDF tree available allows one to run PyMuPDF's `pytest` test\nsuite::\n\n  pip install pytest fontTools\n  pytest PyMuPDF/tests\n\n\n\nNotes about using a non-default MuPDF\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n\nUsing a non-default build of MuPDF by setting environmental variable\n`PYMUPDF_SETUP_MUPDF_BUILD` can cause various things to go wrong and so is\nnot generally supported:\n\n* If MuPDF's major version number differs from what PyMuPDF uses by default,\n  PyMuPDF can fail to build, because MuPDF's API can change between major\n  versions.\n\n* Runtime behaviour of PyMuPDF can change because MuPDF's runtime behaviour\n  changes between different minor releases. This can also break some PyMuPDF\n  tests.\n\n* If MuPDF was built with its default config instead of PyMuPDF's customised\n  config (for example if MuPDF is a system install), it is possible that\n  `tests/test_textbox.py:test_textbox3()` will fail. One can skip this\n  particular test by adding `-k 'not test_textbox3'` to the `pytest`\n  command line.\n\n\nOfficial PyMuPDF Linux wheels may not install on older Linux systems\n--------------------------------------------------------------------\n\nReleases of PyMuPDF are incompatible with older Linux systems.\n\nFor example as of 2025-09-03, `pip install pymupdf` does not work on some AWS\nLambda systems - see https://github.com/pymupdf/PyMuPDF/discussions/4631.\n\nThis is because official PyMuPDF Linux wheels are built with a version of\nglibc determined by the current Python manylinux environment. These wheels are\nincompatible with Linux systems that have an older glibc.\n\nThe official Python manylinux environment is updated periodically to use newer\nglibc versions, so new releases of PyMuPDF become increasingly incompatible\nwith older Linux systems.\n\nThere is nothing that can be done about this, other than updating older Linux\nsystems, or building PyMuPDF locally from source.\n\nFor more details, please see: `Python Packaging Authority <https://www.pypa.io>`_.\n\n\nPackaging\n---------\n\nSee :doc:`packaging`.\n\n\nUsing with Pyodide\n------------------\n\nSee :doc:`pyodide`.\n\n\n.. _installation_ocr:\n\nEnabling Integrated OCR Support\n---------------------------------------------------------\n\nPyMuPDF will already contain all the logic to support OCR functions. But it additionally does need `Tesseract's language support data <https://github.com/tesseract-ocr/tessdata>`_.\n\nIf not specified explicitly, PyMuPDF will attempt to find the installed\nTesseract's `tessdata`, but this should probably not be relied upon.\n\n\nOtherwise PyMuPDF requires that Tesseract's language support folder is\nspecified explicitly either in PyMuPDF OCR functions' `tessdata` arguments or\n`os.environ[\"TESSDATA_PREFIX\"]`.\n\nSo for a working OCR functionality, make sure to complete this checklist:\n\n1. Locate Tesseract's language support folder. Typically you will find it here:\n\n   * Windows: `C:/Program Files/Tesseract-OCR/tessdata`\n   * Unix systems: `/usr/share/tesseract-ocr/4.00/tessdata`\n\n2. Specify the language support folder when calling PyMuPDF OCR functions:\n   \n   * Set the `tessdata` argument.\n   * Or set `os.environ[\"TESSDATA_PREFIX\"]` from within Python.\n   * Or set environment variable `TESSDATA_PREFIX` before running Python, for example:\n   \n     * Windows: `setx TESSDATA_PREFIX \"C:/Program Files/Tesseract-OCR/tessdata\"`\n     * Unix systems: `declare -x TESSDATA_PREFIX=/usr/share/tesseract-ocr/4.00/tessdata`\n\n\n.. note::\n\n    English language support is included by default in Tesseract installation.\n\n    :ref:`Tesseract Language Packs <tesseract-language-packs>` for other languages must be installed separately, and the `tessdata` folder must be specified to PyMuPDF as described above, for OCR to work with those languages.\n\n\n.. note::\n    \n  Find out more on the `official documentation for installing Tesseract website <https://tesseract-ocr.github.io/tessdoc/Installation.html>`_.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/irect.rst",
    "content": ".. include:: header.rst\n\n.. _IRect:\n\n==========\nIRect\n==========\n\nIRect is a rectangular bounding box, very similar to :ref:`Rect`, except that all corner coordinates are integers. IRect is used to specify an area of pixels, e.g. to receive image data during rendering. Otherwise, e.g. considerations concerning emptiness and validity of rectangles also apply to this class. Methods and attributes have the same names, and in many cases are implemented by re-using the respective :ref:`Rect` counterparts.\n\n============================== ==============================================\n**Attribute / Method**          **Short Description**\n============================== ==============================================\n:meth:`IRect.contains`         checks containment of another object\n:meth:`IRect.get_area`         calculate rectangle area\n:meth:`IRect.intersect`        common part with another rectangle\n:meth:`IRect.intersects`       checks for non-empty intersection\n:meth:`IRect.morph`            transform with a point and a matrix\n:meth:`IRect.torect`           matrix that transforms to another rectangle\n:meth:`IRect.norm`             the Euclidean norm\n:meth:`IRect.normalize`        makes a rectangle finite\n:attr:`IRect.bottom_left`      bottom left point, synonym *bl*\n:attr:`IRect.bottom_right`     bottom right point, synonym *br*\n:attr:`IRect.height`           height of the rectangle\n:attr:`IRect.is_empty`         whether rectangle is empty\n:attr:`IRect.is_infinite`      whether rectangle is infinite\n:attr:`IRect.rect`             the :ref:`Rect` equivalent\n:attr:`IRect.top_left`         top left point, synonym *tl*\n:attr:`IRect.top_right`        top_right point, synonym *tr*\n:attr:`IRect.quad`             :ref:`Quad` made from rectangle corners\n:attr:`IRect.width`            width of the rectangle\n:attr:`IRect.x0`               X-coordinate of the top left corner\n:attr:`IRect.x1`               X-coordinate of the bottom right corner\n:attr:`IRect.y0`               Y-coordinate of the top left corner\n:attr:`IRect.y1`               Y-coordinate of the bottom right corner\n============================== ==============================================\n\n**Class API**\n\n.. class:: IRect\n\n   .. method:: __init__(self)\n\n   .. method:: __init__(self, x0, y0, x1, y1)\n\n   .. method:: __init__(self, irect)\n\n   .. method:: __init__(self, sequence)\n\n      Overloaded constructors. Also see examples below and those for the :ref:`Rect` class.\n\n      If another irect is specified, a **new copy** will be made.\n\n      If sequence is specified, it must be a Python sequence type of 4 numbers (see :ref:`SequenceTypes`). Non-integer numbers will be truncated, non-numeric values will raise an exception.\n\n      The other parameters mean integer coordinates.\n\n\n   .. method:: get_area([unit])\n\n      Calculates the area of the rectangle and, with no parameter, equals *abs(IRect)*. Like an empty rectangle, the area of an infinite rectangle is also zero.\n\n      :arg str unit: Specify required unit: respective squares of \"px\" (pixels, default), \"in\" (inches), \"cm\" (centimeters), or \"mm\" (millimeters).\n\n      :rtype: float\n\n   .. method:: intersect(ir)\n\n      The intersection (common rectangular area) of the current rectangle and *ir* is calculated and replaces the current rectangle. If either rectangle is empty, the result is also empty. If either rectangle is infinite, the other one is taken as the result -- and hence also infinite if both rectangles were infinite.\n\n      :arg rect_like ir: Second rectangle.\n\n   .. method:: contains(x)\n\n      Checks whether *x* is contained in the rectangle. It may be :data:`rect_like`, :data:`point_like` or a number. If *x* is an empty rectangle, this is always true. Conversely, if the rectangle is empty this is always ``False``, if *x* is not an empty rectangle and not a number. If *x* is a number, it will be checked to be one of the four components. *x in irect* and *irect.contains(x)* are equivalent.\n\n      :arg x: the object to check.\n      :type x: :ref:`IRect` or :ref:`Rect` or :ref:`Point` or `int`.\n\n      :rtype: bool\n\n   .. method:: intersects(r)\n\n      Checks whether the rectangle and the :data:`rect_like` \"r\" contain a common non-empty :ref:`IRect`. This will always be ``False`` if either is infinite or empty.\n\n      :arg rect_like r: the rectangle to check.\n\n      :rtype: bool\n\n   .. method:: torect(rect)\n\n      * New in version 1.19.3\n      \n      Compute the matrix which transforms this rectangle to a given one. See :meth:`Rect.torect`.\n\n      :arg rect_like rect: the target rectangle. Must not be empty or infinite.\n      :rtype: :ref:`Matrix`\n      :returns: a matrix `mat` such that `self * mat = rect`. Can for example be used to transform between the page and the pixmap coordinates.\n\n\n   .. method:: morph(fixpoint, matrix)\n\n      * New in version 1.17.0\n      \n      Return a new quad after applying a matrix to it using a fixed point.\n\n      :arg point_like fixpoint: the fixed point.\n      :arg matrix_like matrix: the matrix.\n      :returns: a new :ref:`Quad`. This a wrapper of the same-named quad method. If infinite, the infinite quad is returned.\n\n   .. method:: norm()\n\n      * New in version 1.16.0\n      \n      Return the Euclidean norm of the rectangle treated as a vector of four numbers.\n\n   .. method:: normalize()\n\n      Make the rectangle finite. This is done by shuffling rectangle corners. After this, the bottom right corner will indeed be south-eastern to the top left one. See :ref:`Rect` for a more details.\n\n   .. attribute:: top_left\n\n   .. attribute:: tl\n\n      Equals *Point(x0, y0)*.\n\n      :type: :ref:`Point`\n\n   .. attribute:: top_right\n\n   .. attribute:: tr\n\n      Equals *Point(x1, y0)*.\n\n      :type: :ref:`Point`\n\n   .. attribute:: bottom_left\n\n   .. attribute:: bl\n\n      Equals *Point(x0, y1)*.\n\n      :type: :ref:`Point`\n\n   .. attribute:: bottom_right\n\n   .. attribute:: br\n\n      Equals *Point(x1, y1)*.\n\n      :type: :ref:`Point`\n\n   .. attribute:: rect\n\n      The :ref:`Rect` with the same coordinates as floats.\n\n      :type: :ref:`Rect`\n\n   .. attribute:: quad\n\n      The quadrilateral *Quad(irect.tl, irect.tr, irect.bl, irect.br)*.\n\n      :type: :ref:`Quad`\n\n   .. attribute:: width\n\n      Contains the width of the bounding box. Equals *abs(x1 - x0)*.\n\n      :type: int\n\n   .. attribute:: height\n\n      Contains the height of the bounding box. Equals *abs(y1 - y0)*.\n\n      :type: int\n\n   .. attribute:: x0\n\n      X-coordinate of the left corners.\n\n      :type: int\n\n   .. attribute:: y0\n\n      Y-coordinate of the top corners.\n\n      :type: int\n\n   .. attribute:: x1\n\n      X-coordinate of the right corners.\n\n      :type: int\n\n   .. attribute:: y1\n\n      Y-coordinate of the bottom corners.\n\n      :type: int\n\n   .. attribute:: is_infinite\n\n      ``True`` if rectangle is infinite, ``False`` otherwise.\n\n      :type: bool\n\n   .. attribute:: is_empty\n\n      ``True`` if rectangle is empty, ``False`` otherwise.\n\n      :type: bool\n\n\n.. note::\n\n   * This class adheres to the Python sequence protocol, so components can be accessed via their index, too. Also refer to :ref:`SequenceTypes`.\n   * Rectangles can be used with arithmetic operators -- see chapter :ref:`Algebra`.\n\n.. include:: footer.rst\n\n"
  },
  {
    "path": "docs/link.rst",
    "content": ".. include:: header.rst\n\n.. _Link:\n\n================\nLink\n================\nRepresents a pointer to somewhere (this document, other documents, the internet). Links exist per document page, and they are forward-chained to each other, starting from an initial link which is accessible by the :attr:`Page.first_link` property.\n\nThere is a parent-child relationship between a link and its page. If the page object becomes unusable (closed document, any document structure change, etc.), then so does every of its existing link objects -- an exception is raised saying that the object is \"orphaned\", whenever a link property or method is accessed.\n\n========================= ============================================\n**Attribute**             **Short Description**\n========================= ============================================\n:meth:`Link.set_border`   modify border properties\n:meth:`Link.set_colors`   modify color properties\n:meth:`Link.set_flags`    modify link flags\n:attr:`Link.border`       border characteristics\n:attr:`Link.colors`       border line color\n:attr:`Link.dest`         points to destination details\n:attr:`Link.is_external`  checks if the link is an external destination\n:attr:`Link.flags`        link annotation flags\n:attr:`Link.next`         points to next link\n:attr:`Link.rect`         clickable area in untransformed coordinates\n:attr:`Link.uri`          link destination\n:attr:`Link.xref`         :data:`xref` number of the entry\n========================= ============================================\n\n**Class API**\n\n.. class:: Link\n\n   .. method:: set_border(border=None, width=0, style=None, dashes=None)\n\n      PDF only: Change border width and dashing properties.\n\n      *(Changed in version 1.16.9)* Allow specification without using a dictionary. The direct parameters are used if *border* is not a dictionary.\n\n      :arg dict border: a dictionary as returned by the :attr:`border` property, with keys *\"width\"* (*float*), *\"style\"* (*str*) and *\"dashes\"* (*sequence*). Omitted keys will leave the resp. property unchanged. To e.g. remove dashing use: *\"dashes\": []*. If dashes is not an empty sequence, \"style\" will automatically be set to \"D\" (dashed).\n\n      :arg float width: see above.\n      :arg str style: see above.\n      :arg sequence dashes: see above.\n\n   .. method:: set_colors(colors=None, stroke=None)\n\n      PDF only: Changes the \"stroke\" color.\n\n      .. note:: In PDF, links are a subtype of annotations technically and **do not support fill colors**. However, to keep a consistent API, we do allow specifying a `fill=` parameter like with all annotations, which will be ignored with a warning.\n\n      *(Changed in version 1.16.9)* Allow colors to be directly set. These parameters are used if *colors* is not a dictionary.\n\n      :arg dict colors: a dictionary containing color specifications. For accepted dictionary keys and values see below. The most practical way should be to first make a copy of the *colors* property and then modify this dictionary as required.\n      :arg sequence stroke: see above.\n\n   .. method:: set_flags(flags)\n\n      *New in v1.18.16*\n\n      Set the PDF `/F` property of the link annotation. See :meth:`Annot.set_flags` for details. If not a PDF, this method is a no-op.\n\n\n   .. attribute:: flags\n\n      *New in v1.18.16*\n\n      Return the link annotation flags, an integer (see :attr:`Annot.flags` for details). Zero if not a PDF.\n\n\n   .. attribute:: colors\n\n      Meaningful for PDF only: A dictionary of two tuples of floats in range `0 <= float <= 1` specifying the *stroke* and the interior (*fill*) colors. If not a PDF, ``None`` is returned. As mentioned above, the fill color is always `None` for links. The stroke color is used for the border of the link rectangle. The length of the tuple implicitly determines the colorspace: 1 = GRAY, 3 = RGB, 4 = CMYK. So `(1.0, 0.0, 0.0)` stands for RGB color red. The value of each float *f* is mapped to the integer value *i* in range 0 to 255 via the computation *f = i / 255*.\n\n      :rtype: dict\n\n   .. attribute:: border\n\n      Meaningful for PDF only: A dictionary containing border characteristics. It will be ``None`` for non-PDFs and an empty dictionary if no border information exists. The following keys can occur:\n\n      * *width* -- a float indicating the border thickness in points. The value is -1.0 if no width is specified.\n\n      * *dashes* -- a sequence of integers specifying a line dash pattern. *[]* means no dashes, *[n]* means equal on-off lengths of *n* points, longer lists will be interpreted as specifying alternating on-off length values. See the :ref:`AdobeManual` page 126 for more detail.\n\n      * *style* -- 1-byte border style: *S* (Solid) = solid rectangle surrounding the annotation, *D* (Dashed) = dashed rectangle surrounding the link, the dash pattern is specified by the *dashes* entry, *B* (Beveled) = a simulated embossed rectangle that appears to be raised above the surface of the page, *I* (Inset) = a simulated engraved rectangle that appears to be recessed below the surface of the page, *U* (Underline) = a single line along the bottom of the annotation rectangle.\n\n      :rtype: dict\n\n   .. attribute:: rect\n\n      The area that can be clicked in untransformed coordinates.\n\n      :type: :ref:`Rect`\n\n   .. attribute:: is_external\n\n      A bool specifying whether the link target is outside of the current document.\n\n      :type: bool\n\n   .. attribute:: uri\n\n      A string specifying the link target. The meaning of this property should\n      be evaluated in conjunction with property `is_external`:\n      \n      *\n        `is_external` is true: `uri` points to some target outside the current\n        PDF, which may be an internet resource (`uri` starts with ``http://`` or\n        similar), another file (`uri` starts with \"file:\" or \"file://\") or some\n        other service like an e-mail address (`uri` starts with ``mailto:``).\n\n      *\n        `is_external` is false: `uri` will be `None` or point to an\n        internal location. In case of PDF documents, this should either be\n        *#nnnn* to indicate a 1-based (!) page number *nnnn*, or a named\n        location. The format varies for other document types, for example\n        \"../FixedDoc.fdoc#PG_2_LNK_1\" for page number 2 (1-based) in an XPS\n        document.\n\n      :type: str\n\n   .. attribute:: xref\n\n      An integer specifying the PDF :data:`xref`. Zero if not a PDF.\n\n      :type: int\n\n   .. attribute:: next\n\n      The next link or ``None``.\n\n      :type: *Link*\n\n   .. attribute:: dest\n\n      The link destination details object.\n\n      :type: :ref:`linkDest`\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/linkdest.rst",
    "content": ".. include:: header.rst\n\n.. _linkDest:\n\n================\nlinkDest\n================\nClass representing the `dest` property of an outline entry or a link. Describes the destination to which such entries point.\n\n.. note:: Up to MuPDF v1.9.0 this class existed inside MuPDF and was dropped in version 1.10.0. For backward compatibility, PyMuPDF is still maintaining it, although some of its attributes are no longer backed by data actually available via MuPDF.\n\n=========================== ====================================\n**Attribute**               **Short Description**\n=========================== ====================================\n:attr:`linkDest.dest`       destination\n:attr:`linkDest.fileSpec`   file specification (path, filename)\n:attr:`linkDest.flags`      descriptive flags\n:attr:`linkDest.isMap`      is this a MAP?\n:attr:`linkDest.isUri`      is this a URI?\n:attr:`linkDest.kind`       kind of destination\n:attr:`linkDest.lt`         top left coordinates\n:attr:`linkDest.named`      name if named destination\n:attr:`linkDest.newWindow`  name of new window\n:attr:`linkDest.page`       page number\n:attr:`linkDest.rb`         bottom right coordinates\n:attr:`linkDest.uri`        URI\n=========================== ====================================\n\n**Class API**\n\n.. class:: linkDest\n\n   .. attribute:: dest\n\n      Target destination name if :attr:`linkDest.kind` is :data:`LINK_GOTOR` and :attr:`linkDest.page` is *-1*.\n\n      :type: str\n\n   .. attribute:: fileSpec\n\n      Contains the filename and path this link points to, if :attr:`linkDest.kind` is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.\n\n      :type: str\n\n   .. attribute:: flags\n\n      A bitfield describing the validity and meaning of the different aspects of the destination. As far as possible, link destinations are constructed such that e.g. :attr:`linkDest.lt` and :attr:`linkDest.rb` can be treated as defining a bounding box. But the flags indicate which of the values were actually specified, see :ref:`linkDest Flags`.\n\n      :type: int\n\n   .. attribute:: isMap\n\n      This flag specifies whether to track the mouse position when the URI is resolved. Default value: False.\n\n      :type: bool\n\n   .. attribute:: isUri\n\n      Specifies whether this destination is an internet resource (as opposed to e.g. a local file specification in URI format).\n\n      :type: bool\n\n   .. attribute:: kind\n\n      Indicates the type of this destination, like a place in this document, a URI, a file launch, an action or a place in another file. Look at :ref:`linkDest Kinds` to see the names and numerical values.\n\n      :type: int\n\n   .. attribute:: lt\n\n      The top left :ref:`Point` of the destination.\n\n      :type: :ref:`Point`\n\n   .. attribute:: named\n\n      This destination refers to some named action to perform (e.g. a javascript, see :ref:`AdobeManual`). Standard actions provided are *NextPage*, *PrevPage*, *FirstPage*,  and *LastPage*.\n\n      :type: str\n\n   .. attribute:: newWindow\n\n      If true, the destination should be launched in a new window.\n\n      :type: bool\n\n   .. attribute:: page\n\n      The page number (in this or the target document) this destination points to. Only set if :attr:`linkDest.kind` is :data:`LINK_GOTOR` or :data:`LINK_GOTO`. May be *-1* if :attr:`linkDest.kind` is :data:`LINK_GOTOR`. In this case :attr:`linkDest.dest` contains the **name** of a destination in the target document.\n\n      :type: int\n\n   .. attribute:: rb\n\n      The bottom right :ref:`Point` of this destination.\n\n      :type: :ref:`Point`\n\n   .. attribute:: uri\n\n      The name of the URI this destination points to.\n\n      :type: str\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/locales/ja/.readthedocs.yaml",
    "content": "# .readthedocs.yaml\r\n# Note: We use this dedicated yaml inside the locales/ja folder as RTD was having problems building a PDF\r\n# This yaml is the same as the main one - it just removes the PDF build option\r\n\r\n# Required\r\nversion: 2\r\n\r\n# Set the version of Python and other tools you might need\r\nbuild:\r\n  os: ubuntu-20.04\r\n  tools:\r\n    python: \"3.9\"\r\n    # You can also specify other tool versions:\r\n    # nodejs: \"16\"\r\n    # rust: \"1.55\"\r\n    # golang: \"1.17\"\r\n\r\n# Build documentation in the docs/ directory with Sphinx\r\nsphinx:\r\n   configuration: docs/conf.py\r\n\r\n# Optionally declare the Python requirements required to build your docs\r\npython:\r\n   install:\r\n   - requirements: docs/requirements.txt\r\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/404.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header-404.rst:-1 7d1db678351e48a589812b0fc43a3c6e\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header-404.rst:-1 1240b3bfde8e4c75af72a7add2aa6ece\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header-404.rst:-1 e9db42018d9749a3a1b1fcd7d2ffbad7\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../404.rst:4 47500cd0e1e4472092d58a3f1eb0de05\nmsgid \"404!\"\nmsgstr \"\"\n\n#: ../../404.rst:7 00f23d61373848a99a4874c470e1479a\nmsgid \"**This page is not available.**\"\nmsgstr \"**このページは利用できません。**\"\n\n#: ../../404.rst:10 108326f9c443411e998790ba1e98be35\nmsgid \"Please use the menu or search to find what you are looking for.\"\nmsgstr \"メニューまたは検索を使用して、お探しのものを見つけてください。\"\n\n#: ../../footer.rst:60 eab1290efc024ba1b73c0d32ce382104\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/about-feature-matrix.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-08-16 14:20+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/about-performance.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-08-16 14:20+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/about.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 c21340a4b75747d5952e637a324049bf\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 12768be3aef44279a0f53bb67e659597\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 4d3f2343a3e8462e92d346b6ef1bbe0f\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../about.rst:10 6bf350a1548242f08f4231816b75ae9e\nmsgid \"Features Comparison\"\nmsgstr \"機能の比較\"\n\n#: ../../about.rst:16 e6e0680f36684a24b35c48e7756b8ee2\nmsgid \"Feature Matrix\"\nmsgstr \"機能比較表\"\n\n#: ../../about.rst:18 fdad9ebd21e342da9d1b6b35ca5ad4e9\nmsgid \"\"\n\"The following table illustrates how |PyMuPDF| compares with other typical\"\n\" solutions.\"\nmsgstr \"以下の表は、|PyMuPDF| が他の典型的な解決策と比較した場合の違いを示しています。\"\n\n#: ../../about.rst:47 5f1d6f3b09ac43e1ae7043dc7a879c02\nmsgid \"\"\n\"A note about **Office** document types (DOCX, XLXS, PPTX) and **Hangul** \"\n\"documents (HWPX). These documents can be loaded into |PyMuPDF| and you \"\n\"will receive a :ref:`Document <Document>` object.\"\nmsgstr \"\"\n\n#: ../../about.rst:49 9add749bf1d7451aabfcb79190677ddb\nmsgid \"There are some caveats:\"\nmsgstr \"\"\n\n#: ../../about.rst:52 a610a8b3f5cf4333938a9e7a75157f1d\nmsgid \"we convert the input to **HTML** to layout the content.\"\nmsgstr \"\"\n\n#: ../../about.rst:53 a71abef4bb604e3b8f1065200afb7907\nmsgid \"because of this the original page separation has gone.\"\nmsgstr \"\"\n\n#: ../../about.rst:55 255d6618e34f4f11ae7a1a0f54f57322\nmsgid \"\"\n\"When saving out the result any faithful representation of the original \"\n\"layout cannot be expected.\"\nmsgstr \"\"\n\n#: ../../about.rst:57 59954cbab9914471b64ad43b7eb7a58b\nmsgid \"\"\n\"Therefore input files are mostly in a form that's useful for text \"\n\"extraction.\"\nmsgstr \"\"\n\n#: ../../about.rst:65 f3ad21fdc6c841f090824af510994edb\nmsgid \"Performance\"\nmsgstr \"パフォーマンス\"\n\n#: ../../about.rst:69 482ba1a4696f429da50d900517f9001b\nmsgid \"\"\n\"To benchmark |PyMuPDF| performance against a range of tasks a test suite \"\n\"with a fixed set of :ref:`8 PDFs with a total of 7,031 \"\n\"pages<Appendix4_Files_Used>` containing text & images is used to obtain \"\n\"performance timings.\"\nmsgstr \"\"\n\":ref:`8つのPDFファイル（合計7,031ページ）<Appendix4_Files_Used>` \"\n\"にテキストと画像が含まれている固定されたセットのテストスイートを使用して、|PyMuPDF|  \"\n\"のパフォーマンスをさまざまなタスクに対してベンチマークします。\"\n\n#: ../../about.rst:72 11c5e7e482204c7682f05223297c6488\nmsgid \"Here are current results, grouped by task:\"\nmsgstr \"以下は、タスクごとにグループ化された現在の結果です：\"\n\n#: ../../about.rst:81 9f36f4db74ab492ba26cc4fb9946f818\nmsgid \"\"\n\"For more detail regarding the methodology for these performance timings \"\n\"see: :ref:`Performance Comparison Methodology<Appendix4>`.\"\nmsgstr \"これらのパフォーマンスのタイミングに関する方法の詳細については、:ref:`パフォーマンス比較方法<Appendix4>` を参照してください。\"\n\n#: ../../about.rst:89 e86ca33131a544e8a4cc0821737a9a86\nmsgid \"License and Copyright\"\nmsgstr \"ライセンスと著作権\"\n\n#: ../../about.rst:93 061c6a01a19c40198fd34033af39cc6d\nmsgid \"\"\n\"|PyMuPDF| and |MuPDF| are now available under both, open-source |AGPL| \"\n\"and commercial license agreements. Please read the full text of the \"\n\"|AGPL| license agreement, available in the distribution material (file \"\n\"COPYING) and `on the GNU license page \"\n\"<https://www.gnu.org/licenses/agpl-3.0.html>`_, to ensure that your use \"\n\"case complies with the guidelines of the license. If you determine you \"\n\"cannot meet the requirements of the |AGPL|, please contact `Artifex \"\n\"<https://artifex.com/contact/pymupdf-inquiry.php?utm_source=rtd-\"\n\"pymupdf&utm_medium=rtd&utm_content=inline-link>`_ for more information \"\n\"regarding a commercial license.\"\nmsgstr \"\"\n\"PyMuPDFとMuPDFは現在、オープンソースのAGPLと商用ライセンス契約の両方で提供されています。ライセンスのガイドラインに従うことを確認するため、配布資料（COPYINGファイル）と\"\n\" `ここ <https://www.gnu.org/licenses/agpl-3.0.html>`_ \"\n\"にあるAGPLライセンス契約の全文をお読みください。AGPLの要件を満たせないと判断された場合は、商用ライセンスに関する詳細情報については、 \"\n\"`Artifex <https://artifex.com/contact/pymupdf-inquiry.php?utm_source=rtd-\"\n\"pymupdf-jp&utm_medium=rtd&utm_content=inline-link>`_ にお問い合わせください。\"\n\n#: ../../about.rst:111 0cf7adfbbbe6404aae5016ba8cf4ca79\nmsgid \"\"\n\":title:`Artifex` is the exclusive commercial licensing agent for \"\n\":title:`MuPDF`.\"\nmsgstr \":title:`Artifex` Artifexは、:title:`MuPDF` の独占的な商業ライセンスエージェントです。\"\n\n#: ../../about.rst:113 1206bde366264e91900de44a990e7b13\nmsgid \"\"\n\":title:`Artifex`, the :title:`Artifex` logo, :title:`MuPDF`, and the \"\n\":title:`MuPDF` logo are registered trademarks of :title:`Artifex Software\"\n\" Inc.`\"\nmsgstr \"\"\n\":title:`Artifex` 、:title:`Artifex` のロゴ、:title:`MuPDF` \"\n\"、およびMuPDFのロゴは、:title:`Artifex Software Inc.` の登録商標です。\"\n\n#: ../../version.rst:3 b23f02d66d164eb195ed6512c8e9ff6c\n#, fuzzy\nmsgid \"This documentation covers PyMuPDF |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#: ../../version.rst:5 ca881a8c265b46618c644701ea14c695\nmsgid \"\"\n\"The major and minor versions of |PyMuPDF| and |MuPDF| will always be the \"\n\"same. Only the third qualifier (patch level) may deviate from that of \"\n\"|MuPDF|.\"\nmsgstr \"\"\n\n#: ../../version.rst:7 a91d12805e42498fb4eebcb3f7923eb8\nmsgid \"\"\n\"Typically PyMuPDF is released more frequently than MuPDF so it will often\"\n\" be the case that the patch level of PyMuPDF will be greater than the \"\n\"embedded MuPDF.\"\nmsgstr \"\"\n\n#: ../../version.rst:11 2e3b5e5955fc4cba8aafc25d3d650e7a\nmsgid \"For example PyMuPDF-1.24.5 contains MuPDF-1.24.2.\"\nmsgstr \"\"\n\n#: ../../version.rst:13 a60af2aa03494194b19ecf8e3bc095fc\nmsgid \"Also see `pymupdf_version` and `mupdf_version`.\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 ea2d1136af82416baa3286db6ed38f96\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF \"\n#~ \"v1.23.0rc1** features as of **2023-08-10 \"\n#~ \"00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.23.4**\"\n#~ \" features as of **2023-09-26 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.23.5**\"\n#~ \" features as of **2023-10-11 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.23.8**\"\n#~ \" features as of **2023-12-19 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.23.26**\"\n#~ \" features as of **2024-02-29 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.24.2**\"\n#~ \" features as of **2024-04-17 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.24.10**\"\n#~ \" features as of **2024-09-02 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.25.5**\"\n#~ \" features as of **2025-03-31 00:00:01**.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/algebra.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 a244f13b9c764d21b6a4e35ef573b3fc\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 9bd00aa1c6e2464c98edbdfe23c4f225\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 0bb8ce2fa7b8439cb16f9ec725fae345\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../algebra.rst:6 a46fc8868909429d85fea1440fd28881\nmsgid \"Operator Algebra for Geometry Objects\"\nmsgstr \"幾何学オブジェクトのためのオペレーター代数\"\n\n#: ../../algebra.rst:10 f2868bfbb77d48739b417240e859be75\nmsgid \"\"\n\"Instances of classes :ref:`Point`, :ref:`IRect`, :ref:`Rect`, :ref:`Quad`\"\n\" and :ref:`Matrix` are collectively also called \\\"geometry\\\" objects.\"\nmsgstr \"\"\n\"クラス :ref:`Point` 、 :ref:`IRect` 、 :ref:`Rect` 、 :ref:`Quad` 、および \"\n\":ref:`Matrix` のインスタンスは、集合的に「幾何学オブジェクト」とも呼ばれます。\"\n\n#: ../../algebra.rst:12 7c7e99aaa08449cc9a3e4a9c1891053e\nmsgid \"\"\n\"They all are special cases of Python sequences, see :ref:`SequenceTypes` \"\n\"for more background.\"\nmsgstr \"これらはすべてPythonシーケンスの特殊なケースであり、詳細については、PyMuPDFでのPythonシーケンスを引数として使用するを参照してください。\"\n\n#: ../../algebra.rst:14 b6a45b1271a0423d9097d983f99dac54\nmsgid \"\"\n\"We have defined operators for these classes that allow dealing with them \"\n\"(almost) like ordinary numbers in terms of addition, subtraction, \"\n\"multiplication, division, and some others.\"\nmsgstr \"これらのクラスには、加算、減算、乗算、除算など、通常の数値とほぼ同じように取り扱うための演算子が定義されています。\"\n\n#: ../../algebra.rst:16 b84d121c948844b78d31027bcf1cc8bb\nmsgid \"This chapter is a synopsis of what is possible.\"\nmsgstr \"この章では、可能な操作の要約を説明します。\"\n\n#: ../../algebra.rst:19 8da4401664bf45689416d5a624615e21\nmsgid \"General Remarks\"\nmsgstr \"一般的な注意事項\"\n\n#: ../../algebra.rst:20 b27e0413604140b6a4e3d9dd5604397e\nmsgid \"\"\n\"Operators can be either **binary** (i.e. involving two objects) or \"\n\"**unary**.\"\nmsgstr \"演算子は2つのオブジェクトを含むバイナリ演算子または単項演算子になります。\"\n\n#: ../../algebra.rst:22 ff83ad4ef4924a928f7fe7c91f007de7\n\nmsgid \"\"\n\"The resulting type of **binary** operations is either a **new object of \"\n\"the left operand's class,** a bool or (for dot products) a float.\"\nmsgstr \"バイナリ演算の結果の型は、左オペランドのクラスの新しいオブジェクトまたはbool型です。\"\n\n#: ../../algebra.rst:24 b6935b28e0494757bdefacd86e1f3a36\nmsgid \"\"\n\"The result of **unary** operations is either a **new object** of the same\"\n\" class, a bool or a float.\"\nmsgstr \"単項演算の結果は、同じクラスの新しいオブジェクト、bool型、またはfloat型のいずれかです。\"\n\n#: ../../algebra.rst:26 a1336f1afec74044ada260ccd870436a\n\nmsgid \"\"\n\"The binary operators `+, -, *, /` are defined for all classes. They \"\n\"*roughly* do what you would expect -- **except, that the second operand \"\n\"...**\"\nmsgstr \"\"\n\"バイナリ演算子 ``+`` 、``-`` 、``*`` 、 ``/`` \"\n\"はすべてのクラスで定義されています。これらはおおよその期待通りの動作をしますが、2番目のオペランドは...（省略されました）。\"\n\n#: ../../algebra.rst:28 e18cb846582247cb975a9ddc6340a73e\nmsgid \"\"\n\"may always be a number which then performs the operation on every \"\n\"component of the first one,\"\nmsgstr \"第2のオペランドは常に数値であり、それにより最初のオペランドのすべての要素に対して操作を行います。\"\n\n#: ../../algebra.rst:29 e60ed0a7fa554df0a16910687c2c88be\nmsgid \"\"\n\"may always be a numeric sequence of the same length (2, 4 or 6) -- we \"\n\"call such sequences :data:`point_like`, :data:`rect_like`, \"\n\":data:`quad_like` or :data:`matrix_like`, respectively.\"\nmsgstr \"\"\n\"第2のオペランドは常に同じ長さの数値のシーケンスであることができます（2つ、4つ、または6つ） - それぞれ :data:`point_like`\"\n\" 、 :data:`rect_like` 、 :data:`quad_like` 、または :data:`matrix_like` と呼びます。\"\n\n#: ../../algebra.rst:31 d93daa3887f04faead0f46a53b4c2a9a\n\nmsgid \"\"\n\"Rectangles support **additional binary** operations: **intersection** \"\n\"(operator `\\\"&\\\"`), **union** (operator `\\\"|\\\"`) and **containment** \"\n\"checking.\"\nmsgstr \"矩形は追加のバイナリ演算をサポートしています：交差（演算子“&”）、結合（演算子“|”）、および包含チェック。\"\n\n#: ../../algebra.rst:33 03d276c145154e428f81b4e854a12723\nmsgid \"\"\n\"Binary operators fully support in-place operations. So if \\\"°\\\" is a \"\n\"binary operator then the expression `a °= b` is always valid and the same\"\n\" as `a = a ° b`. Therefore, be careful and do **not** do `p1 *= p2` for \"\n\"two points, because thereafter \\\"p1\\\" is a **float**.\"\nmsgstr \"バイナリ演算子は「インプレース演算」を完全にサポートしています。つまり、\"°\"がバイナリ演算子である場合、式 ``a °= b`` は常に有効であり、 ``a = a ° b`` と同じです。したがって、2つの点に対して ``p1 *= p2`` を行わないように注意してください。なぜなら、その後「p1」は浮動小数点数になってしまうからです。\"\n\n#: ../../algebra.rst:37 b197551ac91841fba96a5406efd0e076\nmsgid \"Unary Operations\"\nmsgstr \"単項演算\"\n\n#: ../../algebra.rst:40 ../../algebra.rst:59 299776843ce14340b3ffec69dbf18e83\n#: 9ef10cc27f674df49def7dbf4b132848\nmsgid \"Oper.\"\nmsgstr \"演算\"\n\n#: ../../algebra.rst:40 ../../algebra.rst:59 0723d28bc56b478c85107cedb40b5793\n#: 7bff453d3e3548e4910efaf0d7e280d4\nmsgid \"Result\"\nmsgstr \"結果\"\n\n#: ../../algebra.rst:42 d7ac030d071642528ff3bf57fcc11bd3\nmsgid \"bool(OBJ)\"\nmsgstr \"\"\n\n#: ../../algebra.rst:42 0d27ce4c315a43758b0c7f988ac2baca\nmsgid \"is false exactly if all components of OBJ are zero\"\nmsgstr \"OBJのすべての成分がゼロの場合にのみfalse\"\n\n#: ../../algebra.rst:43 3a98a962f2cb4317ad6986bbdec24e65\nmsgid \"abs(OBJ)\"\nmsgstr \"\"\n\n#: ../../algebra.rst:43 6c1997e211ee4d939dd044c813508abb\nmsgid \"the rectangle area -- equal to norm(OBJ) for the other types\"\nmsgstr \"他のタイプに対してnorm(OBJ)と等しい長方形の面積\"\n\n#: ../../algebra.rst:44 94bcec1a0e3d4e96be8a96074d02378d\nmsgid \"norm(OBJ)\"\nmsgstr \"\"\n\n#: ../../algebra.rst:44 e0b98f2206cf4032b715abe02f8be8cd\nmsgid \"square root of the component squares (Euclidean norm)\"\nmsgstr \"成分の二乗の平方根（ユークリッドノルム）\"\n\n#: ../../algebra.rst:45 00744445072349b8b253bc092cc7bb87\nmsgid \"+OBJ\"\nmsgstr \"\"\n\n#: ../../algebra.rst:45 0b56037ce3e04d528042a1a6098bb2f9\nmsgid \"new copy of OBJ\"\nmsgstr \"OBJの新しいコピー\"\n\n#: ../../algebra.rst:46 0c1dfe4fe3344199b8b76d70f4f7d7f3\nmsgid \"-OBJ\"\nmsgstr \"\"\n\n#: ../../algebra.rst:46 ef82c60af2dc4d238eba6b421e3047d9\nmsgid \"new copy of OBJ with negated components\"\nmsgstr \"成分が反転されたOBJの新しいコピー\"\n\n#: ../../algebra.rst:47 ee6061816bb3437fa7e09c6d431dc788\nmsgid \"~m\"\nmsgstr \"\"\n\n#: ../../algebra.rst:47 1e8a0c10344348238fc0f64c83edd642\nmsgid \"inverse of matrix \\\"m\\\", or the null matrix if not invertible\"\nmsgstr \"行列 \\\"m\\\" の逆行列、または逆行列が存在しない場合は零行列\"\n\n#: ../../algebra.rst:52 398158a768f84b89a520021ea6d0a25f\nmsgid \"Binary Operations\"\nmsgstr \"二項演算\"\n\n#: ../../algebra.rst:53 01209ef26eeb4f6284e42a5165ad12aa\nmsgid \"\"\n\"These are expressions like `a ° b` where \\\"°\\\" is any of the operators \"\n\"`+, -, *, /`. Also binary operations are expressions of the form `a == b`\"\n\" and `b in a`.\"\nmsgstr \"これらは ``a ° b`` のような式であり、ここで「°」は ``+``, ``-``, ``*``, ``/`` などの演算子のいずれかです。また、バイナリ演算には ``a == b`` や ``b in a`` のような形式の式も含まれます。\"\n\n#: ../../algebra.rst:55 347337c08b6e49ba8133b876c65de703\nmsgid \"\"\n\"If \\\"b\\\" is a number, then the respective operation is executed for each \"\n\"component of \\\"a\\\". Otherwise, if \\\"b\\\" is **not a number,** then the \"\n\"following happens:\"\nmsgstr \"もし「b」が数値である場合、それぞれの演算は「a」の各コンポーネントに対して実行されます。一方、「b」が数値ではない場合、以下のことが起こります：\"\n\n#: ../../algebra.rst:61 882647f50a3548ada51850492e59336c\nmsgid \"a+b, a-b\"\nmsgstr \"\"\n\n#: ../../algebra.rst:61 529c2b3a1c8f440f8afd4fba9ce0396e\nmsgid \"component-wise execution, \\\"b\\\" must be \\\"a-like\\\".\"\nmsgstr \"成分ごとの実行。\\\"b\\\" は \\\"a\\\" と同様の要素数である必要があります。\"\n\n#: ../../algebra.rst:62 2606cc3b045c4835abe58d011464d50a\nmsgid \"a*m, a/m\"\nmsgstr \"\"\n\n#: ../../algebra.rst:62 7d3849829e3b4508827663e012314f30\n\nmsgid \"\"\n\"\\\"a\\\" can be a point, rectangle or matrix and \\\"m\\\" is a \"\n\":data:`matrix_like`. *\\\"a/m\\\"* is treated as *\\\"a*~m\\\"* (see note below \"\n\"for non-invertible matrices). If \\\"a\\\" is a **point** or a **rectangle**,\"\n\" then *\\\"a.transform(m)\\\"* is executed. If \\\"a\\\" is a matrix, then matrix\"\n\" concatenation takes place.\"\nmsgstr \"\"\n\"\\\"a\\\" はポイント、矩形、または行列になりますが、\\\"m\\\" は :data:`matrix_like` でなければなりません。\\\"a/m\\\"\"\n\" は \\\"a*〜m\\\" として処理されます（非逆行列の場合は以下の注記を参照）。\\\"a\\\" \"\n\"がポイントまたは矩形の場合、\\\"a.transform(m)\\\" が実行されます。\\\"a\\\" が行列の場合、行列の連結が行われます。\"\n\n#: ../../algebra.rst:67 b98d2bd8c76145a093239f6b2583ff78\nmsgid \"a*b\"\nmsgstr \"\"\n\n#: ../../algebra.rst:67 55f9b0922451482484ef7fe2110fefb7\nmsgid \"returns the **vector dot product** for a point \\\"a\\\" and point-like \\\"b\\\".\"\nmsgstr \"点「a」と点のような「b」に対して、ベクトルの内積を返します。\"\n\n#: ../../algebra.rst:68 2c02e64b04dd47a89a57341e5557c6f4\nmsgid \"a&b\"\nmsgstr \"\"\n\n#: ../../algebra.rst:68 b1ebf38a599942378b28ecc93be28dbc\nmsgid \"\"\n\"**intersection rectangle:** \\\"a\\\" must be a rectangle and \\\"b\\\" \"\n\":data:`rect_like`. Delivers the **largest rectangle** contained in both \"\n\"operands.\"\nmsgstr \"\"\n\"共通の長方形: \\\"a\\\" は長方形であり、\\\"b\\\" は :data:`rect_like` \"\n\"形式である必要があります。両方のオペランドに含まれる最大の長方形を返します。\"\n\n#: ../../algebra.rst:71 6b94ffc704eb47269f5a3961a01cc914\nmsgid \"a|b\"\nmsgstr \"\"\n\n#: ../../algebra.rst:71 f10408473ce74344941deb9adedaea81\nmsgid \"\"\n\"**union rectangle:** \\\"a\\\" must be a rectangle, and \\\"b\\\" may be \"\n\":data:`point_like` or :data:`rect_like`. Delivers the **smallest \"\n\"rectangle** containing both operands.\"\nmsgstr \"\"\n\"合併した長方形: \\\"a\\\" は長方形であり、\\\"b\\\" は 点のような :data:`point_like` :data:`rect_like`\"\n\" 形式である必要があります。両方のオペランドを含む最小の長方形を返します。\"\n\n#: ../../algebra.rst:74 68ba14dfcb0944fb8f12d32ccd74acfc\nmsgid \"b in a\"\nmsgstr \"\"\n\n#: ../../algebra.rst:74 20c6156b787d407bba8ac0eb66d0003f\nmsgid \"\"\n\"if \\\"b\\\" is a number, then `b in tuple(a)` is returned. If \\\"b\\\" is \"\n\":data:`point_like`, :data:`rect_like` or :data:`quad_like`, then \\\"a\\\" \"\n\"must be a rectangle, and `a.contains(b)` is returned.\"\nmsgstr \"\"\n\"もし \\\"b\\\" が数値である場合、 `b in tuple(a)` が返されます。もし \\\"b\\\" が :data:`point_like` \"\n\"形式、 :data:`rect_like` 形式、または :data:`quad_like` 形式である場合、\\\"a\\\" \"\n\"は長方形である必要があり、`a.contains(b)` が返されます。\"\n\n#: ../../algebra.rst:77 14c642acfd6a4cc09dd70b7edfc9479d\nmsgid \"a == b\"\nmsgstr \"\"\n\n#: ../../algebra.rst:77 b5f52a2ccb364df6aafabfc00b804bfd\nmsgid \"``True`` if *bool(a-b)* is ``False`` (\\\"b\\\" may be \\\"a-like\\\").\"\nmsgstr \"bool(a-b) が `False` であれば `True` を返します（\\\"b\\\"は\\\"a-like\\\"である可能性があります）。\"\n\n#: ../../algebra.rst:81 91cf0864d56a40f89a084004444ece8e\nmsgid \"Please note an important difference to usual arithmetic:\"\nmsgstr \"以下は通常の算術との重要な違いに注意してください：\"\n\n#: ../../algebra.rst:83 c2257dafe2e54f93bdf6e878a27abb1e\nmsgid \"\"\n\"Matrix multiplication is **not commutative**, i.e. in general we have \"\n\"`m*n != n*m` for two matrices. Also, there are non-zero matrices which \"\n\"have no inverse, for example `m = Matrix(1, 0, 1, 0, 1, 0)`. If you try \"\n\"to divide by any of these, you will receive a `ZeroDivisionError` \"\n\"exception using operator *\\\"/\\\"*, e.g. for the expression \"\n\"`pymupdf.Identity / m`. But if you formulate `pymupdf.Identity * ~m`, the\"\n\" result will be `pymupdf.Matrix()` (the null matrix).\"\nmsgstr \"\"\n\"行列の乗算は可換ではありません。つまり、一般に2つの行列に対して `m*n != n*m` \"\n\"が成り立ちます。また、逆行列を持たないゼロでない行列も存在します。例えば、`m = Matrix(1, 0, 1, 0, 1, 0)` \"\n\"のような行列があります。これらの行列で除算しようとすると、演算子 *\\\"/\\\"* を使用して `pymupdf.Identity / m` \"\n\"のような式で `ZeroDivisionError` 例外が発生します。しかし、`pymupdf.Identity * ~m` \"\n\"のように記述すると、結果は `pymupdf.Matrix()` （零行列）となります。\"\n\n#: ../../algebra.rst:85 0e187d91aa3543128b18a63bdf168871\nmsgid \"\"\n\"Admittedly, this represents an inconsistency, and we are considering to \"\n\"remove it. For the time being, you can choose to avoid an exception and \"\n\"check whether ~m is the null matrix, or accept a potential \"\n\"*ZeroDivisionError* by using `pymupdf.Identity / m`.\"\nmsgstr \"\"\n\"認めるところがあるかもしれませんが、これは矛盾を示しており、私たちはこれを取り除くことを検討しています。当面の間は、例外を回避し、`~m` \"\n\"が零行列であるかどうかをチェックするか、`pymupdf.Identity / m` を使用して `ZeroDivisionError` \"\n\"の可能性を受け入れることができます。\"\n\n#: ../../algebra.rst:89 de603159545946e8bdc68fe78cd85024\nmsgid \"\"\n\"With these conventions, all the usual algebra rules apply. For example, \"\n\"arbitrarily using brackets **(among objects of the same class!)** is \"\n\"possible: if r1, r2 are rectangles and m1, m2 are matrices, you can do \"\n\"this `(r1 + r2) * m1 * m2`.\"\nmsgstr \"\"\n\"これらの規則に従うと、すべての通常の代数のルールが適用されます。例えば、任意の括弧を使うことができます（同じクラスのオブジェクトの間で！）：もし \"\n\"`r1`, `r2` が長方形であり、`m1`, `m2` が行列であれば、次のようにできます： `(r1 + r2) * m1 * m2` 。\"\n\n#: ../../algebra.rst:90 2e9035f1be214ad5993be5461f301e62\nmsgid \"\"\n\"For all objects of the same class, `a + b + c == (a + b) + c == a + (b + \"\n\"c)` is true.\"\nmsgstr \"同じクラスのオブジェクトに対して、 `a + b + c == (a + b) + c == a + (b + c)` が成り立ちます。\"\n\n#: ../../algebra.rst:91 695f00e56afc43e8bbde8536925b9ffc\nmsgid \"\"\n\"For matrices in addition the following is true: `(m1 + m2) * m3 == m1 * \"\n\"m3 + m2 * m3` (distributivity property).\"\nmsgstr \"行列の加法については、次のような性質が成り立ちます： `(m1 + m2) * m3 == m1 * m3 + m2 * m3` （分配律）。\"\n\n#: ../../algebra.rst:92 85174e316c684b489921150e95d1aed3\nmsgid \"\"\n\"**But the sequence of applying matrices is important:** If r is a \"\n\"rectangle and m1, m2 are matrices, then -- **caution!:**\"\nmsgstr \"ただし、行列の適用順序が重要です：もし `r` が長方形であり、 `m1` ,  `m2` が行列である場合、注意してください！次のような場合：\"\n\n#: ../../algebra.rst:93 8db6b272b39a4051b95fd6474751c244\nmsgid \"`r * m1 * m2 == (r * m1) * m2 != r * (m1 * m2)`\"\nmsgstr \"\"\n\n#: ../../algebra.rst:96 5a5c13a7f2b542b59628658c7a3217f1\nmsgid \"Some Examples\"\nmsgstr \"いくつかの例\"\n\n#: ../../algebra.rst:99 b685ff344b354dd6b03324c45389e661\nmsgid \"Manipulation with numbers\"\nmsgstr \"数値の操作\"\n\n#: ../../algebra.rst:100 92463489f90f4556b3d5a7b306e1e7ac\nmsgid \"\"\n\"For the usual arithmetic operations, numbers are always allowed as second\"\n\" operand. In addition, you can formulate `\\\"x in OBJ\\\"`, where x is a \"\n\"number. It is implemented as `\\\"x in tuple(OBJ)\\\"`::\"\nmsgstr \"\"\n\"通常の算術演算では、数値は常に第二オペランドとして使用できます。さらに、`\\\"x in OBJ\\\"` \"\n\"のように式を記述することもできます。ここで、xは数値です。これは `\\\"x in tuple(OBJ)\\\"` として実装されています::\"\n\n#: ../../algebra.rst:108 d3192c1a63bb460ba17fe04f2de5b3ff\nmsgid \"\"\n\"The following will create the upper left quarter of a document page \"\n\"rectangle::\"\nmsgstr \"以下は、ドキュメントページの四角形の左上の四分の一を作成します::\"\n\n#: ../../algebra.rst:116 9f9d44b5091a4a65844a451e8d7c92c4\nmsgid \"\"\n\"The following will deliver the **middle point of a line** that connects \"\n\"two points **p1** and **p2**::\"\nmsgstr \"以下は、点 `p1` と点 `p2` を結ぶ直線の中点を求めます::\"\n\n#: ../../algebra.rst:125 2908e3f62351463a817217bed9ee7101\nmsgid \"\"\n\"Compute the **vector dot product** of two points. You can compute the \"\n\"**cosine of angles** and check orthogonality.\"\nmsgstr \"2つの点のベクトル内積を計算します。これにより、角度のコサインを計算したり、直交性を確認したりすることができます。\"\n\n#: ../../algebra.rst:149 05936628739f4f5392d49359e0f8860d\nmsgid \"Manipulation with \\\"like\\\" Objects\"\nmsgstr \"「Like」オブジェクトを用いた操作\"\n\n#: ../../algebra.rst:151 64ff208b10184910a7052e2d2fde5560\nmsgid \"\"\n\"The second operand of a binary operation can always be \\\"like\\\" the left \"\n\"operand. \\\"Like\\\" in this context means \\\"a sequence of numbers of the \"\n\"same length\\\". With the above examples::\"\nmsgstr \"2項演算の第2オペランドは常に左オペランドと「like」することができます。「Like」とは、この文脈では「同じ長さの数列」という意味です。上記の例を用いて説明します。\"\n\n#: ../../algebra.rst:162 7626451d4f89418ea6f21c0194766c1e\nmsgid \"To shift a rectangle for 5 pixels to the right, do this::\"\nmsgstr \"長方形を右に5ピクセルシフトさせるには、次のようにします::\"\n\n#: ../../algebra.rst:168 ffbacdbea5aa4828ab455e4e9da44bf2\nmsgid \"\"\n\"Points, rectangles and matrices can be *transformed* with matrices. In \"\n\"PyMuPDF, we treat this like a **\\\"multiplication\\\"** (or resp. \"\n\"**\\\"division\\\"**), where the second operand may be \\\"like\\\" a matrix. \"\n\"Division in this context means \\\"multiplication with the inverted \"\n\"matrix\\\"::\"\nmsgstr \"点、長方形、および行列は行列で変換できます。PyMuPDFでは、これを「乗算」（または「除算」とも）として扱います。ここで、第2オペランドは行列と「like」することができます。「除算」とは、この文脈では「逆行列との乗算」を意味します。\"\n\n#: ../../algebra.rst:208 f6063ded1f794fdfa330d05aab12b59a\nmsgid \"As a specialty, rectangles support additional binary operations:\"\nmsgstr \"特に、長方形は追加の2項演算をサポートしています：\"\n\n#: ../../algebra.rst:210 8ddb30b3a1e6414cb4ab801649852302\nmsgid \"**intersection** -- the common area of rectangle-likes, operator *\\\"&\\\"*\"\nmsgstr \"**交差** -- 長方形や類似の長方形の共通領域を示す演算子 *\\\"&\\\"*\"\n\n#: ../../algebra.rst:211 44b3d1c0634a46f1ae3506fe5d9c9046\nmsgid \"\"\n\"**inclusion** -- enlarge to include a point-like or rect-like, operator \"\n\"*\\\"|\\\"*\"\nmsgstr \"**含有** -- 点状または長方形状を含むように拡大する演算子 *\\\"|\\\"*\"\n\n#: ../../algebra.rst:212 462847c9ff494bef9387ce0aff093bfd\nmsgid \"**containment** check -- whether a point-like or rect-like is inside\"\nmsgstr \"**含有確認** 点状または長方形状が内部にあるかどうかを確認します\"\n\n#: ../../algebra.rst:214 8733fac916f74438a2cecf7b54a9c218\nmsgid \"\"\n\"Here is an example for creating the smallest rectangle enclosing given \"\n\"points::\"\nmsgstr \"以下は、与えられた点を囲む最小の長方形を作成する例です::\"\n\n#: ../../footer.rst:60 1533c6c3a8344ce0b45e9762c0145328\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Binary operators fully support in-place\"\n#~ \" operations, so expressions like `a \"\n#~ \"/= b` are valid if b is \"\n#~ \"numeric or \\\"a_like\\\".\"\n#~ msgstr \"\"\n#~ \"バイナリ演算子は、すべての場所で完全にサポートされているため、``b`` が数値または「a_like」の場合、 \"\n#~ \"``a /= b`` のような式が有効です\"\n\n#~ msgid \"\"\n#~ \"For every geometry object \\\"a\\\" and \"\n#~ \"every number \\\"b\\\", the operations \\\"a\"\n#~ \" ° b\\\" and \\\"a °= b\\\" are \"\n#~ \"always defined for the operators *+, \"\n#~ \"-, *, /*. The respective operation \"\n#~ \"is simply executed for each component\"\n#~ \" of \\\"a\\\". If the **second operand\"\n#~ \" is not a number**, then the \"\n#~ \"following is defined:\"\n#~ msgstr \"\"\n#~ \"あらゆるジオメトリオブジェクト\\\"a\\\"とあらゆる数値 \\\"b\\\" に対して、演算子 ``+``,\"\n#~ \" ``-`` , ``*`` , ``/`` については常に  \"\n#~ \"\\\"a ° b\\\" と \\\"a °= b\\\" \"\n#~ \"の操作が定義されています。それぞれの操作は、\\\"a\\\" \"\n#~ \"の各成分に対して単純に実行されます。もし第二オペランドが数値でない場合、次のように定義されます：\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/annot.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4ac2fe405aa74919af4d4a1801389523\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 aee68aa3a3cc4589bddde105fa520c68\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 60584b8003094a8b9570ee372d8eab4b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../annot.rst:7 f0fb0074a9b6446f8124c5e84ab64978\nmsgid \"Annot\"\nmsgstr \"Annot (注釈)\"\n\n#: ../../annot.rst:9 fafaf69d450d48c5b26a1a93cb2eaa69\nmsgid \"|pdf_only_class|\"\nmsgstr \"PDFのみ。\"\n\n#: ../../annot.rst:11 4869b122c6834f279f19045fee171ca8\nmsgid \"Quote from the :ref:`AdobeManual`:\"\nmsgstr \":ref:`AdobeManual` からの引用: \"\n\n#: ../../annot.rst:13 e7b3050079714378a72611a6fde2125b\nmsgid \"\"\n\"*\\\"An annotation associates an object such as a note, sound, or movie \"\n\"with a location on a page of a PDF document, or provides a way to \"\n\"interact with the user by means of the mouse and keyboard.\\\"*\"\nmsgstr \"「注釈は、ノート、音声、動画などのオブジェクトをPDFドキュメントのページ上の位置に関連付けるか、マウスとキーボードを介してユーザーと対話する手段を提供します。」\"\n\n#: ../../annot.rst:15 5c314b35139f446694f6aca06c7824f1\nmsgid \"\"\n\"There is a parent-child relationship between an annotation and its page. \"\n\"If the page object becomes unusable (closed document, any document \"\n\"structure change, etc.), then so does every of its existing annotation \"\n\"objects -- an exception is raised saying that the object is \\\"orphaned\\\",\"\n\" whenever an annotation property or method is accessed.\"\nmsgstr \"注釈とそのページとの間には親子関係があります。ページオブジェクトが使用できなくなる場合（閉じたドキュメント、文書構造の変更など）、そのページに存在するすべての注釈オブジェクトも同様に使用できなくなります。注釈のプロパティやメソッドにアクセスされるたびに、オブジェクトが「孤立した」という例外が発生します。\"\n\n#: ../../annot.rst:18 ce89c615b0d9400e96011970b5b97556\nmsgid \"**Attribute**\"\nmsgstr \"**アトリビュート** \"\n\n#: ../../annot.rst:18 715a7d9d0eca46759c21efd06dcef6ad\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明** \"\n\n#: ../../annot.rst:20 46ba2c1aef7f47fb8cf735ab0ab8ca51\nmsgid \":meth:`Annot.delete_responses`\"\nmsgstr \"\"\n\n#: ../../annot.rst:20 542edab529f14f8a90c247c58f61d0e4\nmsgid \"delete all responding annotations\"\nmsgstr \"すべての応答アノテーションを削除します\"\n\n#: ../../annot.rst:21 d6f4ad7997854c15ba7ef55c7c2df885\nmsgid \":meth:`Annot.get_file`\"\nmsgstr \"\"\n\n#: ../../annot.rst:21 df78c21ef62f4d29b9892ced6ce30eab\nmsgid \"get attached file content\"\nmsgstr \"添付ファイルの内容を取得します\"\n\n#: ../../annot.rst:22 aaa2f1576e2940d187b785f39fd5d297\nmsgid \":meth:`Annot.get_oc`\"\nmsgstr \"\"\n\n#: ../../annot.rst:22 52de51aa8f364679a043608a648fdb6d\nmsgid \"get :data:`xref` of an :data:`OCG` / :data:`OCMD`\"\nmsgstr \":data:`xref` を :data:`OCG` または :data:`OCMD` に取得します。\"\n\n#: ../../annot.rst:23 ba830719161c41318892442d95b2cb34\nmsgid \":meth:`Annot.get_pixmap`\"\nmsgstr \"\"\n\n#: ../../annot.rst:23 558b79769da645e1be5e25ee89f039ab\nmsgid \"image of the annotation as a pixmap\"\nmsgstr \"アノテーションの画像をピクマップとして取得します\"\n\n#: ../../annot.rst:24 a7049ccda64e4dd6890da7abe84fabf6\nmsgid \":meth:`Annot.get_sound`\"\nmsgstr \"\"\n\n#: ../../annot.rst:24 374a09b731894e87b56c7e841b17d330\nmsgid \"get the sound of an audio annotation\"\nmsgstr \"オーディオアノテーションの音声を取得します\"\n\n#: ../../annot.rst:25 35a90d1b5a004ad387963f3d9607d749\nmsgid \":meth:`Annot.get_text`\"\nmsgstr \"\"\n\n#: ../../annot.rst:25 ../../annot.rst:26 6131792a9d994335b4444e4823388a9a\n#: f86eecd4858f4cb89a366a146014aee5\nmsgid \"extract annotation text\"\nmsgstr \"アノテーションテキストを抽出します\"\n\n#: ../../annot.rst:26 04cf9bb3fb1442709930c64bc5f6b0bb\nmsgid \":meth:`Annot.get_textbox`\"\nmsgstr \"\"\n\n#: ../../annot.rst:27 19db3425545544fcbcd820ce607ec897\nmsgid \":meth:`Annot.get_textpage`\"\nmsgstr \"\"\n\n#: ../../annot.rst:27 c85fb9dd00d64ff99bd74482953c24bf\nmsgid \"create a TextPage for the annotation\"\nmsgstr \"アノテーションのためのポップアップを作成します\"\n\n#: ../../annot.rst:28 802ef16921bd4a60800fbad10cc481fd\nmsgid \":meth:`Annot.set_border`\"\nmsgstr \"\"\n\n#: ../../annot.rst:28 2237d589cf4b43f8accb31706b0ac2e1\nmsgid \"set annotation's border properties\"\nmsgstr \"アノテーションの境界線のプロパティを設定します\"\n\n#: ../../annot.rst:29 d6e3ab0ff8c247faa2df18a3dbd4fb5f\nmsgid \":meth:`Annot.set_blendmode`\"\nmsgstr \"\"\n\n#: ../../annot.rst:29 8ff755a8802d4e4bb4f4c6466fd93439\nmsgid \"set annotation's blend mode\"\nmsgstr \"アノテーションのブレンドモードを設定します\"\n\n#: ../../annot.rst:30 ff206dc2f63444dfae9fbe12712ba514\nmsgid \":meth:`Annot.set_colors`\"\nmsgstr \"\"\n\n#: ../../annot.rst:30 3a8dce63eadd4ffe82a27bc21a526045\nmsgid \"set annotation's colors\"\nmsgstr \"アノテーションの色を設定します\"\n\n#: ../../annot.rst:31 ../../annot.rst:341 7c620a1bbb3d466d8c82b9c8817c33ee\n#: a00f8a2d06fa46afb1028c82837e4185\nmsgid \":meth:`Annot.set_flags`\"\nmsgstr \"\"\n\n#: ../../annot.rst:31 37269417aa5845e78bc95975097fddad\nmsgid \"set annotation's flags field\"\nmsgstr \"アノテーションのフラグフィールドを設定します\"\n\n#: ../../annot.rst:32 60f6edb527ee49f1935786a1f19697cb\nmsgid \":meth:`Annot.set_irt_xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:32 fe64d8f927974fa7be28efe034d209b8\nmsgid \"define the annotation to being \\\"In Response To\\\"\"\nmsgstr \"アノテーションを「応答対象」として定義します\"\n\n#: ../../annot.rst:33 efcba97648754ee0b6f2bf66c5fb7b3b\nmsgid \":meth:`Annot.set_name`\"\nmsgstr \"\"\n\n#: ../../annot.rst:33 f1f066d0c2da4d5f93f7b21c9e06512b\nmsgid \"set annotation's name field\"\nmsgstr \"アノテーションの名前フィールドを設定します\"\n\n#: ../../annot.rst:34 ../../annot.rst:342 068e0ee638a844e4b73d54c8713fd9bb\n#: 444417b076ed4a7f9938de802c9c8687\nmsgid \":meth:`Annot.set_oc`\"\nmsgstr \"\"\n\n#: ../../annot.rst:34 2afdd097e4904b54a8f1ea48f5b61be3\nmsgid \"set :data:`xref` to an :data:`OCG` / :data:`OCMD`\"\nmsgstr \":data:`xref` を :data:`OCG` または :data:`OCMD` に設定します。\"\n\n#: ../../annot.rst:35 c399de4849964e058e1637e53fdef2f9\nmsgid \":meth:`Annot.set_opacity`\"\nmsgstr \"\"\n\n#: ../../annot.rst:35 fff897c6b9cd4cf7bfd2472ea748ca06\nmsgid \"change transparency\"\nmsgstr \"透明度を変更します\"\n\n#: ../../annot.rst:36 d97cf692893c4fe7a6b799f4897c0aef\nmsgid \":meth:`Annot.set_open`\"\nmsgstr \"\"\n\n#: ../../annot.rst:36 75aaff0f9c3c458ab962d5b77a5d79d3\nmsgid \"open / close annotation or its Popup\"\nmsgstr \"アノテーションまたはそのポップアップを開く/閉じる\"\n\n#: ../../annot.rst:37 39f62e91ffef48ce9321e816caa20faa\nmsgid \":meth:`Annot.set_popup`\"\nmsgstr \"\"\n\n#: ../../annot.rst:37 a674eec367f341508c884d315088746a\nmsgid \"create a Popup for the annotation\"\nmsgstr \"アノテーションのためのポップアップを作成します\"\n\n#: ../../annot.rst:38 ../../annot.rst:340 305b0c54c12a450e8f06569799bb8a9f\n#: f592c57486d9486c86df308aa89526da\nmsgid \":meth:`Annot.set_rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:38 26f28928df154a75b841a456bdfdbf0d\nmsgid \"change annotation rectangle\"\nmsgstr \"アノテーションの長方形を変更します\"\n\n#: ../../annot.rst:39 de6a1b1b820b471b86603c34dea03532\nmsgid \":meth:`Annot.set_rotation`\"\nmsgstr \"\"\n\n#: ../../annot.rst:39 9acc32b08f1d4f599b3735e31324426f\nmsgid \"change rotation\"\nmsgstr \"回転を変更します\"\n\n#: ../../annot.rst:40 ../../annot.rst:343 18be6c4fae4e4cccb293fd8e12521dae\n#: 5200f1161df84772b72d390ec55d63cc\nmsgid \":meth:`Annot.update_file`\"\nmsgstr \"\"\n\n#: ../../annot.rst:40 c1b5d04cd03e4575a6d8bc9e47a2ac7f\nmsgid \"update attached file content\"\nmsgstr \"添付ファイルの内容を更新します\"\n\n#: ../../annot.rst:41 736a77ca795b4bffab978f162c15c221\nmsgid \":meth:`Annot.update`\"\nmsgstr \"\"\n\n#: ../../annot.rst:41 53fe58b99d874419bf45e91f443bea49\nmsgid \"apply accumulated annot changes\"\nmsgstr \"蓄積されたアノテーションの変更を適用します\"\n\n#: ../../annot.rst:42 076fef78de8747f98f8de5614822a3a3\nmsgid \":attr:`Annot.blendmode`\"\nmsgstr \"\"\n\n#: ../../annot.rst:42 3663d5144b7e4772a20a3ab76b0b7378\nmsgid \"annotation BlendMode\"\nmsgstr \"アノテーションのブレンドモード\"\n\n#: ../../annot.rst:43 209656247f2147b79d61220568d6e982\nmsgid \":attr:`Annot.border`\"\nmsgstr \"\"\n\n#: ../../annot.rst:43 cd995c15bfff4706a84f1d0deeef716c\nmsgid \"border details\"\nmsgstr \"境界線の詳細\"\n\n#: ../../annot.rst:44 a5a847e7aa1e4a66a59312e3ad69222e\nmsgid \":attr:`Annot.colors`\"\nmsgstr \"\"\n\n#: ../../annot.rst:44 7b16476edb2c47ee929046394941f61e\nmsgid \"border / background and fill colors\"\nmsgstr \"境界線/背景および塗りつぶしの色\"\n\n#: ../../annot.rst:45 c79db9da10a34adf8724954ae760d148\nmsgid \":attr:`Annot.file_info`\"\nmsgstr \"\"\n\n#: ../../annot.rst:45 5e6d650320a44ec89edde9ad8443d028\nmsgid \"get attached file information\"\nmsgstr \"添付ファイル情報を取得します\"\n\n#: ../../annot.rst:46 830bf8e01251454db4eff541902734e7\nmsgid \":attr:`Annot.flags`\"\nmsgstr \"\"\n\n#: ../../annot.rst:46 d8e2f38116e34d6b8bcc0e11a02f64c4\nmsgid \"annotation flags\"\nmsgstr \"アノテーションフラグ\"\n\n#: ../../annot.rst:47 427dbbb309334a4e938d8526af8aedd7\nmsgid \":attr:`Annot.has_popup`\"\nmsgstr \"\"\n\n#: ../../annot.rst:47 60549aa88002459b888f805a2649e95e\nmsgid \"whether annotation has a Popup\"\nmsgstr \"アノテーションにポップアップがあるかどうか\"\n\n#: ../../annot.rst:48 91cb2647177c40108aa8a389fbe4baba\nmsgid \":attr:`Annot.irt_xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:48 4b1a08935c844e1b94fd19e67c73c4bf\nmsgid \"annotation to which this one responds\"\nmsgstr \"このアノテーションへの応答としてのアノテーション\"\n\n#: ../../annot.rst:49 c80c1d9523e54c13bf015a7802006f46\nmsgid \":attr:`Annot.info`\"\nmsgstr \"\"\n\n#: ../../annot.rst:49 e24c29731fb9426296860ef9e14c70f4\nmsgid \"various information\"\nmsgstr \"さまざまな情報\"\n\n#: ../../annot.rst:50 9b1bc0b4f5604360a0fb530ee5571f6f\nmsgid \":attr:`Annot.is_open`\"\nmsgstr \"\"\n\n#: ../../annot.rst:50 76000b5c78d64a51b15f2dfb48416053\nmsgid \"whether annotation or its Popup is open\"\nmsgstr \"アノテーションまたはそのポップアップが開いているかどうか\"\n\n#: ../../annot.rst:51 c908f9af6c5e4097b190ab575189cc0e\nmsgid \":attr:`Annot.line_ends`\"\nmsgstr \"\"\n\n#: ../../annot.rst:51 5b4b1ee3f3ae4f66af35ac09445805c4\nmsgid \"start / end appearance of line-type annotations\"\nmsgstr \"線タイプのアノテーションの始点/終点の外観\"\n\n#: ../../annot.rst:52 270077d780344f6c94f61715f13de4c2\nmsgid \":attr:`Annot.next`\"\nmsgstr \"\"\n\n#: ../../annot.rst:52 0dd927ea19014ab0ab931ee426aa46a2\nmsgid \"link to the next annotation\"\nmsgstr \"次のアノテーションへのリンク\"\n\n#: ../../annot.rst:53 0642e6954b8f41758e18c9fec902315c\nmsgid \":attr:`Annot.opacity`\"\nmsgstr \"\"\n\n#: ../../annot.rst:53 55103257955240a6b3c311e8e1f97f3c\nmsgid \"the annot's transparency\"\nmsgstr \"アノテーションの透明度\"\n\n#: ../../annot.rst:54 7528c54e1c664627851d592e77e4359b\nmsgid \":attr:`Annot.parent`\"\nmsgstr \"\"\n\n#: ../../annot.rst:54 d12a83a84aea44868a11feca2fd75f9e\nmsgid \"page object of the annotation\"\nmsgstr \"アノテーションのページオブジェクト\"\n\n#: ../../annot.rst:55 17d31eb890f346608a29bac66b130ede\nmsgid \":attr:`Annot.popup_rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:55 e67d5b1efe1a49f8824bf40d6af292e8\nmsgid \"rectangle of the annotation's Popup\"\nmsgstr \"アノテーションのポップアップの長方形\"\n\n#: ../../annot.rst:56 f5012088621c45f4a0cfa4ff69b400c8\nmsgid \":attr:`Annot.popup_xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:56 3c9f31c943c04997b05236036e58e2a7\nmsgid \"the PDF :data:`xref` number of the annotation's Popup\"\nmsgstr \"アノテーションのポップアップのPDF :data:`xref` 番号\"\n\n#: ../../annot.rst:57 b0aaf4fc5d1d46a69cbca9c8576c4dff\nmsgid \":attr:`Annot.rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:57 a3afa859fcc54f03b9928dd3e3b37411\nmsgid \"rectangle containing the annotation\"\nmsgstr \"アノテーションを含む長方形\"\n\n#: ../../annot.rst:58 e5405a3d8d6c48e3b0ba2375b00d54fc\nmsgid \":attr:`Annot.type`\"\nmsgstr \"\"\n\n#: ../../annot.rst:58 49ea84134cbd4fcfa71613fdc7c994d4\nmsgid \"type of the annotation\"\nmsgstr \"アノテーションのタイプ\"\n\n#: ../../annot.rst:59 aedf999133ed4add859f5f25fcfd9c0a\nmsgid \":attr:`Annot.vertices`\"\nmsgstr \"\"\n\n#: ../../annot.rst:59 0328a5222a444a84b329ee20a13d1815\nmsgid \"point coordinates of Polygons, PolyLines, etc.\"\nmsgstr \"ポリゴン、ポリラインなどの点の座標\"\n\n#: ../../annot.rst:60 593f8d9df1724b5abbabd4b0fb42cb5f\nmsgid \":attr:`Annot.xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:60 73d760603078437db968d81892fe5450\nmsgid \"the PDF :data:`xref` number\"\nmsgstr \"PDF :data:`xref` 番号\"\n\n#: ../../annot.rst:63 df3b29896fc84aa687b9b3d812b47830\nmsgid \"**Class API**\"\nmsgstr \" **APIクラス** \"\n\n#: ../../annot.rst:75 b763b56670344531ae43994d27d0e054\nmsgid \"Changed in v1.19.2: added support of dpi parameter.\"\nmsgstr \"v1.19.2で変更: dpiパラメータのサポートが追加されました。\"\n\n#: ../../annot.rst:77 571f3475af9d4fd8af0faef1dae8b761\nmsgid \"\"\n\"Creates a pixmap from the annotation as it appears on the page in \"\n\"untransformed coordinates. The pixmap's :ref:`IRect` equals \"\n\"*Annot.rect.irect* (see below). **All parameters are keyword only.**\"\nmsgstr \"\"\n\"変換されていない座標でページ上に表示される注釈からピクスマップを作成します。ピクスマップの :ref:`IRect` は \"\n\"*Annot.rect.irect* と同じです（以下を参照）。 **すべてのパラメータはキーワード専用です。** \"\n\n#: ../../annot.rst 038416b4a91041e89e078df4fe4f5636\n#: 046b68e35745422e8e27b6ad4743720b 0ef49f86e0bd43f78e79e32e94eeea45\n#: 176c3a7acc6e46d38ef37bbfe97eabda 1795f42bf0b242078204d40d7a212c9a\n#: 2ab60eb3db5f4b3594f30a2bb7fd5444 388ae783a9ec418581e0f622c2641963\n#: 43c0bbc7ec774e96973a8f08c6370ebf 4e661fceb8be4c56850376cc43c38594\n#: 5327b6738ac2466a95ae4ef2989536c3 7698812a2a694b63b8da213e56c66c7e\n#: a57f1370f9ac44c2b28c69413752355b a97c7424f15243ca9fa1102ea36941f0\n#: bff13711337448f7809f30648c7765cd c8747aff1faa43f59b605c163d80ed7a\n#: d304c87c1b314f8f8d8449beb2cb9f43 e366806d4cdc4805a5cf6e6605d4c7ab\n#: e6d90ec622494f2cad21e1c4990e3a26 f73c89ed9881402ba2bd06564113f2e8\n#: fe526c08b06a4286849cdeea133c925d\nmsgid \"Parameters\"\nmsgstr \"パラメータ\"\n\n#: ../../annot.rst:79 4ea40779573a4cd48d2f0ca41a27b6cb\nmsgid \"a matrix to be used for image creation. Default is :ref:`Identity`.\"\nmsgstr \"画像の作成に使用される行列。デフォルトは :ref:`Identity` です。\"\n\n#: ../../annot.rst:81 1ceeea87c25445779a772f81c247bf10\nmsgid \"\"\n\"(new in v1.19.2) desired resolution in dots per inch. If not `None`, the \"\n\"matrix parameter is ignored.\"\nmsgstr \"（v1.19.2で新規追加）インチあたりのドット数で指定された解像度。 `None` でない場合、matrixパラメータは無視されます。\"\n\n#: ../../annot.rst:83 17577d5328264f3c8b2c93127b76cb6c\nmsgid \"a colorspace to be used for image creation. Default is ``pymupdf.csRGB``.\"\nmsgstr \"画像の作成に使用されるカラースペース。デフォルトは ``pymupdf.csRGB`` です。\"\n\n#: ../../annot.rst:86 93850b04eff54b39a748a09ca5d3e6bd\nmsgid \"whether to include transparency information. Default is ``False``.\"\nmsgstr \"透明情報を含めるかどうか。デフォルトは ``False`` です。\"\n\n#: ../../annot.rst 089309c51cd74976a42c4fcddda08a0a\n#: 09996d0975d243b1bc59b758b7d44173 1b331e1086824733a78f979f849d4845\n#: 4817d4a35c28463eadae53476e0fd0d5 4b59e1c18c4147e69674c7d1e86501d1\n#: 4c64d5922d9847968b2eeaee6487d0d0 4df6734c085c4a6ba495179996cfe92c\n#: 6347f866f7334ddda019820946166705 67048e418fbe44a79f9f63c0d53cb3a5\n#: 7da6735c6b7f428e9eef30245825960b 7e4ad8f3110c429ea89f047da218ee26\n#: 7f141e9ca331471ba531fcb59d32b10d 90d37be980f143b8aa9b4c16f83f6c90\n#: a74cb6e028054b5abf3bcf4af3e18ad5 a838020417bb45188717e971f12c4b8f\n#: a8439c00be7b4164a1bbeae31ecffb57 a88e7e1341604dbf90a4215903761bf1\n#: b193bdba031541f882f6d4d77564f78c bad1047750b244bca5505f7e797508bc\n#: d5d3fd4c788c48d6a3ad00aa4327e554 dc6f3b8d0e814a898c59d6e18c7b6fac\n#: ddc5fc79a0cd4e73a90a35b7de615f40 e556cbfd31a6417f8e4aab208b84c15a\n#: f867cc47820b4df6923b1b5b90969f1b\nmsgid \"Return type\"\nmsgstr \"戻り値の型\"\n\n#: ../../annot.rst:88 4081b82925b34d7aa9202a29b34e6645\nmsgid \":ref:`Pixmap`\"\nmsgstr \"\"\n\n#: ../../annot.rst:92 b9b41dd1363b465fb91e965b05c005a3\nmsgid \"\"\n\"If the annotation has just been created or modified, you should \"\n\":meth:`Document.reload_page` the page first via `page = \"\n\"doc.reload_page(page)`.\"\nmsgstr \"\"\n\"注釈が作成または変更されたばかりの場合、まず ``page = doc.reload_page(page)`` \"\n\"を使用してページを再読み込みする必要があります。\"\n\n#: ../../annot.rst:94 968363fd034a4b84834bfe008fd58160\nmsgid \"\"\n\"The pixmap will have *\\\"premultiplied\\\"* pixels if `alpha=True`. To learn\"\n\" about some background, e.g. look for \\\"Premultiplied alpha\\\" `in this \"\n\"online glossary \"\n\"<https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\"\nmsgstr \"\"\n\n#: ../../annot.rst:112 ../../annot.rst:133 059d5413f3154aaa8134479d9629d7da\n#: 5b109c06581d4245b9034c003ef2e32f\nmsgid \"New in 1.18.0\"\nmsgstr \"1.18.0 で新たに追加\"\n\n#: ../../annot.rst:114 70fc1c944cd84ce18b5f51c59bbb47f0\nmsgid \"\"\n\"Retrieves the content of the annotation in a variety of formats -- much \"\n\"like the same method for :ref:`Page`.. This currently only delivers \"\n\"relevant data for annotation types 'FreeText' and 'Stamp'. Other types \"\n\"return an empty string (or equivalent objects).\"\nmsgstr \"\"\n\"さまざまなフォーマットで注釈の内容を取得します - これは :ref:`Page` \"\n\"の同じメソッドのように動作します。現在、これはアノテーションタイプ「FreeText」と「Stamp」に関連するデータのみを提供します。他の種類は空の文字列（または同等のオブジェクト）を返します。\"\n\n#: ../../annot.rst:116 4f2629a0de0d499f8b80783953ee846e\nmsgid \"\"\n\"(positional only) the desired format - one of the following values. \"\n\"Please note that this method works exactly like the same-named method of \"\n\":ref:`Page`.  * \\\"text\\\" -- :meth:`TextPage.extractTEXT`, default * \"\n\"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS` * \\\"words\\\" -- \"\n\":meth:`TextPage.extractWORDS` * \\\"html\\\" -- :meth:`TextPage.extractHTML` \"\n\"* \\\"xhtml\\\" -- :meth:`TextPage.extractXHTML` * \\\"xml\\\" -- \"\n\":meth:`TextPage.extractXML` * \\\"dict\\\" -- :meth:`TextPage.extractDICT` * \"\n\"\\\"json\\\" -- :meth:`TextPage.extractJSON` * \\\"rawdict\\\" -- \"\n\":meth:`TextPage.extractRAWDICT`\"\nmsgstr \"\"\n\n#: ../../annot.rst:116 f5480fbc3f3f42fba82218a8e4aec39e\nmsgid \"\"\n\"(positional only) the desired format - one of the following values. \"\n\"Please note that this method works exactly like the same-named method of \"\n\":ref:`Page`.\"\nmsgstr \"\"\n\"(位置指定のみ) 望ましいフォーマット - 以下のいずれかの値の1つです。このメソッドは、:ref:`Page` \"\n\"の同名のメソッドとまったく同じように動作することに注意してください。\"\n\n#: ../../annot.rst:118 72a5b0cb198a4de4a1b5bd8012921a2d\nmsgid \"\\\"text\\\" -- :meth:`TextPage.extractTEXT`, default\"\nmsgstr \"\\\"text\\\" -- :meth:`TextPage.extractTEXT`、デフォルト\"\n\n#: ../../annot.rst:119 a0de89ee87384b559b91cb65e53fd4fe\nmsgid \"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS`\"\nmsgstr \"\"\n\n#: ../../annot.rst:120 abb67ab204e8498a82f39f7786634fa3\nmsgid \"\\\"words\\\" -- :meth:`TextPage.extractWORDS`\"\nmsgstr \"\"\n\n#: ../../annot.rst:121 2a65cab359de401d84fb6c06d18af7fe\nmsgid \"\\\"html\\\" -- :meth:`TextPage.extractHTML`\"\nmsgstr \"\"\n\n#: ../../annot.rst:122 ebb1a0a333b94886a085c62c2910b11b\nmsgid \"\\\"xhtml\\\" -- :meth:`TextPage.extractXHTML`\"\nmsgstr \"\"\n\n#: ../../annot.rst:123 039f6bd299a1459984f1378d7506db1d\nmsgid \"\\\"xml\\\" -- :meth:`TextPage.extractXML`\"\nmsgstr \"\"\n\n#: ../../annot.rst:124 def0587d2e904e678a48944fd55d8845\nmsgid \"\\\"dict\\\" -- :meth:`TextPage.extractDICT`\"\nmsgstr \"\"\n\n#: ../../annot.rst:125 9d446d90b12e480186eb0f5d4d6a88ca\nmsgid \"\\\"json\\\" -- :meth:`TextPage.extractJSON`\"\nmsgstr \"\"\n\n#: ../../annot.rst:126 ba83222452844c0280bc4ca743ec52d2\nmsgid \"\\\"rawdict\\\" -- :meth:`TextPage.extractRAWDICT`\"\nmsgstr \"\"\n\n#: ../../annot.rst:128 fc5b291ff14745a4acd435eba57c0ee4\nmsgid \"\"\n\"(keyword only) restrict the extraction to this area. Should hardly ever \"\n\"be required, defaults to :attr:`Annot.rect`.\"\nmsgstr \"(キーワードのみ) このエリアに抽出を制限します。ほとんど必要ない場合がほとんどで、デフォルトは :attr:`Annot.rect` です。\"\n\n#: ../../annot.rst:129 58a7b13ec10244cab579c577a4a02451\nmsgid \"\"\n\"(keyword only) control the amount of data returned. Defaults to simple \"\n\"text extraction.\"\nmsgstr \"(キーワードのみ) 返されるデータの量を制御します。単純なテキスト抽出がデフォルトです。\"\n\n#: ../../annot.rst:135 abea461b229f40449176733f81fe3e1f\nmsgid \"\"\n\"Return the annotation text. Mostly (except line breaks) equal to \"\n\":meth:`Annot.get_text` with the \\\"text\\\" option.\"\nmsgstr \"注釈のテキストを返します。主に（改行を除く）「text」オプションを使用した :meth:`Annot.get_text` と同等です\"\n\n#: ../../annot.rst:137 7769e9ff53bb477581a82b545145ed52\nmsgid \"the area to consider, defaults to :attr:`Annot.rect`.\"\nmsgstr \"rect (rect-like) – 考慮する領域、デフォルトは :attr:`Annot.rect` です。\"\n\n#: ../../annot.rst:142 2e28ab6b2bd740c788a328a8a392b3d3\n#, fuzzy\nmsgid \"Create a :ref:`TextPage` for the annotation.\"\nmsgstr \"アノテーションのためのポップアップを作成します\"\n\n#: ../../annot.rst:144 ec86c28fbc9c4ea5a4520e3182ebac54\nmsgid \"\"\n\"indicator bits controlling the content available for subsequent text \"\n\"extractions and searches -- see the parameter of :meth:`Annot.get_text`.\"\nmsgstr \"\"\n\"後続のテキスト抽出や検索に利用可能なコンテンツを制御する指標ビット --  :meth:`Annot.get_text` \"\n\"のパラメータを参照してください。\"\n\n#: ../../annot.rst:146 f524fdc0ad6649eabe0dcea86d45490d\nmsgid \"restrict extracted text to this area.\"\nmsgstr \"抽出されるテキストをこのエリアに制限します。\"\n\n#: ../../annot.rst 00ab1155c33d4b8b909387ee865f0f14\n#: 054667c67ee948229ce41dcc4618fb84 70e6a4c25ac54573a0e41c8e5ca39783\n#: 75932b217be7487a9362d25abfb1105c a5e875b7000f42ec9309633efaa12429\n#: c194084f626c4b5799f1d232a00741a2 ffd675b9852a4f828c4dfe677c57a2bf\nmsgid \"Returns\"\nmsgstr \"戻り値\"\n\n#: ../../annot.rst:148 195337666ae04da792bf99b2e5fc7381\nmsgid \":ref:`TextPage`\"\nmsgstr \"\"\n\n#: ../../annot.rst:150 c08b99010b1b4e45886ecf4295e20ea1\nmsgid \"|history_begin|\"\nmsgstr \"\"\n\n#: ../../annot.rst:152 b9da3f595018401c8b8eeb0c1529cca7\nmsgid \"v1.25.5: fixed `clip` arg.\"\nmsgstr \"\"\n\n#: ../../annot.rst:154 0201b53debf84074b8cde915dfcee8f4\nmsgid \"|history_end|\"\nmsgstr \"\"\n\n#: ../../annot.rst:158 7980023e59354afead5f160d58e260cb\nmsgid \"Changed in version 1.16.10\"\nmsgstr \"バージョン 1.16.10 で変更\"\n\n#: ../../annot.rst:160 0b5d367dc98e4a3a9b3fe1c292ce8cb6\nmsgid \"\"\n\"Changes annotation properties. These include dates, contents, subject and\"\n\" author (title). Changes for *name* and *id* will be ignored. The update \"\n\"happens selectively: To leave a property unchanged, set it to ``None``. \"\n\"To delete existing data, use an empty string.\"\nmsgstr \"\"\n\"注釈のプロパティを変更します。これには日付、内容、題名、および著者（タイトル）が含まれます。*名前* と *ID* \"\n\"の変更は無視されます。更新は選択的に行われます：プロパティを変更しない場合は、それを ``None`` \"\n\"に設定します。既存のデータを削除するには、空の文字列を使用します。\"\n\n#: ../../annot.rst:162 82ce1316fe354b898446a0cf7a1713b5\nmsgid \"\"\n\"a dictionary compatible with the *info* property (see below). All entries\"\n\" must be strings. If this argument is not a dictionary, the other \"\n\"arguments are used instead -- else they are ignored.\"\nmsgstr \"\"\n\"*info* \"\n\"プロパティと互換性のある辞書（以下参照）。すべてのエントリは文字列である必要があります。この引数が辞書でない場合、他の引数が代わりに使用されます。それ以外の場合、無視されます。\"\n\n#: ../../annot.rst:163 ../../annot.rst:164 ../../annot.rst:167\n#: 83ea81f2fcaf4733afe8ff369d458b6f 86f02eb815724a3a9d24dd57c593a1a3\n#: c5a737145dcf4d738178459172d94c07\nmsgid \"*(new in v1.16.10)* see description in :attr:`info`.\"\nmsgstr \"*（v1.16.10 で新規追加）* :attr:`info` の説明を参照してください。\"\n\n#: ../../annot.rst:165 5b9616a7ad9147aa931d66313938ba67\nmsgid \"\"\n\"*(new in v1.16.10)* date of annot creation. If given, should be in PDF \"\n\"datetime format.\"\nmsgstr \"*（v1.16.10 で新規追加）* 注釈の作成日。指定する場合、PDF 日時形式である必要があります。\"\n\n#: ../../annot.rst:166 3764dd0b660a48ecba7d241ddd0c78ef\nmsgid \"\"\n\"*(new in v1.16.10)* date of last modification. If given, should be in PDF\"\n\" datetime format.\"\nmsgstr \"*（v1.16.10 で新規追加）* 最終変更日。指定する場合、PDF 日時形式である必要があります。\"\n\n#: ../../annot.rst:171 e43517d418724f92aa471da27a597d2b\nmsgid \"\"\n\"Sets an annotation's line ending styles. Each of these annotation types \"\n\"is defined by a list of points which are connected by lines. The symbol \"\n\"identified by *start* is attached to the first point, and *end* to the \"\n\"last point of this list. For unsupported annotation types, a no-operation\"\n\" with a warning message results.\"\nmsgstr \"\"\n\"注釈の線終端スタイルを設定します。これらの注釈タイプの各々は、線で接続された点のリストによって定義されています。*start* \"\n\"で指定されたシンボルは、最初の点に、*end* \"\n\"はこのリストの最後の点に取り付けられます。サポートされていない注釈タイプの場合、警告メッセージとともに無操作となります。\"\n\n#: ../../annot.rst:175 c6f37bfe8f864b7aa70a6677d903fbdc\nmsgid \"\"\n\"Some symbols have an interior area (diamonds, circles, squares, etc.). \"\n\"These areas are filled with the fill color or the stroke color, depending\"\n\" on the annotation type.\"\nmsgstr \"\"\n\n#: ../../annot.rst:177 35d6ef1a79c74b06ab0a9dcf482f9a65\nmsgid \"The symbol number for the first point.\"\nmsgstr \"最初の点のシンボル番号。\"\n\n#: ../../annot.rst:178 458ad87b80944b07b309331fa16a70a2\nmsgid \"The symbol number for the last point.\"\nmsgstr \"最後の点のシンボル番号。\"\n\n#: ../../annot.rst:182 4fed90be4a2f4f6eb36e2d7f41f31319\nmsgid \"\"\n\"Set the annotation's visibility using PDF optional content mechanisms. \"\n\"This visibility is controlled by the user interface of supporting PDF \"\n\"viewers. It is independent from other attributes like \"\n\":attr:`Annot.flags`.\"\nmsgstr \"\"\n\"PDFのオプションコンテンツメカニズムを使用して、注釈の表示/非表示を設定します。この表示は、サポートするPDFビューアのユーザーインターフェースによって制御されます。:attr:`Annot.flags`\"\n\" のような他の属性とは独立しています。\"\n\n#: ../../annot.rst:184 613a0a96a3a548efb40200791489f4fd\nmsgid \"\"\n\"the :data:`xref` of an optional contents group (OCG or OCMD). Any \"\n\"previous xref will be overwritten. If zero, a previous entry will be \"\n\"removed. An exception occurs if the xref is not zero and does not point \"\n\"to a valid PDF object.\"\nmsgstr \"\"\n\"オプションコンテンツグループ（OCGまたはOCMD）のxref。以前の :data:`xref` \"\n\"は上書きされます。ゼロの場合、以前のエントリが削除されます。xrefがゼロでない場合かつ有効なPDFオブジェクトを指していない場合、例外が発生します。\"\n\n#: ../../annot.rst:186 55d26af3928947678aaeaa3e33027dcc\nmsgid \"This does **not require executing** :meth:`Annot.update` to take effect.\"\nmsgstr \"これは :meth:`Annot.update` の **実行を必要としません。** \"\n\n#: ../../annot.rst:190 7e388a9f2b75447d8394d6d36c4a1bf8\nmsgid \"\"\n\"Return the :data:`xref` of an optional content object, or zero if there \"\n\"is none.\"\nmsgstr \"オプションコンテンツオブジェクトの :data:`xref` 、または存在しない場合はゼロを返します。\"\n\n#: ../../annot.rst:192 e8ec795f695645628c3efbfd3915cec6\nmsgid \"zero or the xref of an OCG (or OCMD).\"\nmsgstr \"ゼロまたはOCG（またはOCMD）のxref。\"\n\n#: ../../annot.rst:197 b2f92c06a6294be3bfd5ec01d0e09768\nmsgid \"New in v1.19.3\"\nmsgstr \"v1.19.3 で新規追加\"\n\n#: ../../annot.rst:199 ad11cb50eb7b4800aec2e137d3accb71\nmsgid \"Set annotation to be \\\"In Response To\\\" another one.\"\nmsgstr \"注釈を別の注釈への「応答として」設定します。\"\n\n#: ../../annot.rst:201 7b8bf875b3bc4826aa14c687fb8cd5d0\nmsgid \"\"\n\"The :data:`xref` of another annotation.  .. note:: Must refer to an \"\n\"existing annotation on this page. Setting this property requires no \"\n\"subsequent `update()`.\"\nmsgstr \"\"\n\n#: ../../annot.rst:201 9e9d820407064710884e6a66aa7f7f55\nmsgid \"The :data:`xref` of another annotation.\"\nmsgstr \"別の注釈の :data:`xref` 。\"\n\n#: ../../annot.rst:203 14f320a016824d5198f1d52227d0a926\nmsgid \"\"\n\"Must refer to an existing annotation on this page. Setting this property \"\n\"requires no subsequent `update()`.\"\nmsgstr \"このプロパティを設定するには、このページの既存の注釈を参照する必要があります。このプロパティを設定する際、後続の `update()` は不要です。\"\n\n#: ../../annot.rst:208 ../../annot.rst:217 ../../annot.rst:237\n#: 481fa7ca48f54e5598a63178e50438ab a466079f958942378ec240211f031c16\n#: f9ec8616d1df4181aa40e2958d601327\nmsgid \"New in v1.18.4\"\nmsgstr \"v1.18.4 で新たに追加\"\n\n#: ../../annot.rst:210 67cc9664fad84f49a83ba297112ca110\nmsgid \"\"\n\"Set the annotation's Popup annotation to open or closed -- **or** the \"\n\"annotation itself, if its type is 'Text' (\\\"sticky note\\\").\"\nmsgstr \"注釈のポップアップ注釈を開いた状態または閉じた状態に設定します – *または* その注釈自体、そのタイプが 'Text'（「付箋」）の場合。\"\n\n#: ../../annot.rst:212 1504f1da1fda45fea8f19f45ffc20d4f\nmsgid \"the desired open state.\"\nmsgstr \"望ましい開いた状態。\"\n\n#: ../../annot.rst:219 c089225b48284823a9b7556a44262d27\nmsgid \"\"\n\"Create a Popup annotation for the annotation and specify its rectangle. \"\n\"If the Popup already exists, only its rectangle is updated.\"\nmsgstr \"注釈のためのポップアップ注釈を作成し、その矩形を指定します。ポップアップが既に存在する場合、その矩形のみが更新されます。\"\n\n#: ../../annot.rst:221 c34e5022b5454828b58718e9dcbc45fe\nmsgid \"the desired rectangle.\"\nmsgstr \"望ましい矩形。\"\n\n#: ../../annot.rst:227 facb954df51640a7ae7fd3710883dc98\nmsgid \"\"\n\"Set the annotation's transparency. Opacity can also be set in \"\n\":meth:`Annot.update`.\"\nmsgstr \"注釈の透明度を設定します。透明度は :meth:`Annot.update` でも設定できます。\"\n\n#: ../../annot.rst:229 d7989596080e46c987557189dc9c25ff\nmsgid \"\"\n\"a float in range *[0, 1]*. Any value outside is assumed to be 1. E.g. a \"\n\"value of 0.5 sets the transparency to 50%.\"\nmsgstr \"*[0、1]* の範囲内の浮動小数点数。範囲外の値は 1 と見なされます。例：0.5 の値は透明度を 50% に設定します。\"\n\n#: ../../annot.rst:231 8cd9cbde74a9498aa0f39f1aceeb59c0\nmsgid \"Three overlapping 'Circle' annotations with each opacity set to 0.5:\"\nmsgstr \"透明度がそれぞれ 0.5 に設定された3つの重なる「Circle」注釈：\"\n\n#: ../../annot.rst:239 78ea45fdfd8c457285f97ad98ced56cb\nmsgid \"\"\n\"The annotation's blend mode. See :ref:`AdobeManual`, page 324 for \"\n\"explanations.\"\nmsgstr \"注釈のブレンドモード。詳細については :ref:`AdobeManual` 、ページ324を参照してください。\"\n\n#: ../../annot.rst:242 30d06915799b4a4d993a5b5fca1059fe\nmsgid \"the blend mode or ``None``.\"\nmsgstr \"ブレンドモードまたは ``None`` 。\"\n\n#: ../../annot.rst:247 9dce9ac76ca040e1a31d5585a57839f6\nmsgid \"New in v1.16.14\"\nmsgstr \"v1.16.14 で新たに追加\"\n\n#: ../../annot.rst:249 dc743497d0c04f36b92127b326b52323\nmsgid \"\"\n\"Set the annotation's blend mode. See :ref:`AdobeManual`, page 324 for \"\n\"explanations. The blend mode can also be set in :meth:`Annot.update`.\"\nmsgstr \"\"\n\"注釈のブレンドモードを設定します。詳細については :ref:`AdobeManual` 、ページ324を参照してください。ブレンドモードは \"\n\":meth:`Annot.update` でも設定できます。\"\n\n#: ../../annot.rst:251 4cc8588ee3a54e0ea07306202519e692\nmsgid \"\"\n\"set the blend mode. Use :meth:`Annot.update` to reflect this in the \"\n\"visual appearance. For predefined values see :ref:`BlendModes`. Use \"\n\"`PDF_BM_Normal` to **remove** a blend mode.\"\nmsgstr \"\"\n\"ブレンドモードを設定します。視覚的な外観に反映するには :meth:`Annot.update` \"\n\"を使用します。事前定義の値についてはPDF標準のブレンドモードを参照してください。ブレンドモードを **削除する** には \"\n\"`PDF_BM_Normal` を使用します。\"\n\n#: ../../annot.rst:256 f91715c6f8dd45839dff56adcd90fe40\nmsgid \"New in version 1.16.0\"\nmsgstr \"バージョン1.16.0で新たに追加\"\n\n#: ../../annot.rst:258 63628e30584640f485f9216a26cc976e\nmsgid \"\"\n\"Change the name field of any annotation type. For 'FileAttachment' and \"\n\"'Text' annotations, this is the icon name, for 'Stamp' annotations the \"\n\"text in the stamp. The visual result (if any) depends on your PDF viewer.\"\n\" See also :ref:`mupdficons`.\"\nmsgstr \"\"\n\"すべての注釈タイプの名前フィールドを変更します。「FileAttachment」と「Text」注釈の場合、これはアイコンの名前であり、「Stamp」注釈の場合はスタンプのテキストです。視覚的な結果（ある場合）は、PDFビューアに依存します。:ref:`mupdficons`\"\n\" も参照してください。\"\n\n#: ../../annot.rst:260 c9956808cf6344fe93a68e352c078f3b\nmsgid \"the new name.\"\nmsgstr \"新しい名前。\"\n\n#: ../../annot.rst:262 77d72775e0d649e0aee5cd748dcf35c5\nmsgid \"\"\n\"If you set the name of a 'Stamp' annotation, then this will **not \"\n\"change** the rectangle, nor will the text be layouted in any way. If you \"\n\"choose a standard text from :ref:`StampIcons` (the **exact** name piece \"\n\"after `\\\"STAMP_\\\"`), you should receive the original layout. An \"\n\"**arbitrary text** will not be changed to upper case, but be written in \"\n\"font \\\"Times-Bold\\\" as is, horizontally centered in **one line** and be \"\n\"shortened to fit. To get your text fully displayed, its length using \"\n\":data:`fontsize` 20 must not exceed 190 points. So please make sure that \"\n\"the following inequality is true: `pymupdf.get_text_length(text, \"\n\"fontname=\\\"tibo\\\", fontsize=20) <= 190`.\"\nmsgstr \"\"\n\"「Stamp」注釈の名前を設定した場合、これは矩形を **変更せず** 、テキストもレイアウトされません。:ref:`StampIcons` \"\n\"から標準のテキストを選択すると（ `\\\"STAMP_\\\"` の後の **正確な** 名前部分）、元のレイアウトが表示されるはずです。**任意** \"\n\"のテキストは大文字に変更されず、「Times-Bold」フォントで水平中央揃えで **1行** \"\n\"に表示され、収まるように短縮されます。テキストを完全に表示するには、フォントサイズ20を使用してのテキストの長さが190ピクセルを超えてはいけません。したがって、以下の不等式が成り立つことを確認してください:\"\n\" `pymupdf.get_text_length(text, fontname=\\\"tibo\\\", fontsize=20) <= 190` 。\"\n\n#: ../../annot.rst:266 215783824e424078a9c68252ef072b76\nmsgid \"\"\n\"Change the rectangle of an annotation. The annotation can be moved around\"\n\" and both sides of the rectangle can be independently scaled. However, \"\n\"the annotation appearance will never get rotated, flipped or sheared. \"\n\"This method only affects certain annotation types [#f2]_ and will lead to\"\n\" a message on Python's `sys.stderr` in other cases. No exception will be \"\n\"raised, but `False` will be returned.\"\nmsgstr \"\"\n\"注釈の矩形を変更します。注釈は移動し、矩形の両側を独立してスケーリングできます。ただし、注釈の外観は回転、反転、またはせん断されることはありません。このメソッドは特定の注釈タイプにのみ影響を与えます\"\n\" [#f2]_  、それ以外の場合はPythonの `sys.stderr` にメッセージが表示されます。例外は発生しませんが、`False` \"\n\"が返されます。\"\n\n#: ../../annot.rst:268 a55821d5ebaa43a79524ea735d7fce30\nmsgid \"\"\n\"the new rectangle of the annotation (finite and not empty). E.g. using a \"\n\"value of *annot.rect + (5, 5, 5, 5)* will shift the annot position 5 \"\n\"pixels to the right and downwards.\"\nmsgstr \"\"\n\"rect (rect_like) – 注釈の新しい矩形（有限で空ではない）です。たとえば、*annot.rect + (5, 5, 5, 5)* \"\n\"の値を使用すると、注釈を右に5ピクセル、下に5ピクセル移動させます。\"\n\n#: ../../annot.rst:270 58ba9ae624c649f59c822a951c81b8d9\nmsgid \"You **need not** invoke :meth:`Annot.update` for activation of the effect.\"\nmsgstr \"効果の有効化には :meth:`Annot.update` を呼び出す **必要はありません** 。\"\n\n#: ../../annot.rst:275 4182447a9b644af7b8fdaadfb8a05d32\nmsgid \"\"\n\"Set the rotation of an annotation. This rotates the annotation rectangle \"\n\"around its center point. Then a **new annotation rectangle** is \"\n\"calculated from the resulting quad.\"\nmsgstr \"注釈の回転を設定します。これにより、注釈の矩形はその中心点を中心に回転します。その後、結果の四角形から **新しい注釈の矩形** が計算されます。\"\n\n#: ../../annot.rst:277 6fc24fed55494f8fb4a955d4d8a13eba\nmsgid \"\"\n\"rotation angle in degrees. Arbitrary values are possible, but will be \"\n\"clamped to the interval `[0, 360)`.\"\nmsgstr \"度数法での回転角度。任意の値が可能ですが、区間 `[0, 360)` にクランプされます。\"\n\n#: ../../annot.rst:280 e4f887994fc5422f95d07305f9ce1cd5\nmsgid \"You **must invoke** :meth:`Annot.update` to activate the effect.\"\nmsgstr \"効果を有効にするには、:meth:`Annot.update` を **呼び出す必要があります** 。\"\n\n#: ../../annot.rst:281 708375ceb35c401f93a653d662ffa946\nmsgid \"\"\n\"For PDF_ANNOT_FREE_TEXT, only one of the values 0, 90, 180 and 270 is \"\n\"possible and will **rotate the text** inside the current rectangle (which\"\n\" remains unchanged). Other values are silently ignored and replaced by 0.\"\nmsgstr \"\"\n\"PDF_ANNOT_FREE_TEXTの場合、値0、90、180、270のいずれかの値のみが可能で、現在の矩形内の **テキストを回転させます**\"\n\" （矩形自体は変更されません）。その他の値は静かに無視され、0に置き換えられます。\"\n\n#: ../../annot.rst:282 9916c3c0474d42789055dd9fb27df6d5\nmsgid \"\"\n\"Otherwise, only the following :ref:`AnnotationTypes` can be rotated: \"\n\"'Square', 'Circle', 'Caret', 'Text', 'FileAttachment', 'Ink', 'Line', \"\n\"'Polyline', 'Polygon', and 'Stamp'. For all others the method is a no-op.\"\nmsgstr \"\"\n\"それ以外の場合、次の :ref:`AnnotationTypes` \"\n\"のみが回転できます：'Square'、'Circle'、'Caret'、'Text'、'FileAttachment'、'Ink'、'Line'、'Polyline'、'Polygon'、および'Stamp'。それ以外のすべての場合、このメソッドは無効です。\"\n\n#: ../../annot.rst:287 21f87eefce9f42cd84347e0b9f4c9750\nmsgid \"\"\n\"Changed in version 1.16.9: Allow specification without using a \"\n\"dictionary. The direct parameters are used if *border* is not a \"\n\"dictionary.\"\nmsgstr \"バージョン1.16.9で変更: 辞書を使用せずに指定を許可。*border* が辞書でない場合、直接のパラメータが使用されます。\"\n\n#: ../../annot.rst:289 a5d1d0e5012145d88adb8f0b58ec843d\nmsgid \"Changed in version 1.22.5: Support of the \\\"cloudy\\\" border effect.\"\nmsgstr \"バージョン1.22.5で変更: \\\"cloudy\\\"ボーダーエフェクトのサポート。\"\n\n#: ../../annot.rst:291 c189c32c136c4970affbad53b8a4962c\nmsgid \"\"\n\"PDF only: Change border width, dashing, style and cloud effect. See the \"\n\":attr:`Annot.border` attribute for more details.\"\nmsgstr \"\"\n\"PDFのみ: ボーダーの幅、点線、スタイル、およびクラウド効果を変更します。詳細については :attr:`Annot.border` \"\n\"属性を参照してください。\"\n\n#: ../../annot.rst:294 cd430c709f2743de8acc763ed90aa387\nmsgid \"\"\n\"a dictionary as returned by the :attr:`border` property, with keys \"\n\"*\\\"width\\\"* (*float*), *\\\"style\\\"* (*str*),  *\\\"dashes\\\"* (*sequence*) \"\n\"and *clouds* (*int*). Omitted keys will leave the resp. property \"\n\"unchanged. Set the border argument to `None` (the default) to use the \"\n\"other arguments.\"\nmsgstr \"\"\n\":attr:`border` プロパティから返されるような辞書で、キーに \"\n\"\\\"width\\\"（float）、\\\"style\\\"（str）、\\\"dashes\\\"（シーケンス）、および \"\n\"\\\"clouds\\\"（int）を持っています。省略されたキーはそれぞれのプロパティを変更しないままにします。他の引数を使用する場合、border引数を\"\n\" `None` （デフォルト）に設定します。\"\n\n#: ../../annot.rst:296 39acc9934225448197fcfd592c9d832f\nmsgid \"A non-negative value will change the border line width.\"\nmsgstr \"非負の値はボーダーの線幅を変更します。\"\n\n#: ../../annot.rst:297 a68a775771684101adfaada1b555645a\nmsgid \"A value other than `None` will change this border property.\"\nmsgstr \"`None` 以外の値はこのボーダープロパティを変更します。\"\n\n#: ../../annot.rst:298 6abbfe1e60884753b2f408c6140c1522\nmsgid \"\"\n\"All items of the sequence must be integers, otherwise the parameter is \"\n\"ignored. To remove dashing use: `dashes=[]`. If dashes is a non-empty \"\n\"sequence, \\\"style\\\" will automatically be set to \\\"D\\\" (dashed).\"\nmsgstr \"\"\n\"シーケンスのすべてのアイテムは整数である必要があり、それ以外の場合、パラメータは無視されます。点線を削除するには、`dashes=[]` \"\n\"を使用します。dashesが空でないシーケンスの場合、\\\"style\\\"は自動的に \\\"D\\\"（点線）に設定されます。\"\n\n#: ../../annot.rst:299 a14bf775a9aa4b5690dfa5d75ad9a268\nmsgid \"\"\n\"A value >= 0 will change this property. Use `clouds=0` to remove the \"\n\"cloudy appearance completely. Only annotation types 'Square', 'Circle', \"\n\"and 'Polygon' are supported with this property.\"\nmsgstr \"\"\n\"0以上の値はこのプロパティを変更します。クラウディな外観を完全に削除するには、`clouds=0` \"\n\"を使用します。このプロパティはアノテーションタイプ 'Square'、'Circle'、および 'Polygon' のみでサポートされています。\"\n\n#: ../../annot.rst:303 ef79e54d0a714869a014c9d730425b72\nmsgid \"Changes the annotation flags. Use the `|` operator to combine several.\"\nmsgstr \"注釈のフラグを変更します。複数のフラグを組み合わせるには `|` 演算子を使用します。\"\n\n#: ../../annot.rst:305 fd0aa1fe5fa54354942159d69033f3dd\nmsgid \"an integer specifying the required flags.\"\nmsgstr \"必要なフラグを指定する整数。\"\n\n#: ../../annot.rst:309 6c045aa7fffe4727b0d500917f834af7\nmsgid \"\"\n\"Changes the \\\"stroke\\\" and \\\"fill\\\" colors for supported annotation types\"\n\" -- not all annotation types accept both. **Do not use this method at all\"\n\" for FreeText annotations** because it has its special conventions to \"\n\"deal with up to three colors (border, fill, text).\"\nmsgstr \"\"\n\"サポートされている注釈タイプに対して「ストローク」と「塗りつぶし」の色を変更します – \"\n\"すべての注釈が両方を受け入れるわけではありません。FreeText注釈にはこのメソッドを一切使用しないでください\"\n\n#: ../../annot.rst:311 db7de1cdaf074887b6a5856f6edce371\nmsgid \"\"\n\"a dictionary containing color specifications. For accepted dictionary \"\n\"keys and values see below. The most practical way should be to first make\"\n\" a copy of the *colors* property and then modify this dictionary as \"\n\"required.\"\nmsgstr \"\"\n\"色の仕様を含む辞書。受け入れられる辞書のキーと値については以下を参照してください。最も実用的な方法は、まず ** \"\n\"プロパティのコピーを作成し、その後必要に応じてこの辞書を変更することです。\"\n\n#: ../../annot.rst:312 ../../annot.rst:313 75cff1ffb24c4912bfeb81a9ebd1432d\n#: ab1efc57d7bc48e98cf5e1bdb658a212\nmsgid \"see above.\"\nmsgstr \"上記を参照してください。\"\n\n#: ../../annot.rst:315 7c1a94d49e3646c1acf119c6dbd9d5d2\nmsgid \"\"\n\"To completely remove a color specification, use an empty sequence like \"\n\"`[]`. If you specify `None`, an existing specification will not be \"\n\"changed.\"\nmsgstr \"色の仕様を完全に削除するには、`[]` のような空のシーケンスを使用してください。`None` を指定した場合、既存の仕様は変更されません。\"\n\n#: ../../annot.rst:320 2a6d90dee7ce4d77b26b92943743267a\nmsgid \"New in version 1.16.12\"\nmsgstr \"バージョン1.16.12で新規追加\"\n\n#: ../../annot.rst:322 595743ee33354f6db6ea8007f5c683d9\nmsgid \"\"\n\"Delete annotations referring to this one. This includes any 'Popup' \"\n\"annotations and all annotations responding to it.\"\nmsgstr \"この注釈を参照する注釈を削除します。これには「ポップアップ」注釈とそれに応答するすべての注釈が含まれます。\"\n\n#: ../../annot.rst:336 3dd084b1ebf84cde9a0f1628888a078a\nmsgid \"\"\n\"Synchronize the appearance of an annotation with its properties after \"\n\"relevant changes.\"\nmsgstr \"関連する変更後に注釈の外観をプロパティに同期させます。\"\n\n#: ../../annot.rst:338 7fe415cd7d454f189581594f76164856\nmsgid \"You can safely **omit** this method **only** for the following changes:\"\nmsgstr \"以下の変更に関して **のみ** 、このメソッドを安全に **省略できます** :\"\n\n#: ../../annot.rst:344 fe15053758b14d7199c023e93f5fb1b5\nmsgid \":meth:`Annot.set_info` (except any changes to *\\\"content\\\"*)\"\nmsgstr \":meth:`Annot.set_info` （*「content」* 以外の変更を除く）\"\n\n#: ../../annot.rst:346 0073d1e84f5d4733b0ed896ad1863ecc\nmsgid \"\"\n\"All arguments are optional. *(Changed in v1.16.14)* Blend mode and \"\n\"opacity are applicable to **all annotation types**. The other arguments \"\n\"are mostly special use, as described below.\"\nmsgstr \"\"\n\"すべての引数はオプションです。 *(v1.16.14で変更)* ブレンドモードと不透明度は **すべての注釈タイプ** に適用されます。 \"\n\"他の引数は主に特殊な用途として、以下で説明されています。\"\n\n#: ../../annot.rst:348 f2ba4ab0eec14256874f4795f0809515\nmsgid \"\"\n\"Color specifications may be made in the usual format used in PuMuPDF as \"\n\"sequences of floats ranging from 0.0 to 1.0 (including both). The \"\n\"sequence length must be 1, 3 or 4 (supporting GRAY, RGB and CMYK \"\n\"colorspaces respectively). For GRAY, just a float is also acceptable.\"\nmsgstr \"カラーの仕様は、通常のPuMuPDFで使用される形式で指定できます。0.0から1.0までの浮動小数点数のシーケンスです（両方を含む）。シーケンスの長さは1、3、または4である必要があります（GRAY、RGB、およびCMYKのカラースペースをサポートしています）。GRAYの場合、浮動小数点数だけでも受け入れられます。\"\n\n#: ../../annot.rst:350 f3ccad414cfa4feea70d7d6d4ee37f20\nmsgid \"\"\n\"*(new in v1.16.14)* **valid for all annotation types:** change or set the\"\n\" annotation's transparency. Valid values are *0 <= opacity < 1*.\"\nmsgstr \"\"\n\"*（v1.16.14で新規）* **すべての注釈タイプに対して有効：** 注釈の透明度を変更または設定します。有効な値は *0 <= \"\n\"opacity < 1です* 。\"\n\n#: ../../annot.rst:352 04465250dcde4c4c860e257ac3e888cc\nmsgid \"\"\n\"*(new in v1.16.14)* **valid for all annotation types:** change or set the\"\n\" annotation's blend mode. For valid values see :ref:`BlendModes`.\"\nmsgstr \"\"\n\"*（v1.16.14で新規）* **すべての注釈タイプに対して有効：** \"\n\"注釈のブレンドモードを変更または設定します。有効な値についてはPDF標準のブレンドモードを参照してください。\"\n\n#: ../../annot.rst:354 9bc27aa105ae42cd82a2451d40ee6e6e\nmsgid \"change :data:`fontsize` of the text. 'FreeText' annotations only.\"\nmsgstr \"テキストのフォントサイズを変更します。 'FreeText' 注釈のみです。\"\n\n#: ../../annot.rst:356 cf2b46ce81194d3889beefcdf7c9b7bc\nmsgid \"\"\n\"change the text color. 'FreeText' annotations only. This has the same \"\n\"effect as ``border_color``. Note that the text color of rich-text \"\n\"annotations cannot be changed at all because it is set by HTML / CSS \"\n\"syntax and part of the text itself.\"\nmsgstr \"テキストの色を変更します。 'FreeText' 注釈のみです。\"\n\n#: ../../annot.rst:358 9573860e39914131a2e6b21985df1d0a\nmsgid \"\"\n\"change the border color. 'FreeText' annotations only. This has the same \"\n\"effect as ``text_color``.\"\nmsgstr \"境界線の色を変更します。 'FreeText' 注釈のみです。\"\n\n#: ../../annot.rst:360 f201d820422e410380867aef925e12c6\nmsgid \"the fill color.\"\nmsgstr \"塗りつぶしの色です。\"\n\n#: ../../annot.rst:362 51b7ae492b9d439ea63ad6e688461680\nmsgid \"\"\n\"*(new in v1.17.2)* add two diagonal lines to the annotation rectangle. \"\n\"'Redact' annotations only. If not desired, ``False`` must be specified \"\n\"even if the annotation was created with ``False``.\"\nmsgstr \"\"\n\"*（v1.17.2で新規）* 注釈の矩形に2本の対角線を追加します。 'Redact' 注釈のみです。希望しない場合、注釈が``False`` \"\n\"で作成された場合でも ``False`` を指定する必要があります。\"\n\n#: ../../annot.rst:364 ca681b7d888b4269b353a917a0251fcc\nmsgid \"\"\n\"new rotation value. Default (-1) means no change. Supports 'FreeText' and\"\n\" several other annotation types (see :meth:`Annot.set_rotation`), [#f1]_.\"\n\" Only choose 0, 90, 180, or 270 degrees for 'FreeText'. Otherwise any \"\n\"integer is acceptable.\"\nmsgstr \"\"\n\"新しい回転値。デフォルト値（-1）は変更なしを意味します。 'FreeText' \"\n\"およびいくつかの他の注釈タイプをサポートします:meth:`Annot.set_rotation` を参照） [#f1]_ 。 \"\n\"'FreeText' の場合、0、90、180、または270度を選択してください。それ以外の場合、任意の整数が受け入れられます。\"\n\n#: ../../annot.rst:368 60ab5d4e01554e09aa2155cfcf1bd6a4\nmsgid \"\"\n\"This method is the only way to change the colors of a FreeText \"\n\"annotation. You cannot use :meth:`Annot.set_colors` for this purpose. But\"\n\" be aware that for rich-text annotations, the text color is never \"\n\"changed. The text color is set by the ``text_color`` entry of the \"\n\"``info`` dictionary. This is a limitation of |MuPDF| and not a bug.\"\nmsgstr \"\"\n\"このメソッドは、FreeText注釈の色を変更する唯一の方法です。この目的には、 :meth:`Annot.set_colors()`  \"\n\"を使用することはできません。 ただし、リッチテキスト注釈の場合は注意が必要です。テキストの色は変更されず、 ``info``  辞書の  \"\n\"``text_color``  エントリによって設定されます。 これは |MuPDF| の制限であり、不具合ではありません。\"\n\n#: ../../annot.rst:370 1112033b5d6844729cb062a449ec85b1\nmsgid \"\"\n\"Using this method inside a :meth:`Page.annots` loop is **not \"\n\"recommended!** This is because most annotation updates require the owning\"\n\" page to be reloaded -- which cannot be done inside this loop. Please use\"\n\" the example coding pattern given in the documentation of this generator.\"\nmsgstr \"\"\n\":meth:`Page.annots` ループ内でこのメソッドを使用することは **お勧めしません！** \"\n\"これは、ほとんどの注釈の更新には所有ページの再読み込みが必要であり、このループ内で行うことはできないためです。このジェネレータのドキュメントで提供されている例のコーディングパターンを使用してください。\"\n\n#: ../../annot.rst:375 4a926753fff744ec9116dd6ed7183650\nmsgid \"Basic information of the annot's attached file.\"\nmsgstr \"アノットが添付されたファイルの基本情報。\"\n\n#: ../../annot.rst:378 dff1e3b1a640429fb53eddd0fa92ce69\nmsgid \"\"\n\"a dictionary with keys *filename*, *ufilename*, *desc* (description), \"\n\"*size* (uncompressed file size), *length* (compressed length) for \"\n\"FileAttachment annot types, else ``None``.\"\nmsgstr \"\"\n\"FileAttachmentアノットタイプの場合、*filename* （ファイル名）、*ufilename* \"\n\"（Unicodeファイル名）、*desc* （説明）、*size* （非圧縮ファイルサイズ）、*length* \"\n\"（圧縮長さ）のキーを持つ辞書。それ以外の場合は ``None`` 。\"\n\n#: ../../annot.rst:382 fff1e94235db41658c4a47630907af7b\nmsgid \"Returns attached file content.\"\nmsgstr \"添付ファイルの内容を返します。\"\n\n#: ../../annot.rst:385 e7858d0b8f274619a0e53226e2ad2558\nmsgid \"the content of the attached file.\"\nmsgstr \"添付ファイルの内容。\"\n\n#: ../../annot.rst:395 0a6f0f824993411db432fbc73cedbf48\nmsgid \"\"\n\"Updates the content of an attached file. All arguments are optional. No \"\n\"arguments lead to a no-op.\"\nmsgstr \"添付ファイルの内容を更新します。すべての引数はオプションです。引数が指定されない場合、操作は行われません。\"\n\n#: ../../annot.rst:397 14cfd5ce68c443c4b5706490bf7ce62c\nmsgid \"\"\n\"the new file content. Omit to only change meta-information.  *(Changed in\"\n\" version 1.14.13)* *io.BytesIO* is now also supported.\"\nmsgstr \"\"\n\n#: ../../annot.rst:397 13e705e69a1d425184d4be574725693d\nmsgid \"the new file content. Omit to only change meta-information.\"\nmsgstr \"新しいファイルの内容。メタ情報のみ変更する場合は省略します。\"\n\n#: ../../annot.rst:399 a1e92b5db60e4c4599063b1893fd8eed\nmsgid \"*(Changed in version 1.14.13)* *io.BytesIO* is now also supported.\"\nmsgstr \"*（バージョン1.14.13で変更）io.BytesIO* もサポートされるようになりました。\"\n\n#: ../../annot.rst:401 16d4a6c7354947dc9ed4a1af1e661951\nmsgid \"new filename to associate with the file.\"\nmsgstr \"ファイルに関連付ける新しいファイル名。\"\n\n#: ../../annot.rst:403 f71c9be54bb649adbc2100b1cf7793e5\nmsgid \"new unicode filename to associate with the file.\"\nmsgstr \"ファイルに関連付ける新しいUnicodeファイル名。\"\n\n#: ../../annot.rst:405 70d2cec5d76d4b4ca6ac53eb58acf503\nmsgid \"new description of the file content.\"\nmsgstr \"ファイル内容の新しい説明。\"\n\n#: ../../annot.rst:409 dfdaec12a2274c30a1f374a77b655ee8\nmsgid \"Return the embedded sound of an audio annotation.\"\nmsgstr \"オーディオアノテーションの埋め込まれた音声を返します。\"\n\n#: ../../annot.rst:412 c7fa04ae49d54d39a39b5d2245c490f0\nmsgid \"\"\n\"the sound audio file and accompanying properties. These are the possible \"\n\"dictionary keys, of which only \\\"rate\\\" and \\\"stream\\\" are always \"\n\"present.  =========== \"\n\"======================================================= Key         \"\n\"Description =========== \"\n\"======================================================= rate        \"\n\"(float, requ.) samples per second channels    (int, opt.) number of sound\"\n\" channels bps         (int, opt.) bits per sample value per channel \"\n\"encoding    (str, opt.) encoding format: Raw, Signed, muLaw, ALaw \"\n\"compression (str, opt.) name of compression filter stream      (bytes, \"\n\"requ.) the sound file content =========== \"\n\"=======================================================\"\nmsgstr \"\"\n\n#: ../../annot.rst:412 df0e243fcf034592a8492436e6e1659a\nmsgid \"\"\n\"the sound audio file and accompanying properties. These are the possible \"\n\"dictionary keys, of which only \\\"rate\\\" and \\\"stream\\\" are always \"\n\"present.\"\nmsgstr \"音声オーディオファイルと関連するプロパティ。これらは可能な辞書キーで、常に「rate」と「stream」が存在します。\"\n\n#: ../../annot.rst:415 12be1c52c4314285af838a6ce29fba9e\nmsgid \"Key\"\nmsgstr \"キー\"\n\n#: ../../annot.rst:415 2bdf4ba35cce4815a2a492cf817897c8\nmsgid \"Description\"\nmsgstr \"説明\"\n\n#: ../../annot.rst:417 0d66d09f790c4ff3bc6c27ba0d9b632a\nmsgid \"rate\"\nmsgstr \"\"\n\n#: ../../annot.rst:417 c1045c0883214be39172475f75e7f5d0\nmsgid \"(float, requ.) samples per second\"\nmsgstr \"(float, 必須) 1秒あたりのサンプル数\"\n\n#: ../../annot.rst:418 8abdaaa9d7fe44dfa74cc67416d30c2b\nmsgid \"channels\"\nmsgstr \"\"\n\n#: ../../annot.rst:418 f74b4b35e92846e28327d70e75e25b02\nmsgid \"(int, opt.) number of sound channels\"\nmsgstr \"(int, オプション) サウンドチャンネルの数\"\n\n#: ../../annot.rst:419 942b2b733eed481b9491bc82bc570e1c\nmsgid \"bps\"\nmsgstr \"\"\n\n#: ../../annot.rst:419 7be514225767447a8a8095e8df1f2bc4\nmsgid \"(int, opt.) bits per sample value per channel\"\nmsgstr \"(int, オプション) チャンネルごとのサンプル値のビット数\"\n\n#: ../../annot.rst:420 b38f02b791694df2ae7e91f5e18e4b63\nmsgid \"encoding\"\nmsgstr \"\"\n\n#: ../../annot.rst:420 73e6b25cf0da41518e6a2a8c8342f9b9\nmsgid \"(str, opt.) encoding format: Raw, Signed, muLaw, ALaw\"\nmsgstr \"(str, オプション) エンコーディング形式: Raw, Signed, muLaw, ALaw\"\n\n#: ../../annot.rst:421 1969b7bd898244968ec9e8b0ccb1bde7\nmsgid \"compression\"\nmsgstr \"\"\n\n#: ../../annot.rst:421 a89ee4a1e5ae438bb9abdf27689f1840\nmsgid \"(str, opt.) name of compression filter\"\nmsgstr \"(str, オプション) 圧縮フィルタの名前\"\n\n#: ../../annot.rst:422 8ae646c528504b2c930d6aeefa18e74b\nmsgid \"stream\"\nmsgstr \"\"\n\n#: ../../annot.rst:422 379f471934fe4d5fab7732b175a2bce2\nmsgid \"(bytes, requ.) the sound file content\"\nmsgstr \"(bytes, 必須) サウンドファイルの内容\"\n\n#: ../../annot.rst:428 04846fc70fde4de09324de235eedf132\nmsgid \"\"\n\"The annotation's transparency. If set, it is a value in range *[0, 1]*. \"\n\"The PDF default is 1. However, in an effort to tell the difference, we \"\n\"return *-1.0* if not set.\"\nmsgstr \"\"\n\"アノテーションの透明度。設定されている場合、範囲 *[0, 1]* の値です。PDFのデフォルトは1ですが、違いを示すために設定されていない場合は\"\n\" *-1.0* を返します。\"\n\n#: ../../annot.rst:434 38341cb4267e49eea899f48c336adc57\nmsgid \"The owning page object of the annotation.\"\nmsgstr \"アノテーションの所属ページオブジェクト。\"\n\n#: ../../annot.rst:436 b69e2ef1768c4682aeceb59e231073e6\nmsgid \":ref:`Page`\"\nmsgstr \"\"\n\n#: ../../annot.rst:440 d8c838f369404f76b51db3fa29590aaf\nmsgid \"The annot rotation.\"\nmsgstr \"アノテーションの回転角度。\"\n\n#: ../../annot.rst:443 0e4000b23bd0487692990ba93841e11b\nmsgid \"\"\n\"a value [-1, 359]. If rotation is not at all, -1 is returned (and implies\"\n\" a rotation angle of 0). Other possible values are normalized to some \"\n\"value value 0 <= angle < 360.\"\nmsgstr \"\"\n\"値は[-1, 359]です。回転が全くない場合、-1が返されます（回転角度0を意味します）。その他の可能な値は、一定の値0 <= angle < \"\n\"360に正規化されます。\"\n\n#: ../../annot.rst:447 675380b4c5e64bf7bff950dcc720a751\nmsgid \"The rectangle containing the annotation.\"\nmsgstr \"アノテーションを含む長方形領域。\"\n\n#: ../../annot.rst:449 ../../annot.rst:549 aebdf20a1fda46b7abc7b4c3e0493882\n#: ec14799005724be998a1275792677a12\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:453 c70b9c19d6d84a359b2b1a7396054162\nmsgid \"The next annotation on this page or None.\"\nmsgstr \"このページ上の次のアノテーションまたはNone。\"\n\n#: ../../annot.rst:455 e2f9dcc59c714b54a43f67ec7b62cff8\nmsgid \"*Annot*\"\nmsgstr \"\"\n\n#: ../../annot.rst:459 606bb69f415d48c0a7aad4dac9c69fc3\nmsgid \"\"\n\"A number and one or two strings describing the annotation type, like \"\n\"**[2, 'FreeText', 'FreeTextCallout']**. The second string entry is \"\n\"optional and may be empty. See the appendix :ref:`AnnotationTypes` for a \"\n\"list of possible values and their meanings.\"\nmsgstr \"\"\n\"アノテーションタイプ を説明する数値と1つまたは2つの文字列、例: **[2, 'FreeText', 'FreeTextCallout']** \"\n\"。第2の文字列エントリはオプションで、空であるかもしれません。可能な値とその意味については、付録の :ref:`AnnotationTypes` \"\n\"のリストを参照してください。\"\n\n#: ../../annot.rst:465 814b528ad1594607875ed97510496fe2\nmsgid \"\"\n\"A dictionary containing various information. All fields are optional \"\n\"strings. For information items not provided, an empty string is returned.\"\nmsgstr \"異なる情報を含む辞書。すべてのフィールドはオプションの文字列です。提供されない情報項目については、空の文字列が返されます。\"\n\n#: ../../annot.rst:467 132313a5fcff4d5b98ca42e3a4bf5fda\nmsgid \"\"\n\"*name* -- e.g. for 'Stamp' annotations it will contain the stamp text \"\n\"like \\\"Sold\\\" or \\\"Experimental\\\", for other annot types you will see the\"\n\" name of the annot's icon here (\\\"PushPin\\\" for FileAttachment).\"\nmsgstr \"\"\n\"*name* – たとえば、 'Stamp' 注釈の場合、 'Sold' または 'Experimental' \"\n\"のようなスタンプテキストが含まれ、他の注釈のタイプでは注釈のアイコンの名前がここに表示されます（FileAttachment の場合は \"\n\"'PushPin'）。\"\n\n#: ../../annot.rst:469 bc6c85b50da94924bc357226258bd3fc\nmsgid \"\"\n\"*content* -- a string containing the text for type *Text* and *FreeText* \"\n\"annotations. Commonly used for filling the text field of annotation pop-\"\n\"up windows.\"\nmsgstr \"\"\n\"*content*  – *テキスト* タイプと *FreeText* \"\n\"注釈のテキストを含む文字列。注釈のポップアップウィンドウのテキストフィールドを埋めるために一般的に使用されます。\"\n\n#: ../../annot.rst:471 d7645d31cbb64e3cb699a731902ecb75\nmsgid \"\"\n\"*title* -- a string containing the title of the annotation pop-up window.\"\n\" By convention, this is used for the **annotation author**.\"\nmsgstr \"*title* – 注釈のポップアップウィンドウのタイトルを含む文字列。通常、これは **注釈の著者** に使用されます。\"\n\n#: ../../annot.rst:473 ba6e837b12eb4a59b39297c6410293cb\nmsgid \"*creationDate* -- creation timestamp.\"\nmsgstr \"*creationDate* – 作成タイムスタンプ。\"\n\n#: ../../annot.rst:474 dea7337d10874b83bd25f6be18463264\nmsgid \"*modDate* -- last modified timestamp.\"\nmsgstr \"*modDate* – 最終変更タイムスタンプ。\"\n\n#: ../../annot.rst:475 affe5f09ffd3424b9ff3466bd9fa10e4\nmsgid \"*subject* -- subject.\"\nmsgstr \"*subject* – 主題。\"\n\n#: ../../annot.rst:476 2839aeb340104f42b830df272fca2fb6\nmsgid \"\"\n\"*id* -- *(new in version 1.16.10)* a unique identification of the \"\n\"annotation. This is taken from PDF key */NM*. Annotations added by \"\n\"PyMuPDF will have a unique name, which appears here.\"\nmsgstr \"\"\n\"*id* – （バージョン1.16.10で新規追加）注釈の一意の識別子。これはPDFキー */ NM* \"\n\"から取得されます。PyMuPDFによって追加された注釈には一意の名前があり、ここに表示されます\"\n\n#: ../../annot.rst:483 16616c415f6e46b7a3677cfdd3112ce3\nmsgid \"\"\n\"An integer whose low order bits contain flags for how the annotation \"\n\"should be presented.\"\nmsgstr \"注釈の表示方法を示すフラグを含む低位ビットを持つ整数。\"\n\n#: ../../annot.rst:489 8339de6110f3442eae85a3e339d2b60f\nmsgid \"\"\n\"A pair of integers specifying start and end symbol of annotations types \"\n\"'FreeText', 'Line', 'PolyLine', and 'Polygon'. ``None`` if not \"\n\"applicable. For possible values and descriptions in this list, see the \"\n\":ref:`AdobeManual`, table 1.76 on page 400.\"\nmsgstr \"\"\n\"'FreeText'、'Line'、'PolyLine'、および'Polygon'の注釈タイプの開始および終了シンボルを指定する2つの整数のペア。該当しない場合は\"\n\" *なし* 。このリストでの可能な値と説明については、:ref:`AdobeManual` のページ400の表1.76を参照してください。\"\n\n#: ../../annot.rst:495 8bf05b20e751463eae59e5c917d94466\nmsgid \"\"\n\"A list containing a variable number of point (\\\"vertices\\\") coordinates \"\n\"(each given by a pair of floats) for various types of annotations:\"\nmsgstr \"さまざまな種類の注釈に対する、可変数の点（\\\"頂点\\\"）座標（各々が浮動小数点数のペアで指定される）を含むリスト：\"\n\n#: ../../annot.rst:497 8912d31ff3344e5e8152219991bcb863\nmsgid \"'Line' -- the starting and ending coordinates (2 float pairs).\"\nmsgstr \"'Line' – 開始座標と終了座標（2つの浮動小数点数のペア）。\"\n\n#: ../../annot.rst:498 a5b0fa3b850f4856bd236c668f63f1eb\nmsgid \"\"\n\"'FreeText' -- 2 or 3 float pairs designating the starting, the (optional)\"\n\" knee point, and the ending coordinates.\"\nmsgstr \"'FreeText' – 開始座標、（オプションの）曲線点、および終了座標を指定する2または3つの浮動小数点数のペア。\"\n\n#: ../../annot.rst:499 b0ee60812ba343fea5fc2d15019955f2\nmsgid \"\"\n\"'PolyLine' / 'Polygon' -- the coordinates of the edges connected by line \"\n\"pieces (n float pairs for n points).\"\nmsgstr \"'PolyLine' / 'Polygon' – 線分で接続されたエッジの座標（nポイントのためのn個の浮動小数点数のペア）。\"\n\n#: ../../annot.rst:500 8fbc31fb944e4da2868503b7613244d0\nmsgid \"\"\n\"text markup annotations -- 4 float pairs specifying the *QuadPoints* of \"\n\"the marked text span (see :ref:`AdobeManual`, page 403).\"\nmsgstr \"\"\n\"テキストのマークアップ注釈 – マークされたテキストスパンのQuadPointsを指定する4つの浮動小数点数のペア（Adobe \"\n\"PDFリファレンス、ページ403を参照）。\"\n\n#: ../../annot.rst:501 09ceddfd7c4642e187b77e4fe278f331\nmsgid \"\"\n\"'Ink' -- list of one to many sublists of vertex coordinates. Each such \"\n\"sublist represents a separate line in the drawing.\"\nmsgstr \"'Ink' – 頂点座標の1つから多数のサブリストのリスト。各サブリストは、描画内の別々の線を表します。\"\n\n#: ../../annot.rst:508 e363318aa7cb46ff97b34487bc567275\n#, fuzzy\nmsgid \"\"\n\"dictionary of two lists of floats in range *0 <= float <= 1* specifying \"\n\"the \\\"stroke\\\" and the interior (\\\"fill\\\") colors. The stroke color is \"\n\"used for borders and everything that is actively painted or written \"\n\"(\\\"stroked\\\"). The fill color is used for the interior of objects like \"\n\"line ends, circles and squares. The lengths of these lists implicitly \"\n\"determine the colorspaces used: 1 = GRAY, 3 = RGB, 4 = CMYK. So \\\"[1.0, \"\n\"0.0, 0.0]\\\" stands for RGB color red. Both lists can be empty if no color\"\n\" is specified. Be aware about some potentially unexpected cases:\"\nmsgstr \"\"\n\"*0 <= 浮動小数点数 <= 1の範囲内* で指定された \\\"ストローク\\\" \"\n\"および内部（\\\"塗りつぶし\\\"）カラーの2つの浮動小数点数のリストから成る辞書。ストロークカラーは、境界線やアクティブに塗装されたり書かれたりするすべてに使用されます。塗りつぶしカラーは、線の端、円、正方形などのオブジェクトの内部に使用されます。これらのリストの長さは、暗黙的に使用されるカラースペースを決定します：1\"\n\" = GRAY、3 = RGB、4 = CMYK。したがって、\\\"[1.0, 0.0, 0.0]\\\" \"\n\"はRGBカラーの赤を表します。どちらのリストも指定されていない場合、空にすることができます。\"\n\n#: ../../annot.rst:510 c98f3742209a4834b74c3d4385888358\nmsgid \"\"\n\"The color of Highlight annotations is a **stroke** color, contrary to \"\n\"intuition.\"\nmsgstr \"\"\n\n#: ../../annot.rst:511 2d1b77af92f94df2901498dee3ecf512\nmsgid \"\"\n\"The color if FreeText annotations is a **stroke** color, but appears as \"\n\"the color that fills the rectangle and any applicable line end symbols. \"\n\"Text color and border color cannot be accessed at all.\"\nmsgstr \"\"\n\n#: ../../annot.rst:517 5673a83fdd3046e1a25a02e890bf9503\nmsgid \"The PDF :data:`xref`.\"\nmsgstr \"PDFの :data:`xref` 。\"\n\n#: ../../annot.rst:523 80d30458b0ae4d81a75fccb23e4560df\nmsgid \"\"\n\"The PDF :data:`xref` of an annotation to which this one responds. Return \"\n\"zero if this is no response annotation.\"\nmsgstr \"この注釈が応答する注釈のPDF :data:`xref` 。これが応答注釈でない場合はゼロを返します。\"\n\n#: ../../annot.rst:529 adc968b773a6471aba76a7111c2340a5\nmsgid \"\"\n\"The PDF :data:`xref` of the associated Popup annotation. Zero if non-\"\n\"existent.\"\nmsgstr \"関連するポップアップ注釈のPDF :data:`xref` 。存在しない場合はゼロ。\"\n\n#: ../../annot.rst:535 87e7894e6b484ea3b6e9b676e28d88b3\nmsgid \"Whether the annotation has a Popup annotation.\"\nmsgstr \"注釈にポップアップ注釈があるかどうか。\"\n\n#: ../../annot.rst:541 a5edaf80b163482b844afac753dce499\nmsgid \"\"\n\"Whether the annotation's Popup is open -- **or** the annotation itself \"\n\"('Text' annotations only).\"\nmsgstr \"注釈のポップアップが開いているかどうか - **または** 注釈自体（'テキスト'注釈のみ）。\"\n\n#: ../../annot.rst:547 600f5a64e8a4400da0c1ae35c135efd1\nmsgid \"\"\n\"The rectangle of the associated Popup annotation. Infinite rectangle if \"\n\"non-existent.\"\nmsgstr \"関連するポップアップ注釈の矩形。存在しない場合は無限の矩形。\"\n\n#: ../../annot.rst:553 9fd4e2374ea64a4f895272c2450db57b\nmsgid \"\"\n\"A tuple of four floats representing the `/RD` entry of the annotation. \"\n\"The four numbers describe the numerical differences (left, top, -right, \"\n\"-bottom) between two rectangles: the :attr:`rect` of the annotation and a\"\n\" rectangle contained within that rectangle. If the entry is missing, this\"\n\" property is `(0, 0, 0, 0)`. If the annotation border is a normal, \"\n\"straight line, these numbers are typically border width divided by 2. If \"\n\"the annotation has a \\\"cloudy\\\" border, you will see the breadth of the \"\n\"cloud semi-circles here. In general, the numbers need not be identical. \"\n\"To compute the inner rectangle do `a.rect + a.rect_delta`.\"\nmsgstr \"\"\n\"注釈の `/RD` \"\n\"エントリを表す4つの浮動小数点数のタプル。これらの4つの数値は、2つの矩形間の数値の差（左、上、-右、-下）を説明しています：注釈の \"\n\":attr:`rect` とその矩形内に含まれる矩形。エントリが存在しない場合、このプロパティは.  `（0、0、0、0）` \"\n\"です。注釈の境界線が通常のまっすぐな線である場合、これらの数値は通常、境界線の幅を2で割ったものです。注釈に「雲状」の境界線がある場合、ここで雲の半円の幅が表示されます。一般的に、これらの数値は同一である必要はありません。内側の矩形を計算するには、`a.rect\"\n\" + a.rect_delta` を使用します。\"\n\n#: ../../annot.rst:557 76373f31dcbe446392d079eb34532b34\nmsgid \"\"\n\"A dictionary containing border characteristics. Empty if no border \"\n\"information exists. The following keys may be present:\"\nmsgstr \"境界線の特性を含む辞書。境界線情報が存在しない場合は空です。次のキーが存在する可能性があります：\"\n\n#: ../../annot.rst:559 2a2fab2fdf524b6184a1f5b62304135a\nmsgid \"\"\n\"*width* -- a float indicating the border thickness in points. The value \"\n\"is -1.0 if no width is specified.\"\nmsgstr \"*width*  – ポイントでの境界線の太さを示す浮動小数点数。幅が指定されていない場合、値は -1.0 です。\"\n\n#: ../../annot.rst:561 ee7176832c7e4740b78bb806706a9d04\nmsgid \"\"\n\"*dashes* -- a sequence of integers specifying a line dashing pattern. \"\n\"*[]* means no dashes, *[n]* means equal on-off lengths of *n* points, \"\n\"longer lists will be interpreted as specifying alternating on-off length \"\n\"values. See the :ref:`AdobeManual` page 126 for more details.\"\nmsgstr \"\"\n\"*dashes* – ラインダッシングパターンを指定する整数のシーケンス。*[]* はダッシュなし、*[n]* は *n* \"\n\"ポイントの等しいオンオフの長さを意味し、より長いリストは交互のオンオフ長さ値を指定して解釈されます。詳細については、:ref:`AdobeManual`\"\n\" のページ126を参照してください。\"\n\n#: ../../annot.rst:563 994ba35808ba4456b6568752b410a28e\nmsgid \"\"\n\"*style* -- 1-byte border style: **\\\"S\\\"** (Solid) = solid line \"\n\"surrounding the annotation, **\\\"D\\\"** (Dashed) = dashed line surrounding \"\n\"the annotation, the dash pattern is specified by the *dashes* entry, \"\n\"**\\\"B\\\"** (Beveled) = a simulated embossed rectangle that appears to be \"\n\"raised above the surface of the page, **\\\"I\\\"** (Inset) = a simulated \"\n\"engraved rectangle that appears to be recessed below the surface of the \"\n\"page, **\\\"U\\\"** (Underline) = a single line along the bottom of the \"\n\"annotation rectangle.\"\nmsgstr \"\"\n\"*style* – 1バイトの境界線スタイル： **\\\"S\\\"** （Solid）= 注釈を囲む実線、 **\\\"D\\\"** （Dashed）= \"\n\"注釈を囲む破線、破線パターンは *dashes* エントリによって指定され、 **“B”** （Beveled）= \"\n\"ページの表面よりも上に浮かぶように見える模擬的な浮き出し矩形、 **\\\"I\\\"** （Inset）= \"\n\"ページの表面よりも下に凹んだように見える模擬的な浮き彫りの矩形、 **\\\"U\\\"** （Underline）= 注釈矩形の底部に沿った単一の線。\"\n\n#: ../../annot.rst:565 7700bc48fde44a268bcd7c4a8afa5304\nmsgid \"\"\n\"*clouds* -- an integer indicating a \\\"cloudy\\\" border, where ``n`` is an \"\n\"integer `-1 <= n <= 2`. A value `n = 0` indicates a straight line (no \"\n\"clouds), 1 means small and 2 means large semi-circles, mimicking the \"\n\"cloudy appearance. If -1, then no specification is present.\"\nmsgstr \"\"\n\"*clouds* – “雲状”の境界を示す整数。``n`` は整数 `-1 <= n <= 2` を指します。値 `n = 0` \"\n\"は直線（雲なし）を示し、1 は小さな半円、2 は大きな半円を模倣した雲の外観を示します。-1 の場合、仕様が存在しないことを示します。\"\n\n#: ../../annot.rst:573 332ac742d76d48529ceb6b4e40f7295a\nmsgid \"Annotation Icons in MuPDF\"\nmsgstr \"MuPDFの注釈アイコン\"\n\n#: ../../annot.rst:574 21859a0e63974afa950419ab98ff55e6\nmsgid \"\"\n\"This is a list of icons referenceable by name for annotation types 'Text'\"\n\" and 'FileAttachment'. You can use them via the *icon* parameter when \"\n\"adding an annotation, or use the as argument in :meth:`Annot.set_name`. \"\n\"It is left to your discretion which item to choose when -- no mechanism \"\n\"will keep you from using e.g. the \\\"Speaker\\\" icon for a \"\n\"'FileAttachment'.\"\nmsgstr \"\"\n\"これは「Text」および「FileAttachment」注釈タイプの名前で参照可能なアイコンのリストです。注釈を追加する際に*icon* \"\n\"パラメータを使用したり、:meth:`Annot.set_name` \"\n\"の引数として使用したりできます。どのアイテムを選択するかはあなたの裁量に任されています - \"\n\"たとえば、「Speaker」アイコンを「FileAttachment」に使用することを防ぐメカニズムは存在しません。\"\n\n#: ../../annot.rst:580 cb12c1793cdb4341b24fbf6538c60d1c\nmsgid \"Example\"\nmsgstr \"例\"\n\n#: ../../annot.rst:581 a2296e47889a4fec983f5aa41e485291\nmsgid \"\"\n\"Change the graphical image of an annotation. Also update the \\\"author\\\" \"\n\"and the text to be shown in the popup window::\"\nmsgstr \"注釈のグラフィカルな画像を変更します。また、ポップアップウィンドウに表示される「著者」とテキストを更新します。\"\n\n#: ../../annot.rst:604 7bff751c7d604fe38047b43fdeb95933\nmsgid \"\"\n\"This is how the circle annotation looks like before and after the change \"\n\"(pop-up windows displayed using Nitro PDF viewer):\"\nmsgstr \"これが、変更前と変更後のサークル注釈の見た目です（Nitro PDFビューアを使用して表示されるポップアップウィンドウ）:\"\n\n#: ../../annot.rst:606 479b5bc5389b486e92aaf64c6226c673\nmsgid \"|circle|\"\nmsgstr \"\"\n\n#: ../../annot.rst:608 031e9835b5ea4674bd3bcd678ae780a5\n#: 8bea81da58c844a9abeb9a5253d1a9b6\nmsgid \"circle\"\nmsgstr \"\"\n\n#: ../../annot.rst:612 a8717fc2c8cd4706b95166aae42c2f9b\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../annot.rst:613 6d03771b774345a5b005846ee4002288\nmsgid \"\"\n\"Rotating an annotation also changes its rectangle. Depending on how the \"\n\"annotation was defined, the original rectangle is **cannot be \"\n\"reconstructed** by setting the rotation value to zero again and will be \"\n\"lost.\"\nmsgstr \"\"\n\"注釈を回転させると、その矩形も変更されます。注釈がどのように定義されたかによって、元の矩形は回転値を再びゼロに設定しても **再構築できず** \"\n\"、失われます。\"\n\n#: ../../annot.rst:615 c6c9d602fa054b6fac8c6ec2c52ad078\nmsgid \"\"\n\"Only the following annotation types support method \"\n\":meth:`Annot.set_rect`: Text, FreeText, Square, Circle, Redact, Stamp, \"\n\"Caret, FileAttachment, Sound, and Movie.\"\nmsgstr \"\"\n\":meth:`Annot.set_rect` \"\n\"をサポートする注釈タイプは、次のものだけです：Text、FreeText、Square、Circle、Redact、Stamp、Caret、FileAttachment、Sound、およびMovie。\"\n\n#: ../../footer.rst:46 bc670bbcee16481398498b6cc9d3f828\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"**This class is supported for PDF documents only.**\"\n#~ msgstr \"**このクラスはPDFドキュメントのみに対応しています。** \"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"While 'FreeText', 'Line', 'PolyLine', and \"\n#~ \"'Polygon' annotations can have these \"\n#~ \"properties, (Py-) MuPDF does not support\"\n#~ \" line ends for 'FreeText', because \"\n#~ \"the call-out variant of it is \"\n#~ \"not supported.\"\n#~ msgstr \"\"\n#~ \"「FreeText」、「Line」、「PolyLine」、および「Polygon」注釈はこれらのプロパティを持つことができますが、（Py-）MuPDF\"\n#~ \" は「FreeText」の線終端をサポートしていません。なぜなら、そのコールアウトバリアントはサポートされていないからです。\"\n\n#~ msgid \"\"\n#~ \"*(Changed in v1.16.16)* Some symbols \"\n#~ \"have an interior area (diamonds, \"\n#~ \"circles, squares, etc.). By default, \"\n#~ \"these areas are filled with the \"\n#~ \"fill color of the annotation. If \"\n#~ \"this is ``None``, then white is \"\n#~ \"chosen. The *fill_color* argument of \"\n#~ \":meth:`Annot.update` can now be used to\"\n#~ \" override this and give line end \"\n#~ \"symbols their own fill color.\"\n#~ msgstr \"\"\n#~ \"*（v1.16.16 で変更）* \"\n#~ \"一部のシンボルには内部領域（ダイヤモンド、円、正方形など）があります。デフォルトでは、これらの領域は注釈の塗りつぶし色で塗りつぶされます。これが\"\n#~ \" ``None`` の場合、白色が選択されます。:meth:`Annot.update` の \"\n#~ \"*fill_color* 引数を使用して、線終端シンボルに独自の塗りつぶし色を設定することができるようになりました。\"\n\n#~ msgid \"\"\n#~ \"Changed in version 1.16.9: Allow colors\"\n#~ \" to be directly set. These parameters\"\n#~ \" are used if *colors* is not a\"\n#~ \" dictionary.\"\n#~ msgstr \"バージョン1.16.9で変更: 色を直接設定できるようにしました。これらのパラメータは、*colors* が辞書でない場合に使用されます。\"\n\n#~ msgid \"\"\n#~ \"the fill color.  * 'Line', 'Polyline',\"\n#~ \" 'Polygon' annotations: use it to \"\n#~ \"give applicable line end symbols a \"\n#~ \"fill color other than that of the\"\n#~ \" annotation *(changed in v1.16.16)*.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"'Line', 'Polyline', 'Polygon' annotations: use\"\n#~ \" it to give applicable line end \"\n#~ \"symbols a fill color other than \"\n#~ \"that of the annotation *(changed in \"\n#~ \"v1.16.16)*.\"\n#~ msgstr \"\"\n#~ \"'Line'、'Polyline'、'Polygon' \"\n#~ \"注釈：適用可能な線の端のシンボルに注釈の色以外の塗りつぶしの色を与えるために使用します *（v1.16.16で変更）* \"\n#~ \"。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/app1.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 fdfbfd4ec6524865abf05d4f02f40bd4\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 4ef893e3d65549bdb97761ade9d2fbe0\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 93b3b77eb5fb4d609385d37e1b52f560\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../app1.rst:7 32522e45284f47b9a2baab2001f554fc\nmsgid \"Appendix 1: Details on Text Extraction\"\nmsgstr \"付録1: テキスト抽出の詳細\"\n\n#: ../../app1.rst:8 7a46450d4e694b47ba30ff347aa1295a\nmsgid \"\"\n\"This chapter provides background on the text extraction methods of \"\n\"PyMuPDF.\"\nmsgstr \"この章では、PyMuPDFのテキスト抽出メソッドに関する背景情報を提供します。\"\n\n#: ../../app1.rst:10 433c42d12e1e466887a62caef1d48c04\nmsgid \"Information of interest are\"\nmsgstr \"興味のある情報は以下です\"\n\n#: ../../app1.rst:12 855bc392f61942508bcfcfee3ff9ad79\nmsgid \"what do they provide?\"\nmsgstr \"彼らは何を提供するのか？\"\n\n#: ../../app1.rst:13 7bfcfb2ef4424ff1bfff9c532da582fc\nmsgid \"what do they imply (processing time / data sizes)?\"\nmsgstr \"それらは何を意味するのか（処理時間 / データサイズ）？\"\n\n#: ../../app1.rst:16 f054be020fee4f7dbe78d82ec1f9a215\nmsgid \"General structure of a TextPage\"\nmsgstr \"TextPageの一般的な構造\"\n\n#: ../../app1.rst:17 c38170b0abfd4137afa0635a2f080530\nmsgid \"\"\n\":ref:`TextPage` is one of (Py-) MuPDF's classes. It is normally created \"\n\"(and destroyed again) behind the curtain, when :ref:`Page` text \"\n\"extraction methods are used, but it is also available directly and can be\"\n\" used as a persistent object. Other than its name suggests, images may \"\n\"optionally also be part of a text page::\"\nmsgstr \"\"\n\":ref:`TextPage` は（Py-）MuPDFのクラスの一つです。通常、:ref:`Page` \"\n\"のテキスト抽出メソッドが使用されるときにカーテンの後ろで作成され（および破棄され）ますが、直接利用することもでき、永続オブジェクトとして使用することができます。その名前が示すよりも、テキストページにはオプションで画像も含まれる場合があります：\"\n\n#: ../../app1.rst:27 fa5133b907134789b7b5bcf5427df499\nmsgid \"A **text page** consists of blocks (= roughly paragraphs).\"\nmsgstr \"**テキストページ** は、ブロック（おおよそ段落）で構成されています。\"\n\n#: ../../app1.rst:29 8a84fe5ed0fa4b028ce78c0283f42e05\nmsgid \"A **block** consists of either lines and their characters, or an image.\"\nmsgstr \"**ブロック** は、行とその文字、または画像のいずれかから成り立っています。\"\n\n#: ../../app1.rst:31 b618a5ef31c6418385e67337d450a352\nmsgid \"A **line** consists of spans.\"\nmsgstr \"**行** は、スパンから成り立っています。\"\n\n#: ../../app1.rst:33 10807e13bcf148d1901a347693b84092\nmsgid \"\"\n\"A **span** consists of adjacent characters with identical font \"\n\"properties: name, size, flags and color.\"\nmsgstr \"**スパン** は、同一のフォントプロパティ（名前、サイズ、フラグ、色）を持つ隣接する文字から成り立っています。\"\n\n#: ../../app1.rst:36 94770e1286bd45faa80dd24ab08a2b98\nmsgid \"Plain Text\"\nmsgstr \"プレーンテキスト\"\n\n#: ../../app1.rst:38 4e59da8e7882467d9e3fc99a17ebcd20\nmsgid \"\"\n\"Function :meth:`TextPage.extractText` (or *Page.get_text(\\\"text\\\")*) \"\n\"extracts a page's plain **text in original order** as specified by the \"\n\"creator of the document.\"\nmsgstr \"\"\n\"関数  :meth:`TextPage.extractText` （または *Page.get_text(\\\"text\\\")* \"\n\"）は、ドキュメントの作成者によって指定された元の順序で、ページのプレーンテキストを抽出します。\"\n\n#: ../../app1.rst:40 43eb12dcbd3741a39565376bce991deb\nmsgid \"An example output::\"\nmsgstr \"例の出力：\"\n\n#: ../../app1.rst:45 9b508c1639d948d0bb34f53480a454de\nmsgid \"\"\n\"The output may not equal an accustomed \\\"natural\\\" reading order. \"\n\"However, you can request a reordering following the scheme \\\"top-left to \"\n\"bottom-right\\\" by executing `page.get_text(\\\"text\\\", sort=True)`.\"\nmsgstr \"\"\n\"出力は通常の「自然な」読み順と一致しない場合があります。ただし、`page.get_text(\\\"text\\\", sort=True)` \"\n\"を実行することで、「左上から右下」のスキームに従った並べ替えを要求することができます。\"\n\n#: ../../app1.rst:49 ../../app1.rst:337 01218363ec8b4f25b01be035183f2bad\n#: ea3b77edca944acd87dfae64354fc218\nmsgid \"BLOCKS\"\nmsgstr \"ブロック\"\n\n#: ../../app1.rst:51 84c30a08712041efbd0d51b5d1f3b869\nmsgid \"\"\n\"Function :meth:`TextPage.extractBLOCKS` (or *Page.get_text(\\\"blocks\\\")*) \"\n\"extracts a page's text blocks as a list of items like::\"\nmsgstr \"\"\n\"関数  :meth:`TextPage.extractBLOCKS` （または `Page.get_text(\\\"blocks\\\")` \"\n\"）は、ページのテキストブロックを以下のような項目のリストとして抽出します：\"\n\n#: ../../app1.rst:55 eca4a5b7ac1e429d922a4caaf3b1508a\nmsgid \"\"\n\"Where the first 4 items are the float coordinates of the block's bbox. \"\n\"The lines within each block are concatenated by a new-line character.\"\nmsgstr \"最初の4つの項目は、ブロックのバウンディングボックスの浮動小数点座標です。各ブロック内の行は改行文字で連結されます。\"\n\n#: ../../app1.rst:57 a2ec0b47ebce4d5a924b99a85953372a\nmsgid \"\"\n\"This is a high-speed method, which by default also extracts image meta \"\n\"information: Each image appears as a block with one text line, which \"\n\"contains meta information. The image itself is not shown.\"\nmsgstr \"これは高速なメソッドであり、デフォルトでは画像のメタ情報も抽出されます。各画像はメタ情報を含む1行のテキスト行で表されるブロックとして表示されます。画像そのものは表示されません。\"\n\n#: ../../app1.rst:59 c7b5a7b9a23e458a96b54934b3ed775f\nmsgid \"\"\n\"As with simple text output above, the `sort` argument can be used as well\"\n\" to obtain a reading order.\"\nmsgstr \"前述の単純なテキスト出力と同様に、`sort` 引数を使用して読み順を取得することもできます。\"\n\n#: ../../app1.rst:61 ../../app1.rst:79 a78d72a8fc184086a8d50d1cf5a9ef1a\n#: e2343d105e624aeb882debda02386431\nmsgid \"Example output::\"\nmsgstr \"例の出力：\"\n\n#: ../../app1.rst:69 ../../app1.rst:338 acff28e048b34b4ba229b68304cfb76b\n#: cddad20f52224312b51a7f0c5053ac5a\nmsgid \"WORDS\"\nmsgstr \"単語\"\n\n#: ../../app1.rst:71 89a704f3ac384146b0b14fac38aa5a65\nmsgid \"\"\n\"Function :meth:`TextPage.extractWORDS` (or *Page.get_text(\\\"words\\\")*) \"\n\"extracts a page's text **words** as a list of items like::\"\nmsgstr \"\"\n\"関数 :meth:`TextPage.extractWORDS` （または *Page.get_text(\\\"words\\\")* \"\n\"）は、ページのテキスト単語を以下のような項目のリストとして抽出します：\"\n\n#: ../../app1.rst:75 f050c877e9a940cdbec7cc265b1bb992\nmsgid \"\"\n\"Where the first 4 items are the float coordinates of the words's bbox. \"\n\"The last three integers provide some more information on the word's \"\n\"whereabouts.\"\nmsgstr \"最初の4つの項目は、単語のバウンディングボックスの浮動小数点座標です。最後の3つの整数は、単語の位置に関する追加情報を提供します\"\n\n#: ../../app1.rst:77 0f54ed7a09db4671bf357a69f4eaf0cf\nmsgid \"\"\n\"This is a high-speed method. As with the previous methods, argument \"\n\"`sort=True` will reorder the words.\"\nmsgstr \"これは高速なメソッドです。前のメソッドと同様に、引数 `sort=True` を使用すると単語が再並べ替えされます。\"\n\n#: ../../app1.rst:95 ../../app1.rst:341 9c256b41e353481a8f9d1120383e185d\n#: b01eed8bd2214d029f98ed8e402c64ec\nmsgid \"HTML\"\nmsgstr \"\"\n\n#: ../../app1.rst:97 ae629776c0304c299e0e8d208a5c09fa\nmsgid \"\"\n\":meth:`TextPage.extractHTML` (or *Page.get_text(\\\"html\\\")* output fully \"\n\"reflects the structure of the page's ``TextPage`` -- much like DICT / \"\n\"JSON below. This includes images, font information and text positions. If\"\n\" wrapped in HTML header and trailer code, it can readily be displayed by \"\n\"an internet browser. Our above example::\"\nmsgstr \"\"\n\":meth:`TextPage.extractHTML` （または *Page.get_text(\\\"html\\\"）* の出力は、ページの \"\n\"`TextPage` の構造を完全に反映します。これは、以下のDICT / \"\n\"JSONのようなものです。これには画像、フォント情報、テキスト位置が含まれます。HTMLヘッダーとトレイラーコードで囲むと、インターネットブラウザで簡単に表示できます。上記の例：\"\n\n#: ../../app1.rst:113 7390b832da484722ac5b9460920b0c9b\nmsgid \"Controlling Quality of HTML Output\"\nmsgstr \"HTML出力の品質の制御\"\n\n#: ../../app1.rst:114 cda88645b63f404c8de487595a91b015\nmsgid \"\"\n\"While HTML output has improved a lot in MuPDF v1.12.0, it is not yet bug-\"\n\"free: we have found problems in the areas **font support** and **image \"\n\"positioning**.\"\nmsgstr \"\"\n\"MuPDF v1.12.0でHTML出力はかなり改善されましたが、まだバグがないわけではありません。**フォントサポート** や**画像の配置**\"\n\" に関する問題が見つかっています。\"\n\n#: ../../app1.rst:116 8e67f6c0b40547eb8c013174c0840a60\nmsgid \"\"\n\"HTML text contains references to the fonts used of the original document.\"\n\" If these are not known to the browser (a fat chance!), it will replace \"\n\"them with others; the results will probably look awkward. This issue \"\n\"varies greatly by browser -- on my Windows machine, MS Edge worked just \"\n\"fine, whereas Firefox looked horrible.\"\nmsgstr \"\"\n\"HTMLテキストには元のドキュメントで使用されたフォントへの参照が含まれています。もしブラウザがそれらを認識できない場合（少ない確率ですが）、他のフォントで置き換えられ、結果が奇妙に見えるかもしれません。この問題はブラウザによって大きく異なります。Windowsマシンでは、MS\"\n\" Edgeはうまく動作するかもしれませんが、Firefoxはひどく見えるかもしれません。\"\n\n#: ../../app1.rst:118 a84f551c6b3c4c0daaeda98b73eff629\nmsgid \"\"\n\"For PDFs with a complex structure, images may not be positioned and / or \"\n\"sized correctly. This seems to be the case for rotated pages and pages, \"\n\"where the various possible page bbox variants do not coincide (e.g. \"\n\"*MediaBox != CropBox*). We do not know yet, how to address this -- we \"\n\"filed a bug at MuPDF's site.\"\nmsgstr \"\"\n\"複雑な構造を持つPDFの場合、画像の位置やサイズが正しく配置されないことがあります。これは回転したページや、さまざまなページbboxのバリアントが一致しない場合に起こる可能性があります（たとえば、*MediaBox\"\n\" != CropBox* ）。これに対処する方法はまだわかっていませんが、MuPDFのサイトにバグを報告しました。\"\n\n#: ../../app1.rst:120 ede45259306f4b25a8a69c2642ee7790\nmsgid \"\"\n\"To address the font issue, you can use a simple utility script to scan \"\n\"through the HTML file and replace font references. Here is a little \"\n\"example that replaces all fonts with one of the :ref:`Base-14-Fonts`: \"\n\"serifed fonts will become \\\"Times\\\", non-serifed \\\"Helvetica\\\" and \"\n\"monospaced will become \\\"Courier\\\". Their respective variations for \"\n\"\\\"bold\\\", \\\"italic\\\", etc. are hopefully done correctly by your browser::\"\nmsgstr \"フォントの問題に対処するために、HTMLファイルをスキャンし、フォントの参照を置換するシンプルなユーティリティスクリプトを使用できます。以下は、すべてのフォントをPDFのベース14フォントの一つに置き換える例です：セリフフォントは「Times」になり、セリフのないフォントは「Helvetica」になり、等幅フォントは「Courier」になります。太字、斜体などの各バリエーションは、おそらくブラウザによって正しく処理されるでしょう。\"\n\n#: ../../app1.rst:160 604f24c1899b445a8e5f147bbea58c6b\nmsgid \"DICT (or JSON)\"\nmsgstr \"DICT（またはJSON）\"\n\n#: ../../app1.rst:162 2b4124eaa6184e5abeb4751eb27b7d28\nmsgid \"\"\n\":meth:`TextPage.extractDICT` (or *Page.get_text(\\\"dict\\\", sort=False)*) \"\n\"output fully reflects the structure of a ``TextPage`` and provides image \"\n\"content and position detail (*bbox* -- boundary boxes in pixel units) for\"\n\" every block, line and span. Images are stored as *bytes* for DICT output\"\n\" and base64 encoded strings for JSON output.\"\nmsgstr \"\"\n\":meth:`TextPage.extractDICT` （または *Page.get_text(\\\"dict\\\", sort=False)* \"\n\"）の出力は、 ``TextPage`` の構造を完全に反映し、各ブロック、行、スパンのために画像の内容と位置の詳細（ *bbox*  – \"\n\"ピクセル単位の境界ボックス）を提供します。画像はDICT出力では *バイト* \"\n\"として格納され、JSON出力ではbase64エンコードされた文字列として格納されます。\"\n\n#: ../../app1.rst:164 c899504e3d93462ebf94a0ae253c284d\nmsgid \"\"\n\"For a visualization of the dictionary structure have a look at \"\n\":ref:`textpagedict`.\"\nmsgstr \"辞書の構造の可視化については、辞書出力の構造をご覧ください。\"\n\n#: ../../app1.rst:166 a85a77c0a97a4b999a9608db09a62055\nmsgid \"Here is how this looks like::\"\nmsgstr \"以下がその様子です：\"\n\n#: ../../app1.rst:192 a39d5bea096643a481b871a235198902\nmsgid \"RAWDICT (or RAWJSON)\"\nmsgstr \"RAWDICT（またはRAWJSON）\"\n\n#: ../../app1.rst:193 e30e534d09664d99a59c74a2819edd1f\nmsgid \"\"\n\":meth:`TextPage.extractRAWDICT` (or *Page.get_text(\\\"rawdict\\\", \"\n\"sort=False)*) is an **information superset of DICT** and takes the detail\"\n\" level one step deeper. It looks exactly like the above, except that the \"\n\"*\\\"text\\\"* items (*string*) in the spans are replaced by the list \"\n\"*\\\"chars\\\"*. Each *\\\"chars\\\"* entry is a character *dict*. For example, \"\n\"here is what you would see in place of item *\\\"text\\\": \\\"Text in black \"\n\"color.\\\"* above::\"\nmsgstr \"\"\n\":meth:`TextPage.extractRAWDICT` （または *Page.get_text(\\\"rawdict\\\", \"\n\"sort=False)*  ）は、**DICTの情報のスーパーセット** \"\n\"であり、詳細レベルを一段階深くします。これは上記のように見えますが、スパン内の *「text」* アイテム（文字列）は *「chars」* \"\n\"というリストに置き換えられます。各 *「chars」* エントリは文字の *dict* です。例えば、 *「Text in black \"\n\"color.」* の代わりに以下のような項目が表示されます：\"\n\n#: ../../app1.rst:224 ../../app1.rst:339 1019709da94c447c87b21a8889ff73c6\n#: 2e6cf3faa00c40b99808a48b7890f736\nmsgid \"XML\"\nmsgstr \"\"\n\n#: ../../app1.rst:226 3e2cf1ef340e453c9ee25d4f7a082534\nmsgid \"\"\n\"The :meth:`TextPage.extractXML` (or *Page.get_text(\\\"xml\\\")*) version \"\n\"extracts text (no images) with the detail level of RAWDICT::\"\nmsgstr \"\"\n\":meth:`TextPage.extractXML` （または *Page.get_text(\\\"xml\\\"）* \"\n\"バージョンは、RAWDICTの詳細レベルでテキスト（画像なし）を抽出します：\"\n\n#: ../../app1.rst:255 b27a0017f5ac4d09a62ef96d7158aa58\nmsgid \"\"\n\"We have successfully tested `lxml <https://pypi.org/project/lxml/>`_ to \"\n\"interpret this output.\"\nmsgstr \"この出力を解釈するためにlxmlを使用して正常にテストしました。\"\n\n#: ../../app1.rst:258 ../../app1.rst:340 769cf57a03fb4d8ebc77e12339dfe126\n#: dfb6a028240f4f25ace3456d80f1e379\nmsgid \"XHTML\"\nmsgstr \"\"\n\n#: ../../app1.rst:259 9489175cb6d1431fab9e8388a1b5ee8d\nmsgid \"\"\n\":meth:`TextPage.extractXHTML` (or *Page.get_text(\\\"xhtml\\\")*) is a \"\n\"variation of TEXT but in HTML format, containing the bare text and images\"\n\" (\\\"semantic\\\" output)::\"\nmsgstr \"\"\n\":meth:`TextPage.extractXHTML` （または *Page.get_text(\\\"xhtml\\\"）* \"\n\"は、テキストと画像を含むHTML形式のTEXTのバリエーションです（「セマンティック」出力）：\"\n\n#: ../../app1.rst:268 e1dc4d16be0744a9a7a2b424f7a34574\nmsgid \"Text Extraction Flags Defaults\"\nmsgstr \"テキスト抽出フラグのデフォルト値\"\n\n#: ../../app1.rst:269 d6b62f1e66934d9391f12416f05cf4c3\nmsgid \"\"\n\"New in version 1.16.2: Method :meth:`Page.get_text` supports a keyword \"\n\"parameter *flags* *(int)* to control the amount and the quality of \"\n\"extracted data. The following table shows the defaults settings (flags \"\n\"parameter omitted or None) for each extraction variant. If you specify \"\n\"flags with a value other than ``None``, be aware that you must set **all \"\n\"desired** options. A description of the respective bit settings can be \"\n\"found in :ref:`TextPreserve`.\"\nmsgstr \"\"\n\"バージョン1.16.2で新しく追加されたメソッド :meth:`Page.get_text` \"\n\"は、抽出されるデータの量と品質を制御するためのキーワードパラメータ `flags` \"\n\"（整数）をサポートしています。以下の表は、各抽出バリエーションのデフォルト設定（ `flags` \"\n\"パラメータが省略されたかNoneの場合）を示しています。 `None` 以外の値でflagsを指定する場合は、**すべての必要なオプション** \"\n\"を設定する必要があることに注意してください。各ビット設定の説明は「テキスト抽出フラグ」で確認できます。\"\n\n#: ../../app1.rst:271 e8bfb1e18c8a40ef9482158b1b48b799\nmsgid \"\"\n\"New in v1.19.6: The default combinations in the following table are now \"\n\"available as Python constants: :data:`TEXTFLAGS_TEXT`, \"\n\":data:`TEXTFLAGS_WORDS`, :data:`TEXTFLAGS_BLOCKS`, \"\n\":data:`TEXTFLAGS_DICT`, :data:`TEXTFLAGS_RAWDICT`, \"\n\":data:`TEXTFLAGS_HTML`, :data:`TEXTFLAGS_XHTML`, :data:`TEXTFLAGS_XML`, \"\n\"and :data:`TEXTFLAGS_SEARCH`. You can now easily modify a default flag, \"\n\"e.g.\"\nmsgstr \"\"\n\"バージョン1.19.6で新しく追加された変更：次の表のデフォルトの組み合わせは、Pythonの定数として利用可能です： \"\n\":data:`TEXTFLAGS_TEXT` 、 :data:`TEXTFLAGS_WORDS` 、 \"\n\":data:`TEXTFLAGS_BLOCKS` 、 :data:`TEXTFLAGS_DICT` 、 \"\n\":data:`TEXTFLAGS_RAWDICT` 、 :data:`TEXTFLAGS_HTML` 、 \"\n\":data:`TEXTFLAGS_XHTML` 、 :data:`TEXTFLAGS_XML` 、 \"\n\":data:`TEXTFLAGS_SEARCH` 。これにより、デフォルトのフラグを簡単に変更できます。例えば、\"\n\n#: ../../app1.rst:273 6b7d5e078dee4d8faefcc18f13641d84\nmsgid \"**include** images in a \\\"blocks\\\" output:\"\nmsgstr \"「blocks」出力に画像を **含める** 場合：\"\n\n#: ../../app1.rst:275 920d23e221534056b885ac4d2aa40959\nmsgid \"`flags = TEXTFLAGS_BLOCKS | TEXT_PRESERVE_IMAGES`\"\nmsgstr \"\"\n\n#: ../../app1.rst:277 442e0b5271e84503b89c3efda021a625\nmsgid \"**exclude** images from a \\\"dict\\\" output:\"\nmsgstr \"「dict」出力から画像を **除外する** 場合：\"\n\n#: ../../app1.rst:279 8cc83a12e452488bbb0828a5b22c007b\nmsgid \"`flags = TEXTFLAGS_DICT & ~TEXT_PRESERVE_IMAGES`\"\nmsgstr \"\"\n\n#: ../../app1.rst:281 883ad6fe76334652937ecd82fe8393a8\nmsgid \"set **dehyphenation off** in text searches:\"\nmsgstr \"テキスト検索での **ハイフネーション** をオフに設定する：\"\n\n#: ../../app1.rst:283 46170567ecc240c88108dc6a14ac7982\nmsgid \"`flags = TEXTFLAGS_SEARCH & ~TEXT_DEHYPHENATE`\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 82de7610a8c84cdaa15aafa49960bf9a\nmsgid \"Indicator\"\nmsgstr \"指標\"\n\n#: ../../app1.rst:287 3892913f9254485a94780c276805766c\nmsgid \"text\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 37c756db16324c458f86f66f086d1941\nmsgid \"html\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 5063d3e2784149f188ffae7dcee78a89\nmsgid \"xhtml\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 0f75631f443a4653a3622a073d27d5a5\nmsgid \"xml\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 5a83675663804474931ef4cde1e02911\nmsgid \"dict\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 78bc13d9ae104947a657ed2b864c5af2\nmsgid \"rawdict\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 c2b7a5a2bcd040c48f4832612cda9e17\nmsgid \"words\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 e0b980adf7324d1cbf814983a363fe72\nmsgid \"blocks\"\nmsgstr \"\"\n\n#: ../../app1.rst:287 dd0b10b8c86e4f088602b83a1b03aa0d\nmsgid \"search\"\nmsgstr \"\"\n\n#: ../../app1.rst:289 9782eb815e0b457292e05170f64c6ada\nmsgid \"preserve ligatures\"\nmsgstr \"連結を保持\"\n\n#: ../../app1.rst:289 ../../app1.rst:290 ../../app1.rst:291 ../../app1.rst:293\n#: ../../app1.rst:294 ../../app1.rst:295 1e983a6cb6d44aceb3853c9a83ba5aaf\n#: 20b8ab4098ee4007bac8fd0a40bfdbb3 233a030d06984ee593bb98e31c636824\n#: 2b27ec6f790744eb9312d79895d0f846 3b76c164a3bd43af8ddd602b9fb58732\n#: 3b9f9e75e6cc47f79c07151895da4ffd 47460e3c55b04dc4b8ace07d8270df1c\n#: 4bdb19637b214e6491ff869852694c6a 567e1e72445749069d46f1f2eff63e0f\n#: 59a08f97de8d4245a3e54d4fb26b0291 5c07f51342ce4bba9fc7be3cda6af8df\n#: 5d843f7031c14f799bd56886af16313f 6f96176fe534473abd3d0a3b10886daf\n#: 775cb0f5f029464d8b6b265a6bd9fbcb 7f8c04030eb2428a8b6e3e4aa1434875\n#: 808f822d5cb846f8bf7e619119fb9318 92acb46014f34d0e94841db5fa7aee7f\n#: 93a5eb0806364fc79a03a21a7e1aae61 98b5b944f37445a483864fd0c3c1acc4\n#: 99ab73e65de34fa382f9740422544e20 a2e3210d3b93435d8ae28371d790b824\n#: a3d6d493a3b043b98c7cb1f8282d9733 a8ca4f38d35b49a399948cd811aa950a\n#: b718c1a0f6744595bea22305cb934b23 bbbec0ca7da34f32aab5fff3961bc220\n#: bf51c38c6b3b4c3aa9e4a844f049a028 c89bbe13e12949ddb0baa34db3c1e2dc\n#: cee800543a0646cca1e99c244818c547 d21544b4657c404689ea4a1442e7b770\n#: d540a50f31844489b476bc3b2eccf0bf df435d6f1108468683ceacd21cfd87c9\n#: e0d49fa814f943faac85b4230fc44880 ed76c68df9d6403bb3828c2fa2b236f3\n#: ef74eb0f02c24d33becc781ce950b651 f20c32d4888f4d029ee7074ede80e23a\n#: f5ce82fd58e648bd8434116561a19697 f6559ff8a2154209bc3e256c2035e51a\n#: fbd7fda4af014d3882244ca311699849 fc0e3ef690de498a853cfa1bbf8aa702\nmsgid \"1\"\nmsgstr \"\"\n\n#: ../../app1.rst:289 ../../app1.rst:291 ../../app1.rst:292 ../../app1.rst:293\n#: ../../app1.rst:295 06a775ff9e024c69b2b20b72b87e2f39\n#: 0dcfeff6364f486b85e82098cd35dad9 251e9b0cc0c1420fae3dd91f99f24d7f\n#: 3698b2725d17402fb0a6d21a9f8528a6 46a337a4a68e49d7a800dd9701077648\n#: 4ba8146f24be48239504f8a299500f64 4dda4b0faa7a41b4bd93757bfa5e48fc\n#: 52d30ea082894e04b0ccd40e6bafc7a5 5994e677f5c94c30828758452ab35e2c\n#: 6063573b774c440dabdd54208c398123 62ed92eea3bd495b99addd70a3fd7823\n#: 6d98e245478f48c590bdc7e8f8585eda 709d6cddbcef491aa2d2d653bb6ecb16\n#: 86e73f4e80894ea5b04fa62a9ca34165 9f9ddfd3cdab40c58298f9300c4e6ad0\n#: a8f2711acc19466397e196137cd3d96a bc6bd4d438e8412289b2d55436bd3341\n#: dbb1a8bf2fa344d9916b1ec4ebf075db ef81628962544a8ebf82a15aac960331\n#: f18b0d81b3da4760894d1814700e43c4 fe2557a2e37b4bf29c6cd13888e1ba55\nmsgid \"0\"\nmsgstr \"\"\n\n#: ../../app1.rst:290 1beaf7102f1945d8bbb04d397b9227f1\nmsgid \"preserve whitespace\"\nmsgstr \"空白を保持\"\n\n#: ../../app1.rst:291 4691c88b06074b38896de74a86973a95\nmsgid \"preserve images\"\nmsgstr \"画像を保持\"\n\n#: ../../app1.rst:291 b2eacea067054a2c89b01026f348d200\n#: cde51036a4774390b6b3b86bad72cebf d34b28c25d6a4b8eb72ae032050e8ef2\nmsgid \"n/a\"\nmsgstr \"\"\n\n#: ../../app1.rst:292 6280ef433e7648fd83936d5d9fabf2e3\nmsgid \"inhibit spaces\"\nmsgstr \"スペースの抑制\"\n\n#: ../../app1.rst:293 ffbb4fff9bc14f4b89c7138073298de3\nmsgid \"dehyphenate\"\nmsgstr \"ハイフネーション解除\"\n\n#: ../../app1.rst:294 1c61f64ea3c046aa98ef330907277d28\nmsgid \"clip to mediabox\"\nmsgstr \"メディアボックスにクリップ\"\n\n#: ../../app1.rst:295 46e9e87165ad4603ad27fca406580f85\nmsgid \"use CID instead of U+FFFD\"\nmsgstr \"\"\n\n#: ../../app1.rst:298 d03c9f5449f345a3b73490298a0485f9\nmsgid \"**search** refers to the text search function.\"\nmsgstr \"**検索** はテキスト検索機能を指します。\"\n\n#: ../../app1.rst:299 e69a3f6563a349f7ac389cad653d8f9f\nmsgid \"**\\\"json\\\"** is handled exactly like **\\\"dict\\\"** and is hence left out.\"\nmsgstr \"**「json」** は **「dict」** とまったく同様に処理されるため、省略されています。\"\n\n#: ../../app1.rst:300 00f7c04e64ee45e09727561d7a20c052\nmsgid \"\"\n\"**\\\"rawjson\\\"** is handled exactly like **\\\"rawdict\\\"** and is hence left\"\n\" out.\"\nmsgstr \"**「rawjson」** は **「rawdict」** とまったく同様に処理されるため、省略されています。\"\n\n#: ../../app1.rst:301 6b8b4b0d4438489eb25ff507f4d3b024\nmsgid \"\"\n\"An \\\"n/a\\\" specification means a value of 0 and setting this bit never \"\n\"has any effect on the output (but an adverse effect on performance).\"\nmsgstr \"「n/a」の指定は値が0であり、このビットを設定しても出力に影響を与えることはありません（ただしパフォーマンスに悪影響を及ぼす可能性があります）。\"\n\n#: ../../app1.rst:302 9e71d45dfa8a432a85b4c21b50596e46\nmsgid \"\"\n\"If you are not interested in images when using an output variant which \"\n\"includes them by default, then by all means set the respective bit off: \"\n\"You will experience a better performance and much lower space \"\n\"requirements.\"\nmsgstr \"画像を含む出力バリアントを使用する際に画像に興味がない場合、必ず該当するビットをオフに設定してください。これにより、パフォーマンスが向上し、スペース要件が大幅に削減されます。\"\n\n#: ../../app1.rst:304 4babe75226f64adeb13494c473d77bda\nmsgid \"To show the effect of `TEXT_INHIBIT_SPACES` have a look at this example::\"\nmsgstr \"`TEXT_INHIBIT_SPACES`  の効果を示すために、この例をご覧ください：\"\n\n#: ../../app1.rst:324 791593433363447884bf96a0f495a7ed\nmsgid \"Performance\"\nmsgstr \"パフォーマンス\"\n\n#: ../../app1.rst:325 0da8da4ddf0640e08849ffc214bbc392\nmsgid \"\"\n\"The text extraction methods differ significantly both: in terms of \"\n\"information they supply, and in terms of resource requirements and \"\n\"runtimes. Generally, more information of course means, that more \"\n\"processing is required and a higher data volume is generated.\"\nmsgstr \"テキスト抽出メソッドは、情報の提供方法とリソース要件、実行時間の両方で大きく異なります。一般的に、情報が多いほど処理が必要であり、より多くのデータが生成されることを意味します。\"\n\n#: ../../app1.rst:327 20586902aec24daab2b5f3efb0591035\n#, python-format\nmsgid \"\"\n\"Especially images have a **very significant** impact. Make sure to \"\n\"exclude them (via the *flags* parameter) whenever you do not need them. \"\n\"To process the below mentioned 2'700 total pages with default flags \"\n\"settings required 160 seconds across all extraction methods. When all \"\n\"images where excluded, less than 50% of that time (77 seconds) were \"\n\"needed.\"\nmsgstr \"\"\n\"特に画像は **非常に大きな** \"\n\"影響を持ちます。必要のない場合は、必ず画像を除外する（フラグパラメータを使用）ようにしてください。以下で言及されている2,700ページの総ページ数をデフォルトのフラグ設定で処理するには、全ての抽出メソッドで160秒が必要でした。画像をすべて除外した場合、その時間の50%未満（77秒）が必要でした。\"\n\n#: ../../app1.rst:329 2e8a95a956e644ac8d4696dce6c61cc2\nmsgid \"\"\n\"To begin with, all methods are **very fast** in relation to other \"\n\"products out there in the market. In terms of processing speed, we are \"\n\"not aware of a faster (free) tool. Even the most detailed method, \"\n\"RAWDICT, processes all 1'310 pages of the :ref:`AdobeManual` in less than\"\n\" 5 seconds (simple text needs less than 2 seconds here).\"\nmsgstr \"\"\n\"まず始めに、すべてのメソッドは市場にある他の製品と比べて **非常に高速** \"\n\"です。処理速度の観点から、より速い（無料の）ツールは私たちの知る限り存在しません。最も詳細なメソッドであるRAWDICTでも、 \"\n\":ref:`AdobeManual` リファレンスの1,310ページを5秒未満で処理できます（ここでは簡単なテキストは2秒未満で処理されます）。\"\n\n#: ../../app1.rst:331 b478d8651f884657b5f2968d78bde08e\nmsgid \"\"\n\"The following table shows average relative speeds (\\\"RSpeed\\\", baseline \"\n\"1.00 is TEXT), taken across ca. 1400 text-heavy and 1300 image-heavy \"\n\"pages.\"\nmsgstr \"以下の表は、約1400ページのテキストが多く、約1300ページが画像が多いページでの平均相対速度（ベースライン1.00はTEXT）を示しています。\"\n\n#: ../../app1.rst:334 e4cd1e92a16243b9bdc20d79c041f5ab\nmsgid \"Method\"\nmsgstr \"メソッド\"\n\n#: ../../app1.rst:334 e7cdf152a1914df4b50d9e29af7c6414\nmsgid \"RSpeed\"\nmsgstr \"平均相対\"\n\n#: ../../app1.rst:334 d842d0f8ae3a48d0a969867502970a0c\nmsgid \"Comments\"\nmsgstr \"コメント\"\n\n#: ../../app1.rst:334 48d44a0956cd43a1b911aeb4417696ea\nmsgid \"no images\"\nmsgstr \"画像なし\"\n\n#: ../../app1.rst:336 52d85a2f5b704adc8c686c36a9f92fe2\nmsgid \"TEXT\"\nmsgstr \"\"\n\n#: ../../app1.rst:336 ../../app1.rst:337 ../../app1.rst:340\n#: 3bcb90f59d8f4da58255a7a86093aa07 59f27de687b642ddb52e91f17533cc5b\n#: a0b2dcf2b2ef4bd7ad4cff46bb823559 db1033e32d794e808303b3da34f587ac\n#: f1cf54ba71c34f339ccf48d538136125\nmsgid \"1.00\"\nmsgstr \"\"\n\n#: ../../app1.rst:336 6dabc232af8f4901aea1c358a0ae9564\nmsgid \"no images, **plain** text, line breaks\"\nmsgstr \"画像なし、 **プレーン** テキスト、改行\"\n\n#: ../../app1.rst:337 23cec37141ab47548b08ce6a51c47532\nmsgid \"image bboxes (only), **block** level text with bboxes, line breaks\"\nmsgstr \"画像のバウンディングボックス（のみ）、 **ブロック** レベルのテキストとバウンディングボックス、改行\"\n\n#: ../../app1.rst:338 04eaefca5e1f41eda6d2831fd36c1a5d\n#: 4f0d944bd46143d298a7a366f9b35d36\nmsgid \"1.02\"\nmsgstr \"\"\n\n#: ../../app1.rst:338 f4c82b98aa294a4ba829c5ba6dd0b736\nmsgid \"no images, **word** level text with bboxes\"\nmsgstr \"画像なし、 **ワード** レベルのテキストとバウンディングボックス\"\n\n#: ../../app1.rst:339 6b2dcc5f62e242a3bc9579407a6568a1\n#: f95901f3f681472a947f2f30ee664a42\nmsgid \"2.72\"\nmsgstr \"\"\n\n#: ../../app1.rst:339 8a17afd3b00a478db3c1a02c3174167f\nmsgid \"no images, **char** level text, layout and font details\"\nmsgstr \"画像なし、**文字** レベルのテキスト、レイアウトとフォントの詳細\"\n\n#: ../../app1.rst:340 0f0de8a5134b47348c6bb22b8c2a813a\nmsgid \"3.32\"\nmsgstr \"\"\n\n#: ../../app1.rst:340 fa9159767f484518983dcfa06467eead\nmsgid \"**base64** images, **span** level text, no layout info\"\nmsgstr \"**base64** 画像、 **スパン** レベルのテキスト、レイアウト情報なし\"\n\n#: ../../app1.rst:341 efb4a91cc528491c86864634ab1c8962\nmsgid \"3.54\"\nmsgstr \"\"\n\n#: ../../app1.rst:341 612c89df3d5046f399cd591cbecfa4d1\nmsgid \"**base64** images, **span** level text, layout and font details\"\nmsgstr \"**base64画像** 、 **スパン** レベルのテキスト、レイアウトとフォントの詳細\"\n\n#: ../../app1.rst:341 82007c0df4b04de7b342be7f608efe6d\nmsgid \"1.01\"\nmsgstr \"\"\n\n#: ../../app1.rst:342 22c93672d1754b45979767b416822fc9\nmsgid \"DICT\"\nmsgstr \"\"\n\n#: ../../app1.rst:342 73dbc0957638492db3cb33c44afc4ff0\nmsgid \"3.93\"\nmsgstr \"\"\n\n#: ../../app1.rst:342 081b9112703a4d6f8b31780c1f8d4708\nmsgid \"**binary** images, **span** level text, layout and font details\"\nmsgstr \"**バイナリ** 画像、 **スパン** レベルのテキスト、レイアウトとフォントの詳細\"\n\n#: ../../app1.rst:342 c0b41f51a7214a12a3efec0ecbba1e5f\nmsgid \"1.04\"\nmsgstr \"\"\n\n#: ../../app1.rst:343 5de542c1e80e424294d32a859e17ca43\nmsgid \"RAWDICT\"\nmsgstr \"\"\n\n#: ../../app1.rst:343 8bec4991b902406e931341dbb186a6d0\nmsgid \"4.50\"\nmsgstr \"\"\n\n#: ../../app1.rst:343 c4f7dd03bce440c6a1820660104e7a31\nmsgid \"**binary** images, **char** level text, layout and font details\"\nmsgstr \"**バイナリ** 画像、**文字** レベルのテキスト、レイアウトとフォントの詳細\"\n\n#: ../../app1.rst:343 71321cf4b722412abdf5f6eaa793ec1d\nmsgid \"1.68\"\nmsgstr \"\"\n\n#: ../../app1.rst:346 e12d6cb6be1b4701a2b213d3f27afa27\n#, python-format\nmsgid \"\"\n\"As mentioned: when excluding image extraction (last column), the relative\"\n\" speeds are changing drastically: except RAWDICT and XML, the other \"\n\"methods are almost equally fast, and RAWDICT requires 40% less execution \"\n\"time than the **now slowest XML**.\"\nmsgstr \"\"\n\"前述のように、画像の抽出を除外する場合（最後の列）、相対速度は大きく変わります。RAWDICTとXMLを除いて、他のメソッドはほぼ同じ速さであり、RAWDICTは\"\n\" **今では遅いXML** よりも40％少ない実行時間を必要とします。\"\n\n#: ../../app1.rst:348 6750dde161a54ad6adb3ada9203f0253\nmsgid \"Look at chapter **Appendix 1** for more performance information.\"\nmsgstr \"もっとパフォーマンス情報については、 **付録1章** をご覧ください。\"\n\n#: ../../footer.rst:60 05804a3786b14f7fa5098ddfaf65f873\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/app2.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ce178b1ad1a74ee4b4c40ab17fe257ae\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 419c2281e2e246658e42483c0a1fc0d6\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 ebb04a69cb76400eb6074b4c9c39ec1f\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../app2.rst:7 64d6bda691354b77987e85bd9a04296b\nmsgid \"Appendix 2: Considerations on Embedded Files\"\nmsgstr \"付録2：埋め込みファイルに関する考慮事項\"\n\n#: ../../app2.rst:8 d15d38307aa649f983ce5b15f6c6a3fd\nmsgid \"\"\n\"This chapter provides some background on embedded files support in \"\n\"PyMuPDF.\"\nmsgstr \"この章では、PyMuPDFにおける埋め込みファイルのサポートに関する背景情報を提供します。\"\n\n#: ../../app2.rst:11 20abd6d046f14fb19306663331d645c0\nmsgid \"General\"\nmsgstr \"一般\"\n\n#: ../../app2.rst:12 7dd965f6d81847bb95992e2db8036f26\nmsgid \"\"\n\"Starting with version 1.4, PDF supports embedding arbitrary files as part\"\n\" (\\\"Embedded File Streams\\\") of a PDF document file (see chapter \\\"7.11.4\"\n\" Embedded File Streams\\\", pp. 103 of the :ref:`AdobeManual`).\"\nmsgstr \"\"\n\"バージョン1.4から、PDFはPDFドキュメントファイルの一部として任意のファイルを埋め込むことができるようになりました（「7.11.4 \"\n\"埋め込みファイルストリーム」章を参照、 :ref:`AdobeManual` リファレンスの103ページ）。\"\n\n#: ../../app2.rst:15 9673011500be45a5b2780b4f29fcb427\nmsgid \"\"\n\"In many aspects, this is comparable to concepts also found in ZIP files \"\n\"or the OLE technique in MS Windows. PDF embedded files do, however, *not*\"\n\" support directory structures as does the ZIP format. An embedded file \"\n\"can in turn contain embedded files itself.\"\nmsgstr \"\"\n\"多くの側面で、これはZIPファイルやMS \"\n\"WindowsのOLE技術でも見られる概念に類似しています。ただし、PDFの埋め込みファイルはZIP形式とは異なり、ディレクトリ構造をサポート \"\n\"*しません* 。埋め込みファイル自体もさらに埋め込みファイルを含むことができます。\"\n\n#: ../../app2.rst:17 21d8ec87be9d4021aec6fa647434f686\nmsgid \"\"\n\"Advantages of this concept are that embedded files are under the PDF \"\n\"umbrella, benefitting from its permissions / password protection and \"\n\"integrity aspects: all data, which a PDF may reference or even may be \"\n\"dependent on, can be bundled into it and so form a single, consistent \"\n\"unit of information.\"\nmsgstr \"このコンセプトの利点は、埋め込みファイルがPDFの枠組みに含まれ、その権限/パスワード保護および整合性の側面を活用できることです。PDFが参照するデータや依存する可能性があるデータはすべて、PDFにまとめて1つの一貫した情報ユニットを形成することができます。\"\n\n#: ../../app2.rst:19 27f0645490d24afd94260b80f51190e2\nmsgid \"\"\n\"In addition to embedded files, PDF 1.7 adds *collections* to its support \"\n\"range. This is an advanced way of storing and presenting meta information\"\n\" (i.e. arbitrary and extensible properties) of embedded files.\"\nmsgstr \"\"\n\"埋め込みファイルに加えて、PDF 1.7は *コレクション* \"\n\"をサポート範囲に追加しました。これは、埋め込みファイルのメタ情報（任意で拡張可能なプロパティ）を格納し、表示する高度な方法です\"\n\n#: ../../app2.rst:22 6461638e9a0c4f6d8dd9404f02cae88c\nmsgid \"MuPDF Support\"\nmsgstr \"MuPDFのサポート\"\n\n#: ../../app2.rst:23 7a4bd68162ca408082e0fe0981edfb0e\nmsgid \"\"\n\"After adding initial support for collections (portfolios) and \"\n\"*/EmbeddedFiles* in MuPDF version 1.11, this support was dropped again in\"\n\" version 1.15.\"\nmsgstr \"\"\n\"MuPDFバージョン1.11でコレクション（ポートフォリオ）と */EmbeddedFiles* \"\n\"への初期サポートを追加した後、このサポートはバージョン1.15で再び削除されました。\"\n\n#: ../../app2.rst:25 5d971b234a074542a7fe67243445baac\nmsgid \"\"\n\"As a consequence, the cli utility *mutool* no longer offers access to \"\n\"embedded files.\"\nmsgstr \"その結果、cliユーティリティ *mutool* ではもはや埋め込みファイルにアクセスできなくなりました。\"\n\n#: ../../app2.rst:27 121edfcf69c34685bbfd37adf5eed763\nmsgid \"\"\n\"PyMuPDF -- having implemented an */EmbeddedFiles* API in response in its \"\n\"version 1.11.0 -- was therefore forced to change gears starting with its \"\n\"version 1.16.0 (we never published a MuPDF v1.15.x compatible PyMuPDF).\"\nmsgstr \"\"\n\"PyMuPDFは、バージョン1.11.0で */EmbeddedFiles*  \"\n\"APIを実装したため、バージョン1.16.0からギアを変更せざるを得なくなりました（MuPDF \"\n\"v1.15.x互換のPyMuPDFは公開されませんでした）。\"\n\n#: ../../app2.rst:29 179951424a4d4e85899ade12ee77d71b\nmsgid \"\"\n\"We are now maintaining our own code basis supporting embedded files. This\"\n\" code makes use of basic MuPDF dictionary and array functions only.\"\nmsgstr \"私たちは現在、埋め込みファイルをサポートする独自のコードベースを維持しています。このコードは、基本的なMuPDFの辞書と配列の機能のみを使用しています。\"\n\n#: ../../app2.rst:32 9f89c97ca1ff44a59f6b127c6a772547\nmsgid \"PyMuPDF Support\"\nmsgstr \"PyMuPDFのサポート\"\n\n#: ../../app2.rst:33 cdda1b955d134a22825d992b8d121028\nmsgid \"\"\n\"We continue to support the full old API with respect to embedded files --\"\n\" with only minor, cosmetic changes.\"\nmsgstr \"私たちは、埋め込みファイルに関する古いAPIを、わずかな見た目の変更のみを行いながら引き続きサポートしています。\"\n\n#: ../../app2.rst:35 77890c822c424653bfeba8e464bc73a5\nmsgid \"\"\n\"There even also is a new function, which delivers a list of all names \"\n\"under which embedded data are registered in a PDF, \"\n\":meth:`Document.embfile_names`.\"\nmsgstr \"\"\n\"また、PDF内の埋め込みデータが登録されているすべての名前のリストを返す新しい関数も存在します。:meth:`Document.embfile_names`\"\n\" です。\"\n\n#: ../../footer.rst:60 0a64be666c834c3aaf01bfaa636d73ad\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/app3.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 6a4f4d9aba284482b17f5158db768103\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 ca8dbdbe51984f3d841ffa5414e59d9f\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 acc2a6d07e304bfeb3e884b734b79031\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../app3.rst:7 635cfbba07cc4d7fafc89714611a9318\nmsgid \"Appendix 3: Assorted Technical Information\"\nmsgstr \"付録3：さまざまな技術情報\"\n\n#: ../../app3.rst:8 4769a2a2c2d84bf2b3ee95f7b4bf80e3\nmsgid \"\"\n\"This section deals with various technical topics, that are not \"\n\"necessarily related to each other.\"\nmsgstr \"このセクションでは、必ずしも関連しないさまざまな技術的なトピックについて取り扱います。\"\n\n#: ../../app3.rst:15 ec8a4400984a477ca650493b54e8d584\nmsgid \"Image Transformation Matrix\"\nmsgstr \"画像変換行列\"\n\n#: ../../app3.rst:16 e34c11954ed74384aadeee4920e21331\nmsgid \"\"\n\"Starting with version 1.18.11, the image transformation matrix is \"\n\"returned by some methods for text and image extraction: \"\n\":meth:`Page.get_text` and :meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\"バージョン1.18.11から、テキストと画像の抽出に関する一部のメソッドで画像変換行列が返されます：:meth:`Page.get_text` \"\n\"および :meth:`Page.get_image_bbox` 。\"\n\n#: ../../app3.rst:18 b72e0ef8b41e494489563ac4faed2c68\nmsgid \"\"\n\"The transformation matrix contains information about how an image was \"\n\"transformed to fit into the rectangle (its \\\"boundary box\\\" = \\\"bbox\\\") \"\n\"on some document page. By inspecting the image's bbox on the page and \"\n\"this matrix, one can determine for example, whether and how the image is \"\n\"displayed scaled or rotated on a page.\"\nmsgstr \"変換行列には、画像が文書ページ上の矩形（「境界ボックス」=「bbox」）に適合するためにどのように変換されたかに関する情報が含まれています。ページ上の画像のbboxとこの行列を検査することにより、例えば画像がページ上で拡大縮小または回転して表示されるかどうか、そしてどのように表示されるかを判断することができます。\"\n\n#: ../../app3.rst:20 d13c3c9d78be4c7baf9efb9708ddda02\nmsgid \"\"\n\"The relationship between image dimension and its bbox on a page is the \"\n\"following:\"\nmsgstr \"画像の寸法とページ上のbboxとの関係は次のとおりです：\"\n\n#: ../../app3.rst:24 24589c9043924415af09f8353878e2fa\nmsgid \"Using the original image's width and height,\"\nmsgstr \"元の画像の幅と高さを使用して、\"\n\n#: ../../app3.rst:23 5fcd053e3c4745e3ac9752cf844e3899\nmsgid \"define the image rectangle `imgrect = pymupdf.Rect(0, 0, width, height)`\"\nmsgstr \"画像の矩形を `imgrect = pymupdf.Rect(0, 0, width, height)` と定義します。\"\n\n#: ../../app3.rst:24 7a8b751ef2f84e4eb0d4f3bffd76a9ba\nmsgid \"\"\n\"define the \\\"shrink matrix\\\" `shrink = pymupdf.Matrix(1/width, 0, 0, \"\n\"1/height, 0, 0)`.\"\nmsgstr \"「縮小行列」を `shrink = pymupdf.Matrix(1/width, 0, 0,1/height, 0, 0)` と定義します。\"\n\n#: ../../app3.rst:26 be4e302d72a047d9ad89310d107eb3e3\nmsgid \"\"\n\"Transforming the image rectangle with its shrink matrix, will result in \"\n\"the unit rectangle: `imgrect * shrink = pymupdf.Rect(0, 0, 1, 1)`.\"\nmsgstr \"\"\n\"画像矩形を縮小行列で変換すると、単位矩形が得られます： `imgrect * shrink = pymupdf.Rect(0, 0, 1, 1)`\"\n\" 。\"\n\n#: ../../app3.rst:28 cd872603d2774c46a06dda3917faa61c\nmsgid \"\"\n\"Using the image **transformation matrix** \\\"transform\\\", the following \"\n\"steps will compute the bbox::\"\nmsgstr \"画像 **変換行列** 「transform」を使用して、次の手順でbboxを計算します：\"\n\n#: ../../app3.rst:34 b2fb7d53a3f8485390e8070c74877726\nmsgid \"\"\n\"Inspecting the matrix product `shrink * transform` will reveal all \"\n\"information about what happened to the image rectangle to make it fit \"\n\"into the bbox on the page: rotation, scaling of its sides and translation\"\n\" of its origin. Let us look at an example:\"\nmsgstr \"\"\n\"行列の積 `shrink * transform` \"\n\"を検査することで、画像矩形がページ上のbboxに適合させるために何が起こったかに関するすべての情報が明らかになります。回転、辺のスケーリング、および原点の移動です。例を見てみましょう：\"\n\n#: ../../app3.rst:71 5677aee6873b459a93e06865c3302434\nmsgid \"PDF Base 14 Fonts\"\nmsgstr \"PDFベース14フォント\"\n\n#: ../../app3.rst:72 3df5aeca5c3f4ccf9325390f51398b06\nmsgid \"\"\n\"The following 14 builtin font names **must be supported by every PDF \"\n\"viewer** application. They are available as a dictionary, which maps \"\n\"their full names amd their abbreviations in lower case to the full font \"\n\"basename. Wherever a **fontname** must be provided in PyMuPDF, any **key \"\n\"or value** from the dictionary may be used::\"\nmsgstr \"\"\n\"以下の14の組み込みフォント名は、**すべてのPDFビューアアプリケーションでサポートされる必要があります** \"\n\"。これらは辞書として利用可能で、それぞれのフルネームとその略称を小文字で完全な **フォントベース名** \"\n\"にマッピングします。PyMuPDFでフォント名を提供する必要がある場合、辞書からの任意の **キーまたは値** を使用できます：\"\n\n#: ../../app3.rst:105 a5f070fd9c6546bfa33ed69a6639683e\nmsgid \"\"\n\"In contrast to their obligation, not all PDF viewers support these fonts \"\n\"correctly and completely -- this is especially true for Symbol and \"\n\"ZapfDingbats. Also, the glyph (visual) images will be specific to every \"\n\"reader.\"\nmsgstr \"義務とは対照的に、すべてのPDFビューアがこれらのフォントを正確かつ完全にサポートしているわけではありません。特にSymbolとZapfDingbatsについては、これが特に当てはまります。また、グリフ（視覚的な）イメージは、それぞれの閲覧者に固有のものになります。\"\n\n#: ../../app3.rst:107 6842b8433a9547b6a82435e36e06fb70\nmsgid \"\"\n\"To see how these fonts can be used -- including the **CJK built-in** \"\n\"fonts -- look at the table in :meth:`Page.insert_font`.\"\nmsgstr \"\"\n\"これらのフォントがどのように使用されるか（ **CJK組み込みフォント** も含めて）、:meth:`Page.insert_font` \"\n\"のテーブルをご覧ください。\"\n\n#: ../../app3.rst:114 e3268f776b5a4b06a629bf9f9c25828c\nmsgid \"Adobe PDF References\"\nmsgstr \"Adobe PDFリファレンス\"\n\n#: ../../app3.rst:116 17a3fab0bc0d4dcc9ab758228d6be220\nmsgid \"\"\n\"This PDF Reference manual published by Adobe is frequently quoted \"\n\"throughout this documentation. It can be viewed and downloaded from \"\n\"`opensource.adobe.com <https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_.\"\nmsgstr \"\"\n\"Adobeによって公開されたこのPDFリファレンスマニュアルは、このドキュメンテーション全体で頻繁に引用されています。 `こちら \"\n\"<https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_ から閲覧およびダウンロードが可能です。\"\n\n#: ../../app3.rst:125 c4f0367b9f574635971bdcbd0d2ca6fb\nmsgid \"Using Python Sequences as Arguments in PyMuPDF\"\nmsgstr \"PythonシーケンスをPyMuPDFで引数として使用する場合\"\n\n#: ../../app3.rst:126 3d89e490fbf7457284a6ae3fcc59d506\nmsgid \"\"\n\"When PyMuPDF objects and methods require a Python **list** of numerical \"\n\"values, other Python **sequence types** are also allowed. Python classes \"\n\"are said to implement the **sequence protocol**, if they have a \"\n\"`__getitem__()` method.\"\nmsgstr \"\"\n\"PyMuPDFのオブジェクトとメソッドが数値の値のPython **リスト** を必要とする場合、他のPython **シーケンス型** \"\n\"も許可されています。Pythonのクラスは、`__getitem__()` メソッドを持つ場合、**シーケンスプロトコル** \"\n\"を実装していると言われています。\"\n\n#: ../../app3.rst:128 bd7b31cc19e54f17857367f55587a14e\nmsgid \"\"\n\"This basically means, you can interchangeably use Python *list* or \"\n\"*tuple* or even *array.array*, *numpy.array* and *bytearray* types in \"\n\"these cases.\"\nmsgstr \"\"\n\"基本的には、これらの場合にPythonの *リスト* や *タプル* 、*array.array* 、*numpy.array* \"\n\"、*bytearray* 型を互換性を持って使用できることを意味しています。\"\n\n#: ../../app3.rst:130 cc50a15ebc1a45c3ba30d1d2615eeb1b\nmsgid \"For example, specifying a sequence `\\\"s\\\"` in any of the following ways\"\nmsgstr \"例えば、次のいずれかの方法でシーケンス `\\\"s\\\"` を指定すると\"\n\n#: ../../app3.rst:132 ba9e965ec2384d4aaaacc84791926237\nmsgid \"`s = [1, 2]` -- a list\"\nmsgstr \"`s = [1, 2]` – リスト\"\n\n#: ../../app3.rst:133 a1b8ab6b13fe41159b6b656dd7debae0\nmsgid \"`s = (1, 2)` -- a tuple\"\nmsgstr \"`s = (1, 2)` – タプル\"\n\n#: ../../app3.rst:134 c68b9c09194b47c78b57fa6656c1ffea\nmsgid \"`s = array.array(\\\"i\\\", (1, 2))` -- an array.array\"\nmsgstr \"`s = array.array(\\\"i\\\", (1, 2))`  – array.array\"\n\n#: ../../app3.rst:135 3a8427a9db4d4436a94ddb0536f292f1\nmsgid \"`s = numpy.array((1, 2))` -- a numpy array\"\nmsgstr \"`s = numpy.array((1, 2))` – numpy配列\"\n\n#: ../../app3.rst:136 33fa18c1c81f441890f097d10863edf5\nmsgid \"`s = bytearray((1, 2))` -- a bytearray\"\nmsgstr \"`s = bytearray((1, 2))` – bytearray\"\n\n#: ../../app3.rst:138 723f57c7a65942108b9add6c3d6123e3\nmsgid \"will make it usable in the following example expressions:\"\nmsgstr \"これによって、以下の例の式で使用可能になります：\"\n\n#: ../../app3.rst:140 7e8310592817456db2c249694ee67e4c\nmsgid \"`pymupdf.Point(s)`\"\nmsgstr \"\"\n\n#: ../../app3.rst:141 ef9f88aff26342c1b8b682b45b03735a\nmsgid \"`pymupdf.Point(x, y) + s`\"\nmsgstr \"\"\n\n#: ../../app3.rst:142 0a05dd917a434de3b831f92af1f206d8\nmsgid \"`doc.select(s)`\"\nmsgstr \"\"\n\n#: ../../app3.rst:144 e7823b7a8a1642dea3763c0d1fcf75df\nmsgid \"\"\n\"Similarly with all geometry objects :ref:`Rect`, :ref:`IRect`, \"\n\":ref:`Matrix` and :ref:`Point`.\"\nmsgstr \"\"\n\"同様に、すべてのジオメトリオブジェクト :ref:`Rect` 、:ref:`IRect` 、:ref:`Matrix` 、 \"\n\":ref:`Point` も同様です。\"\n\n#: ../../app3.rst:146 e62989d3437d4c809e933779b0b4f916\nmsgid \"\"\n\"Because all PyMuPDF geometry classes themselves are special cases of \"\n\"sequences, they (with the exception of :ref:`Quad` -- see below) can be \"\n\"freely used where numerical sequences can be used, e.g. as arguments for \"\n\"functions like *list()*, *tuple()*, *array.array()* or *numpy.array()*. \"\n\"Look at the following snippet to see this work.\"\nmsgstr \"\"\n\"なぜなら、すべてのPyMuPDFジオメトリクラス自体がシーケンスの特殊なケースであるため、（ :ref:`Quad`  \"\n\"を除く）数値のシーケンスが使用可能な場所で自由に使用できるからです。例えば、 *list()* 、 *tuple()* 、 \"\n\"*array.array()* \"\n\n#: ../../app3.rst:163 cd48dbd7918c44989e77808c4e3d2273\nmsgid \"\"\n\":ref:`Quad` is a Python sequence object as well and has a length of 4. \"\n\"Its items however are :data:`point_like` -- not numbers. Therefore, the \"\n\"above remarks do not apply.\"\nmsgstr \"\"\n\":ref:`Quad` もPythonのシーケンスオブジェクトであり、長さが4です。ただし、そのアイテムは数値ではなく \"\n\":data:`point_like` です。したがって、上記の注釈は適用されません。\"\n\n#: ../../app3.rst:170 a239cac6134847fa88f5fdc763bc0034\nmsgid \"Ensuring Consistency of Important Objects in PyMuPDF\"\nmsgstr \"重要なオブジェクトの整合性を確保するためのPyMuPDF\"\n\n#: ../../app3.rst:171 94db2c4ab30441ca82c022e184f57bf9\nmsgid \"\"\n\"PyMuPDF is a Python binding for the C library MuPDF. While a lot of \"\n\"effort has been invested by MuPDF's creators to approximate some sort of \"\n\"an object-oriented behavior, they certainly could not overcome basic \"\n\"shortcomings of the C language in that respect.\"\nmsgstr \"PyMuPDFは、CライブラリMuPDFのPythonバインディングです。MuPDFの開発者たちは、ある種のオブジェクト指向の振る舞いを模倣するために多くの努力をしてきましたが、C言語の基本的な制約を克服することはできませんでした。\"\n\n#: ../../app3.rst:173 7cf69b3e065341f0a20a77da785f6027\nmsgid \"\"\n\"Python on the other hand implements the OO-model in a very clean way. The\"\n\" interface code between PyMuPDF and MuPDF consists of two basic files: \"\n\"*pymupdf.py* and *fitz_wrap.c*. They are created by the excellent SWIG \"\n\"tool for each new version.\"\nmsgstr \"\"\n\"一方で、Pythonは非常にクリーンな方法でOOモデルを実装しています。PyMuPDFとMuPDFの間のインターフェースコードは、基本的に2つのファイルから構成されています：\"\n\" *pymupdf.py* と *fitz_wrap.c* 。これらは、新バージョンごとに優れたSWIGツールによって作成されます。\"\n\n#: ../../app3.rst:175 05bb51a7321b4ecd8dc9585c3e3f3b8c\nmsgid \"\"\n\"When you use one of PyMuPDF's objects or methods, this will result in \"\n\"execution of some code in *pymupdf.py*, which in turn will call some C \"\n\"code compiled with *fitz_wrap.c*.\"\nmsgstr \"\"\n\"PyMuPDFのオブジェクトやメソッドのいずれかを使用すると、これにより *pymupdf.py* でいくつかのコードが実行され、それがさらに \"\n\"*fitz_wrap.c* でコンパイルされたCコードを呼び出します。\"\n\n#: ../../app3.rst:177 0d437950b2ba4e1cbdfd6ccd5a4b5f4b\nmsgid \"\"\n\"Because SWIG goes a long way to keep the Python and the C level in sync, \"\n\"everything works fine, if a certain set of rules is being strictly \"\n\"followed. For example: **never access** a :ref:`Page` object, after you \"\n\"have closed (or deleted or set to ``None``) the owning :ref:`Document`. \"\n\"Or, less obvious: **never access** a page or any of its children (links \"\n\"or annotations) after you have executed one of the document methods \"\n\"*select()*, *delete_page()*, *insert_page()* ... and more.\"\nmsgstr \"\"\n\"SWIGはPythonとCレベルを同期させるために大いに役立っているため、一定のルールが厳密に守られる限り、すべてが正常に動作します。例えば、所有している\"\n\" :ref:`ドキュメント` を閉じたり（または削除したり、Noneに設定したり）した後に :ref:`Page` オブジェクトに \"\n\"**アクセスしないでください** 。また、より明確な例では、 *select()* 、*delete_page()* 、 \"\n\"*insert_page()* などのドキュメントメソッドを実行した後にページやその子要素（リンクや注釈など）に **アクセスしないでください**\"\n\" 。\"\n\n#: ../../app3.rst:179 740cda1605364f24b13938ce08977597\nmsgid \"\"\n\"But just no longer accessing invalidated objects is actually not enough: \"\n\"They should rather be actively deleted entirely, to also free C-level \"\n\"resources (meaning allocated memory).\"\nmsgstr \"ただし、無効なオブジェクトへのアクセスをやめるだけでは実際には十分ではありません。これらのオブジェクトは、Cレベルのリソース（割り当てられたメモリ）も解放するために、完全に削除されるべきです。\"\n\n#: ../../app3.rst:181 9f8e966b70d34ecfabbaf171069a4cca\nmsgid \"\"\n\"The reason for these rules lies in the fact that there is a hierarchical \"\n\"2-level one-to-many relationship between a document and its pages and \"\n\"also between a page and its links / annotations. To maintain a consistent\"\n\" situation, any of the above actions must lead to a complete reset -- in \"\n\"**Python and, synchronously, in C**.\"\nmsgstr \"\"\n\"これらのルールの理由は、ドキュメントとそのページ、およびページとそのリンク/注釈の間に階層的な2段階の1対多の関係があるためです。一貫した状況を維持するために、上記のアクションのいずれもが\"\n\" **PythonとCの両方で** 完全なリセットを引き起こさなければなりません。\"\n\n#: ../../app3.rst:183 a7f44e6e345e43358b3a79b7c052cd44\nmsgid \"SWIG cannot know about this and consequently does not do it.\"\nmsgstr \"SWIGはこれを知ることはできないため、それを実行しません。\"\n\n#: ../../app3.rst:185 9f2723ebd7904acaa02811c5490da7a1\nmsgid \"\"\n\"The required logic has therefore been built into PyMuPDF itself in the \"\n\"following way.\"\nmsgstr \"必要な論理はしたがって、PyMuPDF自体に以下のように組み込まれています。\"\n\n#: ../../app3.rst:187 fd908d3774f14df1b4fb95b1d9afb2f4\nmsgid \"\"\n\"If a page \\\"loses\\\" its owning document or is being deleted itself, all \"\n\"of its currently existing annotations and links will be made unusable in \"\n\"Python, and their C-level counterparts will be deleted and deallocated.\"\nmsgstr \"ページが所有するドキュメントを失ったり、それ自体が削除されると、現在存在するすべての注釈とリンクはPythonで使用できなくなり、それらのCレベルの対応部分が削除されて解放されます。\"\n\n#: ../../app3.rst:189 25e9288e71cb47e586bca43a0f860fb2\nmsgid \"\"\n\"If a document is closed (or deleted or set to ``None``) or if its \"\n\"structure has changed, then similarly all currently existing pages and \"\n\"their children will be made unusable, and corresponding C-level deletions\"\n\" will take place. \\\"Structure changes\\\" include methods like *select()*, \"\n\"*delePage()*, *insert_page()*, *insert_pdf()* and so on: all of these \"\n\"will result in a cascade of object deletions.\"\nmsgstr \"\"\n\"ドキュメントが閉じられたり（または削除されたり、 ``None`` \"\n\"に設定されたり）したり、構造が変更されたりすると、同様に現在存在するすべてのページとその子要素は使用できなくなり、対応するCレベルの削除が行われます。「構造の変更」とは、\"\n\" *select()* 、 *delete_page()* 、 *insert_page()* 、 *insert_pdf()* \"\n\"などのメソッドを含みます。これらのすべてはオブジェクトの削除の連鎖を引き起こします。\"\n\n#: ../../app3.rst:191 54df808609fb4f028e086d3d8e9d2f3b\nmsgid \"\"\n\"The programmer will normally not realize any of this. If he, however, \"\n\"tries to access invalidated objects, exceptions will be raised.\"\nmsgstr \"プログラマーは通常、これらのいずれも気づかないでしょう。ただし、無効なオブジェクトにアクセスしようとすると、例外が発生します。\"\n\n#: ../../app3.rst:193 563eaa2415b64daabefd0a63dca2bd34\nmsgid \"\"\n\"Invalidated objects cannot be directly deleted as with Python statements \"\n\"like *del page* or *page = None*, etc. Instead, their *__del__* method \"\n\"must be invoked.\"\nmsgstr \"\"\n\"無効なオブジェクトは、 *del page* または *page = None* \"\n\"などのPythonステートメントで直接削除することはできません。代わりに、その *__del__* メソッドを呼び出す必要があります。\"\n\n#: ../../app3.rst:195 e5c1f65e4ac6489ca69e7ebe7b57195c\nmsgid \"\"\n\"All pages, links and annotations have the property *parent*, which points\"\n\" to the owning object. This is the property that can be checked on the \"\n\"application level: if *obj.parent == None* then the object's parent is \"\n\"gone, and any reference to its properties or methods will raise an \"\n\"exception informing about this \\\"orphaned\\\" state.\"\nmsgstr \"\"\n\"すべてのページ、リンク、注釈には、所有するオブジェクトを指す *親* \"\n\"プロパティがあります。これはアプリケーションレベルでチェックできるプロパティです： *obj.parent == None* \"\n\"ならば、そのオブジェクトの親は存在せず、そのプロパティやメソッドへの参照は例外を発生させてこの「孤立」した状態について通知します。\"\n\n#: ../../app3.rst:197 d631125a6585402abe79abea78f9a828\nmsgid \"A sample session:\"\nmsgstr \"サンプルセッション：\"\n\n#: ../../app3.rst:214 9f74080977604195aab03d9e5d402dd0\nmsgid \"This shows the cascading effect:\"\nmsgstr \"これは連鎖効果を示しています。\"\n\n#: ../../app3.rst:231 2b8666687af94a81ad4c68af9a5f9e6b\nmsgid \"\"\n\"Objects outside the above relationship are not included in this \"\n\"mechanism. If you e.g. created a table of contents by *toc = \"\n\"doc.get_toc()*, and later close or change the document, then this cannot \"\n\"and does not change variable *toc* in any way. It is your responsibility \"\n\"to refresh such variables as required.\"\nmsgstr \"\"\n\"上記の関係外のオブジェクトは、このメカニズムに含まれていません。たとえば、 `toc = doc.get_toc()`  \"\n\"のように目次を作成し、後で文書を閉じたり変更したりする場合、これは変数 toc \"\n\"をどのようにも変更しません。必要に応じてそのような変数を更新する責任はあなたにあります。\"\n\n#: ../../app3.rst:238 d3876be10a3649c3b2ab6f5d57c69ce0\nmsgid \"Design of Method :meth:`Page.show_pdf_page`\"\nmsgstr \"メソッド  :meth:`Page.show_pdf_page`  の設計\"\n\n#: ../../app3.rst:241 3180435e0924483181b1a26a8cba5f32\nmsgid \"Purpose and Capabilities\"\nmsgstr \"目的と機能\"\n\n#: ../../app3.rst:243 bf37b033f7ca48c58de17d9d2051b74d\nmsgid \"\"\n\"The method displays an image of a (\\\"source\\\") page of another PDF \"\n\"document within a specified rectangle of the current (\\\"containing\\\", \"\n\"\\\"target\\\") page.\"\nmsgstr \"このメソッドは、現在の（「含まれる」、「ターゲット」）ページの指定された矩形内に別のPDF文書の（「ソース」）ページの画像を表示します。\"\n\n#: ../../app3.rst:245 6f60a372555246208767f53ea2bfd820\nmsgid \"\"\n\"**In contrast** to :meth:`Page.insert_image`, this display is vector-\"\n\"based and hence remains accurate across zooming levels.\"\nmsgstr \":meth:`Page.insert_image`  **とは異なり** 、この表示はベクターベースであり、ズームレベルを超えて正確に保たれます。\"\n\n#: ../../app3.rst:246 998a98e328ec42aba32d728c2b4334e4\nmsgid \"\"\n\"**Just like** :meth:`Page.insert_image`, the size of the display is \"\n\"adjusted to the given rectangle.\"\nmsgstr \":meth:`Page.insert_image`  **と同様に** 、表示のサイズは指定された矩形に調整されます。\"\n\n#: ../../app3.rst:248 e75e8ccc88234308a5ec9fa48fa086f2\nmsgid \"The following variations of the display are currently supported:\"\nmsgstr \"現在、次のバリエーションの表示がサポートされています：\"\n\n#: ../../app3.rst:250 d8cc5e5d21b84c21b682d4ab99c0d9df\nmsgid \"\"\n\"Bool parameter `\\\"keep_proportion\\\"` controls whether to maintain the \"\n\"aspect ratio (default) or not.\"\nmsgstr \"Bool パラメーター `\\\"keep_proportion\\\"` はアスペクト比を保持するかどうかを制御します（デフォルト）。\"\n\n#: ../../app3.rst:251 186e450479084963890fe9da769fab60\nmsgid \"\"\n\"Rectangle parameter `\\\"clip\\\"` restricts the visible part of the source \"\n\"page rectangle. Default is the full page.\"\nmsgstr \"矩形パラメーター `\\\"clip\\\"` はソースページの矩形の可視部分を制限します。デフォルトはフルページです。\"\n\n#: ../../app3.rst:252 4f399ef693d44c11953293c07415b9ae\nmsgid \"\"\n\"float `\\\"rotation\\\"` rotates the display by an arbitrary angle (degrees).\"\n\" If the angle is not an integer multiple of 90, only 2 of the 4 corners \"\n\"may be positioned on the target border if also `\\\"keep_proportion\\\"` is \"\n\"true.\"\nmsgstr \"\"\n\"float `\\\"rotation\\\"` \"\n\"は表示を任意の角度（度）で回転させます。角度が90の倍数でない場合、`\\\"keep_proportion\\\"` も true \"\n\"の場合、ターゲットの境界に4つのうち2つのコーナーのみが配置される場合があります。\"\n\n#: ../../app3.rst:253 64850af2d5454c3b8c0cc5f82512df49\nmsgid \"\"\n\"Bool parameter `\\\"overlay\\\"` controls whether to put the image on top \"\n\"(foreground, default) of current page content or not (background).\"\nmsgstr \"\"\n\"Bool パラメーター `\\\"overlay\\\"` \"\n\"は、画像を現在のページコンテンツの上（前景、デフォルト）に配置するか、そうでないか（背景）を制御します。\"\n\n#: ../../app3.rst:255 7e80998882b74dbd8a0af43da85cb0d4\nmsgid \"Use cases include (but are not limited to) the following:\"\nmsgstr \"使用例は以下のようなものがありますが、これに限定されません：\"\n\n#: ../../app3.rst:257 996173b99261405f88be22fdbd55394b\nmsgid \"\"\n\"\\\"Stamp\\\" a series of pages of the current document with the same image, \"\n\"like a company logo or a watermark.\"\nmsgstr \"現在の文書の複数のページに同じ画像（企業のロゴや透かし）を「スタンプ」する。\"\n\n#: ../../app3.rst:258 1c47493c9a7d4b9f86bf2e065fad544e\nmsgid \"\"\n\"Combine arbitrary input pages into one output page to support “booklet” \"\n\"or double-sided printing (known as \\\"4-up\\\", \\\"n-up\\\").\"\nmsgstr \"任意の入力ページを1つの出力ページに組み合わせ、\\\"ブックレット\\\"や両面印刷をサポートする（「4-up」、「n-up」としても知られています）。\"\n\n#: ../../app3.rst:259 7e5cd1ef35154a02b0bee17ee2806729\nmsgid \"\"\n\"Split up (large) input pages into several arbitrary pieces. This is also \"\n\"called “posterization”, because you e.g. can split an A4 page \"\n\"horizontally and vertically, print the 4 pieces enlarged to separate A4 \"\n\"pages, and end up with an A2 version of your original page.\"\nmsgstr \"（大きな）入力ページをいくつかの任意のピースに分割する。これは「ポスタリゼーション」とも呼ばれ、たとえばA4ページを水平および垂直に分割し、4つのピースを別々のA4ページに拡大印刷して、元のページのA2バージョンを作成することができます。\"\n\n#: ../../app3.rst:262 b540c10d38674f279374416c7ec65281\nmsgid \"Technical Implementation\"\nmsgstr \"テクニカル実装\"\n\n#: ../../app3.rst:264 69b731e1cb1b4b1f82341ad0baeff00b\nmsgid \"\"\n\"This is done using PDF **\\\"Form XObjects\\\"**, see section 8.10 on page \"\n\"217 of :ref:`AdobeManual`. On execution of a :meth:`Page.show_pdf_page`, \"\n\"the following things happen:\"\nmsgstr \"\"\n\"これはPDF **「フォームXObject」** を使用して行われます。 :ref:`AdobeManual` リファレンス \"\n\"の217ページ、セクション8.10を参照してください。 :meth:`Page.show_pdf_page`  \"\n\"が実行されると、次のことが起こります。\"\n\n#: ../../app3.rst:266 50910b81c885485fadb624aecb9e1577\nmsgid \"\"\n\"The :data:`resources` and :data:`contents` objects of source page in \"\n\"source document are copied over to the target document, jointly creating \"\n\"a new **Form XObject** with the following properties. The PDF \"\n\":data:`xref` number of this object is returned by the method.\"\nmsgstr \"\"\n\"ソースドキュメント内のソースページの :data:`resources`  と  :data:`contents` \"\n\"オブジェクトは、ターゲットドキュメントにコピーされ、共同で新しい **フォームXObject** が作成されます。このオブジェクトのPDF  \"\n\":data:`xref`  番号がメソッドによって返されます。\"\n\n#: ../../app3.rst:268 a1333276b2c34164b105e04d7d4d2515\nmsgid \"`/BBox` equals `/Mediabox` of the source page\"\nmsgstr \"`/BBox` はソースページの `/Mediabox` に等しいです。\"\n\n#: ../../app3.rst:269 fbe66f56505f421dad721b5efa325673\nmsgid \"`/Matrix` equals the identity matrix.\"\nmsgstr \"`/Matrix` は単位行列と等しいです。\"\n\n#: ../../app3.rst:270 3a867e67f3d843608d9857ad1253fa34\nmsgid \"\"\n\"`/Resources` equals that of the source page. This involves a “deep-copy” \"\n\"of hierarchically nested other objects (including fonts, images, etc.). \"\n\"The complexity involved here is covered by MuPDF's grafting [#f1]_ \"\n\"technique functions.\"\nmsgstr \"\"\n\"`/Resources` \"\n\"はソースページのものに等しいです。これには、階層的にネストされた他のオブジェクト（フォント、画像など）の「ディープコピー」が含まれます。ここでの複雑さは、MuPDFのグラフティング[1]技術関数によってカバーされています。\"\n\n#: ../../app3.rst:271 1a49d5440ba142cf9172da9514e3c857\nmsgid \"\"\n\"This is a stream object type, and its stream is an exact copy of the \"\n\"combined data of the source page's :data:`contents` objects.\"\nmsgstr \"\"\n\"これはストリームオブジェクトタイプであり、そのストリームはソースページの :data:`contents` \"\n\"オブジェクトの結合データの正確なコピーです。\"\n\n#: ../../app3.rst:273 dd47a3e1e5374c23ae28df502b54d8a4\nmsgid \"\"\n\"This Form XObject is only executed once per shown source page. Subsequent\"\n\" displays of the same source page will skip this step and only create \"\n\"\\\"pointer\\\" Form XObjects (done in next step) to this object.\"\nmsgstr \"このフォームXObjectは、表示されるソースページごとに1回だけ実行されます。同じソースページの後続の表示では、このステップはスキップされ、このオブジェクトへの「ポインター」フォームXObject（次のステップで行われる）のみが作成されます。\"\n\n#: ../../app3.rst:275 42724012ec184801b99998826eed3a72\nmsgid \"\"\n\"A second **Form XObject** is then created which the target page uses to \"\n\"invoke the display. This object has the following properties:\"\nmsgstr \"\"\n\"次に、ターゲットページが表示を呼び出すために使用する2番目の **フォームXObject** \"\n\"が作成されます。このオブジェクトには次のような特性があります。\"\n\n#: ../../app3.rst:277 e03b9eae952d4d1bb6e04da71d195465\nmsgid \"`/BBox` equals the `/CropBox` of the source page (or `\\\"clip\\\"`).\"\nmsgstr \"`/BBox` はソースページの `/CropBox`（または `\\\"クリップ\\\"` ）に等しいです。\"\n\n#: ../../app3.rst:278 1749263652a44611a4af6fbe1690c814\nmsgid \"`/Matrix` represents the mapping of `/BBox` to the target rectangle.\"\nmsgstr \"`/Matrix` は `/BBox` からターゲット矩形へのマッピングを表します。\"\n\n#: ../../app3.rst:279 4fb0197364cf4a88b015f8fa5d6d6ff2\nmsgid \"\"\n\"`/XObject` references the previous Form XObject via the fixed name \"\n\"`fullpage`.\"\nmsgstr \"`/XObject` は、以前のフォームXObjectを固定された名前 `fullpage` を介して参照します。\"\n\n#: ../../app3.rst:280 a3736f591c254b8a801d28e108cec9a8\nmsgid \"\"\n\"The stream of this object contains exactly one fixed statement: \"\n\"`/fullpage Do`.\"\nmsgstr \"このオブジェクトのストリームには、正確に1つの固定されたステートメントが含まれています： `/fullpage Do` 。\"\n\n#: ../../app3.rst:281 5d63f1c31a56424b8903208d2ac3af39\nmsgid \"\"\n\"If the method's `\\\"oc\\\"` argument is given, its value is assigned to this\"\n\" Form XObject as `/OC`.\"\nmsgstr \"メソッドの `「oc」` 引数が指定された場合、その値はこのフォームXObjectに `/OC` として割り当てられます。\"\n\n#: ../../app3.rst:283 e5c4f530e1134086bac2da1f45b4d894\nmsgid \"\"\n\"The :data:`resources` and :data:`contents` objects of the target page are\"\n\" now modified as follows.\"\nmsgstr \"ターゲットページの :data:`リソース` と :data:`コンテンツ` オブジェクトは以下のように変更されます。\"\n\n#: ../../app3.rst:285 d81644bc7b114307a984f10eed9801e7\nmsgid \"\"\n\"Add an entry to the `/XObject` dictionary of `/Resources` with the name \"\n\"`fzFrm<n>` (with n chosen such that this entry is unique on the page).\"\nmsgstr \"\"\n\"`/Resources` の `/XObject` 辞書に、 ` fzFrm ` \"\n\"という名前のエントリをページ内で一意であるように追加します（nはこのエントリがページで一意であるように選択されます）。\"\n\n#: ../../app3.rst:286 ff1f4fdf2e59413da229698f3921b8d0\nmsgid \"\"\n\"Depending on `\\\"overlay\\\"`, prepend or append a new object to the page's \"\n\"`/Contents` array, containing the statement `q /fzFrm<n> Do Q`.\"\nmsgstr \"\"\n\"`\\\"overlay\\\"` に応じて、ページの `/ Contents` 配列に新しいオブジェクトを前または後に追加し、ステートメント `q / \"\n\"fzFrm<n> Do Q` を含めます。\"\n\n#: ../../app3.rst:288 01882ae84bb54534ba3c6ab5ca61b114\nmsgid \"This design approach ensures that:\"\nmsgstr \"この設計アプローチは次を保証します：\"\n\n#: ../../app3.rst:290 b9976fb7daeb4b6291c769ba97d9ac06\nmsgid \"\"\n\"The (potentially large) source page is only copied once to the target \"\n\"PDF. Only small \\\"pointer\\\" Form XObjects objects are created per each \"\n\"target page to show the source page.\"\nmsgstr \"（潜在的に大きな）ソースページは、ターゲットPDFに1度だけコピーされます。各ターゲットページごとに、ソースページを表示するための小さな「ポインター」フォームXObjectオブジェクトが作成されます。\"\n\n#: ../../app3.rst:291 521ab75e321e488ca9676c4ce898d1b3\nmsgid \"\"\n\"Each referring target page can have its own `\\\"oc\\\"` parameter to control\"\n\" the source page's visibility individually.\"\nmsgstr \"参照する各ターゲットページは、ソースページの表示を個別に制御するための独自の `「oc」` パラメータを持つことができます。\"\n\n#: ../../app3.rst:298 05bf5b83ea6142389d3172a05aa36f27\nmsgid \"Diagnostics\"\nmsgstr \"\"\n\n#: ../../app3.rst:303 b856bdfa521a4448b19dc8a507f2c401\nmsgid \"|PyMuPDF| messages\"\nmsgstr \"\"\n\n#: ../../app3.rst:305 85b5e6f89d3649809ada540c8eea82a1\nmsgid \"|PyMuPDF| has a Message system for showing text diagnostics.\"\nmsgstr \"\"\n\n#: ../../app3.rst:307 4c84b6f861ea48f3a8e09715aebfc6d9\nmsgid \"\"\n\"By default messages are written to `sys.stdout`. This can be controlled \"\n\"in two ways:\"\nmsgstr \"\"\n\n#: ../../app3.rst:311 74ccaa7010d84feaaff8d9a38c69b5f1\nmsgid \"Set environment variable `PYMUPDF_MESSAGE` before |PyMuPDF| is imported.\"\nmsgstr \"\"\n\n#: ../../app3.rst:314 2f88318d369944be868c62a39006cca7\nmsgid \"Call `set_messages()`:\"\nmsgstr \"\"\n\n#: ../../app3.rst:318 e5c533c2a71c4b608f529bfb4df7afb2\nmsgid \"|MuPDF| errors and warnings\"\nmsgstr \"\"\n\n#: ../../app3.rst:320 1523d23bbbce45f1a25c851f5b69abf0\nmsgid \"|MuPDF| generates text errors and warnings.\"\nmsgstr \"\"\n\n#: ../../app3.rst:323 adb68bfb91384894b21b746a73dd6bc0\nmsgid \"\"\n\"These errors and warnings are appended to an internal list, accessible \"\n\"with `Tools.mupdf_warnings()`. Also see `Tools.reset_mupdf_warnings()`.\"\nmsgstr \"\"\n\n#: ../../app3.rst:327 79324fa6e32d42af95e9abf26233099a\nmsgid \"\"\n\"By default these errors and warnings are also sent to the |PyMuPDF| \"\n\"message system.\"\nmsgstr \"\"\n\n#: ../../app3.rst:330 a71ef1ec2b084888adf04787091192a1\nmsgid \"\"\n\"This can be controlled with `mupdf_display_errors()` and \"\n\"`mupdf_display_warnings()`.\"\nmsgstr \"\"\n\n#: ../../app3.rst:334 83b10651533947bc9bd63e655367d81e\nmsgid \"\"\n\"These messages are prefixed with `MuPDF error:` and `MuPDF warning:` \"\n\"respectively.\"\nmsgstr \"\"\n\n#: ../../app3.rst:337 943f00a7c2a849f483525f7b3653f6a0\nmsgid \"Some |MuPDF| errors may lead to Python exceptions.\"\nmsgstr \"\"\n\n#: ../../app3.rst:339 0cdf1f5474fa4616a11df5f246a531a1\nmsgid \"\"\n\"Example output for a **recoverable error**. We are opening a damaged PDF,\"\n\" but MuPDF is able to repair it and gives us a little information on what\"\n\" happened. Then we illustrate how to find out whether the document can \"\n\"later be saved incrementally. Checking the :attr:`Document.is_dirty` \"\n\"attribute at this point also indicates that during `pymupdf.open` the \"\n\"document had to be repaired:\"\nmsgstr \"\"\n\n#: ../../app3.rst:360 af0558fd6f8c4501a41d850a84d3da7b\nmsgid \"Example output for an **unrecoverable error**:\"\nmsgstr \"\"\n\n#: ../../app3.rst:378 01987f6b7c4e4b13a325bf16dc6d2fda\nmsgid \"Coordinates\"\nmsgstr \"脚注\"\n\n#: ../../app3.rst:381 cc111c4761774e13839c570b6a760b94\nmsgid \"\"\n\"This is one of the most frequently used terms in this documentation. A \"\n\"**coordinate** generally means a pair of numbers `(x, y)` referring to \"\n\"some location, like a corner of a rectangle (:ref:`Rect`), a :ref:`Point`\"\n\" and so forth. The two values usually are floats, but there a objects \"\n\"like images which only allow them to be integers.\"\nmsgstr \"\"\n\n#: ../../app3.rst:383 8e23a5ba1da047d88532eda8f671451a\nmsgid \"\"\n\"To actually *find* a coordinate's location, we also need to know the \"\n\"*reference* point for ``x`` and ``y`` - in other words, we must know \"\n\"where location `(0, 0)` is positioned. Once `(0, 0)` (the \\\"origin\\\") is \"\n\"known, we speak of a \\\"coordinate system\\\".\"\nmsgstr \"\"\n\n#: ../../app3.rst:385 5720add281a54277b7a0232978fa8662\nmsgid \"\"\n\"Several coordinate systems exist in document processing. For instance, \"\n\"the coordinate systems of a PDF page and the image created from it are \"\n\"**different**. We therefore need ways to *transform* coordinates from one\"\n\" system to another (and also back occasionally). This is the task of a \"\n\":ref:`Matrix`. It is a mathematical function which works much like a \"\n\"factor that can be \\\"multiplied\\\" with a point or rectangle to give us \"\n\"the corresponding point / rectangle in another coordinate system. The \"\n\"inverse of a transformation matrix can be used to revert the \"\n\"transformation. Much like multiplying by some factor, say 3, can be \"\n\"reverted by dividing the result by 3 (or multiplying it with 1/3).\"\nmsgstr \"\"\n\n#: ../../app3.rst:388 9bd43359dae34a3db3ed2502539abb9f\nmsgid \"Coordinates and Images\"\nmsgstr \"\"\n\n#: ../../app3.rst:390 ef142876a50648b88ce6825a05daf149\nmsgid \"\"\n\"Images have a coordinate system with integer coordinates. Origin `(0, 0)`\"\n\" is the top-left point. ``x`` values must be in `range(width)`, and ``y``\"\n\" values in `range(height)`. Therefore, ``y`` values *increase* if we go \"\n\"*downwards*. For every image, there is only a **finite number** of \"\n\"coordinates, namely `width * height`. A location in an image is also \"\n\"called a \\\"pixel\\\".\"\nmsgstr \"\"\n\n#: ../../app3.rst:392 a43cf286a2d14b4892269df18f857b1b\nmsgid \"\"\n\"How **large** an image will be (in centimeters or inches) when e.g. \"\n\"printed, depends on additional information: the \\\"resolution\\\". This is \"\n\"measured in **DPI** (dots per inch, or pixels per inch). To find the \"\n\"printed size of some image, we therefore must divide its width and its \"\n\"height by the corresponding DPI values (there may separate ones for width\"\n\" and for height) and will get the respective number of inches.\"\nmsgstr \"\"\n\n#: ../../app3.rst:396 b694fe03ac784433945a778cd53034f2\nmsgid \"Origin Point, Point Size and Y-Axis\"\nmsgstr \"\"\n\n#: ../../app3.rst:398 a92885d699744510b39176e360fb8a63\nmsgid \"\"\n\"In |PDF|, the origin `(0, 0)` of a page is located at its **bottom-left \"\n\"point**. In |MuPDF|, the origin `(0, 0)` of a page is located at its \"\n\"**top-left point**.\"\nmsgstr \"\"\n\n#: ../../app3.rst:403 b0a22dfe25a8493dbcd9b65008507920\nmsgid \"Coordinates are float numbers and measured in **points**, where:\"\nmsgstr \"\"\n\n#: ../../app3.rst:405 68d51777bcaf4642b1031f9dc960cd29\nmsgid \"**one point equals 1/72 inches**.\"\nmsgstr \"\"\n\n#: ../../app3.rst:407 756d6701c9f747b9830a3c7d01111f53\nmsgid \"\"\n\"Typical document page sizes are **ISO A4** and **Letter**. A **Letter** \"\n\"page has a size of **8.5 x 11 inches**, corresponding to **612 x 792 \"\n\"points**. In the |PDF| coordinate system, the top-left point of a \"\n\"**Letter** page hence has the coordinate `(0, 792)` as **the y-axis \"\n\"points upwards**. Now we know our document size the |MuPDF| coordinate \"\n\"system for the bottom right would be coordinate `(612, 792)` (and for \"\n\"|PDF| this coordinate would then be `(612,0)`).\"\nmsgstr \"\"\n\n#: ../../app3.rst:409 50dac25ebb9848779eb3bff43cb168dc\nmsgid \"\"\n\"Theoretically, there are **infinitely many** coordinate positions on a \"\n\"|PDF| page. In practice however, at most the first 5 decimal places are \"\n\"sufficient for a reasonable precision.\"\nmsgstr \"\"\n\n#: ../../app3.rst:412 e630dd4abdb84c43b0315dfb4e77cef8\nmsgid \"\"\n\"In |MuPDF|, multiple document formats are supported - |PDF| just being \"\n\"one among **over a dozen others**. Images are also supported as documents\"\n\" in |MuPDF| (therefore having one page usually). This is one of the \"\n\"reasons why |MuPDF| uses a coordinate system with the origin `(0, 0)` \"\n\"being the **top-left** point of any document page. **The y-axis points \"\n\"downwards**, like with images. Coordinates in |MuPDF| in any case are \"\n\"floats, like in |PDF|.\"\nmsgstr \"\"\n\n#: ../../app3.rst:414 a69f66be61c5411c909b4daed6378f6c\nmsgid \"\"\n\"A rectangle `Rect(0, 0, 100, 100)` for instance in |MuPDF| (and thus \"\n\"|PyMuPDF|) therefore is a square with edges of length 100 points (= 1.39 \"\n\"inches or 3.53 centimeters). Its top-left corner is the origin. To switch\"\n\" between the two coordinate systems |PDF| to |MuPDF|, every :ref:`Page` \"\n\"object has a :attr:`Page.transformation_matrix`. Its inverse can be used \"\n\"to compute a rectangle's PDF coordinates. In this way we can conveniently\"\n\" find that `Rect(0, 0, 100, 100)` in |MuPDF| is the same as `Rect(0, 692,\"\n\" 100, 792)` in |PDF|. See this code snippet::\"\nmsgstr \"\"\n\n#: ../../app3.rst:425 0358a41bcfde49298c244a781732a9cc\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../app3.rst:426 2a940ba3cc664855b3afbb56eaefdade\nmsgid \"\"\n\"MuPDF supports \\\"deep-copying\\\" objects between PDF documents. To avoid \"\n\"duplicate data in the target, it uses so-called \\\"graftmaps\\\", like a \"\n\"form of scratchpad: for each object to be copied, its :data:`xref` number\"\n\" is looked up in the graftmap. If found, copying is skipped. Otherwise, \"\n\"the new :data:`xref` is recorded and the copy takes place. PyMuPDF makes \"\n\"use of this technique in two places so far: :meth:`Document.insert_pdf` \"\n\"and :meth:`Page.show_pdf_page`. This process is fast and very efficient, \"\n\"because it prevents multiple copies of typically large and frequently \"\n\"referenced data, like images and fonts. However, you may still want to \"\n\"consider using garbage collection (option 4) in any of the following \"\n\"cases:\"\nmsgstr \"\"\n\"MuPDFはPDFドキュメント間でオブジェクトを「ディープコピー」することをサポートしています。対象の中で重複するデータを避けるために、「グラフトマップ」と呼ばれる仕組みを使用します。これはスクラッチパッドのようなもので、コピーされる各オブジェクトについて、その\"\n\" :data:`xref` 番号をグラフトマップで調べます。もし見つかれば、コピーはスキップされます。それ以外の場合は、新しい \"\n\":data:`xref` が記録され、コピーが行われます。PyMuPDFは、:meth:`Document.insert_pdf` と \"\n\":meth:`Page.show_pdf_page` \"\n\"の2つの場所でこの技術を使用しています。このプロセスは高速で非常に効率的です。なぜなら、通常大きなデータや頻繁に参照されるデータ（画像やフォントなど）の複数のコピーを防ぐためです。ただし、次のいずれかの場合にはガベージコレクション（オプション4）の使用を検討することをお勧めします：\"\n\n#: ../../app3.rst:428 12291c684340429ebe3dfc12d79126a2\nmsgid \"\"\n\"The target PDF is not new / empty: grafting does not check for resources \"\n\"that already existed (e.g. images, fonts) in the target document before \"\n\"opening it.\"\nmsgstr \"対象のPDFが新しい/空でない場合：グラフティングは、対象ドキュメント内で既に存在しているリソース（例：画像、フォント）をチェックしません。\"\n\n#: ../../app3.rst:429 85b00d1ae84a4e159e1accdfa5034bdc\nmsgid \"\"\n\"Using :meth:`Page.show_pdf_page` for more than one source document: each \"\n\"grafting occurs **within one source** PDF only, not across multiple. So \"\n\"if e.g. the same image exists in pages from different source PDFs, then \"\n\"this will not be detected until garbage collection.\"\nmsgstr \"\"\n\"複数のソースドキュメントで :meth:`Page.show_pdf_page` を使用する場合：グラフティングは **1つのソース** \"\n\"PDF内でのみ発生し、複数のソースPDF間では発生しません。したがって、同じ画像が異なるソースPDFのページに存在する場合、これはガベージコレクションまで検出されません\"\n\n#: ../../footer.rst:46 2a972e62f98f45208da9b9eaf1158726\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Redirecting Error and Warning Messages\"\n#~ msgstr \"エラーと警告メッセージのリダイレクト\"\n\n#~ msgid \"\"\n#~ \"Since MuPDF version 1.16 error and \"\n#~ \"warning messages can be redirected via\"\n#~ \" an official plugin.\"\n#~ msgstr \"MuPDFバージョン1.16以降、エラーと警告メッセージは公式プラグインを介してリダイレクトできます。\"\n\n#~ msgid \"\"\n#~ \"PyMuPDF will put error messages to \"\n#~ \"`sys.stderr` prefixed with the string \"\n#~ \"\\\"mupdf:\\\". Warnings are internally stored \"\n#~ \"and can be accessed via \"\n#~ \"*pymupdf.TOOLS.mupdf_warnings()*. There also is \"\n#~ \"a function to empty this store.\"\n#~ msgstr \"\"\n#~ \"PyMuPDFはエラーメッセージを、先頭に文字列「mupdf:」を付けて `sys.stderr` \"\n#~ \"に表示します。警告は内部で保存され、*pymupdf.TOOLS.mupdf_warnings()* \"\n#~ \"を通じてアクセスできます。また、この保存領域を空にするための関数も存在します。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"For a long time, an older version\"\n#~ \" was also available under `this \"\n#~ \"<http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf>`_\"\n#~ \" link. It seems to be taken off\"\n#~ \" of the web site in October \"\n#~ \"2021. Earlier (pre 1.19.*) versions of\"\n#~ \" the PyMuPDF documentation used to \"\n#~ \"refer to this document. We have \"\n#~ \"undertaken an effort to replace \"\n#~ \"referrals to the current specification \"\n#~ \"above.\"\n#~ msgstr \"\"\n#~ \"長い間、古いバージョンも `この \"\n#~ \"<http://www.adobe.com/content/dam/Adobe/en/devnet/acrobat/pdfs/pdf_reference_1-7.pdf>`_\"\n#~ \" \"\n#~ \"リンクで利用可能でしたが、2021年10月にウェブサイトから取り下げられたようです。以前（1.19.*より前）のPyMuPDFドキュメンテーションはこの文書を参照していました。私たちは、上記の現行仕様への参照を置き換える取り組みを行っています。\"\n\n#~ msgid \"MuPDF errors and warnings\"\n#~ msgstr \"\"\n\n#~ msgid \"MuPDF generates text errors and warnings.\"\n#~ msgstr \"\"\n\n#~ msgid \"Some MuPDF errors may lead to Python exceptions.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/app4.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 613ca8dee3af4e18aee8824f32d62bd7\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 3fb1879bb92640d0b871ed41914b2b0d\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 5800ad4c0c8f4aea8589a92458f2afe9\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../app4.rst:14 452ac8cb00694e9abeae5f9e25ddebf6\nmsgid \"Appendix 4: Performance Comparison Methodology\"\nmsgstr \"付録4：性能比較方法\"\n\n#: ../../app4.rst:16 14ceae9e1c7f4b8f8a0319fbb991a23c\nmsgid \"\"\n\"This article documents the approach to measure :title:`PyMuPDF's` \"\n\"performance and the tools and example files used to do comparisons.\"\nmsgstr \"この記事では、|PyMuPDF| の性能を測定するアプローチと、比較を行うために使用されるツールとサンプルファイルについて説明します。\"\n\n#: ../../app4.rst:18 707cf837e27a4490be01f4ff59f3d6e7\nmsgid \"The following three sections deal with different performance aspects:\"\nmsgstr \"以下の3つのセクションでは、異なる性能の側面に取り組んでいます：\"\n\n#: ../../app4.rst:20 19bf7499dda54ae094b5f694a8ea950f\nmsgid \"\"\n\":ref:`Document Copying<app4_copying>` - This includes opening and parsing\"\n\" :title:`PDFs`, then writing them to an output file. Because the same \"\n\"basic activities are also used for joining (merging) :title:`PDFs`, the \"\n\"results also apply to these use cases.\"\nmsgstr \"\"\n\":ref:`ドキュメントのコピー<app4_copying>` - これには |PDF| \"\n\"ファイルの開閉と解析、そしてそれらを出力ファイルに書き込む作業が含まれます。同じ基本的なアクティビティは、|PDF| \"\n\"ファイルの結合（マージ）にも使用されるため、結果はこれらのユースケースにも適用されます。\"\n\n#: ../../app4.rst:21 8902b7d3bdf44cdeb0a02ebaeb788364\nmsgid \"\"\n\":ref:`Text Extraction<app4_text_extraction>` - This extracts plain text \"\n\"from :title:`PDFs` and writes it to an output text file.\"\nmsgstr \"\"\n\":ref:`テキスト抽出<app4_text_extraction>` - これにより |PDF| \"\n\"ファイルから平文テキストが抽出され、テキストファイルに書き込まれます。\"\n\n#: ../../app4.rst:22 c9e28e548b684c15b6fc6c839fb268d0\nmsgid \"\"\n\":ref:`Page Rendering<app4_page_rendering>` - This converts |PDF| pages to\"\n\" image files looking identical to the pages. This ability is the basic \"\n\"prerequisite for using a tool in :title:`Python GUI` scripts to scroll \"\n\"through documents. We have chosen a medium-quality (resolution 150 DPI) \"\n\"version.\"\nmsgstr \"\"\n\":ref:`ページレンダリング<app4_page_rendering>` - \"\n\"これによりPDFページがページと同じような見た目の画像ファイルに変換されます。この機能は、:title:`Python GUI` \"\n\"スクリプトでドキュメントをスクロールするための基本的な前提条件です。中画質版（解像度150 DPI）を選択しました。\"\n\n#: ../../app4.rst:24 d8c56f0cbbb4415497587ade558105c9\nmsgid \"\"\n\"Please note that in all cases the actual speed in dealing with |PDF| \"\n\"structures is not directly measured: instead, the timings also include \"\n\"the durations of writing files to the operating system's file system. \"\n\"This cannot be avoided because tools other than |PyMuPDF| do not offer \"\n\"the option to e.g., separate the image **creation** step from the \"\n\"following step, which **writes** the image into a file.\"\nmsgstr \"\"\n\"|PDF| \"\n\"構造の処理速度そのものを直接測定するのではなく、すべての場合において、タイミングにはファイルをオペレーティングシステムのファイルシステムに書き込む時間も含まれることに注意してください。これは回避できない要因です。なぜなら、|PyMuPDF|\"\n\" 以外のツールでは、例えばイメージの **作成** ステップと、イメージをファイルに **書き込む** \"\n\"後続のステップを分離するオプションが提供されていないためです。\"\n\n#: ../../app4.rst:26 c95dca0ce6a24b9cbb4e54005da736be\nmsgid \"\"\n\"So all timings documented include a common, OS-oriented base effort. \"\n\"Therefore, performance **differences per tool are actually larger** than \"\n\"the numbers suggest.\"\nmsgstr \"\"\n\"したがって、すべての記録されたタイミングには共通のOS指向の基本的な努力が含まれています。したがって、**ツールごとの性能の違いは、数字が示す以上に実際には大きいです**\"\n\" 。\"\n\n#: ../../app4.rst:33 5c8d1822086844e0b5b6e63e24468509\nmsgid \"Files used\"\nmsgstr \"使用されるファイル\"\n\n#: ../../app4.rst:35 2439752153d84180a23a0e99527d8073\nmsgid \"\"\n\"A set of eight files is used for the performance testing. With each file \"\n\"we have the following information:\"\nmsgstr \"性能テストには、8つのファイルセットが使用されます。各ファイルには、次の情報があります：\"\n\n#: ../../app4.rst:37 b31835ad665241aebc8bce9496462a0b\nmsgid \"**Name** of the file and download **link**.\"\nmsgstr \"ファイル **名** とダウンロード **リンク**。\"\n\n#: ../../app4.rst:38 01b0b7ddaf6342b6acea40fc10548232\nmsgid \"**Size** in bytes.\"\nmsgstr \"バイト単位の **サイズ**。\"\n\n#: ../../app4.rst:39 5cefe438dda843c68dd254d3911dbf09\nmsgid \"Total number of **pages** in file.\"\nmsgstr \"ファイル内の総 **ページ** 数。\"\n\n#: ../../app4.rst:40 245d148da06d4becad20aec51e1fd3bf\nmsgid \"Total number of bookmarks (**Table of Contents** entries).\"\nmsgstr \"ブックマーク（ **目次** エントリー）の総数。\"\n\n#: ../../app4.rst:41 ff1a2993e3254f7686a848f577c48582\nmsgid \"Total number of **links**.\"\nmsgstr \"**リンク** の総数。\"\n\n#: ../../app4.rst:42 fb20f6986d82495e9890d8753eb1f276\nmsgid \"**KB size** per page.\"\nmsgstr \"ページごとの **KBサイズ** 。\"\n\n#: ../../app4.rst:43 1224aaf0dfde40e1a5c3bc91ef4011ff\nmsgid \"\"\n\"**Textsize per page** is the amount text in the whole file in KB, divided\"\n\" by the number of pages.\"\nmsgstr \"**ページごとのテキストサイズ** は、ファイル全体のテキスト量をKBで割ったものです。\"\n\n#: ../../app4.rst:44 8ceb2129883142a09c9d4d383789ed99\nmsgid \"Any **notes** to generally describe the type of file.\"\nmsgstr \"ファイルのタイプを一般的に説明するための **メモ** 。\"\n\n#: ../../app4.rst:50 ../../app4.rst:217 ../../app4.rst:295 ../../app4.rst:407\n#: 1b162242a4a54f7dafcae32349b4ed33 930f7531af8b4c2db858b7c3c63f1c57\n#: b459ef8255c34d8bb8f10527b5b13ae0 dd23f2e000014a6ebfbb0df71f4f4550\nmsgid \"**Name**\"\nmsgstr \"**ファイル名** \"\n\n#: ../../app4.rst:51 651fc5cd40134ce993378901eaed782d\nmsgid \"**Size (bytes)**\"\nmsgstr \"**サイズ（バイト）** \"\n\n#: ../../app4.rst:52 830651a701b543dd92495f528872e442\nmsgid \"**Pages**\"\nmsgstr \"**ページ数** \"\n\n#: ../../app4.rst:53 ad04afd00ac744a8b7c099d48dcdc0c3\nmsgid \"**TOC size**\"\nmsgstr \"**目次サイズ** \"\n\n#: ../../app4.rst:54 4286cb4118494c3c97aa7190ce52bbe1\nmsgid \"**Links**\"\nmsgstr \"**リンク数** \"\n\n#: ../../app4.rst:55 dfccc56073594677aaaf87774c57e911\nmsgid \"**KB/page**\"\nmsgstr \"**KB/ページ** \"\n\n#: ../../app4.rst:56 85615f3120044a3d8f55f0e03fbe8400\nmsgid \"**Textsize/page**\"\nmsgstr \"**テキストサイズ/ページ** \"\n\n#: ../../app4.rst:57 2ed30a8ee08e4381913a180905dc4905\nmsgid \"**Notes**\"\nmsgstr \"**メモ** \"\n\n#: ../../app4.rst:58 81403b323ce2471990b6addcb9d327ed\nmsgid \"`adobe.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:59 6dfced8745d04f139c2262964b78cc6c\nmsgid \"32,472,771\"\nmsgstr \"\"\n\n#: ../../app4.rst:60 fe260ad1414a49ad820440768eed3e3d\nmsgid \"1,310\"\nmsgstr \"\"\n\n#: ../../app4.rst:61 aecc68ede79f49e7a2f4965c4d6d21fb\nmsgid \"794\"\nmsgstr \"\"\n\n#: ../../app4.rst:62 19f68930d6b342c8b63282aacdda31ba\nmsgid \"32,096\"\nmsgstr \"\"\n\n#: ../../app4.rst:63 3db3ea234e5e4dbfb2cb18370be6526b\nmsgid \"24\"\nmsgstr \"\"\n\n#: ../../app4.rst:64 df9644ba42384b7f8df8f1a7f9ac9ca6\nmsgid \"1,942\"\nmsgstr \"\"\n\n#: ../../app4.rst:65 9a0b2a88e8d14cbbaa5e220051bc2cbc\nmsgid \"linearized, many links / bookmarks\"\nmsgstr \"線形化、多くのリンク/ブックマーク\"\n\n#: ../../app4.rst:66 b450a19150554327a540a48702926bd8\nmsgid \"`artifex-website.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:67 f76c22107d8e466e9e9b938d6d2a0c78\nmsgid \"31,570,732\"\nmsgstr \"\"\n\n#: ../../app4.rst:68 121ca9cb77a44f18ae707dc1f62b6828\nmsgid \"47\"\nmsgstr \"\"\n\n#: ../../app4.rst:69 74407cbb0f3b41c8b248f809abe4cf58\nmsgid \"46\"\nmsgstr \"\"\n\n#: ../../app4.rst:70 5a5a12aa804e4285b2c10f71c7b91631\nmsgid \"2,035\"\nmsgstr \"\"\n\n#: ../../app4.rst:71 24d74ed3a9814878b5faa590d81e830c\nmsgid \"656\"\nmsgstr \"\"\n\n#: ../../app4.rst:72 7f66bf0a79ca4e199dd2d27aea8b4e85\nmsgid \"3,538\"\nmsgstr \"\"\n\n#: ../../app4.rst:73 d9c710117eb44abca3a888f45c5f6927\nmsgid \"graphics oriented\"\nmsgstr \"グラフィックス志向\"\n\n#: ../../app4.rst:74 49bc871f44cb4ddbb8d76e2d42b3155b\nmsgid \"`db-systems.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:75 1a5f0c78435c4c6389a2acd6bd91cd28\nmsgid \"29,326,355\"\nmsgstr \"\"\n\n#: ../../app4.rst:76 f88d9c860ac246f49fdafd12ed4cc62e\nmsgid \"1,241\"\nmsgstr \"\"\n\n#: ../../app4.rst:77 ../../app4.rst:78 ../../app4.rst:117 ../../app4.rst:118\n#: 35384af101fd403ca7b83c7bf3616f8c 48b4936078bd42bab97c666b770093d6\n#: 95853467cdac44e5905fa2aa5f876d2d d6739a13778847ea9c11a2c7b08bc8e0\nmsgid \"0\"\nmsgstr \"\"\n\n#: ../../app4.rst:79 d215b500b52e41cc99c84f24fe3890ec\nmsgid \"23\"\nmsgstr \"\"\n\n#: ../../app4.rst:80 a267452974d549de8748e729075a7ac7\nmsgid \"2,142\"\nmsgstr \"\"\n\n#: ../../app4.rst:82 739b78ec9dc84e99917248ee3622b3b2\nmsgid \"`fontforge.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:83 25bd9632f03d4b2293dc4c8a076d05fa\nmsgid \"8,222,384\"\nmsgstr \"\"\n\n#: ../../app4.rst:84 b567e447fe8f4e0490f62422a2d9d569\nmsgid \"214\"\nmsgstr \"\"\n\n#: ../../app4.rst:85 75588fdd5beb42a78773ef5340ecc1b6\nmsgid \"31\"\nmsgstr \"\"\n\n#: ../../app4.rst:86 0c2001d30c0f4f07963b9f2e38b0f614\nmsgid \"242\"\nmsgstr \"\"\n\n#: ../../app4.rst:87 d6c479c026b5484881aa9197ffc88c6a\nmsgid \"38\"\nmsgstr \"\"\n\n#: ../../app4.rst:88 b9139930537345d284aa9a31220d74c6\nmsgid \"1,058\"\nmsgstr \"\"\n\n#: ../../app4.rst:89 710514866ee04905bf3be46a44b683bf\nmsgid \"mix of text & graphics\"\nmsgstr \"テキストとグラフィックスのミックス\"\n\n#: ../../app4.rst:90 c8a1f504fd3746ba9397d4e3d6b274a6\nmsgid \"`pandas.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:91 8642835dbf5d4db99a8c4fbca766a571\nmsgid \"10,585,962\"\nmsgstr \"\"\n\n#: ../../app4.rst:92 7b996090e65044c584d83ea7acda42f0\nmsgid \"3,071\"\nmsgstr \"\"\n\n#: ../../app4.rst:93 ff6fdff8d91a417583e2686c79665e97\nmsgid \"536\"\nmsgstr \"\"\n\n#: ../../app4.rst:94 6916626a7d824adfb4b1475a9d0f3eff\nmsgid \"16,554\"\nmsgstr \"\"\n\n#: ../../app4.rst:95 bc0f680837344f68abbb708440827a84\nmsgid \"3\"\nmsgstr \"\"\n\n#: ../../app4.rst:96 bba11b24685d4d8c94deaa5e074e4bcb\nmsgid \"1,539\"\nmsgstr \"\"\n\n#: ../../app4.rst:97 40e65f53ef05490796b7a4aec9577410\nmsgid \"many pages\"\nmsgstr \"多くのページ\"\n\n#: ../../app4.rst:98 e798c081493c4df095c56e07a50ca1b9\nmsgid \"`pymupdf.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:99 9648e1df46804af395045a08a83de9fe\nmsgid \"6,805,176\"\nmsgstr \"\"\n\n#: ../../app4.rst:100 7f91a57f8a7847b4bd037094e00faa9a\nmsgid \"478\"\nmsgstr \"\"\n\n#: ../../app4.rst:101 226cdbfe630949eab54a52805869a6e7\nmsgid \"276\"\nmsgstr \"\"\n\n#: ../../app4.rst:102 f30b492e535c41748786f54e00e90cb8\nmsgid \"5,277\"\nmsgstr \"\"\n\n#: ../../app4.rst:103 2701b877b410466cb1ae77dd1a2a1e90\nmsgid \"14\"\nmsgstr \"\"\n\n#: ../../app4.rst:104 bcc9d1ef612c4e95b015b553232ad25a\nmsgid \"1,937\"\nmsgstr \"\"\n\n#: ../../app4.rst:105 befe3de8428943f2b55fa3759ae8cbd0\nmsgid \"text oriented\"\nmsgstr \"テキスト志向\"\n\n#: ../../app4.rst:106 1fde26c15a56401eb49e5db71f99cc25\nmsgid \"`pythonbook.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:107 abde300eb8244d23875981f20afdf6ce\nmsgid \"9,983,856\"\nmsgstr \"\"\n\n#: ../../app4.rst:108 f236fb08a1834afeae13579d512733ba\nmsgid \"669\"\nmsgstr \"\"\n\n#: ../../app4.rst:109 d7c1691699514ea893a728c74016301d\nmsgid \"198\"\nmsgstr \"\"\n\n#: ../../app4.rst:110 4af5202a95164d698a13772fb60448a8\nmsgid \"1,953\"\nmsgstr \"\"\n\n#: ../../app4.rst:111 b4141c07d695403e87cedbe5de5863dd\nmsgid \"15\"\nmsgstr \"\"\n\n#: ../../app4.rst:112 72ae61bf2a1b4a52904b806afc0ff6f5\nmsgid \"1,929\"\nmsgstr \"\"\n\n#: ../../app4.rst:114 bb501706366848629a8491cb70e58ec9\nmsgid \"`sample-50-MB-pdf-file.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:115 542f200f9bbd48719bb31d4cf6850f3b\nmsgid \"52,521,850\"\nmsgstr \"\"\n\n#: ../../app4.rst:116 d0db6531af4e488ca48300bebf47246e\nmsgid \"1\"\nmsgstr \"\"\n\n#: ../../app4.rst:119 b80b76ee70584a34977f50acbea06df8\nmsgid \"51,291\"\nmsgstr \"\"\n\n#: ../../app4.rst:120 52119106cfb04a489c5842fab93cd2c5\nmsgid \"23,860\"\nmsgstr \"\"\n\n#: ../../app4.rst:121 513e58b0ccf547edaf2e1b8d4fc09391\nmsgid \"single page, graphics oriented, large file size\"\nmsgstr \"単一ページ、グラフィックス志向、大きなファイルサイズ\"\n\n#: ../../app4.rst:127 b1d1466a4d4f46ee97f9c0c14866930d\nmsgid \"\"\n\"**adobe.pdf** and **pymupdf.pdf** are clearly text oriented, **artifex-\"\n\"website.pdf** and **sample-50-MB-pdf-file.pdf** are graphics oriented. \"\n\"Other files are a mix of both.\"\nmsgstr \"\"\n\"**adobe.pdf** と **pymupdf.pdf** は明らかにテキスト志向です。 **artifex-website.pdf** と \"\n\"**sample-50-MB-pdf-file.pdf** はグラフィックス志向です。その他のファイルは両方のミックスです。\"\n\n#: ../../app4.rst:131 a46db6b46cbd476c9aa08e828b1899a9\nmsgid \"Tools used\"\nmsgstr \"使用されるツール\"\n\n#: ../../app4.rst:133 eff071706abe45db98dc970ba599955e\nmsgid \"\"\n\"In each section, the same fixed set of |PDF| files is being processed by \"\n\"a set of tools. The set of tools used per performance aspect however \"\n\"varies, depending on the supported tool features.\"\nmsgstr \"\"\n\"各セクションでは、同じ固定されたセットの |PDF| \"\n\"ファイルが一連のツールによって処理されます。ただし、性能の側面ごとに使用されるツールのセットは、サポートされるツールの機能に応じて異なります。\"\n\n#: ../../app4.rst:135 e7ff37e32cbd4cdc993c645e7658d227\nmsgid \"\"\n\"All tools are either platform independent, or at least can run on both, \"\n\":title:`Windows` and :title:`Unix` / :title:`Linux`.\"\nmsgstr \"\"\n\"すべてのツールは、プラットフォームに依存しないか、少なくとも :title:`Windows` と :title:`Unix` / \"\n\":title:`Linux` の両方で実行できます。\"\n\n#: ../../app4.rst:141 7507beef7859479e94a8fa9cce614373\nmsgid \"**Tool**\"\nmsgstr \"ツール\"\n\n#: ../../app4.rst:142 7e5c5082ee244cc1850b389fa76d162b\nmsgid \"**Description**\"\nmsgstr \"説明\"\n\n#: ../../app4.rst:143 ../../app4.rst:172 ../../app4.rst:218 ../../app4.rst:296\n#: ../../app4.rst:368 ../../app4.rst:408 51f2639233354454a2be6c8cf943caae\n#: 75b83e125f444081ac46f5b513ffb434 78511b7a3ae24d7ba242cb9f012c945c\n#: cf82339face445409b1cb2230b1cf737 e2f4e337aa6f46ff9d1a57a84bd40231\n#: ea0496359fd4419f88ac295b9d5a7c35\nmsgid \"|PyMuPDF|\"\nmsgstr \"\"\n\n#: ../../app4.rst:144 265dd2b9a51a4748ae710d0a7781b16c\nmsgid \"The tool of this manual.\"\nmsgstr \"このマニュアルのツールです。\"\n\n#: ../../app4.rst:145 0d7018f04c2d4b8b91e09d879a94c489\nmsgid \"PDFrw_\"\nmsgstr \"\"\n\n#: ../../app4.rst:146 1871dfbb59ed44559c1143b8f664ab3b\nmsgid \"\"\n\"A pure :title:`Python` tool, being used by :title:`rst2pdf`, has \"\n\"interface to :title:`ReportLab`.\"\nmsgstr \"\"\n\":title:`rst2pdf` で使用される純粋な :title:`Python` \"\n\"ツールで、ReportLabとのインターフェースを持っています。\"\n\n#: ../../app4.rst:147 db3dc67db0384a4caf25ec3159cc9e8c\nmsgid \"PyPDF2_\"\nmsgstr \"\"\n\n#: ../../app4.rst:148 f00f0472c11846dd8a6d1cb0ac0237bf\nmsgid \"A pure :title:`Python` tool with a large function set.\"\nmsgstr \"多くの機能を備えた純粋な :title:`Python` ツールです。\"\n\n#: ../../app4.rst:149 719bb221eb5b4d34a21a977bfddfa966\nmsgid \"PDFMiner_\"\nmsgstr \"\"\n\n#: ../../app4.rst:150 7c679bd2a294494c86c754ffaddb5cf3\nmsgid \"A pure :title:`Python` to extract text and other data from |PDF|.\"\nmsgstr \"|PDF| からテキストやその他のデータを抽出するための純粋な :title:`Python` ツールです。\"\n\n#: ../../app4.rst:151 ef3100ff8d5049009f9896ca197346c5\nmsgid \"XPDF_\"\nmsgstr \"\"\n\n#: ../../app4.rst:152 89c9c95eccee414e90d74c494ef8fa0c\nmsgid \"A command line utility with multiple functions.\"\nmsgstr \"複数の機能を備えたコマンドラインユーティリティです。\"\n\n#: ../../app4.rst:153 3ac8573211c94c1996a3f39372a5c365\nmsgid \"PikePDF_\"\nmsgstr \"\"\n\n#: ../../app4.rst:154 ad269cc30d2f43dbbd44e72f1cfa24e9\nmsgid \"\"\n\"A :title:`Python` package similar to :title:`PDFrw`, but based on \"\n\":title:`C++` library :title:`QPDF`.\"\nmsgstr \"\"\n\":title:`C++` ライブラリ :title:`QPDF` に基づいた :title:`Python` パッケージで、 \"\n\":title:`PDFrw` に類似しています。\"\n\n#: ../../app4.rst:155 f7a4dbe832784e9c80a9bec19efd26e4\nmsgid \"PDF2JPG_\"\nmsgstr \"\"\n\n#: ../../app4.rst:156 2354f030ddfb48028e2dc5dcdca588bf\nmsgid \"\"\n\"A :title:`Python` package specialized on rendering |PDF| pages to \"\n\":title:`JPG` images.\"\nmsgstr \"|PDF| ページを :title:`JPG` 画像にレンダリングすることに特化した :title:`Python` パッケージです。\"\n\n#: ../../app4.rst:164 20ec5781714e43979415d31bca6e4d91\nmsgid \"Copying / Joining / Merging\"\nmsgstr \"コピー / 結合 / マージ\"\n\n#: ../../app4.rst:166 24e5ae35daf74ce5af40e0c2fc945067\nmsgid \"\"\n\"How fast is a |PDF| file read and its content parsed for further \"\n\"processing? The sheer parsing performance cannot directly be compared, \"\n\"because batch utilities always execute a requested task completely, in \"\n\"one go, front to end. :title:`PDFrw` too, has a *lazy* strategy for \"\n\"parsing, meaning it only parses those parts of a document that are \"\n\"required in any moment.\"\nmsgstr \"\"\n\"|PDF| \"\n\"ファイルの読み取りおよびそのコンテンツの解析は、どれだけ高速に行われるのでしょうか？純粋な解析の性能を直接比較することはできません。なぜなら、バッチユーティリティは常に要求されたタスクを一度に完全に実行するからです。\"\n\" :title:`PDFrw` も解析の際には *レイジー* な戦略を採用しており、必要な瞬間に必要な部分のみを解析します。\"\n\n#: ../../app4.rst:168 9030ee0b64da48c4b6ba3563a6fe7da8\nmsgid \"\"\n\"To find an answer to the question, we therefore measure the time to copy \"\n\"a |PDF| file to an output file with each tool, and do nothing else.\"\nmsgstr \"したがって、この質問に答えるために、各ツールで |PDF| ファイルを出力ファイルにコピーする時間を計測し、それ以外の操作は行いません。\"\n\n#: ../../app4.rst:170 ../../app4.rst:365 75c4e9d6b0f94276ad4a46e7ca064b4c\n#: d29245da53b44d4c931cdfd53a686bcb\nmsgid \"These are the :title:`Python` commands for how each tool is used:\"\nmsgstr \"各ツールの使用方法に関する :title:`Python` コマンドは以下の通りです：\"\n\n#: ../../app4.rst:180 40554a7aac2c4529a5cea2cb201adc33\nmsgid \":title:`PDFrw`\"\nmsgstr \"\"\n\n#: ../../app4.rst:190 2027a14c030c4dafa9b213b842921038\nmsgid \":title:`PikePDF`\"\nmsgstr \"\"\n\n#: ../../app4.rst:198 0554b1918f0442929d092d7d1aa8c6db\nmsgid \":title:`PyPDF2`\"\nmsgstr \"\"\n\n#: ../../app4.rst:210 ../../app4.rst:288 ../../app4.rst:399\n#: 0cc77d5085aa42b092a9d28c9f9b93d1 2151ed94f39e42489d9407b0a8ac0ccb\n#: 8e952a6e6d1d46499282ea93f770529c\nmsgid \"**Observations**\"\nmsgstr \"**観察結果**\"\n\n#: ../../app4.rst:212 ../../app4.rst:290 ../../app4.rst:401\n#: 190b33a2a1264d58900d557c11876da4 2995f439d6cb495da4b80e31d49c47a7\n#: 536ccc62e0b8415f92d295558b4e0e5b\nmsgid \"\"\n\"These are our run time findings in **seconds** along with a base rate \"\n\"summary compared to |PyMuPDF|:\"\nmsgstr \"以下は、実行時間の結果（ **秒単位**）と、 |PyMuPDF| との比較における基本レートの要約です：\"\n\n#: ../../app4.rst:219 a51de26a6852481a8e70a53e96187379\nmsgid \"**PDFrw**\"\nmsgstr \"\"\n\n#: ../../app4.rst:220 933434ca403749c0a4f630ffec63fbf0\nmsgid \"**PikePDF**\"\nmsgstr \"\"\n\n#: ../../app4.rst:221 ../../app4.rst:298 93a77920ab2f426481a1d5037c17135f\n#: a5fda08d4d34464ba81569732331f63c\nmsgid \"**PyPDF2**\"\nmsgstr \"\"\n\n#: ../../app4.rst:222 ../../app4.rst:300 ../../app4.rst:411\n#: 5544726c03fb43a2afaa6c61866bba6a 5ade818fb72c4831ad8691c9cf811c78\n#: af7a989e3b5144c1a3f9d080bc5aea03\nmsgid \"adobe.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:223 aea85b36f9074c44ac0e480e9feedf9a\nmsgid \"1.75\"\nmsgstr \"\"\n\n#: ../../app4.rst:224 1d5d21531c014823b5bd62db7bc0135e\nmsgid \"5.15\"\nmsgstr \"\"\n\n#: ../../app4.rst:225 29285cb95fbc41c7b91b01dda4181c2d\nmsgid \"22.37\"\nmsgstr \"\"\n\n#: ../../app4.rst:226 68b490eb621f4f4eb992f5e5eb9baff5\nmsgid \"374.05\"\nmsgstr \"\"\n\n#: ../../app4.rst:227 ../../app4.rst:305 ../../app4.rst:415\n#: 00246b4fa6bb413aaecfac538ed32b19 20452d17f0ed4d98ab1d92047ddb55a7\n#: dc633929adc3417d9c90d8be2bf90613\nmsgid \"artifex-website.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:228 3e3d60bb5a06431f8423b7fa72008e45\nmsgid \"0.26\"\nmsgstr \"\"\n\n#: ../../app4.rst:229 ../../app4.rst:243 2ce822ddafa04eacb665dcdd8bb34f25\n#: a0ca8a854b9c428a9257c8dbf52b4590\nmsgid \"0.38\"\nmsgstr \"\"\n\n#: ../../app4.rst:230 63e990f7145f451dac1615b7274b980f\nmsgid \"1.41\"\nmsgstr \"\"\n\n#: ../../app4.rst:231 e5e9ce25649c4a7e87d9cfed1d4c1f0a\nmsgid \"2.81\"\nmsgstr \"\"\n\n#: ../../app4.rst:232 ../../app4.rst:310 ../../app4.rst:419\n#: 1abbb91fd2804bff9cc59d244e834dbe 25ef69a136294635ad82241de488155a\n#: 5c166f9365fb4824bbe295d262a4c695\nmsgid \"db-systems.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:233 dfa580f9d5494073b720002293a6fa82\nmsgid \"0.15\"\nmsgstr \"\"\n\n#: ../../app4.rst:234 0cabf0e69a2e40a8920e44b780f064b6\nmsgid \"0.8\"\nmsgstr \"\"\n\n#: ../../app4.rst:235 1b45bb6fb5384d11863727a44bc772d5\nmsgid \"1.68\"\nmsgstr \"\"\n\n#: ../../app4.rst:236 482704feedf44b168160d5c6bf430e89\nmsgid \"2.46\"\nmsgstr \"\"\n\n#: ../../app4.rst:237 ../../app4.rst:315 ../../app4.rst:423\n#: 28cf3f5a2e644968b1b497d836968533 619f6293468e4a5b9414def4ae968f6a\n#: a54e51785c104643876df4110d7f60fb\nmsgid \"fontforge.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:238 80142473274946b2b76110266168f6d2\nmsgid \"0.09\"\nmsgstr \"\"\n\n#: ../../app4.rst:239 fdeb0d08542549ad94e6f5ff68f639e1\nmsgid \"0.14\"\nmsgstr \"\"\n\n#: ../../app4.rst:240 fa056a25dbc24ce8bbb7206ac25c05ae\nmsgid \"0.28\"\nmsgstr \"\"\n\n#: ../../app4.rst:241 ../../app4.rst:308 4bafecabe76b409d8db8ac377d7f7ea9\n#: 5206ddcbea3c43ab869b569ff3172038\nmsgid \"1.1\"\nmsgstr \"\"\n\n#: ../../app4.rst:242 ../../app4.rst:320 ../../app4.rst:427\n#: 283144343a0949668598a967aab1deef 2bf82f9384f34930a1debf451276e32e\n#: f64eb5e532a04104b1c1491cdd231638\nmsgid \"pandas.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:244 c0f38df2b0cd4082acfb9b25f340902a\nmsgid \"2.21\"\nmsgstr \"\"\n\n#: ../../app4.rst:245 9594837d5d2848c6bd8fc40d23f432db\nmsgid \"2.73\"\nmsgstr \"\"\n\n#: ../../app4.rst:246 d52e2689ad7047df8dcab08a5b7c5417\nmsgid \"70.3\"\nmsgstr \"\"\n\n#: ../../app4.rst:247 ../../app4.rst:325 ../../app4.rst:431\n#: 6adf778936ea4b1bac0e0112c0f3d53a ca7e5c0d37d843a5a058022264ef4838\n#: df12e19f983a4715a95aa5e1c4259037\nmsgid \"pymupdf.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:248 50c706b1c6eb4ba783605c298016ffd9\nmsgid \"0.11\"\nmsgstr \"\"\n\n#: ../../app4.rst:249 e6316c498d704c12a367a5598ce1dfa4\nmsgid \"0.56\"\nmsgstr \"\"\n\n#: ../../app4.rst:250 c9b02d42498945f39b746d182ceef93f\nmsgid \"0.83\"\nmsgstr \"\"\n\n#: ../../app4.rst:251 a866f67188d54c70912cd3e19c35d760\nmsgid \"6.05\"\nmsgstr \"\"\n\n#: ../../app4.rst:252 ../../app4.rst:330 ../../app4.rst:435\n#: 2d6911f21f034fdb99236c6da0e5c8fc ca646d19848a4024b113f84e29e5f016\n#: ddf7610dcd7d4c2085d801cc70dfa46b\nmsgid \"pythonbook.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:253 6f0fe33ac23b4d0baf5009363bc75c5b\nmsgid \"0.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:254 680b3cbd12934d07830711fdf35d8c00\nmsgid \"1.2\"\nmsgstr \"\"\n\n#: ../../app4.rst:255 fbbf220c922f4a53ab16e06f0c5042ee\nmsgid \"1.34\"\nmsgstr \"\"\n\n#: ../../app4.rst:256 e94988b7dbc347c09260a2b8a03dd461\nmsgid \"37.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:257 ../../app4.rst:335 ../../app4.rst:439\n#: a9d4ceb80d2c42e0b7bf4c22de480e63 aa346b20c8c14103ad508c92238ca1a8\n#: b0d041755ac04554a0acc858c79f4516\nmsgid \"sample-50-MB-pdf-file.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:258 bcc275d36bf04161834713d6d786e356\nmsgid \"0.12\"\nmsgstr \"\"\n\n#: ../../app4.rst:259 cb526a85171a4e5c924b02fae9f5cff1\nmsgid \"0.1\"\nmsgstr \"\"\n\n#: ../../app4.rst:260 57e608621ccb4404a586b7361b537020\nmsgid \"2.93\"\nmsgstr \"\"\n\n#: ../../app4.rst:261 e280682fa0f048f7bf4a842026ed388c\nmsgid \"0.08\"\nmsgstr \"\"\n\n#: ../../app4.rst:262 ../../app4.rst:340 ../../app4.rst:443\n#: 147889494a0342d39c8d7bc589e777a1 9dde60202b154d62bb5dc5da1b8f3eb4\n#: dcdc53ddede34633afbb78b8cb474780\nmsgid \"**Total**\"\nmsgstr \"**合計** \"\n\n#: ../../app4.rst:263 482ff9ef77514db0a3105d43540c6a79\nmsgid \"**3.05**\"\nmsgstr \"\"\n\n#: ../../app4.rst:264 2f728a892b10493f83a211bbe00dc8c2\nmsgid \"**10.54**\"\nmsgstr \"\"\n\n#: ../../app4.rst:265 8a1310321389468b8eeb7302181de22f\nmsgid \"**33.57**\"\nmsgstr \"\"\n\n#: ../../app4.rst:266 8979d1c755ab4d5480e0e543908439ab\nmsgid \"**494.04**\"\nmsgstr \"\"\n\n#: ../../app4.rst:272 ../../app4.rst:350 ../../app4.rst:451\n#: 39d408ac310b429a9f4630de549c0218 b1cedcb976d7467cb64b4a03e059059f\n#: d60f7ab07be042e9ac4f315656e9d80e\nmsgid \"**Rate compared to PyMuPDF**\"\nmsgstr \"**PyMuPDFに対する比率** \"\n\n#: ../../app4.rst:273 ../../app4.rst:351 ../../app4.rst:452\n#: 5fe241f7da6f4f1287b2ef598e77e63a a1eabf390faf4118b9fbf1c23bcaa970\n#: ca4532068a8749cebe70ecd680077cff\nmsgid \":green-color:`1.0`\"\nmsgstr \"\"\n\n#: ../../app4.rst:274 4bebef049b2147ec9412439a06413b0c\nmsgid \":orange-color:`3.5`\"\nmsgstr \"\"\n\n#: ../../app4.rst:275 bd4c733cfe544784bfac89860db9068e\nmsgid \":orange-color:`11.0`\"\nmsgstr \"\"\n\n#: ../../app4.rst:276 65a3d5ea7ac842238d61067451bc62b9\nmsgid \":red-color:`162`\"\nmsgstr \"\"\n\n#: ../../app4.rst:283 1cd4fd60fed8493aa0180e6aced6f887\nmsgid \"Text Extraction\"\nmsgstr \"テキスト抽出\"\n\n#: ../../app4.rst:285 43ec059052ef49239504e79c59d48792\nmsgid \"\"\n\"The following table shows plain text extraction durations. All tools have\"\n\" been used with their most basic functionality - i.e. no layout re-\"\n\"arrangements, etc.\"\nmsgstr \"\"\n\"以下の表は、プレーンテキストの抽出にかかる時間を示しています。すべてのツールは、基本的な機能のみを使用しています - \"\n\"レイアウトの再配置などはありません。\"\n\n#: ../../app4.rst:297 ../../app4.rst:409 493d81649a04476aa7e157c8155e8816\n#: c7a4bc884d3e4b39ab49157d277af5e6\nmsgid \"**XPDF**\"\nmsgstr \"\"\n\n#: ../../app4.rst:299 55447e13f7cc43598fde158caf1adfbf\nmsgid \"**PDFMiner**\"\nmsgstr \"\"\n\n#: ../../app4.rst:301 71ff39c17b764e46a725f342a082f147\nmsgid \"2.01\"\nmsgstr \"\"\n\n#: ../../app4.rst:302 fce895fddd9544e4b84bbc464bc5d54a\nmsgid \"6.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:303 11d7da5f489c4d5c8f08904e64d58b85\nmsgid \"22.2\"\nmsgstr \"\"\n\n#: ../../app4.rst:304 7a43720209f2409891b79edcb6feebc8\nmsgid \"49.15\"\nmsgstr \"\"\n\n#: ../../app4.rst:306 86da45bd435e4e2fac8f537ac4dc33c6\nmsgid \"0.18\"\nmsgstr \"\"\n\n#: ../../app4.rst:307 9f329e56a13e4944887ba215aadd1c50\nmsgid \"0.3\"\nmsgstr \"\"\n\n#: ../../app4.rst:309 412c97e97e644221bec455efaa9ee865\nmsgid \"4.06\"\nmsgstr \"\"\n\n#: ../../app4.rst:311 3211848a2c7541c4b98431190bc82a51\nmsgid \"1.57\"\nmsgstr \"\"\n\n#: ../../app4.rst:312 7888933412524d77b9710d7c349a6ad8\nmsgid \"4.26\"\nmsgstr \"\"\n\n#: ../../app4.rst:313 78ac7fd7df42471aa6a3ac3bb3b13b4f\nmsgid \"25.75\"\nmsgstr \"\"\n\n#: ../../app4.rst:314 fbda6230814e4005b8c47d862c0364c4\nmsgid \"42.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:316 05c924d4dc1e4feb955b06be14c5e7e7\nmsgid \"0.24\"\nmsgstr \"\"\n\n#: ../../app4.rst:317 eff929019a05485ab7d424571a631738\nmsgid \"0.47\"\nmsgstr \"\"\n\n#: ../../app4.rst:318 d732cff1f2af4741b0cf005af6150933\nmsgid \"2.69\"\nmsgstr \"\"\n\n#: ../../app4.rst:319 d717cab56bbc403fa2d497180e09afac\nmsgid \"4.2\"\nmsgstr \"\"\n\n#: ../../app4.rst:321 6f2bb2d646834a28b637393c83fbe756\nmsgid \"2.41\"\nmsgstr \"\"\n\n#: ../../app4.rst:322 297e3c2d5f354ca6a5f331312ada2eb9\nmsgid \"10.54\"\nmsgstr \"\"\n\n#: ../../app4.rst:323 e7aaee8a7d6d46738acd6d36fd3a1a2b\nmsgid \"25.38\"\nmsgstr \"\"\n\n#: ../../app4.rst:324 22691134bd124353bac936a15dc23c7d\nmsgid \"76.56\"\nmsgstr \"\"\n\n#: ../../app4.rst:326 beb7e60f87f44b00941524176f83234b\nmsgid \"0.49\"\nmsgstr \"\"\n\n#: ../../app4.rst:327 f1987f898ec44e2eae7731378a36d310\nmsgid \"2.34\"\nmsgstr \"\"\n\n#: ../../app4.rst:328 ef61cf5a5cb042fdbb4db7ffb338d866\nmsgid \"6.44\"\nmsgstr \"\"\n\n#: ../../app4.rst:329 22b1b07b84d542088f18ea5fb77ba24f\nmsgid \"13.55\"\nmsgstr \"\"\n\n#: ../../app4.rst:331 0832e852468f492a9ecffee3998af4f2\nmsgid \"0.84\"\nmsgstr \"\"\n\n#: ../../app4.rst:332 3a29ccef7ff44af0bbc12374a5983e38\nmsgid \"2.88\"\nmsgstr \"\"\n\n#: ../../app4.rst:333 be833e3e8322409ba592cc7891bfd260\nmsgid \"9.28\"\nmsgstr \"\"\n\n#: ../../app4.rst:334 fb41a43110744ce98af7eee58740fb05\nmsgid \"24.27\"\nmsgstr \"\"\n\n#: ../../app4.rst:336 81ca0ec15e384df3998d921f54470058\nmsgid \"0.27\"\nmsgstr \"\"\n\n#: ../../app4.rst:337 fe5e6af169c04db999c3003913c8ad6e\nmsgid \"0.44\"\nmsgstr \"\"\n\n#: ../../app4.rst:338 9220f3fa950e47009211a9f69d405117\nmsgid \"8.8\"\nmsgstr \"\"\n\n#: ../../app4.rst:339 a9338bdb413148689255f70fbeead632\nmsgid \"13.29\"\nmsgstr \"\"\n\n#: ../../app4.rst:341 978aa50a4e73446ca6444f7911b99137\nmsgid \"**8.01**\"\nmsgstr \"\"\n\n#: ../../app4.rst:342 c80a0bb069c644938e92b9da92483efa\nmsgid \"**27.42**\"\nmsgstr \"\"\n\n#: ../../app4.rst:343 3aff3e7279a74a2b90e22e23593c2795\nmsgid \"**101.64**\"\nmsgstr \"\"\n\n#: ../../app4.rst:344 4fe0e88c92fd44c7af9bc827ce45422c\nmsgid \"**227.27**\"\nmsgstr \"\"\n\n#: ../../app4.rst:352 63cc33b2658d4c45b2ba8cbe943bd222\nmsgid \":orange-color:`3.42`\"\nmsgstr \"\"\n\n#: ../../app4.rst:353 0533ece4f3e14f7c96cb711e9d3b3fbf\nmsgid \":orange-color:`12.69`\"\nmsgstr \"\"\n\n#: ../../app4.rst:354 1a614a3651e448a9911ab3eedaac4d42\nmsgid \":red-color:`28.37`\"\nmsgstr \"\"\n\n#: ../../app4.rst:360 00b592ac57f64130a8654c00830f154e\nmsgid \"Page Rendering\"\nmsgstr \"ページのレンダリング\"\n\n#: ../../app4.rst:362 f5119aaf183e4f4eb483e9c337c88488\nmsgid \"\"\n\"We have tested rendering speed of |PyMuPDF| against :title:`pdf2jpg` and \"\n\":title:`XPDF` at a resolution of 150 DPI,\"\nmsgstr \"\"\n\"私たちは、解像度150 DPIで |PyMuPDF| のレンダリング速度を :title:`pdf2jpg` と :title:`XPDF` \"\n\"と比較しました。\"\n\n#: ../../app4.rst:382 02cf04dabcd44b9998f6e4e25bbca5ee\nmsgid \":title:`XPDF`\"\nmsgstr \"\"\n\n#: ../../app4.rst:389 90770272b10c416e84826a42e1c212cc\nmsgid \":title:`PDF2JPG`\"\nmsgstr \"\"\n\n#: ../../app4.rst:410 c717d43cc70e48e98e87edcf403d8b03\nmsgid \"**PDF2JPG**\"\nmsgstr \"\"\n\n#: ../../app4.rst:412 da606418caee4a099a285d88fdee4bcb\nmsgid \"51.33\"\nmsgstr \"\"\n\n#: ../../app4.rst:413 d42b2bb121b54a939a97fd7c82e60632\nmsgid \"98.16\"\nmsgstr \"\"\n\n#: ../../app4.rst:414 97e1e5c516654f909a445d6158df2fef\nmsgid \"75.71\"\nmsgstr \"\"\n\n#: ../../app4.rst:416 c1a00e6812494e27a1e5513c5dcb6515\nmsgid \"26.35\"\nmsgstr \"\"\n\n#: ../../app4.rst:417 525f071275c846daaccf5b9ad9472c35\nmsgid \"51.28\"\nmsgstr \"\"\n\n#: ../../app4.rst:418 dab5c30a6ab14679837b7c79be1baef5\nmsgid \"54.11\"\nmsgstr \"\"\n\n#: ../../app4.rst:420 6347c08651eb4dfc963827edfe3c2dfa\nmsgid \"84.59\"\nmsgstr \"\"\n\n#: ../../app4.rst:421 9ff9e6ea2bff413e96b7948a6cdd6c2d\nmsgid \"143.16\"\nmsgstr \"\"\n\n#: ../../app4.rst:422 088e57b2eec94b3bbbf1258987f8c664\nmsgid \"405.22\"\nmsgstr \"\"\n\n#: ../../app4.rst:424 b3cf9ee794b34bad8b6dbfe411512b74\nmsgid \"12.23\"\nmsgstr \"\"\n\n#: ../../app4.rst:425 d51b92890c7442579c00adf23e97f279\nmsgid \"22.18\"\nmsgstr \"\"\n\n#: ../../app4.rst:426 3f7b41851cdf4ca493af2c869d25b055\nmsgid \"20.14\"\nmsgstr \"\"\n\n#: ../../app4.rst:428 226831c9dbf7408f9116226b0776dff5\nmsgid \"138.74\"\nmsgstr \"\"\n\n#: ../../app4.rst:429 c0ff7f066efe4586859fcd60916d8201\nmsgid \"241.67\"\nmsgstr \"\"\n\n#: ../../app4.rst:430 c348dd9ee91b448aad5e075ccac79cbc\nmsgid \"202.06\"\nmsgstr \"\"\n\n#: ../../app4.rst:432 5ac66403bf9a49aead460327d7c44f45\nmsgid \"22.35\"\nmsgstr \"\"\n\n#: ../../app4.rst:433 9173e53f1f69448a83d553ded32bb807\nmsgid \"39.11\"\nmsgstr \"\"\n\n#: ../../app4.rst:434 89611809173d45ae8ac3a4f7089ee725\nmsgid \"33.38\"\nmsgstr \"\"\n\n#: ../../app4.rst:436 533943d891b74af491898743b80b7be3\nmsgid \"30.44\"\nmsgstr \"\"\n\n#: ../../app4.rst:437 940113c92ada4f3fabf8932a0ec143e4\nmsgid \"49.12\"\nmsgstr \"\"\n\n#: ../../app4.rst:438 0698ab345b994705a75ccfaddd9670fa\nmsgid \"55.68\"\nmsgstr \"\"\n\n#: ../../app4.rst:440 022d36dd2a304fca9d994fd8aebb4229\nmsgid \"1.01\"\nmsgstr \"\"\n\n#: ../../app4.rst:441 fb7736a3bc7c4ca29f4fce61faf4b788\nmsgid \"1.32\"\nmsgstr \"\"\n\n#: ../../app4.rst:442 dabe4ab239f1407f95b68ad8269a33af\nmsgid \"5.22\"\nmsgstr \"\"\n\n#: ../../app4.rst:444 23819f93562342a8b546fc017760f1c2\nmsgid \"**367.04**\"\nmsgstr \"\"\n\n#: ../../app4.rst:445 1616c1fe2bca4ff2a048b9308c0f246e\nmsgid \"**646**\"\nmsgstr \"\"\n\n#: ../../app4.rst:446 5bdba98414414ff8ac81e89e0e221e71\nmsgid \"**851.52**\"\nmsgstr \"\"\n\n#: ../../app4.rst:453 d581d4e1ac754c2b9e0172b86aeb3edf\nmsgid \":orange-color:`1.76`\"\nmsgstr \"\"\n\n#: ../../app4.rst:454 5a2a9f45f5b14d398c5c1891f3ed968c\nmsgid \":red-color:`2.32`\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 6f6b539ff34a4640ab8af9e5deaeacb0\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"`adobe.pdf`_\"\n#~ msgstr \"\"\n\n#~ msgid \"`artifex-website.pdf`_\"\n#~ msgstr \"\"\n\n#~ msgid \"`db-systems.pdf`_\"\n#~ msgstr \"\"\n\n#~ msgid \"`fontforge.pdf`_\"\n#~ msgstr \"\"\n\n#~ msgid \"`pandas.pdf`_\"\n#~ msgstr \"\"\n\n#~ msgid \"`pymupdf.pdf`_\"\n#~ msgstr \"\"\n\n#~ msgid \"`pythonbook.pdf`_\"\n#~ msgstr \"\"\n\n#~ msgid \"`sample-50-MB-pdf-file.pdf`_\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/archive-class.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 d617abc2bac44b79b8895c5a477d435e\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 11676cd8a070416581b0f70844041acd\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 e1542b64861144078ef1fec53974ec47\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../archive-class.rst:7 2f0bf46e9ac54fd68b23bc9210c74150\nmsgid \"Archive\"\nmsgstr \"Archive (アーカイブ)\"\n\n#: ../../archive-class.rst:9 46f4ce49429542a1b693c99eadca160d\nmsgid \"New in v1.21.0\"\nmsgstr \"v1.21.0での新機能\"\n\n#: ../../archive-class.rst:11 90ae46c1e95142ec8216ccb598850553\nmsgid \"\"\n\"This class represents a generalization of file folders and container \"\n\"files like ZIP and TAR archives. Archives allow accessing arbitrary \"\n\"collections of file folders, ZIP / TAR files and single binary data \"\n\"elements as if they all were part of one hierarchical tree of folders.\"\nmsgstr \"このクラスは、ファイルフォルダーやZIPやTARアーカイブのようなコンテナファイルの一般化を表します。アーカイブは、ファイルフォルダー、ZIP/TARファイル、および単一のバイナリデータ要素の任意のコレクションにアクセスできるようにし、すべてが1つの階層的なフォルダーツリーの一部であるかのようにします。\"\n\n#: ../../archive-class.rst:13 3fd435f3261d48d4a0a727f172c9ddb6\nmsgid \"\"\n\"In PyMuPDF, archives are currently only used by :ref:`Story` objects to \"\n\"specify where to look for fonts, images and other resources.\"\nmsgstr \"\"\n\"PyMuPDFでは、アーカイブは現在、フォント、画像、およびその他のリソースを検索する場所を指定するために :ref:`Story` \"\n\"オブジェクトによってのみ使用されています。\"\n\n#: ../../archive-class.rst:16 1829b6e552a94dc5a3c61784652f1d73\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../archive-class.rst:16 2bf68b939c1d44f7be1ca6d449c27e53\nmsgid \"**Short Description**\"\nmsgstr \"**簡単な説明**\"\n\n#: ../../archive-class.rst:18 5b94b5437aa84ff9a245301a956f8d18\nmsgid \":meth:`Archive.add`\"\nmsgstr \"\"\n\n#: ../../archive-class.rst:18 8c9d95f042814c25a324f3ce9ec79170\nmsgid \"add new data to the archive\"\nmsgstr \"アーカイブに新しいデータを追加する\"\n\n#: ../../archive-class.rst:19 d5b520ec1d214317ac63ec60b509eb43\nmsgid \":meth:`Archive.has_entry`\"\nmsgstr \"\"\n\n#: ../../archive-class.rst:19 054f56f20f6d4fa8a033a1dd80bd3cb6\nmsgid \"check if given name is a member\"\nmsgstr \"名前で指定されたデータを読む\"\n\n#: ../../archive-class.rst:20 dc2f8062523044d19ec994b1828e3195\nmsgid \":meth:`Archive.read_entry`\"\nmsgstr \"\"\n\n#: ../../archive-class.rst:20 e680d9fb1dd44a7f85a61af9853e4e6d\nmsgid \"read the data given by the name\"\nmsgstr \"名前で指定されたデータを読む\"\n\n#: ../../archive-class.rst:21 e41ca685715b4dcbb45e53b209029663\nmsgid \":attr:`Archive.entry_list`\"\nmsgstr \"\"\n\n#: ../../archive-class.rst:21 f31453b71aeb4ade88edbebb982ff071\nmsgid \"list[dict] of archive items\"\nmsgstr \"アーカイブアイテムのリスト[辞書]\"\n\n#: ../../archive-class.rst:24 98357f302ae84859bd401682492995fa\nmsgid \"**Class API**\"\nmsgstr \"クラス API\"\n\n#: ../../archive-class.rst:30 422de49b171f4d18afbb8516afbc9095\nmsgid \"Creates a new archive. Without parameters, an empty archive is created.\"\nmsgstr \"新しいアーカイブを作成します。パラメーターが指定されない場合、空のアーカイブが作成されます。\"\n\n#: ../../archive-class.rst:32 ae5782f0b4a54bc3be2c009daab1a7ca\nmsgid \"If provided, `content` may be one of the following:\"\nmsgstr \"提供される場合、`content` は次のいずれかであることができます：\"\n\n#: ../../archive-class.rst:34 fbf461b873ef4da5b1fda4e484d46cbf\nmsgid \"another Archive: the archive is being made a sub-archive of the new one.\"\nmsgstr \"別の Archive: アーカイブは新しいアーカイブのサブアーカイブになります。\"\n\n#: ../../archive-class.rst:36 6ac58a1199014e0a932f80579a01fff4\nmsgid \"\"\n\"a string: this must be the name of a local folder or file. `pathlib.Path`\"\n\" objects are also supported.\"\nmsgstr \"文字列: これはローカルフォルダまたはファイルの名前である必要があります。`pathlib.Path` オブジェクトもサポートされています。\"\n\n#: ../../archive-class.rst:38 63b7f15541554ca28bb94dacd2e33b99\nmsgid \"\"\n\"A **folder** will be converted to a sub-archive, so its files (and any \"\n\"sub-folders) can be accessed by their names.\"\nmsgstr \"**フォルダ** はサブアーカイブに変換され、そのファイル（およびサブフォルダ）は名前でアクセスできます。\"\n\n#: ../../archive-class.rst:39 547200864ba043b295790af8b0b2a6cf\nmsgid \"\"\n\"A **file** will be read with mode `\\\"rb\\\"` and these binary data (a \"\n\"`bytes` object) be treated as a single-member sub-archive. In this case, \"\n\"the `path` parameter is **mandatory** and should be the member name under\"\n\" which this item can be found / retrieved.\"\nmsgstr \"\"\n\"**ファイル** はモード `\\\"rb\\\"` で読み取られ、これらのバイナリデータ（ `bytes` \"\n\"オブジェクト）は単一のメンバーサブアーカイブとして扱われます。この場合、`path` パラメーターは **必須** \"\n\"で、このアイテムが見つかる/取得できるメンバー名である必要があります。\"\n\n#: ../../archive-class.rst:41 26fc387cc92a49b18be5fbb6e276303a\nmsgid \"\"\n\"a `zipfile.ZipFile` or `tarfile.TarFile` object: Will be added as a sub-\"\n\"archive.\"\nmsgstr \"`zipfile.ZipFile` または `tarfile.TarFile` オブジェクト: サブアーカイブとして追加されます。\"\n\n#: ../../archive-class.rst:43 a95ece3a221d4379bbdf468f3d625687\nmsgid \"\"\n\"a Python binary object (`bytes`, `bytearray`, `io.BytesIO`): this will \"\n\"add a single-member sub-archive. In this case, the `path` parameter is \"\n\"**mandatory** and should be the member name under which this item can be \"\n\"found / retrieved.\"\nmsgstr \"\"\n\"Python バイナリオブジェクト（ `bytes`、`bytearray` 、`io.BytesIO` ）: \"\n\"これは単一のメンバーサブアーカイブを追加します。この場合、`path` パラメーターは **必須** \"\n\"で、このアイテムが見つかる/取得できるメンバー名である必要があります。\"\n\n#: ../../archive-class.rst:45 6cefb5b8a5ae4538b432a671e5624634\n\nmsgid \"\"\n\"a tuple `(data, name)`: This will add a single-member sub-archive with \"\n\"the member name ``name``. ``data`` may be a Python binary object or a \"\n\"local file name (in which case its binary file content is used). Use this\"\n\" format if you need to specify `path`.\"\nmsgstr \"\"\n\"タプル `(data, name)` : これはメンバー名 ``name`` を持つ単一のメンバーサブアーカイブを追加します。 ``data`` \"\n\"はPythonバイナリオブジェクトまたはローカルファイル名である可能性があります（その場合、バイナリファイルのコンテンツが使用されます）。`path`\"\n\" を指定する必要がある場合は、このフォーマットを使用してください。\"\n\n#: ../../archive-class.rst:47 8916743a3d2e482e8fac00263e7c6839\nmsgid \"\"\n\"a Python sequence: This is a convenience format to specify any \"\n\"combination of the above.\"\nmsgstr \"Pythonシーケンス: これは上記のいずれかの組み合わせを指定するための便益フォーマットです。\"\n\n#: ../../archive-class.rst:49 ea2b6c8e209e48e7a488431fc4d5dc5b\nmsgid \"If provided, `path` must be a string.\"\nmsgstr \"提供される場合、`path` は文字列である必要があります。\"\n\n#: ../../archive-class.rst:51 ce6b5084838e47998c1c0930a1c90a85\nmsgid \"\"\n\"If `content` is either binary data or a file name, this parameter is \"\n\"mandatory and must be the name under which the data can be found.\"\nmsgstr \"`content` がバイナリデータまたはファイル名の場合、このパラメーターは必須で、データが見つかる名前である必要があります。\"\n\n#: ../../archive-class.rst:53 bfdfb9696f9d4267b9a0abcd4944814d\nmsgid \"\"\n\"Otherwise this parameter is optional. It can be used to simulate a folder\"\n\" name or a mount point, under which this sub-archive's elements can be \"\n\"found. For example this specification `Archive((data, \\\"name\\\"), \"\n\"\\\"path\\\")` means that `data` will be found using the element name \"\n\"`\\\"path/name\\\"`. Similar is true for other sub-archives: to retrieve \"\n\"members of a ZIP sub-archive, their names must be prefixed with \"\n\"`\\\"path/\\\"`. The main purpose of this parameter probably is to \"\n\"differentiate between duplicate names.\"\nmsgstr \"\"\n\"それ以外の場合、このパラメーターはオプションです。これは、このサブアーカイブの要素が見つかるマウントポイントまたはフォルダ名をシミュレートするために使用できます。たとえば、この仕様\"\n\" `Archive((data, \\\"name\\\"), \\\"path\\\")` は、データが要素名 \\\"`\\\"path/name\\\"` \"\n\"で見つかります。他のサブアーカイブについても同様です：ZIPサブアーカイブのメンバーを取得するには、その名前に `\\\"path/\\\"` \"\n\"を接頭辞として追加する必要があります。このパラメーターの主な目的は、重複する名前を区別することである可能性があります。\"\n\n#: ../../archive-class.rst:55 61677063f42641209e56a228534c33f2\nmsgid \"\"\n\"If duplicate entry names exist in the archive, always the last entry with\"\n\" that name will be found / retrieved. During archive creation, or \"\n\"appending more data to an archive (see :meth:`Archive.add`) no check for \"\n\"duplicates will be made. Use the `path` parameter to prevent this from \"\n\"happening.\"\nmsgstr \"\"\n\"アーカイブ内に重複するエントリ名が存在する場合、常にその名前の最後のエントリが見つかり/取得されます。アーカイブの作成中、またはアーカイブにさらにデータを追加する際\"\n\" :meth:`Archive.add` を参照）、重複をチェックしません。この問題を防ぐために path パラメーターを使用してください。\"\n\n#: ../../archive-class.rst:59 dc6f307620b443e59c60965c461c7642\nmsgid \"\"\n\"Append a sub-archive. The meaning of the parameters are exactly the same \"\n\"as explained above. Of course, parameter `content` is not optional here.\"\nmsgstr \"サブアーカイブを追加します。パラメータの意味は上記とまったく同じです。もちろん、ここではパラメータ `content` はオプションではありません。\"\n\n#: ../../archive-class.rst:63 e1ad4f204f754654a6584c25842135fb\nmsgid \"Checks whether an entry exists in any of the sub-archives.\"\nmsgstr \"エントリがサブアーカイブのいずれかに存在するかどうかを確認します。\"\n\n#: ../../archive-class.rst 6748d18e7f6946d6b1497df192130d43\n#: feda328ffa8445dea3f5c2af2f98fdad\nmsgid \"Parameters\"\nmsgstr \"パラメータ:\"\n\n#: ../../archive-class.rst:65 ../../archive-class.rst:73\n#: 0458d0fa598349cf8a25c5752c8f840b 1806b51351774f19944fb27526851e14\nmsgid \"\"\n\"The fully qualified name of the entry. So must include any `path` prefix \"\n\"under which the entry's sub-archive has been added.\"\nmsgstr \"エントリの完全修飾名。エントリのサブアーカイブが追加されたパスのプレフィックスを含む必要があります。\"\n\n#: ../../archive-class.rst 0fb6926638df4e5d88376ea0eea6219d\n#: b0c94ca65df04318aad6ff6b1d22633e\nmsgid \"Returns\"\nmsgstr \"戻り値:\"\n\n#: ../../archive-class.rst:67 484ce7feed2141d4b486ae9b49c1c29e\nmsgid \"`True` or `False`.\"\nmsgstr \"`True` または `False` 。\"\n\n#: ../../archive-class.rst:71 affe45e0783c46f782832cb77fb3eb49\nmsgid \"Retrieve the data of an entry.\"\nmsgstr \"エントリのデータを取得します。\"\n\n#: ../../archive-class.rst:75 dc88278b5cee4df6a0867e93b0e234f2\nmsgid \"\"\n\"The binary data (`bytes`) of the entry. If not found, an exception is \"\n\"raised.\"\nmsgstr \"エントリのバイナリデータ（ `bytes` ）です。見つからない場合は例外が発生します。\"\n\n#: ../../archive-class.rst:79 3d32676328d34e37939a65792096baf5\nmsgid \"\"\n\"A list of the archive's sub-archives. Each list item is a dictionary with\"\n\" the following keys:\"\nmsgstr \"アーカイブのサブアーカイブのリストです。各リストアイテムは、次のキーを持つ辞書です：\"\n\n#: ../../archive-class.rst:81 f4a44efa6e934e2ab4d5b59c1abb3212\nmsgid \"`entries` -- a list of (top-level) entry names in this sub-archive.\"\nmsgstr \"`entries` - このサブアーカイブ内の（トップレベルの）エントリ名のリスト。\"\n\n#: ../../archive-class.rst:82 5aefdd53977e4a2aa8c559d7bac700f6\nmsgid \"\"\n\"`fmt` -- the format of the sub-archive. This is one of the strings \"\n\"\\\"dir\\\" (file folder), \\\"zip\\\" (ZIP archive), \\\"tar\\\" (TAR archive), or \"\n\"\\\"tree\\\" for single binary entries or file content.\"\nmsgstr \"\"\n\"`fmt` - サブアーカイブの形式。これは文字列 \"\n\"\\\"dir\\\"（ファイルフォルダ）、\\\"zip\\\"（ZIPアーカイブ）、\\\"tar\\\"（TARアーカイブ）、または単一のバイナリエントリまたはファイルコンテンツの場合は\"\n\" \\\"tree\\\" のいずれかです。\"\n\n#: ../../archive-class.rst:83 ef04652561cc41bca0c8d60f067bb118\nmsgid \"\"\n\"`path` -- the value of the `path` parameter under which this sub-archive \"\n\"was added.\"\nmsgstr \"`path` - このサブアーカイブが追加されたパラメータの値です。\"\n\n#: ../../archive-class.rst:85 ddd26ce7aa1e42c09e3a7daa19769a5a\nmsgid \"**Example:**\"\nmsgstr \"**例：** \"\n\n#: ../../footer.rst:60 9a53a999980d4a2da538998c8bb29234\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/changes.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4b2125667c71405ca651d2f4f33203ce\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 7a5706b2ba4a4c5f9ab33e6a435e268e\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 232846e89a9147f6abd57e2c5299b488\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../../changes.txt:2 4cd69e5be9794686a140129e41fc4b95\nmsgid \"Change Log\"\nmsgstr \"\"\n\n#: ../../../changes.txt:5 1505d60909e543b7809db6369fa0db8f\nmsgid \"**Changes in version 1.26.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:7 ../../../changes.txt:43 ../../../changes.txt:73\n#: ../../../changes.txt:95 ../../../changes.txt:117 ../../../changes.txt:146\n#: ../../../changes.txt:171 ../../../changes.txt:192 ../../../changes.txt:212\n#: ../../../changes.txt:236 ../../../changes.txt:285 ../../../changes.txt:335\n#: ../../../changes.txt:366 ../../../changes.txt:387 ../../../changes.txt:423\n#: ../../../changes.txt:443 ../../../changes.txt:457 ../../../changes.txt:485\n#: ../../../changes.txt:507 ../../../changes.txt:530 ../../../changes.txt:556\n#: ../../../changes.txt:589 ../../../changes.txt:611 ../../../changes.txt:625\n#: ../../../changes.txt:642 ../../../changes.txt:664 ../../../changes.txt:673\n#: ../../../changes.txt:686 ../../../changes.txt:698 ../../../changes.txt:715\n#: ../../../changes.txt:728 ../../../changes.txt:741 ../../../changes.txt:754\n#: ../../../changes.txt:766 ../../../changes.txt:778 ../../../changes.txt:801\n#: ../../../changes.txt:833 ../../../changes.txt:859 ../../../changes.txt:899\n#: ../../../changes.txt:926 ../../../changes.txt:948 ../../../changes.txt:1200\n#: ../../../changes.txt:1334 049a26e13bb94229a79a69f81f7b5fbe\n#: 1f22271ed0b840efae8df95b0ee00fae 223eca2249444ff9ab2190c5225660fc\n#: 287da62560f74d3dab59fced5784a79f 289b8aaf54c746ecad54ca30175d6572\n#: 2a7d7c2ae08a4078a26a35d98478462f 2d7b554ad4614d72aa34334544b1ad84\n#: 3b0c2a7d2f02465d8a435c84b848e950 41d0c2d1b9dc4b92aaee342c76e8f6aa\n#: 4347b8c87fab492bb324cd690a0a5039 45a493f9bbb34d5d86014fc796fc7e5f\n#: 4ac9e175442d4fed9094777114001d05 5294b3baa70340d4b0683ea893cb8227\n#: 55180f0a4ad14d779385728b45523412 56b9abeb67244e568154b0999908dc54\n#: 590720763c4f4b6e944a5b6e9261c46a 5b96e63e430649e09364197f6640d348\n#: 66a4fb9f871646b39fd2935322ff2bd7 681b44b2d00a428f95bec75570a9bd96\n#: 6d3500e7906d4b5b9d5a852686c41f03 77caed4c8cf543c284393db2214dc425\n#: 7930c830c16148e18e377994a974f7f6 8020c55d92a04b68b29f9b5c839563d9\n#: 8dd9e915003d41dbbf42283bf55adefe 959e7f541c2147928cc800dcf3f54fa8\n#: 980c2a259af24fc599c154fab471a6d4 9eeadae797794ba39efcdfe7dd30ea96\n#: a1f33ce2da084e65927b1037ec5431c9 a5748cc98e13464f8d5833fb09a584c6\n#: b003035ab22a486d8191c52df2f18d51 b1ac215bbe134f3e83fc2c3f1315274d\n#: b322fd43be9f42fcb134129f551f03d7 b8505854ea4346dca195196c3c729c8e\n#: baa47c681a164ab190fd710ab752c1e5 be5cdf51439747e9856bf7da70502394\n#: c18708d565ec49bb9b6597c6e4746708 cbe526883f0a481b9e4b1e4727d250df\n#: d23ff8de34d7483c8f2da67985f1837a e53406c760874e3fba6776cc13ce71c4\n#: ea5c09729ad243d1b44e29edb73a3242 f176ccdd28d44b75bfd267fa28648397\n#: f325e778302b4997b940c6c03dc96ae8 fab1e85d6fcb480fba201316c8c6be02\nmsgid \"Other:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:9 eef8efb3b6884f43ada21c5e779231cb\nmsgid \"\"\n\"Retrospectively mark `4756 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4756>`_ as fixed in 1.26.6.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:10 64ed70e9271b4853b276b73970b50572\nmsgid \"\"\n\"Improved safety of `pymupdf embed-extract`. This now refuses to write to \"\n\"an existing file or outside current directory, unless `-output` or new \"\n\"flag `-unsafe` is specified.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:15 f3d0c45b85df4b2e8952e6a2da3389b7\nmsgid \"**Changes in version 1.26.6** (2025-11-05)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:17 f42bfa1ba64243c3bbb367df56f3ac08\nmsgid \"Use MuPDF-1.26.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:19 50c8518a04f0461d92243888e708323a\nmsgid \"Supported Python versions are now 3.10-3.14.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:21 ../../../changes.txt:35 ../../../changes.txt:59\n#: ../../../changes.txt:87 ../../../changes.txt:110 ../../../changes.txt:132\n#: ../../../changes.txt:164 ../../../changes.txt:183 ../../../changes.txt:203\n#: ../../../changes.txt:226 ../../../changes.txt:249 ../../../changes.txt:259\n#: ../../../changes.txt:274 ../../../changes.txt:294 ../../../changes.txt:304\n#: ../../../changes.txt:321 ../../../changes.txt:347 ../../../changes.txt:380\n#: ../../../changes.txt:396 ../../../changes.txt:406 ../../../changes.txt:438\n#: ../../../changes.txt:475 ../../../changes.txt:502 ../../../changes.txt:524\n#: ../../../changes.txt:541 ../../../changes.txt:584 ../../../changes.txt:605\n#: ../../../changes.txt:619 ../../../changes.txt:632 ../../../changes.txt:658\n#: ../../../changes.txt:671 07987b0a21a147d98b3290a64ffa8043\n#: 1f57395ac4ea4c218653cd455c477ae4 21d647e365934565aea69ef24f0cd8f9\n#: 262f48050967468c829ffe26a450be4b 4cef11a8719641dbb922f8aa1573a9c6\n#: 4e96e411a9d04f3394926ff7a164019f 4f462e8fc6bf487c991f26164fb54c0f\n#: 502470bd29ee4a5f910f9b6c271e6371 5fac41e37738489fa8375e221307b3be\n#: 7d9274f30a6d48e080212ec423122787 7fb6e1f0f0a04c768954b3b7aa03e2f1\n#: 8b358fae935541dd89ec020f9bdb1b41 8dbc5997591e480a88aef01fc75581db\n#: 94c9d89ad8d543cb833db162ba31fde4 9b23f29736354e1d8ed1668fd1f388bf\n#: 9e14b9596afa45b3a83e357fbda360af a2ea1d3f01d945e0b1771aa1b29caa0c\n#: a53b73a9f82648878f41f1760093e351 ad004edc4dba484fadde2289418127fe\n#: b70bd970a9944857a416f7ca0c9b1c6b bbd89b8b6e3544ab875a3a6e44ebe68d\n#: c08f485ce1c34a11ba134e40626b051f d727b39943064157a040eb5ba843fe41\n#: d855c86985754c219d04723faa8e0b48 db0403d789674d7aae95b0d2af2dd802\n#: e0509078460b456b924d980a899d39ea e182efb4eac34ad8bac7dece1504bf23\n#: e2459e41e6d84b248942175137234803 e9129fdd854d4510beb02b78caf662e2\n#: f752594e63ac42a1bc09a307033985cb f9a85782009445d9b72155a12a8ec8ed\nmsgid \"Fixed issues:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:23 ae92f1fe5caf4bf1b49a2d9b55379d9c\nmsgid \"\"\n\"**Fixed** `4699 <https://github.com/pymupdf/PyMuPDF/issues/4699>`_: \"\n\"cannot find ExtGState resource\"\nmsgstr \"\"\n\n#: ../../../changes.txt:24 22f8d06dd888459aa4f9fe1120d92dc8\nmsgid \"\"\n\"**Fixed** `4712 <https://github.com/pymupdf/PyMuPDF/issues/4712>`_: Crash\"\n\" with \\\"corrupted double-linked list\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:25 ccf146dfc96a47d3bab7d6102699c73d\nmsgid \"\"\n\"**Fixed** `4720 <https://github.com/pymupdf/PyMuPDF/issues/4720>`_: \"\n\"Memory leaking in rewrite_images?\"\nmsgstr \"\"\n\n#: ../../../changes.txt:26 0f08a4cb18fe493ca72344c67c165f1d\nmsgid \"\"\n\"**Fixed** `4742 <https://github.com/pymupdf/PyMuPDF/issues/4742>`_: \"\n\"'Rect' object has no attribute 'get_area'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:27 e4563a3e5c574da8970663d208888aa7\nmsgid \"\"\n\"**Fixed** `4746 <https://github.com/pymupdf/PyMuPDF/issues/4746>`_: \"\n\"Document.__init__() got an unexpected keyword argument 'encoding'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:28 2b1ad6590a63426bb7c3dc1b135aaf86\nmsgid \"\"\n\"**Fixed** `4756 <https://github.com/pymupdf/PyMuPDF/issues/4756>`_: swig \"\n\"--version doesn't work in all versions of swig; -version should be used \"\n\"instead\"\nmsgstr \"\"\n\n#: ../../../changes.txt:31 f4b0a46bedf54bc695a3074e319c3da7\nmsgid \"**Changes in version 1.26.5** (2025-10-10)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:33 25fffdf714bf48d695db8e6ab1a28c67\nmsgid \"Use MuPDF-1.26.10.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:37 c88a8d28e397405f93d8379d00535d27\nmsgid \"\"\n\"**Fixed** `2883 <https://github.com/pymupdf/PyMuPDF/issues/2883>`_: \"\n\"Improve the Python type annotations for fitz_new\"\nmsgstr \"\"\n\n#: ../../../changes.txt:38 df91056120a24c1caa9c0b77f3fb1984\nmsgid \"\"\n\"**Fixed** `4507 <https://github.com/pymupdf/PyMuPDF/issues/4507>`_: Bugs \"\n\"in pyodide\"\nmsgstr \"\"\n\n#: ../../../changes.txt:39 70703777c2fa401bbc683f91ad94d06f\nmsgid \"\"\n\"**Fixed** `4613 <https://github.com/pymupdf/PyMuPDF/issues/4613>`_: Thai \"\n\"and number blocks are not auto-scaled and get wrong hyphen when using in \"\n\"insert_htmlbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:40 c88bc69f0f244a52ad6f890499799047\nmsgid \"\"\n\"**Fixed** `4700 <https://github.com/pymupdf/PyMuPDF/issues/4700>`_: \"\n\"pymupdf.open() processes .zip file without raising\"\nmsgstr \"\"\n\n#: ../../../changes.txt:41 e323399440274525b34c54f4dec39093\nmsgid \"\"\n\"**Fixed** `4716 <https://github.com/pymupdf/PyMuPDF/issues/4716>`_: \"\n\"Problems with unreadable characters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:45 3abefa34a28e4adf8e2457613ce56b45\nmsgid \"Supported Python versions are now 3.9-3.14.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:46 16783112fa05425cb0e149b83c62e932\nmsgid \"\"\n\"We now define all class methods explicitly instead of with dynamic \"\n\"assignment; this improves type hints.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:47 26f54231a095480aa0f42247a5a89ef4\nmsgid \"Removed `pymupdf.utils.Shape` class, was duplicate of `pymupdf.Shape`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:48 7ecda4cd98c54e6a9b9bf91163eff14b\nmsgid \"Allow use of cibuildwheel to build and test on Pyodide.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:49 93135916c58248c283baf01e7d053cd0\nmsgid \"Fixed various Pyodide bugs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:50 7ecc6290f1054757b942bc4fb105d1eb\nmsgid \"\"\n\"In documentation, added section about Linux wheels and glibc \"\n\"compatibility.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:51 92f2c3d79a944460985276d312eca3e4\nmsgid \"Improved documentation of pymupdf.open()'s <filetype> arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:52 562bb006d36840cdb5aadf8ddd466486\nmsgid \"\"\n\"Retrospectively mark `4544 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4544>`_ as fixed in 1.26.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:55 b67d98ad96244427984fe137baacd5a1\nmsgid \"**Changes in version 1.26.4 (2025-08-25)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:57 6d0728e9c0d245e69d0197ef60d55ff6\nmsgid \"Use MuPDF-1.26.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:61 dae25b5e67ed40678841767ca82960df\nmsgid \"\"\n\"**Fixed** `3806 <https://github.com/pymupdf/PyMuPDF/issues/3806>`_: pdf \"\n\"to image rendering ignore optional content offs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:62 d27cf6acd0904ba3854fc86e793e1b0e\nmsgid \"\"\n\"**Fixed** `4388 <https://github.com/pymupdf/PyMuPDF/issues/4388>`_: \"\n\"Incorrect PixMap from page due to cached data from other PDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:63 2485533a6f1c4ceeab94a3a74ea0040a\nmsgid \"\"\n\"**Fixed** `4457 <https://github.com/pymupdf/PyMuPDF/issues/4457>`_: Wrong\"\n\" characters displayed after font subsetting (w/ native method)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:64 ../../../changes.txt:89\n#: 48034320908941b78280338d69474453 582145c0201942e4a97e4a6715f82496\nmsgid \"\"\n\"**Fixed** `4462 <https://github.com/pymupdf/PyMuPDF/issues/4462>`_: \"\n\"delete_pages() does not accept a single int\"\nmsgstr \"\"\n\n#: ../../../changes.txt:65 ee57c3dd80db447388f6e8ac0d049adb\nmsgid \"\"\n\"**Fixed** `4533 <https://github.com/pymupdf/PyMuPDF/issues/4533>`_: Open \"\n\"PDF error segmentation fault\"\nmsgstr \"\"\n\n#: ../../../changes.txt:66 96cc9c5c43084b5e9cf0162eb38b2dbf\nmsgid \"\"\n\"**Fixed** `4544 <https://github.com/pymupdf/PyMuPDF/issues/4544>`_: About\"\n\" pdf_clip_page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:67 ed6dabd36ac34857a630542ffd191c57\nmsgid \"\"\n\"**Fixed** `4565 <https://github.com/pymupdf/PyMuPDF/issues/4565>`_: MacOS\"\n\" uses Tesseract and not Tesseract-OCR\"\nmsgstr \"\"\n\n#: ../../../changes.txt:68 fb88b0c8cbc84095bf2500c9a32f50ec\nmsgid \"\"\n\"**Fixed** `4571 <https://github.com/pymupdf/PyMuPDF/issues/4571>`_: \"\n\"Broken merged pdfs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:69 ef751fe8798b41eaaf64e166e23768fa\nmsgid \"\"\n\"**Fixed** `4590 <https://github.com/pymupdf/PyMuPDF/issues/4590>`_: \"\n\"TypeError in utils.py scrub(): annot.update_file(buffer=...) is invalid\"\nmsgstr \"\"\n\n#: ../../../changes.txt:70 3b8c0e208f554eaebac0ea6abcd8b46d\nmsgid \"\"\n\"**Fixed** `4614 <https://github.com/pymupdf/PyMuPDF/issues/4614>`_: \"\n\"Intercept bad widgets when inserting to another PDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:71 02cfdc76ab714494bf079b968391320e\nmsgid \"\"\n\"**Fixed** `4639 <https://github.com/pymupdf/PyMuPDF/issues/4639>`_: \"\n\"pymupdf.mupdf.FzErrorGeneric: code=1: Director error: <class \"\n\"'AttributeError'>: 'JM_new_bbox_device_Device' object has no attribute \"\n\"'layer_name'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:75 38712224dd5544e7a462aaeb1e2e304b\nmsgid \"\"\n\"Check that #4392 `Segfault when running with pytest and -Werror` is fixed\"\n\" if PyMuPDF is built with swig>=4.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:76 57972c515886453a932d8eac12c3b328\nmsgid \"Add `Page.clip_to_rect()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:77 586a552aa4af4245b5e12d417ae1f42d\nmsgid \"Improved search for Tesseract data.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:78 9f280d1da9b04eedae2eb7fa58bf1973\nmsgid \"Retrospectively mark #4496 as fixed in 1.26.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:79 3fde7874083c4911a6dd9d05ee3f3e7c\nmsgid \"Retrospectively mark #4503 as fixed in 1.26.3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:80 e25d10cd0c8b485b998c07889f2c2b02\nmsgid \"Added experimental support for Graal.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:83 a4c9e90997aa40e39b6e88a47283df1f\nmsgid \"**Changes in version 1.26.3 (2025-07-02)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:85 f2e0c9ebfbc8436a90fbc5210c2d61c5\nmsgid \"Use MuPDF-1.26.3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:90 88b28524dc38400e86ede8dfd69bda83\nmsgid \"\"\n\"**Fixed** `4503 <https://github.com/pymupdf/PyMuPDF/issues/4503>`_: \"\n\"Undetected character styles\"\nmsgstr \"\"\n\n#: ../../../changes.txt:91 82e1019dfacf4e889e4e2708d5c2ab67\nmsgid \"\"\n\"**Fixed** `4527 <https://github.com/pymupdf/PyMuPDF/issues/4527>`_: \"\n\"Rect.intersects() is much slower than necessary\"\nmsgstr \"\"\n\n#: ../../../changes.txt:92 3195a73537bc44b6be38e2643857a820\nmsgid \"\"\n\"**Fixed** `4564 <https://github.com/pymupdf/PyMuPDF/issues/4564>`_: \"\n\"Possible encoding issue in PDF metadata\"\nmsgstr \"\"\n\n#: ../../../changes.txt:93 ed811f813c204c15a71a72b02b3fc7f7\nmsgid \"\"\n\"**Fixed** `4575 <https://github.com/pymupdf/PyMuPDF/issues/4575>`_: Bug \"\n\"with IRect contains method\"\nmsgstr \"\"\n\n#: ../../../changes.txt:97 80940db1fc98463084fb0536e2a74c75\nmsgid \"Class Shape is now available as pymupdf.Shape.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:98 8d3cbad84fc7406db910769a9e0c49cd\nmsgid \"Added table cell markdown support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:101 979c685df84c433a99b2ce9a6192393e\nmsgid \"**Changes in version 1.26.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:103 6253d76480234ecb99ef69856e2e4d7c\nmsgid \"[Skipped.]\"\nmsgstr \"\"\n\n#: ../../../changes.txt:106 696d62b448d042d7ac4c9ae344c9357e\nmsgid \"**Changes in version 1.26.1 (2025-06-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:108 97fd68cacc0d460ea6453d0f75969b06\nmsgid \"Use MuPDF-1.26.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:112 f027534ba7294a6e8c8c22e759448323\nmsgid \"\"\n\"**Fixed** `4520 <https://github.com/pymupdf/PyMuPDF/issues/4520>`_: \"\n\"show_pdf_page does not like empty pages created by new_page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:113 065f392247ae490ab226f1104d666ddc\nmsgid \"\"\n\"**Fixed** `4524 <https://github.com/pymupdf/PyMuPDF/issues/4524>`_: \"\n\"fitz.get_text ignores 'pages' kwarg\"\nmsgstr \"\"\n\n#: ../../../changes.txt:114 ../../../changes.txt:137\n#: 1c6997f9c6d7494ba9b55c63784e99cf c6a83f4370734e42a4528f25014f39ab\nmsgid \"\"\n\"**Fixed** `4412 <https://github.com/pymupdf/PyMuPDF/issues/4412>`_: \"\n\"Regression? Spurious error? in insert_pdf in v1.25.4\"\nmsgstr \"\"\n\n#: ../../../changes.txt:115 bb0e76951378470a8d36dd42e908266d\nmsgid \"\"\n\"**Fixed** `4496 <https://github.com/pymupdf/PyMuPDF/issues/4496>`_: \"\n\"pymupdf4llm with pymupdfpro\"\nmsgstr \"\"\n\n#: ../../../changes.txt:119 87089d7b25b9490a95ea7686681487c8\nmsgid \"\"\n\"Partial fix for `4503 <https://github.com/pymupdf/PyMuPDF/issues/4503>`_:\"\n\" Undetected character styles\"\nmsgstr \"\"\n\n#: ../../../changes.txt:120 ce6c18a243de4e81b72c53d4fefd499e\nmsgid \"\"\n\"New method `Document.rewrite_images()`, useful for reducing file size, \"\n\"changing image formats, or converting color spaces.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:121 0a3a89d09fd3461ca2a27fcca8f185ed\nmsgid \"`Page.get_text()`: restrict positional args to match docs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:122 1a528cc8a62e43639f658f1f709590c9\nmsgid \"Removed bogus definition of class `Shape`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:123 552b40dd8819435dad4a76eae858df20\nmsgid \"\"\n\"Removed release date from module, docs and changelog. * \"\n\"`pymupdf.pymupdf_date` and `pymupdf.VersionDate` are now both None. * \"\n\"They will be removed in a future release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:128 158c863781294c5c93e9b0a8c8e1f847\nmsgid \"**Changes in version 1.26.0 (2025-05-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:130 18567733eef64ab68965ed498958d670\nmsgid \"Use MuPDF-1.26.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:134 4ea8e6ad2e414e978386c33aad8021d5\nmsgid \"\"\n\"**Fixed** `4324 <https://github.com/pymupdf/PyMuPDF/issues/4324>`_: \"\n\"cluster_drawings() fails to cluster horizontal and vertical thin lines\"\nmsgstr \"\"\n\n#: ../../../changes.txt:135 17554e87f7084cacb19d789d4694754f\nmsgid \"\"\n\"**Fixed** `4363 <https://github.com/pymupdf/PyMuPDF/issues/4363>`_: \"\n\"Trouble with searching\"\nmsgstr \"\"\n\n#: ../../../changes.txt:136 2cb8333bfa3948d0a1e1df290b275159\nmsgid \"\"\n\"**Fixed** `4404 <https://github.com/pymupdf/PyMuPDF/issues/4404>`_: \"\n\"IndexError in page.get_links()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:138 3fb86dc38b76431f8fa289ed24574576\nmsgid \"\"\n\"**Fixed** `4423 <https://github.com/pymupdf/PyMuPDF/issues/4423>`_: \"\n\"pymupdf.mupdf.FzErrorFormat: code=7: cannot find object in xref error \"\n\"encountered after version 1.25.3\"\nmsgstr \"\"\n\n#: ../../../changes.txt:139 e4d0ca8ddf164f08b449dac3a6fa04fa\nmsgid \"\"\n\"**Fixed** `4435 <https://github.com/pymupdf/PyMuPDF/issues/4435>`_: \"\n\"get_pixmap method stuck on one page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:140 73d115f25755496680f56c79674a6351\nmsgid \"\"\n\"**Fixed** `4439 <https://github.com/pymupdf/PyMuPDF/issues/4439>`_: New \"\n\"Xml class from data does not work - bug in code\"\nmsgstr \"\"\n\n#: ../../../changes.txt:141 b25d62127fea4feaa5d944e835c2a666\nmsgid \"\"\n\"**Fixed** `4445 <https://github.com/pymupdf/PyMuPDF/issues/4445>`_: \"\n\"Broken XREF table incorrectly repaired\"\nmsgstr \"\"\n\n#: ../../../changes.txt:142 a0a2ed6ac1354febb9da6afd02bc9b42\nmsgid \"\"\n\"**Fixed** `4447 <https://github.com/pymupdf/PyMuPDF/issues/4447>`_: \"\n\"Stroke color of annotations cannot be correctly set\"\nmsgstr \"\"\n\n#: ../../../changes.txt:143 616298c000ad48cdbc628ef4cdd172d8\nmsgid \"\"\n\"**Fixed** `4479 <https://github.com/pymupdf/PyMuPDF/issues/4479>`_: \"\n\"set_layer_ui_config() toggles all layers rather than just one\"\nmsgstr \"\"\n\n#: ../../../changes.txt:144 b15ec1ffa6f0419c8b5503c50587840c\nmsgid \"\"\n\"**Fixed** `4505 <https://github.com/pymupdf/PyMuPDF/issues/4505>`_: \"\n\"Follow Widget flag values up its parent structure\"\nmsgstr \"\"\n\n#: ../../../changes.txt:148 7b7ea93f30ca49f88b45b05c08ecf10f\nmsgid \"\"\n\"Partial fixed for `4457 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4457>`_: Wrong characters \"\n\"displayed after font subsetting (w/ native method)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:149 b0ae6f4b0bc24e12bd0071f22e599e11\nmsgid \"Support image stamp annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:150 f5f7682cfc6c4abba06ebd809edf0795\nmsgid \"Support recoloring pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:151 01a95f3b08944431b06a9d2e99e50bdf\nmsgid \"\"\n\"Added example of using Django's file storage API to open files with \"\n\"pymupdf.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:152 1ea4d799a2714c90a3ad74a4f03f1ed8\nmsgid \"\"\n\"Clarified FreeText annotation color options. We now raise an exception if\"\n\" an attempt is made to set attributes that can not be supported.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:154 856acd8f3343442bb8ee7254e8b8d062\nmsgid \"Fixed potential segv in Pixmap.is_unicolor().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:155 90dbf6ef976a4d76a799854a5aa774dc\nmsgid \"\"\n\"Added runtime assert that that PyMuPDF and MuPDF were built with \"\n\"compatible NDEBUG settings (related to `4390 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4390>`_).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:157 0862256c36d142c48444aab07763f645\nmsgid \"Simplified handling of filename/filetype when opening documents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:158 5e85ed11581b46daaf1a09b8a22dcccb\nmsgid \"\"\n\"Removed PDF linearization support. * Calls to `Document.save()` with \"\n\"`linear` set to true will now raise an exception. * See \"\n\"https://artifex.com/blog/mupdf-removes-linearisation for more \"\n\"information.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:162 c7ce1a9bb27545978d6d1d9fed1a4524\nmsgid \"**Changes in version 1.25.5 (2025-03-31)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:166 9548bbf70ba9469e8b935a45f29643ed\nmsgid \"\"\n\"**Fixed** `4372 <https://github.com/pymupdf/PyMuPDF/issues/4372>`_: Text \"\n\"insertion fails due to missing /Resources object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:167 f76e7622a9d7433db1b7b82bc7156145\nmsgid \"\"\n\"**Fixed** `4400 <https://github.com/pymupdf/PyMuPDF/issues/4400>`_: \"\n\"Infinite loop in fill_textbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:168 82f33cb8a6d34f62b854eca17a8c4254\nmsgid \"\"\n\"**Fixed** `4403 <https://github.com/pymupdf/PyMuPDF/issues/4403>`_: \"\n\"Unable to get_text() - layer/clip nesting too deep\"\nmsgstr \"\"\n\n#: ../../../changes.txt:169 84b7b13060424773820d4994525080dc\nmsgid \"\"\n\"**Fixed** `4415 <https://github.com/pymupdf/PyMuPDF/issues/4415>`_: PDF \"\n\"page is mirrored, origin is at bottom-left\"\nmsgstr \"\"\n\n#: ../../../changes.txt:173 74a4792d6a8244eb9dcae4beb4bfe0ee\nmsgid \"Use MuPDF-1.25.6.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:174 d248e14b8c1a4e3fab6235c3cf5c614c\nmsgid \"Fixed MuPDF SEGV on MacOS with particular fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:175 82ea9eb171144077a7870ae7a0b9eeb7\nmsgid \"Fixed `Annot.get_textpage()`'s `clip` arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:176 2fccc9761609452e9d10dac746b11059\nmsgid \"Fixed Python-3.14 (pre-release) build error.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:179 2fbd0061abcd475fafe6ef6a570e0d7a\nmsgid \"**Changes in version 1.25.4 (2025-03-14)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:181 9fa9e7eec7694807a4577e93e3fdb54e\nmsgid \"Use MuPDF-1.25.5.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:185 8f7a4be455684495af9c8e17de5ad09d\nmsgid \"\"\n\"**Fixed** `4079 <https://github.com/pymupdf/PyMuPDF/issues/4079>`_: \"\n\"Unexpected result for apply_redactions()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:186 6d876027b2104b01830654bbbae308e9\nmsgid \"\"\n\"**Fixed** `4224 <https://github.com/pymupdf/PyMuPDF/issues/4224>`_: MuPDF\"\n\" error: format error: negative code in 1d faxd\"\nmsgstr \"\"\n\n#: ../../../changes.txt:187 b7b89a62c35d4608987e21ec0f356173\nmsgid \"\"\n\"**Fixed** `4303 <https://github.com/pymupdf/PyMuPDF/issues/4303>`_: \"\n\"page.get_image_info() returns outdated cached results after replacing \"\n\"image\"\nmsgstr \"\"\n\n#: ../../../changes.txt:188 8b5c375bcfc24c81a1ab34fdfe2e3f87\nmsgid \"\"\n\"**Fixed** `4309 <https://github.com/pymupdf/PyMuPDF/issues/4309>`_: \"\n\"FzErrorFormat Error When Deleting First Page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:189 33ebf7622662470e98f52b0e0681e4b1\nmsgid \"\"\n\"**Fixed** `4336 <https://github.com/pymupdf/PyMuPDF/issues/4336>`_: Major\"\n\" Performance Regression: pix.color_count is 150x slower in version 1.25.3\"\n\" compared to 1.23.8\"\nmsgstr \"\"\n\n#: ../../../changes.txt:190 159061230d824914a6d19ad6d73eeb7c\nmsgid \"\"\n\"**Fixed** `4341 <https://github.com/pymupdf/PyMuPDF/issues/4341>`_: \"\n\"Invalid label retrieval when /Kids is an array of multiple /Nums\"\nmsgstr \"\"\n\n#: ../../../changes.txt:194 37e49743f93f41d9bf5880142941c864\nmsgid \"Fixed handling of duplicate widget names when joining PDFs (PR #4347).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:195 0cac0025172c4dd5baf122fc076da58e\nmsgid \"Improved Pyodide build.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:196 638ca0a27dd548cfa15a4095bd238671\nmsgid \"\"\n\"Avoid SWIG-related build errors with Python-3.13 by disabling \"\n\"PY_LIMITED_API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:199 24df824cc0ed4dcaa55266a462308f72\nmsgid \"**Changes in version 1.25.3 (2025-02-06)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:201 86fbdb38e3ab475cb35bce8474a0517d\nmsgid \"Use MuPDF-1.25.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:205 11404e9f065f46d48c17de3eb0a56b4c\nmsgid \"\"\n\"**Fixed** `4139 <https://github.com/pymupdf/PyMuPDF/issues/4139>`_: Text \"\n\"color numbers change between 1.24.14 and 1.25.0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:206 f54ac127378c40efbea689f95f729a3d\nmsgid \"\"\n\"**Fixed** `4141 <https://github.com/pymupdf/PyMuPDF/issues/4141>`_: Some \"\n\"insertion methods fails for pages without a /Resources object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:207 1debce8303bb430aaf3c754c31d4e54a\nmsgid \"\"\n\"**Fixed** `4180 <https://github.com/pymupdf/PyMuPDF/issues/4180>`_: \"\n\"Search problems\"\nmsgstr \"\"\n\n#: ../../../changes.txt:208 a43078709b894315ab60ab8c8077d919\nmsgid \"\"\n\"**Fixed** `4182 <https://github.com/pymupdf/PyMuPDF/issues/4182>`_: Text \"\n\"coordinate extraction error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:209 2aa654ea699a4754864254e38097fcf4\nmsgid \"\"\n\"**Fixed** `4245 <https://github.com/pymupdf/PyMuPDF/issues/4245>`_: \"\n\"Highlighting issue distorted on recent versions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:210 568c972326294ecab31a4378aee8aef3\nmsgid \"\"\n\"**Fixed** `4254 <https://github.com/pymupdf/PyMuPDF/issues/4254>`_: \"\n\"add_freetext_annot is drawing text outside the annotation box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:214 3b1e13a8a53f41568994b6b10d784dd4\nmsgid \"\"\n\"In annotations: * Added support for subtype FreeTextCallout. * Added \"\n\"support for rich text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:217 20ad825019bc421aa9fa359d4c2cf2b9\nmsgid \"\"\n\"Added miter_limit arg to insert_text*() to allow suppression of spikes \"\n\"caused by long miters.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:218 d8f3a5bd962d420482fbab442a82a337\nmsgid \"Add Widget Support to `Document.insert_pdf()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:219 b25922bccda743b4a462eff61aa2da32\nmsgid \"Add `bibi` to span dicts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:220 16e4de5888954261941fe67d4f618949\nmsgid \"Add `synthetic' to char dict.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:221 ../../../changes.txt:963\n#: 2b958160bd134274b90ba5bd456e66c5 43a26b5aad0e4fe485acf6a41282f421\nmsgid \"Fixed Pyodide builds.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:224 f65069a7584b4f128fa5b7cc86d526ab\nmsgid \"**Changes in version 1.25.2 (2025-01-17)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:228 af70ce0fc1a74152b86dbd49d309fdb9\nmsgid \"\"\n\"**Fixed** `4055 <https://github.com/pymupdf/PyMuPDF/issues/4055>`_: \"\n\"\\\"Yes\\\" for all checkboxes does not work for all PDF rendering engines.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:229 4410d36a900d450c97588b75ccb21628\nmsgid \"\"\n\"**Fixed** `4155 <https://github.com/pymupdf/PyMuPDF/issues/4155>`_: \"\n\"samples_mv is unsafe\"\nmsgstr \"\"\n\n#: ../../../changes.txt:230 61173d64746b46848303884ad4f7c6c2\nmsgid \"\"\n\"**Fixed** `4162 <https://github.com/pymupdf/PyMuPDF/issues/4162>`_: Got \"\n\"AttributeError, when tried to add Signature field\"\nmsgstr \"\"\n\n#: ../../../changes.txt:231 ade3c33dc1bc4fe5a6c9c79ad335b6ca\nmsgid \"\"\n\"**Fixed** `4186 <https://github.com/pymupdf/PyMuPDF/issues/4186>`_: \"\n\"Incorrect handling of JPEG with color space CMYK image extraction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:232 b0f948dd2aec4196879b796a7083ce66\nmsgid \"\"\n\"**Fixed** `4195 <https://github.com/pymupdf/PyMuPDF/issues/4195>`_: \"\n\"Pixmaps that are inverted and have an alpha channel are not rendered \"\n\"properly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:233 f983aaf8e72b40329ef333edb032482d\nmsgid \"\"\n\"**Fixed** `4225 <https://github.com/pymupdf/PyMuPDF/issues/4225>`_: \"\n\"pixmap.pil_save() fails due to colorspace definition\"\nmsgstr \"\"\n\n#: ../../../changes.txt:234 b9f784c7a8e347f0839af27a4aee0957\nmsgid \"\"\n\"**Fixed** `4232 <https://github.com/pymupdf/PyMuPDF/issues/4232>`_: \"\n\"Incorrect Font style and Size\"\nmsgstr \"\"\n\n#: ../../../changes.txt:238 46a2de9de8a84001a08386537fad1cb6\nmsgid \"Use Python's built-in glyphname <> unicode conversion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:239 98aaf3100ca44c3eb46b239c085990ce\nmsgid \"Improve speed of pixmap color inversion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:240 761c1030615e4b9f8837990276cdd4aa\nmsgid \"\"\n\"Add new `char_flags` member to span dictionary, for example allows \"\n\"detection of invisible text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:241 26863d989def4dd6b375f90f90ac816a\nmsgid \"Detect image masks in TextPage output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:242 c106eb1531f34065ac0918f8967d868c\nmsgid \"Added `Pixmap.pil_image()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:245 f2917761f4f342b2b20eb583e456ac86\nmsgid \"**Changes in version 1.25.1 (2024-12-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:247 5d2a2817fc15439e8cff5b48d2993934\nmsgid \"Use MuPDF-1.25.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:251 1aa29c8b332c4f06b69b0f5c16618fed\nmsgid \"\"\n\"**Fixed** `4125 <https://github.com/pymupdf/PyMuPDF/issues/4125>`_: \"\n\"memory leak while convert Pixmap's colorspace\"\nmsgstr \"\"\n\n#: ../../../changes.txt:252 6619cbba93b64266b96af9f2fb26333c\nmsgid \"\"\n\"**Fixed** `4034 <https://github.com/pymupdf/PyMuPDF/issues/4034>`_: \"\n\"Possible regression in pdf cleaning during save.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:255 54ab8ad1ec3246298a9019b2227a46d8\nmsgid \"**Changes in version 1.25.0 (2024-12-05)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:257 0a8714b7f18e45878f7b252f8af10ade\nmsgid \"Use MuPDF-1.25.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:261 686ebe75128d4be9b77bba0ddb563a43\nmsgid \"\"\n\"**Fixed** `4026 <https://github.com/pymupdf/PyMuPDF/issues/4026>`_: \"\n\"page.get_text('blocks') output two piece of very similar text with \"\n\"different bbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:262 efd9decd0d2a4a319ebd830a2c8531bd\nmsgid \"\"\n\"**Fixed** `4004 <https://github.com/pymupdf/PyMuPDF/issues/4004>`_: \"\n\"Segmentation Fault When Updating PDF Form Field Value\"\nmsgstr \"\"\n\n#: ../../../changes.txt:263 ebdb384bd8e4477d80b10127b014145b\nmsgid \"\"\n\"**Fixed** `3887 <https://github.com/pymupdf/PyMuPDF/issues/3887>`_: \"\n\"Subset Fonts problem using Fallback Font\"\nmsgstr \"\"\n\n#: ../../../changes.txt:264 e63e1845d9fb45198345afaff67f30e1\nmsgid \"\"\n\"**Fixed** `3886 <https://github.com/pymupdf/PyMuPDF/issues/3886>`_: \"\n\"Another issue with destroying PDF when inserting html\"\nmsgstr \"\"\n\n#: ../../../changes.txt:265 50adbcf9a18043e68b84aa9286698361\nmsgid \"\"\n\"**Fixed** `3751 <https://github.com/pymupdf/PyMuPDF/issues/3751>`_: \"\n\"apply_redactions causes part of the page content to be hidden / \"\n\"transparent\"\nmsgstr \"\"\n\n#: ../../../changes.txt:270 09e722df03fa4db18c4e0da832e997f7\nmsgid \"**Changes in version 1.24.14 (2024-11-19)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:272 cb8ebd6072bd4e11919080375887f166\nmsgid \"Use MuPDF-1.24.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:276 50b663786ee641cb9687580189342f8d\nmsgid \"\"\n\"**Fixed** `3448 <https://github.com/pymupdf/PyMuPDF/issues/3448>`_: \"\n\"get_pixmap function removes the table and leaves just the content behind\"\nmsgstr \"\"\n\n#: ../../../changes.txt:277 54321b37a7f9420b8567fbb6d1e426a4\nmsgid \"\"\n\"**Fixed** `3758 <https://github.com/pymupdf/PyMuPDF/issues/3758>`_: Got \"\n\"\\\"malloc(): unaligned tcache chunk detected Aborted (core dumped)\\\" while\"\n\" using add_redact_annot/apply_redactions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:278 296dc7d294134423a31f7b6d74f2aeaf\nmsgid \"\"\n\"**Fixed** `3813 <https://github.com/pymupdf/PyMuPDF/issues/3813>`_: \"\n\"Stories: Ordered list count broken with nested unordered list\"\nmsgstr \"\"\n\n#: ../../../changes.txt:279 2215310351ca46c1a25a514468a905a8\nmsgid \"\"\n\"**Fixed** `3933 <https://github.com/pymupdf/PyMuPDF/issues/3933>`_: \"\n\"font.valid_codepoints() - malfunction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:280 ff0631f5b7054df4b90b9fa8739b4ec1\nmsgid \"\"\n\"**Fixed** `4018 <https://github.com/pymupdf/PyMuPDF/issues/4018>`_: \"\n\"PyMuPDF hangs when iterating over zero page PDF pages backwards\"\nmsgstr \"\"\n\n#: ../../../changes.txt:281 a2a87af3e4c84a6abc63ea9d9e914391\nmsgid \"\"\n\"**Fixed** `4043 <https://github.com/pymupdf/PyMuPDF/issues/4043>`_: \"\n\"fullcopypage bug\"\nmsgstr \"\"\n\n#: ../../../changes.txt:282 55686d0fa4674d4299310ada01d1735d\nmsgid \"\"\n\"**Fixed** `4047 <https://github.com/pymupdf/PyMuPDF/issues/4047>`_: \"\n\"Segmentation Fault in add_redact_annot\"\nmsgstr \"\"\n\n#: ../../../changes.txt:283 0c2e617044914d04b642de2fa1587abb\nmsgid \"\"\n\"**Fixed** `4050 <https://github.com/pymupdf/PyMuPDF/issues/4050>`_: \"\n\"Content of dict returned by doc.embfile_info() does not fit to \"\n\"documentation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:287 1bb6617fc61d474c946dbf47c807e5d8\nmsgid \"\"\n\"Ensure that words from `Page.get_text()` never contain RTL/LTR char \"\n\"mixtures.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:288 2171b4b55a384da393be21b8cef7cd46\nmsgid \"Fix building with system MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:289 1b697fc68ecb486aa3b482711dd06c98\nmsgid \"Add dot product for points and vectors.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:292 b3aa2aa2bfbc4c9ba5c5d2c84a823910\nmsgid \"**Changes in version 1.24.13 (2024-10-29)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:296 532324021bbe48718cffa19ecedb034c\nmsgid \"\"\n\"**Fixed** `3848 <https://github.com/pymupdf/PyMuPDF/issues/3848>`_:  \"\n\"Piximap program crash\"\nmsgstr \"\"\n\n#: ../../../changes.txt:297 ../../../changes.txt:308\n#: 2387d394753a42ad872fa2268d7e9a29 cb2a797b491348f58ab3ce4ba98b73d9\nmsgid \"\"\n\"**Fixed** `3950 <https://github.com/pymupdf/PyMuPDF/issues/3950>`_:  \"\n\"Unable to consistently extract field labels from PDFs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:298 51536c1106ea45ac9444978b1684c0c1\nmsgid \"\"\n\"**Fixed** `3981 <https://github.com/pymupdf/PyMuPDF/issues/3981>`_:  \"\n\"PyMuPDF 1.24.12 with pyinstaller throws error.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:299 f44e8a92c6004f9f8c5c59b80ddbf558\nmsgid \"\"\n\"**Fixed** `3994 <https://github.com/pymupdf/PyMuPDF/issues/3994>`_:  \"\n\"pix.color_topusage raise Segmentation fault (core dumped)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:302 6bd1fa6f738340babc3df986bdc5a0a5\nmsgid \"**Changes in version 1.24.12 (2024-10-21)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:306 5174733bb6794f2b8c431f53170d0267\nmsgid \"\"\n\"**Fixed** `3914 <https://github.com/pymupdf/PyMuPDF/issues/3914>`_:  \"\n\"Ability to print MuPDF errors to logging instead of stdout\"\nmsgstr \"\"\n\n#: ../../../changes.txt:307 78495d3820584622819a2d243eabe922\nmsgid \"\"\n\"**Fixed** `3916 <https://github.com/pymupdf/PyMuPDF/issues/3916>`_:  \"\n\"insert_htmlbox error: int too large to convert to float\"\nmsgstr \"\"\n\n#: ../../../changes.txt:310 dc5a73b307bb45128375b3e45f21f804\nmsgid \"Supported Python versions are now 3.9-3.13.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:312 7fa696ad2ff84d4fb6204d9eeaa72eec\nmsgid \"Dropped support for Python-3.8 because end-of-life.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:313 2be21c1bbf164eb88dd5059514d52c40\nmsgid \"Added support for Python-3.13 because now released.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:314 a07d59ffaf6a48c8827e65b703ee0856\nmsgid \"See: https://devguide.python.org/versions/\"\nmsgstr \"\"\n\n#: ../../../changes.txt:317 d5600d2cd45b4009ba4eb42289cee550\nmsgid \"**Changes in version 1.24.11 (2024-10-03)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:319 9d700953907b44fe86d10f2023bda708\nmsgid \"Use MuPDF-1.24.10.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:323 808cd9169aeb4de68aaf51afd0fbff17\nmsgid \"\"\n\"**Fixed** `3624 <https://github.com/pymupdf/PyMuPDF/issues/3624>`_: Pdf \"\n\"file transform to image have a black block\"\nmsgstr \"\"\n\n#: ../../../changes.txt:324 8f414ff010194b2abb249bd69290b7a1\nmsgid \"\"\n\"**Fixed** `3859 <https://github.com/pymupdf/PyMuPDF/issues/3859>`_: \"\n\"doc.need_appearances() fails with \\\"AttributeError: module \"\n\"'pymupdf.mupdf' has no attribute 'PDF_TRUE' \\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:325 144003ab4e5743f1a5a6728e0d572424\nmsgid \"\"\n\"**Fixed** `3863 <https://github.com/pymupdf/PyMuPDF/issues/3863>`_: \"\n\"apply_redactions() does not work as expected\"\nmsgstr \"\"\n\n#: ../../../changes.txt:326 dd7478f2b06449c48d6b3c1bda073aa9\nmsgid \"\"\n\"**Fixed** `3905 <https://github.com/pymupdf/PyMuPDF/issues/3905>`_: open \"\n\"stream can raise a FzErrorFormat error instead of FileDataError\"\nmsgstr \"\"\n\n#: ../../../changes.txt:328 bf8693cc8c1349408cbd9fc992ea196e\nmsgid \"Wheels now use the Python Stable ABI:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:330 efc06a4c0fd84a09a008423f67eee13e\nmsgid \"There is one PyMuPDF wheel for each platform.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:331 4c8dea397efc48d68f2a64b021c76ed0\nmsgid \"Each wheel works with all supported Python versions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:332 1c41329749a64d22b3f9e3b61036f38c\nmsgid \"\"\n\"Each wheel is built using the oldest supported Python version (currently \"\n\"3.8).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:333 2e864bd74a2f4ef98e175a1e44fec4df\nmsgid \"There is no PyMuPDFb wheel.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:337 aa491896b5e04bd582e529c840ead400\nmsgid \"Improvements to get_text_words() with sort=True.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:338 283df97df8874c3fa38c6c9a57f6af06\nmsgid \"Tests now always get the latest versions of required Python packages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:339 f6a1523241f54a9ba84dfed4f6dde3b2\nmsgid \"Removed dependency on setuptools.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:340 1596796af81b476e80835455e0a27a29\nmsgid \"Added item to PyMuPDF-1.24.10 changes below - fix of #3630.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:343 0d1ea2fa95e1430a91731b5c309c154f\nmsgid \"**Changes in version 1.24.10 (2024-09-02)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:345 0fdb57593f1f47f78b61e459d90c4fd0\nmsgid \"Use MuPDF-1.24.9.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:349 4c1b818189074d939767d48fa6ba40e6\nmsgid \"\"\n\"**Fixed** `3450 <https://github.com/pymupdf/PyMuPDF/issues/3450>`_: \"\n\"get_pixmap function takes too long to process\"\nmsgstr \"\"\n\n#: ../../../changes.txt:350 03bc289e1528407b8433671ea3e5587e\nmsgid \"\"\n\"**Fixed** `3569 <https://github.com/pymupdf/PyMuPDF/issues/3569>`_: \"\n\"Invalid OCGs not ignored by SVG image creation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:351 3e64094a0a16437ab1fceb4fd8904883\nmsgid \"\"\n\"**Fixed** `3603 <https://github.com/pymupdf/PyMuPDF/issues/3603>`_: \"\n\"ObjStm compression and PDF linearization doesn't work together\"\nmsgstr \"\"\n\n#: ../../../changes.txt:352 4a6c4d95199b49919c2ec7b76da32a3a\nmsgid \"\"\n\"**Fixed** `3650 <https://github.com/pymupdf/PyMuPDF/issues/3650>`_: \"\n\"Linebreak inserted between each letter\"\nmsgstr \"\"\n\n#: ../../../changes.txt:353 a5fb10f857014368871b0ee0628a1ef1\nmsgid \"\"\n\"**Fixed** `3661 <https://github.com/pymupdf/PyMuPDF/issues/3661>`_: \"\n\"Update Document to check the /XYZ len\"\nmsgstr \"\"\n\n#: ../../../changes.txt:354 77892cd87ca346d381b0b249574312b4\nmsgid \"\"\n\"**Fixed** `3698 <https://github.com/pymupdf/PyMuPDF/issues/3698>`_: \"\n\"documentation issue - old code in the annotations documentation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:355 8a4df3770f95440c870288e5f497cf93\nmsgid \"\"\n\"**Fixed** `3705 <https://github.com/pymupdf/PyMuPDF/issues/3705>`_: \"\n\"Document.select() behaves weirdly in some particular kind of pdf files\"\nmsgstr \"\"\n\n#: ../../../changes.txt:356 575c721454394ef5954021b2e3910c5a\nmsgid \"\"\n\"**Fixed** `3706 <https://github.com/pymupdf/PyMuPDF/issues/3706>`_: \"\n\"extend Document.__getitem__ type annotation to reflect that the method \"\n\"also accepts slices\"\nmsgstr \"\"\n\n#: ../../../changes.txt:357 b4081c4845a3495cab35195cfcbd4e5f\nmsgid \"\"\n\"**Fixed** `3727 <https://github.com/pymupdf/PyMuPDF/issues/3727>`_: \"\n\"Method get_pixmap() make the program exit without any exceptions or \"\n\"messages\"\nmsgstr \"\"\n\n#: ../../../changes.txt:358 4a582d7cc3ca40cfba3314faa5800f56\nmsgid \"\"\n\"**Fixed** `3767 <https://github.com/pymupdf/PyMuPDF/issues/3767>`_: \"\n\"Cannot get Tessdata with Tesseract-OCR 5\"\nmsgstr \"\"\n\n#: ../../../changes.txt:359 9a3c4b91a07e4c118de884a8c386dcfb\nmsgid \"\"\n\"**Fixed** `3773 <https://github.com/pymupdf/PyMuPDF/issues/3773>`_: \"\n\"Link.set_border gives TypeError: '<' not supported between instances of \"\n\"'NoneType' and 'int'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:360 d3028f61318447b68e56290fbd6732cc\nmsgid \"\"\n\"**Fixed** `3774 <https://github.com/pymupdf/PyMuPDF/issues/3774>`_: \"\n\"fitz.__version__` does not work anymore\"\nmsgstr \"\"\n\n#: ../../../changes.txt:361 596c2f50505948db9e84f139ffaea8fa\nmsgid \"\"\n\"**Fixed** `3789 <https://github.com/pymupdf/PyMuPDF/issues/3789>`_: \"\n\"ValueError: not enough values to unpack (expected 3, got 2) is thrown \"\n\"when call insert_pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:362 e99c3b3c69d1484f8ea0b97279da22e4\nmsgid \"\"\n\"**Fixed** `3820 <https://github.com/pymupdf/PyMuPDF/issues/3820>`_: class\"\n\" improves namedDest handling\"\nmsgstr \"\"\n\n#: ../../../changes.txt:364 9c63afe342914710a2f4b27172881a97\nmsgid \"\"\n\"**Fixed** `3630 <https://github.com/pymupdf/PyMuPDF/issues/3630>`_: \"\n\"page.apply_redactions gives unwanted black rectangle\"\nmsgstr \"\"\n\n#: ../../../changes.txt:368 a69ca8bf39fc49c78509e477fc16ec48\nmsgid \"\"\n\"Object streams and linearization cannot be used together; attempting to \"\n\"do so will raise an exception. (#3603)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:370 d667244f9aa14f1d8b25176a013989e0\nmsgid \"Fixed handling of non-existing /Contents object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:373 007020c8bc19452da4cd657fdcba20c0\nmsgid \"**Changes in version 1.24.9 (2024-07-24)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:375 3025163fadb648e88e840b5f088e6d56\nmsgid \"Use MuPDF-1.24.8.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:378 259a038beea8413baaac6ee36c977d21\nmsgid \"**Changes in version 1.24.8 (2024-07-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:382 a3d2403d008e4902bda8c294e7d5b193\nmsgid \"\"\n\"**Fixed** `3636 <https://github.com/pymupdf/PyMuPDF/issues/3636>`_: API \"\n\"documentation for the open function is not obvious to find.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:383 eb0f33456dca477bb49123d26150dbd5\nmsgid \"\"\n\"**Fixed** `3654 <https://github.com/pymupdf/PyMuPDF/issues/3654>`_: docx \"\n\"parsing was broken in 1.24.7\"\nmsgstr \"\"\n\n#: ../../../changes.txt:384 6c8df8e668094aef8d31035e9dc0e65d\nmsgid \"\"\n\"**Fixed** `3677 <https://github.com/pymupdf/PyMuPDF/issues/3677>`_: \"\n\"Unable to extract subset font name using the newer versions of PyMuPDF : \"\n\"1.24.6 and 1.24.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:385 c5b0babed39f440d99efdd7a90d63f4b\nmsgid \"\"\n\"**Fixed** `3687 <https://github.com/pymupdf/PyMuPDF/issues/3687>`_: \"\n\"Page.get_text results in AssertionError for epub files\"\nmsgstr \"\"\n\n#: ../../../changes.txt:389 e245fedf7bb24e8d92d8116cb00ad30e\nmsgid \"Fixed various spelling mistakes spotted by codespell.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:390 764d9b752f59499e856f560908cee6d9\nmsgid \"Improved how we modify MuPDF's default configuration on Windows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:391 6e8cb04f867c4ad59e8be783e217fc4d\nmsgid \"Make text search to work with ligatures.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:394 25efadfa996341b38552789392dbaf74\nmsgid \"**Changes in version 1.24.7 (2024-06-26)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:398 fa9eea5710484750bedce90cc64b9daf\nmsgid \"\"\n\"**Fixed** `3615 <https://github.com/pymupdf/PyMuPDF/issues/3615>`_: \"\n\"Document.pagemode or Document.pagelayout crashes for epub files\"\nmsgstr \"\"\n\n#: ../../../changes.txt:399 795aad875dfc458eb4a6c99bccde0cec\nmsgid \"\"\n\"**Fixed** `3616 <https://github.com/pymupdf/PyMuPDF/issues/3616>`_: not \"\n\"last version reported\"\nmsgstr \"\"\n\n#: ../../../changes.txt:402 b75b54baeb764ed5bfca7d9290d654f6\nmsgid \"**Changes in version 1.24.6 (2024-06-25)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:404 ce8d669017974969859f4cf2c64c5c09\nmsgid \"Use MuPDF-1.24.4\"\nmsgstr \"\"\n\n#: ../../../changes.txt:408 f726a1ab74364bca9e9f707167e9d0af\nmsgid \"\"\n\"**Fixed** `3599 <https://github.com/pymupdf/PyMuPDF/issues/3599>`_: \"\n\"Story.fit_width() has a weird line\"\nmsgstr \"\"\n\n#: ../../../changes.txt:409 8e99b98271ea423bb26bb068ec39ea52\nmsgid \"\"\n\"**Fixed** `3594 <https://github.com/pymupdf/PyMuPDF/issues/3594>`_: \"\n\"Garbled extraction for Amazon Sustainability Report\"\nmsgstr \"\"\n\n#: ../../../changes.txt:410 651a15f12d5043b6b328618180353f68\nmsgid \"\"\n\"**Fixed** `3591 <https://github.com/pymupdf/PyMuPDF/issues/3591>`_: \"\n\"'width' in Page.get_drawings() returns width equal as 0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:411 02fe36631c264c87895576864dc44e43\nmsgid \"\"\n\"**Fixed** `3561 <https://github.com/pymupdf/PyMuPDF/issues/3561>`_: \"\n\"ZeroDivisionError: float division by zero with page.apply_redactions()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:412 99db39151ed74f9d97810a41633d73e2\nmsgid \"\"\n\"**Fixed** `3559 <https://github.com/pymupdf/PyMuPDF/issues/3559>`_: \"\n\"SegFault 11 when empty H1 H2 H3 H4 etc element is used in insert_htmlbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:413 5e95ed936be0415c95c278cf1d1a9999\nmsgid \"\"\n\"**Fixed** `3539 <https://github.com/pymupdf/PyMuPDF/issues/3539>`_: Add \"\n\"dotted gridline detection to table recognition\"\nmsgstr \"\"\n\n#: ../../../changes.txt:414 75ffb0d518004dc2a74244b12b6c97bd\nmsgid \"\"\n\"**Fixed** `3519 <https://github.com/pymupdf/PyMuPDF/issues/3519>`_: \"\n\"get_toc(simple=False) AttributeError: 'Outline' object has no attribute \"\n\"'rect'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:415 495d1b01dfb7457ebb231eca62c7c539\nmsgid \"\"\n\"**Fixed** `3510 <https://github.com/pymupdf/PyMuPDF/issues/3510>`_: \"\n\"page.get_label() gets wrong label on the first page of doc\"\nmsgstr \"\"\n\n#: ../../../changes.txt:416 60f43a90ceb845b2adf2947634af64ac\nmsgid \"\"\n\"**Fixed** `3494 <https://github.com/pymupdf/PyMuPDF/issues/3494>`_: \"\n\"1.24.2/1.24.3: spurious characters introduced when using subset_fonts and\"\n\" insert_pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:417 a4e0010c0d8f45beaae70809abc81039\nmsgid \"\"\n\"**Fixed** `3470 <https://github.com/pymupdf/PyMuPDF/issues/3470>`_: \"\n\"subset_fonts error exit without exception/warning\"\nmsgstr \"\"\n\n#: ../../../changes.txt:418 99fd9bbe5dba43aa9c040b3a77aee77c\nmsgid \"\"\n\"**Fixed** `3400 <https://github.com/pymupdf/PyMuPDF/issues/3400>`_: \"\n\"set_toc alters link coordinates for some rotated pages on pymupdf 1.24.2\"\nmsgstr \"\"\n\n#: ../../../changes.txt:419 82687af929194a6dbf9c19ea545b5e0b\nmsgid \"\"\n\"**Fixed** `3347 <https://github.com/pymupdf/PyMuPDF/issues/3347>`_: \"\n\"Incorrect links to points on pages having different heights\"\nmsgstr \"\"\n\n#: ../../../changes.txt:420 340ce003832a4bf4a832ae0623c2ac19\nmsgid \"\"\n\"**Fixed** `3237 <https://github.com/pymupdf/PyMuPDF/issues/3237>`_: \"\n\"Set_metadata() does not work\"\nmsgstr \"\"\n\n#: ../../../changes.txt:421 ce983433667f4f27a675ad0f4ab90de8\nmsgid \"\"\n\"**Fixed** `3493 <https://github.com/pymupdf/PyMuPDF/discussions/3493>`_: \"\n\"Isolate PyMuPDF from other libraries; issues when PyMuPDF is loaded with \"\n\"other libraries like GdkPixbuf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:425 85db5876f5884fdb94a243fa8cea3bb5\nmsgid \"\"\n\"Fixed concurrent use of PyMuPDF caused by use of constant temporary \"\n\"filenames.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:427 7bc8d5be62d24850bd1a2d0b042c5dc7\nmsgid \"Add musllinux x86_64 wheels to release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:429 8442053275014be3a2961c23d5c1e875\nmsgid \"Added clearer version information:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:431 898d54fe7f294059a365ce4df283fa8e\nmsgid \"`pymupdf.pymupdf_version`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:432 e17b0b91f04f41c49b685ec88163c914\nmsgid \"`pymupdf.mupdf_version`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:433 b2b4d699826c44f3b82cbbffd7b8134e\nmsgid \"`pymupdf.pymupdf_date`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:436 0641d353405748829b979a38171a2825\nmsgid \"**Changes in version 1.24.5 (2024-05-30)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:440 d9b804a172e24fa782e586380589a791\nmsgid \"\"\n\"**Fixed** `3479 <https://github.com/pymupdf/PyMuPDF/issues/3479>`_: \"\n\"regression: fill_textbox: IndexError: pop from empty list\"\nmsgstr \"\"\n\n#: ../../../changes.txt:441 d00ec180a30548e7bd1094a5ff22289b\nmsgid \"\"\n\"**Fixed** `3488 <https://github.com/pymupdf/PyMuPDF/issues/3488>`_: \"\n\"set_toc method error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:445 53a42d7778c84e85ab793f4fc54ce4e8\nmsgid \"Some more fixes to use MuPDF floating formatting.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:446 8feda6eedae84994a727c20e7a2336be\nmsgid \"Removed/disabled some unnecessary diagnostics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:447 e96bd409e11d432aa398f8aeedd58c7a\nmsgid \"Fixed utils.do_links() crash.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:448 24e4d4aed05840ea9abe1c2c2805be34\nmsgid \"\"\n\"Experimental new functions `pymupdf.apply_pages()` and \"\n\"`pymupdf.get_text()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:449 b8a6f1cfb64748d79bc0b69465631b51\nmsgid \"Addresses wrong label generation for label styles \\\"a\\\" and \\\"A\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:452 0ba74ae644a1428d89fe14ef6b0babee\nmsgid \"**Changes in version 1.24.4 (2024-05-16)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:454 8347374b5a5e45b28a7f8f4afb292726\nmsgid \"\"\n\"**Fixed** `3418 <https://github.com/pymupdf/PyMuPDF/issues/3418>`_: Re-\"\n\"introduced bug, text align add_redact_annot\"\nmsgstr \"\"\n\n#: ../../../changes.txt:455 cb6d95a9123f4086b6ac158e88717571\nmsgid \"\"\n\"**Fixed** `3472 <https://github.com/pymupdf/PyMuPDF/issues/3472>`_: \"\n\"insert_pdf gives SystemError\"\nmsgstr \"\"\n\n#: ../../../changes.txt:459 c0361428884345bf8531a84f4780ea38\nmsgid \"\"\n\"Fixed sysinstall test failing to remove all of prior installation before \"\n\"new install.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:461 5889a769a9d6497db5651e5de06b452c\nmsgid \"Fixed `utils.do_links()` crash.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:462 18689db9f7b34a0aada6aabae6348c36\nmsgid \"Correct `TextPage` creation Code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:463 47ec7c100c6c4cb89c0c9032e653d85d\nmsgid \"Unified various diagnostics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:464 0ad11e95e8244ebab3b4e28a268c3b58\nmsgid \"Fix bug in `page_merge()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:467 b8f39f2e163741529a0c07525b38ee4e\nmsgid \"**Changes in version 1.24.3 (2024-05-09)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:470 cad11f9fca1541eda51c5b1ddc360907\nmsgid \"\"\n\"The Python module is now called `pymupdf`. `fitz` is still supported for \"\n\"backwards compatibility.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:473 26ab1d955ad94d82a842066be61b2b45\nmsgid \"Use MuPDF-1.24.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:477 d78b4e742a1540d795b9023df668616a\nmsgid \"\"\n\"**Fixed** `3357 <https://github.com/pymupdf/PyMuPDF/issues/3357>`_: \"\n\"PyMuPDF==1.24.0 will hanging when using page.get_text(\\\"text\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:478 d3a781ba5c1b4e4ea729e32165591767\nmsgid \"\"\n\"**Fixed** `3376 <https://github.com/pymupdf/PyMuPDF/issues/3376>`_: \"\n\"Redacting results are not as expected in 1.24.x.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:479 9d45832a290b4dec88aff88537dbbde6\nmsgid \"\"\n\"**Fixed** `3379 <https://github.com/pymupdf/PyMuPDF/issues/3379>`_: \"\n\"Documentation mismatch for get_text_blocks return value order.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:480 fb62ce84c5d24c1b802be0a91c9592fc\nmsgid \"\"\n\"**Fixed** `3381 <https://github.com/pymupdf/PyMuPDF/issues/3381>`_: \"\n\"Contents stream contains floats in scientific notation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:481 0862ddcf8e644d3ea7ac0a7c60de28d1\nmsgid \"\"\n\"**Fixed** `3402 <https://github.com/pymupdf/PyMuPDF/issues/3402>`_: \"\n\"Cannot add Widgets containing inter-field-calculation JavaScript\"\nmsgstr \"\"\n\n#: ../../../changes.txt:482 3d4f814eb5ec4e72a5adea1bd245b32f\nmsgid \"\"\n\"**Fixed** `3414 <https://github.com/pymupdf/PyMuPDF/issues/3414>`_: \"\n\"missing attribute set_dpi()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:483 cdcbe4b8d58544f0948c1b3c28f9b3d9\nmsgid \"\"\n\"**Fixed** `3430 <https://github.com/pymupdf/PyMuPDF/issues/3430>`_: \"\n\"page.get_text() cause process freeze with certain pdf on v1.24.2\"\nmsgstr \"\"\n\n#: ../../../changes.txt:487 ../../../changes.txt:509\n#: 1034de3f71fc4bd187b3f046c83bedbe 8863ca296ccc4716b6f80e99291be2e5\nmsgid \"New/modified methods:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:489 8cea70e9366142759f75487402e703b3\nmsgid \"\"\n\"`Page.remove_rotation()`: new, set page rotation to zero while keeping \"\n\"appearance.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:491 f1014ad8f9ec4d87968c7de24b7e7f70\nmsgid \"Fixed some problems when checking for PDF properties.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:492 64cfa246e9094b0ebd62758e2eb3598f\nmsgid \"\"\n\"Fixed pip builds from sdist (see discussion `3360 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/3360>`_: Alpine linux \"\n\"docker build failing \\\"No matching distribution found for \"\n\"pymupdfb==1.24.1\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:497 f8ef0c76081a402dbac0efa8b7644241\nmsgid \"**Changes in version 1.24.2 (2024-04-17)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:499 bf95d9b1e5994a2091c8f66685f22854\nmsgid \"\"\n\"Removed obsolete classic implementation from releases (previously \"\n\"available as module `fitz_old`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:504 4a87d3564d3d4cedae93e2b51349aaa2\nmsgid \"\"\n\"**Fixed** `3331 <https://github.com/pymupdf/PyMuPDF/issues/3331>`_: \"\n\"Document.pages() is incorrectly type-hinted\"\nmsgstr \"\"\n\n#: ../../../changes.txt:505 84e9e429e5af4263a7fd5db405b5842a\nmsgid \"\"\n\"**Fixed** `3354 <https://github.com/pymupdf/PyMuPDF/issues/3354>`_: \"\n\"PyMuPDF==1.24.1: AttributeError: property 'metadata' of 'Document' object\"\n\" has no setter\"\nmsgstr \"\"\n\n#: ../../../changes.txt:511 818e26cf4c0f4ce08f1bf68e48eab8b0\nmsgid \"`Document.bake()`: new, make annotations / fields permanent content.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:512 6a0b794fe12f4bb4a005a8f1bdc5c188\nmsgid \"\"\n\"`Page.cluster_drawings()`: new, identifies drawing items (i.e. vector \"\n\"graphics or line-art) that belong together based on their geometrical \"\n\"vicinity.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:515 f1fb556a239a49e6b90a938b0360868a\nmsgid \"`Page.apply_redactions()`: added new parameter `text`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:516 c47d84ec4dd34a6687719bcfafebdb25\nmsgid \"\"\n\"`Document.subset_fonts()`: use MuPDF's `pdf_subset_fonts()` instead of \"\n\"PyMuPDF code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:518 b56ff5e11e894337b35ae03c405c4666\nmsgid \"The `Document` class now supports page numbers specified as slices.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:519 68a2d9fa6804400dbecc0e1d60d85280\nmsgid \"Avoid causing MuPDF warnings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:522 167f53146b304aaf9812103ca9c4e29c\nmsgid \"**Changes in version 1.24.1 (2024-04-02)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:526 9dcf0965da0a489cabf3d2ab88226762\nmsgid \"\"\n\"**Fixed** `3278 <https://github.com/pymupdf/PyMuPDF/issues/3278>`_: \"\n\"apply_redactions moves some unredacted text\"\nmsgstr \"\"\n\n#: ../../../changes.txt:527 c23c377d35194a0094bd6e4beab89d9d\nmsgid \"\"\n\"**Fixed** `3301 <https://github.com/pymupdf/PyMuPDF/issues/3301>`_: Be \"\n\"more permissive when classifying links as kind LINK_URI\"\nmsgstr \"\"\n\n#: ../../../changes.txt:528 c6e16db559364535a9c002bd61adb627\nmsgid \"\"\n\"**Fixed** `3306 <https://github.com/pymupdf/PyMuPDF/issues/3306>`_: Text \"\n\"containing capital 'ET' not appearing as annotation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:532 ae65e5dcbdbb47e7b6182ae2f1e35080\nmsgid \"Use MuPDF-1.24.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:533 606e5f2a82694796b16017c9e6988751\nmsgid \"\"\n\"Support ObjStm Compression. Methods `Document.save()`, \"\n\"`Document.ez_save()` and `Document.write()` now support new parameters \"\n\"`use_objstm`, compression_effort` and `preserve_metadata`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:539 e0d826430dab4605843b857d55556f31\nmsgid \"**Changes in version 1.24.0 (2024-03-21)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:543 56ae3cb3eae74794bf8c66f9478e1eaa\nmsgid \"\"\n\"**Fixed** `3281 <https://github.com/pymupdf/PyMuPDF/issues/3281>`_: \"\n\"Preparing metadata (pyproject.toml) did not run successfully\"\nmsgstr \"\"\n\n#: ../../../changes.txt:544 c2af0005171741dfa062c48305fdff68\nmsgid \"\"\n\"**Fixed** `3279 <https://github.com/pymupdf/PyMuPDF/issues/3279>`_: \"\n\"PyMuPDF no longer builds in Alpine Linux\"\nmsgstr \"\"\n\n#: ../../../changes.txt:545 d9b6c05ed6004aca8f3189adad180c42\nmsgid \"\"\n\"**Fixed** `3257 <https://github.com/pymupdf/PyMuPDF/issues/3257>`_: \"\n\"apply_redactions() deleting text outside of annoted box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:546 8baeb884a8f84d2fbf0d5b17af55639c\nmsgid \"\"\n\"**Fixed** `3216 <https://github.com/pymupdf/PyMuPDF/issues/3216>`_: \"\n\"AttributeError: 'Annot' object has no attribute '__del__'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:547 37068b47c21542ccbcc5d6326e7046f1\nmsgid \"\"\n\"**Fixed** `3207 <https://github.com/pymupdf/PyMuPDF/issues/3207>`_: \"\n\"get_drawings's items is missing line from h path operator\"\nmsgstr \"\"\n\n#: ../../../changes.txt:548 a4e36666ffbc4aca8006de811d305b60\nmsgid \"\"\n\"**Fixed** `3201 <https://github.com/pymupdf/PyMuPDF/issues/3201>`_: \"\n\"Memory leaks when merging PDFs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:549 72cdc09b51ef425ab50c8aae8a380ce6\nmsgid \"\"\n\"**Fixed** `3197 <https://github.com/pymupdf/PyMuPDF/issues/3197>`_: \"\n\"page.get_text() returns hexadecimal text for some characters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:550 055ea678a07b4991b05894009ada4484\nmsgid \"\"\n\"**Fixed** `3196 <https://github.com/pymupdf/PyMuPDF/issues/3196>`_: \"\n\"Remove text not working in 1.23.25 version vs 1.20.2\"\nmsgstr \"\"\n\n#: ../../../changes.txt:551 eebdd0d853a04d7890db0116aeda3b84\nmsgid \"\"\n\"**Fixed** `3172 <https://github.com/pymupdf/PyMuPDF/issues/3172>`_: PDF's\"\n\" 45º lines dissapearing in png conversion\"\nmsgstr \"\"\n\n#: ../../../changes.txt:552 fd48b5fe2cf74dbb8772e3ffda26cc5b\nmsgid \"\"\n\"**Fixed** `3135 <https://github.com/pymupdf/PyMuPDF/issues/3135>`_: Do \"\n\"not log warnings to stdout\"\nmsgstr \"\"\n\n#: ../../../changes.txt:553 5a2c034748ca435d97157e0e01631edc\nmsgid \"\"\n\"**Fixed** `3125 <https://github.com/pymupdf/PyMuPDF/issues/3125>`_: \"\n\"get_pixmap method stuck on one page and runs forever\"\nmsgstr \"\"\n\n#: ../../../changes.txt:554 2b0bc004e652473d8424fbaf44acc132\nmsgid \"\"\n\"**Fixed** `2964 <https://github.com/pymupdf/PyMuPDF/issues/2964>`_: There\"\n\" is an issue with the image generated by the page.get_pixmap() function\"\nmsgstr \"\"\n\n#: ../../../changes.txt:558 7489ffec843d457ca500cfb476753615\nmsgid \"Use MuPDF-1.24.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:559 7c55068e2bc44f7a90942db48624c211\nmsgid \"Add support for redacting vector graphics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:560 994636840ff242bb90c2538f8b313764\nmsgid \"Several fixes for table module\"\nmsgstr \"\"\n\n#: ../../../changes.txt:562 1cde4b0108a34c66bcf26a1e69169d92\nmsgid \"Add new method for outputting the table as a markdown string.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:564 9fcf8beb4cbf4808b3636964252fb397\nmsgid \"Address errors in computing the table header object:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:566 466f446d303f45039a8d621fa72be582\nmsgid \"\"\n\"We now allow None as the cell value, because this will be resolved where \"\n\"needed (e.g. in the pandas DataFrame).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:569 b1456724d60f446b99497879dec77edc\nmsgid \"\"\n\"We previously tried to enforce rect-like tuples in all header cell \"\n\"bboxes, however this fails for tables with all-None columns.  This fix \"\n\"enables this and constructs an empty string in the corresponding cell \"\n\"string.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:574 bd966cd782ae48e6bf574d6aa1e75969\nmsgid \"\"\n\"We now correctly include start / stop points of lines in the bbox of the \"\n\"clustered graphic.  We previously joined the line's rectangle - which had\"\n\" no effect because this is always empty.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:578 8b34024dc26b46d6bb00721aee57b203\nmsgid \"Improved exception text if we fail to open document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:579 2ad46d306493434ba2f21cbc55598c4e\nmsgid \"Fixed build with new libclang 18.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:582 e0f45c4d68334077bde30abcb37f442c\nmsgid \"**Changes in version 1.23.26 (2024-02-29)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:586 2f2ec05926254e2f9d6790002f8f0dbb\nmsgid \"\"\n\"**Fixed** `3199 <https://github.com/pymupdf/PyMuPDF/issues/3199>`_: Add \"\n\"entry_points to setuptools configuration to provide command-line console \"\n\"scripts\"\nmsgstr \"\"\n\n#: ../../../changes.txt:587 254166b6829a47ebae52f0d1befd4f8c\nmsgid \"\"\n\"**Fixed** `3209 <https://github.com/pymupdf/PyMuPDF/issues/3209>`_: Empty\"\n\" vertices in ink annotation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:591 72a0f38fcb3f4fadae2a9750a83ecf70\nmsgid \"Improvements to table detection:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:593 70ae893cd45741a59c2a753e1efe9d04\nmsgid \"\"\n\"Improved check for empty tables, fixes bugs when determining table \"\n\"headers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:594 db5ad6c22fa8479fb66f6ada59044c7e\nmsgid \"Improved computation of enveloping vector graphic rectangles.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:595 7f5ea75a3d2b47809b85588c78b70318\nmsgid \"Ignore more meaningless \\\"pseudo\\\" tables\"\nmsgstr \"\"\n\n#: ../../../changes.txt:597 6cd939d409f341f6a264ff3b4624cca6\nmsgid \"Install command-line 'pymupdf' command that runs fitz/__main__.py.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:598 6afb7824085740ccaf2fc01c782dffcb\nmsgid \"Don't overwrite MuPDF's config.h when building on non-Windows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:599 86e24a39bb0541a4ac1e71e88541c698\nmsgid \"\"\n\"Fix `Story` constructor's `archive` arg to match docs - now accepts a \"\n\"single `Archive` constructor arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:600 a3ea96e9f72f483bbf461ca1d128b1e4\nmsgid \"\"\n\"Do not include MuPDF source in sdist; will be downloaded automatically \"\n\"when building.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:603 b80b43ad742c43ab9880dd54056a9973\nmsgid \"**Changes in version 1.23.25 (2024-02-20)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:607 ea65b6e10b4443fd98d4487f8a6227ce\nmsgid \"\"\n\"**Fixed** `3182 <https://github.com/pymupdf/PyMuPDF/issues/3182>`_: \"\n\"Pixmap.invert_irect argument type error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:608 420d27a70b34444aba118e43db9e4802\nmsgid \"\"\n\"**Fixed** `3186 <https://github.com/pymupdf/PyMuPDF/issues/3186>`_: \"\n\"extractText() extracts broken text from pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:609 90aadcf4b788454abbf2665a0b7b8f22\nmsgid \"\"\n\"**Fixed** `3191 <https://github.com/pymupdf/PyMuPDF/issues/3191>`_: Error\"\n\" on .find_tables()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:613 0a5a831494a04b18b50fdfc5d3833038\nmsgid \"\"\n\"When building, be able to specify python-config directly, with \"\n\"environment variable `PIPCL_PYTHON_CONFIG`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:617 93b9bfcd66aa426eaacb92d54e23c667\nmsgid \"**Changes in version 1.23.24 (2024-02-19)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:621 3748e8d370624cd1889b240a694cc72e\nmsgid \"\"\n\"**Fixed** `3148 <https://github.com/pymupdf/PyMuPDF/issues/3148>`_: Table\"\n\" extraction - vertical text not handled correctly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:622 0017cea29f1247be99c102c56a8fabd1\nmsgid \"\"\n\"**Fixed** `3179 <https://github.com/pymupdf/PyMuPDF/issues/3179>`_: Table\"\n\" Detection: Incorrect Separation of Vector Graphics Clusters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:623 dde9c50cb60147428936ac9e5bdacc81\nmsgid \"\"\n\"**Fixed** `3180 <https://github.com/pymupdf/PyMuPDF/issues/3180>`_: \"\n\"Cannot show optional content group: AttributeError: module 'fitz.mupdf' \"\n\"has no attribute 'pdf_array_push_drop'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:627 838816f12e394f49b9e2ef7b4559fd71\nmsgid \"Be able to test system install using `sudo pip install` instead of a venv.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:630 0b4ca8027622493090312b1e74a4839a\nmsgid \"**Changes in version 1.23.23 (2024-02-18)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:634 5c5c4b53219b4e8492fec8aafaa14b7e\nmsgid \"\"\n\"**Fixed** `3126 <https://github.com/pymupdf/PyMuPDF/issues/3126>`_: \"\n\"Initialising Archive with a pathlib.Path fails.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:635 e5745b8508084965a56f4151794f8378\nmsgid \"\"\n\"**Fixed** `3131 <https://github.com/pymupdf/PyMuPDF/issues/3131>`_: \"\n\"Calling the next attribute of an Annot raises a \\\"No attribute .parent\\\" \"\n\"warning\"\nmsgstr \"\"\n\n#: ../../../changes.txt:636 59d2c178ba9c4d47977704a9feccc1ea\nmsgid \"\"\n\"**Fixed** `3134 <https://github.com/pymupdf/PyMuPDF/issues/3134>`_: Using\"\n\" an IRect as clip parameter in Page.get_pixmap no longer works since \"\n\"1.23.9\"\nmsgstr \"\"\n\n#: ../../../changes.txt:637 43be27e8f82c45ef90522a9da30a0a72\nmsgid \"\"\n\"**Fixed** `3140 <https://github.com/pymupdf/PyMuPDF/issues/3140>`_: PDF \"\n\"document stays in use after closing\"\nmsgstr \"\"\n\n#: ../../../changes.txt:638 cbe3a25490474db9973829ac9e661e5b\nmsgid \"\"\n\"**Fixed** `3150 <https://github.com/pymupdf/PyMuPDF/issues/3150>`_: \"\n\"doc.select() hangs on this doc.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:639 b40c96dbbba64f6f82a0dbc3fb5570db\nmsgid \"\"\n\"**Fixed** `3163 <https://github.com/pymupdf/PyMuPDF/issues/3163>`_: \"\n\"AssertionError on using fitz.IRect\"\nmsgstr \"\"\n\n#: ../../../changes.txt:640 5b0e909d8b1c42c4815f57178c08f1d0\nmsgid \"\"\n\"**Fixed** `3177 <https://github.com/pymupdf/PyMuPDF/issues/3177>`_: \"\n\"fitz.Pixmap(None, pix) Unrecognised args for constructing Pixmap\"\nmsgstr \"\"\n\n#: ../../../changes.txt:645 bcff5266d81d44828538dd318c25c548\nmsgid \"\"\n\"Improved `Document.select() by using new MuPDF function \"\n\"`pdf_rearrange_pages()`. This is a more complete (and faster) \"\n\"implementation of what needs to be done here in that not only pages will \"\n\"be rearranged, but also consequential changes will be made to the table \"\n\"of contents, links to removed pages and affected entries in the Optional \"\n\"Content definitions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:651 7e5e70f9786348e485e9f480c4c5f649\nmsgid \"`TextWriter.appendv()`: added `small_caps` arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:652 511da4bdc4cb4d488b5540f7118d05c6\nmsgid \"Fixed some valgrind errors with MuPDF master.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:653 9fa27b2a0f6542779698b58b6ef2797f\nmsgid \"Fixed `Document.insert_image()` when build with MuPDF master.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:656 8215b8e723014b82adeefa3d490e76cf\nmsgid \"**Changes in version 1.23.22 (2024-02-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:660 9499acfbd68c4038bf82444da1a07c47\nmsgid \"\"\n\"**Fixed** `3143 <https://github.com/pymupdf/PyMuPDF/issues/3143>`_: \"\n\"Difference in decoding of OCGs names between doc.get_ocgs() and \"\n\"page.get_drawings()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:662 6a05eddb0f5846589fe4c0086fc9e146\nmsgid \"\"\n\"**Fixed** `3139 <https://github.com/pymupdf/PyMuPDF/issues/3139>`_: \"\n\"Pixmap resizing needs positional arg \\\"clip\\\" - even if None.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:666 9a6bd516b5734957b5d8700fec418b18\nmsgid \"Removed the use of MuPDF function `fz_image_size()` from PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:669 32b339e622b6447890c25a4ab191fd39\nmsgid \"**Changes in version 1.23.21 (2024-02-01)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:675 fab60867577a487b9c3f486166614839\nmsgid \"\"\n\"Fixed bug in set_xml_metadata(), PR `3112 \"\n\"https://github.com/pymupdf/PyMuPDF/pull/3112>`_: Fix pdf_add_stream \"\n\"metadata error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:676 5db3c0df43d7466bb49c93da76eb7ded\nmsgid \"Fixed lack of `.parent` member in `TextPage` from `Annot.get_textpage()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:677 6886cfc95dcf48449baf3597f9ed5a5b\nmsgid \"Fixed bug in `Page.add_widget()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:680 466b6a96778a400fa703f8a164dc6006\nmsgid \"**Changes in version 1.23.20 (2024-01-29)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:682 ../../../changes.txt:693 ../../../changes.txt:711\n#: ../../../changes.txt:723 ../../../changes.txt:737 ../../../changes.txt:750\n#: ../../../changes.txt:761 ../../../changes.txt:773 ../../../changes.txt:797\n#: ../../../changes.txt:917 ../../../changes.txt:934 ../../../changes.txt:966\n#: ../../../changes.txt:1023 ../../../changes.txt:1099\n#: ../../../changes.txt:1133 ../../../changes.txt:1142\n#: ../../../changes.txt:1151 ../../../changes.txt:1169\n#: ../../../changes.txt:1269 ../../../changes.txt:1308\n#: 10bae71e3a574059884b4f1d5baea65c 11746df9cf7b4144bc9cabc8e95b78a9\n#: 35c5e4be6606427a95322276ca783f0e 4bbb30be5f60421a87e36a340ddbe65f\n#: 524f6c6556b5468c90bac3e6f81b279d 5a44d84debe5475da967de80ba53914b\n#: 5ed487b98bc84f92a08fdb4934e8535b 74166ebee93f4e9e999f1cd22be78aaf\n#: 780c7d9984234abebe430e3254afc4e8 a47d1d46827b45bebe969ac04f21dc0f\n#: a6ae2f8c435749c4a8dc5fbe5c95dff6 a776aae290f74bdfaa636b31d9b933e0\n#: bb6b3124820a4512a56446f360c94404 c7fa8793bb6d44aca1771c6152ac83d8\n#: d22de0587ab24d4ab437626e883261d4 dd73709cf4c74a6e9d9a8eba46753cd2\n#: e4a33a6c03dd49d0a338e5b67900cac8 f7e8261277e44b8abe33e6e0f05bcde7\n#: f98503e4ea7c425391e56ac00fbae870 fc10345ba347482ba6bf7042461f8232\nmsgid \"Bug fixes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:684 e101eae15b004da2849ab4be087a4010\nmsgid \"\"\n\"**Fixed** `3100 <https://github.com/pymupdf/PyMuPDF/issues/3100>`_: Wrong\"\n\" internal property accessed in get_xml_metadata\"\nmsgstr \"\"\n\n#: ../../../changes.txt:688 30795d0573e140c88dd4cf9e6887fbe0\nmsgid \"Significantly improved speed of `Document.get_toc()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:691 f23cca9b1fc84d0ea474332f2e1c6c2c\nmsgid \"**Changes in version 1.23.19 (2024-01-25)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:695 36758073da3a48f5bc485fd6a9fc328e\nmsgid \"\"\n\"**Fixed** `3087 <https://github.com/pymupdf/PyMuPDF/issues/3087>`_: \"\n\"Exception in insert_image with mask specified\"\nmsgstr \"\"\n\n#: ../../../changes.txt:696 202f997680f84ed9b7bf363b2b348028\nmsgid \"\"\n\"**Fixed** `3094 <https://github.com/pymupdf/PyMuPDF/issues/3094>`_: \"\n\"TypeError: '<' not supported between instances of 'FzLocation' and 'int' \"\n\"in doc.delete_pages\"\nmsgstr \"\"\n\n#: ../../../changes.txt:700 b8dceb00014f42ccb7877fe431320209\nmsgid \"When finding tables:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:702 311dca44e7df40e0a0c2ece5cca045f3\nmsgid \"\"\n\"Allow addition of user-defined \\\"virtual\\\" vector graphics when finding \"\n\"tables.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:703 743195d5487f4c79b7dea4defa19efdb\nmsgid \"\"\n\"Confirm that the enveloping bboxes of vector graphics are inside the clip\"\n\" rectangle.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:704 91bcfe988eab4abe82d29ec6a73c24ac\nmsgid \"Avoid slow finding of rectangle intersections.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:706 6fbf98c2146642699598279e74ace969\nmsgid \"Added `Font.bbox` property.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:709 02dd1c5dc69346c3aa052addbe84f62d\nmsgid \"**Changes in version 1.23.18 (2024-01-23)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:713 e98e1fa4a6be43e19c1235f235206973\nmsgid \"\"\n\"**Fixed** `3081 <https://github.com/pymupdf/PyMuPDF/issues/3081>`_: \"\n\"doc.close() not closing the document\"\nmsgstr \"\"\n\n#: ../../../changes.txt:717 da8086b4179148e78eef2c50eb3cd527\nmsgid \"\"\n\"Reduced size of sdist to fit on pypi.org (by reducing size of two test \"\n\"files).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:718 0b7e1df1d1024f52810b0f1778d8d2de\nmsgid \"Fix `Annot.file_info()` if no `Desc` item.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:721 df117a0a6648402e8810ca3b417979b4\nmsgid \"**Changes in version 1.23.17 (2024-01-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:725 37f262e5ed6b4d118a5a82e4beb2b4ad\nmsgid \"\"\n\"**Fixed** `3062 <https://github.com/pymupdf/PyMuPDF/issues/3062>`_: \"\n\"page_rotation_reset does not return page to original rotation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:726 f86ef7904604429884e4c81fcf5ae787\nmsgid \"\"\n\"**Fixed** `3070 <https://github.com/pymupdf/PyMuPDF/issues/3070>`_: \"\n\"update_link(): AttributeError: 'Page' object has no attribute 'super'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:730 6c6a0371126c46b0bcc8ebc5df7be344\nmsgid \"Fixed bug in `Page.links()` (PR #3075).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:731 a9475e5785414f199b597f416d8e1f8d\nmsgid \"Fixed bug in `Page.get_bboxlog()` with layers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:732 8867fda0c26e4548b930e7d40da999bc\nmsgid \"Add support for timeouts in scripts/ and tests/run_compound.py.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:735 50f7599b93df4914acc301398f9fb589\nmsgid \"**Changes in version 1.23.16 (2024-01-18)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:739 98d0c677086e45b8aefb2561c344d108\nmsgid \"\"\n\"**Fixed** `3058 <https://github.com/pymupdf/PyMuPDF/issues/3058>`_: \"\n\"Pixmap created from CMYK JPEG delivers RGB format\"\nmsgstr \"\"\n\n#: ../../../changes.txt:743 6280e0fb16044307be72a98e78055199\nmsgid \"\"\n\"In table detection strategy \\\"lines_strict\\\", exclude fill-only vector \"\n\"graphics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:744 7b87c57e26184d6fab0bf49037ae0ee0\nmsgid \"Fixed sysinstall test failure.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:745 479fcf54b5cc40719b42543c6b8eb8d7\nmsgid \"In documentation, update feature matrix with item about text writing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:748 a58ed680108b456f811bd161fcda9c91\nmsgid \"**Changes in version 1.23.15 (2024-01-16)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:752 db43cbaa428745bbbc155e1449a46274\nmsgid \"\"\n\"**Fixed** `3050 <https://github.com/pymupdf/PyMuPDF/issues/3050>`_: \"\n\"python3.9 pix.set_pixel has something wrong in c.append( ord(i))\"\nmsgstr \"\"\n\n#: ../../../changes.txt:756 85116010a87b4782a3c2cf37d6d3c233\nmsgid \"Improved docs for Page.find_tables().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:759 a0e9d51dec614dd5aad7a32d5195c117\nmsgid \"**Changes in version 1.23.14 (2024-01-15)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:763 a147e66fe72c47f7ab10b2211f76dd3f\nmsgid \"\"\n\"**Fixed** `3038 <https://github.com/pymupdf/PyMuPDF/issues/3038>`_: \"\n\"JM_pixmap_from_display_list > Assertion Error : Checking for wrong type\"\nmsgstr \"\"\n\n#: ../../../changes.txt:764 8e99271499a243a0ad21780cd0aa3b4f\nmsgid \"\"\n\"**Fixed** `3039 <https://github.com/pymupdf/PyMuPDF/issues/3039>`_: Issue\"\n\" with doc.close() not closing the document in PyMuPDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:768 3976a531e434472590b8052395aea031\nmsgid \"\"\n\"Ensure valid \\\"re\\\" rectangles in `Page.get_drawings()` with derotated \"\n\"pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:771 082bdc523e1f473f85543e64d3853ad8\nmsgid \"**Changes in version 1.23.13 (2024-01-15)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:775 797a7ea0082844de9aa334285db2046a\nmsgid \"\"\n\"**Fixed** `2979 <https://github.com/pymupdf/PyMuPDF/issues/2979>`_: list \"\n\"index out of range in to_pandas()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:776 95667931dbcb4237bae8f4c9af83594b\nmsgid \"\"\n\"**Fixed** `3001 <https://github.com/pymupdf/PyMuPDF/issues/3001>`_: \"\n\"Calling find_tables() on one document alters the bounding boxes of a \"\n\"subsequent document\"\nmsgstr \"\"\n\n#: ../../../changes.txt:780 186cd9d07f9b4a58beb7e8e41f3bc17d\nmsgid \"Fixed `Rect.height` and `Rect.width` to never return negative values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:781 27c5d3626f094ec5863b809e2a812c25\nmsgid \"Fixed `TextPage.extractIMGINFO()`'s returned `dictkey_yres` value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:784 8255dfd1b9d149ba8ce261e1ceaff664\nmsgid \"**Changes in version 1.23.12 (2024-01-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:786 5bb9f57d3682407b99532c75233dba1f\nmsgid \"\"\n\"**Fixed** `3027 <https://github.com/pymupdf/PyMuPDF/issues/3027>`_: \"\n\"Page.get_text throws Attribute Error for 'parent'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:789 2dae2447cbb74e1fb8e1a42264ec7e70\nmsgid \"**Changes in version 1.23.11 (2024-01-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:791 cd671647a36347d9b8adbfb7ee2447a9\nmsgid \"Fixed some Pixmap construction bugs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:792 e891dfad684a4752b4e5805a6293dfcf\nmsgid \"Fixed Pixmap.yres().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:795 f131f3b1f3b641e989cfeab5425a3e9c\nmsgid \"**Changes in version 1.23.10 (2024-01-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:799 ac50349144d841ab902a3ae407ef8714\nmsgid \"\"\n\"**Fixed** `3020 <https://github.com/pymupdf/PyMuPDF/issues/3020>`_: Can't\"\n\" resize a PixMap\"\nmsgstr \"\"\n\n#: ../../../changes.txt:803 3f395fa335f948a6bf2ec8e7dca4ea01\nmsgid \"Fixed Page.delete_image().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:806 c60fab8d493747628cff1c624cb39043\nmsgid \"**Changes in version 1.23.9 (2024-01-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:808 1fa84ae4248d423485aa5cb183570533\nmsgid \"Default to new \\\"rebased\\\" implementation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:810 950a6848918d4d6b80203a0558ed5266\nmsgid \"\"\n\"The old \\\"classic\\\" implementation is available with `import fitz_old as \"\n\"fitz`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:811 bebd4b40a6314a9b99d384b13f921a74\nmsgid \"\"\n\"For more information about why we are changing to the rebased \"\n\"implementation, see: https://github.com/pymupdf/PyMuPDF/discussions/2680\"\nmsgstr \"\"\n\n#: ../../../changes.txt:814 0a613f5215304e7b922f3fbb0c54ad9c\nmsgid \"Use MuPDF-1.23.9.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:816 ../../../changes.txt:848\n#: 79b8f33e4c684085bbd12543c914a92c ed73712d903c42daa048538222480c72\nmsgid \"Bug fixes (rebased implementation only):\"\nmsgstr \"\"\n\n#: ../../../changes.txt:818 f0a68870dc7e4101b40fb65d25d18b5a\nmsgid \"\"\n\"**Fixed** `2911 <https://github.com/pymupdf/PyMuPDF/issues/2911>`_: \"\n\"Page.derotation_matrix returns a tuple instead of a Matrix with rebased \"\n\"implementation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:819 b056b928a27c4740bfc45a1e268ab0d2\nmsgid \"\"\n\"**Fixed** `2919 <https://github.com/pymupdf/PyMuPDF/issues/2919>`_: \"\n\"Rebased version: KeyError in resolve_names when merging pdfs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:820 736154fa84784e259b795c962116ed21\nmsgid \"\"\n\"**Fixed** `2922 <https://github.com/pymupdf/PyMuPDF/issues/2922>`_: New \"\n\"feature that allows inserting named-destination links doesn't work\"\nmsgstr \"\"\n\n#: ../../../changes.txt:821 bfe6879a0e3449928a0e143e35d1973d\nmsgid \"\"\n\"**Fixed** `2943 <https://github.com/pymupdf/PyMuPDF/issues/2943>`_: \"\n\"ZeroDivisionError: float division by zero when use apply_redactions()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:822 3aea2bcd6a984d8f8e814d25a05ea0cd\nmsgid \"\"\n\"**Fixed** `2950 <https://github.com/pymupdf/PyMuPDF/issues/2950>`_: \"\n\"Shelling out to pip during tests is problematic\"\nmsgstr \"\"\n\n#: ../../../changes.txt:823 64a074a99c094bf2b64bf0a1175cfd6e\nmsgid \"\"\n\"**Fixed** `2954 <https://github.com/pymupdf/PyMuPDF/issues/2954>`_: \"\n\"Replacement unicode character in text extraction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:824 f1ab1e9632c440a1ad3ddceab5970793\nmsgid \"\"\n\"**Fixed** `2957 <https://github.com/pymupdf/PyMuPDF/issues/2957>`_: \"\n\"apply_redactions() moving text\"\nmsgstr \"\"\n\n#: ../../../changes.txt:825 be824c3a45bd4be0b2bc52d892f31652\nmsgid \"\"\n\"**Fixed** `2961 <https://github.com/pymupdf/PyMuPDF/issues/2961>`_: \"\n\"Passing a string as a page number raises IndexError instead of TypeError.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:826 e776dd1532cf4e4b930371d30841afe9\nmsgid \"\"\n\"**Fixed** `2969 <https://github.com/pymupdf/PyMuPDF/issues/2969>`_: \"\n\"annot.next throws AttributeError\"\nmsgstr \"\"\n\n#: ../../../changes.txt:827 ac77c79a100942f8a6159beb24f4e67a\nmsgid \"\"\n\"**Fixed** `2978 <https://github.com/pymupdf/PyMuPDF/issues/2978>`_: \"\n\"1.23.9rc1: module 'fitz.mupdf' has no attribute 'fz_copy_pixmap_rect'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:829 362af45c412f45c39a1d822fab1286b1\nmsgid \"\"\n\"**Fixed** `2907 <https://github.com/pymupdf/PyMuPDF/issues/2907>`_: \"\n\"segfault trying to call clean_contents on certain pdfs with python 3.12\"\nmsgstr \"\"\n\n#: ../../../changes.txt:830 c1135c0939ef4daab6a8385631c53704\nmsgid \"\"\n\"**Fixed** `2905 <https://github.com/pymupdf/PyMuPDF/issues/2905>`_: \"\n\"SystemError: <built-in function TextPage_extractIMGINFO> returned a \"\n\"result with an exception set\"\nmsgstr \"\"\n\n#: ../../../changes.txt:831 a9d0e8515e0c4113af2e60251120838a\nmsgid \"\"\n\"**Fixed** `2742 <https://github.com/pymupdf/PyMuPDF/issues/2742>`_: \"\n\"Segmentation Fault when inserting three (but not two) copies of the same \"\n\"source page into one destination page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:835 bdbbaa0c597e4d8690d2acc01a05a511\nmsgid \"Add optional setting of opacity to `Page.insert_htmlbox()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:836 ec4580cff71a44b881bd2289b03e1e76\nmsgid \"Fixed issue with add_redact_annot() mentioned in #2934.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:837 37a7489f60b24988aabf68ab765c53aa\nmsgid \"\"\n\"Fixed `Page.rotation()` to return 0 for non-PDF documents instead of \"\n\"raising an exception.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:838 c15327390f2c412599adc9f6c2cd41eb\nmsgid \"Fixed internal quad detection to cope with any Python sequence.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:839 b5b25dcbb0e04533b6f266160078d7ac\nmsgid \"\"\n\"Fixed rebased `fitz.pymupdf_version_tuple` - was previously set to mupdf \"\n\"version.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:840 417b49c5b97a43b2884451f91a6ccd72\nmsgid \"\"\n\"Improved support for Linux system installs, including adding regular \"\n\"testing on Github.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:841 dc9b6649df764b6d8bdd0aeb241c8116\nmsgid \"Add missing `flake8` to `scripts/gh_release.py:test_packages`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:842 526255ea77784aa5a86322e409396fbf\nmsgid \"Use newly public functions in MuPDF-1.23.8.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:843 78af7dcf823d4333b745e1411e2535c0\nmsgid \"Improved `scripts/test.py` to help investigation of MuPDF issues.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:846 c4377b33474d4f08b8bb6ea1785e8cae\nmsgid \"**Changes in version 1.23.8 (2023-12-19)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:850 06bc7d28ba624f879fc3f4225f042ebd\nmsgid \"\"\n\"**Fixed** `2634 <https://github.com/pymupdf/PyMuPDF/issues/2634>`_: \"\n\"get_toc and set_toc do not behave consistently for rotated pages\"\nmsgstr \"\"\n\n#: ../../../changes.txt:851 eaabee50b85a41f5a1eee3082375a7d5\nmsgid \"\"\n\"**Fixed** `2861 <https://github.com/pymupdf/PyMuPDF/issues/2861>`_: \"\n\"AttributeError in getLinkDict during PDF Merge\"\nmsgstr \"\"\n\n#: ../../../changes.txt:852 11a45b3c36814980abef6db057685eef\nmsgid \"\"\n\"**Fixed** `2871 <https://github.com/pymupdf/PyMuPDF/issues/2871>`_: \"\n\"KeyError in getLinkDict during PDF merge\"\nmsgstr \"\"\n\n#: ../../../changes.txt:853 f6127a8b2c46475da27184f59e39e7ef\nmsgid \"\"\n\"**Fixed** `2886 <https://github.com/pymupdf/PyMuPDF/issues/2886>`_: Error\"\n\" in Skeleton for Named Link Destinations\"\nmsgstr \"\"\n\n#: ../../../changes.txt:855 ../../../changes.txt:888\n#: 586f106b986842b08028b0f5f627f7ca d8af7ffde72c450d915b0463309a4314\nmsgid \"Bug fixes (rebased and classic implementations):\"\nmsgstr \"\"\n\n#: ../../../changes.txt:857 b33ad6378a46458cb75ad39284db9641\nmsgid \"\"\n\"**Fixed** `2885 <https://github.com/pymupdf/PyMuPDF/issues/2885>`_: \"\n\"pymupdf find tables too slow\"\nmsgstr \"\"\n\n#: ../../../changes.txt:861 ../../../changes.txt:901\n#: 4728a8ecae8e40aa81aac714354f5cd8 dfafbc41ed064d4e9417228eef3b8869\nmsgid \"Rebased implementation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:863 d5e148c0135c420faee01c379333d863\nmsgid \"\"\n\"`Page.insert_htmlbox()`: new, much more powerful alternative to \"\n\"`Page.insert_textbox()` or `TextWriter.fill_textbox()`, using `Story`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:864 61b9573e3d5140e89cab3a5f2306ae99\nmsgid \"`Story.fit*()`: new methods for fitting a Story into an expanded rect.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:865 2c6161c5bc974598a30735ae4181b27c\nmsgid \"`Story.write_with_links()`: add support for external links.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:866 98b4230a54804ef4acb0b180f44e9ae5\nmsgid \"\"\n\"`Document.language()`: fixed to use MuPDF's new \"\n\"`mupdf.fz_string_from_text_language2()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:867 40995750950149ef83a0d8f6ddad76ef\nmsgid \"`Document.subset_fonts()` - fixed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:868 8f0552b58651471a97e511567a32e0c2\nmsgid \"Fixed internal `Archive._add_treeitem()` method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:869 87b1222b024441dea38cf29daba33184\nmsgid \"\"\n\"Fixed `fitz_new.__doc__` to contain PyMuPDF and Python version \"\n\"information, and OS name.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:870 386cb55b9f0c4087ae1996bb06b51a33\nmsgid \"\"\n\"Removed use of `(*args, **kwargs)` in API, we now specify keyword args \"\n\"explicitly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:871 c59b0cc5fecc4bdd9562cd2ce75075d3\nmsgid \"Work with new MuPDF Python exception classes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:873 e3e5a541241440ed9d367ef19430a835\nmsgid \"\"\n\"Fixed bug where `button_states()` returns None when `/AP` points to an \"\n\"indirect object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:874 5af1990cff754cd89a3aa438eb9d383b\nmsgid \"\"\n\"Fixed pillow test to not ignore all errors, and install pillow when \"\n\"testing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:875 1f1299ee32f346b6b3729cf40091e92c\nmsgid \"\"\n\"Added test for `fitz.css_for_pymupdf_font()` (uses package `pymupdf-\"\n\"fonts`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:876 8a8e3b21e7fe474598e60c7c3d327f5b\nmsgid \"Simplified Github Actions test specifications.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:877 285e6db854b84f7fab4a2c650152d2a2\nmsgid \"Updated `tests/README.md`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:880 25533a44e1824331b867fb200db45187\nmsgid \"**Changes in version 1.23.7 (2023-11-30)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:882 583b1de242bb4157b4445d6446ee6bbb\nmsgid \"Bug fixes in rebased implementation, not fixed in classic implementation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:884 235fe8226daa4b0abbac192cae7fd37a\nmsgid \"\"\n\"**Fixed** `2232 <https://github.com/pymupdf/PyMuPDF/issues/2232>`_: \"\n\"Geometry helper classes should support keyword arguments\"\nmsgstr \"\"\n\n#: ../../../changes.txt:885 e575834fcd73477b81b61829f22f495d\nmsgid \"\"\n\"**Fixed** `2788 <https://github.com/pymupdf/PyMuPDF/issues/2788>`_: \"\n\"Problem with get_toc in pymupdf 1.23.6\"\nmsgstr \"\"\n\n#: ../../../changes.txt:886 48886ca53b3d4f75bb21c99311bdb5f3\nmsgid \"\"\n\"**Fixed** `2791 <https://github.com/pymupdf/PyMuPDF/issues/2791>`_: \"\n\"Experiencing small memory leak in save()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:890 10a6b50400ed447497a29b25510f48e4\nmsgid \"\"\n\"**Fixed** `2736 <https://github.com/pymupdf/PyMuPDF/issues/2736>`_: \"\n\"Failure when set cropbox with mediabox negative value\"\nmsgstr \"\"\n\n#: ../../../changes.txt:891 2a0b37db8390439fbb646a9c37103f52\nmsgid \"\"\n\"**Fixed** `2749 <https://github.com/pymupdf/PyMuPDF/issues/2749>`_: \"\n\"RuntimeError: cycle in structure tree\"\nmsgstr \"\"\n\n#: ../../../changes.txt:892 3d06cf904a104c3d90b146fa78bf69ef\nmsgid \"\"\n\"**Fixed** `2753 <https://github.com/pymupdf/PyMuPDF/issues/2753>`_: \"\n\"Story.write_with_links will ignore everything after the first \\\"page \"\n\"break\\\" in the HTML.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:893 8a53b50ea2524665955b3157294a2b2d\nmsgid \"\"\n\"**Fixed** `2812 <https://github.com/pymupdf/PyMuPDF/issues/2812>`_: \"\n\"find_tables on landscape page generates reversed text\"\nmsgstr \"\"\n\n#: ../../../changes.txt:894 888fb15372974a36b1fe3d66ef22e391\nmsgid \"\"\n\"**Fixed** `2829 <https://github.com/pymupdf/PyMuPDF/issues/2829>`_: \"\n\"[cannot create /Annot for kind] is still printed despite #2345 is closed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:895 4bddd57842e24f349a1d201577c84f44\nmsgid \"\"\n\"**Fixed** `2841 <https://github.com/pymupdf/PyMuPDF/issues/2841>`_: \"\n\"Unexpected KeyError when using scrub with fitz_new\"\nmsgstr \"\"\n\n#: ../../../changes.txt:897 94aee473c47b4b39a4c3c4cb53567f41\nmsgid \"Use MuPDF-1.23.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:903 bec49d14f00548e4b548e3392c71e4f9\nmsgid \"Added flake8 code checking to test suite, and made various fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:904 5c2f03ef2da94a85b04bdcaa6b4452b2\nmsgid \"\"\n\"Disable diagnostics during Document constructor to match classic \"\n\"implementation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:906 614caa01606b4df1a5f36c79ba7597dc\nmsgid \"\"\n\"Additional fix to `2553 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/2553>`_: Invalid characters in\"\n\" versions >= 1.22\"\nmsgstr \"\"\n\n#: ../../../changes.txt:907 249c2e20b6584ff5bde073c96d14cef8\nmsgid \"\"\n\"Fixed `MuPDF Bug 707324 \"\n\"<https://bugs.ghostscript.com/show_bug.cgi?id=707324>`_: Story: HTML \"\n\"table row background color repeated incorrectly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:908 40274b78dadb4924955e4fcee62c82e9\nmsgid \"Added `scripts/test.py`, for simple build+test of PyMuPDF git checkout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:909 f4348c71af1f40479d9eb7d08fdba3aa\nmsgid \"Added `fitz.pymupdf_version_tuple`, e.g. `(1, 23, 6)`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:910 0125831c6ca04067b9605b86aefa7ebb\nmsgid \"\"\n\"Restored mistakenly-reverted fix for `2345 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/2345>`_: Turn off print \"\n\"statements in utils.py\"\nmsgstr \"\"\n\n#: ../../../changes.txt:911 ecf3f5029df1424ca67fedcd1eac52e1\nmsgid \"\"\n\"Include any trailing `... repeated <N> times...` text in warnings \"\n\"returned by `mupdf_warnings()` (rebased only).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:915 dae1fc58258f4a368eb9b9e73fdc3418\nmsgid \"**Changes in version 1.23.6 (2023-11-06)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:919 4b44a7b92e344051be42fcb7b2fd86ca\nmsgid \"\"\n\"**Fixed** `2553 <https://github.com/pymupdf/PyMuPDF/issues/2553>`_: \"\n\"Invalid characters in versions >= 1.22\"\nmsgstr \"\"\n\n#: ../../../changes.txt:920 c22c67eda878468e84fdce9860d9470e\nmsgid \"\"\n\"**Fixed** `2608 <https://github.com/pymupdf/PyMuPDF/issues/2608>`_: \"\n\"Incorrect utf32 text extraction (high & low surrogates are split)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:921 ../../../changes.txt:944\n#: 6e09bf78b2e8482189006eea2acba2bb 9836ec3981e942eab17d9cf2073f8760\nmsgid \"\"\n\"**Fixed** `2710 <https://github.com/pymupdf/PyMuPDF/issues/2710>`_: \"\n\"page.rect and text location wrong / differing from older version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:922 cf4d2d380bbc48eb852fc95710f97677\nmsgid \"\"\n\"**Fixed** `2774 <https://github.com/pymupdf/PyMuPDF/issues/2774>`_: wrong\"\n\" encoding for \\\"\\\\?\\\" character when sort=True\"\nmsgstr \"\"\n\n#: ../../../changes.txt:923 1f6c84f41d254543a72dc62354b851c3\nmsgid \"\"\n\"**Fixed** `2775 <https://github.com/pymupdf/PyMuPDF/issues/2775>`_: \"\n\"fitz_new does not work with python3.10 or earlier\"\nmsgstr \"\"\n\n#: ../../../changes.txt:924 87951ce6577046f9b2d94ccd7a8d15cf\nmsgid \"\"\n\"**Fixed** `2777 <https://github.com/pymupdf/PyMuPDF/issues/2777>`_: With \"\n\"fitz_new, wrong type for Page.mediabox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:928 8d946635456d4d35be553ed4ef5c4c20\nmsgid \"Use MuPDF-1.23.5.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:929 f7013808115244fc929c4e70b737e840\nmsgid \"Added Document.resolve_names() (rebased implementation only).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:932 fc23c2f02e0f4d6eaaf921039e93a96f\nmsgid \"**Changes in version 1.23.5 (2023-10-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:936 6009b9edb3184a869f2ce12fd73c20bd\nmsgid \"\"\n\"**Fixed** `2341 <https://github.com/pymupdf/PyMuPDF/issues/2341>`_: \"\n\"Handling negative values in the zoom section for LINK_GOTO in linkDest\"\nmsgstr \"\"\n\n#: ../../../changes.txt:937 0dd0674d2f134d99b73659b6f62b19a1\nmsgid \"\"\n\"**Fixed** `2522 <https://github.com/pymupdf/PyMuPDF/issues/2522>`_: Typo \"\n\"in set_layer() - NameError: name 'f' is not defined\"\nmsgstr \"\"\n\n#: ../../../changes.txt:938 c5288d50055d4c5da1a7e0df44a0ac43\nmsgid \"\"\n\"**Fixed** `2548 <https://github.com/pymupdf/PyMuPDF/issues/2548>`_: Fitz \"\n\"freezes on some PDFs when calling the fitz.Page.get_text_blocks method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:939 5ff84b8fb6be4feb8cdbf5edbbb0abaa\nmsgid \"\"\n\"**Fixed** `2596 <https://github.com/pymupdf/PyMuPDF/issues/2596>`_: \"\n\"save(garbage=3) breaks get_pixmap() with side effect\"\nmsgstr \"\"\n\n#: ../../../changes.txt:940 123cb55d916f49108937ed096e7ddb25\nmsgid \"\"\n\"**Fixed** `2635 <https://github.com/pymupdf/PyMuPDF/issues/2635>`_: \"\n\"\\\"clean=True\\\" makes objects invisible in the pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:941 ../../../changes.txt:969\n#: 7654b31ea4c84890bf69fa4688837d78 8eef4b86cdec4085ae3f96a960c2ce20\nmsgid \"\"\n\"**Fixed** `2637 <https://github.com/pymupdf/PyMuPDF/issues/2637>`_: \"\n\"Page.insert_textbox incorrectly handles the last word if it starts a new \"\n\"line\"\nmsgstr \"\"\n\n#: ../../../changes.txt:942 bcc1d82ed2934ae49084a16db226ddf1\nmsgid \"\"\n\"**Fixed** `2699 <https://github.com/pymupdf/PyMuPDF/issues/2699>`_: \"\n\"extract paragraph with below table\"\nmsgstr \"\"\n\n#: ../../../changes.txt:943 75014a04729c49dd8bc091fb9ba66444\nmsgid \"\"\n\"**Fixed** `2703 <https://github.com/pymupdf/PyMuPDF/issues/2703>`_: Wrong\"\n\" fontsize calculation in corner cases (\\\"page.get_texttrace()\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:945 f469c85d192646e5aab002778053d0a5\nmsgid \"\"\n\"**Fixed** `2723 <https://github.com/pymupdf/PyMuPDF/issues/2723>`_: When \"\n\"will a Python 3.12 wheel be available?\"\nmsgstr \"\"\n\n#: ../../../changes.txt:946 0fa82c24bbeb42d2be8390fbba927f0d\nmsgid \"\"\n\"**Fixed** `2730 <https://github.com/pymupdf/PyMuPDF/issues/2730>`_: \"\n\"persistent get_text() formatting\"\nmsgstr \"\"\n\n#: ../../../changes.txt:950 72690f1bf41e43bda38ccd424aacca3c\nmsgid \"Use MuPDF-1.23.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:951 30ff227bd04646bdb17474afeccd9981\nmsgid \"Fix optimisation flags with system installs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:952 6906912e05f34a26b46e5f8c0b9dd6e0\nmsgid \"\"\n\"Fixed the problem that the clip parameter does not take effect during \"\n\"table recognition\"\nmsgstr \"\"\n\n#: ../../../changes.txt:953 70a6a8cd8dcc4c90acf6957467999a4f\nmsgid \"Support Pillow mode \\\"RGBa\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:954 500cf538fcc84a5d88b63e846009e940\nmsgid \"Support extra word delimiters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:955 c5a98d3b81ca4f3b92ee9b55641041eb\nmsgid \"Support checking valid PDF name objects\"\nmsgstr \"\"\n\n#: ../../../changes.txt:958 9780d5d181924c1f98f6e987dee32f09\nmsgid \"**Changes in version 1.23.4 (2023-09-26)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:960 89f0cd5d2bdb4c2a86b8130279eaafbd\nmsgid \"Improved build instructions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:961 ba599b28412843c2b4970a1f78cfe599\nmsgid \"Fixed Tesseract in rebased implementation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:962 ad9696206b1147e8a6e75796ad68f204\nmsgid \"Improvements to build/install with system MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:964 0b8845dfb30c4a3ebf1bab255c2231f3\nmsgid \"Fixed rebased bug in _insert_image().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:968 0c9e490c29db4714af654a120396b8e6\nmsgid \"\"\n\"**Fixed** `2556 <https://github.com/pymupdf/PyMuPDF/issues/2556>`_: \"\n\"Segmentation fault at caling get_cdrawings(extended=True)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:970 b47698c2a99a4d67be8d09ea95ac3f34\nmsgid \"\"\n\"**Fixed** `2683 <https://github.com/pymupdf/PyMuPDF/issues/2683>`_: \"\n\"Windows sdist build failure - non-quoting of path and using UNIX which \"\n\"command\"\nmsgstr \"\"\n\n#: ../../../changes.txt:971 2e8eaa9c953340e3b7f9cab5aa9c144a\nmsgid \"\"\n\"**Fixed** `2691 <https://github.com/pymupdf/PyMuPDF/issues/2691>`_: \"\n\"Page.get_textpage_ocr() bug in rebased fitz_new version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:972 01bf199cda4f40eb80f58292500d052e\nmsgid \"\"\n\"**Fixed** `2692 <https://github.com/pymupdf/PyMuPDF/issues/2692>`_: \"\n\"Page.get_pixmap(clip=Rect()) bug in rebased fitz_new version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:975 e635ca7f3a7144c7b155a0d53f366bc4\nmsgid \"**Changes in version 1.23.3 (2023-08-31)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:977 b622f722651945db8c9065920951a027\nmsgid \"Fixed use of Tesseract for OCR.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:980 0b6d628f664246e1af3613f80ef88e31\nmsgid \"**Changes in version 1.23.2 (2023-08-28)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:982 5b021aef8d8846649ea00de593b61159\nmsgid \"\"\n\"**Fixed** `#2613 <https://github.com/pymupdf/PyMuPDF/issues/2613>`_: \"\n\"release 1.23.0 not MacOS-arm64 compatible\"\nmsgstr \"\"\n\n#: ../../../changes.txt:985 18a26e38b78544d8bed38a8639d031b2\nmsgid \"**Changes in version 1.23.1 (2023-08-24)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:987 e62a756953074ab996467e70681646a5\nmsgid \"Updated README and package summary description.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:990 a21901dee64f4a1899288f13aaebfd95\nmsgid \"\"\n\"Fixed a problem on some Linux installations with Python-3.10 (and \"\n\"possibly earlier versions) where `import fitz` failed with `ImportError: \"\n\"libcrypt.so.2: cannot open shared object file: No such file or \"\n\"directory`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:996 57b658dc047548bbbf4b37367da3eb2a\nmsgid \"Fixed `incompatible architecture` error on MacOS arm64.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:999 d42dcb0953b54804aee03e472206b6ee\nmsgid \"\"\n\"Fixed installation warning from Poetry about missing entry in wheels' \"\n\"RECORD files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1003 d3a8e8bb4f464faf90ac4e4f2d3d4257\nmsgid \"**Changes in version 1.23.0 (2023-08-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1005 73d894b0d405493fa197c028fc016e16\nmsgid \"Add method `find_tables()` to the `Page` object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1007 0381413ce0b8400e912c1027cc2af4d5\nmsgid \"\"\n\"This allows locating tables on any supported document page, and \"\n\"extracting table content by cell.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1010 7e8f7d58a9bc4339b09e0b5f9ac4ee2d\nmsgid \"New \\\"rebased\\\" implementation of PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1012 9fc6a3029b014900b58e9338c2babb18\nmsgid \"\"\n\"The rebased implementation is available as Python module `fitz_new`. It \"\n\"can be used as a drop-in replacement with `import fitz_new as fitz`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1017 738d34d7aebd43ff89c69b82aa7d46e8\nmsgid \"\"\n\"Python-independent MuPDF libraries are now in a second wheel called \"\n\"`PyMuPDFb` that will be automatically installed by pip.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1020 bca75d93dfe54dd0b930fe20a80af757\nmsgid \"\"\n\"This is to save space on pypi.org - a full release only needs one \"\n\"`PyMuPDFb` wheel for each OS.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1025 5ea8868d14804747b7a032703ca8e9b5\nmsgid \"\"\n\"**Fixed** `#2542 <https://github.com/pymupdf/PyMuPDF/issues/2542>`_: \"\n\"fitz.utils.scrub AttributeError Annot object has no attribute fileUpd \"\n\"inside\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1026 d834522e9a47458f8df14e8f629b6a80\nmsgid \"\"\n\"**Fixed** `#2533 <https://github.com/pymupdf/PyMuPDF/issues/2533>`_: \"\n\"get_texttrace returned a incorrect character bbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1027 fa9e61cc88804262a37529823e6ae230\nmsgid \"\"\n\"**Fixed** `#2537 <https://github.com/pymupdf/PyMuPDF/issues/2537>`_: \"\n\"Validation when setting a grouped RadioButton throws a RuntimeError: path\"\n\" to 'V' has indirects\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1029 ../../../changes.txt:1829\n#: ../../../changes.txt:1993 8bbac0324fdd4e349f9a5fa96e73089b\n#: eaf8cd2128cd4c5c877473f9bd315793 ec5d869f0874493ea625e47c43bf59f8\nmsgid \"Other changes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1031 038268fa0e3d4530b127e02b008b0de5\nmsgid \"Dropped support for Python-3.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1033 2f238ba63e474abd882d994c5d8a6c7d\nmsgid \"Fix for wrong page / annot `/Contents` cleaning.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1035 8de4c1abb94c4af0ae76a8bc208f2498\nmsgid \"We need to set `pdf_filter_options::no_update` to zero.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1037 3be90380c41041df9c0e8a4b1514f49a\nmsgid \"Added new function get_tessdata().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1039 e2dd7eb60faf45958693b36439454d65\nmsgid \"Cope with problem `/Annot` arrays.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1041 f3a9365058d14581b262aefd3dc3f5cd\nmsgid \"\"\n\"When copying page annotations in method Document.insert_pdf we previously\"\n\" did not check the validity of members of the `/Annots` array.  For \"\n\"faulty members (like null or non-dictionary items) this could cause \"\n\"unnecessary exceptions. This fix implements more checks and skips such \"\n\"array items.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1047 15b514dde25a435db2d8761712b2b511\nmsgid \"Additional annotation type checks.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1049 3d28a76d5772428ca847e78115435df5\nmsgid \"\"\n\"We did not previously check for annotation type when getting / setting \"\n\"annotation border properties. This is now checked in accordance with \"\n\"MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1053 1db4c46ee27f4603907a8be59ce434bd\nmsgid \"Increase fault tolerance.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1055 cfeadbde1d1a4bd28e4394f298039395\nmsgid \"\"\n\"Avoid exceptions in method `insert_pdf()` when source pages contains \"\n\"invalid items in the `/Annots` array.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1058 e95424ad171f4befacebac209026dccf\nmsgid \"Return empty border dict for applicable annots.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1060 d32e47da50ad4e1bbec4315e5deb475a\nmsgid \"\"\n\"We previously were returning a non-empty border dictionary even for non-\"\n\"applicable annotation types.  We now return the empty dictionary `{}` in \"\n\"these cases. This requires some corresponding changes in the annotation \"\n\"`.update()` method, namely for dashes and border width.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1065 a743fc735f8e4751aa4c9fb35972a0e6\nmsgid \"Restrict `set_rect` to applicable annot types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1067 33dd0a503f44425489708bfc1eba3781\nmsgid \"\"\n\"We were insufficiently excluding non-applicable annotation types from \"\n\"`set_rect()` method.  We now let MuPDF catch unsupported annotations and \"\n\"return `False` in these cases.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1071 3c981f3c14264a87a5e5864716eb590f\nmsgid \"Wrong fontsize computation in `page.get_texttrace()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1073 d2bca3e2d5044d88b32f20c0e92bf049\nmsgid \"\"\n\"When computing the font size we were using the final text transformation \"\n\"matrix, where we should have taken `span->trm` instead.  This is \"\n\"corrected here.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1077 4e4387c698a9431c875e14e61bfe5993\nmsgid \"Updates to cope with changes to latest MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1079 68949888709c441996bba638e370acdd\nmsgid \"`pdf_lookup_anchor()` has been removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1081 8e5efc45233c429083dbb2e7710b8e46\nmsgid \"Update fill_textbox to better respect rect.width\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1083 193ee81062494935a4b6e5f7a2d5d470\nmsgid \"\"\n\"The function norm_words in fill_textbox had a bug in its last loop, \"\n\"appending n+1 characters when actually measuring width of n characters.  \"\n\"It led to a bug in fill_texbox when you tried to write a single word \"\n\"mostly composed of \\\"wide\\\" letters (M,m, W, w...), causing the written \"\n\"text to exceed the given rect.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1089 6719947ef5ad4b44b30317c8cd0d27f0\nmsgid \"The fix was just to replace n+1 by n.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1091 a7647cf90c074ee7bf1e22c92b11aad2\nmsgid \"Add `script_focus` and `script_blur` options to widget.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1095 e7f3a5c65c2a4b4095652b5ee87ecf26\nmsgid \"**Changes in version 1.22.5 (2023-06-21)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1097 e0f897c4559d4185828a667deab0b5e1\nmsgid \"This release uses ``MuPDF-1.22.2``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1101 d01a2996634d4afd910a1b19f88fe54d\nmsgid \"\"\n\"**Fixed** `#2365 <https://github.com/pymupdf/PyMuPDF/issues/2365>`_: \"\n\"Incorrect dictionary values for type \\\"fs\\\" drawings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1102 37372904c5fc4a288d1bcfae3658be44\nmsgid \"\"\n\"**Fixed** `#2391 <https://github.com/pymupdf/PyMuPDF/issues/2391>`_: \"\n\"Check box automatically uncheck when we update same checkbox more than 1 \"\n\"times.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1103 da93bf73beab4c7394a870d6ef00aa74\nmsgid \"\"\n\"**Fixed** `#2400 <https://github.com/pymupdf/PyMuPDF/issues/2400>`_: Gaps\"\n\" within text of same line not filled with spaces.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1104 c7bbdcecf83d4af18820e8854d6ed2f7\nmsgid \"\"\n\"**Fixed** `#2404 <https://github.com/pymupdf/PyMuPDF/issues/2404>`_: \"\n\"Blacklining an image in PDF won't remove underlying content in version \"\n\"1.22.X.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1105 5dab0dae25104c5fac71c4bea81bd2ab\nmsgid \"\"\n\"**Fixed** `#2430 <https://github.com/pymupdf/PyMuPDF/issues/2430>`_: \"\n\"Incorrectly reducing ref count of Py_None.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1106 28dd826ad25d4fe989f269746f3f3beb\nmsgid \"\"\n\"**Fixed** `#2450 <https://github.com/pymupdf/PyMuPDF/issues/2450>`_: \"\n\"Empty fill color and fill opacity for paths with fill and stroke \"\n\"operations with 1.22.*\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1107 6eeb2a8ef825424fad2bdbac330da13d\nmsgid \"\"\n\"**Fixed** `#2462 <https://github.com/pymupdf/PyMuPDF/issues/2462>`_: \"\n\"Error at \\\"get_drawing(extended=True )\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1108 d83cacb33bfb43289ba1cac19694532b\nmsgid \"\"\n\"**Fixed** `#2468 <https://github.com/pymupdf/PyMuPDF/issues/2468>`_: \"\n\"Decode error when trying to get drawings\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1109 6816013f54d4446bb7b60530a6e49ad6\nmsgid \"\"\n\"**Fixed** `#2710 <https://github.com/pymupdf/PyMuPDF/issues/2710>`_: \"\n\"page.rect and text location wrong / differing from older version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1110 2a55b8aad74742ba905c8261e774e40e\nmsgid \"\"\n\"**Fixed** `#2723 <https://github.com/pymupdf/PyMuPDF/issues/2723>`_: When\"\n\" will a Python 3.12 wheel be available?\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1112 89917a32f35f46348baa0a3c330b174e\nmsgid \"New features:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1114 84e05da539e34fb1b20339210c836492\nmsgid \"\"\n\"**Changed** Annotations now support \\\"cloudy\\\" borders. The \"\n\":attr:`Annot.border` property has the new item `clouds`, and method \"\n\":meth:`Annot.set_border` supports the corresponding `clouds` argument.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1118 bce76d38c410446ba81647f0896ef355\nmsgid \"\"\n\"**Changed** Radio button widgets in the same RB group are now \"\n\"consistently updated **if the group is defined in the standard way**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1121 f53cb26ab76e43dfbbd2f4c2efc5a821\nmsgid \"\"\n\"**Added** Support for the `/Locked` key in PDF Optional Content. This \"\n\"array inside the catalog entry `/OCProperties` can now be extracted and \"\n\"set.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1124 def96ff824944143acfaffad2e689880\nmsgid \"\"\n\"**Added** Support for new parameter `tessdata` in OCR functions. New \"\n\"function :meth:`get_tessdata` locates the language support folder if \"\n\"Tesseract is installed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1129 ab43957ddc794c8a9b04c475426c4984\nmsgid \"**Changes in version 1.22.3 (2023-05-10)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1131 ../../../changes.txt:1140\n#: ../../../changes.txt:1149 ../../../changes.txt:1161\n#: 03ca33346d3944328c25a5c144420613 07f4c427f5f544f5bd7d767983484060\n#: 0fb05318e4944beeb5124143ee76589f d7e781b29559409897126ce3786cd3e7\nmsgid \"This release uses ``MuPDF-1.22.0``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1135 91c90d81ef504a9d8aeaffb101145d25\nmsgid \"\"\n\"**Fixed** `#2333 <https://github.com/pymupdf/PyMuPDF/issues/2333>`_: \"\n\"Unable to set any of button radio group in form\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1138 016b5d8017ec4b46aa0db0ca2575d91b\nmsgid \"**Changes in version 1.22.2 (2023-04-26)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1144 2a883f3384d24cb4b50c413be7b7248d\nmsgid \"\"\n\"**Fixed** `#2369 <https://github.com/pymupdf/PyMuPDF/issues/2369>`_: \"\n\"Image extraction bugs with newer versions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1147 558df7978ec349b98ce43b9afb00b02e\nmsgid \"**Changes in version 1.22.1 (2023-04-18)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1153 2f26d737893143a0b598c60bbf17e7c1\nmsgid \"\"\n\"**Fixed** `#2345 <https://github.com/pymupdf/PyMuPDF/issues/2345>`_: Turn\"\n\" off print statements in utils.py\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1154 88393d4c4b1c4de88301c4a0c889142a\nmsgid \"\"\n\"**Fixed** `#2348 <https://github.com/pymupdf/PyMuPDF/issues/2348>`_: \"\n\"extract_image returns an extension \\\"flate\\\" instead of \\\"png\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1155 a669f7b9c4be4a208b4f533e8f283873\nmsgid \"\"\n\"**Fixed** `#2350 <https://github.com/pymupdf/PyMuPDF/issues/2350>`_: Can \"\n\"not make widget (checkbox) to read-only by adding flags \"\n\"PDF_FIELD_IS_READ_ONLY\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1156 2b3bdc6748004a1aa84e2d6b31562785\nmsgid \"\"\n\"**Fixed** `#2355 <https://github.com/pymupdf/PyMuPDF/issues/2355>`_: \"\n\"1.22.0 error when using get_toc (AttributeError: 'SwigPyObject' object \"\n\"has no attribute)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1159 350bcb28a30944fdacb28843123738f2\nmsgid \"**Changes in version 1.22.0 (2023-04-14)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1163 44f570ec1df54e41a946bffb631b53c9\nmsgid \"Behavioural changes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1165 3826a16556c6458d8e1e603e51ffd973\nmsgid \"\"\n\"Text extraction now includes glyphs that overlap with clip rect; \"\n\"previously they were included only if they were entirely contained within\"\n\" the clip rect.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1171 3c30c3109974444198cf37e90e8ecabb\nmsgid \"\"\n\"**Fixed** `#1763 <https://github.com/pymupdf/PyMuPDF/issues/1763>`_: \"\n\"Interactive(smartform) form PDF calculation not working in pymupdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1172 af42fd504f0640239d81c483794b7e87\nmsgid \"\"\n\"**Fixed** `#1995 <https://github.com/pymupdf/PyMuPDF/issues/1995>`_: \"\n\"RuntimeError: image is too high for a long paged pdf file when trying\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1173 c1d1a1930cec45f3aeb64999517485da\nmsgid \"\"\n\"**Fixed** `#2093 <https://github.com/pymupdf/PyMuPDF/issues/2093>`_: \"\n\"Image in pdf changes color after applying redactions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1174 44f1654607db4a3a8bea70e0742f243f\nmsgid \"\"\n\"**Fixed** `#2108 <https://github.com/pymupdf/PyMuPDF/issues/2108>`_: \"\n\"Redaction removing more text than expected\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1175 13a17730caa849b68c2ae08ecb2ca4d8\nmsgid \"\"\n\"**Fixed** `#2141 <https://github.com/pymupdf/PyMuPDF/issues/2141>`_: \"\n\"Failed to read JPX header when trying to get blocks\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1176 59f63490e3084544a37ad382c51db86f\nmsgid \"\"\n\"**Fixed** `#2144 <https://github.com/pymupdf/PyMuPDF/issues/2144>`_: \"\n\"Replace image throws an error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1177 126c1e66cfb94388a6f083d43390e614\nmsgid \"\"\n\"**Fixed** `#2146 <https://github.com/pymupdf/PyMuPDF/issues/2146>`_: \"\n\"Wrong Handling of Reference Count of \\\"None\\\" Object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1178 c2df8c498e4c4870b10129059c78dc55\nmsgid \"\"\n\"**Fixed** `#2161 <https://github.com/pymupdf/PyMuPDF/issues/2161>`_: \"\n\"Support adding images as pages directly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1179 fa791f2adef34202b8f713657d47816f\nmsgid \"\"\n\"**Fixed** `#2168 <https://github.com/pymupdf/PyMuPDF/issues/2168>`_: \"\n\"``page.add_highlight_annot(start=pointa, stop=pointb)`` not working\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1180 e34fc762c8864c6db478c2a49d9e26ef\nmsgid \"\"\n\"**Fixed** `#2173 <https://github.com/pymupdf/PyMuPDF/issues/2173>`_: \"\n\"Double free of ``Colorspace`` used in ``Pixmap``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1181 18b7a0bf38a14b94a56b1ba2feea09b9\nmsgid \"\"\n\"**Fixed** `#2179 <https://github.com/pymupdf/PyMuPDF/issues/2179>`_: \"\n\"Incorrect documentation for ``pixmap.tint_with()``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1182 30fdc624e4da4b0da0d438177b35bb4d\nmsgid \"\"\n\"**Fixed** `#2208 <https://github.com/pymupdf/PyMuPDF/issues/2208>`_: \"\n\"Pushbutton widget appears as check box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1183 4d209898906843229670a95f12041360\nmsgid \"\"\n\"**Fixed** `#2210 <https://github.com/pymupdf/PyMuPDF/issues/2210>`_: \"\n\"``apply_redactions()`` move pdf text to right after redaction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1184 e6423ce2ee3e42cd842814a3ea98cae3\nmsgid \"\"\n\"**Fixed** `#2220 <https://github.com/pymupdf/PyMuPDF/issues/2220>`_: \"\n\"``Page.delete_image()`` | object has no attribute ``is_image``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1185 c6210c2a77804a929b68c35607fa6823\nmsgid \"\"\n\"**Fixed** `#2228 <https://github.com/pymupdf/PyMuPDF/issues/2228>`_: open\"\n\" some pdf cost too much time\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1186 b599a24386c74a8c913ae912d614557a\nmsgid \"\"\n\"**Fixed** `#2238 <https://github.com/pymupdf/PyMuPDF/issues/2238>`_: Bug \"\n\"- can not extract data from file in the newest version 1.21.1\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1187 b350fda19a5149f5848f62509b82c19a\nmsgid \"\"\n\"**Fixed** `#2242 <https://github.com/pymupdf/PyMuPDF/issues/2242>`_: \"\n\"Python quits silently in ``Story.element_positions()`` if callback \"\n\"function prototype is wrong\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1188 e6dc566181194da487883bc82530e4c5\nmsgid \"\"\n\"**Fixed** `#2246 <https://github.com/pymupdf/PyMuPDF/issues/2246>`_: \"\n\"TextWriter write text in a wrong position\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1189 3a1d2b5a77714081819e4147e4876ed9\nmsgid \"\"\n\"**Fixed** `#2248 <https://github.com/pymupdf/PyMuPDF/issues/2248>`_: \"\n\"After redacting the content, the position of the remaining text changes\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1190 be48ed21d0f44f6dba17fab6201c8b78\nmsgid \"\"\n\"**Fixed** `#2250 <https://github.com/pymupdf/PyMuPDF/issues/2250>`_: \"\n\"docs: unclear or broken link in page.rst\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1191 1f64252d8b684958a8360570bc1b540a\nmsgid \"\"\n\"**Fixed** `#2251 <https://github.com/pymupdf/PyMuPDF/issues/2251>`_: \"\n\"mupdf_display_errors does not apply to Pixmap when loading broken image\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1192 e8ac54952809456694e4b366c0992b6d\nmsgid \"\"\n\"**Fixed** `#2270 <https://github.com/pymupdf/PyMuPDF/issues/2270>`_: \"\n\"``Annot.get_text(\\\"words\\\")`` - doesn't return the first line of words\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1193 982ad8c99b6f4f739e357ee11cd3b514\nmsgid \"\"\n\"**Fixed** `#2275 <https://github.com/pymupdf/PyMuPDF/issues/2275>`_: \"\n\"insert_image: document that rotations are counterclockwise\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1194 eb8b181a15924a07abee72fea8a50ce9\nmsgid \"\"\n\"**Fixed** `#2278 <https://github.com/pymupdf/PyMuPDF/issues/2278>`_: Can \"\n\"not make widget (checkbox) to read-only by adding flags \"\n\"PDF_FIELD_IS_READ_ONLY\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1195 2dd5e761dcb94cde9a62d9e95e521f8a\nmsgid \"\"\n\"**Fixed** `#2290 <https://github.com/pymupdf/PyMuPDF/issues/2290>`_: \"\n\"Different image format/data from Page.get_text(\\\"dict\\\") and \"\n\"Fitz.get_page_images()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1196 b626d2a058c1457bb8fc7b175049d787\nmsgid \"\"\n\"**Fixed** `#2293 <https://github.com/pymupdf/PyMuPDF/issues/2293>`_: 68 \"\n\"failed tests when installing from sdist on my box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1197 c7c26b4cf78644b98a99810e21c743c5\nmsgid \"\"\n\"**Fixed** `#2300 <https://github.com/pymupdf/PyMuPDF/issues/2300>`_: Too \"\n\"much recursion in tree (parents), makes program terminate\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1198 53cf50d333db4541900b708daa262c2d\nmsgid \"\"\n\"**Fixed** `#2322 <https://github.com/pymupdf/PyMuPDF/issues/2322>`_: \"\n\"add_highlight_annot using clip generates \\\"A Number is Out of Range\\\" \"\n\"error in PDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1202 dc34fa0179bf4c0097c613d4e4d7cd5d\nmsgid \"\"\n\"Add key \\\"/AS (Yes)\\\" to the underlying annot object of a selected button\"\n\" form field.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1204 851dc87410c04af3811c1fce6e46d473\nmsgid \"\"\n\"Remove unused ``Document`` methods ``has_xref_streams()`` and \"\n\"``has_old_style_xrefs()`` as MuPDF equivalents have been removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1207 85d63fb357cc4ae6843661251e81671d\nmsgid \"\"\n\"Add new ``Document`` methods and properties for getting/setting \"\n\"``/PageMode``, ``/PageLayout`` and ``/MarkInfo``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1210 4692f2e3d07246f4b715a11b16c41826\nmsgid \"\"\n\"New ``Document`` property ``version_count``, which contains the number of\"\n\" incremental saves plus one.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1213 35dcac5f24064e0aa4e37ed607d7ee66\nmsgid \"\"\n\"New ``Document`` property ``is_fast_webaccess`` which tells whether the \"\n\"document is linearized.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1216 123a5e07f4e14c818cdcd4df6eb3afee\nmsgid \"``DocumentWriter`` is now a context manager.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1218 78db04ba2a9c48b7ad95cf5a7935dbd9\nmsgid \"Add support for ``Pixmap`` JPEG output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1220 75aea400570e4b6e9fec59457f4f883e\nmsgid \"Add support for drawing rectangles with rounded corners.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1222 8f7ef5836f6341ec93a07f437355992f\nmsgid \"``get_drawings()``: added optional ``extended`` arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1224 e60534dd491e4153a778b53b862c3666\nmsgid \"\"\n\"Fixed issue where trace devices' state was not being initialised \"\n\"correctly; data returned from things like ``fitz.Page.get_texttrace()`` \"\n\"might be slightly altered, e.g. ``linewidth`` values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1228 5ce1cdb70dd7438d9abe42cb5886dddc\nmsgid \"\"\n\"Output warning to ``stderr`` if it looks like we are being used with \"\n\"current directory containing an invalid ``fitz/`` directory, because this\"\n\" can break import of ``fitz`` module. For example this happens if one \"\n\"attempts to use ``fitz`` when current directory is a PyMuPDF checkout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1234 ../../../changes.txt:1289\n#: 349693fd237b4cbc8a22aa6cf3da10f1 8656870c12324ba69e9770b2a5f4fad6\nmsgid \"Documentation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1236 d223e4e942aa4b40ae6748f3f806de5d\nmsgid \"General rework:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1238 f085940fb9eb4248aa37862aa5ee511f\nmsgid \"Introduces a new home page and new table of contents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1239 7d45f07d7c9f45d085714f462f775464\nmsgid \"Structural update to include new About section.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1240 fbd4e460a3094b4e9f3cbe8bdb120960\nmsgid \"Comparison & performance graphing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1241 42f77bb0503d48488766f5fdb4d19c15\nmsgid \"Includes performance methodology in appendix.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1242 3bc9a3e24e0249a7a103014e58b0cfe0\nmsgid \"Updates conf.py to understand single back-ticks as code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1243 a3e9a116b3fb453fa81fe3081ca9ac28\nmsgid \"Converts double back-ticks to single back-ticks.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1244 dc12d40a4c6148f6b2c2740f969fe028\nmsgid \"Removes redundant files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1246 4b1314b91c0c4a57afc180019e7fcf7f\nmsgid \"Improve ``insert_file()`` documentation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1248 d4504863060147358071d6130ed1d42c\nmsgid \"``get_bboxlog()``: aded optional ``layers`` to ``get_bboxlog()``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1249 c11f7f0d2dab4b70968cca0abf587247\nmsgid \"\"\n\"``Page.get_texttrace()``: add new dictionary key ``layer``, name of \"\n\"Optional Content Group.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1251 202373f80f8d415a95fc9f1ab5c7f3c6\nmsgid \"Mention use of Python venv in installation documentation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1253 b7d408d9e1624b44b165a77a64070262\nmsgid \"Added missing fix for #2057 to release 1.21.1's changelog.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1255 e6cde05edeef4042a0657f838649a63c\nmsgid \"Fixes many links to the PyMuPDF-Utilities repo scripts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1257 038857900256474c9fded24cb273f8b5\nmsgid \"Avoid duplication of ``changes.txt`` and ``docs/changes.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1259 e343ebb10ae64a2baebc475af2998387\nmsgid \"Build\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1261 70564fcedaa2459bbccc68bc3d893e47\nmsgid \"Added ``pyproject.toml`` file to improve builds using pip etc.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1265 b1ea3fa1f44849439039e1a63d88a6e4\nmsgid \"**Changes in Version 1.21.1 (2022-12-13)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1267 92d79ae3bac04eae98a0a5093fe8273d\nmsgid \"This release uses ``MuPDF-1.21.1``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1271 3276e784b07a47648e6c6390b6cd3266\nmsgid \"\"\n\"**Fixed** `#2110 <https://github.com/pymupdf/PyMuPDF/issues/2110>`_: \"\n\"Fully embedded font is extracted only partially if it occupies more than \"\n\"one object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1272 950a39d02c9a4c8b8fa42d3ac1ac9e37\nmsgid \"\"\n\"**Fixed** `#2094 <https://github.com/pymupdf/PyMuPDF/issues/2094>`_: \"\n\"Rectangle Detection Logic\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1273 2f5a46c0803d4b5a9cbbacd71100b204\nmsgid \"\"\n\"**Fixed** `#2088 <https://github.com/pymupdf/PyMuPDF/issues/2088>`_: \"\n\"Destination point not set for named links in toc\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1274 97e2df4608364a7782f5c3a2e5b51f8d\nmsgid \"\"\n\"**Fixed** `#2087 <https://github.com/pymupdf/PyMuPDF/issues/2087>`_: \"\n\"Image with Filter \\\"[/FlateDecode/JPXDecode]\\\" not extracted\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1275 2168171e471542ada426f030b803e71d\nmsgid \"\"\n\"**Fixed** `#2086 <https://github.com/pymupdf/PyMuPDF/issues/2086>`_: \"\n\"Document.save() owner_pw & user_pw has buffer overflow bug\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1276 a23066f8e8654302b8b78db3816529c8\nmsgid \"\"\n\"**Fixed** `#2076 <https://github.com/pymupdf/PyMuPDF/issues/2076>`_: \"\n\"Segfault in fitz.py\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1277 13898161176b4a65990185478cb80a77\nmsgid \"\"\n\"**Fixed** `#2057 <https://github.com/pymupdf/PyMuPDF/issues/2057>`_: \"\n\"Document.save garbage parameter not working in PyMuPDF 1.21.0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1278 9d7d27f10c4946fd8036c536b9c192e1\nmsgid \"\"\n\"**Fixed** `#2051 <https://github.com/pymupdf/PyMuPDF/issues/2051>`_: \"\n\"Missing DPI Parameter\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1279 f53e894aea1048b0b6ea80c4ea26c7c5\nmsgid \"\"\n\"**Fixed** `#2048 <https://github.com/pymupdf/PyMuPDF/issues/2048>`_: \"\n\"Invalid size of TextPage and bbox with newest version 1.21.0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1280 f969ab18933245a593f97d97ee9ecbf6\nmsgid \"\"\n\"**Fixed** `#2045 <https://github.com/pymupdf/PyMuPDF/issues/2045>`_: \"\n\"SystemError: <built-in function Page_get_texttrace> returned a result \"\n\"with an error set\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1281 1f16bd21e2a8445d9592684ec7ecca51\nmsgid \"\"\n\"**Fixed** `#2039 <https://github.com/pymupdf/PyMuPDF/issues/2039>`_: \"\n\"1.21.0 fails to build against system libmupdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1282 3c45097d33ee470a9481317257d311f7\nmsgid \"\"\n\"**Fixed** `#2036 <https://github.com/pymupdf/PyMuPDF/issues/2036>`_: \"\n\"Archive::Archive defined twice\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1284 6533ecdf4d754fe7a4443b4a1b02bb72\nmsgid \"Other\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1286 9b576f8a8de143e3b3b9de9b6368ca18\nmsgid \"Swallow \\\"&zoom=nan\\\" in link uri strings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1287 f70b7dad981d4d249124939b4f1aaaee\nmsgid \"\"\n\"Add new Page utility methods ``Page.replace_image()`` and \"\n\"``Page.delete_image()``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1291 4f89ab38e60b43ea987d07e27961bb7d\nmsgid \"\"\n\"`#2040 <https://github.com/pymupdf/PyMuPDF/issues/2040>`_: Added note \"\n\"about test failure with non-default build of MuPDF, to \"\n\"``tests/README.md``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1292 558ff70ae6224480af3e735540cac2e3\nmsgid \"\"\n\"`#2037 <https://github.com/pymupdf/PyMuPDF/issues/2037>`_: In \"\n\"``docs/installation.rst``, mention incompatibility with chocolatey.org on\"\n\" Windows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1293 397d721cec884107af23df22baffdcb0\nmsgid \"\"\n\"`#2061 <https://github.com/pymupdf/PyMuPDF/issues/2061>`_: Fixed \"\n\"description of ``Annot.file_info``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1294 c6511b374b8b434caf2413b84c80813d\nmsgid \"\"\n\"`#2065 <https://github.com/pymupdf/PyMuPDF/issues/2065>`_: Show how to \"\n\"insert internal PDF link.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1295 6a5f0c4f501b4afd92cfe917137a0758\nmsgid \"Improved description of building from source without an sdist.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1296 67690117d7be41879e6fa66746eefeb1\nmsgid \"Added information about running tests.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1297 49b3f25fb63147c3b4c90a255b9ef648\nmsgid \"\"\n\"`#2084 <https://github.com/pymupdf/PyMuPDF/issues/2084>`_: Fixed broken \"\n\"link to PyMuPDF-Utilities.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1300 575f368bd94e401b9952c6d42b41700d\nmsgid \"**Changes in Version 1.21.0 (2022-11-8)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1302 673df835349745e7865e5b7f56344a60\nmsgid \"This release uses ``MuPDF-1.21.0``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1304 17bf58b166d24d168b6139c6e77d3a91\nmsgid \"New feature: Stories.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1306 a17fc35b1e5e48ab82510fb0a263af42\nmsgid \"Added wheels for Python-3.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1310 15df913e178e4f6781add4fa251aec7f\nmsgid \"\"\n\"**Fixed** `#1701 <https://github.com/pymupdf/PyMuPDF/issues/1701>`_: \"\n\"Broken custom image insertion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1311 2e7ca2e90f944214af8d8a773028ae37\nmsgid \"\"\n\"**Fixed** `#1854 <https://github.com/pymupdf/PyMuPDF/issues/1854>`_: \"\n\"`Document.delete_pages()` declines keyword arguments.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1312 346bb412bfad447b83a0e599f7336a01\nmsgid \"\"\n\"**Fixed** `#1868 <https://github.com/pymupdf/PyMuPDF/issues/1868>`_: \"\n\"Access Violation Error at `page.apply_redactions()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1313 9284226d16f4445cb9f22941a7e04dab\nmsgid \"\"\n\"**Fixed** `#1909 <https://github.com/pymupdf/PyMuPDF/issues/1909>`_: \"\n\"Adding text with `fontname=\\\"Helvetica\\\"` can silently fail.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1314 c11ff004104f4de1b6e767abc09ba8c4\nmsgid \"\"\n\"**Fixed** `#1913 <https://github.com/pymupdf/PyMuPDF/issues/1913>`_: \"\n\"`draw_rect()`: does not respect width if color is not specified.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1315 0f7b31ba423c48a185bae37f8c31c421\nmsgid \"\"\n\"**Fixed** `#1917 <https://github.com/pymupdf/PyMuPDF/issues/1917>`_: \"\n\"`subset_fonts()`: make it possible to silence the stdout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1316 a785e9b369404f42b2a872e50d17133b\nmsgid \"\"\n\"**Fixed** `#1936 <https://github.com/pymupdf/PyMuPDF/issues/1936>`_: \"\n\"Rectangle detection can be incorrect producing wrong output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1317 08fa2dec869748e4aa0d6b44cb796106\nmsgid \"\"\n\"**Fixed** `#1945 <https://github.com/pymupdf/PyMuPDF/issues/1945>`_: \"\n\"Segmentation fault when saving with `clean=True`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1318 3f1f9499ba9540f090c963df0a8cf1c2\nmsgid \"\"\n\"**Fixed** `#1965 <https://github.com/pymupdf/PyMuPDF/issues/1965>`_: \"\n\"`pdfocr_save()` Hard Crash.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1319 e675868f950a47b89b02bdec849ddfaf\nmsgid \"\"\n\"**Fixed** `#1971 <https://github.com/pymupdf/PyMuPDF/issues/1971>`_: \"\n\"Segmentation fault when using `get_drawings()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1320 9af37195cb0a40ef94d54604e449326c\nmsgid \"\"\n\"**Fixed** `#1946 <https://github.com/pymupdf/PyMuPDF/issues/1946>`_: \"\n\"`block_no` and `block_type` switched in `get_text()` docs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1321 cad632bb6e5347fdb160df1d5e205e7f\nmsgid \"\"\n\"**Fixed** `#2013 <https://github.com/pymupdf/PyMuPDF/issues/2013>`_: \"\n\"AttributeError: 'Widget' object has no attribute '_annot' in delete \"\n\"widget.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1323 c6abbf7c5af64afe8a6d1294f4458a5b\nmsgid \"Misc changes to core code:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1325 bcadf404caaf42199adda95adecf0183\nmsgid \"Fixed various compiler warnings and a sequence-point bug.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1326 1e7ac8c3fc184879954a671e241386ce\nmsgid \"Added support for Memento builds.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1327 2d4b0ca48cff409ab625548ad136c9dd\nmsgid \"Fixed leaks detected by Memento in test suite.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1328 eb361878f2a34aba8443b994d71d171a\nmsgid \"Fixed handling of exceptions in set_name() and set_rect().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1329 a57b2a7cb8ee4135a049aa057aa122ab\nmsgid \"Allow build with latest MuPDF, for regular testing of PyMuPDF master.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1330 94ed6dc32d87489980b579f7731e909a\nmsgid \"Cope with new MuPDF exceptions when setting rect for some Annot types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1331 0ddc8291d7994c71af6956edb68bd61f\nmsgid \"\"\n\"Reduced cosmetic differences between MuPDF's config.h and PyMuPDF's \"\n\"_config.h.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1332 ca97b466331943fbaf5357ca77d105ff\nmsgid \"Cope with various changes to MuPDF API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1336 ebefa94d051a413c87fa9a3656dcceda\nmsgid \"Fixed various broken links and typos in docs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1337 425cc8bc1fcf4fdaac66e442ee2e5513\nmsgid \"Mention install of `swig-python` on MacOS for #875.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1338 7073906d3d64408c836b7d3de96519aa\nmsgid \"Added (untested) wheels for macos-arm64.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1343 30436208e7954516bb195ab1ea1ed488\nmsgid \"**Changes in Version 1.20.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1345 ccf93339cf7245b2820d527e6e093f20\nmsgid \"This release uses ``MuPDF-1.20.3``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1347 e392d8912dbc4a8596ade19a8161d639\nmsgid \"\"\n\"**Fixed** `#1787 <https://github.com/pymupdf/PyMuPDF/issues/1787>`_. Fix \"\n\"linking issues on Unix systems.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1350 4d180eaf011b4a9fbb8c216aa4a505ec\nmsgid \"\"\n\"**Fixed** `#1824 <https://github.com/pymupdf/PyMuPDF/issues/1824>`_. \"\n\"SegFault when applying redactions overlapping a transparent image. (Fixed\"\n\" in ``MuPDF-1.20.3``.)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1354 6cb696c83bfc47bbb07c549f1a1f0267\nmsgid \"Improvements to documentation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1356 0ad4a7a79fe54f24869d872723b404e8\nmsgid \"\"\n\"Improved information about building from source in \"\n\"``docs/installation.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1357 81117814315f48efbc87955f9a7ef58d\nmsgid \"Clarified memory allocation setting ``JM_MEMORY` in ``docs/tools.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1358 b488d65744d743c4b1333dacf311664c\nmsgid \"Fixed link to PDF Reference manual in ``docs/app3.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1359 472c19e0e68c4c109bde0bb001020dac\nmsgid \"Fixed building of html documentation on OpenBSD.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1360 c99ee292bc6c46c686c3cad285701923\nmsgid \"Moved old ``docs/faq.rst`` into separate ``docs/recipes-*`` files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1362 5fed1f452c8f47549032bcab7853bdde\nmsgid \"Removed some unused files and directories:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1364 7c310414b4384898a324f2841f54decd\nmsgid \"``installation/``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1365 5e5ae4637cb640d19cd1b1a5305c90d8\nmsgid \"``docs/wheelnames.txt``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1368 f4d58a60a4f946a69ea863d1d7d30c62\nmsgid \"**Changes in Version 1.20.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1370 23e14128203842beadfff33baa6792ae\nmsgid \"\"\n\"**Fixed** `#1724 <https://github.com/pymupdf/PyMuPDF/issues/1724>`_. Fix \"\n\"for building on FreeBSD.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1373 ca0919e2a72b45eca23b6ffabb073f2d\nmsgid \"\"\n\"**Fixed** `#1771 <https://github.com/pymupdf/PyMuPDF/issues/1771>`_. \"\n\"`linkDest()` had a broken call to `re.match()`, introduced in 1.20.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1376 1acfe9e0464545878372d78884eac896\nmsgid \"\"\n\"**Fixed** `#1751 <https://github.com/pymupdf/PyMuPDF/issues/1751>`_. \"\n\"`get_drawings()` and `get_cdrawings()` previously always returned with \"\n\"`closePath=False`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1379 b1c751d4d6b249f7b1603c75f54e6948\nmsgid \"\"\n\"**Fixed** `#1645 <https://github.com/pymupdf/PyMuPDF/issues/1645>`_. \"\n\"Default FreeText annotation text color is now black.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1382 f7bb3767b4b546a8921290a547e0cf50\nmsgid \"Improvements to sphinx-generated documentation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1384 a5a5cb7bebe241279daf65c0700e6d10\nmsgid \"Use readthedocs theme with enhancements.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1385 d06c9bab26ef40449327e0f849c88152\nmsgid \"Renamed the `.txt` files to have `.rst` suffixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1389 7af006a5c3a84b03914bc4dcb23055ef\nmsgid \"**Changes in Version 1.20.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1391 c5bccf72f35e4edf807800d879e696ff\nmsgid \"This release uses ``MuPDF-1.20.0``, released 2022-06-15.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1393 68d1b02687f849fab3365ec98f0308d4\nmsgid \"\"\n\"Cope with new MuPDF link uri format, changed from ``#<int>,<int>,<int>`` \"\n\"to ``#page=<int>&zoom=<float>,<float>,<float>``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1395 d17d731c792044cfa0b4bc0486f4c5a8\nmsgid \"\"\n\"In ``tests/test_insertpdf.py``, use new reference output \"\n\"``joined-1.20.pdf``. We also check that new output values are \"\n\"approximately the same as the old ones.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1397 96cbfad0c6cb404db15d7aa8d13c5f65\nmsgid \"\"\n\"**Fixed** `#1738 <https://github.com/pymupdf/PyMuPDF/issues/1738>`_. Leak\"\n\" of `pdf_graft_map`. Also fixed a SEGV issue that this seemed to expose, \"\n\"caused by incorrect freeing of underlying fz_document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1400 a1460a0ec164432ebbe35656a0272c02\nmsgid \"\"\n\"**Fixed** `#1733 <https://github.com/pymupdf/PyMuPDF/issues/1733>`_. \"\n\"Fixed ownership of `Annotation.get_pixmap()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1402 1fb8672935f346f18177065d4a876d9b\nmsgid \"Changes to build/release process:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1404 d1f37ff28e754e3891af3658a6d2c4f7\nmsgid \"\"\n\"If pip builds from source because an appropriate wheel is not available, \"\n\"we no longer require MuPDF to be pre-installed. Instead the required \"\n\"MuPDF source is embedded in the sdist and automatically built into \"\n\"PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1406 c6743d7a837547bfbd14121f922f188b\nmsgid \"\"\n\"Various changes to ``setup.py`` to download the required MuPDF release as\"\n\" required. See comments at start of setup.py for details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1408 2deed3b348e44634a95976500ca61ff1\nmsgid \"\"\n\"Added ``.github/workflows/build_wheels.yml`` to control building of \"\n\"wheels on Github.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1412 bfd2558d12c24e4ba3c0aee0edff3507\nmsgid \"**Changes in Version 1.19.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1414 e9b569d9e70b42518f53a71536bd4f28\nmsgid \"\"\n\"**Fixed** `#1620 <https://github.com/pymupdf/PyMuPDF/issues/1620>`_. The \"\n\":ref:`TextPage` created by :meth:`Page.get_textpage` will now be freed \"\n\"correctly (removed memory leak).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1415 058f760c8ce740e48a627eb2aee78a56\nmsgid \"\"\n\"**Fixed** `#1601 <https://github.com/pymupdf/PyMuPDF/issues/1601>`_. \"\n\"Document open errors should now be more concise and easier to interpret. \"\n\"In the course of this, two PyMuPDF-specific Python exceptions have been \"\n\"**added:**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1417 15ef5b12f13b4750a9571bf258d1dd43\nmsgid \"\"\n\"``EmptyFileError`` -- raised when trying to create a :ref:`Document` \"\n\"(``fitz.open()``) from an empty file or zero-length memory.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1418 f1c391fa54a1405ba4a28d352d108404\nmsgid \"\"\n\"``FileDataError`` -- raised when MuPDF encounters irrecoverable document \"\n\"structure issues.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1420 56b2878654114138ac79fad54cecad1b\nmsgid \"**Added** :meth:`Page.load_widget` given a PDF field's xref.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1422 c0ece2db951a48efac1849cd7074f28e\nmsgid \"\"\n\"**Added** Dictionary :attr:`pdfcolor` which provide the about 500 colors \"\n\"defined as PDF color values with the lower case color name as key.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1424 f9628cc364244bf3a41e4b3a8c2d40c6\nmsgid \"\"\n\"**Added** algebra functionality to the :ref:`Quad` class. These objects \"\n\"can now also be added and subtracted among themselves, and be multiplied \"\n\"by numbers and matrices.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1426 b66574a55e8d41d7accf7dd33f070642\nmsgid \"\"\n\"**Added** new constants defining the default text extraction flags for \"\n\"more comfortable handling. Their naming convention is like \"\n\":data:`TEXTFLAGS_WORDS` for ``page.get_text(\\\"words\\\")``. See \"\n\":ref:`text_extraction_flags`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1428 8f6f15bc876b4df68cda93624b20a4ea\nmsgid \"\"\n\"**Changed** :meth:`Page.annots` and :meth:`Page.widgets` to detect and \"\n\"prevent reloading the page (illegally) inside the iterator loops via \"\n\":meth:`Document.reload_page`. Doing this brings down the interpretor. \"\n\"Documented clean ways to do annotation and widget mass updates within \"\n\"properly designed loops.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1430 287feb6044a2402d9651e9690ee78512\nmsgid \"\"\n\"**Changed** several internal utility functions to become standalone \"\n\"(\\\"SWIG inline\\\") as opposed to be part of the :ref:`Tools` class. This, \"\n\"among other things, increases the performance of geometry object \"\n\"creation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1432 ec2b054b07e449debcbc15b510c35e5e\nmsgid \"\"\n\"**Changed** :meth:`Document.update_stream` to always accept stream \"\n\"updates - whether or not the dictionary object behind the xref already is\"\n\" a stream. Thus the former ``new`` parameter is now ignored and will be \"\n\"removed in v1.20.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1437 89534acd0d50489793f84d93defb75d9\nmsgid \"**Changes in Version 1.19.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1439 15c312e55ff84d4990200b73b5ab7088\nmsgid \"\"\n\"**Fixed** `#1518 <https://github.com/pymupdf/PyMuPDF/issues/1518>`_. A \"\n\"limited \\\"fix\\\": in some cases, rectangles and quadrupels were not \"\n\"correctly encoded to support re-drawing by :ref:`Shape`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1441 4ba09954c0b641a2926f1026d979da09\nmsgid \"\"\n\"**Fixed** `#1521 <https://github.com/pymupdf/PyMuPDF/issues/1521>`_. This\"\n\" had the same ultimate reason behind issue #1510.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1443 dde5fa3810eb4a82b0aa2e61d8cf863b\nmsgid \"\"\n\"**Fixed** `#1513 <https://github.com/pymupdf/PyMuPDF/issues/1513>`_. Some\"\n\" Optional Content functions did not support non-ASCII characters.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1445 3d2e4740ec0b41b4aaad51d97655f8e9\nmsgid \"\"\n\"**Fixed** `#1510 <https://github.com/pymupdf/PyMuPDF/issues/1510>`_. \"\n\"Support more soft-mask image subtypes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1447 e79ebb09f5ea405a8ed23fbed6aa913a\nmsgid \"\"\n\"**Fixed** `#1507 <https://github.com/pymupdf/PyMuPDF/issues/1507>`_. \"\n\"Immunize against items in the outlines chain, that are ``\\\"null\\\"`` \"\n\"objects.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1449 cd737a2d921f4ee6929d54d756b3ca78\nmsgid \"\"\n\"**Fixed** re-opened `#1417 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1417>`_. (\\\"too many open \"\n\"files\\\"). This was due to insufficient calls to MuPDF's \"\n\"``fz_drop_document()``. This also fixes `#1550 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1550>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1451 10995303e588406895c48eaa98334bdd\nmsgid \"\"\n\"**Fixed** several undocumented issues in relation to incorrectly setting \"\n\"the text span origin :data:`point_like`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1453 c395df4c98a441958d507eaf1a55d6de\nmsgid \"\"\n\"**Fixed** undocumented error computing the character bbox in method \"\n\":meth:`Page.get_texttrace` when text is **flipped** (as opposed to just \"\n\"rotated).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1455 d82b9d2a17b64ddb90e236a9e42f1420\nmsgid \"\"\n\"**Added** items to the dictionary returned by :meth:`image_properties`: \"\n\"``orientation`` and ``transform`` report the natural image orientation \"\n\"(EXIF data).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1457 30117ed837094556807bb67193004816\nmsgid \"\"\n\"**Added** method :meth:`Document.xref_copy`. It will make a given target \"\n\"PDF object an exact copy of a source object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1462 c6cda05060f04f1080faf3f5125286a2\nmsgid \"**Changes in Version 1.19.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1465 b2517533bd4f4096af88ca08d40edf65\nmsgid \"\"\n\"**Fixed** `#1505 <https://github.com/pymupdf/PyMuPDF/issues/1505>`_. \"\n\"Immunize against circular outline items.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1467 a0d1479b30084068bad49749240fac45\nmsgid \"\"\n\"**Fixed** `#1484 <https://github.com/pymupdf/PyMuPDF/issues/1484>`_. \"\n\"Correct CropBox coordinates are now returned in all situations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1469 cf4a7ec57222449f974ef9027151cf36\nmsgid \"**Fixed** `#1479 <https://github.com/pymupdf/PyMuPDF/issues/1479>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1471 89d3111a652d4fe8809050d5c921e6ea\nmsgid \"\"\n\"**Fixed** `#1474 <https://github.com/pymupdf/PyMuPDF/issues/1474>`_. \"\n\"TextPage objects are now properly deleted again.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1473 ae6c28903fab4ede991daa53cbb1c7b1\nmsgid \"\"\n\"**Added** :ref:`Page` methods and attributes for PDF ``/ArtBox``, \"\n\"``/BleedBox``, ``/TrimBox``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1475 d88880cbc50841bfa7c2c78158e9dd46\nmsgid \"\"\n\"**Added** global attribute :attr:`TESSDATA_PREFIX` for easy checking of \"\n\"OCR support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1477 2be427b5e13c407995bd4f89c694dada\nmsgid \"\"\n\"**Changed** :meth:`Document.xref_set_key` such that dictionary keys will \"\n\"physically be removed if set to value ``\\\"null\\\"``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1479 2a9573afceb049e6b671e0432bd529be\nmsgid \"\"\n\"**Changed** :meth:`Document.extract_font` to optionally return a \"\n\"dictionary (instead of a tuple).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1483 4f57093fd45345639ada517bdde872fb\nmsgid \"**Changes in Version 1.19.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1485 18dfed128cbf40c38cad3ea42fd28a79\nmsgid \"\"\n\"This patch version implements minor improvements for :ref:`Pixmap` and \"\n\"also some important fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1487 1296ee8815a942b6b05e865c50765b3b\nmsgid \"\"\n\"**Fixed** `#1351 <https://github.com/pymupdf/PyMuPDF/discussions/1351>`_.\"\n\" Reverted code that introduced the memory growth in v1.18.15.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1489 3fb4097c0d9c45d884b47f003b15344b\nmsgid \"\"\n\"**Fixed** `#1417 <https://github.com/pymupdf/PyMuPDF/discussions/1417>`_.\"\n\" Developped circumvention for growth of open file handles using \"\n\":meth:`Document.insert_pdf`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1491 770e6646f6e74afcb2d4d3dcf9c81366\nmsgid \"\"\n\"**Fixed** `#1418 <https://github.com/pymupdf/PyMuPDF/discussions/1418>`_.\"\n\" Developped circumvention for memory growth using \"\n\":meth:`Document.insert_pdf`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1493 9689f4e9544c4246b896448b2322a17e\nmsgid \"\"\n\"**Fixed** `#1430 <https://github.com/pymupdf/PyMuPDF/discussions/1430>`_.\"\n\" Developped circumvention for mass pixmap generations of document pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1495 056b81d61e89402fb676e8fa87a24efc\nmsgid \"\"\n\"**Fixed** `#1433 <https://github.com/pymupdf/PyMuPDF/discussions/1433>`_.\"\n\" Solves a bbox error for some Type 3 font in PyMuPDF text processing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1497 d99a708337c94a539ed17294cc959f0d\nmsgid \"\"\n\"**Added** :meth:`Pixmap.color_topusage` to determine the share of the \"\n\"most frequently used color. Solves `#1397 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1397>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1499 72e87358c82b4604b24eac87ac4b4a0f\nmsgid \"\"\n\"**Added** :meth:`Pixmap.warp` which makes a new pixmap from a given \"\n\"arbitrary convex quad inside the pixmap.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1501 82fcb8b930d84658abdd8396247c78de\nmsgid \"\"\n\"**Added** :attr:`Annot.irt_xref` and :meth:`Annot.set_irt_xref` to \"\n\"inquire or set the `/IRT` (\\\"In Responde To\\\") property of an annotation.\"\n\" Implements `#1450 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1450>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1503 9d4d189ab5d14fb799a720844599254d\nmsgid \"\"\n\"**Added** :meth:`Rect.torect` and :meth:`IRect.torect` which compute a \"\n\"matrix that transforms to a given other rectangle.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1505 4efbe89603de46a59e1fac42a1a66f6a\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.color_count` to also return the count of each \"\n\"color.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1506 d98f12929cce4021be5db663b7606192\nmsgid \"\"\n\"**Changed** :meth:`Page.get_texttrace` to also return correct span and \"\n\"character bboxes if ``span[\\\"dir\\\"] != (1, 0)``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1510 d093ad5f399047259588e551285fd994\nmsgid \"**Changes in Version 1.19.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1512 2de7c1c23ba441aa92a089ee02a4635b\nmsgid \"\"\n\"This patch version implements minor improvements for \"\n\":meth:`Page.get_drawings` and also some important fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1514 79ddabf469564139b54099c248dbd2b3\nmsgid \"\"\n\"**Fixed** `#1388 <https://github.com/pymupdf/PyMuPDF/discussions/1388>`_.\"\n\" Fixed intermittent memory corruption when insert or updating \"\n\"annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1516 3f76bb3657c5462ba1ebcdd58bdd3116\nmsgid \"\"\n\"**Fixed** `#1375 <https://github.com/pymupdf/PyMuPDF/discussions/1375>`_.\"\n\" Inconsistencies between line numbers as returned by the \\\"words\\\" and \"\n\"the \\\"dict\\\" options of :meth:`Page.get_text` have been corrected.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1518 da3c5e5c691b4bf89bac0ae41797880b\nmsgid \"\"\n\"**Fixed** `#1364 <https://github.com/pymupdf/PyMuPDF/issues/1342>`_. The \"\n\"check for being a ``\\\"rawdict\\\"`` span in :meth:`recover_span_quad` now \"\n\"works correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1520 63807063fb894a7e983829cafe298fe5\nmsgid \"\"\n\"**Fixed** `#1342 <https://github.com/pymupdf/PyMuPDF/issues/1364>`_. \"\n\"Corrected the check for rectangle infiniteness in \"\n\":meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1522 517a112dc4114acab7f4f5c1b91d6fa8\nmsgid \"\"\n\"**Changed** :meth:`Page.get_drawings`, :meth:`Page.get_cdrawings` to \"\n\"return an indicator on the area orientation covered by a rectangle. This \"\n\"implements `#1355 <https://github.com/pymupdf/PyMuPDF/issues/1355>`_. \"\n\"Also, the recognition rate for rectangles and quads has been \"\n\"significantly improved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1524 dcddfb46c54741fd8eda15a642648605\nmsgid \"\"\n\"**Changed** all text search and extraction methods to set the new \"\n\"``flags`` option ``TEXT_MEDIABOX_CLIP`` to ON by default. That bit causes\"\n\" the automatic suppression of all characters that are completely outside \"\n\"a page's mediabox (in as far as that notion is supported for a document \"\n\"type). This eliminates the need for using ``clip=page.rect`` or similar \"\n\"for omitting text outside the visible area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1526 f1b34d7957c44c178eece4e7a6585117\nmsgid \"\"\n\"**Added** parameter ``\\\"dpi\\\"`` to :meth:`Page.get_pixmap` and \"\n\":meth:`Annot.get_pixmap`. When given, parameter ``\\\"matrix\\\"`` is \"\n\"ignored, and a :ref:`Pixmap` with the desired dots per inch is created.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1528 1317c20bf9004475b5d9e6eff7531e6d\nmsgid \"\"\n\"**Added** attributes :attr:`Pixmap.is_monochrome` and \"\n\":attr:`Pixmap.is_unicolor` allowing fast checks of pixmap properties. \"\n\"Addresses `#1397 <https://github.com/pymupdf/PyMuPDF/discussions/1397>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1530 2f34d297248a424d9e4bd6390d4abd59\nmsgid \"\"\n\"**Added** method :meth:`Pixmap.color_count` to determine the unique \"\n\"colors in the pixmap.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1532 0eb08456d2ad4e70b01c79a2c2394012\nmsgid \"\"\n\"**Added** boolean parameter ``\\\"compress\\\"`` to PDF document method \"\n\":meth:`Document.update_stream`. Addresses / enables solution for `#1408 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1408>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1536 e801177ed48145dda1d2c1383f2b0ffc\nmsgid \"**Changes in Version 1.19.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1538 57c5fb9887f847ba933543ad12d8a479\nmsgid \"\"\n\"This is the first patch version to support MuPDF v1.19.0. Apart from one \"\n\"bug fix, it includes important improvements for OCR support and the \"\n\"option to **sort extracted text** to the standard reading order \\\"from \"\n\"top-left to bottom-right\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1540 650b810759ce426fb04200ced720f29f\nmsgid \"\"\n\"**Fixed** `#1328 <https://github.com/pymupdf/PyMuPDF/issues/1328>`_. \"\n\"\\\"words\\\" text extraction again returns correct ``(x0, y0)`` coordinates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1542 3ba1314a889d44d78998ee7e4000e490\nmsgid \"\"\n\"**Changed** :meth:`Page.get_textpage_ocr`: it now supports parameter \"\n\"``dpi`` to control OCR quality. It is also possible to choose whether the\"\n\" **full page** should be OCRed or **only the images displayed** by the \"\n\"page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1544 e63faaa903ec48a596466ba7c81be36a\nmsgid \"\"\n\"**Changed** :meth:`Page.get_drawings` and :meth:`Page.get_cdrawings` to \"\n\"automatically convert colors to RGB color tuples. Implements `#1332 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1332>`_. Similar change \"\n\"was applied to :meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1546 478ae75188fb496dbd68e612249a93be\nmsgid \"\"\n\"**Changed** :meth:`Page.get_text` to support a parameter ``sort``. If set\"\n\" to ``True`` the output is conveniently sorted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1551 1fcee4618b1a4606bc1bb1cb00a3c04c\nmsgid \"**Changes in Version 1.19.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1553 ddc73ab2354e49519073ae9c706da26e\nmsgid \"\"\n\"This is the first version supporting MuPDF 1.19.*, published 2021-10-05. \"\n\"It introduces many new features compared to the previous version 1.18.*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1555 b350897b3a7d4af6a0a1184d0161e9f5\nmsgid \"\"\n\"PyMuPDF has now picked up integrated Tesseract OCR support, which was \"\n\"already present in MuPDF v1.18.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1557 35dd462d0329459bb8788ee6118ce5b5\nmsgid \"\"\n\"Supported images can be OCRed via their :ref:`Pixmap` which results in a \"\n\"1-page PDF with a text layer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1558 40eb6a6a0deb477f802cfaa332cd816d\nmsgid \"\"\n\"All supported document pages (i.e. not only PDFs), can be OCRed using \"\n\"specialized text extraction methods. The result is a mixture of standard \"\n\"and OCR text (depending on which part of the page was deemed to require \"\n\"OCRing) that can be searched and extracted without restrictions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1559 734f1859407e4513b2cad5b0b02ac6f4\nmsgid \"\"\n\"All this requires an independent installation of Tesseract. MuPDF \"\n\"actually (only) needs the location of Tesseract's ``\\\"tessdata\\\"`` \"\n\"folder, where its language support data are stored. This location must be\"\n\" available as environment variable ``TESSDATA_PREFIX``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1561 b0bd5ab69f33429697fd89f94ea87403\nmsgid \"\"\n\"A new MuPDF feature is **journalling PDF updates**, which is also \"\n\"supported by this PyMuPDF version. Changes may be logged, rolled back or \"\n\"replayed, allowing to implement a whole new level of control over PDF \"\n\"document integrity -- similar to functions present in modern database \"\n\"systems.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1563 c3bc9664f319416cbfbd764f183ecaf1\nmsgid \"\"\n\"A third feature (unrelated to the new MuPDF version) includes the ability\"\n\" to detect when page **objects cover or hide each other**. It is now e.g.\"\n\" possible to see that text is covered by a drawing or an image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1565 368ec08cb31e489e94e2d8a7e4ee86e4\nmsgid \"\"\n\"**Changed** terminology and meaning of important geometry concepts: \"\n\"Rectangles are now characterized as *finite*, *valid* or *empty*, while \"\n\"the definitions of these terms have also changed. Rectangles specifically\"\n\" are now thought of being \\\"open\\\": not all corners and sides are \"\n\"considered part of the retangle. Please do read the :ref:`Rect` section \"\n\"for details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1567 6dd7d23a06ad4f14b2021126e1286e49\nmsgid \"\"\n\"**Added** new parameter `\\\"no_new_id\\\"` to :meth:`Document.save` / \"\n\":meth:`Document.tobytes` methods. Use it to suppress updating the second \"\n\"item of the document ``/ID`` which in PDF indicates that the original \"\n\"file has been updated. If the PDF has no ``/ID`` at all yet, then no new \"\n\"one will be created either.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1569 de9906d677934e3c8dbe4a106dce7c74\nmsgid \"\"\n\"**Added** a **journalling facility** for PDF updates. This allows logging\"\n\" changes, undoing or redoing them, or saving the journal for later use. \"\n\"Refer to :meth:`Document.journal_enable` and friends.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1571 c4160924dc184c4b927a1b6297223458\nmsgid \"\"\n\"**Added** new :ref:`Pixmap` methods :meth:`Pixmap.pdfocr_save` and \"\n\":meth:`Pixmap.pdfocr_tobytes`, which generate a 1-page PDF containing the\"\n\" pixmap as PNG image with OCR text layer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1573 0e3c62d627264d9f8ffce673e0023b81\nmsgid \"\"\n\"**Added** :meth:`Page.get_textpage_ocr` which executes optical character \"\n\"recognition for the page, then extracts the results and stores them \"\n\"together with \\\"normal\\\" page content in a :ref:`TextPage`. Use or reuse \"\n\"this object in subsequent text extractions and text searches to avoid \"\n\"multiple efforts. The existing text search and text extraction methods \"\n\"have been extended to support a separately created textpage -- see next \"\n\"item.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1575 04ef1d300161437ba5b4e28ffed12386\nmsgid \"\"\n\"**Added** a new parameter ``textpage`` to text extraction and text search\"\n\" methods. This allows reuse of a previously created :ref:`TextPage` and \"\n\"thus achieves significant runtime benefits -- which is especially \"\n\"important for the new OCR features. But \\\"normal\\\" text extractions can \"\n\"definitely also benefit.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1577 a6d0664ee9d14b07908e08d426ef50e7\nmsgid \"\"\n\"**Added** :meth:`Page.get_texttrace`, a technical method delivering low-\"\n\"level text character properties. It was present before as a private \"\n\"method, but the author felt it now is mature enough to be officially \"\n\"available. It specifically includes a \\\"sequence number\\\" which indicates\"\n\" the page appearance build operation that painted the text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1579 ccb6adfad05549ff96a7d75a2f08de75\nmsgid \"\"\n\"**Added** :meth:`Page.get_bboxlog` which delivers the list of rectangles \"\n\"of page objects like text, images or drawings. Its significance lies in \"\n\"its sequence: rectangles intersecting areas with a lower index are \"\n\"covering or hiding them.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1581 3edfcd55b842410ab082ab50b80e132f\nmsgid \"\"\n\"**Changed** methods :meth:`Page.get_drawings` and \"\n\":meth:`Page.get_cdrawings` to include a \\\"sequence number\\\" indicating \"\n\"the page appearance build operation that created the drawing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1583 d4fd7415a1f44eb0b738d6f5df0af7cb\nmsgid \"\"\n\"**Fixed** `#1311 <https://github.com/pymupdf/PyMuPDF/issues/1311>`_. \"\n\"Field values in comboboxes should now be handled correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1584 7733dd257974437aa148b45f6ada6568\nmsgid \"\"\n\"**Fixed** `#1290 <https://github.com/pymupdf/PyMuPDF/issues/1290>`_. \"\n\"Error was caused by incorrect rectangle emptiness check, which is fixed \"\n\"due to new geometry logic of this version.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1585 f61c1c44cead4da28d5a0d498a515a7c\nmsgid \"\"\n\"**Fixed** `#1286 <https://github.com/pymupdf/PyMuPDF/issues/1286>`_. Text\"\n\" alignment for redact annotations is working again.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1586 bba07d14226e43b498663a99b03b7eb5\nmsgid \"\"\n\"**Fixed** `#1287 <https://github.com/pymupdf/PyMuPDF/issues/1287>`_. \"\n\"Infinite loop issue for non-Windows systems when applying some redactions\"\n\" has been resolved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1587 5324927b491340e983434647e41ce37e\nmsgid \"\"\n\"**Fixed** `#1284 <https://github.com/pymupdf/PyMuPDF/issues/1284>`_. Text\"\n\" layout destruction after applying redactions in some cases has been \"\n\"resolved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1591 29ec5f63fdcc4f7b857449ced614ae34\nmsgid \"**Changes in Version 1.18.18 / 1.18.19**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1593 629737c065e9445f96330c435e44d4dc\nmsgid \"\"\n\"**Fixed** issue `#1266 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1266>`_. Failure to set \"\n\":attr:`Pixmap.samples` in important cases, was hotfixed in a new version \"\n\"1.18.19.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1595 0abe968e8c8349d6991a7e4002c7cc03\nmsgid \"\"\n\"**Fixed** issue `#1257 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1257>`_. Removing the read-\"\n\"only flag from PDF fields is now possible.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1597 d5ee064120c44b55a574eb82a9b65093\nmsgid \"\"\n\"**Fixed** issue `#1252 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1252>`_. Now correctly \"\n\"specifying the ``zoom`` value for PDF link annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1599 a7183e1808424b69a1a92a0c6c19251d\nmsgid \"\"\n\"**Fixed** issue `#1244 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1244>`_. Now correctly \"\n\"computing the transform matrix in :meth:`Page.get_image__bbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1601 5b909b03e5e84a92b114914838261915\nmsgid \"\"\n\"**Fixed** issue `#1241 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1241>`_. Prevent returning \"\n\"artifact characters in :meth:`Page.get_textbox`, which happened in \"\n\"certain constellations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1603 76b7202d83754586a167674467627ca6\nmsgid \"\"\n\"**Fixed** issue `#1234 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1234>`_. Avoid creating \"\n\"infinite rectangles in corner cases -- :meth:`Page.get_drawings`, \"\n\":meth:`Page.get_cdrawings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1605 11277e7c50c84168b89d7c869c0aeb1e\nmsgid \"\"\n\"**Added** test data and test scripts to the source PyPI source \"\n\"distribution.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1609 490bf1a121f24135b3e3256666187363\nmsgid \"**Changes in Version 1.18.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1611 d1e131b0d646485daf1c919e31b766d3\nmsgid \"\"\n\"Focus of this version are major performance improvements of selected \"\n\"functions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1613 03ea6bb0f78c4d679bd6c08b450d9c4e\nmsgid \"\"\n\"**Fixed** issue `#1199 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1199>`_. Using a non-existing \"\n\"page number in :meth:`Document.get_page_images` and friends will no \"\n\"longer lead to segfaults.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1615 0316ddf4a6a14b918ae314d88765508c\nmsgid \"\"\n\"**Changed** :meth:`Page.get_drawings` to now differentiate between \"\n\"\\\"stroke\\\", \\\"fill\\\" and combined paths. Paths containing more than one \"\n\"rectangle (i.e. \\\"re\\\" items) are now supported. Extracting \\\"clipped\\\" \"\n\"paths is now available as an option.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1617 68269b90e4374ece9bcc4beae2a5d8ab\nmsgid \"\"\n\"**Added** :meth:`Page.get_cdrawings`, performance-optimized version of \"\n\":meth:`Page.get_drawings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1619 b9fdb8798cef43d6af0ab313e6117152\nmsgid \"\"\n\"**Added** :attr:`Pixmap.samples_mv`, *memoryview* of a pixmap's pixel \"\n\"area. Does not copy and thus always accesses the current state of that \"\n\"area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1621 b4530586fbcc46de94110b7f601c43dd\nmsgid \"\"\n\"**Added** :attr:`Pixmap.samples_ptr`, Python \\\"pointer\\\" to a pixmap's \"\n\"pixel area. Allows much faster creation (factor 800+) of Qt images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1627 494c735b3a214b2bb172c9afb76b92b1\nmsgid \"**Changes in Version 1.18.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1629 9320ef32a6ec458db091ec9991261f2f\nmsgid \"\"\n\"**Fixed** issue `#1184 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1184>`_. Existing PDF widget \"\n\"fonts in a PDF are now accepted (i.e. not forcedly changed to a Base-14 \"\n\"font).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1631 159b6408c2ea4b86a063f21fcce0b7de\nmsgid \"\"\n\"**Fixed** issue `#1154 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1154>`_. Text search hits \"\n\"should now be correct when ``clip`` is specified.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1633 e98ab6e601d143ab99e23ce8ac756e25\nmsgid \"**Fixed** issue `#1152 <https://github.com/pymupdf/PyMuPDF/issues/1152>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1635 0793a7276f6a47c7833dc4f02c69c59c\nmsgid \"**Fixed** issue `#1146 <https://github.com/pymupdf/PyMuPDF/issues/1146>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1637 634669f89d54425fabf3395cef374ae3\nmsgid \"\"\n\"**Added** :attr:`Link.flags` and :meth:`Link.set_flags` to the \"\n\":ref:`Link` class. Implements enhancement requests `#1187 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1187>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1639 f0c43b248f16409a8f0905afee41db5d\nmsgid \"\"\n\"**Added** option to *simulate* :meth:`TextWriter.fill_textbox` output for\"\n\" predicting the number of lines, that a given text would occupy in the \"\n\"textbox.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1641 7ed434aeca7e4c8283c2ce9ac764e204\nmsgid \"\"\n\"**Added** text output support as subcommand `gettext` to the ``fitz`` CLI\"\n\" module. Most importantly, original **physical text layout** reproduction\"\n\" is now supported.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1646 7a61839613704cb6ba89df11cfd8e0c5\nmsgid \"**Changes in Version 1.18.15**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1648 76b9d70df76946379cb92b397413d1b1\nmsgid \"\"\n\"**Fixed** issue `#1088 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1088>`_. Removing an \"\n\"annotation's fill color should now work again both ways, using the \"\n\"``fill_color=[]`` argument in :meth:`Annot.update` as well as ``fill=[]``\"\n\" in :meth:`Annot.set_colors`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1650 be8edc4369ba4c6d92c42fd279c10a37\nmsgid \"\"\n\"**Fixed** issue `#1081 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1081>`_. \"\n\":meth:`Document.subset_fonts`: fixed an error which created wrong \"\n\"character widths for some fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1652 c86ec8d5f336461a9a82cf58dab23bca\nmsgid \"\"\n\"**Fixed** issue `#1078 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1078>`_. :meth:`Page.get_text`\"\n\" and other methods related to text extraction: changed the default value \"\n\"of the :ref:`TextPage` ``flags`` parameter. All whitespace and \"\n\":data:`ligatures` are now preserved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1654 6bf853d1b4f24ed3b493acbbaf102307\nmsgid \"\"\n\"**Fixed** issue `#1085 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1085>`_. The old *snake_cased*\"\n\" alias of ``fitz.detTextlength`` is now defined correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1656 0974e8722a4445e0894e2188d5074069\nmsgid \"\"\n\"**Changed** :meth:`Document.subset_fonts` will now correctly prefix font \"\n\"subsets with an appropriate six letter uppercase tag, complying with the \"\n\"PDF specification.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1658 437884a2beb34834be5a5813ff146205\nmsgid \"\"\n\"**Added** new method :meth:`Widget.button_states` which returns the \"\n\"possible values that a button-type field can have when being set to \"\n\"\\\"on\\\" or \\\"off\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1660 e165a6b51c0c42f6ac55bb2164ed36ce\nmsgid \"\"\n\"**Added** support of text with **Small Capital** letters to the \"\n\":ref:`Font` and :ref:`TextWriter` classes. This is reflected by an \"\n\"additional bool parameter ``small_caps`` in various of their methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1665 5fa6df6719ec4a30bc5737a2250ddf26\nmsgid \"**Changes in Version 1.18.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1667 246831ba1ef247c09cc05eb90a12135b\nmsgid \"\"\n\"**Finished** implementing new, \\\"snake_cased\\\" names for methods and \"\n\"properties, that were \\\"camelCased\\\" and awkward in many aspects. At the \"\n\"end of this documentation, there is section :ref:`Deprecated` with more \"\n\"background and a mapping of old to new names.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1669 e9896e6c30074ac28de21b72e13344fd\nmsgid \"\"\n\"**Fixed** issue `#1053 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1053>`_. \"\n\":meth:`Page.insert_image`: when given, include image mask in the hash \"\n\"computation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1671 856342d7e04c4c05ad362a20f30a00c5\nmsgid \"\"\n\"**Fixed** issue `#1043 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1043>`_. Added \"\n\"``Pixmap.getPNGdata`` to the aliases of :meth:`Pixmap.tobytes`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1673 a40ac7bfdd1d4c329450f6a5ba99872e\nmsgid \"\"\n\"**Fixed** an internal error when computing the enveloping rectangle of \"\n\"drawn paths as returned by :meth:`Page.get_drawings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1675 dae13ebf211f48aaa0f6305a01c8c616\nmsgid \"\"\n\"**Fixed** an internal error occasionally causing loops when outputting \"\n\"text via :meth:`TextWriter.fill_textbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1677 944833cd11d14508b1e6e8fa1a487586\nmsgid \"\"\n\"**Added** :meth:`Font.char_lengths`, which returns a tuple of character \"\n\"widths of a string.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1679 4c127faaaa4542d68be1974e72156cdb\nmsgid \"\"\n\"**Added** more ways to specify pages in :meth:`Document.delete_pages`. \"\n\"Now a sequence (list, tuple or range) can be specified, and the Python \"\n\"``del`` statement can be used. In the latter case, Python ``slices`` are \"\n\"also accepted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1681 06fd838ceb61465d9f689dfd3aebbab2\nmsgid \"\"\n\"**Changed** :meth:`Document.del_toc_item`, which disables a single item \"\n\"of the TOC: previously, the title text was removed. Instead, now the \"\n\"complete item will be shown grayed-out by supporting viewers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1686 7a4fd8bb15ab4fbcaaa183993d721089\nmsgid \"**Changes in Version 1.18.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1688 aeb68fdb27db43d68f6b5362aa749391\nmsgid \"**Fixed** issue `#1014 <https://github.com/pymupdf/PyMuPDF/issues/1014>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1689 8ee7d51d2b5941f8b64a7092fe06f789\nmsgid \"\"\n\"**Fixed** an internal memory leak when computing image bboxes -- \"\n\":meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1690 6e3c2aaf0d0b4752b02aa8c91326937e\nmsgid \"\"\n\"**Added** support for low-level access and modification of the PDF \"\n\"trailer. Applies to :meth:`Document.xref_get_keys`, \"\n\":meth:`Document.xref_get_key`, and :meth:`Document.xref_set_key`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1691 d26b610465374b1a95f57d151f841d2e\nmsgid \"**Added** documentation for maintaining private entries in PDF metadata.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1692 49f75a7ada254386acc0d8b341ed91c6\nmsgid \"\"\n\"**Added** documentation for handling transparent image insertions, \"\n\":meth:`Page.insert_image`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1693 457c2b1325b24f60ab107fe02a4e0085\nmsgid \"\"\n\"**Added** :meth:`Page.get_image_rects`, an improved version of \"\n\":meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1694 a7471bfaf29b46c0bf1baba965058c8b\nmsgid \"\"\n\"**Changed** :meth:`Document.delete_pages` to support various ways of \"\n\"specifying pages to delete. Implements `#1042 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1042>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1695 3f2e525e5db5466cbf2b21ae6e3e9c36\nmsgid \"\"\n\"**Changed** :meth:`Page.insert_image` to also accept the xref of an \"\n\"existing image in the file. This allows \\\"copying\\\" images between pages,\"\n\" and extremely fast mutiple insertions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1696 819681238cbc4a129e57b370dfb026fc\nmsgid \"\"\n\"**Changed** :meth:`Page.insert_image` to also accept the integer \"\n\"parameter ``alpha``. To be used for performance improvements.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1697 43b014e80e8041ce88847b0848cd3523\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.set_alpha` to support new parameters for pre-\"\n\"multiplying colors with their alpha values and setting a specific color \"\n\"to fully transparent (e.g. white).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1698 d00c4f08df31471e976b37826d70cb1c\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_add` to automatically set creation \"\n\"and modification date-time. Correspondingly, :meth:`Document.embfile_upd`\"\n\" automatically maintains modification date-time (``/ModDate`` PDF key), \"\n\"and :meth:`Document.embfile_info` correspondingly reports these data. In \"\n\"addition, the embedded file's associated \\\"collection item\\\" is included \"\n\"via its :data:`xref`. This supports the development of PDF portfolio \"\n\"applications.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1702 d6c3f0ac21134173a004ebfa78fe2315\nmsgid \"**Changes in Version 1.18.11 / 1.18.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1704 5c6ecd8a73da4cd6a54e60917ddff07a\nmsgid \"\"\n\"**Fixed** issue `#972 <https://github.com/pymupdf/PyMuPDF/issues/972>`_. \"\n\"Improved layout of source distribution material.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1705 086168881dcc4f639364df509a6877b1\nmsgid \"\"\n\"**Fixed** issue `#962 <https://github.com/pymupdf/PyMuPDF/issues/962>`_. \"\n\"Stabilized Linux distribution detection for generating PyMuPDF from \"\n\"sources.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1706 3a60973423d2463aa5423dc31856ba76\nmsgid \"\"\n\"**Added:** :meth:`Page.get_xobjects` delivers the result of \"\n\":meth:`Document.get_page_xobjects`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1707 a0b89ac75a28458fb93356628c87d9ab\nmsgid \"\"\n\"**Added:** :meth:`Page.get_image_info` delivers meta information for all \"\n\"images shown on the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1708 9e865b21aa37414dbfea24ec37e19b67\nmsgid \"\"\n\"**Added:** :meth:`Tools.mupdf_display_warnings` allows setting on / off \"\n\"the display of MuPDF-generated warnings. The default is off.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1709 e3d2420ee8c24d1aa43455c800972e3c\nmsgid \"\"\n\"**Added:** :meth:`Document.ez_save` convenience alias of \"\n\":meth:`Document.save` with some different defaults.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1710 7007006565b94595b23bf039c3e09338\nmsgid \"\"\n\"**Changed:** Image extractions of document pages now also contain the \"\n\"image's **transformation matrix**. This concerns \"\n\":meth:`Page.get_image_bbox` and the DICT, JSON, RAWDICT, and RAWJSON \"\n\"variants of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1715 62af1c5f6b62467897742422e1590f7d\nmsgid \"**Changes in Version 1.18.10**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1717 922707d45703479bbd67527180a768ec\nmsgid \"\"\n\"**Fixed** issue `#941 <https://github.com/pymupdf/PyMuPDF/issues/941>`_. \"\n\"Added old aliases for :meth:`DisplayList.get_pixmap` and \"\n\":meth:`DisplayList.get_textpage`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1718 5f5903a43c1f44a3bf154f3b1530d64a\nmsgid \"\"\n\"**Fixed** issue `#929 <https://github.com/pymupdf/PyMuPDF/issues/929>`_. \"\n\"Stabilized removal of JavaScript objects with :meth:`Document.scrub`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1719 0972fadf04e741629d46a18515526a9d\nmsgid \"\"\n\"**Fixed** issue `#927 <https://github.com/pymupdf/PyMuPDF/issues/927>`_. \"\n\"Removed a loop in the reworked :meth:`TextWriter.fill_textbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1720 033e96b4eceb4014bd5620c1e986198d\nmsgid \"\"\n\"**Changed** :meth:`Document.xref_get_keys` and \"\n\":meth:`Document.xref_get_key` to also allow accessing the PDF trailer \"\n\"dictionary. This can be done by using `-1` as the xref number argument.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1721 74ff56e5727c43138b496604bbfe57f9\nmsgid \"\"\n\"**Added** a number of functions for reconstructing the quads for text \"\n\"lines, spans and characters extracted by :meth:`Page.get_text` options \"\n\"\\\"dict\\\" and \\\"rawdict\\\". See :meth:`recover_quad` and friends.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1722 29aa32686d874d42b22bfa8a3901aa14\nmsgid \"\"\n\"**Added** :meth:`Tools.unset_quad_corrections` to suppress character quad\"\n\" corrections (occasionally required for erroneous fonts).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1726 3a7453ab65404c52984aee45364e6724\nmsgid \"**Changes in Version 1.18.9**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1729 e1b22c2f9fe54eb993a50fcd6112601f\nmsgid \"\"\n\"**Fixed** issue `#888 <https://github.com/pymupdf/PyMuPDF/issues/888>`_. \"\n\"Removed ambiguous statements concerning PyMuPDF's license, which is now \"\n\"clearly stated to be GNU AGPL V3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1730 f4d998abf2364f48a156cb6de76c69b7\nmsgid \"**Fixed** issue `#895 <https://github.com/pymupdf/PyMuPDF/issues/895>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1731 69b074661fb04a1c9748f0ae259d8153\nmsgid \"\"\n\"**Fixed** issue `#896 <https://github.com/pymupdf/PyMuPDF/issues/896>`_. \"\n\"Since v1.17.6 PyMuPDF suppresses the font subset tags and only reports \"\n\"the base fontname in text extraction outputs \\\"dict\\\" / \\\"json\\\" / \"\n\"\\\"rawdict\\\" / \\\"rawjson\\\". Now a new global parameter can request the old\"\n\" behaviour, :meth:`Tools.set_subset_fontnames`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1732 0e51b11e295245bdb5143f3055f5f4c6\nmsgid \"\"\n\"**Fixed** issue `#885 <https://github.com/pymupdf/PyMuPDF/issues/885>`_. \"\n\"Pixmap creation now also works with filenames given as ``pathlib.Paths``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1733 3bfe043f395249f2ad66c8714a4dcd24\nmsgid \"\"\n\"**Changed** :meth:`Document.subset_fonts`: Text is **not rewritten** any \"\n\"more and should therefore **retain all its origial properties** -- like \"\n\"being hidden or being controlled by Optional Content mechanisms.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1734 23ad1d2d69494a61b31f3bf6e0d688e0\nmsgid \"\"\n\"**Changed** :ref:`TextWriter` output to also accept text in right to left\"\n\" mode (Arabian, Hebrew): :meth:`TextWriter.fill_textbox`, \"\n\":meth:`TextWriter.append`. These methods now accept a new boolean \"\n\"parameter `right_to_left`, which is *False* by default. Implements `#897 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/897>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1735 27997725f8e4450c87939082e366439e\nmsgid \"\"\n\"**Changed** :meth:`TextWriter.fill_textbox` to return all lines of text, \"\n\"that did not fit in the given rectangle. Also changed the default of the \"\n\"``warn`` parameter to no longer print a warning message in overflow \"\n\"situations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1736 66e2fd480ef348c094149914650471d0\nmsgid \"\"\n\"**Added** a utility function :meth:`recover_quad`, which computes the \"\n\"quadrilateral of a span. This function can be used for correctly marking \"\n\"text extracted with the \\\"dict\\\" or \\\"rawdict\\\" options of \"\n\":meth:`Page.get_text`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1740 dce8476d6a3749f89835fc274cdabd84\nmsgid \"**Changes in Version 1.18.8**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1743 fa20b571b5c14e288bfcba7b82655bee\nmsgid \"\"\n\"This is a bug fix version only. We are publishing early because of the \"\n\"potentially widely used functions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1745 21142c13d0cd44bea29198c954e7f0e6\nmsgid \"\"\n\"**Fixed** issue `#881 <https://github.com/pymupdf/PyMuPDF/issues/881>`_. \"\n\"Fixed a memory leak in :meth:`Page.insert_image` when inserting images \"\n\"from files or memory.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1746 5f457acfd5954696ae76970b611ac49a\nmsgid \"\"\n\"**Fixed** issue `#878 <https://github.com/pymupdf/PyMuPDF/issues/878>`_. \"\n\"``pathlib.Path`` objects should now correctly handle file path \"\n\"hierarchies.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1751 85971c3fb54e449190448842ef48209a\nmsgid \"**Changes in Version 1.18.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1754 fbe2287c70d74d55bfa1dd7a61d1a827\nmsgid \"\"\n\"**Added** an experimental :meth:`Document.subset_fonts` which reduces the\"\n\" size of eligible fonts based on their use by text in the PDF. Implements\"\n\" `#855 <https://github.com/pymupdf/PyMuPDF/discussions/855>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1755 e300f81c0c2a414a95786dc2a5b922be\nmsgid \"\"\n\"**Implemented** request `#870 \"\n\"<https://github.com/pymupdf/PyMuPDF/pull/870>`_: \"\n\":meth:`Document.convert_to_pdf` now also supports PDF documents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1756 8b39542efeb8486782751bc4045f8c45\nmsgid \"\"\n\"**Renamed** ``Document.write`` to :meth:`Document.tobytes` for greater \"\n\"clarity. But the deprecated name remains available for some time.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1757 6717eb5a2cfb422a8b239e698e9d1a4e\nmsgid \"\"\n\"**Implemented** request `#843 \"\n\"<https://github.com/pymupdf/PyMuPDF/Discussions/843>`_: \"\n\":meth:`Document.tobytes` now supports linearized PDF output. \"\n\":meth:`Document.save` now also supports writing to Python **file \"\n\"objects**. In addition, the open function now also supports Python file \"\n\"objects.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1758 318196b9b9f24559b099a5a3b86b61a3\nmsgid \"**Fixed** issue `#844 <https://github.com/pymupdf/PyMuPDF/issues/844>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1759 22303a902c214152a94cf6908eaada79\nmsgid \"**Fixed** issue `#838 <https://github.com/pymupdf/PyMuPDF/issues/838>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1760 8d1575cb41f944d1ab091d1f15fdfe3f\nmsgid \"\"\n\"**Fixed** issue `#823 <https://github.com/pymupdf/PyMuPDF/issues/823>`_. \"\n\"More logic for better support of OCRed text output (Tesseract, ABBYY).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1761 938fa234a4d64b4998e755f30a353917\nmsgid \"**Fixed** issue `#818 <https://github.com/pymupdf/PyMuPDF/issues/818>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1762 5b25601056b641bebbe1fdbe9fbf59fc\nmsgid \"**Fixed** issue `#814 <https://github.com/pymupdf/PyMuPDF/issues/814>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1763 b4352fd5bf734216a09bc2b65068a9a1\nmsgid \"\"\n\"**Added** :meth:`Document.get_page_labels` which returns a list of page \"\n\"label definitions of a PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1764 d10d74d2add045f19432215b68dc5965\nmsgid \"\"\n\"**Added** :meth:`Document.has_annots` and :meth:`Document.has_links` to \"\n\"check whether these object types are present anywhere in a PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1765 344e56b009634edaa8a7654870785c6a\nmsgid \"\"\n\"**Added** expert low-level functions to simplify inquiry and modification\"\n\" of PDF object sources: :meth:`Document.xref_get_keys` lists the keys of \"\n\"object :data:`xref`, :meth:`Document.xref_get_key` returns type and \"\n\"content of a key, and :meth:`Document.xref_set_key` modifies the key's \"\n\"value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1766 97ffd95b565242c8a475c6f2123f9b83\nmsgid \"\"\n\"**Added** parameter ``thumbnails`` to :meth:`Document.scrub` to also \"\n\"allow removing page thumbnail images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1767 be54a84b631a4f539269cea4d2530c10\nmsgid \"\"\n\"**Improved** documentation for how to add valid text marker annotations \"\n\"for non-horizontal text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1769 7ec7306e128341c2a63a9daaf99494bb\nmsgid \"\"\n\"We continued the process of renaming methods and properties from \"\n\"*\\\"mixedCase\\\"* to *\\\"snake_case\\\"*. Documentation usually mentions the \"\n\"new names only, but old, deprecated names remain available for some time.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1775 40b8c78ac8154766b3f786804b70d764\nmsgid \"**Changes in Version 1.18.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1777 099ac66b71ab437b8f793444fbf3c368\nmsgid \"**Fixed** issue `#812 <https://github.com/pymupdf/PyMuPDF/issues/812>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1778 8d754c7625ba4e16b8b1d2da2931571c\nmsgid \"\"\n\"**Fixed** issue `#793 <https://github.com/pymupdf/PyMuPDF/issues/793>`_. \"\n\"Invalid document metadata previously prevented opening some documents at \"\n\"all. This error has been removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1779 b6756d8e13654194ae64028173969354\nmsgid \"\"\n\"**Fixed** issue `#792 <https://github.com/pymupdf/PyMuPDF/issues/792>`_. \"\n\"Text search and text extraction will make no rectangle containment checks\"\n\" at all if the default ``clip=None`` is used.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1780 f3374a74399e41139ae1b0fd15053232\nmsgid \"**Fixed** issue `#785 <https://github.com/pymupdf/PyMuPDF/issues/785>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1781 6f0ad41d3e0845679fc1b7f630d9350e\nmsgid \"\"\n\"**Fixed** issue `#780 <https://github.com/pymupdf/PyMuPDF/issues/780>`_. \"\n\"Corrected a parameter check error.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1782 a9af2b2f5b024f1d90aca0eed1eff596\nmsgid \"\"\n\"**Fixed** issue `#779 <https://github.com/pymupdf/PyMuPDF/issues/779>`_. \"\n\"Fixed typo\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1783 52e2c5d1e3734d0b9c1eafeea70502c0\nmsgid \"\"\n\"**Added** an option to set the desired line height for text boxes. \"\n\"Implements `#804 <https://github.com/pymupdf/PyMuPDF/issues/804>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1784 8a89dd2499fa4288aa2e4376409bc950\nmsgid \"\"\n\"**Changed** text position retrieval to better cope with Tesseract's \"\n\"glyphless font. Implements `#803 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/803>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1785 1c3abaa13d464f07839341b87f7b065c\nmsgid \"\"\n\"**Added** an option to choose the prefix of new annotations, fields and \"\n\"links for providing unique annotation ids. Implements request `#807 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/807>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1786 705f241926b94e4faed825b90187d9a8\nmsgid \"\"\n\"**Added** getting and setting color and text properties for Table of \"\n\"Contents items for PDFs. Implements `#779 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/779>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1787 f290b3e394a643ef92eb166d6ac700ba\nmsgid \"\"\n\"**Added** PDF page label handling: :meth:`Page.get_label()` returns the \"\n\"page label, :meth:`Document.get_page_numbers` return all page numbers \"\n\"having a specified label, and :meth:`Document.set_page_labels` adds or \"\n\"updates a PDF's page label definition.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1792 204e52071aeb4560ad583594170382fc\nmsgid \"\"\n\"This version introduces **Python type hinting**. The goal is to provide \"\n\"each parameter and the return value of all functions and methods with \"\n\"type information. This still is work in progress although the majority of\"\n\" functions has already been handled.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1797 ff861662db5c4fe985c61a23a602d0ab\nmsgid \"**Changes in Version 1.18.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1799 8972338cdcc14af3a7644a3dcddf69e2\nmsgid \"\"\n\"Apart from several fixes, this version also focusses on several minor, \"\n\"but important feature improvements. Among the latter is a more precise \"\n\"computation of proper line heights and insertion points for writing / \"\n\"inserting text. As opposed to using font-agnostic constants, these values\"\n\" are now taken from the font's properties.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1801 f9a9d31367f946218578af60d466b702\nmsgid \"\"\n\"Also note that this is the first version which does no longer provide \"\n\"pregenerated wheels for Python versions older than 3.6. PIP also \"\n\"discontinues support for these by end of this year 2020.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1803 93396822ddee484c904221f0e650bb40\nmsgid \"\"\n\"**Fixed** issue `#771 <https://github.com/pymupdf/PyMuPDF/issues/771>`_. \"\n\"By using \\\"small glyph heights\\\" option, the full page text can be \"\n\"extracted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1804 4283660ecb4e497a8d5f66c223269138\nmsgid \"**Fixed** issue `#768 <https://github.com/pymupdf/PyMuPDF/issues/768>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1805 cb94c9971f18482b8a6116bac1e91eda\nmsgid \"**Fixed** issue `#750 <https://github.com/pymupdf/PyMuPDF/issues/750>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1806 0f4ccdc52d33496780a6883b3eac2040\nmsgid \"\"\n\"**Fixed** issue `#739 <https://github.com/pymupdf/PyMuPDF/issues/739>`_. \"\n\"The \\\"dict\\\", \\\"rawdict\\\" and corresponding JSON output variants now have\"\n\" two new *span* keys: ``\\\"ascender\\\"`` and ``\\\"descender\\\"``. These \"\n\"floats represent special font properties which can be used to compute \"\n\"bboxes of spans or characters of **exactly fontsize height** (as opposed \"\n\"to the default line height). An example algorithm is shown in section \"\n\"\\\"Span Dictionary\\\" `here \"\n\"<https://pymupdf.readthedocs.io/en/latest/textpage.html#dictionary-\"\n\"structure-of-extractdict-and-extractrawdict>`_. Also improved the \"\n\"detection and correction of ill-specified ascender / descender values \"\n\"encountered in some fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1807 46d09243233b47bfabfb624aabe62a7f\nmsgid \"\"\n\"**Added** a new, experimental :meth:`Tools.set_small_glyph_heights` -- \"\n\"also in response to issue `#739 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/739>`_. This method sets or \"\n\"unsets a global parameter to **always compute bboxes with fontsize \"\n\"height**. If \\\"on\\\", text searching and all text extractions will \"\n\"returned rectangles, bboxes and quads with a smaller height.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1808 2348f09c087f4e77a9552300a273b2f9\nmsgid \"**Fixed** issue `#728 <https://github.com/pymupdf/PyMuPDF/issues/728>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1809 24ffb89f8a2847978a993810a34d9d8e\nmsgid \"\"\n\"**Changed** fill color logic of 'Polyline' annotations: this parameter \"\n\"now only pertains to line end symbols -- the annotation itself can no \"\n\"longer have a fill color. Also addresses issue `#727 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/727>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1810 d11988b7d91c474394a305026cbdac36\nmsgid \"\"\n\"**Changed** :meth:`Page.getImageBbox` to also compute the bbox if the \"\n\"image is contained in an XObject.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1811 92be2318a74e44bcbfe6d9d124cc6944\nmsgid \"\"\n\"**Changed** :meth:`Shape.insertTextbox`, resp. \"\n\":meth:`Page.insertTextbox`, resp. :meth:`TextWriter.fillTextbox` to \"\n\"respect font's properties \\\"ascender\\\" / \\\"descender\\\" when computing \"\n\"line height and insertion point. This should no longer lead to line \"\n\"overlaps for multi-line output. These methods used to ignore font \"\n\"specifics and used constant values instead.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1816 726b3c851a2742a08174e040daa6b3fc\nmsgid \"**Changes in Version 1.18.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1818 0669695e181f46b8b1d1c44f84c7cc1e\nmsgid \"\"\n\"This version adds several features to support PDF Optional Content. Among\"\n\" other things, this includes OCMDs (Optional Content Membership \"\n\"Dictionaries) with the full scope of *\\\"visibility expressions\\\"* (PDF \"\n\"key ``/VE``), text insertions (including the :ref:`TextWriter` class) and\"\n\" drawings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1820 298b682a9c8e4b17b5d9c2763ce13305\nmsgid \"\"\n\"**Fixed** issue `#727 <https://github.com/pymupdf/PyMuPDF/issues/727>`_. \"\n\"Freetext annotations now support an uncolored rectangle when \"\n\"``fill_color=None``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1821 2e4c66207d0441dd87fc8dee4d8db80f\nmsgid \"\"\n\"**Fixed** issue `#726 <https://github.com/pymupdf/PyMuPDF/issues/726>`_. \"\n\"UTF-8 encoding errors are now handled for HTML / XML :meth:`Page.getText`\"\n\" output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1822 e3ea52520ca74100aa5db3c1a47bcb22\nmsgid \"\"\n\"**Fixed** issue `#724 <https://github.com/pymupdf/PyMuPDF/issues/724>`_. \"\n\"Empty values are no longer stored in the PDF /Info metadata dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1823 a76c87f209e9404ea2a27260f984c079\nmsgid \"\"\n\"**Added** new methods :meth:`Document.set_oc` and :meth:`Document.get_oc`\"\n\" to set or get optional content references for **existing** image and \"\n\"form XObjects. These methods are similar to the same-named methods of \"\n\":ref:`Annot`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1824 6ae1cf58b5734e2db334370bae53194f\nmsgid \"\"\n\"**Added** :meth:`Document.set_ocmd`, :meth:`Document.get_ocmd` for \"\n\"handling OCMDs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1825 02c47a051f444e57a07a5c2cc00d8ece\nmsgid \"**Added** **Optional Content** support for text insertion and drawing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1826 033f5fd3092446d89a8b4be25eaf8fa5\nmsgid \"\"\n\"**Added** new method :meth:`Page.deleteWidget`, which deletes a form \"\n\"field from a page. This is analogous to deleting annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1827 f3f7aabfa367473eb2a71dd0d3b0c8ef\nmsgid \"\"\n\"**Added** support for Popup annotations. This includes defining the Popup\"\n\" rectangle and setting the Popup to open or closed. Methods / attributes \"\n\":meth:`Annot.set_popup`, :meth:`Annot.set_open`, :attr:`Annot.has_popup`,\"\n\" :attr:`Annot.is_open`, :attr:`Annot.popup_rect`, \"\n\":attr:`Annot.popup_xref`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1831 fff305ae1bfa4fa7a3b33de7de989103\nmsgid \"\"\n\"The **naming of methods and attributes** in PyMuPDF is far from being \"\n\"satisfactory: we have *CamelCases*, *mixedCases* and \"\n\"*lower_case_with_underscores* all over the place. With the :ref:`Annot` \"\n\"as the first candidate, we have started an activity to clean this up step\"\n\" by step, converting to lower case with underscores for methods and \"\n\"attributes while keeping UPPERCASE for the constants.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1833 5a5df8a85edd445a9168a3050257beb0\nmsgid \"\"\n\"Old names will remain available to prevent code breaks, but they will no \"\n\"longer be mentioned in the documentation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1834 d9dd3ce555be40288946b5c7b8684d7d\nmsgid \"\"\n\"New methods and attributes of all classes will be named according to the \"\n\"new standard.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1838 8d1aa669d43242329cb1e644baaea966\nmsgid \"**Changes in Version 1.18.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1840 0cc7942ae4f54d4698a56df9bcfc4df1\nmsgid \"\"\n\"As a major new feature, this version introduces support for PDF's \"\n\"**Optional Content** concept.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1842 eba5a3b05af340fd8d30d56d8053156a\nmsgid \"**Fixed** issue `#714 <https://github.com/pymupdf/PyMuPDF/issues/714>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1843 e0d1304eda394d6a88565ba84484d6fe\nmsgid \"**Fixed** issue `#711 <https://github.com/pymupdf/PyMuPDF/issues/711>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1844 bc199ec49e1945f1947218cd0c858828\nmsgid \"\"\n\"**Fixed** issue `#707 <https://github.com/pymupdf/PyMuPDF/issues/707>`_: \"\n\"if a PDF user password, but no owner password is supplied nor present, \"\n\"then the user password is also used as the owner password.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1845 1e99eff725e24f2f91fffda242611187\nmsgid \"\"\n\"**Fixed** ``expand`` and ``deflate`` parameters of methods \"\n\":meth:`Document.save` and :meth:`Document.write`. Individual image and \"\n\"font compression should now finally work. Addresses issue `#713 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/713>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1846 c7dbcce5af3f4805bc0bff4a3aa999c8\nmsgid \"\"\n\"**Added** a support of PDF optional content. This includes several new \"\n\":ref:`Document` methods for inquiring and setting optional content status\"\n\" and adding optional content configurations and groups. In addition, \"\n\"images, form XObjects and annotations now can be bound to optional \"\n\"content specifications. **Resolved** issue `#709 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/709>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1852 7005feac30d44416a7ae56c3c62aa421\nmsgid \"**Changes in Version 1.18.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1854 2557dd6711e74c5687da189106d7b072\nmsgid \"\"\n\"This version contains some interesting improvements for text searching: \"\n\"any number of search hits is now returned and the **hit_max** parameter \"\n\"was removed. The new **clip** parameter in addition allows to restrict \"\n\"the search area. Searching now detects hyphenations at line breaks and \"\n\"accordingly finds hyphenated words.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1856 f5a9d7fa7c5b434388c99b444417932e\nmsgid \"\"\n\"**Fixed** issue `#575 <https://github.com/pymupdf/PyMuPDF/issues/575>`_: \"\n\"if using ``quads=False`` in text searching, then overlapping rectangles \"\n\"on the same line are joined. Previously, parts of the search string, \"\n\"which belonged to different \\\"marked content\\\" items, each generated \"\n\"their own rectangle -- just as if occurring on separate lines.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1857 fa0f315fcdbb4aa7a85ebd875b0542b2\nmsgid \"\"\n\"**Added** :attr:`Document.isRepaired`, which is true if the PDF was \"\n\"repaired on open.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1858 29939ef23137444db25656ddb5c2a50b\nmsgid \"\"\n\"**Added** :meth:`Document.setXmlMetadata` which either updates or creates\"\n\" PDF XML metadata. Implements issue `#691 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/691>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1859 be99f9d509a84865a76d789e59d88508\nmsgid \"**Added** :meth:`Document.getXmlMetadata` returns PDF XML metadata.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1860 b5792e748a424e2f81526972850dbdf9\nmsgid \"\"\n\"**Changed** creation of PDF documents: they will now always carry a PDF \"\n\"identification (``/ID`` field) in the document trailer. Implements issue \"\n\"`#691 <https://github.com/pymupdf/PyMuPDF/issues/691>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1861 66eda59a33aa45ee88d7c201c85dfd3a\nmsgid \"\"\n\"**Changed** :meth:`Page.searchFor`: a new parameter ``clip`` is accepted \"\n\"to restrict the search to this rectangle. Correspondingly, the attribute \"\n\":attr:`TextPage.rect` is now respected by :meth:`TextPage.search`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1862 40efc3861a01468ba0b65c1950845cde\nmsgid \"\"\n\"**Changed** parameter ``hit_max`` in :meth:`Page.searchFor` and \"\n\":meth:`TextPage.search` is now obsolete: methods will return all hits.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1863 52c4e18a02684b35894a335001e4b449\nmsgid \"\"\n\"**Changed** character **selection criteria** in :meth:`Page.getText`: a \"\n\"character is now considered to be part of a ``clip`` if its bbox is fully\"\n\" contained. Before this, a non-empty intersection was sufficient.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1864 b05dff665c9644849dfb39e3b881dc36\nmsgid \"\"\n\"**Changed** :meth:`Document.scrub` to support a new option \"\n\"`redact_images`. This addresses issue `#697 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/697>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1869 dcb97ced9507410d944ce850f20740d7\nmsgid \"**Changes in Version 1.18.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1871 ba246f3cc40a4c189c06444a474f03c8\nmsgid \"\"\n\"**Fixed** issue `#692 <https://github.com/pymupdf/PyMuPDF/issues/692>`_. \"\n\"PyMuPDF now detects and recovers from more cyclic resource dependencies \"\n\"in PDF pages and for the first time reports them in the MuPDF warnings \"\n\"store.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1872 5ea166e77dfd422487491dc7989ac87b\nmsgid \"**Fixed** issue `#686 <https://github.com/pymupdf/PyMuPDF/issues/686>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1873 24c8bae3003740b3b7ef2f1245674d54\nmsgid \"\"\n\"**Added** opacity options for the :ref:`Shape` class: Stroke and fill \"\n\"colors can now be set to some transparency value. This means that all \"\n\":ref:`Page` draw methods, methods :meth:`Page.insertText`, \"\n\":meth:`Page.insertTextbox`, :meth:`Shape.finish`, \"\n\":meth:`Shape.insertText`, and :meth:`Shape.insertTextbox` support two new\"\n\" parameters: *stroke_opacity* and *fill_opacity*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1874 0eab763d4bde434c99750d05c7744be8\nmsgid \"\"\n\"**Added** new parameter ``mask`` to :meth:`Page.insertImage` for \"\n\"optionally providing an external image mask. Resolves issue `#685 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/685>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1875 d7eb84e2b45346e9805c75ed708951db\nmsgid \"\"\n\"**Added** :meth:`Annot.soundGet` for extracting the sound of an audio \"\n\"annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1879 8a1eef562c944225a15aca32aa0a68d0\nmsgid \"**Changes in Version 1.18.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1881 f828b2f6db734312b557796ab1a48396\nmsgid \"\"\n\"This is the first PyMuPDF version supporting MuPDF v1.18. The focus here \"\n\"is on extending PyMuPDF's own functionality -- apart from bug fixing. \"\n\"Subsequent PyMuPDF patches may address features new in MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1883 a9a5a178f719434b9bd31e65ea52f799\nmsgid \"\"\n\"**Fixed** issue `#519 <https://github.com/pymupdf/PyMuPDF/issues/519>`_. \"\n\"This upstream bug occurred occasionally for some pages only and seems to \"\n\"be fixed now: page layout should no longer be ruined in these cases.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1885 532d4ce5429a41979de31fd798876926\nmsgid \"**Fixed** issue `#675 <https://github.com/pymupdf/PyMuPDF/issues/675>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1887 4afda8086e88434b991c90a40f6b3c63\nmsgid \"\"\n\"Unsuccessful storage allocations should now always lead to exceptions \"\n\"(circumvention of an upstream bug intermittently crashing the \"\n\"interpreter).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1888 9b95a7d89275404592c843e6e1a69d20\nmsgid \"\"\n\":ref:`Pixmap` size is now based on ``size_t`` instead of ``int`` in C and\"\n\" should be correct even for extremely large pixmaps.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1890 50d1e348ab4a420e82ff6163e457c791\nmsgid \"\"\n\"**Fixed** issue `#668 <https://github.com/pymupdf/PyMuPDF/issues/668>`_. \"\n\"Specification of dashes for PDF drawing insertion should now correctly \"\n\"reflect the PDF spec.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1891 e2c585c3927446b58b695299aacefa37\nmsgid \"\"\n\"**Fixed** issue `#669 <https://github.com/pymupdf/PyMuPDF/issues/669>`_. \"\n\"A major source of memory leakage in :meth:`Page.insert_pdf` has been \"\n\"removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1892 21f99d039e0b406ba748fa27b51b61ab\nmsgid \"\"\n\"**Added** keyword *\\\"images\\\"* to :meth:`Page.apply_redactions` for fine-\"\n\"controlling the handling of images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1893 06f2d99671fb4a4693ac550bbe174f39\nmsgid \"\"\n\"**Added** :meth:`Annot.getText` and :meth:`Annot.getTextbox`, which offer\"\n\" the same functionality as the :ref:`Page` versions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1894 cc38d6a9295a4baabbe0fa91a8729818\nmsgid \"\"\n\"**Added** key *\\\"number\\\"* to the block dictionaries of \"\n\":meth:`Page.getText` / :meth:`Annot.getText` for options \\\"dict\\\" and \"\n\"\\\"rawdict\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1895 95b81b00ad5f4f67abab2d83e62fa830\nmsgid \"\"\n\"**Added** :meth:`glyph_name_to_unicode` and \"\n\":meth:`unicode_to_glyph_name`. Both functions do not really connect to a \"\n\"specific font and are now independently available, too. The data are now \"\n\"based on the `Adobe Glyph List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1896 3435f8b2d002434ea2961e3bfa9e9ef5\nmsgid \"\"\n\"**Added** convenience functions :meth:`adobe_glyph_names` and \"\n\":meth:`adobe_glyph_unicodes` which return the respective available data.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1897 46734bcd601a4c10b224d8af13288ece\nmsgid \"\"\n\"**Added** :meth:`Page.getDrawings` which returns details of drawing \"\n\"operations on a document page. Works for all document types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1898 0a520f7de35d43a992a69aaff5c5b428\nmsgid \"\"\n\"Improved performance of :meth:`Document.insert_pdf`. Multiple object \"\n\"copies are now also suppressed across multiple separate insertions from \"\n\"the same source. This saves time, memory and target file size. Previously\"\n\" this mechanism was only active within each single method execution. The \"\n\"feature can also be suppressed with the new method bool parameter \"\n\"*final=1*, which is the default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1899 61af4c935234421da5ee00ff3ad32977\nmsgid \"\"\n\"For PNG images created from pixmaps, the resolution (dpi) is now \"\n\"automatically set from the respective :attr:`Pixmap.xres` and \"\n\":attr:`Pixmap.yres` values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1904 5787bf266f7743eba6c3ad62840101c8\nmsgid \"**Changes in Version 1.17.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1906 fe5734ffddc1440683824cf9eaeb5f6e\nmsgid \"\"\n\"**Fixed** issue `#651 <https://github.com/pymupdf/PyMuPDF/issues/651>`_. \"\n\"An upstream bug causing interpreter crashes in corner case redaction \"\n\"processings was fixed by backporting MuPDF changes from their development\"\n\" repo.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1907 ebc978213c4446bba6ca783ac6fc99e5\nmsgid \"\"\n\"**Fixed** issue `#645 <https://github.com/pymupdf/PyMuPDF/issues/645>`_. \"\n\"Pixmap top-left coordinates can be set (again) by their own method, \"\n\":meth:`Pixmap.set_origin`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1908 28e1c70a439943fb93756b8877d3f067\nmsgid \"\"\n\"**Fixed** issue `#622 <https://github.com/pymupdf/PyMuPDF/issues/622>`_. \"\n\":meth:`Page.insertImage` again accepts a :data:`rect_like` parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1909 878ea74492ff47559c0f731484ecd4c7\nmsgid \"\"\n\"**Added** severeal new methods to improve and speed-up table of contents \"\n\"(TOC) handling. Among other things, TOC items can now changed or deleted \"\n\"individually -- without always replacing the complete TOC. Furthermore, \"\n\"access to some PDF page attributes is now possible without first \"\n\"**loading** the page. This has a very significant impact on the \"\n\"performance of TOC manipulation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1910 4808333e353f4b9d9eb4c65d42a50c6d\nmsgid \"\"\n\"**Added** an option to :meth:`Document.insert_pdf` which allows \"\n\"displaying progress messages. Adresses `#640 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/640>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1911 16de294b58a64f549ba7bd27e208d30b\nmsgid \"\"\n\"**Added** :meth:`Page.getTextbox` which extracts text contained in a \"\n\"rectangle. In many cases, this should obsolete writing your own script \"\n\"for this type of thing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1912 9711b2846e2c49f3bb6c283d0b1d9d67\nmsgid \"\"\n\"**Added** new ``clip`` parameter to :meth:`Page.getText` to simplify and \"\n\"speed up text extraction of page sub areas.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1913 8376ab0f05934f11b21f7fe154f09584\nmsgid \"\"\n\"**Added** :meth:`TextWriter.appendv` to add text in **vertical write \"\n\"mode**. Addresses issue `#653 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/653>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1918 bd8548ec9f5e41a8ad54094881be2323\nmsgid \"**Changes in Version 1.17.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1920 d2312ab353dc4344a3ef174e63c10207\nmsgid \"**Fixed** issue `#605 <https://github.com/pymupdf/PyMuPDF/issues/605>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1921 d52cabcacf8e4c7b8f280b8bb95e5d14\nmsgid \"\"\n\"**Fixed** issue `#600 <https://github.com/pymupdf/PyMuPDF/issues/600>`_ \"\n\"-- text should now be correctly positioned also for pages with a CropBox \"\n\"smaller than MediaBox.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1922 84afef0f9451476d83841dc61e1ae4d6\nmsgid \"\"\n\"**Added** text span dictionary key ``origin`` which contains the lower \"\n\"left coordinate of the first character in that span.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1923 c2104decab38443f85a9f4afbcf59e5f\nmsgid \"**Added** attribute :attr:`Font.buffer`, a *bytes* copy of the font file.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1924 3b8f869df37e4187b691a5636fabbcc4\nmsgid \"\"\n\"**Added** parameter *sanitize* to :meth:`Page.cleanContents`. Allows \"\n\"switching of sanitization, so only syntax cleaning will be done.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1928 79b5769975fc461580fc75e187439f1a\nmsgid \"**Changes in Version 1.17.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1930 c3dee94cf9eb4f8c9c29a712da46feee\nmsgid \"\"\n\"**Fixed** issue `#561 <https://github.com/pymupdf/PyMuPDF/issues/561>`_ \"\n\"-- second go: certain :ref:`TextWriter` usages with many alternating \"\n\"fonts did not work correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1931 b1cd45be4c3e414b9a31943b87ffa257\nmsgid \"**Fixed** issue `#566 <https://github.com/pymupdf/PyMuPDF/issues/566>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1932 c4be58f459d54570a15caabfa48b2fea\nmsgid \"**Fixed** issue `#568 <https://github.com/pymupdf/PyMuPDF/issues/568>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1933 a3a69f69f7e446d190a422fd95946055\nmsgid \"\"\n\"**Fixed** -- opacity is now correctly taken from the :ref:`TextWriter` \"\n\"object, if not given in :meth:`TextWriter.writeText`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1934 60e36a0e76204fc39ca63f66c0e017f0\nmsgid \"\"\n\"**Added** a new global attribute :attr:`fitz_fontdescriptors`. Contains \"\n\"information about usable fonts from repository `pymupdf-fonts \"\n\"<https://github.com/pymupdf/pymupdf-fonts>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1935 c5bbfe6d1dfc44bea3cf4c3d67f6d27d\nmsgid \"\"\n\"**Added** :meth:`Font.valid_codepoints` which returns an array of unicode\"\n\" codepoints for which the font has a glyph.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1936 d2abd73772384a31a507c1e1d6f4988b\nmsgid \"\"\n\"**Added** option ``text_as_path`` to :meth:`Page.getSVGimage`. this \"\n\"implements `#580 <https://github.com/pymupdf/PyMuPDF/issues/580>`_. \"\n\"Generates much smaller SVG files with parseable text if set to *False*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1941 0214e36149a247f698e38dfd899ff4fb\nmsgid \"**Changes in Version 1.17.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1943 e333e2461114401ea23d111aa11cbe48\nmsgid \"\"\n\"**Fixed** issue `#561 <https://github.com/pymupdf/PyMuPDF/issues/561>`_. \"\n\"Handling of more than 10 :ref:`Font` objects on one page should now work \"\n\"correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1944 3dc7e6c23bdb4fa2af06fa690d6c50e1\nmsgid \"\"\n\"**Fixed** issue `#562 <https://github.com/pymupdf/PyMuPDF/issues/562>`_. \"\n\"Annotation pixmaps are no longer derived from the page pixmap, thus \"\n\"avoiding unintended inclusion of page content.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1945 598609fee1c2419f8f22dd734d9e4621\nmsgid \"\"\n\"**Fixed** issue `#559 <https://github.com/pymupdf/PyMuPDF/issues/559>`_. \"\n\"This **MuPDF** bug is being temporarily fixed with a pre-version of \"\n\"MuPDF's next release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1946 2b01a159631746d0b9e27d2f4ee7f2f3\nmsgid \"\"\n\"**Added** utility function :meth:`repair_mono_font` for correcting \"\n\"displayed character spacing for some mono-spaced fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1947 d63409b0745449c5b326f78fcbdb243d\nmsgid \"\"\n\"**Added** utility method :meth:`Document.need_appearances` for fine-\"\n\"controlling Form PDF behavior. Addresses issue `#563 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/563>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1948 261813b8c1164f85bd099615986583b1\nmsgid \"\"\n\"**Added** utility function :meth:`sRGB_to_pdf` to recover the PDF color \"\n\"triple for a given color integer in sRGB format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1949 087525d5979d4e88b699951008f083cd\nmsgid \"\"\n\"**Added** utility function :meth:`sRGB_to_rgb` to recover the (R, G, B) \"\n\"color triple for a given color integer in sRGB format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1950 dfce06d94de945d298f54486d626b557\nmsgid \"\"\n\"**Added** utility function :meth:`make_table` which delivers table cells \"\n\"for a given rectangle and desired numbers of columns and rows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1951 a5085ba0096648a5abdb1bac873f8a91\nmsgid \"\"\n\"**Added** support for optional fonts in repository `pymupdf-fonts \"\n\"<https://github.com/pymupdf/pymupdf-fonts>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1955 6035ab0f4f8f4c22b602c2975ca7a9bb\nmsgid \"**Changes in Version 1.17.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1957 dd9eec4fdfa74a648a0ddfffafa83372\nmsgid \"\"\n\"**Fixed** an undocumented issue, which prevented fully cleaning a PDF \"\n\"page when using :meth:`Page.cleanContents`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1958 0847e901e54e42ab97132b411ad8703a\nmsgid \"\"\n\"**Fixed** issue `#540 <https://github.com/pymupdf/PyMuPDF/issues/540>`_. \"\n\"Text extraction for EPUB should again work correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1959 14b815222173483085dcc120dceb9f9b\nmsgid \"\"\n\"**Fixed** issue `#548 <https://github.com/pymupdf/PyMuPDF/issues/548>`_. \"\n\"Documentation now includes ``LINK_NAMED``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1960 f5eb1a9ec46e48479fef6e71d0ce3f21\nmsgid \"\"\n\"**Added** new parameter to control start of text in \"\n\":meth:`TextWriter.fillTextbox`. Implements `#549 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/549>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1961 67cf556f751344f683f697a61d518948\nmsgid \"\"\n\"**Changed** documentation of :meth:`Page.add_redact_annot` to explain the\"\n\" usage of non-builtin fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1965 cc0c58ad8b0b41eda4f8e5716f2b16a8\nmsgid \"**Changes in Version 1.17.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1967 c27ffc8eec8040018fa36d5790749cec\nmsgid \"**Fixed** issue `#533 <https://github.com/pymupdf/PyMuPDF/issues/533>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1968 27350a32fc7840bb8591f6081f20d94d\nmsgid \"\"\n\"**Added** options to modify 'Redact' annotation appearance. Implements \"\n\"`#535 <https://github.com/pymupdf/PyMuPDF/issues/535>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1973 b8bea379222d4215963ee2eb2ffa9049\nmsgid \"**Changes in Version 1.17.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1975 60814804b9f84f3d8b98c3cf2dc5f20c\nmsgid \"**Fixed** issue `#520 <https://github.com/pymupdf/PyMuPDF/issues/520>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1976 9c3b1af133ad4aa9a4f08296f7affa70\nmsgid \"\"\n\"**Fixed** issue `#525 <https://github.com/pymupdf/PyMuPDF/issues/525>`_. \"\n\"Vertices for 'Ink' annots should now be correct.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1977 98b1d51b954b4c56bebe479ae1c44fdb\nmsgid \"\"\n\"**Fixed** issue `#524 <https://github.com/pymupdf/PyMuPDF/issues/524>`_. \"\n\"It is now possible to query and set rotation for applicable annotation \"\n\"types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1979 465b318c922644768dbf6d5a01328404\nmsgid \"\"\n\"Also significantly improved inline documentation for better support of \"\n\"interactive help.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1983 5cd63263f85a4783a6ccfc029201386b\nmsgid \"**Changes in Version 1.17.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1985 b87f5b93bd9b48eeb6c65b06340048e4\nmsgid \"\"\n\"This version is based on MuPDF v1.17. Following are highlights of new and\"\n\" changed features:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1987 b2f1ba6ba94140b98e5cc0fe7a3faa3b\nmsgid \"\"\n\"**Added** extended language support for annotations and widgets: a \"\n\"mixture of Latin, Greece, Russian, Chinese, Japanese and Korean \"\n\"characters can now be used in 'FreeText' annotations and text widgets. No\"\n\" special arrangement is required to use it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1989 e733e136ba8c438db34aca4bb17fc4ef\nmsgid \"\"\n\"Faster page access is implemented for documents supporting a \\\"chapter\\\" \"\n\"structure. This applies to EPUB documents currently. This comes with \"\n\"several new :ref:`Document` methods and changes for \"\n\":meth:`Document.loadPage` and the \\\"indexed\\\" page access *doc[n]*: In \"\n\"addition to specifying a page number as before, a tuple *(chaper, pno)* \"\n\"can be specified to identify the desired page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1991 971b877040f248cdba6abf69baeef371\nmsgid \"\"\n\"**Changed:** Improved support of redaction annotations: images overlapped\"\n\" by redactions are **permanantly modified** by erasing the overlap areas.\"\n\" Also links are removed if overlapped by redactions. This is now fully in\"\n\" sync with PDF specifications.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1995 b49d2e2fb4e447e1b521a7c628189360\nmsgid \"\"\n\"**Changed** :meth:`TextWriter.writeText` to support the *\\\"morph\\\"* \"\n\"parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1996 3fc9ed296a4f4010832533bc9a26128c\nmsgid \"\"\n\"**Added** methods :meth:`Rect.morph`, :meth:`IRect.morph`, and \"\n\":meth:`Quad.morph`, which return a new :ref:`Quad`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1997 b20b08f09a414edaacd286b8f526b6f8\nmsgid \"\"\n\"**Changed** :meth:`Page.add_freetext_annot` to support text alignment via\"\n\" a new *\\\"align\\\"* parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1998 2361ff8be9cc46e1b8f08ddefa02efae\nmsgid \"\"\n\"**Fixed** issue `#508 <https://github.com/pymupdf/PyMuPDF/issues/508>`_. \"\n\"Improved image rectangle calculation to hopefully deliver correct values \"\n\"in most if not all cases.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1999 236cc95410f34fcc89f66e66388bfb9b\nmsgid \"**Fixed** issue `#502 <https://github.com/pymupdf/PyMuPDF/issues/502>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2000 b1667139e4fd40a187d32b0c93485b50\nmsgid \"\"\n\"**Fixed** issue `#500 <https://github.com/pymupdf/PyMuPDF/issues/500>`_. \"\n\":meth:`Document.convertToPDF` should no longer cause memory leaks.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2001 08f135a6cd9f48d68424126027bef590\nmsgid \"\"\n\"**Fixed** issue `#496 <https://github.com/pymupdf/PyMuPDF/issues/496>`_. \"\n\"Annotations and widgets / fields are now added or modified using the \"\n\"coordinates of the **unrotated page**. This behavior is now in sync with \"\n\"other methods modifying PDF pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2002 0129ba9864fa48e3b4ddbc7f32269fc2\nmsgid \"\"\n\"**Added** :attr:`Page.rotationMatrix` and :attr:`Page.derotationMatrix` \"\n\"to support coordinate transformations between the rotated and the \"\n\"original versions of a PDF page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2004 35a97c98b52e49278109e56b99107387\nmsgid \"Potential code breaking changes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2006 1a3fbe2084e24a759582e9aa05cc4591\nmsgid \"\"\n\"The private method ``Page._getTransformation()`` has been removed. Use \"\n\"the public :attr:`Page.transformationMattrix` instead.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2011 f06ca5ab722a487f87a29410f2bb377a\nmsgid \"**Changes in Version 1.16.18**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2013 75fa0dcdb41144b680ec66bfd4a6bd1a\nmsgid \"\"\n\"This version introduces several new features around PDF text output. The \"\n\"motivation is to simplify this task, while at the same time offering \"\n\"extending features.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2015 13b1f23e60414710b4271079289007c0\nmsgid \"\"\n\"One major achievement is using MuPDF's capabilities to dynamically \"\n\"choosing fallback fonts whenever a character cannot be found in the \"\n\"current one. This seemlessly works for Base-14 fonts in combination with \"\n\"CJK fonts (China, Japan, Korea). So a text may contain **any combination \"\n\"of characters** from the Latin, Greek, Russian, Chinese, Japanese and \"\n\"Korean languages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2017 6ffef279ab3d445ca46586a05c3e8d90\nmsgid \"\"\n\"**Fixed** issue `#493 <https://github.com/pymupdf/PyMuPDF/issues/493>`_. \"\n\"``Pixmap(doc, xref)`` should now again correctly resemble the loaded \"\n\"image object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2018 afdb0475290145d38834c612bbb45088\nmsgid \"\"\n\"**Fixed** issue `#488 <https://github.com/pymupdf/PyMuPDF/issues/488>`_. \"\n\"Widget names are now modifiable.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2019 141ce60e1fc44924a6cbdea1662c8a7d\nmsgid \"**Added** new class :ref:`Font` which represents a font.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2020 819be8edbaf04a2ebe870b12436fdad6\nmsgid \"\"\n\"**Added** new class :ref:`TextWriter` which serves as a container for \"\n\"text to be written on a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2021 be45ac51b3d7415e8150584132c49a33\nmsgid \"\"\n\"**Added** :meth:`Page.writeText` to write one or more :ref:`TextWriter` \"\n\"objects to the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2026 c355f22137584b4cbab6f6354bd95bda\nmsgid \"**Changes in Version 1.16.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2029 f3f07b3f33cc44c5984500283eb306e1\nmsgid \"\"\n\"**Fixed** issue `#479 <https://github.com/pymupdf/PyMuPDF/issues/479>`_. \"\n\"PyMuPDF should now more correctly report image resolutions. This applies \"\n\"to both, images (either from images files or extracted from PDF \"\n\"documents) and pixmaps created from images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2030 96daad3b07ac4308a44d307f62c89c50\nmsgid \"\"\n\"**Added** :meth:`Pixmap.set_dpi` which sets the image resolution in x and\"\n\" y directions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2034 33fc9fed734a4bf4990dd592129e984c\nmsgid \"**Changes in Version 1.16.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2037 765ca3ee977d42678126cf84057b4e3d\nmsgid \"**Fixed** issue `#477 <https://github.com/pymupdf/PyMuPDF/issues/477>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2038 6240d3c9c41c46be9652ecabcbae2fbb\nmsgid \"**Fixed** issue `#476 <https://github.com/pymupdf/PyMuPDF/issues/476>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2039 d5cd872ddead486aa29ca5b255ba885e\nmsgid \"\"\n\"**Changed** annotation line end symbol coloring and fixed an error \"\n\"coloring the interior of 'Polyline' /'Polygon' annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2043 bb450a98e5e04667aed64c1004529927\nmsgid \"**Changes in Version 1.16.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2046 3228fbb9e5b4467498da27f2ad55fe5b\nmsgid \"\"\n\"**Changed** text marker annotations to accept parameters beyond just \"\n\"quadrilaterals such that now **text lines between two given points can be\"\n\" marked**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2048 a97e5cc2834a4e96b0ede1ad6db5c900\nmsgid \"\"\n\"**Added** :meth:`Document.scrub` which **removes potentially sensitive \"\n\"data** from a PDF. Implements `#453 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/453>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2050 2f3c7cef276444c480a491776e3ef6e8\nmsgid \"\"\n\"**Added** :meth:`Annot.blendMode` which returns the **blend mode** of \"\n\"annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2052 866e4a88a77d48a1b7aafb511b41907c\nmsgid \"\"\n\"**Added** :meth:`Annot.setBlendMode` to set the annotation's blend mode. \"\n\"This resolves issue `#416 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/416>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2053 501eb9ee56e84e60be74f5ba75eaecb4\nmsgid \"\"\n\"**Changed** :meth:`Annot.update` to accept additional parameters for \"\n\"setting blend mode and opacity.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2054 85b91d3af2b944e09ffc418872e3540e\nmsgid \"\"\n\"**Added** advanced graphics features to **control the anti-aliasing \"\n\"values**, :meth:`Tools.set_aa_level`. Resolves `#467 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/467>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2056 60b4c208b1c04edc9d0cc75db8e9b3ab\nmsgid \"**Fixed** issue `#474 <https://github.com/pymupdf/PyMuPDF/issues/474>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2057 4f4fa5bbd4bb45dc965381d06a2c28e1\nmsgid \"**Fixed** issue `#466 <https://github.com/pymupdf/PyMuPDF/issues/466>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2063 c2150d5e98ed4b29a8d7d0e0e049893a\nmsgid \"**Changes in Version 1.16.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2066 6ffa2c895b184d7c9579c04c5e72d6cc\nmsgid \"\"\n\"**Added** :meth:`Document.getPageXObjectList` which returns a list of \"\n\"**Form XObjects** of the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2067 1ad5db1dcf4e406d84fe85e8ac783a34\nmsgid \"\"\n\"**Added** :meth:`Page.setMediaBox` for changing the physical PDF page \"\n\"size.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2068 dc4ffb1b3bba4dd7a2c0b5018278954e\nmsgid \"\"\n\"**Added** :ref:`Page` methods which have been internal before: \"\n\":meth:`Page.cleanContents` (= :meth:`Page._cleanContents`), \"\n\":meth:`Page.getContents` (= :meth:`Page._getContents`), \"\n\":meth:`Page.getTransformation` (= :meth:`Page._getTransformation`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2074 0a926e1f6bb64ff4ab4b4fed8ea0ee89\nmsgid \"**Changes in Version 1.16.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2076 6f5ea75220774bb684dc3fe1dbf48e9b\nmsgid \"**Fixed** issue `#447 <https://github.com/pymupdf/PyMuPDF/issues/447>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2077 71bac266ce3746019c6a08f26d3ec822\nmsgid \"**Fixed** issue `#461 <https://github.com/pymupdf/PyMuPDF/issues/461>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2078 373fc96ec8a54dee8c321088ee944682\nmsgid \"**Fixed** issue `#397 <https://github.com/pymupdf/PyMuPDF/issues/397>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2079 7cf9d00c4d19420abaaf8c58b10147a0\nmsgid \"**Fixed** issue `#463 <https://github.com/pymupdf/PyMuPDF/issues/463>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2080 fe57fdfdfd8d4dbab5eed84540ad2c09\nmsgid \"\"\n\"**Added** JavaScript support to PDF form fields, thereby fixing `#454 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/454>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2081 3eb09d62dd6044afa545088e6207f9f5\nmsgid \"\"\n\"**Added** a new annotation method :meth:`Annot.delete_responses`, which \"\n\"removes 'Popup' and response annotations referring to the current one. \"\n\"Mainly serves data protection purposes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2082 5c849834cfb14620809866c9ac0b1f25\nmsgid \"\"\n\"**Added** a new form field method :meth:`Widget.reset`, which resets the \"\n\"field value to its default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2083 1d43ac4e7dcf4344b0dfdcf700f6d7a5\nmsgid \"\"\n\"**Changed** and extended handling of redactions: images and XObjects are \"\n\"removed if *contained* in a redaction rectangle. Any partial only \"\n\"overlaps will just be covered by the redaction background color. Now an \"\n\"*overlay* text can be specified to be inserted in the rectangle area to \"\n\"**take the place the deleted original** text. This resolves `#434 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/434>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2087 d41286ba5ebd44c280d5f43f2c164594\nmsgid \"**Changes in Version 1.16.11**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2089 74c14cc395804937832a051835d5fecb\nmsgid \"\"\n\"**Added** Support for redaction annotations via method \"\n\":meth:`Page.add_redact_annot` and :meth:`Page.apply_redactions`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2090 68b7efcedf5f4d94964ff855c1baaa83\nmsgid \"**Fixed** issue #426 (\\\"PolygonAnnotation in 1.16.10 version\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2091 247da6da5b67427fab1dc09bed47037f\nmsgid \"\"\n\"**Fixed** documentation only issues `#443 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/443>`_ and `#444 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/444>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2095 ed5a70ba54b5438786c6e36834b30a3d\nmsgid \"**Changes in Version 1.16.10**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2097 9147f50e16864bfe9fc59b9c324a45ca\nmsgid \"\"\n\"**Fixed** issue #421 (\\\"annot.set_rect(rect) has no effect on text \"\n\"Annotation\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2098 2a0e32d4811546f3a036844d15350182\nmsgid \"\"\n\"**Fixed** issue #417 (\\\"Strange behavior for page.deleteAnnot on 1.16.9 \"\n\"compare to 1.13.20\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2099 85979328a4bc4780a1adf5da1b2e3893\nmsgid \"**Fixed** issue #415 (\\\"Annot.setOpacity throws mupdf warnings\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2100 2419b5fdf6bd4e14bf9217b890caa587\nmsgid \"\"\n\"**Changed** all \\\"add annotation / widget\\\" methods to store a unique \"\n\"name in the */NM* PDF key.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2101 9d4a65a638864c41800994ff9674b45a\nmsgid \"\"\n\"**Changed** :meth:`Annot.setInfo` to also accept direct parameters in \"\n\"addition to a dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2102 d7c062a9ce2e4526a3f42e875262dd86\nmsgid \"\"\n\"**Changed** :attr:`Annot.info` to now also show the annotation's unique \"\n\"id (*/NM* PDF key) if present.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2103 e8cff5d5c3c8451381b2fbccf05c6ad9\nmsgid \"\"\n\"**Added** :meth:`Page.annot_names` which returns a list of all annotation\"\n\" names (*/NM* keys).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2104 9e3fa2fe09b54dc29528cfced4d8729f\nmsgid \"\"\n\"**Added** :meth:`Page.load_annot` which loads an annotation given its \"\n\"unique id (*/NM* key).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2105 f5d8b4dd62cf460a9126ea02f116c488\nmsgid \"\"\n\"**Added** :meth:`Document.reload_page` which provides a new copy of a \"\n\"page after finishing any pending updates to it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2110 072a5e68ce9a45629a888405caa5a5d2\nmsgid \"**Changes in Version 1.16.9**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2112 c18c92f84efa4cfa8b797880e17d8bcb\nmsgid \"\"\n\"**Fixed** #412 (\\\"Feature Request: Allow controlling whether TOC entries \"\n\"should be collapsed\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2113 f9a9a45513f74bfa9a4747231296426f\nmsgid \"**Fixed** #411 (\\\"Seg Fault with page.firstWidget\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2114 cbe0b8f39db641068257179e30232c1f\nmsgid \"**Fixed** #407 (\\\"Annot.setOpacity trouble\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2115 c4b9b8f9ef874c7f88678471ea871da9\nmsgid \"\"\n\"**Changed** methods :meth:`Annot.setBorder`, :meth:`Annot.setColors`, \"\n\":meth:`Link.setBorder`, and :meth:`Link.setColors` to also accept direct \"\n\"parameters, and not just cumbersome dictionaries.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2119 d0e24eb6d1f34da0aca34159c1e8309c\nmsgid \"**Changes in Version 1.16.8**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2121 78fe31bc2d304b78a7a2cec103ad3a86\nmsgid \"\"\n\"**Added** several new methods to the :ref:`Document` class, which make \"\n\"dealing with PDF low-level structures easier. I also decided to provide \"\n\"them as \\\"normal\\\" methods (as opposed to private ones starting with an \"\n\"underscore \\\"_\\\"). These are :meth:`Document.xrefObject`, \"\n\":meth:`Document.xrefStream`, :meth:`Document.xrefStreamRaw`, \"\n\":meth:`Document.PDFTrailer`, :meth:`Document.PDFCatalog`, \"\n\":meth:`Document.metadataXML`, :meth:`Document.updateObject`, \"\n\":meth:`Document.updateStream`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2122 f907ccb57c184be2857e9e13341bcf7f\nmsgid \"\"\n\"**Added** :meth:`Tools.mupdf_disply_errors` which sets the display of \"\n\"mupdf errors on *sys.stderr*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2123 462c8d75060e4a88a09ea596464f5368\nmsgid \"\"\n\"**Added** a commandline facility. This a major new feature: you can now \"\n\"invoke several utility functions via *\\\"python -m fitz ...\\\"*. It should \"\n\"obsolete the need for many of the most trivial scripts. Please refer to \"\n\":ref:`Module`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2128 4f1ac7ae88d343e886b0fc8edee75d46\nmsgid \"**Changes in Version 1.16.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2130 59ec1afd2e0b4cd3a5dc260bd354751e\nmsgid \"\"\n\"Minor changes to better synchronize the binary image streams of \"\n\":ref:`TextPage` image blocks and :meth:`Document.extractImage` images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2132 ac25ec6537ba4e92aab44dcf172c4ba8\nmsgid \"\"\n\"**Fixed** issue #394 (\\\"PyMuPDF Segfaults when using \"\n\"TOOLS.mupdf_warnings()\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2133 d9b7bf416f824ce09246787bdda98e63\nmsgid \"\"\n\"**Changed** redirection of MuPDF error messages: apart from writing them \"\n\"to Python *sys.stderr*, they are now also stored with the MuPDF warnings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2134 f40406dcc3f04e31b7a7a9805de02e42\nmsgid \"\"\n\"**Changed** :meth:`Tools.mupdf_warnings` to automatically empty the store\"\n\" (if not deactivated via a parameter).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2135 2299c535d3cb4aa6a186707196175500\nmsgid \"\"\n\"**Changed** :meth:`Page.getImageBbox` to return an **infinite rectangle**\"\n\" if the image could not be located on the page -- instead of raising an \"\n\"exception.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2140 bfbc4d7dee2442f3b0f015ea21421028\nmsgid \"**Changes in Version 1.16.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2142 c28c263feaa6419cb63d73ad8209d28d\nmsgid \"**Fixed** issue #390 (\\\"Incomplete deletion of annotations\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2143 c5219152f7854dc88d39a7689713a4a8\nmsgid \"\"\n\"**Changed** :meth:`Page.searchFor` / :meth:`Document.searchPageFor` to \"\n\"also support the *flags* parameter, which controls the data included in a\"\n\" :ref:`TextPage`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2144 21ea396db0a04f04ac4bf6146ab72b59\nmsgid \"\"\n\"**Changed** :meth:`Document.getPageImageList`, \"\n\":meth:`Document.getPageFontList` and their :ref:`Page` counterparts to \"\n\"support a new parameter *full*. If true, the returned items will contain \"\n\"the :data:`xref` of the *Form XObject* where the font or image is \"\n\"referenced.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2148 69f333b42ed44c918c9378c6632bd3e2\nmsgid \"**Changes in Version 1.16.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2150 9f2ab73d9d874b4784539e77ddee4f5b\nmsgid \"More performance improvements for text extraction.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2152 fb2a1a0548f3424b8d89927d5f5047ee\nmsgid \"**Fixed** second part of issue #381 (see item in v1.16.4).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2153 3f0ac5e4286c4997836ff33e123dbaf4\nmsgid \"\"\n\"**Added** :meth:`Page.getTextPage`, so it is no longer required to create\"\n\" an intermediate display list for text extractions. Page level wrappers \"\n\"for text extraction and text searching are now based on this, which \"\n\"should improve performance by ca. 5%.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2157 9e9865f910ed4d4399d4dfbe3c3d0597\nmsgid \"**Changes in Version 1.16.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2160 e7d84df2ad7448e1880d04a6a7858521\nmsgid \"\"\n\"**Fixed** issue #381 (\\\"TextPage.extractDICT ... failed ... after \"\n\"upgrading ... to 1.16.3\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2161 17ca6aae522d4d84a5b1c510ca445cc6\nmsgid \"\"\n\"**Added** method :meth:`Document.pages` which delivers a generator \"\n\"iterator over a page range.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2162 b2b7308c362b461bb878fcc1538a0c92\nmsgid \"\"\n\"**Added** method :meth:`Page.links` which delivers a generator iterator \"\n\"over the links of a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2163 765160822cdc4aa9b4b723db791c91b6\nmsgid \"\"\n\"**Added** method :meth:`Page.annots` which delivers a generator iterator \"\n\"over the annotations of a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2164 3eb7fc95d4214c22a621ccb900d1e490\nmsgid \"\"\n\"**Added** method :meth:`Page.widgets` which delivers a generator iterator\"\n\" over the form fields of a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2165 d91d637897d54651a998f7dc0d19dc08\nmsgid \"\"\n\"**Changed** :attr:`Document.is_form_pdf` to now contain the number of \"\n\"widgets, and *False* if not a PDF or this number is zero.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2170 c01be0ed23784665aa2ce10d9ee9e605\nmsgid \"**Changes in Version 1.16.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2172 112fd892e91d4394b0bbd52b9a508533\nmsgid \"\"\n\"Minor changes compared to version 1.16.2. The code of the \\\"dict\\\" and \"\n\"\\\"rawdict\\\" variants of :meth:`Page.getText` has been ported to C which \"\n\"has greatly improved their performance. This improvement is mostly \"\n\"noticeable with text-oriented documents, where they now should execute \"\n\"almost two times faster.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2174 529a6e2ef3a44e7496d36d3b262a6697\nmsgid \"\"\n\"**Fixed** issue #369 (\\\"mupdf: cmsCreateTransform failed\\\") by removing \"\n\"ICC colorspace support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2175 d2e2ed462d9a420181f57a3bf178f0c7\nmsgid \"\"\n\"**Changed** :meth:`Page.getText` to accept additional keywords \\\"blocks\\\"\"\n\" and \\\"words\\\". These will deliver the results of \"\n\":meth:`Page.getTextBlocks` and :meth:`Page.getTextWords`, respectively. \"\n\"So all text extraction methods are now available via a uniform API. \"\n\"Correspondingly, there are now new methods :meth:`TextPage.extractBLOCKS`\"\n\" and :meth:`TextPage.extractWords`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2176 1c333634e45449ce9b326aff470a6f28\nmsgid \"\"\n\"**Changed** :meth:`Page.getText` to default bit indicator \"\n\"*TEXT_INHIBIT_SPACES* to **off**. Insertion of additional spaces is **not\"\n\" suppressed** by default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2180 12e20189c1f143da88f1568d186c2402\nmsgid \"**Changes in Version 1.16.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2182 5b0a0190d48d45a79172681a52191e85\nmsgid \"\"\n\"**Changed** text extraction methods of :ref:`Page` to allow detail \"\n\"control of the amount of extracted data.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2183 26cc0a7bee624a97a6c6ee19ee703703\nmsgid \"\"\n\"**Added** :meth:`planish_line` which maps a given line (defined as a pair\"\n\" of points) to the x-axis.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2184 b3df1c1be11846f9993b323a07181579\nmsgid \"\"\n\"**Fixed** an issue (w/o Github number) which brought down the interpreter\"\n\" when encountering certain non-UTF-8 encodable characters while using \"\n\":meth:`Page.getText` with te \\\"dict\\\" option.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2185 e6ba0bd1a32e4b12891ded9326249a81\nmsgid \"**Fixed** issue #362 (\\\"Memory Leak with getText('rawDICT')\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2189 e9569fdba664447da20f33096718b92f\nmsgid \"**Changes in Version 1.16.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2191 dcc8cf6fc2384f3bb994e03b3a87c729\nmsgid \"\"\n\"**Added** property :attr:`Quad.is_convex` which checks whether a line is \"\n\"contained in the quad if it connects two points of it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2192 cc61e8f19f5e488b8316b4e8235659f5\nmsgid \"\"\n\"**Changed** :meth:`Document.insert_pdf` to now allow dropping or \"\n\"including links and annotations independently during the copy. Fixes \"\n\"issue #352 (\\\"Corrupt PDF data and ...\\\"), which seemed to intermittently\"\n\" occur when using the method for some problematic PDF files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2193 d407b04268d44237912c00860184f190\nmsgid \"\"\n\"**Fixed** a bug which, in matrix division using the syntax *\\\"m1/m2\\\"*, \"\n\"caused matrix *\\\"m1\\\"* to be **replaced** by the result instead of \"\n\"delivering a new matrix.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2194 7817d3234a47487b971b3830ef28ec19\nmsgid \"\"\n\"**Fixed** issue #354 (\\\"SyntaxWarning with Python 3.8\\\"). We now always \"\n\"use *\\\"==\\\"* for literals (instead of the *\\\"is\\\"* Python keyword).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2195 ec50e4c219bd4062ad4ed5c0dddaac86\nmsgid \"\"\n\"**Fixed** issue #353 (\\\"mupdf version check\\\"), to no longer refuse the \"\n\"import when there are only patch level deviations from MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2201 97813723c7e74febb3697d506c0094da\nmsgid \"**Changes in Version 1.16.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2203 2c7908f042184d21a92a433a0dace8f2\nmsgid \"\"\n\"This major new version of MuPDF comes with several nice new or changed \"\n\"features. Some of them imply programming API changes, however. This is a \"\n\"synopsis of what has changed:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2205 a005bf6b6c26445f8a8e708efa7b1e6d\nmsgid \"\"\n\"PDF document encryption and decryption is now **fully supported**. This \"\n\"includes setting **permissions**, **passwords** (user and owner \"\n\"passwords) and the desired encryption method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2206 f64056f6bc3f4c5c9e5716fd5b547a3b\nmsgid \"\"\n\"In response to the new encryption features, PyMuPDF returns an integer \"\n\"(ie. a combination of bits) for document permissions, and no longer a \"\n\"dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2207 12c5b87d97b548be96df9490e4a9b1f8\nmsgid \"\"\n\"Redirection of MuPDF errors and warnings is now natively supported. \"\n\"PyMuPDF redirects error messages from MuPDF to *sys.stderr* and no longer\"\n\" buffers them. Warnings continue to be buffered and will not be \"\n\"displayed. Functions exist to access and reset the warnings buffer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2208 9ee23cc47bf54e33ac5b25ec8bd3a5b0\nmsgid \"Annotations are now **only supported for PDF**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2209 043f8a35721a45789fc958c22ae0db05\nmsgid \"\"\n\"Annotations and widgets (form fields) are now **separate object chains** \"\n\"on a page (although widgets technically still **are** PDF annotations). \"\n\"This means, that you will **never encounter widgets** when using \"\n\":attr:`Page.firstAnnot` or :meth:`Annot.next`. You must use \"\n\":attr:`Page.firstWidget` and :meth:`Widget.next` to access form fields.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2210 98ff046f99264c3aadf74240a8bc473d\nmsgid \"\"\n\"As part of MuPDF's changes regarding widgets, only the following four \"\n\"fonts are supported, when **adding** or **changing** form fields: \"\n\"**Courier, Helvetica, Times-Roman** and **ZapfDingBats**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2212 c153729a2d494ff0ae2def2ff637078a\nmsgid \"List of change details:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2214 b23f45be6d7741b295688a68df3dab61\nmsgid \"\"\n\"**Added** :meth:`Document.can_save_incrementally` which checks conditions\"\n\" that are preventing use of option *incremental=True* of \"\n\":meth:`Document.save`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2215 f4ec8c96484849b498b2ccf6668ed972\nmsgid \"\"\n\"**Added** :attr:`Page.firstWidget` which points to the first field on a \"\n\"page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2216 bcff0ac6bdc749b7b1bdca9295590789\nmsgid \"\"\n\"**Added** :meth:`Page.getImageBbox` which returns the rectangle occupied \"\n\"by an image shown on the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2217 027854d96da7483d84939b2e60db8b94\nmsgid \"\"\n\"**Added** :meth:`Annot.setName` which lets you change the (icon) name \"\n\"field.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2218 bcc01e342bb8486ca3ef80ba6e2007f8\nmsgid \"\"\n\"**Added** outputting the text color in :meth:`Page.getText`: the \"\n\"*\\\"dict\\\"*, *\\\"rawdict\\\"* and *\\\"xml\\\"* options now also show the color \"\n\"in sRGB format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2219 bc0cbfa3b0484956b6eaea0bdb98a8fc\nmsgid \"\"\n\"**Changed** :attr:`Document.permissions` to now contain an integer of \"\n\"bool indicators -- was a dictionary before.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2220 820b45730e5f4cd09d1a94837ecb4e08\nmsgid \"\"\n\"**Changed** :meth:`Document.save`, :meth:`Document.write`, which now \"\n\"fully support password-based decryption and encryption of PDF files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2221 4731ba6ffeda46a2a2d03259b480522f\nmsgid \"\"\n\"**Changed the names of all Python constants** related to annotations and \"\n\"widgets. Please make sure to consult the **Constants and Enumerations** \"\n\"chapter if your script is dealing with these two classes. This decision \"\n\"goes back to the dropped support for non-PDF annotations. The **old \"\n\"names** (starting with \\\"ANNOT_*\\\" or \\\"WIDGET_*\\\") will be available as \"\n\"deprecated synonyms.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2222 238de30d8f3c49d48c79ee5b21a0e5f6\nmsgid \"\"\n\"**Changed** font support for widgets: only *Cour* (Courier), *Helv* \"\n\"(Helvetica, default), *TiRo* (Times-Roman) and *ZaDb* (ZapfDingBats) are \"\n\"accepted when **adding or changing** form fields. Only the plain versions\"\n\" are possible -- not their italic or bold variations. **Reading** \"\n\"widgets, however will show its original font.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2223 e763e7235e744348bb116c13b8db7bfa\nmsgid \"\"\n\"**Changed** the name of the warnings buffer to \"\n\":meth:`Tools.mupdf_warnings` and the function to empty this buffer is now\"\n\" called :meth:`Tools.reset_mupdf_warnings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2224 e51bbdba4a7f47c99ae6f3828cb8299d\nmsgid \"\"\n\"**Changed** :meth:`Page.getPixmap`, :meth:`Document.get_page_pixmap`: a \"\n\"new bool argument *annots* can now be used to **suppress the rendering of\"\n\" annotations** on the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2225 caaa515792364bf3902f0f1c3f484995\nmsgid \"\"\n\"**Changed** :meth:`Page.add_file_annot` and :meth:`Page.add_text_annot` \"\n\"to enable setting an icon.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2226 0086e4a6b881460f8c71102f2729bc2d\nmsgid \"\"\n\"**Removed** widget-related methods and attributes from the :ref:`Annot` \"\n\"object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2227 f50931d062644b8f880b652ea90f83f5\nmsgid \"\"\n\"**Removed** :ref:`Document` attributes *openErrCode*, *openErrMsg*, and \"\n\":ref:`Tools` attributes / methods *stderr*, *reset_stderr*, *stdout*, and\"\n\" *reset_stdout*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2228 a67f4a89f4f64dd68267c94b2d73ce86\nmsgid \"\"\n\"**Removed** **thirdparty zlib** dependency in PyMuPDF: there are now \"\n\"compression functions available in MuPDF. Source installers of PyMuPDF \"\n\"may now omit this extra installation step.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2230 42c8303233d940a8bb202082575e9d67\nmsgid \"**No version published for MuPDF v1.15.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2235 0e262b2012e24e66bcbb16697b9750e3\nmsgid \"**Changes in Version 1.14.20 / 1.14.21**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2237 cf8c37c3fab846c3bfc824d30a64fe50\nmsgid \"\"\n\"**Changed** text marker annotations to support multiple rectangles / \"\n\"quadrilaterals. This fixes issue #341 (\\\"Question : How to addhighlight \"\n\"so that a string spread across more than a line is covered by one \"\n\"highlight?\\\") and similar (#285).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2238 cea5aecbd9e84d1aa23aa5d28149aa16\nmsgid \"\"\n\"**Fixed** issue #331 (\\\"Importing PyMuPDF changes warning filtering \"\n\"behaviour globally\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2243 97bdc13f89b8480bb31a7a26ed32a594\nmsgid \"**Changes in Version 1.14.19**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2245 6b2efadb462c476c86b64734cc2f0abe\nmsgid \"**Fixed** issue #319 (\\\"InsertText function error when use custom font\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2246 55649a3c6956439eb948ff4f5d16de35\nmsgid \"\"\n\"**Added** new method :meth:`Document.get_sigflags` which returns \"\n\"information on whether a PDF is signed. Resolves issue #326 (\\\"How to \"\n\"detect signature in a form pdf?\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2251 8b00c1d84be44f0e843dcc2f618a054f\nmsgid \"**Changes in Version 1.14.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2253 bf77aace3abb4d87a3a27f4fde38cdee\nmsgid \"\"\n\"**Added** :meth:`Document.fullcopyPage` to make full page copies within a\"\n\" PDF (not just copied references as :meth:`Document.copyPage` does).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2254 f5f13a70b41041ac94342d177b78283e\nmsgid \"\"\n\"**Changed** :meth:`Page.getPixmap`, :meth:`Document.get_page_pixmap` now \"\n\"use *alpha=False* as default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2255 0b81e0a298f842cfae56289c691fc8af\nmsgid \"\"\n\"**Changed** text extraction: the span dictionary now (again) contains its\"\n\" rectangle under the *bbox* key.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2256 80171c31ff824cf5a8796464b7f185bd\nmsgid \"\"\n\"**Changed** :meth:`Document.movePage` and :meth:`Document.copyPage` to \"\n\"use direct functions instead of wrapping :meth:`Document.select` -- \"\n\"similar to :meth:`Document.delete_page` in v1.14.16.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2260 2102f0e54ede402daf1c78dac1d0ca26\nmsgid \"**Changes in Version 1.14.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2262 6703d3f0199a482cadb2d9a376aaa7c6\nmsgid \"\"\n\"**Changed** :ref:`Document` methods around PDF */EmbeddedFiles* to no \"\n\"longer use MuPDF's \\\"portfolio\\\" functions. That support will be dropped \"\n\"in MuPDF v1.15 -- therefore another solution was required.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2263 6447adac2fa6472d8d443e4326ffe0f4\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_Count` to be a function (was an \"\n\"attribute).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2264 0f5ec06d87f74cdc82a5f05fa5beae80\nmsgid \"\"\n\"**Added** new method :meth:`Document.embfile_Names` which returns a list \"\n\"of names of embedded files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2265 c99e5b42134b48d28118a34b7b00f400\nmsgid \"\"\n\"**Changed** :meth:`Document.delete_page` and \"\n\":meth:`Document.delete_pages` to internally no longer use \"\n\":meth:`Document.select`, but instead use functions to perform the \"\n\"deletion directly. As it has turned out, the :meth:`Document.select` \"\n\"method yields invalid outline trees (tables of content) for very complex \"\n\"PDFs and sophisticated use of annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2270 d47507f7f3114b71864f6f89dff1d8de\nmsgid \"**Changes in Version 1.14.15**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2272 685a47651ab74ab9baa02751bdfeea45\nmsgid \"\"\n\"**Fixed** issues #301 (\\\"Line cap and Line join\\\"), #300 (\\\"How to draw a\"\n\" shape without outlines\\\") and #298 (\\\"utils.updateRect exception\\\"). \"\n\"These bugs pertain to drawing shapes with PyMuPDF. Drawing shapes without\"\n\" any border is fully supported. Line cap styles and line line join style \"\n\"are now differentiated and support all possible PDF values (0, 1, 2) \"\n\"instead of just being a bool. The previous parameter *roundCap* is \"\n\"deprecated in favor of *lineCap* and *lineJoin* and will be deleted in \"\n\"the next release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2273 69635ffd084f40da8a77aef036ecbc5b\nmsgid \"\"\n\"**Fixed** issue #290 (\\\"Memory Leak with getText('rawDICT')\\\"). This bug \"\n\"caused memory not being (completely) freed after invoking the \\\"dict\\\", \"\n\"\\\"rawdict\\\" and \\\"json\\\" versions of :meth:`Page.getText`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2278 347daa4b4d614a538c8264a0f7513365\nmsgid \"**Changes in Version 1.14.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2280 fd89b8ffed0e45b4becf36770405f0a5\nmsgid \"\"\n\"**Added** new low-level function :meth:`ImageProperties` to determine a \"\n\"number of characteristics for an image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2281 5b71c3a43a3d4b468a46d3704d1a5fed\nmsgid \"\"\n\"**Added** new low-level function :meth:`Document.is_stream`, which checks\"\n\" whether an object is of stream type.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2282 7704e37dc4954c43891ea6905e994602\nmsgid \"\"\n\"**Changed** low-level functions :meth:`Document._getXrefString` and \"\n\":meth:`Document._getTrailerString` now by default return object \"\n\"definitions in a formatted form which makes parsing easy.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2286 60c8b7ae348144f590caa8dd2b6475b4\nmsgid \"**Changes in Version 1.14.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2288 409b6e7270844e05986a6af2e04bf234\nmsgid \"\"\n\"**Changed** methods working with binary input: while ever supporting \"\n\"bytes and bytearray objects, they now also accept *io.BytesIO* input, \"\n\"using their *getvalue()* method. This pertains to document creation, \"\n\"embedded files, FileAttachment annotations, pixmap creation and others. \"\n\"Fixes issue #274 (\\\"Segfault when using BytesIO as a stream for \"\n\"insertImage\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2289 517a02e2889046a4bf151c5da878dec9\nmsgid \"\"\n\"**Fixed** issue #278 (\\\"Is insertImage(keep_proportion=True) broken?\\\"). \"\n\"Images are now correctly presented when keeping aspect ratio.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2294 d22de33a96de48479a5d908ec0ba6cd2\nmsgid \"**Changes in Version 1.14.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2296 8e8898b2f62f4ccfabbc4633afa8d524\nmsgid \"\"\n\"**Changed** the draw methods of :ref:`Page` and :ref:`Shape` to support \"\n\"not only RGB, but also GRAY and CMYK colorspaces. This solves issue #270 \"\n\"(\\\"Is there a way to use CMYK color to draw shapes?\\\"). This change also \"\n\"applies to text insertion methods of :ref:`Shape`, resp. :ref:`Page`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2297 12008f80180643aeb7c59cd9d81f7b17\nmsgid \"\"\n\"**Fixed** issue #269 (\\\"AttributeError in Document.insert_page()\\\"), \"\n\"which occurred when using :meth:`Document.insert_page` with text \"\n\"insertion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2302 5926b5208b964e5bb1c6d9aa237e3b25\nmsgid \"**Changes in Version 1.14.11**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2304 7cd2f991658242e0a818633e00e32840\nmsgid \"\"\n\"**Changed** :meth:`Page.show_pdf_page` to always position the source \"\n\"rectangle centered in the target. This method now also supports \"\n\"**rotation by arbitrary angles**. The argument *reuse_xref* has been \"\n\"deprecated: prevention of duplicates is now **handled internally**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2305 92cb4e6a37f04f8fbe1fe50f20b4315e\nmsgid \"\"\n\"**Changed** :meth:`Page.insertImage` to support rotated display of the \"\n\"image and keeping the aspect ratio. Only rotations by multiples of 90 \"\n\"degrees are supported here.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2306 a3321e012bd14420978e83b39fe71692\nmsgid \"\"\n\"**Fixed** issue #265 (\\\"TypeError: insertText() got an unexpected keyword\"\n\" argument 'idx'\\\"). This issue only occurred when using \"\n\":meth:`Document.insert_page` with also inserting text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2310 ce94e552e8634de490994f5a58a88b5a\nmsgid \"**Changes in Version 1.14.10**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2312 91400574def7471c9bcf3e3b784293fa\nmsgid \"\"\n\"**Changed** :meth:`Page.show_pdf_page` to support rotation of the source \"\n\"rectangle. Fixes #261 (\\\"Cannot rotate insterted pages\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2313 373a473d44604ea0a33bee60a4608003\nmsgid \"\"\n\"**Fixed** a bug in :meth:`Page.insertImage` which prevented insertion of \"\n\"multiple images provided as streams.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2318 a745612de5d944648494f2f4fe5a7367\nmsgid \"**Changes in Version 1.14.9**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2320 786372a66f0346f5b2ebf49918ac01fc\nmsgid \"\"\n\"**Added** new low-level method :meth:`Document._getTrailerString`, which \"\n\"returns the trailer object of a PDF. This is much like \"\n\":meth:`Document._getXrefString` except that the PDF trailer has no / \"\n\"needs no :data:`xref` to identify it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2321 166ee0276f23464790afa4aa78d3fb2b\nmsgid \"\"\n\"**Added** new parameters for text insertion methods. You can now set \"\n\"stroke and fill colors of glyphs (text characters) independently, as well\"\n\" as the thickness of the glyph border. A new parameter *render_mode* \"\n\"controls the use of these colors, and whether the text should be visible \"\n\"at all.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2322 ec5e00cd07f74051b60872c21459da65\nmsgid \"\"\n\"**Fixed** issue #258 (\\\"Copying image streams to new PDF without size \"\n\"increase\\\"): For JPX images embedded in a PDF, \"\n\":meth:`Document.extractImage` will now return them in their original \"\n\"format. Previously, the MuPDF base library was used, which returns them \"\n\"in PNG format (entailing a massive size increase).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2323 9c4df9a330534524ae96733260628fa2\nmsgid \"\"\n\"**Fixed** issue #259 (\\\"Morphing text to fit inside rect\\\"). Clarified \"\n\"use of :meth:`get_text_length` and removed extra line breaks for long \"\n\"words.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2327 40cd0da7bb2c49d28cf036e85d01e73d\nmsgid \"**Changes in Version 1.14.8**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2329 c23dc29674cd4476a5d1ce8bdba7c25b\nmsgid \"\"\n\"**Added** :meth:`Pixmap.set_rect` to change the pixel values in a \"\n\"rectangle. This is also an alternative to setting the color of a complete\"\n\" pixmap (:meth:`Pixmap.clear_with`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2330 647ba02e1ad3448b85b1e417300551d5\nmsgid \"\"\n\"**Fixed** an image extraction issue with JBIG2 (monochrome) encoded PDF \"\n\"images. The issue occurred in :meth:`Page.getText` (parameters \\\"dict\\\" \"\n\"and \\\"rawdict\\\") and in :meth:`Document.extractImage` methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2331 97187008a30a4a7cad0a589358db47c2\nmsgid \"\"\n\"**Fixed** an issue with not correctly clearing a non-alpha :ref:`Pixmap` \"\n\"(:meth:`Pixmap.clear_with`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2332 e8d31f10770246f0a19e29e3fe088dba\nmsgid \"\"\n\"**Fixed** an issue with not correctly inverting colors of a non-alpha \"\n\":ref:`Pixmap` (:meth:`Pixmap.invert_irect`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2336 67dff84982fa4c1680c49d7d32e32cd7\nmsgid \"**Changes in Version 1.14.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2338 7a13d485e8154810a7af7370e7e9252d\nmsgid \"**Added** :meth:`Pixmap.set_pixel` to change one pixel value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2339 4c9debbd3ad14281953bef2ed96535b3\nmsgid \"**Added** documentation for image conversion in the :ref:`FAQ`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2340 78bdc22a5a5e4e64a9d8b4b07bfb1123\nmsgid \"\"\n\"**Added** new function :meth:`get_text_length` to determine the string \"\n\"length for a given font.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2341 a5c814fd37c640aa8a93aa10f85c235c\nmsgid \"\"\n\"**Added** Postscript image output (changed :meth:`Pixmap.save` and \"\n\":meth:`Pixmap.tobytes`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2342 f3c2525369734e7089b7c83e8cf9de47\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.save` and :meth:`Pixmap.tobytes` to ensure \"\n\"valid combinations of colorspace, alpha and output format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2343 b9e74f4416644fccb65daa7e89c723c3\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.save`: the desired format is now inferred from \"\n\"the filename.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2344 2d75602bfe7c4491afe16b74bc43214f\nmsgid \"\"\n\"**Changed** FreeText annotations can now have a transparent background - \"\n\"see :meth:`Annot.update`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2348 6c3551ae311845ee9b99b03931d18295\nmsgid \"**Changes in Version 1.14.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2350 bf604455e7bc49078d6f8fad925b9c40\nmsgid \"\"\n\"**Changed:** :ref:`Shape` methods now strictly use the transformation \"\n\"matrix of the :ref:`Page` -- instead of \\\"manually\\\" calculating \"\n\"locations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2351 a31dae7889694da7be488d4e185ec9eb\nmsgid \"\"\n\"**Added** method :meth:`Pixmap.pixel` which returns the pixel value (a \"\n\"list) for given pixel coordinates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2352 27fb489fd3c4437dae7d84ea827220f4\nmsgid \"\"\n\"**Added** method :meth:`Pixmap.tobytes` which returns a bytes object \"\n\"representing the pixmap in a variety of formats. Previously, this could \"\n\"be done for PNG outputs only (:meth:`Pixmap.tobytes`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2353 1c71f20d72344b9d92a9db58d371f81b\nmsgid \"\"\n\"**Changed:** output of methods :meth:`Pixmap.save` and (the new) \"\n\":meth:`Pixmap.tobytes` may now also be PSD (Adobe Photoshop Document).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2354 fa29ec91aa714c5f907b7366ffb9a3b9\nmsgid \"\"\n\"**Added** method :meth:`Shape.drawQuad` which draws a :ref:`Quad`. This \"\n\"actually is a shorthand for a :meth:`Shape.drawPolyline` with the edges \"\n\"of the quad.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2355 91031a98d09349dbb69473db2e7329ec\nmsgid \"\"\n\"**Changed** method :meth:`Shape.drawOval`: the argument can now be \"\n\"**either** a rectangle (:data:`rect_like`) **or** a quadrilateral \"\n\"(:data:`quad_like`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2359 0e8436f8a5324f5c854c6da3891f584a\nmsgid \"**Changes in Version 1.14.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2361 f161930e41614a59bd8398be1a48b0c9\nmsgid \"**Fixes** issue #239 \\\"Annotation coordinate consistency\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2366 f717329397b04912b44b761001662800\nmsgid \"**Changes in Version 1.14.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2368 c8623149250744e589dc449330738ae7\nmsgid \"This patch version contains minor bug fixes and CJK font output support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2370 090ca3d9b2344ba888c0876c7b71ace0\nmsgid \"\"\n\"**Added** support for the four CJK fonts as PyMuPDF generated text \"\n\"output. This pertains to methods :meth:`Page.insertFont`, \"\n\":meth:`Shape.insertText`, :meth:`Shape.insertTextbox`, and corresponding \"\n\":ref:`Page` methods. The new fonts are available under \\\"reserved\\\" \"\n\"fontnames \\\"china-t\\\" (traditional Chinese), \\\"china-s\\\" (simplified \"\n\"Chinese), \\\"japan\\\" (Japanese), and \\\"korea\\\" (Korean).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2371 0883c9f987274b41ae7f270c3f497622\nmsgid \"**Added** full support for the built-in fonts 'Symbol' and 'Zapfdingbats'.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2372 28cecba376654ea4aabaf41a9a9e76a0\nmsgid \"\"\n\"**Changed:** The 14 standard fonts can now each be referenced by a \"\n\"4-letter abbreviation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2376 2af6e8674b4443da9ecbfff548ce5a69\nmsgid \"**Changes in Version 1.14.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2378 b0f0dfdd4d05439fbb192a2fff012afd\nmsgid \"This patch version contains minor performance improvements.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2380 d55c7a1c5617427cae944d98885ab488\nmsgid \"\"\n\"**Added** support for :ref:`Document` filenames given as *pathlib* object\"\n\" by using the Python *str()* function.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2385 8408ffdc08bd4b988e1d1d8706e8852d\nmsgid \"**Changes in Version 1.14.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2387 5e88bed306444855bb7cb18769259f07\nmsgid \"\"\n\"To support MuPDF v1.14.0, massive changes were required in PyMuPDF -- \"\n\"most of them purely technical, with little visibility to developers. But \"\n\"there are also quite a lot of interesting new and improved features. \"\n\"Following are the details:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2389 ddc84ec9e77d406180396849960f6fd3\nmsgid \"**Added** \\\"ink\\\" annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2390 5ef49f9b2028452da946e586194111bd\nmsgid \"**Added** \\\"rubber stamp\\\" annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2391 4a7bb926db894ea39c7f10315f2e825a\nmsgid \"**Added** \\\"squiggly\\\" text marker annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2392 3398303dd33846db9cfde43f06070d2d\nmsgid \"\"\n\"**Added** new class :ref:`Quad` (quadrilateral or tetragon) -- which \"\n\"represents a general four-sided shape in the plane. The special subtype \"\n\"of rectangular, non-empty tetragons is used in text marker annotations \"\n\"and as returned objects in text search methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2393 6c56ac281b924d2fb189ede6e9c8be61\nmsgid \"\"\n\"**Added** a new option \\\"decrypt\\\" to :meth:`Document.save` and \"\n\":meth:`Document.write`. Now you can **keep encryption** when saving a \"\n\"password protected PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2394 b394b2a1574646c89160273346915f47\nmsgid \"\"\n\"**Added** suppression and redirection of unsolicited messages issued by \"\n\"the underlying C-library MuPDF. Consult :ref:`RedirectMessages` for \"\n\"details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2395 47856295d652463f8184801b60dee8a0\nmsgid \"\"\n\"**Changed:** Changes to annotations now **always require** \"\n\":meth:`Annot.update` to become effective.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2396 ef1b316a5b024381bc8ab808d69d2891\nmsgid \"\"\n\"**Changed** free text annotations to support the full Latin character set\"\n\" and range of appearance options.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2397 506d4cd601f04e2c83386b5ec8940898\nmsgid \"\"\n\"**Changed** text searching, :meth:`Page.searchFor`, to optionally return \"\n\":ref:`Quad` instead :ref:`Rect` objects surrounding each search hit.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2398 4fd963295c354372b9e8574e51f097ee\nmsgid \"\"\n\"**Changed** plain text output: we now add a *\\\\n* to each line if it does\"\n\" not itself end with this character.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2399 1db7b0929bbf4596b2a0d22f3ca7b59c\nmsgid \"**Fixed** issue 211 (\\\"Something wrong in the doc\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2400 f1128c764272467f8fb8a6c3a9b0087e\nmsgid \"\"\n\"**Fixed** issue 213 (\\\"Rewritten outline is displayed only by mupdf-based\"\n\" applications\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2401 f7b1e5c7dc7c4676a9bf4838c03b508c\nmsgid \"**Fixed** issue 214 (\\\"PDF decryption GONE!\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2402 7a1c216e3cf04513bac8a38d46fb777a\nmsgid \"**Fixed** issue 215 (\\\"Formatting of links added with pyMuPDF\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2403 9c9ae8e5f826442d8888cefae230e64e\nmsgid \"**Fixed** issue 217 (\\\"extraction through json is failing for my pdf\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2405 5ae51da467b64e26bfb10cf525eb9581\nmsgid \"\"\n\"Behind the curtain, we have changed the implementation of geometry \"\n\"objects: they now purely exist in Python and no longer have \\\"shadow\\\" \"\n\"twins on the C-level (in MuPDF). This has improved processing speed in \"\n\"that area by more than a factor of two.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2407 b5211152c64342a49990467a8d763bd5\nmsgid \"\"\n\"Because of the same reason, most methods involving geometry parameters \"\n\"now also accept the corresponding Python sequence. For example, in method\"\n\" *\\\"page.show_pdf_page(rect, ...)\\\"* parameter *rect* may now be any \"\n\":data:`rect_like` sequence.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2409 79b7deaba4ec49f58fd8987c7e950e28\nmsgid \"\"\n\"We also invested considerable effort to further extend and improve the \"\n\":ref:`FAQ` chapter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2414 fd91322d1a494ed189d8932bb19e425a\nmsgid \"**Changes in Version 1.13.19**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2416 c99f01c86e0f418e8ece858b509f575f\nmsgid \"\"\n\"This version contains some technical / performance improvements and bug \"\n\"fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2418 f6ca673e1a514b8c88882528546fc938\n#, python-format\nmsgid \"\"\n\"**Changed** memory management: for Python 3 builds, Python memory \"\n\"management is exclusively used across all C-level code (i.e. no more \"\n\"native *malloc()* in MuPDF code or PyMuPDF interface code). This leads to\"\n\" improved memory usage profiles and also some runtime improvements: we \"\n\"have seen > 2% shorter runtimes for text extractions and pixmap creations\"\n\" (on Windows machines only to date).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2419 5bfccbbb021842b9abb0b04bf9de48c3\nmsgid \"\"\n\"**Fixed** an error occurring in Python 2.7, which crashed the interpreter\"\n\" when using :meth:`TextPage.extractRAWDICT` (= \"\n\"*Page.getText(\\\"rawdict\\\")*).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2420 0f2cb31dfbf9466fa8a235d46d2c6e8a\nmsgid \"\"\n\"**Fixed** an error occurring in Python 2.7, when creating link \"\n\"destinations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2421 08e34b265b7e454f94220ea943997f4d\nmsgid \"**Extended** the :ref:`FAQ` chapter with more examples.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2425 63b7e43da4034c64859e960033709c83\nmsgid \"**Changes in Version 1.13.18**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2427 cf5beb6e03c54affafc84f316858c9aa\nmsgid \"\"\n\"**Added** method :meth:`TextPage.extractRAWDICT`, and a corresponding new\"\n\" string parameter \\\"rawdict\\\" to method :meth:`Page.getText`. It extracts\"\n\" text and images from a page in Python *dict* form like \"\n\":meth:`TextPage.extractDICT`, but with the detail level of \"\n\":meth:`TextPage.extractXML`, which is position information down to each \"\n\"single character.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2431 9b563f0c8c3a4d1fb8e8fe127bb76d6c\nmsgid \"**Changes in Version 1.13.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2433 b3c0162af9db4f608389e2c811c7bc4b\nmsgid \"\"\n\"**Fixed** an error that intermittently caused an exception in \"\n\":meth:`Page.show_pdf_page`, when pages from many different source PDFs \"\n\"were shown.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2434 c35c79318b584e5790dbea763351299b\nmsgid \"\"\n\"**Changed** method :meth:`Document.extractImage` to now return more meta \"\n\"information about the extracted imgage. Also, its performance has been \"\n\"greatly improved. Several demo scripts have been changed to make use of \"\n\"this method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2435 ef0a501dd401489f8d0796417bf84a65\nmsgid \"\"\n\"**Changed** method :meth:`Document._getXrefStream` to now return *None* \"\n\"if the object is no stream and no longer raise an exception if otherwise.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2436 7032fecda32745aeb0b54febfa6571f7\nmsgid \"\"\n\"**Added** method :meth:`Document._deleteObject` which deletes a PDF \"\n\"object identified by its :data:`xref`. Only to be used by the experienced\"\n\" PDF expert.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2437 64f62a994fb742cf84570443580cf6a2\nmsgid \"\"\n\"**Added** a method :meth:`paper_rect` which returns a :ref:`Rect` for a \"\n\"supplied paper format string. Example: *fitz.paper_rect(\\\"letter\\\") = \"\n\"fitz.Rect(0.0, 0.0, 612.0, 792.0)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2438 31e24169fc6849878acc3c4b81c2931b\nmsgid \"**Added** a :ref:`FAQ` chapter to this document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2442 43d63ac60a0c46a591e1b79f54377917\nmsgid \"**Changes in Version 1.13.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2444 d904d04d3cfb4dcda46139c25fe24c71\nmsgid \"\"\n\"**Added** support for correctly setting transparency (opacity) for \"\n\"certain annotation types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2445 3b7e735489e94623ac095480bdcbc2a5\nmsgid \"\"\n\"**Added** a tool property (:attr:`Tools.fitz_config`) showing the \"\n\"configuration of this PyMuPDF version.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2446 9c879f61145948b188ee8d93c5efe154\nmsgid \"\"\n\"**Fixed** issue #193 ('insertText(overlay=False) gives \\\"cannot resize a \"\n\"buffer with shared storage\\\" error') by avoiding read-only buffers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2450 5d037ed847b44095be41047f123f2c7d\nmsgid \"**Changes in Version 1.13.15**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2452 7b20562ab960458cb2a37834b262bc0a\nmsgid \"\"\n\"**Fixed** issue #189 (\\\"cannot find builtin CJK font\\\"), so we are \"\n\"supporting builtin CJK fonts now (CJK = China, Japan, Korea). This should\"\n\" lead to correctly generated pixmaps for documents using these languages.\"\n\" This change has consequences for our binary file size: it will now range\"\n\" between 8 and 10 MB, depending on the OS.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2453 09714417974d4784bbb8ce28449b0ed4\nmsgid \"\"\n\"**Fixed** issue #191 (\\\"Jupyter notebook kernel dies after ca. 40 \"\n\"pages\\\"), which occurred when modifying the contents of an annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2457 5adc29b99ec94005bffd7ef24998e110\nmsgid \"**Changes in Version 1.13.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2459 7f38a7f515424bdf958094ead9ab7ef0\nmsgid \"This patch version contains several improvements, mainly for annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2461 b1c7424aa4d54a5caefae33e0e5f4f84\nmsgid \"\"\n\"**Changed** :attr:`Annot.lineEnds` is now a list of two integers \"\n\"representing the line end symbols. Previously was a *dict* of strings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2462 641b3d6d6a8f46359ce78aacec1a00fe\nmsgid \"\"\n\"**Added** support of line end symbols for applicable annotations. PyMuPDF\"\n\" now can generate these annotations including the line end symbols.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2463 f00765d5f2434220a9bfa1b43ce083c6\nmsgid \"\"\n\"**Added** :meth:`Annot.setLineEnds` adds line end symbols to applicable \"\n\"annotation types ('Line', 'PolyLine', 'Polygon').\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2464 c43498bf8fbe4da3bbbd2a1b57eb2ade\nmsgid \"\"\n\"**Changed** technical implementation of :meth:`Page.insertImage` and \"\n\":meth:`Page.show_pdf_page`: they now create there own contents objects, \"\n\"thereby avoiding changes of potentially large streams with consequential \"\n\"compression / decompression efforts and high change volumes with \"\n\"incremental updates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2468 6d6106b5cef0412c859b77efff74d76a\nmsgid \"**Changes in Version 1.13.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2470 76e178082cef4bbcaf9d02facb74a2a8\nmsgid \"\"\n\"This patch version contains several improvements for embedded files and \"\n\"file attachment annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2472 a3ecffcb691f41e18fa492558ef375d5\nmsgid \"\"\n\"**Added** :meth:`Document.embfile_Upd` which allows changing **file \"\n\"content and metadata** of an embedded file. It supersedes the old method \"\n\":meth:`Document.embfile_SetInfo` (which will be deleted in a future \"\n\"version). Content is automatically compressed and metadata may be \"\n\"unicode.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2473 8741c8c5503e49c5a9e436d200d0c70c\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_Add` to now automatically compress \"\n\"file content. Accompanying metadata can now be unicode (had to be ASCII \"\n\"in the past).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2474 c8825e3ce49940899586673a8c1ca760\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_Del` to now automatically delete \"\n\"**all entries** having the supplied identifying name. The return code is \"\n\"now an integer count of the removed entries (was *None* previously).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2475 4958c06f7c0b4eaca87af2482582ca8c\nmsgid \"\"\n\"**Changed** embedded file methods to now also accept or show the PDF \"\n\"unicode filename as additional parameter *ufilename*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2476 0f95f3527f1a489a9a72167a6cee97cf\nmsgid \"\"\n\"**Added** :meth:`Page.add_file_annot` which adds a new file attachment \"\n\"annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2477 14f2faf502b74997b3e11958e4ffd5dd\nmsgid \"\"\n\"**Changed** :meth:`Annot.fileUpd` (file attachment annot) to now also \"\n\"accept the PDF unicode *ufilename* parameter. The description parameter \"\n\"*desc* correctly works with unicode. Furthermore, **all** parameters are \"\n\"optional, so metadata may be changed without also replacing the file \"\n\"content.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2478 f11e4025175f468fb362dc45b4b459a8\nmsgid \"\"\n\"**Changed** :meth:`Annot.fileInfo` (file attachment annot) to now also \"\n\"show the PDF unicode filename as parameter *ufilename*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2479 96f083ba329841dc866568603f6bf4e0\nmsgid \"\"\n\"**Fixed** issue #180 (\\\"page.getText(output='dict') return invalid \"\n\"bbox\\\") to now also work for vertical text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2480 b9c17d72bfcd4a87983f018daf4d8fd9\nmsgid \"\"\n\"**Fixed** issue #185 (\\\"Can't render the annotations created by \"\n\"PyMuPDF\\\"). The issue's cause was the minimalistic MuPDF approach when \"\n\"creating annotations. Several annotation types have no */AP* \"\n\"(\\\"appearance\\\") object when created by MuPDF functions. MuPDF, \"\n\"SumatraPDF and hence also PyMuPDF cannot render annotations without such \"\n\"an object. This fix now ensures, that an appearance object is always \"\n\"created together with the annotation itself. We still do not support line\"\n\" end styles.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2484 17b80da49d874916b1fa04cbc2e8225e\nmsgid \"**Changes in Version 1.13.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2486 16cf3df1aa764ac99837e6ba6929de3a\nmsgid \"\"\n\"**Fixed** issue #180 (\\\"page.getText(output='dict') return invalid \"\n\"bbox\\\"). Note that this is a circumvention of an MuPDF error, which \"\n\"generates zero-height character rectangles in some cases. When this \"\n\"happens, this fix ensures a bbox height of at least fontsize.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2487 61159291a2db420095ce281675ae121e\nmsgid \"\"\n\"**Changed** for ListBox and ComboBox widgets, the attribute list of \"\n\"selectable values has been renamed to :attr:`Widget.choice_values`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2488 bab6778e8c2944089f3b525aa8b0827d\nmsgid \"\"\n\"**Changed** when adding widgets, any missing of the :ref:`Base-14-Fonts` \"\n\"is automatically added to the PDF. Widget text fonts can now also be \"\n\"chosen from existing widget fonts. Any specified field values are now \"\n\"honored and lead to a field with a preset value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2489 30b1813eb102490a896faa64748c1400\nmsgid \"\"\n\"**Added** :meth:`Annot.updateWidget` which allows changing existing form \"\n\"fields -- including the field value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2493 9bc92bc23e1a46ab8548886763c96d47\nmsgid \"**Changes in Version 1.13.11**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2495 474a1a3d16e74ac7bcfe223ce5d3daad\nmsgid \"\"\n\"While the preceeding patch subversions only contained various fixes, this\"\n\" version again introduces major new features:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2497 5edc44b1ecc84b25be1507861ce353f4\nmsgid \"\"\n\"**Added** basic support for PDF widget annotations. You can now add PDF \"\n\"form fields of types Text, CheckBox, ListBox and ComboBox. Where \"\n\"necessary, the PDF is tranformed to a Form PDF with the first added \"\n\"widget.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2498 1a904dc65fe64ade80e693aa4edb88ae\nmsgid \"\"\n\"**Fixed** issues #176 (\\\"wrong file embedding\\\"), #177 (\\\"segment fault \"\n\"when invoking page.getText()\\\")and #179 (\\\"Segmentation fault using \"\n\"page.getLinks() on encrypted PDF\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2503 7b2a31d79daa40d497d99853e692f397\nmsgid \"**Changes in Version 1.13.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2505 445d2b1c88854acbb84fecfeeb62cdc1\nmsgid \"\"\n\"**Added** support of variable page sizes for reflowable documents \"\n\"(e-books, HTML, etc.): new parameters *rect* and *fontsize* in \"\n\":ref:`Document` creation (open), and as a separate method \"\n\":meth:`Document.layout`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2506 b16382d708314b4c9ed3ac5b10f9a517\nmsgid \"\"\n\"**Added** :ref:`Annot` creation of many annotations types: sticky notes, \"\n\"free text, circle, rectangle, line, polygon, polyline and text markers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2507 1444d852579b4d93837b7fe871afbf81\nmsgid \"\"\n\"**Added** support of annotation transparency (:attr:`Annot.opacity`, \"\n\":meth:`Annot.setOpacity`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2508 d544fe252c1f408785338b846f68eb33\nmsgid \"\"\n\"**Changed** :attr:`Annot.vertices`: point coordinates are now grouped as \"\n\"pairs of floats (no longer as separate floats).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2509 d7dd102d5d974b77a860d4ee2a960da8\nmsgid \"\"\n\"**Changed** annotation colors dictionary: the two keys are now named \"\n\"*\\\"stroke\\\"* (formerly *\\\"common\\\"*) and *\\\"fill\\\"*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2510 8ba3ff12895543d4b2b60a1b9a3646d4\nmsgid \"\"\n\"**Added** :attr:`Document.isDirty` which is *True* if a PDF has been \"\n\"changed in this session. Reset to *False* on each :meth:`Document.save` \"\n\"or :meth:`Document.write`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2514 572be3e137d346d1bc831219977e2a47\nmsgid \"**Changes in Version 1.13.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2516 32c7a915842343e78b6da4d29061d488\nmsgid \"\"\n\"Fix #173: for memory-resident documents, ensure the stream object will \"\n\"not be garbage-collected by Python before document is closed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2520 dfb8278835404213b0f3e00e10fa6f44\nmsgid \"**Changes in Version 1.13.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2522 d0f227e259ff4badbddfa8bc99f77761\nmsgid \"\"\n\"New low-level method :meth:`Page._setContents` defines an object given by\"\n\" its :data:`xref` to serve as the :data:`contents` object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2523 f305bdd0987e4a1f95ef94714cb586b7\nmsgid \"\"\n\"Changed and extended PDF form field support: the attribute *widget_text* \"\n\"has been renamed to :attr:`Annot.widget_value`. Values of all form field \"\n\"types (except signatures) are now supported. A new attribute \"\n\":attr:`Annot.widget_choices` contains the selectable values of listboxes \"\n\"and comboboxes. All these attributes now contain *None* if no value is \"\n\"present.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2527 4fd769eb21f048a19b8230f7e72178ca\nmsgid \"**Changes in Version 1.13.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2529 53ed864ab32f470bb28b858354a50e08\nmsgid \"\"\n\":meth:`Document.convertToPDF` now supports page ranges, reverted page \"\n\"sequences and page rotation. If the document already is a PDF, an \"\n\"exception is raised.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2530 76b57e7db1504c5aba637f3c1da9e11c\nmsgid \"\"\n\"Fixed a bug (introduced with v1.13.0) that prevented \"\n\":meth:`Page.insertImage` for transparent images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2534 2ee92c34815a4f8fb2c8e58d119f4ea1\nmsgid \"**Changes in Version 1.13.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2536 b6964dbe69ac4c14913e804c1db84219\nmsgid \"\"\n\"Introduces a way to convert **any MuPDF supported document** to a PDF. If\"\n\" you ever wanted PDF versions of your XPS, EPUB, CBZ or FB2 files -- here\"\n\" is a way to do this.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2538 3b8c44dc6cc2424186ca83fb933f4d4d\nmsgid \"\"\n\":meth:`Document.convertToPDF` returns a Python *bytes* object in PDF \"\n\"format. Can be opened like normal in PyMuPDF, or be written to disk with \"\n\"the *\\\".pdf\\\"* extension.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2542 a74fa53b1f63473e95f8ae83eadc426f\nmsgid \"**Changes in Version 1.13.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2544 7ebed477136d45edbc0674eaaa9dff08\nmsgid \"\"\n\"The major enhancement is PDF form field support. Form fields are \"\n\"annotations of type *(19, 'Widget')*. There is a new document method to \"\n\"check whether a PDF is a form. The :ref:`Annot` class has new properties \"\n\"describing field details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2546 6224991d69044aed91933c6ef3db8872\nmsgid \"\"\n\":attr:`Document.is_form_pdf` is true if object type */AcroForm* and at \"\n\"least one form field exists.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2547 3c3eddc4ca6a41179dba2d970ae478cf\nmsgid \"\"\n\":attr:`Annot.widget_type`, :attr:`Annot.widget_text` and \"\n\":attr:`Annot.widget_name` contain the details of a form field (i.e. a \"\n\"\\\"Widget\\\" annotation).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2551 33caa17db3314e8f8ec675dfcc887087\nmsgid \"**Changes in Version 1.13.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2553 9344a01be7c64abbbe4577c065593441\nmsgid \"\"\n\":meth:`TextPage.extractDICT` is a new method to extract the contents of a\"\n\" document page (text and images). All document types are supported as \"\n\"with the other :ref:`TextPage` *extract*()* methods. The returned object \"\n\"is a dictionary of nested lists and other dictionaries, and **exactly \"\n\"equal** to the JSON-deserialization of the old \"\n\":meth:`TextPage.extractJSON`. The difference is that the result is \"\n\"created directly -- no JSON module is used. Because the user needs no \"\n\"JSON module to interpet the information, it should be easier to use, and \"\n\"also have a better performance, because it contains images in their \"\n\"original **binary format** -- they need not be base64-decoded.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2554 a0c4ad5a3c484f91ac0a8e10f14f5e12\nmsgid \"\"\n\":meth:`Page.getText` correspondingly supports the new parameter value \"\n\"*\\\"dict\\\"* to invoke the above method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2555 093f2f8fbd7d47c8a423fd962433aaf6\nmsgid \"\"\n\":meth:`TextPage.extractJSON` (resp. *Page.getText(\\\"json\\\")*) is still \"\n\"supported for convenience, but its use is expected to decline.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2559 0502f4342d864193843c189056a3f649\nmsgid \"**Changes in Version 1.13.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2561 a1fd3f8dcf7347f0b02e341033bab447\nmsgid \"\"\n\"This version is based on MuPDF v1.13.0. This release is \\\"primarily a bug\"\n\" fix release\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2563 f6293a0c60534e0aa61af056ce5873ab\nmsgid \"\"\n\"In PyMuPDF, we are also doing some bug fixes while introducing minor \"\n\"enhancements. There only very minimal changes to the user's API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2565 112b9e394ace4296b2004b9cc2566a4c\nmsgid \"\"\n\":ref:`Document` construction is more flexible: the new *filetype* \"\n\"parameter allows setting the document type. If specified, any extension \"\n\"in the filename will be ignored. More completely addresses `issue #156 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/156>`_. As part of this, the \"\n\"documentation has been reworked.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2569 1fd37787dc5e4b74860ae968de485c3a\nmsgid \"Changes to :ref:`Pixmap` constructors:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2568 b1dfea15e23f480e9294338557073269\nmsgid \"\"\n\"Colorspace conversion no longer allows dropping the alpha channel: source\"\n\" and target **alpha will now always be the same**. We have seen \"\n\"exceptions and even interpreter crashes when using *alpha = 0*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2569 d13b23318d24436a98e726ab0c700090\nmsgid \"As a replacement, the simple pixmap copy lets you choose the target alpha.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2571 1245466299bd401c91dede79edbe0761\nmsgid \"\"\n\":meth:`Document.save` again offers the full garbage collection range 0 \"\n\"thru 4. Because of a bug in :data:`xref` maintenance, we had to \"\n\"temporarily enforce *garbage > 1*. Finally resolves `issue #148 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/148>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2573 5e0acf1f4a8b4284b68c4664d8506094\nmsgid \"\"\n\":meth:`Document.save` now offers to \\\"prettify\\\" PDF source via an \"\n\"additional argument.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2574 696c719c11ba4d4f8436604179238f4f\nmsgid \"\"\n\":meth:`Page.insertImage` has the additional *stream* \\\\-parameter, \"\n\"specifying a memory area holding an image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2576 083d9194c33f41068f0776f565c79c87\nmsgid \"\"\n\"Issue with garbled PNGs on Linux systems has been resolved (`\\\"Problem \"\n\"writing PNG\\\" #133) <https://github.com/pymupdf/PyMuPDF/issues/133>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2581 98cc7e1927894f43bd5433b0231b3dcf\nmsgid \"**Changes in Version 1.12.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2583 7611c52e40a247d499880fc162bf20bb\nmsgid \"This is an extension of 1.12.3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2585 55de61bfb5954f95b17921dcd4914391\nmsgid \"\"\n\"Fix of `issue #147 <https://github.com/pymupdf/PyMuPDF/issues/147>`_: \"\n\"methods :meth:`Document.getPageFontlist` and \"\n\":meth:`Document.getPageImagelist` now also show fonts and images \"\n\"contained in :data:`resources` nested via \\\"Form XObjects\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2586 241a50f48e4b403481f23435638646e1\nmsgid \"\"\n\"Temporary fix of `issue #148 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/148>`_: Saving to new PDF \"\n\"files will now automatically use *garbage = 2* if a lower value is given.\"\n\" Final fix is to be expected with MuPDF's next version. At that point we \"\n\"will remove this circumvention.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2587 d1aeb27a9161455f91a41a0c53d1de52\nmsgid \"\"\n\"Preventive fix of illegally using stencil / image mask pixmaps in some \"\n\"methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2588 4d9f3bf7e9db4f75a524f3e201db2d32\nmsgid \"\"\n\"Method :meth:`Document.getPageFontlist` now includes the encoding name \"\n\"for each font in the list.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2589 da72830c7d2c40009f927c37bd604e55\nmsgid \"\"\n\"Method :meth:`Document.getPageImagelist` now includes the decode method \"\n\"name for each image in the list.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2593 b3c6fae68a704c8eb5f4e78304a1d854\nmsgid \"**Changes in Version 1.12.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2595 4c52faae63874d45873aa766f417ab6f\nmsgid \"This is an extension of 1.12.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2597 943612aea06749f4962d1ced1418925a\nmsgid \"\"\n\"Many functions now return *None* instead of *0*, if the result has no \"\n\"other meaning than just indicating successful execution \"\n\"(:meth:`Document.close`, :meth:`Document.save`, :meth:`Document.select`, \"\n\":meth:`Pixmap.save` and many others).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2601 6f0d4e2bdd41401d94ed4fe0fd9ec7e8\nmsgid \"**Changes in Version 1.12.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2603 630bed92f4e34421925b88efe1ba42b6\nmsgid \"This is an extension of 1.12.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2605 50a351aa4579484893c9094cda2cfeba\nmsgid \"\"\n\"Method :meth:`Page.show_pdf_page` now accepts the new *clip* argument. \"\n\"This specifies an area of the source page to which the display should be \"\n\"restricted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2607 80570d982b004e41989292ba7bb4ddb9\nmsgid \"\"\n\"New :attr:`Page.CropBox` and :attr:`Page.MediaBox` have been included for\"\n\" convenience.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2612 54fd6f1c51e04778bac0835de4f0361a\nmsgid \"**Changes in Version 1.12.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2614 db11fc420c4b4bd59ba30cf2a4f190d3\nmsgid \"This is an extension of version 1.12.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2616 82affdfbc4bb42ccabe2c77070a11719\nmsgid \"\"\n\"New method :meth:`Page.show_pdf_page` displays another's PDF page. This \"\n\"is a **vector** image and therefore remains precise across zooming. Both \"\n\"involved documents must be PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2618 f0e7a4343cf14d058e07063707db7b7e\nmsgid \"\"\n\"New method :meth:`Page.getSVGimage` creates an SVG image from the page. \"\n\"In contrast to the raster image of a pixmap, this is a vector image \"\n\"format. The return is a unicode text string, which can be saved in a \"\n\"*.svg* file.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2620 c81d51dc94f646fda815c43c09bab73d\nmsgid \"\"\n\"Method :meth:`Page.getTextBlocks` now accepts an additional bool \"\n\"parameter \\\"images\\\". If set to true (default is false), image blocks \"\n\"(metadata only) are included in the produced list and thus allow \"\n\"detecting areas with rendered images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2622 5eafe44f47b34527bfff5138b15affd3\nmsgid \"Minor bug fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2624 6bf7252d584b4c8e9b97592fc0d934e4\nmsgid \"\"\n\"\\\"text\\\" result of :meth:`Page.getText` concatenates all lines within a \"\n\"block using a single space character. MuPDF's original uses \\\"\\\\\\\\n\\\" \"\n\"instead, producing a rather ragged output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2626 94bf5fb0e50249e78857f02ebaaff525\nmsgid \"\"\n\"New properties of :ref:`Page` objects :attr:`Page.MediaBoxSize` and \"\n\":attr:`Page.CropBoxPosition` provide more information about a page's \"\n\"dimensions. For non-PDF files (and for most PDF files, too) these will be\"\n\" equal to :attr:`Page.rect.bottom_right`, resp. \"\n\":attr:`Page.rect.top_left`. For example, class :ref:`Shape` makes use of \"\n\"them to correctly position its items.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2630 74d15ecb1b914538a684a22683984be7\nmsgid \"**Changes in Version 1.12.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2632 ac50d19ead2044d4afef9637fadb68d5\nmsgid \"\"\n\"This version is based on and requires MuPDF v1.12.0. The new MuPDF \"\n\"version contains quite a number of changes -- most of them around text \"\n\"extraction. Some of the changes impact the programmer's API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2634 1b465153b5814abe8ed0d412684e1e54\nmsgid \"\"\n\":meth:`Outline.saveText` and :meth:`Outline.saveXML` have been deleted \"\n\"without replacement. You probably haven't used them much anyway. But if \"\n\"you are looking for a replacement: the output of :meth:`Document.get_toc`\"\n\" can easily be used to produce something equivalent.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2636 b2b48a42c44c4a1dab5f5c66edaf406a\nmsgid \"Class *TextSheet* does no longer exist.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2638 f6faca5ccc3b4ddab529d2c73f600396\nmsgid \"\"\n\"Text \\\"spans\\\" (one of the hierarchy levels of :ref:`TextPage`) no longer\"\n\" contain positioning information (i.e. no \\\"bbox\\\" key). Instead, spans \"\n\"now provide the font information for its text. This impacts our JSON \"\n\"output variant.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2640 cc737a16a9114bea9f2892a3d611d32f\nmsgid \"\"\n\"HTML output has improved very much: it now creates valid documents which \"\n\"can be displayed by browsers to produce a similar view as the original \"\n\"document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2642 88630dce5a784283a7c487d4fd39dfe4\nmsgid \"\"\n\"There is a new output format XHTML, which provides text and images in a \"\n\"browser-readable format. The difference to HTML output is, that no effort\"\n\" is made to reproduce the original layout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2644 3af5ba7ff439426696f0f07a23e1d8fa\nmsgid \"\"\n\"All output formats of :meth:`Page.getText` now support creating complete,\"\n\" valid documents, by wrapping them with appropriate header and trailer \"\n\"information. If you are interested in using the HTML output, please make \"\n\"sure to read :ref:`HTMLQuality`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2646 87e42d9c77a54890af57f976c5071ba7\nmsgid \"\"\n\"To support finding text positions, we have added special methods that \"\n\"don't need detours like :meth:`TextPage.extractJSON` or \"\n\":meth:`TextPage.extractXML`: use :meth:`Page.getTextBlocks` or resp. \"\n\":meth:`Page.getTextWords` to create lists of text blocks or resp. words, \"\n\"which are accompanied by their rectangles. This should be much faster \"\n\"than the standard text extraction methods and also avoids using \"\n\"additional packages for interpreting their output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2651 239ae39492b748df849ea403ef2108f0\nmsgid \"**Changes in Version 1.11.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2653 2c6897b2b1734812a1b0c402d1ba8907\nmsgid \"This is an extension of v1.11.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2655 b024b8bd2f954e69a9f3a58c001cc2d8\nmsgid \"\"\n\"New :meth:`Page.insertFont` creates a PDF */Font* object and returns its \"\n\"object number.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2657 17bf32eed08e4af7a9235c26da714f4c\nmsgid \"\"\n\"New :meth:`Document.extractFont` extracts the content of an embedded font\"\n\" given its object number.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2659 8a06bf9858264b8aaddd5dcc4b335cca\nmsgid \"\"\n\"Methods **FontList(...)** items no longer contain the PDF generation \"\n\"number. This value never had any significance. Instead, the font file \"\n\"extension is included (e.g. \\\"pfa\\\" for a \\\"PostScript Font for ASCII\\\"),\"\n\" which is more valuable information.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2661 f45d17bd4282467ca8855a3a25ae091d\nmsgid \"Fonts other than \\\"simple fonts\\\" (Type1) are now also supported.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2663 18c58364a89d48b6aa981d0c901c91ea\nmsgid \"New options to change :ref:`Pixmap` size:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2665 399900b7d04b4cda9bdb0645844fa951\nmsgid \"Method :meth:`Pixmap.shrink` reduces the pixmap proportionally in place.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2667 3c624215a18b4ee5acf3b3f95f7d3b8f\nmsgid \"\"\n\"A new :ref:`Pixmap` copy constructor allows scaling via setting target \"\n\"width and height.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2672 787726e4ea8e4f998d5c45f15750e062\nmsgid \"**Changes in Version 1.11.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2674 3f97c63d1ab042b0938270157fe47048\nmsgid \"This is an extension of v1.11.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2676 51d6f21f07544106b1652c72ebc2ffe2\nmsgid \"\"\n\"New class *Shape*. It facilitates and extends the creation of image \"\n\"shapes on PDF pages. It contains multiple methods for creating elementary\"\n\" shapes like lines, rectangles or circles, which can be combined into \"\n\"more complex ones and be given common properties like line width or \"\n\"colors. Combined shapes are handled as a unit and e.g. be \\\"morphed\\\" \"\n\"together. The class can accumulate multiple complex shapes and put them \"\n\"all in the page's foreground or background -- thus also reducing the \"\n\"number of updates to the page's :data:`contents` object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2678 2d4cfa604e58468ea1577f10209e6280\nmsgid \"All *Page* draw methods now use the new *Shape* class.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2680 fc7ba2646c3448c297ae41f9fadeda05\nmsgid \"\"\n\"Text insertion methods *insertText()* and *insertTextBox()* now support \"\n\"morphing in addition to text rotation. They have become part of the \"\n\"*Shape* class and thus allow text to be freely combined with graphics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2682 737fb07ba7c242ff9478cdcd66f9c5ec\nmsgid \"\"\n\"A new *Pixmap* constructor allows creating pixmap copies with an added \"\n\"alpha channel. A new method also allows directly manipulating alpha \"\n\"values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2684 8ce597ee78ed4486bbf604c79de4b733\nmsgid \"\"\n\"Binary algebraic operations with geometry objects (matrices, rectangles \"\n\"and points) now generally also support lists or tuples as the second \"\n\"operand. You can add a tuple *(x, y)* of numbers to a :ref:`Point`. In \"\n\"this context, such sequences are called \\\":data:`point_like`\\\" (resp. \"\n\":data:`matrix_like`, :data:`rect_like`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2686 5788fb7d7f784ac09ae37611ece715fa\nmsgid \"\"\n\"Geometry objects now fully support in-place operators. For example, *p /=\"\n\" m* replaces point p with *p * 1/m* for a number, or *p * ~m* for a \"\n\":data:`matrix_like` object *m*. Similarly, if *r* is a rectangle, then *r\"\n\" |= (3, 4)* is the new rectangle that also includes *fitz.Point(3, 4)*, \"\n\"and *r &= (1, 2, 3, 4)* is its intersection with *fitz.Rect(1, 2, 3, 4)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2690 34897b5e1f8042e392f5a46fcd148809\nmsgid \"**Changes in Version 1.11.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2692 d292bd8392b648e4a31cef92ae09f8b5\nmsgid \"This version is based on and requires MuPDF v1.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2694 6de44e4ec25b476cb9fc163cdece9c5f\nmsgid \"\"\n\"Though MuPDF has declared it as being mostly a bug fix version, one major\"\n\" new feature is indeed contained: support of embedded files -- also \"\n\"called portfolios or collections. We have extended PyMuPDF functionality \"\n\"to embrace this up to an extent just a little beyond the *mutool* utility\"\n\" as follows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2696 3f70b50c029542ff87e1112b28bb11f5\nmsgid \"\"\n\"The *Document* class now support embedded files with several new methods \"\n\"and one new property:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2698 1922650fdba747cd960cf08984a60150\nmsgid \"\"\n\"*embfile_Info()* returns metadata information about an entry in the list \"\n\"of embedded files. This is more than *mutool* currently provides: it \"\n\"shows all the information that was used to embed the file (not just the \"\n\"entry's name).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2699 3a1e2417a0dd47e985c0fd31c45e52fa\nmsgid \"\"\n\"*embfile_Get()* retrieves the (decompressed) content of an entry into a \"\n\"*bytes* buffer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2700 9c68f32b3ab04c2ba2849db67d9b5edc\nmsgid \"\"\n\"*embfile_Add(...)* inserts new content into the PDF portfolio. We (in \"\n\"contrast to *mutool*) **restrict** this to entries with a **new name** \"\n\"(no duplicate names allowed).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2701 274f3e1bbceb4acfb7ceb07d7a164afb\nmsgid \"\"\n\"*embfile_Del(...)* deletes an entry from the portfolio (function not \"\n\"offered in MuPDF).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2702 0a75c5b044d54d62b32f6e6a9c1bb143\nmsgid \"\"\n\"*embfile_SetInfo()* -- changes filename or description of an embedded \"\n\"file.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2703 f80bb0230db84d0fb5d130853430ffb0\nmsgid \"*embfile_Count* -- contains the number of embedded files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2705 5474da97a2ee44f59d0e2fd58ad55665\nmsgid \"\"\n\"Several enhancements deal with streamlining geometry objects. These are \"\n\"not connected to the new MuPDF version and most of them are also \"\n\"reflected in PyMuPDF v1.10.0. Among them are new properties to identify \"\n\"the corners of rectangles by name (e.g. *Rect.bottom_right*) and new \"\n\"methods to deal with set-theoretic questions like *Rect.contains(x)* or \"\n\"*IRect.intersects(x)*. Special effort focussed on supporting more \"\n\"\\\"Pythonic\\\" language constructs: *if x in rect ...* is equivalent to \"\n\"*rect.contains(x)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2707 2a7db4a61ce24c848f83c0863bad09b7\nmsgid \"\"\n\"The :ref:`Rect` chapter now has more background on empty amd infinite \"\n\"rectangles and how we handle them. The handling itself was also updated \"\n\"for more consistency in this area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2709 33aee8dea574413681caf242adf8da6a\nmsgid \"We have started basic support for **generation** of PDF content:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2711 deb4a2603a53455cb82d849ad34308aa\nmsgid \"\"\n\"*Document.insert_page()* adds a new page into a PDF, optionally \"\n\"containing some text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2712 f7497c0e1764493a945c64046add98a1\nmsgid \"*Page.insertImage()* places a new image on a PDF page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2713 59797715081c4303a9d023f624eeda19\nmsgid \"*Page.insertText()* puts new text on an existing page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2715 1e1119160b9b47b6838fe3a16078aabc\nmsgid \"\"\n\"For **FileAttachment** annotations, content and name of the attached file\"\n\" can extracted and changed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2719 b6b1a71f6e9c4006ad908aca83e94958\nmsgid \"**Changes in Version 1.10.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2721 2d15107ed72748df88b1f193e0590a28\nmsgid \"**MuPDF v1.10 Impact**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2723 bcefb5c4e9884f03a30f600abedbeb81\nmsgid \"\"\n\"MuPDF version 1.10 has a significant impact on our bindings. Some of the \"\n\"changes also affect the API -- in other words, **you** as a PyMuPDF user.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2725 50ef82a6f0904d01b9d131853ef968fe\nmsgid \"\"\n\"Link destination information has been reduced. Several properties of the \"\n\"*linkDest* class no longer contain valuable information. In fact, this \"\n\"class as a whole has been deleted from MuPDF's library and we in PyMuPDF \"\n\"only maintain it to provide compatibilty to existing code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2727 e0f444dd42e048608c890061f2205bab\nmsgid \"\"\n\"In an effort to minimize memory requirements, several improvements have \"\n\"been built into MuPDF v1.10:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2729 dd57640466d6465693ecfa9e6153edb1\nmsgid \"\"\n\"A new *config.h* file can be used to de-select unwanted features in the C\"\n\" base code. Using this feature we have been able to reduce the size of \"\n\"our binary *_fitz.o* / *_fitz.pyd* by about 50% (from 9 MB to 4.5 MB). \"\n\"When UPX-ing this, the size goes even further down to a very handy 2.3 \"\n\"MB.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2731 42d66398d41a44a099a22715ab110b6a\nmsgid \"\"\n\"The alpha (transparency) channel for pixmaps is now optional. Letting \"\n\"alpha default to *False* significantly reduces pixmap sizes (by 20% -- \"\n\"CMYK, 25% -- RGB, 50% -- GRAY). Many *Pixmap* constructors therefore now \"\n\"accept an *alpha* boolean to control inclusion of this channel. Other \"\n\"pixmap constructors (e.g. those for file and image input) create pixmaps \"\n\"with no alpha alltogether. On the downside, save methods for pixmaps no \"\n\"longer accept a *savealpha* option: this channel will always be saved \"\n\"when present. To minimize code breaks, we have left this parameter in the\"\n\" call patterns -- it will just be ignored.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2733 58b3832200ca448a9f2942f1ec5f30d9\nmsgid \"\"\n\"*DisplayList* and *TextPage* class constructors now **require the \"\n\"mediabox** of the page they are referring to (i.e. the *page.bound()* \"\n\"rectangle). There is no way to construct this information from other \"\n\"sources, therefore a source code change cannot be avoided in these cases.\"\n\" We assume however, that not many users are actually employing these \"\n\"rather low level classes explixitely. So the impact of that change should\"\n\" be minor.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2735 01de368016c141b1b2553cd585883f58\nmsgid \"**Other Changes compared to Version 1.9.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2737 df26434942574d7da8fc1befaf6d049e\nmsgid \"\"\n\"The new :ref:`Document` method *write()* writes an opened PDF to memory \"\n\"(as opposed to a file, like *save()* does).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2738 5190f090e6f84628be18a2e1c9fd43df\nmsgid \"\"\n\"An annotation can now be scaled and moved around on its page. This is \"\n\"done by modifying its rectangle.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2739 0eb2ec9314ee488196226314519b9129\nmsgid \"\"\n\"Annotations can now be deleted. :ref:`Page` contains the new method \"\n\"*deleteAnnot()*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2740 99724b99bd0548eaa19c8c85f41c3b21\nmsgid \"\"\n\"Various annotation attributes can now be modified, e.g. content, dates, \"\n\"title (= author), border, colors.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2741 d958d6b52dd140669174995b9aa48a2c\nmsgid \"\"\n\"Method *Document.insert_pdf()* now also copies annotations of source \"\n\"pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2742 a77b60cbc9834c8885e873395b2e5293\nmsgid \"\"\n\"The *Pages* class has been deleted. As documents can now be accessed with\"\n\" page numbers as indices (like *doc[n] = doc.loadPage(n)*), and document \"\n\"object can be used as iterators, the benefit of this class was too low to\"\n\" maintain it. See the following comments.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2743 8310daf4e1854f8d93f3fccbab7b350f\nmsgid \"\"\n\"*loadPage(n)* / *doc[n]* now accept arbitrary integers to specify a page \"\n\"number, as long as *n < pageCount*. So, e.g. *doc[-500]* is always valid \"\n\"and will load page *(-500) % pageCount*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2744 1204cbb1b1c544fb9e21c114bb1d1ba0\nmsgid \"\"\n\"A document can now also be used as an iterator like this: *for page in \"\n\"doc: ...<do something with \\\"page\\\"> ...*. This will yield all pages of \"\n\"*doc* as *page*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2745 638b89cc45b748c1871ca2d5aead5130\nmsgid \"\"\n\"The :ref:`Pixmap` method *getSize()* has been replaced with property \"\n\"*size*. As before *Pixmap.size == len(Pixmap)* is true.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2746 08362ae590bb4f6d909e17c344eac186\nmsgid \"\"\n\"In response to transparency (alpha) being optional, several new \"\n\"parameters and properties have been added to :ref:`Pixmap` and \"\n\":ref:`Colorspace` classes to support determining their characteristics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2747 26af3ec444444862b651b0a46668621b\nmsgid \"\"\n\"The :ref:`Page` class now contains new properties *firstAnnot* and \"\n\"*firstLink* to provide starting points to the respective class chains, \"\n\"where *firstLink* is just a mnemonic synonym to method *loadLinks()* \"\n\"which continues to exist. Similarly, the new property *rect* is a synonym\"\n\" for method *bound()*, which also continues to exist.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2748 ded24a5038154723bb3341c82e3cbf85\nmsgid \"\"\n\":ref:`Pixmap` methods *samplesRGB()* and *samplesAlpha()* have been \"\n\"deleted because pixmaps can now be created without transparency.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2749 0f12d21dba014e89b8c28b88440ddf0d\nmsgid \"\"\n\":ref:`Rect` now has a property *irect* which is a synonym of method \"\n\"*round()*. Likewise, :ref:`IRect` now has property *rect* to deliver a \"\n\":ref:`Rect` which has the same coordinates as floats values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2750 30d1287837f24dc3b01d070c0235a6b3\nmsgid \"\"\n\"Document has the new method *searchPageFor()* to search for a text \"\n\"string. It works exactly like the corresponding *Page.searchFor()* with \"\n\"page number as additional parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2755 efde2cd3f108453c92668ab6680d8c22\nmsgid \"**Changes in Version 1.9.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2757 0ea28511a44f47cbabd5e1818b9aa8aa\nmsgid \"\"\n\"This version is also based on MuPDF v1.9a. Changes compared to version \"\n\"1.9.2:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2759 4e290039221648db96c98c392772b446\nmsgid \"\"\n\"As a major enhancement, annotations are now supported in a similar way as\"\n\" links. Annotations can be displayed (as pixmaps) and their properties \"\n\"can be accessed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2760 9b2336cd5062432881d29cf06440709d\nmsgid \"\"\n\"In addition to the document *select()* method, some simpler methods can \"\n\"now be used to manipulate a PDF:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2762 8d2322bb4a7d4981a30ae2ec5a2cbdb0\nmsgid \"*copyPage()* copies a page within a document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2763 b7683db8abd54cb09161d5edf19f4bd3\nmsgid \"*movePage()* is similar, but deletes the original.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2764 a4c469e758a1452bb9ab330b06d00638\nmsgid \"*delete_page()* deletes a page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2765 edfd6b26956f4fbfbe96ae5f0b82abd1\nmsgid \"*delete_pages()* deletes a page range\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2767 39a894ab055d4710b6bd443c6df69890\nmsgid \"\"\n\"*rotation* or *setRotation()* access or change a PDF page's rotation, \"\n\"respectively.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2768 4c32f65b4b694d6bb428aa23ca44e50a\nmsgid \"\"\n\"Available but undocumented before, :ref:`IRect`, :ref:`Rect`, \"\n\":ref:`Point` and :ref:`Matrix` support the *len()* method and their \"\n\"coordinate properties can be accessed via indices, e.g. *IRect.x1 == \"\n\"IRect[2]*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2769 f60011476e35442c8866a3831c378b54\nmsgid \"\"\n\"For convenience, documents now support simple indexing: *doc.loadPage(n) \"\n\"== doc[n]*. The index may however be in range *-pageCount < n < \"\n\"pageCount*, such that *doc[-1]* is the last page of the document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2773 b923307f30254e48ba8f3dfb4835b05a\nmsgid \"**Changes in Version 1.9.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2775 6449dd561a1d46078eff4b1c6983b1ae\nmsgid \"\"\n\"This version is also based on MuPDF v1.9a. Changes compared to version \"\n\"1.9.1:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2777 f9a699d3f70e4d6caed1fb3017bf1f0b\nmsgid \"\"\n\"*fitz.open()* (no parameters) creates a new empty **PDF** document, i.e. \"\n\"if saved afterwards, it must be given a *.pdf* extension.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2778 6d6ed72ba57c49cab25dd46b125a7992\nmsgid \"\"\n\":ref:`Document` now accepts all of the following formats (*Document* and \"\n\"*open* are synonyms):\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2780 a3a89203f10e4adeb3cfe637ceb6fdff\nmsgid \"*open()*,\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2781 adac8cae62784b188b7532c740bb1379\nmsgid \"*open(filename)* (equivalent to *open(filename, None)*),\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2782 5d35476e5dcf46248458a566565f6b6f\nmsgid \"*open(filetype, area)* (equivalent to *open(filetype, stream = area)*).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2784 2fdc6dd492a14cc68fa4d2de4e051cfc\nmsgid \"\"\n\"Type of memory area *stream* may be *bytes* or *bytearray*. Thus, e.g. \"\n\"*area = open(\\\"file.pdf\\\", \\\"rb\\\").read()* may be used directly (without \"\n\"first converting it to bytearray).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2785 ad12c912ac3247a4a7c774429b01c39b\nmsgid \"\"\n\"New method *Document.insert_pdf()* (PDFs only) inserts a range of pages \"\n\"from another PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2786 93f16447ec77443ba90329b70366c78f\nmsgid \"\"\n\"*Document* objects doc now support the *len()* function: ``len(doc) == \"\n\"doc.pageCount``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2787 b9dfdd6106944a0ab643f64882fa6526\nmsgid \"\"\n\"New method *Document.getPageImageList()* creates a list of images used on\"\n\" a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2788 f2906fa3f14c4f93bddbe0029d43681f\nmsgid \"\"\n\"New method *Document.getPageFontList()* creates a list of fonts \"\n\"referenced by a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2789 a053e3c6bd69480aa1a4639e8522af69\nmsgid \"\"\n\"New pixmap constructor *fitz.Pixmap(doc, xref)* creates a pixmap based on\"\n\" an opened PDF document and an :data:`xref` number of the image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2790 9dfdd7f9d9b14e15963c179646bcbbeb\nmsgid \"\"\n\"New pixmap constructor *fitz.Pixmap(cspace, spix)* creates a pixmap as a \"\n\"copy of another one *spix* with the colorspace converted to *cspace*. \"\n\"This works for all colorspace combinations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2791 2a61334e5c304e09a3efe93e1daf2a53\nmsgid \"\"\n\"Pixmap constructor *fitz.Pixmap(colorspace, width, height, samples)* now \"\n\"allows *samples* to also be *bytes*, not only *bytearray*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2796 b95080e967b24b66ae4b63c42d239889\nmsgid \"**Changes in Version 1.9.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2798 9273e10701d143069e9c0424e4b6bded\nmsgid \"\"\n\"This version of PyMuPDF is based on MuPDF library source code version \"\n\"1.9a published on April 21, 2016.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2800 517fc4042ed6446e9e7457b0f69e8504\nmsgid \"\"\n\"Please have a look at MuPDF's website to see which changes and \"\n\"enhancements are contained herein.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2802 c70db83bdb1d48d198e4344cae4de7b5\nmsgid \"Changes in version 1.9.1 compared to version 1.8.0 are the following:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2804 0d6385d834804b7d9b0ab1c6ef0d85b8\nmsgid \"New methods *get_area()* for both *fitz.Rect* and *fitz.IRect*\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2805 85fda6915f8c488cb6fbe936f1ea49ab\nmsgid \"\"\n\"Pixmaps can now be created directly from files using the new constructor \"\n\"*fitz.Pixmap(filename)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2806 d92fe0f7f8304a5190d37c53f89f3a24\nmsgid \"The Pixmap constructor *fitz.Pixmap(image)* has been extended accordingly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2807 cdaceee4b768492e9110c3d0cd75e175\nmsgid \"\"\n\"*fitz.Rect* can now be created with all possible combinations of points \"\n\"and coordinates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2808 03f45a90666540d8b5cb4c257457b006\nmsgid \"\"\n\"PyMuPDF classes and methods now all contain  __doc__ strings,  most of \"\n\"them created by SWIG automatically. While the PyMuPDF documentation \"\n\"certainly is more detailed, this feature should help a lot when \"\n\"programming in Python-aware IDEs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2809 2ddafe376f5e4f4e9ac5c3db523eea26\nmsgid \"\"\n\"A new document method of *getPermits()* returns the permissions \"\n\"associated with the current access to the document (print, edit, \"\n\"annotate, copy), as a Python dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2810 38dbe8d276f348d6b76c6d0a15d0676f\nmsgid \"The identity matrix *fitz.Identity* is now **immutable**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2811 fa0425c7b7b04f0bb7c04eec634e2756\nmsgid \"\"\n\"The new document method *select(list)* removes all pages from a document \"\n\"that are not contained in the list. Pages can also be duplicated and re-\"\n\"arranged.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2812 3c561ea70df341be88b491b64dc6f313\nmsgid \"\"\n\"Various improvements and new members in our demo and examples \"\n\"collections. Perhaps most prominently: *PDF_display* now supports \"\n\"scrolling with the mouse wheel, and there is a new example program \"\n\"*wxTableExtract* which allows to graphically identify and extract table \"\n\"data in documents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2813 4d9bea8a8e514d67958c633b66ca31fb\nmsgid \"*fitz.open()* is now an alias of *fitz.Document()*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2814 f62c2e04dea346d0a23964798a6150e8\nmsgid \"\"\n\"New pixmap method *tobytes()* which will return a bytearray formatted as \"\n\"a PNG image of the pixmap.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2815 691532d03793437899a4b59421388b4c\nmsgid \"\"\n\"New pixmap method *samplesRGB()* providing a *samples* version with alpha\"\n\" bytes stripped off (RGB colorspaces only).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2816 2780806eef3f43b28a7e9601a270e9f2\nmsgid \"\"\n\"New pixmap method *samplesAlpha()* providing the alpha bytes only of the \"\n\"*samples* area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2817 21fbef3bc0e64a59a9a9b9f5005063e8\nmsgid \"New iterator *fitz.Pages(doc)* over a document's set of pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2818 707a5edabf3e4c3cbb66ed5d280d40ae\nmsgid \"\"\n\"New matrix methods *invert()* (calculate inverted matrix), *concat()* \"\n\"(calculate matrix product), *pretranslate()* (perform a shift operation).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2819 cc8cea5eaf77474aa84e90031d6f3318\nmsgid \"\"\n\"New *IRect* methods *intersect()* (intersection with another rectangle), \"\n\"*translate()* (perform a shift operation).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2820 893b259908084462b3a1a85629a6ee06\nmsgid \"\"\n\"New *Rect* methods *intersect()* (intersection with another rectangle), \"\n\"*transform()* (transformation with a matrix), *include_point()* (enlarge \"\n\"rectangle to also contain a point), *include_rect()* (enlarge rectangle \"\n\"to also contain another one).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2821 21838e58f15b4457816e55450382ccb9\nmsgid \"Documented *Point.transform()* (transform a point with a matrix).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2822 3f2842cba4c044eb99d8d250d9f84740\nmsgid \"\"\n\"*Matrix*, *IRect*, *Rect* and *Point* classes now support compact, \"\n\"algebraic formulations for manipulating such objects.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2823 bb13c21e58c14cf59f36e99322166ac4\nmsgid \"\"\n\"Incremental saves for changes are possible now using the call pattern \"\n\"*doc.save(doc.name, incremental=True)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2824 34093067a0274622aa66ca0e40f20da0\nmsgid \"\"\n\"A PDF's metadata can now be deleted, set or changed by document method \"\n\"*set_metadata()*. Supports incremental saves.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2825 0e2f9f83f2244178a0772a7f0de76b0d\nmsgid \"\"\n\"A PDF's bookmarks (or table of contents) can now be deleted, set or \"\n\"changed with the entries of a list using document method *set_toc(list)*.\"\n\" Supports incremental saves.\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 0555f8605d724eadbe65f9eb27755b4f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"\"\n\n#~ msgid \"**Changes in version 1.23.0rc1 (2023-08-10)**\"\n#~ msgstr \"\"\n\n#~ msgid \"Contains a new \\\"rebased\\\" implementation of PyMuPDF.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `#2542 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/2542>`_: \"\n#~ \"fritz.utils.scrub AttributeError Annot object \"\n#~ \"has no attribute fileUpd inside\"\n#~ msgstr \"\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Other: * Use MuPDF-1.23.4. * Fix \"\n#~ \"optimisation flags with system installs. \"\n#~ \"* Fixed the problem that the clip\"\n#~ \" parameter does not take effect \"\n#~ \"during table recognition * Support \"\n#~ \"Pillow mode \\\"RGBa\\\" * Support extra \"\n#~ \"word delimiters * Support checking valid\"\n#~ \" PDF name objects\"\n#~ msgstr \"\"\n\n#~ msgid \"**Changes in version 1.24.3 (2024-04-xx)**\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `3180 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/3180>`_: Cannot \"\n#~ \"show optional content group: AttributeError:\"\n#~ \" module 'pymupdf.mupdf' has no attribute\"\n#~ \" 'pdf_array_push_drop'\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `3163 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/3163>`_: \"\n#~ \"AssertionError on using pymupdf.IRect\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `3177 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/3177>`_: \"\n#~ \"pymupdf.Pixmap(None, pix) Unrecognised args \"\n#~ \"for constructing Pixmap\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `2978 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/2978>`_: 1.23.9rc1:\"\n#~ \" module 'pymupdf.mupdf' has no attribute\"\n#~ \" 'fz_copy_pixmap_rect'\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Fixed rebased `pymupdf.pymupdf_version_tuple` - \"\n#~ \"was previously set to mupdf version.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Added test for `pymupdf.css_for_pymupdf_font()` \"\n#~ \"(uses package `pymupdf-fonts`).\"\n#~ msgstr \"\"\n\n#~ msgid \"Added `pymupdf.pymupdf_version_tuple`, e.g. `(1, 23, 6)`.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `2548 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/2548>`_: Fitz \"\n#~ \"freezes on some PDFs when calling \"\n#~ \"the pymupdf.Page.get_text_blocks method.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `#2542 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/2542>`_: \"\n#~ \"pymupdf.utils.scrub AttributeError Annot object \"\n#~ \"has no attribute fileUpd inside\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `#2290 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/2290>`_: Different\"\n#~ \" image format/data from Page.get_text(\\\"dict\\\")\"\n#~ \" and pymupdf.get_page_images()\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Fixed issue where trace devices' state\"\n#~ \" was not being initialised correctly; \"\n#~ \"data returned from things like \"\n#~ \"``pymupdf.Page.get_texttrace()`` might be slightly\"\n#~ \" altered, e.g. ``linewidth`` values.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** `#2076 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/2076>`_: Segfault \"\n#~ \"in pymupdf.py\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"``EmptyFileError`` -- raised when trying \"\n#~ \"to create a :ref:`Document` \"\n#~ \"(``pymupdf.open()``) from an empty file \"\n#~ \"or zero-length memory.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** issue `#1085 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/1085>`_. The \"\n#~ \"old *snake_cased* alias of \"\n#~ \"``pymupdf.detTextlength`` is now defined \"\n#~ \"correctly.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Added** a method :meth:`paper_rect` which\"\n#~ \" returns a :ref:`Rect` for a supplied\"\n#~ \" paper format string. Example: \"\n#~ \"*pymupdf.paper_rect(\\\"letter\\\") = pymupdf.Rect(0.0, \"\n#~ \"0.0, 612.0, 792.0)*.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Geometry objects now fully support \"\n#~ \"in-place operators. For example, *p \"\n#~ \"/= m* replaces point p with *p \"\n#~ \"* 1/m* for a number, or *p *\"\n#~ \" ~m* for a :data:`matrix_like` object \"\n#~ \"*m*. Similarly, if *r* is a \"\n#~ \"rectangle, then *r |= (3, 4)* is\"\n#~ \" the new rectangle that also includes\"\n#~ \" *pymupdf.Point(3, 4)*, and *r &= (1,\"\n#~ \" 2, 3, 4)* is its intersection \"\n#~ \"with *pymupdf.Rect(1, 2, 3, 4)*.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"A new *config.h* file can be used\"\n#~ \" to de-select unwanted features in\"\n#~ \" the C base code. Using this \"\n#~ \"feature we have been able to \"\n#~ \"reduce the size of our binary \"\n#~ \"*_pymupdf.o* / *_pymupdf.pyd* by about \"\n#~ \"50% (from 9 MB to 4.5 MB). \"\n#~ \"When UPX-ing this, the size goes\"\n#~ \" even further down to a very \"\n#~ \"handy 2.3 MB.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*pymupdf.open()* (no parameters) creates a \"\n#~ \"new empty |PDF| document, i.e. if \"\n#~ \"saved afterwards, it must be given \"\n#~ \"a *.pdf* extension.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"New pixmap constructor *pymupdf.Pixmap(doc, \"\n#~ \"xref)* creates a pixmap based on \"\n#~ \"an opened PDF document and an \"\n#~ \":data:`xref` number of the image.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"New pixmap constructor *pymupdf.Pixmap(cspace, \"\n#~ \"spix)* creates a pixmap as a copy\"\n#~ \" of another one *spix* with the \"\n#~ \"colorspace converted to *cspace*. This \"\n#~ \"works for all colorspace combinations.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Pixmap constructor *pymupdf.Pixmap(colorspace, \"\n#~ \"width, height, samples)* now allows \"\n#~ \"*samples* to also be *bytes*, not \"\n#~ \"only *bytearray*.\"\n#~ msgstr \"\"\n\n#~ msgid \"New methods *get_area()* for both *pymupdf.Rect* and *pymupdf.IRect*\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Pixmaps can now be created directly \"\n#~ \"from files using the new constructor \"\n#~ \"*pymupdf.Pixmap(filename)*.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"The Pixmap constructor *pymupdf.Pixmap(image)* \"\n#~ \"has been extended accordingly.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*pymupdf.Rect* can now be created with\"\n#~ \" all possible combinations of points \"\n#~ \"and coordinates.\"\n#~ msgstr \"\"\n\n#~ msgid \"The identity matrix *pymupdf.Identity* is now **immutable**.\"\n#~ msgstr \"\"\n\n#~ msgid \"*pymupdf.open()* is now an alias of *pymupdf.Document()*.\"\n#~ msgstr \"\"\n\n#~ msgid \"New iterator *pymupdf.Pages(doc)* over a document's set of pages.\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Changed** :ref:`TextWriter` output to also\"\n#~ \" accept text in right to left \"\n#~ \"mode (Arabian, Hebrew): \"\n#~ \":meth:`TextWriter.fill_textbox`, :meth:`TextWriter.append`. \"\n#~ \"These methods now accept a new \"\n#~ \"boolean parameter `right_to_left`, which is\"\n#~ \" ``False`` by default. Implements `#897 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/897>`_.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Added** option ``text_as_path`` to \"\n#~ \":meth:`Page.getSVGimage`. this implements `#580 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/580>`_. Generates \"\n#~ \"much smaller SVG files with parseable\"\n#~ \" text if set to ``False``.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Fixed** issue `#559 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/559>`_. This \"\n#~ \"|MuPDF| bug is being temporarily fixed\"\n#~ \" with a pre-version of MuPDF's \"\n#~ \"next release.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Changed** :attr:`Document.is_form_pdf` to now \"\n#~ \"contain the number of widgets, and \"\n#~ \"``False`` if not a PDF or this \"\n#~ \"number is zero.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Changed** method :meth:`Document._getXrefStream` \"\n#~ \"to now return ``None`` if the \"\n#~ \"object is no stream and no longer\"\n#~ \" raise an exception if otherwise.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Changed** :meth:`Document.embfile_Del` to now \"\n#~ \"automatically delete **all entries** having\"\n#~ \" the supplied identifying name. The \"\n#~ \"return code is now an integer \"\n#~ \"count of the removed entries (was \"\n#~ \"``None`` previously).\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**Added** :attr:`Document.isDirty` which is \"\n#~ \"``True`` if a PDF has been changed\"\n#~ \" in this session. Reset to ``False``\"\n#~ \" on each :meth:`Document.save` or \"\n#~ \":meth:`Document.write`.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Changed and extended PDF form field \"\n#~ \"support: the attribute *widget_text* has \"\n#~ \"been renamed to :attr:`Annot.widget_value`. \"\n#~ \"Values of all form field types \"\n#~ \"(except signatures) are now supported. A\"\n#~ \" new attribute :attr:`Annot.widget_choices` \"\n#~ \"contains the selectable values of \"\n#~ \"listboxes and comboboxes. All these \"\n#~ \"attributes now contain ``None`` if no\"\n#~ \" value is present.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Many functions now return ``None`` \"\n#~ \"instead of *0*, if the result has\"\n#~ \" no other meaning than just \"\n#~ \"indicating successful execution \"\n#~ \"(:meth:`Document.close`, :meth:`Document.save`, \"\n#~ \":meth:`Document.select`, :meth:`Pixmap.save` and \"\n#~ \"many others).\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"A new ``Pixmap`` constructor allows \"\n#~ \"creating pixmap copies with an added \"\n#~ \"alpha channel. A new method also \"\n#~ \"allows directly manipulating alpha values.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"The alpha (transparency) channel for \"\n#~ \"pixmaps is now optional. Letting alpha\"\n#~ \" default to ``False`` significantly reduces\"\n#~ \" pixmap sizes (by 20% -- CMYK, \"\n#~ \"25% -- RGB, 50% -- GRAY). Many \"\n#~ \"``Pixmap`` constructors therefore now accept\"\n#~ \" an *alpha* boolean to control \"\n#~ \"inclusion of this channel. Other pixmap\"\n#~ \" constructors (e.g. those for file \"\n#~ \"and image input) create pixmaps with \"\n#~ \"no alpha alltogether. On the downside,\"\n#~ \" save methods for pixmaps no longer\"\n#~ \" accept a *savealpha* option: this \"\n#~ \"channel will always be saved when \"\n#~ \"present. To minimize code breaks, we \"\n#~ \"have left this parameter in the \"\n#~ \"call patterns -- it will just be\"\n#~ \" ignored.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"``DisplayList`` and ``TextPage`` class \"\n#~ \"constructors now **require the mediabox** \"\n#~ \"of the page they are referring to\"\n#~ \" (i.e. the *page.bound()* rectangle). There\"\n#~ \" is no way to construct this \"\n#~ \"information from other sources, therefore \"\n#~ \"a source code change cannot be \"\n#~ \"avoided in these cases. We assume \"\n#~ \"however, that not many users are \"\n#~ \"actually employing these rather low \"\n#~ \"level classes explixitely. So the impact\"\n#~ \" of that change should be minor.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*fitz.open()* (no parameters) creates a \"\n#~ \"new empty |PDF| document, i.e. if \"\n#~ \"saved afterwards, it must be given \"\n#~ \"a *.pdf* extension.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/classes.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 2a3afd4ee887482197b760f562ffccc4\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 88c2fb74c3264e88ab5b351998d6487c\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 704d5cb7888e4240b2b40aab099a2c07\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../classes.rst:5 7c00ecb7e10b4a23a407ab80742606b5\nmsgid \"Classes\"\nmsgstr \"\"\n\n#: ../../footer.rst:60 3cc655b31f5a4c8c856c90f57dbc49cf\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/colors.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 35fb650a253a4f3b8498a5be6524cf11\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 82dc5bc568734b99a2d2f57e0a4da5d0\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 546a16c6fc534b38a0db66fe761c1c61\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../colors.rst:7 248d0e17c78b4f6fa1b57235e07bb572\nmsgid \"Color Database\"\nmsgstr \"カラーデータベース\"\n\n#: ../../colors.rst:8 866762e2283b43a5a605f529de6310df\nmsgid \"\"\n\"Since the introduction of methods involving colors (like \"\n\":meth:`Page.draw_circle`), a requirement may be to have access to \"\n\"predefined colors.\"\nmsgstr \"\"\n\":meth:`Page.draw_circle`) \"\n\"のような色を含むメソッドが導入されて以来、事前定義された色にアクセスする必要があるかもしれません。）\"\n\n#: ../../colors.rst:10 03afc088d6e34acc9076fc34915e9064\nmsgid \"\"\n\"The fabulous GUI package `wxPython <https://wxpython.org/>`_ has a \"\n\"database of over 540 predefined RGB colors, which are given more or less \"\n\"memorizable names. Among them are not only standard names like \\\"green\\\" \"\n\"or \\\"blue\\\", but also \\\"turquoise\\\", \\\"skyblue\\\", and 100 (not only 50 \"\n\"...) shades of \\\"gray\\\", etc.\"\nmsgstr \"\"\n\"素晴らしいGUIパッケージ `wxPython <https://wxpython.org/>`_ \"\n\"には、記憶しやすい名前が与えられた540以上の事前定義されたRGBカラーのデータベースがあります。その中には「green」や「blue」のような標準的な名前だけでなく、「turquoise」や「skyblue」、「gray」の100のシェードなどが含まれています（50だけでなく…）。\"\n\n#: ../../colors.rst:12 7ff92a944ea44490b292556c69b2273b\nmsgid \"\"\n\"We have taken the liberty to copy this database (a list of tuples) \"\n\"modified into PyMuPDF and make its colors available as PDF compatible \"\n\"float triples: for wxPython's *(\\\"WHITE\\\", 255, 255, 255)* we return *(1,\"\n\" 1, 1)*, which can be directly used in *color* and *fill* parameters. We \"\n\"also accept any mixed case of \\\"wHiTe\\\" to find a color.\"\nmsgstr \"\"\n\"私たちは、このデータベース（タプルのリスト）をPyMuPDFにコピーし、その色をPDF互換の浮動小数点トリプルとして利用可能にしました。例えば、wxPythonの(\\\"WHITE\\\",\"\n\" 255, 255, 255)は(1, 1, 1)として返され、これは *直接色* や *塗りつぶし* \"\n\"のパラメータとして使用できます。また、「wHiTe」といった大小文字の組み合わせも受け入れます。\"\n\n#: ../../colors.rst:15 e54f7361ac594e49854f711406c08592\nmsgid \"Function *getColor()*\"\nmsgstr \"関数 *getColor()* \"\n\n#: ../../colors.rst:16 2f1966c2184a4746af35dea0735b144d\nmsgid \"\"\n\"As the color database may not be needed very often, one additional import\"\n\" statement seems acceptable to get access to it::\"\nmsgstr \"カラーデータベースはあまり頻繁に必要ないかもしれないため、アクセスするために1つの追加のインポート文は受け入れられると思われます。\"\n\n#: ../../colors.rst:41 7d1b6378ac6440948098bc91a988cb05\nmsgid \"Printing the Color Database\"\nmsgstr \"カラーデータベースの印刷\"\n\n#: ../../colors.rst:42 a5973aca56984f88bf0fe7e9e3c52644\nmsgid \"\"\n\"If you want to actually see how the many available colors look like, use \"\n\"scripts `print by RGB <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/print-rgb/print.py>`_ or `print by HSV \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/print-\"\n\"hsv/print.py>`_ in the examples directory. They create PDFs (already \"\n\"existing in the same directory) with all these colors. Their only \"\n\"difference is sorting order: one takes the RGB values, the other one the \"\n\"Hue-Saturation-Values as sort criteria. This is a screen print of what \"\n\"these files look like.\"\nmsgstr \"\"\n\"実際に利用可能な多くの色がどのように見えるかを確認したい場合は、examplesディレクトリにある `RGB印刷 \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/print-\"\n\"rgb/print.py>`_ または `HSV印刷 <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/print-hsv/print.py>`_ \"\n\"のスクリプトを使用してください。これらのスクリプトは、これらすべての色を含むPDFを作成します（すでに同じディレクトリに存在します）。これらのファイルはRGB値を使用するものと\"\n\"、ソート基準としてHue-Saturation-\"\n\"Valueを使用するものの2つの違いだけです。以下は、これらのファイルがどのように見えるかのスクリーンプリントです。\"\n\n#: ../../footer.rst:60 d448c701ca134c668840e68d45395229\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/colorspace.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4d4488c4917748bd91bcc3dd579d4cd8\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 806d51d5b25e4c2dbf32c0b904cf8d32\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 7c1c6b7e76d04443adc894e153404331\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../colorspace.rst:7 9117f6e8aa1a4dc0a4d17d89aa5543d1\nmsgid \"Colorspace\"\nmsgstr \"Colorspace (カラースペース)\"\n\n#: ../../colorspace.rst:9 9ff1e9e9281248fbbe713af3f44fa1a1\nmsgid \"Represents the color space of a :ref:`Pixmap`.\"\nmsgstr \":ref:`Pixmap` のカラースペースを表します。\"\n\n#: ../../colorspace.rst:12 b21c879680e34acdbd48605116e91b1a\nmsgid \"**Class API**\"\nmsgstr \"**クラス API** \"\n\n#: ../../colorspace.rst:18 728f2df68cff450fba89dc0e2961d0fd\nmsgid \"Constructor\"\nmsgstr \"コンストラクタ\"\n\n#: ../../colorspace.rst 89cae8192bc741d38d655d66d7b02a2c\nmsgid \"Parameters\"\nmsgstr \"パラメータ:\"\n\n#: ../../colorspace.rst:20 9ca03de683124137b4c31d0d8cedbbb3\nmsgid \"\"\n\"A number identifying the colorspace. Possible values are :data:`CS_RGB`, \"\n\":data:`CS_GRAY` and :data:`CS_CMYK`.\"\nmsgstr \"\"\n\"カラースペースを識別する番号。可能な値は :data:`CS_RGB` 、:data:`CS_GRAY` 、および :data:`CS_CMYK`\"\n\" です。\"\n\n#: ../../colorspace.rst:24 ee0b34b3c30b495c99bb627cad25b1df\nmsgid \"\"\n\"The name identifying the colorspace. Example: *pymupdf.csCMYK.name = \"\n\"'DeviceCMYK'*.\"\nmsgstr \"カラースペースを識別する名前です。例:  *pymupdf.csCMYK.name = 'DeviceCMYK'* 。\"\n\n#: ../../colorspace.rst 1dec254d03ca404d997d0b3d10053f1d\n#: 57ea4a70ca2340d6aa71a8e9824e03a8\nmsgid \"type\"\nmsgstr \"型:\"\n\n#: ../../colorspace.rst:26 0a4657c57f1d49e39feed5228f4c5d25\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../colorspace.rst:30 b3000e3e34554cb5b72ca9feabc9711c\nmsgid \"\"\n\"The number of bytes required to define the color of one pixel. Example: \"\n\"*pymupdf.csCMYK.n == 4*.\"\nmsgstr \"1ピクセルの色を定義するのに必要なバイト数です。例: *pymupdf.csCMYK.n == 4* 。\"\n\n#: ../../colorspace.rst:32 09c02be8130e4c67b7e790e38c19788f\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../colorspace.rst:35 305216fe8af54e58abf2e1fce4d6f78a\nmsgid \"**Predefined Colorspaces**\"\nmsgstr \"**事前定義済みのカラースペース** \"\n\n#: ../../colorspace.rst:37 2a6d64970b50414ca57b9df4b896c7d6\nmsgid \"\"\n\"For saving some typing effort, there exist predefined colorspace objects \"\n\"for the three available cases.\"\nmsgstr \"入力を簡略化するために、三つの利用可能なケースのための事前定義されたカラースペースオブジェクトが存在します。\"\n\n#: ../../colorspace.rst:39 acc3013bd78b41dc8fddea9d4ee301a5\nmsgid \":data:`csRGB`  = *pymupdf.Colorspace(pymupdf.CS_RGB)*\"\nmsgstr \"\"\n\n#: ../../colorspace.rst:40 5813b3b4dcbf437f8815044834076e72\nmsgid \":data:`csGRAY` = *pymupdf.Colorspace(pymupdf.CS_GRAY)*\"\nmsgstr \"\"\n\n#: ../../colorspace.rst:41 57fef72a75814b848806cf016b2c1baf\nmsgid \":data:`csCMYK` = *pymupdf.Colorspace(pymupdf.CS_CMYK)*\"\nmsgstr \"\"\n\n#: ../../footer.rst:60 e39ad3f11f894208aed37df423e4558e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/converting-files.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f8990f687e0047c89745e6b15ef5f312\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 606c02d809cb449ab8e5df484cb2149f\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 90891c93f09445feb007b8f80d447d93\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../converting-files.rst:7 153e0c6c14bf4b8bac1dcdc565ac0f16\nmsgid \"Converting Files\"\nmsgstr \"ファイルの変換\"\n\n#: ../../converting-files.rst:12 9b1bc6f3061c4fd9a084829ef7554c37\nmsgid \"Files to PDF\"\nmsgstr \"ファイルからPDFへ\"\n\n#: ../../converting-files.rst:14 38d5a093dfc24e72b3627f1a2c952515\nmsgid \"\"\n\":ref:`Document types supported by PyMuPDF<HowToOpenAFile>` can easily be \"\n\"converted to |PDF| by using the :meth:`Document.convert_to_pdf` method. \"\n\"This method returns a buffer of data which can then be utilized by \"\n\"|PyMuPDF| to create a new |PDF|.\"\nmsgstr \":ref:`PyMuPDFでサポートされているドキュメントタイプ<HowToOpenAFile>` は、:meth:`Document.convert_to_pdf` メソッドを使用することで簡単に |PDF| に変換できます。このメソッドはデータバッファを返し、それを |PyMuPDF| が利用して新しい |PDF| を作成できます。\"\n\n#: ../../converting-files.rst:18 ../../converting-files.rst:38\n#: ../../converting-files.rst:62 ../../converting-files.rst:82\n#: 2eff8f1c0f704e9d9e23a98078353847 7345723f19864e81be97447aab194cd9\n#: c3ae18efff164928b70b884d3a47caac ecdbf8cbbb2d46bc9bf312b716b264af\nmsgid \"**Example**\"\nmsgstr \"**例**\"\n\n#: ../../converting-files.rst:32 4e3eda1d4bff4593ae1f0333bcc47a5d\nmsgid \"PDF to SVG\"\nmsgstr \"PDFからSVGへ\"\n\n#: ../../converting-files.rst:34 d8f0e0e26f99486485d27038482b5558\nmsgid \"\"\n\"Technically, as SVG files cannot be multipage, we must export each page \"\n\"as an SVG.\"\nmsgstr \"技術的には、SVGファイルは複数ページを持つことができないため、各ページをSVGとしてエクスポートする必要があります。\"\n\n#: ../../converting-files.rst:36 45efc8839a1b44e9a877335aa51df1b6\nmsgid \"\"\n\"To get an SVG representation of a page use the :meth:`Page.get_svg_image`\"\n\" method.\"\nmsgstr \"ページのSVG表現を取得するには、:meth:`Page.get_svg_image` メソッドを使用します。\"\n\n#: ../../converting-files.rst:58 9249883d41654d3c8041c561743679c6\nmsgid \"PDF to Markdown\"\nmsgstr \"PDFからMarkdownへ\"\n\n#: ../../converting-files.rst:60 9d35a0dc74c742419817cfab8ac5fbb6\nmsgid \"\"\n\"By utlilizing the :doc:`PyMuPDF4LLM API <pymupdf4llm/api>` we are able to\"\n\" convert PDF to a Markdown representation.\"\nmsgstr \":doc:`PyMuPDF4LLM API <pymupdf4llm/api>` を利用することで、PDFをMarkdown表現に変換できます。\"\n\n#: ../../converting-files.rst:76 a8c608159d57471c89e55f3c44adafe2\nmsgid \"PDF to DOCX\"\nmsgstr \"PDFからDOCXへ\"\n\n#: ../../converting-files.rst:78 443eb3ec0d3a4ba89f8e4361a7607e16\nmsgid \"\"\n\"Use the pdf2docx_ library which uses |PyMuPDF| to provide document \"\n\"conversion from |PDF| to **DOCX** format.\"\nmsgstr \"|PyMuPDF| を使用してドキュメントを |PDF| から **DOCX** 形式に変換する pdf2docx_ ライブラリを使用します。\"\n\n#: ../../footer.rst:46 bf92de7cbdc140fba9255f9a43b9932a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/coop_low.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 5a355454a0e14f23a63b8a2e7ce669e8\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 09967d10ba634cb1bff385ff21b01dde\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 d1d359d0d40748de8b9c0d01760f6668\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../coop_low.rst:7 bdf9ff13324144f3aea1e6e6fb99a106\nmsgid \"Working together: DisplayList and TextPage\"\nmsgstr \"共同作業：DisplayList と TextPage\"\n\n#: ../../coop_low.rst:8 f4bd6483319f4150b1c8bb96b8e13933\nmsgid \"Here are some instructions on how to use these classes together.\"\nmsgstr \"これらのクラスを一緒に使用する方法に関するいくつかの手順があります。\"\n\n#: ../../coop_low.rst:10 ed7509d3a4e1434498829a99374f641b\nmsgid \"\"\n\"In some situations, performance improvements may be achievable, when you \"\n\"fall back to the detail level explained here.\"\nmsgstr \"一部の状況では、ここで説明されている詳細レベルに戻ると、パフォーマンスの向上が可能かもしれません。\"\n\n#: ../../coop_low.rst:13 cd9e800e616545078dedc61814a029c7\nmsgid \"Create a DisplayList\"\nmsgstr \"DisplayList の作成\"\n\n#: ../../coop_low.rst:14 c3a4cb6ce3974be5af359b73bd3b8d71\nmsgid \"\"\n\"A :ref:`DisplayList` represents an interpreted document page. Methods for\"\n\" pixmap creation, text extraction and text search are  -- behind the \"\n\"curtain -- all using the page's display list to perform their tasks. If a\"\n\" page must be rendered several times (e.g. because of changed zoom \"\n\"levels), or if text search and text extraction should both be performed, \"\n\"overhead can be saved, if the display list is created only once and then \"\n\"used for all other tasks.\"\nmsgstr \"\"\n\":ref:`DisplayList` \"\n\"は解釈された文書ページを表します。ピクセルマップの作成、テキスト抽出、およびテキスト検索のメソッドは、幕の内側で、それぞれのタスクを実行するためにページの表示リストを使用しています。ページを複数回描画する必要がある場合（ズームレベルが変更されたためなど）、またはテキストの検索とテキストの抽出の両方を実行する必要がある場合、表示リストは一度だけ作成し、その後のすべてのタスクに使用すると、オーバーヘッドを節約できます。\"\n\n#: ../../coop_low.rst:18 4a46c1c8dddf48029189e3b15bc68591\nmsgid \"\"\n\"You can also create display lists for many pages \\\"on stack\\\" (in a \"\n\"list), may be during document open, during idling times, or you store it \"\n\"when a page is visited for the first time (e.g. in GUI scripts).\"\nmsgstr \"ディスプレイリストを多くのページに対して「スタック上」（リスト内）で作成することもできます。これはドキュメントを開いている間、アイドリング時間中、またはページが初めて訪れられたとき（GUIスクリプトなど）に行うことができます。\"\n\n#: ../../coop_low.rst:20 2f2b49df380e40cea8dba1b11f5ee9a8\nmsgid \"\"\n\"Note, that for everything what follows, only the display list is needed \"\n\"-- the corresponding :ref:`Page` object could have been deleted.\"\nmsgstr \"\"\n\"注意：以下のすべてのことについて、ディスプレイリストのみが必要です - 対応する :ref:`Page` \"\n\"オブジェクトは削除されている可能性があります。\"\n\n#: ../../coop_low.rst:23 aebfe0ed572842b9ba5b11a8d1aab0d2\nmsgid \"Generate Pixmap\"\nmsgstr \"ピクセルマップの生成\"\n\n#: ../../coop_low.rst:24 7dd16880b19c48e9837fd5dc2c621515\nmsgid \"\"\n\"The following creates a Pixmap from a :ref:`DisplayList`. Parameters are \"\n\"the same as for :meth:`Page.get_pixmap`.\"\nmsgstr \"\"\n\"以下は、:ref:`DisplayList` からピクセルマップを生成するものです。パラメータは :meth:`Page.get_pixmap` \"\n\"と同じです。\"\n\n#: ../../coop_low.rst:28 e89f1e9ef8d649f4a06985425cfa62a4\n#, python-format\nmsgid \"\"\n\"The execution time of this statement may be up to 50% shorter than that \"\n\"of :meth:`Page.get_pixmap`.\"\nmsgstr \"この文の実行時間は、:meth:`Page.get_pixmap` の実行時間よりも最大50％短くなる可能性があります。\"\n\n#: ../../coop_low.rst:31 d7fa50d37ba94e5cb71679b146596aa3\nmsgid \"Perform Text Search\"\nmsgstr \"テキスト検索を実行\"\n\n#: ../../coop_low.rst:32 883c1b8167124e3c87bee02cb540ebbb\nmsgid \"With the display list from above, we can also search for text.\"\nmsgstr \"上記のディスプレイリストを使用して、テキストを検索することもできます。\"\n\n#: ../../coop_low.rst:34 dffc2a72113945cbbce0613fb18a4903\nmsgid \"For this we need to create a :ref:`TextPage`.\"\nmsgstr \"これには、:ref:`TextPage` を作成する必要があります。\"\n\n#: ../../coop_low.rst:42 268c3ac74027425381db0e5a5b1beeec\nmsgid \"Extract Text\"\nmsgstr \"テキストの抽出\"\n\n#: ../../coop_low.rst:43 499d4763043d407c8815a5ff4c386e37\nmsgid \"\"\n\"With the same :ref:`TextPage` object from above, we can now immediately \"\n\"use any or all of the 5 text extraction methods.\"\nmsgstr \"前述の :ref:`TextPage` オブジェクトを使用することで、今すぐに5つのテキスト抽出メソッドのいずれかまたはすべてを使用できます。\"\n\n#: ../../coop_low.rst:45 6f1b9f5de2eb487c9502d14d7e74597c\nmsgid \"\"\n\"Above, we have created our text page without argument. This leads to a \"\n\"default argument of 3 (:data:`ligatures` and white-space are preserved), \"\n\"IAW images will **not** be extracted -- see below.\"\nmsgstr \"\"\n\"前述のように、テキストページを引数なしで作成しました。これにより、デフォルトの引数3（合字と空白が保持されます）が適用されます。つまり、画像は抽出\"\n\" **されません** - 以下を参照してください。\"\n\n#: ../../coop_low.rst:54 ab9774b34e1845db917cc426db636fd8\nmsgid \"Further Performance improvements\"\nmsgstr \"さらなるパフォーマンスの向上\"\n\n#: ../../coop_low.rst:56 8aa6869464d643f1b386fb7323425982\nmsgid \"Pixmap\"\nmsgstr \"\"\n\n#: ../../coop_low.rst:57 d58917690b86432a8db25b4e290c8aab\nmsgid \"As explained in the :ref:`Page` chapter:\"\nmsgstr \"ページの章で説明されているように：\"\n\n#: ../../coop_low.rst:59 5f452558de7e46d1a6bb4d407940f71d\n#, python-format\nmsgid \"\"\n\"If you do not need transparency set *alpha = 0* when creating pixmaps. \"\n\"This will save 25% memory (if RGB, the most common case) and possibly 5% \"\n\"execution time (depending on the GUI software).\"\nmsgstr \"\"\n\"透明度が不要な場合は、ピクスマップを作成する際に alpha = 0 \"\n\"に設定します。これにより、メモリが25％節約されます（RGBの場合、最も一般的なケース）し、GUIソフトウェアに依存して実行時間が5％削減される可能性があります。\"\n\n#: ../../coop_low.rst:62 75cc3ebbf8db48479d9f9b81f89a5254\nmsgid \"TextPage\"\nmsgstr \"\"\n\n#: ../../coop_low.rst:63 08ee726963904764a54737759d3c18d6\nmsgid \"\"\n\"If you do not need images extracted alongside the text of a page, you can\"\n\" set the following option:\"\nmsgstr \"ページのテキストと一緒に画像を抽出する必要がない場合、以下のオプションを設定できます：\"\n\n#: ../../coop_low.rst:68 4251f3ef7f5f4ac69038ff012e1254c6\n#, python-format\nmsgid \"\"\n\"This will save ca. 25% overall execution time for the HTML, XHTML and \"\n\"JSON text extractions and **hugely** reduce the amount of storage (both, \"\n\"memory and disk space) if the document is graphics oriented.\"\nmsgstr \"\"\n\"これにより、HTML、XHTML、およびJSONのテキスト抽出全体の実行時間が約25％節約され、ドキュメントがグラフィックス志向である場合、ストレージ（メモリとディスクスペースの両方）の量が\"\n\" **大幅に** 削減されます。\"\n\n#: ../../coop_low.rst:70 bbd6a64180374797a986afa4351f7218\nmsgid \"If you however do need images, use a value of 7 for flags:\"\nmsgstr \"ただし、画像が必要な場合は、フラグに7の値を使用してください：\"\n\n#: ../../footer.rst:60 ef9f02956d6945e086760c64e2387362\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/deprecated.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-05-06 22:50+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../deprecated.rst:3 d1d5b6242bd2429487e3c00f4bd27b44\nmsgid \":index:`_isWrapped` -- :attr:`Page.is_wrapped`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:4 eadbd707ba5b49ffaa1a8578c63f2fa7\nmsgid \":index:`addCaretAnnot` -- :meth:`Page.add_caret_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:5 f3d2fc15c03d40fe9c5aeee5eb43619e\nmsgid \":index:`addCircleAnnot` -- :meth:`Page.add_circle_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:6 051b8aa821bb412898f73279004d2d87\nmsgid \":index:`addFileAnnot` -- :meth:`Page.add_file_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:7 6b9299e0c63d4f9c840acf5cef786d3b\nmsgid \":index:`addFreetextAnnot` -- :meth:`Page.add_freetext_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:8 448eb9354f114ddc801e1e7e17c90813\nmsgid \":index:`addHighlightAnnot` -- :meth:`Page.add_highlight_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:9 afdf93da30d0472583f679bb32992982\nmsgid \":index:`addInkAnnot` -- :meth:`Page.add_ink_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:10 111293a76e4048d0b5e1605e9e874812\nmsgid \":index:`addLineAnnot` -- :meth:`Page.add_line_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:11 27c091e35cd143f5b67a0e8c8fa0875f\nmsgid \":index:`addPolygonAnnot` -- :meth:`Page.add_polygon_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:12 6933d20ce2e141c5a3fadbd053766d4d\nmsgid \":index:`addPolylineAnnot` -- :meth:`Page.add_polyline_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:13 30c229985fe44b80af84338499a2f559\nmsgid \":index:`addRectAnnot` -- :meth:`Page.add_rect_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:14 d78dac9a27684b5da29499e4b2f6b8f5\nmsgid \":index:`addRedactAnnot` -- :meth:`Page.add_redact_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:15 04264798641b4de3938500d873c2c6f8\nmsgid \":index:`addSquigglyAnnot` -- :meth:`Page.add_squiggly_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:16 fc348b38ada34284b4ff935bc0b96c15\nmsgid \":index:`addStampAnnot` -- :meth:`Page.add_stamp_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:17 bee1ce84496246a38df53948bf77f357\nmsgid \":index:`addStrikeoutAnnot` -- :meth:`Page.add_strikeout_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:18 25dad72947f64b9e8b569df99549e4e9\nmsgid \":index:`addTextAnnot` -- :meth:`Page.add_text_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:19 00aa64572a5f41b9a8cbed77037f912b\nmsgid \":index:`addUnderlineAnnot` -- :meth:`Page.add_underline_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:20 c385a1bc52db4e72a107bfed39ab9073\nmsgid \":index:`addWidget` -- :meth:`Page.add_widget`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:21 18d7411089ff4ab38e8a6b325dbafb58\nmsgid \":index:`chapterCount` -- :attr:`Document.chapter_count`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:22 3e8e8070762748c6ab15040d7ddfbf98\nmsgid \":index:`chapterPageCount` -- :meth:`Document.chapter_page_count`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:23 877a39673c34487ebea478f53dfbf4c4\nmsgid \":index:`cleanContents` -- :meth:`Page.clean_contents`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:24 d264e6c6a4f34ccda276df5fadd9f2f3\nmsgid \":index:`clearWith` -- :meth:`Pixmap.clear_with`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:25 c6e7724402164c7595cec2d1b515954d\nmsgid \":index:`convertToPDF` -- :meth:`Document.convert_to_pdf`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:26 30efb14a60a04279b22147f212ff2ce0\nmsgid \":index:`copyPage` -- :meth:`Document.copy_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:27 71be569311b643fcad76f9175f84ad8d\nmsgid \":index:`copyPixmap` -- :meth:`Pixmap.copy`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:28 9d169e01195d45ef8b642a34622387b3\nmsgid \":index:`CropBox` -- :attr:`Page.cropbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:29 d4e6e34a1e174e78aaaa16cc1589987b\nmsgid \":index:`CropBoxPosition` -- :attr:`Page.cropbox_position`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:30 eb2e77d896d148228b3ac65c9ac53982\nmsgid \":index:`deleteAnnot` -- :meth:`Page.delete_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:31 8f12dc1d6a2c47bc90ace8d1c4c0837a\nmsgid \":index:`deleteLink` -- :meth:`Page.delete_link`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:32 9e4d33fa051741b48c48b7cdb720d90d\nmsgid \":index:`deletePage` -- :meth:`Document.delete_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:33 66877e75a8c649ff8eebd342e28ceedf\nmsgid \":index:`deletePageRange` -- :meth:`Document.delete_pages`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:34 25721559e2fe452c86484ce93215a810\nmsgid \":index:`deleteWidget` -- :meth:`Page.delete_widget`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:35 0c1a8e11e7fd4587ae4312e58bf62d33\nmsgid \":index:`derotationMatrix` -- :attr:`Page.derotation_matrix`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:36 9c6cfa1376f94b509d2447887df70621\nmsgid \":index:`drawBezier` -- :meth:`Page.draw_bezier`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:37 22e65f0dbdfd44d3b77a5f0b9e807410\nmsgid \":index:`drawBezier` -- :meth:`Shape.draw_bezier`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:38 9240fc36aeb64362af89de7221a1ec18\nmsgid \":index:`drawCircle` -- :meth:`Page.draw_circle`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:39 3e71c253f1c64091b41e692eb39e85cb\nmsgid \":index:`drawCircle` -- :meth:`Shape.draw_circle`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:40 be7a4c92ba9346599ed48970f720d423\nmsgid \":index:`drawCurve` -- :meth:`Page.draw_curve`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:41 513be296f2cb4b618a91597a2df7e65d\nmsgid \":index:`drawCurve` -- :meth:`Shape.draw_curve`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:42 c0b7d4f8b2ad4691bd0aa7859ea33b77\nmsgid \":index:`drawLine` -- :meth:`Page.draw_line`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:43 554d906bb05f409190d6e6893190f958\nmsgid \":index:`drawLine` -- :meth:`Shape.draw_line`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:44 b2405f1b84e642eeafb66539f9808fb8\nmsgid \":index:`drawOval` -- :meth:`Page.draw_oval`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:45 aa69dd3ae74a463bb7b144a8d78c7cb4\nmsgid \":index:`drawOval` -- :meth:`Shape.draw_oval`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:46 bd4e3e4e051d4f2aa442d3d777a3b5ff\nmsgid \":index:`drawPolyline` -- :meth:`Page.draw_polyline`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:47 65c2a5f2e60d4e8791bd6bc4911e5d02\nmsgid \":index:`drawPolyline` -- :meth:`Shape.draw_polyline`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:48 ada5b07f1393444ca6f56d8878c5344f\nmsgid \":index:`drawQuad` -- :meth:`Page.draw_quad`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:49 bacd1883810d4581a41f8c39d4b1d590\nmsgid \":index:`drawQuad` -- :meth:`Shape.draw_quad`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:50 44a58d0bc884449eb62d74622f5c6c95\nmsgid \":index:`drawRect` -- :meth:`Page.draw_rect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:51 c0cc88dd71fb497996d4893f4a14d229\nmsgid \":index:`drawRect` -- :meth:`Shape.draw_rect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:52 f0925417a417408fb57e98400f82de38\nmsgid \":index:`drawSector` -- :meth:`Page.draw_sector`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:53 4e06c452b87b43dc88597aecb0183689\nmsgid \":index:`drawSector` -- :meth:`Shape.draw_sector`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:54 f8a714b644134acc857618d42422b411\nmsgid \":index:`drawSquiggle` -- :meth:`Page.draw_squiggle`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:55 93bb79f96d144fd38674d32e9aaa84c9\nmsgid \":index:`drawSquiggle` -- :meth:`Shape.draw_squiggle`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:56 cf3932da67be42dc8007fbee0a4427ec\nmsgid \":index:`drawZigzag` -- :meth:`Page.draw_zigzag`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:57 3107e38c57054eeea4d24f265b0f6671\nmsgid \":index:`drawZigzag` -- :meth:`Shape.draw_zigzag`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:58 03b818471af840fdb95c8dc2d8e7b209\nmsgid \":index:`embeddedFileAdd` -- :meth:`Document.embfile_add`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:59 5167d2308e644b71a09de926761ece0f\nmsgid \":index:`embeddedFileCount` -- :meth:`Document.embfile_count`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:60 161231ecd2224595bf3872c106a60136\nmsgid \":index:`embeddedFileDel` -- :meth:`Document.embfile_del`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:61 1023a942cc61494caba4804eeb29cebc\nmsgid \":index:`embeddedFileGet` -- :meth:`Document.embfile_get`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:62 a52dfb754efa438ea2c232dc7130cf4b\nmsgid \":index:`embeddedFileInfo` -- :meth:`Document.embfile_info`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:63 ef355611163d4b0bb14aaa00d18a0564\nmsgid \":index:`embeddedFileNames` -- :meth:`Document.embfile_names`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:64 999df931002c417da988825a29f420e0\nmsgid \":index:`embeddedFileUpd` -- :meth:`Document.embfile_upd`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:65 bf948d4f5d5f4caab2b7b01337d456e2\nmsgid \":index:`extractFont` -- :meth:`Document.extract_font`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:66 93fd021db67c403a8c52df83b26fea46\nmsgid \":index:`extractImage` -- :meth:`Document.extract_image`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:67 3021f35e288d4b7896cc4998b8d5cd4c\nmsgid \":index:`fileGet` -- :meth:`Annot.get_file`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:68 e766fa14928e487d81044fb5bfec79a7\nmsgid \":index:`fileUpd` -- :meth:`Annot.update_file`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:69 054a45d2bd564e99936796752bc21ae2\nmsgid \":index:`fillTextbox` -- :meth:`TextWriter.fill_textbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:70 5611c1d6bebc4834ba3309d08e108fe4\nmsgid \":index:`findBookmark` -- :meth:`Document.find_bookmark`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:71 19590b26aef74066bd9089aaa473b418\nmsgid \":index:`firstAnnot` -- :attr:`Page.first_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:72 11cd12cfd924436f9989b50bf24076ce\nmsgid \":index:`firstLink` -- :attr:`Page.first_link`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:73 e0341c36f0474b29b165756ff2bf2e39\nmsgid \":index:`firstWidget` -- :attr:`Page.first_widget`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:74 3e529771a460436ca6ec8cc3553b1646\nmsgid \":index:`fullcopyPage` -- :meth:`Document.fullcopy_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:75 7a0f1fd1838049589f29544cbafbee6e\nmsgid \":index:`gammaWith` -- :meth:`Pixmap.gamma_with`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:76 3e03080a489a4185ab0403f5e4a10533\nmsgid \":index:`getArea` -- :meth:`Rect.get_area`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:77 d08fd4faaef048ef9455a3dc22e0abe0\nmsgid \":index:`getArea` -- :meth:`IRect.get_area`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:78 8feb6c6033434a7eb93729dd7a214492\nmsgid \":index:`getCharWidths` -- :meth:`Document.get_char_widths`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:79 e820322f7d12476983ff2f6844edebb7\nmsgid \":index:`getContents` -- :meth:`Page.get_contents`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:80 315689e05e6b4ee79e9ee34b4855c9b3\nmsgid \":index:`getDisplayList` -- :meth:`Page.get_displaylist`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:81 59ef935a55fb48e0ad3d0b05fe9bba6a\nmsgid \":index:`getDrawings` -- :meth:`Page.get_drawings`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:82 fdac52da208b4710a3dcf0603259e088\nmsgid \":index:`getFontList` -- :meth:`Page.get_fonts`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:83 1cb6609cac5344bbb52338df5723abbb\nmsgid \":index:`getImageBbox` -- :meth:`Page.get_image_bbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:84 b2db41e3b28c49fe85ada1aaa5d11c93\nmsgid \":index:`getImageData` -- :meth:`Pixmap.tobytes`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:85 4016e42ec02d47a98cd479a56c1d6f81\nmsgid \":index:`getImageList` -- :meth:`Page.get_images`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:86 ba9df1a02bbb41d699430071a0853142\nmsgid \":index:`getLinks` -- :meth:`Page.get_links`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:87 e45e78c952c149b99893f2bdf0464ce9\nmsgid \":index:`getOCGs` -- :meth:`Document.get_ocgs`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:88 8cb86892aeb14018b456bb1500228603\nmsgid \":index:`getPageFontList` -- :meth:`Document.get_page_fonts`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:89 def3f6e7f54a48d584b35944ac483909\nmsgid \":index:`getPageImageList` -- :meth:`Document.get_page_images`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:90 e60fafcb1644487f85f736966a96e6f3\nmsgid \":index:`getPagePixmap` -- :meth:`Document.get_page_pixmap`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:91 404571c66f3f4449b253bac469681083\nmsgid \":index:`getPageText` -- :meth:`Document.get_page_text`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:92 d912b4e08d8e43759b50bd3fe66bf799\nmsgid \":index:`getPageXObjectList` -- :meth:`Document.get_page_xobjects`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:93 b989c010b0e941358950411ecae89d0d\nmsgid \":index:`getPDFnow` -- :meth:`get_pdf_now`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:94 afc6743031c3459a8b023575e22108ce\nmsgid \":index:`getPDFstr` -- :meth:`get_pdf_str`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:95 4513c128c5d24612b222b6bf32c9ba78\nmsgid \":index:`getPixmap` -- :meth:`Page.get_pixmap`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:96 8e17558bf3a7484da7e142427292d305\nmsgid \":index:`getPixmap` -- :meth:`Annot.get_pixmap`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:97 aaaba69a72e34566b856f031a3cc9f3b\nmsgid \":index:`getPixmap` -- :meth:`DisplayList.get_pixmap`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:98 b6a103d877a149f78ef58e60d1576a51\nmsgid \":index:`getPNGData` -- :meth:`Pixmap.tobytes`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:99 8991d6c4e3dc4accaf8c4e5726f4c4a7\nmsgid \":index:`getPNGdata` -- :meth:`Pixmap.tobytes`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:100 d37fe89c453843e9bbc3c6518487b009\nmsgid \":index:`getRectArea` -- :meth:`Rect.get_area`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:101 31cafead100b4a0eab043b8db48315c9\nmsgid \":index:`getRectArea` -- :meth:`IRect.get_area`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:102 18a3052627f84e0d9076a72aaedd1f56\nmsgid \":index:`getSigFlags` -- :meth:`Document.get_sigflags`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:103 c8a9c4bf70704bc09d700cd72ee9ab2b\nmsgid \":index:`getSVGimage` -- :meth:`Page.get_svg_image`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:104 962d959e225d4325824133ce80ea7844\nmsgid \":index:`getText` -- :meth:`Page.get_text`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:105 d84d77c264e44b28bf9d043ea4bc2a40\nmsgid \":index:`getText` -- :meth:`Annot.get_text`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:106 0e7807a62c5e48aab9c53b62bc99d5f5\nmsgid \":index:`getTextBlocks` -- :meth:`Page.get_text_blocks`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:107 eaa539c4b1e643f1bb4d8541e3c2cae0\nmsgid \":index:`getTextbox` -- :meth:`Page.get_textbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:108 73c3be87d16b4ce1ab32e14a43c83625\nmsgid \":index:`getTextbox` -- :meth:`Annot.get_textbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:109 57184e466926474a8122c92d716efc01\nmsgid \":index:`getTextLength` -- :meth:`get_text_length`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:110 ef0865561e5245caaf7cad5c31fa5b7a\nmsgid \":index:`getTextPage` -- :meth:`Page.get_textpage`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:111 145ac3860c93466f80ff59355fc3ff5a\nmsgid \":index:`getTextPage` -- :meth:`Annot.get_textpage`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:112 9751cae710914d3bab31ee6ba59c5991\nmsgid \":index:`getTextPage` -- :meth:`DisplayList.get_textpage`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:113 5f860f6e22a941eca21077328b814fea\nmsgid \":index:`getTextWords` -- :meth:`Page.get_text_words`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:114 285cb38b768c4499b093536527cca417\nmsgid \":index:`getToC` -- :meth:`Document.get_toc`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:115 06baade7ba234e409910b5725a990d12\nmsgid \":index:`getXmlMetadata` -- :meth:`Document.get_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:116 9fcdf92180a34622be5d144da780ea7a\nmsgid \":index:`ImageProperties` -- :meth:`image_properties`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:117 f394aac5cf1143c38ce86651288f35f0\nmsgid \":index:`includePoint` -- :meth:`Rect.include_point`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:118 570fa5daadf74e338f232b7b4971d361\nmsgid \":index:`includePoint` -- :meth:`IRect.include_point`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:119 8ddaec2281cd46aa8b6c4dcff8562392\nmsgid \":index:`includeRect` -- :meth:`Rect.include_rect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:120 ff5100ed366b479f96fb5c7fedb20a24\nmsgid \":index:`includeRect` -- :meth:`IRect.include_rect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:121 0dfb59dc42064652be63a6368543020e\nmsgid \":index:`insertFont` -- :meth:`Page.insert_font`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:122 d4a5843f50214d2880c0e10589ce890f\nmsgid \":index:`insertImage` -- :meth:`Page.insert_image`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:123 6f95549ce82d47e5ba18bbb14215c08d\nmsgid \":index:`insertLink` -- :meth:`Page.insert_link`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:124 b5e3f22cdb294479ade281982639843b\nmsgid \":index:`insertPage` -- :meth:`Document.insert_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:125 030309c3c03340bab039d374155ef986\nmsgid \":index:`insertPDF` -- :meth:`Document.insert_pdf`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:126 df931ba7d0564c688d145b7f8a2871e0\nmsgid \":index:`insertText` -- :meth:`Page.insert_text`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:127 17b568407a8e44f8a855291d34cf1d90\nmsgid \":index:`insertText` -- :meth:`Shape.insert_text`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:128 561e6f7e79fa47f98b59b04cc29ee2f6\nmsgid \":index:`insertTextbox` -- :meth:`Page.insert_textbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:129 54f104892aa04a8993366721a1017bd0\nmsgid \":index:`insertTextbox` -- :meth:`Shape.insert_textbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:130 8f6ad8ae4e3441d0bbe6ceddd469e8a7\nmsgid \":index:`invertIRect` -- :meth:`Pixmap.invert_irect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:131 3c2a3d820abe454a99bf6a608d7f9750\nmsgid \":index:`isConvex` -- :attr:`Quad.is_convex`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:132 ff4a100633ac4aef8956ee89fea3928c\nmsgid \":index:`isDirty` -- :attr:`Document.is_dirty`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:133 b3d2162130f7469da99822ab533562fb\nmsgid \":index:`isEmpty` -- :attr:`Rect.is_empty`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:134 7902fb832f4d46148e5fb12d33180721\nmsgid \":index:`isEmpty` -- :attr:`IRect.is_empty`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:135 219e226b694b4424a8cc0b243125195b\nmsgid \":index:`isEmpty` -- :attr:`Quad.is_empty`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:136 6d2a36ec88b848888e47502f443ddd2f\nmsgid \":index:`isFormPDF` -- :attr:`Document.is_form_pdf`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:137 ee6a8794ac454167bf112c26aee0679e\nmsgid \":index:`isInfinite` -- :attr:`Rect.is_infinite`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:138 0e449ebf4dbf41c3a5684705c4764d1e\nmsgid \":index:`isInfinite` -- :attr:`IRect.is_infinite`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:139 bb7e257c9c5d4c649588be9dcc1539e8\nmsgid \":index:`isPDF` -- :attr:`Document.is_pdf`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:140 6034a32b2cd641c587f398e466223fbb\nmsgid \":index:`isRectangular` -- :attr:`Quad.is_rectangular`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:141 e04e5574d4294c58a6e2e047385e4bab\nmsgid \":index:`isRectilinear` -- :attr:`Matrix.is_rectilinear`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:142 72f57f01824e4c2090e4cecaaa3bd7b3\nmsgid \":index:`isReflowable` -- :attr:`Document.is_reflowable`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:143 6f1427d4d36448bea20405dd494e4e9b\nmsgid \":index:`isRepaired` -- :attr:`Document.is_repaired`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:144 46501c7649d2435db16b4ba2b180de44\nmsgid \":index:`isStream` -- :meth:`Document.is_stream`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:145 d8c668fe2a6a41368d3753de325db923\nmsgid \":index:`lastLocation` -- :attr:`Document.last_location`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:146 23b2e4723f784739b87a95d0e621af1b\nmsgid \":index:`lineEnds` -- :attr:`Annot.line_ends`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:147 9f84a5afe9f94be08d591804cdb1f2dd\nmsgid \":index:`loadAnnot` -- :meth:`Page.load_annot`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:148 a9b23d3b3f6343dcb80e169000f2b2f5\nmsgid \":index:`loadLinks` -- :meth:`Page.load_links`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:149 25f9456cfe284e5fb321a13a57937aff\nmsgid \":index:`loadPage` -- :meth:`Document.load_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:150 9c522c046f63431fad4d3d4dcae73d31\nmsgid \":index:`makeBookmark` -- :meth:`Document.make_bookmark`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:151 89dd42c792e44a5db93d7cf5e8d1bdd0\nmsgid \":index:`MediaBox` -- :attr:`Page.mediabox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:152 2ce8cf40024f432a8a6d298e8396809e\nmsgid \":index:`MediaBoxSize` -- :attr:`Page.mediabox_size`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:153 fc3637603edc44449553dd1fc10ef2dc\nmsgid \":index:`metadataXML` -- :meth:`Document.xref_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:154 4734ad7ca35e4295bc39b9343fae96bf\nmsgid \":index:`movePage` -- :meth:`Document.move_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:155 29dc231050284695b482c40ab67035cd\nmsgid \":index:`needsPass` -- :attr:`Document.needs_pass`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:156 b7bbcca1b65140f7a23f06023146091a\nmsgid \":index:`newPage` -- :meth:`Document.new_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:157 7b9a25eacb194c1085cd415855c4860e\nmsgid \":index:`newShape` -- :meth:`Page.new_shape`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:158 8173575617414d0989cd5e7b5dbe4825\nmsgid \":index:`nextLocation` -- :meth:`Document.next_location`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:159 0b83f1a78c974acba949f3651c3987ca\nmsgid \":index:`pageCount` -- :attr:`Document.page_count`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:160 d347647e7c4845689c148b6687cbe86e\nmsgid \":index:`pageCropBox` -- :meth:`Document.page_cropbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:161 07ab9db3d77249908e0570a9f601b00b\nmsgid \":index:`pageXref` -- :meth:`Document.page_xref`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:162 c48b011bfa7a49f4a715474371748d0d\nmsgid \":index:`PaperRect` -- :meth:`paper_rect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:163 794d8f18e4b34f019a7e5a1eff5f2db4\nmsgid \":index:`PaperSize` -- :meth:`paper_size`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:164 912bd5afa4174ad7ad07cacc9d16aef4\nmsgid \":index:`paperSizes` -- :attr:`paper_sizes`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:165 b03e09c6342c41299da1cdecfe87a1fc\nmsgid \":index:`PDFCatalog` -- :meth:`Document.pdf_catalog`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:166 962d9ba05d8841d1b1c66b3fc304d6f8\nmsgid \":index:`PDFTrailer` -- :meth:`Document.pdf_trailer`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:167 2f4783d82c5a4d14b0f377fcffb5fed8\nmsgid \":index:`pillowData` -- :meth:`Pixmap.pil_tobytes`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:168 baf9bf3a1e884ddb99139199010c1f5b\nmsgid \":index:`pillowWrite` -- :meth:`Pixmap.pil_save`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:169 96c05e011f1242b9b8163d060e11876a\nmsgid \":index:`planishLine` -- :meth:`planish_line`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:170 68bd0d9d10734094b2e9dbc55162e13a\nmsgid \":index:`preRotate` -- :meth:`Matrix.prerotate`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:171 8bdcf39ac3a04ec584a07c3670e6c1c7\nmsgid \":index:`preScale` -- :meth:`Matrix.prescale`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:172 cf845bc2492648df9b941b7ef7db68b6\nmsgid \":index:`preShear` -- :meth:`Matrix.preshear`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:173 14c5026144d84103b74a07b30fee2512\nmsgid \":index:`preTranslate` -- :meth:`Matrix.pretranslate`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:174 fc0559ee8c6343eea94b1b7e3948e03e\nmsgid \":index:`previousLocation` -- :meth:`Document.prev_location`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:175 27731a7d4029401da7bc531da68f1a21\nmsgid \":index:`readContents` -- :meth:`Page.read_contents`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:176 133ffd4b0d204ec4b93e2e4cfafcb76f\nmsgid \":index:`resolveLink` -- :meth:`Document.resolve_link`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:177 dd161914317344ab9c50aa1713b3bc8a\nmsgid \":index:`rotationMatrix` -- :attr:`Page.rotation_matrix`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:178 12c65e9ce74e4188ade3e84773fff4a4\nmsgid \":index:`searchFor` -- :meth:`Page.search_for`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:179 7ebba037060c4ccb94fb6611ec91a95c\nmsgid \":index:`searchPageFor` -- :meth:`Document.search_page_for`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:180 1bd92b7e92794d7ea9fd5fe12a917fb5\nmsgid \":index:`setAlpha` -- :meth:`Pixmap.set_alpha`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:181 d939772fbf0440968d64b115e336901b\nmsgid \":index:`setBlendMode` -- :meth:`Annot.set_blendmode`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:182 eee4c968e1ce440b9bca3317f1c97c2b\nmsgid \":index:`setBorder` -- :meth:`Annot.set_border`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:183 8972027ca4c64c239a0ac5796eda537e\nmsgid \":index:`setColors` -- :meth:`Annot.set_colors`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:184 25dcdb414c364adcaecd75bbad18538b\nmsgid \":index:`setCropBox` -- :meth:`Page.set_cropbox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:185 3478d381553d46b98ad378b06d3535d7\nmsgid \":index:`setFlags` -- :meth:`Annot.set_flags`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:186 a3f6ed932990480d8ef802f1aa8dc611\nmsgid \":index:`setInfo` -- :meth:`Annot.set_info`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:187 399b02fa3d8645c9a0e6a63968a49ab6\nmsgid \":index:`setLanguage` -- :meth:`Document.set_language`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:188 15718079cc2847dea27b601e918c69d2\nmsgid \":index:`setLineEnds` -- :meth:`Annot.set_line_ends`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:189 c64721b035484fb7afc912582cdde029\nmsgid \":index:`setMediaBox` -- :meth:`Page.set_mediabox`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:190 dda850ad8d874c678fc63fb40bdf18f0\nmsgid \":index:`setMetadata` -- :meth:`Document.set_metadata`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:191 da20869148a84b22aae622c6cf2f1a94\nmsgid \":index:`setName` -- :meth:`Annot.set_name`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:192 3465192236a64449886c7a641b6ae7e4\nmsgid \":index:`setOC` -- :meth:`Annot.set_oc`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:193 565618b0eeda4dab9fcb83f7cb66ced6\nmsgid \":index:`setOpacity` -- :meth:`Annot.set_opacity`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:194 0da4f191ff2a4ee6b4dcd65f2389eaa2\nmsgid \":index:`setOrigin` -- :meth:`Pixmap.set_origin`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:195 18647efea53342d5b7557f7cae05e4a1\nmsgid \":index:`setPixel` -- :meth:`Pixmap.set_pixel`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:196 a24782160fb141e8ac764c333d987674\nmsgid \":index:`setRect` -- :meth:`Annot.set_rect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:197 b6d40d4e98674081b1a9af6708231fdf\nmsgid \":index:`setRect` -- :meth:`Pixmap.set_rect`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:198 5c6f3e60a4784efe97eec74f3efead31\nmsgid \":index:`setResolution` -- :meth:`Pixmap.set_dpi`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:199 d3cf7265bb0345caaa35cee0ccec1f58\nmsgid \":index:`setRotation` -- :meth:`Page.set_rotation`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:200 1573ef9d77b343afb19a92a27d87756e\nmsgid \":index:`setToC` -- :meth:`Document.set_toc`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:201 458d23fe34464a6595998b7eb1018338\nmsgid \":index:`setXmlMetadata` -- :meth:`Document.set_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:202 dbff7623129443ae909b28be52fdaacb\nmsgid \":index:`showPDFpage` -- :meth:`Page.show_pdf_page`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:203 7e7c0909bd734d378738029819134255\nmsgid \":index:`soundGet` -- :meth:`Annot.get_sound`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:204 8161ab61491b42ad924a02953ddd540b\nmsgid \":index:`tintWith` -- :meth:`Pixmap.tint_with`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:205 315914d9d5214bf9bb07a4f746a91ac6\nmsgid \":index:`transformationMatrix` -- :attr:`Page.transformation_matrix`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:206 8e9b02db2d39463b950c2d3bbff108a3\nmsgid \":index:`updateLink` -- :meth:`Page.update_link`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:207 8263c336e9bb402ca9cbd9086d43d75b\nmsgid \":index:`updateObject` -- :meth:`Document.update_object`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:208 6ae4d97e8c5e4da99256aeead52810f1\nmsgid \":index:`updateStream` -- :meth:`Document.update_stream`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:209 73f4ed438af740348f883a9f36ca6474\nmsgid \":index:`wrapContents` -- :meth:`Page.wrap_contents`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:210 78a6c29c00914e158bb52d47d3e67380\nmsgid \":index:`writeImage` -- :meth:`Pixmap.save`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:211 43019b552508422699e7de4d4adc0be3\nmsgid \":index:`writePNG` -- :meth:`Pixmap.save`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:212 534c176a9f984bbba09535e897312f16\nmsgid \":index:`writeText` -- :meth:`Page.write_text`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:213 cd67b2d738be4ecd8d5087581b2752ec\nmsgid \":index:`writeText` -- :meth:`TextWriter.write_text`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:214 63dbb736b48743d28f2b8f6a1feac7f0\nmsgid \":index:`xrefLength` -- :meth:`Document.xref_length`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:215 e817cc360dfe4f009e7c7b400c69193d\nmsgid \":index:`xrefObject` -- :meth:`Document.xref_object`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:216 7c0ef03c3a82406985b37ac2a4840260\nmsgid \":index:`xrefStream` -- :meth:`Document.xref_stream`\"\nmsgstr \"\"\n\n#: ../../deprecated.rst:217 c3fdec8f544048ccbff884ecff95a30c\nmsgid \":index:`xrefStreamRaw` -- :meth:`Document.xref_stream_raw`\"\nmsgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/device.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 db41752d7d77475b91dce6987192b03e\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 9d1395b42c0242c2937c063ec31289da\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 c674fa9ee73a4fcf888b701a69a14f4a\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../device.rst:7 d8f699f2197d4cccb1a32e36349536c8\nmsgid \"Device\"\nmsgstr \"Device (デバイス)\"\n\n#: ../../device.rst:9 c03889a987f445ea84d79f3d5abfb84d\nmsgid \"\"\n\"The different format handlers (pdf, xps, etc.) interpret pages to a \"\n\"\\\"device\\\". Devices are the basis for everything that can be done with a \"\n\"page: rendering, text extraction and searching. The device type is \"\n\"determined by the selected construction method.\"\nmsgstr \"\"\n\"異なるフォーマットハンドラ（pdf、xps \"\n\"など）はページを「デバイス」に解釈します。デバイスはページで行うすべてのことの基盤であり、レンダリング、テキスト抽出、検索などが行えます。デバイスのタイプは選択した構築方法によって決まります。\"\n\n#: ../../device.rst:11 5997f573701045499919ec1f18ab7518\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../device.rst:17 4b9fd079e127474e94506fe9eadb79d7\nmsgid \"Constructor for either a pixel map or a display list device.\"\nmsgstr \"ピクセルマップまたは表示リストデバイスのコンストラクタ。\"\n\n#: ../../device.rst 3029384c54544ad783072064ea96675d\n#: ca7a504aacc440719aba0931b7724c60\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../device.rst:19 9b095106055b4d568344ac7d142034f3\nmsgid \"either a ``Pixmap`` or  a ``DisplayList``.\"\nmsgstr \"``Pixmap`` または ``DisplayList`` のいずれか。\"\n\n#: ../../device.rst:22 30003de713004e58977091af11644238\nmsgid \"\"\n\"An optional `IRect` for ``Pixmap`` devices to restrict rendering to a \"\n\"certain area of the page. If the complete page is required, specify \"\n\"``None``. For display list devices, this parameter must be omitted.\"\nmsgstr \"\"\n\"``Pixmap`` デバイス用の任意の `IRect` \"\n\"で、ページの特定の領域にレンダリングを制限するためのものです。完全なページが必要な場合は、``None`` \"\n\"を指定してください。表示リストデバイスの場合、このパラメータは省略する必要があります。\"\n\n#: ../../device.rst:27 5a3223623124424ba115721d21086469\nmsgid \"Constructor for a text page device.\"\nmsgstr \"テキストページデバイスのコンストラクタ。\"\n\n#: ../../device.rst:29 8f77a7687a804d458ddb9a4be4624d77\nmsgid \"``TextPage`` object\"\nmsgstr \"TextPageオブジェクト\"\n\n#: ../../device.rst:32 53c8b35c8b0e4e488b05cfbe1c988a0d\n#, fuzzy\nmsgid \"\"\n\"control the way how text is parsed into the text page. Currently 3 \"\n\"options can be coded into this parameter, see :ref:`TextPreserve`. To set\"\n\" these options use something like `flags=0 | TEXT_PRESERVE_LIGATURES | \"\n\"...`.\"\nmsgstr \"テキストがテキストページに解析される方法を制御するフラグです\"\n\n#: ../../footer.rst:46 233763b8ff7c42718f2a5b6285c3802f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/displaylist.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 85ee81383b5446bab311d8f7b3c8fcac\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 2aadbeed28004bc5b1af3cafca54cd49\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 5f03ea6228c540d490e7e21dbe7a682e\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../displaylist.rst:7 ffd953b6fbc64a39866787a0edce72c2\nmsgid \"DisplayList\"\nmsgstr \"DisplayList（ディスプレイリスト）\"\n\n#: ../../displaylist.rst:9 a98bdb15facb45eca03a302e65321649\nmsgid \"\"\n\"DisplayList is a list containing drawing commands (text, images, etc.). \"\n\"The intent is two-fold:\"\nmsgstr \"DisplayListは、描画コマンド（テキスト、画像など）を含むリストです。その目的は二つあります：\"\n\n#: ../../displaylist.rst:11 f34b2f44389140eca2d21b0d7c566835\nmsgid \"as a caching-mechanism to reduce parsing of a page\"\nmsgstr \"ページのパースを削減するためのキャッシュメカニズムとして\"\n\n#: ../../displaylist.rst:12 11fd7eeaa74c41e38f44f93fe53f799d\nmsgid \"\"\n\"as a data structure in multi-threading setups, where one thread parses \"\n\"the page and another one renders pages. This aspect is currently not \"\n\"supported by PyMuPDF.\"\nmsgstr \"ページをパースするスレッドとページをレンダリングする別のスレッドでのデータ構造として。この側面は現在、PyMuPDFではサポートされていません。\"\n\n#: ../../displaylist.rst:14 f47fc55997964be8872823d0d68a9434\nmsgid \"\"\n\"A display list is populated with objects from a page, usually by \"\n\"executing :meth:`Page.get_displaylist`. There also exists an independent \"\n\"constructor.\"\nmsgstr \"\"\n\"ディスプレイリストは通常、:meth:`Page.get_displaylist` \"\n\"を実行することによってページからオブジェクトで満たされます。また、独立したコンストラクタも存在します。\"\n\n#: ../../displaylist.rst:16 478941b4f0a74dd5ac00af8a2e5de8e0\nmsgid \"\"\n\"\\\"Replay\\\" the list (once or many times) by invoking one of its methods \"\n\":meth:`~DisplayList.run`, :meth:`~DisplayList.get_pixmap` or \"\n\":meth:`~DisplayList.get_textpage`.\"\nmsgstr \"\"\n\"このリストを（一度または複数回）再生するには、そのメソッドのうちのいずれかを呼び出します。:meth:`~DisplayList.run` \"\n\"、:meth:`~DisplayList.get_pixmap` 、または :meth:`~DisplayList.get_textpage` \"\n\"です。\"\n\n#: ../../displaylist.rst:20 b035d30ab932458c89921fc2091ca6ed\nmsgid \"**Method**\"\nmsgstr \"**メソッド** \"\n\n#: ../../displaylist.rst:20 9ec33062cfa84f33adb5ca985df1b62a\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明** \"\n\n#: ../../displaylist.rst:22 f063e9c7368a4d1bb4efbf9e02d9a7b0\nmsgid \":meth:`~DisplayList.run`\"\nmsgstr \"\"\n\n#: ../../displaylist.rst:22 916c809bdfae4d9b912c30cda33c7d3b\nmsgid \"Run a display list through a device.\"\nmsgstr \"ディスプレイリストをデバイスを介して実行します。\"\n\n#: ../../displaylist.rst:23 a412fe84e6a943109a82c9872dc2a953\nmsgid \":meth:`~DisplayList.get_pixmap`\"\nmsgstr \"\"\n\n#: ../../displaylist.rst:23 b2523139914a4541a0c3f79442bf5c6f\nmsgid \"generate a pixmap\"\nmsgstr \"ピクスマップを生成します。\"\n\n#: ../../displaylist.rst:24 5bfdb590999b469981c332ada5769bbf\nmsgid \":meth:`~DisplayList.get_textpage`\"\nmsgstr \"\"\n\n#: ../../displaylist.rst:24 24b92e98327b4214865e137898c355c1\nmsgid \"generate a text page\"\nmsgstr \"テキストページを生成します。\"\n\n#: ../../displaylist.rst:25 758211c051284705afa9e186fdea6e54\nmsgid \":attr:`~DisplayList.rect`\"\nmsgstr \"\"\n\n#: ../../displaylist.rst:25 8247482dba784fabb5f89ce11f17a64c\nmsgid \"mediabox of the display list\"\nmsgstr \"ディスプレイリストのメディアボックス（表示領域）です。\"\n\n#: ../../displaylist.rst:29 879da44f5b924a8299e2cdf2daa64852\nmsgid \"**Class API**\"\nmsgstr \"**Class API（クラスAPI）** \"\n\n#: ../../displaylist.rst:35 7024f17715094e0bac4657dc96d778fe\nmsgid \"Create a new display list.\"\nmsgstr \"新しいディスプレイリストを作成します。\"\n\n#: ../../displaylist.rst 368347bd6e354c7286c6d761323614c6\n#: 5cffa7e1860f48d2b2b02af84396e8b7 a68f36c6fdbd4638841bd4b5d14e01c5\n#: fbf69acf127c475684179bebec45b555\nmsgid \"Parameters\"\nmsgstr \"パラメーター\"\n\n#: ../../displaylist.rst:37 1a15f2e868934ebfbb706101234b942c\nmsgid \"The page's rectangle.\"\nmsgstr \"ページの矩形。\"\n\n#: ../../displaylist.rst 4aa7e95bfb304eb786873dc128080192\n#: 9628266c652c43e397ab17aff7b09d9a fdc8f4060e4044a4bba226ce56c05efe\nmsgid \"Return type\"\nmsgstr \"戻り値の型\"\n\n#: ../../displaylist.rst:40 136f549e2738445d8d830e101523615c\nmsgid \"``DisplayList``\"\nmsgstr \"\"\n\n#: ../../displaylist.rst:44 a708030e4a714162a183122ff845f300\nmsgid \"\"\n\"Run the display list through a device. The device will populate the \"\n\"display list with its \\\"commands\\\" (i.e. text extraction or image \"\n\"creation). The display list can later be used to \\\"read\\\" a page many \"\n\"times without having to re-interpret it from the document file.\"\nmsgstr \"デバイスを介してディスプレイリストを実行します。デバイスはディスプレイリストをその「コマンド」（つまりテキストの抽出または画像の作成）で満たします。ディスプレイリストは後で文書ファイルから再解釈することなく、ページを多くの回数「読む」ために使用できます。\"\n\n#: ../../displaylist.rst:46 4c8291909a844ff4a2f2ab416252270b\nmsgid \"\"\n\"You will most probably instead use one of the specialized run methods \"\n\"below -- :meth:`get_pixmap` or :meth:`get_textpage`.\"\nmsgstr \"\"\n\"おそらく、以下の専門の実行メソッドの1つを代わりに使用するでしょう - :meth:`get_pixmap` または \"\n\":meth:`get_textpage` 。\"\n\n#: ../../displaylist.rst:48 4f7a4933e8924fe0b4bf3ba52b68b918\nmsgid \"Device\"\nmsgstr \"デバイス\"\n\n#: ../../displaylist.rst:51 c7fc73de742e46aaa1a3bfac323ffe52\nmsgid \"Transformation matrix to apply to the display list contents.\"\nmsgstr \"ディスプレイリストのコンテンツに適用する変換行列。\"\n\n#: ../../displaylist.rst:54 8d876f1c867a4ba9aab91aa8844f11ed\nmsgid \"\"\n\"Only the part visible within this area will be considered when the list \"\n\"is run through the device.\"\nmsgstr \"デバイスを介してリストを実行する際にこの領域内で可視部分のみが考慮されます。\"\n\n#: ../../displaylist.rst:65 4cd71203402f42c084c05537b4069b8e\nmsgid \"Run the display list through a draw device and return a pixmap.\"\nmsgstr \"ディスプレイリストを描画デバイスを介して実行し、ピクスマップを返します。\"\n\n#: ../../displaylist.rst:67 40ffabb8733d4c159fb9c1bf5f123b7a\nmsgid \"matrix to use. Default is the identity matrix.\"\nmsgstr \"使用する行列。デフォルトは単位行列です。\"\n\n#: ../../displaylist.rst:70 9f80e04939df4e869a6aae307600f9b9\nmsgid \"the desired colorspace. Default is RGB.\"\nmsgstr \"望ましいカラースペース。デフォルトはRGBです。\"\n\n#: ../../displaylist.rst:73 004942119bb548268104bdbf345c6626\nmsgid \"determine whether or not (0, default) to include a transparency channel.\"\nmsgstr \"透明チャネルを含めるかどうかを決定します（0、デフォルトは含めない）。\"\n\n#: ../../displaylist.rst:75 63499de6adb349218d9c228d37571c9b\nmsgid \"\"\n\"restrict rendering to the intersection of this area with \"\n\":attr:`DisplayList.rect`.\"\nmsgstr \":attr:`DisplayList.rect` との交差部分にレンダリングを制限します。\"\n\n#: ../../displaylist.rst:77 2b4519ceb62d4ff5aaf26469b6ad27e7\nmsgid \":ref:`Pixmap`\"\nmsgstr \"\"\n\n#: ../../displaylist.rst 9e12b4a400bd4f28a64154727e1341e8\n#: dfd4f14a1c4c40b4b4593b30d2801610\nmsgid \"Returns\"\nmsgstr \"戻り値\"\n\n#: ../../displaylist.rst:78 4d9e816a554e498f8b4ced5ead7fae63\nmsgid \"pixmap of the display list.\"\nmsgstr \"ディスプレイリストのピクスマップ。\"\n\n#: ../../displaylist.rst:82 d201e153d5a74b6286a3f24dd07771e4\nmsgid \"Run the display list through a text device and return a text page.\"\nmsgstr \"ディスプレイリストをテキストデバイスを介して実行し、テキストページを返します。\"\n\n#: ../../displaylist.rst:84 f7168bc2140948b1b23ee9a6555aa19c\nmsgid \"\"\n\"control which information is parsed into a text page. Default value in \"\n\"PyMuPDF is `3 = TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE`, i.e.\"\n\" :data:`ligatures` are **passed through**, white spaces are **passed \"\n\"through** (not translated to spaces), and images are **not included**. \"\n\"See :ref:`TextPreserve`.\"\nmsgstr \"\"\n\"テキストページに解析される情報を制御します。PyMuPDFのデフォルト値は `3 = TEXT_PRESERVE_LIGATURES | \"\n\"TEXT_PRESERVE_WHITESPACE` です。つまり、:data:`ligatures` はそのまま **通過** し、空白はそのまま\"\n\" **通過** します（スペースに変換されません）、画像は **含まれません** 。:ref:`TextPreserve` を参照してください。\"\n\n#: ../../displaylist.rst:86 331d9ffb9e2c41b2a7aa918985944d03\nmsgid \":ref:`TextPage`\"\nmsgstr \"\"\n\n#: ../../displaylist.rst:87 9a3d633bb3b9470e9633979dc60e32db\nmsgid \"text page of the display list.\"\nmsgstr \"ディスプレイリストのテキストページ。\"\n\n#: ../../displaylist.rst:91 a0532ee2b43e4881966b65e83c28a1f5\nmsgid \"\"\n\"Contains the display list's mediabox. This will equal the page's \"\n\"rectangle if it was created via :meth:`Page.get_displaylist`.\"\nmsgstr \"\"\n\"ディスプレイリストのmediaboxを含みます。これは、:meth:`Page.get_displaylist` \"\n\"を介して作成された場合、ページの矩形と等しいです。\"\n\n#: ../../displaylist.rst 027bab9cbfe6488eb3f5cf5818313a0e\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../displaylist.rst:93 3a0e088ac75d4a128417cd79855b6777\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../footer.rst:60 5f7c2ee2445b4bd69c561fa6fb3cf797\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/document-writer-class.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 a8b3ae3a5d614d1e8729320973185b23\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 fdd48e8301e84183b56ee383e825d1d8\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 ee68e630d503448088146398fe92de3e\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../document-writer-class.rst:7 2e25f1ee520c42cd915962f032064cf1\nmsgid \"DocumentWriter\"\nmsgstr \"DocumentWriter(ドキュメントライター)\"\n\n#: ../../document-writer-class.rst:9 9c9bc94001de467cb49c9bf4b7b82cfc\nmsgid \"|pdf_only_class|\"\nmsgstr \"PDFのみ。\"\n\n#: ../../document-writer-class.rst:12 0d6e81eab559420a9cb87ac6aab3fea5\nmsgid \"New in v1.21.0\"\nmsgstr \"バージョン1.21.0で導入\"\n\n#: ../../document-writer-class.rst:14 b10e3b014d11420d87f829cd717b0cd1\nmsgid \"\"\n\"This class represents a utility which can output various :ref:`document \"\n\"types supported by PyMuPDF<Supported_File_Types>`.\"\nmsgstr \"\"\n\"このクラスは、MuPDFで :ref:`サポートされている <Supported_File_Types>` \"\n\"さまざまなドキュメントタイプを出力できるユーティリティを表します。\"\n\n#: ../../document-writer-class.rst:16 9c4bec500209410f8b4cbcf2371d35db\nmsgid \"\"\n\"In |PyMuPDF| only used for outputting PDF documents whose pages are \"\n\"populated by :ref:`Story` DOMs.\"\nmsgstr \"\"\n\"PyMuPDFでは、:ref:`Story` \"\n\"DOM（ドキュメントオブジェクトモデル）でページが埋められたPDFドキュメントを出力するためにのみ使用されます。\"\n\n#: ../../document-writer-class.rst:18 9871fdeac3864a2da5273e4540a0a267\nmsgid \"\"\n\"Using DocumentWriter_ also for other document types might happen in the \"\n\"future.\"\nmsgstr \"将来的には、DocumentWriter_ を他のドキュメントタイプにも使用することがあるかもしれません。\"\n\n#: ../../document-writer-class.rst:21 9968d643215c4572b41cf341313b8f65\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド/属性** \"\n\n#: ../../document-writer-class.rst:21 606c7ae0f2594eddbe42178bb8644d9a\nmsgid \"**Short Description**\"\nmsgstr \"**簡単な説明** \"\n\n#: ../../document-writer-class.rst:23 50c0babb7b8840198f03c08d30e9d3c5\nmsgid \":meth:`DocumentWriter.begin_page`\"\nmsgstr \"\"\n\n#: ../../document-writer-class.rst:23 3bb196d61c3a4aa0b7994d563be77f25\nmsgid \"start a new output page\"\nmsgstr \"新しい出力ページを開始します。\"\n\n#: ../../document-writer-class.rst:24 1f63440a5b0e4d6ea6e75dda50dddea3\nmsgid \":meth:`DocumentWriter.end_page`\"\nmsgstr \"\"\n\n#: ../../document-writer-class.rst:24 10f5e50934fe4657a5d2600346ceafcf\nmsgid \"finish the current output page\"\nmsgstr \"現在の出力ページを終了します。\"\n\n#: ../../document-writer-class.rst:25 b0dad4d0d79645819b89624337d71ac9\nmsgid \":meth:`DocumentWriter.close`\"\nmsgstr \"\"\n\n#: ../../document-writer-class.rst:25 7fbb29ccb4b845ec90dd86ccb30df13f\nmsgid \"flush pending output and close the file\"\nmsgstr \"保留中の出力をフラッシュし、ファイルを閉じます。\"\n\n#: ../../document-writer-class.rst:28 1c4c83c4a8944dd48400b056f6f197d2\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI** \"\n\n#: ../../document-writer-class.rst:34 b3f94e8ec90e4ea783dc2ad85b3a4c37\nmsgid \"\"\n\"Create a document writer object, passing a Python file pointer or a file \"\n\"path. Options to use when saving the file may also be passed.\"\nmsgstr \"Pythonファイルポインタまたはファイルパスを渡してドキュメントライターオブジェクトを作成します。ファイルを保存する際に使用するオプションも渡すことができます。\"\n\n#: ../../document-writer-class.rst:36 8c30ef19be644ae4acdc8aa962a11f4b\nmsgid \"This class can also be used as a Python context manager.\"\nmsgstr \"このクラスはPythonのコンテキストマネージャとしても使用できます。\"\n\n#: ../../document-writer-class.rst 269746a16d004bdba23418807f5f2e30\n#: d6b77987b178432f8bf67e15280f52aa\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../document-writer-class.rst:38 397489f724624b7e9532d6d269dd6670\nmsgid \"\"\n\"the output file. This may be a string file name, or any Python file \"\n\"pointer.  .. note:: By using a `io.BytesIO()` object as file pointer, a \"\n\"document writer can create a PDF in memory. Subsequently, this PDF can be\"\n\" re-opened for input and be further manipulated. This technique is used \"\n\"by several example scripts in :ref:`Stories recipes<RecipesStories>`.\"\nmsgstr \"\"\n\n#: ../../document-writer-class.rst:38 05e9879e1f4b4ae59a5e41c552e922db\nmsgid \"\"\n\"the output file. This may be a string file name, or any Python file \"\n\"pointer.\"\nmsgstr \"出力ファイル。これは文字列のファイル名またはPythonファイルポインタのいずれかです。\"\n\n#: ../../document-writer-class.rst:40 37022195f8fe44c0806b5b19a88bcd4c\nmsgid \"\"\n\"By using a `io.BytesIO()` object as file pointer, a document writer can \"\n\"create a PDF in memory. Subsequently, this PDF can be re-opened for input\"\n\" and be further manipulated. This technique is used by several example \"\n\"scripts in :ref:`Stories recipes<RecipesStories>`.\"\nmsgstr \"\"\n\"`io.BytesIO()` \"\n\"オブジェクトをファイルポインタとして使用することで、ドキュメントライターはメモリ内にPDFを作成できます。その後、このPDFは入力用に再オープンしてさらに操作できます。これは、:ref:`Storiesレシピ<RecipesStories>`\"\n\" のいくつかのサンプルスクリプトで使用されています。\"\n\n#: ../../document-writer-class.rst:42 76a68fdef51c4889b0ad25785985c8b1\nmsgid \"\"\n\"specify saving options for the output PDF. Typical are \\\"compress\\\" or \"\n\"\\\"clean\\\". More possible values may be taken from help output of the \"\n\"`mutool convert` CLI utility.\"\nmsgstr \"\"\n\"出力PDFの保存オプションを指定します。一般的なものは「compress」や「clean」です。その他の可能な値は、`mutool \"\n\"convert` CLI ユーティリティのヘルプ出力から取得できます。\"\n\n#: ../../document-writer-class.rst:46 26994c9b27a84276951802359dd085d9\nmsgid \"Start a new output page of a given dimension.\"\nmsgstr \"指定された寸法の新しい出力ページを開始します。\"\n\n#: ../../document-writer-class.rst:48 76ed5effaf3f494e924c1e4409c325a4\nmsgid \"\"\n\"a rectangle specifying the page size. After this method, output \"\n\"operations may write content to the page.\"\nmsgstr \"ページサイズを指定する矩形。このメソッドの後、出力操作はページにコンテンツを書き込むことができます。\"\n\n#: ../../document-writer-class.rst:52 3ea8959411e545e6b5a8f32498bf303e\nmsgid \"\"\n\"Finish a page. This flushes any pending data and appends the page to the \"\n\"output document.\"\nmsgstr \"ページを終了します。保留中のデータをフラッシュし、ページを出力ドキュメントに追加します。\"\n\n#: ../../document-writer-class.rst:56 444a43febca543608815926d8f431a3e\nmsgid \"\"\n\"Close the output file. This method is required for writing any pending \"\n\"data.\"\nmsgstr \"出力ファイルを閉じます。保留中のデータを書き込むためにこのメソッドが必要です。\"\n\n#: ../../document-writer-class.rst:58 6f307923a0ba47a5a19b6b9a85f7bdc9\nmsgid \"For usage examples consult the section of :ref:`Story`.\"\nmsgstr \"使用例については、:ref:`Story` のセクションを参照してください。\"\n\n#: ../../footer.rst:60 0ad0cba35bcc45868f1d5640bc7e226b\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/document.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 43b4736175594b648a25f0be7fc42424\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 8a34ee99def04d0395e3977c82a70fb3\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 bf3099d94f984c22b00ddb5b985eef67\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../document.rst:7 e9a8d6bb8a584459bedbb314700c7bc7\nmsgid \"Document\"\nmsgstr \"Document (ドキュメント)\"\n\n#: ../../document.rst:11 3a88bb195d634bd1b5bd4e541a3d9a7e\nmsgid \"\"\n\"This class represents a document. It can be constructed from a file or \"\n\"from memory.\"\nmsgstr \"このクラスはドキュメントを表します。ファイルまたはメモリから構築することができます。\"\n\n#: ../../document.rst:13 f093a1011e1247d4b515a122f0025bb6\nmsgid \"\"\n\"There exists the alias *open* for this class, i.e. \"\n\"`pymupdf.Document(...)` and `pymupdf.open(...)` do exactly the same \"\n\"thing.\"\nmsgstr \"\"\n\"このクラスには *「open」* というエイリアスが存在し、つまり、 `pymupdf.Document(...)` と \"\n\"`pymupdf.open(...)` はまったく同じことを行います。\"\n\n#: ../../document.rst:15 77bb8938b5534efcb6b05b4559346d2f\nmsgid \"For details on **embedded files** refer to Appendix 3.\"\nmsgstr \"**埋め込まれたファイル** の詳細については、付録3を参照してください。\"\n\n#: ../../document.rst:19 ed504bde84854a89962d6285ce0c78ac\nmsgid \"\"\n\"Starting with v1.17.0, a new page addressing mechanism for **EPUB files \"\n\"only** is supported. This document type is internally organized in \"\n\"chapters such that pages can most efficiently be found by their so-called\"\n\" \\\"location\\\". The location is a tuple *(chapter, pno)* consisting of the\"\n\" chapter number and the page number **in that chapter**. Both numbers are\"\n\" zero-based.\"\nmsgstr \"\"\n\"バージョン1.17.0から、 **EPUBファイル専用** \"\n\"の新しいページアドレッシングメカニズムがサポートされています。このドキュメントタイプは、ページがその「場所」によって最も効率的に見つけられるように、章ごとに内部的に組織されています。場所は\"\n\" *（章、pno）* というタプルで構成され、章番号と **その章の中** のページ番号を指します。どちらの番号もゼロベースです。\"\n\n#: ../../document.rst:21 15f2eedab10243529b4aa77b9b0c2f8b\nmsgid \"\"\n\"While it is still possible to locate a page via its (absolute) number, \"\n\"doing so may mean that the complete EPUB document must be laid out before\"\n\" the page can be addressed. This may have a significant performance \"\n\"impact if the document is very large. Using the page's *(chapter, pno)* \"\n\"prevents this from happening.\"\nmsgstr \"\"\n\"依然として（絶対的な）番号を使用してページを見つけることは可能ですが、これを行うとページにアクセスする前に完全なEPUBドキュメントをレイアウトする必要があるかもしれません。これはドキュメントが非常に大きい場合、重要なパフォーマンスの影響を持つ可能性があります。ページの\"\n\" *（章、pno）* を使用することで、これを防ぐことができます。\"\n\n#: ../../document.rst:23 a9abb22b0c094890a8af3b64d7d76262\nmsgid \"\"\n\"To maintain a consistent API, PyMuPDF supports the page *location* syntax\"\n\" for **all file types** -- documents without this feature simply have \"\n\"just one chapter. :meth:`Document.load_page` and the equivalent index \"\n\"access now also support a *location* argument.\"\nmsgstr \"\"\n\"一貫性のあるAPIを維持するために、PyMuPDFは **すべてのファイルタイプ** にページの場所構文をサポートしています - \"\n\"この機能のないドキュメントは単に1つの章を持っています。:meth:`Document.load_page` および同等のインデックスアクセスも \"\n\"*場所* 引数をサポートしています。\"\n\n#: ../../document.rst:25 9d716392e88a47ecaad2863ac6b61457\nmsgid \"\"\n\"There are a number of methods for converting between page numbers and \"\n\"locations, for determining the chapter count, the page count per chapter,\"\n\" for computing the next and the previous locations, and the last page \"\n\"location of a document.\"\nmsgstr \"ページ番号と場所の間で変換するためのいくつかのメソッドがあり、章の数を決定するためのメソッド、章ごとのページ数を決定するためのメソッド、次の場所と前の場所を計算するためのメソッド、およびドキュメントの最後のページの場所を計算するためのメソッドがあります。\"\n\n#: ../../document.rst:28 add4a5f06f184d7ebc7b45e419cb3a63\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性** \"\n\n#: ../../document.rst:28 5b71e73348ff43b28c42f734ed068fbd\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明** \"\n\n#: ../../document.rst:30 58a8217257e948d98b9b26ab120c3aea\nmsgid \":meth:`Document.add_layer`\"\nmsgstr \"\"\n\n#: ../../document.rst:30 39da0dbb831848f1837f2799cac832e1\nmsgid \"PDF only: make new optional content configuration\"\nmsgstr \"PDFのみ：新しいオプションコンテンツ設定を作成\"\n\n#: ../../document.rst:31 d82b8d9a76b246c0a8be037689fbfa06\nmsgid \":meth:`Document.add_ocg`\"\nmsgstr \"\"\n\n#: ../../document.rst:31 e5ebdc27906c4b5c8896ae1c353b4787\nmsgid \"PDF only: add new optional content group\"\nmsgstr \"PDFのみ：新しいオプションコンテンツグループを追加\"\n\n#: ../../document.rst:32 e8f6741a63574c62b27f98b22177e828\nmsgid \":meth:`Document.authenticate`\"\nmsgstr \"\"\n\n#: ../../document.rst:32 defb0d7ebb00414b928eb0e592ae812e\nmsgid \"gain access to an encrypted document\"\nmsgstr \"暗号化されたドキュメントへのアクセスを取得\"\n\n#: ../../document.rst:33 b11af2c7c8694f3fa35bab1d987786a2\n#, fuzzy\nmsgid \":meth:`Document.bake`\"\nmsgstr \":meth:`Document.make_bookmark` によって作成されたもの。\"\n\n#: ../../document.rst:33 cf7e8fd44e594a9c90ab7a1833253b0a\nmsgid \"PDF only: make annotations / fields permanent content\"\nmsgstr \"PDFのみ：注釈やフォームフィールドを永続的なコンテンツに変換します\"\n\n#: ../../document.rst:34 20cad3262c664426bb762687b9c4bbd9\nmsgid \":meth:`Document.can_save_incrementally`\"\nmsgstr \"\"\n\n#: ../../document.rst:34 7b023782514349ee95ef2e72917994c8\nmsgid \"check if incremental save is possible\"\nmsgstr \"インクリメンタルセーブが可能かどうかを確認\"\n\n#: ../../document.rst:35 dc05c297ca0b4aefa1f1b7c427aa28c5\nmsgid \":meth:`Document.chapter_page_count`\"\nmsgstr \"\"\n\n#: ../../document.rst:35 4574736b834e4e998c95dfdb960afd78\nmsgid \"number of pages in chapter\"\nmsgstr \"章内のページ数\"\n\n#: ../../document.rst:36 12d37dd646db4d7094ac889b471a0ef8\nmsgid \":meth:`Document.close`\"\nmsgstr \"\"\n\n#: ../../document.rst:36 4ce3e236e34a4972bcc35cabc61b8cb1\nmsgid \"close the document\"\nmsgstr \"ドキュメントを閉じる\"\n\n#: ../../document.rst:37 1ba7c8f336184fe5bc4a0d56e99b08ec\nmsgid \":meth:`Document.convert_to_pdf`\"\nmsgstr \"\"\n\n#: ../../document.rst:37 cc1e97d3992c4552aa43c0f0c4f6807b\nmsgid \"write a PDF version to memory\"\nmsgstr \"PDFバージョンをメモリに書き込む\"\n\n#: ../../document.rst:38 9d859e8c86fa4677925790093524225b\nmsgid \":meth:`Document.copy_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:38 466c568ee935410294a9e211b1e10040\nmsgid \"PDF only: copy a page reference\"\nmsgstr \"PDFのみ：ページの参照をコピー\"\n\n#: ../../document.rst:39 3905e8ae3b06492b9fe02446094b4407\nmsgid \":meth:`Document.del_toc_item`\"\nmsgstr \"\"\n\n#: ../../document.rst:39 9fe2cfba44bd4f73abd8e1af06023fc4\nmsgid \"PDF only: remove a single TOC item\"\nmsgstr \"PDFのみ：単一のTOCアイテムを削除\"\n\n#: ../../document.rst:40 2e8f53ae81b44437bb7e36151dfdf856\nmsgid \":meth:`Document.delete_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:40 87da7bfbf0754384ad4bd489a1b62fb7\nmsgid \"PDF only: delete a page\"\nmsgstr \"PDFのみ：ページを削除\"\n\n#: ../../document.rst:41 ac488459c0594d6cb9b355f29f9f1434\nmsgid \":meth:`Document.delete_pages`\"\nmsgstr \"\"\n\n#: ../../document.rst:41 5ef25e49d8ed498fb185e70e5bbff4e3\nmsgid \"PDF only: delete multiple pages\"\nmsgstr \"PDFのみ：複数のページを削除\"\n\n#: ../../document.rst:42 c2175653712c47fca1ee1cfaba870c91\nmsgid \":meth:`Document.embfile_add`\"\nmsgstr \"\"\n\n#: ../../document.rst:42 5fcdd01035ed45c189614dd16f46d767\nmsgid \"PDF only: add a new embedded file from buffer\"\nmsgstr \"PDFのみ：バッファから新しい埋め込みファイルを追加\"\n\n#: ../../document.rst:43 95b5b715b6224242a7dfafbc0041b9bd\nmsgid \":meth:`Document.embfile_count`\"\nmsgstr \"\"\n\n#: ../../document.rst:43 8f3b00e038294a4aa1b2634f512da7dc\nmsgid \"PDF only: number of embedded files\"\nmsgstr \"PDFのみ：埋め込みファイルの数\"\n\n#: ../../document.rst:44 d39ae28e4b06484dac1e6ba1528cce4c\nmsgid \":meth:`Document.embfile_del`\"\nmsgstr \"\"\n\n#: ../../document.rst:44 7649e79372904462bbdd49f9ab148373\nmsgid \"PDF only: delete an embedded file entry\"\nmsgstr \"PDFのみ：埋め込みファイルエントリを削除\"\n\n#: ../../document.rst:45 964881d13cae457589969e927b3b7163\nmsgid \":meth:`Document.embfile_get`\"\nmsgstr \"\"\n\n#: ../../document.rst:45 93f0d4af7e2f49c08cd5565455a16206\nmsgid \"PDF only: extract an embedded file buffer\"\nmsgstr \"PDFのみ：埋め込みファイルバッファを抽出\"\n\n#: ../../document.rst:46 e82abf28eaa84b889bf8baed0b1f0132\nmsgid \":meth:`Document.embfile_info`\"\nmsgstr \"\"\n\n#: ../../document.rst:46 5d46af817ace455296fb97fec4708e1d\nmsgid \"PDF only: metadata of an embedded file\"\nmsgstr \"PDFのみ：埋め込みファイルのメタデータ\"\n\n#: ../../document.rst:47 24b4158b60f6487290d8264abb16f507\nmsgid \":meth:`Document.embfile_names`\"\nmsgstr \"\"\n\n#: ../../document.rst:47 a79a87dd6905428b8c336bc3a5cbfe4c\nmsgid \"PDF only: list of embedded files\"\nmsgstr \"PDFのみ：埋め込みファイルのリスト\"\n\n#: ../../document.rst:48 d1405add281648888c3aec36f1efa31e\nmsgid \":meth:`Document.embfile_upd`\"\nmsgstr \"\"\n\n#: ../../document.rst:48 3109aa1e33fe4baf82b62abfe73bf1c8\nmsgid \"PDF only: change an embedded file\"\nmsgstr \"PDFのみ：埋め込みファイルを変更\"\n\n#: ../../document.rst:49 df47ab4f60c34106a30295d4248cecc3\nmsgid \":meth:`Document.extract_font`\"\nmsgstr \"\"\n\n#: ../../document.rst:49 a57f7fb1ecec44c1bef98124eabe2af5\nmsgid \"PDF only: extract a font by :data:`xref`\"\nmsgstr \"PDFのみ： :data:`xref` によるフォントの抽出\"\n\n#: ../../document.rst:50 74fa6cb6cbf94754807bc74f0001e10c\nmsgid \":meth:`Document.extract_image`\"\nmsgstr \"\"\n\n#: ../../document.rst:50 ff6d3d0e82a64512ad8964b9c9a0628b\nmsgid \"PDF only: extract an embedded image by :data:`xref`\"\nmsgstr \"PDFのみ： :data:`xref` による埋め込み画像の抽出\"\n\n#: ../../document.rst:51 78f28501b7974812a1cd4f5830cd36dc\nmsgid \":meth:`Document.ez_save`\"\nmsgstr \"\"\n\n#: ../../document.rst:51 4a02f4a72a144d43b1754ec32416bb64\nmsgid \"PDF only: :meth:`Document.save` with different defaults\"\nmsgstr \"PDFのみ：異なるデフォルト値で :meth:`Document.save` を実行\"\n\n#: ../../document.rst:52 3154749d16cf48fe96a7f9c8425bfbf6\nmsgid \":meth:`Document.find_bookmark`\"\nmsgstr \"\"\n\n#: ../../document.rst:52 143e38f832604238a5f900679410b485\nmsgid \"retrieve page location after laid out document\"\nmsgstr \"レイアウトされたドキュメント後のページ位置を取得\"\n\n#: ../../document.rst:53 b271556405414cbaa9d1b57ab58b468c\nmsgid \":meth:`Document.fullcopy_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:53 e7f3a9b06b2c485c9be33faed6e5fe7c\nmsgid \"PDF only: duplicate a page\"\nmsgstr \"PDFのみ：ページの複製\"\n\n#: ../../document.rst:54 7bbeb29bdb63453191c3222b3e097f13\nmsgid \":meth:`Document.get_layer`\"\nmsgstr \"\"\n\n#: ../../document.rst:54 04bc7e5eed374ce89ccbc02847258286\nmsgid \"PDF only: lists of OCGs in ON, OFF, RBGroups\"\nmsgstr \"PDFのみ：ON、OFF、RBGroups内のOCGのリスト\"\n\n#: ../../document.rst:55 970f7427be2f4166889a754bf4d7c025\nmsgid \":meth:`Document.get_layers`\"\nmsgstr \"\"\n\n#: ../../document.rst:55 5697cfd27e9d4b869c8dd5d641f0d33c\nmsgid \"PDF only: list of optional content configurations\"\nmsgstr \"PDFのみ：オプションコンテンツ設定のリスト\"\n\n#: ../../document.rst:56 78785446fbb14cc19554b28a594181f5\nmsgid \":meth:`Document.get_oc`\"\nmsgstr \"\"\n\n#: ../../document.rst:56 2556f20aa201451e8bf65b2c20eada2f\nmsgid \"PDF only: get OCG /OCMD xref of image / form xobject\"\nmsgstr \"PDFのみ：画像/フォームオブジェクトのOCG / OCMD xrefを取得\"\n\n#: ../../document.rst:57 258b50d4a33e45028451dc2a77148f6f\nmsgid \":meth:`Document.get_ocgs`\"\nmsgstr \"\"\n\n#: ../../document.rst:57 afcf637c1119411594869f521a33bd71\nmsgid \"PDF only: info on all optional content groups\"\nmsgstr \"PDFのみ：すべてのオプションコンテンツグループの情報\"\n\n#: ../../document.rst:58 b9e9fda4a6094db0b0ae6679e3068cce\nmsgid \":meth:`Document.get_ocmd`\"\nmsgstr \"\"\n\n#: ../../document.rst:58 2f8facbc52ee427597b065b7b3e02635\nmsgid \"PDF only: retrieve definition of an :data:`OCMD`\"\nmsgstr \"PDFのみ： :data:`OCMD` の定義を取得\"\n\n#: ../../document.rst:59 c07ac7981fea4d33bb0144049e3239ee\nmsgid \":meth:`Document.get_page_fonts`\"\nmsgstr \"\"\n\n#: ../../document.rst:59 3236ca270e6648a08aba4bdba5284c5f\nmsgid \"PDF only: list of fonts referenced by a page\"\nmsgstr \"PDFのみ：ページで参照されるフォントのリスト\"\n\n#: ../../document.rst:60 644a31787f044848869b3f02a9340f62\nmsgid \":meth:`Document.get_page_images`\"\nmsgstr \"\"\n\n#: ../../document.rst:60 6c413f170ae84b1d869a89042deb238e\nmsgid \"PDF only: list of images referenced by a page\"\nmsgstr \"PDFのみ：ページで参照される画像のリスト\"\n\n#: ../../document.rst:61 0bed94104d8144f38c441256e6514eb2\nmsgid \":meth:`Document.get_page_labels`\"\nmsgstr \"\"\n\n#: ../../document.rst:61 41f65092ee164fc297f86373c5ab102b\nmsgid \"PDF only: list of page label definitions\"\nmsgstr \"PDFのみ：ページラベルの定義のリスト\"\n\n#: ../../document.rst:62 862369882af44617a8819906a976bc16\nmsgid \":meth:`Document.get_page_numbers`\"\nmsgstr \"\"\n\n#: ../../document.rst:62 8615e9cd79d941a78c49c2ce9ac0c575\nmsgid \"PDF only: get page numbers having a given label\"\nmsgstr \"PDFのみ：指定されたラベルを持つページ番号を取得\"\n\n#: ../../document.rst:63 dad59db4773e4ee9a396ad31b592ad81\nmsgid \":meth:`Document.get_page_pixmap`\"\nmsgstr \"\"\n\n#: ../../document.rst:63 cbe4b263ffeb44519224759f35a7b530\nmsgid \"create a pixmap of a page by page number\"\nmsgstr \"ページ番号によるページのピクスマップの作成\"\n\n#: ../../document.rst:64 876f95670aed4e86bbdd960315d3bc1b\nmsgid \":meth:`Document.get_page_text`\"\nmsgstr \"\"\n\n#: ../../document.rst:64 be31a13a38bd43c6913b7a80c953ee33\nmsgid \"extract the text of a page by page number\"\nmsgstr \"ページ番号によるページのテキストの抽出\"\n\n#: ../../document.rst:65 978642d705ed459086758fef87cc6513\nmsgid \":meth:`Document.get_page_xobjects`\"\nmsgstr \"\"\n\n#: ../../document.rst:65 9ce6ba28bcd84aa2a35ce24bb1699f48\nmsgid \"PDF only: list of XObjects referenced by a page\"\nmsgstr \"PDFのみ：ページで参照されるXObjectのリスト\"\n\n#: ../../document.rst:66 b597ff3290d34f83bf1b564ee7d148f8\nmsgid \":meth:`Document.get_sigflags`\"\nmsgstr \"\"\n\n#: ../../document.rst:66 16ae9c3a7a1e428283fdbab18375d352\nmsgid \"PDF only: determine signature state\"\nmsgstr \"PDFのみ：署名状態を確認\"\n\n#: ../../document.rst:67 87689643a05c46b4868a2969cda519ea\nmsgid \":meth:`Document.get_toc`\"\nmsgstr \"\"\n\n#: ../../document.rst:67 031806a18b7d4bc0a5ca012eda1b7dbb\nmsgid \"extract the table of contents\"\nmsgstr \"目次を抽出\"\n\n#: ../../document.rst:68 5cfc41d652204ddc955125491bc8ba44\nmsgid \":meth:`Document.get_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../document.rst:68 08d4b18bcfad4ff28f56780ac161ad6d\nmsgid \"PDF only: read the XML metadata\"\nmsgstr \"PDFのみ：XMLメタデータを読み込む\"\n\n#: ../../document.rst:69 ff2b33d4bb2c42f4bb77426a3e22dbd7\nmsgid \":meth:`Document.has_annots`\"\nmsgstr \"\"\n\n#: ../../document.rst:69 1e8a505220e24e65a8c808697aa64afa\nmsgid \"PDF only: check if PDF contains any annots\"\nmsgstr \"PDFのみ：PDFに注釈が含まれているかを確認\"\n\n#: ../../document.rst:70 38f7a0c4a98d4ecb90798f4830568061\nmsgid \":meth:`Document.has_links`\"\nmsgstr \"\"\n\n#: ../../document.rst:70 948d1a0444544a568098d8f5abcbe626\nmsgid \"PDF only: check if PDF contains any links\"\nmsgstr \"PDFのみ：PDFにリンクが含まれているかを確認\"\n\n#: ../../document.rst:71 d1ce6cf6cce1457caabc424ad112e57e\nmsgid \":meth:`Document.insert_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:71 fff75002fe13475b84fc3f18e1ff8ada\nmsgid \"PDF only: insert a new page\"\nmsgstr \"PDFのみ：新しいページを挿入\"\n\n#: ../../document.rst:72 cf8bb81eaa8a48ea9d5a1fbdc1a7ab5a\nmsgid \":meth:`Document.insert_pdf`\"\nmsgstr \"\"\n\n#: ../../document.rst:72 289d2e5d58fe42a1a42bcf72bf0d6ff8\nmsgid \"PDF only: insert pages from another PDF\"\nmsgstr \"PDFのみ：別のPDFからページを挿入\"\n\n#: ../../document.rst:73 8cd752947d534369a28e538b9fb6853c\nmsgid \":meth:`Document.insert_file`\"\nmsgstr \"\"\n\n#: ../../document.rst:73 5cc1ad88bf844c96bf15f6586fd84cb8\nmsgid \"PDF only: insert pages from arbitrary document\"\nmsgstr \"PDFのみ：任意のドキュメントからページを挿入\"\n\n#: ../../document.rst:74 8178801a98ca4bfca4dc9b6ad47ba89f\nmsgid \":meth:`Document.journal_can_do`\"\nmsgstr \"\"\n\n#: ../../document.rst:74 2c867cd421094f95bc050a133eafad70\nmsgid \"PDF only: which journal actions are possible\"\nmsgstr \"PDFのみ：どのジャーナルアクションが可能か\"\n\n#: ../../document.rst:75 283b597442494a8ba9ae9b5bec8bd8fa\nmsgid \":meth:`Document.journal_enable`\"\nmsgstr \"\"\n\n#: ../../document.rst:75 8416ce80179c432d8919be5ce1cb0af6\nmsgid \"PDF only: enables journalling for the document\"\nmsgstr \"PDFのみ：ドキュメントのジャーナルを有効にする\"\n\n#: ../../document.rst:76 6b953871829946af9c2773facdc83609\nmsgid \":meth:`Document.journal_load`\"\nmsgstr \"\"\n\n#: ../../document.rst:76 180edecda8984b7cb87a6274ea19f89a\nmsgid \"PDF only: load journal from a file\"\nmsgstr \"PDFのみ：ファイルからジャーナルを読み込む\"\n\n#: ../../document.rst:77 8391be9d1b0441a0910e17782c0b15ef\nmsgid \":meth:`Document.journal_op_name`\"\nmsgstr \"\"\n\n#: ../../document.rst:77 a817a795918345018097f192480ce45b\nmsgid \"PDF only: return name of a journalling step\"\nmsgstr \"PDFのみ：ジャーナルステップの名前を返す\"\n\n#: ../../document.rst:78 bdb35edbe9394a7fb719c39e4a98e434\nmsgid \":meth:`Document.journal_position`\"\nmsgstr \"\"\n\n#: ../../document.rst:78 22c8acf5b55d4901a0706583047f98ac\nmsgid \"PDF only: return journalling status\"\nmsgstr \"PDFのみ：ジャーナリングステータスを返す\"\n\n#: ../../document.rst:79 bfb92de11a49415b9a637a6bdd41a08a\nmsgid \":meth:`Document.journal_redo`\"\nmsgstr \"\"\n\n#: ../../document.rst:79 941f312fd6dc434bb3e7bb22b43982f9\nmsgid \"PDF only: redo current operation\"\nmsgstr \"PDFのみ：現在の操作をやり直す\"\n\n#: ../../document.rst:80 e39c415d7d064a2ebd5d1597dbd8837e\nmsgid \":meth:`Document.journal_save`\"\nmsgstr \"\"\n\n#: ../../document.rst:80 b584d240bee04b9d8dbaa84d5f8ace78\nmsgid \"PDF only: save journal to a file\"\nmsgstr \"PDFのみ：ジャーナルをファイルに保存\"\n\n#: ../../document.rst:81 377ee634b1b64808a581ac868f85eae3\nmsgid \":meth:`Document.journal_start_op`\"\nmsgstr \"\"\n\n#: ../../document.rst:81 a0ca366002234f6886d132221ae925fc\nmsgid \"PDF only: start an \\\"operation\\\" giving it a name\"\nmsgstr \"PDFのみ：名前を付けて「操作」を開始\"\n\n#: ../../document.rst:82 10f762396c4f489d8414e1f85d21c394\nmsgid \":meth:`Document.journal_stop_op`\"\nmsgstr \"\"\n\n#: ../../document.rst:82 ba97728a122047fd83681c7e71538f60\nmsgid \"PDF only: end current operation\"\nmsgstr \"PDFのみ：現在の操作を終了\"\n\n#: ../../document.rst:83 84244b3958754e2f8e60e088d4e9eaf8\nmsgid \":meth:`Document.journal_undo`\"\nmsgstr \"\"\n\n#: ../../document.rst:83 ac3708bf674842c5802292badc7ce153\nmsgid \"PDF only: undo current operation\"\nmsgstr \"PDFのみ：現在の操作を元に戻す\"\n\n#: ../../document.rst:84 e59cb5b39d03491fb5bae5b59bbfcb28\nmsgid \":meth:`Document.layer_ui_configs`\"\nmsgstr \"\"\n\n#: ../../document.rst:84 d9375c2112274868896c4d42fc331428\nmsgid \"PDF only: list of optional content intents\"\nmsgstr \"PDFのみ：オプションコンテンツインテントのリスト\"\n\n#: ../../document.rst:85 407287d007564aa49ddd7d761d16a854\nmsgid \":meth:`Document.layout`\"\nmsgstr \"\"\n\n#: ../../document.rst:85 24b905752b8f4103b44d7a072952a14d\nmsgid \"re-paginate the document (if supported)\"\nmsgstr \"ドキュメントを再ページ化（サポートされている場合）\"\n\n#: ../../document.rst:86 05540cbb5a6844d2b0066a9329eec704\nmsgid \":meth:`Document.load_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:86 d027aa3f5e7f40449d955369ac59be65\nmsgid \"read a page\"\nmsgstr \"ページを読み込む\"\n\n#: ../../document.rst:87 0f4a3571b20e46c8a8b0a056ca69d9c4\nmsgid \":meth:`Document.make_bookmark`\"\nmsgstr \"\"\n\n#: ../../document.rst:87 3b3bccdfd1ea485b9725001d0321b5c5\nmsgid \"create a page pointer in reflowable documents\"\nmsgstr \"リフローアブルドキュメント内でページポインタを作成\"\n\n#: ../../document.rst:88 41b1ca13914b4f2c945a7fed504d9517\nmsgid \":meth:`Document.move_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:88 00c89823b1274ff99f648f5b2c87ef02\nmsgid \"PDF only: move a page to different location in doc\"\nmsgstr \"PDFのみ：ページをドキュメント内の異なる場所に移動\"\n\n#: ../../document.rst:89 e84ed54f2d154b439faeaab883f5e93b\nmsgid \":meth:`Document.need_appearances`\"\nmsgstr \"\"\n\n#: ../../document.rst:89 676fd03bdf7e409b984fe0faa6d88a76\nmsgid \"PDF only: get/set `/NeedAppearances` property\"\nmsgstr \"PDFのみ： `/NeedAppearances` プロパティを取得/設定\"\n\n#: ../../document.rst:90 669abfabfa6b490aae5c20a6028b2af7\nmsgid \":meth:`Document.new_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:90 8535930473244385bd64d7584523da86\nmsgid \"PDF only: insert a new empty page\"\nmsgstr \"PDFのみ：新しい空白ページを挿入\"\n\n#: ../../document.rst:91 8706fe76caf44c4a9380d5fc92e71903\nmsgid \":meth:`Document.next_location`\"\nmsgstr \"\"\n\n#: ../../document.rst:91 da98e11be3fc4193abf54b8f9d212634\nmsgid \"return (chapter, pno) of following page\"\nmsgstr \"次のページの（章、pno）\"\n\n#: ../../document.rst:92 22873ddadc3b468c8092ae45a23efe56\nmsgid \":meth:`Document.outline_xref`\"\nmsgstr \"\"\n\n#: ../../document.rst:92 939075b4724544878a76f87d8dd1283e\nmsgid \"PDF only: :data:`xref` a TOC item\"\nmsgstr \"PDFのみ：TOCアイテムを :data:`xref` \"\n\n#: ../../document.rst:93 6722c38d0d78497091278cbd1e7b0d6b\nmsgid \":meth:`Document.page_cropbox`\"\nmsgstr \"\"\n\n#: ../../document.rst:93 04b54737e5ca450ca0f3e1483639382d\nmsgid \"PDF only: the unrotated page rectangle\"\nmsgstr \"PDFのみ：回転していないページの矩形\"\n\n#: ../../document.rst:94 af8716cd59ac46be87f21422bc3f8c5e\nmsgid \":meth:`Document.page_xref`\"\nmsgstr \"\"\n\n#: ../../document.rst:94 caf5f921388245b5b5f9b49940c056a7\nmsgid \"PDF only: :data:`xref` of a page number\"\nmsgstr \"PDFのみ：ページ番号の :data:`xref`\"\n\n#: ../../document.rst:95 571b7ea1b2ed4a0da1e2203deda7aa8d\nmsgid \":meth:`Document.pages`\"\nmsgstr \"\"\n\n#: ../../document.rst:95 278ecce412fc4bc58337a84b851ec028\nmsgid \"iterator over a page range\"\nmsgstr \"ページ範囲のイテレータ\"\n\n#: ../../document.rst:96 b85d12a3953342a89d8ffe83eb92ebf9\nmsgid \":meth:`Document.pdf_catalog`\"\nmsgstr \"\"\n\n#: ../../document.rst:96 14e5593718754a4da76d72a4bd33e7bd\nmsgid \"PDF only: :data:`xref` of catalog (root)\"\nmsgstr \"PDFのみ：カタログ（ルート）の :data:`xref` \"\n\n#: ../../document.rst:97 c11a1743ca684d3ca89d53ff36f33438\nmsgid \":meth:`Document.pdf_trailer`\"\nmsgstr \"\"\n\n#: ../../document.rst:97 8108cc2e14de4c0c948f8ea439c4819c\nmsgid \"PDF only: trailer source\"\nmsgstr \"PDFのみ：トレイラーソース\"\n\n#: ../../document.rst:98 b323bdef35c64155905c4cc4403eac19\nmsgid \":meth:`Document.prev_location`\"\nmsgstr \"\"\n\n#: ../../document.rst:98 7617a1f4aac44dddbcc6f92b8d6c45c0\nmsgid \"return (chapter, pno) of preceding page\"\nmsgstr \"前のページの（章、pno）を返す\"\n\n#: ../../document.rst:99 dedcbf0566f74df9aad30be8105ef527\n#, fuzzy\nmsgid \":meth:`Document.rewrite_images`\"\nmsgstr \":meth:`Document.make_bookmark` によって作成されたもの。\"\n\n#: ../../document.rst:99 974b6b3159ed459e8e279788df4cced8\nmsgid \"PDF only: rewrite / extra compression for images\"\nmsgstr \"\"\n\n#: ../../document.rst:100 d2f820953f0446d8be040f143bfd61fb\n#, fuzzy\nmsgid \":meth:`Document.recolor`\"\nmsgstr \":meth:`Document.make_bookmark` によって作成されたもの。\"\n\n#: ../../document.rst:100 feaa2f0d59f5474facff3305163251d5\nmsgid \"PDF only: execute :meth:`Page.recolor` for all pages\"\nmsgstr \"\"\n\n#: ../../document.rst:101 51ab18b8dc104059b4b26a3cc37ee5a2\nmsgid \":meth:`Document.reload_page`\"\nmsgstr \"\"\n\n#: ../../document.rst:101 82cadc34466a4036abf146722491a023\nmsgid \"PDF only: provide a new copy of a page\"\nmsgstr \"PDFのみ：ページの新しいコピーを提供\"\n\n#: ../../document.rst:102 ba53f93a3acc4fbd883b60252e16bf2d\nmsgid \":meth:`Document.resolve_names`\"\nmsgstr \"\"\n\n#: ../../document.rst:102 ea55d63d05fa4c9b897eac4f3ec3a2e4\nmsgid \"PDF only: Convert destination names into a Python dict\"\nmsgstr \"PDFのみ: ページの目的地名をPythonの辞書に変換します\"\n\n#: ../../document.rst:103 1f12d96d086840e0b6a9c584969fe937\nmsgid \":meth:`Document.save`\"\nmsgstr \"\"\n\n#: ../../document.rst:103 bcb05fe7cc084d47a2a47419224e8e50\nmsgid \"PDF only: save the document\"\nmsgstr \"PDFのみ：ドキュメントを保存\"\n\n#: ../../document.rst:104 c17d570731634e2899a9fef7b19f17b8\nmsgid \":meth:`Document.saveIncr`\"\nmsgstr \"\"\n\n#: ../../document.rst:104 c0269e939b344fd597a6956b62bbf2bb\nmsgid \"PDF only: save the document incrementally\"\nmsgstr \"PDFのみ：ドキュメントを増分保存\"\n\n#: ../../document.rst:105 96f92a2b46f64f5d93f97b5e38e2e0a7\nmsgid \":meth:`Document.scrub`\"\nmsgstr \"\"\n\n#: ../../document.rst:105 1ded1c45911c40bb88b0e8789286f7a1\nmsgid \"PDF only: remove sensitive data\"\nmsgstr \"PDFのみ：機密データを削除\"\n\n#: ../../document.rst:106 f6dacc40814f47b2a61ebd3fef801051\nmsgid \":meth:`Document.search_page_for`\"\nmsgstr \"\"\n\n#: ../../document.rst:106 f416a3e245d2413e9b92e1ac94a34eb9\nmsgid \"search for a string on a page\"\nmsgstr \"ページ上で文字列を検索\"\n\n#: ../../document.rst:107 5b7fa0d81fc6489fb3aa22c2f9532987\nmsgid \":meth:`Document.select`\"\nmsgstr \"\"\n\n#: ../../document.rst:107 1b7f3ad42e3748a9bc0b1c819ebfb37f\nmsgid \"PDF only: select a subset of pages\"\nmsgstr \"PDFのみ：ページのサブセットを選択\"\n\n#: ../../document.rst:108 a1bef9a0f9aa4faf97bc5a4d7dd2c439\nmsgid \":meth:`Document.set_layer_ui_config`\"\nmsgstr \"\"\n\n#: ../../document.rst:108 4cabc4e8de1547b6933c5571b6715a17\nmsgid \"PDF only: set OCG visibility temporarily\"\nmsgstr \"PDFのみ：一時的にOCGの表示を設定\"\n\n#: ../../document.rst:109 8f9c6e7f590c4b078b22910ae021833f\nmsgid \":meth:`Document.set_layer`\"\nmsgstr \"\"\n\n#: ../../document.rst:109 cccc69e7410e4bb695682ffd1ad32d9f\nmsgid \"PDF only: mass changing OCG states\"\nmsgstr \"PDFのみ：OCGステータスを一括変更\"\n\n#: ../../document.rst:110 05d50371618b43b4aa923361a11eb0b5\nmsgid \":meth:`Document.set_markinfo`\"\nmsgstr \"\"\n\n#: ../../document.rst:110 a7ac2c7a68e546a49bd24c64b96a58e6\nmsgid \"PDF only: set the MarkInfo values\"\nmsgstr \"PDFのみ：MarkInfoの値を設定\"\n\n#: ../../document.rst:111 b936b94e1de847abaf79d0a2b034e2bc\nmsgid \":meth:`Document.set_metadata`\"\nmsgstr \"\"\n\n#: ../../document.rst:111 ab7be95036d144ae96c077e8c019ae15\nmsgid \"PDF only: set the metadata\"\nmsgstr \"PDFのみ：メタデータを設定\"\n\n#: ../../document.rst:112 e1375d72fe6846d9a08e10a4ee9927c7\nmsgid \":meth:`Document.set_oc`\"\nmsgstr \"\"\n\n#: ../../document.rst:112 f3c50c202d7c4cdf837fb18d8b5c40cf\nmsgid \"PDF only: attach OCG/OCMD to image / form xobject\"\nmsgstr \"PDFのみ：画像/フォームオブジェクトにOCG/OCMDを添付\"\n\n#: ../../document.rst:113 2fdc13211d934a72829f8f6851b833e5\nmsgid \":meth:`Document.set_ocmd`\"\nmsgstr \"\"\n\n#: ../../document.rst:113 77f29139986644ce953f3f1afce1e36c\nmsgid \"PDF only: create or update an :data:`OCMD`\"\nmsgstr \"PDFのみ：:data:`OCMD` を作成または更新\"\n\n#: ../../document.rst:114 56b1be1913b8456b8af7a92efb5bce6c\nmsgid \":meth:`Document.set_page_labels`\"\nmsgstr \"\"\n\n#: ../../document.rst:114 e2ee4ffee5244f369f11d507a9b056ac\nmsgid \"PDF only: add/update page label definitions\"\nmsgstr \"PDFのみ：ページラベルの定義を追加/更新\"\n\n#: ../../document.rst:115 2a236deda376461d8e02dd777aa86a45\nmsgid \":meth:`Document.set_pagemode`\"\nmsgstr \"\"\n\n#: ../../document.rst:115 11e3ef0ce8e7442c849b83550cdd06e9\nmsgid \"PDF only: set the PageMode\"\nmsgstr \"PDFのみ：PageModeを設定\"\n\n#: ../../document.rst:116 32bd955e107e410b89537cae1c991d61\nmsgid \":meth:`Document.set_pagelayout`\"\nmsgstr \"\"\n\n#: ../../document.rst:116 4a6c5debab1643529562d2e5e7f9ec92\nmsgid \"PDF only: set the PageLayout\"\nmsgstr \"PDFのみ：PageLayoutを設定\"\n\n#: ../../document.rst:117 2144e914bdaf45a399949c3c3df56bb5\nmsgid \":meth:`Document.set_toc_item`\"\nmsgstr \"\"\n\n#: ../../document.rst:117 c03b6a76e34d4c29b288cefc04600f0d\nmsgid \"PDF only: change a single TOC item\"\nmsgstr \"PDFのみ：単一のTOCアイテムを変更\"\n\n#: ../../document.rst:118 f8fd3e681d2e40dbbd45e3b30913de56\nmsgid \":meth:`Document.set_toc`\"\nmsgstr \"\"\n\n#: ../../document.rst:118 c25e27e0effa448d8988947b633e20cb\nmsgid \"PDF only: set the table of contents (TOC)\"\nmsgstr \"PDFのみ：目次（TOC）を設定\"\n\n#: ../../document.rst:119 a304c7f00f824dd88396f97ef442c347\nmsgid \":meth:`Document.set_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../document.rst:119 e2419cc26cce4233b4a8273cac482f57\nmsgid \"PDF only: create or update document XML metadata\"\nmsgstr \"PDFのみ：ドキュメントXMLメタデータを作成または更新\"\n\n#: ../../document.rst:120 2e11620ea9d6476e9a56a93b2c3c2d5d\nmsgid \":meth:`Document.subset_fonts`\"\nmsgstr \"\"\n\n#: ../../document.rst:120 ae59a4fbc18b440eb2a7542d14a4c882\nmsgid \"PDF only: create font subsets\"\nmsgstr \"PDFのみ：フォントのサブセットを作成\"\n\n#: ../../document.rst:121 85fa8be173614f9395fad32a48d9021b\nmsgid \":meth:`Document.switch_layer`\"\nmsgstr \"\"\n\n#: ../../document.rst:121 e2bf17afb8eb44fb8d394c7da1b04185\nmsgid \"PDF only: activate OC configuration\"\nmsgstr \"PDFのみ：OC設定をアクティブ化\"\n\n#: ../../document.rst:122 7cf8c2ba034d430383e1bbf0dfe7f8e5\nmsgid \":meth:`Document.tobytes`\"\nmsgstr \"\"\n\n#: ../../document.rst:122 96ef34ce12fa4117920b6d9a451bfec0\nmsgid \"PDF only: writes document to memory\"\nmsgstr \"PDFのみ：ドキュメントをメモリに書き込む\"\n\n#: ../../document.rst:123 9c18cc7be02846ceabcc47cb305f4e32\nmsgid \":meth:`Document.xref_copy`\"\nmsgstr \"\"\n\n#: ../../document.rst:123 1d344c6f485149d08e8cbcb30f14bbfd\nmsgid \"PDF only: copy a PDF dictionary to another :data:`xref`\"\nmsgstr \"PDFのみ：PDF辞書を別の :data:`xref` にコピー\"\n\n#: ../../document.rst:124 d40fcf719f7745d0988864bbd78a0702\nmsgid \":meth:`Document.xref_get_key`\"\nmsgstr \"\"\n\n#: ../../document.rst:124 73c52ddd3eee43a0a4ee02fd0c0654c6\nmsgid \"PDF only: get the value of a dictionary key\"\nmsgstr \"PDFのみ：辞書キーの値を取得\"\n\n#: ../../document.rst:125 573343d13a364c9c8d257a1d98a89f3e\nmsgid \":meth:`Document.xref_get_keys`\"\nmsgstr \"\"\n\n#: ../../document.rst:125 81c53f9f870f4f59a618391c6a2cb5c4\nmsgid \"PDF only: list the keys of object at :data:`xref`\"\nmsgstr \"PDFのみ： :data:`xref` のオブジェクトのキーをリスト\"\n\n#: ../../document.rst:126 76398d72d880411cb46bd73eda703503\nmsgid \":meth:`Document.xref_object`\"\nmsgstr \"\"\n\n#: ../../document.rst:126 53a6e32b9e6b411ebcf5c8e3f096bd6c\nmsgid \"PDF only: get the definition source of :data:`xref`\"\nmsgstr \"PDFのみ：:data:`xref` の定義ソースを取得\"\n\n#: ../../document.rst:127 e66235038073450c9f5a839095cac4c4\nmsgid \":meth:`Document.xref_set_key`\"\nmsgstr \"\"\n\n#: ../../document.rst:127 8204850e62a846f88fbffa42e2637b9a\nmsgid \"PDF only: set the value of a dictionary key\"\nmsgstr \"PDFのみ：辞書キーの値を設定\"\n\n#: ../../document.rst:128 fd30d01999014bbab567b38ddb4353f0\nmsgid \":meth:`Document.xref_stream_raw`\"\nmsgstr \"\"\n\n#: ../../document.rst:128 99ccc2453ba946e7831daec6b7581cf6\nmsgid \"PDF only: raw stream source at :data:`xref`\"\nmsgstr \"PDFのみ： :data:`xref` での生のストリームソース\"\n\n#: ../../document.rst:129 413b3807f32f45a580cca989305c9008\nmsgid \":meth:`Document.xref_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../document.rst:129 fe64670c8c334c77b851161354240171\nmsgid \"PDF only: :data:`xref` of XML metadata\"\nmsgstr \"PDFのみ： XMLメタデータの :data:`xref` \"\n\n#: ../../document.rst:130 9db7fc2a6be446c9a0d597777ccb3db5\nmsgid \":attr:`Document.chapter_count`\"\nmsgstr \"\"\n\n#: ../../document.rst:130 d81d64b31cb94d3caeca06bd43e1e31e\nmsgid \"number of chapters\"\nmsgstr \"章の数\"\n\n#: ../../document.rst:131 88fa80583a8148bdb519161be5facabe\nmsgid \":attr:`Document.FormFonts`\"\nmsgstr \"\"\n\n#: ../../document.rst:131 822a58355d084a57bf43f78079ad7109\nmsgid \"PDF only: list of global widget fonts\"\nmsgstr \"PDFのみ：グローバルウィジェットフォントのリスト\"\n\n#: ../../document.rst:132 3187d844634044e2978d4d650d2b453e\nmsgid \":attr:`Document.is_closed`\"\nmsgstr \"\"\n\n#: ../../document.rst:132 58a7a1c8d488427daf9b1a3fd1b0baa1\nmsgid \"has document been closed?\"\nmsgstr \"ドキュメントが閉じられていますか？\"\n\n#: ../../document.rst:133 c6f2bfcdd3db47b9ae0572f8c6b52068\nmsgid \":attr:`Document.is_dirty`\"\nmsgstr \"\"\n\n#: ../../document.rst:133 c18fd15219484228bbb05b979d2fe93a\nmsgid \"PDF only: has document been changed yet?\"\nmsgstr \"PDFのみ：ドキュメントは変更されましたか？\"\n\n#: ../../document.rst:134 c0b6d32bf1e4495dbf4add91153500f6\nmsgid \":attr:`Document.is_encrypted`\"\nmsgstr \"\"\n\n#: ../../document.rst:134 8d7f114a51b14761b0bad0ab267c341c\nmsgid \"document (still) encrypted?\"\nmsgstr \"ドキュメントは（まだ）暗号化されていますか？\"\n\n#: ../../document.rst:135 1d1dc29fc5324c8b9c4c46188293b390\nmsgid \":attr:`Document.is_fast_webaccess`\"\nmsgstr \"\"\n\n#: ../../document.rst:135 e076fbc4f4f4419f8dfdbbc78e750bc2\nmsgid \"is PDF linearized?\"\nmsgstr \"PDFは線形化されていますか？\"\n\n#: ../../document.rst:136 4c5d509be68646a2a5e6d9288e486e9d\nmsgid \":attr:`Document.is_form_pdf`\"\nmsgstr \"\"\n\n#: ../../document.rst:136 7587e6c5fa74464484f04d42b82a8154\nmsgid \"is this a Form PDF?\"\nmsgstr \"これはフォームPDFですか？\"\n\n#: ../../document.rst:137 fc1951f5f9b644eca1bf32692e0a1084\nmsgid \":attr:`Document.is_pdf`\"\nmsgstr \"\"\n\n#: ../../document.rst:137 6744e037129540b5a068f48e079dd435\nmsgid \"is this a PDF?\"\nmsgstr \"これはPDFですか？\"\n\n#: ../../document.rst:138 03fdede084af4116b4d1587c067ff1f9\nmsgid \":attr:`Document.is_reflowable`\"\nmsgstr \"\"\n\n#: ../../document.rst:138 4a6c359253dd4c9690d177ea6a3b6683\nmsgid \"is this a reflowable document?\"\nmsgstr \"これはリフローアブルドキュメントですか？\"\n\n#: ../../document.rst:139 26433c11990f4f1e902b967ec62f9520\nmsgid \":attr:`Document.is_repaired`\"\nmsgstr \"\"\n\n#: ../../document.rst:139 3c658c42265747b7b521caba0b46b998\nmsgid \"PDF only: has this PDF been repaired during open?\"\nmsgstr \"PDFのみ：このPDFは開いている間に修復されましたか？\"\n\n#: ../../document.rst:140 cb53e80ca0614de784a45e404b379a60\nmsgid \":attr:`Document.last_location`\"\nmsgstr \"\"\n\n#: ../../document.rst:140 b7ace66466d54470b61071e9bfce414a\nmsgid \"(chapter, pno) of last page\"\nmsgstr \"最後のページの（章、pno）\"\n\n#: ../../document.rst:141 d4fd8a51760b4c4a964822cf87c4fd5b\nmsgid \":attr:`Document.metadata`\"\nmsgstr \"\"\n\n#: ../../document.rst:141 e49fe7d5415b4ea0aa5ff965dea0a4c2\nmsgid \"metadata\"\nmsgstr \"メタデータ\"\n\n#: ../../document.rst:142 b1eb281747194e0c9dc37769e5a35996\nmsgid \":attr:`Document.markinfo`\"\nmsgstr \"\"\n\n#: ../../document.rst:142 5c53ed8e5b3a43f790eb41430cf74c00\nmsgid \"PDF MarkInfo value\"\nmsgstr \"PDF MarkInfoの値\"\n\n#: ../../document.rst:143 28f8419fd8854bc281aa1a7973a0d651\nmsgid \":attr:`Document.name`\"\nmsgstr \"\"\n\n#: ../../document.rst:143 c074932b6df14c2a9bbac171d00a72e1\nmsgid \"filename of document\"\nmsgstr \"ドキュメントのファイル名\"\n\n#: ../../document.rst:144 c143ec8f77d7403ba2f5e950ada44f9f\nmsgid \":attr:`Document.needs_pass`\"\nmsgstr \"\"\n\n#: ../../document.rst:144 3a653b354e264d5ab111c00c2150d5ce\nmsgid \"require password to access data?\"\nmsgstr \"データにアクセスするにはパスワードが必要ですか？\"\n\n#: ../../document.rst:145 57c337795d3b41af8567072e6b7cf577\nmsgid \":attr:`Document.outline`\"\nmsgstr \"\"\n\n#: ../../document.rst:145 4c478e059e5b4ac0ac83ee75ae7da76b\nmsgid \"first `Outline` item\"\nmsgstr \"最初のアウトラインアイテム\"\n\n#: ../../document.rst:146 396a4b645ae04c80b5961baa2e075796\nmsgid \":attr:`Document.page_count`\"\nmsgstr \"\"\n\n#: ../../document.rst:146 67b13af7113547a8918fa5f210dcfaeb\nmsgid \"number of pages\"\nmsgstr \"ページ数\"\n\n#: ../../document.rst:147 cd51b0df05524051bca654f008981df0\nmsgid \":attr:`Document.permissions`\"\nmsgstr \"\"\n\n#: ../../document.rst:147 f33c48f888124f82af9dc413e5f9a50e\nmsgid \"permissions to access the document\"\nmsgstr \"ドキュメントへのアクセス権限\"\n\n#: ../../document.rst:148 0868038137794381a564152619e1814b\nmsgid \":attr:`Document.pagemode`\"\nmsgstr \"\"\n\n#: ../../document.rst:148 783f323a456349b186450d63549da121\nmsgid \"PDF PageMode value\"\nmsgstr \"PDF PageModeの値\"\n\n#: ../../document.rst:149 032d2ee20d6542c4975ad6c7e2f75522\nmsgid \":attr:`Document.pagelayout`\"\nmsgstr \"\"\n\n#: ../../document.rst:149 d9816800d017496f8603c2fca0b2e1d0\nmsgid \"PDF PageLayout value\"\nmsgstr \"PDF PageLayoutの値\"\n\n#: ../../document.rst:150 cf17ce8d51c043f3a964384ca0a92c53\nmsgid \":attr:`Document.version_count`\"\nmsgstr \"\"\n\n#: ../../document.rst:150 646aa6db9c8b4351b27593bdfaf5f24c\nmsgid \"PDF count of versions\"\nmsgstr \"PDFバージョンの数\"\n\n#: ../../document.rst:153 8f58511508294d49bd7a7f950c9bd7c9\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../document.rst:174 b482340231f44738bb9cf3c571f4f7d5\nmsgid \"Create a ``Document`` object.\"\nmsgstr \"``Document`` オブジェクトを作成します。\"\n\n#: ../../document.rst:176 1c55311b5fa64850a06598e2a8ce9a7c\nmsgid \"With default parameters, a **new empty PDF** document will be created.\"\nmsgstr \"デフォルトのパラメータを使用すると、**新しい空の PDF** ドキュメントが作成されます。\"\n\n#: ../../document.rst:177 22c55c2d255f491f89be960f4babb5e5\nmsgid \"If ``stream`` is given, then the document is created from memory.\"\nmsgstr \"``stream`` が指定された場合、ドキュメントはメモリから作成されます。\"\n\n#: ../../document.rst:178 3a8f75233dd54040a52ad9ae44d26e74\nmsgid \"\"\n\"If ``stream`` is `None`, then a document is created from the file given \"\n\"by ``filename``.\"\nmsgstr \"\"\n\"*stream* が `None` の場合、*filename* \"\n\"で指定されたファイルからドキュメントが作成されます。そのタイプは拡張子から推測されます。これは *filetype* によって上書きできます。\"\n\n#: ../../document.rst 00a908e8a7684c1db0a3b35d910dfc89\n#: 035c82154d7945aeaedacdae5ef9e83e 0494f5c7dd3e4dbdad753d8fc418426a\n#: 053524db9ab3421685fe89d78c566686 09e2f20f6eb4448a8af6859f0c972be3\n#: 1164be645ddb4224a7d1dfbaf1cd5aae 11a4366dcede41cfaa7fdd36496c01f8\n#: 134ee532dfa449f7a4ae06f57cf5988e 13b2e4a1b9744b59bf530b2f115364c0\n#: 242606a542a04a0eb4db1492072bbbd1 26c165f89a5f499eb2bad0cdc07423df\n#: 28a91b3ddd5446e6ac630c63f80bc46c 2d988720b730480abd51f3485f33b9dd\n#: 2dc2f4b45060421cb1b0e7609a77cf95 36c8dc94af7341e0bdd08b5127d8485c\n#: 38acd225df3c4b4ca9c150e5d7033af0 3d87ac16734548f390215976b31c8c04\n#: 3ef1c3fc9e334d3fb17e329f068ea72c 409cb3c2f05441b9be706339b72b0f8b\n#: 448429be618e43a0b10ba1ae0e5d7e88 45ae45d35fe74d62b719166a69e7064d\n#: 45bce8087950479e8fa7477db3a20711 530ff5d58e3a4d9e98c9aeb8c5605bdb\n#: 551a6935861b439098d9d062611f616a 58261b2fcc5c49f5933bcfdab369ef17\n#: 5a5aea508b954bb49e513cf02243ce16 5ac5beffb52646b18b7348ac1b2737e7\n#: 5ea82374068c4ab4b571bb6daa9be348 6414b2f2a6ac4b7ba788941cca287706\n#: 6a5b8d3dc8bf40e29ded3ec3e9ffc38b 6c98f98bb31f4c98ae8a19bf33683ff0\n#: 6f1d6803f6944c3eb09805a162627403 6f37c861b8b84191948d358812e43a6a\n#: 73823030d66d461c9de9c71a08b04c67 7423014684c24e4e94f2ed1856e30e86\n#: 766ac26fd7d04013a82d44a6359f02e4 7a58704d8b8c46fa9d2a7e06b609b5e6\n#: 7c1441be492648c6868dc599cbcf5290 7d00af6b27284bc49da99cf2abcd1c4a\n#: 7f44721ca2974b3390c251bd6d32cb0d 8645eb3d5aff4b538c51ae5de766f320\n#: 8cf10f5e5765410c89421d4efc29c2bb 8faa136e57734811b95284b118993d56\n#: 9098706c0a9241599811b31b5e16c768 99d0a9c7f22d43fd91b94d3c9d440d40\n#: 9af405444dc145959d9744d4fca8d186 9c7eefa6c1ab43fb9581311c53f3dbae\n#: 9cd2f9315b7e4cf6b879188ba6e88ad3 9e5092bbf1e14cdba4a8622d40c8e74a\n#: a542a56d8f1347c6bbbeb1c6edbd40a1 a72dfd60198e40ae9582c427e0a70e8a\n#: ac4cc19f3f184b118dc2bb188462d316 ac57ebf36eac4d7eb5338b7d3e1d2a38\n#: af376c9284994378ba44d7d738372d08 b294f327f5df461a865037b3521e9b64\n#: b34e803114f74c439be67a2ea91fa82c b38308ff71d54e1f94cc7c713b830e63\n#: b8c7e0cb4b5c4e28b7cd299e01fc5c13 c37ef0bd30d84df79116ba9247cfb66c\n#: c8b4346f33e5443fbb32425aeaac3976 cb94891111504901bb93c32cc492a56e\n#: cc075b040dc84fd79ab823949da8569a cc70b1049ca94aae8a5ed47bbc2731b1\n#: cc8c8e6cb09e446dbd6c913800d9e92d cd44b293d5944613acbb4ebf13982f69\n#: de44007b099b4574b6ba370e8062081d e91161bf404a4c1aa6938f7206969d75\n#: e92666d7cb144f5aa9320e4172973126 ecb58c0295154bcba79da2c6bb14ecd0\n#: f5e2748d98ca490ba49440b716ce1557 f6ab3d9b4a4c4173b419ce4f678343f3\n#: f9bc09fc5ea34227a7114500e5ce81a6 fa33f17ae9614356bbae44d1f3ec88ff\n#: fd852a1fe1934034b07fecc82f20016f\nmsgid \"Parameters\"\nmsgstr \"パラメータ\"\n\n#: ../../document.rst:180 58d96afc6c3f4041817e26ee41843ed2\nmsgid \"\"\n\"A UTF-8 string or ``pathlib.Path`` object containing a file path. The \"\n\"document type is always determined from the file content.  The \"\n\"``filetype`` parameter is ignored, except when content inspection was \"\n\"unsuccessful. This is regularly the case for plain text types like \"\n\"\\\"txt\\\", \\\"html\\\", \\\"xml\\\" etc. with a wrong or missing file extension.\"\nmsgstr \"\"ファイルパスを含むUTF-8文字列または ``pathlib.Path`` オブジェクトです。\"\n\"ドキュメントタイプは常にファイルの内容から判定されます。\"\n\"``filetype`` パラメータは、内容の検査が失敗した場合を除いて無視されます。\"\n\"これは、誤った、または欠落したファイル拡張子を持つ \"\n\"\\\"txt\\\"、\\\"html\\\"、\\\"xml\\\" などのプレーンテキストタイプでよくあるケースです。\"\"\n\n#: ../../document.rst:182 42a021002ca24463805b8c682c3ef247\nmsgid \"\"\n\"A memory area containing file data. The document type is always detected \"\n\"from the data content. The ``filetype`` parameter is ignored, except when\"\n\" content inspection was unsuccessful. This is regularly the case for \"\n\"plain text types like \\\"txt\\\", \\\"html\\\", \\\"xml\\\" etc.\"\nmsgstr \"\"ファイルデータを含むメモリ領域です。ドキュメントタイプは常にデータの内容から検出されます。\"\n\"``filetype`` パラメータは、内容の検査が失敗した場合を除いて無視されます。\"\n\"これは、\\\"txt\\\"、\\\"html\\\"、\\\"xml\\\" などのプレーンテキストタイプでよくあるケースです。\"\"\n\n#: ../../document.rst:184 df0bacd926f548f7993192643669e3da\nmsgid \"\"\n\"A string specifying the type of document. This is only ever needed when \"\n\"file content inspection fails. Text types like \\\"txt\\\", \\\"html\\\", \\\"xml\\\"\"\n\" etc. cannot be disambiguated by their content. When such files are \"\n\"provided in memory or being provided with the wrong file extension, this \"\n\"parameter **must** be used.\"\nmsgstr \"\"ドキュメントのタイプを指定する文字列です。これは、ファイル内容の検査が失敗した場合にのみ必要です。\"\n\"\\\"txt\\\"、\\\"html\\\"、\\\"xml\\\" などのテキストタイプは、その内容によって識別することができません。\"\n\"このようなファイルがメモリ内で提供される場合、または誤ったファイル拡張子で提供される場合、\"\n\"このパラメータを **必ず** 使用してください。\"\"\n\n#: ../../document.rst:186 78759e58f1034e9b8808547679e5f0c7\nmsgid \"\"\n\"a rectangle specifying the desired page size. This parameter is only \"\n\"meaningful for documents with a variable page layout (\\\"reflowable\\\" \"\n\"documents), like e-books or HTML, and ignored otherwise. If specified, it\"\n\" must be a non-empty, finite rectangle with top-left coordinates (0, 0). \"\n\"Together with parameter :data:`fontsize`, each page will be accordingly \"\n\"laid out and hence also determine the number of pages.\"\nmsgstr \"\"\n\"希望のページサイズを指定する矩形。このパラメータは可変ページレイアウト（\\\"reflowable\\\" ドキュメント）を持つドキュメント（電子書籍や\"\n\" HTML のようなもの）にのみ意味があり、それ以外の場合は無視されます。指定される場合、非空で有限な矩形で、左上座標 (0, 0) \"\n\"を持っていなければなりません。*fontsize* パラメータと一緒に、各ページのレイアウトが適切に行われ、したがってページ数も決定されます。\"\n\n#: ../../document.rst:188 a39ff59bcd5b443e8be15251425208dd\nmsgid \"\"\n\"may used together with ``height`` as an alternative to ``rect`` to \"\n\"specify layout information.\"\nmsgstr \"レイアウト情報を指定するための ``rect`` の代替として、 ``height``  と一緒に使用できます。\"\n\n#: ../../document.rst:190 5850f945318e4c5ba3ad88d7be9ed8f7\nmsgid \"\"\n\"may used together with ``width`` as an alternative to ``rect`` to specify\"\n\" layout information.\"\nmsgstr \"レイアウト情報を指定するための ``rect`` の代替として、 ``width`` と一緒に使用できます。\"\n\n#: ../../document.rst:192 a2fc132738884e6f835292f70dbf813b\nmsgid \"\"\n\"the default :data:`fontsize` for reflowable document types. This \"\n\"parameter is ignored if none of the parameters ``rect`` or ``width`` and \"\n\"``height`` are specified. Will be used to calculate the page layout.\"\nmsgstr \"\"\n\"可変ページドキュメントタイプのデフォルト :data:`fontsize`。 ``rect`` または ``width`` と \"\n\"``height`` のいずれのパラメータも指定されていない場合、このパラメータは無視されます。ページレイアウトを計算するために使用されます。\"\n\n#: ../../document.rst 31cdc47b32794a798531bbe848c5bda9\n#: 8c8d6154dfd44d2ba07f8f96a6d9efca\nmsgid \"Raises\"\nmsgstr \"\"\n\n#: ../../document.rst:194 93b67db706e5441b96d643f164ce062f\nmsgid \"if the *type* of any parameter does not conform.\"\nmsgstr \"任意のパラメータの *型* が準拠していない場合。\"\n\n#: ../../document.rst:195 42762fcf592649558e1963103f6dc8a7\nmsgid \"\"\n\"if the file / path cannot be found. Re-implemented as subclass of \"\n\"`RuntimeError`.\"\nmsgstr \"ファイル/パスが見つからない場合。`RuntimeError` のサブクラスとして再実装されました。\"\n\n#: ../../document.rst:196 2057576b00c94522986d094e8c68c1df\nmsgid \"\"\n\"if the file / path is empty or the `bytes` object in memory has zero \"\n\"length. A subclass of `FileDataError` and `RuntimeError`.\"\nmsgstr \"\"\n\"ファイル/パスが空であるか、メモリ内の `bytes` オブジェクトの長さがゼロの場合。`FileDataError` および \"\n\"`RuntimeError` のサブクラス。\"\n\n#: ../../document.rst:197 7af323bd72ba4aeab2300ae9ce1c8deb\nmsgid \"if an unknown file type is explicitly specified.\"\nmsgstr \"明示的に未知のファイルタイプが指定された場合。\"\n\n#: ../../document.rst:198 18d265e2b9244cc3abe76c5bbd2278b0\nmsgid \"\"\n\"if the document has an invalid structure for the given type -- or is no \"\n\"file at all (but e.g. a folder). A subclass of `RuntimeError`.\"\nmsgstr \"\"\n\"ドキュメントが指定されたタイプに対して無効な構造を持っているか、ファイルではない場合（たとえば、フォルダの場合）。`RuntimeError` \"\n\"のサブクラス。\"\n\n#: ../../document.rst 047c76e2fca94ff59ddfc0ba555820e2\n#: 05f5daa98f00493bbb7a374f27f0a4b2 0659f08fa83e47a5955522391fa15698\n#: 06edaf8239974c938d93dc80fa34d7b3 07f23348a83747a994bfc38292cb6817\n#: 158edb1f340741378949ce4bab7d1208 192965113ee04caf8146575bc393c6b2\n#: 2059d856b5964cc6a0bf7b8f3fda5404 22190b4c653441329a53fd9cd6af3bb8\n#: 226eb33d228e44ddb55b37be48020765 24bc92cfaa3940289ca3ea8cd27d3106\n#: 2dafdb9211e64d488d5e9593226ca06e 312853a1c43e4fe0a603faa0c4dceabc\n#: 31ab2b887428472a8ad5bd876a2c0fa3 3ecac14ada7f4ac787def38bf6a8f6cf\n#: 3f9435a31fca4d4d8cbb170875d2a3a4 464a3d0819674be3a513b02da8c87f09\n#: 4c3f4194da5c4dea946bb543c410e000 556c0e94fdbc48f7ad1c45b988d89c4b\n#: 57359910ea7448e7a17fd9dedd43b13f 57bff51834564091b9d1b4055ff2a4e2\n#: 6056f1e956114601907e8db93075c69d 64ecbf4b3b474f7eb72622284e2cb7ba\n#: 66279346c97044d48e845dc1660bd20c 729ef3cc086d42e98982d5116d01854d\n#: 760161a30c3e4264b6add40c459ecd55 779098b76b7e497ea7d0ac5ff5f230ba\n#: 7807cc54e173424c98cd91c0e09a81fe 7ae314f6b0e24da3a92ce747b3bbcf11\n#: 882d32145fa2437186746febf7ff6b9e 8dd9a3cf674448ce866dfa99e2966320\n#: 977bcac8f3714ed9bc2f7a27dce3d310 9988c1213e394ff0839023541b3cda02\n#: acbfc888b60d461b8e34b1893ba6857b ad784150a80c454cb020cf1b36616ada\n#: addfabd60db741858e920a4caf7bee46 aff867c7df6c43feb44be7a1705c3c90\n#: b532e1af2f86421292f40080c67d8130 ce1aa2bb29194111b35b8883f494fbbb\n#: cfed3fbff8a046ed885355b399d4a2ab ebbe17e44f874fdd8ecbc146d1756273\n#: ec39975fff364d138618b3f0a03d7f7c f01df95655be4d7ba337b69dc87134d0\n#: faa22c65030b43fabbb90aae7cc4bcbb fb61cf4fd04246d88877968bcd325279\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../document.rst:200 cf78e0bdd8b34963964a9914c2b152e3\nmsgid \"\"\n\"A document object. If the document cannot be created, an exception is \"\n\"raised in the above sequence. Note that PyMuPDF-specific exceptions, \"\n\"`FileNotFoundError`, `EmptyFileError` and `FileDataError` are intercepted\"\n\" if you check for `RuntimeError`.  In case of problems you can see more \"\n\"detail in the internal messages store: \"\n\"`print(pymupdf.TOOLS.mupdf_warnings())` (which will be emptied by this \"\n\"call, but you can also prevent this -- consult \"\n\":meth:`Tools.mupdf_warnings`).\"\nmsgstr \"\"\n\n#: ../../document.rst:200 a8c942677a9c4be198f8b855f9a7aa87\nmsgid \"\"\n\"A document object. If the document cannot be created, an exception is \"\n\"raised in the above sequence. Note that PyMuPDF-specific exceptions, \"\n\"`FileNotFoundError`, `EmptyFileError` and `FileDataError` are intercepted\"\n\" if you check for `RuntimeError`.\"\nmsgstr \"\"\n\"ドキュメントオブジェクト。ドキュメントを作成できない場合、上記の順序で例外が発生します。PyMuPDF固有の例外、`FileNotFoundError`\"\n\" 、`EmptyFileError` 、および `FileDataError` は、`RuntimeError` \"\n\"をチェックする場合にキャッチされます。\"\n\n#: ../../document.rst:202 e37b3dcfa1ef4bb18a5147e0847b1947\nmsgid \"\"\n\"In case of problems you can see more detail in the internal messages \"\n\"store: `print(pymupdf.TOOLS.mupdf_warnings())` (which will be emptied by \"\n\"this call, but you can also prevent this -- consult \"\n\":meth:`Tools.mupdf_warnings`).\"\nmsgstr \"\"\n\"問題が発生した場合、内部メッセージストアで詳細を確認できます： `print(pymupdf.TOOLS.mupdf_warnings())` \"\n\"（この呼び出しによって空にされますが、これを防ぐこともできます - :meth:`Tools.mupdf_warnings` \"\n\"を参照してください）。\"\n\n#: ../../document.rst:204 2b66040c852944bf8054bbb5fc40f830\nmsgid \"Overview of possible forms, note: `open` is a synonym of `Document`::\"\nmsgstr \"可能なフォームの概要、注： `open` は `Document` の同義語です::\"\n\n#: ../../document.rst:221 64bcc08b1e204f36b85a92e3bf4a7b7b\nmsgid \"\"\n\"Raster images with a wrong (but supported) file extension **are no \"\n\"problem**. MuPDF will determine the correct image type when file \"\n\"**content** is actually accessed and will process it without complaint.\"\nmsgstr \"\"\n\"サポートされているが正しくないファイル拡張子を持つラスター画像は **問題ありません** 。MuPDFは、ファイルの実際の **内容**  \"\n\"がアクセスされると正しい画像タイプを判断し、何もクレームをつけずに処理します。\"\n\n#: ../../document.rst:223 f9c50ee3ebf24470b38de4cdc1f54b1b\nmsgid \"\"\n\"The Document class can be also be used as a **context manager**. Exiting \"\n\"the content manager will close the document automatically.\"\nmsgstr \"Document クラスは **コンテキストマネージャ** としても使用できます。終了時に、ドキュメントは自動的に閉じられます。\"\n\n#: ../../document.rst:239 ../../document.rst:249 ../../document.rst:309\n#: ../../document.rst:355 1730d717878941ef892b30c483eca126\n#: 483dca214c8e48079d2e4c46ba3235ca 4d05d842450e4edfae325ef65d2b7611\n#: f30d1bf6555e43a49b37fc613c1508b0\nmsgid \"New in v1.18.4\"\nmsgstr \"v1.18.4 で新規追加\"\n\n#: ../../document.rst:241 eba6c4b1e61146a6bb640a3f95719819\nmsgid \"\"\n\"Return the cross reference number of an :data:`OCG` or :data:`OCMD` \"\n\"attached to an image or form xobject.\"\nmsgstr \"画像またはフォームXObjectに添付された :data:`OCG` または :data:`OCMD` のクロスリファレンス番号を返します。\"\n\n#: ../../document.rst:243 ad2e8305cca245ccbb0fb3c0b6258d90\nmsgid \"\"\n\"the :data:`xref` of an image or form xobject. Valid such cross reference \"\n\"numbers are returned by :meth:`Document.get_page_images`, resp. \"\n\":meth:`Document.get_page_xobjects`. For invalid numbers, an exception is \"\n\"raised.\"\nmsgstr \"\"\n\"画像またはフォームXObjectの :data:`xref` \"\n\"。有効なクロスリファレンス番号は、:meth:`Document.get_page_images` または \"\n\":meth:`Document.get_page_xobjects` で返されます。無効な番号の場合、例外が発生します。\"\n\n#: ../../document.rst 0500953c20e7437cb07eb1e5b5ab6d95\n#: 0a34e8c806934adbb39a562cec45ed00 0dbcdc6042ab41719e7bfb23d45e9498\n#: 0f529499a28c45e689047cb279bef176 2dfb2fc75f3c4ae48c9621d951c8b20d\n#: 34e50adf35b049d59f94366d6a1c4d01 3c8c31137eed41449dd23adac7aa0431\n#: 4b2ccda028124833b98c4b8d75dc5796 4bef2068106e4e12b153e5f9c3d0a73f\n#: 553755100d5e4a9fbdac0009e6aab03b 613035964f614edeaf5c9e07ebae1838\n#: 6ef8b75ae6c942cb8bab3048fece0e1c 7f12d638e7764df0b3b1b81088afcdad\n#: 80b0f09950a4445fa028f7bff7e85366 80f84520db924d0398f865a7c6875a5f\n#: 821c42fa24fe4ff68ef126f5150071ab 8a85efe68f114c0eae3355efc6be9ed9\n#: 90fd0a7b1fd84565868c7a4915335e92 910331f87ce84bedb176f82e21061663\n#: ab6d6004faef490596417bcdad04ff0e ab9ee70f563b4f58b630bd00db9096cc\n#: b1fb8a32cfbf4a3185cc6a0b9dffa6f0 b35706daab7e445e88f47d8377413f7f\n#: ba9ffa28e36f4e13bbd25d4f25a464a1 bfdee673d70a4b918589e416740c1b9c\n#: cbc5f629858c4424b7ee4ec850a7588b cd443890b968437eae8ea9cc73288cec\n#: d1a86fcdf8044a5cae21c2c3e71a8a30 d211bea9230d4be78a69c08250062eca\n#: e5405416c793476395b89cc26926e4a6 e810c1ec77c24b9b983b6168bc72c737\n#: e9ad8885d4414821ab5dda6ccb064634 f51ea798020a41dfa00ef5586e64de2a\n#: f8a557a2ff2a48ecbece73e853f0a03b fc5ab7c5392b43dfb5212c6091f15304\n#: fef16f5342014574b4c13ceed01202b0\nmsgid \"Return type\"\nmsgstr \"戻り値の型\"\n\n#: ../../document.rst:245 c041477b58714e209412601d6ad826df\nmsgid \"\"\n\"the cross reference number of an optional contents object or zero if \"\n\"there is none.\"\nmsgstr \"オプションコンテンツオブジェクトのクロスリファレンス番号、または存在しない場合はゼロ。\"\n\n#: ../../document.rst:251 c8de893dbc234e21bc29025c8fced233\nmsgid \"\"\n\"If :data:`xref` represents an image or form xobject, set or remove the \"\n\"cross reference number *ocxref* of an optional contents object.\"\nmsgstr \"\"\n\":data:`xref` が画像またはフォームXObjectを表す場合、オプションコンテンツオブジェクトのクロスリファレンス番号 *ocxref*\"\n\"  を設定または削除します。\"\n\n#: ../../document.rst:253 6267c33679a84edbad42cf549b96a4d7\nmsgid \"\"\n\"the :data:`xref` of an image or form xobject [#f5]_. Valid such cross \"\n\"reference numbers are returned by :meth:`Document.get_page_images`, resp.\"\n\" :meth:`Document.get_page_xobjects`. For invalid numbers, an exception is\"\n\" raised.\"\nmsgstr \"\"\n\"画像またはフォームXObjectの :data:`xref` \"\n\"[#f5]_。有効なクロスリファレンス番号は、:meth:`Document.get_page_images` または \"\n\":meth:`Document.get_page_xobjects` で返されます。無効な番号の場合、例外が発生します。\"\n\n#: ../../document.rst:254 dafcd054da864b7bac355ee5b787c2db\nmsgid \"\"\n\"the :data:`xref` number of an :data:`OCG` / :data:`OCMD`. If not zero, an\"\n\" invalid reference raises an exception. If zero, any OC reference is \"\n\"removed.\"\nmsgstr \"\"\n\":data:`OCG` / :data:`OCMD` の :data:`xref` \"\n\"番号。ゼロでない場合、無効な参照は例外を発生させます。ゼロの場合、任意のOC参照が削除されます。\"\n\n#: ../../document.rst:259 ../../document.rst:269 ../../document.rst:280\n#: ../../document.rst:292 ../../document.rst:366 ../../document.rst:378\n#: ../../document.rst:400 ../../document.rst:418 ../../document.rst:434\n#: 23926cee6be044648a5c37b816d143bd 5cb2942c0bd2436aa86c4ef9fe4aeb7c\n#: 89fe4090f50d42499290ad8b8c5d9d27 8aab2fbbb4b740cc93f678bbf28f5d89\n#: bbf66277dd1d49b8aa08f5333630c6aa bfee650f7a0840288662be53901e0e16\n#: d64e06f1af29426e832fa442c29fae08 e6c3241b846345b49e2c2654f71724b5\n#: ec6c47d3bc2e4eeb91c14aba11424529\nmsgid \"New in v1.18.3\"\nmsgstr \"v1.18.3 で新規追加\"\n\n#: ../../document.rst:261 4a50ac946de94468b0d17ce0c5cd0bfd\nmsgid \"\"\n\"Show optional layer configurations. There always is a standard one, which\"\n\" is not included in the response.\"\nmsgstr \"オプションのレイヤー構成を表示します。常に標準のものが存在し、それは応答に含まれていません。\"\n\n#: ../../document.rst:271 62a7c759e42d4b04873f1b12d3184db4\nmsgid \"\"\n\"Add an optional content configuration. Layers serve as a collection of ON\"\n\" / OFF states for optional content groups and allow fast visibility \"\n\"switches between different views on the same document.\"\nmsgstr \"\"\n\"オプションのコンテンツ構成を追加します。レイヤーはオプションコンテンツグループのON / \"\n\"OFFの状態のコレクションとして機能し、同じドキュメントの異なるビュー間での高速な表示切り替えを可能にします。\"\n\n#: ../../document.rst:273 0407f1ddb2e2486d857a6ecfee7bdd01\nmsgid \"arbitrary name.\"\nmsgstr \"任意の名前。\"\n\n#: ../../document.rst:274 78e5e16c7cde40f587fa378470778e67\nmsgid \"(optional) creating software.\"\nmsgstr \"（オプション）作成ソフトウェア。\"\n\n#: ../../document.rst:275 141b82fff5454e1bb16c1ad6b039bbed\nmsgid \"\"\n\"a sequence of OCG :data:`xref` numbers which should be set to ON when \"\n\"this layer gets activated. All OCGs not listed here will be set to OFF.\"\nmsgstr \"\"\n\"このレイヤーがアクティブになったときにONに設定されるOCG :data:`xref`  \"\n\"番号のシーケンス。ここでリストされていないすべてのOCGはOFFに設定されます。\"\n\n#: ../../document.rst:282 f4c042d87e1840a2843af4d4117001eb\nmsgid \"\"\n\"Switch to a document view as defined by the optional layer's \"\n\"configuration number. This is temporary, except if established as \"\n\"default.\"\nmsgstr \"オプションレイヤーの構成番号によって定義されたドキュメントビューに切り替えます。これは一時的なものであり、デフォルトとして確立されていない限り、一時的なものです。\"\n\n#: ../../document.rst:284 c5e86d78dd054fe59d48bfdfd027505f\nmsgid \"config number as returned by :meth:`Document.layer_configs`.\"\nmsgstr \":meth:`Document.layer_configs` によって返される構成番号。\"\n\n#: ../../document.rst:285 12da226f47384fb9856ab8e3539b8f7f\nmsgid \"make this the default configuration.\"\nmsgstr \"これをデフォルト構成にします。\"\n\n#: ../../document.rst:287 a0359149d06f41c3a0c31aa7fd513161\nmsgid \"\"\n\"Activates the ON / OFF states of OCGs as defined in the identified layer.\"\n\" If ``as_default=True``, then additionally all layers, including the \"\n\"standard one, are merged and the result is written back to the standard \"\n\"layer, and **all optional layers are deleted**.\"\nmsgstr \"\"\n\"識別されたレイヤーで定義されたOCGのON / OFFの状態をアクティブにします。 ``as_default=True`` \"\n\"の場合、追加で、標準のレイヤーを含むすべてのレイヤーがマージされ、結果が標準レイヤーに書き込まれ、 \"\n\"**すべてのオプションレイヤーが削除されます** 。\"\n\n#: ../../document.rst:294 019d0c5001d94da99732a3ea85edb766\nmsgid \"\"\n\"Add an optional content group. An OCG is the most important unit of \"\n\"information to determine object visibility. For a PDF, in order to be \"\n\"regarded as having optional content, at least one OCG must exist.\"\nmsgstr \"オプションコンテンツグループを追加します。OCGはオブジェクトの表示を決定するための最も重要な情報単位です。PDFでは、オプションコンテンツとして扱われるためには、少なくとも1つのOCGが存在する必要があります。\"\n\n#: ../../document.rst:296 df98d756b4024732b2403d8409bb80d0\nmsgid \"arbitrary name. Will show up in supporting PDF viewers.\"\nmsgstr \"任意の名前。サポートするPDFビューアに表示されます。\"\n\n#: ../../document.rst:297 645459e390354faea10340dc61b7b599\nmsgid \"layer configuration number. Default -1 is the standard configuration.\"\nmsgstr \"レイヤー構成番号。デフォルトは-1で、標準構成です。\"\n\n#: ../../document.rst:298 f6fa2faa541148c5accbe497d973571b\nmsgid \"standard visibility status for objects pointing to this OCG.\"\nmsgstr \"このOCGを指すオブジェクトの標準の表示状態。\"\n\n#: ../../document.rst:299 40453f0b3a0b40219a2f25b7ebc97193\nmsgid \"\"\n\"a string or list of strings declaring the visibility intents. There are \"\n\"two PDF standard values to choose from: \\\"View\\\" and \\\"Design\\\". Default \"\n\"is \\\"View\\\". Correct **spelling is important**.\"\nmsgstr \"\"\n\"表示意図を宣言する文字列または文字列のリスト。PDF標準の2つの値から選択できます: \\\"View\\\" と \\\"Design\\\"。デフォルトは \"\n\"\\\"View\\\" です。 **正確なスペルが重要です** 。\"\n\n#: ../../document.rst:300 5c48545ceb124bb5a9377cf6d70d146f\nmsgid \"\"\n\"another influencer for OCG visibility. This will become part of the OCG's\"\n\" `/Usage` key. There are two PDF standard values to choose from: \"\n\"\\\"Artwork\\\" and \\\"Technical\\\". Default is \\\"Artwork\\\". Please only change\"\n\" when required.\"\nmsgstr \"\"\n\"OCGの表示に影響を与えるもう一つの要因。これはOCGの `/Usage` キーの一部になります。PDF標準の2つの値から選択できます: \"\n\"\\\"Artwork\\\" と \\\"Technical\\\"。デフォルトは \\\"Artwork\\\" です。必要な場合にのみ変更してください。\"\n\n#: ../../document.rst:302 747d12bc0ae0484c9865443714401394\nmsgid \"\"\n\":data:`xref` of the created OCG. Use as entry for `oc` parameter in \"\n\"supporting objects.\"\nmsgstr \"作成されたOCGの :data:`xref` 。サポートオブジェクトの `oc` パラメータのエントリとして使用します。\"\n\n#: ../../document.rst:304 e6da50b60736424ab6212f1f73d1e613\nmsgid \"\"\n\"Multiple OCGs with identical parameters may be created. This will not \"\n\"cause problems. Garbage option 3 of :meth:`Document.save` will get rid of\"\n\" any duplicates.\"\nmsgstr \"\"\n\"同一のパラメータを持つ複数のOCGを作成することができます。これは問題を引き起こしません。:meth:`Document.save` \"\n\"のゴミオプション3を使用すれば、重複を削除できます。\"\n\n#: ../../document.rst:311 af571053832447268949688f1f4dfb77\nmsgid \"\"\n\"Create or update an :data:`OCMD`, **Optional Content Membership \"\n\"Dictionary.**\"\nmsgstr \":data:`OCMD` （ **Optional Content Membership Dictionary** ）を作成または更新します。\"\n\n#: ../../document.rst:313 176f6da4c473440c9136b9f539104722\nmsgid \":data:`xref` of the OCMD to be updated, or 0 for a new OCMD.\"\nmsgstr \"更新するOCMDの :data:`xref` 、または新しいOCMDの場合は0\"\n\n#: ../../document.rst:314 c62679a99da644e8b4803a0c9d329a9a\nmsgid \"a sequence of :data:`xref` numbers of existing :data:`OCG` PDF objects.\"\nmsgstr \"既存の :data:`OCG` PDFオブジェクトの :data:`xref` 番号のシーケンス。\"\n\n#: ../../document.rst:315 4b77e6d94ae7432085d1e1936f946ec6\nmsgid \"\"\n\"one of \\\"AnyOn\\\" (default), \\\"AnyOff\\\", \\\"AllOn\\\", \\\"AllOff\\\" (mixed or \"\n\"lower case).\"\nmsgstr \"\\\"AnyOn\\\"（デフォルト）、\\\"AnyOff\\\"、\\\"AllOn\\\"、\\\"AllOff\\\"のいずれか。大文字小文字は区別されません。\"\n\n#: ../../document.rst:316 52aa1d09e9274734ae9c2082f3543182\nmsgid \"\"\n\"a \\\"visibility expression\\\". This is a list of arbitrarily nested other \"\n\"lists -- see explanation below. Use as an alternative to the combination \"\n\"*ocgs* / *policy* if you need to formulate more complex conditions.\"\nmsgstr \"\"\n\"\\\"表示条件式\\\"。これは他のリストを任意に入れ子にしたリストです - 説明は以下を参照してください。より複雑な条件を定式化する必要がある場合、 \"\n\"*ocgs* / *policy* の組み合わせの代替として使用します。\"\n\n#: ../../document.rst:318 82c5e6b9f0df4f9e8364caf4e1030f20\nmsgid \"\"\n\":data:`xref` of the OCMD. Use as `oc=xref` parameter in supporting \"\n\"objects, and respectively in :meth:`Document.set_oc` or \"\n\":meth:`Annot.set_oc`.\"\nmsgstr \"\"\n\"OCMDの :data:`xref` 。サポートオブジェクトの `oc=xref` \"\n\"パラメータとして使用し、:meth:`Document.set_oc` または :meth:`Annot.set_oc` にもそれぞれ使用します。\"\n\n#: ../../document.rst:322 ff4a88e9bc164073a711f1c9e12ff4e5\nmsgid \"\"\n\"Like an OCG, an OCMD has a visibility state ON or OFF, and it can be used\"\n\" like an OCG. In contrast to an OCG, the OCMD state is determined by \"\n\"evaluating the state of one or more OCGs via special forms of **boolean \"\n\"expressions.** If the expression evaluates to true, the OCMD state is ON \"\n\"and OFF for false.\"\nmsgstr \"\"\n\"OCGと同様に、OCMDには表示状態ONまたはOFFがあり、OCGのように使用できます。OCGとは異なり、OCMDの状態は **ブール式** \"\n\"の特別な形式を使用して1つ以上のOCGの状態を評価することによって決定されます。式がtrueに評価される場合、OCMDの状態はONで、falseに評価される場合はOFFです。\"\n\n#: ../../document.rst:324 7624a64d7d344afcb6b9c711969255fd\nmsgid \"There are two ways to formulate OCMD visibility:\"\nmsgstr \"OCMDの表示を定式化する方法は2つあります:\"\n\n#: ../../document.rst:326 f286a0292bdc4233bb5cae6692a86360\nmsgid \"\"\n\"Use the combination of *ocgs* and *policy*: The *policy* value is \"\n\"interpreted as follows:\"\nmsgstr \"*ocgs* と *policy* の組み合わせを使用する: *policy* の値は次のように解釈されます：\"\n\n#: ../../document.rst:328 cd5febb83dd14249b5c74b772683ca78\nmsgid \"AnyOn -- (default) true if at least one OCG is ON.\"\nmsgstr \"(デフォルト) 少なくとも1つのOCGがONの場合、true。\"\n\n#: ../../document.rst:329 d198b9b66f374b60b940b079312cd963\nmsgid \"AnyOff -- true if at least one OCG is OFF.\"\nmsgstr \"少なくとも1つのOCGがOFFの場合、true。\"\n\n#: ../../document.rst:330 075a921c145249f5b1eca9f6602422ba\nmsgid \"AllOn -- true if all OCGs are ON.\"\nmsgstr \"すべてのOCGがONの場合、true。\"\n\n#: ../../document.rst:331 fa6c2c43aba44d159e35b8f57e646e0c\nmsgid \"AllOff -- true if all OCGs are OFF.\"\nmsgstr \"すべてのOCGがOFFの場合、true。\"\n\n#: ../../document.rst:333 06df4aa95eb7403f92d354cdafc71cc9\nmsgid \"\"\n\"Suppose you want two PDF objects be displayed exactly one at a time (if \"\n\"one is ON, then the other one must be OFF):\"\nmsgstr \"2つのPDFオブジェクトを、必ず1つずつ表示するようにしたい場合（1つがONの場合、他の1つはOFFにする必要があります）：\"\n\n#: ../../document.rst:335 65c7260ce3b54ff484d2f1642d17fc89\nmsgid \"\"\n\"Solution: use an **OCG** for object 1 and an **OCMD** for object 2. \"\n\"Create the OCMD via `set_ocmd(ocgs=[xref], policy=\\\"AllOff\\\")`, with the \"\n\":data:`xref` of the OCG.\"\nmsgstr \"\"\n\"解決策: オブジェクト1用のOCGとオブジェクト2用のOCMDを使用します。 OCMDは `set_ocmd(ocgs=[xref], \"\n\"policy=\\\"AllOff\\\")` を使用して作成し、OCGの :data:`xref` を指定します。\"\n\n#: ../../document.rst:337 daf6a22c4b2a43d6a4bab99eff6c02c3\nmsgid \"\"\n\"Use the **visibility expression** *ve*: This is a list of two or more \"\n\"items. The **first item** is a logical keyword: one of the strings \"\n\"**\\\"and\\\"**, **\\\"or\\\"**, or **\\\"not\\\"**. The **second** and all \"\n\"subsequent items must either be an integer or another list. An integer \"\n\"must be the :data:`xref` number of an OCG. A list must again have at \"\n\"least two items starting with one of the boolean keywords. This syntax is\"\n\" a bit awkward, but quite powerful:\"\nmsgstr \"\"\n\"**表示条件式** *ve* を使用する: これは2つ以上のアイテムから成るリストです。 **最初のアイテム** は論理キーワードで、文字列 \"\n\"**\\\"and\\\"** 、**\\\"or\\\"** 、または **\\\"not\\\"** \"\n\"のいずれかです。2番目以降のアイテムは整数または別のリストである必要があります。整数はOCGの :data:`xref` \"\n\"番号でなければなりません。リストは再び少なくとも2つのアイテムから始まり、ブールキーワードのいずれかで始まる必要があります。この構文はやや厄介ですが、非常に強力です：\"\n\n#: ../../document.rst:339 3542e922141d45e9bcd5d64b3ad00ead\nmsgid \"Each list must start with a logical keyword.\"\nmsgstr \"各リストは論理キーワードで始まる必要があります。\"\n\n#: ../../document.rst:340 fa6c94f45a68492895b165d5688053b2\nmsgid \"\"\n\"If the keyword is a **\\\"not\\\"**, then the list must have exactly two \"\n\"items. If it is **\\\"and\\\"** or **\\\"or\\\"**, any number of other items may \"\n\"follow.\"\nmsgstr \"\"\n\"キーワードが **\\\"not\\\"** の場合、リストは正確に2つのアイテムを持たなければなりません。 **\\\"and\\\"** または \"\n\"**\\\"or\\\"** の場合、その後にいくつでも他のアイテムが続くことができます。\"\n\n#: ../../document.rst:341 2d88da6745cb40e5afe68d8a712a15df\nmsgid \"\"\n\"Items following the logical keyword may be either integers or again a \"\n\"list. An *integer* must be the xref of an OCG. A *list* must conform to \"\n\"the previous rules.\"\nmsgstr \"\"\n\"論理キーワードの後に続くアイテムは、整数または再びリストである必要があります。 *整数* はOCGのxref番号でなければなりません。 *リスト*\"\n\" は前述のルールに従う必要があります。\"\n\n#: ../../document.rst:343 d786a59eab5449a5ad1c6130e01c2bca\nmsgid \"**Examples:**\"\nmsgstr \"**例:** \"\n\n#: ../../document.rst:345 32e37d05f4b94a2c9f8a2241e144216c\nmsgid \"\"\n\"`set_ocmd(ve=[\\\"or\\\", 4, [\\\"not\\\", 5], [\\\"and\\\", 6, 7]])`. This delivers \"\n\"ON if the following is true: **\\\"4 is ON, or 5 is OFF, or 6 and 7 are \"\n\"both ON\\\"**.\"\nmsgstr \"\"\n\"`set_ocmd(ve=[\\\"or\\\", 4, [\\\"not\\\", 5], [\\\"and\\\", 6, 7]])` \"\n\"。これは次の条件がtrueの場合にONを返します: **\\\"4がON、または5がOFF、または6と7が両方ON** \\\"。\"\n\n#: ../../document.rst:346 8bff1ec6e8a545a19fcf60c341c39b3f\nmsgid \"\"\n\"`set_ocmd(ve=[\\\"not\\\", xref])`. This has the same effect as the OCMD \"\n\"example created under 1.\"\nmsgstr \"`set_ocmd(ve=[\\\"not\\\", xref])` 。これは1で作成されたOCMDの例と同じ効果があります。\"\n\n#: ../../document.rst:348 bb5ab99cc5154c058bd6c6c21d77efdb\nmsgid \"\"\n\"For more details and examples see page 224 of :ref:`AdobeManual`. Also do\"\n\" have a look at example scripts `here <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/optional-content>`_.\"\nmsgstr \"\"\n\"詳細と例については、 :ref:`AdobeManual` の224ページを参照してください。また、`こちら \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/optional-\"\n\"content>`_ の例のスクリプトもご覧いただけます。\"\n\n#: ../../document.rst:350 710f05e9b696464fa3f0137f62c2204b\nmsgid \"\"\n\"Visibility expressions, `/VE`, are part of PDF specification version 1.6.\"\n\" So not all PDF viewers / readers may already support this feature and \"\n\"hence will react in some standard way for those cases.\"\nmsgstr \"\"\n\"表示条件式 `/VE` \"\n\"はPDF仕様バージョン1.6の一部です。したがって、すべてのPDFビューア/リーダーがすでにこの機能をサポートしているわけではなく\"\n\n#: ../../document.rst:357 fad572b38ee64c15b7ffc0ca037efa59\nmsgid \"Retrieve the definition of an :data:`OCMD`.\"\nmsgstr \":data:`OCMD` の定義を取得します。\"\n\n#: ../../document.rst:359 3a57bb52cf234bbeaa0eef4f2d589d31\nmsgid \"the :data:`xref` of the OCMD.\"\nmsgstr \":data:`xref` （int）- OCMDのxref。\"\n\n#: ../../document.rst:361 8beef4ef63b642df94ebb105bec160d8\nmsgid \"a dictionary with the keys :data:`xref`, *ocgs*, *policy* and *ve*.\"\nmsgstr \":data:`xref` 、*ocgs* 、*policy*、*ve* のキーを持つ辞書\"\n\n#: ../../document.rst:368 e2155a3ac05040b9add64191e6b9e0ff\nmsgid \"\"\n\"List of optional content groups by status in the specified configuration.\"\n\" This is a dictionary with lists of cross reference numbers for OCGs that\"\n\" occur in the arrays `/ON`, `/OFF` or in some radio button group \"\n\"(`/RBGroups`).\"\nmsgstr \"\"\n\"指定された構成内のステータス別オプションコンテンツグループのリスト。これは、OCGsのクロスリファレンス番号のリストを持つ辞書で、`/ON` \"\n\"、`/OFF` 、またはラジオボタングループ (`/RBGroups`) のいずれかに出現するOCGsに対応しています。\"\n\n#: ../../document.rst:370 5c4df35639784744a466356b3362cbc6\nmsgid \"the configuration layer (default is the standard config layer).\"\nmsgstr \"構成レイヤー（デフォルトは標準の構成レイヤー）。\"\n\n#: ../../document.rst:380 2f281f33088346b08c527ae42e6f1c4e\nmsgid \"Changed in v1.22.5: Support list of *locked* OCGs.\"\nmsgstr \"バージョン1.22.5で変更: *ロックされた* OCGのリストをサポート。\"\n\n#: ../../document.rst:382 e1b37420106d4246a034d0a858461ca2\nmsgid \"\"\n\"Mass status changes of optional content groups. **Permanently** sets the \"\n\"status of OCGs.\"\nmsgstr \"オプションコンテンツグループの大量ステータス変更。OCGのステータスを **永続的に** 設定します。\"\n\n#: ../../document.rst:384 a2e67c4937b043b797822f7cd599b808\nmsgid \"desired configuration layer, choose -1 for the default one.\"\nmsgstr \"希望の構成レイヤー、デフォルトのものには-1を選択します。\"\n\n#: ../../document.rst:385 a5d626582a0c4adeac28522f8e23f533\nmsgid \"\"\n\"list of :data:`xref` of OCGs to set ON. Replaces previous values. An \"\n\"empty list will cause no OCG being set to ON anymore. Should be specified\"\n\" if `basestate=\\\"ON\\\"` is used.\"\nmsgstr \"\"\n\"ONに設定するOCGの :data:`xref` \"\n\"のリスト。以前の値を置換します。空のリストはもうOCGをONに設定しなくなります。`basestate=\\\"ON\\\"` \"\n\"が使用される場合は指定する必要があります。\"\n\n#: ../../document.rst:386 b105d154868648c0a78aa7ddeab0e341\nmsgid \"\"\n\"list of :data:`xref` of OCGs to set OFF. Replaces previous values. An \"\n\"empty list will cause no OCG being set to OFF anymore. Should be \"\n\"specified if `basestate=\\\"OFF\\\"` is used.\"\nmsgstr \"\"\n\"OFFに設定するOCGの :data:`xref` のリスト。以前の値を置換します。空のリストはもうOCGをOFFに設定しなくなります。 \"\n\"`basestate=\\\"OFF\\\"` が使用される場合は指定する必要があります。\"\n\n#: ../../document.rst:387 00ee5fd0e019474a870809b586d7a8dc\nmsgid \"\"\n\"state of OCGs that are not mentioned in *on* or *off*. Possible values \"\n\"are \\\"ON\\\", \\\"OFF\\\" or \\\"Unchanged\\\". Upper / lower case possible.\"\nmsgstr \"\"\n\"*on* または *off* \"\n\"で言及されていないOCGの状態。可能な値は「ON」、「OFF」または「Unchanged」です。大文字/小文字を区別できます。\"\n\n#: ../../document.rst:388 00be43e01f734962a6706a02e112feb2\nmsgid \"\"\n\"a list of lists. Replaces previous values. Each sublist should contain \"\n\"two or more OCG xrefs. OCGs in the same sublist are handled like buttons \"\n\"in a radio button group: setting one to ON automatically sets all other \"\n\"group members to OFF.\"\nmsgstr \"\"\n\"リストのリスト。以前の値を置換します。各サブリストには2つ以上のOCG \"\n\"xrefを含める必要があります。同じサブリスト内のOCGはラジオボタングループ内のボタンのように処理され、1つをONに設定すると他のすべてのグループメンバーがOFFに設定されます。\"\n\n#: ../../document.rst:389 fa0a09aca08c40b1b90f36b23146c355\nmsgid \"a list of OCG xref number that cannot be changed by the user interface.\"\nmsgstr \"ユーザーインターフェースで変更できないOCG xref番号のリスト。\"\n\n#: ../../document.rst:391 e1c4e0490d9940e1883ad98f81859df8\nmsgid \"Values `None` will not change the corresponding PDF array.\"\nmsgstr \"値 `None` は対応するPDF配列を変更しません。\"\n\n#: ../../document.rst:402 6b83e49681b24a10b144d4a9e4acc01d\nmsgid \"\"\n\"Details of all optional content groups. This is a dictionary of \"\n\"dictionaries like this (key is the OCG's :data:`xref`):\"\nmsgstr \"オプションコンテンツグループの詳細情報。これは次のような辞書の辞書です（キーはOCGの :data:`xref` です）：\"\n\n#: ../../document.rst:420 36edc40743fe4afb943bac223003f082\nmsgid \"\"\n\"Show the visibility status of optional content that is modifiable by the \"\n\"user interface of supporting PDF viewers.\"\nmsgstr \"サポートするPDFビューアのユーザーインターフェースで変更可能なオプションコンテンツの表示状態を表示します。\"\n\n#: ../../document.rst:422 75b0b7f00565469eb5c15de91d146e92\nmsgid \"\"\n\"Only reports items contained in the currently selected layer \"\n\"configuration.\"\nmsgstr \"現在選択されているレイヤー設定に含まれるアイテムのみを報告します。\"\n\n#: ../../document.rst:429 34d23ea600964ffa9e171337ddac9bef\nmsgid \"The meaning of the dictionary keys is as follows:\"\nmsgstr \"辞書のキーの意味は次の通りです：\"\n\n#: ../../document.rst:425 a6f590d8251a4781a92016be8710b113\nmsgid \"*depth:* item's nesting level in the `/Order` array\"\nmsgstr \"*depth:*  `/Order` 配列内のアイテムのネストレベル\"\n\n#: ../../document.rst:426 f6a9c537d38e4cdb89490b8d63d75c4b\nmsgid \"*locked:* true if cannot be changed via user interfaces\"\nmsgstr \"*locked:* ユーザーインターフェースを介して変更できない場合はtrue\"\n\n#: ../../document.rst:427 208b1ca352e74127bda9ca8a9983cbe6\nmsgid \"*number:* running sequence number\"\nmsgstr \"*number:* 連続するシーケンス番号\"\n\n#: ../../document.rst:428 ab611eafc0ae4bbfb5cfc33ec4c9f161\nmsgid \"*on:* item state\"\nmsgstr \"*on:* アイテムの状態\"\n\n#: ../../document.rst:429 6fd780d71a13487ca690fbfc3311d4bd\nmsgid \"*text:* text string or name field of the originating OCG\"\nmsgstr \"*text:* 元のOCGのテキスト文字列または名前フィールド\"\n\n#: ../../document.rst:430 286752141da0452e9dff2a920379fecb\nmsgid \"\"\n\"*type:* one of \\\"label\\\" (set by a text string), \\\"checkbox\\\" (set by a \"\n\"single OCG) or \\\"radiobox\\\" (set by a set of connected OCGs)\"\nmsgstr \"\"\n\"*type:* \\\"label\\\"（テキスト文字列によって設定）、\\\"checkbox\\\"（単一のOCGによって設定）、または \"\n\"\\\"radiobox\\\"（接続されたOCGのセットによって設定）のいずれか\"\n\n#: ../../document.rst:436 623754e00b3f43feaccf231803da154d\nmsgid \"\"\n\"Modify OC visibility status of content groups. This is analog to what \"\n\"supporting PDF viewers would offer.\"\nmsgstr \"コンテンツグループのOC表示状態を変更します。これは、サポートするPDFビューアが提供するものと同様です。\"\n\n#: ../../document.rst:438 7a68db8cb2cb477680821155ce320684\nmsgid \"\"\n\"Please note that visibility is **not** a property stored with the OCG. It\"\n\" is not even information necessarily present in the PDF document at all. \"\n\"Instead, the current visibility is **temporarily** set using the user \"\n\"interface of some supporting PDF consumer software. The same type of \"\n\"functionality is offered by this method.\"\nmsgstr \"\"\n\"表示状態はOCGとして保存されるプロパティ **ではない** \"\n\"ことに注意してください。それはPDFドキュメントに必ずしも存在しない情報でもありません。代わりに、現在の表示状態はサポートするPDF消費者ソフトウェアのユーザーインターフェースを使用して**一時的に**\"\n\" 設定されます。このメソッドでも同じタイプの機能が提供されます。\"\n\n#: ../../document.rst:440 81a92011a9ea497fb7600465d2f7249c\nmsgid \"To make **permanent** changes, use :meth:`Document.set_layer`.\"\nmsgstr \"**永続的な** 変更を行うには、:meth:`Document.set_layer` を使用してください。\"\n\n#: ../../document.rst:442 995bfe639a02475fbeeb37b8f6e73e95\nmsgid \"\"\n\"either the sequence number of the item in list \"\n\":meth:`Document.layer_configs` or the \\\"text\\\" of one of these items.\"\nmsgstr \":meth:`Document.layer_configs` リストのアイテムのシーケンス番号またはこれらのアイテムの「テキスト」。\"\n\n#: ../../document.rst:443 775f2c9f68934b7098b0531a61f3e3a1\nmsgid \"\"\n\"`PDF_OC_ON` = set on (default), `PDF_OC_TOGGLE` = toggle on/off, \"\n\"`PDF_OC_OFF` = set off.\"\nmsgstr \"\"\n\"`PDF_OC_ON` = ONに設定（デフォルト）、`PDF_OC_TOGGLE` = ON/OFFを切り替え、`PDF_OC_OFF` = \"\n\"OFFに設定。\"\n\n#: ../../document.rst:448 27be24636736454f8669d2bf32f5850e\nmsgid \"\"\n\"Decrypts the document with the string *password*. If successful, document\"\n\" data can be accessed. For PDF documents, the \\\"owner\\\" and the \\\"user\\\" \"\n\"have different privileges, and hence different passwords may exist for \"\n\"these authorization levels. The method will automatically establish the \"\n\"appropriate (owner or user) access rights for the provided password.\"\nmsgstr \"\"\n\"文字列の *パスワード* \"\n\"でドキュメントを複合化します。成功した場合、ドキュメントデータにアクセスできます。PDFドキュメントの場合、「オーナー」および「ユーザー」には異なる特権があり、したがってこれらの認証レベルに異なるパスワードが存在する可能性があります。このメソッドは提供されたパスワードに適切な（オーナーまたはユーザー）アクセス権を自動的に確立します。\"\n\n#: ../../document.rst:450 85327273191345d7a0064b7bfa2198b3\nmsgid \"owner or user password.\"\nmsgstr \"オーナーまたはユーザーパスワード。\"\n\n#: ../../document.rst:453 9c5364f7fc154375a06079af2df92681\nmsgid \"\"\n\"a positive value if successful, zero otherwise (the string does not match\"\n\" either password). If positive, the indicator \"\n\":attr:`Document.is_encrypted` is set to ``False``. **Positive** return \"\n\"codes carry the following information detail:  * 1 => authenticated, but \"\n\"the PDF has neither owner nor user passwords. * 2 => authenticated with \"\n\"the **user** password. * 4 => authenticated with the **owner** password. \"\n\"* 6 => authenticated and both passwords are equal -- probably a rare \"\n\"situation.  .. note::    The document may be protected by an owner, but \"\n\"**not** by a user password. Detect this situation via \"\n\"`doc.authenticate(\\\"\\\") == 2`. This allows opening and reading the \"\n\"document without authentication, but, depending on the \"\n\":attr:`Document.permissions` value, other actions may be prohibited. \"\n\"PyMuPDF (like MuPDF) in this case **ignores those restrictions**. So, -- \"\n\"in contrast to any PDF viewers -- you can for example extract text and \"\n\"add or modify content, even if the respective permission flags \"\n\"`PDF_PERM_COPY`, `PDF_PERM_MODIFY`, `PDF_PERM_ANNOTATE`, etc. are set \"\n\"off! It is your responsibility building a legally compliant application \"\n\"where applicable.\"\nmsgstr \"\"\n\n#: ../../document.rst:453 08583032eafa41b7ac9b194f3bda03fa\nmsgid \"\"\n\"a positive value if successful, zero otherwise (the string does not match\"\n\" either password). If positive, the indicator \"\n\":attr:`Document.is_encrypted` is set to ``False``. **Positive** return \"\n\"codes carry the following information detail:\"\nmsgstr \"\"\n\"成功した場合は正の値、それ以外はゼロです（文字列がどちらのパスワードとも一致しない場合）。正の戻り値がある場合、インジケータ \"\n\":attr:`Document.is_encrypted` は ``False`` に設定されます。**正の** \"\n\"戻り値コードには、次の情報の詳細が含まれています：\"\n\n#: ../../document.rst:455 91f0bb6a692a4682a4c34c71ee148f1e\nmsgid \"1 => authenticated, but the PDF has neither owner nor user passwords.\"\nmsgstr \"1 => 認証済み、ただしPDFにはオーナーまたはユーザーパスワードがありません。\"\n\n#: ../../document.rst:456 ba4f57095e824261b0a64d65bc13465d\nmsgid \"2 => authenticated with the **user** password.\"\nmsgstr \"2 => **ユーザー** パスワードで認証済み。\"\n\n#: ../../document.rst:457 bfb7a0beede248c8a99fea4df83c1674\nmsgid \"4 => authenticated with the **owner** password.\"\nmsgstr \"4 => **オーナー** パスワードで認証済み。\"\n\n#: ../../document.rst:458 b8eaae626e8f42f29a0612cb9c166585\nmsgid \"\"\n\"6 => authenticated and both passwords are equal -- probably a rare \"\n\"situation.\"\nmsgstr \"6 => 認証済みで両方のパスワードが等しい-おそらくまれな状況\"\n\n#: ../../document.rst:462 73fc6cf7a70b4ed7b17c292f3bc63fa7\nmsgid \"\"\n\"The document may be protected by an owner, but **not** by a user \"\n\"password. Detect this situation via `doc.authenticate(\\\"\\\") == 2`. This \"\n\"allows opening and reading the document without authentication, but, \"\n\"depending on the :attr:`Document.permissions` value, other actions may be\"\n\" prohibited. PyMuPDF (like MuPDF) in this case **ignores those \"\n\"restrictions**. So, -- in contrast to any PDF viewers -- you can for \"\n\"example extract text and add or modify content, even if the respective \"\n\"permission flags `PDF_PERM_COPY`, `PDF_PERM_MODIFY`, `PDF_PERM_ANNOTATE`,\"\n\" etc. are set off! It is your responsibility building a legally compliant\"\n\" application where applicable.\"\nmsgstr \"\"\n\"ドキュメントはオーナーによって保護されている場合でも、ユーザーパスワードによって保護 **されていない** \"\n\"場合があります。この状況は、`doc.authenticate(\\\"\\\") == 2` \"\n\"を使用して検出できます。これにより、認証なしでドキュメントを開いて読むことができますが、:attr:`Document.permissions` \"\n\"値に応じて、他のアクションが制限される場合があります。この場合、PyMuPDF（MuPDFと同様）はこれらの **制限を無視します** \"\n\"。したがって、`PDF_PERM_COPY` 、`PDF_PERM_MODIFY` 、`PDF_PERM_ANNOTATE` \"\n\"などの対応する許可フラグがオフに設定されていても、テキストを抽出したり、コンテンツを追加または変更したりすることができます！該当する場合、法的に適合するアプリケーションを構築する責任があります。\"\n\n#: ../../document.rst:466 119ec5a546d0492cbc3d44a94c5c6e67\nmsgid \"New in v 1.18.6\"\nmsgstr \"バージョン 1.18.6 での新機能\"\n\n#: ../../document.rst:468 71cef20992634be89bc64e392ac17031\nmsgid \"\"\n\"PDF only: Return a list of page numbers that have the specified label -- \"\n\"note that labels may not be unique in a PDF. This implies a sequential \"\n\"search through **all page numbers** to compare their labels.\"\nmsgstr \"\"\n\"PDF のみ：指定されたラベルを持つページ番号のリストを返します。ラベルは PDF \"\n\"では一意でないことがあることに注意してください。これは、**すべてのページ番号** を逐次検索してそのラベルを比較することを意味します。\"\n\n#: ../../document.rst:470 a2a599a9359442d8b21007f88a6371db\nmsgid \"Implementation detail -- pages are **not loaded** for this purpose.\"\nmsgstr \"実装の詳細 - この目的でページは **読み込まれません** 。\"\n\n#: ../../document.rst:472 946caeaeaaec48838a6a321dc1963727\nmsgid \"the label to look for, e.g. \\\"vii\\\" (Roman number 7).\"\nmsgstr \"検索対象のラベル、例： \\\"vii\\\"（ローマ数字 7）。\"\n\n#: ../../document.rst:473 76acb3f67de149159a5b95ff30cb08b6\nmsgid \"\"\n\"stop after first hit. Useful e.g. if labelling is known to be unique, or \"\n\"there are many pages, etc. The default will check every page number.\"\nmsgstr \"最初の一致で停止します。ラベリングが一意であることがわかっている場合や、多くのページがある場合などに便利です。デフォルトではすべてのページ番号をチェックします。\"\n\n#: ../../document.rst:475 9adccc3fc8054990ad6014e9041d93de\nmsgid \"\"\n\"list of page numbers that have this label. Empty if none found, no labels\"\n\" defined, etc.\"\nmsgstr \"このラベルを持つページ番号のリスト。見つからない場合やラベルが定義されていない場合などは空です。\"\n\n#: ../../document.rst:480 ../../document.rst:843 ../../document.rst:864\n#: ../../document.rst:1897 ../../document.rst:1921\n#: 05910086455448f18e257168cd8e2a36 14ada1583e2942948f2bb1e6134d7866\n#: 3450b554a2e0411eacdd819c036cccc2 80adb24663644aa28fa9a11528256936\n#: 92afdec41f4a4a328c24a25cbcd0b7a6\nmsgid \"New in v1.18.7\"\nmsgstr \"バージョン 1.18.7 での新機能\"\n\n#: ../../document.rst:482 743daa378cfe4792ad9fa83a2909eb8d\nmsgid \"\"\n\"PDF only: Extract the list of page label definitions. Typically used for \"\n\"modifications before feeding it into :meth:`Document.set_page_labels`.\"\nmsgstr \"\"\n\"PDF のみ：ページラベルの定義のリストを抽出します。通常は :meth:`Document.set_page_labels` \"\n\"に渡す前の変更に使用されます。\"\n\n#: ../../document.rst:484 0f5d97b8193a461b8fe7e04b712adae9\nmsgid \"a list of dictionaries as defined in :meth:`Document.set_page_labels`.\"\nmsgstr \":meth:`Document.set_page_labels` で定義されたように辞書のリスト。\"\n\n#: ../../document.rst:488 244cbe336b1e4cddb8491c05e5ec5b15\nmsgid \"New in v1.18.6\"\nmsgstr \"バージョン 1.18.6 での新機能\"\n\n#: ../../document.rst:490 470a1bc4f0404283b7358f77bc840a9d\nmsgid \"PDF only: Add or update the page label definitions of the PDF.\"\nmsgstr \"PDF のみ：PDF のページラベルの定義を追加または更新します。\"\n\n#: ../../document.rst:492 d0c5ec05dc0f4ba5a381635a4cf3c93b\nmsgid \"\"\n\"a list of dictionaries. Each dictionary defines a label building rule and\"\n\" a 0-based \\\"start\\\" page number. That start page is the first for which \"\n\"the label definition is valid. Each dictionary has up to 4 items and \"\n\"looks like `{'startpage': int, 'prefix': str, 'style': str, \"\n\"'firstpagenum': int}` and has the following items.  - `startpage`: (int) \"\n\"the first page number (0-based) to apply the label rule. This key **must \"\n\"be present**. The rule is applied to all subsequent pages until either \"\n\"end of document or superseded by the rule with the next larger page \"\n\"number. - `prefix`: (str) an arbitrary string to start the label with, \"\n\"e.g. \\\"A-\\\". Default is \\\"\\\". - `style`: (str) the numbering style. \"\n\"Available are \\\"D\\\" (decimal), \\\"r\\\"/\\\"R\\\" (Roman numbers, lower / upper \"\n\"case), and \\\"a\\\"/\\\"A\\\" (lower / upper case alphabetical numbering: \\\"a\\\" \"\n\"through \\\"z\\\", then \\\"aa\\\" through \\\"zz\\\", etc.). Default is \\\"\\\". If \"\n\"\\\"\\\", no numbering will take place and the pages in that range will \"\n\"receive the same label consisting of the `prefix` value. If prefix is \"\n\"also omitted, then the label will be \\\"\\\". - `firstpagenum`: (int) start \"\n\"numbering with this value. Default is 1, smaller values are ignored.\"\nmsgstr \"\"\n\n#: ../../document.rst:492 0fab77fbe73e4149aa809d1d7d83d4ce\nmsgid \"\"\n\"a list of dictionaries. Each dictionary defines a label building rule and\"\n\" a 0-based \\\"start\\\" page number. That start page is the first for which \"\n\"the label definition is valid. Each dictionary has up to 4 items and \"\n\"looks like `{'startpage': int, 'prefix': str, 'style': str, \"\n\"'firstpagenum': int}` and has the following items.\"\nmsgstr \"\"\n\"辞書のリスト。各辞書はラベル構築ルールと 0 ベースの \\\"start\\\" \"\n\"ページ番号を定義します。その開始ページはラベル定義が有効になる最初のページです。各辞書は最大 4 つの項目を持ち、 `{'startpage': \"\n\"int, 'prefix': str, 'style': str, 'firstpagenum': int}` という形式で、次の項目を持ちます。\"\n\n#: ../../document.rst:494 7eeface47e22458b9ccd093d60a289a2\nmsgid \"\"\n\"`startpage`: (int) the first page number (0-based) to apply the label \"\n\"rule. This key **must be present**. The rule is applied to all subsequent\"\n\" pages until either end of document or superseded by the rule with the \"\n\"next larger page number.\"\nmsgstr \"\"\n\"`startpage` :（int）ラベルルールを適用する最初のページ番号（0 ベース）。このキーは **存在する必要があります** \"\n\"。ルールはドキュメントの終端に達するか、次の大きなページ番号を持つルールに置き換えられるまで、すべての後続ページに適用されます。\"\n\n#: ../../document.rst:495 74fd610222f54117be5ff8aa62d5e852\nmsgid \"\"\n\"`prefix`: (str) an arbitrary string to start the label with, e.g. \\\"A-\\\".\"\n\" Default is \\\"\\\".\"\nmsgstr \"`prefix` :（str）ラベルの先頭に付ける任意の文字列、例： \\\"A-\\\"。デフォルトは \\\"\\\" です。\"\n\n#: ../../document.rst:496 27261aba29414162837b13ebf37bfbb9\nmsgid \"\"\n\"`style`: (str) the numbering style. Available are \\\"D\\\" (decimal), \"\n\"\\\"r\\\"/\\\"R\\\" (Roman numbers, lower / upper case), and \\\"a\\\"/\\\"A\\\" (lower /\"\n\" upper case alphabetical numbering: \\\"a\\\" through \\\"z\\\", then \\\"aa\\\" \"\n\"through \\\"zz\\\", etc.). Default is \\\"\\\". If \\\"\\\", no numbering will take \"\n\"place and the pages in that range will receive the same label consisting \"\n\"of the `prefix` value. If prefix is also omitted, then the label will be \"\n\"\\\"\\\".\"\nmsgstr \"\"\n\"style:（str）番号付けのスタイル。使用できるのは \\\"D\\\"（10 進数）、\\\"r\\\"/\\\"R\\\"（ローマ数字、小文字/大文字）、および \"\n\"\\\"a\\\"/\\\"A\\\"（小文字/大文字のアルファベット番号： \\\"a\\\" から \\\"z\\\"、次に \\\"aa\\\" から \\\"zz\\\" \"\n\"など）。デフォルトは \\\"\\\" です。 \\\"\\\" \"\n\"の場合、番号付けは行われず、その範囲のページはプレフィックス値から成る同じラベルを受け取ります。`prefix` も省略された場合、ラベルは \"\n\"\\\"\\\" になります。\"\n\n#: ../../document.rst:497 3ceaa9f717194b72bdd2f7f205217200\nmsgid \"\"\n\"`firstpagenum`: (int) start numbering with this value. Default is 1, \"\n\"smaller values are ignored.\"\nmsgstr \"`firstpagenum` :（int）この値から番号付けを開始します。デフォルトは 1 で、小さい値は無視されます。\"\n\n#: ../../document.rst:499 2afd6593eaf0423e8afcd6635c826754\nmsgid \"For example::\"\nmsgstr \"例::\"\n\n#: ../../document.rst:504 040ded0fb2be4e5cbeadc76208560d19\nmsgid \"\"\n\"will generate the labels \\\"A-10\\\", \\\"A-11\\\", \\\"A-12\\\", \\\"A-13\\\", \\\"1\\\", \"\n\"\\\"2\\\", \\\"3\\\", ... for pages 6, 7 and so on until end of document. Pages 0\"\n\" through 5 will have the label \\\"\\\".\"\nmsgstr \"\"\n\"次のラベルを生成します: \\\"A-10\\\"、\\\"A-11\\\"、\\\"A-12\\\"、\\\"A-13\\\"、\\\"1\\\"、\\\"2\\\"、\\\"3\\\"、... \"\n\"ページ 6、7、など、ドキュメントの終了まで続きます。ページ 0 から 5 まではラベル \\\"A-\\\" が付きます。\"\n\n#: ../../document.rst:509 ../../document.rst:523\n#: 0aa8b9c83c1b41719f9cbd43feabcdf8 846b39d637a5466f8c256fcfce4f4571\nmsgid \"New in v.1.17.3\"\nmsgstr \"バージョン 1.17.3 での新機能\"\n\n#: ../../document.rst:511 12e98a99804a4723ac02582721c5a896\nmsgid \"\"\n\"Return a page pointer in a reflowable document. After re-layouting the \"\n\"document, the result of this method can be used to find the new location \"\n\"of the page.\"\nmsgstr \"リフロータブルなドキュメント内のページポインターを返します。ドキュメントの再レイアウト後、このメソッドの結果はページの新しい位置を見つけるために使用できます。\"\n\n#: ../../document.rst:513 c31102cafa52492ca638735d028e8d7f\nmsgid \"Do not confuse with items of a table of contents, TOC.\"\nmsgstr \"目次の項目とは混同しないでください。\"\n\n#: ../../document.rst:515 9ffd70204ee543ffa134b90dad39f75a\nmsgid \"page location. Must be a valid *(chapter, pno)*.\"\nmsgstr \"ページの位置。有効なものである必要があります *（章、ページ番号）* 。\"\n\n#: ../../document.rst:518 c028fcff4f6a4c409c5bd4f2c7094af3\nmsgid \"\"\n\"a long integer in pointer format. To be used for finding the new location\"\n\" of the page after re-layouting the document. Do not touch or re-assign.\"\nmsgstr \"ポインターフォーマットの長整数。ドキュメントの再レイアウト後のページの新しい位置を見つけるために使用されます。変更しないでください。\"\n\n#: ../../document.rst:525 aae59f9b08ae4ed7b02b7f7a2dd7a991\nmsgid \"Return the new page location after re-layouting the document.\"\nmsgstr \"ドキュメントの再レイアウト後の新しいページの位置を返します。\"\n\n#: ../../document.rst:527 a8da17fc210f4a43a9d2b4ceb3185c5f\nmsgid \"created by :meth:`Document.make_bookmark`.\"\nmsgstr \":meth:`Document.make_bookmark` によって作成されたもの。\"\n\n#: ../../document.rst:530 1d07a10894004002a21058fdfeac44af\nmsgid \"the new (chapter, pno) of the page.\"\nmsgstr \"ページの新しい（章、ページ番号）。\"\n\n#: ../../document.rst:535 ../../document.rst:547 ../../document.rst:558\n#: 61c1413e338345c9ab33c2b1c5f9decc 6a5cad42e88f4f499c7181e080b1f971\n#: 946e1b36b28b4432a39b16f8c68d62e0\nmsgid \"New in v.1.17.0\"\nmsgstr \"バージョン 1.17.0 での新機能\"\n\n#: ../../document.rst:537 c8b174e76e7b434db43abd0893095ba8\nmsgid \"Return the number of pages of a chapter.\"\nmsgstr \"章のページ数を返します。\"\n\n#: ../../document.rst:539 967dfc416734482196f7a8ffa7d45bd4\nmsgid \"the 0-based chapter number.\"\nmsgstr \"0 ベースの章番号。\"\n\n#: ../../document.rst:542 2a83ec2d4ea54b1897eeb50f82566adc\nmsgid \"\"\n\"number of pages in chapter. Relevant only for document types with chapter\"\n\" support (EPUB currently).\"\nmsgstr \"章内のページ数。章のサポートを持つドキュメントタイプに関連します（現在は EPUB のみ）。\"\n\n#: ../../document.rst:549 162f24578e6749c8ada15b85d4be6bea\nmsgid \"Return the location of the following page.\"\nmsgstr \"次のページの位置を返します。\"\n\n#: ../../document.rst:551 ../../document.rst:562\n#: 76dcbeac58be4a63aa5feb22ccbcc31e b635038017484753aa510b172311664a\nmsgid \"\"\n\"the current page id. This must be a tuple *(chapter, pno)* identifying an\"\n\" existing page.\"\nmsgstr \"現在のページ ID。これは既存のページを識別するタプル *（章、ページ番号）* である必要があります。\"\n\n#: ../../document.rst:553 077a38466aeb4464b21c75847fc03419\nmsgid \"\"\n\"The tuple of the following page, i.e. either *(chapter, pno + 1)* or \"\n\"*(chapter + 1, 0)*, **or** the empty tuple *()* if the argument was the \"\n\"last page. Relevant only for document types with chapter support (EPUB \"\n\"currently).\"\nmsgstr \"\"\n\"次のページのタプル、つまり *（章、ページ番号 + 1）* または *（章 + 1、0）* 、**または** \"\n\"引数が最後のページである場合は空のタプル *()* 。章のサポートを持つドキュメントタイプに関連します（現在は EPUB のみ）。\"\n\n#: ../../document.rst:560 540ac91bacd24f2184f90373daac0a7e\nmsgid \"Return the locator of the preceding page.\"\nmsgstr \"前のページの位置を返します。\"\n\n#: ../../document.rst:564 bec578e6b61c4cc9b0f254bbcb0f48b7\nmsgid \"\"\n\"The tuple of the preceding page, i.e. either *(chapter, pno - 1)* or the \"\n\"last page of the preceding chapter, **or** the empty tuple *()* if the \"\n\"argument was the first page. Relevant only for document types with \"\n\"chapter support (EPUB currently).\"\nmsgstr \"\"\n\"前のページのタプル、つまり *（章、ページ番号 - 1）* **または** 前の章の最後のページ、または引数が最初のページである場合は空のタプル \"\n\"*()* 。章のサポートを持つドキュメントタイプに関連します（現在は EPUB のみ）。\"\n\n#: ../../document.rst:569 68dfefa5502f425289fc497e0d9c6238\nmsgid \"\"\n\"Changed in v1.17.0: For document types supporting a so-called \\\"chapter \"\n\"structure\\\" (like EPUB), pages can also be loaded via the combination of \"\n\"chapter number and relative page number, instead of the absolute page \"\n\"number. This should **significantly speed up access** for large \"\n\"documents.\"\nmsgstr \"\"\n\"バージョン 1.17.0 で変更: \\\"章の構造\\\" \"\n\"をサポートするドキュメントタイプ（例：EPUB）の場合、絶対ページ番号の代わりに章番号と相対ページ番号の組み合わせを使用してページをロードすることもできます。これにより、大きなドキュメントへの\"\n\" **アクセスが大幅に高速化される** はずです。\"\n\n#: ../../document.rst:571 e7a2e814cced49258d2f9b21245d2ce6\nmsgid \"\"\n\"Create a :ref:`Page` object for further processing (like rendering, text \"\n\"searching, etc.).\"\nmsgstr \"さらなる処理（レンダリング、テキスト検索など）のための :ref:`Page` オブジェクトを作成します。\"\n\n#: ../../document.rst:573 ac4b297778cb465a83c732f4f6565380\nmsgid \"\"\n\"*(Changed in v1.17.0)*  Either a 0-based page number, or a tuple \"\n\"*(chapter, pno)*. For an **integer**, any `-∞ < page_id < page_count` is \"\n\"acceptable. While page_id is negative, :attr:`page_count` will be added \"\n\"to it. For example: to load the last page, you can use \"\n\"*doc.load_page(-1)*. After this you have page.number = doc.page_count - \"\n\"1.  For a tuple, *chapter* must be in range \"\n\":attr:`Document.chapter_count`, and *pno* must be in range \"\n\":meth:`Document.chapter_page_count` of that chapter. Both values are \"\n\"0-based. Using this notation, :attr:`Page.number` will equal the given \"\n\"tuple. Relevant only for document types with chapter support (EPUB \"\n\"currently).\"\nmsgstr \"\"\n\n#: ../../document.rst:573 b9bae2aee5bb433692e4d9ced23afc6b\nmsgid \"*(Changed in v1.17.0)*\"\nmsgstr \"*（バージョン 1.17.0 で変更）*\"\n\n#: ../../document.rst:575 17221ad920ec4edda2e3f56e1ee986a5\nmsgid \"\"\n\"Either a 0-based page number, or a tuple *(chapter, pno)*. For an \"\n\"**integer**, any `-∞ < page_id < page_count` is acceptable. While page_id\"\n\" is negative, :attr:`page_count` will be added to it. For example: to \"\n\"load the last page, you can use *doc.load_page(-1)*. After this you have \"\n\"page.number = doc.page_count - 1.\"\nmsgstr \"\"\n\"0ベースのページ番号またはタプル *（章、ページ番号）* のいずれか。**整数** の場合、`-∞ < page_id < page_count`\"\n\" が許容されます。`page_id` が負の場合、 :attr:`page_count` \"\n\"が追加されます。たとえば、最後のページを読み込むには、*doc.load_page(-1)* を使用できます。これにより、 \"\n\"`page.number = doc.page_count - 1` となります。\"\n\n#: ../../document.rst:577 039ea62786ac4483a2ff851942f8e61e\nmsgid \"\"\n\"For a tuple, *chapter* must be in range :attr:`Document.chapter_count`, \"\n\"and *pno* must be in range :meth:`Document.chapter_page_count` of that \"\n\"chapter. Both values are 0-based. Using this notation, \"\n\":attr:`Page.number` will equal the given tuple. Relevant only for \"\n\"document types with chapter support (EPUB currently).\"\nmsgstr \"\"\n\"タプルの場合、*chapter* は :attr:`Document.chapter_count` の範囲内になければならず、*ページ番号* \"\n\"はその章の :meth:`Document.chapter_page_count` \"\n\"の範囲内になければなりません。両方の値は0から始まります。この表記法を使用すると、:attr:`Page.number` \"\n\"は指定されたタプルに等しくなります。章のサポートを持つドキュメントタイプに関連します（現在は EPUB のみ）。\"\n\n#: ../../document.rst:579 ../../document.rst:683 ../../document.rst:1452\n#: 0006a5a1428c489b85ee1ef72f368b66 1abd4533c839432f8b762c82cf15dc63\n#: 78a10b5d4c74403ab6e8fb90b05f6cc0\nmsgid \":ref:`Page`\"\nmsgstr \"\"\n\n#: ../../document.rst:583 d4516954d08e43daae3d737a83243151\nmsgid \"\"\n\"Documents also follow the Python sequence protocol with page numbers as \"\n\"indices: *doc.load_page(n) == doc[n]*.\"\nmsgstr \"\"\n\"ドキュメントはページ番号をインデックスとするPythonのシーケンスプロトコルに従います：indices: *doc.load_page(n) \"\n\"== doc[n]* 。\"\n\n#: ../../document.rst:585 caf16253efc94349815ad78668652297\nmsgid \"\"\n\"For **absolute page numbers** only, expressions like *\\\"for page in doc: \"\n\"...\\\"* and *\\\"for page in reversed(doc): ...\\\"* will successively yield \"\n\"the document's pages. Refer to :meth:`Document.pages` which allows \"\n\"processing pages as with slicing.\"\nmsgstr \"\"\n\"**絶対ページ番号** の場合、式  *\\\"for page in doc: …\\\"* および  *\\\"for page in \"\n\"reversed(doc): …\\\"*  は文書のページを順次生成します。スライシングのようにページを処理できる \"\n\":meth:`Document.pages` を参照してください。\"\n\n#: ../../document.rst:587 4eec9f75b1a648e5954520327f163582\nmsgid \"\"\n\"You can also use index notation with the new chapter-based page \"\n\"identification: use *page = doc[(5, 2)]* to load the third page of the \"\n\"sixth chapter.\"\nmsgstr \"\"\n\"新しい章ベースのページ識別にもインデックス表記を使用できます： *page = doc[(5, 2)]* として、 \"\n\"6番目の章の3番目のページを読み込むことができます。\"\n\n#: ../../document.rst:589 d88b05b23ebe48cdbc81a8716291829e\nmsgid \"\"\n\"To maintain a consistent API, for document types not supporting a chapter\"\n\" structure (like PDFs), :attr:`Document.chapter_count` is 1, and pages \"\n\"can also be loaded via tuples *(0, pno)*. See this [#f3]_ footnote for \"\n\"comments on performance improvements.\"\nmsgstr \"\"\n\"一貫性のあるAPIを維持するため、章の構造をサポートしていないドキュメントタイプ（PDFなど）の場合、:attr:`Document.chapter_count`\"\n\" は1であり、ページはタプル *（0、pno）* を使用しても読み込むことができます。パフォーマンスの改善に関するコメントについては、この \"\n\"[#f3]_ の注釈を参照してください。\"\n\n#: ../../document.rst:594 5877b0a8ee034827a6486e55a27c1721\nmsgid \"\"\n\"PDF only: Walk through all images and rewrite them according to the \"\n\"specified parameters. This is useful for reducing file size, changing \"\n\"image formats, or converting color spaces.\"\nmsgstr \"\"\n\n#: ../../document.rst:596 1894640743d14d81939992952b89a89f\nmsgid \"\"\n\"The typical usage is extra compression of images for significantly \"\n\"reducing the file size of the PDF. When setting quality and the dpi \"\n\"parameters to positive values and accepting defaults for the rest, the \"\n\"following will happen:\"\nmsgstr \"\"\n\n#: ../../document.rst:598 3a74a4a4263048e1bfc0579a97bb35b8\nmsgid \"\"\n\"Lossy and lossless images will be rewritten as JPEG images \"\n\"(FZ_RECOMPRESS_JPEG) as far as technically possible.\"\nmsgstr \"\"\n\n#: ../../document.rst:600 01a553ed3bbe401db8ad3152294f8695\nmsgid \"\"\n\"Bitonal (monochrome) images will be rewritten in FAX format \"\n\"(FZ_RECOMPRESS_FAX).\"\nmsgstr \"\"\n\n#: ../../document.rst:602 38e8687fa2994142bc5da75bec6d83e2\nmsgid \"Subsampling method is **FZ_SUBSAMPLE_AVERAGE** (see below).\"\nmsgstr \"\"\n\n#: ../../document.rst:604 79b3413d2429401d99ae3a43030056f6\nmsgid \"\"\n\"target DPI value for the resampled images. Ignored if `dpi_threshold` is \"\n\"`None`, otherwise must be less than `dpi_threshold` and positive.\"\nmsgstr \"\"\n\n#: ../../document.rst:606 41d9689ed361448fbcb5a13023c76806\nmsgid \"\"\n\"If None (the default) no resampling takes place. Otherwise images with a \"\n\"DPI value larger than this will be resampled to `dpi_target` (which must \"\n\"be less than `dpi_threshold`).\"\nmsgstr \"\"\n\n#: ../../document.rst:608 29da9ea4d0af4d69a22f61ffa363e949\nmsgid \"\"\n\"desired target JPEG quality, a value between 0 and 100. 0 means no \"\n\"quality change, 100 means best quality.\"\nmsgstr \"\"\n\n#: ../../document.rst:610 1aa75d1dd8f3426d8dcb2ebb3b2e4c90\nmsgid \"include lossy image types (e.g. JPEG).\"\nmsgstr \"\"\n\n#: ../../document.rst:612 9697131e0d414bb4933c23e702734b4d\nmsgid \"include lossless image types (e.g. PNG).\"\nmsgstr \"\"\n\n#: ../../document.rst:614 0c8117c9cafd459880a5aec4cc9d974d\nmsgid \"include black-and-white images (e.g. FAX).\"\nmsgstr \"\"\n\n#: ../../document.rst:616 21bb122962844205b76401ccbbb01a30\nmsgid \"include colored images.\"\nmsgstr \"\"\n\n#: ../../document.rst:618 2eb49df120b7429296a9281ccd362ad8\nmsgid \"include grayscale images.\"\nmsgstr \"\"\n\n#: ../../document.rst:620 b54e5d5881bd40679b8c78f0b46f72ec\nmsgid \"\"\n\"if True, the PDF will be converted to grayscale by executing \"\n\":meth:`Document.recolor` before all image processing. Please note that \"\n\"this will also change text and vector graphics to grayscale -- not just \"\n\"the images.\"\nmsgstr \"\"\n\n#: ../../document.rst:622 3afbe56d4eae4bf291351d87ea284a07\nmsgid \"\"\n\"This parameter is intended for expert users. Except ``set_to_gray``, all \"\n\"other parameters are ignored. It must be an object prepared in the \"\n\"following way: ``options = pymupdf.mupdf.PdfImageRewriterOptions()``. \"\n\"Then attributes of this object can be set to achieve fine-grained \"\n\"control. Following are the adjustable attributes of the ``options`` \"\n\"object and their default (do nothing) values.\"\nmsgstr \"\"\n\n#: ../../document.rst:652 226b700f0609456da42369d0a574ec09\nmsgid \"\"\n\"The ``*_recompress_method`` attributes may be one of the values \"\n\"**FZ_RECOMPRESS_NEVER (0), FZ_RECOMPRESS_SAME (1), FZ_RECOMPRESS_LOSSLESS\"\n\" (2), FZ_RECOMPRESS_JPEG (3), FZ_RECOMPRESS_J2K (4), FZ_RECOMPRESS_FAX \"\n\"(5)**. Value FZ_RECOMPRESS_NEVER will skip this image type altogether and\"\n\" FZ_RECOMPRESS_SAME will not change the type. The other values will \"\n\"execute type conversions (as far as technically possible).\"\nmsgstr \"\"\n\n#: ../../document.rst:654 28345897c04e47cb8bd7b419a399e52e\nmsgid \"\"\n\"The ``*_quality`` values are strings of integers from \\\"0\\\" to \\\"100\\\" or\"\n\" ``None``.\"\nmsgstr \"\"\n\n#: ../../document.rst:656 431fb82d92d144e39a7eb33de4cee3d5\nmsgid \"\"\n\"The ``*_subsample_method`` attributes are either **FZ_SUBSAMPLE_AVERAGE \"\n\"(0)** or **FZ_SUBSAMPLE_BICUBIC (1)** and refer to how a pixel value is \"\n\"derived from its neighboring pixels during subsampling. For some \"\n\"background see `this Wikipedia article about bicubic interpolation \"\n\"<https://en.wikipedia.org/wiki/Bicubic_interpolation>`_.\"\nmsgstr \"\"\n\n#: ../../document.rst:658 a5582d3eeef04969839b567872912234\nmsgid \"\"\n\"Attributes ``*_subsample_threshold`` excludes images from subsampling \"\n\"which have a lower DPI. Participating images will be subsampled to the \"\n\"DPI values given by the ``*_subsample_to`` values. Values of 0 mean that \"\n\"no subsampling will take place.\"\nmsgstr \"\"\n\n#: ../../document.rst:660 c5e4028872844f00bd7eb9ce4c910e75\nmsgid \"\"\n\"The ``*_subsample_threshold`` values should be chosen notably larger than\"\n\" the ``*_subsample_to`` values to ensure that there are enough size \"\n\"savings. After all, every subsampling inevitably incurs quality losses.\"\nmsgstr \"\"\n\n#: ../../document.rst:662 4021cd52c00c475ca2229590caeff58a\nmsgid \"An example for a good choice is ``threshold=100`` and ``to=72``.\"\nmsgstr \"\"\n\n#: ../../document.rst:667 62fadb98a46e4b6ab9224f097849e731\nmsgid \"\"\n\"PDF only: Change the color component counts for all object types text, \"\n\"images and vector graphics for all pages.\"\nmsgstr \"\"\n\n#: ../../document.rst:669 fac366c35c4f430489dc4d0814e4349d\nmsgid \"\"\n\"desired color space indicated by the number of color components: 1 = \"\n\"DeviceGRAY, 3 = DeviceRGB, 4 = DeviceCMYK.\"\nmsgstr \"\"\n\n#: ../../document.rst:671 baaefdcc658142cfb2d0d72964381651\nmsgid \"\"\n\"The typical use case is 1 (DeviceGRAY) which converts the PDF to \"\n\"grayscale.\"\nmsgstr \"\"\n\n#: ../../document.rst:676 b3feb6280dce4bb68a6d09f67ad179e5\nmsgid \"New in v1.16.10\"\nmsgstr \"バージョン 1.16.10 での新機能\"\n\n#: ../../document.rst:678 e20ca78781fd4ff7a8ed580599a1ec63\nmsgid \"\"\n\"PDF only: Provide a new copy of a page after finishing and updating all \"\n\"pending changes.\"\nmsgstr \"PDF のみ：保留中のすべての変更を終了および更新した後、ページの新しいコピーを提供します。\"\n\n#: ../../document.rst:680 d63490fa56354fc49d5d536ea547ebe1\nmsgid \"page object.\"\nmsgstr \"ページオブジェクト。\"\n\n#: ../../document.rst:685 f33b5c1ccafd4b1c975285d4daf5b37d\nmsgid \"\"\n\"a new copy of the same page. All pending updates (e.g. to annotations or \"\n\"widgets) will be finalized and a fresh copy of the page will be loaded.  \"\n\".. note:: In a typical use case, a page :ref:`Pixmap` should be taken \"\n\"after annotations / widgets have been added or changed. To force all \"\n\"those changes being reflected in the page structure, this method re-\"\n\"instates a fresh copy while keeping the object hierarchy \\\"document -> \"\n\"page -> annotations/widgets\\\" intact.\"\nmsgstr \"\"\n\n#: ../../document.rst:685 5e83a01c5a4f43609931c09d2cd5bf4e\nmsgid \"\"\n\"a new copy of the same page. All pending updates (e.g. to annotations or \"\n\"widgets) will be finalized and a fresh copy of the page will be loaded.\"\nmsgstr \"同じページの新しいコピー。すべての保留中の更新（注釈やウィジェットなど）が確定し、ページの新しいコピーが読み込まれます。\"\n\n#: ../../document.rst:687 aa9f1f86225a4ad39148e534ef4be453\nmsgid \"\"\n\"In a typical use case, a page :ref:`Pixmap` should be taken after \"\n\"annotations / widgets have been added or changed. To force all those \"\n\"changes being reflected in the page structure, this method re-instates a \"\n\"fresh copy while keeping the object hierarchy \\\"document -> page -> \"\n\"annotations/widgets\\\" intact.\"\nmsgstr \"\"\n\"典型的なユースケースでは、注釈やウィジェットが追加または変更された後にページの :ref:`Pixmap` \"\n\"を取得する必要があります。これらの変更がページ構造に反映されるようにするために、このメソッドは \\\"document -> page -> \"\n\"annotations/widgets\\\" のオブジェクト階層を保持したまま、新しいコピーを再設定します。\"\n\n#: ../../document.rst:692 e255e70994eb4eea840af29512883ee8\nmsgid \"PDF only: Convert destination names into a Python dict.\"\nmsgstr \"PDFのみ: ページの目的地名をPythonの辞書に変換します\"\n\n#: ../../document.rst:694 e3317825d1b84d09a0976e4563a7d1e8\nmsgid \"\"\n\"A dictionary with the following layout:  * *key*: (str) the name. * \"\n\"*value*: (dict) with the following layout:     * \\\"page\\\":  target page \"\n\"number (0-based). If no page number found -1.     * \\\"to\\\": (x, y) target\"\n\" point on page. Currently in PDF coordinates,       i.e. point (0,0) is \"\n\"the bottom-left of the page.     * \\\"zoom\\\": (float) the zoom factor.\"\n\"     * \\\"dest\\\": (str) only present if the target location on the page \"\n\"has       not been provided as \\\"/XYZ\\\" or if no page number was found. \"\n\"Examples::      {         '__bookmark_1': {'page': 0, 'to': (0.0, 541.0),\"\n\" 'zoom': 0.0},         '__bookmark_2': {'page': 0, 'to': (0.0, 481.45), \"\n\"'zoom': 0.0},     }  or::      {         \"\n\"'21154a7c20684ceb91f9c9adc3b677c40': {'page': -1, 'dest': '/XYZ 15.75 \"\n\"1486 0'},         ...     }\"\nmsgstr \"\"\n\n#: ../../document.rst:695 d974d89343f748ec8a5cc27429f3e94d\nmsgid \"A dictionary with the following layout:\"\nmsgstr \"以下のキーを持つ辞書:\"\n\n#: ../../document.rst:697 f4ac483d1fc042b18a323b154eb5a4f2\nmsgid \"*key*: (str) the name.\"\nmsgstr \"キー: (str) 名前\"\n\n#: ../../document.rst:703 333b90d0cade45ef8d3c12111bba5ae8\nmsgid \"*value*: (dict) with the following layout:\"\nmsgstr \"以下のキーを持つ辞書:\"\n\n#: ../../document.rst:699 1299456f72ed4127a7574602814bfe6f\nmsgid \"\\\"page\\\":  target page number (0-based). If no page number found -1.\"\nmsgstr \"\\\"page\\\": 対象のページ番号（0から始まる）。ページ番号が見つからない場合は-1。\"\n\n#: ../../document.rst:700 7e4c618113094b25b9edc3ad8396e7bf\nmsgid \"\"\n\"\\\"to\\\": (x, y) target point on page. Currently in PDF coordinates, i.e. \"\n\"point (0,0) is the bottom-left of the page.\"\nmsgstr \"\\\"to\\\": (x, y) ページ上のターゲットポイント。現在はPDF座標であり、つまり点(0,0)がページの左下になります。\"\n\n#: ../../document.rst:702 cfa4c5d417154aa5a6c373ee783adb27\nmsgid \"\\\"zoom\\\": (float) the zoom factor.\"\nmsgstr \"\\\"zoom\\\": ターゲットページ上のズームファクター（float）。\"\n\n#: ../../document.rst:703 37cf95d00aae40aaba647f6bc7c9e566\nmsgid \"\"\n\"\\\"dest\\\": (str) only present if the target location on the page has not \"\n\"been provided as \\\"/XYZ\\\" or if no page number was found.\"\nmsgstr \"\\\"dest\\\": (str) \\\"/XYZ\\\" としてターゲット位置が指定されていない場合や、ページ番号が見つからない場合にのみ存在します。\"\n\n#: ../../document.rst:705 4171adc015d64c7c9d92bebe575448f8\nmsgid \"Examples::\"\nmsgstr \"例::\"\n\n#: ../../document.rst:712 d7fb5dcb203748afb273aac0c2a9a100\nmsgid \"or::\"\nmsgstr \"または:\"\n\n#: ../../document.rst:719 a874c7048ebb4429a74d36e9cd9d1ca5\nmsgid \"\"\n\"All names found in the catalog under keys \\\"/Dests\\\" and \\\"/Names/Dests\\\"\"\n\" are included.\"\nmsgstr \"キー \\\"/Dests\\\" および \\\"/Names/Dests\\\" の下でカタログ内に見つかるすべての名前が含まれます。\"\n\n#: ../../document.rst:722 51b104ce68654b67ab928f76dddb73f1\nmsgid \"New in v1.23.6\"\nmsgstr \"v1.23.6で新登場\"\n\n#: ../../document.rst:727 ../../document.rst:737 ../../document.rst:1166\n#: ../../document.rst:1176 ../../document.rst:1188\n#: 00ae9907f6a54b55baab674cf76aed28 2415dd9f180a4b7382a3d9297719fed0\n#: 27ca4d25a0534901a9ec78d94dced53f a3a52436d0f141078ff75591bac0f5bf\n#: d5f1f55ab01a49bca5f15494ce1880e5\nmsgid \"New in v1.17.7\"\nmsgstr \"バージョン 1.17.7 での新機能\"\n\n#: ../../document.rst:729 abe5b967ce1c41568bb16dd577d6a71e\nmsgid \"\"\n\"PDF only: Return the unrotated page rectangle -- **without loading the \"\n\"page** (via :meth:`Document.load_page`). This is meant for internal \"\n\"purpose requiring best possible performance.\"\nmsgstr \"\"\n\"PDF のみ：ページを読み込まずに（:meth:`Document.load_page` \"\n\"を介さずに）、回転を無視してページの長方形を返します。これは、最高のパフォーマンスを必要とする内部目的のために使用されます。\"\n\n#: ../../document.rst:731 ../../document.rst:741\n#: 87245fe71e5749bbb5fdd8323971d38a 9aa5f7f4352646a6874011b4413b9eb2\nmsgid \"0-based page number.\"\nmsgstr \"0から始まるページ番号。\"\n\n#: ../../document.rst:733 8ae5e02a100d4c57be33964251202070\nmsgid \":ref:`Rect` of the page like :meth:`Page.rect`, but ignoring any rotation.\"\nmsgstr \":meth:`Page.rect` のようなページの :ref:`Rect` ですが、回転を無視します。\"\n\n#: ../../document.rst:739 afe91f4bac4e4f20b4d11da8c7b6a121\nmsgid \"\"\n\"PDF only: Return the :data:`xref` of the page -- **without loading the \"\n\"page** (via :meth:`Document.load_page`). This is meant for internal \"\n\"purpose requiring best possible performance.\"\nmsgstr \"\"\n\"PDF のみ： **ページを読み込まずに** （:meth:`Document.load_page` を介さずに）、ページの \"\n\":data:`xref` を返します。これは、最高のパフォーマンスを必要とする内部目的のために使用されます。\"\n\n#: ../../document.rst:743 e13e841034c54a368597cae910b0bd41\nmsgid \":data:`xref` of the page like :attr:`Page.xref`.\"\nmsgstr \":attr:`Page.xref` のようなページの :data:`xref` 。\"\n\n#: ../../document.rst:747 9212f6c6b841428ea6bd7592d5586fb1\nmsgid \"New in v1.16.4\"\nmsgstr \"バージョン 1.16.4 での新機能\"\n\n#: ../../document.rst:749 17449b4eba2f4041965b2d8d7fb19b83\nmsgid \"\"\n\"A generator for a range of pages. Parameters have the same meaning as in \"\n\"the built-in function *range()*. Intended for expressions of the form \"\n\"*\\\"for page in doc.pages(start, stop, step): ...\\\"*.\"\nmsgstr \"\"\n\"一連のページのためのジェネレーター。パラメーターの意味は組み込みの *range()* 関数と同じです。 *\\\"for page in \"\n\"doc.pages(start, stop, step): …\\\"* の形式の式に使用することを意図しています。\"\n\n#: ../../document.rst:751 775c0864ae46420c9c3f515b377a7e2e\nmsgid \"\"\n\"start iteration with this page number. Default is zero, allowed values \"\n\"are `-∞ < start < page_count`. While this is negative, :attr:`page_count`\"\n\" is added **before** starting the iteration.\"\nmsgstr \"\"\n\"このページ番号から反復を開始します。デフォルトはゼロで、許容値は `-∞ < start < page_count` \"\n\"です。負の値の間は反復を開始する **前に** :attr:`page_count` が追加されます。\"\n\n#: ../../document.rst:752 99edc914fc1f455b97fabaf836e1ebbf\nmsgid \"\"\n\"stop iteration at this page number. Default is :attr:`page_count`, \"\n\"possible are `-∞ < stop <= page_count`. Larger values are **silently \"\n\"replaced** by the default. Negative values will cyclically emit the pages\"\n\" in reversed order. As with the built-in *range()*, this is the first \"\n\"page **not** returned.\"\nmsgstr \"\"\n\"このページ番号で反復を停止します。デフォルトは :attr:`page_count` で、可能な値は `-∞ < stop <= \"\n\"page_count` です。大きな値はデフォルトで **静かに置き換えられます** 。負の値は逆順でページを循環的に生成します。組み込みの \"\n\"*range()* 関数と同様に、これは **返されない** 最初のページです。\"\n\n#: ../../document.rst:753 94a16241b73e479a8fb39b6e7ecdf23b\nmsgid \"\"\n\"stepping value. Defaults are 1 if start < stop and -1 if start > stop. \"\n\"Zero is not allowed.\"\nmsgstr \"ステップ値。start < stop の場合はデフォルトで1、start > stop の場合は-1です。ゼロは許可されていません。\"\n\n#: ../../document.rst:755 a7bd93c5ab5640fd8a828ca438a31865\nmsgid \"\"\n\"a generator iterator over the document's pages. Some examples:  * \"\n\"\\\"doc.pages()\\\" emits all pages. * \\\"doc.pages(4, 9, 2)\\\" emits pages 4, \"\n\"6, 8. * \\\"doc.pages(0, None, 2)\\\" emits all pages with even numbers. * \"\n\"\\\"doc.pages(-2)\\\" emits the last two pages. * \\\"doc.pages(-1, -1)\\\" emits\"\n\" all pages in reversed order. * \\\"doc.pages(-1, -10)\\\" always emits 10 \"\n\"pages in reversed order, starting with the last page -- **repeatedly** if\"\n\" the document has less than 10 pages. So for a 4-page document the \"\n\"following page numbers are emitted: 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, \"\n\"3.\"\nmsgstr \"\"\n\n#: ../../document.rst:755 cc92b04eb37d4654ac39f335cb55af6e\nmsgid \"a generator iterator over the document's pages. Some examples:\"\nmsgstr \"ドキュメントのページに対するジェネレーターイテレーターです。いくつかの例:\"\n\n#: ../../document.rst:757 2aee4283e6af403382105fb2889ef17e\nmsgid \"\\\"doc.pages()\\\" emits all pages.\"\nmsgstr \"\\\"doc.pages()\\\" はすべてのページを生成します。\"\n\n#: ../../document.rst:758 56483ad2fcb04e8ab0aec6fd11cb6e1f\nmsgid \"\\\"doc.pages(4, 9, 2)\\\" emits pages 4, 6, 8.\"\nmsgstr \"\\\"doc.pages(4, 9, 2)\\\" はページ4、6、8を生成します。\"\n\n#: ../../document.rst:759 5cd6a791eadb403db8d65526627bdb2d\nmsgid \"\\\"doc.pages(0, None, 2)\\\" emits all pages with even numbers.\"\nmsgstr \"\\\"doc.pages(0, None, 2)\\\" はすべての偶数ページを生成します。\"\n\n#: ../../document.rst:760 20d5d59f55454cbf886fcc21995dad97\nmsgid \"\\\"doc.pages(-2)\\\" emits the last two pages.\"\nmsgstr \"\\\"doc.pages(-2)\\\" は最後の2ページを生成します。\"\n\n#: ../../document.rst:761 591d03692b724c96b7a6d853e1e12b95\nmsgid \"\\\"doc.pages(-1, -1)\\\" emits all pages in reversed order.\"\nmsgstr \"\\\"doc.pages(-1, -1)\\\" は逆の順序ですべてのページを生成します。\"\n\n#: ../../document.rst:762 630fb05a54d244e7b9f565ba6c0792b3\nmsgid \"\"\n\"\\\"doc.pages(-1, -10)\\\" always emits 10 pages in reversed order, starting \"\n\"with the last page -- **repeatedly** if the document has less than 10 \"\n\"pages. So for a 4-page document the following page numbers are emitted: \"\n\"3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3.\"\nmsgstr \"\"\n\"\\\"doc.pages(-1, -10)\\\" は常に逆の順序で10ページを生成し、最後のページから始まり、ドキュメントが10ページ未満の場合は \"\n\"**繰り返し** 生成します。したがって、4ページのドキュメントの場合、次のページ番号が生成されます: \"\n\"3、2、1、0、3、2、1、0、3、2、1、0、3。\"\n\n#: ../../document.rst:771 0fa355e484264f9abb37a38413d80d59\nmsgid \"\"\n\"Create a PDF version of the current document and write it to memory. \"\n\"**All document types** are supported. The parameters have the same \"\n\"meaning as in :meth:`insert_pdf`. In essence, you can restrict the \"\n\"conversion to a page subset, specify page rotation, and revert page \"\n\"sequence.\"\nmsgstr \"\"\n\"現在のドキュメントのPDFバージョンを作成し、メモリに書き込みます。**すべてのドキュメントタイプ** がサポートされています。パラメータは \"\n\":meth:`insert_pdf` と同じ意味を持ちます。 \"\n\"基本的に、ページのサブセットに変換を制限し、ページの回転を指定し、ページの順序を逆にすることができます。\"\n\n#: ../../document.rst:773 f660af86d92b44218c359971345422f9\nmsgid \"first page to copy (0-based). Default is first page.\"\nmsgstr \"コピーする最初のページ（0ベース）。デフォルトは最初のページです。\"\n\n#: ../../document.rst:775 3d05e54e25ec4883ba7e2f21584ced49\nmsgid \"last page to copy (0-based). Default is last page.\"\nmsgstr \"コピーする最後のページ（0ベース）。デフォルトは最後のページです。\"\n\n#: ../../document.rst:777 e908fe6a3ae046c19144a9205411192b\nmsgid \"\"\n\"rotation angle. Default is 0 (no rotation). Should be *n * 90* with an \"\n\"integer n (not checked).\"\nmsgstr \"回転角度。デフォルトは0度（回転なし）です。整数n（チェックされていない）で *n * 90* である必要があります。\"\n\n#: ../../document.rst:780 85de97fa9e5449bc9293fe03eef6116f\nmsgid \"\"\n\"a Python *bytes* object containing a PDF file image. It is created by \"\n\"internally using `tobytes(garbage=4, deflate=True)`. See :meth:`tobytes`.\"\n\" You can output it directly to disk or open it as a PDF. Here are some \"\n\"examples::  >>> # convert an XPS file to PDF >>> xps = \"\n\"pymupdf.open(\\\"some.xps\\\") >>> pdfbytes = xps.convert_to_pdf() >>> >>> # \"\n\"either do this --> >>> pdf = pymupdf.open(\\\"pdf\\\", pdfbytes) >>> \"\n\"pdf.save(\\\"some.pdf\\\") >>> >>> # or this --> >>> pdfout = \"\n\"open(\\\"some.pdf\\\", \\\"wb\\\") >>> pdfout.tobytes(pdfbytes) >>> \"\n\"pdfout.close()  >>> # copy image files to PDF pages >>> # each page will \"\n\"have image dimensions >>> doc = pymupdf.open()                     # new \"\n\"PDF >>> imglist = [ ... image file names ...] # e.g. a directory listing \"\n\">>> for img in imglist:         imgdoc=pymupdf.open(img)           # open\"\n\" image as a document         pdfbytes=imgdoc.convert_to_pdf()  # make a \"\n\"1-page PDF of it         imgpdf=pymupdf.open(\\\"pdf\\\", pdfbytes)         \"\n\"doc.insert_pdf(imgpdf)             # insert the image PDF >>> \"\n\"doc.save(\\\"allmyimages.pdf\\\")\"\nmsgstr \"\"\n\n#: ../../document.rst:780 20b5ab52b58544c4999de0b6274f05b2\nmsgid \"\"\n\"a Python *bytes* object containing a PDF file image. It is created by \"\n\"internally using `tobytes(garbage=4, deflate=True)`. See :meth:`tobytes`.\"\n\" You can output it directly to disk or open it as a PDF. Here are some \"\n\"examples::\"\nmsgstr \"\"\n\"PDFファイルイメージを含むPythonの *bytes* オブジェクト。内部的に `tobytes(garbage=4, \"\n\"deflate=True)` を使用して作成されます。:meth:`tobytes` \"\n\"を参照してください。これを直接ディスクに出力するか、PDFとして開くことができます。以下にいくつかの例を示します::\"\n\n#: ../../document.rst:806 d8485f88d433407bb0cd60e194f20727\nmsgid \"\"\n\"The method uses the same logic as the *mutool convert* CLI. This works \"\n\"very well in most cases -- however, beware of the following limitations.\"\nmsgstr \"\"\n\"このメソッドは、*mutool convert* \"\n\"CLIと同じロジックを使用しています。これはほとんどの場合非常にうまく機能しますが、以下の制限に注意してください。\"\n\n#: ../../document.rst:808 357cacd34cd642f39b1da1f75056dc90\nmsgid \"\"\n\"Image files: perfect, no issues detected. However, image transparency is \"\n\"ignored. If you need that (like for a watermark), use \"\n\":meth:`Page.insert_image` instead. Otherwise, this method is recommended \"\n\"for its much better performance.\"\nmsgstr \"\"\n\"画像ファイル: 完璧で、問題は検出されません。ただし、画像の透明度は無視されます。透明度が必要な場合（ウォーターマークなど）、代わりに \"\n\":meth:`Page.insert_image` \"\n\"を使用してください。それ以外の場合、このメソッドははるかに優れたパフォーマンスのために推奨されます。\"\n\n#: ../../document.rst:809 06b36e92e8d645b7bc68371b93dbc572\nmsgid \"\"\n\"XPS: appearance very good. Links work fine, outlines (bookmarks) are \"\n\"lost, but can easily be recovered [#f2]_.\"\nmsgstr \"XPS: 外観は非常に良好です。リンクは正常に機能し、アウトライン（ブックマーク）は失われますが、簡単に回復できます [#f2]_。\"\n\n#: ../../document.rst:810 8d7b046661b24660b15edfc764b15786\nmsgid \"EPUB, CBZ, FB2: similar to XPS.\"\nmsgstr \"EPUB、CBZ、FB2: XPSと類似しています。\"\n\n#: ../../document.rst:811 78e1835be7ce41eaa08865503b86c38c\nmsgid \"\"\n\"SVG: medium. Roughly comparable to `svglib \"\n\"<https://github.com/deeplook/svglib>`_.\"\nmsgstr \"SVG: 中程度です。おおよそ `svglib <https://github.com/deeplook/svglib>`_ と比較できます。\"\n\n#: ../../document.rst:815 55fb4e92b6f84d06b5b5c8aec273b3e2\nmsgid \"Creates a table of contents (TOC) out of the document's outline chain.\"\nmsgstr \"ドキュメントのアウトラインチェーンから目次（TOC）を作成します。\"\n\n#: ../../document.rst:817 3c16d727444c4c31980289c39d4e07b3\nmsgid \"\"\n\"Indicates whether a simple or a detailed TOC is required. If ``False``, \"\n\"each item of the list also contains a dictionary with :ref:`linkDest` \"\n\"details for each outline entry.\"\nmsgstr \"\"\n\"簡単なTOCまたは詳細なTOCが必要かを示す値です。``False`` の場合、リストの各アイテムにはアウトラインエントリごとの \"\n\":ref:`linkDest` の詳細を含む辞書も含まれます。\"\n\n#: ../../document.rst:821 e45ac6b1b63f4d28b26628339a2251b7\nmsgid \"\"\n\"a list of lists. Each entry has the form *[lvl, title, page, dest]*. Its \"\n\"entries have the following meanings:  * *lvl* -- hierarchy level \"\n\"(positive *int*). The first entry is always 1. Entries in a row are \"\n\"either **equal**, **increase** by 1, or **decrease** by any number. * \"\n\"*title* -- title (*str*) * *page* -- 1-based source page number (*int*). \"\n\"`-1` if no destination or outside document. * *dest* -- (*dict*) included\"\n\" only if *simple=False*. Contains details of the TOC item as follows:    \"\n\"- kind: destination kind, see :ref:`linkDest Kinds`.   - file: filename \"\n\"if kind is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.   - page: target \"\n\"page, 0-based, :data:`LINK_GOTOR` or :data:`LINK_GOTO` only.   - to: \"\n\"position on target page (:ref:`Point`).   - zoom: (float) zoom factor on \"\n\"target page.   - xref: :data:`xref` of the item (0 if no PDF).   - color:\"\n\" item color in PDF RGB format `(red, green, blue)`, or omitted (always \"\n\"omitted if no PDF).   - bold: true if bold item text or omitted. PDF \"\n\"only.   - italic: true if italic item text, or omitted. PDF only.   - \"\n\"collapse: true if sub-items are folded, or omitted. PDF only.   - \"\n\"nameddest: target name if kind=4. PDF only. (New in 1.23.7.)\"\nmsgstr \"\"\n\n#: ../../document.rst:821 1f4b3e4744174653ae693109208dc49e\nmsgid \"\"\n\"a list of lists. Each entry has the form *[lvl, title, page, dest]*. Its \"\n\"entries have the following meanings:\"\nmsgstr \"リストのリスト。各エントリは次の形式を持っています: *[lvl, title, page, dest]* 。そのエントリは次の意味を持っています:\"\n\n#: ../../document.rst:823 e192fb552d1c4616a8fb7a8144812e58\nmsgid \"\"\n\"*lvl* -- hierarchy level (positive *int*). The first entry is always 1. \"\n\"Entries in a row are either **equal**, **increase** by 1, or **decrease**\"\n\" by any number.\"\nmsgstr \"\"\n\"*lvl* – 階層レベル（正の整数）。最初のエントリは常に1です。行内のエントリは **等しい** か、1ずつ **増加** または任意の数で \"\n\"**減少** します。\"\n\n#: ../../document.rst:824 29ecc17d35fa4115831c070fb3dc3da6\nmsgid \"*title* -- title (*str*)\"\nmsgstr \"*title* – タイトル（*str*）\"\n\n#: ../../document.rst:825 b5a9d59ce8954429a123261cd1e5e2ce\nmsgid \"\"\n\"*page* -- 1-based source page number (*int*). `-1` if no destination or \"\n\"outside document.\"\nmsgstr \"*page* – 1から始まるページ番号（*int*）。`-1` の場合、宛先なしまたはドキュメント外。\"\n\n#: ../../document.rst:826 1ed7122c8921425fa82f34ab81b0e14a\nmsgid \"\"\n\"*dest* -- (*dict*) included only if *simple=False*. Contains details of \"\n\"the TOC item as follows:\"\nmsgstr \"*dest* – (*dict*) *simple=False* の場合のみ含まれます。TOCアイテムの詳細が以下のように含まれます:\"\n\n#: ../../document.rst:828 18fd10a0fe68426b8268f99befab8ea5\nmsgid \"kind: destination kind, see :ref:`linkDest Kinds`.\"\nmsgstr \"kind: 宛先の種類、:ref:`linkDest Kinds` を参照。\"\n\n#: ../../document.rst:829 aeeca928a4f149d4b22d0f844cb317ce\nmsgid \"file: filename if kind is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.\"\nmsgstr \"file: `kind` が :data:`LINK_GOTOR` または :data:`LINK_LAUNCH` の場合のファイル名。\"\n\n#: ../../document.rst:830 21331bc906fb47aa9693dfe714690418\nmsgid \"page: target page, 0-based, :data:`LINK_GOTOR` or :data:`LINK_GOTO` only.\"\nmsgstr \"page: ターゲットページ、0ベース、:data:`LINK_GOTOR` または :data:`LINK_GOTO` の場合のみ。\"\n\n#: ../../document.rst:831 129a6492e95f4d6b9235c8566486f1cd\nmsgid \"to: position on target page (:ref:`Point`).\"\nmsgstr \"to: ターゲットページ上の位置 (:ref:`Point`)。\"\n\n#: ../../document.rst:832 1760adf4a8fe4f5d916c06a0718c0b3c\nmsgid \"zoom: (float) zoom factor on target page.\"\nmsgstr \"zoom: ターゲットページ上のズームファクター（float）。\"\n\n#: ../../document.rst:833 b72db90d2fd5463883c5566c8d708676\nmsgid \"xref: :data:`xref` of the item (0 if no PDF).\"\nmsgstr \"xref: アイテムの :data:`xref` （PDFがない場合は0）。\"\n\n#: ../../document.rst:834 ef52959e5a364bbdbede8eba835399d0\nmsgid \"\"\n\"color: item color in PDF RGB format `(red, green, blue)`, or omitted \"\n\"(always omitted if no PDF).\"\nmsgstr \"color: PDF RGB形式 `(red, green, blue)` のアイテムカラー、または省略（PDFがない場合は常に省略）。\"\n\n#: ../../document.rst:835 c6abd3655b1041c49d660425bdda3b9d\nmsgid \"bold: true if bold item text or omitted. PDF only.\"\nmsgstr \"bold: アイテムテキストが太字の場合、または省略。PDFのみ。\"\n\n#: ../../document.rst:836 790bd5ed794d4267aa960bc8d4ea5458\nmsgid \"italic: true if italic item text, or omitted. PDF only.\"\nmsgstr \"italic: アイテムテキストがイタリックの場合、または省略。PDFのみ。\"\n\n#: ../../document.rst:837 7a972813f0bc46f2aec437108637c21c\nmsgid \"collapse: true if sub-items are folded, or omitted. PDF only.\"\nmsgstr \"collapse: サブアイテムが折りたたまれている場合、または省略。PDFのみ。\"\n\n#: ../../document.rst:838 0a4c3b65b69e40f2bc742b0f74fa774e\nmsgid \"nameddest: target name if kind=4. PDF only. (New in 1.23.7.)\"\nmsgstr \"\"\n\n#: ../../document.rst:845 a5836c5cdff0458b8bee0e893e323504\nmsgid \"\"\n\"PDF only: Return the PDF dictionary keys of the :data:`dictionary` object\"\n\" provided by its xref number.\"\nmsgstr \"PDFのみ: xref番号で提供される :data:`dictionary` オブジェクトのPDF辞書キーを返します。\"\n\n#: ../../document.rst:847 05b0b53203ac4aa9b0d24d401d355137\nmsgid \"\"\n\"the :data:`xref`. *(Changed in v1.18.10)* Use `-1` to access the special \"\n\"dictionary \\\"PDF trailer\\\".\"\nmsgstr \":data:`xref` 。 *(v1.18.10で変更)* \\\"PDF trailer\\\" としてアクセスするには `-1` を使用します。\"\n\n#: ../../document.rst:849 608982aaeb9c4e0483f619e22304399f\nmsgid \"\"\n\"a tuple of dictionary keys present in object :data:`xref`. Examples:  >>>\"\n\" from pprint import pprint >>> import pymupdf >>> \"\n\"doc=pymupdf.open(\\\"pymupdf.pdf\\\") >>> xref = doc.page_xref(0)  # xref of \"\n\"page 0 >>> pprint(doc.xref_get_keys(xref))  # primary level keys of a \"\n\"page ('Type', 'Contents', 'Resources', 'MediaBox', 'Parent') >>> \"\n\"pprint(doc.xref_get_keys(-1))  # primary level keys of the trailer \"\n\"('Type', 'Index', 'Size', 'W', 'Root', 'Info', 'ID', 'Length', 'Filter') \"\n\">>>\"\nmsgstr \"\"\n\n#: ../../document.rst:849 df215624f145490e82a53931b1a144ba\nmsgid \"a tuple of dictionary keys present in object :data:`xref`. Examples:\"\nmsgstr \":data:`xref` オブジェクトに存在する辞書キーのタプル。例:\"\n\n#: ../../document.rst:866 6575211909ea416eb59abe9e9d74b18a\nmsgid \"\"\n\"PDF only: Return type and value of a PDF dictionary key of a \"\n\":data:`dictionary` object given by its xref.\"\nmsgstr \"PDFのみ: xrefによって提供される :data:`dictionary` オブジェクトのPDF辞書キーの戻り値の型と値を返します。\"\n\n#: ../../document.rst:868 e72020a16f2c46d9b9c110390a8ef3b8\nmsgid \"\"\n\"the :data:`xref`. *Changed in v1.18.10:* Use `-1` to access the special \"\n\"dictionary \\\"PDF trailer\\\".\"\nmsgstr \":data:`xref` 。*v1.18.10で変更:* 特別な辞書 \\\"PDF trailer\\\"  にアクセスするには `-1` を使用します。\"\n\n#: ../../document.rst:870 15710a8605c242738c9d34bc9295c2a8\nmsgid \"\"\n\"the desired PDF key. Must **exactly** match (case-sensitive) one of the \"\n\"keys contained in :meth:`Document.xref_get_keys`.\"\nmsgstr \"\"\n\"望ましいPDFキー。:meth:`Document.xref_get_keys` \"\n\"に含まれるキーのいずれかと厳密に一致する必要があります（大文字と小文字を区別します）。\"\n\n#: ../../document.rst:874 1d8b5b14cc604c8097524b1e8ce3bd1a\nmsgid \"\"\n\"A tuple (type, value) of strings, where type is one of \\\"xref\\\", \"\n\"\\\"array\\\", \\\"dict\\\", \\\"int\\\", \\\"float\\\", \\\"null\\\", \\\"bool\\\", \\\"name\\\", \"\n\"\\\"string\\\" or \\\"unknown\\\" (should not occur). Independent of \\\"type\\\", \"\n\"the value of the key is **always** formatted as a string -- see the \"\n\"following example -- and (almost always) a faithful reflection of what is\"\n\" stored in the PDF. In most cases, the format of the value string also \"\n\"gives a clue about the key type:\"\nmsgstr \"\"\n\"文字列のタプル（type、value）、ここでtypeは次のいずれかです: \"\n\"\\\"xref\\\"、\\\"array\\\"、\\\"dict\\\"、\\\"int\\\"、\\\"float\\\"、\\\"null\\\"、\\\"bool\\\"、\\\"name\\\"、\\\"string\\\"\"\n\" または \\\"unknown\\\"（発生しないはず）。\\\"type\\\" に関係なく、キーの値は **常に** 文字列としてフォーマットされます – \"\n\"以下の例を参照 – \"\n\"そして（ほとんどの場合）PDFに格納されている内容の忠実な反映です。ほとんどの場合、値文字列のフォーマットもキーのタイプについてのヒントを提供します:\"\n\n#: ../../document.rst:876 f3a754b526724add862cf709d3e6a80f\nmsgid \"A \\\"name\\\" always starts with a \\\"/\\\" slash.\"\nmsgstr \"\\\"name\\\" は常に \\\"/\\\" スラッシュで始まります。\"\n\n#: ../../document.rst:877 156bcb3e4be0431a950ef8733fb4726f\nmsgid \"An \\\"xref\\\" always ends with \\\" 0 R\\\".\"\nmsgstr \"\\\"xref\\\" は常に \\\" 0 R\\\" で終わります。\"\n\n#: ../../document.rst:878 028b075a7b6743b4992177c05b64dd3c\nmsgid \"An \\\"array\\\" is always enclosed in \\\"[...]\\\" brackets.\"\nmsgstr \"\\\"array\\\" は常に \\\"[...]\\\" 角括弧で囲まれています。\"\n\n#: ../../document.rst:879 498042f7ba7941f489e490897176da71\nmsgid \"A \\\"dict\\\" is always enclosed in \\\"<<...>>\\\" brackets.\"\nmsgstr \"\\\"dict\\\" は常に \\\"<<...>>\\\" 角括弧で囲まれています。\"\n\n#: ../../document.rst:880 9a602b09b09445b8ab3a85710d4daff4\nmsgid \"\"\n\"A \\\"bool\\\", resp. \\\"null\\\" always equal either \\\"true\\\", \\\"false\\\", resp.\"\n\" \\\"null\\\".\"\nmsgstr \"\\\"bool\\\" または \\\"null\\\" は常に \\\"true\\\"、\\\"false\\\" または \\\"null\\\" のいずれかです。\"\n\n#: ../../document.rst:881 3599f60a08a442d2a3fe36a99d5cbfbe\nmsgid \"\"\n\"\\\"float\\\" and \\\"int\\\" are represented by their string format -- and are \"\n\"thus not always distinguishable.\"\nmsgstr \"\\\"float\\\" と \\\"int\\\" は文字列形式で表され、したがって常に区別できるわけではありません。\"\n\n#: ../../document.rst:882 178b674795594e1d8c179336c614b1c2\nmsgid \"\"\n\"A \\\"string\\\" is converted to UTF-8 and may therefore deviate from what is\"\n\" stored in the PDF. For example, the PDF key \\\"Author\\\" may have a value \"\n\"of \\\"<FEFF004A006F0072006A00200058002E0020004D0063004B00690065>\\\" in the \"\n\"file, but the method will return `('string', 'Jorj X. McKie')`.\"\nmsgstr \"\"\n\"\\\"string\\\" はUTF-8に変換され、したがってPDFに格納されている内容と異なる場合があります。たとえば、PDFキー \"\n\"\\\"Author\\\" はファイル内で \"\n\"\\\"FEFF004A006F0072006A00200058002E0020004D0063004B00690065\\\" \"\n\"という値を持つかもしれませんが、このメソッドは  `('string', 'Jorj X. McKie')` を返します。\"\n\n#: ../../document.rst:911 5ec6251f88fd4c9a8f9aa0c0de4ef793\nmsgid \"New in v1.18.7, changed in v 1.18.13\"\nmsgstr \"バージョン1.18.7で新規追加、バージョン1.18.13で変更されました。\"\n\n#: ../../document.rst:912 277a8925b1254249865a344d4e15ce92\nmsgid \"Changed in v1.19.4: remove a key \\\"physically\\\" if set to \\\"null\\\".\"\nmsgstr \"バージョン1.19.4で変更: \\\"null\\\" に設定された場合、キーを \\\"物理的に\\\" 削除します。\"\n\n#: ../../document.rst:914 3800031db9924e0b93e21a204f5abfd2\nmsgid \"\"\n\"PDF only: Set (add, update, delete) the value of a PDF key for the \"\n\":data:`dictionary` object given by its xref.\"\nmsgstr \"PDFのみ: xrefによって提供される :data:`dictionary` オブジェクトのPDFキーの値を設定（追加、更新、削除）します。\"\n\n#: ../../document.rst:916 87400e3bfd904856bd104cdc238c25ef\nmsgid \"\"\n\"This is an expert function: if you do not know what you are doing, there \"\n\"is a high risk to render (parts of) the PDF unusable. Please do consult \"\n\":ref:`AdobeManual` about object specification formats (page 18) and the \"\n\"structure of special dictionary types like page objects.\"\nmsgstr \"\"\n\"これはエキスパート向けの機能です。何をしているのかわからない場合、PDFの（一部の）使用不能の高いリスクがあります。PDFオブジェクト仕様フォーマット（ページ18）やページオブジェクトなどの特別な辞書タイプの構造については\"\n\" :ref:`AdobeManual` を参照してください。\"\n\n#: ../../document.rst:918 249156cd0aa4484c824c8bd971c5f55d\nmsgid \"\"\n\"the :data:`xref`. *Changed in v1.18.13:* To update the PDF trailer, \"\n\"specify -1.\"\nmsgstr \":data:`xref` 。バージョン1.18.13で変更: PDFトレーラーを更新する場合、-1を指定します。\"\n\n#: ../../document.rst:919 defb25fd803549ecbd76352234501833\nmsgid \"\"\n\"the desired PDF key (without leading \\\"/\\\"). Must not be empty. Any valid\"\n\" PDF key -- whether already present in the object (which will be \"\n\"overwritten) -- or new. It is possible to use PDF path notation like \"\n\"`\\\"Resources/ExtGState\\\"` -- which sets the value for key \"\n\"`\\\"/ExtGState\\\"` as a sub-object of `\\\"/Resources\\\"`.\"\nmsgstr \"\"\n\"望ましいPDFキー（先頭の \\\"/\\\" \"\n\"なし）。空であってはいけません。既にオブジェクト内に存在するかどうかに関係なく、新しいPDFキーでも構いません。PDFパス表記 \"\n\"（`\\\"Resources/ExtGState\\\"` のような）を使用して、`\\\"/Resources\\\"` のサブオブジェクトとしてキー \"\n\"`\\\"/ExtGState\\\"` の値を設定することも可能です。\"\n\n#: ../../document.rst:920 90eda3333fa54a88ba8598e27bdc720a\nmsgid \"\"\n\"the value for the key. It must be a non-empty string and, depending on \"\n\"the desired PDF object type, the following rules must be observed. There \"\n\"is some syntax checking, but **no type checking** and no checking if it \"\n\"makes sense PDF-wise, i.e. **no semantics checking**. Upper / lower case \"\n\"is important!\"\nmsgstr \"キーの値。空でない文字列である必要があり、望ましいPDFオブジェクトのタイプに応じて以下のルールを守る必要があります。一部の構文チェックは行われますが、型チェックやPDFとして意味があるかどうかのチェックは行われません。大文字と小文字の区別が重要です！\"\n\n#: ../../document.rst:922 a7fd503efdb34cf08f1886ee7162fb2f\nmsgid \"\"\n\"*:data:`xref`* -- must be provided as `\\\"nnn 0 R\\\"` with a valid \"\n\":data:`xref` number nnn of the PDF. The suffix \\\"`0 R`\\\" is required to \"\n\"be recognizable as an xref by PDF applications.\"\nmsgstr \"\"\n\"*:data:`xref`* – 有効なPDFのxref番号nnnを持つ `\\\"nnn 0 R\\\"` として提供される必要があります。サフィックス\"\n\" \\\"`0 R`\\\" はPDFアプリケーションによって :data:`xref` として認識されるため必要です。\"\n\n#: ../../document.rst:923 80568ddddb28424aafbeb4bfb8629262\nmsgid \"\"\n\"**array** -- a string like `\\\"[a b c d e f]\\\"`. The brackets are \"\n\"required. Array items must be separated by at least one space (not commas\"\n\" like in Python). An empty array `\\\"[]\\\"` is possible and *equivalent* to\"\n\" removing the key. Array items may be any PDF objects, like dictionaries,\"\n\" xrefs, other arrays, etc. Like in Python, array items may be of \"\n\"different types.\"\nmsgstr \"\"\n\"**array** – `\\\"[a b c d e f]\\\"` \"\n\"のような文字列。角括弧が必要です。配列の要素は少なくとも1つのスペースで区切られている必要があります（Pythonのようなカンマではありません）。空の配列\"\n\" `\\\"[]\\\"` も可能で、キーを削除することと *同等* \"\n\"です。配列のアイテムは、辞書、xref、他の配列など、PDFオブジェクトである必要があります。Pythonと同様に、配列のアイテムは異なるタイプである場合があります。\"\n\n#: ../../document.rst:924 8776c9b8b4a24c0591f8ceec49ed2dca\nmsgid \"\"\n\"**dict** -- a string like `\\\"<< ... >>\\\"`. The brackets are required and \"\n\"must enclose a valid PDF dictionary definition. The empty dictionary \"\n\"`\\\"<<>>\\\"` is possible and *equivalent* to removing the key.\"\nmsgstr \"\"\n\"**dict** – `\\\"<< ... >>\\\"` のような文字列。角括弧が必要で、有効なPDF辞書定義を囲む必要があります。空の辞書 \"\n\"`\\\"<<>>\\\"` も可能で、キーを削除することと *同等* です。\"\n\n#: ../../document.rst:925 e8b31a1d2c3a4878a02465e970ff484d\nmsgid \"**int** -- an integer formatted **as a string**.\"\nmsgstr \"**int** – **文字列として** フォーマットされた整数。\"\n\n#: ../../document.rst:926 4efb1d2d1f8248bd9c93bdbed526f048\nmsgid \"\"\n\"**float** -- a float formatted **as a string**. Scientific notation (with\"\n\" exponents) is **not allowed by PDF**.\"\nmsgstr \"**float**  – 文字列としてフォーマットされた浮動小数点数。科学的表記法（指数を含む）は **PDFでは許可されていません** 。\"\n\n#: ../../document.rst:927 28ad2273e2b04ec1a4e28b1e8627be22\nmsgid \"\"\n\"**null** -- the string `\\\"null\\\"`. This is the PDF equivalent to Python's\"\n\" `None` and causes the key to be ignored -- however not necessarily \"\n\"removed, resp. removed on saves with garbage collection. *Changed in \"\n\"v1.19.4:* If the key is no path hierarchy (i.e. contains no slash \\\"/\\\"),\"\n\" then it will be completely removed.\"\nmsgstr \"\"\n\"**null** – 文字列 `\\\"null\\\"`。これはPythonの `None` \"\n\"に相当し、キーを無視させますが、必ずしも削除されるわけではありません。ガベージコレクションを伴う保存時に削除される場合があります。*バージョン1.19.4で変更:*\"\n\" キーがパス階層でない場合（つまりスラッシュ \\\"/\\\" を含まない場合）、それは完全に削除されます。\"\n\n#: ../../document.rst:928 adabb0e0f0ed4a6681b1296c1502547a\nmsgid \"**bool** -- one of the strings `\\\"true\\\"` or `\\\"false\\\"`.\"\nmsgstr \"**bool** – `\\\"true\\\"` または `\\\"false\\\"` のいずれかの文字列。\"\n\n#: ../../document.rst:929 1594ca312d7f48acbc4d82268247f9ee\nmsgid \"\"\n\"**name** -- a valid PDF name with a leading slash like this: \"\n\"`\\\"/PageLayout\\\"`. See page 16 of the :ref:`AdobeManual`.\"\nmsgstr \"\"\n\"**name** – `\\\"/PageLayout\\\"` のように先頭にスラッシュを持つ有効なPDF名。:ref:`AdobeManual` \"\n\"のページ16を参照してください。\"\n\n#: ../../document.rst:930 28a5e09473bf4296a58a3ec3460e12be\nmsgid \"\"\n\"**string** -- a valid PDF string. **All PDF strings must be enclosed by \"\n\"brackets**. Denote the empty string as `\\\"()\\\"`. Depending on its \"\n\"content, the possible brackets are\"\nmsgstr \"\"\n\"**string** – 有効なPDF文字列。 **すべてのPDF文字列は角括弧で囲まれている必要があります** 。空の文字列は `\\\"()\\\"`\"\n\" として表記されます。内容に応じて、可能な角括弧は次の通りです。\"\n\n#: ../../document.rst:932 bf4426b2937d496185dc5ca3086d1560\nmsgid \"\"\n\"\\\"(...)\\\" for ASCII-only text. Reserved PDF characters must be backslash-\"\n\"escaped and non-ASCII characters must be provided as 3-digit backslash-\"\n\"escaped octals -- including leading zeros. Example: 12 = 0x0C must be \"\n\"encoded as `\\\\014`.\"\nmsgstr \"\"\n\"\\\"(…)\\\"：ASCIIのテキストの場合。予約されたPDF文字はバックスラッシュでエスケープし、非ASCII文字は先頭にゼロパディングされた3桁のバックスラッシュエスケープの8進数で提供する必要があります。例:\"\n\" 12 = 0x0C は `\\\\014` としてエンコードする必要があります。\"\n\n#: ../../document.rst:933 b3138023eeab42d8976d82ae328a48e7\nmsgid \"\"\n\"\\\"<...>\\\" for hex-encoded text. Every character must be represented by \"\n\"two hex-digits (lower or upper case).\"\nmsgstr \"\\\"<…>\\\"：16進数でエンコードされたテキストの場合。各文字は2桁の16進数で表されなければなりません（大文字または小文字）。\"\n\n#: ../../document.rst:935 04514ffed9104a3f82cba27d60dae539\nmsgid \"\"\n\"If in doubt, we **strongly recommend** to use :meth:`get_pdf_str`! This \"\n\"function automatically generates the right brackets, escapes, and overall\"\n\" format. It will for example do conversions like these:\"\nmsgstr \"\"\n\"疑念がある場合は、:meth:`get_pdf_str` \"\n\"の使用を**強くお勧めします**！この関数は自動的に適切な角括弧、エスケープ、および全体のフォーマットを生成します。たとえば、次のような変換を行います。\"\n\n#: ../../document.rst:947 e157d6a6ebb44a58a5382b3125619640\nmsgid \"\"\n\"Creates a pixmap from page *pno* (zero-based). Invokes \"\n\":meth:`Page.get_pixmap`.\"\nmsgstr \"*pno* （ゼロベース）のページからピクスマップを作成します。:meth:`Page.get_pixmap` を呼び出します。\"\n\n#: ../../document.rst:949 bb646c2e759e4d2bbee44f4ad97ec08e\nmsgid \"All parameters except `pno` are *keyword-only.*\"\nmsgstr \"`pno` 以外のすべてのパラメーターは *キーワード専用* です。\"\n\n#: ../../document.rst:951 663b27e190f34a04a42b233cf48b0d2d\nmsgid \"page number, 0-based in `-∞ < pno < page_count`.\"\nmsgstr \"pno (int) – ページ番号、ゼロベース、`-∞ < pno < page_count`。\"\n\n#: ../../document.rst:953 83e16eb54fbc471cbb9c5e21748734af\nmsgid \":ref:`Pixmap`\"\nmsgstr \"\"\n\n#: ../../document.rst:957 4aaceb696b71426cac76aa4f65fadab7\nmsgid \"New in v1.16.13\"\nmsgstr \"バージョン1.16.13で新規追加\"\n\n#: ../../document.rst:958 b4622be6eecf433d824b4e0092311b23\nmsgid \"Changed in v1.18.11\"\nmsgstr \"バージョン1.18.11で変更\"\n\n#: ../../document.rst:960 a50d47a57f9a458cbdb6f4c19c9ecc2f\nmsgid \"PDF only: Return a list of all XObjects referenced by a page.\"\nmsgstr \"PDFのみ: ページによって参照されるすべてのXObjectのリストを返します。\"\n\n#: ../../document.rst:962 ../../document.rst:977 ../../document.rst:1004\n#: b512284cd0944db08267225142b30973 b7a9d1c1640a44e49194253e80f28940\n#: bcc36ae910474f22b80c5aeb1e3cd296\nmsgid \"page number, 0-based, `-∞ < pno < page_count`.\"\nmsgstr \"ページ番号、ゼロベース、`-∞ < pno < page_count`。\"\n\n#: ../../document.rst:965 c4fd71139bd44bb8ada4e97a475737cd\nmsgid \"\"\n\"a list of (non-image) XObjects. These objects typically represent pages \"\n\"*embedded* (not copied) from other PDFs. For example, \"\n\":meth:`Page.show_pdf_page` will create this type of object. An item of \"\n\"this list has the following layout: `(xref, name, invoker, bbox)`, where\"\n\"  * *:data:`xref`* (*int*) is the XObject's :data:`xref`. * **name** \"\n\"(*str*) is the symbolic name to reference the XObject. * **invoker** \"\n\"(*int*) the :data:`xref` of the invoking XObject or zero if the page \"\n\"directly invokes it. * **bbox** (:ref:`Rect`) the boundary box of the \"\n\"XObject's location on the page **in untransformed coordinates**. To get \"\n\"actual, non-rotated page coordinates, multiply with the page's \"\n\"transformation matrix :attr:`Page.transformation_matrix`. *Changed in \"\n\"v.18.11:* the bbox is now formatted as :ref:`Rect`.\"\nmsgstr \"\"\n\n#: ../../document.rst:965 21d6f7f8ef56493e8984e44eec7d841b\nmsgid \"\"\n\"a list of (non-image) XObjects. These objects typically represent pages \"\n\"*embedded* (not copied) from other PDFs. For example, \"\n\":meth:`Page.show_pdf_page` will create this type of object. An item of \"\n\"this list has the following layout: `(xref, name, invoker, bbox)`, where\"\nmsgstr \"\"\n\"（画像でない）XObjectのリスト。これらのオブジェクトは通常、他のPDFから **埋め込まれた** \"\n\"（コピーされていない）ページを表します。例えば、:meth:`Page.show_pdf_page` \"\n\"はこのタイプのオブジェクトを作成します。このリストのアイテムは以下のレイアウトを持っています：`(xref, name, invoker, \"\n\"bbox)`、ここで\"\n\n#: ../../document.rst:967 d6f78447afef45d7a168cf13ab89fbcc\nmsgid \"*:data:`xref`* (*int*) is the XObject's :data:`xref`.\"\nmsgstr \"*:data:`xref`* (*int*) はXObjectの :data:`xref` です。\"\n\n#: ../../document.rst:968 2f42c8f85790488dbce62e7093baa9c5\nmsgid \"**name** (*str*) is the symbolic name to reference the XObject.\"\nmsgstr \"**name** (*str*) はXObjectを参照するための象徴的な名前です。\"\n\n#: ../../document.rst:969 2355cf43667b42aaae40b91b5a5937b9\nmsgid \"\"\n\"**invoker** (*int*) the :data:`xref` of the invoking XObject or zero if \"\n\"the page directly invokes it.\"\nmsgstr \"\"\n\"**invoker** (*int*) は、ページがそれを直接呼び出す場合はゼロ、それ以外の場合は呼び出し元XObjectの \"\n\":data:`xref` です。\"\n\n#: ../../document.rst:970 ce656f07b3d3474ba08d6e123b8117c4\nmsgid \"\"\n\"**bbox** (:ref:`Rect`) the boundary box of the XObject's location on the \"\n\"page **in untransformed coordinates**. To get actual, non-rotated page \"\n\"coordinates, multiply with the page's transformation matrix \"\n\":attr:`Page.transformation_matrix`. *Changed in v.18.11:* the bbox is now\"\n\" formatted as :ref:`Rect`.\"\nmsgstr \"\"\n\"**bbox** (:ref:`Rect`) はXObjectのページ上の位置の境界ボックスで、**変換されていない座標で** \"\n\"表されます。実際の、回転していないページ座標を取得するには、ページの変換行列 :attr:`Page.transformation_matrix`\"\n\" を掛けてください。*バージョン1.18.11で変更:* **bbox** は今や :ref:`Rect` としてフォーマットされています。\"\n\n#: ../../document.rst:975 6fe8a93907b94d18969a4b9ab14c4359\nmsgid \"\"\n\"PDF only: Return a list of all images (directly or indirectly) referenced\"\n\" by the page.\"\nmsgstr \"PDFのみ: ページによって参照されるすべての画像（直接または間接的に）のリストを返します。\"\n\n#: ../../document.rst:978 9f4e6fd3f1e04b22a5a95840ab1550ff\nmsgid \"\"\n\"whether to also include the referencer's :data:`xref` (which is zero if \"\n\"this is the page).\"\nmsgstr \"このページがそのページ自体の場合、参照元の :data:`xref` も含めるかどうか（これがページの場合はゼロ）。\"\n\n#: ../../document.rst:982 4efb3fbf341f42098699c1b7689ee45c\nmsgid \"\"\n\"a list of images **referenced** by this page. Each item looks like:  \"\n\"`(xref, smask, width, height, bpc, colorspace, alt_colorspace, name, \"\n\"filter, referencer)`    * ``xref`` (*int*) is the image object number   *\"\n\" ``smask`` (*int*) is the object number of its soft-mask image   * \"\n\"``width`` (*int*) is the image width   * ``height`` (*int*) is the image \"\n\"height   * ``bpc`` (*int*) denotes the number of bits per component \"\n\"(normally 8)   * ``colorspace`` (*str*) a string naming the colorspace \"\n\"(like **DeviceRGB**)   * ``alt_colorspace`` (*str*) is any alternate \"\n\"colorspace depending on the value of **colorspace**   * ``name`` (*str*) \"\n\"is the symbolic name by which the image is referenced   * ``filter`` \"\n\"(*str*) is the decode filter of the image (:ref:`AdobeManual`, pp. 22).\"\n\"   * ``referencer`` (*int*) the :data:`xref` of the referencer. Zero if \"\n\"directly referenced by the page. Only present if *full=True*.\"\nmsgstr \"\"\n\n#: ../../document.rst:982 8f9928f663504d3d9168282aed83e5cc\n#, fuzzy\nmsgid \"a list of images **referenced** by this page. Each item looks like:\"\nmsgstr \"このページで **参照されている** 画像のリスト。各アイテムは以下のようになります：\"\n\n#: ../../document.rst:984 00f4ef107d1c4db385603c6339a76099\nmsgid \"\"\n\"`(xref, smask, width, height, bpc, colorspace, alt_colorspace, name, \"\n\"filter, referencer)`\"\nmsgstr \"\"\n\n#: ../../document.rst:986 3d896dcb29714890a22bfb1f0ffc4a34\n#, fuzzy\nmsgid \"``xref`` (*int*) is the image object number\"\nmsgstr \"*:data:`xref`* (*int*) は画像オブジェクトの番号です\"\n\n#: ../../document.rst:987 9acc8321d4094ed1b2397b95f2886d22\n#, fuzzy\nmsgid \"``smask`` (*int*) is the object number of its soft-mask image\"\nmsgstr \"**smask** (*int*) はそのソフトマスク画像のオブジェクト番号です\"\n\n#: ../../document.rst:988 0f53d4a9d9074947a83aab2d9a176cb1\n#, fuzzy\nmsgid \"``width`` (*int*) is the image width\"\nmsgstr \"*width* (*int*) 画像の幅\"\n\n#: ../../document.rst:989 35c2acc0727549249953c971d8917290\n#, fuzzy\nmsgid \"``height`` (*int*) is the image height\"\nmsgstr \"*height* (*int*) 画像の高さ\"\n\n#: ../../document.rst:990 7413ba2b65df40ec96a73858402002a4\n#, fuzzy\nmsgid \"``bpc`` (*int*) denotes the number of bits per component (normally 8)\"\nmsgstr \"**bpc** (*int*) はコンポーネントごとのビット数を示します（通常は8）\"\n\n#: ../../document.rst:991 b43082aeae534bf3af1fdd913d40e5b1\n#, fuzzy\nmsgid \"``colorspace`` (*str*) a string naming the colorspace (like **DeviceRGB**)\"\nmsgstr \"**colorspace** (*str*) は色空間の名前を示す文字列です（ **DeviceRGB** など）\"\n\n#: ../../document.rst:992 029549b0601a446da7e5e1b15bdc3f5d\n#, fuzzy\nmsgid \"\"\n\"``alt_colorspace`` (*str*) is any alternate colorspace depending on the \"\n\"value of **colorspace**\"\nmsgstr \"**alt. colorspace** (*str*) は **colorspace** の値に依存する代替の色空間です\"\n\n#: ../../document.rst:993 e2137f9fc6d845d4b63d058fc6cd19d3\n#, fuzzy\nmsgid \"``name`` (*str*) is the symbolic name by which the image is referenced\"\nmsgstr \"**name** (*str*) は画像が参照される際の象徴的な名前です\"\n\n#: ../../document.rst:994 6676261a491d4bc4b0e9543f4d842080\n#, fuzzy\nmsgid \"\"\n\"``filter`` (*str*) is the decode filter of the image (:ref:`AdobeManual`,\"\n\" pp. 22).\"\nmsgstr \"**filter** (*str*) は画像のデコードフィルタです（:ref:`AdobeManual`、pp. 22）。\"\n\n#: ../../document.rst:995 d92b9e1700fd4c62854642a1f6dde89c\n#, fuzzy\nmsgid \"\"\n\"``referencer`` (*int*) the :data:`xref` of the referencer. Zero if \"\n\"directly referenced by the page. Only present if *full=True*.\"\nmsgstr \"\"\n\"**referencer** (*int*) は参照元の :data:`xref` です。直接ページから参照されている場合はゼロ。 \"\n\"*full=True* の場合のみ存在します\"\n\n#: ../../document.rst:997 c07f09a4315a4410bcdfa4e0e35c5613\nmsgid \"\"\n\"In general, this is not the list of images that are **actually \"\n\"displayed**. This method only parses several PDF objects to collect \"\n\"references to embedded images. It does not analyse the page's \"\n\":data:`contents`, where all the actual image display commands are \"\n\"defined. To get this information, please use :meth:`Page.get_image_info`.\"\n\" Also have a look at the discussion in section :ref:`textpagedict`.\"\nmsgstr \"\"\n\"一般的に、これは **実際に表示されている** \"\n\"画像のリストではありません。このメソッドは埋め込まれた画像への参照を収集するためにいくつかのPDFオブジェクトのみを解析します。実際の画像表示コマンドが定義されているページの内容は解析しません。この情報を取得するには、:meth:`Page.get_image_info`\"\n\" を使用してください。また、:ref:`textpagedict` のセクションでの議論もご覧ください。\"\n\n#: ../../document.rst:1002 50688d36bbf24221a9c4c9d2d3383083\n#, fuzzy\nmsgid \"\"\n\"PDF only: Return a list of all fonts (directly or indirectly) referenced \"\n\"by the page object definition.\"\nmsgstr \"PDFのみ: ページによって参照されるすべてのフォント（直接または間接的に）のリストを返します。\"\n\n#: ../../document.rst:1005 0f887570532b4208be1fe1b83d43adbc\nmsgid \"\"\n\"whether to also include the referencer's :data:`xref`. If ``True``, the \"\n\"returned items are one entry longer. Use this option if you need to know,\"\n\" whether the page directly references the font. In this case the last \"\n\"entry is 0. If the font is referenced by an `/XObject` of the page, you \"\n\"will find its :data:`xref` here.\"\nmsgstr \"\"\n\"参照元の :data:`xref` も含めるかどうか。``True`` \"\n\"の場合、返されるアイテムは1つ多くなります。ページがフォントを直接参照しているかどうかを知る必要がある場合は、このオプションを使用します。この場合、最後のエントリは0です。フォントがページの\"\n\" `/XObject` によって参照される場合、その :data:`xref` をここで見つけることができます。\"\n\n#: ../../document.rst:1009 b483bbc3f4c244c6acc8c409b25f1dd5\nmsgid \"\"\n\"a list of fonts referenced by the object definition of the page. Each \"\n\"entry looks like:  `(xref, ext, type, basefont, name, encoding, \"\n\"referencer)`      * ``xref`` (*int*) is the font object number (may be \"\n\"zero if the PDF uses one of the builtin fonts directly)     * ``ext`` \"\n\"(*str*) font file extension (e.g. \\\"ttf\\\", see :ref:`FontExtensions`)\"\n\"     * ``type`` (*str*) is the font type (like \\\"Type1\\\" or \\\"TrueType\\\" \"\n\"etc.)     * ``basefont`` (*str*) is the base font name,     * ``name`` \"\n\"(*str*) is the symbolic name, by which the font is referenced     * \"\n\"``encoding`` (*str*) the font's character encoding if different from its \"\n\"built-in encoding (:ref:`AdobeManual`, p. 254):     * ``referencer`` \"\n\"(*int* optional) the :data:`xref` of the referencer. Zero if directly \"\n\"referenced by the page, otherwise the xref of an XObject. Only present if\"\n\" *full=True*.\"\nmsgstr \"\"\n\n#: ../../document.rst:1009 58bcdadb2ba8444d931f586e64adae5e\n#, fuzzy\nmsgid \"\"\n\"a list of fonts referenced by the object definition of the page. Each \"\n\"entry looks like:\"\nmsgstr \"このページで参照されているフォントのリスト。各エントリは以下のようになります：\"\n\n#: ../../document.rst:1011 4a04236fee1f48d1a11fcb7b3892c541\nmsgid \"`(xref, ext, type, basefont, name, encoding, referencer)`\"\nmsgstr \"\"\n\n#: ../../document.rst:1013 82b62283f3904f859c1cfc7fd913aa3a\n#, fuzzy\nmsgid \"\"\n\"``xref`` (*int*) is the font object number (may be zero if the PDF uses \"\n\"one of the builtin fonts directly)\"\nmsgstr \"\"\n\"*:data:`xref`* (*int*) \"\n\"はフォントオブジェクト番号です（PDFが組み込みフォントを直接使用している場合、ゼロになることがあります）\"\n\n#: ../../document.rst:1014 b281d41a2a104abc96fb433a1ccf6917\n#, fuzzy\nmsgid \"\"\n\"``ext`` (*str*) font file extension (e.g. \\\"ttf\\\", see \"\n\":ref:`FontExtensions`)\"\nmsgstr \"**ext** (*str*) フォントファイルの拡張子（例: \\\"ttf\\\"、:ref:`FontExtensions` を参照）\"\n\n#: ../../document.rst:1015 a3da8b4719364cddb5b13b0530926e71\n#, fuzzy\nmsgid \"``type`` (*str*) is the font type (like \\\"Type1\\\" or \\\"TrueType\\\" etc.)\"\nmsgstr \"**type** (*str*) フォントの種類（\\\"Type1\\\"や\\\"TrueType\\\"など）\"\n\n#: ../../document.rst:1016 a967a9a698a54fc6b11d779661ce60f1\n#, fuzzy\nmsgid \"``basefont`` (*str*) is the base font name,\"\nmsgstr \"**basefont** (*str*) ベースフォント名\"\n\n#: ../../document.rst:1017 614bd868a5294452b00f8986ef84424a\n#, fuzzy\nmsgid \"``name`` (*str*) is the symbolic name, by which the font is referenced\"\nmsgstr \"**name** (*str*) フォントが参照される象徴的な名前\"\n\n#: ../../document.rst:1018 76630068ae7f4e588fb71e0a5e8fda81\n#, fuzzy\nmsgid \"\"\n\"``encoding`` (*str*) the font's character encoding if different from its \"\n\"built-in encoding (:ref:`AdobeManual`, p. 254):\"\nmsgstr \"\"\n\"**encoding** (*str*) \"\n\"フォントの文字エンコーディング。組み込みエンコーディングと異なる場合（:ref:`AdobeManual`、p. 254を参照）：\"\n\n#: ../../document.rst:1019 d9bbbba29f0d49179ac6534d71492729\n#, fuzzy\nmsgid \"\"\n\"``referencer`` (*int* optional) the :data:`xref` of the referencer. Zero \"\n\"if directly referenced by the page, otherwise the xref of an XObject. \"\n\"Only present if *full=True*.\"\nmsgstr \"\"\n\"**referencer** (*int*、オプション) 参照元のxref。ページから直接参照されている場合は0、それ以外の場合はXObjectの\"\n\" :data:`xref` です。 *full=True* の場合のみ存在します。\"\n\n#: ../../document.rst:1021 0754eb9f62d34168ad17f5bc693e308d\nmsgid \"Example::\"\nmsgstr \"例::\"\n\n#: ../../document.rst:1034 bf4929ce53d44735a61082c4227b290d\nmsgid \"\"\n\"This list has no duplicate entries: the combination of :data:`xref`, \"\n\"*name* and *referencer* is unique.\"\nmsgstr \"このリストには重複するエントリはありません：:data:`xref` 、*name* 、および *referencer* の組み合わせは一意です。\"\n\n#: ../../document.rst:1035 1b9423c83bd84bdfbc55c57f23bc2164\n#, fuzzy\nmsgid \"\"\n\"In general, this is a true superset of the fonts actually in use by this \"\n\"page. The PDF creator may e.g. have specified some global list, of which \"\n\"each page make only partial use.\"\nmsgstr \"一般的に、これはこのページで実際に使用されているフォントのスーパーセットです。PDF作成者は、各ページが部分的にしか使用しない、グローバルリストを指定したかもしれません。\"\n\n#: ../../document.rst:1036 9b8712ad035b4ee5af594a3e164f7d0b\nmsgid \"\"\n\"Be aware that font names returned by some variants of \"\n\":meth:`Page.get_text` (respectively :ref:`TextPage` methods) need not \"\n\"(exactly) equal the base font name shown here. Reasons for any \"\n\"differences include:\"\nmsgstr \"\"\n\n#: ../../document.rst:1038 9e3187a8049f43a8ab6ba7659956a13b\nmsgid \"\"\n\"This method always shows any subset prefixes (the pattern ``ABCDEF+``), \"\n\"whereas text extractions do not do this by default.\"\nmsgstr \"\"\n\n#: ../../document.rst:1039 0abee5e9efcf4f259b19dbbf3c112ac9\nmsgid \"\"\n\"Text extractions use the base library to access the font name, which has \"\n\"a length cap of 31 bytes and generally interrogates the font file binary \"\n\"to access the name. Method ``get_page_fonts()`` however looks at the PDF \"\n\"definition source.\"\nmsgstr \"\"\n\n#: ../../document.rst:1040 ceff7473261d4ef0af2e8cd13f8a1f2b\nmsgid \"\"\n\"Text extractions work for all supported document types in exactly the \"\n\"same way -- not just for PDFs. Consequently they do not contain PDF-\"\n\"specifics.\"\nmsgstr \"\"\n\n#: ../../document.rst:1044 b8db4c274c904f3e8d043eaf8c4fa329\nmsgid \"\"\n\"Extracts the text of a page given its page number *pno* (zero-based). \"\n\"Invokes :meth:`Page.get_text`.\"\nmsgstr \"ページ番号 *pno* （0から始まる）を指定して、ページのテキストを抽出します。:meth:`Page.get_text` を呼び出します。\"\n\n#: ../../document.rst:1046 ab0bf8a80bdf468dae5fcab8e58d513e\nmsgid \"page number, 0-based, any value `-∞ < pno < page_count`.\"\nmsgstr \"ページ番号、0から始まる、任意の値 `-∞ < pno < page_count`。\"\n\n#: ../../document.rst:1048 27bf81508d0b4d2c934168e49148ac1b\nmsgid \"For other parameter refer to the page method.\"\nmsgstr \"その他のパラメータについては、ページのメソッドを参照してください。\"\n\n#: ../../document.rst:1060 881bca230ae54f04b7233142e165e1fc\nmsgid \"\"\n\"Re-paginate (\\\"reflow\\\") the document based on the given page dimension \"\n\"and fontsize. This only affects some document types like e-books and \"\n\"HTML. Ignored if not supported. Supported documents have ``True`` in \"\n\"property :attr:`is_reflowable`.\"\nmsgstr \"\"\n\"与えられたページの寸法とフォントサイズに基づいて、ドキュメントを再ページ割り（\\\"リフロー\\\"）します。これは電子書籍やHTMLなどの一部のドキュメントタイプにのみ影響します。サポートされていない場合は無視されます。サポートされているドキュメントには\"\n\" :attr:`is_reflowable` プロパティで ``True`` が設定されています。\"\n\n#: ../../document.rst:1062 b4368178fd834f7cba473e3683f57587\nmsgid \"desired page size. Must be finite, not empty and start at point (0, 0).\"\nmsgstr \"望ましいページサイズ。有限で、空でなく、ポイント（0, 0）で始まる必要があります。\"\n\n#: ../../document.rst:1063 ff2a60554e4c4e2a812c93fbdb80be62\n#, fuzzy\nmsgid \"use it together with ``height`` as alternative to ``rect``.\"\nmsgstr \"*rect* との代替として、*height* と一緒に使用します。\"\n\n#: ../../document.rst:1064 0ba8b89ec07f4191990fb69a81e9d18e\n#, fuzzy\nmsgid \"use it together with ``width`` as alternative to ``rect``.\"\nmsgstr \"*rect* との代替として、*width* と一緒に使用します。\"\n\n#: ../../document.rst:1065 9073142bb51c42689875626b7abe5c25\nmsgid \"the desired default fontsize.\"\nmsgstr \"望ましいデフォルトのフォントサイズ。\"\n\n#: ../../document.rst:1069 a01cabf5e69f408980b2a61a12447312\nmsgid \"\"\n\"PDF only: Keeps only those pages of the document whose numbers occur in \"\n\"the list. Empty sequences or elements outside `range(doc.page_count)` \"\n\"will cause a *ValueError*. For more details see remarks at the bottom or \"\n\"this chapter.\"\nmsgstr \"\"\n\"PDFのみ：ドキュメントのページ番号がリストに含まれるページのみ保持します。空のシーケンスまたは範囲外の要素 \"\n\"`range(doc.page_count)` は *ValueError* \"\n\"を引き起こします。詳細については、この章の最後の注釈を参照してください。\"\n\n#: ../../document.rst:1071 b811b2733b5a4543a065fd5bef0c2d19\nmsgid \"\"\n\"The sequence (see :ref:`SequenceTypes`) of page numbers (zero-based) to \"\n\"be included. Pages not in the sequence will be deleted (from memory) and \"\n\"become unavailable until the document is reopened. **Page numbers can \"\n\"occur multiple times and in any order:** the resulting document will \"\n\"reflect the sequence exactly as specified.\"\nmsgstr \"\"\n\"(:ref:`SequenceTypes`) – \"\n\"ページ番号（0から始まる）のシーケンス（PyMuPDFで引数として使用する場合はPythonシーケンスを使用）を含めるためのもの。シーケンス内に含まれていないページは（メモリから）削除され、ドキュメントが再オープンされるまで利用できなくなります。**ページ番号は複数回発生し、任意の順序で発生できます：**\"\n\" 結果のドキュメントは指定された正確なシーケンスを反映します。\"\n\n#: ../../document.rst:1075 a0e792f0e7504785a8c3f46ae77381a0\nmsgid \"\"\n\"Page numbers in the sequence need not be unique nor be in any particular \"\n\"order. This makes the method a versatile utility to e.g. select only the \"\n\"even or the odd pages or meeting some other criteria and so forth.\"\nmsgstr \"シーケンス内のページ番号は一意である必要も、特定の順序である必要もありません。これにより、この方法は、例えば偶数のページだけを選択したり、奇数のページだけを選択したり、その他の基準を満たしたりするなど、多目的に使用できます。\"\n\n#: ../../document.rst:1077 a835fa5157904b5ab455cb2eb91f202c\nmsgid \"\"\n\"On a technical level, the method will always create a new \"\n\":data:`pagetree`.\"\nmsgstr \"技術的なレベルでは、この方法は常に新しい :data:`pagetree` を作成します。\"\n\n#: ../../document.rst:1079 ccc5be5dc4ae4ec0b2ef3ca6f735a437\nmsgid \"\"\n\"When dealing with only a few pages, methods :meth:`copy_page`, \"\n\":meth:`move_page`, :meth:`delete_page` are easier to use. In fact, they \"\n\"are also **much faster** -- by at least one order of magnitude when the \"\n\"document has many pages.\"\nmsgstr \"\"\n\"数ページしか扱わない場合、methods :meth:`copy_page` \"\n\"、:meth:`move_page`、:meth:`delete_page` \"\n\"を使用する方が簡単です。実際、これらの方法は、文書に多くのページがある場合でも、少なくとも1桁のオーダーで **高速です** 。\"\n\n#: ../../document.rst:1084 6ea57c9287dc40f394387af6be79301e\nmsgid \"\"\n\"PDF only: Sets or updates the metadata of the document as specified in \"\n\"*m*, a Python dictionary.\"\nmsgstr \"PDFのみ： *m* で指定されたPythonの辞書と同じキーを持つ辞書を設定または更新します。\"\n\n#: ../../document.rst:1086 8f5fd7f7e37241278a248b6dfdf47633\nmsgid \"\"\n\"A dictionary with the same keys as *metadata* (see below). All keys are \"\n\"optional. A PDF's format and encryption method cannot be set or changed \"\n\"and will be ignored. If any value should not contain data, do not specify\"\n\" its key or set the value to `None`. If you use *{}* all metadata \"\n\"information will be cleared to the string *\\\"none\\\"*. If you want to \"\n\"selectively change only some values, modify a copy of *doc.metadata* and \"\n\"use it as the argument. Arbitrary unicode values are possible if \"\n\"specified as UTF-8-encoded.\"\nmsgstr \"\"\n\"*metadata* \"\n\"（以下参照）と同じキーを持つ辞書。すべてのキーはオプションです。PDFのフォーマットと暗号化方法は設定または変更できないため、無視されます。データを含めないべき値がある場合、そのキーを指定しないか、値を\"\n\" `None` に設定しないでください。*{}* を使用すると、すべてのメタデータ情報が文字列 *\\\"none\\\"* \"\n\"にクリアされます。一部の値のみを選択的に変更したい場合は、*doc.metadata* \"\n\"のコピーを変更して引数として使用してください。UTF-8でエンコードされた場合、任意のUnicode値が指定可能です。\"\n\n#: ../../document.rst:1088 378dd664bfff4b00a333924796f6afa1\nmsgid \"\"\n\"*(Changed in v1.18.4)* Empty values or \\\"none\\\" are no longer written, \"\n\"but completely omitted.\"\nmsgstr \"*（v1.18.4で変更）* 空の値または \\\"none\\\" は書き込まれなくなり、完全に省略されます。\"\n\n#: ../../document.rst:1092 7defc5da9e384a81910c8e57c5c08c9b\nmsgid \"PDF only: Get the document XML metadata.\"\nmsgstr \"PDFのみ：ドキュメントのXMLメタデータを取得します。\"\n\n#: ../../document.rst:1095 022fd903a25f47d892ec5c148aa9731c\nmsgid \"XML metadata of the document. Empty string if not present or not a PDF.\"\nmsgstr \"ドキュメントのXMLメタデータ。存在しない場合やPDFでない場合は空の文字列。\"\n\n#: ../../document.rst:1099 3bc746006bd14cad95bbd71e15614ea4\nmsgid \"PDF only: Sets or updates XML metadata of the document.\"\nmsgstr \"PDFのみ：ドキュメントのXMLメタデータを設定または更新します。\"\n\n#: ../../document.rst:1101 815c87ed354f45afb5034d3fa4df2b7a\nmsgid \"\"\n\"the new XML metadata. Should be XML syntax, however no checking is done \"\n\"by this method and any string is accepted.\"\nmsgstr \"xml（str）–新しいXMLメタデータ。XML構文である必要がありますが、このメソッドではチェックされず、任意の文字列が受け入れられます。\"\n\n#: ../../document.rst:1106 ../../document.rst:1115 ../../document.rst:1124\n#: ../../document.rst:2062 ../../document.rst:2070 ../../document.rst:2078\n#: ../../document.rst:2086 ../../document.rst:2094\n#: 4956c403ef204b3a9535793528deea60 54acf2c9d3094866ada7757386c3c700\n#: 697a878d761047fb8f538a6c5d2b112d 897bf7c435d6499494abe2b762aa7625\n#: d481448871f2481096ebf5ba1c5cd890 e1271d18b89947ae8490b4cecbcc4277\n#: e7a671ebea5446029fd0019bf910f05a fc68fc012f1e4cbcbcf1e4f9c9adbca6\nmsgid \"New in v1.22.2\"\nmsgstr \"v1.22.2で新登場\"\n\n#: ../../document.rst:1108 6095a410473445d68dd1082d0e3598f9\nmsgid \"PDF only: Set the `/PageLayout`.\"\nmsgstr \"PDFのみ：`/PageLayout` を設定します。\"\n\n#: ../../document.rst:1110 b8d4a1a8ad4c46a6bb4dc931bfb281a2\nmsgid \"\"\n\"one of the strings \\\"SinglePage\\\", \\\"OneColumn\\\", \\\"TwoColumnLeft\\\", \"\n\"\\\"TwoColumnRight\\\", \\\"TwoPageLeft\\\", \\\"TwoPageRight\\\". Lower case is \"\n\"supported.\"\nmsgstr \"以下の文字列のいずれか、\\\"SinglePage\\\"、\\\"OneColumn\\\"、\\\"TwoColumnLeft\\\"、\\\"TwoColumnRight\\\"、\\\"TwoPageLeft\\\"、\\\"TwoPageRight\\\"。小文字もサポートされています。\"\n\n#: ../../document.rst:1117 83135c81dcbb41e49d6872b76d675476\nmsgid \"PDF only: Set the `/PageMode`.\"\nmsgstr \"PDFのみ：`/PageMode` を設定します。\"\n\n#: ../../document.rst:1119 361f59248bed437f82de57b9c0cff394\nmsgid \"\"\n\"one of the strings \\\"UseNone\\\", \\\"UseOutlines\\\", \\\"UseThumbs\\\", \"\n\"\\\"FullScreen\\\", \\\"UseOC\\\", \\\"UseAttachments\\\". Lower case is supported.\"\nmsgstr \"以下の文字列のいずれか、\\\"UseNone\\\"、\\\"UseOutlines\\\"、\\\"UseThumbs\\\"、\\\"FullScreen\\\"、\\\"UseOC\\\"、\\\"UseAttachments\\\"。小文字もサポートされています。\"\n\n#: ../../document.rst:1126 484c93332c134d25b3c8e46c7153b12a\nmsgid \"PDF only: Set the `/MarkInfo` values.\"\nmsgstr \"PDFのみ：`/MarkInfo` の値を設定します。\"\n\n#: ../../document.rst:1128 a217e06c6a7c47e1a6fe64aeadf09de5\nmsgid \"\"\n\"a dictionary like this one: `{\\\"Marked\\\": False, \\\"UserProperties\\\": \"\n\"False, \\\"Suspects\\\": False}`. This dictionary contains information about \"\n\"the usage of Tagged PDF conventions. For details please see the `PDF \"\n\"specifications <https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_.\"\nmsgstr \"\"\n\"次のような辞書：`{\\\"Marked\\\": False, \\\"UserProperties\\\": False, \\\"Suspects\\\": \"\n\"False}`。この辞書にはタグ付きPDF規則の使用に関する情報が含まれています。詳細については `PDF仕様 \"\n\"<https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_ を参照してください。\"\n\n#: ../../document.rst:1133 1a3785bb335b40d5b5f05f19d59dc55f\nmsgid \"\"\n\"PDF only: Replaces the **complete current outline** tree (table of \"\n\"contents) with the one provided as the argument. After successful \"\n\"execution, the new outline tree can be accessed as usual via \"\n\":meth:`Document.get_toc` or via :attr:`Document.outline`. Like with other\"\n\" output-oriented methods, changes become permanent only via :meth:`save` \"\n\"(incremental save supported). Internally, this method consists of the \"\n\"following two steps. For a demonstration see example below.\"\nmsgstr \"\"\n\"PDFのみ：提供された引数で **現在のアウトラインツリー（目次）全体** を置き換えます。成功した実行後、新しいアウトラインツリーは通常通り D\"\n\" :meth:`Document.get_toc` または :attr:`Document.outline` \"\n\"を使用してアクセスできます。他の出力指向のメソッドと同様に、変更は :meth:`save` \"\n\"（増分保存対応）を介してのみ永続的になります。内部的には、このメソッドは次の2つのステップで構成されています。デモンストレーションについては以下の例を参照してください。\"\n\n#: ../../document.rst:1135 fab5fac64dd3452580cdcccdd7303f00\nmsgid \"Step 1 deletes all existing bookmarks.\"\nmsgstr \"ステップ1：すべての既存のブックマークを削除します。\"\n\n#: ../../document.rst:1137 3e9734d29cee4dd182cbcc2cfd77a07c\nmsgid \"Step 2 creates a new TOC from the entries contained in *toc*.\"\nmsgstr \"ステップ2：*toc* に含まれるエントリを使用して新しいTOCを作成します。\"\n\n#: ../../document.rst:1139 1e6897bee93b42f48e1da50ac920665c\nmsgid \"\"\n\"A list / tuple with **all bookmark entries** that should form the new \"\n\"table of contents. Output variants of :meth:`get_toc` are acceptable. To \"\n\"completely remove the table of contents specify an empty sequence or \"\n\"None. Each item must be a list with the following format.  * [lvl, title,\"\n\" page [, dest]] where    - **lvl** is the hierarchy level (int > 0) of \"\n\"the item, which **must be 1** for the first item and at most 1 larger \"\n\"than the previous one.    - **title** (str) is the title to be displayed.\"\n\" It is assumed to be UTF-8-encoded (relevant for multibyte code points \"\n\"only).    - **page** (int) is the target page number **(attention: \"\n\"1-based)**. Must be in valid range if positive. Set it to -1 if there is \"\n\"no target, or the target is external.    - **dest** (optional) is a \"\n\"dictionary or a number. If a number, it will be interpreted as the \"\n\"desired height (in points) this entry should point to on the page. Use a \"\n\"dictionary (like the one given as output by `get_toc(False)`) for a \"\n\"detailed control of the bookmark's properties, see \"\n\":meth:`Document.get_toc` for a description.\"\nmsgstr \"\"\n\n#: ../../document.rst:1141 fe3a1323fbad4254982338ebfe8c989f\nmsgid \"\"\n\"A list / tuple with **all bookmark entries** that should form the new \"\n\"table of contents. Output variants of :meth:`get_toc` are acceptable. To \"\n\"completely remove the table of contents specify an empty sequence or \"\n\"None. Each item must be a list with the following format.\"\nmsgstr \"\"\n\"新しい目次を形成するための **すべてのブックマークエントリ** を含むリスト/タプル。:meth:`get_toc` \"\n\"の出力バリエーションが許容されます。目次を完全に削除するには、空のシーケンスまたはNoneを指定してください。各アイテムは、次の形式である必要があります。\"\n\n#: ../../document.rst:1143 85509f224b1249c4b5b63690222e9eb0\nmsgid \"[lvl, title, page [, dest]] where\"\nmsgstr \"[lvl, title, page [, dest]] ここで\"\n\n#: ../../document.rst:1145 690744393f344093958f9ddfa8f135c0\nmsgid \"\"\n\"**lvl** is the hierarchy level (int > 0) of the item, which **must be 1**\"\n\" for the first item and at most 1 larger than the previous one.\"\nmsgstr \"**lvl** はアイテムの階層レベル（int > 0）で、最初のアイテムの場合は1で、前のアイテムより最大1大きくする必要があります。\"\n\n#: ../../document.rst:1147 0e0033a874d3456abc5787e7192d318d\nmsgid \"\"\n\"**title** (str) is the title to be displayed. It is assumed to be \"\n\"UTF-8-encoded (relevant for multibyte code points only).\"\nmsgstr \"\"\n\"**title** \"\n\"（str）は表示されるタイトルです。UTF-8でエンコードされていると仮定されています（マルチバイトコードポイントの場合に関連します）。\"\n\n#: ../../document.rst:1149 4803db27502949be9cae49f68a00c3c4\nmsgid \"\"\n\"**page** (int) is the target page number **(attention: 1-based)**. Must \"\n\"be in valid range if positive. Set it to -1 if there is no target, or the\"\n\" target is external.\"\nmsgstr \"\"\n\"**page**（int）は対象のページ番号です **（注意：1から始まります）** \"\n\"。正の場合、有効な範囲内になければなりません。対象がない場合、または対象が外部の場合は-1に設定します。\"\n\n#: ../../document.rst:1151 de6ec335a2dc463b9619f7d960d55fd8\nmsgid \"\"\n\"**dest** (optional) is a dictionary or a number. If a number, it will be \"\n\"interpreted as the desired height (in points) this entry should point to \"\n\"on the page. Use a dictionary (like the one given as output by \"\n\"`get_toc(False)`) for a detailed control of the bookmark's properties, \"\n\"see :meth:`Document.get_toc` for a description.\"\nmsgstr \"\"\n\"**dest** \"\n\"（オプション）は辞書または数値です。数値の場合、このエントリがページ上で指し示すべき目標の高さ（ポイント単位）と解釈されます。詳細なブックマークのプロパティを制御するには（`get_toc(False)`\"\n\" によって出力されるものと同様の辞書を使用してください）、:meth:`Document.get_toc` の説明を参照してください。\"\n\n#: ../../document.rst:1153 4b2509feab4d42c1896479cb753f319a\nmsgid \"\"\n\"*(new in v1.16.9)* controls the hierarchy level beyond which outline \"\n\"entries should initially show up collapsed. The default 1 will hence only\"\n\" display level 1, higher levels must be unfolded using the PDF viewer. To\"\n\" unfold everything, specify either a large integer, 0 or None.\"\nmsgstr \"\"\n\"*（v1.16.9で新規追加）* \"\n\"アウトラインエントリが初めて折りたたまれて表示される階層レベルを制御します。デフォルトの1はレベル1のみを表示し、より高いレベルはPDFビューアを使用して展開する必要があります。すべてを展開するには、大きな整数、0、またはNoneを指定してください。\"\n\n#: ../../document.rst:1156 2e9ef17d9ad7433caf717d11a0bef04d\nmsgid \"the number of inserted, resp. deleted items.\"\nmsgstr \"挿入されたアイテム、または削除されたアイテムの数。\"\n\n#: ../../document.rst:1158 cc6b2a61bf8745ad9a685a8bdb934307\nmsgid \"\"\n\"Changed in v1.23.8: Destination 'to' coordinates should now be in the \"\n\"same coordinate system as those returned by `get_toc()` (internally they \"\n\"are now transformed with `page.cropbox` and `page.rotation_matrix`). So \"\n\"for example `set_toc(get_toc())` now gives unchanged destination 'to' \"\n\"coordinates.\"\nmsgstr \"\"\n\"1.23.8 で変更されました: デスティネーションの 'to' 座標は、現在 `get_toc()` で返される座標系と同じ座標系であるべきです\"\n\" (内部的には `page.cropbox` と `page.rotation_matrix` で変換されます)。したがって、例えば \"\n\"`set_toc(get_toc())` は、変更されていない 'to' 座標を与えます。\"\n\n#: ../../document.rst:1168 69ead51269304dd6b951d0f68345cb21\nmsgid \"\"\n\"PDF only: Return the :data:`xref` of the outline item. This is mainly \"\n\"used for internal purposes.\"\nmsgstr \"PDFのみ：アウトラインアイテムの :data:`xref` を返します。これは主に内部用途で使用されます。\"\n\n#: ../../document.rst:1170 ac5515f1060a4f2f8cfea8c5de047f36\n#, fuzzy\nmsgid \"index of the item in list :meth:`Document.get_toc`.\"\nmsgstr \":meth:`Document.get_toc` のリスト内のアイテムのインデックス。\"\n\n#: ../../document.rst:1172 968f01ffca3d4358afb5662a933cd835\nmsgid \":data:`xref`.\"\nmsgstr \"\"\n\n#: ../../document.rst:1177 34e33888ad8a4b238bbf919bd98c86cd\nmsgid \"\"\n\"Changed in v1.18.14: no longer remove the item's text, but show it \"\n\"grayed-out.\"\nmsgstr \"v1.18.14で変更: アイテムのテキストを削除しなくなり、灰色で表示されます。\"\n\n#: ../../document.rst:1179 dd42c42f2ed74d9f9c635912f3d908da\nmsgid \"\"\n\"PDF only: Remove this TOC item. This is a high-speed method, which \"\n\"**disables** the respective item, but leaves the overall TOC structure \"\n\"intact. Physically, the item still exists in the TOC tree, but is shown \"\n\"grayed-out and will no longer point to any destination.\"\nmsgstr \"\"\n\"PDFのみ: この目次アイテムを削除します。これは高速なメソッドで、該当するアイテムを **無効にします** \"\n\"が、全体の目次構造はそのままです。物理的には、アイテムはまだ目次ツリーに存在しますが、灰色で表示され、もはやどの宛先も指し示しません。\"\n\n#: ../../document.rst:1181 14518935bf6542a1909828b5acc5bb9d\nmsgid \"\"\n\"This also implies that you can reassign the item to a new destination \"\n\"using :meth:`Document.set_toc_item`, when required.\"\nmsgstr \"\"\n\"これはまた、必要な場合に:meth:`Document.set_toc_item` \"\n\"を使用してアイテムを新しい宛先に再割り当てできることを意味します。\"\n\n#: ../../document.rst:1183 22d9b55991c34bb6b5b50464e9d3ede0\nmsgid \"the index of the item in list :meth:`Document.get_toc`.\"\nmsgstr \":meth:`Document.get_toc` のリスト内のアイテムのインデックス。\"\n\n#: ../../document.rst:1189 f97ad420e8f2448d89a3942f5f4ecdde\nmsgid \"Changed in v1.18.6\"\nmsgstr \"v1.18.6で変更\"\n\n#: ../../document.rst:1191 f37714c941aa4caab4557723d10633c7\nmsgid \"\"\n\"PDF only: Changes the TOC item identified by its index. Change the item \"\n\"**title**, **destination**, **appearance** (color, bold, italic) or \"\n\"collapsing sub-items -- or to remove the item altogether.\"\nmsgstr \"\"\n\"PDFのみ: インデックスによって識別されるTOCアイテムを変更します。アイテムの **タイトル** 、**宛先** 、 **外観** \"\n\"（色、太字、イタリック）を変更したり、サブアイテムを折りたたんだり、アイテムを完全に削除したりするために使用します。\"\n\n#: ../../document.rst:1193 28fc5be05b3a4afa92b7a5f95bbf478b\nmsgid \"\"\n\"Use this method if you need specific changes for selected entries only \"\n\"and want to avoid replacing the complete TOC. This is beneficial \"\n\"especially when dealing with large table of contents.\"\nmsgstr \"選択したエントリに対して特定の変更が必要で、完全なTOCを置き換えたくない場合にこのメソッドを使用します。大きな目次を扱う場合に特に便利です。\"\n\n#: ../../document.rst:1195 288fc512c31544d3be554d8f5cce5cb9\nmsgid \"the index of the entry in the list created by :meth:`Document.get_toc`.\"\nmsgstr \":meth:`Document.get_toc` によって作成されたリスト内のエントリのインデックス。\"\n\n#: ../../document.rst:1196 a16b6cc4ad6a49e496bc2541ff752cfd\nmsgid \"\"\n\"the new destination. A dictionary like the last entry of an item in \"\n\"`doc.get_toc(False)`. Using this as a template is recommended. When \"\n\"given, **all other parameters are ignored** -- except title.\"\nmsgstr \"\"\n\"新しい宛先。`doc.get_toc(False)` のアイテムの最後のエントリのような辞書を使用することが推奨されます。指定された場合、他の \"\n\"**すべてのパラメータは無視されます** - タイトル以外。\"\n\n#: ../../document.rst:1197 8d519eb7f6f84aa586f6894b855ec1b4\nmsgid \"\"\n\"the link kind, see :ref:`linkDest Kinds`. If :data:`LINK_NONE`, then all \"\n\"remaining parameter will be ignored, and the TOC item will be removed -- \"\n\"same as :meth:`Document.del_toc_item`. If None, then only the title is \"\n\"modified and the remaining parameters are ignored. All other values will \"\n\"lead to making a new destination dictionary using the subsequent \"\n\"arguments.\"\nmsgstr \"\"\n\"リンクの種類、:ref:`linkDest Kinds` を参照してください。:data:`LINK_NONE` \"\n\"の場合、残りのパラメータはすべて無視され、TOCアイテムは削除されます - :meth:`Document.del_toc_item` \"\n\"と同じです。Noneの場合、タイトルのみが変更され、残りのパラメータは無視されます。それ以外の値は、後続の引数を使用して新しい宛先辞書を作成します。\"\n\n#: ../../document.rst:1198 23d121f44ba448deb820d78571787db2\nmsgid \"\"\n\"the 1-based page number, i.e. a value 1 <= pno <= doc.page_count. \"\n\"Required for LINK_GOTO.\"\nmsgstr \"1から始まるページ番号、つまり1 <= pno <= doc.page_count。LINK_GOTOの場合に必要です。\"\n\n#: ../../document.rst:1199 32c7c87f9e8e403ab8146f49e7a37529\nmsgid \"the URL text. Required for LINK_URI.\"\nmsgstr \"URLのテキスト。LINK_URIの場合に必要です。\"\n\n#: ../../document.rst:1200 43fcbce5ce9847278bc2628a403f4e40\nmsgid \"the desired new title. None if no change.\"\nmsgstr \"新しいタイトル。変更しない場合はNone。\"\n\n#: ../../document.rst:1201 6840fbdc207c43779b48e2f8df7435b6\nmsgid \"\"\n\"(optional) points to a coordinate on the target page. Relevant for \"\n\"LINK_GOTO. If omitted, a point near the page's top is chosen.\"\nmsgstr \"（オプション）対象ページ上の座標を指定します。LINK_GOTOの場合に関連します。省略された場合、ページの上部近くのポイントが選択されます。\"\n\n#: ../../document.rst:1202 7c940e27b57c48529e5d3e8ff0325a69\nmsgid \"required for LINK_GOTOR and LINK_LAUNCH.\"\nmsgstr \"LINK_GOTORおよびLINK_LAUNCHに必要です。\"\n\n#: ../../document.rst:1203 132587a96eb44d79895a5275d7a58ec9\nmsgid \"use this zoom factor when showing the target page.\"\nmsgstr \"対象ページを表示する際にこのズームファクターを使用します。\"\n\n#: ../../document.rst:1205 51f0afa8fe36446da6457ee40177e6ac\nmsgid \"**Example use:** Change the TOC of the SWIG manual to achieve this:\"\nmsgstr \"**使用例:** SWIGマニュアルのTOCを変更して、次のことを達成します：\"\n\n#: ../../document.rst:1207 89691e2e24d042b7afaa252f2404e728\nmsgid \"\"\n\"Collapse everything below top level and show the chapter on Python \"\n\"support in red, bold and italic::\"\nmsgstr \"トップレベル以下をすべて折りたたみ、Pythonサポートの章を赤色で太字かつイタリックで表示::\"\n\n#: ../../document.rst:1224 cb071d795eef4051859facdf9c2c7f83\nmsgid \"\"\n\"In the previous example, we have changed only 42 of the 1240 TOC items of\"\n\" the file.\"\nmsgstr \"前の例では、ファイルの1240のTOCアイテムのうち、わずか42のみを変更しました。\"\n\n#: ../../document.rst:1228 4b6c6cb7b0cd41fe85e5ecb9dfbff8ec\nmsgid \"\"\n\"PDF only: Convert annotations and / or widgets to become permanent parts \"\n\"of the pages. The PDF **will be changed** by this method. If `widgets` is\"\n\" `True`, the document will also no longer be a \\\"Form PDF\\\".\"\nmsgstr \"\"\n\"PDF のみ: 注釈やウィジェットをページの永続的な部分に変換します。このメソッドによって PDF **は変更されます**。 `widgets` \"\n\"が `True` の場合、ドキュメントは「フォーム PDF」ではなくなります。\"\n\n#: ../../document.rst:1230 b1618c1259c44d298694a1fdd071bea7\nmsgid \"\"\n\"All pages will look the same, but will no longer have annotations, \"\n\"respectively fields. The visible parts will be converted to standard \"\n\"text, vector graphics or images as required.\"\nmsgstr \"すべてのページが同じように見えますが、注釈またはフィールドがなくなります。必要に応じて、表示される部分は標準のテキスト、ベクトルグラフィックス、または画像に変換されます。\"\n\n#: ../../document.rst:1232 4e629c4362f5458dacd2bb2f00dc9a42\nmsgid \"\"\n\"The method may thus be a viable **alternative for PDF-to-PDF \"\n\"conversions** using :meth:`Document.convert_to_pdf`.\"\nmsgstr \"\"\n\"このメソッドは、:meth:`Document.convert_to_pdf` を使用して PDF を PDF \"\n\"に変換する際の代替手段として有効な選択肢です。\"\n\n#: ../../document.rst:1234 eac5b3e2fdae4934a3324c3826cb5be0\nmsgid \"\"\n\"Please consider that annotations are complex objects and may consist of \"\n\"more data \\\"underneath\\\" their visual appearance. Examples are \\\"Text\\\" \"\n\"and \\\"FileAttachment\\\" annotations. When \\\"baking in\\\" annotations / \"\n\"widgets with this method, all this underlying information (attached \"\n\"files, comments, associated PopUp annotations, etc.) will be lost and be \"\n\"removed on next garbage collection.\"\nmsgstr \"\"\n\"注釈は複雑なオブジェクトであり、視覚的な外観の下にさらに多くのデータが存在する場合があります。例としては、\\\"Text\\\" や \"\n\"\\\"FileAttachment\\\" \"\n\"の注釈が挙げられます。このメソッドで注釈やウィジェットを組み込む際には、この下部情報（添付ファイル、コメント、関連するポップアップ注釈など）がすべて失われ、次のガベージコレクション時に削除されます。\"\n\n#: ../../document.rst:1236 8a23bab53bf14c8aa574e2e600474bcd\n#, fuzzy\nmsgid \"\"\n\"Use this feature for instance for :meth:`Page.show_pdf_page` (which \"\n\"supports neither annotations nor widgets) when the source pages should \"\n\"look exactly the same in the target.\"\nmsgstr \"\"\n\"たとえば、 :meth:`Document.insert_pdf` （ウィジェットのコピーをサポートしていない）や \"\n\":meth:`Page.show_pdf_page` \"\n\"（注釈やウィジェットをサポートしていない）などのメソッドで、ソースページがターゲットで完全に同じように見えるようにする場合にこの機能を使用します。\"\n\n#: ../../document.rst:1239 a39cbfa8407c4df6af1eb80d30cb91ff\nmsgid \"convert annotations.\"\nmsgstr \"注釈を変換するかどうか。\"\n\n#: ../../document.rst:1240 45f21baaa61b4e06b77104c6c6735089\nmsgid \"\"\n\"convert fields / widgets. After execution, the document will no longer be\"\n\" a \\\"Form PDF\\\".\"\nmsgstr \"フィールド / ウィジェットを変換します。実行後、ドキュメントはもはや「フォーム PDF」ではありません。\"\n\n#: ../../document.rst:1245 6cddb53c70e64e57b442090c1f2207d2\nmsgid \"New in v1.16.0\"\nmsgstr \"v1.16.0で新規追加\"\n\n#: ../../document.rst:1247 fa1fdbe516594d0d98a0d538a5555317\nmsgid \"\"\n\"Check whether the document can be saved incrementally. Use it to choose \"\n\"the right option without encountering exceptions.\"\nmsgstr \"ドキュメントを増分保存できるかどうかを確認します。例外を発生させずに正しいオプションを選択するために使用します。\"\n\n#: ../../document.rst:1251 34130af2a2be4418bd86e36c3ebe8d5a\nmsgid \"New in v1.16.14\"\nmsgstr \"v1.16.14で新規追加\"\n\n#: ../../document.rst:1253 d9e7b0b6be0e4bb98d2275cf4c18136d\nmsgid \"\"\n\"PDF only: Remove potentially sensitive data from the PDF. This function \"\n\"is inspired by the similar \\\"Sanitize\\\" function in Adobe Acrobat \"\n\"products. The process is configurable by a number of options.\"\nmsgstr \"\"\n\"PDFのみ：PDFから潜在的に機密性の高いデータを削除します。この関数はAdobe \"\n\"Acrobat製品の類似の「Sanitize」機能にインスパイアを受けたものです。プロセスはさまざまなオプションで設定可能です。\"\n\n#: ../../document.rst:1255 122850b369374792b6f0ff12b94fc87b\nmsgid \"Search for 'FileAttachment' annotations and remove the file content.\"\nmsgstr \"'FileAttachment' 注釈を検索してファイルコンテンツを削除します。\"\n\n#: ../../document.rst:1256 e8f4d3ec34634deeb615c44f546d61d3\nmsgid \"\"\n\"Remove any comments from page painting sources. If this option is set to \"\n\"``False``, then this is also done for *hidden_text* and *redactions*.\"\nmsgstr \"\"\n\"ページ描画ソースからコメントを削除します。このオプションが ``False`` に設定されている場合、*hidden_text* と \"\n\"*redactions* に対しても同様の処理が行われます。\"\n\n#: ../../document.rst:1257 6919e0d4f13c46b1ade6ed30abaf7ef7\nmsgid \"Remove embedded files.\"\nmsgstr \"埋め込みファイルを削除します。\"\n\n#: ../../document.rst:1258 7e5564f6654a4449bb1bad2f78316f86\nmsgid \"Remove OCRed text and invisible text [#f7]_.\"\nmsgstr \"OCRedテキストと不可視テキストを削除します [#f7]_。\"\n\n#: ../../document.rst:1259 fd5111edbec040ae8e77d30b21c503a4\nmsgid \"Remove JavaScript sources.\"\nmsgstr \"JavaScriptソースを削除します。\"\n\n#: ../../document.rst:1260 7054ef539ad641c2bf57e166ebbd4952\nmsgid \"Remove PDF standard metadata.\"\nmsgstr \"PDF標準のメタデータを削除します。\"\n\n#: ../../document.rst:1261 8f65baf5ab154d0b992eefec509ce93e\nmsgid \"Apply redaction annotations.\"\nmsgstr \"レダクション注釈を適用します。\"\n\n#: ../../document.rst:1262 f7f0f74a02e9491988b1dc2a0587aaae\nmsgid \"\"\n\"how to handle images if applying redactions. One of 0 (ignore), 1 (blank \"\n\"out overlaps) or 2 (remove).\"\nmsgstr \"レダクションを適用する場合の画像の処理方法。0（無視）、1（オーバーラップをブランク化）、または2（削除）のいずれかです。\"\n\n#: ../../document.rst:1263 a65be763835e4d588b701873d968784e\nmsgid \"Remove all links.\"\nmsgstr \"すべてのリンクを削除します。\"\n\n#: ../../document.rst:1264 9931675e2d0040f7a193eb79f2ee2884\nmsgid \"Reset all form fields to their defaults.\"\nmsgstr \"すべてのフォームフィールドをデフォルトにリセットします。\"\n\n#: ../../document.rst:1265 5f0d45da4d9f4c71b72ef46e91b342fd\nmsgid \"Remove all responses from all annotations.\"\nmsgstr \"すべての注釈からすべての応答を削除します。\"\n\n#: ../../document.rst:1266 3253836eaaec4b2ca87df3b3b95f015a\nmsgid \"Remove thumbnail images from pages.\"\nmsgstr \"ページからサムネイル画像を削除します。\"\n\n#: ../../document.rst:1267 73179141037a4f01b4e064b767ebb9a8\nmsgid \"Remove XML metadata.\"\nmsgstr \"XMLメタデータを削除します。\"\n\n#: ../../document.rst:1272 ../../document.rst:1349\n#: 46784658632a419388980eb13c1041a1 da6e920ba12d438988b9655f9fac67c5\nmsgid \"Changed in v1.18.7\"\nmsgstr \"v1.18.7で変更\"\n\n#: ../../document.rst:1273 ../../document.rst:1350\n#: 12262e65b5664f109f47051864977083 56c375b6fe6a4791bf227b919ad7e097\nmsgid \"Changed in v1.19.0\"\nmsgstr \"v1.19.0で変更\"\n\n#: ../../document.rst:1274 ../../document.rst:1351\n#: 5260dc902fd9499b8410a0aaa18efdd9 b9acb7ade9fc4b05939e79ad1d0d7a94\n#, fuzzy\nmsgid \"Changed in v1.24.1\"\nmsgstr \"v1.14.12で変更\"\n\n#: ../../document.rst:1276 bc516f2e012c4878bd37006c7e9e88b0\nmsgid \"PDF only: Saves the document in its **current state**.\"\nmsgstr \"PDFのみ：ドキュメントの **現在の状態** を保存します。\"\n\n#: ../../document.rst:1278 ce7de6ce58a34138ace194aa363ea3c0\nmsgid \"\"\n\"The file path, `pathlib.Path` or file object to save to. A file object \"\n\"must have been created before via `open(...)` or `io.BytesIO()`. Choosing\"\n\" `io.BytesIO()` is similar to :meth:`Document.tobytes` below, which \"\n\"equals the `getvalue()` output of an internally created `io.BytesIO()`.\"\nmsgstr \"\"\n\"保存先のファイルパス、`pathlib.Path` 、またはファイルオブジェクト。ファイルオブジェクトは `open(...)` または \"\n\"`io.BytesIO()` を介して事前に作成されている必要があります。`io.BytesIO()` を選択することは、以下の \"\n\":meth:`Document.tobytes` と同等で、内部で作成された `io.BytesIO()` の `getvalue()` \"\n\"出力に等しいです。\"\n\n#: ../../document.rst:1280 aa801ed2c60e4edc9a6b9a636ce2c7ce\nmsgid \"\"\n\"Do garbage collection. Positive values exclude \\\"incremental\\\".  * 0 = \"\n\"none * 1 = remove unused (unreferenced) objects. * 2 = in addition to 1, \"\n\"compact the :data:`xref` table. * 3 = in addition to 2, merge duplicate \"\n\"objects. * 4 = in addition to 3, check :data:`stream` objects for \"\n\"duplication. This may be slow because such data are typically large.\"\nmsgstr \"\"\n\n#: ../../document.rst:1280 98a9fdc676634ec3b02acc9b22deea8a\nmsgid \"Do garbage collection. Positive values exclude \\\"incremental\\\".\"\nmsgstr \"ガベージコレクションを実行します。正の値は「増分」を除外します。\"\n\n#: ../../document.rst:1282 ../../document.rst:1300\n#: 01264ad0b1f348908fb979dacacd82dd a59c0bd122c043e99f85c56dbb619e23\nmsgid \"0 = none\"\nmsgstr \"0 = なし\"\n\n#: ../../document.rst:1283 c584c994c62c47b6bb2d9c9eec495a25\nmsgid \"1 = remove unused (unreferenced) objects.\"\nmsgstr \"1 = 未使用（参照されていない）オブジェクトを削除します。\"\n\n#: ../../document.rst:1284 90892bbc3ba948e49451a75bd88e5ec1\nmsgid \"2 = in addition to 1, compact the :data:`xref` table.\"\nmsgstr \"2 = 1に加えて、:data:`xref` テーブルを最適化します。\"\n\n#: ../../document.rst:1285 441ba00255e545c58a3c0873eb9b5b75\nmsgid \"3 = in addition to 2, merge duplicate objects.\"\nmsgstr \"3 = 2に加えて、重複したオブジェクトを統合します。\"\n\n#: ../../document.rst:1286 da68f0ef05be4518b693fe96dcf63799\nmsgid \"\"\n\"4 = in addition to 3, check :data:`stream` objects for duplication. This \"\n\"may be slow because such data are typically large.\"\nmsgstr \"4 = 3に加えて、ストリームオブジェクトの重複をチェックします。これは、そのようなデータが通常大きいため、遅い場合があります。\"\n\n#: ../../document.rst:1288 87ab7b3d94364600a46fd3583338cf33\nmsgid \"\"\n\"Clean and sanitize content streams [#f1]_. Corresponds to \\\"mutool clean \"\n\"-sc\\\".\"\nmsgstr \"コンテンツストリームをクリーンアップおよびサニタイズします [#f1]_。これは「mutool clean -sc」に対応します。\"\n\n#: ../../document.rst:1290 307368cf4bae4dd3a31a1c6dba695999\nmsgid \"Deflate (compress) uncompressed streams.\"\nmsgstr \"未圧縮のストリームをデフレート（圧縮）します。\"\n\n#: ../../document.rst:1291 074aa683f32949a09fd3b5218932b9d2\nmsgid \"*(new in v1.18.3)* Deflate (compress) uncompressed image streams [#f4]_.\"\nmsgstr \"*（v1.18.3で新規追加）* 未圧縮の画像ストリームをデフレート（圧縮）します [#f4]_。\"\n\n#: ../../document.rst:1292 f47d59f8289a4a0b8f6227e131941c9e\nmsgid \"\"\n\"*(new in v1.18.3)* Deflate (compress) uncompressed fontfile streams \"\n\"[#f4]_.\"\nmsgstr \"（v1.18.3で新規追加）未圧縮のフォントファイルストリームをデフレート（圧縮）します [#f4]_。\"\n\n#: ../../document.rst:1294 98dd2b4baaf142159a443d2deb715b9b\nmsgid \"\"\n\"Only save changes to the PDF. Excludes \\\"garbage\\\" and \\\"linear\\\". Can \"\n\"only be used if *outfile* is a string or a `pathlib.Path` and equal to \"\n\":attr:`Document.name`. Cannot be used for files that are decrypted or \"\n\"repaired and also in some other cases. To be sure, check \"\n\":meth:`Document.can_save_incrementally`. If this is false, saving to a \"\n\"new file is required.\"\nmsgstr \"\"\n\"PDFへの変更を保存します。 \\\"garbage\\\" および \\\"linear\\\" を除外します。*outfile* が文字列または \"\n\"`pathlib.Path` であり、:attr:`Document.name` \"\n\"に等しい場合にのみ使用できます。復号化または修復されたファイルおよび一部の他の場合には使用できません。確実にするために、:meth:`Document.can_save_incrementally`\"\n\" を確認してください。これがFalseの場合、新しいファイルに保存する必要があります。\"\n\n#: ../../document.rst:1296 b7d42cf66e264b78b3aaa3cee4468fa6\nmsgid \"convert binary data to ASCII.\"\nmsgstr \"バイナリデータをASCIIに変換します。\"\n\n#: ../../document.rst:1298 005ca024523d404887a1514b77c99675\nmsgid \"\"\n\"Decompress objects. Generates versions that can be better read by some \"\n\"other programs and will lead to larger files.  * 0 = none * 1 = images * \"\n\"2 = fonts * 255 = all\"\nmsgstr \"\"\n\n#: ../../document.rst:1298 2bb773df27374e8880b5a9762601b294\nmsgid \"\"\n\"Decompress objects. Generates versions that can be better read by some \"\n\"other programs and will lead to larger files.\"\nmsgstr \"オブジェクトを展開します。他のプログラムにより読みやすいバージョンを生成し、ファイルサイズが大きくなります。\"\n\n#: ../../document.rst:1301 4c34dc68468f45819bd8a5140a26fc7d\nmsgid \"1 = images\"\nmsgstr \"1 = 画像\"\n\n#: ../../document.rst:1302 9b54dc5c6dee40a8ac7fda271235a869\nmsgid \"2 = fonts\"\nmsgstr \"2 = フォント\"\n\n#: ../../document.rst:1303 7559171a73a04f818f09a84c49f541b8\nmsgid \"255 = all\"\nmsgstr \"255 = すべて\"\n\n#: ../../document.rst:1305 4b275a55b310440cbc6bed0da1fcc137\n#, fuzzy\nmsgid \"\"\n\"Save a linearised version of the document. This option creates a file \"\n\"format for improved performance for Internet access. Excludes \"\n\"\\\"incremental\\\" and \\\"use_objstms\\\".\"\nmsgstr \"\"\n\"ドキュメントの線形バージョンを保存します。このオプションは、インターネットアクセスのパフォーマンス向上のためのファイル形式を作成します。 \"\n\"\\\"増分\\\" を除外します。\"\n\n#: ../../document.rst:1307 8d34e1be34a6456583de08a964b06ffe\nmsgid \"\"\n\"Prettify the document source for better readability. PDF objects will be \"\n\"reformatted to look like the default output of \"\n\":meth:`Document.xref_object`.\"\nmsgstr \"\"\n\"ドキュメントソースを見やすく整形します。PDFオブジェクトは、:meth:`Document.xref_object` \"\n\"のデフォルト出力のように再フォーマットされます。\"\n\n#: ../../document.rst:1309 6c8fa6521582483489eafa899e3a7b5e\nmsgid \"\"\n\"Suppress the update of the file's `/ID` field. If the file happens to \"\n\"have no such field at all, also suppress creation of a new one. Default \"\n\"is `False`, so every save will lead to an updated file identification.\"\nmsgstr \"\"\n\"ファイルの `/ID` フィールドの更新を抑制します。 \"\n\"ファイルにそのようなフィールドがまったくない場合、新しいフィールドの作成も抑制します。デフォルトは `False` \"\n\"で、各保存でファイル識別情報が更新されます。\"\n\n#: ../../document.rst:1311 2abbbdfe20de45a989cb6206cb2a676c\nmsgid \"\"\n\"*(new in v1.16.0)* Set the desired permission levels. See \"\n\":ref:`PermissionCodes` for possible values. Default is granting all.\"\nmsgstr \"\"\n\"（v1.16.0で新規追加）希望の権限レベルを設定します。可能な値については :ref:`PermissionCodes` \"\n\"を参照してください。デフォルトはすべてを許可します。\"\n\n#: ../../document.rst:1313 8026bd5ba1c04716af36a27cfb56c0f3\nmsgid \"\"\n\"*(new in v1.16.0)* set the desired encryption method. See \"\n\":ref:`EncryptionMethods` for possible values.\"\nmsgstr \"\"\n\"*（v1.16.0で新規追加）* 希望の暗号化メソッドを設定します。可能な値については :ref:`EncryptionMethods` \"\n\"を参照してください。\"\n\n#: ../../document.rst:1315 973dde478560485086c44526497bacd5\nmsgid \"\"\n\"*(new in v1.16.0)* set the document's owner password. *(Changed in \"\n\"v1.18.3)* If not provided, the user password is taken if provided. The \"\n\"string length must not exceed 40 characters.\"\nmsgstr \"\"\n\"*（v1.16.0で新規追加）* ドキュメントの所有者パスワードを設定します。 (v1.18.3で変更) \"\n\"指定しない場合、ユーザーパスワードが提供された場合にユーザーパスワードが使用されます。文字列の長さは40文字を超えてはいけません。\"\n\n#: ../../document.rst:1317 3c2c2b927a9448bfb0a16d0db2c915e4\nmsgid \"\"\n\"*(new in v1.16.0)* set the document's user password. The string length \"\n\"must not exceed 40 characters.\"\nmsgstr \"（v1.16.0で新規追加）ドキュメントのユーザーパスワードを設定します。文字列の長さは40文字を超えてはいけません。\"\n\n#: ../../document.rst:1319 7fee682328a94e6288a75978a7630ce1\nmsgid \"\"\n\"*(new in v1.24.0)* compression option that converts eligible PDF object \"\n\"definitions to information that is stored in some other object's \"\n\":data:`stream` data. Depending on the `deflate` parameter value, the \"\n\"converted object definitions will be compressed -- which can lead to very\"\n\" significant file size reductions.\"\nmsgstr \"\"\n\"*（v1.24.0で新機能）* 可変化PDFオブジェクト定義を他のオブジェクトの :data:`stream`  \"\n\"データに格納される情報に変換する圧縮オプションです。`deflate` \"\n\"パラメータの値に応じて、変換されたオブジェクト定義が圧縮されます。これにより、ファイルサイズが非常に大幅に削減される可能性があります。\"\n\n#: ../../document.rst:1321 8ffaa1fceb4f4e34a5b8891e046c1ee3\nmsgid \"\"\n\"The method does not check, whether a file of that name already exists, \"\n\"will hence not ask for confirmation, and overwrite the file. It is your \"\n\"responsibility as a programmer to handle this.\"\nmsgstr \"このメソッドは、その名前のファイルがすでに存在するかどうかをチェックしません。したがって、確認を求めずにファイルを上書きします。これについては、プログラマーとしての責任があります。\"\n\n#: ../../document.rst:1325 be3ee913b5004b3d9517106841ba688a\nmsgid \"**File size reduction**\"\nmsgstr \"**ファイルサイズの削減**\"\n\n#: ../../document.rst:1327 1bf790168b284a5d9aaaf7d91cc13bbc\n#, fuzzy\nmsgid \"\"\n\"1. Use the save options like `garbage=3|4, deflate=True, \"\n\"use_objstms=True|1`. Do not touch the default values `expand=False|0, \"\n\"clean=False|0, incremental=False|0, linear=False|0`. This is a \"\n\"\\\"lossless\\\" file size reduction. There is a convenience version of this \"\n\"method with these values set by default, :meth:`Document.ez_save` -- \"\n\"please see below.\"\nmsgstr \"\"\n\"オプションとして、`garbage=3|4, deflate=True, use_objstms=True|1`. \"\n\"デフォルト値に触れないでください。 `expand=False|0, clean=False|0, incremental=False|0` \"\n\"は変更しないでください。これは「非破壊的」なファイルサイズの削減です。これらの値がデフォルトで設定されたメソッドの簡易版もあります。 \"\n\":meth:`Document.ez_save()` をご覧ください。\"\n\n#: ../../document.rst:1330 3d1ee9059bd24a83a6aaae8687200458\nmsgid \"\"\n\"\\\"Lossy\\\" file size reduction in essence must give up something with \"\n\"respect to images, like (a) remove all images (b) replace images by their\"\n\" grayscale versions (c) reduce image resolutions. Find examples in the \"\n\"`PyMuPDF Utilities \\\"replace-image\\\" folder <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/examples/replace-image>`_.\"\nmsgstr \"\"\n\"本質的に「損失のある」ファイルサイズの削減は、画像に関して何かを犠牲にする必要があります。例えば、(a) すべての画像を削除する、(b) \"\n\"画像をグレースケールに置換する、(c) 画像の解像度を低下させるなどの方法があります。`PyMuPDF Utilities \\\"replace-\"\n\"image\\\" folder <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/examples/replace-image>`_ に例があります。\"\n\n#: ../../document.rst:1334 805878d8902f44539b76f7fba424c58d\nmsgid \"New in v1.18.11\"\nmsgstr \"v1.18.11で新規追加\"\n\n#: ../../document.rst:1336 fb2bc3ab13bc4cbdb9cdeedc4a300457\nmsgid \"\"\n\"PDF only: The same as :meth:`Document.save` but with changed defaults \"\n\"`deflate=True, garbage=3, use_objstms=1`.\"\nmsgstr \"\"\n\"PDFのみ：:meth:`Document.save` と同じですが、デフォルト値が `deflate=True, garbage=3, \"\n\"use_objstms=1` に変更されています。\"\n\n#: ../../document.rst:1340 4ca43c0eb0764d4d86c7783d00292313\n#, fuzzy\nmsgid \"\"\n\"PDF only: saves the document incrementally. This is a convenience \"\n\"abbreviation for ``doc.save(doc.name, incremental=True, \"\n\"encryption=PDF_ENCRYPT_KEEP)``.\"\nmsgstr \"\"\n\"PDFのみ：ドキュメントを増分的に保存します。これは、 *doc.save(doc.name, incremental=True, \"\n\"encryption=PDF_ENCRYPT_KEEP)* の簡略表記です。\"\n\n#: ../../document.rst:1344 3722cd78e2724185aa38db282136d51f\nmsgid \"\"\n\"Saving incrementally may be required if the document contains verified \"\n\"signatures which would be invalidated by saving to a new file.\"\nmsgstr \"増分保存が必要な場合、ドキュメントに確認済みの署名が含まれている場合、新しいファイルに保存することによって無効になる可能性があります。\"\n\n#: ../../document.rst:1353 abab584e13af432a87536b0dd1525b25\nmsgid \"\"\n\"PDF only: Writes the **current content of the document** to a bytes \"\n\"object instead of to a file. Obviously, you should be wary about memory \"\n\"requirements. The meanings of the parameters exactly equal those in \"\n\":meth:`save`. Chapter :ref:`FAQ` contains an example for using this \"\n\"method as a pre-processor to `pdfrw \"\n\"<https://pypi.python.org/pypi/pdfrw/0.3>`_.\"\nmsgstr \"\"\n\"PDFのみ： **ドキュメントの現在のコンテンツ** \"\n\"をファイルではなくバイトオブジェクトに書き込みます。明らかに、メモリ要件に注意する必要があります。パラメータの意味は :meth:`save` \"\n\"とまったく同じです。チャプター :ref:`FAQ` には、このメソッドを `pdfrw \"\n\"<https://pypi.python.org/pypi/pdfrw/0.3>`_ の前処理として使用する例が含まれています。\"\n\n#: ../../document.rst:1355 0d08d4531d0547afa8dd2711eb5fb49a\nmsgid \"*(Changed in v1.16.0)* for extended encryption support.\"\nmsgstr \"*(v1.16.0で変更)* 拡張暗号サポート用。\"\n\n#: ../../document.rst:1358 6de0cf28802e42058ca66973d5ee0b8c\nmsgid \"a bytes object containing the complete document.\"\nmsgstr \"ドキュメント全体を含むbytesオブジェクト。\"\n\n#: ../../document.rst:1362 0274353b276b45c697447eefc6c5af10\nmsgid \"\"\n\"Search for \\\"text\\\" on page number \\\"pno\\\". Works exactly like the \"\n\"corresponding :meth:`Page.search_for`. Any integer `-∞ < pno < \"\n\"page_count` is acceptable.\"\nmsgstr \"\"\n\"\\\"pno\\\" ページ上で  \\\"text\\\" を検索します。対応する :meth:`Page.search_for` \"\n\"とまったく同じ方法で機能します。整数 `-∞ < pno < page_count` ならどのような値でも受け入れられます。\"\n\n#: ../../document.rst:1380 8f33a8224c6b4cd698ee597a13d325b1\n#, fuzzy\nmsgid \"\"\n\"PDF only: Copy the page range **[from_page, to_page]** (including both) \"\n\"of PDF document *docsrc* into the current one. Inserts will start with \"\n\"page number *start_at*. Value -1 indicates default values. All pages thus\"\n\" copied will be rotated as specified. Links, annotations and widgets can \"\n\"be excluded in the target, see below. All page numbers are 0-based.\"\nmsgstr \"\"\n\"PDFのみ：PDFドキュメント *docsrc* のページ範囲 **[from_page、to_page]** \"\n\"（両方を含む）を現在のドキュメントにコピーします。挿入はページ番号 *start_at* \"\n\"から開始します。値-1はデフォルト値を示します。したがって、コピーされるすべてのページは指定されたように回転します。リンクと注釈は対象から除外することができます（以下参照）。すべてのページ番号は0から始まります。\"\n\n#: ../../document.rst:1382 5c1428d40caa43a5a10f4b77f20b3e69\nmsgid \"\"\n\"An opened PDF *Document* which must not be the current document. However,\"\n\" it may refer to the same underlying file.\"\nmsgstr \"現在のドキュメントではない、開かれたPDF *ドキュメント* 。ただし、同じ基盤ファイルを参照する場合があります。\"\n\n#: ../../document.rst:1385 07b6f53e82724a5ab67dd0b79067fa1e\nmsgid \"First page number in *docsrc*. Default is zero.\"\nmsgstr \"*docsrc* 内の最初のページ番号。デフォルトはゼロです。\"\n\n#: ../../document.rst:1387 fea37107f5404d54996345114e37441b\nmsgid \"Last page number in *docsrc* to copy. Defaults to last page.\"\nmsgstr \"コピーする *docsrc* 内の最後のページ番号。デフォルトは最終ページです。\"\n\n#: ../../document.rst:1389 524d0fb0b9814e21962ad50b5f471743\nmsgid \"\"\n\"First copied page, will become page number *start_at* in the target. \"\n\"Default -1 appends the page range to the end. If zero, the page range \"\n\"will be inserted before current first page.\"\nmsgstr \"\"\n\"コピーされる最初のページ、対象のページ番号 *start_at* \"\n\"になります。デフォルト-1はページ範囲を末尾に追加します。ゼロの場合、ページ範囲は現在の最初のページの前に挿入されます。\"\n\n#: ../../document.rst:1391 4c91282a041f4252be3ddf0b31888ef6\nmsgid \"\"\n\"All copied pages will be rotated by the provided value (degrees, integer \"\n\"multiple of 90).\"\nmsgstr \"コピーされるすべてのページは、指定された値（度数、90の整数倍）で回転します。\"\n\n#: ../../document.rst:1393 d336910ac6904a34ad264c74f9a12eb0\nmsgid \"\"\n\"Choose whether (internal and external) links should be included in the \"\n\"copy. Default is `True`. *Named* links (:data:`LINK_NAMED`) and internal \"\n\"links to outside the copied page range are **always excluded**.\"\nmsgstr \"\"\n\"(内部および外部) リンクをコピーに含めるかどうかを選択します。デフォルトは ``True`` です。コピー対象外のコピー範囲外の内部リンクは \"\n\"**常に除外されます** 。\"\n\n#: ../../document.rst:1395 a02aff5f97f748429af6f525e52152d3\n#, fuzzy\nmsgid \"choose whether annotations should be included in the copy.\"\nmsgstr \"*(v1.16.1で新規追加)* 注釈をコピーに含めるかどうかを選択します。 フォームフィールドはコピーできません。\"\n\n#: ../../document.rst:1397 b94bf24da9974674ace2e3acc4991939\nmsgid \"\"\n\"choose whether annotations should be included in the copy. If `True` and \"\n\"at least one of the source pages contains form fields, the target PDF \"\n\"will be turned into a Form PDF (if not already being one).\"\nmsgstr \"\"\n\n#: ../../document.rst:1399 291ec7b0d4b64883aba67c7050c566bf\nmsgid \"\"\n\"*(New in version 1.25.5)* Choose how to handle duplicate root field names\"\n\" in the source pages. This parameter is ignored if `widgets=False`.  \"\n\"Default is ``False`` which will add unifying strings to the name of those\"\n\" source root fields which have a duplicate in the target. For instance, \"\n\"if \\\"name\\\" already occurs in the target, the source widget's name will \"\n\"be changed to \\\"name [text]\\\" with a suitably chosen string \\\"text\\\".  If\"\n\" ``True``, root fields with duplicate names in source and target will be \"\n\"converted to so-called \\\"Kids\\\" of a \\\"Parent\\\" object (which lists all \"\n\"kid widgets in a PDF array). This will effectively turn those kids into \"\n\"instances of the \\\"same\\\" widget: if e.g. one of the kids is changed, \"\n\"then all its instances will automatically inherit this change -- no \"\n\"matter on which page they happen to be displayed.\"\nmsgstr \"\"\n\n#: ../../document.rst:1399 78659c3b81a3457a9ea0a009a43d5632\nmsgid \"\"\n\"*(New in version 1.25.5)* Choose how to handle duplicate root field names\"\n\" in the source pages. This parameter is ignored if `widgets=False`.\"\nmsgstr \"\"\n\n#: ../../document.rst:1401 690ea9568fba4c748332acfea9bf268d\nmsgid \"\"\n\"Default is ``False`` which will add unifying strings to the name of those\"\n\" source root fields which have a duplicate in the target. For instance, \"\n\"if \\\"name\\\" already occurs in the target, the source widget's name will \"\n\"be changed to \\\"name [text]\\\" with a suitably chosen string \\\"text\\\".\"\nmsgstr \"\"\n\n#: ../../document.rst:1403 207b76f69b4b43b8abf32aaed907a586\nmsgid \"\"\n\"If ``True``, root fields with duplicate names in source and target will \"\n\"be converted to so-called \\\"Kids\\\" of a \\\"Parent\\\" object (which lists \"\n\"all kid widgets in a PDF array). This will effectively turn those kids \"\n\"into instances of the \\\"same\\\" widget: if e.g. one of the kids is \"\n\"changed, then all its instances will automatically inherit this change --\"\n\" no matter on which page they happen to be displayed.\"\nmsgstr \"\"\n\n#: ../../document.rst:1405 8d9fefec8ad44d23b3c63e2ae6a7a00f\nmsgid \"\"\n\"*(new in v1.17.7)* specify an interval size greater zero to see progress \"\n\"messages on `sys.stdout`. After each interval, a message like `Inserted \"\n\"30 of 47 pages.` will be printed.\"\nmsgstr \"\"\n\"*(v1.17.7で新規追加)* `sys.stdout` \"\n\"で進捗メッセージを表示するための大きなゼロより大きい間隔を指定します。各間隔後、`Inserted 30 of 47 pages.` \"\n\"のようなメッセージが印刷されます。\"\n\n#: ../../document.rst:1407 d77922d1b37a405687f51453c41a5a42\nmsgid \"\"\n\"*(new in v1.18.0)* controls whether the list of already copied objects \"\n\"should be **dropped** after this method, default ``True``. Set it to 0 \"\n\"except for the last one of multiple insertions from the same source PDF. \"\n\"This saves target file size and speeds up execution considerably.\"\nmsgstr \"\"\n\"*(v1.18.0で新規追加)* このメソッドの後にすでにコピーされたオブジェクトのリストを **削除する** かどうかを制御します。デフォルトは\"\n\" ``True`` \"\n\"です。同じソースPDFからの複数の挿入の最後以外は、0に設定します。これにより、対象ファイルのサイズが節約され、実行が大幅に高速化されます。\"\n\n#: ../../document.rst:1411 56b4354a86094489a6bf9bde208dc994\nmsgid \"\"\n\"This is a page-based method. Document-level information of source \"\n\"documents is therefore mostly ignored. Examples include Optional Content,\"\n\" Embedded Files, `StructureElem`, table of contents, page labels, \"\n\"metadata, named destinations (and other named entries) and some more.\"\nmsgstr \"\"\n\n#: ../../document.rst:1413 5a07fe3f9eea4d2fae962abdd3b1a7ff\nmsgid \"\"\n\"If `from_page > to_page`, pages will be **copied in reverse order**. If \"\n\"`0 <= from_page == to_page`, then one page will be copied.\"\nmsgstr \"\"\n\"`from_page > to_page` の場合、ページは **逆の順序でコピーされます** 。`0 <= from_page == \"\n\"to_page`  の場合、1ページがコピーされます。\"\n\n#: ../../document.rst:1415 dc1395aabeda4fbcabbf2f13c6749c77\nmsgid \"\"\n\"`docsrc` TOC entries **will not be copied**. It is easy however, to \"\n\"recover a table of contents for the resulting document. Look at the \"\n\"examples below and at program `join.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py>`_ in the \"\n\"*examples* directory: it can join PDF documents and at the same time \"\n\"piece together respective parts of the tables of contents.\"\nmsgstr \"\"\n\"*docsrc* のTOCエントリは **コピーされません** \"\n\"。ただし、結果のドキュメントの目次を復元することは簡単です。以下の例と、*examples* ディレクトリのプログラム `join.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/join-\"\n\"documents/join.py>`_ \"\n\"を参照してください：これはPDFドキュメントを結合し、同時に対応する目次の部分を組み立てることができます。\"\n\n#: ../../document.rst:1432 45174efe8b574e39bd0fee7fda1c588a\nmsgid \"New in v1.22.0\"\nmsgstr \"v1.22.0で新規追加\"\n\n#: ../../document.rst:1434 cd44330e994a49b99c61e25595eb7c0b\nmsgid \"\"\n\"PDF only: Add an arbitrary supported document to the current PDF. Opens \"\n\"\\\"infile\\\" as a document, converts it to a PDF and then invokes \"\n\":meth:`Document.insert_pdf`. Parameters are the same as for that method. \"\n\"Among other things, this features an easy way to append images as full \"\n\"pages to an output PDF.\"\nmsgstr \"\"\n\"PDFのみ：任意のサポートされているドキュメントを現在のPDFに追加します。 \\\"infile\\\" \"\n\"をドキュメントとして開き、PDFに変換し、:meth:`Document.insert_pdf` \"\n\"を呼び出します。パラメータはそのメソッドと同じです。他のことの中で、これには画像を出力PDFに完全なページとして追加する簡単な方法が含まれています。\"\n\n#: ../../document.rst:1436 e33a6fdc9cda41afbf2acefddf2174a3\nmsgid \"\"\n\"the input document to insert. May be a filename specification as is valid\"\n\" for creating a :ref:`Document` or a :ref:`Pixmap`.\"\nmsgstr \"\"\n\"挿入する入力ドキュメント。:ref:`Document` を作成する際に有効なファイル名の指定または :ref:`Pixmap` \"\n\"である可能性があります。\"\n\n#: ../../document.rst:1445 43f27667e5fa455e8b6be14bbed94320\nmsgid \"PDF only: Insert an empty page.\"\nmsgstr \"PDFのみ：空のページを挿入します。\"\n\n#: ../../document.rst:1447 760c94fa936d413985a6348d9a97a2fa\n#, fuzzy\nmsgid \"\"\n\"page number index (zero-indexed) at which to insert page. Special values \"\n\"-1 and *doc.page_count* insert **after** the last page.\"\nmsgstr \"\"\n\"新しいページを挿入する前のページ番号。`1 < pno <= page_count` である必要があります。特別な値-1および \"\n\"*doc.page_count* は最後のページの後に挿入します。\"\n\n#: ../../document.rst:1449 9c2a0e62a39a43d19cf8bc37207291e7\nmsgid \"page width.\"\nmsgstr \"ページの幅。\"\n\n#: ../../document.rst:1450 4a2e0f95cd75496fb7ca0aa473e0434a\nmsgid \"page height.\"\nmsgstr \"ページの高さ。\"\n\n#: ../../document.rst:1453 0bd2d3396b664c20a387f310baf3c618\nmsgid \"\"\n\"the created page object. Be aware that the page numbers of pages after \"\n\"the inserted one will have changed after method execution. For the same \"\n\"reason, **all existing page objects will be invalidated.** Using them \"\n\"will lead to exceptions.\"\nmsgstr \"\"\n\n#: ../../document.rst:1465 e582e4a0e898429a8087c9237aea9caf\nmsgid \"\"\n\"PDF only: Insert a new page and insert some text. Convenience function \"\n\"which combines :meth:`Document.new_page` and (parts of) \"\n\":meth:`Page.insert_text`.\"\nmsgstr \"\"\n\"PDFのみ：新しいページを挿入し、テキストを挿入します。:meth:`Document.new_page` と \"\n\":meth:`Page.insert_text` の一部を組み合わせた便利な関数です。\"\n\n#: ../../document.rst:1467 05fc5d62cf1442ef87870b03bf4656e6\n#, fuzzy\nmsgid \"\"\n\"page number index (zero-indexed) at which to insert page. Special values \"\n\"-1 and `doc.page_count` insert **after** the last page.  Changed in \"\n\"v1.14.12    This is now a positional parameter\"\nmsgstr \"\"\n\"**挿入する前** のページ番号（0ベース）を指定します。範囲 `range(-1, doc.page_count + 1)` \"\n\"内である必要があります。特別な値-1および `doc.page_count` は最後のページの **後** に挿入します。\"\n\n#: ../../document.rst:1467 93c42f35dfc74d969baf39f16e854b2c\n#, fuzzy\nmsgid \"\"\n\"page number index (zero-indexed) at which to insert page. Special values \"\n\"-1 and `doc.page_count` insert **after** the last page.\"\nmsgstr \"\"\n\"**挿入する前** のページ番号（0ベース）を指定します。範囲 `range(-1, doc.page_count + 1)` \"\n\"内である必要があります。特別な値-1および `doc.page_count` は最後のページの **後** に挿入します。\"\n\n#: ../../document.rst:1470 b97cd8599f7b49db97a3779b3b40e27a\nmsgid \"Changed in v1.14.12\"\nmsgstr \"v1.14.12で変更\"\n\n#: ../../document.rst:1470 f6d15d624bcd4485930085e83cc129ac\nmsgid \"This is now a positional parameter\"\nmsgstr \"これは今ポジションパラメータです\"\n\n#: ../../document.rst:1472 cf6bb035b54e4fcdad814450ae34dcef\nmsgid \"For the other parameters, please consult the aforementioned methods.\"\nmsgstr \"その他のパラメータについては、前述のメソッドをご参照ください。\"\n\n#: ../../document.rst:1475 62dbaf5e5aea49478a003ee16008856d\nmsgid \"\"\n\"the result of :meth:`Page.insert_text` (number of successfully inserted \"\n\"lines).\"\nmsgstr \":meth:`Page.insert_text` の結果（正常に挿入された行数）。\"\n\n#: ../../document.rst:1479 587c560e526a416f9adba46d934431cd\n#, fuzzy\nmsgid \"\"\n\"PDF only: Delete a page given by its 0-based number in `-∞ < pno < \"\n\"page_count`.\"\nmsgstr \"PDFのみ：0ベースの番号で指定されたページを削除します。`-∞ < pno < page_count - 1` です。\"\n\n#: ../../document.rst:1481 ../../document.rst:1488\n#: 2de6c5ed33694928b05b3af60acc735b 5e0e19b1164a4922a5c4de39dadf8d94\nmsgid \"Changed in v1.18.14: support Python's `del` statement.\"\nmsgstr \"v1.18.14で変更：Pythonの `del` 文をサポート。\"\n\n#: ../../document.rst:1483 b53db2a971f54e8fa8fe54fc059f0ece\nmsgid \"\"\n\"the page to be deleted. Negative number count backwards from the end of \"\n\"the document (like with indices). Default is the last page.\"\nmsgstr \"削除するページ。負の数は文書の末尾から逆に数えます（インデックスと同様）。デフォルトは最後のページです。\"\n\n#: ../../document.rst:1487 f663c7417d0c4717918bc0edbdaa19f6\nmsgid \"Changed in v1.18.13: more flexibility specifying pages to delete.\"\nmsgstr \"v1.18.13 で変更されました: 削除するページを指定する柔軟性が向上しました。\"\n\n#: ../../document.rst:1490 5a7de5dc80b84affad561bc4fedaf80b\nmsgid \"PDF only: Delete multiple pages given as 0-based numbers.\"\nmsgstr \"PDF のみ: 0 ベースの番号として指定された複数のページを削除します。\"\n\n#: ../../document.rst:1494 875c5dde7ff14ca9aa7522c71259f94c\nmsgid \"\"\n\"**Format 1:** Use keywords. Represents the old format. A contiguous range\"\n\" of pages is removed.\"\nmsgstr \"**フォーマット 1:** キーワードを使用します。古いフォーマットを表します。連続したページ範囲が削除されます。\"\n\n#: ../../document.rst:1493 6b7772a6ff3f4a2db6d2dcb99fded671\nmsgid \"\\\"from_page\\\": first page to delete. Zero if omitted.\"\nmsgstr \"\\\"from_page\\\": 削除する最初のページ。省略された場合はゼロです。\"\n\n#: ../../document.rst:1494 0e5c6f821d7044d5ac7c0e6f5ed7f64b\nmsgid \"\"\n\"\\\"to_page\\\": last page to delete. Last page in document if omitted. Must \"\n\"not be less then \\\"from_page\\\".\"\nmsgstr \"\"\n\"\\\"to_page\\\": 削除する最後のページ。省略された場合はドキュメント内の最後のページです。\\\"from_page\\\" \"\n\"より小さくしてはいけません。\"\n\n#: ../../document.rst:1496 e8904441ed83424eb87fa87a6a684b2a\nmsgid \"\"\n\"**Format 2:** Two page numbers as positional parameters. Handled like \"\n\"Format 1.\"\nmsgstr \"**フォーマット 2:** 位置パラメータとしての2つのページ番号。フォーマット 1 と同様に処理されます。\"\n\n#: ../../document.rst:1498 163ec2bcd7934971b9000245d8e3d209\nmsgid \"\"\n\"**Format 3:** One positional integer parameter. Equivalent to \"\n\":meth:`Page.delete_page`.\"\nmsgstr \"**フォーマット 3:** 1 つの位置パラメータの整数。:meth:`Page.delete_page` に相当します。\"\n\n#: ../../document.rst:1500 ac9b0d2bb525429d8ac5afe495854517\nmsgid \"\"\n\"**Format 4:** One positional parameter of type *list*, *tuple* or \"\n\"*range()* of page numbers. The items of this sequence may be in any order\"\n\" and may contain duplicates.\"\nmsgstr \"\"\n\"**フォーマット 4:** ページ番号のリスト、*タプル*、または *range()* \"\n\"の1つの位置パラメータ。このシーケンスのアイテムは任意の順序であり、重複していてもかまいません。\"\n\n#: ../../document.rst:1502 2e8e4f3f1ff24632b93215697d0a2594\nmsgid \"\"\n\"**Format 5:** *(New in v1.18.14)* Using the Python `del` statement and \"\n\"index / slice notation is now possible.\"\nmsgstr \"\"\n\"**フォーマット 5:** *(v1.18.14 で新規)* Python の `del` ステートメントとインデックス / \"\n\"スライス表記を使用することができます。\"\n\n#: ../../document.rst:1506 be52d2bac85f42c8a561522fc5dc7694\nmsgid \"\"\n\"*(Changed in v1.14.17, optimized in v1.17.7)* In an effort to maintain a \"\n\"valid PDF structure, this method and :meth:`delete_page` will also \"\n\"deactivate items in the table of contents which point to deleted pages. \"\n\"\\\"Deactivation\\\" here means, that the bookmark will point to nowhere and \"\n\"the title will be shown grayed-out by supporting PDF viewers. The overall\"\n\" TOC structure is left intact.\"\nmsgstr \"\"\n\"*(v1.14.17 で変更, v1.17.7 で最適化)* 有効な PDF 構造を維持するために、このメソッドと \"\n\":meth:`delete_page` は、削除されたページを指す目次のアイテムも無効化します。ここでの \\\"無効化\\\" \"\n\"とは、ブックマークがどこを指しているのか分からなくなり、サポートされている PDF \"\n\"ビューアによってタイトルがグレーアウト表示されることを意味します。全体の目次構造は維持されます。\"\n\n#: ../../document.rst:1508 2ea9db623ee644ce851f517b21468bbc\nmsgid \"\"\n\"It will also remove any **links on remaining pages** which point to a \"\n\"deleted one. This action may have an extended response time for documents\"\n\" with many pages.\"\nmsgstr \"\"\n\"また、削除されたページを指す **残りのページ上のリンク** \"\n\"も削除されます。これにより、多くのページを持つドキュメントでは拡張された応答時間が発生する可能性があります。\"\n\n#: ../../document.rst:1510 9e268616509345318e19407e7f4fce54\nmsgid \"Following examples will all delete pages 500 through 519:\"\nmsgstr \"以下の例はすべて、ページ500から519を削除します:\"\n\n#: ../../document.rst:1512 8554875e1e58416180c485b06d4698b6\nmsgid \"`doc.delete_pages(500, 519)`\"\nmsgstr \"\"\n\n#: ../../document.rst:1513 1c822f9af13441608441afe5bf0640dd\nmsgid \"`doc.delete_pages(from_page=500, to_page=519)`\"\nmsgstr \"\"\n\n#: ../../document.rst:1514 e46ee2d732134660b9a9f857991dabce\nmsgid \"`doc.delete_pages((500, 501, 502, ... , 519))`\"\nmsgstr \"\"\n\n#: ../../document.rst:1515 b30e293c5c9640ba9f5d8f3875607c97\nmsgid \"`doc.delete_pages(range(500, 520))`\"\nmsgstr \"\"\n\n#: ../../document.rst:1516 1e369b51a48c4110bfb776a7c91dac36\nmsgid \"`del doc[500:520]`\"\nmsgstr \"\"\n\n#: ../../document.rst:1517 33382327b14c40309cb885c892db74dc\nmsgid \"`del doc[(500, 501, 502, ... , 519)]`\"\nmsgstr \"\"\n\n#: ../../document.rst:1518 835883ce222348f1939be4af90e88154\nmsgid \"`del doc[range(500, 520)]`\"\nmsgstr \"\"\n\n#: ../../document.rst:1520 65e4760990f848c7a684989dd067afbd\nmsgid \"\"\n\"For the :ref:`AdobeManual` the above takes about 0.6 seconds, because the\"\n\" remaining 1290 pages must be cleaned from invalid links.\"\nmsgstr \"\"\n\":ref:`AdobeManual` \"\n\"では、上記の操作に約0.6秒かかります。なぜなら、残りの1290ページから無効なリンクを削除する必要があるからです。\"\n\n#: ../../document.rst:1522 7af3a67223f04f44835189f49959825d\nmsgid \"\"\n\"In general, the performance of this method is dependent on the number of \"\n\"remaining pages -- **not** on the number of deleted pages: in the above \"\n\"example, **deleting all pages except** those 20, will need much less \"\n\"time.\"\nmsgstr \"\"\n\"一般的に、このメソッドのパフォーマンスは残りのページの数に依存します - 削除されたページの数には依存 **しません** \"\n\"。上記の例では、20個のページ **以外のすべてのページを削除する** 場合、はるかに少ない時間がかかります。\"\n\n#: ../../document.rst:1527 652ee83c146f452098f4379a8c73047a\nmsgid \"PDF only: Copy a page reference within the document.\"\nmsgstr \"PDF のみ: ドキュメント内でページの参照をコピーします。\"\n\n#: ../../document.rst:1529 ac1cce6e9936446eb35a3ffe8ca915d1\nmsgid \"the page to be copied. Must be in range `0 <= pno < page_count`.\"\nmsgstr \"コピーするページ。範囲は `0 <= pno < page_count` である必要があります。\"\n\n#: ../../document.rst:1531 ../../document.rst:1543\n#: c41b90dc8ef640408f1a617a2e0fc519 ca3166610784468cbc085259ba27a3ea\nmsgid \"\"\n\"the page number in front of which to copy. The default inserts **after** \"\n\"the last page.\"\nmsgstr \"コピーする位置の前のページ番号。デフォルトでは最後のページの **後** に挿入されます。\"\n\n#: ../../document.rst:1533 8468fc8b63444047b7a1fe75547cd1fd\nmsgid \"\"\n\"Only a new **reference** to the page object will be created -- not a new \"\n\"page object, all copied pages will have identical attribute values, \"\n\"including the :attr:`Page.xref`. This implies that any changes to one of \"\n\"these copies will appear on all of them.\"\nmsgstr \"\"\n\"ページオブジェクトへの新しい **参照** のみが作成されます - \"\n\"新しいページオブジェクトは作成されません。すべてのコピーされたページは、:attr:`Page.xref` \"\n\"を含む属性値が同じになります。これは、これらのコピーの1つに対する変更がすべてのコピーに反映されることを意味します。\"\n\n#: ../../document.rst:1537 d97170af740a4e5fbd5d5be2e8c4c008\nmsgid \"New in v1.14.17\"\nmsgstr \"v1.14.17 で新規\"\n\n#: ../../document.rst:1539 e5bfe27961644509afa6eb237a7aaa90\nmsgid \"PDF only: Make a full copy (duplicate) of a page.\"\nmsgstr \"PDF のみ: ページの完全なコピー（複製）を作成します。\"\n\n#: ../../document.rst:1541 bb27bf35370f4350896c2af762ffb1bc\nmsgid \"the page to be duplicated. Must be in range `0 <= pno < page_count`.\"\nmsgstr \"複製するページ。範囲は `0 <= pno < page_count` である必要があります。\"\n\n#: ../../document.rst:1547 f703ba87ea974305a4c30425ca1ff9b9\nmsgid \"\"\n\"In contrast to :meth:`copy_page`, this method creates a new page object \"\n\"(with a new :data:`xref`), which can be changed independently from the \"\n\"original.\"\nmsgstr \"\"\n\":meth:`copy_page` とは異なり、このメソッドは新しいページオブジェクト（新しい :data:`xref` \"\n\"を持つ）を作成します。これは元のページから独立して変更できます。\"\n\n#: ../../document.rst:1549 07e3b642c6b94e9e8f52daa72f74a907\nmsgid \"\"\n\"Any Popup and \\\"IRT\\\" (\\\"in response to\\\") annotations are **not copied**\"\n\" to avoid potentially incorrect situations.\"\nmsgstr \"ポップアップと \\\"IRT\\\"（\\\"応答先\\\"）注釈は、潜在的に誤った状況を回避するために **コピーされません** 。\"\n\n#: ../../document.rst:1553 43ec556cbc38492c8049b8372e53daac\nmsgid \"PDF only: Move (copy and then delete original) a page within the document.\"\nmsgstr \"PDF のみ: ドキュメント内でページを移動します（コピーしてから元のページを削除）。\"\n\n#: ../../document.rst:1555 b044a8f7a7af40788e9d81537eb619ad\nmsgid \"the page to be moved. Must be in range `0 <= pno < page_count`.\"\nmsgstr \"移動するページ。範囲は `0 <= pno < page_count` である必要があります。\"\n\n#: ../../document.rst:1557 946f21ee475c42878bf3b1dae84f7d69\nmsgid \"\"\n\"the page number in front of which to insert the moved page. The default \"\n\"moves **after** the last page.\"\nmsgstr \"移動したページの前に挿入するページ番号。デフォルトでは最後のページの **後** に移動します。\"\n\n#: ../../document.rst:1562 e8d7a9d259534c618a11baa88ffeb3fc\nmsgid \"New in v1.17.4\"\nmsgstr \"v1.17.4 で新規\"\n\n#: ../../document.rst:1564 8b3171a1d9a142c9a9c030fe8d31c8d2\nmsgid \"\"\n\"PDF only: Get or set the */NeedAppearances* property of Form PDFs. Quote:\"\n\" *\\\"(Optional) A flag specifying whether to construct appearance streams \"\n\"and appearance dictionaries for all widget annotations in the document \"\n\"... Default value: false.\\\"* This may help controlling the behavior of \"\n\"some readers / viewers.\"\nmsgstr \"\"\n\"PDF のみ: Form PDF の */NeedAppearances* プロパティを取得または設定します。引用: \"\n\"*\\\"（オプション）ドキュメント内のすべてのウィジェット注釈の外観ストリームと外観辞書を構築するかどうかを指定するフラグ...デフォルト値: \"\n\"false\\\"* 。これは一部のリーダー/ビューアの動作を制御するのに役立つかもしれません。\"\n\n#: ../../document.rst:1566 21bdc7002b114b8794f1a0a9c6ee76a5\nmsgid \"\"\n\"set the property to this value. If omitted or `None`, inquire the current\"\n\" value.\"\nmsgstr \"プロパティをこの値に設定します。省略された場合または `None` の場合、現在の値を問い合わせます。\"\n\n#: ../../document.rst:1569 78f9700e38dd443e9f73a91fda3dc450\nmsgid \"\"\n\"* None: not a Form PDF, or property not defined. * True / False: the \"\n\"value of the property (either just set or existing for inquiries). Has no\"\n\" effect if no Form PDF.\"\nmsgstr \"\"\n\n#: ../../document.rst:1570 c0025670860c42d5bd1c8f5c34a6dad6\nmsgid \"None: not a Form PDF, or property not defined.\"\nmsgstr \"None: フォーム PDF ではないか、プロパティが定義されていない。\"\n\n#: ../../document.rst:1571 eb06f30be4434520bda89c558742261d\nmsgid \"\"\n\"True / False: the value of the property (either just set or existing for \"\n\"inquiries). Has no effect if no Form PDF.\"\nmsgstr \"True / False: プロパティの値（設定されたばかりまたは問い合わせ用に存在する）。フォーム PDF がない場合は影響しません。\"\n\n#: ../../document.rst:1577 75e79125f8c7472cb0a19ed8e1458e1a\nmsgid \"\"\n\"PDF only: Return whether the document contains signature fields. This is \"\n\"an optional PDF property: if not present (return value -1), no \"\n\"conclusions can be drawn -- the PDF creator may just not have bothered \"\n\"using it.\"\nmsgstr \"\"\n\"PDF のみ: ドキュメントに署名フィールドが含まれているかどうかを返します。これはオプションの PDF プロパティです。存在しない場合（返り値 \"\n\"-1）、結論を導くことはできません - PDF の作成者は単にそれを使用しなかった可能性があります。\"\n\n#: ../../document.rst:1580 9a14234501f54034bb1bf739d64a15fa\nmsgid \"\"\n\"* -1: not a Form PDF / no signature fields recorded / no *SigFlags* \"\n\"found. * 1: at least one signature field exists. * 3:  contains \"\n\"signatures that may be invalidated if the file is saved (written) in a \"\n\"way that alters its previous contents, as opposed to an incremental \"\n\"update.\"\nmsgstr \"\"\n\n#: ../../document.rst:1581 9bad9283ef584aa2b078c83f7d777b63\nmsgid \"-1: not a Form PDF / no signature fields recorded / no *SigFlags* found.\"\nmsgstr \"-1: フォーム PDF でない / 署名フィールドが記録されていない / *SigFlags* が見つからない。\"\n\n#: ../../document.rst:1582 deabde5552354d23bc0241dce237b354\nmsgid \"1: at least one signature field exists.\"\nmsgstr \"1: 少なくとも1つの署名フィールドが存在します。\"\n\n#: ../../document.rst:1583 af34d2d341994de4b3f79434d0d6027a\nmsgid \"\"\n\"3:  contains signatures that may be invalidated if the file is saved \"\n\"(written) in a way that alters its previous contents, as opposed to an \"\n\"incremental update.\"\nmsgstr \"3: ファイルが前の内容を変更する方法で保存（書き込み）されると、署名が無効になる可能性のある署名が含まれています。これは増分更新とは対照的です。\"\n\n#: ../../document.rst:1592 04fdb7d7d7c84095a3494d40af0b5926\nmsgid \"\"\n\"Changed in v1.14.16: The sequence of positional parameters \\\"name\\\" and \"\n\"\\\"buffer\\\" has been changed to comply with the call pattern of other \"\n\"functions.\"\nmsgstr \"\"\n\"v1.14.16 で変更されました: 位置パラメータ \\\"name\\\" と \\\"buffer\\\" \"\n\"の順序が他の関数の呼び出しパターンに従うように変更されました。\"\n\n#: ../../document.rst:1594 fcd3db75809240cc8f190dd9a00289d2\nmsgid \"\"\n\"PDF only: Embed a new file. All string parameters except the name may be \"\n\"unicode (in previous versions, only ASCII worked correctly). File \"\n\"contents will be compressed (where beneficial).\"\nmsgstr \"\"\n\"PDF のみ: 新しいファイルを埋め込みます。名前以外のすべての文字列パラメータは Unicode である場合があります（以前のバージョンでは \"\n\"ASCII しか正しく動作しませんでした）。ファイルの内容は（有益な場合に）圧縮されます。\"\n\n#: ../../document.rst:1596 2cea88e56a044b0c8bad08e9a205ccde\nmsgid \"entry identifier, **must not already exist**.\"\nmsgstr \"エントリの識別子、**すでに存在しない必要** があります。\"\n\n#: ../../document.rst:1597 b4cb313585c3435fa169abd1fa4d1619\nmsgid \"\"\n\"file contents.  *(Changed in v1.14.13)* *io.BytesIO* is now also \"\n\"supported.\"\nmsgstr \"\"\n\n#: ../../document.rst:1597 4280d1c050654a94a34238d69e159094\nmsgid \"file contents.\"\nmsgstr \"ファイルの内容。\"\n\n#: ../../document.rst:1599 ../../document.rst:1673\n#: 31a1f516458f40c39c3f700e4ef89de4 b0eb6859ed644497bc3e05f9f73434b3\nmsgid \"*(Changed in v1.14.13)* *io.BytesIO* is now also supported.\"\nmsgstr \"*(v1.14.13 で変更)* *io.BytesIO* もサポートされるようになりました。\"\n\n#: ../../document.rst:1601 ac97d3204a544f86b77d976c92acbf7b\nmsgid \"optional filename. Documentation only, will be set to *name* if `None`.\"\nmsgstr \"オプションのファイル名。ドキュメンテーション専用で、`None` の場合は *name* に設定されます。\"\n\n#: ../../document.rst:1602 a5690203a4ba480eb382e82deceb9895\nmsgid \"\"\n\"optional unicode filename. Documentation only, will be set to *filename* \"\n\"if `None`.\"\nmsgstr \"オプションのUnicodeファイル名。ドキュメンテーション専用で、`None` の場合は *filename* に設定されます。\"\n\n#: ../../document.rst:1603 6d4f198ba29348218b4fe50cccdefa1f\nmsgid \"optional description. Documentation only, will be set to *name* if `None`.\"\nmsgstr \"オプションの説明。ドキュメンテーション専用で、`None` の場合は *name* に設定されます。\"\n\n#: ../../document.rst:1606 7b71f66a34ea47e9a71e7fe5e7d64fa0\nmsgid \"\"\n\"*(Changed in v1.18.13)* The method now returns the :data:`xref` of the \"\n\"inserted file. In addition, the file object now will be automatically \"\n\"given the PDF keys `/CreationDate` and `/ModDate` based on the current \"\n\"date-time.\"\nmsgstr \"\"\n\"*(v1.18.13 で変更)* このメソッドは挿入されたファイルの :data:`xref` \"\n\"も返すようになりました。さらに、ファイルオブジェクトには現在の日時に基づいて自動的に PDF キー `/CreationDate` および \"\n\"`/ModDate` が設定されるようになりました。\"\n\n#: ../../document.rst:1611 207a6bc78c654390b4b1f2cf463dd50f\nmsgid \"\"\n\"Changed in v1.14.16: This is now a method. In previous versions, this was\"\n\" a property.\"\nmsgstr \"v1.14.16 で変更されました: これは現在のメソッドです。以前のバージョンではプロパティでした。\"\n\n#: ../../document.rst:1613 0cb7ff09b67448ac9cd78cb7b0b7efb7\nmsgid \"PDF only: Return the number of embedded files.\"\nmsgstr \"PDF のみ: 埋め込まれたファイルの数を返します。\"\n\n#: ../../document.rst:1617 005666a2614842c9b4353f5f802b6c55\nmsgid \"\"\n\"PDF only: Retrieve the content of embedded file by its entry number or \"\n\"name. If the document is not a PDF, or entry cannot be found, an \"\n\"exception is raised.\"\nmsgstr \"\"\n\"PDF のみ: エントリ番号または名前によって埋め込まれたファイルの内容を取得します。ドキュメントが PDF \"\n\"でない場合、またはエントリが見つからない場合、例外が発生します。\"\n\n#: ../../document.rst:1619 ../../document.rst:1639 ../../document.rst:1670\n#: 869875aa0dfe44808e52deebefea1de1 b13cd4114f2545a9be72cfc74d7c87be\n#: bf32473089a3483e8ddc9dac22d37916\nmsgid \"index or name of entry. An integer must be in `range(embfile_count())`.\"\nmsgstr \"エントリのインデックスまたは名前。整数は範囲内である必要があります `range(embfile_count())`。\"\n\n#: ../../document.rst:1625 e338d280c75b4573b622feabbe710c57\nmsgid \"Changed in v1.14.16: Items can now be deleted by index, too.\"\nmsgstr \"v1.14.16 で変更されました: インデックスによってアイテムを削除できるようになりました。\"\n\n#: ../../document.rst:1627 333fc09a48dc4e96be1d0d96576eccba\nmsgid \"\"\n\"PDF only: Remove an entry from `/EmbeddedFiles`. As always, physical \"\n\"deletion of the embedded file content (and file space regain) will occur \"\n\"only when the document is saved to a new file with a suitable garbage \"\n\"option.\"\nmsgstr \"\"\n\"PDF のみ: `/EmbeddedFiles` \"\n\"からエントリを削除します。いつものように、適切なガベージオプションを使用して新しいファイルに保存すると、埋め込まれたファイルの内容の物理的な削除（およびファイルスペースの回復）が行われます。\"\n\n#: ../../document.rst:1629 eee9b150efa74ebb95b8d065ce663d9e\nmsgid \"index or name of entry.\"\nmsgstr \"エントリのインデックスまたは名前。\"\n\n#: ../../document.rst:1631 8c4ab8c1f77e4c2985abe3c93f92b10d\nmsgid \"\"\n\"When specifying an entry name, this function will only **delete the first\"\n\" item** with that name. Be aware that PDFs not created with PyMuPDF may \"\n\"contain duplicate names. So you may want to take appropriate precautions.\"\nmsgstr \"\"\n\"エントリ名を指定する場合、この関数はその名前を持つ **最初のアイテムのみを削除します** 。PyMuPDF で作成された PDF 以外の PDF\"\n\" には重複する名前が含まれている可能性があるため、適切な注意を払う必要があるかもしれません。\"\n\n#: ../../document.rst:1635 ce3e3fdc43df49f29497bf219a55ffb7\nmsgid \"Changed in v1.18.13\"\nmsgstr \"v1.18.13 で変更されました\"\n\n#: ../../document.rst:1637 66294342e3bd417fa3d25391a8d4394d\nmsgid \"\"\n\"PDF only: Retrieve information of an embedded file given by its number or\"\n\" by its name.\"\nmsgstr \"PDF のみ: 埋め込まれたファイルの情報を取得します。エントリ番号または名前によって指定されたファイルの情報を取得します。\"\n\n#: ../../document.rst:1642 d938771d7b2e410ebbe66f3bffdc3111\nmsgid \"\"\n\"a dictionary with the following keys:  * ``name`` -- (*str*) name under \"\n\"which this entry is stored * ``filename`` -- (*str*) filename * \"\n\"``ufilename`` -- (*unicode*) filename * ``description`` -- (*str*) \"\n\"description * ``size`` -- (*int*) original file size * ``length`` -- \"\n\"(*int*) compressed file length * ``creationDate`` -- (*str*) date-time of\"\n\" item creation in PDF format * ``modDate`` -- (*str*) date-time of last \"\n\"change in PDF format * ``collection`` -- (*int*) :data:`xref` of the \"\n\"associated PDF portfolio item if any, else zero. * ``checksum`` -- \"\n\"(*str*) a hashcode of the stored file content as a hexadecimal string. \"\n\"Should be MD5 according to PDF specifications, but be prepared to see \"\n\"other hashing algorithms.\"\nmsgstr \"\"\n\n#: ../../document.rst:1642 ab305172c9934b6d9c00eb5ed6e4649a\nmsgid \"a dictionary with the following keys:\"\nmsgstr \"以下のキーを持つ辞書:\"\n\n#: ../../document.rst:1644 b7a076e5859b4bcab80e34541859d7ca\nmsgid \"``name`` -- (*str*) name under which this entry is stored\"\nmsgstr \"``name`` – (*str*) このエントリが格納されている名前\"\n\n#: ../../document.rst:1645 121172b7332143a8b549ef30f4bd5bb1\nmsgid \"``filename`` -- (*str*) filename\"\nmsgstr \"``filename`` – (*str*) ファイル名\"\n\n#: ../../document.rst:1646 89fd41822ad34573a7b952b2fd4303ac\nmsgid \"``ufilename`` -- (*unicode*) filename\"\nmsgstr \"``ufilename`` – (*unicode*) Unicode ファイル名\"\n\n#: ../../document.rst:1647 437589e818d74dc3aa02750c07e6aff9\nmsgid \"``description`` -- (*str*) description\"\nmsgstr \"``description`` – (*str*) 説明\"\n\n#: ../../document.rst:1648 8bf22226e6b946ba8904a12c9047c6db\nmsgid \"``size`` -- (*int*) original file size\"\nmsgstr \"``size`` – (*int*) 元のファイルサイズ\"\n\n#: ../../document.rst:1649 aac50a010de4434abbf736335b328344\nmsgid \"``length`` -- (*int*) compressed file length\"\nmsgstr \"``length`` – (*int*) 圧縮ファイルの長さ\"\n\n#: ../../document.rst:1650 e79e7816a4a14e959f1d7ae2ce4e4ee3\nmsgid \"``creationDate`` -- (*str*) date-time of item creation in PDF format\"\nmsgstr \"``creationDate`` – (*str*) PDF 形式のアイテム作成の日時\"\n\n#: ../../document.rst:1651 d29662d08223403686e394f5d5d4de79\nmsgid \"``modDate`` -- (*str*) date-time of last change in PDF format\"\nmsgstr \"``modDate`` – (*str*) PDF 形式の最終変更の日時\"\n\n#: ../../document.rst:1652 69752e18d0a54012a9dbebd7a2a8eded\nmsgid \"\"\n\"``collection`` -- (*int*) :data:`xref` of the associated PDF portfolio \"\n\"item if any, else zero.\"\nmsgstr \"``collection`` – (*int*) 関連する PDF ポートフォリオアイテムの :data:`xref`（あれば）、それ以外はゼロ。\"\n\n#: ../../document.rst:1653 870473bef4414d4a9f160c797a395163\nmsgid \"\"\n\"``checksum`` -- (*str*) a hashcode of the stored file content as a \"\n\"hexadecimal string. Should be MD5 according to PDF specifications, but be\"\n\" prepared to see other hashing algorithms.\"\nmsgstr \"\"\n\"``checksum`` – (*str*) 16進数の文字列として格納されたファイルコンテンツのハッシュコード。PDF 仕様に従えば MD5 \"\n\"であるべきですが、他のハッシュアルゴリズムも見る可能性があるので、準備しておいてください。\"\n\n#: ../../document.rst:1657 b293ff432c4943c7b13c527f6ae85be2\nmsgid \"\"\n\"PDF only: Return a list of embedded file names. The sequence of the names\"\n\" equals the physical sequence in the document.\"\nmsgstr \"PDF のみ: 埋め込まれたファイルの名前のリストを返します。名前のシーケンスはドキュメント内の物理的なシーケンスと同じです。\"\n\n#: ../../document.rst:1668 40d7ae2aac41481b8256423dedbe2570\nmsgid \"\"\n\"PDF only: Change an embedded file given its entry number or name. All \"\n\"parameters are optional. Letting them default leads to a no-operation.\"\nmsgstr \"\"\n\"PDF のみ: \"\n\"エントリ番号または名前によって指定された埋め込まれたファイルを変更します。すべてのパラメータはオプションです。デフォルトで設定すると、操作は行われません。\"\n\n#: ../../document.rst:1671 f59d2798159c472e8b861edc7cafc49e\nmsgid \"\"\n\"the new file content.  *(Changed in v1.14.13)* *io.BytesIO* is now also \"\n\"supported.\"\nmsgstr \"新しいファイルの内容。*(v1.14.13 で変更)* *io.BytesIO* もサポートされるようになりました。\"\n\n#: ../../document.rst:1671 cb03da4bee5c476891ce54c568329d5b\nmsgid \"the new file content.\"\nmsgstr \"新しいファイルの内容。\"\n\n#: ../../document.rst:1675 5b7dac2348554f989d99d3971995632c\nmsgid \"the new filename.\"\nmsgstr \"新しいファイル名。\"\n\n#: ../../document.rst:1676 cf4779ea31f6485baa24ba26f618ee73\nmsgid \"the new unicode filename.\"\nmsgstr \"新しいUnicodeファイル名。\"\n\n#: ../../document.rst:1677 0c0c1f586af547b3806f6c000e271d90\nmsgid \"the new description.\"\nmsgstr \"新しい説明。\"\n\n#: ../../document.rst:1679 0588e113557544cfa618e9fa05550f26\nmsgid \"\"\n\"*(Changed in v1.18.13)*  The method now returns the :data:`xref` of the \"\n\"file object.\"\nmsgstr \"*(v1.18.13 で変更)* このメソッドはファイルオブジェクトの :data:`xref` も返すようになりました。\"\n\n#: ../../document.rst:1682 caacf7f8451042be88437cdd7ebf80f6\nmsgid \"\"\n\"xref of the file object. Automatically, its `/ModDate` PDF key will be \"\n\"updated with the current date-time.\"\nmsgstr \"ファイルオブジェクトのxref。自動的に、`/ModDate` PDF キーが現在の日時で更新されます。\"\n\n#: ../../document.rst:1687 c1612e02ab6e4aaa90882747a1695057\nmsgid \"\"\n\"Release objects and space allocations associated with the document. If \"\n\"created from a file, also closes *filename* (releasing control to the \"\n\"OS). Explicitly closing a document is equivalent to deleting it, `del \"\n\"doc`, or assigning it to something else like `doc = None`.\"\nmsgstr \"\"\n\"文書に関連付けられたオブジェクトとスペースの割り当てを解放します。ファイルから作成された場合、ファイル名も閉じられ（OS \"\n\"に制御を解放）ます。文書を明示的に閉じることは、それを削除すること、`del doc` 、または `doc = None` \"\n\"のように別のものに割り当てることと同等です。\"\n\n#: ../../document.rst:1691 ../../document.rst:1705 ../../document.rst:1712\n#: ../../document.rst:1719 ../../document.rst:1730 ../../document.rst:1739\n#: ../../document.rst:1888 2d1db6abe10b4b30a5fee4fc3150a1a2\n#: 3696c9e47a5d4f279ca6e13ca9badc38 5dffd418b2484c78bff8e129dd0beda0\n#: 90fec84dc6174a0e8a82750746e35157 c721b36a29cf4051bbf9e0ca82266951\n#: c9d56f09885c4db3afad4b92d4bb30c5 d854778651b548139937059eb60c11db\nmsgid \"New in v1.16.8\"\nmsgstr \"\"\n\n#: ../../document.rst:1692 a23659b9ffbc469f9b1e6aeaf63329c8\nmsgid \"Changed in v1.18.10\"\nmsgstr \"v1.18.10 で変更\"\n\n#: ../../document.rst:1694 8ef598a908184a068d803110e0727a3e\nmsgid \"PDF only: Return the definition source of a PDF object.\"\nmsgstr \"PDF のみ: PDF オブジェクトの定義ソースを返します。\"\n\n#: ../../document.rst:1696 2f3c19c00a5c4c33880871794c2207c2\n#, fuzzy\nmsgid \"\"\n\"the object's :data:`xref`. *Changed in v1.18.10:* A value of `-1` returns\"\n\" the PDF trailer source.\"\nmsgstr \"オブジェクトの :data`xref` 。*v1.18.10 で変更:* -1 の値は PDF トレーラーのソースを返します。\"\n\n#: ../../document.rst:1697 d7825dd896e841a4946cd46633cc1cba\nmsgid \"whether to generate a compact output with no line breaks or spaces.\"\nmsgstr \"改行やスペースのないコンパクトな出力を生成するかどうか。\"\n\n#: ../../document.rst:1698 4a2d6a2741b84dbbabd0ae4824b249b6\nmsgid \"whether to ASCII-encode binary data.\"\nmsgstr \"バイナリデータを ASCII エンコードするかどうか。\"\n\n#: ../../document.rst:1701 d289d49008164203be7390dad133165b\nmsgid \"The object definition source.\"\nmsgstr \"オブジェクトの定義ソース。\"\n\n#: ../../document.rst:1707 33f4eb609f2e4a31bcedf6bbb15f807b\nmsgid \"\"\n\"PDF only: Return the :data:`xref` number of the PDF catalog (or root) \"\n\"object. Use that number with :meth:`Document.xref_object` to see its \"\n\"source.\"\nmsgstr \"\"\n\"PDF のみ: PDF カタログ（またはルート）オブジェクトの :data:`xref` 番号を返します。これを \"\n\":meth:`Document.xref_object` で使用してそのソースを表示できます。\"\n\n#: ../../document.rst:1714 25deae598bf0499b83ce312067283693\nmsgid \"\"\n\"PDF only: Return the trailer source of the PDF,  which is usually located\"\n\" at the PDF file's end. This is :meth:`Document.xref_object` with an \"\n\":data:`xref` argument of -1.\"\nmsgstr \"\"\n\"PDF のみ: PDF のトレーラーソースを返します。通常、これは PDF ファイルの末尾にあります。これは \"\n\":meth:`Document.xref_object` で :data:`xref` 引数が -1 の場合です。\"\n\n#: ../../document.rst:1721 e4cb3087b0c64d3eb47f44d544152d83\nmsgid \"\"\n\"PDF only: Return the **decompressed** contents of the :data:`xref` stream\"\n\" object.\"\nmsgstr \"PDF のみ: :data:`xref` ストリームオブジェクトの **解凍された** コンテンツを返します。\"\n\n#: ../../document.rst:1723 ../../document.rst:1743 ../../document.rst:1762\n#: bd1262c85c614c2d81fa5f15f512c739 e80e7230a803497aa97d368a20d6e190\n#: f5b32eb85c0e4db8be3bb7ba4cea4d21\nmsgid \":data:`xref` number.\"\nmsgstr \":data:`xref` 番号。\"\n\n#: ../../document.rst:1726 c2333be86e844fc98605aa5bf81d198f\nmsgid \"the (decompressed) stream of the object.\"\nmsgstr \"（解凍された）オブジェクトのストリーム。\"\n\n#: ../../document.rst:1732 283d3fc3dd6540698765de3addb1126c\nmsgid \"\"\n\"PDF only: Return the **unmodified** (esp. **not decompressed**) contents \"\n\"of the :data:`xref` stream object. Otherwise equal to \"\n\":meth:`Document.xref_stream`.\"\nmsgstr \"\"\n\"PDF のみ: :data:`xref` ストリームオブジェクトの**変更前**（特に \"\n\"**解凍されていない**）コンテンツを返します。それ以外の点では :meth:`Document.xref_stream` と同等です。\"\n\n#: ../../document.rst:1735 462546377c3c4cd4b1472360c095b7c1\nmsgid \"the (original, unmodified) stream of the object.\"\nmsgstr \"（元の、変更前の）オブジェクトのストリーム。\"\n\n#: ../../document.rst:1741 0b9b082e450d41eb9b314d3946b524a8\nmsgid \"\"\n\"PDF only: Replace object definition of :data:`xref` with the provided \"\n\"string. The xref may also be new, in which case this instruction \"\n\"completes the object definition. If a page object is also given, its \"\n\"links and annotations will be reloaded afterwards.\"\nmsgstr \"\"\n\"PDF のみ: :data:`xref` のオブジェクト定義を提供された文字列で置き換えます。xref \"\n\"が新しい場合、この命令はオブジェクト定義を完成させます。ページオブジェクトも指定された場合、そのリンクと注釈が後で再ロードされ、リンクと/または注釈に関連する変更が反映されます。\"\n\n#: ../../document.rst:1745 8933f62dde2645e88c680302e0737fdd\nmsgid \"a string containing a valid PDF object definition.\"\nmsgstr \"有効な PDF オブジェクト定義を含む文字列。\"\n\n#: ../../document.rst:1747 a2630fd6e0d64414b7ad457df37269b0\nmsgid \"\"\n\"a page object. If provided, indicates, that annotations of this page \"\n\"should be refreshed (reloaded) to reflect changes incurred with links and\"\n\" / or annotations.\"\nmsgstr \"ページオブジェクト。指定された場合、このページの注釈が変更を反映するために再ロードされることを示します。\"\n\n#: ../../document.rst:1751 6e2ff3cc8ba1477faddb0b4a8c62a0c1\nmsgid \"zero if successful, otherwise an exception will be raised.\"\nmsgstr \"成功した場合はゼロ、それ以外の場合は例外が発生します。\"\n\n#: ../../document.rst:1756 59e3f67362e24cab9751cfb4f80bdaee\nmsgid \"New in v.1.16.8\"\nmsgstr \"v1.16.8 で新規\"\n\n#: ../../document.rst:1757 e613c9bdf9154e69bfdb4290b3db58b3\nmsgid \"Changed in v1.19.2: added parameter \\\"compress\\\"\"\nmsgstr \"v1.19.2 で変更: パラメータ \\\"compress\\\" を追加\"\n\n#: ../../document.rst:1758 b5a2a17e15894322882de2242d8fd8d7\nmsgid \"\"\n\"Changed in v1.19.6: deprecated parameter \\\"new\\\". Now confirms that the \"\n\"object is a PDF dictionary object.\"\nmsgstr \"\"\n\"v1.19.6 で変更: パラメータ \\\"new\\\" を非推奨にし、無視します。オブジェクトが PDF \"\n\"辞書オブジェクトであることを確認するようになりました。\"\n\n#: ../../document.rst:1760 be549db0daac4457bfaa4bd7267ba26b\nmsgid \"\"\n\"Replace the stream of an object identified by :data:`xref`, which must be\"\n\" a PDF dictionary. If the object is no :data:`stream`, it will be turned \"\n\"into one. The function automatically performs a compress operation \"\n\"(\\\"deflate\\\") where beneficial.\"\nmsgstr \"\"\n\"xref で識別されるオブジェクトのストリームを置き換えます。:data:`xref` は PDF \"\n\"辞書である必要があります。オブジェクトがストリームでない場合、それをストリームに変換します。この関数は、有益な場合には自動的に圧縮操作（\\\"deflate\\\"）を実行します。\"\n\n#: ../../document.rst:1764 10fe63cbe0d341f3a69640433bd62174\nmsgid \"\"\n\"the new content of the stream.  *(Changed in v1.14.13:)* *io.BytesIO* \"\n\"objects are now also supported.\"\nmsgstr \"\"\n\n#: ../../document.rst:1764 af4a5ac5fb2a4e098c781ed0b4edc120\nmsgid \"the new content of the stream.\"\nmsgstr \"ストリームの新しい内容。\"\n\n#: ../../document.rst:1766 8f1f5a91c7ab489dbcf4485406b77160\nmsgid \"*(Changed in v1.14.13:)* *io.BytesIO* objects are now also supported.\"\nmsgstr \"*(v1.14.13 で変更:)* *io.BytesIO* オブジェクトもサポートされるようになりました。\"\n\n#: ../../document.rst:1768 15ae756f4ecb41b288efbd1eb2c46b65\nmsgid \"*deprecated* and ignored. Will be removed some time after v1.20.0.\"\nmsgstr \"*非推奨* で無視されます。v1.20.0 以降のある時点で削除されます。\"\n\n#: ../../document.rst:1769 937c966669724ea086fc25ab2b60cdac\nmsgid \"\"\n\"whether to compress the inserted stream. If `True` (default), the stream \"\n\"will be inserted using `/FlateDecode` compression (if beneficial), \"\n\"otherwise the stream will inserted as is.\"\nmsgstr \"\"\n\"挿入されるストリームを圧縮するかどうか。`True` の場合（デフォルト）、ストリームは `/FlateDecode` \"\n\"圧縮を使用して挿入されます（有益な場合）、それ以外の場合はストリームはそのまま挿入されます。\"\n\n#: ../../document.rst:1771 52d2cd2519ce458b821f982d7560f805\nmsgid \"\"\n\"if :data:`xref` does not represent a PDF :data:`dict`. An empty \"\n\"dictionary ``<<>>`` is accepted. So if you just created the xref and want\"\n\" to give it a stream, first execute `doc.update_object(xref, \\\"<<>>\\\")`, \"\n\"and then insert the stream data with this method.\"\nmsgstr \"\"\n\":data:`xref` が PDF 辞書を表していない場合。空の辞書 < は受け入れられます。したがって、xref \"\n\"を作成し、それにストリームを指定する場合は、まず `doc.update_object(xref, \\\"<<>>\\\")` \"\n\"を実行し、その後、このメソッドでストリームデータを挿入してください。\"\n\n#: ../../document.rst:1773 cb6a6dc6a8254e4c8bb0f9c0590b4a57\nmsgid \"\"\n\"The method is primarily (but not exclusively) intended to manipulate \"\n\"streams containing PDF operator syntax (see pp. 643 of the \"\n\":ref:`AdobeManual`) as it is the case for e.g. page content streams.\"\nmsgstr \"\"\n\"このメソッドは主に（しかし排他的ではなく）PDFオペレータ構文を含むストリームを操作することを意図しています（:ref:`AdobeManual`\"\n\" の pp. 643 参照）。例えばページのコンテンツストリームのようにです。\"\n\n#: ../../document.rst:1775 e6f22217dcf04f5ca0789618ccc4b6a1\nmsgid \"\"\n\"If you update a contents stream, consider using save parameter \"\n\"*clean=True* to ensure consistency between PDF operator source and the \"\n\"object structure.\"\nmsgstr \"\"\n\"コンテンツストリームを更新する場合、PDFオペレータのソースとオブジェクト構造の間の整合性を確保するために save パラメータを \"\n\"*clean=True* で使用することを検討してください。\"\n\n#: ../../document.rst:1777 9175289674fe42d58a6b6abdb5e16e51\nmsgid \"\"\n\"Example: Let us assume that you no longer want a certain image appear on \"\n\"a page. This can be achieved by deleting the respective reference in its \"\n\"contents source(s) -- and indeed: the image will be gone after reloading \"\n\"the page. But the page's :data:`resources` object would still show the \"\n\"image as being referenced by the page. This save option will clean up any\"\n\" such mismatches.\"\nmsgstr \"\"\n\"例: ある画像をページに表示させたくないと仮定しましょう。これは、そのコンテンツソース内の該当する参照を削除することによって実現できます - \"\n\"そして実際には、ページを再読み込みした後、画像は消えてしまいます。ただし、ページの :data:`resources` \"\n\"は、まだその画像がページによって参照されていると表示されます。この保存オプションは、そのような不一致をクリーンアップします。\"\n\n#: ../../document.rst:1782 d9275845ca0549f9810fe1c459229023\nmsgid \"New in v1.19.5\"\nmsgstr \"v1.19.5 で新規\"\n\n#: ../../document.rst:1784 1978f66df0e74a988b853cc4459b38d0\n#, fuzzy\nmsgid \"\"\n\"PDF Only: Make ``target`` xref an exact copy of ``source``. If ``source``\"\n\" is a :data:`stream`, then this data is also copied.\"\nmsgstr \"\"\n\"PDF のみ: *ターゲット* の xref をソースの正確なコピーにします。*ソース* が :data:`stream` \"\n\"の場合、これらのデータもコピーされます。\"\n\n#: ../../document.rst:1786 ede3e57cd1a54c4dae2acc826a5ca8bf\nmsgid \"the source :data:`xref`. It must be an existing **dictionary** object.\"\nmsgstr \"ソースの :data:`xref`。既存の **辞書** オブジェクトである必要があります。\"\n\n#: ../../document.rst:1787 a114c0a1e048457db2694da7e1b8a322\nmsgid \"\"\n\"the target xref. Must be an existing **dictionary** object. If the xref \"\n\"has just been created, make sure to initialize it as a PDF dictionary \"\n\"with the minimum specification ``<<>>``.\"\nmsgstr \"\"\n\"ターゲットの :data:`xref`。既存の **辞書** オブジェクトである必要があります。xref が新たに作成されたばかりの場合、最小仕様\"\n\" ``<<>>`` を持つ PDF 辞書として初期化することを確認してください。\"\n\n#: ../../document.rst:1788 59c3eb8299844c509459fa4e5a6ff3b1\nmsgid \"\"\n\"an optional list of top-level keys in ``target``, that should not be \"\n\"removed in preparation of the copy process.\"\nmsgstr \"``target`` 内のトップレベルのキーを削除する準備段階で削除しない、オプションのキーリスト。\"\n\n#: ../../document.rst:1792 1447fd7c08ef42a7ae90572fa47e3c80\nmsgid \"This method has much in common with Python's *dict* method `copy()`.\"\nmsgstr \"このメソッドは、Python の *dict* メソッド `copy()` と多くの共通点があります。\"\n\n#: ../../document.rst:1793 c332b30c15b841de889aa5834596e374\nmsgid \"Both xref numbers must represent existing dictionaries.\"\nmsgstr \"両方の xref 番号は既存の辞書を表す必要があります。\"\n\n#: ../../document.rst:1794 c4b2efbb94164cf0bb995217e6390c71\nmsgid \"\"\n\"Before data is copied from *source*, all *target* dictionary keys are \"\n\"deleted. You can specify exceptions from this in the ``keep`` list. If \"\n\"*source* however has a same-named key, its value will still replace the \"\n\"target.\"\nmsgstr \"\"\n\"データがソースからコピーされる前に、すべての *ターゲット* 辞書のキーが削除されます。この削除からの例外を ``keep`` \"\n\"リストで指定できます。ただし、*ソース* に同じ名前のキーがある場合、その値はターゲットに置き換えられます。\"\n\n#: ../../document.rst:1795 a83d35411e754766978f64291fb8cb50\nmsgid \"\"\n\"If ``source`` is a :data:`stream` object, then these data will also be \"\n\"copied over, and ``target`` will be converted to a stream object.\"\nmsgstr \"\"\n\"``source`` が ``stream`` オブジェクトである場合、そのデータもコピーされ、``target`` は ``stream`` \"\n\"オブジェクトに変換されます。\"\n\n#: ../../document.rst:1796 344e7a4ddcfb4ab89dcfcc2862bc8f8d\nmsgid \"\"\n\"A typical use case is to replace or remove an existing image without \"\n\"using redaction annotations. Example scripts can be seen `in this PyMuPDF\"\n\" Utilities example <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/examples/replace-image>`_.\"\nmsgstr \"\"\n\"典型的な使用例は、赤塗り注釈を使用せずに既存の画像を置き換えたり削除したりすることです。例のスクリプトは `こちら \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples\"\n\"/replace-image>`_ で確認できます。\"\n\n#: ../../document.rst:1800 bb36292ec69e4f9b98c4ec88541612f9\nmsgid \"\"\n\"PDF Only: Extract data and meta information of an image stored in the \"\n\"document. The output can directly be used to be stored as an image file, \"\n\"as input for PIL, :ref:`Pixmap` creation, etc. This method avoids using \"\n\"pixmaps wherever possible to present the image in its original format \"\n\"(e.g. as JPEG).\"\nmsgstr \"\"\n\"PDF のみ: \"\n\"文書に格納された画像のデータとメタ情報を抽出します。出力は、画像ファイルとして保存するための直接的な使用、PIL、:ref:`Pixmap` \"\n\"の作成などに使用できます。このメソッドは、できる限りピクマップを使用せず、画像をその元の形式（例：JPEG \"\n\"として）で表示することを目的としています。\"\n\n#: ../../document.rst:1802 78f689ab3d4340b284a59caa46718c80\nmsgid \"\"\n\":data:`xref` of an image object. If this is not in `range(1, \"\n\"doc.xref_length())`, or the object is no image or other errors occur, \"\n\"`None` is returned and no exception is raised.\"\nmsgstr \"\"\n\"画像オブジェクトの :data:`xref`。これが  `range(1, doc.xref_length())` \"\n\"の範囲外であるか、オブジェクトが画像でないか、その他のエラーが発生した場合、 `None` が返され、例外は発生しません。\"\n\n#: ../../document.rst:1805 6f94452f16664114839249285cdf2d94\nmsgid \"\"\n\"a dictionary with the following keys  * *ext* (*str*) image type (e.g. \"\n\"*'jpeg'*), usable as image file extension * *smask* (*int*) :data:`xref` \"\n\"number of a stencil (/SMask) image or zero * ``width`` (*int*) image \"\n\"width * ``height`` (*int*) image height * *colorspace* (*int*) the \"\n\"image's *colorspace.n* number. * *cs-name* (*str*) the image's \"\n\"*colorspace.name*. * *xres* (*int*) resolution in x direction. Please \"\n\"also see :data:`resolution`. * *yres* (*int*) resolution in y direction. \"\n\"Please also see :data:`resolution`. * *image* (*bytes*) image data, \"\n\"usable as image file content\"\nmsgstr \"\"\n\n#: ../../document.rst:1805 d87f3e046f2f4b23bc0807e8168812e2\nmsgid \"a dictionary with the following keys\"\nmsgstr \"以下のキーを持つ辞書\"\n\n#: ../../document.rst:1807 ba7ba718761e492e8f662d09ddc95835\nmsgid \"*ext* (*str*) image type (e.g. *'jpeg'*), usable as image file extension\"\nmsgstr \"*ext* (*str*) 画像タイプ（例：*'jpeg'*）、画像ファイルの拡張子として使用可能\"\n\n#: ../../document.rst:1808 9522a445d9c2447e81797f1553daa0ed\nmsgid \"*smask* (*int*) :data:`xref` number of a stencil (/SMask) image or zero\"\nmsgstr \"*smask* (*int*) ステンシル（/SMask）画像の :data:`xref` 番号またはゼロ\"\n\n#: ../../document.rst:1809 07061033da1b4b1888cc6d96246e3731\n#, fuzzy\nmsgid \"``width`` (*int*) image width\"\nmsgstr \"*width* (*int*) 画像の幅\"\n\n#: ../../document.rst:1810 7a2ee3334e0b43b799cce3fa8a5067cf\n#, fuzzy\nmsgid \"``height`` (*int*) image height\"\nmsgstr \"*height* (*int*) 画像の高さ\"\n\n#: ../../document.rst:1811 674a1227dfb24764810f8a3c8e1d5115\nmsgid \"*colorspace* (*int*) the image's *colorspace.n* number.\"\nmsgstr \"*colorspace* (*int*) 画像のカラースペースの数\"\n\n#: ../../document.rst:1812 87b5931935934adaac549c6c0d2dae5c\nmsgid \"*cs-name* (*str*) the image's *colorspace.name*.\"\nmsgstr \"*cs-name* (*str*) 画像のカラースペースの名前\"\n\n#: ../../document.rst:1813 d1cdc8cf4e38466bad4393a9edda8188\nmsgid \"\"\n\"*xres* (*int*) resolution in x direction. Please also see \"\n\":data:`resolution`.\"\nmsgstr \"*xres* (*int*) x 方向の解像度。:data:`resolution` も参照してください。\"\n\n#: ../../document.rst:1814 41f36105a6ef458ca0d0efda56b787f7\nmsgid \"\"\n\"*yres* (*int*) resolution in y direction. Please also see \"\n\":data:`resolution`.\"\nmsgstr \"*yres* (*int*) y 方向の解像度。:data:`resolution` も参照してください。\"\n\n#: ../../document.rst:1815 3b09fc2f822e4a66bcf89f5064888d20\nmsgid \"*image* (*bytes*) image data, usable as image file content\"\nmsgstr \"*image* (*bytes*) 画像データ、画像ファイルのコンテンツとして使用可能\"\n\n#: ../../document.rst:1827 a2ca74b0d3fb44a6af4caf922486b13a\nmsgid \"\"\n\"There is a functional overlap with *pix = pymupdf.Pixmap(doc, xref)*, \"\n\"followed by a *pix.tobytes()*. Main differences are that extract_image, \"\n\"**(1)** does not always deliver PNG image formats, **(2)** is **very** \"\n\"much faster with non-PNG images, **(3)** usually results in much less \"\n\"disk storage for extracted images, **(4)** returns `None` in error cases \"\n\"(generates no exception). Look at the following example images within the\"\n\" same PDF.\"\nmsgstr \"\"\n\"*pix = pymupdf.Pixmap(doc, xref)* *に続いてpix.tobytes()* \"\n\"という機能的な重複があります。主な違いは、extract_imageは、**(1)** 必ずしもPNG画像形式を提供しない、 **(2)** \"\n\"PNG以外の画像では非常に高速である、 **(3)** 抽出された画像のディスクストレージが通常ははるかに少ない、 **(4)** \"\n\"エラーケースでは `None` を返す（例外を生成しない）という点です。同じPDF内の以下の例の画像を見てみましょう。\"\n\n#: ../../document.rst:1829 ebb9a040a28642529996bc8a3d5e3341\nmsgid \"xref 1268 is a PNG -- Comparable execution time and identical output::\"\nmsgstr \"xref 1268 は PNG 形式です - 比較可能な実行時間と同じ出力::\"\n\n#: ../../document.rst:1841 b4ad30db2af64226b788bc78cdbf2620\nmsgid \"\"\n\"xref 1186 is a JPEG -- :meth:`Document.extract_image` is **many times \"\n\"faster** and produces a **much smaller** output (2.48 MB vs. 0.35 MB)::\"\nmsgstr \"\"\n\"xref 1186 は JPEG です - :meth:`Document.extract_image` は \"\n\"**何倍も速く**、はるかに小さい出力を生成します（2.48 MB に対して 0.35 MB）::\"\n\n#: ../../document.rst:1856 f238369b37934968ae4ada422517679c\nmsgid \"Changed in v1.19.4: return a dictionary if `named == True`.\"\nmsgstr \"v1.19.4 で変更: `named == True` の場合、辞書を返します。\"\n\n#: ../../document.rst:1858 63b965c660cb48f599a8e3ef61279d03\nmsgid \"\"\n\"PDF Only: Return an embedded font file's data and appropriate file \"\n\"extension. This can be used to store the font as an external file. The \"\n\"method does not throw exceptions (other than via checking for PDF and \"\n\"valid :data:`xref`).\"\nmsgstr \"\"\n\"PDF のみ: \"\n\"埋め込まれたフォントファイルのデータと適切なファイル拡張子を返します。これを使用してフォントを外部ファイルとして保存することができます。このメソッドは例外をスローしません（PDF\"\n\" および有効な :data:`xref` のチェックを除く）。\"\n\n#: ../../document.rst:1860 5868fff7a5c1434d8331e423b2da5b01\nmsgid \"PDF object number of the font to extract.\"\nmsgstr \"抽出するフォントの PDF オブジェクト番号。\"\n\n#: ../../document.rst:1861 e93cee0f89174e4bac856b0c26d404a5\nmsgid \"\"\n\"only return font information, not the buffer. To be used for information-\"\n\"only purposes, avoids allocation of large buffer areas.\"\nmsgstr \"フォント情報のみを返し、バッファの割り当てを回避するために使用します。\"\n\n#: ../../document.rst:1862 fa79f073e29f4634a730854470e90a80\nmsgid \"\"\n\"If true, a dictionary with the following keys is returned: 'name' (font \"\n\"base name), 'ext' (font file extension), 'type' (font type), 'content' \"\n\"(font file content).\"\nmsgstr \"\"\n\"`True` の場合、次のキーを持つ辞書が返されます： 'name'（フォントのベース名）、 'ext'（フォントファイルの拡張子）、 \"\n\"'type'（フォントのタイプ）、 'content'（フォントファイルの内容）。\"\n\n#: ../../document.rst:1865 ab89baff11f24d95bf92e569980f0cfe\n#, fuzzy\nmsgid \"\"\n\"a tuple `(basename, ext, type, content)`, where *ext* is a 3-byte \"\n\"suggested file extension (*str*), *basename* is the font's name (*str*), \"\n\"*type* is the font's type (e.g. \\\"Type1\\\") and *content* is a bytes \"\n\"object containing the font file's content (or *b\\\"\\\"*). For possible \"\n\"extension values and their meaning see :ref:`FontExtensions`. Return \"\n\"details on error:  * `(\\\"\\\", \\\"\\\", \\\"\\\", b\\\"\\\")` -- invalid xref or xref \"\n\"is not a (valid) font object. * `(basename, \\\"n/a\\\", \\\"Type1\\\", b\\\"\\\")` \"\n\"-- *basename* is not embedded and thus cannot be extracted. This is the \"\n\"case for e.g. the :ref:`Base-14-Fonts` and Type 3 fonts.\"\nmsgstr \"\"\n\"`(basename, ext, type, content)` のタプルで、ext \"\n\"は3バイトの推奨ファイル拡張子（*str*）で、*basename* はフォントの名前（*str*）で、*type* \"\n\"はフォントのタイプ（例：「Type1」）で、*content* はフォントファイルの内容を含むバイトオブジェクトです（または *b\\\"\\\"* \"\n\"）。可能な拡張子の値とその意味については :ref:`FontExtensions` を参照してください。エラー時の返り値の詳細:\"\n\n#: ../../document.rst:1865 3b2b1686981b408f9b4ca383fc8e0886\nmsgid \"\"\n\"a tuple `(basename, ext, type, content)`, where *ext* is a 3-byte \"\n\"suggested file extension (*str*), *basename* is the font's name (*str*), \"\n\"*type* is the font's type (e.g. \\\"Type1\\\") and *content* is a bytes \"\n\"object containing the font file's content (or *b\\\"\\\"*). For possible \"\n\"extension values and their meaning see :ref:`FontExtensions`. Return \"\n\"details on error:\"\nmsgstr \"\"\n\"`(basename, ext, type, content)` のタプルで、ext \"\n\"は3バイトの推奨ファイル拡張子（*str*）で、*basename* はフォントの名前（*str*）で、*type* \"\n\"はフォントのタイプ（例：「Type1」）で、*content* はフォントファイルの内容を含むバイトオブジェクトです（または *b\\\"\\\"* \"\n\"）。可能な拡張子の値とその意味については :ref:`FontExtensions` を参照してください。エラー時の返り値の詳細:\"\n\n#: ../../document.rst:1867 481c41a571e542b7a7aa786175062a42\nmsgid \"\"\n\"`(\\\"\\\", \\\"\\\", \\\"\\\", b\\\"\\\")` -- invalid xref or xref is not a (valid) font\"\n\" object.\"\nmsgstr \"`(\\\"\\\", \\\"\\\", \\\"\\\", b\\\"\\\")` – 無効な xref または xref が（有効な）フォントオブジェクトではない場合。\"\n\n#: ../../document.rst:1868 cb4b7c40a27e4f8d8952d515656acd8b\nmsgid \"\"\n\"`(basename, \\\"n/a\\\", \\\"Type1\\\", b\\\"\\\")` -- *basename* is not embedded and\"\n\" thus cannot be extracted. This is the case for e.g. the \"\n\":ref:`Base-14-Fonts` and Type 3 fonts.\"\nmsgstr \"\"\n\"`(basename, \\\"n/a\\\", \\\"Type1\\\", b\\\"\\\")` – *basename* \"\n\"は埋め込まれておらず、したがって抽出できません。これは、例えば :ref:`Base-14-Fonts` フォントや Type 3 \"\n\"フォントの場合に該当します。\"\n\n#: ../../document.rst:1870 41ac3a9a578a46a889335bb7b87bcaf6\nmsgid \"Example:\"\nmsgstr \"例:\"\n\n#: ../../document.rst:1879 02cfca352adb406f958c62b5d22f6565\nmsgid \"\"\n\"The basename is returned unchanged from the PDF. So it may contain \"\n\"characters (such as blanks) which may disqualify it as a filename for \"\n\"your operating system. Take appropriate action.\"\nmsgstr \"\"\n\"*ベースネーム* は PDF から変更されずに返されます。そのため、それには (空白などの) \"\n\"ファイル名として使用できない文字が含まれている可能性があります。適切な措置を取ってください。\"\n\n#: ../../document.rst:1882 986fdf8314ca4329828c2ddb689dc2cd\nmsgid \"\"\n\"The returned *basename* in general is **not** the original file name, but\"\n\" it probably has some similarity.\"\nmsgstr \"通常、返される *ベースネーム* は元のファイル名ではなく、いくつかの類似性があるかもしれません。\"\n\n#: ../../document.rst:1883 1a93938a9e004ef4a3f2d30cbd5711b6\nmsgid \"\"\n\"If parameter `named == True`, a dictionary with the following keys is \"\n\"returned: `{'name': 'T1', 'ext': 'n/a', 'type': 'Type3', 'content': \"\n\"b''}`.\"\nmsgstr \"\"\n\"`named == True` の場合、次のキーを持つ辞書が返されます: `{'name': 'T1', 'ext': 'n/a', \"\n\"'type': 'Type3', 'content': b''}`。\"\n\n#: ../../document.rst:1890 bf48f5599c0b4eba92b57c5c2878337f\nmsgid \"PDF only: Return the :data:`xref` of the document's XML metadata.\"\nmsgstr \"PDF のみ: ドキュメントの XML メタデータの :data:`xref` を返します。\"\n\n#: ../../document.rst:1899 b15d00f9e287463e9d85fb59c132c2fb\nmsgid \"\"\n\"PDF only: Check whether there are links, resp. annotations anywhere in \"\n\"the document.\"\nmsgstr \"PDF のみ: ドキュメント内にリンクまたは注釈が存在するかどうかを確認します。\"\n\n#: ../../document.rst:1901 a8ad087d8d95460885065c1393b39d3c\nmsgid \"\"\n\"``True`` / ``False``. As opposed to fields, which are also stored in a \"\n\"central place of a PDF document, the existence of links / annotations can\"\n\" only be detected by parsing each page. These methods are tuned to do \"\n\"this efficiently and will immediately return, if the answer is ``True`` \"\n\"for a page. For PDFs with many thousand pages however, an answer may take\"\n\" some time [#f6]_ if no link, resp. no annotation is found.\"\nmsgstr \"\"\n\"``True`` / ``False`` 。フィールドとは異なり、リンクや注釈の存在は PDF \"\n\"ドキュメントの中心的な場所に格納されているわけではなく、各ページを解析してのみ検出できます。これらのメソッドは効率的に実行するように調整されており、ページに対して\"\n\" ``True`` の回答がある場合、すぐに返されます。ただし、多くのページを持つ PDF \"\n\"の場合、リンクや注釈が見つからない場合、回答に時間がかかることがあります [#f6]_。\"\n\n#: ../../document.rst:1906 e21fcef1343540d1a708042f4c0792a7\nmsgid \"\"\n\"PDF only: Investigate eligible fonts for their use by text in the \"\n\"document. If a font is supported and a size reduction is possible, that \"\n\"font is replaced by a version with a subset of its characters.\"\nmsgstr \"\"\n\"PDF のみ: \"\n\"ドキュメント内のテキストによる使用を検討するための適格なフォントを調査します。サポートされているフォントで、サイズの削減が可能な場合、そのフォントは文字のサブセットを含むバージョンで置換されます。\"\n\n#: ../../document.rst:1908 09503144287d4b18848ae8923ddfa67b\nmsgid \"Use this method immediately before saving the document.\"\nmsgstr \"このメソッドは、ドキュメントを保存する直前に使用します\"\n\n#: ../../document.rst:1910 539a01e1c805488b9294c170eac3feac\nmsgid \"\"\n\"write various progress information to sysout. This currently only has an \"\n\"effect if `fallback` is `True`.\"\nmsgstr \"さまざまな進行状況情報を sysout に書き込みます。現在、これは `fallback` が `True` の場合にのみ効果があります。\"\n\n#: ../../document.rst:1911 8981e0208a9f4e28b42ee5f66a328834\nmsgid \"\"\n\"if `True` use the deprecated algorithm that makes use of package \"\n\"`fontTools <https://pypi.org/project/fonttools/>`_ (which hence must be \"\n\"installed). If using the recommended value `False` (default), MuPDF's \"\n\"native function is used -- which is **very much faster** and can subset a\"\n\" broader range of font types. Package fontTools is not required then.\"\nmsgstr \"\"\n\"`True` の場合、非推奨のアルゴリズムを使用して、パッケージ `fontTools \"\n\"<https://pypi.org/project/fonttools/>`_  を使用します（従って、fontTools \"\n\"がインストールされている必要があります）。推奨される値 `False` （デフォルト）を使用すると、MuPDF \"\n\"のネイティブ関数が使用されます。これは非常に高速で、より広範なフォントタイプをサブセット化できます。この場合、パッケージ fontTools \"\n\"は必要ありません。\"\n\n#: ../../document.rst:1913 a15a1047f45b4352a716896e69d6a301\nmsgid \"\"\n\"The greatest benefit can be achieved when creating new PDFs using large \"\n\"fonts like is typical for Asian scripts. When using the :ref:`Story` \"\n\"class or method :meth:`Page.insert_htmlbox`, multiple fonts may \"\n\"automatically be included -- without the programmer becoming aware of it.\"\nmsgstr \"\"\n\"最大の利点は、アジアのスクリプトに典型的な大きなフォントを使用して新しい PDF を作成する場合に得られます。 :ref:`Story`  \"\n\"クラスまたはメソッド  :meth:`Page.insert_htmlbox`  \"\n\"を使用する場合、複数のフォントが自動的に含まれる場合がありますが、プログラマーが気付かない場合もあります。\"\n\n#: ../../document.rst:1915 7fadfbd8f00548ec9586225f78483b9b\nmsgid \"\"\n\"In all these cases, the set of actually used unicodes mostly is very \"\n\"small compared to the number of glyphs available in the used fonts. Using\"\n\" this method can easily reduce the embedded font binaries by two orders \"\n\"of magnitude -- from several megabytes down to a low two-digit kilobyte \"\n\"amount.\"\nmsgstr \"\"\n\"これらのすべての場合、実際に使用される Unicode \"\n\"のセットは、使用されるフォントの使用可能なグリフの数に比べて非常に小さいことがほとんどです。このメソッドを使用すると、埋め込まれたフォントのバイナリを容易に2桁のキロバイト量にまで減らすことができます。\"\n\n#: ../../document.rst:1917 866600d061f646dbb57bf75dabe4392e\nmsgid \"\"\n\"Creating font subsets leaves behind a large number of large, now unused \"\n\"PDF objects (\\\"ghosts\\\"). Therefore, make sure to compress and garbage-\"\n\"collect when saving the file. We recommend to use \"\n\":meth:`Document.ez_save`.\"\nmsgstr \"\"\n\"フォントのサブセットを作成すると、多数の大きな、今は使用されていない PDF \"\n\"オブジェクト（「ゴースト」）が残ります。そのため、ファイルを保存する際に圧縮およびガベージコレクトを行ってください。:meth:`Document.ez_save`\"\n\" の使用をお勧めします。\"\n\n#: ../../document.rst:1919 024990b74b30463dbc350e966d4356da\nmsgid \"|history_begin|\"\nmsgstr \"\"\n\n#: ../../document.rst:1922 513bd76513be4e288a19f6b96bbaa3ef\nmsgid \"Changed in v1.18.9\"\nmsgstr \"v1.18.9で変更\"\n\n#: ../../document.rst:1923 c85bdf00338b456db45d324b6c867387\nmsgid \"Changed in v1.24.2 use native function of MuPDF.\"\nmsgstr \"v1.24.2 で変更され、MuPDF のネイティブ機能を使用するようになりました。\"\n\n#: ../../document.rst:1925 3535b4d59fd44f9a83c2e71b62145fcd\nmsgid \"|history_end|\"\nmsgstr \"\"\n\n#: ../../document.rst:1930 ../../document.rst:1936 ../../document.rst:1943\n#: ../../document.rst:1950 ../../document.rst:1959 ../../document.rst:1966\n#: ../../document.rst:1975 ../../document.rst:1982 ../../document.rst:1989\n#: ../../document.rst:1998 ../../document.rst:2007\n#: 23c850b632f041fc84bbedf086e50e40 29d64060d52e41a994835f8172a847b0\n#: 60d9d50b61334a3683c961e3a783127f 6b69181c8a7a4cfcaa51258244099614\n#: 92ffa30293174c12bdea4b8d6057552d b587c518ff2b4b239282ddc410c7020a\n#: bda3066db65e4117823bef6cd27678a5 bf910fcc06ee45ccb89cd50ea75979e3\n#: da2ebdf8956f483cb5f692d348eb4f5e dd484398c14a4d69b0296188557677a0\n#: e1bd5bb69f054b608a0564f9de3951e3\nmsgid \"New in v1.19.0\"\nmsgstr \"v1.19.0 で新規追加\"\n\n#: ../../document.rst:1932 e3b3225611884f5f8a13d93a5fa8fed2\nmsgid \"\"\n\"PDF only: Enable journalling. Use this before you start logging \"\n\"operations.\"\nmsgstr \"PDF のみ: ジャーナリングを有効にします。ログ操作を開始する前にこれを使用します。\"\n\n#: ../../document.rst:1938 8249cad73bec4dd3811b53fedbf3851b\nmsgid \"\"\n\"PDF only: Start journalling an *\\\"operation\\\"* identified by a string \"\n\"\\\"name\\\". Updates will fail for a journal-enabled PDF, if no operation \"\n\"has been started.\"\nmsgstr \"\"\n\"PDF のみ: 文字列 \\\"name\\\" で識別される *\\\"操作\\\"* のジャーナリングを開始します。ジャーナリングが有効な PDF \"\n\"に対しては、操作が開始されていない場合、更新が失敗します。\"\n\n#: ../../document.rst:1945 704071b7f7704603a6810cce4ef29486\nmsgid \"\"\n\"PDF only: Stop the current operation. The updates between start and stop \"\n\"of an operation belong to the same unit of work and will be undone / \"\n\"redone together.\"\nmsgstr \"PDF のみ: 現在の操作を停止します。操作の開始から終了までの間の更新は、同じユニットの作業に属し、一緒に元に戻される / やり直されます。\"\n\n#: ../../document.rst:1952 8856cfd27a08421e8a3a415ac03757b5\nmsgid \"\"\n\"PDF only: Return the numbers of the current operation and the total \"\n\"operation count.\"\nmsgstr \"PDF のみ: 現在の操作番号と総操作数を返します。\"\n\n#: ../../document.rst:1954 7aef4dabfe7f42ee8e132777108552c3\nmsgid \"\"\n\"a tuple `(step, steps)` containing the current operation number and the \"\n\"total number of operations in the journal. If **step** is 0, we are at \"\n\"the top of the journal. If **step** equals **steps**, we are at the \"\n\"bottom. Updating the PDF with anything other than undo or redo will \"\n\"automatically remove all journal entries after the current one and the \"\n\"new update will become the new last entry in the journal. The updates \"\n\"corresponding to the removed journal entries will be permanently lost.\"\nmsgstr \"\"\n\"ジャーナル内の現在の操作番号と総操作数を含むタプル `(step, steps)` が返されます。**step** が 0 \"\n\"の場合、ジャーナルの先頭にいることを示します。**step** が **steps** \"\n\"と等しい場合、ジャーナルの末尾にいることを示します。undo または redo 以外の何かで PDF \"\n\"を更新すると、現在のエントリ以降のすべてのジャーナルエントリが自動的に削除され、新しい更新がジャーナルの新しい最後のエントリになります。削除されたジャーナルエントリに対応する更新は永久に失われます。\"\n\n#: ../../document.rst:1961 5804540e567442e986c965d58055649e\nmsgid \"PDF only: Return the name of operation number *step.*\"\nmsgstr \"PDF のみ: 操作番号 *step* の操作名を返します。\"\n\n#: ../../document.rst:1968 f0a5f14026814bc0838219dad0e6c78d\nmsgid \"\"\n\"PDF only: Show whether forward (\\\"redo\\\") and / or backward (\\\"undo\\\") \"\n\"executions are possible from the current journal position.\"\nmsgstr \"PDF のみ: 現在のジャーナル位置から前方（\\\"やり直し\\\"）および後方（\\\"元に戻す\\\"）の実行が可能かどうかを表示します。\"\n\n#: ../../document.rst:1970 5066e32c51d74905ac1aaf5bb22faf52\nmsgid \"\"\n\"a dictionary `{\\\"undo\\\": bool, \\\"redo\\\": bool}`. The respective method is\"\n\" available if its value is `True`.\"\nmsgstr \"`{\\\"undo\\\": bool, \\\"redo\\\": bool}` 形式の辞書。各メソッドはその値が `True` の場合に利用可能です。\"\n\n#: ../../document.rst:1977 bca8256424854422903812de1880cf69\nmsgid \"\"\n\"PDF only: Revert (undo) the current step in the journal. This moves \"\n\"towards the journal's top.\"\nmsgstr \"PDF のみ: ジャーナル内の現在のステップを元に戻します（元に戻す）。これにより、ジャーナルの先頭に向かって移動します。\"\n\n#: ../../document.rst:1984 c840e9624cdb422484fa864d8235880f\nmsgid \"\"\n\"PDF only: Re-apply (redo) the current step in the journal. This moves \"\n\"towards the journal's bottom.\"\nmsgstr \"PDF のみ：現在のステップをジャーナルのボトムに戻して再適用します。\"\n\n#: ../../document.rst:1991 58b8caa5be0c42e4ad1af76dfb16eb62\nmsgid \"PDF only: Save the journal to a file.\"\nmsgstr \"PDF のみ：ジャーナルをファイルに保存します。\"\n\n#: ../../document.rst:1993 64c4bc40fb8f405e9953e7eb030677d4\nmsgid \"\"\n\"either a filename as string or a file object opened as \\\"wb\\\" (or an \"\n\"`io.BytesIO()` object).\"\nmsgstr \"文字列としてのファイル名または \\\"wb\\\" で開かれたファイルオブジェクト (または `io.BytesIO()` オブジェクト)。\"\n\n#: ../../document.rst:2000 b77b3dcb8b40499faf7067ff14e0ac3d\nmsgid \"\"\n\"PDF only: Load journal from a file. Enables journalling for the document.\"\n\" If journalling is already enabled, an exception is raised.\"\nmsgstr \"\"\n\"PDF \"\n\"のみ：ファイルからジャーナルを読み込みます。ドキュメントのジャーナリングを有効にします。既にジャーナリングが有効になっている場合、例外が発生します。\"\n\n#: ../../document.rst:2002 4961c34dc2e34a79bc11de4657129a91\nmsgid \"\"\n\"the filename (str) of the journal or a file object opened as \\\"rb\\\" (or \"\n\"an `io.BytesIO()` object).\"\nmsgstr \"ジャーナルのファイル名 (str) または \\\"rb\\\" で開かれたファイルオブジェクト (または `io.BytesIO()` オブジェクト)。\"\n\n#: ../../document.rst:2009 b7d0c0f588064a908bf9eb652ed74157\nmsgid \"\"\n\"PDF only: Saves a \\\"snapshot\\\" of the document. This is a PDF document \"\n\"with a special, incremental-save format compatible with journalling -- \"\n\"therefore no save options are available. Saving a snapshot is not \"\n\"possible for new documents.\"\nmsgstr \"\"\n\"PDF のみ：ドキュメントの「スナップショット」を保存します。これは、ジャーナリングと互換性のある特別なインクリメンタルセーブ形式を持つ PDF \"\n\"ドキュメントです。そのため、セーブオプションは利用できません。新しいドキュメントにはスナップショットを保存することはできません。\"\n\n#: ../../document.rst:2011 2545bccc73fa4299b3e544581d325b2d\nmsgid \"\"\n\"This is a normal PDF document with no usage restrictions whatsoever. If \"\n\"it is not being changed in any way, it can be used together with its \"\n\"journal to undo / redo operations or continue updating.\"\nmsgstr \"\"\n\"これは通常の PDF \"\n\"ドキュメントで、制限はありません。何も変更されていない場合、そのスナップショットはジャーナルと共に操作を元に戻したり、やり直したり、更新を続けたりするために使用できます。\"\n\n#: ../../document.rst:2016 e424a27e6b2643928977f3d6aa555cb3\nmsgid \"\"\n\"Contains the first :ref:`Outline` entry of the document (or `None`). Can \"\n\"be used as a starting point to walk through all outline items. Accessing \"\n\"this property for encrypted, not authenticated documents will raise an \"\n\"*AttributeError*.\"\nmsgstr \"\"\n\"ドキュメントの最初のアウトラインエントリを含みます (または \"\n\"`None`)。すべてのアウトラインアイテムを歩く出発点として使用できます。暗号化された、認証されていないドキュメントに対してこのプロパティにアクセスすると、*AttributeError*\"\n\" が発生します。\"\n\n#: ../../document.rst 1602273cc936401281de518030afe066\n#: 16f29bf99132426f87c8a1a3a19e00e2 28f47def4ae34ebba8d1b7ed547bef39\n#: 2d1462d16cab46708c2ea82e0c12389d 3042551ff76e414a8b0fbd0249e3dbc2\n#: 32ae939840b646df97a2f59c6dbbb95d 37ba5b84daea4a13bd04359c6cd8f01d\n#: 610be889b0ed46b6b67b919761c5328c 7198eba9028c42ab86329761fdd6189d\n#: 7f3d268e33dc4d32ade745103b248f42 8757f1490fa24ef3a7e6900eece671f5\n#: 8c9cfec8c566490b9639225e031a57fe a081d38bf1be4385a577bfc95efe4956\n#: a15d802d6d3f4b57988cd8306eb4c8ef a4df564b9c0a486e84405a39b6299935\n#: b1f9eacd35de4db691b1ed0287a78333 bb8e4f6e9b2c4e09abe1a99243658dca\n#: c4a68e2e7f19437b8849a9ffe38fbf3b cda3e67477524036890a97e0103ac73b\n#: ce0880d44e354062a461cde8ea9b8ecc f50c8eac8d5b46b989ee843ce5e55e52\nmsgid \"type\"\nmsgstr \"タイプ\"\n\n#: ../../document.rst:2018 09f8caef7fbd48cd82a0924621d2a9e0\nmsgid \":ref:`Outline`\"\nmsgstr \"\"\n\n#: ../../document.rst:2022 f6902ea6d7c74e0e9df77ba8f44bc184\nmsgid \"\"\n\"``False`` if document is still open. If closed, most other attributes and\"\n\" methods will have been deleted / disabled. In addition, :ref:`Page` \"\n\"objects referring to this document (i.e. created with \"\n\":meth:`Document.load_page`) and their dependent objects will no longer be\"\n\" usable. For reference purposes, :attr:`Document.name` still exists and \"\n\"will contain the filename of the original document (if applicable).\"\nmsgstr \"\"\n\"もし文書がまだ開いている場合は ``False`` \"\n\"です。閉じた場合、他のほとんどの属性やメソッドが削除されたり無効になります。また、この文書を参照する :ref:`Page` \"\n\"オブジェクト（すなわち :meth:`Document.load_page` \"\n\"で作成されたもの）とそれに依存するオブジェクトは利用できなくなります。参照用に、:attr:`Document.name` \"\n\"はまだ存在し、元の文書のファイル名が含まれます（該当する場合）。\"\n\n#: ../../document.rst:2024 ../../document.rst:2030 ../../document.rst:2036\n#: ../../document.rst:2050 ../../document.rst:2058 ../../document.rst:2066\n#: ../../document.rst:2104 ../../document.rst:2110\n#: 0cefab557d984344bfda0158a1f52684 394c1dd8d7534572ba79ebb0cccca67f\n#: 66e5ea720bed4a8db1dc0ce57284dd20 7727b1750813444ba91203426800b004\n#: 7e8cf3312cff4ac48dce16a36311f52a aa51fa3df40249eaa4a1e1a0d5310e13\n#: d9e029f9473442ebbb79145d3e00c7d3 f2ab1deb6ba9463aaa494cc84adb11ea\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../document.rst:2028 be46ed59c726495784dfc24c6c0e257d\nmsgid \"\"\n\"``True`` if this is a PDF document and contains unsaved changes, else \"\n\"``False``.\"\nmsgstr \"これがPDFドキュメントであり、保存されていない変更が含まれている場合は ``True`` 、それ以外は ``False`` です。\"\n\n#: ../../document.rst:2034 b53c8bd571224a64808858ec1262f49c\nmsgid \"``True`` if this is a PDF document, else ``False``.\"\nmsgstr \"これがPDFドキュメントである場合は ``True`` 、それ以外は ``False`` です。\"\n\n#: ../../document.rst:2040 5b077860c7f84173a695652fa22ede87\nmsgid \"\"\n\"``False`` if this is not a PDF or has no form fields, otherwise the \"\n\"number of root form fields (fields with no ancestors).\"\nmsgstr \"\"\n\"これがPDFでないか、フォームフィールドが含まれていない場合は ``False`` \"\n\"であり、それ以外の場合はルートフォームフィールド（祖先のないフィールド）の数です。\"\n\n#: ../../document.rst:2042 c94346686fa04426a6f4827511abb382\nmsgid \"*(Changed in v1.16.4)* Returns the total number of (root) form fields.\"\nmsgstr \"*（v1.16.4で変更）* （ルート）フォームフィールドの合計数を返します。\"\n\n#: ../../document.rst:2044 64d2a67af100488b8d2efa6e1883d02a\nmsgid \"bool,int\"\nmsgstr \"\"\n\n#: ../../document.rst:2048 c2a8e91d886f4dd39afa57c9e57ace12\nmsgid \"\"\n\"``True`` if document has a variable page layout (like e-books or HTML). \"\n\"In this case you can set the desired page dimensions during document \"\n\"creation (open) or via method :meth:`layout`.\"\nmsgstr \"\"\n\"文書が可変ページレイアウト（電子書籍やHTMLのような）を持つ場合は ``True`` です。この場合、文書の作成（オープン）時または \"\n\":meth:`layout` メソッドを使用して所望のページ寸法を設定できます。\"\n\n#: ../../document.rst:2054 097934b832ba49788816a0be330fcc4d\nmsgid \"New in v1.18.2\"\nmsgstr \"v1.18.2で新しく追加されました。\"\n\n#: ../../document.rst:2056 a3953a101b3d436c889b977615129521\nmsgid \"\"\n\"``True`` if PDF has been repaired during open (because of major structure\"\n\" issues). Always ``False`` for non-PDF documents. If true, more details \"\n\"have been stored in `TOOLS.mupdf_warnings()`, and \"\n\":meth:`Document.can_save_incrementally` will return ``False``.\"\nmsgstr \"\"\n\"PDFがオープン時に修復された場合は ``True`` です（主要な構造上の問題のため）。非PDF文書の場合は常に ``False`` \"\n\"です。``True`` の場合、詳細は `TOOLS.mupdf_warnings()` \"\n\"に保存され、:meth:`Document.can_save_incrementally` は ``False`` を返します。\"\n\n#: ../../document.rst:2064 2cce725fd9f3422f8aecbdee94679aea\nmsgid \"``True`` if PDF is in linearized format. ``False`` for non-PDF documents.\"\nmsgstr \"PDFが直線化形式である場合は ``True`` です。非PDF文書の場合はFalseです。\"\n\n#: ../../document.rst:2072 f3bed56567f343e7be019a7113151958\nmsgid \"\"\n\"A dictionary indicating the `/MarkInfo` value. If not specified, the \"\n\"empty dictionary is returned. If not a PDF, `None` is returned.\"\nmsgstr \"`/MarkInfo` の値を示す辞書です。指定されていない場合、空の辞書が返されます。PDFでない場合は `None` が返されます。\"\n\n#: ../../document.rst:2074 ../../document.rst:2138\n#: 4fac34bbddf141cc9db4746145385918 c43c67dc2942407d8e9945f28ce574e8\nmsgid \"dict\"\nmsgstr \"\"\n\n#: ../../document.rst:2080 3c2381448f9746669bed68baf5d9bb53\nmsgid \"\"\n\"A string containing the `/PageMode` value. If not specified, the default \"\n\"\\\"UseNone\\\" is returned. If not a PDF, `None` is returned.\"\nmsgstr \"\"\n\"`/PageMode` の値を含む文字列です。指定されていない場合、デフォルトの「UseNone」が返されます。PDFでない場合、`None` \"\n\"が返されます。\"\n\n#: ../../document.rst:2082 ../../document.rst:2090 ../../document.rst:2144\n#: 3be5c37120cd4a79b8474f458308b81a 531912d21abf43ce967a311e2f37dbb5\n#: 68eeac57aeee49e799a0fb10f3ff10db\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../document.rst:2088 94d13e47f92c425ca9ceffd8061d5b3c\nmsgid \"\"\n\"A string containing the `/PageLayout` value. If not specified, the \"\n\"default \\\"SinglePage\\\" is returned. If not a PDF, `None` is returned.\"\nmsgstr \"\"\n\"`/PageLayout` \"\n\"の値を含む文字列です。指定されていない場合、デフォルトの「SinglePage」が返されます。PDFでない場合、`None` が返されます。\"\n\n#: ../../document.rst:2096 376302c8e2864821a4ed3203d7970057\nmsgid \"\"\n\"An integer counting the number of versions present in the document. Zero \"\n\"if not a PDF, otherwise the number of incremental saves plus one.\"\nmsgstr \"ドキュメント内に存在するバージョンの数をカウントする整数です。PDFでない場合、ゼロです。それ以外の場合、増分保存の数に1を加えたものです。\"\n\n#: ../../document.rst:2098 ../../document.rst:2118 ../../document.rst:2150\n#: ../../document.rst:2158 ../../document.rst:2166\n#: 3ccae1d5a11a4795b4cb9fbb7abb90fb 551cfa067ca747078f3544b2b9a4c75d\n#: 6dc1779125fa4a5e89941961eedf2852 c694fc32adcc41ba87ad799a94b4e7e4\n#: e3e8e1e7807b4796bdf0baacbe43920e\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../document.rst:2102 15c8db41a1944a7bbc1153ac5f6933af\nmsgid \"\"\n\"Indicates whether the document is password-protected against access. This\"\n\" indicator remains unchanged -- **even after the document has been \"\n\"authenticated**. Precludes incremental saves if true.\"\nmsgstr \"\"\n\"ドキュメントがアクセス制限のあるパスワードで保護されているかどうかを示します。この指示は、**ドキュメントが認証された後も** 変更されません。 \"\n\"`True` の場合、増分保存が不可能です。\"\n\n#: ../../document.rst:2108 cfd83d7fc9914f1ea0b309e4421dafc9\nmsgid \"\"\n\"This indicator initially equals :attr:`Document.needs_pass`. After \"\n\"successful authentication, it is set to ``False`` to reflect the \"\n\"situation.\"\nmsgstr \"\"\n\"この指示は、最初に :attr:`Document.needs_pass` と等しいです。認証が成功した後、状況を反映するために \"\n\"``False`` に設定されます。\"\n\n#: ../../document.rst:2114 9694db51001240f19eb22fb0d5f7c271\nmsgid \"\"\n\"Changed in v1.16.0: This is now an integer comprised of bit indicators. \"\n\"Was a dictionary previously.\"\nmsgstr \"\"\n\n#: ../../document.rst:2116 1db1f23f8ebc4475b568658aa43f199a\nmsgid \"\"\n\"Contains the permissions to access the document. This is an integer \"\n\"containing bool values in respective bit positions. For example, if \"\n\"*doc.permissions & pymupdf.PDF_PERM_MODIFY > 0*, you may change the \"\n\"document. See :ref:`PermissionCodes` for details.\"\nmsgstr \"\"\n\"アクセス許可を示します。これは、対応するビット位置にbool値を含む整数です。例えば、*doc.permissions & \"\n\"pymupdf.PDF_PERM_MODIFY > 0*  \"\n\"の場合、ドキュメントを変更できます。詳細については、:ref:`PermissionCodes` を参照してください。\"\n\n#: ../../document.rst:2122 7962fdc44f174396b7e69eae4e54c130\nmsgid \"\"\n\"Contains the document's meta data as a Python dictionary or `None` (if \"\n\"*is_encrypted=True* and *needPass=True*). Keys are *format*, \"\n\"*encryption*, *title*, *author*, *subject*, *keywords*, *creator*, \"\n\"*producer*, *creationDate*, *modDate*, *trapped*. All item values are \"\n\"strings or `None`.\"\nmsgstr \"\"\n\"文書のメタデータをPythonの辞書形式で含んでいます。ただし、*is_encrypted=True* かつ *needPass=True* \"\n\"の場合は `None` です。キーは \"\n\"*format*、*encryption*、*title*、*author*、*subject*、*keywords*、*creator*、*producer*、*creationDate*、*modDate*、*trapped*\"\n\" です。すべてのアイテムの値は文字列または `None` です。\"\n\n#: ../../document.rst:2124 6cfc801351f94f7b861f48bb410d28c7\nmsgid \"\"\n\"Except *format* and *encryption*, for PDF documents, the key names \"\n\"correspond in an obvious way to the PDF keys */Creator*, */Producer*, \"\n\"*/CreationDate*, */ModDate*, */Title*, */Author*, */Subject*, */Trapped* \"\n\"and */Keywords* respectively.\"\nmsgstr \"\"\n\"*format* と *encryption* を除いて、PDF 文書の場合、キー名は明らかな方法で PDF キー \"\n\"*/Creator*、*/Producer*、*/CreationDate*、*/ModDate*、*/Title*、*/Author*、*/Subject*、*/Trapped*、*/Keywords*\"\n\" に対応しています。\"\n\n#: ../../document.rst:2126 f20bf71e53de47268b103331add7edf9\nmsgid \"*format* contains the document format (e.g. 'PDF-1.6', 'XPS', 'EPUB').\"\nmsgstr \"*format* には文書のフォーマット（例： 'PDF-1.6'、'XPS'、'EPUB'）が含まれます。\"\n\n#: ../../document.rst:2128 3efef9d77a4c425db7765bd868246cfe\nmsgid \"\"\n\"*encryption* either contains `None` (no encryption), or a string naming \"\n\"an encryption method (e.g. *'Standard V4 R4 128-bit RC4'*). Note that an \"\n\"encryption method may be specified **even if** *needs_pass=False*. In \"\n\"such cases not all permissions will probably have been granted. Check \"\n\":attr:`Document.permissions` for details.\"\nmsgstr \"\"\n\"*encryption* には `None` （暗号化なし）または暗号化メソッドを示す文字列（例： *'Standard V4 R4 \"\n\"128-bit RC4'*） が含まれます。 *needs_pass=False* \"\n\"の場合でも暗号化メソッドが指定される場合があります。その場合、すべての権限が付与されていない可能性があります。詳細は \"\n\":attr:`Document.permissions` を確認してください。\"\n\n#: ../../document.rst:2130 9d90a31d5dc443e499dc24e80ac6a7fd\nmsgid \"\"\n\"If the date fields contain valid data (which need not be the case at \"\n\"all!), they are strings in the PDF-specific timestamp format \"\n\"\\\"D:<TS><TZ>\\\", where\"\nmsgstr \"\"\n\"日付フィールドに有効なデータが含まれている場合（必ずしもそうである必要はありません！）、それらは PDF 固有のタイムスタンプ形式 \"\n\"\\\"D:<TS><TZ>\\\" の文字列です。\"\n\n#: ../../document.rst:2132 20a10dd0049e479fb79845780b64734a\nmsgid \"\"\n\"<TS> is the 12 character ISO timestamp *YYYYMMDDhhmmss* (*YYYY* - year, \"\n\"*MM* - month, *DD* - day, *hh* - hour, *mm* - minute, *ss* - second), and\"\nmsgstr \"\"\n\"<TS> は 12 文字の ISO タイムスタンプ YYYYMMDDhhmmss（*YYYY* - 年、*MM* - 月、*DD* - \"\n\"日、*hh* - 時、*mm* - 分、*ss* - 秒）であり、\"\n\n#: ../../document.rst:2134 5da96c47c93747d58f34b49ac5ef58cd\nmsgid \"\"\n\"<TZ> is a time zone value (time interval relative to GMT) containing a \"\n\"sign ('+' or '-'), the hour (*hh*), and the minute (*'mm'*, note the \"\n\"apostrophes!).\"\nmsgstr \"\"\n\"<TZ> は GMT に対する時刻間隔を示す符号（'+' または \"\n\"'-'）、時間（*hh*）、および分（*'mm'*、アポストロフィに注意！）を含むタイムゾーン値です。\"\n\n#: ../../document.rst:2136 22d1786adac24570a27a1aae46488101\nmsgid \"\"\n\"A Paraguayan value might hence look like *D:20150415131602-04'00'*, which\"\n\" corresponds to the timestamp April 15, 2015, at 1:16:02 pm local time \"\n\"Asuncion.\"\nmsgstr \"\"\n\"したがって、パラグアイの値は *D:20150415131602-04'00'* となり、これは Asuncion の現地時間で 2015 年 4\"\n\" 月 15 日午後 1 時 16 分 02 秒を表します。\"\n\n#: ../../document.rst:2142 b0cf324cb8914ca695f619ae42bd9652\nmsgid \"\"\n\"Contains the *filename* or *filetype* value with which *Document* was \"\n\"created.\"\nmsgstr \"*Document* が作成された *ファイル名* または *ファイルタイプ* の値を含みます。\"\n\n#: ../../document.rst:2148 7f4ed0f5c41e456189313cbfc5952e49\nmsgid \"\"\n\"Contains the number of pages of the document. May return 0 for documents \"\n\"with no pages. Function `len(doc)` will also deliver this result.\"\nmsgstr \"文書のページ数を含みます。ページがない文書の場合は 0 を返す場合があります。`len(doc)` 関数もこの結果を返します。\"\n\n#: ../../document.rst:2154 ../../document.rst:2162\n#: 73610f94f5a34127a2dda3a113913b25 c06566f44d3f4e20a91862264e4a1c99\nmsgid \"New in v1.17.0\"\nmsgstr \"v1.17.0 で新たに追加されました\"\n\n#: ../../document.rst:2156 8cf8164c876c405e800d30202732e6f6\nmsgid \"\"\n\"Contains the number of chapters in the document. Always at least 1. \"\n\"Relevant only for document types with chapter support (EPUB currently). \"\n\"Other documents will return 1.\"\nmsgstr \"\"\n\"文書の章の数を含みます。常に少なくとも 1 です。章のサポートがある文書タイプ（現在は EPUB のみ）にのみ関連します。その他の文書は 1 \"\n\"を返します。\"\n\n#: ../../document.rst:2164 e5dfbd74ae114264bf5b918a7e215bda\nmsgid \"\"\n\"Contains (chapter, pno) of the document's last page. Relevant only for \"\n\"document types with chapter support (EPUB currently). Other documents \"\n\"will return `(0, page_count - 1)` and `(0, -1)` if it has no pages.\"\nmsgstr \"\"\n\"文書の最後のページの（章、pno）を含みます。章のサポートがある文書タイプ（現在は EPUB のみ）にのみ関連します。その他の文書は `(0, \"\n\"page_count - 1)` と `(0, -1)` を返します。\"\n\n#: ../../document.rst:2170 6161488e20a3440a8af171ec632bfd3e\nmsgid \"\"\n\"A list of form field font names defined in the */AcroForm* object. `None`\"\n\" if not a PDF.\"\nmsgstr \"*/AcroForm* オブジェクトで定義されたフォームフィールドのフォント名のリストです。PDF でない場合は `None` です。\"\n\n#: ../../document.rst:2172 ef0288df376442b1b18ffdc60b13aad3\nmsgid \"list\"\nmsgstr \"\"\n\n#: ../../document.rst:2174 3cddcafda79b4acfa4346bad9396da59\nmsgid \"\"\n\"For methods that change the structure of a PDF (:meth:`insert_pdf`, \"\n\":meth:`select`, :meth:`copy_page`, :meth:`delete_page` and others), be \"\n\"aware that objects or properties in your program may have been \"\n\"invalidated or orphaned. Examples are :ref:`Page` objects and their \"\n\"children (links, annotations, widgets), variables holding old page \"\n\"counts, tables of content and the like. Remember to keep such variables \"\n\"up to date or delete orphaned objects. Also refer to \"\n\":ref:`ReferenialIntegrity`.\"\nmsgstr \"\"\n\"PDFの構造を変更するメソッド \"\n\"(:meth:`insert_pdf`、:meth:`select`、:meth:`copy_page`、:meth:`delete_page` \"\n\"など）を使用する場合、プログラム内のオブジェクトやプロパティが無効化されたり孤立したりする可能性があることに注意してください。これには \"\n\":ref:`Page` \"\n\"オブジェクトとその子要素（リンク、注釈、ウィジェット）、古いページ数を保持する変数、目次などが含まれます。このような変数を最新の情報に保つか、孤立したオブジェクトを削除することを忘れないでください。:ref:`ReferenialIntegrity`\"\n\" も参照してください。\"\n\n#: ../../document.rst:2177 a2398cf6ad98476d944c903b70fee21b\nmsgid \":meth:`set_metadata` Example\"\nmsgstr \":meth:`set_metadata` の例\"\n\n#: ../../document.rst:2178 ddf7de671f964452acd94d777e10a07d\nmsgid \"\"\n\"Clear metadata information. If you do this out of privacy / data \"\n\"protection concerns, make sure you save the document as a new file with \"\n\"*garbage > 0*. Only then the old */Info* object will also be physically \"\n\"removed from the file. In this case, you may also want to clear any XML \"\n\"metadata inserted by several PDF editors:\"\nmsgstr \"\"\n\"メタデータ情報をクリアします。プライバシー/データ保護の理由からこれを行う場合は、*ガベージ > 0* \"\n\"でドキュメントを新しいファイルとして保存してから古い */Info* \"\n\"オブジェクトもファイルから物理的に削除されることを確認してください。この場合、いくつかのPDFエディタによって挿入されたXMLメタデータもクリアすることを検討するかもしれません。\"\n\n#: ../../document.rst:2196 642d2b67cd2f40c088b9ab627d5bcce7\nmsgid \":meth:`set_toc` Demonstration\"\nmsgstr \":meth:`set_toc` のデモンストレーション\"\n\n#: ../../document.rst:2197 23344c44c0964dfd87e2ed6368dfe5f2\nmsgid \"\"\n\"This shows how to modify or add a table of contents. Also have a look at \"\n\"`import.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/import-toc/import.py>`_ and `export.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples\"\n\"/export-toc/export.py>`_ in the examples directory.\"\nmsgstr \"\"\n\"これは、目次を変更または追加する方法を示しています。また、examplesディレクトリにある `import.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/import-toc/import.py>`_ と `export.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/examples/export-toc/export.py>`_ \"\n\"も参照してみてください。\"\n\n#: ../../document.rst:2217 c5bd350315cb42bb9d44f2ed5f142cf7\nmsgid \":meth:`insert_pdf` Examples\"\nmsgstr \":meth:`insert_pdf` の例\"\n\n#: ../../document.rst:2218 37f35aaa221e450b9c7923b3fb645393\nmsgid \"**(1) Concatenate two documents including their TOCs:**\"\nmsgstr \"**（1）2つの文書を連結して、それぞれの目次を含める：**\"\n\n#: ../../document.rst:2230 19d9ac4c4ce54408a9ff1fc42b2ec3ab\nmsgid \"\"\n\"Obviously, similar ways can be found in more general situations. Just \"\n\"make sure that hierarchy levels in a row do not increase by more than \"\n\"one. Inserting dummy bookmarks before and after *toc2* segments would \"\n\"heal such cases. A ready-to-use GUI (wxPython) solution can be found in \"\n\"script `join.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/join-documents/join.py>`_ of the examples \"\n\"directory.\"\nmsgstr \"\"\n\"明らかに、より一般的な状況についても同様の方法が見つかるでしょう。連続するヒエラルキーレベルが1以上増加しないように注意してください。 \"\n\"**toc2** \"\n\"セグメントの前後にダミーのブックマークを挿入することで、そのような場合を修正できます。すぐに使用できるGUI（wxPython）の解決策は、examplesディレクトリのスクリプト\"\n\" `join.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/join-documents/join.py>`_  で見つけることができます。\"\n\n#: ../../document.rst:2232 ec37bfa672424492b706bb55ae38792d\nmsgid \"**(2) More examples:**\"\nmsgstr \"**（2）その他の例：**\"\n\n#: ../../document.rst:2244 daa47d21176046b3b8cdcc9a15eff373\nmsgid \"Other Examples\"\nmsgstr \"他の例\"\n\n#: ../../document.rst:2245 25b5f7ff173e4cbb974822ddf15bda53\nmsgid \"**Extract all page-referenced images of a PDF into separate PNG files**::\"\nmsgstr \"**PDF内のすべてのページ参照画像を個別のPNGファイルに抽出します**::\"\n\n#: ../../document.rst:2260 9dcc333da1824dcb84886586cf37039d\nmsgid \"**Rotate all pages of a PDF:**\"\nmsgstr \"**PDFのすべてのページを回転させます：**\"\n\n#: ../../document.rst:2265 00e524b709ed425197a1390a21596acd\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../document.rst:2266 a15a2e8120a74e39a05d411ee7c1c7d1\nmsgid \"\"\n\"Content streams describe what (e.g. text or images) appears where and how\"\n\" on a page. PDF uses a specialized mini language similar to PostScript to\"\n\" do this (pp. 643 in :ref:`AdobeManual`), which gets interpreted when a \"\n\"page is loaded.\"\nmsgstr \"\"\n\"コンテンツストリームは、ページ上に何が表示され、どのように表示されるかを説明します。PDFは、ページが読み込まれると解釈される、PostScriptに似た専門のミニ言語を使用しています（:ref:`AdobeManual`\"\n\" のpp. 643）。\"\n\n#: ../../document.rst:2268 ca3b618244bb41b19d1e10271e0d41c1\nmsgid \"\"\n\"However, you **can** use :meth:`Document.get_toc` and \"\n\":meth:`Page.get_links` (which are available for all document types) and \"\n\"copy this information over to the output PDF. See demo `convert.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/convert-document/convert.py>`_.\"\nmsgstr \"\"\n\"ただし、:meth:`Document.get_toc` と :meth:`Page.get_links` \"\n\"（すべてのドキュメントタイプで利用可能）を使用して、この情報を出力PDFにコピーできます。デモ `convert.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/convert-document/convert.py>`_ を参照してください。\"\n\n#: ../../document.rst:2270 6f0e49f40f3b42b282cf974f985eacf7\nmsgid \"\"\n\"For applicable (EPUB) document types, loading a page via its absolute \"\n\"number may result in layouting a large part of the document, before the \"\n\"page can be accessed. To avoid this performance impact, prefer chapter-\"\n\"based access. Use convenience methods and attributes \"\n\":meth:`Document.next_location`, :meth:`Document.prev_location` and \"\n\":attr:`Document.last_location` for maintaining a high level of coding \"\n\"efficiency.\"\nmsgstr \"\"\n\"該当する（EPUB）ドキュメントタイプの場合、絶対番号でページを読み込むと、ページにアクセスする前にドキュメントの大部分のレイアウトが発生する場合があります。このパフォーマンスへの影響を避けるために、章ベースのアクセスを優先します。:meth:`Document.prev_location`、:attr:`Document.last_location`、:attr:`Document.last_location`\"\n\" といった便利なメソッドや属性を使用して、高いコーディング効率を維持してください。\"\n\n#: ../../document.rst:2272 7e142ce80a5a4b0a88149a89bca628b3\nmsgid \"\"\n\"These parameters cause separate handling of stream categories: use it \"\n\"together with `expand` to restrict decompression to streams other than \"\n\"images / fontfiles.\"\nmsgstr \"\"\n\"これらのパラメータはストリームカテゴリの別々の処理を引き起こします：これらを `expand` \"\n\"と一緒に使用して、画像やフォントファイル以外のストリームの解凍を制限できます。\"\n\n#: ../../document.rst:2274 03c1d89d03c1475593eabb3e4292b9a3\nmsgid \"Examples for \\\"Form XObjects\\\" are created by :meth:`Page.show_pdf_page`.\"\nmsgstr \"「Form XObjects」の例は、:meth:`Page.show_pdf_page` によって作成されます。\"\n\n#: ../../document.rst:2276 7a2f02a6696b4fbe97fb5959655cf631\nmsgid \"\"\n\"For a ``False`` the **complete document** must be scanned. Both methods \"\n\"**do not load pages,** but only scan object definitions. This makes them \"\n\"at least 10 times faster than application-level loops (where total \"\n\"response time roughly equals the time for loading all pages). For the \"\n\":ref:`AdobeManual` (756 pages) and the Pandas documentation (over 3070 \"\n\"pages) -- both have no annotations -- the method needs about 11 ms for \"\n\"the answer ``False``. So response times will probably become significant \"\n\"only well beyond this order of magnitude.\"\nmsgstr \"\"\n\"``False`` の場合、完全なドキュメントをスキャンする必要があります。ただし、これらのメソッドは \"\n\"**ページを読み込まず**、オブジェクト定義のみをスキャンします。これにより、アプリケーションレベルのループよりも少なくとも10倍高速になります（合計応答時間はすべてのページを読み込む時間とほぼ同じです）。:ref:`AdobeManual`（756ページ）とPandasのドキュメンテーション（3070ページ以上）の両方に注釈がない場合、このメソッドは\"\n\" ``False`` \"\n\"の回答に約11ミリ秒かかります。したがって、応答時間はおそらくこのオーダーオブマグニチュードをはるかに超えた範囲で初めて重要になる可能性があります。\"\n\n#: ../../document.rst:2278 877071710b344f2f93ce93231f4a36a5\nmsgid \"\"\n\"This only works under certain conditions. For example, if there is normal\"\n\" text covered by some image on top of it, then this is undetectable and \"\n\"the respective text is **not** removed. Similar is true for white text on\"\n\" white background, and so on.\"\nmsgstr \"\"\n\"これは特定の条件下でのみ機能します。たとえば、上に何らかの画像が覆っている通常のテキストがある場合、これは検出不可能で、該当するテキストは削除 \"\n\"**されません**。同様に、白い背景の白いテキストなども同様です。\"\n\n#: ../../footer.rst:46 1a755c93e67b4ba193138e8e29cfc599\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"a list of lists. Each entry has\"\n#~ \" the form *[lvl, title, page, dest]*.\"\n#~ \" Its entries have the following \"\n#~ \"meanings:  * *lvl* -- hierarchy level\"\n#~ \" (positive *int*). The first entry is\"\n#~ \" always 1. Entries in a row are\"\n#~ \" either **equal**, **increase** by 1, \"\n#~ \"or **decrease** by any number. * \"\n#~ \"*title* -- title (*str*) * *page* \"\n#~ \"-- 1-based page number (*int*). If \"\n#~ \"`-1` either no destination or outside\"\n#~ \" document. * *dest* -- (*dict*) \"\n#~ \"included only if *simple=False*. Contains \"\n#~ \"details of the TOC item as \"\n#~ \"follows:    - kind: destination kind, \"\n#~ \"see :ref:`linkDest Kinds`.   - file: \"\n#~ \"filename if kind is :data:`LINK_GOTOR` \"\n#~ \"or :data:`LINK_LAUNCH`.   - page: target \"\n#~ \"page, 0-based, :data:`LINK_GOTOR` or \"\n#~ \":data:`LINK_GOTO` only.   - to: position \"\n#~ \"on target page (:ref:`Point`).   - zoom:\"\n#~ \" (float) zoom factor on target page.\"\n#~ \"   - xref: :data:`xref` of the item\"\n#~ \" (0 if no PDF).   - color: item\"\n#~ \" color in PDF RGB format `(red, \"\n#~ \"green, blue)`, or omitted (always \"\n#~ \"omitted if no PDF).   - bold: true\"\n#~ \" if bold item text or omitted. \"\n#~ \"PDF only.   - italic: true if \"\n#~ \"italic item text, or omitted. PDF \"\n#~ \"only.   - collapse: true if sub-\"\n#~ \"items are folded, or omitted. PDF \"\n#~ \"only.\"\n#~ msgstr \"\"\n\n#~ msgid \"Only available in PyMuPDF's \\\"rebased\\\" implementation.\"\n#~ msgstr \"\"\n\n#~ msgid \"arg int xref\"\n#~ msgstr \"\"\n\n#~ msgid \"arg bool info_only\"\n#~ msgstr \"\"\n\n#~ msgid \"arg bool named\"\n#~ msgstr \"\"\n\n#~ msgid \"rtype\"\n#~ msgstr \"\"\n\n#~ msgid \"tuple,dict\"\n#~ msgstr \"\"\n\n#~ msgid \"returns\"\n#~ msgstr \"\"\n\n#~ msgid \"New in v1.18.7, changed in v1.18.9\"\n#~ msgstr \"v1.18.7 で新規追加、v1.18.9 で変更\"\n\n#~ msgid \"\"\n#~ \"Package `fontTools <https://pypi.org/project/fonttools/>`_\"\n#~ \" **must be installed**. It is \"\n#~ \"required for creating the font subsets.\"\n#~ \" If not installed, the method raises\"\n#~ \" an `ImportError` exception.\"\n#~ msgstr \"\"\n#~ \"`fontTools <https://pypi.org/project/fonttools/>`_ パッケージが\"\n#~ \" **インストールされている必要があります**。フォントサブセットの作成に必要です。インストールされていない場合、メソッドは \"\n#~ \"`ImportError` 例外を発生させます。\"\n\n#~ msgid \"\"\n#~ \"Supported font types only include \"\n#~ \"embedded OTF, TTF and WOFF that \"\n#~ \"are **not already subsets**.\"\n#~ msgstr \"\"\n#~ \"サポートされているフォントタイプには、埋め込まれた OTF、TTF、および WOFF \"\n#~ \"のみが含まれ、**すでにサブセットであるものは含まれません** 。\"\n\n#~ msgid \"\"\n#~ \"**Changed in v1.18.9:** A subset font\"\n#~ \" directly replaces its original -- \"\n#~ \"text remains untouched and **is not \"\n#~ \"rewritten.** It thus should retain all\"\n#~ \" its properties, like spacing, hiddenness,\"\n#~ \" control by Optional Content, etc.\"\n#~ msgstr \"\"\n#~ \"**v1.18.9** で変更: サブセットフォントはその元のフォントを直接置換します - \"\n#~ \"テキストは変更されず、**書き直されません**。したがって、スペーシング、非表示、オプションのコンテンツによる制御など、すべてのプロパティが保持されるはずです。\"\n\n#~ msgid \"\"\n#~ \"The greatest benefit can be achieved \"\n#~ \"when creating new PDFs using large \"\n#~ \"fonts like is typical for Asian \"\n#~ \"scripts. In these cases, the set \"\n#~ \"of actually used unicodes mostly is \"\n#~ \"small compared to the number of \"\n#~ \"glyphs in the font. Using this \"\n#~ \"feature can easily reduce the embedded\"\n#~ \" font binary by two orders of \"\n#~ \"magnitude -- from several megabytes to\"\n#~ \" a low two-digit kilobyte amount.\"\n#~ msgstr \"\"\n#~ \"最大の利点は、アジアの文字に典型的な大きなフォントを使用して新しい PDF \"\n#~ \"を作成する場合に得られます。このような場合、実際に使用されているユニコードのセットは、フォント内のグリフの数と比較して非常に小さいことが多いです。この機能を使用すると、埋め込まれたフォントのバイナリサイズを容易に2桁のキロバイト単位にまで削減できます\"\n#~ \" - 数メガバイトから低二桁キロバイトの量にまで。\"\n\n#~ msgid \"\"\n#~ \"a list of images **referenced** by \"\n#~ \"this page. Each item looks like  \"\n#~ \"`(xref, smask, width, height, bpc, \"\n#~ \"colorspace, alt. colorspace, name, filter, \"\n#~ \"referencer)`  Where    * *:data:`xref`* \"\n#~ \"(*int*) is the image object number   \"\n#~ \"* **smask** (*int*) is the object \"\n#~ \"number of its soft-mask image   *\"\n#~ \" **width** and **height** (*ints*) are \"\n#~ \"the image dimensions   * **bpc** (*int*)\"\n#~ \" denotes the number of bits per \"\n#~ \"component (normally 8)   * **colorspace** \"\n#~ \"(*str*) a string naming the colorspace\"\n#~ \" (like **DeviceRGB**)   * **alt. \"\n#~ \"colorspace** (*str*) is any alternate \"\n#~ \"colorspace depending on the value of \"\n#~ \"**colorspace**   * **name** (*str*) is \"\n#~ \"the symbolic name by which the \"\n#~ \"image is referenced   * **filter** \"\n#~ \"(*str*) is the decode filter of \"\n#~ \"the image (:ref:`AdobeManual`, pp. 22).   \"\n#~ \"* **referencer** (*int*) the :data:`xref` \"\n#~ \"of the referencer. Zero if directly \"\n#~ \"referenced by the page. Only present \"\n#~ \"if *full=True*.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"`(xref, smask, width, height, bpc, \"\n#~ \"colorspace, alt. colorspace, name, filter, \"\n#~ \"referencer)`\"\n#~ msgstr \"\"\n\n#~ msgid \"**width** and **height** (*ints*) are the image dimensions\"\n#~ msgstr \"**width** と **height** （*int*）は画像の寸法です\"\n\n#~ msgid \"arg int idx: index of the item in list :meth:`Document.get_toc`.\"\n#~ msgstr \"引数 int idx: :meth:`Document.get_toc` リスト内のアイテムのインデックス。\"\n\n#~ msgid \"\"\n#~ \"Changed in v1.19.3 - as a fix \"\n#~ \"to issue `#537 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/537>`_, form \"\n#~ \"fields are always excluded.\"\n#~ msgstr \"\"\n#~ \"v1.19.3で変更 - 問題＃ `#537 \"\n#~ \"<https://github.com/pymupdf/PyMuPDF/issues/537>`_ \"\n#~ \"の修正として、フォームフィールドは常に除外されます。\"\n\n#~ msgid \"\"\n#~ \"This is a page-based method. \"\n#~ \"Document-level information of source \"\n#~ \"documents is therefore ignored. Examples \"\n#~ \"include Optional Content, Embedded Files, \"\n#~ \"`StructureElem`, `AcroForm`, table of \"\n#~ \"contents, page labels, metadata, named \"\n#~ \"destinations (and other named entries) \"\n#~ \"and some more. As a consequence, \"\n#~ \"specifically, **Form Fields (widgets) can \"\n#~ \"never be copied** -- although they \"\n#~ \"seem to appear on pages only. Look\"\n#~ \" at :meth:`Document.bake` for converting a\"\n#~ \" source document if you need to \"\n#~ \"retain at least widget **appearances.**\"\n#~ msgstr \"\"\n#~ \"これはページベースのメソッドです。そのため、ソース文書のドキュメントレベルの情報は無視されます。例には、オプショナルコンテンツ、埋め込みファイル、\"\n#~ \" `StructureElem` 、 `AcroForm` \"\n#~ \"、目次、ページラベル、メタデータ、名前付き目的地（および他の名前付きエントリ）などがあります。その結果、具体的にはフォームフィールド（ウィジェット）はコピーできません。\"\n#~ \" - たとえそれらがページ上に表示されているように見える場合でも。ウィジェットの **外観** \"\n#~ \"を少なくとも保持する必要がある場合は、:meth:`Document.bake` をご覧ください。\"\n\n#~ msgid \"the created page object.\"\n#~ msgstr \"作成されたページオブジェクト。\"\n\n#~ msgid \"\"\n#~ \"a dictionary with the following keys:\"\n#~ \"  * *name* -- (*str*) name under \"\n#~ \"which this entry is stored * \"\n#~ \"*filename* -- (*str*) filename * \"\n#~ \"*ufilename* -- (*unicode*) filename * \"\n#~ \"*desc* -- (*str*) description * *size*\"\n#~ \" -- (*int*) original file size * \"\n#~ \"*length* -- (*int*) compressed file \"\n#~ \"length * *creationDate* -- *(New in \"\n#~ \"v1.18.13)* (*str*) date-time of item \"\n#~ \"creation in PDF format * *modDate* \"\n#~ \"-- *(New in v1.18.13)* (*str*) date-\"\n#~ \"time of last change in PDF format\"\n#~ \" * *collection* -- *(New in \"\n#~ \"v1.18.13)* (*int*) :data:`xref` of the \"\n#~ \"associated PDF portfolio item if any,\"\n#~ \" else zero. * *checksum* -- *(New \"\n#~ \"in v1.18.13)* (*str*) a hashcode of \"\n#~ \"the stored file content as a \"\n#~ \"hexadecimal string. Should be MD5 \"\n#~ \"according to PDF specifications, but be\"\n#~ \" prepared to see other hashing \"\n#~ \"algorithms.\"\n#~ msgstr \"\"\n\n#~ msgid \"New in v1.14.16\"\n#~ msgstr \"v1.14.16 で新規\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"Changed in v1.14.13: support `io.BytesIO` for memory documents.\"\n#~ msgstr \"v1.14.13 で変更: メモリドキュメント用に `io.BytesIO` をサポート。\"\n\n#~ msgid \"\"\n#~ \"Changed in v1.19.6: Clearer, shorter and\"\n#~ \" more consistent exception messages. File\"\n#~ \" type \\\"pdf\\\" is always assumed if\"\n#~ \" not specified. Empty files and \"\n#~ \"memory areas will always lead to \"\n#~ \"exceptions.\"\n#~ msgstr \"\"\n#~ \"v1.19.6 で変更: \"\n#~ \"より明確で短く、一貫性のある例外メッセージ。ファイルタイプが指定されていない場合、常にファイルタイプ \\\"pdf\\\" \"\n#~ \"が仮定されます。空のファイルとメモリ領域は常に例外を発生させます。\"\n\n#~ msgid \"\"\n#~ \"If *stream* is given, then the \"\n#~ \"document is created from memory and, \"\n#~ \"if not a PDF, either *filename* or\"\n#~ \" *filetype* must indicate its type.\"\n#~ msgstr \"\"\n#~ \"*stream* が指定されている場合、ドキュメントはメモリから作成され、PDF でない場合は \"\n#~ \"*filename* または *filetype* のいずれかがそのタイプを示さなければなりません。\"\n\n#~ msgid \"\"\n#~ \"A UTF-8 string or *pathlib* object \"\n#~ \"containing a file path. The document \"\n#~ \"type is inferred from the filename \"\n#~ \"extension. If not present or not \"\n#~ \"matching :ref:`a supported \"\n#~ \"type<Supported_File_Types>`, a PDF document is\"\n#~ \" assumed. For memory documents, this \"\n#~ \"argument may be used instead of \"\n#~ \"`filetype`, see below.\"\n#~ msgstr \"\"\n#~ \"ファイルパスを含む UTF-8 文字列または *pathlib* \"\n#~ \"オブジェクト。ドキュメントのタイプはファイル名の拡張子から推測されます。存在しないか、:ref:`サポートされてい<Supported_File_Types>`\"\n#~ \" ないタイプに一致しない場合、PDF ドキュメントが仮定されます。メモリドキュメントの場合、`filetype` \"\n#~ \"の代わりにこの引数を使用できます。詳細は以下を参照してください。\"\n\n#~ msgid \"\"\n#~ \"A memory area containing a supported \"\n#~ \"document. If not a PDF, its type\"\n#~ \" **must** be specified by either \"\n#~ \"`filename` or `filetype`.\"\n#~ msgstr \"\"\n#~ \"(bytes, bytearray, BytesIO) - \"\n#~ \":ref:`サポートされている<Supported_File_Types>` ドキュメントを含むメモリ領域。PDF \"\n#~ \"でない場合、そのタイプは `filename` または `filetype` \"\n#~ \"のいずれかによって指定 **しなければなりません** 。\"\n\n#~ msgid \"\"\n#~ \"A string specifying the type of \"\n#~ \"document. This may be anything looking\"\n#~ \" like a filename (e.g. \\\"x.pdf\\\"), in\"\n#~ \" which case MuPDF uses the extension\"\n#~ \" to determine the type, or a \"\n#~ \"mime type like *application/pdf*. Just \"\n#~ \"using strings like \\\"pdf\\\"  or \\\".pdf\\\"\"\n#~ \" will also work. May be omitted \"\n#~ \"for PDF documents, otherwise must match\"\n#~ \" :ref:`a supported document \"\n#~ \"type<Supported_File_Types>`.\"\n#~ msgstr \"\"\n#~ \"ドキュメントのタイプを指定する文字列。ファイル名のように見えるもの（例: \"\n#~ \"\\\"x.pdf\\\"）である必要があります。この場合、MuPDF \"\n#~ \"は拡張子を使用してタイプを判断します。*application/pdf* のような mime \"\n#~ \"タイプも使用できます。単に \\\"pdf\\\" または \\\".pdf\\\" \"\n#~ \"のような文字列を使用することもできます。PDF ドキュメントの場合、省略可能であり、それ以外の場合は \"\n#~ \":ref:`サポートされている<Supported_File_Types>` ドキュメントタイプに一致しなければなりません。\"\n\n#~ msgid \"\"\n#~ \"Not all document types are checked \"\n#~ \"for valid formats already at open \"\n#~ \"time. Raster images for example will \"\n#~ \"raise exceptions only later, when trying\"\n#~ \" to access the content. Other types\"\n#~ \" (notably with non-binary content) \"\n#~ \"may also be opened (and sometimes \"\n#~ \"**accessed**) successfully -- sometimes even\"\n#~ \" when having invalid content for the\"\n#~ \" format:\"\n#~ msgstr \"\"\n#~ \"すべてのドキュメントタイプがオープン時に有効なフォーマットで確認されるわけではありません。例えば、ラスター画像はコンテンツにアクセスしようとした際に例外を発生させることがあります。他のタイプ（特にバイナリでないコンテンツを持つもの）は、有効なコンテンツを持たない場合でも成功してオープンされ（そして時に\"\n#~ \" **アクセスされる** こともあります）：\"\n\n#~ msgid \"\"\n#~ \"HTM, HTML, XHTML: **always** opened, \"\n#~ \"`metadata[\\\"format\\\"]` is \\\"HTML5\\\", resp. \"\n#~ \"\\\"XHTML\\\".\"\n#~ msgstr \"\"\n#~ \"HTM、HTML、XHTML: **常に** オープンされ、 \"\n#~ \"`metadata[\\\"format\\\"]` は \\\"HTML5\\\" または \"\n#~ \"\\\"XHTML\\\" です。\"\n\n#~ msgid \"\"\n#~ \"XML, FB2: **always** opened, \"\n#~ \"`metadata[\\\"format\\\"]` is \\\"FictionBook2\\\".\"\n#~ msgstr \"XML、FB2: **常に** オープンされ、 `metadata[\\\"format\\\"]` は \\\"FictionBook2\\\" です。\"\n\n#~ msgid \"\"\n#~ \"PDF only: Change the color component \"\n#~ \"counts for all object types text, \"\n#~ \"image and vector graphics for all \"\n#~ \"pages.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"a list of images **referenced** by \"\n#~ \"this page. Each item looks like  \"\n#~ \"`(xref, smask, width, height, bpc, \"\n#~ \"colorspace, alt_colorspace, name, filter, \"\n#~ \"referencer)`  Where    * *:data:`xref`* \"\n#~ \"(*int*) is the image object number   \"\n#~ \"* **smask** (*int*) is the object \"\n#~ \"number of its soft-mask image   *\"\n#~ \" **width** (*int*) is the image width\"\n#~ \"   * **height** (*int*) is the image\"\n#~ \" height   * **bpc** (*int*) denotes \"\n#~ \"the number of bits per component \"\n#~ \"(normally 8)   * **colorspace** (*str*) \"\n#~ \"a string naming the colorspace (like \"\n#~ \"**DeviceRGB**)   * **alt_colorspace** (*str*) \"\n#~ \"is any alternate colorspace depending on\"\n#~ \" the value of **colorspace**   * \"\n#~ \"**name** (*str*) is the symbolic name\"\n#~ \" by which the image is referenced\"\n#~ \"   * **filter** (*str*) is the decode\"\n#~ \" filter of the image (:ref:`AdobeManual`,\"\n#~ \" pp. 22).   * **referencer** (*int*) \"\n#~ \"the :data:`xref` of the referencer. Zero\"\n#~ \" if directly referenced by the page.\"\n#~ \" Only present if *full=True*.\"\n#~ msgstr \"\"\n\n#~ msgid \"Where\"\n#~ msgstr \"ここで\"\n\n#~ msgid \"**(xref, ext, type, basefont, name, encoding, referencer)**,\"\n#~ msgstr \"\"\n\n#~ msgid \"where\"\n#~ msgstr \"ここで\"\n\n#~ msgid \"\"\n#~ \"page number (0-based) **in front of \"\n#~ \"which** to insert. Must be in \"\n#~ \"`range(-1, doc.page_count + 1)`. Special \"\n#~ \"values -1 and `doc.page_count` insert \"\n#~ \"**after** the last page.  Changed in \"\n#~ \"v1.14.12    This is now a positional \"\n#~ \"parameter\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"a dictionary with the following keys\"\n#~ \"  * *ext* (*str*) image type (e.g.\"\n#~ \" *'jpeg'*), usable as image file \"\n#~ \"extension * *smask* (*int*) :data:`xref` \"\n#~ \"number of a stencil (/SMask) image \"\n#~ \"or zero * *width* (*int*) image \"\n#~ \"width * *height* (*int*) image height\"\n#~ \" * *colorspace* (*int*) the image's \"\n#~ \"*colorspace.n* number. * *cs-name* \"\n#~ \"(*str*) the image's *colorspace.name*. * \"\n#~ \"*xres* (*int*) resolution in x \"\n#~ \"direction. Please also see :data:`resolution`.\"\n#~ \" * *yres* (*int*) resolution in y \"\n#~ \"direction. Please also see :data:`resolution`.\"\n#~ \" * *image* (*bytes*) image data, \"\n#~ \"usable as image file content\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/faq.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 fc37bbaea9e645f2a1934950c4d360aa\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 3e2f00868cab4dc9b3f9c47206f4e0e1\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 dc5cbb9888564cd2904f297d4612db6a\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../faq.rst:7 34a4b295156e4a8b80a33df4e0d989fe\nmsgid \"FAQ\"\nmsgstr \"\"\n\n#: ../../faq.rst:9 42099b86e20e4e99a1843a506f01916e\nmsgid \"A collection of recipes in “How-To” format for using PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../faq.rst:12 b75419af6b7a47d9900bf518ab5e1ad3\nmsgid \"Please see:\"\nmsgstr \"\"\n\n#: ../../faq.rst:14 478d3b75ae384ae8b14fb10fdd9b39fc\nmsgid \":ref:`Recipes: Table of Contents<RecipesTOC>`\"\nmsgstr \"\"\n\n#: ../../footer.rst:60 ebceb100878042a6ade4b6d7432a599e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/font.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 e188dde9abe149bc8995bf7a6a0bc7d6\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 3cb714fa525c44bbbbd491bc8f62336e\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 c23c7d47fe3e429dbde810adabc353b6\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../font.rst:7 d2748ea1ae9940f6b22b259ae4533e13\nmsgid \"Font\"\nmsgstr \"Font (フォント)\"\n\n#: ../../font.rst:9 3bf53a70d692484eaabd5afc3aab44c8\nmsgid \"New in v1.16.18\"\nmsgstr \"新機能：v1.16.18\"\n\n#: ../../font.rst:11 4c18f6c0f2b6494fbf226048ecce0907\nmsgid \"\"\n\"This class represents a font as defined in |MuPDF| (``fz_font_s`` \"\n\"structure). It is required for the new class :ref:`TextWriter` and the \"\n\"new :meth:`Page.write_text`. Currently, it has no connection to how fonts\"\n\" are used in methods :meth:`Page.insert_text` or \"\n\":meth:`Page.insert_textbox`, respectively.\"\nmsgstr \"\"\n\"このクラスは、|MuPDF| で定義されたフォント（ ``fz_font_s`` 構造体）を表します。これは、新しいクラス \"\n\":ref:`TextWriter` と新しい :meth:`Page.write_text` \"\n\"に必要であり、現在、:meth:`Page.insert_text` または :meth:`Page.insert_textbox` \"\n\"メソッドでフォントがどのように使用されているかとは関係ありません。\"\n\n#: ../../font.rst:13 2125868871f645fb9fa0d4390f116a1a\nmsgid \"\"\n\"A ``Font`` object also contains useful general information, like the font\"\n\" bbox, the number of defined glyphs, glyph names or the ``bbox`` of a \"\n\"single glyph.\"\nmsgstr \"\"\n\"``Font`` オブジェクトには、フォント ``bbox`` 、定義済みグリフの数、グリフ名、単一グリフの ``bbox`` \"\n\"など、有用な一般情報も含まれています。\"\n\n#: ../../font.rst:17 842b44a70bf34b07ac2692aa84a193da\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド/属性** \"\n\n#: ../../font.rst:17 f69a466cefe443c3855949e5cc5ffcd6\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明** \"\n\n#: ../../font.rst:19 1bba986439da408a84c24de22da3768d\nmsgid \":meth:`~Font.glyph_advance`\"\nmsgstr \"\"\n\n#: ../../font.rst:19 627a6c4218dd4762ae098709cdb920ad\nmsgid \"Width of a character\"\nmsgstr \"文字の幅\"\n\n#: ../../font.rst:20 6ca041bd76a54c949510e2ed77ca58f0\nmsgid \":meth:`~Font.glyph_bbox`\"\nmsgstr \"\"\n\n#: ../../font.rst:20 d9fb542d691c44a19873b891f02b7812\nmsgid \"Glyph rectangle\"\nmsgstr \"グリフの矩形\"\n\n#: ../../font.rst:21 e7791392edbd4e5d9094df1b320d2c5b\nmsgid \":meth:`~Font.glyph_name_to_unicode`\"\nmsgstr \"\"\n\n#: ../../font.rst:21 13f06c680aba44698114079c036bcdba\nmsgid \"Get unicode from glyph name\"\nmsgstr \"グリフ名からUnicodeを取得\"\n\n#: ../../font.rst:22 c04368ada6c341f093c2f4872cd5cd52\nmsgid \":meth:`~Font.has_glyph`\"\nmsgstr \"\"\n\n#: ../../font.rst:22 689634c88d144bef9223b78f39009eda\nmsgid \"Return glyph id of unicode\"\nmsgstr \"UnicodeのグリフIDを返す\"\n\n#: ../../font.rst:23 a369a0e87b4340168dce9cd130684d3c\nmsgid \":meth:`~Font.text_length`\"\nmsgstr \"\"\n\n#: ../../font.rst:23 f20e22d5c6534f99a10aad9ab98d9ae3\nmsgid \"Compute string length\"\nmsgstr \"文字列の長さを計算\"\n\n#: ../../font.rst:24 d46c723021014de19f30cce31dd6fa83\nmsgid \":meth:`~Font.char_lengths`\"\nmsgstr \"\"\n\n#: ../../font.rst:24 2c939c616c2a45d19cef1d2e9148c5f8\nmsgid \"Tuple of char widths of a string\"\nmsgstr \"文字列の文字幅のタプル\"\n\n#: ../../font.rst:25 30fcbf0fac8c4137ac05697051b7a487\nmsgid \":meth:`~Font.unicode_to_glyph_name`\"\nmsgstr \"\"\n\n#: ../../font.rst:25 96a805868d65421593f69cabcbdff444\nmsgid \"Get glyph name of a unicode\"\nmsgstr \"Unicodeのグリフ名を取得\"\n\n#: ../../font.rst:26 556560ade52f45878ccd9247ed48b124\nmsgid \":meth:`~Font.valid_codepoints`\"\nmsgstr \"\"\n\n#: ../../font.rst:26 f98352016c9a420597ecdc2d4da47bcd\nmsgid \"Array of supported unicodes\"\nmsgstr \"サポートされているUnicodeの配列\"\n\n#: ../../font.rst:27 8046f6ca0658408896ffec620e7c19d2\nmsgid \":attr:`~Font.ascender`\"\nmsgstr \"\"\n\n#: ../../font.rst:27 bdef6c925fd24cd6a8bd423203561e10\nmsgid \"Font ascender\"\nmsgstr \"フォントのアセンダ\"\n\n#: ../../font.rst:28 b9972b7d50024c5f92aae461b95e9b9d\nmsgid \":attr:`~Font.descender`\"\nmsgstr \"\"\n\n#: ../../font.rst:28 333b36880ce240299a20b8d485071b31\nmsgid \"Font descender\"\nmsgstr \"フォントのディセンダ\"\n\n#: ../../font.rst:29 1ca68d63143c41ae9afaf82231bb0b98\nmsgid \":attr:`~Font.bbox`\"\nmsgstr \"\"\n\n#: ../../font.rst:29 88947fe258eb49d5a4bcd7f9262d6f64\nmsgid \"Font rectangle\"\nmsgstr \"フォントの矩形\"\n\n#: ../../font.rst:30 70204c08ad4f48bfb90c610ace5e2f16\nmsgid \":attr:`~Font.buffer`\"\nmsgstr \"\"\n\n#: ../../font.rst:30 d8dc88a830a143b69cf9198d43a1d8be\nmsgid \"Copy of the font's binary image\"\nmsgstr \"フォントのバイナリイメージのコピー\"\n\n#: ../../font.rst:31 087ab4d9b8c245329f433d0e0bc1dae2\nmsgid \":attr:`~Font.flags`\"\nmsgstr \"\"\n\n#: ../../font.rst:31 b08397d234cf4d828c277f81b7e5797c\nmsgid \"Collection of font properties\"\nmsgstr \"フォントのプロパティのコレクション\"\n\n#: ../../font.rst:32 1b9e053341ba4bf29f37614365fca44e\nmsgid \":attr:`~Font.glyph_count`\"\nmsgstr \"\"\n\n#: ../../font.rst:32 9266fb9484fe42618bd4b861302ec139\nmsgid \"Number of supported glyphs\"\nmsgstr \"サポートされているグリフの数\"\n\n#: ../../font.rst:33 a1a23dee533f4eb9a0253e7ed4dc2160\nmsgid \":attr:`~Font.name`\"\nmsgstr \"\"\n\n#: ../../font.rst:33 f7c44ea05506418686745a0a8b4ccf1e\nmsgid \"Name of font\"\nmsgstr \"フォントの名前\"\n\n#: ../../font.rst:34 4d8600344c934dca966561b9b23705a3\nmsgid \":attr:`~Font.is_bold`\"\nmsgstr \"\"\n\n#: ../../font.rst:34 42bd831f9b604a58adec9428f2799d4a\nmsgid \"`True` if bold\"\nmsgstr \"\"\n\n#: ../../font.rst:35 4fd252e5611e4f25ad7279f120909cc1\nmsgid \":attr:`~Font.is_monospaced`\"\nmsgstr \"\"\n\n#: ../../font.rst:35 53567d475247479ebe27771a05253749\nmsgid \"`True` if mono-spaced\"\nmsgstr \"\"\n\n#: ../../font.rst:36 386c083d80e24cd8889a76d1ed0d655e\nmsgid \":attr:`~Font.is_serif`\"\nmsgstr \"\"\n\n#: ../../font.rst:36 dc515a68d8984513880dd9652137056b\nmsgid \"`True` if serif, `False` if sans-serif\"\nmsgstr \"\"\n\n#: ../../font.rst:37 ef38964ab5634a4a8afc1a4043834bcb\nmsgid \":attr:`~Font.is_italic`\"\nmsgstr \"\"\n\n#: ../../font.rst:37 6ab8b6017630445e8a8d73bd87250888\nmsgid \"`True` if italic\"\nmsgstr \"\"\n\n#: ../../font.rst:41 ef6bc7e0d9cf42848d2ea5ec97cad0e8\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../font.rst:60 07b4413b01ae4ae89132a4d69299fcff\nmsgid \"\"\n\"Font constructor. The large number of parameters are used to locate font,\"\n\" which most closely resembles the requirements. Not all parameters are \"\n\"ever required -- see the below pseudo code explaining the logic how the \"\n\"parameters are evaluated.\"\nmsgstr \"\"\n\"フォントコンストラクタ。多くのパラメータは、要件に最も近いフォントを特定するために使用されます。必ずしもすべてのパラメータが必要とされるわけではありません\"\n\" - パラメータが評価されるロジックを説明する以下の疑似コードを参照してください。\"\n\n#: ../../font.rst 51829dd751b848658d1ba228b94ce1de\n#: 6865a3bfb8444b439d877a9d8a59cb0a 722fbb72278d4e3e8bb0df13f398859a\n#: 8cbc7148711c4ee9a078b6a806370c78 a100d7e7206946cda8a733ebb3f80137\n#: c931f89accb14562827a19ea990df0aa f0f58970e4794ad2b4f9ab161b976692\n#: f42510c818544c6180a85f87a852dd28\nmsgid \"Parameters\"\nmsgstr \"パラメータ\"\n\n#: ../../font.rst:62 b7c66967af094eed88e4cd0bfa9c0b59\nmsgid \"\"\n\"one of the :ref:`Base-14-Fonts` or CJK fontnames. Also possible are a \"\n\"select few other names like (watch the correct spelling): \\\"Arial\\\", \"\n\"\\\"Times\\\", \\\"Times Roman\\\".  *(Changed in v1.17.5)*  If you have \"\n\"installed `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_, \"\n\"there are also new \\\"reserved\\\" fontnames available, which are listed in \"\n\":attr:`fitz_fonts` and in the table further down.\"\nmsgstr \"\"\n\n#: ../../font.rst:62 4f54e9a21f4e4cdd94eb896e84a11207\nmsgid \"\"\n\"one of the :ref:`Base-14-Fonts` or CJK fontnames. Also possible are a \"\n\"select few other names like (watch the correct spelling): \\\"Arial\\\", \"\n\"\\\"Times\\\", \\\"Times Roman\\\".\"\nmsgstr \"\"\n\":ref:`Base-14-Fonts` またはCJKフォントの名前のいずれか。また、\\\"Arial\\\"、\\\"Times\\\"、\\\"Times \"\n\"Roman\\\"などの選択的な名前も可能です。\"\n\n#: ../../font.rst:64 33128ec921644adcb669eed87f58d1ad\nmsgid \"*(Changed in v1.17.5)*\"\nmsgstr \"(v1.17.5で変更)\"\n\n#: ../../font.rst:66 2580ac163f6d40a6a97df2667e044b70\nmsgid \"\"\n\"If you have installed `pymupdf-fonts <https://pypi.org/project/pymupdf-\"\n\"fonts/>`_, there are also new \\\"reserved\\\" fontnames available, which are\"\n\" listed in :attr:`fitz_fonts` and in the table further down.\"\nmsgstr \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ \"\n\"をインストールしている場合、:attr:`fitz_fonts` と下の表でリストされている新しい「予約済み」フォント名も利用可能です。\"\n\n#: ../../font.rst:68 0115b8805a994350b1e9b88652d9c671\nmsgid \"the filename of a fontfile somewhere on your system [#f1]_.\"\nmsgstr \"システムのどこかにあるフォントファイルのファイル名 [#f1]_。\"\n\n#: ../../font.rst:69 855671c475ce4d4a95574d50da436fa8\nmsgid \"a fontfile loaded in memory [#f1]_.\"\nmsgstr \"メモリ内にロードされたフォントファイル [#f1]_。\"\n\n#: ../../font.rst:70 b4cd7e175eb14d658f5faa379b3ef701\nmsgid \"\"\n\"the number of a UCDN script. Currently supported in PyMuPDF are numbers \"\n\"24, and 32 through 35.\"\nmsgstr \"\"\n\"UCDN（Unicode Character Database \"\n\"Number）のスクリプト番号です。現在、PyMuPDFでサポートされている番号は、24、および32から35です。\"\n\n#: ../../font.rst:71 d5a5fc15ea7c4e1b8d26964a61b402e8\nmsgid \"\"\n\"one of the values \\\"zh-Hant\\\" (traditional Chinese), \\\"zh-Hans\\\" \"\n\"(simplified Chinese), \\\"ja\\\" (Japanese) and \\\"ko\\\" (Korean). Otherwise, \"\n\"all ISO 639 codes from the subsets 1, 2, 3 and 5 are also possible, but \"\n\"are currently documentary only.\"\nmsgstr \"UCDNスクリプトの番号。現在、PyMuPDFでサポートされているのは24、および32から35の数値です\"\n\n#: ../../font.rst:72 5b0e786be58c4a09a48eacc61882197e\nmsgid \"an alternative selector for one of the CJK fonts.\"\nmsgstr \"CJKフォントの選択のための代替セレクタ。\"\n\n#: ../../font.rst:73 6af1f2fb252e4071bab746f2ad57c01d\nmsgid \"look for a bold font.\"\nmsgstr \"太字のフォントを探します。\"\n\n#: ../../font.rst:74 6f2bffef2aa94c92b00fa9cf6d97a283\nmsgid \"look for an italic font.\"\nmsgstr \"イタリック体のフォントを探します。\"\n\n#: ../../font.rst:75 23ca0f2751ed4b2f834236f7e744dd36\nmsgid \"look for a serifed font.\"\nmsgstr \"セリフ付きのフォントを探します。\"\n\n#: ../../font.rst 1d22b29a05e741f387368f96870d4c1b\n#: 1e8b6f0bc4da4c4db71fcd4ce33f7f4d 1ebfff0006a54633b2e48a4cf728c55b\n#: 3126e087ce6d47cbb326a10281420878 3aaf4a67eaa8475e97bebd3b14716268\n#: 3b8e58b5a2034fddbba0b9f34d785351 425ebf256d4842928912c98469178b2e\n#: 455992af6eea4168919f71ca6e0a63e9 7512b5e1267b491c80d9886fcb846c91\nmsgid \"Returns\"\nmsgstr \"戻り値\"\n\n#: ../../font.rst:77 d564d7e503224782b914ea4c4d4bd55b\nmsgid \"\"\n\"a |MuPDF| font if successful. This is the overall sequence of checks to \"\n\"determine an appropriate font:  =========== \"\n\"============================================================ Argument    \"\n\"Action =========== \"\n\"============================================================ fontfile?   \"\n\"Create font from file, exception if failure. fontbuffer? Create font from\"\n\" buffer, exception if failure. ordering>=0 Create universal font, always \"\n\"succeeds. fontname?   Create a Base-14 font, universal font, or font\"\n\"             provided by `pymupdf-fonts <https://pypi.org/project\"\n\"/pymupdf-fonts/>`_. See table below. =========== \"\n\"============================================================\"\nmsgstr \"\"\n\n#: ../../font.rst:77 cea38fccea5241229aadba228571f8be\nmsgid \"\"\n\"a |MuPDF| font if successful. This is the overall sequence of checks to \"\n\"determine an appropriate font:\"\nmsgstr \"成功した場合は |MuPDF| フォント。適切なフォントを特定するための全体のチェックのシーケンスは次のとおりです。\"\n\n#: ../../font.rst:80 580ec24b97e749299e613764ef3403c6\nmsgid \"Argument\"\nmsgstr \"引数\"\n\n#: ../../font.rst:80 c41ca6b5584649b586f676f06f22549b\nmsgid \"Action\"\nmsgstr \"アクション\"\n\n#: ../../font.rst:82 98333181f4584c9c8bca13c85c415262\nmsgid \"fontfile?\"\nmsgstr \"\"\n\n#: ../../font.rst:82 73d6da924f634bc7b6e4fe044072fe6d\nmsgid \"Create font from file, exception if failure.\"\nmsgstr \"ファイルからフォントを作成し、失敗した場合は例外をスローします。\"\n\n#: ../../font.rst:83 130073b0bea44ffc890479cdb5f5340d\nmsgid \"fontbuffer?\"\nmsgstr \"\"\n\n#: ../../font.rst:83 a74986c74e6843eea78fcc35d447c3a2\nmsgid \"Create font from buffer, exception if failure.\"\nmsgstr \"バッファからフォントを作成し、失敗した場合は例外をスローします。\"\n\n#: ../../font.rst:84 29919d8588f5493dafda4cfe7f0555b1\nmsgid \"ordering>=0\"\nmsgstr \"\"\n\n#: ../../font.rst:84 3f0b6b784f1742238213e67a82078abf\nmsgid \"Create universal font, always succeeds.\"\nmsgstr \"ユニバーサルフォントを作成し、常に成功します。\"\n\n#: ../../font.rst:85 fe70636ee76b429da54199e913507119\nmsgid \"fontname?\"\nmsgstr \"\"\n\n#: ../../font.rst:85 a411aeb787b5416f854bb729f143e0b6\nmsgid \"\"\n\"Create a Base-14 font, universal font, or font provided by `pymupdf-fonts\"\n\" <https://pypi.org/project/pymupdf-fonts/>`_. See table below.\"\nmsgstr \"\"\n\"ベース14フォント、ユニバーサルフォント、または `pymupdf-fonts <https://pypi.org/project\"\n\"/pymupdf-fonts/>`_ で提供されるフォントを作成します。下の表を参照してください。\"\n\n#: ../../font.rst:92 d6d370d9961e418c8c6a25a191d46651\nmsgid \"\"\n\"With the usual reserved names \\\"helv\\\", \\\"tiro\\\", etc., you will create \"\n\"fonts with the expected names \\\"Helvetica\\\", \\\"Times-Roman\\\" and so on. \"\n\"**However**, and in contrast to :meth:`Page.insert_font` and friends,\"\nmsgstr \"\"\n\"通常の予約済みの名前「helv」、「tiro」などを使用すると、期待どおりの名前「Helvetica」、「Times-\"\n\"Roman」などのフォントが作成されます。**ただし** 、:meth:`Page.insert_font` などとは異なり、\"\n\n#: ../../font.rst:94 31fed8debc7c42ca9166ee0b1ef74c98\nmsgid \"a font file will **always** be embedded in your PDF,\"\nmsgstr \"フォントファイルはPDFに **常に** 埋め込まれます。\"\n\n#: ../../font.rst:95 9b3d8892b4424474889b2416ef13836b\nmsgid \"\"\n\"Greek and Cyrillic characters are supported without needing the \"\n\"*encoding* parameter.\"\nmsgstr \"ギリシャ文字およびキリル文字は *エンコーディング* パラメータを必要とせずにサポートされます。\"\n\n#: ../../font.rst:97 c07988cc48644ac8846d43cf555ae595\nmsgid \"\"\n\"Using *ordering >= 0*, or fontnames \\\"cjk\\\", \\\"china-t\\\", \\\"china-s\\\", \"\n\"\\\"japan\\\" or \\\"korea\\\" will **always create the same \\\"universal\\\"** font\"\n\" **\\\"Droid Sans Fallback Regular\\\"**. This font supports **all Chinese, \"\n\"Japanese, Korean and Latin characters**, including Greek and Cyrillic. \"\n\"This is a sans-serif font.\"\nmsgstr \"\"\n\"ordering >= \"\n\"0を使用するか、フォント名「cjk」、「china-t」、「china-s」、「japan」、「korea」を使用すると、**常に同じ「汎用」**\"\n\" フォント **「Droid Sans Fallback \"\n\"Regular」が作成されます**。このフォントは、**中国語、日本語、韓国語、ラテン文字、ギリシャ文字、キリル文字を含むすべての文字をサポートしています**。これはサンセリフのフォントです。\"\n\n#: ../../font.rst:99 6db4519008e44ee682c2a27e4d316f4b\nmsgid \"\"\n\"Actually, you would rarely ever need another sans-serif font than \"\n\"**\\\"Droid Sans Fallback Regular\\\"**. **Except** that this font file is \"\n\"relatively large and adds about 1.65 MB (compressed) to your PDF file \"\n\"size. If you do not need CJK support, stick with specifying \\\"helv\\\", \"\n\"\\\"tiro\\\" etc., and you will get away with about 35 KB compressed.\"\nmsgstr \"\"\n\"実際、通常、「Droid Sans Fallback \"\n\"Regular」以外のサンセリフのフォントはほとんど必要ありません。ただし、このフォントファイルは比較的大きく、PDFファイルサイズを約1.65 \"\n\"MB（圧縮）増加させます。CJKのサポートが必要でない場合は、「helv」、「tiro」などを指定し、約35 KB（圧縮）で済むでしょう。\"\n\n#: ../../font.rst:101 79c699cd0e0a44828e95752e5f6f2ebe\nmsgid \"\"\n\"If you **know** you have a mixture of CJK and Latin text, consider just \"\n\"using `Font(\\\"cjk\\\")` because this supports everything and also \"\n\"significantly (by a factor of up to three) speeds up execution: MuPDF \"\n\"will always find any character in this single font and never needs to \"\n\"check fallbacks.\"\nmsgstr \"\"\n\"CJKとラテン文字の混合テキストがあることを **知っている** 場合は、単に `Font(\\\"cjk\\\")` \"\n\"を使用して、すべてをサポートし、実行を大幅に高速化します（最大3倍）。MuPDFは常にこの単一のフォントで任意の文字を見つけることができ、フォールバックをチェックする必要はありません。\"\n\n#: ../../font.rst:103 71613c830de34e6f9ecdf39faec59a38\nmsgid \"\"\n\"But if you do use some other font, you will still automatically be able \"\n\"to also write CJK characters: MuPDF detects this situation and silently \"\n\"falls back to the universal font (which will then of course also be \"\n\"embedded in your PDF).\"\nmsgstr \"ただし、他のフォントを使用する場合、CJK文字を書き込むことも自動的にできるようになります。MuPDFはこの状況を検出し、静かにユニバーサルフォントにフォールバックします（その場合、当然、PDFにも埋め込まれます）。\"\n\n#: ../../font.rst:105 f904db70b3d246e1b10894809cb39326\nmsgid \"\"\n\"*(New in v1.17.5)* Optionally, some new \\\"reserved\\\" fontname codes \"\n\"become available if you install `pymupdf-fonts <https://pypi.org/project\"\n\"/pymupdf-fonts/>`_, `pip install pymupdf-fonts`. **\\\"Fira Mono\\\"** is a \"\n\"mono-spaced sans font set and **FiraGO** is another non-serifed \"\n\"\\\"universal\\\" font set which supports all Latin (including Cyrillic and \"\n\"Greek) plus Thai, Arabian, Hewbrew and Devanagari -- but none of the CJK \"\n\"languages. The size of a FiraGO font is only a quarter of the \\\"Droid \"\n\"Sans Fallback\\\" size (compressed 400 KB vs. 1.65 MB) -- **and** it \"\n\"provides the weights bold, italic, bold-italic -- which the universal \"\n\"font doesn't.\"\nmsgstr \"\"\n\"*（v1.17.5で新登場）* オプションで、`pymupdf-fonts <https://pypi.org/project/pymupdf-\"\n\"fonts/>`_ をインストールすると、いくつかの新しい「予約済み」フォント名コードが利用可能になります。 **\\\"Fira Mono\\\"** \"\n\"は等幅のサンセリフフォントセットで、**FiraGO** \"\n\"はラテン文字（キリル文字とギリシャ文字を含む）およびタイ語、アラビア語、ヘブライ語、デーバナガリ語をサポートする別のサンセリフの「ユニバーサル」フォントセットですが、CJK言語はサポートしていません。\"\n\" FiraGOフォントのサイズは「Droid Sans Fallback」のサイズの1/4だけです（圧縮400 KB対1.65 MB） \"\n\"**そして** 、ユニバーサルフォントにはない太字、イタリック、太字イタリックのウェイトを提供しています。\"\n\n#: ../../font.rst:107 51115005ef5b45048d055b7507f8bde1\nmsgid \"\"\n\"**\\\"Space Mono\\\"** is another nice and small mono-spaced font from Google\"\n\" Fonts, which supports Latin Extended characters and comes with all 4 \"\n\"important weights.\"\nmsgstr \"\"\n\"**\\\"Space Mono\\\"** \"\n\"はGoogleフォントからのもう1つの素敵で小さな等幅フォントで、ラテン拡張文字をサポートし、すべての4つの重要なウェイトが含まれています。\"\n\n#: ../../font.rst:109 96727739a91940c6a331ed087081f309\nmsgid \"\"\n\"The following table maps a fontname code to the corresponding font. For \"\n\"the current content of the package please see its documentation:\"\nmsgstr \"次の表は、フォント名コードを対応するフォントにマッピングしています。パッケージの現在の内容については、そのドキュメンテーションを参照してください：\"\n\n#: ../../font.rst:112 1a8503b417cf4c8fada552e8610a6e75\nmsgid \"Code\"\nmsgstr \"コード\"\n\n#: ../../font.rst:112 2d8f3f6732334560b3d503193be52bed\nmsgid \"Fontname\"\nmsgstr \"フォント名\"\n\n#: ../../font.rst:112 c74b2b12e6aa454b8f2dbb4143ffd7bf\nmsgid \"New in\"\nmsgstr \"バージョン\"\n\n#: ../../font.rst:112 09250ac84f2f444481bee3de0bd29007\nmsgid \"Comment\"\nmsgstr \"コメント\"\n\n#: ../../font.rst:114 3092d884950f4b6eb710a9de0dd03966\nmsgid \"figo\"\nmsgstr \"\"\n\n#: ../../font.rst:114 660c171a6c564814aecb4286056ec31a\nmsgid \"FiraGO Regular\"\nmsgstr \"FiraGO レギュラー\"\n\n#: ../../font.rst:114 ../../font.rst:115 ../../font.rst:116 ../../font.rst:117\n#: ../../font.rst:118 ../../font.rst:119 3e80c8fdb0dd48d780069b2449ee507f\n#: 410d087d7e1243d1a54c1ae0aab172ac 6f27e46024f84abd97777e835ae6517f\n#: 794afaec71784e91b7e817f22ead4ffe baa94f214aea4d77a1a5fad071d449f1\n#: ed541c0c11684da3bebb342489caa3cb\nmsgid \"v1.0.0\"\nmsgstr \"\"\n\n#: ../../font.rst:114 aababde120ff4dbcbe21832121ff155b\nmsgid \"narrower than Helvetica\"\nmsgstr \"Helveticaよりも狭い\"\n\n#: ../../font.rst:115 01a9c98efef34d0aba6ba3fa0d37813b\nmsgid \"figbo\"\nmsgstr \"\"\n\n#: ../../font.rst:115 b83719e8b5724cd69e516c29b9367ebb\nmsgid \"FiraGO Bold\"\nmsgstr \"FiraGO ボールド\"\n\n#: ../../font.rst:116 4bbe563434c7425796dc77766d23c9c8\nmsgid \"figit\"\nmsgstr \"\"\n\n#: ../../font.rst:116 480523c94e564e26be18e84adb38e861\nmsgid \"FiraGO Italic\"\nmsgstr \"FiraGO イタリック\"\n\n#: ../../font.rst:117 1e31c41d5df44c4fb09a83fdbd89e06d\nmsgid \"figbi\"\nmsgstr \"\"\n\n#: ../../font.rst:117 0e71b818d3cd4256a6f49c7416f6b1ca\nmsgid \"FiraGO Bold Italic\"\nmsgstr \"FiraGO ボールドイタリック\"\n\n#: ../../font.rst:118 7137d532bea243b482a7189e3a3286f8\nmsgid \"fimo\"\nmsgstr \"\"\n\n#: ../../font.rst:118 d52c3785bf6c4c6c9fa414b6953b3c21\nmsgid \"Fira Mono Regular\"\nmsgstr \"Fira Mono レギュラー\"\n\n#: ../../font.rst:119 a6bb6a057367406e8c6451c50221bd10\nmsgid \"fimbo\"\nmsgstr \"\"\n\n#: ../../font.rst:119 a9be831c53d643c381182387817e7347\nmsgid \"Fira Mono Bold\"\nmsgstr \"Fira Mono ボールド\"\n\n#: ../../font.rst:120 2ff90048652c45d8ad808bd8e873a930\nmsgid \"spacemo\"\nmsgstr \"\"\n\n#: ../../font.rst:120 10b17a9bdac441b2a4af57265d22e503\nmsgid \"Space Mono Regular\"\nmsgstr \"Space Mono レギュラー\"\n\n#: ../../font.rst:120 ../../font.rst:121 ../../font.rst:122 ../../font.rst:123\n#: 71f76d3cde6b47a3b8a7a0a571913454 74e5c245413f43a1b0bcd54884d11f9b\n#: 811a2ce8ecf443c3b7c4a0009f550f69 ad9d314c839645d1b264c21f9d500a5d\nmsgid \"v1.0.1\"\nmsgstr \"\"\n\n#: ../../font.rst:121 cc6628c7c246454785eae18aa76df135\nmsgid \"spacembo\"\nmsgstr \"\"\n\n#: ../../font.rst:121 899d31ca415d4d60a771344775afb052\nmsgid \"Space Mono Bold\"\nmsgstr \"Space Mono ボールド\"\n\n#: ../../font.rst:122 0fa8a8df23aa46a18ebc85a45faef555\nmsgid \"spacemit\"\nmsgstr \"\"\n\n#: ../../font.rst:122 121e740c51fa4e13b45b780076fdc770\nmsgid \"Space Mono Italic\"\nmsgstr \"Space Mono イタリック\"\n\n#: ../../font.rst:123 8c761931925c4c9080802855c8de2158\nmsgid \"spacembi\"\nmsgstr \"\"\n\n#: ../../font.rst:123 c294981796074117b39f66e1d0fc697f\nmsgid \"Space Mono Bold-Italic\"\nmsgstr \"Space Mono ボールドイタリック\"\n\n#: ../../font.rst:124 fb3d22993d774962addb0d5e18962566\nmsgid \"math\"\nmsgstr \"\"\n\n#: ../../font.rst:124 d72ffadba17c47d98e45bad69d43f48a\nmsgid \"Noto Sans Math Regular\"\nmsgstr \"Noto Sans Math レギュラー\"\n\n#: ../../font.rst:124 ../../font.rst:125 ../../font.rst:126 ../../font.rst:127\n#: 4a51871589de44a49f3d817a3e4641ca a1e187ea3001421b848c3e15b2da294f\n#: c7f9419b4b474f9990c0e7b2548b89bd f44b20960c864e1a812db6b82ccc7b01\nmsgid \"v1.0.2\"\nmsgstr \"\"\n\n#: ../../font.rst:124 3527017ccae847e198b6aa3fd407bf86\nmsgid \"math symbols\"\nmsgstr \"数学記号\"\n\n#: ../../font.rst:125 f0c044192be8422bbb062dcfe3fa3867\nmsgid \"music\"\nmsgstr \"\"\n\n#: ../../font.rst:125 5091921f86b8478b884595a229b30799\nmsgid \"Noto Music Regular\"\nmsgstr \"Noto Music レギュラー\"\n\n#: ../../font.rst:125 0cfb05fc68a6412895e997a6f27ab557\nmsgid \"musical symbols\"\nmsgstr \"音楽記号\"\n\n#: ../../font.rst:126 198d0ac76851400696fd7bfe7e9c60b3\nmsgid \"symbol1\"\nmsgstr \"\"\n\n#: ../../font.rst:126 8bf74ea20b3d41c081691ba396ba7ec2\nmsgid \"Noto Sans Symbols Regular\"\nmsgstr \"Noto Sans Symbols レギュラー\"\n\n#: ../../font.rst:126 96ef9a86cd4c4af9ad70de3493072981\nmsgid \"replacement for \\\"symb\\\"\"\nmsgstr \"\\\"symb\\\"の代替\"\n\n#: ../../font.rst:127 4eae35b6626f44edb67bbd03f28f00d6\nmsgid \"symbol2\"\nmsgstr \"\"\n\n#: ../../font.rst:127 b1fdca63e3d74dd29efec985e0b244dc\nmsgid \"Noto Sans Symbols2 Regular\"\nmsgstr \"Noto Sans Symbols2 レギュラー\"\n\n#: ../../font.rst:127 0bd6d32f20eb48dd988041621b3d5200\nmsgid \"extended symbol set\"\nmsgstr \"拡張記号セット\"\n\n#: ../../font.rst:128 aa751e08f13849d1a55e72c6aebf8f49\nmsgid \"notos\"\nmsgstr \"\"\n\n#: ../../font.rst:128 89dea662c0eb4c7eb232a7fdba6ebc9a\nmsgid \"Noto Sans Regular\"\nmsgstr \"Noto Sans レギュラー\"\n\n#: ../../font.rst:128 ../../font.rst:129 ../../font.rst:130 ../../font.rst:131\n#: 459d3d0e43ff4bf5aa61c68e8e685e29 67cb7c095cf74781840d29e84aa0034b\n#: 91a98cec9643445d9d588f6c148714f4 d8bd23d980b1436583464316e47308db\nmsgid \"v1.0.3\"\nmsgstr \"\"\n\n#: ../../font.rst:128 6b98b595462b4d478057da307cdea30a\nmsgid \"alternative to Helvetica\"\nmsgstr \"Helveticaの代替\"\n\n#: ../../font.rst:129 691a807af162494ab0b5af4186c9110c\nmsgid \"notosit\"\nmsgstr \"\"\n\n#: ../../font.rst:129 24201a800ba0419c9bee4bf90edf8825\nmsgid \"Noto Sans Italic\"\nmsgstr \"Noto Sans イタリック\"\n\n#: ../../font.rst:130 4dd91c5ba63544bba1ceb32e1fdefd55\nmsgid \"notosbo\"\nmsgstr \"\"\n\n#: ../../font.rst:130 ff244216f5904a4697fcab3f6d021a6a\nmsgid \"Noto Sans Bold\"\nmsgstr \"Noto Sans ボールド\"\n\n#: ../../font.rst:131 aa8c2e1781f54593b3331c086c19b814\nmsgid \"notosbi\"\nmsgstr \"\"\n\n#: ../../font.rst:131 6857edcacab24c27817264bb11d9bdad\nmsgid \"Noto Sans BoldItalic\"\nmsgstr \"Noto Sans ボールドイタリック\"\n\n#: ../../font.rst:141 2a37a1a4a1aa4945b8df8dbf7e64e154\nmsgid \"\"\n\"Check whether the unicode ``chr`` exists in the font or (option) some \"\n\"fallback font. May be used to check whether any \\\"TOFU\\\" symbols will \"\n\"appear on output.\"\nmsgstr \"\"\n\"指定した Unicode 文字 ``chr`` \"\n\"がフォント内または（オプションで）フォールバックフォント内に存在するかどうかを確認します。これは、「TOFU（豆腐）」と呼ばれる記号が出力に表示されるかどうかを確認するために使用できます。\"\n\n#: ../../font.rst:143 009b9aeb3f9944d596e9f49f9899c324\nmsgid \"the unicode of the character (i.e. ``ord()``).\"\nmsgstr \"文字の Unicode 値（すなわち、``ord()`` 関数の結果）。\"\n\n#: ../../font.rst:144 a8641b2b63ec4b07875c388e202271b9\nmsgid \"the language -- currently unused.\"\nmsgstr \"言語（現在は未使用）。\"\n\n#: ../../font.rst:145 1bf9dc08f5954b5f965c6b5ea1570763\nmsgid \"the UCDN script number.\"\nmsgstr \"UCDN（Unicode Common Locale Data Repository）スクリプト番号。\"\n\n#: ../../font.rst:146 c652199037ea41779589cd7c702796e7\nmsgid \"\"\n\"*(new in v1.17.5)* perform an extended search in fallback fonts or \"\n\"restrict to current font (default).\"\nmsgstr \"*（v1.17.5 で新たに追加）* フォールバックフォントでの拡張検索を実行するか、現在のフォントに制限するかを指定します（デフォルト）。\"\n\n#: ../../font.rst:147 97e5feeeb43a4af0bb9163c00cad3e2b\nmsgid \"*(changed in 1.17.7)* the glyph number. Zero indicates no glyph found.\"\nmsgstr \"*（v1.17.7 で変更）* グリフ番号。ゼロはグリフが見つからないことを示します。\"\n\n#: ../../font.rst:151 fed10a374e2445d1be29d1f78a496de5\nmsgid \"New in v1.17.5\"\nmsgstr \"v1.17.5 で新たに追加\"\n\n#: ../../font.rst:153 290f44f3033a469e89d5444b5d3ec4f9\nmsgid \"Return an array of unicodes supported by this font.\"\nmsgstr \"このフォントがサポートする Unicode の配列を返します。\"\n\n#: ../../font.rst:155 ab16e827b27d4022b45b4c90a328da02\n#, python-format\nmsgid \"\"\n\"an ``array.array`` [#f2]_ of length at most :attr:`Font.glyph_count`. \"\n\"I.e. ``chr()`` of every item in this array has a glyph in the font \"\n\"without using fallbacks. This is an example display of the supported \"\n\"glyphs:  >>> import pymupdf >>> font = pymupdf.Font(\\\"math\\\") >>> vuc = \"\n\"font.valid_codepoints() >>> for i in vuc:       print(\\\"%04X %s (%s)\\\" % \"\n\"(i, chr(i), font.unicode_to_glyph_name(i))) 0000 000D   (CR) 0020   \"\n\"(space) 0021 ! (exclam) 0022 \\\" (quotedbl) 0023 # (numbersign) 0024 $ \"\n\"(dollar) 0025 % (percent) ... 00AC ¬ (logicalnot) 00B1 ± (plusminus) ... \"\n\"21D0 ⇐ (arrowdblleft) 21D1 ⇑ (arrowdblup) 21D2 ⇒ (arrowdblright) 21D3 ⇓ \"\n\"(arrowdbldown) 21D4 ⇔ (arrowdblboth) ... 221E ∞ (infinity) ...\"\nmsgstr \"\"\n\n#: ../../font.rst:155 7031be6a1bcf4a65b62350eb968608e6\nmsgid \"\"\n\"an ``array.array`` [#f2]_ of length at most :attr:`Font.glyph_count`. \"\n\"I.e. ``chr()`` of every item in this array has a glyph in the font \"\n\"without using fallbacks. This is an example display of the supported \"\n\"glyphs:\"\nmsgstr \"\"\n\":attr:`Font.glyph_count` 以上の長さを持つ ``array.array`` [#f2]_。つまり、この配列内の各アイテムの\"\n\" ``chr()`` は、フォールバックを使用せずにフォント内にグリフを持っていることを示します。以下はサポートされるグリフの例示です：\"\n\n#: ../../font.rst:183 c5ad65fa71a74dd9a63ab09809f0f9cf\nmsgid \"\"\n\"This method only returns meaningful data for fonts having a CMAP \"\n\"(character map, charmap, the `/ToUnicode` PDF key). Otherwise, this array\"\n\" will have length 1 and contain zero only.\"\nmsgstr \"\"\n\"このメソッドは、CMAP（文字マップ、charmap、`/ToUnicode` PDF \"\n\"キー）を持つフォントに対してのみ意味のあるデータを返します。それ以外の場合、この配列は長さ1で、ゼロのみを含みます。\"\n\n#: ../../font.rst:192 af8b042889b54a38b2a5ddd689449328\nmsgid \"Calculate the \\\"width\\\" of the character's glyph (visual representation).\"\nmsgstr \"文字のグリフ（視覚的な表現）の「幅」を計算します。\"\n\n#: ../../font.rst:194 c1f6c6b34907404e97ad72617e0fc346\nmsgid \"\"\n\"the unicode number of the character. Use ``ord()``, not the character \"\n\"itself. Again, this should normally work even if a character is not \"\n\"supported by that font, because fallback fonts will be checked where \"\n\"necessary.\"\nmsgstr \"\"\n\"文字のUnicode番号。文字自体ではなく、``ord()`` \"\n\"を使用します。文字がそのフォントでサポートされていない場合でも、必要に応じてフォールバックフォントがチェックされるため、通常は機能するはずです。\"\n\n#: ../../font.rst:195 e838a07682d84a869e2fa1cc89abf58a\nmsgid \"write mode, ``0`` = horizontal, ``1`` = vertical.\"\nmsgstr \"書き込みモード、 ``0`` = 横方向、 ``1`` = 縦方向。\"\n\n#: ../../font.rst:197 2dc7e2ceacbb4ef690b919a430d04d1b\nmsgid \"The other parameters are not in use currently.\"\nmsgstr \"その他のパラメータは現在使用されていません。\"\n\n#: ../../font.rst:199 e8423a5397284db1919f456052773ded\nmsgid \"a float representing the glyph's width relative to **fontsize 1**.\"\nmsgstr \"**フォントサイズ** 1に対するグリフの幅を表す浮動小数点数。\"\n\n#: ../../font.rst:203 47dc9dab1b4c4cb8b9e6a069008d81b1\nmsgid \"\"\n\"Return the unicode value for a given glyph name. Use it in conjunction \"\n\"with `chr()` if you want to output e.g. a certain symbol.\"\nmsgstr \"指定されたグリフ名のUnicode値を返します。特定のシンボルを出力したい場合は、`chr()` と組み合わせて使用します。\"\n\n#: ../../font.rst:205 749831c099134aa7bf7ffe282b0836b5\nmsgid \"The name of the glyph.\"\nmsgstr \"グリフの名前。\"\n\n#: ../../font.rst:207 377293d9901943dbb4c7c31c7985c7d9\nmsgid \"\"\n\"The unicode integer, or 65533 = 0xFFFD if the name is unknown. Examples: \"\n\"`font.glyph_name_to_unicode(\\\"Sigma\\\") = 931`, \"\n\"`font.glyph_name_to_unicode(\\\"sigma\\\") = 963`. Refer to the `Adobe Glyph \"\n\"List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ publication for a list of glyph names \"\n\"and their unicode numbers. Example:  >>> font = pymupdf.Font(\\\"helv\\\") \"\n\">>> font.has_glyph(font.glyph_name_to_unicode(\\\"infinity\\\")) True\"\nmsgstr \"\"\n\n#: ../../font.rst:207 765a70f4e5934d66adf72deeaaad3599\nmsgid \"\"\n\"The unicode integer, or 65533 = 0xFFFD if the name is unknown. Examples: \"\n\"`font.glyph_name_to_unicode(\\\"Sigma\\\") = 931`, \"\n\"`font.glyph_name_to_unicode(\\\"sigma\\\") = 963`. Refer to the `Adobe Glyph \"\n\"List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ publication for a list of glyph names \"\n\"and their unicode numbers. Example:\"\nmsgstr \"\"\n\"Unicode整数、または名前が不明な場合は65533 = \"\n\"0xFFFDです。例：`font.glyph_name_to_unicode(\\\"Sigma\\\") = \"\n\"931`、`font.glyph_name_to_unicode(\\\"sigma\\\") = 963` 。Adobe Glyph \"\n\"Listの出版物を参照して、グリフ名とUnicode番号のリストを確認してください。例：\"\n\n#: ../../font.rst:219 ceed99f4b1f641ae9879e4ef9b43cfcf\nmsgid \"The glyph rectangle relative to :data:`fontsize` 1.\"\nmsgstr \":data:`fontsize` 1に対するグリフの矩形領域。\"\n\n#: ../../font.rst:221 9803fc558ea94924824b3c6f36f33ce5\nmsgid \"``ord()`` of the character.\"\nmsgstr \"文字の ``ord()`` 。\"\n\n#: ../../font.rst:223 cae0a18260bf47dcb9d033363ab5176b\nmsgid \"a :ref:`Rect`.\"\nmsgstr \":ref:`Rect`。\"\n\n#: ../../font.rst:228 c530486f148348589a870c1a6fad982d\nmsgid \"Show the name of the character's glyph.\"\nmsgstr \"文字のグリフの名前を表示します。\"\n\n#: ../../font.rst:230 b33374c8c5234c618bbb03b5c25bd99b\nmsgid \"\"\n\"the unicode number of the character. Use ``ord()``, not the character \"\n\"itself.\"\nmsgstr \"文字のunicode番号。文字自体ではなく ``ord()`` を使用します。\"\n\n#: ../../font.rst:232 39265ca9c3774508a81f7b6c33627e8d\nmsgid \"\"\n\"a string representing the glyph's name. E.g. `font.glyph_name(ord(\\\"#\\\"))\"\n\" = \\\"numbersign\\\"`. For an invalid code \\\".notfound\\\" is returned.  .. \"\n\"note:: *(Changed in v1.18.0)* This method and \"\n\":meth:`Font.glyph_name_to_unicode` no longer depend on a font and instead\"\n\" retrieve information from the **Adobe Glyph List**. Also available as \"\n\"`pymupdf.unicode_to_glyph_name()` and resp. \"\n\"`pymupdf.glyph_name_to_unicode()`.\"\nmsgstr \"\"\n\n#: ../../font.rst:232 7b64931c6f244cfca3c0761329de7f73\nmsgid \"\"\n\"a string representing the glyph's name. E.g. `font.glyph_name(ord(\\\"#\\\"))\"\n\" = \\\"numbersign\\\"`. For an invalid code \\\".notfound\\\" is returned.\"\nmsgstr \"\"\n\"グリフの名前を表す文字列。例：`font.glyph_name(ord(\\\"#\\\")) = \\\"numbersign\\\"` \"\n\"。無効なコードの場合、\\\".notfound\\\" が返されます。\"\n\n#: ../../font.rst:234 20712f7e063243888f6395b18c3acae8\nmsgid \"\"\n\"*(Changed in v1.18.0)* This method and :meth:`Font.glyph_name_to_unicode`\"\n\" no longer depend on a font and instead retrieve information from the \"\n\"**Adobe Glyph List**. Also available as `pymupdf.unicode_to_glyph_name()`\"\n\" and resp. `pymupdf.glyph_name_to_unicode()`.\"\nmsgstr \"\"\n\"*(1.18.0で変更)* このメソッドと:meth:`Font.glyph_name_to_unicode` \"\n\"はもはやフォントに依存せず、**Adobe Glyph List** \"\n\"から情報を取得します。`pymupdf.unicode_to_glyph_name()` とresp. \"\n\"`pymupdf.glyph_name_to_unicode()` としても利用可能です。\"\n\n#: ../../font.rst:241 38b6209e6a4344a8b3be848dc476755c\nmsgid \"Calculate the length in points of a unicode string.\"\nmsgstr \"Unicode文字列の長さをポイント単位で計算します。\"\n\n#: ../../font.rst:243 142ac4b87bb644ffa8514275b3e51007\nmsgid \"\"\n\"There is a functional overlap with :meth:`get_text_length` for Base-14 \"\n\"fonts only.\"\nmsgstr \"Base-14フォントに対しては、:meth:`get_text_length` と機能が重複しています。\"\n\n#: ../../font.rst:245 ../../font.rst:269 7c8abec195d7425ab74856419d327b59\n#: f31ddd69af474ca98115ec49230627cf\nmsgid \"a text string, UTF-8 encoded.\"\nmsgstr \"テキスト文字列、UTF-8エンコード。\"\n\n#: ../../font.rst:247 ../../font.rst:271 280e2e6390a84299b1eb50742751cc45\n#: 5880b72ffefe4073a534b44ef82aa00b\nmsgid \"the :data:`fontsize`.\"\nmsgstr \":data:`fontsize`。\"\n\n#: ../../font.rst 24af9fb41f6d40be800f9d6a56909af0\n#: 375fd3e160764b6f97a1b86fc740fe8a 465db7792c4b472f806017a0d364f367\n#: 53682f9b23a84002ab90b511020b49f6 5fa74d99fa99412f91d3a82aefa8e4bf\n#: 70db0a0a767e4ee8867951f816a54be0 9353b0e144af4fc7a2f47be5d63e325b\n#: b579c7fff96e4c608f8eb22666e2666d d2e13bff74024b768ddd4405202d6cab\n#: d3196a22363c47ecb37dd5972f00334e\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../font.rst:251 ec7a7979f9e7418fbdceaeee4f29b39d\nmsgid \"\"\n\"the length of the string in points when stored in the PDF. If a character\"\n\" is not contained in the font, it will automatically be looked up in a \"\n\"fallback font.  .. note:: This method was originally implemented in \"\n\"Python, based on calling :meth:`Font.glyph_advance`. For performance \"\n\"reasons, it has been rewritten in C for v1.18.14. To compute the width of\"\n\" a single character, you can now use either of the following without \"\n\"performance penalty:     1. `font.glyph_advance(ord(\\\"Ä\\\")) * fontsize`\"\n\"    2. `font.text_length(\\\"Ä\\\", fontsize=fontsize)`     For multi-\"\n\"character strings, the method offers a huge performance advantage \"\n\"compared to the previous implementation: instead of about 0.5 \"\n\"microseconds for each character, only 12.5 nanoseconds are required for \"\n\"the second and subsequent ones.\"\nmsgstr \"\"\n\n#: ../../font.rst:251 f41d04198f2341a990157155d7f740b1\nmsgid \"\"\n\"the length of the string in points when stored in the PDF. If a character\"\n\" is not contained in the font, it will automatically be looked up in a \"\n\"fallback font.\"\nmsgstr \"PDFに格納された文字列のポイント単位の長さ。文字がフォントに含まれていない場合、自動的にフォールバックフォントで検索されます。\"\n\n#: ../../font.rst:253 57ccdf4bd0474e3280e1cdda9d041027\nmsgid \"\"\n\"This method was originally implemented in Python, based on calling \"\n\":meth:`Font.glyph_advance`. For performance reasons, it has been \"\n\"rewritten in C for v1.18.14. To compute the width of a single character, \"\n\"you can now use either of the following without performance penalty:\"\nmsgstr \"\"\n\"このメソッドは元々Pythonで実装され、:meth:`Font.glyph_advance` \"\n\"を呼び出すことに基づいていました。性能の理由から、v1.18.14向けにCで書き直されました。単一の文字の幅を計算するには、以下のいずれかを使用でき、パフォーマンスに差異はありません：\"\n\n#: ../../font.rst:255 b485562f46994ef3a76ed0ba8f486f14\nmsgid \"`font.glyph_advance(ord(\\\"Ä\\\")) * fontsize`\"\nmsgstr \"\"\n\n#: ../../font.rst:256 7b3106bb9bf0498198809c557ab60339\nmsgid \"`font.text_length(\\\"Ä\\\", fontsize=fontsize)`\"\nmsgstr \"\"\n\n#: ../../font.rst:258 3724b3d50f664946b0d42d8fab2f84f6\nmsgid \"\"\n\"For multi-character strings, the method offers a huge performance \"\n\"advantage compared to the previous implementation: instead of about 0.5 \"\n\"microseconds for each character, only 12.5 nanoseconds are required for \"\n\"the second and subsequent ones.\"\nmsgstr \"複数文字の文字列に対して、このメソッドは以前の実装と比べて非常に高速で、各文字ごとに約0.5マイクロ秒かかる代わりに、2番目以降の文字には12.5ナノ秒しか必要ありません。\"\n\n#: ../../font.rst:265 aafd060e84e541abbe7b30af94aa8ded\nmsgid \"*New in v1.18.14*\"\nmsgstr \"*v1.18.14で新たに導入*\"\n\n#: ../../font.rst:267 7decb74d1d39477b9462d29370e42a35\nmsgid \"Sequence of character lengths in points of a unicode string.\"\nmsgstr \"Unicode文字列の文字の長さ（ポイント単位）のシーケンス。\"\n\n#: ../../font.rst:275 76401a090dc249fcab049f83b6f83cee\nmsgid \"\"\n\"the lengths in points of the characters of a string when stored in the \"\n\"PDF. It works like :meth:`Font.text_length` broken down to single \"\n\"characters. This is a high speed method, used e.g. in \"\n\":meth:`TextWriter.fill_textbox`. The following is true (allowing rounding\"\n\" errors): `font.text_length(text) == sum(font.char_lengths(text))`.  >>> \"\n\"font = pymupdf.Font(\\\"helv\\\") >>> text = \\\"PyMuPDF\\\" >>> \"\n\"font.text_length(text) 50.115999937057495 >>> \"\n\"pymupdf.get_text_length(text, fontname=\\\"helv\\\") 50.115999937057495 >>> \"\n\"sum(font.char_lengths(text)) 50.115999937057495 >>> \"\n\"pprint(font.char_lengths(text)) (7.336999952793121,  # P 5.5,\"\n\"                 # y 9.163000047206879,   # M 6.115999937057495,   # u \"\n\"7.336999952793121,   # P 7.942000031471252,   # D 6.721000015735626)   # \"\n\"F\"\nmsgstr \"\"\n\n#: ../../font.rst:275 1544e745681a4b6da063619a2e9620b7\nmsgid \"\"\n\"the lengths in points of the characters of a string when stored in the \"\n\"PDF. It works like :meth:`Font.text_length` broken down to single \"\n\"characters. This is a high speed method, used e.g. in \"\n\":meth:`TextWriter.fill_textbox`. The following is true (allowing rounding\"\n\" errors): `font.text_length(text) == sum(font.char_lengths(text))`.\"\nmsgstr \"\"\n\"PDFに保存される文字列の各文字の長さ（ポイント単位）。これは、:meth:`Font.text_length` \"\n\"を各文字に分解したようなものです。高速なメソッドであり、例えば:meth:`TextWriter.fill_textbox` \"\n\"で使用されています。以下が成り立ちます（丸め誤差を許容する）：`font.text_length(text) == \"\n\"sum(font.char_lengths(text))`。\"\n\n#: ../../font.rst:297 d80b29e9dd8c454da9c51b26d9cad2fe\nmsgid \"New in v1.17.6\"\nmsgstr \"新機能 v1.17.6\"\n\n#: ../../font.rst:299 30834747dcfd4dc48a79f57ad356cdd3\nmsgid \"Copy of the binary font file content.\"\nmsgstr \"バイナリフォントファイルのコンテンツのコピー。\"\n\n#: ../../font.rst:305 71cd13ec6bab4c46bb9c7dbb8108fb63\nmsgid \"\"\n\"A dictionary with various font properties, each represented as bools. \"\n\"Example for Helvetica::\"\nmsgstr \"Helveticaの例など、さまざまなフォントプロパティを持つ辞書で、それぞれがブール値として表されています。\"\n\n#: ../../font.rst:325 dbe85241cd3a4910a0da84236fc69d03\nmsgid \"Name of the font. May be \\\"\\\" or \\\"(null)\\\".\"\nmsgstr \"フォントの名前。空文字列であることもあります。\"\n\n#: ../../font.rst:329 190864bf642d4836b3e8ed0493dc4672\nmsgid \"The font bbox. This is the maximum of its glyph bboxes.\"\nmsgstr \"フォントのbbox。これは、そのグリフのbboxの最大値です。\"\n\n#: ../../font.rst:331 33b968a3b28241e9a604dd232bd3bf7c\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../font.rst:337 38e95b49eec642f784ca39d58b0b40df\nmsgid \"The number of glyphs defined in the font.\"\nmsgstr \"グリフ数。\"\n\n#: ../../font.rst:341 ../../font.rst:349 aa9a0f03418b4adba2109af305a941e1\n#: b18be968a53743bdb4bdab316af4c374\nmsgid \"New in v1.18.0\"\nmsgstr \"v1.18.0で新規追加\"\n\n#: ../../font.rst:343 d3c64bfaff7540aa857c6dcc2fc2b0a0\nmsgid \"\"\n\"The ascender value of the font, see `ascender typography \"\n\"<https://en.wikipedia.org/wiki/Ascender_(typography)>`_ for details. \"\n\"Please note that there is a difference to the strict definition: our \"\n\"value includes everything above the baseline -- not just the height \"\n\"difference between upper case \\\"A\\\" and and lower case \\\"a\\\".\"\nmsgstr \"フォントのアセンダー値。詳細についてはこちらを参照してください。ただし、厳密な定義とは異なり、私たちの値にはベースラインを上回るすべてが含まれます。単に大文字の「A」と小文字の「a」の高さの違いだけでなく、ベースラインを上回るすべてが含まれます。\"\n\n#: ../../font.rst:351 7fba1bd77fd74cc1abdb335fe3269fbc\nmsgid \"\"\n\"The descender value of the font, see `descender typography \"\n\"<https://en.wikipedia.org/wiki/Descender>`_ for details. This value \"\n\"always is negative and is the portion that some glyphs descend below the \"\n\"base line, for example \\\"g\\\" or \\\"y\\\". As a consequence, the value \"\n\"`ascender - descender` is the total height, that every glyph of the font \"\n\"fits into. This is true at least for most fonts -- as always, there are \"\n\"exceptions, especially for calligraphic fonts, etc.\"\nmsgstr \"\"\n\"フォントのディセンダー値。詳細についてはこちらを参照してください。この値は常に負であり、一部のグリフがベースライン以下に降りる部分、例えば「g」や「y」です。したがって、`アセンダー\"\n\" - ディセンダー` \"\n\"の値は、フォントのすべてのグリフが収まる総高さです。これはほとんどのフォントに当てはまりますが、いくつかの例外があります。特にカリグラフィーフォントなどです。\"\n\n#: ../../font.rst:363 4ffede0fc21c4b5fa0f667a903b92e93\nmsgid \"\"\n\"A number of attributes with obvious meanings. Reflect some values of the \"\n\":attr:`Font.flags` dictionary.\"\nmsgstr \"明らかな意味を持つ属性がいくつかあります。これらは :attr:`Font.flags` 辞書の値の一部を反映しています。\"\n\n#: ../../font.rst:368 4bd92baafe77479faa63b31082e0c69a\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../font.rst:369 d66637c72e2b45aea7edd3cb116ec328\nmsgid \"\"\n\"MuPDF does not support all fontfiles with this feature and will raise \"\n\"exceptions like *\\\"mupdf: FT_New_Memory_Face((null)): unknown file \"\n\"format\\\"*, if it encounters issues.\"\nmsgstr \"\"\n\"MuPDFはこの機能を持つすべてのフォントファイルをサポートしておらず、問題が発生すると *「mupdf: \"\n\"FT_New_Memory_Face((null)): unknown file format」* \"\n\"といった例外を発生させます。:ref:`TextWriter` のメソッドは :attr:`Font.is_writable` をチェックします。\"\n\n#: ../../font.rst:371 7213fcc59c214e508d3da6221ec0d21a\nmsgid \"\"\n\"The built-in Python module `array` has been chosen for its speed and low \"\n\"memory requirement.\"\nmsgstr \"組み込みの *array* モジュールは、その速度と値のコンパクトな表現のために選択されました。\"\n\n#: ../../footer.rst:46 3dc04747492b4b4bac6e2c6af8d83002\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \":attr:`~Font.is_writable`\"\n#~ msgstr \"\"\n\n#~ msgid \"Font usable with :ref:`TextWriter`\"\n#~ msgstr \":ref:`TextWriter` で使用可能なフォント\"\n\n#~ msgid \"Indicates whether this font can be used with :ref:`TextWriter`.\"\n#~ msgstr \"このフォントを :ref:`TextWriter` で使用できるかどうかを示します。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"a MuPDF font if successful. This \"\n#~ \"is the overall sequence of checks \"\n#~ \"to determine an appropriate font:  \"\n#~ \"=========== \"\n#~ \"============================================================ \"\n#~ \"Argument    Action =========== \"\n#~ \"============================================================ \"\n#~ \"fontfile?   Create font from file, \"\n#~ \"exception if failure. fontbuffer? Create \"\n#~ \"font from buffer, exception if failure.\"\n#~ \" ordering>=0 Create universal font, always\"\n#~ \" succeeds. fontname?   Create a Base-14 \"\n#~ \"font, universal font, or font             \"\n#~ \"provided by `pymupdf-fonts \"\n#~ \"<https://pypi.org/project/pymupdf-fonts/>`_. See \"\n#~ \"table below. =========== \"\n#~ \"============================================================\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/footer.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../footer.rst:60 74c961cfd0e64769bcdb58467763a6c6\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/functions.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4362cd8e08a74daebc63e2250a1293cd\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 8c3fd3acd0a54dacaaaea104c5ca20e2\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 7d4f452edf45487b8855a2fdb4b7f37b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../functions.rst:5 764415be522b4af7bed822bf808d3c81\nmsgid \"Functions\"\nmsgstr \"関数\"\n\n#: ../../functions.rst:6 7d85734965b44884afa1f60ccbb9fce3\nmsgid \"\"\n\"The following are miscellaneous functions and attributes on a fairly low-\"\n\"level technical detail.\"\nmsgstr \"以下は、PDFに関する低レベルな技術的詳細に関するさまざまな関数と属性です。\"\n\n#: ../../functions.rst:8 87eea67bd6bd469c809cfb2f400fd0ac\nmsgid \"\"\n\"Some functions provide detail access to PDF structures. Others are \"\n\"stripped-down, high performance versions of other functions which provide\"\n\" more information.\"\nmsgstr \"一部の関数は、PDF構造への詳細なアクセスを提供します。他の関数の高性能バージョンで、より多くの情報を提供する関数から派生しています。\"\n\n#: ../../functions.rst:10 3e757537a03d4b07bdcba164caba05f3\nmsgid \"Yet others are handy, general-purpose utilities.\"\nmsgstr \"また、その他にも便利な汎用ユーティリティが含まれています。\"\n\n#: ../../functions.rst:14 3a980a38ec2e42368864c2737353297a\nmsgid \"**Function**\"\nmsgstr \"**関数**\"\n\n#: ../../functions.rst:14 53d11d16c6cb41359e0d1eb9434091a8\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../functions.rst:16 add8a0f8af544090bd2b69bec2a08b06\nmsgid \":attr:`Annot.apn_bbox`\"\nmsgstr \"\"\n\n#: ../../functions.rst:16 5e6c725340da4680b4b2182ec97992ef\nmsgid \"PDF only: bbox of the appearance object\"\nmsgstr \"PDFのみ：外観オブジェクトのバウンディングボックス\"\n\n#: ../../functions.rst:17 0e00e13e8cd249aea5b27907a5924ac2\nmsgid \":attr:`Annot.apn_matrix`\"\nmsgstr \"\"\n\n#: ../../functions.rst:17 f099fa1353fa448486e549396e8c85c4\nmsgid \"PDF only: the matrix of the appearance object\"\nmsgstr \"PDFのみ：外観オブジェクトの行列\"\n\n#: ../../functions.rst:18 04cb195c672149e79a5dbf453e0dd2d2\nmsgid \":attr:`Page.is_wrapped`\"\nmsgstr \"\"\n\n#: ../../functions.rst:18 733534121ca84a7dae39d79a0e4fdf8e\nmsgid \"check whether contents wrapping is present\"\nmsgstr \"コンテンツの折り返しが存在するかどうかを確認します\"\n\n#: ../../functions.rst:19 6070d8798ae847c7b81482b126630c8a\nmsgid \":meth:`adobe_glyph_names`\"\nmsgstr \"\"\n\n#: ../../functions.rst:19 3e1263f453fb48c78527c09031c8dfda\nmsgid \"list of glyph names defined in **Adobe Glyph List**\"\nmsgstr \"**Adobe Glyph List** で定義されたグリフ名のリスト\"\n\n#: ../../functions.rst:20 8540cf95e6284b908e38968f6e2b84b1\nmsgid \":meth:`adobe_glyph_unicodes`\"\nmsgstr \"\"\n\n#: ../../functions.rst:20 868c1c4b39334083b57fc6f75dc63c73\nmsgid \"list of unicodes defined in **Adobe Glyph List**\"\nmsgstr \"**Adobe Glyph List** で定義されたUnicodeのリスト\"\n\n#: ../../functions.rst:21 b9f2db6bdc1f4375b9d86730afc564cf\nmsgid \":meth:`Annot.clean_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:21 c89e0a09bfd5482e9a00164e53985cdb\nmsgid \"PDF only: clean the annot's :data:`contents` object\"\nmsgstr \"PDFのみ：アノテーションの :data:`contents` オブジェクトをクリーンアップ\"\n\n#: ../../functions.rst:22 32cff1b105fc415ab1df92fb4a1367ee\nmsgid \":meth:`Annot.set_apn_bbox`\"\nmsgstr \"\"\n\n#: ../../functions.rst:22 490b8142dc73479a84f8532efe1a7dd0\nmsgid \"PDF only: set the bbox of the appearance object\"\nmsgstr \"PDFのみ：外観オブジェクトのバウンディングボックスを設定\"\n\n#: ../../functions.rst:23 825eafcadc4840a6b3da5b4eae9803b5\nmsgid \":meth:`Annot.set_apn_matrix`\"\nmsgstr \"\"\n\n#: ../../functions.rst:23 bd593d88e1054999ba94daf514352282\nmsgid \"PDF only: set the matrix of the appearance object\"\nmsgstr \"PDFのみ：外観オブジェクトの行列を設定\"\n\n#: ../../functions.rst:24 c442dc2915174eb9bca27cc7aaec5a63\nmsgid \":meth:`ConversionHeader`\"\nmsgstr \"\"\n\n#: ../../functions.rst:24 39f5b60624524140bcf3d19279f48605\nmsgid \"return header string for *get_text* methods\"\nmsgstr \"*get_text* メソッド用のヘッダー文字列を返す\"\n\n#: ../../functions.rst:25 2832c8a25ff645c1833824445cd50d2e\nmsgid \":meth:`ConversionTrailer`\"\nmsgstr \"\"\n\n#: ../../functions.rst:25 809aa5cd142a4d28927bdedc1f5d789a\nmsgid \"return trailer string for *get_text* methods\"\nmsgstr \"*get_text* メソッド用のトレーラー文字列を返す\"\n\n#: ../../functions.rst:26 793c18c2f91c4349a65f71f6504d9872\nmsgid \":meth:`Document.del_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../functions.rst:26 2c210b89288b437482fee9c882c0c7a4\nmsgid \"PDF only: remove XML metadata\"\nmsgstr \"PDFのみ：XMLメタデータを削除\"\n\n#: ../../functions.rst:27 0bd03bc3092d4f75ab36f591dd57098a\nmsgid \":meth:`Document.get_char_widths`\"\nmsgstr \"\"\n\n#: ../../functions.rst:27 cb86339da05542aaafc997cf781c9fb9\nmsgid \"PDF only: return a list of glyph widths of a font\"\nmsgstr \"PDFのみ：フォントのグリフ幅のリストを返す\"\n\n#: ../../functions.rst:28 56fc88a38fce4ad58e50e488249dc90a\nmsgid \":meth:`Document.get_new_xref`\"\nmsgstr \"\"\n\n#: ../../functions.rst:28 950c2315e268432ca322e1428ccede80\nmsgid \"PDF only: create and return a new :data:`xref` entry\"\nmsgstr \"PDFのみ：新しい :data:`xref` エントリを作成して返す\"\n\n#: ../../functions.rst:29 496d02cad3d94be590dc49051170a1c4\nmsgid \":meth:`Document.is_stream`\"\nmsgstr \"\"\n\n#: ../../functions.rst:29 586f78f3e3d24a80bc537b10b6756ccb\nmsgid \"PDF only: check whether an :data:`xref` is a stream object\"\nmsgstr \"PDFのみ：:data:`xref` がストリームオブジェクトであるかどうかを確認\"\n\n#: ../../functions.rst:30 578b7d1ff1d6471a84f62fa135e05681\nmsgid \":meth:`Document.xml_metadata_xref`\"\nmsgstr \"\"\n\n#: ../../functions.rst:30 253ad5dd537940c684f95c34413e9613\nmsgid \"PDF only: return XML metadata :data:`xref` number\"\nmsgstr \"PDFのみ：XMLメタデータの :data:`xref` 番号を返す\"\n\n#: ../../functions.rst:31 4f8b6a367f104e19b3686d48c220b2e8\nmsgid \":meth:`Document.xref_length`\"\nmsgstr \"\"\n\n#: ../../functions.rst:31 944580e1219b4d6da596e2f0ecac1e0c\nmsgid \"PDF only: return length of :data:`xref` table\"\nmsgstr \"PDFのみ：:data:`xref` テーブルの長さを返す\"\n\n#: ../../functions.rst:32 9e00d8d6db8640a48b68b28cce3d2d56\nmsgid \":meth:`EMPTY_IRECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:32 ../../functions.rst:34\n#: 4f93c48b456e40edb3bf54e18372fbcd 8885468553b943e2804495b185674bdb\nmsgid \"return the (standard) empty / invalid rectangle\"\nmsgstr \"標準の空の/無効な矩形を返す\"\n\n#: ../../functions.rst:33 116425823f97476ba4ef170d8f70b2a5\nmsgid \":meth:`EMPTY_QUAD`\"\nmsgstr \"\"\n\n#: ../../functions.rst:33 1db98794aff94fc58a84179249ea06eb\nmsgid \"return the (standard) empty / invalid quad\"\nmsgstr \"標準の空の/無効な四角形を返す\"\n\n#: ../../functions.rst:34 9000c9e5d6c6449ea2fac2877457a80c\nmsgid \":meth:`EMPTY_RECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:35 a2378f40c3bd4ff68bf33e9d7f8d55a0\nmsgid \":meth:`get_pdf_now`\"\nmsgstr \"\"\n\n#: ../../functions.rst:35 e3d896a505e3415f91020a611d1b60cb\nmsgid \"return the current timestamp in PDF format\"\nmsgstr \"現在のタイムスタンプをPDF形式で返す\"\n\n#: ../../functions.rst:36 44be0971a3e943d4b339543e89c7d3e5\nmsgid \":meth:`get_pdf_str`\"\nmsgstr \"\"\n\n#: ../../functions.rst:36 d222dad1da46497a90683f26ca17b272\nmsgid \"return PDF-compatible string\"\nmsgstr \"PDF互換の文字列を返す\"\n\n#: ../../functions.rst:37 97fc6fa0db4446d9884dd169f4279dba\nmsgid \":meth:`get_text_length`\"\nmsgstr \"\"\n\n#: ../../functions.rst:37 110ac58da1a44ce2999975602c6c0e1a\nmsgid \"return string length for a given font & :data:`fontsize`\"\nmsgstr \"指定したフォントと :data:`fontsize` の文字列長を返す\"\n\n#: ../../functions.rst:38 c90ff4bd56b84326a2666157890bfd03\nmsgid \":meth:`glyph_name_to_unicode`\"\nmsgstr \"\"\n\n#: ../../functions.rst:38 401f5bf92bb74478b4d7029ec15dd089\nmsgid \"return unicode from a glyph name\"\nmsgstr \"グリフ名からUnicodeを返す\"\n\n#: ../../functions.rst:39 99beef3b550a46ba98443a9d326de35b\nmsgid \":meth:`image_profile`\"\nmsgstr \"\"\n\n#: ../../functions.rst:39 143bc56e8ef9413e96b151d77c64ae6f\nmsgid \"return a dictionary of basic image properties\"\nmsgstr \"基本的な画像プロパティの辞書を返します。\"\n\n#: ../../functions.rst:40 2290ac67413048f9a7e8bc3c1bed82da\nmsgid \":meth:`INFINITE_IRECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:40 ../../functions.rst:42\n#: 6c93c70e175b4feebad851e5e2d302e5 db34282539ff4d0cbcbb59a0746f4ad5\nmsgid \"return the (only existing) infinite rectangle\"\nmsgstr \"（唯一存在する）無限の矩形を返します。\"\n\n#: ../../functions.rst:41 15427ddf5f9d40ea95e44583d180da0e\nmsgid \":meth:`INFINITE_QUAD`\"\nmsgstr \"\"\n\n#: ../../functions.rst:41 c51f25d2a9ab403aaf35fdc880ac80ea\nmsgid \"return the (only existing) infinite quad\"\nmsgstr \"（唯一存在する）無限のクワッドを返します。\"\n\n#: ../../functions.rst:42 9c580aaf4136403aa2944098c657ef29\nmsgid \":meth:`INFINITE_RECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:43 ffa25a10067248539ecece4ed9e0453d\nmsgid \":meth:`make_table`\"\nmsgstr \"\"\n\n#: ../../functions.rst:43 7533bf849012437cbd56f1d3ab66a42c\nmsgid \"split rectangle in sub-rectangles\"\nmsgstr \"矩形をサブ矩形に分割します。\"\n\n#: ../../functions.rst:44 312874e2effa4bc0bfd1300774e3a463\nmsgid \":meth:`Page.clean_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:44 01e6fccf3e744a89a6858df35f24007a\nmsgid \"PDF only: clean the page's :data:`contents` objects\"\nmsgstr \"PDF のみ：ページの :data:`contents` オブジェクトをクリーンアップします\"\n\n#: ../../functions.rst:45 3dd8b9b45ab44ebba9d1b686be8dc50b\nmsgid \":meth:`Page.get_bboxlog`\"\nmsgstr \"\"\n\n#: ../../functions.rst:45 dfbe6b6c5f9f47fd88042b9ae17531f3\nmsgid \"list of rectangles that envelop text, drawing or image objects\"\nmsgstr \"テキスト、描画、または画像オブジェクトを囲む矩形のリストです。\"\n\n#: ../../functions.rst:46 c65e19fd4d02409cb4543812fa3b43d4\nmsgid \":meth:`Page.get_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:46 299985f0af5147d7aa248ec6d462f2d1\nmsgid \"PDF only: return a list of content :data:`xref` numbers\"\nmsgstr \"PDF のみ：コンテンツ :data:`xref` 番号のリストを返します。\"\n\n#: ../../functions.rst:47 c2ceb3b6204947318ef0c33b8b87b0d3\nmsgid \":meth:`Page.get_displaylist`\"\nmsgstr \"\"\n\n#: ../../functions.rst:47 c37180301960473ba34f6e7663b61b99\nmsgid \"create the page's display list\"\nmsgstr \"ページの表示リストを作成します。\"\n\n#: ../../functions.rst:48 5b0003105f4240f88525d89fa0c0908d\nmsgid \":meth:`Page.get_text_blocks`\"\nmsgstr \"\"\n\n#: ../../functions.rst:48 dd0afb0850654e8695ffc98210144dc8\nmsgid \"extract text blocks as a Python list\"\nmsgstr \"テキスト ブロックを Python リストとして抽出します。\"\n\n#: ../../functions.rst:49 76e04262af69408e9a63c3184fb7bad0\nmsgid \":meth:`Page.get_text_words`\"\nmsgstr \"\"\n\n#: ../../functions.rst:49 9f393e28ef804590afa7ec5de0048155\nmsgid \"extract text words as a Python list\"\nmsgstr \"テキストワードを Python リストとして抽出します。\"\n\n#: ../../functions.rst:50 1c8ae2f8f1f84b618bf7807fb1a10cc4\nmsgid \":meth:`Page.get_texttrace`\"\nmsgstr \"\"\n\n#: ../../functions.rst:50 e214fbbc63ae4d19a39fbd35f361f107\nmsgid \"low-level text information\"\nmsgstr \"低レベルのテキスト情報です。\"\n\n#: ../../functions.rst:51 c12d9e81a4f14a1ead2ead8d7f981a7c\nmsgid \":meth:`Page.read_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:51 4ea4aa95a0e74da39d80427e97d0c2f4\nmsgid \"PDF only: get complete, concatenated /Contents source\"\nmsgstr \"PDF のみ：完全な連結 /Contents ソースを取得します。\"\n\n#: ../../functions.rst:52 0a7b92c5ce184b8696922871f9786f30\nmsgid \":meth:`Page.run`\"\nmsgstr \"\"\n\n#: ../../functions.rst:52 e20ec70bf4894a6aa07e7a11aaf63d9e\nmsgid \"run a page through a device\"\nmsgstr \"ページをデバイスを介して実行します。\"\n\n#: ../../functions.rst:53 f318ac76d76d4865bd43843061a922e7\nmsgid \":meth:`Page.set_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:53 efe0c81605704542bfd7c295f5f6ccce\nmsgid \"PDF only: set page's :data:`contents` to some :data:`xref`\"\nmsgstr \"PDF のみ：ページの :data:`contents` を特定の :data:`xref` に設定します。\"\n\n#: ../../functions.rst:54 4eb1f3fa01d74d89bd9e13660d80aace\nmsgid \":meth:`Page.wrap_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:54 1e1087f91ea540e786db6751528af559\nmsgid \"wrap contents with stacking commands\"\nmsgstr \"スタッキング コマンドでコンテンツをラップします。\"\n\n#: ../../functions.rst:55 09fa362cbcc546d5bf5d8ff7ab48a08e\nmsgid \":meth:`css_for_pymupdf_font`\"\nmsgstr \"\"\n\n#: ../../functions.rst:55 e8300bd4f1b44f5db6278ec60b77cd26\nmsgid \"create CSS source for a font in package pymupdf_fonts\"\nmsgstr \"パッケージ pymupdf_fonts のフォント用の CSS ソースを作成します。\"\n\n#: ../../functions.rst:56 f03759eda97c48b2a48fa4f9b0fedb9a\nmsgid \":meth:`paper_rect`\"\nmsgstr \"\"\n\n#: ../../functions.rst:56 b1fb4ea8173343e4b372c4196e07d4ea\nmsgid \"return rectangle for a known paper format\"\nmsgstr \"既知の用紙形式の矩形を返します。\"\n\n#: ../../functions.rst:57 18bd1781e96740a0bd73013a3d7b664c\nmsgid \":meth:`paper_size`\"\nmsgstr \"\"\n\n#: ../../functions.rst:57 4c71d20789bf4aafba9b403c91023308\nmsgid \"return width, height for a known paper format\"\nmsgstr \"既知の用紙形式の幅と高さを返します。\"\n\n#: ../../functions.rst:58 448bae55c0144a77bf34e084c2087748\nmsgid \":meth:`paper_sizes`\"\nmsgstr \"\"\n\n#: ../../functions.rst:58 a4b88a6f83704283b1d067b9b422950b\nmsgid \"dictionary of pre-defined paper formats\"\nmsgstr \"事前定義の用紙形式の辞書です。\"\n\n#: ../../functions.rst:59 b534913dfb3a46caa10a1f68b16f99f5\nmsgid \":meth:`planish_line`\"\nmsgstr \"\"\n\n#: ../../functions.rst:59 dfa9809478844cd3a030cab4d9dfd1c2\nmsgid \"matrix to map a line to the x-axis\"\nmsgstr \"直線を x 軸にマップする行列です。\"\n\n#: ../../functions.rst:60 73b07e7023524c939f290cfec3c5147d\nmsgid \":meth:`recover_char_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:60 5d790e90a6db4ee39f6b9c7eaeaabaee\nmsgid \"compute the quad of a char (\\\"rawdict\\\")\"\nmsgstr \"文字のクワッドを計算します（\\\"rawdict\\\"）。\"\n\n#: ../../functions.rst:61 c7b763ff7e8242908671eb76801b55c5\nmsgid \":meth:`recover_line_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:61 907e455060ee4289a865a3187bb4704e\nmsgid \"compute the quad of a subset of line spans\"\nmsgstr \"ラインスパンのサブセットのクワッドを計算します\"\n\n#: ../../functions.rst:62 7f4adbdf1e7345cd91ccb084d979616b\nmsgid \":meth:`recover_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:62 0077aa420f404be69c0b00c321022093\nmsgid \"compute the quad of a span (\\\"dict\\\", \\\"rawdict\\\")\"\nmsgstr \"スパンのクワッドを計算する (\\\"dict\\\", \\\"rawdict\\\")\"\n\n#: ../../functions.rst:63 02efaa1a3ddc4f1c8aa20484a700e7e4\nmsgid \":meth:`recover_span_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:63 8ce412850eb445b78abe6ca665a2a77f\nmsgid \"compute the quad of a subset of span characters\"\nmsgstr \"行スパンのサブセットのクワッドを計算します。\"\n\n#: ../../functions.rst:64 c8a3bffef95e412ca257c252d6bff657\nmsgid \":meth:`set_messages`\"\nmsgstr \"\"\n\n#: ../../functions.rst:64 ae0c40a4b5ed4b718dfb8abc492ca10e\nmsgid \"set destination of |PyMuPDF| messages.\"\nmsgstr \"\"\n\n#: ../../functions.rst:65 0d4e3f46893442b5b8eba64b982bf3f2\nmsgid \":meth:`sRGB_to_pdf`\"\nmsgstr \"\"\n\n#: ../../functions.rst:65 d696f1caa15445b6bb8d91e71984f0a4\nmsgid \"return PDF RGB color tuple from an sRGB integer\"\nmsgstr \"sRGB 整数から PDF RGB カラー タプルを返します。\"\n\n#: ../../functions.rst:66 65f3ad24442c445fb34dae8002131da9\nmsgid \":meth:`sRGB_to_rgb`\"\nmsgstr \"\"\n\n#: ../../functions.rst:66 3d999340cd904162a8038d1a4126b947\nmsgid \"return (R, G, B) color tuple from an sRGB integer\"\nmsgstr \"sRGB 整数から (R、G、B) カラー タプルを返します。\"\n\n#: ../../functions.rst:67 766d7f863ca4428e842619c0ebca36ef\nmsgid \":meth:`unicode_to_glyph_name`\"\nmsgstr \"\"\n\n#: ../../functions.rst:67 6d5f5fe4327b4bf9b8aae045c9bf2b99\nmsgid \"return glyph name from a unicode\"\nmsgstr \"Unicode からグリフ名を返します。\"\n\n#: ../../functions.rst:68 b9b504a041b94a4f8519153749eb4825\nmsgid \":meth:`get_tessdata`\"\nmsgstr \"\"\n\n#: ../../functions.rst:68 a2891d94940c4cf8a54ab447f7b15370\nmsgid \"locates the language support of the Tesseract-OCR installation\"\nmsgstr \"Tesseract-OCR インストールの言語サポートを特定します。\"\n\n#: ../../functions.rst:69 f1824ee678fd459f92586806ad603df7\nmsgid \":meth:`colors_pdf_dict`\"\nmsgstr \"\"\n\n#: ../../functions.rst:69 0d099e9629fb4b689e08965adfc300e0\nmsgid \"return dict of color names.\"\nmsgstr \"\"\n\n#: ../../functions.rst:70 8dffcc2057e74973bf33f55a5145efa7\nmsgid \":meth:`colors_wx_list`\"\nmsgstr \"\"\n\n#: ../../functions.rst:70 df83f96c7f9049f9a2135f8c7c3e1f45\nmsgid \"return list of color names.\"\nmsgstr \"\"\n\n#: ../../functions.rst:71 a7d1b2ff6e7b499991be2827f2ce182f\nmsgid \":attr:`fitz_fontdescriptors`\"\nmsgstr \"\"\n\n#: ../../functions.rst:71 2bd5030a1ab34dfea799a7bac792e409\nmsgid \"dictionary of available supplement fonts\"\nmsgstr \"利用可能な補足フォントの辞書です。\"\n\n#: ../../functions.rst:72 213d79bfa9874a63ac1a4cfeb7032132\nmsgid \":attr:`PYMUPDF_MESSAGE`\"\nmsgstr \"\"\n\n#: ../../functions.rst:72 01828b10e24e4ca7a6ec84f910c2955e\nmsgid \"destination of |PyMuPDF| messages.\"\nmsgstr \"\"\n\n#: ../../functions.rst:73 fe68fe9641d94830aac3959ef70a3a46\nmsgid \":attr:`pdfcolor`\"\nmsgstr \"\"\n\n#: ../../functions.rst:73 19755c9b06fb412fac21ab46d85760d4\nmsgid \"dictionary of almost 500 RGB colors in PDF format.\"\nmsgstr \"PDF 形式のほぼ 500 以上の RGB カラーの辞書です。\"\n\n#: ../../functions.rst:78 688881b3cb454361936fad432734136c\nmsgid \"\"\n\"Convenience function to return width and height of a known paper format \"\n\"code. These values are given in pixels for the standard resolution 72 \"\n\"pixels = 1 inch.\"\nmsgstr \"既知の用紙フォーマットの幅と高さを返す便利な関数です。これらの値は、標準解像度 72 ピクセル = 1 インチのピクセル単位で指定されます。\"\n\n#: ../../functions.rst:80 df6f7db7c5e64bb99187e217a5e55d94\nmsgid \"\"\n\"Currently defined formats include **'A0'** through **'A10'**, **'B0'** \"\n\"through **'B10'**, **'C0'** through **'C10'**, **'Card-4x6'**, **'Card-\"\n\"5x7'**, **'Commercial'**, **'Executive'**, **'Invoice'**, **'Ledger'**, \"\n\"**'Legal'**, **'Legal-13'**, **'Letter'**, **'Monarch'** and **'Tabloid-\"\n\"Extra'**, each in either portrait or landscape format.\"\nmsgstr \"\"\n\"現在の定義されたフォーマットには、**‘A0’** から **‘A10’**、**‘B0’** から **‘B10’**、**‘C0’** から \"\n\"**‘C10’**、**‘Card-4x6’**、**‘Card-\"\n\"5x7’**、**‘Commercial’**、**‘Executive’**、**‘Invoice’**、**‘Ledger’**、**‘Legal’**、**‘Legal-13’**、**‘Letter’**、**‘Monarch\"\n\"’**、**‘Tabloid-Extra’** が含まれており、各フォーマットは縦向きまたは横向きで提供されています。\"\n\n#: ../../functions.rst:82 1227353c5f80413d8e4366aaa7e00301\nmsgid \"\"\n\"A format name must be supplied as a string (case **in** \\\\sensitive), \"\n\"optionally suffixed with \\\"-L\\\" (landscape) or \\\"-P\\\" (portrait). No \"\n\"suffix defaults to portrait.\"\nmsgstr \"\"\n\"フォーマット名は、文字列として指定する必要があります（大文字小文字を区別しない）。オプションで \\\" -L\\\"（横向き）または \\\" \"\n\"-P\\\"（縦向き）でサフィックスを付けることができます。サフィックスが指定されていない場合、デフォルトは縦向きです。\"\n\n#: ../../functions.rst 0859ddc790de48e98a47485cde669401\n#: 09aae792d39a4719b5feaf0ab83fff20 19bfd0356987458d83477865a5d1a227\n#: 49070de6bbd648339c39152b16917361 5abb2b0067e04d25a6a480258935ec7b\n#: 64942c1bcabb4af8b61d6c1763fa9ec1 7e3314757aad4fc1a94940b29ca6827c\n#: 813511b4bfb04affbe03c50f1c74e9c8 82b50464d79647069ebf77eb5eaa2f72\n#: 89cb96a7503f42ea8e5af77eae2653a1 92ffa13c8ae94cb2b2fa323e85adf355\n#: 99b800f8ef394726a8cf31b1e64c2e16 9d31e1e684094f7b843f37fca583e403\n#: 9fd573cd7d544e0aa4901376821e273b a1c3d38ad8b348718a4c58ba8de0d1f6\n#: a36d22d544834da3858edb86ef6f1644 ac8c99d18c2b4b9bb781c6f88660d86b\n#: b6d2ba4ce7ea4aeda4dcafbeb54f8f0d b770518ae6a749dbb83e9e8e640a10ee\n#: cd5810abe8154ef1bb614e2940eece1a f11cee020a504c72a63ce27fbbd09651\n#: fa237829f2624242ba676a501a682730 fe1aebb4ec3b40bd940fea19abc2ba9f\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../functions.rst:84 58f6fc5980274479b8466f9943b239a0\nmsgid \"\"\n\"any format name from above in upper or lower case, like *\\\"A4\\\"* or \"\n\"*\\\"letter-l\\\"*.\"\nmsgstr \"\"\n\"上記のいずれかのフォーマット名を大文字または小文字で指定します。たとえば、*\\\"A4\\\"* または *\\\"letter-l\\\"* \"\n\"のように指定します。\"\n\n#: ../../functions.rst 03f1fe2e5c3943e183598885bc51d1dc\n#: 1857900ce17a4569876c842ed42c6268 20b469d28e6e4ef18b3176a5e74627d3\n#: 20f0ad032864401e8e11b10c90f9c24b 27537b59f5694129a544cd09ee1e4957\n#: 2e112e3af1b74659bdb9c43d7db12a74 3062eec0ad0247d28f2f532f9cd5cce4\n#: 51bd37f77a214f6a8d3c6918723b9eea 5a94a14aae9b4984be7e3591cb6101df\n#: 6b1952aa0aa84cbe8c865623124268ab 6cf6024e798045079d4c6551e3a7b175\n#: 8bbd1c084844464088dab98f7d9f4965 9caea92222fe4cdc8432df38e26f83c6\n#: acae4a31653a4d72b4a2e701c6c059b0 ad60dbf189334ee5a807f1faec163c26\n#: b13938ce54e342d49bb6ee61f3927459 bd9c2eff50e34f239e7589f9e6ad949c\n#: d3cd059ede494646bac809314f2a7aa3 dedeff11b7fe409fa341704aee20d714\n#: f446e807ba984edf862a261ccd18ee92 f661f3aea2174106b4f7c07557d2937d\n#: fcea4521481d45bb8138e2bc86f57dd6 fd35d8681ef34d8882c8131bfbb9325f\n#: ffae2284aadc4ea5b7ce903b300110e5\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../functions.rst 241f189d177b4abe8781c1323a0ec686\n#: 269469e84adb406bba0203eeb27db4ea 3002f251a3b34a938e7f3b2d8ff54f55\n#: 393bd2c99abb435c9096087b1340609a 4c3f97315cf04d0891ea76a1bc4cdec7\n#: 4ce3f7bf85464affb653fdc3cde40999 4d87d3c54e3f482fbeae0695ccae2f3d\n#: 54eed5b94cd8484089e327a49e09c976 6b22f8b9a6ca4d4cbc8cc4d236263067\n#: 7c586b43f1e2413b82c7aec73497ad09 7d42f6afd5844f1caca525f80b3c1328\n#: 8bc58d3f2fc9447e98d7349da31213de a168611b4d644084a80c9ebf51127c66\n#: a636bdbee8ca4bb993b51dab8564eb04 afce09bb4d3e4e5dad5ccfaa3e62395a\n#: b4b81ec6ce2548c6a66b0675d31bd1d6 b7e7fb7a4c2747b1adf7a8583f8654c4\n#: b8cab8292e6e4f3ea1b79e200dca449d be0506cde75249c5b7cf35d1ae34c87d\n#: c02e22251e0c496c99819e2bbfd566f2 e1d0fe254797467e8a7b7fe3ea0ae483\n#: e1de8b977cf8465eb45cad2ef5f5e0dd eb4281b814a647efb2ad231baf1ca7ae\n#: f468fa01ceb94ad8ac3451a68a33ae39 fda237d8691b4a959eeca8fe09b6bbae\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../functions.rst:87 b4296412402b46a4965f9ad12430f3a5\nmsgid \"\"\n\"*(width, height)* of the paper format. For an unknown format *(-1, -1)* \"\n\"is returned. Examples: *pymupdf.paper_size(\\\"A4\\\")* returns *(595, 842)* \"\n\"and *pymupdf.paper_size(\\\"letter-l\\\")* delivers *(792, 612)*.\"\nmsgstr \"\"\n\"用紙フォーマットの *(幅、高さ)*。不明なフォーマットの場合、(-1、-1) \"\n\"が返されます。例：*pymupdf.paper_size(\\\"A4\\\")* は (595、842) \"\n\"を返し、*pymupdf.paper_size(\\\"letter-l\\\")* は *(792、612)* を返します。\"\n\n#: ../../functions.rst:93 5b13894197174f5b9b605cf39be91764\nmsgid \"Convenience function to return a :ref:`Rect` for a known paper format.\"\nmsgstr \"既知の紙のフォーマットに対応する :ref:`Rect` を返す便益関数です。\"\n\n#: ../../functions.rst:95 2b01808a6f984885ad72685e42b6ba34\nmsgid \"any format name supported by :meth:`paper_size`.\"\nmsgstr \":meth:`paper_size` でサポートされている任意のフォーマット名。\"\n\n#: ../../functions.rst:97 398230d02c1a4139a2c25e15afd00441\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../functions.rst:98 3bcbeafd12094f66b7da10fbb6e44d13\nmsgid \"\"\n\"*pymupdf.Rect(0, 0, width, height)* with *width, \"\n\"height=pymupdf.paper_size(s)*.\"\nmsgstr \"\"\n\n#: ../../functions.rst:109 dfd4fa5a7ed645d687e1add0d26f8fd9\nmsgid \"\"\n\"Sets destination of |PyMuPDF| messages to a file descriptor, a file, an \"\n\"existing stream or `Python's logging system \"\n\"<https://docs.python.org/3/library/logging.html>`_.\"\nmsgstr \"\"\n\n#: ../../functions.rst:113 7ca7d103b38f48e6807607f1b5fb4e04\nmsgid \"Usually one would only set one arg, or one or more `pylogging*` args.\"\nmsgstr \"\"\n\n#: ../../functions.rst:115 d3110ebcfa014f9a9e9dffbfb07b8429\nmsgid \"\"\n\"A text specification of destination; for details see description of \"\n\"environmental variable `PYMUPDF_MESSAGE`.\"\nmsgstr \"\"\n\n#: ../../functions.rst:118 f2568fbdee6a469e86d30e697b54e228\nmsgid \"Write to file descriptor.\"\nmsgstr \"\"\n\n#: ../../functions.rst:120 3005a922a0bd4a02926e0a5b40014183\nmsgid \"\"\n\"Write to existing stream, which must have methods `.write(text)` and \"\n\"`.flush()`.\"\nmsgstr \"\"\n\n#: ../../functions.rst:123 7bae0338bdf7484c9e843251d5c4268e\nmsgid \"Write to a file.\"\nmsgstr \"\"\n\n#: ../../functions.rst:125 629d6fa80e1140f48a18cd82a8d2631d\nmsgid \"Append to a file.\"\nmsgstr \"\"\n\n#: ../../functions.rst:127 af3dad1d6ce942b8bc8207879fb6e153\nmsgid \"Write to Python's `logging` system.\"\nmsgstr \"\"\n\n#: ../../functions.rst:129 edef27de299d43b580f0142468f71ade\nmsgid \"Write to Python's `logging` system using specified Logger.\"\nmsgstr \"\"\n\n#: ../../functions.rst:131 97f0f14a9c6543069de109bdaa320698\nmsgid \"Write to Python's `logging` system using specified level.\"\nmsgstr \"\"\n\n#: ../../functions.rst:133 54a6240e34794f1d8f029e59eef09948\nmsgid \"\"\n\"Write to Python's `logging` system using specified logger name. Only used\"\n\" if `pylogging_logger` is ``None``. Default is `pymupdf`.\"\nmsgstr \"\"\n\n#: ../../functions.rst:137 7fc3645c02074a4aa4ff724cf1ab0856\nmsgid \"\"\n\"If any `pylogging*` arg is not ``None``, we write to `Python's logging \"\n\"system <https://docs.python.org/3/library/logging.html>`_.\"\nmsgstr \"\"\n\n#: ../../functions.rst:144 ../../functions.rst:156 ../../functions.rst:270\n#: 70ea9f075bbc45bc9f22e2b8a925f0c2 d9fd6097dd8642d681771c59c34ec163\n#: e3bdeda869f54aae9ed48140bfa9aa51\nmsgid \"*New in v1.17.4*\"\nmsgstr \"*バージョン1.17.4で新たに追加*\"\n\n#: ../../functions.rst:146 0aa93594a530468e84df8471d05d150d\nmsgid \"\"\n\"Convenience function returning a PDF color triple (red, green, blue) for \"\n\"a given sRGB color integer as it occurs in :meth:`Page.get_text` \"\n\"dictionaries \\\"dict\\\" and \\\"rawdict\\\".\"\nmsgstr \"\"\n\":meth:`Page.get_text`  の辞書 \\\"dict\\\" および \\\"rawdict\\\" に存在する与えられた sRGB \"\n\"カラー整数に対して、PDF カラーのトリプル（赤、緑、青）を返す便益関数です。\"\n\n#: ../../functions.rst:148 ../../functions.rst:160\n#: 864b3d47658d4c118df2f33b9208300f 8b645478645441eebd77be6157685571\nmsgid \"\"\n\"an integer of format RRGGBB, where each color component is an integer in \"\n\"range(255).\"\nmsgstr \"各カラーコンポーネントが範囲[0, 255]の整数である RRGGBB 形式の整数。\"\n\n#: ../../functions.rst:150 87564fe0c411497099602ced50913c18\nmsgid \"\"\n\"a tuple (red, green, blue) with float items in interval *0 <= item <= 1* \"\n\"representing the same color. Example `sRGB_to_pdf(0xff0000) = (1, 0, 0)` \"\n\"(red).\"\nmsgstr \"\"\n\"*0 <= item <= 1* \"\n\"の間の浮動小数点数アイテムを持つタプル（赤、緑、青）で、同じカラーを表します。例：`sRGB_to_pdf(0xff0000) = (1, 0, \"\n\"0)` （赤）。\"\n\n#: ../../functions.rst:158 33afb580cfbe4b5fb5fed85569086eeb\nmsgid \"\"\n\"Convenience function returning a color (red, green, blue) for a given \"\n\"*sRGB* color integer.\"\nmsgstr \"与えられた *sRGB* カラー整数に対して、カラー（赤、緑、青）を返す便益関数です。\"\n\n#: ../../functions.rst:162 99b662fe46f9469682b0a7ec89eed460\nmsgid \"\"\n\"a tuple (red, green, blue) with integer items in `range(256)` \"\n\"representing the same color. Example `sRGB_to_pdf(0xff0000) = (255, 0, \"\n\"0)` (red).\"\nmsgstr \"\"\n\"整数アイテムが `range(256)` の範囲にある、同じ色を表すタプル（赤、緑、青）。例： `sRGB_to_pdf(0xff0000) = \"\n\"(255, 0, 0)` （赤）\"\n\n#: ../../functions.rst:168 ../../functions.rst:183 ../../functions.rst:198\n#: ../../functions.rst:211 79490e25884e4b379b80f56b00625d5c\n#: 8802b9dd8e1644918618883055d9afaf 8d692f79ec3d47b5a19c94c7e7f90981\n#: cc00fcf3f3834541862d9a786318f32f\nmsgid \"*New in v1.18.0*\"\nmsgstr \"*バージョン1.18.0で新たに追加*\"\n\n#: ../../functions.rst:170 5ba3d698e66646eeba96e992e95fc235\nmsgid \"\"\n\"Return the unicode number of a glyph name based on the **Adobe Glyph \"\n\"List**.\"\nmsgstr \"**Adobe Glyph List** に基づくグリフ名のUnicode番号を返す関数です。\"\n\n#: ../../functions.rst:172 bdb4dabbf07a42e1b2aaa60fafc3f6a5\nmsgid \"\"\n\"the name of some glyph. The function is based on the `Adobe Glyph List \"\n\"<https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_.\"\nmsgstr \"\"\n\"グリフの名前。この関数は `Adobe Glyph List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ に基づいています。\"\n\n#: ../../functions.rst:175 7f83c8a40f1f4f5182386d25b2900e70\n#, fuzzy\nmsgid \"the unicode. Invalid ``name`` entries return `0xfffd (65533)`.\"\nmsgstr \"Unicode番号。無効な *name* のエントリは `0xfffd (65533)` を返します。\"\n\n#: ../../functions.rst:177 ../../functions.rst:205 ../../functions.rst:218\n#: 06e18a271eb844ff8ee1fc0870be4fb8 d7d9853398734fcbb59570519db66ef3\n#: e5f542bf904c4baf92ddadf03e7802e6\nmsgid \"\"\n\"A similar functionality is provided by package `fontTools \"\n\"<https://pypi.org/project/fonttools/>`_ in its *agl* sub-package.\"\nmsgstr \"\"\n\"同様の機能は、`fontTools <https://pypi.org/project/fonttools/>`_ パッケージの *agl* \"\n\"サブパッケージで提供されています。\"\n\n#: ../../functions.rst:185 9c9f41d26b6f44d5a0675c56c191b7b5\nmsgid \"\"\n\"Return the glyph name of a unicode number, based on the **Adobe Glyph \"\n\"List**.\"\nmsgstr \"以下は、**Adobe Glyph List** に基づいた、Unicode番号に基づいたグリフ名を返す関数です。\"\n\n#: ../../functions.rst:187 3efb1935917c44828cdb74dd8e802d39\n#: a7cc8fab866e446fb5d9bd91531a6e33\nmsgid \"\"\n\"the unicode given by e.g. `ord(\\\"ß\\\")`. The function is based on the \"\n\"`Adobe Glyph List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_.\"\nmsgstr \"\"\n\"Unicode番号、例：`ord(\\\"ß\\\")` によって与えられます。この関数は `Adobe Glyph List \"\n\"<https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ に基づいています。\"\n\n#: ../../functions.rst:190 5176a1a461ef43a1bfbefacc552c8a8b\nmsgid \"\"\n\"the glyph name. E.g. `pymupdf.unicode_to_glyph_name(ord(\\\"Ä\\\"))` returns \"\n\"`'Adieresis'`.\"\nmsgstr \"グリフ名、例：`pymupdf.unicode_to_glyph_name(ord(\\\"Ä\\\"))` は `'Adieresis'` を返します。\"\n\n#: ../../functions.rst:192 2d968ce1f4004533b122972fdbbabdf7\nmsgid \"\"\n\"A similar functionality is provided by package `fontTools \"\n\"<https://pypi.org/project/fonttools/>`_: in its *agl* sub-package.\"\nmsgstr \"\"\n\"類似の機能は、`fontTools <https://pypi.org/project/fonttools/>`_ パッケージの *agl* \"\n\"サブパッケージで提供されています。\"\n\n#: ../../functions.rst:200 cdc27cc2524340f49b6cc45e587c802c\nmsgid \"Return a list of glyph names defined in the **Adobe Glyph List**.\"\nmsgstr \"**Adobe Glyph List** で定義されたグリフ名のリストを返します。\"\n\n#: ../../functions.rst:203 2fd087c0315e407ea96067edc1c4393c\nmsgid \"list of strings.\"\nmsgstr \"文字列のリスト。\"\n\n#: ../../functions.rst:213 a02dfb86773a455382f6a6c0268d3499\nmsgid \"\"\n\"Return a list of unicodes for there exists a glyph name in the **Adobe \"\n\"Glyph List**.\"\nmsgstr \"**Adobe Glyph List** にグリフ名が存在するUnicodeのリストを返します。\"\n\n#: ../../functions.rst:216 b7378500b7af448d86db01202a45986c\nmsgid \"list of integers.\"\nmsgstr \"整数のリスト。\"\n\n#: ../../functions.rst:224 44322f42c7554831ac045bccb97dbc3c\nmsgid \"*New in v1.21.0*\"\nmsgstr \"*新機能 v1.21.0*\"\n\n#: ../../functions.rst:226 24ae3761fb07422393846de0c9c3fa88\nmsgid \"**Utility function for use with \\\"Story\\\" applications.**\"\nmsgstr \"**\\\"Story\\\" アプリケーションで使用するためのユーティリティ関数。**\"\n\n#: ../../functions.rst:228 fd42be5d92474036bd944ca8660478de\nmsgid \"\"\n\"Create CSS `@font-face` items for the given fontcode in pymupdf-fonts. \"\n\"Creates a CSS font-family for all fonts starting with string \"\n\"\\\"fontcode\\\".\"\nmsgstr \"\"\n\"指定された \\\"fontcode\\\" に対して CSS `@font-face` アイテムを作成します。文字列 \\\"fontcode\\\" \"\n\"で始まるすべてのフォント用に CSS font-family を作成します。\"\n\n#: ../../functions.rst:230 a814b536199949e891f96f03e13d68a2\nmsgid \"\"\n\"The font naming convention in package pymupdf-fonts is \\\"fontcode<sf>\\\", \"\n\"where the suffix \\\"sf\\\" is one of \\\"\\\" (empty), \\\"it\\\"/\\\"i\\\", \"\n\"\\\"bo\\\"/\\\"b\\\" or \\\"bi\\\". These suffixes thus represent the regular, \"\n\"italic, bold or bold-italic variants of that font.\"\nmsgstr \"\"\n\"パッケージ pymupdf-fonts でのフォントの命名規則は \\\"fontcode<sf>\\\" で、サフィックス \\\"sf\\\" \"\n\"は（空白）、\\\"it\\\"、\\\"i\\\"、\\\"bo\\\"、\\\"b\\\"、\\\"bi\\\" \"\n\"のいずれかです。したがって、これらのサフィックスは、フォントの通常の、イタリックの、太字の、太字イタリックのバリアントを表します。\"\n\n#: ../../functions.rst:232 ee523a99cc234e859fb1a6cabd4448c4\nmsgid \"For example, font code \\\"notos\\\" refers to fonts\"\nmsgstr \"例えば、フォントコード \\\"notos\\\" は以下のフォントに対応します。\"\n\n#: ../../functions.rst:234 1624cd3ce5cb41d68b00cfbdefbab550\nmsgid \"\\\"notos\\\" - \\\"Noto Sans Regular\\\"\"\nmsgstr \"\"\n\n#: ../../functions.rst:235 b5bfb596ccb74dcf835b39d8f7d13881\nmsgid \"\\\"notosit\\\" - \\\"Noto Sans Italic\\\"\"\nmsgstr \"\"\n\n#: ../../functions.rst:236 f4b764ed2d584d8893bf0b2de910b9cf\nmsgid \"\\\"notosbo\\\" - \\\"Noto Sans Bold\\\"\"\nmsgstr \"\"\n\n#: ../../functions.rst:237 a8b2daa11b7845f3bed1ce18440ef016\nmsgid \"\\\"notosbi\\\" - \\\"Noto Sans Bold Italic\\\"\"\nmsgstr \"\"\n\n#: ../../functions.rst:239 cb8e8390629f4d188e7e1dbc5af60b03\nmsgid \"\"\n\"The function creates (up to) four CSS `@font-face` definitions and \"\n\"collectively assigns the `font-family` name \\\"notos\\\" to them (or the \"\n\"\\\"name\\\" value if provided). Associated font buffers are placed / added \"\n\"to the provided archive.\"\nmsgstr \"\"\n\"この関数は（最大で）4つの CSS `@font-face` 定義を作成し、それらに `font-family` 名 \"\n\"\\\"notos\\\"（または指定された \\\"name\\\" \"\n\"の値）を割り当てます。関連するフォントバッファは提供されたアーカイブに配置されます/追加されます。\"\n\n#: ../../functions.rst:241 b1578620590c4d49a662b6873f7c33e7\nmsgid \"\"\n\"To use the font in the Python API for :ref:`Story`, execute \"\n\"`.set_font(fontcode)` (or \\\"name\\\" if given). The correct font weight or \"\n\"style will automatically be selected as required.\"\nmsgstr \"\"\n\":ref:`Story` の Python API でフォントを使用するには、`.set_font(fontcode)`（または指定した場合は \"\n\"\\\"name\\\"）を実行します。必要に応じて正しいフォントウェイトまたはスタイルが自動的に選択されます。\"\n\n#: ../../functions.rst:243 5c4c7320f1f8400e924e56c72a17c2c3\nmsgid \"\"\n\"For example to replace the \\\"sans-serif\\\" HTML standard (i.e. Helvetica) \"\n\"with the above \\\"notos\\\", execute the following. Whenever \\\"sans-serif\\\" \"\n\"is used (whether explicitly or implicitly), the Noto Sans fonts will be \"\n\"selected.\"\nmsgstr \"\"\n\"たとえば、上記の \\\"notos\\\" で \\\"sans-serif\\\" HTML 標準（Helvetica）を置き換えるには、次のように実行します\"\n\"。\\\"sans-serif\\\" が使用される場合（明示的にまたは暗黙的に）、Noto Sans フォントが選択されます。\"\n\n#: ../../functions.rst:245 3ab4384a20d149669910ef03ad792c3a\nmsgid \"\"\n\"`CSS = pymupdf.css_for_pymupdf_font(\\\"notos\\\", name=\\\"sans-serif\\\", \"\n\"archive=...)`\"\nmsgstr \"\"\n\n#: ../../functions.rst:247 3206db2b9e4548d9873d135de0833c62\nmsgid \"Expects and returns the CSS source, with the new CSS definitions appended.\"\nmsgstr \"CSS ソースが期待されており、新しい CSS 定義が追加されています。\"\n\n#: ../../functions.rst:249 a2d622ad8ee347cdbf24cf65b46dd835\nmsgid \"\"\n\"one of the font codes present in package `pymupdf-fonts \"\n\"<https://pypi.org/project/pymupdf-fonts/>`_ (usually) representing the \"\n\"regular version of the font family.\"\nmsgstr \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ \"\n\"パッケージに存在するフォントファミリーの通常バージョンを表す、フォントコード。\"\n\n#: ../../functions.rst:250 3e43aa6f3cb7415c856593e0c2009f4d\nmsgid \"\"\n\"any already existing CSS source, or `None`. The function will append its \"\n\"new definitions to this. This is the string that **must be used** as \"\n\"`user_css` when creating the :ref:`Story`.\"\nmsgstr \"\"\n\"既存の CSS ソース、または `None`。新しい定義はこれに追加されます。これは :ref:`Story` を作成する際に \"\n\"`user_css` として **使用する必要がある** 文字列です。\"\n\n#: ../../functions.rst:251 96d99d7375ed4394a4e5ec1661857dde\nmsgid \"\"\n\":ref:`Archive`, **mandatory**. All font binaries (i.e. up to four) found \"\n\"for \\\"fontcode\\\" will be added to the archive. This is the archive that \"\n\"**must be used** as `archive` when creating the :ref:`Story`.\"\nmsgstr \"\"\n\":ref:`Archive`、**必須** です。\\\"fontcode\\\" \"\n\"に対して見つかるすべてのフォントバイナリ（最大で4つ）がアーカイブに追加されます。これは :ref:`Story` を作成する際に \"\n\":ref:`Archive` として**使用する必要があります** 。\"\n\n#: ../../functions.rst:252 efd7cc2ac7184a718e3bdc84648becc0\nmsgid \"\"\n\"the name under which the \\\"fontcode\\\" fonts should be found. If omitted, \"\n\"\\\"fontcode\\\" will be used.\"\nmsgstr \"\\\"fontcode\\\" フォントが見つかる名前。省略した場合、\\\"fontcode\\\" が使用されます。\"\n\n#: ../../functions.rst:255 d17bb0f3f24845159c50104934ef2fc9\nmsgid \"\"\n\"Modified CSS, with appended `@font-face` statements for each font variant\"\n\" of fontcode. Fontbuffers associated with \\\"fontcode\\\" will have been \"\n\"added to 'archive'. The function will automatically find up to 4 font \"\n\"variants. All pymupdf-fonts (that are no special purpose like math or \"\n\"music, etc.) have regular, bold, italic and bold-italic variants. To see \"\n\"currently available font codes check \"\n\"`pymupdf.fitz_fontdescriptors.keys()`. This will show something like \"\n\"`dict_keys(['cascadia', 'cascadiai', 'cascadiab', 'cascadiabi', 'figbo', \"\n\"'figo', 'figbi', 'figit', 'fimbo', 'fimo', 'spacembo', 'spacembi', \"\n\"'spacemit', 'spacemo', 'math', 'music', 'symbol1', 'symbol2', 'notosbo', \"\n\"'notosbi', 'notosit', 'notos', 'ubuntu', 'ubuntubo', 'ubuntubi', \"\n\"'ubuntuit', 'ubuntm', 'ubuntmbo', 'ubuntmbi', 'ubuntmit'])`.\"\nmsgstr \"\"\n\"変更された CSS。\\\"fontcode\\\" の各フォントバリアントに対して追加された `@font-face` \"\n\"ステートメントを含みます。関連する pymupdf-fonts のフォントバッファが 'archive' に追加されます。関数は最大で 4 \"\n\"つのフォントバリアントを自動的に見つけます。現在利用可能なフォントコードを確認するには、`pymupdf.fitz_fontdescriptors.keys()`\"\n\" を使用します。これにより、`dict_keys(['cascadia', 'cascadiai', 'cascadiab', \"\n\"'cascadiabi', 'figbo', 'figo', 'figbi', 'figit', 'fimbo', 'fimo', \"\n\"'spacembo', 'spacembi', 'spacemit', 'spacemo', 'math', 'music', \"\n\"'symbol1', 'symbol2', 'notosbo', 'notosbi', 'notosit', 'notos', 'ubuntu',\"\n\" 'ubuntubo', 'ubuntubi', 'ubuntuit', 'ubuntm', 'ubuntmbo', 'ubuntmbi', \"\n\"'ubuntmit'])` のようなものが表示されます。\"\n\n#: ../../functions.rst:257 9c918c7741a8450fadc38bb8e6d8248e\nmsgid \"\"\n\"Here is a complete snippet for using the \\\"Noto Sans\\\" font instead of \"\n\"\\\"Helvetica\\\"::\"\nmsgstr \"以下は \\\"Helvetica\\\" の代わりに \\\"Noto Sans\\\" フォントを使用する完全なスニペットです::\"\n\n#: ../../functions.rst:272 b6bf01dfadf043f89d73dc2362986d56\n#, fuzzy\nmsgid \"\"\n\"Convenience function to split a rectangle into sub-rectangles of equal \"\n\"size. Returns a list of `rows` lists, each containing `cols` :ref:`Rect` \"\n\"items. Each sub-rectangle can then be addressed by its row and column \"\n\"index.\"\nmsgstr \"\"\n\"矩形をサブ矩形に分割するための関数です。*行* のリストを含むリストを返し、各リストには指定された *列数* の :ref:`Rect` \"\n\"アイテムが含まれています。各サブ矩形はその行と列のインデックスでアクセスできます。\"\n\n#: ../../functions.rst:274 2379b768d70b429e80b9ee76ff6affc6\nmsgid \"the rectangle to split.\"\nmsgstr \"分割する矩形。\"\n\n#: ../../functions.rst:275 bc2cff2237ae4cc2b772925cc341db0f\nmsgid \"the desired number of columns.\"\nmsgstr \"列の数。\"\n\n#: ../../functions.rst:276 bb04dcac38e94e4ea02e6ce480164b8f\nmsgid \"the desired number of rows.\"\nmsgstr \"行の数。\"\n\n#: ../../functions.rst:277 afead5470e7e4b4ba96f6b47fa94c27f\nmsgid \"\"\n\"a list of :ref:`Rect` objects of equal size, whose union equals *rect*. \"\n\"Here is the layout of a 3x4 table created by `cell = \"\n\"pymupdf.make_table(rect, cols=4, rows=3)`:\"\nmsgstr \"\"\n\"等しいサイズの :ref:`Rect` オブジェクトのリストで、それらの合併は元の *rect* と同じです。たとえば、`cell = \"\n\"pymupdf.make_table(rect, cols=4, rows=3)` によって作成された 3x4 \"\n\"のテーブルのレイアウトは次のようになります：\"\n\n#: ../../functions.rst:287 3cf17d4592c24625a3c0f8b4ccf257b9\nmsgid \"New in version 1.16.2)*\"\nmsgstr \"*バージョン1.16.2で新たに導入されました。*\"\n\n#: ../../functions.rst:289 3de02919aba44c58882ea49db6a70ca4\nmsgid \"\"\n\"Return a matrix which maps the line from p1 to p2 to the x-axis such that\"\n\" p1 will become (0,0) and p2 a point with the same distance to (0,0).\"\nmsgstr \"p1からp2への直線をx軸にマッピングする行列を返します。その際、p1は(0,0)になり、p2は(0,0)から同じ距離に配置されるように変換されます。\"\n\n#: ../../functions.rst:291 d5051adab1c74eff8ca8bbcac46881e6\nmsgid \"starting point of the line.\"\nmsgstr \"直線の始点。\"\n\n#: ../../functions.rst:292 0739796326eb427b8251e930406ec398\nmsgid \"end point of the line.\"\nmsgstr \"直線の終点。\"\n\n#: ../../functions.rst:294 b3f32ee30e7e408ea53d346c946793b4\nmsgid \":ref:`Matrix`\"\nmsgstr \"\"\n\n#: ../../functions.rst:295 80f96c88c5c54adb87efd7e63247f4cf\nmsgid \"\"\n\"a matrix which combines a rotation and a translation::     >>> p1 = \"\n\"pymupdf.Point(1, 1)    >>> p2 = pymupdf.Point(4, 5)    >>> abs(p2 - p1)  \"\n\"# distance of points    5.0    >>> m = pymupdf.planish_line(p1, p2)    \"\n\">>> p1 * m    Point(0.0, 0.0)    >>> p2 * m    Point(5.0, \"\n\"-5.960464477539063e-08)    >>> # distance of the resulting points    >>> \"\n\"abs(p2 * m - p1 * m)    5.0   .. image:: images/img-planish.png    \"\n\":scale: 40\"\nmsgstr \"\"\n\n#: ../../functions.rst:295 85ea149f226e4e2ca4d42190a34693e5\nmsgid \"a matrix which combines a rotation and a translation::\"\nmsgstr \"回転と平行移動を組み合わせた行列::\"\n\n#: ../../functions.rst:319 d7085018534f47e2b428476e6d18257b\nmsgid \"\"\n\"A dictionary of pre-defines paper formats. Used as basis for \"\n\":meth:`paper_size`.\"\nmsgstr \"あらかじめ定義された用紙フォーマットの辞書。:meth:`paper_size` の基盤として使用されます。\"\n\n#: ../../functions.rst:325 1100f2cd223244e098a59cab294695cd\nmsgid \"New in v1.17.5\"\nmsgstr \"バージョン1.17.5で新たに導入されました\"\n\n#: ../../functions.rst:327 611b74fc7f2f49e7be426fe3db89be8f\nmsgid \"\"\n\"A dictionary of usable fonts from repository `pymupdf-fonts \"\n\"<https://pypi.org/project/pymupdf-fonts/>`_. Items are keyed by their \"\n\"reserved fontname and provide information like this::\"\nmsgstr \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ \"\n\"リポジトリから使用可能なフォントの辞書。アイテムは予約されたフォント名でキー付けされ、以下のような情報を提供します::\"\n\n#: ../../functions.rst:343 43582b0da1f84beba44a5e36e2cdd048\nmsgid \"If `pymupdf-fonts` is not installed, the dictionary is empty.\"\nmsgstr \"`pymupdf-fonts` がインストールされていない場合、この辞書は空です。\"\n\n#: ../../functions.rst:345 5c5c8927cd35468f8b40e91051754525\nmsgid \"\"\n\"The dictionary keys can be used to define a :ref:`Font` via e.g. `font = \"\n\"pymupdf.Font(\\\"fimo\\\")` -- just like you can do it with the builtin fonts\"\n\" \\\"Helvetica\\\" and friends.\"\nmsgstr \"\"\n\"辞書のキーは、例えば `font = pymupdf.Font(\\\"fimo\\\")` \"\n\"のように使用してフォントを定義できます。これは、組み込みのフォント \\\"Helvetica\\\" やその他のフォントと同様に行うことができます。\"\n\n#: ../../functions.rst:351 829280be90364ab59d34ab8bcb9ee3a5\nmsgid \"\"\n\"If in `os.environ` when |PyMuPDF| is imported, sets destination of \"\n\"|PyMuPDF| messages. Otherwise messages are sent to `sys.stdout`.\"\nmsgstr \"\"\n\n#: ../../functions.rst:355 2a7234b598ca4be78a6ed7fd2cd0e68b\nmsgid \"\"\n\"If the value starts with `fd:`, the remaining text should be an integer \"\n\"file descriptor to which messages are written.\"\nmsgstr \"\"\n\n#: ../../functions.rst:358 52dfedc05920490596eb9bb364ca70ad\nmsgid \"For example `PYMUPDF_MESSAGE=fd:2` will send messages to stderr.\"\nmsgstr \"\"\n\n#: ../../functions.rst:360 c2c608b9dd754c2095660836dded1873\nmsgid \"\"\n\"If the value starts with `path:`, the remaining text is the path of a \"\n\"file to which messages are written. If the file already exists, it is \"\n\"truncated.\"\nmsgstr \"\"\n\n#: ../../functions.rst:364 f8a67537ff5540058906057a31801f10\nmsgid \"\"\n\"If the value starts with `path+:`, the remaining text is the path of file\"\n\" to which messages are written. If the file already exists, we append \"\n\"output.\"\nmsgstr \"\"\n\n#: ../../functions.rst:369 a97a4cc6ac8941099d31bee564b661d6\nmsgid \"\"\n\"If the value starts with `logging:`, messages are written to `Python's \"\n\"logging system <https://docs.python.org/3/library/logging.html>`_. The \"\n\"remaining text can contain comma-separated name=value items:\"\nmsgstr \"\"\n\n#: ../../functions.rst:373 85f8ee63e7c242de87aa78d6da95ec89\nmsgid \"`level=<int>` sets the logging level.\"\nmsgstr \"\"\n\n#: ../../functions.rst:374 ced54a7765f14a2c90cc9b941ac3cdaf\nmsgid \"`name=<str>` sets the logger name (default is `pymupdf`).\"\nmsgstr \"\"\n\n#: ../../functions.rst:376 79d9e976d47c48d2b2f5d924b71d2bdd\nmsgid \"Other items are ignored.\"\nmsgstr \"\"\n\n#: ../../functions.rst:378 e6049a9e63db495e951e0a96d3dbe162\nmsgid \"Other prefixes will cause an error.\"\nmsgstr \"\"\n\n#: ../../functions.rst:380 cea43b4378c542439ade76acf38cef95\nmsgid \"Also see `set_messages()`.\"\nmsgstr \"\"\n\n#: ../../functions.rst:387 d33f434c014340318a8b4f2408cf37ee\nmsgid \"New in v1.19.6\"\nmsgstr \"バージョン1.19.6で新たに導入されました\"\n\n#: ../../functions.rst:389 2d49cc1b71804cc6add57d8ac8aeeb40\nmsgid \"\"\n\"Contains about 500 RGB colors in PDF format with the color name as key. \"\n\"To see what is there, you can obviously look at \"\n\"`pymupdf.pdfcolor.keys()`.\"\nmsgstr \"\"\n\"PDF形式の約500個のRGB色が、色の名前をキーとして含まれています。中身を確認するには、`pymupdf.pdfcolor.keys()` \"\n\"を見ることができます。\"\n\n#: ../../functions.rst:391 210b4f32e51c447c920aa1e17090177d\nmsgid \"Examples:\"\nmsgstr \"例：\"\n\n#: ../../functions.rst:393 78b6aa54c3d8499c933344b9d67aa935\nmsgid \"`pymupdf.pdfcolor[\\\"red\\\"] = (1.0, 0.0, 0.0)`\"\nmsgstr \"\"\n\n#: ../../functions.rst:394 25976b6b069c4a278c407ca0a6e0dd34\nmsgid \"\"\n\"`pymupdf.pdfcolor[\\\"skyblue\\\"] = (0.5294117647058824, 0.807843137254902, \"\n\"0.9215686274509803)`\"\nmsgstr \"\"\n\n#: ../../functions.rst:395 036d984bb9494bfb970022074689d37d\nmsgid \"\"\n\"`pymupdf.pdfcolor[\\\"wheat\\\"] = (0.9607843137254902, 0.8705882352941177, \"\n\"0.7019607843137254)`\"\nmsgstr \"\"\n\n#: ../../functions.rst:401 8e917a8067e94f15b90b52ee3016acc1\nmsgid \"\"\n\"Convenience function to return the current local timestamp in PDF \"\n\"compatible format, e.g. *D:20170501121525-04'00'* for local datetime May \"\n\"1, 2017, 12:15:25 in a timezone 4 hours westward of the UTC meridian.\"\nmsgstr \"\"\n\"PDF互換の形式で現在のローカルタイムスタンプを返す便利な関数です。例: \"\n\"ローカルの日付と時刻が2017年5月1日12時15分25秒で、UTC子午線の西4時間のタイムゾーンにある場合、*D:20170501121525-04’00’*\"\n\" となります。\"\n\n#: ../../functions.rst:404 f9d2422e60aa4b95b2387399f8819412\nmsgid \"current local PDF timestamp.\"\nmsgstr \"現在のローカルPDFタイムスタンプ。\"\n\n#: ../../functions.rst:410 7c48f1b5388547b9847fe88c7fbcd18a\nmsgid \"New in version 1.14.7\"\nmsgstr \"バージョン1.14.7で新規追加\"\n\n#: ../../functions.rst:412 64c91a6941404cf293748277c1e40776\nmsgid \"\"\n\"Calculate the length of text on output with a given **builtin** font, \"\n\":data:`fontsize` and encoding.\"\nmsgstr \"指定された *組み込み* フォント、:data:`fontsize` 、およびエンコーディングで出力されるテキストの長さを計算します。\"\n\n#: ../../functions.rst:414 1b351f62d3ce47ba820d95770c3b7ccf\nmsgid \"the text string.\"\nmsgstr \"テキスト文字列。\"\n\n#: ../../functions.rst:415 7a65fc2611854e61ae76f3d30079961a\n#, fuzzy\nmsgid \"\"\n\"the font name. Must be one of either the :ref:`Base-14-Fonts` or the CJK \"\n\"fonts, identified by their \\\"reserved\\\" fontnames (see table in \"\n\":meth:`Page.insert_font`).\"\nmsgstr \"\"\n\"フォント名。:ref:`Base-14-Fonts` \"\n\"またはCJKフォントのいずれかでなければなりません。これらは「予約済み」フォント名で識別されます（:meth:`Page.insert_font`\"\n\" のテーブルを参照）。\"\n\n#: ../../functions.rst:416 932954ed0adf44ef9900d8f882a388e7\nmsgid \"the :data:`fontsize`.\"\nmsgstr \":data:`fontsize`。\"\n\n#: ../../functions.rst:417 d499111356cf4e9081c8c3c2912a57bd\nmsgid \"\"\n\"the encoding to use. Besides 0 = Latin, 1 = Greek and 2 = Cyrillic \"\n\"(Russian) are available. Relevant for Base-14 fonts \\\"Helvetica\\\", \"\n\"\\\"Courier\\\" and \\\"Times\\\" and their variants only. Make sure to use the \"\n\"same value as in the corresponding text insertion.\"\nmsgstr \"\"\n\"使用するエンコーディング。0 = ラテン、1 = ギリシャ、2 = \"\n\"キリル文字（ロシア語）が利用可能です。ベース14フォント「Helvetica」、「Courier」、「Times」とそのバリアントにのみ関連します。対応するテキスト挿入で使用する値と同じ値を使用してください。\"\n\n#: ../../functions.rst:419 9120edd3ebae44b4acc13d6f9de3fc03\nmsgid \"\"\n\"the length in points the string will have (e.g. when used in \"\n\":meth:`Page.insert_text`).\"\nmsgstr \"文字列が持つポイント単位の長さ（たとえば、:meth:`Page.insert_text` で使用する場合）。\"\n\n#: ../../functions.rst:421 79cef2d8477740418dbe285f8a7e7d06\nmsgid \"\"\n\"This function will only do the calculation -- it won't insert font nor \"\n\"text.\"\nmsgstr \"この関数は計算のみを行います - フォントまたはテキストを挿入しません。\"\n\n#: ../../functions.rst:423 00b63292efa741d3a51b9a25802baf30\nmsgid \"\"\n\"The :ref:`Font` class offers a similar method, :meth:`Font.text_length`, \"\n\"which supports Base-14 fonts and any font with a character map (CMap, \"\n\"Type 0 fonts).\"\nmsgstr \"\"\n\":ref:`Font` クラスは、Base-14フォントおよび文字マップ（CMap、Type \"\n\"0フォントをサポートする任意のフォントに対応した似たようなメソッド :meth:`Font.text_length` を提供しています。\"\n\n#: ../../functions.rst:425 cfcfc76eb218486fa8b032c6c50ab81e\nmsgid \"\"\n\"If you use this function to determine the required rectangle width for \"\n\"the (:ref:`Page` or :ref:`Shape`) *insert_textbox* methods, be aware that\"\n\" they calculate on a **by-character level**. Because of rounding effects,\"\n\" this will mostly lead to a slightly larger number: \"\n\"*sum([pymupdf.get_text_length(c) for c in text]) > \"\n\"pymupdf.get_text_length(text)*. So either (1) do the same, or (2) use \"\n\"something like *pymupdf.get_text_length(text + \\\"'\\\")* for your \"\n\"calculation.\"\nmsgstr \"\"\n\"この関数を使用して（:ref:`Page` または :ref:`Shape`）*insert_textbox* \"\n\"メソッドの必要な矩形の幅を決定する場合、**文字単位で** \"\n\"計算されることに注意してください。丸め効果のため、これはほとんどの場合、やや大きな数になります：*sum([pymupdf.get_text_length(c)\"\n\" for c in text]) > \"\n\"pymupdf.get_text_length(text)*。したがって、（1）同じことを行うか、（2）計算に \"\n\"*pymupdf.get_text_length(text + \\\"’\\\")* のようなものを使用してください。\"\n\n#: ../../functions.rst:431 763b708ba6ae4ddab04cf7af4a0c1d41\nmsgid \"\"\n\"Make a PDF-compatible string: if the text contains code points *ord(c) > \"\n\"255*, then it will be converted to UTF-16BE with BOM as a hexadecimal \"\n\"character string enclosed in \\\"<>\\\" brackets like *<feff...>*. Otherwise,\"\n\" it will return the string enclosed in (round) brackets, replacing any \"\n\"characters outside the ASCII range with some special code. Also, every \"\n\"\\\"(\\\", \\\")\\\" or backslash is escaped with a backslash.\"\nmsgstr \"\"\n\"PDF互換の文字列を作成します。テキストに含まれる文字のコードポイントが *ord(c) > 255* の場合、それはUTF-\"\n\"16BEに変換され、BOMが含まれた16進数の文字列で \\\"<>\\\" \"\n\"ブラケットで囲まれます。それ以外の場合は、ASCII範囲外の文字を特別なコードで置き換えて、（丸い）カッコで囲まれた文字列が返されます。また、すべての\"\n\" \\\"(\\\", \\\")\\\", またはバックスラッシュはバックスラッシュでエスケープされます。\"\n\n#: ../../functions.rst:433 c2b249b32f5f45e889b055dec35c3b1c\nmsgid \"the object to convert\"\nmsgstr \"変換するオブジェクト\"\n\n#: ../../functions.rst:436 1acb62d7d240428ab032edcf601996ca\nmsgid \"PDF-compatible string enclosed in either *()* or *<>*.\"\nmsgstr \"*()* または *<>* で囲まれたPDF互換の文字列。\"\n\n#: ../../functions.rst:442 702d8585021a43eba297b69d4836db1d\nmsgid \"New in v1.16.7\"\nmsgstr \"バージョン1.16.7で新規追加\"\n\n#: ../../functions.rst:443 d731f027bad84dc4a0c0fa97dddbc2ba\nmsgid \"\"\n\"Changed in v1.19.5: also return natural image orientation extracted from \"\n\"EXIF data if present.\"\nmsgstr \"バージョン1.19.5で変更：EXIFデータから抽出した自然な画像の向きも返すように変更されました。\"\n\n#: ../../functions.rst:444 27b180112c374ac4a920954d1634ef4d\nmsgid \"\"\n\"Changed in v1.22.5: always return `None` in error cases instead of an \"\n\"empty dictionary.\"\nmsgstr \"バージョン1.22.5で変更：エラーケースで空の辞書ではなく、常に `None` を返すように変更されました。\"\n\n#: ../../functions.rst:446 9803cc75c9f044399d2dda1e316afe12\nmsgid \"\"\n\"Show important properties of an image provided as a memory area. Its main\"\n\" purpose is to avoid using other Python packages just to determine them.\"\nmsgstr \"メモリ領域として提供される画像の重要なプロパティを表示します。主な目的は、これらのプロパティを決定するために他のPythonパッケージを使用しないようにすることです。\"\n\n#: ../../functions.rst:448 fdf0ee2300ce40418b494c923b925202\nmsgid \"\"\n\"either an image in memory or an **opened** file. An image in memory may \"\n\"be any of the formats `bytes`, `bytearray` or `io.BytesIO`.\"\nmsgstr \"\"\n\"メモリ内の画像または **開いた** ファイル。メモリ内の画像は、`bytes`、`bytearray`、または `io.BytesIO` \"\n\"形式のいずれかです。\"\n\n#: ../../functions.rst:451 fe8ea596a2524046aa4127a94283a123\nmsgid \"\"\n\"No exception is ever raised. In case of an error, `None` is returned. \"\n\"Otherwise, there are the following items::     In [2]: \"\n\"pymupdf.image_profile(open(\\\"nur-ruhig.jpg\\\", \\\"rb\\\").read())    Out[2]:\"\n\"    {'width': 439,    'height': 501,    'orientation': 0,  # natural \"\n\"orientation (from EXIF)    'transform': (1.0, 0.0, 0.0, 1.0, 0.0, 0.0),  \"\n\"# orientation matrix    'xres': 96,    'yres': 96,    'colorspace': 3,\"\n\"    'bpc': 8,    'ext': 'jpeg',    'cs-name': 'DeviceRGB'}  There is the \"\n\"following relation to **Exif** information encoded in `orientation`, and \"\n\"correspondingly in the `transform` matrix-like (quoted from MuPDF \"\n\"documentation, *ccw* = counter-clockwise):     0. Undefined    1. 0 \"\n\"degree ccw rotation. (Exif = 1)    2. 90 degree ccw rotation. (Exif = 8)\"\n\"    3. 180 degree ccw rotation. (Exif = 3)    4. 270 degree ccw rotation.\"\n\" (Exif = 6)    5. flip on X. (Exif = 2)    6. flip on X, then rotate ccw \"\n\"by 90 degrees. (Exif = 5)    7. flip on X, then rotate ccw by 180 \"\n\"degrees. (Exif = 4)    8. flip on X, then rotate ccw by 270 degrees. \"\n\"(Exif = 7)   .. note::     * For some \\\"exotic\\\" images (FAX encodings, \"\n\"RAW formats and the like), this method will not work. You can however \"\n\"still work with such images in PyMuPDF, e.g. by using \"\n\":meth:`Document.extract_image` or create pixmaps via `Pixmap(doc, xref)`.\"\n\" These methods will automatically convert exotic images to the PNG format\"\n\" before returning results.    * You can also get the properties of images\"\n\" embedded in a PDF, via their :data:`xref`. In this case make sure to \"\n\"extract the raw stream: \"\n\"`pymupdf.image_profile(doc.xref_stream_raw(xref))`.    * Images as \"\n\"returned by the image blocks of :meth:`Page.get_text` using \\\"dict\\\" or \"\n\"\\\"rawdict\\\" options are also supported.\"\nmsgstr \"\"\n\n#: ../../functions.rst:452 6c919d4bab45428dbd8afb4362c1639b\nmsgid \"\"\n\"No exception is ever raised. In case of an error, `None` is returned. \"\n\"Otherwise, there are the following items::\"\nmsgstr \"例外は発生しません。エラーの場合、`None` が返されます。それ以外の場合、以下のアイテムがあります::\"\n\n#: ../../functions.rst:467 b9c14ed655074650822790e551f4ca7d\nmsgid \"\"\n\"There is the following relation to **Exif** information encoded in \"\n\"`orientation`, and correspondingly in the `transform` matrix-like (quoted\"\n\" from MuPDF documentation, *ccw* = counter-clockwise):\"\nmsgstr \"\"\n\"以下は、**Exif** 情報にエンコードされた`orientation` と、対応する `transform` \"\n\"マトリックスの関係です（MuPDFドキュメンテーションから引用、*ccw* = 反時計回り）：\"\n\n#: ../../functions.rst:469 19e611ede392404ba77fd6f75497a37d\nmsgid \"Undefined\"\nmsgstr \"未定義\"\n\n#: ../../functions.rst:470 32314d4117e54bddb20d74a136422abf\nmsgid \"0 degree ccw rotation. (Exif = 1)\"\nmsgstr \"0度の反時計回りの回転（Exif = 1）\"\n\n#: ../../functions.rst:471 781696a0f9f242fe89d413224e12432e\nmsgid \"90 degree ccw rotation. (Exif = 8)\"\nmsgstr \"90度の反時計回りの回転（Exif = 8）\"\n\n#: ../../functions.rst:472 589888419f494f768f3287b5f5fa3e86\nmsgid \"180 degree ccw rotation. (Exif = 3)\"\nmsgstr \"180度の反時計回りの回転（Exif = 3）\"\n\n#: ../../functions.rst:473 f01ff82a9eed4b9f844b157ad3881ef5\nmsgid \"270 degree ccw rotation. (Exif = 6)\"\nmsgstr \"270度の反時計回りの回転（Exif = 6）\"\n\n#: ../../functions.rst:474 0446ad252a924396aaeed11ed1109b46\nmsgid \"flip on X. (Exif = 2)\"\nmsgstr \"X軸で反転（Exif = 2）\"\n\n#: ../../functions.rst:475 26416c1428b9417cb36e3f04129eb26b\nmsgid \"flip on X, then rotate ccw by 90 degrees. (Exif = 5)\"\nmsgstr \"X軸で反転し、さらに90度反時計回りに回転（Exif = 5）\"\n\n#: ../../functions.rst:476 7bf8066761234bc9b89b24615ac9ff55\nmsgid \"flip on X, then rotate ccw by 180 degrees. (Exif = 4)\"\nmsgstr \"X軸で反転し、さらに180度反時計回りに回転（Exif = 4）\"\n\n#: ../../functions.rst:477 e588846b59874666b6702e6ff455f044\nmsgid \"flip on X, then rotate ccw by 270 degrees. (Exif = 7)\"\nmsgstr \"X軸で反転し、さらに270度反時計回りに回転（Exif = 7）\"\n\n#: ../../functions.rst:482 b2e5bec7f40640858d351ef7a4d13151\nmsgid \"\"\n\"For some \\\"exotic\\\" images (FAX encodings, RAW formats and the like), \"\n\"this method will not work. You can however still work with such images in\"\n\" PyMuPDF, e.g. by using :meth:`Document.extract_image` or create pixmaps \"\n\"via `Pixmap(doc, xref)`. These methods will automatically convert exotic \"\n\"images to the PNG format before returning results.\"\nmsgstr \"\"\n\"一部の「エキゾチック」な画像（FAXエンコーディング、RAWフォーマットなど）では、この方法は機能しない場合があります。ただし、PyMuPDFでは引き続きこのような画像を使用できます。たとえば、:meth:`Document.extract_image`\"\n\" を使用したり、`Pixmap(doc, xref)` \"\n\"を介してピクマップを作成したりできます。これらのメソッドは、結果を返す前にエキゾチックな画像を自動的にPNG形式に変換します。\"\n\n#: ../../functions.rst:483 60dfbff3781a411aa5ac084ed06bc481\nmsgid \"\"\n\"You can also get the properties of images embedded in a PDF, via their \"\n\":data:`xref`. In this case make sure to extract the raw stream: \"\n\"`pymupdf.image_profile(doc.xref_stream_raw(xref))`.\"\nmsgstr \"\"\n\"また、PDFに埋め込まれた画像のプロパティをxrefを介して取得することもできます。この場合は生のストリームを抽出してください： \"\n\"`pymupdf.image_profile(doc.xref_stream_raw(xref))`。\"\n\n#: ../../functions.rst:484 68c194bfed0d449c9f716b2f8c1e9a6d\nmsgid \"\"\n\"Images as returned by the image blocks of :meth:`Page.get_text` using \"\n\"\\\"dict\\\" or \\\"rawdict\\\" options are also supported.\"\nmsgstr \":meth:`Page.get_text` の画像ブロックが「dict」または「rawdict」オプションを使用して返す画像もサポートされています。\"\n\n#: ../../functions.rst:491 841e72c301064b7d8cd16a7659df3715\nmsgid \"\"\n\"Return the header string required to make a valid document out of page \"\n\"text outputs.\"\nmsgstr \"ページのテキスト出力を有効なドキュメントに変換するために必要なヘッダー文字列を返します。\"\n\n#: ../../functions.rst:493 ../../functions.rst:505\n#: 98ab75da842e44f0aba2173690b17420 be09e3df54dd47cc9a0f9dad37daf7ba\nmsgid \"type of document. Use the same as the output parameter of *get_text()*.\"\nmsgstr \"ドキュメントの種類。*get_text()* メソッドのoutputパラメータと同じものを使用します。\"\n\n#: ../../functions.rst:495 91d48bdf66814693aa7ac8c87d1d2704\nmsgid \"optional arbitrary name to use in output types \\\"json\\\" and \\\"xml\\\".\"\nmsgstr \"出力タイプ \\\"json\\\" および \\\"xml\\\" で使用するオプションの任意の名前。\"\n\n#: ../../functions.rst:503 8f75e703912b484cad9c58f9ef286a30\nmsgid \"\"\n\"Return the trailer string required to make a valid document out of page \"\n\"text outputs. See :meth:`Page.get_text` for an example.\"\nmsgstr \":meth:`Page.get_text` の例を参照して、ページテキストの出力から有効な文書を作成するために必要なトレーラー文字列を返します。\"\n\n#: ../../functions.rst:513 7bf3dbf728174900a685386f86d7b613\nmsgid \"\"\n\"Delete an object containing XML-based metadata from the PDF. (Py-) MuPDF \"\n\"does not support XML-based metadata. Use this if you want to make sure \"\n\"that the conventional metadata dictionary will be used exclusively. Many \"\n\"thirdparty PDF programs insert their own metadata in XML format and thus \"\n\"may override what you store in the conventional dictionary. This method \"\n\"deletes any such reference, and the corresponding PDF object will be \"\n\"deleted during next garbage collection of the file.\"\nmsgstr \"PDF内からXMLベースのメタデータを含むオブジェクトを削除します。PyMuPDFではXMLベースのメタデータはサポートされていません。従って、従来のメタデータ辞書が排他的に使用されることを確認したい場合に使用します。多くのサードパーティのPDFプログラムは、独自のXML形式でメタデータを挿入し、従来の辞書に保存されている内容を上書きする可能性があります。このメソッドはそのような参照を削除し、ファイルの次回のガベージコレクション時に対応するPDFオブジェクトが削除されます。\"\n\n#: ../../functions.rst:519 62c4ccaa8b8c436c990340d78e6341c0\nmsgid \"\"\n\"Return the XML-based metadata :data:`xref` of the PDF if present -- also \"\n\"refer to :meth:`Document.del_xml_metadata`. You can use it to retrieve \"\n\"the content via :meth:`Document.xref_stream` and then work with it using \"\n\"some XML software.\"\nmsgstr \"\"\n\"PDFのXMLベースのメタデータの :data:`xref` \"\n\"を返します。存在する場合は、:meth:`Document.del_xml_metadata` \"\n\"にも言及してください。これを使用して、:meth:`Document.xref_stream` \"\n\"を介してコンテンツを取得し、それをいくつかのXMLソフトウェアを使用して操作できます。\"\n\n#: ../../functions.rst:522 28fca2e874754c1b8e1f76de939f070b\nmsgid \":data:`xref` of PDF file level XML metadata -- or 0 if none exists.\"\nmsgstr \"PDFファイルレベルのXMLメタデータの :data:`xref`。存在しない場合は0。\"\n\n#: ../../functions.rst:528 bb22cba4009542cf9cbe10b1bdf7d0a0\nmsgid \"Run a page through a device.\"\nmsgstr \"ページをデバイスを通じて実行します。\"\n\n#: ../../functions.rst:530 b59467cb760a428cb9a1ad3ddc2372f5\nmsgid \"Device, obtained from one of the :ref:`Device` constructors.\"\nmsgstr \":ref:`Device`。デバイスのコンストラクタから取得します。\"\n\n#: ../../functions.rst:533 764e316039514bc2b1c84a2a3613584f\nmsgid \"\"\n\"Transformation to apply to the page. Set it to :ref:`Identity` if no \"\n\"transformation is desired.\"\nmsgstr \"ページに適用する変換。変換を行わない場合は :ref:`Identity` に設定します。\"\n\n#: ../../functions.rst:540 132d218ecda54d83a572eccb181b290d\nmsgid \"New in v1.19.0\"\nmsgstr \"新機能 v1.19.0\"\n\n#: ../../functions.rst:541 eb0d8183af6d46dcaa937647ed837885\nmsgid \"\"\n\"Changed in v1.22.0: optionally also return the OCG name applicable to the\"\n\" boundary box.\"\nmsgstr \"v1.22.0 で変更: 境界ボックスに適用される OCG 名もオプションで返すように変更されました。\"\n\n#: ../../functions.rst:543 2b307ac70a2c47239fe84735d4ea5dcc\nmsgid \"\"\n\"a list of rectangles that envelop text, image or drawing objects. Each \"\n\"item is a tuple `(type, (x0, y0, x1, y1))` where the second tuple \"\n\"consists of rectangle coordinates, and *type* is one of the following \"\n\"values. If `layers=True`, there is a third item containing the OCG name \"\n\"or `None`: `(type, (x0, y0, x1, y1), None)`.  * `\\\"fill-text\\\"` -- normal\"\n\" text (painted without character borders) * `\\\"stroke-text\\\"` -- text \"\n\"showing character borders only * `\\\"ignore-text\\\"` -- text that should \"\n\"not be displayed (e.g. as used by OCR text layers) * `\\\"fill-path\\\"` -- \"\n\"drawing with fill color (and no border) * `\\\"stroke-path\\\"` -- drawing \"\n\"with border (and no fill color) * `\\\"fill-image\\\"` -- displays an image *\"\n\" `\\\"fill-shade\\\"` -- display a shading  The item sequence represents the \"\n\"**sequence in which these commands are executed** to build the page's \"\n\"appearance. Therefore, if an item's bbox intersects or contains that of a\"\n\" previous item, then the previous item may be (partially) covered / \"\n\"hidden.   So this list can be used to detect such situations. An item's \"\n\"index in this list equals the value of a `\\\"seqno\\\"` in dictionaries as \"\n\"returned by :meth:`Page.get_drawings` and :meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\n#: ../../functions.rst:543 1b114fa4f3f64d72bd937199e3a3d2f7\nmsgid \"\"\n\"a list of rectangles that envelop text, image or drawing objects. Each \"\n\"item is a tuple `(type, (x0, y0, x1, y1))` where the second tuple \"\n\"consists of rectangle coordinates, and *type* is one of the following \"\n\"values. If `layers=True`, there is a third item containing the OCG name \"\n\"or `None`: `(type, (x0, y0, x1, y1), None)`.\"\nmsgstr \"\"\n\"テキスト、画像、または描画オブジェクトを囲む矩形のリスト。各アイテムはタプル `(type, (x0, y0, x1, y1))` \"\n\"で、第2のタプルは矩形の座標を表し、*type* は以下の値のいずれかです。`layers=True` の場合、OCG 名または `None` \"\n\"を含む第3のアイテムがあります: `(type, (x0, y0, x1, y1), None)`。\"\n\n#: ../../functions.rst:545 abf0c36f44e04ee8a5a2afa7b724f5a1\nmsgid \"`\\\"fill-text\\\"` -- normal text (painted without character borders)\"\nmsgstr \"`\\\"fill-text\\\"` – 通常のテキスト（文字の境界線なしで描画）\"\n\n#: ../../functions.rst:546 37dd54d3f17044c6b337bff4655966a0\nmsgid \"`\\\"stroke-text\\\"` -- text showing character borders only\"\nmsgstr \"`\\\"stroke-text\\\"` – 文字の境界線のみを表示するテキスト\"\n\n#: ../../functions.rst:547 849119a86cd44565a26d3541b70c0516\nmsgid \"\"\n\"`\\\"ignore-text\\\"` -- text that should not be displayed (e.g. as used by \"\n\"OCR text layers)\"\nmsgstr \"`\\\"ignore-text\\\"` – 表示されないべきテキスト（OCR テキストレイヤーなどで使用されます）\"\n\n#: ../../functions.rst:548 aec96117beef420c82608445b9e8819a\nmsgid \"`\\\"fill-path\\\"` -- drawing with fill color (and no border)\"\nmsgstr \"`\\\"fill-path\\\"` – 塗りつぶしカラーで描画（境界線なし）\"\n\n#: ../../functions.rst:549 b1d6ad4002a641048ce03e94bd21d5bb\nmsgid \"`\\\"stroke-path\\\"` -- drawing with border (and no fill color)\"\nmsgstr \"`\\\"stroke-path\\\"` – 境界線で描画（塗りつぶしカラーなし）\"\n\n#: ../../functions.rst:550 b0e26ed279dc4820a41a7f8a4e615183\nmsgid \"`\\\"fill-image\\\"` -- displays an image\"\nmsgstr \"`\\\"fill-image\\\"` – 画像を表示\"\n\n#: ../../functions.rst:551 7ad6ff9b7faf470cbe306351c31df8ec\nmsgid \"`\\\"fill-shade\\\"` -- display a shading\"\nmsgstr \"`\\\"fill-shade\\\"` – シェーディングを表示\"\n\n#: ../../functions.rst:553 218f82ee4e624649b8e8a57969e46706\nmsgid \"\"\n\"The item sequence represents the **sequence in which these commands are \"\n\"executed** to build the page's appearance. Therefore, if an item's bbox \"\n\"intersects or contains that of a previous item, then the previous item \"\n\"may be (partially) covered / hidden.\"\nmsgstr \"\"\n\"**アイテムのシーケンスは、ページの外観を構築するためにこれらのコマンドが実行される** 順序を表します。したがって、アイテムの bbox \"\n\"が前のアイテムの bbox と交差または包含されている場合、前のアイテムは（部分的に）カバー / 隠される可能性があります。\"\n\n#: ../../functions.rst:556 5593f221ed344831866cbd474df50bc3\nmsgid \"\"\n\"So this list can be used to detect such situations. An item's index in \"\n\"this list equals the value of a `\\\"seqno\\\"` in dictionaries as returned \"\n\"by :meth:`Page.get_drawings` and :meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\"したがって、このリストを使用してそのような状況を検出できます。このリスト内のアイテムのインデックスは、:meth:`Page.get_drawings`\"\n\"  および :meth:`Page.get_texttrace` によって返される辞書の `\\\"seqno\\\"` の値と等しいです。\"\n\n#: ../../functions.rst:563 1b4ab5c71554402a9c63ee38f27e71cb\nmsgid \"New in v1.18.16\"\nmsgstr \"v1.18.16 で新機能\"\n\n#: ../../functions.rst:564 83fdfa37d163451e9ff96def5e0de5c0\nmsgid \"Changed in v1.19.0: added key \\\"seqno\\\".\"\nmsgstr \"v1.19.0 で変更: キー \\\"seqno\\\" を追加。\"\n\n#: ../../functions.rst:565 916f4cdfdeda417abeea07844d42deca\nmsgid \"\"\n\"Changed in v1.19.1: stroke and fill colors now always are either RGB or \"\n\"GRAY\"\nmsgstr \"v1.19.1 で変更: ストロークと塗りつぶしのカラーは常に RGB または GRAY です\"\n\n#: ../../functions.rst:566 8c99ffdc891844ad872fd6def677e08b\nmsgid \"\"\n\"Changed in v1.19.3: span and character bboxes are now also correct if \"\n\"`dir != (1, 0)`.\"\nmsgstr \"v1.19.3 で変更: `dir != (1, 0)` の場合、スパンと文字の bbox も正確になりました。\"\n\n#: ../../functions.rst:567 03678344ac2e4f0ba4e15f06b3b558d0\nmsgid \"Changed in v1.22.0: add new dictionary key \\\"layer\\\".\"\nmsgstr \"v1.22.0 で変更: 新しい辞書キー \\\"layer\\\" を追加。\"\n\n#: ../../functions.rst:570 6d08591e52224bc08f77d6dcb26d9a04\nmsgid \"\"\n\"Return low-level text information of the page. The method is available \"\n\"for **all** document types. The result is a list of Python dictionaries \"\n\"with the following content::\"\nmsgstr \"\"\n\"ページの低レベルなテキスト情報を返します。このメソッドは **すべて** のドキュメントタイプで利用可能です。結果は、以下の内容を持つ \"\n\"Python 辞書のリストです。\"\n\n#: ../../functions.rst:606 cc0d6a11bdbc410cb9411001f8e05eee\nmsgid \"Details:\"\nmsgstr \"\"\n\n#: ../../functions.rst:608 11f8d880efa247139f7f83220839a83a\nmsgid \"\"\n\"Information above tagged with \\\"(1)\\\" has the same meaning and value as \"\n\"explained in :ref:`TextPage`.\"\nmsgstr \"「(1)」でタグ付けされた情報は、:ref:`TextPage` で説明された内容と同じ意味と値を持っています。\"\n\n#: ../../functions.rst:610 4d9d835859f449e0a40b7667d81451a8\n#, fuzzy\nmsgid \"\"\n\"Please note that the font ``flags`` value will never contain a \"\n\"*superscript* flag bit: the detection of superscripts is done within \"\n\"MuPDF :ref:`TextPage` code -- it is not a property of any font.\"\nmsgstr \"\"\n\"フォント `flags` の値には *superscript* フラグビットが含まれないことに注意してください。上付き文字の検出はMuPDF \"\n\":ref:`TextPage` 内で行われます。これは任意のフォントのプロパティではありません。\"\n\n#: ../../functions.rst:611 d9f311aa264940be9b1fd7dc476446f3\nmsgid \"\"\n\"Also note, that the text *color* is encoded as the usual tuple of floats \"\n\"0 <= f <= 1 -- not in sRGB format. Depending on `span[\\\"type\\\"]`, \"\n\"interpret this as fill color or stroke color.\"\nmsgstr \"\"\n\"また、テキストの *color* は通常の浮動小数点数のタプル（0 <= f <= \"\n\"1）でエンコードされており、sRGB形式ではありません。`span[\\\"type\\\"]` \"\n\"に応じて、これを塗りつぶし色またはストローク色として解釈してください。\"\n\n#: ../../functions.rst:613 c32efb528d114e888542af9a76a9477a\nmsgid \"There are 3 text span types:\"\nmsgstr \"テキストスパンには3つのタイプがあります：\"\n\n#: ../../functions.rst:615 ea8c6854860c4abc84f35271f246cf6f\nmsgid \"\"\n\"0: Filled text -- equivalent to PDF text rendering mode 0 (`0 Tr`, the \"\n\"default in PDF), only each character's \\\"inside\\\" is shown.\"\nmsgstr \"0：塗りつぶしテキスト - PDFテキストレンダリングモード0（`0 Tr`、PDFのデフォルト）と同等で、各文字の「内部」のみが表示されます。\"\n\n#: ../../functions.rst:616 8c5b60838d0043ad832b76f6964725ec\nmsgid \"\"\n\"1: Stroked text -- equivalent to `1 Tr`, only the character borders are \"\n\"shown.\"\nmsgstr \"1：ストロークテキスト - `1 Tr` に相当し、文字の境界のみが表示されます。\"\n\n#: ../../functions.rst:617 aad83dab705242819a32cf3d87f3fcd2\nmsgid \"3: Ignored text -- equivalent to `3 Tr` (hidden text).\"\nmsgstr \"3：無視されたテキスト - `3 Tr` に相当し（非表示テキスト）。\"\n\n#: ../../functions.rst:619 95d1e914c8254b37a6c64251be78ac76\n#, python-format\nmsgid \"\"\n\"Line width in this context is important only for processing \"\n\"`span[\\\"type\\\"] != 0`: it determines the thickness of the character's \"\n\"border line. This value may not be provided at all with the text data. In\"\n\" this case, a value of 5% of the :data:`fontsize` (`span[\\\"size\\\"] * \"\n\"0,05`) is generated. Often, an \\\"artificial\\\" bold text in PDF is created\"\n\" by `2 Tr`. There is no equivalent span type for this case. Instead, \"\n\"respective text is represented by two consecutive spans -- which are \"\n\"identical in every aspect, except for their types, which are 0, resp 1. \"\n\"It is your responsibility to handle this type of situation - in \"\n\":meth:`Page.get_text`, MuPDF is doing this for you.\"\nmsgstr \"\"\n\"この文脈では、線の幅は `span[\\\"type\\\"] != 0` \"\n\"を処理する際にのみ重要であり、文字の境界線の厚さを決定します。この値はテキストデータと一緒に提供されないこともあります。この場合、:data:`fontsize`\"\n\" の5％（`span[\\\"size\\\"] * 0.05`）の値が生成されます。PDF内の「人工」の太字テキストは、通常、`2 Tr` \"\n\"によって作成されます。この場合、このケースの等価なスパンタイプは存在しません。代わりに、対応するテキストは2つの連続したスパンによって表されます。これらのスパンはすべての側面が同一であり、タイプ以外は異なります（0、1）。このタイプの状況を処理する責任はあなたにあります。:meth:`Page.get_text`\"\n\" では、MuPDFがこれを代わりに行います。\"\n\n#: ../../functions.rst:620 606f56ad2fa34ddb82e2171ac68c7ae0\nmsgid \"\"\n\"For data compactness, the character's unicode is provided here. Use \"\n\"built-in function `chr()` for the character itself.\"\nmsgstr \"データのコンパクトさのために、文字のUnicodeがここで提供されます。文字自体には `chr()` という組み込み関数を使用します。\"\n\n#: ../../functions.rst:621 eafb5c8d2c0a47fe87b904f337b62657\nmsgid \"\"\n\"The alpha / opacity value of the span's text, `0 <= opacity <= 1`, 0 is \"\n\"invisible text, 1 (100%) is intransparent. Depending on `span[\\\"type\\\"]`,\"\n\" interpret this value as *fill* opacity or, resp. *stroke* opacity.\"\nmsgstr \"\"\n\"スパンのテキストのアルファ/不透明度値、`0 <= opacity <= \"\n\"1`、0は見えないテキスト、1（100％）は不透明です。`span[\\\"type\\\"]` に応じて、この値を *fill* の不透明度または \"\n\"*stroke* の不透明度として解釈してください。\"\n\n#: ../../functions.rst:622 eb23d9902fba49d087006466112feef8\nmsgid \"\"\n\"*(Changed in v1.19.0)* This value is equal or close to `char[\\\"bbox\\\"]` \"\n\"of \\\"rawdict\\\". In particular, the bbox **height** value is always \"\n\"computed as if **\\\"small glyph heights\\\"** had been requested.\"\nmsgstr \"\"\n\"*（v1.19.0で変更）* この値は「rawdict」の `char[\\\"bbox\\\"]` と等しいか、近い値です。特に、bboxの \"\n\"**高さ** の値は常に **「小さなグリフの高さ」** が要求されたかのように計算されます。\"\n\n#: ../../functions.rst:623 3ef916cf4c6d4625b153f657810bcaac\nmsgid \"*(New in v1.19.0)* This is the union of all character bboxes.\"\nmsgstr \"*（v1.19.0で新規）* これはすべての文字bboxの合併です。\"\n\n#: ../../functions.rst:624 b64b0fd0a2f8435aada9591350d3276e\nmsgid \"\"\n\"*(New in v1.19.0)* Enumerates the commands that build up the page's \"\n\"appearance. Can be used to find out whether text is effectively hidden by\"\n\" objects, which are painted \\\"later\\\", or *over* some object. So if there\"\n\" is a drawing or image with a higher sequence number, whose bbox overlaps\"\n\" (parts of) this text span, one may assume that such an object hides the \"\n\"resp. text. Different text spans have identical sequence numbers if they \"\n\"were created in one go.\"\nmsgstr \"\"\n\"*（v1.19.0で新規）* \"\n\"ページの外観を構築するコマンドを列挙します。テキストが実際には後で「描画」されるオブジェクトによって隠れるか、またはいくつかのオブジェクトの上にかかっているかを判断するのに使用できます。したがって、bboxがこのテキストスパンのbboxと交差または含まれている場合、以前のアイテムが（部分的に）カバー/非表示にされる可能性があります。\"\n\n#: ../../functions.rst:625 4e53fc30ab4b434a8dd462b37df55b15\nmsgid \"\"\n\"*(New in v1.22.0)* The name of the Optional Content Group (OCG) if \"\n\"applicable or `None`.\"\nmsgstr \"*（v1.22.0で新規）* 該当する場合、Optional Content Group（OCG）の名前、または `None`\"\n\n#: ../../functions.rst:627 18fcebc358184f629a5dac8dd24f561d\nmsgid \"\"\n\"Here is a list of similarities and differences of `page.get_texttrace()` \"\n\"compared to `page.get_text(\\\"rawdict\\\")`:\"\nmsgstr \"\"\n\"以下は、`page.get_texttrace()` と `page.get_text(\\\"rawdict\\\")` \"\n\"を比較した類似点と相違点のリストです：\"\n\n#: ../../functions.rst:629 10242bfca81e4c638b761ecd11ecc22b\nmsgid \"\"\n\"The method is up to **twice as fast,** compared to \\\"rawdict\\\" \"\n\"extraction. Depends on the amount of text.\"\nmsgstr \"メソッドは、テキストの量に依存しますが、\\\"rawdict\\\" の抽出と比較して最大 **2倍速い** です。\"\n\n#: ../../functions.rst:630 563d2bcc5e534c8aa65c037cb918a041\nmsgid \"\"\n\"The returned data is very **much smaller in size** -- although it \"\n\"provides more information.\"\nmsgstr \"返されるデータは **非常に小さく** 、より多くの情報を提供します。\"\n\n#: ../../functions.rst:631 22d9ce68958844f9b04f8ce7c51e84a7\nmsgid \"\"\n\"Additional types of text **invisibility can be detected**: opacity = 0 or\"\n\" type > 1 or overlapping bbox of an object with a higher sequence number.\"\nmsgstr \"\"\n\"追加のテキストの **不可視性のタイプを検出できます** ：不透明度 = 0またはタイプ > \"\n\"1またはシーケンス番号の高いオブジェクトとの境界ボックスが重なる。\"\n\n#: ../../functions.rst:632 b7e1c0e67b62467e9bdadba9d42d6c6b\nmsgid \"\"\n\"If MuPDF returns unicode 0xFFFD (65533) for unrecognized characters, you \"\n\"may still be able to deduct desired information from the glyph id.\"\nmsgstr \"\"\n\"MuPDFが認識できない文字に対してUnicode \"\n\"0xFFFD（65533）を返す場合、グリフIDから必要な情報を導き出すことができるかもしれません。\"\n\n#: ../../functions.rst:633 b1f31df6bda84153ace8673ae63e9996\nmsgid \"\"\n\"The `span[\\\"chars\\\"]` **contains no spaces**, **except** the document \"\n\"creator has explicitly coded them. They **will never be generated** like \"\n\"it happens in :meth:`Page.get_text` methods. To provide some help for \"\n\"doing your own computations here, the width of a space character is \"\n\"given. This value is derived from the font where possible. Otherwise the \"\n\"value of a fallback font is taken.\"\nmsgstr \"\"\n\"`span[\\\"chars\\\"]` には **スペースは含まれません** 。ただし、ドキュメントの作成者が明示的にコード化しない限り、それらは \"\n\":meth:`Page.get_text` メソッドで発生するように \"\n\"**生成されません**。自分自身の計算を行うのを助けるために、スペース文字の幅が提供されます。この値はフォントから派生しています。それ以外の場合はフォールバックフォントの値が取られます。\"\n\n#: ../../functions.rst:634 c94dc74956874bfa8ac4c59d48c0cc87\nmsgid \"\"\n\"There is no effort to organize text like it happens for a :ref:`TextPage`\"\n\" (the hierarchy of blocks, lines, spans, and characters). Characters are \"\n\"simply extracted in sequence, one by one, and put in a span. Whenever any\"\n\" of the span's characteristics changes, a new span is started. So you may\"\n\" find characters with different `origin.y` values in the same span (which\"\n\" means they would appear in different lines). You cannot assume, that \"\n\"span characters are sorted in any particular order -- you must make sense\"\n\" of the info yourself, taking `span[\\\"dir\\\"]`, `span[\\\"wmode\\\"]`, etc. \"\n\"into account.\"\nmsgstr \"\"\n\":ref:`TextPage` \"\n\"のようにテキストを整理する取り組みはありません（ブロック、行、スパン、および文字の階層構造）。文字は単純に順番に抽出され、スパンに配置されます。スパンの特性が変更されるたびに、新しいスパンが開始されます。したがって、同じスパン内で異なる\"\n\" `origin.y` \"\n\"値を持つ文字を見つけることができます（これは異なる行に表示されることを意味します）。スパンの文字が特定の順序でソートされているとは仮定できません。情報を理解し、`span[\\\"dir\\\"]`、`span[\\\"wmode\\\"]`\"\n\" などを考慮に入れる必要があります。\"\n\n#: ../../functions.rst:652 7acddc7741614360bf17d5596c8cc5ab\nmsgid \"Ligatures are represented like this:\"\nmsgstr \"リガチャは次のように表されます：\"\n\n#: ../../functions.rst:636 e72abf836baf467c93105d9dde8d8035\nmsgid \"\"\n\"MuPDF handles the following ligatures: \\\"fi\\\", \\\"ff\\\", \\\"fl\\\", \\\"ft\\\", \"\n\"\\\"st\\\", \\\"ffi\\\", and \\\"ffl\\\" (only the first 3 are mostly ever used). If \"\n\"the page contains e.g. ligature \\\"fi\\\", you will find the following two \"\n\"character items subsequent to each other::\"\nmsgstr \"\"\n\"MuPDFは次のリガチャを処理します。 \\\"fi\\\"、 \\\"ff\\\"、 \\\"fl\\\"、 \\\"ft\\\"、 \\\"st\\\"、 \\\"ffi\\\"、および \"\n\"\\\"ffl\\\"（ほとんどは最初の3つが使用されます）。したがって、ページに \\\"fi\\\" \"\n\"のようなリガチャが含まれている場合、次の2つの文字アイテムが連続して表示されます。\"\n\n#: ../../functions.rst:641 d46f58a609804bea982da0876d2ba90f\nmsgid \"\"\n\"This means that the bbox of the first ligature character is the area \"\n\"containing the complete, compound glyph. Subsequent ligature components \"\n\"are recognizable by their glyph value -1 and a bbox of width zero.\"\nmsgstr \"これにより、最初の合字文字のbboxは、完全な合成グリフを含む領域です。後続の合字コンポーネントは、そのグリフ値が-1で幅がゼロであることで識別できます。\"\n\n#: ../../functions.rst:642 5f6b5b48f4684036ad328bffca38325a\nmsgid \"\"\n\"You may want to replace those 2 or 3 char tuples by one, that represents \"\n\"the ligature itself. Use the following mapping of ligatures to unicodes:\"\nmsgstr \"これらの2つまたは3つの文字のタプルを、合字自体を表す1つに置き換えたい場合があるかもしれません。次のような合字をUnicodeにマッピングします。\"\n\n#: ../../functions.rst:644 889bc72258b64c39bbba09ab96188589\nmsgid \"`\\\"ff\\\" -> 0xFB00`\"\nmsgstr \"\"\n\n#: ../../functions.rst:645 950a98981e9b4f3cad52eca1073f9df2\nmsgid \"`\\\"fi\\\" -> 0xFB01`\"\nmsgstr \"\"\n\n#: ../../functions.rst:646 897debd680f84f00b2b72a621eb0ef78\nmsgid \"`\\\"fl\\\" -> 0xFB02`\"\nmsgstr \"\"\n\n#: ../../functions.rst:647 06805958e3a24f58ba7fe31f2c71b37c\nmsgid \"`\\\"ffi\\\" -> 0xFB03`\"\nmsgstr \"\"\n\n#: ../../functions.rst:648 108d095c0546443c9aed1a351b544e51\nmsgid \"`\\\"ffl\\\" -> 0xFB04`\"\nmsgstr \"\"\n\n#: ../../functions.rst:649 685cc70784514cb8b5c01b88bff6ab68\nmsgid \"`\\\"ft\\\" -> 0xFB05`\"\nmsgstr \"\"\n\n#: ../../functions.rst:650 0b2c082689e24ccca607cf35dac9ca2f\nmsgid \"`\\\"st\\\" -> 0xFB06`\"\nmsgstr \"\"\n\n#: ../../functions.rst:652 3916ffdd9f474f4a8021e3466c4251ec\nmsgid \"\"\n\"So you may want to replace the two example tuples above by the following \"\n\"single one: `(0xFB01, glyph, (x, y), (x0, y0, x1, y1))` (there is usually\"\n\" no need to lookup the correct glyph id for 0xFB01 in the resp. font, but\"\n\" you may execute `font.has_glyph(0xFB01)` and use its return value).\"\nmsgstr \"\"\n\"したがって、上記の2つの例のタプルを次の単一のタプルで置き換えたい場合があります：`(0xFB01, glyph, (x, y), (x0, \"\n\"y0, x1, \"\n\"y1))`（通常、0xFB01の正しいグリフIDをフォント内で調べる必要はありませんが、`font.has_glyph(0xFB01)` \"\n\"を実行し、その戻り値を使用することができます）。\"\n\n#: ../../functions.rst:654 57e26aabbddd4a9f9a02d4b02c1ef955\n#, fuzzy\nmsgid \"\"\n\"**Changed in v1.19.3:** Similar to other text extraction methods, the \"\n\"character and span bboxes envelop the character quads. To recover the \"\n\"quads, follow the same methods :meth:`recover_quad`, \"\n\":meth:`recover_char_quad` or :meth:`recover_span_quad` as explained in \"\n\":ref:`textpagedict`. Use either `None` or `span[\\\"dir\\\"]` for the writing\"\n\" direction.\"\nmsgstr \"\"\n\"**v1.19.3で変更：** \"\n\"他のテキスト抽出方法と同様に、文字とスパンのbboxは文字のクアッドを包含します。クアッドを回復するには、:ref:`textpagedict` \"\n\"で説明されている :meth:`recover_quad`、:meth:`recover_char_quad`、または \"\n\":meth:`recover_span_quad` の同じ方法を使用します。書き込み方向にはNoneまたはspan `span[\\\"dir\\\"]`\"\n\" を使用してください。\"\n\n#: ../../functions.rst:656 c735d25ff37c439293d1c84142159a58\nmsgid \"\"\n\"**Changed in v1.21.1:** If applicable, the name of the OCG is shown in \"\n\"`\\\"layer\\\"`.\"\nmsgstr \"**v1.21.1** で変更：該当する場合、OCGの名前が `\\\"layer\\\"` に表示されます。\"\n\n#: ../../functions.rst:662 73cb0ecbc9904cfd9eedd2cf201a34ac\nmsgid \"\"\n\"Ensures that the page's so-called graphics state is balanced and new \"\n\"content can be inserted correctly.\"\nmsgstr \"\"\n\n#: ../../functions.rst:664 2fce8c9f6cfc4f5580d8dbfbdac54581\nmsgid \"\"\n\"In versions 1.24.1+ of PyMuPDF the method was improved and is being \"\n\"executed automatically as required, so you should no longer need to \"\n\"concern yourself with it.\"\nmsgstr \"\"\n\n#: ../../functions.rst:666 6ca70959e73644b19510f3250902df9a\nmsgid \"We discourage using :meth:`Page.clean_contents` to achieve this.\"\nmsgstr \"\"\n\n#: ../../functions.rst:672 fbfdfc139dba4d859c7e23c259a08157\nmsgid \"\"\n\"Indicate whether the page's so-called graphic state is balanced. If \"\n\"`False`, :meth:`Page.wrap_contents` should be executed if new content is \"\n\"inserted (only relevant in `overlay=True` mode). In newer versions \"\n\"(1.24.1+), this check and corresponding adjustments are automatically \"\n\"executed -- you therefore should not be concerned about this anymore.\"\nmsgstr \"\"\n\n#: ../../functions.rst:680 de1474a27a3c4f17a4b06482b9593875\nmsgid \"\"\n\"Deprecated wrapper for :meth:`TextPage.extractBLOCKS`.  Use \"\n\":meth:`Page.get_text` with the \\\"blocks\\\" option instead.\"\nmsgstr \"\"\n\":meth:`TextPage.extractBLOCKS` の非推奨のラッパーです。代わりにオプション \\\"blocks\\\" を使用して \"\n\":meth:`Page.get_text` を使用してください。\"\n\n#: ../../functions.rst:688 88b9617fbc71462e867dbd12dd918d79\nmsgid \"\"\n\"Deprecated wrapper for :meth:`TextPage.extractWORDS`. Use \"\n\":meth:`Page.get_text` with the \\\"words\\\" option instead.\"\nmsgstr \"\"\n\n#: ../../functions.rst:696 e63d78e973014b5da39d398c04e37cd0\nmsgid \"Run a page through a list device and return its display list.\"\nmsgstr \"ページをリストデバイスを介して実行し、そのディスプレイリストを返します。\"\n\n#: ../../functions.rst:698 18c7a9bcd3614b61abe4ffa70c25080c\nmsgid \":ref:`DisplayList`\"\nmsgstr \"\"\n\n#: ../../functions.rst:699 95ce406969764ffea7a51bd7cb001954\nmsgid \"the display list of the page.\"\nmsgstr \"ページのディスプレイリスト。\"\n\n#: ../../functions.rst:705 2f7950caaff2497e85a41efaf8b7ab40\n#, fuzzy\nmsgid \"\"\n\"PDF only: Retrieve a list of :data:`xref` of :data:`contents` objects of \"\n\"a page. May be empty or contain multiple integers. If the page is cleaned\"\n\" (:meth:`Page.clean_contents`), it will be no more than one entry. The \"\n\"\\\"source\\\" of each `/Contents` object can be individually read by \"\n\":meth:`Document.xref_stream` using an item of this list. Method \"\n\":meth:`Page.read_contents` in contrast walks through this list and \"\n\"concatenates the corresponding sources into one `bytes` object.\"\nmsgstr \"\"\n\"PDFのみ：ページの :data:`contents` オブジェクトの :data:`xref` \"\n\"のリストを取得します。空であるか、複数の整数を含むことがあります。ページがクリーンアップされた場合（:meth:`Page.clean_contents`）、最大で1つのエントリになります。各/Contentsオブジェクトの\"\n\" \\\"source\\\" は、このリストのアイテムを使用して :meth:`Document.xref_stream` \"\n\"で個別に読み取ることができます。一方、:meth:`Page.read_contents` メソッドは、このリストを走査し、対応するソースを1つの\"\n\" `bytes` オブジェクトに連結します。\"\n\n#: ../../functions.rst:713 0e0e858c5fb34899bf5b31067d9f6cf0\nmsgid \"\"\n\"PDF only: Let the page's `/Contents` key point to this xref. Any \"\n\"previously used contents objects will be ignored and can be removed via \"\n\"garbage collection.\"\nmsgstr \"\"\n\"PDFのみ：ページの `/Contents` \"\n\"キーをこのxrefに設定します。以前に使用されていたコンテンツオブジェクトは無視され、ガベージコレクションを使用して削除できます。\"\n\n#: ../../functions.rst:719 5d1261cb25b84350a7512c2587a9a33e\nmsgid \"Changed in v1.17.6\"\nmsgstr \"v1.17.6で変更\"\n\n#: ../../functions.rst:721 246c4ca104b04817bab2b24be75d9bcb\nmsgid \"\"\n\"PDF only: Clean and concatenate all :data:`contents` objects associated \"\n\"with this page. \\\"Cleaning\\\" includes syntactical corrections, \"\n\"standardizations and \\\"pretty printing\\\" of the contents stream. \"\n\"Discrepancies between :data:`contents` and :data:`resources` objects will\"\n\" also be corrected if sanitize is true. See :meth:`Page.get_contents` for\"\n\" more details.\"\nmsgstr \"\"\n\"PDFのみ：このページに関連付けられたすべての :data:`contents` ツオブジェクトをクリーンアップして連結します。 \"\n\"\\\"クリーニング\\\"には、構文の修正、標準化、およびコンテンツストリームの \\\"きれいな印刷\\\"が含まれます。 \"\n\"sanitizeがtrueの場合、:data:`contents` と :data:`resources` \"\n\"オブジェクト間の不一致も修正されます。詳細については、:meth:`Page.get_contents` を参照してください。\"\n\n#: ../../functions.rst:723 301ef7e95bd144f8b88b541724fc0d58\nmsgid \"\"\n\"Changed in version 1.16.0 Annotations are no longer implicitly cleaned by\"\n\" this method. Use :meth:`Annot.clean_contents` separately.\"\nmsgstr \"\"\n\"バージョン1.16.0以降、注釈はこのメソッドによって暗黙的にクリーンアップされなくなりました。 \"\n\":meth:`Annot.clean_contents` を別途使用してください。\"\n\n#: ../../functions.rst:725 fb9142fcb2a94012a3fdd682a262552a\nmsgid \"\"\n\"*(new in v1.17.6)* if true, synchronization between resources and their \"\n\"actual use in the contents object is snychronized. For example, if a font\"\n\" is not actually used for any text of the page, then it will be deleted \"\n\"from the `/Resources/Font` object.\"\nmsgstr \"\"\n\"*（v1.17.6で新たに）* \"\n\"trueの場合、リソースとコンテンツオブジェクト間の同期が行われます。たとえば、ページのテキストでフォントが実際に使用されていない場合、それは \"\n\"`/Resources/Font`  オブジェクトから削除されます。\"\n\n#: ../../functions.rst:727 fc916fcfc1a14c108f31a9985fbb06f9\nmsgid \"\"\n\"This is a complex function which may generate large amounts of new data \"\n\"and render old data unused. It is **not recommended** using it together \"\n\"with the **incremental save** option. Also note that the resulting \"\n\"singleton new */Contents* object is **uncompressed**. So you should save \"\n\"to a **new file** using options *\\\"deflate=True, garbage=3\\\"*.\"\nmsgstr \"\"\n\"これは大量の新しいデータを生成し、古いデータを使用しないようにする複雑な機能です。**増分保存** オプションと一緒に使用することは \"\n\"**お勧めできません** 。また、結果のシングルトンの新しい */Contents* オブジェクトは **非圧縮です**。したがって、オプション \"\n\"*\\\"deflate=True、garbage=3\\\"* を使用して **新しいファイル** に保存する必要があります。\"\n\n#: ../../functions.rst:729 ee091ea4bbad4137bdf94b65bf7e1505\nmsgid \"\"\n\"Do not any longer use this method to ensure correct insertions on PDF \"\n\"pages. Since PyMuPDF version 1.24.2 this is taken care of automatically.\"\nmsgstr \"\"\n\n#: ../../functions.rst:735 da8e22bf756d4516a6435fef2ee406ef\nmsgid \"\"\n\"*New in version 1.17.0.* Return the concatenation of all :data:`contents`\"\n\" objects associated with the page -- without cleaning or otherwise \"\n\"modifying them. Use this method whenever you need to parse this source in\"\n\" its entirety without having to bother how many separate contents objects\"\n\" exist.\"\nmsgstr \"\"\n\"*v1.17.0で新たに追加。* ページに関連付けられたすべての :data:`contents` \"\n\"オブジェクトの連結を返します。クリーニングや変更などを行わずに、このソース全体を解析する必要がある場合にこのメソッドを使用します。\"\n\n#: ../../functions.rst:744 0ea4768fd42d4fcdb406a86bb35b0b3c\nmsgid \"\"\n\"Clean the :data:`contents` streams associated with the annotation. This \"\n\"is the same type of action which :meth:`Page.clean_contents` performs -- \"\n\"just restricted to this annotation.\"\nmsgstr \"\"\n\"アノテーションに関連付けられた :data:`contents` \"\n\"ストリームをクリーンアップします。これは、:meth:`Page.clean_contents` \"\n\"が実行するのと同じ種類のアクションですが、この注釈に制限されています。\"\n\n#: ../../functions.rst:751 c48de20f6397476e88558a5f14a2c96c\nmsgid \"\"\n\"Return a list of character glyphs and their widths for a font that is \"\n\"present in the document. A font must be specified by its PDF cross \"\n\"reference number :data:`xref`. This function is called automatically from\"\n\" :meth:`Page.insert_text` and :meth:`Page.insert_textbox`. So you should \"\n\"rarely need to do this yourself.\"\nmsgstr \"\"\n\"ドキュメント内に存在するフォントに対して、文字のグリフと幅のリストを返します。フォントはPDFのクロスリファレンス番号 :data:`xref` \"\n\"で指定する必要があります。この関数は、:meth:`Page.insert_text` および \"\n\":meth:`Page.insert_textbox` から自動的に呼び出されます。したがって、自分で行う必要があることはほとんどありません。\"\n\n#: ../../functions.rst:753 005b7266f7284e90bab8b77be14c642e\nmsgid \"\"\n\"cross reference number of a font embedded in the PDF. To find a font \"\n\":data:`xref`, use e.g. *doc.get_page_fonts(pno)* of page number *pno* and\"\n\" take the first entry of one of the returned list entries.\"\nmsgstr \"\"\n\"ドキュメントに埋め込まれたPDFのクロスリファレンス番号。フォントの :data:`xref` を見つけるには、例えば、ページ番号 *pno* の\"\n\" *doc.get_page_fonts(pno)* を使用し、返されたリストエントリの最初を取得します。\"\n\n#: ../../functions.rst:755 c40931be83a048c2b0e4d6547935db08\nmsgid \"\"\n\"limits the number of returned entries. The default of 256 is enforced for\"\n\" all fonts that only support 1-byte characters, so-called \\\"simple \"\n\"fonts\\\" (checked by this method). All :ref:`Base-14-Fonts` are simple \"\n\"fonts.\"\nmsgstr \"\"\n\"返されるエントリの数を制限します。256のデフォルト値は、1バイトの文字のみをサポートする「シンプルフォント」と呼ばれるフォントに対して適用されます（このメソッドで確認されます）。すべてのPDF\"\n\" :ref:`Base-14-Fonts` はシンプルフォントです。\"\n\n#: ../../functions.rst:758 c0afe718bd2442b18653b0b77f36b88c\nmsgid \"\"\n\"a list of *limit* tuples. Each character *c* has an entry  *(g, w)* in \"\n\"this list with an index of *ord(c)*. Entry *g* (integer) of the tuple is \"\n\"the glyph id of the character, and float *w* is its normalized width. The\"\n\" actual width for some :data:`fontsize` can be calculated as *w * \"\n\"fontsize*. For simple fonts, the *g* entry can always be safely ignored. \"\n\"In all other cases *g* is the basis for graphically representing *c*.\"\nmsgstr \"\"\n\"*limit* のタプルのリストです。各文字cには、*ord(c)* のインデックスでエントリ *（g、w）* があります。タプルの \"\n\"*g*（整数）エントリは文字のグリフIDで、float *w* はその正規化された幅です。一部のフォントサイズに対する実際の幅は、*w * \"\n\":data:`fontsize`* として計算できます。シンプルフォントの場合、gエントリは常に安全に無視できます。それ以外の場合、*g* は \"\n\"*c* を視覚的に表現するための基礎です。\"\n\n#: ../../functions.rst:760 d14f388f645f450e95a675c15496f9d0\nmsgid \"This function calculates the pixel width of a string called *text*::\"\nmsgstr \"この関数は、*text* と呼ばれる文字列のピクセル幅を計算します::\"\n\n#: ../../functions.rst:772 8580164da36b4e0c9468ee8d665d36ac\nmsgid \"New in version 1.14.14\"\nmsgstr \"バージョン1.14.14で新規追加\"\n\n#: ../../functions.rst:774 e5ce7ef74ebc4d4f8905c40e607a49ce\nmsgid \"\"\n\"PDF only: Check whether the object represented by :data:`xref` is a \"\n\":data:`stream` type. Return is ``False`` if not a PDF or if the number is\"\n\" outside the valid xref range.\"\nmsgstr \"\"\n\"PDFのみ：:data:`xref` によって表されるオブジェクトが :data:`stream` \"\n\"タイプかどうかを確認します。PDFでない場合や、有効なxref範囲外の場合はFalseを返します。\"\n\n#: ../../functions.rst:776 2cbd0ce6bddd4eb7894ddab3fda4d4c8\nmsgid \":data:`xref` number.\"\nmsgstr \":data:`xref` 番号。\"\n\n#: ../../functions.rst:778 9a6d0c88e56045e394739af6408a6b4e\nmsgid \"\"\n\"``True`` if the object definition is followed by data wrapped in keyword \"\n\"pair *stream*, *endstream*.\"\nmsgstr \"*stream*、*endstream* のキーワードペアで囲まれたデータに続いてオブジェクト定義がある場合は ``True``。\"\n\n#: ../../functions.rst:784 5b978581dd6b490e8af4afbf4586ca56\nmsgid \"\"\n\"Increase the :data:`xref` by one entry and return that number. This can \"\n\"then be used to insert a new object.\"\nmsgstr \":data:`xref` を1つ増やしてその番号を返します。これは新しいオブジェクトを挿入するために使用できます。\"\n\n#: ../../functions.rst:786 948cbb06043d486e90adbfb3b3275fa8\nmsgid \"\"\n\"int :returns: the number of the new :data:`xref` entry. Please note, that\"\n\" only a new entry in the PDF's cross reference table is created. At this \"\n\"point, there will not yet exist a PDF object associated with it. To \"\n\"create an (empty) object with this number use `doc.update_xref(xref, \"\n\"\\\"<<>>\\\")`.\"\nmsgstr \"\"\n\"int :returns: 新しい :data:`xref` \"\n\"エントリの数。PDFのクロスリファレンステーブルに新しいエントリのみが作成されます。この段階では、それに関連付けられたPDFオブジェクトはまだ存在しません。この番号で（空の）オブジェクトを作成するには、`doc.update_xref(xref、\\\"<<>>\\\")`\"\n\" を使用します。\"\n\n#: ../../functions.rst:793 e932ac5caa9f4c298a13a6d379dd7a51\nmsgid \"Return length of :data:`xref` table.\"\nmsgstr \":data:`xref` テーブルの長さを返します。\"\n\n#: ../../functions.rst:796 f840df5df4b545b1bbf730bf184c5803\nmsgid \"the number of entries in the :data:`xref` table.\"\nmsgstr \":data:`xref` テーブルのエントリ数。\"\n\n#: ../../functions.rst:802 b5d9bd2f14554b25bbb8fb9470c51da6\nmsgid \"\"\n\"Compute the quadrilateral of a text span extracted via options \\\"dict\\\" \"\n\"or \\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\":meth:`Page.get_text` のオプション \\\"dict\\\" または \\\"rawdict\\\" \"\n\"で抽出されたテキストスパンの四辺形を計算します。\"\n\n#: ../../functions.rst:804 91a864a4261a4b1abf61f04339ba4ede\nmsgid \"\"\n\"`line[\\\"dir\\\"]` of the owning line.  Use `None` for a span from \"\n\":meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\"所有する行の `line[\\\"dir\\\"]`。:meth:`Page.get_texttrace` からのスパンの場合は `None` \"\n\"を使用します。\"\n\n#: ../../functions.rst:805 ../../functions.rst:815 ../../functions.rst:826\n#: 7033d11e092540f4ba156c04a297c691 74f50cf2036e4339af0cf16e7378d340\n#: 994444b97874454798b14763f2d63fca\nmsgid \"the span.\"\nmsgstr \"スパン。\"\n\n#: ../../functions.rst:806 ddc5c01bb3e44f12bf7284bf4fe74e81\nmsgid \"\"\n\"the :ref:`Quad` of the span, usable for text marker annotations \"\n\"('Highlight', etc.).\"\nmsgstr \"スパンの :ref:`Quad`、テキストマーカーアノテーション（'ハイライト' など）で使用できます。\"\n\n#: ../../functions.rst:812 f9901afa0a67408ebc90c04e01c93f8a\nmsgid \"\"\n\"Compute the quadrilateral of a text character extracted via option \"\n\"\\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \":meth:`Page.get_text` のオプション \\\"rawdict\\\" で抽出されたテキスト文字の四辺形を計算します。\"\n\n#: ../../functions.rst:814 ../../functions.rst:825\n#: 67860855da1c47c8828ebecc90f766d6 7da81809c8ba42679d5e884d49b6878f\nmsgid \"\"\n\"`line[\\\"dir\\\"]` of the owning line. Use `None` for a span from \"\n\":meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\"所有する行の `line[\\\"dir\\\"]`。:meth:`Page.get_texttrace` からのスパンの場合は `None` \"\n\"を使用します。\"\n\n#: ../../functions.rst:816 131dbbd284734ed089c4778deb4dd003\nmsgid \"the character.\"\nmsgstr \"文字。\"\n\n#: ../../functions.rst:817 f88cafc7c32a4d6fad1b6135cd5cc40f\nmsgid \"\"\n\"the :ref:`Quad` of the character, usable for text marker annotations \"\n\"('Highlight', etc.).\"\nmsgstr \"文字の :ref:`Quad`、テキストマーカーアノテーション（'ハイライト' など）で使用できます。\"\n\n#: ../../functions.rst:823 d59e0653bc4246c7a9357ca70c5860b0\nmsgid \"\"\n\"Compute the quadrilateral of a subset of characters of a span extracted \"\n\"via option \\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \":meth:`Page.get_text` のオプション \\\"rawdict\\\" で抽出されたスパンの一部の文字の四辺形を計算します。\"\n\n#: ../../functions.rst:827 dadf644469074a32aa88fc7fdcf7698b\nmsgid \"\"\n\"the characters to consider. If given, the selected extraction option must\"\n\" be \\\"rawdict\\\".\"\nmsgstr \"考慮する文字。省略した場合、。指定する場合、選択した抽出オプションは \\\"rawdict\\\" である必要があります。\"\n\n#: ../../functions.rst:828 dfa12d94ceb3431eb63330adacb7bfe9\nmsgid \"\"\n\"the :ref:`Quad` of the selected characters, usable for text marker \"\n\"annotations ('Highlight', etc.).\"\nmsgstr \"選択された文字の :ref:`Quad` 、テキストマーカーアノテーション（'ハイライト' など）で使用できます。\"\n\n#: ../../functions.rst:834 6aa28bd6817943bfbb2746f7a6243580\nmsgid \"\"\n\"Compute the quadrilateral of a subset of spans of a text line extracted \"\n\"via options \\\"dict\\\" or \\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\":meth:`Page.get_text` のオプション \\\"dict\\\" または \\\"rawdict\\\" \"\n\"で抽出されたテキスト行の一部のスパンの四辺形を計算します。\"\n\n#: ../../functions.rst:836 78daeef8140c41a8a9c0b8b6c4532d1b\nmsgid \"the line.\"\nmsgstr \"行。\"\n\n#: ../../functions.rst:837 e903ee7d5d594fc1811c896806a6bb8e\nmsgid \"\"\n\"a sub-list of `line[\\\"spans\\\"]`. If omitted, the full line quad will be \"\n\"returned.\"\nmsgstr \"`line[\\\"spans\\\"]` のサブリスト。省略した場合、選択した行の四辺形が返されます。\"\n\n#: ../../functions.rst:838 4d44abbf27ac4dd98103b18718b1b07a\nmsgid \"\"\n\"the :ref:`Quad` of the selected line spans, usable for text marker \"\n\"annotations ('Highlight', etc.).\"\nmsgstr \"選択された行のスパンの :ref:`Quad`、テキストマーカーアノテーション（'ハイライト' など）で使用できます。\"\n\n#: ../../functions.rst:844 4afcc06f3e38430bafe222f1079b22a0\nmsgid \"Detect Tesseract language support folder.\"\nmsgstr \"\"\n\n#: ../../functions.rst:846 cab287431498493d97889bd9dc044f9d\nmsgid \"\"\n\"This function is used to enable OCR via Tesseract even if the language \"\n\"support folder is not specified directly or in environment variable \"\n\"TESSDATA_PREFIX.\"\nmsgstr \"\"\n\n#: ../../functions.rst:850 9ae2a9e271bd4bee918746c9384d309b\nmsgid \"If <tessdata> is set we return it directly.\"\nmsgstr \"\"\n\n#: ../../functions.rst:852 ff58521ec09244cf9af0e5556f7a846f\nmsgid \"Otherwise we return `os.environ['TESSDATA_PREFIX']` if set.\"\nmsgstr \"\"\n\n#: ../../functions.rst:854 e6350e60bfa84e9e9bc83ba51e45b115\nmsgid \"\"\n\"Otherwise we search for a Tesseract installation and return its language \"\n\"support folder.\"\nmsgstr \"\"\n\n#: ../../functions.rst:857 0e05c86bfe6f46f1b4451934cd24174b\nmsgid \"Otherwise we raise an exception.\"\nmsgstr \"\"\n\n#: ../../functions.rst:867 ec04b5d7ae7c4b2698bdbf79b6fee421\nmsgid \"\"\n\"Return the (unique) infinite rectangle `Rect(-2147483648.0, \"\n\"-2147483648.0, 2147483520.0, 2147483520.0)`, resp. the :ref:`IRect` and \"\n\":ref:`Quad` counterparts. It is the largest possible rectangle: all valid\"\n\" rectangles are contained in it.\"\nmsgstr \"\"\n\"(ユニークな) 無限の四角形 \"\n\"`Rect(-2147483648.0、-2147483648.0、2147483520.0、2147483520.0)`、または \"\n\":ref:`IRect` と :ref:`Quad` の対応するものを返します。これは最大の可能な四角形で、すべての有効な四角形が含まれます。\"\n\n#: ../../functions.rst:877 0089e42de5e24fdc9314358b9f612356\nmsgid \"\"\n\"Return the \\\"standard\\\" empty and invalid rectangle `Rect(2147483520.0, \"\n\"2147483520.0, -2147483648.0, -2147483648.0)` resp. quad. Its top-left and\"\n\" bottom-right point values are reversed compared to the infinite \"\n\"rectangle. It will e.g. be used to indicate empty bboxes in \"\n\"`page.get_text(\\\"dict\\\")` dictionaries. There are however infinitely many\"\n\" empty or invalid rectangles.\"\nmsgstr \"\"\n\"「標準」の空白で無効な四角形  `Rect(2147483520.0, 2147483520.0, -2147483648.0, \"\n\"-2147483648.0)` \"\n\"または対応する四角形を返します。その左上と右下のポイント値は、無限の四角形と比較して反転しています。たとえば、`page.get_text(\\\"dict\\\")`\"\n\" 辞書内の空の bboxes を示すために使用されます。ただし、無限に多くの空のまたは無効な四角形が存在します。\"\n\n#: ../../functions.rst:883 fea470f568524b038bb0e30aed353ec9\nmsgid \"\"\n\"Returns a dict mapping lower-case color name to `(red, green, blue)` \"\n\"tuple, and `red`, `green`, `blue` are floats in range 0..1.\"\nmsgstr \"\"\n\n#: ../../functions.rst:888 c23cf90537d54067a5727d87647c89d2\nmsgid \"\"\n\"Returns a list of `(colorname, red, green, blue)` tuples, where \"\n\"`colorname` is upper case and `red`, `green`, `blue` are integers in \"\n\"range 0..255.\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 e369c07a6dfc4a3d9e7f48a78f52b9bf\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"return the quad for a text span (\\\"dict\\\" / \\\"rawdict\\\")\"\n#~ msgstr \"テキスト スパンのクワッドを返す (\\\"dict\\\", \\\"rawdict\\\")\"\n\n#~ msgid \"*New in v1.18.9*\"\n#~ msgstr \"*新機能 v1.18.9*\"\n\n#~ msgid \"\"\n#~ \"Convenience function returning the \"\n#~ \"quadrilateral enveloping the text of a\"\n#~ \" text span, as returned by \"\n#~ \":meth:`Page.get_text` using the \\\"dict\\\" or\"\n#~ \" \\\"rawdict\\\" options.\"\n#~ msgstr \"\"\n#~ \":meth:`Page.get_text` を使用して、テキストスパンのテキストを囲む四角形を返す便利な関数。オプションとして\"\n#~ \" \\\"dict\\\" または \\\"rawdict\\\" を指定して \"\n#~ \":meth:`Page.get_text` から返されたテキストスパンの情報を使用します。\"\n\n#~ msgid \"the value `line[\\\"dir\\\"]` of the span's line.\"\n#~ msgstr \"スパンのラインの値 `line[\\\"dir\\\"]`。\"\n\n#~ msgid \"the span sub-dictionary.\"\n#~ msgstr \"スパンのサブディクショナリ。\"\n\n#~ msgid \"the quadrilateral of the span's text.\"\n#~ msgstr \"スパンのテキストの四角形。\"\n\n#~ msgid \"\"\n#~ \"Put string pair \\\"q\\\" / \\\"Q\\\" \"\n#~ \"before, resp. after a page's */Contents*\"\n#~ \" object(s) to ensure that any \"\n#~ \"\\\"geometry\\\" changes are **local** only.\"\n#~ msgstr \"\"\n#~ \"ページの */Contents* オブジェクトの前、または後ろに文字列ペア \\\"q\\\" /\"\n#~ \" \\\"Q\\\" を配置して、どんな \\\"geometry\\\" の変更も **ローカル**\"\n#~ \" な変更だけになるようにします。\"\n\n#~ msgid \"\"\n#~ \"Use this method as an alternative, \"\n#~ \"minimalist version of :meth:`Page.clean_contents`.\"\n#~ \" Its advantage is a small footprint\"\n#~ \" in terms of processing time and \"\n#~ \"impact on the data size of \"\n#~ \"incremental saves. Multiple executions of \"\n#~ \"this method are no problem and \"\n#~ \"have no functional impact: `b\\\"q q \"\n#~ \"contents Q Q\\\"` is treated like \"\n#~ \"`b\\\"q contents Q\\\"`.\"\n#~ msgstr \"\"\n#~ \"このメソッドは、:meth:`Page.clean_contents` \"\n#~ \"の代替として使用します。その利点は、処理時間と増分保存のデータサイズへの影響が少ないことです。このメソッドの複数回実行は問題ありませんし、機能的な影響もありません。例えば、`b\\\"q\"\n#~ \" q contents Q Q\\\"` は `b\\\"q \"\n#~ \"contents Q\\\"` と同様に扱われます。\"\n\n#~ msgid \"\"\n#~ \"Indicate whether :meth:`Page.wrap_contents` may \"\n#~ \"be required for object insertions in \"\n#~ \"standard PDF geometry. Note that this\"\n#~ \" is a quick, basic check only: \"\n#~ \"a value of ``False`` may still be\"\n#~ \" a false alarm. But nevertheless \"\n#~ \"executing :meth:`Page.wrap_contents` will have \"\n#~ \"no negative side effects.\"\n#~ msgstr \"\"\n#~ \":meth:`Page.wrap_contents` \"\n#~ \"が標準のPDFジオメトリにオブジェクトを挿入する際に必要かどうかを示します。ただし、これは迅速で基本的なチェックであることに注意してください。``False``\"\n#~ \" の値でも誤報の可能性があることに留意してください。ただし、:meth:`Page.wrap_contents` \"\n#~ \"を実行しても負の副作用はありません。\"\n\n#~ msgid \":attr:`TESSDATA_PREFIX`\"\n#~ msgstr \"\"\n\n#~ msgid \"a copy of `os.environ[\\\"TESSDATA_PREFIX\\\"]`\"\n#~ msgstr \"os.environ[\\\"TESSDATA_PREFIX\\\"] のコピーです\"\n\n#~ msgid \"New in v1.19.4\"\n#~ msgstr \"バージョン1.19.4で新たに導入されました\"\n\n#~ msgid \"\"\n#~ \"Copy of `os.environ[\\\"TESSDATA_PREFIX\\\"]` for \"\n#~ \"convenient checking whether there is \"\n#~ \"integrated Tesseract OCR support.\"\n#~ msgstr \"便利なチェックに使用される `os.environ[\\\"TESSDATA_PREFIX\\\"]` のコピー\"\n\n#~ msgid \"\"\n#~ \"If this attribute is `None`, \"\n#~ \"Tesseract-OCR is either not installed, \"\n#~ \"or the environment variable is not \"\n#~ \"set to point to Tesseract's language \"\n#~ \"support folder.\"\n#~ msgstr \"\"\n#~ \"この属性が `None` の場合、Tesseract-\"\n#~ \"OCRはインストールされていないか、環境変数がTesseractの言語サポートフォルダを指すように設定されていない可能性があります。\"\n\n#~ msgid \"\"\n#~ \"This variable is now checked before \"\n#~ \"OCR functions are tried. This prevents\"\n#~ \" verbose messages from MuPDF.\"\n#~ msgstr \"この変数は、OCR関数が試行される前に確認されます。これにより、MuPDFから冗長なメッセージが表示されるのを防ぎます。\"\n\n#~ msgid \"\"\n#~ \"This method obsoletes the use of \"\n#~ \":meth:`Page.clean_contents` in most cases. The\"\n#~ \" advantage this method is a small \"\n#~ \"footprint in terms of processing time\"\n#~ \" and a low impact on the data\"\n#~ \" size of incremental saves.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Return the name of Tesseract's language\"\n#~ \" support folder. Use this function if\"\n#~ \" the environment variable `TESSDATA_PREFIX` \"\n#~ \"has not been set.\"\n#~ msgstr \"\"\n#~ \"Tesseractの言語サポートフォルダの名前を返します。環境変数 `TESSDATA_PREFIX` \"\n#~ \"が設定されていない場合にこの関数を使用します\"\n\n#~ msgid \"\"\n#~ \"`os.getenv(\\\"TESSDATA_PREFIX\\\")` if not `None`. \"\n#~ \"Otherwise, if Tesseract-OCR is \"\n#~ \"installed, locate the name of \"\n#~ \"`tessdata`. If no installation is found,\"\n#~ \" return `False`.  The folder name can\"\n#~ \" be used as parameter `tessdata` in\"\n#~ \" methods :meth:`Page.get_textpage_ocr`, \"\n#~ \":meth:`Pixmap.pdfocr_save` and \"\n#~ \":meth:`Pixmap.pdfocr_tobytes`.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"`os.getenv(\\\"TESSDATA_PREFIX\\\")` if not `None`. \"\n#~ \"Otherwise, if Tesseract-OCR is \"\n#~ \"installed, locate the name of \"\n#~ \"`tessdata`. If no installation is found,\"\n#~ \" return `False`.\"\n#~ msgstr \"\"\n#~ \"`os.getenv(\\\"TESSDATA_PREFIX\\\")` が `None` でない場合\"\n#~ \"、またはTesseract-OCRがインストールされている場合は、`tessdata` \"\n#~ \"の名前を見つけます。インストールが見つからない場合、`False` を返します。\"\n\n#~ msgid \"\"\n#~ \"The folder name can be used as \"\n#~ \"parameter `tessdata` in methods \"\n#~ \":meth:`Page.get_textpage_ocr`, :meth:`Pixmap.pdfocr_save` \"\n#~ \"and :meth:`Pixmap.pdfocr_tobytes`.\"\n#~ msgstr \"\"\n#~ \"このフォルダの名前は、メソッド \"\n#~ \":meth:`Page.get_textpage_ocr`、:meth:`Pixmap.pdfocr_save`、および \"\n#~ \":meth:`Pixmap.pdfocr_tobytes` の `tessdata` \"\n#~ \"パラメータに使用できます。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Write to Python's `logging` system using\"\n#~ \" specified logger name. Only used if\"\n#~ \" `pylogging_logger` is None. Default is \"\n#~ \"`pymupdf`.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"If any `pylogging*` arg is not \"\n#~ \"None, we write to `Python's logging \"\n#~ \"system <https://docs.python.org/3/library/logging.html>`_.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/glossary.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b0e2cd94d0aa4b3a934fbebb0e61235b\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 f1baafce3d564895b00cf4bc56d7bb33\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 819b0bef657b4ba4a0ab2d3e4ec0b4d8\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../glossary.rst:7 9941910a374d4a0db2b472ea37c6f1f8\nmsgid \"Glossary\"\nmsgstr \"用語集\"\n\n#: ../../glossary.rst:11 0c491cef7a4041028d651475e56a294b\nmsgid \"\"\n\"This is an essential general mathematical / geometrical term for \"\n\"understanding this documentation. Please see this section for a more \"\n\"detailed discussion: :ref:`Coordinates`.\"\nmsgstr \"\"\n\n#: ../../glossary.rst:15 b03cc7629633424488939ad7912ff819\nmsgid \"A Python sequence of 6 numbers.\"\nmsgstr \"6つの数字からなるPythonのシーケンス。\"\n\n#: ../../glossary.rst:19 bd43bb115ff04c94b19ca36c5f5d02f6\nmsgid \"A Python sequence of 4 numbers.\"\nmsgstr \"4つの数字からなるPythonのシーケンス。\"\n\n#: ../../glossary.rst:23 1a31b68b33264ca5a77bd2b6902ffe53\nmsgid \"A Python sequence of 4 integers.\"\nmsgstr \"4つの整数からなるPythonのシーケンス。\"\n\n#: ../../glossary.rst:27 2a42549c54164862ab4a896ad4f7e587\nmsgid \"A Python sequence of 2 numbers.\"\nmsgstr \"2つの数字からなるPythonのシーケンス。\"\n\n#: ../../glossary.rst:31 5d5f5915c82d4921bed1e2f95ab91ecb\nmsgid \"A Python sequence of 4 :data:`point_like` items.\"\nmsgstr \"4つの :data:`point_like` アイテムからなるPythonのシーケンス。\"\n\n#: ../../glossary.rst:35 775806cbba59489bac52cba16de32799\nmsgid \"\"\n\"A number of values in a PDF can inherited by objects further down in a \"\n\"parent-child relationship. The mediabox (physical size) of pages may for \"\n\"example be specified only once or in some node(s) of the :data:`pagetree`\"\n\" and will then be taken as value for all *kids*, that do not specify \"\n\"their own value.\"\nmsgstr \"\"\n\"PDF内のいくつかの値は、親子関係で下位のオブジェクトに継承されることがあります。例えば、ページのmediabox（物理的なサイズ）は一度だけ指定されるか、:data:`pagetree`\"\n\" のいくつかのノードで指定され、それ以外の値を指定しない子供たちにとってその値が取得されます。\"\n\n#: ../../glossary.rst:41 d6aa867681e449c0a945275210eb6353\nmsgid \"\"\n\"A PDF array of 4 floats specifying a physical page size -- \"\n\"(:data:`inheritable`, mandatory). This rectangle should contain all other\"\n\" PDF  -- optional -- page rectangles, which may be specified in addition:\"\n\" CropBox, TrimBox, ArtBox and BleedBox. Please consult :ref:`AdobeManual`\"\n\" for details. The MediaBox is the only rectangle, for which there is no \"\n\"difference between MuPDF and PDF coordinate systems: \"\n\":attr:`Page.mediabox` will always show the same coordinates as the \"\n\"`/MediaBox` key in a page's object definition. For all other rectangles, \"\n\"MuPDF transforms y coordinates such that the **top** border is the point \"\n\"of reference. This can sometimes be confusing -- you may for example \"\n\"encounter a situation like this one:\"\nmsgstr \"\"\n\"物理的なページサイズを指定する4つの浮動小数点数からなるPDF配列 \"\n\"-（:data:`inheritable`、必須）。この矩形には、追加で指定できる他のすべてのPDFページ矩形を含める必要があります。これらの矩形にはCropBox、TrimBox、ArtBox、BleedBoxがあります。詳細については、\"\n\" :ref:`AdobeManual`  を参照してください。MediaBoxは、MuPDFとPDFの座標系の間に違いがない唯一の矩形です。 \"\n\":attr:`Page.mediabox` は常に、ページオブジェクト定義内の `/MediaBox` \"\n\"キーと同じ座標を示します。他のすべての矩形に関して、MuPDFはy座標を変換し、上部境界が参照点となるようにします。これは時に混乱することがあります。例えば、次のような状況に遭遇することがあります。\"\n\n#: ../../glossary.rst:43 4b7aa0adab17468e947f9b8eb328fd00\nmsgid \"\"\n\"The page definition contains the following identical values: `/MediaBox [\"\n\" 36 45 607.5 765 ]`, `/CropBox [ 36 45 607.5 765 ]`.\"\nmsgstr \"\"\n\"ページ定義には次のような同一の値が含まれています:  `/MediaBox [ 36 45 607.5 765 ]` 、 `/CropBox [ \"\n\"36 45 607.5 765 ]`。 \"\n\n#: ../../glossary.rst:44 c3336320e59f48f9986d52f340b7a4d4\nmsgid \"\"\n\"PyMuPDF accordingly shows `page.mediabox = Rect(36.0, 45.0, 607.5, \"\n\"765.0)`.\"\nmsgstr \"したがって、PyMuPDFは `page.mediabox = Rect(36.0, 45.0, 607.5, 765.0)` と表示します。 \"\n\n#: ../../glossary.rst:45 a216a8839aee420cbe653cdb1e90cee1\nmsgid \"\"\n\"**BUT:** `page.cropbox = Rect(36.0, 0.0, 607.5, 720.0)`, because the two \"\n\"y-coordinates have been transformed (45 subtracted from both of them).\"\nmsgstr \"\"\n\"しかし、 `page.cropbox = Rect(36.0, 0.0, 607.5, 720.0)` \"\n\"です。なぜなら、2つのy座標が変換されているため（両方から45が引かれているため）です。\"\n\n#: ../../glossary.rst:49 8fa4e076a5e744bfa85ec3664e4908ce\nmsgid \"\"\n\"A PDF array of 4 floats specifying a page's visible area -- \"\n\"(:data:`inheritable`, optional). It is the default for TrimBox, ArtBox \"\n\"and BleedBox. If not present, it defaults to MediaBox. This value is \"\n\"**not affected** if the page is rotated -- in contrast to \"\n\":attr:`Page.rect`. Also, other than the page rectangle, the top-left \"\n\"corner of the cropbox may or may not be *(0, 0)*.\"\nmsgstr \"\"\n\"ページの可視領域を指定する4つの浮動小数点数からなるPDF配列 \"\n\"-（:data:`inheritable`、任意）。これはTrimBox、ArtBox、BleedBoxのデフォルト値です。存在しない場合、デフォルトはMediaBoxです。この値はページが回転している場合には影響を受けません\"\n\" -  :attr:`Page.rect` とは対照的です。また、ページ矩形以外では、クロップボックスの左上隅が(0, \"\n\"0)であるかどうかは問題ありません。\"\n\n#: ../../glossary.rst:54 695d4331e2574a73a6bc119defe798a4\nmsgid \"\"\n\"A central PDF :data:`dictionary` -- also called the \\\"root\\\" -- \"\n\"containing document-wide parameters and pointers to many other \"\n\"information. Its :data:`xref` is returned by \"\n\":meth:`Document.pdf_catalog`.\"\nmsgstr \"\"\n\"中央のPDF :data:`dictionary` - または「ルート」とも呼ばれる - \"\n\"で、文書全体のパラメータと多くの他の情報へのポインタを含んでいます。その :data:`xref` は \"\n\":meth:`Document.pdf_catalog` で返されます。\"\n\n#: ../../glossary.rst:58 972c6ce4df00407a83efb4a5e33cf1b8\nmsgid \"\"\n\"More precisely, the **PDF trailer** contains information in \"\n\":data:`dictionary` format. It is usually located at the file's end. In \"\n\"this dictionary, you will find things like the xrefs of the catalog and \"\n\"the metadata, the number of :data:`xref` numbers, etc. Here is the \"\n\"definition of the PDF spec:\"\nmsgstr \"\"\n\"より正確には、PDFトレーラーには :data:`dictionary` \"\n\"形式の情報が含まれています。通常、ファイルの末尾に配置されています。この辞書には、カタログやメタデータの :data:`xref` \"\n\"、:data:`xref` の数などが含まれています。PDF仕様の定義は次のとおりです：\"\n\n#: ../../glossary.rst:60 c620690ecfe5406fbe8d467efeb91794\nmsgid \"\"\n\"*\\\"The trailer of a PDF file enables an application reading the file to \"\n\"quickly find the cross-reference table and certain special objects. \"\n\"Applications should read a PDF file from its end.\\\"*\"\nmsgstr \"「PDFファイルのトレーラーは、ファイルを読むアプリケーションがクロスリファレンステーブルと特定の特別なオブジェクトを迅速に見つけることを可能にします。アプリケーションはPDFファイルを末尾から読むべきです。」\"\n\n#: ../../glossary.rst:62 bbfcfb28f25f49608557cc077c9f2ff2\nmsgid \"\"\n\"To access the trailer in PyMuPDF, use the usual methods \"\n\":meth:`Document.xref_object`, :meth:`Document.xref_get_key` and \"\n\":meth:`Document.xref_get_keys` with `-1` instead of a positive xref \"\n\"number.\"\nmsgstr \"\"\n\"PyMuPDFでトレーラーにアクセスするには、通常の方法で :meth:`Document.xref_object` 、 \"\n\":meth:`Document.xref_get_key` 、:meth:`Document.xref_get_keys` \"\n\"を使用し、正のxref番号の代わりに `-1` を指定します。\"\n\n#: ../../glossary.rst:66 52c596bdac704429bcc9b0406875b7fc\nmsgid \"\"\n\"A **content stream** is a PDF :data:`object` with an attached \"\n\":data:`stream`, whose data consists of a sequence of instructions \"\n\"describing the graphical elements to be painted on a page, see \\\"Stream \"\n\"Objects\\\" on page 19 of :ref:`AdobeManual`. For an overview of the mini-\"\n\"language used in these streams, see chapter \\\"Operator Summary\\\" on page \"\n\"643 of the :ref:`AdobeManual`. A PDF :data:`page` can have none to many \"\n\"contents objects. If it has none, the page is empty (but still may show \"\n\"annotations). If it has several, they will be interpreted in sequence as \"\n\"if their instructions had been present in one such object (i.e. like in a\"\n\" concatenated string). It should be noted that there are more stream \"\n\"object types which use the same syntax: e.g. appearance dictionaries \"\n\"associated with annotations and Form XObjects.\"\nmsgstr \"\"\n\"コンテンツストリームは、PDF :data:`object` に添付された :data:`stream` \"\n\"を持ち、そのデータはページに描画されるグラフィカル要素を記述する命令のシーケンスから成り立っています。 :ref:`AdobeManual` \"\n\"の「Stream Objects」（p.19）を参照してください。これらのストリームで使用されるミニ言語の概要については、 \"\n\":ref:`AdobeManual` の「Operator \"\n\"Summary」章（p.643）をご覧ください。PDFページには0から多くのコンテンツオブジェクトを持つことができます。コンテンツオブジェクトが存在しない場合、ページは空になります（ただし注釈は表示される可能性があります）。複数のコンテンツオブジェクトがある場合、それらは1つのオブジェクトに存在するかのように順番に解釈されます（つまり、連結された文字列のように）。なお、同じ構文を使用する他のストリームオブジェクトタイプもあることに注意してください。たとえば、注釈に関連する外観辞書やフォームXObjectなどです。\"\n\n#: ../../glossary.rst:68 fcc09656179a42c7974f67c0e38f4c94\nmsgid \"PyMuPDF provides a number of methods to deal with contents of PDF pages:\"\nmsgstr \"PyMuPDFは、PDFページのコンテンツに対処するためのいくつかのメソッドを提供しています：\"\n\n#: ../../glossary.rst:70 aa25f61d861242e7a13b1c745587ebad\nmsgid \"\"\n\":meth:`Page.read_contents()` -- reads and concatenates all page contents \"\n\"into one `bytes` object.\"\nmsgstr \":meth:`Page.read_contents()` – ページのすべてのコンテンツを読み込んで1つのバイトオブジェクトに連結します。\"\n\n#: ../../glossary.rst:71 85a71eda07ba4442b8014231e74ff345\nmsgid \"\"\n\":meth:`Page.clean_contents()` -- a wrapper of a MuPDF function that \"\n\"reads, concatenates and syntax-cleans all page contents. After this, only\"\n\" one `/Contents` object will exist. In addition, page :data:`resources` \"\n\"will have been synchronized with it such that it will contain exactly \"\n\"those images, fonts and other objects that the page actually references.\"\nmsgstr \"\"\n\":meth:`Page.clean_contents()` – \"\n\"MuPDFの関数をラップして、ページのすべてのコンテンツを読み込んで連結し、構文をクリーンアップします。これにより、1つの  \"\n\"`/Contents` オブジェクトのみが存在します。さらに、ページの :data:`resources` \"\n\"はそれと同期され、ページが実際に参照する画像、フォント、その他のオブジェクトのみが含まれるようになります。\"\n\n#: ../../glossary.rst:72 47bbed208b0b4183bd6abbb069ce2eb9\nmsgid \"\"\n\":meth:`Page.get_contents()` -- return a list of :data:`xref` numbers of a\"\n\" page's :data:`contents` objects. May be empty. Use \"\n\":meth:`Document.xref_stream()` with one of these xrefs to read the resp. \"\n\"contents section.\"\nmsgstr \"\"\n\":meth:`Page.get_contents()` – ページの :data:`contents` オブジェクトの :data:`xref` \"\n\"番号のリストを返します。空かもしれません。:meth:`Document.xref_stream()` \"\n\"をこれらのxrefの1つとともに使用して、対応するコンテンツセクションを読み込むことができます。\"\n\n#: ../../glossary.rst:73 fc38f58008f949d283ae3b24382f368a\nmsgid \"\"\n\":meth:`Page.set_contents()` -- set a page's `/Contents` key to the \"\n\"provided :data:`xref` number.\"\nmsgstr \":meth:`Page.set_contents()` – ページの `/Contents` キーを指定されたxref番号に設定します。\"\n\n#: ../../glossary.rst:77 7f136697e7be484382e85c200cb2c6dc\nmsgid \"\"\n\"A :data:`dictionary` containing references to any resources (like images \"\n\"or fonts) required by a PDF :data:`page` (required, inheritable, \"\n\":ref:`AdobeManual` p. 81) and certain other objects (Form XObjects). This\"\n\" dictionary appears as a sub-dictionary in the object definition under \"\n\"the key */Resources*. Being an inheritable object type, there may exist \"\n\"\\\"parent\\\" resources for all pages or certain subsets of pages.\"\nmsgstr \"\"\n\"PDFページに必要なリソース（画像やフォントなど）への参照を含む :data:`dictionary`（必須、継承可能、 \"\n\":ref:`AdobeManual`  p. 81）および一部の他のオブジェクト（フォームXObject）が必要です。この \"\n\":data:`dictionary` \"\n\"は、オブジェクト定義内のキー/リソースの下にサブ辞書として表示されます。継承可能なオブジェクトタイプであるため、すべてのページまたは一部のページの「親」リソースが存在する可能性があります。\"\n\n#: ../../glossary.rst:81 bf3936e13b07411e9f15d4dea0704603\nmsgid \"\"\n\"A PDF :data:`object` type, which is somewhat comparable to the same-named\"\n\" Python notion: \\\"A dictionary object is an associative table containing \"\n\"pairs of objects, known as the dictionary's entries. The first element of\"\n\" each entry is the key and the second element is the value. The key must \"\n\"be a name (...). The value can be any kind of object, including another \"\n\"dictionary. A dictionary entry whose value is null (...) is equivalent to\"\n\" an absent entry.\\\" (:ref:`AdobeManual` p. 18).\"\nmsgstr \"\"\n\"PDF :data:`object` \"\n\"のタイプで、同じ名前のPythonの概念に多少似ています。「辞書オブジェクトは、辞書のエントリとして知られるオブジェクトのペアを含む連想テーブルです。各エントリの最初の要素はキーであり、2番目の要素は値です。キーは名前である必要があります（...）。値は他の辞書を含む他の種類のオブジェクトであることができます。値がnull\"\n\" (...) の辞書エントリは、不在のエントリと同等です。」（:ref:`AdobeManual` p. 18）。\"\n\n#: ../../glossary.rst:83 a5774d115d78486887db6243636d5362\nmsgid \"\"\n\"Dictionaries are the most important :data:`object` type in PDF. Here is \"\n\"an example (describing a :data:`page`)::\"\nmsgstr \"辞書は、PDF内で最も重要なオブジェクトのタイプです。以下は、:data:`page` を記述する例です::\"\n\n#: ../../glossary.rst:102 45aa2b19b71e458e8fa25a2c78d596a6\nmsgid \"\"\n\"*Contents*, *Type*, *MediaBox*, etc. are **keys**, *40 0 R*, *Page*, *[0 \"\n\"0 595.32 841.92]*, etc. are the respective **values**. The strings \"\n\"*\\\"<<\\\"* and *\\\">>\\\"* are used to enclose object definitions.\"\nmsgstr \"\"\n\"Contents、Type、MediaBoxなどはキーであり、40 0 R、Page、[0 0 595.32 \"\n\"841.92]などはそれぞれの値です。「<<」と「>>」という文字列は、オブジェクト定義を括るために使用されます。\"\n\n#: ../../glossary.rst:104 a6f9190af07842339804c618355e0e27\nmsgid \"\"\n\"This example also shows the syntax of **nested** dictionary values: \"\n\"*Resources* has an object as its value, which in turn is a dictionary \"\n\"with keys like *ExtGState* (with the value *<</R7 26 0 R>>*, which is \"\n\"another dictionary), etc.\"\nmsgstr \"\"\n\"この例は、ネストされた辞書の値の構文も示しています。Resourcesはその値としてオブジェクトを持ち、それ自体がExtGState（値は<</R7\"\n\" 26 0 R>>で、これは別の辞書です）、などのキーを持つ辞書です。\"\n\n#: ../../glossary.rst:108 b97660907730454fb80cae8fff9da131\nmsgid \"\"\n\"A PDF page is a :data:`dictionary` object which defines one page in a \"\n\"PDF, see :ref:`AdobeManual` p. 71.\"\nmsgstr \"\"\n\"PDFページは、PDF内の1つのページを定義する :data:`dictionary` オブジェクトであり、 :ref:`AdobeManual`\"\n\" p. 71を参照してください。\"\n\n#: ../../glossary.rst:112 97d4db102e0e4330938ad1f4e7fca422\nmsgid \"\"\n\"The pages of a document are accessed through a structure known as the \"\n\"page tree, which defines the ordering of pages in the document. The tree \"\n\"structure allows PDF consumer applications, using only limited memory, to\"\n\" quickly open a document containing thousands of pages. The tree contains\"\n\" nodes of two types: intermediate nodes, called page tree nodes, and leaf\"\n\" nodes, called page objects. (:ref:`AdobeManual` p. 75).\"\nmsgstr \"\"\n\"文書のページは、ページツリーとして知られる構造を介してアクセスされ、文書内のページの順序を定義します。このツリー構造により、限られたメモリしか使用しないPDFコンシューマーアプリケーションでも、数千ページを含む文書を迅速に開くことができます。ツリーには2種類のノードが含まれています。中間ノードはページツリーノードと呼ばれ、葉ノードはページオブジェクトと呼ばれます。（:ref:`AdobeManual`\"\n\" p. 75）。\"\n\n#: ../../glossary.rst:114 2dbcc685903a4543922f7629dbdc1af4\nmsgid \"\"\n\"While it is possible to list all page references in just one array, PDFs \"\n\"with many pages are often created using *balanced tree* structures \"\n\"(\\\"page trees\\\") for faster access to any single page. In relation to the\"\n\" total number of pages, this can reduce the average page access time by \"\n\"page number from a linear to some logarithmic order of magnitude.\"\nmsgstr \"ページ参照を単一の配列でリストすることは可能ですが、多くのページを含むPDFは、より迅速な単一ページへのアクセスのためにバランスの取れたツリー構造（「ページツリー」）を使用して作成されることがよくあります。全ページ数に対して、これにより平均ページアクセス時間がページ番号による線形から対数のオーダーに削減されることがあります。\"\n\n#: ../../glossary.rst:116 aca1e345565340d197f15bb05ce23148\nmsgid \"\"\n\"For fast page access, MuPDF can use its own array in memory -- \"\n\"independently from what may or may not be present in the document file. \"\n\"This array is indexed by page number and therefore much faster than even \"\n\"the access via a perfectly balanced page tree.\"\nmsgstr \"\"\n\"高速なページアクセスのために、MuPDFは独自のメモリ内配列を使用できます - \"\n\"文書ファイルに存在するかどうかに関係なく。この配列はページ番号でインデックスされるため、完全にバランスが取れたページツリーを経由するアクセスよりもはるかに高速です。\"\n\n#: ../../glossary.rst:120 cf48ba84c41b4860a00bb4859a5f1ab6\nmsgid \"\"\n\"Similar to Python, PDF supports the notion *object*, which can come in \"\n\"eight basic types: boolean values (\\\"true\\\" or \\\"false\\\"), integer and \"\n\"real numbers, strings (**always** enclosed in brackets -- either \\\"()\\\", \"\n\"or \\\"<>\\\" to indicate hexadecimal), names (must always start with a \"\n\"\\\"/\\\", e.g. `/Contents`), arrays (enclosed in brackets \\\"[]\\\"), \"\n\"dictionaries (enclosed in brackets \\\"<<>>\\\"), streams (enclosed by \"\n\"keywords \\\"stream\\\" / \\\"endstream\\\"), and the null object (\\\"null\\\") \"\n\"(:ref:`AdobeManual` p. 13). Objects can be made identifiable by assigning\"\n\" a label. This label is then called *indirect* object. PyMuPDF supports \"\n\"retrieving definitions of indirect objects via their cross reference \"\n\"number via :meth:`Document.xref_object`.\"\nmsgstr \"\"\n\"Pythonに類似して、PDFはオブジェクトの概念をサポートしており、8つの基本型があります：ブール値（「true」または「false」）、整数と実数、文字列（常に括弧で囲まれています\"\n\" - 「()」または「<>」で16進数を示す）、名前（必ず「/」で始まる必要があります、例： \"\n\"`/Contents`）、配列（括弧「[]」で囲まれています）、辞書（括弧「<<>>」で囲まれています）、ストリーム（キーワード「stream」/「endstream」で囲まれています）、およびヌルオブジェクト（「null」）（:ref:`AdobeManual`\"\n\" p. \"\n\"13）。オブジェクトはラベルを割り当てることで識別可能にすることができます。このラベルは、間接オブジェクトと呼ばれます。PyMuPDFは、:meth:`Document.xref_object`\"\n\"  を介して間接オブジェクトの定義をクロスリファレンス番号を使って取得することができます。\"\n\n#: ../../glossary.rst:124 65f67d11513245eea25bbcfe453941d4\nmsgid \"\"\n\"A PDF :data:`dictionary` :data:`object` type which is followed by a \"\n\"sequence of bytes, similar to Python *bytes*. \\\"However, a PDF \"\n\"application can read a stream incrementally, while a string must be read \"\n\"in its entirety. Furthermore, a stream can be of unlimited length, \"\n\"whereas a string is subject to an implementation limit. For this reason, \"\n\"objects with potentially large amounts of data, such as images and page \"\n\"descriptions, are represented as streams.\\\" \\\"A stream consists of a \"\n\":data:`dictionary` followed by zero or more bytes bracketed between the \"\n\"keywords *stream* and *endstream*\\\"::\"\nmsgstr \"\"\n\"PDFの :data:`dictionary` :data:`object` \"\n\"タイプで、Pythonのbytesに似たバイト列が続きます。ただし、「PDFアプリケーションはストリームを段階的に読むことができますが、文字列は完全に読む必要があります。さらに、ストリームの長さは無制限ですが、文字列は実装の制限に従います。そのため、画像やページの説明などの大量のデータを含むオブジェクトは、ストリームとして表現されます。」「ストリームは、キーワード「stream」と「endstream」で囲まれた0バイト以上のバイトで構成される\"\n\" :data:`dictionary` の後に続きます」::\"\n\n#: ../../glossary.rst:135 1f0727e3f450432f9923a4ffd2cc8cee\nmsgid \"\"\n\"See :ref:`AdobeManual` p. 19. PyMuPDF supports retrieving stream content \"\n\"via :meth:`Document.xref_stream`. Use :meth:`Document.is_stream` to \"\n\"determine whether an object is of stream type.\"\nmsgstr \"\"\n\":ref:`AdobeManual` p. 19を参照してください。PyMuPDFは、:meth:`Document.xref_stream` \"\n\"を介してストリームコンテンツを取得するサポートを提供しています。オブジェクトがストリームタイプかどうかを判断するには、:meth:`Document.is_stream`\"\n\" を使用します。\"\n\n#: ../../glossary.rst:139 d732f9dcef7e47028ca43a5647adcb9c\nmsgid \"\"\n\"A mathematical notion meaning a vector of norm (\\\"length\\\") 1 -- usually \"\n\"the Euclidean norm is implied. In PyMuPDF, this term is restricted to \"\n\":ref:`Point` objects, see :attr:`Point.unit`.\"\nmsgstr \"\"\n\"数学的な概念で、ノルム（「長さ」）が1のベクトルを意味します。通常、ユークリッドノルムが含まれます。PyMuPDFでは、この用語は \"\n\":ref:`Point` オブジェクトに制限されます。:attr:`Point.unit` を参照してください。\"\n\n#: ../../glossary.rst:143 26fb51d68f234a088d1702a7b331d879\nmsgid \"\"\n\"Abbreviation for cross-reference number: this is an integer unique \"\n\"identification for objects in a PDF. There exists a cross-reference table\"\n\" (which may physically consist of several separate segments) in each PDF,\"\n\" which stores the relative position of each object for quick lookup. The \"\n\"cross-reference table is one entry longer than the number of existing \"\n\"object: item zero is reserved and must not be used in any way. Many \"\n\"PyMuPDF classes have an :data:`xref` attribute (which is zero for non-\"\n\"PDFs), and one can find out the total number of objects in a PDF via \"\n\":meth:`Document.xref_length` *- 1*.\"\nmsgstr \"\"\n\"クロスリファレンス番号の省略形：これはPDF内のオブジェクトに対する一意の識別子である整数です。各PDFにはクロスリファレンステーブルが存在し（物理的には複数の別々のセグメントで構成される場合があります）、各オブジェクトの相対位置をクイックルックアップのために保存します。クロスリファレンステーブルは既存のオブジェクトの数よりも1つ長いエントリを持っており、アイテム0は予約され、何の方法でも使用してはいけません。多くのPyMuPDFクラスにはxref属性（非PDFの場合はゼロ）があり、:meth:`Document.xref_length`\"\n\" - 1を介してPDF内のオブジェクトの総数を知ることができます。\"\n\n#: ../../glossary.rst:148 6c021fd6a5aa44d7b8b3e0905f3f7b08\nmsgid \"\"\n\"When referring to font size this metric is measured in points where 1 \"\n\"inch = 72 points.\"\nmsgstr \"フォントサイズを指す際、このメトリックは1インチ = 72ポイントとして測定されます。\"\n\n#: ../../glossary.rst:152 c558da0bdc1446d89fcd51030a930245\nmsgid \"\"\n\"Images and :ref:`Pixmap` objects may contain resolution information \"\n\"provided as \\\"dots per inch\\\", dpi, in each direction (horizontal and \"\n\"vertical). When MuPDF reads an image from a file or from a PDF object, it\"\n\" will parse this information and put it in :attr:`Pixmap.xres`, \"\n\":attr:`Pixmap.yres`, respectively. If it finds no meaningful information \"\n\"in the input (like non-positive values or values exceeding 4800), it will\"\n\" use \\\"sane\\\" defaults instead. The usual default value is 96, but it may\"\n\" also be 72 in some cases (e.g. for JPX images).\"\nmsgstr \"\"\n\"イメージや :ref:`Pixmap` \"\n\"オブジェクトには、各方向（水平および垂直）の「インチあたりのドット数」である解像度情報が含まれている場合があります。MuPDFはファイルまたはPDFオブジェクトからイメージを読み取る際、この情報を解析し、それぞれ\"\n\" :attr:`Pixmap.xres` 、:attr:`Pixmap.yres` \"\n\"に設定します。入力内で有意義な情報が見つからない場合（非正の値や4800を超える値など）、代わりに「適切な」デフォルト値を使用します。通常のデフォルト値は96ですが、一部の場合（例えばJPXイメージの場合）は72になる場合もあります。\"\n\n#: ../../glossary.rst:156 8e9c840d574c4b3d8c897a834b9362df\nmsgid \"\"\n\"Optional content properties dictionary - a sub :data:`dictionary` of the \"\n\"PDF :data:`catalog`. The central place to store optional content \"\n\"information, which is identified by the key `/OCProperties`. This \"\n\"dictionary has two required and one optional entry: (1) `/OCGs`, \"\n\"required, an array listing all optional content groups, (2) `/D`, \"\n\"required, the default optional content configuration dictionary (OCCD), \"\n\"(3) `/Configs`, optional, an array of alternative OCCDs.\"\nmsgstr \"\"\n\"オプショナルコンテンツプロパティ辞書（OCPD） - PDF :data:`catalog` のサブ \"\n\":data:`dictionary`。オプショナルコンテンツ情報を保存する中心的な場所で、キー `/OCProperties` \"\n\"で識別されます。この辞書には2つの必須エントリと1つのオプションエントリがあります：（1） `/OCGs` \"\n\"、必須、すべてのオプショナルコンテンツグループをリストする配列、（2） `/D` \"\n\"、必須、デフォルトのオプショナルコンテンツ構成辞書（OCCD）、（3） `/Configs` 、オプション、代替のOCCDの配列。\"\n\n#: ../../glossary.rst:161 0100632cdca744f69f1f6913c969d05d\nmsgid \"\"\n\"Optional content configuration dictionary - a PDF :data:`dictionary` \"\n\"inside the PDF :data:`OCPD`. It stores a setting of ON / OFF states of \"\n\"OCGs and how they are presented to a PDF viewer program. Selecting a \"\n\"configuration is quick way to achieve temporary mass visibility state \"\n\"changes. After opening a PDF, the `/D` configuration of the :data:`OCPD` \"\n\"is always activated. Viewer should offer a way to switch between the \"\n\"`/D`, or one of the optional configurations contained in array \"\n\"`/Configs`.\"\nmsgstr \"\"\n\"オプショナルコンテンツ構成辞書（OCCD） - PDF :data:`OCPD` 内のPDF \"\n\":data:`dictionary`。これはOCGのON / \"\n\"OFF状態とPDFビューアプログラムにどのように表示されるかの設定を保存します。構成を選択することは、一時的な質量表示状態の変更を素早く行う方法です。PDFを開いた後、:data:`OCPD`\"\n\" の `/D` 構成は常にアクティブになります。ビューアは `/D` 、または配列 `/Configs` \"\n\"に含まれるオプショナル構成のいずれかに切り替える方法を提供する必要があります。\"\n\n#: ../../glossary.rst:166 43b7c2249e154c59bf5a59cfd2cf86e2\nmsgid \"\"\n\"Optional content group -- a :data:`dictionary` object used to control the\"\n\" visibility of other PDF objects like images or annotations. \"\n\"Independently on which page they are defined, objects with the same OCG \"\n\"can simultaneously be shown or hidden by setting their OCG to ON or OFF. \"\n\"This can be achieved via the user interface provided by many PDF viewers \"\n\"(Adobe Acrobat), or programmatically.\"\nmsgstr \"\"\n\"オプショナルコンテンツグループ（OCG） - 画像や注釈などの他のPDFオブジェクトの表示を制御するために使用される \"\n\":data:`dictionary` \"\n\"オブジェクト。どのページで定義されているかに関係なく、同じOCGを持つオブジェクトは、OCGをONまたはOFFに設定することで同時に表示または非表示にできます。これは多くのPDFビューア（Adobe\"\n\" Acrobat）が提供するユーザーインターフェース、またはプログラムを使用して達成できます。\"\n\n#: ../../glossary.rst:170 f4ba5ac63bea490bbc335d7fade50a6b\nmsgid \"\"\n\"Optional content membership dictionary -- a :data:`dictionary` object \"\n\"which can be used like an :data:`OCG`: it has a visibility state. The \"\n\"visibility of an OCMD is **computed:** it is a logical expression, which \"\n\"uses the state of one or more OCGs to produce a boolean value. The \"\n\"expression's result is interpreted as ON (true) or OFF (false).\"\nmsgstr \"\"\n\"オプショナルコンテンツメンバーシップ辞書（OCMD） - :data:`OCG` \"\n\"のように使用できる辞書オブジェクトで、表示状態を持ちます。OCMDの表示は計算されます：これはOCGの1つ以上の状態を使用してブール値を生成する論理式です。式の結果はON（true）またはOFF（false）として解釈されます。\"\n\n#: ../../glossary.rst:174 522b5dde5e3b49df8ab57178f4d58ed1\nmsgid \"\"\n\"Some frequent character combinations are represented by their own special\"\n\" glyphs in more advanced fonts. Typical examples are \\\"fi\\\", \\\"fl\\\", \"\n\"\\\"ffi\\\" and \\\"ffl\\\". These compounds are called *ligatures*. In PyMuPDF \"\n\"text extractions, there is the option to either return the corresponding \"\n\"unicode unchanged, or split ligatures up into their constituent parts: \"\n\"\\\"fi\\\" ==> \\\"f\\\" + \\\"i\\\", etc.\"\nmsgstr \"\"\n\"一部の頻繁な文字の組み合わせは、より高度なフォントでは固有の特別なグリフで表されます。典型的な例には「fi」、「fl」、「ffi」、「ffl」などがあります。これらの複合体はリガチャと呼ばれます。PyMuPDFのテキスト抽出では、対応するユニコードを変更せずに返すオプションがあり、またリガチャをその構成要素に分割することもできます：「fi」\"\n\" ==> 「f」+「i」など。\"\n\n#: ../../footer.rst:60 04c382aafad34653bc0f596f100e3271\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/header-404.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.26\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-03-05 14:46+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header-404.rst:-1 c2c49975f2854128bb488c59ce955f84\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header-404.rst:-1 371ca3eaed8242b8bf4e8df0b45a6113\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header-404.rst:-1 a60c91d091c44274bed060f48efb71b1\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/header.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-09-28 14:54+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 5eedbfe14cba4a21b822c8197f635c3f\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 ef34ef4fc02843218e7c1e16cfb6fe2f\nmsgid \"PyMuPDF is a high-performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 93ea3b2b433546f9b198b2f2455bb6df\nmsgid \"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/how-to-open-a-file.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.8\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 21b5c4028adc463abcc84975940e6301\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 ee82d615395c4e24b8b07395ed871d70\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 1d5b2478c53f433882bce199582d444d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../how-to-open-a-file.rst:7 5ea3d22849e641d897ccb82f8a12500f\nmsgid \"Opening Files\"\nmsgstr \"ファイルを開く\"\n\n#: ../../how-to-open-a-file.rst:16 395abd8299ba47be838498d680488494\nmsgid \"Supported File Types\"\nmsgstr \"サポートされているファイルタイプ\"\n\n#: ../../how-to-open-a-file.rst:21 cb3463a996b24a14a008c2fc0ad2b685\nmsgid \"PyMuPDF\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:23 036ac377808741358875a6692e0b2d95\nmsgid \"|PyMuPDF| can open files other than just |PDF|.\"\nmsgstr \"|PyMuPDF| は |PDF| 以外のファイルも開くことができます。\"\n\n#: ../../how-to-open-a-file.rst:25 ../../how-to-open-a-file.rst:38\n#: 1a17fc4b2c2e43a9a47e3a2a1ed82bd4 40ef4134dff248bc8869aed36fd176fc\nmsgid \"The following file types are supported:\"\nmsgstr \"|PyMuPDF| は以下のファイルタイプをサポートしています：\"\n\n#: ../../how-to-open-a-file.rst:34 fa9ae965eea142478505848892067bb0\nmsgid \"PyMuPDF Pro\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:36 c4725d269a0e41b0867c5b6b16b8960b\nmsgid \"|PyMuPDF Pro| can open Office files.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:43 d91d49bc138843188ab0077259cd82ae\nmsgid \"**DOC/DOCX**\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:44 6ff3d492743f45da9b9967b7ac205f1c\nmsgid \"**XLS/XLSX**\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:45 4c317c161ef64bebb742fc17e8e5c6d3\nmsgid \"**PPT/PPTX**\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:46 dfd0df787a6d4a8bada3b55675495889\nmsgid \"**HWP/HWPX**\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:63 61701c1d1007436987106ec058719b82\nmsgid \"How to Open a File\"\nmsgstr \"ファイルを開く方法\"\n\n#: ../../how-to-open-a-file.rst:65 9dd2157acd454f2ea9e62168276399c2\nmsgid \"To open a file, do the following:\"\nmsgstr \"ファイルを開くには、次の手順を実行します。\"\n\n#: ../../how-to-open-a-file.rst:72 284b59b0b7ca41789da44c7d61f81fc7\nmsgid \"\"\n\"The above creates a :ref:`Document`. The instruction `doc = \"\n\"pymupdf.Document(\\\"a.pdf\\\")` does exactly the same. So, `open` is just a \"\n\"convenient alias and you can find its full API documented in that \"\n\"chapter.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:76 1a5ad0264ff94231899c2caafe461a22\n#, fuzzy\nmsgid \"\"\n\"File Recognizer: Opening with :index:`a Wrong File Extension <pair: \"\n\"wrong; file extension>`\"\nmsgstr \"拡張子の異なるファイルを開く\"\n\n#: ../../how-to-open-a-file.rst:78 90b4fc7ee95f43f49a70a15c890eb8b8\n#, fuzzy\nmsgid \"\"\n\"If you have a document with a wrong file extension for its type, do not \"\n\"worry: it will still be opened correctly, thanks to the integrated file \"\n\"\\\"content recognizer\\\".\"\nmsgstr \"拡張子がファイルタイプと異なっていても、正しく開くことができます。\"\n\n#: ../../how-to-open-a-file.rst:80 792fc8fc530d4591b0673684e9d0b274\nmsgid \"\"\n\"This component looks at the actual data in the file using a number of \"\n\"heuristics -- independent of the file extension. This of course is also \"\n\"true for file names **without** an extension.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:82 8eec48ad8d35400f93aa9ef384f1baee\nmsgid \"Here is a list of details about how the file content recognizer works:\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:84 999889fc95024292bbe0dc81938a321a\nmsgid \"\"\n\"When opening from a file name, use the ``filetype`` parameter if your \"\n\"file format cannot be determined by content inspection. This is for \"\n\"instance the case for all text files: \\\"txt\\\", \\\"html\\\", \\\"xml\\\" or \"\n\"source files. If the file extension is missing or wrong or the file \"\n\"resides in memory, the ``filetype`` must be used. File formats that can \"\n\"successfully be recognized will be opened even without or wrong \"\n\"extensions, and the ``filetype`` paraneter will be ignored.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:86 1ac5dd5257eb4ed280e6ec3ed082da31\nmsgid \"\"\n\"Files based on text content do not contain unambiguously recognizable \"\n\"internal structures. This is true for source files (Python, C, etc.) but \"\n\"also HTML, XML and so on. Here, the file extensions and the ``filetype`` \"\n\"parameter continue to play a role and are used to create a \\\"Tex\\\" / \"\n\"\\\"HTML\\\" / ... document. Correspondingly, text files with other / no \"\n\"extensions, can successfully be opened using ``filetype``.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:92 b9b6d23c55ea4547afea0a22f2d79c6d\n#, fuzzy\nmsgid \"Opening Remote Files\"\nmsgstr \"ファイルを開く\"\n\n#: ../../how-to-open-a-file.rst:95 3b43bf59bfc148328c683743eac1329f\nmsgid \"\"\n\"For remote files on a server (i.e. non-local files), you will need to \"\n\"*stream* the file data to |PyMuPDF|.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:97 34b7bf2e937a4250810966ed193bdfc8\nmsgid \"\"\n\"For example use the `requests \"\n\"<https://requests.readthedocs.io/en/latest/>`_ library as follows:\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:110 f259d8091f7242e7bdd2c51ebdd3f925\nmsgid \"Opening Files from Cloud Services\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:112 21d40cb6351a4c69bc14196e1eb014ea\nmsgid \"\"\n\"For further examples which deal with files held on typical cloud services\"\n\" please see these `Cloud Interactions code snippets \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/cloud-\"\n\"interactions>`_.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:120 de92d6a4c46143de86751bded4adc336\n#, fuzzy\nmsgid \"Opening Django Files\"\nmsgstr \"C# ファイルを開く\"\n\n#: ../../how-to-open-a-file.rst:122 2a24401c8daf4ec1967ffd20ab41ce1c\nmsgid \"\"\n\"Django implements a `File Storage API \"\n\"<https://docs.djangoproject.com/en/5.1/ref/files/storage/>`_ to store \"\n\"files. The default is the `FileSystemStorage \"\n\"<https://docs.djangoproject.com/en/5.1/ref/files/storage/#the-\"\n\"filesystemstorage-class>`_, but the `django-storages <https://django-\"\n\"storages.readthedocs.io/en/latest/index.html>`_ library provides a number\"\n\" of other storage backends.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:124 ce91bc54879b4e0caad6216633c87800\nmsgid \"\"\n\"You can open the file, move the contents into memory, then pass the \"\n\"contents to |PyMuPDF| as a stream.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:139 619bd327f13f4ed1a9204d62ce0a0e40\nmsgid \"Please note that if the file you open is large, you may run out of memory.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:141 e974ef8989724d7ca39ae4e2f528060d\nmsgid \"\"\n\"The File Storage API works well if you're using different storage \"\n\"backends in different environments. If you're only using the \"\n\"`FileSystemStorage`, you can simply use the `obj.file.name` to open the \"\n\"file directly with |PyMuPDF| as shown in an earlier example.\"\nmsgstr \"\"\n\n#: ../../how-to-open-a-file.rst:149 11fadcb68ef146fc93ca9f4473e140a5\nmsgid \"Opening Files as Text\"\nmsgstr \"ファイルをテキストとして開く\"\n\n#: ../../how-to-open-a-file.rst:152 79658fdcc60c4f62821491708e3874a6\nmsgid \"\"\n\"|PyMuPDF| has the capability to open any plain text file as a document. \"\n\"In order to do this you should provide the `filetype` parameter for the \"\n\"`pymupdf.open` function as `\\\"txt\\\"`.\"\nmsgstr \"\"\n\"|PyMuPDF| には、プレーン テキスト ファイルをドキュメントとして開く機能があります。 これを行うには、`pymupdf.open` \"\n\"関数の `filetype` パラメータを「txt」として指定する必要があります。\"\n\n#: ../../how-to-open-a-file.rst:159 d72a0b8f986843488dfc6ddc257e4f45\nmsgid \"\"\n\"In this way you are able to open a variety of file types and perform the \"\n\"typical **non-PDF** specific features like text searching, text \"\n\"extracting and page rendering. Obviously, once you have rendered your \"\n\"`txt` content, then saving as |PDF| or merging with other |PDF| files is \"\n\"no problem.\"\nmsgstr \"\"\n\"このようにして、さまざまな種類のファイルを開いて、テキスト検索、テキスト抽出、ページ レンダリングなどの |PDF| \"\n\"に固有ではない一般的な機能を実行できます。 明らかに、txt コンテンツをレンダリングしたら、 |PDF| として保存したり、他の |PDF| \"\n\"ファイルと結合したりすることは問題ありません。\"\n\n#: ../../how-to-open-a-file.rst:163 25cb1a49799b43669b7c520e52fc2e46\nmsgid \"Examples\"\nmsgstr \"例\"\n\n#: ../../how-to-open-a-file.rst:167 df4ce47e55a94298b344689b280a64df\nmsgid \"Opening a `C#` file\"\nmsgstr \"C# ファイルを開く\"\n\n#: ../../how-to-open-a-file.rst:176 2f20ca6b671845fca3ae2bceeb25eebd\nmsgid \"Opening an ``XML`` file\"\nmsgstr \"XML ファイルを開く\"\n\n#: ../../how-to-open-a-file.rst:184 1c25e62b57d843c9b5b8122f59295144\nmsgid \"Opening a `JSON` file\"\nmsgstr \"JSON ファイルを開く\"\n\n#: ../../how-to-open-a-file.rst:191 687e69a017bb48b682d8b720ad323f52\nmsgid \"And so on!\"\nmsgstr \"等々！\"\n\n#: ../../how-to-open-a-file.rst:193 f6ae4e85cdb1469bbf04502e1bb02ccd\nmsgid \"\"\n\"As you can imagine many text based file formats can be *very simply \"\n\"opened* and *interpreted* by |PyMuPDF|. This can make data analysis and \"\n\"extraction for a wide range of previously unavailable files possible.\"\nmsgstr \"\"\n\"ご想像のとおり、多くのテキスト ベースのファイル形式は、|PyMuPDF| によって非常に簡単に開いて解釈できます。 \"\n\"これにより、これまで利用できなかった広範囲のファイルのデータ分析と抽出が突然可能になります。\"\n\n#: ../../footer.rst:46 6894d49c24fc4cfa8f9d99a9257edfdf\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"The above creates a :ref:`Document`. The\"\n#~ \" instruction `doc = pymupdf.Document(\\\"a.pdf\\\")`\"\n#~ \" does exactly the same. So, `open`\"\n#~ \" is just a convenient alias  and \"\n#~ \"you can find its full API \"\n#~ \"documented in that chapter.\"\n#~ msgstr \"\"\n\n#~ msgid \"Assume that *\\\"some.file\\\"* is actually an **XPS**. Open it like so:\"\n#~ msgstr \"例えば *\\\"some.file\\\"* が実際には **XPS** ファイルの場合は、以下のようにして開きます：\"\n\n#~ msgid \"\"\n#~ \"|PyMuPDF| itself does not try to \"\n#~ \"determine the file type from the \"\n#~ \"file contents. **You** are responsible \"\n#~ \"for supplying the file type information\"\n#~ \" in some way -- either implicitly,\"\n#~ \" via the file extension, or \"\n#~ \"explicitly as shown with the `filetype`\"\n#~ \" parameter. There are pure :title:`Python`\"\n#~ \" packages like `filetype \"\n#~ \"<https://pypi.org/project/filetype/>`_ that help you\"\n#~ \" doing this. Also consult the \"\n#~ \":ref:`Document` chapter for a full \"\n#~ \"description.\"\n#~ msgstr \"\"\n#~ \"|PyMuPDF| \"\n#~ \"自体は、ファイルの内容からファイルタイプを判断しようとはしません。このため、ユーザーがファイルの拡張子などを通じて暗黙的に、または \"\n#~ \"`filetype <https://pypi.org/project/filetype/>`_ \"\n#~ \"パラメーターを通じて明示的にファイルタイプの情報を提供する責任があります。また、詳細な説明については \"\n#~ \":ref:`Document` の章を参照してください。\"\n\n#~ msgid \"\"\n#~ \"If |PyMuPDF| encounters a file with \"\n#~ \"an unknown / missing extension, it \"\n#~ \"will try to open it as a \"\n#~ \"|PDF|. So in these cases there is\"\n#~ \" no need for additional precautions. \"\n#~ \"Similarly, for memory documents, you can\"\n#~ \" just specify `doc=pymupdf.open(stream=mem_area)` \"\n#~ \"to open it as a |PDF| document.\"\n#~ msgstr \"\"\n#~ \"|PyMuPDF| \"\n#~ \"は不明なファイルや拡張子のないファイルはPDFとして開きます。このため、これらの場合は追加の情報は必要ありません。同様に、メモリ上のドキュメントの場合は、`doc=pymupdf.open(stream=mem_area)`\"\n#~ \" と指定するだけでPDFドキュメントとして開くことができます。\"\n\n#~ msgid \"\"\n#~ \"If you attempt to open an \"\n#~ \"unsupported file then |PyMuPDF| will \"\n#~ \"throw a file data error.\"\n#~ msgstr \"サポートされていないファイルを開こうとした場合、PyMuPDFはファイルデータエラーをスローします。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/identity.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7b37ecd8dc3743a9a786f62dd0bec6f7\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 7dda5857ca604606b110ce5cddbf35fa\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 024f5eebaeb24a6ea2775fd31cbf04c8\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../identity.rst:7 74c7b4d54f2f490aa6411228918d1102\nmsgid \"Identity\"\nmsgstr \"Identity (アイデンティティ)\"\n\n#: ../../identity.rst:9 9eea7980a3264df58d614219614f391d\nmsgid \"\"\n\"Identity is a :ref:`Matrix` that performs no action -- to be used \"\n\"whenever the syntax requires a matrix, but no actual transformation \"\n\"should take place. It has the form *pymupdf.Matrix(1, 0, 0, 1, 0, 0)*.\"\nmsgstr \"\"\n\"アイデンティティは、何もアクションを実行しない :ref:`Matrix` \"\n\"で、構文がマトリックスを必要とするが実際の変換が必要ない場合に使用されます。それは  *pymupdf.Matrix(1, 0, 0, 1, 0,\"\n\" 0)* の形をしています。\"\n\n#: ../../identity.rst:11 cf3f047b3bcd457781d6d1b0a6555a40\nmsgid \"\"\n\"Identity is a constant, an \\\"immutable\\\" object. So, all of its matrix \"\n\"properties are read-only and its methods are disabled.\"\nmsgstr \"アイデンティティは、定数であり、変更できない「不変」のオブジェクトです。そのため、すべてのマトリックスのプロパティは読み取り専用であり、そのメソッドは無効になっています。\"\n\n#: ../../identity.rst:13 0eeb4dcb5f1f4643912b79cb1dc0929a\nmsgid \"\"\n\"If you need a **mutable** identity matrix as a starting point, use one of\"\n\" the following statements::\"\nmsgstr \"**変更可能な** アイデンティティマトリックスが必要な場合、次の文のいずれかを使用してください::\"\n\n#: ../../footer.rst:60 d7eead894067453da2f782c487c8f59e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/index.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../index.rst:33 8fd6f740bd354549b09f02e29d6aeb9f\nmsgid \"About\"\nmsgstr \"\"\n\n#: ../../index.rst:42 325ca6b150394307ad977ddc59e8199c\nmsgid \"User Guide\"\nmsgstr \"ユーザーガイド\"\n\n#: ../../index.rst:54 55f11e9ee1a448aaa422415824a72910\nmsgid \"How to Guide\"\nmsgstr \"使用方法ガイド\"\n\n#: ../../index.rst:61 382947f10dad49e09057aef86f6b7bdf\nmsgid \"API Reference\"\nmsgstr \"APIリファレンス\"\n\n#: ../../index.rst:74 cf7180ed975342a3ad0632f165b96c7b\nmsgid \"Other\"\nmsgstr \"その他\"\n\n#: ../../header.rst:-1 17cdca8041b545be91c717e1482c6e92\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 929d834795de4b6c9c42aede9d848712\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 883d9811455e45eea8d6c2f3434cae01\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../index.rst:20 8cfb3ae729874f858ac4b9e18e20bf6a\nmsgid \"Welcome to |PyMuPDF|\"\nmsgstr \"PyMuPDFへようこそ\"\n\n#: ../../index.rst:22 32ae9730ead142168b8b4abaaef4b7c3\nmsgid \"\"\n\"|PyMuPDF| is a high-performance **Python** library for data extraction, \"\n\"analysis, conversion & manipulation of |PDF| (and other) documents.\"\nmsgstr \"\"\n\"|PyMuPDF| は、|PDF| （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な :title:`Python` \"\n\"ライブラリです。\"\n\n#: ../../index.rst:24 6a8830c4d9b54905a1ec1b90ebb54e90\nmsgid \"\"\n\"|PyMuPDF| is hosted on `GitHub <https://github.com/pymupdf/PyMuPDF>`_ and\"\n\" registered on `PyPI <https://pypi.org/project/PyMuPDF/>`_.\"\nmsgstr \"\"\n\"|PyMuPDF| は  `GitHub <https://github.com/pymupdf/PyMuPDF>`_  でホストされ、`PyPI\"\n\" <https://pypi.org/project/PyMuPDF/>`_ に登録されています。\"\n\n#: ../../footer.rst:60 ../../index.rst:29 11945e0949f341ad9d1670429005389a\n#: ec790aafb26941e99e919f9eba35a52e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Find out about **PyMuPDF Utilities**\"\n#~ msgstr \"PyMuPDF Utilitiesについて詳しく知る\"\n\n#~ msgid \"\"\n#~ \"The :title:`GitHub` repository `PyMuPDF-\"\n#~ \"Utilities <https://github.com/pymupdf/PyMuPDF-Utilities>`_\"\n#~ \" contains a full range of examples,\"\n#~ \" demonstrations and use cases.\"\n#~ msgstr \"\"\n#~ \"GitHubリポジトリ `PyMuPDF-Utilities \"\n#~ \"<https://github.com/pymupdf/PyMuPDF-Utilities>`_ \"\n#~ \"には、さまざまな例、デモンストレーション、およびユースケースが含まれています。\"\n\n#~ msgid \"Do you need |PDF| to **DOCX** conversion?\"\n#~ msgstr \"|PDF| から **DOCX** への変換が必要ですか?\"\n\n#~ msgid \"\"\n#~ \"We recommend the pdf2docx_ library which\"\n#~ \" uses |PyMuPDF| and the **python-\"\n#~ \"docx** library to provide simple \"\n#~ \"document conversion from |PDF| to \"\n#~ \"**DOCX** format.\"\n#~ msgstr \"\"\n#~ \"|PyMuPDF| を使用する pdf2docx_ ライブラリと、|PDF| から \"\n#~ \"**DOCX** 形式への簡単なドキュメント変換を提供する **python-docx** \"\n#~ \"ライブラリをお勧めします。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/installation.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 bc107b9bc1f9411db1b06a2b9a73ce64\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 d7d772a2db0344ea81f7e2d671249a0d\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 3d75e7a13d97463585cb89b8a4cf50e2\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../installation.rst:6 ../../installation.rst:31\n#: 0e5b938092394f76bb79bd60b8b7bcc8 362130f7ee184277a844a2094e73b166\nmsgid \"Installation\"\nmsgstr \"インストール\"\n\n#: ../../installation.rst:9 5756ccf1a8cf47d489d528757b4ff1ed\nmsgid \"Requirements\"\nmsgstr \"要件\"\n\n#: ../../installation.rst:11 59418d8369d141eb9ff64af78a5cd0d1\nmsgid \"\"\n\"All the examples below assume that you are running inside a Python \"\n\"virtual environment. See: https://docs.python.org/3/library/venv.html for\"\n\" details. We also assume that `pip` is up to date.\"\nmsgstr \"\"\n\"以下のすべての例は、Pythonの仮想環境内で実行していると仮定しています。詳細については、https://docs.python.org/3/library/venv.html\"\n\" を参照してください。また、pipが最新であると仮定しています。\"\n\n#: ../../installation.rst:15 c0c567ab87e545dcb02f98a499237cac\nmsgid \"For example:\"\nmsgstr \"例えば:\"\n\n#: ../../installation.rst:17 3566b454695c4d74836795503dc32f88\nmsgid \"Windows::\"\nmsgstr \"\"\n\n#: ../../installation.rst:23 30d9561c3bbd45f79998c3672a481495\nmsgid \"Linux, MacOS::\"\nmsgstr \"\"\n\n#: ../../installation.rst:33 a214d3639973479385b1f7fb97f49eb2\n#, fuzzy\nmsgid \"|PyMuPDF| should be installed using pip with::\"\nmsgstr \"PyMuPDFをインストールするには、次のようにpipを使用してください::\"\n\n#: ../../installation.rst:37 ea5698bf08544d95ab4dfd879681ba77\nmsgid \"\"\n\"This will install from a Python wheel if one is available for your \"\n\"platform.\"\nmsgstr \"この方法でインストールすると、対象のプラットフォームに対応するPythonのwheelファイルがある場合は、それを使用してインストールされます。\"\n\n#: ../../installation.rst:41 41710c287f054c699809c8bb0c6be619\nmsgid \"Installation when a suitable wheel is not available\"\nmsgstr \"適切なwheelファイルが利用できない場合のインストール方法\"\n\n#: ../../installation.rst:43 edcf8eac64af49bb9cbe25cbe7de7c5a\nmsgid \"\"\n\"If a suitable Python wheel is not available, pip will automatically build\"\n\" from source using a Python sdist.\"\nmsgstr \"適切なPythonのwheelファイルが利用できない場合、pipは自動的にPythonのsdistからビルドします。\"\n\n#: ../../installation.rst:46 10c33b59ba9e4c868ae010f2a7028814\nmsgid \"**This requires C/C++ development tools to be installed**:\"\nmsgstr \"**これにはC/C++の開発ツールがインストールされている必要があります：**\"\n\n#: ../../installation.rst:48 5ad6beabf5d6474dab9c471133784cb8\nmsgid \"On Windows:\"\nmsgstr \"Windowsの場合:\"\n\n#: ../../installation.rst:51 c850480032484111ad409c8a6d7cc794\nmsgid \"\"\n\"Install Visual Studio 2019. If not installed in a standard location, set \"\n\"environmental variable `PYMUPDF_SETUP_DEVENV` to the location of the \"\n\"`devenv.com` binary.\"\nmsgstr \"\"\n\"Visual Studio 2019をインストールしてください。標準の場所にインストールされていない場合は、環境変数 \"\n\"`PYMUPDF_SETUP_DEVENV` を `devenv.com` バイナリの場所に設定してください\"\n\n#: ../../installation.rst:56 65947958187d45018d139034858bc083\nmsgid \"\"\n\"Having other installed versions of Visual Studio, for example Visual \"\n\"Studio 2022, can cause problems because one can end up with MuPDF and \"\n\"PyMuPDF code being compiled with different compiler versions.\"\nmsgstr \"\"\n\"他のバージョンのVisual Studio（例：Visual Studio \"\n\"2022）がインストールされている場合、異なるコンパイラバージョンでMuPDFとPyMuPDFのコードがコンパイルされる可能性があるため、問題が発生することがあります。\"\n\n#: ../../installation.rst:60 9e448ffec0c64a40968de3839f6b2855\nmsgid \"The build will automatically download and build MuPDF.\"\nmsgstr \"自動的にMuPDFをダウンロードしてビルドします。\"\n\n#: ../../installation.rst:66 9ea3e134885d4f05a4c3e2a4f5bc1095\nmsgid \"Problems after installation\"\nmsgstr \"インストール後の問題\"\n\n#: ../../installation.rst:68 ../../installation.rst:117\n#: 0d4df66268c544a69e1dba24527b39dc da5b4f00d11844939c6ba2c50436cde5\nmsgid \"On Windows, Python error::\"\nmsgstr \"\"\n\n#: ../../installation.rst:72 05623aa04f7948f1928a5424140c8d9d\nmsgid \"\"\n\"This has been occasionally seen if `MSVCP140.dll` is missing, and appears\"\n\" to be caused by a bug in some versions (2015-2017) of `Microsoft Visual \"\n\"C++ Redistributables`.\"\nmsgstr \"\"\n\"これは、`MSVCP140.dll` が見つからない場合に時折発生し、`Microsoft Visual C++` \"\n\"再頒布可能パッケージの一部のバージョン (2015 ～ 2017) のバグが原因であると思われます。\"\n\n#: ../../installation.rst:76 9472b21821c84665a04e27961520861f\nmsgid \"\"\n\"It is recommended to search for `MSVCP140.dll` in https://msdn.com to \"\n\"find instructions for how to reinstall it. For example \"\n\"https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist has \"\n\"permalinks to the latest supported versions.\"\nmsgstr \"\"\n\"https://msdn.com で `MSVCP140.dll` を検索して、再インストールする方法の手順を見つけることをお勧めします。 \"\n\"たとえば、https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist \"\n\"には、サポートされている最新バージョンへのパーマリンクがあります。\"\n\n#: ../../installation.rst:81 3007dd23091741939a53721b7d628b74\nmsgid \"See https://github.com/pymupdf/PyMuPDF/issues/2678 for more details.\"\nmsgstr \"詳細については、https://github.com/pymupdf/PyMuPDF/issues/2678 を参照してください。\"\n\n#: ../../installation.rst:84 c9a39b500d3d45a1b18d1c3f00c2982e\nmsgid \"Python error::\"\nmsgstr \"\"\n\n#: ../../installation.rst:88 53589cbbfa6944378c7034ed948fa3b4\nmsgid \"\"\n\"This can happen if PyMuPDF's legacy name `fitz` is used (for example \"\n\"`import fitz` instead of `import pymupdf`), and an unrelated Python \"\n\"package called `fitz` (https://pypi.org/project/fitz/) is installed.\"\nmsgstr \"\"\n\n#: ../../installation.rst:92 f32677d324ec471f8b25f4becffc62f5\nmsgid \"\"\n\"The fitz package appears to be no longer maintained (the latest release \"\n\"is from 2017), but unfortunately it does not seem possible to remove it \"\n\"from pypi.org. It does not even work on its own, as well as breaking the \"\n\"use of PyMuPDF's legacy name.\"\nmsgstr \"\"\n\n#: ../../installation.rst:97 31c58415e64d4285b88f8e33a6d97802\nmsgid \"There are a few ways to avoid this problem:\"\nmsgstr \"\"\n\n#: ../../installation.rst:100 3f88b66501a544699823982b2254031f\nmsgid \"\"\n\"Use `import pymupdf` instead of `import fitz`, and update one's code to \"\n\"match.\"\nmsgstr \"\"\n\n#: ../../installation.rst:103 eb2fe6e966f44853b6678fc67361a0c0\nmsgid \"Or uninstall the `fitz` package and reinstall PyMuPDF::\"\nmsgstr \"\"\n\n#: ../../installation.rst:108 f733312e30d5442d8681d28dfc2e0418\nmsgid \"Or use `import pymupdf as fitz`. However this has not been well tested.\"\nmsgstr \"\"\n\n#: ../../installation.rst:110 d2942ed579c547888ca1290602ed28cc\nmsgid \"With Jupyter labs on Apple Silicon (arm64), Python error::\"\nmsgstr \"\"\n\n#: ../../installation.rst:114 3dedae1d6af9447eb2192ed96052aa90\nmsgid \"\"\n\"This appears to be a problem in Jupyter labs; see: \"\n\"https://github.com/pymupdf/PyMuPDF/issues/3643#issuecomment-2210588778.\"\nmsgstr \"\"\n\n#: ../../installation.rst:121 7bd3b3ebec5f4f07900684f56429ad36\nmsgid \"\"\n\"This was reported 2025-03-26 in \"\n\"https://github.com/pymupdf/PyMuPDF/issues/4405.\"\nmsgstr \"\"\n\n#: ../../installation.rst:123 b6139c99d78e45a6a9105ecc8404f710\nmsgid \"The fix appears to be to install the latest `VC_redist.x64.exe`.\"\nmsgstr \"\"\n\n#: ../../installation.rst:127 bccf958282944bd4ac99d1ccf70707d4\nmsgid \"Notes\"\nmsgstr \"メモ\"\n\n#: ../../installation.rst:130 61583f96dcfd4261a2c77d364470a2ac\nmsgid \"Wheels are available for the following platforms:\"\nmsgstr \"\"\n\n#: ../../installation.rst:132 182364ca9ac94666825e7076e6d26a82\nmsgid \"Windows 32-bit Intel.\"\nmsgstr \"\"\n\n#: ../../installation.rst:133 005535b4e858480eb22fb9ed70cd49fe\nmsgid \"Windows 64-bit Intel.\"\nmsgstr \"\"\n\n#: ../../installation.rst:134 7687fad16e9e41379221c5187c01a9f6\nmsgid \"Linux 64-bit Intel.\"\nmsgstr \"\"\n\n#: ../../installation.rst:135 e8bae64d60a44c078ddab450469e771d\nmsgid \"Linux 64-bit ARM.\"\nmsgstr \"\"\n\n#: ../../installation.rst:136 2064ef5679e64d3db0b45c1dfbdff952\nmsgid \"MacOS 64-bit Intel.\"\nmsgstr \"\"\n\n#: ../../installation.rst:137 2190d152d5d0476b86a7e483d9bf4e00\nmsgid \"MacOS 64-bit ARM.\"\nmsgstr \"\"\n\n#: ../../installation.rst:139 5ba4832bb0ca40c3a6f960f5b5665e84\nmsgid \"Details:\"\nmsgstr \"\"\n\n#: ../../installation.rst:141 41c9bfb953b447c484a012628de54f36\nmsgid \"We release a single wheel for each of the above platforms.\"\nmsgstr \"\"\n\n#: ../../installation.rst:144 8cf71ef8029a4d07ada650d699bfd1fc\nmsgid \"\"\n\"Each wheel uses the Python Stable ABI of the current oldest supported \"\n\"Python version (currently 3.10), and so works with all later Python \"\n\"versions, including new Python releases.\"\nmsgstr \"\"\n\n#: ../../installation.rst:149 85f0cb2340464eacb0b93de71ce3a42b\nmsgid \"\"\n\"Wheels are tested on all Python versions currently marked as \"\n\"\\\"Supported\\\" on https://devguide.python.org/versions/, currently \"\n\"|python_versions|.\"\nmsgstr \"\"\n\n#: ../../installation.rst:153 b10deebc967f4ab8bdb0f24ad98ed832\nmsgid \"\"\n\"Wheels are not available for Python installed with `Chocolatey \"\n\"<https://chocolatey.org/>`_ on Windows. Instead install Python using the \"\n\"Windows installer from the python.org website, see: \"\n\"http://www.python.org/downloads\"\nmsgstr \"\"\n\"`Chocolatey <https://chocolatey.org/>`_ \"\n\"を使用してWindowsにインストールされたPythonには、ホイールが利用できません。代わりに、python.orgのウェブサイトからWindowsインストーラーを使用してPythonをインストールしてください。詳細は、以下を参照してください：http://www.python.org/downloads\"\n\n#: ../../installation.rst:159 624bcf09993d4be0ae0f8a75b8353859\nmsgid \"\"\n\"Wheels are not available for Linux-aarch64 with `Musl libc \"\n\"<https://musl.libc.org/>`_ (For example `Alpine Linux \"\n\"<https://alpinelinux.org/>`_ on aarch64), and building from source is \"\n\"known to fail.\"\nmsgstr \"\"\n\n#: ../../installation.rst:164 efeb850ab27c435e9bdc7b4bfcce4292\nmsgid \"\"\n\"There are no **mandatory** external dependencies. However, some optional \"\n\"feature are available only if additional components are installed:\"\nmsgstr \"必須の外部依存関係はありません。ただし、追加のコンポーネントをインストールした場合にのみ、一部のオプション機能が利用可能です：\"\n\n#: ../../installation.rst:166 112f6dc0117840bb96de1ccb40383a6e\nmsgid \"\"\n\"`Pillow <https://pypi.org/project/Pillow/>`_ is required for \"\n\":meth:`Pixmap.pil_save` and :meth:`Pixmap.pil_tobytes`.\"\nmsgstr \"\"\n\"`Pillow <https://pypi.org/project/Pillow/>`_ は :meth:`Pixmap.pil_save` と \"\n\":meth:`Pixmap.pil_tobytes` の実行に必要です。\"\n\n#: ../../installation.rst:167 1ee77df6b8b94e6798a002846af1766e\nmsgid \"\"\n\"`fontTools <https://pypi.org/project/fonttools/>`_ is required for \"\n\":meth:`Document.subset_fonts`.\"\nmsgstr \"\"\n\"`fontTools <https://pypi.org/project/fonttools/>`_ は \"\n\":meth:`Document.subset_fonts` の実行に必要です。\"\n\n#: ../../installation.rst:168 28cbd6c15f344131b911099e680559b0\nmsgid \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ is a \"\n\"collection of nice fonts to be used for text output methods.\"\nmsgstr \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ \"\n\"は、テキスト出力の方法に使用するための素敵なフォントのコレクションです。\"\n\n#: ../../installation.rst:170 4e52c3cf248c4abcb79594a420fd423f\nmsgid \"\"\n\"`Tesseract-OCR <https://github.com/tesseract-ocr/tesseract>`_ for optical\"\n\" character recognition in images and document pages. Tesseract is \"\n\"separate software, not a Python package. To enable OCR functions in \"\n\"PyMuPDF, Tesseract must be installed and the `tessdata` folder name \"\n\"specified; see below.\"\nmsgstr \"\"\n\n#: ../../installation.rst:176 c26a998174ff490b98bd7883858b8b37\nmsgid \"\"\n\"You can install these additional components at any time -- before or \"\n\"after installing PyMuPDF. PyMuPDF will detect their presence during \"\n\"import or when the respective functions are being used.\"\nmsgstr \"これらの追加コンポーネントはいつでもインストールできます。PyMuPDFのインストール前または後に行うことができます。PyMuPDFは、これらのコンポーネントがインポート時または対応する機能が使用される際に検出します。\"\n\n#: ../../installation.rst:180 06f197dc89334f00b8fde2aa343e6a2f\nmsgid \"Build and install from a local PyMuPDF source tree\"\nmsgstr \"ローカルのPyMuPDFソースツリーからビルドしてインストールします\"\n\n#: ../../installation.rst:182 a5b05e1ca807403ba4f04f8b040f4089\nmsgid \"Initial setup:\"\nmsgstr \"初期設定：\"\n\n#: ../../installation.rst:184 6544cbacb1694401940667fbf45ebbe0\nmsgid \"Install C/C++ development tools as described above.\"\nmsgstr \"上記に記載されているように、C/C++の開発ツールをインストールしてください。\"\n\n#: ../../installation.rst:185 0645317ab66746168a76c49a26e93d39\nmsgid \"Enter a Python venv and update pip, as described above.\"\nmsgstr \"上記に記載されているように、Pythonのvenvに入り、pipをアップデートしてください。\"\n\n#: ../../installation.rst:187 82271eef944e4faf817e14c489cd2c16\nmsgid \"Get a PyMuPDF source tree:\"\nmsgstr \"PyMuPDFのソースツリーを取得します：\"\n\n#: ../../installation.rst:189 3c67a60c157048679a1dafd0e6abe5fb\nmsgid \"Clone the PyMuPDF git repository::\"\nmsgstr \"PyMuPDFのGitリポジトリをクローンしてください::\"\n\n#: ../../installation.rst:194 7b0c1e0a13d44979ab25c04feb345ad1\nmsgid \"\"\n\"Or download and extract a `.zip` or `.tar.gz` source release from \"\n\"https://github.com/pymupdf/PyMuPDF/releases.\"\nmsgstr \"\"\n\"または、https://github.com/pymupdf/PyMuPDF/releases から `.zip` または `.tar.gz` \"\n\"形式のソースリリースをダウンロードして展開してください。\"\n\n#: ../../installation.rst:197 9edcc8838b654d3a9e1882ee8edefa4c\nmsgid \"Then one can build PyMuPDF in two ways:\"\nmsgstr \"PyMuPDFを2つの方法でビルドできます：\"\n\n#: ../../installation.rst:199 575e45b815c94f7cad04f1b45e7c3d7f\nmsgid \"Build and install PyMuPDF with default MuPDF version::\"\nmsgstr \"デフォルトのMuPDFバージョンでPyMuPDFをビルドしてインストール::\"\n\n#: ../../installation.rst:203 bb7099833f204ff3829afd0cd54324cf\nmsgid \"\"\n\"This will automatically download a specific hard-coded MuPDF source \"\n\"release, and build it into PyMuPDF.\"\nmsgstr \"これにより、特定のハードコードされたMuPDFソースリリースが自動的にダウンロードされ、PyMuPDFにビルドされます。\"\n\n#: ../../installation.rst:206 86e76ec90c1c4d7a89dcb112d69ccbba\nmsgid \"Or build and install PyMuPDF using a local MuPDF source tree:\"\nmsgstr \"または、ローカルのMuPDFソースツリーを使用してPyMuPDFをビルドしてインストールします：\"\n\n#: ../../installation.rst:208 b9853c693d1f49358428f38af93edc33\nmsgid \"Clone the MuPDF git repository::\"\nmsgstr \"MuPDFのGitリポジトリをクローンします：\"\n\n#: ../../installation.rst:213 854b5ebfeb9847efb51d37d0f3e4c259\nmsgid \"\"\n\"Build PyMuPDF, specifying the location of the local MuPDF tree with the \"\n\"environmental variables `PYMUPDF_SETUP_MUPDF_BUILD`::\"\nmsgstr \"\"\n\"環境変数 `PYMUPDF_SETUP_MUPDF_BUILD` を使用して、ローカルな MuPDF ツリーの場所を指定して PyMuPDF \"\n\"をビルドします::\"\n\n#: ../../installation.rst:218 24b5cda1241e4f36b5aaf31c8df91447\nmsgid \"\"\n\"Also, one can build for different Python versions in the same PyMuPDF \"\n\"tree:\"\nmsgstr \"同じPyMuPDFツリー内で異なるPythonバージョン用にビルドする方法：\"\n\n#: ../../installation.rst:221 fc0b1a2699064aaaa377451775502e20\nmsgid \"\"\n\"PyMuPDF will build for the version of Python that is being used to run \"\n\"`pip`. To run `pip` with a specific Python version, use `python -m pip` \"\n\"instead of `pip`.\"\nmsgstr \"\"\n\"PyMuPDF は、`pip` を実行する Python のバージョンに対応してビルドされます。特定の Python バージョンで pip \"\n\"を実行するには、`pip` の代わりに `python -m pip` を使用してください。\"\n\n#: ../../installation.rst:225 dd80aa73dedb4313a237f8c77a2d783d\nmsgid \"So for example on Windows one can build different versions with::\"\nmsgstr \"したがって、Windows 上で異なるバージョンをビルドする場合、次のようにできます::\"\n\n#: ../../installation.rst:229 4fbc355486c04e7fb88bcdd8ffae7059\nmsgid \"or::\"\nmsgstr \"または::\"\n\n#: ../../installation.rst:235 207c24c76f364447839aefe03523527b\nmsgid \"Running tests\"\nmsgstr \"テストの実行\"\n\n#: ../../installation.rst:237 052b595cbe1448d79c441e326e94f9d7\nmsgid \"\"\n\"Having a PyMuPDF tree available allows one to run PyMuPDF's `pytest` test\"\n\" suite::\"\nmsgstr \"PyMuPDFのディレクトリが利用可能な場合、PyMuPDFの `pytest` テストスイートを実行できます。::\"\n\n#: ../../installation.rst:246 795e4545d04f4e04baa8a0527281f16e\nmsgid \"Notes about using a non-default MuPDF\"\nmsgstr \"非デフォルトのMuPDFを使用する際の注意事項\"\n\n#: ../../installation.rst:248 9a130c5a8a0946668b8885f28af8aa04\nmsgid \"\"\n\"Using a non-default build of MuPDF by setting environmental variable \"\n\"`PYMUPDF_SETUP_MUPDF_BUILD` can cause various things to go wrong and so \"\n\"is not generally supported:\"\nmsgstr \"\"\n\"環境変数 `PYMUPDF_SETUP_MUPDF_BUILD` \"\n\"を設定して非デフォルトのMuPDFビルドを使用すると、さまざまな問題が発生する可能性があるため、一般的にはサポートされていません。\"\n\n#: ../../installation.rst:252 79b112fde2cc4475bbef94325d535a3d\nmsgid \"\"\n\"If MuPDF's major version number differs from what PyMuPDF uses by \"\n\"default, PyMuPDF can fail to build, because MuPDF's API can change \"\n\"between major versions.\"\nmsgstr \"もしMuPDFのメジャーバージョン番号がPyMuPDFがデフォルトで使用するものと異なる場合、PyMuPDFはビルドに失敗する可能性があります。なぜなら、MuPDFのAPIはメジャーバージョン間で変更されることがあるからです。\"\n\n#: ../../installation.rst:256 26963aaabb354a0fb893981e3cd6b8d0\nmsgid \"\"\n\"Runtime behaviour of PyMuPDF can change because MuPDF's runtime behaviour\"\n\" changes between different minor releases. This can also break some \"\n\"PyMuPDF tests.\"\nmsgstr \"PyMuPDFのランタイム動作は、異なるマイナーリリース間でMuPDFのランタイム動作が変更されるため、変わる可能性があります。これは一部のPyMuPDFのテストにも影響を及ぼすことがあります。\"\n\n#: ../../installation.rst:260 cf6ea4f83bfa409381276082a6a8bdf9\nmsgid \"\"\n\"If MuPDF was built with its default config instead of PyMuPDF's \"\n\"customised config (for example if MuPDF is a system install), it is \"\n\"possible that `tests/test_textbox.py:test_textbox3()` will fail. One can \"\n\"skip this particular test by adding `-k 'not test_textbox3'` to the \"\n\"`pytest` command line.\"\nmsgstr \"\"\n\"MuPDFがPyMuPDFのカスタマイズされた設定ではなく、デフォルトの設定でビルドされた場合（たとえば、MuPDFがシステムにインストールされた場合）、`tests/test_textbox.py:test_textbox3()`\"\n\" が失敗する可能性があります。この特定のテストをスキップするには、`pytest` コマンドラインに `-k 'not \"\n\"test_textbox3'` を追加してください。\"\n\n#: ../../installation.rst:268 700f4d8e58e84935b6c6975860df3b8f\nmsgid \"Official PyMuPDF Linux wheels may not install on older Linux systems\"\nmsgstr \"\"\n\n#: ../../installation.rst:270 b47547ab827c4869a01099c6505cf69a\nmsgid \"Releases of PyMuPDF are incompatible with older Linux systems.\"\nmsgstr \"\"\n\n#: ../../installation.rst:272 808eb6388cc546d782e08fad72571c1d\nmsgid \"\"\n\"For example as of 2025-09-03, `pip install pymupdf` does not work on some\"\n\" AWS Lambda systems - see \"\n\"https://github.com/pymupdf/PyMuPDF/discussions/4631.\"\nmsgstr \"\"\n\n#: ../../installation.rst:275 debea54d4d7a43c2878628b326c0c3f0\nmsgid \"\"\n\"This is because official PyMuPDF Linux wheels are built with a version of\"\n\" glibc determined by the current Python manylinux environment. These \"\n\"wheels are incompatible with Linux systems that have an older glibc.\"\nmsgstr \"\"\n\n#: ../../installation.rst:279 bf75483c6b084df08b1cc5bd8206d1bf\nmsgid \"\"\n\"The official Python manylinux environment is updated periodically to use \"\n\"newer glibc versions, so new releases of PyMuPDF become increasingly \"\n\"incompatible with older Linux systems.\"\nmsgstr \"\"\n\n#: ../../installation.rst:283 91117ed642e046819ecc665f9b6c9b50\nmsgid \"\"\n\"There is nothing that can be done about this, other than updating older \"\n\"Linux systems, or building PyMuPDF locally from source.\"\nmsgstr \"\"\n\n#: ../../installation.rst:286 e7b222da2a044c2fa1eedf9c819d97ca\nmsgid \"\"\n\"For more details, please see: `Python Packaging Authority \"\n\"<https://www.pypa.io>`_.\"\nmsgstr \"\"\n\n#: ../../installation.rst:290 4adbb8931dfd4590a44a57ffb3936e97\nmsgid \"Packaging\"\nmsgstr \"パッケージング\"\n\n#: ../../installation.rst:292 53c33343b4c24290ad643762f5bbb050\nmsgid \"See :doc:`packaging`.\"\nmsgstr \":doc:`packaging` を参照してください。\"\n\n#: ../../installation.rst:296 477e709115dd4d119aea37fb3a68a54b\nmsgid \"Using with Pyodide\"\nmsgstr \"Pyodideとの使用\"\n\n#: ../../installation.rst:298 28b8424d39f448fd863709fd16271d9a\nmsgid \"See :doc:`pyodide`.\"\nmsgstr \":doc:`pyodide` を参照してください。\"\n\n#: ../../installation.rst:304 05d1ad76d8ff49d8b8be1c318e026ccb\nmsgid \"Enabling Integrated OCR Support\"\nmsgstr \"統合OCRサポートの有効化\"\n\n#: ../../installation.rst:306 1088128a9ea343a09d2433086fcee140\nmsgid \"\"\n\"If you do not intend to use this feature, skip this step. Otherwise, it \"\n\"is required for both installation paths: **from wheels and from \"\n\"sources.**\"\nmsgstr \"\"\n\"もしこの機能を使用しない場合は、このステップをスキップしてください。それ以外の場合は、**ホイールからのインストールとソースからのインストールの両方**\"\n\" に必要です。\"\n\n#: ../../installation.rst:308 18290d46b0854568b242288afd51a0da\nmsgid \"\"\n\"PyMuPDF will already contain all the logic to support OCR functions. But \"\n\"it additionally does need `Tesseract’s language support data \"\n\"<https://github.com/tesseract-ocr/tessdata>`_.\"\nmsgstr \"\"\n\"PyMuPDFにはすでにOCR機能をサポートするためのロジックが含まれていますが、追加でTesseractの言語サポートデータが必要です。そのため\"\n\"、Tesseract-OCRのインストールが依然として必要です。\"\n\n#: ../../installation.rst:310 0cbfeba7ee2e4382baa33ea4562e36c3\nmsgid \"\"\n\"If not specified explicitly, PyMuPDF will attempt to find the installed \"\n\"Tesseract's tessdata, but this should probably not be relied upon.\"\nmsgstr \"\"\n\n#: ../../installation.rst:313 340c284211c64d04a0a7705bbaed97a1\nmsgid \"\"\n\"Otherwise PyMuPDF requires that Tesseract's language support folder is \"\n\"specified explicitly either in PyMuPDF OCR functions' `tessdata` \"\n\"arguments or `os.environ[\\\"TESSDATA_PREFIX\\\"]`.\"\nmsgstr \"\"\n\n#: ../../installation.rst:317 4050e5d26f8d4fcebd4429bf4468f2c1\nmsgid \"So for a working OCR functionality, make sure to complete this checklist:\"\nmsgstr \"OCR機能を正常に動作させるために、以下のチェックリストを完了してください：\"\n\n#: ../../installation.rst:319 ae04b692262d427da4c557773bbb6331\nmsgid \"\"\n\"Locate Tesseract's language support folder. Typically you will find it \"\n\"here:\"\nmsgstr \"Tesseractの言語サポートフォルダを見つけてください。通常、以下の場所にあります：\"\n\n#: ../../installation.rst:321 518b279edc7f426199e22b43bb47488e\nmsgid \"Windows: `C:/Program Files/Tesseract-OCR/tessdata`\"\nmsgstr \"\"\n\n#: ../../installation.rst:322 2829c0e448b44e639344346371835824\nmsgid \"Unix systems: `/usr/share/tesseract-ocr/4.00/tessdata`\"\nmsgstr \"Unixシステム: `/usr/share/tesseract-ocr/4.00/tessdata`\"\n\n#: ../../installation.rst:324 d8669511863246a096ce609ebddc096b\nmsgid \"Specify the language support folder when calling PyMuPDF OCR functions:\"\nmsgstr \"\"\n\n#: ../../installation.rst:326 2defdb35431444ab8cb2a6832cb3cc88\nmsgid \"Set the `tessdata` argument.\"\nmsgstr \"\"\n\n#: ../../installation.rst:327 eda39b64a6ca464d8c23f1eeec197a8f\nmsgid \"Or set `os.environ[\\\"TESSDATA_PREFIX\\\"]` from within Python.\"\nmsgstr \"\"\n\n#: ../../installation.rst:328 d711c5765afc4c0cafadc80892c613e9\nmsgid \"\"\n\"Or set environment variable `TESSDATA_PREFIX` before running Python, for \"\n\"example:\"\nmsgstr \"\"\n\n#: ../../installation.rst:330 adb02ed301f749c0b70fa768f6279980\nmsgid \"\"\n\"Windows: `setx TESSDATA_PREFIX \\\"C:/Program Files/Tesseract-\"\n\"OCR/tessdata\\\"`\"\nmsgstr \"\"\n\n#: ../../installation.rst:331 a7d44e96bab64a1492085fe6649aa5ba\nmsgid \"\"\n\"Unix systems: `declare -x TESSDATA_PREFIX=/usr/share/tesseract-\"\n\"ocr/4.00/tessdata`\"\nmsgstr \"\"\n\"Unixシステム: `declare -x TESSDATA_PREFIX=/usr/share/tesseract-\"\n\"ocr/4.00/tessdata`\"\n\n#: ../../footer.rst:46 04ec8ea4e7e743ab9f77de31a752358a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"On Unix-style systems such as \"\n#~ \"Linux, OpenBSD and FreeBSD, use the \"\n#~ \"system package manager to install SWIG.\"\n#~ msgstr \"Unixスタイルのシステム（Linux、OpenBSD、FreeBSDなど）では、SWIGをインストールするにはシステムのパッケージマネージャを使用してください。\"\n\n#~ msgid \"For example on Debian Linux, do: `sudo apt install swig`\"\n#~ msgstr \"例えば、Debian Linuxの場合は、次のようにしてください： `sudo apt install swig`\"\n\n#~ msgid \"\"\n#~ \"Install SWIG by following the \"\n#~ \"instructions at: \"\n#~ \"https://swig.org/Doc4.0/Windows.html#Windows_installation\"\n#~ msgstr \"以下の指示に従って、SWIGをインストールしてください：https://swig.org/Doc4.0/Windows.html#Windows_installation\"\n\n#~ msgid \"\"\n#~ \"On MacOS, install MacPorts using the \"\n#~ \"instructions at: https://www.macports.org/install.php\"\n#~ msgstr \"MacOSでMacPortsをインストールする場合は、以下の指示に従ってください：https://www.macports.org/install.php\"\n\n#~ msgid \"Then install SWIG with: `sudo port install swig`\"\n#~ msgstr \"その後、以下のコマンドを使用してSWIGをインストールしてください： `sudo port install swig`\"\n\n#~ msgid \"You may also need: `sudo port install swig-python`\"\n#~ msgstr \"以下も必要になるかもしれません： `sudo port install swig-python`\"\n\n#~ msgid \"Installation from source without using an sdist\"\n#~ msgstr \"sdistを使用せずにソースからインストールする方法\"\n\n#~ msgid \"\"\n#~ \"Clone the git repository at \"\n#~ \"https://github.com/pymupdf/PyMuPDF, for example::\"\n#~ msgstr \"https://github.com/pymupdf/PyMuPDF から git リポジトリをクローンしてください\"\n\n#~ msgid \"\"\n#~ \"PyMuPDF will build for the version \"\n#~ \"of Python that runs `setup.py`. So \"\n#~ \"for example on Windows one can \"\n#~ \"build different versions by using `py\"\n#~ \" -3.9` or `py -3.10-32`.\"\n#~ msgstr \"\"\n#~ \"PyMuPDFは、`setup.py` \"\n#~ \"を実行するPythonのバージョンにビルドされます。したがって、例えばWindowsで異なるバージョンをビルドする場合、`py \"\n#~ \"-3.9` や `py -3.10-32` を使用することができます。\"\n\n#~ msgid \"Building and testing with git checkouts of PyMuPDF and MuPDF\"\n#~ msgstr \"PyMuPDFとMuPDFのgitチェックアウトを使ってビルドとテストを行う\"\n\n#~ msgid \"Things to do:\"\n#~ msgstr \"やるべきこと：\"\n\n#~ msgid \"Get PyMuPDF.\"\n#~ msgstr \"PyMuPDFを取得する。\"\n\n#~ msgid \"Get MuPDF.\"\n#~ msgstr \"MuPDFを取得する。\"\n\n#~ msgid \"Create a Python virtual environment.\"\n#~ msgstr \"Pythonの仮想環境を作成する。\"\n\n#~ msgid \"\"\n#~ \"Build PyMuPDF with environmental variable \"\n#~ \"`PYMUPDF_SETUP_MUPDF_BUILD` set to the path\"\n#~ \" of the local MuPDF checkout.\"\n#~ msgstr \"\"\n#~ \"`PYMUPDF_SETUP_MUPDF_BUILD` \"\n#~ \"環境変数をローカルのMuPDFチェックアウトのパスに設定して、PyMuPDFをビルドする。\"\n\n#~ msgid \"Run PyMuPDF tests.\"\n#~ msgstr \"PyMuPDFのテストを実行する。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Wheels are available for Windows (32-bit\"\n#~ \" Intel, 64-bit Intel), Linux (64-bit \"\n#~ \"Intel, 64-bit ARM) and Mac OSX \"\n#~ \"(64-bit Intel, 64-bit ARM), Python \"\n#~ \"versions 3.7 and up.\"\n#~ msgstr \"\"\n#~ \"Windows（32ビットIntel、64ビットIntel）、Linux（64ビットIntel、64ビットARM）、およびMac \"\n#~ \"OSX（64ビットIntel、64ビットARM）用のホイールが利用可能で、Pythonバージョン3.7以上に対応しています。\"\n\n#~ msgid \"Install Tesseract.\"\n#~ msgstr \"Tesseractをインストールしてください\"\n\n#~ msgid \"\"\n#~ \"As of `PyMuPDF-1.20.0`, the required \"\n#~ \"MuPDF source code is already in \"\n#~ \"the sdist and is automatically built \"\n#~ \"into PyMuPDF.\"\n#~ msgstr \"`PyMuPDF-1.20.0` 現在、必要なMuPDFのソースコードがsdistに含まれており、自動的にPyMuPDFに組み込まれています。\"\n\n#~ msgid \"\"\n#~ \"Build and install from local PyMuPDF \"\n#~ \"checkout and optional local MuPDF \"\n#~ \"checkout\"\n#~ msgstr \"ローカルの PyMuPDF チェックアウトとオプションのローカル MuPDF チェックアウトからビルドしてインストールします。\"\n\n#~ msgid \"Build and install PyMuPDF::\"\n#~ msgstr \"PyMuPDFをビルドしてインストールしてください::\"\n\n#~ msgid \"\"\n#~ \"When running Python scripts that use \"\n#~ \"PyMuPDF, make sure that the current \"\n#~ \"directory is not the `PyMuPDF/` \"\n#~ \"directory.\"\n#~ msgstr \"\"\n#~ \"PyMuPDFを使用するPythonスクリプトを実行する際は、現在のディレクトリが `PyMuPDF/` \"\n#~ \"ディレクトリでないことを確認してください。\"\n\n#~ msgid \"\"\n#~ \"Otherwise, confusingly, Python will attempt\"\n#~ \" to import `fitz` from the local \"\n#~ \"`fitz/` directory, which will fail \"\n#~ \"because it only contains source files.\"\n#~ msgstr \"\"\n#~ \"そうでない場合、Pythonは混乱する可能性があります。Pythonはローカルの `fitz/` ディレクトリから\"\n#~ \" `fitz` をインポートしようとしますが、それはソースファイルのみを含んでいるため、失敗します。\"\n\n#~ msgid \"On Windows `ImportError: DLL load failed while importing _fitz`.\"\n#~ msgstr \"Windowsの場合: `ImportError: DLL load failed while importing _fitz`.\"\n\n#~ msgid \"\"\n#~ \"Wheels are available for Windows (32-bit\"\n#~ \" Intel, 64-bit Intel), Linux (64-bit \"\n#~ \"Intel, 64-bit ARM) and Mac OSX \"\n#~ \"(64-bit Intel, 64-bit ARM), for Python\"\n#~ \" versions marked as \\\"Supported\\\" on \"\n#~ \"https://devguide.python.org/versions/.\"\n#~ msgstr \"\"\n#~ \"ホイールは、Windows向けには（32ビットIntel、64ビットIntel）、Linux向けには（64ビットIntel、64ビットARM）、およびMac\"\n#~ \" OSX向けには（64ビットIntel、64ビットARM）提供されています。 \"\n#~ \"Pythonのバージョンは、「https://devguide.python.org/versions/」で「サポートされている」とマークされています。\"\n\n#~ msgid \"\"\n#~ \"PyMuPDF does not support Python versions\"\n#~ \" prior to 3.8. Older wheels can \"\n#~ \"be found in `this <https://github.com/pymupdf\"\n#~ \"/PyMuPDF-Optional-Material/tree/master/wheels-upto-\"\n#~ \"Py3.5>`_ repository and on `PyPI \"\n#~ \"<https://pypi.org/project/PyMuPDF/>`_.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Please note that we generally follow \"\n#~ \"the official Python release schedules. \"\n#~ \"For Python versions dropping out of \"\n#~ \"official support this means, that \"\n#~ \"generation of wheels will also be \"\n#~ \"ceased for them.\"\n#~ msgstr \"\"\n#~ \"PyMuPDFはPythonバージョン3.8以前をサポートしていません。古いバージョンのホイールは、`この \"\n#~ \"<https://github.com/pymupdf/PyMuPDF-Optional-\"\n#~ \"Material/tree/master/wheels-upto-Py3.5>`_ リポジトリや \"\n#~ \"`PyPI <https://pypi.org/project/PyMuPDF/>`_ でも見つけることができます\"\n\n#~ msgid \"\"\n#~ \"`Tesseract-OCR <https://github.com/tesseract-\"\n#~ \"ocr/tesseract>`_ for optical character \"\n#~ \"recognition in images and document \"\n#~ \"pages. Tesseract is separate software, \"\n#~ \"not a Python package. To enable \"\n#~ \"OCR functions in PyMuPDF, the software\"\n#~ \" must be installed and the system \"\n#~ \"environment variable `\\\"TESSDATA_PREFIX\\\"` must \"\n#~ \"be defined and contain the `tessdata`\"\n#~ \" folder name of the Tesseract \"\n#~ \"installation location. See below.\"\n#~ msgstr \"\"\n#~ \"`Tesseract-OCR <https://github.com/tesseract-\"\n#~ \"ocr/tesseract>`_ \"\n#~ \"は、画像やドキュメントページの光学文字認識（OCR）のためのソフトウェアです。TesseractはPythonのパッケージではなく、独立したソフトウェアです。PyMuPDFでOCR機能を有効にするには、Tesseractソフトウェアをインストールし、システム環境変数の\"\n#~ \" `\\\"TESSDATA_PREFIX\\\"` を定義して、Tesseractのインストール場所にある \"\n#~ \"`tessdata` フォルダの名前を含める必要があります。以下を参照してください。\"\n\n#~ msgid \"\"\n#~ \"The language support folder location \"\n#~ \"must be communicated either via storing\"\n#~ \" it in the environment variable \"\n#~ \"`\\\"TESSDATA_PREFIX\\\"`, or as a parameter \"\n#~ \"in the applicable functions.\"\n#~ msgstr \"\"\n#~ \"言語サポートフォルダの場所は、`\\\"TESSDATA_PREFIX\\\"` \"\n#~ \"という環境変数に保存するか、適用される関数のパラメータとして指定する必要があります。\"\n\n#~ msgid \"Set the environment variable `TESSDATA_PREFIX`\"\n#~ msgstr \"環境変数 `TESSDATA_PREFIX` を設定してください：\"\n\n#~ msgid \"\"\n#~ \"On Windows systems, this must happen \"\n#~ \"outside Python -- before starting your\"\n#~ \" script. Just manipulating `os.environ` \"\n#~ \"will not work!\"\n#~ msgstr \"\"\n#~ \"Windowsシステムでは、これはPythonの外部で行われる必要があります。スクリプトを実行する前に行ってください。`os.environ`\"\n#~ \" を操作するだけではうまく動作しません！\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Each wheel uses the Python Stable \"\n#~ \"ABI of the current oldest supported \"\n#~ \"Python version (currently 3.9), and so\"\n#~ \" works with all later Python \"\n#~ \"versions, including new Python releases.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Wheels are tested on all Python \"\n#~ \"versions currently marked as \\\"Supported\\\" \"\n#~ \"on https://devguide.python.org/versions/, currently \"\n#~ \"3.9, 3.10, 3.11, 3.12 and 3.13.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/intro.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.10\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-09-11 21:42+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 a41c7bb7308c4b5b830c403db1c8d522\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 4b9111f0fec54685953c69def64e45f3\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 49bb2731e94d4111965ffae8aa08a21f\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../intro.rst:4 f7699a4ad92d446ba773ba2396f91a3a\nmsgid \"Introduction\"\nmsgstr \"\"\n\n#: ../../intro.rst:15 12aec34e36c34e14a32ebeecf2c16431\nmsgid \"\"\n\"|PyMuPDF| is a Python binding for `MuPDF <https://www.mupdf.com/>`_ --\"\n\"  a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit, which\"\n\" is maintained and developed by Artifex Software, Inc\"\nmsgstr \"\"\n\n#: ../../intro.rst:17 be6754fe8f954f80897efdca10164de8\nmsgid \"\"\n\"MuPDF can access files in PDF, XPS, OpenXPS, CBZ, EPUB, MOBI and FB2 \"\n\"(e-books) formats, and it is known for its top performance and high \"\n\"rendering quality.\"\nmsgstr \"\"\n\n#: ../../intro.rst:19 b3268360e4cf4c56a5509810b370fa25\nmsgid \"\"\n\"MuPDF stands out among all similar products for its top rendering \"\n\"capability and unsurpassed processing speed. At the same time, its \"\n\"\\\"light weight\\\" makes it an excellent choice for platforms where \"\n\"resources are typically limited, like smartphones.\"\nmsgstr \"\"\n\n#: ../../intro.rst:21 c9802de5dae44cffb37698c1f86e6dde\nmsgid \"\"\n\"Check this out yourself and compare the various free PDF-viewers. In \"\n\"terms of speed and rendering quality `SumatraPDF \"\n\"<http://www.sumatrapdfreader.org/>`_ ranges at the top (apart from \"\n\"MuPDF's own standalone viewer) -- since it has changed its library basis \"\n\"to  MuPDF!\"\nmsgstr \"\"\n\n#: ../../intro.rst:23 c91ccfeae8fa4367815a63762c89721e\nmsgid \"\"\n\"With PyMuPDF you can access files with extensions like “.pdf”, “.xps”, \"\n\"“.oxps”, “.cbz”, “.fb2”, \\\".mobi\\\" or “.epub”. In addition, about 10 \"\n\"popular image formats can also be opened and handled like documents.\"\nmsgstr \"\"\n\n#: ../../intro.rst:25 903db6f8457c48e694fba6a66f5afd03\nmsgid \"\"\n\"PyMuPDF provides access to many important functions of MuPDF from within \"\n\"a Python environment, and we are continuously seeking to expand this \"\n\"function set.\"\nmsgstr \"\"\n\n#: ../../intro.rst:27 d4748fd6a1fe44e19d6bd9b222cb61cd\nmsgid \"\"\n\"PyMuPDF runs and has been tested on Mac, Linux and Windows for Python \"\n\"versions 3.8 [#f1]_ and up. Other platforms should work too, as long as \"\n\"MuPDF and Python support them.\"\nmsgstr \"\"\n\n#: ../../intro.rst:29 c748d030070b427c80417beaff9b6342\nmsgid \"\"\n\"PyMuPDF is hosted on `GitHub <https://github.com/pymupdf/PyMuPDF>`_ and \"\n\"registered on `PyPI <https://pypi.org/project/PyMuPDF/>`_.\"\nmsgstr \"\"\n\n#: ../../intro.rst:31 2be39641dab44b1c8e1dfa7afe144c4d\nmsgid \"\"\n\"For MS Windows, Mac OSX and Linux Python wheels are available -- please \"\n\"see the installation chapter.\"\nmsgstr \"\"\n\n#: ../../intro.rst:33 edeb85c952ab458dbd75bc79773b3448\nmsgid \"\"\n\"The GitHub repository `PyMuPDF-Utilities <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities>`_ contains a full range of examples, demonstrations \"\n\"and use cases.\"\nmsgstr \"\"\n\n#: ../../intro.rst:36 21bc387c7484451aa6678a479ef7b24b\nmsgid \"Note on the legacy module name *fitz*\"\nmsgstr \"\"\n\n#: ../../intro.rst:37 5b06571ac8e44ca498d5d938ad978bc1\nmsgid \"\"\n\"Prior to release 1.24.3, the top level Python import name for this \"\n\"library was **\\\"fitz\\\"**. This has historical reasons:\"\nmsgstr \"\"\n\n#: ../../intro.rst:39 54b20466f423486cb7a419f853600c0f\nmsgid \"The original rendering library for MuPDF was called *Libart*.\"\nmsgstr \"\"\n\n#: ../../intro.rst:41 8e099c2cdacc4a9bb75ad97643b3f913\nmsgid \"\"\n\"*\\\"After Artifex Software acquired the MuPDF project, the development \"\n\"focus shifted on writing a new modern graphics library called \\\"Fitz\\\". \"\n\"Fitz was originally intended as an R&D project to replace the aging \"\n\"Ghostscript graphics library, but has instead become the rendering engine\"\n\" powering MuPDF.\\\"* (Quoted from `Wikipedia \"\n\"<https://en.wikipedia.org/wiki/MuPDF>`_).\"\nmsgstr \"\"\n\n#: ../../intro.rst:43 b3f34235d3034b02a4880f492a05b577\nmsgid \"`import fitz` is still supported for backwards compatibility.\"\nmsgstr \"\"\n\n#: ../../intro.rst:47 213da85a65254b2caf874559e9e67019\nmsgid \"\"\n\"Use of legacy name `fitz` can fail if defunct package pypi.org `fitz` is \"\n\"installed; see :ref:`problems-after-installation`.\"\nmsgstr \"\"\n\n#: ../../intro.rst:51 3577e73ae4f34a25b80069861e962f37\nmsgid \"License and Copyright\"\nmsgstr \"\"\n\n#: ../../intro.rst:52 874d0e2d51844efea0695f5bd19c58c2\nmsgid \"\"\n\"In order to comply with MuPDF’s dual licensing model, PyMuPDF has entered\"\n\" into an agreement with Artifex who has the right to sublicense PyMuPDF \"\n\"to third parties.\"\nmsgstr \"\"\n\n#: ../../intro.rst:54 0b731cd148964d8db2bd16ba896ea1f9\nmsgid \"\"\n\"PyMuPDF and MuPDF are now available under both, open-source AGPL and \"\n\"commercial license agreements. Please read the full text of the AGPL \"\n\"license agreement, available in the distribution material (file COPYING) \"\n\"and `here <https://www.gnu.org/licenses/agpl-3.0.html>`_, to ensure that \"\n\"your use case complies with the guidelines of the license. If you \"\n\"determine you cannot meet the requirements of the AGPL, please contact \"\n\"`Artifex <https://artifex.com/contact/>`_ for more information regarding \"\n\"a commercial license.\"\nmsgstr \"\"\n\n#: ../../intro.rst:56 473e50eb75544325969f223a85c2172e\nmsgid \"Artifex is the exclusive commercial licensing agent for MuPDF.\"\nmsgstr \"\"\n\n#: ../../intro.rst:58 777d916fb52441aabdd18216e4977bf9\nmsgid \"\"\n\"Artifex, the Artifex logo, MuPDF, and the MuPDF logo are registered \"\n\"trademarks of Artifex Software Inc. © 2022 Artifex Software, Inc. All \"\n\"rights reserved.\"\nmsgstr \"\"\n\n#: ../../version.rst:3 ac529f29c7004bdab4f7da3dbb922e12\nmsgid \"\"\n\"This documentation covers **PyMuPDF v1.24.10** features as of \"\n\"**2024-09-02 00:00:01**.\"\nmsgstr \"\"\n\n#: ../../version.rst:5 d0267645ce504840843677d4a3060147\nmsgid \"\"\n\"The major and minor versions of |PyMuPDF| and |MuPDF| will always be \"\n\"the same. Only the third qualifier (patch level) may deviate from that of\"\n\" |MuPDF|.\"\nmsgstr \"\"\n\n#: ../../version.rst:7 f26be46a33a04d54965c32772883e3ab\nmsgid \"\"\n\"Typically PyMuPDF is released more frequently than MuPDF so it will often\"\n\" be the case that the patch level of PyMuPDF will be greater than the \"\n\"embedded MuPDF.\"\nmsgstr \"\"\n\n#: ../../version.rst:11 ccdc763817ae4046bebe37eeb819b308\nmsgid \"For example PyMuPDF-1.24.5 contains MuPDF-1.24.2.\"\nmsgstr \"\"\n\n#: ../../version.rst:13 d116a1d660c74042baf5a7bd51e852b0\nmsgid \"Also see `pymupdf_version` and `mupdf_version`.\"\nmsgstr \"\"\n\n#: ../../intro.rst:66 7fed4e7b825746bbbcf0054fbe740a34\nmsgid \"Footnotes\"\nmsgstr \"\"\n\n#: ../../intro.rst:67 4cbcfdb2063e434a839290ebb3369077\nmsgid \"\"\n\"PyMuPDF generally only supports Python versions that are still maintained\"\n\" by the Python Software Foundation. Once a Python version is being \"\n\"retired, PyMuPDF support will also be ended. This means that wheels for a\"\n\" retired Python platform will no longer be provided, and that Python \"\n\"language features may be used that did not exist in the retired Python \"\n\"version.\"\nmsgstr \"\"\n\n#: ../../footer.rst:60 4201ffb7de1543f7bcbcec3989cad1e5\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"\"\n\n#: ../../footer.rst:-1 9fc4919ea2ad4bbe8a478f523c247979\nmsgid \"Discord logo\"\nmsgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/irect.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 9da9a1f0d8ad4810a00d9c3ffb986077\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 c119c5ee601a454eb3d762c5116445d1\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 e312792ce16248f98f71d027cbbe1d64\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../irect.rst:7 ddef2d577f7c46fca0650922f46a8a81\nmsgid \"IRect\"\nmsgstr \"\"\n\n#: ../../irect.rst:9 64079ef1a00e45ee981d0d272179f2e3\nmsgid \"\"\n\"IRect is a rectangular bounding box, very similar to :ref:`Rect`, except \"\n\"that all corner coordinates are integers. IRect is used to specify an \"\n\"area of pixels, e.g. to receive image data during rendering. Otherwise, \"\n\"e.g. considerations concerning emptiness and validity of rectangles also \"\n\"apply to this class. Methods and attributes have the same names, and in \"\n\"many cases are implemented by re-using the respective :ref:`Rect` \"\n\"counterparts.\"\nmsgstr \"\"\n\"IRect（整数長方形）は、:ref:`Rect` \"\n\"と非常に似ているが、すべての角の座標が整数であるという点が異なります。IRectは、レンダリング中に画像データを受け取る領域を指定するために使用されます。それ以外にも、長方形の空白や有効性に関する考慮事項が適用されます。メソッドと属性は同じ名前を持ち、多くの場合、対応する\"\n\" :ref:`Rect` の対応部分を再利用して実装されています。\"\n\n#: ../../irect.rst:12 ab97696201f6481cb7a9151183d74b19\nmsgid \"**Attribute / Method**\"\nmsgstr \"**属性/メソッド**\"\n\n#: ../../irect.rst:12 efcc94105da54f018a86e821fec2d8cd\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../irect.rst:14 dc94e84e46af4660871003b4bcf7a4f4\nmsgid \":meth:`IRect.contains`\"\nmsgstr \"\"\n\n#: ../../irect.rst:14 92ea7aa5de9a48a9b5ac185c1794a7e5\nmsgid \"checks containment of another object\"\nmsgstr \"他のオブジェクトの含まれているかを確認します。\"\n\n#: ../../irect.rst:15 124cec4d00074c519fbf6ce8ac42a723\nmsgid \":meth:`IRect.get_area`\"\nmsgstr \"\"\n\n#: ../../irect.rst:15 2053892c2f4c422ab19ae350ecbe23e8\nmsgid \"calculate rectangle area\"\nmsgstr \"長方形の面積を計算します。\"\n\n#: ../../irect.rst:16 a5bdba1573d44547b8b0673e7cd37dce\nmsgid \":meth:`IRect.intersect`\"\nmsgstr \"\"\n\n#: ../../irect.rst:16 d1f0c881eaab47f3a362862bee94a3ec\nmsgid \"common part with another rectangle\"\nmsgstr \"別の長方形との共通部分を取得します。\"\n\n#: ../../irect.rst:17 11746224755e4a3b9da4cfe7f4269d11\nmsgid \":meth:`IRect.intersects`\"\nmsgstr \"\"\n\n#: ../../irect.rst:17 924de332ec5b4656a802d2e85f6927e7\nmsgid \"checks for non-empty intersection\"\nmsgstr \"非空の交差をチェックします。\"\n\n#: ../../irect.rst:18 2132f387192449f0ac037eb9a66f3777\nmsgid \":meth:`IRect.morph`\"\nmsgstr \"\"\n\n#: ../../irect.rst:18 530d3654b8ba4812a36e35dfad701ddf\nmsgid \"transform with a point and a matrix\"\nmsgstr \"ポイントと行列を使用して変換します。\"\n\n#: ../../irect.rst:19 a3769ab66bee466a8c94fb47b13ff0e2\nmsgid \":meth:`IRect.torect`\"\nmsgstr \"\"\n\n#: ../../irect.rst:19 d7e2a8f91121496a914e133895de1d66\nmsgid \"matrix that transforms to another rectangle\"\nmsgstr \"別の長方形に変換する行列。\"\n\n#: ../../irect.rst:20 81cff3d0715f416da3509d8bb9b099ce\nmsgid \":meth:`IRect.norm`\"\nmsgstr \"\"\n\n#: ../../irect.rst:20 444fb6d41f6c4e34b0fceb673ba3dc81\nmsgid \"the Euclidean norm\"\nmsgstr \"ユークリッドノルム。\"\n\n#: ../../irect.rst:21 c5fbf520ee1e47958587d44173e70ad4\nmsgid \":meth:`IRect.normalize`\"\nmsgstr \"\"\n\n#: ../../irect.rst:21 9fadec1aa0fa42899e37379ddec7c9d1\nmsgid \"makes a rectangle finite\"\nmsgstr \"長方形を有限にします。\"\n\n#: ../../irect.rst:22 ad485c24a3a34720ba6cdce4aa57cd30\nmsgid \":attr:`IRect.bottom_left`\"\nmsgstr \"\"\n\n#: ../../irect.rst:22 0f87509f1d3043d49419e4bf77e7d5b6\nmsgid \"bottom left point, synonym *bl*\"\nmsgstr \"左下のポイント、同義語の *bl* \"\n\n#: ../../irect.rst:23 6b2e1bb32097415c9539dbb2ae43ca43\nmsgid \":attr:`IRect.bottom_right`\"\nmsgstr \"\"\n\n#: ../../irect.rst:23 4888cfd6ae27499381d64bedabc834ae\nmsgid \"bottom right point, synonym *br*\"\nmsgstr \"右下のポイント、同義語の *br* \"\n\n#: ../../irect.rst:24 ef3263604d9e406da1601cab4d8bac3e\nmsgid \":attr:`IRect.height`\"\nmsgstr \"\"\n\n#: ../../irect.rst:24 ed8730e7d3eb43a38680c2490024ea3a\nmsgid \"height of the rectangle\"\nmsgstr \"長方形の高さ\"\n\n#: ../../irect.rst:25 c4c26d29c9dc490fb9ce003895f46551\nmsgid \":attr:`IRect.is_empty`\"\nmsgstr \"\"\n\n#: ../../irect.rst:25 2c44a8bb62b7482a8ea229f24405e7a2\nmsgid \"whether rectangle is empty\"\nmsgstr \"長方形が空かどうか\"\n\n#: ../../irect.rst:26 62f693c4f27d4da28c1416bdf2633620\nmsgid \":attr:`IRect.is_infinite`\"\nmsgstr \"\"\n\n#: ../../irect.rst:26 583895dab1fb49df97e3c485ef00b41b\nmsgid \"whether rectangle is infinite\"\nmsgstr \"長方形が無限であるかどうか\"\n\n#: ../../irect.rst:27 bf8fa54275764b07a1cc4cf60133e69e\nmsgid \":attr:`IRect.rect`\"\nmsgstr \"\"\n\n#: ../../irect.rst:27 67cc7f8daa2844e0a01efba201d0c056\nmsgid \"the :ref:`Rect` equivalent\"\nmsgstr \":ref:`Rect` の同等物\"\n\n#: ../../irect.rst:28 8f89c6c745e54747aed947c8dd097575\nmsgid \":attr:`IRect.top_left`\"\nmsgstr \"\"\n\n#: ../../irect.rst:28 9593c3c6673e4014bc7f1f38035db854\nmsgid \"top left point, synonym *tl*\"\nmsgstr \"左上のポイント、同義語の *tl* \"\n\n#: ../../irect.rst:29 ccd49d6f1ebd447dbc14e886376eeedd\nmsgid \":attr:`IRect.top_right`\"\nmsgstr \"\"\n\n#: ../../irect.rst:29 f5d3a7dbdfc2490e90041a1cce9c6e78\nmsgid \"top_right point, synonym *tr*\"\nmsgstr \"右上のポイント、同義語の *tr* \"\n\n#: ../../irect.rst:30 092c64736cb9423fbade8738a18def52\nmsgid \":attr:`IRect.quad`\"\nmsgstr \"\"\n\n#: ../../irect.rst:30 02794414a93b473e9430f42716496fae\nmsgid \":ref:`Quad` made from rectangle corners\"\nmsgstr \"長方形の角から作成された四角形\"\n\n#: ../../irect.rst:31 8f40f8f7548f45d69bb49e4340ea0e8c\nmsgid \":attr:`IRect.width`\"\nmsgstr \"\"\n\n#: ../../irect.rst:31 9a5de017b1ca40b7b146ca25383c738e\nmsgid \"width of the rectangle\"\nmsgstr \"長方形の幅\"\n\n#: ../../irect.rst:32 0c0b410baf734144851d33016cbdddd0\nmsgid \":attr:`IRect.x0`\"\nmsgstr \"\"\n\n#: ../../irect.rst:32 219bd087640142edad26e0cef53ce452\nmsgid \"X-coordinate of the top left corner\"\nmsgstr \"左上隅のX座標\"\n\n#: ../../irect.rst:33 41ac1de7703f44bcbe5f615ba2dce3ea\nmsgid \":attr:`IRect.x1`\"\nmsgstr \"\"\n\n#: ../../irect.rst:33 ae41326e3d484ab889ee2b9c5ff3a7de\nmsgid \"X-coordinate of the bottom right corner\"\nmsgstr \"右下隅のX座標\"\n\n#: ../../irect.rst:34 a3223a0657ab45b087b1c100476b4a17\nmsgid \":attr:`IRect.y0`\"\nmsgstr \"\"\n\n#: ../../irect.rst:34 19062c693a07420a8c8d2f3b3c1eb750\nmsgid \"Y-coordinate of the top left corner\"\nmsgstr \"左上隅のY座標\"\n\n#: ../../irect.rst:35 c1c7be5dd2ef41a2b6d447cb43a6a07e\nmsgid \":attr:`IRect.y1`\"\nmsgstr \"\"\n\n#: ../../irect.rst:35 be7ae048d8ea46edaf23968ef9c8bce1\nmsgid \"Y-coordinate of the bottom right corner\"\nmsgstr \"右下隅のY座標\"\n\n#: ../../irect.rst:38 d9ba47e2fb7f40a5b94b36b2e8690bd1\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../irect.rst:50 1c5e8f4e34f047098b41ead038224c50\nmsgid \"\"\n\"Overloaded constructors. Also see examples below and those for the \"\n\":ref:`Rect` class.\"\nmsgstr \"オーバーロードされたコンストラクタ。また、以下の例と :ref:`Rect` クラスの例も参照してください。\"\n\n#: ../../irect.rst:52 50def18ce8504003afbebdd0a9a55ac1\nmsgid \"If another irect is specified, a **new copy** will be made.\"\nmsgstr \"別のirectが指定された場合、**新しいコピー** が作成されます。\"\n\n#: ../../irect.rst:54 9b2e5c01c35646e3ad3647dfb830f028\nmsgid \"\"\n\"If sequence is specified, it must be a Python sequence type of 4 numbers \"\n\"(see :ref:`SequenceTypes`). Non-integer numbers will be truncated, non-\"\n\"numeric values will raise an exception.\"\nmsgstr \"シーケンスが指定された場合、それは4つの数値のPythonシーケンス型である必要があります（:ref:`SequenceTypes`）。整数以外の数値は切り捨てられ、数値以外の値は例外を発生させます。\"\n\n#: ../../irect.rst:56 2cd32524540f40ac87e1e408344a827d\nmsgid \"The other parameters mean integer coordinates.\"\nmsgstr \"その他のパラメータは整数座標を意味します。\"\n\n#: ../../irect.rst:61 840c50265ae3462c89c54b22ce7e67f9\nmsgid \"\"\n\"Calculates the area of the rectangle and, with no parameter, equals \"\n\"*abs(IRect)*. Like an empty rectangle, the area of an infinite rectangle \"\n\"is also zero.\"\nmsgstr \"長方形の面積を計算し、パラメータなしで *abs(IRect)* に等しいです。空の長方形と同様に、無限の長方形の面積もゼロです。\"\n\n#: ../../irect.rst 4f00a177e1bc4d3d89dda38f1909fa94\n#: 4fc3aa5f280242c986288acbfa1b8175 9b5b83039e0c4fdeaf7685aa05b6bb16\n#: aa8fbd2f167e422e9b6b3aaac458e3a9 b69ba3e050904df0afe8a6d582ef2363\n#: ed922b3129dd4c73b25f962b90ae50aa\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../irect.rst:63 3be2e3c29aba4f5189e0cbb7f1144057\nmsgid \"\"\n\"Specify required unit: respective squares of \\\"px\\\" (pixels, default), \"\n\"\\\"in\\\" (inches), \\\"cm\\\" (centimeters), or \\\"mm\\\" (millimeters).\"\nmsgstr \"\"\n\"必要な単位を指定します：「px」（ピクセル、デフォルト）、 「in」（インチ）、 \"\n\"「cm」（センチメートル）、または「mm」（ミリメートル）のそれぞれの平方。\"\n\n#: ../../irect.rst 4e47019f7b9b4864aef1988ad0bcbdd9\n#: 8a353e9947ea4ef2b6e0a6872cda119d 9f7bfdd3aed843358d17fe22401cb884\n#: a7c70439c9f2475ba9e98c25daaa8da2\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../irect.rst:69 782b0a38b1a44a3fb17923582226e601\nmsgid \"\"\n\"The intersection (common rectangular area) of the current rectangle and \"\n\"*ir* is calculated and replaces the current rectangle. If either \"\n\"rectangle is empty, the result is also empty. If either rectangle is \"\n\"infinite, the other one is taken as the result -- and hence also infinite\"\n\" if both rectangles were infinite.\"\nmsgstr \"\"\n\"現在の長方形と *ir* \"\n\"の交差（共通の長方形領域）を計算し、現在の長方形に置き換えます。どちらかの長方形が空の場合、結果も空です。どちらかの長方形が無限の場合、もう一方が結果として取られます。したがって、両方の長方形が無限である場合、結果も無限です。\"\n\n#: ../../irect.rst:71 fcebc17df9614b1882a8032f5fcee80a\nmsgid \"Second rectangle.\"\nmsgstr \"第2の長方形。\"\n\n#: ../../irect.rst:75 bca6b46c6fce4c0391d350804618c7b0\nmsgid \"\"\n\"Checks whether *x* is contained in the rectangle. It may be \"\n\":data:`rect_like`, :data:`point_like` or a number. If *x* is an empty \"\n\"rectangle, this is always true. Conversely, if the rectangle is empty \"\n\"this is always ``False``, if *x* is not an empty rectangle and not a \"\n\"number. If *x* is a number, it will be checked to be one of the four \"\n\"components. *x in irect* and *irect.contains(x)* are equivalent.\"\nmsgstr \"\"\n\"*x* が長方形に含まれているかどうかを確認します。それは \"\n\":data:`rect_like`、:data:`point_like`、または数値であるかもしれません。*x* \"\n\"が空の長方形の場合、これは常に真です。逆に、長方形が空の場合、これは常に偽です。xが空の長方形でなく、数値でない場合、これは常に偽です。 *x* \"\n\"が数値の場合、それは4つの構成要素の1つであることが確認されます。 *x* in *irect* および *irect.contains(x)* \"\n\"は同等です\"\n\n#: ../../irect.rst:77 2a8a12b2850d4bfba7bba2b40cc06f55\nmsgid \"the object to check.\"\nmsgstr \"確認するオブジェクト。\"\n\n#: ../../irect.rst:84 50064e8a49c54a6da52a3b0900a114f3\nmsgid \"\"\n\"Checks whether the rectangle and the :data:`rect_like` \\\"r\\\" contain a \"\n\"common non-empty :ref:`IRect`. This will always be ``False`` if either is\"\n\" infinite or empty.\"\nmsgstr \"\"\n\"長方形と :data:`rect_like`「r」が共通の非空 :ref:`IRect` \"\n\"を含むかどうかをチェックします。どちらかが無限または空の場合、これは常に ``False`` になります。\"\n\n#: ../../irect.rst:86 b0c988e57dce4071a0e518ca1e93877f\nmsgid \"the rectangle to check.\"\nmsgstr \"チェックする長方形。\"\n\n#: ../../irect.rst:92 1bbbf78a89784f7db6abf366bea409ae\nmsgid \"New in version 1.19.3\"\nmsgstr \"バージョン1.19.3で新登場\"\n\n#: ../../irect.rst:94 f3726b71047d42a58f879f9c00944d3f\nmsgid \"\"\n\"Compute the matrix which transforms this rectangle to a given one. See \"\n\":meth:`Rect.torect`.\"\nmsgstr \"この長方形を指定された長方形に変換する行列を計算します。:meth:`Rect.torect` を参照してください。\"\n\n#: ../../irect.rst:96 dcc19ae43b814fe4b56fa555133432ce\nmsgid \"the target rectangle. Must not be empty or infinite.\"\nmsgstr \"ターゲットの長方形。空または無限であってはなりません。\"\n\n#: ../../irect.rst:97 d473a4edcd124daab7417f12570976d0\nmsgid \":ref:`Matrix`\"\nmsgstr \"\"\n\n#: ../../irect.rst e2953f28a3ff42908f0e4d0811230263\n#: f368ffdbb210464aac1693355694b761\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../irect.rst:98 056021e1cc164996aed45008297df188\nmsgid \"\"\n\"a matrix `mat` such that `self * mat = rect`. Can for example be used to \"\n\"transform between the page and the pixmap coordinates.\"\nmsgstr \"`self * mat = rect` となるような行列 `mat` 。たとえば、ページとピクセルマップの座標間を変換するために使用できます。\"\n\n#: ../../irect.rst:103 88b85325f704446180fd037b13f438d8\nmsgid \"New in version 1.17.0\"\nmsgstr \"新機能 バージョン1.17.0\"\n\n#: ../../irect.rst:105 2b9036d190fb49e0b5f461aba0df7c7f\nmsgid \"Return a new quad after applying a matrix to it using a fixed point.\"\nmsgstr \"指定された固定点に行列を適用した後の新しい四角形を返します。\"\n\n#: ../../irect.rst:107 3ff780516b4146f3ae0d550b2b4a36ce\nmsgid \"the fixed point.\"\nmsgstr \"固定点。\"\n\n#: ../../irect.rst:108 1fbd651a14a1443596afb4e080f12015\nmsgid \"the matrix.\"\nmsgstr \"行列。\"\n\n#: ../../irect.rst:109 f932937ceb634ac7890e4cb6a194a02b\nmsgid \"\"\n\"a new :ref:`Quad`. This a wrapper of the same-named quad method. If \"\n\"infinite, the infinite quad is returned.\"\nmsgstr \"新しい :ref:`Quad`。これは同じ名前のquadメソッドのラッパーです。無限であれば、無限の四角形が返されます。\"\n\n#: ../../irect.rst:113 613eaa02d46e4a9eab41724a4e10baa2\nmsgid \"New in version 1.16.0\"\nmsgstr \"新機能 バージョン1.16.0\"\n\n#: ../../irect.rst:115 e05020824bd94a418f7786caff3a68e5\nmsgid \"\"\n\"Return the Euclidean norm of the rectangle treated as a vector of four \"\n\"numbers.\"\nmsgstr \"四角形を4つの数字のベクトルとして扱った場合のユークリッドノルムを返します。\"\n\n#: ../../irect.rst:119 deaf5a4b9f8440fd8fe7b802f78ec9b9\nmsgid \"\"\n\"Make the rectangle finite. This is done by shuffling rectangle corners. \"\n\"After this, the bottom right corner will indeed be south-eastern to the \"\n\"top left one. See :ref:`Rect` for a more details.\"\nmsgstr \"\"\n\"四角形を有限にします。これは四角形の角を入れ替えることによって行われます。この操作後、右下の角は確かに左上の角の南東になります。詳細については、:ref:`Rect`\"\n\" を参照してください。\"\n\n#: ../../irect.rst:125 55613d17f4fd4a458eca520133551eb0\nmsgid \"Equals *Point(x0, y0)*.\"\nmsgstr \"*Point(x0, y0)* と同等です。\"\n\n#: ../../irect.rst 1fb6ace84c4d4e938a1ff7c0b704b38f\n#: 49d4afd12c6a42c4a29bf9c269eadfe0 5b4a83c92ca649dda2e8fa0e691bbd89\n#: 6cbe1cdc288d48ee9c6b6bd68a21fea6 7559f9666807471eaa667884ab2f79b5\n#: 8d8f0f2b15df45779323571cd1a1b751 c86cbf20e5234741bd7bc1e8fd9a44ca\n#: d2aad704feb949ebb36c3a4e729a8d5f d793441a05ce4bc48b85052e697d053e\n#: dc8594c4fac847ac8161c79a639811ce e8ad8d35ebcb4d0795598f07a336334c\n#: f52efa790e584d859f3797654913b784 f66efb6c2f134fa69083a7c6b1a857ab\n#: ff031729ca2a4ce1ad1e658f12ce0cfe\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../irect.rst:127 ../../irect.rst:135 ../../irect.rst:143\n#: ../../irect.rst:151 308d3cb353bb49ae94161cf7dc7218d3\n#: 3249e89f3b7c4ac2bea38ea5214c52c5 785ff830f1234dc69f3c770992c2a410\n#: 884b7d46c20742c0a7283bee8b40a43f\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../irect.rst:133 921cb3a2a7cf4cbf806f9d772749b917\nmsgid \"Equals *Point(x1, y0)*.\"\nmsgstr \"*Point(x1, y0)* と同等です。\"\n\n#: ../../irect.rst:141 13776e76c48248909500e8fe82c9d0a4\nmsgid \"Equals *Point(x0, y1)*.\"\nmsgstr \"*Point(x0, y1)* と同等です。\"\n\n#: ../../irect.rst:149 99f201fd44fd4ed0a1f49b75400f0d0f\nmsgid \"Equals *Point(x1, y1)*.\"\nmsgstr \"*Point(x1, y1)* と同等です。\"\n\n#: ../../irect.rst:155 63204ddea7a14d2592a7ad0f9dd74810\nmsgid \"The :ref:`Rect` with the same coordinates as floats.\"\nmsgstr \"浮動小数点座標と同じ座標を持つ :ref:`Rect` です。\"\n\n#: ../../irect.rst:157 2d7b927314b342cb96c8fb15d3b8e3b9\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../irect.rst:161 57dfabd4e9b049e4900273a9ec4cb817\nmsgid \"The quadrilateral *Quad(irect.tl, irect.tr, irect.bl, irect.br)*.\"\nmsgstr \"四角形 *Quad(irect.tl, irect.tr, irect.bl, irect.br)です* 。\"\n\n#: ../../irect.rst:163 a199b927484848978ec222114a9da0cc\nmsgid \":ref:`Quad`\"\nmsgstr \"\"\n\n#: ../../irect.rst:167 1d437103ee594f9b944058db4631bb9d\nmsgid \"Contains the width of the bounding box. Equals *abs(x1 - x0)*.\"\nmsgstr \"境界ボックスの幅を含みます。*abs(x1 - x0)* と同等です。\"\n\n#: ../../irect.rst:169 ../../irect.rst:175 ../../irect.rst:181\n#: ../../irect.rst:187 ../../irect.rst:193 ../../irect.rst:199\n#: 083882bcb7354a55bf7f4dd85eef92b9 8ed88f37bd6742da83895a91a8685917\n#: 967dc9f8c2fc43b7b56954d34441687f 9958930f4f6e45b5980d2c23669ce09f\n#: ac4b6a2822ce482a8dbfbf739c4ffa79 bd9b56e6197441be9f3888a17b04d9a4\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../irect.rst:173 b187d2fbc4bd439e834930d74922794b\nmsgid \"Contains the height of the bounding box. Equals *abs(y1 - y0)*.\"\nmsgstr \"境界ボックスの高さを含みます。*abs(y1 - y0)* と同等です。\"\n\n#: ../../irect.rst:179 4777545ac79b48f1a71c4b3dffbbe470\nmsgid \"X-coordinate of the left corners.\"\nmsgstr \"左上隅のX座標です。\"\n\n#: ../../irect.rst:185 187b3e2a62fa440b84c0265a597e11e0\nmsgid \"Y-coordinate of the top corners.\"\nmsgstr \"上端のY座標です。\"\n\n#: ../../irect.rst:191 4539d20b89644229aae3fcc4c1196436\nmsgid \"X-coordinate of the right corners.\"\nmsgstr \"右上隅のX座標です。\"\n\n#: ../../irect.rst:197 69a9d5438d1b4b199976b0b23ba70a7e\nmsgid \"Y-coordinate of the bottom corners.\"\nmsgstr \"下端のY座標です。\"\n\n#: ../../irect.rst:203 34a8989b9f274d83b0a6c5031b749190\nmsgid \"``True`` if rectangle is infinite, ``False`` otherwise.\"\nmsgstr \"四角形が無限の場合は ``True`` 、それ以外の場合は``False`` です。\"\n\n#: ../../irect.rst:205 ../../irect.rst:211 c8f3501df5c14812ae13827184765c29\n#: d6f0997b994c464fa7457bb7c1cce89c\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../irect.rst:209 5fea893d5a0e409aacb5452b2ffa3fcf\nmsgid \"``True`` if rectangle is empty, ``False`` otherwise.\"\nmsgstr \"四角形が空の場合は ``True``、それ以外の場合は ``False`` です。\"\n\n#: ../../irect.rst:216 e58bd147e5934ff788a34135346e5c97\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"\"\n\"このクラスはPythonのシーケンスプロトコルに従っているため、コンポーネントはインデックスを使用してアクセスできます。また、:ref:`SequenceTypes`\"\n\" も参照してください。\"\n\n#: ../../irect.rst:217 0d59de499da146b2914c95df6f414f34\nmsgid \"\"\n\"Rectangles can be used with arithmetic operators -- see chapter \"\n\":ref:`Algebra`.\"\nmsgstr \"また、四角形は算術演算子と一緒に使用できます - :ref:`Algebra` を参照してください。\"\n\n#: ../../footer.rst:60 7dccd50b2f2443208394ecb0c842c1dd\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/link.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 789ef3e179a7439395eb0d05014100e0\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 d6bae0d656e54c42bbd6fabc354253ae\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 c2865acb728b48b0be9ebcbf4ca09b69\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../link.rst:7 c688c9e8319141a9be77a5892a13809d\nmsgid \"Link\"\nmsgstr \"Link (リンク)\"\n\n#: ../../link.rst:8 52cdea6624d9492a8f1367f1fee8b4f8\nmsgid \"\"\n\"Represents a pointer to somewhere (this document, other documents, the \"\n\"internet). Links exist per document page, and they are forward-chained to\"\n\" each other, starting from an initial link which is accessible by the \"\n\":attr:`Page.first_link` property.\"\nmsgstr \"\"\n\"リンクは、どこかへのポインタを表します（この文書、他の文書、インターネットなど）。リンクは文書のページごとに存在し、最初のリンクは \"\n\":attr:`Page.first_link` プロパティでアクセスできます。リンクはお互いにフォワードチェーンされ、最初のリンクから始まります。\"\n\n#: ../../link.rst:10 ae08ffa8e9f4429bb99c55016bdcc961\nmsgid \"\"\n\"There is a parent-child relationship between a link and its page. If the \"\n\"page object becomes unusable (closed document, any document structure \"\n\"change, etc.), then so does every of its existing link objects -- an \"\n\"exception is raised saying that the object is \\\"orphaned\\\", whenever a \"\n\"link property or method is accessed.\"\nmsgstr \"リンクとそのページとの親子関係があります。ページオブジェクトが使用できなくなると（ドキュメントがクローズされた場合、ドキュメント構造が変更された場合など）、そのページに存在するリンクオブジェクトも使用できなくなります。リンクのプロパティまたはメソッドにアクセスしようとすると、「オーファン」というオブジェクトが発生し、例外が発生します。\"\n\n#: ../../link.rst:13 540b33af6e004a60a5c462085df023e5\nmsgid \"**Attribute**\"\nmsgstr \"**属性**\"\n\n#: ../../link.rst:13 f47bd46a654a45a4ba851c09a22eea60\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../link.rst:15 f7c6af0af71e4dd19562174e5497a60d\nmsgid \":meth:`Link.set_border`\"\nmsgstr \"\"\n\n#: ../../link.rst:15 1792d06c2e574c19a323b62f42c2d45c\nmsgid \"modify border properties\"\nmsgstr \"境界線のプロパティを変更します\"\n\n#: ../../link.rst:16 d9891c2fa8284703a452d3df1a0653fd\nmsgid \":meth:`Link.set_colors`\"\nmsgstr \"\"\n\n#: ../../link.rst:16 5c1f73fa45454debbad1d5891c4378cd\nmsgid \"modify color properties\"\nmsgstr \"色のプロパティを変更します\"\n\n#: ../../link.rst:17 0af10d50600346ea8663643e1de0eb8b\nmsgid \":meth:`Link.set_flags`\"\nmsgstr \"\"\n\n#: ../../link.rst:17 6e5bbdf2f3f94fb5a120e1443763be30\nmsgid \"modify link flags\"\nmsgstr \"リンクフラグを変更します\"\n\n#: ../../link.rst:18 6dce9d5a48824fff84e601d4aecdc691\nmsgid \":attr:`Link.border`\"\nmsgstr \"\"\n\n#: ../../link.rst:18 604357ac107245f993ae3b1650ebcf79\nmsgid \"border characteristics\"\nmsgstr \"境界線の特性\"\n\n#: ../../link.rst:19 56981bc862ef422cac26e01e4529b563\nmsgid \":attr:`Link.colors`\"\nmsgstr \"\"\n\n#: ../../link.rst:19 d2b934f42ed647d39eafa1cf42d776d1\nmsgid \"border line color\"\nmsgstr \"境界線の色\"\n\n#: ../../link.rst:20 53bcd3c8bba14f7bbc40266833181e80\nmsgid \":attr:`Link.dest`\"\nmsgstr \"\"\n\n#: ../../link.rst:20 f923e0b3b9744816a353b2e8fa3e2210\nmsgid \"points to destination details\"\nmsgstr \"宛先の詳細を指します\"\n\n#: ../../link.rst:21 5eed957ff70b41e98d0eb9285cd96980\nmsgid \":attr:`Link.is_external`\"\nmsgstr \"\"\n\n#: ../../link.rst:21 effa067d28d44d16bb8fe8e503593a5d\n#, fuzzy\nmsgid \"checks if the link is an external destination\"\nmsgstr \"外部宛先ですか？\"\n\n#: ../../link.rst:22 bbe68bce0387407795c1edda367ef2ab\nmsgid \":attr:`Link.flags`\"\nmsgstr \"\"\n\n#: ../../link.rst:22 ad43a0946bcc486ca5aa72ecdd1d02bf\nmsgid \"link annotation flags\"\nmsgstr \"リンク注釈のフラグ\"\n\n#: ../../link.rst:23 eef3e8a36ea145629db1a703e87f575d\nmsgid \":attr:`Link.next`\"\nmsgstr \"\"\n\n#: ../../link.rst:23 627116875da8492cbc9685c5ef7289cc\nmsgid \"points to next link\"\nmsgstr \"次のリンクを指します\"\n\n#: ../../link.rst:24 08387b2d8317483d9cc61f3452cea422\nmsgid \":attr:`Link.rect`\"\nmsgstr \"\"\n\n#: ../../link.rst:24 58a914c6c1424572881b90bcc4392db4\n#, fuzzy\nmsgid \"clickable area in untransformed coordinates\"\nmsgstr \"変換されていない座標内のクリック可能な領域\"\n\n#: ../../link.rst:25 b115d680a21b46a6b85d654dd3a49b79\nmsgid \":attr:`Link.uri`\"\nmsgstr \"\"\n\n#: ../../link.rst:25 969ecf8c8c9341bf8ee037a0c9ee9a8b\nmsgid \"link destination\"\nmsgstr \"リンクの宛先\"\n\n#: ../../link.rst:26 253e0f31052f499b9e4346932b58c7d9\nmsgid \":attr:`Link.xref`\"\nmsgstr \"\"\n\n#: ../../link.rst:26 2e407687ff9648c88d884bc113153b63\nmsgid \":data:`xref` number of the entry\"\nmsgstr \"エントリの :data:`xref` 番号\"\n\n#: ../../link.rst:29 86c8b11333584703a538c055122d3356\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../link.rst:35 12ea65b799b44f38acf6a8810d508ddb\nmsgid \"PDF only: Change border width and dashing properties.\"\nmsgstr \"PDFのみ：境界線の幅と破線プロパティを変更します。\"\n\n#: ../../link.rst:37 3336d65932154a7e8220f704075033f6\nmsgid \"\"\n\"*(Changed in version 1.16.9)* Allow specification without using a \"\n\"dictionary. The direct parameters are used if *border* is not a \"\n\"dictionary.\"\nmsgstr \"*（バージョン1.16.9で変更）* 辞書を使用せずに仕様を許可します。*border* が辞書でない場合、直接のパラメータが使用されます。\"\n\n#: ../../link.rst 25b24c0fd56f4c30b5aed0630d379730\n#: 9ee61ab2fe8942bfabb7ea27592c0b6d\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../link.rst:39 528de9f4f21d4757bc32323b7c87d926\nmsgid \"\"\n\"a dictionary as returned by the :attr:`border` property, with keys \"\n\"*\\\"width\\\"* (*float*), *\\\"style\\\"* (*str*) and *\\\"dashes\\\"* (*sequence*).\"\n\" Omitted keys will leave the resp. property unchanged. To e.g. remove \"\n\"dashing use: *\\\"dashes\\\": []*. If dashes is not an empty sequence, \"\n\"\\\"style\\\" will automatically be set to \\\"D\\\" (dashed).\"\nmsgstr \"\"\n\":attr:`border` プロパティによって返される辞書で、キー \"\n\"*\\\"width\\\"*（*浮動小数点*）、*\\\"style\\\"*（*str*）、*\\\"dashes\\\"*（*シーケンス*）を持っています。省略されたキーは、対応するプロパティを変更しません。例えば点線を削除するには、*「dashes」：[]*\"\n\" を使用します。dashes が空のシーケンスでない場合、「style」は自動的に \\\"D\\\"（点線）に設定されます。\"\n\n#: ../../link.rst:41 ../../link.rst:42 ../../link.rst:43 ../../link.rst:54\n#: 15adf27929424619b20cae84b36ad609 8795a2d1dc084425af561ecd4c4c5474\n#: b0c1d9cdb57843a98c0a60c9326e7883 c13273a1875d45e793d46962a4b7f884\nmsgid \"see above.\"\nmsgstr \"上記を参照してください。\"\n\n#: ../../link.rst:47 4f104147b1394836b55a5df9c3e2ab47\nmsgid \"PDF only: Changes the \\\"stroke\\\" color.\"\nmsgstr \"PDFのみ： \\\"stroke\\\" 色を変更します。\"\n\n#: ../../link.rst:49 16686de7e6af4e18ab0ae3e6db98bf9b\nmsgid \"\"\n\"In PDF, links are a subtype of annotations technically and **do not \"\n\"support fill colors**. However, to keep a consistent API, we do allow \"\n\"specifying a `fill=` parameter like with all annotations, which will be \"\n\"ignored with a warning.\"\nmsgstr \"\"\n\"PDFでは、リンクは技術的には注釈のサブタイプであり、**塗りつぶし色はサポートしていません**。ただし、一貫したAPIを維持するために、すべての注釈と同様に\"\n\" `fill=` パラメータを指定することを許可しており、警告とともに無視されます。\"\n\n#: ../../link.rst:51 59d3c81f089043dc9af7a58db867cfcc\nmsgid \"\"\n\"*(Changed in version 1.16.9)* Allow colors to be directly set. These \"\n\"parameters are used if *colors* is not a dictionary.\"\nmsgstr \"*(バージョン1.16.9で変更)*: 色を直接設定することを許可します。これらのパラメータは、*colors* が辞書でない場合に使用されます。\"\n\n#: ../../link.rst:53 8c2d9c9d399c48e98a0d4c825a606c31\nmsgid \"\"\n\"a dictionary containing color specifications. For accepted dictionary \"\n\"keys and values see below. The most practical way should be to first make\"\n\" a copy of the *colors* property and then modify this dictionary as \"\n\"required.\"\nmsgstr \"\"\n\"色仕様を含む辞書。受け入れられる辞書のキーと値については以下を参照してください。最も実用的な方法は、まず *colors* \"\n\"プロパティのコピーを作成し、必要に応じてこの辞書を修正することです。\"\n\n#: ../../link.rst:58 ../../link.rst:65 3104b3d644e844db944ae3665b6c89cb\n#: be4fe26181df4bd18dfb13ff2743cbac\nmsgid \"*New in v1.18.16*\"\nmsgstr \"*(新バージョン1.18.16で追加)*\"\n\n#: ../../link.rst:60 383edfd8cffc48289a05af780555e233\nmsgid \"\"\n\"Set the PDF `/F` property of the link annotation. See \"\n\":meth:`Annot.set_flags` for details. If not a PDF, this method is a no-\"\n\"op.\"\nmsgstr \"\"\n\"リンク注釈のPDF  `/F` プロパティを設定します。詳細については、:meth:`Annot.set_flags` \"\n\"を参照してください。PDFでない場合、このメソッドは無効です。\"\n\n#: ../../link.rst:67 8ace46d310c8449cb730957a35026758\nmsgid \"\"\n\"Return the link annotation flags, an integer (see :attr:`Annot.flags` for\"\n\" details). Zero if not a PDF.\"\nmsgstr \"リンク注釈フラグ、整数（詳細については :attr:`Annot.flags` を参照）。PDFでない場合、ゼロです。\"\n\n#: ../../link.rst:72 4f66fbc6806c4cc3afd7d0c728786903\nmsgid \"\"\n\"Meaningful for PDF only: A dictionary of two tuples of floats in range `0\"\n\" <= float <= 1` specifying the *stroke* and the interior (*fill*) colors.\"\n\" If not a PDF, ``None`` is returned. As mentioned above, the fill color \"\n\"is always `None` for links. The stroke color is used for the border of \"\n\"the link rectangle. The length of the tuple implicitly determines the \"\n\"colorspace: 1 = GRAY, 3 = RGB, 4 = CMYK. So `(1.0, 0.0, 0.0)` stands for \"\n\"RGB color red. The value of each float *f* is mapped to the integer value\"\n\" *i* in range 0 to 255 via the computation *f = i / 255*.\"\nmsgstr \"\"\n\"(意味があるのはPDFのみ): ストロークと内部（*塗りつぶし*）の色を指定する `0 <= float <= 1` \"\n\"の2つの浮動小数点数のタプルを含む辞書。PDFでない場合、``None`` が返されます。上記のように、リンクの塗りつぶしの色は常に `None`\"\n\" です。ストロークの色はリンクの境界のために使用されます。タプルの長さは暗黙的に色空間を決定します: 1 = GRAY、3 = RGB、4 = \"\n\"CMYK。したがって、 `(1.0、0.0、0.0)` はRGBカラーの赤を表します。各浮動小数点数 *f* の値は、*f = i / 255* \"\n\"の計算を介して範囲0から255の整数値 *i* にマップされます。\"\n\n#: ../../link.rst a7911594ade24fedb4eb4d5aa32134e3\n#: fd0f1aaed0b7451b864e11bf131bfc85\nmsgid \"Return type\"\nmsgstr \"戻り値のタイプ\"\n\n#: ../../link.rst:78 8c427c80ff3040929a19af74adb2502f\nmsgid \"\"\n\"Meaningful for PDF only: A dictionary containing border characteristics. \"\n\"It will be ``None`` for non-PDFs and an empty dictionary if no border \"\n\"information exists. The following keys can occur:\"\nmsgstr \"\"\n\"(意味があるのはPDFのみ): ボーダーの特性を含む辞書。非PDFの場合、またはボーダー情報が存在しない場合、``None`` \"\n\"になります。次のキーが含まれる場合があります:\"\n\n#: ../../link.rst:80 4a20f270fb5040f285e44464113e3f4e\nmsgid \"\"\n\"*width* -- a float indicating the border thickness in points. The value \"\n\"is -1.0 if no width is specified.\"\nmsgstr \"*width* - ポイント単位でのボーダーの厚さを示す浮動小数点数。幅が指定されていない場合、値は-1.0になります。\"\n\n#: ../../link.rst:82 031e7d00747b4e7f97f54d9125824c13\nmsgid \"\"\n\"*dashes* -- a sequence of integers specifying a line dash pattern. *[]* \"\n\"means no dashes, *[n]* means equal on-off lengths of *n* points, longer \"\n\"lists will be interpreted as specifying alternating on-off length values.\"\n\" See the :ref:`AdobeManual` page 126 for more detail.\"\nmsgstr \"\"\n\"*dashes* - ラインダッシュパターンを指定する整数のシーケンス。*[]* はダッシュがないことを意味し、*[n]* は \"\n\"*n*ポイントの等しいオンオフの長さを指定し、長いリストは交互にオンオフの長さ値を指定すると解釈されます。詳細については \"\n\":ref:`AdobeManual` のページ126を参照してください。\"\n\n#: ../../link.rst:84 b1ce9fb22af2473084abfad8dcc81664\nmsgid \"\"\n\"*style* -- 1-byte border style: *S* (Solid) = solid rectangle surrounding\"\n\" the annotation, *D* (Dashed) = dashed rectangle surrounding the link, \"\n\"the dash pattern is specified by the *dashes* entry, *B* (Beveled) = a \"\n\"simulated embossed rectangle that appears to be raised above the surface \"\n\"of the page, *I* (Inset) = a simulated engraved rectangle that appears to\"\n\" be recessed below the surface of the page, *U* (Underline) = a single \"\n\"line along the bottom of the annotation rectangle.\"\nmsgstr \"\"\n\"*style* - 1バイトのボーダースタイル: \"\n\"*S*（実線）=注釈を囲む実線の四角形、*D*（破線）=リンクを囲む破線の四角形、ダッシュパターンは *dashes* エントリで指定されます、 \"\n\"*B* （ベベル）=ページの表面から持ち上げられたように見える模倣の浮き彫りの四角形、 *I* \"\n\"（インセット）=ページの表面からくぼみがあるように見える模倣の刻まれた四角形、 *U* （下線）=注釈四角形の底部に沿った単一の線。\"\n\n#: ../../link.rst:90 f0b94d1fd724429f9db2c8920d74db77\nmsgid \"The area that can be clicked in untransformed coordinates.\"\nmsgstr \"クリックできる領域、変換されていない座標での\"\n\n#: ../../link.rst 275915bb29d54074a8eee5bb003e6f35\n#: 4cc4afb263e942e982a0c610ec312fed 61d480baed10423880ce97394eef1896\n#: 70b3b447b662426ca1084fb4942fc8f6 a60b7e4f00d946b98c5bd0406ac9f8cb\n#: b81ca89a6ed84d7a914f39bc42817ff7\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../link.rst:92 ef517da173d042b5b2f74bba55ab4cde\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect` （矩形）\"\n\n#: ../../link.rst:96 d54fc6555294411bab3c8c9b85b0fbcc\nmsgid \"\"\n\"A bool specifying whether the link target is outside of the current \"\n\"document.\"\nmsgstr \"現在の文書の外部にリンクの対象があるかどうかを指定するブール値。\"\n\n#: ../../link.rst:98 64dfe441deaf43ba9c1393ca9b801ce0\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../link.rst:102 23ce8eaf99fc4747a0d479729c096f79\nmsgid \"\"\n\"A string specifying the link target. The meaning of this property should \"\n\"be evaluated in conjunction with property `is_external`:\"\nmsgstr \"⚠️\"\n\n#: ../../link.rst:106 434842aad107476da3635f648121b5d5\n#, fuzzy\nmsgid \"\"\n\"`is_external` is true: `uri` points to some target outside the current \"\n\"PDF, which may be an internet resource (`uri` starts with ``http://`` or \"\n\"similar), another file (`uri` starts with \\\"file:\\\" or \\\"file://\\\") or \"\n\"some other service like an e-mail address (`uri` starts with \"\n\"``mailto:``).\"\nmsgstr \"⚠️\"\n\n#: ../../link.rst:112 9f133b2c3fce47338ccfeb9dad429fa6\nmsgid \"\"\n\"`is_external` is false: `uri` will be `None` or point to an internal \"\n\"location. In case of PDF documents, this should either be *#nnnn* to \"\n\"indicate a 1-based (!) page number *nnnn*, or a named location. The \"\n\"format varies for other document types, for example \"\n\"\\\"../FixedDoc.fdoc#PG_2_LNK_1\\\" for page number 2 (1-based) in an XPS \"\n\"document.\"\nmsgstr \"⚠️\"\n\n#: ../../link.rst:119 47f95869926845dfa68de8ffff9c59ab\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../link.rst:123 05b9e3e95335428f838140f7e0e85b7b\nmsgid \"An integer specifying the PDF :data:`xref`. Zero if not a PDF.\"\nmsgstr \"PDF :data:`xref` を指定する整数。PDFでない場合はゼロ。\"\n\n#: ../../link.rst:125 08dd0b407efc4037b5bf9715bf5410f4\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../link.rst:129 19952b4d82224998827923818129feeb\nmsgid \"The next link or ``None``.\"\nmsgstr \"次のリンクまたは ``None``。\"\n\n#: ../../link.rst:131 7091be260ac544a5955b3c6502751efb\nmsgid \"*Link*\"\nmsgstr \"*Link* （リンク）\"\n\n#: ../../link.rst:135 7dd1efb015df4899bf9b0392c76b6b6d\nmsgid \"The link destination details object.\"\nmsgstr \"リンクの対象の詳細オブジェクト。\"\n\n#: ../../link.rst:137 428b1356734c407883ebe43912f1f3ea\nmsgid \":ref:`linkDest`\"\nmsgstr \"\"\n\n#: ../../footer.rst:60 9de2e7e1b27c4242976413a45087b2a6\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"A string specifying the link target. \"\n#~ \"The meaning of this property should \"\n#~ \"be evaluated in conjunction with \"\n#~ \"property *isExternal*. The value may be\"\n#~ \" ``None``, in which case *isExternal \"\n#~ \"== False*. If *uri* starts with \"\n#~ \"*file://*, *mailto:*, or an internet \"\n#~ \"resource name, *isExternal* is ``True``. \"\n#~ \"In all other cases *isExternal == \"\n#~ \"False* and *uri* points to an \"\n#~ \"internal location. In case of PDF \"\n#~ \"documents, this should either be *#nnnn*\"\n#~ \" to indicate a 1-based (!) page \"\n#~ \"number *nnnn*, or a named location. \"\n#~ \"The format varies for other document \"\n#~ \"types, e.g. *uri = \"\n#~ \"'../FixedDoc.fdoc#PG_2_LNK_1'* for page number \"\n#~ \"2 (1-based) in an XPS document.\"\n#~ msgstr \"\"\n#~ \"リンクの対象を指定する文字列。このプロパティの意味は、プロパティ *isExternal* \"\n#~ \"と共に評価する必要があります。値が ``None`` の場合、*isExternal == \"\n#~ \"False* です。 *uri* が *file://、mailto:* \"\n#~ \"、またはインターネットリソース名で始まる場合、 *isExternal* は ``True`` \"\n#~ \"です。それ以外の場合、 *isExternal == False* で \"\n#~ \"*uri* は内部の場所を指します。PDF文書の場合、これは1から始まるページ番号 *nnnn* \"\n#~ \"を示すために *#nnnn* \"\n#~ \"であるか、名前付きの場所である必要があります。他の文書タイプの場合、フォーマットは異なります。たとえば、XPS文書の場合、 \"\n#~ \"*uri = '../FixedDoc.fdoc#PG_2_LNK_1'* \"\n#~ \"は、2ページ（1から始まる）を示します。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/linkdest.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 c9d403d602c14550a5468c49b79ec151\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 2ce574ba495d4bef8dfc597a774b5eb2\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 8d5420280aa04b0e82c737fe2879efc1\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../linkdest.rst:7 5be0406fa37d496c8d775d5c14ccbc9b\nmsgid \"linkDest\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:8 dbc5983be663459da1a305db6fd4b633\nmsgid \"\"\n\"Class representing the `dest` property of an outline entry or a link. \"\n\"Describes the destination to which such entries point.\"\nmsgstr \"アウトラインエントリまたはリンクの `dest` プロパティを表すクラス。これらのエントリが指す先の目的地を説明します。\"\n\n#: ../../linkdest.rst:10 fadcf1b2cb264b42a61422b1b39f9940\nmsgid \"\"\n\"Up to MuPDF v1.9.0 this class existed inside MuPDF and was dropped in \"\n\"version 1.10.0. For backward compatibility, PyMuPDF is still maintaining \"\n\"it, although some of its attributes are no longer backed by data actually\"\n\" available via MuPDF.\"\nmsgstr \"\"\n\"MuPDF \"\n\"v1.9.0まで、このクラスはMuPDF内に存在し、バージョン1.10.0で削除されました。後方互換性のため、PyMuPDFはそれを引き続き維持していますが、その属性のいくつかは実際にはMuPDFを介して利用可能なデータでバックアップされていないことに注意してください。\"\n\n#: ../../linkdest.rst:13 5cc4c7e9b4c94a61b74581d3ab546826\nmsgid \"**Attribute**\"\nmsgstr \"**属性**\"\n\n#: ../../linkdest.rst:13 2bb1dd6fb2e14d74b6262ace5e110a91\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../linkdest.rst:15 4f46e630676f4c0d9573cd5caeeeec87\nmsgid \":attr:`linkDest.dest`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:15 b8176d37e0ab4c298fa79512e4e04ca7\nmsgid \"destination\"\nmsgstr \"目的地\"\n\n#: ../../linkdest.rst:16 7d38469c9fd94cc5ae034b83b7dc6c89\nmsgid \":attr:`linkDest.fileSpec`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:16 c7535db1bddc446a8d9ec72cbe6ffee5\nmsgid \"file specification (path, filename)\"\nmsgstr \"ファイル仕様（パス、ファイル名）\"\n\n#: ../../linkdest.rst:17 09737ba6f55b4fd39a12293d1d0d3425\nmsgid \":attr:`linkDest.flags`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:17 b064dee65c8e4774b3aaf4042b4297e5\nmsgid \"descriptive flags\"\nmsgstr \"説明的なフラグ\"\n\n#: ../../linkdest.rst:18 4bcf60e4eab64157a425d9fc9067c73d\nmsgid \":attr:`linkDest.isMap`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:18 07f875efd9754adc83c776866a862b02\nmsgid \"is this a MAP?\"\nmsgstr \"これはMAPですか？\"\n\n#: ../../linkdest.rst:19 91af568ccac84cd5b4ee16d388bbb93e\nmsgid \":attr:`linkDest.isUri`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:19 ee75600c30be45058d58b89f78d55876\nmsgid \"is this a URI?\"\nmsgstr \"これはURIですか？\"\n\n#: ../../linkdest.rst:20 855d7ecb78564fbcbf4373cff63475fe\nmsgid \":attr:`linkDest.kind`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:20 8649be963579431cbf6b4132d29871dc\nmsgid \"kind of destination\"\nmsgstr \"目的地の種類\"\n\n#: ../../linkdest.rst:21 2e3bd4e2ae394a558dbc24ba2ac241b8\nmsgid \":attr:`linkDest.lt`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:21 704e8f3a402648918640ee171f22159a\nmsgid \"top left coordinates\"\nmsgstr \"左上の座標\"\n\n#: ../../linkdest.rst:22 e72f8149e16f4a28b4994101fa9458fa\nmsgid \":attr:`linkDest.named`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:22 7024a1c5676a4db182cde158adddcefd\nmsgid \"name if named destination\"\nmsgstr \"名前付き目的地の名前\"\n\n#: ../../linkdest.rst:23 a607a689ec9a430585a215fd17274636\nmsgid \":attr:`linkDest.newWindow`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:23 306056d18da1405fb16d64afcd5db2b1\nmsgid \"name of new window\"\nmsgstr \"新しいウィンドウの名前\"\n\n#: ../../linkdest.rst:24 0e354263696b4dea884ce7b0e8659268\nmsgid \":attr:`linkDest.page`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:24 709b2315bb6242709a51deccd9017a09\nmsgid \"page number\"\nmsgstr \"ページ番号\"\n\n#: ../../linkdest.rst:25 db8af5778b80458c8954ad3b5d8f4b1d\nmsgid \":attr:`linkDest.rb`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:25 cc7df48156634225ab78f47225de634e\nmsgid \"bottom right coordinates\"\nmsgstr \"右下の座標\"\n\n#: ../../linkdest.rst:26 9591bd156430496fa34539728e98f4f2\nmsgid \":attr:`linkDest.uri`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:26 cd8d4153a6044983bdc26e8c29c809ad\nmsgid \"URI\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:29 578749192c9f4502a4e8daf7c90af448\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../linkdest.rst:35 bcd161881123491fb6ea03b01fee7817\nmsgid \"\"\n\"Target destination name if :attr:`linkDest.kind` is :data:`LINK_GOTOR` \"\n\"and :attr:`linkDest.page` is *-1*.\"\nmsgstr \"\"\n\":attr:`linkDest.kind` が:data:`LINK_GOTOR` であり、:attr:`linkDest.page` が \"\n\"*-1* の場合、対象の宛先名。\"\n\n#: ../../linkdest.rst 24dee675d4504f8981a51fa2b8c9ae57\n#: 3c8f45e7a79841869726ce8c2db738bb 4e7db470641845cb993cb6d79edfc402\n#: 5282e07210cd45d1afe857765c18bb82 600998af429f4438b130f86a27543213\n#: 6190f4a6cbe547ee9bd7ce0672cbe0ea 6a314b30d1cd42cfb8ce9fbf698ea996\n#: 870a506b36024eee8203fa29ce90b30b a7317f9a30854058bcfea86fbe37948e\n#: cefd59f82f5344b9bb86d527d790c30d df60e9fbe1294169ba1907f3adf1b9ee\n#: f0cbb7037b834652bf39d488832ee865\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:37 ../../linkdest.rst:43 ../../linkdest.rst:79\n#: ../../linkdest.rst:103 5bb912195e6349f8b39f6b50f9cb244b\n#: 621a722c520f47be96d16809c80f9936 ef378de79abf404d8902449278613652\n#: f1c0a413cf6f4affa2d72ce50adf67ef\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:41 0d7b86556af7432ca01f62687b7105b8\nmsgid \"\"\n\"Contains the filename and path this link points to, if \"\n\":attr:`linkDest.kind` is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.\"\nmsgstr \"\"\n\":attr:`linkDest.kind` が :data:`LINK_GOTOR` または :data:`LINK_LAUNCH` \"\n\"の場合、このリンクが指すファイル名とパスが含まれています。\"\n\n#: ../../linkdest.rst:47 e82ff43942aa42d181926cc8311a04ad\nmsgid \"\"\n\"A bitfield describing the validity and meaning of the different aspects \"\n\"of the destination. As far as possible, link destinations are constructed\"\n\" such that e.g. :attr:`linkDest.lt` and :attr:`linkDest.rb` can be \"\n\"treated as defining a bounding box. But the flags indicate which of the \"\n\"values were actually specified, see :ref:`linkDest Flags`.\"\nmsgstr \"\"\n\"宛先のさまざまな側面の有効性と意味を説明するビットフィールド。できる限り、リンクの宛先は、:attr:`linkDest.lt` と \"\n\":attr:`linkDest.rb` \"\n\"をバウンディングボックスを定義するものとして扱えるように構築されています。ただし、フラグは、値のうち実際に指定されたものを示します。:ref:`linkDest\"\n\" Flags` を参照してください。\"\n\n#: ../../linkdest.rst:49 ../../linkdest.rst:67 ../../linkdest.rst:91\n#: 1e2a30929fb3424ca85ef2673484279a c4abce4eafe44aa48a61e88929d22db8\n#: e6f10f094da249a08f0b1da68a5ad807\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:53 5ca1397ac660408a8118784ff2e478e2\nmsgid \"\"\n\"This flag specifies whether to track the mouse position when the URI is \"\n\"resolved. Default value: False.\"\nmsgstr \"このフラグは、URIが解決されるときにマウスの位置を追跡するかどうかを指定します。デフォルト値：False。\"\n\n#: ../../linkdest.rst:55 ../../linkdest.rst:61 ../../linkdest.rst:85\n#: 03a9fad387d243f5936876e77a91a777 5d8a261398264f87bcb172afe9477166\n#: b1cc8e9c4d094ea7b9418b5001babd00\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:59 9653264615ef4612b74c934e94035162\nmsgid \"\"\n\"Specifies whether this destination is an internet resource (as opposed to\"\n\" e.g. a local file specification in URI format).\"\nmsgstr \"この宛先がインターネットリソースであるか（URI形式のローカルファイル仕様とは異なる場合）、指定します。\"\n\n#: ../../linkdest.rst:65 572624f8e5234fcfabe2886d19f59fb8\nmsgid \"\"\n\"Indicates the type of this destination, like a place in this document, a \"\n\"URI, a file launch, an action or a place in another file. Look at \"\n\":ref:`linkDest Kinds` to see the names and numerical values.\"\nmsgstr \"\"\n\"この宛先のタイプを示します。この文書内の場所、URI、ファイル起動、アクション、または他のファイル内の場所など。リンク宛先の種類を確認するには、:ref:`linkDest\"\n\" Kinds` を参照してください。\"\n\n#: ../../linkdest.rst:71 8df3c853090f4d899931e326f5459d67\nmsgid \"The top left :ref:`Point` of the destination.\"\nmsgstr \"宛先の左上の :ref:`Point` 。\"\n\n#: ../../linkdest.rst:73 ../../linkdest.rst:97 3c5d8c4d8bb041fc8c0f7572f332a8fa\n#: 4501f09bd6dd44348a5a0d661f366be0\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../linkdest.rst:77 35ddae2dc20442baa69cb10014649914\nmsgid \"\"\n\"This destination refers to some named action to perform (e.g. a \"\n\"javascript, see :ref:`AdobeManual`). Standard actions provided are \"\n\"*NextPage*, *PrevPage*, *FirstPage*,  and *LastPage*.\"\nmsgstr \"\"\n\"この宛先は実行する名前付きアクションを指します（たとえば、JavaScriptなど、:ref:`AdobeManual` \"\n\"を参照）。提供される標準アクションは、*NextPage*、*PrevPage*、*FirstPage*、および *LastPage* です。\"\n\n#: ../../linkdest.rst:83 8f9e7bda1b8f488aa95b2e92bbb2e3d2\nmsgid \"If true, the destination should be launched in a new window.\"\nmsgstr \"trueの場合、宛先は新しいウィンドウで起動する必要があります。\"\n\n#: ../../linkdest.rst:89 2a3bd78c3548465da36247eac48b559e\nmsgid \"\"\n\"The page number (in this or the target document) this destination points \"\n\"to. Only set if :attr:`linkDest.kind` is :data:`LINK_GOTOR` or \"\n\":data:`LINK_GOTO`. May be *-1* if :attr:`linkDest.kind` is \"\n\":data:`LINK_GOTOR`. In this case :attr:`linkDest.dest` contains the \"\n\"**name** of a destination in the target document.\"\nmsgstr \"\"\n\"この宛先が指すページ番号（この文書または対象の文書内）です。:attr:`linkDest.kind` が :data:`LINK_GOTOR` \"\n\"または :data:`LINK_GOTO` の場合にのみ設定されます。:attr:`linkDest.kind` が \"\n\":data:`LINK_GOTOR` の場合、*-1* になる場合があります。この場合、:attr:`linkDest.dest` \"\n\"には対象の文書内の宛先の名前が含まれます。\"\n\n#: ../../linkdest.rst:95 c402b9a2b14a499684cc75932a7b3061\nmsgid \"The bottom right :ref:`Point` of this destination.\"\nmsgstr \"この宛先の右下の :ref:`Point`。\"\n\n#: ../../linkdest.rst:101 efac7e980e8e403c9d1c9d57cd1420bc\nmsgid \"The name of the URI this destination points to.\"\nmsgstr \"この宛先が指すURIの名前。\"\n\n#: ../../footer.rst:60 d9aa1a371bcc4440af0a82a4a3ca0b1f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/lowlevel.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f8b51ec0649943efad8a9aad2f2ae5f0\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 f7f6d9b162764bd5bab35f0de0f68994\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 320005d084534805bbe61a078db61350\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../lowlevel.rst:5 4f2d1ec9ba784ccaaa499966f89668e5\nmsgid \"Low Level Functions and Classes\"\nmsgstr \"低レベルの関数とクラス\"\n\n#: ../../lowlevel.rst:6 b0646074fd384255aef9e51bfce2650a\nmsgid \"\"\n\"Contains a number of functions and classes for the experienced user. To \"\n\"be used for special needs or performance requirements.\"\nmsgstr \"経験豊富なユーザー向けの関数とクラスが多数含まれています。 特別なニーズやパフォーマンス要件に使用します。\"\n\n#: ../../footer.rst:60 4631787f1e8f470d9ab48b85edc12753\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/matrix.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 22b6a2a0571c4176bce077c545c814b3\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 73c9619ac3ee44d084a65d56842dc380\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 84065a34a4a14808906180f02e2efea2\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../matrix.rst:7 8a040befeffb44ac97583a22b00537bb\nmsgid \"Matrix\"\nmsgstr \"Matrix (マトリックス)\"\n\n#: ../../matrix.rst:9 8eb69980d89943bb8e94c77820ab6263\nmsgid \"\"\n\"Matrix is a row-major 3x3 matrix used by image transformations in MuPDF \"\n\"(which complies with the respective concepts laid down in the \"\n\":ref:`AdobeManual`). With matrices you can manipulate the rendered image \"\n\"of a page in a variety of ways: (parts of) the page can be rotated, \"\n\"zoomed, flipped, sheared and shifted by setting some or all of just six \"\n\"float values.\"\nmsgstr \"\"\n\"マトリックスは、MuPDFでの画像変換に使用される行優先の3x3マトリックスです（これは :ref:`AdobeManual` \"\n\"に規定されている対応するコンセプトに従っています）。マトリックスを使用することで、ページの描画画像をさまざまな方法で操作できます。ページの一部またはすべてを回転、拡大縮小、反転、せん断、シフトなどに設定することができます。これらの操作には、たった6つの浮動小数点数値のいくつかまたはすべてを設定します。\"\n\n#: ../../matrix.rst:12 99311bf26c5b4fd5b0df9afed1d8ff5a\n#, fuzzy\nmsgid \"\"\n\"Since all points or pixels live in a two-dimensional space, one column \"\n\"vector of that matrix is a constant unit vector, and only the remaining \"\n\"six elements are used for manipulations. These six elements are usually \"\n\"represented by `[a, b, c, d, e, f]`. Here is how they are positioned in \"\n\"the matrix:\"\nmsgstr \"\"\n\"すべてのポイントまたはピクセルは2次元の空間に存在するため、そのマトリックスの1つの列ベクトルは定数ユニットベクトルであり、操作に使用されるのは残りの6つの要素のみです。これらの6つの要素は通常、\"\n\" *[a、b、c、d、e、f]* で表されます。以下は、それらがマトリックス内でどのように配置されているかです。\"\n\n#: ../../matrix.rst:17 981036c6e6c24d00adc24601b311399b\nmsgid \"Please note:\"\nmsgstr \"注意点：\"\n\n#: ../../matrix.rst:19 f1ae75aa82ce4a989a3afb538b648bd5\nmsgid \"\"\n\"the below methods are just convenience functions -- everything they do, \"\n\"can also be achieved by directly manipulating the six numerical values\"\nmsgstr \"以下のメソッドは便宜的な機能であり、行うすべてのことは、6つの数値の値を直接操作しても実現できます。\"\n\n#: ../../matrix.rst:20 26c41674818040ab9d706c72f62e5b31\nmsgid \"\"\n\"all manipulations can be combined -- you can construct a matrix that \"\n\"rotates **and** shears **and** scales **and** shifts, etc. in one go. If \"\n\"you however choose to do this, do have a look at the **remarks** further \"\n\"down or at the :ref:`AdobeManual`.\"\nmsgstr \"\"\n\"すべての操作を組み合わせることができます。1回の操作で回転、せん断、スケール、シフトなどを同時に実行するマトリックスを構築できます。ただし、これを行う場合は、後での\"\n\" **注釈** または :ref:`AdobeManual` を参照してください。\"\n\n#: ../../matrix.rst:23 afd4ea95b6d34a6e914cc64e20f4259b\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド／属性**\"\n\n#: ../../matrix.rst:23 c34d2903bcee45ddb3cc5e621baefea0\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../matrix.rst:25 11abdcd6cd234d4fa95850fe12580df9\nmsgid \":meth:`Matrix.prerotate`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:25 80427e602a66422cac1da53c44af455f\nmsgid \"perform a rotation\"\nmsgstr \"回転を実行\"\n\n#: ../../matrix.rst:26 cad3e578828b433ba7ba0051be2032bf\nmsgid \":meth:`Matrix.prescale`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:26 a7e0bd6a201641fb912613e9f27fd76f\nmsgid \"perform a scaling\"\nmsgstr \"スケーリングを実行\"\n\n#: ../../matrix.rst:27 50c7f90d06004c62b19c6bff1b5a0ee9\nmsgid \":meth:`Matrix.preshear`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:27 10745ab48ff842fa86f0dba65a8ac4c9\nmsgid \"perform a shearing (skewing)\"\nmsgstr \"せん断（歪み）を実行\"\n\n#: ../../matrix.rst:28 b4c7cc3f2aff4f929fd556b21396c232\nmsgid \":meth:`Matrix.pretranslate`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:28 cefba85880554c02abc66d69a6a32faf\nmsgid \"perform a translation (shifting)\"\nmsgstr \"移動（シフト）を実行\"\n\n#: ../../matrix.rst:29 b3b9abc777594cf8b33d5290836afe88\nmsgid \":meth:`Matrix.concat`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:29 fe1f3aa66e6042309e54265e9b99b18d\nmsgid \"perform a matrix multiplication\"\nmsgstr \"マトリックスの乗算を実行\"\n\n#: ../../matrix.rst:30 fb89b2f56f6247ac8fc9b88f34f7e6c1\nmsgid \":meth:`Matrix.invert`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:30 4dab7517ebb647c78b179fbe83285a9f\nmsgid \"calculate the inverted matrix\"\nmsgstr \"反転されたマトリックスを計算\"\n\n#: ../../matrix.rst:31 3f0c29fd96594bd7824f5d9ab40c0fd7\nmsgid \":meth:`Matrix.norm`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:31 bee6a79c30594e5a9982c37569a07722\nmsgid \"the Euclidean norm\"\nmsgstr \"ユークリッドノルム\"\n\n#: ../../matrix.rst:32 b0e601bc11b94c5b978faf3969d20262\nmsgid \":attr:`Matrix.a`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:32 7bd503f42cb2438da182834d71fb2dd4\nmsgid \"zoom factor X direction\"\nmsgstr \"ズームファクターX方向\"\n\n#: ../../matrix.rst:33 b20b6e26dcf04b37bf9d3226d6b7720f\nmsgid \":attr:`Matrix.b`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:33 dc49e0f4424c40eaa3c9b116b0a0d20f\nmsgid \"shearing effect Y direction\"\nmsgstr \"せん断効果Y方向\"\n\n#: ../../matrix.rst:34 d2e19dfdd9104ec19d44f40c663bcc03\nmsgid \":attr:`Matrix.c`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:34 0a2f7dcd0de34db7a4c69a001674c37a\nmsgid \"shearing effect X direction\"\nmsgstr \"せん断効果X方向\"\n\n#: ../../matrix.rst:35 c72a8985cba049b487c8ffebefcf9d99\nmsgid \":attr:`Matrix.d`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:35 c1fe0a57201a4eb6ad2a830ae1b17b15\nmsgid \"zoom factor Y direction\"\nmsgstr \"ズームファクターY方向\"\n\n#: ../../matrix.rst:36 e471bd7cfd92424ab1e5f3e5059d4be9\nmsgid \":attr:`Matrix.e`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:36 d19ab3110ade4ac3b17c845a8c80fb37\nmsgid \"horizontal shift\"\nmsgstr \"水平シフト\"\n\n#: ../../matrix.rst:37 4a6eb68a255c4608873196c13298d411\nmsgid \":attr:`Matrix.f`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:37 0f0db520282844e9869b27e82d6fba11\nmsgid \"vertical shift\"\nmsgstr \"垂直シフト\"\n\n#: ../../matrix.rst:38 e75c12f64eee44059ea4b0762741fdb1\nmsgid \":attr:`Matrix.is_rectilinear`\"\nmsgstr \"\"\n\n#: ../../matrix.rst:38 bc57693d7a8c445eb2a7717732d081b9\nmsgid \"true if rect corners will remain rect corners\"\nmsgstr \"角の位置が直線のままの場合はTrue\"\n\n#: ../../matrix.rst:41 01aaa6a5cece41dd86f5e6c6f0d08b42\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../matrix.rst:59 56627216de1442368ffe90a40bd40b5a\nmsgid \"Overloaded constructors.\"\nmsgstr \"オーバーロードされたコンストラクター。\"\n\n#: ../../matrix.rst:61 ab9ade436b794d9cb70e8ec07c59573e\nmsgid \"\"\n\"Without parameters, the zero matrix *Matrix(0.0, 0.0, 0.0, 0.0, 0.0, \"\n\"0.0)* will be created.\"\nmsgstr \"パラメーターなしの場合、ゼロ行列 *Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)* が作成されます。\"\n\n#: ../../matrix.rst:63 0ff005031e87475e82c82f509a503432\nmsgid \"\"\n\"*zoom-** and *shear-** specify zoom or shear values (float) and create a \"\n\"zoom or shear matrix, respectively.\"\nmsgstr \"*zoom-** および *shear-** はズームまたはシアーの値（float）を指定し、それぞれズームまたはシアーの行列を作成します。\"\n\n#: ../../matrix.rst:65 3772827e3c4e46efaa66e0541654fbde\nmsgid \"For \\\"matrix\\\" a **new copy** of another matrix will be made.\"\nmsgstr \"\\\"matrix\\\" の場合、別の行列の **新しいコピー** が作成されます。\"\n\n#: ../../matrix.rst:67 e0de220e569d4fb192d61776da7cc98d\nmsgid \"\"\n\"Float value \\\"degree\\\" specifies the creation of a rotation matrix which \"\n\"rotates anti-clockwise.\"\nmsgstr \"浮動小数点値  \\\"degree\\\" は、反時計回りに回転する行列を作成することを指定します。\"\n\n#: ../../matrix.rst:69 202fbb08a1534f9b873b978d1ee2f25e\nmsgid \"\"\n\"A \\\"sequence\\\" must be any Python sequence object with exactly 6 float \"\n\"entries (see :ref:`SequenceTypes`).\"\nmsgstr \"\"\n\"\\\"sequence\\\" は、正確に 6 つの浮動小数点エントリを持つ任意の Python \"\n\"シーケンスオブジェクトである必要があります（:ref:`SequenceTypes`）。\"\n\n#: ../../matrix.rst:71 3290c36cfd044349b8b73b9a12b39105\n#, fuzzy\nmsgid \"\"\n\"*pymupdf.Matrix(1, 1)* and *pymupdf.Matrix(pymupdf.Identity)* create \"\n\"modifiable versions of the :ref:`Identity` matrix, which looks like *[1, \"\n\"0, 0, 1, 0, 0]*.\"\nmsgstr \"\"\n\"*pymupdf.Matrix(1, 1)*、*pymupdf.Matrix(0.0)* および \"\n\"*pymupdf.Matrix(pymupdf.Identity)*) は、*[1, 0, 0, 1, 0, 0]* のような \"\n\":ref:`Identity` マトリックスの修正可能なバージョンを作成します。\"\n\n#: ../../matrix.rst:75 2d27925e056c4beab39284c17c097dc8\nmsgid \"New in version 1.16.0\"\nmsgstr \"バージョン 1.16.0 で新規追加\"\n\n#: ../../matrix.rst:77 23099b3eeb904d19a2fca93ba4ff4ac2\nmsgid \"Return the Euclidean norm of the matrix as a vector.\"\nmsgstr \"ベクトルとしての行列のユークリッドノルムを返します。\"\n\n#: ../../matrix.rst:81 cf82a48349524343a3a9fb35951b2482\nmsgid \"\"\n\"Modify the matrix to perform a counter-clockwise rotation for positive \"\n\"*deg* degrees, else clockwise. The matrix elements of an identity matrix \"\n\"will change in the following way:\"\nmsgstr \"\"\n\"マトリックスを修正して、正の *deg* \"\n\"度の場合は反時計回りに、それ以外の場合は時計回りに回転します。アイデンティティマトリックスの行列要素は以下のように変更されます：\"\n\n#: ../../matrix.rst:83 a024346df65d49e7bcdef1a35d0f0ea9\nmsgid \"*[1, 0, 0, 1, 0, 0] -> [cos(deg), sin(deg), -sin(deg), cos(deg), 0, 0]*.\"\nmsgstr \"*[1, 0, 0, 1, 0, 0] -> [cos(deg), sin(deg), -sin(deg), cos(deg), 0, 0]*。\"\n\n#: ../../matrix.rst 0e2caa4b969d4e8c883315663dfbb010\n#: 2a76f7fdef494d7cb96fb9bcb0b288a0 44ed05851fab4cd4b3017cd0b82bc4f4\n#: 797389fbee9c42f6a11d44d628804863 c8b2675c06ee43c4abcd46c105be0f19\n#: e6e50d5d62724013ba993ce51b6e65a8\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../matrix.rst:85 34bf9b5e70b9486285ffd6799c5556ca\nmsgid \"\"\n\"The rotation angle in degrees (use conventional notation based on Pi = \"\n\"180 degrees).\"\nmsgstr \"度単位での回転角度（180度ベースの従来の表記法を使用します）。\"\n\n#: ../../matrix.rst:89 94eb659613c24f939142b8fc6dd19ab4\nmsgid \"\"\n\"Modify the matrix to scale by the zoom factors sx and sy. Has effects on \"\n\"attributes *a* thru *d* only: *[a, b, c, d, e, f] -> [a*sx, b*sx, c*sy, \"\n\"d*sy, e, f]*.\"\nmsgstr \"\"\n\"マトリックスを修正してズームファクター sx および sy でスケーリングします。属性 *a* から *d* にのみ影響を与えます： *[a, \"\n\"b, c, d, e, f] -> [a*sx, b*sx, c*sy, d*sy, e, f]*。\"\n\n#: ../../matrix.rst:91 72c725939ccb4e8b90b12926ae88abec\nmsgid \"\"\n\"Zoom factor in X direction. For the effect see description of attribute \"\n\"*a*.\"\nmsgstr \"X方向のズームファクター。効果については属性 *a* の説明を参照してください。\"\n\n#: ../../matrix.rst:93 2ef911aad48643e18db6f643f2613c9a\nmsgid \"\"\n\"Zoom factor in Y direction. For the effect see description of attribute \"\n\"*d*.\"\nmsgstr \"Y方向のズームファクター。効果については属性 *d* の説明を参照してください。\"\n\n#: ../../matrix.rst:97 a47d6e8530894f2aac1846c0416c7f14\nmsgid \"\"\n\"Modify the matrix to perform a shearing, i.e. transformation of \"\n\"rectangles into parallelograms (rhomboids). Has effects on attributes *a*\"\n\" thru *d* only: *[a, b, c, d, e, f] -> [c*sy, d*sy, a*sx, b*sx, e, f]*.\"\nmsgstr \"\"\n\"行列を修正して、シアリング、つまり長方形を平行四辺形（ひし形）に変換する操作を実行します。属性 *a* から *d* にのみ影響を与えます： \"\n\"*[a, b, c, d, e, f] -> [c*sy, d*sy, a*sx, b*sx, e, f]*。\"\n\n#: ../../matrix.rst:99 7af0396c77db4280bd8b6ef9764cab2d\nmsgid \"Shearing effect in X direction. See attribute *c*.\"\nmsgstr \"X 方向のシアリング効果。属性 *c* を参照してください。\"\n\n#: ../../matrix.rst:101 5a8d7d2b58c348f0bf481d54d9ff5b01\nmsgid \"Shearing effect in Y direction. See attribute *b*.\"\nmsgstr \"Y 方向のシアリング効果。属性 *b* を参照してください。\"\n\n#: ../../matrix.rst:105 152c5f45800e42b6a038fee68ba116d4\nmsgid \"\"\n\"Modify the matrix to perform a shifting / translation operation along the\"\n\" x and / or y axis. Has effects on attributes *e* and *f* only: *[a, b, \"\n\"c, d, e, f] -> [a, b, c, d, tx*a + ty*c, tx*b + ty*d]*.\"\nmsgstr \"\"\n\"X 軸および / または Y 軸に沿ったシフト / 移動操作を実行するために行列を修正します。属性 *e* と *f* にのみ影響を与えます： \"\n\"*[a, b, c, d, e, f] -> [a, b, c, d, tx*a + ty*c, tx*b + ty*d]* 。\"\n\n#: ../../matrix.rst:107 8b15e98fb7734d2fb7d3a90c734616fd\nmsgid \"Translation effect in X direction. See attribute *e*.\"\nmsgstr \"X 方向の移動効果。属性 *e* を参照してください。\"\n\n#: ../../matrix.rst:109 1ac03cdeaadf47039b40d141265dad51\nmsgid \"Translation effect in Y direction. See attribute *f*.\"\nmsgstr \"Y 方向の移動効果。属性 *f* を参照してください。\"\n\n#: ../../matrix.rst:113 a7232949340949e6bee6b5a75b157849\nmsgid \"\"\n\"Calculate the matrix product *m1 * m2* and store the result in the \"\n\"current matrix. Any of *m1* or *m2* may be the current matrix. Be aware \"\n\"that matrix multiplication is not commutative. So the sequence of *m1*, \"\n\"*m2* is important.\"\nmsgstr \"\"\n\"行列の積 *m1* * *m2* を計算し、その結果を現在の行列に格納します。*m1* または *m2* \"\n\"のいずれかが現在の行列である場合があります。行列の乗算は可換ではないことに注意してください。したがって、*m1*、*m2* の順序が重要です。\"\n\n#: ../../matrix.rst:115 c868c7bce6e24c17aefb279a2b589bad\nmsgid \"First (left) matrix.\"\nmsgstr \"最初の（左側）行列。\"\n\n#: ../../matrix.rst:118 6a23a720cc824c018154df578fbe2287\nmsgid \"Second (right) matrix.\"\nmsgstr \"2 番目の（右側）行列。\"\n\n#: ../../matrix.rst:123 c1c62753df994db5a29eaf60b74d5311\nmsgid \"\"\n\"Calculate the matrix inverse of *m* and store the result in the current \"\n\"matrix. Returns *1* if *m* is not invertible (\\\"degenerate\\\"). In this \"\n\"case the current matrix **will not change**. Returns *0* if *m* is \"\n\"invertible, and the current matrix is replaced with the inverted *m*.\"\nmsgstr \"\"\n\"行列 *m* の逆行列を計算し、その結果を現在の行列に格納します。*m* が逆行列を持たない場合（\\\"degenerate\\\"）は 1 \"\n\"を返します。この場合、現在の行列は *変更されません* 。m が逆行列を持つ場合は 0 を返し、現在の行列は m の逆行列で置き換えられます。\"\n\n#: ../../matrix.rst:125 6f3f8c966b71407b9e3b02488f7f4034\nmsgid \"Matrix to be inverted. If not provided, the current matrix will be used.\"\nmsgstr \"逆行列を計算する行列。提供されない場合、現在の行列が使用されます。\"\n\n#: ../../matrix.rst e8077cac107d4551bdd9b1c1d14a4952\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../matrix.rst:132 db229e59a31b455b98ea5ccfa578122a\nmsgid \"\"\n\"Scaling in X-direction **(width)**. For example, a value of 0.5 performs \"\n\"a shrink of the **width** by a factor of 2. If a < 0, a left-right flip \"\n\"will (additionally) occur.\"\nmsgstr \"X方向 **（幅）** のスケーリング。たとえば、0.5の値は **幅** を2倍に縮小します。a < 0の場合、左右反転が追加で発生します。\"\n\n#: ../../matrix.rst 6fcedf91827d4c289e6a645364d76ea6\n#: 8654b40d08014804b0c0e8c304580291 96cbe6754a4b4f99bb7e0e80e180c0a6\n#: afc20c369a9f4c739bc1f16197754859 c2c0c17a6a334d9daf1a246b0a95ca15\n#: fab66c3105f3412b8e17b401ecfe57ab fceb1d67502e44b49baa260b088dd68f\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../matrix.rst:134 ../../matrix.rst:140 ../../matrix.rst:146\n#: ../../matrix.rst:152 ../../matrix.rst:158 ../../matrix.rst:164\n#: 137024cc37b74d68971a780ab821bb5c 20de69effd914f3f92727bc07f7de025\n#: 5804209069a04b28ae858ceb0466f4d1 5b5b333b8cb346858ac4e11335709c2a\n#: 789de033d5c0443997dabc1c08157dbc 867fd680a9e9402583480286d03e27ca\nmsgid \"float\"\nmsgstr \"\"\n\n#: ../../matrix.rst:138 c229f8ba4d804490b761e624fe313b6d\nmsgid \"\"\n\"Causes a shearing effect: each `Point(x, y)` will become `Point(x, y - \"\n\"b*x)`. Therefore, horizontal lines will be \\\"tilt\\\".\"\nmsgstr \"\"\n\"シアリング効果を引き起こします：各 `Point(x, y)` は `Point(x、y - b * x)` \"\n\"になります。したがって、水平線は「傾斜」します。\"\n\n#: ../../matrix.rst:144 7b98255d69974126bcf901feb1b268f6\nmsgid \"\"\n\"Causes a shearing effect: each `Point(x, y)` will become `Point(x - c*y, \"\n\"y)`. Therefore, vertical lines will be \\\"tilt\\\".\"\nmsgstr \"\"\n\"シアリング効果を引き起こします：各 `Point(x, y)` は `Point(x - c * y、y)` \"\n\"になります。したがって、垂直線は「傾斜」します。\"\n\n#: ../../matrix.rst:150 ac4f38489ad847b7827dcac0e26521a5\nmsgid \"\"\n\"Scaling in Y-direction **(height)**. For example, a value of 1.5 performs\"\n\" a stretch of the **height** by 50%. If d < 0, an up-down flip will \"\n\"(additionally) occur.\"\nmsgstr \"Y方向 **（高さ）** でのスケーリング。たとえば、1.5の値は **高さ** を50％伸ばします。d < 0の場合、上下反転が追加で発生します。\"\n\n#: ../../matrix.rst:156 9660c53c0df84ae99b72badb3989dddf\nmsgid \"\"\n\"Causes a horizontal shift effect: Each *Point(x, y)* will become *Point(x\"\n\" + e, y)*. Positive (negative) values of *e* will shift right (left).\"\nmsgstr \"\"\n\"水平シフト効果を引き起こします：各 *Point(x, y)* は *Point(x + e、y)* \"\n\"になります。eの正の（負の）値は右に（左に）シフトします。\"\n\n#: ../../matrix.rst:162 96c71528239744f1b8cd967c2e46cb62\nmsgid \"\"\n\"Causes a vertical shift effect: Each *Point(x, y)* will become *Point(x, \"\n\"y - f)*. Positive (negative) values of *f* will shift down (up).\"\nmsgstr \"\"\n\"垂直シフト効果を引き起こします：各 *Point(x, y)* は *Point(x、y - f)* になります。*f* \"\n\"の正の（負の）値は下に（上に）シフトします。\"\n\n#: ../../matrix.rst:168 fbbefd1680244e43b84002ed9a436dec\nmsgid \"\"\n\"Rectilinear means that no shearing is present and that any rotations are \"\n\"integer multiples of 90 degrees. Usually this is used to confirm that \"\n\"(axis-aligned) rectangles before the transformation are still axis-\"\n\"aligned rectangles afterwards.\"\nmsgstr \"矩形の意味は、シアリングが存在せず、回転が90度の整数倍であることを示します。通常、これは変換前の（軸に沿った）矩形が変換後も軸に沿った矩形であることを確認するために使用されます。\"\n\n#: ../../matrix.rst:170 36d4d94103214600af41eafe39212e90\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../matrix.rst:174 90ffe958045f48d090dba5ba44f73165\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"\"\n\"このクラスはPythonのシーケンスプロトコルに従っているため、コンポーネントにはインデックスを使用できます。また、:ref:`SequenceTypes`\"\n\" を参照してください。\"\n\n#: ../../matrix.rst:175 ae28f509b9434158ad3509b43fcadd26\nmsgid \"\"\n\"Matrices can be used with arithmetic operators almost like ordinary \"\n\"numbers: they can be added, subtracted, multiplied or divided -- see \"\n\"chapter :ref:`Algebra`.\"\nmsgstr \"\"\n\"行列は、通常の数値のようにほとんどの算術演算子を使用して操作できます。行列は加算、減算、乗算、または除算できます。ジオメトリオブジェクトの \"\n\":ref:`Algebra`。\"\n\n#: ../../matrix.rst:176 8bec4a086d304bbb9bfd022e4556dd29\nmsgid \"\"\n\"Matrix multiplication is **not commutative** -- changing the sequence of \"\n\"the multiplicands will change the result in general. So it can quickly \"\n\"become unclear which result a transformation will yield.\"\nmsgstr \"\"\n\"行列の乗算は \"\n\"**可換ではありません**。乗算要因のシーケンスを変更すると、一般に結果が変わります。そのため、変換がどの結果を生じるかがすぐに不明確になることがあります。\"\n\n#: ../../matrix.rst:180 281fd31e543c4617a40894e7ac37597e\nmsgid \"Examples\"\nmsgstr \"例\"\n\n#: ../../matrix.rst:181 401084daabc9429b9009d38c9e0f2aec\nmsgid \"\"\n\"Here are examples that illustrate some of the achievable effects. All \"\n\"pictures show some text, inserted under control of some matrix and \"\n\"relative to a fixed reference point (the red dot).\"\nmsgstr \"以下は、いくつかの可能な効果を示す例です。すべての図は、固定された参照点（赤いドット）に対するある行列の制御下で挿入されたテキストを示しています。\"\n\n#: ../../matrix.rst:183 ef95f7140bc84ceb80f3fe9cc5ffe0d2\nmsgid \"The :ref:`Identity` matrix performs no operation.\"\nmsgstr \":ref:`Identity` 行列は操作を行いません。\"\n\n#: ../../matrix.rst:188 a80fc2a091374e8cb6815dfe8672bddd\nmsgid \"\"\n\"The scaling matrix `Matrix(2, 0.5)` stretches by a factor of 2 in \"\n\"horizontal, and shrinks by factor 0.5 in vertical direction.\"\nmsgstr \"スケーリング行列 `Matrix(2, 0.5)` は、水平方向に2倍の拡大を行い、垂直方向には0.5倍の縮小を行います。\"\n\n#: ../../matrix.rst:193 9699134c66a146af9068adb90948b8f2\nmsgid \"\"\n\"Attributes :attr:`Matrix.e` and :attr:`Matrix.f` shift horizontally and, \"\n\"respectively vertically. In the following 10 to the right and 20 down.\"\nmsgstr \"\"\n\"属性 :attr:`Matrix.e` および :attr:`Matrix.f` \"\n\"は、それぞれ水平方向および垂直方向にシフトします。以下の場合、右に10、下に20シフトします。\"\n\n#: ../../matrix.rst:198 168fe9a931a94651ac55f633dffbe987\nmsgid \"A negative :attr:`Matrix.a` causes a left-right flip.\"\nmsgstr \"負の :attr:`Matrix.a` は左右反転を引き起こします。\"\n\n#: ../../matrix.rst:203 f2cb4722af2e45f6ac67fda814935ea4\nmsgid \"A negative :attr:`Matrix.d` causes an up-down flip.\"\nmsgstr \"負の :attr:`Matrix.d` は上下反転を引き起こします。\"\n\n#: ../../matrix.rst:208 28cc582a5ec24205816af0c892b692d1\nmsgid \"Attribute :attr:`Matrix.b` tilts upwards / downwards along the x-axis.\"\nmsgstr \"属性 M :attr:`Matrix.b` はx軸に沿って上向き/下向きに傾きます。\"\n\n#: ../../matrix.rst:213 a2b77644fc61456690d3603561dae948\nmsgid \"Attribute :attr:`Matrix.c` tilts left / right along the y-axis.\"\nmsgstr \"属性 :attr:`Matrix.c` はy軸に沿って左に傾く/右に傾きます。\"\n\n#: ../../matrix.rst:218 bd842bfbd48b44509584185764d44373\nmsgid \"\"\n\"Matrix `Matrix(beta)` performs counterclockwise rotations for positive \"\n\"angles `beta`.\"\nmsgstr \"Matrix `Matrix(beta)` は、正の角度 `beta` の反時計回りの回転を実行します。\"\n\n#: ../../matrix.rst:223 ac0b2cc97b1347ab9f63fa8f97f50072\nmsgid \"Show some effects on a rectangle::\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 2a49496b580540908297c502618954b2\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/module.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 62136ba5c5a74ecfa227336e448d62b5\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 6fc9c3c622e84783910d3b11c3709f37\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 d611277d72c64dd99b3b9f2f8ec96367\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../module.rst:7 f33c4cbb9f05422084dddcddaf87949a\nmsgid \"Command line interface\"\nmsgstr \"\"\n\n#: ../../module.rst:9 9f557fd4350a42ed9a1df58860be9669\nmsgid \"New in version 1.16.8\"\nmsgstr \"バージョン 1.16.8 で新たに追加されました\"\n\n#: ../../module.rst:11 ecd7d23131464943807a4fb959173755\nmsgid \"\"\n\"PyMuPDF can also be used from the command line to perform utility \"\n\"functions. This feature should obsolete writing some of the most basic \"\n\"scripts.\"\nmsgstr \"PyMuPDFは、ユーティリティ機能を実行するためにモジュールとしてコマンドラインで使用することもできます。この機能により、最も基本的なスクリプトの記述が廃止される可能性があります。\"\n\n#: ../../module.rst:13 20b8d208b65e4c74bf7ad83bfb388393\nmsgid \"\"\n\"Admittedly, there is some functional overlap with the MuPDF CLI `mutool`.\"\n\" On the other hand, PDF embedded files are no longer supported by MuPDF, \"\n\"so PyMuPDF is offering something unique here.\"\nmsgstr \"\"\n\"確かに、MuPDF CLI  `mutool`  \"\n\"といくつかの機能的な重複があります。一方で、PDFの埋め込みファイルはもはやMuPDFではサポートされていないため、PyMuPDFはここで独自の機能を提供しています。\"\n\n#: ../../module.rst:16 61944c3cbe72440580bdadeeb1269b75\nmsgid \"Invocation\"\nmsgstr \"呼び出し\"\n\n#: ../../module.rst:18 295dfa35e12a40d48e27c0055204d5a7\nmsgid \"The command-line interface can be invoked in two ways.\"\nmsgstr \"コマンドラインインターフェースは2つの方法で呼び出すことができます。\"\n\n#: ../../module.rst:20 7177082a690146019882a6b232aa8853\nmsgid \"Use the installed `pymupdf` command::\"\nmsgstr \"インストールされた `pymupdf` のコマンドを使用します。\"\n\n#: ../../module.rst:24 87e819afc653442caceed77952e1ed58\nmsgid \"Or use Python's `-m` switch with PyMuPDF's `pymupdf` module::\"\nmsgstr \"\"\n\n#: ../../module.rst:31 c1e7f23de6ef452a83faa31ed988d657\nmsgid \"General remarks:\"\nmsgstr \"一般的な注意事項：\"\n\n#: ../../module.rst:33 fd3bac8dc3e9421eb2371c451ec1c3da\nmsgid \"\"\n\"Request help via `\\\"-h\\\"`, resp. command-specific help via `\\\"command \"\n\"-h\\\"`.\"\nmsgstr \"ヘルプを要求するには、`\\\"-h\\\"` 、またはコマンド固有のヘルプを要求するには `\\\"command -h\\\"` を使用します。\"\n\n#: ../../module.rst:34 dbd5a72f66d84df5b18b6bec2f4fd2f5\nmsgid \"Parameters may be abbreviated where this does not introduce ambiguities.\"\nmsgstr \"曖昧さが生じない場所では、パラメータは省略形で指定できます。\"\n\n#: ../../module.rst:35 73cd69c626714f7aa1e084d11447cea6\nmsgid \"\"\n\"Several commands support parameters `-pages` and `-xrefs`. They are \"\n\"intended for down-selection. Please note that:\"\nmsgstr \"\"\n\"いくつかのコマンドは、 `-pages` と  `-xrefs`  \"\n\"のパラメータをサポートしています。これらは選択範囲を絞るためのものです。以下に注意してください：\"\n\n#: ../../module.rst:37 7ff6972a285a4695baa4e4276641b755\nmsgid \"**page numbers** for this utility must be given **1-based**.\"\nmsgstr \"このユーティリティでは、**ページ番号** は1から始まる必要があります。\"\n\n#: ../../module.rst:38 b9688dc1937342d0a9ba2a88937c6d0a\nmsgid \"valid :data:`xref` numbers start at 1.\"\nmsgstr \"有効な  :data:`xref`  番号は1から始まります。\"\n\n#: ../../module.rst:39 7c0c1890d37b41f6820770dd6bed4376\nmsgid \"\"\n\"Specify a comma-separated list of either *single* integers or integer \"\n\"*ranges*. A **range** is a pair of integers separated by one hyphen \"\n\"\\\"-\\\". Integers must not exceed the maximum page, resp. xref number. To \"\n\"specify that maximum, the symbolic variable \\\"N\\\" may be used. Integers \"\n\"or ranges may occur several times, in any sequence and may overlap. If in\"\n\" a range the first number is greater than the second one, the respective \"\n\"items will be processed in reversed order.\"\nmsgstr \"\"\n\"シングル整数または整数の範囲のコンマ区切りのリストを指定します。範囲は、ハイフン \\\" - \\\" \"\n\"で区切られた整数のペアです。整数は、最大ページまたは xref 番号を超えてはいけません。最大値を指定するには、記号変数 \\\"N\\\" \"\n\"を使用できます。整数または範囲は複数回、任意の順序で重複して出現する可能性があります。範囲内の最初の数値が2番目の数値よりも大きい場合、それらのアイテムは逆順で処理されます。\"\n\n#: ../../module.rst:41 ee46edb0ea2b44e98364d207aaa2d1ef\nmsgid \"How to use the module inside your script::\"\nmsgstr \"スクリプト内でモジュールを使用する方法::\"\n\n#: ../../module.rst:50 123a2e5ad2564826b878adadaf638eeb\nmsgid \"\"\n\"Use the following 2-liner and compile it with `Nuitka \"\n\"<https://pypi.org/project/Nuitka/>`_ in standalone mode. This will give \"\n\"you a CLI executable with all the module's features, that can be used on \"\n\"all compatible platforms without Python, PyMuPDF or MuPDF being \"\n\"installed.\"\nmsgstr \"\"\n\"以下の2行のコードを使用し、 `Nuitka <https://pypi.org/project/Nuitka/>`_ \"\n\"をスタンドアロンモードでコンパイルします。これにより、Python、PyMuPDF、またはMuPDFがインストールされていないすべての互換プラットフォームで使用できる、モジュールのすべての機能を備えたCLI実行可能ファイルが得られます。\"\n\n#: ../../module.rst:59 621c5379e7d44e29a5ae735c58352834\nmsgid \"Cleaning and Copying\"\nmsgstr \"クリーニングとコピー\"\n\n#: ../../module.rst:63 a41c329fb87940c482d0805086ecc3cf\nmsgid \"\"\n\"This command will optimize the PDF and store the result in a new file. \"\n\"You can use it also for encryption, decryption and creating sub \"\n\"documents. It is mostly similar to the MuPDF command line utility \"\n\"*\\\"mutool clean\\\"*::\"\nmsgstr \"\"\n\"このコマンドは、PDFを最適化し、その結果を新しいファイルに保存します。また、暗号化、復号化、およびサブドキュメントの作成にも使用できます。これは、ほとんど\"\n\" MuPDF のコマンドラインユーティリティ \\\"mutool clean\\\" と似ています::\"\n\n#: ../../module.rst:96 95c61ecff9474da7a32002be18ff00b3\nmsgid \"\"\n\"If you specify \\\"-pages\\\", be aware that only page-related objects are \"\n\"copied, **no document-level items** like e.g. embedded files.\"\nmsgstr \"「-pages」を指定する場合、ページ関連のオブジェクトのみがコピーされることに注意してください。埋め込みファイルのようなドキュメントレベルのアイテムはコピーされません。\"\n\n#: ../../module.rst:98 958ae9bd4e2244ae9cbb5d24a62a8c94\nmsgid \"Please consult :meth:`Document.save` for the parameter meanings.\"\nmsgstr \"パラメータの意味については、 :meth:`Document.save` をご参照ください。\"\n\n#: ../../module.rst:102 5b59f04532e94259bf5b3ecd530ca408\nmsgid \"Extracting Fonts and Images\"\nmsgstr \"フォントと画像の抽出\"\n\n#: ../../module.rst:103 170896a4fb624362bfbd8172cf909da4\nmsgid \"Extract fonts or images from selected PDF pages to a desired directory::\"\nmsgstr \"選択したPDFページからフォントや画像を指定したディレクトリに抽出します::\"\n\n#: ../../module.rst:123 220fe33385e844f3928ec0625f051414\nmsgid \"\"\n\"**Image filenames** are built according to the naming scheme: **\\\"img-\"\n\"xref.ext\\\"**, where \\\"ext\\\" is the extension associated with the image \"\n\"and \\\"xref\\\" the :data:`xref` of the image PDF object.\"\nmsgstr \"\"\n\"**画像のファイル名** は、命名規則に従って構築されます： **\\\"img-xref.ext\\\"** で、\\\"ext\\\" \"\n\"は画像に関連する拡張子であり、\\\"xref\\\" は画像PDFオブジェクトの :data:`xref` です。\"\n\n#: ../../module.rst:125 d56994d8f2a8433280e4ef35819f2e7a\nmsgid \"\"\n\"**Font filenames** consist of the fontname and the associated extension. \"\n\"Any spaces in the fontname are replaced with hyphens \\\"-\\\".\"\nmsgstr \"\"\n\"**フォントのファイル名** は、フォント名と関連する拡張子から構成されます。フォント名にスペースがある場合、ハイフン \\\"-\\\" \"\n\"で置き換えられます。\"\n\n#: ../../module.rst:127 a8e1a30f5fde401d810825a6e3b01a09\nmsgid \"The output directory must already exist.\"\nmsgstr \"出力ディレクトリはすでに存在している必要があります。\"\n\n#: ../../module.rst:129 f2bc1eaf74014a2c9c0473449a9e7b11\nmsgid \"\"\n\"Except for output directory creation, this feature is **functionally \"\n\"equivalent** to and obsoletes `this script <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-\"\n\"pages.py>`_.\"\nmsgstr \"\"\n\"出力ディレクトリの作成を除いて、この機能は `このスクリプト <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_ \"\n\"と機能的に同等であり、これを使うことで廃止できます。\"\n\n#: ../../module.rst:133 b52a0c02382d4e9abbd491e7b26f50d8\nmsgid \"Joining PDF Documents\"\nmsgstr \"PDF文書の結合\"\n\n#: ../../module.rst:134 b52dba2292bb478f86d8bd2a68e72d49\nmsgid \"To join several PDF files specify::\"\nmsgstr \"複数のPDFファイルを結合するには、次のように指定します::\"\n\n#: ../../module.rst:153 e75a700cceee42eda662850bcb411254\nmsgid \"\"\n\"Each input must be entered as **\\\"filename,password,pages\\\"**. Password \"\n\"and pages are optional.\"\nmsgstr \"各入力は「ファイル名、パスワード、ページ」の形式で入力してください。パスワードとページはオプションです。\"\n\n#: ../../module.rst:154 5bbc4bbfbbe44ea29ce63dc28468ecde\nmsgid \"\"\n\"The password entry **is required** if the \\\"pages\\\" entry is used. If the\"\n\" PDF needs no password, specify two commas.\"\nmsgstr \"パスワードエントリは「ページ」エントリが使用される場合に必要です。PDFにパスワードが必要ない場合は、2つのコンマを指定してください。\"\n\n#: ../../module.rst:155 24124b66f3f9496c9cba03a6c3987619\nmsgid \"\"\n\"The **\\\"pages\\\"** format is the same as explained at the top of this \"\n\"section.\"\nmsgstr \"「ページ」のフォーマットは、このセクションの先頭で説明したものと同じです。\"\n\n#: ../../module.rst:156 6c8cd3be3fd844a18d6859e34270344c\nmsgid \"\"\n\"Each input file is immediately closed after use. Therefore you can use \"\n\"one of them as output filename, and thus overwrite it.\"\nmsgstr \"各入力ファイルは使用後すぐに閉じられます。したがって、出力ファイル名の1つとして使用し、上書きすることができます。\"\n\n#: ../../module.rst:159 62faf24e6a7143aca5c2f6d4d0a3bd13\nmsgid \"Example: To join the following files\"\nmsgstr \"例: 以下のファイルを結合する\"\n\n#: ../../module.rst:161 088838df3b2545f8801c172c3bc996f0\nmsgid \"**file1.pdf:** all pages, back to front, no password\"\nmsgstr \"**file1.pdf:** すべてのページ、最前面から最後尾、パスワードなし\"\n\n#: ../../module.rst:162 72f4cc0b55a64f16a43ce016fb9d46a0\nmsgid \"**file2.pdf:** last page, first page, password: \\\"secret\\\"\"\nmsgstr \"**file2.pdf:** 最後のページ、最前面、パスワード: \\\"secret\\\"\"\n\n#: ../../module.rst:163 518dcf41451c4ab098ae80c98c705da7\nmsgid \"**file3.pdf:** pages 5 to last, no password\"\nmsgstr \"**file3.pdf:** 5ページから最後尾、パスワードなし\"\n\n#: ../../module.rst:165 579e18430ffe47deaf32eb9b5bb856c7\nmsgid \"and store the result as **output.pdf** enter this command:\"\nmsgstr \"そして結果を  **output.pdf**  として保存するには、次のコマンドを入力してください:\"\n\n#: ../../module.rst:167 945d0c96b4b34fc782a86ae2fcf40aa5\nmsgid \"\"\n\"``pymupdf join -o output.pdf file1.pdf,,N-1 file2.pdf,secret,N,1 \"\n\"file3.pdf,,5-N``\"\nmsgstr \"\"\n\n#: ../../module.rst:171 45664921245f42c09b294edb251048f5\nmsgid \"Low Level Information\"\nmsgstr \"低レベル情報\"\n\n#: ../../module.rst:173 fdf3d7f12d914afe950de66d094693fa\nmsgid \"\"\n\"Display PDF internal information. Again, there are similarities to \"\n\"*\\\"mutool show\\\"*::\"\nmsgstr \"PDFの内部情報を表示します。再度、 *「mutool show」* との類似点があります。\"\n\n#: ../../module.rst:194 ad5c07b578e24a87b4bdfa72f035288d\nmsgid \"Examples::\"\nmsgstr \"例::\"\n\n#: ../../module.rst:243 a932285ed88f489cb35fb9fd00084410\nmsgid \"Embedded Files Commands\"\nmsgstr \"埋め込みファイルコマンド\"\n\n#: ../../module.rst:245 22fe7451356d4b07a68f7b814a48f7db\nmsgid \"\"\n\"The following commands deal with embedded files -- which is a feature \"\n\"completely removed from MuPDF after v1.14, and hence from all its command\"\n\" line tools.\"\nmsgstr \"\"\n\"以下のコマンドは埋め込みファイルに関するもので、MuPDF \"\n\"v1.14以降から完全に削除され、そのためすべてのコマンドラインツールからも削除されています。\"\n\n#: ../../module.rst:248 031889fce5ba40c8aa00dca7f543935f\nmsgid \"Information\"\nmsgstr \"情報\"\n\n#: ../../module.rst:250 923441e6e99c4679913ea9650bd321f3\nmsgid \"Show the embedded file names (long or short format)::\"\nmsgstr \"埋め込みファイルの名前を表示します（長いフォーマットまたは短いフォーマット）::\"\n\n#: ../../module.rst:266 2938ace8fd974862bd2b852f6d01c1b5\nmsgid \"Example::\"\nmsgstr \"例::\"\n\n#: ../../module.rst:287 4b906057dfa84c65ba2f7b3875e76f45\nmsgid \"Detailed output would look like this per entry::\"\nmsgstr \"詳細な出力は、各エントリごとに以下のようになります::\"\n\n#: ../../module.rst:297 fa6b969dc09f4e7aa8ddad1a74b85f27\nmsgid \"Extraction\"\nmsgstr \"抽出\"\n\n#: ../../module.rst:299 b95b620ad9f548139f65380c81a609eb\nmsgid \"Extract an embedded file like this::\"\nmsgstr \"埋め込みファイルを以下のように抽出します::\"\n\n#: ../../module.rst:317 b425246653d244139ee6064fef0cce03\nmsgid \"\"\n\"For details consult :meth:`Document.embfile_get`. Example (refer to \"\n\"previous section)::\"\nmsgstr \"詳細については、Document.embfile_get() を参照してください。例（前のセクションを参照）::\"\n\n#: ../../module.rst:323 beb7e7b57a2d40d7b80215a90a015016\nmsgid \"Deletion\"\nmsgstr \"削除\"\n\n#: ../../module.rst:324 a66d4e86731745edabc9c4f4e5e0bb9f\nmsgid \"Delete an embedded file like this::\"\nmsgstr \"以下のようにして埋め込みファイルを削除します::\"\n\n#: ../../module.rst:340 c7c9134eddaa4ad2b9672122f1aa8fe9\nmsgid \"For details consult :meth:`Document.embfile_del`.\"\nmsgstr \"詳細については、 :meth:`Document.embfile_del`  を参照してください。\"\n\n#: ../../module.rst:343 8027d6ea455e4050ace1ead2c3a951fb\nmsgid \"Insertion\"\nmsgstr \"挿入\"\n\n#: ../../module.rst:344 05c0ffa1d1fd4495a04887a13fa6a0ff\nmsgid \"Add a new embedded file using this command::\"\nmsgstr \"このコマンドを使用して新しい埋め込みファイルを追加します::\"\n\n#: ../../module.rst:364 a3ce7e14c5a6493190e34f36253a7b11\nmsgid \"\"\n\"*\\\"NAME\\\"* **must not** already exist in the PDF. For details consult \"\n\":meth:`Document.embfile_add`.\"\nmsgstr \"\"\n\"*\\\"NAME\\\"* は既にPDF内に存在していてはいけません。詳細については、 :meth:`Document.embfile_add`  \"\n\"を参照してください。\"\n\n#: ../../module.rst:367 8b7188f7140248f2ace12ff2559a5810\nmsgid \"Updates\"\nmsgstr \"更新\"\n\n#: ../../module.rst:368 bf7de82ffcc6488492d7f1ed813a78d7\nmsgid \"Update an existing embedded file using this command::\"\nmsgstr \"このコマンドを使用して既存の埋め込みファイルを更新します::\"\n\n#: ../../module.rst:393 dfb87b27e010457ea91a44ac1607508d\nmsgid \"\"\n\"Use this method to change meta-information of the file -- just omit the \"\n\"*\\\"PATH\\\"*. For details consult :meth:`Document.embfile_upd`.\"\nmsgstr \"\"\n\"ファイルのメタ情報を変更するために、この方法を使用します - 単に「PATH」を省略してください。詳細については、 \"\n\":meth:`Document.embfile_upd`  を参照してください。\"\n\n#: ../../module.rst:397 9724107b71a3473586bf932f86556d37\nmsgid \"Copying\"\nmsgstr \"コピー\"\n\n#: ../../module.rst:398 320c9dfca9614ce1aad38deec15e2f14\nmsgid \"Copy embedded files between PDFs::\"\nmsgstr \"PDF間で埋め込みファイルをコピーします::\"\n\n#: ../../module.rst:422 4f474c3c92134dbf92a95d04287f6b7c\nmsgid \"Text Extraction\"\nmsgstr \"テキスト抽出 \"\n\n#: ../../module.rst:423 10013955206643cdabf54b9427cf9162\nmsgid \"New in v1.18.16\"\nmsgstr \"v1.18.16で新登場\"\n\n#: ../../module.rst:425 6175e1799fe14be7857049aacbf4f76e\nmsgid \"\"\n\"Extract text from arbitrary :ref:`supported \"\n\"documents<Supported_File_Types>` to a textfile. Currently, there are \"\n\"three output formatting modes available: simple, block sorting and \"\n\"reproduction of physical layout.\"\nmsgstr \"\"\n\"任意の :ref:`サポートされたドキュメント <Supported_File_Types>` \"\n\"からテキストをテキストファイルに抽出します。現在、3つの出力フォーマットモードが利用可能です：シンプル、ブロックソート、物理的なレイアウトの再現。\"\n\n#: ../../module.rst:427 104746a6d24348c085e4d1f05530f3c4\nmsgid \"\"\n\"**Simple** text extraction reproduces all text as it appears in the \"\n\"document pages -- no effort is made to rearrange in any particular \"\n\"reading order.\"\nmsgstr \"\"\n\"**シンプル** なテキスト抽出は、ドキュメントページに表示される通りのすべてのテキストを再現します - \"\n\"特定の読み取り順序に再配置する努力は行われません。\"\n\n#: ../../module.rst:428 46976f7ba91e4ed195d1d2970b450ce8\nmsgid \"\"\n\"**Block sorting** sorts text blocks (as identified by MuPDF) by ascending\"\n\" vertical, then horizontal coordinates. This should be sufficient to \"\n\"establish a \\\"natural\\\" reading order for basic pages of text.\"\nmsgstr \"\"\n\"**ブロックソート** \"\n\"は、テキストブロック（MuPDFによって識別される）を垂直座標、水平座標の昇順に並べ替えます。これは、基本的なテキストページの「自然な」読み取り順序を確立するために十分です。\"\n\n#: ../../module.rst:429 736d584551084ce0ae8db3ab132de413\nmsgid \"\"\n\"**Layout** strives to reproduce the original appearance of the input \"\n\"pages. You can expect results like this (produced by the command `pymupdf\"\n\" gettext -pages 1 demo1.pdf`):\"\nmsgstr \"\"\n\"**レイアウト** は、入力ページの元の外観を再現しようとします。次のような結果が期待できます（コマンド  `pymupdf gettext \"\n\"-pages 1 demo1.pdf`  によって生成されたもの）：\"\n\n#: ../../module.rst:434 50eb59c01b5243e4a1beb240596e9fcf\nmsgid \"\"\n\"The \\\"gettext\\\" command offers a functionality similar to the CLI tool \"\n\"`pdftotext` by XPDF software, http://www.foolabs.com/xpdf/ -- this is \"\n\"especially true for \\\"layout\\\" mode, which combines that tool's `-layout`\"\n\" and `-table` options.\"\nmsgstr \"\"\n\"「gettext」コマンドは、XPDFソフトウェアのCLIツール `pdftotext` \"\n\"と似た機能を提供します。http://www.foolabs.com/xpdf/ - \"\n\"これは特に「レイアウト」モードに当てはまり、このモードはそのツールの `-layout` と `-table` オプションを組み合わせています。\"\n\n#: ../../module.rst:438 49563f540be445d984dba68ffffbfe02\nmsgid \"\"\n\"After each page of the output file, a formfeed character, `hex(12)` is \"\n\"written -- even if the input page has no text at all. This behavior can \"\n\"be controlled via options.\"\nmsgstr \"\"\n\"出力ファイルの各ページの後に、フォームフィード文字 `hex(12)` が書き込まれます - \"\n\"入力ページにテキストがない場合でもです。この動作はオプションを介して制御できます。\"\n\n#: ../../module.rst:440 647dbf1080904cb5b86c438feafcb584\nmsgid \"\"\n\"For \\\"layout\\\" mode, **only horizontal, left-to-right, top-to bottom** \"\n\"text is supported, other text is ignored. In this mode, text is also \"\n\"ignored, if its :data:`fontsize` is too small.\"\nmsgstr \"\"\n\"「レイアウト」モードでは、水平方向、左から右、上から下のテキストのみがサポートされ、他のテキストは無視されます。また、このモードでは、:data:`fontsize`\"\n\" が小さすぎる場合もテキストが無視されます。\"\n\n#: ../../module.rst:442 baeab1e7bac9497995324b659ebebf03\nmsgid \"\"\n\"\\\"Simple\\\" and \\\"blocks\\\" mode in contrast output **all text** for any \"\n\"text size or orientation.\"\nmsgstr \"対照的に、「シンプル」モードと「ブロック」モードでは、テキストのサイズや向きに関係なくすべてのテキストが出力されます。\"\n\n#: ../../module.rst:444 8617ac5a55024a57b4b1d70bdb264ced\nmsgid \"Command::\"\nmsgstr \"コマンド::\"\n\n#: ../../module.rst:472 f1019c52949f4174acd4b9381a394601\nmsgid \"\"\n\"Command options may be abbreviated as long as no ambiguities are \"\n\"introduced. So the following do the same:\"\nmsgstr \"コマンドのオプションは、曖昧さが生じない限り、省略形を使用することができます。したがって、以下のように同じ結果を得ることができます：\"\n\n#: ../../module.rst:474 d70e9f44b99141809981474f2ff8b052\nmsgid \"\"\n\"`... -output text.txt -noligatures -noformfeed -convert-white -grid 3 \"\n\"-extra-spaces ...`\"\nmsgstr \"\"\n\n#: ../../module.rst:475 07cb51f3b38747abbb4010f810490249\nmsgid \"`... -o text.txt -nol -nof -c -g 3 -e ...`\"\nmsgstr \"\"\n\n#: ../../module.rst:477 f16b9ac2c6c14bd5bb7fcea64f1fcd80\nmsgid \"\"\n\"The output filename defaults to the input with its extension replaced by \"\n\"`.txt`. As with other commands, you can select page ranges **(caution: \"\n\"1-based!)** in `mutool` format, as indicated above.\"\nmsgstr \"\"\n\"出力ファイル名は、入力ファイル名の拡張子が  `.txt` に置換されたものがデフォルトです。他のコマンドと同様に、上記に示されているように、 \"\n\"`mutool` 形式でページ範囲（注意：1から始まる）を選択できます。\"\n\n#: ../../module.rst:479 f23822348e0f44868acd1a434c638317\nmsgid \"**mode:** (str) select a formatting mode -- default is \\\"layout\\\".\"\nmsgstr \"**mode:** (str) フォーマットモードを選択します - デフォルトは「レイアウト」です。\"\n\n#: ../../module.rst:480 34f6f03b6b7c4d14b5b53d480ad19652\nmsgid \"\"\n\"**noligatures:** (bool) corresponds to **not** \"\n\":data:`TEXT_PRESERVE_LIGATURES`. If specified, ligatures (present in \"\n\"advanced fonts: glyphs combining multiple characters like \\\"fi\\\") are \"\n\"split up into their components (i.e. \\\"f\\\", \\\"i\\\"). Default is passing \"\n\"them through.\"\nmsgstr \"\"\n\"**noligatures:** (bool) :data:`TEXT_PRESERVE_LIGATURES` \"\n\"に相当します。指定された場合、リガチャ（複数の文字を結合するグリフ、例:「fi」のようなもの）はその構成要素（つまり「f」、「i」）に分割されます。デフォルトはそのまま通過させることです。\"\n\n#: ../../module.rst:481 7ad52df691114a03bf07a72f2434d4a9\nmsgid \"\"\n\"**convert-white:** corresponds to **not** \"\n\":data:`TEXT_PRESERVE_WHITESPACE`. If specified, all white space \"\n\"characters (like tabs) are replaced with one or more spaces. Default is \"\n\"passing them through.\"\nmsgstr \"\"\n\"**convert-white:**  :data:`TEXT_PRESERVE_WHITESPACE`  \"\n\"に相当します。指定された場合、すべての空白文字（タブなど）は1つ以上のスペースに置き換えられます。デフォルトはそのまま通過させることです。\"\n\n#: ../../module.rst:482 b925a23489d24b3396cf53888050c32d\nmsgid \"\"\n\"**extra-spaces:**  (bool) corresponds to **not** \"\n\":data:`TEXT_INHIBIT_SPACES`. If specified, large gaps between adjacent \"\n\"characters will be filled with one or more spaces. Default is off.\"\nmsgstr \"\"\n\"**extra-spaces:**  (bool) :data:`TEXT_INHIBIT_SPACES`  \"\n\"に相当します。指定された場合、隣接する文字間の大きな間隔は1つ以上のスペースで埋められます。デフォルトはオフです。\"\n\n#: ../../module.rst:483 9d95e72389b3445ba510fb682107c642\n#, fuzzy\nmsgid \"\"\n\"**noformfeed:**  (bool) instead of `hex(12)` (formfeed), write linebreaks\"\n\" ``\\\\n`` at end of output pages.\"\nmsgstr \"\"\n\"**noformfeed:** (bool)  `hex(12)` （フォームフィード）の代わりに、出力ページの末尾に  ``\\\\n`` \"\n\"個の改行を書き込みます。\"\n\n#: ../../module.rst:484 703f5774d5234679a03f67da753bc40a\nmsgid \"**skip-empty:**  (bool) skip pages with no text.\"\nmsgstr \"**skip-empty:**  ((bool) テキストがないページをスキップします。\"\n\n#: ../../module.rst:485 8f19a7610cc64fc88819c1b7fc295330\nmsgid \"\"\n\"**grid:** lines with a vertical coordinate difference of no more than \"\n\"this value (in points) will be merged into the same output line. Only \"\n\"relevant for \\\"layout\\\" mode. **Use with care:** 3 or the default 2 \"\n\"should be adequate in most cases. If **too large**, lines that are \"\n\"*intended* to be different in the original may be merged and will result \"\n\"in garbled and / or incomplete output. If **too low**, artifact separate \"\n\"output lines may be generated for some spans in the input line, just \"\n\"because they are coded in a different font with slightly deviating \"\n\"properties.\"\nmsgstr \"\"\n\"**grid:** 垂直座標の差がこの値（ポイント単位）を超えない行は、同じ出力行に結合されます。 \"\n\"「レイアウト」モードにのみ関連します。注意して使用してください: \"\n\"ほとんどの場合、3またはデフォルトの2が適切です。大きすぎると、元のフォントで異なる行が結合され、文字化けや不完全な出力が発生する可能性があります。低すぎると、入力行の一部の範囲で個別の出力行が生成されることがありますが、これはわずかに異なる特性を持つ別のフォントでコーディングされているためです。\"\n\n#: ../../module.rst:486 eac14db14ad14562a3b3b10a76827016\nmsgid \"\"\n\"**fontsize:** include text with :data:`fontsize` larger than this value \"\n\"only (default 3). Only relevant for \\\"layout\\\" option.\"\nmsgstr \"\"\n\"**fontsize:** この値よりも大きな :data:`fontsize` を持つテキストのみを含めます（デフォルト3）。 \"\n\"「レイアウト」オプションにのみ関連します。\"\n\n#: ../../footer.rst:46 bf24bcacdf454aba8a6c79d83a00209b\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Module *fitz*\"\n#~ msgstr \"モジュール *fitz*\"\n\n#~ msgid \"Invoke the module like this::\"\n#~ msgstr \"次のようにしてモジュールを呼び出します::\"\n\n#~ msgid \"\"\n#~ \"*python -m fitz join -o output.pdf \"\n#~ \"file1.pdf,,N-1 file2.pdf,secret,N,1 file3.pdf,,5-N*\"\n#~ msgstr \"\"\n\n#~ msgid \"Or use Python's `-m` switch with PyMuPDF's `fitz` module::\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*pymupdf join -o output.pdf file1.pdf,,N-1 \"\n#~ \"file2.pdf,secret,N,1 file3.pdf,,5-N*\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/outline.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 bbc8f87339104f1898b46c688e53d1bf\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 c349cfed692041d1831e68981b1432f3\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 ccc1347133a5468990182905e2e49042\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../outline.rst:7 ac9aff233a8946e286c95d2a2f9a8e13\nmsgid \"Outline\"\nmsgstr \"Outline (アウトライン)\"\n\n#: ../../outline.rst:9 7a3be59ed3114a5c8bffd3f17bbb2211\n#, fuzzy\nmsgid \"\"\n\"The document outline (otherwise known as \\\"bookmarks\\\") is a property of \"\n\":ref:`Document` (see :attr:`Document.outline`). If not ``None``, it \"\n\"stands for the first outline item of the document. Its properties in turn\"\n\" define the characteristics of this item and also point to other outline \"\n\"items in \\\"horizontal\\\" or downward direction. The full tree of all \"\n\"outline items for e.g. a conventional table of contents (TOC) can be \"\n\"recovered by following these \\\"pointers\\\".\"\nmsgstr \"\"\n\"*アウトライン*（または「ブックマーク」）は、*Document* のプロパティです。それが ``None`` \"\n\"でない場合、それはドキュメントの最初のアウトライン項目を表します。そのプロパティは、この項目の特性を定義し、また「水平」または下向きの方向に他のアウトライン項目を指します。たとえば、通常の目次（TOC）のためのすべてのアウトライン項目の完全なツリーは、これらの「ポインター」をたどることで回復できます。\"\n\n#: ../../outline.rst:12 b45a2c09637c4f3e9d2b01f1ba92a39f\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../outline.rst:12 47ad240edf4f474fa4acbc5fda0372cb\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../outline.rst:14 be403d58c4de4b12a011b9ed0d0e543f\nmsgid \":attr:`Outline.down`\"\nmsgstr \"\"\n\n#: ../../outline.rst:14 247939926687419fbfef8ca1aca02f0d\nmsgid \"next item downwards\"\nmsgstr \"次の項目は下向き\"\n\n#: ../../outline.rst:15 96c69672ce3043259545e0e655eb91db\nmsgid \":attr:`Outline.next`\"\nmsgstr \"\"\n\n#: ../../outline.rst:15 4a5f23f96cf749c7872473b681590785\nmsgid \"next item same level\"\nmsgstr \"同じレベルの次の項目\"\n\n#: ../../outline.rst:16 c573402a06284cd492bec3c1d27d1e3d\nmsgid \":attr:`Outline.page`\"\nmsgstr \"\"\n\n#: ../../outline.rst:16 506be6a2e42d4302bdbc7b4e28e2394d\nmsgid \"page number (0-based)\"\nmsgstr \"ページ番号（0から始まる）\"\n\n#: ../../outline.rst:17 f119da14666b4fd3b371cf4ffc3e472a\nmsgid \":attr:`Outline.title`\"\nmsgstr \"\"\n\n#: ../../outline.rst:17 76ae4b21a6a6447da64b2d5e96423ea6\nmsgid \"title\"\nmsgstr \"タイトル\"\n\n#: ../../outline.rst:18 a5fad59c22974e90b9ea8aad24218452\nmsgid \":attr:`Outline.uri`\"\nmsgstr \"\"\n\n#: ../../outline.rst:18 841c94119419481b8d836018ece01af9\nmsgid \"string further specifying outline target\"\nmsgstr \"アウトラインのターゲットをさらに指定する文字列\"\n\n#: ../../outline.rst:19 8cfeb148873e49c09a78d54e1a2f77c6\nmsgid \":attr:`Outline.is_external`\"\nmsgstr \"\"\n\n#: ../../outline.rst:19 8a8f02b1287645c8905eec8793a1b5b6\nmsgid \"target outside document\"\nmsgstr \"ドキュメントの外部のターゲットかどうか\"\n\n#: ../../outline.rst:20 5de9d126a21d480a9e1ca3476bebb4d3\nmsgid \":attr:`Outline.is_open`\"\nmsgstr \"\"\n\n#: ../../outline.rst:20 7fc18da2ba4d4cbe9f3b2a82d39f02da\nmsgid \"whether sub-outlines are open or collapsed\"\nmsgstr \"サブアウトラインが開いているか折りたたまれているか\"\n\n#: ../../outline.rst:21 6aa64d2eff674fa2890310aecbb14167\nmsgid \":attr:`Outline.dest`\"\nmsgstr \"\"\n\n#: ../../outline.rst:21 0a87f99431e642139f4b43d536359abe\nmsgid \"points to destination details object\"\nmsgstr \"宛先の詳細オブジェクトを指す\"\n\n#: ../../outline.rst:24 5ed102082bf84d049ca1f0ce22437f31\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../outline.rst:30 7b0ddca9a47d4e648ebdab93710cb150\nmsgid \"\"\n\"The next outline item on the next level down. Is ``None`` if the item has\"\n\" no children.\"\nmsgstr \"次の階層のアウトライン項目です。アイテムに子要素がない場合は ``None`` です。\"\n\n#: ../../outline.rst 057e37ce84814a1c8c344aab938047f2\n#: 1e93414e062d488e892d2f22750666de 76ab3bd1d70641f185a95f718ad0bb69\n#: 7bd6079115d0441a82b8de2daaa1f4f9 9ecaaca5f8fd42c5b695d3f7ac9a5477\n#: bc6ef4078c8a4c91a859ae4437517df7 e5dc2bd2705743d59033178491288a7a\n#: ea89654da5734c92aa2797336d8dfbc6\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../outline.rst:32 8b64d66496a54db0908a0f6af0d7969e\nmsgid \":ref:`Outline`\"\nmsgstr \"\"\n\n#: ../../outline.rst:36 b8f40bec44ec498a866b8b610465788d\nmsgid \"\"\n\"The next outline item at the same level as this item. Is ``None`` if this\"\n\" is the last one in its level.\"\nmsgstr \"このアイテムと同じレベルの次のアウトライン項目です。このアイテムがそのレベルで最後の場合、``None`` です。\"\n\n#: ../../outline.rst:38 78788e777e334a73bb007bf2b10702b8\nmsgid \"`Outline`\"\nmsgstr \"\"\n\n#: ../../outline.rst:42 e0f2f185ffc545688e36397b2ab22051\nmsgid \"The page number (0-based) this bookmark points to.\"\nmsgstr \"このブックマークが指すページ番号（0から始まる）です。\"\n\n#: ../../outline.rst:44 f47207285d9f4747a109ad0f93928b78\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../outline.rst:48 53ed66d010ce46c8a8afa6580844ac5d\nmsgid \"The item's title as a string or ``None``.\"\nmsgstr \"アイテムのタイトル、または ``None`` の文字列です。\"\n\n#: ../../outline.rst:50 ../../outline.rst:83 f43c0734193d4aedae69249948755e99\n#: fc9bbc88a2e842c090ac4d2ea7adf221\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../outline.rst:54 d0a15fed61c5446e815f91424b141eab\nmsgid \"\"\n\"Indicator showing whether any sub-outlines should be expanded (``True``) \"\n\"or be collapsed (``False``). This information is interpreted by PDF \"\n\"reader software.\"\nmsgstr \"サブアウトラインが展開されるべきか（``True``）折りたたまれるべきか（``False``）を示すインジケーターです。この情報はPDFリーダーソフトウェアによって解釈されます。\"\n\n#: ../../outline.rst:56 ../../outline.rst:62 1e2367a870064e0ab9fefe235f8f9199\n#: 309c517aaa49400181d997b03fb6d487\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../outline.rst:60 eabf7026067444bd881e44370ac424e5\nmsgid \"\"\n\"A bool specifying whether the target is outside (``True``) of the current\"\n\" document.\"\nmsgstr \"対象が現在のドキュメントの外部（``True``）かどうかを示すブール値です。\"\n\n#: ../../outline.rst:66 6e1ed475f293437aa748d4d40f55bbc0\nmsgid \"\"\n\"A string specifying the link target. The meaning of this property should \"\n\"be evaluated in conjunction with property `is_external`:\"\nmsgstr \"リンクの対象を指定する文字列。このプロパティの意味は、プロパティ `is_external` と一緒に評価されるべきです。\"\n\n#: ../../outline.rst:70 048200e34ebe4f88b8f6ecdfad9e9724\n#, fuzzy\nmsgid \"\"\n\"`is_external` is true: ``uri`` points to some target outside the current \"\n\"PDF, which may be an internet resource (``uri`` starts with ``http://`` \"\n\"or similar), another file (``uri`` starts with ``file:`` or ``file://``) \"\n\"or some other service like an e-mail address (``uri`` starts with \"\n\"``mailto:``).\"\nmsgstr \"\"\n\"`is_external` がtrueの場合： `uri` は、現在のPDFの外部のターゲットを指します。これは、インターネットリソース（ \"\n\"`uri` が \\\"http://\\\" などで始まる）、別のファイル（`uri` が \\\"file:\\\" または \\\"file://\\\" \"\n\"で始まる）、または電子メールアドレスなどのその他のサービス（ `uri` が \\\"mailto:\\\" で始まる）である可能性があります。\"\n\n#: ../../outline.rst:76 e2b37e452977480aadfbf5e2b8eb7ced\n#, fuzzy\nmsgid \"\"\n\"`is_external` is false: ``uri`` will be `None` or point to an internal \"\n\"location. In case of PDF documents, this should either be *#nnnn* to \"\n\"indicate a 1-based (!) page number *nnnn*, or a named location. The \"\n\"format varies for other document types, for example \"\n\"\\\"../FixedDoc.fdoc#PG_2_LNK_1\\\" for page number 2 (1-based) in an XPS \"\n\"document.\"\nmsgstr \"\"\n\"`is_external` がfalseの場合：`uri` は `None` \"\n\"になるか、または内部の位置を指します。PDFドキュメントの場合、これは1から始まるページ番号 *nnnn* を示すために *#nnnn* \"\n\"であるか、名前付きの場所を示します。他のドキュメントタイプの場合、形式は異なります。たとえば、XPSドキュメントのページ番号2（1から始まる）の場合は\"\n\" \\\"../FixedDoc.fdoc#PG_2_LNK_1\\\" です。\"\n\n#: ../../outline.rst:87 0774302e2b4a4cc5be36f90e97235665\nmsgid \"The link destination details object.\"\nmsgstr \"リンクの宛先詳細オブジェクトです。\"\n\n#: ../../outline.rst:89 2c95888d87c844888823cf7c4bfbdd8d\nmsgid \":ref:`linkDest`\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 3da3281d20a349b2afbe0ca6afa704a3\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"A string specifying the link target. \"\n#~ \"The meaning of this property should \"\n#~ \"be evaluated in conjunction with \"\n#~ \"*isExternal*. The value may be ``None``,\"\n#~ \" in which case *isExternal == False*.\"\n#~ \" If *uri* starts with *file://*, \"\n#~ \"*mailto:*, or an internet resource name,\"\n#~ \" *isExternal* is ``True``. In all \"\n#~ \"other cases *isExternal == False* and\"\n#~ \" *uri* points to an internal \"\n#~ \"location. In case of PDF documents, \"\n#~ \"this should either be *#nnnn* to \"\n#~ \"indicate a 1-based (!) page number \"\n#~ \"*nnnn*, or a named location. The \"\n#~ \"format varies for other document types,\"\n#~ \" e.g. *uri = '../FixedDoc.fdoc#PG_21_LNK_84'* \"\n#~ \"for page number 21 (1-based) in an\"\n#~ \" XPS document.\"\n#~ msgstr \"\"\n#~ \"リンクのターゲットを指定する文字列です。このプロパティの意味は *isExternal* \"\n#~ \"と連動して評価されるべきです。値が ``None`` の場合、*isExternal == \"\n#~ \"False* です。*uri* が *file://、mailto:* \"\n#~ \"、またはインターネットリソース名で始まる場合、*isExternal* は ``True`` \"\n#~ \"です。それ以外の場合、*isExternal == False* で、*uri* \"\n#~ \"は内部の場所を指します。PDFドキュメントの場合、これは1から始まるページ番号 *nnnn* を示すための \"\n#~ \"*#nnnn* \"\n#~ \"であるか、名前付きの場所である必要があります。他のドキュメントタイプの場合、例えばXPSドキュメントの場合、*uri = \"\n#~ \"'../FixedDoc.fdoc#PG_21_LNK_84'* は、ページ番号21（1から始まる）を示します。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/packaging.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2024-09-11 21:42+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ea339b8cf2d7425a8df74a11b8967508\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 5cca523385734e86a2f0b714b8baa7d8\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF（およびその他の）ドキュメントのデータ抽出、解析、変換、および操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 d2a6dea50de74aee87d8c5a1392014ac\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF テキスト抽出、PDF 画像抽出、PDF 変換、PDF テーブル、PDF 分割、PDF 作成、Pyodide、PyScript\"\n\n#: ../../packaging.rst:5 92d36a7e439d47098564112377f93fb8\nmsgid \"Packaging for Linux distributions\"\nmsgstr \"Linux ディストリビューション向けのパッケージング\"\n\n#: ../../packaging.rst:9 db33f856c6964c8f82f944305803a5c3\nmsgid \"Requirements\"\nmsgstr \"要件\"\n\n#: ../../packaging.rst:11 dd51b73f026546128b58ca1dbc07d09b\nmsgid \"Python\"\nmsgstr \"\"\n\n#: ../../packaging.rst:12 619f89f2b9d94ee08bc949768cf1c902\nmsgid \"MuPDF checkout (including submodules).\"\nmsgstr \"MuPDF チェックアウト（サブモジュールを含む）。\"\n\n#: ../../packaging.rst:13 3e8513b568314fd08934c01a489b24ff\nmsgid \"PyMuPDF checkout.\"\nmsgstr \"PyMuPDF チェックアウト。\"\n\n#: ../../packaging.rst:14 c0fcde2fbd534fafb5383c841b93e6a0\nmsgid \"System packages listed in `scripts/sysinstall.py:g_sys_packages`.\"\nmsgstr \"`scripts/sysinstall.py:g_sys_packages` にリストされたシステムパッケージ。\"\n\n#: ../../packaging.rst:15 5628693598754932bd53d13010047308\nmsgid \"Python packages listed in `pyproject.toml`.\"\nmsgstr \"`pyproject.toml` にリストされた Python パッケージ。\"\n\n#: ../../packaging.rst:17 cb7a28284f2e4f08827c755968f0877e\nmsgid \"Extra requirements for running tests:\"\nmsgstr \"テストの実行に必要な追加要件：\"\n\n#: ../../packaging.rst:19 7e9780bb68154a86a58fcfad997a5bee\nmsgid \"Python packages listed in `scripts/gh_release.py:test_packages`.\"\nmsgstr \"`scripts/gh_release.py:test_packages` にリストされた Python パッケージ。\"\n\n#: ../../packaging.rst:23 b4c0cecc40d24541aa536d3e453b991a\nmsgid \"General steps\"\nmsgstr \"一般的な手順\"\n\n#: ../../packaging.rst:25 968e7bb7a90f41a8869285b39c5ffb7b\nmsgid \"Build and install MuPDF:\"\nmsgstr \"MuPDF をビルドしてインストールする：\"\n\n#: ../../packaging.rst:27 f87b44cacfff43ab983716288eb0f4a4\nmsgid \"Install required system packages.\"\nmsgstr \"必要なシステムパッケージをインストールします。\"\n\n#: ../../packaging.rst:28 d9ac56053379472a852112940eadff9f\nmsgid \"\"\n\"Run `make install-shared-python` on MuPDF's `Makefile` with at least \"\n\"these make variables:\"\nmsgstr \"\"\n\"MuPDF の `Makefile` で `make install-shared-python` を実行し、少なくともこれらの make \"\n\"変数を設定します：\"\n\n#: ../../packaging.rst:31 f91b3554819741e18f724952afefff0d\nmsgid \"`DESTDIR` set to the install directory, e.g. `/`.\"\nmsgstr \"`DESTDIR` をインストールディレクトリに設定します。例: `/`。\"\n\n#: ../../packaging.rst:33 a1bb9179a5924291a4d95d69779a7638\nmsgid \"\"\n\"`prefix` set to location relative to DESTDIR, such as `/usr/local` or \"\n\"`/usr`. Must start with `/`.\"\nmsgstr \"\"\n\"`prefix` を DESTDIR に相対的な場所に設定します。たとえば `/usr/local` または /usr など、必ず / \"\n\"で始める必要があります。\"\n\n#: ../../packaging.rst:35 ff45c57dc53a474aa442f256588c55cc\nmsgid \"`USE_SYSTEM_LIBS=yes`.\"\nmsgstr \"\"\n\n#: ../../packaging.rst:36 6403f4dd52254fbfa53af0e1352ceeaa\nmsgid \"`HAVE_LEPTONICA=yes`.\"\nmsgstr \"\"\n\n#: ../../packaging.rst:37 482b9da209504d059ff223aedd76019b\nmsgid \"`HAVE_TESSERACT=yes`.\"\nmsgstr \"\"\n\n#: ../../packaging.rst:39 51e3ef8e388c4e2eb2a6f493f0f9c614\nmsgid \"Build and install PyMuPDF:\"\nmsgstr \"`pip install ./PyMuPDF`\"\n\n#: ../../packaging.rst:42 499f0afa88564953ac9c266474d2aa0d\nmsgid \"\"\n\"Run `pip install ./PyMuPDF` or `pip wheel ./PyMuPDF` with at least these \"\n\"environment variables:\"\nmsgstr \"\"\n\"`pip install ./PyMuPDF` または `pip wheel ./PyMuPDF` \"\n\"を実行します。少なくとも以下の環境変数を設定してください：\"\n\n#: ../../packaging.rst:46 6d1d80bf3e7648e6be69dc15eac81a10\nmsgid \"\"\n\"`PYMUPDF_SETUP_MUPDF_BUILD=` (empty string) to prevent download and build\"\n\" of hard-coded MuPDF release.\"\nmsgstr \"\"\n\"`PYMUPDF_SETUP_MUPDF_BUILD=` （空の文字列）：ハードコードされた MuPDF \"\n\"リリースのダウンロードとビルドを防ぐために設定します。\"\n\n#: ../../packaging.rst:49 f0669625912e43c2b839e632328453b7\nmsgid \"\"\n\"`CFLAGS`, `CXXFLAGS` and `LDFLAGS` set to allow visibility of the \"\n\"installed MuPDF headers and shared libraries.\"\nmsgstr \"\"\n\"`CFLAGS`、`CXXFLAGS`、および `LDFLAGS` を設定して、インストールされた MuPDF \"\n\"のヘッダーと共有ライブラリが見えるようにします。\"\n\n#: ../../packaging.rst:52 fa04c3bb56c941df8b521704c781e646\nmsgid \"Run PyMuPDF tests:\"\nmsgstr \"PyMuPDF テストを実行する：\"\n\n#: ../../packaging.rst:54 ab5423a83a72485ba9d3f2a257dfc8d6\nmsgid \"Ensure required Python packages are available.\"\nmsgstr \"必要な Python パッケージが利用可能であることを確認します\"\n\n#: ../../packaging.rst:56 9549372318d448939b9315704df3c716\nmsgid \"Run `pytest -k \\\"not test_color_count and not test_3050\\\" PyMuPDF`\"\nmsgstr \"`pytest -k \\\"not test_color_count and not test_3050\\\" PyMuPDF` を実行します。\"\n\n#: ../../packaging.rst:58 d6c894edd7704171b3995de2b1102647\nmsgid \"\"\n\"Test `test_color_count` is known fail if MuPDF is not built with \"\n\"PyMuPDF's custom config.h.\"\nmsgstr \"\"\n\"`test_color_count` テストは、MuPDF が PyMuPDF のカスタム config.h \"\n\"でビルドされていない場合に失敗することが既知です。\"\n\n#: ../../packaging.rst:59 5a4624ddb10d46b9a944a59b2579188b\nmsgid \"\"\n\"Test `test_3050` is known to fail if MuPDF is built without its own \"\n\"third-party libraries.\"\nmsgstr \"`test_3050` テストは、MuPDF が独自のサードパーティライブラリを使用せずにビルドされている場合に失敗することが既知です。\"\n\n#: ../../packaging.rst:63 a2a65b48ae41408488f21ffce49014d0\nmsgid \"Use of scripts/sysinstall.py\"\nmsgstr \"scripts/sysinstall.py の使用\"\n\n#: ../../packaging.rst:65 eea1b531c51e4d31a0e82c6fab02eab2\nmsgid \"\"\n\"`scripts/sysinstall.py` provides a useful example of build, install and \"\n\"test commands that are known to to work, because it is run regularly by \"\n\"Github action `.github/workflows/test_sysinstall.yml`.\"\nmsgstr \"\"\n\"`scripts/sysinstall.py` は、定期的に GitHub アクション \"\n\"`.github/workflows/test_sysinstall.yml` \"\n\"で実行されるため、動作が確認されているビルド、インストール、およびテストコマンドの便利な例を提供しています。\"\n\n#: ../../packaging.rst:69 388e54101bff4f3fa4ae2619fe831f17\nmsgid \"Run with `-h` or look at the doc-string to see detailed usage information.\"\nmsgstr \"詳細な使用方法については、`-h` を付けて実行するか、ドキュメント文字列を参照してください。\"\n\n#: ../../packaging.rst:70 9256146054514b818c9dcb29a92af8b5\nmsgid \"It uses Debian-style `apt` commands to install system packages.\"\nmsgstr \"システムパッケージのインストールには、Debian スタイルの `apt` コマンドが使用されます。\"\n\n#: ../../packaging.rst:71 cb3514ca6d8c491dba99488d16d69d11\nmsgid \"By default it assumes local git checkouts `mupdf/` and `PyMuPDF/`.\"\nmsgstr \"デフォルトでは、ローカルの git チェックアウトである `mupdf/` と `PyMuPDF/` を想定しています。\"\n\n#: ../../packaging.rst:73 c626332a346d49e2b6784037fc0062b1\nmsgid \"\"\n\"To run a full build, install and test for both a local fake root and the \"\n\"system root:\"\nmsgstr \"ローカルのフェイクルートとシステムルートの両方で、フルビルド、インストール、およびテストを実行するには、\"\n\n#: ../../packaging.rst:81 808c407963ab412c91b112f433a7533a\nmsgid \"To see what commands would be run without actually running them:\"\nmsgstr \"実際に実行せずに実行されるコマンドを確認するには:\"\n\n#: ../../packaging.rst:89 d5029b9f860543aaa4c5a38f00c82e36\nmsgid \"See also\"\nmsgstr \"参考にしてください\"\n\n#: ../../packaging.rst:92 c20265f491b4469d8ab455749f78c3b0\nmsgid \"\"\n\"`setup.py`'s initial doc-comment has detailed information about the \"\n\"environment variables used when building PyMuPDF.\"\nmsgstr \"\"\n\"参考にしてください `setup.py` の最初のドキュメントコメントには、PyMuPDF \"\n\"をビルドする際に使用される環境変数に関する詳細な情報が含まれています。\"\n\n#~ msgid \"\"\n#~ \"`PYMUPDF_SETUP_IMPLEMENTATIONS=b` to build only \"\n#~ \"the rebased implementation. [This will \"\n#~ \"become the default in a future \"\n#~ \"release.]\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"[As of 2024-04-15, tere is no need\"\n#~ \" to set `PYMUPDF_SETUP_IMPLEMENTATIONS=b` to \"\n#~ \"build only the rebased implementation, \"\n#~ \"as this is now the default.]\"\n#~ msgstr \"\"\n#~ \"[2024年4月15日現在、`PYMUPDF_SETUP_IMPLEMENTATIONS=b` \"\n#~ \"を設定して、リベースされた実装のみをビルドする必要はありません。これはデフォルトの動作です。]\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/page.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 8170fcd05dee4c51bf9505113ceeca73\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 6af23f31d1794ebe8d4cd00cdb2c6335\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 2370c44a09c14c6ea409cf2644e17d14\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../page.rst:7 8937c9a408d44d8e9a9409e7bff61e0e\nmsgid \"Page\"\nmsgstr \"Page (ページ)\"\n\n#: ../../page.rst:9 9245c311a52d403f9622088450ec1ed8\nmsgid \"\"\n\"Class representing a document page. A page object is created by \"\n\":meth:`Document.load_page` or, equivalently, via indexing the document \"\n\"like `doc[n]` - it has no independent constructor.\"\nmsgstr \"\"\n\"ドキュメントページを表すクラス。ページオブジェクトは :meth:`Document.load_page` \"\n\"またはドキュメントをインデックスで参照することで作成されます（例： `doc[n]` ） - 独立したコンストラクタはありません。\"\n\n#: ../../page.rst:11 5b3a16daffa34c41881df3783e022020\nmsgid \"\"\n\"There is a parent-child relationship between a document and its pages. If\"\n\" the document is closed or deleted, all page objects (and their \"\n\"respective children, too) in existence will become unusable \"\n\"(\\\"orphaned\\\"): If a page property or method is being used, an exception \"\n\"is raised.\"\nmsgstr \"ドキュメントとそのページとの親子関係があります。ドキュメントが閉じられるか削除されると、存在するすべてのページオブジェクト（およびそれに関連する子供たちも）が使用できなくなります（「孤児」になります）。ページのプロパティまたはメソッドを使用している場合、例外が発生します。\"\n\n#: ../../page.rst:13 c43aa4901b134ef0af55b777bc691555\nmsgid \"\"\n\"Several page methods have a :ref:`Document` counterpart for convenience. \"\n\"At the end of this chapter you will find a synopsis.\"\nmsgstr \"便宜のために、いくつかのページメソッドには :ref:`Document` の対応するメソッドがあります。この章の最後に概要があります。\"\n\n#: ../../page.rst:15 b2fc39847f5843cf894fb6ef28439127\nmsgid \"\"\n\"Many times in this chapter we are using the term **coordinate**. It is of\"\n\" high importance to have at least a basic understanding of what that is \"\n\"and that you feel comfortable with the section :ref:`Coordinates`.\"\nmsgstr \"\"\n\"この章では何度も **「座標」** という用語を使用しています。それが何を意味するかを少なくとも基本的な理解があること、そして \"\n\":ref:`Coordinates` のセクションに慣れていることが非常に重要です。\"\n\n#: ../../page.rst:18 0638e07e50a943388068f4aee50716dd\nmsgid \"Modifying Pages\"\nmsgstr \"ページの修正\"\n\n#: ../../page.rst:19 4a50620eb10f44d0877cd46debc5c2a0\nmsgid \"\"\n\"Changing page properties and adding or changing page content is available\"\n\" for PDF documents only.\"\nmsgstr \"ページのプロパティを変更し、ページの内容を追加または変更することは、PDFドキュメントのみで使用可能です。\"\n\n#: ../../page.rst:21 86a3398051794f1585b0f0f44c54cd6d\nmsgid \"In a nutshell, this is what you can do with PyMuPDF:\"\nmsgstr \"要するに、PyMuPDFでできることは次のとおりです：\"\n\n#: ../../page.rst:23 16d07d121728484981e076fe815bd0f7\nmsgid \"Modify page rotation and the visible part (\\\"cropbox\\\") of the page.\"\nmsgstr \"ページの回転とページの可視部分（「クロップボックス」）の変更。\"\n\n#: ../../page.rst:24 a55eb2352dec4ac4808c3f070a2c45bc\nmsgid \"Insert images, other PDF pages, text and simple geometrical objects.\"\nmsgstr \"画像、他のPDFページ、テキスト、単純な幾何学的オブジェクトの挿入。\"\n\n#: ../../page.rst:25 ccfedac9094242d9a2236213fede33ac\nmsgid \"Add annotations and form fields.\"\nmsgstr \"アノテーションとフォームフィールドの追加。\"\n\n#: ../../page.rst:29 648ad24ff28a4782b799c7cc2209686d\nmsgid \"\"\n\"Methods require coordinates (points, rectangles) to put content in \"\n\"desired places. Please be aware that these coordinates **must always** be\"\n\" provided relative to the **unrotated** page (since v1.17.0). The reverse\"\n\" is also true: except :attr:`Page.rect`, resp. :meth:`Page.bound` (both \"\n\"*reflect* when the page is rotated), all coordinates returned by methods \"\n\"and attributes pertain to the unrotated page.\"\nmsgstr \"\"\n\"メソッドには、コンテンツを所望の場所に配置するために座標（ポイント、矩形）が必要です。v1.17.0以降、これらの座標は常に \"\n\"**回転していない** ページに対して提供する **必要があります**。逆もまた真実です：:attr:`Page.rect`, resp. \"\n\":meth:`Page.bound` を除いて（ページが回転したときを *反映* \"\n\"しています）、メソッドと属性が返すすべての座標は回転していないページに関連しています。\"\n\n#: ../../page.rst:31 43cad26b1c8b405cbde663afa1390699\nmsgid \"\"\n\"So the returned value of e.g. :meth:`Page.get_image_bbox` will not change\"\n\" if you do a :meth:`Page.set_rotation`. The same is true for coordinates \"\n\"returned by :meth:`Page.get_text`, annotation rectangles, and so on. If \"\n\"you want to find out, where an object is located in **rotated \"\n\"coordinates**, multiply the coordinates with \"\n\":attr:`Page.rotation_matrix`. There also is its inverse, \"\n\":attr:`Page.derotation_matrix`, which you can use when interfacing with \"\n\"other readers, which may behave differently in this respect.\"\nmsgstr \"\"\n\"したがって、:meth:`Page.get_image_bbox` \"\n\"などのメソッドの返される値は、Page.set_rotation()を実行しても変更されません。同じことが \"\n\":meth:`Page.get_text`、アノテーションの矩形などから返される座標にも当てはまります。オブジェクトが **回転した座標** \"\n\"でどこにあるかを調べたい場合は、座標を:attr:`Page.rotation_matrix` \"\n\"で乗算します。:attr:`Page.derotation_matrix` \"\n\"とその逆行列もあり、他のリーダーと連携する際に使用できます。この点で異なる動作をするかもしれません。\"\n\n#: ../../page.rst:35 4602f0a46b4b45d692b0e8b0e0a8b4cd\nmsgid \"\"\n\"If you add or update annotations, links or form fields on the page and \"\n\"immediately afterwards need to work with them (i.e. **without leaving the\"\n\" page**), you should reload the page using :meth:`Document.reload_page` \"\n\"before referring to these new or updated items.\"\nmsgstr \"\"\n\"ページに注釈、リンク、またはフォームフィールドを追加または更新し、直後にこれらの新しいまたは更新されたアイテムを操作する必要がある場合（つまり \"\n\"**ページを離れずに**）、:meth:`Document.reload_page` を使用してページを再読み込みする必要があります。\"\n\n#: ../../page.rst:37 d30757a5570341c492c9b6b2dd27e8da\nmsgid \"\"\n\"Reloading the page is generally recommended -- although not strictly \"\n\"required in all cases. However, some annotation and widget types have \"\n\"extended features in PyMuPDF compared to MuPDF. More of these extensions \"\n\"may also be added in the future.\"\nmsgstr \"一般的にはページを再読み込みすることをお勧めしますが、すべてのケースで厳密に必要とされるわけではありません。ただし、PyMuPDFの注釈とウィジェットの種類の一部は、MuPDFと比較して拡張機能を持っています。今後もこれらの拡張機能が増えるかもしれません\"\n\n#: ../../page.rst:39 b54db556e2734b51bbd36600ec731807\nmsgid \"\"\n\"Releoading the page ensures all your changes have been fully applied to \"\n\"PDF structures, so you can safely create Pixmaps or successfully iterate \"\n\"over annotations, links and form fields.\"\nmsgstr \"ページを再読み込むことで、変更がPDF構造に完全に適用され、Pixa画像を作成したり、アノテーション、リンク、フォームフィールドを正常にイテレートしたりできるようになります。\"\n\n#: ../../page.rst:42 86f8776f6e6a46c2bd6677f03df546f8\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../page.rst:42 41c16cff24c249a6b99784f27f4c62a9\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../page.rst:44 e73e4ad3cfa341f28634b14957a79fc4\nmsgid \":meth:`Page.add_caret_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:44 0a9cf0b37f5d495db9ccba909ec825b7\nmsgid \"PDF only: add a caret annotation\"\nmsgstr \"PDFのみ：キャレットアノテーションを追加します\"\n\n#: ../../page.rst:45 41b70f4be08542938df342847627409d\nmsgid \":meth:`Page.add_circle_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:45 218dcdd140e442ef906cbc5f8489d215\nmsgid \"PDF only: add a circle annotation\"\nmsgstr \"PDFのみ：円注釈を追加します\"\n\n#: ../../page.rst:46 0d9b6d05bb1b40759acc10ba769f6906\nmsgid \":meth:`Page.add_file_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:46 876465f48d654d82a63dea158fa06436\nmsgid \"PDF only: add a file attachment annotation\"\nmsgstr \"PDFのみ：ファイル添付アノテーションを追加します\"\n\n#: ../../page.rst:47 b2e7234dd6e14d6ead8dc67c38dcd6ef\nmsgid \":meth:`Page.add_freetext_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:47 1e63f79e07b646fc9c5b6ca226e005fb\nmsgid \"PDF only: add a text annotation\"\nmsgstr \"PDFのみ：テキストアノテーションを追加します\"\n\n#: ../../page.rst:48 0f9e70d7023442f3be97c1dae2ec1c4e\nmsgid \":meth:`Page.add_highlight_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:48 36abc8a5ff054548915094f9d993af36\nmsgid \"PDF only: add a \\\"highlight\\\" annotation\"\nmsgstr \"PDFのみ：「ハイライト」アノテーションを追加します\"\n\n#: ../../page.rst:49 91e515dbd7054bf8b273bc1712b7ede5\nmsgid \":meth:`Page.add_ink_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:49 db733d1bfea845e690867fc0e23fbfea\nmsgid \"PDF only: add an ink annotation\"\nmsgstr \"PDFのみ：インク注釈を追加します\"\n\n#: ../../page.rst:50 87836b81e070400981d42f52007af7c7\nmsgid \":meth:`Page.add_line_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:50 2adc6fe8aa5c4316a257de5e2135f8e8\nmsgid \"PDF only: add a line annotation\"\nmsgstr \"PDFのみ：線アノテーションを追加します\"\n\n#: ../../page.rst:51 b2d616fda77c4a52bd1e433ed3b52703\nmsgid \":meth:`Page.add_polygon_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:51 85362227a8ad4cbfaf3fb0f24f477a3a\nmsgid \"PDF only: add a polygon annotation\"\nmsgstr \"PDFのみ：多角形アノテーションを追加します\"\n\n#: ../../page.rst:52 328e52dc8744435a9fb26981dfdc829f\nmsgid \":meth:`Page.add_polyline_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:52 11200ba7725f40f79ca3dce0a53e0658\nmsgid \"PDF only: add a multi-line annotation\"\nmsgstr \"PDFのみ：多線アノテーションを追加します\"\n\n#: ../../page.rst:53 51ed3acb625345fb8b7a53c31a1b6b19\nmsgid \":meth:`Page.add_rect_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:53 22ac83d8d3484f13a9a14fddae22e821\nmsgid \"PDF only: add a rectangle annotation\"\nmsgstr \"PDFのみ：四角アノテーション釈を追加します\"\n\n#: ../../page.rst:54 db442110b3b54ccbb5eb1ae5a44bb3d9\nmsgid \":meth:`Page.add_redact_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:54 e18de06d48a64f5b87eb5d921b043efc\nmsgid \"PDF only: add a redaction annotation\"\nmsgstr \"PDFのみ：黒塗りアノテーションを追加します\"\n\n#: ../../page.rst:55 806f505045ad4d659c8ff7424ccdb0b0\nmsgid \":meth:`Page.add_squiggly_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:55 374a25c00ffc44fb802bc987d05fd85b\nmsgid \"PDF only: add a \\\"squiggly\\\" annotation\"\nmsgstr \"PDFのみ：「波線」アノテーションを追加します\"\n\n#: ../../page.rst:56 b22a9d9ab80a4d18b3882b1b2797bc3e\nmsgid \":meth:`Page.add_stamp_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:56 9f8e591880af48f9bde9a32d695627ed\nmsgid \"PDF only: add a \\\"rubber stamp\\\" annotation\"\nmsgstr \"PDFのみ：「スタンプ」アノテーションを追加します\"\n\n#: ../../page.rst:57 1c4fffe9b32a4becb309c4360641ab34\nmsgid \":meth:`Page.add_strikeout_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:57 d6643236b85b4b26a0f3fda17a9c9ecc\nmsgid \"PDF only: add a \\\"strike-out\\\" annotation\"\nmsgstr \"PDFのみ：「取り消し線」アノテーションを追加します\"\n\n#: ../../page.rst:58 fd38c00281a845e1a4b042ac4bf44a96\nmsgid \":meth:`Page.add_text_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:58 b4a33cb834274558bd500a00ec92e154\nmsgid \"PDF only: add a comment\"\nmsgstr \"PDFのみ：コメントを追加します\"\n\n#: ../../page.rst:59 0e221e35eb7f44379a4f2046ddc3b906\nmsgid \":meth:`Page.add_underline_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:59 e068f52a14424ecaa984ab47792d7886\nmsgid \"PDF only: add an \\\"underline\\\" annotation\"\nmsgstr \"PDFのみ：「下線」アノテーションを追加します\"\n\n#: ../../page.rst:60 973d14e3ad8d4ca98132079d720bce1c\nmsgid \":meth:`Page.add_widget`\"\nmsgstr \"\"\n\n#: ../../page.rst:60 0548a6ef761045238cc51f6f030dfd77\nmsgid \"PDF only: add a PDF Form field\"\nmsgstr \"PDFのみ：PDFフォームフィールドを追加します\"\n\n#: ../../page.rst:61 e83f5334f31f49c59809b11ec3eab44c\nmsgid \":meth:`Page.annot_names`\"\nmsgstr \"\"\n\n#: ../../page.rst:61 cf863f93e5054e6c8c65e9c13f29db6b\nmsgid \"PDF only: a list of annotation (and widget) names\"\nmsgstr \"PDFのみ：アノテーション（およびウィジェット）の名前のリスト\"\n\n#: ../../page.rst:62 7d51dd8ff9a64250aff67b396cb27d97\nmsgid \":meth:`Page.annot_xrefs`\"\nmsgstr \"\"\n\n#: ../../page.rst:62 3028d6c3a5a1465295200f57fe4b9b39\nmsgid \"PDF only: a list of annotation (and widget) xrefs\"\nmsgstr \"PDFのみ：アノテーション（およびウィジェット）のxrefのリスト\"\n\n#: ../../page.rst:63 f9476aa9073b4c29b002ff703fed1459\nmsgid \":meth:`Page.annots`\"\nmsgstr \"\"\n\n#: ../../page.rst:63 62c9c440545d4ac7bbdb80a4850e7a15\nmsgid \"return a generator over the annots on the page\"\nmsgstr \"ページ上のアノテーションのジェネレーターを返します\"\n\n#: ../../page.rst:64 5ba75b9f8d854aa5ae6d8f8d0abf748e\nmsgid \":meth:`Page.apply_redactions`\"\nmsgstr \"\"\n\n#: ../../page.rst:64 54e665bc95f24b30b241db10ed18fe35\nmsgid \"PDF only: process the redactions of the page\"\nmsgstr \"PDFのみ：ページの塗りつぶしを処理します\"\n\n#: ../../page.rst:65 48940a168fa5416c9de089ffdbfd71cf\nmsgid \":meth:`Page.clip_to_rect`\"\nmsgstr \"\"\n\n#: ../../page.rst:65 75f03d5629d84a5cbe0e590d162fb8c9\nmsgid \"PDF only: remove page content outside a rectangle\"\nmsgstr \"\"\n\n#: ../../page.rst:66 88bea8ccf72f49399f12f7f909be3ca0\nmsgid \":meth:`Page.bound`\"\nmsgstr \"\"\n\n#: ../../page.rst:66 ../../page.rst:137 b7afacb8a954462e86e9d8f8b3052327\n#: f2d199f18ba54dc682035890309cc3d4\nmsgid \"rectangle of the page\"\nmsgstr \"ページの矩形\"\n\n#: ../../page.rst:67 04c89237383a468a84c1c7a4fbd7ca94\nmsgid \":meth:`Page.cluster_drawings`\"\nmsgstr \"\"\n\n#: ../../page.rst:67 cd9d4243e92c4687bd69ec2908325cfe\nmsgid \"PDF only: bounding boxes of vector graphics\"\nmsgstr \"PDFのみ：ベクトルグラフィックスの境界ボックス\"\n\n#: ../../page.rst:68 708439d9c4c8432db9603b531bb52dc1\nmsgid \":meth:`Page.delete_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:68 2fd52bbdf7674f0eaa4067190fc99fbc\nmsgid \"PDF only: delete an annotation\"\nmsgstr \"PDFのみ：アノテーションを削除します\"\n\n#: ../../page.rst:69 07e58c4b429f4cd495cdc2461631dfd2\nmsgid \":meth:`Page.delete_image`\"\nmsgstr \"\"\n\n#: ../../page.rst:69 ea1f41e1c935433d82d9c049d5bf7c51\nmsgid \"PDF only: delete an image\"\nmsgstr \"PDFのみ：画像を削除します\"\n\n#: ../../page.rst:70 7fc216eeee264ecab7dd0ca35aa1ec17\nmsgid \":meth:`Page.delete_link`\"\nmsgstr \"\"\n\n#: ../../page.rst:70 4a1fcd926d6d4a2395f61dc2dcf8d355\nmsgid \"PDF only: delete a link\"\nmsgstr \"PDFのみ：リンクを削除します\"\n\n#: ../../page.rst:71 a8258588f3ca43abb6c2210464293269\nmsgid \":meth:`Page.delete_widget`\"\nmsgstr \"\"\n\n#: ../../page.rst:71 fdbb77379c8b4f1198a09d22c552b1e7\nmsgid \"PDF only: delete a widget / field\"\nmsgstr \"PDFのみ：ウィジェット/フィールドを削除します\"\n\n#: ../../page.rst:72 d7147a663aef49b1b3198691be1cdc51\nmsgid \":meth:`Page.draw_bezier`\"\nmsgstr \"\"\n\n#: ../../page.rst:72 8b72e59ea4044e6ab49f4d05472ceba9\nmsgid \"PDF only: draw a cubic Bezier curve\"\nmsgstr \"PDFのみ：三次ベジエ曲線を描画します\"\n\n#: ../../page.rst:73 e974652a1a6f45aa8229cf5deffa331f\nmsgid \":meth:`Page.draw_circle`\"\nmsgstr \"\"\n\n#: ../../page.rst:73 ab1d3da2c8ff42fc8fe017430b57d854\nmsgid \"PDF only: draw a circle\"\nmsgstr \"PDFのみ：円を描画します\"\n\n#: ../../page.rst:74 cb75b4cc4fb54f92958534162d5b23bd\nmsgid \":meth:`Page.draw_curve`\"\nmsgstr \"\"\n\n#: ../../page.rst:74 f7ad1d0eb1434261a85c72f19d1a430a\nmsgid \"PDF only: draw a special Bezier curve\"\nmsgstr \"PDFのみ：特別なベジエ曲線を描画します\"\n\n#: ../../page.rst:75 821014e377aa404d84cbf5f34c523dbc\nmsgid \":meth:`Page.draw_line`\"\nmsgstr \"\"\n\n#: ../../page.rst:75 00ec24619ceb48a992088804eff5de28\nmsgid \"PDF only: draw a line\"\nmsgstr \"PDFのみ：直線を描画します\"\n\n#: ../../page.rst:76 bc002085ee9a4d66ba298b35bafb4599\nmsgid \":meth:`Page.draw_oval`\"\nmsgstr \"\"\n\n#: ../../page.rst:76 fef8e3d9c6e04e21b8189b2860b82f3b\nmsgid \"PDF only: draw an oval / ellipse\"\nmsgstr \"PDFのみ：楕円を描画します\"\n\n#: ../../page.rst:77 9e89eb69dd59435fb35fe33566cf57b0\nmsgid \":meth:`Page.draw_polyline`\"\nmsgstr \"\"\n\n#: ../../page.rst:77 06eaf6fd8ad042cd838a42ac93221e56\nmsgid \"PDF only: connect a point sequence\"\nmsgstr \"PDFのみ：点のシーケンスを接続します\"\n\n#: ../../page.rst:78 cf7b9e235bba401cacc271deafd6f401\nmsgid \":meth:`Page.draw_quad`\"\nmsgstr \"\"\n\n#: ../../page.rst:78 2ef56dd6206b4945bcc0e17b13b1f49b\nmsgid \"PDF only: draw a quad\"\nmsgstr \"PDF のみ: クアッドを描く\"\n\n#: ../../page.rst:79 ad64094c84b54c70a8d3f1b0356f955e\nmsgid \":meth:`Page.draw_rect`\"\nmsgstr \"\"\n\n#: ../../page.rst:79 99ffa6aaa0364c4c88ca8ac5c47de0bf\nmsgid \"PDF only: draw a rectangle\"\nmsgstr \"PDFのみ：四角形を描画します\"\n\n#: ../../page.rst:80 2c663eab158c4b11be91591a29f93faa\nmsgid \":meth:`Page.draw_sector`\"\nmsgstr \"\"\n\n#: ../../page.rst:80 02df21db9f47463ea8a7b21c97becaa0\nmsgid \"PDF only: draw a circular sector\"\nmsgstr \"PDFのみ：円セクタを描画します\"\n\n#: ../../page.rst:81 2dfce9feeb7a4c1bbad1797a7b4d6707\nmsgid \":meth:`Page.draw_squiggle`\"\nmsgstr \"\"\n\n#: ../../page.rst:81 fda33db89e424deeb78ea729069a761e\nmsgid \"PDF only: draw a squiggly line\"\nmsgstr \"PDFのみ：波線を描画します\"\n\n#: ../../page.rst:82 f18233d62ec842ce8d0ec507f6ca4432\nmsgid \":meth:`Page.draw_zigzag`\"\nmsgstr \"\"\n\n#: ../../page.rst:82 2c0fde654875416f905af2f467b3cf1c\nmsgid \"PDF only: draw a zig-zagged line\"\nmsgstr \"PDFのみ：ジグザグ線を描画します\"\n\n#: ../../page.rst:83 0ad5611bf2ea4d9797c43b07aaf17f67\nmsgid \":meth:`Page.find_tables`\"\nmsgstr \"\"\n\n#: ../../page.rst:83 3c716fff66534b89be3e42bff1821cae\nmsgid \"locate tables on the page\"\nmsgstr \"ページ上のテーブルを検出します\"\n\n#: ../../page.rst:84 9760c26080364bb38b892d7079635820\nmsgid \":meth:`Page.get_drawings`\"\nmsgstr \"\"\n\n#: ../../page.rst:84 1a642c31f38440c99d4eed26eca1cf1e\nmsgid \"get vector graphics on page\"\nmsgstr \"ページ上のベクトルグラフィックを取得します\"\n\n#: ../../page.rst:85 ../../page.rst:2355 0212137293b847f19ef60d639f77da9f\n#: bd4a028783c641958b19f4cf86d7d235\nmsgid \":meth:`Page.get_fonts`\"\nmsgstr \"\"\n\n#: ../../page.rst:85 8ffe9443af43443788c6103faf1fe29f\nmsgid \"PDF only: get list of referenced fonts\"\nmsgstr \"PDFのみ：参照されたフォントのリストを取得\"\n\n#: ../../page.rst:86 d299b9cb1da54036adf1f73e8fe204f5\nmsgid \":meth:`Page.get_image_bbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:86 258e644759a344a1a93e5fe92f4d572d\nmsgid \"PDF only: get bbox and matrix of embedded image\"\nmsgstr \"PDFのみ：埋め込まれた画像のバウンディングボックスと行列を取得\"\n\n#: ../../page.rst:87 28b400999b9b44a897e4ff4130298469\nmsgid \":meth:`Page.get_image_info`\"\nmsgstr \"\"\n\n#: ../../page.rst:87 1fc9f5618837431d95f9edc92be81f1f\nmsgid \"get list of meta information for all used images\"\nmsgstr \"使用されるすべての画像のメタ情報のリストを取得\"\n\n#: ../../page.rst:88 356cdd777ea54c359213f21664133141\nmsgid \":meth:`Page.get_image_rects`\"\nmsgstr \"\"\n\n#: ../../page.rst:88 85adc8a6b1f7459186e411e073476e72\nmsgid \"PDF only: improved version of :meth:`Page.get_image_bbox`\"\nmsgstr \"PDFのみ： :meth:`Page.get_image_bbox` の改良バージョンを取得\"\n\n#: ../../page.rst:89 ../../page.rst:2356 9c773ca1a4c04ae39dd31e751a19d4a8\n#: f6df8c02ac2a4f6083b0ad1a477980f3\nmsgid \":meth:`Page.get_images`\"\nmsgstr \"\"\n\n#: ../../page.rst:89 463a60e6db60402bbfd7e0365544fcc5\nmsgid \"PDF only: get list of referenced images\"\nmsgstr \"PDFのみ：参照された画像のリストを取得\"\n\n#: ../../page.rst:90 72a5fbb7f5ae4b5aba9cd75c236dfd17\nmsgid \":meth:`Page.get_label`\"\nmsgstr \"\"\n\n#: ../../page.rst:90 8a64a3606f554ddca8135f8fcf01bdcb\nmsgid \"PDF only: return the label of the page\"\nmsgstr \"PDFのみ：ページのラベルを返す\"\n\n#: ../../page.rst:91 3d9b2f63e38640eba28039648bcdd37c\nmsgid \":meth:`Page.get_links`\"\nmsgstr \"\"\n\n#: ../../page.rst:91 baebde09d09f4430a9a16ab90e53e61c\nmsgid \"get all links\"\nmsgstr \"すべてのリンクを取得\"\n\n#: ../../page.rst:92 ../../page.rst:2357 4a56014985a94a87ac357a4612aaf5fa\n#: ed985753e8674d2c99c1b565cc9ccbf7\nmsgid \":meth:`Page.get_pixmap`\"\nmsgstr \"\"\n\n#: ../../page.rst:92 dfbe408764ca4ea7a194aeda516c3b3b\nmsgid \"create a page image in raster format\"\nmsgstr \"ラスターフォーマットのページイメージを作成\"\n\n#: ../../page.rst:93 84ff5221a3f34016b7d222d2a504b8d8\nmsgid \":meth:`Page.get_svg_image`\"\nmsgstr \"\"\n\n#: ../../page.rst:93 d47abd082cf34e8ba1416053d7f9f36c\nmsgid \"create a page image in SVG format\"\nmsgstr \"SVGフォーマットのページイメージを作成\"\n\n#: ../../page.rst:94 ../../page.rst:2358 236e4ae277e5430092c860d3b877309e\n#: 534bf943e881493a9c1890cf7869b882\nmsgid \":meth:`Page.get_text`\"\nmsgstr \"\"\n\n#: ../../page.rst:94 8fcda9fdb4054ee4925dd13a83d5c7f9\nmsgid \"extract the page's text\"\nmsgstr \"ページのテキストを抽出\"\n\n#: ../../page.rst:95 8e3abc00882d408bad7eb252ba91611b\nmsgid \":meth:`Page.get_textbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:95 05aaa24df0f34405b93ba13e56afaffd\nmsgid \"extract text contained in a rectangle\"\nmsgstr \"特定の矩形に含まれるテキストを抽出\"\n\n#: ../../page.rst:96 25d5c92ec4e64cb6b99f8822be72860a\nmsgid \":meth:`Page.get_textpage_ocr`\"\nmsgstr \"\"\n\n#: ../../page.rst:96 1b455eb2a8fe4616a02979e821ec50ce\nmsgid \"create a TextPage with OCR for the page\"\nmsgstr \"ページのOCR付きのTextPageを作成\"\n\n#: ../../page.rst:97 b452235a93834d8b98588dc1103fdda3\nmsgid \":meth:`Page.get_textpage`\"\nmsgstr \"\"\n\n#: ../../page.rst:97 86c970be01be4a46b056f68be2cc43b9\nmsgid \"create a TextPage for the page\"\nmsgstr \"ページのTextPageを作成\"\n\n#: ../../page.rst:98 f5ea422d48294efdb6c416ce7dc132c5\nmsgid \":meth:`Page.get_xobjects`\"\nmsgstr \"\"\n\n#: ../../page.rst:98 074c5bea324d4dd7b71a76685d7bf5ac\nmsgid \"PDF only: get list of referenced xobjects\"\nmsgstr \"PDFのみ：参照されたxobjectのリストを取得\"\n\n#: ../../page.rst:99 fad014b3566248f2b8fef12ad6d63683\nmsgid \":meth:`Page.insert_font`\"\nmsgstr \"\"\n\n#: ../../page.rst:99 a13f7d11090b45e7b1e1fdcd51b6771b\nmsgid \"PDF only: insert a font for use by the page\"\nmsgstr \"PDFのみ：ページで使用するフォントを挿入\"\n\n#: ../../page.rst:100 eb9fab9be3844f698f3f7981238fd0cc\nmsgid \":meth:`Page.insert_image`\"\nmsgstr \"\"\n\n#: ../../page.rst:100 5ecd33232193401eba7aad556bde3428\nmsgid \"PDF only: insert an image\"\nmsgstr \"PDFのみ：画像を挿入\"\n\n#: ../../page.rst:101 bf9559cfcb304283b984cd3b63082707\nmsgid \":meth:`Page.insert_link`\"\nmsgstr \"\"\n\n#: ../../page.rst:101 065c8f93c7394778aa3bece800130689\nmsgid \"PDF only: insert a link\"\nmsgstr \"PDFのみ：リンクを挿入\"\n\n#: ../../page.rst:102 77c641ea6e564e8eb59cd4339292bdcd\nmsgid \":meth:`Page.insert_text`\"\nmsgstr \"\"\n\n#: ../../page.rst:102 93437db590444321bf292dcc19733056\nmsgid \"PDF only: insert text\"\nmsgstr \"PDFのみ：テキストを挿入\"\n\n#: ../../page.rst:103 c552d045e73f45f9b03240ef2fab0611\nmsgid \":meth:`Page.insert_htmlbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:103 bdbe18d30a0c4be9875135057d42044e\nmsgid \"PDF only: insert html text in a rectangle\"\nmsgstr \"PDFのみ: 指定された矩形にテキストを追加します。\"\n\n#: ../../page.rst:104 119b6fdbf8b44f5f84c8616c320b6d0a\nmsgid \":meth:`Page.insert_textbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:104 33a379824b3d46c7b6df06f0d0e25eb1\nmsgid \"PDF only: insert a text box\"\nmsgstr \"PDFのみ：テキストボックスを挿入\"\n\n#: ../../page.rst:105 e4a2a7be4af54df396d64469f81c0902\nmsgid \":meth:`Page.links`\"\nmsgstr \"\"\n\n#: ../../page.rst:105 6752a070405544cba6cff49390f95edd\nmsgid \"return a generator of the links on the page\"\nmsgstr \"ページ上のリンクのジェネレータを返す\"\n\n#: ../../page.rst:106 10bf8179f1ce486fabaa949403bacd70\nmsgid \":meth:`Page.load_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:106 014af39f35314a68afbe150161286b66\nmsgid \"PDF only: load a specific annotation\"\nmsgstr \"PDFのみ：特定のアノテーションを読み込む\"\n\n#: ../../page.rst:107 e1685690b2d44e14a8978d8b1339627e\nmsgid \":meth:`Page.load_widget`\"\nmsgstr \"\"\n\n#: ../../page.rst:107 5f2f4a616a774f9d92c511a1bc7eec7d\nmsgid \"PDF only: load a specific field\"\nmsgstr \"PDFのみ：特定のフィールドを読み込む\"\n\n#: ../../page.rst:108 a8dd3d29d1384269b38a150ffdca450c\nmsgid \":meth:`Page.load_links`\"\nmsgstr \"\"\n\n#: ../../page.rst:108 c159d07089f2405190c47cf67e28fb74\nmsgid \"return the first link on a page\"\nmsgstr \"ページ上の最初のリンクを返す\"\n\n#: ../../page.rst:109 94bb3a983df740fbbbc60a44a7e75a25\nmsgid \":meth:`Page.new_shape`\"\nmsgstr \"\"\n\n#: ../../page.rst:109 f7e23a9cbe464b7fbd4ceafb2bd2f884\nmsgid \"PDF only: create a new :ref:`Shape`\"\nmsgstr \"PDFのみ：新しい :ref:`Shape` を作成\"\n\n#: ../../page.rst:110 e7cbb0a3cc32479290ed8187d341a4cc\nmsgid \":meth:`Page.recolor`\"\nmsgstr \"\"\n\n#: ../../page.rst:110 e17cc9c9d35a4b528ecc51356afc4294\nmsgid \"PDF only: change the colorspace of objects\"\nmsgstr \"\"\n\n#: ../../page.rst:111 2b963b54441840a5a4ff1089e26ecb2f\nmsgid \":meth:`Page.remove_rotation`\"\nmsgstr \"\"\n\n#: ../../page.rst:111 2a452763180a40b8b9d7840ae8da0992\n#, fuzzy\nmsgid \"PDF only: set page rotation to 0\"\nmsgstr \"PDFのみ：ページの回転を設定\"\n\n#: ../../page.rst:112 8f321974b8444af0b093d1295c75cf05\nmsgid \":meth:`Page.replace_image`\"\nmsgstr \"\"\n\n#: ../../page.rst:112 a847c5c8166640328cfb165bbaa6a992\nmsgid \"PDF only: replace an image\"\nmsgstr \"PDFのみ：画像を置換\"\n\n#: ../../page.rst:113 ../../page.rst:2359 0f7e94bdfa2048379aadc4ec274917ac\n#: 474092e2fbb04bd8b3fb386d1de12af5\nmsgid \":meth:`Page.search_for`\"\nmsgstr \"\"\n\n#: ../../page.rst:113 6556b8acd7d240d7b97207cf0df3d619\nmsgid \"search for a string\"\nmsgstr \"文字列を検索\"\n\n#: ../../page.rst:114 dac3b78a1a3c43848aa71d71a9ac932f\nmsgid \":meth:`Page.set_artbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:114 c5cb8b37faa84d478e691b9d7aeeb072\nmsgid \"PDF only: modify `/ArtBox`\"\nmsgstr \"PDFのみ： `/ArtBox` を変更\"\n\n#: ../../page.rst:115 f33dd235a0224b98a72d79e99d400754\nmsgid \":meth:`Page.set_bleedbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:115 03a5e490c9f342c1b33650557bb311cf\nmsgid \"PDF only: modify `/BleedBox`\"\nmsgstr \"PDFのみ：/BleedBoxを変更\"\n\n#: ../../page.rst:116 1954aab05621455aafbf63b3dc604da9\nmsgid \":meth:`Page.set_cropbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:116 662dd3600dac46358c61710f34c8ec91\nmsgid \"PDF only: modify the :data:`cropbox` (visible page)\"\nmsgstr \"PDFのみ： :data:`cropbox` （可視ページ）を変更\"\n\n#: ../../page.rst:117 6a2fd94e05d047a1a8f604c96105f9d2\nmsgid \":meth:`Page.set_mediabox`\"\nmsgstr \"\"\n\n#: ../../page.rst:117 2b67269297d34d6c9ac1dee4f63a8961\nmsgid \"PDF only: modify `/MediaBox`\"\nmsgstr \"PDFのみ：/MediaBoxを変更\"\n\n#: ../../page.rst:118 3c19f680917744e48b7ffa6e60497c91\nmsgid \":meth:`Page.set_rotation`\"\nmsgstr \"\"\n\n#: ../../page.rst:118 44b06f5ab1f4409db21e8180c6840f21\nmsgid \"PDF only: set page rotation\"\nmsgstr \"PDFのみ：ページの回転を設定\"\n\n#: ../../page.rst:119 8f9ca0aa08a7434faaa9e139cc23c4cc\nmsgid \":meth:`Page.set_trimbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:119 e1be1521eed84ba3ac0ec715ca539607\nmsgid \"PDF only: modify `/TrimBox`\"\nmsgstr \"PDFのみ：`/TrimBox` を変更\"\n\n#: ../../page.rst:120 e490c2e919d348a8bd996d89b6379831\nmsgid \":meth:`Page.show_pdf_page`\"\nmsgstr \"\"\n\n#: ../../page.rst:120 0ca4ee87ad0d45d999070687313ee6c2\nmsgid \"PDF only: display PDF page image\"\nmsgstr \"PDFのみ：PDFページ画像を表示\"\n\n#: ../../page.rst:121 373f0f9543e5488e8bd497bb817ff8c0\nmsgid \":meth:`Page.update_link`\"\nmsgstr \"\"\n\n#: ../../page.rst:121 3916b852a5ab4aef891aee7bd6819784\nmsgid \"PDF only: modify a link\"\nmsgstr \"PDFのみ：リンクを変更\"\n\n#: ../../page.rst:122 833c40f55d4c480bae57ee0a61660f55\nmsgid \":meth:`Page.widgets`\"\nmsgstr \"\"\n\n#: ../../page.rst:122 54727116195946e3a45618e914ff037f\nmsgid \"return a generator over the fields on the page\"\nmsgstr \"ページ上のフィールドのジェネレータを返す\"\n\n#: ../../page.rst:123 dd2c38c530664eda8d7154c879458e0d\nmsgid \":meth:`Page.write_text`\"\nmsgstr \"\"\n\n#: ../../page.rst:123 a543915750f14b829b0c094cb7bfe01d\nmsgid \"write one or more :ref:`Textwriter` objects\"\nmsgstr \"1つ以上の :ref:`Textwriter` オブジェクトを書き込む\"\n\n#: ../../page.rst:124 9adae32b783846ffb5e94e4430cac493\nmsgid \":attr:`Page.cropbox_position`\"\nmsgstr \"\"\n\n#: ../../page.rst:124 31b13eebd9f441bcab940d3c944776b8\nmsgid \"displacement of the :data:`cropbox`\"\nmsgstr \":data:`cropbox` の位置\"\n\n#: ../../page.rst:125 1e42f4312b634f3f9c8e85739c813eb8\nmsgid \":attr:`Page.cropbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:125 cf64d8442e414dc0879c602b3b0b489e\nmsgid \"the page's :data:`cropbox`\"\nmsgstr \"ページの :data:`cropbox`\"\n\n#: ../../page.rst:126 fc92d1a42e694fa6ac0161ed12cb39c0\nmsgid \":attr:`Page.artbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:126 ff906dbe697d49c0989435a6d87f1a1d\nmsgid \"the page's `/ArtBox`\"\nmsgstr \"ページの `/ArtBox`\"\n\n#: ../../page.rst:127 a73f503950b14012a9d0b865c3a9b45b\nmsgid \":attr:`Page.bleedbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:127 a368349472a349a381872c4867d6b3a6\nmsgid \"the page's `/BleedBox`\"\nmsgstr \"ページの `/BleedBox`\"\n\n#: ../../page.rst:128 1215951372f347e498df9704fb8e3912\nmsgid \":attr:`Page.trimbox`\"\nmsgstr \"\"\n\n#: ../../page.rst:128 e299310368b645b396a106343b8f3f97\nmsgid \"the page's `/TrimBox`\"\nmsgstr \"ページの `/TrimBox`\"\n\n#: ../../page.rst:129 07634bad562d4f4da72af4503f45af6c\nmsgid \":attr:`Page.derotation_matrix`\"\nmsgstr \"\"\n\n#: ../../page.rst:129 62bff9b163644f9a8a4d57b8c38631b5\nmsgid \"PDF only: get coordinates in unrotated page space\"\nmsgstr \"PDFのみ：回転されていないページ空間内の座標を取得\"\n\n#: ../../page.rst:130 9d8f0942aabf4466872c935bff52be92\nmsgid \":attr:`Page.first_annot`\"\nmsgstr \"\"\n\n#: ../../page.rst:130 9b10c13e23d649018aaaa01888b0752c\nmsgid \"first :ref:`Annot` on the page\"\nmsgstr \"ページ上の最初の :ref:`Annot`\"\n\n#: ../../page.rst:131 007425f57c1c45cab27b9fd5356dc25c\nmsgid \":attr:`Page.first_link`\"\nmsgstr \"\"\n\n#: ../../page.rst:131 599bf77705da424f9842f1fc4593e422\nmsgid \"first :ref:`Link` on the page\"\nmsgstr \"ページ上の最初の :ref:`Link`\"\n\n#: ../../page.rst:132 d306281af9fe472ebd48cb5da990d400\nmsgid \":attr:`Page.first_widget`\"\nmsgstr \"\"\n\n#: ../../page.rst:132 c045b6255e904caeb1248136a17fdcb4\nmsgid \"first widget (form field) on the page\"\nmsgstr \"ページ上の最初のウィジェット（フォームフィールド）\"\n\n#: ../../page.rst:133 61a7569544b04f579eeeccb6dbebf33e\nmsgid \":attr:`Page.mediabox_size`\"\nmsgstr \"\"\n\n#: ../../page.rst:133 5740d94335274d2cb2f1a0aaed9e73d2\nmsgid \"bottom-right point of :data:`mediabox`\"\nmsgstr \":data:`mediabox` の右下のポイント\"\n\n#: ../../page.rst:134 93c29178cc5749b6829fd8dfed0b62f9\nmsgid \":attr:`Page.mediabox`\"\nmsgstr \"\"\n\n#: ../../page.rst:134 8800f1ba240a448a94f2b724b21b6f97\nmsgid \"the page's :data:`mediabox`\"\nmsgstr \"ページの :data:`mediabox`\"\n\n#: ../../page.rst:135 c50c79da136d456fa1b50250eea7203e\nmsgid \":attr:`Page.number`\"\nmsgstr \"\"\n\n#: ../../page.rst:135 0fc96eb9fc344189ad927dad1dbfc341\nmsgid \"page number\"\nmsgstr \"ページ番号\"\n\n#: ../../page.rst:136 695f5ae69bcd4635b33ebd6ed673c706\nmsgid \":attr:`Page.parent`\"\nmsgstr \"\"\n\n#: ../../page.rst:136 4061cff6ba714b82bd4a109854384956\nmsgid \"owning document object\"\nmsgstr \"所属するドキュメントオブジェクト\"\n\n#: ../../page.rst:137 ddc6ff6c91ee414dbdf6805bbe28c767\nmsgid \":attr:`Page.rect`\"\nmsgstr \"\"\n\n#: ../../page.rst:138 1ea7f17570a540a989a56c5b01d20bff\nmsgid \":attr:`Page.rotation_matrix`\"\nmsgstr \"\"\n\n#: ../../page.rst:138 f3a09c1c09e046388be436720f61b660\nmsgid \"PDF only: get coordinates in rotated page space\"\nmsgstr \"PDFのみ：回転したページ空間内の座標を取得\"\n\n#: ../../page.rst:139 ddf87c132d5e429eb3e16dd0d9a7533a\nmsgid \":attr:`Page.rotation`\"\nmsgstr \"\"\n\n#: ../../page.rst:139 b85fb7d6d7ad4c7ab2a14c0d2093c398\nmsgid \"PDF only: page rotation\"\nmsgstr \"PDFのみ：ページの回転\"\n\n#: ../../page.rst:140 8af77a0f8bb64059bbb281a4e56ca015\nmsgid \":attr:`Page.transformation_matrix`\"\nmsgstr \"\"\n\n#: ../../page.rst:140 092b7fc6ca7a4d0f86bfb8f90459e30f\nmsgid \"PDF only: translate between PDF and MuPDF space\"\nmsgstr \"PDFのみ：PDFとMuPDFのスペース間を変換\"\n\n#: ../../page.rst:141 bb906c9e47254441950fe2061cb7283f\nmsgid \":attr:`Page.xref`\"\nmsgstr \"\"\n\n#: ../../page.rst:141 4e19cd5ead774a58b9478f33dfc08d66\nmsgid \"PDF only: page :data:`xref`\"\nmsgstr \"PDFのみ：ページの :data:`xref`\"\n\n#: ../../page.rst:144 7dd691ddf1214165b60d22ae28b1c9f0\nmsgid \"**Class API**\"\nmsgstr \"**クラス API**\"\n\n#: ../../page.rst:150 c7b40172c5bc47398e0abf78d418e310\nmsgid \"\"\n\"Determine the rectangle of the page. Same as property :attr:`Page.rect`. \"\n\"For PDF documents this **usually** also coincides with :data:`mediabox` \"\n\"and :data:`cropbox`, but not always. For example, if the page is rotated,\"\n\" then this is reflected by this method -- the :attr:`Page.cropbox` \"\n\"however will not change.\"\nmsgstr \"\"\n\"ページの長方形を決定します。下記の :attr:`Page.rect` プロパティと同じです。PDF文書の場合、通常は \"\n\":data:`mediabox` と :data:`cropbox` \"\n\"と一致しますが、常にそうとは限りません。たとえば、ページが回転している場合、このメソッドに反映されますが、:attr:`Page.cropbox`\"\n\" は変更されません。\"\n\n#: ../../page.rst 07da7245f1d64a65b2b4254797f65491\n#: 16467ad0e8d64d7d85006bda933b3200 274157befb1b469fa2f28b340c60adc9\n#: 33737a34b2944633a24492dbe9c2d147 3f24c0b2d0254e06b54bf5e2b6f88555\n#: 43215cbc86534ac285647938e0b2a2a2 6ad65941237c4751902d551fa14d5e71\n#: 780c66ef56ae428dba33fe118ceaeb0e 7f54a5a3c98d4cebb61a506237a4643e\n#: 86172078b6f44f549b02563feed36a81 963bc09177024b08b6c785605249a826\n#: 986fd139ad45437e87c7593c11d6a47b 9a2fe8da29584084a592464409782175\n#: 9fb73c5f593f462a967426864943a5aa a42bc637a18a46dfb72820a97f51ba1a\n#: ab3dd8b5e88049939c12db64481baefa b05be138bafb4bb2ae77367972743409\n#: b14e9f1be1b74a14844053e00ed4bf02 c2858bea2fa445b695054db4f9bb3e3d\n#: c2a8aab54fbb4862893ab1555e5fad49 c8bc2f1e08e5407ab1670a313332ad5e\n#: ceae107b8e8a40d7a69d740fb4d3a283 d3bf58c1898f437c81297b2d9ddd04b0\n#: de7a1f0132d34b6d8cf9fd97e950cf77 dfa066004b01431aaca46c33f8710478\n#: e079c387d0ec447cb4127c54e273c96e e16013432c3c473797fe1429e17df94b\n#: ee88a3da14804c22825ad9be9d13dc1c f19ee08a02c543e4b42dff9b4d74f1d3\n#: fb45ddf994894d8e82465a6136c23734\nmsgid \"Return type\"\nmsgstr \"戻り値の型\"\n\n#: ../../page.rst:152 ../../page.rst:2200 ../../page.rst:2210\n#: ../../page.rst:2222 ../../page.rst:2283 ../../page.rst:2289\n#: ../../page.rst:2432 ../../page.rst:2492 17dce4a3dac0430f981fd5f333253854\n#: 1fcc8c10d3314f7ba2155b0f3e8a20fb 70bf6ccb650d40ec885b1b2a34b36172\n#: 72236d1673274a9781172bacbbac9335 7cc89df9fff64c9aac0c90c75083a7e6\n#: 87c39a1029e54b5990a21c179e2f359d a7543904f25e400681f49fb50b50c9de\n#: be7afb8df5954242b2dca9c5af5a1e97\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../page.rst:156 0ec0c7438154470994b23ca319d41d4d\nmsgid \"\"\n\"PDF only: Add a caret icon. A caret annotation is a visual symbol \"\n\"normally used to indicate the presence of text edits on the page.\"\nmsgstr \"\"\n\"PDFのみ: \"\n\"ケアットアイコンを追加します。ケアットアノテーションは通常、ページ上でテキストの編集が存在することを示すために使用される視覚的なシンボルです\"\n\n#: ../../page.rst 00b3632567644912bffe0c7c68195548\n#: 054320e3c706475d93bbf517174a2cd9 0878b21ab311460bb8d044b195f065c9\n#: 09105ffebd5b4af99479ab1908edbf71 09d72a257dd8425ab36e4cf43950a91d\n#: 0da394c31bee4739a806cd889c071c24 1367cad38f644d23983d0e9832ffec1d\n#: 16b87a761f6947ecae635b1721df752a 2028dc07db06471db752d79ad2b97ad4\n#: 20957df1cc49455882744213ebf99d1f 291031d6bab54401ba4808b736782a57\n#: 2fb9573932ef4990aa17dad40ec62903 31c0111741a24d9984a4f7e8f6d384d6\n#: 38bbd18c135b4b35b2e8265a0abd6588 3d67d0eb2fe04c27aacb768de4673ca0\n#: 40031e90ddd54975b1bda8bf0a808d63 46529b455a46414f8fc3569e8cd74ee0\n#: 498ee9c49c214e368374cf7456d63aef 4d3cee8bc2d1469d9a7dd085fddcd328\n#: 503687535947403eb1e47df55fe26cc2 535cf8e9a9484fefaf11b8666a8a6642\n#: 54f7a37e80354629988dce94a656e940 5bf5fff4bcbb4463ad26a8a5f6b5eb1e\n#: 6d08910d5dc84544b81029616ce95d40 71f8f7f7626947a39f84c7bcad375207\n#: 7e7bec8634ba460780bca9ae053753bc 8302f70a54514fbc89e0b1dde1048026\n#: 84033749e37e4b759f3ebe8c94d59fd3 8e4bcb6977f14382bbbbd46621f00dc1\n#: 941fa38cd676457fbe97b6490b7ae8cf 9a6bc2252f91444aa5ec776c39df263e\n#: 9d5a62b410b947b8865a28874d59ea97 a33d3566faac442ab7b530abc59aa4e5\n#: ae64f9becd5347639cb3883b239e0f88 b25079f1b5b942f88cd338be4b0166e4\n#: b87de502ffdf4ccb85876fbefa001a43 b8c63bbc665f43f1ae6aee0196ff6cae\n#: bb5b5a5eb33b48d19ffa688a1384052a c3ff7da5a1f844cfb8ec962ae1c60da4\n#: ca7e4f1b3e0f4da39ef4397d425ffad9 d000ac18dfbe40e28fd0bdc71f3a858b\n#: d74c4ba05c7449d3a2b8faa4188e1fe1 f1f1aceff0ce40aeac912afeece61dac\n#: f280525254e24464af14333042b57307 f40fc35b625c4b8ab27414a1e0a2c197\n#: f8023b505b6749289bf7f1735ff8dc84 f8cb1838b1c74387ae60068ec2949d7d\n#: fdaf5844924a4192b07017546577808b\nmsgid \"Parameters\"\nmsgstr \"パラメータ\"\n\n#: ../../page.rst:158 f1fd38d47b7b448b98e7fc18cdf0610d\nmsgid \"\"\n\"the top left point of a 20 x 20 rectangle containing the MuPDF-provided \"\n\"icon.\"\nmsgstr \"point (point_like) – MuPDFが提供するアイコンを含む20 x 20の長方形の左上のポイント。\"\n\n#: ../../page.rst:160 ../../page.rst:181 ../../page.rst:240 ../../page.rst:264\n#: ../../page.rst:273 ../../page.rst:284 ../../page.rst:295 ../../page.rst:323\n#: ../../page.rst:388 ../../page.rst:600 ../../page.rst:1923\n#: ../../page.rst:2258 0a58216226494e178dde4651b0611959\n#: 1fe577105c91488e9f0560a7b8796e99 2877c7fb524b42e0b6e9275ef04a546e\n#: 5605b94a8f004396a557de9db39517c5 58d03141cddf4ab89128aacdfc62091e\n#: 6b8b6d0719d745b699b11d162b55b2b3 9068eacd05c74b9aa20035a54a6bfd25\n#: 90aa1e78784a47c383c80669c4fb882c 9fa31f84235845bca516caf1ba22f068\n#: a59e0172e0fd4306839da9756ad512a0 b7f3ee5707fe4eadb31fad70473e9aeb\n#: b9c8a147995d4e00940e43b61dca788f\nmsgid \":ref:`Annot`\"\nmsgstr \"\"\n\n#: ../../page.rst 0dffbb758e964d6d8e27b7cc916fcece\n#: 19fbc273b908406d9bebee248b9f341e 1ab9f9b6b79c430ebfac79d31add954f\n#: 1dd29dece91e45be836be0ec87b241f5 2bec5ff55c37456483e4dafce21fed0a\n#: 40db1e056e2e4015a335ef534d7d7d09 42075d2ac0074ccfad9579bf6a79fa97\n#: 4355228500d64c04877e4ef51bf816a2 46ab70cb395f45efa6127ced35e93b87\n#: 49e64f07d58e457a9516b85180e23e8f 4b7549ca59cf4895854db1abc8ac1c6d\n#: 4e7c576b76ad419db6610f3bbc600de3 517df8f478b340bbb8fb49f29e7075f9\n#: 5ff6d3905f974c44ab6b29bd90db2428 6197d8c4c73844138b4c591ce0ba628e\n#: 61cef6bf48df4cec82d6645cfd249e28 63a63e53773f4fa6a34666d256a266c5\n#: 6d4f832405714fcb9c1d1a4e6bcd3f97 74b115386a78411cb1e82b6401e27f88\n#: 7c0515b75c9146acb8105883bc9ff293 804e462e6dc8457fa3baee083aa7c0af\n#: 81628f78bf8f4fc0a7752cceb4e6b7a8 8180d1bab4e44971968d755badc44129\n#: 81d0d0a948bf405eadb682854c67e850 870d5db2cc324545a4c6657a37454ca5\n#: 90896fe1186947b891c9e82e55d7eb0a 916f9182ca0b44f0be8298f1610ee103\n#: 99a9710b564e4de1bbb28e4e6e4816ae 9c8d55eba9d7433f9e9fee31b10de98e\n#: a5242692396a4b0f88b0461287fd9538 a79f1c2cced84134bae0b2cbdb521451\n#: c536198c110441ec8f582db7296da842 c81c6629c1d743ada613c4cd50b30e27\n#: de8e6016be4241f28bcb504a7760cbe6 dfff7bd57dab4210bfeee1741e0dba54\n#: e253b98abd6b43f1821d613362b34a45 eaaa3a14ee1e4d228a712a52abd75d6c\n#: ef0de4bbb46d4b7ebf89f100548e5a7e ef162dbd023c4bcfbffbc4bd1bb5e973\n#: f5694bc35f254fc3ad0381ec573bad5b\nmsgid \"Returns\"\nmsgstr \"戻り値\"\n\n#: ../../page.rst:161 725d7121e14f4a59ac0c7b1fdce04357\nmsgid \"\"\n\"the created annotation. Stroke color blue = (0, 0, 1), no fill color \"\n\"support.\"\nmsgstr \"作成されたアノテーション。ストロークの色は青=(0, 0, 1)で、塗りつぶしの色はサポートされていません。\"\n\n#: ../../page.rst:166 ../../page.rst:243 ../../page.rst:328 ../../page.rst:368\n#: ../../page.rst:540 ../../page.rst:613 ../../page.rst:649 ../../page.rst:671\n#: ../../page.rst:696 ../../page.rst:711 ../../page.rst:733 ../../page.rst:761\n#: ../../page.rst:790 ../../page.rst:857 ../../page.rst:894 ../../page.rst:919\n#: ../../page.rst:944 ../../page.rst:968 ../../page.rst:992 ../../page.rst:1017\n#: ../../page.rst:1041 ../../page.rst:1066 ../../page.rst:1090\n#: ../../page.rst:1115 ../../page.rst:1140 ../../page.rst:1321\n#: ../../page.rst:1369 ../../page.rst:1393 ../../page.rst:1451\n#: ../../page.rst:1479 ../../page.rst:1501 ../../page.rst:1542\n#: ../../page.rst:1653 ../../page.rst:1676 ../../page.rst:1735\n#: ../../page.rst:1765 ../../page.rst:1785 ../../page.rst:1800\n#: ../../page.rst:1841 ../../page.rst:1882 ../../page.rst:1896\n#: ../../page.rst:1910 ../../page.rst:1928 ../../page.rst:1945\n#: ../../page.rst:2046 ../../page.rst:2083 ../../page.rst:2107\n#: ../../page.rst:2125 ../../page.rst:2172 06e0aca46a0b497995a0933772704269\n#: 141cb4fdb9f645d4aeaea7b7024a5052 1a66f50d90b04e749b4732040a0034bf\n#: 2003c624641d4d84acb78c5bc64570f3 2c4d8bd8d31e4b3d9e373b8eb7af09c2\n#: 30c98e90c3b44ec789d6ba46abf05fa1 3224c46abf7343f4afe5cf8537bf7fa1\n#: 34d52f2c3e7648e6897fd5ff07398ab3 3b45669122f9411fa021821d3d9661d7\n#: 3c4ea15bd48a46b791a050505f8caaee 3d5e060b49d34386b501bf1b8b7c8d1c\n#: 4988794a42404e5bba37c3323e105fd1 512b3c36f1914ccb91651173577f889e\n#: 52f0d7450dfe49a78ddf7879e240686a 5a3e49f66f844cf7a226447ba515514c\n#: 5ce877309d474b3895438c07db4cc025 5d8bc521f1ab40bea08f06305a0133dc\n#: 62fa68c4de434ad89adf8fd663faa9b0 6aafe1bc29f6405c8373a8f764191655\n#: 747b6c2893d54c3f97ed3377cb0e1ce5 766bfd0bdee34cb9a30b2444fa9640e3\n#: 76a3a3500f1341a8a5423df815a5d80e 77777ddfc172483ba1f24281cef1af24\n#: 8306e28fb421477ca15958f8993a706a 83b6f324e7d44593a436db0e839ee638\n#: 84a409e92469401cb2471c796119ffda 8bdd9f15f33f4127a32d7bcfc7ec4422\n#: 913f042d35ea407b8ae71b5c88d7ebb0 92eca8a07ce840e58717a6f674b107f8\n#: 9d3f92cd8fb1461e99f67ee8f00ffce3 9f34f467e9c2454ea41e4bd724b6f44b\n#: aa47e7de7bbf4ab9b38289d426fc55b1 aba5c0dd558b410ea11ca40a3e8a9fe6\n#: aecae63f68e646e8aad20d73eda5ee5e af34016c28c84aa7aab373f75a440f93\n#: b3689628e86b4de7a18aebf3de050de5 b46fa7c15f2343d184eec41fd9db3529\n#: ce4a7227d53b4c0bb56195ad279b5e34 d13c0eba77cb4d9ab1f7288b8ce2f473\n#: d2499636a4484e5eb81c6ad965045c9e d2c46e917760489bbc62741618ea979a\n#: d496035da211495894f02763aab46d52 d4b1c15d3db94414aa4c77f192dc5e62\n#: d539de04647e4ddeaf022884e895ff0e dafe015561de445e8048fba403c2f26c\n#: df8f779752144b98944a98a1f1fe0b99 e2839fd8badb49bfaa229c37513be843\n#: e76ecfba7ee24286bcb6ee2406fd255a e827f59db4b44f1f9f7b0e526f8bef78\nmsgid \"|history_begin|\"\nmsgstr \"\"\n\n#: ../../page.rst:168 a432ca9a84a64f4f93ffef1d2d8b1818\nmsgid \"New in v1.16.0\"\nmsgstr \"v1.16.0で新たに追加された\"\n\n#: ../../page.rst:170 ../../page.rst:247 ../../page.rst:332 ../../page.rst:376\n#: ../../page.rst:545 ../../page.rst:617 ../../page.rst:653 ../../page.rst:675\n#: ../../page.rst:700 ../../page.rst:715 ../../page.rst:737 ../../page.rst:765\n#: ../../page.rst:794 ../../page.rst:870 ../../page.rst:898 ../../page.rst:923\n#: ../../page.rst:948 ../../page.rst:972 ../../page.rst:996 ../../page.rst:1021\n#: ../../page.rst:1045 ../../page.rst:1070 ../../page.rst:1094\n#: ../../page.rst:1120 ../../page.rst:1144 ../../page.rst:1345\n#: ../../page.rst:1373 ../../page.rst:1397 ../../page.rst:1459\n#: ../../page.rst:1484 ../../page.rst:1506 ../../page.rst:1547\n#: ../../page.rst:1663 ../../page.rst:1684 ../../page.rst:1740\n#: ../../page.rst:1769 ../../page.rst:1793 ../../page.rst:1804\n#: ../../page.rst:1855 ../../page.rst:1886 ../../page.rst:1900\n#: ../../page.rst:1914 ../../page.rst:1932 ../../page.rst:1949\n#: ../../page.rst:2051 ../../page.rst:2090 ../../page.rst:2112\n#: ../../page.rst:2130 ../../page.rst:2176 02badfee54914c3f83727889b1b4ff33\n#: 0595e10a378642e0bbe023669874e726 08449e46bba64aacade9e311407ea072\n#: 0a2994c82ef1450ebb9756b4fb0dfc1f 0c5821d235c84248b3e340f1c793cebf\n#: 0f22055db7d14cac92d34c39f82872fa 1a567f1151e843229f0254cede4cf4b4\n#: 1e1e5b59c2ab4dcab2182160cd9d7fc4 201fa97422c246fdb4cc8f5a01af81a2\n#: 2418a5d90afb42e797c383c4b35b82e3 26d6d9eaf82c4a87a18593f4c71dd611\n#: 2986afb3a4524ab282fd814b66b7b124 29de7beadc114997b1d486f2e93e4701\n#: 2c5f31d1f39c428abbe3963bfe89a076 31a9087f87a342cdbff2a000e761fafe\n#: 33f63e74eb534732beae8ecb511e8510 3d260b67c14c4b21a1e767eb18a7ca54\n#: 46a9d7d5f0b94aa9b18bd4189ed9c34a 47a28c0e7222419b89633a5ae0e77749\n#: 5e5876e07cbb430e874d23691122fae2 622972c036ee44af83db95693614231f\n#: 672303667e104177b5204910e3fdf14f 81d282163d3a4a82bb5cbdcfd15d0dce\n#: 84f3a15e69814963aa1b9db2971e9707 87f85a7f6fd74f43a16acbad543db66e\n#: 93e3dda4c5a243db90b873c791394d69 9e980b217a884705aafd2f0704ca0dd6\n#: a106f2b5aa45444483dc8651848f0889 a2b7f0a98f5149148ad7f0b0ab94d391\n#: af17b808a1324b0bbea2ead2da174b99 b1eedf6b66fe4cad8728aed5fc96761b\n#: baa2a3be67d7485ea3f4fe4fbd5e6d71 bfaa4ce78d0e46309534834d76880310\n#: c096c887b83b4268997e9a453d25b842 c73fd911a20749508df1d8b19b8c57a3\n#: c801277ce33e42a6ba3362f269f6c5ef cba5fb8b9aa44348bf2b7d5390911709\n#: cc1324586d194932a0ca2cf16122eef1 d3b56b46642d4641908a8dceea5e5077\n#: d6737cec766d4e95b377fd109f9d1285 de95b2f374174e2e8d6060866e4a0f78\n#: e124096bc19d4cdcb7b3f234de20c1e1 e2e5c451a119407483e7607b1c5ed9ae\n#: eaffd1e6736a4720841de28506c4dab6 f0c52cf5e35a4bd8a41f7f68312cd088\n#: f2da4f7eb3ee47a9b5c788654cbb1c98 f6fb260e08d34ba8901d564ca14d8199\n#: f95dac36543742408e550976f9dad77a ffd730a0dc0a496e88a4ac68c698cc8e\nmsgid \"|history_end|\"\nmsgstr \"\"\n\n#: ../../page.rst:174 d8ec3873695a46faa388afe6e3743ca3\nmsgid \"\"\n\"PDF only: Add a comment icon (\\\"sticky note\\\") with accompanying text. \"\n\"Only the icon is visible, the accompanying text is hidden and can be \"\n\"visualized by many PDF viewers by hovering the mouse over the symbol.\"\nmsgstr \"\"\n\"PDFのみ: \"\n\"コメントアイコン（「付箋」）を追加し、それに関連するテキストを含めます。アイコンのみが表示され、関連するテキストは非表示で、多くのPDFビューアではアイコンの上にマウスを重ねることで可視化できます。\"\n\n#: ../../page.rst:176 444f1e5c16ea4352a788a5efd10e1569\nmsgid \"\"\n\"the top left point of a 20 x 20 rectangle containing the MuPDF-provided \"\n\"\\\"note\\\" icon.\"\nmsgstr \"提供されたMuPDFアイコンが含まれる20 x 20の矩形の左上の点。\"\n\n#: ../../page.rst:178 ba51896b030f4534ac7582b69b2e717d\nmsgid \"\"\n\"the commentary text. This will be shown on double clicking or hovering \"\n\"over the icon. May contain any Latin characters.\"\nmsgstr \"コメントテキスト。これはダブルクリックまたはアイコンの上にカーソルを合わせることで表示されます。ラテン文字を含むことができます。\"\n\n#: ../../page.rst:179 fcd4a7236e1246889d7569f393c0061e\nmsgid \"\"\n\"choose one of \\\"Note\\\" (default), \\\"Comment\\\", \\\"Help\\\", \\\"Insert\\\", \"\n\"\\\"Key\\\", \\\"NewParagraph\\\", \\\"Paragraph\\\" as the visual symbol for the \"\n\"embodied text [#f4]_. (New in v1.16.0)\"\nmsgstr \"\"\n\"*（v1.16.0で新規追加）*  \"\n\"\\\"Note\\\"（デフォルト）、\\\"Comment\\\"、\\\"Help\\\"、\\\"Insert\\\"、\\\"Key\\\"、\\\"NewParagraph\\\"、\\\"Paragraph\\\"\"\n\" のいずれかを、具体的なテキストの視覚的なシンボルとして選択してください。 [#f4]_\"\n\n#: ../../page.rst:182 00b05d93137644ecae6d4d1ab0d1942c\nmsgid \"\"\n\"the created annotation. Stroke color yellow = (1, 1, 0), no fill color \"\n\"support.\"\nmsgstr \"作成された注釈。ストロークカラーは黄色（1, 1, 0）、塗りつぶしカラーのサポートはありません。\"\n\n#: ../../page.rst:202 da81bd77253c4a21b14cc4130621cc52\nmsgid \"\"\n\"PDF only: Add text in a given rectangle. Optionally, the appearance of a \"\n\"\\\"callout\\\" shape can be requested by specifying two or three point-like \"\n\"objects -- see below.\"\nmsgstr \"\"\n\n#: ../../page.rst:204 5f99d477c3e745cf8ec1e4a0ff35d8c5\n#, fuzzy\nmsgid \"\"\n\"the rectangle into which the text should be inserted. Text is \"\n\"automatically wrapped to a new line at box width. Text portions not \"\n\"fitting into the rectangle will be invisible without warning.\"\nmsgstr \"テキストを挿入する矩形。テキストはボックスの幅で自動的に改行されます。ボックスに収まらない行は見えません。\"\n\n#: ../../page.rst:206 e5b43ec9291c4d949b0f2cd507783ddd\nmsgid \"\"\n\"the text. May contain any mixture of Latin, Greek, Cyrillic, Chinese, \"\n\"Japanese and Korean characters. If `richtext=True` (see below), the \"\n\"string is interpreted as HTML syntax. This adds a plethora of ways for \"\n\"attractive effects.\"\nmsgstr \"\"\n\n#: ../../page.rst:208 1b209d97cea54825a17f2e38b4c1f41f\n#, fuzzy\nmsgid \"the :data:`fontsize`. Default is 11. Ignored if `richtext=True`.\"\nmsgstr \":data:`fontsize`。デフォルトは12です。\"\n\n#: ../../page.rst:210 c6363a1c3e3844dda24dce395cde51d4\nmsgid \"\"\n\"The font name. Default is \\\"Helv\\\". Ignored if `richtext=True`, otherwise\"\n\" the following **restritions apply:**  * Accepted alternatives are \"\n\"\\\"Helv\\\" (Helvetica), \\\"Cour\\\" (Courier), \\\"TiRo\\\" (Timnes-Roman), \"\n\"\\\"ZaDb\\\" (ZapfDingBats) and \\\"Symb\\\" (Symbol). The name may be \"\n\"abbreviated to the first two characters, like \\\"Co\\\" for \\\"Cour\\\", lower \"\n\"case accepted.  * Bold or italic variants of the fonts are **not \"\n\"supported.**\"\nmsgstr \"\"\n\n#: ../../page.rst:210 8bccdef5bfa349ac8cc4a0b0df77d779\nmsgid \"\"\n\"The font name. Default is \\\"Helv\\\". Ignored if `richtext=True`, otherwise\"\n\" the following **restritions apply:**\"\nmsgstr \"\"\n\n#: ../../page.rst:212 36e99423c0944ce5b4cb2ed37304d148\nmsgid \"\"\n\"Accepted alternatives are \\\"Helv\\\" (Helvetica), \\\"Cour\\\" (Courier), \"\n\"\\\"TiRo\\\" (Timnes-Roman), \\\"ZaDb\\\" (ZapfDingBats) and \\\"Symb\\\" (Symbol). \"\n\"The name may be abbreviated to the first two characters, like \\\"Co\\\" for \"\n\"\\\"Cour\\\", lower case accepted.\"\nmsgstr \"\"\n\n#: ../../page.rst:214 ef7c988255f8408693dcd893daee5569\nmsgid \"Bold or italic variants of the fonts are **not supported.**\"\nmsgstr \"\"\n\n#: ../../page.rst:216 272d5192e6a54a489f66fa6362549341\n#, fuzzy\nmsgid \"the text color. Default is black. Ignored if `richtext=True`.\"\nmsgstr \"テキストの色。デフォルトは黒です。(v1.16.0で新規追加)\"\n\n#: ../../page.rst:218 af477130273e4b5fa28d9e37245755e8\nmsgid \"\"\n\"the fill color. This is used for ``rect`` and the end point of the \"\n\"callout lines when applicable. Default is ``None``.\"\nmsgstr \"\"\n\n#: ../../page.rst:220 4d76d5a8790d4b839bd983dd6ec9d77c\nmsgid \"\"\n\"This parameter **only has an effect** if `richtext=True`. Otherwise, \"\n\"``text_color`` is used.\"\nmsgstr \"\"\n\n#: ../../page.rst:222 e0f1c549358349d0a0f8708295f71f6f\nmsgid \"\"\n\"the width of border and ``callout`` lines. Default is 0 (no border), in \"\n\"which case callout lines may still appear with some hairline width, \"\n\"depending on the PDF viewer used. In any case, this value must be \"\n\"positive to see a border line.\"\nmsgstr \"\"\n\n#: ../../page.rst:224 b03d77e2b6b64e91aa9ddd2c3b69b614\nmsgid \"\"\n\"a list of floats specifying how border and callout lines should be \"\n\"dashed. Default is ``None``.\"\nmsgstr \"\"\n\n#: ../../page.rst:226 9289999654b34275b118b35ca71befbd\nmsgid \"\"\n\"a list / tuple of two or three :data:`point_like` objects, which will be \"\n\"interpreted as end point [, knee point] and start point (in this \"\n\"sequence) of up to two line segments, converting this annotation into a \"\n\"call-out shape.\"\nmsgstr \"\"\n\n#: ../../page.rst:228 22ed97f9b1574b94babadcefb21d3b01\nmsgid \"\"\n\"the line end symbol of the call-out line. It is drawn at the first point \"\n\"specified in the `callout` list. Default is an open arrow. For possible \"\n\"values see :ref:`AnnotationLineEnds`.\"\nmsgstr \"\"\n\n#: ../../page.rst:230 c35ad9a2509141878cedbb95c593fe7b\nmsgid \"\"\n\"a float `0 <= opacity < 1` turning the annotation transparent. Default is\"\n\" no transparency.\"\nmsgstr \"\"\n\n#: ../../page.rst:232 37a763be7bad491cb45931b9429c4c68\nmsgid \"\"\n\"text alignment, one of TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, \"\n\"TEXT_ALIGN_RIGHT - justify is **not supported**. Ignored if \"\n\"`richtext=True`.\"\nmsgstr \"\"\n\n#: ../../page.rst:234 a37c990e9bf349eaba83f81515bc08c1\n#, fuzzy\nmsgid \"\"\n\"the text orientation. Accepted values are integer multiples of 90°. \"\n\"Invalid entries receive a rotation of 0.\"\nmsgstr \"テキストの向き。受け入れられる値は0、90、270で、無効なエントリはゼロに設定されます。\"\n\n#: ../../page.rst:236 6d3d35985f8548eab9441accfbadfd21\nmsgid \"\"\n\"treat ``text`` as HTML syntax. This allows to achieve **bold**, *italic*,\"\n\" arbitrary text colors, font sizes, text alignment including justify and \"\n\"more - as far as the PDF subset of HTML and styling instructions supports\"\n\" this. This is similar to what happens in :meth:`Page.insert_htmlbox`. \"\n\"The base library will for example pull in required fonts if it encounters\"\n\" characters not contained in the standard ones. Some parameters are \"\n\"ignored if this option is set, as mentioned above. Default is ``False``.\"\nmsgstr \"\"\n\n#: ../../page.rst:238 24105781e9b74f28961a17ef0741d795\nmsgid \"\"\n\"supply optional HTML styling information in CSS syntax. Ignored if \"\n\"`richtext=False`.\"\nmsgstr \"\"\n\n#: ../../page.rst:241 e19d564ac39043ba9412a1833b016354\n#, fuzzy\nmsgid \"the created annotation.\"\nmsgstr \"ウィジェットアノテーション。\"\n\n#: ../../page.rst:245 cb932ff975034cf5a46ebce5a3d5fef3\nmsgid \"Changed in v1.19.6: add border color parameter\"\nmsgstr \"v1.19.6で変更：境界色パラメータを追加\"\n\n#: ../../page.rst:251 d9ffc94d2383440f958329808b2ed6c3\nmsgid \"\"\n\"PDF only: Add a file attachment annotation with a \\\"PushPin\\\" icon at the\"\n\" specified location.\"\nmsgstr \"PDFのみ: 指定された場所に「PushPin」アイコンを持つファイル添付注釈を追加します。\"\n\n#: ../../page.rst:253 7850850451ec4c9097b96541fdc27394\nmsgid \"\"\n\"the top-left point of a 18x18 rectangle containing the MuPDF-provided \"\n\"\\\"PushPin\\\" icon.\"\nmsgstr \"ムPDFで提供される「PushPin」アイコンを含む18x18の四角形の左上のポイント。\"\n\n#: ../../page.rst:255 acfe93b4198344eda02d7a03b353ca77\n#, fuzzy\nmsgid \"\"\n\"the data to be stored (actual file content, any data, etc.).  Changed in \"\n\"v1.14.13: *io.BytesIO* is now also supported.\"\nmsgstr \"格納するデータ（実際のファイルコンテンツ、任意のデータなど）。\"\n\n#: ../../page.rst:255 2057d907ffcd43ec996b431d8e1bdd4f\nmsgid \"the data to be stored (actual file content, any data, etc.).\"\nmsgstr \"格納するデータ（実際のファイルコンテンツ、任意のデータなど）。\"\n\n#: ../../page.rst:257 77c6e5d0221f4f609584f3422eb787ea\nmsgid \"Changed in v1.14.13: *io.BytesIO* is now also supported.\"\nmsgstr \"v1.14.13で変更: *io.BytesIO* もサポートされるようになりました。\"\n\n#: ../../page.rst:259 39073228b9ad4c41a7d61973ff451f7f\nmsgid \"the filename to associate with the data.\"\nmsgstr \"データに関連付けるファイル名。\"\n\n#: ../../page.rst:260 41da9cdaf23648b68c9a78554a1290b4\nmsgid \"the optional PDF unicode version of filename. Defaults to filename.\"\nmsgstr \"ファイルのPDF Unicodeバージョンのオプション。デフォルトはファイル名です。\"\n\n#: ../../page.rst:261 12cc7d8353a347bbb77ac0a487196e29\nmsgid \"an optional description of the file. Defaults to filename.\"\nmsgstr \"ファイルのオプションの説明。デフォルトはファイル名です。\"\n\n#: ../../page.rst:262 8c253c5f387245ef8decce89d2c40230\nmsgid \"\"\n\"choose one of \\\"PushPin\\\" (default), \\\"Graph\\\", \\\"Paperclip\\\", \\\"Tag\\\" as\"\n\" the visual symbol for the attached data [#f4]_. (New in v1.16.0)\"\nmsgstr \"\"\n\"v1.16.0で新しく追加された）添付データの視覚的なシンボルとして、次のいずれかを選択します。\\\"PushPin\\\"（デフォルト）、\\\"Graph\\\"、\\\"Paperclip\\\"、\\\"Tag\\\"\"\n\" [#f4]_。\"\n\n#: ../../page.rst:265 5d93a52505284c3eab585fcea69a39c4\nmsgid \"\"\n\"the created annotation.  Stroke color yellow = (1, 1, 0), no fill color \"\n\"support.\"\nmsgstr \"作成された注釈。線の色は黄色（1, 1, 0）、塗りつぶしのサポートはありません。\"\n\n#: ../../page.rst:269 b5bdde79e584483899f7f79e214ff8bd\nmsgid \"PDF only: Add a \\\"freehand\\\" scribble annotation.\"\nmsgstr \"PDFのみ: \\\"freehand\\\"の落書き注釈を追加します。\"\n\n#: ../../page.rst:271 0e40df92c5674ec487c4a9919ab386b7\nmsgid \"\"\n\"a list of one or more lists, each containing :data:`point_like` items. \"\n\"Each item in these sublists is interpreted as a :ref:`Point` through \"\n\"which a connecting line is drawn. Separate sublists thus represent \"\n\"separate drawing lines.\"\nmsgstr \"\"\n\"1つまたは複数のリストからなり、それぞれが :data:`point_like` \"\n\"アイテムを含むリストの1つです。これらのサブリスト内の各アイテムは、接続された線が描画される :ref:`Point` \"\n\"として解釈されます。したがって、個々のサブリストは別々の描画ラインを表します。\"\n\n#: ../../page.rst:274 8e3f7652ecd14f8c8c052fed6fcf46f3\nmsgid \"\"\n\"the created annotation in default appearance black =(0, 0, 0),line width \"\n\"1. No fill color support.\"\nmsgstr \"作成された注釈はデフォルトの外観で黒色（0, 0, 0）で、線の幅は1です。塗りつぶしのサポートはありません。\"\n\n#: ../../page.rst:278 b86f901fd3ad4d71a03591ec9cd6df54\nmsgid \"PDF only: Add a line annotation.\"\nmsgstr \"PDFのみ: 直線注釈を追加します。\"\n\n#: ../../page.rst:280 68b283c40be64dab874b8a80425794b5\nmsgid \"the starting point of the line.\"\nmsgstr \"直線の開始点。\"\n\n#: ../../page.rst:282 0d2d2c2792b045a0815b8c65212644da\nmsgid \"the end point of the line.\"\nmsgstr \"直線の終点。\"\n\n#: ../../page.rst:285 ba6653fa181c4c5c908a5f2ceac4386d\nmsgid \"\"\n\"the created annotation. It is drawn with line (stroke) color red = (1, 0,\"\n\" 0) and line width 1. No fill color support. The **annot rectangle** is \"\n\"automatically created to contain both points, each one surrounded by a \"\n\"circle of radius 3 * line width to make room for any line end symbols.\"\nmsgstr \"\"\n\"作成された注釈。線（ストローク）の色は赤色（1, 0, 0）で、線の幅は1です。塗りつぶしのサポートはありません。**アノテーションの四角形** \"\n\"は、各点を囲む半径 3 * 線幅の円で作成され、各点の周りにシンボルの線の終わりのためのスペースを確保します。\"\n\n#: ../../page.rst:291 9dbfa38e942545b2a0abc3c2d0b1945a\nmsgid \"PDF only: Add a rectangle, resp. circle annotation.\"\nmsgstr \"PDFのみ: 長方形、または円の注釈を追加します。\"\n\n#: ../../page.rst:293 c0d788aeb5e84abea2f2313cc9512956\nmsgid \"\"\n\"the rectangle in which the circle or rectangle is drawn, must be finite \"\n\"and not empty. If the rectangle is not equal-sided, an ellipse is drawn.\"\nmsgstr \"円または長方形が描かれる矩形。有限で空でない必要があります。矩形が正方形でない場合、楕円が描画されます。\"\n\n#: ../../page.rst:296 dee1374ec0114b3cab8a319b08afaa42\nmsgid \"\"\n\"the created annotation. It is drawn with line (stroke) color red = (1, 0,\"\n\" 0), line width 1, fill color is supported.\"\nmsgstr \"作成された注釈。線（ストローク）の色は赤色（1、0、0）、線の幅は1で、塗りつぶしのサポートがあります\"\n\n#: ../../page.rst:301 64d43e8d6be3414694bba69efaee620a\nmsgid \"Redactions\"\nmsgstr \"\"\n\n#: ../../page.rst:305 a84361a8bc454638a5382f3b141486ef\n#, fuzzy\nmsgid \"\"\n\"**PDF only**: Add a redaction annotation. A redaction annotation \"\n\"identifies an area whose content should be removed from the document. \"\n\"Adding such an annotation is the first of two steps. It makes visible \"\n\"what will be removed in the subsequent step, \"\n\":meth:`Page.apply_redactions`.\"\nmsgstr \"\"\n\"**PDFのみ** \"\n\"：赤塗り注釈を追加します。赤塗り注釈は、文書から削除されるコンテンツを識別します。このような注釈を追加することは、2つの手順の最初です。次の手順、:meth:`Page.apply_redactions`\"\n\" で削除される内容を可視化します。\"\n\n#: ../../page.rst:307 5dac4a2ac6394fc99f25e30413c301da\nmsgid \"\"\n\"specifies the (rectangular) area to be removed which is always equal to \"\n\"the annotation rectangle. This may be a :data:`rect_like` or \"\n\":data:`quad_like` object. If a quad is specified, then the enveloping \"\n\"rectangle is taken.\"\nmsgstr \"常に注釈の矩形と等しい削除する領域を指定します。これはrect_likeまたはquad_likeオブジェクトである必要があります。四角形が指定された場合、包括的な矩形が取られます。\"\n\n#: ../../page.rst:309 4d76e403896a4b05b4f4abebe01e0204\nmsgid \"\"\n\"text to be placed in the rectangle after applying the redaction (and thus\"\n\" removing old content). (New in v1.16.12)\"\nmsgstr \"*(v1.16.12で新機能)* 赤字を適用した後に矩形に配置するテキスト（従って古いコンテンツを削除します）。\"\n\n#: ../../page.rst:311 1f18c3b53454466c85cd51ab44ed410d\nmsgid \"\"\n\"the font to use when ``text`` is given, otherwise ignored. Only CJK and \"\n\"the :ref:`Base-14-Fonts` are supported. Apart from this, the same rules \"\n\"apply as for :meth:`Page.insert_textbox` -- which is what the method \"\n\":meth:`Page.apply_redactions` internally invokes.\"\nmsgstr \"\"\n\n#: ../../page.rst:313 15e6fd75902e4d668d2c53ce39c6612b\nmsgid \"\"\n\"the :data:`fontsize` to use for the replacing text. If the text is too \"\n\"large to fit, several insertion attempts will be made, gradually reducing\"\n\" the :data:`fontsize` to no less than 4. If then the text will still not \"\n\"fit, no text insertion will take place at all. (New in v1.16.12)\"\nmsgstr \"\"\n\"置換テキストに使用する :data:`fontsize` 。テキストが大きすぎて収まらない場合、:data:`fontsize` \"\n\"を4未満にならないように徐々に縮小して、複数の挿入試行が行われます。その後もテキストが収まらない場合、テキストの挿入は行われません。 \"\n\"(v1.16.12 で新規追加)\"\n\n#: ../../page.rst:315 c037bef2ae914aac887186cb50012cc1\n#, fuzzy\nmsgid \"\"\n\"the horizontal alignment for the replacing text. See \"\n\":meth:`insert_textbox` for available values. The vertical alignment is \"\n\"(approximately) centered.\"\nmsgstr \"\"\n\"置換テキストの水平配置です。使用可能な値については、:meth:`insert_textbox` \"\n\"を参照してください。PDFの組み込みフォント（CJKまたは :ref:`Base-14-Fonts` \"\n\"）を使用する場合、垂直配置は（おおよそ）中央になります。 (v1.16.12で新規)\"\n\n#: ../../page.rst:317 8f310d455d444b068857a16bcdfc4f51\nmsgid \"\"\n\"the fill color of the rectangle **after applying** the redaction. The \"\n\"default is *white = (1, 1, 1)*, which is also taken if ``None`` is \"\n\"specified. To suppress a fill color altogether, specify ``False``. In \"\n\"this cases the rectangle remains transparent. (New in v1.16.12)\"\nmsgstr \"\"\n\"**適用後** の赤塗りの四角形の塗りつぶし色です。デフォルトは *white = (1, 1, 1)* で、``None`` \"\n\"が指定された場合も同様です。塗りつぶし色を抑制するには、``False`` \"\n\"を指定します。この場合、四角形は透明のままです。（v1.16.12で新規追加）\"\n\n#: ../../page.rst:319 f812c2b775b04ee1b3c04c57cbebaed0\nmsgid \"\"\n\"the color of the replacing text. Default is *black = (0, 0, 0)*. (New in \"\n\"v1.16.12)\"\nmsgstr \"*(新機能 v1.16.12)* 置換テキストの色です。デフォルトは *black = (0, 0, 0)* です。\"\n\n#: ../../page.rst:321 a2ae0126926c491abf40d2a1c2b0a3f8\nmsgid \"add two diagonal lines to the annotation rectangle. (New in v1.17.2)\"\nmsgstr \"*(新機能 v1.17.2)* アノテーションの矩形に2つの対角線を追加します。\"\n\n#: ../../page.rst:324 6d7e478605e94dbc8eb4b0b84e535142\nmsgid \"\"\n\"the created annotation. Its standard appearance looks like a red \"\n\"rectangle (no fill color), optionally showing two diagonal lines. Colors,\"\n\" line width, dashing, opacity and blend mode can now be set and applied \"\n\"via :meth:`Annot.update` like with other annotations. (Changed in \"\n\"v1.17.2)\"\nmsgstr \"\"\n\"作成された注釈です。その標準的な外観は、赤い四角形（塗りつぶし色なし）であり、必要に応じて二つの対角線を表示します。色、線の太さ、破線、不透明度、およびブレンドモードは、他の注釈と同様に、:meth:`Annot.update`\"\n\" を介して設定および適用できます。（v1.17.2で変更）\"\n\n#: ../../page.rst:330 ../../page.rst:370 185241df5ccf4107bb94ed75536d2869\n#: 3f492500f5c74544b8191d63b72a7f35\nmsgid \"New in v1.16.11\"\nmsgstr \"新機能 v1.16.11\"\n\n#: ../../page.rst:337 865d86b155654e3d97b02053e505d379\n#, fuzzy\nmsgid \"\"\n\"**PDF only**: Remove all **content** contained in any redaction rectangle\"\n\" on the page.\"\nmsgstr \"PDFのみ：赤塗りの矩形に含まれるすべての **テキストコンテンツ** を削除します。\"\n\n#: ../../page.rst:339 e78a9bf11c1c4ad2bbb5c21f5af5e49a\nmsgid \"**This method applies and then deletes all redactions from the page.**\"\nmsgstr \"**このメソッドは、ページからすべての赤塗りを適用して削除します。**\"\n\n#: ../../page.rst:341 09073582e1e649d382d2a335dd82d782\nmsgid \"\"\n\"How to redact overlapping images. The default (2) blanks out overlapping \"\n\"pixels. `PDF_REDACT_IMAGE_NONE | 0` ignores, and `PDF_REDACT_IMAGE_REMOVE\"\n\" | 1` completely removes images overlapping any redaction annotation. \"\n\"Option `PDF_REDACT_IMAGE_REMOVE_UNLESS_INVISIBLE | 3` only removes images\"\n\" that are actually visible.\"\nmsgstr \"\"\n\"重なる画像をレダクトする方法。デフォルトの（2）は、重なるピクセルを空白にします。 `PDF_REDACT_IMAGE_NONE | 0`  \"\n\"は無視し、 `PDF_REDACT_IMAGE_REMOVE | 1`  は、いずれかのレダクション注釈と重なる画像を完全に削除します。オプション\"\n\"  `PDF_REDACT_IMAGE_REMOVE_UNLESS_INVISIBLE | 3`  は、実際に見える画像のみを削除します。\"\n\n#: ../../page.rst:343 f11b640439064a57804428691b95557c\n#, fuzzy, python-format\nmsgid \"\"\n\"How to redact overlapping vector graphics (also called \\\"line-art\\\" or \"\n\"\\\"drawings\\\"). The default (2) removes any overlapping vector graphics. \"\n\"`PDF_REDACT_LINE_ART_NONE | 0` ignores, and \"\n\"`PDF_REDACT_LINE_ART_REMOVE_IF_COVERED | 1` removes graphics fully \"\n\"contained in a redaction annotation. When removing line-art, please be \"\n\"aware that **stroked** vector graphics (i.e. type \\\"s\\\" or \\\"sf\\\") have a\"\n\" **larger wrapping rectangle** than one might expect: first of all, at \"\n\"least 50% of the path's line width have to be added in each direction to \"\n\"truly include all of the drawing. If a so-called \\\"miter limit\\\" is \"\n\"provided (see page 121 of the PDF specification), the enlarging value is \"\n\"`miter * width / 2`. So, when letting everything default (width = 1, \"\n\"miter = 10), the redaction rectangle should be at least 5 points larger \"\n\"in every direction.\"\nmsgstr \"\"\n\"重なるベクトルグラフィックス（または「ラインアート」や「図面」とも呼ばれる）を塗りつぶす方法。デフォルト値（2）では、重なるベクトルグラフィックスがすべて削除されます。`PDF_REDACT_LINE_ART_NONE\"\n\" | 0` は無視し、`PDF_REDACT_LINE_ART_IF_COVERED | 1` \"\n\"は、赤塗り注釈に完全に含まれるグラフィックスを削除します。ラインアートを削除する際は、 **ストロークされた** \"\n\"ベクトルグラフィックス（つまりタイプ「s」または「sf」）が、期待される **よりも大きなラッピング長方形** \"\n\"を持つことに注意してください：まず第一に、パスの線幅の少なくとも50％を、各方向に追加する必要があります。描画のすべてを含めるため。所謂「マイターリミット」が提供されている場合（PDF仕様書の121ページを参照）、拡大値は\"\n\" `miter * width / \"\n\"2`.です。すべてをデフォルト値（幅＝1、マイター＝10）にする場合、赤塗りの長方形は各方向に少なくとも5ポイント大きくする必要があります。\"\n\n#: ../../page.rst:345 b62537b48f434247b1f5f7043574b596\nmsgid \"\"\n\"Whether to redact overlapping text. The default `PDF_REDACT_TEXT_REMOVE |\"\n\" 0` removes all characters whose boundary box overlaps any redaction \"\n\"rectangle. This complies with the original legal / data protection \"\n\"intentions of redaction annotations. Other use cases however may require \"\n\"to **keep text** while redacting vector graphics or images. This can be \"\n\"achieved by setting `text=True|PDF_REDACT_TEXT_NONE | 1`. This does **not\"\n\" comply** with the data protection intentions of redaction annotations. \"\n\"**Do so at your own risk.**\"\nmsgstr \"\"\n\"重なるテキストを塗りつぶすかどうかを指定します。デフォルトでは、`PDF_REDACT_TEXT_REMOVE | 0` \"\n\"は、境界ボックスが赤塗り四角形と重なるすべての文字を削除します。これは、元の法的/データ保護の意図に適合しています。ただし、他のユースケースでは、ベクトルグラフィックスや画像を赤塗りする一方で**テキストを保持**する必要がある場合があります。これは、`text=True|PDF_REDACT_TEXT_NONE\"\n\" | 1` を設定することで実現できます。これは、赤塗り注釈のデータ保護の意図には適合していませんので、自己責任で行ってください。\"\n\n#: ../../page.rst:347 1aba7daeb2cd4a4ca3d5d9e6f3c074fa\nmsgid \"\"\n\"`True` if at least one redaction annotation has been processed, `False` \"\n\"otherwise.\"\nmsgstr \"少なくとも1つの赤字注釈が処理された場合は ``True``、それ以外の場合は ``False``。\"\n\n#: ../../page.rst:350 1b977b6ed04246c3ae5faf3f785569f1\nmsgid \"\"\n\"Text contained in a redaction rectangle will be **physically** removed \"\n\"from the page (assuming :meth:`Document.save` with a suitable garbage \"\n\"option) and will no longer appear in e.g. text extractions or anywhere \"\n\"else. All redaction annotations will also be removed. Other annotations \"\n\"are unaffected.\"\nmsgstr \"\"\n\"赤塗りの四角に含まれるテキストは、**物理的に** \"\n\"ページから削除されます（適切なゴミオプションを使用したDocument.save()の場合）、テキスト抽出などの場所にはもはや表示されません。また、すべての赤塗りの注釈も削除されます。他の注釈には影響しません。\"\n\n#: ../../page.rst:352 487f11ac3e46441faf9dd99f32447379\nmsgid \"\"\n\"All overlapping links will be removed. If the rectangle of the link was \"\n\"covering text, then only the overlapping part of the text is being \"\n\"removed. Similar applies to images covered by link rectangles.\"\nmsgstr \"重なっているすべてのリンクは削除されます。リンクの四角がテキストを覆っている場合、テキストの重なる部分のみが削除されます。画像もリンクの四角によってカバーされている場合、同様のことが適用されます。\"\n\n#: ../../page.rst:354 8e50b4b5fe0b444aa2b5fda22df95a93\nmsgid \"\"\n\"The overlapping parts of **images** will be blanked-out for default \"\n\"option `PDF_REDACT_IMAGE_PIXELS` (changed in v1.18.0). Option 0 does not \"\n\"touch any images and 1 will remove any image with an overlap.\"\nmsgstr \"\"\n\"**画像** の重なり部分は、デフォルトのオプションである `PDF_REDACT_IMAGE_PIXELS`  \"\n\"では塗りつぶされます（v1.18.0で変更されました）。オプション0は画像を一切変更せず、1は重なり合う画像をすべて削除します。\"\n\n#: ../../page.rst:356 6a9f7ffec9fa4701a8c230e0944d5de8\nmsgid \"\"\n\"For option `images=PDF_REDACT_IMAGE_REMOVE` only this page's **references\"\n\" to the images** are removed - not necessarily the images themselves. \"\n\"Images are completely removed from the file only, if no longer referenced\"\n\" at all (assuming suitable garbage collection options).\"\nmsgstr \"\"\n\"`images=PDF_REDACT_IMAGE_REMOVE` のオプションの場合、このページの **画像への参照** \"\n\"のみが削除されます。適切なゴミ収集オプションがあると、画像はファイルから完全に削除されます。\"\n\n#: ../../page.rst:358 e4034acfd25f4158a32e53879651c689\nmsgid \"\"\n\"For option `images=PDF_REDACT_IMAGE_PIXELS` a new image of format PNG is \"\n\"created, which the page will use in place of the original one. The \"\n\"original image is not deleted or replaced as part of this process, so \"\n\"other pages may still show the original. In addition, the new, modified \"\n\"PNG image currently is **stored uncompressed**. Do keep these aspects in \"\n\"mind when choosing the right garbage collection method and compression \"\n\"options during save.\"\nmsgstr \"\"\n\"`images=PDF_REDACT_IMAGE_PIXELS` \"\n\"のオプションでは、新しいPNG形式の画像が作成され、ページは元の画像の代わりにそれを使用します。このプロセスの一環として、元の画像は削除されず、他のページでは引き続き元の画像が表示される可能性があります。さらに、新しい変更されたPNG画像は現在\"\n\" **圧縮されていない状態で保存されています** 。保存時に適切なゴミ収集メソッドと圧縮オプションを選択する際に、これらの側面を考慮してください。\"\n\n#: ../../page.rst:360 dc47a452593a4cb3a3e131031f5730d7\nmsgid \"\"\n\"**Text removal** is done by character: A character is removed if its bbox\"\n\" has a **non-empty overlap** with a redaction rectangle (changed in MuPDF\"\n\" v1.17). Depending on the font properties and / or the chosen line \"\n\"height, deletion may occur for undesired text parts. Using \"\n\":meth:`Tools.set_small_glyph_heights` with a ``True`` argument before \"\n\"text search may help to prevent this.\"\nmsgstr \"\"\n\"**テキストの削除** は文字ごとに行われます：文字のbboxが赤塗りの四角と非空の重なりを持つ場合、文字が削除されます（MuPDF \"\n\"v1.17で変更）。フォントの特性や選択した行の高さに応じて、望ましくないテキスト部分が削除される場合があります。テキスト検索前に \"\n\":meth:`Tools.set_small_glyph_heights` を ``True`` \"\n\"引数で使用して、これを防ぐのに役立つ場合があります。\"\n\n#: ../../page.rst:362 ee9e385dfb9447b8a537d61b2365d03f\nmsgid \"\"\n\"Redactions are a simple way to replace single words in a PDF, or to just \"\n\"physically remove them. Locate the word \\\"secret\\\" using some text \"\n\"extraction or search method and insert a redaction using \\\"xxxxxx\\\" as \"\n\"replacement text for each occurrence.\"\nmsgstr \"赤塗りは、PDF内の単語を置き換えるための簡単な方法であり、単語を物理的に削除するためのものです。テキスト抽出または検索方法を使用して単語「秘密」を見つけ、それぞれの出現ごとに代替テキスト「xxxxxx」を使用して赤塗りを挿入します。\"\n\n#: ../../page.rst:364 aeeaa43dc6f547be81c82b217ea0b35f\nmsgid \"\"\n\"Be wary if the replacement is longer than the original -- this may lead \"\n\"to an awkward appearance, line breaks or no new text at all.\"\nmsgstr \"注意が必要です。代替テキストが元のテキストよりも長い場合、見栄えが悪くなったり、改行が発生したり、新しいテキストがまったく表示されなくなる可能性があるためです。\"\n\n#: ../../page.rst:366 ea636c09a9924bb8b5646e6dfac446f9\nmsgid \"\"\n\"For a number of reasons, the new text may not exactly be positioned on \"\n\"the same line like the old one -- especially true if the replacement font\"\n\" was not one of CJK or :ref:`Base-14-Fonts`.\"\nmsgstr \"\"\n\"いくつかの理由から、新しいテキストは古いテキストとまったく同じ行に配置されないことがあります。特に、代替フォントがCJKまたはPDF \"\n\":ref:`Base-14-Fonts` の場合には特に当てはまります。\"\n\n#: ../../page.rst:371 3a1768a048d347a4807733013681a35b\nmsgid \"\"\n\"Changed in v1.16.12: The previous *mark* parameter is gone. Instead, the \"\n\"respective rectangles are filled with the individual *fill* color of each\"\n\" redaction annotation. If a *text* was given in the annotation, then \"\n\":meth:`insert_textbox` is invoked to insert it, using parameters provided\"\n\" with the redaction.\"\nmsgstr \"\"\n\"v1.16.12で変更：以前の *mark* \"\n\"パラメータは削除されました。代わりに、各赤字注釈の個々の塗りつぶし色で各赤字領域が塗りつぶされます。アノテーションで *text* \"\n\"が指定された場合、そのテキストを挿入するために、redactionで提供されたパラメータを使用して :meth:`insert_textbox` \"\n\"が呼び出されます。\"\n\n#: ../../page.rst:372 bb9c6db9f287498290c02c005b04b563\nmsgid \"\"\n\"Changed in v1.18.0: added option for handling images that overlap \"\n\"redaction areas.\"\nmsgstr \"v1.18.0で変更：赤字領域と重なる画像を処理するためのオプションが追加されました。\"\n\n#: ../../page.rst:373 3106c488a58e4ee7aebb2137a0641e62\nmsgid \"Changed in v1.23.27: added option for removing graphics as well.\"\nmsgstr \"\"\n\n#: ../../page.rst:374 14c5c16ae5274f2c93cae93f149bbaac\nmsgid \"Changed in v1.24.2: added option `keep_text` to leave text untouched.\"\nmsgstr \"\"\n\n#: ../../page.rst:384 16a23881460e4301bee92bf2d492116a\nmsgid \"\"\n\"PDF only: Add an annotation consisting of lines which connect the given \"\n\"points. A **Polygon's** first and last points are automatically \"\n\"connected, which does not happen for a **PolyLine**. The **rectangle** is\"\n\" automatically created as the smallest rectangle containing the points, \"\n\"each one surrounded by a circle of radius 3 (= 3 * line width). The \"\n\"following shows a 'PolyLine' that has been modified with colors and line \"\n\"ends.\"\nmsgstr \"\"\n\"PDFのみ：指定されたポイントを接続する線から成る注釈を追加します。多角形 **（Polygon）** \"\n\"の最初と最後のポイントは自動的に接続されますが、**PolyLine** ではそれが発生しません。各ポイントは半径3の円で囲まれた最小の \"\n\"**四角形** として自動的に作成されます（半径3 = 3 * 線の幅）。以下は、色や線端を変更した「PolyLine」の例を示しています。\"\n\n#: ../../page.rst:386 48e0dcb2eacd42a58db10f609be72065\nmsgid \"a list of :data:`point_like` objects.\"\nmsgstr \"points（list）– :data:`point_like` オブジェクトのリスト。\"\n\n#: ../../page.rst:389 ffc26708d41548e79d6d16bef4dec96c\nmsgid \"\"\n\"the created annotation. It is drawn with line color black, line width 1 \"\n\"no fill color but fill color support. Use methods of :ref:`Annot` to make\"\n\" any changes to achieve something like this:\"\nmsgstr \"\"\n\"作成されたアノテーションです。線の色は黒で描画され、線の幅は1で、塗りつぶし色はサポートされています。このような外見を実現するために、:ref:`Annot`\"\n\" のメソッドを使用して変更を加えることができます。\"\n\n#: ../../page.rst:402 77481744eb7b4202a73407869d31200a\nmsgid \"\"\n\"PDF only: These annotations are normally used for **marking text** which \"\n\"has previously been somehow located (for example via \"\n\":meth:`Page.search_for`). But this is not required: you are free to \"\n\"\\\"mark\\\" just anything.\"\nmsgstr \"\"\n\"PDFのみ: これらのアノテーションは通常、以前に何らかの方法で見つかったテキスト（たとえば、:meth:`Page.search_for` \"\n\"を使用して）をマーキングするために使用されます。ただし、これは必須ではありません：何でも「マーク」することができます。\"\n\n#: ../../page.rst:404 8b9c2a1ec12243d584aa92eb85b61fe6\nmsgid \"\"\n\"Standard (stroke only -- no fill color support) colors are chosen per \"\n\"annotation type: **yellow** for highlighting, **red** for striking out, \"\n\"**green** for underlining, and **magenta** for wavy underlining.\"\nmsgstr \"\"\n\"通常、アノテーションの種類ごとに標準の（ストロークのみで、塗りつぶし色はサポートされていません）色が選択されます。ハイライト用に \"\n\"**黄色**、取り消し線用に **赤色**、下線用に **緑色**、波線下線用に **マゼンタ色** です。\"\n\n#: ../../page.rst:406 ddb3fc3897074943b2d1b989ef777ed7\nmsgid \"\"\n\"All these four methods convert the arguments into a list of :ref:`Quad` \"\n\"objects. The **annotation** rectangle is then calculated to envelop all \"\n\"these quadrilaterals.\"\nmsgstr \"\"\n\"これらの四つのメソッドは、引数を :ref:`Quad` オブジェクトのリストに変換します。その後、アノテーション \"\n\"の矩形は、これらの四角形を包含するように計算されます。\"\n\n#: ../../page.rst:410 e5e7ecd7dac94d878780bcbf4ccf47ee\nmsgid \"\"\n\":meth:`search_for` delivers a list of either :ref:`Rect` or :ref:`Quad` \"\n\"objects. Such a list can be directly used as an argument for these \"\n\"annotation types and will deliver **one common annotation** for all \"\n\"occurrences of the search string::\"\nmsgstr \"\"\n\":meth:`search_for` は :ref:`Rect` または :ref:`Quad` \"\n\"オブジェクトのリストを返します。このようなリストは、これらのアノテーションタイプの引数として直接使用でき、検索文字列のすべての出現に対して \"\n\"**共通のアノテーション** を提供します::\"\n\n#: ../../page.rst:417 be498e99e49f4a21b7e2148a246e5d3a\nmsgid \"\"\n\"Obviously, text marker annotations need to know what is the top, the \"\n\"bottom, the left, and the right side of the area(s) to be marked. If the \"\n\"arguments are quads, this information is given by the sequence of the \"\n\"quad points. In contrast, a rectangle delivers much less information -- \"\n\"this is illustrated by the fact, that 4! = 24 different quads can be \"\n\"constructed with the four corners of a rectangle.\"\nmsgstr \"\"\n\"明らかに、テキストマーカーアノテーションは、マークされる領域の上部、下部、左部、右部が何であるかを知る必要があります。引数がquadsの場合、この情報は四角形のポイントのシーケンスによって提供されます。対照的に、矩形ははるかに少ない情報を提供します\"\n\" - これは、四角形の四つの角を使用して24の異なる四角形が構築できるという事実によって示されています。\"\n\n#: ../../page.rst:419 7c806b98a76e4db298927d6b2db7f217\nmsgid \"\"\n\"Therefore, we **strongly recommend** to use the `quads` option for text \"\n\"searches, to ensure correct annotations. A similar consideration applies \"\n\"to marking **text spans** extracted with the \\\"dict\\\" / \\\"rawdict\\\" \"\n\"options of :meth:`Page.get_text`. For more details on how to compute \"\n\"quadrilaterals in this case, see section \\\"How to Mark Non-horizontal \"\n\"Text\\\" of :ref:`FAQ`.\"\nmsgstr \"\"\n\"したがって、正しいアノテーションを確保するために、テキスト検索に `quads` オプションを使用することを \"\n\"**強くお勧めします**。同様の考慮事項は、:meth:`Page.get_text` の「dict」/「rawdict」オプションで抽出された \"\n\"**テキストスパン** をマークする場合にも適用されます。この場合の四角形の計算方法の詳細については、:ref:`FAQ` \"\n\"の「非水平テキストのマーキング方法」セクションを参照してください。\"\n\n#: ../../page.rst:421 b12e854cdc77477bb69cfa7be1147221\nmsgid \"\"\n\"the location(s) -- rectangle(s) or quad(s) -- to be marked. (Changed in \"\n\"v1.14.20) A list or tuple must consist of :data:`rect_like` or \"\n\":data:`quad_like` items (or even a mixture of either). Every item must be\"\n\" finite, convex and not empty (as applicable). **Set this parameter to** \"\n\"``None`` if you want to use the following arguments (Changed in \"\n\"v1.16.14). And vice versa: if not ``None``, the remaining parameters must\"\n\" be ``None``.\"\nmsgstr \"\"\n\"*(v1.14.20で変更)* マーキングする位置、つまり矩形または四角形。リストまたはタプルは、:data:`rect_like` または \"\n\":data:`quad_like` \"\n\"のアイテム（またはその混合）で構成されている必要があります。各アイテムは、適用可能な限り有限で凸面で空でなければなりません \"\n\"*（v1.16.14で変更）* 。このパラメータを ``None`` \"\n\"に設定すると、次の引数を使用できるようになります。逆もまたしかり：Noneでない場合、残りのパラメータは ``None`` でなければなりません。\"\n\n#: ../../page.rst:428 089f510a4e0741409b2021b3736270b5\nmsgid \"\"\n\"start text marking at this point. Defaults to the top-left point of \"\n\"*clip*. Must be provided if `quads` is ``None``. (New in v1.16.14)\"\nmsgstr \"\"\n\"*(v1.16.14で新規)* このポイントでテキストマーキングを開始します。*clip* の左上のポイントがデフォルトです。`quads` が \"\n\"``None`` の場合、提供する必要があります。\"\n\n#: ../../page.rst:429 d2de277e9e6a43a484c54b51d6ea8199\nmsgid \"\"\n\"stop text marking at this point. Defaults to the bottom-right point of \"\n\"*clip*. Must be used if `quads` is ``None``. (New in v1.16.14)\"\nmsgstr \"\"\n\"*(v1.16.14で新規)* このポイントでテキストマーキングを停止します。*clip* の右下のポイントがデフォルトです。quadsが \"\n\"``None`` の場合、使用する必要があります。\"\n\n#: ../../page.rst:430 ffbdd0cf15b94a05abb2545b0b56572d\nmsgid \"\"\n\"only consider text lines intersecting this area. Defaults to the page \"\n\"rectangle. Only use if `start` and `stop` are provided. (New in v1.16.14)\"\nmsgstr \"\"\n\"*(v1.16.14で新規)* この領域と交差するテキスト行のみを考慮します。ページの矩形がデフォルトです。`start` および `stop` \"\n\"が提供されている場合にのみ使用してください。\"\n\n#: ../../page.rst:432 95d9be073ec0435b8a050f40e80e333d\nmsgid \":ref:`Annot` or ``None`` (changed in v1.16.14).\"\nmsgstr \":ref:`Annot` または *(v1.16.14で変更)* ``None``\"\n\n#: ../../page.rst:433 7d7542fa5b7c41b6aa27c333c40f1708\nmsgid \"\"\n\"the created annotation. If *quads* is an empty list, **no annotation** is\"\n\" created (changed in v1.16.14).\"\nmsgstr \"作成された注釈。 *(v1.16.14で変更)* *quads* が空のリストの場合、**アノテーションは作成されません**。\"\n\n#: ../../page.rst:436 98644a2344314f44ba04ba5bb452616e\nmsgid \"\"\n\"You can use parameters *start*, *stop* and *clip* to highlight \"\n\"consecutive lines between the points *start* and *stop* (starting with \"\n\"v1.16.14). Make use of *clip* to further reduce the selected line bboxes \"\n\"and thus deal with e.g. multi-column pages. The following multi-line \"\n\"highlight on a page with three text columns was created by specifying the\"\n\" two red points and setting clip accordingly.\"\nmsgstr \"\"\n\"v1.16.14以降、開始、停止、および *clip* というパラメータを使用して、*start* と *stop* \"\n\"の間の連続した行をハイライトできます。*clip* \"\n\"を使用して、選択した行のbboxをさらに縮小し、たとえば多列のページを扱うことができます。次の多行のハイライトは、2つの赤いポイントを指定し、それに応じてクリップを設定することによって、3つのテキスト列を持つページに作成されました。\"\n\n#: ../../page.rst:445 75642278b2224e88a9772fd96d3a3059\nmsgid \"\"\n\"Cluster vector graphics (synonyms are line-art or drawings) based on \"\n\"their geometrical vicinity. The method walks through the output of \"\n\":meth:`Page.get_drawings` and joins paths whose `path[\\\"rect\\\"]` are \"\n\"closer to each other than some tolerance values (given in the arguments).\"\n\" The result is a list of rectangles that each wrap things like tables \"\n\"(with gridlines), pie charts, bar charts, etc.\"\nmsgstr \"\"\n\"図形のクラスター（同義語は線画やドローイングです）を、幾何学的な近接性に基づいてグループ化します。このメソッドは、 \"\n\":meth:`Page.get_drawings` の出力を処理し、その中で、`path[\\\"rect\\\"]` \"\n\"がある許容値（引数で指定された）よりも近いパスを結合します。結果は、各々が表（格子状の線がある）、円グラフ、棒グラフなどのものを包含する長方形のリストです。\"\n\n#: ../../page.rst:447 8af220b5d116468da1c3a74e2d346cd4\nmsgid \"only consider paths inside this area. The default is the full page.\"\nmsgstr \"only consider paths inside this area. The default is the full page.\"\n\n#: ../../page.rst:449 0f2851c495ca480fb94cd3aec130a7b3\nmsgid \"\"\n\"(optional) provide a previously generated output of \"\n\":meth:`Page.get_drawings`. If `None` the method will execute the method.\"\nmsgstr \"（任意）以前に生成された :meth:`Page.get_drawings` の出力を提供します。`None` の場合、メソッドが実行されます。\"\n\n#: ../../page.rst:451 49e0542c28684b6b903d2d86c7b062a6\nmsgid \"\"\n\"Assume vector graphics to be close enough neighbors for belonging to the \"\n\"same rectangle. Default is 3 points.\"\nmsgstr \"\"\n\n#: ../../page.rst:453 ce87a4c4de064cb49cd1d3430b4676d3\nmsgid \"\"\n\"If `True` (default), the method will to remove rectangles having width or\"\n\" height smaller than the respective tolerance value. If `False` no such \"\n\"filtering is done.\"\nmsgstr \"\"\n\n#: ../../page.rst:457 a09f9aad182c477caf151dc66eb6f2cd\nmsgid \"\"\n\"Find tables on the page and return an object with related information. \"\n\"Typically, the default values of the many parameters will be sufficient. \"\n\"Adjustments should ever only be needed in corner case situations.\"\nmsgstr \"ページ上のテーブルを見つけ、関連情報を含むオブジェクトを返します。通常、多くのパラメータのデフォルト値は十分です。調整が必要なのは、極めてまれなケースのみです。\"\n\n#: ../../page.rst:459 74a611af01fb41deac6b00bf3e092130\nmsgid \"\"\n\"specify a region to consider within the page rectangle and ignore the \"\n\"rest. Default is the full page.\"\nmsgstr \"ページの長方形内で考慮する領域を指定します。デフォルトはページ全体です。\"\n\n#: ../../page.rst:461 c6cda0b38ecc4c4ab6b9e66681366f13\nmsgid \"\"\n\"Request a **table detection** strategy. Valid values are \\\"lines\\\", \"\n\"\\\"lines_strict\\\" and \\\"text\\\".  Default is **\\\"lines\\\"** which uses all \"\n\"vector graphics on the page to detect grid lines.  Strategy \"\n\"**\\\"lines_strict\\\"** ignores borderless rectangle vector graphics. \"\n\"Sometimes single text pieces have background colors which may lead to \"\n\"false columns or lines. This strategy ignores them and can thus increase \"\n\"detection precision.  If **\\\"text\\\"** is specified, text positions are \"\n\"used to generate \\\"virtual\\\" column and / or row boundaries. Use \"\n\"`min_words_*` to request the number of words for considering their \"\n\"coordinates.  Use parameters `vertical_strategy` and \"\n\"`horizontal_strategy` **instead** for a more fine-grained treatment of \"\n\"the dimensions.\"\nmsgstr \"**テーブル検出**戦略をリクエストします。有効な値は、**「lines」**、**「lines_strict」** 、**「text」** です\"\n\n#: ../../page.rst:461 49dcc16d7dc54781abdfa232abec999e\nmsgid \"\"\n\"Request a **table detection** strategy. Valid values are \\\"lines\\\", \"\n\"\\\"lines_strict\\\" and \\\"text\\\".\"\nmsgstr \"**テーブル検出**戦略をリクエストします。有効な値は、**「lines」**、**「lines_strict」** 、**「text」** です。\"\n\n#: ../../page.rst:463 487f50ea618a41b69d1d35e5becc936e\nmsgid \"\"\n\"Default is **\\\"lines\\\"** which uses all vector graphics on the page to \"\n\"detect grid lines.\"\nmsgstr \"デフォルトは **「lines」** で、ページ上のすべてのベクトルグラフィックスを使用してグリッド線を検出します。\"\n\n#: ../../page.rst:465 475d14ec21db4fa5b86f652beb2fa96e\nmsgid \"\"\n\"Strategy **\\\"lines_strict\\\"** ignores borderless rectangle vector \"\n\"graphics. Sometimes single text pieces have background colors which may \"\n\"lead to false columns or lines. This strategy ignores them and can thus \"\n\"increase detection precision.\"\nmsgstr \"\"\n\"ストラテジー **「lines_strict」** \"\n\"は、境界のない四角形のベクトルグラフィックスを無視します。時には、個々のテキスト部分に背景色があることがあり、これが誤った列や行を生じる可能性があります。この戦略はそれらを無視し、したがって検出精度を向上させることができます。\"\n\n#: ../../page.rst:467 620ca770d5a84f1f8274b964de8e0a8d\nmsgid \"\"\n\"If **\\\"text\\\"** is specified, text positions are used to generate \"\n\"\\\"virtual\\\" column and / or row boundaries. Use `min_words_*` to request \"\n\"the number of words for considering their coordinates.\"\nmsgstr \"検索アルゴリズムを指定します。デフォルトでは「lines」はベクトル描画を探します。指定された場合、「text」ではテキストの位置を使用して「仮想」列境界を生成します。x座標を考慮するための単語数を指定するには、`min_words_*`を使用します。\"\n\n#: ../../page.rst:469 55aec1b404204b0e83768215c8eae28d\nmsgid \"\"\n\"Use parameters `vertical_strategy` and `horizontal_strategy` **instead** \"\n\"for a more fine-grained treatment of the dimensions.\"\nmsgstr \"サイズの微調整には、`vertical_strategy` と`horizontal_strategy` パラメータを使用してください。\"\n\n#: ../../page.rst:471 b57bc9f7abbd4ef9babbe5d0dff06e4d\nmsgid \"\"\n\"y-coordinates of rows. If provided, there will be no attempt to identify \"\n\"additional table rows. This influences table detection.\"\nmsgstr \"行のy座標を含む浮動小数点数のリスト。指定した場合、追加のテーブル行を識別しないようにします。\"\n\n#: ../../page.rst:473 d7014235e8a2469d8a599a403b70c460\nmsgid \"\"\n\"x-coordinates of columns. If provided, there will be no attempt to \"\n\"identify additional table columns. This influences table detection.\"\nmsgstr \"列のx座標を含む浮動小数点数のリスト。指定した場合、追加のテーブル列を識別しないようにします。\"\n\n#: ../../page.rst:475 8597b2d142824c29a8116c7c89749dfa\nmsgid \"\"\n\"relevant for vertical strategy option \\\"text\\\": at least this many words \"\n\"must coincide to establish a **virtual column** boundary.\"\nmsgstr \"垂直戦略オプション「text」に関連します。少なくともこの数の単語が一致する必要があり、仮想の列境界を確立します。\"\n\n#: ../../page.rst:477 1fff3607f10f4335ae8da286bcf1b265\nmsgid \"\"\n\"relevant for horizontal strategy option \\\"text\\\": at least this many \"\n\"words must coincide to establish a **virtual row** boundary.\"\nmsgstr \"水平戦略オプション「text」に関連します。少なくともこの数の単語が一致する必要があり、仮想の行境界を確立します。\"\n\n#: ../../page.rst:479 fe507763ad9248bbbe7ed10253cf19a6\nmsgid \"\"\n\"Any two horizontal lines whose y-values differ by no more than this value\"\n\" will be **snapped** into one. Accordingly for vertical lines. Default is\"\n\" 3. Separate values can be specified instead for the dimensions, using \"\n\"`snap_x_tolerance` and `snap_y_tolerance`.\"\nmsgstr \"\"\n\"各縦線は、y値の差がこの値以下であれば、一つに結合されます。同様に、各横線も結合されます。デフォルトは3です。この値の代わりに、次元ごとに異なる値を指定することもできます。`snap_x_tolerance`\"\n\" および `snap_y_tolerance` を使用してください。\"\n\n#: ../../page.rst:481 019d0273cf7b4e5d82a05b28826235ea\nmsgid \"\"\n\"Any two lines will be **joined** to one if the end and the start points \"\n\"differ by no more than this value (in points). Default is 3. Instead of \"\n\"this value, separate values can be specified for the dimensions using \"\n\"`join_x_tolerance` and `join_y_tolerance`.\"\nmsgstr \"\"\n\"2つのラインの終点と始点の間の差がこの値（ポイント単位）以下の場合、それらは1つのラインに **結合されます**    \"\n\"。デフォルトは3です。この値の代わりに、`join_x_tolerance` と `join_y_tolerance` \"\n\"を使用して寸法ごとに別々の値を指定できます。\"\n\n#: ../../page.rst:483 ca0d9fea67634596941e6d13c7395948\nmsgid \"\"\n\"Ignore a line if its length does not exceed this value (points). Default \"\n\"is 3.\"\nmsgstr \"この値（ポイント単位）を超えない場合、線を無視します。デフォルトは3です\"\n\n#: ../../page.rst:485 a638d4f3b5d944a19aa7ef553c1b08f2\nmsgid \"\"\n\"When combining lines into cell borders, orthogonal lines must be within \"\n\"this value (points) to be considered intersecting. Default is 3. Instead \"\n\"of this value, separate values can be specified for the dimensions using \"\n\"`intersection_x_tolerance` and `intersection_y_tolerance`.\"\nmsgstr \"\"\n\"直交するラインをセルの境界線に結合する際に、それらの直交するラインはこの値（ポイント単位）以内である必要があります。デフォルトは3です。この値の代わりに、次元ごとに個別の値を指定することもできます。`intersection_x_tolerance`\"\n\" と `intersection_y_tolerance` を使用します。\"\n\n#: ../../page.rst:487 9b17ecb26f16435eab08ade1ce87a836\nmsgid \"\"\n\"Characters will be combined into words only if their distance is no \"\n\"larger than this value (points). Default is 3. Instead of this value, \"\n\"separate values can be specified for the dimensions using \"\n\"`text_x_tolerance` and `text_y_tolerance`.\"\nmsgstr \"\"\n\"文字が単語に結合されるのは、その距離がこの値（ポイント）を超えない場合のみです。デフォルト値は3です。この値の代わりに、次元ごとに別々の値を指定することもできます。`text_x_tolerance`\"\n\" と `text_y_tolerance` を使用します。\"\n\n#: ../../page.rst:489 a6a350a7a75140a7be8ccce2ee4fb8c4\n#, fuzzy\nmsgid \"\"\n\"Specify a list of \\\"lines\\\" (i.e. pairs of :data:`point_like` objects) as\"\n\" **additional**, \\\"virtual\\\" vector graphics. These lines may help with \"\n\"table and / or cell detection and will not otherwise influence the \"\n\"detection strategy. Especially, in contrast to parameters \"\n\"`horizontal_lines` and `vertical_lines`, they will not prevent detecting \"\n\"rows or columns in other ways. These lines will be treated exactly like \"\n\"\\\"real\\\" vector graphics in terms of joining, snapping, intersecting, \"\n\"minimum length and containment in the `clip` rectangle. Similarly, lines \"\n\"not parallel to any of the coordinate axes will be ignored.\"\nmsgstr \"\"\n\"以下のような「lines」（つまり、 :data:`point_like` オブジェクトのペア）のリストを追加の「仮想」ベクトル \"\n\"グラフィックスとして指定します。これらの線は、テーブルと/またはセルの検出に役立ち、検出戦略には影響しません。特に、`horizontal_lines`\"\n\" と `vertical_lines` \"\n\"パラメータとは異なり、これらの線は他の方法で行または列を検出するのを妨げません。これらの線は、結合、スナップ、交差、最小長、およびクリップ矩形内への含有の点で、「実際の」ベクトル\"\n\" グラフィックスとまったく同様に処理されます。同様に、座標軸のいずれかに平行でない線は無視されます。\"\n\n#: ../../page.rst:491 2de25b9194a945d9b22879d826f9d4fd\n#, fuzzy\nmsgid \"\"\n\"Specify a list of rectangles (:data:`rect_like` objects) as \"\n\"**additional**, \\\"virtual\\\" vector graphics. These rectangles may help \"\n\"with table and / or cell detection and will not otherwise influence the \"\n\"detection strategy. Especially, in contrast to parameters \"\n\"`horizontal_lines` and `vertical_lines`, they will not prevent detecting \"\n\"rows or columns in other ways. These rectangles will be treated exactly \"\n\"like \\\"real\\\" vector graphics in terms of joining, snapping, \"\n\"intersecting, minimum length and containment in the `clip` rectangle.\"\nmsgstr \"\"\n\"以下のような「lines」（つまり、 :data:`point_like` オブジェクトのペア）のリストを追加の「仮想」ベクトル \"\n\"グラフィックスとして指定します。これらの線は、テーブルと/またはセルの検出に役立ち、検出戦略には影響しません。特に、`horizontal_lines`\"\n\" と `vertical_lines` \"\n\"パラメータとは異なり、これらの線は他の方法で行または列を検出するのを妨げません。これらの線は、結合、スナップ、交差、最小長、およびクリップ矩形内への含有の点で、「実際の」ベクトル\"\n\" グラフィックスとまったく同様に処理されます。同様に、座標軸のいずれかに平行でない線は無視されます。\"\n\n#: ../../page.rst:493 c824c246b4444d25905dca68201a67e6\nmsgid \"\"\n\"list of vector graphics in the format as returned be \"\n\":meth:`Page.get_drawings`. Using this parameter will prevent the method \"\n\"to extract vector graphics itself. This is useful if the vector graphics \"\n\"are already available. This can save execution time significantly.\"\nmsgstr \"\"\n\n#: ../../page.rst:497 f04ba862cde54466baab8d1b6048b4a5\nmsgid \"\"\n\"a `TableFinder` object that has the following significant attributes:  * \"\n\"`cells`: a list of **all bboxes** on the page, that have been identified \"\n\"as table cells (across all tables). Each cell is a :data:`rect_like` \"\n\"tuple `(x0, y0, x1, y1)` of coordinates or `None`. * `tables`: a list of \"\n\"`Table` objects. This is `[]` if the page has no tables. Single tables \"\n\"can be found as items of this list. But the `TableFinder` object itself \"\n\"is also a sequence of its tables. This means that if `tabs` is a \"\n\"`TableFinder` object, then table \\\"n\\\" is delivered by `tabs.tables[n]` \"\n\"as well as by the shorter `tabs[n]`.   * The `Table` object has the \"\n\"following attributes:    * ``bbox``: the bounding box of the table as a \"\n\"tuple `(x0, y0, x1, y1)`.   * ``cells``: bounding boxes of the table's \"\n\"cells (list of tuples). A cell may also be `None`.   * ``extract()``: \"\n\"this method returns the text content of each table cell as a list of list\"\n\" of strings.   * ``to_markdown()``: this method returns the table as a \"\n\"**string in markdown format** (compatible to Github). Markdown viewers \"\n\"can render the string as a table. This output is optimized for **small \"\n\"token** sizes, which is especially beneficial for LLM/RAG feeds. Pandas \"\n\"DataFrames (see method `to_pandas()` below) offer an equivalent markdown \"\n\"table output which however is better readable for the human eye. Any line\"\n\" breaks (``\\\\n``) in cells are replaced by HTML line breaks tags `<br>`.\"\n\"   * `to_pandas()`: this method returns the table as a `pandas \"\n\"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n\"<https://pandas.pydata.org/docs/reference/frame.html>`_. DataFrames are \"\n\"very versatile objects allowing a plethora of table manipulation methods \"\n\"and outputs to almost 20 well-known formats, among them Excel files, CSV,\"\n\" JSON, markdown-formatted tables and more. `DataFrame.to_markdown()` \"\n\"generates a Github-compatible markdown format optimized for human \"\n\"readability. This method however requires the package `tabulate \"\n\"<https://pypi.org/project/tabulate/>`_ to be installed in addition to \"\n\"pandas itself.   * ``header``: a `TableHeader` object containing header \"\n\"information of the table.   * ``col_count``: an integer containing the \"\n\"number of table columns.   * ``row_count``: an integer containing the \"\n\"number of table rows.   * ``rows``: a list of `TableRow` objects \"\n\"containing two attributes, ``bbox`` is the boundary box of the row, and \"\n\"`cells` is a list of table cells contained in this row.  * The \"\n\"`TableHeader` object has the following attributes:    * ``bbox``: the \"\n\"bounding box of the header.   * `cells`: a list of bounding boxes \"\n\"containing the name of the respective column.   * `names`: a list of \"\n\"strings containing the text of each of the cell bboxes. They represent \"\n\"the column names -- which are used when exporting the table to pandas \"\n\"DataFrames, markdown, etc.   * `external`: a bool indicating whether the \"\n\"header bbox is outside the table body (`True`) or not. Table headers are \"\n\"never identified by the `TableFinder` logic. Therefore, if `external` is \"\n\"true, then the header cells are not part of any cell identified by \"\n\"`TableFinder`. If `external == False`, then the first table row is the \"\n\"header.  Please have a look at these `Jupyter notebooks \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-\"\n\"analysis>`_, which cover standard situations like multiple tables on one \"\n\"page or joining table fragments across multiple pages.  .. caution:: The \"\n\"lifetime of the `TableFinder` object, as well as that of all its tables \"\n\"**equals the lifetime of the page**. If the page object is deleted or \"\n\"reassigned, all tables are no longer valid.     The only way to keep \"\n\"table content beyond the page's availability is to **extract it** via \"\n\"methods `Table.to_markdown()`, `Table.to_pandas()` or a copy of \"\n\"`Table.extract()` (e.g. `Table.extract()[:]`).  .. note::     Once a \"\n\"table has been extracted to a **Pandas DataFrame** with `to_pandas()` it \"\n\"is easy to convert to other file types with the **Pandas API**:     - \"\n\"table to Markdown, use `to_markdown \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_markdown.html#pandas.DataFrame.to_markdown>`_\"\n\"    - table to JSON, use: `to_json \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html>`_\"\n\"    - table to Excel, use: `to_excel \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html>`_\"\n\"    - table to CSV, use: `to_csv \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html>`_\"\n\"    - table to HTML, use: `to_html \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html>`_\"\n\"    - table to SQL, use: `to_sql \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:497 84419d75309847998f10e74484826aa4\nmsgid \"a `TableFinder` object that has the following significant attributes:\"\nmsgstr \"`TableFinder` オブジェクトには、次の重要な属性があります：\"\n\n#: ../../page.rst:499 914dadb7b99c41e397f201925e416bf3\nmsgid \"\"\n\"`cells`: a list of **all bboxes** on the page, that have been identified \"\n\"as table cells (across all tables). Each cell is a :data:`rect_like` \"\n\"tuple `(x0, y0, x1, y1)` of coordinates or `None`.\"\nmsgstr \"\"\n\"**cells:** \"\n\"ページ上でテーブルのセルとして識別されたすべてのバウンディングボックスのリスト（すべてのテーブルを対象にします）。各セルは座標のタプル (x0, \"\n\"y0, x1, y1) または `None` です。\"\n\n#: ../../page.rst:500 9583a87c04ff4e42be01211503a625ff\nmsgid \"\"\n\"`tables`: a list of `Table` objects. This is `[]` if the page has no \"\n\"tables. Single tables can be found as items of this list. But the \"\n\"`TableFinder` object itself is also a sequence of its tables. This means \"\n\"that if `tabs` is a `TableFinder` object, then table \\\"n\\\" is delivered \"\n\"by `tabs.tables[n]` as well as by the shorter `tabs[n]`.\"\nmsgstr \"\"\n\"**tables:** Table オブジェクトのリスト。ページにテーブルが含まれていない場合、これは `[]` \"\n\"になります。単一のテーブルはこのリストのアイテムとして見つけることができますが、`TableFinder` \"\n\"オブジェクト自体もそのテーブルのシーケンスです。つまり、`tabs` が `TableFinder` オブジェクトである場合、テーブル番号 \"\n\"\\\"n\\\" は `tabs.tables[n]` およびより短い `tabs[n]` によって提供されます。\"\n\n#: ../../page.rst:503 2b85b5bbae0b4d1d9f39db8007aca40e\nmsgid \"The `Table` object has the following attributes:\"\nmsgstr \"`Table` オブジェクトには次の属性があります：\"\n\n#: ../../page.rst:505 c012c8a43f22438dabb93e5220436935\n#, fuzzy\nmsgid \"``bbox``: the bounding box of the table as a tuple `(x0, y0, x1, y1)`.\"\nmsgstr \"**bbox:** テーブルのバウンディングボックス（タプル）`(x0, y0, x1, y1)`。\"\n\n#: ../../page.rst:506 698bd70ef8b34723b3be7258f9e41a9b\n#, fuzzy\nmsgid \"\"\n\"``cells``: bounding boxes of the table's cells (list of tuples). A cell \"\n\"may also be `None`.\"\nmsgstr \"**cells:** テーブルのセルのバウンディングボックス（タプル）のリスト。セルは `None` である場合もあります。\"\n\n#: ../../page.rst:507 5df00852328d4938af7a291d32ff1081\n#, fuzzy\nmsgid \"\"\n\"``extract()``: this method returns the text content of each table cell as\"\n\" a list of list of strings.\"\nmsgstr \"**extract():** このメソッドは、各テーブルセルのテキストコンテンツを文字列のリストのリストとして返します。\"\n\n#: ../../page.rst:508 4a75e91b2fa2471d8011d96b0fe413ef\nmsgid \"\"\n\"``to_markdown()``: this method returns the table as a **string in \"\n\"markdown format** (compatible to Github). Markdown viewers can render the\"\n\" string as a table. This output is optimized for **small token** sizes, \"\n\"which is especially beneficial for LLM/RAG feeds. Pandas DataFrames (see \"\n\"method `to_pandas()` below) offer an equivalent markdown table output \"\n\"which however is better readable for the human eye. Any line breaks \"\n\"(``\\\\n``) in cells are replaced by HTML line breaks tags `<br>`.\"\nmsgstr \"\"\n\n#: ../../page.rst:509 e617dce6f36248939178f71102d4b3ad\n#, fuzzy\nmsgid \"\"\n\"`to_pandas()`: this method returns the table as a `pandas \"\n\"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n\"<https://pandas.pydata.org/docs/reference/frame.html>`_. DataFrames are \"\n\"very versatile objects allowing a plethora of table manipulation methods \"\n\"and outputs to almost 20 well-known formats, among them Excel files, CSV,\"\n\" JSON, markdown-formatted tables and more. `DataFrame.to_markdown()` \"\n\"generates a Github-compatible markdown format optimized for human \"\n\"readability. This method however requires the package `tabulate \"\n\"<https://pypi.org/project/tabulate/>`_ to be installed in addition to \"\n\"pandas itself.\"\nmsgstr \"\"\n\"`to_pandas()` : このメソッドは、テーブルを `pandas \"\n\"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n\"<https://pandas.pydata.org/docs/reference/frame.html>`_ として返します。DataFrame\"\n\" は非常に多目的なオブジェクトであり、さまざまなテーブル操作メソッドや、Excel ファイル、CSV、JSON、markdown \"\n\"形式のテーブルなど、約 20 種類のよく知られたフォーマットへの出力が可能です。`DataFrame.to_markdown()` \"\n\"は、人間が読みやすいように最適化された Github 互換の markdown 形式を生成します。ただし、このメソッドには pandas \"\n\"だけでなく、 [tablutate](https://pypi.org/project/tabulate/)  \"\n\"パッケージの追加インストールが必要です。\"\n\n#: ../../page.rst:510 5f646932780e47628df37150eba6cb11\nmsgid \"\"\n\"``header``: a `TableHeader` object containing header information of the \"\n\"table.\"\nmsgstr \"**header:** テーブルのヘッダー情報を含む `TableHeader` オブジェクト。\"\n\n#: ../../page.rst:511 2d6afff58bdd4b22982426aeaf93f0eb\n#, fuzzy\nmsgid \"``col_count``: an integer containing the number of table columns.\"\nmsgstr \"**col_count:** テーブルの列数を含む整数。\"\n\n#: ../../page.rst:512 a011c98d056a4ab99078f551a9c555a7\n#, fuzzy\nmsgid \"``row_count``: an integer containing the number of table rows.\"\nmsgstr \"**row_count:**  テーブルの行数を含む整数。\"\n\n#: ../../page.rst:513 ea78abc0fa2b48fc82e3b1818b26a2b9\n#, fuzzy\nmsgid \"\"\n\"``rows``: a list of `TableRow` objects containing two attributes, \"\n\"``bbox`` is the boundary box of the row, and `cells` is a list of table \"\n\"cells contained in this row.\"\nmsgstr \"\"\n\"**rows:** `TableRow` オブジェクトのリストで、*bbox* は行の境界ボックスで、*cells* \"\n\"はこの行に含まれるテーブルセルのリストです。\"\n\n#: ../../page.rst:515 9195a39415c24bd5b313c7328c2cb59f\nmsgid \"The `TableHeader` object has the following attributes:\"\nmsgstr \"`TableHeader` オブジェクトには次の属性があります：\"\n\n#: ../../page.rst:517 4f75c5d8372b41b596f2132f8f9cb869\nmsgid \"``bbox``: the bounding box of the header.\"\nmsgstr \"**bbox:** ヘッダーのバウンディングボックス。\"\n\n#: ../../page.rst:518 573cb43edf9046a5b0564d46d89d463c\nmsgid \"\"\n\"`cells`: a list of bounding boxes containing the name of the respective \"\n\"column.\"\nmsgstr \"**cells:** 各列の名前を含むバウンディングボックスのリスト。\"\n\n#: ../../page.rst:519 9a2e52a4c74c49148081c9d490cbb1b1\nmsgid \"\"\n\"`names`: a list of strings containing the text of each of the cell \"\n\"bboxes. They represent the column names -- which are used when exporting \"\n\"the table to pandas DataFrames, markdown, etc.\"\nmsgstr \"\"\n\"**names:** 各セルのバウンディングボックス内のテキストを含む文字列のリスト。これらは列の名前を表します。これらはテーブルを pandas\"\n\" DataFrame または CSV などにエクスポートする際に使用できます。\"\n\n#: ../../page.rst:520 f6724988042c4b698633b4cf7e752649\nmsgid \"\"\n\"`external`: a bool indicating whether the header bbox is outside the \"\n\"table body (`True`) or not. Table headers are never identified by the \"\n\"`TableFinder` logic. Therefore, if `external` is true, then the header \"\n\"cells are not part of any cell identified by `TableFinder`. If `external \"\n\"== False`, then the first table row is the header.\"\nmsgstr \"\"\n\"**external:** ヘッダーのバウンディングボックスがテーブル本体の外部にあるかどうかを示すブール値（`True` \"\n\"の場合、外部）。テーブルのヘッダーは TableFinder のロジックによって識別されないため、*external* が True \"\n\"の場合、ヘッダーセルは `TableFinder` によって識別された任意のセルの一部ではありません。`external == False` \"\n\"の場合、最初のテーブル行がヘッダーです。\"\n\n#: ../../page.rst:522 75e1dfe474ed4ac0a22da38addfd7eb7\nmsgid \"\"\n\"Please have a look at these `Jupyter notebooks \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-\"\n\"analysis>`_, which cover standard situations like multiple tables on one \"\n\"page or joining table fragments across multiple pages.\"\nmsgstr \"\"\n\"これらの `Jupyter notebooks <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/table-analysis>`_ \"\n\"をご覧ください。これらのノートブックでは、1つのページに複数のテーブルがある場合や、複数のページにまたがるテーブル断片を結合するなど、標準的な状況がカバーされています。\"\n\n#: ../../page.rst:524 5542b53a24dd430ab806eafb4021ebb6\nmsgid \"\"\n\"The lifetime of the `TableFinder` object, as well as that of all its \"\n\"tables **equals the lifetime of the page**. If the page object is deleted\"\n\" or reassigned, all tables are no longer valid.\"\nmsgstr \"\"\n\n#: ../../page.rst:526 75ed5e4bc66d4338bc281838569cf1ed\nmsgid \"\"\n\"The only way to keep table content beyond the page's availability is to \"\n\"**extract it** via methods `Table.to_markdown()`, `Table.to_pandas()` or \"\n\"a copy of `Table.extract()` (e.g. `Table.extract()[:]`).\"\nmsgstr \"\"\n\n#: ../../page.rst:530 020511fcaf024437a95dea516e1c4075\nmsgid \"\"\n\"Once a table has been extracted to a **Pandas DataFrame** with \"\n\"`to_pandas()` it is easy to convert to other file types with the **Pandas\"\n\" API**:\"\nmsgstr \"\"\n\n#: ../../page.rst:532 1802aeb23deb4170b11761cf16a41608\nmsgid \"\"\n\"table to Markdown, use `to_markdown \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_markdown.html#pandas.DataFrame.to_markdown>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:533 05c0dff89ae44350a0f8cb185d9ca6c6\nmsgid \"\"\n\"table to JSON, use: `to_json \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:534 b9be51cdd74544d7a7b240e4943d42e4\nmsgid \"\"\n\"table to Excel, use: `to_excel \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:535 0b4b368f030c4f65bae428c76e61dd78\nmsgid \"\"\n\"table to CSV, use: `to_csv \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:536 c952cf87a79642ff9849bb5c2e32e39b\nmsgid \"\"\n\"table to HTML, use: `to_html \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:537 307428a286cf4f15a96b17d0e3720f43\nmsgid \"\"\n\"table to SQL, use: `to_sql \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:542 b045da5db3aa4ea2af45fd37b2e43ad8\nmsgid \"New in version 1.23.0\"\nmsgstr \"新機能バージョン1.23.0\"\n\n#: ../../page.rst:543 e2de54e7d89b48cf868f7e7b254d8f11\nmsgid \"Changed in version 1.23.19: new argument `add_lines`.\"\nmsgstr \"1.23.19で変更された点：新しい引数 `add_lines` 。\"\n\n#: ../../page.rst:549 e7ba1b19c5964a6b875bacb0405e7b4a\nmsgid \"\"\n\"There is also the `pdf2docx extract tables method`_ which is capable of \"\n\"table extraction if you prefer.\"\nmsgstr \"必要に応じて、テーブル抽出を行う `pdf2docx extract tables method`_ も利\"\n\n#: ../../page.rst:554 07554ca053404982b9be25b02745810b\nmsgid \"\"\n\"PDF only: Add a \\\"rubber stamp\\\" annotation to e.g. indicate the \"\n\"document's intended use (\\\"DRAFT\\\", \\\"CONFIDENTIAL\\\", etc.). The \"\n\"parameter may be either an integer to select text from a predefined array\"\n\" of standard texts or an image.\"\nmsgstr \"\"\n\n#: ../../page.rst:556 0e380a591d864ca49e58155f8217e31a\nmsgid \"rectangle where to place the annotation.\"\nmsgstr \"アノテーションを配置する矩形領域。\"\n\n#: ../../page.rst:557 c7d3ea80fdb64fc9b0957574df07aadd\nmsgid \"\"\n\"The following options are available:  * The id number (int) of the stamp \"\n\"text. For available stamps see :ref:`StampIcons`.  * A string specifying \"\n\"an image file path.  * A ``bytes``, ``bytearray`` or ``io.BytesIO`` \"\n\"object for an image in memory.  * A :ref:`Pixmap`.\"\nmsgstr \"\"\n\n#: ../../page.rst:557 74442f94aab649a8ba4710d8284a0e27\nmsgid \"The following options are available:\"\nmsgstr \"\"\n\n#: ../../page.rst:559 140cb281aae84a22b89e70c6729c9ae6\n#, fuzzy\nmsgid \"\"\n\"The id number (int) of the stamp text. For available stamps see \"\n\":ref:`StampIcons`.\"\nmsgstr \"スタンプテキストのID番号。使用可能なスタンプについては :ref:`StampIcons` を参照してください。\"\n\n#: ../../page.rst:561 a86218a2b5ca41798ea2e87e076fede6\nmsgid \"A string specifying an image file path.\"\nmsgstr \"\"\n\n#: ../../page.rst:563 2ab257ca8fa64d76a9a88d8c0cb8fdbf\nmsgid \"\"\n\"A ``bytes``, ``bytearray`` or ``io.BytesIO`` object for an image in \"\n\"memory.\"\nmsgstr \"\"\n\n#: ../../page.rst:565 6470d3eee4704e8aa7445e56cc77a9aa\nmsgid \"A :ref:`Pixmap`.\"\nmsgstr \"\"\n\n#: ../../page.rst:567 122c6baf020a4bac971ac2367b0cf3df\nmsgid \"**Text-based stamps**\"\nmsgstr \"\"\n\n#: ../../page.rst:569 ee84cbb991794dbc8418e486393dc58b\nmsgid \"\"\n\":attr:`Annot.rect` is automatically calculated as the largest rectangle \"\n\"with an aspect ratio of ``width:height = 3.8`` that fits in the provided \"\n\"``rect``. Its position is vertically and horizontally centered.\"\nmsgstr \"\"\n\n#: ../../page.rst:570 c58ca83a6d0d476c87477063c93639f0\nmsgid \"The font chosen is \\\"Times Bold\\\" and the text will be upper case.\"\nmsgstr \"選択されるフォントは「Times Bold」で、テキストは大文字になります。\"\n\n#: ../../page.rst:571 4bb912d4e39343ceb25f2cc8f03fde19\n#, fuzzy\nmsgid \"\"\n\"The appearance can be modified using :meth:`Annot.set_opacity` and by \"\n\"setting the \\\"stroke\\\" color. By PDF specification, stamp annotations \"\n\"have no \\\"fill\\\" color.\"\nmsgstr \"\"\n\"外観は :meth:`Annot.set_opacity` を使用して変更でき、\\\"stroke\\\" \"\n\"色を設定することができます（「fill」色はサポートされていません）。\"\n\n#: ../../page.rst:575 064624bb57674dd49f4b0f0ab02bce4d\nmsgid \"**Image-based stamps**\"\nmsgstr \"\"\n\n#: ../../page.rst:577 e17409d3940644e6b56475fa8581c0a2\nmsgid \"\"\n\"The image is scaled to fit into the rectangle `rect` such that the \"\n\"image's center and the center of `rect` coincide. The aspect ratio of the\"\n\" image is preserved, so the image may not fill the entire rectangle. \"\n\"However, at least one of the given rectangle's width or height are fully \"\n\"covered.\"\nmsgstr \"\"\n\n#: ../../page.rst:578 ec8dc9929ec44befb62f520a5bdce9b6\nmsgid \"\"\n\"The annotation can be modified via :meth:`Annot.set_opacity`. This method\"\n\" therefore is a way to display images transparently even if no alpha \"\n\"channel is present.\"\nmsgstr \"\"\n\n#: ../../page.rst:579 5ad9fae89ca94e40910abdcf5da94353\nmsgid \"Setting colors has no effect on image stamps.\"\nmsgstr \"\"\n\n#: ../../page.rst:580 6e2bc4decc3d49899690b03ac8cc7481\nmsgid \"\"\n\"Rotating image-based stamps **is not supported**. Setting the rotation \"\n\"may lead to unexpected results.\"\nmsgstr \"\"\n\n#: ../../page.rst:584 a28852a4a1d94c6f9180b933ec9dcd50\nmsgid \"\"\n\"PDF only: Add a PDF Form field (\\\"widget\\\") to a page. This also **turns \"\n\"the PDF into a Form PDF**. Because of the large amount of different \"\n\"options available for widgets, we have developed a new class \"\n\":ref:`Widget`, which contains the possible PDF field attributes. It must \"\n\"be used for both, form field creation and updates.\"\nmsgstr \"\"\n\"PDFのみ：ページにPDFフォームフィールド（ウィジェット）を追加します。これにより、PDFがフォームPDFに変換されます。ウィジェットにはさまざまなオプションがあるため、フォームフィールドの作成と更新の両方に使用する必要があるため、可能なPDFフィールド属性を含む新しいクラス\"\n\" :ref:`Widget` を開発しました。\"\n\n#: ../../page.rst:586 5b4e58c5d61a4b0a86c9ac4f611770a7\nmsgid \"a :ref:`Widget` object which must have been created upfront.\"\nmsgstr \"事前に作成されている必要がある :ref:`Widget` オブジェクト。\"\n\n#: ../../page.rst:589 bcc225bd9cfb49cea096e52ab83f35d7\nmsgid \"a widget annotation.\"\nmsgstr \"ウィジェットアノテーション。\"\n\n#: ../../page.rst:593 d639ef397d36485e8aa8bb26d31c0378\nmsgid \"\"\n\"The removal will now include any bound 'Popup' or response annotations \"\n\"and related objects (changed in v1.16.6).\"\nmsgstr \"v1.16.6 で変更: 削除操作には、現在は関連する 'Popup' や応答アノテーションおよび関連するオブジェクトも含まれます。\"\n\n#: ../../page.rst:595 8a00f469b1414059b4c586637e921948\nmsgid \"PDF only: Delete annotation from the page and return the next one.\"\nmsgstr \"PDFのみ：ページから注釈を削除し、次の注釈を返します。\"\n\n#: ../../page.rst:597 0482b1a51d404765adec9f2a73d29869\nmsgid \"the annotation to be deleted.\"\nmsgstr \"削除するアノテーション。\"\n\n#: ../../page.rst:601 8d0565728a8f4e40bbedbf26823b785b\nmsgid \"\"\n\"the annotation following the deleted one. Please remember that physical \"\n\"removal requires saving to a new file with garbage > 0.\"\nmsgstr \"削除された注釈の後に続く注釈。物理的な削除には、ガベージ> 0で新しいファイルに保存する必要があることを覚えておいてください。\"\n\n#: ../../page.rst:605 701b3fe6c5c04d919d89284c697a8e04\nmsgid \"PDF only: Delete field from the page and return the next one.\"\nmsgstr \"PDFのみ：ページからフィールドを削除し、次のフィールドを返します。\"\n\n#: ../../page.rst:607 1f8e2118ea0f45548c869b582e9da683\nmsgid \"the widget to be deleted.\"\nmsgstr \"削除するウィジェット。\"\n\n#: ../../page.rst:610 ../../page.rst:1940 ../../page.rst:2264\n#: 79632ab9e049470dbe64dda2553e676e 81cdfe378ae74469b530973f279448bc\n#: 860a45b3a45b411da64f22bbf25a1576\nmsgid \":ref:`Widget`\"\nmsgstr \"\"\n\n#: ../../page.rst:611 0b787a1fc4ec42bda0b70222cd36d91c\nmsgid \"\"\n\"the widget following the deleted one. Please remember that physical \"\n\"removal requires saving to a new file with garbage > 0.\"\nmsgstr \"削除されたウィジェットの後に続くウィジェット。物理的な削除には、ガベージ> 0で新しいファイルに保存する必要があることを覚えておいてください。\"\n\n#: ../../page.rst:615 1b3c837eecb949b0bc0edd8df4124f3c\nmsgid \"(New in v1.18.4)\"\nmsgstr \"v1.18.4で変更\"\n\n#: ../../page.rst:622 c49122e36228451b838d9f1aa5efebc9\nmsgid \"\"\n\"PDF only: Delete the specified link from the page. The parameter must be \"\n\"an **original item** of :meth:`get_links()`, see \"\n\":ref:`link_dict_description`. The reason for this is the dictionary's \"\n\"*\\\"xref\\\"* key, which identifies the PDF object to be deleted.\"\nmsgstr \"\"\n\"PDFのみ：ページから指定したリンクを削除します。パラメータは :meth:`get_links()` \"\n\"の元のアイテムである必要があります（以下参照）。これは辞書の *「xref」* キーがPDFオブジェクトを識別するための理由です。\"\n\n#: ../../page.rst:624 922f58de7690440b8f4d3afd8f153fd3\nmsgid \"the link to be deleted.\"\nmsgstr \"削除するリンクです。\"\n\n#: ../../page.rst:628 50ac389b0cfe45568e5b6a1734037114\nmsgid \"\"\n\"PDF only: Insert a new link on this page. The parameter must be a \"\n\"dictionary of format as provided by :meth:`get_links()`, see \"\n\":ref:`link_dict_description`.\"\nmsgstr \"\"\n\"PDFのみ：このページに新しいリンクを挿入します。パラメータは :meth:`get_links()` \"\n\"で提供される形式の辞書である必要があります（以下参照）。\"\n\n#: ../../page.rst:630 e2e38196067748a485135b6e842933e0\nmsgid \"the link to be inserted.\"\nmsgstr \"挿入するリンクです。\"\n\n#: ../../page.rst:634 d59a62d84a804721930f49e18365d762\nmsgid \"\"\n\"PDF only: Modify the specified link. The parameter must be a (modified) \"\n\"**original item** of :meth:`get_links()`, see \"\n\":ref:`link_dict_description`. The reason for this is the dictionary's \"\n\"*\\\"xref\\\"* key, which identifies the PDF object to be changed.\"\nmsgstr \"\"\n\"PDFのみ：指定されたリンクを変更します。パラメータは :meth:`get_links()` （以下参照）の **元のアイテム** \"\n\"である必要があります（変更された場合）。これは辞書の *「xref」* キーがPDFオブジェクトを識別するための理由です。\"\n\n#: ../../page.rst:636 07822e8f830441a381c271aa8a1209a1\nmsgid \"the link to be modified.\"\nmsgstr \"変更するリンクです。\"\n\n#: ../../page.rst:638 0de77211c8ab4e39bc3a706653fbbe95\nmsgid \"\"\n\"If updating / inserting a URI link (`\\\"kind\\\": LINK_URI`), please make \"\n\"sure to start the value for the `\\\"uri\\\"` key with a disambiguating \"\n\"string like `\\\"http://\\\"`, `\\\"https://\\\"`, `\\\"file://\\\"`, `\\\"ftp://\\\"`, \"\n\"`\\\"mailto:\\\"`, etc. Otherwise -- depending on your browser or other \"\n\"\\\"consumer\\\" software -- unexpected default assumptions may lead to \"\n\"unwanted behaviours.\"\nmsgstr \"\"\n\"URIリンク（`\\\"kind\\\": LINK_URI`）を更新/挿入する場合は、\\\"uri\\\"キーの値を必ず \"\n\"`「http://」`、`「https://」`、`「file://」` \"\n\"、`「ftp://」`、「mailto：」などの区別可能な文字列で始めるようにしてください。そうしないと、ブラウザや他の「コンシューマ」ソフトウェアによって、予期しないデフォルトの仮定が不要な動作につながる可能性があります。\"\n\n#: ../../page.rst:643 69289bebf6b44c29b0292e6d9c0985ed\nmsgid \"PDF only: Return the label for the page.\"\nmsgstr \"PDFのみ：ページのラベルを返します。\"\n\n#: ../../page.rst:647 3eb1a4da448a4ad1aef74e4f8337c3d5\nmsgid \"the label string like \\\"vii\\\" for Roman numbering or \\\"\\\" if not defined.\"\nmsgstr \"ローマ数字の「vii」などのラベル文字列、または定義されていない場合は \\\"\\\"。\"\n\n#: ../../page.rst:651 ad9f6c2321eb41708816ca80d962a3da\nmsgid \"New in v1.18.6\"\nmsgstr \"v1.18.6で新規追加\"\n\n#: ../../page.rst:657 e2f26ba92210426f9f0957a589aa226e\nmsgid \"Retrieves **all** links of a page.\"\nmsgstr \"ページの **すべて** のリンクを取得します。\"\n\n#: ../../page.rst:660 dbe8d31972064e49852b68e14f0e731d\nmsgid \"\"\n\"A list of dictionaries. For a description of the dictionary entries, see \"\n\":ref:`link_dict_description`. Always use this or the :meth:`Page.links` \"\n\"method if you intend to make changes to the links of a page.\"\nmsgstr \"\"\n\"辞書のリスト。辞書エントリの説明については以下を参照してください。ページのリンクを変更する意図がある場合は、:meth:`Page.links` \"\n\"メソッドまたはこれを常に使用してください。\"\n\n#: ../../page.rst:664 982dbd008c68482ab6a205bec8a0536d\nmsgid \"\"\n\"Return a generator over the page's links. The results equal the entries \"\n\"of :meth:`Page.get_links`.\"\nmsgstr \"ページのリンクをイテレーターとして返します。結果は :meth:`Page.get_links` のエントリと同じです。\"\n\n#: ../../page.rst:666 c23f5985f84f45ce96f719ffbfc1180b\nmsgid \"\"\n\"a sequence of integers to down-select to one or more link kinds. Default \"\n\"is all links. Example: *kinds=(pymupdf.LINK_GOTO,)* will only return \"\n\"internal links.\"\nmsgstr \"\"\n\"1つ以上のリンク種別をダウン選択するための整数のシーケンス。デフォルトはすべてのリンクです。例：*kinds=(pymupdf.LINK_GOTO,)*\"\n\" は内部リンクのみを返します。\"\n\n#: ../../page.rst:669 933e377cd2a647b394396f8c8c657dc3\nmsgid \"an entry of :meth:`Page.get_links()` for each iteration.\"\nmsgstr \"各イテレーションごとの :meth:`Page.get_links()` のエントリ。\"\n\n#: ../../page.rst:673 ../../page.rst:698 ../../page.rst:713\n#: 2bcfe2f227934e13883dccdfd49bf552 522c66b3f0834a05b0d694a35a3d60c7\n#: 58c5a6638d064f8f9c81265ab468b76e\nmsgid \"New in v1.16.4\"\nmsgstr \"v1.16.4で新規追加\"\n\n#: ../../page.rst:679 9895c4a674ad4ee9bd390eb10d90b9f3\nmsgid \"Return a generator over the page's annotations.\"\nmsgstr \"ページの注釈をイテレーターとして返します。\"\n\n#: ../../page.rst:681 b187bf843be8421f8dddb40d6f9e9bc1\nmsgid \"\"\n\"a sequence of integers to down-select to one or more annotation types. \"\n\"Default is all annotations. Example: `types=(pymupdf.PDF_ANNOT_FREETEXT, \"\n\"pymupdf.PDF_ANNOT_TEXT)` will only return 'FreeText' and 'Text' \"\n\"annotations.\"\nmsgstr \"\"\n\"1つ以上の注釈タイプをダウン選択するための整数のシーケンス。デフォルトはすべての注釈です。例：`types=(pymupdf.PDF_ANNOT_FREETEXT,\"\n\" pymupdf.PDF_ANNOT_TEXT)` は「FreeText」および「Text」注釈のみを返します。\"\n\n#: ../../page.rst:684 af312b81213748debdaed085f717b02e\nmsgid \"\"\n\"an :ref:`Annot` for each iteration.  .. caution::      You **cannot \"\n\"safely update annotations** from within this generator. This is because \"\n\"most annotation updates require reloading the page via `page = \"\n\"doc.reload_page(page)`. To circumvent this restriction, make a list of \"\n\"annotations xref numbers first and then iterate over these numbers::\"\n\"        In [4]: xrefs = [annot.xref for annot in \"\n\"page.annots(types=[...])]       In [5]: for xref in xrefs:          ...:\"\n\"     annot = page.load_annot(xref)          ...:     annot.update()\"\n\"          ...:     page = doc.reload_page(page)       In [6]:\"\nmsgstr \"\"\n\n#: ../../page.rst:684 cbc5b2fa7395471cbd33de5cfadaf49a\nmsgid \"an :ref:`Annot` for each iteration.\"\nmsgstr \"各イテレーションごとの :ref:`Annot`。\"\n\n#: ../../page.rst:687 c2f668696d264c1b82fa9512ec3d67fe\nmsgid \"\"\n\"You **cannot safely update annotations** from within this generator. This\"\n\" is because most annotation updates require reloading the page via `page \"\n\"= doc.reload_page(page)`. To circumvent this restriction, make a list of \"\n\"annotations xref numbers first and then iterate over these numbers::\"\nmsgstr \"\"\n\"このジェネレータ内から **アノテーションを安全に更新することはできません**。これは、ほとんどの注釈の更新にはpage = \"\n\"doc.reload_page(page)を介してページを再読み込みする必要があるためです。この制限を回避するために、まず注釈のxref番号のリストを作成し、その後これらの番号を繰り返し処理します::\"\n\n#: ../../page.rst:704 cf4dc50262134d9b8991d68d2387fda1\nmsgid \"Return a generator over the page's form fields.\"\nmsgstr \"フォームフィールドのジェネレーターを返します。\"\n\n#: ../../page.rst:706 09b37fc07a8b4617ba3ab3e1ed7e81ee\nmsgid \"\"\n\"a sequence of integers to down-select to one or more widget types. \"\n\"Default is all form fields. Example: \"\n\"`types=(pymupdf.PDF_WIDGET_TYPE_TEXT,)` will only return 'Text' fields.\"\nmsgstr \"\"\n\"1つ以上のウィジェットタイプに選択を絞り込むための整数のシーケンス。デフォルトではすべてのフォームフィールドが対象です。例: \"\n\"`types=(pymupdf.PDF_WIDGET_TYPE_TEXT,)` を指定すると 'Text' フィールドのみが返されます。\"\n\n#: ../../page.rst:709 b4a6fd5ab9f74f1aa81ff011fd4473d4\nmsgid \"a :ref:`Widget` for each iteration.\"\nmsgstr \"各イテレーションでの :ref:`Widget`\"\n\n#: ../../page.rst:720 91c0b9169e9b478ab89cee70033f2b07\nmsgid \"\"\n\"PDF only: Write the text of one or more :ref:`Textwriter` objects to the \"\n\"page.\"\nmsgstr \"PDF のみ: 1つ以上の :ref:`Textwriter`  オブジェクトのテキストをページに書き込みます。\"\n\n#: ../../page.rst:722 a55443e916e2419994c89d95d80a0911\nmsgid \"\"\n\"where to place the text. If omitted, the rectangle union of the text \"\n\"writers is used.\"\nmsgstr \"テキストを配置する場所。省略した場合、テキストライターの矩形の合併が使用されます。\"\n\n#: ../../page.rst:723 cce444b656e64b60a81ce94494e38f3d\nmsgid \"\"\n\"a non-empty tuple / list of :ref:`TextWriter` objects or a single \"\n\":ref:`TextWriter`.\"\nmsgstr \"1つ以上の :ref:`TextWriter` オブジェクトのタプル/リスト、または単一の :ref:`TextWriter` です。\"\n\n#: ../../page.rst:724 d271cb55070d4f5487e21e1eacd3c751\nmsgid \"set transparency, overwrites resp. value in the text writers.\"\nmsgstr \"透明度を設定し、テキストライターの値を上書きします。\"\n\n#: ../../page.rst:725 3c29e8bef62342fea254c2dc367dd6c5\nmsgid \"set the text color, overwrites  resp. value in the text writers.\"\nmsgstr \"テキストの色を設定し、テキストライターの値を上書きします。\"\n\n#: ../../page.rst:726 c86c42e9bcd24d43869350b460d4d700\nmsgid \"put the text in foreground or background.\"\nmsgstr \"テキストを前景または背景に配置するかどうか。\"\n\n#: ../../page.rst:727 63b9bb95ed42482580a37bf19dbe45a5\nmsgid \"maintain the aspect ratio.\"\nmsgstr \"アスペクト比を保持するかどうか。\"\n\n#: ../../page.rst:728 9e0772c8aa0c408d881ef210c734cb28\nmsgid \"rotate the text by an arbitrary angle.\"\nmsgstr \"テキストを任意の角度で回転します。\"\n\n#: ../../page.rst:729 16cea029005545c49f87400b6e929e58\nmsgid \"the :data:`xref` of an :data:`OCG` or :data:`OCMD`. (New in v1.18.4)\"\nmsgstr \"*(v1.18.4 で新たに追加)* :data:`OCG` または :data:`OCMD` の :data:`xref`。\"\n\n#: ../../page.rst:731 674aebc5fc8e4803bf557ef50bf29172\nmsgid \"\"\n\"Parameters *overlay, keep_proportion, rotate* and *oc* have the same \"\n\"meaning as in :meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\"*overlay、keep_proportion、rotate、oc* パラメーターは :meth:`Page.show_pdf_page` \"\n\"と同じ意味を持ちます。\"\n\n#: ../../page.rst:735 efb00b02fde547eeb0b25bf6f23dcc15\nmsgid \"New in v1.16.18\"\nmsgstr \"v1.16.18 で追加された新機能です。\"\n\n#: ../../page.rst:759 ac14c88754ee44f99b0bec586cb0acda\n#, fuzzy\nmsgid \"\"\n\"PDF only: Insert text lines starting at :data:`point_like` ``point``. See\"\n\" :meth:`Shape.insert_text`.\"\nmsgstr \"\"\n\"PDFのみ: :data:`point_like` *point* からテキストを挿入します。:meth:`Shape.insert_text` \"\n\"を参照してください。\"\n\n#: ../../page.rst:763 ../../page.rst:792 ../../page.rst:896 ../../page.rst:921\n#: ../../page.rst:946 ../../page.rst:970 ../../page.rst:994 ../../page.rst:1019\n#: ../../page.rst:1043 ../../page.rst:1068 ../../page.rst:1092\n#: ../../page.rst:1117 ../../page.rst:1142 16f565fc3199438e95a9f991424f44b4\n#: 3eec8de7562c4ff5807b32eaada58d2d 3fc49e0d00de4149a91ed98db7b39d82\n#: 6885c68bc46a4bf5803fc9bb9d518db9 6edade0a885e4aa990ece4507b2ad4c0\n#: 919db5753717454db1b1e8ba55000ca4 935d13e1eb4f47bdbbf0d3b48d3afe77\n#: 981866858e6e4f62a147faf42cd4c8c5 a36b2ebbf9244ee0ac2a4140992d02c7\n#: e01505a51cf44ee98a13168527fcf25f f124938d669846f7b838a60573194e18\n#: f2425ff3386d4be590ef1711bc0182f5 f64299f68d4c4b01b12b2e5bccb7fb45\nmsgid \"Changed in v1.18.4\"\nmsgstr \"v1.18.4 で変更\"\n\n#: ../../page.rst:788 847e042eb216477ca6976051a061f859\nmsgid \"\"\n\"PDF only: Insert text into the specified :data:`rect_like` *rect*. See \"\n\":meth:`Shape.insert_textbox`.\"\nmsgstr \"\"\n\"PDF のみ：指定された :data:`rect_like` の *rect* \"\n\"にテキストを挿入します。:meth:`Shape.insert_textbox` を参照してください。\"\n\n#: ../../page.rst:810 6aba6ac9699e4252b53eb6f4ae4a7dcd\nmsgid \"\"\n\"**PDF only:** Insert text into the specified rectangle. The method has \"\n\"similarities with methods :meth:`Page.insert_textbox` and \"\n\":meth:`TextWriter.fill_textbox`, but is **much more powerful**. This is \"\n\"achieved by letting a :ref:`Story` object do all the required processing.\"\nmsgstr \"\"\n\"**PDFのみ:** 指定された矩形にテキストを挿入します。このメソッドは、:meth:`Page.insert_textbox` メソッドと \"\n\":meth:`TextWriter.fill_textbox` メソッドと類似していますが、はるかに強力です。これは、:ref:`Story` \"\n\"(ストーリー) オブジェクトに必要なすべての処理を行わせることで実現されます。\"\n\n#: ../../page.rst:812 ee10551fb26a4ec0b9db75ebbb21cf0b\n#, fuzzy\nmsgid \"\"\n\"Parameter ``text`` may be a string as in the other methods. But it will \"\n\"be **interpreted as HTML source** and may therefore also contain HTML \"\n\"language elements -- including styling. The `css` parameter may be used \"\n\"to pass in additional styling instructions.\"\nmsgstr \"\"\n\"パラメータ `text` は、他のメソッドと同様に文字列である場合があります。ただし、これは **HTMLソース** \"\n\"として解釈され、そのためスタイリングを含むHTML言語要素も含まれる可能性があります。`css` \"\n\"パラメータを使用して追加のスタイリング指示を渡すことができます。\"\n\n#: ../../page.rst:814 e3b6f6aa9ef74189af88441862202e6b\n#, fuzzy\nmsgid \"\"\n\"Automatic line breaks are generated at word boundaries. The \\\"soft \"\n\"hyphen\\\" character `\\\"&#173;\\\"` (or `&shy;`) can be used to cause \"\n\"hyphenation and thus may also cause line breaks. **Forced** line breaks \"\n\"however are only achievable via the HTML tag ``<br>`` - ``\\\\n`` is \"\n\"ignored and will be treated like a space.\"\nmsgstr \"\"\n\"自動的な改行は単語の境界で生成されます。 \\\"soft hyphen\\\" 文字 `\\\"&#173;\\\"`（または `&shy;` \"\n\"）を使用するとハイフネーションが引き起こされ、その結果改行も生じる場合があります。ただし、強制的な改行はHTMLタグ `<br>` - \"\n\"`\\\"\\\\\\\\n\\\"` を使用してのみ実現可能であり、\\\"\\n\"\n\"\\\"は無視され、空白と同じように扱われます。\"\n\n#: ../../page.rst:816 7db693f5847b4c808cdcf8245af57aac\nmsgid \"With this method the following can be achieved:\"\nmsgstr \"このメソッドでは、次のことが可能です。\"\n\n#: ../../page.rst:818 f3aed1a429bc4b0a87d9d8be413d7ec4\nmsgid \"\"\n\"Styling effects like bold, italic, text color, text alignment, font size \"\n\"or font switching.\"\nmsgstr \"太字、斜体、テキストの色、テキストの配置、フォントサイズ、またはフォントの切り替えなどのスタイル効果\"\n\n#: ../../page.rst:819 e0b541df39074db0a80a56cd57984e79\nmsgid \"\"\n\"The text may include arbitrary languages -- **including right-to-left** \"\n\"languages.\"\nmsgstr \"テキストには、**右から左に書かれる言語を含む** 任意の言語を含めることができます。\"\n\n#: ../../page.rst:820 d9d140639c804339ba9b3ea6f5fbc848\nmsgid \"\"\n\"Scripts like `Devanagari <https://en.wikipedia.org/wiki/Devanagari>`_ and\"\n\" several others in Asia have a highly complex system of ligatures, where \"\n\"two or more unicodes together yield one glyph. The Story uses the \"\n\"software package `HarfBuzz <https://harfbuzz.github.io/>`_ , to deal with\"\n\" these things and produce correct output.\"\nmsgstr \"\"\n\"`Devanagari <https://en.wikipedia.org/wiki/Devanagari>`_ \"\n\"やその他のアジアの文字など、2つ以上のUnicodeが一つのグリフに変換される複雑なリガチャーのあるスクリプトは、正しい出力を生成するためにソフトウェアパッケージ\"\n\" `HarfBuzz <https://harfbuzz.github.io/>`_ を使用しています。\"\n\n#: ../../page.rst:821 09c3f85d8cfa4925a966b311e81d4be2\nmsgid \"\"\n\"One can also **include images** via HTML tag `<img>` -- the Story will \"\n\"take care of the appropriate layout. This is an alternative option to \"\n\"insert images, compared to :meth:`Page.insert_image`.\"\nmsgstr \"\"\n\"画像はHTMLタグ `<img>` \"\n\"を介して含めることができ、Storyが適切なレイアウトを担当します。これは、:meth:`Page.insert_image` \"\n\"と比較した画像の挿入の代替オプションです。\"\n\n#: ../../page.rst:822 15709477c471444fb826b7246bc9303b\nmsgid \"\"\n\"HTML tables (tag `<table>`) may be included in the text and will be \"\n\"handled appropriately.\"\nmsgstr \"HTMLテーブル（  `<table>` タグ）をテキストに含めることができ、適切に処理されます。\"\n\n#: ../../page.rst:823 498e6ef15995416fb84b1883d5d92638\nmsgid \"Links are automatically generated when present.\"\nmsgstr \"リンクが存在する場合、自動的にリンクが生成されます。\"\n\n#: ../../page.rst:825 897b9824e00144589853950e0fc085d7\nmsgid \"If content does not fit in the rectangle, the developer has two choices:\"\nmsgstr \"もしコンテンツが長方形に収まらない場合、開発者には2つの選択肢があります。:\"\n\n#: ../../page.rst:827 a9594e868a9140d48ee407ab97e2458e\nmsgid \"\"\n\"**either** only be informed about this (and accept a no-op, just like \"\n\"with the other textbox insertion methods),\"\nmsgstr \"**それとも** 、このことについての情報のみを受け取り（他のテキストボックスの挿入メソッドと同様に、何も起こらないことを受け入れる）、\"\n\n#: ../../page.rst:828 c80278844b0f4a10aa7d6f6c3f44d861\nmsgid \"**or** (`scale_low=0` - the default) scale down the content until it fits.\"\nmsgstr \"**または** （ `scale_low=0` - デフォルト）コンテンツを収まるまで縮小します。\"\n\n#: ../../page.rst:830 9ae3b284474e4a8fa2f79faa63d3257f\nmsgid \"rectangle on page to receive the text.\"\nmsgstr \"テキストを配置する長方形の領域。\"\n\n#: ../../page.rst:831 2a0f0754bb6546f6a30c1c29ce8432c5\nmsgid \"\"\n\"the text to be written. Can contain a mixture of plain text and HTML tags\"\n\" with styling instructions. Alternatively, a :ref:`Story` object may be \"\n\"specified (in which case the internal Story generation step will be \"\n\"omitted). A Story must have been generated with all required styling and \"\n\"Archive information.\"\nmsgstr \"\"\n\"書き込むテキスト。スタイル指示を含むプレーンテキストとHTMLタグの混合物であることができます。代替として、 \"\n\":ref:`Story`（ストーリー）オブジェクトを指定することもできます（その場合、内部のストーリー生成ステップは省略されます）。必要なすべてのスタイリングとアーカイブ情報で生成されたストーリーを指定する必要があります。\"\n\n#: ../../page.rst:832 14181b61a0884be297ef3685294cdda4\n#, fuzzy\nmsgid \"\"\n\"optional string containing additional CSS instructions. This parameter is\"\n\" ignored if ``text`` is a Story.\"\nmsgstr \"（オプション）追加のCSS指示を含む文字列。`text` がストーリーの場合、このパラメータは無視されます。\"\n\n#: ../../page.rst:833 324740ae7018450e95548a711684a3c1\nmsgid \"\"\n\"if necessary, scale down the content until it fits in the target \"\n\"rectangle. This sets the down scaling limit. Default is 0, no limit. A \"\n\"value of 1 means no down-scaling permitted. A value of e.g. 0.2 means \"\n\"maximum down-scaling by 80%.\"\nmsgstr \"コンテンツがターゲットの長方形に収まるまで必要に応じてコンテンツのスケーリングを行います。これはダウンスケーリングの制限を設定します。デフォルトは0で、制限なしを意味します。値が1の場合、ダウンスケーリングは許可されません。たとえば、0.2の値は、最大で80％のダウンスケーリングを意味します。\"\n\n#: ../../page.rst:834 c292373f60e74b0a9e7acb742bfd00f9\n#, fuzzy\nmsgid \"\"\n\"an Archive object that points to locations where to find images or non-\"\n\"standard fonts. If ``text`` refers to images or non-standard fonts, this \"\n\"parameter is required. This parameter is ignored if ``text`` is a Story.\"\nmsgstr \"画像や非標準のフォントの場所を指すアーカイブオブジェクト。テキストが画像や非標準のフォントを参照する場合、このパラメータが必要です。テキストがストーリーの場合、このパラメータは無視されます\"\n\n#: ../../page.rst:835 e06bdf8120344edea5c871c8b734bed9\nmsgid \"\"\n\"one of the values 0, 90, 180, 270. Depending on this, text will be \"\n\"filled:  - 0: top-left to bottom-right. - 90: bottom-left to top-right. -\"\n\" 180: bottom-right to top-left. - 270: top-right to bottom-left.  .. \"\n\"image:: images/img-rotate.*\"\nmsgstr \"\"\n\n#: ../../page.rst:835 5d44f86e3d34408fae9c505f2eb51a22\nmsgid \"one of the values 0, 90, 180, 270. Depending on this, text will be filled:\"\nmsgstr \"0、90、180、270のいずれかの値。これに応じて、テキストが埋められます:\"\n\n#: ../../page.rst:837 9fd548225f8245c1bdd20ddef928329d\nmsgid \"0: top-left to bottom-right.\"\nmsgstr \"0：左上から右下に。\"\n\n#: ../../page.rst:838 793a65bf3a3545e49a9ab0e68d7e1080\nmsgid \"90: bottom-left to top-right.\"\nmsgstr \"90：左下から右上に。\"\n\n#: ../../page.rst:839 c66768a9d53b4dd28889d3dc2e47fb81\nmsgid \"180: bottom-right to top-left.\"\nmsgstr \"180：右下から左上に。\"\n\n#: ../../page.rst:840 0e3ecfcbddc244d3a80913c9e9cf9524\nmsgid \"270: top-right to bottom-left.\"\nmsgstr \"270：右上から左下に。\"\n\n#: ../../page.rst:844 2aaaebae93dd4932a8c2460350eb2887\nmsgid \"\"\n\"the xref of an :data:`OCG` / :data:`OCMD` or 0. Please refer to \"\n\":meth:`Page.show_pdf_page` for details.\"\nmsgstr \"\"\n\":data:`OCG` （オプションコンテンツグループ）/ :data:`OCMD` \"\n\"（オプションコンテンツメタデータ）のxrefまたは0。詳細については、 :meth:`Page.show_pdf_page` を参照してください。\"\n\n#: ../../page.rst:845 b604f2246e724e6b881b6c6f67f39527\nmsgid \"\"\n\"set the fill and stroke opacity of the content. Only values `0 <= opacity\"\n\" < 1` are considered.\"\nmsgstr \"コンテンツの塗りつぶしとストロークの不透明度を設定します。`0 <= opacity < 1` の値のみ考慮されます。\"\n\n#: ../../page.rst:846 219fcacb5f0346e0a24bdff2f9da09df\nmsgid \"\"\n\"put the text in front of other content. Please refer to \"\n\":meth:`Page.show_pdf_page` for details.\"\nmsgstr \"テキストを他のコンテンツの前に配置します。詳細については、:meth:`Page.show_pdf_page` を参照してください。\"\n\n#: ../../page.rst:848 2d7a34e664184e029228581824d74532\nmsgid \"\"\n\"A tuple of floats `(spare_height, scale)`.  - spare_height: The \"\n\"(positive) height of the remaining space in `rect` below the   text, or \"\n\"-1 if we failed to fit. - scale: The scaling required; `0 < scale <= 1`. \"\n\"Will be `scale_low`   if we failed to fit.\"\nmsgstr \"\"\n\n#: ../../page.rst:848 59f16a716d924e38b4bce004bff088e0\nmsgid \"A tuple of floats `(spare_height, scale)`.\"\nmsgstr \"浮動小数点数のタプル `(spare_height, scale)` です。\"\n\n#: ../../page.rst:850 9a5db1bacf1b48f4b4b2f4d206231059\nmsgid \"\"\n\"spare_height: The (positive) height of the remaining space in `rect` \"\n\"below the text, or -1 if we failed to fit.\"\nmsgstr \"\"\n\n#: ../../page.rst:852 a9b179217d2846d9a9518f6eac262918\nmsgid \"\"\n\"scale: The scaling required; `0 < scale <= 1`. Will be `scale_low` if we \"\n\"failed to fit.\"\nmsgstr \"\"\n\n#: ../../page.rst:855 65774661f353460199b1f64e1215ae23\nmsgid \"\"\n\"Please refer to examples in this section of the recipes: \"\n\":ref:`RecipesText_I_c`.\"\nmsgstr \"このレシピの例を参照してください：:ref:`RecipesText_I_c`。\"\n\n#: ../../page.rst:859 a5843434b81d490487977efeb5d8cb77\n#, fuzzy\nmsgid \"New in v1.26.5:\"\nmsgstr \"v1.16.5 で新機能。\"\n\n#: ../../page.rst:861 9207751e2f024fa8a44590fb3b9ebe6d\nmsgid \"do additional scaling to fit long words.\"\nmsgstr \"\"\n\n#: ../../page.rst:863 c4c760f58b134e3fbdab0bbb8f2a7379\nmsgid \"\"\n\"If we succeeded and scaled down, the returned `spare_height` is now \"\n\"generally positive instead of being fixed to zero, because the final \"\n\"rect's height is usually not an exact multiple of the font line height.\"\nmsgstr \"\"\n\n#: ../../page.rst:867 ad918ee3f341411ba0aa7c506a1f02ea\n#, fuzzy\nmsgid \"New in v1.23.8: rebased-only.\"\nmsgstr \"v1.21.0で新たに追加\"\n\n#: ../../page.rst:868 8a3a7377bf1a457fbf81074b185a2c90\n#, fuzzy\nmsgid \"New in v1.23.9: `opacity` parameter.\"\nmsgstr \"v1.19.1で変更：`sort` パラメータを追加\"\n\n#: ../../page.rst:873 af588c948d8f4d3f83c4677718197726\nmsgid \"**Drawing Methods**\"\nmsgstr \"**描画メソッド**\"\n\n#: ../../page.rst:892 49a6624229f44fe6ba71c7e9ca8d75ef\nmsgid \"\"\n\"PDF only: Draw a line from *p1* to *p2* (:data:`point_like` \\\\s). See \"\n\":meth:`Shape.draw_line`.\"\nmsgstr \"\"\n\"PDF のみ：*p1* から *p2* までの直線を描画します（:data:`point_like` \"\n\"\\\\s）。:meth:`Shape.draw_line` を参照してください。\"\n\n#: ../../page.rst:917 9b38905ad1dd4d0ead359e61852a1b54\nmsgid \"\"\n\"PDF only: Draw a zigzag line from *p1* to *p2* (:data:`point_like` \\\\s). \"\n\"See :meth:`Shape.draw_zigzag`.\"\nmsgstr \"\"\n\"PDF のみ：p1 から p2 までのジグザグ線を描画します（:data:`point_like` \"\n\"\\\\s）。:meth:`Shape.draw_zigzag` を参照してください。\"\n\n#: ../../page.rst:942 9c336220359d487c96ab2495463d04bf\nmsgid \"\"\n\"PDF only: Draw a squiggly (wavy, undulated) line from *p1* to *p2* \"\n\"(:data:`point_like` \\\\s). See :meth:`Shape.draw_squiggle`.\"\nmsgstr \"\"\n\"PDF のみ：*p1* から *p2* までの波線（うねり）を描画します（:data:`point_like` \"\n\"\\\\s）。:meth:`Shape.draw_squiggle` を参照してください。\"\n\n#: ../../page.rst:966 dda4c1acb3be44ea84511701f5e0e066\nmsgid \"\"\n\"PDF only: Draw a circle around *center* (:data:`point_like`) with a \"\n\"radius of *radius*. See :meth:`Shape.draw_circle`.\"\nmsgstr \"\"\n\"PDF のみ：*center* を中心に、半径 *radius* の円を描画します \"\n\":data:`point_like`。:meth:`Shape.draw_circle` を参照してください。\"\n\n#: ../../page.rst:990 2e0189701fa74750b9dacd5303fc0bd4\nmsgid \"\"\n\"PDF only: Draw an oval (ellipse) within the given :data:`rect_like` or \"\n\":data:`quad_like`. See :meth:`Shape.draw_oval`.\"\nmsgstr \"\"\n\"PDF のみ：指定された :data:`rect_like` または :data:`quad_like` \"\n\"内に楕円を描画します。:meth:`Shape.draw_oval` を参照してください。\"\n\n#: ../../page.rst:1015 5099c99eeaa644dbb974a50f3152aa30\nmsgid \"\"\n\"PDF only: Draw a circular sector, optionally connecting the arc to the \"\n\"circle's center (like a piece of pie). See :meth:`Shape.draw_sector`.\"\nmsgstr \"\"\n\"PDFのみ: \"\n\"円形セクターを描画し、オプションで円の中心とアークを接続します（パイの一部のように）。:meth:`Shape.draw_sector` \"\n\"を参照してください。\"\n\n#: ../../page.rst:1039 f3dd8d945074407c8054e936336973f1\nmsgid \"\"\n\"PDF only: Draw several connected lines defined by a sequence of \"\n\":data:`point_like` \\\\s. See :meth:`Shape.draw_polyline`.\"\nmsgstr \"\"\n\"PDFのみ: 一連の :data:`point_like` \\\\s \"\n\"ポイントによって定義された接続された複数のラインを描画します。:meth:`Shape.draw_polyline` を参照してください。\"\n\n#: ../../page.rst:1064 28ea8c05024f440bb036391514064d3d\nmsgid \"\"\n\"PDF only: Draw a cubic Bézier curve from *p1* to *p4* with the control \"\n\"points *p2* and *p3* (all are :data:`point_like` \\\\s). See \"\n\":meth:`Shape.draw_bezier`.\"\nmsgstr \"\"\n\"PDFのみ: 制御ポイント *p2* および *p3* を使用して、*p1* から *p4* \"\n\"へのキュービックベジエ曲線を描画します（すべてのポイントは :data:`point_like` \"\n\"です）。:meth:`Shape.draw_bezier` を参照してください。\"\n\n#: ../../page.rst:1088 157ccab0cc4d491a8bb08c506c20ee93\nmsgid \"\"\n\"PDF only: This is a special case of *draw_bezier()*. See \"\n\":meth:`Shape.draw_curve`.\"\nmsgstr \"PDFのみ: これは *draw_bezier()* の特別なケースです。:meth:`Shape.draw_curve` を参照してください。\"\n\n#: ../../page.rst:1113 b8490d3dba144147892f25e4d622068e\nmsgid \"PDF only: Draw a rectangle. See :meth:`Shape.draw_rect`.\"\nmsgstr \"PDFのみ: 四角形を描画します。:meth:`Shape.draw_rect` を参照してください。\"\n\n#: ../../page.rst:1118 a272604a8c1f470c9a130f447d1fdb3f\nmsgid \"Changed in v1.22.0: Added parameter *radius*.\"\nmsgstr \"v1.22.0で変更：パラメーター *radius* を追加しました。\"\n\n#: ../../page.rst:1138 73015a6ba1b54fef8169908a7281e136\nmsgid \"PDF only: Draw a quadrilateral. See :meth:`Shape.draw_quad`.\"\nmsgstr \"PDFのみ: 四辺形を描画します。:meth:`Shape.draw_quad` を参照してください。\"\n\n#: ../../page.rst:1156 09dfe16658184db3a8101d292d524018\nmsgid \"\"\n\"PDF only: Add a new font to be used by text output methods and return its\"\n\" :data:`xref`. If not already present in the file, the font definition \"\n\"will be added. Supported are the built-in :data:`Base14_Fonts` and the \"\n\"CJK fonts via **\\\"reserved\\\"** fontnames. Fonts can also be provided as a\"\n\" file path or a memory area containing the image of a font file.\"\nmsgstr \"\"\n\"PDFのみ: テキスト出力メソッドで使用する新しいフォントを追加し、その :data:`xref` \"\n\"を返します。ファイルにまだ存在しない場合、フォントの定義が追加されます。組み込みの :data:`Base14_Fonts` および CJK \"\n\"フォントがサポートされており、**「予約済み」** \"\n\"フォント名を介して使用できます。フォントはファイルパスまたはフォントファイルのイメージを含むメモリ領域として提供することもできます。\"\n\n#: ../../page.rst:1158 2a54c648d14d47758ff2034915e314ce\nmsgid \"\"\n\"The name by which this font shall be referenced when outputting text on \"\n\"this page. In general, you have a \\\"free\\\" choice here (but consult the \"\n\":ref:`AdobeManual`, page 16, section 7.3.5 for a formal description of \"\n\"building legal PDF names). However, if it matches one of the \"\n\":data:`Base14_Fonts` or one of the CJK fonts, *fontfile* and *fontbuffer*\"\n\" **are ignored**.  In other words, you cannot insert a font via \"\n\"*fontfile* / *fontbuffer* and also give it a reserved *fontname*.  .. \"\n\"note:: A reserved fontname can be specified in any mixture of upper or \"\n\"lower case and still match the right built-in font definition: fontnames \"\n\"\\\"helv\\\", \\\"Helv\\\", \\\"HELV\\\", \\\"Helvetica\\\", etc. all lead to the same \"\n\"font definition \\\"Helvetica\\\". But from a :ref:`Page` perspective, these \"\n\"are **different references**. You can exploit this fact when using \"\n\"different *encoding* variants (Latin, Greek, Cyrillic) of the same font \"\n\"on a page.\"\nmsgstr \"\"\n\n#: ../../page.rst:1158 f1417bd8c11d42f18da9e7cc192a9b54\nmsgid \"\"\n\"The name by which this font shall be referenced when outputting text on \"\n\"this page. In general, you have a \\\"free\\\" choice here (but consult the \"\n\":ref:`AdobeManual`, page 16, section 7.3.5 for a formal description of \"\n\"building legal PDF names). However, if it matches one of the \"\n\":data:`Base14_Fonts` or one of the CJK fonts, *fontfile* and *fontbuffer*\"\n\" **are ignored**.\"\nmsgstr \"\"\n\"このフォントをこのページ上でテキスト出力する際に参照される名前。 \"\n\"一般的に、ここで「自由な」選択ができます（ただし、:ref:`AdobeManual`、ページ16、セクション7.3.5を参照して正当なPDF名の形式的な説明を確認してください）。ただし、:data:`Base14_Fonts`\"\n\" またはCJKフォントのいずれかと一致する場合、*fontfile* および *fontbuffer* は **無視されます。**\"\n\n#: ../../page.rst:1160 b07885c01b7c4d2f98af200a61b2239f\nmsgid \"\"\n\"In other words, you cannot insert a font via *fontfile* / *fontbuffer* \"\n\"and also give it a reserved *fontname*.\"\nmsgstr \"言い換えれば、フォントを *fontfile* / *fontbuffer* 経由で挿入し、予約されたフォント名も指定することはできません。\"\n\n#: ../../page.rst:1162 6e3e5a1b1302490bbebb40eb041aa480\nmsgid \"\"\n\"A reserved fontname can be specified in any mixture of upper or lower \"\n\"case and still match the right built-in font definition: fontnames \"\n\"\\\"helv\\\", \\\"Helv\\\", \\\"HELV\\\", \\\"Helvetica\\\", etc. all lead to the same \"\n\"font definition \\\"Helvetica\\\". But from a :ref:`Page` perspective, these \"\n\"are **different references**. You can exploit this fact when using \"\n\"different *encoding* variants (Latin, Greek, Cyrillic) of the same font \"\n\"on a page.\"\nmsgstr \"\"\n\"予約されたフォント名は、大文字と小文字の組み合わせで指定でき、それでも適切な組み込みフォントの定義に一致します。フォント名「helv」、「Helv」、「HELV」、「Helvetica」などはすべて同じフォント定義「Helvetica」につながります。ただし、ページの観点からはこれらは\"\n\" **異なる参照** です。同じフォントの異なる *エンコーディング* \"\n\"バリアント（ラテン、ギリシャ、キリル文字など）をページ上で使用する場合、この事実を利用できます。\"\n\n#: ../../page.rst:1164 b329abbc6b5940dba48a2d1be997d3bd\nmsgid \"\"\n\"a path to a font file. If used, *fontname* must be **different from all \"\n\"reserved names**.\"\nmsgstr \"フォントファイルへのパス。使用する場合、*fontname* は **すべての予約済みの名前と異なる必要があります**。\"\n\n#: ../../page.rst:1166 298c716b43174038aeedbf20294a8600\nmsgid \"\"\n\"the memory image of a font file. If used, *fontname* must be **different \"\n\"from all reserved names**. This parameter would typically be used with \"\n\":attr:`Font.buffer` for fonts supported / available via :ref:`Font`.\"\nmsgstr \"\"\n\"フォントファイルのメモリイメージ。使用する場合、*fontname* は **すべての予約済みの名前と異なる** \"\n\"必要があります。通常、このパラメーターは :attr:`Font.buffer` を介してサポート/利用可能な :ref:`Font` \"\n\"に使用されます。\"\n\n#: ../../page.rst:1168 39ebae8797b04f77959ffa0509ce652e\nmsgid \"\"\n\"applicable for *fontfile* / *fontbuffer* cases only: enforce treatment as\"\n\" a \\\"simple\\\" font, i.e. one that only uses character codes up to 255.\"\nmsgstr \"\"\n\"*fontfile* / *fontbuffer* \"\n\"ケースにのみ適用可能：「シンプル」フォントとしての扱いを強制します。つまり、文字コードが255までしか使用しないフォントです。\"\n\n#: ../../page.rst:1170 447d0c124033428aa957f8b973050309\nmsgid \"\"\n\"applicable for the \\\"Helvetica\\\", \\\"Courier\\\" and \\\"Times\\\" sets of \"\n\":data:`Base14_Fonts` only. Select one of the available encodings Latin \"\n\"(0), Cyrillic (2) or Greek (1). Only use the default (0 = Latin) for \"\n\"\\\"Symbol\\\" and \\\"ZapfDingBats\\\".\"\nmsgstr \"\"\n\":data:`Base14_Fonts` \"\n\"の「Helvetica」、「Courier」、「Times」セットにのみ適用可能。利用可能なエンコーディングのうち、ラテン（0）、キリル文字（2）、ギリシャ文字（1）のいずれかを選択します。「Symbol」と「ZapfDingBats」についてはデフォルト（0\"\n\" = ラテン）のみを使用してください。\"\n\n#: ../../page.rst 55c9386c63724c5392c7040df4f8c387\nmsgid \"rytpe\"\nmsgstr \"\"\n\n#: ../../page.rst:1172 ../../page.rst:2186 ../../page.rst:2270\n#: ../../page.rst:2440 ../../page.rst:2447 2c6cefa6a7064fe39392c90935ff2122\n#: 676e80ae36ef403cb3222e23c7e6840b 7a9f38940fcc4070a1e1cc06aa5851eb\n#: 8c51842a55794d7cbd92e8622328da3d fe56946be4db4f028208db1bac0c8edd\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../page.rst:1173 1779ac4a712d4617bd783fabd20b84ee\nmsgid \"the :data:`xref` of the installed font.\"\nmsgstr \"インストールされたフォントの :data:`xref`。\"\n\n#: ../../page.rst:1175 f3eee244ef7e4992a7a6ffe42d5109ab\nmsgid \"\"\n\"Built-in fonts will not lead to the inclusion of a font file. So the \"\n\"resulting PDF file will remain small. However, your PDF viewer software \"\n\"is responsible for generating an appropriate appearance -- and there \"\n\"**exist** differences on whether or how each one of them does this. This \"\n\"is especially true for the CJK fonts. But also Symbol and ZapfDingbats \"\n\"are incorrectly handled in some cases. Following are the **Font Names** \"\n\"and their correspondingly installed **Base Font** names:\"\nmsgstr \"\"\n\"組み込みフォントはフォントファイルの追加を必要とせず、結果として生成されるPDFファイルは小さく保たれます。ただし、PDFビューアソフトウェアは適切な外観を生成する責任があり、それぞれがこれをどのように行うかには違い\"\n\" \"\n\"**があります**。これは特にCJKフォントに関して当てはまります。しかし、シンボルとZapfDingbatsも一部のケースで正しく扱われていないことがあります。以下は\"\n\" **Font Names** とそれに対応するインストールされた **Base Font** 名です：\"\n\n#: ../../page.rst:1177 0cc0406f7e4a492daeb1c4db6e780bb9\nmsgid \"**Base-14 Fonts** [#f1]_\"\nmsgstr \"**ベース14フォント** [1]\"\n\n#: ../../page.rst:1180 ../../page.rst:1201 4be11b26fad54b2bb9545b4f821120d8\n#: 5ba9280b3946433d8d5e7f1249a1c17a\nmsgid \"**Font Name**\"\nmsgstr \"**フォント名**\"\n\n#: ../../page.rst:1180 ../../page.rst:1201 eccfb3aa2983434c99d693447ff65632\n#: f469987f95914ac38d3567e772be2909\nmsgid \"**Installed Base Font**\"\nmsgstr \"**インストールされたベースフォント**\"\n\n#: ../../page.rst:1180 ../../page.rst:1201 0637ce2b61f94d70bfa5fd14cc3eba4e\n#: 779ba5a624ae4a31b519f88f420474a2\nmsgid \"**Comments**\"\nmsgstr \"**コメント**\"\n\n#: ../../page.rst:1182 1346d71024ce401593ebe1b1ef929f0b\nmsgid \"helv\"\nmsgstr \"\"\n\n#: ../../page.rst:1182 8472540636cb4b3e80d4a141f2dc9490\nmsgid \"Helvetica\"\nmsgstr \"\"\n\n#: ../../page.rst:1182 ../../page.rst:1186 ../../page.rst:1190\n#: 15bcf8de9a4c4b42bd4547caeca437a2 26e37e84ddb44e20b9537973739375c3\n#: 5c44fa7e15ec4ab29fb285d84ed09b05\nmsgid \"normal\"\nmsgstr \"通常\"\n\n#: ../../page.rst:1183 3fee6d1ad3694348bf8fcac4335b1b17\nmsgid \"heit\"\nmsgstr \"\"\n\n#: ../../page.rst:1183 87fa2f15152d45758b2638a2c65b0b80\nmsgid \"Helvetica-Oblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1183 ../../page.rst:1187 ../../page.rst:1191\n#: 465a0dc7d5d8412d84bb0971fdc0b959 ab575e9dd96549db97f540585a2a1401\n#: d09fc6af893444f8ab7b7f844d73072b\nmsgid \"italic\"\nmsgstr \"斜体\"\n\n#: ../../page.rst:1184 a90419279ba544bf97d046d85a18d8a6\nmsgid \"hebo\"\nmsgstr \"\"\n\n#: ../../page.rst:1184 940f9d62685d47d79d73ba75f785b854\nmsgid \"Helvetica-Bold\"\nmsgstr \"\"\n\n#: ../../page.rst:1184 ../../page.rst:1188 ../../page.rst:1192\n#: 04cf9160aab94c5ea9fe0faf40ad7adf 97e04d362f7242fd8c53039399b33811\n#: af07c4f6d96048b5a3bcb67c7533fee7\nmsgid \"bold\"\nmsgstr \"太字\"\n\n#: ../../page.rst:1185 fde6ad4e4bcf48a7bd1e80b3871d9b92\nmsgid \"hebi\"\nmsgstr \"\"\n\n#: ../../page.rst:1185 d81ace351e8e4bffab2c4c31676b09c7\nmsgid \"Helvetica-BoldOblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1185 ../../page.rst:1189 ../../page.rst:1193\n#: 5e8fbcd6618b45a0b30369755eb54917 85cf3978bda64f41904f681d9066700d\n#: a49dcd7211ec4174a9e39f18f4f20287\nmsgid \"bold-italic\"\nmsgstr \"太字斜体\"\n\n#: ../../page.rst:1186 eecbf522339f408682429018eb42d819\nmsgid \"cour\"\nmsgstr \"\"\n\n#: ../../page.rst:1186 1aabbf1917b940a884122759b6201772\nmsgid \"Courier\"\nmsgstr \"\"\n\n#: ../../page.rst:1187 2914ccf1d5474fb4a4171cd1fb40d000\nmsgid \"coit\"\nmsgstr \"\"\n\n#: ../../page.rst:1187 356dc6005a6f4ccb8872f1d0dc02b045\nmsgid \"Courier-Oblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1188 3146fa4f560442ab8fd3866e31f9f31d\nmsgid \"cobo\"\nmsgstr \"\"\n\n#: ../../page.rst:1188 b7317958a6a64ff7b299cfa08352c7e3\nmsgid \"Courier-Bold\"\nmsgstr \"\"\n\n#: ../../page.rst:1189 6314e10383d44543a4e6f83d8dfd36f5\nmsgid \"cobi\"\nmsgstr \"\"\n\n#: ../../page.rst:1189 edae3864abe74d9e9967f2f6616f58ac\nmsgid \"Courier-BoldOblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1190 8e463570936f44cea10cef6f53bfd751\nmsgid \"tiro\"\nmsgstr \"\"\n\n#: ../../page.rst:1190 174a7e61ef724680ae4975dda6e210db\nmsgid \"Times-Roman\"\nmsgstr \"\"\n\n#: ../../page.rst:1191 e10c734e894746798210ea22c0453c7f\nmsgid \"tiit\"\nmsgstr \"\"\n\n#: ../../page.rst:1191 181f9f5afcfe408e803a31614283f687\nmsgid \"Times-Italic\"\nmsgstr \"\"\n\n#: ../../page.rst:1192 e7fd292fdf5f46839550048a54d145c0\nmsgid \"tibo\"\nmsgstr \"\"\n\n#: ../../page.rst:1192 cff467ef11664e0786a2da8638aaf7e8\nmsgid \"Times-Bold\"\nmsgstr \"\"\n\n#: ../../page.rst:1193 feb7d3b171814377804d10433dd16286\nmsgid \"tibi\"\nmsgstr \"\"\n\n#: ../../page.rst:1193 88f60b707d244358b731b9cf46cdb6aa\nmsgid \"Times-BoldItalic\"\nmsgstr \"\"\n\n#: ../../page.rst:1194 c57996e01b024a07b7dcdd172113e66d\nmsgid \"symb\"\nmsgstr \"\"\n\n#: ../../page.rst:1194 4ae4d7c1cb9a4dd5943b5159d29bd4fa\nmsgid \"Symbol\"\nmsgstr \"\"\n\n#: ../../page.rst:1194 ../../page.rst:1195 82ed675d31704bb7915d0d6fa3d61608\n#: a2563ed5af004de389fd34f47716f55a\nmsgid \"[#f3]_\"\nmsgstr \"\"\n\n#: ../../page.rst:1195 699cea507d7a4aafaae0b57d2da6ff00\nmsgid \"zadb\"\nmsgstr \"\"\n\n#: ../../page.rst:1195 c9971b33bd8f4ad1934c43cdca551699\nmsgid \"ZapfDingbats\"\nmsgstr \"\"\n\n#: ../../page.rst:1198 ba64298625da4c61bff99a98efb06dda\nmsgid \"**CJK Fonts** [#f2]_ (China, Japan, Korea)\"\nmsgstr \"**CJKフォント** [2] (中国、日本、韓国)\"\n\n#: ../../page.rst:1203 f7a0ceef14004e83ae9d95c602fbdd52\nmsgid \"china-s\"\nmsgstr \"\"\n\n#: ../../page.rst:1203 fcfbc81bc11d4acc8149da6092052844\nmsgid \"Heiti\"\nmsgstr \"\"\n\n#: ../../page.rst:1203 1dd341e3f7214b41ab71ab4321f9eb68\nmsgid \"simplified Chinese\"\nmsgstr \"簡体字中国語\"\n\n#: ../../page.rst:1204 5dd5140d1ee74ac7b20d9f83860874d5\nmsgid \"china-ss\"\nmsgstr \"\"\n\n#: ../../page.rst:1204 93712db63e114dd28efb908d8da11df5\nmsgid \"Song\"\nmsgstr \"\"\n\n#: ../../page.rst:1204 bce8b6de318645aaa2cfe29f0acb8e8e\nmsgid \"simplified Chinese (serif)\"\nmsgstr \"簡体字中国語（セリフ）\"\n\n#: ../../page.rst:1205 f0cbfe83750e4adbb3aa02a97efe7e9b\nmsgid \"china-t\"\nmsgstr \"\"\n\n#: ../../page.rst:1205 69f469612d1b4fbc9c41f2757d500ffd\nmsgid \"Fangti\"\nmsgstr \"\"\n\n#: ../../page.rst:1205 c14b5f7d14aa44cba182604bf144df6f\nmsgid \"traditional Chinese\"\nmsgstr \"繁体字中国語\"\n\n#: ../../page.rst:1206 a11679c0768a4e98874b92f12f1d87eb\nmsgid \"china-ts\"\nmsgstr \"\"\n\n#: ../../page.rst:1206 5370162be60f43e98245542771de88a0\nmsgid \"Ming\"\nmsgstr \"\"\n\n#: ../../page.rst:1206 2a928b4cc6df4bfb80208379140e769c\nmsgid \"traditional Chinese (serif)\"\nmsgstr \"繁体字中国語（セリフ）\"\n\n#: ../../page.rst:1207 1b7f2377dd8f4f52b5ef57afe4eecde0\nmsgid \"japan\"\nmsgstr \"\"\n\n#: ../../page.rst:1207 e34fddfb59a04f2a9b71c94d81918412\nmsgid \"Gothic\"\nmsgstr \"\"\n\n#: ../../page.rst:1207 d5c5342d26fc4d6f96eb3997548c5851\nmsgid \"Japanese\"\nmsgstr \"\"\n\n#: ../../page.rst:1208 12165a7df13e4b5ab6e43c7e32125931\nmsgid \"japan-s\"\nmsgstr \"\"\n\n#: ../../page.rst:1208 0953d1d866774f409553c943377f12a3\nmsgid \"Mincho\"\nmsgstr \"\"\n\n#: ../../page.rst:1208 9572a32bd5394a0fb22a993d3da56f12\nmsgid \"Japanese (serif)\"\nmsgstr \"\"\n\n#: ../../page.rst:1209 b034ac397af24d97b54198b0dc1a0106\nmsgid \"korea\"\nmsgstr \"\"\n\n#: ../../page.rst:1209 77d9bd94bd424297ae8d55caede11d7d\nmsgid \"Dotum\"\nmsgstr \"\"\n\n#: ../../page.rst:1209 137787a942204c3d92736320affcc205\nmsgid \"Korean\"\nmsgstr \"\"\n\n#: ../../page.rst:1210 9a9d738dfda44b9aa58fb64b3124d6bc\nmsgid \"korea-s\"\nmsgstr \"\"\n\n#: ../../page.rst:1210 f4422a172efb456298f1cfe8feadd41f\nmsgid \"Batang\"\nmsgstr \"\"\n\n#: ../../page.rst:1210 44e44d3711ab4bc4b187b6a643352c2d\nmsgid \"Korean (serif)\"\nmsgstr \"\"\n\n#: ../../page.rst:1226 ebfe84984dbf44bba9f5d4cfd48dd7c5\nmsgid \"\"\n\"PDF only: Put an image inside the given rectangle. The image may already \"\n\"exist in the PDF or be taken from a pixmap, a file, or a memory area.\"\nmsgstr \"PDFのみ：指定された矩形内に画像を配置します。画像はすでにPDF内に存在するか、ピクスマップ、ファイル、またはメモリ領域から取得できます。\"\n\n#: ../../page.rst:1229 3aeff7f3684742f6808a7cb9c5d040e4\nmsgid \"where to put the image. Must be finite and not empty.\"\nmsgstr \"画像を配置する場所。有限で空でない必要があります。\"\n\n#: ../../page.rst:1230 d45e6802a1074852961e19a40ec99241\nmsgid \"deprecated and ignored.\"\nmsgstr \"非推奨であり、無視されます。\"\n\n#: ../../page.rst:1231 2fd482a63d504aba8d5a06556defeaca\nmsgid \"\"\n\"name of an image file (all formats supported by MuPDF -- see \"\n\":ref:`ImageFiles`).\"\nmsgstr \"画像ファイルの名前（MuPDFでサポートされているすべての形式 – :ref:`ImageFiles` を参照）。\"\n\n#: ../../page.rst:1235 c2cd820ab2964b5da51744d5043c6110\nmsgid \"maintain the aspect ratio of the image.\"\nmsgstr \"アスペクト比を保持するかどうか。\"\n\n#: ../../page.rst:1237 8a4ab9cc08dc417c839101fc59d154c2\nmsgid \"\"\n\"image in memory -- to be used as image mask (alpha values) for the base \"\n\"image. When specified, the base image must be provided as a filename or a\"\n\" stream -- and must not be an image that already has a mask.\"\nmsgstr \"\"\n\"メモリ内の画像 -- \"\n\"ベース画像のマスク（アルファ値）として使用されます。指定する場合、ベース画像はファイル名またはストリームとして提供する必要があります。また、既にマスクを持つ画像ではない必要があります。\"\n\n#: ../../page.rst:1241 5950e8c3d6b049b49b8b33f3b7d7e984\nmsgid \"\"\n\"(:data:`xref`) make image visibility dependent on this :data:`OCG` or \"\n\":data:`OCMD`. Ignored after the first of multiple insertions. The \"\n\"property is stored with the generated PDF image object and therefore \"\n\"controls the image's visibility throughout the PDF.\"\nmsgstr \"\"\n\"(:data:`xref`) この画像の表示をこの :data:`OCG` または :data:`OCMD` \"\n\"に依存させます。複数回の挿入の最初の後には無視されます。このプロパティは生成された PDF 画像オブジェクトに格納されるため、PDF \"\n\"全体で画像の表示を制御します。\"\n\n#: ../../page.rst:1246 ca9ec75c86ff49f1996ec1f71bd991f1\nmsgid \"see :ref:`CommonParms`.\"\nmsgstr \":ref:`CommonParms` を参照してください。\"\n\n#: ../../page.rst:1247 2101e44007764ff4b9fc70034e923f14\nmsgid \"a pixmap containing the image.\"\nmsgstr \"画像を含むピクスマップ。\"\n\n#: ../../page.rst:1248 1c37153fd1a84795bd7d52d410652dd2\nmsgid \"\"\n\"rotate the image. Must be an integer multiple of 90 degrees. Positive \"\n\"values rotate anti-clockwise. If you need a rotation by an arbitrary \"\n\"angle, consider converting the image to a PDF \"\n\"(:meth:`Document.convert_to_pdf`) first and then use \"\n\":meth:`Page.show_pdf_page` instead.\"\nmsgstr \"\"\n\"(v1.14.11で新機能)* \"\n\"画像を回転させます。90度の整数倍である必要があります。正の値は反時計回りに回転します。任意の角度での回転が必要な場合は、まず画像をPDFに変換（:meth:`Document.convert_to_pdf`）し、:meth:`Page.show_pdf_page`\"\n\" を使用することを検討してください。\"\n\n#: ../../page.rst:1255 d82f79d78a2149dea58350e93243aee9\nmsgid \"image in memory (all formats supported by MuPDF -- see :ref:`ImageFiles`).\"\nmsgstr \"メモリ内の画像（MuPDFでサポートされているすべての形式 – :ref:`ImageFiles` を参照）。\"\n\n#: ../../page.rst:1258 624aeee769f14067b962ec6c6772884c\nmsgid \"\"\n\"the :data:`xref` of an image already present in the PDF. If given, \"\n\"parameters `filename`, `pixmap`, `stream`, `alpha` and `mask` are \"\n\"ignored. The page will simply receive a reference to the existing image.\"\nmsgstr \"\"\n\"PDF内にすでに存在する画像の :data:`xref` 。指定された場合、 `filename` 、 `Pixmap` 、 `stream` 、\"\n\" `alpha` 、および `mask` パラメータは無視されます。ページは単純に既存の画像への参照を受け取ります。\"\n\n#: ../../page.rst:1266 256e69a0b35540ffa17700d11892d52a\nmsgid \"\"\n\"The `xref` of the embedded image. This can be used as the `xref` argument\"\n\" for very significant performance boosts, if the image is inserted again.\"\nmsgstr \"埋め込まれた画像の `xref` です。この値は、画像を再度挿入する場合のxref引数として使用でき、非常に大幅なパフォーマンス向上に役立ちます。\"\n\n#: ../../page.rst:1271 1710b1878d634eec899b7e937995dd29\nmsgid \"This example puts the same image on every page of a document::\"\nmsgstr \"この例では、ドキュメントのすべてのページに同じ画像を配置します：\"\n\n#: ../../page.rst:1286 d2f2977024734be187ee6c67296ceddc\nmsgid \"\"\n\"The method detects multiple insertions of the same image (like in the \"\n\"above example) and will store its data only on the first execution.  This\"\n\" is even true (although less performant), if using the default `xref=0`.\"\nmsgstr \"\"\n\"このメソッドは、同じ画像が複数回挿入される場合（上記の例のように）を検出し、データは最初の実行時にのみ保存されます。これは、デフォルトの \"\n\"`xref=0` を使用している場合でも（性能は劣るが）同様です\"\n\n#: ../../page.rst:1291 e09a9f96a77a45a3911b7156af831514\nmsgid \"\"\n\"The method cannot detect if the same image had already been part of the \"\n\"file before opening it.\"\nmsgstr \"このメソッドは、ファイルを開く前に同じ画像がすでにファイルの一部であるかどうかを検出できません。\"\n\n#: ../../page.rst:1295 0b1f424f05a748ab81ff1bafa6c48e60\nmsgid \"\"\n\"You can use this method to provide a background or foreground image for \"\n\"the page, like a copyright or a watermark. Please remember, that \"\n\"watermarks require a transparent image if put in foreground ...\"\nmsgstr \"このメソッドを使用して、ページの背景または前景画像（著作権表示や透かしのようなもの）を提供できます。ただし、前景に透明な画像が必要な場合は、そのことを覚えておいてください...\"\n\n#: ../../page.rst:1300 ec6d73c55b6f48e58dce7dddb6b9b885\nmsgid \"\"\n\"The image may be inserted uncompressed, e.g. if a `Pixmap` is used or if \"\n\"the image has an alpha channel. Therefore, consider using `deflate=True` \"\n\"when saving the file. In addition, there are ways to control the image \"\n\"size -- even if transparency comes into play. Have a look at \"\n\":ref:`RecipesImages_O`.\"\nmsgstr \"\"\n\"画像は非圧縮で挿入されることがあります。たとえば、``Pixmap`` \"\n\"を使用するか、画像にアルファチャンネルがある場合です。したがって、ファイルを保存する際には *deflate=True* \"\n\"を使用することを検討してください。また、透明性が関与する場合でも、画像サイズを効果的に制御する方法が存在します。ドキュメンテーションの \"\n\":ref:`RecipesImages_O` セクションをご覧ください。\"\n\n#: ../../page.rst:1307 26f522e4130a45c996856013f4248085\nmsgid \"\"\n\"The image is stored in the PDF at its original quality level. This may be\"\n\" much better than what you need for your display. Consider **decreasing \"\n\"the image size** before insertion -- e.g. by using the pixmap option and \"\n\"then shrinking it or scaling it down (see :ref:`Pixmap` chapter). The PIL\"\n\" method `Image.thumbnail()` can also be used for that purpose. The file \"\n\"size savings can be very significant.\"\nmsgstr \"\"\n\"画像はPDF内でその元の品質で保存されます。これは、ディスプレイに必要なものよりもはるかに優れている場合があります。挿入前に \"\n\"**画像サイズを減少させる** \"\n\"ことを検討してください。たとえば、Pixmapオプションを使用してから縮小または縮小することができます（:ref:`Pixmap` \"\n\"の章を参照）。PILメソッドの *Image.thumbnail()* \"\n\"もそのために使用できます。ファイルサイズの節約は非常に大きい場合があります。\"\n\n#: ../../page.rst:1316 7dd604efc17a470f8e83896eb438e817\nmsgid \"\"\n\"Another efficient way to display the same image on multiple pages is \"\n\"another method: :meth:`show_pdf_page`. Consult \"\n\":meth:`Document.convert_to_pdf` for how to obtain intermediary PDFs \"\n\"usable for that method.\"\nmsgstr \"同じ画像を複数のページで効率的に表示する別の方法は、別のメソッドです：:meth:`show_pdf_page`。そのメソッドで使用可能な中間のPDFを取得する方法については、:meth:`Document.convert_to_pdf`\"\n\n#: ../../page.rst:1323 007b8ec985c743b98a2526414fd73df2\nmsgid \"Changed in v1.14.1: By default, the image keeps its aspect ratio.\"\nmsgstr \"v1.14.1で変更：デフォルトでは、画像はアスペクト比を保持します\"\n\n#: ../../page.rst:1324 4452eaabf85e49498dd430de980d27e9\n#, fuzzy\nmsgid \"Changed in v1.14.11: Added args `keep_proportion`, `rotate`.\"\nmsgstr \"v1.19.1で変更：`sort` パラメータを追加\"\n\n#: ../../page.rst:1325 2ba03f5cc3b24b45b04e05c824efe689\nmsgid \"Changed in v1.14.13:\"\nmsgstr \"v1.14.17で変更されました\"\n\n#: ../../page.rst:1328 7b5b3391686e4574b4aac42a4d8ace9a\n#, fuzzy\nmsgid \"\"\n\"The image is now always placed **centered** in the rectangle, i.e. the \"\n\"centers of image and rectangle are equal.\"\nmsgstr \"v1.14.13で変更：画像は矩形の **中央に** 常に配置されます。つまり、画像と矩形の中心が等しいです。\"\n\n#: ../../page.rst:1330 ff7cb4876385436180fb0bf0bbb48d24\nmsgid \"Added support for `stream` as `io.BytesIO`.\"\nmsgstr \"\"\n\n#: ../../page.rst:1332 9cf81fa0283d4b9cb71320c19ac808f6\nmsgid \"\"\n\"Changed in v1.17.6: Insertion rectangle no longer needs to have a non-\"\n\"empty intersection with the page's :attr:`Page.cropbox` [#f5]_.\"\nmsgstr \"v1.17.6で変更：挿入矩形はもはやページの :attr:`Page.cropbox` [#f5]_ と非空の交差を持つ必要はありません。\"\n\n#: ../../page.rst:1335 bd6b8a78d7bc45058b5b8a9b6ec02558\n#, fuzzy\nmsgid \"Changed in v1.18.1: Added `mask` arg.\"\nmsgstr \"v1.19.1で変更：`sort` パラメータを追加\"\n\n#: ../../page.rst:1336 2c51ffb03126487db1b393ca77b62af8\n#, fuzzy\nmsgid \"Changed in v1.18.3: Added `oc` arg.\"\nmsgstr \"v1.19.1で変更：`sort` パラメータを追加\"\n\n#: ../../page.rst:1337 71b397af9ab44427bb4ab1ce54bdb69e\n#, fuzzy\nmsgid \"Changed in v1.18.13:\"\nmsgstr \"v1.18.17で変更\"\n\n#: ../../page.rst:1339 42bef278e6f241daa5aa1e58f8b0bd66\n#, fuzzy\nmsgid \"Allow providing the image as the xref of an existing one.\"\nmsgstr \"v1.18.13で変更：既存の画像のxrefとして画像を提供できるようになりました。\"\n\n#: ../../page.rst:1340 9ab36815831741359f4fd92d83098864\nmsgid \"Added `xref` arg.\"\nmsgstr \"\"\n\n#: ../../page.rst:1341 8cf02d8c00e0422f86c35c8edecd0bb3\n#, fuzzy\nmsgid \"Return `xref` of stored image.\"\nmsgstr \"画像の :data:`xref`。\"\n\n#: ../../page.rst:1343 0d480b48652b455db23c555469c7e152\n#, fuzzy\nmsgid \"Changed in v1.19.3: deprecate and ignore `alpha` arg.\"\nmsgstr \"*(v1.19.3で変更)* 非推奨。指定された場合、無視されます。\"\n\n#: ../../page.rst:1356 28427482b562417ea265e0fab0c58c39\nmsgid \"Replace the image at xref with another one.\"\nmsgstr \"xrefで指定された画像を別の画像で置き換えます。\"\n\n#: ../../page.rst:1358 ../../page.rst:1383 03972eac51224992b99445962cd73e00\n#: fb26544be9924f54b1ea2b7cf64b51e5\nmsgid \"the :data:`xref` of the image.\"\nmsgstr \"画像の :data:`xref`。\"\n\n#: ../../page.rst:1359 4bb1648156be4a2e8852a24a6299b9e6\nmsgid \"the filename of the new image.\"\nmsgstr \"新しい画像のファイル名。\"\n\n#: ../../page.rst:1360 419422370be4417db9baaab1ddfbbdb9\nmsgid \"the :ref:`Pixmap` of the new image.\"\nmsgstr \"新しい画像の :ref:`Pixmap`。\"\n\n#: ../../page.rst:1361 ebfa76c83d5f40aaa2fd584dad3aca99\nmsgid \"the memory area containing the new image.\"\nmsgstr \"新しい画像を含むメモリ領域。\"\n\n#: ../../page.rst:1363 b020ddbad3f24249901bb68283bb3d41\nmsgid \"\"\n\"Arguments `filename`, `pixmap`, `stream` have the same meaning as in \"\n\":meth:`Page.insert_image`, especially exactly one of these must be \"\n\"provided.\"\nmsgstr \"\"\n\"`filename`、`pixmap`、`stream` の引数は、特に :meth:`Page.insert_image` \"\n\"での意味と同じです。特に、これらのうちの1つだけを指定する必要があります。\"\n\n#: ../../page.rst:1365 7dcc679acb8646a2a981d441c0831067\nmsgid \"\"\n\"This is a **global replacement:** the new image will also be shown \"\n\"wherever the old one has been displayed throughout the file.\"\nmsgstr \"これは **グローバルな置換** です：新しい画像は、古い画像がファイル全体で表示されていた場所でも表示されます。\"\n\n#: ../../page.rst:1367 0d8c4f895bef4b01b332a9495dbed6f8\nmsgid \"\"\n\"This method mainly exists for technical purposes. Typical uses include \"\n\"replacing large images by smaller versions, like a lower resolution, \"\n\"graylevel instead of colored, etc., or changing transparency.\"\nmsgstr \"このメソッドは主に技術的な目的で存在しています。典型的な使用例には、大きな画像を解像度の低いバージョン、カラーではなくグレースケールなど、より小さなバージョンで置き換えることが含まれます。または透明度を変更することもあります。\"\n\n#: ../../page.rst:1371 ../../page.rst:1395 5e9c066911d24f75ae4f2ee7a54f420b\n#: 97f009de6f15443b920db61aeaad86da\nmsgid \"New in v1.21.0\"\nmsgstr \"v1.21.0で新たに追加\"\n\n#: ../../page.rst:1381 5368e85893144ec286056edbb95d01ce\nmsgid \"\"\n\"Delete the image at xref. This is slightly misleading: actually the image\"\n\" is being replaced with a small transparent :ref:`Pixmap` using above \"\n\":meth:`Page.replace_image`. The visible effect however is equivalent.\"\nmsgstr \"\"\n\"画像のxrefを削除します。これはわずかに誤解を招くかもしれませんが、実際には、画像は上記の :meth:`Page.replace_image`\"\n\" を使用して小さな透明な :ref:`Pixmap` で置き換えられます。しかし、視覚的な効果は同等です。\"\n\n#: ../../page.rst:1385 0831eb1b8bca4c61b2d3ebed9d550e5c\nmsgid \"\"\n\"This is a **global replacement:** the image will disappear wherever the \"\n\"old one has been displayed throughout the file.\"\nmsgstr \"これは **グローバルな置換です：** 新しい画像は、古い画像がファイル全体で表示されていた場所でも表示されなくなります。\"\n\n#: ../../page.rst:1387 c9ddf64d62404209971e52006fcb17e7\nmsgid \"\"\n\"If you inspect / extract a page's images by methods like \"\n\":meth:`Page.get_images`, :meth:`Page.get_image_info` or \"\n\":meth:`Page.get_text`, the replacing \\\"dummy\\\" image will be detected \"\n\"like so `(45, 47, 1, 1, 8, 'DeviceGray', '', 'Im1', 'FlateDecode')` and \"\n\"also seem to \\\"cover\\\" the same boundary box on the page.\"\nmsgstr \"\"\n\":meth:`Page.get_images`、:meth:`Page.get_image_info`、または \"\n\":meth:`Page.get_text` \"\n\"などのメソッドを使用してページの画像を調査/抽出する場合、置き換えられた「ダミー」画像は次のように検出されます`(45, 47, 1, 1, 8,\"\n\" 'DeviceGray', '', 'Im1', 'FlateDecode')` 、また同じ境界ボックスをページ上に「覆う」ように見えます。\"\n\n#: ../../page.rst:1418 bb880c0f368a4fbbbae89df8e178f2da\n#, fuzzy\nmsgid \"\"\n\"Retrieves the content of a page in a variety of formats. Depending on the\"\n\" ``flags`` value, this may include text, images and several other object \"\n\"types. The method is a wrapper for multiple :ref:`TextPage` methods by \"\n\"choosing the output option `opt` as follows:\"\nmsgstr \"\"\n\"さまざまな形式でページのコンテンツを取得します。出力オプション `opt` を選択することで、複数の :ref:`TextPage` \"\n\"メソッドのラッパーとなります。\"\n\n#: ../../page.rst:1420 b344fdd22cdc43d98962ff99de701878\n#, fuzzy\nmsgid \"\"\n\"\\\"text\\\" -- :meth:`TextPage.extractTEXT`, default. Always includes **text\"\n\" only.**\"\nmsgstr \"“text” – :meth:`TextPage.extractTEXT`、デフォルト\"\n\n#: ../../page.rst:1421 fbf6d08c721944dfac447c3a384d7bf5\nmsgid \"\"\n\"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS`. Includes text and **may** \"\n\"include image meta information.\"\nmsgstr \"\"\n\n#: ../../page.rst:1422 722959ebcd9149aea46db80c88a28f83\nmsgid \"\\\"words\\\" -- :meth:`TextPage.extractWORDS`. Always includes **text only.**\"\nmsgstr \"\"\n\n#: ../../page.rst:1423 bb571f32650b4f859aaed06999e59518\nmsgid \"\\\"html\\\" -- :meth:`TextPage.extractHTML`. May include text and images.\"\nmsgstr \"\"\n\n#: ../../page.rst:1424 30f45825dda040dcaadc3f958006270c\nmsgid \"\\\"xhtml\\\" -- :meth:`TextPage.extractXHTML`. May include text and images.\"\nmsgstr \"\"\n\n#: ../../page.rst:1425 e24d7f1a9bb84b0ba6e43afd1213577c\nmsgid \"\\\"xml\\\" -- :meth:`TextPage.extractXML`. Always includes **text only.**\"\nmsgstr \"\"\n\n#: ../../page.rst:1426 1cc75fbc16704d78b2f7f039de703b41\nmsgid \"\\\"dict\\\" -- :meth:`TextPage.extractDICT`. May include text and images.\"\nmsgstr \"\"\n\n#: ../../page.rst:1427 9f8b972db8ef4ed4af0377bd3d686f04\nmsgid \"\\\"json\\\" -- :meth:`TextPage.extractJSON`. May include text and images.\"\nmsgstr \"\"\n\n#: ../../page.rst:1428 939274b46b2742a0b2f06125cc6a7de8\nmsgid \"\"\n\"\\\"rawdict\\\" -- :meth:`TextPage.extractRAWDICT`. May include text and \"\n\"images.\"\nmsgstr \"\"\n\n#: ../../page.rst:1429 5cea2dd8403c40dba76071690ece94e8\nmsgid \"\"\n\"\\\"rawjson\\\" -- :meth:`TextPage.extractRAWJSON`. May include text and \"\n\"images.\"\nmsgstr \"\"\n\n#: ../../page.rst:1431 abfc7bb6441b49359a8be48ffb7d3299\n#, fuzzy\nmsgid \"\"\n\"A string indicating the requested format, one of the above. A mixture of \"\n\"upper and lower case is supported. If misspelled, option \\\"text\\\" is \"\n\"silently assumed.\"\nmsgstr \"要求される形式を示す文字列、上記のいずれか。大文字と小文字の組み合わせがサポートされています\"\n\n#: ../../page.rst:1433 00954f527a9d4159be3ea3fd320a5264\nmsgid \"\"\n\"restrict the extraction to this rectangle. If ``None`` (default), the \"\n\"visible part of the page is taken. Any content (text, images) that is \"\n\"**not fully contained** in ``clip`` will be completely omitted. To avoid \"\n\"clipping altogether use ``clip=pymupdf.INFINITE_RECT()``. Only then the \"\n\"extraction will contain all items. This parameter has **no effect** on \"\n\"options \\\"html\\\", \\\"xhtml\\\" and \\\"xml\\\".\"\nmsgstr \"\"\n\n#: ../../page.rst:1435 d00942229f724825a1985c7a3b498e48\nmsgid \"\"\n\"indicator bits to control whether to include images or how text should be\"\n\" handled with respect to white spaces and :data:`ligatures`. See \"\n\":ref:`TextPreserve` for available indicators and \"\n\":ref:`text_extraction_flags` for default settings. (New in v1.16.2)\"\nmsgstr \"\"\n\"画像を含めるか、テキストをどのように空白や :data:`ligatures` に対応させるかを制御するための指示ビット。 \"\n\"使用可能な指示ビットについては、 :ref:`TextPreserve`  を参照してください。 また、デフォルト設定については、 \"\n\":ref:`text_extraction_flags`  を参照してください。 (v1.16.2で新規追加)\"\n\n#: ../../page.rst:1437 ff767e74ef754fd0b761adce1c0755af\n#, fuzzy\nmsgid \"\"\n\"use a previously created :ref:`TextPage`. This reduces execution time \"\n\"**very significantly:** by more than 50% and up to 95%, depending on the \"\n\"extraction option. If specified, the 'flags' and 'clip' arguments are \"\n\"ignored, because they are textpage-only properties. If omitted, a new, \"\n\"temporary textpage will be created.\"\nmsgstr \"\"\n\"(v1.19.0で新たに追加) 事前に作成したTextPageを使用します。これにより、実行時間が **非常に大幅に** \"\n\"削減されます：抽出オプションに応じて50％以上、95％まで削減されます。指定した場合、 'flags' および 'clip' \"\n\"引数は無視されます。テキストページ専用のプロパティであるためです。省略した場合、新しい一時的なテキストページが作成されます。\"\n\n#: ../../page.rst:1439 0d379c1332d54af0b7fe997a2a196607\nmsgid \"\"\n\"sort the output by vertical, then horizontal coordinates. In many cases, \"\n\"this should suffice to generate a \\\"natural\\\" reading order. Has no \"\n\"effect on (X)HTML and XML. For options \\\"blocks\\\", \\\"dict\\\", \\\"json\\\", \"\n\"\\\"rawdict\\\", \\\"rawjson\\\", sorting happens by coordinates `(y1, x0)` of \"\n\"the respective block bbox. For options \\\"words\\\" and \\\"text\\\", the text \"\n\"lines are completely re-synthesized to follow the reading sequence and \"\n\"appearance in the document -- which even establishes the original layout \"\n\"to some extent.\"\nmsgstr \"\"\n\n#: ../../page.rst:1441 454f4d1a695349a5af19fe16e8ac850b\nmsgid \"\"\n\"use these characters as *additional* word separators with the \\\"words\\\" \"\n\"output option (ignored otherwise). By default, all white spaces \"\n\"(including non-breaking space `0xA0`) indicate start and end of a word. \"\n\"Now you can specify more characters causing this. For instance, the \"\n\"default will return `\\\"john.doe@outlook.com\\\"` as **one** word. If you \"\n\"specify `delimiters=\\\"@.\\\"` then the **four** words `\\\"john\\\"`, \"\n\"`\\\"doe\\\"`, `\\\"outlook\\\"`, `\\\"com\\\"` will be returned. Other possible uses\"\n\" include ignoring punctuation characters `delimiters=string.punctuation`.\"\n\" The \\\"word\\\" strings will not contain any delimiting character. (New in \"\n\"v1.23.5)\"\nmsgstr \"\"\n\"これらの文字を、追加の単語の区切りとして、\\\"words\\\" \"\n\"出力オプションで使用します（それ以外の場合は無視されます）。デフォルトでは、すべての空白（非改行スペース  `0xA0`  \"\n\"を含む）が単語の開始と終了を示します。これにより、さらにこれを引き起こす文字を指定できます。例えば、デフォルトでは \"\n\"\\\"john.doe@outlook.com\\\" は1つの単語として返されます。`delimiters=\\\"@.\\\"`  \"\n\"と指定すると、\\\"john\\\"、\\\"doe\\\"、\\\"outlook\\\"、\\\"com\\\" \"\n\"の4つの単語が返されます。その他の可能な用途には、句読点を無視するための `delimiters = string.punctuation` \"\n\"があります。\\\"word\\\" 文字列には、区切り文字は含まれません。 (v1.23.5で新たに追加)\"\n\n#: ../../page.rst:1443 1a1a305c24f342e6bf95c3f7d5abff5b\nmsgid \"*str, list, dict*\"\nmsgstr \"\"\n\n#: ../../page.rst:1444 b8027602fe4641e6baffd0342399c796\nmsgid \"\"\n\"The page's content as a string, a list or a dictionary. Refer to the \"\n\"corresponding :ref:`TextPage` method for details.\"\nmsgstr \"ページの内容を表す文字列、リスト、または辞書。詳細については対応するTextPageメソッドを参照してください。\"\n\n#: ../../page.rst:1448 f6258a84615d4051a4bdeefcbb6ae5c8\nmsgid \"\"\n\"You can use this method as a **document conversion tool** from :ref:`any \"\n\"supported document type<Supported_File_Types>` to one of TEXT, HTML, \"\n\"XHTML or XML documents.\"\nmsgstr \"\"\n\"このメソッドを、:ref:`any supported document type<Supported_File_Types>` \"\n\"からTEXT、HTML、XHTML、またはXMLドキュメントのいずれかに変換する **ドキュメント変換ツール** として使用できます。\"\n\n#: ../../page.rst:1449 d67d562f042b43baaec86719b9be1cc3\nmsgid \"\"\n\"The inclusion of text via the *clip* parameter is decided on a by-\"\n\"character level: a character becomes part of the output, if its bbox is \"\n\"contained in `clip`. This **deviates** from the algorithm used in \"\n\"redaction annotations: a character will be **removed if its bbox \"\n\"intersects** any redaction annotation.\"\nmsgstr \"\"\n\n#: ../../page.rst:1453 02b0706b377a4a2c8542b9912375c6fb\nmsgid \"Changed in v1.19.0: added `textpage` parameter\"\nmsgstr \"v1.19.0で変更：`textpage` パラメータを追加\"\n\n#: ../../page.rst:1454 6262160ff433484da974bfec2f1d6455\nmsgid \"Changed in v1.19.1: added `sort` parameter\"\nmsgstr \"v1.19.1で変更：`sort` パラメータを追加\"\n\n#: ../../page.rst:1455 7d8a0f75db5141718c58f57c8ea61339\nmsgid \"\"\n\"Changed in v1.19.6: added new constants for defining default flags per \"\n\"method.\"\nmsgstr \"v1.19.6で変更：各メソッドごとのデフォルトフラグを定義するための新しい定数を追加\"\n\n#: ../../page.rst:1456 b540829e88b44088ab6080ee39781162\n#, fuzzy\nmsgid \"Changed in v1.23.5: added `delimiters` parameter\"\nmsgstr \"v1.19.1で変更：`sort` パラメータを追加\"\n\n#: ../../page.rst:1457 f21302e5b5fc433d9eafad550a0c3bf3\nmsgid \"\"\n\"Changed in v1.24.11: changed the effect of `sort_True` for \\\"text\\\" and \"\n\"\\\"words\\\" to closely follow natural reading sequence.\"\nmsgstr \"\"\n\n#: ../../page.rst:1467 f72917c9df2643619cd122f9937e01b7\nmsgid \"Retrieve the text contained in a rectangle.\"\nmsgstr \"指定された矩形に含まれるテキストを取得します。\"\n\n#: ../../page.rst:1469 d29b943fb6264892af9f65f8294d080f\nmsgid \"rect-like.\"\nmsgstr \"矩形のようなもの。\"\n\n#: ../../page.rst:1470 edd1211e0b82476bb7b10d17c964ea49\nmsgid \"\"\n\"a :ref:`TextPage` to use. If omitted, a new, temporary textpage will be \"\n\"created.\"\nmsgstr \"使用する :ref:`TextPage`。省略した場合、新しい一時的なテキストページが作成されます。\"\n\n#: ../../page.rst:1472 f969b8fc7f7c48728eeddb42868ce8ea\n#, fuzzy\nmsgid \"\"\n\"a string with interspersed linebreaks where necessary. It is based on \"\n\"dedicated code (changed in v1.19.0). A typical use is checking the result\"\n\" of :meth:`Page.search_for`:  >>> rl = page.search_for(\\\"currency:\\\") >>>\"\n\" page.get_textbox(rl[0]) 'Currency:' >>>\"\nmsgstr \"\"\n\"必要に応じて改行が挿入された文字列。v1.19.0 で変更: \"\n\"それは専用のコードに基づいています。典型的な使用例は、:meth:`Page.search_for` の結果をチェックすることです\"\n\n#: ../../page.rst:1472 912cee7436a643138c8c1b4f9b301dae\nmsgid \"\"\n\"a string with interspersed linebreaks where necessary. It is based on \"\n\"dedicated code (changed in v1.19.0). A typical use is checking the result\"\n\" of :meth:`Page.search_for`:\"\nmsgstr \"\"\n\"必要に応じて改行が挿入された文字列。v1.19.0 で変更: \"\n\"それは専用のコードに基づいています。典型的な使用例は、:meth:`Page.search_for` の結果をチェックすることです\"\n\n#: ../../page.rst:1481 6de0c6ee1c03469881ba013d692e5e35\nmsgid \"New in v1.17.7\"\nmsgstr \"新機能 v1.17.7\"\n\n#: ../../page.rst:1482 e4935dced8b94aca9efb4afba263a7fb\nmsgid \"Changed in v1.19.0: add `textpage` parameter\"\nmsgstr \"v1.19.0 で変更: `textpage`  パラメータを追加\"\n\n#: ../../page.rst:1493 7a18efd3d4754d2684bd23bccf41f0ff\nmsgid \"Create a :ref:`TextPage` for the page.\"\nmsgstr \"ページ用の :ref:`TextPage` を作成します\"\n\n#: ../../page.rst:1495 51e00198f9d646eab27c192b9aea744f\nmsgid \"\"\n\"indicator bits controlling the content available for subsequent text \"\n\"extractions and searches -- see the parameter of :meth:`Page.get_text`.\"\nmsgstr \"後続のテキスト抽出と検索で使用可能なコンテンツを制御する指示ビット – :meth:`Page.get_text` のパラメータを参照してください。\"\n\n#: ../../page.rst:1497 5572906e140e44ecb06655f487590e67\nmsgid \"restrict extracted text to this area. (New in v1.17.7)\"\nmsgstr \"*(v1.17.7 で新機能)* 抽出されたテキストをこの領域に制限します。\"\n\n#: ../../page.rst:1499 ed4c7fe483e04e7fa6ef285ed0aabfaa\nmsgid \":ref:`TextPage`\"\nmsgstr \"\"\n\n#: ../../page.rst:1503 53211b14972c45ce95fed701a955ce76\nmsgid \"New in v1.16.5\"\nmsgstr \"v1.16.5 で新機能。\"\n\n#: ../../page.rst:1504 776bf515596945789a57848499b6c4f3\nmsgid \"Changed in v1.17.7: introduced `clip` parameter.\"\nmsgstr \"v1.17.7 で変更: `clip` パラメータが導入されました。\"\n\n#: ../../page.rst:1518 c4dd0ac2f6c749dc86e9c9f46bc04ab4\nmsgid \"\"\n\"**Optical Character Recognition** (**OCR**) technology can be used to \"\n\"extract text data for documents where text is in a raster image format \"\n\"throughout the page. Use this method to **OCR** a page for text \"\n\"extraction.\"\nmsgstr \"\"\n\"**光学式文字認識** （ **OCR**   \"\n\"）技術は、ページ全体でテキストがラスター画像形式であるドキュメントからテキストデータを抽出するために使用できます。このメソッドを使用して、テキストの抽出のためにページを\"\n\" **OCR** します。\"\n\n#: ../../page.rst:1520 b9a82917607b4e6cb945f63162446435\nmsgid \"\"\n\"This method returns a :ref:`TextPage` for the page that includes OCRed \"\n\"text. MuPDF will invoke Tesseract-OCR if this method is used. Otherwise \"\n\"this is a normal :ref:`TextPage` object.\"\nmsgstr \"\"\n\"OCRed テキストを含むページの :ref:`TextPage` を作成します。このメソッドを使用すると、MuPDF は Tesseract-\"\n\"OCR を呼び出します。それ以外の場合、これは通常の :ref:`TextPage` オブジェクトです。\"\n\n#: ../../page.rst:1522 0f72332f2d0b4578b4f0dee4584618de\nmsgid \"\"\n\"indicator bits controlling the content available for subsequent test \"\n\"extractions and searches -- see the parameter of :meth:`Page.get_text`.\"\nmsgstr \"後続のテキスト抽出と検索に使用可能なコンテンツを制御する指示ビット – :meth:`Page.get_text` のパラメータを参照してください。\"\n\n#: ../../page.rst:1523 660122e729864444930eca6c6058d543\nmsgid \"\"\n\"the expected language(s). Use \\\"+\\\"-separated values if multiple \"\n\"languages are expected, \\\"eng+spa\\\" for English and Spanish.\"\nmsgstr \"期待される言語。複数の言語が期待される場合は \\\"+\\\" で区切って指定します。たとえば英語とスペイン語の場合は \\\"eng+spa\\\" です。\"\n\n#: ../../page.rst:1524 8e2055a7b98241ab8f2b99472fcd2b36\nmsgid \"\"\n\"the desired resolution in dots per inch. Influences recognition quality \"\n\"(and execution time).\"\nmsgstr \"インチ当たりのドット数で指定された解像度。認識品質（および実行時間）に影響を与えます。\"\n\n#: ../../page.rst:1525 1bbb094f99c7482692d9722355ab839f\nmsgid \"whether to OCR the full page, or just the displayed images.\"\nmsgstr \"ページ全体を OCR するか、表示された画像のみを OCR するかを指定します。\"\n\n#: ../../page.rst:1526 a86b4db13a9647eabfbe9a9ea7764250\nmsgid \"\"\n\"The name of Tesseract's language support folder `tessdata`. If omitted, \"\n\"this information must be present as environment variable \"\n\"`TESSDATA_PREFIX`. Can be determined by function :meth:`get_tessdata`.\"\nmsgstr \"\"\n\"Tesseract の言語サポートフォルダ `tessdata` の名前。省略した場合、この情報は環境変数 `TESSDATA_PREFIX` \"\n\"として存在している必要があります。tessdata を取得する関数 :meth:`get_tessdata` によって決定できます。\"\n\n#: ../../page.rst:1528 e2b38a41773d450b9d7fcba677c1cec3\nmsgid \"\"\n\"This method does **not** support a clip parameter -- OCR will always \"\n\"happen for the complete page rectangle.\"\nmsgstr \"このメソッドは clip パラメータをサポート **していない** ため、OCR は常に完全なページ矩形に対して行われます\"\n\n#: ../../page.rst:1530 67507d94eba94ed08e5eb43692679739\nmsgid \"\"\n\"a :ref:`TextPage`. Execution may be significantly longer than \"\n\":meth:`Page.get_textpage`.  For a full page OCR, **all text** will have \"\n\"the font \\\"GlyphlessFont\\\" from Tesseract. In case of partial OCR, normal\"\n\" text will keep its properties, and only text coming from images will \"\n\"have the GlyphlessFont.  .. note::     **OCRed text is only available** \"\n\"to PyMuPDF's text extractions and searches if their `textpage` parameter \"\n\"specifies the output of this method.     `This Jupyter notebook \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/jupyter-\"\n\"notebooks/partial-ocr.ipynb>`_ walks through an example for using OCR \"\n\"textpages.\"\nmsgstr \"\"\n\n#: ../../page.rst:1532 cf2a7760cfb443baa47a4bc69a183a10\nmsgid \"\"\n\"a :ref:`TextPage`. Execution may be significantly longer than \"\n\":meth:`Page.get_textpage`.\"\nmsgstr \":ref:`TextPage`。実行時間は :meth:`Page.get_textpage` よりも大幅に長くなる場合があります。\"\n\n#: ../../page.rst:1534 59281044c1694fa8bc05052dde8a8b61\nmsgid \"\"\n\"For a full page OCR, **all text** will have the font \\\"GlyphlessFont\\\" \"\n\"from Tesseract. In case of partial OCR, normal text will keep its \"\n\"properties, and only text coming from images will have the GlyphlessFont.\"\nmsgstr \"\"\n\"フルページの OCR の場合、**すべてのテキスト** は Tesseract の \\\"GlyphlessFont\\\" になります。部分的な \"\n\"OCR の場合、通常のテキストはそのプロパティを保持し、画像から来たテキストのみが GlyphlessFont になります。\"\n\n#: ../../page.rst:1538 25c757f4eee247258f1ede687682f046\nmsgid \"\"\n\"**OCRed text is only available** to PyMuPDF's text extractions and \"\n\"searches if their `textpage` parameter specifies the output of this \"\n\"method.\"\nmsgstr \"\"\n\"OCRed textは、PyMuPDFのテキスト抽出と検索でのみ利用可能であり、その `TextPage` \"\n\"パラメータがこのメソッドの出力を指定している場合にのみ利用できます。\"\n\n#: ../../page.rst:1540 c435c939d0844f6a8b12eeb8cb97a60b\n#, fuzzy\nmsgid \"\"\n\"`This Jupyter notebook <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/jupyter-notebooks/partial-ocr.ipynb>`_ walks \"\n\"through an example for using OCR textpages.\"\nmsgstr \"\"\n\"`このJupyter <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master\"\n\"/jupyter-notebooks/partial-ocr.ipynb>`_ ノートブックは、OCRテキストページを使用する例を説明します。\"\n\n#: ../../page.rst:1544 82a1337f759a45e69b8059ba07c5f9ec\nmsgid \"New in v.1.19.0\"\nmsgstr \"v1.19.0 で新機能\"\n\n#: ../../page.rst:1545 ef149d6f0f034e2cabfcfa52f76ef29b\nmsgid \"Changed in v1.19.1: support full and partial OCRing a page.\"\nmsgstr \"v1.19.1 で変更: ページのフルと部分的な OCR をサポート\"\n\n#: ../../page.rst:1552 f8e43b5512004252930e9ec3cb8121e3\nmsgid \"\"\n\"Return the vector graphics of the page. These are instructions which draw\"\n\" lines, rectangles, quadruples or curves, including properties like \"\n\"colors, transparency, line width and dashing, etc. Alternative terms are \"\n\"\\\"line art\\\" and \\\"drawings\\\".\"\nmsgstr \"ページのベクトルグラフィックスを返します。これらは線、四角形、四角形または曲線を描画するための命令で、色、透明度、線の幅、点線などのプロパティを含みます。代替用語は「ラインアート」と「ドローイング」です。\"\n\n#: ../../page.rst:1554 869b1f3970494e6d891c51443fe53cb5\nmsgid \"\"\n\"a list of dictionaries. Each dictionary item contains one or more single \"\n\"draw commands belonging together: they have the same properties (colors, \"\n\"dashing, etc.). This is called a **\\\"path\\\"** in PDF, so we adopted that \"\n\"name here, but the method **works for all document types**.\"\nmsgstr \"\"\n\"辞書のリスト。各辞書アイテムには、同じプロパティ（色、破線など）を持つ1つ以上の単一の描画コマンドが含まれます。これらはPDFでは \"\n\"**\\\"path\\\"** と呼ばれ、ここではその名前を採用していますが、このメソッドは **すべてのドキュメントタイプに対して機能します**。\"\n\n#: ../../page.rst:1556 f3e8e14810b346db9e0d9daf21785bd0\nmsgid \"\"\n\"The path dictionary for fill, stroke and fill-stroke paths has been \"\n\"designed to be compatible with class :ref:`Shape`. There are the \"\n\"following keys:\"\nmsgstr \"\"\n\"fill、stroke、fill-strokeパスのパス辞書は、:ref:`Shape` \"\n\"クラスと互換性があるように設計されています。次のキーがあります：\"\n\n#: ../../page.rst:1559 ../../page.rst:1624 ../../page.rst:1639\n#: 67ad4d2045064408a1ba01ed1133b577 684b63cfdbba471590c8920f29d9f8f7\n#: 841c49d1b9c3471fbd4b6331bd834c2d\nmsgid \"Key\"\nmsgstr \"キー\"\n\n#: ../../page.rst:1559 ../../page.rst:1624 ../../page.rst:1639\n#: 53eafcdffbbb462692a32a21d65807cb b73ebbf5174947a7b65775975c268fef\n#: e6a75d84f7894a54b059143c3eb6d496\nmsgid \"Value\"\nmsgstr \"値\"\n\n#: ../../page.rst:1561 ../../page.rst:1626 1cd5ef8dbb2a41cab7389e8a152a5f80\n#: dba13b652f364711bedc84bf0829f6b0\nmsgid \"closePath\"\nmsgstr \"\"\n\n#: ../../page.rst:1561 ../../page.rst:1568 17de4ae5744f46daa1814aa43c42758f\n#: 8a0b75118dfd46d1a51e9b65a3de4a58\nmsgid \"Same as the parameter in :ref:`Shape`.\"\nmsgstr \":ref:`Shape` のパラメーターと同じです。\"\n\n#: ../../page.rst:1562 e7b3e55be02b4642bd39a31728cf6bfc\nmsgid \"color\"\nmsgstr \"\"\n\n#: ../../page.rst:1562 1f9691afbd1947d59d6a9c1931f7114a\nmsgid \"Stroke color (see :ref:`Shape`).\"\nmsgstr \"ストロークカラー（:ref:`Shape` を参照）。\"\n\n#: ../../page.rst:1563 a41f8ac8ad3c456c94b7b376478779c4\nmsgid \"dashes\"\nmsgstr \"\"\n\n#: ../../page.rst:1563 75fe6e50f5354e64a476154321cf2884\nmsgid \"Dashed line specification (see :ref:`Shape`).\"\nmsgstr \"破線の仕様（:ref:`Shape` を参照）。\"\n\n#: ../../page.rst:1564 ../../page.rst:1627 6893e5608b214e1f8f7e27b226873876\n#: b0d4725240454e9fadaba4f5c5c850ed\nmsgid \"even_odd\"\nmsgstr \"\"\n\n#: ../../page.rst:1564 dc9d1115e0404dcbb68abe6eb77a8b35\nmsgid \"Fill colors of area overlaps -- same as the parameter in :ref:`Shape`.\"\nmsgstr \"領域のオーバーラップの塗りつぶし色（:ref:`Shape` を参照）。\"\n\n#: ../../page.rst:1565 26b27fdfbe5a46b8b0b8281a09a482b2\nmsgid \"fill\"\nmsgstr \"\"\n\n#: ../../page.rst:1565 fd5b317c225545fbb8250da001708803\nmsgid \"Fill color  (see :ref:`Shape`).\"\nmsgstr \"塗りつぶしカラー（:ref:`Shape` を参照）。\"\n\n#: ../../page.rst:1566 ../../page.rst:1628 35545459a9b744d0a23e37a9aef542d4\n#: cb4b82247f4d424fa9f883be7d91afd4\nmsgid \"items\"\nmsgstr \"\"\n\n#: ../../page.rst:1566 493c8c2dec8f4027bdb28b760e666c1b\nmsgid \"List of draw commands: lines, rectangles, quads or curves.\"\nmsgstr \"描画コマンド（直線、四角形、四角形、曲線など）のリスト。\"\n\n#: ../../page.rst:1567 37210e119ca1451290adf2a89f269cb2\nmsgid \"lineCap\"\nmsgstr \"\"\n\n#: ../../page.rst:1567 a2626ee2b3a74e1fb776f90793e227c5\nmsgid \"Number 3-tuple, use its max value on output with :ref:`Shape`.\"\nmsgstr \"3つの数値からなるタプル。出力時に :ref:`Shape` との最大値を使用します。\"\n\n#: ../../page.rst:1568 f4d8e219e2f64f1680a7c881a83b260c\nmsgid \"lineJoin\"\nmsgstr \"\"\n\n#: ../../page.rst:1569 950e8cc3745342f7826691d71f31f7e5\nmsgid \"fill_opacity\"\nmsgstr \"\"\n\n#: ../../page.rst:1569 4d4650f75a8e4396adfded67df0767c3\nmsgid \"fill color transparency (see :ref:`Shape`). (New in v1.18.17)\"\nmsgstr \"v1.18.17で新しく追加された塗りつぶしカラーの透明度（:ref:`Shape` を参照）。\"\n\n#: ../../page.rst:1570 e9b05909669b4677b8e3a68eb18f0588\nmsgid \"stroke_opacity\"\nmsgstr \"\"\n\n#: ../../page.rst:1570 b9a5e59fcfd14e9b9aae6f4ff5098865\nmsgid \"stroke color transparency  (see :ref:`Shape`). (New in v1.18.17)\"\nmsgstr \"v1.18.17で新しく追加されたストロークカラーの透明度（:ref:`Shape` を参照）。\"\n\n#: ../../page.rst:1571 ../../page.rst:1629 ../../page.rst:1641\n#: 396b005a11e4432ab5482ffe50b3d61d 80c6973f07714e1c9453b787c54bf5b7\n#: ea83089bd43b454894be96e4850f824b\nmsgid \"rect\"\nmsgstr \"\"\n\n#: ../../page.rst:1571 9d7bacf5e4354e0c86c3c9bd4401f6dc\nmsgid \"Page area covered by this path. Information only.\"\nmsgstr \"このパスでカバーされるページ領域。情報のみ。\"\n\n#: ../../page.rst:1572 ../../page.rst:1630 ../../page.rst:1642\n#: 24fac03d9b2b451384416fe5f78db143 a67392e66f764fd4b96c6c091fcfe069\n#: ba34e287651645a8a7de9f9ce9ef0d5c\nmsgid \"layer\"\nmsgstr \"\"\n\n#: ../../page.rst:1572 285aa0882ae1442d94405a6a35a4492d\nmsgid \"name of applicable Optional Content Group. (New in v1.22.0)\"\nmsgstr \"v1.22.0で新しく追加された適用可能なオプションコンテンツグループの名前\"\n\n#: ../../page.rst:1573 ../../page.rst:1631 ../../page.rst:1643\n#: 273156c615254021b3cf1e377897bbc5 3b054f8bb5b9486d99b99e62d3bf5685\n#: a84a2657ecc24963828aa7e4dadfeab4\nmsgid \"level\"\nmsgstr \"\"\n\n#: ../../page.rst:1573 110acb6bf408488e9e421af328fa9d51\nmsgid \"the hierarchy level if `extended=True`. (New in v1.22.0)\"\nmsgstr \"v1.22.0で新しく追加された `extended=True` の場合の階層レベル\"\n\n#: ../../page.rst:1574 755b90abd14946a39aeeb0c3a6d64858\nmsgid \"seqno\"\nmsgstr \"\"\n\n#: ../../page.rst:1574 ab333668880148c5bcbb944ff2e72050\nmsgid \"command number when building page appearance. (New in v1.19.0)\"\nmsgstr \"v1.19.0で新しく追加されたページ表示を構築する際のコマンド番号\"\n\n#: ../../page.rst ../../page.rst:1575 ../../page.rst:1633 ../../page.rst:1648\n#: 09c8e555385e47fc97e73ebfd3dd04bf 0d0baa2c58864bf0aaf04e11bbc433d9\n#: 16fd53bebab845e7b14791cb33f919fe 31ce9aa1df7e40a68f2c5f62e6ba484b\n#: 3410a53940f0434ca67cfb41198bb2f0 35e83c59c3514d7fb3b3153505e76068\n#: 506e3da6e2804fb5a0ba281b65419ac2 52415d0516fe43aa963858ff74eb86c3\n#: 5e9311c5c55c47c1b2b2cadc4a66db12 62864ef6f3db473292d55c992c0de8c7\n#: 695c03fb5cb74905af8b144210886b6c 6d88f9f8146647408ca720eb2639440d\n#: 70c939a93c2e4d07b551c6a3357d38bb 71b611108f864cb2a6bfea2fd779ca40\n#: 80808763cc4e4f07b8b9799442a48d04 83e3d24314624f098b245e49198c48d1\n#: 87a6add728944a7c978acf71d98c584e 8aea933f1c4c46608271d33b001e3347\n#: 8b6a6acc29f24bfdb57d92ac9e4a045a 92ff84c878f34a4594725fae0575009b\n#: 9438f342c06943fface3e341a34df2b8 974268f30c784035a84eaebfe210cd18\n#: 9bb07cd381434d8b82e253ba5094c088 a96abc6aa8864f4d92f1c9428ccf8b75\n#: ae50cdfdfd9b4989a954861e1a55164a b63e1567826045b5a119a457977b02a7\n#: b650a636652a4bed990a6e58a75790ed bbb50ffa42684b95a959efa8633eb29c\n#: c9b439ade3814c0d8ded9fc9af2b9bc8 caf0437e4fff4cd49a3205aaccb6cc79\n#: cb13688627aa446181023ea67d345fe1 e22bdcabea7145ad86fae5a319b7a90a\n#: fc4dc4c3601b4fc0ba378cbd5a35dda6\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../page.rst:1575 da590961ef344547956aadf05b289b30\nmsgid \"type of this path. (New in v1.18.17)\"\nmsgstr \"このパスのタイプ。 (v1.18.17で新規追加)\"\n\n#: ../../page.rst:1576 ../../page.rst:1719 4aa3677ead1f4c61bb6574218d24bab9\n#: 6118b6070da0480c9a1c25e056ec8abb\nmsgid \"width\"\nmsgstr \"\"\n\n#: ../../page.rst:1576 a6722de8bea742f18c275db16917fc03\nmsgid \"Stroke line width. (see :ref:`Shape`).\"\nmsgstr \"ストロークラインの幅（:ref:`Shape` を参照）。\"\n\n#: ../../page.rst:1579 ed5265d8748c41bc89dcea0e43820815\nmsgid \"\"\n\"Key `\\\"opacity\\\"` has been replaced by the new keys `\\\"fill_opacity\\\"` \"\n\"and `\\\"stroke_opacity\\\"`. This is now compatible with the corresponding \"\n\"parameters of :meth:`Shape.finish`. (Changed in v1.18.17)\"\nmsgstr \"\"\n\"*(バージョン1.18.17で変更)* キー  `\\\"opacity\\\"` は新しいキー  `\\\"fill_opacity\\\"` および \"\n\"\\\"stroke_opacity\\\"` に置き換えられました。これは、:meth:`Shape.finish` \"\n\"の対応するパラメーターと互換性があるようになりました。\"\n\n#: ../../page.rst:1582 32f9db8262474d6cb9e66a650d39602d\nmsgid \"\"\n\"For paths other than groups or clips, key `\\\"type\\\"` takes one of the \"\n\"following values:\"\nmsgstr \"グループやクリップ以外のパスに対して、キー `\\\"type\\\"` は次のいずれかの値を取ります：\"\n\n#: ../../page.rst:1584 c0b05d924d2a4c7693eed244061cb086\nmsgid \"\"\n\"**\\\"f\\\"** -- this is a *fill-only* path. Only key-values relevant for \"\n\"this operation have a meaning, not applicable ones are present with a \"\n\"value of ``None``: `\\\"color\\\"`, `\\\"lineCap\\\"`, `\\\"lineJoin\\\"`, \"\n\"`\\\"width\\\"`, `\\\"closePath\\\"`, `\\\"dashes\\\"` and should be ignored.\"\nmsgstr \"\"\n\"**\\\"f\\\"**  - これは *fill-only* のパスです。この操作に関連するキーの値のみが意味を持ち、適用されないものは値が \"\n\"``None`` で存在します。: \"\n\"`\\\"color\\\"`、`\\\"lineCap\\\"`、\\\"lineJoin\\\"`、`\\\"width\\\"`、`\\\"closePath\\\"`、`\\\"dashes\\\"`\"\n\" は無視すべきです。\"\n\n#: ../../page.rst:1585 8c8a235505ce4644a896122fad7d5260\nmsgid \"\"\n\"**\\\"s\\\"** -- this is a *stroke-only* path. Similar to previous, key \"\n\"`\\\"fill\\\"` is present with value ``None``.\"\nmsgstr \"\"\n\"**\\\"s\\\"** - これは *stroke-only* のパスです。以前と同様に、キー `\\\"fill\\\"` は値が ``None`` \"\n\"で存在します。\"\n\n#: ../../page.rst:1586 af52343e1c124d299e93555b1fd95094\nmsgid \"\"\n\"**\\\"fs\\\"** -- this is a path performing combined *fill* and *stroke* \"\n\"operations.\"\nmsgstr \"**\\\"fs\\\"** - これは *fill* と *stroke* の組み合わせ操作を実行するパスです\"\n\n#: ../../page.rst:1588 43313ea722f34fc8a309b70525a81840\nmsgid \"Each item in `path[\\\"items\\\"]` is one of the following:\"\nmsgstr \"`path[\\\"items\\\"]` の各アイテムは、次のいずれかです：\"\n\n#: ../../page.rst:1590 c739530352f348fab20572b09779faa4\nmsgid \"`(\\\"l\\\", p1, p2)` - a line from p1 to p2 (:ref:`Point` objects).\"\nmsgstr \"`(\\\"l\\\", p1, p2)` - p1 から p2 への直線（:ref:`Point` オブジェクト）。\"\n\n#: ../../page.rst:1591 23c7b2f0773c4217b131c3ed4e91144d\nmsgid \"\"\n\"`(\\\"c\\\", p1, p2, p3, p4)` - cubic Bézier curve **from p1 to p4** (p2 and \"\n\"p3 are the control points). All objects are of type :ref:`Point`.\"\nmsgstr \"\"\n\"`(\\\"c\\\", p1, p2, p3, p4)` - **p1 から p4 へ** の三次ベジエ曲線（p2 と p3 \"\n\"は制御点です）。すべてのオブジェクトは :ref:`Point` タイプです。\"\n\n#: ../../page.rst:1592 182b64307110415e801d9fd57ce0dd93\nmsgid \"\"\n\"`(\\\"re\\\", rect, orientation)` - a :ref:`Rect`. Multiple rectangles within\"\n\" the same path are now detected (changed in v1.18.17). Integer \"\n\"`orientation` is 1 resp. -1 indicating whether the enclosed area is \"\n\"rotated left (1 = anti-clockwise), or resp. right [#f7]_ (changed in \"\n\"v1.19.2).\"\nmsgstr \"\"\n\"`(\\\"re\\\", rect, orientation)` - a :ref:`Rect` 同じパス内の複数の矩形が検出されます \"\n\"(v1.18.17で変更)。整数のorientationは、含まれる領域が左に回転しているかどうかを示します (1 = \"\n\"反時計回り)。または右に回転しているかどうかを示します [#f7]_ (v1.19.2で変更)\"\n\n#: ../../page.rst:1593 a1e0959514f34373885cee413d61fe44\nmsgid \"\"\n\"`(\\\"qu\\\", quad)` - a :ref:`Quad`. 3 or 4 consecutive lines are detected \"\n\"to actually represent a :ref:`Quad` (changed in v1.19.2:). (New in \"\n\"v1.18.17)\"\nmsgstr \"\"\n\"`(\\\"qu\\\", quad)` - \"\n\":ref:`Quad`。*バージョン1.18.17で新しく追加され、バージョン1.19.2で変更されました:* 3つまたは4つの連続する線が \"\n\"Quad を実際に表すことが検出されます。\"\n\n#: ../../page.rst:1597 8737dee28b734402854dc865731fa242\n#, fuzzy\nmsgid \"\"\n\"Using class :ref:`Shape`, you should be able to recreate the original \"\n\"drawings on a separate (PDF) page with high fidelity under normal, not \"\n\"too sophisticated circumstances. Please see the following comments on \"\n\"restrictions. A coding draft can be found in :ref:`How to Extract \"\n\"Drawings <RecipesDrawingAndGraphics_Extract_Drawings>`.\"\nmsgstr \"\"\n\"クラス :ref:`Shape` \"\n\"を使用すると、通常の、あまり洗練されていない状況で、高い忠実度で元の図面を別の（PDF）ページに再作成できるはずです。制約事項に関する以下のコメントをご覧ください。コーディングのドラフトは、:ref:`FAQ`\"\n\" の「図面の抽出」章のセクションにあります。\"\n\n#: ../../page.rst:1599 3aab8e3a27f344888a1f81b6a87ca092\nmsgid \"\"\n\"Specifying `extended=True` significantly alters the output. Most \"\n\"importantly, new dictionary types are present: \\\"clip\\\" and \\\"group\\\". \"\n\"All paths will now be organized in a hierarchic structure which is \"\n\"encoded by the new integer key \\\"level\\\", the hierarchy level. Each group\"\n\" or clip establishes a new hierarchy, which applies to all subsequent \"\n\"paths having a *larger* level value. (New in v1.22.0)\"\nmsgstr \"\"\n\"extended=Trueを指定すると、出力が大幅に変更されます。最も重要なのは、新しい辞書タイプが存在することです: \\\"clip\\\" および \"\n\"\\\"group\\\"。すべてのパスは、新しい整数キー \"\n\"\\\"level\\\"、つまり階層レベルでエンコードされた階層構造に組織されます。各グループまたはクリップは、新しい階層を確立し、それ以降のすべてのパスに適用されます。\"\n\" (v1.22.0で新規)\"\n\n#: ../../page.rst:1601 1748684dc4e14785be96e811eeb77ccd\nmsgid \"\"\n\"Any path with a smaller level value than its predecessor will end the \"\n\"scope of (at least) the preceding hierarchy level. A \\\"clip\\\" path with \"\n\"the same level as the preceding clip will end the scope of that clip. \"\n\"Same is true for groups. This is best explained by an example::\"\nmsgstr \"\"\n\"前任者よりも小さいレベル値を持つパスは、少なくとも前の階層レベルのスコープを終了します。前のクリップと同じレベルの \\\"clip\\\" \"\n\"パスは、そのクリップのスコープを終了します。同様に、グループも同じです。これは、次の例で最もよく説明されます：\"\n\n#: ../../page.rst:1617 6f3f822ea769448791e724a14fb47c4e\nmsgid \"\"\n\"The clip in line 0 applies to line including line 7. Group in line 2 \"\n\"applies to lines 3 to 5, clip in line 3 only applies to line 4.\"\nmsgstr \"行0の「clip」は行7を含む行全体に適用されます。行2の「group」は行3から5までの行に適用され、行3の「clip」は行4にのみ適用されます。\"\n\n#: ../../page.rst:1619 e9f022fb71814f56ad2df5f517acbd13\nmsgid \"\"\n\"\\\"stroke\\\" in line 4 is under control of \\\"group\\\" in line 2 and \\\"clip\\\"\"\n\" in line 3 (which in turn is a subset of line 0 clip).\"\nmsgstr \"行4の「stroke」は行2の「group」と行3の「clip」（それ自体が行0の「clip」のサブセットです）の制御下にあります。\"\n\n#: ../../page.rst:1621 6625c75c092d46e3a7e09245afa0c057\nmsgid \"\"\n\"**\\\"clip\\\"** dictionary. Its values (most importantly \\\"scissor\\\") remain\"\n\" valid / apply as long as following dictionaries have a **larger \"\n\"\\\"level\\\"** value.\"\nmsgstr \"**「clip」** 辞書。その値（特に「scissor」）は、後続の辞書が「level」の値が大きい限り、有効で適用されます。\"\n\n#: ../../page.rst:1626 ../../page.rst:1627 ../../page.rst:1628\n#: ../../page.rst:1629 ../../page.rst:1630 ../../page.rst:1631\n#: ../../page.rst:1641 ../../page.rst:1642 ../../page.rst:1643\n#: 0b1b63f41c404901b1643b11b45a5867 62247667752f4b578ccac9e0ecbf590f\n#: 7c9a0aa3e8c649d7bee3ac7454b43e93 8366a70901664384adfb01a3b67ee7a8\n#: 953f66d4fd474cbab098faaf2de24bd4 9aa1a22c1adb4eb9a1439d3e2ff1dc95\n#: a1f6eff494b646fbb07a9a6339af5a87 bc4222fbdf6542cdbb7491fb0063b6a2\n#: c1372886b46f46a5afba4a892a59ac6b\nmsgid \"Same as in \\\"stroke\\\" or \\\"fill\\\" dictionaries\"\nmsgstr \"「stroke」または「fill」の辞書と同じ\"\n\n#: ../../page.rst:1632 ab690b8cb544494f80184b0c2875a553\nmsgid \"scissor\"\nmsgstr \"\"\n\n#: ../../page.rst:1632 236ed2afc6734846a1cae6d95ea45663\nmsgid \"the clip rectangle\"\nmsgstr \"クリップ矩形\"\n\n#: ../../page.rst:1633 d15367360f8c488fb8e82f9a295c789d\nmsgid \"\\\"clip\\\"\"\nmsgstr \"\"\n\n#: ../../page.rst:1636 d738d1231fd84ceb820cca1d992713db\nmsgid \"\"\n\"\\\"group\\\" dictionary. Its values remain valid (apply) as long as \"\n\"following dictionaries have a **larger \\\"level\\\"** value. Any dictionary \"\n\"with an equal or lower level end this group.\"\nmsgstr \"「group」辞書。その値は、後続の辞書が「level」の値が大きい限り、有効で適用されます。同じレベルまたはそれ以下の辞書がこのグループを終了します。\"\n\n#: ../../page.rst:1644 cd11376cc4d0426fa447eb7c0f0baff9\nmsgid \"isolated\"\nmsgstr \"\"\n\n#: ../../page.rst:1644 e0738e311c024fb998234f0f1fe4f9ed\nmsgid \"(bool) Whether this group is isolated\"\nmsgstr \"（ブール）このグループが孤立しているかどうか\"\n\n#: ../../page.rst:1645 b2ae44ac73bb4cae949ced93c0d41e4d\nmsgid \"knockout\"\nmsgstr \"\"\n\n#: ../../page.rst:1645 156f97e7dd9a462388446f5d35f3992c\nmsgid \"(bool) Whether this is a \\\"Knockout Group\\\"\"\nmsgstr \"（ブール）これが「Knockout Group」であるかどうか\"\n\n#: ../../page.rst:1646 ded1960d4efa41c88ecdaba0d99c93a7\nmsgid \"blendmode\"\nmsgstr \"\"\n\n#: ../../page.rst:1646 5a270db7a07242328025288ce3607085\nmsgid \"Name of the BlendMode, default is \\\"Normal\\\"\"\nmsgstr \"BlendModeの名前、デフォルトは「Normal」\"\n\n#: ../../page.rst:1647 404d1a92eafc46789f2290501a8b3971\nmsgid \"opacity\"\nmsgstr \"\"\n\n#: ../../page.rst:1647 c6cec53ea64546d5ada9351c5f7021dc\nmsgid \"Float value in range [0, 1].\"\nmsgstr \"範囲[0、1]内の浮動小数点値\"\n\n#: ../../page.rst:1648 a32b4e5b645e47a38fae496213fe05c8\nmsgid \"\\\"group\\\"\"\nmsgstr \"\"\n\n#: ../../page.rst:1651 2df5c71b6d04456cb8e757571346136a\nmsgid \"\"\n\"The method is based on the output of :meth:`Page.get_cdrawings` -- which \"\n\"is much faster, but requires somewhat more attention processing its \"\n\"output.\"\nmsgstr \"\"\n\"このメソッドは、 :meth:`Page.get_cdrawings` \"\n\"の出力に基づいています。これははるかに高速ですが、出力の処理には多少の注意が必要です。\"\n\n#: ../../page.rst:1655 71f7d609802a4816840f59ed160efa23\nmsgid \"New in v1.18.0\"\nmsgstr \"v1.18.0で新規追加\"\n\n#: ../../page.rst:1656 fb8f5286189c4662a4cceffc1eba220f\nmsgid \"Changed in v1.18.17\"\nmsgstr \"v1.18.17で変更\"\n\n#: ../../page.rst:1657 e68c9de4f0a34718a2f1dfa501188aa8\nmsgid \"Changed in v1.19.0: add \\\"seqno\\\" key, remove \\\"clippings\\\" key\"\nmsgstr \"v1.19.0で変更: “seqno”キーを追加、“clippings”キーを削除\"\n\n#: ../../page.rst:1658 2ce82133d3a848308013a2da324444a8\nmsgid \"\"\n\"Changed in v1.19.1: \\\"color\\\" / \\\"fill\\\" keys now always are either are \"\n\"RGB tuples or `None`. This resolves issues caused by exotic colorspaces.\"\nmsgstr \"\"\n\"v1.19.1で変更: “color” / \"\n\"“fill”キーは常にRGBタプルまたはNoneのいずれかであるように変更。これにより、異常なカラースペースに起因する問題が解消されます。\"\n\n#: ../../page.rst:1659 9b91a351faa841d684907b0234c55356\nmsgid \"\"\n\"Changed in v1.19.2: add an indicator for the *\\\"orientation\\\"* of the \"\n\"area covered by an \\\"re\\\" item.\"\nmsgstr \"v1.19.2で変更: \\\"re\\\" アイテムでカバーされる領域の *\\\"orientation\\\"* を示すインジケーターを追加\"\n\n#: ../../page.rst:1660 75ed0d5f99574606ba73b9dd0420738f\nmsgid \"\"\n\"Changed in v1.22.0: add new key `\\\"layer\\\"` which contains the name of \"\n\"the Optional Content Group of the path (or `None`).\"\nmsgstr \"v1.22.0で変更: 新しいキー `\\\"layer\\\"` を追加。これにはパスのオプションコンテンツグループの名前が含まれます（またはNone）。\"\n\n#: ../../page.rst:1661 7008b61db0b949ac97b7f1bfa2e2e90c\nmsgid \"\"\n\"Changed in v1.22.0: add parameter `extended` to also return clipping and \"\n\"group paths.\"\nmsgstr \"v1.22.0で変更: クリッピングとグループパスも返すようにするためのパラメーター `extended` を追加\"\n\n#: ../../page.rst:1669 a96f2efad24c40d9969480c93d059df4\nmsgid \"\"\n\"Extract the vector graphics on the page. Apart from following technical \"\n\"differences, functionally equivalent to :meth:`Page.get_drawings`, but \"\n\"much faster:\"\nmsgstr \"\"\n\"ページ上のベクトルグラフィックスを抽出します。技術的な違いを除いて、:meth:`Page.get_drawings` \"\n\"と機能的に同等ですが、はるかに高速です：\"\n\n#: ../../page.rst:1671 3cf72c72b8b14a14956e2d8174d231e4\nmsgid \"\"\n\"Every path type only contains the relevant keys, e.g. a stroke path has \"\n\"no `\\\"fill\\\"` color key. See comment in method :meth:`Page.get_drawings`.\"\nmsgstr \"\"\n\"各パスタイプには関連するキーのみ含まれます。たとえば、ストロークパスには `\\\"fill\\\"` カラーキーはありません。 \"\n\":meth:`Page.get_drawings` メソッドのコメントを参照してください。\"\n\n#: ../../page.rst:1672 80f8f4ff491c4bff8b8aa785b886d608\nmsgid \"\"\n\"Coordinates are given as :data:`point_like`, :data:`rect_like` and \"\n\":data:`quad_like` **tuples** -- not as :ref:`Point`, :ref:`Rect`, \"\n\":ref:`Quad` objects.\"\nmsgstr \"\"\n\"座は :data:`point_like`、:data:`rect_like`、:data:`quad_like` の **tuples** \"\n\"として与えられます。:ref:`Point`、:ref:`Rect`、:ref:`Quad` オブジェクトとしてではなく。\"\n\n#: ../../page.rst:1674 4b700daa5e5f40fa9606f84421e48b44\nmsgid \"\"\n\"If performance is a concern, consider using this method: Compared to \"\n\"versions earlier than 1.18.17, you should see much shorter response \"\n\"times. We have seen pages that required 2 seconds then, now only need 200\"\n\" ms with this method.\"\nmsgstr \"性能が懸念される場合、このメソッドを使用することを検討してください。バージョン1.18.17より前と比較して、応答時間が大幅に短縮されるはずです。以前は2秒かかったページが、このメソッドを使用すると200ミリ秒で完了する場合もあります。\"\n\n#: ../../page.rst:1678 82ced38ad2c542e2af33c904c6804a7d\nmsgid \"New in v1.18.17\"\nmsgstr \"新機能（v1.18.17）\"\n\n#: ../../page.rst:1679 0320aecb048143c88baa0ae5cd45aa17\nmsgid \"Changed in v1.19.0: removed \\\"clippings\\\" key, added \\\"seqno\\\" key.\"\nmsgstr \"v1.19.0で変更：「clippings」キーを削除、新たに「seqno」キーを追加。\"\n\n#: ../../page.rst:1680 13fe0b91e6a441d8a64550e72fe9e288\nmsgid \"Changed in v1.19.1: always generate RGB color tuples.\"\nmsgstr \"v1.19.1で変更：常にRGBカラータプルを生成します。\"\n\n#: ../../page.rst:1681 939fc3ee15724d3e9eca02626e4dd209\nmsgid \"\"\n\"Changed in v1.22.0: added new key `\\\"layer\\\"` which contains the name of \"\n\"the Optional Content Group of the path (or `None`).\"\nmsgstr \"v1.22.0で変更：新たに「layer」というキーが追加され、パスのオプションコンテンツグループの名前（またはNone）が含まれます。\"\n\n#: ../../page.rst:1682 7d630d9224974c81a4aaefd5f9181654\n#, fuzzy\nmsgid \"\"\n\"Changed in v1.22.0: added parameter `extended` to also return clipping \"\n\"paths.\"\nmsgstr \"v1.22.0で変更：クリッピングパスを返すためのパラメータ「extended」が追加されました。\"\n\n#: ../../page.rst:1689 ea979f6ebe4e41efa9388507c821a9c8\nmsgid \"\"\n\"PDF only: Return a list of fonts referenced by the page. Wrapper for \"\n\":meth:`Document.get_page_fonts`.\"\nmsgstr \"PDFのみ：ページで参照されているフォントのリストを返します。:meth:`Document.get_page_fonts` のラッパーです。\"\n\n#: ../../page.rst:1694 35702954b233483e986ca6767f8e2c41\nmsgid \"\"\n\"PDF only: Return a list of images referenced by the page. Wrapper for \"\n\":meth:`Document.get_page_images`.\"\nmsgstr \"PDFのみ：ページで参照されているイメージのリストを返します。:meth:`Document.get_page_images` のラッパーです。\"\n\n#: ../../page.rst:1703 e27bbe5080354b09be116ea34e97539c\nmsgid \"\"\n\"Return a list of meta information dictionaries for all images displayed \"\n\"by the page. This works for all document types.\"\nmsgstr \"\"\n\n#: ../../page.rst:1705 58b8fd3467b6413d95b81f9cd5c61415\nmsgid \"\"\n\"Compute the MD5 hashcode for each encountered image, which allows \"\n\"identifying image duplicates. This adds the key `\\\"digest\\\"` to the \"\n\"output, whose value is a 16 byte `bytes` object. (New in v1.18.13)\"\nmsgstr \"\"\n\"*新機能（v1.18.13)*：各イメージのMD5ハッシュコードを計算し、イメージの重複を識別できるようにします。これにより、出力に \"\n\"`\\\"digest\\\"` キーが追加され、その値は16バイトのバイトオブジェクトです。\"\n\n#: ../../page.rst:1707 e89fb63bb59d4806b77c4b8d8330597e\nmsgid \"\"\n\"**PDF only.** Try to find the :data:`xref` for each image. Implies \"\n\"`hashes=True`. Adds the `\\\"xref\\\"` key to the dictionary. If not found, \"\n\"the value is 0, which means, the image is either \\\"inline\\\" or its xref \"\n\"is undetectable for some reason. Please note that this option has an \"\n\"extended response time, because the MD5 hashcode will be computed at \"\n\"least two times for each image with an xref. (New in v1.18.13)\"\nmsgstr \"\"\n\n#: ../../page.rst:1710 5c7d342802164ffc821b3c5a9df090ee\nmsgid \"\"\n\"A list of dictionaries. This includes information for **exactly those** \"\n\"images, that are shown on the page -- including *\\\"inline images\\\"*. The \"\n\"dictionary layout is similar to that of image blocks in \"\n\"`page.get_text(\\\"dict\\\")`.  In contrast to images included in \"\n\":meth:`Page.get_text`, image **binary content** is not loaded by this \"\n\"method, which drastically reduces memory usage. Another difference is \"\n\"that image detection is not restricted to the visible part of the page or\"\n\" any ``clip`` parameter: method :meth:`Page.get_text` will only extract \"\n\"images **fully contained** in the provided ``clip``.  =============== \"\n\"=============================================================== **Key**\"\n\"             **Value** =============== \"\n\"=============================================================== number\"\n\"          block number (``int``) bbox            image bbox on page, \"\n\":data:`rect_like` width           original image width (``int``) height\"\n\"          original image height (``int``) cs-name         colorspace name\"\n\" (``str``) colorspace      colorspace.n (``int``) xres            \"\n\"resolution in x-direction (``int``) [#f10]_ yres            resolution in\"\n\" y-direction (``int``) [#f10]_ bpc             bits per component \"\n\"(``int``) size            storage occupied by image (``int``) digest\"\n\"          MD5 hashcode (``bytes``), if ``hashes`` is true xref\"\n\"            image :data:`xref` or 0, if *xrefs* is true transform       \"\n\"matrix transforming image rect to bbox, :data:`matrix_like` has-mask\"\n\"        whether the image is transparent and has a mask (``bool``) \"\n\"=============== \"\n\"===============================================================  Multiple\"\n\" occurrences of the same image are always reported. You can detect \"\n\"duplicates by comparing their `digest` values.\"\nmsgstr \"\"\n\n#: ../../page.rst:1710 b56c6cfb35a14ff8aab2e98fbea4236b\n#, fuzzy\nmsgid \"\"\n\"A list of dictionaries. This includes information for **exactly those** \"\n\"images, that are shown on the page -- including *\\\"inline images\\\"*. The \"\n\"dictionary layout is similar to that of image blocks in \"\n\"`page.get_text(\\\"dict\\\")`.\"\nmsgstr \"\"\n\"辞書のリスト。これには、ページに表示されているイメージに関する情報が含まれます。:meth:`Page.get_text` \"\n\"で含まれている画像ブロックとは異なり、画像の **binary content** \"\n\"は読み込まれないため、メモリの使用量が大幅に削減されます。辞書のレイアウトは、ページ.get_text(\\\"dict\\\")内のイメージブロックと似ています。\"\n\n#: ../../page.rst:1712 93ecc3c5bbae4c92ae4cecf391770755\nmsgid \"\"\n\"In contrast to images included in :meth:`Page.get_text`, image **binary \"\n\"content** is not loaded by this method, which drastically reduces memory \"\n\"usage. Another difference is that image detection is not restricted to \"\n\"the visible part of the page or any ``clip`` parameter: method \"\n\":meth:`Page.get_text` will only extract images **fully contained** in the\"\n\" provided ``clip``.\"\nmsgstr \"\"\n\n#: ../../page.rst:1715 a7a064c18ac546ac8c5f5be2910e0bf3\nmsgid \"**Key**\"\nmsgstr \"**キー**\"\n\n#: ../../page.rst:1715 d16e6fb7b03143b5ba0140010250fd69\nmsgid \"**Value**\"\nmsgstr \"**値**\"\n\n#: ../../page.rst:1717 1907cae26e1b493e957c192126f8bd58\nmsgid \"number\"\nmsgstr \"\"\n\n#: ../../page.rst:1717 d27911324a5a4a0fafd9d6e2550ef566\n#, fuzzy\nmsgid \"block number (``int``)\"\nmsgstr \"ブロック番号 *(整数)*\"\n\n#: ../../page.rst:1718 f6a7c2aaf9e1462bbeeb72cb31bf79d9\nmsgid \"bbox\"\nmsgstr \"\"\n\n#: ../../page.rst:1718 86eb7e0ea23f4bdcac8257dc8460c60c\nmsgid \"image bbox on page, :data:`rect_like`\"\nmsgstr \"ページ上の画像の境界ボックス、:data:`rect_like`\"\n\n#: ../../page.rst:1719 f952cb79a0dd4bcf9e6f76a0c369e396\n#, fuzzy\nmsgid \"original image width (``int``)\"\nmsgstr \"元の画像の幅 *(整数)*\"\n\n#: ../../page.rst:1720 43cc7cf52ac3463abb66db570a2f515a\nmsgid \"height\"\nmsgstr \"\"\n\n#: ../../page.rst:1720 8ff4acda1c0b47359b27bb83e55ed142\n#, fuzzy\nmsgid \"original image height (``int``)\"\nmsgstr \"元の画像の高さ *(整数*\"\n\n#: ../../page.rst:1721 7b5e02a5db25462a9201cb3ca634db93\nmsgid \"cs-name\"\nmsgstr \"\"\n\n#: ../../page.rst:1721 e8aed799c5204ef995ee98b0e15b1752\n#, fuzzy\nmsgid \"colorspace name (``str``)\"\nmsgstr \"カラースペース名 *(文字列)*\"\n\n#: ../../page.rst:1722 470b51b79e894363aa2f3e7b4395e012\nmsgid \"colorspace\"\nmsgstr \"\"\n\n#: ../../page.rst:1722 66bd8b12699c4b87beaa2678b6847f61\n#, fuzzy\nmsgid \"colorspace.n (``int``)\"\nmsgstr \"colorspace.n *(整数)*\"\n\n#: ../../page.rst:1723 010a2b1b2cc040d18328b23373335b39\nmsgid \"xres\"\nmsgstr \"\"\n\n#: ../../page.rst:1723 8e9ab06b3360480a969c713111c0e1b7\n#, fuzzy\nmsgid \"resolution in x-direction (``int``) [#f10]_\"\nmsgstr \"x方向の解像度 *(整数)*\"\n\n#: ../../page.rst:1724 2a2d1ea79f0e4c1d952227ba35b19bcc\nmsgid \"yres\"\nmsgstr \"\"\n\n#: ../../page.rst:1724 1f63c35a38104eaf9ac1f4c0a446c2d3\n#, fuzzy\nmsgid \"resolution in y-direction (``int``) [#f10]_\"\nmsgstr \"y方向の解像度 *(整数)*\"\n\n#: ../../page.rst:1725 6afb17cd205b4d36b405379292e5cc7e\nmsgid \"bpc\"\nmsgstr \"\"\n\n#: ../../page.rst:1725 2b3f9b22e8954cc68e29c89a9755baab\n#, fuzzy\nmsgid \"bits per component (``int``)\"\nmsgstr \"コンポーネントごとのビット数 *(整数)*\"\n\n#: ../../page.rst:1726 87dc60b6e9dd4ff8b3e8dc2dac2d46f8\nmsgid \"size\"\nmsgstr \"\"\n\n#: ../../page.rst:1726 a5aa0c1d578b42cf9833f66aca7fec20\n#, fuzzy\nmsgid \"storage occupied by image (``int``)\"\nmsgstr \"画像が占めるストレージ容量 *(整数)*\"\n\n#: ../../page.rst:1727 5b99ae76cf7a47c58d86b4331f33c9a4\nmsgid \"digest\"\nmsgstr \"\"\n\n#: ../../page.rst:1727 e999edeff85549c6a9c7ae83208b170d\n#, fuzzy\nmsgid \"MD5 hashcode (``bytes``), if ``hashes`` is true\"\nmsgstr \"MD5ハッシュコード（バイト）、*hashes* がtrueの場合\"\n\n#: ../../page.rst:1728 522f8069369a4655b9e90e66fce84ec6\nmsgid \"xref\"\nmsgstr \"\"\n\n#: ../../page.rst:1728 0d5fc56e9adb4cc0add3fa114a0d0b1a\nmsgid \"image :data:`xref` or 0, if *xrefs* is true\"\nmsgstr \"画像の :data:`xref` または0、*xrefs* がtrueの場合\"\n\n#: ../../page.rst:1729 d500ae56d3ae4425a687416bc7d26d3e\nmsgid \"transform\"\nmsgstr \"\"\n\n#: ../../page.rst:1729 bbf4e06903aa4ffab22418f35b7f0346\nmsgid \"matrix transforming image rect to bbox, :data:`matrix_like`\"\nmsgstr \"画像の境界ボックスをbboxに変換するための行列、:data:`matrix_like`\"\n\n#: ../../page.rst:1730 f0f0216b6f1541eaa6cc1001d10aea53\nmsgid \"has-mask\"\nmsgstr \"\"\n\n#: ../../page.rst:1730 49f00035ed2d4832890306c637415dbb\nmsgid \"whether the image is transparent and has a mask (``bool``)\"\nmsgstr \"\"\n\n#: ../../page.rst:1733 3b610224f44344e5b62359a6e14b4856\nmsgid \"\"\n\"Multiple occurrences of the same image are always reported. You can \"\n\"detect duplicates by comparing their `digest` values.\"\nmsgstr \"同じ画像の複数の出現は常に報告されます。digestの値を比較して重複を検出できます。\"\n\n#: ../../page.rst:1737 946d5705f3bb433ba251ee6b7b08f6c3\nmsgid \"New in v1.18.11\"\nmsgstr \"*新機能（v1.18.11)*\"\n\n#: ../../page.rst:1738 29620790dffa4bf8951b84a7d7d93aeb\nmsgid \"\"\n\"Changed in v1.18.13: added image MD5 hashcode computation and \"\n\":data:`xref` search.\"\nmsgstr \"*v1.18.13で変更：* イメージのMD5ハッシュコードの計算と :data:`xref` の検索が追加されました。\"\n\n#: ../../page.rst:1745 38f20a8134cf4edb84b0b83559c20eb7\nmsgid \"\"\n\"PDF only: Return a list of Form XObjects referenced by the page. Wrapper \"\n\"for :meth:`Document.get_page_xobjects`.\"\nmsgstr \"\"\n\"PDFのみ：ページで参照されているフォームXObjectのリストを返します。:meth:`Document.get_page_xobjects` \"\n\"のラッパーです。\"\n\n#: ../../page.rst:1753 f08fc49d243849d6907078ee53743eb5\nmsgid \"\"\n\"PDF only: Return boundary boxes and transformation matrices of an \"\n\"embedded image. This is an improved version of \"\n\":meth:`Page.get_image_bbox` with the following differences:\"\nmsgstr \"\"\n\"PDFのみ：埋め込み画像の境界ボックスと変換行列を返します。これは :meth:`Page.get_image_bbox` \"\n\"の改良バージョンで、次の違いがあります：\"\n\n#: ../../page.rst:1755 22156183966643a5abe5b2dcacf61595\nmsgid \"\"\n\"There is no restriction on **how** the image is invoked (by the page or \"\n\"one of its Form XObjects). The result is always complete and correct.\"\nmsgstr \"\"\n\"画像が **どのように** \"\n\"呼び出されるかに制限はありません（ページまたはそのフォームXObjectのいずれかによって）。結果は常に完全かつ正確です。\"\n\n#: ../../page.rst:1756 121ff8e320a1435bb587e969f50728e6\nmsgid \"\"\n\"The result is a list of :ref:`Rect` or (:ref:`Rect`, :ref:`Matrix`) \"\n\"objects -- depending on *transform*. Each list item represents one \"\n\"location of the image on the page. Multiple occurrences might not be \"\n\"detectable by :meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\"結果は :ref:`Rect` または（:ref:`Rect`、:ref:`Matrix`）オブジェクトのリストです（*transform* \"\n\"に応じて異なります）。各リスト項目は、ページ上の画像の1つの場所を表します。:meth:`Page.get_image_bbox` \"\n\"では複数の出現を検出できない場合があります。\"\n\n#: ../../page.rst:1757 db0c1992b2224619af8e0a8bb266e3b1\nmsgid \"\"\n\"The method invokes :meth:`Page.get_image_info` with `xrefs=True` and \"\n\"therefore has a noticeably longer response time than \"\n\":meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\"このメソッドは、`xrefs=True` で :meth:`Page.get_image_info` \"\n\"を呼び出すため、:meth:`Page.get_image_bbox` よりも明らかに長い応答時間がかかります。\"\n\n#: ../../page.rst:1759 78a2677113da42d5bd78cf20c9620dbd\nmsgid \"\"\n\"an item of the list :meth:`Page.get_images`, or the reference **name** \"\n\"entry of such an item (item[7]), or the image :data:`xref`.\"\nmsgstr \"\"\n\":meth:`Page.get_images` のリストアイテム、そのようなアイテムの参照 **name** \"\n\"エントリ（item[7]）、または画像の :data:`xref`。\"\n\n#: ../../page.rst:1760 31656212bb61408a979a149a7a68a16a\nmsgid \"\"\n\"also return the matrix used to transform the image rectangle to the bbox \"\n\"on the page. If true, then tuples `(bbox, matrix)` are returned.\"\nmsgstr \"画像の矩形をbboxに変換するために使用される行列も返すかどうか。trueの場合、タプル `(bbox, matrix)` が返されます。\"\n\n#: ../../page.rst:1763 60ceecb376bd4029a4ab81a98b09e532\nmsgid \"\"\n\"Boundary boxes and respective transformation matrices for each image \"\n\"occurrence on the page. If the item is not on the page, an empty list \"\n\"`[]` is returned.\"\nmsgstr \"ページ上の各画像出現に対する境界ボックスとそれに対応する変換行列。アイテムがページ上にない場合、空のリスト `[]`  が返されます。\"\n\n#: ../../page.rst:1767 15d195e0ae454a65b7d0197c769e3ce8\n#, fuzzy\nmsgid \"New in v1.18.13\"\nmsgstr \"*v1.18.13で新規追加*\"\n\n#: ../../page.rst:1777 94b1ab0ccf4f48ec8d1cb13b3f36d800\nmsgid \"\"\n\"PDF only: Return boundary box and transformation matrix of an embedded \"\n\"image.\"\nmsgstr \"PDFのみ：埋め込まれたイメージの境界ボックスと変換行列を返します。\"\n\n#: ../../page.rst:1779 8e645372dbf647aeb56ff450edaebd00\nmsgid \"\"\n\"an item of the list :meth:`Page.get_images` with *full=True* specified, \"\n\"or the reference **name** entry of such an item, which is item[-3] (or \"\n\"item[7] respectively).\"\nmsgstr \"\"\n\":meth:`Page.get_images` のリストのアイテムで *full=True* \"\n\"が指定されているもの、またはそのようなアイテムの参照名 **name**  エントリ、つまりitem[-3]（またはitem[7]）。\"\n\n#: ../../page.rst:1780 428845107f2c47e2abc7f576c506ed08\nmsgid \"\"\n\"return the matrix used to transform the image rectangle to the bbox on \"\n\"the page (new in v1.18.11). Default is just the bbox. If true, then a \"\n\"tuple `(bbox, matrix)` is returned.\"\nmsgstr \"\"\n\"*(v1.18.11で新規)* イメージの矩形をページのbboxに変換するために使用される行列も返すかどうか。デフォルトはbboxのみです。 \"\n\"trueの場合、タプル `(bbox, matrix)` が返されます。\"\n\n#: ../../page.rst:1782 819ebb0f28364cdcba4fbe7ca98bd2d4\nmsgid \":ref:`Rect` or (:ref:`Rect`, :ref:`Matrix`)\"\nmsgstr \":ref:`Rect` または（:ref:`Rect`、:ref:`Matrix`）\"\n\n#: ../../page.rst:1783 ee52dd3a62a6439abd4fda83efaf8d5f\nmsgid \"\"\n\"the boundary box of the image -- optionally also its transformation \"\n\"matrix.  |history_begin|  * (Changed in v1.16.7): If the page in fact \"\n\"does not display this image, an infinite rectangle is returned now. In \"\n\"previous versions, an exception was raised. Formally invalid parameters \"\n\"still raise exceptions. * (Changed in v1.17.0): Only images referenced \"\n\"directly by the page are considered. This means that images occurring in \"\n\"embedded PDF pages are ignored and an exception is raised. * (Changed in \"\n\"v1.18.5): Removed the restriction introduced in v1.17.0: any item of the \"\n\"page's image list may be specified. * (Changed in v1.18.11): Partially \"\n\"re-instated a restriction: only those images are considered, that are \"\n\"either directly referenced by the page or by a Form XObject directly \"\n\"referenced by the page. * (Changed in v1.18.11): Optionally also return \"\n\"the transformation matrix together with the bbox as the tuple `(bbox, \"\n\"transform)`.  |history_end|\"\nmsgstr \"\"\n\n#: ../../page.rst:1783 a7f8641e4ad14324ac60e051d749d295\nmsgid \"\"\n\"the boundary box of the image -- optionally also its transformation \"\n\"matrix.\"\nmsgstr \"イメージの境界ボックス - オプションでその変換行列も。\"\n\n#: ../../page.rst:1787 9e1a1ef665584353a75fb92c8bafa923\n#, fuzzy\nmsgid \"\"\n\"(Changed in v1.16.7): If the page in fact does not display this image, an\"\n\" infinite rectangle is returned now. In previous versions, an exception \"\n\"was raised. Formally invalid parameters still raise exceptions.\"\nmsgstr \"\"\n\"*(v1.16.7で変更)* \"\n\"–実際にはこのイメージを表示していない場合、無限の矩形が返されるようになりました。以前のバージョンでは、例外が発生しました。形式的に無効なパラメータは引き続き例外を発生させます。\"\n\n#: ../../page.rst:1788 ad45cfaae88845f6b9ecf0120285e6e9\n#, fuzzy\nmsgid \"\"\n\"(Changed in v1.17.0): Only images referenced directly by the page are \"\n\"considered. This means that images occurring in embedded PDF pages are \"\n\"ignored and an exception is raised.\"\nmsgstr \"\"\n\"*(v1.17.0で変更)* \"\n\"–ページで直接参照されているイメージのみが考慮されます。これは、埋め込まれたPDFページに存在するイメージは無視され、例外が発生します。\"\n\n#: ../../page.rst:1789 de570fe3dafb4fd99deff2899b6c1fc0\n#, fuzzy\nmsgid \"\"\n\"(Changed in v1.18.5): Removed the restriction introduced in v1.17.0: any \"\n\"item of the page's image list may be specified.\"\nmsgstr \"*(v1.18.5で変更)* –v1.17.0で導入された制限を削除しました：ページのイメージリストの任意のアイテムを指定できます。\"\n\n#: ../../page.rst:1790 e303c4b6b12a4d76a7a5f2c788dcb37e\n#, fuzzy\nmsgid \"\"\n\"(Changed in v1.18.11): Partially re-instated a restriction: only those \"\n\"images are considered, that are either directly referenced by the page or\"\n\" by a Form XObject directly referenced by the page.\"\nmsgstr \"\"\n\"*(v1.18.11で変更)* \"\n\"–一部の制限を部分的に再導入しました：ページで直接参照されるイメージまたはページで直接参照されるフォームXObjectによって参照されるイメージのみが考慮されます。\"\n\n#: ../../page.rst:1791 bc011ef28d61422a955614e4c2d8dc86\n#, fuzzy\nmsgid \"\"\n\"(Changed in v1.18.11): Optionally also return the transformation matrix \"\n\"together with the bbox as the tuple `(bbox, transform)`.\"\nmsgstr \"*(v1.18.11で変更)* –オプションでbboxと一緒に変換行列も返すことができます（タプルとして）。\"\n\n#: ../../page.rst:1797 bcfcaef3b1814721b638515684f8d52c\nmsgid \"\"\n\"Be aware that :meth:`Page.get_images` may contain \\\"dead\\\" entries i.e. \"\n\"images, which the page **does not display**. This is no error, but \"\n\"intended by the PDF creator. No exception will be raised in this case, \"\n\"but an infinite rectangle is returned. You can avoid this from happening \"\n\"by executing :meth:`Page.clean_contents` before this method.\"\nmsgstr \"\"\n\":meth:`Page.get_images` \"\n\"には「不要な」エントリが含まれている場合があることに注意してください。これはPDF作成者によって意図的に設定されたものであり、エラーではありません。この場合、例外は発生しませんが、無限の矩形が返されます。このような状況を回避するには、このメソッドの前に\"\n\" :meth:`Page.clean_contents` を実行することができます。\"\n\n#: ../../page.rst:1798 49d027f793a94bafb910acbfe3e05a8b\nmsgid \"\"\n\"The image's \\\"transformation matrix\\\" is defined as the matrix, for which\"\n\" the expression `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` is true, \"\n\"lookup details here: :ref:`ImageTransformation`.\"\nmsgstr \"\"\n\"イメージの「変換行列」は、`bbox / transform == pymupdf.Rect(0, 0, 1, 1)` \"\n\"という式が真であるための行列であり、詳細はこちらを参照してください：:ref:`ImageTransformation`。\"\n\n#: ../../page.rst:1802 70224468b38f44aebf1c2a1d3af4a178\nmsgid \"Changed in v1.18.11: return image transformation matrix\"\nmsgstr \"変更点 v1.18.11：イメージの変換行列を返すようになりました\"\n\n#: ../../page.rst:1811 d3e86ad4c19a4d3292c0d4ddac497b97\nmsgid \"\"\n\"Create an SVG image from the page. Only full page images are currently \"\n\"supported.\"\nmsgstr \"ページからSVGイメージを作成します。現在、フルページのイメージのみがサポートされています。\"\n\n#: ../../page.rst:1813 1eff949fcbd24567ac700df17d5c59c4\nmsgid \"a matrix, default is :ref:`Identity`.\"\nmsgstr \"行列、デフォルトは :ref:`Identity` です。\"\n\n#: ../../page.rst:1814 df2f3c9f709a489c9ca5f91abbc6b312\nmsgid \"\"\n\"-- controls how text is represented. ``True`` outputs each character as a\"\n\" series of elementary draw commands, which leads to a more precise text \"\n\"display in browsers, but a **very much larger** output for text-oriented \"\n\"pages. Display quality for ``False`` relies on the presence of the \"\n\"referenced fonts on the current system. For missing fonts, the internet \"\n\"browser will fall back to some default -- leading to unpleasant \"\n\"appearances. Choose ``False`` if you want to parse the text of the SVG. \"\n\"(New in v1.17.5)\"\nmsgstr \"\"\n\"テキストの表現方法を制御します。``True`` \"\n\"は、各文字を一連の基本的な描画コマンドとして出力し、これによりブラウザでのテキスト表示がより正確になりますが、テキスト指向のページの場合、非常に大きな出力になります。``False``\"\n\" \"\n\"の場合、表示品質は現在のシステムに参照されるフォントの存在に依存します。欠落しているフォントの場合、インターネットブラウザはいくつかのデフォルトにフォールバックします\"\n\" -- これにより見栄えが悪くなります。SVGのテキストを解析したい場合は ``False`` を選択してください。(v1.17.5で新規追加)\"\n\n#: ../../page.rst:1816 255d76aeb25540379f4e2750fc40476e\nmsgid \"\"\n\"a UTF-8 encoded string that contains the image. Because SVG has XML \"\n\"syntax it can be saved in a text file, the standard extension is `.svg`.\"\n\"  .. note:: In case of a PDF, you can circumvent the \\\"full page image \"\n\"only\\\" restriction by modifying the page's CropBox before using the \"\n\"method.\"\nmsgstr \"\"\n\n#: ../../page.rst:1816 d70d0e09fa10457c899a88af18ac233f\nmsgid \"\"\n\"a UTF-8 encoded string that contains the image. Because SVG has XML \"\n\"syntax it can be saved in a text file, the standard extension is `.svg`.\"\nmsgstr \"\"\n\"UTF-8エンコードされた文字列で、イメージを含みます。 SVGにはXML構文があるため、テキストファイルに保存でき、標準の拡張子は `.svg`\"\n\" です。\"\n\n#: ../../page.rst:1818 2038b89974854ccb915bf35207525477\nmsgid \"\"\n\"In case of a PDF, you can circumvent the \\\"full page image only\\\" \"\n\"restriction by modifying the page's CropBox before using the method.\"\nmsgstr \"PDFの場合、メソッドを使用する前に、ページのCropBoxを変更して「フルページイメージのみ」制限を回避できます。\"\n\n#: ../../page.rst:1830 49256f649c7340c2b5790800b7a54e49\nmsgid \"\"\n\"Create a pixmap from the page. This is probably the most often used \"\n\"method to create a :ref:`Pixmap`.\"\nmsgstr \"ページからピクスマップを作成します。おそらく、:ref:`Pixmap` を作成するために最も頻繁に使用されるメソッドでしょう。\"\n\n#: ../../page.rst:1832 05f2f80f7ace4f0f8eb70cf8231a45fb\nmsgid \"All parameters are *keyword-only.*\"\nmsgstr \"すべてのパラメータは *keyword-only.* です。\"\n\n#: ../../page.rst:1834 3aff081d3a1d4330a5efbb941d465d5d\nmsgid \"default is :ref:`Identity`.\"\nmsgstr \"デフォルトは :ref:`Identity` です。\"\n\n#: ../../page.rst:1835 13d257c5df27414c9c926dad92e8d2b4\n#, fuzzy\nmsgid \"\"\n\"desired resolution in x and y direction. If not `None`, the `\\\"matrix\\\"` \"\n\"parameter is ignored. (New in v1.19.2)\"\nmsgstr \"(v1.19.2で新たに追加) x方向およびy方向の所望の解像度。`None` でない場合、`\\\"matrix\\\"` パラメータは無視されます。\"\n\n#: ../../page.rst:1836 eff39884626a45f0af6b14007330fc96\nmsgid \"\"\n\"The desired colorspace, one of \\\"GRAY\\\", \\\"RGB\\\" or \\\"CMYK\\\" (case \"\n\"insensitive). Or specify a :ref:`Colorspace`, ie. one of the predefined \"\n\"ones: :data:`csGRAY`, :data:`csRGB` or :data:`csCMYK`.\"\nmsgstr \"\"\n\"所望のカラースペース、\\\"GRAY\\\"、\\\"RGB\\\"、または\\\"CMYK\\\"のいずれか（大文字/小文字を区別しない）。または、:ref:`Colorspace`\"\n\" のように、事前定義されたもののいずれかを指定できます：:data:`csGRAY`、:data:`csRGB`、:data:`csCMYK`。\"\n\n#: ../../page.rst:1838 8dda6eb66c8a4a9dbb71d8d35094999d\nmsgid \"\"\n\"restrict rendering to the intersection of this area with the page's \"\n\"rectangle.\"\nmsgstr \"ページの矩形とこの領域の交差に描画を制限します。\"\n\n#: ../../page.rst:1839 0f258e14c9804c39ad177677aeda8455\n#, fuzzy, python-format\nmsgid \"\"\n\"whether to add an alpha channel. Always accept the default ``False`` if \"\n\"you do not really need transparency. This will save a lot of memory (25% \"\n\"in case of RGB ... and pixmaps are typically **large**!), and also \"\n\"processing time. Also note an **important difference** in how the image \"\n\"will be rendered: with ``True`` the pixmap's samples area will be pre-\"\n\"cleared with *0x00*. This results in **transparent** areas where the page\"\n\" is empty. With ``False`` the pixmap's samples will be pre-cleared with \"\n\"*0xff*. This results in **white** where the page has nothing to show.  \"\n\"|history_begin|  Changed in v1.14.17   The default alpha value is now \"\n\"``False``.    * Generated with *alpha=True*    .. image:: images/img-\"\n\"alpha-1.*     * Generated with *alpha=False*    .. image:: images/img-\"\n\"alpha-0.*  |history_end|\"\nmsgstr \"\"\n\"透明チャネルを追加するかどうか。本当に透明性が必要でない場合は、常にデフォルトの ``False`` \"\n\"を受け入れてください。これにより、メモリ（RGBの場合25％…ピクスマップは通常大きいです！）と処理時間が大幅に節約されます。また、画像がレンダリングされる方法についても重要な違いに注意してください：\"\n\" ``True``  \"\n\"の場合、ピクスマップのサンプル領域は0x00で事前クリアされます。これにより、ページが空白の場所には透明な領域が表示されます。Falseの場合、ピクスマップのサンプルは\"\n\" *0xff* で事前クリアされます。これにより、ページに表示する内容がない場所には  **white** が表示されます。\"\n\n#: ../../page.rst:1839 9ed06c39712e4b0c9b1ef2b9190ad178\n#, python-format\nmsgid \"\"\n\"whether to add an alpha channel. Always accept the default ``False`` if \"\n\"you do not really need transparency. This will save a lot of memory (25% \"\n\"in case of RGB ... and pixmaps are typically **large**!), and also \"\n\"processing time. Also note an **important difference** in how the image \"\n\"will be rendered: with ``True`` the pixmap's samples area will be pre-\"\n\"cleared with *0x00*. This results in **transparent** areas where the page\"\n\" is empty. With ``False`` the pixmap's samples will be pre-cleared with \"\n\"*0xff*. This results in **white** where the page has nothing to show.\"\nmsgstr \"\"\n\"透明チャネルを追加するかどうか。本当に透明性が必要でない場合は、常にデフォルトの ``False`` \"\n\"を受け入れてください。これにより、メモリ（RGBの場合25％…ピクスマップは通常大きいです！）と処理時間が大幅に節約されます。また、画像がレンダリングされる方法についても重要な違いに注意してください：\"\n\" ``True``  \"\n\"の場合、ピクスマップのサンプル領域は0x00で事前クリアされます。これにより、ページが空白の場所には透明な領域が表示されます。Falseの場合、ピクスマップのサンプルは\"\n\" *0xff* で事前クリアされます。これにより、ページに表示する内容がない場所には  **white** が表示されます。\"\n\n#: ../../page.rst:1853 99981aa2da1b40108adc66b7b571c447\nmsgid \"Changed in v1.14.17\"\nmsgstr \"v1.14.17で変更されました\"\n\n#: ../../page.rst:1844 62f1b49c3dd141c7a8ef0c9daff44467\nmsgid \"The default alpha value is now ``False``.\"\nmsgstr \"デフォルトのalpha値は ``False`` になりました。\"\n\n#: ../../page.rst:1846 5166a6cd936e46849e89ded514dbdb2e\nmsgid \"Generated with *alpha=True*\"\nmsgstr \"*alpha=True* で生成されたもの\"\n\n#: ../../page.rst:1851 6528d1cab5cc405bb3b064f7c9215219\nmsgid \"Generated with *alpha=False*\"\nmsgstr \"*alpha=False* で生成されたもの\"\n\n#: ../../page.rst:1857 d7ad01e00ec4466ca4c6561aac481fdc\nmsgid \"\"\n\"*(new in version 1.16.0)* whether to also render annotations or to \"\n\"suppress them. You can create pixmaps for annotations separately.\"\nmsgstr \"*(v1.16.0で新たに追加)* アノテーションをレンダリングするか抑制するか。注釈用に個別にピクスマップを作成できます。\"\n\n#: ../../page.rst:1859 7bfc8bde1fbc42ba9c5adf955fb5f6fe\nmsgid \":ref:`Pixmap`\"\nmsgstr \"\"\n\n#: ../../page.rst:1860 1036350ef4604f60bc3bfb184510331d\nmsgid \"\"\n\"Pixmap of the page. For fine-controlling the generated image, the by far \"\n\"most important parameter is **matrix**. E.g. you can increase or decrease\"\n\" the image resolution by using **Matrix(xzoom, yzoom)**. If zoom > 1, you\"\n\" will get a higher resolution: zoom=2 will double the number of pixels in\"\n\" that direction and thus generate a 2 times larger image. Non-positive \"\n\"values will flip horizontally, resp. vertically. Similarly, matrices also\"\n\" let you rotate or shear, and you can combine effects via e.g. matrix \"\n\"multiplication. See the :ref:`Matrix` section to learn more.\"\nmsgstr \"\"\n\"ページのピクスマップ。生成されたイメージを細かく制御するために、最も重要なパラメータは **matrix** \"\n\"です。たとえば、Matrix(xzoom, yzoom)を使用してイメージの解像度を増減させることができます。zoom > \"\n\"1の場合、より高い解像度が得られ、zoom=2はその方向のピクセル数を2倍にし、したがって2倍の大きさのイメージを生成します。非正の値は水平または垂直に反転させます。同様に、行列は回転やシアーも可能にし、行列の乗算を介して効果を組み合わせることもできます。詳細については、:ref:`Matrix`\"\n\" セクションをご覧ください。\"\n\n#: ../../page.rst:1864 e709657156c54e5da49e39a889d755f4\nmsgid \"\"\n\"The pixmap will have *\\\"premultiplied\\\"* pixels if `alpha=True`. To learn\"\n\" about some background, e.g. look for \\\"Premultiplied alpha\\\" `here \"\n\"<https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\"\nmsgstr \"\"\n\n#: ../../page.rst:1866 dc63977f417c4d669f251e232b7449ef\nmsgid \"\"\n\"The method will respect any page rotation and will not exceed the \"\n\"intersection of `clip` and :attr:`Page.cropbox`. If you need the page's \"\n\"mediabox (and if this is a different rectangle), you can use a snippet \"\n\"like the following to achieve this::\"\nmsgstr \"\"\n\"このメソッドはページの回転を尊重し、`clip` と :attr:`Page.cropbox` \"\n\"の交差を超えません。ページのmediaboxが必要な場合（およびこれが異なる矩形の場合）、次のようなスニペットを使用してこれを実現できます::\"\n\n#: ../../page.rst:1884 fe786b6a9efe4d3c8dae1c2c34a4d27b\nmsgid \"Changed in v1.19.2: added support of parameter dpi.\"\nmsgstr \"v1.19.2で変更：dpiパラメータのサポートを追加。\"\n\n#: ../../page.rst:1892 caeb4aa2a305433fa72d601d086e5dcc\nmsgid \"\"\n\"PDF only: return a list of the names of annotations, widgets and links. \"\n\"Technically, these are the */NM* values of every PDF object found in the \"\n\"page's */Annots*  array.\"\nmsgstr \"\"\n\"PDFのみ：アノテーション、ウィジェット、およびリンクの名前のリストを返します。技術的には、これらはページの */Annots*  \"\n\"配列で見つかるすべてのPDFオブジェクトの */NM* 値です。\"\n\n#: ../../page.rst:1898 0699ea9e43f8424985dc482f87ffd38f\nmsgid \"New in v1.16.10\"\nmsgstr \"新機能 v1.16.10\"\n\n#: ../../page.rst:1905 d7384e93d12547c486263203beb5df89\nmsgid \"\"\n\"PDF only: return a list of the :data:`xref` numbers of annotations, \"\n\"widgets and links -- technically of all entries found in the page's \"\n\"*/Annots*  array.\"\nmsgstr \"\"\n\"PDFのみ：アノテーション、ウィジェット、およびリンクの :data:`xref` \"\n\"番号のリストを返します。技術的には、これらはページの/Annots配列で見つかるすべてのエントリのxrefです。\"\n\n#: ../../page.rst:1908 5b6f31dd87454760829a55acc10e55e4\nmsgid \"\"\n\"a list of items *(xref, type)* where type is the annotation type. Use the\"\n\" type to tell apart links, fields and annotations, see \"\n\":ref:`AnnotationTypes`.\"\nmsgstr \"\"\n\"xref、タイプがアノテーションのタイプであるアイテム *(xref, type)* \"\n\"のリスト。リンク、フィールド、およびアノテーションを区別するためにタイプを使用します。:ref:`AnnotationTypes` \"\n\"を参照してください。\"\n\n#: ../../page.rst:1912 ../../page.rst:1930 4b1840a2328c4c0491ae53e88e80dc76\n#: b332754a68c4477fab234d683f4ccc96\nmsgid \"New in v1.17.1\"\nmsgstr \"新機能 v1.17.1\"\n\n#: ../../page.rst:1919 53ebddaf93d34d5f9f69386f293f9c73\nmsgid \"\"\n\"PDF only: return the annotation identified by *ident*. This may be its \"\n\"unique name (PDF `/NM` key), or its :data:`xref`.\"\nmsgstr \"PDFのみ：*ident* で識別されるアノテーションを返します。これはその一意の名前（PDF `/NM` キー）またはxrefかもしれません。\"\n\n#: ../../page.rst:1921 afb025534f664db7ad9db85c38f9072f\nmsgid \"the annotation name or xref.\"\nmsgstr \"アノテーションの名前またはxref。\"\n\n#: ../../page.rst:1924 91e98027fa814f2480abca950000bf48\nmsgid \"the annotation or ``None``.\"\nmsgstr \"アノテーションまたは ``None``。\"\n\n#: ../../page.rst:1926 32f21d6698f1497e83db2ebea1787d39\nmsgid \"\"\n\"Methods :meth:`Page.annot_names`, :meth:`Page.annot_xrefs` provide lists \"\n\"of names or xrefs, respectively, from where an item may be picked and \"\n\"loaded via this method.\"\nmsgstr \"\"\n\"メソッド :meth:`Page.annot_names`、:meth:`Page.annot_xrefs` \"\n\"は、アイテムが取得およびこのメソッドを介して読み込まれる名前またはxrefのリストを提供します。\"\n\n#: ../../page.rst:1936 cca236bad55648c5a810e50ea814bd7f\nmsgid \"PDF only: return the field identified by :data:`xref`.\"\nmsgstr \"PDFのみ：:data:`xref` で識別されるフィールドを返します。\"\n\n#: ../../page.rst:1938 d134928d1cc946309ab62309be76ed11\nmsgid \"the field's xref.\"\nmsgstr \"フィールドのxref。\"\n\n#: ../../page.rst:1941 41e62df3bd46456bab6e1244b57e31a7\nmsgid \"the field or ``None``.\"\nmsgstr \"フィールドまたは ``None``。\"\n\n#: ../../page.rst:1943 9c8f4697de594066ae8f9cee0e8400f5\nmsgid \"\"\n\"This is similar to the analogous method :meth:`Page.load_annot` -- except\"\n\" that here only the xref is supported as identifier.\"\nmsgstr \"これはメソッド :meth:`Page.load_annot` と同様ですが、ここでは識別子としてxrefのみがサポートされています。\"\n\n#: ../../page.rst:1947 9edc19c825ad440887b7caf99bc36ec3\nmsgid \"New in v1.19.6\"\nmsgstr \"新機能 v1.19.6\"\n\n#: ../../page.rst:1953 ad01580beaea437fbd1d6157e0f3a623\nmsgid \"Return the first link on a page. Synonym of property :attr:`first_link`.\"\nmsgstr \"最初のリンクを返します。プロパティ :attr:`first_link` の同義語です。\"\n\n#: ../../page.rst:1955 ../../page.rst:2252 a74924baab27499ea18455c3c6910571\n#: dc342a221f14447d8a7417d1c20a4cc1\nmsgid \":ref:`Link`\"\nmsgstr \"\"\n\n#: ../../page.rst:1956 dee7a33cc0c84aa0b6adfd89805d64e8\nmsgid \"first link on the page (or ``None``).\"\nmsgstr \"ページ上の最初のリンク（または ``None``）。\"\n\n#: ../../page.rst:1963 eb961b30b31c4afa82d2e0317201406b\nmsgid \"PDF only: Set the rotation of the page.\"\nmsgstr \"PDFのみ：ページの回転を設定します。\"\n\n#: ../../page.rst:1965 469042c9d56641299b3be924dd53d60b\nmsgid \"\"\n\"An integer specifying the required rotation in degrees. Must be an \"\n\"integer multiple of 90. Values will be converted to one of 0, 90, 180, \"\n\"270.\"\nmsgstr \"度数で指定された必要な回転を表す整数。90の整数倍である必要があります。値は0、90、180、270のいずれかに変換されます。\"\n\n#: ../../page.rst:1969 227ee516ba554a0cb14b99795c5e0a9f\n#, fuzzy\nmsgid \"PDF only: Change the colorspace components of all objects on page.\"\nmsgstr \"PDFのみ: ページの表示領域を変更します。\"\n\n#: ../../page.rst:1971 d2515f60d6af4e17a82832e769938548\nmsgid \"\"\n\"The desired count of color components. Must be one of 1, 3 or 4, which \"\n\"results in color spaces DeviceGray, DeviceRGB or DeviceCMYK respectively.\"\n\" The method affects text, images and vector graphics. For instance, with \"\n\"the default value 1, a page will be converted to grayscale. If a page is \"\n\"already grayscale, the method will not cause visible changes -- \"\n\"independent of the value of ``components``.\"\nmsgstr \"\"\n\n#: ../../page.rst:1973 dd674046551f4c3cb79fef4fa79b7b15\nmsgid \"These changes are **permanent** and cannot be reverted.\"\nmsgstr \"\"\n\n#: ../../page.rst:1977 9095c069ad1649f98d53bd1aaff0c92c\nmsgid \"\"\n\"PDF only: Permanently remove page content outside the given rectangle. \"\n\"This is similar to :meth:`Page.set_cropbox`, but the page's rectangle \"\n\"will not be changed, only the content outside the rectangle will be \"\n\"removed.\"\nmsgstr \"\"\n\n#: ../../page.rst:1979 37a6c35649b145f08a5decf125e56bf2\n#, fuzzy\nmsgid \"\"\n\"The rectangle to clip to. Must be finite and its intersection with the \"\n\"page must not be empty.\"\nmsgstr \"現在のページに画像を配置する場所。有限である必要があり、ページとの交差部分が空でない必要があります。\"\n\n#: ../../page.rst:1981 9347d32590004624ad7e93346a5d559f\nmsgid \"\"\n\"The method works best for text: All text on the page will be removed \"\n\"(decided by single character) that has no intersection with the \"\n\"rectangle. For vector graphics, the method will remove all paths that \"\n\"have no intersection with the rectangle. For images, the method will \"\n\"remove all images that have no intersection with the rectangle. Vectors \"\n\"and images **having** an intersection with the rectangle, will be kept in\"\n\" their entirety.\"\nmsgstr \"\"\n\n#: ../../page.rst:1983 f6a3ae3f011144d49017e42c7f6d1b6b\nmsgid \"\"\n\"The method roughly has the same effect as if four redactions had been \"\n\"applied that cover the rectangle's outside.\"\nmsgstr \"\"\n\n#: ../../page.rst:1985 ae033183ff37421bbbd56e4a52f60bd2\n#, fuzzy\nmsgid \"New in v1.26.4.\"\nmsgstr \"v1.16.4で新規追加\"\n\n#: ../../page.rst:1989 1f930abbc15c4ff89b61da8eff5ec500\nmsgid \"\"\n\"PDF only: Set page rotation to 0 while maintaining appearance and page \"\n\"content.\"\nmsgstr \"PDFのみ：外観とページ内容を維持しながらページの回転を0に設定します。\"\n\n#: ../../page.rst:1991 30ffde127f4745dab1c91c8d166bf86b\nmsgid \"\"\n\"The inverted matrix used to achieve this change. If the page was not \"\n\"rotated (rotation 0), :ref:`Identity` is returned. The method \"\n\"automatically recomputes the rectangles of any annotations, links and \"\n\"widgets present on the page.  This method may come in handy when e.g. \"\n\"used with :meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\"この変更を実現するために使用される反転した行列。ページが回転していない場合（回転0）、:ref:`Identity` \"\n\"が返されます。メソッドは、ページに存在するアノテーション、リンク、およびウィジェットの矩形を自動的に再計算します\"\n\n#: ../../page.rst:1991 33e0bd938fe84b5c8783dcfdf5544ae7\nmsgid \"\"\n\"The inverted matrix used to achieve this change. If the page was not \"\n\"rotated (rotation 0), :ref:`Identity` is returned. The method \"\n\"automatically recomputes the rectangles of any annotations, links and \"\n\"widgets present on the page.\"\nmsgstr \"\"\n\"この変更を実現するために使用される反転した行列。ページが回転していない場合（回転0）、:ref:`Identity` \"\n\"が返されます。メソッドは、ページに存在するアノテーション、リンク、およびウィジェットの矩形を自動的に再計算します。\"\n\n#: ../../page.rst:1993 2da47a2010e34b029e3f0edff15b2ea6\nmsgid \"\"\n\"This method may come in handy when e.g. used with \"\n\":meth:`Page.show_pdf_page`.\"\nmsgstr \"このメソッドは、たとえば :meth:`Page.show_pdf_page` と一緒に使用する場合に便利です。\"\n\n#: ../../page.rst:2003 8097fb4ce62d438a9173044458d89700\nmsgid \"\"\n\"PDF only: Display a page of another PDF. This is similar to \"\n\":meth:`Page.insert_image` but the source page will appear like a copy of \"\n\"itself and will not be rasterized. This is a multi-purpose method. For \"\n\"example, you can use it to:\"\nmsgstr \"\"\n\n#: ../../page.rst:2005 a3de5ee714974a4bbc3c15d6db7c596e\nmsgid \"\"\n\"create \\\"n-up\\\" versions of existing PDF files, combining several input \"\n\"pages into **one output page** (see example `combine.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/combine-pages/combine.py>`_),\"\nmsgstr \"\"\n\"既存のPDFファイルの「n-up」バージョンを作成し、複数の入力ページを1つの出力ページに結合します（例： `combine.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/combine-pages/combine.py>`_ を参照）。\"\n\n#: ../../page.rst:2006 56a92497a6424d06ac1dc154b2b7c2e3\nmsgid \"\"\n\"create \\\"posterized\\\" PDF files, i.e. every input page is split up in \"\n\"parts which each create a separate output page (see `posterize.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/posterize-document/posterize.py>`_),\"\nmsgstr \"\"\n\"「ポスター化」されたPDFファイルを作成します。つまり、各入力ページは別々の出力ページを作成する部分に分割されます（`posterize.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/posterize-document/posterize.py>`_ を参照）。\"\n\n#: ../../page.rst:2007 809839e89a244a85af528e2781c72346\n#, fuzzy\nmsgid \"\"\n\"include PDF-based vector images like company logos, watermarks, etc., see\"\n\" `svg-logo.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/examples/svg-logo.py>`_, which puts an SVG-based \"\n\"logo on each page.\"\nmsgstr \"\"\n\"企業のロゴ、透かし画像など、PDFベースのベクトル画像を含めます。`svg-logo.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/examples/svg-logo.py>`_ \"\n\"は、各ページにSVGベースのロゴを配置します（SVGからPDFへの変換を処理するために追加のパッケージが必要です）。\"\n\n#: ../../page.rst:2009 94e420eeb95544848178411930596331\nmsgid \"\"\n\"where to place the image on current page. Must be finite and its \"\n\"intersection with the page must not be empty.\"\nmsgstr \"現在のページに画像を配置する場所。有限である必要があり、ページとの交差部分が空でない必要があります。\"\n\n#: ../../page.rst:2010 4a518b41f0fa4d20a7ddfdacc3b5387e\nmsgid \"\"\n\"source PDF document containing the page. Must be a different document \"\n\"object, but may be the same file.\"\nmsgstr \"ページを含むソースPDFドキュメント。異なるドキュメントオブジェクトである必要がありますが、同じファイルであることもあります。\"\n\n#: ../../page.rst:2013 2258364ee77342648f9f9d13598d61a0\nmsgid \"page number (0-based, in `-∞ < pno < docsrc.page_count`) to be shown.\"\nmsgstr \"表示するページ番号（0から始まる、`-∞ < pno < docsrc.page_count`）。指定されたページ。\"\n\n#: ../../page.rst:2015 9eb0129dc8f54fb9976933c50276a085\nmsgid \"\"\n\"whether to maintain the width-height-ratio (default). If false, all 4 \"\n\"corners are always positioned on the border of the target rectangle -- \"\n\"whatever the rotation value. In general, this will deliver distorted and \"\n\"/or non-rectangular images.\"\nmsgstr \"幅高さ比率を維持するかどうか（デフォルト）。falseの場合、4つの角は常にターゲット矩形の境界に配置されます（回転値に関係なく）。一般的に、これは歪んだおよび/または非四角形の画像を提供します。\"\n\n#: ../../page.rst:2017 85f7fd026bd24e8da3654da5636d9989\nmsgid \"put image in foreground (default) or background.\"\nmsgstr \"画像を前景（デフォルト）または背景に配置します。\"\n\n#: ../../page.rst:2019 42fcaea11ef446568915be1f505467ee\nmsgid \"\"\n\"(:data:`xref`) make visibility dependent on this :data:`OCG` / \"\n\":data:`OCMD` (which must be defined in the target PDF) [#f9]_. (New in \"\n\"v1.18.3)\"\nmsgstr \"\"\n\"*(v1.18.3で新機能)* （:data:`xref`）この :data:`OCG` / :data:`OCMD` \"\n\"（ターゲットPDFで定義されている必要があります）に依存する可視性を作成します [#f9]_。\"\n\n#: ../../page.rst:2020 13030fbfedf34278a676f08d0826d36e\nmsgid \"\"\n\"show the source rectangle rotated by some angle. Any angle is supported \"\n\"(changed in v1.14.11). (New in v1.14.10)\"\nmsgstr \"*(v1.14.10で新機能)* ソースの矩形を一定の角度で表示します\"\n\n#: ../../page.rst:2022 149ad5f2cd814d68a80da796e0a382a0\nmsgid \"\"\n\"choose which part of the source page to show. Default is the full page, \"\n\"else must be finite and its intersection with the source page must not be\"\n\" empty.\"\nmsgstr \"表示するソースページの一部を選択します。デフォルトはフルページですが、有限である必要があり、ソースページとの交差部分が空でない必要があります。\"\n\n#: ../../page.rst:2024 b8efe161593647e58619c74b77cac9a2\n#, fuzzy\nmsgid \"\"\n\"In contrast to method :meth:`Document.insert_pdf`, this method does not \"\n\"copy annotations, widgets or links, so these objects are not included in \"\n\"the target [#f6]_. But all its **other resources (text, images, fonts, \"\n\"etc.)** will be imported into the current PDF. They will therefore appear\"\n\" in text extractions and in :meth:`get_fonts` and :meth:`get_images` \"\n\"lists -- even if they are not contained in the visible area given by \"\n\"*clip*.\"\nmsgstr \"\"\n\"メソッド :meth:`Document.insert_pdf` \"\n\"とは異なり、このメソッドは注釈、ウィジェット、リンクをコピーしないため、これらは対象に含まれません \"\n\"[#f6]_。ただし、その他のすべてのリソース（テキスト、画像、フォントなど）は現在のPDFにインポートされます。したがって、テキストの抽出と \"\n\":meth:`get_fonts` および :meth:`get_images` リストに表示されます。表示領域に含まれていなくても。\"\n\n#: ../../page.rst:2026 a57abb1f967d4c35b6e7d4beed87ad89\nmsgid \"Example: Show the same source page, rotated by 90 and by -90 degrees:\"\nmsgstr \"例：同じソースページを90度と-90度回転して表示します。\"\n\n#: ../../page.rst:2048 c1b751195e4c4efca470bedbe8800d2c\nmsgid \"\"\n\"Changed in v1.14.11: Parameter *reuse_xref* has been deprecated. Position\"\n\" the source rectangle centered in target rectangle. Any rotation angle is\"\n\" now supported.\"\nmsgstr \"v1.14.11で変更：パラメータreuse_xrefは非推奨となりました。ソースの矩形をターゲットの矩形の中央に配置します。任意の回転角度がサポートされます。\"\n\n#: ../../page.rst:2049 81f070423325403d8564dc51aabef7ff\nmsgid \"Changed in v1.18.3: New parameter `oc`.\"\nmsgstr \"v1.18.3で変更：新しいパラメータ `oc` が追加されました。\"\n\n#: ../../page.rst:2055 39c3b9e093904d029cf16873b12f7494\nmsgid \"PDF only: Create a new :ref:`Shape` object for the page.\"\nmsgstr \"PDFのみ：ページ用の新しい :ref:`Shape`  オブジェクトを作成します。\"\n\n#: ../../page.rst:2057 fa925ab7db3840c19b1f80067f7da55d\nmsgid \":ref:`Shape`\"\nmsgstr \"\"\n\n#: ../../page.rst:2058 6be44310501147678b1f55bb5578c9e3\nmsgid \"a new :ref:`Shape` to use for compound drawings. See description there.\"\nmsgstr \"複合描画に使用する新しい :ref:`Shape` オブジェクト。詳細はそちらの説明を参照してください。\"\n\n#: ../../page.rst:2069 a4ff3e983b264801b477b8f199b8e57b\nmsgid \"Search for *needle* on a page. Wrapper for :meth:`TextPage.search`.\"\nmsgstr \"ページ上で *needle* を検索します。:meth:`TextPage.search` のラッパーです。\"\n\n#: ../../page.rst:2071 73895714ee9e477299763e3cb38e6b55\nmsgid \"\"\n\"Text to search for. May contain spaces. Upper / lower case is ignored, \"\n\"but only works for ASCII characters: For example, \\\"COMPÉTENCES\\\" will \"\n\"not be found if needle is \\\"compétences\\\" -- \\\"compÉtences\\\" however \"\n\"will. Similar is true for German umlauts and the like.\"\nmsgstr \"検索対象のテキスト。スペースを含めることができます。大文字/小文字は無視されますが、ASCII文字に対してのみ機能します：たとえば、needleが「COMPÉTENCES」の場合、needleが「compétences」の場合には見つかりません。「compÉtences」の場合は見つかります。同様に、ドイツ語のウムラウトなどにも当てはまります。\"\n\n#: ../../page.rst:2072 002d648a94cf4efd970e8372efdfacc3\n#, fuzzy\nmsgid \"only search within this area. (New in v1.18.2)\"\nmsgstr \"*(v1.18.2で新規追加)* この領域内でのみ検索します。\"\n\n#: ../../page.rst:2073 76ceadd2652e4b9c8e90959e238bfc73\nmsgid \"Return object type :ref:`Quad` instead of :ref:`Rect`.\"\nmsgstr \"四角形の代わりに :ref:`Quad` オブジェクトのタイプを返します。\"\n\n#: ../../page.rst:2074 e6e8cb9ec29b4a5b839fca538d50fa20\nmsgid \"\"\n\"Control the data extracted by the underlying :ref:`TextPage`. By default,\"\n\" ligatures and white spaces are kept, and hyphenation [#f8]_ is detected.\"\nmsgstr \"\"\n\"基本となる :ref:`TextPage` によって抽出されるデータを制御します。デフォルトでは、リガチャと空白を保持し、ハイフン化 [#f8]_\"\n\" が検出されます。\"\n\n#: ../../page.rst:2075 06406f39a7c54d7fa2b7e1270314e74c\nmsgid \"\"\n\"use a previously created :ref:`TextPage`. This reduces execution time \"\n\"**significantly.** If specified, the 'flags' and 'clip' arguments are \"\n\"ignored. If omitted, a temporary textpage will be created. (New in \"\n\"v1.19.0)\"\nmsgstr \"\"\n\"以前に作成された :ref:`TextPage` （テキストページ）を使用します。これにより、実行時間が大幅に短縮されます。指定された場合、 \"\n\"'flags'および 'clip'引数は無視されます。省略された場合、一時的なテキストページが作成されます。 (v1.19.0で新規)\"\n\n#: ../../page.rst:2079 939066ea93704b6e8c1b0f3cf6d6c2aa\nmsgid \"\"\n\"A list of :ref:`Rect` or  :ref:`Quad` objects, each of which  -- \"\n\"**normally!** -- surrounds one occurrence of *needle*. **However:** if \"\n\"parts of *needle* occur on more than one line, then a separate item is \"\n\"generated for each these parts. So, if `needle = \\\"search string\\\"`, two \"\n\"rectangles may be generated.  |history_begin|  Changes in v1.18.2:  * \"\n\"There no longer is a limit on the list length (removal of the `hit_max` \"\n\"parameter). * If a word is **hyphenated** at a line break, it will still \"\n\"be found. E.g. the needle \\\"method\\\" will be found even if hyphenated as \"\n\"\\\"meth-od\\\" at a line break, and two rectangles will be returned: one \"\n\"surrounding \\\"meth\\\" (without the hyphen) and another one surrounding \"\n\"\\\"od\\\".  |history_end|\"\nmsgstr \"\"\n\n#: ../../page.rst:2081 c05f559f100049cea4ceda637e6a62d8\nmsgid \"\"\n\"A list of :ref:`Rect` or  :ref:`Quad` objects, each of which  -- \"\n\"**normally!** -- surrounds one occurrence of *needle*. **However:** if \"\n\"parts of *needle* occur on more than one line, then a separate item is \"\n\"generated for each these parts. So, if `needle = \\\"search string\\\"`, two \"\n\"rectangles may be generated.\"\nmsgstr \"\"\n\":ref:`Rect` または :ref:`Quad` \"\n\"オブジェクトのリストで、通常、needleの一致を1つ囲みます。ただし、needleの一部が複数の行にまたがる場合、それぞれの部分に対して別のアイテムが生成されます。したがって、`needle\"\n\" = \\\"search string\\\"` の場合、2つの四角形が生成される可能性があります。\"\n\n#: ../../page.rst:2085 a4fa930c59aa42a0aca0d7f145f57c91\n#, fuzzy\nmsgid \"Changes in v1.18.2:\"\nmsgstr \"**v1.18.2の変更点：**\"\n\n#: ../../page.rst:2087 34a34ce97b8c4692a917624a7ecdb810\nmsgid \"\"\n\"There no longer is a limit on the list length (removal of the `hit_max` \"\n\"parameter).\"\nmsgstr \"リストの長さに制限はもうありません（`hit_max` パラメータの削除）。\"\n\n#: ../../page.rst:2088 9a6ca09716d44c778fbec65e72e939e1\nmsgid \"\"\n\"If a word is **hyphenated** at a line break, it will still be found. E.g.\"\n\" the needle \\\"method\\\" will be found even if hyphenated as \\\"meth-od\\\" at\"\n\" a line break, and two rectangles will be returned: one surrounding \"\n\"\\\"meth\\\" (without the hyphen) and another one surrounding \\\"od\\\".\"\nmsgstr \"\"\n\"単語が行の区切りでハイフン化されている場合でも、検出されます。たとえば、needleが行の区切りで「meth-\"\n\"od」としてハイフン化されていても、「method」としてハイフン化されていない部分を囲む1つの四角形と、「od」としてハイフン化されていない部分を囲む別の四角形が返されます。\"\n\n#: ../../page.rst:2092 662052c0c33a4e73acb81cb5192fe61d\nmsgid \"\"\n\"The method supports multi-line text marker annotations: you can use the \"\n\"full returned list as **one single** parameter for creating the \"\n\"annotation.\"\nmsgstr \"このメソッドは、複数行のテキストマーカーアノテーションをサポートしており、返されたリスト全体を1つのパラメータとして使用してアノテーションを作成できます。\"\n\n#: ../../page.rst:2096 d72d3688d1fe45db834e99d826ea81cb\nmsgid \"\"\n\"There is a tricky aspect: the search logic regards **contiguous multiple \"\n\"occurrences** of *needle* as one: assuming *needle* is \\\"abc\\\", and the \"\n\"page contains \\\"abc\\\" and \\\"abcabc\\\", then only **two** rectangles will \"\n\"be returned, one for \\\"abc\\\", and a second one for \\\"abcabc\\\".\"\nmsgstr \"\"\n\"トリッキーな側面があります。検索ロジックは、連続した複数の *needle* の出現を1つと見なします。つまり、*needle*  \"\n\"が「abc」で、ページに「abc」と「abcabc」が含まれている場合、2つの矩形のみが返され、1つは「abc」に、もう1つは「abcabc」になります。\"\n\n#: ../../page.rst:2097 f5397b6783a14dba9b1af693cf68e148\nmsgid \"\"\n\"You can always use :meth:`Page.get_textbox` to check what text actually \"\n\"is being surrounded by each rectangle.\"\nmsgstr \"常に :meth:`Page.get_textbox` を使用して、各矩形で実際に囲まれているテキストを確認できます。\"\n\n#: ../../page.rst:2099 ebe71ed021b74b83bd40b6780f483fa1\nmsgid \"\"\n\"A feature repeatedly asked for is supporting **regular expressions** when\"\n\" specifying the `\\\"needle\\\"` string: **There is no way to do this.** If \"\n\"you need something in that direction, first extract text in the desired \"\n\"format and then subselect the result by matching with some regex pattern.\"\n\" Here is an example for matching words::\"\nmsgstr \"\"\n\"`\\\"needle\\\"` \"\n\"文字列を指定する際に正規表現をサポートする機能が何度も要求されていますが、これを行う方法はありません。この方向性の何かが必要な場合は、まず希望の形式でテキストを抽出し、それを正規表現パターンと一致させて結果をサブセレクトしてください。単語を一致させる例を以下に示します。\"\n\n#: ../../page.rst:2105 6bfe1b333a774f6484753f3cc3b8da11\nmsgid \"\"\n\"The `matches` list will contain the words matching the given pattern. In \"\n\"the same way you can select `span[\\\"text\\\"]` from the output of \"\n\"`page.get_text(\\\"dict\\\")`.\"\nmsgstr \"\"\n\"`matches`  リストには、指定されたパターンに一致する単語が含まれます。同様の方法で、`page.get_text(\\\"dict\\\")` \"\n\"の出力から `span[\\\"text\\\"]` を選択できます。\"\n\n#: ../../page.rst:2109 8c1e32a30f8c426abf7dd87f6070bb8d\nmsgid \"\"\n\"Changed in v1.18.2: added `clip` parameter. Remove `hit_max` parameter. \"\n\"Add default \\\"dehyphenate\\\".\"\nmsgstr \"v1.18.2で変更：`clip` パラメータを追加。`hit_max`  パラメータを削除。デフォルトの「デハイフェネート」を追加。\"\n\n#: ../../page.rst:2110 110f4cf460aa4ed6bec6ae04a6620637\nmsgid \"Changed in v1.19.0: added `textpage` parameter.\"\nmsgstr \"v1.19.0で変更：`textpage`  パラメータを追加。\"\n\n#: ../../page.rst:2117 313a785cdc6f421b99568769e2acd45e\nmsgid \"\"\n\"PDF only: Change the physical page dimension by setting :data:`mediabox` \"\n\"in the page's object definition.\"\nmsgstr \"PDFのみ: ページのオブジェクト定義内で :data:`mediabox` を設定することにより、物理ページの寸法を変更します。\"\n\n#: ../../page.rst:2119 8d1e74b016eb4617852f1fe9b546a5f9\nmsgid \"the new :data:`mediabox` value.\"\nmsgstr \"新しい :data:`mediabox` の値。\"\n\n#: ../../page.rst:2121 fc8bf8612c1b4ec497ac37834d417213\nmsgid \"\"\n\"This method also removes the page's other (optional) rectangles \"\n\"(:data:`cropbox`, ArtBox, TrimBox and Bleedbox) to prevent inconsistent \"\n\"situations. This will cause those to assume their default values.\"\nmsgstr \"このメソッドは、ページの他の（オプションの）矩形（:data:`cropbox`、ArtBox、TrimBox、Bleedbox）も削除し、一貫性のない状況を防ぐためにそれらをデフォルト値に戻します。\"\n\n#: ../../page.rst:2123 97c1c0ea8a6b47b2a9ddbc93131b0204\nmsgid \"\"\n\"For non-empty pages this may have undesired effects, because the location\"\n\" of all content depends on this value and will therefore change position \"\n\"or even disappear.\"\nmsgstr \"これにより、非空のページでは望ましくない効果が発生する可能性があるため、すべてのコンテンツの位置がこの値に依存し、したがって位置が変わるか、完全に消える可能性があります。\"\n\n#: ../../page.rst:2127 91c689a47be5437e8dac4417d5dd0848\nmsgid \"New in v1.16.13\"\nmsgstr \"v1.16.13で新規追加\"\n\n#: ../../page.rst:2128 877c5c9a76684e38a46ebe2fbcc5ca68\nmsgid \"Changed in v1.19.4: remove all other rectangle definitions.\"\nmsgstr \"v1.19.4で変更: 他のすべての矩形定義を削除しました。\"\n\n#: ../../page.rst:2135 14fdd70511ec4ff2913a0491f7678978\nmsgid \"PDF only: change the visible part of the page.\"\nmsgstr \"PDFのみ: ページの表示領域を変更します。\"\n\n#: ../../page.rst:2137 7fa9c11b08f441dc87a46fc4dbf98182\nmsgid \"\"\n\"the new visible area of the page. Note that this **must** be specified in\"\n\" **unrotated coordinates**, not empty, nor infinite and be completely \"\n\"contained in the :attr:`Page.mediabox`.\"\nmsgstr \"\"\n\"ページの新しい表示領域。これは回転していない座標で指定する必要があり、空ではなく、無限ではなく、:attr:`Page.mediabox` \"\n\"に完全に含まれている必要があります。\"\n\n#: ../../page.rst:2139 25df1b49bf0a4d80891be253a545cf76\nmsgid \"\"\n\"After execution **(if the page is not rotated)**, :attr:`Page.rect` will \"\n\"equal this rectangle, but be shifted to the top-left position (0, 0) if \"\n\"necessary. Example session:\"\nmsgstr \"\"\n\"実行後（ページが回転していない場合）、:attr:`Page.rect`  \"\n\"はこの矩形と等しくなりますが、必要に応じて左上の位置（0、0）にシフトされます。以下は例セッションです：\"\n\n#: ../../page.rst:2170 2c53f6bfb41d4389ac83aca28049d92c\nmsgid \"\"\n\"PDF only: Set the resp. rectangle in the page object. For the meaning of \"\n\"these objects see :ref:`AdobeManual`, page 77. Parameter and restrictions\"\n\" are the same as for :meth:`Page.set_cropbox`.\"\nmsgstr \"\"\n\"PDFのみ: ページオブジェクト内の対応する矩形を設定します。これらのオブジェクトの意味については、:ref:`AdobeManual` \"\n\"の77ページを参照してください。パラメータと制約は :meth:`Page.set_cropbox` と同じです。\"\n\n#: ../../page.rst:2174 51f449db2a3c44e189cf5fca9f485392\nmsgid \"New in v1.19.4\"\nmsgstr \"v1.19.4で新規追加\"\n\n#: ../../page.rst:2180 d0971433c9404486893ed8f9b8260a5e\nmsgid \"\"\n\"Contains the rotation of the page in degrees (always 0 for non-PDF \"\n\"types). This is a copy of the value in the PDF file. The PDF \"\n\"documentation says:\"\nmsgstr \"ページの回転角度を度数で含みます（非PDFタイプでは常に0）。\"\n\n#: ../../page.rst:2182 e4d847e602314207b08e68c851df6531\nmsgid \"\"\n\"*\\\"The number of degrees by which the page should be rotated clockwise \"\n\"when displayed or printed. The value must be a multiple of 90. Default \"\n\"value: 0.\\\"*\"\nmsgstr \"*「ページを表示または印刷する際に、時計回りに回転させる度数。値は90の倍数でなければなりません。デフォルト値：0」* \"\n\n#: ../../page.rst:2184 f95f2857345c4ab1b2ddf5e5bc9a02d7\nmsgid \"\"\n\"In PyMuPDF, we make sure that this attribute is always one of 0, 90, 180 \"\n\"or 270.\"\nmsgstr \"PyMuPDFでは、この属性が常に0、90、180、または270のいずれかであることを確認しています。\"\n\n#: ../../page.rst:2190 61f3d0cf602c4013b227d09247d5dea4\nmsgid \"\"\n\"Contains the top-left point of the page's `/CropBox` for a PDF, otherwise\"\n\" *Point(0, 0)*.\"\nmsgstr \"PDFの場合、ページの `/CropBox` の左上の点を含みます。それ以外の場合は *Point(0, 0)*。\"\n\n#: ../../page.rst:2192 ../../page.rst:2216 7816845ecf174917a69749a210307f96\n#: a70e370c3c004de999a9efabfc433212\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../page.rst:2196 6c185f908ac141b989b3b83d6d62f20c\nmsgid \"\"\n\"The page's `/CropBox` for a PDF. Always the **unrotated** page rectangle \"\n\"is returned. For a non-PDF this will always equal the page rectangle.\"\nmsgstr \"\"\n\"PDFのページの `/CropBox`  です。常に **回転していない** \"\n\"ページの矩形が返されます。非PDFの場合、これは常にページの矩形と等しいです。\"\n\n#: ../../page.rst:2198 d7f9ff9e1ee9469888ae5361c32a62ff\nmsgid \"\"\n\"In PDF, the relationship between `/MediaBox`, `/CropBox` and page \"\n\"rectangle may sometimes be confusing, please do lookup the glossary for \"\n\":data:`MediaBox`.\"\nmsgstr \"\"\n\"PDFでは、`/MediaBox`、`/CropBox`、およびページの矩形の関係は混乱することがあります。:data:`MediaBox` \"\n\"の用語集を参照してください。\"\n\n#: ../../page.rst:2208 d9a54722197a46059242db3e1d3a7319\nmsgid \"\"\n\"The page's `/ArtBox`, `/BleedBox`, `/TrimBox`, respectively. If not \"\n\"provided, defaulting to :attr:`Page.cropbox`.\"\nmsgstr \"\"\n\"PDFのページの/ArtBox、/BleedBox、/TrimBoxです。指定されていない場合、:attr:`Page.cropbox` \"\n\"にデフォルトで設定されます。\"\n\n#: ../../page.rst:2214 23b408953e2a4e86961ce70710f0fac0\nmsgid \"\"\n\"Contains the width and height of the page's :attr:`Page.mediabox` for a \"\n\"PDF, otherwise the bottom-right coordinates of :attr:`Page.rect`.\"\nmsgstr \"\"\n\"PDFのページの :attr:`Page.mediabox` の幅と高さを含みます。それ以外の場合、:attr:`Page.rect` \"\n\"の右下の座標です。\"\n\n#: ../../page.rst:2220 3435a4b6c7174525b0cb781fce4321ef\nmsgid \"The page's :data:`mediabox` for a PDF, otherwise :attr:`Page.rect`.\"\nmsgstr \"PDFのページの :data:`mediabox`、それ以外の場合は :attr:`Page.rect` です。\"\n\n#: ../../page.rst:2224 4df8f5c334964811a7137810e8a527a8\nmsgid \"\"\n\"For most PDF documents and for **all other document types**, `page.rect \"\n\"== page.cropbox == page.mediabox` is true. However, for some PDFs the \"\n\"visible page is a true subset of :data:`mediabox`. Also, if the page is \"\n\"rotated, its `Page.rect` may not equal `Page.cropbox`. In these cases the\"\n\" above attributes help to correctly locate page elements.\"\nmsgstr \"\"\n\"ほとんどのPDF文書および他のすべてのドキュメントタイプに対して、`page.rect == page.cropbox == \"\n\"page.mediabox` が真です。ただし、一部のPDFでは、表示ページが v \"\n\"の真の部分集合である場合があります。また、ページが回転している場合、`Page.rect` は `Page.cropbox` \"\n\"と等しくないかもしれません。これらの場合、上記の属性はページの要素を正しく位置付けるのに役立ちます。\"\n\n#: ../../page.rst:2228 d7f34f4307fe42d2b00939a7c2d9b9d6\nmsgid \"\"\n\"This matrix translates coordinates from the PDF space to the MuPDF space.\"\n\" For example, in PDF `/Rect [x0 y0 x1 y1]` the pair (x0, y0) specifies \"\n\"the **bottom-left** point of the rectangle -- in contrast to MuPDF's \"\n\"system, where (x0, y0) specify top-left. Multiplying the PDF coordinates \"\n\"with this matrix will deliver the (Py-) MuPDF rectangle version. \"\n\"Obviously, the inverse matrix will again yield the PDF rectangle.\"\nmsgstr \"\"\n\"この行列は、PDF空間からMuPDF空間への座標の変換に使用されます。たとえば、PDFの `/Rect [x0 y0 x1 y1]` \"\n\"では、ペア(x0、y0)が矩形の左下の点を指定します。これはMuPDFのシステムとは異なり、ここでは(x0、y0)は左上を指定します。PDF座標をこの行列で掛け算すると、（Py-）MuPDF矩形バージョンが得られます。明らかに、逆行列は再びPDF矩形を返します。\"\n\n#: ../../page.rst:2230 ../../page.rst:2246 699d02c9b35a4d618e67346779cd3952\n#: 6d0fd753260b4a269b9592b9ebba1e22\nmsgid \":ref:`Matrix`\"\nmsgstr \"\"\n\n#: ../../page.rst:2236 a5de7aa7bb6c40b4af9ab822d2fe0c61\nmsgid \"\"\n\"These matrices may be used for dealing with rotated PDF pages. When \"\n\"adding / inserting anything to a PDF page, the coordinates of the \"\n\"**unrotated** page are always used. These matrices help translating \"\n\"between the two states. Example: if a page is rotated by 90 degrees -- \"\n\"what would then be the coordinates of the top-left Point(0, 0) of an A4 \"\n\"page?\"\nmsgstr \"\"\n\"これらの行列は、回転したPDFページの取り扱いに使用できます。PDFページに何かを追加/挿入する際、**回転していない** \"\n\"ページの座標が常に使用されます。これらの行列は、2つの状態間での変換を支援します。例：ページが90度回転した場合、A4ページの左上のPoint(0,\"\n\" 0)の座標は何になりますか？\"\n\n#: ../../page.rst:2250 46775a2e1ffd4cc3a43e6c5596c0ead9\nmsgid \"Contains the first :ref:`Link` of a page (or ``None``).\"\nmsgstr \"ページの最初の :ref:`Link` を含みます（または ``None``）。\"\n\n#: ../../page.rst:2256 0768580c4efd4f2d93de5acfbd002a40\nmsgid \"Contains the first :ref:`Annot` of a page (or ``None``).\"\nmsgstr \"ページの最初の :ref:`Annot` を含みます（または ``None``）。\"\n\n#: ../../page.rst:2262 4a694bc3ae1c4722b7ff991244d6257b\nmsgid \"Contains the first :ref:`Widget` of a page (or ``None``).\"\nmsgstr \"ページの最初の :ref:`Widget` を含みます（または ``None``）。\"\n\n#: ../../page.rst:2268 7d1c6125f8284e8c9f39a10aa30103aa\nmsgid \"The page number.\"\nmsgstr \"ページ番号。\"\n\n#: ../../page.rst:2274 b2669057819b4d6e916eceb404f4d4a6\nmsgid \"The owning document object.\"\nmsgstr \"所属するドキュメントオブジェクト。\"\n\n#: ../../page.rst:2276 3c750c7bd6f64a0f942eb49c6ba43e3e\nmsgid \":ref:`Document`\"\nmsgstr \"\"\n\n#: ../../page.rst:2281 80a0d7ab5d684176876073a103e2c4dd\nmsgid \"\"\n\"Contains the rectangle of the page. Same as result of \"\n\":meth:`Page.bound()`.\"\nmsgstr \"ページの矩形を含みます。:meth:`Page.bound()` の結果と同じです。\"\n\n#: ../../page.rst:2287 b211572eb97c4f9288b72564a3087914\nmsgid \"The page's PDF :data:`xref`. Zero if not a PDF.\"\nmsgstr \"ページのPDF :data:`xref`。PDFでない場合はゼロです。\"\n\n#: ../../page.rst:2296 330f7b7647944c63ac3bc3ca6bf3f7ac\nmsgid \"Description of *get_links()* Entries\"\nmsgstr \"*get_links()* エントリの説明\"\n\n#: ../../page.rst:2297 2648f2152b014814987e0dc0b7cfaa91\nmsgid \"\"\n\"Each entry of the :meth:`Page.get_links` list is a dictionary with the \"\n\"following keys:\"\nmsgstr \":meth:`Page.get_links` リストの各エントリは、以下のキーを持つ辞書です：\"\n\n#: ../../page.rst:2299 e5c4e6907f6748d9b291f48ef9be9969\nmsgid \"\"\n\"*kind*:  (required) an integer indicating the kind of link. This is one \"\n\"of *LINK_NONE*, *LINK_GOTO*, *LINK_GOTOR*, *LINK_LAUNCH*, or *LINK_URI*. \"\n\"For values and meaning of these names refer to :ref:`linkDest Kinds`.\"\nmsgstr \"\"\n\"*kind*：（必須）リンクの種類を示す整数。*LINK_NONE*、*LINK_GOTO*、*LINK_GOTOR*、*LINK_LAUNCH*、または\"\n\" *LINK_URI* のいずれかです。\"\n\n#: ../../page.rst:2301 b82063bc31e64ff5910c18796372ade3\nmsgid \"\"\n\"*from*:  (required) a :ref:`Rect` describing the \\\"hot spot\\\" location on\"\n\" the page's visible representation (where the cursor changes to a hand \"\n\"image, usually).\"\nmsgstr \"\"\n\"*from*：（必須）ページの可視な表現上の「ホットスポット」の場所を示す :ref:`Rect` \"\n\"（通常、カーソルが手のイメージに変わる場所です）。\"\n\n#: ../../page.rst:2303 5bf55439f5024bf3b33ca376989d47ae\nmsgid \"\"\n\"*page*:  a 0-based integer indicating the destination page. Required for \"\n\"*LINK_GOTO* and *LINK_GOTOR*, else ignored.\"\nmsgstr \"page：宛先ページを示す0ベースの整数。*LINK_GOTO*および *LINK_GOTOR* の場合に必要ですが、それ以外の場合は無視されます。\"\n\n#: ../../page.rst:2305 65bd0136b92944d9a0a10ef2ee48ace2\nmsgid \"\"\n\"*to*:   either a *pymupdf.Point*, specifying the destination location on \"\n\"the provided page, default is *pymupdf.Point(0, 0)*, or a symbolic \"\n\"(indirect) name. If an indirect name is specified, *page = -1* is \"\n\"required and the name must be defined in the PDF in order for this to \"\n\"work. Required for *LINK_GOTO* and *LINK_GOTOR*, else ignored.\"\nmsgstr \"\"\n\"*to*：宛先ページ上の宛先場所を指定する *pymupdf.Point*、デフォルトは *pymupdf.Point(0, \"\n\"0)*、またはシンボリック（間接）名です。間接名が指定された場合、*page = -1* \"\n\"が必要で、名前はPDFで定義されている必要があります。*LINK_GOTO* および *LINK_GOTOR* \"\n\"の場合に必要ですが、それ以外の場合は無視されます。\"\n\n#: ../../page.rst:2307 6868a28eed0f4944b3281fe9952cc61d\nmsgid \"\"\n\"*file*: a string specifying the destination file. Required for \"\n\"*LINK_GOTOR* and *LINK_LAUNCH*, else ignored.\"\nmsgstr \"file：宛先ファイルを指定する文字列。LINK_GOTORおよびLINK_LAUNCHの場合に必要ですが、それ以外の場合は無視されます。\"\n\n#: ../../page.rst:2309 06a46ce37a71407f9de78e7a1c830883\nmsgid \"\"\n\"*uri*:  a string specifying the destination internet resource. Required \"\n\"for *LINK_URI*, else ignored. You should make sure to start this string \"\n\"with an unambiguous substring, that classifies the subtype of the URL, \"\n\"like `\\\"http://\\\"`, `\\\"https://\\\"`, `\\\"file://\\\"`, `\\\"ftp://\\\"`, \"\n\"`\\\"mailto:\\\"`, etc. Otherwise your browser will try to interpret the text\"\n\" and come to unwanted / unexpected conclusions about the intended URL \"\n\"type.\"\nmsgstr \"\"\n\"*uri*: LINK_URI用に指定された、インターネットリソースの宛先を示す文字列。*LINK_URI* \"\n\"の場合に必要で、それ以外の場合は無視されます。この文字列は、`\\\"http://\\\"`、`\\\"https://\\\"`、`\\\"file://\\\"`、`\\\"ftp://\\\"`、`\\\"mailto:\\\"`\"\n\" \"\n\"など、URLのサブタイプを識別する明確なサブストリングで始めるようにしてください。そうしないと、ブラウザがテキストを解釈し、意図しない/予期しない結論に達する可能性があります。\"\n\n#: ../../page.rst:2311 d09b61a1ccd94c4782bb9e12c1371ed4\nmsgid \"\"\n\":data:`xref`: an integer specifying the PDF :data:`xref` of the link \"\n\"object. Do not change this entry in any way. Required for link deletion \"\n\"and update, otherwise ignored. For non-PDF documents, this entry contains\"\n\" *-1*. It is also *-1* for **all** entries in the *get_links()* list, if \"\n\"**any** of the links is not supported by MuPDF - see \"\n\":ref:`notes_on_supporting_links`.\"\nmsgstr \"\"\n\":data:`xref`: リンクオブジェクトのPDF :data:`xref` \"\n\"を指定する整数。このエントリを何らかの方法で変更しないでください。リンクの削除と更新に必要で、それ以外の場合は無視されます。非PDFドキュメントの場合、このエントリには\"\n\" *-1* が含まれます。また、MuPDFがサポートしていないリンクがある場合、*get_links()*  \"\n\"リストのすべてのエントリに対しても-1になります。詳細については以下の注釈を参照してください。\"\n\n#: ../../page.rst:2316 ca9d2e5b20dc4945ab5c36ba5fe32ee0\nmsgid \"Notes on Supporting Links\"\nmsgstr \"リンクのサポートに関する注記\"\n\n#: ../../page.rst:2317 153628a3a4a646ffa511f00e6bf330e6\nmsgid \"\"\n\"MuPDF's support for links has changed in **v1.10a**. These changes affect\"\n\" link types :data:`LINK_GOTO` and :data:`LINK_GOTOR`.\"\nmsgstr \"\"\n\"**v1.10a** 以降、MuPDFのリンクサポートが変更されました。これらの変更は :data:`LINK_GOTO` および \"\n\":data:`LINK_GOTOR` というリンクタイプに影響を与えます。\"\n\n#: ../../page.rst:2320 ac15e6ee350d44a8a44de4197833bb6f\nmsgid \"\"\n\"Reading (pertains to method *get_links()* and the *first_link* property \"\n\"chain)\"\nmsgstr \"読み取り *get_links()* メソッドおよび*first_link* プロパティチェーンに関連）\"\n\n#: ../../page.rst:2322 0d5ea7869b084e17a975066e947fd27c\nmsgid \"\"\n\"If MuPDF detects a link to another file, it will supply either a \"\n\"*LINK_GOTOR* or a *LINK_LAUNCH* link kind. In case of *LINK_GOTOR* \"\n\"destination details may either be given as page number (eventually \"\n\"including position information), or as an indirect destination.\"\nmsgstr \"\"\n\"MuPDFが別のファイルへのリンクを検出する場合、*LINK_GOTOR* または *LINK_LAUNCH* \"\n\"リンクの種類を提供します。*LINK_GOTOR* \"\n\"の場合、宛先の詳細はページ番号（位置情報を含むことがある）または間接的な宛先として指定できます。\"\n\n#: ../../page.rst:2324 8460c5420845442387f0514e8c1cbf00\nmsgid \"\"\n\"If an indirect destination is given, then this is indicated by *page = \"\n\"-1*, and *link.dest.dest* will contain this name. The dictionaries in the\"\n\" *get_links()* list will contain this information as the *to* value.\"\nmsgstr \"\"\n\"間接的な宛先が指定された場合、page = -1で示され、*link.dest.dest* にこの名前が含まれます。 *get_links()* \"\n\"リスト内の辞書には、この情報がto値として含まれます。\"\n\n#: ../../page.rst:2326 8abfed4c51c3411799b1a19205d7ce7e\nmsgid \"\"\n\"**Internal links are always** of kind *LINK_GOTO*. If an internal link \"\n\"specifies an indirect destination, it **will always be resolved** and the\"\n\" resulting direct destination will be returned. Names are **never \"\n\"returned for internal links**, and undefined destinations will cause the \"\n\"link to be ignored.\"\nmsgstr \"内部リンクは常にLINK_GOTOの種類です。内部リンクが間接的な宛先を指定した場合、常に解決され、結果の直接的な宛先が返されます。内部リンクには名前は返されず、未定義の宛先はリンクが無視される原因になります。\"\n\n#: ../../page.rst:2329 5b18953ee4ad4219b62275b81fbc5ddf\nmsgid \"Writing\"\nmsgstr \"書き込み\"\n\n#: ../../page.rst:2331 0de4046ec1434f2caf33d1d0f937dc46\nmsgid \"\"\n\"PyMuPDF writes (updates, inserts) links by constructing and writing the \"\n\"appropriate PDF object **source**. This makes it possible to specify \"\n\"indirect destinations for *LINK_GOTOR* **and** *LINK_GOTO* link kinds \"\n\"(pre *PDF 1.2* file formats are **not supported**).\"\nmsgstr \"\"\n\"PyMuPDFはリンクを構築して適切なPDFオブジェクト **ソース** を書き込むことにより、リンクを書き込み（更新、挿入）します。これにより、\"\n\" *LINK_GOTOR* および *LINK_GOTO* リンク種別に対して間接的な宛先を指定できます（**PDF 1.2** \"\n\"ファイル形式以前はサポートされていません）。\"\n\n#: ../../page.rst:2333 44475c60d0bb4e1896c7d6d9f54c1bc4\nmsgid \"\"\n\"If a *LINK_GOTO* indirect destination specifies an undefined name, this \"\n\"link can later on not be found / read again with MuPDF / PyMuPDF. Other \"\n\"readers however **will** detect it, but flag it as erroneous.\"\nmsgstr \"\"\n\"*LINK_GOTO* の間接的な宛先が未定義の名前を指定した場合、このリンクは後でMuPDF / \"\n\"PyMuPDFで再び見つけることはできません。ただし、他のリーダーはそれを検出し、エラーとしてフラグ付けます。\"\n\n#: ../../page.rst:2335 e97441d500fd4cbca093072001464735\nmsgid \"\"\n\"Indirect *LINK_GOTOR* destinations can in general of course not be \"\n\"checked for validity and are therefore **always accepted**.\"\nmsgstr \"一般的な注意: 間接的な *LINK_GOTOR* の宛先は一般的に有効性を確認できないため、常に受け入れられます。\"\n\n#: ../../page.rst:2337 f91d81599f744ef191138bdba01275a1\nmsgid \"\"\n\"**Example: How to insert a link pointing to another page in the same \"\n\"document**\"\nmsgstr \"**例: 同じドキュメント内の別のページを指すリンクを挿入する方法**\"\n\n#: ../../page.rst:2339 253b3fcbe5b34a058e8cce4baddbe409\nmsgid \"\"\n\"Determine the rectangle on the current page, where the link should be \"\n\"placed. This may be the bbox of an image or some text.\"\nmsgstr \"リンクを配置する現在のページの矩形を決定します。これは画像または一部のテキストのbboxである場合があります。\"\n\n#: ../../page.rst:2341 75763ee86eb04ffbbe5b886eebd09616\nmsgid \"\"\n\"Determine the target page number (\\\"pno\\\", 0-based) and a :ref:`Point` on\"\n\" it, where the link should be directed to.\"\nmsgstr \"ターゲットページ番号（0から始まる）と、リンクを指定するためのそのページ上の :ref:`Point` を決定します。\"\n\n#: ../../page.rst:2343 da45c4d7d2cf48049d7c7f88370a9dba\nmsgid \"\"\n\"Create a dictionary `d = {\\\"kind\\\": pymupdf.LINK_GOTO, \\\"page\\\": pno, \"\n\"\\\"from\\\": bbox, \\\"to\\\": point}`.\"\nmsgstr \"\"\n\"辞書 `d = {\\\"kind\\\": pymupdf.LINK_GOTO, \\\"page\\\": pno, \\\"from\\\": bbox, \"\n\"\\\"to\\\": point}` を作成します。\"\n\n#: ../../page.rst:2345 60e5b2f417a74a0c97ba824efdaefd93\nmsgid \"Execute `page.insert_link(d)`.\"\nmsgstr \"page.insert_link(d)を実行します。\"\n\n#: ../../page.rst:2349 0b3e910653ec4d80abba445bbb13921a\nmsgid \"Homologous Methods of :ref:`Document` and :ref:`Page`\"\nmsgstr \":ref:`Document` と :ref:`Page` の同様のメソッドに関する説明です。\"\n\n#: ../../page.rst:2350 26d9e6f47ecb405283f2b5a81a7906f3\nmsgid \"\"\n\"This is an overview of homologous methods on the :ref:`Document` and on \"\n\"the :ref:`Page` level.\"\nmsgstr \"これは、:ref:`Document` と :ref:`Page` レベルでの同様のメソッドの概要です。\"\n\n#: ../../page.rst:2353 30f1c80e96954d7a8d908b00de01d053\nmsgid \"**Document Level**\"\nmsgstr \"**Document Level（ドキュメントレベル）**\"\n\n#: ../../page.rst:2353 d3484b7b4dab482587ce24b47380e9f6\nmsgid \"**Page Level**\"\nmsgstr \"**Page Level（ページレベル）**\"\n\n#: ../../page.rst:2355 749f5d81a505410c95dfc298f9321878\nmsgid \":meth:`Document.get_page_fonts`\"\nmsgstr \"\"\n\n#: ../../page.rst:2356 41cb520def50422cada301e1c49c5f3d\nmsgid \":meth:`Document.get_page_images`\"\nmsgstr \"\"\n\n#: ../../page.rst:2357 8a690ea87be148078b0576d999f057fb\nmsgid \":meth:`Document.get_page_pixmap`\"\nmsgstr \"\"\n\n#: ../../page.rst:2358 984984f6cc6d4a9498c4a27025b79202\nmsgid \":meth:`Document.get_page_text`\"\nmsgstr \"\"\n\n#: ../../page.rst:2359 49d5563cc8e34fc490cedcd93dcf899f\nmsgid \":meth:`Document.search_page_for`\"\nmsgstr \"\"\n\n#: ../../page.rst:2364 77c9d1d7bbef4177962336adc5064826\nmsgid \"\"\n\"Most document methods (left column) exist for convenience reasons, and \"\n\"are just wrappers for: *Document[pno].<page method>*. So they **load and \"\n\"discard the page** on each execution.\"\nmsgstr \"\"\n\"多くのドキュメントメソッド（左側の列）は利便性のために存在し、*Document[pno].<page method>* \"\n\"のラッパーであるだけで、各実行でページを読み込んで破棄します。\"\n\n#: ../../page.rst:2366 e0140280aedb4565a755312c2fe002cc\n#, fuzzy\nmsgid \"\"\n\"However, the first two methods work differently. They only need a page's \"\n\"object definition statement - the page itself will **not** be loaded. So \"\n\"e.g. :meth:`Page.get_fonts` is a wrapper the other way round and defined \"\n\"as follows: `page.get_fonts` == \"\n\"`page.parent.get_page_fonts(page.number)`.\"\nmsgstr \"\"\n\"ただし、最初の2つのメソッドは異なる方法で動作します。これらはページのオブジェクト定義ステートメントだけを必要とし、ページ自体は読み込まれません。例えば、:meth:`Page.get_fonts`\"\n\" は逆に定義され、次のようになります: *page.get_fonts == \"\n\"page.parent.get_page_fonts(page.number)*。\"\n\n#: ../../page.rst:2369 3b3743f5a8784405b026dc4dccf459b4\nmsgid \"\"\n\"When calling the :ref:`Document` equivalent methods then the page number \"\n\"is sent through as a parameter, e.g.:\"\nmsgstr \"\"\n\n#: ../../page.rst:2371 23d4fa19cff54bf3a4082b4375479d9c\nmsgid \"`Document.get_page_images(pno)` or `Document.get_page_text(pno)`\"\nmsgstr \"\"\n\n#: ../../page.rst:2375 7a08e4eae20c4587b61464662be5018f\n#, fuzzy\nmsgid \"\"\n\"The page number parameter, ``pno``, is a 0-based integer `-∞ < pno < \"\n\"page_count`.\"\nmsgstr \"ページ番号「pno」は0から始まる整数であり、`-∞ < pno < page_count` です。\"\n\n#: ../../page.rst:2382 0e56aad36ef2434eaaa062ac4d6b1078\nmsgid \"Tables and Related Classes\"\nmsgstr \"\"\n\n#: ../../page.rst:2384 630834d3fb7f49fabf1df19c954b5e8e\nmsgid \"\"\n\"The `TableFinder` class is returned by :meth:`Page.find_tables` and has \"\n\"related classes as follows:\"\nmsgstr \"\"\n\n#: ../../page.rst:2389 fefc2003da7640af95d0c8fe2fa4ae0b\nmsgid \"\"\n\"An object always returned by :meth:`Page.find_tables`. Attributes of \"\n\"interest:\"\nmsgstr \"\"\n\n#: ../../page.rst:2393 b1facb7319d64fe1814982a94e08e694\nmsgid \"\"\n\"A list of :class:`Table` objects, each of which represents a table found \"\n\"on the page. An empty list if no tables are found.\"\nmsgstr \"\"\n\n#: ../../page.rst:2397 d9c68273a7ed4f9389de63201f1329e4\nmsgid \"A reference to the :ref:`Page` object.\"\nmsgstr \"\"\n\n#: ../../page.rst:2399 ../../page.rst:2411 672ced5c87644dc2ab8425cfb3735842\n#: a46083173b284a9a95fec38e2ff752ba\nmsgid \":ref:`Page`\"\nmsgstr \"\"\n\n#: ../../page.rst:2404 09993a5d0359435c82005cbe7053461a\nmsgid \"An object representing a table found on the page.\"\nmsgstr \"\"\n\n#: ../../page.rst:2409 334f29b68048440bb2c92ed1d075c7e4\nmsgid \"A back-reference to the owning page.\"\nmsgstr \"\"\n\n#: ../../page.rst:2415 fa2948c2cbd84d36bc110ba375ce9dcf\nmsgid \"An array of `Rect` objects for each cell in the table.\"\nmsgstr \"\"\n\n#: ../../page.rst:2417 ../../page.rst:2454 ../../page.rst:2461\n#: ../../page.rst:2498 ../../page.rst:2504 0b50c46907a6406dbbfcc4a9d7d842c0\n#: 1f804a3ec218447b9ebe0a4eb0662c6c 6ab7e6b040ab43b3a52010e0236f593d\n#: 89f000de4e84477dac230df671fd8a17 ff379839dfcf4dc09a1fc2dd862b6e83\nmsgid \"list\"\nmsgstr \"\"\n\n#: ../../page.rst:2422 fff4c850223145f2b09c22904bdecb3d\nmsgid \"A `TableHeader` object.\"\nmsgstr \"\"\n\n#: ../../page.rst:2424 16480aa7bae54a44b65eb4a3ad51ca39\nmsgid \"`TableHeader`\"\nmsgstr \"\"\n\n#: ../../page.rst:2429 cb817f7210a04ab19d07808de14accbe\n#, fuzzy\nmsgid \"The bounding box of all cells of the table header.\"\nmsgstr \"**bbox:** ヘッダーのバウンディングボックス。\"\n\n#: ../../page.rst:2438 e42d4b4d7ae94e84bbba1635affb7264\nmsgid \"Number of rows in the table.\"\nmsgstr \"\"\n\n#: ../../page.rst:2445 dab42295898940e289ac06b2d6448eb3\nmsgid \"Number of columns in the table.\"\nmsgstr \"\"\n\n#: ../../page.rst:2452 c32a46770fa84ab8a8442c7324cca9b8\nmsgid \"An array of `TableRow` objects for each row in the table.\"\nmsgstr \"\"\n\n#: ../../page.rst:2459 5e94d9003fcf4a0c9bc37419ed453180\nmsgid \"Extracts table cell text data into a list.\"\nmsgstr \"\"\n\n#: ../../page.rst:2465 4f9105edf01140a8bcac5f19a880eabb\nmsgid \"Extracts table data into Markdown text format.\"\nmsgstr \"\"\n\n#: ../../page.rst:2468 3fa618e2424d4b4fb55e83275cc442b9\nmsgid \"If ``True`` then markdown syntax is removed from cell content.\"\nmsgstr \"\"\n\n#: ../../page.rst:2469 888238e384834e50bf7109918e9694c5\nmsgid \"\"\n\"If ``True`` then cell content `None` is replaced by the values above \"\n\"(columns) or left (rows) in an effort to approximate row and columns \"\n\"spans.\"\nmsgstr \"\"\n\n#: ../../page.rst:2472 a454ab9fb7dc493797f334048225e316\n#, fuzzy\nmsgid \"string\"\nmsgstr \"書き込み\"\n\n#: ../../page.rst:2477 0c321bd8063c4c9f83179c7cc7985e85\nmsgid \"\"\n\"Return a `pandas DataFrame <https://pypi.org/project/pandas/>`_ \"\n\"`DataFrame <https://pandas.pydata.org/docs/reference/frame.html>`_ \"\n\"version of the table.\"\nmsgstr \"\"\n\n#: ../../page.rst:2479 596d18b7bb884f478f918f7acedadd09\nmsgid \"pandas DataFrame\"\nmsgstr \"\"\n\n#: ../../page.rst:2486 127cceead5c244e8a61282d74b663861\nmsgid \"Dedicated class for table headers.\"\nmsgstr \"\"\n\n#: ../../page.rst:2490 a954a6b14acd4faf9c8748ad7f616d9c\nmsgid \"\"\n\"The bounding box of the union of cells belonging to the table header, \"\n\"given as a tuple (x0, y0, x1, y1). This rectangle contains all table \"\n\"header cells.\"\nmsgstr \"\"\n\n#: ../../page.rst:2496 18255190a91e49549ec8607494bcfad6\nmsgid \"A list of tuples for each bbox of a column header.\"\nmsgstr \"\"\n\n#: ../../page.rst:2502 bbadce9734a54ebf8f060fda7b75f154\nmsgid \"A list of strings with column header text.\"\nmsgstr \"\"\n\n#: ../../page.rst:2508 d0766391701c4fbcbfc1afe7ab941644\nmsgid \"A boolean indicating whether the header is outside the table cells.\"\nmsgstr \"\"\n\n#: ../../page.rst:2510 bf9a41b295214c1d8a33fbf5ff2d0674\n#, fuzzy\nmsgid \"`bool`\"\nmsgstr \"太字\"\n\n#: ../../page.rst:2515 7e240363ad36487abb9c0b9048455344\nmsgid \"Dedicated class for table rows.\"\nmsgstr \"\"\n\n#: ../../page.rst:2522 f121b788e07f4404822f89f64a76f622\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../page.rst:2523 a6e7a54deb36449583b6c8f5faa956b1\nmsgid \"\"\n\"If your existing code already uses the installed base name as a font \"\n\"reference (as it was supported by PyMuPDF versions earlier than 1.14), \"\n\"this will continue to work.\"\nmsgstr \"既存のコードがフォントの参照としてインストール済みのベース名を使用している場合（これはPyMuPDFバージョン1.14以前でサポートされていました）、これは引き続き機能します。\"\n\n#: ../../page.rst:2525 041b50e8dc5a4737947d980e5bcdfadc\nmsgid \"\"\n\"Not all PDF reader software (including internet browsers and office \"\n\"software) display all of these fonts. And if they do, the difference \"\n\"between the **serifed** and the **non-serifed** version may hardly be \"\n\"noticeable. But serifed and non-serifed versions lead to different \"\n\"installed base fonts, thus providing an option to be displayable with \"\n\"your specific PDF viewer.\"\nmsgstr \"PDFリーダーソフトウェア（インターネットブラウザやオフィスソフトウェアを含む）がすべてのこれらのフォントを表示するわけではありません。そして、表示されても、セリフ付きとセリフなしバージョンの違いはほとんど気付かれないかもしれません。ただし、セリフ付きとセリフなしバージョンは異なるインストール済みベースのフォントにリードするため、特定のPDFビューアで表示可能なオプションが提供されます。\"\n\n#: ../../page.rst:2527 d0a153a29bcf4cc7bbc8a126f31438ec\nmsgid \"\"\n\"Not all PDF readers display these fonts at all. Some others do, but use a\"\n\" wrong character spacing, etc.\"\nmsgstr \"すべてのPDFリーダーがこれらのフォントを表示するわけではありません。一部の他のソフトウェアは表示するかもしれませんが、文字間隔が間違っているなどの問題が発生する場合があります。\"\n\n#: ../../page.rst:2529 4c36bdbe56f14fbd93778c7b846894f0\nmsgid \"\"\n\"You are generally free to choose any of the :ref:`mupdficons` you \"\n\"consider adequate.\"\nmsgstr \"適切と思われるMuPDFの注釈アイコンのいずれを選択することは自由です。\"\n\n#: ../../page.rst:2531 f0955458c88b48f0bc91091ffac7934c\nmsgid \"\"\n\"The previous algorithm caused images to be **shrunk** to this \"\n\"intersection. Now the image can be anywhere on :attr:`Page.mediabox`, \"\n\"potentially being invisible or only partially visible if the cropbox \"\n\"(representing the visible page part) is smaller.\"\nmsgstr \"\"\n\"以前のアルゴリズムでは、画像がこの交差点に縮小されることがありました。今では画像は　:attr:`Page.mediabox` \"\n\"のどこにでも配置でき、cropbox（表示ページ部分を表す）が小さい場合、画像は見えないか部分的にしか見えない可能性があります。\"\n\n#: ../../page.rst:2533 ee4935ee06214192915f0a7d40c3c57d\nmsgid \"\"\n\"If you need to also see annotations or fields in the target page, you can\"\n\" convert the source PDF using :meth:`Document.bake`. The underlying MuPDF\"\n\" function of that method will convert these objects to normal page \"\n\"content. Then use :meth:`Page.show_pdf_page` with the converted PDF page.\"\nmsgstr \"\"\n\"ターゲットページで注釈やフィールドも表示する必要がある場合、ソースPDFを別のPDFに変換して :meth:`Document.bake` \"\n\"を使用してみることができます。そのメソッドの基本となるMuPDFの機能は、これらのオブジェクトを通常のページコンテンツに変換します。その後、変換されたPDFページを使用して\"\n\"　:meth:`Page.show_pdf_page` を使用します。\"\n\n#: ../../page.rst:2535 e97c4c82263941379759ee87f2b26a7d\nmsgid \"\"\n\"In PDF, an area enclosed by some lines or curves can have a property \"\n\"called \\\"orientation\\\". This is significant for switching on or off the \"\n\"fill color of that area when there exist multiple area overlaps - see \"\n\"discussion in method :meth:`Shape.finish` using the \\\"non-zero winding \"\n\"number\\\" rule. While orientation of curves, quads, triangles and other \"\n\"shapes enclosed by lines always was detectable, this has been impossible \"\n\"for \\\"re\\\" (rectangle) items in the past. Adding the orientation \"\n\"parameter now delivers the missing information.\"\nmsgstr \"\"\n\"PDFにおいて、いくつかの線や曲線で囲まれた領域は、「方向性（orientation）」と呼ばれるプロパティを持つことがあります。これは、複数の領域が重なる場合にその領域の塗りつぶし色をオンまたはオフに切り替える際に重要です。この方向性は「非ゼロの巡回数\"\n\"（non-zero winding number）ルール」を使用した :meth:`Shape.finish` \"\n\"メソッドの議論で詳しく説明されています。曲線、四角形、三角形などの線で囲まれた形状の方向性は常に検出可能でしたが、これまでは「re」（長方形）アイテムに対しては不可能でした。orientationパラメータを追加することで、この不足していた情報を提供できるようになりました。\"\n\n#: ../../page.rst:2537 8612026f5b474906aa96aa5c9f0fe43a\nmsgid \"\"\n\"Hyphenation detection simply means that if the last character of a line \"\n\"is \\\"-\\\", it will be assumed to be a continuation character. That \"\n\"character will not be found by text searching with its default flag \"\n\"setting. Please take note, that a MuPDF *line* may not always be what you\"\n\" expect: words separated by overly large gaps (e.g. caused by text \"\n\"justification) may constitute separate MuPDF lines. If then any of these \"\n\"words ends with a hyphen, it will only be found by text searching if \"\n\"hyphenation is switched off.\"\nmsgstr \"\"\n\"ハイフネーション検出とは、行の最後の文字が「-」である場合、それが連続文字であると仮定することを意味します。この文字は、デフォルトのフラグ設定を使用してテキスト検索されないでしょう。MuPDFの行が常に期待どおりであるわけではないことに注意してください：文字の間隔が非常に大きい（テキストの正当化によって引き起こされる場合など）、単語が別々のMuPDFの\"\n\"　*line* \"\n\"を構成する可能性があります。その後、これらの単語のいずれかがハイフンで終わる場合、ハイフネーションがオフになっていない限り、テキスト検索でのみ見つかるでしょう。\"\n\n#: ../../page.rst:2539 f928aef1dad441f1a458d6f312a66855\nmsgid \"\"\n\"Objects inside the source page, like images, text or drawings, are never \"\n\"aware of whether their owning page now is under OC control inside the \"\n\"target PDF. If source page objects are OC-controlled in the source PDF, \"\n\"then this will not be retained on the target: they will become \"\n\"unconditionally visible.\"\nmsgstr \"ソースページ内のオブジェクト、例えば画像、テキスト、または図面などは、所有ページがターゲットPDF内でOC（オプションコンテンツ）制御下にあるかどうかを認識することは決してありません。ソースページのオブジェクトがソースPDF内でOCに制御されている場合、これはターゲットに保持されないため、それらは無条件に表示されます。\"\n\n#: ../../page.rst:2541 fe1cfbaa56a3485cb70119f33c3e64d5\nmsgid \"\"\n\"This value is always 96, the default of the PDF interpreter. It **does \"\n\"not reflect** the resolution of the image itself. If you need the image's\"\n\" resolution, use the :meth:`Pixmap.xres` and :meth:`Pixmap.yres` \"\n\"attributes of the :ref:`Pixmap` created from the image binary.\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 ada5e78849734f1196f922af9c2cb075\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"image in memory (all formats supported\"\n#~ \" by MuPDF -- see :ref:`ImageFiles`).  \"\n#~ \"Changed in v1.14.13: *io.BytesIO* is now\"\n#~ \" also supported.\"\n#~ msgstr \"\"\n\n#~ msgid \"Changed in v1.14.13: *io.BytesIO* is now also supported.\"\n#~ msgstr \"v1.14.13で変更：*io.BytesIO* もサポートされるようになりました。\"\n\n#~ msgid \"\"\n#~ \"*(new in version v1.18.1)* image in \"\n#~ \"memory -- to be used as image \"\n#~ \"mask (alpha values) for the base \"\n#~ \"image. When specified, the base image\"\n#~ \" must be provided as a filename \"\n#~ \"or a stream -- and must not \"\n#~ \"be an image that already has a \"\n#~ \"mask.\"\n#~ msgstr \"\"\n#~ \"*(v1.18.1で新機能)* \"\n#~ \"ベース画像の画像マスク（アルファ値）として使用するためのメモリ内の画像。指定する場合、ベース画像はファイル名またはストリームとして提供され、すでにマスクを持っている画像ではない必要があります。\"\n\n#~ msgid \"\"\n#~ \"*(New in v1.18.13)* the :data:`xref` of\"\n#~ \" an image already present in the \"\n#~ \"PDF. If given, parameters `filename`, \"\n#~ \"`pixmap`, `stream`, `alpha` and `mask` \"\n#~ \"are ignored. The page will simply \"\n#~ \"receive a reference to the existing \"\n#~ \"image.\"\n#~ msgstr \"\"\n#~ \"(v1.18.13で新機能)* \"\n#~ \"PDFに既に存在する画像のxref。指定された場合、`filename`、`pixmap`、`stream`、`alpha`、および \"\n#~ \"`mask` のパラメータは無視されます。ページは単に既存の画像への参照を受け取ります。\"\n\n#~ msgid \"\"\n#~ \"*(new in v1.18.3)* (:data:`xref`) make \"\n#~ \"image visibility dependent on this \"\n#~ \":data:`OCG` or :data:`OCMD`. Ignored after \"\n#~ \"the first of multiple insertions. The\"\n#~ \" property is stored with the \"\n#~ \"generated PDF image object and therefore\"\n#~ \" controls the image's visibility throughout\"\n#~ \" the PDF.\"\n#~ msgstr \"\"\n#~ \"(v1.18.3で新機能)*（:data:`xref`）画像の表示をこの :data:`OCG`または \"\n#~ \":data:`OCMD` \"\n#~ \"に依存させます。複数の挿入の最初の後は無視されます。このプロパティは生成されたPDF画像オブジェクトに保存されるため、PDF全体で画像の表示を制御します。\"\n\n#~ msgid \"*(new in version v1.14.11)* maintain the aspect ratio of the image.\"\n#~ msgstr \"(v1.14.11で新機能)* 画像のアスペクト比を保持します。\"\n\n#~ msgid \"For a description of *overlay* see :ref:`CommonParms`.\"\n#~ msgstr \"*overlay* の説明については :ref:`CommonParms` を参照してください。\"\n\n#~ msgid \"*Changed in v1.18.13:* Return xref of stored image.\"\n#~ msgstr \"*v1.18.13で変更：* 格納された画像のxrefを返します。\"\n\n#~ msgid \"\"\n#~ \"the font name. Default is \\\"Helv\\\". \"\n#~ \"Accepted alternatives are \\\"Cour\\\", \\\"TiRo\\\",\"\n#~ \" \\\"ZaDb\\\" and \\\"Symb\\\". The name may\"\n#~ \" be abbreviated to the first two \"\n#~ \"characters, like \\\"Co\\\" for \\\"Cour\\\". \"\n#~ \"Lower case is also accepted. *(Changed\"\n#~ \" in v1.16.0)* Bold or italic variants\"\n#~ \" of the fonts are **no longer \"\n#~ \"accepted**. A user-contributed script \"\n#~ \"provides a circumvention for this \"\n#~ \"restriction -- see section *Using \"\n#~ \"Buttons and JavaScript* in chapter \"\n#~ \":ref:`FAQ`. *(New in v1.17.0)* The \"\n#~ \"actual font to use is now \"\n#~ \"determined on a by-character level, \"\n#~ \"and all required fonts (or sub-\"\n#~ \"fonts) are automatically included. Therefore,\"\n#~ \" you should rarely ever need to \"\n#~ \"care about this parameter and let \"\n#~ \"it default (except you insist on a\"\n#~ \" serifed font for your non-CJK \"\n#~ \"text parts).\"\n#~ msgstr \"\"\n#~ \"フォント名。デフォルトは「Helv」です。受け入れられる代替案は「Cour」、「TiRo」、「ZaDb」、「Symb」です。名前は、最初の2文字まで省略することができます。「Co」のように、小文字も受け入れられます。*（v1.16.0で変更）*\"\n#~ \" \"\n#~ \"フォントの太字または斜体のバリアントはもはや受け入れられません。この制限を回避するユーザー投稿のスクリプトが提供されており、:ref:`FAQ`\"\n#~ \" \"\n#~ \"の章で「ボタンとJavaScriptの使用」を参照してください。（v1.17.0で新規追加）使用する実際のフォントは、文字ごとに決定され、必要なすべてのフォント（またはサブフォント）が自動的に含まれます。したがって、このパラメータについて心配する必要はほとんどありません。デフォルトにしておくべきです（CJK以外のテキスト部分にセリフフォントを希望する場合を除く）。\"\n\n#~ msgid \"*(new in v1.16.0)* the text color. Default is black.\"\n#~ msgstr \"*（v1.16.0で新規追加）* テキストの色。デフォルトは黒です。\"\n\n#~ msgid \"*(new in v1.16.0)* the fill color. Default is white.\"\n#~ msgstr \"*（v1.16.0で新規追加）* 塗りつぶしの色。デフォルトは白です。\"\n\n#~ msgid \"\"\n#~ \"*(new in v1.17.0)* text alignment, one\"\n#~ \" of TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, \"\n#~ \"TEXT_ALIGN_RIGHT - justify is **not \"\n#~ \"supported**.\"\n#~ msgstr \"\"\n#~ \"*（v1.17.0で新規追加）* \"\n#~ \"テキストの配置、TEXT_ALIGN_LEFT、TEXT_ALIGN_CENTER、TEXT_ALIGN_RIGHTのいずれか。ジャスティファイは\"\n#~ \" **サポートされていません**。\"\n\n#~ msgid \"\"\n#~ \"the data to be stored (actual file\"\n#~ \" content, any data, etc.).  Changed \"\n#~ \"in v1.14.13 *io.BytesIO* is now also \"\n#~ \"supported.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*(New in v1.16.12)* the font to \"\n#~ \"use when *text* is given, otherwise \"\n#~ \"ignored. The same rules apply as \"\n#~ \"for :meth:`Page.insert_textbox` -- which is\"\n#~ \" the method :meth:`Page.apply_redactions` \"\n#~ \"internally invokes. The replacement text \"\n#~ \"will be **vertically centered**, if this\"\n#~ \" is one of the CJK or \"\n#~ \":ref:`Base-14-Fonts`.  .. note::     * For \"\n#~ \"an **existing** font of the page, \"\n#~ \"use its reference name as *fontname* \"\n#~ \"(this is *item[4]* of its entry in\"\n#~ \" :meth:`Page.get_fonts`).    * For a **new,\"\n#~ \" non-builtin** font, proceed as \"\n#~ \"follows::        page.insert_text(point,  # \"\n#~ \"anywhere, but outside all redaction \"\n#~ \"rectangles           \\\"something\\\",  # some \"\n#~ \"non-empty string           fontname=\\\"newname\\\",  \"\n#~ \"# new, unused reference name           \"\n#~ \"fontfile=\\\"...\\\",  # desired font file\"\n#~ \"           render_mode=3,  # makes the text\"\n#~ \" invisible       )       page.add_redact_annot(..., \"\n#~ \"fontname=\\\"newname\\\")\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*(New in v1.16.12)* the :data:`fontsize` \"\n#~ \"to use for the replacing text. If\"\n#~ \" the text is too large to fit,\"\n#~ \" several insertion attempts will be \"\n#~ \"made, gradually reducing the :data:`fontsize`\"\n#~ \" to no less than 4. If then \"\n#~ \"the text will still not fit, no\"\n#~ \" text insertion will take place at\"\n#~ \" all.\"\n#~ msgstr \"\"\n#~ \"*(新機能 v1.16.12)* 置換テキストに使用する :data:`fontsize` \"\n#~ \"です。テキストが収まりきらない場合、:data:`fontsize` \"\n#~ \"を徐々に4未満にならないまで縮小し、テキストがまだ収まらない場合はテキストの挿入は行われません。\"\n\n#~ msgid \"\"\n#~ \"*(New in v1.16.12)* the horizontal \"\n#~ \"alignment for the replacing text. See\"\n#~ \" :meth:`insert_textbox` for available values. \"\n#~ \"The vertical alignment is (approximately) \"\n#~ \"centered if a PDF built-in font\"\n#~ \" is used (CJK or :ref:`Base-14-Fonts`).\"\n#~ msgstr \"\"\n#~ \"*(新機能 v1.16.12)* 置換テキストの水平方向の配置を指定します。使用可能な値については \"\n#~ \":meth:`insert_textbox` を参照してください。PDF組み込みフォント（CJKまたは \"\n#~ \":ref:`Base-14-Fonts`）が使用されている場合、垂直方向の配置は（おおよそ）中央になります。\"\n\n#~ msgid \"\"\n#~ \"*(New in v1.16.12)* the fill color \"\n#~ \"of the rectangle **after applying** the\"\n#~ \" redaction. The default is *white =\"\n#~ \" (1, 1, 1)*, which is also \"\n#~ \"taken if ``None`` is specified. \"\n#~ \"*(Changed in v1.16.13)* To suppress a\"\n#~ \" fill color altogether, specify ``False``.\"\n#~ \" In this cases the rectangle remains\"\n#~ \" transparent.\"\n#~ msgstr \"\"\n#~ \"*(新機能 v1.16.12)* レッドアクションを **適用した後** \"\n#~ \"の矩形の塗りつぶし色です。デフォルトは *white = (1, 1, 1)*\"\n#~ \" で、``None`` が指定された場合もこれが適用されます。 *(新機能 v1.16.13)*\"\n#~ \" 塗りつぶし色を抑制するには、``False`` を指定します。この場合、矩形は透明のままです。\"\n\n#~ msgid \"\"\n#~ \"the created annotation. *(Changed in \"\n#~ \"v1.17.2)* Its standard appearance looks \"\n#~ \"like a red rectangle (no fill \"\n#~ \"color), optionally showing two diagonal \"\n#~ \"lines. Colors, line width, dashing, \"\n#~ \"opacity and blend mode can now be\"\n#~ \" set and applied via :meth:`Annot.update`\"\n#~ \" like with other annotations.\"\n#~ msgstr \"\"\n#~ \"作成されたアノテーション。 *(新機能 v1.17.2)* \"\n#~ \"その標準の外観は赤い矩形（塗りつぶし色なし）のようです。オプションで2つの対角線を表示できます。色、線の幅、破線、不透明度、ブレンドモードは、他の注釈と同様に\"\n#~ \" :meth:`Annot.update` を介して設定および適用できます。\"\n\n#~ msgid \"\"\n#~ \"Find tables on the page and return\"\n#~ \" an object with related information. \"\n#~ \"Typically, only very few of the \"\n#~ \"many arguments ever need to be \"\n#~ \"specified -- they mainly are tools \"\n#~ \"to react to corner case situations.\"\n#~ msgstr \"ページ上のテーブルを検出し、関連情報を持つオブジェクトを返します。通常、指定する必要がある引数は非常に少数であり、主に特殊な状況に対応するためのツールです。\"\n\n#~ msgid \"\"\n#~ \"request a search algorithm. The \"\n#~ \"\\\"lines\\\" default looks for vector \"\n#~ \"drawings. If \\\"text\\\" is specified, text\"\n#~ \" positions are used to generate \"\n#~ \"\\\"virtual\\\" row boundaries. The \\\"text\\\" \"\n#~ \"choices are recommended when dealing \"\n#~ \"with pages without any vector graphics\"\n#~ \" -- like when this is an OCRed\"\n#~ \" page.\"\n#~ msgstr \"検索アルゴリズムを指定します。デフォルトでは「lines」はベクトル描画を探します。指定された場合、「text」ではテキストの位置を使用して「仮想」行境界を生成します。「text」の選択肢は、ベクトルグラフィックが含まれていないページと取り扱う場合に推奨されます。\"\n\n#~ msgid \"\"\n#~ \"The remaining parameters are limits for\"\n#~ \" merging different objects. For instance:\"\n#~ \" Two horizontal lines with the same\"\n#~ \" x-coordinates and a vertical distance \"\n#~ \"less than 3 will be merged \"\n#~ \"(\\\"snapped\\\") to one line.\"\n#~ msgstr \"残りのパラメーターは、異なるオブジェクトを統合するための制限です。例えば、x座標が同じで垂直距離が3未満の2つの水平線は1つの線に「スナップ」されます。\"\n\n#~ msgid \"\"\n#~ \"a `TableFinder` object that has the \"\n#~ \"following significant attributes:  * \"\n#~ \"**cells:** a list of **all bboxes** \"\n#~ \"on the page, that have been \"\n#~ \"identified as table cells (across all\"\n#~ \" tables). Each cell is a tuple \"\n#~ \"`(x0, y0, x1, y1)` of coordinates \"\n#~ \"or `None`. * **tables:** a list of\"\n#~ \" `Table` objects. This is `[]` if \"\n#~ \"the page has no tables. Please \"\n#~ \"note that while single tables can \"\n#~ \"be found as items of this list,\"\n#~ \" the `TableFinder` object itself is \"\n#~ \"also a sequence of it tables. This\"\n#~ \" means that if `tabs` is a \"\n#~ \"`TableFinder` object, then table number \"\n#~ \"\\\"n\\\" is delivered by `tabs.tables[n]` \"\n#~ \"as well as by the shorter \"\n#~ \"`tabs[n]`.   * The `Table` object has\"\n#~ \" the following attributes:     * **bbox:**\"\n#~ \" the bounding box of the table \"\n#~ \"as a tuple `(x0, y0, x1, y1)`.\"\n#~ \"    * **cells:** bounding boxes of \"\n#~ \"the table's cells (list of tuples). \"\n#~ \"A cell may also be `None`.    *\"\n#~ \" **extract():** this method returns the \"\n#~ \"text content of each table cell as\"\n#~ \" a list of list of strings.    \"\n#~ \"* **to_pandas():** this method returns \"\n#~ \"the table as a `pandas \"\n#~ \"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n#~ \"<https://pandas.pydata.org/docs/reference/frame.html>`_.    *\"\n#~ \" **header:** a `TableHeader` object \"\n#~ \"containing header information of the \"\n#~ \"table.    * **col_count:** an integer \"\n#~ \"containing the number of table columns.\"\n#~ \"    * **row_count:** an integer containing\"\n#~ \" the number of table rows.    * \"\n#~ \"**rows:** a list of `TableRow` objects\"\n#~ \" containing two attributes: *bbox* is \"\n#~ \"the boundary box of the row, and\"\n#~ \" *cells* is a list of table \"\n#~ \"cells contained in this row.  * \"\n#~ \"The `TableHeader` object has the \"\n#~ \"following attributes:     * **bbox:** the \"\n#~ \"bounding box of the header.    * \"\n#~ \"**cells:** a list of bounding boxes \"\n#~ \"containing the name of the respective\"\n#~ \" column.    * **names:** a list of\"\n#~ \" strings containing the text of each\"\n#~ \" of the cell bboxes. They represent\"\n#~ \" the column names -- which can \"\n#~ \"be used when exporting the table \"\n#~ \"to pandas DataFrames or CSV, etc.    \"\n#~ \"* **external:** a bool indicating \"\n#~ \"whether the header bbox is outside \"\n#~ \"the table body (`True`) or not. \"\n#~ \"Table headers are never identified by\"\n#~ \" the `TableFinder` logic. Therefore, if \"\n#~ \"*external* is true, then the header \"\n#~ \"cells are not part of any cell \"\n#~ \"identified by `TableFinder`. If `external \"\n#~ \"== False`, then the first table \"\n#~ \"row is the header.  Please have a\"\n#~ \" look at these `Jupyter notebooks \"\n#~ \"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master\"\n#~ \"/table-analysis>`_, which cover standard \"\n#~ \"situations like multiple tables on one\"\n#~ \" page or joining table fragments \"\n#~ \"across multiple pages.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*(Changed in v1.18.0)* The overlapping \"\n#~ \"parts of **images** will be blanked-\"\n#~ \"out for default option \"\n#~ \"`PDF_REDACT_IMAGE_PIXELS`. Option 0 does not\"\n#~ \" touch any images and 1 will \"\n#~ \"remove any image with an overlap. \"\n#~ \"Please be aware that there is a\"\n#~ \" bug for option *PDF_REDACT_IMAGE_PIXELS =\"\n#~ \" 2*: transparent images will be \"\n#~ \"incorrectly handled!\"\n#~ msgstr \"\"\n#~ \"*（v1.18.0で変更）* デフォルトオプション `PDF_REDACT_IMAGE_PIXELS` \"\n#~ \"の場合、**画像** \"\n#~ \"の重なる部分はブランクにされます。オプション0は画像には影響せず、オプション1は重なる画像を完全に削除します。ただし、オプション \"\n#~ \"*PDF_REDACT_IMAGE_PIXELS = 2* \"\n#~ \"にはバグがあることに注意してください：透明な画像が誤って処理されます！\"\n\n#~ msgid \"\"\n#~ \"Automatic line breaks are inserted at\"\n#~ \" word boundaries. The \\\"soft hyphen\\\" \"\n#~ \"character `\\\"&#173;\\\"` can be used to\"\n#~ \" cause hyphenation and thus also \"\n#~ \"cause line breaks. **Forced** line \"\n#~ \"breaks however are only achievable via\"\n#~ \" the HTML tag `<br>` - `\\\"\\\\\\\\n\\\"`\"\n#~ \" is ignored and will be treated \"\n#~ \"like a space.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"The text may include arbitrary languages\"\n#~ \" -- **including right-to-left** \"\n#~ \"languages.\"\n#~ msgstr \"\"\n\n#~ msgid \"**either** be just informed (and accept a no-op),\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**or** (`scale=True` - the default) \"\n#~ \"scale down the content until it \"\n#~ \"fits.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"the text to be written. Can \"\n#~ \"contain plain text and HTML tags \"\n#~ \"with styling instructions. Alternatively, a\"\n#~ \" :ref:`Story` object may be specified \"\n#~ \"(in which case the internal Story \"\n#~ \"generation step will be omitted). A \"\n#~ \"Story must have been generated with \"\n#~ \"all required styling and Archive \"\n#~ \"information.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"optional string containing additional CSS \"\n#~ \"instructions. Ignored if `text` is a \"\n#~ \"Story.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"if necessary scale down the content \"\n#~ \"until it fits in the target \"\n#~ \"rectangle. This sets the down scaling\"\n#~ \" limit. Default is 0, no limit. \"\n#~ \"A value of 1 means no down-\"\n#~ \"scaling. A value of e.g. 0.2 means\"\n#~ \" maximum down-scaling by 80%.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"an Archive object that points to \"\n#~ \"locations where to find images or \"\n#~ \"non-standard fonts. If `text` refers \"\n#~ \"to images, this parameter is always \"\n#~ \"required. Ignored if `text` is a \"\n#~ \"Story.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"A string indicating the requested \"\n#~ \"format, one of the above. A \"\n#~ \"mixture of upper and lower case is\"\n#~ \" supported.  Changed in v1.16.3 Values \"\n#~ \"\\\"words\\\" and \\\"blocks\\\" are now also\"\n#~ \" accepted.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*(new in v1.16.2)* indicator bits to \"\n#~ \"control whether to include images or \"\n#~ \"how text should be handled with \"\n#~ \"respect to white spaces and \"\n#~ \":data:`ligatures`. See :ref:`TextPreserve` for \"\n#~ \"available indicators and \"\n#~ \":ref:`text_extraction_flags` for default settings.\"\n#~ msgstr \"\"\n#~ \"*(v1.16.2で新たに追加)* 画像を含めるか、テキストを空白文字と :data:`ligatures` \"\n#~ \"にどのように処理するかを制御するための指示ビット。使用可能な指示子については:ref:`TextPreserve` \"\n#~ \"を、デフォルト設定についてはText :ref:`text_extraction_flags` を参照してください。\"\n\n#~ msgid \"\"\n#~ \"(new in v1.19.1) sort the output \"\n#~ \"by vertical, then horizontal coordinates. \"\n#~ \"In many cases, this should suffice \"\n#~ \"to generate a \\\"natural\\\" reading order.\"\n#~ \" Has no effect on (X)HTML and \"\n#~ \"XML. Output option **\\\"words\\\"** sorts \"\n#~ \"by `(y1, x0)` of the words' \"\n#~ \"bboxes. Similar is true for \\\"blocks\\\",\"\n#~ \" \\\"dict\\\", \\\"json\\\", \\\"rawdict\\\", \\\"rawjson\\\":\"\n#~ \" they all are sorted by `(y1, \"\n#~ \"x0)` of the resp. block bbox. If\"\n#~ \" specified for \\\"text\\\", then internally\"\n#~ \" \\\"blocks\\\" is used.\"\n#~ msgstr \"\"\n#~ \"(v1.19.1で新たに追加) \"\n#~ \"出力を垂直方向、水平方向の座標で並べ替えます。多くの場合、これで「自然な」読み取り順序を生成できるはずです。これは(X)HTMLおよびXMLには影響しません。出力オプション\"\n#~ \" “words” は単語のbboxの `(y1, x0)` \"\n#~ \"で並べ替えます。同様のことは “blocks”、 “dict”、 “json”、 \"\n#~ \"“rawdict”、 “rawjson”にも当てはまります。それらはすべて、respです。ブロックbboxの \"\n#~ \"`(y1, x0)` でソートされます。 “text” に対して指定された場合、内部的には\"\n#~ \" “blocks” が使用されます。\"\n\n#~ msgid \"\"\n#~ \"(new in v1.23.5) use these characters\"\n#~ \" as *additional* word separators with \"\n#~ \"the \\\"words\\\" output option (ignored \"\n#~ \"otherwise). By default, all white spaces\"\n#~ \" (including non-breaking space `0xA0`) \"\n#~ \"indicate start and end of a word.\"\n#~ \" Now you can specify more characters\"\n#~ \" causing this. For instance, the \"\n#~ \"default will return `\\\"john.doe@outlook.com\\\"` \"\n#~ \"as **one** word. If you specify \"\n#~ \"`delimiters=\\\"@.\\\"` then the **four** words\"\n#~ \" `\\\"john\\\"`, `\\\"doe\\\"`, `\\\"outlook\\\"`, `\\\"com\\\"`\"\n#~ \" will be returned. Other possible \"\n#~ \"uses include ignoring punctuation characters\"\n#~ \" `delimiters=string.punctuation`. The \\\"word\\\" \"\n#~ \"strings will not contain any delimiting\"\n#~ \" character.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"The inclusion of text via the \"\n#~ \"*clip* parameter is decided on a \"\n#~ \"by-character level: **(changed in \"\n#~ \"v1.18.2)** a character becomes part of\"\n#~ \" the output, if its bbox is \"\n#~ \"contained in *clip*. This **deviates** \"\n#~ \"from the algorithm used in redaction \"\n#~ \"annotations: a character will be \"\n#~ \"**removed if its bbox intersects** any\"\n#~ \" redaction annotation.\"\n#~ msgstr \"\"\n#~ \"clipパラメータを使用してテキストを含めるかどうかは、文字単位で決定されます **(v1.18.2で変更)** \"\n#~ \"。キャラクタのbboxが *clip* \"\n#~ \"に含まれている場合、そのキャラクタは出力の一部となります。これは、赤塗りのアノテーションで使用されるアルゴリズムとは \"\n#~ \"**異なります** ：\"\n\n#~ msgid \"\"\n#~ \"a string with interspersed linebreaks \"\n#~ \"where necessary. Changed in v1.19.0: It\"\n#~ \" is based on dedicated code. A \"\n#~ \"tyical use is checking the result \"\n#~ \"of :meth:`Page.search_for`:  >>> rl = \"\n#~ \"page.search_for(\\\"currency:\\\") >>> page.get_textbox(rl[0])\"\n#~ \" 'Currency:' >>>\"\n#~ msgstr \"\"\n\n#~ msgid \"(new in v1.18.17) type of this path.\"\n#~ msgstr \"v1.18.17で新しく追加されたパスのタイプ。\"\n\n#~ msgid \"\"\n#~ \"`(\\\"re\\\", rect, orientation)` - a \"\n#~ \":ref:`Rect`. *Changed in v1.18.17:* Multiple\"\n#~ \" rectangles within the same path are\"\n#~ \" now detected. *Changed in v1.19.2:* \"\n#~ \"added integer `orientation` which is 1\"\n#~ \" resp. -1 indicating whether the \"\n#~ \"enclosed area is rotated left (1 =\"\n#~ \" anti-clockwise), or resp. right \"\n#~ \"[#f7]_.\"\n#~ msgstr \"\"\n#~ \"`(\\\"re\\\", rect, orientation)` - \"\n#~ \":ref:`Rect`。*バージョン1.18.17で変更:* \"\n#~ \"同じパス内の複数の矩形が検出されるようになりました。*バージョン1.19.2で変更:* 整数の \"\n#~ \"orientation が追加され、内包された領域が左に回転（1 = \"\n#~ \"反時計回り）するか、右に回転するかを示します [#f7]_。\"\n\n#~ msgid \"\"\n#~ \"Starting with v1.19.2, quads and \"\n#~ \"rectangles are more reliably recognized \"\n#~ \"as such.\"\n#~ msgstr \"バージョン1.19.2から、四角形と四角形は、より信頼性のある方法で認識されるようになりました。\"\n\n#~ msgid \"\"\n#~ \"**New in v1.22.0:** Specifying `extended=True`\"\n#~ \" significantly alters the output. Most \"\n#~ \"importantly, new dictionary types are \"\n#~ \"present: \\\"clip\\\" and \\\"group\\\". All \"\n#~ \"paths will now be organized in a\"\n#~ \" hierarchic structure which is encoded \"\n#~ \"by the new integer key \\\"level\\\", \"\n#~ \"the hierarchy level. Each group or \"\n#~ \"clip establishes a new hierarchy, which\"\n#~ \" applies to all subsequent paths \"\n#~ \"having a *larger* level value.\"\n#~ msgstr \"\"\n#~ \"**新機能 v1.22.0:** `extended=True` \"\n#~ \"を指定すると、出力が大幅に変更されます。最も重要な変更点は、新しい辞書タイプ「clip」および「group」が存在することです。すべてのパスは、新しい整数キー「level」でエンコードされる階層構造に整理されます。各グループまたはクリップは、その後に大きなレベル値を持つすべての後続のパスに適用される新しい階層を確立します。\"\n\n#~ msgid \"Key `\\\"type\\\"` takes one of the following values:\"\n#~ msgstr \"`\\\"type\\\"` キーは、以下のいずれかの値を取ります：\"\n\n#~ msgid \"\"\n#~ \"**\\\"f\\\"** -- this is a *fill-only*\"\n#~ \" path. Only key-values relevant for\"\n#~ \" this operation have a meaning, \"\n#~ \"irrelevant ones have been added with \"\n#~ \"default values for backward compatibility: \"\n#~ \"`\\\"color\\\"`, `\\\"lineCap\\\"`, `\\\"lineJoin\\\"`, \"\n#~ \"`\\\"width\\\"`, `\\\"closePath\\\"`, `\\\"dashes\\\"` and \"\n#~ \"should be ignored.\"\n#~ msgstr \"\"\n#~ \"**\\\"f\\\"**– これは *fill-only* \"\n#~ \"のパスです。この操作に関連するキーと値だけが意味を持ち、無関係なものは後方互換性を保つためにデフォルトの値が追加されています。したがって、`\\\"color\\\"`、`\\\"lineCap\\\"`、`\\\"lineJoin\\\"`、`\\\"width\\\"`、`\\\"closePath\\\"`、`\\\"dashes\\\"`\"\n#~ \" などは無視されるべきです。\"\n\n#~ msgid \"\"\n#~ \"**\\\"s\\\"** -- this is a *stroke-\"\n#~ \"only* path. Similar to previous, key \"\n#~ \"`\\\"fill\\\"` is present with value `None`.\"\n#~ msgstr \"\"\n#~ \"**\\\"s\\\"** – これは *stroke-only* \"\n#~ \"のパスです。前述のように、キー \\\"fill\\\" が値 `None` で存在します。\"\n\n#~ msgid \"\"\n#~ \"Using class :ref:`Shape`, you should be\"\n#~ \" able to recreate the original \"\n#~ \"drawings on a separate (PDF) page \"\n#~ \"with high fidelity under normal, not \"\n#~ \"too sophisticated circumstances. Please see\"\n#~ \" the following comments on restrictions.\"\n#~ \" A coding draft can be found in\"\n#~ \" section \\\"How to Extract Drawings\\\" \"\n#~ \"of chapter :ref:`FAQ`.\"\n#~ msgstr \"\"\n#~ \":ref:`Shape` \"\n#~ \"クラスを使用すると、通常の、あまり複雑でない状況で、元の図面を高い忠実度で別の（PDF）ページに再作成できるはずです。制約事項に関する以下のコメントを参照してください。コーディングの草案は、FAQの「図面の抽出方法」セクションにあります。\"\n\n#~ msgid \"\"\n#~ \"*New in v1.18.13:* **PDF only.** Try \"\n#~ \"to find the :data:`xref` for each \"\n#~ \"image. Implies `hashes=True`. Adds the \"\n#~ \"`\\\"xref\\\"` key to the dictionary. If \"\n#~ \"not found, the value is 0, which\"\n#~ \" means, the image is either \"\n#~ \"\\\"inline\\\" or otherwise undetectable. Please\"\n#~ \" note that this option has an \"\n#~ \"extended response time, because the MD5\"\n#~ \" hashcode will be computed at least\"\n#~ \" two times for each image with \"\n#~ \"an xref.\"\n#~ msgstr \"\"\n#~ \"*新機能（v1.18.13)*：**PDFのみ。** b各イメージの :data:`xref` \"\n#~ \"を見つけようとします。`hashes=True` を含意します。辞書に `\\\"xref\\\"` \"\n#~ \"キーが追加されます。見つからない場合、値は0で、イメージが「インライン」または他の方法で検出できないことを意味します。このオプションは応答時間が延長されるため、注意が必要です。少なくとも2回のMD5ハッシュコードの計算が各イメージに対して行われます。\"\n\n#~ msgid \"\"\n#~ \"the boundary box of the image --\"\n#~ \" optionally also its transformation matrix.\"\n#~ \"  * *(Changed in v1.16.7)* -- If \"\n#~ \"the page in fact does not display\"\n#~ \" this image, an infinite rectangle is\"\n#~ \" returned now. In previous versions, \"\n#~ \"an exception was raised. Formally \"\n#~ \"invalid parameters still raise exceptions. \"\n#~ \"* *(Changed in v1.17.0)* -- Only \"\n#~ \"images referenced directly by the page\"\n#~ \" are considered. This means that \"\n#~ \"images occurring in embedded PDF pages\"\n#~ \" are ignored and an exception is \"\n#~ \"raised. * *(Changed in v1.18.5)* -- \"\n#~ \"Removed the restriction introduced in \"\n#~ \"v1.17.0: any item of the page's \"\n#~ \"image list may be specified. * \"\n#~ \"*(Changed in v1.18.11)* -- Partially \"\n#~ \"re-instated a restriction: only those \"\n#~ \"images are considered, that are either\"\n#~ \" directly referenced by the page or\"\n#~ \" by a Form XObject directly \"\n#~ \"referenced by the page. * *(Changed \"\n#~ \"in v1.18.11)* -- Optionally also return\"\n#~ \" the transformation matrix together with\"\n#~ \" the bbox as the tuple `(bbox, \"\n#~ \"transform)`.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"*(new in v1.17.5)* -- controls how \"\n#~ \"text is represented. ``True`` outputs \"\n#~ \"each character as a series of \"\n#~ \"elementary draw commands, which leads to\"\n#~ \" a more precise text display in \"\n#~ \"browsers, but a **very much larger** \"\n#~ \"output for text-oriented pages. Display\"\n#~ \" quality for ``False`` relies on the\"\n#~ \" presence of the referenced fonts on\"\n#~ \" the current system. For missing \"\n#~ \"fonts, the internet browser will fall\"\n#~ \" back to some default -- leading \"\n#~ \"to unpleasant appearances. Choose ``False``\"\n#~ \" if you want to parse the text\"\n#~ \" of the SVG.\"\n#~ msgstr \"\"\n#~ \"*(v1.17.5で新規)* \"\n#~ \"–テキストの表現方法を制御します。Trueは、各文字を基本的な描画コマンドのシリーズとして出力し、ブラウザでより正確なテキスト表示を提供しますが、テキスト指向のページでは非常に大きな出力になります。\"\n#~ \" ``False`` \"\n#~ \"の表示品質は、現在のシステム上の参照フォントの存在に依存しています。不足しているフォントの場合、インターネットブラウザはデフォルトにフォールバックし、不快な外観になります。\"\n#~ \" SVGのテキストを解析する場合は ``False`` を選択してください。\"\n\n#~ msgid \"\"\n#~ \"whether to add an alpha channel. \"\n#~ \"Always accept the default ``False`` if\"\n#~ \" you do not really need transparency.\"\n#~ \" This will save a lot of memory\"\n#~ \" (25% in case of RGB ... and\"\n#~ \" pixmaps are typically **large**!), and \"\n#~ \"also processing time. Also note an \"\n#~ \"**important difference** in how the \"\n#~ \"image will be rendered: with ``True``\"\n#~ \" the pixmap's samples area will be\"\n#~ \" pre-cleared with *0x00*. This \"\n#~ \"results in **transparent** areas where \"\n#~ \"the page is empty. With ``False`` \"\n#~ \"the pixmap's samples will be pre-\"\n#~ \"cleared with *0xff*. This results in \"\n#~ \"**white** where the page has nothing \"\n#~ \"to show.  Changed in v1.14.17    The \"\n#~ \"default alpha value is now ``False``.\"\n#~ \"     * Generated with *alpha=True*     ..\"\n#~ \" image:: images/img-alpha-1.*      * \"\n#~ \"Generated with *alpha=False*     .. image::\"\n#~ \" images/img-alpha-0.*\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"(new in v1.19.0) use a previously \"\n#~ \"created :ref:`TextPage`. This reduces \"\n#~ \"execution time **significantly.** If \"\n#~ \"specified, the 'flags' and 'clip' \"\n#~ \"arguments are ignored. If omitted, a \"\n#~ \"temporary textpage will be created.\"\n#~ msgstr \"\"\n#~ \"(v1.19.0で新規追加) 以前に作成した :ref:`TextPage` \"\n#~ \"を使用します。これにより、実行時間が大幅に短縮されます。指定した場合、「flags」と「clip」引数は無視されます。省略した場合、一時的なテキストページが作成されます。\"\n\n#~ msgid \"\"\n#~ \"A list of :ref:`Rect` or  :ref:`Quad`\"\n#~ \" objects, each of which  -- \"\n#~ \"**normally!** -- surrounds one occurrence \"\n#~ \"of *needle*. **However:** if parts of\"\n#~ \" *needle* occur on more than one \"\n#~ \"line, then a separate item is \"\n#~ \"generated for each these parts. So, \"\n#~ \"if `needle = \\\"search string\\\"`, two \"\n#~ \"rectangles may be generated.  **Changes \"\n#~ \"in v1.18.2:**    * There no longer \"\n#~ \"is a limit on the list length \"\n#~ \"(removal of the `hit_max` parameter).   \"\n#~ \"* If a word is **hyphenated** at\"\n#~ \" a line break, it will still be\"\n#~ \" found. E.g. the needle \\\"method\\\" \"\n#~ \"will be found even if hyphenated \"\n#~ \"as \\\"meth-od\\\" at a line break,\"\n#~ \" and two rectangles will be returned:\"\n#~ \" one surrounding \\\"meth\\\" (without the \"\n#~ \"hyphen) and another one surrounding \"\n#~ \"\\\"od\\\".\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"a `TableFinder` object that has the \"\n#~ \"following significant attributes:  * \"\n#~ \"**cells:** a list of **all bboxes** \"\n#~ \"on the page, that have been \"\n#~ \"identified as table cells (across all\"\n#~ \" tables). Each cell is a tuple \"\n#~ \"`(x0, y0, x1, y1)` of coordinates \"\n#~ \"or `None`. * **tables:** a list of\"\n#~ \" `Table` objects. This is `[]` if \"\n#~ \"the page has no tables. Single \"\n#~ \"tables can be found as items of\"\n#~ \" this list. But the `TableFinder` \"\n#~ \"object itself is also a sequence \"\n#~ \"of its tables. This means that if\"\n#~ \" `tabs` is a `TableFinder` object, \"\n#~ \"then table \\\"n\\\" is delivered by \"\n#~ \"`tabs.tables[n]` as well as by the \"\n#~ \"shorter `tabs[n]`.   * The `Table` \"\n#~ \"object has the following attributes:    \"\n#~ \"* **bbox:** the bounding box of \"\n#~ \"the table as a tuple `(x0, y0, \"\n#~ \"x1, y1)`.   * **cells:** bounding boxes\"\n#~ \" of the table's cells (list of \"\n#~ \"tuples). A cell may also be \"\n#~ \"`None`.   * **extract():** this method \"\n#~ \"returns the text content of each \"\n#~ \"table cell as a list of list \"\n#~ \"of strings.   * **to_pandas():** this \"\n#~ \"method returns the table as a \"\n#~ \"`pandas <https://pypi.org/project/pandas/>`_ `DataFrame\"\n#~ \" <https://pandas.pydata.org/docs/reference/frame.html>`_.   *\"\n#~ \" **header:** a `TableHeader` object \"\n#~ \"containing header information of the \"\n#~ \"table.   * **col_count:** an integer \"\n#~ \"containing the number of table columns.\"\n#~ \"   * **row_count:** an integer containing\"\n#~ \" the number of table rows.   * \"\n#~ \"**rows:** a list of `TableRow` objects\"\n#~ \" containing two attributes: *bbox* is \"\n#~ \"the boundary box of the row, and\"\n#~ \" *cells* is a list of table \"\n#~ \"cells contained in this row.  * \"\n#~ \"The `TableHeader` object has the \"\n#~ \"following attributes:    * **bbox:** the \"\n#~ \"bounding box of the header.   * \"\n#~ \"**cells:** a list of bounding boxes \"\n#~ \"containing the name of the respective\"\n#~ \" column.   * **names:** a list of \"\n#~ \"strings containing the text of each \"\n#~ \"of the cell bboxes. They represent \"\n#~ \"the column names -- which can be\"\n#~ \" used when exporting the table to \"\n#~ \"pandas DataFrames or CSV, etc.   * \"\n#~ \"**external:** a bool indicating whether \"\n#~ \"the header bbox is outside the \"\n#~ \"table body (`True`) or not. Table \"\n#~ \"headers are never identified by the \"\n#~ \"`TableFinder` logic. Therefore, if *external*\"\n#~ \" is true, then the header cells \"\n#~ \"are not part of any cell \"\n#~ \"identified by `TableFinder`. If `external \"\n#~ \"== False`, then the first table \"\n#~ \"row is the header.  Please have a\"\n#~ \" look at these `Jupyter notebooks \"\n#~ \"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master\"\n#~ \"/table-analysis>`_, which cover standard \"\n#~ \"situations like multiple tables on one\"\n#~ \" page or joining table fragments \"\n#~ \"across multiple pages.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"**to_pandas():** this method returns the \"\n#~ \"table as a `pandas \"\n#~ \"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n#~ \"<https://pandas.pydata.org/docs/reference/frame.html>`_.\"\n#~ msgstr \"\"\n#~ \"**to_pandas():** このメソッドは、テーブルを `pandas \"\n#~ \"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n#~ \"<https://pandas.pydata.org/docs/reference/frame.html>`_ として返します。\"\n\n#~ msgid \"\"\n#~ \"How to redact overlapping images. The\"\n#~ \" default (2) blanks out overlapping \"\n#~ \"pixels. *PDF_REDACT_IMAGE_NONE* (0) ignores, \"\n#~ \"and *PDF_REDACT_IMAGE_REMOVE* (1) completely \"\n#~ \"removes all overlapping images.\"\n#~ msgstr \"重なる画像の赤字領域の処理方法。デフォルト（2）では重なるピクセルを消去します\"\n\n#~ msgid \"\"\n#~ \"The overlapping parts of **images** will\"\n#~ \" be blanked-out for default option\"\n#~ \" `PDF_REDACT_IMAGE_PIXELS` (changed in v1.18.0).\"\n#~ \" Option 0 does not touch any \"\n#~ \"images and 1 will remove any image\"\n#~ \" with an overlap. Please be aware \"\n#~ \"that there is a bug for option \"\n#~ \"*PDF_REDACT_IMAGE_PIXELS = 2*: transparent \"\n#~ \"images will be incorrectly handled!\"\n#~ msgstr \"\"\n\n#~ msgid \"PDF only: Add text in a given rectangle.\"\n#~ msgstr \"PDFのみ: 指定された矩形にテキストを追加します。\"\n\n#~ msgid \"\"\n#~ \"the text. May contain any mixture \"\n#~ \"of Latin, Greek, Cyrillic, Chinese, \"\n#~ \"Japanese and Korean characters. The \"\n#~ \"respective required font is automatically \"\n#~ \"determined. (New in v1.17.0)\"\n#~ msgstr \"\"\n#~ \"テキスト。*（v1.17.0で新規追加）* \"\n#~ \"ラテン文字、ギリシャ文字、キリル文字、中国語、日本語、韓国語の文字を任意の組み合わせで含めることができます。必要なフォントは自動的に決定されます。\"\n\n#~ msgid \"\"\n#~ \"the font name. Default is \\\"Helv\\\". \"\n#~ \"Accepted alternatives are \\\"Cour\\\", \\\"TiRo\\\",\"\n#~ \" \\\"ZaDb\\\" and \\\"Symb\\\". The name may\"\n#~ \" be abbreviated to the first two \"\n#~ \"characters, like \\\"Co\\\" for \\\"Cour\\\". \"\n#~ \"Lower case is also accepted. Bold \"\n#~ \"or italic variants of the fonts \"\n#~ \"are **not accepted** (changed in \"\n#~ \"v1.16.0). A user-contributed script \"\n#~ \"provides a circumvention for this \"\n#~ \"restriction -- see section *Using \"\n#~ \"Buttons and JavaScript* in chapter \"\n#~ \":ref:`FAQ`. The actual font to use \"\n#~ \"is now determined on a by-\"\n#~ \"character level, and all required fonts\"\n#~ \" (or sub-fonts) are automatically \"\n#~ \"included. Therefore, you should rarely \"\n#~ \"ever need to care about this \"\n#~ \"parameter and let it default (except \"\n#~ \"you insist on a serifed font for\"\n#~ \" your non-CJK text parts). (New \"\n#~ \"in v1.17.0)\"\n#~ msgstr \"\"\n#~ \"フォント名。デフォルトは \\\"Helv\\\" です。受け入れられる代替は \"\n#~ \"\\\"Cour\\\"、\\\"TiRo\\\"、\\\"ZaDb\\\"、\\\"Symb\\\" です。名前は \\\"Cour\\\" \"\n#~ \"のように最初の2文字に省略されることがあります。小文字も受け入れられます。太字やイタリックのバリアントのフォントは受け入れられません（v1.16.0で変更）。ユーザー投稿のスクリプトがこの制限を回避する方法を提供しています\"\n#~ \" - \"\n#~ \"FAQの章の「ボタンとJavaScriptの使用」セクションを参照してください。使用する実際のフォントは、今では文字ごとに決定され、必要なすべてのフォント（またはサブフォント）が自動的に含まれます。したがって、このパラメーターについて心配する必要があることはほとんどありませんし、デフォルトのままにしておくことが推奨されます（非CJKテキスト部分にセリフのあるフォントが必要な場合を除く）。（v1.17.0で新規）\"\n\n#~ msgid \"the fill color. Default is white. (New in v1.16.0)\"\n#~ msgstr \"塗りつぶしの色です。デフォルトは白です。(v1.16.0 で新規追加)\"\n\n#~ msgid \"the text color. Default is black.\"\n#~ msgstr \"テキストの色。デフォルトは黒です。\"\n\n#~ msgid \"the border color. Default is `None`. (New in v1.19.6)\"\n#~ msgstr \"*（v1.19.6で新規追加）* 境界色。デフォルトは `None` です。\"\n\n#~ msgid \"\"\n#~ \"text alignment, one of TEXT_ALIGN_LEFT, \"\n#~ \"TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT - justify \"\n#~ \"is **not supported**. (New in v1.17.0)\"\n#~ msgstr \"\"\n#~ \"テキストの配置は、TEXT_ALIGN_LEFT、TEXT_ALIGN_CENTER、TEXT_ALIGN_RIGHTのいずれかを指定します。ジャスティファイは\"\n#~ \" **サポートされていません** 。(v1.17.0で新規追加)\"\n\n#~ msgid \"\"\n#~ \"the created annotation. Color properties \"\n#~ \"**can only be changed** using special\"\n#~ \" parameters of :meth:`Annot.update`. There, \"\n#~ \"you can also set a border color\"\n#~ \" different from the text color.\"\n#~ msgstr \"\"\n#~ \"作成された注釈。色のプロパティは、:meth:`Annot.update` の特別なパラメータを使用して \"\n#~ \"**のみ変更できます**。そこでは、テキストの色とは異なる境界色を設定することもできます。\"\n\n#~ msgid \"\"\n#~ \"the font to use when *text* is \"\n#~ \"given, otherwise ignored. The same rules\"\n#~ \" apply as for :meth:`Page.insert_textbox` \"\n#~ \"-- which is the method \"\n#~ \":meth:`Page.apply_redactions` internally invokes. \"\n#~ \"The replacement text will be \"\n#~ \"**vertically centered**, if this is one\"\n#~ \" of the CJK or :ref:`Base-14-Fonts`. \"\n#~ \"(New in v1.16.12)  .. note::     * \"\n#~ \"For an **existing** font of the \"\n#~ \"page, use its reference name as \"\n#~ \"*fontname* (this is *item[4]* of its \"\n#~ \"entry in :meth:`Page.get_fonts`).    * For \"\n#~ \"a **new, non-builtin** font, proceed \"\n#~ \"as follows::        page.insert_text(point,  # \"\n#~ \"anywhere, but outside all redaction \"\n#~ \"rectangles           \\\"something\\\",  # some \"\n#~ \"non-empty string           fontname=\\\"newname\\\",  \"\n#~ \"# new, unused reference name           \"\n#~ \"fontfile=\\\"...\\\",  # desired font file\"\n#~ \"           render_mode=3,  # makes the text\"\n#~ \" invisible       )       page.add_redact_annot(..., \"\n#~ \"fontname=\\\"newname\\\")\"\n#~ msgstr \"\"\n#~ \"（新機能 v1.16.12）テキストが指定された場合に使用するフォントで、それ以外の場合は無視されます。 \"\n#~ \":meth:`Page.insert_textbox` \"\n#~ \"に適用されるルールと同じです。:meth:`Page.apply_redactions` \"\n#~ \"が内部的に呼び出すメソッドです。置換テキストは、CJKフォントまたは P :ref:`Base-14-Fonts`\"\n#~ \" の場合、垂直方向に中央揃えになります。\"\n\n#~ msgid \"\"\n#~ \"the font to use when *text* is \"\n#~ \"given, otherwise ignored. The same rules\"\n#~ \" apply as for :meth:`Page.insert_textbox` \"\n#~ \"-- which is the method \"\n#~ \":meth:`Page.apply_redactions` internally invokes. \"\n#~ \"The replacement text will be \"\n#~ \"**vertically centered**, if this is one\"\n#~ \" of the CJK or :ref:`Base-14-Fonts`. \"\n#~ \"(New in v1.16.12)\"\n#~ msgstr \"\"\n#~ \"（新機能 v1.16.12）テキストが指定された場合に使用するフォントで、それ以外の場合は無視されます。 \"\n#~ \":meth:`Page.insert_textbox` \"\n#~ \"に適用されるルールと同じです。:meth:`Page.apply_redactions` \"\n#~ \"が内部的に呼び出すメソッドです。置換テキストは、CJKフォントまたは P :ref:`Base-14-Fonts`\"\n#~ \" の場合、垂直方向に中央揃えになります。\"\n\n#~ msgid \"\"\n#~ \"For an **existing** font of the \"\n#~ \"page, use its reference name as \"\n#~ \"*fontname* (this is *item[4]* of its \"\n#~ \"entry in :meth:`Page.get_fonts`).\"\n#~ msgstr \"\"\n#~ \"ページの **既存** のフォントの場合、参照名を *fontname* \"\n#~ \"として使用してください（これは :meth:`Page.get_fonts` のエントリの \"\n#~ \"*item[4]* です）。\"\n\n#~ msgid \"For a **new, non-builtin** font, proceed as follows::\"\n#~ msgstr \"**新しいビルトインでない** フォントの場合、次の手順を実行します::\"\n\n#~ msgid \"\"\n#~ \"a `TableFinder` object that has the \"\n#~ \"following significant attributes:  * `cells`:\"\n#~ \" a list of **all bboxes** on \"\n#~ \"the page, that have been identified \"\n#~ \"as table cells (across all tables). \"\n#~ \"Each cell is a :data:`rect_like` tuple\"\n#~ \" `(x0, y0, x1, y1)` of coordinates\"\n#~ \" or `None`. * `tables`: a list \"\n#~ \"of `Table` objects. This is `[]` \"\n#~ \"if the page has no tables. Single\"\n#~ \" tables can be found as items \"\n#~ \"of this list. But the `TableFinder` \"\n#~ \"object itself is also a sequence \"\n#~ \"of its tables. This means that if\"\n#~ \" `tabs` is a `TableFinder` object, \"\n#~ \"then table \\\"n\\\" is delivered by \"\n#~ \"`tabs.tables[n]` as well as by the \"\n#~ \"shorter `tabs[n]`.   * The `Table` \"\n#~ \"object has the following attributes:    \"\n#~ \"* `bbox`: the bounding box of the\"\n#~ \" table as a tuple `(x0, y0, x1,\"\n#~ \" y1)`.   * `cells`: bounding boxes of\"\n#~ \" the table's cells (list of tuples).\"\n#~ \" A cell may also be `None`.   *\"\n#~ \" `extract()`: this method returns the \"\n#~ \"text content of each table cell as\"\n#~ \" a list of list of strings.   *\"\n#~ \" `to_markdown()`: this method returns the\"\n#~ \" table as a **string in markdown \"\n#~ \"format** (compatible to Github). Supporting\"\n#~ \" viewers can render the string as \"\n#~ \"a table. This output is optimized \"\n#~ \"for **small token** sizes, which is \"\n#~ \"especially beneficial for LLM/RAG feeds. \"\n#~ \"Pandas DataFrames (see method `to_pandas()`\"\n#~ \" below) offer an equivalent markdown \"\n#~ \"table output which however is better \"\n#~ \"readable for the human eye.   * \"\n#~ \"`to_pandas()`: this method returns the \"\n#~ \"table as a `pandas \"\n#~ \"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n#~ \"<https://pandas.pydata.org/docs/reference/frame.html>`_. \"\n#~ \"DataFrames are very versatile objects \"\n#~ \"allowing a plethora of table \"\n#~ \"manipulation methods and outputs to \"\n#~ \"almost 20 well-known formats, among \"\n#~ \"them Excel files, CSV, JSON, \"\n#~ \"markdown-formatted tables and more. \"\n#~ \"`DataFrame.to_markdown()` generates a Github-\"\n#~ \"compatible markdown format optimized for \"\n#~ \"human readability. This method however \"\n#~ \"requires the package \"\n#~ \"[tablutate](https://pypi.org/project/tabulate/) to \"\n#~ \"installed in addition to pandas itself.\"\n#~ \"   * ``header``: a `TableHeader` object \"\n#~ \"containing header information of the \"\n#~ \"table.   * `col_count`: an integer \"\n#~ \"containing the number of table columns.\"\n#~ \"   * `row_count`: an integer containing \"\n#~ \"the number of table rows.   * \"\n#~ \"`rows`: a list of `TableRow` objects \"\n#~ \"containing two attributes, ``bbox`` is \"\n#~ \"the boundary box of the row, and\"\n#~ \" `cells` is a list of table \"\n#~ \"cells contained in this row.  * \"\n#~ \"The `TableHeader` object has the \"\n#~ \"following attributes:    * ``bbox``: the \"\n#~ \"bounding box of the header.   * \"\n#~ \"`cells`: a list of bounding boxes \"\n#~ \"containing the name of the respective\"\n#~ \" column.   * `names`: a list of \"\n#~ \"strings containing the text of each \"\n#~ \"of the cell bboxes. They represent \"\n#~ \"the column names -- which are used\"\n#~ \" when exporting the table to pandas\"\n#~ \" DataFrames, markdown, etc.   * `external`:\"\n#~ \" a bool indicating whether the header\"\n#~ \" bbox is outside the table body \"\n#~ \"(`True`) or not. Table headers are \"\n#~ \"never identified by the `TableFinder` \"\n#~ \"logic. Therefore, if `external` is true,\"\n#~ \" then the header cells are not \"\n#~ \"part of any cell identified by \"\n#~ \"`TableFinder`. If `external == False`, \"\n#~ \"then the first table row is the\"\n#~ \" header.  Please have a look at \"\n#~ \"these `Jupyter notebooks <https://github.com/pymupdf\"\n#~ \"/PyMuPDF-Utilities/tree/master/table-analysis>`_, which\"\n#~ \" cover standard situations like multiple\"\n#~ \" tables on one page or joining \"\n#~ \"table fragments across multiple pages.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"PDF only: Add a \\\"rubber stamp\\\" \"\n#~ \"like annotation to e.g. indicate the \"\n#~ \"document's intended use (\\\"DRAFT\\\", \"\n#~ \"\\\"CONFIDENTIAL\\\", etc.).\"\n#~ msgstr \"PDF専用: \\\"ドラフト\\\"、\\\"機密\\\"などの文書の意図した使用を示すための「スタンプ」のような注釈を追加します。\"\n\n#~ msgid \"\"\n#~ \"The stamp's text and its border \"\n#~ \"line will automatically be sized and \"\n#~ \"be put horizontally and vertically \"\n#~ \"centered in the given rectangle. \"\n#~ \":attr:`Annot.rect` is automatically calculated \"\n#~ \"to fit the given **width** and \"\n#~ \"will usually be smaller than this \"\n#~ \"parameter.\"\n#~ msgstr \"\"\n#~ \"スタンプのテキストとその境界線は、自動的にサイズ変更され、指定された矩形内で水平および垂直方向に中央に配置されます。:attr:`Annot.rect`\"\n#~ \" は指定された **幅** に合わせて自動的に計算され、通常はこのパラメータよりも小さくなります。\"\n\n#~ msgid \"\"\n#~ \"This can be used to create \"\n#~ \"watermark images: on a temporary PDF \"\n#~ \"page create a stamp annotation with \"\n#~ \"a low opacity value, make a pixmap\"\n#~ \" from it with *alpha=True* (and \"\n#~ \"potentially also rotate it), discard the\"\n#~ \" temporary PDF page and use the \"\n#~ \"pixmap with :meth:`insert_image` for your \"\n#~ \"target PDF.\"\n#~ msgstr \"\"\n#~ \"これは透かし画像を作成するために使用できます。一時的なPDFページ上に低い不透明度のスタンプ注釈を作成し、*alpha=True* \"\n#~ \"でそれからピクスマップを作成し（おそらく回転させることもあります）、一時的なPDFページを破棄し、ターゲットのPDFに挿入するためにピクスマップを\"\n#~ \" :meth:`insert_image` で使用します。\"\n\n#~ msgid \"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"words\\\" -- :meth:`TextPage.extractWORDS`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"html\\\" -- :meth:`TextPage.extractHTML`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"xhtml\\\" -- :meth:`TextPage.extractXHTML`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"xml\\\" -- :meth:`TextPage.extractXML`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"dict\\\" -- :meth:`TextPage.extractDICT`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"json\\\" -- :meth:`TextPage.extractJSON`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"rawdict\\\" -- :meth:`TextPage.extractRAWDICT`\"\n#~ msgstr \"\"\n\n#~ msgid \"\\\"rawjson\\\" -- :meth:`TextPage.extractRAWJSON`\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"A string indicating the requested \"\n#~ \"format, one of the above. A \"\n#~ \"mixture of upper and lower case is\"\n#~ \" supported.  Values \\\"words\\\" and \"\n#~ \"\\\"blocks\\\" are also accepted (changed in\"\n#~ \" v1.16.3).\"\n#~ msgstr \"要求される形式を示す文字列、上記のいずれか。大文字と小文字の組み合わせがサポートされています\"\n\n#~ msgid \"Values \\\"words\\\" and \\\"blocks\\\" are also accepted (changed in v1.16.3).\"\n#~ msgstr \"v1.16.3で変更された値 “words” と “blocks” も受け入れられるようになりました。\"\n\n#~ msgid \"\"\n#~ \"restrict extracted text to this \"\n#~ \"rectangle. If None, the full page \"\n#~ \"is taken. Has **no effect** for \"\n#~ \"options \\\"html\\\", \\\"xhtml\\\" and \\\"xml\\\". \"\n#~ \"(New in v1.17.7)\"\n#~ msgstr \"\"\n#~ \"*(v1.17.7で新たに追加)* 抽出されたテキストをこの矩形に制限します。Noneの場合、フルページが取得されます。 \"\n#~ \"“html”、“xhtml”、“xml”のオプションには **影響しません**。\"\n\n#~ msgid \"\"\n#~ \"sort the output by vertical, then \"\n#~ \"horizontal coordinates. In many cases, \"\n#~ \"this should suffice to generate a \"\n#~ \"\\\"natural\\\" reading order. Has no effect\"\n#~ \" on (X)HTML and XML. Output option\"\n#~ \" **\\\"words\\\"** sorts by `(y1, x0)` of\"\n#~ \" the words' bboxes. Similar is true\"\n#~ \" for \\\"blocks\\\", \\\"dict\\\", \\\"json\\\", \"\n#~ \"\\\"rawdict\\\", \\\"rawjson\\\": they all are \"\n#~ \"sorted by `(y1, x0)` of the resp.\"\n#~ \" block bbox. If specified for \"\n#~ \"\\\"text\\\", then internally \\\"blocks\\\" is \"\n#~ \"used. (New in v1.19.1)\"\n#~ msgstr \"\"\n#~ \"出力を垂直座標、次に水平座標でソートします。多くの場合、これで「自然な」読み取り順序を生成するのに十分です。 \"\n#~ \"(X)HTMLおよびXMLには影響しません。出力オプション「words」は、単語の境界ボックスの  `(y1, \"\n#~ \"x0)`  \"\n#~ \"でソートされます。\\\"blocks\\\"、\\\"dict\\\"、\\\"json\\\"、\\\"rawdict\\\"、\\\"rawjson\\\" \"\n#~ \"についても同様であり、それぞれのブロックの境界ボックスの  `(y1, x0)`  でソートされます。\"\n#~ \" \\\"text\\\" に対して指定された場合、内部的には \\\"blocks\\\" が使用されます。\"\n#~ \" (v1.19.1で新たに追加)\"\n\n#~ msgid \"\"\n#~ \"The inclusion of text via the \"\n#~ \"*clip* parameter is decided on a \"\n#~ \"by-character level: a character becomes \"\n#~ \"part of the output, if its bbox\"\n#~ \" is contained in *clip* (changed in\"\n#~ \" v1.18.2). This **deviates** from the \"\n#~ \"algorithm used in redaction annotations: \"\n#~ \"a character will be **removed if \"\n#~ \"its bbox intersects** any redaction \"\n#~ \"annotation.\"\n#~ msgstr \"\"\n#~ \"*clip* パラメータを使用したテキストの含み方は、文字ごとのレベルで決定されます：文字のバウンディングボックスが \"\n#~ \"*clip*  に含まれる場合、その文字は出力の一部となります（v1.18.2で変更）。 \"\n#~ \"これは、レダクション注釈で使用されるアルゴリズムとは異なります：文字のバウンディングボックスがどのレダクション注釈とも交差する場合、文字は削除されます。\"\n\n#~ msgid \"\"\n#~ \"a :ref:`TextPage`. Execution may be \"\n#~ \"significantly longer than :meth:`Page.get_textpage`.\"\n#~ \"  For a full page OCR, **all \"\n#~ \"text** will have the font \"\n#~ \"\\\"GlyphlessFont\\\" from Tesseract. In case \"\n#~ \"of partial OCR, normal text will \"\n#~ \"keep its properties, and only text \"\n#~ \"coming from images will have the \"\n#~ \"GlyphlessFont.  .. note::     **OCRed text \"\n#~ \"is only available** to PyMuPDF's text\"\n#~ \" extractions and searches if their \"\n#~ \"`textpage` parameter specifies the output \"\n#~ \"of this method.     `This \"\n#~ \"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master\"\n#~ \"/jupyter-notebooks/partial-ocr.ipynb>`_ Jupyter \"\n#~ \"notebook walks through an example for\"\n#~ \" using OCR textpages.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Return a list of meta information \"\n#~ \"dictionaries for all images shown on \"\n#~ \"the page. This works for all \"\n#~ \"document types. Technically, this is a\"\n#~ \" subset of the dictionary output of\"\n#~ \" :meth:`Page.get_text`: the image binary \"\n#~ \"content and any text on the page\"\n#~ \" are ignored.\"\n#~ msgstr \"\"\n#~ \"ページ上に表示されているすべてのイメージに関するメタ情報辞書のリストを返します。これはすべての文書タイプで機能します。技術的には、これは\"\n#~ \" :meth:`Page.get_text` \"\n#~ \"の辞書出力のサブセットであり、画像のバイナリコンテンツとページ上のテキストは無視されます。\"\n\n#~ msgid \"\"\n#~ \"**PDF only.** Try to find the \"\n#~ \":data:`xref` for each image. Implies \"\n#~ \"`hashes=True`. Adds the `\\\"xref\\\"` key \"\n#~ \"to the dictionary. If not found, \"\n#~ \"the value is 0, which means, the\"\n#~ \" image is either \\\"inline\\\" or \"\n#~ \"otherwise undetectable. Please note that \"\n#~ \"this option has an extended response \"\n#~ \"time, because the MD5 hashcode will \"\n#~ \"be computed at least two times for\"\n#~ \" each image with an xref. (New \"\n#~ \"in v1.18.13)\"\n#~ msgstr \"\"\n#~ \"**PDFのみ。** 各画像の :data:`xref` \"\n#~ \"を見つけようとします。`hashes=True` を意味します。辞書に `\\\"xref\\\"` \"\n#~ \"キーを追加します。見つからない場合、値は0で、画像が「インライン」であるか、または他の方法で検出できないことを意味します。このオプションは、少なくとも各画像に対してMD5ハッシュコードが2回計算されるため、応答時間が延びることに注意してください。(v1.18.13で新規追加)\"\n\n#~ msgid \"\"\n#~ \"A list of dictionaries. This includes\"\n#~ \" information for **exactly those** images,\"\n#~ \" that are shown on the page --\"\n#~ \" including *\\\"inline images\\\"*. In contrast\"\n#~ \" to images included in \"\n#~ \":meth:`Page.get_text`, image **binary content** \"\n#~ \"is not loaded, which drastically reduces\"\n#~ \" memory usage. The dictionary layout \"\n#~ \"is similar to that of image blocks\"\n#~ \" in `page.get_text(\\\"dict\\\")`.  =============== \"\n#~ \"=============================================================== \"\n#~ \"**Key**             **Value** =============== \"\n#~ \"=============================================================== \"\n#~ \"number          block number *(int)* bbox\"\n#~ \"            image bbox on page, \"\n#~ \":data:`rect_like` width           original image \"\n#~ \"width *(int)* height          original image\"\n#~ \" height *(int)* cs-name         colorspace\"\n#~ \" name *(str)* colorspace      colorspace.n \"\n#~ \"*(int)* xres            resolution in \"\n#~ \"x-direction *(int)* yres            resolution \"\n#~ \"in y-direction *(int)* bpc             bits\"\n#~ \" per component *(int)* size            \"\n#~ \"storage occupied by image *(int)* digest\"\n#~ \"          MD5 hashcode *(bytes)*, if \"\n#~ \"*hashes* is true xref            image \"\n#~ \":data:`xref` or 0, if *xrefs* is \"\n#~ \"true transform       matrix transforming image\"\n#~ \" rect to bbox, :data:`matrix_like` \"\n#~ \"=============== \"\n#~ \"===============================================================  \"\n#~ \"Multiple occurrences of the same image\"\n#~ \" are always reported. You can detect\"\n#~ \" duplicates by comparing their `digest` \"\n#~ \"values.\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This parameter only has an effect \"\n#~ \"if `richtext=True`. Otherwise, ``text_color`` \"\n#~ \"is used.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"the width of border and ``callout`` \"\n#~ \"lines. Default is 0 (no border), \"\n#~ \"in which case callout lines may \"\n#~ \"still appear with some hairline width,\"\n#~ \" depending on the PDF viewer used.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"treat ``text`` as HTML syntax. This \"\n#~ \"allows to achieve **bold**, *italic*, \"\n#~ \"arbitrary text colors, font sizes, text\"\n#~ \" alignment including justify and more \"\n#~ \"- as far as HTML and styling \"\n#~ \"instructions support this. This is \"\n#~ \"similar to what happens in \"\n#~ \":meth:`Page.insert_htmlbox`. The base library \"\n#~ \"will for example pull in required \"\n#~ \"fonts if it encounters characters not\"\n#~ \" contained in the standard ones. Some\"\n#~ \" parameters are ignored if this \"\n#~ \"option is set, as mentioned above. \"\n#~ \"Default is ``False``.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"a `TableFinder` object that has the \"\n#~ \"following significant attributes:  * `cells`:\"\n#~ \" a list of **all bboxes** on \"\n#~ \"the page, that have been identified \"\n#~ \"as table cells (across all tables). \"\n#~ \"Each cell is a :data:`rect_like` tuple\"\n#~ \" `(x0, y0, x1, y1)` of coordinates\"\n#~ \" or `None`. * `tables`: a list \"\n#~ \"of `Table` objects. This is `[]` \"\n#~ \"if the page has no tables. Single\"\n#~ \" tables can be found as items \"\n#~ \"of this list. But the `TableFinder` \"\n#~ \"object itself is also a sequence \"\n#~ \"of its tables. This means that if\"\n#~ \" `tabs` is a `TableFinder` object, \"\n#~ \"then table \\\"n\\\" is delivered by \"\n#~ \"`tabs.tables[n]` as well as by the \"\n#~ \"shorter `tabs[n]`.   * The `Table` \"\n#~ \"object has the following attributes:    \"\n#~ \"* ``bbox``: the bounding box of \"\n#~ \"the table as a tuple `(x0, y0, \"\n#~ \"x1, y1)`.   * ``cells``: bounding boxes\"\n#~ \" of the table's cells (list of \"\n#~ \"tuples). A cell may also be \"\n#~ \"`None`.   * ``extract()``: this method \"\n#~ \"returns the text content of each \"\n#~ \"table cell as a list of list \"\n#~ \"of strings.   * ``to_markdown()``: this \"\n#~ \"method returns the table as a \"\n#~ \"**string in markdown format** (compatible \"\n#~ \"to Github). Supporting viewers can \"\n#~ \"render the string as a table. This\"\n#~ \" output is optimized for **small \"\n#~ \"token** sizes, which is especially \"\n#~ \"beneficial for LLM/RAG feeds. Pandas \"\n#~ \"DataFrames (see method `to_pandas()` below)\"\n#~ \" offer an equivalent markdown table \"\n#~ \"output which however is better readable\"\n#~ \" for the human eye.   * \"\n#~ \"`to_pandas()`: this method returns the \"\n#~ \"table as a `pandas \"\n#~ \"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n#~ \"<https://pandas.pydata.org/docs/reference/frame.html>`_. \"\n#~ \"DataFrames are very versatile objects \"\n#~ \"allowing a plethora of table \"\n#~ \"manipulation methods and outputs to \"\n#~ \"almost 20 well-known formats, among \"\n#~ \"them Excel files, CSV, JSON, \"\n#~ \"markdown-formatted tables and more. \"\n#~ \"`DataFrame.to_markdown()` generates a Github-\"\n#~ \"compatible markdown format optimized for \"\n#~ \"human readability. This method however \"\n#~ \"requires the package `tabulate \"\n#~ \"<https://pypi.org/project/tabulate/>`_ to be \"\n#~ \"installed in addition to pandas itself.\"\n#~ \"   * ``header``: a `TableHeader` object \"\n#~ \"containing header information of the \"\n#~ \"table.   * ``col_count``: an integer \"\n#~ \"containing the number of table columns.\"\n#~ \"   * ``row_count``: an integer containing\"\n#~ \" the number of table rows.   * \"\n#~ \"``rows``: a list of `TableRow` objects\"\n#~ \" containing two attributes, ``bbox`` is \"\n#~ \"the boundary box of the row, and\"\n#~ \" `cells` is a list of table \"\n#~ \"cells contained in this row.  * \"\n#~ \"The `TableHeader` object has the \"\n#~ \"following attributes:    * ``bbox``: the \"\n#~ \"bounding box of the header.   * \"\n#~ \"`cells`: a list of bounding boxes \"\n#~ \"containing the name of the respective\"\n#~ \" column.   * `names`: a list of \"\n#~ \"strings containing the text of each \"\n#~ \"of the cell bboxes. They represent \"\n#~ \"the column names -- which are used\"\n#~ \" when exporting the table to pandas\"\n#~ \" DataFrames, markdown, etc.   * `external`:\"\n#~ \" a bool indicating whether the header\"\n#~ \" bbox is outside the table body \"\n#~ \"(`True`) or not. Table headers are \"\n#~ \"never identified by the `TableFinder` \"\n#~ \"logic. Therefore, if `external` is true,\"\n#~ \" then the header cells are not \"\n#~ \"part of any cell identified by \"\n#~ \"`TableFinder`. If `external == False`, \"\n#~ \"then the first table row is the\"\n#~ \" header.  Please have a look at \"\n#~ \"these `Jupyter notebooks <https://github.com/pymupdf\"\n#~ \"/PyMuPDF-Utilities/tree/master/table-analysis>`_, which\"\n#~ \" cover standard situations like multiple\"\n#~ \" tables on one page or joining \"\n#~ \"table fragments across multiple pages.  \"\n#~ \".. caution:: The lifetime of the \"\n#~ \"`TableFinder` object, as well as that\"\n#~ \" of all its tables **equals the \"\n#~ \"lifetime of the page**. If the \"\n#~ \"page object is deleted or reassigned,\"\n#~ \" all tables are no longer valid.\"\n#~ \"     The only way to keep table \"\n#~ \"content beyond the page's availability \"\n#~ \"is to **extract it** via methods \"\n#~ \"`Table.to_markdown()`, `Table.to_pandas()` or a \"\n#~ \"copy of `Table.extract()` (e.g. \"\n#~ \"`Table.extract()[:]`).  .. note::     Once a\"\n#~ \" table has been extracted to a \"\n#~ \"**Pandas DataFrame** with `to_pandas()` it \"\n#~ \"is easy to convert to other file\"\n#~ \" types with the **Pandas API**:     -\"\n#~ \" table to Markdown, use `to_markdown \"\n#~ \"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_markdown.html#pandas.DataFrame.to_markdown>`_\"\n#~ \"    - table to JSON, use: `to_json\"\n#~ \" \"\n#~ \"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html>`_\"\n#~ \"    - table to Excel, use: `to_excel\"\n#~ \" \"\n#~ \"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html>`_\"\n#~ \"    - table to CSV, use: `to_csv \"\n#~ \"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html>`_\"\n#~ \"    - table to HTML, use: `to_html\"\n#~ \" \"\n#~ \"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html>`_\"\n#~ \"    - table to SQL, use: `to_sql \"\n#~ \"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html>`_\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"``to_markdown()``: this method returns the \"\n#~ \"table as a **string in markdown \"\n#~ \"format** (compatible to Github). Supporting\"\n#~ \" viewers can render the string as \"\n#~ \"a table. This output is optimized \"\n#~ \"for **small token** sizes, which is \"\n#~ \"especially beneficial for LLM/RAG feeds. \"\n#~ \"Pandas DataFrames (see method `to_pandas()`\"\n#~ \" below) offer an equivalent markdown \"\n#~ \"table output which however is better \"\n#~ \"readable for the human eye.\"\n#~ msgstr \"\"\n#~ \"`to_markdown()` ：このメソッドは、テーブルをGitHubと互換性のある \"\n#~ \"**Markdown形式の文字列** \"\n#~ \"として返します。サポートされているビューアは、文字列をテーブルとしてレンダリングできます。この出力は、LLM/RAGフィードに特に有益な小さいトークンサイズに最適化されています。PandasのDataFrames（後述の\"\n#~ \" `to_pandas()` \"\n#~ \"メソッドを参照）は、同等のMarkdownテーブル出力を提供しますが、人間の目にはより読みやすいです。\"\n\n#~ msgid \"\"\n#~ \"A tuple of floats `(spare_height, \"\n#~ \"scale)`.  - `spare_height`: -1 if \"\n#~ \"content did not fit, else >= 0.\"\n#~ \" It is the height of the unused\"\n#~ \" (still available) rectangle stripe. \"\n#~ \"Positive only if scale = 1 (no \"\n#~ \"down-scaling happened). - `scale`: \"\n#~ \"down-scaling factor, 0 < scale <= \"\n#~ \"1.  Please refer to examples in \"\n#~ \"this section of the recipes: \"\n#~ \":ref:`RecipesText_I_c`.\"\n#~ msgstr \"\"\n#~ \"`spare_height`: \"\n#~ \"コンテンツが収まらなかった場合は-1、そうでない場合は0以上の値です。未使用の（まだ利用可能な）長方形のストライプの高さです。スケール=1の場合にのみ正の値です（ダウンスケーリングが行われなかった場合）。\"\n\n#~ msgid \"\"\n#~ \"`spare_height`: -1 if content did not\"\n#~ \" fit, else >= 0. It is the \"\n#~ \"height of the unused (still available)\"\n#~ \" rectangle stripe. Positive only if \"\n#~ \"scale = 1 (no down-scaling \"\n#~ \"happened).\"\n#~ msgstr \"\"\n#~ \"`spare_height`: \"\n#~ \"コンテンツが収まらなかった場合は-1、そうでない場合は0以上の値です。未使用の（まだ利用可能な）長方形のストライプの高さです。スケール=1の場合にのみ正の値です（ダウンスケーリングが行われなかった場合）。\"\n\n#~ msgid \"`scale`: down-scaling factor, 0 < scale <= 1.\"\n#~ msgstr \"`scale`: ダウンスケーリングファクター、0 < scale <= 1。\"\n\n#~ msgid \"\"\n#~ \"A list of dictionaries. This includes\"\n#~ \" information for **exactly those** images,\"\n#~ \" that are shown on the page --\"\n#~ \" including *\\\"inline images\\\"*. The \"\n#~ \"dictionary layout is similar to that \"\n#~ \"of image blocks in `page.get_text(\\\"dict\\\")`.\"\n#~ \"  In contrast to images included in\"\n#~ \" :meth:`Page.get_text`, image **binary content**\"\n#~ \" is not loaded by this method, \"\n#~ \"which drastically reduces memory usage. \"\n#~ \"Another difference is that image \"\n#~ \"detection is not restricted to the \"\n#~ \"visible part of the page or any\"\n#~ \" ``clip`` parameter: method :meth:`Page.get_text`\"\n#~ \" will only extract images **fully \"\n#~ \"contained** in the provided ``clip``.  \"\n#~ \"=============== \"\n#~ \"=============================================================== \"\n#~ \"**Key**             **Value** =============== \"\n#~ \"=============================================================== \"\n#~ \"number          block number (``int``) bbox\"\n#~ \"            image bbox on page, \"\n#~ \":data:`rect_like` width           original image \"\n#~ \"width (``int``) height          original image\"\n#~ \" height (``int``) cs-name         \"\n#~ \"colorspace name (``str``) colorspace      \"\n#~ \"colorspace.n (``int``) xres            resolution\"\n#~ \" in x-direction (``int``) yres            \"\n#~ \"resolution in y-direction (``int``) bpc\"\n#~ \"             bits per component (``int``) \"\n#~ \"size            storage occupied by image \"\n#~ \"(``int``) digest          MD5 hashcode \"\n#~ \"(``bytes``), if ``hashes`` is true xref\"\n#~ \"            image :data:`xref` or 0, if \"\n#~ \"*xrefs* is true transform       matrix \"\n#~ \"transforming image rect to bbox, \"\n#~ \":data:`matrix_like` has-mask        whether \"\n#~ \"the image is transparent and has a\"\n#~ \" mask (``bool``) =============== \"\n#~ \"===============================================================  \"\n#~ \"Multiple occurrences of the same image\"\n#~ \" are always reported. You can detect\"\n#~ \" duplicates by comparing their `digest` \"\n#~ \"values.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"PDF only: Display a page of \"\n#~ \"another PDF as a **vector image** \"\n#~ \"(otherwise similar to :meth:`Page.insert_image`).\"\n#~ \" This is a multi-purpose method. \"\n#~ \"For example, you can use it to:\"\n#~ msgstr \"\"\n#~ \"PDFのみ：別のPDFのページをベクトルイメージとして表示します（それ以外は :meth:`Page.insert_image`\"\n#~ \" に類似）。これは多目的なメソッドです。たとえば、次のようなことに使用できます。\"\n\n#~ msgid \"*Document.get_page_fonts(pno)*\"\n#~ msgstr \"\"\n\n#~ msgid \"*Document.get_page_images(pno)*\"\n#~ msgstr \"\"\n\n#~ msgid \"*Document.get_page_pixmap(pno, ...)*\"\n#~ msgstr \"\"\n\n#~ msgid \"*Document.get_page_text(pno, ...)*\"\n#~ msgstr \"\"\n\n#~ msgid \"*Document.search_page_for(pno, ...)*\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/pixmap.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 77cdad9d379a4a459fb8f61a5126752b\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 32cc68ce63c240bdb7a2fdfe4d927af7\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 db64d0baaca745e7910c08e63ef36441\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../pixmap.rst:7 e0494509a30b4c1991cc5e57de63e15b\nmsgid \"Pixmap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:9 32dd6915408a408ea1d9db1812927e46\nmsgid \"\"\n\"Pixmaps (\\\"pixel maps\\\") are objects at the heart of MuPDF's rendering \"\n\"capabilities. They represent plane rectangular sets of pixels. Each pixel\"\n\" is described by a number of bytes (\\\"components\\\") defining its color, \"\n\"plus an optional alpha byte defining its transparency.\"\nmsgstr \"Pixmap（「ピクセルマップ」）は、MuPDFの描画機能の中心にあるオブジェクトです。それらは平面的な長方形のピクセルセットを表します。各ピクセルは、その色を定義するバイト数（「コンポーネント」）と、透明度を定義するオプションのアルファバイトで説明されます\"\n\n#: ../../pixmap.rst:11 0ae7623584d34b0793a6b1689e2e9ff9\nmsgid \"\"\n\"In PyMuPDF, there exist several ways to create a pixmap. Except the first\"\n\" one, all of them are available as overloaded constructors. A pixmap can \"\n\"be created ...\"\nmsgstr \"PyMuPDFでは、ピクセルマップを作成するためのいくつかの方法が存在します。最初の方法を除いて、すべての方法はオーバーロードされたコンストラクタとして使用できます。ピクセルマップは、以下の方法で作成できます...\"\n\n#: ../../pixmap.rst:13 73ba045692a74b84a13ce27f369588ef\nmsgid \"from a document page (method :meth:`Page.get_pixmap`)\"\nmsgstr \"ドキュメントページから（メソッド :meth:`Page.get_pixmap` を使用）\"\n\n#: ../../pixmap.rst:14 d9db8727d6f34c5ea67a95212b48a901\nmsgid \"empty, based on :ref:`Colorspace` and :ref:`IRect` information\"\nmsgstr \":ref:`Colorspace` と :ref:`IRect` 情報に基づいて空のものを作成\"\n\n#: ../../pixmap.rst:15 3bd37a5d119449b79b2df8e6183899b2\nmsgid \"from a file\"\nmsgstr \"ファイルから\"\n\n#: ../../pixmap.rst:16 6c2ae5d2cf9e4e9c8a85876940ac2c65\nmsgid \"from an in-memory image\"\nmsgstr \"メモリ内のイメージから\"\n\n#: ../../pixmap.rst:17 985854117e77421ab5c08305ad9a7ebc\nmsgid \"from a memory area of plain pixels\"\nmsgstr \"平易なピクセルのメモリ領域から\"\n\n#: ../../pixmap.rst:18 51817c0b224a4d79becc251812e52d59\nmsgid \"from an image inside a PDF document\"\nmsgstr \"PDFドキュメント内のイメージから\"\n\n#: ../../pixmap.rst:19 c50a8dabd5de4315af9f49bd6f4e3300\nmsgid \"as a copy of another pixmap\"\nmsgstr \"他のピクセルマップのコピーとして\"\n\n#: ../../pixmap.rst:21 a40603d11eae465f98c51d914e3f60f0\nmsgid \"\"\n\"A number of image formats is supported as input for points 3. and 4. \"\n\"above. See section :ref:`ImageFiles`.\"\nmsgstr \"\"\n\"3.と4.のポイントに対する入力として多くの画像フォーマットがサポートされています。サポートされている入力画像フォーマットの詳細については、:ref:`ImageFiles`\"\n\" のセクションを参照してください。\"\n\n#: ../../pixmap.rst:23 3bdce298316f4c59aea2dcf926ba360d\nmsgid \"\"\n\"Have a look at the :ref:`FAQ` section to see some pixmap usage \\\"at \"\n\"work\\\".\"\nmsgstr \"ピクセルマップの使用例については、:ref:`FAQ` セクションをご覧ください。\"\n\n#: ../../pixmap.rst:26 c77d9f0a0ac441569275429f77da5352\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../pixmap.rst:26 0c5aa62f906e4af38c4f3f15dbd58acb\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../pixmap.rst:28 2202b52b548143ffb14aef4ce3088e4e\nmsgid \":meth:`Pixmap.clear_with`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:28 f8c6fd586d294e3194f9966984db1cd7\nmsgid \"clear parts of the pixmap\"\nmsgstr \"ピクセルマップの一部をクリアします。\"\n\n#: ../../pixmap.rst:29 74887257fa9a4ce4bccdc2c054561ab8\nmsgid \":meth:`Pixmap.color_count`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:29 266d94deb7124050adc51b2d0925c285\nmsgid \"determine used colors\"\nmsgstr \"使用された色を決定します。\"\n\n#: ../../pixmap.rst:30 6fa71e0e57754c778d2a793a2d4b5e0c\nmsgid \":meth:`Pixmap.color_topusage`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:30 40a15ae449a04a5fa2c777c1ac0a6175\nmsgid \"determine share of most used color\"\nmsgstr \"最も使用される色のシェアを決定します。\"\n\n#: ../../pixmap.rst:31 b915ce033980496eb00292ada4fbcca5\nmsgid \":meth:`Pixmap.copy`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:31 8e57cd2829fa414abc482e80c6d4c4d9\nmsgid \"copy parts of another pixmap\"\nmsgstr \"別のピクセルマップの一部をコピーします。\"\n\n#: ../../pixmap.rst:32 112981a34c4348f8ad862d81cdc02514\nmsgid \":meth:`Pixmap.gamma_with`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:32 f42a9b37c4ac4000a006188d993c87e5\nmsgid \"apply a gamma factor to the pixmap\"\nmsgstr \"ピクセルマップにガンマ係数を適用します。\"\n\n#: ../../pixmap.rst:33 01c950df9e2145aa8d39d7760c67ad87\nmsgid \":meth:`Pixmap.invert_irect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:33 8fd44b50652147ff824e5fc414ff6a30\nmsgid \"invert the pixels of a given area\"\nmsgstr \"指定された領域のピクセルを反転させます。\"\n\n#: ../../pixmap.rst:34 516fe80e3c4a459a81a150dc6a462f8e\nmsgid \":meth:`Pixmap.pdfocr_save`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:34 ../../pixmap.rst:35 67e410a8f8c842c1944b038c5708de2d\n#: f38b40a1d99c4c509644c872d19b87e2\nmsgid \"save the pixmap as an OCRed 1-page PDF\"\nmsgstr \"OCR処理済みの1ページのPDFとしてピクセルマップを保存します。\"\n\n#: ../../pixmap.rst:35 be86eecb9ae84058896ab1db4a2fcab1\nmsgid \":meth:`Pixmap.pdfocr_tobytes`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:36 b0881e3fa8064b569e1476c50325b3d7\nmsgid \":meth:`Pixmap.pil_image`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:36 6075a73ecdcb46979d4b836f39403d5f\nmsgid \"create a Pillow Image\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:37 c71cca896c4e47509c4fa0e362fa044c\nmsgid \":meth:`Pixmap.pil_save`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:37 4be536342cb047aeb0a6b64adbba1e9a\n#, fuzzy\nmsgid \"save as a Pillow Image\"\nmsgstr \"Pillowを使用してイメージとして保存します。\"\n\n#: ../../pixmap.rst:38 52b8400d5cce434b87e23399f61d2117\nmsgid \":meth:`Pixmap.pil_tobytes`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:38 bafc4631127f4561936ab5d1e6403a2d\n#, fuzzy\nmsgid \"write to `bytes` as a Pillow Image\"\nmsgstr \"Pillowを使用してバイトオブジェクトに書き込みます。\"\n\n#: ../../pixmap.rst:39 4002db687ffc4feabe3a41f2274b7804\nmsgid \":meth:`Pixmap.pixel`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:39 efb78dfb56524049a7580e3a15723114\nmsgid \"return the value of a pixel\"\nmsgstr \"ピクセルの値を返します。\"\n\n#: ../../pixmap.rst:40 e0ffa2a456944476bb6984b064566f95\nmsgid \":meth:`Pixmap.save`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:40 7f4131a6b70d41cd802f09e3f4f6f11f\nmsgid \"save the pixmap in a variety of formats\"\nmsgstr \"さまざまな形式でピクセルマップを保存します。\"\n\n#: ../../pixmap.rst:41 23956dccd6e94052aef51929b1c393dc\nmsgid \":meth:`Pixmap.set_alpha`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:41 3979119c35f341c694e03dd5db7a0115\nmsgid \"set alpha values\"\nmsgstr \"アルファ値を設定します。\"\n\n#: ../../pixmap.rst:42 80aa084bf73c4f61abbf2f808d42bdcd\nmsgid \":meth:`Pixmap.set_dpi`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:42 881510d8c71545b59d91fb5dac173605\nmsgid \"set the image resolution\"\nmsgstr \"イメージの解像度を設定します。\"\n\n#: ../../pixmap.rst:43 af00886d005e4a1890d7b7789b93e7e7\nmsgid \":meth:`Pixmap.set_origin`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:43 7e6045d9838046cea1cd1fcb38a15dab\nmsgid \"set pixmap x,y values\"\nmsgstr \"ピクセルマップのx、y値を設定します。\"\n\n#: ../../pixmap.rst:44 cb25eecee8af4917ab427d3cf303152f\nmsgid \":meth:`Pixmap.set_pixel`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:44 23d1909be60a4b269aaec2547ae2aa05\nmsgid \"set color and alpha of a pixel\"\nmsgstr \"ピクセルの色とアルファを設定します。\"\n\n#: ../../pixmap.rst:45 72b4d710dc894939936c377380bbc22e\nmsgid \":meth:`Pixmap.set_rect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:45 0f7af78460a4450da9d9108517b4d4c4\nmsgid \"set color and alpha of all pixels in a rectangle\"\nmsgstr \"四角形内のすべてのピクセルの色とアルファを設定します。\"\n\n#: ../../pixmap.rst:46 b791b993ad61409eaef1d0b360847ffc\nmsgid \":meth:`Pixmap.shrink`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:46 38e21b2c7aa8493e8bb7266e1e835f69\nmsgid \"reduce size keeping proportions\"\nmsgstr \"比率を保持しながらサイズを縮小します。\"\n\n#: ../../pixmap.rst:47 be56d7fc15e24cf2826c82badd69df56\nmsgid \":meth:`Pixmap.tint_with`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:47 d5a1e740218c41ceb31d912cae43599f\nmsgid \"tint the pixmap\"\nmsgstr \"ピクセルマップに色調を付けます。\"\n\n#: ../../pixmap.rst:48 408bd07e5e004c53845a34ccb73684f6\nmsgid \":meth:`Pixmap.tobytes`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:48 dbfd2cd88a2e40689877d688108593b5\nmsgid \"return a memory area in a variety of formats\"\nmsgstr \"さまざまな形式のメモリ領域を返します。\"\n\n#: ../../pixmap.rst:49 73ad7e8e412146939a933bc554653bd9\nmsgid \":meth:`Pixmap.warp`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:49 27dcdd34ccd6434c8be2f3d0cab9f361\nmsgid \"return a pixmap made from a quad inside\"\nmsgstr \"内部の四角形から作成されたピクセルマップを返します。\"\n\n#: ../../pixmap.rst:50 85defbb4523445e9bfc92785c42fcb0b\nmsgid \":attr:`Pixmap.alpha`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:50 f9f7e74d1a854ce584726e3236d915a4\nmsgid \"transparency indicator\"\nmsgstr \"透明度指示子\"\n\n#: ../../pixmap.rst:51 fbf1760092864dcf8f5566ac85074c05\nmsgid \":attr:`Pixmap.colorspace`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:51 48b501a974724e6cadfe58ebbfebeb9a\nmsgid \"pixmap's :ref:`Colorspace`\"\nmsgstr \"ピクセルマップの :ref:`Colorspace`\"\n\n#: ../../pixmap.rst:52 b766c11c9d60491bb1cd9e4c8cfd9751\nmsgid \":attr:`Pixmap.digest`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:52 3d7b532618f3451896efe2d64d4ffdfe\nmsgid \"MD5 hashcode of the pixmap\"\nmsgstr \"ピクセルマップのMD5ハッシュコード\"\n\n#: ../../pixmap.rst:53 76675540ad27482bada64b6a598d25f9\nmsgid \":attr:`Pixmap.height`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:53 3c22531079e34fa79dddc4e586d958e6\nmsgid \"pixmap height\"\nmsgstr \"ピクセルマップの高さ\"\n\n#: ../../pixmap.rst:54 9182d024c67b490b9fe7855b4f5715d0\nmsgid \":attr:`Pixmap.interpolate`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:54 3688b5e0286840669d320a95bc5a17fb\nmsgid \"interpolation method indicator\"\nmsgstr \"補間メソッド指示子\"\n\n#: ../../pixmap.rst:55 b7b0a90b1ba846e89b22db0ed4553281\nmsgid \":attr:`Pixmap.is_monochrome`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:55 df352c76b67546089f124cbd0e5babb1\nmsgid \"check if only black and white occur\"\nmsgstr \"黒と白だけが存在するか確認します。\"\n\n#: ../../pixmap.rst:56 a17ad0a90a7d413c9fb8b1aa83257598\nmsgid \":attr:`Pixmap.is_unicolor`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:56 81dfed8a598641f6ae936549b0e7f7ba\nmsgid \"check if only one color occurs\"\nmsgstr \"単一の色しか存在しないか確認します。\"\n\n#: ../../pixmap.rst:57 abd7ff4e70754c9daef32d9525250608\nmsgid \":attr:`Pixmap.irect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:57 2791b580e848470a814a376d6e220255\nmsgid \":ref:`IRect` of the pixmap\"\nmsgstr \"ピクセルマップの :ref:`IRect` \"\n\n#: ../../pixmap.rst:58 2fec6f3a895d4409b0e482a40f200f22\nmsgid \":attr:`Pixmap.n`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:58 c7b79f65d4494cdb897cc22abe8eff21\nmsgid \"bytes per pixel\"\nmsgstr \"ピクセルごとのバイト数\"\n\n#: ../../pixmap.rst:59 743bc8e881d44773b5fcf7beffc6a3fa\nmsgid \":attr:`Pixmap.samples_mv`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:59 4179ce00d1e746b295e577083af074b0\nmsgid \"`memoryview` of pixel area\"\nmsgstr \"ピクセル領域の `memoryview` \"\n\n#: ../../pixmap.rst:60 c5ff63d0faaa4137832a944521ce8069\nmsgid \":attr:`Pixmap.samples_ptr`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:60 8116e2e6a5fe470082d7fbdca4673935\nmsgid \"Python pointer to pixel area\"\nmsgstr \"ピクセル領域へのPythonポインタ\"\n\n#: ../../pixmap.rst:61 2abc33dc84a348c6ad9b8da90c57e531\nmsgid \":attr:`Pixmap.samples`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:61 060cb94948d84088a5cf7c6d4319fea3\nmsgid \"`bytes` copy of pixel area\"\nmsgstr \"ピクセル領域の `bytes` コピー\"\n\n#: ../../pixmap.rst:62 d41ed2ab508249d0ae96e3145e92258b\nmsgid \":attr:`Pixmap.size`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:62 cfe014376f9745ea9c2ce0e7a11bb369\nmsgid \"pixmap's total length\"\nmsgstr \"ピクセルマップの合計長さ\"\n\n#: ../../pixmap.rst:63 34fea4631d014515b7406f2f5bb813bc\nmsgid \":attr:`Pixmap.stride`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:63 5a29f36af34340aea9cba617eed85cc6\nmsgid \"size of one image row\"\nmsgstr \"1つの画像行のサイズ\"\n\n#: ../../pixmap.rst:64 62ed9c389676438299a427713f0f7b08\nmsgid \":attr:`Pixmap.width`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:64 70e7618e0783483ea97302b042784152\nmsgid \"pixmap width\"\nmsgstr \"ピクセルマップの幅\"\n\n#: ../../pixmap.rst:65 e62961e6786e48c796a2e5a23a76654f\nmsgid \":attr:`Pixmap.x`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:65 4e8faa2fe6154453bf50951bfbcbfa0e\nmsgid \"X-coordinate of top-left corner\"\nmsgstr \"左上隅のX座標\"\n\n#: ../../pixmap.rst:66 d69ccf0ae1844b88aaff3eb7fbfa1973\nmsgid \":attr:`Pixmap.xres`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:66 a1ecbc77214845fea2e4c6cee89a8ce8\nmsgid \"resolution in X-direction\"\nmsgstr \"X方向の解像度\"\n\n#: ../../pixmap.rst:67 83ca1188acde43af9c9f6c742f8c9fcb\nmsgid \":attr:`Pixmap.y`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:67 b0432d623ef4473aa3515de8b215d9f5\nmsgid \"Y-coordinate of top-left corner\"\nmsgstr \"左上隅のY座標\"\n\n#: ../../pixmap.rst:68 b704d755356e4e53903e4306cb1850d6\nmsgid \":attr:`Pixmap.yres`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:68 857aeb5083a44b1795d1ede13f95021f\nmsgid \"resolution in Y-direction\"\nmsgstr \"Y方向の解像度\"\n\n#: ../../pixmap.rst:71 a006e37a45ad4ed88da3603714dc9820\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../pixmap.rst:77 046bff7f68fe47dc89b42ec79b63be49\nmsgid \"\"\n\"**New empty pixmap:** Create an empty pixmap of size and origin given by \"\n\"the rectangle. So, *irect.top_left* designates the top left corner of the\"\n\" pixmap, and its width and height are *irect.width* resp. *irect.height*.\"\n\" Note that the image area is **not initialized** and will contain crap \"\n\"data -- use eg. :meth:`clear_with` or :meth:`set_rect` to be sure.\"\nmsgstr \"\"\n\"**新しい空のピクマップ:** 指定された矩形のサイズと原点を持つ空のピクマップを作成します。したがって、*irect.top_left* \"\n\"はピクマップの左上隅を示し、その幅と高さは *irect.width* および *irect.height* です。イメージ領域は \"\n\"**初期化されず** 、データが格納されます。データを初期化するには、:meth:`clear_with` や :meth:`set_rect` \"\n\"などを使用してください。\"\n\n#: ../../pixmap.rst 02b0fea3d9c34817aad000ad9f071590\n#: 054aba92b788492e988045fb104e4481 0eb0df83e45a406cb560af5072cdff86\n#: 2d9ab2f5c1024f7085600fc7ec9dc603 42fca49eb0844237a0b14c72c95e7dbc\n#: 4c84fc0dcb054b659ed6e2dae1b27605 57542313cdbd47cc89f43d9329495cb5\n#: 610dfac6df044219bea31b4eb7ef6b47 63f20c0df7eb4be8be807f287c781d58\n#: 67a50e42c1294501bb59b8b035850481 687444f1e3dc45509b4ec2a7192c0a48\n#: 73fe0913c7364c31916311fc0cffc16e 7e25b63146fa45858f1ff6b966a16913\n#: 8b3e2416c26c445bb9979be602f6adf5 95824bfb86ff41de835e47b77393048f\n#: a5c5caaf10934649be3b74635eb16787 af618a04af8e40efa6512d296a27fb9b\n#: bdfbcea144bd4cfb93f787f52dfadf48 c7f77794bd054561aa08e0b18497e5bd\n#: d044792ccaea48328805a0a6efd678c9 d625b8ee73b34a459873edc513b40002\n#: d81abb686bb542518846ad32bd035b5e dd1276958278455fb3ad0d1ad3b08045\n#: dd4e9e5837dc4c1eb17ec63c8681b4d4 e60d8f4e03c24b918ad9bdf22e21adb0\n#: f1bff3e4b66c4afca6ae66a014ac0fc1 f2e0f5d755134588846f75c89c28b5af\n#: f8a2e37bd2ef4ca79bf827a1a3fe8e70\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:79 56321802a9014c348fa2d20d4294c9f2\nmsgid \"colorspace.\"\nmsgstr \"カラースペース。\"\n\n#: ../../pixmap.rst:82 3753a76b227f496eb369ca2d40057f0c\nmsgid \"The pixmap's position and dimension.\"\nmsgstr \"ピクマップの位置と寸法。\"\n\n#: ../../pixmap.rst:84 0f1256f4866c4a888d73cefe035cfb17\nmsgid \"\"\n\"Specifies whether transparency bytes should be included. Default is \"\n\"``False``.\"\nmsgstr \"透明度バイトを含めるかどうかを指定します。デフォルトは ``False`` です。\"\n\n#: ../../pixmap.rst:88 b9326c334f6345fdaf185501bfa27892\nmsgid \"\"\n\"**Copy and set colorspace:** Copy *source* pixmap converting colorspace. \"\n\"Any colorspace combination is possible, but source colorspace must not be\"\n\" ``None``.\"\nmsgstr \"\"\n\"**コピーとカラースペースの設定:** カラースペースを変換しながら *ソース* \"\n\"ピクマップをコピーします。どのカラースペースの組み合わせでも可能ですが、ソースカラースペースは ``None`` であってはいけません。\"\n\n#: ../../pixmap.rst:90 97014f607fba4a5cb553297120c90034\nmsgid \"\"\n\"desired **target** colorspace. This **may also be** ``None``. In this \"\n\"case, a \\\"masking\\\" pixmap is created: its :attr:`Pixmap.samples` will \"\n\"consist of the source's alpha bytes only.\"\nmsgstr \"\"\n\"**ターゲット** となるカラースペース。これは ``None`` **である場合もあります** 。この場合、 \\\"マスク\\\" \"\n\"ピクマップが作成されます。その :attr:`Pixmap.samples` は、ソースのアルファバイトだけで構成されます。\"\n\n#: ../../pixmap.rst:93 ../../pixmap.rst:112 36ef86e1d48d4c5a9dd2bf95b2fd7b14\n#: 52423174b9b746d2840bdc738fa82069\nmsgid \"the source pixmap.\"\nmsgstr \"ソースピクマップ。\"\n\n#: ../../pixmap.rst:98 1df405a79ae244d1a01b677a84951540\nmsgid \"New in v1.18.18\"\nmsgstr \"バージョン 1.18.18 で新規追加\"\n\n#: ../../pixmap.rst:100 dac52c1c940a488587523e971b8678bb\nmsgid \"\"\n\"**Copy and add image mask:** Copy *source* pixmap, add an alpha channel \"\n\"with transparency data from a mask pixmap.\"\nmsgstr \"**コピーとイメージマスクの追加:** ソースピクマップをコピーし、マスクピクマップから透明度データを持つアルファチャネルを追加します。\"\n\n#: ../../pixmap.rst:102 760c74ba53044cbcbdf31aee15f90bca\nmsgid \"pixmap without alpha channel.\"\nmsgstr \"アルファチャネルを持たないピクマップ。\"\n\n#: ../../pixmap.rst:105 46e5c3640fcf48d382edee1c823984e6\nmsgid \"a mask pixmap. Must be a graysale pixmap.\"\nmsgstr \"マスクピクマップ。グレースケールのピクマップである必要があります。\"\n\n#: ../../pixmap.rst:110 d9ec3e84c0ea4239b426990e4164290e\nmsgid \"\"\n\"**Copy and scale:** Copy *source* pixmap, scaling new width and height \"\n\"values -- the image will appear stretched or shrunk accordingly. Supports\"\n\" partial copying. The source colorspace may be ``None``.\"\nmsgstr \"\"\n\"**コピーとスケーリング:** \"\n\"ソースピクマップをコピーし、新しい幅と高さの値にスケーリングします。イメージはそれに応じてストレッチまたは縮小されます。部分的なコピーをサポートしています。ソースカラースペースは\"\n\" ``None`` であってもかまいません。\"\n\n#: ../../pixmap.rst:115 682ea20bf52b4efe901eaeac97e98829\nmsgid \"desired target width.\"\nmsgstr \"ターゲットの幅。\"\n\n#: ../../pixmap.rst:117 3bf8da6692aa4465bad88ed923353c01\nmsgid \"desired target height.\"\nmsgstr \"ターゲットの高さ。\"\n\n#: ../../pixmap.rst:119 7aa6286551464fc79c589f402e5f4064\nmsgid \"restrict the resulting pixmap to this region of the **scaled** pixmap.\"\nmsgstr \"**スケーリングされた** ピクマップのこの領域に制限します。\"\n\n#: ../../pixmap.rst:121 3be7525712a64bad8e5cc168ff57efeb\nmsgid \"\"\n\"If width or height do not *represent* integers (i.e. `value.is_integer() \"\n\"!= True`), then the resulting pixmap **will have an alpha channel**.\"\nmsgstr \"\"\n\"幅または高さが整数を *表していない* 場合（つまり、`value.is_integer() != True` の場合）、結果のピクマップには \"\n\"**アルファチャンネルが含まれます** 。\"\n\n#: ../../pixmap.rst:125 fcd3877dc9924a5098cb10a1fec25153\nmsgid \"\"\n\"**Copy and add or drop alpha:** Copy *source* and add or drop its alpha \"\n\"channel. Identical copy if *alpha* equals *source.alpha*. If an alpha \"\n\"channel is added, its values will be set to 255.\"\nmsgstr \"\"\n\"**コピーしてアルファの追加または削除：** *ソース* をコピーし、そのアルファチャンネルを追加または削除します。*alpha* が \"\n\"*source.alpha* と等しい場合、同一のコピーになります。アルファチャンネルが追加される場合、その値は255に設定されます。\"\n\n#: ../../pixmap.rst:127 ../../pixmap.rst:305 29341e581eda460c9963b056957f0057\n#: 6755e67f1ebd4c6397a96a8387727fc0\nmsgid \"source pixmap.\"\nmsgstr \"ソースのピクマップ。\"\n\n#: ../../pixmap.rst:130 c616e3541c6f481680da4d95d038b5f5\nmsgid \"\"\n\"whether the target will have an alpha channel, default and mandatory if \"\n\"source colorspace is ``None``.\"\nmsgstr \"対象にアルファチャンネルがあるかどうか、デフォルトで、ソースのcolorspaceが ``None`` の場合は必須です。\"\n\n#: ../../pixmap.rst:132 df4cef61a1c149a39965a6f332bf9f2c\nmsgid \"\"\n\"A typical use includes separation of color and transparency bytes in \"\n\"separate pixmaps. Some applications require this like e.g. \"\n\"*wx.Bitmap.FromBufferAndAlpha()* of *wxPython*:\"\nmsgstr \"\"\n\"典型的な使用例には、カラーと透明バイトを別々のピクマップに分離することが含まれます。一部のアプリケーションでは、*wxPython* の \"\n\"*wx.Bitmap.FromBufferAndAlpha()* など、これが必要です。\"\n\n#: ../../pixmap.rst:142 154d69621fb94872a7ad34eae19ef7aa\nmsgid \"\"\n\"**From a file:** Create a pixmap from *filename*. All properties are \"\n\"inferred from the input. The origin of the resulting pixmap is *(0, 0)*.\"\nmsgstr \"\"\n\"**ファイルから:** ファイル名から pixmap を作成します。すべてのプロパティは入力から推測されます。生成される pixmap の原点は \"\n\"*(0, 0)* です。\"\n\n#: ../../pixmap.rst:144 aedb335cf31242c6807afec841343b05\nmsgid \"Path of the image file.\"\nmsgstr \"画像ファイルのパス。\"\n\n#: ../../pixmap.rst:148 e21d860e62cb466b8dcd5c58ecd8816a\nmsgid \"\"\n\"**From memory:** Create a pixmap from a memory area. All properties are \"\n\"inferred from the input. The origin of the resulting pixmap is *(0, 0)*.\"\nmsgstr \"\"\n\"**メモリから:** メモリ領域から pixmap を作成します。すべてのプロパティは入力から推測されます。生成される pixmap の原点は \"\n\"*(0, 0)* です。\"\n\n#: ../../pixmap.rst:150 74221d3aec5f41afae36e2b37ac8dfc7\nmsgid \"\"\n\"Data containing a complete, valid image. Could have been created by e.g. \"\n\"*stream = bytearray(open('image.file', 'rb').read())*. Type *bytes* is \"\n\"supported in **Python 3 only**, because *bytes == str* in Python 2 and \"\n\"the method will interpret the stream as a filename.  *Changed in version \"\n\"1.14.13:* *io.BytesIO* is now also supported.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:150 e9ed395c0d8c4b56a458e072bbd347e0\nmsgid \"\"\n\"Data containing a complete, valid image. Could have been created by e.g. \"\n\"*stream = bytearray(open('image.file', 'rb').read())*. Type *bytes* is \"\n\"supported in **Python 3 only**, because *bytes == str* in Python 2 and \"\n\"the method will interpret the stream as a filename.\"\nmsgstr \"\"\n\"完全で有効な画像を含むデータ。例えば、*stream = bytearray(open('image.file', 'rb').read())* \"\n\"などで作成できます。Python 2 では *bytes* はサポートされていないため、**Python 3 のみ** \"\n\"対応しています。なぜなら、Python 2 では *bytes == str* \"\n\"となり、このメソッドはストリームをファイル名と解釈する可能性があるからです。\"\n\n#: ../../pixmap.rst:152 a162db2d5e5f46a092952a708f6e5469\nmsgid \"*Changed in version 1.14.13:* *io.BytesIO* is now also supported.\"\nmsgstr \"*バージョン 1.14.13 で変更:* *io.BytesIO* もサポートされるようになりました。\"\n\n#: ../../pixmap.rst:157 016950d3c686415a993d228b20deed87\nmsgid \"\"\n\"**From plain pixels:** Create a pixmap from *samples*. Each pixel must be\"\n\" represented by a number of bytes as controlled by the *colorspace* and \"\n\"*alpha* parameters. The origin of the resulting pixmap is *(0, 0)*. This \"\n\"method is useful when raw image data are provided by some other program \"\n\"-- see :ref:`FAQ`.\"\nmsgstr \"\"\n\"**生のピクセルから:** *サンプル* から pixmap を作成します。各ピクセルは、*カラースペース* と *alpha* \"\n\"パラメーターによって制御されるバイト数で表現される必要があります。生成される pixmap の原点は *(0, 0)* \"\n\"です。このメソッドは、他のプログラムによって生の画像データが提供される場合に有用です - :ref:`FAQ` を参照してください。\"\n\n#: ../../pixmap.rst:159 cda1965dbe524b2f958354d3bf86203d\nmsgid \"Colorspace of image.\"\nmsgstr \"画像のカラースペース。\"\n\n#: ../../pixmap.rst:162 e4ca43e6639b433195a95bc4b9cff17c\nmsgid \"image width\"\nmsgstr \"画像の幅\"\n\n#: ../../pixmap.rst:164 e6bd73524bf443928467e7d153097052\nmsgid \"image height\"\nmsgstr \"画像の高さ\"\n\n#: ../../pixmap.rst:166 bc04c5ee0a2f4c219321973a46ca1fec\nmsgid \"\"\n\"an area containing all pixels of the image. Must include alpha values if \"\n\"specified.  *Changed in version 1.14.13:* (1) *io.BytesIO* can now also \"\n\"be used. (2) Data are now **copied** to the pixmap, so may safely be \"\n\"deleted or become unavailable.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:166 882216b59426469ebf0fc58e1a590a22\nmsgid \"\"\n\"an area containing all pixels of the image. Must include alpha values if \"\n\"specified.\"\nmsgstr \"画像のすべてのピクセルを含む領域。指定されている場合はアルファ値を含める必要があります。\"\n\n#: ../../pixmap.rst:168 94da32783c284a7c9e5cd26b1aa7aead\nmsgid \"\"\n\"*Changed in version 1.14.13:* (1) *io.BytesIO* can now also be used. (2) \"\n\"Data are now **copied** to the pixmap, so may safely be deleted or become\"\n\" unavailable.\"\nmsgstr \"\"\n\"*バージョン 1.14.13 で変更:* (1) *io.BytesIO* も使用できるようになりました。 (2) データは pixmap に \"\n\"**コピーされる** ようになり、安全に削除または利用不可能になります。\"\n\n#: ../../pixmap.rst:170 92e53d092aa1464db50b36eb7899219d\nmsgid \"whether a transparency channel is included.\"\nmsgstr \"透明チャネルを含めるかどうか。\"\n\n#: ../../pixmap.rst:174 d35de668e91d424ebf94418d892dcbd6\nmsgid \"\"\n\"The following equation **must be true**: *(colorspace.n + alpha) * width \"\n\"* height == len(samples)*.\"\nmsgstr \"\"\n\"以下の式が **成り立つ必要があります** : *(colorspace.n + alpha) * width * height == \"\n\"len(samples)*。\"\n\n#: ../../pixmap.rst:175 1c597631a5304c869da76bb9d81e6ed9\nmsgid \"\"\n\"Starting with version 1.14.13, the samples data are **copied** to the \"\n\"pixmap.\"\nmsgstr \"バージョン 1.14.13 以降、サンプルデータは pixmap に **コピーされます** 。\"\n\n#: ../../pixmap.rst:180 5c8af01ebb9141c4b8de801dd3f3356e\nmsgid \"\"\n\"**From a PDF image:** Create a pixmap from an image **contained in PDF** \"\n\"*doc* identified by its :data:`xref`. All pimap properties are set by the\"\n\" image. Have a look at `extract-img1.py \"\n\"<https://github.com/pymupdf/PyMuPDF/tree/master/demo/extract-img1.py>`_ \"\n\"and `extract-img2.py <https://github.com/pymupdf/PyMuPDF/tree/master/demo\"\n\"/extract-img2.py>`_ to see how this can be used to recover all of a PDF's\"\n\" images.\"\nmsgstr \"\"\n\"**PDFイメージから：**  PDFドキュメント内の :data:`xref` \"\n\"で識別されるイメージからピクスマップを作成します。ピクスマップのすべてのプロパティはイメージによって設定されます。これがどのように使用されるかを確認するには\"\n\"、`extract-img1.py <https://github.com/pymupdf/PyMuPDF/tree/master/demo\"\n\"/extract-img1.py>`_ と `extract-img2.py \"\n\"<https://github.com/pymupdf/PyMuPDF/tree/master/demo/extract-img2.py>`_ \"\n\"をご覧ください。これにより、PDFのすべてのイメージを復元できます。\"\n\n#: ../../pixmap.rst:182 83027e8baba3428f9138b9272d50b7c5\nmsgid \"an opened |PDF| document.\"\nmsgstr \"開かれた |PDF| ドキュメント。\"\n\n#: ../../pixmap.rst:185 1d115e0cbe8d45c1a12b21ba961b218c\nmsgid \"\"\n\"the :data:`xref` of an image object. For example, you can make a list of \"\n\"images used on a particular page with :meth:`Document.get_page_images`, \"\n\"which also shows the :data:`xref` numbers of each image.\"\nmsgstr \"\"\n\"画像オブジェクトの :data:`xref`。たとえば、:meth:`Document.get_page_images` \"\n\"を使用して特定のページで使用されるすべてのイメージのリストを作成し、各イメージの :data:`xref` 番号も表示できます。\"\n\n#: ../../pixmap.rst:189 af2a4e8f44da46f9b6b2a58073bb2cfc\nmsgid \"Initialize the samples area.\"\nmsgstr \"サンプル領域を初期化します。\"\n\n#: ../../pixmap.rst:191 e9fa66fe4f434c59baeea5e2c721a40d\nmsgid \"\"\n\"if specified, values from 0 to 255 are valid. Each color byte of each \"\n\"pixel will be set to this value, while alpha will be set to 255 (non-\"\n\"transparent) if present. If omitted, then all bytes (including any alpha)\"\n\" are cleared to *0x00*.\"\nmsgstr \"\"\n\"指定された場合、0から255の値が有効です。各ピクセルの各カラーバイトはこの値に設定され、存在する場合はアルファが255（非透明）に設定されます。省略された場合、すべてのバイト（アルファを含む）が\"\n\" *0x00* にクリアされます。\"\n\n#: ../../pixmap.rst:193 bb47605a216946dba119a8bf60a6dcdd\nmsgid \"\"\n\"the area to be cleared. Omit to clear the whole pixmap. Can only be \"\n\"specified, if *value* is also specified.\"\nmsgstr \"クリアする領域。ピクスマップ全体をクリアするには省略します。*value* も指定されている場合のみ指定できます。\"\n\n#: ../../pixmap.rst:197 78bf5b67f38f46178532a1e37e7ddd72\nmsgid \"\"\n\"Colorize a pixmap by replacing black and / or white with colors given as \"\n\"**sRGB integer** values. Only colorspaces :data:`CS_GRAY` and \"\n\":data:`CS_RGB` are supported, others are ignored with a warning.\"\nmsgstr \"\"\n\"ピクスマップを色付けして、黒と/または白を **sRGB整数値** として指定された色で置き換えます。:data:`CS_GRAY` と \"\n\":data:`CS_RGB` のカラースペースのみサポートされており、他のカラースペースは警告付きで無視されます。\"\n\n#: ../../pixmap.rst:199 abae57d0723b4345a89b12f880d933fa\nmsgid \"\"\n\"If the colorspace is :data:`CS_GRAY`, the average *(red + green + \"\n\"blue)/3* will be taken. The pixmap will be changed in place.\"\nmsgstr \"カラースペースが :data:`CS_GRAY` の場合、平均（赤+緑+青）/3が取得されます。ピクスマップはその場で変更されます。\"\n\n#: ../../pixmap.rst:201 04577dadbfbc43a3abbe3d997f6561ab\nmsgid \"replace black with this value. Specifying 0x000000 makes no changes.\"\nmsgstr \"黒をこの値で置き換えます。0x000000を指定しても変更はありません。\"\n\n#: ../../pixmap.rst:202 43f498ae78e443a28b06bdcc72789414\nmsgid \"replace white with this value. Specifying 0xFFFFFF makes no changes.\"\nmsgstr \"白をこの値で置き換えます。0xFFFFFFを指定しても変更はありません。\"\n\n#: ../../pixmap.rst:204 391411e29bc24c0183271fc962fc85ae\nmsgid \"Examples:\"\nmsgstr \"例：\"\n\n#: ../../pixmap.rst:206 6e89c521384c4c5bbc9619d3efe8b909\nmsgid \"`tint_with(0x000000, 0xFFFFFF)` is a no-op.\"\nmsgstr \"`tint_with(0x000000, 0xFFFFFF)` は操作なしです。\"\n\n#: ../../pixmap.rst:207 64e6d46367ef4feca63cb7fb163d6b63\nmsgid \"\"\n\"`tint_with(0x00FF00, 0xFFFFFF)` changes black to green, leaves white \"\n\"intact.\"\nmsgstr \"`tint_with(0x00FF00, 0xFFFFFF)` は黒を緑に変更し、白はそのままです。\"\n\n#: ../../pixmap.rst:208 8ea3f30122264c92b50ec935ec42fc3c\nmsgid \"`tint_with(0xFF0000, 0x0000FF)` changes black to red and white to blue.\"\nmsgstr \"`tint_with(0xFF0000, 0x0000FF)` は黒を赤に変更し、白を青に変更します。\"\n\n#: ../../pixmap.rst:213 ca2f9c12e08649b5870ae3ad64eacd72\nmsgid \"\"\n\"Apply a gamma factor to a pixmap, i.e. lighten or darken it. Pixmaps with\"\n\" colorspace ``None`` are ignored with a warning.\"\nmsgstr \"ピクセルマップにガンマ係数を適用し、つまり明るくしたり暗くしたりします。色空間が ``None`` のピクセルマップは警告とともに無視されます。\"\n\n#: ../../pixmap.rst:215 f4c36ad3313f4088882a49b8ff1847ec\nmsgid \"\"\n\"*gamma = 1.0* does nothing, *gamma < 1.0* lightens, *gamma > 1.0* darkens\"\n\" the image.\"\nmsgstr \"*gamma = 1.0* は何も行いません。*gamma < 1.0* は明るくし、*gamma > 1.0* は暗くします。\"\n\n#: ../../pixmap.rst:219 8543630bd8134fbfbad3e241950d6cea\n#, fuzzy\nmsgid \"\"\n\"Shrink the pixmap by dividing both, its width and height by 2\\\\ \"\n\":sup:``n``.\"\nmsgstr \"Pixmapを2の :sup:`n` 乗で縮小します。\"\n\n#: ../../pixmap.rst:221 30c7f5ad783249949e9748a49eb7d9f9\nmsgid \"\"\n\"determines the new pixmap (samples) size. For example, a value of 2 \"\n\"divides width and height by 4 and thus results in a size of one 16\\\\ \"\n\":sup:`th` of the original. Values less than 1 are ignored with a warning.\"\nmsgstr \"新しいPixmap（サンプル）のサイズを決定します。例えば、値が2の場合、幅と高さを4分の1に分割し、元のサイズの16分の1のサイズになります。1未満の値は警告として無視されます。\"\n\n#: ../../pixmap.rst:223 f45f17093df4420cb6fbc619648afd22\nmsgid \"\"\n\"Use this methods to reduce a pixmap's size retaining its proportion. The \"\n\"pixmap is changed \\\"in place\\\". If you want to keep original and also \"\n\"have more granular choices, use the resp. copy constructor above.\"\nmsgstr \"これを使用して比を保持したままPixmapのサイズを縮小します。Pixmapは「その場で」変更されます。元のピクセルを保持し、より詳細な選択肢を持つ場合は、上記のコピーコンストラクタを使用してください。\"\n\n#: ../../pixmap.rst:227 1455e6653c744eeba403a49f543d6fab\nmsgid \"\"\n\"*New in version:: 1.14.5:* Return the value of the pixel at location (x, \"\n\"y) (column, line).\"\nmsgstr \"*バージョン1.14.5* で新規追加：位置（x、y）（列、行）のピクセルの値を返します。\"\n\n#: ../../pixmap.rst:229 ../../pixmap.rst:239 4665e9dd65654240abe6ee77bae37183\n#: ffb7d135ed9a41f1b4f0bfa146d6de82\nmsgid \"the column number of the pixel. Must be in `range(pix.width)`.\"\nmsgstr \"ピクセルの列番号。範囲 `range(pix.width)` 内である必要があります。\"\n\n#: ../../pixmap.rst:230 f1efa4c149644cc680d5348ad2c2e068\nmsgid \"the line number of the pixel, Must be in `range(pix.height)`.\"\nmsgstr \"ピクセルの行番号、範囲 `range(pix.height)` 内である必要があります。\"\n\n#: ../../pixmap.rst 369baee8d7234ef2ab7f82e75e9111ad\n#: a81a4cbd70ad4e0b8fb189a247cfcaaf b3a66cf736f24daea703147e167c320f\n#: cc865d958a3d4c81b2cbd3d3f814714b d2546977b027475993b2df887c1cb6e8\n#: e81aa1c04aa6419da09b400752672904 eb0378b2f08a49a0af740a769d1a6087\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../pixmap.rst 186871c10cae496984d33e4181c189b0\n#: 24ba23b408644b24bd9aa5c5c7695c13 375a4a43a898465fa252490979e2f154\n#: 44939b8c082c4f128aecb10f802bce36 8183d07de46a4c909fc8ff25a1c13b5e\n#: 82dd9565faa544cf8799ce6981d78e02 a7c02e0b9035405a9f75f61d1ef8a011\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:233 1c117c2f7320435ab28104a0c9e6b3f0\nmsgid \"\"\n\"a list of color values and, potentially the alpha value. Its length and \"\n\"content depend on the pixmap's colorspace and the presence of an alpha. \"\n\"For RGBA pixmaps the result would e.g. be *[r, g, b, a]*. All items are \"\n\"integers in `range(256)`.\"\nmsgstr \"\"\n\"色の値と、必要に応じてアルファ値のリスト。その長さと内容は、Pixmap \"\n\"の色空間とアルファの存在に依存します。RGBAピクセルマップの場合、結果は例えば *[r、g、b、a]* となります。すべてのアイテムは \"\n\"`range(256)` の整数です。\"\n\n#: ../../pixmap.rst:237 4e3d50e363f54e7da5ab00f4aa58fec5\nmsgid \"\"\n\"*New in version 1.14.7:* Manipulate the pixel at location (x, y) (column,\"\n\" line).\"\nmsgstr \"*バージョン1.14.7で新規追加：* 位置（x、y）（列、行）のピクセルを操作します。\"\n\n#: ../../pixmap.rst:240 0dcca10c1c4c4b58b61746cd5da73f43\nmsgid \"the line number of the pixel. Must be in `range(pix.height)`.\"\nmsgstr \"ピクセルの行番号、`range(pix.height)` 内である必要があります。\"\n\n#: ../../pixmap.rst:241 eee0a54112754d7db4a0e21facaf19c8\nmsgid \"\"\n\"the desired pixel value given as a sequence of integers in `range(256)`. \"\n\"The length of the sequence must equal :attr:`Pixmap.n`, which includes \"\n\"any alpha byte.\"\nmsgstr \"\"\n\"`range(256)` の整数で表されるシーケンスとして指定された所望のピクセル値。シーケンスの長さは :attr:`Pixmap.n` \"\n\"に等しくなければならず、これにはアルファバイトも含まれます。\"\n\n#: ../../pixmap.rst:245 223fcf7f54984d26a1a64657ed00a81d\nmsgid \"*New in version 1.14.8:* Set the pixels of a rectangle to a value.\"\nmsgstr \"*新しいバージョン1.14.8で導入されました：* 特定の値で長方形のピクセルを設定します。\"\n\n#: ../../pixmap.rst:247 95d0f97710ba444391fd993ca732bc02\nmsgid \"\"\n\"the rectangle to be filled with the value. The actual area is the \"\n\"intersection of this parameter and :attr:`Pixmap.irect`. For an empty \"\n\"intersection (or an invalid parameter), no change will happen.\"\nmsgstr \"\"\n\"値で埋める長方形。実際のエリアはこのパラメータと :attr:`Pixmap.irect`  \"\n\"の交差です。空の交差（または無効なパラメータ）の場合、変更は行われません。\"\n\n#: ../../pixmap.rst:248 a8fe7a3cf13a40e6a5abc4a65a481906\nmsgid \"\"\n\"the desired value, given as a sequence of integers in `range(256)`. The \"\n\"length of the sequence must equal :attr:`Pixmap.n`, which includes any \"\n\"alpha byte.\"\nmsgstr \"\"\n\"`range(256)` 内の整数のシーケンスとして指定された所望の値。シーケンスの長さは :attr:`Pixmap.n` \"\n\"と等しくなければならず、これにはアルファバイトも含まれます。\"\n\n#: ../../pixmap.rst:251 ef594268cf964435b0f7fae7229908c8\nmsgid \"\"\n\"``False`` if the rectangle was invalid or had an empty intersection with \"\n\":attr:`Pixmap.irect`, else ``True``.\"\nmsgstr \"irectが無効であるか、:attr:`Pixmap.irect` と交差しない場合は ``False``、それ以外の場合は ``True`` 。\"\n\n#: ../../pixmap.rst:255 bcf6532518a34f9c87fe6473f29b283c\nmsgid \"\"\n\"This method is equivalent to :meth:`Pixmap.set_pixel` executed for each \"\n\"pixel in the rectangle, but is obviously **very much faster** if many \"\n\"pixels are involved.\"\nmsgstr \"\"\n\"このメソッドは、多くのピクセルが関与する場合に **非常に高速** であるため、長方形内の各ピクセルに対して実行される \"\n\":meth:`Pixmap.set_pixel` と同等です。\"\n\n#: ../../pixmap.rst:256 bc5f1b513a0f4c4fa649296505adae7c\nmsgid \"\"\n\"This method can be used similar to :meth:`Pixmap.clear_with` to \"\n\"initialize a pixmap with a certain color like this: \"\n\"*pix.set_rect(pix.irect, (255, 255, 0))* (RGB example, colors the \"\n\"complete pixmap with yellow).\"\nmsgstr \"\"\n\"このメソッドは、:meth:`Pixmap.clear_with` \"\n\"のように、次のようにして特定の色でピクセルマップを初期化するために使用できます。 *pix.set_rect(pix.irect, (255, \"\n\"255, 0))* （RGBの例、ピクセルマップ全体を黄色で色付けします）。\"\n\n#: ../../pixmap.rst:260 a513c003abe849829c11fe1447ebad4c\nmsgid \"New in v1.17.7\"\nmsgstr \"v1.17.7で新規導入\"\n\n#: ../../pixmap.rst:262 0b7cc0a788dd40cb8acfbdb60fc95d01\nmsgid \"Set the x and y values of the pixmap's top-left point.\"\nmsgstr \"ピクセルマップの左上の点のxとyの値を設定します。\"\n\n#: ../../pixmap.rst:264 235e6e23b0b24739bc80e81e21526714\nmsgid \"x coordinate\"\nmsgstr \"x座標\"\n\n#: ../../pixmap.rst:265 6abac422a54b4e5bb66a4859637f5a69\nmsgid \"y coordinate\"\nmsgstr \"y座標\"\n\n#: ../../pixmap.rst:270 c5527c1032f044a2a640143d01653c61\nmsgid \"New in v1.16.17\"\nmsgstr \"v1.16.17で新規導入.\"\n\n#: ../../pixmap.rst:272 f49f9e8464474d7cbf7a85f1ba506a82\nmsgid \"\"\n\"Changed in v1.18.0: When saving as a PNG image, these values will be \"\n\"stored now.\"\nmsgstr \"v1.18.0で変更：PNGイメージとして保存する場合、これらの値が保存されるようになりました。\"\n\n#: ../../pixmap.rst:274 a468673bcf8b49a68b788fd8ae23b5d5\nmsgid \"Set the resolution (dpi) in x and y direction.\"\nmsgstr \"xおよびy方向の解像度（dpi）を設定します。\"\n\n#: ../../pixmap.rst:276 0ac91572ffc64e2bba64b0279d3fc7a3\nmsgid \"resolution in x direction.\"\nmsgstr \"x方向の解像度。\"\n\n#: ../../pixmap.rst:277 1eb356ec57454ca9815ab72ead63956f\nmsgid \"resolution in y direction.\"\nmsgstr \"y方向の解像度。\"\n\n#: ../../pixmap.rst:282 8623995d2c004b0ba2caf470042846f1\nmsgid \"Changed in v 1.18.13\"\nmsgstr \"変更内容：v1.18.13で変更\"\n\n#: ../../pixmap.rst:284 82d487067f8d4ced9ef11d081f5e4ce8\nmsgid \"Change the alpha values. The pixmap must have an alpha channel.\"\nmsgstr \"アルファ値を変更します。ピクマップにはアルファチャンネルが必要です。\"\n\n#: ../../pixmap.rst:286 c98fe169c19c487481ca55cd0633f3f8\nmsgid \"\"\n\"the new alpha values. If provided, its length must be at least *width * \"\n\"height*. If omitted (`None`), all alpha values are set to 255 (no \"\n\"transparency). *Changed in version 1.14.13:* *io.BytesIO* is now also \"\n\"accepted.\"\nmsgstr \"\"\n\"新しいアルファ値。指定された場合、その長さは少なくとも *幅×高* \"\n\"さでなければなりません。省略した場合（`None`）、すべてのアルファ値が255（透明でない）に設定されます。*バージョン1.14.13で変更：*\"\n\" *io.BytesIO* も受け入れられるようになりました。\"\n\n#: ../../pixmap.rst:287 e94c3d6b68c141e2b61b6f54ab717d33\nmsgid \"\"\n\"*New in v1.18.13:* whether to premultiply color components with the alpha\"\n\" value.\"\nmsgstr \"*v1.18.13で新登場：* カラーコンポーネントをアルファ値と乗算するかどうか。\"\n\n#: ../../pixmap.rst:288 fbe9e806927d460389c858b14d4f3644\nmsgid \"\"\n\"ignore the alpha value and set this color to fully transparent. A \"\n\"sequence of integers in `range(256)` with a length of :attr:`Pixmap.n`. \"\n\"Default is ``None``. For example, a typical choice for RGB would be \"\n\"`opaque=(255, 255, 255)` (white).\"\nmsgstr \"\"\n\"アルファ値を無視し、この色を完全に透明に設定します。長さが :attr:`Pixmap.n` で `range(256)` \"\n\"内の整数のシーケンスです。デフォルトは ``None`` です。たとえば、RGBの典型的な選択肢は `opaque=(255, 255, \"\n\"255)` （白）です。\"\n\n#: ../../pixmap.rst:293 e617ef83731c4689a35511a90c29ceeb\nmsgid \"\"\n\"Invert the color of all pixels in :ref:`IRect` *irect*. Will have no \"\n\"effect if colorspace is ``None``.\"\nmsgstr \"\"\n\":ref:`IRect` *irect* 内のすべてのピクセルの色を反転させます。colorspaceが ``None`` \"\n\"の場合は効果がありません。\"\n\n#: ../../pixmap.rst:295 b9d38a022bef44f89d241d1964237fbb\nmsgid \"The area to be inverted. Omit to invert everything.\"\nmsgstr \"反転する領域。すべて反転するには省略します。\"\n\n#: ../../pixmap.rst:299 e764fb3df0324f5187dbb68ba9a917ba\nmsgid \"\"\n\"Copy the *irect* part of the *source* pixmap into the corresponding area \"\n\"of this one. The two pixmaps may have different dimensions and can each \"\n\"have :data:`CS_GRAY` or :data:`CS_RGB` colorspaces, but they currently \"\n\"**must** have the same alpha property [#f2]_. The copy mechanism \"\n\"automatically adjusts discrepancies between source and target like so:\"\nmsgstr \"\"\n\"*ソース* ピクマップの *irect* \"\n\"部分を、このピクマップの対応する領域にコピーします。2つのピクマップは異なる寸法を持つことができ、それぞれが :data:`CS_GRAY` \"\n\"または :data:`CS_RGB` カラースペースを持つことができますが、現在は同じアルファプロパティ [#f2]_ \"\n\"を持っている必要があります。コピー機構は、次のようにソースとターゲットの間の不一致を自動的に調整します。\"\n\n#: ../../pixmap.rst:301 e270f22850b84663930783d1f33ca33c\nmsgid \"\"\n\"If copying from :data:`CS_GRAY` to :data:`CS_RGB`, the source gray-shade \"\n\"value will be put into each of the three rgb component bytes. If the \"\n\"other way round, *(r + g + b) / 3* will be taken as the gray-shade value \"\n\"of the target.\"\nmsgstr \"\"\n\":data:`CS_GRAY` から :data:`CS_RGB` \"\n\"にコピーする場合、ソースのグレーシェード値は、3つのRGBコンポーネントバイトの各々に配置されます。逆の場合、*（r + g + b）/ 3* \"\n\"がターゲットのグレーシェード値として取られます。\"\n\n#: ../../pixmap.rst:303 e29fc4caf130461db1843ba16fe4fc72\nmsgid \"\"\n\"Between *irect* and the target pixmap's rectangle, an \\\"intersection\\\" is\"\n\" calculated at first. This takes into account the rectangle coordinates \"\n\"and the current attribute values :attr:`Pixmap.x` and :attr:`Pixmap.y` \"\n\"(which you are free to modify for this purpose via \"\n\":meth:`Pixmap.set_origin`). Then the corresponding data of this \"\n\"intersection are copied. If the intersection is empty, nothing will \"\n\"happen.\"\nmsgstr \"\"\n\"*irect* とターゲットピクマップの長方形の間で、まず「交差」を計算します。これは、長方形の座標と現在の属性値 \"\n\":attr:`Pixmap.x` および  :attr:`Pixmap.y` （これを目的のために \"\n\":meth:`Pixmap.set_origin` \"\n\"を介して自由に変更できます）を考慮に入れます。その後、この交差のデータがコピーされます。交差が空の場合、何も起こりません。\"\n\n#: ../../pixmap.rst:308 fb1b535c8adc44baa4c729c25fec3e14\nmsgid \"The area to be copied.\"\nmsgstr \"コピーする領域。\"\n\n#: ../../pixmap.rst:310 82448c014aa543b68e66cec1b07f3d96\nmsgid \"\"\n\"Example: Suppose you have two pixmaps, `pix1` and `pix2` and you want to \"\n\"copy the lower right quarter of `pix2` to `pix1` such that it starts at \"\n\"the top-left point of `pix1`. Use the following snippet::\"\nmsgstr \"\"\n\"例： `pix1` と `pix2` という2つのピクマップがあるとし、`pix2` の右下の四半期を `pix1` にコピーし、それが \"\n\"`pix1` の左上の点から開始するようにしたい場合、次のスニペットを使用します::\"\n\n#: ../../pixmap.rst:329 7fbfff308f9d4627a4a6f2fc60e1651e\nmsgid \"\"\n\"Changed in v1.22.0: Added **direct support of JPEG** images. Image \"\n\"quality can be controlled via parameter \\\"jpg_quality\\\".\"\nmsgstr \"v1.22.0で変更：**JPEG画像の直接サポート** が追加されました。画像の品質は「jpg_quality」パラメータを使用して制御できます。\"\n\n#: ../../pixmap.rst:331 97bd54f9e597471292898030e2002c7a\nmsgid \"\"\n\"Save pixmap as an image file. Depending on the output chosen, only some \"\n\"or all colorspaces are supported and different file extensions can be \"\n\"chosen. Please see the table below.\"\nmsgstr \"Pixmapを画像ファイルとして保存します。選択した出力に応じて、一部またはすべてのカラースペースがサポートされ、異なるファイル拡張子を選択できます。詳細については以下の表をご覧ください。\"\n\n#: ../../pixmap.rst:333 9cbb39acd6fd43c7b4231f63399b34d8\nmsgid \"\"\n\"The file to save to. May be provided as a string, as a ``pathlib.Path`` \"\n\"or as a Python file object. In the latter two cases, the filename is \"\n\"taken from the resp. object. The filename's extension determines the \"\n\"image format, which can be overruled by the output parameter.\"\nmsgstr \"\"\n\"保存先のファイル。文字列、``pathlib.Path`` \"\n\"、またはPythonファイルオブジェクトとして提供できます。後の2つの場合、ファイル名は対応するオブジェクトから取得されます。ファイル名の拡張子は画像フォーマットを決定し、出力パラメータで上書きできます。\"\n\n#: ../../pixmap.rst:335 a8f9fb30eb6f4e129ccdb1eb4dfb2d50\nmsgid \"\"\n\"The desired image format. The default is the filename's extension. If \"\n\"both, this value and the file extension are unsupported, an exception is \"\n\"raised. For possible values see :ref:`PixmapOutput`.\"\nmsgstr \"\"\n\"望ましい画像フォーマット。デフォルトはファイル名の拡張子です。この値とファイル拡張子の両方がサポートされていない場合、例外が発生します。:ref:`PixmapOutput`\"\n\" を参照してください。\"\n\n#: ../../pixmap.rst:336 ../../pixmap.rst:346 57c5e89d61b643828893b09c1506e81c\n#: a4031bcffabf4809bb9b3450054f39ec\nmsgid \"\"\n\"The desired image quality, default 95. Only applies to JPEG images, else \"\n\"ignored. This parameter trades quality against file size. A value of 98 \"\n\"is close to lossless. Higher values should not lead to better quality.\"\nmsgstr \"望ましい画像品質、デフォルトは95です。JPEG画像にのみ適用され、それ以外の場合は無視されます。このパラメータは品質とファイルサイズをトレードオフにします。値が98の場合、ほぼロスレスです。より高い値は品質を向上させることはありません。\"\n\n#: ../../pixmap.rst 31830ae4676c49a29f6eda0ec74b2cc7\n#: 35f861d76f76416f84ca4a6cfbb9ba36 9e7d20d2ebff48a5a2f12a7bb9cb207f\n#: 9e8d92287683474c8894ca359bc0df3c eaa3f51d3c63445d921c804b8d264fba\nmsgid \"Raises\"\nmsgstr \"例外\"\n\n#: ../../pixmap.rst:338 ../../pixmap.rst:348 74c8c07d5a4d429180ebc61a6dc88b40\n#: 888fc652cefb483cbc631acba45b2a8c\nmsgid \"For unsupported image formats.\"\nmsgstr \"サポートされていない画像フォーマットの場合。\"\n\n#: ../../pixmap.rst:342 3e89ee831b4744b2a7778a6f2ab7d705\nmsgid \"\"\n\"New in version 1.14.5: Return the pixmap as a *bytes* memory object of \"\n\"the specified format -- similar to :meth:`save`.\"\nmsgstr \"\"\n\"新機能（バージョン1.14.5）：指定されたフォーマットのピクマップをバイトメモリオブジェクトとして返します。これは :meth:`save` \"\n\"と似ています。\"\n\n#: ../../pixmap.rst:343 4dff4d1183ff44f2a456ec123ddad67f\nmsgid \"\"\n\"Changed in v1.22.0: Added **direct JPEG support**. Image quality can be \"\n\"influenced via new parameter \\\"jpg_quality\\\".\"\nmsgstr \"\"\n\"v1.22.0で変更： **JPEG画像の直接サポート** \"\n\"が追加されました。画像の品質は「jpg_quality」パラメータを使用して制御できます。\"\n\n#: ../../pixmap.rst:345 17d9ad6bf1cd4d0caaf174d46a29b286\nmsgid \"\"\n\"The desired image format. The default is \\\"png\\\". For possible values see\"\n\" :ref:`PixmapOutput`.\"\nmsgstr \"望ましい画像フォーマット。デフォルトは \\\"png\\\" です。:ref:`PixmapOutput` を参照してください。\"\n\n#: ../../pixmap.rst:351 7a4a3392440c413b9549ddfd80aa09e8\nmsgid \"\"\n\"The requested image format. The default is \\\"png\\\". For other possible \"\n\"values see :ref:`PixmapOutput`.\"\nmsgstr \"リクエストされた画像フォーマットです。デフォルトは \\\"png\\\" です。:ref:`PixmapOutput` を参照してください。\"\n\n#: ../../pixmap.rst:355 ../../pixmap.rst:370 024249ef113f468bba659314559663a8\n#: 3ebc661e655c4894a0780bd40d34f1b9\nmsgid \"New in v1.19.0\"\nmsgstr \"v1.19.0 で新規追加\"\n\n#: ../../pixmap.rst:357 ../../pixmap.rst:372 98399e67142a4ab4bfa0146bb6a938e0\n#: fde150994fb44c0dac805e2d7807ae53\nmsgid \"Changed in v1.22.5: Support of new parameter for Tesseract's tessdata.\"\nmsgstr \"v1.22.5 で変更：Tesseract の tessdata に関する新しいパラメータのサポート。\"\n\n#: ../../pixmap.rst:359 7e216757569f4c4ebb1b9d88f2858c00\nmsgid \"\"\n\"Perform text recognition using Tesseract and save the image as a 1-page \"\n\"PDF with an OCR text layer.\"\nmsgstr \"Tesseract を使用してテキスト認識を実行し、OCR テキスト レイヤーを持つ 1 ページの PDF として画像を保存します。\"\n\n#: ../../pixmap.rst:361 9e480852cca4498d8cb34f674e078760\nmsgid \"\"\n\"identifies the file to save to. May be either a string or a pointer to a \"\n\"file opened with \\\"wb\\\" (includes `io.BytesIO()` objects).\"\nmsgstr \"\"\n\"保存先のファイルを識別します。文字列または \\\"wb\\\" で開かれたファイルへのポインタ (`io.BytesIO()` \"\n\"オブジェクトを含む）のいずれかである必要があります。\"\n\n#: ../../pixmap.rst:362 739251505f694c69af4730ee2d8f7848\nmsgid \"whether to compress the resulting PDF, default is `True`.\"\nmsgstr \"結果の PDF を圧縮するかどうか。デフォルトは `True` です。\"\n\n#: ../../pixmap.rst:363 8c1c54fe56a34bf19f07465936ed9f10\nmsgid \"\"\n\"the languages occurring in the image. This must be specified in Tesseract\"\n\" format. Default is \\\"eng\\\" for English. Use \\\"+\\\"-separated Tesseract \"\n\"language codes for multiple languages, like \\\"eng+spa\\\" for English and \"\n\"Spanish.\"\nmsgstr \"\"\n\"画像内で使用される言語。Tesseract の形式で指定する必要があります。デフォルトは \"\n\"\\\"eng\\\"（英語）です。複数の言語を使用する場合、\\\"eng+spa\\\" のように \\\"+\\\" で区切った Tesseract \"\n\"言語コードを使用します（英語とスペイン語の場合など）。\"\n\n#: ../../pixmap.rst:364 fcca47fa76a9459cbec299e7f148dec6\n#, fuzzy\nmsgid \"\"\n\"folder name of Tesseract's language support. If omitted, this information\"\n\" must be present as environment variable `TESSDATA_PREFIX`.\"\nmsgstr \"\"\n\":arg str tessdata: Tesseractの言語サポートフォルダーの名前です。省略した場合、この情報は環境変数 \"\n\"`TESSDATA_PREFIX` として存在している必要があります。\"\n\n#: ../../pixmap.rst:366 21a4cf67602b4076b49b985e8aa0c66b\nmsgid \"\"\n\"**Will fail** if Tesseract is not installed or if the environment \"\n\"variable \\\"TESSDATA_PREFIX\\\" is not set to the `tessdata` folder name and\"\n\" not provided as parameter.\"\nmsgstr \"\"\n\"Tesseract がインストールされていない場合や、環境変数 \\\"TESSDATA_PREFIX\\\" が `tessdata` \"\n\"フォルダ名に設定されておらず、またはパラメータとして提供されていない場合、この関数は **失敗します** 。\"\n\n#: ../../pixmap.rst:374 32b8acd13d9f48e1bfd79ab1023be929\nmsgid \"\"\n\"Perform text recognition using Tesseract and convert the image to a \"\n\"1-page PDF with an OCR text layer. Internally invokes \"\n\":meth:`Pixmap.pdfocr_save`.\"\nmsgstr \"\"\n\"Tesseractを使用してテキスト認識を実行し、画像をOCRテキストレイヤーを持つ1ページのPDFに変換します。内部的には \"\n\":meth:`Pixmap.pdfocr_save` を呼び出します\"\n\n#: ../../pixmap.rst:376 9e005bf6ab3440c085ee1193ba601f87\nmsgid \"\"\n\"A 1-page PDF file in memory. Could be opened like \"\n\"`doc=pymupdf.open(\\\"pdf\\\", pix.pdfocr_tobytes())`, and text extractions \"\n\"could be performed on its `page=doc[0]`.  .. note::     Another possible \"\n\"use is insertion into some pdf. The following snippet reads the images of\"\n\" a folder and stores them as pages in a new PDF that contain an OCR text \"\n\"layer::        doc = pymupdf.open()       for imgfile in \"\n\"os.listdir(folder):          pix = pymupdf.Pixmap(imgfile)          \"\n\"imgpdf = pymupdf.open(\\\"pdf\\\", pix.pdfocr_tobytes())          \"\n\"doc.insert_pdf(imgpdf)          pix = None          imgpdf.close()       \"\n\"doc.save(\\\"ocr-images.pdf\\\")\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:376 b412ebf7d201478890ec75b641a17871\nmsgid \"\"\n\"A 1-page PDF file in memory. Could be opened like \"\n\"`doc=pymupdf.open(\\\"pdf\\\", pix.pdfocr_tobytes())`, and text extractions \"\n\"could be performed on its `page=doc[0]`.\"\nmsgstr \"\"\n\"メモリ内の1ページのPDFファイル。次のようにして開くことができます： `doc=pymupdf.open(\\\"pdf\\\", \"\n\"pix.pdfocr_tobytes())` 、そしてそのページ=doc[0]でテキストの抽出が行えます。\"\n\n#: ../../pixmap.rst:380 2cd418d767ef4149b35f4d0415d14af1\nmsgid \"\"\n\"Another possible use is insertion into some pdf. The following snippet \"\n\"reads the images of a folder and stores them as pages in a new PDF that \"\n\"contain an OCR text layer::\"\nmsgstr \"\"\n\"別の可能性として、PDF に挿入することが考えられます。次のスニペットは、フォルダ内の画像を読み取り、OCR テキスト レイヤーを含む新しい \"\n\"PDF ページとして保存します::\"\n\n#: ../../pixmap.rst:394 efc06e14189c4871827c5261c0623dfa\nmsgid \"Create a Pillow Image from the pixmap. PIL / Pillow must be installed.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:396 ../../pixmap.rst:416 ../../pixmap.rst:424\n#: 3df2560f6e804a789cc70c26deec880b 8087c1edcca942f186efe9ad6be77c16\n#: 85c874d70f274112a51bc6ce56e6e197\nmsgid \"if Pillow is not installed.\"\nmsgstr \"Pillow がインストールされていない場合\"\n\n#: ../../pixmap.rst:397 69708896f8e44f9eb5a130326ae36b80\nmsgid \"a ``PIL.Image`` object\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:401 3f77a2ee05134b31a570bc40ff704b87\nmsgid \"\"\n\"Write the pixmap as an image file using Pillow. Use this method for \"\n\"output unsupported by MuPDF. Examples are\"\nmsgstr \"\"\n\"Pillow を使用して pixmap を画像ファイルとして書き込みます。これは MuPDF \"\n\"でサポートされていない出力に使用します。例として、以下が挙げられます。\"\n\n#: ../../pixmap.rst:403 8f8925fd0a1e4868840945ccf3b35017\nmsgid \"Formats JPX, J2K, WebP, etc.\"\nmsgstr \"JPX、J2K、WebP などの形式\"\n\n#: ../../pixmap.rst:404 bd17d3e24fb740469efea4743e5ffb78\nmsgid \"Storing EXIF information.\"\nmsgstr \"EXIF 情報の保存\"\n\n#: ../../pixmap.rst:405 d7d0bc56bfcb4f179b7f00d2ad59c255\nmsgid \"\"\n\"If you do not provide dpi information, the values *xres*, *yres* stored \"\n\"with the pixmap are automatically used.\"\nmsgstr \"dpi 情報を提供しない場合、pixmap に格納されている *xres*、*yres* の値が自動的に使用されます。\"\n\n#: ../../pixmap.rst:407 20bf1e69dd5147b9a108ab328fe2657e\n#, fuzzy\nmsgid \"\"\n\"A simple example: `pix.pil_save(\\\"some.webp\\\", optimize=True, dpi=(150, \"\n\"150))`.\"\nmsgstr \"\"\n\"簡単な例: `pix.pil_save(\\\"some.webp\\\", optimize=True, dpi=(150, 150))` \"\n\"。他のパラメータの詳細については、Pillow のドキュメンテーションを参照してください。\"\n\n#: ../../pixmap.rst:409 71799e7c62324bbea016ae30eafbc021\nmsgid \"\"\n\"If the pixmap's colorspace is RGB with transparency, the alpha values may\"\n\" or may not already be multiplied into the color components \"\n\"ref/green/blue (called \\\"premultiplied\\\"). To enforce undoing \"\n\"premultiplication, set this parameter to `True`. To learn about some \"\n\"background, e.g. look for `\\\"Premultiplied alpha\\\" on this page \"\n\"<https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:412 c5f67c82cc1b4a078d120281dc779a59\nmsgid \"For details on other parameters see the Pillow documentation.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:414 d3f2fde19b034f09971604debcf8e6dc\nmsgid \"\"\n\"Since v1.22.0, PyMuPDF supports JPEG output directly. We recommended to \"\n\"no longer use this method for JPEG output -- for performance reasons and \"\n\"for avoiding unnecessary external dependencies.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:420 835e9bbf2bc047f2b9657ca7741ec37e\nmsgid \"New in v1.17.3\"\nmsgstr \"v1.17.3 で新しく追加されました\"\n\n#: ../../pixmap.rst:422 d0177a551753414586749bf415cf6080\n#, fuzzy\nmsgid \"\"\n\"Return an image as a bytes object in the specified format using Pillow. \"\n\"For example `stream = pix.pil_tobytes(format=\\\"WEBP\\\", optimize=True, \"\n\"dpi=(150, 150))`. Also see above. For details on other parameters see the\"\n\" Pillow documentation.\"\nmsgstr \"\"\n\"Pillow を使用して指定された形式の画像として bytes オブジェクトとして画像を返します。例: `stream = \"\n\"pix.pil_tobytes(format=\\\"WEBP\\\", optimize=True)` 。詳細なパラメータについては、Pillow \"\n\"のドキュメンテーションを参照してください。\"\n\n#: ../../pixmap.rst:431 ../../pixmap.rst:466 68173364cda84dab84fa461435fdec56\n#: b156a10f58714dae92ca5c3163c24112\nmsgid \"New in v1.19.3\"\nmsgstr \"v1.19.3 で新しく追加されました\"\n\n#: ../../pixmap.rst:433 129930765e83498b8cb4362c41d7fb9a\nmsgid \"\"\n\"Return a new pixmap by \\\"warping\\\" the quad such that the quad corners \"\n\"become the new pixmap's corners. The target pixmap's `irect` will be `(0,\"\n\" 0, width, height)`.\"\nmsgstr \"\"\n\"四角形を \\\"ワープ\\\" して、四角形の角が新しい pixmap の角になるようにします。対象 pixmap の `irect` は `(0, \"\n\"0, width, height)` になります。\"\n\n#: ../../pixmap.rst:435 6c6e2bf54f6c4c1cbd3c172dbbfb7712\nmsgid \"\"\n\"a convex quad with coordinates inside :attr:`Pixmap.irect` (including the\"\n\" border points).\"\nmsgstr \":attr:`Pixmap.irect` の内部にある座標を持つ凸四角形（境界点も含む）\"\n\n#: ../../pixmap.rst:436 e9644c03761249019390c475ce09eeb9\nmsgid \"desired resulting width.\"\nmsgstr \"望ましい幅\"\n\n#: ../../pixmap.rst:437 5af3c5ce964244d9ac8c1210ae145777\nmsgid \"desired resulting height.\"\nmsgstr \"望ましい高さ\"\n\n#: ../../pixmap.rst:438 23af53d676c943ab8270f1f4eb3e15f8\nmsgid \"\"\n\"A new pixmap where the quad corners are mapped to the pixmap corners in a\"\n\" clockwise fashion: `quad.ul -> irect.tl`, `quad.ur -> irect.tr`, etc.\"\nmsgstr \"\"\n\"新しいピクスマップで、四角形の角が時計回りにピクスマップの角にマップされます: `quad.ul -> irect.tl`、`quad.ur ->\"\n\" irect.tr` など。\"\n\n#: ../../pixmap.rst:439 c3fb88fba3f7447889bc2174e90ed4ed\nmsgid \"\"\n\":ref:`Pixmap`  .. image:: images/img-warp.*      :scale: 40      :align: \"\n\"center\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:439 8eb4c765b10a4af0b07fe6d1cd7386d2\nmsgid \":ref:`Pixmap`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:448 ../../pixmap.rst:505 ../../pixmap.rst:514\n#: 00c62e32e38c4d82895121b426757269 0149558efd01426095beb5bf88035b73\n#: 5c3eedb1091c4eb1af8d1010e7f2b3f0\nmsgid \"New in v1.19.2\"\nmsgstr \"v1.19.2で導入\"\n\n#: ../../pixmap.rst:449 b8fe5dd5d0294610a99db8d7ebd6deec\nmsgid \"Changed in v1.19.3\"\nmsgstr \"v1.19.3で変更\"\n\n#: ../../pixmap.rst:451 c2da2a6121594d6c8b3f4e6e7d643cee\nmsgid \"Determine the pixmap's unique colors and their count.\"\nmsgstr \"Pixmapのユニークな色とそのカウントを特定します。\"\n\n#: ../../pixmap.rst:453 992445f66d104d8c89ac2f8297c8e9c4\nmsgid \"\"\n\"*(changed in v1.19.3)* If `True` return a dictionary of color pixels and \"\n\"their usage count, else just the number of unique colors.\"\nmsgstr \"*（v1.19.3で変更）* `True` の場合、色ピクセルとその使用回数の辞書を返し、それ以外の場合はユニークな色の数だけを返します。\"\n\n#: ../../pixmap.rst:454 db2ea4eae7a1492dad41fae7951b0160\nmsgid \"\"\n\"a rectangle inside :attr:`Pixmap.irect`. If provided, only those pixels \"\n\"are considered. This allows inspecting sub-rectangles of a given pixmap \"\n\"directly -- instead of building sub-pixmaps.\"\nmsgstr \"\"\n\":attr:`Pixmap.irect` \"\n\"内の四角形。指定した場合、そのピクセルのみが考慮されます。これにより、指定されたPixmapのサブ四角形を直接調査できます。\"\n\n#: ../../pixmap.rst:456 61a615b057024b7a9b6ac7fe5ff849ab\nmsgid \"\"\n\"either the number of colors, or a dictionary with the items `pixel: \"\n\"count`. The pixel key is a `bytes` object of length :attr:`Pixmap.n`.  ..\"\n\" note:: To recover the **tuple** of a pixel, use \"\n\"`tuple(colors.keys()[i])` for the i-th item.     * The response time \"\n\"depends on the pixmap's samples size and may be more than a second for \"\n\"very large pixmaps.    * Where applicable, pixels with different alpha \"\n\"values will be treated as different colors.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:456 9ad0b09ff1334369af15be4f052a2f6f\nmsgid \"\"\n\"either the number of colors, or a dictionary with the items `pixel: \"\n\"count`. The pixel key is a `bytes` object of length :attr:`Pixmap.n`.\"\nmsgstr \"\"\n\"色の数、または `pixel: count` の項目を持つ辞書。pixelキーは :attr:`Pixmap.n` の長さの `bytes` \"\n\"オブジェクトです。\"\n\n#: ../../pixmap.rst:458 d7bdc5a53abc43d6a1041953b5c0c526\nmsgid \"\"\n\"To recover the **tuple** of a pixel, use `tuple(colors.keys()[i])` for \"\n\"the i-th item.\"\nmsgstr \"ピクセルのタプルを復元するには、i番目の項目に対して `tuple(colors.keys()[i])` を使用します。\"\n\n#: ../../pixmap.rst:460 260f96dbe8c04ab1a25159255b8b79a7\nmsgid \"\"\n\"The response time depends on the pixmap's samples size and may be more \"\n\"than a second for very large pixmaps.\"\nmsgstr \"応答時間はPixmapのsamplesサイズに依存し、非常に大きなPixmapの場合は1秒以上かかることがあります。\"\n\n#: ../../pixmap.rst:461 1b987ef794b6454eb0d9366a05344070\nmsgid \"\"\n\"Where applicable, pixels with different alpha values will be treated as \"\n\"different colors.\"\nmsgstr \"該当する場合、異なるアルファ値を持つピクセルは異なる色として扱われます。\"\n\n#: ../../pixmap.rst:468 2b6490adea534fa6a8de4eaf1edb354a\nmsgid \"Return the most frequently used color and its relative frequency.\"\nmsgstr \"最も頻繁に使用される色とその相対頻度を返します。\"\n\n#: ../../pixmap.rst:470 485c7c5b4da94258b242db7b59b19b53\nmsgid \"\"\n\"A rectangle inside :attr:`Pixmap.irect`. If provided, only those pixels \"\n\"are considered. This allows inspecting sub-rectangles of a given pixmap \"\n\"directly -- instead of building sub-pixmaps.\"\nmsgstr \"\"\n\":attr:`Pixmap.irect` \"\n\"内の四角形。指定した場合、そのピクセルのみが考慮されます。これにより、指定されたPixmapのサブ四角形を直接調査できます。\"\n\n#: ../../pixmap.rst:472 9110208e27134f02a9b9bcdc7700add8\n#, python-format\nmsgid \"\"\n\"A tuple `(ratio, pixel)` where `0 < ratio <= 1` and *pixel* is the pixel \"\n\"value of the color. Use this to decide if the image is \\\"almost\\\" \"\n\"unicolor: a response `(0.95, b\\\"\\\\x00\\\\x00\\\\x00\\\")` means that 95% of all\"\n\" pixels are black. See an example here :ref:`RecipesImages_P`.\"\nmsgstr \"\"\n\"比率 `0 < ratio <= 1` および色のピクセル値を持つタプル。これを使用して画像が「ほぼ」単一の色であるかどうかを判断します。応答 \"\n\"`(0.95, b\\\"\\\\x00\\\\x00\\\\x00\\\")` \"\n\"は、すべてのピクセルの95%が黒であることを示します。こちらの例を参照してください：「Pixmapsの使用方法：テキストの可視性の確認」\"\n\n#: ../../pixmap.rst:477 5e93c19118c44e4598fc55ffb9cd04f6\nmsgid \"Indicates whether the pixmap contains transparency information.\"\nmsgstr \"Pixmapに透明情報が含まれているかどうかを示します。\"\n\n#: ../../pixmap.rst 09340208613f48af95d9e1d2a3ef91fa\n#: 0cc2b878ea234bfe8d91795141e3924d 0ff51066858f4faaad58612b0fbd5896\n#: 163c7d4bd8d3405ca26c2650fa5d8a10 3eb04a688a904a5eaadf5d79aed68b1a\n#: 4869cfa0cd314211b192a2294838c7dc 5124ac9063654c24a37926de5ab662b6\n#: 557f147c6be94fe083e8082986fa08b6 5ee3e6766dd44d2582e805125e914472\n#: 5f52d2e5c48c47d7aec0c2b7a743fd46 6124bd56d7524796b1aa3c3e18458232\n#: 7c890834a7cf4a088780dfb0e21745a8 84cbd010ada9441a9182c12bbe62059b\n#: 89488e9f1e4c4e3d8c6ca9ce290016a4 8be2b06b344443289085426c1e14fa50\n#: 922e0d0d08124b5081bcbb57569a2aa8 a1b9de76b34b47f9b95c7bb1563b9e5a\n#: d0c0191f32ed43c6a6857c305705698b ead0a6e9dc94433ba020dae746028076\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:479 ../../pixmap.rst:509 ../../pixmap.rst:518\n#: ../../pixmap.rst:633 3d5651d764be40cca15a078b7f2531b8\n#: 694a5ede4c4c43319c089b1737fd0b9c a65782123b144e4186d43ddd5c138a97\n#: cd79fe63f067476c8342570d590c3121\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:483 98d329d87318478090434465b043c79d\nmsgid \"\"\n\"The MD5 hashcode (16 bytes) of the pixmap. This is a technical value used\"\n\" for unique identifications.\"\nmsgstr \"PixmapのMD5ハッシュコード（16バイト）。これは一意の識別に使用される技術的な値です。\"\n\n#: ../../pixmap.rst:485 ../../pixmap.rst:537 d353d95ffd0249c9985587a89eec06f3\n#: fe9d2fb1853646c9bb567d4a448e58de\nmsgid \"bytes\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:489 94c016ffd0e94ef8a92a913eac909cf0\nmsgid \"\"\n\"The colorspace of the pixmap. This value may be ``None`` if the image is \"\n\"to be treated as a so-called *image mask* or *stencil mask* (currently \"\n\"happens for extracted PDF document images only).\"\nmsgstr \"\"\n\"Pixmapのカラースペース。この値は、イメージが *イメージマスク* または *ステンシルマスク* として扱われる場合、``None`` \"\n\"になることがあります（現在、抽出されたPDFドキュメントイメージのみが該当）。\"\n\n#: ../../pixmap.rst:491 b6cfc944281042b38f313e221d8208ee\nmsgid \":ref:`Colorspace`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:495 6a4abc1ca4ea41e5b98e5867969d0aea\nmsgid \"\"\n\"Contains the length of one row of image data in :attr:`Pixmap.samples`. \"\n\"This is primarily used for calculation purposes. The following \"\n\"expressions are true:\"\nmsgstr \":attr:`Pixmap.samples` 内の画像データの1行の長さを含みます。これは主に計算目的で使用されます。次の式が真です：\"\n\n#: ../../pixmap.rst:497 9ef5987d2b004c03a37ac85ebe94eb90\nmsgid \"`len(samples) == height * stride`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:498 ad30730142bb41048a7ad4d99adb37ff\nmsgid \"`width * n == stride`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:500 ../../pixmap.rst:575 ../../pixmap.rst:581\n#: ../../pixmap.rst:589 ../../pixmap.rst:597 ../../pixmap.rst:603\n#: ../../pixmap.rst:609 ../../pixmap.rst:615 ../../pixmap.rst:621\n#: ../../pixmap.rst:627 565eef89a4f1443196235c362117a790\n#: 5790752de4bc4483b7998ab835faa57f 6b853b1effba4f9fa88e23a4ae3e5bf7\n#: a40cc5c113bb4004862e82488bb6ad45 accc4d8148f54c7db1495d30f6c968f0\n#: bca3975d0f204589a21f970e856552f3 d03716e1479c4f6b823e4712bf40c8e9\n#: d2bde8f030b0409d8de6030b27ad0c95 d833bb6cf43f4a109aa43ffba391db0f\n#: d8b756b8057c42329c2c1040697bad3a\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:507 8695567f63d74993b36963cb05639cf6\nmsgid \"Is `True` for a gray pixmap which only has the colors black and white.\"\nmsgstr \"灰色のピクマップで、黒と白の色しか持たない場合は `True` です。\"\n\n#: ../../pixmap.rst:516 b44722fd47e341cb9f851ef65e077148\nmsgid \"\"\n\"Is `True` if all pixels are identical (any colorspace). Where applicable,\"\n\" pixels with different alpha values will be treated as different colors.\"\nmsgstr \"\"\n\"すべてのピクセルが同じ場合、`True` \"\n\"です（どのカラースペースでも適用）。該当する場合、異なるアルファ値を持つピクセルは異なる色として扱われます。\"\n\n#: ../../pixmap.rst:523 6f074461eb274b3388c6956012c6f942\nmsgid \"Contains the :ref:`IRect` of the pixmap.\"\nmsgstr \"ピクマップの :ref:`IRect` を含みます。\"\n\n#: ../../pixmap.rst:525 8f50d53afc654b528e20564902041ddb\nmsgid \":ref:`IRect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:529 3abafa8c77804d0482f902d9e46ffb92\nmsgid \"\"\n\"The color and (if :attr:`Pixmap.alpha` is true) transparency values for \"\n\"all pixels. It is an area of `width * height * n` bytes. Each n bytes \"\n\"define one pixel. Each successive n bytes yield another pixel in scanline\"\n\" order. Subsequent scanlines follow each other with no padding. E.g. for \"\n\"an RGBA colorspace this means, *samples* is a sequence of bytes like \"\n\"*..., R, G, B, A, ...*, and the four byte values R, G, B, A define one \"\n\"pixel.\"\nmsgstr \"\"\n\"すべてのピクセルの色と（ :attr:`Pixmap.alpha` がtrueの場合）透明度の値です。これは `width * height * \"\n\"n` \"\n\"バイトの領域です。各nバイトは1つのピクセルを定義します。各続くnバイトは、スキャンラインの順序で別のピクセルを生成します。連続するスキャンラインはパディングなしで続きます。たとえばRGBAカラースペースの場合、*samples*\"\n\" は *…、R、G、B、A、…* のようなバイトのシーケンスで、4つのバイト値R、G、B、Aが1つのピクセルを定義します。\"\n\n#: ../../pixmap.rst:531 4d2c9332a9384bb2ac55549aea165f04\nmsgid \"\"\n\"This area can be passed to other graphics libraries like PIL (Python \"\n\"Imaging Library) to do additional processing like saving the pixmap in \"\n\"other image formats.\"\nmsgstr \"\"\n\"この領域は、PIL（Python Imaging \"\n\"Library）などの他のグラフィックライブラリに渡すことができ、ピクマップを他の画像形式で保存するなどの追加の処理を行うのに使用できます。\"\n\n#: ../../pixmap.rst:534 44ba67d25a5246c9b5c0fd86fc515d65\nmsgid \"\"\n\"The underlying data is typically a **large** memory area, from which a \"\n\"`bytes` copy is made for this attribute ... each time you access it: for \"\n\"example an RGB-rendered letter page has a samples size of almost 1.4 MB. \"\n\"So consider assigning a new variable to it or use the `memoryview` \"\n\"version :attr:`Pixmap.samples_mv` (new in v1.18.17).\"\nmsgstr \"\"\n\"基本データは通常、この属性にアクセスするたびに `bytes` \"\n\"のコピーが作成される大きなメモリ領域です。たとえば、RGBAでレンダリングされた文字ページのsamplesサイズはほぼ1.4 \"\n\"MBです。したがって、新しい変数に代入するか、`memoryview` バージョン :attr:`Pixmap.samples_mv` \"\n\"（v1.18.17で新機能）を使用するか、などの検討が必要です。\"\n\n#: ../../pixmap.rst:535 028c2991fa3746d8ba4fcb1363e0ac36\nmsgid \"\"\n\"Any changes to the underlying data are available only after accessing \"\n\"this attribute again. This is different from using the memoryview \"\n\"version.\"\nmsgstr \"基本データへの変更は、この属性に再度アクセスするまで利用できません。これは `memoryview` バージョンを使用する場合とは異なります。\"\n\n#: ../../pixmap.rst:541 ../../pixmap.rst:563 6231b732cd664d9ea3f80fe04f0151c9\n#: a54baa772ece47f4b743977662b324a4\nmsgid \"New in v1.18.17\"\nmsgstr \"新機能 v1.18.17\"\n\n#: ../../pixmap.rst:543 090480ef9ce349efab292a2a0fe883b7\nmsgid \"\"\n\"Like :attr:`Pixmap.samples`, but in Python `memoryview` format. It is \"\n\"built pointing to the memory in the pixmap -- not from a copy of it. So \"\n\"its creation speed is independent from the pixmap size, and any changes \"\n\"to pixels will be available immediately.\"\nmsgstr \"\"\n\":attr:`Pixmap.samples` と同様ですが、Pythonの `memoryview` \"\n\"形式です。これはピクマップ内のメモリを指すように構築されており、コピーではありません。そのため、作成速度はピクマップのサイズに依存せず、ピクセルへの変更はすぐに利用可能です。\"\n\n#: ../../pixmap.rst:545 93fdd4817c6d451593bce44eed03a5c1\nmsgid \"\"\n\"Copies like `bytearray(pix.samples_mv)`, or `bytes(pixmap.samples_mv)` \"\n\"are equivalent to and can be used in place of `pix.samples`.\"\nmsgstr \"\"\n\"`bytearray(pix.samples_mv)` や `bytes(pixmap.samples_mv)` \"\n\"などのコピーは、`pix.samples` の代わりに使用でき、同等です。\"\n\n#: ../../pixmap.rst:547 a15d8e7edd204441a7b9a76052a64fac\nmsgid \"We also have `len(pix.samples) == len(pix.samples_mv)`.\"\nmsgstr \"また、`len(pix.samples) == len(pix.samples_mv)` です。\"\n\n#: ../../pixmap.rst:549 f7663a0870b54e46b8a6d53a9a5d3958\nmsgid \"\"\n\"Look at this example from a 2 MB JPEG: the memoryview is **ten thousand \"\n\"times faster**::\"\nmsgstr \"この2 MBのJPEGからのこの例をご覧ください： `memoryview` は **10000倍高速** です::\"\n\n#: ../../pixmap.rst:556 4d36f9e0a4af4491be38efa57f54faf8\nmsgid \"\"\n\"After the Pixmap has been destroyed, any attempt to use the memoryview \"\n\"will fail with ValueError.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:559 91107ae487b14fe0b83a14f571082c55\nmsgid \"memoryview\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:565 d3bfaae3761a4c0eb851933ffe8701a3\nmsgid \"\"\n\"Python pointer to the pixel area. This is a special integer format, which\"\n\" can be used by supporting applications (such as PyQt) to directly \"\n\"address the samples area and thus build their images extremely fast. For \"\n\"example::\"\nmsgstr \"ピクセル領域へのPythonポインターです。これは特別な整数形式で、サポートするアプリケーション（PyQtなど）がサンプル領域に直接アクセスし、非常に高速に画像を構築できるように使用できます。例えば::\"\n\n#: ../../pixmap.rst:570 92d9db2f39614549b2c8a9605c681e0b\nmsgid \"\"\n\"Both of the above lead to the same Qt image, but (2) can be **many \"\n\"hundred times faster**, because it avoids an additional copy of the pixel\"\n\" area.\"\nmsgstr \"以下はQtイメージへの2つの方法ですが、(2)はピクセル領域の追加のコピーを回避するため、通常 **何百倍も高速** です。\"\n\n#: ../../pixmap.rst:572 37f284851e024d87b4ae3d3f4b495885\nmsgid \"\"\n\"Warning: after the Pixmap has been destroyed, the Python pointer will be \"\n\"invalid and attempting to use it may crash the Python interpreter.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:579 ad8485f478d04d1791c23f7e6c8cf984\nmsgid \"\"\n\"Contains *len(pixmap)*. This will generally equal *len(pix.samples)* plus\"\n\" some platform-specific value for defining other attributes of the \"\n\"object.\"\nmsgstr \"\"\n\"これは *pixmap の長さ* を含んでいます。通常、これは *pix.samples の長さ* \"\n\"にプラットフォーム固有の他の属性を定義するためのいくつかの値を加えたものです。\"\n\n#: ../../pixmap.rst:587 c1796fc010774081b59146b900edf924\nmsgid \"Width of the region in pixels.\"\nmsgstr \"ピクセル単位の領域の幅。\"\n\n#: ../../pixmap.rst:595 d21ef5432611489797b4691400ea9d15\nmsgid \"Height of the region in pixels.\"\nmsgstr \"ピクセル単位の領域の高さ。\"\n\n#: ../../pixmap.rst:601 5f88d51c88864babb326d12c5da3c8b4\nmsgid \"\"\n\"X-coordinate of top-left corner in pixels. Cannot directly be changed -- \"\n\"use :meth:`Pixmap.set_origin`.\"\nmsgstr \"ピクセル単位での左上隅のX座標。直接変更できません。:meth:`Pixmap.set_origin` を使用してください。\"\n\n#: ../../pixmap.rst:607 d82f9559530f4ed3a33c06c66cd24f3c\nmsgid \"\"\n\"Y-coordinate of top-left corner in pixels. Cannot directly be changed -- \"\n\"use :meth:`Pixmap.set_origin`.\"\nmsgstr \"ピクセル単位での左上隅のY座標。直接変更できません。:meth:`Pixmap.set_origin` を使用してください。\"\n\n#: ../../pixmap.rst:613 26e889e8aa564bbea3553b3d55151e83\n#, fuzzy\nmsgid \"\"\n\"Number of components per pixel. This number depends on colorspace and \"\n\"alpha. If colorspace is not ``None`` (stencil masks), then *Pixmap.n - \"\n\"Pixmap.alpha == pixmap.colorspace.n* is true. If colorspace is ``None``, \"\n\"then *n == alpha == 1*.\"\nmsgstr \"\"\n\"ピクセルごとのコンポーネントの数。この数は色空間とアルファに依存します。色空間が ``None`` \"\n\"でない場合（ステンシルマスク）、*Pixmap.n - Pixmap.alpha == pixmap.colorspace.n* \"\n\"がtrueです。色空間が ``None`` の場合、*n == alpha == 1* です。\"\n\n#: ../../pixmap.rst:619 ddc7c2c6d915466a8673711ed573419a\nmsgid \"\"\n\"Horizontal resolution in dpi (dots per inch). Please also see \"\n\":data:`resolution`. Cannot directly be changed -- use \"\n\":meth:`Pixmap.set_dpi`.\"\nmsgstr \"\"\n\"水平解像度（dpi単位）。:data:`resolution` \"\n\"も参照してください。直接変更できません。:meth:`Pixmap.set_dpi` を使用してください。\"\n\n#: ../../pixmap.rst:625 5952023fee854e3f82d65f1dbcc33361\nmsgid \"\"\n\"Vertical resolution in dpi (dots per inch). Please also see \"\n\":data:`resolution`. Cannot directly be changed -- use \"\n\":meth:`Pixmap.set_dpi`.\"\nmsgstr \"\"\n\"垂直解像度（dpi単位）。:data:`resolution` \"\n\"も参照してください。直接変更できません。:meth:`Pixmap.set_dpi` を使用してください。\"\n\n#: ../../pixmap.rst:631 966a193e7ae14efe944c435e65718b73\nmsgid \"\"\n\"An information-only boolean flag set to ``True`` if the image will be \"\n\"drawn using \\\"linear interpolation\\\". If ``False`` \\\"nearest neighbour \"\n\"sampling\\\" will be used.\"\nmsgstr \"\"\n\"情報のみのブールフラグで、イメージが「線形補間」を使用して描画される場合に ``True`` に設定されます。``False`` \"\n\"の場合、「最近傍サンプリング」が使用されます。\"\n\n#: ../../pixmap.rst:638 32f8505442184689838784d6630b61ca\nmsgid \"Supported Input Image Formats\"\nmsgstr \"サポートされている入力画像フォーマット\"\n\n#: ../../pixmap.rst:639 708fca4db2a64b96a2de83796cd396e7\nmsgid \"\"\n\"The following file types are supported as **input** to construct pixmaps:\"\n\" **BMP, JPEG, GIF, TIFF, JXR, JPX**, **PNG**, **PAM** and all of the \"\n\"**Portable Anymap** family (**PBM, PGM, PNM, PPM**). This support is two-\"\n\"fold:\"\nmsgstr \"\"\n\"次のファイルタイプは、ピクスマップを構築するための **入力** \"\n\"としてサポートされています：**BMP、JPEG、GIF、TIFF、JXR、JPX**、**PNG**、**PAM**、およびすべての \"\n\"**Portable Anymap** ファミリー（**PBM、PGM、PNM、PPM**）。このサポートは二重の方法で提供されています：\"\n\n#: ../../pixmap.rst:641 4f4eb0bb22404ab184bf7ed8014abcc3\nmsgid \"\"\n\"Directly create a pixmap with *Pixmap(filename)* or *Pixmap(byterray)*. \"\n\"The pixmap will then have properties as determined by the image.\"\nmsgstr \"\"\n\"*Pixmap（ファイル名）* または *Pixmap（バイト配列）* \"\n\"を使用してピクスマップを直接作成します。その後、ピクスマップには画像によって決定されるプロパティが含まれます。\"\n\n#: ../../pixmap.rst:643 1f9a875b37444d988033c769493f20e4\nmsgid \"\"\n\"Open such files with *pymupdf.open(...)*. The result will then appear as \"\n\"a document containing one single page. Creating a pixmap of this page \"\n\"offers all the options available in this context: apply a matrix, choose \"\n\"colorspace and alpha, confine the pixmap to a clip area, etc.\"\nmsgstr \"\"\n\"*pymupdf.open(...)* \"\n\"を使用してこのようなファイルを開きます。その結果、単一のページを含むドキュメントとして表示されます。このページのピクスマップを作成すると、このコンテキストで利用可能なすべてのオプションを使用できます：行列を適用、色空間とアルファを選択、ピクスマップをクリップエリアに制限などが含まれます。\"\n\n#: ../../pixmap.rst:645 b8da58f972e349c099d429016189277f\nmsgid \"\"\n\"**SVG images** are only supported via method 2 above, not directly as \"\n\"pixmaps. But remember: the result of this is a **raster image** as is \"\n\"always the case with pixmaps [#f1]_.\"\nmsgstr \"\"\n\"**SVG画像** は、直接ピクスマップとしてではなく、上記の方法2でのみサポートされています。ただし、ピクスマップの場合と同様、その結果は \"\n\"**ラスターイメージ** です [#f1]_。\"\n\n#: ../../pixmap.rst:650 5eb573904fb7401cb281c16fb4549f3a\nmsgid \"Supported Output Image Formats\"\nmsgstr \"サポートされている出力画像フォーマット\"\n\n#: ../../pixmap.rst:651 e4357173b7ec40d892ee19fcd4f3b83d\nmsgid \"\"\n\"A number of image **output** formats are supported. You have the option \"\n\"to either write an image directly to a file (:meth:`Pixmap.save`), or to \"\n\"generate a bytes object (:meth:`Pixmap.tobytes`). Both methods accept a \"\n\"string identifying the desired format (**Format** column below). Please \"\n\"note that not all combinations of pixmap colorspace, transparency support\"\n\" (alpha) and image format are possible.\"\nmsgstr \"\"\n\"いくつかの画像 **出力** \"\n\"フォーマットがサポートされています。画像を直接ファイルに書き込むオプション（:meth:`Pixmap.save`）またはバイトオブジェクトを生成するオプション（:meth:`Pixmap.tobytes`）があります。どちらのメソッドも、希望の\"\n\" **フォーマット** \"\n\"を識別する文字列を受け入れます（下のフォーマット列）。ただし、すべてのピクスマップの色空間、透明度サポート（アルファ）、および画像フォーマットの組み合わせが可能であるわけではないことに注意してください。\"\n\n#: ../../pixmap.rst:654 4dbea7a06e2b4187a123a1c604d44efe\nmsgid \"**Format**\"\nmsgstr \"**フォーマット**\"\n\n#: ../../pixmap.rst:654 80b26e8d30f3423393a42e35c1a19bb0\nmsgid \"**Colorspaces**\"\nmsgstr \"**カラースペース**\"\n\n#: ../../pixmap.rst:654 227b7bee485d4b79a2402f03891614ea\nmsgid \"**alpha**\"\nmsgstr \"**アルファ**\"\n\n#: ../../pixmap.rst:654 9797dfa1d6b74610af214069c4ee23d6\nmsgid \"**Extensions**\"\nmsgstr \"**拡張子**\"\n\n#: ../../pixmap.rst:654 a635c115d504411785c1bf1a3984582a\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../pixmap.rst:656 3f28e0c2c0e44d239075c2258795286a\nmsgid \"jpg, jpeg\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 ../../pixmap.rst:657 ../../pixmap.rst:663\n#: ../../pixmap.rst:664 18832c370236476095068f372050837f\n#: 3eb2a94753b44fdd9c7731ef24aef48b 4a67821c83134b4db3e4be1914c17d60\n#: c83309e3c1934fc7ae1a973ebe7d1300\nmsgid \"gray, rgb, cmyk\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 ../../pixmap.rst:658 ../../pixmap.rst:659\n#: ../../pixmap.rst:661 ../../pixmap.rst:662 ../../pixmap.rst:663\n#: 02f9cb78532645d38d5abf940e1679f8 0cdb296b3e59480f8ec76bf53ac1c17b\n#: 2e0bd0a838434201878c609cff82145c 73c34c7c328f4d31af9f2258cc254f0d\n#: 947c1b80c66441799e2aba09091f8adb dd93afdec02947318d933a37f2c15024\nmsgid \"no\"\nmsgstr \"なし\"\n\n#: ../../pixmap.rst:656 600504f9efd041ffb5b69ec388b137e9\nmsgid \".jpg, .jpeg\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 26fa6ed5043a4a66a2c7adf39eb4e0cf\nmsgid \"Joint Photographic Experts Group\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:657 6f1f99578dd84b0b96b1fb4707aac08b\nmsgid \"pam\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:657 ../../pixmap.rst:660 ../../pixmap.rst:664\n#: 1389030dbadc408693776ddaa02d250f db4043e33252451d9cfa830afcf4325c\n#: eb6f616d9083427b85a8e817b7b3c601\nmsgid \"yes\"\nmsgstr \"あり\"\n\n#: ../../pixmap.rst:657 2f529016f72342f3ad621590a17c2720\nmsgid \".pam\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:657 e2baced162604080b59bf27d358fda6c\nmsgid \"Portable Arbitrary Map\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 95a9f8727e6846bdad7d42b2756dcf5e\nmsgid \"pbm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 ../../pixmap.rst:659 ../../pixmap.rst:660\n#: ../../pixmap.rst:661 ../../pixmap.rst:662 220d5771addc47059dfafb3b7fd7a809\n#: 68fd8f934dac404f86a38dcab3bb7bc2 91f4a25b5a5148af9a8c601bdc987ee9\n#: 9d56458bd5944b7eab22abdec12c33c6 da23d0d1e79b4239bc3b878fd251ed6f\nmsgid \"gray, rgb\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 10546c5955514cb99a4533ae396c259f\nmsgid \".pbm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 3a22578bed7f479ba9f8bd94ddba617b\nmsgid \"Portable Bitmap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:659 12f4977253d34e7fb05ef71f9b6bb875\nmsgid \"pgm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:659 34b5715a5a94481fa5410ee5467f5ae1\nmsgid \".pgm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:659 06d8a88352b54e25b36fc1dbd2289ecc\nmsgid \"Portable Graymap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:660 31684d0764064d42a3a8d884741e85be\nmsgid \"png\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:660 34455c189f334f3ab56545b979560b1b\nmsgid \".png\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:660 682ed1780ad3421e9223fdefb0b8184c\nmsgid \"Portable Network Graphics\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:661 f94a2f8f962f47fc9c9b1a7e2a906e11\nmsgid \"pnm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:661 964f7dfd9ae844129b05d2e56342317d\nmsgid \".pnm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:661 d627891286e44ad3987520c5e705f3a1\nmsgid \"Portable Anymap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:662 3ada12b4d8b84c17aac44fec31492b76\nmsgid \"ppm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:662 29fa1a416b3345479d3cb7258b83155e\nmsgid \".ppm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:662 9045e7c717ae4d61ae56392d64c8f030\nmsgid \"Portable Pixmap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:663 b528c16c8d064788976a0d977cf72a73\nmsgid \"ps\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:663 3d3a984cad1f4a1ba8eca7cfbc0af43f\nmsgid \".ps\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:663 f472a32950f140dcbd4258d41e955e95\nmsgid \"Adobe PostScript Image\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:664 d30993e0b1534a1da119de1e713e1fe7\nmsgid \"psd\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:664 c340e5edd2234429989f7c57fcbe6d4f\nmsgid \".psd\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:664 5ad137cb3c0c44fb8491eab0123adabe\nmsgid \"Adobe Photoshop Document\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:668 5b70a01cdd2d49678a5104943c6ceb05\nmsgid \"\"\n\"Not all image file types are supported (or at least common) on all OS \"\n\"platforms. E.g. PAM and the Portable Anymap formats are rare or even \"\n\"unknown on Windows.\"\nmsgstr \"\"\n\"すべての画像ファイル形式がすべてのOSプラットフォームでサポートされているわけではありません（または少なくとも一般的ではありません）。たとえば、PAMおよびPortable\"\n\" Anymap形式はWindowsでは珍しいか、またはまったく知られていません。\"\n\n#: ../../pixmap.rst:669 ac24d0029a85434e89d87aea3c768299\nmsgid \"\"\n\"Especially pertaining to CMYK colorspaces, you can always convert a CMYK \"\n\"pixmap to an RGB pixmap with *rgb_pix = pymupdf.Pixmap(pymupdf.csRGB, \"\n\"cmyk_pix)* and then save that in the desired format.\"\nmsgstr \"\"\n\"特にCMYKカラースペースに関連することについて、常にCMYK pixmapを *rgb_pix = \"\n\"pymupdf.Pixmap(pymupdf.csRGB、cmyk_pix)* に変換し、その後、その形式で保存できます。\"\n\n#: ../../pixmap.rst:670 0d389b2c11cb4b7dbad0be0409dbf4dc\nmsgid \"\"\n\"As can be seen, MuPDF's image support range is different for input and \"\n\"output. Among those supported both ways, PNG and JPEG are probably the \"\n\"most popular.\"\nmsgstr \"ご覧のように、MuPDFの画像サポート範囲は入力と出力で異なります。両方の方法でサポートされているものの中で、PNGとJPEGはおそらく最も人気があります。\"\n\n#: ../../pixmap.rst:671 78fe092f468843e984dee90661b2dbac\nmsgid \"\"\n\"We also recommend using \\\"ppm\\\" formats as input to tkinter's \"\n\"*PhotoImage* method like this: *tkimg = \"\n\"tkinter.PhotoImage(data=pix.tobytes(\\\"ppm\\\"))* (also see the tutorial). \"\n\"This is **very** fast (**60 times** faster than PNG).\"\nmsgstr \"\"\n\"また、tkinterの *PhotoImage* メソッドへの入力として「ppm」形式を使用することをお勧めします。*tkimg = \"\n\"tkinter.PhotoImage(data=pix.tobytes(\\\"ppm\\\"))* のように（チュートリアルも参照してください）。これは\"\n\" **非常に** 高速です（PNGよりも60倍速いです）。\"\n\n#: ../../pixmap.rst:676 ae8dd148bf7a4c1ea2de109295f929f5\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../pixmap.rst:677 b53f5a80a69a41dea8df4b23d4e4be3d\nmsgid \"\"\n\"If you need a **vector image** from the SVG, you must first convert it to\"\n\" a PDF. Try :meth:`Document.convert_to_pdf`. If this is not good enough, \"\n\"look for other SVG-to-PDF conversion tools like the Python packages \"\n\"`svglib <https://pypi.org/project/svglib>`_, `CairoSVG \"\n\"<https://pypi.org/project/cairosvg>`_, `Uniconvertor \"\n\"<https://sk1project.net/modules.php?name=Products&product=uniconvertor&op=download>`_\"\n\" or the Java solution `Apache Batik <https://github.com/apache/batik>`_. \"\n\"Have a look at our Wiki for more examples.\"\nmsgstr \"\"\n\"SVGから **ベクトル画像** \"\n\"が必要な場合、まずそれをPDFに変換する必要があります。:meth:`Document.convert_to_pdf` \"\n\"を試してみてください。これで十分でない場合、他のSVGからPDFへの変換ツールを探してみてください。Pythonパッケージ `svglib \"\n\"<https://pypi.org/project/svglib>`_ 、 `CairoSVG \"\n\"<https://pypi.org/project/cairosvg>`_ 、 `Uniconvertor \"\n\"<https://sk1project.net/modules.php?name=Products&product=uniconvertor&op=download>`_\"\n\" 、またはJavaソリューションである `Apache Batik <https://github.com/apache/batik>`_ \"\n\"などがあります。詳細な例についてはWikiをご覧ください。\"\n\n#: ../../pixmap.rst:679 7efc30a117974783984b2f586a774632\nmsgid \"\"\n\"To also set the alpha property, add an additional step to this method by \"\n\"dropping or adding an alpha channel to the result.\"\nmsgstr \"アルファプロパティも設定する場合は、このメソッドに追加ステップを追加し、結果にアルファチャンネルを追加または削除してください。\"\n\n#: ../../footer.rst:46 e3d72edf62c54080b2839fccccec965e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"Since v1.22.0, PyMuPDF supports JPEG \"\n#~ \"output directly. For both, performance \"\n#~ \"reasons and for reducing external \"\n#~ \"dependencies, the use of this method \"\n#~ \"is no longer recommended when outputting\"\n#~ \" JPEG images.\"\n#~ msgstr \"\"\n#~ \"v1.22.0 以降、PyMuPDF はJPEG \"\n#~ \"出力を直接サポートしています。パフォーマンスの理由と外部の依存関係を減らすために、JPEG \"\n#~ \"画像を出力する場合にはこのメソッドの使用は推奨されなくなりました。\"\n\n#~ msgid \".raises ImportError: if Pillow is not installed.\"\n#~ msgstr \"**ImportError** -- Pillow がインストールされていない場合\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"a ˇˇPIL.Imageˇˇ object\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"If the pixmap's colorspace is RGB \"\n#~ \"with transparency, the alpha values may\"\n#~ \" or may not already be multiplied \"\n#~ \"into the color components ref/green/blue \"\n#~ \"(called \\\"premultiplied\\\"). To enforce undoing\"\n#~ \" premultiplication, set this parameter to\"\n#~ \" `True`. To learn about some \"\n#~ \"background, e.g. look for \\\"Premultiplied \"\n#~ \"alpha\\\" `here \"\n#~ \"<https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/point.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 0d500c9fea194e18bdf21282347590bd\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 e33c40891e6e4d32874b82f04358d0c3\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 66e5e2ad40694dd291575cb985997e52\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../point.rst:7 1a7b12dde1344c6b8af9cf30d960d3a2\nmsgid \"Point\"\nmsgstr \"Point (ポイント)\"\n\n#: ../../point.rst:9 9373b96698944d69a97d4aa9025c1380\nmsgid \"\"\n\"*Point* represents a point in the plane, defined by its x and y \"\n\"coordinates.\"\nmsgstr \"*Point* は、そのx座標とy座標で定義される平面上のポイントを表します。\"\n\n#: ../../point.rst:12 ddd49ef47c8f4f308f1ddf551cc2e567\nmsgid \"**Attribute / Method**\"\nmsgstr \"**属性/メソッド**\"\n\n#: ../../point.rst:12 ed814359d1e345869d70ff6ee4cdc137\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../point.rst:14 4032a33dd2b0453585391c0e32c93025\nmsgid \":meth:`Point.distance_to`\"\nmsgstr \"\"\n\n#: ../../point.rst:14 9b1b84ecc1484fa58a5bd82f7efcc3e0\nmsgid \"calculate distance to point or rect\"\nmsgstr \"ポイントまたは長方形までの距離を計算します\"\n\n#: ../../point.rst:15 1d732af9b4494df9b35b7fc90450942a\nmsgid \":meth:`Point.norm`\"\nmsgstr \"\"\n\n#: ../../point.rst:15 24cca31dc32d48ebb45024fe75817652\nmsgid \"the Euclidean norm\"\nmsgstr \"ユークリッドノルム\"\n\n#: ../../point.rst:16 a4fdce716744491d81882b1974682151\nmsgid \":meth:`Point.transform`\"\nmsgstr \"\"\n\n#: ../../point.rst:16 0af15635b5b848668ada5ffbe0cbd6df\nmsgid \"transform point with a matrix\"\nmsgstr \"行列でポイントを変換します\"\n\n#: ../../point.rst:17 d888e3fab54a4373b8feaaf91ebd5ae1\nmsgid \":attr:`Point.abs_unit`\"\nmsgstr \"\"\n\n#: ../../point.rst:17 183111208bb2467cb4b0394b7b4ab584\nmsgid \"same as unit, but positive coordinates\"\nmsgstr \"ユニットと同じですが、座標が正です\"\n\n#: ../../point.rst:18 9d60bb6c9d1c47ab98ee6fa40c9e579e\nmsgid \":attr:`Point.unit`\"\nmsgstr \"\"\n\n#: ../../point.rst:18 3d36d8d93e024d4fb909fb12f00b7ff2\nmsgid \"point coordinates divided by *abs(point)*\"\nmsgstr \"座標を *abs(point)* で割ったもの\"\n\n#: ../../point.rst:19 0f6cbe3e87d741b298d27c89be5c87cd\nmsgid \":attr:`Point.x`\"\nmsgstr \"\"\n\n#: ../../point.rst:19 ed960716ff06486ba3d689e34b3796e3\nmsgid \"the X-coordinate\"\nmsgstr \"X座標\"\n\n#: ../../point.rst:20 dafbd6c6033d4c93957636f1b93bbb34\nmsgid \":attr:`Point.y`\"\nmsgstr \"\"\n\n#: ../../point.rst:20 14468a77b47b4dd6befbf66696bd10e2\nmsgid \"the Y-coordinate\"\nmsgstr \"Y座標\"\n\n#: ../../point.rst:23 d7c7ec15f0c64ec0bde77f8040a3949b\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../point.rst:35 4f945447bee6442cad5956d1a6846689\nmsgid \"Overloaded constructors.\"\nmsgstr \"オーバーロードされたコンストラクタ。\"\n\n#: ../../point.rst:37 67c4744696474b708d6c7b4519ea6369\nmsgid \"Without parameters, *Point(0, 0)* will be created.\"\nmsgstr \"パラメーターなしで、*Point(0, 0)* が作成されます。\"\n\n#: ../../point.rst:39 83a7b067d7034877898de81fa905a27b\nmsgid \"\"\n\"With another point specified, a **new copy** will be created, \"\n\"\\\"sequence\\\" is a Python sequence of 2 numbers (see \"\n\":ref:`SequenceTypes`).\"\nmsgstr \"\"\n\"他のポイントが指定された場合、**新しいコピー** が作成され、 \"\n\"\\\"sequence\\\"は2つの数値からなるPythonシーケンスです（:ref:`SequenceTypes`）。\"\n\n#: ../../point.rst 019a616c168b4a2f861f9af0ee399ea7\n#: 2bca886d5a7047579d56cd8ca0b2d161 e9644af7e0554639a33a4f730ebd999f\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../point.rst:41 016a723eaaa64a778d1da1aaff44c2c0\nmsgid \"x coordinate of the point\"\nmsgstr \"ポイントのx座標\"\n\n#: ../../point.rst:43 043d8b3675e44b1b8a995cfffb851812\nmsgid \"y coordinate of the point\"\nmsgstr \"ポイントのy座標\"\n\n#: ../../point.rst:47 bda3f4adf4774b85838e3f7624d90d0c\nmsgid \"\"\n\"Calculate the distance to *x*, which may be :data:`point_like` or \"\n\":data:`rect_like`. The distance is given in units of either pixels \"\n\"(default), inches, centimeters or millimeters.\"\nmsgstr \"\"\n\"*x* までの距離を計算します。 *x* は :data:`point_like` または :data:`rect_like` \"\n\"である可能性があります。距離は、ピクセル（デフォルト）、インチ、センチメートル、ミリメートルのいずれかの単位で指定されます。\"\n\n#: ../../point.rst:49 51eb5b1d201a4f12a44618b02b2f0ac7\nmsgid \"to which to compute the distance.\"\nmsgstr \"距離を計算する対象\"\n\n#: ../../point.rst:51 0ae910e1ebbb43498a2d28bc4183b6b8\nmsgid \"the unit to be measured in. One of \\\"px\\\", \\\"in\\\", \\\"cm\\\", \\\"mm\\\".\"\nmsgstr \"測定単位。 \\\"px\\\"、 \\\"in\\\"、 \\\"cm\\\"、 \\\"mm\\\"のいずれか\"\n\n#: ../../point.rst 3a555709592f4392804556d4a3ec4e27\n#: 73ea2dd2fe974651a11d7cc2de129e1b\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../point.rst 477b136a22ab4265a3da36bf573fe39d\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../point.rst:54 2030d7a487e149959a154537312a572e\nmsgid \"\"\n\"the distance to *x*. If this is :data:`rect_like`, then the distance  * \"\n\"is the length of the shortest line connecting to one of the rectangle \"\n\"sides * is calculated to the **finite version** of it * is zero if it \"\n\"**contains** the point\"\nmsgstr \"\"\n\n#: ../../point.rst:54 af0a3e229e7e43cebbe0f3ab85666636\nmsgid \"the distance to *x*. If this is :data:`rect_like`, then the distance\"\nmsgstr \"*x* までの距離。これが :data:`rect_like` の場合、距離\"\n\n#: ../../point.rst:56 35dd44147c624976886941cec496f10d\nmsgid \"\"\n\"is the length of the shortest line connecting to one of the rectangle \"\n\"sides\"\nmsgstr \"長方形の任意の辺に接続する最短線の長さ\"\n\n#: ../../point.rst:57 b958d1db25694ade9997b6fb88065cb1\nmsgid \"is calculated to the **finite version** of it\"\nmsgstr \"その **有限バージョン** が計算されます\"\n\n#: ../../point.rst:58 50b8b68670d44ab58ff2a5e1471a2375\nmsgid \"is zero if it **contains** the point\"\nmsgstr \"ポイントを **含む** 場合はゼロ\"\n\n#: ../../point.rst:62 961b212deb1f4d2ab46a27116cacccab\nmsgid \"New in version 1.16.0\"\nmsgstr \"バージョン1.16.0で新規追加\"\n\n#: ../../point.rst:64 ebf5e01ee8414746b3bc426ee94ea1b3\nmsgid \"\"\n\"Return the Euclidean norm (the length) of the point as a vector. Equals \"\n\"result of function *abs()*.\"\nmsgstr \"ベクトルとしてのポイントのユークリッドノルム（長さ）を返します。 *abs()* 関数の結果と等しいです。\"\n\n#: ../../point.rst:68 74d77a8f32a14ab58d2ea6a9d9fbd224\nmsgid \"Apply a matrix to the point and replace it with the result.\"\nmsgstr \"ポイントに行列を適用して、その結果で置き換えます。\"\n\n#: ../../point.rst:70 781600b0f789421093c8d211a828214c\nmsgid \"The matrix to be applied.\"\nmsgstr \"適用する行列。\"\n\n#: ../../point.rst:72 ../../point.rst:80 ../../point.rst:86\n#: 5bb59ebd897348deb9ddbeecd467559a 93624a23e8f049d89ba4d5f25f6d5ca5\n#: f42faeb785d84a6aa8ca09b294d45d72\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../point.rst:76 ffda14407cc94228ab7552a1ff1596ad\nmsgid \"\"\n\"Result of dividing each coordinate by *norm(point)*, the distance of the \"\n\"point to (0,0). This is a vector of length 1 pointing in the same \"\n\"direction as the point does. Its x, resp. y values are equal to the \"\n\"cosine, resp. sine of the angle this vector (and the point itself) has \"\n\"with the x axis.\"\nmsgstr \"\"\n\"各座標を *norm(point)* \"\n\"、ポイントが（0、0）からの距離で割った結果です。これは、ポイント自体がx軸との角度を持つベクトルと同じ方向を指す長さ1のベクトルです。そのx、resp。\"\n\" yの値は、このベクトル（およびポイント自体）がx軸とどのような角度を持っているかに等しいです。\"\n\n#: ../../point.rst 365fd452be064ca7b35dd82343f61722\n#: 61aabb3fb7b242c483bcbc3dfbf244a5 ee619eddf0ff4ef4b1cb279d8fa7a6f3\n#: f4ef146bdd194e079d0bbdb3fe0a7a02\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../point.rst:84 98dd11ae2ded46fba9aa5bc2f6b1667e\nmsgid \"\"\n\"Same as :attr:`unit` above, replacing the coordinates with their absolute\"\n\" values.\"\nmsgstr \"同じく、上記の :attr:`unit` と同様のもので、座標をそれぞれの絶対値に置き換えたものです。\"\n\n#: ../../point.rst:90 19dceabb090d4f1db7c2c31ba2634756\nmsgid \"The x coordinate\"\nmsgstr \"x座標\"\n\n#: ../../point.rst:92 ../../point.rst:98 3c19788c87c14335baeb6e261c4491a0\n#: d9f4c536626243e68f4e6c81133e0338\nmsgid \"float\"\nmsgstr \"\"\n\n#: ../../point.rst:96 6300e816dea5405293aee117b39c4d79\nmsgid \"The y coordinate\"\nmsgstr \"y座標\"\n\n#: ../../point.rst:102 c67aba539e2441e1b48edda3875e6285\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"\"\n\"このクラスはPythonのシーケンスプロトコルに従っており、コンポーネントはインデックスを使用してアクセスできます。また、PyMuPDFでの引数としてPythonのシーケンスを使用する方法については、:ref:`SequenceTypes`\"\n\" を参照してください。\"\n\n#: ../../point.rst:103 b49de5b5939f4ea2b4916b2303345e68\nmsgid \"\"\n\"Rectangles can be used with arithmetic operators -- see chapter \"\n\":ref:`Algebra`.\"\nmsgstr \"長方形は算術演算子と共に使用できます - 幾 :ref:`Algebra` を参照してください。\"\n\n#: ../../footer.rst:60 6e7a0e3f1a044447ac39d419d2f8145a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/pymupdf-layout/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-26 17:04+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 55554f175cc249878ead6e3e984a2e8a\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 6aa2efac349e4bcab64dd67c0a0d5b13\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 fc386a5037ac4a0ba4239f1c51308e56\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../pymupdf-layout/index.rst:8 65880921881d4c9a95f25a114c1617cc\nmsgid \"PyMuPDF Layout\"\nmsgstr \"\"\n\n#: ../../pymupdf-layout/index.rst:11 26826b75387e4aadb2a29e8f577d4b8a\nmsgid \"\"\n\"|PyMuPDF Layout| is a lightweight layout analysis extension for |PyMuPDF|\"\n\" that turns PDFs into clean, structured data with minimal setup. It’s \"\n\"fast, accurate, and efficient without any GPU requirement.\"\nmsgstr \"PyMuPDF Layout は、PyMuPDF 用の軽量なレイアウト解析拡張機能で、最小限のセットアップで PDF をクリーンで構造化されたデータに変換します。高速で正確かつ効率的であり、GPU を必要としません。\"\n\n#: ../../pymupdf-layout/index.rst:13 20fc4e9d5eae44d58cced93202624c15\nmsgid \"\"\n\"It is an optional, but recommended, addition to the |PyMuPDF| library \"\n\"especially if you are required to more accurately extract structured data\"\n\" with better semantic information.\"\nmsgstr \"これは PyMuPDF ライブラリへのオプションですが推奨される追加機能であり、特により正確な意味情報を持つ構造化データの抽出が必要な場合に有用です。\"\n\n#: ../../pymupdf-layout/index.rst:17 6cb4d2e97d464990a633d2defd97698e\nmsgid \"Installing\"\nmsgstr \"インストール\"\n\n#: ../../pymupdf-layout/index.rst:19 85aefd1baecd485b800f2238aba711c7\nmsgid \"Install from |PyPI| with::\"\nmsgstr \"|PyPI|  からインストールするには::\"\n\n#: ../../pymupdf-layout/index.rst:26 5e49fc1022b0491e968e6dac9a6ebd28\nmsgid \"Using\"\nmsgstr \"使用方法\"\n\n#: ../../pymupdf-layout/index.rst:29 c4caa7b3525f461385db5339599b8e02\nmsgid \"\"\n\"In nutshell, |PyMuPDF Layout| detects the layout to extract, but we need \"\n\"|PyMuPDF4LLM| for the API interface. This provides us with options to \"\n\"extract document content as |Markdown|, |JSON| or |TXT|.\"\nmsgstr \"簡単に言えば、PyMuPDF Layout は抽出するレイアウトを検出しますが、API インターフェースには PyMuPDF4LLM が必要です。これにより、ドキュメントコンテンツを Markdown、JSON、または TXT として抽出するオプションが提供されます。\"\n\n#: ../../pymupdf-layout/index.rst:31 2851cd8bd3374a3c8fc60a4a0fe524e8\nmsgid \"\"\n\"Let's set up the Python coding environment to get started and open a PDF \"\n\"then we'll move on to the semantic data extraction.\"\nmsgstr \"それでは、始めるために Python コーディング環境をセットアップし、PDF を開いてから、セマンティックデータ抽出に進みましょう。\"\n\n#: ../../pymupdf-layout/index.rst:34 6a1648fb91cc454788a795ffc391432a\nmsgid \"Register packages and open a PDF\"\nmsgstr \"パッケージを登録して PDF を開く\"\n\n#: ../../pymupdf-layout/index.rst:36 1ba188d096bc425abbfee2ba07430823\nmsgid \"First up let's import the libraries and open a sample document::\"\nmsgstr \"まず、ライブラリをインポートしてサンプルドキュメントを開きましょう::\"\n\n#: ../../pymupdf-layout/index.rst:42 d7900ddabe0644c09c53ba9fb57126b0\nmsgid \"\"\n\"Note, in the above code, that |PyMuPDF Layout| must be imported as shown \"\n\"and before importing |PyMuPDF4LLM| to activate |PyMuPDF|'s layout feature\"\n\" and make it available to |PyMuPDF4LLM|.\"\nmsgstr \"上記のコードでは、|PyMuPDF Layout| は示されているようにインポートする必要があり、|PyMuPDF| のレイアウト機能を有効にして |PyMuPDF4LLM| で利用可能にするために、|PyMuPDF4LLM| をインポートする前にインポートする必要があることに注意してください。\"\n\n#: ../../pymupdf-layout/index.rst:44 7b66dd7c7a164f99b1fd0113f2ccf699\nmsgid \"\"\n\"Omitting the first line would cause execution of standard |PyMuPDF4LLM| -\"\n\" without the layout feature!\"\nmsgstr \"最初の行を省略すると、レイアウト機能なしの標準 |PyMuPDF4LLM| が実行されます!\"\n\n#: ../../pymupdf-layout/index.rst:47 a21b9bc7b3844b0ab455c3f364a2057f\nmsgid \"Extract the structured data\"\nmsgstr \"構造化データを抽出する\"\n\n#: ../../pymupdf-layout/index.rst:49 35bc60862bb24334a75b7dc95b60156f\nmsgid \"\"\n\"We've activated the |PyMuPDF Layout| library and we've loaded a document,\"\n\" next let's extract the structured data. This is now like a super-charged\"\n\" version of standard |PyMuPDF4LLM| with ``Layout`` working behind the \"\n\"scenes combining heuristics with machine learning - for better extraction\"\n\" results.\"\nmsgstr \"|PyMuPDF Layout| ライブラリを有効にし、ドキュメントを読み込みました。次に構造化データを抽出しましょう。これは、``Layout`` がバックグラウンドでヒューリスティックと機械学習を組み合わせて動作する、標準 |PyMuPDF4LLM| の強化版のようなもので、より良い抽出結果が得られます。\"\n\n#: ../../pymupdf-layout/index.rst:52 8fabaa7045ea40bca50d9b6cf1904b2b\nmsgid \"Extract as Markdown\"\nmsgstr \"Markdown として抽出\"\n\n#: ../../pymupdf-layout/index.rst:60 253f86c879cd4cfda51045e1311a3cba\nmsgid \"Extract as JSON\"\nmsgstr \"JSON として抽出\"\n\n#: ../../pymupdf-layout/index.rst:68 8da4947d5b974f24803ba5ed16e8cd77\nmsgid \"Extract as TXT\"\nmsgstr \"TXT として抽出\"\n\n#: ../../pymupdf-layout/index.rst:76 5bbe37c28031413fa4f86978d66b0161\nmsgid \"\"\n\"Please refer top the full :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` for \"\n\"more.\"\nmsgstr \"詳細については、完全な :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` を参照してください。\"\n\n#: ../../pymupdf-layout/index.rst:78 6eedc55b27574fb583b04a9b9f3e3f55\nmsgid \"Finally we can save the output to an external file as follows::\"\nmsgstr \"最後に、次のように出力を外部ファイルに保存できます\"\n\n#: ../../pymupdf-layout/index.rst:86 9bdb3f269e1c497e91d97cdc3a687bff\nmsgid \"Headers & Footers\"\nmsgstr \"ヘッダーとフッター\"\n\n#: ../../pymupdf-layout/index.rst:89 c239bc0bbbd64d318e6e8fdc55d1efbe\nmsgid \"\"\n\"Many documents will have header and footer information on each page of a \"\n\"PDF which you may or may not want to include. This information can be \"\n\"repetitive and simply not needed ( e.g. the same logo and document title \"\n\"or page number information is not always really important when it comes \"\n\"to extracting the document content ).\"\nmsgstr \"多くのドキュメントでは、PDF の各ページにヘッダーとフッター情報があり、これを含めたい場合と含めたくない場合があります。この情報は繰り返しになることがあり、単に不要な場合があります（例えば、同じロゴやドキュメントタイトル、ページ番号情報は、ドキュメントコンテンツを抽出する際に常に重要とは限りません）。\"\n\n#: ../../pymupdf-layout/index.rst:91 ee2ea44ed53e4d95860be54bee8ead00\nmsgid \"\"\n\"|PyMuPDF Layout| is trained in detecting these typical document elements \"\n\"and able to omit them.\"\nmsgstr \"|PyMuPDF Layout| は、これらの典型的なドキュメント要素を検出するようにトレーニングされており、それらを省略することができます。\"\n\n#: ../../pymupdf-layout/index.rst:93 2e53e75f3b83455ab9f885efaae230c7\nmsgid \"\"\n\"So in this case we can adjust our API calls to ignore these elements as \"\n\"follows::\"\nmsgstr \"したがって、この場合、次のように API 呼び出しを調整してこれらの要素を無視できます::\"\n\n#: ../../pymupdf-layout/index.rst:101 fc82782444984a34ab18e40f5123faeb\nmsgid \"\"\n\"Please note that page ``header`` / ``footer`` exclusion is not applicable\"\n\" to JSON output as it aims to always represent all data for the included \"\n\"pages. Please refer to the full :ref:`PyMuPDF4LLM API <pymupdf4llm-api>`\"\n\" for more.\"\nmsgstr \"``header`` / ``footer`` の除外は、含まれるページのすべてのデータを常に表現することを目的としているため、JSON 出力には適用されないことに注意してください。詳細については、完全な :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` を参照してください。\"\n\n#: ../../pymupdf-layout/index.rst:104 a00239ede95b43319833ba01713ce8d7\nmsgid \"Extending Capability\"\nmsgstr \"機能の拡張\"\n\n#: ../../pymupdf-layout/index.rst:107 f3bec49e1ee042caad2ba1f1f8d07230\nmsgid \"Using with Pro\"\nmsgstr \"PyMuPDF Pro との使用\"\n\n#: ../../pymupdf-layout/index.rst:109 1a6a4c0ada2842d588768a849fe3c7f3\nmsgid \"\"\n\"We are able to extend |PyMuPDF Layout| to work with |PyMuPDF Pro| and \"\n\"thus increase our capability by allowing Office documents to be provided \"\n\"as input files. In this case all we have to do is to add the import for \"\n\"|PyMuPDF Pro| and unlock it::\"\nmsgstr \"|PyMuPDF Layout| を |PyMuPDF Pro| と連携させることで機能を拡張し、Office ドキュメントを入力ファイルとして提供できるようにすることで能力を向上させることができます。この場合、|PyMuPDF Pro| のインポートを追加してロックを解除するだけです::\"\n\n#: ../../pymupdf-layout/index.rst:116 695ebd9778304b3da362108ea2e9695e\nmsgid \"Now we can happily load Office files and convert them as follows::\"\nmsgstr \"これで、次のように Office ファイルを読み込んで変換できます::\"\n\n#: ../../pymupdf-layout/index.rst:122 14fdcdcd4aab4335919c50efc4749185\nmsgid \"OCR support\"\nmsgstr \"OCR サポート\"\n\n#: ../../pymupdf-layout/index.rst:124 99eb4f65329d45c7bb6eaf035c255259\nmsgid \"\"\n\"The new layout-sensitive |PyMuPDF4LLM| version also evaluates whether a \"\n\"page would benefit from applying OCR to it. If its heuristics come to \"\n\"this conclusion, the built-in Tesseract-OCR module is automatically \"\n\"invoked. Its results are then handled like normal page content.\"\nmsgstr \"新しいレイアウト対応の  |PyMuPDF4LLM|  バージョンは、ページに OCR を適用することが有益かどうかも評価します。ヒューリスティックがこの結論に達した場合、組み込みの  **Tesseract-OCR**  モジュールが自動的に呼び出されます。その結果は、通常のページコンテンツと同様に処理されます。\"\n\n#: ../../pymupdf-layout/index.rst:126 cdbf9a9f1f5341cc96aaaa1a6a74434f\nmsgid \"\"\n\"If a page contains (roughly) no text at all, but is covered with images \"\n\"or many character-sized vectors, a check is made using `OpenCV \"\n\"<https://pypi.org/project/opencv-python/>`_ whether text is *probably* \"\n\"detectable on the page at all. This is done to tell apart image-based \"\n\"text from ordinary pictures (like photographs).\"\nmsgstr \"ページにテキストがほとんど含まれていないが、画像や多数の文字サイズのベクターで覆われている場合、`OpenCV <https://pypi.org/project/opencv-python/>`_ を使用して、ページ上でテキストが検出可能かどうかをチェックします。これは、画像ベースのテキストを通常の写真などの画像と区別するために行われます。\"\n\n#: ../../pymupdf-layout/index.rst:128 8c8ba1c1b2bc4875b04cc60b98293a08\nmsgid \"\"\n\"If the page does contain text but too many characters are unreadable \"\n\"(like \\\"�����\\\"), OCR is also executed, but **for the affected text areas\"\n\" only** -- not the full page. This way, we avoid losing already existing \"\n\"text and other content like images and vectors.\"\nmsgstr \"ページにテキストが含まれているものの、読み取り不可能な文字（「�����」など）が多すぎる場合、OCR も実行されますが、影響を受けるテキスト領域のみが対象となり、ページ全体ではありません。これにより、既存のテキストや画像やベクターなどの他のコンテンツが失われるのを防ぎます。\"\n\n#: ../../pymupdf-layout/index.rst:130 225a390ebce94321a090f94ab2165c16\nmsgid \"\"\n\"For these heuristics to work we need both, an existing :ref:`Tesseract installation <installation_ocr>` and the availability of `OpenCV <https://pypi.org/project/opencv-python/>`_ in the Python environment. If\"\n\" either is missing, no OCR is attempted at all.\"\nmsgstr \"これらのヒューリスティックが機能するには、 :ref:`Tesseract installation <installation_ocr>` のインストールと Python 環境での `OpenCV <https://pypi.org/project/opencv-python/>`_ の利用可能性の両方が必要です。どちらか一方が欠けている場合、OCR はまったく試行されません。\"\n\nmsgid \"The decision tree for whether OCR is actually used or not depends on the following:\"\nmsgstr \"OCRが実際に使用されるかどうかの決定木は、以下に依存します\"\n\nmsgid \":ref:`PyMuPDF Layout is imported <pymupdf_layout_using>`\"\nmsgstr \"PyMuPDF Layoutがインポートされている\"\n\nmsgid \"In the :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` you have `use_ocr` enabled (this is set to `True` by default)\"\nmsgstr \":ref:`PyMuPDF4LLM API <pymupdf4llm-api>` で ``use_ocr`` が有効になっている（これはデフォルトで ``True`` に設定されています）\"\n\nmsgid \":ref:`Tesseract is correctly installed <installation_ocr>`\"\nmsgstr \":ref:`Tesseractが正しくインストールされている <installation_ocr>`\"\n\nmsgid \"`OpenCV <https://pypi.org/project/opencv-python/>`_ is available in your Python environment\"\nmsgstr \"`OpenCV <https://pypi.org/project/opencv-python/>`_ がPython環境で利用可能である\"\n\n#: ../../pymupdf-layout/index.rst:137 fddcc1ea96e64c658554704bb141490b\nmsgid \"|PyMuPDF Layout| and |PyMuPDF4LLM| parameter caveats\"\nmsgstr \"|PyMuPDF Layout| と |PyMuPDF4LLM| のパラメータに関する注意事項\"\n\n#: ../../pymupdf-layout/index.rst:139 b7f33df2c3974ea1bbead613286f3639\nmsgid \"\"\n\"If you have imported ``pymupdf.layout``, |PyMuPDF4LLM| changes its \"\n\"behavior in various areas quite significantly. New methods become \"\n\"available and also some features are no longer supported. Please visit \"\n\"`this site <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ for\"\n\" a detailed description of the changes. That web site is being kept up to\"\n\" date while we continue to work on improvements.\"\nmsgstr \"``pymupdf.layout`` をインポートした場合、|PyMuPDF4LLM| はさまざまな領域でその動作を大幅に変更します。新しいメソッドが利用可能になり、一部の機能はサポートされなくなります。変更の詳細については、`このサイト <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ を参照してください。このウェブサイトは、改善作業を続けながら最新の状態に保たれています。\"\n\n#: ../../footer.rst:46 fcc43bbf382644f6928a40bc9aea37c1\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/pymupdf-pro/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ff337a9fa03e4fd6a3d7aaec4930912f\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 b9e1a76b005b46c7a35e27ac36b668dd\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 5b66ad60d8974f3fb8061286f4b23214\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:8 07624f1e03dd463c99bf82f95b91a35e\nmsgid \"PyMuPDF Pro\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:11 879666c817c94726a9df9e5880d5425a\nmsgid \"|PyMuPDF Pro| is a set of *commercial extensions* for |PyMuPDF|.\"\nmsgstr \"|PyMuPDF Pro| は、|PyMuPDF| 用の *商用拡張機能* セットです。\"\n\n#: ../../pymupdf-pro/index.rst:13 ae90e3fd121f4e04a0a9ecd747514717\nmsgid \"\"\n\"Enhance |PyMuPDF| capability with **Office** document support & \"\n\"**RAG/LLM** integrations.\"\nmsgstr \"**Office** ドキュメントサポートと **RAG/LLM** 統合で |PyMuPDF| の機能を強化します。\"\n\n#: ../../pymupdf-pro/index.rst:15 aed2c2f793d348d8bf6eb0811eecb47a\nmsgid \"\"\n\"Enables Office document handling, including ``doc``, ``docx``, ``hwp``, \"\n\"``hwpx``, ``ppt``, ``pptx``, ``xls``, ``xlsx``, and others.\"\nmsgstr \"``doc``、``docx``、``hwp``、``hwpx``、``ppt``、``pptx``、``xls``、``xlsx`` などの Office ドキュメント処理を可能にします。\"\n\n#: ../../pymupdf-pro/index.rst:16 997a064abea1408d914a30cae0872289\nmsgid \"Supports text and table extraction, document conversion and more.\"\nmsgstr \"テキストと表の抽出、ドキュメント変換などをサポートします。\"\n\n#: ../../pymupdf-pro/index.rst:17 7ee872ab1d5c4992b77ebbf8c3cf149c\nmsgid \"Includes the commercial version of |PyMuPDF4LLM|.\"\nmsgstr \"PyMuPDF4LLM の商用バージョンが含まれています。\"\n\n#: ../../pymupdf-pro/index.rst:19 83cc2a9a8a854516b90d26d2841aad02\nmsgid \"\"\n\"To enquire about obtaining a commercial license, then `use this contact \"\n\"page <https://artifex.com/contact/>`_.\"\nmsgstr \"商用ライセンスの取得についてお問い合わせの場合は、`こちらのお問い合わせページをご利用ください <https://artifex.com/contact/>`_。\"\n\n#: ../../pymupdf-pro/index.rst:24 f0a9c51213864c898871ca01453557e1\nmsgid \"\"\n\"A licensed version of |PyMuPDF Pro| also gives you a licensed version of \"\n\"|PyMuPDF4LLM|. If you are interested in using the |PyMuPDF4LLM| package \"\n\"you should install it separately.\"\nmsgstr \"|PyMuPDF Pro| のライセンス版には、|PyMuPDF4LLM| のライセンス版も含まれています。|PyMuPDF4LLM| パッケージの使用に興味がある場合は、個別にインストールする必要があります。\"\n\n#: ../../pymupdf-pro/index.rst:28 4a1d503fea744f4ba62d54e186f02d87\nmsgid \"Platform support\"\nmsgstr \"プラットフォームサポート\"\n\n#: ../../pymupdf-pro/index.rst:30 78076f4c0458474f913d726a0fb0e0bc\nmsgid \"Available for these platforms only:\"\nmsgstr \"以下のプラットフォームでのみ利用可能\"\n\n#: ../../pymupdf-pro/index.rst:32 ed38f46c156840689524033bf7da829d\nmsgid \"Windows x86_64.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:33 259897daea654cb8a90bc8e65c6e4f76\nmsgid \"Linux x86_64 (glibc).\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:34 1923df7caa0b4f04a3b259b4c866ba6e\nmsgid \"MacOS x86_64.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:35 fd5d8bf6fc12467a826ce8202a1d2ec3\nmsgid \"MacOS arm64.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:39 f2952d3e2f47435bb640b83bd15721c4\nmsgid \"Office file support\"\nmsgstr \"Office ファイルサポート\"\n\n#: ../../pymupdf-pro/index.rst:41 7c38d85a3c164f3a90d869b52ef96eb1\nmsgid \"\"\n\"In addition to the `standard file types supported by PyMuPDF \"\n\"<Supported_File_Types>`, |PyMuPDF Pro| supports:\"\nmsgstr \"`PyMuPDF がサポートする標準ファイルタイプ <Supported_File_Types>` に加えて、|PyMuPDF Pro| は以下をサポートします\"\n\n#: ../../pymupdf-pro/index.rst:46 67438064f36f474186aeb4fbfb093d31\nmsgid \"**DOC/DOCX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:47 9ab995c3f8214b9ab04698d96a84b4e2\nmsgid \"**XLS/XLSX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:48 9e2c997d6ac44df79efb09f56a593cbb\nmsgid \"**PPT/PPTX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:49 28e3c375094f40258eea347ffcaf5a8f\nmsgid \"**HWP/HWPX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro/index.rst:66 9ccca49db9fb4df98d9464183c30d68c\nmsgid \"Usage\"\nmsgstr \"使用方法\"\n\n#: ../../pymupdf-pro/index.rst:69 edd61111e81a46198c9ef49a53e782b0\nmsgid \"Installation\"\nmsgstr \"インストール\"\n\n#: ../../pymupdf-pro/index.rst:71 f961577e8ffd49469227db2bbdcd9bb2\nmsgid \"Install via pip with:\"\nmsgstr \"pip でインストールするには\"\n\n#: ../../pymupdf-pro/index.rst:79 699e6bf8334b4cf8b23793ff0e45ccbf\nmsgid \"Loading an **Office** document\"\nmsgstr \"**Office** ドキュメントを読み込む\"\n\n#: ../../pymupdf-pro/index.rst:81 08e39b8bfc514665aafb5c1aa211bcfc\nmsgid \"\"\n\"Import |PyMuPDF Pro| and you can then reference **Office** documents \"\n\"directly, e.g.:\"\nmsgstr \"|PyMuPDF Pro| をインポートすると、**Office** ドキュメントを直接参照できます。例えば:\"\n\n#: ../../pymupdf-pro/index.rst:92 e21e201731344245a88c7e6bdd9c2dc2\nmsgid \"\"\n\"All standard |PyMuPDF| functionality is exposed as expected - |PyMuPDF \"\n\"Pro| handles the extended **Office** file types\"\nmsgstr \"すべての標準 |PyMuPDF| 機能が期待どおりに公開されます - |PyMuPDF Pro| は拡張された **Office** ファイルタイプを処理します\"\n\n#: ../../pymupdf-pro/index.rst:95 32d84f02e19a40b5bb42c1d26a81afe5\nmsgid \"\"\n\"From then on you can work with document pages just as you would do \"\n\"normally, but with respect to the `restrictions \"\n\"<PyMuPDFPro_Restrictions>`.\"\nmsgstr \"その後は、`制限事項 <PyMuPDFPro_Restrictions>` を考慮しながら、通常どおりドキュメントページを操作できます。\"\n\n#: ../../pymupdf-pro/index.rst:99 36c298b59008468ab926c22842511b25\nmsgid \"Converting an **Office** document to |PDF|\"\nmsgstr \"**Office** ドキュメントを |PDF| に変換する\"\n\n#: ../../pymupdf-pro/index.rst:101 c01333a0e65f42d29d469ace26b3fd91\nmsgid \"\"\n\"The following code snippet can convert your **Office** document to |PDF| \"\n\"format:\"\nmsgstr \"次のコードスニペットは、**Office** ドキュメントを |PDF| 形式に変換できます:\"\n\n#: ../../pymupdf-pro/index.rst:119 cd5eb6eaf8094ced89572a48282454ca\nmsgid \"Restrictions\"\nmsgstr \"制限事項\"\n\n#: ../../pymupdf-pro/index.rst:122 badbfba0a2a0495290e9594585aaefc9\nmsgid \"\"\n\"|PyMuPDF Pro| functionality is restricted without a license key as \"\n\"follows:\"\nmsgstr \"|PyMuPDF Pro| 機能は、ライセンスキーがない場合、次のように制限されます:\"\n\n#: ../../pymupdf-pro/index.rst:124 0edbc072da504add956116e21d3eebde\nmsgid \"**Only the first 3 pages of any document will be available.**\"\nmsgstr \"どのドキュメントでも最初の3ページのみが利用可能です。\"\n\n#: ../../pymupdf-pro/index.rst:126 6fa9f0d4dec94b3db782dacdc632f5a0\nmsgid \"\"\n\"To unlock full functionality you should `obtain a trial key \"\n\"<https://pymupdf.pro/try-pro/>`_.\"\nmsgstr \"すべての機能のロックを解除するには、`トライアルキーを取得 <https://pymupdf.pro/try-pro/>`_ してください。\"\n\n#: ../../pymupdf-pro/index.rst:132 ff0d00debbdb4746809d8750352f10bc\nmsgid \"Trial keys\"\nmsgstr \"トライアルキー\"\n\n#: ../../pymupdf-pro/index.rst:134 e689628360fa4b4497ccbb720dd0faca\nmsgid \"\"\n\"To obtain a license key `please fill out the form on this page \"\n\"<https://pymupdf.pro/try-pro/>`_. You will then have the trial key \"\n\"emailled to the address you submitted.\"\nmsgstr \"ライセンスキーを取得するには、`このページのフォームに記入 <https://pymupdf.pro/try-pro/>`_ してください。提出したアドレスにトライアルキーがメールで送信されます。\"\n\n#: ../../pymupdf-pro/index.rst:138 b4af428798424c3baae4771829727b28\nmsgid \"Using a key\"\nmsgstr \"キーの使用\"\n\n#: ../../pymupdf-pro/index.rst:141 6766aa2a1d144b81a15c3ad28ce403da\nmsgid \"Initialize |PyMuPDF Pro| with a key as follows:\"\nmsgstr \"次のようにキーで |PyMuPDF Pro| を初期化します\"\n\n#: ../../pymupdf-pro/index.rst:149 92e495f1e7934e1e83d346f56ab9833d\nmsgid \"\"\n\"This will allow you to evaluate the product for a limited time. If you \"\n\"want to use |PyMuPDF Pro| after this time you should then `enquire about \"\n\"obtaining a commercial license <https://artifex.com/products/pymupdf-\"\n\"pro/>`_.\"\nmsgstr \"これにより、限られた期間製品を評価できます。この期間後も |PyMuPDF Pro| を使用したい場合は、`商用ライセンスの取得についてお問い合わせ <https://artifex.com/products/pymupdf-pro/>`_ ください。\"\n\n#: ../../pymupdf-pro/index.rst:153 a394162132a04de092aabb5d2fcbc814\nmsgid \"Fonts\"\nmsgstr \"フォント\"\n\n#: ../../pymupdf-pro/index.rst:155 8e2db8a260ac4b8597a804b55d7ab547\nmsgid \"\"\n\"By default `pymupdf.pro.unlock()` searches for all installed font \"\n\"directories.\"\nmsgstr \"デフォルトでは、`pymupdf.pro.unlock()` はインストールされているすべてのフォントディレクトリを検索します。\"\n\n#: ../../pymupdf-pro/index.rst:157 e0cd7217fd79445ea7e79586abad31d1\nmsgid \"This can be controlled with keyword-only args:\"\nmsgstr \"これは、キーワード専用引数で制御できます:\"\n\n#: ../../pymupdf-pro/index.rst:159 879866813ec14fd08f5b249e833e7ee7\nmsgid \"\"\n\"`fontpath`: specific font directories, either as a list/tuple or \"\n\"`os.sep`-separated string. If None (the default), we use \"\n\"`os.environ['PYMUPDFPRO_FONT_PATH']` if set.\"\nmsgstr \"`fontpath`: 特定のフォントディレクトリ。リスト/タプルまたは `os.sep` で区切られた文字列として指定します。None（デフォルト）の場合、設定されていれば `os.environ['PYMUPDFPRO_FONT_PATH']` を使用します。\"\n\n#: ../../pymupdf-pro/index.rst:161 5ca9e3934e6c4c91b603c12662c79cf6\nmsgid \"\"\n\"`fontpath_auto`: Whether to append system font directories. If None (the \"\n\"default) we use true if `os.environ['PYMUPDFPRO_FONT_PATH_AUTO']` is '1'.\"\n\" If true we append all system font directories.\"\nmsgstr \"`fontpath_auto`: システムフォントディレクトリを追加するかどうか。None（デフォルト）の場合、`os.environ['PYMUPDFPRO_FONT_PATH_AUTO']` が '1' であれば true を使用します。true の場合、すべてのシステムフォントディレクトリを追加します。\"\n\n#: ../../pymupdf-pro/index.rst:165 5ecf267b5f8f4e68be5f69f1cbee4782\nmsgid \"\"\n\"Function `pymupdf.pro.get_fontpath()` returns a tuple of all font \"\n\"directories used by `unlock()`.\"\nmsgstr \"関数 `pymupdf.pro.get_fontpath()` は、`unlock()` で使用されるすべてのフォントディレクトリのタプルを返します。\"\n\n#: ../../footer.rst:46 b26519c017c744e3b52c222b2633f6ed\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/pymupdf-pro.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.10\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 0dfe01c73aa0450484e10fe2c161a22f\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 b4ed4e93bf294eb098966f465bc797c5\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 ec46200e47134602a82ee60a1118c156\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:9 26812dee4da947c7918d490500c2067c\nmsgid \"PyMuPDF Pro\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:12 aa17b9e367774bb89e40e6d34d5ec0fe\nmsgid \"|PyMuPDF Pro| is a set of *commercial extensions* for |PyMuPDF|.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:14 11f22babd0e94a46b70d2de6efd179bc\nmsgid \"\"\n\"Enhance |PyMuPDF| capability with **Office** document support & \"\n\"**RAG/LLM** integrations.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:16 38e3e965f4184ecc965744d00c2568d5\nmsgid \"\"\n\"Enables Office document handling, including ``doc``, ``docx``, ``hwp``, \"\n\"``hwpx``, ``ppt``, ``pptx``, ``xls``, ``xlsx``, and others.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:17 0a12a5f74ed941a9be6cef8798aa2cbd\nmsgid \"Supports text and table extraction, document conversion and more.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:18 49a700600f224867985cf301867199d8\nmsgid \"Includes the commercial version of |PyMuPDF4LLM|.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:20 9450c9107df04fe5bc38e0324bf54c01\nmsgid \"\"\n\"To enquire about obtaining a commercial license, then `use this contact \"\n\"page <https://artifex.com/contact/>`_.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:25 1321bc95b45541b48337e44f78b58020\nmsgid \"\"\n\"A licensed version of |PyMuPDF Pro| also gives you a licensed version of \"\n\"|PyMuPDF4LLM|. If you are interested in using the |PyMuPDF4LLM| package \"\n\"you should install it separately.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:29 f655cf9fdd1f48dd9e890f8c5aef653f\nmsgid \"Platform support\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:31 367befe5f1a34b7fb9665758548f6448\nmsgid \"Available for these platforms only:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:33 a256db349f5242a38297eda82fd9ee71\nmsgid \"Windows x86_64.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:34 9e2ffb09f61f430f9594a418d1ee8ab0\nmsgid \"Linux x86_64 (glibc).\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:35 97423a8756fc40408f80993fce6a1fc6\nmsgid \"MacOS x86_64.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:36 1a59aca2bbc44194b2dde06a89fac54f\nmsgid \"MacOS arm64.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:40 0abf65ed31ca4a949b4b81e0bb521522\nmsgid \"Office file support\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:42 b8f3023035f74b3dacbf2e3210f2c12f\nmsgid \"\"\n\"In addition to the `standard file types supported by PyMuPDF \"\n\"<Supported_File_Types>`, |PyMuPDF Pro| supports:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:47 45349c74355f48c0abf3ae8f486843a6\nmsgid \"**DOC/DOCX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:48 777b729313244ad298c7b6d5bb49c369\nmsgid \"**XLS/XLSX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:49 371c1c089e4c475caf8acc946169b878\nmsgid \"**PPT/PPTX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:50 d6ec7208ebdc4049815db59e7ec6641e\nmsgid \"**HWP/HWPX**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:67 097b80f124fa49fd92bab9375f53b975\nmsgid \"Usage\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:70 f5c7cbdc4f62456199de7159bd404d58\nmsgid \"Installation\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:72 dabefb8cfac54dabb7e1859dbc4578ed\nmsgid \"Install via pip with:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:80 47d8f70087754faa8e60ff7f7e0d1b2a\nmsgid \"Loading an **Office** document\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:82 f5cf1df845294870b35e718fadf85b1f\nmsgid \"\"\n\"Import |PyMuPDF Pro| and you can then reference **Office** documents \"\n\"directly, e.g.:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:93 470f5d9c683947b2b97f3e90e42f8a5d\nmsgid \"\"\n\"All standard |PyMuPDF| functionality is exposed as expected - |PyMuPDF \"\n\"Pro| handles the extended **Office** file types\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:96 72c50a703f314197b00a1d336392d8dc\nmsgid \"\"\n\"From then on you can work with document pages just as you would do \"\n\"normally, but with respect to the `restrictions \"\n\"<PyMuPDFPro_Restrictions>`.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:100 5b447b0138f849efa8d4cb7a1cfd910b\nmsgid \"Converting an **Office** document to |PDF|\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:102 b8e5b07700944b9da32ae37ca9175e00\nmsgid \"\"\n\"The following code snippet can convert your **Office** document to |PDF| \"\n\"format:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:120 26c5a530a9a54f56bc28027850958f25\nmsgid \"Restrictions\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:123 2391a063f21c4de092b0beca7b94377e\nmsgid \"\"\n\"|PyMuPDF Pro| functionality is restricted without a license key as \"\n\"follows:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:125 1e6b67342d31405ab0f72646252650df\nmsgid \"**Only the first 3 pages of any document will be available.**\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:127 c176b676614c4507959f495c339a3e71\nmsgid \"\"\n\"To unlock full functionality you should `obtain a trial key \"\n\"<https://pymupdf.io/try-pro/>`_.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:133 9a01dcbd3af143b6bad7400a98e6b69d\nmsgid \"Trial keys\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:135 89e312aa37bd4b749727cd14913e2e70\nmsgid \"\"\n\"To obtain a license key `please fill out the form on this page \"\n\"<https://pymupdf.io/try-pro/>`_. You will then have the trial key \"\n\"emailled to the address you submitted.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:139 371fa0ea70f44d9e8e6e9155a631426f\nmsgid \"Using a key\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:142 25f50e294ef5429e86781bea1e1b1e29\nmsgid \"Initialize |PyMuPDF Pro| with a key as follows:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:150 b01044f9b9f34927892044fa1c007b7f\nmsgid \"\"\n\"This will allow you to evaluate the product for a limited time. If you \"\n\"want to use |PyMuPDF Pro| after this time you should then `enquire about \"\n\"obtaining a commercial license <https://artifex.com/products/pymupdf-\"\n\"pro/>`_.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:154 fcfee54b997f4b5a8368464ac33e8568\nmsgid \"Fonts\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:156 c22971d466c14a31aeb4f6e851c88144\nmsgid \"\"\n\"By default `pymupdf.pro.unlock()` searches for all installed font \"\n\"directories.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:158 c388a7575cdf4d709d86899170008a23\nmsgid \"This can be controlled with keyword-only args:\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:160 9c1f44585d134e12bb9b74ce4a83121b\nmsgid \"\"\n\"`fontpath`: specific font directories, either as a list/tuple or \"\n\"`os.sep`-separated string. If None (the default), we use \"\n\"`os.environ['PYMUPDFPRO_FONT_PATH']` if set.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:162 ae8654a3d7f14d329aa5caf0f2ccde78\nmsgid \"\"\n\"`fontpath_auto`: Whether to append system font directories. If None (the \"\n\"default) we use true if `os.environ['PYMUPDFPRO_FONT_PATH_AUTO']` is '1'.\"\n\" If true we append all system font directories.\"\nmsgstr \"\"\n\n#: ../../pymupdf-pro.rst:166 28aa600bf1164c318f946da4d23619db\nmsgid \"\"\n\"Function `pymupdf.pro.get_fontpath()` returns a tuple of all font \"\n\"directories used by `unlock()`.\"\nmsgstr \"\"\n\n#: ../../footer.rst:60 fdcd80e27b7c41f882a85b921e2ee500\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"\"\n\n#~ msgid \"Enhance |PyMuPDF| capability with **Office** document support.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"|PyMuPDF Pro| offers all the features\"\n#~ \" of |PyMuPDF|, plus enhanced functionality\"\n#~ \" to support **Office** documents.\"\n#~ msgstr \"\"\n\n#~ msgid \"Load, parse and extract text data from **Office** files\"\n#~ msgstr \"\"\n\n#~ msgid \"Ablility to render **Office** files\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/pymupdf4llm/api.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.10\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-26 17:04+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 82786ea5867f4818b6c5c7b3e8a55ef0\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 1a6aac6ec3e34205b07c2f37fdc69e13\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 ab4f1a2eeccd4098ae98718eac840f2e\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/api.rst:9 4e5664b1124d48d18fd12e59b727a0bd\nmsgid \"API\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/api.rst:12 e4fe663d1ee04cf7bbc808eeb9ce308b\nmsgid \"The |PyMuPDF4LLM| API\"\nmsgstr \"|PyMuPDF4LLM| API\"\n\n#: ../../footer.rst:46 1ed68f4bf8fd45fab04f7a49fba09f0a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\nmsgid \"Prints the version of the library.\"\nmsgstr \"ライブラリのバージョンを出力します。\"\n\nmsgid \"Reads the pages of the file and outputs the text of its pages in |Markdown| format. How this should happen in detail can be influenced by a number of parameters. Please note that **support for building page chunks** from the |Markdown| text is supported.\"\nmsgstr \"ファイルのページを読み取り、各ページのテキストを |Markdown| 形式で出力します。詳細な動作は複数のパラメータで制御できます。 |Markdown| テキストからページチャンクを構築する機能がサポートされていることにご注意ください。\"\n\nmsgid \"the file, to be specified either as a file path string, or as a |PyMuPDF| :class:`Document` (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| :class:`Document`.\"\nmsgstr \"ファイルは、ファイルパス文字列、または |PyMuPDF| :class:`Document` (``pymupdf.open`` で作成) のいずれかで指定します。``pathlib.Path`` 指定、Pythonファイル風オブジェクト、メモリ内ドキュメントなどを使用する場合は、|PyMuPDF| :class:`Document` を **必ず** 使用してください。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| does a simple check for the general background color of the pages (default is ``True``). If any text or vector has this color it will be ignored. May increase detection accuracy.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| ページの全体的な背景色を簡易的にチェックします（デフォルトは ``True``）。テキストやベクターがこの色の場合、無視されます。検出精度が向上する可能性があります。\"\n\nmsgid \"specify the desired image resolution in dots per inch. Relevant only if `write_images=True` or `embed_images=True`. Default value is 150.\"\nmsgstr \"希望する画像解像度をドット・パー・インチ（DPI）で指定します。``write_images=True`` または ``embed_images=True`` の場合のみ有効です。デフォルト値は150です。\"\n\nmsgid \"|PyMuPDFLayoutMode_Valid| use :ref:`OCR capability <pymupdf_layout_ocr_support>` to help analyse the page.\"\nmsgstr \"|PyMuPDFLayoutMode_Valid| :ref:`OCR機能 <pymupdf_layout_ocr_support>` を使用してページの分析を支援します。\"\n\nmsgid \"|PyMuPDFLayoutMode_Valid| specify the desired image resolution in dots per inch for applying OCR to the intermediate image of the page. Default value is 400. Only relevant if the page has been determined to profit from OCR (no or few text, most of the page covered by images or character-like vectors, etc.). Large values may increase the OCR precision but increase memory requirements and processing time. There also is a risk of over-sharpening the image which may decrease OCR precision. So the default value should probably be sufficiently high.\"\nmsgstr \"|PyMuPDFLayoutMode_Valid| ページの中間画像にOCRを適用する際の希望する画像解像度をドット・パー・インチ（DPI）で指定します。デフォルト値は400です。ページがOCRの恩恵を受けると判断された場合（テキストが無いまたは少ない、ページの大部分が画像または文字のようなベクターで覆われているなど）のみ有効です。大きな値を指定するとOCRの精度が向上する可能性がありますが、メモリ要件と処理時間が増加します。また、画像が過度にシャープ化されてOCRの精度が低下するリスクもあります。そのため、デフォルト値はおそらく十分に高い値となっています。\"\n\nmsgid \"like `write_images`, but images will be included in the markdown text as base64-encoded strings. Mutually exclusive with `write_images` and ignores `image_path`. This may drastically increase the size of your markdown text.\"\nmsgstr \"``write_images`` と同様ですが、画像はbase64エンコードされた文字列としてマークダウンテキストに含まれます。``write_images`` とは相互排他的であり、``image_path`` は無視されます。これによりマークダウンテキストのサイズが大幅に増加する可能性があります。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| a value of `True` enforces `page_chunks=True` and adds key \"words\" to each page dictionary. Its value is a list of words as delivered by PyMuPDF's `Page` method `get_text(\"words\")`. The sequence of the words in this list is the same as the extracted text.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| ``True`` を指定すると ``page_chunks=True`` が強制され、各ページの辞書にキー「words」が追加されます。その値は、PyMuPDFの ``Page`` メソッド ``get_text(\"words\")`` によって提供される単語のリストです。このリスト内の単語の順序は、抽出されたテキストと同じです。**「レイアウトモード」では無視されます。**\"\n\nmsgid \"Overwrites or sets the desired image file name of written images. Useful when the document is provided as a memory object (which has no inherent file name).\"\nmsgstr \"書き込まれる画像の希望するファイル名を上書きまたは設定します。ドキュメントがメモリオブジェクト（固有のファイル名を持たない）として提供される場合に便利です。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| limit the font size to consider for text extraction. If the font size is lower than what is set then the text won't be considered for extraction. Default is `3`, meaning only text with a font size `>= 3` will be considered for extraction.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| テキスト抽出時に考慮するフォントサイズの下限を設定します。フォントサイズが設定値より小さい場合、そのテキストは抽出対象として考慮されません。デフォルトは ``3`` で、フォントサイズが ``>= 3`` のテキストのみが抽出対象として考慮されます。\"\n\nmsgid \"|PyMuPDFLayoutMode_Valid| boolean to switch on/off page footer content. This parameter controls whether to include or omit footer text from all the document pages. Useful if the document has repetitive footer content which doesn't add any value to the overall extraction data. Default is `True` meaning that footer content will be considered.\"\nmsgstr \"|PyMuPDFLayoutMode_Valid| ページフッターの内容を含めるか除外するかを切り替えるブール値です。このパラメータは、ドキュメント全ページのフッターテキストを含めるか省略するかを制御します。ドキュメントに繰り返しのフッター内容があり、全体的な抽出データに価値を追加しない場合に便利です。デフォルトは ``True`` で、フッターの内容が考慮されることを意味します。\"\n\nmsgid \"generate text output even when overlapping images / graphics. This text then appears after the respective image.\"\nmsgstr \"画像やグラフィックが重なっている場合でもテキスト出力を生成します。このテキストは該当する画像の後に表示されます。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| use this to limit dealing with excess amounts of vector graphics elements. Scientific documents, or pages simulating text via graphics commands may contain tens of thousands of these objects. As vector graphics are analyzed for multiple purposes, runtime may quickly become intolerable. With this parameter, all vector graphics will be ignored if their count exceeds the threshold.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| 過剰な量のベクターグラフィック要素への対処を制限するために使用します。科学文書や、グラフィックコマンドでテキストをシミュレートするページには、これらのオブジェクトが数万個含まれている場合があります。ベクターグラフィックは複数の目的で分析されるため、実行時間がすぐに許容できないレベルになる可能性があります。このパラメータを使用すると、ベクターグラフィックの数が閾値を超えた場合、すべてのベクターグラフィックが無視されます。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| use this if you want to provide your own header detection logic. This may be a callable or an object having a method named `get_header_id`. It must accept a text span (a span dictionary as contained in :meth:`~.extractDICT`) and a keyword parameter \"page\" (which is the owning :ref:`Page <page>` object). It must return a string \"\" or up to 6 \"#\" characters followed by 1 space. If omitted (`None`), a full document scan will be performed to find the most popular font sizes and derive header levels based on them. To completely avoid this behavior specify `hdr_info=lambda s, page=None: \"\"` or `hdr_info=False`.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| 独自のヘッダー検出ロジックを提供したい場合に使用します。これは、呼び出し可能オブジェクト、または ``get_header_id`` という名前のメソッドを持つオブジェクトです。テキストスパン（:meth:`~.extractDICT` に含まれるスパン辞書）とキーワードパラメータ「page」（所有する :ref:`Page <page>` オブジェクト）を受け入れる必要があります。空文字列 \"\" または最大6個の \"#\" 文字とその後に続く1つのスペースを返す必要があります。省略した場合（``None``）、ドキュメント全体がスキャンされ、最も一般的なフォントサイズを見つけ、それに基づいてヘッダーレベルが導出されます。この動作を完全に回避するには、``hdr_info=lambda s, page=None: \"\"`` または ``hdr_info=False`` を指定してください。\"\n\nmsgid \"|PyMuPDFLayoutMode_Valid| boolean to switch on/off page header content. This parameter controls whether we want to include or omit the header content from all the document pages. Useful if the document has repetitive header content which doesn't add any value to the overall extraction data. Default is `True` meaning that header content will be considered.\"\nmsgstr \"|PyMuPDFLayoutMode_Valid| ページヘッダーの内容を含めるか除外するかを切り替えるブール値です。このパラメータは、ドキュメント全ページのヘッダー内容を含めるか省略するかを制御します。ドキュメントに繰り返しのヘッダー内容があり、全体的な抽出データに価値を追加しない場合に便利です。デフォルトは ``True`` で、ヘッダーの内容が考慮されることを意味します。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| if ``True`` includes text even when completely transparent. Default is ``False``: transparent text will be ignored which usually increases detection accuracy.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| ``True`` の場合、完全に透明なテキストも含めます。デフォルトは ``False`` で、透明なテキストは無視され、通常は検出精度が向上します。**「レイアウトモード」では無視されます。**\"\n\nmsgid \"if `True` then mono-spaced text lines do not receive special formatting. Code blocks will no longer be generated. This value is set to `True` if `extract_words=True` is used.\"\nmsgstr \"``True`` の場合、等幅テキスト行は特別なフォーマットを受けません。コードブロックは生成されなくなります。``extract_words=True`` が使用される場合、この値は ``True`` に設定されます。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| (New in v.0.0.20) Disregard vector graphics on the page. This may help detecting text correctly when pages are very crowded (often the case for documents representing presentation slides). Also speeds up processing time. This automatically prevents table detection.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| (v.0.0.20の新機能) ページ上のベクターグラフィックを無視します。ページが非常に混雑している場合（プレゼンテーションスライドを表すドキュメントでよくあるケース）、テキストを正しく検出するのに役立つ可能性があります。また、処理時間も短縮されます。これにより、テーブル検出が自動的に無効になります。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| (New in v.0.0.20) Disregard images on the page. This may help detecting text correctly when pages are very crowded (often the case for documents representing presentation slides). Also speeds up processing time.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| (v.0.0.20の新機能) ページ上の画像を無視します。ページが非常に混雑している場合（プレゼンテーションスライドを表すドキュメントでよくあるケース）、テキストを正しく検出するのに役立つ可能性があります。また、処理時間も短縮されます。\"\n\nmsgid \"specify the desired image format via its extension. Default is \"png\" (portable network graphics). Another popular format may be \"jpg\". Possible values are all :ref:`supported output formats <Supported_File_Types>`.\"\nmsgstr \"拡張子を使用して希望する画像形式を指定します。デフォルトは「png」（ポータブルネットワークグラフィックス）です。他の一般的な形式としては「jpg」があります。使用可能な値は、すべての :ref:`サポートされている出力形式 <Supported_File_Types>` です。\"\n\nmsgid \"store images in this folder. Relevant if `write_images=True`. Default is the path of the script directory.\"\nmsgstr \"このフォルダに画像を保存します。``write_images=True`` の場合に有効です。デフォルトはスクリプトディレクトリのパスです。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| this must be a ``0 <= value < 1``. Images are ignored if `width / page.rect.width <= image_size_limit` or `height / page.rect.height <= image_size_limit`. For instance, the default value 0.05 means that to be considered for inclusion, an image's width and height must be larger than 5% of the page's width and height, respectively.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| ``0 <= value < 1`` の値である必要があります。``width / page.rect.width <= image_size_limit`` または ``height / page.rect.height <= image_size_limit`` の場合、画像は無視されます。たとえば、デフォルト値の0.05は、画像が含まれる対象として考慮されるには、画像の幅と高さがそれぞれページの幅と高さの5%より大きくなければならないことを意味します。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| a float or a sequence of 2 or 4 floats specifying page borders. Only objects inside the margins will be considered for output.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| ページの境界を指定する浮動小数点数、または2個もしくは4個の浮動小数点数のシーケンスです。マージン内のオブジェクトのみが出力対象として考慮されます。\"\n\nmsgid \"`margin=f` yields `(f, f, f, f)` for `(left, top, right, bottom)`.\"\nmsgstr \"``margin=f`` は ``(left, top, right, bottom)`` に対して ``(f, f, f, f)`` を生成します。\"\n\nmsgid \"`(top, bottom)` yields  `(0, top, 0, bottom)`.\"\nmsgstr \"``(top, bottom)`` は ``(0, top, 0, bottom)`` を生成します。\"\n\nmsgid \"To always read full pages **(default)**, use `margins=0`.\"\nmsgstr \"常にページ全体を読み取る **(デフォルト)** には、``margins=0`` を使用します。\"\n\nmsgid \"if `True` the output will be a list of `Document.page_count` dictionaries (one per page). Each dictionary has the following structure:\"\nmsgstr \"``True`` の場合、出力は ``Document.page_count`` 個の辞書のリスト（ページごとに1つ）になります。各辞書は以下の構造を持ちます:\"\n\nmsgid \"**\\\"metadata\\\"** - a dictionary consisting of the document's metadata :attr:`Document.metadata`, enriched with additional keys **\\\"file_path\\\"** (the file name), **\\\"page_count\\\"** (number of pages in document), and **\\\"page_number\\\"** (1-based page number).\"\nmsgstr \"**\"metadata\"** - ドキュメントのメタデータ :attr:`Document.metadata` から構成される辞書で、追加のキー **\"file_path\"** （ファイル名）、**\"page_count\"** （ドキュメント内のページ数）、および **\"page_number\"** （1ベースのページ番号）で拡張されています。\"\n\nmsgid \"**\\\"toc_items\\\"** - a list of Table of Contents items pointing to this page. Each item of this list has the format `[lvl, title, pagenumber]`, where `lvl` is the hierarchy level, `title` a string and `pagenumber` as a 1-based page number.\"\nmsgstr \"**\"toc_items\"** - このページを指す目次項目のリストです。このリストの各項目は ``[lvl, title, pagenumber]`` の形式を持ち、``lvl`` は階層レベル、``title`` は文字列、``pagenumber`` は1ベースのページ番号です。\"\n\nmsgid \"**\\\"tables\\\"** - a list of tables on this page. Each item is a dictionary with keys \\\"bbox\\\", \\\"row_count\\\" and \\\"col_count\\\". Key \\\"bbox\\\" is a `pymupdf.Rect` in tuple format of the table's position on the page.\"\nmsgstr \"**\"tables\"** - このページ上のテーブルのリストです。各項目は、キー「bbox」、「row_count」、「col_count」を持つ辞書です。キー「bbox」は、ページ上のテーブルの位置を示すタプル形式の ``pymupdf.Rect`` です。\"\n\nmsgid \"**\\\"images\\\"** - |PyMuPDFLayoutMode_EmptyList| a list of images on the page. This a copy of page method :meth:`Page.get_image_info`.\"\nmsgstr \"**\\\"images\\\"** - |PyMuPDFLayoutMode_EmptyList| ページ上の画像のリストです。これは、ページメソッド :meth:`Page.get_image_info` のコピーです。\"\n\nmsgid \"**\\\"graphics\\\"** - |PyMuPDFLayoutMode_EmptyList| a list of vector graphics rectangles on the page. This is a list of boundary boxes of clustered vector graphics as delivered by method :meth:`Page.cluster_drawings`.\"\nmsgstr \"**\\\"graphics\\\"** - |PyMuPDFLayoutMode_EmptyList| ページ上のベクターグラフィック矩形のリストです。これは、メソッド :meth:`Page.cluster_drawings` によって提供されるクラスタ化されたベクターグラフィックのバウンディングボックスのリストです。\"\n\nmsgid \"**\\\"text\\\"** - page content as |Markdown| text.\"\nmsgstr \"**\\\"text\\\"** - |Markdown| テキストとしてのページ内容です。\"\n\nmsgid \"**\\\"words\\\"** - |PyMuPDFLayoutMode_EmptyList| if `extract_words=True` was used. This is a list of tuples `(x0, y0, x1, y1, \\\"wordstring\\\", bno, lno, wno)` as delivered by `page.get_text(\\\"words\\\")`. The **sequence** of these tuples however is the same as produced in the markdown text string and thus honors multi-column text. This is also true for text in tables: words are extracted in the sequence of table row cells.\"\nmsgstr \"**\\\"words\\\"** - |PyMuPDFLayoutMode_EmptyList| ``extract_words=True`` が使用された場合に含まれます。これは、``page.get_text(\"words\")`` によって提供されるタプル ``(x0, y0, x1, y1, \"wordstring\", bno, lno, wno)`` のリストです。ただし、これらのタプルの **順序** はマークダウンテキスト文字列で生成される順序と同じであり、したがってマルチカラムテキストを尊重します。これはテーブル内のテキストにも当てはまります。単語はテーブル行のセルの順序で抽出されます。\"\n\nmsgid \"specify a desired page height. For relevance see the `page_width` parameter. If using the default `None`, the document will appear as one large page with a width of `page_width`. Consequently in this case, no markdown page separators will occur (except the final one), respectively only one page chunk will be returned.\"\nmsgstr \"希望するページの高さを指定します。関連性については ``page_width`` パラメータを参照してください。デフォルトの ``None`` を使用する場合、ドキュメントは ``page_width`` の幅を持つ1つの大きなページとして表示されます。したがって、この場合、マークダウンページ区切り文字は発生せず（最後のものを除く）、それぞれ1つのページチャンクのみが返されます。\"\n\nmsgid \"if ``True`` inserts a string ``--- end of page=n ---`` at the end of each page output. Intended for debugging purposes. The page number is 0-based. The separator string is wrapped with line breaks. Default is ``False``.\"\nmsgstr \"``True`` の場合、各ページ出力の最後に文字列 ``--- end of page=n ---`` を挿入します。デバッグ目的を想定しています。ページ番号は0ベースです。区切り文字列は改行で囲まれます。デフォルトは ``False`` です。\"\n\n\nmsgid \"specify a desired page width. This is ignored for documents with a fixed page width like PDF, XPS etc. **Reflowable** documents however, like e-books, office [#f2]_ or text files have no fixed page dimensions. They by default are assumed to have Letter format width (612) and an **unlimited** page height. This means that the **full document is treated as one large page.**\"\nmsgstr \"希望するページの幅を指定します。PDF、XPSなどの固定ページ幅を持つドキュメントでは無視されます。しかし、電子書籍、オフィス [#f2]_ ファイル、テキストファイルなどの **リフロー可能な** ドキュメントには固定のページサイズがありません。これらはデフォルトでレター形式の幅（612）と **無制限の** ページの高さを持つと見なされます。これは、**ドキュメント全体が1つの大きなページとして扱われる** ことを意味します。\"\n\nmsgid \"optional, the pages to consider for output (caution: specify 0-based page numbers). If omitted (`None`) all pages are processed. Any Python sequence with integer items is accepted. The sequence is sorted and processed to only contain unique items.\"\nmsgstr \"オプションで、出力対象として考慮するページを指定します（注意:0ベースのページ番号を指定してください）。省略した場合（``None``）、すべてのページが処理されます。整数項目を持つ任意のPythonシーケンスが受け入れられます。シーケンスはソートされ、一意の項目のみを含むように処理されます。\"\n\nmsgid \"Default is `False`. A value of `True` displays a progress bar as pages are being converted. Package `tqdm <https://pypi.org/project/tqdm/>`_ is used if installed, otherwise the built-in text based progress bar is used.\"\nmsgstr \"デフォルトは ``False`` です。``True`` を指定すると、ページが変換される際に進捗バーが表示されます。インストールされている場合はパッケージ `tqdm <https://pypi.org/project/tqdm/>`_ が使用され、それ以外の場合は組み込みのテキストベースの進捗バーが使用されます。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| see: :meth:`table detection strategy <Page.find_tables>`. Default is `\"lines_strict\"` which ignores background colors. In some occasions, other strategies may be more successful, for example `\"lines\"` which uses all vector graphics objects for detection.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| 参照: :meth:`テーブル検出戦略 <Page.find_tables>`。デフォルトは ``\"lines_strict\"`` で、背景色を無視します。状況によっては、他の戦略がより成功する場合があります。たとえば、すべてのベクターグラフィックオブジェクトを検出に使用する ``\"lines\"`` などです。\"\n\nmsgid \"|PyMuPDFLayoutMode_Ignored| (New in v.0.0.19) Default is `False`. A value of `True` will use the glyph number of the characters instead of the character itself if the font does not store the Unicode value.\"\nmsgstr \"|PyMuPDFLayoutMode_Ignored| (v.0.0.19の新機能) デフォルトは ``False`` です。``True`` を指定すると、フォントがUnicode値を保存していない場合、文字自体の代わりに文字のグリフ番号が使用されます。\"\n\nmsgid \"when encountering images or vector graphics, images will be created from the respective page area and stored in the specified folder. |Markdown| references will be generated pointing to these images. Any text contained in these areas will not be included in the text output (but appear as part of the images). Therefore, if for instance your document has text written on full page images, make sure to set this parameter to `False`.\"\nmsgstr \"画像またはベクターグラフィックに遭遇した場合、該当するページ領域から画像が作成され、指定されたフォルダに保存されます。これらの画像を指す |Markdown| 参照が生成されます。これらの領域に含まれるテキストは、テキスト出力には含まれません（ただし、画像の一部として表示されます）。したがって、たとえば、ドキュメントにフルページ画像上に書かれたテキストがある場合は、このパラメータを ``False`` に設定してください。\"\n\nmsgid \"If using :ref:`PyMuPDF Layout <pymupdf-layout>`, boundary boxes that are classified as \"picture\" by the layout module will be treated as images - independent from the mixture of text, images or vector graphics they may be covering. If `force_text=True` is used, text will still be extracted from these areas and included in the output  after the respective image reference.\"\nmsgstr \":ref:`PyMuPDF Layout <pymupdf-layout>` を使用する場合、レイアウトモジュールによって「picture」として分類されたバウンディングボックスは、テキスト、画像、またはベクターグラフィックの混在に関係なく、画像として扱われます。``force_text=True`` が使用された場合、これらの領域からテキストが抽出され、該当する画像参照の後に出力に含まれます。\"\n\nmsgid \"Either a string of the combined text of all selected document pages, or a list of dictionaries if `page_chunks=True`.\"\nmsgstr \"選択されたすべてのドキュメントページの結合されたテキストの文字列、または ``page_chunks=True`` の場合は辞書のリストです。\"\n\nmsgid \"Reads the pages of the file and outputs the text of its pages in |TXT| format.\"\nmsgstr \"ファイルのページを読み取り、各ページのテキストを |TXT| 形式で出力します。\"\n\nmsgid \"|PyMuPDFLayoutMode_Valid|. This method is only available with PyMuPDF Layout.\"\nmsgstr \"|PyMuPDFLayoutMode_Valid| このメソッドは「レイアウトモード」でのみ利用可能です。つまり、pymupdf4llmのインポートが ``import pymupdf.layout`` ステートメントの **後に** 行われた場合のみです。\"\n\nmsgid \"the file, to be specified either as a file path string, or as a |PyMuPDF| :class:`Document` (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| :class:`Document`.\"\nmsgstr \"ファイルは、ファイルパス文字列、または |PyMuPDF| :class:`Document` (``pymupdf.open`` で作成) のいずれかで指定します。``pathlib.Path`` 指定、Pythonファイル風オブジェクト、メモリ内ドキュメントなどを使用する場合は、|PyMuPDF| :class:`Document` を **必ず** 使用してください。\"\n\nmsgid \"boolean to switch on/off page header content. This parameter controls whether to include or omit the header content from all the document pages. Useful if the document has repetitive header content which doesn't add any value to the overall extraction data. Default is `True` meaning that header content will be written.\"\nmsgstr \"ページヘッダーの内容を含めるか除外するかを切り替えるブール値です。このパラメータは、ドキュメント全ページのヘッダー内容を含めるか省略するかを制御します。ドキュメントに繰り返しのヘッダー内容があり、全体的な抽出データに価値を追加しない場合に便利です。デフォルトは ``True`` で、ヘッダーの内容が出力されることを意味します。\"\n\nmsgid \"boolean to switch on/off page footer content. This parameter controls whether to include or omit the footer content from all the document pages. Useful if the document has repetitive footer content which doesn't add any value to the overall extraction data. Default is `True` meaning that footer content will be written.\"\nmsgstr \"ページフッターの内容を含めるか除外するかを切り替えるブール値です。このパラメータは、ドキュメント全ページのフッター内容を含めるか省略するかを制御します。ドキュメントに繰り返しのフッター内容があり、全体的な抽出データに価値を追加しない場合に便利です。デフォルトは ``True`` で、フッターの内容が出力されることを意味します。\"\n\nmsgid \"if `True` then mono-spaced text lines do not receive special formatting. No blocks will be written and text lines will be written continuously.\"\nmsgstr \"``True`` の場合、等幅テキスト行は特別なフォーマットを受けません。ブロックは書き込まれず、テキスト行は連続して書き込まれます。\"\n\nmsgid \"optional, the pages to consider for output (caution: specify 0-based page numbers). If omitted (`None`) all pages are processed. Any Python sequence with integer items is accepted. The sequence is sorted and processed to only contain unique items.\"\nmsgstr \"オプションで、出力対象として考慮するページを指定します（注意:0ベースのページ番号を指定してください）。省略した場合（``None``）、すべてのページが処理されます。整数項目を持つ任意のPythonシーケンスが受け入れられます。シーケンスはソートされ、一意の項目のみを含むように処理されます。\"\n\nmsgid \"generate text output also when overlapping images / graphics. This text then appears after the respective image reference. Images (i.e. \\\"picture\\\" areas) however will not be written to the text output but appear as a text line in the output like `==> picture [width x height] <==`.\"\nmsgstr \"画像やグラフィックが重なっている場合でもテキスト出力を生成します。このテキストは該当する画像参照の後に表示されます。ただし、画像（つまり「picture」領域）はテキスト出力には書き込まれず、``==> picture [width x height] <==`` のようなテキスト行として出力に表示されます。\"\n\nmsgid \"Default is `False`. A value of `True` displays a progress bar as pages are being converted. Package `tqdm <https://pypi.org/project/tqdm/>`_ is used if installed, otherwise the built-in text based progress bar is used.\"\nmsgstr \"デフォルトは ``False`` です。``True`` を指定すると、ページが変換される際に進捗バーが表示されます。インストールされている場合はパッケージ `tqdm <https://pypi.org/project/tqdm/>`_ が使用され、それ以外の場合は組み込みのテキストベースの進捗バーが使用されます。\"\n\nmsgid \"Parses the document and the specified pages and converts the result into a |JSON|-formatted string.\"\nmsgstr \"ドキュメントと指定されたページを解析し、結果を |JSON| 形式の文字列に変換します。\"\n\n\nmsgid \"the file, to be specified either as a file path string, or as a |PyMuPDF| :class:`Document` (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| :class:`Document`.\"\nmsgstr \"ファイルは、ファイルパス文字列、または |PyMuPDF| :class:`Document` (``pymupdf.open`` で作成) のいずれかで指定します。``pathlib.Path`` 指定、Pythonファイル風オブジェクト、メモリ内ドキュメントなどを使用する場合は、|PyMuPDF| :class:`Document` を **必ず** 使用してください。\"\n\nmsgid \"specify the desired image resolution in dots per inch. Default value is 150. Only relevant if one of the parameters `write_images=True` or `embed_images=True` is used.\"\nmsgstr \"希望する画像解像度をドット・パー・インチ（DPI）で指定します。デフォルト値は150です。``write_images=True`` または ``embed_images=True`` のいずれかのパラメータが使用される場合にのみ有効です。\"\n\nmsgid \"specify the desired image format via its extension. Default is \\\"png\\\" (portable network graphics). Another popular format may be \\\"jpg\\\". Possible values are all :ref:`supported output formats <Supported_File_Types>`. Only relevant if one of the parameters `write_images=True` or `embed_images=True` is used.\"\nmsgstr \"拡張子を使用して希望する画像形式を指定します。デフォルトは「png」（ポータブルネットワークグラフィックス）です。他の一般的な形式としては「jpg」があります。使用可能な値は、すべての :ref:`サポートされている出力形式 <Supported_File_Types>` です。``write_images=True`` または ``embed_images=True`` のいずれかのパラメータが使用される場合にのみ有効です。\"\n\nmsgid \"store images in this folder. Relevant if `write_images=True`. Default is the path of the script directory. Page areas classified as \\\"picture\\\" will be written as image files to the specified location. The image file names will be of the format `{image_path}/{filename}-pagenumber-image_number.{image_format}`.\"\nmsgstr \"このフォルダに画像を保存します。``write_images=True`` の場合に有効です。デフォルトはスクリプトディレクトリのパスです。「picture」として分類されたページ領域は、指定された場所に画像ファイルとして書き込まれます。画像ファイル名は ``{image_path}/{filename}-pagenumber-image_number.{image_format}`` の形式になります。\"\n\nmsgid \"generate text output for text that is written upon areas that are classified as \\\"picture\\\" by the layout module. This may be especially be useful when picture content is not stored.\"\nmsgstr \"レイアウトモジュールによって「picture」として分類された領域上に書かれたテキストのテキスト出力を生成します。これは、画像内容が保存されない場合に特に便利です。\"\n\nmsgid \"display a progress bar during processing.\"\nmsgstr \"処理中に進捗バーを表示します。\"\n\nmsgid \"store image binaries for \\\"picture\\\" boundary boxes. Base64-encoded images are included in the JSON output. Ignores `image_path` if used. This may drastically increase the size of your JSON text.\"\nmsgstr \"「picture」バウンディングボックスの画像バイナリを保存します。Base64エンコードされた画像がJSON出力に含まれます。使用された場合、``image_path`` は無視されます。これによりJSONテキストのサイズが大幅に増加する可能性があります。\"\n\nmsgid \"store image files \\\"picture\\\" boundary boxes.when encountering images, image files will be created from the respective page area and stored in the specified folder. Any text contained in these areas will still be included in the text output.\"\nmsgstr \"「picture」バウンディングボックスの画像ファイルを保存します。画像に遭遇した場合、該当するページ領域から画像ファイルが作成され、指定されたフォルダに保存されます。これらの領域に含まれるテキストは、引き続きテキスト出力に含まれます。\"\n\nmsgid \"optional, the pages to consider for output (caution: specify 0-based page numbers). If omitted (`None`) all pages are processed. Specify any valid Python sequence containing integers between `0` and `page_count - 1`.\"\nmsgstr \"オプションで、出力対象として考慮するページを指定します（注意:0ベースのページ番号を指定してください）。省略した場合（``None``）、すべてのページが処理されます。``0`` から ``page_count - 1`` の間の整数を含む任意の有効なPythonシーケンスを指定してください。\"\n\nmsgid \"Please see `this site <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ for more background and the current status of further improvements regarding usage with :ref:`PyMuPDF Layout <pymupdf-layout>`.\"\nmsgstr \"レイアウトモードに関する更なる改善の背景と現状については、`このサイト <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ をご覧ください。\"\n\nmsgid \"Create a `pdf_markdown_reader.PDFMarkdownReader` using the `LlamaIndex`_ package. Please note that this package will **not automatically be installed** when installing **pymupdf4llm**.\"\nmsgstr \"`LlamaIndex`_ パッケージを使用して ``pdf_markdown_reader.PDFMarkdownReader`` を作成します。このパッケージは **pymupdf4llm** をインストールする際に **自動的にインストールされない** ことに注意してください。\"\n\nmsgid \"For details on the possible arguments, please consult the LlamaIndex documentation [#f1]_.\"\nmsgstr \"可能な引数の詳細については、LlamaIndexのドキュメント [#f1]_ を参照してください。\"\n\nmsgid \"`NotImplementedError`: Please install required `LlamaIndex`_ package.\"\nmsgstr \"``NotImplementedError``: 必要な `LlamaIndex`_ パッケージをインストールしてください。\"\n\nmsgid \"a `pdf_markdown_reader.PDFMarkdownReader` and issues message \"Successfully imported LlamaIndex\". Please note that this method needs several seconds to execute. For details on using the markdown reader please see below.\"\nmsgstr \"``pdf_markdown_reader.PDFMarkdownReader`` と、メッセージ「Successfully imported LlamaIndex」を返します。このメソッドの実行には数秒かかることに注意してください。マークダウンリーダーの使用方法の詳細については、以下を参照してください。\"\n\nmsgid \"This class is not available in \\\"layout mode\\\", i.e. if the import of pymupdf4llm has happened **after** the statement ``import pymupdf.layout``.\"\nmsgstr \"このクラスは「レイアウトモード」では利用できません。つまり、pymupdf4llmのインポートが ``import pymupdf.layout`` ステートメントの **後に** 行われた場合は利用できません。\"\n\nmsgid \"Create an object which maps text font sizes to the respective number of '#' characters which are used by Markdown syntax to indicate header levels. The object is created by scanning the document for font size \\\"popularity\\\". The most popular font size and all smaller sizes are used for body text. Larger font sizes are mapped to the respective header levels - which correspond to the HTML tags `<h1>` to `<h6>`.\"\nmsgstr \"テキストフォントサイズをマークダウン構文でヘッダーレベルを示すために使用される '#' 文字の数にマッピングするオブジェクトを作成します。このオブジェクトは、ドキュメントをスキャンしてフォントサイズの「人気度」を調べることで作成されます。最も一般的なフォントサイズとそれより小さいすべてのサイズは本文テキストに使用されます。より大きいフォントサイズは、それぞれのヘッダーレベル（HTMLタグ ``<h1>`` から ``<h6>`` に対応）にマッピングされます。\"\n\nmsgid \"All font sizes are rounded to integer values.\"\nmsgstr \"すべてのフォントサイズは整数値に丸められます。\"\n\nmsgid \"If more than 6 header levels would be required, then the largest number smaller than the `<h6>` font size is used for body text.\"\nmsgstr \"6つを超えるヘッダーレベルが必要な場合、``<h6>`` フォントサイズより小さい最大の数値が本文テキストに使用されます。\"\n\nmsgid \"Please note that creating the object will read and inspect the text of the entire document - independently of reading the document again in the `to_markdown()` method subsequently. Method `to_markdown()` by default **will create this object** if you do not override its `hdr_info=None` parameter.\"\nmsgstr \"オブジェクトの作成は、その後 ``to_markdown()`` メソッドでドキュメントを再度読み取ることとは独立して、ドキュメント全体のテキストを読み取って検査することに注意してください。``to_markdown()`` メソッドは、``hdr_info=None`` パラメータを上書きしない場合、デフォルトで **このオブジェクトを作成します**。\"\n\nmsgid \"the file, to be specified either as a file path string, or as a |PyMuPDF| Document (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| Document.\"\nmsgstr \"ファイルは、ファイルパス文字列、または |PyMuPDF| Document (``pymupdf.open`` で作成) のいずれかで指定します。``pathlib.Path`` 指定、Pythonファイル風オブジェクト、メモリ内ドキュメントなどを使用する場合は、|PyMuPDF| Document を **必ず** 使用してください。\"\n\nmsgid \"optional, the pages to consider. If omitted all pages are processed.\"\nmsgstr \"オプションで、考慮するページを指定します。省略した場合、すべてのページが処理されます。\"\n\nmsgid \"the default font size limit for body text. Only used when the document scan does not deliver valid information.\"\nmsgstr \"本文テキストのデフォルトのフォントサイズ下限です。ドキュメントスキャンが有効な情報を提供しない場合にのみ使用されます。\"\n\nmsgid \"the maximum number of header levels to be used. Valid values are in `range(1, 7)`. The default is 6, which corresponds to the HTML tags `<h1>` to `<h6>`. A smaller value will limit the number of generated header levels. For instance, a value of 3 will only generate header tags \\\"#\\\", \\\"##\\\" and \\\"###\\\". Body text will be assumed for all font sizes smaller than the one corresponding to \\\"###\\\".\"\nmsgstr \"使用する最大ヘッダーレベル数です。有効な値は ``range(1, 7)`` 内です。デフォルトは6で、HTMLタグ ``<h1>`` から ``<h6>`` に対応します。より小さい値を指定すると、生成されるヘッダーレベルの数が制限されます。たとえば、値3を指定すると、ヘッダータグ「#」、「##」、「###」のみが生成されます。「###」に対応するフォントサイズより小さいすべてのフォントサイズは本文テキストと見なされます。\"\n\nmsgid \"Return appropriate markdown header prefix. This is either \\\"\\\" or a string of \\\"#\\\" characters followed by a space.\"\nmsgstr \"適切なマークダウンヘッダープレフィックスを返します。これは空文字列 ``\"\"``、または「#」文字列とそれに続くスペースのいずれかです。\"\n\nmsgid \"Given a text span from a \\\"dict\\\" extraction, determine the markdown header prefix string of 0 to n concatenated '#' characters.\"\nmsgstr \"「dict」抽出からのテキストスパンを指定すると、0からn個の連結された「#」文字からなるマークダウンヘッダープレフィックス文字列を決定します。\"\n\nmsgid \"a dictionary containing the text span information. This is the same dictionary as returned by `page.get_text(\\\"dict\\\")`.\"\nmsgstr \"テキストスパン情報を含む辞書です。これは ``page.get_text(\"dict\")`` によって返される辞書と同じものです。\"\n\nmsgid \"the owning page object. This can be used when additional information needs to be extracted.\"\nmsgstr \"所有するページオブジェクトです。追加情報を抽出する必要がある場合に使用できます。\"\n\nmsgid \"a string of \\\"#\\\" characters followed by a space.\"\nmsgstr \"「#」文字列とそれに続くスペースです。\"\n\nmsgid \"A dictionary mapping (integer) font sizes to Markdown header strings like ``{14: '# ', 12: '## '}``. The dictionary is created by the :class:`IdentifyHeaders` constructor. The keys are the font sizes of the text spans in the document. The values are the respective header strings.\"\nmsgstr \"整数のフォントサイズを ``{14: '# ', 12: '## '}`` のようなマークダウンヘッダー文字列にマッピングする辞書です。この辞書は :class:`IdentifyHeaders` コンストラクタによって作成されます。キーはドキュメント内のテキストスパンのフォントサイズです。値はそれぞれのヘッダー文字列です。\"\n\nmsgid \"An integer value indicating the font size limit for body text. This is computed as ``min(header_id.keys()) - 1``. In the above example, body_limit would be 11.\"\nmsgstr \"本文テキストのフォントサイズ下限を示す整数値です。これは ``min(header_id.keys()) - 1`` として計算されます。上記の例では、body_limitは11になります。\"\n\nmsgid \"**How to limit header levels (example)**\"\nmsgstr \"**ヘッダーレベルを制限する方法（例）**\"\n\nmsgid \"Limit the generated header levels to 3::\"\nmsgstr \"生成されるヘッダーレベルを3に制限します::\"\n\nmsgid \"**How to provide your own header logic (example 1)**\"\nmsgstr \"**独自のヘッダーロジックを提供する方法（例1）**\"\n\nmsgid \"Provide your own function which uses pre-determined, fixed font sizes::\"\nmsgstr \"事前に決定された固定のフォントサイズを使用する独自の関数を提供します::\"\n\nmsgid \"**How to provide your own header logic (example 2)**\"\nmsgstr \"**独自のヘッダーロジックを提供する方法（例2）**\"\n\nmsgid \"This user function uses the document's Table of Contents -- under the assumption that the bookmark text is also present as a header line on the page (which certainly need not be the case!)::\"\nmsgstr \"このユーザー関数はドキュメントの目次を使用します。ブックマークテキストがヘッダー行としてページ上にも存在することを前提としています（これは必ずしもそうであるとは限りません！）::\"\n\nmsgid \"Create an object which uses the document's Table of Contents (TOC) to determine header levels. Upon object creation, the table of contents is read via the `Document.get_toc()` method. The TOC data is then used to determine header levels in the `to_markdown()` method.\"\nmsgstr \"ドキュメントの目次（TOC）を使用してヘッダーレベルを決定するオブジェクトを作成します。オブジェクト作成時に、``Document.get_toc()`` メソッドを介して目次が読み取られます。その後、TOCデータは ``to_markdown()`` メソッドでヘッダーレベルを決定するために使用されます。\"\n\nmsgid \"This is an alternative to :class:`IdentifyHeaders`. Instead of running through the full document to identify font sizes, it uses the document's Table Of Contents (TOC) to identify headers on pages. Like :class:`IdentifyHeaders`, this also is no guarantee to find headers, but for well-built Table of Contents, there is a good chance for more correctly identifying header lines on document pages than the font-size-based approach.\"\nmsgstr \"これは :class:`IdentifyHeaders` の代替手段です。フォントサイズを識別するためにドキュメント全体を実行する代わりに、ドキュメントの目次（TOC）を使用してページ上のヘッダーを識別します。:class:`IdentifyHeaders` と同様に、これもヘッダーを見つけることを保証するものではありませんが、適切に構築された目次の場合、フォントサイズベースのアプローチよりもドキュメントページ上のヘッダー行をより正確に識別できる可能性が高くなります。\"\n\nmsgid \"It also has the advantage of being much faster than the font-size-based approach, as it does not execute a full document scan or even access any of the document pages.\"\nmsgstr \"また、ドキュメント全体のスキャンを実行したり、ドキュメントページにアクセスしたりしないため、フォントサイズベースのアプローチよりもはるかに高速であるという利点もあります。\"\n\nmsgid \"Examples where this approach works very well are the Adobe's files on PDF documentation.\"\nmsgstr \"このアプローチが非常にうまく機能する例としては、AdobeのPDFドキュメントに関するファイルがあります。\"\n\nmsgid \"Please note that this feature **does not read document pages** where the table of contents may exist as normal standard text. It only accesses data as provided by the `Document.get_toc()` method. It will not identify any headers for documents where the table of contents is not available as a collection of bookmarks.\"\nmsgstr \"この機能は、目次が通常の標準テキストとして存在する可能性のある **ドキュメントページを読み取りません**。``Document.get_toc()`` メソッドによって提供されるデータにのみアクセスします。目次がブックマークのコレクションとして利用できないドキュメントの場合、ヘッダーを識別しません。\"\n\nmsgid \"Return appropriate markdown header prefix. This is either an empty string or a string of \\\"#\\\" characters followed by a space.\"\nmsgstr \"適切なマークダウンヘッダープレフィックスを返します。これは空文字列、または「#」文字列とそれに続くスペースのいずれかです。\"\n\nmsgid \"Given a text span from a \\\"dict\\\" extraction variant, determine the markdown header prefix string of 0 to n concatenated \\\"#\\\" characters.\"\nmsgstr \"「dict」抽出バリアントからのテキストスパンを指定すると、0からn個の連結された「#」文字からなるマークダウンヘッダープレフィックス文字列を決定します。\"\n\nmsgid \"a dictionary containing the text span information. This is the same dictionary as returned by `page.get_text(\\\"dict\\\")`.\"\nmsgstr \"テキストスパン情報を含む辞書です。これは ``page.get_text(\"dict\")`` によって返される辞書と同じものです。\"\n\nmsgid \"the owning page object. This can be used when additional information needs to be extracted.\"\nmsgstr \"テキストスパン情報を含む辞書です。これは ``page.get_text(\"dict\")`` によって返される辞書と同じものです。\"\n\nmsgid \"a string of \\\"#\\\" characters followed by a space.\"\nmsgstr \"「#」文字列とそれに続くスペースです。\"\n\nmsgid \"**How to use class TocHeaders**\"\nmsgstr \"**TocHeaders クラスの使用方法**\"\n\nmsgid \"This is a version of previous **example 2** that uses :class:`TocHeaders` for header identification::\"\nmsgstr \"これは、ヘッダー識別に :class:`TocHeaders` を使用する以前の **例2** のバージョンです\"\n\nmsgid \"This is the only method of the markdown reader you should currently use to extract markdown data. Please in any case ignore methods `aload_data()` and `lazy_load_data()`. Other methods like `use_doc_meta()` may or may not make sense. For more information, please consult the LlamaIndex documentation [#f1]_.\"\nmsgstr \"これは、マークダウンデータを抽出するために現在使用すべきマークダウンリーダーの唯一のメソッドです。いかなる場合でも、``aload_data()`` および ``lazy_load_data()`` メソッドは無視してください。``use_doc_meta()`` などの他のメソッドは、意味がある場合とない場合があります。詳細については、LlamaIndexのドキュメント [#f1]_ を参照してください。\"\n\nmsgid \"Under the hood the method will execute `to_markdown()`.\"\nmsgstr \"内部的には、このメソッドは ``to_markdown()`` を実行します。\"\n\nmsgid \"a list of `LlamaIndexDocument` documents - one for each page.\"\nmsgstr \"``LlamaIndexDocument`` ドキュメントのリストです。ページごとに1つです。\"\n\nmsgid \"For a list of changes, please see file `CHANGES.md <https://github.com/pymupdf/RAG/blob/main/CHANGES.md>`_.\"\nmsgstr \"変更点の一覧については、ファイル `CHANGES.md <https://github.com/pymupdf/RAG/blob/main/CHANGES.md>`_ を参照してください。\"\n\nmsgid \"`LlamaIndex documentation <https://docs.llamaindex.ai/en/stable/>`_\"\nmsgstr \"`LlamaIndexドキュメント <https://docs.llamaindex.ai/en/stable/>`_\"\n\nmsgid \"When using PyMuPDF-Pro, supported office documents are converted internally into a PDF-like format. Therefore, they **will have fixed page dimensions** and be no longer \"reflowable\". Consequently, the page width and page height specifications will be ignored as well in these cases.\"\nmsgstr \"PyMuPDF-Proを使用する場合、サポートされているオフィスドキュメントは内部的にPDF形式に変換されます。したがって、これらは **固定のページサイズを持ち**、「リフロー可能」ではなくなります。その結果、これらの場合はページ幅とページ高さの指定も無視されます。\"\n\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/pymupdf4llm/index.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-26 17:04+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 d999746961f541d091c04253454c2495\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 942f0462179c4c28a52bfb5b4819a15a\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 cc1a6ef974e74b6299fc9df6b833ae6d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/index.rst:8 96b9f29894ff49beba7a07931c5c900d\nmsgid \"PyMuPDF4LLM\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/index.rst:10 59d6714b7f6549e0a52c173974da2135\nmsgid \"\"\n\"|PyMuPDF4LLM| is aimed to make it easier to extract |PDF| content in the \"\n\"format you need for **LLM** & **RAG** environments. It supports \"\n\":ref:`Markdown extraction <extracting_as_md>` as well as :ref:`LlamaIndex\"\n\" document output <extracting_as_llamaindex>`.\"\nmsgstr \"\"\n\"|PyMuPDF4LLM| は、**LLM** や **RAG** 環境で必要な形式で |PDF| \"\n\"コンテンツを簡単に抽出できるようにすることを目的としています。 **Markdown** 形式での抽出や、 **LlamaIndex** \"\n\"ドキュメント出力もサポートしています。\"\n\n#: ../../pymupdf4llm/index.rst:12 8b36d59c925f4a0d93873eeab7e4843a\nmsgid \"\"\n\"When using |PyMuPDF4LLM| with PyMuPDF-Layout, page layout detection will \"\n\"be greatly improved. This is true for table detection, but also for the \"\n\"detection of page headers and footers, footnotes, list items and text \"\n\"paragraphs. In addition two new methods become available, `to_json()` and\"\n\" `to_text()`.\"\nmsgstr \"PyMuPDF4LLM を PyMuPDF-Layout と併用すると、ページレイアウト検出が大幅に改善されます。これは表の検出だけでなく、ページヘッダーとフッター、脚注、リスト項目、テキスト段落の検出にも当てはまります。さらに、`to_json()` と `to_text()` という2つの新しいメソッドが利用可能になります。\"\n\n#: ../../pymupdf4llm/index.rst:16 50bf080e50e64ba58e973f0addf24d73\nmsgid \"\"\n\"You can extend the supported file types to also include **Office** \"\n\"document formats (DOC/DOCX, XLS/XLSX, PPT/PPTX, HWP/HWPX) by :ref:`using \"\n\"PyMuPDF Pro with PyMuPDF4LLM <using_pymupdf4llm_withpymupdfpro>`.\"\nmsgstr \"\"\n\":ref:`PyMuPDF ProをPyMuPDF4LLMと併用することで \"\n\"<using_pymupdf4llm_withpymupdfpro>`、対応するファイル形式を拡張し、 **Office** \"\n\"ドキュメント形式（DOC/DOCX、XLS/XLSX、PPT/PPTX、HWP/HWPX）も含めることができます。\"\n\n#: ../../pymupdf4llm/index.rst:19 38428359cdaf4039b439454f5c712ec7\nmsgid \"Features\"\nmsgstr \"特徴\"\n\n#: ../../pymupdf4llm/index.rst:21 5f4fb197fcdd4a0ab3ac79607a78a25e\nmsgid \"Support for multi-column pages\"\nmsgstr \"マルチカラムページのサポート\"\n\n#: ../../pymupdf4llm/index.rst:22 7e249663241a4aacb2f9b1fcb4450393\nmsgid \"\"\n\"Support for image and vector graphics extraction (and inclusion of \"\n\"references in the MD text)\"\nmsgstr \"画像およびベクターグラフィックスの抽出のサポート（MDテキストへの参照の挿入を含む）\"\n\n#: ../../pymupdf4llm/index.rst:23 cf659dc9b2da48d69e7ab3d1cda7f132\nmsgid \"Support for page chunking output.\"\nmsgstr \"ページ分割出力のサポート\"\n\n#: ../../pymupdf4llm/index.rst:24 20715d6347fb42b7b485fba224287741\nmsgid \"\"\n\"Direct support for output as :ref:`LlamaIndex Documents \"\n\"<extracting_as_llamaindex>`.\"\nmsgstr \":ref:`LlamaIndexドキュメント <extracting_as_llamaindex>` としての直接出力のサポート\"\n\n#: ../../pymupdf4llm/index.rst:25 ed7f233894d54e93aca9c1f33a896476\nmsgid \"In \\\"layout mode\\\": Support for plain text output similar to Markdown\"\nmsgstr \"「レイアウトモード」: Markdown と同様のプレーンテキスト出力のサポート\"\n\n#: ../../pymupdf4llm/index.rst:26 e29cc03c8f6f40be974a1f9262165c9c\nmsgid \"In \\\"layout mode\\\": Support for JSON output\"\nmsgstr \"「レイアウトモード」: JSON 出力のサポート\"\n\n#: ../../pymupdf4llm/index.rst:30 90f6c12aacd14b7eba944b6c1e013ed5\nmsgid \"Functionality\"\nmsgstr \"機能\"\n\n#: ../../pymupdf4llm/index.rst:32 e63a722974dc41f3928dc372e66da5c0\nmsgid \"\"\n\"This package converts the pages of a file to text in **Markdown** format \"\n\"using |PyMuPDF|.\"\nmsgstr \"このパッケージは、|PyMuPDF| を使用して |PDF| のページを **Markdown** 形式のテキストに変換します。\"\n\n#: ../../pymupdf4llm/index.rst:34 1504c800279e44568bfbbeef3eb2ba6d\nmsgid \"\"\n\"Standard text and tables are detected, brought in the right reading \"\n\"sequence and then together converted to **GitHub**-compatible \"\n\"**Markdown** text.\"\nmsgstr \"\"\n\"標準のテキストやテーブルが検出され、適切な読み取り順序で取り込まれ、その後一緒に **GitHub** 互換の **Markdown** \"\n\"テキストに変換されます。\"\n\n#: ../../pymupdf4llm/index.rst:36 4d3e28d4b9654f6889e99f25edeafb6f\nmsgid \"\"\n\"Header lines are identified via the font size and appropriately prefixed \"\n\"with one or more `#` tags.\"\nmsgstr \"ヘッダー行はフォントサイズで識別され、適切に1つまたは複数の＃タグで接頭語が付けられます。\"\n\n#: ../../pymupdf4llm/index.rst:38 d3dc9c01915e4fd5a47c1784eae70c00\nmsgid \"\"\n\"Bold, italic, mono-spaced text and code blocks are detected and formatted\"\n\" accordingly. Similar applies to ordered and unordered lists.\"\nmsgstr \"太字、斜体、等幅テキスト、およびコードブロックが検出され、それに応じて書式が付けられます。順序付けられたリストと順不同リストにも同様のことが適用されます。\"\n\n#: ../../pymupdf4llm/index.rst:40 bc9f92950b5b4c038ed82153c462a0c6\nmsgid \"\"\n\"By default, all document pages are processed. If desired, a subset of \"\n\"pages can be specified by providing a list of `0`-based page numbers.\"\nmsgstr \"デフォルトでは、すべての文書ページが処理されます。必要に応じて、`0` から始まるページ番号のリストを指定してサブセットのページを指定できます。\"\n\n#: ../../pymupdf4llm/index.rst:44 24714fd3cb744a908099e19f1af6ce7e\nmsgid \"Installation\"\nmsgstr \"インストール\"\n\n#: ../../pymupdf4llm/index.rst:47 dd73904df42146e18551936620e44355\nmsgid \"Install the package via **pip** with:\"\nmsgstr \"パッケージを **pip** を使用してインストールするには、次のコマンドを使用します:\"\n\n#: ../../pymupdf4llm/index.rst:58 a08840e778fe46379ec9110ad3c3608a\nmsgid \"Extracting a file as **Markdown**\"\nmsgstr \"ファイルをMarkdown形式で抽出する\"\n\n#: ../../pymupdf4llm/index.rst:60 98c0760b58c04cbeb1299faf5b79ab3f\nmsgid \"\"\n\"To retrieve your document content in **Markdown** simply install the \"\n\"package and then use a couple of lines of **Python** code to get results.\"\nmsgstr \"\"\n\"ドキュメントの内容を **Markdown** で取得するには、パッケージをインストールし、数行の **Python** \"\n\"コードを使用するだけで結果を得ることができます。\"\n\n#: ../../pymupdf4llm/index.rst:64 6a398956ca7f4c9c9057734393a79743\nmsgid \"Then in your **Python** script do:\"\nmsgstr \"**Python** スクリプトでは:\"\n\n#: ../../pymupdf4llm/index.rst:75 b227684a017d42e8b88f83ad2a3c673e\nmsgid \"\"\n\"Instead of the filename string as above, one can also provide a \"\n\":ref:`PyMuPDF Document <Document>`. A second parameter may be a list of \"\n\"`0`-based page numbers, e.g. `[0, 1]` would just select the first and \"\n\"second pages of the document.\"\nmsgstr \"上記のファイル名文字列の代わりに、:ref:`PyMuPDF Document <Document>` を提供することもできます。2番目のパラメータは、0ベースのページ番号のリストである可能性があります。例えば、[0, 1] はドキュメントの最初と2番目のページのみを選択します。\"\n\n#: ../../pymupdf4llm/index.rst:78 a0929decafbc41cb86a00b46905219e0\nmsgid \"\"\n\"If you want to store your **Markdown** file, e.g. store as a UTF8-encoded\"\n\" file, then do:\"\nmsgstr \"**Markdown** ファイルを保存したい場合、例えばUTF8でエンコードされたファイルとして保存する場合は、次のようにします。\"\n\n#: ../../pymupdf4llm/index.rst:91 fe47c11343ec4d278c9f9cc524bccb86\nmsgid \"Extracting a file as a **LlamaIndex** document\"\nmsgstr \"ファイルをLlamaIndexドキュメントとして抽出する\"\n\n#: ../../pymupdf4llm/index.rst:93 6834228bb5524c319b8c3d5dbe8138d6\nmsgid \"\"\n\"|PyMuPDF4LLM| supports direct conversion to a **LLamaIndex** document. A \"\n\"document is first converted into **Markdown** format and then a \"\n\"**LlamaIndex** document is returned as follows:\"\nmsgstr \"\"\n\"|PyMuPDF4LLM| は **LlamaIndex** ドキュメントへの直接変換をサポートしています。ドキュメントはまず \"\n\"**Markdown** 形式に変換され、その後、以下のように **LlamaIndex** ドキュメントとして返されます。\"\n\n#: ../../pymupdf4llm/index.rst:107 e653025ecf1948759d96b33b7902c524\nmsgid \"Using with |PyMuPDF Pro|\"\nmsgstr \"PyMuPDF Proとの使用 \"\n\n#: ../../pymupdf4llm/index.rst:110 9e877b4bd26d43cbaf81821091d51a1b\nmsgid \"\"\n\"For **Office** document support, |PyMuPDF4LLM| works seamlessly with \"\n\"|PyMuPDF Pro|. Assuming you have :doc:`../pymupdf-pro` installed you will\"\n\" be able to work with **Office** documents as expected:\"\nmsgstr \"\"\n\"**Office** ドキュメントのサポートのために、|PyMuPDF4LLM| は |PyMuPDF Pro| \"\n\"とシームレスに動作します。:doc:`../pymupdf-pro` がインストールされている場合、期待通りに **Office** \"\n\"ドキュメントを操作できます。\"\n\n#: ../../pymupdf4llm/index.rst:121 ff1a10504dbe4b5381a2f6232a21b346\nmsgid \"\"\n\"As you can see |PyMuPDF Pro| functionality will be available within the \"\n\"|PyMuPDF4LLM| context!\"\nmsgstr \"ご覧のとおり、|PyMuPDF Pro| の機能は |PyMuPDF4LLM| のコンテキスト内で利用可能になります！\"\n\n#: ../../pymupdf4llm/index.rst:126 32a7f061e08e4a6ca0f4f3fddb070669\nmsgid \"API\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/index.rst:128 b4ebede9414d489da467192cd788038a\nmsgid \"See :ref:`the PyMuPDF4LLM API <pymupdf4llm-api>`.\"\nmsgstr \":ref:`PyMuPDF4LLM API <pymupdf4llm-api>` をご覧ください。\"\n\n#: ../../pymupdf4llm/index.rst:131 bb3e7108ffa0474c9130db24bde17039\nmsgid \"Further Resources\"\nmsgstr \"追加リソース\"\n\n#: ../../pymupdf4llm/index.rst:135 ec0ceb929e634253940d9d8b12c34e12\nmsgid \"Sample code\"\nmsgstr \"サンプルコード\"\n\n#: ../../pymupdf4llm/index.rst:137 f2d41ac1c1d24d9289e6ce68bc9370de\n#, fuzzy\nmsgid \"\"\n\"`Command line RAG Chatbot with PyMuPDF \"\n\"<https://github.com/pymupdf/RAG/tree/main/examples/country-capitals>`_\"\nmsgstr \"\"\n\"`PyMuPDFを使用したコマンドラインRAGチャットボット <https://github.com/pymupdf/RAG/tree/main\"\n\"/country-capitals>`_\"\n\n#: ../../pymupdf4llm/index.rst:138 bf6ddba28b86427ab7c934e3fe869608\n#, fuzzy\nmsgid \"\"\n\"`Example of a Browser Application using Langchain and PyMuPDF \"\n\"<https://github.com/pymupdf/RAG/tree/main/examples/GUI>`_\"\nmsgstr \"\"\n\"`LangchainとPyMuPDFを使用したブラウザアプリケーションの例 \"\n\"<https://github.com/pymupdf/RAG/tree/main/GUI>`_\"\n\n#: ../../pymupdf4llm/index.rst:142 05f33a793ba04dbea19e7a464b4c8cd5\nmsgid \"Blogs\"\nmsgstr \"ブログ\"\n\n#: ../../pymupdf4llm/index.rst:144 d6c3173afe6a4dbd880c662d9a8b9e66\nmsgid \"\"\n\"`RAG/LLM and PDF: Enhanced Text Extraction <https://artifex.com/blog/rag-\"\n\"llm-and-pdf-enhanced-text-extraction>`_\"\nmsgstr \"\"\n\"`RAG/LLMとPDF: テキスト抽出の強化 <https://qiita.com/jamie-\"\n\"lemon/items/455e14f83b4f5c81034b>`_\"\n\n#: ../../pymupdf4llm/index.rst:145 2469a1a8ebb649b083d10e876d5b3022\nmsgid \"\"\n\"`Creating a RAG Chatbot with ChatGPT and PyMuPDF \"\n\"<https://artifex.com/blog/creating-a-rag-chatbot-with-chatgpt-and-\"\n\"pymupdf>`_\"\nmsgstr \"\"\n\"`ChatGPTとPyMuPDFを使用したRAGチャットボットの作成 <https://qiita.com/jamie-\"\n\"lemon/items/df6703906392ae8295f3>`_\"\n\n#: ../../pymupdf4llm/index.rst:146 750da7ec1111406c9f24fe09151140ae\nmsgid \"\"\n\"`Building a RAG Chatbot GUI with the ChatGPT API and PyMuPDF \"\n\"<https://artifex.com/blog/building-a-rag-chatbot-gui-with-the-chatgpt-\"\n\"api-and-pymupdf>`_\"\nmsgstr \"\"\n\"`ChatGPT APIとPyMuPDFを使用してRAGチャットボットGUIを構築 <https://qiita.com/jamie-\"\n\"lemon/items/f075ae56cf56723c9409>`_\"\n\n#: ../../pymupdf4llm/index.rst:147 d820865d4e2b470b975fd95e67ec0436\nmsgid \"\"\n\"`RAG/LLM and PDF: Conversion to Markdown Text with PyMuPDF \"\n\"<https://artifex.com/blog/rag-llm-and-pdf-conversion-to-markdown-text-\"\n\"with-pymupdf>`_\"\nmsgstr \"\"\n\"`RAG/LLMとPDF：PyMuPDFを使用したMarkdownテキストへの変換 <https://qiita.com/jamie-\"\n\"lemon/items/1f2eb43f439fd28202a0>`_\"\n\n#: ../../footer.rst:46 30b12247e1244acba7a2885245d87849\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/pyodide.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 14998f025d1148cda63f25bfef057aa2\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 5c54bd9a0f054a82914a040bee536ad6\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF（およびその他の）ドキュメントのデータ抽出、解析、変換、および操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 ce438b15da5b4a318f4e36069383eb06\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF テキスト抽出、PDF 画像抽出、PDF 変換、PDF テーブル、PDF 分割、PDF 作成、Pyodide、PyScript\"\n\n#: ../../pyodide.rst:4 92e84ecde2114f28830f75ff139cc150\nmsgid \"Pyodide\"\nmsgstr \"\"\n\n#: ../../pyodide.rst:8 3c7cff0a2616443fbc6d49b71a7d5ef9\nmsgid \"Overview\"\nmsgstr \"概要\"\n\n#: ../../pyodide.rst:11 e962a3c031f2439688768b2b5d926e9a\nmsgid \"\"\n\"`Pyodide <https://pyodide.org>`_ is a client-side Python implementation \"\n\"that runs in a web browser.\"\nmsgstr \"`Pyodide <https://pyodide.org>`_ は、ウェブブラウザで実行されるクライアントサイドの Python 実装です\"\n\n#: ../../pyodide.rst:14 e26bc674818d456fb786a4cc5b979023\nmsgid \"The Pyodide build of PyMuPDF is currently experimental.\"\nmsgstr \"PyMuPDF の Pyodide ビルドは現在実験的な段階です。\"\n\n#: ../../pyodide.rst:18 d8c36794d9a943e19a0cd695b98e4172\nmsgid \"Building a PyMuPDF wheel for Pyodide\"\nmsgstr \"Pyodide 用の PyMuPDF ホイールの構築\"\n\n#: ../../pyodide.rst:20 1dcd6f33eb094fc284df0d904ce1cefa\nmsgid \"\"\n\"A PyMuPDF wheel for Pyodide can be built by running \"\n\"`scripts/gh_release.py` with some environmental variable settings. This \"\n\"is regularly tested on Github by `.github/workflows/test_pyodide.yml`.\"\nmsgstr \"\"\n\"Pyodide 用の PyMuPDF ホイールは、いくつかの環境変数設定を使用して `scripts/gh_release.py` \"\n\"を実行することで構築できます。これは、`.github/workflows/test_pyodide.yml` によって定期的に GitHub \"\n\"上でテストされています。\"\n\n#: ../../pyodide.rst:24 04f1fabb002143fb9a715d8db14af45a\nmsgid \"\"\n\"Here is an example of this, a single Linux command (to be run with the \"\n\"current directory set to a PyMuPDF checkout), that builds a Pyodide \"\n\"wheel::\"\nmsgstr \"以下は、これの例です。現在のディレクトリが PyMuPDF のチェックアウトに設定されている場合に実行される単一の Linux コマンドです。\"\n\n#: ../../pyodide.rst:33 eef89f5827ec4b709ca1d2e0ac5c097f\nmsgid \"This does the following (all inside Python venv's):\"\nmsgstr \"これは以下の作業を行います（すべて Python venv 内で実行）：\"\n\n#: ../../pyodide.rst:35 12858012b88247c7bb3c683954628295\nmsgid \"\"\n\"Download (git clone and pip install) and customise a Pyodide build \"\n\"environment.\"\nmsgstr \"Pyodide ビルド環境をダウンロード（git clone および pip install）し、カスタマイズします\"\n\n#: ../../pyodide.rst:36 3e87e7f44f7545bbbb191af42283fe54\nmsgid \"Download (git clone) the latest MuPDF.\"\nmsgstr \"最新の MuPDF をダウンロード（git clone）します。\"\n\n#: ../../pyodide.rst:37 160cb2ec1c1c4a209a7fba7562c0d145\nmsgid \"Build MuPDF and PyMuPDF in the Pyodide build environment.\"\nmsgstr \"MuPDF と PyMuPDF を Pyodide ビルド環境でビルドします。\"\n\n#: ../../pyodide.rst:38 ccad3592e88243efab0d160923ed215a\nmsgid \"Create a wheel in `dist/`.\"\nmsgstr \"`dist/` にホイールを作成します\"\n\n#: ../../pyodide.rst:40 5a3384a91a534d249a926eb839230cea\nmsgid \"\"\n\"For more information, see the comments for functions \"\n\"`build_pyodide_wheel()` and `pyodide_setup()` in `scripts/gh_release.py`.\"\nmsgstr \"\"\n\"詳細については、`scripts/gh_release.py` 内の関数 `build_pyodide_wheel()` と \"\n\"`pyodide_setup()` のコメントを参照してください。\"\n\n#: ../../pyodide.rst:45 b46c76365b9046c195143674ad6f9337\nmsgid \"Using a Pyodide wheel\"\nmsgstr \"Pyodide ホイールの使用方法\"\n\n#: ../../pyodide.rst:48 6a5b9ebd00244e88809b7cddb3efb929\nmsgid \"\"\n\"Upload the wheel (for example \"\n\"`PyMuPDF/dist/PyMuPDF-1.24.2-cp311-cp311-emscripten_3_1_32_wasm32.whl`) \"\n\"to a webserver which has been configured to allow Cross-origin resource \"\n\"sharing (https://en.wikipedia.org/wiki/Cross-origin_resource_sharing).\"\nmsgstr \"\"\n\"`PyMuPDF/dist/PyMuPDF-1.24.2-cp311-cp311-emscripten_3_1_32_wasm32.whl` \"\n\"のようなホイールを、Cross-origin resource sharing（https://en.wikipedia.org/wiki\"\n\"/Cross-origin_resource_sharing）を許可するように構成されたウェブサーバにアップロードします。\"\n\n#: ../../pyodide.rst:54 12bd07e412b5464e9cd32cbc111e2a26\nmsgid \"\"\n\"The wheel can be used in a Pyodide console running in a web browser, or a\"\n\" JupyterLite notebook running in a web browser.\"\nmsgstr \"このホイールは、ウェブブラウザで実行されている Pyodide コンソールまたは JupyterLite ノートブックで使用できます。\"\n\n#: ../../pyodide.rst:57 fe96c467a1374441b725c5ed97d79a57\nmsgid \"To create a Pyodide console, go to:\"\nmsgstr \"Pyodide コンソールを作成するには、次のURLにアクセスしてください：\"\n\n#: ../../pyodide.rst:59 910ab71af3894948a37af8412a6954fb\nmsgid \"https://pyodide.org/en/stable/console.html\"\nmsgstr \"\"\n\n#: ../../pyodide.rst:61 6433c259686c469bac6c3f3a824351f2\nmsgid \"To create a JupyterLite notebook, go to:\"\nmsgstr \"JupyterLite ノートブックを作成するには、次のURLにアクセスしてください：\"\n\n#: ../../pyodide.rst:63 4903ffff457f434691fffa07bd2f73a5\nmsgid \"https://jupyterlite.readthedocs.io/en/latest/_static/lab/index.html\"\nmsgstr \"\"\n\n#: ../../pyodide.rst:66 09c760f53c434ee6b3ce75b594a85cad\nmsgid \"\"\n\"In both these cases, one can use the following code to download the wheel\"\n\" (replace `url` with the URL of the uploaded wheel) and import it::\"\nmsgstr \"れらの場合、以下のコードを使用してホイールをダウンロード（`url` をアップロードされたホイールの URL に置き換える）し、インポートできます：\"\n\n#: ../../pyodide.rst:74 dbd55ab15c224387b85ff3b29f3fd2c7\nmsgid \"\"\n\"Note that `micropip.install()` does not work, because of PyMuPDF's use of\"\n\" shared libraries.\"\nmsgstr \"`micropip.install()` は PyMuPDF が共有ライブラリを使用しているため機能しないことに注意してください。\"\n\n#: ../../pyodide.rst:79 d9fce175d654431a9a455df1cddc005f\nmsgid \"Loading a PDF document from a URL into PyMuPDF\"\nmsgstr \"PyMuPDF にURLからPDFドキュメントを読み込む\"\n\n#: ../../pyodide.rst:82 5e286969bc7e464ab645cff0b5e85861\nmsgid \"\"\n\"Pyodide browser console does not have generic network access, so for \"\n\"example `urllib.request.urlopen(url)` fails. But Pyodide has a built-in \"\n\"`pyodide.http` module that uses javascript internally, which one can use \"\n\"to download into a `bytes` instance, which can be used to create a \"\n\"PyMuPDF `Document` instance::\"\nmsgstr \"\"\n\"Pyodide ブラウザコンソールには一般的なネットワークアクセスがないため、例えば `urllib.request.urlopen(url)` \"\n\"は失敗します。しかし、Pyodide には JavaScript を内部で使用する組み込みの `pyodide.http` \"\n\"モジュールがあります。これを使用して `bytes` インスタンスにダウンロードし、それを使用して PyMuPDF `Document` \"\n\"インスタンスを作成できます：\"\n\n#: ../../pyodide.rst:93 9022520dcaa9430fb6e28b813ef995c2\nmsgid \"It looks like this only works with `https://`, not `http://`.\"\nmsgstr \"これは `https://` でのみ機能するようです。`http://` では機能しません。\"\n\n#: ../../footer.rst:60 84f62677a793440aa7ea160b7c3c1a2f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは、|version| までのすべてのバージョンをカバーしています\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/quad.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 3ad4b4dd8a9d444dbdb71d2f893d147d\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 8e281561019a467090b604cbf8c25baa\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 7a22fe4efbda4a6e9221d09c9a1e31f5\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../quad.rst:7 35e2527763ab458fa5ba06887a186967\nmsgid \"Quad\"\nmsgstr \"Quad (クアッド)\"\n\n#: ../../quad.rst:9 7800e12444f748a6831e1efc77128fa3\nmsgid \"\"\n\"Represents a four-sided mathematical shape (also called \\\"quadrilateral\\\"\"\n\" or \\\"tetragon\\\") in the plane, defined as a sequence of four \"\n\":ref:`Point` objects ul, ur, ll, lr (conveniently called upper left, \"\n\"upper right, lower left, lower right).\"\nmsgstr \"\"\n\"Quad（四角形または四辺形とも呼ばれる）は、平面上の数学的な四角形を表すもので、ul（上部左側）、ur（上部右側）、ll（下部左側）、lr（下部右側）の4つの\"\n\" :ref:`Point` オブジェクトのシーケンスとして定義されます。\"\n\n#: ../../quad.rst:11 4d17c9c46c584b239de386721cba1810\nmsgid \"\"\n\"Quads can **be obtained** as results of text search methods \"\n\"(:meth:`Page.search_for`), and they **are used** to define text marker \"\n\"annotations (see e.g. :meth:`Page.add_squiggly_annot` and friends), and \"\n\"in several draw methods (like :meth:`Page.draw_quad` / \"\n\":meth:`Shape.draw_quad`, :meth:`Page.draw_oval`/ \"\n\":meth:`Shape.draw_quad`).\"\nmsgstr \"\"\n\"Quadはテキスト検索メソッド（ :meth:`Page.search_for` など）の結果として **取得でき** \"\n\"、テキストマーカーアノテーション :meth:`Page.add_squiggly_annot` \"\n\"などを参照）の定義や、:meth:`Page.draw_oval` / :meth:`Shape.draw_quad` \"\n\"などのいくつかの描画メソッドで使用されます。\"\n\n#: ../../quad.rst:15 7b24b5db8f874de9a5211dce20991a59\nmsgid \"\"\n\"If the corners of a rectangle are transformed with a **rotation**, \"\n\"**scale** or **translation** :ref:`Matrix`, then the resulting quad is \"\n\"**rectangular** (= congruent to a rectangle), i.e. all of its corners \"\n\"again enclose angles of 90 degrees. Property :attr:`Quad.is_rectangular` \"\n\"checks whether a quad can be thought of being the result of such an \"\n\"operation.\"\nmsgstr \"\"\n\"四角形の角が **回転**、**スケール**、または **移動** :ref:`Matrix` で変換される場合、結果の四角形は **長方形** \"\n\"です（長方形と合同の意味）、つまりそのすべての角は再び90度の角度を囲んでいます。:attr:`Quad.is_rectangular` \"\n\"プロパティは、四角形がこのような操作の結果であるかどうかを確認します。\"\n\n#: ../../quad.rst:17 688788bd21fd45f692790d0473acb161\nmsgid \"\"\n\"This is not true for all matrices: e.g. shear matrices produce \"\n\"parallelograms, and non-invertible matrices deliver \\\"degenerate\\\" \"\n\"tetragons like triangles or lines.\"\nmsgstr \"これはすべての行列に対して当てはまるわけではありません。例えば、シア行列は平行四辺形を生成し、非可逆行列は三角形や線のような「退化」した四角形を提供します。\"\n\n#: ../../quad.rst:19 cf1183ff01fc48bf97106c5a287a5ff7\nmsgid \"\"\n\"Attribute :attr:`Quad.rect` obtains the enveloping rectangle. Vice versa,\"\n\" rectangles now have attributes :attr:`Rect.quad`, resp. \"\n\":attr:`IRect.quad` to obtain their respective tetragon versions.\"\nmsgstr \"\"\n\"属性 :attr:`Quad.rect` は包括的な長方形を取得します。その逆も成り立ち、長方形には \"\n\":attr:`Rect.quad`、:attr:`IRect.quad` 属性が含まれ、それぞれそれらの四辺形バージョンを取得できます。\"\n\n#: ../../quad.rst:23 50d7d842d9734fa599c188cc646d7b45\nmsgid \"**Methods / Attributes**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../quad.rst:23 19f74f68bb13495c8ebf6c8b0b42f965\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../quad.rst:25 e538183055244dc08b0b15c4b8912add\nmsgid \":meth:`Quad.transform`\"\nmsgstr \"\"\n\n#: ../../quad.rst:25 9f2dd03a77524dfd9b216fbb23b9cda3\nmsgid \"transform with a matrix\"\nmsgstr \"行列を使用して変換します\"\n\n#: ../../quad.rst:26 6235ae5796024a74a6be5aa7991d9d4e\nmsgid \":meth:`Quad.morph`\"\nmsgstr \"\"\n\n#: ../../quad.rst:26 ee610799d4d446bc8e8b0e6c5bbbb1d6\nmsgid \"transform with a point and matrix\"\nmsgstr \"ポイントと行列を使用して変換します\"\n\n#: ../../quad.rst:27 046b52453a10469e8acd23a2744d436c\nmsgid \":attr:`Quad.ul`\"\nmsgstr \"\"\n\n#: ../../quad.rst:27 6a03caf34312460985dc2fa98abdf184\nmsgid \"upper left point\"\nmsgstr \"左上のポイント\"\n\n#: ../../quad.rst:28 4ccf2ab7cc924c399255bcdbd26f5233\nmsgid \":attr:`Quad.ur`\"\nmsgstr \"\"\n\n#: ../../quad.rst:28 be0476ca60a84fc08b7232ed236c4a76\nmsgid \"upper right point\"\nmsgstr \"右上のポイント\"\n\n#: ../../quad.rst:29 a9835aa97d1b4882af33c92e9119563a\nmsgid \":attr:`Quad.ll`\"\nmsgstr \"\"\n\n#: ../../quad.rst:29 b7fffd7413fc4d0cafb1f629cf052760\nmsgid \"lower left point\"\nmsgstr \"左下のポイント\"\n\n#: ../../quad.rst:30 c28f7725993c42398e1efe0361e4cd0c\nmsgid \":attr:`Quad.lr`\"\nmsgstr \"\"\n\n#: ../../quad.rst:30 928da6d5fb114af49b9f822994eeca25\nmsgid \"lower right point\"\nmsgstr \"右下のポイント\"\n\n#: ../../quad.rst:31 b6205ef513fc4875b98f196a42177c78\nmsgid \":attr:`Quad.is_convex`\"\nmsgstr \"\"\n\n#: ../../quad.rst:31 5b826a02006c4d41b209de06b14a5189\nmsgid \"true if quad is a convex set\"\nmsgstr \"四角形が凸集合である場合は true\"\n\n#: ../../quad.rst:32 51d60aeda5e54bcbaf2e39b528354d95\nmsgid \":attr:`Quad.is_empty`\"\nmsgstr \"\"\n\n#: ../../quad.rst:32 352c6bcfc0894aaeb7400e72b81e1e94\nmsgid \"true if quad is an empty set\"\nmsgstr \"四角形が空の集合である場合は true\"\n\n#: ../../quad.rst:33 36eca873465943169ce2e899cbb1a5e6\nmsgid \":attr:`Quad.is_rectangular`\"\nmsgstr \"\"\n\n#: ../../quad.rst:33 bc110a7f43304b5f9cf4b9e5f348d237\nmsgid \"true if quad is congruent to a rectangle\"\nmsgstr \"四角形が長方形と合同である場合は true\"\n\n#: ../../quad.rst:34 42b941820433460aa6e4f0939cbd93a7\nmsgid \":attr:`Quad.rect`\"\nmsgstr \"\"\n\n#: ../../quad.rst:34 6870fe5a0464469ab8425e8f89f7a530\nmsgid \"smallest containing :ref:`Rect`\"\nmsgstr \"最も小さい包含 :ref:`Rect`\"\n\n#: ../../quad.rst:35 79aa77876e4d45a289d673fe00a95995\nmsgid \":attr:`Quad.width`\"\nmsgstr \"\"\n\n#: ../../quad.rst:35 1082a3b6b72b40888b3797974c6f1191\nmsgid \"the longest width value\"\nmsgstr \"最も長い幅の値\"\n\n#: ../../quad.rst:36 7a4558a4427841528a563259add0a04b\nmsgid \":attr:`Quad.height`\"\nmsgstr \"\"\n\n#: ../../quad.rst:36 a3081f95dafb42188a9b34f2e0664367\nmsgid \"the longest height value\"\nmsgstr \"最も長い高さの値\"\n\n#: ../../quad.rst:39 b2cf4d9a187b48ff8960c68e29a2f5ce\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../quad.rst:51 5500a6189d9147a996038ae4dccde288\nmsgid \"\"\n\"Overloaded constructors: \\\"ul\\\", \\\"ur\\\", \\\"ll\\\", \\\"lr\\\" stand for \"\n\":data:`point_like` objects (the four corners), \\\"sequence\\\" is a Python \"\n\"sequence with four :data:`point_like` objects.\"\nmsgstr \"\"\n\"オーバーロードされたコンストラクター: \\\"ul\\\"、\\\"ur\\\"、\\\"ll\\\"、\\\"lr\\\"は :data:`point_like` \"\n\"オブジェクト（4つの角）を表し、\\\"sequence\\\" は4つの :data:`point_like` \"\n\"オブジェクトを持つPythonのシーケンスです。\"\n\n#: ../../quad.rst:53 93948e27f11149d3b2de812391df3cbe\nmsgid \"If \\\"quad\\\" is specified, the constructor creates a **new copy** of it.\"\nmsgstr \"\\\"quad\\\" が指定されている場合、コンストラクターはそれの **新しいコピー** を作成します。\"\n\n#: ../../quad.rst:55 f2671c8b3169475cb8037f714c6b1f02\nmsgid \"\"\n\"Without parameters, a quad consisting of 4 copies of *Point(0, 0)* is \"\n\"created.\"\nmsgstr \"パラメーターが指定されていない場合、4つの *Point(0, 0)* のコピーからなる四角形が作成されます。\"\n\n#: ../../quad.rst:60 111c1f817d0f46f4a18dcfd6c663c18a\nmsgid \"\"\n\"Modify the quadrilateral by transforming each of its corners with a \"\n\"matrix.\"\nmsgstr \"四角形の各角を行列で変換して四角形を変更します。\"\n\n#: ../../quad.rst 8266d43d9f56420bb2aa23d082c0b121\n#: 8b1eac95560f446b8e20b55dd12a6816\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../quad.rst:62 ../../quad.rst:69 0d634d4d35d54c30baabad227f22028f\n#: 9a047b3f95b14bb7b64ad40042d33edf\nmsgid \"the matrix.\"\nmsgstr \"行列。\"\n\n#: ../../quad.rst:66 3267067416df4dd8b8c8377a0d0e60c2\nmsgid \"\"\n\"*(New in version 1.17.0)* \\\"Morph\\\" the quad with a matrix-like using a \"\n\"point-like as fixed point.\"\nmsgstr \"*(バージョン1.17.0で新たに導入)* マトリクスのようなものを使用して四角形を\\\"変形\\\"させ、固定ポイントとしてポイントライクを使用します。\"\n\n#: ../../quad.rst:68 d59f47deb52f43bbaac3720001127772\nmsgid \"the point.\"\nmsgstr \"ポイント。\"\n\n#: ../../quad.rst aa094e5057b24cf88c8f90ad40d9a6cb\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../quad.rst:70 c0beb373c7644f0aa60225c4310d6f7e\nmsgid \"a new quad (no operation if this is the infinite quad).\"\nmsgstr \"新しい四角形（これが無限の四角形の場合、操作は行われません）。\"\n\n#: ../../quad.rst:75 dddc8689476548da8e50846d44537f2d\nmsgid \"\"\n\"The smallest rectangle containing the quad, represented by the blue area \"\n\"in the following picture.\"\nmsgstr \"四角形を含む最小の長方形で、以下の図の青い領域で表されます。\"\n\n#: ../../quad.rst 0d91757c4c9c4ded9d29ce0f2a2c7b6e\n#: 25ea7b95ca1c470bbd0c8c43d4724eb8 3608dfc13924419a90f0f72f4942d4bb\n#: 46bbb10a82e94600b8fc797424ddd669 47c64c1542614109b19d7cfe7ff52b48\n#: 8c84322b6cca4f0aaeb2da2b9c139ad2 9c0e2fe975e94117ad5671c3ae223f92\n#: d3ab357c8c344e4fbbffbbf6e592d8f7 d6db0b6368ce47b28d082a226b28263e\n#: ea8761efdea544869198ae33343519b9\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../quad.rst:79 a447749ed60c435c945ea6d5ac0e1531\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../quad.rst:83 44f1f1d4404e42f0a16619c78d94e880\nmsgid \"Upper left point.\"\nmsgstr \"左上のポイント\"\n\n#: ../../quad.rst:85 ../../quad.rst:91 ../../quad.rst:97 ../../quad.rst:103\n#: 03736f05a8f5421189f98f0b2563c031 a6060101e92f44bf89658804e52b0c6c\n#: cd76cb6712a84b878c58e674036c6b57 e745c97cd50f406d99f625378bc07267\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../quad.rst:89 a15d9aa488ac46398e1300d7a621789d\nmsgid \"Upper right point.\"\nmsgstr \"右上のポイント\"\n\n#: ../../quad.rst:95 e58949b5a6124ea7b84c82246b331fa5\nmsgid \"Lower left point.\"\nmsgstr \"左下のポイント\"\n\n#: ../../quad.rst:101 459751b609574eee8992e1f4ed63a8be\nmsgid \"Lower right point.\"\nmsgstr \"右下のポイント\"\n\n#: ../../quad.rst:107 42081dff926d4b2dbfc85eebd7c6b91c\nmsgid \"New in version 1.16.1\"\nmsgstr \"新しいバージョン1.16.1で追加されました\"\n\n#: ../../quad.rst:109 18727351228e45f18f66be1e6b1a0431\nmsgid \"\"\n\"Checks if for any two points of the quad, all points on their connecting \"\n\"line also belong to the quad.\"\nmsgstr \"このクアッドの任意の2点について、それらを結ぶ直線上のすべての点もこのクアッドに属するかどうかをチェックします。\"\n\n#: ../../quad.rst:114 ../../quad.rst:120 ../../quad.rst:126\n#: 269c1e4494824e2cb5936c9aeaae79e7 c41948d6f881462aac8ced961485b1ec\n#: dea8b14143c94257a8c383e3f0c1f9a2\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../quad.rst:118 fb252aa17185476b93956d6738fff2e7\nmsgid \"\"\n\"True if enclosed area is zero, which means that at least three of the \"\n\"four corners are on the same line. If this is false, the quad may still \"\n\"be degenerate or not look like a tetragon at all (triangles, \"\n\"parallelograms, trapezoids, ...).\"\nmsgstr \"\"\n\"Enclosed \"\n\"areaがゼロの場合はTrueで、これは4つの角のうち少なくとも3つが同じ直線上にあることを意味します。これがfalseの場合、クアッドは依然として退化しているか、全くテトラゴンのようには見えないかもしれません（三角形、平行四辺形、台形など）。\"\n\n#: ../../quad.rst:124 df1dab125bdf4e06b610448db4325b06\nmsgid \"\"\n\"True if all corner angles are 90 degrees. This implies that the quad is \"\n\"**convex and not empty**.\"\nmsgstr \"4つの角のすべての角度が90度の場合はTrueです。これは、クアッドが **凸面であり、空ではない** ことを意味します。\"\n\n#: ../../quad.rst:130 4f39bb3710a4402da4e1c2a2d8e7f5f4\nmsgid \"The maximum length of the top and the bottom side.\"\nmsgstr \"上辺と下辺の最大の長さ。\"\n\n#: ../../quad.rst:132 ../../quad.rst:138 dbf8525cf293442a8ac2170ef5d5830b\n#: dc2fb941fd18465297cb72af2629fce0\nmsgid \"float\"\nmsgstr \"\"\n\n#: ../../quad.rst:136 637d9c47fc5448c6b6b12ed59410f8cf\nmsgid \"The maximum length of the left and the right side.\"\nmsgstr \"上辺と下辺の最大の長さ。\"\n\n#: ../../quad.rst:141 deee9fb98ab34d4494ac466fabaea29d\nmsgid \"Remark\"\nmsgstr \"リマーク\"\n\n#: ../../quad.rst:142 1b61ac0c866a4df28afb4a722645cf08\nmsgid \"\"\n\"This class adheres to the sequence protocol, so components can be dealt \"\n\"with via their indices, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"\"\n\"このクラスはシーケンスプロトコルに従っており、要素にはインデックスを使用できます。また、:ref:`SequenceTypes` \"\n\"を参照してください。\"\n\n#: ../../quad.rst:145 6215145a706f4cd4a73d3ab4595807a9\nmsgid \"Algebra and Containment Checks\"\nmsgstr \"代数と包含チェック\"\n\n#: ../../quad.rst:146 fb0679a33ccb4fdb98427f9407938675\nmsgid \"\"\n\"Starting with v1.19.6, quads can be used in algebraic expressions like \"\n\"the other geometry object -- the respective restrictions have been \"\n\"lifted. In particular, all the following combinations of containment \"\n\"checking are now possible:\"\nmsgstr \"\"\n\"v1.19.6から、クアッドは他のジオメトリオブジェクトと同様に代数的な式で使用できるようになりました - \"\n\"対応する制限が解除されました。特に、次の包含チェックの組み合わせがすべて可能になりました。\"\n\n#: ../../quad.rst:148 0e4401adcb5f4fc485e655c876a8ae28\nmsgid \"`{Point | IRect | Rect | Quad} in {IRect | Rect | Quad}`\"\nmsgstr \"\"\n\n#: ../../quad.rst:150 7f8244052cb6402a939f0594f0b6a759\nmsgid \"Please note the following interesting detail:\"\nmsgstr \"次の興味深い詳細に注意してください：\"\n\n#: ../../quad.rst:152 9671396ad46747c2ae802633663007ee\nmsgid \"\"\n\"For a rectangle, only its top-left point belongs to it. Since v1.19.0, \"\n\"rectangles are defined to be \\\"open\\\", such that its bottom and its right\"\n\" edge do not belong to it -- including the respective corners. But for \"\n\"quads there exists no such notion like \\\"openness\\\", so we have the \"\n\"following somewhat surprising implication:\"\nmsgstr \"\"\n\"長方形の場合、その上辺のみがそれに属しています。v1.19.0以降、長方形は「オープン」であると定義されており、その底辺と右端はそれに属していません\"\n\" - それには対応する角も含まれます。しかし、クアッドには「オープン」のような概念が存在しないため、次のようなやや驚くべき含意があります：\"\n\n#: ../../footer.rst:60 cc3f6c4d45844fe8ad36b35c6e3bd3ab\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/rag.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 d58a444fc92843a18660ede50d62d095\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 6e2254ee60a14d48a1348f2b46d484d2\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDFは、PDF（およびその他）ドキュメントのデータ抽出、解析、変換、および操作のための高性能なPythonライブラリです。\"\n\n#: ../../header.rst:-1 bc86116b658f4d3fb0e20919e6179a1e\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDF画像抽出、PDF変換、PDFテーブル、PDF分割、PDF作成、Pyodide、PyScript\"\n\n#: ../../rag.rst:6 1e69d82c08b049a6b539ae49ee8df24e\nmsgid \"PyMuPDF, LLM & RAG\"\nmsgstr \"PyMuPDF、LLM、およびRAG\"\n\n#: ../../rag.rst:9 056a5c68abb744c7863c87748f5cc0b1\nmsgid \"\"\n\"Integrating |PyMuPDF| into your :title:`Large Language Model (LLM)` \"\n\"framework and overall :title:`RAG (Retrieval-Augmented Generation`) \"\n\"solution provides the fastest and most reliable way to deliver document \"\n\"data.\"\nmsgstr \"\"\n\"|PyMuPDF| を :title:`大規模言語モデル（LLM）` フレームワークおよび全体的な :title:`RAG（Retrieval-\"\n\"Augmented Generation）` ソリューションに統合することで、文書データを提供する最も高速かつ信頼性の高い方法が提供されます。\"\n\n#: ../../rag.rst:11 fee93922167c4b2d9d9054f8565193f4\nmsgid \"\"\n\"There are a few well known :title:`LLM` solutions which have their own \"\n\"interfaces with |PyMuPDF| - it is a fast growing area, so please let us \"\n\"know if you discover any more!\"\nmsgstr \"\"\n\"いくつかのよく知られた :title:`LLM` ソリューションは、|PyMuPDF| \"\n\"と独自のインターフェースを持っています。この分野は急速に成長しているため、もっと見つけた場合はお知らせください。\"\n\n#: ../../rag.rst:13 87158dfd9b9a4174a93d56546e871f72\nmsgid \"\"\n\"If you need to export to :title:`Markdown` or obtain a \"\n\":title:`LlamaIndex` Document from a file:\"\nmsgstr \":title:`Markdown` へのエクスポートやファイルから :title:`LlamaIndex` ドキュメントを取得する必要がある場合は:\"\n\n#: ../../rag.rst:31 51971a71e3ca420db71fb2080da653ad\nmsgid \"Integration with :title:`LangChain`\"\nmsgstr \":title:`LangChain` との統合\"\n\n#: ../../rag.rst:33 9e2065dc5185491abcf869e4a276c5be\nmsgid \"\"\n\"It is simple to integrate directly with :title:`LangChain` by using their\"\n\" dedicated loader as follows:\"\nmsgstr \":title:`LangChain` の専用ローダーを使用して直接統合するのは簡単です。以下のようにします：\"\n\n#: ../../rag.rst:43 236dcfb83a264f6c83e921a7905a29bc\nmsgid \"\"\n\"See `LangChain Using PyMuPDF \"\n\"<https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf\"\n\"/#using-pymupdf>`_ for full details.\"\nmsgstr \"\"\n\"`LangChainを完全に利用する詳細については、PyMuPDF \"\n\"<https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf\"\n\"/#using-pymupdf>`_ を参照してください。\"\n\n#: ../../rag.rst:47 f9ce52737bda4fc5b4075b6ad14b9e2e\nmsgid \"Integration with :title:`LlamaIndex`\"\nmsgstr \":title:`LlamaIndex` との統合\"\n\n#: ../../rag.rst:50 1b7d2270a3c74a44b70efbcee8b0d37f\nmsgid \"\"\n\"Use the dedicated `PyMuPDFReader` from :title:`LlamaIndex` 🦙 to manage \"\n\"your document loading.\"\nmsgstr \":title:`LlamaIndex` 🦙 の専用 `PyMuPDFReader` を使用して、文書の読み込みを管理します。\"\n\n#: ../../rag.rst:58 40923d58ee41475bb0ee10e7014a578a\nmsgid \"\"\n\"See `Building RAG from Scratch \"\n\"<https://docs.llamaindex.ai/en/stable/examples/low_level/oss_ingestion_retrieval>`_\"\n\" for more.\"\nmsgstr \"\"\n\"詳細は、 `ゼロからRAGを構築する \"\n\"<https://docs.llamaindex.ai/en/stable/examples/low_level/oss_ingestion_retrieval>`_\"\n\"  をご覧ください。\"\n\n#: ../../rag.rst:62 3055cf26690d4e289489b37eaf7b5333\nmsgid \"Preparing Data for Chunking\"\nmsgstr \"データのチャンキングの準備\"\n\n#: ../../rag.rst:64 e37920b16364455dad472a5c99218cda\nmsgid \"\"\n\"Chunking (or splitting) data is essential to give context to your \"\n\":title:`LLM` data and with :title:`Markdown` output now supported by \"\n\"|PyMuPDF| this means that `Level 3 chunking \"\n\"<https://medium.com/@anuragmishra_27746/five-levels-of-chunking-\"\n\"strategies-in-rag-notes-from-gregs-video-7b735895694d#b123>`_ is \"\n\"supported.\"\nmsgstr \"\"\n\"データのチャンキング（または分割）は、:title:`LLM` データに文脈を与えるために不可欠であり、|PyMuPDF| が \"\n\":title:`Markdown` 出力をサポートするようになったことで、`レベル3のチャンキング \"\n\"<https://medium.com/@anuragmishra_27746/five-levels-of-chunking-\"\n\"strategies-in-rag-notes-from-gregs-video-7b735895694d#b123>`_ \"\n\"がサポートされることを意味します。\"\n\n#: ../../rag.rst:71 9a8d957771b04869afd1441e12a280be\nmsgid \"Outputting as :title:`Markdown`\"\nmsgstr \":title:`Markdown` 形式で出力\"\n\n#: ../../rag.rst:73 6076246f267449deace88b822ddabfe0\n#, fuzzy\nmsgid \"\"\n\"In order to export your document in :title:`Markdown` format you will \"\n\"need a separate helper. Package :doc:`pymupdf4llm/index` is a high-level \"\n\"wrapper of |PyMuPDF| functions which for each page outputs standard and \"\n\"table text in an integrated Markdown-formatted string across all document\"\n\" pages:\"\nmsgstr \"\"\n\":title:`Markdown` 形式で文書をエクスポートするには、別途のヘルパーが必要です。パッケージ `pymupdf4llm \"\n\"<https://pypi.org/project/pymupdf4llm/>`_ \"\n\"は、各ページに対して標準テキストとテーブルテキストを統合されたMarkdown形式の文字列で出力する、|PyMuPDF| \"\n\"関数の高レベルなラッパーです。\"\n\n#: ../../rag.rst:87 58590b8ebc244b9db1cc83c63adc2d1b\n#, fuzzy\nmsgid \"For further information please refer to: :doc:`pymupdf4llm/index`.\"\nmsgstr \"\"\n\"詳細については、次を参照してください： `pymupdf4llmのドキュメント \"\n\"<https://pymupdf4llm.readthedocs.io>`_。\"\n\n#: ../../rag.rst:91 b32a1b079e794491a5e021d26fb18453\nmsgid \"How to use :title:`Markdown` output\"\nmsgstr \":title:`Markdown` 出力の使用方法\"\n\n#: ../../rag.rst:93 8045470b5fa04886b83960e80fc71aae\nmsgid \"\"\n\"Once you have your data in :title:`Markdown` format you are ready to \"\n\"chunk/split it and supply it to your :title:`LLM`, for example, if this \"\n\"is :title:`LangChain` then do the following:\"\nmsgstr \"\"\n\":title:`Markdown` 形式のデータが準備できたら、データをチャンク化/分割して :title:`LLM` \"\n\"に供給する準備が整います。例えば、:title:`LangChain` の場合は、次の手順を行います。\"\n\n#: ../../rag.rst:109 4d0c5d7c2dc04c059fbdb5ad0709c2af\nmsgid \"\"\n\"For more see `5 Levels of Text Splitting <https://github.com\"\n\"/FullStackRetrieval-\"\n\"com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb>`_\"\nmsgstr \"\"\n\"詳細は `「テキスト分割の5レベル」 <https://github.com/FullStackRetrieval-\"\n\"com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb>`_\"\n\"  を参照してください。\"\n\n#: ../../rag.rst:113 896b1dd74ff24363becbdac98144b86c\nmsgid \"Related Blogs\"\nmsgstr \"関連ブログ\"\n\n#: ../../rag.rst:115 a036501ebb68414192f47e189aec5f3d\nmsgid \"\"\n\"To find out more about |PyMuPDF|, :title:`LLM` & :title:`RAG` check out \"\n\"our blogs for implementations & tutorials.\"\nmsgstr \"\"\n\"|PyMuPDF| 、 :title:`LLM` 、および :title:`RAG` \"\n\"について詳しく知りたい場合は、実装やチュートリアルに関するブログをチェックしてください。\"\n\n#: ../../rag.rst:119 a8b36bcfa4c746e4b21ffd62e4c38618\nmsgid \"Methodologies to Extract Text\"\nmsgstr \"テキストを抽出するための方法論\"\n\n#: ../../rag.rst:121 f69b739e4b764e0b856de55aa7f97093\nmsgid \"\"\n\"`Enhanced Text Extraction <https://artifex.com/blog/rag-llm-and-pdf-\"\n\"enhanced-text-extraction>`_\"\nmsgstr \"`テキスト抽出の強化 <https://qiita.com/jamie-lemon/items/455e14f83b4f5c81034b>`_ \"\n\n#: ../../rag.rst:122 3ae24a0e46354d408bcdaf4deb16af33\nmsgid \"\"\n\"`Conversion to Markdown Text with PyMuPDF <https://artifex.com/blog/rag-\"\n\"llm-and-pdf-conversion-to-markdown-text-with-pymupdf>`_\"\nmsgstr \"\"\n\"`PyMuPDFを使用したMarkdownテキストへの変換 <https://qiita.com/jamie-\"\n\"lemon/items/1f2eb43f439fd28202a0>`_\"\n\n#: ../../rag.rst:127 bbe057c5d511484c8b9bd0b656c6216c\nmsgid \"Create a Chatbot to discuss your documents\"\nmsgstr \"文書を議論するためのチャットボットを作成する\"\n\n#: ../../rag.rst:129 1255eb5a25064e6c8ae8ca5b8af9b0a4\nmsgid \"\"\n\"`Make a simple command line Chatbot <https://artifex.com/blog/creating-a\"\n\"-rag-chatbot-with-chatgpt-and-pymupdf>`_\"\nmsgstr \"\"\n\"`シンプルなコマンドラインのチャットボットを作成するシンプルなコマンドラインのチャットボットを作成する <https://qiita.com\"\n\"/jamie-lemon/items/df6703906392ae8295f3>`_\"\n\n#: ../../rag.rst:130 569c7f488bc747a2801a4b6532a9c3dd\nmsgid \"\"\n\"`Make a Chatbot GUI <https://artifex.com/blog/building-a-rag-chatbot-gui-\"\n\"with-the-chatgpt-api-and-pymupdf>`_\"\nmsgstr \"\"\n\"`チャットボットGUIを作成する <https://qiita.com/jamie-\"\n\"lemon/items/f075ae56cf56723c9409>`_\"\n\n#: ../../footer.rst:60 45a2c818f8ae4c1fa455751e51ab3e21\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは、|version| までのすべてのバージョンをカバーしています。\"\n\n#~ msgid \"If you need to export to :title:`Markdown`:\"\n#~ msgstr \":title:`Markdown` にエクスポートする必要がある場合：\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-annotations.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 d1ad502e2163461abd37b8e0afad7b09\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 9b5018bc6d0347e3ac0dca7c86ee8578\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 9215720d8e8043e38ff196c7e9cfe5f0\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-annotations.rst:7 43c8624c55e14be2aac3624caf95357e\nmsgid \"Annotations\"\nmsgstr \"注釈\"\n\n#: ../../recipes-annotations.rst:12 3eb67bbfa6584d6e8bfe087440a64e64\nmsgid \"How to Add and Modify Annotations\"\nmsgstr \"注釈の追加と変更方法\"\n\n#: ../../recipes-annotations.rst:14 0e7efcdb24c74719b4c01251f4a59aa5\nmsgid \"\"\n\"In |PyMuPDF|, new annotations can be added via :ref:`Page` methods. Once \"\n\"an annotation exists, it can be modified to a large extent using methods \"\n\"of the :ref:`Annot` class.\"\nmsgstr \"\"\n\"PyMuPDFでは、新しい注釈を :ref:`Page` メソッドを介して追加することができます。一度注釈が存在すると、 :ref:`Annot`\"\n\" クラスのメソッドを使用して大幅に変更できます。\"\n\n#: ../../recipes-annotations.rst:16 2bf001f41c6b451b9937901bb58f7e23\nmsgid \"\"\n\"Annotations can **only** be inserted in |PDF| pages - other document \"\n\"types do not support annotation insertion.\"\nmsgstr \"注釈は PDF ページにのみ 挿入可能です。他のドキュメント形式では、注釈の挿入はサポートされていません。\"\n\n#: ../../recipes-annotations.rst:18 ba516eb1a56945e5a9bac7e9fa24fed1\nmsgid \"\"\n\"In contrast to many other tools, initial insert of annotations happens \"\n\"with a minimum number of properties. We leave it to the programmer to \"\n\"e.g. set attributes like author, creation date or subject.\"\nmsgstr \"他の多くのツールとは異なり、注釈の初期挿入は最小限のプロパティで行われます。例えば、著者、作成日、サブジェクトなどの属性をプログラマーが設定することができます。\"\n\n#: ../../recipes-annotations.rst:20 bc78178891f1440fbfa8e0aaff01e11c\nmsgid \"\"\n\"As an overview for these capabilities, look at the following script that \"\n\"fills a PDF page with most of the available annotations. Look in the next\"\n\" sections for more special situations:\"\nmsgstr \"これらの機能の概要については、次のスクリプトを参照してください。このスクリプトはPDFページに利用可能な注釈のほとんどを埋めるものです。より特殊な状況については、次のセクションをご覧ください。\"\n\n#: ../../recipes-annotations.rst:26 c8504dce5bb44372b1c68fe8f9b98fb7\nmsgid \"This script should lead to the following output:\"\nmsgstr \"このスクリプトは次のような出力を生成します：\"\n\n#: ../../recipes-annotations.rst:36 96b9bb9ba45a444c973060143fc425cf\nmsgid \"How to Use FreeText\"\nmsgstr \"FreeTextの使用方法\"\n\n#: ../../recipes-annotations.rst:37 e91fc84e2d79457190b40cbf621719b3\nmsgid \"\"\n\"This script shows a couple of basic ways to deal with 'FreeText' \"\n\"annotations:\"\nmsgstr \"このスクリプトは、'FreeText'注釈を扱ういくつかの方法を示しています::\"\n\n#: ../../recipes-annotations.rst:41 ../../recipes-annotations.rst:50\n#: 2cdef3691b1341f4a6850d9d8de067bb 350586a50d5144a2b8d9db627bd71e24\nmsgid \"The result looks like this:\"\nmsgstr \"結果は次のようになります。\"\n\n#: ../../recipes-annotations.rst:46 e86ede73d664430791e03da9a5d63702\nmsgid \"Here is an example for using rich text and call-out lines:\"\nmsgstr \"\"\n\n#: ../../recipes-annotations.rst:63 f49b197275794adaa27d02d5ac0b32cf\nmsgid \"How to Use Ink Annotations\"\nmsgstr \"インク注釈の使用方法\"\n\n#: ../../recipes-annotations.rst:64 e0df9dc619c746da9593612a87cd3f0a\nmsgid \"\"\n\"Ink annotations are used to contain freehand scribbling. A typical \"\n\"example may be an image of your signature consisting of first name and \"\n\"last name. Technically an ink annotation is implemented as a **list of \"\n\"lists of points**. Each point list is regarded as a continuous line \"\n\"connecting the points. Different point lists represent independent line \"\n\"segments of the annotation.\"\nmsgstr \"インク注釈は、自由な手書きの落書きを含むために使用されます。典型的な例として、名前と姓からなる署名の画像が挙げられます。技術的には、インク注釈は点のリストのリストとして実装されます。各点のリストは、点を結んだ連続的な線と見なされます。異なる点のリストは、注釈の独立した線セグメントを表します。\"\n\n#: ../../recipes-annotations.rst:66 dbdd441a25c44bd4aae5f2367cf85f3d\n#, fuzzy\nmsgid \"\"\n\"The following script creates an ink annotation with two mathematical \"\n\"curves (sine and cosine function graphs) as line segments:\"\nmsgstr \"以下のスクリプトは、二つの数学的な曲線（正弦関数と余弦関数のグラフ）を線セグメントとして持つインク注釈を作成します::\"\n\n#: ../../recipes-annotations.rst:70 bb6171a96157475f875163c29bc8e76f\nmsgid \"This is the result:\"\nmsgstr \"これが結果です：\"\n\n#: ../../footer.rst:60 79b679f62bef466ea3444589a3f3ef6f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Using Buttons and JavaScript\"\n#~ msgstr \"ボタンとJavaScriptの使用\"\n\n#~ msgid \"\"\n#~ \"Since MuPDF v1.16, 'FreeText' annotations \"\n#~ \"no longer support bold or italic \"\n#~ \"versions of the Times-Roman, Helvetica\"\n#~ \" or Courier fonts.\"\n#~ msgstr \"\"\n#~ \"MuPDF v1.16以降、'FreeText'注釈はもはやTimes-\"\n#~ \"Roman、Helvetica、Courierフォントの太字や斜体バージョンをサポートしていません。\"\n\n#~ msgid \"\"\n#~ \"A big **thank you** to our user\"\n#~ \" `@kurokawaikki <https://github.com/kurokawaikki>`_, \"\n#~ \"who contributed the following script to\"\n#~ \" **circumvent this restriction**.\"\n#~ msgstr \"\"\n#~ \"この制限を回避するために、次のスクリプトを提供してくれたユーザー `@kurokawaikki \"\n#~ \"<https://github.com/kurokawaikki>`_ さんに心から感謝します。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-common-issues-and-their-solutions.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4668aba35041418d9985c1a35575a6b3\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 1011e86add0c4e648dea40533c7fd1a2\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 10324b8854a4413791056120093832e9\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:7\n#: 20bc28cec0154c7c9136122bd912f369\nmsgid \"Common Issues and their Solutions\"\nmsgstr \"一般的な問題とその解決方法\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:10\n#: 7f1290c0169445d78461fff755cfc034\nmsgid \"How To Dynamically Clean Up Corrupt :title:`PDFs`\"\nmsgstr \"壊れた |PDF| を動的にクリーンアップする方法\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:12\n#: ce6827f92d194d24abb5efce34f05be9\nmsgid \"\"\n\"This shows a potential use of |PyMuPDF| with another Python PDF library \"\n\"(the excellent pure Python package `pdfrw \"\n\"<https://pypi.python.org/pypi/pdfrw>`_ is used here as an example).\"\nmsgstr \"\"\n\"これは、別のPython PDFライブラリ（素晴らしい純粋なPythonパッケージである `pdfrw \"\n\"<https://pypi.python.org/pypi/pdfrw>`_ \"\n\"を例として使用しています）と組み合わせてPyMuPDFを潜在的に使用する方法を示しています。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:14\n#: 4b79f85178e14c0bada317304b337db0\nmsgid \"\"\n\"If a clean, non-corrupt / decompressed PDF is needed, one could \"\n\"dynamically invoke PyMuPDF to recover from many problems like so::\"\nmsgstr \"\"\n\"クリーンで壊れていない / \"\n\"解凍されていないPDFが必要な場合、次のようにしてPyMuPDFを動的に呼び出して多くの問題から回復することができます::\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:50\n#: e6d9c9e53bdc4e6ea4fff95948a77ce0\nmsgid \"\"\n\"With the command line utility *pdftk* (`available \"\n\"<https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/>`_ for Windows \"\n\"only, but reported to also run under `Wine <https://www.winehq.org/>`_) a\"\n\" similar result can be achieved, see `here \"\n\"<http://www.overthere.co.uk/2013/07/22/improving-pypdf2-with-pdftk/>`_. \"\n\"However, you must invoke it as a separate process via *subprocess.Popen*,\"\n\" using stdin and stdout as communication vehicles.\"\nmsgstr \"\"\n\"コマンドラインユーティリティ `pdftk <https://www.pdflabs.com/tools/pdftk-the-pdf-\"\n\"toolkit/>`_ （Windowsのみで利用可能ですが、 `Wine <https://www.winehq.org/>`_ \"\n\"下でも動作すると報告されています）を使用すると、類似の結果を得ることができます。詳細は `こちら \"\n\"<http://www.overthere.co.uk/2013/07/22/improving-pypdf2-with-pdftk/>`_ \"\n\"をご覧ください。ただし、stdinとstdoutを通信手段として使用して別のプロセスとしてsubprocess.Popenを介して呼び出す必要があります。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:55\n#: 3f9ab9bf78a74d9781937269cf8ef3cb\nmsgid \"How to Convert Any Document to |PDF|\"\nmsgstr \"どの文書も |PDF| に変換する方法\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:57\n#: ca2811011d7b40808c8a55f65188b25f\nmsgid \"\"\n\"Here is a script that converts any |PyMuPDF| :ref:`supported \"\n\"document<Supported_File_Types>` to a |PDF|. These include XPS, EPUB, FB2,\"\n\" CBZ and image formats, including multi-page TIFF images.\"\nmsgstr \"\"\n\"以下は、任意のPyMuPDFが :ref:`サポートされている <Supported_File_Types>` \"\n\"文書をPDFに変換するスクリプトです。これにはXPS、EPUB、FB2、CBZ、および複数ページのTIFFイメージを含む画像フォーマットが含まれます。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:59\n#: d7e2dfdcb75b40739daf46856a819f58\nmsgid \"\"\n\"It features maintaining any metadata, table of contents and links \"\n\"contained in the source document::\"\nmsgstr \"これにはソース文書に含まれるメタデータ、目次、リンクを保持する機能が備わっています::\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:131\n#: a41bc630ff314f64bcfa4150a08c3c84\nmsgid \"Changing Annotations: Unexpected Behaviour\"\nmsgstr \"注釈の変更：予期しない動作\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:134\n#: 9b87b714c12948aa94ae2868604c760c\nmsgid \"Problem\"\nmsgstr \"問題\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:135\n#: 5870f9a9b1184a3cb1849e71b71e5026\nmsgid \"There are two scenarios:\"\nmsgstr \"2つのシナリオがあります：\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:137\n#: b360eb295e35468b9a48ce456cc717e7\nmsgid \"\"\n\"**Updating** an annotation with PyMuPDF which was created by some other \"\n\"software.\"\nmsgstr \"他のソフトウェアで作成された注釈をPyMuPDFで**更新**する。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:138\n#: c2f4bd673f784318906b6982c2873fdf\nmsgid \"\"\n\"**Creating** an annotation with PyMuPDF and later changing it with some \"\n\"other software.\"\nmsgstr \"PyMuPDFで注釈を**作成**し、後で他のソフトウェアで変更する。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:140\n#: 3a2c5f9ca0da4058b2119d1e5ee6432c\nmsgid \"\"\n\"In both cases you may experience unintended changes, like a different \"\n\"annotation icon or text font, the fill color or line dashing have \"\n\"disappeared, line end symbols have changed their size or even have \"\n\"disappeared too, etc.\"\nmsgstr \"どちらの場合でも、異なる注釈アイコンやテキストフォント、塗りつぶしの色や線の破線が消えたり、線の端のシンボルのサイズが変わったり、さらには消えたりするなど、意図しない変更が発生する可能性があります。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:143\n#: ../../recipes-common-issues-and-their-solutions.rst:182\n#: ../../recipes-common-issues-and-their-solutions.rst:195\n#: 0ec3d7b289ed40d1b1c9a6e6509cb81c 3db222ba67d34ffe8b9c76049639a28f\n#: 4947608029184f4eacde97cb22e6b0a0\nmsgid \"Cause\"\nmsgstr \"原因\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:144\n#: 580b99ed7b294df89844c876e4930bb6\nmsgid \"\"\n\"Annotation maintenance is handled differently by each PDF maintenance \"\n\"application. Some annotation types may not be supported, or not be \"\n\"supported fully or some details may be handled in a different way than in\"\n\" another application. **There is no standard.**\"\nmsgstr \"注釈の保守は、各PDF保守アプリケーションごとに異なる方法で処理されます。一部の注釈タイプはサポートされないか、完全にはサポートされていない場合もあり、また、他のアプリケーションとは異なる方法で詳細が処理される場合もあります。標準規格は存在しません。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:146\n#: 0d39ed4b97424a2a87eb4bec722728b0\nmsgid \"\"\n\"Almost always a PDF application also comes with its own icons (file \"\n\"attachments, sticky notes and stamps) and its own set of supported text \"\n\"fonts. For example:\"\nmsgstr \"ほとんどの場合、PDFアプリケーションには独自のアイコン（ファイル添付、付箋、スタンプなど）とサポートされるテキストフォントのセットが付属しています。例えば：\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:148\n#: 65134846c0a240acb342d722b107de3f\nmsgid \"\"\n\"(Py-) MuPDF only supports these 5 basic fonts for 'FreeText' annotations:\"\n\" Helvetica, Times-Roman, Courier, ZapfDingbats and Symbol -- no italics /\"\n\" no bold variations. When changing a 'FreeText' annotation created by \"\n\"some other app, its font will probably not be recognized nor accepted and\"\n\" be replaced by Helvetica.\"\nmsgstr \"\"\n\"(Py-) MuPDFは、'FreeText'注釈に対してこれらの5つの基本フォントのみをサポートしています：Helvetica、Times-\"\n\"Roman、Courier、ZapfDingbats、Symbol - 斜体や太字のバリエーションはありません。他のアプリで作成された \"\n\"'FreeText' 注釈を変更する際、そのフォントはおそらく認識されず、Helveticaに置き換えられる可能性があります。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:150\n#: e2cbd8bfb3d14500a0612d1d8d2c5ec6\nmsgid \"\"\n\"PyMuPDF supports all PDF text markers (highlight, underline, strikeout, \"\n\"squiggly), but these types cannot be updated with Adobe Acrobat Reader.\"\nmsgstr \"\"\n\"PyMuPDFはすべてのPDFテキストマーカー（ハイライト、下線、取り消し線、波線）をサポートしていますが、これらのタイプはAdobe \"\n\"Acrobat Readerで更新することはできません。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:152\n#: 5f42aed9c005492a92b5b6aa0cbcd03e\nmsgid \"\"\n\"In most cases there also exists limited support for line dashing which \"\n\"causes existing dashes to be replaced by straight lines. For example:\"\nmsgstr \"ほとんどの場合、破線には限定的なサポートが存在し、既存の破線が直線に置き換えられることがあります。例えば：\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:154\n#: 7651dba336694614afc84cba3418f5cc\nmsgid \"\"\n\"PyMuPDF fully supports all line dashing forms, while other viewers only \"\n\"accept a limited subset.\"\nmsgstr \"PyMuPDFはすべての線の破線形式を完全にサポートしていますが、他のビューアは一部の形式しか受け入れません。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:158\n#: 01eaf095c9b6491d88ab187baa0e5739\nmsgid \"Solutions\"\nmsgstr \"解決策\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:159\n#: ecb162091bfd40ba807179842faf6a91\nmsgid \"Unfortunately there is not much you can do in most of these cases.\"\nmsgstr \"残念ながら、これらの多くの場合、あまり対処できることはありません。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:161\n#: f4ff16b309524593aafb3a90fa47384c\nmsgid \"Stay with the same software for **creating and changing** an annotation.\"\nmsgstr \"注釈の作成と変更に同じソフトウェアを使用してください。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:162\n#: ddc8bae66d8249efbc79df236e51d0d0\nmsgid \"\"\n\"When using PyMuPDF to change an \\\"alien\\\" annotation, try to **avoid** \"\n\":meth:`Annot.update`. The following methods **can be used without it,** \"\n\"so that the original appearance should be maintained:\"\nmsgstr \"\"\n\"\\\"異なる\\\"注釈を変更する際にPyMuPDFを使用する場合、:meth:`Annot.update` \"\n\"を避けるようにしてください。次のメソッドは、元の外観を維持するために、:meth:`Annot.update` を使用せずに使用できます：\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:164\n#: 57c092ce6a7d45d4952de8c67279fa4f\nmsgid \":meth:`Annot.set_rect` (location changes)\"\nmsgstr \":meth:`Annot.set_rect` (位置の変更)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:165\n#: d313ef9ae75449729e1849ab57d05a32\nmsgid \":meth:`Annot.set_flags` (annotation behaviour)\"\nmsgstr \":meth:`Annot.set_flags` (注釈の動作)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:166\n#: ff9f33feb2224cd69192417071637524\nmsgid \":meth:`Annot.set_info` (meta information, except changes to *content*)\"\nmsgstr \":meth:`Annot.set_info` (メタ情報、*コンテンツ* の変更以外)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:167\n#: 90c72eaaebfa4a848238a0cd487b74e6\nmsgid \":meth:`Annot.set_popup` (create popup or change its rect)\"\nmsgstr \":meth:`Annot.set_popup` (ポップアップの作成または位置の変更)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:168\n#: fea8fa06e33040f2b13ce9a7b5306f8f\n#, fuzzy\nmsgid \"\"\n\":meth:`Annot.set_oc` (add / remove reference to optional content \"\n\"information)\"\nmsgstr \":meth:`Annot.set_optional_content` (オプションコンテンツ情報への参照の追加/削除)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:169\n#: cee27cf68bda482690d014a3468ad911\nmsgid \":meth:`Annot.set_open`\"\nmsgstr \"\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:170\n#: 85c766ba5c7c4ec9a875af07684f5f8f\nmsgid \":meth:`Annot.update_file` (file attachment changes)\"\nmsgstr \":meth:`Annot.update_file` (ファイル添付の変更)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:174\n#: 6e6d7441feb444b08da4f309c51f2989\nmsgid \"Missing or Unreadable Extracted Text\"\nmsgstr \"欠落または読み取り不可能な抽出テキスト\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:175\n#: 01ae9eb704e14a1e8f24cf021dc91c0e\nmsgid \"\"\n\"Fairly often, text extraction does not work text as you would expect: \"\n\"text may be missing, or may not appear in the reading sequence visible on\"\n\" your screen, or contain garbled characters (like a ? or a \\\"TOFU\\\" \"\n\"symbol), etc. This can be caused by a number of different problems.\"\nmsgstr \"非常にしばしば、テキスト抽出が期待通りに機能しないことがあります。テキストが欠落しているか、画面上で表示される読み取り順序に表示されないか、文字が文字化けしている（「？」や「TOFU」シンボルなど）ことがあります。これはさまざまな問題が原因で起こる可能性があります。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:178\n#: e80411b38d4845d9b2714609a65db94c\nmsgid \"Problem: no text is extracted\"\nmsgstr \"問題：テキストが抽出されない\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:179\n#: 29d32a1dea084e1886b86272d02868c8\nmsgid \"\"\n\"Your PDF viewer does display text, but you cannot select it with your \"\n\"cursor, and text extraction delivers nothing.\"\nmsgstr \"PDFビューアはテキストを表示しているが、カーソルで選択できず、テキストの抽出結果が何も表示されない。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:183\n#: 407916e2cc0148868141e8b6e9837feb\nmsgid \"\"\n\"You may be looking at an image embedded in the PDF page (e.g. a scanned \"\n\"PDF).\"\nmsgstr \"PDFページに埋め込まれた画像を表示している可能性がある（例：スキャンされたPDF）。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:184\n#: 94397a359e604251a6ce3e563fe0ef48\nmsgid \"\"\n\"The PDF creator used no font, but **simulated** text by painting it, \"\n\"using little lines and curves. E.g. a capital \\\"D\\\" could be painted by a\"\n\" line \\\"|\\\" and a left-open semi-circle, an \\\"o\\\" by an ellipse, and so \"\n\"on.\"\nmsgstr \"PDFの作成者がフォントを使用せず、テキストをペイントして小さな線と曲線を使用して模倣している場合がある。たとえば、大文字の「D」は縦棒「|」と左開きの半円で描かれ、「o」は楕円で描かれるなど。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:187\n#: ../../recipes-common-issues-and-their-solutions.rst:200\n#: 4fedb4cf875041c2a5e70dae89f7991f fb8a38a5ca084321aac57be8d1ebb7bb\nmsgid \"Solution\"\nmsgstr \"解決策\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:188\n#: 3ab64c25a2be4f59907562b0f68b24dc\nmsgid \"\"\n\"Use an OCR software like `OCRmyPDF <https://pypi.org/project/ocrmypdf/>`_\"\n\" to insert a hidden text layer underneath the visible page. The resulting\"\n\" PDF should behave as expected.\"\nmsgstr \"\"\n\"`OCRmyPDF <https://pypi.org/project/ocrmypdf/>`_ \"\n\"のようなOCRソフトウェアを使用して、表示ページの下に非表示のテキストレイヤーを挿入します。その結果のPDFは期待どおりに動作するはずです。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:191\n#: a8f6e51df1dc464fbb0f7475eba7a54b\nmsgid \"Problem: unreadable text\"\nmsgstr \"問題：読み取れないテキスト\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:192\n#: 7e6f3f7dc9964fac985a7fb4c533b3f2\nmsgid \"\"\n\"Text extraction does not deliver the text in readable order, duplicates \"\n\"some text, or is otherwise garbled.\"\nmsgstr \"テキストの抽出が読みやすい順序で行われず、一部のテキストが重複しているか、その他の理由で文字化けしている。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:196\n#: 060884ca10f34a9fa6daba7b2794c592\nmsgid \"\"\n\"The single characters are readable as such (no \\\"<?>\\\" symbols), but the \"\n\"sequence in which the text is **coded in the file** deviates from the \"\n\"reading order. The motivation behind may be technical or protection of \"\n\"data against unwanted copies.\"\nmsgstr \"個々の文字はそのまま読み取れるが（「<?>」シンボルがない）、テキストがファイル内でコード化された順序が読み取り順序と異なる場合がある。その背後には技術的な問題やデータの不正なコピーからの保護がある可能性がある。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:197\n#: 99dd9930809d4551bfe5d806b32e28bc\nmsgid \"\"\n\"Many \\\"<?>\\\" symbols occur, indicating MuPDF could not interpret these \"\n\"characters. The font may indeed be unsupported by MuPDF, or the PDF \"\n\"creator may haved used a font that displays readable text, but on purpose\"\n\" obfuscates the originating corresponding unicode character.\"\nmsgstr \"多くの「<?>」シンボルが表示され、MuPDFがこれらの文字を解釈できないことを示している場合。フォントがMuPDFでサポートされていない可能性があるか、PDFの作成者が読み取り可能なテキストを表示するフォントを使用しているが、意図的に元の対応するUnicode文字を曖昧にしている場合があります。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:201\n#: 7e9a1b033ba149c29732bf6d66164707\nmsgid \"Use layout preserving text extraction: `python -m fitz gettext file.pdf`.\"\nmsgstr \"レイアウトを保持するテキスト抽出を使用します： `python -m fitz gettext file.pdf`。\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:202\n#: 05bbf78e0c8c447794e360a1dda9f6df\nmsgid \"\"\n\"If other text extraction tools also don't work, then the only solution \"\n\"again is OCRing the page.\"\nmsgstr \"他のテキスト抽出ツールも機能しない場合は、再びOCRでページを処理するのが唯一の解決策です。\"\n\n#: ../../footer.rst:60 8010577d7dfe46e7ab6edda3adc1976a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Misplaced Item Insertions on PDF Pages\"\n#~ msgstr \"PDFページ上の誤ったアイテムの挿入\"\n\n#~ msgid \"\"\n#~ \"You inserted an item (like an \"\n#~ \"image, an annotation or some text) \"\n#~ \"on an existing PDF page, but later\"\n#~ \" you find it being placed at a\"\n#~ \" different location than intended. For \"\n#~ \"example an image should be inserted \"\n#~ \"at the top, but it unexpectedly \"\n#~ \"appears near the bottom of the \"\n#~ \"page.\"\n#~ msgstr \"既存のPDFページにアイテム（画像、注釈、テキストなど）を挿入しましたが、後で意図した場所とは異なる位置に配置されていることがあります。たとえば、画像はページの上部に挿入する予定でしたが、予想外にページの下部近くに表示されています。\"\n\n#~ msgid \"\"\n#~ \"The creator of the PDF has \"\n#~ \"established a non-standard page geometry\"\n#~ \" without keeping it \\\"local\\\" (as \"\n#~ \"they should!). Most commonly, the PDF\"\n#~ \" standard point (0,0) at *bottom-\"\n#~ \"left* has been changed to the \"\n#~ \"*top-left* point. So top and bottom\"\n#~ \" are reversed -- causing your \"\n#~ \"insertion to be misplaced.\"\n#~ msgstr \"PDFの作成者が標準ではないページジオメトリを設定しており、それを「ローカル」に保持していないためです（正しい方法で保持すべきです）。最も一般的には、PDF標準の座標（0,0）が左下にある点から、左上の点に変更されています。したがって、上下が逆転し、挿入が誤って配置されてしまいます。\"\n\n#~ msgid \"\"\n#~ \"The visible image of a PDF page\"\n#~ \" is controlled by commands coded in\"\n#~ \" a special mini-language. For an \"\n#~ \"overview of this language consult \"\n#~ \"\\\"Operator Summary\\\" on pp. 643 of \"\n#~ \"the :ref:`AdobeManual`. These commands are \"\n#~ \"stored in :data:`contents` objects as \"\n#~ \"strings (*bytes* in PyMuPDF).\"\n#~ msgstr \"\"\n#~ \"PDFページの可視イメージは、特別なミニ言語でコード化されたコマンドによって制御されています。この言語の概要については、 \"\n#~ \":ref:`AdobeManual` のpp. \"\n#~ \"643にある「オペレーターサマリー」を参照してください。これらのコマンドは、 :data:`contents` \"\n#~ \"オブジェクトに文字列（PyMuPDFではバイト）として格納されます。\"\n\n#~ msgid \"\"\n#~ \"There are commands in that language, \"\n#~ \"which change the coordinate system of\"\n#~ \" the page for all the following \"\n#~ \"commands. In order to limit the \"\n#~ \"scope of such commands to \\\"local\\\", \"\n#~ \"they must be wrapped by the \"\n#~ \"command pair *q* (\\\"save graphics \"\n#~ \"state\\\", or \\\"stack\\\") and *Q* \"\n#~ \"(\\\"restore graphics state\\\", or \\\"unstack\\\").\"\n#~ msgstr \"この言語には、次に続くすべてのコマンドの座標系を変更するコマンドがあります。このようなコマンドのスコープを「ローカル」に制限するためには、コマンドペアq（「グラフィックスステートの保存」または「スタック」）およびQ（「グラフィックスステートの復元」または「アンスタック」）で囲む必要があります。\"\n\n#~ msgid \"So the PDF creator did this::\"\n#~ msgstr \"したがって、PDFの作成者は次のように行いました::\"\n\n#~ msgid \"where they should have done this::\"\n#~ msgstr \"正しくは、次のように行うべきでした::\"\n\n#~ msgid \"\"\n#~ \"In the mini-language's syntax, spaces\"\n#~ \" and line breaks are equally accepted\"\n#~ \" token delimiters.\"\n#~ msgstr \"ミニ言語の構文では、スペースと改行は同様にトークンの区切りとして受け入れられます。\"\n\n#~ msgid \"Multiple consecutive delimiters are treated as one.\"\n#~ msgstr \"複数の連続した区切りは、1つとして扱われます。\"\n\n#~ msgid \"\"\n#~ \"Keywords \\\"stream\\\" and \\\"endstream\\\" are \"\n#~ \"inserted automatically -- not by the \"\n#~ \"programmer.\"\n#~ msgstr \"キーワード「stream」と「endstream」は自動的に挿入されます - プログラマーによって挿入されるものではありません。\"\n\n#~ msgid \"\"\n#~ \"Since v1.16.0, there is the property \"\n#~ \":attr:`Page.is_wrapped`, which lets you check\"\n#~ \" whether a page's contents are \"\n#~ \"wrapped in that string pair.\"\n#~ msgstr \"v1.16.0以降、プロパティPage.is_wrappedがあり、ページの内容がその文字列ペアでラップされているかどうかを確認できます。\"\n\n#~ msgid \"\"\n#~ \"If it is ``False`` or if you \"\n#~ \"want to be on the safe side, \"\n#~ \"pick one of the following:\"\n#~ msgstr \"それが `False` であるか、安全側に立ちたい場合、次のいずれかを選択してください：\"\n\n#~ msgid \"\"\n#~ \"The easiest way: in your script, \"\n#~ \"do a :meth:`Page.clean_contents` before you\"\n#~ \" do your first item insertion.\"\n#~ msgstr \"最も簡単な方法：スクリプトで最初のアイテム挿入を行う前に :meth:`Page.clean_contents` を実行します。\"\n\n#~ msgid \"\"\n#~ \"Pre-process your PDF with the \"\n#~ \"MuPDF command line utility *mutool clean\"\n#~ \" -c ...* and work with its \"\n#~ \"output file instead.\"\n#~ msgstr \"PDFをMuPDFコマンドラインユーティリティ `mutool clean -c …` で前処理し、その出力ファイルで作業します。\"\n\n#~ msgid \"\"\n#~ \"Directly wrap the page's :data:`contents` \"\n#~ \"with the stacking commands before you\"\n#~ \" do your first item insertion.\"\n#~ msgstr \"最初のアイテム挿入を行う前に、直接ページの内容をスタッキングコマンドでラップします。\"\n\n#~ msgid \"\"\n#~ \"**Solutions 1. and 2.** use the \"\n#~ \"same technical basis and **do a \"\n#~ \"lot more** than what is required \"\n#~ \"in this context: they also clean \"\n#~ \"up other inconsistencies or redundancies \"\n#~ \"that may exist, multiple */Contents* \"\n#~ \"objects will be concatenated into one,\"\n#~ \" and much more.\"\n#~ msgstr \"\"\n#~ \"**解決策1と2** \"\n#~ \"は同じ技術的基盤を使用しており、この文脈で必要なもの以上のことを行います：他の不整合や冗長性もクリーンアップされ、複数の \"\n#~ \"*/Contents* オブジェクトが1つに結合されるなど、さまざまな操作が行われます。\"\n\n#~ msgid \"\"\n#~ \"For **incremental saves,** solution 1. \"\n#~ \"has an unpleasant implication: it will\"\n#~ \" bloat the update delta, because it\"\n#~ \" changes so many things and, in \"\n#~ \"addition, stores the **cleaned contents \"\n#~ \"uncompressed**. So, if you use \"\n#~ \":meth:`Page.clean_contents` you should consider \"\n#~ \"**saving to a new file** with (at\"\n#~ \" least) *garbage=3* and *deflate=True*.\"\n#~ msgstr \"\"\n#~ \"増分保存の場合、解決策1には不快な影響があります：多くの変更を行い、さらにクリーンされた内容を非圧縮で保存するため、更新デルタが膨れる可能性があります。したがって、\"\n#~ \" :meth:`Page.clean_contents` を使用する場合は、（少なくとも） \"\n#~ \"`garbage=3` および `deflate=True` \"\n#~ \"を指定して新しいファイルに保存することを検討する必要があります。\"\n\n#~ msgid \"\"\n#~ \"**Solution 3.** is completely under your\"\n#~ \" control and only does the minimum\"\n#~ \" corrective action. There is a handy\"\n#~ \" utility method :meth:`Page.wrap_contents` which\"\n#~ \" -- as twe name suggests -- \"\n#~ \"**wraps** the page's :data:`contents` \"\n#~ \"object(s) by the PDF commands `q` \"\n#~ \"and `Q`.\"\n#~ msgstr \"\"\n#~ \"**解決策3** は完全にあなたの制御下にあり、最小限の修正しか行いません。便利なユーティリティメソッド \"\n#~ \":meth:`Page.wrap_contents` があり、名前が示すように、ページの内容 \"\n#~ \"(:data:`contents`) オブジェクトをPDFコマンド `q` と `Q`\"\n#~ \" でラップします。\"\n\n#~ msgid \"\"\n#~ \"This solution is extremely fast and \"\n#~ \"the changes to the PDF are \"\n#~ \"minimal. This is useful in situations\"\n#~ \" where incrementally saving the file \"\n#~ \"is desirable -- or even a must \"\n#~ \"when the PDF has been digitally \"\n#~ \"signed and you cannot change this \"\n#~ \"status.\"\n#~ msgstr \"この解決策は非常に高速で、PDFへの変更は最小限です。これは、ファイルを増分保存することが望ましい場合、またはPDFがデジタル署名されており、このステータスを変更できない場合に便利です。\"\n\n#~ msgid \"We recommend the following snippet to get the situation under control:\"\n#~ msgstr \"次のスニペットを使用して状況をコントロールすることをお勧めします：\"\n\n#~ msgid \"How to Deal with Messages Issued by :title:`MuPDF`\"\n#~ msgstr \":title:`MuPDF` から発行されるメッセージの処理方法\"\n\n#~ msgid \"\"\n#~ \"Since |PyMuPDF| v1.16.0, **error messages**\"\n#~ \" issued by the underlying :title:`MuPDF`\"\n#~ \" library are being redirected to the\"\n#~ \" Python standard device *sys.stderr*. So\"\n#~ \" you can handle them like any \"\n#~ \"other output going to this devices.\"\n#~ msgstr \"\"\n#~ \"PyMuPDF v1.16.0以降、基盤となるMuPDFライブラリから発行されるエラーメッセージは、Python標準デバイス\"\n#~ \" *sys.stderr* \"\n#~ \"にリダイレクトされます。したがって、これらのメッセージはこのデバイスに出力される他の出力と同様に扱うことができます。\"\n\n#~ msgid \"\"\n#~ \"In addition, these messages go to \"\n#~ \"the internal buffer together with any\"\n#~ \" :title:`MuPDF` warnings -- see below.\"\n#~ msgstr \"さらに、これらのメッセージはMuPDFの警告とともに内部バッファに送られます - 以下を参照してください。\"\n\n#~ msgid \"\"\n#~ \"We always prefix these messages with \"\n#~ \"an identifying string *\\\"mupdf:\\\"*. If \"\n#~ \"you prefer to not see recoverable \"\n#~ \"MuPDF errors at all, issue the \"\n#~ \"command `pymupdf.TOOLS.mupdf_display_errors(False)`.\"\n#~ msgstr \"\"\n#~ \"これらのメッセージは常に識別用の文字列 `\\\"mupdf:\\\"` \"\n#~ \"で始まります。復旧可能なMuPDFエラーを全く表示したくない場合は、コマンド  \"\n#~ \"`pymupdf.TOOLS.mupdf_display_errors(False)` を発行してください。\"\n\n#~ msgid \"\"\n#~ \"MuPDF warnings continue to be stored \"\n#~ \"in an internal buffer and can be\"\n#~ \" viewed using :meth:`Tools.mupdf_warnings`.\"\n#~ msgstr \"MuPDFの警告は引き続き内部バッファに保存され、 :meth:`Tools.mupdf_warnings` を使用して表示できます。\"\n\n#~ msgid \"\"\n#~ \"Please note that MuPDF errors may \"\n#~ \"or may not lead to Python \"\n#~ \"exceptions. In other words, you may \"\n#~ \"see error messages from which MuPDF \"\n#~ \"can recover and continue processing.\"\n#~ msgstr \"MuPDFのエラーがPython例外につながる場合とつながらない場合があることに注意してください。言い換えれば、MuPDFが回復して処理を続けることができるエラーメッセージが表示される可能性があります。\"\n\n#~ msgid \"\"\n#~ \"Example output for a **recoverable \"\n#~ \"error**. We are opening a damaged \"\n#~ \"PDF, but MuPDF is able to repair\"\n#~ \" it and gives us a little \"\n#~ \"information on what happened. Then we\"\n#~ \" illustrate how to find out whether\"\n#~ \" the document can later be saved \"\n#~ \"incrementally. Checking the \"\n#~ \":attr:`Document.is_dirty` attribute at this \"\n#~ \"point also indicates that during \"\n#~ \"`pymupdf.open` the document had to be\"\n#~ \" repaired:\"\n#~ msgstr \"\"\n#~ \"回復可能なエラーの例出力です。損傷したPDFを開いていますが、MuPDFはそれを修復し、何が起こったかに関する少しの情報を提供しています。その後、ドキュメントが後で増分保存できるかどうかを調べる方法も示しています。この時点で\"\n#~ \" :attr:`Document.is_dirty` 属性をチェックすることも、 `pymupdf.open`\"\n#~ \" の際にドキュメントを修復する必要があったことを示しています::\"\n\n#~ msgid \"Example output for an **unrecoverable error**:\"\n#~ msgstr \"**復旧できないエラー**の例出力:\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-drawing-and-graphics.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 cb49434c487144e990e8778af438e31c\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 b51ec2c5bec0471caa6c704e84d440e8\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 5049a6512fcf48e592552896861b4264\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-drawing-and-graphics.rst:7 c0b1ffca482b4acc93f866d4c279b9d4\nmsgid \"Drawing and Graphics\"\nmsgstr \"描画とグラフィックス\"\n\n#: ../../recipes-drawing-and-graphics.rst:11 cead69fa4d944be19c81d6669a194971\nmsgid \"\"\n\"When the terms \\\"Drawings\\\" or \\\"Graphics\\\" are mentioned here we are \"\n\"referring to \\\"Vector Graphics\\\" or \\\"Line Art\\\".\"\nmsgstr \"ここで「Drawings」や「Graphics」という用語が言及されている場合、それは「ベクトルグラフィックス」や「線画」を指しています。\"\n\n#: ../../recipes-drawing-and-graphics.rst:13 688ad77eb281436f8d8c2e421a35ccae\nmsgid \"Therefore please consider these terms as being synonymous!\"\nmsgstr \"したがって、これらの用語を同義語として考えてください。\"\n\n#: ../../recipes-drawing-and-graphics.rst:16 d4e85709e4c54144a43b7930cee0c0b5\nmsgid \"\"\n\"PDF files support elementary drawing operations as part of their syntax. \"\n\"These are **vector graphics** and include basic geometrical objects like \"\n\"lines, curves, circles, rectangles including specifying colors.\"\nmsgstr \"PDFファイルは、その構文の一部として基本的な描画操作をサポートしています。これらは**ベクトルグラフィックス**であり、線、曲線、円、長方形などの基本的な幾何学的オブジェクトを含み、色の指定も可能です。\"\n\n#: ../../recipes-drawing-and-graphics.rst:18 9cd89e5c62e34160bf2adcbf9cb4d393\nmsgid \"\"\n\"The syntax for such operations is defined in \\\"A Operator Summary\\\" on \"\n\"page 643 of the :ref:`AdobeManual`. Specifying these operators for a PDF \"\n\"page happens in its :data:`contents` objects.\"\nmsgstr \"\"\n\"このような操作の構文は、:ref:`AdobeManual` の「A Operator \"\n\"Summary」のページ643で定義されています。PDFページのためのこれらのオペレータは、その内容 \"\n\"(:data:`contents`)オブジェクト内で指定されます。\"\n\n#: ../../recipes-drawing-and-graphics.rst:20 4a3ebf96479040d49b72aa665e43f8a3\nmsgid \"\"\n\"|PyMuPDF| implements a large part of the available features via its \"\n\":ref:`Shape` class, which is comparable to notions like \\\"canvas\\\" in \"\n\"other packages (e.g. `reportlab <https://pypi.org/project/reportlab/>`_).\"\nmsgstr \"\"\n\"PyMuPDFは、 :ref:`Shape` クラスを介して利用可能な多くの機能を実装しており、これは他のパッケージ（例： `reportlab \"\n\"<https://pypi.org/project/reportlab/>`_ など）の「キャンバス」のような概念と類似しています。\"\n\n#: ../../recipes-drawing-and-graphics.rst:22 1bcec4ef8d0a4c69a61128221389abfa\nmsgid \"\"\n\"A shape is always created as a **child of a page**, usually with an \"\n\"instruction like `shape = page.new_shape()`. The class defines numerous \"\n\"methods that perform drawing operations on the page's area. For example, \"\n\"`last_point = shape.draw_rect(rect)` draws a rectangle along the borders \"\n\"of a suitably defined `rect = pymupdf.Rect(...)`.\"\nmsgstr \"\"\n\"シェイプは常にページの子として作成され、通常は `shape = page.new_shape()` \"\n\"のような命令で行います。このクラスは、ページの領域に描画操作を実行するための多数のメソッドを定義しています。たとえば、 `last_point =\"\n\" shape.draw_rect(rect)` は、適切に定義された `rect = pymupdf.Rect(…)` \"\n\"の境界に沿って四角形を描画します。\"\n\n#: ../../recipes-drawing-and-graphics.rst:24 522b5200167c42fc91bcda96ab482884\nmsgid \"\"\n\"The returned *last_point* **always** is the :ref:`Point` where drawing \"\n\"operation ended (\\\"last point\\\"). Every such elementary drawing requires \"\n\"a subsequent :meth:`Shape.finish` to \\\"close\\\" it, but there may be \"\n\"multiple drawings which have one common ``finish()`` method.\"\nmsgstr \"\"\n\"返されるlast_pointは常に描画操作が終了する :ref:`Point` \"\n\"（「最後のポイント」）です。このような基本的な描画ごとに、それを「閉じる」ために :meth:`Shape.finish` \"\n\"が必要ですが、1つの共通の``finish()``メソッドを持つ複数の描画があるかもしれません。\"\n\n#: ../../recipes-drawing-and-graphics.rst:26 a1a6cf576e374185b575ac29ef915ceb\nmsgid \"\"\n\"In fact, :meth:`Shape.finish` *defines* a group of preceding draw \"\n\"operations to form one -- potentially rather complex -- graphics object. \"\n\"|PyMuPDF| provides several predefined graphics in `shapes_and_symbols.py \"\n\"<https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/shapes/shapes_and_symbols.py>`_ which demonstrate \"\n\"how this works.\"\nmsgstr \"\"\n\"実際には、 :meth:`Shape.finish` \"\n\"は、1つの（潜在的に非常に複雑な）グラフィックオブジェクトを形成するための前の描画操作のグループを定義します。PyMuPDFは、これがどのように機能するかを示す\"\n\" `shapes_and_symbols.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/shapes/shapes_and_symbols.py>`_ \"\n\"内のいくつかの事前定義されたグラフィックスを提供しています。\"\n\n#: ../../recipes-drawing-and-graphics.rst:28 6682ec89ed0243e1a7c05a40ab825358\nmsgid \"\"\n\"If you import this script, you can also directly use its graphics as in \"\n\"the following example::\"\nmsgstr \"このスクリプトをインポートすると、次の例のようにそのグラフィックスを直接使用することもできます::\"\n\n#: ../../recipes-drawing-and-graphics.rst:86 ccbd2af5bfaa46dcbe5f2f15e412fc23\nmsgid \"This is the script's outcome:\"\nmsgstr \"これがスクリプトの結果です:\"\n\n#: ../../recipes-drawing-and-graphics.rst:97 65b162adbc52489e95a0170bada6afe9\nmsgid \"How to Extract Drawings\"\nmsgstr \"描画の抽出方法\"\n\n#: ../../recipes-drawing-and-graphics.rst:99 8373533f008548a89798eddeba96f9d8\nmsgid \"New in v1.18.0\"\nmsgstr \"v1.18.0で新登場\"\n\n#: ../../recipes-drawing-and-graphics.rst:101 0acd4de5d8554ebaa10b1347a50cf1de\nmsgid \"\"\n\"Drawing commands (**vector graphics**) issued by a page can be extracted \"\n\"as a list of dictionaries. Interestingly, this is possible for :ref:`all \"\n\"supported document types<Supported_File_Types>` -- not just PDF: so you \"\n\"can use it for XPS, EPUB and others as well.\"\nmsgstr \"\"\n\"ページから発行された描画コマンドを抽出できます。興味深いことに、これはすべての :ref:`サポートされている \"\n\"<Supported_File_Types>` ドキュメントタイプに対して可能です – PDFだけでなく、XPS、EPUBなどにも使用できます。\"\n\n#: ../../recipes-drawing-and-graphics.rst:103 7a07bc7541854578ad35f95ad5dfc330\nmsgid \"\"\n\"Page method, :meth:`Page.get_drawings()` accesses draw commands and \"\n\"converts them into a list of Python dictionaries. Each dictionary -- \"\n\"called a \\\"path\\\" -- represents a separate drawing -- it may be simple \"\n\"like a single line, or a complex combination of lines and curves \"\n\"representing one of the shapes of the previous section.\"\nmsgstr \"\"\n\":ref:`Page` メソッド、:meth:`Page.get_drawings()` \"\n\"は描画コマンドにアクセスし、それらをPythonの辞書のリストに変換します。各辞書 – 「パス」と呼ばれる – は個別の描画を表します – \"\n\"それは単純な単一の線であるか、前のセクションの形状の1つを表す線と曲線の複雑な組み合わせであるかもしれません。\"\n\n#: ../../recipes-drawing-and-graphics.rst:105 7ffb5ff050964de093cfe20336fa283d\nmsgid \"\"\n\"The *path* dictionary has been designed such that it can easily be used \"\n\"by the :ref:`Shape` class and its methods. Here is an example for a page \"\n\"with one path, that draws a red-bordered yellow circle inside rectangle \"\n\"`Rect(100, 100, 200, 200)`::\"\nmsgstr \"\"\n\"パスの辞書は、 :ref:`Shape` \"\n\"クラスとそのメソッドで簡単に使用できるように設計されています。以下は、1つのパスを持つページの例で、そのパスは `Rect(100, 100, \"\n\"200, 200)` の内側に赤い境界線の黄色い円を描画します::\"\n\n#: ../../recipes-drawing-and-graphics.rst:140 c1f4f56de6e1441f988e21f4184bed57\nmsgid \"\"\n\"You need (at least) 4 Bézier curves (of 3rd order) to draw a circle with \"\n\"acceptable precision. See this `Wikipedia article \"\n\"<https://en.wikipedia.org/wiki/B%C3%A9zier_curve>`_ for some background.\"\nmsgstr \"\"\n\"適切な精度で円を描画するには、（少なくとも）4つの3次ベジエ曲線が必要です。背景については、この `Wikipediaの記事 \"\n\"<https://en.wikipedia.org/wiki/B%C3%A9zier_curve>`_ を参照してください。\"\n\n#: ../../recipes-drawing-and-graphics.rst:143 be59d541be214b669a9c6663ca6abcd1\nmsgid \"\"\n\"The following is a code snippet which extracts the drawings of a page and\"\n\" re-draws them on a new page::\"\nmsgstr \"以下は、ページの描画を抽出し、それらを新しいページに再描画するコードの断片です::\"\n\n#: ../../recipes-drawing-and-graphics.rst:194 660c9c99b6864b26ad3a377cf1d1f343\nmsgid \"\"\n\"As can be seen, there is a high congruence level with the :ref:`Shape` \"\n\"class. With one exception: For technical reasons `lineCap` is a tuple of \"\n\"3 numbers here, whereas it is an integer in :ref:`Shape` (and in PDF). So\"\n\" we simply take the maximum value of that tuple.\"\nmsgstr \"\"\n\"ご覧の通り、 :ref:`Shape` クラスとの高い一致度があります。ただし1つ例外があります。技術的な理由から、ここでは `lineCap` \"\n\"は3つの数字のタプルですが、 :ref:`Shape` クラス（およびPDF内）では整数です。そのため、そのタプルの最大値を単純に取得します。\"\n\n#: ../../recipes-drawing-and-graphics.rst:196 d8e69210bfb24c3ebf97b7efbc549af6\nmsgid \"\"\n\"Here is a comparison between input and output of an example page, created\"\n\" by the previous script:\"\nmsgstr \"以下は、前のスクリプトで作成された例のページの入力と出力の比較です。\"\n\n#: ../../recipes-drawing-and-graphics.rst:201 9fc8264dcf1f4bfd98a7c1ad1aa9aee3\nmsgid \"\"\n\"The reconstruction of graphics, like shown here, is not perfect. The \"\n\"following aspects will not be reproduced as of this version:\"\nmsgstr \"ここに示されているようなグラフィックスの再構築は完璧ではありません。次の点は、このバージョンでは再現されません：\"\n\n#: ../../recipes-drawing-and-graphics.rst:203 8166cbf0fbaf40bb8343e4d7155fc0ce\nmsgid \"\"\n\"Page definitions can be complex and include instructions for not showing \"\n\"/ hiding certain areas to keep them invisible. Things like this are \"\n\"ignored by :meth:`Page.get_drawings` - it will always return all paths.\"\nmsgstr \"\"\n\"ページの定義は複雑になる可能性があり、特定の領域を表示しない/非表示にするための指示を含むことがあります。こうしたことは、 \"\n\":meth:`Page.get_drawings` によって無視されます – このメソッドは常にすべてのパスを返します。\"\n\n#: ../../recipes-drawing-and-graphics.rst:205 fd360aa336ff48d2b72658c63221a561\nmsgid \"\"\n\"You can use the path list to make your own lists of e.g. all lines or all\"\n\" rectangles on the page and subselect them by criteria, like color or \"\n\"position on the page etc.\"\nmsgstr \"パスのリストを使用して、ページ上のすべての線またはすべての四角形などのリストを作成し、色やページ上の位置などの基準でサブセレクトすることができます。\"\n\n#: ../../recipes-drawing-and-graphics.rst:210 93b3944bb9e543f48ca901f90fb021e4\nmsgid \"How to Delete Drawings\"\nmsgstr \"描画の削除方法\"\n\n#: ../../recipes-drawing-and-graphics.rst:212 094bb3cfc57b4461b8e1fea1652d63a5\nmsgid \"\"\n\"To delete drawings/vector graphics we must use a :ref:`Redaction \"\n\"Annotation <The_Basics_Redacting>` with the bounding box of the drawing \"\n\"and then **add and apply** a redaction to it to delete it.\"\nmsgstr \"\"\n\"描画やベクトルグラフィックスを削除するには、その描画の境界ボックスを持つ \"\n\":ref:`赤字アノテーション<The_Basics_Redacting>` を使用し、それに赤字を **追加して適用する** 必要があります。\"\n\n#: ../../recipes-drawing-and-graphics.rst:215 2f4f8d0e3e694181a5ce64ea3ccbe672\nmsgid \"\"\n\"The following code shows an example of deleting the first drawing found \"\n\"on the page::\"\nmsgstr \"以下のコードは、ページ上で最初に見つかった描画を削除する例を示しています：\"\n\n#: ../../recipes-drawing-and-graphics.rst:225 edf0ff01d38248c8b9f6608213f47b52\nmsgid \"\"\n\"See :meth:`Page.apply_redactions` for the parameter options which can be \"\n\"sent - you are able to apply deletion options to image, drawing and text \"\n\"objects which are bound by the annotation area.\"\nmsgstr \"\"\n\":meth:`Page.apply_redactions` \"\n\"には送信できるパラメータオプションがあります。アノテーション領域によって境界付けられたイメージ、描画、テキストオブジェクトに削除オプションを適用できます。\"\n\n#: ../../recipes-drawing-and-graphics.rst:229 ada7ddfefd1344ee94d178c3df118ae1\nmsgid \"How to Draw Graphics\"\nmsgstr \"グラフィックスを描画する方法\"\n\n#: ../../recipes-drawing-and-graphics.rst:231 4606dbe6b222488fac1f4948be78ee37\nmsgid \"\"\n\"Drawing graphics is as simple as calling the type of :meth:`Drawing \"\n\"Method <Page.draw_line>` you may want. You can draw graphics directly on \"\n\"pages or within shape objects.\"\nmsgstr \"\"\n\"グラフィックスを描画することは、必要な :meth:`描画方法 <Page.draw_line>` \"\n\"の種類を呼び出すだけです。グラフィックスは、ページ上または形状オブジェクト内に直接描画できます。\"\n\n#: ../../recipes-drawing-and-graphics.rst:234 55d0693f8fc14f2e8744839a6f7afe99\nmsgid \"For example, to draw a circle::\"\nmsgstr \"例えば、円を描画するには：\"\n\n#: ../../recipes-drawing-and-graphics.rst:245 1426496584b041f18b185bc3ee064f75\nmsgid \"\"\n\"The :ref:`Shape` object can be used to combine multiple drawings that \"\n\"should receive common properties as specified by :meth:`Shape.finish`.\"\nmsgstr \"\"\n\":ref:`Shape` オブジェクトは、:meth:`Shape.finish` \"\n\"で指定された共通のプロパティを受け取る必要がある複数の描画を組み合わせるために使用できます。\"\n\n#: ../../footer.rst:60 15d9c97491bd46d9806555b60b5da2ed\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-images.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 e08ff8c04b304218ac81d35f41292ac6\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 a1f1910f4f4b427c872afb309d8717ae\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 067d19d0feee4d3ea790680243bcadde\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-images.rst:7 57931bcbe871420b8981b5294574c1f6\nmsgid \"Images\"\nmsgstr \"画像\"\n\n#: ../../recipes-images.rst:14 c30d7e40298f4ae28b6931514dcdda2d\nmsgid \"How to Make Images from Document Pages\"\nmsgstr \"ドキュメントページから画像を作成する方法\"\n\n#: ../../recipes-images.rst:16 a5b0953e89e6485ea0cc82a8785e31cf\nmsgid \"\"\n\"This little script will take a document filename and generate a PNG file \"\n\"from each of its pages.\"\nmsgstr \"この小さなスクリプトは、文書のファイル名を取得し、各ページからPNGファイルを生成します。\"\n\n#: ../../recipes-images.rst:18 f1183a990e834decbf12969a97c76cf8\nmsgid \"The document can be any :ref:`supported type<Supported_File_Types>`.\"\nmsgstr \"文書の種類は、:ref:`サポートされている <Supported_File_Types>` どんな形式でも構いません。\"\n\n#: ../../recipes-images.rst:20 86fd95ad8dba47ed87f53ab293cc7058\nmsgid \"\"\n\"The script works as a command line tool which expects the filename being \"\n\"supplied as a parameter. The generated image files (1 per page) are \"\n\"stored in the directory of the script::\"\nmsgstr \"このスクリプトはコマンドラインツールとして動作し、ファイル名をパラメータとして指定することを期待しています。生成された画像ファイル（1ページごとに1つ）は、スクリプトが格納されているディレクトリに保存されます。::\"\n\n#: ../../recipes-images.rst:29 3e69a1bf5a8d49978cfc9c8dabfc3648\nmsgid \"\"\n\"The script directory will now contain PNG image files named *page-0.png*,\"\n\" *page-1.png*, etc. Pictures have the dimension of their pages with width\"\n\" and height rounded to integers, e.g. 595 x 842 pixels for an A4 portrait\"\n\" sized page. They will have a resolution of 96 dpi in x and y dimension \"\n\"and have no transparency. You can change all that -- for how to do this, \"\n\"read the next sections.\"\nmsgstr \"\"\n\"スクリプトのディレクトリには、これから *page-0.png* 、 *page-1.png* \"\n\"などという名前のPNG画像ファイルが含まれるようになります。画像は各ページの寸法に合わせて整数に丸められた幅と高さを持ちます。例えば、A4縦向きのページであれば595\"\n\" x 842ピクセルとなります。これらの画像は水平方向と垂直方向の解像度が96 \"\n\"dpiで、透明度はありません。これらの設定を変更することもできます。詳細については、次のセクションをお読みください。\"\n\n#: ../../recipes-images.rst:37 338b2dd52c564f7d9850839bb2b6e0c9\nmsgid \"How to Increase :index:`Image Resolution <pair: image; resolution>`\"\nmsgstr \"画像の解像度を上げる方法\"\n\n#: ../../recipes-images.rst:39 4770c88fce1d4a0782d7b461b2a4c8b6\nmsgid \"\"\n\"The image of a document page is represented by a :ref:`Pixmap`, and the \"\n\"simplest way to create a pixmap is via method :meth:`Page.get_pixmap`.\"\nmsgstr \"\"\n\"文書ページの画像はPixmapによって表されます。 :ref:`Pixmap` を作成するもっとも簡単な方法は、メソッド \"\n\":meth:`Page.get_pixmap` を使うことです。\"\n\n#: ../../recipes-images.rst:41 fe71e979e90a4e36ab7e012b4e4cfbaf\nmsgid \"\"\n\"This method has many options to influence the result. The most important \"\n\"among them is the :ref:`Matrix`, which lets you :index:`zoom`, rotate, \"\n\"distort or mirror the outcome.\"\nmsgstr \"このメソッドには結果に影響を与える多くのオプションがあります。その中でも最も重要なのは行列（Matrix）であり、これによって結果を拡大、回転、歪ませる、または反転することができます。\"\n\n#: ../../recipes-images.rst:43 879c14c6b55746e184a6a3659ddb8624\nmsgid \"\"\n\":meth:`Page.get_pixmap` by default will use the :ref:`Identity` matrix, \"\n\"which does nothing.\"\nmsgstr \":meth:`Page.get_pixmap` はデフォルトで :ref:`Identity` 行列を使用しますが、これは何も行いません。\"\n\n#: ../../recipes-images.rst:45 7ae61bca1b914ef58650814764c86556\nmsgid \"\"\n\"In the following, we apply a :index:`zoom factor <pair: resolution;zoom>`\"\n\" of 2 to each dimension, which will generate an image with a four times \"\n\"better resolution for us (and also about 4 times the size)::\"\nmsgstr \"以下では、各次元に2倍のズームを適用し、結果として解像度が4倍向上した画像を生成します（そしてサイズも約4倍になります）。::\"\n\n#: ../../recipes-images.rst:53 a015d3083e624dd0bb52595296bcda69\nmsgid \"\"\n\"Since version 1.19.2 there is a more direct way to set the resolution: \"\n\"Parameter `\\\"dpi\\\"` (dots per inch) can be used in place of `\\\"matrix\\\"`.\"\n\" To create a 300 dpi image of a page specify `pix = \"\n\"page.get_pixmap(dpi=300)`. Apart from notation brevity, this approach has\"\n\" the additional advantage that the **dpi value is saved with the image** \"\n\"file -- which does not happen automatically when using the Matrix \"\n\"notation.\"\nmsgstr \"\"\n\"バージョン1.19.2以降では、解像度を設定するより直接的な方法があります。 `\\\"dpi\\\"` （インチあたりのドット数）というパラメータを \"\n\"`\\\"matrix\\\"` の代わりに使用することができます。ページの300 dpiの画像を作成するには、 `pix = \"\n\"page.get_pixmap(dpi=300)` \"\n\"と指定します。略記法の利便性に加えて、この方法の追加の利点は、dpiの値が画像ファイルとともに保存されることです。これはMatrixの記法を使用する場合に自動的に行われることはありません。\"\n\n#: ../../recipes-images.rst:61 8e820a068673426d8b07c503b4b9b1eb\nmsgid \"How to Create :index:`Partial Pixmaps` (Clips)\"\nmsgstr \"部分的なPixmap（クリップ）の作成方法\"\n\n#: ../../recipes-images.rst:62 3575f660d7f34fcf8740261d5cc13939\nmsgid \"\"\n\"You do not always need or want the full image of a page. This is the case\"\n\" e.g. when you display the image in a GUI and would like to fill the \"\n\"respective window with a zoomed part of the page.\"\nmsgstr \"常にページの完全な画像が必要なわけではありませんし、必要ともしない場合があります。例えば、GUIで画像を表示し、ページのズームされた部分でウィンドウを埋めたい場合などが該当します。\"\n\n#: ../../recipes-images.rst:64 91a6b74e53dc47bba254ef54f6903677\nmsgid \"\"\n\"Let's assume your GUI window has room to display a full document page, \"\n\"but you now want to fill this room with the bottom right quarter of your \"\n\"page, thus using a four times better resolution.\"\nmsgstr \"GUIウィンドウにフルの文書ページを表示するスペースがあると仮定しましょうが、現在はページの右下の四分の一でこのスペースを埋めたいとします。これにより、解像度が4倍向上します。\"\n\n#: ../../recipes-images.rst:66 0c121baa24eb407eb7c91b5f481189c8\nmsgid \"\"\n\"To achieve this, define a rectangle equal to the area you want to appear \"\n\"in the GUI and call it \\\"clip\\\". One way of constructing rectangles in \"\n\"PyMuPDF is by providing two diagonally opposite corners, which is what we\"\n\" are doing here.\"\nmsgstr \"これを実現するために、GUIに表示したい領域に等しい矩形を定義し、「クリップ」と呼びます。PyMuPDFでは、矩形を構築する方法の1つは、対角線上にある2つの角を指定することです。これがここで行っていることです。\"\n\n#: ../../recipes-images.rst:79 355e4acbef614ba299f86cec24da6c88\nmsgid \"\"\n\"In the above we construct *clip* by specifying two diagonally opposite \"\n\"points: the middle point *mp* of the page rectangle, and its bottom \"\n\"right, *rect.br*.\"\nmsgstr \"\"\n\"上記では、 `clip` を構築するために、2つの対角線上の点を指定しています：ページ矩形の中心点である `mp` と、その右下の点である \"\n\"`rect.br` です。\"\n\n#: ../../recipes-images.rst:87 39c83e942ce74cb9baddcc259d24777e\nmsgid \"How to Zoom a Clip to a GUI Window\"\nmsgstr \"GUIウィンドウにクリップをズームする方法\"\n\n#: ../../recipes-images.rst:88 5ffea1d8340c4a08939f161390fd42ae\nmsgid \"\"\n\"Please also read the previous section. This time we want to **compute the\"\n\" zoom factor** for a clip, such that its image best fits a given GUI \"\n\"window. This means, that the image's width or height (or both) will equal\"\n\" the window dimension. For the following code snippet you need to provide\"\n\" the WIDTH and HEIGHT of your GUI's window that should receive the page's\"\n\" clip rectangle.\"\nmsgstr \"前のセクションもお読みください。今回は、クリップのズームファクターを計算して、その画像が指定されたGUIウィンドウに最適にフィットするようにします。つまり、画像の幅または高さ（または両方）がウィンドウの寸法と等しくなります。次のコードスニペットでは、GUIウィンドウのWIDTHとHEIGHTを提供する必要があります。それらはページのクリップ矩形を受け取る必要があります。\"\n\n#: ../../recipes-images.rst:105 61635a6d0bae4040986c0bd5b66441a2\nmsgid \"\"\n\"For the other way round, now assume you **have** the zoom factor and need\"\n\" to **compute the fitting clip**.\"\nmsgstr \"逆の場合は、ズームファクターがあると仮定し、フィッティングクリップを計算する必要があります。\"\n\n#: ../../recipes-images.rst:107 2903b44af458484da6825578d79b1da4\nmsgid \"\"\n\"In this case we have `zoom = HEIGHT/clip.height = WIDTH/clip.width`, so \"\n\"we must set `clip.height = HEIGHT/zoom` and, `clip.width = WIDTH/zoom`. \"\n\"Choose the top-left point `tl` of the clip on the page to compute the \"\n\"right pixmap::\"\nmsgstr \"\"\n\"この場合、 `zoom = HEIGHT/clip.height = WIDTH/clip.width`  となるので、 `clip.height\"\n\" = HEIGHT/zoom`  および  `clip.width = WIDTH/zoom`  \"\n\"と設定する必要があります。クリップ内のページ上の左上の点 tl を選択して、適切なピクマップを計算します。\"\n\n#: ../../recipes-images.rst:124 956b4a0c798e4b199a96b3f962fadf70\nmsgid \"How to Create or Suppress Annotation Images\"\nmsgstr \"注釈画像の作成または抑制方法\"\n\n#: ../../recipes-images.rst:125 88238495026f4e289613d5e50b81a474\nmsgid \"\"\n\"Normally, the pixmap of a page also shows the page's annotations. \"\n\"Occasionally, this may not be desirable.\"\nmsgstr \"通常、ページのピクマップにはページの注釈も表示されます。しかし、時にはこれが望ましくない場合があります。\"\n\n#: ../../recipes-images.rst:127 7cec58430afd46ed9e720d3b6fa029db\nmsgid \"\"\n\"To suppress the annotation images on a rendered page, just specify \"\n\"`annots=False` in :meth:`Page.get_pixmap`.\"\nmsgstr \"描画されたページから注釈画像を抑制するには、 :meth:`Page.get_pixmap` で  `annots=False` を指定します。\"\n\n#: ../../recipes-images.rst:129 f75aaef8eaa54984a2d2fe045e60d421\nmsgid \"\"\n\"You can also render annotations separately: they have their own \"\n\":meth:`Annot.get_pixmap` method. The resulting pixmap has the same \"\n\"dimensions as the annotation rectangle.\"\nmsgstr \"\"\n\"注釈を個別にレンダリングすることもできます。注釈には独自の :meth:`Annot.get_pixmap` \"\n\"メソッドがあります。結果のピクマップは注釈の矩形と同じ寸法です。\"\n\n#: ../../recipes-images.rst:141 9ff376603198474f97ccc539fa162925\nmsgid \"How to Extract Images: Non-PDF Documents\"\nmsgstr \"画像の抽出方法：非PDFドキュメント\"\n\n#: ../../recipes-images.rst:143 e1ee913277e849ab932b9b97874133c3\nmsgid \"\"\n\"In contrast to the previous sections, this section deals with \"\n\"**extracting** images **contained** in documents, so they can be \"\n\"displayed as part of one or more pages.\"\nmsgstr \"前のセクションとは対照的に、このセクションではドキュメントに含まれる画像の抽出に取り組みます。これにより、これらの画像を1つ以上のページの一部として表示することができます。\"\n\n#: ../../recipes-images.rst:145 a1a829c4fe444807b6db244124c9137d\nmsgid \"\"\n\"If you want to recreate the original image in file form or as a memory \"\n\"area, you have basically two options:\"\nmsgstr \"元の画像をファイル形式またはメモリ領域として再作成したい場合、基本的に2つのオプションがあります：\"\n\n#: ../../recipes-images.rst:147 773185000e944e7daeaf940ca6fda472\nmsgid \"\"\n\"Convert your document to a PDF, and then use one of the PDF-only \"\n\"extraction methods. This snippet will convert a document to PDF::\"\nmsgstr \"ドキュメントをPDFに変換し、その後PDF専用の抽出方法のいずれかを使用します。以下のスニペットはドキュメントをPDFに変換します::\"\n\n#: ../../recipes-images.rst:153 6416afce3c7447f98cbcd8b2d98214dd\nmsgid \"\"\n\"Use :meth:`Page.get_text` with the \\\"dict\\\" parameter. This works for all\"\n\" document types. It will extract all text and images shown on the page, \"\n\"formatted as a Python dictionary. Every image will occur in an image \"\n\"block, containing meta information and **the binary image data**. For \"\n\"details of the dictionary's structure, see :ref:`TextPage`. The method \"\n\"works equally well for PDF files. This creates a list of all images shown\"\n\" on a page::\"\nmsgstr \"\"\n\"「dict」パラメータを使って :meth:`Page.get_text` \"\n\"を使用します。これはすべてのドキュメントタイプに対して機能します。これにより、ページに表示されているすべてのテキストと画像がPythonの辞書としてフォーマットされて抽出されます。各画像は、メタ情報とバイナリ画像データを含む画像ブロックに含まれます。辞書の構造の詳細については、\"\n\" :ref:`TextPage` \"\n\"を参照してください。この方法はPDFファイルにも同じくうまく機能します。これにより、ページに表示されているすべての画像のリストが作成されます::\"\n\n#: ../../recipes-images.rst:182 28308796e3ad4f7abf4d6c2b939aca48\nmsgid \"How to Extract Images: PDF Documents\"\nmsgstr \"画像の抽出方法：PDFドキュメント\"\n\n#: ../../recipes-images.rst:184 0fc3745f79b8438d9b922c7957f09651\nmsgid \"\"\n\"Like any other \\\"object\\\" in a PDF, images are identified by a cross \"\n\"reference number (:data:`xref`, an integer). If you know this number, you\"\n\" have two ways to access the image's data:\"\nmsgstr \"\"\n\"PDF内の他のオブジェクトと同様に、画像は交差参照番号（ :data:`xref` \"\n\"、整数）によって識別されます。この番号を知っていれば、画像のデータにアクセスする方法が2つあります：\"\n\n#: ../../recipes-images.rst:186 f2a6f39609bb4bcb838f8d7a34a28da5\nmsgid \"\"\n\"**Create** a :ref:`Pixmap` of the image with instruction *pix = \"\n\"pymupdf.Pixmap(doc, xref)*. This method is **very** fast (single digit \"\n\"micro-seconds). The pixmap's properties (width, height, ...) will reflect\"\n\" the ones of the image. In this case there is no way to tell which image \"\n\"format the embedded original has.\"\nmsgstr \"\"\n\"**画像の** :ref:`Pixmap` を作成します。指示： `pix = pymupdf.Pixmap(doc, xref)` \"\n\"。この方法は非常に高速です（単桁のマイクロ秒）。 :ref:`Pixmap` \"\n\"のプロパティ（幅、高さなど）は、画像のものと同じになります。この場合、埋め込まれたオリジナルの画像形式を判別する方法はありません。\"\n\n#: ../../recipes-images.rst:188 903b6e9628bb4a0ea1ad4d2ff2f35557\nmsgid \"\"\n\"**Extract** the image with *img = doc.extract_image(xref)*. This is a \"\n\"dictionary containing the binary image data as *img[\\\"image\\\"]*. A number\"\n\" of meta data are also provided -- mostly the same as you would find in \"\n\"the pixmap of the image. The major difference is string *img[\\\"ext\\\"]*, \"\n\"which specifies the image format: apart from \\\"png\\\", strings like \"\n\"\\\"jpeg\\\", \\\"bmp\\\", \\\"tiff\\\", etc. can also occur. Use this string as the \"\n\"file extension if you want to store to disk. The execution speed of this \"\n\"method should be compared to the combined speed of the statements *pix = \"\n\"pymupdf.Pixmap(doc, xref);pix.tobytes()*. If the embedded image is in PNG\"\n\" format, the speed of :meth:`Document.extract_image` is about the same \"\n\"(and the binary image data are identical). Otherwise, this method is \"\n\"**thousands of times faster**, and the **image data is much smaller**.\"\nmsgstr \"\"\n\"**画像を抽出します。指示**： `img = doc.extract_image(xref)` \"\n\"。これはバイナリ画像データを含む辞書です。多くのメタデータも提供されますが、主に画像の :ref:`Pixmap` \"\n\"で見つけることができるものとほぼ同じです。主な違いは、文字列 img[\\\"ext\\\"] であり、画像形式を指定します。\\\"png\\\" 以外にも \"\n\"\\\"jpeg\\\" 、 \\\"bmp\\\"、 \\\"tiff\\\" \"\n\"などの文字列が出現することがあります。ディスクに保存する場合は、この文字列をファイル拡張子として使用します。このメソッドの実行速度は、以下のステートメントの組み合わせ速度\"\n\" `pix = pymupdf.Pixmap(doc, xref);pix.tobytes()` \"\n\"と比較する必要があります。埋め込まれた画像がPNG形式の場合、 :meth:`Document.extract_image` \"\n\"の速度はほぼ同じで（バイナリ画像データも同じです）、それ以外の場合は、このメソッドは数千倍高速であり、画像データも小さくなります\"\n\n#: ../../recipes-images.rst:190 110186a162f04f83955d7d59285d446b\nmsgid \"\"\n\"The question remains: **\\\"How do I know those 'xref' numbers of \"\n\"images?\\\"**. There are two answers to this:\"\nmsgstr \"**「どのようにして画像の'xref'番号を知るのか？」** これには2つの答えがあります：\"\n\n#: ../../recipes-images.rst:192 ad8338028ef944a19307f2547e05528f\nmsgid \"\"\n\"**\\\"Inspect the page objects:\\\"** Loop through the items of \"\n\":meth:`Page.get_images`. It is a list of list, and its items look like \"\n\"*[xref, smask, ...]*, containing the :data:`xref` of an image. This \"\n\":data:`xref` can then be used with one of the above methods. Use this \"\n\"method for **valid (undamaged)** documents. Be wary however, that the \"\n\"same image may be referenced multiple times (by different pages), so you \"\n\"might want to provide a mechanism avoiding multiple extracts.\"\nmsgstr \"\"\n\"**「ページオブジェクトを検査する」** ： :meth:`Page.get_images` \"\n\"の項目をループ処理します。これはリストのリストであり、項目は `[xref、smask、...]` のようになっており、画像の \"\n\":data:`xref` を含んでいます。この :data:`xref` \"\n\"を上記の方法の1つで使用できます。これは有効（損傷していない）なドキュメントに使用しますが、同じ画像が複数回（異なるページで）参照されることがあるため、複数回の抽出を避けるメカニズムを提供することが望ましいかもしれません。\"\n\n#: ../../recipes-images.rst:193 afeb949615fb470d958fdfc35b1fe9dd\nmsgid \"\"\n\"**\\\"No need to know:\\\"** Loop through the list of **all xrefs** of the \"\n\"document and perform a :meth:`Document.extract_image` for each one. If \"\n\"the returned dictionary is empty, then continue -- this :data:`xref` is \"\n\"no image. Use this method if the PDF is **damaged (unusable pages)**. \"\n\"Note that a PDF often contains \\\"pseudo-images\\\" (\\\"stencil masks\\\") with\"\n\" the special purpose of defining the transparency of some other image. \"\n\"You may want to provide logic to exclude those from extraction. Also have\"\n\" a look at the next section.\"\nmsgstr \"\"\n\"**「知る必要はありません」**：ドキュメントのすべての :data:`xref` のリストをループ処理し、各 :data:`xref` に対して\"\n\" :meth:`Document.extract_image` を実行します。返される辞書が空であれば、続けて次の :data:`xref` \"\n\"を処理します。この :data:`xref` \"\n\"は画像ではありません。これはPDFが損傷している（使用できないページがある）場合に使用します。PDFにはしばしば他の画像の透明度を定義する特別な目的の「擬似画像」（ステンシルマスク）が含まれていることに注意してください。これらを抽出から除外するためのロジックを提供することがあるかもしれません。次のセクションも参照してください。\"\n\n#: ../../recipes-images.rst:195 6d656f35aa69461f8e47b7f4bf499261\nmsgid \"\"\n\"For both extraction approaches, there exist ready-to-use general purpose \"\n\"scripts:\"\nmsgstr \"これらの抽出方法の両方に対して、一般的な用途のスクリプトが存在します。\"\n\n#: ../../recipes-images.rst:197 490e93536036437fab679b20daac6f6a\nmsgid \"\"\n\"`extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_ \"\n\"extracts images page by page:\"\nmsgstr \"\"\n\"`extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_  \"\n\"はページごとに画像を抽出します。\"\n\n#: ../../recipes-images.rst:202 87adba5350a8467e87dc3f0e80cae1e4\nmsgid \"\"\n\"and `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_ \"\n\"extracts images by xref table:\"\nmsgstr \"\"\n\"`extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_  \"\n\"はxrefテーブルによって画像を抽出します。\"\n\n#: ../../recipes-images.rst:213 b53c02001e2f4f7391e6e9e880b0631f\nmsgid \"How to Handle Image Masks\"\nmsgstr \"画像マスクの処理方法\"\n\n#: ../../recipes-images.rst:214 32034dc3accf4622b51ead4c06f67509\nmsgid \"\"\n\"Some images in PDFs are accompanied by **image masks**. In their simplest\"\n\" form, masks represent alpha (transparency) bytes stored as separate \"\n\"images. In order to reconstruct the original of an image, which has a \"\n\"mask, it must be \\\"enriched\\\" with transparency bytes taken from its \"\n\"mask.\"\nmsgstr \"PDF内の一部の画像には画像マスクが付属しています。最も単純な形式では、マスクは別の画像として格納されたアルファ（透明度）バイトを表します。画像の元の形を復元するには、そのマスクから取得した透明度バイトを使用して画像を「補完」する必要があります。\"\n\n#: ../../recipes-images.rst:216 e0828025961548d4a2ed0f2e5b9cedf6\nmsgid \"\"\n\"Whether an image does have such a mask can be recognized in one of two \"\n\"ways in PyMuPDF:\"\nmsgstr \"PyMuPDFでは、画像にそのようなマスクがあるかどうかは次の2つの方法で認識できます：\"\n\n#: ../../recipes-images.rst:218 4c26a844692448d6818018bc8e19f652\nmsgid \"\"\n\"An item of :meth:`Document.get_page_images` has the general format \"\n\"`(xref, smask, ...)`, where :data:`xref` is the image's :data:`xref` and \"\n\"*smask*, if positive, then it is the :data:`xref` of a mask.\"\nmsgstr \"\"\n\":meth:`Document.get_page_images` の項目は一般的な形式 `（xref、smask、...）` \"\n\"を持ちます。ここで、xrefは画像の :data:`xref` であり、 「smask」 が正の場合、それはマスクの :data:`xref` \"\n\"です。\"\n\n#: ../../recipes-images.rst:219 8011ba0428cc4b87a64b8031ea34ea90\nmsgid \"\"\n\"The (dictionary) results of :meth:`Document.extract_image` have a key \"\n\"*\\\"smask\\\"*, which also contains any mask's :data:`xref` if positive.\"\nmsgstr \"\"\n\":meth:`Document.extract_image` の結果（辞書）には、キー「smask」があります。このキーには、マスクの \"\n\":data:`xref` が含まれています。\"\n\n#: ../../recipes-images.rst:221 65aadf1969e44334a7c86d7524a50702\nmsgid \"\"\n\"If *smask == 0* then the image encountered via :data:`xref` can be \"\n\"processed as it is.\"\nmsgstr \"`smask == 0` の場合、 :data:`xref` を介して遭遇した画像はそのまま処理できます。\"\n\n#: ../../recipes-images.rst:223 302ce99937d44ca995fcedb51c11aaae\nmsgid \"\"\n\"To recover the original image using PyMuPDF, the procedure depicted as \"\n\"follows must be executed:\"\nmsgstr \"PyMuPDFを使用して元の画像を復元するためには、以下に示す手順を実行する必要があります：\"\n\n#: ../../recipes-images.rst:232 df80dda6fd5a4c4db985e0cfa929ee0a\nmsgid \"\"\n\"Step (1) creates a pixmap of the basic image. Step (2) does the same with\"\n\" the image mask. Step (3) adds an alpha channel and fills it with \"\n\"transparency information.\"\nmsgstr \"ステップ（1）では、基本画像のピクマップを作成します。ステップ（2）では、同じことを画像マスクで行います。ステップ（3）では、アルファチャンネルを追加し、透明情報で埋めます。\"\n\n#: ../../recipes-images.rst:234 4a160a9c64ac45caa88c66099e2af1b1\nmsgid \"\"\n\"The scripts `extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_, \"\n\"and `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_ \"\n\"above also contain this logic.\"\nmsgstr \"\"\n\"また、上記の `extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_ \"\n\"および `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_  \"\n\"というスクリプトにもこのロジックが含まれています。\"\n\n#: ../../recipes-images.rst:250 0f2b285905974f1b99efded1652e0905\nmsgid \"How to Make one PDF of all your Pictures (or Files)\"\nmsgstr \"すべての写真（またはファイル）を1つのPDFにする方法\"\n\n#: ../../recipes-images.rst:251 8d8107e9ab0942c88a4abccc8f7092dc\nmsgid \"\"\n\"We show here **three scripts** that take a list of (image and other) \"\n\"files and put them all in one PDF.\"\nmsgstr \"以下に、（画像およびその他の）ファイルのリストを受け取り、それらをすべて1つのPDFに結合する3つのスクリプトを示します。\"\n\n#: ../../recipes-images.rst:253 3df4d9f329c4453f9ca02d580bd2b3ba\nmsgid \"**Method 1: Inserting Images as Pages**\"\nmsgstr \"**方法1：画像をページとして挿入する方法**\"\n\n#: ../../recipes-images.rst:255 0bbd32458c89450b9f8adc7638530473\nmsgid \"\"\n\"The first one converts each image to a PDF page with the same dimensions.\"\n\" The result will be a PDF with one page per image. It will only work for \"\n\":ref:`supported image<Supported_File_Types>` file formats::\"\nmsgstr \"\"\n\"最初の方法では、各画像を同じ寸法のPDFページに変換します。結果は、1つの画像に1ページのPDFとなります。ただし、 \"\n\":ref:`サポートされている <Supported_File_Types>` 画像ファイル形式のみで動作します。::\"\n\n#: ../../recipes-images.rst:278 959fd3ad51dc45daa6b1f1310ad95124\nmsgid \"\"\n\"This will generate a PDF only marginally larger than the combined \"\n\"pictures' size. Some numbers on performance:\"\nmsgstr \"これにより、結合された画像のサイズとほとんど変わらないPDFが生成されます。パフォーマンスに関するいくつかの数値：\"\n\n#: ../../recipes-images.rst:280 4996fb148b334e01b2a6baaedf636b52\nmsgid \"\"\n\"The above script needed about 1 minute on my machine for 149 pictures \"\n\"with a total size of 514 MB (and about the same resulting PDF size).\"\nmsgstr \"上記のスクリプトは、149枚の画像で合計サイズが514 MBの場合、私のマシン上で約1分かかりました（生成されたPDFのサイズもほぼ同じです）。\"\n\n#: ../../recipes-images.rst:285 b684aa875c574e47bc3fc5f6c15767d1\nmsgid \"\"\n\"Look `here <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/insert-images/insert.py>`_ for a more \"\n\"complete source code: it offers a directory selection dialog and skips \"\n\"unsupported files and non-file entries.\"\nmsgstr \"\"\n\"より完全なソースコードは `こちら <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/insert-images/insert.py>`_ \"\n\"をご覧ください：ディレクトリ選択ダイアログを提供し、サポートされていないファイルやファイルでないエントリをスキップします。\"\n\n#: ../../recipes-images.rst:287 03c855c845f74ac1bcf9ce3a7ee420c1\nmsgid \"\"\n\"We might have used :meth:`Page.insert_image` instead of \"\n\":meth:`Page.show_pdf_page`, and the result would have been a similar \"\n\"looking file. However, depending on the image type, it may store **images\"\n\" uncompressed**. Therefore, the save option *deflate = True* must be used\"\n\" to achieve a reasonable file size, which hugely increases the runtime \"\n\"for large numbers of images. So this alternative **cannot be \"\n\"recommended** here.\"\nmsgstr \"\"\n\":meth:`Page.insert_image` の代わりに :meth:`Page.show_pdf_page` \"\n\"を使用することもできましたが、結果として似たような外観のファイルになります。ただし、画像の種類によっては、非圧縮で画像を保存する場合があります。そのため、適切なファイルサイズを得るためには、保存オプションとして\"\n\" `deflate = True` \"\n\"を使用する必要がありますが、これにより大量の画像の場合、実行時間が大幅に増加します。そのため、この代替方法はお勧めできません。\"\n\n#: ../../recipes-images.rst:289 41c532d33e8f42a39bb7560b25d00787\nmsgid \"**Method 2: Embedding Files**\"\nmsgstr \"**方法2：ファイルの埋め込み**\"\n\n#: ../../recipes-images.rst:291 490c3dd2b7d64db682e9ea9f27e723df\nmsgid \"\"\n\"The second script **embeds** arbitrary files -- not only images. The \"\n\"resulting PDF will have just one (empty) page, required for technical \"\n\"reasons. To later access the embedded files again, you would need a \"\n\"suitable PDF viewer that can display and / or extract embedded files::\"\nmsgstr \"2つ目のスクリプトは、画像だけでなく、任意のファイルを埋め込みます。技術的な理由で必要なので、結果として得られるPDFには1つだけ（空の）ページがあります。埋め込まれたファイルに後でアクセスするためには、埋め込まれたファイルを表示または抽出できる適切なPDFビューアが必要です::\"\n\n#: ../../recipes-images.rst:316 aa85ab6a4d7f4c068e437bc62ecde2f7\nmsgid \"\"\n\"This is by far the fastest method, and it also produces the smallest \"\n\"possible output file size. The above pictures needed 20 seconds on my \"\n\"machine and yielded a PDF size of 510 MB. Look `here \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/embed-\"\n\"images/embed.py>`_ for a more complete source code: it offers a directory\"\n\" selection dialog and skips non-file entries.\"\nmsgstr \"\"\n\"これは断然最も高速な方法であり、可能な限り最小の出力ファイルサイズを生成します。上記の画像は私のマシンで20秒かかり、PDFのサイズは510 \"\n\"MBになりました。より完全なソースコードは `こちら <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/examples/embed-images/embed.py>`_  \"\n\"をご覧ください：ディレクトリ選択ダイアログを提供し、ファイルでないエントリをスキップします。\"\n\n#: ../../recipes-images.rst:318 a5e66a78eac4476db9b235257835f444\nmsgid \"**Method 3: Attaching Files**\"\nmsgstr \"**方法3：ファイルの添付**\"\n\n#: ../../recipes-images.rst:320 25dd45dc2fc5483686500405d2daa76a\nmsgid \"\"\n\"A third way to achieve this task is **attaching files** via page \"\n\"annotations see `here <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/attach-images/attach.py>`_ for the \"\n\"complete source code.\"\nmsgstr \"\"\n\"このタスクを達成する第3の方法は、ページの注釈を介してファイルを添付する方法です。完全なソースコードについては `こちら \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/attach-images/attach.py>`_ をご覧ください。\"\n\n#: ../../recipes-images.rst:322 fde0ae6309414feb89541d4ee22f054a\nmsgid \"\"\n\"This has a similar performance as the previous script and it also \"\n\"produces a similar file size. It will produce PDF pages which show a \"\n\"'FileAttachment' icon for each attached file.\"\nmsgstr \"これは前のスクリプトと同様のパフォーマンスを持ち、似たようなファイルサイズも生成します。それぞれの添付ファイルに対して「FileAttachment」アイコンが表示されるPDFページを生成します。\"\n\n#: ../../recipes-images.rst:326 807309e9b6e0443c892b7a6d9f92f145\nmsgid \"\"\n\"Both, the **embed** and the **attach** methods can be used for \"\n\"**arbitrary files** -- not just images.\"\nmsgstr \"埋め込みと添付の両方の方法は、画像だけでなく任意のファイルにも使用できます。\"\n\n#: ../../recipes-images.rst:328 26ac29237c8d43398109384507fd51a8\nmsgid \"\"\n\"We strongly recommend using the awesome package `PySimpleGUI \"\n\"<https://pypi.org/project/PySimpleGUI/>`_ to display a progress meter for\"\n\" tasks that may run for an extended time span. It's pure Python, uses \"\n\"Tkinter (no additional GUI package) and requires just one more line of \"\n\"code!\"\nmsgstr \"\"\n\"長時間にわたるタスクに対して進捗メーターを表示するために、素晴らしいパッケージ `PySimpleGUI \"\n\"<https://pypi.org/project/PySimpleGUI/>`_  \"\n\"の使用を強くお勧めします。これは純粋なPythonであり、Tkinter（追加のGUIパッケージは不要）を使用し、たった1行のコードを追加するだけで使えます！\"\n\n#: ../../recipes-images.rst:342 ebad9685f21841c2b8ee9ac84740ecf2\nmsgid \"How to Create Vector Images\"\nmsgstr \"ベクター画像の作成方法\"\n\n#: ../../recipes-images.rst:343 40ce7c0f9b0044e3939ba507d3f936fd\nmsgid \"\"\n\"The usual way to create an image from a document page is \"\n\":meth:`Page.get_pixmap`. A pixmap represents a raster image, so you must \"\n\"decide on its quality (i.e. resolution) at creation time. It cannot be \"\n\"changed later.\"\nmsgstr \"\"\n\"ドキュメントページから画像を作成する通常の方法は、 :meth:`Page.get_pixmap` \"\n\"を使用することです。ピクマップはラスター画像を表しますので、作成時にその品質（つまり解像度）を決定する必要があります。後から変更することはできません。\"\n\n#: ../../recipes-images.rst:345 35c05b06ad73440aa94313c3f527dc97\nmsgid \"\"\n\"PyMuPDF also offers a way to create a **vector image** of a page in SVG \"\n\"format (scalable vector graphics, defined in XML syntax). SVG images \"\n\"remain precise across zooming levels (of course with the exception of any\"\n\" raster graphic elements embedded therein).\"\nmsgstr \"PyMuPDFはまた、SVG形式（XML構文で定義されたスケーラブルベクターグラフィックス）でページのベクター画像を作成する方法を提供しています。SVG画像はズームレベルで正確性を保持します（もちろん、埋め込まれたラスターグラフィックス要素を除く）。\"\n\n#: ../../recipes-images.rst:347 3664556134d441ee8ca7d943fe0e97b5\nmsgid \"\"\n\"Instruction *svg = page.get_svg_image(matrix=pymupdf.Identity)* delivers \"\n\"a UTF-8 string *svg* which can be stored with extension \\\".svg\\\".\"\nmsgstr \"\"\n\"指示  `svg = page.get_svg_image(matrix=pymupdf.Identity)`  はUTF-8文字列 *svg* \"\n\"を提供します。これは  \\\".svg\\\" の拡張子で保存できます。\"\n\n#: ../../recipes-images.rst:363 2e788e908541456db558a6d1e638447c\nmsgid \"How to Convert Images\"\nmsgstr \"画像の変換方法\"\n\n#: ../../recipes-images.rst:364 eaecfbf3be504291831504c4b64f18ba\nmsgid \"\"\n\"Just as a feature among others, PyMuPDF's image conversion is easy. It \"\n\"may avoid using other graphics packages like PIL/Pillow in many cases.\"\nmsgstr \"PyMuPDFの画像変換も他の機能と同様に簡単です。多くの場合、PIL/Pillowなどの他のグラフィックスパッケージを使用する必要がないかもしれません。\"\n\n#: ../../recipes-images.rst:366 c3f0f2ee44ad425e8ec5c957c779fbd5\nmsgid \"Notwithstanding that interfacing with Pillow is almost trivial.\"\nmsgstr \"ただし、Pillowとの連携はほとんど自明です。\"\n\n#: ../../recipes-images.rst:369 6b90048732484c0bb7bfd07609cd24ce\nmsgid \"**Input Formats**\"\nmsgstr \"**入力フォーマット**\"\n\n#: ../../recipes-images.rst:369 07a5c9395a4c45299d51e3bd83222984\nmsgid \"**Output Formats**\"\nmsgstr \"**出力フォーマット**\"\n\n#: ../../recipes-images.rst:369 8350dc457b254b8291594699ce54839d\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../recipes-images.rst:371 0979a1ef86ea4e20a05e557a7442a3b2\nmsgid \"BMP\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:371 ../../recipes-images.rst:373\n#: ../../recipes-images.rst:374 ../../recipes-images.rst:375\n#: ../../recipes-images.rst:376 ../../recipes-images.rst:383\n#: ../../recipes-images.rst:384 0bacf30757bb4f319e65010549478182\n#: 3ad593408aa445ce99d7f7d9479bca6d 55dc892386e3401f95cd320419c8edc9\n#: 7df71f3343174cfb84397536f4af3a84 84d138cd65ae497681d5c605ce8f2af7\n#: 95f327688bc1431c9523ec2101e353b0 c96232bb6e7340e2a5eb85364348a2a0\nmsgid \".\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:371 5897545255814fd5ba5a65241d15eced\nmsgid \"Windows Bitmap\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:372 41f6b3399986413abe65e2869c4053ea\n#: d00191a3adf74e71b0459460b1c2e159\nmsgid \"JPEG\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:372 d3b57018b2e3452080901854b19d1342\nmsgid \"Joint Photographic Experts Group\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:373 a3bdd964789b43cbad6247e119a6c54a\nmsgid \"JXR\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:373 bbea31de8177475b8158cf220a94abcb\nmsgid \"JPEG Extended Range\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:374 809526ac7ac74d2fb28e089e82a225d7\nmsgid \"JPX/JP2\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:374 9bf0ef68929647cd85f92ab8f862d849\nmsgid \"JPEG 2000\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:375 c791169bcfe4452e80b2573539c06ef1\nmsgid \"GIF\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:375 4a2960cefc3b47e496db085a39846137\nmsgid \"Graphics Interchange Format\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:376 4dcf6574e1574eaf922b9851c56ab035\nmsgid \"TIFF\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:376 df65730301314c1f95cb3c5315179281\nmsgid \"Tagged Image File Format\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:377 492608579f5a466e93c3441942845056\n#: 671fbf03f46c46f6a82cc000cfea3b33\nmsgid \"PNG\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:377 6800194509e449b699a2f117857a1789\nmsgid \"Portable Network Graphics\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:378 12727b15f7504523b43a9f77cc9a9923\n#: 221349ddd94740f18dc2a986e2f63e53\nmsgid \"PNM\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:378 7b091d14802241e4bba073bd5e0dc0d6\nmsgid \"Portable Anymap\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:379 bf3bacb00fbe43da9d560e7fbe4f78f4\n#: ed77816ad90043ff838934fe85431860\nmsgid \"PGM\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:379 37c68be55f8c46a3a92da90ed0894ded\nmsgid \"Portable Graymap\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:380 6f4d332905c643b9899a52fd96de577c\n#: 8530d6f66aaf4ed8b8e74e8de3aaf662\nmsgid \"PBM\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:380 78f4ada30b5940558d7575226b665930\nmsgid \"Portable Bitmap\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:381 18ad666221cb4e268aac5b2adcb051bc\n#: e4ac66013a6b40ef8f5f8dbcc44cbf3d\nmsgid \"PPM\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:381 46c1b8ed50c14c30b04706c0bcee355d\nmsgid \"Portable Pixmap\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:382 4eee3125b6b24045bf368e25ea1ccfe7\n#: 65190b879c2b49ce893b4dd5d72947a4\nmsgid \"PAM\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:382 9cb3d8054e01459bad986a5ff4b72d76\nmsgid \"Portable Arbitrary Map\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:383 172c0b24c3c74558b48cecb435b62a71\nmsgid \"PSD\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:383 d957051043af4e16a05d1bab3b7846e0\nmsgid \"Adobe Photoshop Document\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:384 61adad659533407383e3030a6a26682a\nmsgid \"PS\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:384 bd96837df2984e15953ba98f2ce8e7ca\nmsgid \"Adobe Postscript\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:387 2e9599f2f28e412f95d48fc8a90716c0\nmsgid \"The general scheme is just the following two lines::\"\nmsgstr \"一般的なスキームは以下の2行です::\"\n\n#: ../../recipes-images.rst:392 6a1955099311437ea3d6c722779fe787\nmsgid \"**Remarks**\"\nmsgstr \"**コメント**\"\n\n#: ../../recipes-images.rst:394 5e7c8ed9975341bb9b398e94977a1c35\nmsgid \"\"\n\"The **input** argument of *pymupdf.Pixmap(arg)* can be a file or a bytes \"\n\"/ io.BytesIO object containing an image.\"\nmsgstr \"`pymupdf.Pixmap(arg)` の入力引数は、画像を含むファイルまたはbytes/io.BytesIOオブジェクトを指定できます。\"\n\n#: ../../recipes-images.rst:395 29c03f633e3c4f85905a883594780a1a\nmsgid \"\"\n\"Instead of an output **file**, you can also create a bytes object via \"\n\"*pix.tobytes(\\\"yyy\\\")* and pass this around.\"\nmsgstr \"出力ファイルの代わりに、 `pix.tobytes(\\\"yyy\\\")` を使用してbytesオブジェクトを作成し、それを渡すこともできます。\"\n\n#: ../../recipes-images.rst:396 08d941cbdcde49e7894c7cd54dceeb12\nmsgid \"\"\n\"As a matter of course, input and output formats must be compatible in \"\n\"terms of colorspace and transparency. The ``Pixmap`` class has batteries \"\n\"included if adjustments are needed.\"\nmsgstr \"\"\n\"もちろん、入力と出力のフォーマットは、色空間と透過性の面で互換性が必要です。 :ref:`Pixmap` \"\n\"クラスには、必要に応じて調整を行うための組み込みの機能が備わっています。\"\n\n#: ../../recipes-images.rst:399 3264d7f4236e472d9acb18b03a6c378f\nmsgid \"**Convert JPEG to Photoshop**::\"\nmsgstr \"**JPEGをPhotoshopに変換する**::\"\n\n#: ../../recipes-images.rst:405 03352131b8ff486f8481486724d51437\nmsgid \"\"\n\"Convert **JPEG to Tkinter PhotoImage**. Any **RGB / no-alpha** image \"\n\"works exactly the same. Conversion to one of the **Portable Anymap** \"\n\"formats (PPM, PGM, etc.) does the trick, because they are supported by \"\n\"all Tkinter versions::\"\nmsgstr \"アルファ付きのPNGをTkinterのPhotoImageに変換してください。これには、PPMへの変換を行う前にアルファバイトを削除する必要があります。\"\n\n#: ../../recipes-images.rst:412 1d8ba60c17ef4537a879f8880ddf842e\nmsgid \"\"\n\"Convert **PNG with alpha** to Tkinter PhotoImage. This requires \"\n\"**removing the alpha bytes**, before we can do the PPM conversion::\"\nmsgstr \"アルファ付きのPNGをTkinterのPhotoImageに変換します。このためには、PPMへの変換を行う前にアルファバイトを取り除く必要があります。\"\n\n#: ../../recipes-images.rst:429 e998a366000347d1b54bed12c09423fd\nmsgid \"How to Use Pixmaps: Gluing Images\"\nmsgstr \"ピクスマップの使用方法：画像の結合\"\n\n#: ../../recipes-images.rst:431 f97460e4da964505a4f7c1625d462e07\nmsgid \"\"\n\"This shows how pixmaps can be used for purely graphical, non-document \"\n\"purposes. The script reads an image file and creates a new image which \"\n\"consist of 3 * 4 tiles of the original::\"\nmsgstr \"\"\n\"これは、ピクスマップを純粋にグラフィカルで、文書ではない目的で使用する方法を示しています。スクリプトは画像ファイルを読み込み、元の画像の3 * \"\n\"4タイルからなる新しい画像を作成します。\"\n\n#: ../../recipes-images.rst:451 4e2ddaf362f641b79cccb12467620742\nmsgid \"This is the input picture:\"\nmsgstr \"これが入力画像です。\"\n\n#: ../../recipes-images.rst:456 517480af4baf43568e79bdb13b6ab85c\nmsgid \"Here is the output:\"\nmsgstr \"こちらが出力結果です。\"\n\n#: ../../recipes-images.rst:473 172a0fbba4984e9cb6d93f6ed02742fa\nmsgid \"How to Use Pixmaps: Making a Fractal\"\nmsgstr \"ピクスマップの使用方法：フラクタルの作成\"\n\n#: ../../recipes-images.rst:475 18c71aef80304611bec96e98bcd38669\nmsgid \"\"\n\"Here is another Pixmap example that creates **Sierpinski's Carpet** -- a \"\n\"fractal generalizing the **Cantor Set** to two dimensions. Given a square\"\n\" carpet, mark its 9 sub-suqares (3 times 3) and cut out the one in the \"\n\"center. Treat each of the remaining eight sub-squares in the same way, \"\n\"and continue *ad infinitum*. The end result is a set with area zero and \"\n\"fractal dimension 1.8928...\"\nmsgstr \"\"\n\"ここでは、もう一つのピクスマップの例を紹介します。シェルピンスキーのカーペット（Sierpinski's \"\n\"Carpet）と呼ばれるフラクタルで、カントール集合を2次元に一般化したものです。正方形のカーペットにおいて、9つの部分正方形（3行3列）をマークし、中央の正方形を切り抜きます。残りの8つの部分正方形に対しても同じ操作を行い、無限に続けます。その結果、面積がゼロであり、フラクタル次元は1.8928...となります。\"\n\n#: ../../recipes-images.rst:477 53c09705945d4ed3bec2d17b7c9f1581\nmsgid \"\"\n\"This script creates an approximate image of it as a PNG, by going down to\"\n\" one-pixel granularity. To increase the image precision, change the value\"\n\" of n (precision)::\"\nmsgstr \"このスクリプトは、1ピクセルの精度にまで細かくなったPNGの近似画像を作成します。画像の精度を高めるには、n（精度）の値を変更してください::\"\n\n#: ../../recipes-images.rst:531 68789bca8b624ff491e93d5a400ff3ac\nmsgid \"The result should look something like this:\"\nmsgstr \"結果は以下のようになるはずです：\"\n\n#: ../../recipes-images.rst:541 93a642a1f6fb4a578a82d7b7baf97ad3\nmsgid \"How to Interface with NumPy\"\nmsgstr \"NumPyとのインターフェース方法\"\n\n#: ../../recipes-images.rst:543 8f95a3058d5348dfa20391d4596a676e\nmsgid \"\"\n\"This shows how to create a PNG file from a numpy array (several times \"\n\"faster than most other methods)::\"\nmsgstr \"これは、NumPy配列からPNGファイルを作成する方法を示しています（他の方法よりも数倍高速です）。\"\n\n#: ../../recipes-images.rst:570 fe1a53c3297d463785209cfc2a811f98\nmsgid \"How to Add Images to a PDF Page\"\nmsgstr \"PDFページに画像を追加する方法\"\n\n#: ../../recipes-images.rst:572 c4977664b53940488eefb7c79db6760f\nmsgid \"\"\n\"There are two methods to add images to a PDF page: \"\n\":meth:`Page.insert_image` and :meth:`Page.show_pdf_page`. Both methods \"\n\"have things in common, but there are also differences.\"\nmsgstr \"\"\n\"PDFページに画像を追加するには、2つの方法があります： :meth:`Page.insert_image` と \"\n\":meth:`Page.show_pdf_page` です。両方の方法には共通点がありますが、違いもあります。\"\n\n#: ../../recipes-images.rst:575 05867b3cbf1e4cfbb8b56cd82480ca49\nmsgid \"**Criterion**\"\nmsgstr \"**基準**\"\n\n#: ../../recipes-images.rst:575 1a4fb4ba40034ec697f3f519a1472c05\nmsgid \":meth:`Page.insert_image`\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:575 c77d016df1554917b7a351e1213d6d30\nmsgid \":meth:`Page.show_pdf_page`\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:577 adaf610a08404152879eecde101b3358\nmsgid \"displayable content\"\nmsgstr \"表示可能なコンテンツ\"\n\n#: ../../recipes-images.rst:577 be7f0aa395a84ea0967b19ea32e118ad\nmsgid \"image file, image in memory, pixmap\"\nmsgstr \"画像ファイル、メモリ内の画像、ピクスマップ \"\n\n#: ../../recipes-images.rst:577 5dcf084c5bf14f44b42f33e83b39ffb0\nmsgid \"PDF page\"\nmsgstr \"PDFページ\"\n\n#: ../../recipes-images.rst:578 b21f95bfb2da4d1da8dc1a8de8fcd793\nmsgid \"display resolution\"\nmsgstr \"表示解像度 \"\n\n#: ../../recipes-images.rst:578 e5fb57d9b06e415496d5fdd4ad9d2860\nmsgid \"image resolution\"\nmsgstr \"画像の解像度 \"\n\n#: ../../recipes-images.rst:578 f162cd0a2ec54a14bc65d19390efb3ab\nmsgid \"vectorized (except raster page content)\"\nmsgstr \"ベクトル化（ラスターページコンテンツを除く）\"\n\n#: ../../recipes-images.rst:579 8f71139fa4184451a269095eaf3b024d\nmsgid \"rotation\"\nmsgstr \"回転\"\n\n#: ../../recipes-images.rst:579 e07ae649fe5a43b98128e34d2b7295f4\nmsgid \"0, 90, 180 or 270 degrees\"\nmsgstr \"0度、90度、180度または270度\"\n\n#: ../../recipes-images.rst:579 6f5358e1760c4bfca5a3a418b8c268ff\nmsgid \"any angle\"\nmsgstr \"任意の角度\"\n\n#: ../../recipes-images.rst:580 fd811b11808e4d7fa0b6e434c51cc9de\nmsgid \"clipping\"\nmsgstr \"クリッピング\"\n\n#: ../../recipes-images.rst:580 c2558fbbf1774081b28e0116ee882210\nmsgid \"no (full image only)\"\nmsgstr \"いいえ（全体の画像のみ）\"\n\n#: ../../recipes-images.rst:580 ../../recipes-images.rst:585\n#: a907ff72bff14ccab44936c7756bc1a0 dc5568a67d5546399d10903c2198e7b1\nmsgid \"yes\"\nmsgstr \"はい\"\n\n#: ../../recipes-images.rst:581 9be3b939efd74eb9b064149922973fd7\nmsgid \"keep aspect ratio\"\nmsgstr \"アスペクト比を保持\"\n\n#: ../../recipes-images.rst:581 90e967a63c944ad2a4d5d5e1a1e1f586\n#: ae736e0e2d874c22a9ff0e8ec0eafd07\nmsgid \"yes (default option)\"\nmsgstr \"はい（デフォルトオプション）\"\n\n#: ../../recipes-images.rst:582 149cd46d36314fd9983779124a4b00a5\nmsgid \"transparency (water marking)\"\nmsgstr \"透明性（ウォーターマーキング）\"\n\n#: ../../recipes-images.rst:582 f5ee92e1f762447294b068b3151cf8ba\nmsgid \"depends on the image\"\nmsgstr \"画像による\"\n\n#: ../../recipes-images.rst:582 48bce5fbaea9451c8a0205e90189408b\nmsgid \"depends on the page\"\nmsgstr \"ページによる\"\n\n#: ../../recipes-images.rst:583 b0cc7970f86848258e39444054ac610b\nmsgid \"location / placement\"\nmsgstr \"位置/配置 \"\n\n#: ../../recipes-images.rst:583 3d965dc24e154178970ddf5ed7662f16\n#: 5a690d8091e446ac921b5a5e97de9884\nmsgid \"scaled to fit target rectangle\"\nmsgstr \"ターゲットの矩形にフィットするようにスケーリング\"\n\n#: ../../recipes-images.rst:584 78fa2e33851d443584542c9de0f6ea73\nmsgid \"performance\"\nmsgstr \"パフォーマンス\"\n\n#: ../../recipes-images.rst:584 07bc6beb376d4561bf3ed4427bfeada8\n#: 883bd897a4de4ed2a0f2af42a61dd792\nmsgid \"automatic prevention of duplicates;\"\nmsgstr \"重複の自動防止\"\n\n#: ../../recipes-images.rst:585 7ef2987d846a48a9a38bb80ba9ee36be\nmsgid \"multi-page image support\"\nmsgstr \"マルチページ画像のサポート\"\n\n#: ../../recipes-images.rst:585 02be9acec59f4fa3adf501ba7f63438f\nmsgid \"no\"\nmsgstr \"いいえ\"\n\n#: ../../recipes-images.rst:586 018cb20575654c4aa10c951f189464f3\nmsgid \"ease of use\"\nmsgstr \"使いやすさ\"\n\n#: ../../recipes-images.rst:586 c28d925902ab48b389c171a05aca19c6\nmsgid \"simple, intuitive;\"\nmsgstr \"シンプルで直感的\"\n\n#: ../../recipes-images.rst:586 afc67eb6d74a495c9dc4e53eb661ae08\nmsgid \"\"\n\"simple, intuitive; **usable for all document types** (including images!) \"\n\"after conversion to PDF via :meth:`Document.convert_to_pdf`\"\nmsgstr \"\"\n\"シンプルで直感的; :meth:`Document.convert_to_pdf` \"\n\"を介してPDFに変換後、すべてのドキュメントタイプ（画像を含む！）に使用可能\"\n\n#: ../../recipes-images.rst:592 e4d67c78bd67458c84faeb0c8e6ea5f5\nmsgid \"\"\n\"Basic code pattern for :meth:`Page.insert_image`. **Exactly one** of the \"\n\"parameters **filename / stream / pixmap** must be given, if not re-\"\n\"inserting an existing image::\"\nmsgstr \"\"\n\":meth:`Page.insert_image` の基本的なコードパターン。 **filename / stream / pixmap** \"\n\"のうち、1つだけを指定する必要があります（既存の画像を再挿入しない場合）::\"\n\n#: ../../recipes-images.rst:607 a7bbf44ff07e494bb6788af779c4f19f\nmsgid \"\"\n\"Basic code pattern for :meth:`Page.show_pdf_page`. Source and target PDF \"\n\"must be different :ref:`Document` objects (but may be opened from the \"\n\"same file)::\"\nmsgstr \"\"\n\":meth:`Page.show_pdf_page` の基本的なコードパターン。ソースとターゲットのPDFは異なる :ref:`Document`\"\n\" オブジェクトである必要があります（ただし、同じファイルから開くこともできます）::\"\n\n#: ../../recipes-images.rst:623 247c3cb945de42e3977137d8975573b2\nmsgid \"How to Use Pixmaps: Checking Text Visibility\"\nmsgstr \"ピクスマップの使用方法：テキストの表示可否の確認\"\n\n#: ../../recipes-images.rst:625 265feb286a04491a9466ccd75f125d7a\nmsgid \"\"\n\"Whether or not a given piece of text is actually visible on a page \"\n\"depends on a number of factors:\"\nmsgstr \"特定のテキストが実際にページ上で表示されるかどうかは、いくつかの要因に依存します：\"\n\n#: ../../recipes-images.rst:627 cb95f70cf5474c549b283bb06a5b637d\nmsgid \"\"\n\"Text is not covered by another object but may have the same color as the \"\n\"background i.e., white-on-white etc.\"\nmsgstr \"テキストは他のオブジェクトによって隠されていないが、背景と同じ色を持っている場合があります。例えば、白文字が白地になっているなどです。\"\n\n#: ../../recipes-images.rst:628 d8c9eec28274456bbae7dfd39049394b\nmsgid \"\"\n\"Text may be covered by an image or vector graphics. Detecting this is an \"\n\"important capability, for example to uncover badly anonymized legal \"\n\"documents.\"\nmsgstr \"テキストは画像やベクトルグラフィックスによって隠されている場合があります。これを検出することは重要な機能であり、例えば不適切に匿名化された法的文書を解明するために使用されます。\"\n\n#: ../../recipes-images.rst:629 54573a8eea4e421ca5e82c476f55b0e9\nmsgid \"\"\n\"Text is created hidden. This technique is usually used by OCR tools to \"\n\"store the recognized text in an invisible layer on the page.\"\nmsgstr \"テキストが非表示に作成される場合があります。これは通常、OCRツールが認識されたテキストをページ上の非表示レイヤーに保存するために使用されます。\"\n\n#: ../../recipes-images.rst:631 421ec6799ba94504a184bb6003eeeac8\nmsgid \"\"\n\"The following shows how to detect situation 1. above, or situation 2. if \"\n\"the covering object is unicolor::\"\nmsgstr \"以下では、1.の状況を検出する方法、または2.の状況を検出する方法（カバーしているオブジェクトが単色である場合）を示します::\"\n\n#: ../../recipes-images.rst:645 a958215274f14ffc9a1039c6445e57ec\nmsgid \"\"\n\"Method :meth:`Pixmap.color_topusage` returns a tuple `(ratio, pixel)` \"\n\"where 0 < ratio <= 1 and *pixel* is the pixel value of the color. Please \"\n\"note that we create a **pixmap only once**. This can save a lot of \"\n\"processing time if there are multiple hit rectangles.\"\nmsgstr \"\"\n\"メソッド :meth:`Pixmap.color_topusage` は、タプル `(ratio, pixel)` \"\n\"（比率、ピクセル）を返します。ここで、0 < ratio <= \"\n\"1であり、pixelは色のピクセル値です。複数のヒット矩形がある場合、ピクスマップを1回だけ作成することに注意してください。これにより、処理時間を大幅に節約できます。\"\n\n#: ../../recipes-images.rst:647 675626a41d9f4ee49cee5bb637261c3f\nmsgid \"\"\n\"The logic of the above code is: If the needle's rectangle is (\\\"almost\\\":\"\n\" > 95%) unicolor, then the text cannot be visible. A typical result for \"\n\"visible text returns the color of the background (mostly white) and a \"\n\"ratio around 0.7 to 0.8, for example `(0.685, b'\\\\xff\\\\xff\\\\xff')`.\"\nmsgstr \"\"\n\"上記のコードのロジックは次の通りです：もしニードルの矩形が「ほぼ」（95％以上）単色であれば、テキストは表示されないと判断します。テキストが表示される場合の典型的な結果は、背景の色（主に白）と比率が0.7から0.8程度で返されることがあります。例えば、`(0.685,\"\n\" b'xffxffxff')` のような結果が得られます。\"\n\n#: ../../footer.rst:60 20230f8c88394d47a41e985bb5942765\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-journalling.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 1dec65ff7f144a209a6670156424f1bd\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 a2496778c1824e0d8507743948d5699d\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 d11779a821a640a9b5f1a505bdf860e4\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-journalling.rst:7 71340aa0c4f8460eb610827b5dd6a0e2\nmsgid \"Journalling\"\nmsgstr \"ジャーナリング\"\n\n#: ../../recipes-journalling.rst:10 982db193623640f18388d6961fe5fc64\nmsgid \"\"\n\"Starting with version 1.19.0, journalling is possible when updating PDF \"\n\"documents.\"\nmsgstr \"バージョン1.19.0から、PDFドキュメントの更新時にジャーナリングが可能になりました。\"\n\n#: ../../recipes-journalling.rst:12 239c97bb5a8f4f329aa3e2fcd8a01db7\nmsgid \"\"\n\"Journalling is a logging mechanism which permits either **reverting** or \"\n\"**re-applying** changes to a PDF. Similar to LUWs \\\"Logical Units of \"\n\"Work\\\" in modern database systems, one can group a set of updates into an\"\n\" \\\"operation\\\". In MuPDF journalling, an operation plays the role of a \"\n\"LUW.\"\nmsgstr \"ジャーナリングは、PDFへの変更を元に戻したり再適用したりするためのログ記録メカニズムです。近代的なデータベースシステムにおける「論理ユニット・オブ・ワーク（LUW）」のように、一連の更新を「操作」としてグループ化することができます。MuPDFジャーナリングでは、操作がLUWの役割を果たします。\"\n\n#: ../../recipes-journalling.rst:14 2e4f6dca544a400cb7dc16a559d9e182\nmsgid \"\"\n\"In contrast to LUW implementations found in database systems, MuPDF \"\n\"journalling happens on a **per document level**. There is no support for \"\n\"simultaneous updates across multiple PDFs: one would have to establish \"\n\"one's own logic here.\"\nmsgstr \"データベースシステムで見られるLUWの実装とは異なり、MuPDFジャーナリングはドキュメント単位で行われます。複数のPDFで同時に更新するためのサポートはありません。それぞれのPDFに対して独自のロジックを確立する必要があります。\"\n\n#: ../../recipes-journalling.rst:16 001589c65f8641d5a1bc838871c82e35\nmsgid \"\"\n\"Journalling must be *enabled* via a document method. Journalling is \"\n\"possible for existing or new documents. Journalling **can be disabled \"\n\"only** by closing the file.\"\nmsgstr \"ジャーナリングは、ドキュメントメソッドを介して有効にする必要があります。既存のドキュメントまたは新規ドキュメントのジャーナリングが可能です。ファイルを閉じることでのみジャーナリングを無効にすることができます。\"\n\n#: ../../recipes-journalling.rst:17 a4f5223ab97d41c0a62d52cebe7f3f76\nmsgid \"\"\n\"Once enabled, every change must happen inside an *operation* -- otherwise\"\n\" an exception is raised. An operation is started and stopped via document\"\n\" methods. Updates happening between these two calls form an LUW and can \"\n\"thus collectively be rolled back or re-applied, or, in MuPDF terminology \"\n\"\\\"undone\\\" resp. \\\"redone\\\".\"\nmsgstr \"有効になると、すべての変更は操作の内部で行われる必要があります。そうでない場合、例外が発生します。操作はドキュメントメソッドを介して開始および停止されます。これらの呼び出し間で行われる更新はLUWを形成し、集合的に元に戻すか再適用するために使用できます。MuPDFの用語で言えば、「元に戻す」または「やり直す」ことができます。\"\n\n#: ../../recipes-journalling.rst:18 25ef245260a64a689f1ba395d0478ac2\nmsgid \"\"\n\"At any point, the journalling status can be queried: whether journalling \"\n\"is active, how many operations have been recorded, whether \\\"undo\\\" or \"\n\"\\\"redo\\\" is possible, the current position inside the journal, etc.\"\nmsgstr \"いつでも、ジャーナリングの状態をクエリできます。ジャーナリングがアクティブかどうか、いくつの操作が記録されたか、元に戻すかやり直すかが可能か、ジャーナル内の現在位置などがわかります。\"\n\n#: ../../recipes-journalling.rst:19 892e3b69463b47138a6b723746d7696b\nmsgid \"\"\n\"The journal can be **saved to** or **loaded from** a file. These are \"\n\"document methods.\"\nmsgstr \"ジャーナルはファイルに保存またはロードできます。これらはドキュメントメソッドです。\"\n\n#: ../../recipes-journalling.rst:20 cdc871b87c994a95b38a0893539bf950\nmsgid \"\"\n\"When loading a journal file, compatibility with the document is checked \"\n\"and journalling is automatically enabled upon success.\"\nmsgstr \"ジャーナルファイルをロードする際には、ドキュメントとの互換性がチェックされ、成功した場合に自動的にジャーナリングが有効になります。\"\n\n#: ../../recipes-journalling.rst:21 1196a86518ec42bca06599556dfdd95a\nmsgid \"\"\n\"For an **existing** PDF being journalled, a special new save method is \"\n\"available: :meth:`Document.save_snapshot`. This performs a special \"\n\"incremental save that includes all journalled updates so far. If its \"\n\"journal is saved at the same time (immediately after the document \"\n\"snapshot), then document and journal are in sync and can later on be used\"\n\" together to undo or redo operations or to continue journalled updates --\"\n\" just as if there had been no interruption.\"\nmsgstr \"\"\n\"ジャーナリングされている既存のPDFに対しては、特別な新しい保存メソッドが利用可能です。:meth:`Document.save_snapshot`\"\n\" \"\n\"これにより、これまでにジャーナリングされたすべての更新を含む特別なインクリメンタル保存が行われます。そのジャーナルも同時に保存される場合（ドキュメントスナップショットの直後に保存）、ドキュメントとジャーナルは同期され、後で操作を元に戻したりやり直したりするために一緒に使用できるようになります。まるで中断がなかったかのように。\"\n\n#: ../../recipes-journalling.rst:22 9d858c95d29142a3a507fa019d4e9d37\nmsgid \"\"\n\"The snapshot PDF is a valid PDF in every aspect and fully usable. If the \"\n\"document is however changed in any way without using its journal file, \"\n\"then a desynchronization will take place and the journal is rendered \"\n\"unusable.\"\nmsgstr \"スナップショットPDFは、あらゆる側面で有効なPDFであり、完全に使用可能です。ただし、ジャーナルファイルを使用せずにドキュメントが変更された場合、同期が取れなくなり、ジャーナルは利用できなくなります。\"\n\n#: ../../recipes-journalling.rst:23 4e9981f3904e441abb451168eda31059\nmsgid \"\"\n\"Snapshot files are structured like incremental updates. Nevertheless, the\"\n\" internal journalling logic requires, that saving **must happen to a new \"\n\"file**. So the user should develop a file naming convention to support \"\n\"recognizable relationships between an original PDF, like `original.pdf` \"\n\"and its snapshot sets, like `original-snap1.pdf` / `original-snap1.log`, \"\n\"`original-snap2.pdf` / `original-snap2.log`, etc.\"\nmsgstr \"\"\n\"スナップショットファイルはインクリメンタルな更新のように構造化されています。ただし、内部のジャーナリングロジックでは、新しいファイルに保存する必要があります。したがって、ユーザーはオリジナルのPDF（例：\"\n\" `original.pdf` ）とそのスナップショットセット（例： `original-snap1.pdf` / `original-\"\n\"snap1.log` 、 `original-snap2.pdf` / `original-snap2.log` \"\n\"など）の間に認識可能な関係をサポートするためのファイル命名規則を開発する必要があります。\"\n\n#: ../../recipes-journalling.rst:26 264672a5144c439aa2688cf062e5a892\nmsgid \"Example Session 1\"\nmsgstr \"例セッション1\"\n\n#: ../../recipes-journalling.rst:27 ../../recipes-journalling.rst:98\n#: 8fc51b450a4641898c023ca78938b76c b070a7f183aa43c1952ff72bd0f73150\nmsgid \"Description:\"\nmsgstr \"説明：\"\n\n#: ../../recipes-journalling.rst:29 47b36e04f5904ef6b8e643c6c2931dc9\nmsgid \"\"\n\"Make a new PDF and enable journalling. Then add a page and some text \"\n\"lines -- each as a separate operation.\"\nmsgstr \"新しいPDFを作成し、ジャーナリングを有効にします。次に、ページを追加し、いくつかのテキスト行を別々の操作として追加します。\"\n\n#: ../../recipes-journalling.rst:30 d39c4b27b3da4f7d87244024fe21133e\nmsgid \"\"\n\"Navigate within the journal, undoing and redoing these updates and \"\n\"displaying status and file results::\"\nmsgstr \"ジャーナル内を移動し、これらの更新を元に戻したりやり直したりし、状態やファイルの結果を表示します::\"\n\n#: ../../recipes-journalling.rst:97 7f4dff6cd221460f9f0864bb65418846\nmsgid \"Example Session 2\"\nmsgstr \"例セッション2\"\n\n#: ../../recipes-journalling.rst:100 739153cf7c154739af31ab2abb5d842f\nmsgid \"\"\n\"Similar to previous, but after undoing some operations, we now add a \"\n\"different update. This will cause:\"\nmsgstr \"前回と同様ですが、いくつかの操作を元に戻した後、異なる更新を追加します。これにより、次のことが起こります：\"\n\n#: ../../recipes-journalling.rst:102 d1dfb6a4d5d948b6981dc9765882191b\nmsgid \"permanent removal of the undone journal entries\"\nmsgstr \"元に戻されたジャーナルエントリが永久に削除されます。\"\n\n#: ../../recipes-journalling.rst:103 19eab643d86a4d72b86f188ae3dd2592\nmsgid \"the new update operation will become the new last entry.\"\nmsgstr \"新しい更新操作は新しい最後のエントリになります。\"\n\n#: ../../footer.rst:60 187a959e74914bfe8f8d8164226852bd\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-low-level-interfaces.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7f129fba564145f8954ab3f7e226f0ec\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 c67d240759fd40d187a0308599adeca9\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 076a135f5e7c4cc5bd9192d710ce8cdb\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-low-level-interfaces.rst:7 4f7ca622e5254dcb820080c8ec29fe16\nmsgid \"Low-Level Interfaces\"\nmsgstr \"低レベルインターフェース\"\n\n#: ../../recipes-low-level-interfaces.rst:10 1fea1e3b7f2f4f31a3c902bf61e962c9\nmsgid \"\"\n\"Numerous methods are available to access and manipulate PDF files on a \"\n\"fairly low level. Admittedly, a clear distinction between \\\"low level\\\" \"\n\"and \\\"normal\\\" functionality is not always possible or subject to \"\n\"personal taste.\"\nmsgstr \"PDFファイルにアクセスして操作するための多くのメソッドが低レベルで利用可能です。正直なところ、「低レベル」機能と「通常」機能の明確な区別は常にできるわけではなく、個人の好みによるところもあります。\"\n\n#: ../../recipes-low-level-interfaces.rst:12 1de25fa4e10d4576a94ca8b7096618bd\nmsgid \"\"\n\"It also may happen, that functionality previously deemed low-level is \"\n\"later on assessed as being part of the normal interface. This has \"\n\"happened in v1.14.0 for the class :ref:`Tools` - you now find it as an \"\n\"item in the Classes chapter.\"\nmsgstr \"\"\n\"また、以前は低レベルと考えられていた機能が後に通常のインターフェースの一部として評価されることもあります。例えば、バージョン1.14.0ではクラス\"\n\" :ref:`Tools` についてそのようなことが起きており、現在では「Classes」のセクションで見つけることができます。\"\n\n#: ../../recipes-low-level-interfaces.rst:14 1007d8a4ff5c4147805c1dc892b9b29c\nmsgid \"\"\n\"It is a matter of documentation only in which chapter of the \"\n\"documentation you find what you are looking for. Everything is available \"\n\"and always via the same interface.\"\nmsgstr \"何を探しているかに関しては、ドキュメントのどのセクションにあるかはドキュメンテーションのみの問題です。すべての情報は同じインターフェースを介して常に利用可能です。\"\n\n#: ../../recipes-low-level-interfaces.rst:19 f087f3a96eec4b1a9dd86d6e8a3cffd7\nmsgid \"How to Iterate through the :data:`xref` Table\"\nmsgstr \":data:`xref` テーブルのイテレーション方法\"\n\n#: ../../recipes-low-level-interfaces.rst:20 0027f20fcd894b3f921d205dbf3c6fbb\nmsgid \"\"\n\"A PDF's :data:`xref` table is a list of all objects defined in the file. \"\n\"This table may easily contain many thousands of entries -- the manual \"\n\":ref:`AdobeManual` for example has 127,000 objects. Table entry \\\"0\\\" is \"\n\"reserved and must not be touched. The following script loops through the \"\n\":data:`xref` table and prints each object's definition::\"\nmsgstr \"\"\n\"PDFの :data:`xref` \"\n\"テーブルはファイル内で定義されているすべてのオブジェクトのリストです。このテーブルには非常に多くのエントリが含まれることがあります - 例えば \"\n\":ref:`AdobeManual` \"\n\"マニュアルには127,000のオブジェクトが含まれています。テーブルのエントリ「0」は予約されており、触れてはいけません\"\n\n#: ../../recipes-low-level-interfaces.rst:32 bf35a4cef5db4592ba20e8879d737aff\nmsgid \"This produces the following output::\"\nmsgstr \"これにより、以下の出力が生成されます::\"\n\n#: ../../recipes-low-level-interfaces.rst:72 b83975ea49a84c1a8993fd6918a32c64\nmsgid \"A PDF object definition is an ordinary ASCII string.\"\nmsgstr \"PDFオブジェクトの定義は通常のASCII文字列です。\"\n\n#: ../../recipes-low-level-interfaces.rst:77 2cab525052174e5889a8b5eeea539330\nmsgid \"How to Handle Object Streams\"\nmsgstr \"オブジェクトストリームの処理方法\"\n\n#: ../../recipes-low-level-interfaces.rst:78 658c13e1cc6947b09fc237301c2bc678\nmsgid \"\"\n\"Some object types contain additional data apart from their object \"\n\"definition. Examples are images, fonts, embedded files or commands \"\n\"describing the appearance of a page.\"\nmsgstr \"オブジェクトストリームの処理方法一部のオブジェクトタイプには、オブジェクト定義以外に追加のデータが含まれています。例として、画像、フォント、埋め込みファイル、またはページの外観を記述するコマンドが挙げられます。\"\n\n#: ../../recipes-low-level-interfaces.rst:80 2796bcc0f1ed4c599541dd675171586e\nmsgid \"\"\n\"Objects of these types are called \\\"stream objects\\\". PyMuPDF allows \"\n\"reading an object's stream via method :meth:`Document.xref_stream` with \"\n\"the object's :data:`xref` as an argument. It is also possible to write \"\n\"back a modified version of a stream using :meth:`Document.update_stream`.\"\nmsgstr \"\"\n\"これらのタイプのオブジェクトは「ストリームオブジェクト」と呼ばれます。PyMuPDFでは、メソッド \"\n\":meth:`Document.xref_stream` を使用して、オブジェクトの :data:`xref` \"\n\"を引数としてオブジェクトのストリームを読み取ることができます。また、:meth:`Document.update_stream` \"\n\"を使用して、ストリームの変更されたバージョンを書き戻すことも可能です。\"\n\n#: ../../recipes-low-level-interfaces.rst:82 3771d4779f8f40dba59160b01c9ee9cf\nmsgid \"\"\n\"Assume that the following snippet wants to read all streams of a PDF for \"\n\"whatever reason::\"\nmsgstr \"次のスニペットが、PDFのすべてのストリームを読み取るためのものであると仮定します::\"\n\n#: ../../recipes-low-level-interfaces.rst:91 9c27d6d70d6b40fba9999600e789863f\nmsgid \"\"\n\":meth:`Document.xref_stream` automatically returns a stream decompressed \"\n\"as a bytes object -- and :meth:`Document.update_stream` automatically \"\n\"compresses it if beneficial.\"\nmsgstr \"\"\n\":meth:`Document.xref_stream` \"\n\"は自動的にバイトオブジェクトとして展開されたストリームを返し、:meth:`Document.update_stream` \"\n\"は必要に応じて自動的に圧縮されます。\"\n\n#: ../../recipes-low-level-interfaces.rst:96 8090153b26c14df4a507877668bc7624\nmsgid \"How to Handle Page Contents\"\nmsgstr \"ページ内容の処理方法\"\n\n#: ../../recipes-low-level-interfaces.rst:97 848d7acefeb245dc8af34902fe0aff24\nmsgid \"\"\n\"A PDF page can have zero or multiple :data:`contents` objects. These are \"\n\"stream objects describing **what** appears **where** and **how** on a \"\n\"page (like text and images). They are written in a special mini-language \"\n\"described e.g. in chapter \\\"APPENDIX A - Operator Summary\\\" on page 643 \"\n\"of the :ref:`AdobeManual`.\"\nmsgstr \"\"\n\"PDFページにはゼロまたは複数の :data:`contents` \"\n\"オブジェクトが存在できます。これらは、ページ上に何がどこにどのように表示されるかを記述するストリームオブジェクト（テキストや画像など）です。これらは、:ref:`AdobeManual`\"\n\" のページ643の「付録A - オペレーターサマリー」などで説明されている特別なミニ言語で記述されています。\"\n\n#: ../../recipes-low-level-interfaces.rst:99 4188f5c77de44ced870411c31528cec5\nmsgid \"\"\n\"Every PDF reader application must be able to interpret the contents \"\n\"syntax to reproduce the intended appearance of the page.\"\nmsgstr \"すべてのPDFリーダーアプリケーションは、コンテンツの構文を解釈してページの意図した表示を再現できる必要があります。\"\n\n#: ../../recipes-low-level-interfaces.rst:101 1f87bc0453d24082b53750397e2d3f74\nmsgid \"\"\n\"If multiple :data:`contents` objects are provided, they must be \"\n\"interpreted in the specified sequence in exactly the same way as if they \"\n\"were provided as a concatenation of the several.\"\nmsgstr \"\"\n\"複数の :data:`contents` \"\n\"オブジェクトが提供される場合、それらは複数のコンテンツを連結した場合とまったく同じ方法で、指定された順序で解釈される必要があります。\"\n\n#: ../../recipes-low-level-interfaces.rst:103 c8df9beb4ec84255a6972a53be5fca52\nmsgid \"\"\n\"There are good technical arguments for having multiple :data:`contents` \"\n\"objects:\"\nmsgstr \"複数の :data:`contents` オブジェクトを持つメリットには、次のような良い技術的理由があります：\"\n\n#: ../../recipes-low-level-interfaces.rst:105 98cc88c334df4c1ebefdc905e195d627\nmsgid \"\"\n\"It is a lot easier and faster to just add new :data:`contents` objects \"\n\"than maintaining a single big one (which entails reading, decompressing, \"\n\"modifying, recompressing, and rewriting it for each change).\"\nmsgstr \"\"\n\"新しい :data:`contents` \"\n\"オブジェクトを追加するだけで、単一の大きなコンテンツオブジェクトを維持するよりもはるかに簡単で高速です（各変更のたびに読み取り、展開、変更、再圧縮、書き直しが必要です）。\"\n\n#: ../../recipes-low-level-interfaces.rst:106 f2458f2703db48d58afa2677cb1a6f0b\nmsgid \"\"\n\"When working with incremental updates, a modified big :data:`contents` \"\n\"object will bloat the update delta and can thus easily negate the \"\n\"efficiency of incremental saves.\"\nmsgstr \"\"\n\"増分更新を使用する場合、修正された大きな :data:`contents` \"\n\"オブジェクトは更新デルタを膨らませ、増分保存の効率を簡単に打ち消す可能性があります。\"\n\n#: ../../recipes-low-level-interfaces.rst:108 774608ae29314d87af2590cc55b0b96a\nmsgid \"\"\n\"For example, PyMuPDF adds new, small :data:`contents` objects in methods \"\n\":meth:`Page.insert_image`, :meth:`Page.show_pdf_page` and the \"\n\":ref:`Shape` methods.\"\nmsgstr \"\"\n\"例えば、PyMuPDFは :meth:`Page.insert_image` 、 :meth:`Page.show_pdf_page` 、および\"\n\"  :ref:`Shape` メソッドで新しい小さな :data:`contents` オブジェクトを追加します。\"\n\n#: ../../recipes-low-level-interfaces.rst:110 5cc4b562e7f643678dec3abbd5c901af\nmsgid \"\"\n\"However, there are also situations when a **single** :data:`contents` \"\n\"object is beneficial: it is easier to interpret and more compressible \"\n\"than multiple smaller ones.\"\nmsgstr \"\"\n\"ただし、単一の :data:`contents` \"\n\"オブジェクトが有益な状況もあります。それは複数の小さなオブジェクトよりも解釈が容易で、圧縮が効果的です。\"\n\n#: ../../recipes-low-level-interfaces.rst:112 f8d8be1710d74bb9b417dc9948c862c9\nmsgid \"Here are two ways of combining multiple contents of a page::\"\nmsgstr \"以下は、ページの複数のコンテンツを組み合わせる2つの方法です：\"\n\n#: ../../recipes-low-level-interfaces.rst:124 0016b0cc7db9493c9b5bfecfdd25e99c\nmsgid \"\"\n\"The clean function :meth:`Page.clean_contents` does a lot more than just \"\n\"glueing :data:`contents` objects: it also corrects and optimizes the PDF \"\n\"operator syntax of the page and removes any inconsistencies with the \"\n\"page's object definition.\"\nmsgstr \"\"\n\":meth:`Page.clean_contents` は、:data:`contents` \"\n\"オブジェクトを結合するだけでなく、ページのPDFオペレータ構文を修正し最適化し、ページのオブジェクト定義との整合性を保つためにも役立ちます。\"\n\n#: ../../recipes-low-level-interfaces.rst:129 8fd84d6a4af441adb8fcf1c77aa5b0bd\nmsgid \"How to Access the PDF Catalog\"\nmsgstr \"PDFカタログへのアクセス方法\"\n\n#: ../../recipes-low-level-interfaces.rst:130 2a2e41fa0c34401ea22c6f2ed40a89e7\nmsgid \"\"\n\"This is a central (\\\"root\\\") object of a PDF. It serves as a starting \"\n\"point to reach important other objects and it also contains some global \"\n\"options for the PDF::\"\nmsgstr \"これはPDFの中心的な（\\\"ルート\\\"）オブジェクトです。これは重要な他のオブジェクトに到達するための出発点として機能し、PDFのいくつかのグローバルオプションも含まれています::\"\n\n#: ../../recipes-low-level-interfaces.rst:146 5b118633d9a341a1a95aed016917f5d2\nmsgid \"\"\n\"Indentation, line breaks and comments are inserted here for clarification\"\n\" purposes only and will not normally appear. For more information on the \"\n\"PDF catalog see section 7.7.2 on page 71 of the :ref:`AdobeManual`.\"\nmsgstr \"\"\n\"字下げ、改行、コメントは説明のために挿入されており、通常は表示されません。PDFカタログの詳細については、 :ref:`AdobeManual` \"\n\"のページ71のセクション7.7.2を参照してください。\"\n\n#: ../../recipes-low-level-interfaces.rst:151 f6b9f5c2736444a09a44be0af1efd3ef\nmsgid \"How to Access the PDF File Trailer\"\nmsgstr \"PDFファイルトレーラーへのアクセス方法\"\n\n#: ../../recipes-low-level-interfaces.rst:152 4cb33f7607ff4b7da3a368b706d7f85d\nmsgid \"\"\n\"The trailer of a PDF file is a :data:`dictionary` located towards the end\"\n\" of the file. It contains special objects, and pointers to important \"\n\"other information. See :ref:`AdobeManual` p. 42. Here is an overview:\"\nmsgstr \"\"\n\"PDFファイルのトレーラーは、ファイルの終わりに位置する :data:`dictionary` \"\n\"です。特別なオブジェクトと、重要な他の情報へのポインタが含まれています。:ref:`AdobeManual` を参照してください（p. \"\n\"42）。以下に概要を示します：\"\n\n#: ../../recipes-low-level-interfaces.rst:155 6a08c29e38b14b4f8780edbf2bbd57ed\nmsgid \"**Key**\"\nmsgstr \"**キー**\"\n\n#: ../../recipes-low-level-interfaces.rst:155 58913ef5bc0e42449995f9ddc470a9b6\nmsgid \"**Type**\"\nmsgstr \"**タイプ**\"\n\n#: ../../recipes-low-level-interfaces.rst:155 6bd41f1c095b4146a4be333408ae4d28\nmsgid \"**Value**\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:157 4f3f1be3c87948899e54efc916c7ef18\nmsgid \"Size\"\nmsgstr \"**値**\"\n\n#: ../../recipes-low-level-interfaces.rst:157\n#: ../../recipes-low-level-interfaces.rst:158\n#: ../../recipes-low-level-interfaces.rst:163 81a6a91f16444f15bdeeaaf278f1bcd1\n#: 8682c7b530344453ade63634c104ed4f f11a36ccb1b94cd3ae600b685375afff\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:157 c285913e7e4943f9867315f2d6712e7f\nmsgid \"Number of entries in the cross-reference table + 1.\"\nmsgstr \"クロスリファレンステーブル内のエントリ数 + 1 の数値。\"\n\n#: ../../recipes-low-level-interfaces.rst:158 c49bb116e66c4fca9cdeb500ae675247\nmsgid \"Prev\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:158 28fbdab151c14d60acbe435e09d03829\nmsgid \"Offset to previous :data:`xref` section (indicates incremental updates).\"\nmsgstr \"前の :data:`xref` セクションへのオフセット（増分更新を示す）。\"\n\n#: ../../recipes-low-level-interfaces.rst:159 96893c3d42a943ffaa753c2af598ddda\nmsgid \"Root\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:159\n#: ../../recipes-low-level-interfaces.rst:160\n#: ../../recipes-low-level-interfaces.rst:161 17e32472677349bfa94d61bc793d8475\n#: 2d049d53c6cd4ae8a2bc07f1cbcf53bb ce33dca31774448c9bdd1e213de5d090\nmsgid \"dictionary\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:159 fecd0772f75c49fdb36a4962c490461e\nmsgid \"(indirect) Pointer to the catalog. See previous section.\"\nmsgstr \"(間接的) カタログへのポインタ。前のセクションを参照してください。\"\n\n#: ../../recipes-low-level-interfaces.rst:160 b7b167190b0149ce9bdd9ef671d03ae2\nmsgid \"Encrypt\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:160 aa8f56b6637c4a7ca41846fa1ebf6eca\nmsgid \"Pointer to encryption object (encrypted files only).\"\nmsgstr \"(暗号化されたファイルのみ) 暗号化オブジェクトへのポインタ。\"\n\n#: ../../recipes-low-level-interfaces.rst:161 d9be1827baa242068f64cd1307f9bd58\nmsgid \"Info\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:161 597be1c0e13342c694e56f1faf8dcca5\nmsgid \"(indirect) Pointer to information (metadata).\"\nmsgstr \"(間接的) 情報（メタデータ）へのポインタ。\"\n\n#: ../../recipes-low-level-interfaces.rst:162 66abcc5c41b044d7ba24bef4374f4cba\nmsgid \"ID\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:162 e6d762fa8f38487992b7f2ddc8737388\nmsgid \"array\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:162 ae4de832cc2c4e1cb9943cb9a61596da\nmsgid \"File identifier consisting of two byte strings.\"\nmsgstr \"2つのバイト文字列からなるファイル識別子。\"\n\n#: ../../recipes-low-level-interfaces.rst:163 fe39430132414ae0b7367e63724369e0\nmsgid \"XRefStm\"\nmsgstr \"\"\n\n#: ../../recipes-low-level-interfaces.rst:163 2f5419e850a744d790f2b70a0e221c5a\nmsgid \"Offset of a cross-reference stream. See :ref:`AdobeManual` p. 49.\"\nmsgstr \"クロスリファレンスストリームのオフセット。:ref:`AdobeManual` を参照してください（p. 49）。\"\n\n#: ../../recipes-low-level-interfaces.rst:166 f658e5b17a384d9c90104cba97aa85ff\nmsgid \"\"\n\"Access this information via PyMuPDF with :meth:`Document.pdf_trailer` or,\"\n\" equivalently, via :meth:`Document.xref_object` using -1 instead of a \"\n\"valid :data:`xref` number.\"\nmsgstr \"\"\n\"これらの情報には、PyMuPDFを使用して :meth:`Document.pdf_trailer` または、同等の \"\n\":meth:`Document.xref_object` を使用して -1 の代わりに有効な :data:`xref` \"\n\"番号を指定することでアクセスします。\"\n\n#: ../../recipes-low-level-interfaces.rst:187 98759bbd8d114604a80fbf742832adba\nmsgid \"How to Access XML Metadata\"\nmsgstr \"XMLメタデータへのアクセス方法\"\n\n#: ../../recipes-low-level-interfaces.rst:188 a4c560abb05646a6b21fccc292008ea0\nmsgid \"\"\n\"A PDF may contain XML metadata in addition to the standard metadata \"\n\"format. In fact, most PDF viewer or modification software adds this type \"\n\"of information when saving the PDF (Adobe, Nitro PDF, PDF-XChange, etc.).\"\nmsgstr \"\"\n\"PDFには、標準のメタデータ形式に加えてXMLメタデータが含まれている場合があります。実際、ほとんどのPDFビューアや編集ソフトウェアは、PDFを保存する際に（Adobe、Nitro\"\n\" PDF、PDF-XChangeなど）この種の情報を追加します。\"\n\n#: ../../recipes-low-level-interfaces.rst:190 a02f8f95ed834b4386f05f01b7baf217\nmsgid \"\"\n\"PyMuPDF has no way to **interpret or change** this information directly, \"\n\"because it contains no XML features. XML metadata is however stored as a \"\n\":data:`stream` object, so it can be read, modified with appropriate \"\n\"software and written back.\"\nmsgstr \"\"\n\"しかし、PyMuPDFはXMLの機能を持たないため、この情報を直接解釈または変更する方法はありません。ただし、XMLメタデータは \"\n\":data:`stream` オブジェクトとして格納されているため、適切なソフトウェアで読み取り、変更し、書き戻すことができます。\"\n\n#: ../../recipes-low-level-interfaces.rst:202 763734a1837d4847a3c820225381f4cb\nmsgid \"\"\n\"Using some XML package, the XML data can be interpreted and / or modified\"\n\" and then stored back. The following also works, if the PDF previously \"\n\"had no XML metadata::\"\nmsgstr \"あるXMLパッケージを使用して、XMLデータを解釈および/または変更し、それを保存し直すことができます。次の方法もPDFに以前にXMLメタデータがない場合にも機能します::\"\n\n#: ../../recipes-low-level-interfaces.rst:213 b484e4babb6b4821a2d4ca50b936f40b\nmsgid \"How to Extend PDF Metadata\"\nmsgstr \"PDFメタデータの拡張方法\"\n\n#: ../../recipes-low-level-interfaces.rst:214 bd8ade0701494f0aa8d64389ba8c01db\nmsgid \"\"\n\"Attribute :attr:`Document.metadata` is designed so it works for all \"\n\":ref:`supported document types<Supported_File_Types>` in the same way: it\"\n\" is a Python dictionary with a **fixed set of key-value pairs**. \"\n\"Correspondingly, :meth:`Document.set_metadata` only accepts standard \"\n\"keys.\"\nmsgstr \"\"\n\"属性  :attr:`Document.metadata`  は、すべての :ref:`サポートされている \"\n\"<Supported_File_Types>` \"\n\"ドキュメントタイプで同じ方法で機能するように設計されています。これは、固定されたキーと値のセットを持つPython辞書です。同様に、:meth:`Document.set_metadata`\"\n\" は標準のキーのみを受け入れます。\"\n\n#: ../../recipes-low-level-interfaces.rst:216 2ed9e5740749448898a94bedd85fa94f\nmsgid \"\"\n\"However, PDFs may contain items not accessible like this. Also, there may\"\n\" be reasons to store additional information, like copyrights. Here is a \"\n\"way to handle **arbitrary metadata items** by using PyMuPDF low-level \"\n\"functions.\"\nmsgstr \"しかし、PDFにはこのようにアクセスできない項目が含まれている場合があります。また、著作権などの追加情報を保存する理由もあるかもしれません。以下は、PyMuPDFの低レベル関数を使用して任意のメタデータ項目を処理する方法です。\"\n\n#: ../../recipes-low-level-interfaces.rst:218 f2e1b634d30a481da6cb600b52f2dccc\nmsgid \"As an example, look at this standard metadata output of some PDF::\"\nmsgstr \"例として、次のPDFの標準メタデータ出力をご覧ください::\"\n\n#: ../../recipes-low-level-interfaces.rst:237 ae127729cd53409cb04f9ebc390699c4\nmsgid \"\"\n\"Use the following code to see **all items** stored in the metadata \"\n\"object::\"\nmsgstr \"以下のコードを使用して、メタデータオブジェクトに保存されているすべてのアイテムを表示します::\"\n\n#: ../../recipes-low-level-interfaces.rst:265 f219d010f8094f62934815b489d0dc25\nmsgid \"\"\n\"*Vice versa*, you can also **store private metadata items** in a PDF. It \"\n\"is your responsibility to make sure that these items conform to PDF \"\n\"specifications - especially they must be (unicode) strings. Consult \"\n\"section 14.3 (p. 548) of the :ref:`AdobeManual` for details and caveats::\"\nmsgstr \"\"\n\"逆に、PDFにはプライベートなメタデータアイテムを保存することもできます。これらのアイテムがPDF仕様に準拠していることを確認する責任はあなたにあります。特に、これらは（Unicode）文字列である必要があります。詳細や注意事項については、Adobe\"\n\" PDFリファレンスのセクション14.3（p. 548）を参照してください::\"\n\n#: ../../recipes-low-level-interfaces.rst:287 2dc3761486a541f6821711dfd609da05\nmsgid \"\"\n\"To delete selected keys, use `doc.xref_set_key(xref, \\\"mykey\\\", \"\n\"\\\"null\\\")`. As explained in the next section, string \\\"null\\\" is the PDF \"\n\"equivalent to Python's `None`. A key with that value will be treated as \"\n\"not being specified -- and physically removed in garbage collections.\"\nmsgstr \"\"\n\"選択したキーを削除するには、`doc.xref_set_key(xref, \\\"mykey\\\", \\\"null\\\")` \"\n\"を使用します。次のセクションで説明されているように、文字列 `\\\"null\\\"` はPDFのバージョンでPythonの `None` \"\n\"に相当します。その値のキーは指定されていないものとして扱われ、ガベージコレクションで物理的に削除されます。\"\n\n#: ../../recipes-low-level-interfaces.rst:292 b8e1f01138dd4a638ffd1e3689508d1c\nmsgid \"How to Read and Update PDF Objects\"\nmsgstr \"PDFオブジェクトの読み取りと更新方法\"\n\n#: ../../recipes-low-level-interfaces.rst:297 c7c33727bafc478ca88a1cdae0ec859b\nmsgid \"\"\n\"There also exist granular, elegant ways to access and manipulate selected\"\n\" PDF :data:`dictionary` keys.\"\nmsgstr \"選択したPDF :data:`dictionary` キーにアクセスし、操作するための粒状で洗練された方法も存在します。\"\n\n#: ../../recipes-low-level-interfaces.rst:299 04aa0e1d70b944b3a904ea382f4f0c30\nmsgid \"\"\n\":meth:`Document.xref_get_keys` returns the PDF keys of the object at \"\n\":data:`xref`::\"\nmsgstr \":meth:`Document.xref_get_keys` は、:data:`xref` のオブジェクトのPDFキーを返します::\"\n\n#: ../../recipes-low-level-interfaces.rst:308 ec3415a9ffc54434860c48bc58bd55d9\nmsgid \"Compare with the full object definition::\"\nmsgstr \"完全なオブジェクト定義と比較してください::\"\n\n#: ../../recipes-low-level-interfaces.rst:319 4ee823aae30f4627b0f7c02f4267bfdc\nmsgid \"\"\n\"Single keys can also be accessed directly via \"\n\":meth:`Document.xref_get_key`. The value **always is a string** together \"\n\"with type information, that helps with interpreting it::\"\nmsgstr \"\"\n\"単一のキーは、 :meth:`Document.xref_get_key`  \"\n\"を介して直接アクセスすることもできます。値は常に文字列であり、それを解釈するのに役立つタイプ情報が含まれています::\"\n\n#: ../../recipes-low-level-interfaces.rst:324 5b603693f93c4e03a5111618579b46ce\nmsgid \"Here is a full listing of the above page keys::\"\nmsgstr \"以下は、上記のページキーの完全な一覧です::\"\n\n#: ../../recipes-low-level-interfaces.rst:335 f13dcde484e24d32bc88ea9b8cf371dd\nmsgid \"\"\n\"An undefined key inquiry returns `('null', 'null')` -- PDF object type \"\n\"`null` corresponds to `None` in Python. Similar for the booleans `true` \"\n\"and `false`.\"\nmsgstr \"\"\n\"未定義のキーの問い合わせは、`('null', 'null')` を返します - PDFオブジェクトタイプ `null` はPythonの \"\n\"`None` に対応します。 `true` および `false` も同様です。\"\n\n#: ../../recipes-low-level-interfaces.rst:336 14eee493b6bb4c06b2afcbdade3ca9e7\nmsgid \"\"\n\"Let us add a new key to the page definition that sets its rotation to 90 \"\n\"degrees (you are aware that there actually exists \"\n\":meth:`Page.set_rotation` for this?)::\"\nmsgstr \"\"\n\"ページ定義に新しいキーを追加して、その回転角を90度に設定しましょう（実際には :meth:`Page.set_rotation` \"\n\"が存在することを知っているかと思いますが、そうですか？）::\"\n\n#: ../../recipes-low-level-interfaces.rst:351 b9ecea1e87e7421faea4ae09003de94f\nmsgid \"\"\n\"This method can also be used to remove a key from the :data:`xref` \"\n\"dictionary by setting its value to `null`: The following will remove the \"\n\"rotation specification from the page: `doc.xref_set_key(page.xref, \"\n\"\\\"Rotate\\\", \\\"null\\\")`. Similarly, to remove all links, annotations and \"\n\"fields from a page, use `doc.xref_set_key(page.xref, \\\"Annots\\\", \"\n\"\\\"null\\\")`. Because `Annots` by definition is an array, setting en empty \"\n\"array with the statement `doc.xref_set_key(page.xref, \\\"Annots\\\", \"\n\"\\\"[]\\\")` would do the same job in this case.\"\nmsgstr \"\"\n\"このメソッドは、値を `null` に設定することで :data:`xref` \"\n\"辞書からキーを削除するためにも使用できます：次の方法は、ページから回転指定を削除します： `doc.xref_set_key(page.xref,\"\n\" \\\"Rotate\\\", \\\"null\\\")` 。同様に、ページからすべてのリンク、注釈、およびフィールドを削除するには、 \"\n\"`doc.xref_set_key(page.xref, \\\"Annots\\\", \\\"null\\\")`  を使用します。`Annots` \"\n\"は定義上配列であるため、`doc.xref_set_key(page.xref, \\\"Annots\\\", \\\"[]\\\")` \"\n\"という文で空の配列を設定すると、同じ操作が実行されます。\"\n\n#: ../../recipes-low-level-interfaces.rst:353 25ee5ad120ca43a7af7fb238b8ee91cd\nmsgid \"\"\n\"PDF dictionaries can be hierarchically nested. In the following page \"\n\"object definition both, `Font` and `XObject` are subdictionaries of \"\n\"`Resources`::\"\nmsgstr \"\"\n\"PDF辞書は階層的に入れ子にすることができます。次のページオブジェクト定義では、`Font` と `XObject` は両方とも \"\n\"`Resources` のサブディクショナリです::\"\n\n#: ../../recipes-low-level-interfaces.rst:373 166311ecb59d42579d5324506515d2e5\nmsgid \"\"\n\"The above situation **is supported** by methods \"\n\":meth:`Document.xref_set_key` and :meth:`Document.xref_get_key`: use a \"\n\"path-like notation to point at the required key. For example, to retrieve\"\n\" the value of key `Im1` above, specify the complete chain of dictionaries\"\n\" \\\"above\\\" it in the key argument: `\\\"Resources/XObject/Im1\\\"`::\"\nmsgstr \"\"\n\"上記の状況は、メソッド :meth:`Document.xref_set_key` と :meth:`Document.xref_get_key`\"\n\" によってサポートされています。必要なキーを指すために、パスのような表記法を使用します。たとえば、上記の `Im1` \"\n\"キーの値を取得するには、キー引数にその上位の辞書の完全なチェーン `\\\"Resources/XObject/Im1\\\"` を指定します::\"\n\n#: ../../recipes-low-level-interfaces.rst:378 decc969788824b2f905d28ed9ea37c97\nmsgid \"\"\n\"The path notation can also be used to **directly set a value**: use the \"\n\"following to let `Im1` point to a different object::\"\nmsgstr \"パス表記法は、値を直接設定するためにも使用できます。以下を使用して、`Im1` を異なるオブジェクトを指すように設定します::\"\n\n#: ../../recipes-low-level-interfaces.rst:399 8134074039144ebca0e928b428cf7ad4\nmsgid \"\"\n\"Be aware, that **no semantic checks** whatsoever will take place here: if\"\n\" the PDF has no xref 9999, it won't be detected at this point.\"\nmsgstr \"ここでは、何の意味的なチェックも行われないことに注意してください。PDFにxref 9999が存在しない場合、この段階では検出されません。\"\n\n#: ../../recipes-low-level-interfaces.rst:401 d717c7f21a174300a90bb992653ab939\nmsgid \"\"\n\"If a key does not exist, it will be created by setting its value. \"\n\"Moreover, if any intermediate keys do not exist either, they will also be\"\n\" created as necessary. The following creates an array `D` several levels \"\n\"below the existing dictionary `A`. Intermediate dictionaries `B` and `C` \"\n\"are automatically created::\"\nmsgstr \"\"\n\"キーが存在しない場合、その値を設定することで新しく作成されます。さらに、中間のキーが存在しない場合も、必要に応じて自動的に作成されます。次の例では、既存の辞書\"\n\" `A` の下にいくつかの階層下に配列 `D` を作成しています。中間の辞書 `B` と `C` も自動的に作成されます::\"\n\n#: ../../recipes-low-level-interfaces.rst:421 79d1fc2866c6405e852e7bc1d59c5f72\nmsgid \"\"\n\"When setting key values, basic **PDF syntax checking** will be done by \"\n\"MuPDF. For example, new keys can only be created **below a dictionary**. \"\n\"The following tries to create some new string item `E` below the \"\n\"previously created array `D`::\"\nmsgstr \"\"\n\"キーの値を設定する際には、MuPDFによって基本的なPDF構文のチェックが行われます。たとえば、新しいキーは辞書の下にのみ作成できます。次の例では、以前に作成された配列\"\n\" `D` の下に新しい文字列アイテム `E` を作成しようとしています：\"\n\n#: ../../recipes-low-level-interfaces.rst:429 891aef9e0fe9425881312a1752d59e9f\nmsgid \"\"\n\"It is also **not possible**, to create a key if some higher level key is \"\n\"an **\\\"indirect\\\"** object, i.e. an xref. In other words, xrefs can only \"\n\"be modified directly and not implicitly via other objects referencing \"\n\"them::\"\nmsgstr \"同様に、上位のキーが「間接」オブジェクト、つまりxrefである場合、キーを作成することはできません。言い換えれば、xrefは直接的に変更できるが、それを参照する他のオブジェクトを通じて暗黙的に変更することはできません::\"\n\n#: ../../recipes-low-level-interfaces.rst:442 cb6c84fd491f4c3eaab967eb4ab22326\nmsgid \"\"\n\"These are expert functions! There are no validations as to whether valid \"\n\"PDF objects, xrefs, etc. are specified. As with other low-level methods \"\n\"there is the risk to render the PDF, or parts of it unusable.\"\nmsgstr \"これらは専門家向けの機能です！有効なPDFオブジェクトやxrefなどが指定されているかどうかの検証はありません。他の低レベルメソッドと同様に、PDF全体またはその一部を利用不能にする可能性があるため注意が必要です。\"\n\n#: ../../footer.rst:60 4695c17edec440ea85382cf6f78ad072\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-multiprocessing.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 05b9195b227d4fbc825fc852831e4554\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 d1146968098a44928b810551252f816f\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 0072b638d978499db19c4b4f4f7a3707\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-multiprocessing.rst:17 0f0b2d7d9f684b409ff0e5784ca866ac\nmsgid \"Multiprocessing\"\nmsgstr \"マルチプロセッシング\"\n\n#: ../../recipes-multiprocessing.rst:19 3062a6b9aec34db2aec0a9bb17a0ef61\nmsgid \"\"\n\"|PyMuPDF| does not support running on multiple threads - doing so may \"\n\"cause incorrect behaviour or even crash Python itself.\"\nmsgstr \"\"\n\n#: ../../recipes-multiprocessing.rst:21 74aa37e95d05468c982d841a2f5e2366\nmsgid \"\"\n\"However, there is the option to use :title:`Python's` *multiprocessing* \"\n\"module in a variety of ways.\"\nmsgstr \"ただし、Pythonのmultiprocessingモジュールをさまざまな方法で使用するオプションがあります。\"\n\n#: ../../recipes-multiprocessing.rst:23 83777a97e9db4e779e16756b9eb3ee39\nmsgid \"\"\n\"If you are looking to speed up page-oriented processing for a large \"\n\"document, use this script as a starting point. It should be at least \"\n\"twice as fast as the corresponding sequential processing.\"\nmsgstr \"大きなドキュメントのページ指向処理を高速化することを検討している場合は、このスクリプトを出発点として使用してください。対応する順次処理よりも少なくとも2倍の速さで動作するはずです。\"\n\n#: ../../recipes-multiprocessing.rst:26 ../../recipes-multiprocessing.rst:37\n#: 2098918775344f8e9c7de44ba8423fb1 824c4f30793e4c428daf4a27269debd1\nmsgid \"|toggleStart|\"\nmsgstr \"\"\n\n#: ../../recipes-multiprocessing.rst:31 ../../recipes-multiprocessing.rst:42\n#: dd13074c598d44c4b568775518218436 ea94b563d305488a93bcc8650477d412\nmsgid \"|toggleEnd|\"\nmsgstr \"\"\n\n#: ../../recipes-multiprocessing.rst:34 9ad6e6b758c14434a47e7b271aebc806\nmsgid \"\"\n\"Here is a more complex example involving inter-process communication \"\n\"between a main process (showing a GUI) and a child process doing \"\n\"|PyMuPDF| access to a document.\"\nmsgstr \"以下は、メインプロセス（GUIを表示）とドキュメントへのPyMuPDFアクセスを行う子プロセスとの間のプロセス間通信を含む、より複雑な例です。\"\n\n#: ../../footer.rst:60 fbfd1487311a41a4acc53de3122dc430\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \":title:`MuPDF` has no integrated support \"\n#~ \"for threading - calling itself \"\n#~ \"\\\"thread-agnostic\\\". While there do exist\"\n#~ \" tricky possibilities to still use \"\n#~ \"threading with :title:`MuPDF`, the baseline\"\n#~ \" consequence for |PyMuPDF| is:\"\n#~ msgstr \"\"\n#~ \":title:`MuPDF` はスレッディングに対する統合サポートを持っておらず、「スレッドに対して無関心（thread-\"\n#~ \"agnostic）」と呼ばれています。MuPDFとスレッディングを組み合わせて使用するトリッキーな可能性は存在しますが、PyMuPDFの基本的な影響は次のとおりです：\"\n\n#~ msgid \"**No Python threading support**.\"\n#~ msgstr \"**Pythonスレッディングのサポートはありません。**.\"\n\n#~ msgid \"\"\n#~ \"Using |PyMuPDF| in a :title:`Python` \"\n#~ \"threading environment will lead to \"\n#~ \"blocking effects for the main thread.\"\n#~ msgstr \"|PyMuPDF| を :title:`Python` スレッディング環境で使用すると、メインスレッドでのブロッキング効果が発生します。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-ocr.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 8c06718aa6d94a588549b1b5d04439ff\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 53d78f25612a42cea99758721dc13394\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDFは、PDF（およびその他）ドキュメントのデータ抽出、分析、変換、および操作のための高性能なPythonライブラリです。\"\n\n#: ../../header.rst:-1 bffa3c55f0b648508f7e9ef104450bca\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキストの抽出、PDF画像の抽出、PDF変換、PDFテーブル、PDF分割、PDF作成、Pyodide、PyScript\"\n\n#: ../../recipes-ocr.rst:17 c241da654a734566aa9837f159d775f0\nmsgid \"OCR - Optical Character Recognition\"\nmsgstr \"OCR - 光学文字認識\"\n\n#: ../../recipes-ocr.rst:19 0aa275f26c85470caecaed5eecb9df0b\nmsgid \"\"\n\"|PyMuPDF| has integrated support for OCR (Optical Character Recognition).\"\n\" It is possible to use OCR for both, images (via the :ref:`Pixmap` class)\"\n\" and for document pages.\"\nmsgstr \"\"\n\"|PyMuPDF| にはOCR（光学文字認識）の統合サポートがあります。OCRは、画像（ :ref:`Pixmap` \"\n\"クラスを介して）および文書ページの両方に使用できます。\"\n\n#: ../../recipes-ocr.rst:21 51aed55192864e8e92dfdbae828d1b05\n\nmsgid \"\"\n\"The feature is currently based on Tesseract-OCR which must be installed \"\n\"as a separate application -- see the :ref:`installation_ocr`.\"\nmsgstr \"\"\n\"この機能は現在、 :ref:`installation_ocr` に基づいており、別途アプリケーションとしてインストールする必要があります。インストール手順は、インストールチャプターを参照してください。\"\n\n#: ../../recipes-ocr.rst:24 b1216080a3f54b3c8f76397e1abb6bfb\nmsgid \"How to OCR an Image\"\nmsgstr \"画像のOCR方法\"\n\n#: ../../recipes-ocr.rst:25 3246894b688c4472b993c9cb737b849b\nmsgid \"\"\n\"A supported image must first be converted to a :ref:`Pixmap`. The Pixmap \"\n\"can then be saved to a 1-page PDF. This page will look like the original \"\n\"image with the same width and height. It will contain a layer of text as \"\n\"recognized by Tesseract.\"\nmsgstr \"\"\n\"サポートされている画像はまず :ref:`Pixmap` \"\n\"に変換される必要があります。次に、Pixmapを1ページのPDFに保存できます。このページは、元の画像と同じ幅と高さを持つように見えます。それには、Tesseractによって認識されたテキストのレイヤーが含まれています。\"\n\n#: ../../recipes-ocr.rst:27 d4515bb735c54591a730fae2a142b782\nmsgid \"\"\n\"The PDF can be generated via one of the methods \"\n\":meth:`Pixmap.pdfocr_save` or :meth:`Pixmap.pdfocr_tobytes`, as a file on\"\n\" disk or as a PDF in memory.\"\nmsgstr \"\"\n\"PDFは、次のいずれかの方法、つまり :meth:`Pixmap.pdfocr_save` または \"\n\":meth:`Pixmap.pdfocr_tobytes` を使用して、ディスク上のファイルとして、またはメモリ内のPDFとして生成できます。\"\n\n#: ../../recipes-ocr.rst:29 487a184cd0104d00b896c90725d548eb\nmsgid \"\"\n\"The text can be extracted and searched with the usual text extraction and\"\n\" search methods (:meth:`Page.get_text`, :meth:`Page.search_for`, etc.). \"\n\"Please also note the following important facts and prerequisites:\"\nmsgstr \"\"\n\"通常のテキスト抽出および検索方法（ :meth:`Page.get_text` 、 :meth:`Page.search_for` \"\n\"など）を使用して、テキストを抽出および検索することができます。また、次の重要な事実と前提条件にも注意してください：\"\n\n#: ../../recipes-ocr.rst:31 fea2a323626648cf8e2f358bf60c9790\nmsgid \"\"\n\"When converting the image to a Pixmap, please confirm that the color \"\n\"space is RGB and alpha is `False` (no transparency). Convert the original\"\n\" Pixmap if necessary.\"\nmsgstr \"\"\n\"画像をPixmapに変換する際に、カラースペースがRGBであり、alphaが `False` \"\n\"（透明度なし）であることを確認してください。必要に応じて元のPixmapを変換してください。\"\n\n#: ../../recipes-ocr.rst:32 602c256e951449f1a5d1de19052b4e81\nmsgid \"\"\n\"All text is written as \\\"hidden\\\" with Tesseract's own `GlyphLessFont`, a\"\n\" mono-spaced font with metrics comparable to Courier.\"\nmsgstr \"\"\n\"すべてのテキストは、Tesseractの独自の `GlyphLessFont` \"\n\"で「非表示」として書かれています。これは、Courierに類似したメトリクスを持つ等幅フォントです。\"\n\n#: ../../recipes-ocr.rst:33 cec1c1656b124ccb8c05d4e5faabe5fe\nmsgid \"\"\n\"All text has the properties regular and black (i.e. no bold, no italic, \"\n\"no information about the original fonts).\"\nmsgstr \"すべてのテキストは、regularとblackのプロパティを持ちます（太字や斜体はなく、元のフォントに関する情報はありません）。\"\n\n#: ../../recipes-ocr.rst:34 40decd5ed0f641c5a1a1df6f0e46b543\nmsgid \"\"\n\"Tesseract does not recognize vector graphics (i.e. no drawings / line-\"\n\"art).\"\nmsgstr \"Tesseractはベクトルグラフィックスを認識しません（つまり、図面や線画はありません）。\"\n\n#: ../../recipes-ocr.rst:36 92a869d875f440a1823e69cb418dd13c\nmsgid \"This approach is also recommended to OCR a complete scanned PDF:\"\nmsgstr \"スキャンされた完全なPDFをOCRするためにも、この手法が推奨されています：\"\n\n#: ../../recipes-ocr.rst:38 66094238af8143488b9393b6174ad73b\nmsgid \"Render each page to a :ref:`Pixmap` with desired resolution\"\nmsgstr \"各ページを所望の解像度で :ref:`Pixmap` にレンダリングします\"\n\n#: ../../recipes-ocr.rst:39 117254e7b2ba43c181367c88db16205e\nmsgid \"Append the resulting 1-page PDF to the output PDF\"\nmsgstr \"得られた1ページのPDFを出力PDFに追加します\"\n\n#: ../../recipes-ocr.rst:42 d7dece4adeb4437b99e1820d71befa7c\nmsgid \"How to OCR a Document Page\"\nmsgstr \"ドキュメントページのOCR方法\"\n\n#: ../../recipes-ocr.rst:43 7c3e4697da8f4603b29acd1ad05093d5\nmsgid \"\"\n\"Any supported document page can be OCR-ed -- either the complete page or \"\n\"only the image areas on it.\"\nmsgstr \"サポートされているどのドキュメントページでもOCR処理が可能です。ページ全体、またはその上の画像領域のみを対象にすることができます。\"\n\n#: ../../recipes-ocr.rst:45 ba6c9f5cda8043bf858b00e93aa23ded\nmsgid \"\"\n\"Because optical character recognition is about one thousand times slower \"\n\"than standard text extraction, we make sure to do OCR only once per page \"\n\"and store the result in a :ref:`TextPage`. Using this TextPage for all \"\n\"subsequent extractions and text searches will then happen with \"\n\"|PyMuPDF|'s usual top speed.\"\nmsgstr \"\"\n\"光学文字認識は通常のテキスト抽出よりも約1000倍遅いため、1ページにつき1回だけOCR処理を行い、その結果をTextPageに保存します。この \"\n\":ref:`TextPage` をすべての後続の抽出とテキスト検索に使用することで、PyMuPDFの通常の高速性で処理が行われます。\"\n\n#: ../../recipes-ocr.rst:47 30ced681346a45b69d752411d4546ef8\nmsgid \"To OCR a document page, follow this approach:\"\nmsgstr \"ドキュメントページをOCRするには、この手順に従ってください：\"\n\n#: ../../recipes-ocr.rst:49 d100d50f78564e60a3c001137881dbe0\nmsgid \"\"\n\"Determine whether OCR is needed / beneficial at all. A number of criteria\"\n\" can be used for this decision, like:\"\nmsgstr \"まず、OCRが全く必要であるか、または有益かどうかを判断します。この決定には、次のような基準を使用できます：\"\n\n#: ../../recipes-ocr.rst:51 d822f6b5f27e4ec8985dabafd5355ded\nmsgid \"page is completely covered by an image\"\nmsgstr \"ページが画像で完全にカバーされている\"\n\n#: ../../recipes-ocr.rst:52 e2b83dfda8654688ace9b92549d12d49\nmsgid \"no text exists on the page\"\nmsgstr \"ページにテキストが存在しない\"\n\n#: ../../recipes-ocr.rst:53 92db54fd9afa4d38a9032f18d836b8cf\nmsgid \"thousands of small vector graphics (indicating *simulated* text)\"\nmsgstr \"数千の小さなベクトルグラフィックス（ *模擬* テキストを示す）\"\n\n#: ../../recipes-ocr.rst:55 83ba5b35db48464f8945a3dabc2e53f0\nmsgid \"\"\n\"OCR the page and store result in a :ref:`TextPage` object using an \"\n\"instruction like `tp = page.get_textpage_ocr(...)`.\"\nmsgstr \"\"\n\"ページをOCR処理し、結果を :ref:`TextPage` オブジェクトに保存します。この操作は、 `tp = \"\n\"page.get_textpage_ocr(...)`  のような命令を使用して行います。\"\n\n#: ../../recipes-ocr.rst:57 58b836a92fe443749da93c2ff3c9a23e\nmsgid \"\"\n\"Refer to the produced :ref:`TextPage` in all subsequent text extractions \"\n\"and searches via the `textpage=tp` parameter.\"\nmsgstr \"\"\n\"以降のすべてのテキスト抽出と検索では、 `textpage=tp`  パラメータを使用して生成された :ref:`TextPage` \"\n\"を参照してください。\"\n\n#: ../../footer.rst:60 3baf39a2c3104ca786b8b27e9c52e1a8\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは、|version| までのすべてのバージョンをカバーしています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-optional-content.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b9adf564010b470a971c6291f3680a9f\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 4f641f2c45c0425a8a232bd594ce5a8e\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 9aa457bbf5a14960b09296e9b2e285cc\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-optional-content.rst:7 f386f73d902d4f638a7820107f09b953\nmsgid \"Optional Content Support\"\nmsgstr \"オプションコンテンツのサポート\"\n\n#: ../../recipes-optional-content.rst:9 fcfec01c6f83417597feed152e9cf82e\nmsgid \"\"\n\"This document explains PyMuPDF's support of the PDF concept **\\\"Optional \"\n\"Content\\\"**.\"\nmsgstr \"この文書では、PyMuPDFにおけるPDFコンセプト **「オプションコンテンツ」** のサポートについて説明します。\"\n\n#: ../../recipes-optional-content.rst:12 3f7db4b17b0c4708ba190ca50f3cf65f\nmsgid \"Introduction: The Optional Content Concept\"\nmsgstr \"はじめに：オプションコンテンツのコンセプト\"\n\n#: ../../recipes-optional-content.rst:13 1a20a0429dbd4d22b3e438897b87f6ec\nmsgid \"\"\n\"*Optional Content* in PDF is a way to show or hide parts of a document \"\n\"based on certain conditions: Parameters that can be set to ON or to OFF \"\n\"when using a supporting PDF consumer (viewer), or programmatically.\"\nmsgstr \"PDFのオプションコンテンツは、特定の条件に基づいてドキュメントの一部を表示または非表示にする方法です。これは、サポートするPDFコンシューマ（ビューア）を使用する際にONまたはOFFに設定できるパラメータ、またはプログラムを使用して行います。\"\n\n#: ../../recipes-optional-content.rst:15 aaecb435f0b74040bb7788f47b75ef27\nmsgid \"\"\n\"This capability is useful in items such as CAD drawings, layered artwork,\"\n\" maps, and multi-language documents. Typical uses include showing or \"\n\"hiding details of complex vector graphics like geographical maps, \"\n\"technical devices, architectural designs and similar, including \"\n\"automatically switching between different zooming levels. Other use cases\"\n\" may be to automatically show different detail levels when displaying a \"\n\"document on screen as opposed to printing it.\"\nmsgstr \"この機能は、CAD図面、レイヤー化されたアートワーク、地図、多言語ドキュメントなどのアイテムで有用です。一般的な用途には、地理的な地図、技術デバイス、建築設計などの複雑なベクトルグラフィックの詳細の表示または非表示、異なるズームレベル間の自動切り替えなどが含まれます。他の用途としては、画面上でドキュメントを表示する際と印刷する際で自動的に異なる詳細レベルを表示することが考えられます。\"\n\n#: ../../recipes-optional-content.rst:17 f07e3ad64d7846e98be13b841e104284\nmsgid \"\"\n\"Special PDF objects, so-called **Optional Content Groups** (OCGs) are \"\n\"used to define these different *layers* of content.\"\nmsgstr \"特別なPDFオブジェクトである「オプションコンテンツグループ（OCG）」を使用して、これらの異なるコンテンツのレイヤーを定義します。\"\n\n#: ../../recipes-optional-content.rst:19 8e40a4dd32264311b329d5ef6d1b3feb\nmsgid \"\"\n\"Assigning an OCG to a \\\"normal\\\" PDF object (like a text or an image) \"\n\"causes that object to be visible or hidden, depending on the current \"\n\"state of the assigned OCG.\"\nmsgstr \"「通常の」PDFオブジェクト（テキストや画像など）にOCGを割り当てると、そのオブジェクトは割り当てられたOCGの現在の状態に応じて表示または非表示になります。\"\n\n#: ../../recipes-optional-content.rst:21 55f0e10ade9d4f99abf06a67d6897563\nmsgid \"\"\n\"To ease definition of the overall configuration of a PDF's Optional \"\n\"Content, OCGs can be organized in higher level groupings, called **OC \"\n\"Configurations**. Each configuration being a collection of OCGs, together\"\n\" with each OCG's desired initial visibility state. Selecting one of these\"\n\" configurations (via the PDF viewer or programmatically) causes a \"\n\"corresponding visibility change of all affected PDF objects throughout \"\n\"the document.\"\nmsgstr \"PDFのオプションコンテンツの全体的な構成を簡単に定義するために、OCGは高レベルのグループ化である「OC構成」に組織化できます。各構成は、OCGの望ましい初期表示状態とともに、OCGのコレクションです。これらの構成のいずれかを選択する（PDFビューアまたはプログラムを介して）と、ドキュメント全体で影響を受けるすべてのPDFオブジェクトの表示状態が対応するように変更されます。\"\n\n#: ../../recipes-optional-content.rst:23 335985a556c34d438df38487d6cae48b\nmsgid \"Except for the default one, OC Configurations are optional.\"\nmsgstr \"デフォルト以外のOC構成はオプションです。\"\n\n#: ../../recipes-optional-content.rst:25 fccc4cf720904ea79e6efd0b6034ca87\nmsgid \"\"\n\"For more explanations and additional background please refer to PDF \"\n\"specification manuals.\"\nmsgstr \"詳細な説明や追加の背景情報については、PDF仕様マニュアルを参照してください。\"\n\n#: ../../recipes-optional-content.rst:28 c00fd4817a4b47efbf6a64bfa9134f7e\nmsgid \"PyMuPDF Support for PDF Optional Content\"\nmsgstr \"PDFオプショナルコンテンツのPyMuPDFサポート\"\n\n#: ../../recipes-optional-content.rst:29 58da3cf082224fbab5a10febc9e9918c\nmsgid \"\"\n\"PyMuPDF offers full support for viewing, defining, changing and deleting \"\n\"Option Content Groups, Configurations, maintaining the assignment of OCGs\"\n\" to PDF objects and programmatically switching between OC Configurations \"\n\"and the visibility states of each single OCG.\"\nmsgstr \"PyMuPDFは、オプショナルコンテンツグループや構成の表示、定義、変更、削除、OCGのPDFオブジェクトへの割り当ての維持、OC構成間のプログラムによる切り替えや各単一OCGの可視性状態のサポートを完全に提供します。\"\n\n#: ../../recipes-optional-content.rst:32 150d36f9de0441a599f6371982441f3d\nmsgid \"How to Add Optional Content\"\nmsgstr \"オプショナルコンテンツの追加方法\"\n\n#: ../../recipes-optional-content.rst:33 73887253f5d24ae7ba64f723a91eaf07\nmsgid \"\"\n\"This is as simple as adding an Optional Content Group, OCG, to a PDF: \"\n\":meth:`Document.add_ocg`.\"\nmsgstr \"これは、PDFにオプショナルコンテンツグループ（OCG）を追加するだけの簡単な手順です：:meth:`Document.add_ocg`。\"\n\n#: ../../recipes-optional-content.rst:35 bc0c989ada934a9a9e91392eed44e3c6\nmsgid \"\"\n\"If previously the PDF had no OC support at all, the required setup (like \"\n\"defining the default OC Configuration) will be done at this point \"\n\"automatically.\"\nmsgstr \"以前にPDFがまったくOCサポートを持っていなかった場合、必要なセットアップ（デフォルトのOC構成の定義など）は自動的に行われます。\"\n\n#: ../../recipes-optional-content.rst:37 cdfece8bcb5842e8a95237834b218484\nmsgid \"\"\n\"The method returns an :data:`xref` of the created OCG. Use this xref to \"\n\"associate (mark) any PDF object with it, that you want to make dependent \"\n\"on this OCG's state. For example, you can insert an image on a page and \"\n\"refer to the xref like this::\"\nmsgstr \"\"\n\"このメソッドは、作成されたOCGの :data:`xref` \"\n\"を返します。このxrefを使用して、このOCGの状態に依存するようにする任意のPDFオブジェクトを関連付け（マーク）します。例えば、ページに画像を挿入し、次のようにxrefを参照できます::\"\n\n#: ../../recipes-optional-content.rst:41 6ffb9b4bd14d4579967827abb6fab656\nmsgid \"\"\n\"If you want to put an **existing** image under the control of an OCG, you\"\n\" must first find out the image's xref number (called `img_xref` here) and\"\n\" then do `doc.set_oc(img_xref, xref)`. After this, the image will be \"\n\"(in-) visible everywhere throughout the document if the OCG's state is \"\n\"\\\"ON\\\", respectively \\\"OFF\\\". You can also assign a different OCG with \"\n\"this method.\"\nmsgstr \"\"\n\"既存の画像をOCGの制御下に配置したい場合、まず画像のxref番号（ここでは `img_xref` と呼びます）を調べ、その後 \"\n\"`doc.set_oc(img_xref, xref)` \"\n\"を行う必要があります。これにより、OCGの状態が「ON」または「OFF」の場合、画像はドキュメント全体で（非）表示になります。また、このメソッドで異なるOCGを割り当てることもできます。\"\n\n#: ../../recipes-optional-content.rst:43 57ddbd4662c64c7da80144e82353dd65\nmsgid \"To **remove** an OCG from an image, do `doc.set_oc(img_xref, 0)`.\"\nmsgstr \"画像からOCGを削除するには、 `doc.set_oc(img_xref, 0)` を行います。\"\n\n#: ../../recipes-optional-content.rst:45 7cf89450ea9246beaa5cc79c376ec93c\nmsgid \"\"\n\"One single OCG can be assigned to multiple PDF objects to control their \"\n\"visibility.\"\nmsgstr \"1つのOCGは複数のPDFオブジェクトに割り当てて、それらの可視性を制御することができます。\"\n\n#: ../../recipes-optional-content.rst:48 7410b55143ef4843a28d68ebad34fd9a\nmsgid \"How to Define Complex Optional Content Conditions\"\nmsgstr \"複雑なオプショナルコンテンツ条件の定義方法\"\n\n#: ../../recipes-optional-content.rst:50 896d39eb29204989ade197882ff6a5ce\nmsgid \"\"\n\"Sophisticated logical conditions can be established to address complex \"\n\"visibility needs.\"\nmsgstr \"複雑な可視性のニーズに対応するために、洗練された論理条件を設定することができます。\"\n\n#: ../../recipes-optional-content.rst:52 a5c986cc1555410ebbc392e3476e93fe\nmsgid \"\"\n\"For example, you might want to create a multi-language document, so the \"\n\"user may switch between languages as required.\"\nmsgstr \"例えば、ユーザーが必要に応じて言語を切り替えることができるような多言語ドキュメントを作成したいかもしれません。\"\n\n#: ../../recipes-optional-content.rst:54 48cadb3f29334ff5aa265acd08dfdc06\nmsgid \"Please have a look at `this Jupyter Notebook`_ and execute it as desired.\"\nmsgstr \"\"\n\"`この Jupyter Notebook <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/jupyter-notebooks/optional-content.ipynb>`_  \"\n\"をご覧いただき、必要に応じて実行してみてください。\"\n\n#: ../../recipes-optional-content.rst:56 49114e4ceda7440399518471d7dc8eb7\nmsgid \"\"\n\"Certainly, your requirements may even be more complex and involve \"\n\"multiple OCGs with ON/OFF states that are connected by some kind of \"\n\"logical relationship -- but it should give you an impression of what is \"\n\"possible and how to plan your next steps.\"\nmsgstr \"もちろん、あなたの要件はさらに複雑で、論理的な関係で接続された複数のON/OFF状態を持つ複数のOCGが関与する可能性がありますが、これは可能なことと次のステップを計画する方法を示すものとなるでしょう。\"\n\n#: ../../footer.rst:60 067fc234c31f4747987f53713303219a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-stories.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 c1cb378bf8d4476fb2cf4501913fbf5e\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 3c891d0a0fb04d97936ca58bbdece2de\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 f644d1bc2e234382901d316b4c0cb553\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-stories.rst:18 c45a9555e4e144b9af3b42d2801ac42d\nmsgid \"Stories\"\nmsgstr \"ストーリーズ\"\n\n#: ../../recipes-stories.rst:20 61fc6f658db84ae4ac5c035a17aaebab\nmsgid \"\"\n\"This document showcases some typical use cases for \"\n\":ref:`Stories<WorkingWithStories>`.\"\nmsgstr \"このドキュメントは、 :ref:`ストーリーズ<WorkingWithStories>` の典型的な使用例を示しています。\"\n\n#: ../../recipes-stories.rst:22 8153b8f5ad474b97857309ad103d02ba\nmsgid \"\"\n\"As mentioned in the :ref:`tutorial<WorkingWithStories>`, stories may be \"\n\"created using up to three input sources: HTML, CSS and Archives -- all of\"\n\" which are optional and which, respectively, can be provided \"\n\"programmatically.\"\nmsgstr \"\"\n\":ref:`チュートリアル<WorkingWithStories>` \"\n\"で説明されているように、ストーリーズは最大3つの入力ソース（HTML、CSS、アーカイブ）を使用して作成できます。これらのソースはすべてオプションであり、それぞれプログラムで提供することができます。\"\n\n#: ../../recipes-stories.rst:24 d57ad4f561994730aebf4f597f37bad9\nmsgid \"The following examples will showcase combinations for using these inputs.\"\nmsgstr \"以下の例では、これらの入力を使用した組み合わせを示します。\"\n\n#: ../../recipes-stories.rst:28 ac8b802e808e4084b58d55ce03509ad8\nmsgid \"\"\n\"Many of these recipe's source code are included as examples in the `docs`\"\n\" folder.\"\nmsgstr \"これらのレシピのソースコードの多くは、ドキュメントフォルダ内の例として含まれています。\"\n\n#: ../../recipes-stories.rst:34 f07dc61a03bf4989b1e6604b220aef91\nmsgid \"How to Add a Line of Text with Some Formatting\"\nmsgstr \"テキストの行をいくつかの書式で追加する方法\"\n\n#: ../../recipes-stories.rst:36 89f52f47ec32483480e0cf60bd8494fb\nmsgid \"Here is the inevitable \\\"Hello World\\\" example. We will show two variants:\"\nmsgstr \"以下は、避けられない「Hello World」の例です。2つのバリアントを示します：\"\n\n#: ../../recipes-stories.rst:38 0f4aae8b064d445d907c6ca0008c498d\nmsgid \"Create using existing HTML source [#f1]_, that may come from anywhere.\"\nmsgstr \"どこからでも取得できる既存のHTMLソース [#f1]_ を使用して作成します。\"\n\n#: ../../recipes-stories.rst:39 5cb05c255e5b48348d3ab83f3bd57f28\nmsgid \"Create using the Python API.\"\nmsgstr \"Python APIを使用して作成します。\"\n\n#: ../../recipes-stories.rst:43 e8ff5379e66c49ce8776461b904793ef\nmsgid \"\"\n\"Variant using an existing HTML source [#f1]_ -- which in this case is \"\n\"defined as a constant in the script::\"\nmsgstr \"既存のHTMLソース [#f1]_ を使用したバリアント – この場合、スクリプト内で定数として定義されています::\"\n\n#: ../../recipes-stories.rst:69 fa5eb25963534e29b44ef593d2a08afd\nmsgid \"\"\n\"The above effect (sans-serif and blue text) could have been achieved by \"\n\"using a separate CSS source like so::\"\nmsgstr \"上記の効果（サンセリフ体および青いテキスト）は、次のように別のCSSソースを使用することで達成できます::\"\n\n#: ../../recipes-stories.rst:90 f582657322b343a4a158ef19912473f1\nmsgid \"The Python API variant -- everything is created programmatically::\"\nmsgstr \"Python APIのバリアント - すべてがプログラムで作成されます::\"\n\n#: ../../recipes-stories.rst:114 a47a4f8569b14eb893a5ce9aeb3db643\nmsgid \"Both variants will produce the same output PDF.\"\nmsgstr \"どちらのバリアントも同じ出力のPDFを生成します。\"\n\n#: ../../recipes-stories.rst:122 2748abc7a81f48868dc86feadeed7cdc\nmsgid \"How to use Images\"\nmsgstr \"画像の使用方法\"\n\n#: ../../recipes-stories.rst:124 ecce5ae8803442768c9c0c9dcbaa0b91\nmsgid \"\"\n\"Images can be referenced in the provided HTML source, or the reference to\"\n\" a desired image can also be stored via the Python API. In any case, this\"\n\" requires using an :ref:`Archive`, which refers to the place where the \"\n\"image can be found.\"\nmsgstr \"\"\n\"画像は提供されたHTMLソース内で参照することができます。また、Python \"\n\"APIを介して必要な画像への参照も保存することができます。どちらの場合も、画像が見つかる場所を指す :ref:`Archive` \"\n\"を使用する必要があります。\"\n\n#: ../../recipes-stories.rst:126 db9731d3f4a84908b18bd2c0bac15515\nmsgid \"\"\n\"Images with the binary content embedded in the HTML source are **not \"\n\"supported** by stories.\"\nmsgstr \"HTMLソースにバイナリコンテンツが埋め込まれた画像は、ストーリーズではサポートされていません。\"\n\n#: ../../recipes-stories.rst:128 621a5032b00c42b780871bc2b317708f\nmsgid \"\"\n\"We extend our \\\"Hello World\\\" example from above and display an image of \"\n\"our planet right after the text. Assuming the image has the name \"\n\"\\\"world.jpg\\\" and is present in the script's folder, then this is the \"\n\"modified version of the above Python API variant::\"\nmsgstr \"\"\n\"前述の「Hello \"\n\"World」の例を拡張し、テキストの直後に地球の画像を表示します。画像の名前が「world.jpg」であり、スクリプトのフォルダに存在すると仮定すると、次に示すようにPython\"\n\" APIバリアントを修正したものとなります::\"\n\n#: ../../recipes-stories.rst:168 0bd066e55e8d42828fb2a8874920b48f\nmsgid \"How to Read External HTML and CSS for a Story\"\nmsgstr \"外部のHTMLとCSSをストーリーに読み込む方法\"\n\n#: ../../recipes-stories.rst:170 1dd80d2a8aa54fb7b10356e199ee9a9b\nmsgid \"These cases are fairly straightforward.\"\nmsgstr \"これらのケースはかなり直接的です。\"\n\n#: ../../recipes-stories.rst:172 9e74fe2a5497459c880103c0b8c72e49\nmsgid \"\"\n\"As a general recommendation, HTML and CSS sources should be **read as \"\n\"binary files** and decoded before using them in a story. The Python \"\n\"`pathlib.Path` provides convenient ways to do this::\"\nmsgstr \"\"\n\"一般的な推奨事項として、HTMLとCSSのソースはバイナリファイルとして読み込まれ、ストーリーで使用する前にデコードされるべきです。Pythonの\"\n\" `pathlib.Path` は、これを便利に行うための方法を提供しています。::\"\n\n#: ../../recipes-stories.rst:193 b15949b2628f4e559db2166cab03e684\nmsgid \"How to Output Database Content with Story Templates\"\nmsgstr \"データベースの内容をストーリーテンプレートで出力する方法\"\n\n#: ../../recipes-stories.rst:195 ee70b3e26cb24cd281fd481f24b0f1f0\nmsgid \"\"\n\"This script demonstrates how to report SQL database content using an \"\n\"**HTML template**.\"\nmsgstr \"このスクリプトは**HTMLテンプレート**を使用してSQLデータベースの内容を報告する方法を示しています。\"\n\n#: ../../recipes-stories.rst:199 b38843035c074c12875aa488d121d745\nmsgid \"The example SQL database contains two tables:\"\nmsgstr \"この例のSQLデータベースには2つのテーブルが含まれています：\"\n\n#: ../../recipes-stories.rst:201 2a5e075abb974afb8fabb4bc379b46cc\nmsgid \"\"\n\"Table \\\"films\\\" contains one row per film with the fields **\\\"title\\\"**, \"\n\"**\\\"director\\\"** and (release) **\\\"year\\\"**.\"\nmsgstr \"テーブル「films」には、フィールド「title」、「director」、および（公開）「year」を持つ1つの映画ごとの行が含まれています。\"\n\n#: ../../recipes-stories.rst:202 3ca9978ff3384e669316aec51f82f4e3\nmsgid \"\"\n\"Table \\\"actors\\\" contains one row per actor and film title (fields \"\n\"(actor) **\\\"name\\\"** and (film) **\\\"title\\\"**).\"\nmsgstr \"テーブル「actors」には、1つの行に1人の俳優と映画のタイトルが含まれています（フィールド（actor）「name」と（film）「title」）。\"\n\n#: ../../recipes-stories.rst:204 bcb64849fff74c60903737949f68225d\nmsgid \"\"\n\"The story DOM consists of a template for one film, which reports film \"\n\"data together with a list of casted actors.\"\nmsgstr \"ストーリーDOMは、映画の1つのテンプレートから成り、映画のデータと出演俳優のリストを報告します。\"\n\n#: ../../recipes-stories.rst:206 ../../recipes-stories.rst:231\n#: ../../recipes-stories.rst:257 ../../recipes-stories.rst:309\n#: ../../recipes-stories.rst:343 ../../recipes-stories.rst:377\n#: ../../recipes-stories.rst:398 ../../recipes-stories.rst:433\n#: ../../recipes-stories.rst:467 ../../recipes-stories.rst:497\n#: ../../recipes-stories.rst:531 2b3dd500f0434c64b97cf8b801ea18e2\n#: 64fc1d7aed8a43cd92ff2d020bf13ec8 7eb60a8b9a42446594e53b2bf3c68871\n#: a16e34a298a6425880ddf4fb4371e66e a22398fc103f4437ac647a31dd0d5fbf\n#: b70a18528557465e8f61dc1122eca0ed c000544d4c274bbb9db7672b53850bc0\n#: d1607e50f7864da5afac7f3a5c6cfb74 d7f83da6ed26402bbc3b8fe0bc8c3e6c\n#: daf59f85090b4c6dac31f2a2498b1d40 f3388231edfd4b7a869bc003cbfe749a\nmsgid \"**Files:**\"\nmsgstr \"**ファイル：**\"\n\n#: ../../recipes-stories.rst:208 54585f66fd3d47c8b7fa6a18c5e6d437\nmsgid \"`docs/samples/filmfestival-sql.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:209 a25f79113d4845688acf7e96fc25d405\nmsgid \"`docs/samples/filmfestival-sql.db`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:212 ../../recipes-stories.rst:235\n#: ../../recipes-stories.rst:263 ../../recipes-stories.rst:316\n#: ../../recipes-stories.rst:347 ../../recipes-stories.rst:360\n#: ../../recipes-stories.rst:381 ../../recipes-stories.rst:402\n#: ../../recipes-stories.rst:437 ../../recipes-stories.rst:471\n#: ../../recipes-stories.rst:501 ../../recipes-stories.rst:535\n#: 0db5e50af58744b9a3fb1c616e67a684 28fc170e69fd4a44b4fa959ea9b3e32e\n#: 33679f3b5997465888776dda77506957 36f0be1fd15b4a8c84694c64491bd2c7\n#: 37527330942949a0bd3be5dba9e785c4 5485b7bba46c4eda83ec8b43ca3d2ecf\n#: 7e7b5ee4ed9b4cf090a10dcda115473d addec11282d24d079e19186339ab1b65\n#: c2ad827c824c44718c01801f503eb406 d8b52254ec3547f19f86eaca688e79bd\n#: de7617178b054648a843a36e24659eab fd40019209fb42f487a8b1836bcd3638\nmsgid \"|toggleStart|\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:216 ../../recipes-stories.rst:239\n#: ../../recipes-stories.rst:267 ../../recipes-stories.rst:320\n#: ../../recipes-stories.rst:351 ../../recipes-stories.rst:364\n#: ../../recipes-stories.rst:385 ../../recipes-stories.rst:406\n#: ../../recipes-stories.rst:441 ../../recipes-stories.rst:475\n#: ../../recipes-stories.rst:505 ../../recipes-stories.rst:539\n#: 1f64c481b7224504a02af891e0682cb3 266ea01fca494309b1cd1c30895d31bc\n#: 27da42d77a6b435bb286157e8930f759 52efc716cc3147a6a6486dfc0795eb8e\n#: 532a65455e3d4cc5acae0770c9f6847d 5e487c5fb8fa43078450b2f3e6e90793\n#: 78f9acaef114448fb9edcb0e9b8ad611 918069a403554628bffb1412599598c8\n#: 92734f09b2ab4e3c80847c556c5ede0f 9d3b034ebb21493683dc0e7e2bb7f19b\n#: a4115389a45c49f79c5235d1cab2feba f46a83317e2744c6979346649f812fde\nmsgid \"|toggleEnd|\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:225 50ac8bd58ac94ca9bad75235813275b8\nmsgid \"How to Integrate with Existing PDFs\"\nmsgstr \"既存のPDFと統合する方法\"\n\n#: ../../recipes-stories.rst:227 30768c0ff00d46c8acc3718442620f18\nmsgid \"\"\n\"Because a :ref:`DocumentWriter` can only write to a new file, stories \"\n\"cannot be placed on existing pages. This script demonstrates a \"\n\"circumvention of this restriction.\"\nmsgstr \"\"\n\":ref:`DocumentWriter` \"\n\"は新しいファイルにのみ書き込むことができるため、ストーリーは既存のページに配置することはできません。このスクリプトは、この制限を回避する方法を示しています。\"\n\n#: ../../recipes-stories.rst:229 c4b4b44242604021bc2168807cae604d\nmsgid \"\"\n\"The basic idea is letting :ref:`DocumentWriter` output to a PDF in \"\n\"memory. Once the story has finished, we re-open this memory PDF and put \"\n\"its pages to desired locations on **existing** pages via method \"\n\":meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\"基本的な考え方は、 :ref:`DocumentWriter`  \"\n\"がメモリ内のPDFに出力することです。ストーリーが完了したら、このメモリPDFを再度開き、メソッド \"\n\":meth:`Page.show_pdf_page` を使用してそのページを既存のページに必要な位置に配置します。\"\n\n#: ../../recipes-stories.rst:233 0ee71e800fb14b2ea803f1438f5379e4\nmsgid \"`docs/samples/showpdf-page.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:248 2464de777541472497c10c81706a8467\nmsgid \"\"\n\"How to Make Multi-Columned Layouts and Access Fonts from Package \"\n\"`pymupdf-fonts`_\"\nmsgstr \"多段組のレイアウトを作成し、パッケージ `pymupdf-fonts`_ からフォントにアクセスする方法\"\n\n#: ../../recipes-stories.rst:250 8dfd6dd8ca784d958d2a901ee4009a15\nmsgid \"\"\n\"This script outputs an article (taken from Wikipedia) that contains text \"\n\"and multiple images and uses a 2-column page layout.\"\nmsgstr \"このスクリプトは、テキストと複数の画像を含む記事（Wikipediaから取得）を出力し、2列のページレイアウトを使用します。\"\n\n#: ../../recipes-stories.rst:252 96f19cd490e0468983187394fd4f755d\nmsgid \"\"\n\"In addition, two \\\"Ubuntu\\\" font families from package `pymupdf-fonts`_ \"\n\"are used instead of defaulting to Base-14 fonts.\"\nmsgstr \"\"\n\"さらに、デフォルトではBase-14フォントにデフォルトでなく、パッケージpymupdf-\"\n\"fontsから2つの「Ubuntu」フォントファミリが使用されています。\"\n\n#: ../../recipes-stories.rst:254 d104d23aa09e4c20a51bd1765f6ec72d\nmsgid \"\"\n\"Yet another feature used here is that all data -- the images and the \"\n\"article HTML -- are jointly stored in a ZIP file.\"\nmsgstr \"ここで使用される別の機能は、すべてのデータ – 画像と記事のHTML – が共にZIPファイルに格納されていることです。\"\n\n#: ../../recipes-stories.rst:259 aabca9ed8f1545efa8e6c35a8fa570ed\nmsgid \"`docs/samples/quickfox.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:260 ../../recipes-stories.rst:313\n#: 56254f7b3a3f48038ba0fec7307956e4 d0d48278d419432ea98f56ca84a85f66\nmsgid \"`docs/samples/quickfox.zip`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:276 c5b48fe9ccc34243a9cafef7d92058ac\nmsgid \"How to Make a Layout which Wraps Around a Predefined \\\"no go area\\\" Layout\"\nmsgstr \"あらかじめ定義された「禁止エリア」レイアウトに囲まれたレイアウトの作成方法\"\n\n#: ../../recipes-stories.rst:279 9aeb4c6c24cf45918fc271c1bb22d655\nmsgid \"\"\n\"This is a demo script using PyMuPDF's Story class to output text as a PDF\"\n\" with a two-column page layout.\"\nmsgstr \"これは、PyMuPDFのStoryクラスを使用してテキストを2列のページレイアウトでPDFとして出力するデモスクリプトです。\"\n\n#: ../../recipes-stories.rst:282 9a9deed471b545109ffbf69ae0a63c13\nmsgid \"The script demonstrates the following features:\"\nmsgstr \"このスクリプトは、以下の機能を示しています：\"\n\n#: ../../recipes-stories.rst:284 8325013303e24647a592be6d38854cfa\nmsgid \"Layout text around images of an existing (\\\"target\\\") PDF.\"\nmsgstr \"既存の（「ターゲット」）PDFの画像の周りにテキストをレイアウトします。\"\n\n#: ../../recipes-stories.rst:285 12cd3a4970c942d28bc420575afefa73\nmsgid \"\"\n\"Based on a few global parameters, areas on each page are identified, that\"\n\" can be used to receive text layouted by a Story.\"\nmsgstr \"各ページの特定の領域が、Storyによってレイアウトされたテキストを受け入れるために使用できるように、いくつかのグローバルパラメータに基づいて識別されます。\"\n\n#: ../../recipes-stories.rst:287 5fb1ec0a189e438fbbb5d287d889152d\nmsgid \"\"\n\"These global parameters are not stored anywhere in the target PDF and \"\n\"must therefore be provided in some way:\"\nmsgstr \"これらのグローバルパラメータは、ターゲットPDF内のどこにも保存されず、したがってどのような方法で提供される必要があります：\"\n\n#: ../../recipes-stories.rst:290 2939a7b2c8ff40199db1fb38e01d1c41\nmsgid \"The width of the border(s) on each page.\"\nmsgstr \"各ページのボーダーの幅。\"\n\n#: ../../recipes-stories.rst:291 07ff55f6cd4b4ea3ada2d0100b667d23\nmsgid \"\"\n\"The fontsize to use for text. This value determines whether the provided \"\n\"text will fit in the empty spaces of the (fixed) pages of target PDF. It \"\n\"cannot be predicted in any way. The script ends with an exception if \"\n\"target PDF has not enough pages, and prints a warning message if not all \"\n\"pages receive at least some text. In both cases, the FONTSIZE value can \"\n\"be changed (a float value).\"\nmsgstr \"テキストに使用するフォントサイズ。この値は、提供されたテキストがターゲットPDFの（固定された）ページの空白スペースに収まるかどうかを決定します。これはどのように予測することもできません。ターゲットPDFに十分なページがない場合、スクリプトは例外をスローし、すべてのページが少なくとも一部のテキストを受け取らない場合は警告メッセージが表示されます。どちらの場合も、FONTSIZEの値を変更できます（浮動小数点数）。\"\n\n#: ../../recipes-stories.rst:297 7f2693aa52f8413c957e3697cd159a39\nmsgid \"Use of a 2-column page layout for the text.\"\nmsgstr \"テキストのための2列のページレイアウトの使用。\"\n\n#: ../../recipes-stories.rst:298 74329206c6d84722884bd5ba5f248027\nmsgid \"\"\n\"The layout creates a temporary (memory) PDF. Its produced page content \"\n\"(the text) is used to overlay the corresponding target page. If text \"\n\"requires more pages than are available in target PDF, an exception is \"\n\"raised. If not all target pages receive at least some text, a warning is \"\n\"printed.\"\nmsgstr \"レイアウトは一時的な（メモリ）PDFを作成します。その生成されたページのコンテンツ（テキスト）は、対応するターゲットページに重ねて配置されます。テキストがターゲットPDFの利用可能なページよりも多くのページを必要とする場合、例外が発生します。すべてのターゲットページが少なくとも一部のテキストを受け取らない場合、警告が表示されます。\"\n\n#: ../../recipes-stories.rst:302 d18a70eaed5c44b98873dc74a92721a1\nmsgid \"\"\n\"The script reads \\\"image-no-go.pdf\\\" in its own folder. This is the \"\n\"\\\"target\\\" PDF. It contains 2 pages with each 2 images (from the original\"\n\" article), which are positioned at places that create a broad overall \"\n\"test coverage. Otherwise the pages are empty.\"\nmsgstr \"\"\n\"スクリプトは、自分自身のフォルダ内の「image-no-\"\n\"go.pdf」を読み込みます。これが「ターゲット」PDFです。オリジナルの記事から2つの画像（各2ページ）を含み、それらは広範なテストカバレッジを作成する場所に配置されています。それ以外の場合、ページは空です。\"\n\n#: ../../recipes-stories.rst:306 f46ddb852a574bd5a7bac7520a202c10\nmsgid \"\"\n\"The script produces \\\"quickfox-image-no-go.pdf\\\" which contains the \"\n\"original pages and image positions, but with the original article text \"\n\"laid out around them.\"\nmsgstr \"\"\n\"スクリプトは「quickfox-image-no-\"\n\"go.pdf」を生成し、元のページと画像の位置を含みますが、元の記事のテキストがその周りにレイアウトされます。\"\n\n#: ../../recipes-stories.rst:311 7df54784e06541489011541c3865adce\nmsgid \"`docs/samples/quickfox-image-no-go.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:312 06568562593e4d99b28e5de2e3b0939a\nmsgid \"`docs/samples/quickfox-image-no-go.pdf`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:329 71c7aa076de44ec38e26d2fb754afc9b\nmsgid \"How to Output an HTML Table\"\nmsgstr \"HTMLテーブルの出力方法\"\n\n#: ../../recipes-stories.rst:331 3301f44c71164017b224858b8757665b\nmsgid \"Outputting HTML tables is supported as follows:\"\nmsgstr \"HTMLテーブルの出力は次のようにサポートされています：\"\n\n#: ../../recipes-stories.rst:333 41e583af9b0542cdb2079c8ff6906052\nmsgid \"\"\n\"Flat table layouts are supported (\\\"rows x columns\\\"), no support of the \"\n\"\\\"colspan\\\" / \\\"rowspan\\\" attributes.\"\nmsgstr \"フラットなテーブルレイアウト（「行 × 列」）がサポートされており、「colspan」/「rowspan」属性はサポートされていません。\"\n\n#: ../../recipes-stories.rst:334 47d7baea9d4e4285881ba226de5af09d\nmsgid \"\"\n\"Table header tag :htmlTag:`th` supports attribute \\\"scope\\\" with values \"\n\"\\\"row\\\" or \\\"col\\\". Applicable text will be bold by default.\"\nmsgstr \"\"\n\"テーブルヘッダータグ :htmlTag:`th` は、属性 “scope” をサポートし、値として “row” または “col” \"\n\"を持ちます。適用されるテキストはデフォルトで太字になります。\"\n\n#: ../../recipes-stories.rst:335 74d5008eb5a141a3a1cfc8a54b018574\nmsgid \"\"\n\"Column widths are computed automatically based on column content. They \"\n\"cannot be directly set.\"\nmsgstr \"列の幅は、列のコンテンツに基づいて自動的に計算されます。直接設定することはできません。\"\n\n#: ../../recipes-stories.rst:336 eced7f475d8d4d39b1c9a6daa98cb9e3\nmsgid \"\"\n\"Table **cells may contain images** which will be considered in the column\"\n\" width calculation magic.\"\nmsgstr \"テーブルのセルには画像を含めることができ、これは列幅計算の際に考慮されます。\"\n\n#: ../../recipes-stories.rst:337 2d09432449124bd29ad88bb9203b3eb7\nmsgid \"\"\n\"Row heights are computed automatically based on row content - leading to \"\n\"multi-line rows where needed.\"\nmsgstr \"行の高さは、行のコンテンツに基づいて自動的に計算され、必要に応じて複数行の行が生成されます。\"\n\n#: ../../recipes-stories.rst:338 99cd09b56b7a4038b94e8cc59054e98e\nmsgid \"\"\n\"The potentially multiple lines of a table row will always be kept \"\n\"together on one page (respectively \\\"where\\\" rectangle) and not be split.\"\nmsgstr \"テーブルの行の潜在的に複数行は、常に1つのページ（または “where” 矩形）にまとめて表示され、分割されることはありません。\"\n\n#: ../../recipes-stories.rst:339 2b0dd155fb9b46abb1a3a34b5165e5cb\nmsgid \"\"\n\"Table header rows are only **shown on the first page / \\\"where\\\" \"\n\"rectangle.**\"\nmsgstr \"テーブルのヘッダー行は、最初のページ / \\\"where\\\" 矩形のみに表示されます。\"\n\n#: ../../recipes-stories.rst:340 9c971454188c471695037fe19b0b291f\nmsgid \"\"\n\"The \\\"style\\\" attribute is ignored when given directly in HTML table \"\n\"elements. Styling for a table and its elements must happen separately, in\"\n\" CSS source or within the :htmlTag:`style` tag.\"\nmsgstr \"\"\n\"直接HTMLテーブル要素に  \\\"style\\\"   属性が与えられた場合、無視されます。テーブルとその要素のスタイリングは、CSSソース内または\"\n\" :htmlTag:`style`  タグ内で別途行う必要があります。\"\n\n#: ../../recipes-stories.rst:341 b6be54c8961a40fca5e5624606c40804\nmsgid \"\"\n\"Styling for :htmlTag:`tr` elements is not supported and ignored. \"\n\"Therefore, a table-wide grid or alternating row background colors are not\"\n\" supported. One of the following example scripts however shows an easy \"\n\"way to deal with this limitation.\"\nmsgstr \"\"\n\":htmlTag:`tr` \"\n\"要素のスタイリングはサポートされておらず、無視されます。したがって、テーブル全体のグリッドや交互の行の背景色はサポートされていません。ただし、以下の例スクリプトのいずれかは、この制限に対処する簡単な方法を示しています。\"\n\n#: ../../recipes-stories.rst:345 3250a44850a04ea2b556eaa99626d432\nmsgid \"`docs/samples/table01.py` This script reflects basic features.\"\nmsgstr \"`docs/samples/table01.py` このスクリプトは基本的な機能を反映しています。\"\n\n#: ../../recipes-stories.rst:353 338c9d76f79b41df86b53304991fa447\nmsgid \"\"\n\"`docs/samples/national-capitals.py` Advanced script extending table \"\n\"output options using simple additional code:\"\nmsgstr \"\"\n\"`docs/samples/national-capitals.py` \"\n\"シンプルな追加コードを使用してテーブル出力オプションを拡張する高度なスクリプト:\"\n\n#: ../../recipes-stories.rst:355 90d13dbe2506480f9d05c17929eb6886\nmsgid \"Multi-page output simulating **repeating header rows**\"\nmsgstr \"繰り返しヘッダー行をシミュレートするマルチページ出力\"\n\n#: ../../recipes-stories.rst:356 cbf54ca5c2024e268d1186a280b3aa24\nmsgid \"Alternating table row background colors\"\nmsgstr \"交互のテーブル行の背景色\"\n\n#: ../../recipes-stories.rst:357 2f63b307cf484d58a093efeda123e5fd\nmsgid \"Table rows and columns delimited by gridlines\"\nmsgstr \"グリッドラインで区切られたテーブル行と列\"\n\n#: ../../recipes-stories.rst:358 e5f6f8efbb6f4165b34f336502bd9f1c\nmsgid \"Table rows dynamically generated / filled with data from an SQL database\"\nmsgstr \"SQLデータベースからデータを動的に生成/埋めるテーブル行\"\n\n#: ../../recipes-stories.rst:373 fe9ae949732f4a8aa60268158ee88be6\nmsgid \"How to Create a Simple Grid Layout\"\nmsgstr \"シンプルなグリッドレイアウトの作成方法\"\n\n#: ../../recipes-stories.rst:375 715590c3c78d4629ad6c5345990d29e2\nmsgid \"\"\n\"By creating a sequence of :ref:`Story` objects within a grid created via \"\n\"the :ref:`make_table<Functions_make_table>` function a developer can \"\n\"create grid layouts as required.\"\nmsgstr \"\"\n\":ref:`make_table<Functions_make_table>` 関数を使用して作成されたグリッド内で :ref:`Story` \"\n\"オブジェクトのシーケンスを作成することで、開発者は必要なグリッドレイアウトを作成できます。\"\n\n#: ../../recipes-stories.rst:379 dd275a6adf8f4b8ea21b21fe0f4be667\nmsgid \"`docs/samples/simple-grid.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:394 5e3cbf68e72d48f9a4d031caea74efe1\nmsgid \"How to Generate a Table of Contents\"\nmsgstr \"目次の生成方法\"\n\n#: ../../recipes-stories.rst:396 eef825fca149402fa59fd4d03097fbcc\nmsgid \"\"\n\"This script lists the source code of all Python scripts that live in the \"\n\"script's directory.\"\nmsgstr \"このスクリプトは、スクリプトのディレクトリに存在するすべてのPythonスクリプトのソースコードをリスト表示します。\"\n\n#: ../../recipes-stories.rst:400 f90b481f29e84be197d7b43765469464\nmsgid \"`docs/samples/code-printer.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:409 c06dd956b971493bb3b3cbb5ad0a3e22\nmsgid \"It features the following capabilities:\"\nmsgstr \"次の機能が備わっています：\"\n\n#: ../../recipes-stories.rst:411 b4d75405cd1b4d2bb534b59fb384119e\nmsgid \"\"\n\"Automatic generation of a Table of Contents (TOC) on separately numbered \"\n\"pages at the start of the document - using a specialized :ref:`Story`.\"\nmsgstr \"専用の :ref:`Story` を使用して、文書の冒頭に独立したページごとに自動的に目次（TOC）を生成します。\"\n\n#: ../../recipes-stories.rst:413 6337def52daa43f9abdd769a10a39184\nmsgid \"\"\n\"Use of 3 separate :ref:`Story` objects per page: header story, footer \"\n\"story and the story for printing the Python sources.\"\nmsgstr \"\"\n\"ページごとに3つの別個の :ref:`Story` \"\n\"オブジェクトを使用：ヘッダーストーリー、フッターストーリー、Pythonソースの印刷用ストーリー。\"\n\n#: ../../recipes-stories.rst:415 4f7e17024ef64638a584ff82424ee1e1\nmsgid \"\"\n\"The page **footer is automatically changed** to show the name of the \"\n\"current Python file.\"\nmsgstr \"ページフッターは自動的に変更され、現在のPythonファイル名が表示されます。\"\n\n#: ../../recipes-stories.rst:417 13b96aa9ead945c698966dcda2ef5de1\nmsgid \"\"\n\"Use of :meth:`Story.element_positions` to collect the data for the TOC \"\n\"and for the dynamic adjustment of page footers. This is an example of a \"\n\"**bidirectional communication** between the story output process and the \"\n\"script.\"\nmsgstr \"\"\n\":meth:`Story.element_positions`  \"\n\"の使用により、TOCのデータの収集とページフッターの動的調整に使用されます。これは、ストーリー出力プロセスとスクリプト間の双方向コミュニケーションの例です。\"\n\n#: ../../recipes-stories.rst:419 a1b7b48737734821b3d4cee8cb99deb6\nmsgid \"\"\n\"The main PDF with the Python sources is being written to memory by its \"\n\":ref:`DocumentWriter`. Another :ref:`Story` / :ref:`DocumentWriter` pair \"\n\"is then used to create a (memory) PDF for the TOC pages. Finally, both \"\n\"these PDFs are joined and the result stored to disk.\"\nmsgstr \"\"\n\"主なPythonソースをその :ref:`DocumentWriter` によってメモリに書き込みます。その後、もう一つの \"\n\":ref:`Story` / :ref:`DocumentWriter` \"\n\"のペアを使用して（メモリ）PDFをTOCページのために作成します。最後に、これらのPDFは結合されて結果がディスクに保存されます。\"\n\n#: ../../recipes-stories.rst:428 99dd73162add4ea0afbb0634cf53dcf6\nmsgid \"How to Display a List from JSON Data\"\nmsgstr \"JSONデータからリストを表示する方法\"\n\n#: ../../recipes-stories.rst:430 6fdc8240537845b5b007826459e137e2\nmsgid \"\"\n\"This example takes some JSON data input which it uses to populate a \"\n\":ref:`Story`. It also contains some visual text formatting and shows how \"\n\"to add links.\"\nmsgstr \"\"\n\"この例では、JSONデータ入力を使用して :ref:`Story` \"\n\"を生成し、いくつかの視覚的なテキスト書式設定を行い、リンクを追加する方法を示しています。\"\n\n#: ../../recipes-stories.rst:435 af211242fc1e45d4935f0534d472ea83\nmsgid \"`docs/samples/json-example.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:451 d1800a418d944e7bbe3af548c292e262\nmsgid \"Using the Alternative :meth:`Story.write*()` functions\"\nmsgstr \":meth:`Story.write*()` 関数の使用方法\"\n\n#: ../../recipes-stories.rst:453 a6aa8d8c6606441b896c25ed8b547c36\nmsgid \"\"\n\"The :meth:`Story.write*()` functions provide a different way to use the \"\n\":ref:`Story` functionality, removing the need for calling code to \"\n\"implement a loop that calls :meth:`Story.place()` and \"\n\":meth:`Story.draw()` etc, at the expense of having to provide at least a \"\n\"`rectfn()` callback.\"\nmsgstr \"\"\n\":meth:`Story.write*()` 関数は、 :ref:`Story`  \"\n\"機能を異なる方法で使用するための方法を提供します。これにより、呼び出しコードが  :meth:`Story.place()`  や \"\n\":meth:`Story.draw()`  などを呼び出すループを実装する必要がなくなりますが、少なくとも  `rectfn()`  \"\n\"コールバックを提供する必要があります。\"\n\n#: ../../recipes-stories.rst:462 0b9c207cf6c34028bd59a17ba745a06b\nmsgid \"How to do Basic Layout with :meth:`Story.write()`\"\nmsgstr \":meth:`Story.write()` を使用した基本的なレイアウトの方法\"\n\n#: ../../recipes-stories.rst:464 3afb41fae5c04c80bb274a6695783cf8\nmsgid \"\"\n\"This script lays out multiple copies of its own source code, into four \"\n\"rectangles per page.\"\nmsgstr \"このスクリプトは、自身のソースコードの複数のコピーを1ページあたり4つの四角形にレイアウトします。\"\n\n#: ../../recipes-stories.rst:469 eaa7c3914c6e4d10b06fc5e83aef6ef9\nmsgid \"`docs/samples/story-write.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:484 254625a2c4634deb8a6e5fed8ffd181e\nmsgid \"\"\n\"How to do Iterative Layout for a Table of Contents with \"\n\":meth:`Story.write_stabilized()`\"\nmsgstr \":meth:`Story.write_stabilized()` を使用した目次付きの繰り返しレイアウトの方法\"\n\n#: ../../recipes-stories.rst:486 f99a682ccb04406c9c3fb8d6add61ab6\nmsgid \"\"\n\"This script creates html content dynamically, adding a contents section \"\n\"based on :ref:`ElementPosition` items that have non-zero `.heading` \"\n\"values.\"\nmsgstr \"\"\n\"このスクリプトは、要素の位置情報（:ref:`ElementPosition` アイテム）を基にコンテンツを動的に作成し、`.heading`  \"\n\"値がゼロでない要素に基づいて目次セクションを追加します。\"\n\n#: ../../recipes-stories.rst:489 f707d1092f04401f906070fe2e82c373\nmsgid \"\"\n\"The contents section is at the start of the document, so modifications to\"\n\" the contents can change page numbers in the rest of the document, which \"\n\"in turn can cause page numbers in the contents section to be incorrect.\"\nmsgstr \"目次セクションは文書の先頭に配置されているため、目次への変更によって文書の他の部分のページ番号が変更され、それに伴い目次セクションのページ番号が正しくなくなる可能性があります。\"\n\n#: ../../recipes-stories.rst:493 0fee61fd78ed4f9ab50188a4fd67cce7\nmsgid \"\"\n\"So the script uses :meth:`Story.write_stabilized()` to repeatedly lay \"\n\"things out until things are stable.\"\nmsgstr \"したがって、スクリプトは  :meth:`Story.write_stabilized()` を使用して、安定するまで繰り返しレイアウトを行います。\"\n\n#: ../../recipes-stories.rst:499 42fb0df4e27948abb714018fac0417f5\nmsgid \"`docs/samples/story-write-stabilized.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:514 17025d9951f14511b6e562a16ce16843\nmsgid \"\"\n\"How to do Iterative Layout and Create PDF Links with \"\n\":meth:`Story.write_stabilized_links()`\"\nmsgstr \"繰り返しレイアウトと PDF リンクの作成方法：:meth:`Story.write_stabilized_links()` の使用\"\n\n#: ../../recipes-stories.rst:516 fb00dcb0ee8d442495b1e4dff18aa8bc\nmsgid \"\"\n\"This script is similar to the one described in \\\"How to use \"\n\":meth:`Story.write_stabilized()`\\\" above, except that the generated PDF \"\n\"also contains links that correspond to the internal links in the original\"\n\" html.\"\nmsgstr \"\"\n\"このスクリプトは、「:meth:`Story.write_stabilized()` \"\n\"の使用方法」で説明されているものと類似していますが、生成される PDF には、元の HTML 内の内部リンクに対応するリンクも含まれています。\"\n\n#: ../../recipes-stories.rst:520 6dc7e0e7857b4aa5a713ffcb6869f11c\nmsgid \"\"\n\"This is done by using :meth:`Story.write_stabilized_links()`; this is \"\n\"slightly different from :meth:`Story.write_stabilized()`:\"\nmsgstr \"\"\n\"これは、:meth:`Story.write_stabilized_links()` を使用して行われます。これは  \"\n\":meth:`Story.write_stabilized()` とわずかに異なります：\"\n\n#: ../../recipes-stories.rst:523 77950ef72ea147ec8060ff1ce1609032\nmsgid \"It does not take a :ref:`DocumentWriter` `writer` arg.\"\nmsgstr \":ref:`DocumentWriter` の `writer` 引数は必要ありません。\"\n\n#: ../../recipes-stories.rst:524 f61073b1496a472eb4ffa2abdafdbcdd\nmsgid \"It returns a PDF :ref:`Document` instance.\"\nmsgstr \"PDF :ref:`Document` のインスタンスを返します。\"\n\n#: ../../recipes-stories.rst:526 8200eb3c7ddb4141beb9fd18576a6795\nmsgid \"\"\n\"[The reasons for this are a little involved; for example a \"\n\":ref:`DocumentWriter` is not necessarily a PDF writer, so doesn't really \"\n\"work in a PDF-specific API.]\"\nmsgstr \"\"\n\"[これに関する理由は少し複雑です。例えば、 :ref:`DocumentWriter` が必ずしも PDF ライターであるとは限らず、PDF \"\n\"特有の API ではあまりうまく動作しないためです。]\"\n\n#: ../../recipes-stories.rst:533 6cb38487f6e444d1a3092633504e9b1e\nmsgid \"`docs/samples/story-write-stabilized-links.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:547 7ab6a39468b647919043a79fb3f1c46b\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../recipes-stories.rst:548 6b3a6c4d3e5341b0b7eb4ef2b8a275a9\nmsgid \"HTML & CSS support\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:552 a2b43d5c16a449989cd09987682f3446\nmsgid \"\"\n\"At the time of writing the HTML engine for Stories is fairly basic and \"\n\"supports a subset of CSS2 attributes.\"\nmsgstr \"執筆時点では、ストーリーのHTMLエンジンはかなり基本的であり、一部のCSS2属性をサポートしています。\"\n\n#: ../../recipes-stories.rst:554 97098e31431e469cb54b616f0cdfed52\nmsgid \"Some important CSS support to consider:\"\nmsgstr \"考慮すべき重要なCSSサポート:\"\n\n#: ../../recipes-stories.rst:556 6aea20cf470f4b5b85843b4657ecc2c2\nmsgid \"The only available layout is relative layout.\"\nmsgstr \"唯一利用可能なレイアウトは相対レイアウトです。\"\n\n#: ../../recipes-stories.rst:557 569101dce0664d508b481c1cce2d5b73\nmsgid \"`background` is unavailable, use `background-color` instead.\"\nmsgstr \"`background` は利用できませんが、代わりに `background-color` を使用してください。\"\n\n#: ../../recipes-stories.rst:558 6d32b59649cf4d4ea1b9b964f070004f\nmsgid \"`float` is unavailable.\"\nmsgstr \"`float` は利用できません。\"\n\n#: ../../footer.rst:60 bf323a0643e14a8fbf2f882c9ed3db27\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes-text.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 db5f378b70004af590010a41f0163be1\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 148acec04cbf474bb41f5d5e3c1ec508\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 e6b3ab82dcbf41f687b68d59732a00a5\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../recipes-text.rst:7 70700f14953047898a918c1a07026ce4\nmsgid \"Text\"\nmsgstr \"テキスト\"\n\n#: ../../recipes-text.rst:13 83030b51505549bba2596e8da94111a2\nmsgid \"How to Extract all Document Text\"\nmsgstr \"すべてのドキュメントテキストを抽出する方法\"\n\n#: ../../recipes-text.rst:15 d8d7d26a27a346a5b03d28e400fed598\nmsgid \"\"\n\"This script will take a document filename and generate a text file from \"\n\"all of its text.\"\nmsgstr \"このスクリプトは、ドキュメントのファイル名を受け取り、そのテキストからテキストファイルを生成します。\"\n\n#: ../../recipes-text.rst:17 c4c73613ac86439c93304a2549dbad7f\nmsgid \"The document can be any :ref:`supported type<Supported_File_Types>`.\"\nmsgstr \"ドキュメントは、:ref:`サポートされている <Supported_File_Types>` 任意のタイプのものが使用できます。\"\n\n#: ../../recipes-text.rst:19 8a339400b648449eab4a10cf290842dc\nmsgid \"\"\n\"The script works as a command line tool which expects the document \"\n\"filename supplied as a parameter. It generates one text file named \"\n\"\\\"filename.txt\\\" in the script directory. Text of pages is separated by a\"\n\" form feed character::\"\nmsgstr \"このスクリプトはコマンドラインツールとして機能し、ドキュメントのファイル名をパラメータとして受け取ります。スクリプトのディレクトリに「filename.txt」という名前のテキストファイルが生成されます。ページのテキストはフォームフィード文字で区切られます。\"\n\n#: ../../recipes-text.rst:28 8a4f5ec777ce40e8a27b5ef06541f000\nmsgid \"\"\n\"The output will be plain text as it is coded in the document. No effort \"\n\"is made to prettify in any way. Specifically for PDF, this may mean \"\n\"output not in usual reading order, unexpected line breaks and so forth.\"\nmsgstr \"出力はドキュメント内でコード化された通りのプレーンテキストになるため、見栄えの調整は行いません。特にPDFの場合、通常の読み順にならない出力や予期せぬ改行などが発生するかもしれません。\"\n\n#: ../../recipes-text.rst:30 fa3eea374680406b9a9fba35f66055ca\nmsgid \"\"\n\"You have many options to rectify this -- see chapter :ref:`Appendix2`. \"\n\"Among them are:\"\nmsgstr \"\"\n\"これを修正するための多くのオプションがあります。詳細は :ref:`Appendix2` \"\n\"章「埋め込みファイルに関する考慮事項」を参照してください。以下の方法があります：\"\n\n#: ../../recipes-text.rst:32 93321f1d110c45879711cddd65ff7248\nmsgid \"\"\n\"Extract text in HTML format and store it as a HTML document, so it can be\"\n\" viewed in any browser.\"\nmsgstr \"テキストをHTML形式で抽出し、HTMLドキュメントとして保存することで、任意のブラウザで表示できるようにします。\"\n\n#: ../../recipes-text.rst:33 d31ce8ccb61f4333b9485c37ae95f7a1\nmsgid \"\"\n\"Extract text as a list of text blocks via *Page.get_text(\\\"blocks\\\")*. \"\n\"Each item of this list contains position information for its text, which \"\n\"can be used to establish a convenient reading order.\"\nmsgstr \"Page.get_text(\\\"blocks\\\")を使ってテキストブロックのリストとして抽出します。リストの各アイテムにはテキストの位置情報が含まれており、便利な読み順を確立するのに使用できます。\"\n\n#: ../../recipes-text.rst:34 97d77e0ecd494eb89e58bf1dfd6f89b0\nmsgid \"\"\n\"Extract a list of single words via *Page.get_text(\\\"words\\\")*. Its items \"\n\"are words with position information. Use it to determine text contained \"\n\"in a given rectangle -- see next section.\"\nmsgstr \"Page.get_text(\\\"words\\\")を使って単語のリストを抽出します。各アイテムには位置情報が含まれています。これを使用して特定の四角形に含まれるテキストを決定します。\"\n\n#: ../../recipes-text.rst:36 f695a7c93e504149bb7de0f587892b2a\nmsgid \"See the following two sections for examples and further explanations.\"\nmsgstr \"以下の2つのセクションを見て、例と詳細な説明をご覧ください。\"\n\n#: ../../recipes-text.rst:44 37809012042b408fab85b6b39de8e823\nmsgid \"How to Extract Text as Markdown\"\nmsgstr \"テキストをMarkdown形式で抽出する方法\"\n\n#: ../../recipes-text.rst:46 5c0dcdf0ae704f9aa9fd1bc738b0c185\nmsgid \"\"\n\"This is especially useful for :title:`RAG/LLM` environments - please see \"\n\":ref:`Outputting as Markdown <rag_outputting_as_md>`.\"\nmsgstr \"\"\n\"これは、特に :title:`RAG/LLM`  環境にとって便利です -  :ref:`Outputting as Markdown \"\n\"<rag_outputting_as_md>` を参照してください。\"\n\n#: ../../recipes-text.rst:52 442230f4e860484f83323c6a20d08e08\nmsgid \"How to Extract Key-Value Pairs from a Page\"\nmsgstr \"ページからキーと値のペアを抽出する方法\"\n\n#: ../../recipes-text.rst:53 9555400172a34d69bae562156d51b80c\nmsgid \"\"\n\"If the layout of a page is *\\\"predictable\\\"* in some sense, then there is\"\n\" a simple way to find the values for a given set of keywords fast and \"\n\"easily -- without using regular expressions. Please see `this example \"\n\"script <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/text-\"\n\"extraction/lookup-keywords.py>`_.\"\nmsgstr \"\"\n\"もしページのレイアウトがある程度予測可能であれば、正規表現を使用せずに、特定のキーワードに対する値を迅速かつ簡単に見つける方法があります。 \"\n\"`以下の例のスクリプト <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master\"\n\"/text-extraction/lookup-keywords.py>`_ を参照してください。\"\n\n#: ../../recipes-text.rst:55 f8548ec2c56441c0aa02ed28f3607350\nmsgid \"\\\"Predictable\\\" in this context means:\"\nmsgstr \"ここでの「予測可能」とは、次のような意味です：\"\n\n#: ../../recipes-text.rst:57 0e297df5b4ed4548956122fabdd7e963\nmsgid \"\"\n\"Every keyword is followed by its value -- no other text is present in \"\n\"between them.\"\nmsgstr \"各キーワードの後にはその値が続きます。それらの間に他のテキストはありません。\"\n\n#: ../../recipes-text.rst:58 f9375ed8400040619728b9f1d3031882\nmsgid \"\"\n\"The bottom of the value's boundary box is **not above** the one of the \"\n\"keyword.\"\nmsgstr \"値の境界ボックスの下端は、キーワードの境界ボックスよりも上にありません。\"\n\n#: ../../recipes-text.rst:59 be1d806d61424c179b103fbdfef14d11\nmsgid \"\"\n\"There are **no other restrictions**: the page layout may or may not be \"\n\"fixed, and the text may also have been stored as one string. Key and \"\n\"value may have any distance from each other.\"\nmsgstr \"他の制約はありません：ページのレイアウトが固定されているかどうかは問いませんし、テキストは1つの文字列として保存されている可能性もあります。キーと値はお互いに任意の距離を持つかもしれません。\"\n\n#: ../../recipes-text.rst:61 05731f2a8f5b4e72a99dbd3afb4628ff\nmsgid \"\"\n\"For example, the following five key-value pairs will be correctly \"\n\"identified::\"\nmsgstr \"例として、以下の5つのキーと値のペアが正しく識別されます::\"\n\n#: ../../recipes-text.rst:77 635adbc1c75c4e019220ca2fafd16863\nmsgid \"How to Extract Text from within a Rectangle\"\nmsgstr \"四角形内のテキストを抽出する方法\"\n\n#: ../../recipes-text.rst:78 c66f827c3b4e4d40937891f31bca0ed8\nmsgid \"\"\n\"There is now (v1.18.0) more than one way to achieve this. We therefore \"\n\"have created a `folder <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/textbox-extraction>`_ in the PyMuPDF-Utilities \"\n\"repository specifically dealing with this topic.\"\nmsgstr \"\"\n\"現在（v1.18.0）では、これを実現するための複数の方法があります。そのため、私たちは `PyMuPDF-Utilities \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/textbox-\"\n\"extraction>`_ リポジトリに、この特定のトピックに対応するフォルダを作成しました。\"\n\n#: ../../recipes-text.rst:88 d80121123daf4bf2a3e069027d837c3f\nmsgid \"How to Extract Text in Natural Reading Order\"\nmsgstr \"自然な読み順でテキストを抽出する方法\"\n\n#: ../../recipes-text.rst:90 c1cc039bb3804acebad6d1f03565e6be\nmsgid \"\"\n\"One of the common issues with PDF text extraction is, that text may not \"\n\"appear in any particular reading order.\"\nmsgstr \"PDFのテキスト抽出によくある問題の1つは、テキストが特定の読み順に表示されないことです。\"\n\n#: ../../recipes-text.rst:92 16fbf3e452294bcd88f4d82c83bc87d6\nmsgid \"\"\n\"This is the responsibility of the PDF creator (software or a human). For \"\n\"example, page headers may have been inserted in a separate step -- after \"\n\"the document had been produced. In such a case, the header text will \"\n\"appear at the end of a page text extraction (although it will be \"\n\"correctly shown by PDF viewer software). For example, the following \"\n\"snippet will add some header and footer lines to an existing PDF::\"\nmsgstr \"これはPDFの作成者（ソフトウェアまたは人間）の責任です。たとえば、ページヘッダーはドキュメントが作成された後の別のステップで挿入された可能性があります。そのような場合、ヘッダーテキストはページテキストの抽出の最後に表示されることがあります（ただし、PDFビューアソフトウェアでは正しく表示されます）。以下のスニペットは、既存のPDFにいくつかのヘッダーとフッターの行を追加します::\"\n\n#: ../../recipes-text.rst:104 978688d53bd949cc898416980acbc003\nmsgid \"\"\n\"The text sequence extracted from a page modified in this way will look \"\n\"like this:\"\nmsgstr \"このように変更されたページから抽出されたテキストのシーケンスは次のようになります：\"\n\n#: ../../recipes-text.rst:106 ef048f5a008646e991b0568de7841cb2\nmsgid \"original text\"\nmsgstr \"元のテキスト\"\n\n#: ../../recipes-text.rst:107 dc14bb8d05724f89a619b2d3cceb4926\nmsgid \"header line\"\nmsgstr \"ヘッダーライン\"\n\n#: ../../recipes-text.rst:108 babbbbad94c4402ea4effe7f7adbca5d\nmsgid \"footer line\"\nmsgstr \"フッターライン\"\n\n#: ../../recipes-text.rst:110 e694010b792d4eb0855e2f6564a46a67\nmsgid \"\"\n\"PyMuPDF has several means to re-establish some reading sequence or even \"\n\"to re-generate a layout close to the original:\"\nmsgstr \"PyMuPDFには、いくつかの方法で読み順を再確立したり、元のレイアウトに近い形で再生成する手段があります：\"\n\n#: ../../recipes-text.rst:112 716e99c2ff9344fe81fafd78de2007c3\nmsgid \"\"\n\"Use `sort` parameter of :meth:`Page.get_text`. It will sort the output \"\n\"from top-left to bottom-right (ignored for XHTML, HTML and XML output).\"\nmsgstr \"\"\n\":meth:`Page.get_text` の `sort` \"\n\"パラメーターを使用します。これにより、出力が左上から右下に向かってソートされます（XHTML、HTML、XML出力には無効です）。\"\n\n#: ../../recipes-text.rst:113 bcd2685affe8476281c9b4f6df0f6ff9\nmsgid \"\"\n\"Use the `pymupdf` module in CLI: `python -m pymupdf gettext ...`, which \"\n\"produces a text file where text has been re-arranged in layout-preserving\"\n\" mode. Many options are available to control the output.\"\nmsgstr \"\"\n\"CLIで `pymupdf` モジュールを使用します： `python -m pymupdf gettext ...` \"\n\"。これにより、テキストがレイアウトを保持するモードで再配置されたテキストファイルが生成されます。出力を制御するための多くのオプションが利用可能です。\"\n\n#: ../../recipes-text.rst:115 b14412bcce2e4fabab0f9c2421c08934\nmsgid \"\"\n\"You can also use the above mentioned `script \"\n\"<https://github.com/pymupdf/PyMuPDF/wiki/How-to-extract-text-\"\n\"from-a-rectangle>`_ with your modifications.\"\nmsgstr \"\"\n\"また、上記の `スクリプト <https://github.com/pymupdf/PyMuPDF/wiki/How-to-extract-\"\n\"text-from-a-rectangle>`_ を自分の変更とともに使用することもできます。\"\n\n#: ../../recipes-text.rst:122 6fb4548c9a0a42da9939b9ba59fee62a\nmsgid \"\"\n\"How to :index:`Extract Table Content <pair: extract; table>` from \"\n\"Documents\"\nmsgstr \"ドキュメントから表の内容を抽出する方法\"\n\n#: ../../recipes-text.rst:123 b9aeb958d874414a8dfbe817d7e491be\nmsgid \"\"\n\"If you see a table in a document, you are normally not looking at \"\n\"something like an embedded Excel or other identifiable object. It usually\"\n\" is just normal, standard text, formatted to appear as tabular data.\"\nmsgstr \"文書で表を見る場合、通常は埋め込まれたExcelなどの識別可能なオブジェクトのようなものではありません。通常、単なる通常の標準テキストで、表のデータとして表示されるようにフォーマットされています。\"\n\n#: ../../recipes-text.rst:125 48f2b8ac5dc54b469a4fac3b57e95083\nmsgid \"\"\n\"Extracting tabular data from such a page area therefore means that you \"\n\"must find a way to **identify** the table area (i.e. its boundary box), \"\n\"then **(1)** graphically indicate table and column borders, and **(2)** \"\n\"then extract text based on this information.\"\nmsgstr \"したがって、そのようなページ領域から表のデータを抽出するには、まず表の領域（つまり、その境界ボックス）を特定する方法を見つける必要があり、その後（1）グラフィカルに表と列の境界を示し、（2）この情報に基づいてテキストを抽出する必要があります。\"\n\n#: ../../recipes-text.rst:127 b55a6db346bb4df3adb269cd4da2d2a1\nmsgid \"\"\n\"This can be a very complex task, depending on details like the presence \"\n\"or absence of lines, rectangles or other supporting vector graphics.\"\nmsgstr \"これは、線、四角形、またはその他のサポートベクトルグラフィックの存在または不在などの詳細に依存するため、非常に複雑なタスクになる可能性があります。\"\n\n#: ../../recipes-text.rst:129 2ab382191b1e4c8dbcb05ab17b9a6f16\nmsgid \"\"\n\"Method :meth:`Page.find_tables` does all that for you, with a high table \"\n\"detection precision. Its great advantage is that there are no external \"\n\"library dependencies, nor the need to employ artificial intelligence or \"\n\"machine learning technologies. It also provides an integrated interface \"\n\"to the well-known Python package for data analysis `pandas \"\n\"<https://pypi.org/project/pandas/>`_.\"\nmsgstr \"\"\n\"Method :meth:`Page.find_tables` \"\n\"は、高い表検出精度を備えて、すべてをあなたのために行います。その大きな利点は、外部ライブラリの依存関係がないこと、人工知能や機械学習技術を使用する必要がないことです。また、データ分析のためのPythonパッケージである\"\n\" `pandas <https://pypi.org/project/pandas/>`_ のための統合されたインターフェースも提供します。\"\n\n#: ../../recipes-text.rst:131 b620d2150671401698d7a280f56ee3cc\nmsgid \"\"\n\"Please have a look at example `Jupyter notebooks \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-\"\n\"analysis>`_, which cover standard situations like multiple tables on one \"\n\"page or joining table fragments across multiple pages.\"\nmsgstr \"\"\n\"標準的な状況をカバーする例の `Jupyter <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/table-analysis>`_ \"\n\"ノートブックをご覧いただければ幸いです。これには、1つのページに複数の表や複数のページにまたがる表の断片を結合するなどの状況が含まれています。\"\n\n#: ../../recipes-text.rst:138 259587f74c604a45bd83bdba19dbfdd9\nmsgid \"How to Mark Extracted Text\"\nmsgstr \"抽出したテキストをマークする方法\"\n\n#: ../../recipes-text.rst:139 b7f64cd47ccb4f889b2a09f74c66564f\nmsgid \"\"\n\"There is a standard search function to search for arbitrary text on a \"\n\"page: :meth:`Page.search_for`. It returns a list of :ref:`Rect` objects \"\n\"which surround a found occurrence. These rectangles can for example be \"\n\"used to automatically insert annotations which visibly mark the found \"\n\"text.\"\nmsgstr \"\"\n\"ページ上で任意のテキストを検索するための標準的な検索機能があります:  :meth:`Page.search_for` \"\n\"です。これは、見つかったテキストを囲む :ref:`Rect` \"\n\"オブジェクトのリストを返します。これらの四角形は、見つかったテキストを目に見えるようにマークするために自動的に注釈を挿入するのに使用できます。\"\n\n#: ../../recipes-text.rst:141 febfc5dbb25f420dbf6c3ef3e88b24c4\nmsgid \"This method has advantages and drawbacks. Pros are:\"\nmsgstr \"この方法には利点と欠点があります。利点は次のとおりです：\"\n\n#: ../../recipes-text.rst:143 101f473976a74f1c9ab424859e8862dd\nmsgid \"The search string can contain blanks and wrap across lines\"\nmsgstr \"検索文字列には空白を含めることができ、行をまたぐことができます。\"\n\n#: ../../recipes-text.rst:144 6ad25d7b6043421a8142042b3b9a3ec9\nmsgid \"Upper or lower case characters are treated equal\"\nmsgstr \"大文字と小文字は同じように扱われます。\"\n\n#: ../../recipes-text.rst:145 b3efeff8f1c9463ab435a4742bc0c5bd\nmsgid \"Word hyphenation at line ends is detected and resolved\"\nmsgstr \"行末での単語のハイフネーションが検出され、解決されます。\"\n\n#: ../../recipes-text.rst:146 7a50b0a1eba54da5a0cbd913bde35367\nmsgid \"\"\n\"Return may also be a list of :ref:`Quad` objects to precisely locate text\"\n\" that is **not parallel** to either axis -- using :ref:`Quad` output is \"\n\"also recommended, when page rotation is not zero.\"\nmsgstr \"\"\n\"返り値は :ref:`Quad` \"\n\"オブジェクトのリストになる場合もあり、これにより軸に対して平行でないテキストを正確に位置付けることができます。ページの回転がゼロでない場合には、 \"\n\":ref:`Quad` の出力を使用することも推奨されます。\"\n\n#: ../../recipes-text.rst:148 9f60ccd5aee74a1bb2f791ed857906ac\nmsgid \"But you also have other options::\"\nmsgstr \"ただし、他にも選択肢があります::\"\n\n#: ../../recipes-text.rst:182 324f957419b2409787a7496e75b13dee\nmsgid \"\"\n\"This script uses `Page.get_text(\\\"words\\\")` to look for a string, handed \"\n\"in via cli parameter. This method separates a page's text into \\\"words\\\" \"\n\"using white spaces as delimiters. Further remarks:\"\nmsgstr \"このスクリプトは、cliパラメーターを介して渡された文字列を検索するためにPage.get_text(\\\"words\\\")を使用します。この方法では、ページのテキストがスペースと改行を区切りとして「単語」に分割されます。さらなる注釈：\"\n\n#: ../../recipes-text.rst:184 e11b43b6869e46b89ed4021f9ca781ea\nmsgid \"\"\n\"If found, the **complete word containing the string** is marked \"\n\"(underlined) -- not only the search string.\"\nmsgstr \"文字列が見つかった場合、検索文字列だけでなく、その文字列を含む完全な単語がマークされます（アンダーラインが引かれます）。\"\n\n#: ../../recipes-text.rst:185 04e60745b3b34c6b91dcf325e659bc11\nmsgid \"\"\n\"The search string may **not contain word delimiters**. By default, word \"\n\"delimiters are white spaces and the non-breaking space `chr(0xA0)`. If \"\n\"you use extra delimiting characters like `page.get_text(\\\"words\\\", \"\n\"delimiters=\\\"./,\\\")` then none of these characters should be included in \"\n\"your search string either.\"\nmsgstr \"\"\n\"検索文字列には単語の区切り文字を含めることはできません。デフォルトでは、単語の区切り文字は空白と非改行空白 `chr(0xA0)` です。もし、 \"\n\"`page.get_text(\\\"words\\\", delimiters=\\\"./,\\\")`  \"\n\"のような追加の区切り文字を使用する場合は、これらの文字を検索文字列に含めてはいけません。\"\n\n#: ../../recipes-text.rst:186 d2efc0fb67834d26a4980492e4ba653b\nmsgid \"\"\n\"As shown here, upper / lower cases are **respected**. But this can be \"\n\"changed by using the string method *lower()* (or even regular \"\n\"expressions) in function *mark_word*.\"\nmsgstr \"\"\n\"ここで示したように、大文字と小文字は区別されますが、`mark_word` 関数で `lower()` \"\n\"メソッド（または正規表現）を使用することで変更できます。\"\n\n#: ../../recipes-text.rst:187 f1f92985f2ae49809306e7b57ba6c5b1\nmsgid \"There is **no upper limit**: all occurrences will be detected.\"\nmsgstr \"上限はありません。すべての出現を検出します。\"\n\n#: ../../recipes-text.rst:188 6639bc0b294042f3b7da287582d935d1\nmsgid \"\"\n\"You can use **anything** to mark the word: 'Underline', 'Highlight', \"\n\"'StrikeThrough' or 'Square' annotations, etc.\"\nmsgstr \"単語をマークするために何を使用しても構いません：「アンダーライン」、「ハイライト」、「取り消し線」、「四角」の注釈などがあります。\"\n\n#: ../../recipes-text.rst:189 f003fe97efd4436285d6bc3016b36180\nmsgid \"\"\n\"Here is an example snippet of a page of this manual, where \\\"MuPDF\\\" has \"\n\"been used as the search string. Note that all strings **containing \"\n\"\\\"MuPDF\\\"** have been completely underlined (not just the search string).\"\nmsgstr \"以下は、このマニュアルのページの一部の例スニペットで、「MuPDF」が検索文字列として使用されています。注意：「MuPDF」を含むすべての文字列が完全にアンダーラインで引かれていることに注意してください（検索文字列だけでなく）。\"\n\n#: ../../recipes-text.rst:200 07364170c89f43d7a469ec584d3f4f06\nmsgid \"How to Mark Searched Text\"\nmsgstr \"検索したテキストをマークする方法\"\n\n#: ../../recipes-text.rst:204 11638cbd201f4578b319a8b04e773026\nmsgid \"This script searches for text and marks it::\"\nmsgstr \"このスクリプトはテキストを検索してマークします::\"\n\n#: ../../recipes-text.rst:230 15b785bdfebf418aba157f4f78a77e4b\nmsgid \"The result looks like this:\"\nmsgstr \"結果は以下のようになります：\"\n\n#: ../../recipes-text.rst:241 080eb1dc215a426e9e7a03e134dc4fa2\nmsgid \"How to Mark Non-horizontal Text\"\nmsgstr \"非水平テキストをマークする方法\"\n\n#: ../../recipes-text.rst:242 6fe2ff76b1d0421d8ab98c926c234cb0\nmsgid \"\"\n\"The previous section already shows an example for marking non-horizontal \"\n\"text, that was detected by text **searching**.\"\nmsgstr \"前のセクションでは、テキスト検索によって検出された非水平テキストのマークの例が既に示されています。\"\n\n#: ../../recipes-text.rst:244 9f3587b3ee80418e80f13b3ad91233ec\nmsgid \"\"\n\"But text **extraction** with the \\\"dict\\\" / \\\"rawdict\\\" options of \"\n\":meth:`Page.get_text` may also return text with a non-zero angle to the \"\n\"x-axis. This is indicated by the value of the line dictionary's `\\\"dir\\\"`\"\n\" key: it is the tuple `(cosine, sine)` for that angle. If `line[\\\"dir\\\"] \"\n\"!= (1, 0)`, then the text of all its spans is rotated by (the same) angle\"\n\" != 0.\"\nmsgstr \"\"\n\"しかし、 :meth:`Page.get_text` \"\n\"の「dict」/「rawdict」オプションを使用したテキスト抽出では、x軸に対してゼロでない角度のテキストも返される場合があります。これは、行の辞書の\"\n\" \\\"dir\\\" キーの値によって示されます：それはその角度に対する  `(cosine, sine)`  のタプルです。 \"\n\"`line[\\\"dir\\\"] != (1, 0)`  であれば、すべてのスパンのテキストは (同じ) 角度 != 0 によって回転しています。\"\n\n#: ../../recipes-text.rst:246 b5ac4e18122a4f8985e80cf88f3152b4\nmsgid \"\"\n\"The \\\"bboxes\\\" returned by the method however are rectangles only -- not \"\n\"quads. So, to mark span text correctly, its quad must be recovered from \"\n\"the data contained in the line and span dictionary. Do this with the \"\n\"following utility function (new in v1.18.9)::\"\nmsgstr \"ただし、このメソッドによって返される「bboxes」は四角形のみであり、クワッドではありません。したがって、スパンテキストを正しくマークするには、行とスパンの辞書に含まれるデータからクワッドを回復する必要があります。以下のユーティリティ関数を使用してください（v1.18.9で新しく追加されました）::\"\n\n#: ../../recipes-text.rst:251 220c8fb8fa4b46c781ff32905bc0a24e\nmsgid \"\"\n\"If you want to **mark the complete line** or a subset of its spans in one\"\n\" go, use the following snippet (works for v1.18.10 or later)::\"\nmsgstr \"一度に完全な行またはその一部のスパンをマークしたい場合は、以下のスニペットを使用してください（v1.18.10以降で動作します）\"\n\n#: ../../recipes-text.rst:258 85d1dfa0969b4848b83f9b2f117d981c\nmsgid \"\"\n\"The `spans` argument above may specify any sub-list of `line[\\\"spans\\\"]`.\"\n\" In the example above, the second to second-to-last span are marked. If \"\n\"omitted, the complete line is taken.\"\nmsgstr \"\"\n\"上記の `spans` 引数は、`line[\\\"spans\\\"]` \"\n\"の任意の部分リストを指定できます。上記の例では、2番目から最後から2番目のスパンがマークされます。省略すると、完全な行が取得されます\"\n\n#: ../../recipes-text.rst:265 b4aaece1bac342df88b2588a53b1488f\nmsgid \"How to Analyze Font Characteristics\"\nmsgstr \"フォントの特性を分析する方法\"\n\n#: ../../recipes-text.rst:266 3d03a051124b43d1bae8d901b0aecd28\nmsgid \"\"\n\"To analyze the characteristics of text in a PDF use this elementary \"\n\"script as a starting point:\"\nmsgstr \"PDF内のテキストの特性を分析するには、以下の初歩的なスクリプトを出発点として使用します::\"\n\n#: ../../recipes-text.rst:271 f055a412baca41b5a95b0ecadafe2e3e\nmsgid \"Here is the PDF page and the script output:\"\nmsgstr \"以下はPDFページとスクリプトの出力です。\"\n\n#: ../../recipes-text.rst:282 66219ea8cab542688f83c1bd81f081c1\nmsgid \"How to Insert Text\"\nmsgstr \"テキストの挿入方法\"\n\n#: ../../recipes-text.rst:283 4e0c636dd4ac4eb387bcde62a6a2a175\nmsgid \"\"\n\"PyMuPDF provides ways to insert text on new or existing PDF pages with \"\n\"the following features:\"\nmsgstr \"PyMuPDFは、以下の機能を備えて新しいまたは既存のPDFページにテキストを挿入する方法を提供しています：\"\n\n#: ../../recipes-text.rst:285 155bbc5aa1454c93b980b30ac316c0b0\nmsgid \"\"\n\"choose the font, including built-in fonts and fonts that are available as\"\n\" files\"\nmsgstr \"フォントの選択：組み込みのフォントやファイルとして利用可能なフォントを選択できます。\"\n\n#: ../../recipes-text.rst:286 b9dd50f8a43d417ea405cd07b235088d\nmsgid \"choose text characteristics like bold, italic, font size, font color, etc.\"\nmsgstr \"テキストの特性の選択：太字、斜体、フォントサイズ、フォントカラーなど、テキストの特性を選択できます。\"\n\n#: ../../recipes-text.rst:287 f938ab7b656c436297d8120a887e4fcc\nmsgid \"position the text in multiple ways:\"\nmsgstr \"テキストの配置方法：\"\n\n#: ../../recipes-text.rst:289 96ff2b06077841bf82fb23104230f9ed\nmsgid \"either as simple line-oriented output starting at a certain point,\"\nmsgstr \"特定のポイントを起点として単純な行指向の出力として配置することができます。 \"\n\n#: ../../recipes-text.rst:290 dcf40c10ea294dc8a656732166297259\nmsgid \"\"\n\"or fitting text in a box provided as a rectangle, in which case text \"\n\"alignment choices are also available,\"\nmsgstr \"ボックスにテキストをフィットさせる場合は、テキストの配置を選択することもできます。この場合、テキストの整列オプションも利用できます。\"\n\n#: ../../recipes-text.rst:291 056f2e92f23f4d41beb702386a246a80\nmsgid \"\"\n\"choose whether text should be put in foreground (overlay existing \"\n\"content),\"\nmsgstr \"テキストを前面に配置するか選択できます（既存のコンテンツをオーバーレイします）。\"\n\n#: ../../recipes-text.rst:292 5999867be03a4be495cbfd225913c3d4\nmsgid \"\"\n\"all text can be arbitrarily \\\"morphed\\\", i.e. its appearance can be \"\n\"changed via a :ref:`Matrix`, to achieve effects like scaling, shearing or\"\n\" mirroring,\"\nmsgstr \"テキストは任意に「変形」されることができます。つまり、行列を使用して拡大、せん断、反転などの効果を得ることができます。\"\n\n#: ../../recipes-text.rst:293 25c6fa1fb2344a02a3a693135a7b5ad4\nmsgid \"\"\n\"independently from morphing and in addition to that, text can be rotated \"\n\"by integer multiples of 90 degrees.\"\nmsgstr \"変形とは別に、テキストを90度の整数倍で回転させることもできます。\"\n\n#: ../../recipes-text.rst:295 2190abc125234360a3e1fab88ef34947\nmsgid \"\"\n\"All of the above is provided by three basic :ref:`Page`, resp. \"\n\":ref:`Shape` methods:\"\nmsgstr \"以上のすべては、それぞれの基本的な :ref:`Page` 、:ref:`Shape` メソッドによって提供されています。\"\n\n#: ../../recipes-text.rst:297 4fb036ddb792472197216092b9eefddb\nmsgid \"\"\n\":meth:`Page.insert_font` -- install a font for the page for later \"\n\"reference. The result is reflected in the output of \"\n\":meth:`Document.get_page_fonts`. The font can be:\"\nmsgstr \"\"\n\":meth:`Page.insert_font` - ページにフォントをインストールして後で参照できるようにします。その結果は、 \"\n\":meth:`Document.get_page_fonts` の出力に反映されます。フォントは以下の方法で提供できます：\"\n\n#: ../../recipes-text.rst:299 3c7f3dadc700412b9396227e3e8b9ff6\nmsgid \"provided as a file,\"\nmsgstr \"ファイルとして提供する。\"\n\n#: ../../recipes-text.rst:300 40d5ff2c32c44c6584f3112ed978abef\nmsgid \"via :ref:`Font` (then use :attr:`Font.buffer`)\"\nmsgstr \":ref:`Font` を使用して提供する（その場合、 :attr:`Font.buffer` を使用します）。\"\n\n#: ../../recipes-text.rst:301 6267fd1e928e41658810a84d52de31c7\nmsgid \"already present somewhere in **this or another** PDF, or\"\nmsgstr \"既にこのPDFまたは別のPDFのどこかに存在する。\"\n\n#: ../../recipes-text.rst:302 2ebf7edb3c7e4c4482334300df5af372\nmsgid \"be a **built-in** font.\"\nmsgstr \"組み込みフォントである。\"\n\n#: ../../recipes-text.rst:304 e6a884a850ad4cb49e2a74eeb2f5bc61\nmsgid \"\"\n\":meth:`Page.insert_text` -- write some lines of text. Internally, this \"\n\"uses :meth:`Shape.insert_text`.\"\nmsgstr \"\"\n\":meth:`Page.insert_text`  - テキストの行を書き込みます。内部的には :meth:`Shape.insert_text`\"\n\" を使用します。\"\n\n#: ../../recipes-text.rst:306 5252e3a0b80e49a4af1e7a62b8a2cc00\nmsgid \"\"\n\":meth:`Page.insert_textbox` -- fit text in a given rectangle. Here you \"\n\"can choose text alignment features (left, right, centered, justified) and\"\n\" you keep control as to whether text actually fits. Internally, this uses\"\n\" :meth:`Shape.insert_textbox`.\"\nmsgstr \"\"\n\":meth:`Page.insert_textbox`  - \"\n\"指定された矩形にテキストをフィットさせます。ここでは、テキストの整列機能（左揃え、右揃え、中央揃え、両端揃え）を選択できます。また、テキストが実際にフィットするかどうかの制御もできます。内部的には\"\n\" :meth:`Shape.insert_textbox` を使用します。\"\n\n#: ../../recipes-text.rst:308 0d6285e91b3c45608b972b2de7612705\nmsgid \"Both text insertion methods automatically install the font as necessary.\"\nmsgstr \"テキスト挿入の両方の方法は、必要に応じてフォントを自動的にインストールします。\"\n\n#: ../../recipes-text.rst:314 4615115cc7ec417e9025309e87d5c912\nmsgid \"How to Write Text Lines\"\nmsgstr \"テキスト行を書く方法\"\n\n#: ../../recipes-text.rst:315 c5ec955ab13243b49f36ee01f5a5e363\nmsgid \"Output some text lines on a page::\"\nmsgstr \"ページにいくつかのテキスト行を出力する方法::\"\n\n#: ../../recipes-text.rst:336 8385d05c2aaf4baf89657017938f1841\nmsgid \"\"\n\"With this method, only the **number of lines** will be controlled to not \"\n\"go beyond page height. Surplus lines will not be written and the number \"\n\"of actual lines will be returned. The calculation uses a line height \"\n\"calculated from the :data:`fontsize` and 36 points (0.5 inches) as bottom\"\n\" margin.\"\nmsgstr \"\"\n\"この方法では、ページの高さを超えないように行の数だけを制御します。余剰の行は書き込まれず、実際の行数が返されます。計算には、:data:`fontsize`\"\n\" と36ポイント（0.5インチ）のボトムマージンから計算された行の高さが使用されます。\"\n\n#: ../../recipes-text.rst:338 86eb433806094945b5d70882c088708a\nmsgid \"\"\n\"Line **width is ignored**. The surplus part of a line will simply be \"\n\"invisible.\"\nmsgstr \"行の幅は無視されます。行の余剰部分は単に見えなくなります。\"\n\n#: ../../recipes-text.rst:340 a76488ed16d54e53b404c6f7a09d9313\nmsgid \"\"\n\"However, for built-in fonts there are ways to calculate the line width \"\n\"beforehand - see :meth:`get_text_length`.\"\nmsgstr \"ただし、組み込みのフォントには、行の幅を事前に計算する方法があります。 :meth:`get_text_length` を参照してください。\"\n\n#: ../../recipes-text.rst:342 b366c349b7114db78ed6f108144468f9\nmsgid \"\"\n\"Here is another example. It inserts 4 text strings using the four \"\n\"different rotation options, and thereby explains, how the text insertion \"\n\"point must be chosen to achieve the desired result::\"\nmsgstr \"以下は別の例です。4つの異なる回転オプションを使用してテキスト文字列を挿入し、それにより、望む結果を得るためにどのようにテキスト挿入ポイントを選択すべきかを説明しています::\"\n\n#: ../../recipes-text.rst:378 fb820c64521f4522a238d2ce77dcaf18\nmsgid \"This is the result:\"\nmsgstr \"これが結果です。\"\n\n#: ../../recipes-text.rst:390 541c84709e8840f99fe3aba0b40495a5\nmsgid \"How to Fill a Text Box\"\nmsgstr \"テキストボックスの塗りつぶし方\"\n\n#: ../../recipes-text.rst:391 c6dcf5cccb0044f8b35d759a5221dfae\nmsgid \"\"\n\"This script fills 4 different rectangles with text, each time choosing a \"\n\"different rotation value::\"\nmsgstr \"このスクリプトは、異なる回転値を選択して、4つの異なる長方形にテキストを塗りつぶします。\"\n\n#: ../../recipes-text.rst:428 2e957f827c5b40aaa4e166eb9499bfbb\nmsgid \"\"\n\"Some default values were used above: font size 11 and text alignment \"\n\"\\\"left\\\". The result will look like this:\"\nmsgstr \"上記ではいくつかのデフォルト値が使用されました：フォント「Helvetica」、フォントサイズ11、テキストの配置は「左寄せ」です。結果は以下のようになります。\"\n\n#: ../../recipes-text.rst:438 c7e2172b7c074d11b35164dc32c22e23\nmsgid \"How to Fill a Box with HTML Text\"\nmsgstr \"HTMLテキストでボックスを埋める方法\"\n\n#: ../../recipes-text.rst:439 42df2d56d1f34d98823882e630fe1cf7\nmsgid \"\"\n\"Method :meth:`Page.insert_htmlbox` offers a **much more powerful** way to\"\n\" insert text in a rectangle.\"\nmsgstr \"メソッド :meth:`Page.insert_htmlbox` は、矩形にテキストを挿入するための **より強力な** 方法を提供します。\"\n\n#: ../../recipes-text.rst:441 d5759271e33d478eae11f568d17338fc\nmsgid \"\"\n\"Instead of simple, plain text, this method accepts HTML source, which may\"\n\" not only contain HTML tags but also styling instructions to influence \"\n\"things like font, font weight (bold) and style (italic), color and much \"\n\"more.\"\nmsgstr \"このメソッドは、単純なプレーンテキストではなく、HTMLソースを受け入れます。HTMLタグのみならず、フォント、フォントの太さ（太字）、スタイル（イタリック）、色などを含むスタイル指示も含まれます。\"\n\n#: ../../recipes-text.rst:443 ba663f954c914a1a8d20788c385f392c\nmsgid \"\"\n\"It is also possible to mix multiple fonts and languages, to output HTML \"\n\"tables and to insert images and URI links.\"\nmsgstr \"複数のフォントや言語を混在させ、HTMLテーブルを出力し、画像やURIリンクを挿入することも可能です。\"\n\n#: ../../recipes-text.rst:445 e592608d0a5348499aff8a592bb61837\nmsgid \"\"\n\"For even more styling flexibility, an additional CSS source may also be \"\n\"given.\"\nmsgstr \"さらなるスタイリングの柔軟性を求める場合、追加のCSSソースを指定することもできます。\"\n\n#: ../../recipes-text.rst:447 11d3134828ab455a9beb1bd08b3eedc9\nmsgid \"\"\n\"The method is based on the :ref:`Story` class. Therefore, complex script \"\n\"systems like Devanagari, Nepali, Tamil and many are supported and written\"\n\" correctly thanks to using the HarfBuzz library - which provides this so-\"\n\"called **\\\"text shaping\\\"** feature.\"\nmsgstr \"\"\n\"このメソッドは、 :ref:`Story` \"\n\"（ストーリー）クラスに基づいています。そのため、デーヴァナーガリ、ネパール語、タミル語などの複雑な文字体系がサポートされ、HarfBuzzライブラリを使用して正しく書き込まれています\"\n\" - これがいわゆる **「テキストの形成」** 機能を提供します。\"\n\n#: ../../recipes-text.rst:449 702e632bbb1846448ff097d413da8fb7\nmsgid \"\"\n\"Any required fonts to output characters are automatically pulled in from \"\n\"the Google NOTO font library - as a fallback (when the -- optionally \"\n\"supplied -- user font(s) do not contain some glyphs).\"\nmsgstr \"\"\n\"文字を出力するために必要なフォントは、--オプションで提供される--\"\n\"ユーザーフォントが一部のグリフを含んでいない場合のフォールバックとして、Google NOTOフォントライブラリから自動的に取得されます。\"\n\n#: ../../recipes-text.rst:451 6c11c27cd47042e2974d9dad0680a2a9\nmsgid \"\"\n\"As a small glimpse into the features offered here, we will output the \"\n\"following HTML-enriched text::\"\nmsgstr \"ここで提供される機能の一端をご覧いただくために、以下のHTMLエンリッチされたテキストを出力します：\"\n\n#: ../../recipes-text.rst:476 2ad55055659d456fabde0186e22d4e26\nmsgid \"\"\n\"Please note how the \\\"css\\\" parameter is used to globally select the \"\n\"default \\\"sans-serif\\\" font and a font size of 14.\"\nmsgstr \"「css」パラメータが、デフォルトの「sans-serif」フォントとフォントサイズ14をグローバルに選択する方法に注意してください。\"\n\n#: ../../recipes-text.rst:478 ../../recipes-text.rst:546\n#: 3c4cca1121d6405eb83e0cb2871b7570 8e7f4fe263f24763bbf69efa19489d99\nmsgid \"The result will look like this:\"\nmsgstr \"結果は以下のようになります：\"\n\n#: ../../recipes-text.rst:483 b7f446683eca4524b8fc2bd988191712\nmsgid \"How to output HTML tables and images\"\nmsgstr \"HTMLテーブルや画像を出力する方法\"\n\n#: ../../recipes-text.rst:485 ed6bb1a3fe524fbda24f9c97da319399\nmsgid \"\"\n\"Here is another example that outputs a table with this method. This time,\"\n\" we are including all the styling in the HTML source itself. Please also \"\n\"note, how it works to include an image - even within a table cell::\"\nmsgstr \"以下は、このメソッドを使用してテーブルを出力する別の例です。今回は、すべてのスタイリングをHTMLソース自体に含めています。また、テーブルセル内に画像を含める方法についても、ご注意ください::\"\n\n#: ../../recipes-text.rst:552 4cd24c13bbba4d8d8b0887c53d530e7e\nmsgid \"How to Output Languages of the World\"\nmsgstr \"世界の言語を出力する方法\"\n\n#: ../../recipes-text.rst:554 5e1849ae29cd4ee787b3105c593def1a\nmsgid \"\"\n\"Our third example will demonstrate the automatic multi-language support. \"\n\"It includes automatic **text shaping** for complex scripting systems like\"\n\" Devanagari and right-to-left languages::\"\nmsgstr \"\"\n\"3つ目の例では、自動多言語サポートを示します。これには、デーヴァナーガリや右から左への言語などの複雑なスクリプトシステムに対する自動 \"\n\"**テキスト整形** も含まれます：\"\n\n#: ../../recipes-text.rst:584 7f93ecf38f45410098070b9c478823f0\nmsgid \"And this is the output:\"\nmsgstr \"これが結果です。\"\n\n#: ../../recipes-text.rst:589 0fc8a571f2164e8b8fa47da93210cc9b\nmsgid \"How to Specify your Own Fonts\"\nmsgstr \"独自のフォントを指定する方法\"\n\n#: ../../recipes-text.rst:591 f4ddad35adde440a9851a6e69fcfcf35\nmsgid \"\"\n\"Define your font files in CSS syntax using the `@font-face` statement. \"\n\"You need a separate `@font-face` for every combination of font weight and\"\n\" font style (e.g. bold or italic) you want to be supported. The following\"\n\" example uses the famous MS Comic Sans font in its four variants regular,\"\n\" bold, italic and bold-italic.\"\nmsgstr \"\"\n\"`@font-face` \"\n\"ステートメントを使用して、CSS構文でフォントファイルを定義します。サポートされるフォントのウェイトとスタイル（太字や斜体など）の組み合わせごとに、個別の\"\n\" `@font-face` が必要です。以下の例では、有名な MS Comic Sans フォントの 4 \"\n\"つのバリアント（通常、太字、斜体、太字斜体）を使用しています。\"\n\n#: ../../recipes-text.rst:593 f8779468c07c47ef9000fb2979f5214c\nmsgid \"\"\n\"As these four font files are located in the system's folder \"\n\"`C:/Windows/Fonts` the method needs an :ref:`Archive` definition that \"\n\"points to that folder::\"\nmsgstr \"\"\n\"これらの 4 つのフォントファイルがシステムのフォルダ `C:/Windows/Fonts` にあるため、このメソッドには、そのフォルダを指す \"\n\":ref:`Archive` （アーカイブ）の定義が必要です。\"\n\n#: ../../recipes-text.rst:642 06ab66e236cc4a2ea7d4c5a99612f4dd\nmsgid \"How to Request Text Alignment\"\nmsgstr \"テキストの配置をリクエストする方法\"\n\n#: ../../recipes-text.rst:644 7795bb870b4f42f187a0efe85b6c761d\nmsgid \"This example combines multiple requirements:\"\nmsgstr \"この例では、複数の要件を組み合わせています\"\n\n#: ../../recipes-text.rst:646 ff142aa60660494db8d4272e60183ff1\nmsgid \"Rotate the text by 90 degrees anti-clockwise.\"\nmsgstr \"テキストを90度反時計回りに回転させます。\"\n\n#: ../../recipes-text.rst:647 c1627013d8474a4f82eb9fcc874f012c\nmsgid \"\"\n\"Use a font from package `pymupdf-fonts <https://pypi.org/project/pymupdf-\"\n\"fonts/>`_. You will see that the respective CSS definitions are a lot \"\n\"easier in this case.\"\nmsgstr \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ \"\n\"パッケージからフォントを使用します。この場合、該当するCSS定義がはるかに簡単であることに気付くでしょう。\"\n\n#: ../../recipes-text.rst:648 827ab2e55bb64443b6dcbb706662051a\nmsgid \"Align the text with the \\\"justify\\\" option.\"\nmsgstr \"テキストを \\\"justify\\\" オプションで配置します。\"\n\n#: ../../recipes-text.rst:698 424d197ff94d4b4f9c4c0cc4513a960d\nmsgid \"How to Extract Text with Color\"\nmsgstr \"色付きのテキストを抽出する方法\"\n\n#: ../../recipes-text.rst:700 a842d1070655423986ddbb7afdbb289b\nmsgid \"\"\n\"Iterate through your text blocks and find the spans of text you need for \"\n\"this information.\"\nmsgstr \"テキストブロックを繰り返し処理し、必要な情報のテキストスパンを見つけます。\"\n\n#: ../../footer.rst:60 b02445d3686f4215969d2dff8b922af2\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"The search string may **not contain spaces** or other white space.\"\n#~ msgstr \"検索文字列にはスペースや他の空白文字を含めることはできません。\"\n\n#~ msgid \"How to Use Non-Standard Encoding\"\n#~ msgstr \"非標準エンコーディングの使用方法\"\n\n#~ msgid \"\"\n#~ \"Since v1.14, MuPDF allows Greek and \"\n#~ \"Russian encoding variants for the \"\n#~ \":data:`Base14_Fonts`. In PyMuPDF this is \"\n#~ \"supported via an additional *encoding* \"\n#~ \"argument. Effectively, this is relevant \"\n#~ \"for Helvetica, Times-Roman and Courier\"\n#~ \" (and their bold / italic forms) \"\n#~ \"and characters outside the ASCII code\"\n#~ \" range only. Elsewhere, the argument \"\n#~ \"is ignored. Here is how to request\"\n#~ \" Russian encoding with the standard \"\n#~ \"font Helvetica::\"\n#~ msgstr \"\"\n#~ \"v1.14以降、MuPDFでは :data:`Base14_Fonts` \"\n#~ \"のギリシャ語およびロシア語のエンコーディングバリアントが許可されています。PyMuPDFでは、これは追加のエンコーディング引数を介してサポートされています。これは実際にはHelvetica\"\n#~ \"、Times-\"\n#~ \"Roman、Courier（およびそれらの太字/斜体形式）およびASCIIコード範囲外の文字にのみ影響します。他の場所では、この引数は無視されます。以下は、標準フォントHelveticaでロシア語のエンコーディングを要求する方法です::\"\n\n#~ msgid \"\"\n#~ \"The valid encoding values are \"\n#~ \"TEXT_ENCODING_LATIN (0), TEXT_ENCODING_GREEK (1),\"\n#~ \" and TEXT_ENCODING_CYRILLIC (2, Russian) \"\n#~ \"with Latin being the default. Encoding\"\n#~ \" can be specified by all relevant \"\n#~ \"font and text insertion methods.\"\n#~ msgstr \"有効なエンコーディング値は、TEXT_ENCODING_LATIN（0）、TEXT_ENCODING_GREEK（1）、TEXT_ENCODING_CYRILLIC（2、ロシア語）であり、デフォルトはLatinです。エンコーディングは、すべての関連するフォントおよびテキスト挿入メソッドで指定できます。\"\n\n#~ msgid \"\"\n#~ \"By the above statement, the fontname \"\n#~ \"*helv* is automatically connected to the\"\n#~ \" Russian font variant of Helvetica. \"\n#~ \"Any subsequent text insertion with \"\n#~ \"**this fontname** will use the Russian\"\n#~ \" Helvetica encoding.\"\n#~ msgstr \"上記の記述により、フォント名「helv」は自動的にHelveticaのロシア語バリアントに接続されます。このフォント名を使用して以降のテキスト挿入では、ロシア語のHelveticaエンコーディングが使用されます。\"\n\n#~ msgid \"\"\n#~ \"If you change the fontname just \"\n#~ \"slightly, you can also achieve an \"\n#~ \"**encoding \\\"mixture\\\"** for the **same \"\n#~ \"base font** on the same page::\"\n#~ msgstr \"フォント名をわずかに変更することで、同じベースフォントの同じページ上でエンコーディングの「混合」を実現することもできます。\"\n\n#~ msgid \"The result:\"\n#~ msgstr \"結果は以下の通りです。\"\n\n#~ msgid \"\"\n#~ \"The snippet above indeed leads to \"\n#~ \"three different copies of the Helvetica\"\n#~ \" font in the PDF. Each copy is\"\n#~ \" uniquely identified (and referenceable) by\"\n#~ \" using the correct upper-lower case\"\n#~ \" spelling of the reserved word \"\n#~ \"\\\"helv\\\"::\"\n#~ msgstr \"上記のスニペットは実際にPDF内にHelveticaフォントの3つの異なるコピーを生成します。各コピーは正しい大文字小文字のスペル（\\\"helv\\\"）を使用して一意に識別され、参照が可能です。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/recipes.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4009185189884afa815f06437219b17a\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 0945b3eedd774aa1bf2ed67c92baa34e\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 5438d71f4a5f445c9c4929c4169009b8\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../footer.rst:60 8482813d3d6a47a39130184e645552b4\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/rect.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 3c227dada5ad4b709a49770ee170baa6\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 8f56716e037546c8b467b98c68c725a0\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 dfa0342751984e2f98c9f67f7362520d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../rect.rst:7 ad45c59577c04e0d97cd0d7904581921\nmsgid \"Rect\"\nmsgstr \"Rect (矩形)\"\n\n#: ../../rect.rst:9 7f5d586f3c114edaa7ba458bfd6acb19\nmsgid \"\"\n\"*Rect* represents a rectangle defined by four floating point numbers x0, \"\n\"y0, x1, y1. They are treated as being coordinates of two diagonally \"\n\"opposite points. The first two numbers are regarded as the \\\"top left\\\" \"\n\"corner P\\\\ :sub:`(x0,y0)` and P\\\\ :sub:`(x1,y1)` as the \\\"bottom right\\\" \"\n\"one. However, these two properties need not coincide with their intuitive\"\n\" meanings -- read on.\"\nmsgstr \"\"\n\"*Rect* \"\n\"は、4つの浮動小数点数x0、y0、x1、y1によって定義される矩形を表します。これらは対角線上の2つの点の座標と見なされます。最初の2つの数は「左上」のコーナー\"\n\" P\\\\ :sub:`(x0,y0)` とし、 P\\\\ :sub:`(x1,y1)` \"\n\"は「右下」のコーナーとします。ただし、これら2つのプロパティは直感的な意味と一致する必要はありません。以下を読んでください。\"\n\n#: ../../rect.rst:11 dafcd3bc742b4bf98df8a2d355642314\nmsgid \"The following remarks are also valid for :ref:`IRect` objects:\"\nmsgstr \":ref:`IRect` オブジェクトにも以下の注釈は有効です。\"\n\n#: ../../rect.rst:13 be324158236b4de8923841e0b42e8290\nmsgid \"\"\n\"A rectangle in the sense of (Py-) MuPDF **(and PDF)** always has \"\n\"**borders parallel to the x- resp. y-axis**. A general orthogonal \"\n\"tetragon **is not a rectangle** -- in contrast to the mathematical \"\n\"definition.\"\nmsgstr \"\"\n\"(Py-)MuPDF **（およびPDF）** の意味での矩形は常に **x-またはy軸に平行な境界** を持ちます。一般的な直交四角形は \"\n\"**矩形ではなく** 、数学的な定義とは対照的です。\"\n\n#: ../../rect.rst:14 03d260254e054fa0874151431af0b147\nmsgid \"\"\n\"The constructing points can be (almost! -- see below) anywhere in the \"\n\"plane -- they need not even be different, and e.g. \\\"top left\\\" need not \"\n\"be the geometrical \\\"north-western\\\" point.\"\nmsgstr \"構築ポイントは平面上のどこにでも配置できます。異なる必要すらなく、たとえば「左上」が幾何学的に「北西」の点である必要はありません。\"\n\n#: ../../rect.rst:15 fe6fa15cf8b7439aa597e5fcf5b13134\nmsgid \"Units are in points, where 72 points is 1 inch.\"\nmsgstr \"単位はポイントで、72ポイントが1インチです。\"\n\n#: ../../rect.rst:20 130a99f1057240a98f97beb4238fadbc\nmsgid \"\"\n\"For any given quadruple of numbers, the geometrically \\\"same\\\" rectangle \"\n\"can be defined in four different ways:\"\nmsgstr \"与えられた4つの数値に対して、幾何学的に「同じ」矩形は4つの異なる方法で定義できます。\"\n\n#: ../../rect.rst:17 03ee461b9fd7463e92b92b0999c2952b\nmsgid \"Rect(P\\\\ :sub:`(x0,y0)`, P\\\\ :sub:`(x1,y1)`\\\\ )\"\nmsgstr \"\"\n\n#: ../../rect.rst:18 4e4f6956c7774df98b15fe8f1f149cef\nmsgid \"Rect(P\\\\ :sub:`(x1,y1)`, P\\\\ :sub:`(x0,y0)`\\\\ )\"\nmsgstr \"\"\n\n#: ../../rect.rst:19 7b63166e1f914252a70101cc5e25c590\nmsgid \"Rect(P\\\\ :sub:`(x0,y1)`, P\\\\ :sub:`(x1,y0)`\\\\ )\"\nmsgstr \"\"\n\n#: ../../rect.rst:20 baae5ac330ae44adb90f80708b977873\nmsgid \"Rect(P\\\\ :sub:`(x1,y0)`, P\\\\ :sub:`(x0,y1)`\\\\ )\"\nmsgstr \"\"\n\n#: ../../rect.rst:22 3775def55ff3492ea62cba278b2ff00e\nmsgid \"**(Changed in v1.19.0)** Hence some classification:\"\nmsgstr \"**(v1.19.0で変更)** したがって、いくつかの分類があります。\"\n\n#: ../../rect.rst:24 005b82343a4c4d4282a0fc3d8a056830\nmsgid \"\"\n\"A rectangle is called **valid** if `x0 <= x1` and `y0 <= y1` (i.e. the \"\n\"bottom right point is \\\"south-eastern\\\" to the top left one), otherwise \"\n\"**invalid**. Of the four alternatives above, **only the first** is valid.\"\n\" Please take into account, that in MuPDF's coordinate system, the y-axis \"\n\"is oriented from **top to bottom**. Invalid rectangles have been called \"\n\"infinite in earlier versions.\"\nmsgstr \"\"\n\"矩形は、 `x0 <= x1`  および  `y0 <= y1` （つまり、右下の点が左上の点の「南東」にある）の場合にのみ **有効** \"\n\"と呼ばれます。したがって、上記の4つの代替案のうち、**最初のものだけ** が有効です。MuPDFの座標系では、y軸は **上から下** \"\n\"に向かっていますので、注意してください。無効な矩形は以前のバージョンでは 無限と呼ばれていました。\"\n\n#: ../../rect.rst:26 50cc1e1a23b7410e9b40d9e4a22e2552\nmsgid \"\"\n\"A rectangle is called **empty** if `x0 >= x1` or `y0 >= y1`. This \"\n\"implies, that **invalid rectangles are also always empty.** And `width` \"\n\"(resp. `height`) is **set to zero** if `x0 > x1` (resp. `y0 > y1`). In \"\n\"previous versions, a rectangle was empty only if one of width or height \"\n\"was zero.\"\nmsgstr \"\"\n\"矩形は、 `x0 >= x1`  または  `y0 >= y1`  の場合に **空** と呼ばれます。これは、**無効な矩形** \"\n\"も常に空であることを意味します。また、 `x0 > x1` （または `y0 > y1` ）の場合、幅（または高さ）は **ゼロに設定** \"\n\"されます。以前のバージョンでは、矩形が空であるのは幅または高さのいずれかがゼロの場合に限られていました。\"\n\n#: ../../rect.rst:28 6b8c92c5c94146e38742390553f50ad5\nmsgid \"\"\n\"Rectangle coordinates **cannot be outside** the number range from \"\n\"`FZ_MIN_INF_RECT = -2147483648` to `FZ_MAX_INF_RECT = 2147483520`. Both \"\n\"values have been chosen, because they are the smallest / largest 32bit \"\n\"integers that survive C float conversion roundtrips. In previous versions\"\n\" there was no limit for coordinate values.\"\nmsgstr \"\"\n\"矩形の座標は、`FZ_MIN_INF_RECT = -2147483648` から `FZ_MAX_INF_RECT = 2147483520`\"\n\"  \"\n\"までの数値範囲内にある必要があります。これらの値は、C浮動小数点変換のラウンドトリップを生き残る最小/最大の32ビット整数であるため選ばれました。以前のバージョンでは、座標値の制限はありませんでした。\"\n\n#: ../../rect.rst:30 f7c36d56736842c7b5057e7ce77215f1\nmsgid \"\"\n\"There is **exactly one \\\"infinite\\\" rectangle**, defined by `x0 = y0 = \"\n\"FZ_MIN_INF_RECT` and `x1 = y1 = FZ_MAX_INF_RECT`. It contains every other\"\n\" rectangle. It is mainly used for technical purposes -- e.g. when a \"\n\"function call should ignore a formally required rectangle argument. This \"\n\"rectangle is not empty.\"\nmsgstr \"\"\n\"**「無限」の矩形は** 、`x0 = y0 = FZ_MIN_INF_RECT` および `x1 = y1 = FZ_MAX_INF_RECT`\"\n\" \"\n\"で定義され、他のすべての矩形を含みます。これは主に技術的な目的で使用されます。たとえば、関数呼び出しで形式的に必要な矩形引数を無視する必要がある場合などです。この矩形は空ではありません。\"\n\n#: ../../rect.rst:32 3fd9c878f8a345649eececf661fa6d0d\nmsgid \"\"\n\"**Rectangles are (semi-) open:** The right and the bottom edges \"\n\"(including the resp. corners) are not considered part of the rectangle. \"\n\"This implies, that only the top-left corner `(x0, y0)` can ever belong to\"\n\" the rectangle - the other three corners never do. An empty rectangle \"\n\"contains no corners at all.\"\nmsgstr \"\"\n\"**矩形は（半）開いています**。右側と下側のエッジ（およびそれに含まれるコーナー）は矩形の一部とは見なされません。したがって、矩形に属することができるのは左上のコーナー\"\n\"  `(x0, y0)` のみです。他の3つのコーナーは常に含まれません。空の矩形にはまったくコーナーが含まれていません。\"\n\n#: ../../rect.rst:38 e57daedf444e46e1b812656ca7832537\nmsgid \"Here is an overview of the changes.\"\nmsgstr \"以下は変更の概要です。\"\n\n#: ../../rect.rst:41 d393f3a6d9de4c8fa2e06182c5f78760\nmsgid \"Notion\"\nmsgstr \"概要\"\n\n#: ../../rect.rst:41 d97438c124b14f35aa198e1ddfb8cfd0\nmsgid \"Versions < 1.19.0\"\nmsgstr \"バージョン < 1.19.0\"\n\n#: ../../rect.rst:41 7af7abdfb7bc4aa4b28ed21073d90bea\nmsgid \"Versions 1.19.*\"\nmsgstr \"バージョン 1.19.*\"\n\n#: ../../rect.rst:43 e4224c064e3f4f68bbb16f57e9a1c844\nmsgid \"empty\"\nmsgstr \"空\"\n\n#: ../../rect.rst:43 48dde36927434fceacc3a177956672c7\nmsgid \"x0 = x1 or y0 = y1\"\nmsgstr \"x0 = x1 または y0 = y1\"\n\n#: ../../rect.rst:43 3835fcc0738d40929f1271a1c05290b9\nmsgid \"x0 >= x1 or y0 >= y1 -- includes invalid rects\"\nmsgstr \"x0 >= x1 または y0 >= y1 – 無効な矩形も含む\"\n\n#: ../../rect.rst:44 f6c28fec698849cf9309e6c849791287\nmsgid \"valid\"\nmsgstr \"有効\"\n\n#: ../../rect.rst:44 754108a5de3646168f6a70e07a111bd9\nmsgid \"n/a\"\nmsgstr \"なし\"\n\n#: ../../rect.rst:44 e09f640fd0134a039d61766e33a9c329\nmsgid \"x0 <= x1 and y0 <= y1\"\nmsgstr \"x0 <= x1 かつ y0 <= y1\"\n\n#: ../../rect.rst:45 17a59c383cd546c8adfe6a7d8ef48da9\nmsgid \"infinite\"\nmsgstr \"無限\"\n\n#: ../../rect.rst:45 65113a7b423f4f98b9ce9fcada710d50\nmsgid \"all rects where x0 > x1 or y1 > y0\"\nmsgstr \"x0 > x1 または y1 > y0 のすべての矩形\"\n\n#: ../../rect.rst:45 41c40bda2ada47e085b2f7f2004a8b76\nmsgid \"**exactly one infinite rect / irect!**\"\nmsgstr \"**無限の矩形 / irectは1つだけです！**\"\n\n#: ../../rect.rst:46 4f4ac3d83ad64ebba6176c33b68c4cb3\nmsgid \"coordinate values\"\nmsgstr \"座標値\"\n\n#: ../../rect.rst:46 453a3c51c1434dc5b1579f747187deb0\nmsgid \"all numbers\"\nmsgstr \"すべての数値\"\n\n#: ../../rect.rst:46 4ca5d71efdb04d8693a83e57697d9d37\nmsgid \"`FZ_MIN_INF_RECT <= number <= FZ_MAX_INF_RECT`\"\nmsgstr \"FZ_MIN_INF_RECT <= 数値 <= FZ_MAX_INF_RECT\"\n\n#: ../../rect.rst:47 2209987532a249858e55c63d07e52b9c\nmsgid \"borders, corners\"\nmsgstr \"境界、コーナー\"\n\n#: ../../rect.rst:47 b6ae01c480064de9b11987d6892db4ca\nmsgid \"are parts of the rectangle\"\nmsgstr \"矩形の一部です\"\n\n#: ../../rect.rst:47 8ef673ab0bbc4257baaeffbe19220f28\nmsgid \"right and bottom corners and edges **are outside**\"\nmsgstr \"右下の角とエッジは **外側にあります**\"\n\n#: ../../rect.rst:50 e3e932700fd949daa0353b543c8a1a4c\nmsgid \"\"\n\"There are new top level functions defining infinite and standard empty \"\n\"rectangles and quads, see :meth:`INFINITE_RECT` and friends.\"\nmsgstr \"\"\n\"新しいトップレベルの関数が追加され、無限と標準の空の四角形および四角形を定義します。:meth:`INFINITE_RECT` \"\n\"などを参照してください。\"\n\n#: ../../rect.rst:54 81a610b0aa1f472b8ae9fea35a2a2c01\nmsgid \"**Methods / Attributes**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../rect.rst:54 4ed08c7116224212b88dc25acd42d0b0\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../rect.rst:56 5981a119a05e4daa876289ac03fc5a13\nmsgid \":meth:`Rect.contains`\"\nmsgstr \"\"\n\n#: ../../rect.rst:56 3b511deb4033483dbea1c5c304c2ec6f\nmsgid \"checks containment of point_likes and rect_likes\"\nmsgstr \"point_likesおよびrect_likesの包含をチェックします。\"\n\n#: ../../rect.rst:57 9f5f335e79444316a8a3c6dea665cf95\nmsgid \":meth:`Rect.get_area`\"\nmsgstr \"\"\n\n#: ../../rect.rst:57 1de8d41280804dcf9822b29195cfe5fe\nmsgid \"calculate rectangle area\"\nmsgstr \"四角形の面積を計算します。\"\n\n#: ../../rect.rst:58 7a22090e4a0d467a8ad2400c55ed9f2f\nmsgid \":meth:`Rect.include_point`\"\nmsgstr \"\"\n\n#: ../../rect.rst:58 0526b2070f7e45feab7a311c9ee31128\nmsgid \"enlarge rectangle to also contain a point\"\nmsgstr \"点も含むように四角形を拡大します。\"\n\n#: ../../rect.rst:59 5d2792546865489e8ac28d97886676fb\nmsgid \":meth:`Rect.include_rect`\"\nmsgstr \"\"\n\n#: ../../rect.rst:59 d9b74ad40df64c1da33f10578102b172\nmsgid \"enlarge rectangle to also contain another one\"\nmsgstr \"別の四角形も含むように四角形を拡大します。\"\n\n#: ../../rect.rst:60 a084869227454408971a27d515578280\nmsgid \":meth:`Rect.intersect`\"\nmsgstr \"\"\n\n#: ../../rect.rst:60 fc0d24eaf262443a9767ab3a639a91cf\nmsgid \"common part with another rectangle\"\nmsgstr \"別の四角形との共通部分です。\"\n\n#: ../../rect.rst:61 783c6bb9f98a4c9a9173a33426e15261\nmsgid \":meth:`Rect.intersects`\"\nmsgstr \"\"\n\n#: ../../rect.rst:61 48c32f08f9bd4fcaba35388fa46ffb7d\nmsgid \"checks for non-empty intersections\"\nmsgstr \"非空の交差をチェックします。\"\n\n#: ../../rect.rst:62 54b41e15307745659f567a94fe69654b\nmsgid \":meth:`Rect.morph`\"\nmsgstr \"\"\n\n#: ../../rect.rst:62 2724138758314afea0cd2a6f82c22cdd\nmsgid \"transform with a point and a matrix\"\nmsgstr \"点と行列を使用して四角形を変形します。\"\n\n#: ../../rect.rst:63 fa29117650a04cf992bfbf167039b34d\nmsgid \":meth:`Rect.torect`\"\nmsgstr \"\"\n\n#: ../../rect.rst:63 a1b856036d3a4a869c4bfef61e84bc7d\nmsgid \"the matrix that transforms to another rectangle\"\nmsgstr \"別の四角形に変換する行列です。\"\n\n#: ../../rect.rst:64 eb541dbc3c38455b94ddf221f6366d80\nmsgid \":meth:`Rect.norm`\"\nmsgstr \"\"\n\n#: ../../rect.rst:64 61a0e738f2784973be15065b6e9b3bf2\nmsgid \"the Euclidean norm\"\nmsgstr \"ユークリッドノルム\"\n\n#: ../../rect.rst:65 e9cec2f1207b4e358bcb22df6331bb76\nmsgid \":meth:`Rect.normalize`\"\nmsgstr \"\"\n\n#: ../../rect.rst:65 8ba545c6dd824fd08fd072a2c568c6db\nmsgid \"makes a rectangle valid\"\nmsgstr \"四角形を有効にします\"\n\n#: ../../rect.rst:66 ebfc99cce7a74afabc7adf051e9804cc\nmsgid \":meth:`Rect.round`\"\nmsgstr \"\"\n\n#: ../../rect.rst:66 a5ff1b1dfaf54324b20c6908d06f2c7e\nmsgid \"create smallest :ref:`Irect` containing rectangle\"\nmsgstr \"最小の :ref:`Irect` を含む四角形を作成します。\"\n\n#: ../../rect.rst:67 9c630cfbce96430dbd549ce3edbf5de2\nmsgid \":meth:`Rect.transform`\"\nmsgstr \"\"\n\n#: ../../rect.rst:67 3294ada857004ea2801a93dcdcae9cbb\nmsgid \"transform rectangle with a matrix\"\nmsgstr \"行列で四角形を変形します。\"\n\n#: ../../rect.rst:68 00f6aca11ba74d9290a39ae6e4d9abdb\nmsgid \":attr:`Rect.bottom_left`\"\nmsgstr \"\"\n\n#: ../../rect.rst:68 d8d4c9d808554a389d40caa0c16d5a69\nmsgid \"bottom left point, synonym *bl*\"\nmsgstr \"左下の点、シノニム *bl*\"\n\n#: ../../rect.rst:69 82732f58f72f413b869e3dbe3fc017dd\nmsgid \":attr:`Rect.bottom_right`\"\nmsgstr \"\"\n\n#: ../../rect.rst:69 25213177c72349529fffc2b8650278c6\nmsgid \"bottom right point, synonym *br*\"\nmsgstr \"右下の点、シノニム *br*\"\n\n#: ../../rect.rst:70 dee76b0bf2084300ae141c9fc27008bb\nmsgid \":attr:`Rect.height`\"\nmsgstr \"\"\n\n#: ../../rect.rst:70 7fec492b654e4a6c8f203435ebdcb0e3\nmsgid \"rectangle height\"\nmsgstr \"四角形の高さ\"\n\n#: ../../rect.rst:71 948cec288c54453aa28f00e584acce0b\nmsgid \":attr:`Rect.irect`\"\nmsgstr \"\"\n\n#: ../../rect.rst:71 a1899a79673d49c5a4273f091b474322\nmsgid \"equals result of method *round()*\"\nmsgstr \"*round()* メソッドの結果と等しい\"\n\n#: ../../rect.rst:72 d60c028c8e234efe9a338e184bb6bc55\nmsgid \":attr:`Rect.is_empty`\"\nmsgstr \"\"\n\n#: ../../rect.rst:72 95f758bc9cc644d6a61e703bee39b954\nmsgid \"whether rectangle is empty\"\nmsgstr \"四角形が空かどうか\"\n\n#: ../../rect.rst:73 3d96f5aae5a54e4eac8a41dc8027ebe2\nmsgid \":attr:`Rect.is_valid`\"\nmsgstr \"\"\n\n#: ../../rect.rst:73 0d07626ab6d5457c93ed36d852fe9dc5\nmsgid \"whether rectangle is valid\"\nmsgstr \"四角形が有効かどうか\"\n\n#: ../../rect.rst:74 ec6784767db149e1af2d3bed517a3154\nmsgid \":attr:`Rect.is_infinite`\"\nmsgstr \"\"\n\n#: ../../rect.rst:74 e2775e5155c94511a9a0b4351aa5aeed\nmsgid \"whether rectangle is infinite\"\nmsgstr \"四角形が無限かどうか\"\n\n#: ../../rect.rst:75 27198e6de32c47129ff1d90e9bcd052b\nmsgid \":attr:`Rect.top_left`\"\nmsgstr \"\"\n\n#: ../../rect.rst:75 991fbeb519074c779da08190535db4a5\nmsgid \"top left point, synonym *tl*\"\nmsgstr \"左上の点、シノニム *tl*\"\n\n#: ../../rect.rst:76 ee1026c3112e4ce5ace785e6dbd51983\nmsgid \":attr:`Rect.top_right`\"\nmsgstr \"\"\n\n#: ../../rect.rst:76 a429e926fb354c3eacca067673ad17f3\nmsgid \"top_right point, synonym *tr*\"\nmsgstr \"右上の点、シノニム *tr*\"\n\n#: ../../rect.rst:77 5a5eef69cfdd4fc1b267e64d1899c83d\nmsgid \":attr:`Rect.quad`\"\nmsgstr \"\"\n\n#: ../../rect.rst:77 39bf27b7ec18496996041d704db52fa2\nmsgid \":ref:`Quad` made from rectangle corners\"\nmsgstr \"四角形の角から作成される :ref:`Quad`\"\n\n#: ../../rect.rst:78 b77feb74e6d84afe86da1aa9ffd1d688\nmsgid \":attr:`Rect.width`\"\nmsgstr \"\"\n\n#: ../../rect.rst:78 ba35625a52bb44278539861d0133f079\nmsgid \"rectangle width\"\nmsgstr \"四角形の幅\"\n\n#: ../../rect.rst:79 38859d042e6f49b88c35544ec6e4ed3c\nmsgid \":attr:`Rect.x0`\"\nmsgstr \"\"\n\n#: ../../rect.rst:79 7e53ad8c6a824feca26905c64f3e0ea3\nmsgid \"left corners' x coordinate\"\nmsgstr \"左上のx座標\"\n\n#: ../../rect.rst:80 f4f68e6053a840c2a566cf242d7f05b1\nmsgid \":attr:`Rect.x1`\"\nmsgstr \"\"\n\n#: ../../rect.rst:80 b53b5091498c454d88765a544d585de5\nmsgid \"right corners' x -coordinate\"\nmsgstr \"右上のx座標\"\n\n#: ../../rect.rst:81 91c7514c010f464098de9b6e9007f4a8\nmsgid \":attr:`Rect.y0`\"\nmsgstr \"\"\n\n#: ../../rect.rst:81 119b6bb77d59497fa78ea76552d86acd\nmsgid \"top corners' y coordinate\"\nmsgstr \"上部のy座標\"\n\n#: ../../rect.rst:82 45436c8c00564776b422a0208c48ae3d\nmsgid \":attr:`Rect.y1`\"\nmsgstr \"\"\n\n#: ../../rect.rst:82 251741ae294247ddadf61d053276d89f\nmsgid \"bottom corners' y coordinate\"\nmsgstr \"下部のy座標\"\n\n#: ../../rect.rst:85 d211a7b97cc54d93b48553a9425130b9\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../rect.rst:103 01827e33142142419f360c9f35834288\nmsgid \"\"\n\"Overloaded constructors: *top_left*, *bottom_right* stand for \"\n\":data:`point_like` objects, \\\"sequence\\\" is a Python sequence type of 4 \"\n\"numbers (see :ref:`SequenceTypes`), \\\"rect\\\" means another \"\n\":data:`rect_like`, while the other parameters mean coordinates.\"\nmsgstr \"\"\n\"オーバーロードされたコンストラクター：*top_left*、*bottom_right* は :data:`point_like` \"\n\"オブジェクトを表し、「sequence」は4つの数値からなるPythonシーケンス型です（:ref:`SequenceTypes` \"\n\"を参照）、rectは別の :data:`rect_like` を意味し、他のパラメーターは座標を意味します。\"\n\n#: ../../rect.rst:105 e075a06a3e264a5fbf6aea37d81f20d9\nmsgid \"If \\\"rect\\\" is specified, the constructor creates a **new copy** of it.\"\nmsgstr \"\\\"rect\\\" が指定されている場合、コンストラクターはそれの **新しいコピー** を作成します。\"\n\n#: ../../rect.rst:107 1f9d77ad703345a2a3964ae75caea048\n#, fuzzy\nmsgid \"\"\n\"Without parameters, the empty rectangle ``Rect(0.0, 0.0, 0.0, 0.0)`` is \"\n\"created.\"\nmsgstr \"パラメーターなしで、空の長方形 *Rect(0.0, 0.0, 0.0, 0.0)* が作成されます。\"\n\n#: ../../rect.rst:111 f10e380576a7412d80886a3b8a51700e\n#, fuzzy\nmsgid \"\"\n\"Creates the smallest containing :ref:`IRect`. This is **not the same** as\"\n\" simply rounding the rectangle's edges: The top left corner is rounded \"\n\"upwards and to the left while the bottom right corner is rounded \"\n\"downwards and to the right.\"\nmsgstr \"\"\n\"最小の :ref:`IRect` を作成します。これは単に長方形のエッジを四捨五入することとは \"\n\"**異なります**。左上のコーナーは上方向および左方向に丸められ、右下のコーナーは下方向および右方向に丸められます。\"\n\n#: ../../rect.rst:116 552d25bc341a48aba138b957a55b9e83\nmsgid \"If the rectangle is **empty**, the result is also empty.\"\nmsgstr \"もし矩形が空の場合、結果も **空** です。\"\n\n#: ../../rect.rst:117 df26f93d58284c6a970ae3863ef681bb\nmsgid \"\"\n\"**Possible paradox:** The result may be empty, **even if** the rectangle \"\n\"is **not** empty! In such cases, the result obviously does **not** \"\n\"contain the rectangle. This is because MuPDF's algorithm allows for a \"\n\"small tolerance (1e-3). Example:\"\nmsgstr \"\"\n\"**可能性のある逆説:** 矩形が空で **ない** 場合 **でも** 、結果が空になることがあります！このような場合、結果は明らかに矩形を \"\n\"**含みません**。これは、MuPDFのアルゴリズムがわずかな許容差（1e-3）を許容しているためです。例：\"\n\n#: ../../rect.rst 223b51190466453684b2185f3dfc69c0\n#: 297e474bcf4f49858a23f80dd7128c65 388342f8d94e4d26b238b48872bd5511\n#: 4f188f0a74b347a8ba82283a386abbde 6c7f84d51c1c4b3b9dcf69c73a6d6715\n#: 6f729bc4a8b948998da46a928feb54e6 96b897da73d141458d7b0fa47bb6846a\n#: f8ae67a6da5847d7838f6d57ffbba97e\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../rect.rst:127 31c287fef6e3445cafe94d866b5e73bf\nmsgid \":ref:`IRect`\"\nmsgstr \"\"\n\n#: ../../rect.rst:131 c8c2cfc194a8468fa9550492f440f872\nmsgid \"\"\n\"Transforms the rectangle with a matrix and **replaces the original**. If \"\n\"the rectangle is empty or infinite, this is a no-operation.\"\nmsgstr \"次の条件を満たす場合、行列を使用して長方形を変換し、**元の長方形を置き換えます** ：長方形が空であるか無限である場合、これは操作が行われません。\"\n\n#: ../../rect.rst 1769e651f3b64df78e388f49683edfc2\n#: 312414a60f5241d7abaee3b012e0c7f4 54d06860552f4fa4bf1e92782d2b517a\n#: aecbea35a63240b7bb02c03f083daacf d9b739a44f4b427b9772f8da4198b7b3\n#: dca5e2461b874ed6ac599ed5bf67591e dd42b3800611490e9091e6942a813e85\n#: e64ab107750d4908974794940a14b516 f9eb8fc37f314b86bb12b6037ad64aca\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../rect.rst:133 17bbbee58ca246578928bb7c3f404ef5\nmsgid \"The matrix for the transformation.\"\nmsgstr \"m（行列）–変換用の行列。\"\n\n#: ../../rect.rst:136 5b54b6fd35e047b9b19b8e92d649c886\nmsgid \"``Rect``\"\nmsgstr \"\"\n\n#: ../../rect.rst ad2d6666f58d4edab133c0b63812dad1\n#: ee287750d1ff4757a1f4aab28350cc3f f617b587a6e84a1d879ad6eb2a4b8163\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../rect.rst:137 9310c42c457243d2adf6a8ef7e65abb4\nmsgid \"the smallest rectangle that contains the transformed original.\"\nmsgstr \"変換された元の長方形を含む最小の長方形。\"\n\n#: ../../rect.rst:141 515fef48ca8a47adbebb14b402eb85f4\nmsgid \"\"\n\"The intersection (common rectangular area, largest rectangle contained in\"\n\" both) of the current rectangle and *r* is calculated and **replaces the \"\n\"current** rectangle. If either rectangle is empty, the result is also \"\n\"empty. If *r* is infinite, this is a no-operation. If the rectangles are \"\n\"(mathematically) disjoint sets, then the result is invalid. If the result\"\n\" is valid but empty, then the rectangles touch each other in a corner or \"\n\"(part of) a side.\"\nmsgstr \"\"\n\"現在の長方形とrの共通の長方形エリア（両方に含まれる最大の長方形）を計算し、**現在の長方形を置き換えます**。どちらかの長方形が空の場合、結果も空になります。*r*\"\n\" \"\n\"が無限である場合、これは操作が行われません。長方形が（数学的に）交差していない場合、結果は無効になります。結果が有効でも空の場合、長方形は互いに角または一部の側面に接触しています。\"\n\n#: ../../rect.rst:143 ../../rect.rst:150 5ae4d4eaacb44add974c0aa6cf33f6f8\n#: cb94768c038d40d6be30db81f8988f9e\nmsgid \"Second rectangle\"\nmsgstr \"第二の長方形\"\n\n#: ../../rect.rst:148 db7d498e829c4302919da10e026d8ac5\nmsgid \"\"\n\"The smallest rectangle containing the current one and ``r`` is calculated\"\n\" and **replaces the current** one. If either rectangle is infinite, the \"\n\"result is also infinite. If ``r`` is empty, the current rectangle remains\"\n\" unchanged. Else if the current rectangle is empty, it is replaced by \"\n\"``r``.\"\nmsgstr \"\"\n\n#: ../../rect.rst:155 d539db24271d4c00bd98e51fb2c3f2ab\nmsgid \"\"\n\"The smallest rectangle containing the current one and :data:`point_like` \"\n\"``p`` is calculated and **replaces the current** one. **The infinite \"\n\"rectangle remains unchanged.** To create the rectangle that wraps a \"\n\"sequence of points, start with :meth:`EMPTY_RECT` and successively \"\n\"include the members of the sequence.\"\nmsgstr \"\"\n\n#: ../../rect.rst:157 6a72290dd49345a0a63b3757d59663ca\nmsgid \"Point to include.\"\nmsgstr \"含めるポイント。\"\n\n#: ../../rect.rst:163 ba33391fc40040a4a994136d913ee366\nmsgid \"\"\n\"Calculate the area of the rectangle and, with no parameter, equals \"\n\"*abs(rect)*. Like an empty rectangle, the area of an infinite rectangle \"\n\"is also zero. So, at least one of *pymupdf.Rect(p1, p2)* and \"\n\"*pymupdf.Rect(p2, p1)* has a zero area.\"\nmsgstr \"\"\n\"長方形の面積を計算し、パラメーターなしで *abs（rect）* と同じです。空の長方形の面積はゼロであるため、少なくとも \"\n\"*pymupdf.Rect（p1、p2）* と *pymupdf.Rect（p2、p1）* のいずれかがゼロの面積を持っている必要があります。\"\n\n#: ../../rect.rst:165 6f367ec895b04a5282f232e658390010\nmsgid \"\"\n\"Specify required unit: respective squares of *px* (pixels, default), *in*\"\n\" (inches), *cm* (centimeters), or *mm* (millimeters).\"\nmsgstr \"\"\n\"必要な単位を指定します： *px* （ピクセル、デフォルト）の平方、*in* （インチ）、*cm* （センチメートル）、または *mm* \"\n\"（ミリメートル）の平方。\"\n\n#: ../../rect.rst:170 f1fdbdae13644bca9624eea1bed293ba\nmsgid \"\"\n\"Checks whether *x* is contained in the rectangle. It may be an *IRect*, \"\n\"*Rect*, *Point* or number. If *x* is an empty rectangle, this is always \"\n\"true. If the rectangle is empty this is always ``False`` for all non-\"\n\"empty rectangles and for all points. `x in rect` and `rect.contains(x)` \"\n\"are equivalent.\"\nmsgstr \"\"\n\"*x* が四角形内に含まれているかどうかをチェックします。xは *IRect*、*Rect*、*Point*、または数値のいずれかです。もし \"\n\"*x* \"\n\"が空の四角形である場合、これは常にtrueです。四角形が空である場合、これはすべての空でない四角形とすべてのポイントに対して常にfalseです。`x\"\n\" in rect` および `rect.contains(x)` は同等です。\"\n\n#: ../../rect.rst:172 ca3270a90eac40a4bbb2ec88e8547446\nmsgid \"the object to check.\"\nmsgstr \"チェックするオブジェクト。\"\n\n#: ../../rect.rst:179 a2c14b05b36d4decbe4367b3aa764e2f\nmsgid \"\"\n\"Checks whether the rectangle and a :data:`rect_like` \\\"r\\\" contain a \"\n\"common non-empty :ref:`Rect`. This will always be ``False`` if either is \"\n\"infinite or empty.\"\nmsgstr \"\"\n\"長方形と :data:`rect_like` \\\"r\\\" \"\n\"が共通の非空のRectを含むかどうかをチェックします。どちらかが無限または空の場合、これは常に ``False`` になります。\"\n\n#: ../../rect.rst:181 fd7c3c60afa7402f98f4d782416f106d\nmsgid \"the rectangle to check.\"\nmsgstr \"チェックする長方形。\"\n\n#: ../../rect.rst:187 a9fe2a547ab44768a39b47d8d9ef868e\nmsgid \"New in version 1.19.3\"\nmsgstr \"新機能（バージョン1.19.3）\"\n\n#: ../../rect.rst:189 d15a89c433be470288ee2017503a040f\nmsgid \"Compute the matrix which transforms this rectangle to a given one.\"\nmsgstr \"この長方形を指定した長方形に変換する行列を計算します。\"\n\n#: ../../rect.rst:191 7492eabbe7d24bdba52f9f8ead663bcd\nmsgid \"the target rectangle. Must not be empty or infinite.\"\nmsgstr \"ターゲットの長方形。空または無限であってはいけません。\"\n\n#: ../../rect.rst:192 1d5dde507c8b434e94689248050663f0\nmsgid \":ref:`Matrix`\"\nmsgstr \"\"\n\n#: ../../rect.rst:193 fc8cb54b6f794b9ca05b2b2fb57c5290\nmsgid \"\"\n\"a matrix `mat` such that `self * mat = rect`. Can for example be used to \"\n\"transform between the page and the pixmap coordinates. See an example use\"\n\" here :ref:`RecipesImages_P`.\"\nmsgstr \"\"\n\"`self * mat = rect` となるような行列 `mat` です。たとえば、ページとピクスマップの座標間を変換するのに使用できます。 \"\n\"使用例はこちらを参照してください :ref:`RecipesImages_P` \"\n\n#: ../../rect.rst:197 6bfb5ec48e4742898de3cb22ba429c99\nmsgid \"New in version 1.17.0\"\nmsgstr \"新機能バージョン1.17.0\"\n\n#: ../../rect.rst:199 33c676862f1241db9159e7a0b76a9f67\nmsgid \"\"\n\"Return a new quad after applying a matrix to the rectangle using the \"\n\"fixed point `fixpoint`.\"\nmsgstr \"固定点 `fixpoint` を使用して、行列を長方形に適用した後の新しい四角形を返します。\"\n\n#: ../../rect.rst:201 c4251e2f175d41d48a4e66ee81b8a2a0\nmsgid \"the fixed point.\"\nmsgstr \"固定ポイント。\"\n\n#: ../../rect.rst:202 3597e1c1f5d84296b016ca74793b5554\nmsgid \"the matrix.\"\nmsgstr \"行列。\"\n\n#: ../../rect.rst:203 e7dca746738f46ff95c1c3f83513868b\nmsgid \"\"\n\"a new :ref:`Quad`. This a wrapper for the same-named quad method. If \"\n\"infinite, the infinite quad is returned.\"\nmsgstr \"新しい :ref:`Quad` 。これは同じ名前の四角形メソッドのラッパーです。無限の場合、無限の四角形が返されます。\"\n\n#: ../../rect.rst:207 f0e8c79473044506bfc164d658cd0559\nmsgid \"New in version 1.16.0\"\nmsgstr \"新機能バージョン1.16.0\"\n\n#: ../../rect.rst:209 5675696559db481c8264784ff3dc7467\nmsgid \"\"\n\"Return the Euclidean norm of the rectangle treated as a vector of four \"\n\"numbers.\"\nmsgstr \"四角形を4つの数値のベクトルとして扱った場合のユークリッドノルムを返します。\"\n\n#: ../../rect.rst:213 d5b4c7b243b04370ad7717618f6af173\nmsgid \"\"\n\"**Replace** the rectangle with its valid version. This is done by \"\n\"shuffling the rectangle corners. After completion of this method, the \"\n\"bottom right corner will indeed be south-eastern to the top left one (but\"\n\" may still be empty).\"\nmsgstr \"\"\n\"長方形をその有効なバージョンで \"\n\"**置き換えます**。これは長方形のコーナーをシャッフルして行います。このメソッドの完了後、右下のコーナーは確かに左上のコーナーの南東になります（ただし、空である可能性があります）。\"\n\n#: ../../rect.rst:217 55f5202f243c431cb4a6aae82d228176\nmsgid \"Equals result of method *round()*.\"\nmsgstr \"*round()* メソッドの結果と同じです。\"\n\n#: ../../rect.rst:223 8ce16ab6c7df44f5abb8f92883c8d5c5\nmsgid \"Equals *Point(x0, y0)*.\"\nmsgstr \"*Point(x0, y0)* と等しい。\"\n\n#: ../../rect.rst 140ba1c8d224453686c608739d150b66\n#: 17b10802a6f2405c86d6e263e499d22f 5444bac90c254f1c84d6fe7c0e28890d\n#: 5bacf55f6fdc41e0a4eaecf91679d95d 5e0076fec68344b9b5094a29a7778e51\n#: 6362dacd20114c8e8d8beda49463e502 7bdb41b9074b4fe8b70f89b3feb982f8\n#: 8b32b0a8f85c488f8622250501ee942a 9ebaad019109481ebcf4ddd743d67f01\n#: d8d182de61d74096abf1ed76f13825b2 dd68eb47fe4f425fb08826a909877002\n#: f6c692b144934eb0ba0bbce5f99825bf\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../rect.rst:225 ../../rect.rst:233 ../../rect.rst:241 ../../rect.rst:249\n#: 3bb0a2aad0b34e11b52697850a333f20 403eb084f6f64eb590a9e0627f324bc1\n#: 8690457d8ba940b09ec2249670a3ef5b 93767b206e804fd582e4db28c1eb3219\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../rect.rst:231 62f995500f554a04a83c5d7392c75231\nmsgid \"Equals `Point(x1, y0)`.\"\nmsgstr \"`Point(x1, y0)` と等しい。\"\n\n#: ../../rect.rst:239 4b524e88114c4a3d9795ac77e101aac6\nmsgid \"Equals `Point(x0, y1)`.\"\nmsgstr \"`Point(x0, y1)` と等しい。\"\n\n#: ../../rect.rst:247 c781f4a98d33484a8fd5eeb72de6719e\nmsgid \"Equals `Point(x1, y1)`.\"\nmsgstr \"\"\n\n#: ../../rect.rst:253 4fdbb1259b894b85abf811e41bf30f7f\nmsgid \"The quadrilateral `Quad(rect.tl, rect.tr, rect.bl, rect.br)`.\"\nmsgstr \"四角形 `Quad(rect.tl, rect.tr, rect.bl, rect.br)`。\"\n\n#: ../../rect.rst:255 a29713ba4e8a43c290093038d033627b\nmsgid \":ref:`Quad`\"\nmsgstr \"\"\n\n#: ../../rect.rst:259 a19815eed800437580d69960abffb442\nmsgid \"Width of the rectangle. Equals `max(x1 - x0, 0)`.\"\nmsgstr \"長方形の幅。`max(x1 - x0, 0)` と等しい。\"\n\n#: ../../rect.rst:265 19c9fc7532244739bb242fc281fe9ab4\nmsgid \"Height of the rectangle. Equals `max(y1 - y0, 0)`.\"\nmsgstr \"長方形の高さ。`max(y1 - y0, 0)` と等しい。\"\n\n#: ../../rect.rst:271 e9d9d68a615844588179b0a9c4ddb63d\nmsgid \"X-coordinate of the left corners.\"\nmsgstr \"左上の x 座標。\"\n\n#: ../../rect.rst:273 ../../rect.rst:279 ../../rect.rst:285 ../../rect.rst:291\n#: 3159fff4ace944f5b28b66c85c40a391 595d30cddc2441798812da3e6aa60405\n#: 7d4d519c37524ecd93c59a92f14a52ee c3f30ece20574d289dd0729b1555cb67\nmsgid \"float\"\nmsgstr \"\"\n\n#: ../../rect.rst:277 ef85ef105e694e3faab5ca56c0e0eecb\nmsgid \"Y-coordinate of the top corners.\"\nmsgstr \"左上の y 座標。\"\n\n#: ../../rect.rst:283 01de9b8a52134ea9893026eb6219e2ed\nmsgid \"X-coordinate of the right corners.\"\nmsgstr \"右下の x 座標。\"\n\n#: ../../rect.rst:289 0324e83243014e8facb3691297c10edd\nmsgid \"Y-coordinate of the bottom corners.\"\nmsgstr \"右下の y 座標。\"\n\n#: ../../rect.rst:295 63c3980c456449ab98ca919497d7ee18\nmsgid \"`True` if this is the infinite rectangle.\"\nmsgstr \"これが無限の長方形の場合は `True`。\"\n\n#: ../../rect.rst:297 ../../rect.rst:303 ../../rect.rst:309\n#: 84e580180c7c4388939f1b2876f6eb67 9aaf58f7198848dc9acfe4b42c84ad6f\n#: b9b7f26129e94195801107367cb7fbcc\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../rect.rst:301 18ecd70d16ed40779b23464233b589ed\nmsgid \"`True` if rectangle is empty.\"\nmsgstr \"これが無限の長方形である場合は `True`。\"\n\n#: ../../rect.rst:307 472d89b6e5324c3487cd59bb9818711c\nmsgid \"`True` if rectangle is valid.\"\nmsgstr \"長方形が空である場合は `True`。\"\n\n#: ../../rect.rst:313 9531f9684b3d4fe5add3912c57ef0e6a\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"\"\n\"このクラスはPythonのシーケンスプロトコルに従っており、要素にはインデックスを使用できます。Using Python Sequences as\"\n\" Arguments in PyMuPDFも参照してください\"\n\n#: ../../rect.rst:314 a8f439886c4540a88cfb3aa32cee5363\nmsgid \"\"\n\"Rectangles can be used with arithmetic operators -- see chapter \"\n\":ref:`Algebra`.\"\nmsgstr \"四角形は算術演算子と組み合わせて使用できます - :ref:`Algebra` の演算子代数の章を参照してください。\"\n\n#: ../../footer.rst:46 7bc9c45a377e4124a0eb39872343423a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"The smallest rectangle containing the \"\n#~ \"current one and *r* is calculated \"\n#~ \"and **replaces the current** one. If \"\n#~ \"either rectangle is infinite, the result\"\n#~ \" is also infinite. If one is \"\n#~ \"empty, the other one will be taken\"\n#~ \" as the result.\"\n#~ msgstr \"\"\n#~ \"現在の長方形と *r* \"\n#~ \"を含む最小の長方形を計算し、**現在の長方形を置き換えます**。どちらかの長方形が無限の場合、結果も無限になります。1つが空である場合、もう1つが結果として取られます。\"\n\n#~ msgid \"\"\n#~ \"The smallest rectangle containing the \"\n#~ \"current one and point *p* is \"\n#~ \"calculated and **replaces the current** \"\n#~ \"one. **The infinite rectangle remains \"\n#~ \"unchanged.** To create a rectangle \"\n#~ \"containing a series of points, start \"\n#~ \"with (the empty) *pymupdf.Rect(p1, p1)* \"\n#~ \"and successively include the remaining \"\n#~ \"points.\"\n#~ msgstr \"\"\n#~ \"現在の長方形と点 *p* \"\n#~ \"を含む最小の長方形を計算し、**現在の長方形を置き換えます**。無限の長方形は変更されません。一連の点を含む長方形を作成するには、（空の）\"\n#~ \" *pymupdf.Rect(p1, p1)* から始め、残りの点を順次含めてください。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"*Rect*\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/resources.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.2\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 32a5d41df1df459eb1e9d04ab26ae6e9\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 f853d94bef1043f19d324049bb6fc247\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDFは、PDF（およびその他）ドキュメントのデータ抽出、分析、変換、および操作のための高性能なPythonライブラリです。\"\n\n#: ../../header.rst:-1 ee9fba5239104891a698642d810eda59\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFのテキスト抽出、PDFの画像抽出、PDFの変換、PDFのテーブル、PDFの分割、PDFの作成、Pyodide、PyScript\"\n\n#: ../../resources.rst:6 50c78b642e87465bab2c3916355a95a0\nmsgid \"Resources\"\nmsgstr \"リソース\"\n\n#: ../../resources.rst:9 4ff3e7104cb64db5af2a616677e85c6e\nmsgid \"**PyMuPDF Pro**\"\nmsgstr \"\"\n\n#: ../../resources.rst:12 08c45bb03e394054bea50f41ce8a06d0\nmsgid \"For **Office** file support `try PyMuPDF Pro <pymupdf-pro>`.\"\nmsgstr \"**Office** ファイルのサポートには、`PyMuPDF Pro <pymupdf-pro>` をお試しください。\"\n\n#: ../../resources.rst:20 5af5e4a006674fbf9c2bb32995565bc2\nmsgid \"Find out about **PyMuPDF Utilities**\"\nmsgstr \"**PyMuPDFユーティリティ** について調べる\"\n\n#: ../../resources.rst:22 9107d5d9ff12463c8aaa340fe660b894\nmsgid \"\"\n\"The :title:`GitHub` repository `PyMuPDF-Utilities \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities>`_ contains a full range of\"\n\" examples, demonstrations and use cases.\"\nmsgstr \"\"\n\":title:`GitHub` リポジトリ `PyMuPDF-Utilities <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities>`_ には、豊富な例、デモ、およびユースケースが含まれています。\"\n\n#: ../../resources.rst:31 661997d9b5904871afc832b5d106ec7e\nmsgid \"Do you need |PDF| to **DOCX** conversion?\"\nmsgstr \"|PDF| を **DOCX** に変換する必要がありますか？\"\n\n#: ../../resources.rst:33 4d1c4a0b38be4825a6719886af0641bf\nmsgid \"\"\n\"We recommend the pdf2docx_ library which uses |PyMuPDF| and the **python-\"\n\"docx** library to provide simple document conversion from |PDF| to \"\n\"**DOCX** format.\"\nmsgstr \"\"\n\"pdf2docx_ ライブラリをお勧めします。これは、|PDF| から **DOCX** 形式への簡単なドキュメント変換を提供するために \"\n\"|PyMuPDF| と **python-docx** ライブラリを使用しています。\"\n\n#: ../../footer.rst:60 bd4e8b3283ae4bb3b28a33df47889855\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは、|version| までのすべてのバージョンをカバーしています\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/shape.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7909b1fec71a4bb1918715ca5918f604\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 87466d36d4244b14b06775988b5a86da\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 c4e019a1ef45475794222706f39fa6bd\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../shape.rst:6 a9435293f59542b2850588abf5b6a5c0\nmsgid \"Shape\"\nmsgstr \"Shape（シェイプ）\"\n\n#: ../../shape.rst:8 c22618002fb44404a4ac660d7663c2a9\nmsgid \"|pdf_only_class|\"\nmsgstr \"\"\n\n#: ../../shape.rst:10 83f7ae44343b4e29b36be26c67c582a7\nmsgid \"\"\n\"This class allows creating interconnected graphical elements on a PDF \"\n\"page. Its methods have the same meaning and name as the corresponding \"\n\":ref:`Page` methods.\"\nmsgstr \"\"\n\"このクラスは、PDFページ上で相互に接続されたグラフィカル要素を作成できるようにします。このクラスのメソッドは、対応する :ref:`Page` \"\n\"クラスのメソッドと同じ意味と名前を持っています。\"\n\n#: ../../shape.rst:12 1687c125d94c4a889d4123d18b33a654\nmsgid \"\"\n\"In fact, each :ref:`Page` draw method is just a convenience wrapper for \"\n\"(1) one shape draw method, (2) the :meth:`Shape.finish` method, and (3) \"\n\"the :meth:`Shape.commit` method. For page text insertion, only the \"\n\":meth:`Shape.commit` method is invoked. If many draw and text operations \"\n\"are executed for a page, you should always consider using a Shape object.\"\nmsgstr \"\"\n\"実際には、各 :ref:`Page` クラスの描画メソッドは、（1）シェイプの描画メソッド、（2） :meth:`Shape.finish`  \"\n\"メソッド、（3） :meth:`Shape.commit`  \"\n\"メソッドの3つの要素の便利なラッパーです。ページテキストの挿入に関しては、:meth:`Shape.commit` \"\n\"メソッドのみが呼び出されます。ページで多くの描画およびテキスト操作を実行する場合、常にShapeオブジェクトの使用を検討することをお勧めします。\"\n\n#: ../../shape.rst:14 61eb314053054e4e9a36e36845c74ae6\nmsgid \"\"\n\"Several draw methods can be executed in a row and each one of them will \"\n\"contribute to one drawing. Once the drawing is complete, the \"\n\":meth:`Shape.finish` method must be invoked to apply color, dashing, \"\n\"width, morphing and other attributes.\"\nmsgstr \"\"\n\"このクラスのいくつかの描画メソッドは、連続して実行でき、それぞれが1つの描画に貢献します。描画が完了したら、:meth:`Shape.finish`\"\n\" メソッドを呼び出して色、破線、幅、変形などの属性を適用する必要があります。\"\n\n#: ../../shape.rst:16 f3481ff5d87c41998cb0f7de7874cbee\nmsgid \"\"\n\"**Draw** methods of this class (and :meth:`Shape.insert_textbox`) are \"\n\"logging the area they are covering in a rectangle (:attr:`Shape.rect`). \"\n\"This property can for instance be used to set \"\n\":attr:`Page.cropbox_position`.\"\nmsgstr \"\"\n\"このクラスの **描画** メソッド（および :meth:`Shape.insert_textbox` ）は、カバーしている領域を矩形 \"\n\"(:attr:`Shape.rect`)で記録します。このプロパティは、:attr:`Page.cropbox_position` \"\n\"を設定するために使用できます。\"\n\n#: ../../shape.rst:18 93fc8032a8144e439538867e5d7d9ff1\nmsgid \"\"\n\"**Text insertions** :meth:`Shape.insert_text` and \"\n\":meth:`Shape.insert_textbox` implicitly execute a \\\"finish\\\" and \"\n\"therefore only require :meth:`Shape.commit` to become effective. As a \"\n\"consequence, both include parameters for controlling properties like \"\n\"colors, etc.\"\nmsgstr \"\"\n\"**テキストの挿入** 操作である :meth:`Shape.insert_text` および \"\n\":meth:`Shape.insert_textbox` は、暗黙的に「finish」を実行し、効果を発揮するために \"\n\":meth:`Shape.commit` \"\n\"のみが必要です。その結果、両方のメソッドには色などのプロパティを制御するためのパラメータが含まれています。\"\n\n#: ../../shape.rst:21 7753ef6a86874229bc626bf090e7fd68\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../shape.rst:21 21306cc0a07a4be8b729f6d593a2a25e\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../shape.rst:23 76875c2923b44844919d4f7dbc4ff2ae\nmsgid \":meth:`Shape.commit`\"\nmsgstr \"\"\n\n#: ../../shape.rst:23 b6e101dde14a4c0399c2d1e32dfae0e3\nmsgid \"update the page's contents\"\nmsgstr \"ページの内容を更新します\"\n\n#: ../../shape.rst:24 68e32b027b2a42519c263a5d79f0aca5\nmsgid \":meth:`Shape.draw_bezier`\"\nmsgstr \"\"\n\n#: ../../shape.rst:24 cfd73fa2818546d897d3cc7dbf43cb7f\nmsgid \"draw a cubic Bezier curve\"\nmsgstr \"キュービックベジエ曲線を描画します\"\n\n#: ../../shape.rst:25 4f7b9a227586442b8c80cfc50bb5d2f6\nmsgid \":meth:`Shape.draw_circle`\"\nmsgstr \"\"\n\n#: ../../shape.rst:25 9f885ddec57646dc9618b9b296ef806e\nmsgid \"draw a circle around a point\"\nmsgstr \"指定した点を中心に円を描画します\"\n\n#: ../../shape.rst:26 aa0ac0a299bb4cacbdb189b821d1057f\nmsgid \":meth:`Shape.draw_curve`\"\nmsgstr \"\"\n\n#: ../../shape.rst:26 444333668308404a995780c7c2ffd1e8\nmsgid \"draw a cubic Bezier using one helper point\"\nmsgstr \"ヘルパーポイントを使用してキュービックベジエ曲線を描画します\"\n\n#: ../../shape.rst:27 1b7d6cc35258460398a82cc2ea5f5017\nmsgid \":meth:`Shape.draw_line`\"\nmsgstr \"\"\n\n#: ../../shape.rst:27 0a76a1b23d26472bb46eaef1b0b11d37\nmsgid \"draw a line\"\nmsgstr \"直線を描画します\"\n\n#: ../../shape.rst:28 eea95a7b69df4cc6a775a0d4015d87f5\nmsgid \":meth:`Shape.draw_oval`\"\nmsgstr \"\"\n\n#: ../../shape.rst:28 34529e37e99440538218de68e175f373\nmsgid \"draw an ellipse\"\nmsgstr \"楕円を描画します\"\n\n#: ../../shape.rst:29 8817f8a373594a85a5b96f2658e31d98\nmsgid \":meth:`Shape.draw_polyline`\"\nmsgstr \"\"\n\n#: ../../shape.rst:29 3b98bc2fd12c456c8a2410d43daa8912\nmsgid \"connect a sequence of points\"\nmsgstr \"一連の点を接続します\"\n\n#: ../../shape.rst:30 4022cf63cc3a496696d3f62c0a2805ab\nmsgid \":meth:`Shape.draw_quad`\"\nmsgstr \"\"\n\n#: ../../shape.rst:30 bde0f7baa3e145cda4e9d029099dda80\nmsgid \"draw a quadrilateral\"\nmsgstr \"四角形を描画します\"\n\n#: ../../shape.rst:31 c4addcda29c140a6b1975890737ead18\nmsgid \":meth:`Shape.draw_rect`\"\nmsgstr \"\"\n\n#: ../../shape.rst:31 2b173978a5c64357ac1aabcc6e976c73\nmsgid \"draw a rectangle\"\nmsgstr \"長方形を描画します\"\n\n#: ../../shape.rst:32 7f7f34efc2e944109b6c07df81c75430\nmsgid \":meth:`Shape.draw_sector`\"\nmsgstr \"\"\n\n#: ../../shape.rst:32 d5d4937a74fb42b7b20852638b500044\nmsgid \"draw a circular sector or piece of pie\"\nmsgstr \"円形セクターまたはパイの一部を描画します\"\n\n#: ../../shape.rst:33 880b0c8a153e48fdaa1029e9be76e520\nmsgid \":meth:`Shape.draw_squiggle`\"\nmsgstr \"\"\n\n#: ../../shape.rst:33 da68180d030a4b1fb309de94d47743b1\nmsgid \"draw a squiggly line\"\nmsgstr \"波線を描画します\"\n\n#: ../../shape.rst:34 9fe45650af3d4e0ca97f2b9d25d87789\nmsgid \":meth:`Shape.draw_zigzag`\"\nmsgstr \"\"\n\n#: ../../shape.rst:34 63c2fdb3045d4b81ae22677572e74fbe\nmsgid \"draw a zigzag line\"\nmsgstr \"ジグザグ線を描画します\"\n\n#: ../../shape.rst:35 c22ba5f6783649118106601684861498\nmsgid \":meth:`Shape.finish`\"\nmsgstr \"\"\n\n#: ../../shape.rst:35 7c247cc071c04f4383953864f5d543ee\nmsgid \"finish a set of draw commands\"\nmsgstr \"描画コマンドのセットを完了します\"\n\n#: ../../shape.rst:36 0ba068100e264e0b9e9ec1f368662d1d\nmsgid \":meth:`Shape.insert_text`\"\nmsgstr \"\"\n\n#: ../../shape.rst:36 5dd5770c7a054a66ab3b70a9d530c6f3\nmsgid \"insert text lines\"\nmsgstr \"テキスト行を挿入します\"\n\n#: ../../shape.rst:37 fa4216d497f9485cb9c79fc192a851bf\nmsgid \":meth:`Shape.insert_textbox`\"\nmsgstr \"\"\n\n#: ../../shape.rst:37 47ec8b14ef6c4a6d97b355006a0b0b62\nmsgid \"fit text into a rectangle\"\nmsgstr \"テキストを長方形に合わせて挿入します\"\n\n#: ../../shape.rst:38 f1252e5521e147f5bb1c776091ef3328\nmsgid \":attr:`Shape.doc`\"\nmsgstr \"\"\n\n#: ../../shape.rst:38 7f05739c6d0d459aa0631c532353654e\nmsgid \"stores the page's document\"\nmsgstr \"ページのドキュメントを格納します\"\n\n#: ../../shape.rst:39 61f46d3f420545e684f380815c9730f3\nmsgid \":attr:`Shape.draw_cont`\"\nmsgstr \"\"\n\n#: ../../shape.rst:39 8a19e4b60bd145ceaa799130f96ab50f\nmsgid \"draw commands since last :meth:`Shape.finish`\"\nmsgstr \":meth:`Shape.finish` 以降の描画コマンドを格納します\"\n\n#: ../../shape.rst:40 dbc1fe5e22804f4291fdc27abafe492f\nmsgid \":attr:`Shape.height`\"\nmsgstr \"\"\n\n#: ../../shape.rst:40 a1b344bfa62b474dbecc168b7566abfd\nmsgid \"stores the page's height\"\nmsgstr \"ページの高さを格納します\"\n\n#: ../../shape.rst:41 98c50cf9d34b4f1fac07407191336a46\nmsgid \":attr:`Shape.lastPoint`\"\nmsgstr \"\"\n\n#: ../../shape.rst:41 d744e08ab64c4be89b54b91da06292ad\nmsgid \"stores the current point\"\nmsgstr \"現在のポイントを格納します\"\n\n#: ../../shape.rst:42 3c7b42195cfb495cba0b78bee8af7989\nmsgid \":attr:`Shape.page`\"\nmsgstr \"\"\n\n#: ../../shape.rst:42 94b8094277504a3e865c3fc7a2fbadcf\nmsgid \"stores the owning page\"\nmsgstr \"所有するページを格納します\"\n\n#: ../../shape.rst:43 74e41af07b7e49dfb9e8897106da6072\nmsgid \":attr:`Shape.rect`\"\nmsgstr \"\"\n\n#: ../../shape.rst:43 2fd72b972ba64904b71bf6a28bf4aa69\nmsgid \"rectangle surrounding drawings\"\nmsgstr \"描画を囲む長方形を格納します\"\n\n#: ../../shape.rst:44 d662c10c7b284e1a9e8fb0cfacc0af7e\nmsgid \":attr:`Shape.text_cont`\"\nmsgstr \"\"\n\n#: ../../shape.rst:44 260872b329274794a91fbe27de9d0fd7\nmsgid \"accumulated text insertions\"\nmsgstr \"累積テキスト挿入を格納します\"\n\n#: ../../shape.rst:45 260f168374084a0389735532a415f968\nmsgid \":attr:`Shape.totalcont`\"\nmsgstr \"\"\n\n#: ../../shape.rst:45 cca60781247448a6bef1b019d5b03005\nmsgid \"accumulated string to be stored in :data:`contents`\"\nmsgstr \":data:`contents` に格納する累積文字列を格納します\"\n\n#: ../../shape.rst:46 bf5489e997644d1b86ef1a304a20a630\nmsgid \":attr:`Shape.width`\"\nmsgstr \"\"\n\n#: ../../shape.rst:46 320f315bc7e34fb9a224c8104c0490ba\nmsgid \"stores the page's width\"\nmsgstr \"ページの幅を格納します\"\n\n#: ../../shape.rst:49 bb77ff1beb1643f1a32fbeb881764556\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../shape.rst:55 f849eb8fe4ea4d84ae176a3bfaddbc5d\nmsgid \"\"\n\"Create a new drawing. During importing PyMuPDF, the *pymupdf.Page* object\"\n\" is being given the convenience method *new_shape()* to construct a \"\n\"*Shape* object. During instantiation, a check will be made whether we do \"\n\"have a PDF page. An exception is otherwise raised.\"\nmsgstr \"\"\n\"新しい描画を作成します。PyMuPDFをインポートする際、*pymupdf.Page* オブジェクトには *Shape* \"\n\"オブジェクトを構築するための便利なメソッド *new_shape()* \"\n\"が提供されます。インスタンス化中に、PDFページが存在するかどうかのチェックが行われます。それ以外の場合は例外が発生します。\"\n\n#: ../../shape.rst 1c33018ebf664e5c82016942d1b106b9\n#: 1ffb902ffb054dea81b4421598d73d3b 2c7222c93878455593e199cee35f9bc0\n#: 526e0601602e4ad294c77828899ee151 652ecb786383456887f3e684eb50a16f\n#: 8351d111f6ba44c5a48d07b45ecd69ec 8512993c092848e68b405672b0329a5f\n#: 97750b106384485e9da4b3a178fc8b8a bdcf123cefb04a72ac000f1e6d213cab\n#: d33f1cb5159441b288aacd2ccae007dd d522a8dc82fa46aaa1bf98571addfab6\n#: ec2e6f2b47e543f780ac5d88287a15e3 f4f238ef2bbb4c60a0db78dc6ba48ae3\n#: fc6fd8d86630442eac29f0ee69909dd3\nmsgid \"Parameters\"\nmsgstr \"パラメータ\"\n\n#: ../../shape.rst:57 7af1e6f9a6c54700a96a634680458cf7\nmsgid \"an existing page of a PDF document.\"\nmsgstr \"PDFドキュメントの既存のページ。\"\n\n#: ../../shape.rst:62 76f377d8f0084511ba9e8ab03be15272\nmsgid \"Draw a line from :data:`point_like` objects *p1* to *p2*.\"\nmsgstr \":data:`point_like` オブジェクト *p1* から *p2* への直線を描画します。\"\n\n#: ../../shape.rst:64 ../../shape.rst:78 ../../shape.rst:114\n#: 0bd9ca4fa2034c02bba75a1ed84436e8 67a3775d53744800bce979bd9509dae4\n#: 6fdeeec1ae7344738df476d7c0995efd\nmsgid \"starting point\"\nmsgstr \"開始点\"\n\n#: ../../shape.rst:66 ../../shape.rst:80 ../../shape.rst:116\n#: 233bc3b5db494f95bd617855177b0ba3 b9a33dfd5ad0434bb5d1681c4ef5477f\n#: d7a11d5e2d0843bf98b67ccb4c5a1b5c\nmsgid \"end point\"\nmsgstr \"終了点\"\n\n#: ../../shape.rst 00c99cce86684724a7484f034aead4b9\n#: 11b2ce9eb7ac446288dfe432b6af2d66 37b1db5fc557483698f96296fca977a1\n#: 398f16080c7c485daf19f594085b75e3 4fb89ac12ab341e98fd2fbfde502762f\n#: 79c3be157132461c91fbd43f577c6960 7f449ff12a28486c9377d3eae5881abe\n#: 86a6ff3345b34b99a0b2846ce9b63f97 87752e32bcb84c439a39262387ed43ad\n#: 8ce97810f50346f1963cb9045d0e3bc9 9a9e08e465d642609b4034f0ac585738\n#: e06a173ede194c2499189e3f4ea96d22 f8c5c0c193bf4857a6d61a7fe76a58a0\nmsgid \"Return type\"\nmsgstr \"戻り値の型\"\n\n#: ../../shape.rst:68 ../../shape.rst:84 ../../shape.rst:120\n#: ../../shape.rst:129 ../../shape.rst:138 ../../shape.rst:157\n#: ../../shape.rst:173 ../../shape.rst:185 ../../shape.rst:207\n#: ../../shape.rst:224 ../../shape.rst:233 ../../shape.rst:448\n#: 02178d1d64304122974cdd7d2eda4e9a 04e3fd71585f46408e34e1b5d2918e9d\n#: 1b90b951d85a446a9b18d2751aa79908 258641b6956c4c2ebb65129fbc72ae92\n#: 2c6a3892b51541d9b2bc4f6aa0613353 318dc522d9764a2e9e4ad48a39be4ebb\n#: 60c74e5979e14e0e8d70ebeb78df14b9 6b818606a66c4dc494a2fe410d34be22\n#: 6f503a8ab6474890be0934600cf2de3b 881f284fe0a54cc180a7ff765822eb7e\n#: 8b84d3286ddb4519bb3afc99075e83fb f570f468b63940e4b0b9f5890f13db63\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../shape.rst 19bca25aa417451a9d8eb8425f4d7fe5\n#: 2d7984c3e8b24f9cacf4f90e2f10a7e0 42bcff3c5d7c4b3ea0f0cff8b94a1936\n#: 5725a8009d724bfda07948d7fdd6a975 5ab553dbd9a245ef85863361d3458c06\n#: 5baa94cd077f42439269059c4560779d a0d4f65446c742a5b9f88f747fecf574\n#: a8b9ec9227c447c7b5b7e475f0ad137b b93d921a09e2475eb2dfecc00159859c\n#: c9221ebfa6724c35be3fe1b3043dcc84 edda77c9978d4bdc8e49a11220f628de\n#: fda0a5dbf3e44f70993141cd223cda9f ffd43af87088494c8ab238422d4affeb\nmsgid \"Returns\"\nmsgstr \"戻り値\"\n\n#: ../../shape.rst:69 ../../shape.rst:85 ../../shape.rst:121\n#: 03c2703f4c2c4c488c6e1dd5a8bde13f 54fc79ebcc5547368af108398f088aa1\n#: d5a893ea1f9f4e6cb959502504cda257\nmsgid \"the end point, *p2*.\"\nmsgstr \"終了点 *p2*。\"\n\n#: ../../shape.rst:76 eed928e2a53b4d0db6454fc9a3031e88\nmsgid \"\"\n\"Draw a squiggly (wavy, undulated) line from :data:`point_like` objects \"\n\"*p1* to *p2*. An integer number of full wave periods will always be \"\n\"drawn, one period having a length of *4 * breadth*. The breadth parameter\"\n\" will be adjusted as necessary to meet this condition. The drawn line \"\n\"will always turn \\\"left\\\" when leaving *p1* and always join *p2* from the\"\n\" \\\"right\\\".\"\nmsgstr \"\"\n\":data:`point_like` オブジェクト *p1* から *p2* \"\n\"への波線（うねり、曲線）を描画します。常に整数回の完全な波の周期が描画され、1つの周期の長さは4 * \"\n\"breadthです。必要に応じて幅パラメータが調整され、この条件を満たします。描かれる線は常に *p1* を離れる際に「左」に曲がり、*p2* \"\n\"には常に「右」から接続します。\"\n\n#: ../../shape.rst:82 cbee403daaee4a56b9b2f131ff95afb9\nmsgid \"\"\n\"the amplitude of each wave. The condition *2 * breadth < abs(p2 - p1)* \"\n\"must be true to fit in at least one wave. See the following picture, \"\n\"which shows two points connected by one full period.\"\nmsgstr \"\"\n\"各波の振幅。条件 *2 * breadth < abs(p2 - p1)* \"\n\"が少なくとも1つの波に収まる必要があります。次の図は、1つの完全な周期で接続された2つの点を示しています。\"\n\n#: ../../shape.rst:89 c61f3a8ac2e84d7e88c065f6a80328ac\nmsgid \"\"\n\"Here is an example of three connected lines, forming a closed, filled \"\n\"triangle. Little arrows indicate the stroking direction.\"\nmsgstr \"以下は、閉じた塗りつぶされた三角形を形成する三つの連結した線の例です。小さな矢印はストロークの方向を示しています。\"\n\n#: ../../shape.rst:105 3b09c6c0299043ad9e407b82096dc07f\nmsgid \"\"\n\"Waves drawn are **not** trigonometric (sine / cosine). If you need that, \"\n\"have a look at `draw.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/draw-sines/draw.py>`_.\"\nmsgstr \"\"\n\"描かれる波は三角関数（正弦/余弦）**ではありません**。それが必要な場合は `draw.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/draw-\"\n\"sines/draw.py>`_ を参照してください。\"\n\n#: ../../shape.rst:112 e6d38796d27441ac9eb554ae3567f070\nmsgid \"\"\n\"Draw a zigzag line from :data:`point_like` objects *p1* to *p2*. \"\n\"Otherwise works exactly like :meth:`Shape.draw_squiggle`.\"\nmsgstr \"\"\n\":data:`point_like` オブジェクト *p1* から *p2* へジグザグのラインを描画します。それ以外は \"\n\":meth:`Shape.draw_squiggle` とまったく同じです。\"\n\n#: ../../shape.rst:118 2686f76e3e56495ca08bdd2711d1c28e\nmsgid \"\"\n\"the amplitude of the movement. The condition *2 * breadth < abs(p2 - p1)*\"\n\" must be true to fit in at least one period.\"\nmsgstr \"動きの振幅。1つの周期に収まるように振幅を調整します。条件は *2 * breadth < abs(p2 - p1)* である必要があります。\"\n\n#: ../../shape.rst:125 bfb5a00ac07547bf822e4b2d95c0f3d7\nmsgid \"\"\n\"Draw several connected lines between points contained in the sequence \"\n\"*points*. This can be used for creating arbitrary polygons by setting the\"\n\" last item equal to the first one.\"\nmsgstr \"\"\n\"シーケンス *points* \"\n\"に含まれるポイント間にいくつかの接続されたラインを描画します。これを使用して、最後のアイテムを最初のアイテムと等しく設定することで、任意の多角形を作成できます。\"\n\n#: ../../shape.rst:127 9afa3278382745228b82849acc3d1db1\nmsgid \"\"\n\"a sequence of :data:`point_like` objects. Its length must at least be 2 \"\n\"(in which case it is equivalent to *draw_line()*).\"\nmsgstr \"\"\n\":data:`point_like` オブジェクトのシーケンス。その長さは少なくとも2である必要があります（この場合、*draw_line()* \"\n\"と同等です）。\"\n\n#: ../../shape.rst:130 b0f8276e3be04c6996c165c83ed3fdbd\nmsgid \"*points[-1]* -- the last point in the argument sequence.\"\nmsgstr \"引数シーケンスの最後のポイント、*points[-1]*。\"\n\n#: ../../shape.rst:134 bf9fc4f7ee704353953bbb497b85a344\nmsgid \"\"\n\"Draw a standard cubic Bézier curve from *p1* to *p4*, using *p2* and *p3*\"\n\" as control points.\"\nmsgstr \"*p1* から *p4* への標準的な立方ベジエ曲線を *p2*と *p3* を制御ポイントとして描画します。\"\n\n#: ../../shape.rst:136 65ae6d8fa1ca4696b5ceec6e6a33a484\n#, fuzzy\nmsgid \"All arguments are :data:`point_like` objects.\"\nmsgstr \"すべての引数は :data:`point_like` です。\"\n\n#: ../../shape.rst:139 c3bc7d17a1564a259bbccff931fbceb4\nmsgid \"the end point, *p4*.\"\nmsgstr \"終了点 *p4*。\"\n\n#: ../../shape.rst:141 540f633870214c57b214a2d3dc6fad47\nmsgid \"\"\n\"The points do not need to be different -- experiment a bit with some of \"\n\"them being equal!\"\nmsgstr \"ポイントは異なる必要はありません。一部のポイントが等しい場合も試してみてください！\"\n\n#: ../../shape.rst:143 cc32f6b9b719471e990541995cb91d8a\nmsgid \"Example:\"\nmsgstr \"例：\"\n\n#: ../../shape.rst:149 3cd13feab216456fb40eabb0f87476f2\nmsgid \"\"\n\"Draw an \\\"ellipse\\\" inside the given tetragon (quadrilateral). If it is a\"\n\" square, a regular circle is drawn, a general rectangle will result in an\"\n\" ellipse. If a quadrilateral is used instead, a plethora of shapes can be\"\n\" the result.\"\nmsgstr \"指定された四角形（四辺形）内に「楕円」を描画します。正方形の場合、正円が描かれ、一般的な長方形は楕円になります。四角形が使用される場合、さまざまな形状が結果として得られる可能性があります。\"\n\n#: ../../shape.rst:151 3beef81862054f6c9dcfb27abe73062b\nmsgid \"\"\n\"The drawing starts and ends at the middle point of the line `bottom-left \"\n\"-> top-left` corners in an anti-clockwise movement.\"\nmsgstr \"描画は、反時計回りの動きで、左下隅 -> 左上隅の中間点で開始し、終了します。\"\n\n#: ../../shape.rst:153 dbc5cddf46e74369a4ec90c4aba4a510\nmsgid \"\"\n\":data:`rect_like` or :data:`quad_like`.  *Changed in version 1.14.5:*  \"\n\"Quads are now also supported.\"\nmsgstr \"\"\n\n#: ../../shape.rst:153 0704abfebefe4fe78ed8116b1a8491c3\nmsgid \":data:`rect_like` or :data:`quad_like`.\"\nmsgstr \":data:`rect_like` または :data:`quad_like`。\"\n\n#: ../../shape.rst:155 b5056fbc16ad42e4b786c5a89beddb09\nmsgid \"*Changed in version 1.14.5:*  Quads are now also supported.\"\nmsgstr \"*バージョン1.14.5で変更：* 四角形もサポートされるようになりました。\"\n\n#: ../../shape.rst:158 913c4e5f92e8407f8da84ba1fbe6cb29\nmsgid \"\"\n\"the middle point of line `rect.bl -> rect.tl`, or resp. `quad.ll -> \"\n\"quad.ul`. Look at just a few examples here, or at the *quad-show?.py* \"\n\"scripts in the PyMuPDF-Utilities repository.\"\nmsgstr \"\"\n\"`rect.bl -> rect.tl` 、または `quad.ll -> quad.ul` の線の中間点。いくつかの例はこちら\"\n\"、またはPyMuPDF-Utilitiesリポジトリの  *quad-show?.py*  スクリプトをご覧ください。\"\n\n#: ../../shape.rst:165 e10d02b00d77481699e5ed1c3824246d\nmsgid \"\"\n\"Draw a circle given its center and radius. The drawing starts and ends at\"\n\" point `center - (radius, 0)` in an **anti-clockwise** movement. This \"\n\"point is the middle of the enclosing square's left side.\"\nmsgstr \"\"\n\"指定された中心と半径で円を描きます。描画は、**反時計回り** の動きで、ポイント `center - (radius, 0)` \"\n\"で始まり、終了します。このポイントは、包括的な正方形の左側の中央です。\"\n\n#: ../../shape.rst:167 ab7929d6c83247179ab99962d0e45182\nmsgid \"\"\n\"This is a shortcut for `draw_sector(center, start, 360, \"\n\"fullSector=False)`. To draw the same circle in a **clockwise** movement, \"\n\"use `-360` as degrees.\"\nmsgstr \"\"\n\"これは  `draw_sector(center, start, 360, fullSector=False)` \"\n\"のショートカットです。**時計回り** に同じ円を描画するには、度数として -360 を使用してください。\"\n\n#: ../../shape.rst:169 ../../shape.rst:199 6f2705ad71a74c2b917e39246bc2698d\n#: bd872730dfb6401aa65d5bf0dcfa4a1d\nmsgid \"the center of the circle.\"\nmsgstr \"円の中心。\"\n\n#: ../../shape.rst:171 5b6ab9084a254ee998a1d680ac1e0240\nmsgid \"the radius of the circle. Must be positive.\"\nmsgstr \"円の半径。正である必要があります。\"\n\n#: ../../shape.rst:174 7c4ce467661b468b8439dadac7926f6a\nmsgid \"\"\n\"`Point(center.x - radius, center.y)`.  .. image:: images/img-drawcircle.*\"\n\"    :scale: 60\"\nmsgstr \"\"\n\n#: ../../shape.rst:174 2debffa3cd414df1912ce3b384b1301c\nmsgid \"`Point(center.x - radius, center.y)`.\"\nmsgstr \"\"\n\n#: ../../shape.rst:181 ee66694536bb4ca4a6a74521eab10648\nmsgid \"\"\n\"A special case of *draw_bezier()*: Draw a cubic Bezier curve from *p1* to\"\n\" *p3*. On each of the two lines `p1 -> p2` and `p3 -> p2` one control \"\n\"point is generated. Both control points will therefore be on the same \"\n\"side of the line `p1 -> p3`. This guaranties that the curve's curvature \"\n\"does not change its sign. If the lines to p2 intersect with an angle of \"\n\"90 degrees, then the resulting curve is a quarter ellipse (resp. quarter \"\n\"circle, if of same length).\"\nmsgstr \"\"\n\"*draw_bezier()* の特殊なケース: *p1* から *p3* までの三次ベジエ曲線を描きます。各ライン `p1 -> p2` および\"\n\" `p3 -> p2` に制御点が生成されます。したがって、両方の制御点はライン `p1 -> p3` \"\n\"の同じ側にあります。これにより、曲線の曲率が符号を変更しないことが保証されます。p2 \"\n\"へのラインが90度で交差する場合、結果の曲線は四分の楕円（同じ長さの場合は四半期の円）です。\"\n\n#: ../../shape.rst:183 b9aa05d9515a4765ba0ed43ffaf7fdc8\nmsgid \"All arguments are :data:`point_like`.\"\nmsgstr \"すべての引数は :data:`point_like` です。\"\n\n#: ../../shape.rst:186 17f64971541f45cd813e80d02b9a38f9\nmsgid \"\"\n\"the end point, *p3*. The following is a filled quarter ellipse segment. \"\n\"The yellow area is oriented **clockwise:**  .. image:: images/img-\"\n\"drawCurve.png    :align: center\"\nmsgstr \"\"\n\n#: ../../shape.rst:186 13f26770deb8487da263851084fcf4e9\nmsgid \"\"\n\"the end point, *p3*. The following is a filled quarter ellipse segment. \"\n\"The yellow area is oriented **clockwise:**\"\nmsgstr \"終点、p3。以下は塗りつぶされた四分の楕円セグメントです。黄色の領域は **時計回り** に向いています：\"\n\n#: ../../shape.rst:197 e52f58c73f024ab492a6b26bf05ef6d1\nmsgid \"\"\n\"Draw a circular sector, optionally connecting the arc to the circle's \"\n\"center (like a piece of pie).\"\nmsgstr \"円のセクタを描き、必要に応じて円の中心に弧を接続します（パイの一片のように）。\"\n\n#: ../../shape.rst:201 4a4f8fd9d4ae4e9f9d879279d68a23eb\nmsgid \"\"\n\"one of the two end points of the pie's arc segment. The other one is \"\n\"calculated from the *angle*.\"\nmsgstr \"パイの弧セグメントの2つの端点のうちの1つ。*角度* から他の端点が計算されます。\"\n\n#: ../../shape.rst:203 cde4d3b5b77e4714a1e8229d3a7d5901\nmsgid \"\"\n\"the angle of the sector in degrees. Used to calculate the other end point\"\n\" of the arc. Depending on its sign, the arc is drawn anti-clockwise \"\n\"(positive) or clockwise.\"\nmsgstr \"その符号に応じて、弧は反時計回り（正の値）または時計回りに描かれます。\"\n\n#: ../../shape.rst:205 240361925857465eae04d2b1fb29fe7f\nmsgid \"\"\n\"whether to draw connecting lines from the ends of the arc to the circle \"\n\"center. If a fill color is specified, the full \\\"pie\\\" is colored, \"\n\"otherwise just the sector.\"\nmsgstr \"弧の端点から円の中心に接続線を描くかどうか。塗りつぶし色が指定されている場合、完全な「パイ」が色付けされ、それ以外の場合はセクタのみが色付けされます。\"\n\n#: ../../shape.rst:208 be7cd89a7589439eb4d78244412304ad\nmsgid \"\"\n\"the other end point of the arc. Can be used as starting point for a \"\n\"following invocation to create logically connected pies charts. Examples:\"\n\"  .. image:: images/img-drawSector1.*  .. image:: images/img-\"\n\"drawSector2.*\"\nmsgstr \"\"\n\n#: ../../shape.rst:208 0043e2c7a86744b4a2bc4d7f0bce8a4b\nmsgid \"\"\n\"the other end point of the arc. Can be used as starting point for a \"\n\"following invocation to create logically connected pies charts. Examples:\"\nmsgstr \"弧のもう一方の端点。論理的に接続されたパイチャートを作成するための次の呼び出しの開始点として使用できます。以下は例です：\"\n\n#: ../../shape.rst:217 5fb3a670ab80402c9dcadb97fd8823f0\nmsgid \"Changed in v1.22.0: Added parameter *radius*.\"\nmsgstr \"変更された v1.22.0 で：パラメーター *radius* が追加されました。\"\n\n#: ../../shape.rst:219 d0e527f29d634bf6a4487b2594b804af\nmsgid \"\"\n\"Draw a rectangle. The drawing starts and ends at the top-left corner in \"\n\"an anti-clockwise movement.\"\nmsgstr \"長方形を描画します。描画は、上部左隅から反時計回りの動きで始まり、終了します。\"\n\n#: ../../shape.rst:221 9f2b7555b1844871bbf67f60773f3566\nmsgid \"where to put the rectangle on the page.\"\nmsgstr \"ページ上の長方形の配置先。\"\n\n#: ../../shape.rst:222 67f101fa3c674ce7b113450e58af1ac1\n#, python-format\nmsgid \"\"\n\"draw rounded rectangle corners. If not `None`, specifies the radius of \"\n\"the curvature as a percentage of a rectangle side length. This must one \"\n\"or (a tuple of) two floats `0 < radius <= 0.5`, where 0.5 corresponds to \"\n\"50% of the respective side. If a float, the radius of the curvature is \"\n\"computed as `radius * min(width, height)`, drawing the corner's perimeter\"\n\" as a quarter circle. If a tuple `(rx, ry)` is given, then the curvature \"\n\"is asymmetric with respect to the horizontal and vertical directions. A \"\n\"value of `radius=(0.5, 0.5)` draws an ellipse.\"\nmsgstr \"\"\n\"角の丸みを付けた長方形を描画します。`None` でない場合、曲線の半径を長方形の辺の長さのパーセンテージとして指定します。これは 1 つまたは \"\n\"2 つの浮動小数点数、`0 < radius <= 0.5` でなければなりません。0.5 は、対応する辺の 50% \"\n\"に相当します。浮動小数点数の場合、曲線の半径は `radius * min(width, height)` として計算され、角の周囲を 1/4 \"\n\"円で描画します。タプル `(rx, ry)` が指定された場合、曲線は水平および垂直方向に対して非対称です。`radius=(0.5, 0.5)`\"\n\" は楕円を描画します。\"\n\n#: ../../shape.rst:225 6c3047af9341428fb1852d642a8d8fb3\nmsgid \"top-left corner of the rectangle.\"\nmsgstr \"長方形の上部左隅。\"\n\n#: ../../shape.rst:229 654bd0a3b7ce4bf78f0d2d85b1d37414\nmsgid \"\"\n\"Draw a quadrilateral. The drawing starts and ends at the top-left corner \"\n\"(:attr:`Quad.ul`) in an anti-clockwise movement. It is a shortcut of \"\n\":meth:`Shape.draw_polyline` with the argument `(ul, ll, lr, ur, ul)`.\"\nmsgstr \"\"\n\"四角形を描画します。描画は、上部左隅 (:attr:`Quad.ul`) から反時計回りの動きで始まり、終了します。これは \"\n\":meth:`Shape.draw_polyline` の引数 `(ul, ll, lr, ur, ul)` を使用したショートカットです。\"\n\n#: ../../shape.rst:231 046262682daf47c8be64f00f93f9acba\nmsgid \"where to put the tetragon on the page.\"\nmsgstr \"ページ上の四角形の配置先。\"\n\n#: ../../shape.rst:234 3fe224acf6924b1085f1052564c9423f\nmsgid \":attr:`Quad.ul`.\"\nmsgstr \"\"\n\n#: ../../shape.rst:253 0de6d95816a442d3b9408559071e8954\nmsgid \"\"\n\"Finish a set of *draw*()* methods by applying :ref:`CommonParms` to all \"\n\"of them.\"\nmsgstr \"次の *draw*()* メソッドの一連の描画を、:ref:`CommonParms` をそれらすべてに適用して終了します。\"\n\n#: ../../shape.rst:255 56332b3691544dfbaf0fd9e731231bc5\nmsgid \"\"\n\"It has **no effect on** :meth:`Shape.insert_text` and \"\n\":meth:`Shape.insert_textbox`.\"\nmsgstr \"\"\n\":meth:`Shape.insert_text` および :meth:`Shape.insert_textbox` には \"\n\"**影響を与えません**。\"\n\n#: ../../shape.rst:257 549c8c7eeb8344aaa7576d3e8a534e9c\nmsgid \"\"\n\"The method also supports **morphing the compound drawing** using \"\n\":ref:`Point` *fixpoint* and :ref:`matrix` *matrix*.\"\nmsgstr \"\"\n\"このメソッドは、:ref:`Point` *fixpoint* と :ref:`matrix` *matrix* を使用して、テキストまたは \"\n\"**複合描画を変形させること** もサポートしています。\"\n\n#: ../../shape.rst:259 dba0c80e395c4f9992d5e84ad7225ffd\nmsgid \"\"\n\"morph the text or the compound drawing around some arbitrary :ref:`Point`\"\n\" *fixpoint* by applying :ref:`Matrix` *matrix* to it. This implies that \"\n\"*fixpoint* is a **fixed point** of this operation: it will not change its\"\n\" position. Default is no morphing (``None``). The matrix can contain any \"\n\"values in its first 4 components, *matrix.e == matrix.f == 0* must be \"\n\"true, however. This means that any combination of scaling, shearing, \"\n\"rotating, flipping, etc. is possible, but translations are not.\"\nmsgstr \"\"\n\"テキストまたは複合描画を、任意の :ref:`Point` *fixpoint* に :ref:`Matrix` *matrix* \"\n\"を適用して変形します。これにより、*fixpoint* はこの操作の **固定ポイント** \"\n\"であることを意味します。その位置は変わりません。デフォルトは変形なし（``None``）です。ただし、matrixの最初の4つの成分には任意の値を含めることができ、*matrix.e\"\n\" == matrix.f == 0* \"\n\"である必要があります。これは、スケーリング、シアリング、回転、反転など、移動以外の組み合わせが可能であることを意味しますが、移動はできません。\"\n\n#: ../../shape.rst:261 5dafa22688dd4869b353c3ba9d3b07f7\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for stroke colors. Value < 0 or > 1 \"\n\"will be ignored. Default is 1 (intransparent).\"\nmsgstr \"*（v1.18.1で新規追加）* ストロークの透明度を設定します。値が0未満または1を超える場合は無視されます。デフォルトは1（不透明）です。\"\n\n#: ../../shape.rst:262 ccec6b24043c40a28e9532eddd90bdce\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for fill colors. Default is 1 \"\n\"(intransparent).\"\nmsgstr \"*（v1.18.1で新規追加）* 塗りつぶしの色の透明度を設定します。デフォルトは1（不透明）です。\"\n\n#: ../../shape.rst:264 df15c1363a6a46538ab6875019646cbd\nmsgid \"\"\n\"request the **\\\"even-odd rule\\\"** for filling operations. Default is \"\n\"``False``, so that the **\\\"nonzero winding number rule\\\"** is used. These\"\n\" rules are alternative methods to apply the fill color where areas \"\n\"overlap. Only with fairly complex shapes a different behavior is to be \"\n\"expected with these rules. For an in-depth explanation, see \"\n\":ref:`AdobeManual`, pp. 137 ff. Here is an example to demonstrate the \"\n\"difference.\"\nmsgstr \"\"\n\"塗りつぶし操作に対して **「even-oddルール」** を要求します。デフォルトは ``False`` で、したがって \"\n\"**「非ゼロのワインディング数ルール」** \"\n\"が使用されます。これらのルールは、領域が重なる場所で塗りつぶし色を適用するための代替メソッドです。複雑な形状では、これらのルールに異なる振る舞いが期待されることはほとんどありません。詳細な説明については、:ref:`AdobeManual`\"\n\" の137ページ以降を参照してください。以下はその違いを示す例です。\"\n\n#: ../../shape.rst:266 c674e567b1e5433eaf84acd80acc23dc\nmsgid \"\"\n\"*(new in v1.18.4)* the :data:`xref` number of an :data:`OCG` or \"\n\":data:`OCMD` to make this drawing conditionally displayable.\"\nmsgstr \"\"\n\"*（v1.18.4で新規追加）* この描画を条件付きで表示可能にする :data:`OCG` または :data:`OCMD` の \"\n\":data:`xref` 番号。\"\n\n#: ../../shape.rst:270 63c92f36394847c489986e7f2afbb97a\nmsgid \"For each pixel in a shape, the following will happen:\"\nmsgstr \"各ピクセルの場合、以下のことが起こります：\"\n\n#: ../../shape.rst:272 36c14ed50f0445be999e611bc169aa24\nmsgid \"\"\n\"Rule **\\\"even-odd\\\"** counts, how many areas contain the pixel. If this \"\n\"count is **odd,** the pixel is regarded **inside** the shape, if it is \"\n\"**even**, the pixel is **outside**.\"\nmsgstr \"\"\n\"ルール **「even-odd」** は、ピクセルを含むエリアの数をカウントします。このカウントが **奇数** の場合、ピクセルは形状の \"\n\"**内部** と見なされ、偶数の場合は **外部** と見なされます。\"\n\n#: ../../shape.rst:274 3effcfe2b7fe4980b3622d1cc2555db9\nmsgid \"\"\n\"The default rule **\\\"nonzero winding\\\"** in addition looks at the \"\n\"*\\\"orientation\\\"* of each area containing the pixel: it **adds 1** if an \"\n\"area is drawn anti-clockwise and it **subtracts 1** for clockwise areas. \"\n\"If the result is zero, the pixel is regarded **outside,** pixels with a \"\n\"non-zero count are **inside** the shape.\"\nmsgstr \"\"\n\"デフォルトのルール **「nonzero winding」** では、ピクセルを含む各エリアの *「方向」* \"\n\"も考慮されます。エリアが反時計回りに描かれている場合は **1を追加し** 、時計回りのエリアは **1を引きます** \"\n\"。結果がゼロの場合、ピクセルは **外部** と見なされ、非ゼロのカウントを持つピクセルは形状の **内部** と見なされます。\"\n\n#: ../../shape.rst:276 b72f9a0a9d6a42fba11e06941aaae289\nmsgid \"\"\n\"Of the four shapes in above image, the top two each show three circles \"\n\"drawn in standard manner (anti-clockwise, look at the arrows). The lower \"\n\"two shapes contain one (the top-left) circle drawn clockwise. As can be \"\n\"seen, area orientation is irrelevant for the right column (even-odd \"\n\"rule).\"\nmsgstr \"\"\n\"上記の画像の4つの形状のうち、上の2つはそれぞれ標準的な方法で描かれた3つの円を示しています（反時計回り、矢印を参照）。下の2つの形状には時計回りに描かれた1つ（左上）の円が含まれています。右の列では、エリアの方向は無視されることがわかります\"\n\"（even-oddルール）。\"\n\n#: ../../shape.rst:297 a50a3db9c4f74b3aaed7c91f010f050f\n#, fuzzy\nmsgid \"Insert text lines starting at ``point``.\"\nmsgstr \"テキスト行を *point* で開始します。\"\n\n#: ../../shape.rst:299 d60ae29ad0ca4e709ff2c72d7bf5c264\nmsgid \"\"\n\"the bottom-left position of the first character of *text* in pixels. It \"\n\"is important to understand, how this works in conjunction with the \"\n\"*rotate* parameter. Please have a look at the following picture. The \"\n\"small red dots indicate the positions of *point* in each of the four \"\n\"possible cases.  .. image:: images/img-inserttext.*    :scale: 33\"\nmsgstr \"\"\n\n#: ../../shape.rst:299 1521f8f6fbea43a0be0deb7904e4623c\nmsgid \"\"\n\"the bottom-left position of the first character of *text* in pixels. It \"\n\"is important to understand, how this works in conjunction with the \"\n\"*rotate* parameter. Please have a look at the following picture. The \"\n\"small red dots indicate the positions of *point* in each of the four \"\n\"possible cases.\"\nmsgstr \"\"\n\"テキストの最初の文字の下部左位置（ピクセル単位）。*rotate* \"\n\"パラメータとの連携方法を理解することが重要です。以下の画像をご覧ください。小さな赤い点は、各ケースでの *point* の位置を示しています。\"\n\n#: ../../shape.rst:304 c50197a3ee954fc4b17e16da50350320\n#, fuzzy\nmsgid \"\"\n\"the text to be inserted. May be specified as either a string type or as a\"\n\" sequence type. For sequences, or strings containing line breaks ``\\\\n``,\"\n\" several lines will be inserted. No care will be taken if lines are too \"\n\"wide, but the number of inserted lines will be limited by \\\"vertical\\\" \"\n\"space on the page (in the sense of reading direction as established by \"\n\"the *rotate* parameter). Any rest of *text* is discarded -- the return \"\n\"code however contains the number of inserted lines.\"\nmsgstr \"\"\n\"挿入するテキスト。文字列型または文字列のシーケンス型として指定できます。シーケンスの場合、または改行文字 *\\\\n* \"\n\"を含む文字列の場合、複数の行が挿入されます。ただし、行があまりにも幅が広い場合、挿入される行数はページ上の「垂直」スペース（*回転* \"\n\"パラメータによって確立される読み取り方向の意味で）によって制限されます。*テキスト* \"\n\"の残り部分は破棄されますが、戻りコードには挿入された行数が含まれます。\"\n\n#: ../../shape.rst:306 ../../shape.rst:346 a2bce94fcad44fc08799f6d16a27e19d\n#: f75a16cbc40142c5a8ce2199eb87b25c\nmsgid \"\"\n\"a factor to override the line height calculated from font properties. If \"\n\"not `None`, a line height of `fontsize * lineheight` will be used.\"\nmsgstr \"\"\n\"フォントのプロパティから計算された行の高さをオーバーライドするためのファクター。``None`` でない場合、`fontsize * \"\n\"lineheight` の行の高さが使用されます。\"\n\n#: ../../shape.rst:307 1ecd328d935546d38c4621a762982871\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for stroke colors (the **border \"\n\"line** of a character). Only  `0 <= value <= 1` will be considered. \"\n\"Default is 1 (intransparent).\"\nmsgstr \"*（v1.18.1で新規追加）* ストロークの透明度を設定します。値が0未満または1を超える場合は無視されます。デフォルトは1（不透明）です。\"\n\n#: ../../shape.rst:308 ../../shape.rst:351 168d47f1a50e45efbddb4be1a0a28d1c\n#: 7029b8b04590494a850f9bf97c737317\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for fill colors. Default is 1 \"\n\"(intransparent). Use this value to control transparency of the text \"\n\"color. Stroke opacity **only** affects the border line of characters.\"\nmsgstr \"\"\n\"*（v1.18.1で新たに追加）* \"\n\"塗りつぶしカラーの透明度を設定します。デフォルトは1（不透明）です。テキストカラーの透明度を制御するためにこの値を使用します。ストロークの透明度は文字の境界線に\"\n\" **のみ** 影響します。\"\n\n#: ../../shape.rst:310 bc253669783d43fbbcea827f904f8df7\nmsgid \"\"\n\"determines whether to rotate the text. Acceptable values are multiples of\"\n\" 90 degrees. Default is 0 (no rotation), meaning horizontal text lines \"\n\"oriented from left to right. 180 means text is shown upside down from \"\n\"**right to left**. 90 means anti-clockwise rotation, text running \"\n\"**upwards**. 270 (or -90) means clockwise rotation, text running \"\n\"**downwards**. In any case, *point* specifies the bottom-left coordinates\"\n\" of the first character's rectangle. Multiple lines, if present, always \"\n\"follow the reading direction established by this parameter. So line 2 is \"\n\"located **above** line 1 in case of `rotate = 180`, etc.\"\nmsgstr \"\"\n\"テキストを回転させるかどうかを決定します。許容される値は90度の倍数です。デフォルトは0（回転なし）で、左から右への水平テキストが表示されます。180は、**右から左**\"\n\" への上下逆さテキストを意味し、90は反時計回りの回転で、テキストが **上向き** \"\n\"に表示されます。270（または-90）は時計回りの回転で、テキストが **下向き** \"\n\"に表示されます。いずれの場合も、pointは最初の文字の矩形の左下の座標を指定します。存在する場合、複数行は常にこのパラメータによって確立された読み取り方向に従います。したがって、\"\n\" *rotate = 180* の場合、行2は行1の **上に** 配置されます。\"\n\n#: ../../shape.rst:312 ../../shape.rst:355 68906f83108042f0b104b462a3b39709\n#: 9759f8b8a55448eb88645d85395ee4e8\nmsgid \"\"\n\"*(new in v1.18.4)* the :data:`xref` number of an :data:`OCG` or \"\n\":data:`OCMD` to make this text conditionally displayable.\"\nmsgstr \"\"\n\"*(v1.18.4 新機能)* :data:`OCG` または :data:`OCMD` の :data:`xref` \"\n\"番号、テキストを条件付きで表示可能にするためのものです。\"\n\n#: ../../shape.rst:315 ed86c6cd4572455ba92ae3ff42b41fdf\nmsgid \"number of lines inserted.\"\nmsgstr \"挿入された行数。\"\n\n#: ../../shape.rst:317 ../../shape.rst:367 4a40110f016f4c7bb3e919ac462d14e3\n#: 785b22c9fbc5484186666fbe76c0f207\nmsgid \"For a description of the other parameters see :ref:`CommonParms`.\"\nmsgstr \"他のパラメータの説明については  :ref:`CommonParms` を参照してください。\"\n\n#: ../../shape.rst:338 32569db0897946de8f8338dcc82e3dd3\nmsgid \"\"\n\"PDF only: Insert text into the specified rectangle. The text will be \"\n\"split into lines and words and then filled into the available space, \"\n\"starting from one of the four rectangle corners, which depends on \"\n\"`rotate`. Line feeds and multiple space will be respected.\"\nmsgstr \"\"\n\"PDFのみ：指定された矩形にテキストを挿入します。テキストは行と単語に分割され、*回転* \"\n\"に応じて異なる矩形の角から始まり、利用可能なスペースに挿入されます。行送りと複数のスペースは尊重されます。\"\n\n#: ../../shape.rst:340 c50da8ee249d416084e826f0a8a2efd6\nmsgid \"the area to use. It must be finite and not empty.\"\nmsgstr \"使用する領域。有限でかつ空でなければなりません。\"\n\n#: ../../shape.rst:342 7990001f1d8a482696c3ea94ee3b11c5\nmsgid \"\"\n\"the text to be inserted. Must be specified as a string or a sequence of \"\n\"strings. Line breaks are respected also when occurring in a sequence \"\n\"entry.\"\nmsgstr \"挿入するテキスト。文字列または文字列のシーケンスとして指定する必要があります。シーケンスエントリ内の行送りも尊重されます。\"\n\n#: ../../shape.rst:344 8bfa2ed038884962a70ceb3e0459dc06\nmsgid \"\"\n\"align each text line. Default is 0 (left). Centered, right and justified \"\n\"are the other supported options, see :ref:`TextAlign`. Please note that \"\n\"the effect of parameter value *TEXT_ALIGN_JUSTIFY* is only achievable \"\n\"with \\\"simple\\\" (single-byte) fonts (including the :ref:`Base-14-Fonts`).\"\nmsgstr \"\"\n\"各テキスト行を整列させます。デフォルトは0（左揃え）。センタリング、右揃え、ジャスティファイドがサポートされている他のオプションです。詳細は \"\n\":ref:`TextAlign` を参照してください。なお、パラメータ値  *TEXT_ALIGN_JUSTIFY* \"\n\"の効果は、「シンプル」（単一バイト）フォント（:ref:`Base-14-Fonts` を含む）でのみ達成できます。\"\n\n#: ../../shape.rst:348 9adb4b3bbe094da8a624bd552fc13f21\nmsgid \"\"\n\"controls handling of tab characters ``\\\\t`` using the \"\n\"`string.expandtabs()` method **per each line**.\"\nmsgstr \"タブ文字 *\\\\t* の処理を **行ごとに** *string.expandtabs()* メソッドを使用して制御します。\"\n\n#: ../../shape.rst:350 67177b4ade6c4da5a4523395d6bd4bf4\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for stroke colors. Negative values \"\n\"and values > 1 will be ignored. Default is 1 (intransparent).\"\nmsgstr \"*（v1.18.1で新たに追加）* ストロークカラーの透明度を設定します。負の値や1より大きい値は無視されます。デフォルトは1（不透明）です。\"\n\n#: ../../shape.rst:353 d5edb13ac13b4ab4ba9d26fa3d3a6d82\nmsgid \"\"\n\"requests text to be rotated in the rectangle. This value must be a \"\n\"multiple of 90 degrees. Default is 0 (no rotation). Effectively, the four\"\n\" values `0`, `90`, `180` and `270` (= `-90`) are processed, each causing \"\n\"the text to start in a different rectangle corner. Bottom-left is `90`, \"\n\"bottom-right is `180`, and `-90 / 270` is top-right. See the example how \"\n\"text is filled in a rectangle. This argument takes precedence over \"\n\"morphing. See the second example, which shows text first rotated left by \"\n\"`90` degrees and then the whole rectangle rotated clockwise around is \"\n\"lower left corner.\"\nmsgstr \"\"\n\"テキストを矩形内で回転させるように要求します。受け入れ可能な値は90度の倍数です。デフォルトは0（回転なし）、つまり左から右への水平なテキスト行です。180は、右から左に逆さまに表示されることを意味します。90は反時計回りの回転で、テキストは上に向かって表示されます。270（または-90）は時計回りの回転で、テキストは下に向かって表示されます。いずれの場合も、pointは最初の文字の矩形の左下の座標を指定します。複数行がある場合は、常にこのパラメータで確立された読み取り方向に従います。したがって、rotate\"\n\" = 180の場合、行2は行1の上に配置されますなど。\"\n\n#: ../../shape.rst:358 c9924f296b104dcb885e423a8329287a\nmsgid \"\"\n\"**If positive or zero**: successful execution. The value returned is the \"\n\"unused rectangle line space in pixels. This may safely be ignored -- or \"\n\"be used to optimize the rectangle, position subsequent items, etc.  **If \"\n\"negative**: no execution. The value returned is the space deficit to \"\n\"store text lines. Enlarge rectangle, decrease *fontsize*, decrease text \"\n\"amount, etc.\"\nmsgstr \"\"\n\n#: ../../shape.rst:359 ff434ea0b01748d3a22351b8914d1de9\nmsgid \"\"\n\"**If positive or zero**: successful execution. The value returned is the \"\n\"unused rectangle line space in pixels. This may safely be ignored -- or \"\n\"be used to optimize the rectangle, position subsequent items, etc.\"\nmsgstr \"\"\n\"**正またはゼロの場合** \"\n\"：正常な実行。返される値は使用されていない矩形行のスペース（ピクセル単位）です。これを安全に無視するか、矩形を最適化したり、後続のアイテムの位置を調整したりするために使用できます。\"\n\n#: ../../shape.rst:361 2d7f62a0c5ec468eb58daea2b7b74842\nmsgid \"\"\n\"**If negative**: no execution. The value returned is the space deficit to\"\n\" store text lines. Enlarge rectangle, decrease *fontsize*, decrease text \"\n\"amount, etc.\"\nmsgstr \"\"\n\"**負の場合**： \"\n\"実行なし。返される値はテキスト行を格納するためのスペース不足です。矩形を拡大したり、フォントサイズを減少させたり、テキストの量を減少させたりする必要があります。\"\n\n#: ../../shape.rst:375 f65e40d3ebec4535af01faa79e3c04db\nmsgid \"\"\n\"Update the page's :data:`contents` with the accumulated drawings, \"\n\"followed by any text insertions. If text overlaps drawings, it will be \"\n\"written on top of the drawings.\"\nmsgstr \"\"\n\"ページの :data:`contents` \"\n\"を蓄積された描画に更新し、その後テキスト挿入が続きます。テキストが描画と重なる場合、テキストは描画の上に書き込まれます。\"\n\n#: ../../shape.rst:377 3cc36436278147c4bf9af8031f1046a3\nmsgid \"**Do not forget to execute this method:**\"\nmsgstr \"**このメソッドを実行しないことは忘れないでください：**\"\n\n#: ../../shape.rst:379 44ccc171888e476f88b7c3ce68d54ad9\nmsgid \"\"\n\"If a shape is **not committed, it will be ignored and the page will not \"\n\"be changed!**\"\nmsgstr \"シェイプが **確定されていない** 場合、無視され、ページは変更されません！\"\n\n#: ../../shape.rst:381 8911998982cf45e6b4d61df722ae0084\nmsgid \"\"\n\"The method will reset attributes :attr:`Shape.rect`, :attr:`lastPoint`, \"\n\":attr:`draw_cont`, :attr:`text_cont` and :attr:`totalcont`. Afterwards, \"\n\"the shape object can be reused for the **same page**.\"\nmsgstr \"\"\n\"このメソッドは、属性 :attr:`Shape.rect`、:attr:`lastPoint` 、:attr:`draw_cont` \"\n\"、:attr:`text_cont` 、および :attr:`totalcont` をリセットします。その後、シェイプオブジェクトは \"\n\"**同じページ** で再利用できます。\"\n\n#: ../../shape.rst:383 90b57d6cc3344abaa5ae796d17518c78\nmsgid \"\"\n\"determine whether to put content in foreground (default) or background. \"\n\"Relevant only, if the page already has a non-empty :data:`contents` \"\n\"object.\"\nmsgstr \"\"\n\"コンテンツを前面（デフォルト）または背面に配置するかどうかを決定します。ページに既存の非空の :data:`contents` \"\n\"オブジェクトがある場合のみ関連します。\"\n\n#: ../../shape.rst:385 555f29f07330465799e60c983380d945\nmsgid \"**---------- Attributes ----------**\"\nmsgstr \"**属性**\"\n\n#: ../../shape.rst:389 bcd84d9d71fe4ab7a75882c2f6ea55ee\nmsgid \"For reference only: the page's document.\"\nmsgstr \"参照専用：ページの文書。\"\n\n#: ../../shape.rst 4bc5f78dcd47499499d993fc76937923\n#: 51e0e906798c404999816e887c14725e 583eb30bb6764d82886dcee5ecc5ef23\n#: 7da907572dab4cdd850b1f99866f1208 84fee03ff02a47de895a2e76a85339b0\n#: 8ad67482ac084e4e8acd77c771ac9813 bd1c39ed922a4dba9f34104a29bd9bd6\n#: dc8385568c9641d9bb717e0218bc356a f04ca533ba0f465e9baafc622227ff3a\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../shape.rst:391 d4a7179efc87417687ed54512b5fd372\nmsgid \":ref:`Document`\"\nmsgstr \"\"\n\n#: ../../shape.rst:395 e50d0793a5eb432bb3c2ca8ea196f4c2\nmsgid \"For reference only: the owning page.\"\nmsgstr \"参照専用：所属するページ。\"\n\n#: ../../shape.rst:397 a88ee833273045f299c35dd3ead948a4\nmsgid \":ref:`Page`\"\nmsgstr \"\"\n\n#: ../../shape.rst:401 2bad01b347624c13a0c42fc3970fc1b5\nmsgid \"Copy of the page's height\"\nmsgstr \"ページの高さのコピー\"\n\n#: ../../shape.rst:403 ../../shape.rst:409 a1d7f49541cb48ab8a1087635dffe627\n#: ee0e76b01d494167bc804a4bcb20168e\nmsgid \"float\"\nmsgstr \"\"\n\n#: ../../shape.rst:407 ae4a0df9e57c45dd99dc05694d71194d\nmsgid \"Copy of the page's width.\"\nmsgstr \"ページの幅のコピー。\"\n\n#: ../../shape.rst:413 36e04a92b85b455f986d86cf86a84b9d\nmsgid \"\"\n\"Accumulated command buffer for **draw methods** since last finish. Every \"\n\"finish method will append its commands to :attr:`Shape.totalcont`.\"\nmsgstr \"\"\n\"最後のfinish以降の **描画メソッド** の蓄積コマンドバッファ。各finishメソッドはそのコマンドを \"\n\":attr:`Shape.totalcont` に追加します。\"\n\n#: ../../shape.rst:415 ../../shape.rst:421 ../../shape.rst:442\n#: 0e691c52a692459fb3651063bbd96fa1 3bd5e87273ea409ba3861ff7a5df3fba\n#: 6131e3edacf44d948d0f06ae76196fb4\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../shape.rst:419 1c7cc423d0b647cc8b976e70594d7e5a\nmsgid \"\"\n\"Accumulated text buffer. All **text insertions** go here. This buffer \"\n\"will be appended to :attr:`totalcont` :meth:`Shape.commit`, so that text \"\n\"will never be covered by drawings in the same Shape.\"\nmsgstr \"\"\n\"蓄積されたテキストバッファ。すべての **テキスト挿入** はここに行われます。このバッファは :attr:`totalcont` \"\n\":meth:`Shape.commit` に追加されるため、テキストは同じShape内の描画に覆われることはありません。\"\n\n#: ../../shape.rst:425 31e0348adf3949dea03c7e108eec0e9a\nmsgid \"\"\n\"Rectangle surrounding drawings. This attribute is at your disposal and \"\n\"may be changed at any time. Its value is set to ``None`` when a shape is \"\n\"created or committed. Every *draw** method, and \"\n\":meth:`Shape.insert_textbox` update this property (i.e. **enlarge** the \"\n\"rectangle as needed). **Morphing** operations, however \"\n\"(:meth:`Shape.finish`, :meth:`Shape.insert_textbox`) are ignored.\"\nmsgstr \"\"\n\"描画を囲む矩形。この属性はあなたの自由に使用でき、いつでも変更できます。シェイプが作成または確定されたとき、その値は ``None`` \"\n\"に設定されます。すべての *draw** メソッド、および :meth:`Shape.insert_textbox` \"\n\"はこのプロパティを更新します（必要に応じて矩形を **拡大します** ）。ただし、**変形** 操作（:meth:`Shape.finish` \"\n\"、:meth:`Shape.insert_textbox` ）は無視されます。\"\n\n#: ../../shape.rst:427 58e3a175f61343beb779d52d6f9a968a\nmsgid \"\"\n\"A typical use of this attribute would be setting \"\n\":attr:`Page.cropbox_position` to this value, when you are creating shapes\"\n\" for later or external use. If you have not manipulated the attribute \"\n\"yourself, it should reflect a rectangle that contains all drawings so \"\n\"far.\"\nmsgstr \"\"\n\"この属性の典型的な使用法は、後でまたは外部で使用するためにシェイプを作成する場合、:attr:`Page.cropbox_position` \"\n\"をこの値に設定することです。自分で属性を操作していない場合、これはこれまでのすべての描画を含む矩形を反映するはずです。\"\n\n#: ../../shape.rst:429 bde3111f6fcb4fde8ae6d94e2b784878\nmsgid \"\"\n\"If you have used morphing and need a rectangle containing the morphed \"\n\"objects, use the following code::\"\nmsgstr \"変形を使用し、変形されたオブジェクトを含む矩形が必要な場合、次のコードを使用します::\"\n\n#: ../../shape.rst:436 8b59162d4cdc4453a1a62c884c29d8c5\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../shape.rst:440 70f79c2bf0624368be25e43a4b7a3c3f\nmsgid \"\"\n\"Total accumulated command buffer for draws and text insertions. This will\"\n\" be used by :meth:`Shape.commit`.\"\nmsgstr \"描画およびテキスト挿入のための累積コマンドバッファです。これは :meth:`Shape.commit` で使用されます。\"\n\n#: ../../shape.rst:446 2a512a35544e4ff4bc0908226c3f1474\nmsgid \"\"\n\"For reference only: the current point of the drawing path. It is ``None``\"\n\" at *Shape* creation and after each *finish()* and *commit()*.\"\nmsgstr \"\"\n\"参照用: 描画パスの現在のポイントです。*Shape* の作成時、および各 *finish()* および *commit()* の後には \"\n\"``None`` です。\"\n\n#: ../../shape.rst:451 5f43e7fa99ee464a8f4e310b6073e35b\nmsgid \"Usage\"\nmsgstr \"使用法\"\n\n#: ../../shape.rst:452 a35b85f2df424fe5a8123cbd236b49c9\nmsgid \"\"\n\"A drawing object is constructed by *shape = page.new_shape()*. After \"\n\"this, as many draw, finish and text insertions methods as required may \"\n\"follow. Each sequence of draws must be finished before the drawing is \"\n\"committed. The overall coding pattern looks like this::\"\nmsgstr \"\"\n\"drawingオブジェクトは `shape = page.new_shape()` \"\n\"によって構築されます。その後、必要なだけ多くのdraw、finish、およびテキスト挿入メソッドが続きます。描画をコミットする前に、各描画シーケンスを終了する必要があります。全体のコーディングパターンは次のようになります::\"\n\n#: ../../shape.rst:471 7d0392c130464a54a962cc95cad3ce9d\nmsgid \"\"\n\"Each *finish()* combines the preceding draws into one logical shape, \"\n\"giving it common colors, line width, morphing, etc. If *closePath* is \"\n\"specified, it will also connect the end point of the last draw with the \"\n\"starting point of the first one.\"\nmsgstr \"\"\n\"各 *finish()* メソッドは、前の描画を1つの論理的なシェイプに結合し、共通の色、線の幅、変形などを設定します。*closePath* \"\n\"が指定されている場合、最後の描画のエンドポイントを最初の描画のスタートポイントと接続します。\"\n\n#: ../../shape.rst:473 d909c60fe1834c8eb1936c81f4fe8a7c\nmsgid \"\"\n\"To successfully create compound graphics, let each draw method use the \"\n\"end point of the previous one as its starting point. In the above pseudo \"\n\"code, *draw2* should hence use the returned :ref:`Point` of *draw1* as \"\n\"its starting point. Failing to do so, would automatically start a new \"\n\"path and *finish()* may not work as expected (but it won't complain \"\n\"either).\"\nmsgstr \"\"\n\"複合グラフィックを正常に作成するには、各 draw \"\n\"メソッドが前の描画のエンドポイントを次の描画のスタートポイントとして使用してください。上記の疑似コードでは、*draw2* は *draw1* \"\n\"の戻り値である :ref:`Point` \"\n\"を次の描画のスタートポイントとして使用すべきです。そうしないと、自動的に新しいパスが開始され、*finish()* \"\n\"が期待どおりに動作しないかもしれません（ただし、エラーは発生しません）。\"\n\n#: ../../shape.rst:475 fb42b4b00cfd4c8f9bc125398e78d941\nmsgid \"\"\n\"Text insertions may occur anywhere before the commit (they neither touch \"\n\":attr:`Shape.draw_cont` nor :attr:`Shape.lastPoint`). They are appended \"\n\"to *Shape.totalcont* directly, whereas draws will be appended by \"\n\"*Shape.finish*.\"\nmsgstr \"\"\n\"テキストの挿入は、コミット（commit）の前にどこでも発生できます :attr:`Shape.draw_cont` または \"\n\":attr:`Shape.lastPoint` に触れません）。テキストは直接 *Shape.totalcont* に追加されますが、描画は \"\n\"*Shape.finish* によって追加されます。\"\n\n#: ../../shape.rst:477 f1ba4537b82747479d0306c9e87f4f4c\nmsgid \"\"\n\"Each *commit* takes all text insertions and shapes and places them in \"\n\"foreground or background on the page -- thus providing a way to control \"\n\"graphical layers.\"\nmsgstr \"各 *コミット* は、すべてのテキスト挿入とシェイプをページの前面または背面に配置し、グラフィックのレイヤーを制御する方法を提供します。\"\n\n#: ../../shape.rst:479 f54933082b2d4eff99e12a13fc1482a9\nmsgid \"\"\n\"**Only** *commit* **will update** the page's contents, the other methods \"\n\"are basically string manipulations.\"\nmsgstr \"*コミット* **のみ** がページのコンテンツを **更新します**。他のメソッドは基本的に文字列の操作です。\"\n\n#: ../../shape.rst:482 278641dcb46d4baf936c58e97dcd5458\nmsgid \"Examples\"\nmsgstr \"例\"\n\n#: ../../shape.rst:483 eb1041462daa4eaea29f2c68f9820833\nmsgid \"Create a full circle of pieces of pie in different colors::\"\nmsgstr \"異なる色のピースを使用して円形のパイを作成します::\"\n\n#: ../../shape.rst:498 eaebaebe3baa4f09947553ff9e26c2a1\nmsgid \"Here is an example for 5 colors:\"\nmsgstr \"以下は5つの色の例です。\"\n\n#: ../../shape.rst:502 3cf653254d684532a9c3aba1c78bfd12\nmsgid \"\"\n\"Create a regular n-edged polygon (fill yellow, red border). We use \"\n\"*draw_sector()* only to calculate the points on the circumference, and \"\n\"empty the draw command buffer again before drawing the polygon::\"\nmsgstr \"\"\n\"正則なn角形を作成します（塗りつぶしは黄色、赤い境界線）。周囲の点を計算するために *draw_sector（）* \"\n\"を使用し、多角形を描く前に描画コマンドバッファを空にします::\"\n\n#: ../../shape.rst:517 e093071b33a14f6ca8a50b7e9ef6d3b1\nmsgid \"Here is the polygon for n = 7:\"\nmsgstr \"n = 7の場合の多角形は次のとおりです：\"\n\n#: ../../shape.rst:524 32cfdbeb116244d09f20318c9cbaa2ac\nmsgid \"Common Parameters\"\nmsgstr \"共通パラメータ\"\n\n#: ../../shape.rst:526 e8e32aa90b154bf9b1f9186f60ab584a\nmsgid \"**fontname** (*str*)\"\nmsgstr \"\"\n\n#: ../../shape.rst:528 77ba86666bd24c11b1d1d22120f706a7\nmsgid \"In general, there are three options:\"\nmsgstr \"一般的に、3つのオプションがあります：\"\n\n#: ../../shape.rst:530 02905b80e6194c4eacf48669a2b4862d\nmsgid \"\"\n\"Use one of the standard :ref:`Base-14-Fonts`. In this case, *fontfile* \"\n\"**must not** be specified and *\\\"Helvetica\\\"* is used if this parameter \"\n\"is omitted, too.\"\nmsgstr \"\"\n\"標準の :ref:`Base-14-Fonts` のいずれかを使用します。この場合、*fontfile* を指定 \"\n\"**してはいけず**、このパラメータを省略した場合は *「Helvetica」* が使用されます。\"\n\n#: ../../shape.rst:531 e643b83ac7934c6a8daf143d5e6ea969\nmsgid \"\"\n\"Choose a font already in use by the page. Then specify its **reference** \"\n\"name prefixed with a slash \\\"/\\\", see example below.\"\nmsgstr \"既にページで使用されているフォントを選択します。その場合、スラッシュ「/」で前置された **参照** 名を指定します。以下の例を参照してください。\"\n\n#: ../../shape.rst:532 1aa96eb291154994b5334cb249b357b8\nmsgid \"\"\n\"Specify a font file present on your system. In this case choose an \"\n\"arbitrary, but new name for this parameter (without \\\"/\\\" prefix).\"\nmsgstr \"システムに存在するフォントファイルを指定します。この場合、任意の新しい名前をこのパラメータに選択します（「/」接頭辞なし）。\"\n\n#: ../../shape.rst:534 42e52261eb524d2984f6a0c4332a2f24\nmsgid \"\"\n\"If inserted text should re-use one of the page's fonts, use its reference\"\n\" name appearing in :meth:`Page.get_fonts` like so:\"\nmsgstr \"\"\n\"挿入されるテキストがページのフォントの1つを再利用する場合は、:meth:`Page.get_fonts` \"\n\"に表示される参照名を次のように使用します：\"\n\n#: ../../shape.rst:536 17c14b3525c343518ae06671819af5b8\nmsgid \"\"\n\"Suppose the font list has the item *[1024, 0, 'Type1', 'NimbusMonL-Bold',\"\n\" 'R366']*, then specify *fontname = \\\"/R366\\\", fontfile = None* to use \"\n\"font *NimbusMonL-Bold*.\"\nmsgstr \"\"\n\"フォントリストに項目 *[1024, 0, 'Type1', 'NimbusMonL-Bold', 'R366']* がある場合、フォント \"\n\"*NimbusMonL-Bold*  を使用するには、*fontname = \\\"/R366\\\"、fontfile = None* と指定します。\"\n\n#: ../../shape.rst:540 30272688bae040099e4f10745899bb73\nmsgid \"**fontfile** (*str*)\"\nmsgstr \"\"\n\n#: ../../shape.rst:542 c86a2afe0b8040a3841ecc108e5f0c2a\nmsgid \"\"\n\"File path of a font existing on your computer. If you specify *fontfile*,\"\n\" make sure you use a *fontname* **not occurring** in the above list. This\"\n\" new font will be embedded in the PDF upon *doc.save()*. Similar to new \"\n\"images, a font file will be embedded only once. A table of MD5 codes for \"\n\"the binary font contents is used to ensure this.\"\nmsgstr \"\"\n\"コンピューターに存在するフォントのファイルパス。*fontfile* を指定する場合、上記のリストに **存在しない** *フォント名* \"\n\"を使用してください。この新しいフォントは、*doc.save()* \"\n\"時にPDFに埋め込まれます。画像と同様に、フォントファイルは1度だけ埋め込まれます。バイナリフォントコンテンツのMD5コードのテーブルが使用され、これを確実にします。\"\n\n#: ../../shape.rst:546 de497e62ab204c48ae01fa7ac3ed1c32\nmsgid \"**set_simple** (*bool*)\"\nmsgstr \"\"\n\n#: ../../shape.rst:548 8620026ea526446e8ef1ca19f9760737\nmsgid \"\"\n\"Fonts installed from files are installed as **Type0** fonts by default. \"\n\"If you want to use 1-byte characters only, set this to true. This setting\"\n\" cannot be reverted. Subsequent changes are ignored.\"\nmsgstr \"\"\n\"ファイルからインストールされたフォントは、デフォルトで **Type0** \"\n\"フォントとしてインストールされます。1バイト文字のみを使用する場合は、これをtrueに設定します。この設定は元に戻すことはできません。後続の変更は無視されます。\"\n\n#: ../../shape.rst:552 3981f48a75204dc09ff6f422f689ffa4\nmsgid \"**fontsize** (*float*)\"\nmsgstr \"\"\n\n#: ../../shape.rst:554 30ac30c13b44417bbeb1b66ed6d98114\nmsgid \"Font size of text, see: :data:`fontsize`.\"\nmsgstr \"テキストのフォントサイズ、参照： :data:`fontsize`。\"\n\n#: ../../shape.rst:558 4d0dc80686d94b4c88776c39286aa523\nmsgid \"**dashes** (*str*)\"\nmsgstr \"\"\n\n#: ../../shape.rst:560 47655eea2c2e46188c15bd1c75c4117a\n#, fuzzy\nmsgid \"\"\n\"Causes lines to be drawn dashed. The general format is `\\\"[n m] p\\\"` of \"\n\"(up to) 3 floats denoting pixel lengths. ``n`` is the dash length, ``m`` \"\n\"(optional) is the subsequent gap length, and ``p`` (the \\\"phase\\\" - \"\n\"**required**, even if 0!) specifies how many pixels should be skipped \"\n\"before the dashing starts. If ``m`` is omitted, it defaults to ``n``.\"\nmsgstr \"\"\n\"線を破線で描画するようにします。一般的なフォーマットは、ピクセル長を示す（最大）3つの浮動小数点数の `\\\"[n m] p\\\"` です。``n``\"\n\" は破線の長さ、``m`` （オプション）はその後のギャップの長さ、 ``p`` （「位相」 - 0であっても \"\n\"**必須**！）は、破線が開始される前にスキップするべきピクセルの数を指定します。``m`` が省略された場合、``n`` \"\n\"にデフォルト値が設定されます。\"\n\n#: ../../shape.rst:562 c003ae76596a4f938a7fd5de9cb061a3\nmsgid \"\"\n\"A continuous line (no dashes) is drawn with `\\\"[] 0\\\"` or ``None`` or \"\n\"`\\\"\\\"`. Examples:\"\nmsgstr \"連続線（破線なし）は `\\\"[] 0\\\"` または ``None`` または `\\\"\\\"` で描画されます。例：\"\n\n#: ../../shape.rst:564 e6cbda6711694eb8b100b5a9792385ef\nmsgid \"\"\n\"Specifying `\\\"[3 4] 0\\\"` means dashes of 3 and gaps of 4 pixels following\"\n\" each other.\"\nmsgstr \"`\\\"[3 4] 0\\\"` を指定すると、3ピクセルの破線と4ピクセルのギャップが交互に続きます。\"\n\n#: ../../shape.rst:565 3391c97c4550433782ec215117a6557d\nmsgid \"`\\\"[3 3] 0\\\"` and `\\\"[3] 0\\\"` do the same thing.\"\nmsgstr \"`\\\"[3 3] 0\\\"` と `\\\"[3] 0\\\"` は同じことをします。\"\n\n#: ../../shape.rst:567 f068a3fa466545ecaf2d248a20fc2739\nmsgid \"\"\n\"For (the rather complex) details on how to achieve sophisticated dashing \"\n\"effects, see :ref:`AdobeManual`, page 217.\"\nmsgstr \"洗練された破線効果を実現する詳細な詳細については、:ref:`AdobeManual` の217ページを参照してください。\"\n\n#: ../../shape.rst:571 82aa9894181a4fe3b697261487bbfe7e\nmsgid \"**color / fill** (*list, tuple*)\"\nmsgstr \"**色/塗りつぶし** （*リスト、タプル*）\"\n\n#: ../../shape.rst:573 3ed2643ec6df4cc28a73683cb286285e\nmsgid \"\"\n\"Stroke and fill colors can be specified as tuples or list of of floats \"\n\"from 0 to 1. These sequences must have a length of 1 (GRAY), 3 (RGB) or 4\"\n\" (CMYK). For GRAY colorspace, a single float instead of the unwieldy \"\n\"*(float,)* or *[float]* is also accepted. Accept (default) or use `None` \"\n\"to not use the parameter.\"\nmsgstr \"\"\n\"線の色と塗りつぶしの色は、0から1までの浮動小数点数からなるリストまたはタプルとして指定できます。これらのシーケンスの長さは、1（GRAY）、3（RGB）、または4（CMYK）でなければなりません。GRAYカラースペースの場合、*[float]*\"\n\" や*(float,)* \"\n\"の代わりに単一の浮動小数点数を使用することもできます。このパラメータを受け入れるには、（デフォルト）を受け入れるか、または使用しないようにするには\"\n\" `None` を使用します。\"\n\n#: ../../shape.rst:575 06bd406c862d430d8527a7a38b17df9b\nmsgid \"\"\n\"To simplify color specification, method *getColor()* in *pymupdf.utils* \"\n\"may be used to get predefined RGB color triples by name. It accepts a \"\n\"string as the name of the color and returns the corresponding triple. The\"\n\" method knows over 540 color names -- see section :ref:`ColorDatabase`.\"\nmsgstr \"\"\n\"色の指定を簡略化するために、*pymupdf.utils* の *getColor()* \"\n\"メソッドを使用して、名前に対応するRGBカラートリプルを取得することができます。これは色の名前を指定する文字列を受け入れ、対応するトリプルを返します。このメソッドは540以上のカラー名を認識します。:ref:`ColorDatabase`\"\n\" のセクションを参照してください。\"\n\n#: ../../shape.rst:577 3313c7d4006745a8b2fc466404404f63\nmsgid \"\"\n\"Please note that the term *color* usually means \\\"stroke\\\" color when \"\n\"used in conjunction with fill color.\"\nmsgstr \"ご注意ください。*色* という用語は、通常、塗りつぶし色と組み合わせて使用される場合に「線の」色を意味します\"\n\n#: ../../shape.rst:579 0a6d8ba9500941c4bc6aa00352d41451\nmsgid \"\"\n\"If letting default a color parameter to `None`, then no resp. color \"\n\"selection command will be generated. If *fill* and *color* are both \"\n\"`None`, then the drawing will contain no color specification. But it will\"\n\" still be \\\"stroked\\\", which causes PDF's default color \\\"black\\\" be used\"\n\" by Adobe Acrobat and all other viewers.\"\nmsgstr \"\"\n\"色パラメータのデフォルト値を `None` にする場合、対応する色の選択コマンドは生成されません。*fill* と *color* がどちらも \"\n\"`None` の場合、描画には色の指定が含まれません。ただし、まだ「ストローク」されているため、Adobe \"\n\"Acrobatや他のビューアではPDFのデフォルトカラー「ブラック」が使用されます。\"\n\n#: ../../shape.rst:583 2e5246304d274dfaa37af742928af0ea\n#, fuzzy\nmsgid \"**width** (*float*)\"\nmsgstr \"**border_width** （*浮動小数点数*）\"\n\n#: ../../shape.rst:585 77b8db9870114d7f91f971f5aaa99512\nmsgid \"\"\n\"The stroke (\\\"border\\\") width of the elements in a shape (if applicable).\"\n\" The default value is 1. The values width, color and fill have the \"\n\"following relationship / dependency:\"\nmsgstr \"図形内の要素のストローク（\\\"枠線\\\"）の幅（適用可能な場合）。デフォルト値は1です。幅、色、塗りつぶしの値は、以下の関係/依存関係を持ちます：\"\n\n#: ../../shape.rst:587 bd3f3d47979d4ba6967fc689176d7873\nmsgid \"\"\n\"If `fill=None` shape elements will always be drawn with a border - even \"\n\"if `color=None` (in which case black is taken) or `width=0` (in which \"\n\"case 1 is taken).\"\nmsgstr \"\"\n\"`fill=None` の場合、shape要素は常に枠線で描画されます -  `color=None` \"\n\"の場合（その場合、黒が使用されます）、または `width=0` の場合（その場合、1が使用されます）でもです。\"\n\n#: ../../shape.rst:588 50e316e85bee43f3ae23b6e8bf36459e\n#, fuzzy\nmsgid \"\"\n\"Shapes without border can only be achieved if a fill color is specified \"\n\"(which may be white of course). To achieve this, specify `width=0`. In \"\n\"this case, the ``color`` parameter is ignored.\"\nmsgstr \"\"\n\"枠線のない図形は、塗りつぶしの色が指定されている場合のみ実現できます（もちろん白色であっても構いません）。これを実現するには、 `width=0`\"\n\" を指定します。この場合、 `color` パラメータは無視されます。\"\n\n#: ../../shape.rst:592 dbf0b7aa242944fd9c3dba05b0a5476c\nmsgid \"**stroke_opacity / fill_opacity** (*floats*)\"\nmsgstr \"**stroke_opacity / fill_opacity** （*浮動小数点数*）\"\n\n#: ../../shape.rst:594 f10fd732b18e4d06882b251b866820ed\nmsgid \"\"\n\"Both values are floats in range [0, 1]. Negative values or values > 1 \"\n\"will ignored (in most cases). Both set the transparency such that a value\"\n\" 0.5 corresponds to 50% transparency, 0 means invisible and 1 means \"\n\"intransparent. For e.g. a rectangle the stroke opacity applies to its \"\n\"border and fill opacity to its interior.\"\nmsgstr \"両方の値は[0、1]の範囲の浮動小数点数です。負の値または1を超える値は（ほとんどの場合）無視されます。両方の値は、透明度を設定し、たとえば値0.5は50％の透明度を示し、0は不可視を意味し、1は不透明を意味します。たとえば四角形の場合、stroke_opacityはその境界に、fill_opacityはその内部に適用されます。\"\n\n#: ../../shape.rst:596 908ef08674a94047bf811e5db7824042\n#, fuzzy\nmsgid \"\"\n\"For text insertions (:meth:`Shape.insert_text` and \"\n\":meth:`Shape.insert_textbox`), use *fill_opacity* for the text. At first \"\n\"sight this seems surprising, but it becomes obvious when you look further\"\n\" down to `render_mode`: `fill_opacity` applies to the yellow and \"\n\"`stroke_opacity` applies to the blue color.\"\nmsgstr \"\"\n\"テキストの挿入（:meth:`Shape.insert_text` および :meth:`Shape.insert_textbox` \"\n\"）の場合、テキストには *fill_opacity* を使用してください。最初は驚くかもしれませんが、*render_mode* \"\n\"の詳細を見ると明らかになります。*fill_opacity* は黄色に適用され、*stroke_opacity* は青色に適用されます。\"\n\n#: ../../shape.rst:600 807dedb850524343a44713165dc92d74\nmsgid \"**border_width** (*float*)\"\nmsgstr \"**border_width** （*浮動小数点数*）\"\n\n#: ../../shape.rst:602 7c05f5b49a074002a9a8e24fa16e09c0\nmsgid \"\"\n\"Set the border width for text insertions. New in v1.14.9. Relevant only \"\n\"if the render mode argument is used with a value greater zero.\"\nmsgstr \"テキスト挿入の境界線の幅を設定します。v1.14.9で新しく追加されました。render_mode引数がゼロより大きい値で使用されている場合にのみ関連します。\"\n\n#: ../../shape.rst:606 e8f74369b5414cf39c02c7bdc84d0278\nmsgid \"**render_mode** (*int*)\"\nmsgstr \"**render_mode** (*整数*)\"\n\n#: ../../shape.rst:608 07e11204dc2b4479bd2e65c3e33aad8d\nmsgid \"\"\n\"*New in version 1.14.9:* Integer in `range(8)` which controls the text \"\n\"appearance (:meth:`Shape.insert_text` and :meth:`Shape.insert_textbox`). \"\n\"See page 246 in :ref:`AdobeManual`. New in v1.14.9. These methods now \"\n\"also differentiate between fill and stroke colors.\"\nmsgstr \"\"\n\"*バージョン1.14.9で新たに導入された* `range(8)` \"\n\"内の整数。これはテキストの外観（:meth:`Shape.insert_text` および \"\n\":meth:`Shape.insert_textbox` ）を制御します。:ref:`AdobeManual` \"\n\"のページ246を参照してください。バージョン1.14.9での新機能です。これらのメソッドは、塗りつぶしの色とストロークの色を区別するようになりました。\"\n\n#: ../../shape.rst:610 69a9ed429520483291966e04bc134827\nmsgid \"\"\n\"For default 0, only the text fill color is used to paint the text. For \"\n\"backward compatibility, using the *color* parameter instead also works.\"\nmsgstr \"\"\n\"デフォルト値0では、テキストの塗りつぶし色のみがテキストを塗りつぶすために使用されます。*color* \"\n\"パラメーターを代わりに使用することも、後方互換性のために機能します。\"\n\n#: ../../shape.rst:611 92f8238398a445de9ac634455065140b\nmsgid \"\"\n\"For render mode 1, only the border of each glyph (i.e. text character) is\"\n\" drawn with a thickness as set in argument *border_width*. The color \"\n\"chosen in the *color* argument is taken for this, the *fill* parameter is\"\n\" ignored.\"\nmsgstr \"\"\n\"render_mode 1では、各グリフ（つまりテキスト文字）の境界線のみが指定された *border_width* \"\n\"で描画されます。この際、*color* 引数で選択した色が使用され、*fill* パラメーターは無視されます。\"\n\n#: ../../shape.rst:612 6dd3e1055d934657ae6fbe17f98f1b7b\nmsgid \"\"\n\"For render mode 2, the glyphs are filled and stroked, using both color \"\n\"parameters and the specified border width. You can use this value to \"\n\"simulate **bold text** without using another font: choose the same value \"\n\"for *fill* and *color* and an appropriate value for *border_width*.\"\nmsgstr \"\"\n\"render_mode \"\n\"2では、グリフは塗りつぶされ、ストロークされ、両方の色パラメーターと指定された境界幅が使用されます。別のフォントを使用せずに \"\n\"**太字のテキスト** をシミュレートするためにこの値を使用できます。*fill* と *color* \"\n\"に同じ値を選択し、*border_width* に適切な値を選択します。\"\n\n#: ../../shape.rst:613 44ab50cc9488478cbafcd5e8d9859763\nmsgid \"\"\n\"For render mode 3, the glyphs are neither stroked nor filled: the text \"\n\"becomes invisible.\"\nmsgstr \"render_mode 3では、グリフはストロークも塗りつぶしもされません。テキストは見えなくなります。\"\n\n#: ../../shape.rst:615 e59e76826913438ea50a2cc075ab7cd2\nmsgid \"\"\n\"The following examples use border_width=0.3, together with a fontsize of \"\n\"15. Stroke color is blue and fill color is some yellow.\"\nmsgstr \"以下の例では、border_width=0.3を使用し、フォントサイズは15です。ストロークの色は青で、塗りつぶしの色は黄色です。\"\n\n#: ../../shape.rst:621 082047ee68a54ee3ae920d7817052247\n#, fuzzy\nmsgid \"**miter_limit** (*float*)\"\nmsgstr \"**border_width** （*浮動小数点数*）\"\n\n#: ../../shape.rst:623 5df811fb349949d38e4160fbc8097077\nmsgid \"\"\n\"A float specifying the maximum acceptable value of the quotient `miter-\"\n\"length / line-width` (\\\"miter quotient\\\"). Used in text output methods. \"\n\"This is only relevant for non-zero render mode values -- then, characters\"\n\" are written with border lines (i.e. \\\"stroked\\\").\"\nmsgstr \"\"\n\n#: ../../shape.rst:625 fcdf5a0b4b05400fabcc68e71bbfe4a3\nmsgid \"\"\n\"If two lines stroking some character meet at a sharp (<= 90°) angle and \"\n\"the line width is large enough, then \\\"spikes\\\" may become visible -- \"\n\"causing an ugly appearance as shown below. For more background, see page \"\n\"126 of the :ref:`AdobeManual`.\"\nmsgstr \"\"\n\n#: ../../shape.rst:627 61ef12d76d4c44a5971fbe5f377e42cd\nmsgid \"\"\n\"For instance, when joins meet at 90°, then the miter length is ``sqrt(2) \"\n\"* line-width``, so the miter quotient is ``sqrt(2)``.\"\nmsgstr \"\"\n\n#: ../../shape.rst:629 6e57edd425af46cab1f0544ea9fb09d6\nmsgid \"\"\n\"If ``miter_limit`` is exceeded, then all joins with a larger qotient will\"\n\" appear as beveled (\\\"butt\\\" appearance).\"\nmsgstr \"\"\n\n#: ../../shape.rst:631 1b9c88426fad4881993b42f8df4e29ba\nmsgid \"\"\n\"The default value 1 (and any smaller value) will ensure that all joins \"\n\"are rendered as a butt. A value of ``None`` will use the PDF default \"\n\"value.\"\nmsgstr \"\"\n\n#: ../../shape.rst:633 6c5240d22b91424eb8a99f3f6cdd9e61\nmsgid \"Example text showing spikes (``miter_limit=None``):\"\nmsgstr \"\"\n\n#: ../../shape.rst:637 22b2f2ab87704749865bf8654f86f486\nmsgid \"Example text suppressing spikes (``miter_limit=1``):\"\nmsgstr \"\"\n\n#: ../../shape.rst:643 ef72de748a3241f494828889b778a5c3\nmsgid \"**overlay** (*bool*)\"\nmsgstr \"**オーバーレイ** （*bool*）\"\n\n#: ../../shape.rst:645 1a50148614e94b0f9e09a72b981ba540\nmsgid \"Causes the item to appear in foreground (default) or background.\"\nmsgstr \"アイテムを前景（ デフォルト）または背景に表示させます。\"\n\n#: ../../shape.rst:649 f9c30f5c9a0245e5acbf5d0126b40609\nmsgid \"**morph** (*sequence*)\"\nmsgstr \"**morph** （*シーケンス*）\"\n\n#: ../../shape.rst:651 5029b952e1be402ea4aea727b6c5334a\nmsgid \"\"\n\"Causes \\\"morphing\\\" of either a shape, created by the *draw*()* methods, \"\n\"or the text inserted by page methods *insert_textbox()* / \"\n\"*insert_text()*. If not ``None``, it must be a pair *(fixpoint, matrix)*,\"\n\" where *fixpoint* is a :ref:`Point` and *matrix* is a :ref:`Matrix`. The \"\n\"matrix can be anything except translations, i.e. *matrix.e == matrix.f ==\"\n\" 0* must be true. The point is used as a fixed point for the matrix \"\n\"operation. For example, if *matrix* is a rotation or scaling, then \"\n\"*fixpoint* is its center. Similarly, if *matrix* is a left-right or up-\"\n\"down flip, then the mirroring axis will be the vertical, respectively \"\n\"horizontal line going through *fixpoint*, etc.\"\nmsgstr \"\"\n\"*draw*()* メソッドによって作成されたシェイプまたはページメソッド *insert_textbox（）*/ *insert_text（）*\"\n\" によって挿入されたテキストのいずれかの「変形」を引き起こします。 ``None`` でない場合、*（fixpoint、matrix）* \"\n\"のペアでなければなりません。ここで、*fixpoint* は :ref:`Point` であり、*matrix* は :ref:`Matrix` \"\n\"です。行列は、*matrix.e == matrix.f == 0* \"\n\"でない限り、移動以外の任意のものにすることができます。ポイントは、行列操作の固定ポイントとして使用されます。たとえば、*行列* \"\n\"が回転またはスケーリングである場合、*fixpoint* はその中心です。同様に、*行列* が左右または上下の反転である場合、鏡像化される軸は \"\n\"*fixpoint* を介して通る垂直、または水平の線です。\"\n\n#: ../../shape.rst:653 b02e3c71c8f64fc68a15b90bf3c129ea\nmsgid \"\"\n\"Several methods contain checks whether the to be inserted items will \"\n\"actually fit into the page (like :meth:`Shape.insert_text`, or \"\n\":meth:`Shape.draw_rect`). For the result of a morphing operation there is\"\n\" however no such guaranty: this is entirely the programmer's \"\n\"responsibility.\"\nmsgstr \"\"\n\"いくつかのメソッドには、ページに挿入されるアイテムが実際に適合するかどうかをチェックする検証が含まれています（:meth:`Shape.insert_text`\"\n\" 、または :meth:`Shape.draw_rect` \"\n\"など）。変形操作の結果にはそのような保証はありません。これは完全にプログラマーの責任です。\"\n\n#: ../../shape.rst:657 62281c77ca8f47188d63f20f3712a5b0\nmsgid \"**lineCap (deprecated: \\\"roundCap\\\")** (*int*)\"\nmsgstr \"**lineCap（非推奨：「roundCap」**）（*int*）\"\n\n#: ../../shape.rst:659 cd5b630baa744b1189ae847e6e8286fd\nmsgid \"\"\n\"Controls the look of line ends. The default value 0 lets each line end at\"\n\" exactly the given coordinate in a sharp edge. A value of 1 adds a semi-\"\n\"circle to the ends, whose center is the end point and whose diameter is \"\n\"the line width. Value 2 adds a semi-square with an edge length of line \"\n\"width and a center of the line end.\"\nmsgstr \"線の末端の外観を制御します。デフォルト値0は、各線の末端が鋭いエッジで正確な座標で終了することを許可します。値1は、末端に直径が線の幅で中心が末端ポイントである半円を追加します。値2は、線の幅と線の末端を中心とする辺の長さがある半正方形を追加します。\"\n\n#: ../../shape.rst:661 6026a44a326145afa3e7a6f376a1bbf6\nmsgid \"*Changed in version 1.14.15*\"\nmsgstr \"\"\n\n#: ../../shape.rst:665 2e6dced4dc3b49d0bfc6d15aba362eba\nmsgid \"**lineJoin** (*int*)\"\nmsgstr \"\"\n\n#: ../../shape.rst:667 66fbb0a47a7648efa567adac178985a1\nmsgid \"\"\n\"*New in version 1.14.15:* Controls the way how line connections look \"\n\"like. This may be either as a sharp edge (0), a rounded join (1), or a \"\n\"cut-off edge (2, \\\"butt\\\").\"\nmsgstr \"\"\n\"*バージョン1.14.15で新規追加：* \"\n\"ラインの接続方法を制御します。これは、鋭いエッジ（0）、丸い接続（1）、または切り取られたエッジ（2、「butt」）のいずれかです。\"\n\n#: ../../shape.rst:671 82bab1c6af0a4d169a36b68529a2ab41\nmsgid \"**closePath** (*bool*)\"\nmsgstr \"\"\n\n#: ../../shape.rst:673 991347c321464275b6f78b81a2f89e09\nmsgid \"\"\n\"Causes the end point of a drawing to be automatically connected with the \"\n\"starting point (by a straight line).\"\nmsgstr \"描画の終点を自動的に始点に直線で接続させる原因となります。\"\n\n#: ../../footer.rst:46 703f5e6cdc364cd898823615d897ea50\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"a factor to override the line \"\n#~ \"height calculated from font properties. \"\n#~ \"If not `None`, a line height of\"\n#~ \" `fontsize * lineheight` will be \"\n#~ \"used.  :arg int expandtabs: controls \"\n#~ \"handling of tab characters ``\\\\t`` using\"\n#~ \" the `string.expandtabs()` method **per \"\n#~ \"each line**.\"\n#~ msgstr \"\"\n#~ \"フォントのプロパティから計算された行の高さをオーバーライドするためのファクター。``None`` でない場合、`fontsize\"\n#~ \" * lineheight` の行の高さが使用されます。\"\n\n#~ msgid \"arg int expandtabs\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/story-class.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 5a64c03ac3304767805a34e5519dc643\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 987f101ad8fa44c9a85292f456737790\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 937bf2fcb1964c3f97071eb2764745fd\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../story-class.rst:7 b33db4381f96455f881c4cb8b48a9239\nmsgid \"Story\"\nmsgstr \"Story (ストーリー)\"\n\n#: ../../story-class.rst:11 96383b7b49df4dc69e7545f0a3d37164\nmsgid \"New in v1.21.0\"\nmsgstr \"バージョン1.21.0で新規追加\"\n\n#: ../../story-class.rst:14 7d3756e920e1487eb3e1b3bf28ed6f9b\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../story-class.rst:14 51a2ed231a8d4b16a5606ce08ce54e8b\nmsgid \"**Short Description**\"\nmsgstr \"**簡単な説明**\"\n\n#: ../../story-class.rst:16 65726e39b3794bb9a492d8c5ba15990f\nmsgid \":meth:`Story.reset`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:16 d9f0619b632e4bb582c9bbc227d889b5\nmsgid \"\\\"rewind\\\" story output to its beginning\"\nmsgstr \"ストーリーの出力を先頭に巻き戻す\"\n\n#: ../../story-class.rst:17 7c94ba99f15b4f4d847c8263ca0b5132\nmsgid \":meth:`Story.place`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:17 5ef6af8dda1c4704b193cb14b0e43f33\nmsgid \"compute story content to fit in provided rectangle\"\nmsgstr \"指定された長方形に収まるストーリーのコンテンツを計算\"\n\n#: ../../story-class.rst:18 bb0b48f6450441f5a3dd54b788dee19a\nmsgid \":meth:`Story.draw`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:18 8570b10f54d345139cfe978f97d8c9b3\nmsgid \"write the computed content to current page\"\nmsgstr \"計算されたコンテンツを現在のページに書き込む\"\n\n#: ../../story-class.rst:19 f57f0a347b814e60b8da011ae533e111\nmsgid \":meth:`Story.element_positions`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:19 2e5a11cc2c1c430a878377cd43dbd28c\nmsgid \"callback function logging currently processed story content\"\nmsgstr \"現在処理中のストーリーコンテンツを記録するコールバック関数\"\n\n#: ../../story-class.rst:20 7d3e1c7cf395410d9a7653dac537daad\nmsgid \":attr:`Story.body`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:20 1979b2f75d824d3588dc32499dace02a\nmsgid \"the story's underlying :htmlTag:`body`\"\nmsgstr \"ストーリーの基本となる :htmlTag:`body`\"\n\n#: ../../story-class.rst:21 7ba33a6d21124637b218ce0b7f3d3ec1\nmsgid \":meth:`Story.write`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:21 757b24965dee4f998578cefcb1a94b35\nmsgid \"places and draws Story to a DocumentWriter\"\nmsgstr \"ストーリーを :ref:`DocumentWriter` に配置して描画します\"\n\n#: ../../story-class.rst:22 5005e48c2d114342997d30259781a86d\nmsgid \":meth:`Story.write_stabilized`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:22 12712f5deea24c88b77364960c58dbdb\nmsgid \"iterative layout of html content to a DocumentWriter\"\nmsgstr \"HTMLコンテンツを :ref:`DocumentWriter` に反復的にレイアウトします\"\n\n#: ../../story-class.rst:23 16d33507e0554249ba750773fb5cb53d\nmsgid \":meth:`Story.write_with_links`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:23 93c333b6d5f843cf8258a5274dfa22f0\nmsgid \"like `write()` but also creates PDF links\"\nmsgstr \"`write()` と同様ですが、PDFリンクも作成します\"\n\n#: ../../story-class.rst:24 25e70986951c4b668e0a1704e2984855\nmsgid \":meth:`Story.write_stabilized_with_links`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:24 2b185135aa8348fb825dded5295a7474\nmsgid \"like `write_stabilized()` but also creates PDF links\"\nmsgstr \"`write_stabilized()` と同様ですが、PDFリンクも作成します\"\n\n#: ../../story-class.rst:25 f7ca87bbd93e492587ff63f31dc3d7d5\nmsgid \":meth:`Story.fit`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:25 ../../story-class.rst:252\n#: 945d31669d104a67b4251a8a2ed5b133 c2cb9dc7bf694149806fb89443a430ba\nmsgid \"Finds optimal rect that contains the story `self`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:26 57ee0022377e4fbbaf74f70142af7217\nmsgid \":meth:`Story.fit_scale`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:27 f73eb5fd926e4dc5b66afcbd819851d6\nmsgid \":meth:`Story.fit_height`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:28 c5a858a25f3c4e45adf3c65f77eb35b4\nmsgid \":meth:`Story.fit_width`\"\nmsgstr \"\"\n\n#: ../../story-class.rst:31 555f8dfcf2c6423696e0a8111f5a202f\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../story-class.rst:37 834595e0caee413fb07ac0888c96cf9c\nmsgid \"\"\n\"Create a **story**, optionally providing HTML and CSS source. The HTML is\"\n\" parsed, and held within the Story as a DOM (Document Object Model).\"\nmsgstr \"\"\n\"**ストーリー** \"\n\"を作成します。オプションでHTMLとCSSのソースを提供できます。HTMLは解析され、ストーリー内でDOM（ドキュメントオブジェクトモデル）として保持されます。\"\n\n#: ../../story-class.rst:40 d9a1893bb0f14ccf9425ee58f9e72dfc\nmsgid \"\"\n\"This structure may be modified: content (text, images) may be added, \"\n\"copied, modified or removed by using methods of the :ref:`Xml` class.\"\nmsgstr \"この構造は変更できます。テキスト、画像などのコンテンツは、:ref:`Xml` クラスのメソッドを使用して追加、コピー、変更、または削除できます。\"\n\n#: ../../story-class.rst:43 f0a727b22fb84079ae4095e10e3c2373\nmsgid \"\"\n\"When finished, the **story** can be written to any device; in typical \"\n\"usage the device may be provided by a :ref:`DocumentWriter` to make new \"\n\"pages.\"\nmsgstr \"\"\n\"完了したら、**ストーリー** を任意のデバイスに書き込むことができます。通常の使用法では、デバイスは新しいページを生成するために \"\n\":ref:`DocumentWriter` によって提供されます。\"\n\n#: ../../story-class.rst:46 8bd0a736bc6749f68af7bee1912f8244\nmsgid \"Here are some general remarks:\"\nmsgstr \"以下は一般的な注意事項です：\"\n\n#: ../../story-class.rst:48 0f8c24eeaf79495db53a2614e831f91a\nmsgid \"\"\n\"The :ref:`Story` constructor parses and validates the provided HTML to \"\n\"create the DOM.\"\nmsgstr \":ref:`Story` コンストラクタは提供されたHTMLを解析し、検証してDOMを作成します。\"\n\n#: ../../story-class.rst:49 a8c9195a3cdf4ea9bc8acd4c4bc70ff2\nmsgid \"\"\n\"PyMuPDF provides a number of ways to manipulate the HTML source by \"\n\"providing access to the *nodes* of the underlying DOM. Documents can be \"\n\"completely built from ground up programmatically, or the existing DOM can\"\n\" be modified pretty arbitrarily. For details of this interface, please \"\n\"see the :ref:`Xml` class.\"\nmsgstr \"\"\n\"PyMuPDFは、基本的なDOMのノードへのアクセスを提供することでHTMLソースを操作する方法をいくつか提供しています。文書は完全にプログラム的に構築することも、既存のDOMをかなり任意に変更することもできます。このインターフェースの詳細については、:ref:`Xml`\"\n\" クラスをご覧ください。\"\n\n#: ../../story-class.rst:54 9a32acd1613e44cd87d2f73e6e3790e4\nmsgid \"\"\n\"If no (or no more) changes to the DOM are required, the story is ready to\"\n\" be laid out and to be fed to a series of devices (typically devices \"\n\"provided by a :ref:`DocumentWriter` to produce new pages).\"\nmsgstr \"\"\n\"DOMへの変更が必要ない（またはもう必要ない）場合、ストーリーはレイアウトが可能であり、新しいページを生成するために通常は \"\n\":ref:`DocumentWriter` によって提供されるデバイスに供給する準備ができています。\"\n\n#: ../../story-class.rst:57 de9ba211086b47eca447de9b6b5356c1\nmsgid \"\"\n\"The next step is to place the story and write it out. This can either be \"\n\"done directly, by looping around calling `place()` and `draw()`, or \"\n\"alternatively, the looping can handled for you using the `write()` or \"\n\"`write_stabilised()` methods. Which method you choose is largely a matter\"\n\" of taste.\"\nmsgstr \"\"\n\"次のステップは、ストーリーを配置して書き出すことです。これは、直接行うこともできます（`place()` と `draw()` \"\n\"を呼び出すことでループ処理することで）、または代替として `write()` または `write_stabilised()` \"\n\"メソッドを使用しても、ループ処理を自動化できます。どの方法を選択するかは主に好みの問題です。\"\n\n#: ../../story-class.rst:63 9615fc9723fb4897a2817bb454bf3149\nmsgid \"To work in the first of these styles, the following loop should be used:\"\nmsgstr \"最初のスタイルで作業するには、次のループを使用する必要があります：\"\n\n#: ../../story-class.rst:65 41867b8cd7bb4533b097c4aa2dd1a08e\nmsgid \"\"\n\"Obtain a suitable device to write to; typically by requesting a new, \"\n\"empty page from a :ref:`DocumentWriter`.\"\nmsgstr \"適切なデバイスを取得します。通常、:ref:`DocumentWriter` から新しい空のページを要求することで取得します。\"\n\n#: ../../story-class.rst:68 6e11ba83740c42a0814219e6c7bb4f2f\nmsgid \"\"\n\"Determine one or more rectangles on the page, that should receive \"\n\"**story** data. Note that not every page needs to have the same set of \"\n\"rectangles.\"\nmsgstr \"\"\n\"ページ上に **ストーリー** \"\n\"データを受け取る必要がある1つまたは複数の長方形を決定します。すべてのページが同じ長方形セットを持つ必要はないことに注意してください。\"\n\n#: ../../story-class.rst:71 27521b4c124e42ad873a6b98785cc18d\nmsgid \"\"\n\"Pass each rectangle to the **story** to place it, learning what part of \"\n\"that rectangle has been filled, and whether there is more story data that\"\n\" did not fit. This step can be repeated several times with adjusted \"\n\"rectangles until the caller is happy with the results.\"\nmsgstr \"\"\n\"各長方形を **ストーリー** \"\n\"に渡して配置し、その長方形のどの部分が埋まったか、また収まらなかったストーリーデータがあるかを学びます。このステップは、調整された長方形で何度も繰り返すことができ、呼び出し元が結果に満足するまで続けることができます。\"\n\n#: ../../story-class.rst:76 05e07028c7d3438d8b4564f851c3f6dd\nmsgid \"\"\n\"Optionally, at this point, we can request details of where interesting \"\n\"items have been placed, by calling the `element_positions()` method. \"\n\"Items are deemed to be interesting if their integer `heading` attribute \"\n\"is a non-zero (corresponding to HTML tags :htmlTag:`h1` - :htmlTag:`h6`),\"\n\" if their `id` attribute is not `None` (corresponding to HTML tag \"\n\":htmlTag:`id`), or if their `href` attribute is not `None` (responding to\"\n\" HTML tag :htmlTag:`href`). This can conveniently be used for automatic \"\n\"generation of a Table of Contents, an index of images or the like.\"\nmsgstr \"\"\n\"任意で、この段階で `element_positions()` \"\n\"メソッドを呼び出して、興味深いアイテムが配置された場所の詳細をリクエストすることができます。アイテムは、整数の `heading` \"\n\"属性がゼロでない場合（:htmlTag:`h1` - :htmlTag:`h6`）、id属性がNoneでない場合（:htmlTag:`id` \"\n\"に対応）、またはhref属性がNoneでない場合（:htmlTag:`href` \"\n\"に対応）に興味深いと見なされます。これは、目次、画像の索引などの自動生成に便利に使用できます。\"\n\n#: ../../story-class.rst:85 921092efac384debac3b3b54e0888f7f\nmsgid \"Next, draw that rectangle out to the device with the `draw()` method.\"\nmsgstr \"次に、`draw()` メソッドを使用してその長方形をデバイスに描画します。\"\n\n#: ../../story-class.rst:86 d36b5912ed30437198b3cf8b6a589d81\nmsgid \"\"\n\"If the most recent call to `place()` indicated that all the story data \"\n\"had fitted, stop now.\"\nmsgstr \"最も最近の `place()` の呼び出しが、すべてのストーリーデータが収まったことを示した場合、ここで停止します。\"\n\n#: ../../story-class.rst:88 c97e2fc9a4d7461f87a1b0a14181de80\nmsgid \"\"\n\"Otherwise, we can loop back. If there are more rectangles to be placed on\"\n\" the current device (page), we jump back to step 3 - if not, we jump back\"\n\" to step 1 to get a new device.\"\nmsgstr \"それ以外の場合、ループを戻すことができます。現在のデバイス（ページ）に配置するためにさらに長方形がある場合は、ステップ3に戻ります。長方形がない場合は、新しいデバイスを取得するためにステップ1に戻ります。\"\n\n#: ../../story-class.rst:91 58ca39dc2e03443689141076908acc02\nmsgid \"\"\n\"Alternatively, in the case where you are using a :ref:`DocumentWriter`, \"\n\"the `write()` or `write_stabilized()` methods can be used. These handle \"\n\"all the looping for you, in exchange for being provided with callbacks \"\n\"that control the behaviour (notably a callback that enumerates the \"\n\"rectangles/pages to use).\"\nmsgstr \"\"\n\"代わりに、:ref:`DocumentWriter` を使用している場合、`write()` または `write_stabilized()` \"\n\"メソッドを使用できます。これらは、動作を制御するコールバックが提供される代わりに、すべてのループ処理を処理します（特に使用する長方形/ページを列挙するコールバックが含まれます）。\"\n\n#: ../../story-class.rst:96 d2f8dc8f478942b69038e2d6d08a91fe\nmsgid \"\"\n\"Which part of the **story** will land on which rectangle / which page, is\"\n\" fully under control of the :ref:`Story` object and cannot be predicted.\"\nmsgstr \"\"\n\"**ストーリー** オブジェクトがどの部分がどの長方形/ページに配置されるかは、完全に :ref:`Story` \"\n\"オブジェクトの制御下にあり、予測することはできません。\"\n\n#: ../../story-class.rst:98 a231e6de936e448a93e21ff261ff8b39\nmsgid \"\"\n\"Images may be part of a **story**. They will be placed together with any \"\n\"surrounding text.\"\nmsgstr \"画像は **ストーリー** の一部となる可能性があります。画像は周囲のテキストと一緒に配置されます。\"\n\n#: ../../story-class.rst:99 10d7d8aa6a1c47998853f3879c904e3a\nmsgid \"\"\n\"Multiple stories may - independently from each other - write to the same \"\n\"page. For example, one may have separate stories for page header, page \"\n\"footer, regular text, comment boxes, etc.\"\nmsgstr \"複数のストーリーは、互いに独立して同じページに書き込むことができます。たとえば、ページヘッダー、ページフッター、通常のテキスト、コメントボックスなどの異なるストーリーを持つことができます。\"\n\n#: ../../story-class.rst 0c16913df99f4028a3870cbbbd910379\n#: 104010970e1342a5a900ab45a655ed39 1d65623102054847865dc9b04f9af565\n#: 456fb972dc3a4159952dd56ac1654590 47b053df5e8a436b92de3d583ae08f39\n#: 4c8c1511d6ca4de3b1ff6c538979f186 6cb09318829e49438c6c48b4681dfc29\n#: b0223ffe432744529572c26fc11dab80 c448f77784b245c2b24ce441b2722ea0\n#: fe317c7a33064ffea7eca66586243546\nmsgid \"Parameters\"\nmsgstr \"パラメーター:\"\n\n#: ../../story-class.rst:103 287c70d5ad0647e88290a1333ac631e0\nmsgid \"\"\n\"HTML source code. If omitted, a basic minimum is generated (see below). \"\n\"If provided, not a complete HTML document is needed. The in-built source \"\n\"parser will forgive (many / most) HTML syntax errors and also accepts \"\n\"HTML fragments like `\\\"<b>Hello, <i>World!</i></b>\\\"`.\"\nmsgstr \"\"\n\"HTMLソースコード。省略した場合、基本的な最小限のHTMLが生成されます（以下参照）。指定した場合、完全なHTML文書は必要ありません。組み込みのソースパーサは（多くの）HTML構文エラーを許容し、また\"\n\" `\\\"<b>Hello, <i>World!</i></b>\\\"` のようなHTMLフラグメントも受け入れます。\"\n\n#: ../../story-class.rst:108 63178e97fc4246158cbc7062597c4b93\nmsgid \"CSS source code. If provided, must contain valid CSS specifications.\"\nmsgstr \"CSSソースコード。指定する場合、有効なCSS仕様を含む必要があります。\"\n\n#: ../../story-class.rst:109 0cf5afcd55e544ad8724adfc4be7f3bb\nmsgid \"the default text font size.\"\nmsgstr \"デフォルトのテキストフォントサイズ。\"\n\n#: ../../story-class.rst:110 049536668785410f8df0dbcb3a1feddc\nmsgid \"\"\n\"an :ref:`Archive` from which to load resources for rendering. Currently \"\n\"supported resource types are images and text fonts. If omitted, the story\"\n\" will not try to look up any such data and may thus produce incomplete \"\n\"output.  .. note:: Instead of an actual archive, valid arguments for \"\n\"**creating** an :ref:`Archive` can also be provided -- in which case an \"\n\"archive will temporarily be constructed. So, instead of `story = \"\n\"pymupdf.Story(archive=pymupdf.Archive(\\\"myfolder\\\"))`, one can also \"\n\"shorter write `story = pymupdf.Story(archive=\\\"myfolder\\\")`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:110 51aa7bb6ca3c42a58819b3c524960306\nmsgid \"\"\n\"an :ref:`Archive` from which to load resources for rendering. Currently \"\n\"supported resource types are images and text fonts. If omitted, the story\"\n\" will not try to look up any such data and may thus produce incomplete \"\n\"output.\"\nmsgstr \"\"\n\"レンダリングのためのリソースをロードするための :ref:`Archive` \"\n\"。現在サポートされているリソースタイプは画像とテキストフォントです。省略した場合、ストーリーはそのようなデータを検索しようとはせず、不完全な出力を生成する可能性があります。\"\n\n#: ../../story-class.rst:112 a1bdde42988b468c929fe9fb82452451\nmsgid \"\"\n\"Instead of an actual archive, valid arguments for **creating** an \"\n\":ref:`Archive` can also be provided -- in which case an archive will \"\n\"temporarily be constructed. So, instead of `story = \"\n\"pymupdf.Story(archive=pymupdf.Archive(\\\"myfolder\\\"))`, one can also \"\n\"shorter write `story = pymupdf.Story(archive=\\\"myfolder\\\")`.\"\nmsgstr \"\"\n\"アーカイブの代わりに、:ref:`Archive` を一時的に **構築する** ための有効な引数も提供できます。したがって、`story = \"\n\"pymupdf.Story(archive=pymupdf.Archive(\\\"myfolder\\\"))` の代わりに、`story = \"\n\"pymupdf.Story(archive=\\\"myfolder\\\")` と短縮して記述することもできます。 \"\n\n#: ../../story-class.rst:116 e956d2bfd28841d7a04df00b07957e4f\nmsgid \"\"\n\"Calculate that part of the story's content, that will fit in the provided\"\n\" rectangle. The method maintains a pointer which part of the story's \"\n\"content has already been written and upon the next invocation resumes \"\n\"from that pointer's position.\"\nmsgstr \"ストーリーのコンテンツのうち、指定された長方形に収まる部分を計算します。このメソッドは、ストーリーのコンテンツのどの部分が既に書き込まれたかを示すポインタを維持し、次回の呼び出し時にそのポインタの位置から再開します。\"\n\n#: ../../story-class.rst:118 dc9976ea8ccc4d79bc216fce83ed6c9d\nmsgid \"\"\n\"layout the current part of the content to fit into this rectangle. This \"\n\"must be a sub-rectangle of the page's :ref:`MediaBox<Glossary_MediaBox>`.\"\nmsgstr \"\"\n\"現在のコンテンツをこの長方形に収めるためのレイアウト。これはページの :ref:`MediaBox<Glossary_MediaBox>` \"\n\"のサブ長方形でなければなりません。\"\n\n#: ../../story-class.rst daaea6c19d22421da33214020526af4d\nmsgid \"Return type\"\nmsgstr \"戻り値の型:\"\n\n#: ../../story-class.rst 954873df303d499d861dc708a54e6c20\nmsgid \"Returns\"\nmsgstr \"戻り値:\"\n\n#: ../../story-class.rst:121 4d9be8b010ca4b4b8dcc983949132f37\nmsgid \"\"\n\"a bool (int) `more` and a rectangle `filled`. If `more == 0`, all content\"\n\" of the story has been written, otherwise more is waiting to be written \"\n\"to subsequent rectangles / pages. Rectangle `filled` is the part of \"\n\"`where` that has actually been filled.\"\nmsgstr \"\"\n\"bool (int) `more` と、実際に `filled` 長方形を返します。`more == 0` \"\n\"の場合、ストーリーのすべてのコンテンツが書き込まれたことを意味し、それ以外の場合、`more` \"\n\"は次の長方形/ページに書き込むために待機しています。埋められた長方形は実際に埋められた `where` の一部です。\"\n\n#: ../../story-class.rst:125 a836145f2a5a4a75b589eefba9b24211\nmsgid \"Write the content part prepared by :meth:`Story.place` to the page.\"\nmsgstr \":meth:`Story.place` によって準備されたコンテンツの一部をページに書き込みます。\"\n\n#: ../../story-class.rst:127 152149a28a8b49acaaf7bfeadead892c\nmsgid \"\"\n\"the :ref:`Device` created by `dev = writer.begin_page(mediabox)`. The \"\n\"device knows how to call all MuPDF functions needed to write the content.\"\nmsgstr \"\"\n\"`dev = writer.begin_page(mediabox)` で作成された \"\n\":ref:`Device`。このデバイスは、コンテンツを書き込むために必要なすべてのMuPDF関数を呼び出す方法を知っています。\"\n\n#: ../../story-class.rst:128 35b2e7568db140c9abf31a7ee3ef7f54\nmsgid \"\"\n\"a matrix for transforming content when writing to the page. An example \"\n\"may be writing rotated text. The default means no transformation (i.e. \"\n\"the :ref:`Identity` matrix).\"\nmsgstr \"\"\n\"ページに書き込む際にコンテンツを変形させるための行列。テキストを回転させるなどの例が考えられます。デフォルトでは変換は行われず（つまり \"\n\":ref:`Identity` 行列）、コンテンツはそのまま書き込まれます。\"\n\n#: ../../story-class.rst:132 e9b8bfcac05244199692b5afb6d90ed0\nmsgid \"\"\n\"Let the Story provide positioning information about certain HTML elements\"\n\" once their place on the current page has been computed - i.e. invoke \"\n\"this method **directly after** :meth:`Story.place`.\"\nmsgstr \"\"\n\"ストーリーが現在のページ上で特定のHTML要素の配置情報を提供するようにします。つまり、:meth:`Story.place` の **直後に**\"\n\" このメソッドを呼び出します。\"\n\n#: ../../story-class.rst:134 e0021c2f17db417c8976fce48469b736\nmsgid \"\"\n\"*Story* will pass position information to *function*. This information \"\n\"can for example be used to generate a Table of Contents.\"\nmsgstr \"*Story* は位置情報を *関数* に渡します。この情報は、目次の生成などに便利に使用できます。\"\n\n#: ../../story-class.rst:136 27a5d6e27ace4870892e746111d4365b\nmsgid \"\"\n\"a Python function accepting an :class:`ElementPosition` object. It will \"\n\"be invoked by the Story object to process positioning information. The \"\n\"function **must** be a callable accepting exactly one argument.\"\nmsgstr \"\"\n\":class:`ElementPosition` \"\n\"オブジェクトを受け入れるPython関数。この関数は、位置情報を処理するためにStoryオブジェクトによって呼び出されます。**関数** \"\n\"は正確に1つの引数を受け入れるcallableである必要があります。\"\n\n#: ../../story-class.rst:137 08bda4472e0b457faada19c08c19734e\nmsgid \"\"\n\"an optional dictionary with any **additional** information that should be\"\n\" added to the :class:`ElementPosition` instance passed to `function`. \"\n\"Like for example the current output page number. Every key in this \"\n\"dictionary must be a string that conforms to the rules for a valid Python\"\n\" identifier. The complete set of information is explained below.\"\nmsgstr \"\"\n\"`function` に渡される :class:`ElementPosition` インスタンスに **追加** \"\n\"情報を追加するためのオプションの辞書。たとえば、現在の出力ページ番号などが含まれることがあります。この辞書のすべてのキーは、有効なPython識別子の規則に従う文字列である必要があります。情報の完全なセットは以下で説明されています。\"\n\n#: ../../story-class.rst:146 98941c7d778c4d34a3d76bb76b5739dc\nmsgid \"Rewind the story's document to the beginning for starting over its output.\"\nmsgstr \"ストーリーのドキュメントを最初に戻して、出力を再開します。\"\n\n#: ../../story-class.rst:150 2eaf3e53d3c34b20bd6b65526619e383\nmsgid \"\"\n\"The :htmlTag:`body` part of the story's DOM. This attribute contains the \"\n\":ref:`Xml` node of :htmlTag:`body`. All relevant content for PDF \"\n\"production is contained between \\\"<body>\\\" and \\\"</body>\\\".\"\nmsgstr \"\"\n\"ストーリーのDOMの :htmlTag:`body` 部分。この属性には :htmlTag:`body` の :ref:`Xml` \"\n\"ノードが含まれています。PDFの制作に関連するすべてのコンテンツは、「<body>」と「</body>」の間に含まれています。\"\n\n#: ../../story-class.rst:154 09a8579966ad4dd69d832b7cff35811b\nmsgid \"\"\n\"Places and draws Story to a `DocumentWriter`. Avoids the need for calling\"\n\" code to implement a loop that calls `Story.place()` and `Story.draw()` \"\n\"etc, at the expense of having to provide at least the `rectfn()` \"\n\"callback.\"\nmsgstr \"\"\n\"Storyを :ref:`DocumentWriter` に配置し、描画します。これにより、`Story.place()` および \"\n\"`Story.draw()` などを呼び出すループの実装が不要になりますが、`rectfn()` コールバックを少なくとも提供する必要があります。\"\n\n#: ../../story-class.rst:159 5194586e662141618935bdf29a379921\nmsgid \"a `DocumentWriter` or None.\"\nmsgstr \":ref:`DocumentWriter` または `None`。\"\n\n#: ../../story-class.rst:160 d62e010560f14bf1b7cd210ebf78b20c\n#, fuzzy\nmsgid \"\"\n\"a callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:  * mediabox: None or rect for new page. * rect: \"\n\"The next rect into which content should be placed. * ctm: None or a \"\n\"`Matrix`.\"\nmsgstr \"\"\n\"`(rect_num: int, filled: Rect)` を取り、`(mediabox, rect, ctm)` \"\n\"を返すcallable：mediabox\"\n\n#: ../../story-class.rst:160 ae5c5dc080b540f09ad256f10c2cf83d\nmsgid \"\"\n\"a callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:\"\nmsgstr \"`(rect_num: int, filled: Rect)` を取り、`(mediabox, rect, ctm)` を返すcallable：\"\n\n#: ../../story-class.rst:163 ../../story-class.rst:204\n#: 193ce6bab9f74a3a9cf1bbeaf3b2dc88 991faab1db1a4e479714af5b2e511e0e\n#, fuzzy\nmsgid \"mediabox: None or rect for new page.\"\nmsgstr \"新しいページ用の `None` またはrect。\"\n\n#: ../../story-class.rst:164 ../../story-class.rst:205\n#: 2c523120813f4975b82ffb2efb008126 cbe16d25e8e24253b41d04316f0700a3\n#, fuzzy\nmsgid \"rect: The next rect into which content should be placed.\"\nmsgstr \"コンテンツを配置する次の矩形。\"\n\n#: ../../story-class.rst:165 6068e757476744c2a2008edf19b650a1\n#, fuzzy\nmsgid \"ctm: None or a `Matrix`.\"\nmsgstr \"`None` または `Matrix`。\"\n\n#: ../../story-class.rst:166 54470f3ad61e4531aca719c848ecebb4\nmsgid \"\"\n\"None, or a callable taking `(position: ElementPosition)`:  * position:\"\n\"     An `ElementPosition` with an extra `.page_num` member. Typically \"\n\"called multiple times as we generate elements that are headings or have \"\n\"an id.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:166 0c1e37384309449d8a3f1aa31612af12\n#, fuzzy\nmsgid \"None, or a callable taking `(position: ElementPosition)`:\"\nmsgstr \"\"\n\"`None` または(ElementPosition)を取り、`(position: ElementPosition)`: \"\n\"positionを返すcallable：\"\n\n#: ../../story-class.rst:168 78f15911e52b455d87f6517e46edf76d\nmsgid \"position:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:169 8ba40e35c2734c1d8c5eb72cc71c82f4\nmsgid \"An `ElementPosition` with an extra `.page_num` member.\"\nmsgstr \"`.page_num` メンバーを持つ `ElementPosition`。\"\n\n#: ../../story-class.rst:170 9d3b6f846744442c8f1ebd5c03e1a944\nmsgid \"\"\n\"Typically called multiple times as we generate elements that are headings\"\n\" or have an id.\"\nmsgstr \"通常、見出しやIDを持つ要素を生成する際に複数回呼び出されます。\"\n\n#: ../../story-class.rst:172 0d6deb6dd4d9405ab38dff88ad1fc98f\nmsgid \"\"\n\"None, or a callable taking `(page_num, mediabox, dev, after)`; called at \"\n\"start (`after=0`) and end (`after=1`) of each page.\"\nmsgstr \"\"\n\"`None` または `(page_num, mediabox, dev, after)` \"\n\"を取り、各ページの開始(`after=0`)および終了（`after=1`）時に呼び出されます。\"\n\n#: ../../story-class.rst:178 a79665d597fb416d960734c83cfd6657\nmsgid \"\"\n\"Static method that does iterative layout of html content to a \"\n\"`DocumentWriter`.\"\nmsgstr \"htmlコンテンツを :ref:`DocumentWriter` に対して反復的にレイアウトするための静的メソッド。\"\n\n#: ../../story-class.rst:181 6fc706ddf1b648e68d59f87ae642ba3d\nmsgid \"\"\n\"For example this allows one to add a table of contents section while \"\n\"ensuring that page numbers are patched up until stable.\"\nmsgstr \"これにより、ページ番号が安定するまで目次セクションを追加したりすることができます。\"\n\n#: ../../story-class.rst:184 624160a14d984361bd0974171f55c924\nmsgid \"\"\n\"Repeatedly creates a new `Story` from `(contentfn(), user_css, em, \"\n\"archive)` and lays it out with internal call to `Story.write()`; uses a \"\n\"None writer and extracts the list of `ElementPosition`'s which is passed \"\n\"to the next call of `contentfn()`.\"\nmsgstr \"\"\n\"`(contentfn()、user_css、em、archive)` から新しい `Story` \"\n\"を繰り返し作成し、`Story.write()` への内部呼び出しでそれをレイアウトします。 `None` \"\n\"のライターを使用し、`ElementPosition` のリストを次回の `contentfn()` 呼び出しに渡します。\"\n\n#: ../../story-class.rst:190 4b831cab0cb845b08bcd23293dfacaff\nmsgid \"\"\n\"When the html from `contentfn()` becomes unchanged, we do a final \"\n\"iteration using `writer`.\"\nmsgstr \"`contentfn()` からのhtmlが変更されなくなると、`writer` を使用して最終的な反復処理を行います。\"\n\n#: ../../story-class.rst:193 fc2b4f5717ce43d49be5f534a63440f9\nmsgid \"A `DocumentWriter`.\"\nmsgstr \":ref:`DocumentWriter`。\"\n\n#: ../../story-class.rst:195 8156be2fda8e4081b5e9447ab8e0e84f\nmsgid \"\"\n\"A function taking a list of `ElementPositions` and returning a string \"\n\"containing html. The returned html can depend on the list of positions, \"\n\"for example with a table of contents near the start.\"\nmsgstr \"\"\n\"`ElementPositions` \"\n\"のリストを取り、htmlを含む文字列を返す関数。返されるhtmlは、位置のリストに依存する場合があります。たとえば、最初の近くに目次がある場合です。\"\n\n#: ../../story-class.rst:200 f67b52fd424e4dc68961c8310fcaa746\n#, fuzzy\nmsgid \"\"\n\"A callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:  * mediabox: None or rect for new page. * rect: \"\n\"The next rect into which content should be placed. * ctm: A `Matrix`.\"\nmsgstr \"\"\n\"`(rect_num: int, filled: Rect)` を取り、`(mediabox, rect, ctm)` \"\n\"を返すcallable：mediabox\"\n\n#: ../../story-class.rst:201 2619bfc1a11c4ae089bce95a0a0b388f\nmsgid \"\"\n\"A callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:206 893cb8063b414afaaced0a0058f0d3ab\n#, fuzzy\nmsgid \"ctm: A `Matrix`.\"\nmsgstr \":ref:`Matrix`。\"\n\n#: ../../story-class.rst:207 fa079791f265424f89482cae4560278b\nmsgid \"\"\n\"None, or a callable taking `(page_num, medibox, dev, after)`; called at \"\n\"start (`after=0`) and end (`after=1`) of each page.\"\nmsgstr \"\"\n\"`None` または `(page_num、medibox、dev、after)` \"\n\"を取り、各ページの開始（`after=0`）および終了（`after=1`）時に呼び出されます。\"\n\n#: ../../story-class.rst:212 1f50bce4bc934df3b5d624e1b672e8a7\nmsgid \"\"\n\"If true, we add unique ids to all header tags that don't already have an \"\n\"id. This can help automatic generation of tables of contents.\"\nmsgstr \"Trueの場合、idを持たないすべての見出しタグに一意のidを追加します。これは目次の自動生成に役立ちます\"\n\n#: ../../story-class.rst:216 4d3d89f8a84e4ddca5b6f49a19e7360f\nmsgid \"Returns:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:217 67ed7ea6343840ce8ca2af472e723907\nmsgid \"None.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:221 dc5ef0f369b64b56a861bebe37e7d740\nmsgid \"\"\n\"Similar to `write()` except that we don't have a `writer` arg and we \"\n\"return a PDF `Document` in which links have been created for each \"\n\"internal html link.\"\nmsgstr \"\"\n\"`write()` に類似していますが、`writer` 引数がなく、内部のHTMLリンクごとにリンクが作成されたPDF `Document` \"\n\"が返されます。\"\n\n#: ../../story-class.rst:227 f60fb57103404e4487a18f27456b9ac5\nmsgid \"\"\n\"Similar to `write_stabilized()` except that we don't have a `writer` arg \"\n\"and instead return a PDF `Document` in which links have been created for \"\n\"each internal html link.\"\nmsgstr \"\"\n\"`write_stabilized()` に類似していますが、`writer` \"\n\"引数がなく、代わりに各内部のHTMLリンクにリンクが作成されたPDF `Document` が返されます。\"\n\n#: ../../story-class.rst:233 06abc8ee0cef4e4998719c4d3848c318\nmsgid \"The result from a `Story.fit*()` method.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:235 f882cf97ed5e42b69f1212bd5c0d3b3e\nmsgid \"Members:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:237 05afdcff48b54e87a70244ac485320f6\nmsgid \"`big_enough`:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:238 296c3d062bc34a2f9826b3fe722423ed\nmsgid \"`True` if the fit succeeded.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:239 910160ef882e49209e123946968ad89d\nmsgid \"`filled`:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:240 2be02fcee76042b3b1e67242108c02d8\nmsgid \"From the last call to `Story.place()`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:241 7f3007c064224426bdeffe2f30577d5a\nmsgid \"`more`:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:242 14d98da06ba44fadacc3c05f8c88d916\nmsgid \"`False` if the fit succeeded.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:243 bea5727ffc6f4a0f9b4816919098061b\nmsgid \"`numcalls`:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:244 508bd595de3a4b6a87cf8cece9b67d36\nmsgid \"Number of calls made to `self.place()`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:245 0c4225d297644946b97fffd257cb3149\n#, fuzzy\nmsgid \"`parameter`:\"\nmsgstr \"パラメーター:\"\n\n#: ../../story-class.rst:246 a38a79d488cc413583a588ace44bad64\nmsgid \"The successful parameter value, or the largest failing value.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:247 e5e7d478999f4d3aa75cc2e4a0bf8ed2\nmsgid \"`rect`:\"\nmsgstr \"\"\n\n#: ../../story-class.rst:248 865655b3648b49e19a5b3683d5ac952c\nmsgid \"The rect created from `parameter`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:254 ../../story-class.rst:282\n#: ../../story-class.rst:304 ../../story-class.rst:325\n#: 13889911bf6e4b4099ac3db022c63ba7 181f41eeee2248529bcc9f4180a0fd2f\n#: 2a70154984d84fde9207702c6951f227 833e95a45bf24525a22b1bf7caedcfd7\nmsgid \"Returns a `Story.FitResult` instance.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:256 9f2d407c6f7447a384ccc54acb6bbb6d\nmsgid \"\"\n\"On success, the last call to `self.place()` will have been with the \"\n\"returned rectangle, so `self.draw()` can be used directly.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:259 723d3c893ffb40979529d0c13998947c\nmsgid \"\"\n\"A callable taking a floating point `parameter` and returning a \"\n\"`pymupdf.Rect()`. If the rect is empty, we assume the story will not fit \"\n\"and do not call `self.place()`.  Must guarantee that `self.place()` \"\n\"behaves monotonically when given rect `fn(parameter`) as `parameter` \"\n\"increases. This usually means that both width and height increase or stay\"\n\" unchanged as `parameter` increases.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:260 9507ed4935a0463eb2d74e2300c6e45c\nmsgid \"\"\n\"A callable taking a floating point `parameter` and returning a \"\n\"`pymupdf.Rect()`. If the rect is empty, we assume the story will not fit \"\n\"and do not call `self.place()`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:264 b8b210f2827f4137a23a52bb43be5a7d\nmsgid \"\"\n\"Must guarantee that `self.place()` behaves monotonically when given rect \"\n\"`fn(parameter`) as `parameter` increases. This usually means that both \"\n\"width and height increase or stay unchanged as `parameter` increases.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:268 a4dba85757184a2f88067b0d0bc2a5ac\nmsgid \"Minimum parameter to consider; `None` for -infinity.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:270 c3041af96355455e9dd9c1d8b9001d02\nmsgid \"Maximum parameter to consider; `None` for +infinity.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:272 50ba04ced3904450bbb765d580667a8a\nmsgid \"Maximum error in returned `parameter`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:274 ../../story-class.rst:295\n#: ../../story-class.rst:317 ../../story-class.rst:338\n#: 4560cdaee7304e68af9c9515d9baeeab 853d4b4eccc64445b4dadae224277597\n#: 9a97ca12c0fd4e4cad25cd646c9fd3a1 c27eb2778a574ddd9cdbb5da9e952da1\nmsgid \"If true we output diagnostics.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:279 4dca0fa3d9dc4d74a72be9a25b3042f5\nmsgid \"\"\n\"Finds smallest value `scale` in range `scale_min..scale_max` where `scale\"\n\" * rect` is large enough to contain the story `self`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:284 ../../story-class.rst:306\n#: 3e56c24499df4c63acde4cd29372549c c1836f4303104884b7f75d1c7d7f4c18\nmsgid \"width of rect.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:286 ../../story-class.rst:327\n#: 599c4470f82444f093e40776f0fc3088 d107736639a3470a838f7ae926a0c493\nmsgid \"height of rect.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:288 192ebb0b7d2c4255ae07cda187e1c04a\nmsgid \"Minimum scale to consider; must be >= 0.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:290 9becc562a2894913ac6b78b33fa618a8\nmsgid \"Maximum scale to consider, must be >= scale_min or `None` for infinite.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:293 b80e9c9c5a024ab9b415c43f695db382\nmsgid \"Maximum error in returned scale.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:300 20b042fb975b4ef38c6a275f58290800\nmsgid \"\"\n\"Finds smallest height in range `height_min..height_max` where a rect with\"\n\" size `(width, height)` is large enough to contain the story `self`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:308 de3278b094bd4069a6ade29bab864b2e\nmsgid \"Minimum height to consider; must be >= 0.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:310 d890a80ccfbc4767b155bf963080574b\nmsgid \"Maximum height to consider, must be >= height_min or `None` for infinite.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:313 ../../story-class.rst:334\n#: 345fc763c90942b3af9314cb53d3635c fb1f9d71eaf340dfb2d14dff3ccbaf8d\nmsgid \"`(x0, y0)` of rect.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:315 05ba2969245642aa9c5df4b5faa1c1c7\nmsgid \"Maximum error in returned height.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:322 2c063f96e3d24728acc052323d414f48\nmsgid \"\"\n\"Finds smallest width in range `width_min..width_max` where a rect with \"\n\"size `(width, height)` is large enough to contain the story `self`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:329 755a76f8bcad4f9c9b17627fb2dd2b92\nmsgid \"Minimum width to consider; must be >= 0.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:331 4a9bc91b4df64e0aae622c2fc204c366\nmsgid \"Maximum width to consider, must be >= width_min or `None` for infinite.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:336 a4d66b18a35f42759e36401ac18b5919\nmsgid \"Maximum error in returned width.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:343 d2d8c9c232984e92ab30e2dc905f7f7a\nmsgid \"Element Positioning CallBack function\"\nmsgstr \"要素位置コールバック関数\"\n\n#: ../../story-class.rst:345 a81639ecc64041979b5a57ccef510f75\nmsgid \"\"\n\"The callback function can be used to log information about story output. \"\n\"The function's access to the information is read-only: it has no way to \"\n\"influence the story's output.\"\nmsgstr \"コールバック関数は、ストーリーの出力に関する情報を記録するために使用できます。この関数は情報への読み取り専用アクセスを持ち、ストーリーの出力に影響を与える方法はありません。\"\n\n#: ../../story-class.rst:347 d63a34b1197048c0a8e7128565d99b11\nmsgid \"\"\n\"A typical loop for executing a story with using this method would look \"\n\"like this::\"\nmsgstr \"このメソッドを使用してストーリーを実行する典型的なループは次のようになります:\"\n\n#: ../../story-class.rst:379 022c24b9ecb142e4b995435e43d0abba\nmsgid \"Attributes of the ElementPosition class\"\nmsgstr \"ElementPosition クラスの属性\"\n\n#: ../../story-class.rst:380 eb9fd926dd144458ad966437c52bc9b3\nmsgid \"\"\n\"Exactly one parameter must be passed to the function provided by \"\n\":meth:`Story.element_positions`. It is an object with the following \"\n\"attributes:\"\nmsgstr \":meth:`Story.element_positions` で提供される関数に渡すパラメータは、次の属性を持つオブジェクトである必要があります。\"\n\n#: ../../story-class.rst:382 51f35390ddf549c49309c8e41b08fc0d\nmsgid \"\"\n\"The parameter passed to the `recorder` function is an object with the \"\n\"following attributes:\"\nmsgstr \"`recorder` 関数に渡されるパラメータは、次の属性を持つオブジェクトです。\"\n\n#: ../../story-class.rst:384 ea7a7e801d004da2946b291daf693c79\nmsgid \"`elpos.depth` (int) -- depth of this element in the box structure.\"\nmsgstr \"`elpos.depth` （int）– ボックス構造内でのこの要素の深さ。\"\n\n#: ../../story-class.rst:386 eedd651708ad4d08ab6358db8492fe86\nmsgid \"\"\n\"`elpos.heading` (int) -- the header level, 0 if no header, 1-6 for \"\n\":htmlTag:`h1` - :htmlTag:`h6`.\"\nmsgstr \"\"\n\"`elpos.heading` （int）– ヘッダーレベル、ヘッダーがない場合は0、 :htmlTag:`h1` - :htmlTag:`h6`\"\n\" に対して1-6。\"\n\n#: ../../story-class.rst:388 58c1d6c18dbc4defa9fdccf70fb9f5a1\n#, fuzzy\nmsgid \"\"\n\"`elpos.href` (str) -- value of the `href` attribute, or None if not \"\n\"defined.\"\nmsgstr \"`elpos.href` （str）– `href` 属性の値、または未定義の場合は `None`。\"\n\n#: ../../story-class.rst:390 085ae77bd6a0482e9bfed8909e66cc63\nmsgid \"`elpos.id` (str) -- value of the `id` attribute, or None if not defined.\"\nmsgstr \"`elpos.id` （str）– `id` 属性の値、または未定義の場合は `None`。\"\n\n#: ../../story-class.rst:392 6148773811f84de3837f6e84482b5a6f\nmsgid \"`elpos.rect` (tuple) -- element position on page.\"\nmsgstr \"`elpos.rect` （tuple）– ページ上の要素の位置。\"\n\n#: ../../story-class.rst:394 e46b041d8944429f8ec58070b71170c3\nmsgid \"`elpos.text` (str) -- immediate text of the element.\"\nmsgstr \"`elpos.text` （str）– 要素の直接のテキスト。\"\n\n#: ../../story-class.rst:396 10ae79dfd5114378b05c394821db2139\nmsgid \"\"\n\"`elpos.open_close` (int bit field) -- bit 0 set: opens element, bit 1 \"\n\"set: closes element. Relevant for elements that may contain other \"\n\"elements and thus may not immediately be closed after being created / \"\n\"opened.\"\nmsgstr \"\"\n\"`elpos.open_close` （int ビットフィールド）– \"\n\"ビット0がセットされている場合、要素を開く。ビット1がセットされている場合、要素を閉じる。他の要素を含む可能性がある要素に対して、即座に作成/開始された後にすぐに閉じられない要素に関連します。\"\n\n#: ../../story-class.rst:398 d06166cffa24405cbbc118345b121dc7\nmsgid \"`elpos.rect_num` (int) -- count of rectangles filled by the story so far.\"\nmsgstr \"`elpos.rect_num` （int）– これまでにストーリーで埋められた長方形の数。\"\n\n#: ../../story-class.rst:400 1559da9c2ea247b99415efc378836399\nmsgid \"\"\n\"`elpos.page_num` (int) -- page number; only present when using \"\n\"`pymupdf.Story.write*()` functions.\"\nmsgstr \"`elpos.page_num` （int）– ページ番号。`pymupdf.Story.write*()` 関数を使用する場合にのみ存在します。\"\n\n#: ../../footer.rst:60 c25ec66bf75249a58ca8ecc2e8d0184a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"a callable taking `(rect_num: int, \"\n#~ \"filled: Rect)` and returning `(mediabox, \"\n#~ \"rect, ctm)`:     mediabox:         None or \"\n#~ \"rect for new page.     rect:         The\"\n#~ \" next rect into which content should\"\n#~ \" be placed.     ctm:         None or \"\n#~ \"a `Matrix`.\"\n#~ msgstr \"\"\n\n#~ msgid \"mediabox:\"\n#~ msgstr \"\"\n\n#~ msgid \"rect:\"\n#~ msgstr \"\"\n\n#~ msgid \"ctm:\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"None, or a callable taking `(position:\"\n#~ \" ElementPosition)`: position:     An \"\n#~ \"`ElementPosition` with an extra `.page_num`\"\n#~ \" member. Typically called multiple times\"\n#~ \" as we generate elements that are \"\n#~ \"headings or have an id.\"\n#~ msgstr \"\"\n\n#~ msgid \".\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/supported-files-table.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2024.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.8\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2023-12-21 13:53+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/textpage.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 a689d6f014ae4b3e996f4ea1430fd7e2\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 fcaf663acdd64264ba54a9b09a7a053d\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 2384969b3a1a48ecb481ced21413e4ab\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../textpage.rst:7 b50883dcbbd2424db737f428b4204dc7\nmsgid \"TextPage\"\nmsgstr \"TextPage (テキストページ)\"\n\n#: ../../textpage.rst:9 6e81bba1ccf7481d8fc21ba0651cd715\nmsgid \"\"\n\"This class represents text and images shown on a document page. All \"\n\":ref:`MuPDF document types<Supported_File_Types>` are supported.\"\nmsgstr \"\"\n\"このクラスは、文書ページに表示されるテキストと画像を表します。すべての :ref:`MuPDF document \"\n\"types<Supported_File_Types>` がサポートされています。\"\n\n#: ../../textpage.rst:11 214a6f0b55b94183bb1a4fee5b003e96\nmsgid \"\"\n\"The usual ways to create a textpage are :meth:`DisplayList.get_textpage` \"\n\"and :meth:`Page.get_textpage`. Because there is a limited set of methods \"\n\"in this class, there exist wrappers in :ref:`Page` which are handier to \"\n\"use. The last column of this table shows these corresponding :ref:`Page` \"\n\"methods.\"\nmsgstr \"\"\n\"テキストページを作成する通常の方法は、:meth:`DisplayList.get_textpage` および \"\n\":meth:`Page.get_textpage` です。このクラスにはメソッドのセットが制限されているため、:ref:`Page` \"\n\"内にはより使いやすいラッパーが存在します。この表の最後の列には、対応する :ref:`Page` メソッドが示されています。\"\n\n#: ../../textpage.rst:13 8974c23cb16b4aa1b56189eff275c6fe\nmsgid \"For a description of what this class is all about, see Appendix 2.\"\nmsgstr \"このクラスに関する詳細な説明については、付録2を参照してください。\"\n\n#: ../../textpage.rst:16 a2ef271a41f24f089f82cb6c12de5544\nmsgid \"**Method**\"\nmsgstr \"**メソッド**\"\n\n#: ../../textpage.rst:16 5b00ef707e3f4637b40a48d5d422e544\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../textpage.rst:16 c508a7963cbb4c77ab691615841f72fb\nmsgid \"page get_text or search method\"\nmsgstr \"page get_textまたはsearchメソッド\"\n\n#: ../../textpage.rst:18 24790f911d6d4af491f3f0d4a90c5e4e\nmsgid \":meth:`~.extractText`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:18 56f3e18347124df290f5bb60a9c6ab6f\nmsgid \"extract plain text\"\nmsgstr \"プレーンテキストを抽出します\"\n\n#: ../../textpage.rst:18 ../../textpage.rst:19 292888a082e041b8820ab5b47243fa82\n#: 587fc832f8b941329c209fc49dd67b0b\nmsgid \"\\\"text\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:19 062786889a8a4ad586cea1bcbfa2bb0d\nmsgid \":meth:`~.extractTEXT`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:19 e0b7b72c38c746a4b7c512c66b738f1c\nmsgid \"synonym of previous\"\nmsgstr \"前述の同義語\"\n\n#: ../../textpage.rst:20 98ed5aa1b9884de7858b147ee2bd2f0c\nmsgid \":meth:`~.extractBLOCKS`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:20 35f208a1af3c4c5c8f17069788e702ca\nmsgid \"plain text grouped in blocks\"\nmsgstr \"ブロックにグループ化されたプレーンテキスト\"\n\n#: ../../textpage.rst:20 6318f67c8f964981b4a354142092e102\nmsgid \"\\\"blocks\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:21 07a1408ddaf24b158ac6dc5d9fcc8115\nmsgid \":meth:`~.extractWORDS`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:21 52e0458f76ee4231a07829bb051b29ac\nmsgid \"all words with their bbox\"\nmsgstr \"すべての単語とそのバウンディングボックス\"\n\n#: ../../textpage.rst:21 2efe7bf211e74dc4a731d81393a6e10c\nmsgid \"\\\"words\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:22 7c9da76988c243e0b79a0f2a5c23cee7\nmsgid \":meth:`~.extractHTML`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:22 269dcb92057443e096b0cd366dd7ba29\nmsgid \"page content in HTML format\"\nmsgstr \"HTML形式のページコンテンツ\"\n\n#: ../../textpage.rst:22 d24ee0e44d5c45e59f125aacaccf3465\nmsgid \"\\\"html\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:23 388abf5016ba455c959cdd56009a4499\nmsgid \":meth:`~.extractXHTML`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:23 b09f5acedceb4611bc7ea51121eb9bb2\nmsgid \"page content in XHTML format\"\nmsgstr \"XHTML形式のページコンテンツ\"\n\n#: ../../textpage.rst:23 416a7019408e492da02693ffd6949a7a\nmsgid \"\\\"xhtml\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:24 ee85d9810eff41caa760d9ffb2a4fed2\nmsgid \":meth:`~.extractXML`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:24 8ab1b023d2cc42b6ae74cb3b92b8d797\nmsgid \"page text in XML format\"\nmsgstr \"XML形式のページテキスト\"\n\n#: ../../textpage.rst:24 fd3d4026c2c045b6a5dc724cd3c1cd16\nmsgid \"\\\"xml\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:25 a0d67d42d20d483ba2dc7c60232c4262\nmsgid \":meth:`~.extractDICT`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:25 ../../textpage.rst:27 1867105a7ef841cd809711e47e335c93\n#: 8cfc8dba8d384e489e2948bcbd7adaca\nmsgid \"page content in *dict* format\"\nmsgstr \"*辞書* 形式のページコンテンツ\"\n\n#: ../../textpage.rst:25 8159466e656146a38f47f43f6bdcb810\nmsgid \"\\\"dict\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:26 1d75b88f1edb442898ea8017de3492d7\nmsgid \":meth:`~.extractJSON`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:26 ../../textpage.rst:28 7480fba67d534ecc8956acf7902d5aed\n#: 82d01a9dbb1d488198ecd836fed442ff\nmsgid \"page content in JSON format\"\nmsgstr \"JSON形式のページコンテンツ\"\n\n#: ../../textpage.rst:26 78d2d0b851b240db8420aa1f8c823676\nmsgid \"\\\"json\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:27 1ade4b09c9674544bb58977574f5d593\nmsgid \":meth:`~.extractRAWDICT`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:27 3155e2902bcd4713aa47e4919ec46081\nmsgid \"\\\"rawdict\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:28 b5f0e031790f497694abb5caa6eee204\nmsgid \":meth:`~.extractRAWJSON`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:28 9b7e2e49823242bf83ea6a25986488d0\nmsgid \"\\\"rawjson\\\"\"\nmsgstr \"\"\n\n#: ../../textpage.rst:29 c2c9458e9c4a490087a519b61ecc5b19\nmsgid \":meth:`~.search`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:29 ee8c8a71aa524335969fbb8af60b211e\nmsgid \"Search for a string in the page\"\nmsgstr \"ページ内の文字列を検索します\"\n\n#: ../../textpage.rst:29 f79465ca7ff14a0a80fc365911c70bf6\nmsgid \":meth:`Page.search_for`\"\nmsgstr \"\"\n\n#: ../../textpage.rst:32 083eef252c154937ae0bc85aa81aff68\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../textpage.rst:40 f33111b086ad4d72980c782edd305dd0\nmsgid \"\"\n\"Return a string of the page's complete text. The text is UTF-8 unicode \"\n\"and in the same sequence as specified at the time of document creation.\"\nmsgstr \"ページの完全なテキストの文字列を返します。テキストはUTF-8ユニコードで、文書作成時に指定された順序と同じです。\"\n\n#: ../../textpage.rst 3e9d1669f2fe4f15ab3177563f0420e3\n#: 4bd4b9fa21ed426188fe213d2241f4ac 720def9977a743fdb77d7caeb93f8e63\n#: aea747bd7d624e70bc7def00d62df838 ca24753a6b21474daba199227cbdb7cd\n#: d0072bc05d7144aca56767bfde82c6a9 e1647eb182054d70be24b2cc9c6381ca\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../textpage.rst:42 ../../textpage.rst:85 ../../textpage.rst:93\n#: ../../textpage.rst:113 ../../textpage.rst:121\n#: 053cd209c0cd44b08367efe95d323dcb 2e3408186db64af29672df98a2541c3a\n#: 88f4b7d0b3014f8ab6a88c7157c764d9 eafc202f0101431bbd82bb8f066f24c2\n#: f7da0622405347bcb10099abdba152a3\nmsgid \"\"\n\"(new in v1.19.1) sort the output by vertical, then horizontal \"\n\"coordinates. In many cases, this should suffice to generate a \\\"natural\\\"\"\n\" reading order.\"\nmsgstr \"\"\n\n#: ../../textpage.rst 07f5f0a7fa5f4efbb1093cd496e1425a\n#: 0f27872a10dd46fda6c8e7ecaf77c92b 34621dc4778249c49fbd4c5f8fd2fd39\n#: 4c8745e920b8430fadff84a8e977a147 5081234f6b32451d915cc94583c1d60e\n#: 9a9a5268dcfc421cb4ca9b69e5030ee1 9f3241fa28914e49a481723379042cd8\n#: c0b2e445162446e1b4a2e0eb834ac7ca f3b8d685f26e44edbe5e23bac745020d\n#: f63537f76faf47c884089748bdcbcd8b f8803c61a6fc41fe89a08237112d6d49\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../textpage.rst:49 63307d556a584ea19173a54596c7f880\nmsgid \"\"\n\"Textpage content as a list of text lines grouped by block. Each list \"\n\"items looks like this::\"\nmsgstr \"テキストページの内容を、ブロックごとにグループ化されたテキスト行のリストとして返します。各リストアイテムは次のようになります::\"\n\n#: ../../textpage.rst:53 78718be495234f9dbfa93e48e16d1e13\nmsgid \"\"\n\"The first four entries are the block's bbox coordinates, *block_type* is \"\n\"1 for an image block, 0 for text. *block_no* is the block sequence \"\n\"number. Multiple text lines are joined via line breaks.\"\nmsgstr \"\"\n\"最初の4つのエントリはブロックのbbox座標で、*ブblock_type* は画像ブロックの場合は1、テキストの場合は0です。*block_no*\"\n\" はブロックのシーケンス番号です。複数のテキスト行は改行で結合されます。\"\n\n#: ../../textpage.rst:55 12f402e2e12346f8b7dd871f590f3197\nmsgid \"\"\n\"For an image block, its bbox and a text line with some image meta \"\n\"information is included -- **not the image content**.\"\nmsgstr \"画像ブロックの場合、そのbboxと画像メタ情報を含むテキスト行が含まれますが、**画像の内容は含まれません**。\"\n\n#: ../../textpage.rst:57 fb2f6c324124423bb74dbd2e4b974806\nmsgid \"\"\n\"This is a high-speed method with just enough information to output plain \"\n\"text in desired reading sequence.\"\nmsgstr \"これは、必要な読み取り順序でプレーンテキストを出力するのに十分な情報を持つ高速なメソッドです。\"\n\n#: ../../textpage.rst:63 cfb05f044359435fb061d158cb6ef21e\nmsgid \"Changed in v1.23.5: added `delimiters` parameter\"\nmsgstr \"\"\n\n#: ../../textpage.rst:65 e3116b1baa374ce2b67b6002aaae107d\nmsgid \"\"\n\"Textpage content as a list of single words with bbox information. An item\"\n\" of this list looks like this::\"\nmsgstr \"テキストページの内容を、bbox情報を持つ単語のリストとして返します。このリストのアイテムは次のようになります::\"\n\n#: ../../textpage.rst:69 6f56fac0469e45afa313a96110815e53\nmsgid \"\"\n\"(new in v1.23.5) use these characters as *additional* word separators. By\"\n\" default, all white spaces (including the non-breaking space `0xA0`) \"\n\"indicate start and end of a word. Now you can specify more characters \"\n\"causing this. For instance, the default will return \"\n\"`\\\"john.doe@outlook.com\\\"` as **one** word. If you specify \"\n\"`delimiters=\\\"@.\\\"` then the **four** words `\\\"john\\\"`, `\\\"doe\\\"`, \"\n\"`\\\"outlook\\\"`, `\\\"com\\\"` will be returned. Other possible uses include \"\n\"ignoring punctuation characters `delimiters=string.punctuation`. The \"\n\"\\\"word\\\" strings will not contain any delimiting character.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:71 f122cb9dbcfb43fb8cd911d4aabb4817\n#, fuzzy\nmsgid \"\"\n\"This is a high-speed method which e.g. allows extracting text from within\"\n\" given areas or recovering the text reading sequence.\"\nmsgstr \"\"\n\"スペースで区切られたすべてが *「単語」* \"\n\"として扱われます。これは、指定された領域内からテキストを抽出したり、テキストの読み取り順序を復元したりするのに適した高速なメソッドです。\"\n\n#: ../../textpage.rst:77 9fd59d1b4ce240e7ab72d24d4bfe0b1d\nmsgid \"\"\n\"Textpage content as a string in HTML format. This version contains \"\n\"complete formatting and positioning information. Images are included \"\n\"(encoded as base64 strings). You need an HTML package to interpret the \"\n\"output in Python. Your internet browser should be able to adequately \"\n\"display this information, but see :ref:`HTMLQuality`.\"\nmsgstr \"\"\n\"HTML形式の文字列としてのテキストページの内容を返します。このバージョンには完全なフォーマットと位置情報が含まれています。画像も含まれており（base64文字列としてエンコードされています）、Pythonで出力を解釈するためにはHTMLパッケージが必要です。インターネットブラウザはこの情報を適切に表示できるはずですが、:ref:`HTMLQuality`\"\n\" を参照してください。\"\n\n#: ../../textpage.rst:83 a07e225c4bf3412585128a2fb86b8200\nmsgid \"\"\n\"Textpage content as a Python dictionary. Provides same information detail\"\n\" as HTML. See below for the structure.\"\nmsgstr \"TextPageの内容をPythonの辞書として取得します。HTMLと同じ情報の詳細を提供します。構造については以下を参照してください。\"\n\n#: ../../textpage.rst:91 3c7dcaacfe924c9ab076958b43f75600\nmsgid \"\"\n\"Textpage content as a JSON string. Created by \"\n\"`json.dumps(TextPage.extractDICT())`. It is included for backlevel \"\n\"compatibility. You will probably use this method ever only for outputting\"\n\" the result to some file. The  method detects binary image data and \"\n\"converts them to base64 encoded strings.\"\nmsgstr \"\"\n\"TextPageの内容をJSON形式の文字列として取得します。`json.dumps(TextPage.extractDICT())` \"\n\"によって作成されます。これは過去の互換性のために含まれています。おそらく、結果をファイルに出力する際にのみこのメソッドを使用するでしょう。このメソッドはバイナリ画像データを検出し、それらをBase64エンコードされた文字列に変換します。\"\n\n#: ../../textpage.rst:99 87f36a88ced6410383dcdafa2979eae5\nmsgid \"\"\n\"Textpage content as a string in XHTML format. Text information detail is \"\n\"comparable with :meth:`extractTEXT`, but also contains images (base64 \"\n\"encoded). This method makes no attempt to re-create the original visual \"\n\"appearance.\"\nmsgstr \"\"\n\"TextPageの内容をXHTML形式の文字列として取得します。テキスト情報の詳細は :meth:`extractTEXT` \"\n\"と比較できますが、画像も含まれます（Base64エンコードされています）。このメソッドは元の視覚的な外観を再作成しようとしません。\"\n\n#: ../../textpage.rst:105 ce4a584473674c4e91533c25a532fe15\nmsgid \"\"\n\"Textpage content as a string in XML format. This contains complete \"\n\"formatting information about every single character on the page: font, \"\n\"size, line, paragraph, location, color, etc. Contains no images. You need\"\n\" an XML package to interpret the output in Python.\"\nmsgstr \"TextPageの内容をXML形式の文字列として取得します。これにはページ上の各文字に関する完全なフォーマット情報が含まれています：フォント、サイズ、行、段落、位置、色など。画像は含まれていません。Pythonで出力を解釈するにはXMLパッケージが必要です。\"\n\n#: ../../textpage.rst:111 53dc5f5e5cc04c54a952877ba4755541\nmsgid \"\"\n\"Textpage content as a Python dictionary -- technically similar to \"\n\":meth:`extractDICT`, and it contains that information as a subset \"\n\"(including any images). It provides additional detail down to each \"\n\"character, which makes using XML obsolete in many cases. See below for \"\n\"the structure.\"\nmsgstr \"\"\n\"TextPageの内容をPythonの辞書として取得します。技術的には :meth:`extractDICT` \"\n\"と類似しており、その情報をサブセットとして含みます（画像も含まれます）。詳細については以下を参照してください。\"\n\n#: ../../textpage.rst:119 33863035deb9499b8feb6d00b3064acb\nmsgid \"\"\n\"Textpage content as a JSON string. Created by \"\n\"`json.dumps(TextPage.extractRAWDICT())`. You will probably use this \"\n\"method ever only for outputting the result to some file. The  method \"\n\"detects binary image data and converts them to base64 encoded strings.\"\nmsgstr \"\"\n\"TextPageの内容をJSON形式の文字列として取得します。`json.dumps(TextPage.extractRAWDICT())` \"\n\"によって作成されます。おそらく、結果をファイルに出力する際にのみこのメソッドを使用するでしょう。このメソッドはバイナリ画像データを検出し、それらをBase64エンコードされた文字列に変換します。\"\n\n#: ../../textpage.rst:127 209053b84b6545e3994a163287facefa\nmsgid \"Changed in v1.18.2\"\nmsgstr \"変更内容 v1.18.2\"\n\n#: ../../textpage.rst:129 05ffbacb61c7489882f082b48886e8d5\nmsgid \"Search for *string* and return a list of found locations.\"\nmsgstr \"*文字列* を検索し、見つかった位置のリストを返します。\"\n\n#: ../../textpage.rst:131 c71683b946f54d84aff575da2005613b\nmsgid \"\"\n\"the string to search for. Upper and lower cases will all match if needle \"\n\"consists of ASCII letters only -- it does not yet work for \\\"Ä\\\" versus \"\n\"\\\"ä\\\", etc.\"\nmsgstr \"\"\n\"検索対象の文字列。ASCII文字だけで構成されている場合、大文字と小文字はすべて一致します。これはまだ、例えば  \\\"Ä\\\" と \\\"ä\\\" \"\n\"のような場合には機能しません。\"\n\n#: ../../textpage.rst:132 0f1af98486ec43429066d8c48e3dc958\nmsgid \"return quadrilaterals instead of rectangles.\"\nmsgstr \"長方形の代わりに四辺形を返すかどうか。\"\n\n#: ../../textpage.rst 943e3f54b51f470ba6d34411ccdabcd3\nmsgid \"Returns\"\nmsgstr \"\"\n\n#: ../../textpage.rst:134 89e19eb80ccd4b318611f268b0f75d7e\nmsgid \"\"\n\"a list of :ref:`Rect` or :ref:`Quad` objects, each surrounding a found \"\n\"*needle* occurrence. As the search string may contain spaces, its parts \"\n\"may be found on different lines. In this case, more than one rectangle \"\n\"(resp. quadrilateral) are returned. **(Changed in v1.18.2)** The method \"\n\"**now supports dehyphenation**, so it will find e.g. \\\"method\\\", even if \"\n\"it was hyphenated in two parts \\\"meth-\\\" and \\\"od\\\" across two lines. The\"\n\" two returned rectangles will contain \\\"meth\\\" (no hyphen) and \\\"od\\\".\"\nmsgstr \"\"\n\"見つかった *needle* の出現箇所を囲む :ref:`Rect` または :ref:`Quad` \"\n\"オブジェクトのリスト。検索文字列にはスペースが含まれる可能性があるため、その部分が異なる行に存在することがあります。この場合、複数の長方形（または四辺形）が返されます\"\n\" **（v1.18.2 で変更）** 。このメソッドは **今ではハイフネーションに対応しており** 、例えば \\\"method\\\" が \"\n\"\\\"meth-\\\" と \\\"od\\\" という2つの部分に分かれている場合でも、\\\"meth\\\"（ハイフンなし）と \\\"od\\\" \"\n\"の2つの長方形が含まれます。\"\n\n#: ../../textpage.rst:136 c134a9fb178648ae8bab433d54e37e2b\nmsgid \"**Overview of changes in v1.18.2:**\"\nmsgstr \"**v1.18.2 での変更内容の概要：**\"\n\n#: ../../textpage.rst:138 d9a3438955224e5685de548903667d74\nmsgid \"The `hit_max` parameter has been removed: all hits are always returned.\"\nmsgstr \"`hit_max` パラメータが削除され、すべてのヒットが常に返されます。\"\n\n#: ../../textpage.rst:139 c687c9305d954f6eaea257e2fe5bbe58\nmsgid \"\"\n\"The `rect` parameter of the :ref:`TextPage` is now respected: only text \"\n\"inside this area is examined. Only characters with fully contained bboxes\"\n\" are considered. The wrapper method :meth:`Page.search_for` \"\n\"correspondingly supports a *clip* parameter.\"\nmsgstr \"\"\n\":ref:`TextPage` の `rect` パラメータが尊重され、この領域内のテキストのみが検査されます。完全に含まれる bboxes \"\n\"を持つ文字のみが考慮されます。:meth:`Page.search_for` のラッパーメソッドも対応するクリップパラメータをサポートしています。\"\n\n#: ../../textpage.rst:140 ec9e270e430341a88939c174a0e838a3\nmsgid \"**Hyphenated words** are now found.\"\nmsgstr \"**ハイフネーションされた単語** も見つかります。\"\n\n#: ../../textpage.rst:141 595b14cd29774ef49fd1666b1d37dbb7\nmsgid \"\"\n\"**Overlapping rectangles** in the same line are now automatically joined.\"\n\" We assume that such separations are an artifact created by multiple \"\n\"marked content groups, containing parts of the same search needle.\"\nmsgstr \"\"\n\"同じ行内の **重複する長方形** \"\n\"は自動的に結合されます。このような分割は、同じ検索対象の一部を含む複数のマークコンテンツグループによって作成されたアーティファクトと仮定されます。\"\n\n#: ../../textpage.rst:143 7b283f04f24544e18dc95d6f698f1a39\nmsgid \"\"\n\"Example Quad versus Rect: when searching for needle \\\"pymupdf\\\", then the\"\n\" corresponding entry will either be the blue rectangle, or, if *quads* \"\n\"was specified, the quad *Quad(ul, ur, ll, lr)*.\"\nmsgstr \"\"\n\"例：Quad 対 Rect：needle \\\"pymupdf\\\" を検索する場合、対応するエントリは青い長方形であるか、*quads* \"\n\"が指定された場合は四辺形 *Quad(ul, ur, ll, lr)* になります。\"\n\n#: ../../textpage.rst:149 22015cb6553240db9caee4c5d4d0a06b\nmsgid \"\"\n\"The rectangle associated with the text page. This either equals the \"\n\"rectangle of the creating page or the `clip` parameter of \"\n\":meth:`Page.get_textpage` and text extraction / searching methods.\"\nmsgstr \"\"\n\"テキストページに関連付けられた矩形。これは、作成ページの矩形または :meth:`Page.get_textpage` \"\n\"およびテキスト抽出/検索メソッドの `clip` パラメーターと一致する場合があります。\"\n\n#: ../../textpage.rst:151 e4d7797e393d49f38a2ad6066b720a21\nmsgid \"\"\n\"The output of text searching and most text extractions **is restricted to\"\n\" this rectangle**. (X)HTML and XML output will however always extract the\"\n\" full page.\"\nmsgstr \"\"\n\"テキスト検索およびほとんどのテキスト抽出の出力は \"\n\"**この矩形に制限されます**。ただし、(X)HTMLおよびXMLの出力は常にフルページを抽出します。\"\n\n#: ../../textpage.rst:156 746d4f0331d74f5eb4b706ab194b8b02\nmsgid \"Structure of Dictionary Outputs\"\nmsgstr \"辞書出力の構造\"\n\n#: ../../textpage.rst:157 ae8559712aa84a3b8f3abc14fba42605\nmsgid \"\"\n\"Methods :meth:`TextPage.extractDICT`, :meth:`TextPage.extractJSON`, \"\n\":meth:`TextPage.extractRAWDICT`, and :meth:`TextPage.extractRAWJSON` \"\n\"return dictionaries, containing the page's text and image content. The \"\n\"dictionary structures of all four methods are almost equal. They strive \"\n\"to map the text page's information hierarchy of blocks, lines, spans and \"\n\"characters as precisely as possible, by representing each of these by its\"\n\" own sub-dictionary:\"\nmsgstr \"\"\n\":meth:`TextPage.extractDICT`、:meth:`TextPage.extractJSON` \"\n\"、:meth:`TextPage.extractRAWDICT` 、:meth:`TextPage.extractRAWJSON` \"\n\"は、ページのテキストおよび画像コンテンツを含む辞書を返します。これらの4つのメソッドの辞書構造はほぼ同じです。これらは、ブロック、行、スパン、文字の情報階層をテキストページにできるだけ正確にマップし、各要素を独自のサブ辞書で表現することを目指しています。\"\n\n#: ../../textpage.rst:159 1fc549b40ec54504aba36b49e614c7cc\nmsgid \"A **page** consists of a list of **block dictionaries**.\"\nmsgstr \"**ページ** は **ブロック辞書** のリストから構成されます。\"\n\n#: ../../textpage.rst:160 531deb445eda49c78ee0170f577f2f93\nmsgid \"A (text) **block** consists of a list of **line dictionaries**.\"\nmsgstr \"(テキスト) **ブロック** は、**行辞書** のリストから構成されます。\"\n\n#: ../../textpage.rst:161 5d0d26a55df64fb0bc4619f73f865415\nmsgid \"A **line** consists of a list of **span dictionaries**.\"\nmsgstr \"**行** は、**スパン辞書** のリストから構成されます。\"\n\n#: ../../textpage.rst:162 d297bff2aae540828c971d533f6fe3bb\nmsgid \"\"\n\"A **span** either consists of the text itself or, for the RAW variants, a\"\n\" list of **character dictionaries**.\"\nmsgstr \"**スパン** は、テキスト自体またはRAWバリアントの場合、**文字辞書** のリストから構成されます。\"\n\n#: ../../textpage.rst:163 37000c1f71684c77a812407e7849a0e0\nmsgid \"\"\n\"RAW variants: a **character** is a dictionary of its origin, bbox and \"\n\"unicode.\"\nmsgstr \"RAWバリアント：**文字** はその起源、bbox、およびUnicodeの辞書です。\"\n\n#: ../../textpage.rst:165 192df2422b5e482bbb29f7afc93e8cdc\nmsgid \"\"\n\"All PyMuPDF geometry objects herein (points, rectangles, matrices) are \"\n\"represented by there **\\\"like\\\"** formats: a :data:`rect_like` *tuple* is\"\n\" used instead of a :ref:`Rect`, etc. The reasons for this are performance\"\n\" and memory considerations:\"\nmsgstr \"\"\n\"ここでのすべてのPyMuPDFジオメトリオブジェクト（ポイント、矩形、行列）は、:data:`rect_like` *タプル* の形式で \"\n\":ref:`Rect` などの代わりに使用されます。これは、パフォーマンスとメモリの考慮事項からです。\"\n\n#: ../../textpage.rst:167 517e734e4772478cb6b1bc32cab2ab16\nmsgid \"\"\n\"This code is written in C, where Python tuples can easily be generated. \"\n\"The geometry objects on the other hand are defined in Python source only.\"\n\" A conversion of each Python tuple into its corresponding geometry object\"\n\" would add significant -- and largely unnecessary -- execution time.\"\nmsgstr \"\"\n\"このコードはCで書かれており、Pythonタプルは簡単に生成できます。一方、ジオメトリオブジェクトはPythonソースでのみ定義されています。 \"\n\"各Pythonタプルを対応するジオメトリオブジェクトに変換することは、実行時間を大幅に（かつ不必要に）増加させるでしょう。\"\n\n#: ../../textpage.rst:168 a7f4b55b2bb84753bc138ab3a04c2f8a\nmsgid \"\"\n\"A 4-tuple needs about 168 bytes, the corresponding :ref:`Rect` 472 bytes \"\n\"- almost three times the size. A \\\"dict\\\" dictionary for a text-heavy \"\n\"page contains 300+ bbox objects -- which thus require about 50 KB storage\"\n\" as 4-tuples versus 140 KB as :ref:`Rect` objects. A \\\"rawdict\\\" output \"\n\"for such a page will however contain **4 to 5 thousand** bboxes, so in \"\n\"this case we talk about 750 KB versus 2 MB.\"\nmsgstr \"\"\n\"4つのタプルは約168バイト、対応する :ref:`Rect` は472バイトです - \"\n\"サイズのほぼ3倍です。テキストが豊富なページの「dict」辞書には300以上のbboxオブジェクトが含まれているため、これらは4タプルとして約50\"\n\" KBのストレージを必要としますが、:ref:`Rect` オブジェクトでは約140 \"\n\"KBです。このようなページの「rawdict」出力は、**4,000から5,000** のbboxを含む場合がありますので、この場合は750 \"\n\"KB対2 MBとなります。\"\n\n#: ../../textpage.rst:170 bbdd6aa883a447c5b6bbb24a389b7944\nmsgid \"\"\n\"Please also note, that only **bboxes** (= :data:`rect_like` 4-tuples) are\"\n\" returned, whereas a :ref:`TextPage` actually has the **full position \"\n\"information** -- in :ref:`Quad` format. The reason for this decision is \"\n\"again a memory consideration: a :data:`quad_like` needs 488 bytes (3 \"\n\"times the size of a :data:`rect_like`). Given the mentioned amounts of \"\n\"generated bboxes, returning :data:`quad_like` information would have a \"\n\"significant impact.\"\nmsgstr \"\"\n\"また、注意してください。 **bboxes** （rect_like 4タプル）のみが返され、:ref:`TextPage` には \"\n\"**完全な位置情報** が含まれていることです - Quad形式で。これはメモリの考慮事項です。:data:`quad_like` \"\n\"には488バイト（:data:`rect_like` \"\n\"の3倍のサイズ）が必要です。言及した数の生成されたbboxを考えると、:data:`quad_like` \"\n\"情報を返すことは重大な影響を与えるでしょう。\"\n\n#: ../../textpage.rst:172 d2d5ce2b47bc4940b491f08fbbaa0027\nmsgid \"\"\n\"In the vast majority of cases, we are dealing with **horizontal text \"\n\"only**, where bboxes provide entirely sufficient information.\"\nmsgstr \"ほとんどの場合、**水平テキストのみ** を扱っており、bboxは十分な情報を提供します。\"\n\n#: ../../textpage.rst:174 feb1b497d7a04358ac4fc4f59750eb21\nmsgid \"\"\n\"In addition, **the full quad information is not lost**: it can be \"\n\"recovered as needed for lines, spans, and characters by using the \"\n\"appropriate function from the following list:\"\nmsgstr \"さらに、**フルクワッド情報は失われていません**。必要に応じて、以下のリストから適切な関数を使用して行、スパン、および文字のクワッド情報を回復できます：\"\n\n#: ../../textpage.rst:176 e89548afd6dc44168e0b77628a3cba31\nmsgid \":meth:`recover_quad` -- the quad of a complete span\"\nmsgstr \":meth:`recover_quad` – 完全なスパンのクワッド\"\n\n#: ../../textpage.rst:177 27d71bee525843278a01adf552fa7a36\nmsgid \":meth:`recover_span_quad` -- the quad of a character subset of a span\"\nmsgstr \":meth:`recover_span_quad` – スパンの一部の文字のクワッド\"\n\n#: ../../textpage.rst:178 041a2862fe3d48ac95055a9328f85989\nmsgid \":meth:`recover_line_quad` -- the quad of a line\"\nmsgstr \":meth:`recover_line_quad` – 行のクワッド\"\n\n#: ../../textpage.rst:179 66ae40921c104d34aba6daaf7127f04f\nmsgid \":meth:`recover_char_quad` -- the quad of a character\"\nmsgstr \":meth:`recover_char_quad` – 文字のクワッド\"\n\n#: ../../textpage.rst:181 727a2901b16c4ddd96ae14b244c5424a\nmsgid \"\"\n\"As mentioned, using these functions is ever only needed, if the text is \"\n\"**not written horizontally** -- `line[\\\"dir\\\"] != (1, 0)` -- and you need\"\n\" the quad for text marker annotations (:meth:`Page.add_highlight_annot` \"\n\"and friends).\"\nmsgstr \"\"\n\"前述のように、これらの関数を使用する必要があるのは、テキストが **水平に書かれていない** 場合 - `line[\\\"dir\\\"] != (1,\"\n\" 0)` - およびテキストマーカーアノテーション（:meth:`Page.add_highlight_annot` \"\n\"など）でクワッドが必要な場合のみです。\"\n\n#: ../../textpage.rst:191 7805ac6076c748d18288314bba88341d\nmsgid \"Page Dictionary\"\nmsgstr \"ページ辞書\"\n\n#: ../../textpage.rst:194 ../../textpage.rst:208 ../../textpage.rst:251\n#: ../../textpage.rst:263 ../../textpage.rst:285 ../../textpage.rst:369\n#: 29f9782130d642a8b2fddc4dfd20716c 70f3d2461fad4b3fadb0fc3afaea9f2e\n#: 975906fdd1184ad3ad3fd3d27e4993b0 baf341562d684245aa92ddd993c2dd48\n#: bf7900e8b9b5405a8f0d4d83a8bf0411 c6778ca210f143f38e1b9841a02401e9\nmsgid \"**Key**\"\nmsgstr \"**キー**\"\n\n#: ../../textpage.rst:194 ../../textpage.rst:208 ../../textpage.rst:251\n#: ../../textpage.rst:263 ../../textpage.rst:285 ../../textpage.rst:369\n#: 264a4f1acc10474eb5e78fe3b5e5823b b4b639c47a4a414db8f8f3bb50ee8dc9\n#: cc9c466c5ba84957921e1ff86a57d116 d94353036c5b40c1846dd829e554f27f\n#: f0dc2d1c0f2f41dea26d6f56aa6b3a26 fe805e2ac2f84c418cdee9f01871d787\nmsgid \"**Value**\"\nmsgstr \"**値**\"\n\n#: ../../textpage.rst:196 ../../textpage.rst:214\n#: 07aa10194d0d48eb97c6202f508f7705 8f326282fbe8407aa66c61b1d8bcd062\nmsgid \"width\"\nmsgstr \"\"\n\n#: ../../textpage.rst:196 f244c49149a243688a1885d014c7a1bb\nmsgid \"width of the `clip` rectangle *(float)*\"\nmsgstr \"`clip` 矩形の幅 *(float)*\"\n\n#: ../../textpage.rst:197 ../../textpage.rst:215\n#: b8882d43fa804c8a9c251b3ec47cef6d bcccca2b99b94b7ea01f4de3b4b7c85a\nmsgid \"height\"\nmsgstr \"\"\n\n#: ../../textpage.rst:197 3100ead6fa2e45f5b61d6969928e4877\nmsgid \"height of the `clip` rectangle *(float)*\"\nmsgstr \"`clip` 矩形の高さ *(float)*\"\n\n#: ../../textpage.rst:198 c5935e75747b42e799fe04c7f318b0da\nmsgid \"blocks\"\nmsgstr \"\"\n\n#: ../../textpage.rst:198 30ab779a07894b089542bb81604f9b47\nmsgid \"*list* of block dictionaries\"\nmsgstr \"ブロック辞書の *list* \"\n\n#: ../../textpage.rst:202 db462c15f35c46f5b52a233a3beed4d0\nmsgid \"Block Dictionaries\"\nmsgstr \"ブロック辞書\"\n\n#: ../../textpage.rst:203 952d964d7a5e43c2848616b970e2716c\nmsgid \"\"\n\"Block dictionaries come in two different formats for **image blocks** and\"\n\" for **text blocks**.\"\nmsgstr \"ブロック辞書は、**画像ブロック** と **テキストブロック** の2つの異なるフォーマットで提供されます。\"\n\n#: ../../textpage.rst:205 238f68f9676441f1bdcff950557a856e\nmsgid \"**Image block:**\"\nmsgstr \"**画像ブロック：**\"\n\n#: ../../textpage.rst:210 ../../textpage.rst:253\n#: 800a3c27effc460f9480726ec3a5c729 d35d41a494c04f6285bda0eace697528\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../textpage.rst:210 6328d3cec703451097bfaa7cf7f6c65f\n#, fuzzy\nmsgid \"1 = image (``int``)\"\nmsgstr \"1 = 画像 *(int)*\"\n\n#: ../../textpage.rst:211 ../../textpage.rst:254 ../../textpage.rst:265\n#: ../../textpage.rst:287 ../../textpage.rst:372\n#: 13e6c3dfe54549b9b050cea92d99d01a 322f2d6f5b2b44ed9706ad2f98ad459c\n#: 4f766fcb9538433a8d4db8a39a80ff3c bc56648f4c414b1eb1faa55dba01ab98\n#: db0fdf56b2254240a588914bece3c707\nmsgid \"bbox\"\nmsgstr \"\"\n\n#: ../../textpage.rst:211 ff4d18f9a8d24d16a31d552e95f6e589\nmsgid \"image bbox on page (:data:`rect_like`)\"\nmsgstr \"ページ上の画像の境界ボックス（:data:`rect_like`）\"\n\n#: ../../textpage.rst:212 ../../textpage.rst:255\n#: 4c56479091544270885701e21d3794c0 5d311b7030c74d77b291641b825cabc0\nmsgid \"number\"\nmsgstr \"\"\n\n#: ../../textpage.rst:212 044f427c89414858935273b873628617\n#, fuzzy\nmsgid \"block count (``int``)\"\nmsgstr \"ブロック数 *(int)*\"\n\n#: ../../textpage.rst:213 d457db3dffd648f5b421b9dabda513e8\nmsgid \"ext\"\nmsgstr \"\"\n\n#: ../../textpage.rst:213 9a1b2497c15747ccae408e2908b03716\n#, fuzzy\nmsgid \"image type (``str``), as file extension, see below\"\nmsgstr \"画像の種類 *(str)*、ファイル拡張子として、以下参照\"\n\n#: ../../textpage.rst:214 65917d8aff0a47ae97e1c880700ae5b9\n#, fuzzy\nmsgid \"original image width (``int``)\"\nmsgstr \"元の画像の幅 *(int)*\"\n\n#: ../../textpage.rst:215 ef1b2983b8484b67aea4e7c52ec94c5e\n#, fuzzy\nmsgid \"original image height (``int``)\"\nmsgstr \"元の画像の高さ *(int)*\"\n\n#: ../../textpage.rst:216 cdbc1a0fe83a45878f7d57c8195c2541\nmsgid \"colorspace\"\nmsgstr \"\"\n\n#: ../../textpage.rst:216 0768d9dd62e74b518365212bb8f2d509\n#, fuzzy\nmsgid \"colorspace component count (``int``)\"\nmsgstr \"カラースペースのコンポーネント数 *(int)*\"\n\n#: ../../textpage.rst:217 c72ef151fd0843acbf96ee02c0b50384\nmsgid \"xres\"\nmsgstr \"\"\n\n#: ../../textpage.rst:217 2b798798946e43259c410f01235ab8cf\n#, fuzzy\nmsgid \"resolution in x-direction (``int``) [#f3]_\"\nmsgstr \"x方向の解像度 *(int)*\"\n\n#: ../../textpage.rst:218 711945f5b34049a1b07317557513f490\nmsgid \"yres\"\nmsgstr \"\"\n\n#: ../../textpage.rst:218 91a31d61290640b8988418d1a9ebb3ba\n#, fuzzy\nmsgid \"resolution in y-direction (``int``) [#f3]_\"\nmsgstr \"y方向の解像度 *(int)*\"\n\n#: ../../textpage.rst:219 c247c45f267c4a6281d20687be8c99af\nmsgid \"bpc\"\nmsgstr \"\"\n\n#: ../../textpage.rst:219 8934e38405664f3fa8f78d65d3a6dba5\n#, fuzzy\nmsgid \"bits per component (``int``)\"\nmsgstr \"コンポーネントごとのビット数 *(int)*\"\n\n#: ../../textpage.rst:220 2db498cd52714dd8b5097aa444b17ac0\nmsgid \"transform\"\nmsgstr \"\"\n\n#: ../../textpage.rst:220 c07a01fdd4744863a7e7b665d9066376\nmsgid \"matrix transforming image rect to bbox (:data:`matrix_like`)\"\nmsgstr \"画像矩形を境界ボックスに変換する行列（:data:`matrix_like`）\"\n\n#: ../../textpage.rst:221 ../../textpage.rst:292\n#: 416da7dc62f34728a5e65a5b6eccec10 e5bfbe8873ce4531a1a93eea31b542ab\nmsgid \"size\"\nmsgstr \"\"\n\n#: ../../textpage.rst:221 ef114c513c0140809c273a1fca277935\n#, fuzzy\nmsgid \"size of the image in bytes (``int``)\"\nmsgstr \"画像のサイズ（バイト単位）*(int)*\"\n\n#: ../../textpage.rst:222 b4442e7378f340ad9bbc40a5bda85f94\nmsgid \"image\"\nmsgstr \"\"\n\n#: ../../textpage.rst:222 44de8974cd434bbca7c4dea100e9987f\n#, fuzzy\nmsgid \"image content (``bytes``)\"\nmsgstr \"画像コンテンツ *(bytes)*\"\n\n#: ../../textpage.rst:223 ce697bda1a494d35a92a1a9b886f4a53\nmsgid \"mask\"\nmsgstr \"\"\n\n#: ../../textpage.rst:223 203d79f1d981499da21d8cae601cef42\nmsgid \"image mask content (``bytes``) for transparent images\"\nmsgstr \"\"\n\n#: ../../textpage.rst:226 7b2748f1df1342538dd7b750dd6db1db\nmsgid \"\"\n\"Possible values of the \\\"ext\\\" key are \\\"bmp\\\", \\\"gif\\\", \\\"jpeg\\\", \"\n\"\\\"jpx\\\" (JPEG 2000), \\\"jxr\\\" (JPEG XR), \\\"png\\\", \\\"pnm\\\", and \\\"tiff\\\".\"\nmsgstr \"\"\n\"\\\"ext\\\"キーの可能な値は、\\\"bmp\\\"、\\\"gif\\\"、\\\"jpeg\\\"、\\\"jpx\\\"（JPEG 2000）、\\\"jxr\\\"（JPEG \"\n\"XR）、\\\"png\\\"、\\\"pnm\\\"、および \\\"tiff\\\" です。\"\n\n#: ../../textpage.rst:230 f165771e95ce4de587ef46d0281ce182\nmsgid \"\"\n\"An image block is generated for **all and every image occurrence** on the\"\n\" page. Hence there may be duplicates, if an image is shown at different \"\n\"locations.\"\nmsgstr \"ページ上の **すべての画像** が画像ブロックとして生成されます。したがって、画像が異なる場所で表示される場合、重複が発生する可能性があります。\"\n\n#: ../../textpage.rst:232 34122c8c572a45d7a4acfd1f2cbbbe55\nmsgid \"\"\n\":ref:`TextPage` and corresponding method :meth:`Page.get_text` are \"\n\"**available for all document types**. Only for PDF documents, methods \"\n\":meth:`Document.get_page_images` / :meth:`Page.get_images` offer some \"\n\"overlapping functionality as far as image lists are concerned. But both \"\n\"lists **may or may not** contain the same items. Any differences are most\"\n\" probably caused by one of the following:\"\nmsgstr \"\"\n\":ref:`TextPage` および対応するメソッド :meth:`Page.get_text` は **すべてのドキュメントタイプ** \"\n\"で利用可能です。PDFドキュメントの場合、:meth:`Document.get_page_images` / \"\n\":meth:`Page.get_images` は画像リストに関する機能が一部重複しています。ただし、これらのリストは同じアイテムを \"\n\"**含むかどうかは必ずしも保証されません**。違いがある場合、その原因はおそらく次のいずれかです。\"\n\n#: ../../textpage.rst:234 87715f6d6a82452b8ef41b7cbb3b917c\nmsgid \"\"\n\"\\\"Inline\\\" images (see page 214 of the :ref:`AdobeManual`) of a PDF page \"\n\"are contained in a textpage, but **do not appear** in \"\n\":meth:`Page.get_images`.\"\nmsgstr \"\"\n\"PDFページの「インライン」画像（:ref:`AdobeManual` \"\n\"のページ214を参照）はテキストページに含まれていますが、:meth:`Page.get_images` には **表示されません**。\"\n\n#: ../../textpage.rst:235 7671c8c4e14e4452a9de51d3be9f9a57\nmsgid \"\"\n\"Annotations may also contain images -- these will **not appear** in \"\n\":meth:`Page.get_images`.\"\nmsgstr \"アノテーションにも画像が含まれることがあります。これらは :meth:`Page.get_images` には **表示されません**。\"\n\n#: ../../textpage.rst:236 528e4366c2844284b6b3e06d85663c2c\nmsgid \"\"\n\"Image blocks in a textpage are generated for **every** image location -- \"\n\"whether or not there are any duplicates. This is in contrast to \"\n\":meth:`Page.get_images`, which will list each image only once (per \"\n\"reference name).\"\nmsgstr \"\"\n\"テキストページの画像ブロックは、画像の場所 **ごとに** \"\n\"生成されます。重複があるかどうかに関係なくです。これは、:meth:`Page.get_images` \"\n\"では各画像が1回だけリストされる（参照名ごとに）のとは対照的です。\"\n\n#: ../../textpage.rst:237 6ba5259a29524a72bae31a85c368deb0\nmsgid \"\"\n\"Images mentioned in the page's :data:`object` definition will **always** \"\n\"appear in :meth:`Page.get_images` [#f1]_. But it may happen, that there \"\n\"is no \\\"display\\\" command in the page's :data:`contents` (erroneously or \"\n\"on purpose). In this case the image will **not appear** in the textpage.\"\nmsgstr \"\"\n\"ページの :data:`object` 定義で言及されている画像は、常に :meth:`Page.get_images` に表示されます \"\n\"[#f1]_。ただし、ページの :data:`contents` に「表示」コマンドがない場合、画像はテキストページに表示されません。\"\n\n#: ../../textpage.rst:239 e7f81738e67441429325db9963571f7d\nmsgid \"\"\n\"The image's \\\"transformation matrix\\\" is defined as the matrix, for which\"\n\" the expression `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` is true, \"\n\"lookup details here: :ref:`ImageTransformation`.\"\nmsgstr \"\"\n\"画像の「変換行列」は、`bbox / transform == pymupdf.Rect(0, 0, 1, 1)` \"\n\"という式が真である場合の行列です。詳細はこちらを参照してください： :ref:`ImageTransformation`。\"\n\n#: ../../textpage.rst:241 57bed7561cd444e0b640b95c35da2f85\nmsgid \"\"\n\"A transparent image may be accompanied by a mask image. This is stored \"\n\"under key `\\\"mask\\\"` and has the format of a `DeviceGray` PNG image. \"\n\"Otherwise the value of this key is ``None``. If present, you may be able \"\n\"to recover (an equivalent of) the original image -- i.e. with \"\n\"transparency -- by creating :ref:`Pixmap` objects from the \\\"image\\\", \"\n\"respectively \\\"mask\\\" values and overlay them. This is not guaranteed to \"\n\"always work because mask images come in multiple formats, of which not \"\n\"all qualify for the conditions under which overlaying Pixmaps are \"\n\"supported. Here is a code snippet:\"\nmsgstr \"\"\n\n#: ../../textpage.rst:248 4615f23b245b4db39e8ea23b4d176464\nmsgid \"**Text block:**\"\nmsgstr \"**テキストブロック：**\"\n\n#: ../../textpage.rst:253 db5d3f31fc8d4153b8fafecfdf3d1727\nmsgid \"0 = text *(int)*\"\nmsgstr \"0 = テキスト *(int)*\"\n\n#: ../../textpage.rst:254 6964cf3c7ba24458aae29d347f3f603a\nmsgid \"block rectangle, :data:`rect_like`\"\nmsgstr \"ブロックの矩形、:data:`rect_like`\"\n\n#: ../../textpage.rst:255 731cf949720a4619b5ea681f7764d295\nmsgid \"block count *(int)*\"\nmsgstr \"ブロック数 *(int)*\"\n\n#: ../../textpage.rst:256 3a23e4510e7949e29bf987d16327eb49\nmsgid \"lines\"\nmsgstr \"\"\n\n#: ../../textpage.rst:256 ede4e782ec014752989f15767a43462d\nmsgid \"*list* of text line dictionaries\"\nmsgstr \"テキスト行の辞書の *list*\"\n\n#: ../../textpage.rst:260 647d1430aba549968a23caa9bd2bf178\nmsgid \"Line Dictionary\"\nmsgstr \"\"\n\n#: ../../textpage.rst:265 88d566f6551a42a29f62a0819ecbed64\nmsgid \"line rectangle, :data:`rect_like`\"\nmsgstr \"行の矩形、:data:`rect_like`\"\n\n#: ../../textpage.rst:266 bc961e945f144c85a9e1a2193c3a4443\nmsgid \"wmode\"\nmsgstr \"\"\n\n#: ../../textpage.rst:266 220a8c26dda34ae4b15fb120791f0296\nmsgid \"writing mode *(int)*: 0 = horizontal, 1 = vertical\"\nmsgstr \"書き込みモード *(int)*：0 = 水平、1 = 垂直\"\n\n#: ../../textpage.rst:267 b23571753e8641b391f1c7bd3d666faf\nmsgid \"dir\"\nmsgstr \"\"\n\n#: ../../textpage.rst:267 f040c814bf3643e0b50bb1889d157bc2\nmsgid \"writing direction, :data:`point_like`\"\nmsgstr \"書き込み方向、:data:`point_like`\"\n\n#: ../../textpage.rst:268 f4df6d31bea14f7d9133d10fe217a237\nmsgid \"spans\"\nmsgstr \"\"\n\n#: ../../textpage.rst:268 d2626131157f45bda11a0a0240ae20e0\nmsgid \"*list* of span dictionaries\"\nmsgstr \"スパン辞書の *list*\"\n\n#: ../../textpage.rst:271 827a258f7a314424b22d7d3077bc4795\n#, fuzzy\nmsgid \"\"\n\"The value of key *\\\"dir\\\"* is the **unit vector** `dir = (cosine, -sine)`\"\n\" of the angle, which the text has relative to the x-axis [#f2]_. See the \"\n\"following picture: The word in each quadrant (counter-clockwise from top-\"\n\"right to bottom-right) is rotated by 30, 120, 210 and 300 degrees \"\n\"respectively.\"\nmsgstr \"\"\n\"キー *\\\"dir\\\"* の値は、テキストが x 軸に対してどの角度であるかを示す **ユニットベクトル** `dir = (cosine, \"\n\"sine)` \"\n\"です。次の図を参照してください：各象限内の単語（右上から反時計回りに、上から下まで）は、それぞれ30、120、210、300度回転しています。\"\n\n#: ../../textpage.rst:277 76e3be33b8eb4d20a040a290a7493044\nmsgid \"Span Dictionary\"\nmsgstr \"\"\n\n#: ../../textpage.rst:279 44e867372fca4010ae8c117e6f57244a\nmsgid \"\"\n\"Spans contain the actual text. A line contains **more than one span \"\n\"only**, if it contains text with different font properties.\"\nmsgstr \"スパンには実際のテキストが含まれています。フォントのプロパティが異なるテキストを含む場合を除き、1行には複数のスパンが含まれます。\"\n\n#: ../../textpage.rst:281 2484e6f332594c488b1ab6e8e45e8358\nmsgid \"Changed in version 1.14.17 Spans now also have a *bbox* key (again).\"\nmsgstr \"バージョン1.14.17で変更されました：スパンには *bbox* キーが含まれています（再び）。\"\n\n#: ../../textpage.rst:282 fe2deeccb3484496b06cee9c45979177\nmsgid \"Changed in version 1.17.6 Spans now also have an *origin* key.\"\nmsgstr \"バージョン1.17.6で変更されました：スパンには *origin* キーも含まれています。\"\n\n#: ../../textpage.rst:287 24917424394140498d62e12db012d491\nmsgid \"span rectangle, :data:`rect_like`\"\nmsgstr \"スパンの矩形、:data:`rect_like`\"\n\n#: ../../textpage.rst:288 ../../textpage.rst:371\n#: d062895875c246f08ce11e156a46fe6c e4eadb2bf3fd4656a1dcaea2aa762fb2\nmsgid \"origin\"\nmsgstr \"\"\n\n#: ../../textpage.rst:288 49dcac4791f7495283b181cd85e5cb96\nmsgid \"the first character's origin, :data:`point_like`\"\nmsgstr \"最初の文字の原点、:data:`point_like`\"\n\n#: ../../textpage.rst:289 a039c803b12f44f2b903bfd72ff968f0\nmsgid \"font\"\nmsgstr \"\"\n\n#: ../../textpage.rst:289 e59d2678453347c3b2290c87101bee41\nmsgid \"font name *(str)*\"\nmsgstr \"フォント名  *（str）*\"\n\n#: ../../textpage.rst:290 9789271ef0d44ca8b8b7753a47109329\nmsgid \"ascender\"\nmsgstr \"\"\n\n#: ../../textpage.rst:290 bae202ea90f340c08117616fba695605\nmsgid \"ascender of the font *(float)*\"\nmsgstr \"フォントのアセンダー *（float）*\"\n\n#: ../../textpage.rst:291 f04de1e03bc64ecb932178642bbf28a2\nmsgid \"descender\"\nmsgstr \"\"\n\n#: ../../textpage.rst:291 cab39571402145599cd516740c2cd5e3\nmsgid \"descender of the font *(float)*\"\nmsgstr \"フォントのディセンダー *（float）*\"\n\n#: ../../textpage.rst:292 7bb34b245d0e4a7a807d37f771540973\nmsgid \"font size *(float)*\"\nmsgstr \"フォントサイズ *（float）*\"\n\n#: ../../textpage.rst:293 728b3550893a43df91864ece6b6a6c75\nmsgid \"flags\"\nmsgstr \"\"\n\n#: ../../textpage.rst:293 d4144f5c31e240ca8a9bc6a9902c4b40\nmsgid \"font characteristics *(int)*\"\nmsgstr \"フォントの特性 *（int）*\"\n\n#: ../../textpage.rst:294 4ab488b7a402495f924066ec5fa0901d\nmsgid \"char_flags\"\nmsgstr \"\"\n\n#: ../../textpage.rst:294 ac689e1eb3bd44c196f5a43696910e9c\n#, fuzzy\nmsgid \"char characteristics *(int)*\"\nmsgstr \"フォントの特性 *（int）*\"\n\n#: ../../textpage.rst:295 70dfc6783fdb4c5a8a1e0ad9b92b44fc\nmsgid \"color\"\nmsgstr \"\"\n\n#: ../../textpage.rst:295 0c21ca835d2f477e934a8f5cec1f8a4c\n#, fuzzy\nmsgid \"text color in sRGB format 0xRRGGBB *(int)*.\"\nmsgstr \"sRGB形式のテキストカラー *（int）*\"\n\n#: ../../textpage.rst:296 8e921b08a2ba477497897d70a87f4977\nmsgid \"alpha\"\nmsgstr \"\"\n\n#: ../../textpage.rst:296 ec794a253afb48ea90cf9d7494caa03b\nmsgid \"text opacity 0..255 *(int)*.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:297 72dbc8f290b94f6c88700e6a5df12717\nmsgid \"text\"\nmsgstr \"\"\n\n#: ../../textpage.rst:297 42bc9c7faaed433c9e3868ab04254f3f\nmsgid \"(only for :meth:`extractDICT`) text *(str)*\"\nmsgstr \"（:meth:`extractDICT` のみ）テキスト *（str）* \"\n\n#: ../../textpage.rst:298 6c4e864e58554766a1c930bd0e32e581\nmsgid \"chars\"\nmsgstr \"\"\n\n#: ../../textpage.rst:298 287db5214934490ba0764caaa9ee699d\nmsgid \"(only for :meth:`extractRAWDICT`) *list* of character dictionaries\"\nmsgstr \"（:meth:`extractRAWDICT` のみ）文字の辞書の*list*\"\n\n#: ../../textpage.rst:301 6a3a9323a60541ca97db64597a2a451a\nmsgid \"|history_begin|\"\nmsgstr \"\"\n\n#: ../../textpage.rst:303 e0b8ee67e36546b0b5b8b155e00eeb45\nmsgid \"*(New in version 1.25.3.0):* Added *\\\"alpha\\\"* item.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:305 04010301eebf4c2dbf6989108e207ae9\nmsgid \"\"\n\"*(New in version 1.16.0):* *\\\"color\\\"* is the text color encoded in sRGB \"\n\"(int) format, e.g. 0xFF0000 for red. There are functions for converting \"\n\"this integer back to formats (r, g, b) (PDF with float values from 0 to \"\n\"1) :meth:`sRGB_to_pdf`, or (R, G, B), :meth:`sRGB_to_rgb` (with integer \"\n\"values from 0 to 255).\"\nmsgstr \"\"\n\"*バージョン1.16.0で新しく追加された項目：*. *「color」* \"\n\"はsRGB（int）形式でエンコードされたテキストカラーで、例えば赤の場合は0xFF0000です。この整数をフォーマット（r、g、b）（PDFでは0から1の範囲の浮動小数点値）\"\n\" :meth:`sRGB_to_pdf` または（R、G、B）、:meth:`sRGB_to_rgb` \"\n\"（整数値で0から255の範囲）に変換するための関数があります。\"\n\n#: ../../textpage.rst:307 744bef29da2f4dbc90404a35ef0fd253\nmsgid \"\"\n\"*(New in v1.18.5):* *\\\"ascender\\\"* and *\\\"descender\\\"* are font \"\n\"properties, provided relative to :data:`fontsize` 1. Note that descender \"\n\"is a negative value. The following picture shows the relationship to \"\n\"other values and properties.\"\nmsgstr \"\"\n\"*バージョン1.18.5で新しく追加された項目：* *「ascender」* と *「descender」* は、フォントのプロパティで、 \"\n\":data:`fontsize` \"\n\"1に対して提供されます。ディセンダーは負の値であることに注意してください。以下の画像は、他の値やプロパティとの関係を示しています。\"\n\n#: ../../textpage.rst:309 e0a8a997405247f6bb89749ab0b624b7\nmsgid \"|history_end|\"\nmsgstr \"\"\n\n#: ../../textpage.rst:314 9b180b7db6ac43e489b8d8e9ccb31622\nmsgid \"\"\n\"These numbers may be used to compute the minimum height of a character \"\n\"(or span) -- as opposed to the standard height provided in the \\\"bbox\\\" \"\n\"values (which actually represents the **line height**). The following \"\n\"code recalculates the span bbox to have a height of **fontsize** exactly \"\n\"fitting the text inside:\"\nmsgstr \"\"\n\"これらの数字は、文字（またはスパン）の最小の高さを計算するために使用できます。これは、実際には行の高さを表す「bbox」値ではなく、フォントサイズに完全に合わせるための高さを表します。次のコードは、スパンのbboxを、内部のテキストに完全に合わせる高さが\"\n\" **フォントサイズ** となるように再計算します：\"\n\n#: ../../textpage.rst:324 91c353d85b0a45d7bde9987e275b50b5\nmsgid \"\"\n\"The above calculation may deliver a **larger** height! This may e.g. \"\n\"happen for OCRed documents, where the risk of all sorts of text artifacts\"\n\" is high. MuPDF tries to come up with a reasonable bbox height, \"\n\"independently from the :data:`fontsize` found in the PDF. So please \"\n\"ensure that the height of `span[\\\"bbox\\\"]` is **larger** than \"\n\"`span[\\\"size\\\"]`.\"\nmsgstr \"\"\n\"上記の計算は、**より大きな** \"\n\"高さをもたらす可能性があります。これは、OCRedドキュメントなどで発生する可能性があります。MuPDFは、PDFに存在する \"\n\":data:`fontsize` から独立して、適切なbboxの高さを見つけ出そうとします。したがって、`span[\\\"bbox\\\"]` の高さが\"\n\" `span[\\\"size\\\"]` よりも大きいことを確認してください。\"\n\n#: ../../textpage.rst:326 cfa2fe9816d741889a16e7a98228f45f\nmsgid \"\"\n\"You may request PyMuPDF to do all of the above automatically by executing\"\n\" `pymupdf.TOOLS.set_small_glyph_heights(True)`. This sets a global \"\n\"parameter so that all subsequent text searches and text extractions are \"\n\"based on reduced glyph heights, where meaningful.\"\nmsgstr \"\"\n\"PyMuPDFに対して、`pymupdf.TOOLS.set_small_glyph_heights(True)` \"\n\"を実行して、上記のすべてを自動的に実行するように依頼することができます。これは、すべての後続のテキスト検索とテキスト抽出が、縮小されたグリフの高さを基に行われるようにするためのグローバルパラメータを設定します。\"\n\n#: ../../textpage.rst:328 dcd3f3103b3a404ea59ed88e1020efbe\nmsgid \"\"\n\"The following shows the original span rectangle in red and the rectangle \"\n\"with re-computed height in blue.\"\nmsgstr \"以下は、元のspanの矩形を赤で、再計算された高さを持つ矩形を青で示しています。\"\n\n#: ../../textpage.rst:334 c4897a84054b4b60ab66d79b8388e431\nmsgid \"\"\n\"*\\\"flags\\\"* is an integer, which represents font properties except for \"\n\"the first bit 0. They are to be interpreted like this:\"\nmsgstr \"*\\\"flags\\\"* は、フォントのプロパティを表す整数で、最初のビット 0 を除いて次のように解釈されます：\"\n\n#: ../../textpage.rst:336 817f541495b84011b646fb0f5a0c1eff\n#, fuzzy\nmsgid \"\"\n\"bit 0: superscripted (:data:`TEXT_FONT_SUPERSCRIPT`) -- not a font \"\n\"property, detected by MuPDF code.\"\nmsgstr \"bit 0: superscripted (2\\\\ :sup:`0`)  - フォントのプロパティではなく、MuPDFコードによって検出されます。\"\n\n#: ../../textpage.rst:337 4966d75813f448898822b04faffbe380\nmsgid \"bit 1: italic (:data:`TEXT_FONT_ITALIC`)\"\nmsgstr \"\"\n\n#: ../../textpage.rst:338 31205a9cd37941e0ac7c7fbbfb19ffc1\n#, fuzzy\nmsgid \"bit 2: serifed (:data:`TEXT_FONT_SERIFED`)\"\nmsgstr \"ビット 2: セリフ付き (2\\\\ :sup:`2`)\"\n\n#: ../../textpage.rst:339 f887f5fcd078467cbd8ea212d8133aa3\n#, fuzzy\nmsgid \"bit 3: monospaced (:data:`TEXT_FONT_MONOSPACED`)\"\nmsgstr \"ビット 3: モノスペース (2\\\\ :sup:`3`)\"\n\n#: ../../textpage.rst:340 075ed56b276245c096a3204cc111339a\nmsgid \"bit 4: bold (:data:`TEXT_FONT_BOLD`)\"\nmsgstr \"\"\n\n#: ../../textpage.rst:342 fafa4c4a530a43fa8278e455dd07640f\nmsgid \"Test these characteristics like so:\"\nmsgstr \"これらの特性は、次のようにテストできます：\"\n\n#: ../../textpage.rst:348 ffbc346b79aa4a6189253e08eeb6280f\nmsgid \"\"\n\"Bits 1 thru 4 are font properties, i.e. encoded in the font program. \"\n\"Please note, that this information is not necessarily correct or \"\n\"complete: fonts quite often contain wrong data here.\"\nmsgstr \"\"\n\"ビット1からビット4までがフォントのプロパティであり、つまりフォントプログラムにエンコードされています。 \"\n\"ただし、この情報は必ずしも正確または完全ではないことに注意してください。フォントにはしばしば誤ったデータが含まれていることがあります。\"\n\n#: ../../textpage.rst:350 67a56b648e48459abc86b3d71dded7d7\nmsgid \"\"\n\"*\\\"char_flags\\\"* is an integer, which represents extra character \"\n\"properties:\"\nmsgstr \"\"\n\n#: ../../textpage.rst:352 16e54aeb7318448cb0edbbce096027cc\nmsgid \"bit 0: strikeout.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:353 f36bc128a5084f419c7b735cc7a5caeb\nmsgid \"bit 1: underline.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:354 05f6a81ee7234929b145f42b0eaeb4ee\nmsgid \"bit 2: synthetic (always 0, see char dictionary).\"\nmsgstr \"\"\n\n#: ../../textpage.rst:355 2d7d278b9b7b46479144808b701ed7da\nmsgid \"bit 3: filled.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:356 a0b8d460dd8a42e69537652330a1f9ee\nmsgid \"bit 4: stroked.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:357 430da53ed561403d90a8c2c28cc01a90\nmsgid \"bit 5: clipped.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:359 26fc27f279ca42fba75113be40e54d40\nmsgid \"\"\n\"For example if not filled and not stroked (`if not (char_flags & 2**3 & \"\n\"2**4): ...`) then the text will be invisible.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:362 f68e611505354310ab256d5f4ac755f3\nmsgid \"(`char_flags` is new in v1.25.2.)\"\nmsgstr \"\"\n\n#: ../../textpage.rst:366 2b6029a504d149d0b74200b8dd10b461\nmsgid \"Character Dictionary for :meth:`extractRAWDICT`\"\nmsgstr \"文字のディクショナリ、:meth:`extractRAWDICT`\"\n\n#: ../../textpage.rst:371 e3322f02de66484cb59d9ddf2e914bcb\nmsgid \"character's left baseline point, :data:`point_like`\"\nmsgstr \"文字の左ベースラインポイント、:data:`point_like`\"\n\n#: ../../textpage.rst:372 3a206190a9b4495299d14480848ee306\nmsgid \"character rectangle, :data:`rect_like`\"\nmsgstr \"文字の矩形、:data:`rect_like`\"\n\n#: ../../textpage.rst:373 7925e02a5e07443895c900f6450205fa\nmsgid \"synthetic\"\nmsgstr \"\"\n\n#: ../../textpage.rst:373 d557f7b009724b00a3418fb77e4943ce\nmsgid \"bool.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:374 fb692a970116495a977cac2daff0d94b\nmsgid \"c\"\nmsgstr \"\"\n\n#: ../../textpage.rst:374 30e9a39551314a14a169ee11d34c575f\nmsgid \"the character (unicode)\"\nmsgstr \"文字（ユニコード）\"\n\n#: ../../textpage.rst:377 504a88fbf1324f19a3ed16c3f2c0c942\nmsgid \"(`synthetic` is new in v1.25.3.)\"\nmsgstr \"\"\n\n#: ../../textpage.rst:379 9d820af6f3ac446a912245d16d5e7bdd\nmsgid \"\"\n\"This image shows the relationship between a character's bbox and its \"\n\"quad: |textpagechar|\"\nmsgstr \"この画像は、文字のbboxとそのquadの関係を示しています：|textpagechar|\"\n\n#: ../../textpage.rst:381 64023f700298486f98b566eac340e37b\n#: 7901af22526f478cb0ba76a7cc56288e\nmsgid \"textpagechar\"\nmsgstr \"\"\n\n#: ../../textpage.rst:386 ab41f5e333004a04a46c0505e9d7bebf\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../textpage.rst:387 9c3377a336cd4477b8afbd4528d4dee0\nmsgid \"\"\n\"Image specifications for a PDF page are done in a page's (sub-) \"\n\":data:`dictionary`, called `/Resources`. Resource dictionaries can be \"\n\"**inherited** from any of the page's parent objects (usually the \"\n\":data:`catalog` -- the top-level parent). The PDF creator may e.g. define\"\n\" one `/Resources` on file level, naming all images and / or all fonts \"\n\"ever used by any page. In these cases, :meth:`Page.get_images` and \"\n\":meth:`Page.get_fonts` will consequently return the same lists for all \"\n\"pages. If desired, this situation can be reverted using \"\n\":meth:`Page.clean_contents`. After execution, the page's object \"\n\"definition will show fonts and images that are actually used.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:389 8ebe9e78accc4c87b80eb50757ed695f\nmsgid \"\"\n\"The coordinate systems of MuPDF and PDF are different in that MuPDF uses \"\n\"the page's top-left point as `(0, 0)`. In PDF, this is the bottom-left \"\n\"point. Therefore, the positive direction for MuPDF's y-axis is **from top\"\n\" to bottom**. This causes the sign change for the sine value here: a \"\n\"**negative** value indicates anti-clockwise rotation of the text.\"\nmsgstr \"\"\n\n#: ../../textpage.rst:391 9bfe3c4bcdac45eb9b746197c51d2a7a\nmsgid \"\"\n\"This value is always 96, the default of the PDF interpreter. It **does \"\n\"not reflect** the resolution of the image itself. If you need the image's\"\n\" resolution, use the :meth:`Pixmap.xres` and :meth:`Pixmap.yres` \"\n\"attributes of the :ref:`Pixmap` created from the returned image binary.\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 909bafb54f4646cd8842c5ccd34ceeef\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"Image specifications for a PDF page \"\n#~ \"are done in a page's (sub-) \"\n#~ \":data:`dictionary`, called *\\\"/Resources\\\"*. \"\n#~ \"Resource dictionaries can be **inherited** \"\n#~ \"from the page's parent object (usually\"\n#~ \" the :data:`catalog`). The PDF creator \"\n#~ \"may e.g. define one */Resources* on \"\n#~ \"file level, naming all images and \"\n#~ \"all fonts ever used by any page.\"\n#~ \" In these cases, :meth:`Page.get_images` \"\n#~ \"and :meth:`Page.get_fonts` will return the \"\n#~ \"same lists for all pages.\"\n#~ msgstr \"\"\n#~ \"PDFページの画像仕様は、ページの（サブ） :data:`dictionary`  *「/Resources」*\"\n#~ \" として行われます。リソースディクショナリは、通常 :data:`catalog` \"\n#~ \"のページ親オブジェクトから継承されます。PDFの作成者は、ファイル全体で1つの/ */Resources* \"\n#~ \"を定義し、すべてのページで使用されるすべての画像とフォントを名前で指定する場合があります。これらの場合、:meth:`Page.get_images`\"\n#~ \" と :meth:`Page.get_fonts` はすべてのページに対して同じリストを返します。\"\n\n#~ msgid \"*(Changed in v1.18.0)* -- new dict key *number*, the block number.\"\n#~ msgstr \"*(v1.18.0で変更)* - 新しいdictキー *number* 、ブロック番号。\"\n\n#~ msgid \"\"\n#~ \"*(Changed in v1.18.11)* -- new dict \"\n#~ \"key *transform*, the image transformation \"\n#~ \"matrix for image blocks.\"\n#~ msgstr \"*(v1.18.11で変更)* - 新しいdictキー *transform* 、画像ブロックの画像変換行列。\"\n\n#~ msgid \"\"\n#~ \"*(Changed in v1.18.11)* -- new dict \"\n#~ \"key *size*, the size of the image\"\n#~ \" in bytes for image blocks.\"\n#~ msgstr \"*(v1.18.11で変更)* - 新しいdictキー *size* 、画像ブロックのバイト単位の画像サイズ。\"\n\n#~ msgid \"bit 1: italic (2\\\\ :sup:`1`)\"\n#~ msgstr \"ビット 1: イタリック(2\\\\ :sup:`1`)\"\n\n#~ msgid \"bit 4: bold (2\\\\ :sup:`4`)\"\n#~ msgstr \"ビット 4: ボールド (2\\\\ :sup:`4`)\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/textwriter.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 95c1ee7365714a268b45d71ca863b7ee\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 8dbea99845b74a23bde58d46198a17ac\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 cf3d095401604af48e44cc3a35d66bff\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../textwriter.rst:7 e9730367b10a49359e1d45817a7f7880\nmsgid \"TextWriter\"\nmsgstr \"TextWriter (テキストライター)\"\n\n#: ../../textwriter.rst:9 cda3eb15a6fe4186b26bf8276092c97f\nmsgid \"|pdf_only_class|\"\nmsgstr \"PDFのみ。\"\n\n#: ../../textwriter.rst:11 db627f8740eb4561a5527a9d4ca4e25f\nmsgid \"New in v1.16.18\"\nmsgstr \"v1.16.18で新たに追加\"\n\n#: ../../textwriter.rst:13 67e48f18fa9440238b3a1969be763ace\nmsgid \"\"\n\"This class represents a MuPDF *text* object. The basic idea is to \"\n\"**decouple (1) text preparation, and (2) text output** to PDF pages.\"\nmsgstr \"\"\n\"このクラスはMuPDFの *text* \"\n\"オブジェクトを表します。**基本的なアイデアは、（1）テキストの準備と（2）PDFページへのテキストの出力を切り離すことです** 。\"\n\n#: ../../textwriter.rst:15 5a301b5eac7846a6a95cae297b7806a2\nmsgid \"\"\n\"During **preparation**, a text writer stores any number of text pieces \"\n\"(\\\"spans\\\") together with their positions and individual font \"\n\"information. The **output** of the writer's prepared content may happen \"\n\"multiple times to any PDF page with a compatible page size.\"\nmsgstr \"\"\n\"**準備**中、テキストライターはテキストピース（「スパン」）を任意の数保存し、それぞれの位置と個別のフォント情報とともに保存します。ライターの準備されたコンテンツの\"\n\" **出力** は、互換性のあるページサイズを持つ任意のPDFページに複数回行われる可能性があります。\"\n\n#: ../../textwriter.rst:17 7cf591fcc0cf40af9d587a72b702b960\nmsgid \"\"\n\"A text writer is an elegant alternative to methods \"\n\":meth:`Page.insert_text` and friends:\"\nmsgstr \"テキストライターは、:meth:`Page.insert_text` などと比較して、次の点で優れた代替手段です：\"\n\n#: ../../textwriter.rst:19 8d88b6d0545142bc9885b1dcbb44a4ea\nmsgid \"\"\n\"**Improved text positioning:** Choose any point where insertion of text \"\n\"should start. Storing text returns the \\\"cursor position\\\" after the \"\n\"*last character* of the span.\"\nmsgstr \"\"\n\"**改良されたテキスト配置：** テキストを挿入する開始点を任意に選択できます。テキストの保存はスパンの *最後の文字の後* \"\n\"の「カーソル位置」を返します。\"\n\n#: ../../textwriter.rst:20 4014fff4490f449991524305bfef1c4b\nmsgid \"\"\n\"**Free font choice:** Each text span has its own font and \"\n\":data:`fontsize`. This lets you easily switch when composing a larger \"\n\"text.\"\nmsgstr \"\"\n\"**自由なフォントの選択：** 各テキストスパンには独自のフォントと :data:`fontsize` \"\n\"があります。大きなテキストを作成する際に簡単に切り替えることができます。\"\n\n#: ../../textwriter.rst:21 96e0cdf2386340edafe0ed3b9aa2a211\nmsgid \"\"\n\"**Automatic fallback fonts:** If a character is not supported by the \"\n\"chosen font, alternative fonts are automatically searched. This \"\n\"significantly reduces the risk of seeing unprintable symbols in the \"\n\"output (\\\"TOFUs\\\" -- looking like a small rectangle). PyMuPDF now also \"\n\"comes with the **universal font \\\"Droid Sans Fallback Regular\\\"**, which \"\n\"supports **all Latin** characters (including Cyrillic and Greek), and \"\n\"**all CJK** characters (Chinese, Japanese, Korean).\"\nmsgstr \"\"\n\"**自動フォントのフォールバック：** \"\n\"選択したフォントが文字をサポートしていない場合、代替フォントが自動的に検索されます。これにより、出力で印刷できない記号を見るリスク（「TOFUs」\"\n\" - 小さな四角形に見える）が大幅に減少します。PyMuPDFはまた、**すべてのラテン**文字（キリル文字とギリシャ文字を含む）および \"\n\"**すべてのCJK**文字（中国語、日本語、韓国語）をサポートする **ユニバーサルフォント「Droid Sans Fallback \"\n\"Regular」** を提供します。\"\n\n#: ../../textwriter.rst:22 89a8833cb85e46909d178dc372f5aaac\nmsgid \"\"\n\"**Cyrillic and Greek Support:** The :ref:`Base-14-fonts` have integrated \"\n\"support of Cyrillic and Greek characters **without specifying encoding.**\"\n\" Your text may be a mixture of Latin, Greek and Cyrillic.\"\nmsgstr \"キリル文字とギリシャ文字のサポート：PDFベース14フォントには、エンコーディングを指定せずにキリル文字とギリシャ文字の統合サポートがあります。テキストはラテン文字、ギリシャ文字、キリル文字の混合である可能性があります。\"\n\n#: ../../textwriter.rst:23 939bfd358cb14ee1ac3d682b4310030f\nmsgid \"\"\n\"**Transparency support:** Parameter *opacity* is supported. This offers a\"\n\" handy way to create watermark-style text.\"\nmsgstr \"\"\n\"**透明度のサポート：** パラメータの *透明度* \"\n\"がサポートされています。これはウォーターマークスタイルのテキストを作成する便利な方法を提供します。\"\n\n#: ../../textwriter.rst:24 36106b9c863b43c39d4d348af9680b3e\nmsgid \"\"\n\"**Justified text:** Supported for any font -- not just simple fonts as in\"\n\" :meth:`Page.insert_textbox`.\"\nmsgstr \"\"\n\"**両端揃えのテキスト**： :meth:`Page.insert_textbox` \"\n\"のような単純なフォントだけでなく、すべてのフォントでサポートされています。\"\n\n#: ../../textwriter.rst:25 88d0bcdd76b94defb985b51bd7050a50\nmsgid \"\"\n\"**Reusability:** A TextWriter object exists independent from PDF pages. \"\n\"It can be written multiple times, either to the same or to other pages, \"\n\"in the same or in different PDFs, choosing different colors or \"\n\"transparency.\"\nmsgstr \"\"\n\"**再利用性：** \"\n\"テキストライターオブジェクトはPDFページとは独立して存在します。同じページまたは異なるページ、同じPDFまたは異なるPDFに、異なる色や透明度を選択して複数回書き込むことができます。\"\n\n#: ../../textwriter.rst:27 6ef8000439b141009aae765ba8c24479\nmsgid \"Using this object entails three steps:\"\nmsgstr \"このオブジェクトを使用するには、次の3つのステップが必要です：\"\n\n#: ../../textwriter.rst:29 55dea84332984f3ca477041ec762edcf\nmsgid \"\"\n\"When **created**, a TextWriter requires a fixed **page rectangle** in \"\n\"relation to which it calculates text positions. A text writer can write \"\n\"to pages of this size only.\"\nmsgstr \"\"\n\"**作成** 時に、テキストライターはテキストの位置を計算するために関連する固定 **ページの矩形** \"\n\"を必要とします。テキストライターは、このサイズのページにのみ書き込むことができます。\"\n\n#: ../../textwriter.rst:30 57f72fe6a49d41c7be7ed160f47f3019\nmsgid \"\"\n\"Store text in the TextWriter using methods :meth:`TextWriter.append`, \"\n\":meth:`TextWriter.appendv` and :meth:`TextWriter.fill_textbox` as often \"\n\"as is desired.\"\nmsgstr \"\"\n\"テキストライターを使用してテキストを \"\n\":meth:`TextWriter.append`、:meth:`TextWriter.appendv`、および \"\n\":meth:`TextWriter.fill_textbox` メソッドで必要な回数だけ保存します。\"\n\n#: ../../textwriter.rst:31 ac5cfe5c0bf548bf8358a2cc4efa279b\nmsgid \"Output the TextWriter object on some PDF page(s).\"\nmsgstr \"TextWriter オブジェクトをいくつかのPDFページに出力します。\"\n\n#: ../../textwriter.rst:35 a70f239f39dc44bcbbcc7f367f4f04e8\nmsgid \"\"\n\"Starting with version 1.17.0, TextWriters **do support** text rotation \"\n\"via the *morph* parameter of :meth:`TextWriter.write_text`.\"\nmsgstr \"\"\n\"バージョン1.17.0から、TextWriterは :meth:`TextWriter.write_text` の *morph* \"\n\"パラメータを介したテキストの回転を **サポートしています** 。\"\n\n#: ../../textwriter.rst:37 39efcbe7af8242d59a6e61a1577bd093\nmsgid \"\"\n\"There also exists :meth:`Page.write_text` which combines one or more \"\n\"TextWriters and jointly writes them to a given rectangle and with a given\"\n\" rotation angle -- much like :meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\"また、 :meth:`Page.write_text` \"\n\"も存在し、1つ以上のTextWriterを組み合わせて、指定された矩形と回転角に共同で書き込みます - \"\n\":meth:`Page.show_pdf_page` のように。\"\n\n#: ../../textwriter.rst:41 58759c7fac7b4e859398a94c56641cf5\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../textwriter.rst:41 f8b99b262c4e479daa04854b10a8ca62\nmsgid \"**Short Description**\"\nmsgstr \"**短い説明**\"\n\n#: ../../textwriter.rst:43 5aef1526d3ed401ebe84391dae14eb4e\nmsgid \":meth:`~TextWriter.append`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:43 8a1f849d010e4a069dd84d412203d33f\nmsgid \"Add text in horizontal write mode\"\nmsgstr \"水平書き込みモードでテキストを追加します。\"\n\n#: ../../textwriter.rst:44 a3aab120ca1545a79fce7af51ccd1964\nmsgid \":meth:`~TextWriter.appendv`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:44 30601ff66d064e7bbc6b0711078114c1\nmsgid \"Add text in vertical write mode\"\nmsgstr \"垂直書き込みモードでテキストを追加します。\"\n\n#: ../../textwriter.rst:45 665726b1a2f74150b2cf20b54f5d3864\nmsgid \":meth:`~TextWriter.fill_textbox`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:45 79bdf8fe196e481f9e0f7e6b6d83fa39\nmsgid \"Fill rectangle (horizontal write mode)\"\nmsgstr \"矩形を埋めます（水平書き込みモード）。\"\n\n#: ../../textwriter.rst:46 50d2cf2d0f664964ad637397d702ba01\nmsgid \":meth:`~TextWriter.write_text`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:46 e17f4b99e3a3451090107da06c63083d\nmsgid \"Output TextWriter to a PDF page\"\nmsgstr \"TextWriterをPDFページに出力します。\"\n\n#: ../../textwriter.rst:47 b1dd0ce95c524931a45226c559b5fc7f\nmsgid \":attr:`~TextWriter.color`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:47 977d247f29344daebbc7eb2edad63dda\nmsgid \"Text color (can be changed)\"\nmsgstr \"テキストの色（変更可能です）。\"\n\n#: ../../textwriter.rst:48 a702a69b27f04a1a8bf416872181b83c\nmsgid \":attr:`~TextWriter.last_point`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:48 9c6a85c298f542b0ad83608987c80d7c\nmsgid \"Last written character ends here\"\nmsgstr \"最後に書かれた文字がここで終了します。\"\n\n#: ../../textwriter.rst:49 85bb365488064af39728ae2cff15a95e\nmsgid \":attr:`~TextWriter.opacity`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:49 360143b334e144b188b4fc4606f37cd1\nmsgid \"Text opacity (can be changed)\"\nmsgstr \"テキストの透明度（変更可能です）。\"\n\n#: ../../textwriter.rst:50 44cf6996b53b4136925af2dd23e6d3c3\nmsgid \":attr:`~TextWriter.rect`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:50 a79f2dca7b614eaaa5682eae3f4fa368\nmsgid \"Page rectangle used by this TextWriter\"\nmsgstr \"このTextWriterが使用するページの矩形。\"\n\n#: ../../textwriter.rst:51 86888b68bbf045c8a8e10712005c4259\nmsgid \":attr:`~TextWriter.text_rect`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:51 cd277f06068040caa6fda7759192bbd3\nmsgid \"Area occupied so far\"\nmsgstr \"現在までに占有された領域。\"\n\n#: ../../textwriter.rst:55 07466a577be94bd3ab53ccdfc689e759\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../textwriter.rst 0671bfe1c02041f88c29cf3ea4be264b\n#: 7841a29906a944f189e7e759b6592a97 7cb374b81c074ac69a19656e5756ce8c\n#: 800737d8455c4751bf6f9476b3e4a8df ffbf23da457b4c1fbab7452f6745e439\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:61 1156a360315c4f6cab4971ea0b50224f\nmsgid \"rectangle internally used for text positioning computations.\"\nmsgstr \"テキストの配置計算に内部的に使用される矩形。\"\n\n#: ../../textwriter.rst:62 51fad4a4f8034a198c2666a029ac959b\nmsgid \"\"\n\"sets the transparency for the text to store here. Values outside the \"\n\"interval `[0, 1)` will be ignored. A value of e.g. 0.5 means 50% \"\n\"transparency.\"\nmsgstr \"ここに保存されるテキストの透明度を設定します。区間 `[0, 1)` 外の値は無視されます。例：0.5の場合、50％の透明度を意味します。\"\n\n#: ../../textwriter.rst:63 6b628abb5ffe4a5585ddb2b56255b5dd\nmsgid \"\"\n\"the color of the text. All colors are specified as floats *0 <= color <= \"\n\"1*. A single float represents some gray level, a sequence implies the \"\n\"colorspace via its length.\"\nmsgstr \"\"\n\"テキストの色。すべての色は浮動小数点数 *0 <= color <= 1* \"\n\"として指定されます。単一の浮動小数点数は一定の灰色レベルを表し、シーケンスはその長さを介して色空間を示します。\"\n\n#: ../../textwriter.rst:68 0fa13673da764fdaab29ebfad67bf44c\nmsgid \"*Changed in v1.18.9*\"\nmsgstr \"*バージョン1.18.9で変更*\"\n\n#: ../../textwriter.rst:69 ../../textwriter.rst:100\n#: 08713255cee94718b3bc26b0dda8f233 be3763dd7a294137b65bf5a1770830d3\nmsgid \"*Changed in v1.18.15*\"\nmsgstr \"*バージョン1.18.15で変更*\"\n\n#: ../../textwriter.rst:71 6f8eddc35363416184aad7c44e5d01ef\nmsgid \"Add some new text in horizontal writing.\"\nmsgstr \"水平書き込みで新しいテキストを追加します。\"\n\n#: ../../textwriter.rst:73 ../../textwriter.rst:104\n#: 31e8d87141cf44c5890e5151a73047f4 f7e1346516c8429f9cafb3010a03a215\nmsgid \"start position of the text, the bottom left point of the first character.\"\nmsgstr \"テキストの開始位置、最初の文字の左下の点です。\"\n\n#: ../../textwriter.rst:74 3b2200db94814c6b84f09e2a67431714\nmsgid \"\"\n\"a string of arbitrary length. It will be written starting at position \"\n\"\\\"pos\\\".\"\nmsgstr \"任意の長さの文字列。位置「pos」から書き始められます。\"\n\n#: ../../textwriter.rst:75 ../../textwriter.rst:106\n#: 6080d699b79c4e7cabc81e6632904644 8f2fdb3f4ec442f4b7703714fb642f4c\nmsgid \"a :ref:`Font`. If omitted, `pymupdf.Font(\\\"helv\\\")` will be used.\"\nmsgstr \":ref:`Font`。省略された場合、`pymupdf.Font(\\\"helv\\\")` が使用されます。\"\n\n#: ../../textwriter.rst:76 09fbce8fe4ee46b0a95710e2b4761014\nmsgid \"the :data:`fontsize`, a positive number, default 11.\"\nmsgstr \":data:`fontsize`、正の数、デフォルトは11です。\"\n\n#: ../../textwriter.rst:77 ../../textwriter.rst:108\n#: 4483c3fec8c3452cac52b7d831f281c1 87ccb28c8f1b4453af79b92ad4c5aabd\nmsgid \"\"\n\"the language to use, e.g. \\\"en\\\" for English. Meaningful values should be\"\n\" compliant with the ISO 639 standards 1, 2, 3 or 5. Reserved for future \"\n\"use: currently has no effect as far as we know.\"\nmsgstr \"\"\n\"使用する言語、例：英語の場合は \\\"en\\\"。意味のある値はISO \"\n\"639規格1、2、3、または5に準拠している必要があります。将来の使用を予約しています：現在はわかる限りでは何の効果もありません。\"\n\n#: ../../textwriter.rst:78 d8bd68ad24da40269a51cc710d5053e8\nmsgid \"\"\n\"*(New in v1.18.9)* whether the text should be written from right to left.\"\n\" Applicable for languages like Arabian or Hebrew. Default is ``False``. \"\n\"If ``True``, any Latin parts within the text will automatically \"\n\"converted. There are no other consequences, i.e. \"\n\":attr:`TextWriter.last_point` will still be the rightmost character, and \"\n\"there neither is any alignment taking place. Hence you may want to use \"\n\":meth:`TextWriter.fill_textbox` instead.\"\nmsgstr \"\"\n\"*（バージョン1.18.9で新機能）* テキストを右から左に書くかどうか。アラビア語やヘブライ語などの言語に適用されます。デフォルトは \"\n\"``False`` です。``True`` \"\n\"の場合、テキスト内のラテン語部分は自動的に変換されます。他に何の影響もないため、:attr:`TextWriter.last_point` \"\n\"は依然として最右の文字ですし、配置も行われません。そのため、代わりに :meth:`TextWriter.fill_textbox` \"\n\"を使用することがあります。\"\n\n#: ../../textwriter.rst:79 75daea05a2a449aa9e600dc6f54efa72\nmsgid \"\"\n\"*(New in v1.18.15)* look for the character's Small Capital version in the\"\n\" font. If present, take that value instead. Otherwise the original \"\n\"character (this font or the fallback font) will be taken. The fallback \"\n\"font will never return small caps. For example, this snippet::  >>> doc =\"\n\" pymupdf.open() >>> page = doc.new_page() >>> text = \\\"PyMuPDF: the \"\n\"Python bindings for MuPDF\\\" >>> font = pymupdf.Font(\\\"figo\\\")  # choose a\"\n\" font with small caps >>> tw = pymupdf.TextWriter(page.rect) >>> \"\n\"tw.append((50,100), text, font=font, small_caps=True) >>> \"\n\"tw.write_text(page) >>> doc.ez_save(\\\"x.pdf\\\")  will produce this PDF \"\n\"text:  .. image:: images/img-smallcaps.*\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:79 46eb184e73ae4219ac1e4bed06322f56\nmsgid \"\"\n\"*(New in v1.18.15)* look for the character's Small Capital version in the\"\n\" font. If present, take that value instead. Otherwise the original \"\n\"character (this font or the fallback font) will be taken. The fallback \"\n\"font will never return small caps. For example, this snippet::\"\nmsgstr \"\"\n\"*（バージョン1.18.15で新機能）* \"\n\"フォント内の文字の小文字バージョンを探します。存在する場合、その値が使用されます。それ以外の場合、元の文字（このフォントまたはフォールバックフォント）が使用されます。フォールバックフォントは小文字バージョンを返しません。たとえば、次のスニペット::\"\n\n#: ../../textwriter.rst:90 973003c33fe84aa69d42e2c43c861a09\nmsgid \"will produce this PDF text:\"\nmsgstr \"これにより、このPDFテキストが生成されます：\"\n\n#: ../../textwriter.rst 031973dcb92c46dfb30974b0b0277dbb\n#: 56067c1753344901a2a112d292086782 6fe2f7cc1d5b405588798ce1725db0d6\nmsgid \"Returns\"\nmsgstr \"返り値：\"\n\n#: ../../textwriter.rst:95 ../../textwriter.rst:111\n#: 2916a5791a9446a1be47d9bdde016b5b 2d57d9c3e3404a1b8aaedf35dc4f6d7d\nmsgid \"\"\n\":attr:`text_rect` and :attr:`last_point`. *(Changed in v1.18.0:)* Raises \"\n\"an exception for an unsupported font -- checked via \"\n\":attr:`Font.is_writable`.\"\nmsgstr \"\"\n\":attr:`text_rect` および :attr:`last_point`。 *（v1.18.0 \"\n\"で変更）*：サポートされていないフォントの場合、:attr:`Font.is_writable` を介してチェックされた例外が発生します。\"\n\n#: ../../textwriter.rst:102 53cbfa2552fa46b2837c5848f6ae7eed\nmsgid \"Add some new text in vertical, top-to-bottom writing.\"\nmsgstr \"縦書きの新しいテキストを追加します。\"\n\n#: ../../textwriter.rst:105 77e2561d4b4a448caf4a7b3ecbc624ce\nmsgid \"a string. It will be written starting at position \\\"pos\\\".\"\nmsgstr \"文字列。 \\\"pos\\\" から開始して書き込まれます。\"\n\n#: ../../textwriter.rst:107 1195a41741cd44ca8653fce3a3c8b23f\nmsgid \"the :data:`fontsize`, a positive float, default 11.\"\nmsgstr \":data:`fontsize`、正の浮動小数点数、デフォルトは 11 です。\"\n\n#: ../../textwriter.rst:109 ../../textwriter.rst:133\n#: 48cdfcdb373b4a939b9ac2491aaf9f76 a007fa3bc26e4925bac3b3884fa1d6f4\nmsgid \"*(New in v1.18.15)* see :meth:`append`.\"\nmsgstr \"*（v1.18.15 で新しい）* 詳細は :meth:`append` を参照してください。\"\n\n#: ../../textwriter.rst:115 131d2ddda39f47e5b8750ce4e02aacf1\nmsgid \"\"\n\"Changed in 1.17.3: New parameter `pos` to specify where to start writing \"\n\"within rectangle.\"\nmsgstr \"1.17.3で変更：新しいパラメーター `pos` を追加して、矩形内での書き込みを開始する位置を指定できるようにしました。\"\n\n#: ../../textwriter.rst:116 29062b4cba8b458c9715b63563932eea\nmsgid \"\"\n\"Changed in v1.18.9: Return list of lines which do not fit in rectangle. \"\n\"Support writing right-to-left (e.g. Arabian, Hebrew).\"\nmsgstr \"v1.18.9で変更：矩形に収まらない行のリストを返すようにしました。右から左に書くサポートを追加（アラビア語、ヘブライ語など）。\"\n\n#: ../../textwriter.rst:117 1af15893d8c0406eaba47e8cbc605623\nmsgid \"Changed in v1.18.15: Prefer small caps if supported by the font.\"\nmsgstr \"v1.18.15で変更：フォントがサポートしている場合、小文字のテキストを優先します。\"\n\n#: ../../textwriter.rst:119 557382b2514d472bbe73f5017c792395\nmsgid \"\"\n\"Fill a given rectangle with text in horizontal writing mode. This is a \"\n\"convenience method to use as an alternative for :meth:`append`.\"\nmsgstr \"指定された矩形を水平書きモードでテキストで埋めます。これは、:meth:`append` の代替手段として使用する便利な方法です。\"\n\n#: ../../textwriter.rst:121 cef4e997c224414e95918704fa70b178\nmsgid \"the area to fill. No part of the text will appear outside of this.\"\nmsgstr \"埋める領域。テキストのいずれの部分もこれの外には表示されません。\"\n\n#: ../../textwriter.rst:122 eb9a1f87715c476190b440d505b21385\nmsgid \"\"\n\"the text. Can be specified as a (UTF-8) string or a list / tuple of \"\n\"strings. A string will first be converted to a list using *splitlines()*.\"\n\" Every list item will begin on a new line (forced line breaks).\"\nmsgstr \"\"\n\"テキスト。UTF-8文字列または文字列のリスト/タプルとして指定できます。文字列は最初に *splitlines()* \"\n\"を使用してリストに変換されます。各リストアイテムは新しい行で始まります（強制的な改行が行われます）。\"\n\n#: ../../textwriter.rst:123 adaa607ca4b34119b1413a21aa5d5703\nmsgid \"\"\n\"*(new in v1.17.3)* start storing at this point. Default is a point near \"\n\"rectangle top-left.\"\nmsgstr \"*（v1.17.3で新規）* このポイントから記憶を開始します。デフォルトは矩形の左上近くのポイントです。\"\n\n#: ../../textwriter.rst:124 093d30283065429a8003316402078989\nmsgid \"the :ref:`Font`, default `pymupdf.Font(\\\"helv\\\")`.\"\nmsgstr \":ref:`Font`、デフォルトは `pymupdf.Font(\\\"helv\\\")`。\"\n\n#: ../../textwriter.rst:125 fa67844b1bdc4fd5b33c77ea89ae7619\nmsgid \"the :data:`fontsize`.\"\nmsgstr \":data:`fontsize`\"\n\n#: ../../textwriter.rst:126 a3f0cf660cc34b2aa6461b460ccc9fd7\nmsgid \"\"\n\"text alignment. Use one of TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, \"\n\"TEXT_ALIGN_RIGHT or TEXT_ALIGN_JUSTIFY.\"\nmsgstr \"テキストの配置。TEXT_ALIGN_LEFT、TEXT_ALIGN_CENTER、TEXT_ALIGN_RIGHT、またはTEXT_ALIGN_JUSTIFYのいずれかを使用します。\"\n\n#: ../../textwriter.rst:127 fab2e37b003c4547a135db4871ab87f9\nmsgid \"\"\n\"*(New in v1.18.9)* whether the text should be written from right to left.\"\n\" Applicable for languages like Arabian or Hebrew. Default is ``False``. \"\n\"If ``True``, any Latin parts are automatically reverted. You must still \"\n\"set the alignment (if you want right alignment), it does not happen \"\n\"automatically -- the other alignment options remain available as well.\"\nmsgstr \"\"\n\"*(v1.18.9で新規）* テキストを右から左に書くかどうか。アラビア語やヘブライ語などの言語に適用可能です。デフォルトは ``False`` \"\n\"です。``True`` \"\n\"の場合、ラテン文字部分は自動的に反転されます。右寄せを希望する場合、引き続き配置を設定する必要があります（他の配置オプションも利用可能）。\"\n\n#: ../../textwriter.rst:128 fbd4a0182852411d9c83784e6421be47\nmsgid \"\"\n\"on text overflow do nothing, warn, or raise an exception. Overflow text \"\n\"will never be written. **Changed in v1.18.9:**  * Default is ``None``. * \"\n\"The list of overflow lines will be returned.\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:128 0e6db582f2eb4eb28e4c2efbd9fb40e1\nmsgid \"\"\n\"on text overflow do nothing, warn, or raise an exception. Overflow text \"\n\"will never be written. **Changed in v1.18.9:**\"\nmsgstr \"テキストのオーバーフローがある場合、何もしない、警告する、または例外を発生させるかどうか。オーバーフローテキストは書き込まれません。**v1.18.9で変更：**\"\n\n#: ../../textwriter.rst:130 cdae6e2706854c9e826f849d936c11ee\nmsgid \"Default is ``None``.\"\nmsgstr \"デフォルトは ``None`` です。\"\n\n#: ../../textwriter.rst:131 1bda032411484b10b23479232b916047\nmsgid \"The list of overflow lines will be returned.\"\nmsgstr \"オーバーフローラインのリストが返されます。\"\n\n#: ../../textwriter.rst 035f3f34d091461bbe3cc1d030bfe153\n#: 1871d0ab981b44759c8973a335232ef3 6459020d5302480fb99a57af3fd39d02\n#: 92e14712db2944b694cdf765796b471d d0a0b9758d76412fb2a1f68276a1f782\n#: f3e6dee2f74245bfa95d18620e9bd73d\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:136 396c812b4c0346d69cbc578eaae29744\nmsgid \"\"\n\"*New in v1.18.9* -- List of lines that did not fit in the rectangle. Each\"\n\" item is a tuple `(text, length)` containing a string and its length (on \"\n\"the page).\"\nmsgstr \"\"\n\"*v1.18.9で新規* -矩形に収まらなかった行のリスト。各アイテムは、文字列とそのページ上の長さ（長さ）を含むタプル `(text, \"\n\"length)` です。\"\n\n#: ../../textwriter.rst:138 cd3a09fa82ee40e399e27a6aa0c1235d\nmsgid \"\"\n\"Use these methods as often as is required -- there is no technical limit \"\n\"(except memory constraints of your system). You can also mix \"\n\":meth:`append` and text boxes and have multiple of both. Text positioning\"\n\" is exclusively controlled by the insertion point. Therefore there is no \"\n\"need to adhere to any order. *(Changed in v1.18.0:)* Raise an exception \"\n\"for an unsupported font -- checked via :attr:`Font.is_writable`.\"\nmsgstr \"\"\n\"これらのメソッドは必要な回数だけ使用できます。技術的な制限はありません（システムのメモリ制約を除く）。また、:meth:`append` \"\n\"とテキストボックスを混在させ、それぞれ複数持つこともできます。テキストの配置は挿入ポイントによってのみ制御されます。したがって、特定の順序に従う必要はありません。*（v1.18.0で変更）*\"\n\" ：サポートされていないフォントに対して例外を発生させます - :attr:`Font.is_writable` をチェックします。\"\n\n#: ../../textwriter.rst:143 54709b98b30a47ac89166f31faf2772a\nmsgid \"\"\n\"Write the TextWriter text to a page, which is the only mandatory \"\n\"parameter. The other parameters can be used to temporarily override the \"\n\"values used when the TextWriter was created.\"\nmsgstr \"TextWriterのテキストをページに書き込みます。これは唯一の必須パラメータで、TextWriterが作成されたときに使用される値を一時的にオーバーライドするために、他のパラメータを使用できます。\"\n\n#: ../../textwriter.rst:145 59f4fdcbbc44452680ba4c0c95aa5cff\nmsgid \"write to this :ref:`Page`.\"\nmsgstr \"この :ref:`Page` に書き込みます。\"\n\n#: ../../textwriter.rst:146 ../../textwriter.rst:147\n#: 376b4dcec8264f3db2f6be76d778904b d45c4d5a07474ef4a0cd683fdd04bcdc\nmsgid \"override the value of the TextWriter for this output.\"\nmsgstr \"この出力のためにTextWriterの値をオーバーライドします。\"\n\n#: ../../textwriter.rst:148 ee07ac03480b41539d94053d359dd9d3\nmsgid \"\"\n\"modify the text appearance by applying a matrix to it. If provided, this \"\n\"must be a sequence *(fixpoint, matrix)* with a point-like *fixpoint* and \"\n\"a matrix-like *matrix*. A typical example is rotating the text around \"\n\"*fixpoint*.\"\nmsgstr \"\"\n\"テキストの外観を変更するために、それに行列を適用して修正します。提供される場合、これは *（fixpoint、matrix）* \"\n\"としてシーケンスでなければなりません。point-like *fixpoint* とmatrix-like *matrix* \"\n\"を持っています。典型的な例は、テキストを *fixpoint* の周りで回転させることです。\"\n\n#: ../../textwriter.rst:149 b45dc013b8e740f9bef33593ed5c8711\nmsgid \"put in foreground (default) or background.\"\nmsgstr \"前景（デフォルト）または背景に配置します。\"\n\n#: ../../textwriter.rst:150 ba9cfbd9695340699d7179b74412ef18\nmsgid \"*(new in v1.18.4)* the :data:`xref` of an :data:`OCG` or :data:`OCMD`.\"\nmsgstr \"*（v1.18.4で新規）* :data:`OCG` または :data:`OCMD` の :data:`xref`。\"\n\n#: ../../textwriter.rst:151 9523549f48f246a3ae03b7bc5f901456\nmsgid \"\"\n\"The PDF `Tr` operator value. Values: 0 (default), 1, 2, 3 (invisible).  \"\n\".. image:: images/img-rendermode.*\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:151 78528b40a6544fe0a046dee8ae6857ef\nmsgid \"The PDF `Tr` operator value. Values: 0 (default), 1, 2, 3 (invisible).\"\nmsgstr \"PDF `Tr` 演算子の値。値：0（デフォルト）、1、2、3（不可視）。\"\n\n#: ../../textwriter.rst:158 525f73853e924927ad796c65943a368d\nmsgid \"The area currently occupied.\"\nmsgstr \"現在占有されている領域。\"\n\n#: ../../textwriter.rst:160 ../../textwriter.rst:184\n#: ba565ed25cdd42f7862fcb93e757cf70 be5a7d304fd0479ea3d522fa0b628537\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:164 87ebb8ff55c24240abc1589af86e4a9a\nmsgid \"\"\n\"The \\\"cursor position\\\" -- a :ref:`Point` -- after the last written \"\n\"character (its bottom-right).\"\nmsgstr \"最後に書かれた文字の後にある「カーソル位置」 - :ref:`Point` 形式。\"\n\n#: ../../textwriter.rst:166 ac55d30024ef4851bc1e890d44698e93\nmsgid \":ref:`Point`\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:170 3f90c9a1dc4c4511a85d2dd1d614e275\nmsgid \"The text opacity (modifiable).\"\nmsgstr \"テキストの不透明度（変更可能）。\"\n\n#: ../../textwriter.rst:176 40b6c71ad92443f69b941e2ae68ef65d\nmsgid \"The text color (modifiable).\"\nmsgstr \"テキストの色（変更可能）。\"\n\n#: ../../textwriter.rst:182 c8c0cc26dcc643b4b7a36449cc37508b\nmsgid \"\"\n\"The page rectangle for which this TextWriter was created. Must not be \"\n\"modified.\"\nmsgstr \"このTextWriterが作成されたページの長方形。変更しないでください。\"\n\n#: ../../textwriter.rst:187 96d56c1eedc9403da49260989a4dc7c5\n#, fuzzy\nmsgid \"\"\n\"To see some demo scripts dealing with TextWriter, have a look at `the \"\n\"TextWriter demo scripts <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/textwriter>`_.\"\nmsgstr \"\"\n\"TextWriterを扱うデモスクリプトを見るには、`この <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/textwriter>`_ リポジトリをご覧ください。\"\n\n#: ../../textwriter.rst:189 86f5ad85ef9f430798003667a5d4bba8\nmsgid \"Opacity and color apply to **all the text** in this object.\"\nmsgstr \"不透明度と色は、このオブジェクト内の **すべてのテキスト** に適用されます。\"\n\n#: ../../textwriter.rst:190 3fd56e7645674dd592624498a3b40033\nmsgid \"\"\n\"If you need different colors / transparency, you must create a separate \"\n\"TextWriter. Whenever you determine the color should change, simply append\"\n\" the text to the respective TextWriter using the previously returned \"\n\":attr:`last_point` as position for the new text span.\"\nmsgstr \"\"\n\"異なる色/透明度が必要な場合、別々のTextWriterを作成する必要があります。色が変更されるべきと判断した場合、新しいテキストスパンの位置として前回返された\"\n\" :attr:`last_point` を使用して、対応するTextWriterにテキストを追加するだけです。\"\n\n#: ../../textwriter.rst:191 473cca9e82e445e7a947ffeaead9f1d6\nmsgid \"\"\n\"Appending items or text boxes can occur in arbitrary order: only the \"\n\"position parameter controls where text appears.\"\nmsgstr \"アイテムまたはテキストボックスの追加は任意の順序で発生できます：テキストが表示される位置を制御するのは、位置パラメータのみです。\"\n\n#: ../../textwriter.rst:192 e86c99a3e580410c80b33c1b9273d1e5\nmsgid \"\"\n\"Font and :data:`fontsize` can freely vary within the same TextWriter. \"\n\"This can be used to let text with different properties appear on the same\"\n\" displayed line: just specify *pos* accordingly, and e.g. set it to \"\n\":attr:`last_point` of the previously added item.\"\nmsgstr \"\"\n\"同じTextWriter内でフォントと :data:`fontsize` \"\n\"を自由に変更できます。これは、異なるプロパティを持つテキストが同じ表示される行に表示されるようにするために使用できます。posを適切に指定し、前に追加したアイテムの\"\n\" :attr:`last_point` に設定してください。\"\n\n#: ../../textwriter.rst:193 0dd912f04fa84ab7832bd944567f6dc1\nmsgid \"\"\n\"You can use the *pos* argument of :meth:`TextWriter.fill_textbox` to set \"\n\"the position of the first text character. This allows filling the same \"\n\"textbox with contents from different :ref:`TextWriter` objects, thus \"\n\"allowing for multiple colors, opacities, etc.\"\nmsgstr \"\"\n\":meth:`TextWriter.fill_textbox` の *pos* \"\n\"引数を使用して、最初のテキスト文字の位置を設定できます。これにより、異なる :ref:`TextWriter` \"\n\"オブジェクトからのコンテンツを含む同じテキストボックスを埋めることができ、複数の色、不透明度などが可能になります。\"\n\n#: ../../textwriter.rst:194 46ddcc45b9594214860870dcb571f619\nmsgid \"\"\n\"MuPDF does not support all fonts with this feature, e.g. no Type3 fonts. \"\n\"Starting with v1.18.0 this can be checked via the font attribute \"\n\":attr:`Font.is_writable`. This attribute is also checked when using \"\n\":ref:`TextWriter` methods.\"\nmsgstr \"\"\n\"MuPDFは、この機能を持つすべてのフォントをサポートしているわけではありません。たとえば、Type3フォントはサポートされていません。v1.18.0以降、:attr:`Font.is_writable`\"\n\" 属性を使用して、これを確認できます。この属性は、:ref:`TextWriter` メソッドを使用する際にもチェックされます。\"\n\n#: ../../footer.rst:46 b6d5682a116d45b9b5a6850c9cfd6f9e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"\"\n#~ \"**Free font choice:** Each text span \"\n#~ \"has its own font and fontsize. \"\n#~ \"This lets you easily switch when \"\n#~ \"composing a larger text.\"\n#~ msgstr \"\"\n\n#~ msgid \"the fontsize, a positive number, default 11.\"\n#~ msgstr \"\"\n\n#~ msgid \"the fontsize, a positive float, default 11.\"\n#~ msgstr \"\"\n\n#~ msgid \"the fontsize.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Font and fontsize can freely vary \"\n#~ \"within the same TextWriter. This can \"\n#~ \"be used to let text with different\"\n#~ \" properties appear on the same \"\n#~ \"displayed line: just specify *pos* \"\n#~ \"accordingly, and e.g. set it to \"\n#~ \":attr:`last_point` of the previously added \"\n#~ \"item.\"\n#~ msgstr \"\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/the-basics.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ebd72ea23c554adea55b860ac32cfd10\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 d808fab239944edbb4a07604487c3d4d\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 32d34325b50d49718d4ae087152d121b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../the-basics.rst:8 3ef401bbe47d4d928056b1ad88406df4\nmsgid \"The Basics\"\nmsgstr \"基本\"\n\n#: ../../the-basics.rst:13 7ad7d2aeeb0949939d1edf110e9cde48\nmsgid \"Opening a File\"\nmsgstr \"ファイルを開く\"\n\n#: ../../the-basics.rst:16 b3977994add44c128857ebe6778dbce8\nmsgid \"To open a file, do the following:\"\nmsgstr \"ファイルを開くには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:27 ../../the-basics.rst:58 ../../the-basics.rst:119\n#: ../../the-basics.rst:149 ../../the-basics.rst:199 ../../the-basics.rst:249\n#: ../../the-basics.rst:287 ../../the-basics.rst:377 ../../the-basics.rst:416\n#: ../../the-basics.rst:467 ../../the-basics.rst:553 ../../the-basics.rst:638\n#: ../../the-basics.rst:694 ../../the-basics.rst:886 ../../the-basics.rst:1070\n#: 2739866db7be4d6fbd854a42404c20bb 279266de676f42ee8ca372b72f1b50d3\n#: 42d583c1c82e4c1c9c61e4221d22858b 4bbc83d3c8014f94bca9c10402d0772f\n#: 6eb5cd518be24829a8fea50dc936924e 6f01de37c57b45dd826d3e9df5dd3352\n#: 72e59350df88431bb0d56787d262e6f3 76f22999a4234db0a736d9b66557dd9a\n#: 9aa232f9bff64aec84bc0061ae859fde a56f4151e39f4227823677221a30af73\n#: cb848559a7ed4bceb96742c75b6a8a26 d2d7c31ddd6a4481afad882faa434f0c\n#: d8991f84c3e6479fa2c6050dd8b27e28 e70c606f8abd4024a11d97fb8f7cd006\n#: fabe4bd1a2d042da9318fbae362a32ad\nmsgid \"**Taking it further**\"\nmsgstr \"**さらに進む**\"\n\n#: ../../the-basics.rst:29 1ec0b9c37a314b2cb8dde60de149c32e\nmsgid \"\"\n\"See the :ref:`list of supported file types<Supported_File_Types>` and \"\n\":ref:`The How to Guide on Opening Files <HowToOpenAFile>` for more \"\n\"advanced options.\"\nmsgstr \"\"\n\"より高度なオプションについては、:ref:`サポートされている <Supported_File_Types>` と \"\n\":ref:`ファイルを開く方法ガイド<HowToOpenAFile>` のリストを参照してください。\"\n\n#: ../../the-basics.rst:38 cb07704fb73043b2827ddfe5306bb8eb\nmsgid \"Extract text from a |PDF|\"\nmsgstr \"|PDF| からテキストを抽出する\"\n\n#: ../../the-basics.rst:40 63223b54f3cc495aa83fddc584a650c9\nmsgid \"To extract all the text from a |PDF| file, do the following:\"\nmsgstr \"|PDF| ファイルからすべてのテキストを抽出するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:54 82cde87ae4a8477cb30daea5d72f5f54\nmsgid \"\"\n\"Of course it is not just |PDF| which can have text extracted - all the \"\n\":ref:`supported document file formats <About_Feature_Matrix>` such as \"\n\":title:`MOBI`, :title:`EPUB`, :title:`TXT` can have their text extracted.\"\nmsgstr \"\"\n\"もちろん、PDFだけでなく、MOBI、EPUB、TXTなどの :ref:`サポートされているドキュメントファイル形式 \"\n\"<About_Feature_Matrix>` でもテキストを抽出できます。\"\n\n#: ../../the-basics.rst:60 68a8a1314b8a474a9636d7ff5ebf2245\nmsgid \"\"\n\"If your document contains image based text content the use OCR on the \"\n\"page for subsequent text extraction:\"\nmsgstr \"もし文書に画像ベースのテキストコンテンツが含まれている場合は、後続のテキスト抽出のためにそのページでOCRを使用してください。\"\n\n#: ../../the-basics.rst:67 ../../the-basics.rst:121\n#: 009d24e7339b46f7afe03c6afa62fbd2 b502b55793844906a001df204caff15f\nmsgid \"\"\n\"There are many more examples which explain how to extract text from \"\n\"specific areas or how to extract tables from documents. Please refer to \"\n\"the :ref:`How to Guide for Text<RecipesText>`.\"\nmsgstr \"特定の領域からテキストを抽出する方法や、文書から表を抽出する方法など、さらに多くの例があります。テキストの方法ガイドを参照してください。\"\n\n#: ../../the-basics.rst:69 58a9cf1efe6a40b5ada05038e2d55412\nmsgid \"\"\n\"You can now also :ref:`extract text in Markdown \"\n\"format<rag_outputting_as_md>`.\"\nmsgstr \":ref:`Markdown形式でテキストを抽出 <rag_outputting_as_md>` することもできます。\"\n\n#: ../../the-basics.rst:71 ../../the-basics.rst:123 ../../the-basics.rst:153\n#: ../../the-basics.rst:208 ../../the-basics.rst:255 ../../the-basics.rst:291\n#: ../../the-basics.rst:318 ../../the-basics.rst:343 ../../the-basics.rst:383\n#: ../../the-basics.rst:420 ../../the-basics.rst:474 ../../the-basics.rst:500\n#: ../../the-basics.rst:527 ../../the-basics.rst:608 ../../the-basics.rst:659\n#: ../../the-basics.rst:698 ../../the-basics.rst:762 ../../the-basics.rst:821\n#: ../../the-basics.rst:898 ../../the-basics.rst:928 ../../the-basics.rst:964\n#: ../../the-basics.rst:990 ../../the-basics.rst:1074\n#: 06196b3b11364bd8ba72a68806270fbc 28f136db73ea4ff8b27a322e19a05299\n#: 2a2f674929bc4956b9fa645ec55231da 2a42d66f67ea469da857b3aefcefb111\n#: 34dfbca2e1ef487085d769c401e479da 4b5819a0804e42669c6c95bd78540195\n#: 57551550d33b446da752ec01b2d38be1 58193e34f85e4f3286969bb715d2ed1b\n#: 758afc8b33924ed7afa93712789855ff 7c7a34a487ba49719ca245b940618040\n#: 926638700d944932adaab0f81e219328 99f090981eab4af2adb7c096da2ae2e3\n#: 9f4be351ab174a7fbfd5426ee671e7f8 ac69cd30aed24f97aa9c7c5eff88d4b3\n#: adf8863e8d274a1e9e4cd774f4b6c024 b6dfec45d83b42e68fc997fcb0213e92\n#: c34132ed22984098ac5b8bd1e9a4806b c8f4c6c1d0ee4228977d9294144fbc0e\n#: cb4e3c70daa14279926090c987c7a950 e547959996fc49f483ba7574079782d7\n#: f8047ddd3ad0454c8c7eb0d0258590f1 fca50bef410a492eb5e9db5cd98453f0\n#: fd039b9c5e9e49b2a72044dabcf4d52c\nmsgid \"**API reference**\"\nmsgstr \"**APIリファレンス**\"\n\n#: ../../the-basics.rst:73 099a4007de224f26813b7e0c6086aba5\nmsgid \":meth:`Page.get_text`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:85 3478a0ef399a4f90bdf04e54b4b848f8\nmsgid \"Extract images from a |PDF|\"\nmsgstr \"|PDF| から画像を抽出する\"\n\n#: ../../the-basics.rst:87 2c137c284bae4ff3bd22402af36ebe06\nmsgid \"To extract all the images from a |PDF| file, do the following:\"\nmsgstr \"|PDF| すべての画像を抽出するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:125 58022a36615f4658a70db9b3d3cb08c0\nmsgid \":meth:`Page.get_images`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:126 887f2573340f469a8f4bb2e328eaf5a3\nmsgid \":ref:`Pixmap<Pixmap>`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:133 734558bdb8694762a5d412b1e2faa7e9\nmsgid \"Extract vector graphics\"\nmsgstr \"ベクトルグラフィックスを抽出\"\n\n#: ../../the-basics.rst:135 0377de0bb75a443c8d1266b4d5b21c9a\nmsgid \"To extract all the vector graphics from a document page, do the following:\"\nmsgstr \"ドキュメントのページからすべてのベクトルグラフィックスを抽出するには、以下の手順に従います：\"\n\n#: ../../the-basics.rst:145 495a59882911438aae6c87d4c09cc096\nmsgid \"\"\n\"This will return a dictionary of paths for any vector drawings found on \"\n\"the page.\"\nmsgstr \"これにより、ページ上で見つかったすべてのベクター図形のパスの辞書が返されます。\"\n\n#: ../../the-basics.rst:151 edb401df140347688dfb686967959746\nmsgid \"\"\n\"Please refer to: :ref:`How to Extract \"\n\"Drawings<RecipesDrawingAndGraphics_Extract_Drawings>`.\"\nmsgstr \"\"\n\"次のページを参照してください： :ref:`「描画の抽出方法」 \"\n\"<RecipesDrawingAndGraphics_Extract_Drawings>`。\"\n\n#: ../../the-basics.rst:155 99278f5d80fa49a1b1b55bb0d070fe0a\n#, fuzzy\nmsgid \":meth:`Page.get_drawings`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:166 3f2a04b771b4465fba3841d4145c94eb\nmsgid \"Merging |PDF| files\"\nmsgstr \"|PDF| ファイルの結合\"\n\n#: ../../the-basics.rst:168 00fbed70866b44078ae8b3f72592c767\nmsgid \"To merge |PDF| files, do the following:\"\nmsgstr \"|PDF| ファイルを結合するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:182 2c3a5d3d3d264086993c70ed0f9610ad\nmsgid \"Merging |PDF| files with other types of file\"\nmsgstr \"|PDF| ァイルと他の種類のファイルを結合する\"\n\n#: ../../the-basics.rst:184 2a56bc4e77b14621bdc02e63f9456750\nmsgid \"\"\n\"With :meth:`Document.insert_file` you can invoke the method to merge \"\n\":ref:`supported files<Supported_File_Types>` with |PDF|. For example:\"\nmsgstr \"\"\n\":meth:`Document.insert_file` \"\n\"を使用すると、サポートされているファイルをPDFと結合するメソッドを呼び出すことができます。例えば：\"\n\n#: ../../the-basics.rst:201 f2e00ac506914ac4b90cf6ba9b933452\n#, fuzzy\nmsgid \"\"\n\"It is easy to join PDFs with :meth:`Document.insert_pdf` & \"\n\":meth:`Document.insert_file`. Given open |PDF| documents, you can copy \"\n\"page ranges from one to the other. You can select the point where the \"\n\"copied pages should be placed, you can revert the page sequence and also \"\n\"change page rotation.\"\nmsgstr \"\"\n\":meth:`Document.insert_pdf` と :meth:`Document.insert_file` \"\n\"を使用すれば、PDFを簡単に結合できます。開かれたPDF文書がある場合、片方のPDFから別のPDFへページの範囲をコピーすることができます。コピーされたページが配置される位置を選択することができ、ページの順序を元に戻すこともできます。さらに、ページの回転も変更することができます。詳細な説明はこの\"\n\" `Wiki <https://github.com/pymupdf/PyMuPDF/wiki/Inserting-Pages-from-\"\n\"other-PDFs>`_ の記事に記載されています。\"\n\n#: ../../the-basics.rst:203 097d528e7b89483887fe9b103286246d\nmsgid \"\"\n\"The GUI script `join.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/join-documents/join.py>`_ uses this method\"\n\" to join a list of files while also joining the respective table of \"\n\"contents segments. It looks like this:\"\nmsgstr \"\"\n\"GUIスクリプト `join.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/join-documents/join.py>`_ \"\n\"では、この方法を使用してファイルのリストを結合し、それぞれの目次セグメントも結合します。スクリプトの見た目は以下のようになっています:\"\n\n#: ../../the-basics.rst:210 1fbf6ae246834c7daa68bb87e30c563d\nmsgid \":meth:`Document.insert_pdf`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:211 eb458481793c4cb1b1e232362c454d05\nmsgid \":meth:`Document.insert_file`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:218 b75e34a3e76543769aa5c7b08099b88e\nmsgid \"Working with Coordinates\"\nmsgstr \"座標を扱う\"\n\n#: ../../the-basics.rst:220 ba6915f5f3614cfc866c5d6a96dd7561\nmsgid \"\"\n\"There is one *mathematical term* that you should feel comfortable with \"\n\"when using |PyMuPDF| -  **\\\"coordinates\\\"**. Please have a quick look at \"\n\"the :ref:`Coordinates` section to understand the coordinate system to \"\n\"help you with positioning objects and understand your document space.\"\nmsgstr \"\"\n\"|PyMuPDF| を使用する際に快適に感じるべき *数学用語* が1つあります - **「座標」** \"\n\"です。オブジェクトの配置や文書空間の理解に役立つ座標系を理解するために、:ref:`Coordinates` セクションを簡単にご覧ください。\"\n\n#: ../../the-basics.rst:229 1a7cee38451a4ac49f536db1c8867f23\nmsgid \"Adding a watermark to a |PDF|\"\nmsgstr \"|PDF| ファイルにウォータマークを追加する方法\"\n\n#: ../../the-basics.rst:231 7a831a320dcb4d03b66a33b5656a1592\nmsgid \"To add a watermark to a |PDF| file, do the following:\"\nmsgstr \"|PDF| ファイルにウォータマークを追加するには、以下の手順を実行してください:\"\n\n#: ../../the-basics.rst:251 32163f8855f94b3da489e46235d0f84f\nmsgid \"\"\n\"Adding watermarks is essentially as simple as adding an image at the base\"\n\" of each |PDF| page. You should ensure that the image has the required \"\n\"opacity and aspect ratio to make it look the way you need it to.\"\nmsgstr \"ウォータマークを追加することは、基本的には各PDFページの底辺に画像を追加するだけです。画像が必要な透明度とアスペクト比を持っていることを確認して、必要な見た目になるようにします。\"\n\n#: ../../the-basics.rst:253 8b5f52f2d540405f8e19f3ff6efd6007\nmsgid \"\"\n\"In the example above a new image is created from each file reference, but\"\n\" to be more performant (by saving memory and file size) this image data \"\n\"should be referenced only once - see the code example and explanation on \"\n\":meth:`Page.insert_image` for the implementation.\"\nmsgstr \"\"\n\"前述の例では、各ファイル参照から新しい画像が作成されていますが、メモリとファイルサイズを節約するために、この画像データは1回だけ参照されるようにすると、パフォーマンスが向上します\"\n\" - Page.insert_image()のコード例と説明を参照してください。\"\n\n#: ../../the-basics.rst:257 fcfe127ad9414e8a9a9f6fe506eca749\nmsgid \":meth:`Page.bound`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:258 ../../the-basics.rst:294\n#: 2122203304f24c7e86364c4e44d8c515 5bd4a37b290b484ab12ffef1d743e039\nmsgid \":meth:`Page.insert_image`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:267 74156cf07c4c44abb86f01275234c22c\nmsgid \"Adding an image to a |PDF|\"\nmsgstr \"|PDF| に画像を追加する\"\n\n#: ../../the-basics.rst:269 e4ad47cff3e149b09cfcee436ce71ec0\nmsgid \"To add an image to a |PDF| file, for example a logo, do the following:\"\nmsgstr \"PDFファイルに画像を追加するためには、例えばロゴを追加する場合、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:289 ef303cbd63ea4d6cae44d744a77253f8\nmsgid \"\"\n\"As with the watermark example you should ensure to be more performant by \"\n\"only referencing the image once if possible - see the code example and \"\n\"explanation on :meth:`Page.insert_image`.\"\nmsgstr \"\"\n\"ウォータマークの例と同様に、できる限り画像を1回だけ参照することで、より効率的な処理を行うようにしてください。詳細は \"\n\":meth:`Page.insert_image` のコード例と説明を参照してください。\"\n\n#: ../../the-basics.rst:293 0a5e74d57a334f90b301d4f7266ae6a7\nmsgid \":ref:`Rect<Rect>`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:303 97f7c41b4fcc40d297f51e89344ec00e\nmsgid \"Rotating a |PDF|\"\nmsgstr \"|PDF| を回転させる\"\n\n#: ../../the-basics.rst:305 a6bb30db140947ee94661859e458334a\nmsgid \"To add a rotation to a page, do the following:\"\nmsgstr \"ページに回転を追加するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:320 5b2ac1a6f5284ffdbcf63f04a5bb87e3\nmsgid \":meth:`Page.set_rotation`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:328 5d0f43e3da814e9195c2500beb9b2aae\nmsgid \"Cropping a |PDF|\"\nmsgstr \"|PDF| のトリミング\"\n\n#: ../../the-basics.rst:330 ebcd5ad854a344fb8fdb76e0f157f822\nmsgid \"To crop a page to a defined :ref:`Rect<Rect>`, do the following:\"\nmsgstr \"定義された矩形 :ref:`Rect<Rect>` にページをトリミングするには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:345 10f26d2a0e9f428c877fe76eca3149b4\nmsgid \":meth:`Page.set_cropbox`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:354 37f2015ccbe843179609bdd2ce54ce25\nmsgid \":index:`Attaching Files <triple: attach;embed;file>`\"\nmsgstr \":index:`ファイルの添付 <triple: attach;embed;file>`\"\n\n#: ../../the-basics.rst:356 73fa4a36d3114266a5b8c37898cdd520\nmsgid \"To attach another file to a page, do the following:\"\nmsgstr \"別のファイルをページに添付するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:379 fef41696e0104638bfa7e9e46f94d5da\nmsgid \"\"\n\"When adding the file with :meth:`Page.add_file_annot` note that the third\"\n\" parameter for the `filename` should include the actual file extension. \"\n\"Without this the attachment possibly will not be able to be recognized as\"\n\" being something which can be opened. For example, if the `filename` is \"\n\"just *\\\"attachment\\\"* when view the resulting PDF and attempting to open \"\n\"the attachment you may well get an error. However, with \"\n\"*\\\"attachment.pdf\\\"* this can be recognized and opened by PDF viewers as \"\n\"a valid file type.\"\nmsgstr \"\"\n\":meth:`Page.add_file_annot` \"\n\"でファイルを追加する際には、ファイル名を指定する第三引数には実際のファイルの拡張子を含める必要があります。これがないと、添付ファイルが開けるものとして認識されない可能性があります。例えば、ファイル名が単に「attachment」とだけ指定されている場合、生成されたPDFを見て添付ファイルを開こうとするとエラーが発生するかもしれません。しかし、「attachment.pdf」と指定されている場合、PDFビューアーで有効なファイルタイプとして認識され、開くことができます。\"\n\n#: ../../the-basics.rst:381 2eb971ca49044acfb758808877174159\nmsgid \"\"\n\"The default icon for the attachment is by default a \\\"push pin\\\", however\"\n\" you can change this by setting the `icon` parameter.\"\nmsgstr \"添付ファイルのデフォルトアイコンは「押しピン」ですが、 `icon` パラメータを設定することでこれを変更することができます。\"\n\n#: ../../the-basics.rst:385 472cb94f410f45d389386b479f752c7d\nmsgid \":ref:`Point<Point>`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:386 ../../the-basics.rst:422\n#: bc83ca635d004bbea323fc12889c3475 e3b71ff6dabe4e7092a149500b391650\nmsgid \":meth:`Document.tobytes`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:387 861dcb9381e943f982a5ff2233584d56\nmsgid \":meth:`Page.add_file_annot`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:396 36ca0a3374d84c2d914b97f4600f49bc\nmsgid \":index:`Embedding Files <triple: attach;embed;file>`\"\nmsgstr \":index:`ファイルを埋め込む <triple: attach;embed;file>`\"\n\n#: ../../the-basics.rst:398 3d3da8f629564876915a4356adb5a4c5\nmsgid \"To embed a file to a document, do the following:\"\nmsgstr \"ファイルを文書に埋め込むには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:418 522ee31eaa5c4be29e943f9e031733ce\nmsgid \"\"\n\"As with :ref:`attaching files<The_Basics_Attaching_Files>`, when adding \"\n\"the file with :meth:`Document.embfile_add` note that the first parameter \"\n\"for the `filename` should include the actual file extension.\"\nmsgstr \"\"\n\"ファイルを添付する場合と同様に、 :meth:`Document.embfile_add` \"\n\"でファイルを追加する際には、ファイル名を指定する第一引数には実際のファイルの拡張子を含める必要があります\"\n\n#: ../../the-basics.rst:423 d105ed0d5499461a9a468719a7df3543\nmsgid \":meth:`Document.embfile_add`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:433 2182d5b6f29e40d39aab4f677fedfa2b\nmsgid \"Deleting Pages\"\nmsgstr \"ページを削除する\"\n\n#: ../../the-basics.rst:435 634d1c5913ad422281859654914d1268\nmsgid \"To delete a page from a document, do the following:\"\nmsgstr \"文書からページを削除するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:445 437764ad7c2747118b3feb3fa4f1367b\nmsgid \"To delete a multiple pages from a document, do the following:\"\nmsgstr \"複数のページを文書から削除するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:459 7ffda49506894b2ca02ad9e6bc7e975a\nmsgid \"What happens if I delete a page referred to by bookmarks or hyperlinks?\"\nmsgstr \"ブックマークやハイパーリンクで参照されているページを削除した場合、どうなりますか？\"\n\n#: ../../the-basics.rst:461 9ccef7fc01e34b1f890333f741269c36\nmsgid \"\"\n\"A bookmark (entry in the Table of Contents) will become inactive and will\"\n\" no longer navigate to any page.\"\nmsgstr \"ブックマーク（目次のエントリー）は無効になり、もはやどのページにもナビゲートしません\"\n\n#: ../../the-basics.rst:463 2db9a64894ac4cc5926029b386cc8dbc\nmsgid \"\"\n\"A hyperlink will be removed from the page that contains it. The visible \"\n\"content on that page will not otherwise be changed in any way.\"\nmsgstr \"ハイパーリンクは、それを含むページから削除されます。そのページの可視コンテンツは、他の方法で変更されることはありません。\"\n\n#: ../../the-basics.rst:469 a64aa50abd5848b8a15b0f27de5f2595\nmsgid \"\"\n\"The page index is zero-based, so to delete page 10 of a document you \"\n\"would do the following `doc.delete_page(9)`.\"\nmsgstr \"ページのインデックスは0から始まるため、文書の10ページ目を削除するには、以下のようにします:  `doc.delete_page(9)`。\"\n\n#: ../../the-basics.rst:471 fb3cae6bf2b54a59b81ff59a5bb7563e\nmsgid \"\"\n\"Similarly, `doc.delete_pages(from_page=9, to_page=14)` will delete pages \"\n\"10 - 15 inclusive.\"\nmsgstr \"\"\n\"同様に、 `doc.delete_pages(from_page=9, to_page=14)` \"\n\"は、ページ10からページ15までを含む範囲のページを削除します。\"\n\n#: ../../the-basics.rst:476 ed756abf6b3e413c9ffbb5a6caf6b88b\nmsgid \":meth:`Document.delete_page`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:477 65198e829eef4bb381f47ddf30cc7e4f\nmsgid \":meth:`Document.delete_pages`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:485 7bbd41be5ecb4d2e9c76a3a244cca14d\nmsgid \"Re-Arranging Pages\"\nmsgstr \"ページを再配置する\"\n\n#: ../../the-basics.rst:487 a1f98aa6a7714dab99cef5e054cfb3bd\nmsgid \"To change the sequence of pages, i.e. re-arrange pages, do the following:\"\nmsgstr \"ページを再配置するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:502 f179f7f7f5794947ac4541278ba55b6e\nmsgid \":meth:`Document.move_page`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:511 d21575e2370d4ad4ab02f2ab07dd150c\nmsgid \"Copying Pages\"\nmsgstr \"ページをコピーする\"\n\n#: ../../the-basics.rst:514 57a67ecb95784254803c922f7d08f6c6\nmsgid \"To copy pages, do the following:\"\nmsgstr \"ページをコピーするには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:529 5a496f287a5b41fbb7d2b54cb5c697c8\nmsgid \":meth:`Document.copy_page`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:537 892cc58284e0408d8b96e992e24544cb\nmsgid \"Selecting Pages\"\nmsgstr \"ページを選択する\"\n\n#: ../../the-basics.rst:540 3db8f868455c4422a22a8739d7651725\nmsgid \"To select pages, do the following:\"\nmsgstr \"ページを選択するには、以下の手順を実行してください：\"\n\n#: ../../the-basics.rst:555 09491c46d0124346a4620dc928ac2a9e\nmsgid \"\"\n\"With |PyMuPDF| you have all options to copy, move, delete or re-arrange \"\n\"the pages of a |PDF|. Intuitive methods exist that allow you to do this \"\n\"on a page-by-page level, like the :meth:`Document.copy_page` method.\"\nmsgstr \"\"\n\"|PyMuPDF| を使用すると、 |PDF| のページをコピー、移動、削除、または再配置するためのオプションがすべて揃っています。 \"\n\":meth:`Document.copy_page` メソッドのように、ページ単位で直感的なメソッドを使用してこれらの操作を行うことができます。\"\n\n#: ../../the-basics.rst:557 f38fd21a8beb4136bb4eda2f7ed52873\nmsgid \"\"\n\"Or you alternatively prepare a complete new page layout in form of a \"\n\":title:`Python` sequence, that contains the page numbers you want, in the\"\n\" sequence you want, and as many times as you want each page. The \"\n\"following may illustrate what can be done with :meth:`Document.select`\"\nmsgstr \"\"\n\"または、 :title:`Python` \"\n\"のシーケンスとして完全な新しいページレイアウトを準備し、希望するページ番号を希望する順序で含め、必要なページ数だけ繰り返すこともできます。次の例は、\"\n\" :meth:`Document.select` を使用した可能性を示しています。\"\n\n#: ../../the-basics.rst:564 88e421ecb4fc4d56adaf214dccae4daa\nmsgid \"\"\n\"Now let's prepare a PDF for double-sided printing (on a printer not \"\n\"directly supporting this):\"\nmsgstr \"以下のように、両面印刷用にPDFを準備しましょう（直接これをサポートしていないプリンターで）：\"\n\n#: ../../the-basics.rst:566 74d3cda3847c46b7af864e6bc7c19cf8\nmsgid \"\"\n\"The number of pages is given by `len(doc)` (equal to `doc.page_count`). \"\n\"The following lists represent the even and the odd page numbers, \"\n\"respectively:\"\nmsgstr \"\"\n\"ページ数は `len(doc)`（ `doc.page_count` \"\n\"と同じ）で与えられます。以下のリストは、それぞれ偶数ページと奇数ページの番号を表しています：\"\n\n#: ../../the-basics.rst:573 2e020acac7f14b078d00def4cebc4fec\nmsgid \"\"\n\"This snippet creates the respective sub documents which can then be used \"\n\"to print the document:\"\nmsgstr \"このスニペットは、それぞれのサブドキュメントを作成し、それらを使用してドキュメントを印刷することができます：\"\n\n#: ../../the-basics.rst:585 a77fc70595bb4766ad8a0d5ffca2b8cf\nmsgid \"\"\n\"For more information also have a look at this Wiki `article \"\n\"<https://github.com/pymupdf/PyMuPDF/wiki/Rearranging-Pages-of-a-PDF>`_.\"\nmsgstr \"\"\n\"詳細については、この `ウィキの記事 <https://github.com/pymupdf/PyMuPDF/wiki/Rearranging-\"\n\"Pages-of-a-PDF>`_ もご覧ください。\"\n\n#: ../../the-basics.rst:588 6c87cc6c645e4408a02889aca746f748\nmsgid \"\"\n\"The following example will reverse the order of all pages (**extremely \"\n\"fast:** sub-second time for the 756 pages of the :ref:`AdobeManual`):\"\nmsgstr \"\"\n\"次の例は、すべてのページの順序を逆にするものです（非常に高速:  :ref:`AdobeManual` \"\n\"リファレンスの756ページをサブセカンドの時間で処理します）。\"\n\n#: ../../the-basics.rst:598 b9eda6c35a9b4b569375594839df0a97\nmsgid \"\"\n\"This snippet duplicates the PDF with itself so that it will contain the \"\n\"pages *0, 1, ..., n, 0, 1, ..., n* **(extremely fast and without \"\n\"noticeably increasing the file size!)**:\"\nmsgstr \"このスニペットは、PDFを自身と重複させることで、ページ0、1、…、n、0、1、…、nを含むようにします（非常に高速で、ファイルサイズをほとんど増やさずに実現します！）：\"\n\n#: ../../the-basics.rst:610 db170cb4731c4d9fb983242366f6e186\nmsgid \":meth:`Document.select`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:621 11bf1fc8a6144c888028b25e240c5514\nmsgid \"Adding Blank Pages\"\nmsgstr \"空白のページを追加する\"\n\n#: ../../the-basics.rst:623 e6ba26e2fe264930b67c0e9ff511017c\nmsgid \"To add a blank page, do the following:\"\nmsgstr \"空白のページを追加するには、以下の手順を行います：\"\n\n#: ../../the-basics.rst:640 c73c566766104c198225c46f3fa4b332\nmsgid \"Use this to create the page with another pre-defined paper format:\"\nmsgstr \"以下の方法を使用して、別の事前定義された用紙フォーマットを使ってページを作成します：\"\n\n#: ../../the-basics.rst:648 fa99380598a74f60a839a06cb2b9f706\nmsgid \"\"\n\"The convenience function :meth:`paper_size` knows over 40 industry \"\n\"standard paper formats to choose from. To see them, inspect dictionary \"\n\":attr:`paperSizes`. Pass the desired dictionary key to :meth:`paper_size`\"\n\" to retrieve the paper dimensions. Upper and lower case is supported. If \"\n\"you append \\\"-L\\\" to the format name, the landscape version is returned.\"\nmsgstr \"\"\n\"便利な関数 :meth:`paper_size` は、40以上の業界標準の用紙フォーマットを選択できます。それらを確認するには、辞書 \"\n\"attr:`paperSizes`  を調べてください。用紙の寸法を取得するために、希望する辞書キーを :meth:`paper_size` \"\n\"に渡します。大文字と小文字の両方がサポートされています。フォーマット名に「-L」を追加すると、横長バージョンが返されます。\"\n\n#: ../../the-basics.rst:650 7bb204302fe64b9c8102ce9b60e306f1\nmsgid \"\"\n\"Here is a 3-liner that creates a |PDF|: with one empty page. Its file \"\n\"size is 460 bytes:\"\nmsgstr \"以下は、1ページの空白の |PDF|: を作成するための3行のコードです。ファイルサイズは460バイトです。\"\n\n#: ../../the-basics.rst:661 16708fa927574853b07cfbe391fa574a\nmsgid \":meth:`Document.new_page`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:662 555dd6a7a4ca428ca05ffe585eb7dd98\nmsgid \":attr:`paperSizes`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:671 0c9d0f6b0af141bc92c8094e7d5d0fee\nmsgid \"Inserting Pages with Text Content\"\nmsgstr \"ページにテキストコンテンツを挿入する\"\n\n#: ../../the-basics.rst:673 8801a769c6764d358d2334b4dd80e5d6\nmsgid \"\"\n\"Using the :meth:`Document.insert_page` method also inserts a new page and\"\n\" accepts the same `width` and `height` parameters. But it lets you also \"\n\"insert arbitrary text into the new page and returns the number of \"\n\"inserted lines.\"\nmsgstr \"\"\n\":meth:`Document.insert_page` \"\n\"メソッドを使用すると、新しいページが挿入され、同じ幅と高さのパラメーターが受け入れられます。しかし、このメソッドでは新しいページに任意のテキストを挿入することができ、挿入された行数が返されます。\"\n\n#: ../../the-basics.rst:696 1f709a1e688c4c64ad9835a43df6b7e5\nmsgid \"\"\n\"The text parameter can be a (sequence of) string (assuming UTF-8 \"\n\"encoding). Insertion will start at :ref:`Point` (50, 72), which is one \"\n\"inch below top of page and 50 points from the left. The number of \"\n\"inserted text lines is returned.\"\nmsgstr \"\"\n\"テキストパラメーターは、UTF-8エンコーディングを想定している（シーケンスの）文字列です。挿入はページの上端から1インチ下であるポイント \"\n\":ref:`Point` (50, 72) から始まり、左から50ポイントの位置です。挿入されたテキストの行数が返されます。\"\n\n#: ../../the-basics.rst:700 5503e405b8a74c46ac510d142a942f92\nmsgid \":meth:`Document.insert_page`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:711 28cd42d51f99409a89dd644e5a331e95\nmsgid \"Splitting Single Pages\"\nmsgstr \"単一のページを分割する\"\n\n#: ../../the-basics.rst:713 7caccc9bbcaa4fa2941b493e69be1447\nmsgid \"\"\n\"This deals with splitting up pages of a |PDF| in arbitrary pieces. For \"\n\"example, you may have a |PDF| with *Letter* format pages which you want \"\n\"to print with a magnification factor of four: each page is split up in 4 \"\n\"pieces which each going to a separate |PDF| page in *Letter* format \"\n\"again.\"\nmsgstr \"\"\n\"この方法は、 |PDF| のページを任意の部分に分割することに関連しています。例えば、Letterフォーマットのページを含む |PDF| \"\n\"を、4倍の拡大率で印刷したい場合を考えてみましょう。各ページは4つの部分に分割され、それぞれが再びLetterフォーマットの個別の |PDF| \"\n\"ページになります。\"\n\n#: ../../the-basics.rst:756 ../../the-basics.rst:814\n#: 3ad50277922f4b4c9ce6e2eb2d3b4350 650a82fa6a3444c7b4f1119637692c77\nmsgid \"Example:\"\nmsgstr \"例:\"\n\n#: ../../the-basics.rst:764 ../../the-basics.rst:823\n#: 7f62edf5aa794474925340a623c05d4b a9ff4ea823fa4eaf80c415c485663e6b\nmsgid \":meth:`Page.cropbox_position`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:765 ../../the-basics.rst:824\n#: 86564b77e5c3440dba3f909f25fed95e ffceed2bb2ac4e738336a3eb438cb502\nmsgid \":meth:`Page.show_pdf_page`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:775 02e8677a9ee44d47acfb3845cbeb17f3\nmsgid \"Combining Single Pages\"\nmsgstr \"単一のページを結合する\"\n\n#: ../../the-basics.rst:777 2f61c36415a847069ab18578a22a28b3\nmsgid \"\"\n\"This deals with joining |PDF| pages to form a new |PDF| with pages each \"\n\"combining two or four original ones (also called \\\"2-up\\\", \\\"4-up\\\", \"\n\"etc.). This could be used to create booklets or thumbnail-like overviews.\"\nmsgstr \"\"\n\"これは、2つまたは4つの元のページを組み合わせた新しい |PDF| \"\n\"を作成することを意味します（または「2-up」、「4-up」などとも呼ばれます）。これは、ブックレットやサムネイルのような概要を作成するために使用できます。\"\n\n#: ../../the-basics.rst:833 8a7f8d78c24e4f378fee6b2230783c26\nmsgid \"|PDF| Encryption & Decryption\"\nmsgstr \"|PDF| の暗号化と復号化\"\n\n#: ../../the-basics.rst:836 71dc729191e040fd8118fee77ba6a2a8\nmsgid \"\"\n\"Starting with version 1.16.0, |PDF| decryption and encryption (using \"\n\"passwords) are fully supported. You can do the following:\"\nmsgstr \"バージョン1.16.0から、PDFの暗号化と復号化（パスワードを使用）が完全にサポートされています。以下のことができます：\"\n\n#: ../../the-basics.rst:838 dd359c928f974ab5947e47392afdc2a9\nmsgid \"\"\n\"Check whether a document is password protected / (still) encrypted \"\n\"(:attr:`Document.needs_pass`, :attr:`Document.is_encrypted`).\"\nmsgstr \"\"\n\"ドキュメントがパスワード保護されているか、（まだ）暗号化されているかを確認する（:attr:`Document.needs_pass`, \"\n\":attr:`Document.is_encrypted`）。\"\n\n#: ../../the-basics.rst:839 f16ee2a615fe4984bb226ff54db0fe8f\nmsgid \"Gain access authorization to a document (:meth:`Document.authenticate`).\"\nmsgstr \"ドキュメントへのアクセス権を取得する（:meth:`Document.authenticate`）。\"\n\n#: ../../the-basics.rst:840 6a05b415f16d40768f4e1564236d6231\nmsgid \"\"\n\"Set encryption details for PDF files using :meth:`Document.save` or \"\n\":meth:`Document.write` and\"\nmsgstr \":meth:`Document.save` または :meth:`Document.write` を使用して、PDFファイルの暗号化詳細を設定する。\"\n\n#: ../../the-basics.rst:842 a28670df924945ff88d6be01321e1a30\nmsgid \"decrypt or encrypt the content\"\nmsgstr \"内容の復号化または暗号化\"\n\n#: ../../the-basics.rst:843 d73094fe4cc9466a9bf3378d56401b78\nmsgid \"set password(s)\"\nmsgstr \"パスワードの設定\"\n\n#: ../../the-basics.rst:844 5aed08cd9fcc43ab8d5b06fb650a0ca6\nmsgid \"set the encryption method\"\nmsgstr \"暗号化方式の設定\"\n\n#: ../../the-basics.rst:845 76a02a01b3e04059b3deb41a2a8ffb73\nmsgid \"set permission details\"\nmsgstr \"権限の詳細設定\"\n\n#: ../../the-basics.rst:847 7fca3b11f52b4b0ca3876005bd500c57\nmsgid \"A PDF document may have two different passwords:\"\nmsgstr \"PDF文書には2つの異なるパスワードが存在する場合があります：\"\n\n#: ../../the-basics.rst:849 73c3a5f74efb4167905a89f8f1383c0a\nmsgid \"\"\n\"The **owner password** provides full access rights, including changing \"\n\"passwords, encryption method, or permission detail.\"\nmsgstr \"オーナーパスワード：パスワードを変更したり、暗号化方法を変更したり、権限の詳細を含む完全なアクセス権を提供します。\"\n\n#: ../../the-basics.rst:850 e2fb43f6fcdb49739207db257e3f97bb\nmsgid \"\"\n\"The **user password** provides access to document content according to \"\n\"the established permission details. If present, opening the |PDF| in a \"\n\"viewer will require providing it.\"\nmsgstr \"ユーザーパスワード：文書の内容にアクセスするための権限詳細に基づいてアクセスを提供します。存在する場合、ビューアでPDFを開く際にユーザーパスワードを入力する必要があります。\"\n\n#: ../../the-basics.rst:852 c66bf0cbf4934d79a253d8f6b43d51f4\nmsgid \"\"\n\"Method :meth:`Document.authenticate` will automatically establish access \"\n\"rights according to the password used.\"\nmsgstr \"メソッド :meth:`Document.authenticate` は、使用されるパスワードに基づいて自動的にアクセス権を確立します。\"\n\n#: ../../the-basics.rst:854 8d09fb5167d443ef9ee672510c3def18\nmsgid \"\"\n\"The following snippet creates a new |PDF| and encrypts it with separate \"\n\"user and owner passwords. Permissions are granted to print, copy and \"\n\"annotate, but no changes are allowed to someone authenticating with the \"\n\"user password.\"\nmsgstr \"\"\n\"以下のスニペットは新しい |PDF| \"\n\"を作成し、別々のユーザーパスワードとオーナーパスワードで暗号化します。印刷、コピー、注釈付けの権限が与えられますが、ユーザーパスワードで認証するユーザーに対しては変更は許可されません\"\n\n#: ../../the-basics.rst:888 10c5018907dd4496be681ebd8e664fd6\nmsgid \"\"\n\"Opening this document with some viewer (Nitro Reader 5) reflects these \"\n\"settings:\"\nmsgstr \"このドキュメントをいくつかのビューア（Nitro Reader 5など）で開くと、これらの設定が反映されます：\"\n\n#: ../../the-basics.rst:892 03d88819ea404f0aaf81ffe5d60d7425\nmsgid \"\"\n\"**Decrypting** will automatically happen on save as before when no \"\n\"encryption parameters are provided.\"\nmsgstr \"暗号化パラメータが提供されていない場合、保存時に自動的に復号化されます。\"\n\n#: ../../the-basics.rst:894 f367fcac22c6414ab97981825f130856\nmsgid \"\"\n\"To **keep the encryption method** of a PDF save it using \"\n\"`encryption=pymupdf.PDF_ENCRYPT_KEEP`. If `doc.can_save_incrementally() \"\n\"== True`, an incremental save is also possible.\"\nmsgstr \"\"\n\"PDFの暗号化方法を保持するには、`encryption=pymupdf.PDF_ENCRYPT_KEEP` を使用して保存します。また、 \"\n\"`doc.can_save_incrementally() == True` であれば、増分保存も可能です\"\n\n#: ../../the-basics.rst:896 beec27387fd7422bb3e063049ff22429\nmsgid \"\"\n\"To **change the encryption method** specify the full range of options \"\n\"above (`encryption`, `owner_pw`, `user_pw`, `permissions`). An \"\n\"incremental save is **not possible** in this case.\"\nmsgstr \"暗号化方法を変更する場合は、上記のすべてのオプション（`encryption`、`owner_pw`、`user_pw`、`permissions`）を指定します。この場合、増分保存はできません。\"\n\n#: ../../the-basics.rst:900 20699b9f6451443d8b941958c154d7a7\nmsgid \":meth:`Document.save`\"\nmsgstr \"\"\n\n#: ../../the-basics.rst:909 d798da65fa514bd0aebc4068c084a7ca\nmsgid \"Extracting Tables from a :title:`Page`\"\nmsgstr \"ページからのテーブルの抽出\"\n\n#: ../../the-basics.rst:911 e4ef14dd9323461295fcdab920a24b7e\nmsgid \"Tables can be found and extracted from any document :ref:`Page`.\"\nmsgstr \"表はどのドキュメントの :ref:`Page` からも見つけて抽出できます。\"\n\n#: ../../the-basics.rst:930 fc83ee37b6f443bc9104c718aa70c0ec\n#, fuzzy\nmsgid \":meth:`Page.find_tables`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:935 ae116fead03d40f4ae9e9e1fa4dd5657\nmsgid \"\"\n\"There is also the `pdf2docx extract tables method`_ which is capable of \"\n\"table extraction if you prefer.\"\nmsgstr \"お好みの場合、テーブル抽出が `可能なpdf2docxのextract tablesメソッド`_ もあります。\"\n\n#: ../../the-basics.rst:944 09cbe8ebd73f4fdbae255f4eb4ac88d9\nmsgid \"Getting Page Links\"\nmsgstr \"ページリンクの取得\"\n\n#: ../../the-basics.rst:946 8f8e76066ac34e6288f125de53c52324\nmsgid \"Links can be extracted from a :ref:`Page` to return :ref:`Link` objects.\"\nmsgstr \":ref:`Page` からリンクを抽出して :ref:`Link` オブジェクトを返すことができます。\"\n\n#: ../../the-basics.rst:966 4b1b5f7afbde4704808ac3807d07675a\n#, fuzzy\nmsgid \":meth:`Page.first_link`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:975 b3aade8e69434effb9c03ef1b44c1f10\nmsgid \"Getting All Annotations from a Document\"\nmsgstr \"ドキュメントからすべての注釈を取得する\"\n\n#: ../../the-basics.rst:977 6801cadfb5354b0ab04f7979d5a356ba\nmsgid \"\"\n\"Annotations (:ref:`Annot`) on pages can be retrieved with the \"\n\"`page.annots()` method.\"\nmsgstr \"ページ上の注釈 (:ref:`Annot`) は、`page.annots()` メソッドを使用して取得できます。\"\n\n#: ../../the-basics.rst:992 bf4d519f3c994f33b280f0de93018463\n#, fuzzy\nmsgid \":meth:`Page.annots`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:1002 c5273dfabc3043a8b9607b2a9d28ce43\nmsgid \"Redacting content from a |PDF|\"\nmsgstr \"|PDF| からコンテンツを塗りつぶす\"\n\n#: ../../the-basics.rst:1004 e030189f77db4e8983c5a6528654fd34\nmsgid \"\"\n\"Redactions are special types of annotations which can be marked onto a \"\n\"document page to denote an area on the page which should be securely \"\n\"removed. After marking an area with a rectangle then this area will be \"\n\"marked for *redaction*, once the redaction is *applied* then the content \"\n\"is securely removed.\"\nmsgstr \"マーキングされた領域に矩形を使用して、ページ上の削除されるべき領域を示すために、赤字が付けられる特別なアノテーションです。領域に矩形をマークした後、その領域は赤字としてマークされ、赤字が適用されると、そのコンテンツは安全に削除されます。\"\n\n#: ../../the-basics.rst:1006 576dffbcb6454f419fb44e03a6766f97\nmsgid \"\"\n\"For example if we wanted to redact all instances of the name \\\"Jane Doe\\\"\"\n\" from a document we could do the following:\"\nmsgstr \"たとえば、ドキュメントから名前「ジェーン・ドー」のすべてのインスタンスを塗りつぶしたい場合は、次のようにします：\"\n\n#: ../../the-basics.rst:1034 512a331e2f6a4420af87d029a290261c\nmsgid \"\"\n\"Another example could be redacting an area of a page, but not to redact \"\n\"any line art (i.e. vector graphics) within the defined area, by setting a\"\n\" parameter flag as follows:\"\nmsgstr \"別の例として、ページの領域を塗りつぶすが、定義された領域内の線画（ベクトルグラフィックス）を塗りつぶさないように、パラメータフラグを設定することができます。\"\n\n#: ../../the-basics.rst:1065 eed2e214f7454d77b9f11502e75e71b6\nmsgid \"\"\n\"Once a redacted version of a document is saved then the redacted content \"\n\"in the |PDF| is *irretrievable*. Thus, a redacted area in a document \"\n\"removes text and graphics completely from that area.\"\nmsgstr \"\"\n\"文書の塗りつぶし済みバージョンを保存すると、|PDF| 内の塗りつぶされたコンテンツは *取り戻すことができなくなります* \"\n\"。したがって、文書内の塗りつぶされた領域は、その領域からテキストとグラフィックスを完全に削除します。\"\n\n#: ../../the-basics.rst:1072 24199c7a643e40f981bc9a2d6b9a76f5\nmsgid \"\"\n\"The are a few options for creating and applying redactions to a page, for\"\n\" the full API details to understand the parameters to control these \"\n\"options refer to the API reference.\"\nmsgstr \"ページに赤字を作成して適用するためのいくつかのオプションがあります。これらのオプションを制御するためのパラメータを理解するためには、完全なAPI詳細についてAPIリファレンスを参照してください。\"\n\n#: ../../the-basics.rst:1076 5620f79d90484e0c84d9f1e6cf483ef2\n#, fuzzy\nmsgid \":meth:`Page.add_redact_annot`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:1078 2238e86dba64405e99bc6de9a1e29266\n#, fuzzy\nmsgid \":meth:`Page.apply_redactions`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:1088 64e88b96ce2b4df99e9d8c97cae10c8f\nmsgid \"Converting PDF Documents\"\nmsgstr \"PDF ドキュメントの変換\"\n\n#: ../../the-basics.rst:1090 c9b689d1ca1242deaf0ecf74d670aa7b\nmsgid \"\"\n\"We recommend the pdf2docx_ library which uses |PyMuPDF| and the **python-\"\n\"docx** library to provide simple document conversion from |PDF| to \"\n\"**DOCX** format.\"\nmsgstr \"\"\n\"PyMuPDF を使用する pdf2docx_ ライブラリと、|PDF| から **DOCX** 形式への簡単なドキュメント変換を提供する \"\n\"**python-docx** ライブラリをお勧めします。\"\n\n#: ../../footer.rst:60 3aa3d5fcda7349e5a5c5339a71002610\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"Supported File Types\"\n#~ msgstr \"サポートされているファイルタイプ\"\n\n#~ msgid \"|PyMuPDF| supports the following file types:\"\n#~ msgstr \"|PyMuPDF| は以下のファイルタイプをサポートしています：\"\n\n#~ msgid \"\"\n#~ \"Opening with :index:`a Wrong File \"\n#~ \"Extension <pair: wrong; file extension>`\"\n#~ msgstr \"間違ったファイル拡張子でファイルを開く\"\n\n#~ msgid \"\"\n#~ \"If you have a document with a \"\n#~ \"wrong file extension for its type, \"\n#~ \"you can still correctly open it.\"\n#~ msgstr \"もしドキュメントのファイル拡張子がその種類に対して間違っていても、正しく開くことができます。\"\n\n#~ msgid \"Assume that *\\\"some.file\\\"* is actually an XPS. Open it like so:\"\n#~ msgstr \"*\\\"some.file\\\"* が実際にXPSファイルだと仮定して、以下のようにして開いてください：\"\n\n#~ msgid \"\"\n#~ \"There are many file types beyond \"\n#~ \"|PDF| which can be opened by \"\n#~ \"|PyMuPDF|, for more details see the \"\n#~ \"list of :ref:`supported file \"\n#~ \"types<Supported_File_Types>`.\"\n#~ msgstr \"\"\n#~ \"「PyMuPDF」で開くことができるのは、|PDF| \"\n#~ \"に限らず、多くのファイルタイプがあります。詳細については、:ref:`サポートされているファイルタイプのリスト<Supported_File_Types>`\"\n#~ \" をご覧ください。\"\n\n#~ msgid \"\"\n#~ \"|PyMuPDF| itself does not try to \"\n#~ \"determine the file type from the \"\n#~ \"file contents. **You** are responsible \"\n#~ \"for supplying the filetype info in \"\n#~ \"some way -- either implicitly via \"\n#~ \"the file extension, or explicitly as \"\n#~ \"shown. There are pure :title:`Python` \"\n#~ \"packages like `filetype \"\n#~ \"<https://pypi.org/project/filetype/>`_ that help you\"\n#~ \" doing this. Also consult the \"\n#~ \":ref:`Document` chapter for a full \"\n#~ \"description.\"\n#~ msgstr \"\"\n#~ \"PyMuPDF自体は、ファイルの内容からファイルタイプを判断しようとはしません。ファイルの拡張子などを通じて暗黙的に、または明示的にファイルタイプ情報を提供する責任があります。`filetype\"\n#~ \" <https://pypi.org/project/filetype/>`_ \"\n#~ \"などの純粋なPythonパッケージがこのような操作をサポートしています。また、詳細な説明についてはドキュメントの章を参照してください。\"\n\n#~ msgid \"\"\n#~ \"If |PyMuPDF| encounters a file with \"\n#~ \"an unknown / missing extension, it \"\n#~ \"will try to open it as a \"\n#~ \"|PDF|. So in these cases there is\"\n#~ \" no need for additional precautions. \"\n#~ \"Similarly, for memory documents, you can\"\n#~ \" just specify `doc=pymupdf.open(stream=mem_area)` \"\n#~ \"to open it as a |PDF| document.\"\n#~ msgstr \"\"\n#~ \"|PyMuPDF| \"\n#~ \"が不明な/欠落している拡張子のファイルに遭遇した場合、それをPDFとして開こうと試みます。したがって、これらの場合は追加の注意が必要ありません。同様に、メモリ上のドキュメントの場合は、`doc=pymupdf.open(stream=mem_area)`\"\n#~ \" と指定するだけでPDFドキュメントとして開くことができます\"\n\n#~ msgid \"\"\n#~ \"If you attempt to open an \"\n#~ \"unsupported file then |PyMuPDF| will \"\n#~ \"throw a file data error.\"\n#~ msgstr \"サポートされていないファイルを開こうとした場合、PyMuPDFはファイルデータエラーをスローします。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/tools.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 fa4cb1c40839408c9c8cd07e9e01bb93\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 0eadbcdf62a345f492e6c5df071271b8\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 ac94c9f7137942e6a95a87c8a8567dd6\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../tools.rst:6 630133a66584427d8841e6ac73cd74b2\nmsgid \"Tools\"\nmsgstr \"Tools (ツール)\"\n\n#: ../../tools.rst:8 9874cd63550144bdb2077af42f68c67f\nmsgid \"\"\n\"This class is a collection of utility methods and attributes, mainly \"\n\"around memory management. To simplify and speed up its use, it is \"\n\"automatically instantiated under the name *TOOLS* when PyMuPDF is \"\n\"imported.\"\nmsgstr \"\"\n\"このクラスは、メモリ管理を中心としたユーティリティメソッドと属性のコレクションです。使用を簡素化し、高速化するために、PyMuPDFがインポートされると、自動的に\"\n\" *TOOLS* という名前でインスタンス化されます。\"\n\n#: ../../tools.rst:11 99d510145a8d481b814d6864371fd664\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド/属性**\"\n\n#: ../../tools.rst:11 5a58a92212e44a278c9d89c56b3e1210\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../tools.rst:13 2b964d526bc34dbca89696e9a7f8a649\nmsgid \":meth:`Tools.gen_id`\"\nmsgstr \"\"\n\n#: ../../tools.rst:13 2e23b218a694403f803ca3d4641d1e46\nmsgid \"generate a unique identifier\"\nmsgstr \"一意の識別子を生成します。\"\n\n#: ../../tools.rst:14 24f42327e36744579573d798b230bef0\nmsgid \":meth:`Tools.store_shrink`\"\nmsgstr \"\"\n\n#: ../../tools.rst:14 b4c3bfa744874fc3a556cbd6b8e9b6b8\nmsgid \"shrink the storables cache [#f1]_\"\nmsgstr \"格納可能キャッシュを縮小します [#f1]_。\"\n\n#: ../../tools.rst:15 bad8f3d46e5b4afdb102c4e7bf50d072\nmsgid \":meth:`Tools.mupdf_warnings`\"\nmsgstr \"\"\n\n#: ../../tools.rst:15 a2b9a9e372e04cecb473e320064f1301\nmsgid \"return the accumulated MuPDF warnings\"\nmsgstr \"蓄積されたMuPDFの警告を返します。\"\n\n#: ../../tools.rst:16 965bf5733d4a437c9bf6499bb67ce938\nmsgid \":meth:`Tools.mupdf_display_errors`\"\nmsgstr \"\"\n\n#: ../../tools.rst:16 95fb9fea93424795be84f9bccfc5a2c6\nmsgid \"control whether MuPDF errors are displayed as messages.\"\nmsgstr \"\"\n\n#: ../../tools.rst:17 aae25f7b27504eacb2dcb5df61f4be65\nmsgid \":meth:`Tools.mupdf_display_warnings`\"\nmsgstr \"\"\n\n#: ../../tools.rst:17 0ec8dcf6c973477abe4aa02ed3c8b605\nmsgid \"control whether MuPDF warnings are displayed as messages.\"\nmsgstr \"\"\n\n#: ../../tools.rst:18 53a94e9b9d1044b394e412402f3dcf71\nmsgid \":meth:`Tools.reset_mupdf_warnings`\"\nmsgstr \"\"\n\n#: ../../tools.rst:18 39ad9b132aad445c8698e388b85423ed\n#, fuzzy\nmsgid \"empty MuPDF warnings/errors message buffer.\"\nmsgstr \"MuPDFの警告メッセージバッファを空にします。\"\n\n#: ../../tools.rst:19 6719fb8425af4227a2a2717806cd2872\nmsgid \":meth:`Tools.set_aa_level`\"\nmsgstr \"\"\n\n#: ../../tools.rst:19 084c6bfe822c4d048572d1bb4db01b5d\nmsgid \"set the anti-aliasing values\"\nmsgstr \"アンチエイリアシングの値を設定します。\"\n\n#: ../../tools.rst:20 30023363ff6e4e8aa20333cd744dab27\nmsgid \":meth:`Tools.set_annot_stem`\"\nmsgstr \"\"\n\n#: ../../tools.rst:20 104ce28d382346ac85d8db2cfcb5da80\nmsgid \"set the prefix of new annotation / link ids\"\nmsgstr \"新しい注釈/リンクIDのプレフィックスを設定します。\"\n\n#: ../../tools.rst:21 de68f470119b4a60b48b7054e2f46a0c\nmsgid \":meth:`Tools.set_small_glyph_heights`\"\nmsgstr \"\"\n\n#: ../../tools.rst:21 f69f8f062c094ffcac57dd21b3725054\nmsgid \"search and extract using small bbox heights\"\nmsgstr \"小さなbbox高さを使用して検索および抽出します。\"\n\n#: ../../tools.rst:22 a5f65f4e49c744f2b64fd47f8f963187\nmsgid \":meth:`Tools.set_subset_fontnames`\"\nmsgstr \"\"\n\n#: ../../tools.rst:22 d7a4ef524baa414c934afd124e2039c8\nmsgid \"control suppression of subset fontname tags\"\nmsgstr \"サブセットフォント名タグの抑制を制御します。\"\n\n#: ../../tools.rst:23 f7f424f91b824b6fbc8d16f177210157\nmsgid \":meth:`Tools.show_aa_level`\"\nmsgstr \"\"\n\n#: ../../tools.rst:23 de220ac6db8f43b590219bfc76ada785\nmsgid \"return the anti-aliasing values\"\nmsgstr \"アンチエイリアシングの値を返します。\"\n\n#: ../../tools.rst:24 9822bd4c433c4e73a4a62e8e2fd8d55d\nmsgid \":meth:`Tools.unset_quad_corrections`\"\nmsgstr \"\"\n\n#: ../../tools.rst:24 1ebfd2086c444331b2bf1d386b71dc90\nmsgid \"disable PyMuPDF-specific code\"\nmsgstr \"PyMuPDF固有のコードを無効にします。\"\n\n#: ../../tools.rst:25 b93af0b1adae41ab8ef6adfe0264b3d7\nmsgid \":attr:`Tools.fitz_config`\"\nmsgstr \"\"\n\n#: ../../tools.rst:25 4aabf943204d404e9bcd0659b004b61a\nmsgid \"configuration settings of PyMuPDF\"\nmsgstr \"PyMuPDFの設定設定\"\n\n#: ../../tools.rst:26 bda50dea0b1b426db8d540c41f8e225d\nmsgid \":attr:`Tools.store_maxsize`\"\nmsgstr \"\"\n\n#: ../../tools.rst:26 d98d3a57e7f648caac4f8c85c2aa73dc\nmsgid \"maximum storables cache size\"\nmsgstr \"最大格納可能キャッシュサイズ\"\n\n#: ../../tools.rst:27 832df81af8a44bf994b2927588b125b4\nmsgid \":attr:`Tools.store_size`\"\nmsgstr \"\"\n\n#: ../../tools.rst:27 1e9ca667256f4ce88906ba326e637a59\nmsgid \"current storables cache size\"\nmsgstr \"現在の格納可能キャッシュサイズ\"\n\n#: ../../tools.rst:30 876332768bb84673a877ceb4dece1450\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../tools.rst:36 65fde22db17c4647b856922e599073a4\nmsgid \"\"\n\"A convenience method returning a unique positive integer which will \"\n\"increase by 1 on every invocation. Example usages include creating unique\"\n\" keys in databases - its creation should be faster than using timestamps \"\n\"by an order of magnitude.\"\nmsgstr \"1回の呼び出しごとに1ずつ増加する一意の正の整数を返す便利なメソッドです。使用例には、データベース内で一意のキーを作成することが含まれます。タイムスタンプを使用するよりも作成が10倍高速であるべきです。\"\n\n#: ../../tools.rst:38 ab15f82a042e4ed3b078c757f4e63b86\nmsgid \"\"\n\"MuPDF has dropped support for this in v1.14.0, so we have re-implemented \"\n\"a similar function with the following differences:\"\nmsgstr \"MuPDFはv1.14.0でこれをサポートを中止したため、次の違いを持つ類似の関数を再実装しました。\"\n\n#: ../../tools.rst:40 84cae01ccf524246ac7b4d9427698005\nmsgid \"\"\n\"It is not part of MuPDF's global context and not threadsafe (not an issue\"\n\" because we do not support threads in PyMuPDF anyway).\"\nmsgstr \"これはMuPDFのグローバルコンテキストの一部ではなく、スレッドセーフではありません（とにかくPyMuPDFではスレッドをサポートしていないため、これは問題ではありません）。\"\n\n#: ../../tools.rst:41 f05a3f0eec6c47eaab32b3d7dbadfa32\nmsgid \"\"\n\"It is implemented as *int*. This means that the maximum number is \"\n\"*sys.maxsize*. Should this number ever be exceeded, the counter starts \"\n\"over again at 1.\"\nmsgstr \"\"\n\"これはintとして実装されています。つまり、最大値は *sys.maxsize* \"\n\"です。この数値がいつか超過される場合、カウンターは1から再開します。\"\n\n#: ../../tools.rst 17bbc4e0e9b1480aab24e4c8d6b901fd\n#: 2c7d5afc0c614f2e947541283319a8aa 3f0e5e23a1b3401fab7534a9ffddfb6f\n#: 4bceb68ff0cf4c4db44a34b626d14422 4bfaf26ceea2422398c767ec7da4f944\n#: 656f7c4b2db04ef1928e253ee58fbda8 783c6110b0e84fa69ec1e999f0763115\n#: 886de849a3b644a3b7483f4f34d47ab1 9956690247394b5abfa7987d9cb2942f\n#: ae9fe9f8edaa4afa9830772bb949887b\nmsgid \"Return type\"\nmsgstr \"戻り値:\"\n\n#: ../../tools.rst 05be31d115d84df1af6eec3998b6c813\n#: 1b38a72665554ad2b7b31cd24642d09f 322b991feded4473a556bdb214b03b1d\n#: 47b093107003487e9ca47b7610cc6159 63fec7ceb4ea496eba269d589582ac36\n#: a18d16ae4a364a9d863acd8c74a5fa94 b4f07341f4ad48e897984538401987b3\n#: c6c09e9c896c4a13b41f9be7c7bd6ff6 db36bae168a54d46838b57f99adb8f1d\nmsgid \"Returns\"\nmsgstr \"返り値:\"\n\n#: ../../tools.rst:44 d04c5dc089994e268783aceaffad24d8\nmsgid \"a unique positive integer.\"\nmsgstr \"一意の正の整数。\"\n\n#: ../../tools.rst:49 5ebeca1825d746f39692eebb86cb9f42\nmsgid \"New in v1.18.6\"\nmsgstr \"v1.18.6で新登場\"\n\n#: ../../tools.rst:51 8b6fd71202b24c318c21b52e9aabae8c\nmsgid \"Set or inquire the prefix for the id of new annotations, fields or links.\"\nmsgstr \"新しい注釈、フィールド、またはリンクのIDのプレフィックスを設定または問い合わせます。\"\n\n#: ../../tools.rst 1ecb667b90fb4a4baa562619c4cf215f\n#: 658ec43b52b04330bf7a40f38e909bbc 95eef4039ef94ba79c670022599c654c\n#: b3ae48d8f1a449ddbe4b6a9ae98cf4d9 c299a5cad9db4f4c84dde48c1ef4fc58\n#: c4311092aae34e4691fb6e3995c50792 c79cc99a8ac340c2a6a9adc2b3fe239a\n#: ca6497050d944cf788e55eb72bc9f7d1 f54117de12074455b85ab6c94ff7dd5b\nmsgid \"Parameters\"\nmsgstr \"パラメータ\"\n\n#: ../../tools.rst:53 3501d21aa8734541bc1aa99a8ed5190c\nmsgid \"\"\n\"if omitted, the current value is returned, default is \\\"fitz\\\". \"\n\"Annotations, fields / widgets and links technically are subtypes of the \"\n\"same type of object (`/Annot`) in PDF documents. An `/Annot` object may \"\n\"be given a unique identifier within a page. For each of the applicable \"\n\"subtypes, PyMuPDF generates identifiers \\\"stem-Annn\\\", \\\"stem-Wnnn\\\" or \"\n\"\\\"stem-Lnnn\\\" respectively. The number \\\"nnn\\\" is used to enforce the \"\n\"required uniqueness.\"\nmsgstr \"\"\n\"省略された場合、現在の値が返され、デフォルトは  \\\"fitz\\\" \"\n\"です。注釈、フィールド/ウィジェット、およびリンクは技術的にはPDF文書内の同じ種類のオブジェクト（`/Annot`）のサブタイプです。`/Annot`\"\n\" オブジェクトは、ページ内で一意の識別子を持つことができます。適用可能なサブタイプごとに、PyMuPDFはそれぞれ \\\"stem-Annn\"\n\"\\\"、\\\"stem-Wnnn\\\"、または \\\"stem-Lnnn\\\" の識別子を生成します。番号 \\\"nnn\\\" \"\n\"は必要な一意性を強制するために使用されます。\"\n\n#: ../../tools.rst:56 b611d59a32fa4723ae6eea8e46c1e4fc\nmsgid \"the current value.\"\nmsgstr \"現在の値。\"\n\n#: ../../tools.rst:61 ed4a7b571b5840db82e999c073d641bb\nmsgid \"New in v1.18.5\"\nmsgstr \"v1.18.5で新登場\"\n\n#: ../../tools.rst:63 d110db042c104cd9a70ee2ba0ea17274\nmsgid \"\"\n\"Set or inquire reduced bbox heights in text extract and text search \"\n\"methods.\"\nmsgstr \"テキスト抽出およびテキスト検索メソッドでのbboxの高さを縮小するかどうかを設定または問い合わせます。\"\n\n#: ../../tools.rst:65 9dacdc2684a04823aaf2faa1c6a84582\nmsgid \"\"\n\"if omitted or `None`, the current setting is returned. For other values \"\n\"the *bool()* function is applied to set a global variable. If `True`, \"\n\":meth:`Page.search_for` and :meth:`Page.get_text` methods return \"\n\"character, span, line or block bboxes that have a height of *font size*. \"\n\"If `False` (standard setting when PyMuPDF is imported), bbox height will \"\n\"be based on font properties and normally equal *line height*.\"\nmsgstr \"\"\n\"省略された場合または `None` の場合、現在の設定が返されます。他の値の場合、*bool()* \"\n\"関数が適用され、グローバル変数を設定します。`True` の場合、:meth:`Page.search_for` および \"\n\":meth:`Page.get_text` メソッドは *フォントサイズ* \"\n\"の高さを持つ文字、スパン、行、またはブロックのbboxを返します。`False` \"\n\"の場合（PyMuPDFがインポートされたときの標準設定）、bboxの高さはフォントのプロパティに基づき、通常は *行の高さ* と同じです。\"\n\n#: ../../tools.rst:68 ../../tools.rst:81 ../../tools.rst:95\n#: 3d9f991f869c4e3687694b4b5d83e20f 8fa94c128ef84d4db600a970cc431f03\n#: fb141d29fa904b54ac786f25cee529a0\nmsgid \"``True`` or ``False``.\"\nmsgstr \"``True`` または ``False``。\"\n\n#: ../../tools.rst:70 6ff2af93fffb41d1952b1726635074e7\nmsgid \"\"\n\"Text extraction options \\\"xml\\\", \\\"xhtml\\\" and \\\"html\\\", which directly \"\n\"wrap MuPDF code, are not influenced by this.\"\nmsgstr \"直接MuPDFコードをラップするテキスト抽出オプション「xml」、「xhtml」、「html」は、これに影響を受けません。\"\n\n#: ../../tools.rst:74 3e2f146855c24da3bc5620a6dbf0fe16\nmsgid \"New in v1.18.9\"\nmsgstr \"バージョン1.18.9で追加されました\"\n\n#: ../../tools.rst:76 a47cf06efd8f42ed94738ff03d3423d2\nmsgid \"Control suppression of subset fontname tags in text extractions.\"\nmsgstr \"テキスト抽出におけるサブセットフォント名のタグを抑制する制御を行います。\"\n\n#: ../../tools.rst:78 c87edd954d4c42e6b4fdd9829d79cd37\nmsgid \"\"\n\"if omitted / `None`, the current setting is returned. Arguments \"\n\"evaluating to `True` or `False` set a global variable. If `True`, options\"\n\" \\\"dict\\\", \\\"json\\\", \\\"rawdict\\\" and \\\"rawjson\\\" will return e.g. \"\n\"`\\\"NOHSJV+Calibri-Light\\\"`, otherwise only `\\\"Calibri-Light\\\"` (the \"\n\"default). The setting remains in effect until changed again.\"\nmsgstr \"\"\n\"省略された場合 `None`、現在の設定が返されます。`True` または `False` \"\n\"の値を評価して、グローバル変数を設定します。`True` の場合、オプション \"\n\"\\\"dict\\\"、\\\"json\\\"、\\\"rawdict\\\"、\\\"rawjson\\\" は例えば `\\\"NOHSJV+Calibri-Light\\\"`\"\n\" のように返され、それ以外の場合はデフォルトの `\\\"Calibri-Light\\\"` のみが返されます。設定は再度変更されるまで有効です。\"\n\n#: ../../tools.rst:83 82a85fb54bd7436c925ba3b349ae06ef\nmsgid \"\"\n\"Except mentioned above, no other text extraction variants are influenced \"\n\"by this. This is especially true for the options \\\"xml\\\", \\\"xhtml\\\" and \"\n\"\\\"html\\\", which are based on MuPDF code. They extract the font name \"\n\"`\\\"Calibri-Light\\\"`, or even just the **family** name -- `Calibri` in \"\n\"this example.\"\nmsgstr \"\"\n\"上記に記載されている以外のテキスト抽出バリアントには影響しません。特に、MuPDFコードに基づくオプション \"\n\"\\\"xml\\\"、\\\"xhtml\\\"、\\\"html\\\" には影響しません。これらはフォント名 `\\\"Calibri-\"\n\"Light\\\"`、またはこの例の場合はファミリー名 `Calibri` のみを抽出します。\"\n\n#: ../../tools.rst:88 149b8e463c8f481c96e3b70333a749dc\nmsgid \"New in v1.18.10\"\nmsgstr \"バージョン1.18.10で追加されました\"\n\n#: ../../tools.rst:90 159ffb24af174c1f8c260dc38669bafc\nmsgid \"\"\n\"Enable / disable PyMuPDF-specific code, that tries to rebuild valid \"\n\"character quads when encountering nonsense in :meth:`Page.get_text` text \"\n\"extractions. This code depends on certain font properties (ascender and \"\n\"descender), which do not exist in rare situations and cause segmentation \"\n\"faults when trying to access them. This method sets a global parameter in\"\n\" PyMuPDF, which suppresses execution of this code.\"\nmsgstr \"\"\n\":meth:`Page.get_text` \"\n\"テキスト抽出で無意味なものを検出した際に、有効な文字の四角形を再構築しようとするPyMuPDF固有のコードの有効化/無効化を行います。このコードは、存在しない場合があるフォントの特性（ascenderおよびdescender）に依存しており、これらの特性にアクセスしようとするとセグメンテーション違反が発生します。このメソッドはPyMuPDF内のグローバルパラメータを設定し、このコードの実行を抑制します。\"\n\n#: ../../tools.rst:92 e6745e3e0ce7442b9f04193751691b0a\nmsgid \"\"\n\"if omitted or `None`, the current setting is returned. For other values \"\n\"the *bool()* function is applied to set a global variable. If `True`, \"\n\"PyMuPDF will not try to access the resp. font properties and use values \"\n\"`ascender=0.8` and `descender=-0.2` instead.\"\nmsgstr \"\"\n\"省略された場合、または `None` 、現在の設定が返されます。他の値の場合、*bool()* \"\n\"関数が適用され、グローバル変数を設定します。`True` の場合、PyMuPDFは該当するフォントの特性にアクセスしようとせず、代わりに \"\n\"`ascender=0.8` および `descender=-0.2` の値を使用します。\"\n\n#: ../../tools.rst:100 4c85e3216c354121a73b16cd1b293077\nmsgid \"Reduce the storables cache by a percentage of its current size.\"\nmsgstr \"現在のサイズを基準に、ストレージキャッシュのサイズを指定した割合で減少させます。\"\n\n#: ../../tools.rst:102 7618f829b73f402e918ae962dfb6a9f0\nmsgid \"\"\n\"the percentage of current size to free. If 100+ the store will be \"\n\"emptied, if zero, nothing will happen. MuPDF's caching strategy is \"\n\"\\\"least recently used\\\", so low-usage elements get deleted first.\"\nmsgstr \"現在のサイズの何パーセントを解放するかを指定します。100以上の場合、ストアは空になります。むしろ、何も変更されません。MuPDFのキャッシング戦略は「最後に使用されたもの」なので、使用頻度の低い要素が最初に削除されます。\"\n\n#: ../../tools.rst:105 b452872341864da4b7fbb34a1df97034\nmsgid \"\"\n\"the new current store size. Depending on the situation, the size \"\n\"reduction may be larger than the requested percentage.\"\nmsgstr \"新しい現在のストアサイズ。状況に応じて、要求された割合よりもサイズが大幅に削減される場合があります。\"\n\n#: ../../tools.rst:109 ../../tools.rst:119 b2c6c42229034879a13c08954bd588f3\n#: b6ae51cffc9c4a38a66643a43141bf46\nmsgid \"New in version 1.16.14\"\nmsgstr \"バージョン1.16.14で新たに追加\"\n\n#: ../../tools.rst:111 e883965495954aed98f30f83e9079e4f\nmsgid \"\"\n\"Return the current anti-aliasing values. These values control the \"\n\"rendering quality of graphics and text elements.\"\nmsgstr \"現在のアンチエイリアシング値を返します。これらの値は、グラフィックスとテキスト要素のレンダリング品質を制御します。\"\n\n#: ../../tools.rst:114 d4f138c5562e4a23a0da982a9c981f64\nmsgid \"\"\n\"A dictionary with the following initial content: `{'graphics': 8, 'text':\"\n\" 8, 'graphics_min_line_width': 0.0}`.\"\nmsgstr \"\"\n\"以下の初期内容を持つ辞書： `{'graphics': 8, 'text': 8, 'graphics_min_line_width': \"\n\"0.0}`。\"\n\n#: ../../tools.rst:121 debfdfadcaeb4efd8e0c271b9fdc0a06\nmsgid \"\"\n\"Set the new number of bits to use for anti-aliasing. The same value is \"\n\"taken currently for graphics and text rendering. This might change in a \"\n\"future MuPDF release.\"\nmsgstr \"アンチエイリアシングに使用するビット数を設定します。現在はグラフィックスとテキストのレンダリングに同じ値が使用されます。将来のMuPDFリリースで変更されるかもしれません。\"\n\n#: ../../tools.rst:123 3afd6a391b304cf9a27f036dd2a8eaea\nmsgid \"\"\n\"an integer ranging between 0 and 8. Value outside this range will be \"\n\"silently changed to valid values. The value will remain in effect \"\n\"throughout the current session or until changed again.\"\nmsgstr \"0から8までの範囲の整数。この範囲外の値は静かに有効な値に変更されます。この値は、現在のセッション全体または再度変更されるまで有効です。\"\n\n#: ../../tools.rst:128 ../../tools.rst:167 6647accef2ce43b5b05bcd3953c5d30a\n#: e0edaaaf95744a8f9baf9b72c5df725a\nmsgid \"New in version 1.16.0\"\nmsgstr \"バージョン1.16.0で新たに追加\"\n\n#: ../../tools.rst:130 1c026c1906724ca1b13646c1e61293e9\nmsgid \"Empty MuPDF warnings message buffer.\"\nmsgstr \"MuPDFの警告メッセージバッファを空にします。\"\n\n#: ../../tools.rst:135 df4c55d8bc2a4f6ca7f828393cd543b2\n#, fuzzy\nmsgid \"Control whether MuPDF errors should be displayed as |PyMuPDF| messages.\"\nmsgstr \"MuPDFのエラーを表示するかどうかを表示または設定します。\"\n\n#: ../../tools.rst:138 ../../tools.rst:154 73102cae996e4e1ca4fda07841b0a537\n#: c281bd2c631d4437a13966f361de0044\nmsgid \"If `None`, the current setting is left unchanged.\"\nmsgstr \"\"\n\n#: ../../tools.rst:139 4465af6643354c54be13db87f1577e1c\nmsgid \"\"\n\"Otherwise changes the current setting to `bool(value)`; if ``True``, \"\n\"future MuPDF errors will be shown as :ref:`Messages`.\"\nmsgstr \"\"\n\n#: ../../tools.rst:141 014bd4cfe67c4bb3bcc80ada14574ac7\nmsgid \"\"\n\"Regardless of this setting, MuPDF errors will always be stored in the \"\n\"warnings store.\"\nmsgstr \"\"\n\n#: ../../tools.rst:142 ../../tools.rst:158 8670777bc54b406d9b8d60d6f5053a03\n#: 8d3b08113ac444d1b78d9668a9fc41e5\nmsgid \"Upon import of |PyMuPDF| this value is ``True``.\"\nmsgstr \"\"\n\n#: ../../tools.rst:144 ../../tools.rst:160 83494dc367d6491db6461f478975266d\n#: a414e7de4bda4732bfea1df4dd2a1c93\nmsgid \"The current setting as ``True`` or ``False``.\"\nmsgstr \"\"\n\n#: ../../tools.rst:146 ../../tools.rst:162 80a5617a5563495a9a4817dcf619cea1\n#: dddb4d52d6d14c31b7f962bd3d1b949d\nmsgid \"New in version 1.16.8\"\nmsgstr \"バージョン1.16.8で新たに追加\"\n\n#: ../../tools.rst:151 af5f9e3136c24a14964064e6626325cf\nmsgid \"Control whether MuPDF warnings should be displayed as |PyMuPDF| messages.\"\nmsgstr \"\"\n\n#: ../../tools.rst:155 ac6aeba8d7af46f58aaa48643288ede1\nmsgid \"\"\n\"Otherwise changes the current setting to `bool(value)`; if ``True``, \"\n\"future MuPDF warnings will be shown as :ref:`Messages`.\"\nmsgstr \"\"\n\n#: ../../tools.rst:157 634e03217c9946ba97edc0b2a56d297f\nmsgid \"\"\n\"Regardless of this setting, MuPDF warnings will always be stored in the \"\n\"warnings store.\"\nmsgstr \"\"\n\n#: ../../tools.rst:169 ef0995c7931b4d9c8a892c119669e82d\nmsgid \"\"\n\"Return all stored MuPDF messages as a string with interspersed line-\"\n\"breaks.\"\nmsgstr \"すべての保存されたMuPDFメッセージを、改行が挿入された文字列として返します。\"\n\n#: ../../tools.rst:171 d3fae7bc59084382bd08ee62f17f5669\nmsgid \"*(new in version 1.16.7)* whether to automatically empty the store.\"\nmsgstr \"*（バージョン1.16.7で新たに追加）* ストアを自動的に空にするかどうか。\"\n\n#: ../../tools.rst:176 ed88482c9c404c6eb13f4e44e68a6402\nmsgid \"\"\n\"A dictionary containing the actual values used for configuring PyMuPDF \"\n\"and MuPDF. Also refer to the installation chapter. This is an overview of\"\n\" the keys, each of which describes the status of a support aspect.\"\nmsgstr \"PyMuPDFとMuPDFを設定するために使用される実際の値を含む辞書です。インストールの章も参照してください。これは各キーを概説したもので、それぞれがサポートの側面のステータスを記述しています。\"\n\n#: ../../tools.rst:179 983aafaaf72f47258fa885a81ffc31de\nmsgid \"**Key**\"\nmsgstr \"**キー**\"\n\n#: ../../tools.rst:179 2f18cc5c3f894e9e8c20b1cf745c4d35\nmsgid \"**Support included for ...**\"\nmsgstr \"**サポートが含まれているのは...**\"\n\n#: ../../tools.rst:181 67e338ca234a4c2aa997416d0d1c5e17\nmsgid \"plotter-g\"\nmsgstr \"\"\n\n#: ../../tools.rst:181 84bd5e00e5604b07b62a4f670c9ce45f\nmsgid \"Gray colorspace rendering\"\nmsgstr \"グレーカラースペースのレンダリング\"\n\n#: ../../tools.rst:182 76b2f02c816740679adf790799635016\nmsgid \"plotter-rgb\"\nmsgstr \"\"\n\n#: ../../tools.rst:182 79231c9485fd412994543d8f4d42c1fa\nmsgid \"RGB colorspace rendering\"\nmsgstr \"RGBカラースペースのレンダリング\"\n\n#: ../../tools.rst:183 91d85a25304d4436bfeed78b823f708d\nmsgid \"plotter-cmyk\"\nmsgstr \"\"\n\n#: ../../tools.rst:183 924491f03aaf43d8a889798e8268c631\nmsgid \"CMYK colorspcae rendering\"\nmsgstr \"CMYKカラースペースのレンダリング\"\n\n#: ../../tools.rst:184 b0fe29a8de9a4503a0c5bd27e7fc2b1e\nmsgid \"plotter-n\"\nmsgstr \"\"\n\n#: ../../tools.rst:184 e2367e803bd544e0a704fa3f6f4a377f\nmsgid \"overprint rendering\"\nmsgstr \"オーバープリントのレンダリング\"\n\n#: ../../tools.rst:185 40de005f09c64d48a68030bc62f04a7a\nmsgid \"pdf\"\nmsgstr \"\"\n\n#: ../../tools.rst:185 017318bcef5043d3a24dc1ac259bd96d\nmsgid \"PDF documents\"\nmsgstr \"PDFドキュメント\"\n\n#: ../../tools.rst:186 7879df7588cf4b4881667d16ef9b4044\nmsgid \"xps\"\nmsgstr \"\"\n\n#: ../../tools.rst:186 554de734100a44889b05ea16bbbb4801\nmsgid \"XPS documents\"\nmsgstr \"XPSドキュメント\"\n\n#: ../../tools.rst:187 e899c76673eb4de781ea52b20f05d668\nmsgid \"svg\"\nmsgstr \"\"\n\n#: ../../tools.rst:187 2dfe37a142164ae3acbc5c646b670f4f\nmsgid \"SVG documents\"\nmsgstr \"SVGドキュメント\"\n\n#: ../../tools.rst:188 5f181d975a094cc29464ac24fe074950\nmsgid \"cbz\"\nmsgstr \"\"\n\n#: ../../tools.rst:188 0bc4106af7494ee88794d1ae4bb7ff79\nmsgid \"CBZ documents\"\nmsgstr \"CBZドキュメント\"\n\n#: ../../tools.rst:189 61552041ec884b1bbe274dbbda088bd1\nmsgid \"img\"\nmsgstr \"\"\n\n#: ../../tools.rst:189 d12314e92993424f83174027a6ec725b\nmsgid \"IMG documents\"\nmsgstr \"IMGドキュメント\"\n\n#: ../../tools.rst:190 dd29953e1c66455a9923bf816e2a3282\nmsgid \"html\"\nmsgstr \"\"\n\n#: ../../tools.rst:190 127d85fe33354ac7971afa414123d63a\nmsgid \"HTML documents\"\nmsgstr \"HTMLドキュメント\"\n\n#: ../../tools.rst:191 10cbf4f7a1cd41b9a80e083b7c002bed\nmsgid \"epub\"\nmsgstr \"\"\n\n#: ../../tools.rst:191 9ec403b9146f43eea9153809fffae100\nmsgid \"EPUB documents\"\nmsgstr \"EPUBドキュメント\"\n\n#: ../../tools.rst:192 481a896d6b84460e8c1282ef91422469\nmsgid \"jpx\"\nmsgstr \"\"\n\n#: ../../tools.rst:192 22765c91abce4d04836e6ff2519678ef\nmsgid \"JPEG2000 images\"\nmsgstr \"JPEG2000画像\"\n\n#: ../../tools.rst:193 d46c0035bc044897ada86595b3d04bda\nmsgid \"js\"\nmsgstr \"\"\n\n#: ../../tools.rst:193 dfe437b8979a42939b5938fb1f481ed3\nmsgid \"JavaScript\"\nmsgstr \"\"\n\n#: ../../tools.rst:194 8ddda388461a473c9736d53993c96bcf\nmsgid \"tofu\"\nmsgstr \"\"\n\n#: ../../tools.rst:194 7c1d3ad770de460f824862a33e06e231\nmsgid \"all TOFU fonts\"\nmsgstr \"すべてのTOFUフォント\"\n\n#: ../../tools.rst:195 ac7fb6b9c8e445aeb8f522c60057cf2b\nmsgid \"tofu-cjk\"\nmsgstr \"\"\n\n#: ../../tools.rst:195 6285e0aecced48a88277034654e7e42d\nmsgid \"CJK font subset (China, Japan, Korea)\"\nmsgstr \"CJKフォントのサブセット（中国、日本、韓国）\"\n\n#: ../../tools.rst:196 2a0c3f09e54c410a975730ce5aaa00de\nmsgid \"tofu-cjk-ext\"\nmsgstr \"\"\n\n#: ../../tools.rst:196 32e4ef23a02f4c36a24fd31d49a5607e\nmsgid \"CJK font extensions\"\nmsgstr \"CJKフォント拡張\"\n\n#: ../../tools.rst:197 8cf92f3f79df450ebefd0fbca0b7d825\nmsgid \"tofu-cjk-lang\"\nmsgstr \"\"\n\n#: ../../tools.rst:197 b7426777724d4f16b655a5c11d77f9dd\nmsgid \"CJK font language extensions\"\nmsgstr \"CJKフォントの言語拡張\"\n\n#: ../../tools.rst:198 703a769d7b434dcaa4cfa08f972492b2\nmsgid \"tofu-emoji\"\nmsgstr \"\"\n\n#: ../../tools.rst:198 846d00d7a0a249ea87e0c1029b8e395c\nmsgid \"TOFU emoji fonts\"\nmsgstr \"TOFU絵文字フォント\"\n\n#: ../../tools.rst:199 66b289107a8e4e8abd1bd9d88d481d42\nmsgid \"tofu-historic\"\nmsgstr \"\"\n\n#: ../../tools.rst:199 6f259e97e9bd497d9e9a1e025bcf9982\nmsgid \"TOFU historic fonts\"\nmsgstr \"TOFU歴史的フォント\"\n\n#: ../../tools.rst:200 14977ce1ee544b9abfc8db96b0cbb68c\nmsgid \"tofu-symbol\"\nmsgstr \"\"\n\n#: ../../tools.rst:200 dd5d0777ea504428b2029606f420e098\nmsgid \"TOFU symbol fonts\"\nmsgstr \"TOFUシンボルフォント\"\n\n#: ../../tools.rst:201 629d3ba30efd4345bbc69f56a1d9810c\nmsgid \"tofu-sil\"\nmsgstr \"\"\n\n#: ../../tools.rst:201 bfbb2fb374b64c6082355e8e493b429f\nmsgid \"TOFU SIL fonts\"\nmsgstr \"TOFU SILフォント\"\n\n#: ../../tools.rst:202 4f7a65512f0844ef818c1d9624c5c335\nmsgid \"icc\"\nmsgstr \"\"\n\n#: ../../tools.rst:202 7fc4ac21a5104fac97ffb3afa1c5980d\nmsgid \"ICC profiles\"\nmsgstr \"ICCプロファイル\"\n\n#: ../../tools.rst:203 c40e5ca7f3024ac2b2434d42fd91fc52\nmsgid \"py-memory\"\nmsgstr \"\"\n\n#: ../../tools.rst:203 9b71c6d69b014bf2b7b0c8fe41ce6e22\nmsgid \"using Python memory management [#f2]_\"\nmsgstr \"Pythonメモリ管理を使用 [#f2]_\"\n\n#: ../../tools.rst:204 ab89c03d6ab44abfb553acb0f1bf378b\nmsgid \"base14\"\nmsgstr \"\"\n\n#: ../../tools.rst:204 002400f1661d403bb8cd28b30acbd9b1\nmsgid \"Base-14 fonts (should always be true)\"\nmsgstr \"Base-14フォント（常にtrueである必要があります）\"\n\n#: ../../tools.rst:207 a7392b4d969e4c53a89f24a17bedd641\n#, fuzzy\nmsgid \"\"\n\"For an explanation of the term \\\"TOFU\\\" see `this Wikipedia article \"\n\"<https://en.wikipedia.org/wiki/Noto_fonts>`_::\"\nmsgstr \"\"\n\"「TOFU」の用語の説明については、 `このウィキペディアの記事 \"\n\"<https://en.wikipedia.org/wiki/Noto_fonts>`_ を参照してください。::\"\n\n#: ../../tools.rst:241 f0ca1b8827e0409b8d193598bd42bbb6\nmsgid \"\"\n\"Maximum storables cache size in bytes. |PyMuPDF| is generated with a \"\n\"value of 268'435'456 (256 MB, the default value), which you should \"\n\"therefore always see here. If this value is zero, then an \\\"unlimited\\\" \"\n\"growth is permitted.\"\nmsgstr \"\"\n\"ストアブルキャッシュの最大サイズ（バイト単位）。 |PyMuPDF| は、デフォルト値である268'435'456（256 \"\n\"MB）で生成されており、したがって常にここで見るはずです。この値がゼロの場合、増加の「制限なし」が許可されています。\"\n\n#: ../../tools.rst:247 c4a141a4e2f54f6c821d474393efda1b\nmsgid \"\"\n\"Current storables cache size in bytes. This value may change (and will \"\n\"usually increase) with every use of a |PyMuPDF| function. It will \"\n\"(automatically) decrease only when :attr:`Tools.store_maxsize` is going \"\n\"to be exceeded: in this case, |MuPDF| will evict low-usage objects until \"\n\"the value is again in range.\"\nmsgstr \"\"\n\"現在のストアブルキャッシュのサイズ（バイト単位）。この値は、 |PyMuPDF| \"\n\"の関数を使用するたびに変更される可能性があります（通常は増加します）。この値は、:attr:`Tools.store_maxsize` \"\n\"が超過される場合にのみ（自動的に）減少し、その場合、MuPDFは使用率の低いオブジェクトを削除して、値が再び範囲内に収まるようにします。\"\n\n#: ../../tools.rst:252 081f0727dfcf40879ab8811e1fa325d3\nmsgid \"Example Session\"\nmsgstr \"セッションの例\"\n\n#: ../../tools.rst:288 99b53db972bc49c58f0d4592323bf6c1\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../tools.rst:289 df2b4099a10547688c103f8b5777ecc7\nmsgid \"\"\n\"This memory area is internally used by MuPDF, and it serves as a cache \"\n\"for objects that have already been read and interpreted, thus improving \"\n\"performance. The most bulky object types are images and also fonts. When \"\n\"an application starts up the MuPDF library (in our case this happens as \"\n\"part of *import pymupdf*), it must specify a maximum size for this area. \"\n\"PyMuPDF's uses the default value (256 MB) to limit memory consumption. \"\n\"Use the methods here to control or investigate store usage. For example: \"\n\"even after a document has been closed and all related objects have been \"\n\"deleted, the store usage may still not drop down to zero. So you might \"\n\"want to enforce that before opening another document.\"\nmsgstr \"\"\n\"このメモリ領域はMuPDF内部で使用され、既に読み取られ解釈されたオブジェクトのキャッシュとして機能し、パフォーマンスを向上させます。最も重いオブジェクトのタイプは画像およびフォントです。アプリケーションがMuPDFライブラリを起動するとき（私たちの場合、これは\"\n\" *import pymupdf* の一部として発生します）、この領域の最大サイズを指定する必要があります。 \"\n\"PyMuPDFはメモリ消費を制限するためにデフォルト値（256 \"\n\"MB）を使用します。ここで提供されているメソッドを使用してストアの使用状況を制御または調査できます。たとえば、文書が閉じられ、関連するすべてのオブジェクトが削除された後でも、ストアの使用状況がゼロにならないことがあります。したがって、別の文書を開く前にこれを強制したいかもしれません。\"\n\n#: ../../tools.rst:291 cff1cb203bfb4dd0a6e7c5c76c91e337\nmsgid \"\"\n\"By default PyMuPDF and MuPDF use `malloc()`/`free()` for dynamic memory \"\n\"management. One can instead force them to use the Python allocation \"\n\"functions `PyMem_New()`/`PyMem_Del()`, by modifying *fitz/fitz.i* to do \"\n\"`#define JM_MEMORY 1` and rebuilding PyMuPDF.\"\nmsgstr \"\"\n\"デフォルトでは、PyMuPDFおよびMuPDFは動的メモリ管理に `malloc()`/`free()` \"\n\"を使用します。代わりに、*fitz/fitz.i* を変更して `#define JM_MEMORY 1` \"\n\"を行い、PyMuPDFを再構築することで、Pythonの割り当て関数 `PyMem_New()`/`PyMem_Del()` \"\n\"を使用するように強制することができます。\"\n\n#: ../../footer.rst:60 03615545ca9c49a09aa7623e8edafff5\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"::\"\n#~ msgstr \"\"\n\n#~ msgid \"empty MuPDF messages on STDOUT\"\n#~ msgstr \"STDOUTのMuPDFメッセージを空にします。\"\n\n#~ msgid \"\"\n#~ \"if not a bool, the current setting\"\n#~ \" is returned. If true, MuPDF errors\"\n#~ \" will be shown on *sys.stderr*, \"\n#~ \"otherwise suppressed. In any case, \"\n#~ \"messages continue to be stored in \"\n#~ \"the warnings store. Upon import of \"\n#~ \"PyMuPDF this value is ``True``.\"\n#~ msgstr \"\"\n#~ \"boolでない場合、現在の設定が返されます。Trueの場合、MuPDFのエラーは *sys.stderr* \"\n#~ \"に表示され、それ以外の場合は抑制されます。いずれの場合も、メッセージは警告ストアに引き続き保存されます。PyMuPDFのインポート時にこの値は\"\n#~ \" ``True`` です。\"\n\n#~ msgid \"``True`` or ``False``\"\n#~ msgstr \"``True`` または ``False``\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/tutorial.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 af1c872c0c8149488a828ec57db0d05a\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 5f296e40a5a84c7db71c20c23cf034c9\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 6ce8107c629e456a909666cce87fe6bd\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../tutorial.rst:8 939af6d1c28b485eb4ff9f7d7027d32c\nmsgid \"Tutorial\"\nmsgstr \"チュートリアル\"\n\n#: ../../tutorial.rst:12 4f39e913a37d45aaaae25d581b6b21a5\nmsgid \"\"\n\"This tutorial will show you the use of |PyMuPDF|, |MuPDF| in Python, step\"\n\" by step.\"\nmsgstr \"このチュートリアルでは、PythonでのPyMuPDF、MuPDFのステップバイステップの使用方法を紹介します。\"\n\n#: ../../tutorial.rst:14 5a427c507e6b44479862e8eb2c0a69ba\nmsgid \"\"\n\"Because |MuPDF| supports not only PDF, but also XPS, OpenXPS, CBZ, CBR, \"\n\"FB2 and EPUB formats, so does |PyMuPDF| [#f1]_. Nevertheless, for the \"\n\"sake of brevity we will only talk about PDF files. At places where indeed\"\n\" only PDF files are supported, this will be mentioned explicitly.\"\nmsgstr \"MuPDFはPDFだけでなく、XPS、OpenXPS、CBZ、CBR、FB2、EPUB形式もサポートしており、PyMuPDFも同様です[1]。ただし、簡潔さのために、ここではPDFファイルについてのみ話を進めます。本当にPDFファイルのみがサポートされている場所では、明示的にその旨を記述します。\"\n\n#: ../../tutorial.rst:16 b2c324e1eda6484681a5b98002f9f022\nmsgid \"\"\n\"In addition to this introduction, please do visit PyMuPDF's `YouTube \"\n\"Channel <https://www.youtube.com/@PyMuPDF>`_ which covers most of the \"\n\"following in the form of YouTube \\\"Shorts\\\" and longer videos.\"\nmsgstr \"\"\n\"このイントロダクションに加えて、ぜひ `PyMuPDF の YouTube \"\n\"<https://www.youtube.com/@PyMuPDF>`_  チャンネル \"\n\"もご覧ください。以下の内容の多くが、YouTubeの「ショート動画」や長編動画の形式で紹介されています。\"\n\n#: ../../tutorial.rst:19 c23da3317c5d43fdadba3fa7c99c3afc\nmsgid \"Importing the Bindings\"\nmsgstr \"バインディングのインポート\"\n\n#: ../../tutorial.rst:20 a04dcd4a09c3420f950b46d664276cd8\nmsgid \"\"\n\"The Python bindings to MuPDF are made available by this import statement.\"\n\" We also show here how your version can be checked::\"\nmsgstr \"MuPDFへのPythonバインディングは、このインポート文によって利用可能になります。また、ここではあなたのバージョンを確認する方法も示します::\"\n\n#: ../../tutorial.rst:30 56adbb5b22484758912815cc290316d8\nmsgid \"Note on the Name *fitz*\"\nmsgstr \"*fitz* という名前についての注意事項\"\n\n#: ../../tutorial.rst:32 3b2a413d1d2040d38bbc841d83f98d16\nmsgid \"\"\n\"Old versions of |PyMuPDF| had their **Python** import name as `fitz`. \"\n\"Newer versions use `pymupdf` instead, and offer `fitz` as a fallback so \"\n\"that old code will still work.\"\nmsgstr \"このライブラリのPythonのトップレベルインポート名は **\\\"fitz\\\"** です。 これには歴史的な理由があります：\"\n\n#: ../../tutorial.rst:34 e7ad072736bc434da33243355f43a143\nmsgid \"The reason for the name `fitz` is a historical curiosity:\"\nmsgstr \"これには歴史的な理由があります：\"\n\n#: ../../tutorial.rst:36 0a1388985e214bc8803f67a3cdc99664\nmsgid \"The original rendering library for MuPDF was called *Libart*.\"\nmsgstr \"MuPDFの元々のレンダリングライブラリは *Libart* と呼ばれていました。\"\n\n#: ../../tutorial.rst:38 6bb98d1d5fd843a9a823b5a023f389e8\nmsgid \"\"\n\"*\\\"After Artifex Software acquired the MuPDF project, the development \"\n\"focus shifted on writing a new modern graphics library called \\\"Fitz\\\". \"\n\"Fitz was originally intended as an R&D project to replace the aging \"\n\"Ghostscript graphics library, but has instead become the rendering engine\"\n\" powering MuPDF.\\\"* (Quoted from `Wikipedia \"\n\"<https://en.wikipedia.org/wiki/MuPDF>`_).\"\nmsgstr \"\"\n\"「 Artifex SoftwareがMuPDFプロジェクトを取得した後、開発の焦点は新しいモダンなグラフィックスライブラリ \"\n\"\\\"Fitz\\\"の開発に移りました。 \"\n\"Fitzの開発に移りました。Fitzは元々古くなったGhostscriptグラフィックスライブラリを置き換えるためのR＆Dプロジェクトとして意図されていましたが、代わりにMuPDFを駆動するレンダリングエンジンになりました。」*\"\n\" (  `Wikipedia <https://en.wikipedia.org/wiki/MuPDF>`_ より引用 ) 。\"\n\n#: ../../tutorial.rst:42 f0b608072e0948f0a8d5019e86f78ae4\nmsgid \"\"\n\"Use of legacy name `fitz` can fail if defunct pypi.org package `fitz` is \"\n\"installed; see :ref:`problems-after-installation`.\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:48 5b6f4f47d3d14b3dabbafb6419e1bfd3\nmsgid \"Opening a Document\"\nmsgstr \"ドキュメントの開く\"\n\n#: ../../tutorial.rst:50 bad87b705ed349689aeb233740a2a4dd\nmsgid \"\"\n\"To access a :ref:`supported document<Supported_File_Types>`, it must be \"\n\"opened with the following statement::\"\nmsgstr \":ref:`サポートされているドキュメント <Supported_File_Types>` にアクセスするには、次の文で開く必要があります::\"\n\n#: ../../tutorial.rst:54 8ee29d11c6664eaba2d74e39fe256992\nmsgid \"\"\n\"This creates the :ref:`Document` object *doc*. *filename* must be a \"\n\"Python string (or a `pathlib.Path`) specifying the name of an existing \"\n\"file.\"\nmsgstr \"\"\n\"これにより、 :ref:`Document` \"\n\"オブジェクトdocが作成されます。filenameは、既存のファイルの名前を指定するPythonの文字列（または `pathlib.Path` \"\n\"）である必要があります。\"\n\n#: ../../tutorial.rst:56 fd7dc22114c4467ea703f11c5e4ddad9\nmsgid \"\"\n\"It is also possible to open a document from memory data, or to create a \"\n\"new, empty PDF. See :ref:`Document` for details. You can also use \"\n\":ref:`Document` as a *context manager*.\"\nmsgstr \"\"\n\"また、メモリデータからドキュメントを開くことや、新しい空のPDFを作成することも可能です。詳細については、 :ref:`Document` \"\n\"を参照してください。 :ref:`Document` はコンテキストマネージャとしても使用できます。\"\n\n#: ../../tutorial.rst:58 e53b2ee3b09744bba7d0a597e3110a06\nmsgid \"\"\n\"A document contains many attributes and functions. Among them are meta \"\n\"information (like \\\"author\\\" or \\\"subject\\\"), number of total pages, \"\n\"outline and encryption information.\"\nmsgstr \"ドキュメントには多くの属性と関数が含まれています。その中には、メタ情報（「author」や「subject」など）、総ページ数、アウトライン、暗号化情報などがあります。\"\n\n#: ../../tutorial.rst:61 ed2d7a85b35c446faacb3600235eef21\nmsgid \"Some :ref:`Document` Methods and Attributes\"\nmsgstr \"いくつかの :ref:`Document` メソッドと属\"\n\n#: ../../tutorial.rst:64 3b4470725538483087f6877a0b238a75\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド / 属性**\"\n\n#: ../../tutorial.rst:64 348a919c08be4e7bacbcbdebf6aadceb\nmsgid \"**Description**\"\nmsgstr \"説明\"\n\n#: ../../tutorial.rst:66 3c58bb5e0cfd4357bf595f5730c490f5\nmsgid \":attr:`Document.page_count`\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:66 71bcf48456184a0a864819c5c6c6b639\nmsgid \"the number of pages (*int*)\"\nmsgstr \"ページ数 (*int*)\"\n\n#: ../../tutorial.rst:67 a9ca3bea8587466696f8c3a412c51474\nmsgid \":attr:`Document.metadata`\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:67 5d63c2f5c2bf442da412566cddc8f0da\nmsgid \"the metadata (*dict*)\"\nmsgstr \"メタデータ (*dict*)\"\n\n#: ../../tutorial.rst:68 3a230f9d11cf49c8abaabfc21332281a\nmsgid \":meth:`Document.get_toc`\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:68 670c25d439184b3d864535494e4bc345\nmsgid \"get the table of contents (*list*)\"\nmsgstr \"目次を取得する (*list*)\"\n\n#: ../../tutorial.rst:69 4dbf36bdcc774cfe94f6fe488e23ab70\nmsgid \":meth:`Document.load_page`\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:69 6a5260a61382415882e9d006c179fe90\nmsgid \"read a :ref:`Page`\"\nmsgstr \":ref:`Page` を読む\"\n\n#: ../../tutorial.rst:73 d6bc5b209b1c4e7aa5b367e616992438\nmsgid \"Accessing Meta Data\"\nmsgstr \"メタデータへのアクセス\"\n\n#: ../../tutorial.rst:74 5eeb7a67a3834701bda60567079af358\nmsgid \"\"\n\"PyMuPDF fully supports standard metadata. :attr:`Document.metadata` is a \"\n\"Python dictionary with the following keys. It is available for **all \"\n\"document types**, though not all entries may always contain data. For \"\n\"details of their meanings and formats consult the respective manuals, \"\n\"e.g. :ref:`AdobeManual` for PDF. Further information can also be found in\"\n\" chapter :ref:`Document`. The meta data fields are strings or ``None`` if\"\n\" not otherwise indicated. Also be aware that not all of them always \"\n\"contain meaningful data -- even if they are not ``None``.\"\nmsgstr \"\"\n\"PyMuPDFは標準的なメタデータを完全にサポートしています。 :attr:`Document.metadata` \"\n\"はPythonの辞書で、次のキーが含まれています。これはすべてのドキュメントタイプで利用可能ですが、すべてのエントリが常にデータを含むわけではありません。それらの意味や形式の詳細については、対応するマニュアルを参照してください。例えば、PDFの場合は\"\n\" :ref:`AdobeManual` を参照してください。さらなる情報は :ref:`Document` \"\n\"の章でも見つけることができます。メタデータのフィールドは文字列または ``None`` \"\n\"です（特に指定がない場合）。また、それらのすべてが常に意味のあるデータを含んでいるわけではないことにも注意してください。\"\n\n#: ../../tutorial.rst:77 6c9a21d704a241029ce9b7f001b7bac5\nmsgid \"Key\"\nmsgstr \"キー\"\n\n#: ../../tutorial.rst:77 8400973337594bcf8e3da33817744ccf\nmsgid \"Value\"\nmsgstr \"値\"\n\n#: ../../tutorial.rst:79 6aa5ce470f8642c4af491e28af8bc999\nmsgid \"producer\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:79 52ee9d5cf1d94e4e824f1486804c0a49\nmsgid \"producer (producing software)\"\nmsgstr \"プロデューサー（生成ソフトウェア）\"\n\n#: ../../tutorial.rst:80 85a0fa96090940f499052abc68aac361\nmsgid \"format\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:80 cd1a7dc5cfca479ca59b0e5e2b00f5bb\nmsgid \"format: 'PDF-1.4', 'EPUB', etc.\"\nmsgstr \"形式：'PDF-1.4'、'EPUB'など\"\n\n#: ../../tutorial.rst:81 96773e4fde41492a8fbc9d8e0dfffe01\nmsgid \"encryption\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:81 4b242b9f88fb40e4847a8ad0358789ec\nmsgid \"encryption method used if any\"\nmsgstr \"暗号化方法（適用されている場合）\"\n\n#: ../../tutorial.rst:82 520e1f5cffc3419faccbecacb778ad88\n#: adc5542c41534ce68fe9d02192b1f9e0\nmsgid \"author\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:83 d593bfa2f3f1464ca98020a5d8cc2d74\nmsgid \"modDate\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:83 49db626a877e41699ba02058512b97d9\nmsgid \"date of last modification\"\nmsgstr \"最終更新日\"\n\n#: ../../tutorial.rst:84 ac0f4c311d9d4f91b366556afa0eac07\n#: cad667882e9247ed9a8465e9e8f6f30e\nmsgid \"keywords\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:85 4a12c1d082794891871985009346217e\n#: 9afee53342a24f749bd6b1695ceba4ca\nmsgid \"title\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:86 0659f2376ae84f0694559432c6acc6ab\nmsgid \"creationDate\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:86 c3e9c7f2af964de1a4ea55d6dfc87ae7\nmsgid \"date of creation\"\nmsgstr \"作成日\"\n\n#: ../../tutorial.rst:87 f7336bfddb6c47da8c979a965fd0e200\nmsgid \"creator\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:87 cde7dc3a8d604edeb4df81869876cc12\nmsgid \"creating application\"\nmsgstr \"作成アプリケーション\"\n\n#: ../../tutorial.rst:88 59f646e95f21440aab80a6d9eaee2cb5\n#: dfcc9986b7404e3ea4869973f3300afb\nmsgid \"subject\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:91 e212f47f482f4ba086c347c1ee602818\nmsgid \"\"\n\"Apart from these standard metadata, **PDF documents** starting from PDF \"\n\"version 1.4 may also contain so-called *\\\"metadata streams\\\"* (see also \"\n\":data:`stream`). Information in such streams is coded in XML. PyMuPDF \"\n\"deliberately contains no XML components for this purpose (the \"\n\":ref:`PyMuPDF Xml class<Xml>` is a helper class intended to access the \"\n\"DOM content of a :ref:`Story` object), so we do not directly support \"\n\"access to information contained therein. But you can extract the stream \"\n\"as a whole, inspect or modify it using a package like `lxml`_ and then \"\n\"store the result back into the PDF. If you want, you can also delete this\"\n\" data altogether.\"\nmsgstr \"\"\n\"PDFバージョン1.4以降のPDFドキュメントには、これらの標準的なメタデータに加えて、いわゆる「メタデータストリーム」（streamも参照）が含まれていることがあります。このようなストリームに含まれる情報はXMLでコード化されています。PyMuPDFは意図的にこの目的のためにXMLコンポーネントを含んでいないため（\"\n\" :ref:`PyMuPDF Xml class<Xml>` クラスは :ref:`Story` \"\n\"オブジェクトのDOMコンテンツにアクセスするためのヘルパークラスです）、その情報への直接的なアクセスをサポートしていません。しかし、 \"\n\"`lxml`_  \"\n\"などのパッケージを使用してストリーム全体を抽出し、検査または変更し、その結果をPDFに再格納することはできます。必要な場合は、このデータを完全に削除することもできます。\"\n\n#: ../../tutorial.rst:93 5ec202ac5c494be3bf62e68bf5ba28b1\nmsgid \"\"\n\"There are two utility scripts in the repository that `metadata import \"\n\"(PDF only)`_ resp. `metadata export`_ metadata from resp. to CSV files.\"\nmsgstr \"\"\n\"リポジトリには、`metadata import(PDF only)`_ および `metadata export`_ \"\n\"をCSVファイルに行うための2つのユーティリティスクリプトがあります\"\n\n#: ../../tutorial.rst:96 1d31369f6b884d08a61b700b01e9e7b1\nmsgid \"Working with Outlines\"\nmsgstr \"アウトラインと一緒に作業する\"\n\n#: ../../tutorial.rst:97 fe8e22242a324f349fca363f8d0f6348\nmsgid \"\"\n\"The easiest way to get all outlines (also called \\\"bookmarks\\\") of a \"\n\"document, is by loading its *table of contents*::\"\nmsgstr \"アウトライン（または「ブックマーク」とも呼ばれる）を取得する最も簡単な方法は、そのドキュメントの目次を読み込むことです::\"\n\n#: ../../tutorial.rst:101 4fe54a9ca0244cd9871ba72a155cbe95\nmsgid \"\"\n\"This will return a Python list of lists *[[lvl, title, page, ...], ...]* \"\n\"which looks much like a conventional table of contents found in books.\"\nmsgstr \"\"\n\"これにより、Pythonのリストであるリスト [[lvl, title, page, ...], ...] \"\n\"が返されます。これは、本に見られる伝統的な目次に非常によく似たものです。\"\n\n#: ../../tutorial.rst:103 a0df1526a42e4d88bf1fb24bf14c2392\nmsgid \"\"\n\"*lvl* is the hierarchy level of the entry (starting from 1), *title* is \"\n\"the entry's title, and *page* the page number (1-based!). Other \"\n\"parameters describe details of the bookmark target.\"\nmsgstr \"\"\n\"lvl はエントリーの階層レベル（1から開始）を示し、title はエントリーのタイトル、page \"\n\"はページ番号（1から始まる）を示します。その他のパラメータはブックマークのターゲットの詳細を説明します。\"\n\n#: ../../tutorial.rst:105 f60efb5302364edfb64c7775c185929b\nmsgid \"\"\n\"There are two utility scripts in the repository that `toc import (PDF \"\n\"only)`_ resp. `toc export`_ table of contents from resp. to CSV files.\"\nmsgstr \"\"\n\"リポジトリ内には、CSVファイルから目次をインポートおよびエクスポートするためのユーティリティスクリプトが2つあります。詳細は、 `toc \"\n\"import (PDF only)`_  および `toc export`_ をご覧ください。\"\n\n#: ../../tutorial.rst:108 f7e0d8ac5cd64bbfb19d5a7680f37840\nmsgid \"Working with Pages\"\nmsgstr \"ページの操作\"\n\n#: ../../tutorial.rst:109 bea68ab57a6a4ec49fa98a57625daec3\nmsgid \":ref:`Page` handling is at the core of MuPDF's functionality.\"\nmsgstr \":ref:`Page` の処理はMuPDFの機能の中核です。\"\n\n#: ../../tutorial.rst:111 705fbd37cfd04f5eb2725ee74973716c\nmsgid \"\"\n\"You can render a page into a raster or vector (SVG) image, optionally \"\n\"zooming, rotating, shifting or shearing it.\"\nmsgstr \"ページをラスターまたはベクター（SVG）イメージにレンダリングすることができます。オプションでズーム、回転、シフト、またはシアーを行うこともできます\"\n\n#: ../../tutorial.rst:112 07346e73ca2f4851bcb7243ed707f0c5\nmsgid \"\"\n\"You can extract a page's text and images in many formats and search for \"\n\"text strings.\"\nmsgstr \"テキストと画像を多くの形式で抽出し、テキスト文字列を検索することができます。\"\n\n#: ../../tutorial.rst:113 b10390460b7e469d933d4b0bca64cbd8\nmsgid \"\"\n\"For PDF documents many more methods are available to add text or images \"\n\"to pages.\"\nmsgstr \"PDFドキュメントの場合、さらに多くのメソッドが利用可能で、テキストや画像をページに追加することができます\"\n\n#: ../../tutorial.rst:115 634af7e840c34aba910ebc8b50aac6b1\nmsgid \"\"\n\"First, a :ref:`Page` must be created. This is a method of \"\n\":ref:`Document`::\"\nmsgstr \"最初に :ref:`Page` を作成する必要があります。これは :ref:`Document`  のメソッドです::\"\n\n#: ../../tutorial.rst:120 e13781020ec34c48a1d29405c5d4063b\nmsgid \"\"\n\"Any integer `-∞ < pno < page_count` is possible here. Negative numbers \"\n\"count backwards from the end, so *doc[-1]* is the last page, like with \"\n\"Python sequences.\"\nmsgstr \"\"\n\"ここでは、どんな整数  `-∞ < pno < page_count`  でも可能です。負の数は末尾から逆に数えますので、doc[-1] \"\n\"はPythonのシーケンスと同様に最後のページになります\"\n\n#: ../../tutorial.rst:122 4e28316907e444489cfbf10a12e27bba\nmsgid \"\"\n\"Some more advanced way would be using the document as an **iterator** \"\n\"over its pages::\"\nmsgstr \"より高度な方法として、ドキュメントをそのページの  **イテレータ** として使用することもできます::\"\n\n#: ../../tutorial.rst:136 84e73234fd424852a2b36c0bc15b2d9d\nmsgid \"Once you have your page, here is what you would typically do with it:\"\nmsgstr \"ページを取得したら、通常は次のようなことを行います：\"\n\n#: ../../tutorial.rst:139 088737b71af34948b17fbe30a60a9dc4\nmsgid \"Inspecting the Links, Annotations or Form Fields of a Page\"\nmsgstr \"リンク、注釈、またはフォームフィールドをページで調査する\"\n\n#: ../../tutorial.rst:140 80600b8ed5664159a8aad4e5b6706037\nmsgid \"\"\n\"Links are shown as \\\"hot areas\\\" when a document is displayed with some \"\n\"viewer software. If you click while your cursor shows a hand symbol, you \"\n\"will usually be taken to the target that is encoded in that hot area. \"\n\"Here is how to get all links::\"\nmsgstr \"リンクは、ドキュメントがビューアソフトウェアで表示されるときに「ホットエリア」として表示されます。カーソルが手のシンボルを示すときにクリックすると、通常、そのホットエリアにエンコードされたターゲットに移動します。以下はすべてのリンクを取得する方法です::\"\n\n#: ../../tutorial.rst:145 5b90391005b24d46b953ffde747dbd80\nmsgid \"\"\n\"*links* is a Python list of dictionaries. For details see \"\n\":meth:`Page.get_links`.\"\nmsgstr \"`links` はPythonの辞書のリストです。詳細は :meth:`Page.get_links` を参照してください。\"\n\n#: ../../tutorial.rst:147 19b388140fd44ace88779d4d2f85e3f5\nmsgid \"You can also use an iterator which emits one link at a time::\"\nmsgstr \"また、一度に1つのリンクを生成するイテレータを使用することもできます::\"\n\n#: ../../tutorial.rst:152 972adb409c6b4d1781d1976cb040f944\nmsgid \"\"\n\"If dealing with a PDF document page, there may also exist annotations \"\n\"(:ref:`Annot`) or form fields (:ref:`Widget`), each of which have their \"\n\"own iterators::\"\nmsgstr \"PDFドキュメントのページを扱う場合、注釈（:ref:`Annot`）やフォームフィールド（:ref:`Widget`）も存在する場合があります。それぞれに独自のイテレータがあります::\"\n\n#: ../../tutorial.rst:162 354960511fbd4e299b3561f27464ffa6\nmsgid \"Rendering a Page\"\nmsgstr \"ページのレンダリング\"\n\n#: ../../tutorial.rst:163 4b29e0e4b9f04b54a4b12db45462cebe\nmsgid \"This example creates a **raster** image of a page's content::\"\nmsgstr \"以下の例は、ページの内容をラスター画像として作成します::\"\n\n#: ../../tutorial.rst:167 b23c4b5d3b5345f0add5cb0dffaa6255\nmsgid \"\"\n\"``pix`` is a :ref:`Pixmap` object which (in this case) contains an \"\n\"**RGB** image of the page, ready to be used for many purposes. Method \"\n\":meth:`Page.get_pixmap` offers lots of variations for controlling the \"\n\"image: resolution / DPI, colorspace (e.g. to produce a grayscale image or\"\n\" an image with a subtractive color scheme), transparency, rotation, \"\n\"mirroring, shifting, shearing, etc. For example: to create an **RGBA** \"\n\"image (i.e. containing an alpha channel), specify *pix = \"\n\"page.get_pixmap(alpha=True)*.\"\nmsgstr \"\"\n\"`pix` はページのRGBイメージを含む :ref:`Pixmap` \"\n\"オブジェクトです。このイメージは多くの目的に使用する準備ができています。:meth:`Page.get_pixmap` \"\n\"メソッドには、画像を制御するためのさまざまなオプションが用意されています：解像度/DPI、カラースペース（例えば、グレースケールイメージや減色カラースキームのイメージを作成するために）、透明度、回転、ミラーリング、シフト、シアーなどがあります。例えば、RGBAイメージ（アルファチャネルを含むイメージ）を作成する場合は、`pix\"\n\" = page.get_pixmap(alpha=True)` と指定します。\"\n\n#: ../../tutorial.rst:169 e2331fb68ff848cab6245b27ba5f4079\nmsgid \"\"\n\"A :ref:`Pixmap` contains a number of methods and attributes which are \"\n\"referenced below. Among them are the integers ``width``, ``height`` (each\"\n\" in pixels) and ``stride`` (number of bytes of one horizontal image \"\n\"line). Attribute ``samples`` represents a rectangular area of bytes \"\n\"representing the image data (a Python ``bytes`` object).\"\nmsgstr \"\"\n\":ref:`Pixmap` \"\n\"には、以下で参照されるいくつかのメソッドと属性が含まれています。その中には、ピクセル単位の整数である幅、高さ（それぞれピクセル単位）および \"\n\"`stride` （1つの水平イメージラインのバイト数）があります。属性 `samples` \"\n\"は、イメージデータを表すバイトの長方形領域（Pythonの `bytes` オブジェクト）を表します。\"\n\n#: ../../tutorial.rst:171 03e8c67cd34a4299bbacfe8abd40de63\nmsgid \"\"\n\"You can also create a **vector** image of a page by using \"\n\":meth:`Page.get_svg_image`. Refer to this `Vector Image Support page`_ \"\n\"for details.\"\nmsgstr \"\"\n\":meth:`Page.get_svg_image` \"\n\"を使用することで、ページのベクターイメージを作成することもできます。詳細については、`Vector Image Support page`_ \"\n\"ページを参照してください。\"\n\n#: ../../tutorial.rst:174 c887d409be174ceca947d6b32e881d03\nmsgid \"Saving the Page Image in a File\"\nmsgstr \"ページのイメージをファイルに保存する\"\n\n#: ../../tutorial.rst:175 5e39659faf42451083abd892ba3bdb4e\nmsgid \"We can simply store the image in a PNG file::\"\nmsgstr \"簡単にページのイメージをPNGファイルに保存できます::\"\n\n#: ../../tutorial.rst:180 7ef7b19218354906a6c5d511a0672a1f\nmsgid \"Displaying the Image in GUIs\"\nmsgstr \"GUIでイメージを表示する\"\n\n#: ../../tutorial.rst:181 f6651c84f3d54689abdaff0d00a3095e\nmsgid \"\"\n\"We can also use it in GUI dialog managers. :attr:`Pixmap.samples` \"\n\"represents an area of bytes of all the pixels as a Python bytes object. \"\n\"Here are some examples, find more in the `examples`_ directory.\"\nmsgstr \"\"\n\"GUIダイアログマネージャーでも使用できます。 :attr:`Pixmap.samples` \"\n\"は、すべてのピクセルのバイトの領域をPythonのbytesオブジェクトとして表します。以下はいくつかの例ですが、さらに多くの例は \"\n\"`examples`_  ディレクトリで見つけることができます。\"\n\n#: ../../tutorial.rst:184 93b0ff029516467ca4a36bb526aeb687\nmsgid \"wxPython\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:185 6f03843027834dda8394ee85d04238d5\nmsgid \"\"\n\"Consult their documentation for adjustments to RGB(A) pixmaps and, \"\n\"potentially, specifics for your wxPython release::\"\nmsgstr \"RGB(A)のピクセルマップに対する調整や、可能な場合はwxPythonのリリースに特有の詳細については、関連するドキュメントを参照してください。\"\n\n#: ../../tutorial.rst:193 b6f1e9b15675411e9bd7023777e4b99a\nmsgid \"Tkinter\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:194 c11e72b65c0e4368a0fe00c748909105\nmsgid \"Please also see section 3.19 of the `Pillow documentation`_::\"\nmsgstr \"`Pillow documentation`_ ドキュメントのセクション3.19も参照してください。\"\n\n#: ../../tutorial.rst:203 41e53493133b4606b75fc48aa4b02d6b\nmsgid \"The following **avoids using Pillow**::\"\nmsgstr \"以下の方法では、Pillowを使用しないようにしています。\"\n\n#: ../../tutorial.rst:210 2d36aa26bccf4e5ba49ede95aef20a49\nmsgid \"\"\n\"If you are looking for a complete Tkinter script paging through **any \"\n\"supported** document, `here it is!`_. It can also zoom into pages, and it\"\n\" runs under Python 2 or 3. It requires the extremely handy `PySimpleGUI`_\"\n\" pure Python package.\"\nmsgstr \"\"\n\"もし、サポートされている任意のドキュメントをページ送りで表示する完全なTkinterスクリプトをお探しでしたら、`こちらがあります！ \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/browse-document/browse.py>`_ また、このスクリプトではページをズームインすることもでき、Python \"\n\"2または3で動作します。非常に便利な純粋なPythonパッケージである `PySimpleGUI`_ が必要です。\"\n\n#: ../../tutorial.rst:213 9a88cb97b2d9452ab197250569501e5f\nmsgid \"PyQt4, PyQt5, PySide\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:214 daeac83261ba4066a7dc604d3aa562f2\nmsgid \"Please also see section 3.16 of the `Pillow documentation`_::\"\nmsgstr \"Pillowドキュメントのセクション3.16も参照してください。\"\n\n#: ../../tutorial.rst:223 b85add3e93e4499b89e82f1646430a26\nmsgid \"\"\n\"Again, you also can get along **without using Pillow.** Qt's `QImage` \"\n\"luckily supports native Python pointers, so the following is the \"\n\"recommended way to create Qt images::\"\nmsgstr \"Pillowを使用せずに進めることもできます。幸運なことに、QtのQImageはネイティブなPythonポインタをサポートしているので、以下はQtイメージを作成する推奨される方法です。\"\n\n#: ../../tutorial.rst:233 0fcb7bc54009424fa20575e22fb06d0e\nmsgid \"Extracting Text and Images\"\nmsgstr \"テキストや画像を抽出する\"\n\n#: ../../tutorial.rst:234 f5900cc6c4924334a0f4bf4d1bdae4ae\nmsgid \"\"\n\"We can also extract all text, images and other information of a page in \"\n\"many different forms, and levels of detail::\"\nmsgstr \"ページのすべてのテキスト、画像、およびその他の情報を、さまざまな形式や詳細レベルで抽出することもできます。::\"\n\n#: ../../tutorial.rst:238 48bff694040b45549010d3b53435733b\nmsgid \"\"\n\"Use one of the following strings for *opt* to obtain different formats \"\n\"[#f2]_:\"\nmsgstr \"異なるフォーマットを得るために、以下の文字列のうち1つをoptに使用できます [#f2]_:\"\n\n#: ../../tutorial.rst:240 3c9203fe338a46629695295936dc44a4\nmsgid \"\"\n\"**\\\"text\\\"**: (default) plain text with line breaks. No formatting, no \"\n\"text position details, no images.\"\nmsgstr \"**\\\"text\\\"**:  (デフォルト) 行送りのプレーンテキスト。書式設定やテキストの位置の詳細、画像は含まれません。\"\n\n#: ../../tutorial.rst:242 ef523faacbb4433e9599b78451f9a623\nmsgid \"**\\\"blocks\\\"**: generate a list of text blocks (= paragraphs).\"\nmsgstr \"**\\\"blocks\\\"**: テキストブロック（段落）のリストを生成します。\"\n\n#: ../../tutorial.rst:244 494f2cbaf4dc4d3595b54a18d8165a4f\nmsgid \"**\\\"words\\\"**: generate a list of words (strings not containing spaces).\"\nmsgstr \"**\\\"words\\\"**: 単語（スペースを含まない文字列）のリストを生成します。\"\n\n#: ../../tutorial.rst:246 f95d696f7efa4e48a4fe4018638ee139\nmsgid \"\"\n\"**\\\"html\\\"**: creates a full visual version of the page including any \"\n\"images. This can be displayed with your internet browser.\"\nmsgstr \"**\\\"html\\\"**: 画像を含むページの完全な視覚的バージョンを作成します。これはインターネットブラウザで表示できます。\"\n\n#: ../../tutorial.rst:248 8f24748d78b04cc6b92c29fcae8ff8ca\nmsgid \"\"\n\"**\\\"dict\\\"** / **\\\"json\\\"**: same information level as HTML, but provided\"\n\" as a Python dictionary or resp. JSON string. See \"\n\":meth:`TextPage.extractDICT` for details of its structure.\"\nmsgstr \"\"\n\"**\\\"dict\\\"** / **\\\"json\\\"**: \"\n\"HTMLと同じ情報レベルですが、Pythonの辞書またはJSON文字列として提供されます。その構造の詳細については、:meth:`TextPage.extractDICT`\"\n\" を参照してください。\"\n\n#: ../../tutorial.rst:250 266283a205584bb98dd88e0282b81b8a\nmsgid \"\"\n\"**\\\"rawdict\\\"** / **\\\"rawjson\\\"**: a super-set of **\\\"dict\\\"** / \"\n\"**\\\"json\\\"**. It additionally provides character detail information like \"\n\"XML. See :meth:`TextPage.extractRAWDICT` for details of its structure.\"\nmsgstr \"\"\n\"**\\\"rawdict\\\"** / **\\\"rawjson\\\"**: \\\"dict\\\" / \"\n\"\\\"json\\\"のスーパーセットです。これにはXMLのような文字の詳細情報も含まれます。その構造の詳細については、:meth:`TextPage.extractRAWDICT`\"\n\" を参照してください。\"\n\n#: ../../tutorial.rst:252 be5015a7daf84be89659b718295dcaf6\nmsgid \"\"\n\"**\\\"xhtml\\\"**: text information level as the TEXT version but includes \"\n\"images. Can also be displayed by internet browsers.\"\nmsgstr \"**\\\"xhtml\\\"**: TEXTバージョンのテキスト情報レベルを含み、画像も含まれます。インターネットブラウザでも表示できます。\"\n\n#: ../../tutorial.rst:254 6a9fccccc2af470dbe418b64d95196fb\nmsgid \"\"\n\"**\\\"xml\\\"**: contains no images, but full position and font information \"\n\"down to each single text character. Use an XML module to interpret.\"\nmsgstr \"\"\n\"**\\\"xml\\\"**: \"\n\"画像は含まれませんが、各テキスト文字までの完全な位置とフォント情報を含みます。XMLモジュールを使用して解釈することができます。\"\n\n#: ../../tutorial.rst:256 c2fb29629d574544ba6240118706a993\nmsgid \"\"\n\"To give you an idea about the output of these alternatives, we did text \"\n\"example extracts. See :ref:`Appendix1`.\"\nmsgstr \"これらの代替方法の出力のイメージを示すために、テキストの例抽出を行いました。:ref:`Appendix1` を参照してください\"\n\n#: ../../tutorial.rst:259 6fcbe8fa549f4672940aa6a7baa43298\nmsgid \"Searching for Text\"\nmsgstr \"テキストを検索す\"\n\n#: ../../tutorial.rst:260 055f0da706d34efba1868870cc7ac25e\nmsgid \"You can find out, exactly where on a page a certain text string appears::\"\nmsgstr \"特定のテキスト文字列がページのどこに現れるかを正確に調べることができます。::\"\n\n#: ../../tutorial.rst:264 fa6460b021d44b8aba602b1940777f99\nmsgid \"\"\n\"This delivers a list of rectangles (see :ref:`Rect`), each of which \"\n\"surrounds one occurrence of the string \\\"mupdf\\\" (case insensitive). You \"\n\"could use this information to e.g. highlight those areas (PDF only) or \"\n\"create a cross reference of the document.\"\nmsgstr \"\"\n\"このコードは、\\\"mupdf\\\"（大文字と小文字を区別しない）という文字列が含まれる各領域を囲む長方形（ :ref:`Rect` \"\n\"参照）のリストを生成します。この情報を使って、それらの領域を強調表示したり（PDFのみ）、文書のクロスリファレンスを作成したりすることができます。\"\n\n#: ../../tutorial.rst:266 9602ff0fbee54febb5a9bce0eb7643a8\nmsgid \"\"\n\"Please also do have a look at chapter :ref:`cooperation` and at demo \"\n\"programs `demo.py`_ and `demo-lowlevel.py`_. Among other things they \"\n\"contain details on how the :ref:`TextPage`, :ref:`Device` and \"\n\":ref:`DisplayList` classes can be used for a more direct control, e.g. \"\n\"when performance considerations suggest it.\"\nmsgstr \"\"\n\"また、:ref:`cooperation` という章、およびデモプログラム `demo.py`_ と `demo-lowlevel.py`_ \"\n\"も参照してください。これらには、:ref:`TextPage` 、 :ref:`Device` 、:ref:`DisplayList` \"\n\"クラスをより直接的に制御する方法に関する詳細な情報が含まれています。例えば、パフォーマンスを考慮する必要がある場合などに役立ちます\"\n\n#: ../../tutorial.rst:273 d532b1e3d0b249d5863b7d1af292f56f\nmsgid \"Stories: Generating PDF from HTML Source\"\nmsgstr \"ストーリー: HTMLソースからPDFを生成する\"\n\n#: ../../tutorial.rst:275 416352710d134781921a3400fd5b5ef0\nmsgid \"\"\n\"The :ref:`Story` class is a new feature of PyMuPDF version 1.21.0. It \"\n\"represents support for MuPDF's **\\\"story\\\"** interface.\"\nmsgstr \"\"\n\"ストーリークラスはPyMuPDFバージョン1.21.0の新機能です。これはMuPDFの :ref:`Story` \"\n\"インターフェースに対するサポートを表しています。\"\n\n#: ../../tutorial.rst:277 accd3e3fc6d547b78b274237642033d6\nmsgid \"\"\n\"The following is a quote from the book `\\\"MuPDF Explored\\\"`_ by Robin \"\n\"Watts from `Artifex`_:\"\nmsgstr \"以下はArtifexのRobin Wattsによる書籍「MuPDF Explored」からの引用です。\"\n\n#: ../../tutorial.rst:281 47e500970eb842949a968db6adee0910\nmsgid \"\"\n\"*Stories provide a way to easily layout styled content for use with \"\n\"devices, such as those offered by Document Writers (...). The concept of \"\n\"a story comes from desktop publishing, which in turn (...) gets it from \"\n\"newspapers. If you consider a traditional newspaper layout, it will \"\n\"consist of various news articles (stories) that are laid out into \"\n\"multiple columns, possibly across multiple pages.*\"\nmsgstr \"*ストーリーは、ドキュメントライターなどのデバイスで使用するためのスタイル付きコンテンツを簡単にレイアウトする方法を提供します。ストーリーという概念は、デスクトップパブリッシングから来ており、それ自体が新聞から取り入れられています。伝統的な新聞のレイアウトを考えると、複数の列や複数のページにわたって配置されたさまざまなニュース記事（ストーリー）で構成されています。*\"\n\n#: ../../tutorial.rst:283 27ebf650cfb746b6ae9e42bdde508478\nmsgid \"\"\n\"*Accordingly, MuPDF uses a story to represent a flow of text with styling\"\n\" information. The user of the story can then supply a sequence of \"\n\"rectangles into which the story will be laid out, and the positioned text\"\n\" can then be drawn to an output device. This keeps the concept of the \"\n\"text itself (the story) to be separated from the areas into which the \"\n\"text should be flowed (the layout).*\"\nmsgstr \"*それに応じて、MuPDFでは、テキストのフローとスタイリング情報を表すためにストーリーを使用しています。ストーリーのユーザーは、ストーリーをレイアウトするための矩形のシーケンスを提供し、配置されたテキストを出力デバイスに描画できます。これにより、テキスト自体（ストーリー）がテキストを配置する領域（レイアウト）から分離されるという概念が保持されます*\"\n\n#: ../../tutorial.rst:287 7da64d937fe84390a33b56158c76d219\nmsgid \"\"\n\"A Story works somewhat similar to an internet browser: It faithfully \"\n\"parses and renders HTML hypertext and also optional stylesheets (CSS). \"\n\"But its **output is a PDF** -- not web pages.\"\nmsgstr \"ストーリーは、インターネットブラウザといくつかの点で似ています。それは忠実にHTMLハイパーテキストとオプションのスタイルシート（CSS）を解析してレンダリングします。ただし、出力されるのはPDFであり、ウェブページではありません。\"\n\n#: ../../tutorial.rst:290 290d5414b6754a0a8cec4ef553811e70\nmsgid \"\"\n\"When creating a :ref:`Story`, the input from up to three different \"\n\"information sources is taken into account. All these items are optional.\"\nmsgstr \"ストーリーを作成する際には、最大3つの異なる情報源からの入力が考慮されます。これらのすべてのアイテムはオプションです。\"\n\n#: ../../tutorial.rst:292 b76811f3a6e94ca48849af027b1e4aa7\nmsgid \"\"\n\"HTML source code, either a Python string or **created by the script** \"\n\"using methods of :ref:`Xml`.\"\nmsgstr \"HTMLソースコード：Pythonの文字列として提供されるか、 :ref:`Xml` のメソッドを使用してスクリプトによって作成されます。\"\n\n#: ../../tutorial.rst:294 631005d36d9d478eb1222c6746a62f78\nmsgid \"\"\n\"CSS (Cascaded Style Sheet) source code, provided as a Python string. CSS \"\n\"can be used to provide styling information (text font size, color, etc.) \"\n\"like it would happen for web pages. Obviously, this string may also be \"\n\"read from a file.\"\nmsgstr \"CSS（カスケーディングスタイルシート）ソースコード：Pythonの文字列として提供されます。CSSは、ウェブページにおけるように、スタイリング情報（テキストフォントサイズ、色など）を提供するために使用できます。もちろん、この文字列はファイルから読み込むこともできます。\"\n\n#: ../../tutorial.rst:296 b555903aaf064df4ac02bf4379ecd84b\nmsgid \"\"\n\"An :ref:`Archive` **must be used** whenever the DOM references images, or\"\n\" uses text fonts except the standard :ref:`Base-14-Fonts`, CJK fonts and \"\n\"the NOTO fonts generated into the PyMuPDF binary.\"\nmsgstr \"\"\n\"DOMが画像を参照する場合や、標準の :ref:`Base-14-Fonts` \"\n\"、CJKフォント、およびPyMuPDFバイナリに生成されたNOTOフォント以外のテキストフォントを使用する場合、 :ref:`Archive` \"\n\"を使用する必要があります。\"\n\n#: ../../tutorial.rst:299 5a5a7775caf44157ab99d4fb18a08da0\nmsgid \"\"\n\"The :ref:`API<Xml>` allows creating DOMs completely from scratch, \"\n\"including desired styling information. It can also be used to modify or \"\n\"extend **provided** HTML: text can be deleted or replaced, or its styling\"\n\" can be changed. Text -- for example extracted from databases -- can also\"\n\" be added and fill template-like HTML documents.\"\nmsgstr \"\"\n\"この :ref:`API<Xml>` \"\n\"では、望むスタイル情報を含めて、DOMを完全にゼロから作成することができます。また、提供されたHTMLを変更したり拡張したりするためにも使用できます。テキストは削除や置換ができ、スタイルも変更できます。データベースから抽出されたテキストを追加して、テンプレートのようなHTMLドキュメントを作成することもできます。\"\n\n#: ../../tutorial.rst:301 eff1f356f57a4a5baa32893df82ccc7f\nmsgid \"\"\n\"It is **not required** to provide syntactically complete HTML documents: \"\n\"snippets like `<b>Hello <i>World!</i></b>` are fully accepted, and many /\"\n\" most syntax errors are automatically corrected.\"\nmsgstr \"\"\n\"文法的に完全なHTMLドキュメントを提供する必要はありません。例えば ``<b>Hello<i>World!</i></b>`` \"\n\"のような断片も完全に受け入れられ、多くの場合、構文エラーは自動的に修正されます。\"\n\n#: ../../tutorial.rst:303 365fa2cc06434ed8ad7429aaf3a63265\nmsgid \"\"\n\"After the HTML is considered complete, it can be used to create a PDF \"\n\"document. This happens via the new :ref:`DocumentWriter` class. The \"\n\"programmer calls its methods to create a new empty page, and passes \"\n\"rectangles to the Story to fill them.\"\nmsgstr \"\"\n\"HTMLが完成したと見なされた後、それを使用してPDF文書を作成できます。これは新しい :ref:`DocumentWriter`  \"\n\"クラスを介して行われます。プログラマーはそのメソッドを呼び出して新しい空のページを作成し、:ref:`Story` \"\n\"に矩形を渡してそれらを埋めることができます。\"\n\n#: ../../tutorial.rst:305 3291ca47108e47b19f4b0bc0a5a4027b\nmsgid \"\"\n\"The story in turn will return completion codes indicating whether or not \"\n\"more content is waiting to be written. Which part of the content will \"\n\"land in which rectangle or on which page is automatically determined by \"\n\"the story itself -- it cannot be influenced other than by providing the \"\n\"rectangles.\"\nmsgstr \"\"\n\":ref:`Story` \"\n\"は、書き込まれる待機中のコンテンツがあるかどうかを示す完了コードを返します。コンテンツのどの部分がどの矩形またはどのページに配置されるかは、:ref:`Story`\"\n\" 自体によって自動的に決定されます。矩形を提供すること以外では影響を与えることはできません。\"\n\n#: ../../tutorial.rst:307 bd9d9dd769be42d4b2431ad4fac946e4\nmsgid \"\"\n\"Please see the :ref:`Stories recipes<RecipesStories>` for a number of \"\n\"typical use cases.\"\nmsgstr \"典型的な使用例については、 :ref:`Stories recipes<RecipesStories>` レシピをご覧ください。\"\n\n#: ../../tutorial.rst:311 b4514f2b40064533bbf026420a0260d7\nmsgid \"PDF Maintenance\"\nmsgstr \"PDFメンテナンス\"\n\n#: ../../tutorial.rst:312 76f8cae636954def812f6bd6aa4d9077\nmsgid \"\"\n\"PDFs are the only document type that can be **modified** using PyMuPDF. \"\n\"Other file types are read-only.\"\nmsgstr \"PDFはPyMuPDFを使用して変更できる唯一のドキュメントタイプです。他のファイルタイプは読み取り専用です。\"\n\n#: ../../tutorial.rst:314 6d192d43c9e24232be29c65e1e0c1018\nmsgid \"\"\n\"However, you can convert **any document** (including images) to a PDF and\"\n\" then apply all PyMuPDF features to the conversion result. Find out more \"\n\"here :meth:`Document.convert_to_pdf`, and also look at the demo script \"\n\"`pdf-converter.py`_ which can convert any :ref:`supported \"\n\"document<Supported_File_Types>` to PDF.\"\nmsgstr \"\"\n\"ただし、任意のドキュメント（画像を含む）をPDFに変換し、変換結果にすべてのPyMuPDF機能を適用することができます。 \"\n\":meth:`Document.convert_to_pdf` \"\n\"で詳細を確認できます。また、任意のサポートされているドキュメントをPDFに変換できるデモスクリプト `pdf-converter.py`_ \"\n\"も確認してください。\"\n\n#: ../../tutorial.rst:316 05d7bbe4027a4e9b98372c4707c22cd4\nmsgid \"\"\n\":meth:`Document.save()` always stores a PDF in its current (potentially \"\n\"modified) state on disk.\"\nmsgstr \":meth:`Document.save()` は常に現在の（変更された可能性のある）PDFをディスクに保存します。\"\n\n#: ../../tutorial.rst:318 400c516b51f0441a9c6ac7d433101329\nmsgid \"\"\n\"You normally can choose whether to save to a new file, or just append \"\n\"your modifications to the existing one (\\\"incremental save\\\"), which \"\n\"often is very much faster.\"\nmsgstr \"通常、新しいファイルに保存するか、既存のファイルに変更内容を追加するか（「増分保存」）を選択できます。増分保存は非常に高速な場合があります。\"\n\n#: ../../tutorial.rst:320 57fdfcd11a1245249d7e837f37b43094\nmsgid \"\"\n\"The following describes ways how you can manipulate PDF documents. This \"\n\"description is by no means complete: much more can be found in the \"\n\"following chapters.\"\nmsgstr \"以下にPDFドキュメントを操作する方法を示しますが、これに限らず、詳細は次の章でさらに見つけることができます。\"\n\n#: ../../tutorial.rst:323 ec4c85ec57124203b67f52652f082b88\nmsgid \"Modifying, Creating, Re-arranging and Deleting Pages\"\nmsgstr \"ページの修正、作成、再配置、および削\"\n\n#: ../../tutorial.rst:324 625ab390c172404fbdc7aa9520874495\nmsgid \"\"\n\"There are several ways to manipulate the so-called **page tree** (a \"\n\"structure describing all the pages) of a PDF:\"\nmsgstr \"PDFの**ページツリー** （すべてのページを記述する構造）を操作するためには、いくつかの方法があります。\"\n\n#: ../../tutorial.rst:326 159259eb9e4145daa6c13b2ad767f12e\nmsgid \"\"\n\":meth:`Document.delete_page` and :meth:`Document.delete_pages` delete \"\n\"pages.\"\nmsgstr \":meth:`Document.delete_page` と :meth:`Document.delete_pages` はページを削除します。\"\n\n#: ../../tutorial.rst:328 473d5897fff649019f539d6232e91f44\nmsgid \"\"\n\":meth:`Document.copy_page`, :meth:`Document.fullcopy_page` and \"\n\":meth:`Document.move_page` copy or move a page to other locations within \"\n\"the same document.\"\nmsgstr \"\"\n\":meth:`Document.copy_page` 、 :meth:`Document.fullcopy_page` 、 \"\n\":meth:`Document.move_page` は、ページを同じドキュメント内の他の場所にコピーしたり移動したりします。\"\n\n#: ../../tutorial.rst:330 1e6c19e64c734426bec58da4dfbe7e0b\nmsgid \"\"\n\":meth:`Document.select` shrinks a PDF down to selected pages. Parameter \"\n\"is a sequence [#f3]_ of the page numbers that you want to keep. These \"\n\"integers must all be in range *0 <= i < page_count*. When executed, all \"\n\"pages **missing** in this list will be deleted. Remaining pages will \"\n\"occur **in the sequence and as many times (!) as you specify them**.\"\nmsgstr \"\"\n\":meth:`Document.select` \"\n\"はPDFを選択したページに縮小します。パラメータは[3]のページ番号のシーケンスで、保持したいページの番号を指定します。これらの整数はすべて範囲 \"\n\"`0 <= i < page_count` \"\n\"にある必要があります。実行されると、このリストに含まれていないすべてのページが削除されます。残ったページは指定した順序通りに（指定回数分！）現れます。\"\n\n#: ../../tutorial.rst:332 1032d54636274cfab2c769409afa76e0\nmsgid \"So you can easily create new PDFs with\"\nmsgstr \"したがって、次のような簡単な方法で新しいPDFを作成できます:\"\n\n#: ../../tutorial.rst:334 e8415caf00594110bef2b948c89abcbd\nmsgid \"the first or last 10 pages,\"\nmsgstr \"最初または最後の10ページ\"\n\n#: ../../tutorial.rst:335 fc336f721207413b95dce987329adfad\nmsgid \"only the odd or only the even pages (for doing double-sided printing),\"\nmsgstr \"奇数ページのみまたは偶数ページのみ（両面印刷用）\"\n\n#: ../../tutorial.rst:336 3a6929bd1e7d4e178ef1549c9c67d87a\nmsgid \"pages that **do** or **don't** contain a given text,\"\nmsgstr \"特定のテキストを含むまたは含まないページ\"\n\n#: ../../tutorial.rst:337 968ba746356447208207a1cee391ea52\nmsgid \"reverse the page sequence, ...\"\nmsgstr \"ページの順序を逆にする\"\n\n#: ../../tutorial.rst:339 1c2ed724e9564be1a8841011462e53a1\nmsgid \"... whatever you can think of.\"\nmsgstr \"... など、思いつく限りのことができます。\"\n\n#: ../../tutorial.rst:341 3a7dc1aa206e4858a930d0cc0ce437cf\nmsgid \"\"\n\"The saved new document will contain links, annotations and bookmarks that\"\n\" are still valid (i.a.w. either pointing to a selected page or to some \"\n\"external resource).\"\nmsgstr \"保存された新しいドキュメントには、まだ有効なリンク、注釈、およびブックマークが含まれています（選択したページを指すか、あるいは外部リソースを指すかを問わず）。\"\n\n#: ../../tutorial.rst:343 62273df02f3a43edaca93b7b9899b551\nmsgid \"\"\n\":meth:`Document.insert_page` and :meth:`Document.new_page` insert new \"\n\"pages.\"\nmsgstr \":meth:`Document.insert_page` および :meth:`Document.new_page` は新しいページを挿入します。\"\n\n#: ../../tutorial.rst:345 62ec5bdcc4854cc0ab7b5a9c5de8295e\nmsgid \"\"\n\"Pages themselves can moreover be modified by a range of methods (e.g. \"\n\"page rotation, annotation and link maintenance, text and image \"\n\"insertion).\"\nmsgstr \"さらに、ページ自体はさまざまな方法で変更できます（ページの回転、注釈とリンクの維持、テキストと画像の挿入など）\"\n\n#: ../../tutorial.rst:348 f481a1f85523458ba716bfffa017ecc2\nmsgid \"Joining and Splitting PDF Documents\"\nmsgstr \"PDF文書の結合と分割\"\n\n#: ../../tutorial.rst:350 5c4f9e715c364f99ab85e02a35390a54\nmsgid \"\"\n\"Method :meth:`Document.insert_pdf` copies pages **between different** PDF\"\n\" documents. Here is a simple **joiner** example (*doc1* and *doc2* being \"\n\"opened PDFs)::\"\nmsgstr \"\"\n\"メソッド  :meth:`Document.insert_pdf` は異なるPDF文書間でページをコピーします。以下は簡単な結合の例です（ \"\n\"`doc1` と `doc2` は開かれたPDF文書です）::\"\n\n#: ../../tutorial.rst:355 76e1ca6378be4c7780b008c6aa0147b1\nmsgid \"\"\n\"Here is a snippet that **splits** *doc1*. It creates a new document of \"\n\"its first and its last 10 pages::\"\nmsgstr \"以下は、 `doc1` を分割するスニペットです。最初の10ページと最後の10ページを含む新しいドキュメントを作成します。\"\n\n#: ../../tutorial.rst:362 425d928677684aaebd2c13acc306cc3a\nmsgid \"\"\n\"More can be found in the :ref:`Document` chapter. Also have a look at \"\n\"`PDFjoiner.py`_.\"\nmsgstr \":ref:`Document` の章にはさらに詳細が記載されています。また、 `PDFjoiner.py`_ も確認してください。\"\n\n#: ../../tutorial.rst:365 3a32f81f55af4ff2942e6a5bda5351e4\nmsgid \"Embedding Data\"\nmsgstr \"データの埋め込み\"\n\n#: ../../tutorial.rst:367 e8c1a07274464e69b5716d2cfcd333a2\nmsgid \"\"\n\"PDFs can be used as containers for arbitrary data (executables, other \"\n\"PDFs, text or binary files, etc.) much like ZIP archives.\"\nmsgstr \"PDFはZIPアーカイブのように、任意のデータ（実行可能ファイル、他のPDF、テキストファイル、バイナリファイルなど）をコンテナとして使用できます。\"\n\n#: ../../tutorial.rst:369 e53116859c304e5d8cae52bca7615d49\n#, fuzzy\nmsgid \"\"\n\"PyMuPDF fully supports this feature via :ref:`Document` ``embfile_*`` \"\n\"methods and attributes. For some detail read :ref:`Appendix 3`, consult \"\n\"the Wiki on `dealing with embedding files`_, or the example scripts \"\n\"`embedded-copy.py`_, `embedded-export.py`_, `embedded-import.py`_, and \"\n\"`embedded-list.py`_.\"\nmsgstr \"\"\n\"PyMuPDFは :ref:`Document` *embfile_** \"\n\"メソッドと属性を介して、この機能を完全にサポートしています。詳細については、 :ref:`Appendix3` \"\n\"を読むか、ファイルの埋め込みに対処するためのウィキを参照してください。また、exampleスクリプトの `embedded-copy.py`_ \"\n\"、`embedded-export.py`_ 、`embedded-import.py`_ 、および `embedded-list.py`_ \"\n\"も参考になるでしょう。\"\n\n#: ../../tutorial.rst:373 7e063cc85bf74b67af328699883eabcd\nmsgid \"Saving\"\nmsgstr \"保存\"\n\n#: ../../tutorial.rst:375 ddc980f323444d9a888df621e5e4413a\nmsgid \"\"\n\"As mentioned above, :meth:`Document.save` will **always** save the \"\n\"document in its current state.\"\nmsgstr \"前述のように、 :meth:`Document.save` は常にドキュメントを現在の状態で保存します。\"\n\n#: ../../tutorial.rst:377 938eb4bca93d44e7ad9d9db6a21b0197\nmsgid \"\"\n\"You can write changes back to the **original PDF** by specifying option \"\n\"``incremental=True``. This process is (usually) **extremely fast**, since\"\n\" changes are **appended to the original file** without completely \"\n\"rewriting it.\"\nmsgstr \"\"\n\"オプション  `incremental=True`  \"\n\"を指定することで、変更を元のPDFに書き戻すことができます。このプロセスは（通常）非常に高速です。変更は元のファイルに追加されるため、完全に書き直す必要がありません。\"\n\n#: ../../tutorial.rst:379 34a90e8b41204457b27c7bf4c896ed07\nmsgid \"\"\n\":meth:`Document.save` options correspond to options of MuPDF's command \"\n\"line utility *mutool clean*, see the following table.\"\nmsgstr \"\"\n\":meth:`Document.save` のオプションは、MuPDFのコマンドラインユーティリティmutool \"\n\"cleanのオプションと対応しています。以下の表を参照してください。\"\n\n#: ../../tutorial.rst:382 1163070c3e2e478c9edfeeef99960201\nmsgid \"**Save Option**\"\nmsgstr \"**保存オプション**\"\n\n#: ../../tutorial.rst:382 94311b1ebca3478a8d7bf6f6d522fd8b\nmsgid \"**mutool**\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:382 962d3ef8846c431c8e9dfdf9d487bfb1\nmsgid \"**Effect**\"\nmsgstr \"**効果**\"\n\n#: ../../tutorial.rst:384 b65cf8acc8bc476f8334931a4c8a17b8\nmsgid \"garbage=1\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:384 6b4221531c1b4915975145d5a46840f9\nmsgid \"g\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:384 b773213735d5433a912d7d50de094b58\nmsgid \"garbage collect unused objects\"\nmsgstr \"未使用のオブジェクトをガベージコレクションします\"\n\n#: ../../tutorial.rst:385 9bb3557107484b32b9d48ee883975e41\nmsgid \"garbage=2\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:385 e5d8266ec4434156843ae8d329cb1234\nmsgid \"gg\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:385 5d1cd64ee4a44495b52e5808a4c51ebf\nmsgid \"in addition to 1, compact :data:`xref` tables\"\nmsgstr \"1に加えて、xrefテーブルをコンパクトにします\"\n\n#: ../../tutorial.rst:386 5846a30c454d494b9cb77c2612b7e3ba\nmsgid \"garbage=3\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:386 8499a2c0b7254ddfbc44cba627532452\nmsgid \"ggg\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:386 349d1afd120c468c8663d3467baf0a1d\nmsgid \"in addition to 2, merge duplicate objects\"\nmsgstr \"2に加えて、重複したオブジェクトをマージします\"\n\n#: ../../tutorial.rst:387 f97513200d184db2818ef3272e06659d\nmsgid \"garbage=4\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:387 8818b59f9bf3464e8ff2acae77c152f2\nmsgid \"gggg\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:387 c284ddf0b0794e979bfa728c57373d83\nmsgid \"in addition to 3, merge duplicate stream content\"\nmsgstr \"3に加えて、重複したストリームの内容をマージします\"\n\n#: ../../tutorial.rst:388 7874a21a2a374610abddf1cbd7efb717\nmsgid \"clean=True\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:388 c1e6bac1097a452a8399150c1e9c8279\nmsgid \"cs\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:388 9ddc64830c9040ed8451f02ed2741816\nmsgid \"clean and sanitize content streams\"\nmsgstr \"コンテンツストリームをクリーンアップしてサニタイズします\"\n\n#: ../../tutorial.rst:389 c2f486c396c84db0ba07db1c9ee5a7ae\nmsgid \"deflate=True\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:389 49a98a67d15747c98e6ca70bb53f3c51\nmsgid \"z\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:389 37e910e46f2247d3a69e36dbd0748d94\nmsgid \"deflate uncompressed streams\"\nmsgstr \"非圧縮のストリームをdeflate圧縮します\"\n\n#: ../../tutorial.rst:390 7ffbd7aa96264ff1902b58f73b4fd092\nmsgid \"deflate_images=True\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:390 83ea4c4b317d488092885540eb84f939\nmsgid \"i\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:390 4e719956c06a4d49bb8d10a19576ee42\nmsgid \"deflate image streams\"\nmsgstr \"画像ストリームをdeflate圧縮します\"\n\n#: ../../tutorial.rst:391 c33f6052e9494538ae7f4e1191c64fd2\nmsgid \"deflate_fonts=True\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:391 9786f972e1be4a16b85ffee8b754ec19\nmsgid \"f\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:391 79fefb0533874ecb8a096e7db7f10332\nmsgid \"deflate fontfile streams\"\nmsgstr \"フォントファイルストリームをdeflate圧縮します\"\n\n#: ../../tutorial.rst:392 423d166f2fc54b4498a9377a2dd30960\nmsgid \"ascii=True\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:392 a67143a6cbe040c590ae0a63a0fe9234\nmsgid \"a\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:392 59590f861522439b8f81250d3941e06c\nmsgid \"convert binary data to ASCII format\"\nmsgstr \"バイナリデータをASCII形式に変換します\"\n\n#: ../../tutorial.rst:393 86236a9e66cf4150970d92080d6e1583\nmsgid \"linear=True\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:393 5893e24f2faa4060ba0c43aa63dbd263\nmsgid \"l\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:393 0dec5675398e49978e78651893a99395\nmsgid \"create a linearized version\"\nmsgstr \"線形化バージョンを作成します\"\n\n#: ../../tutorial.rst:394 febbe58d4b104f8bbe950ccccccb1859\nmsgid \"expand=True\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:394 ef0e028a01314e21a0d744ca0d2ad01f\nmsgid \"d\"\nmsgstr \"\"\n\n#: ../../tutorial.rst:394 09ec7a0736e34a67aa68a9542195d17e\nmsgid \"decompress all streams\"\nmsgstr \"すべてのストリームを解凍します\"\n\n#: ../../tutorial.rst:397 e917b060c085407fb80a474e3bec75e9\n#, fuzzy\nmsgid \"\"\n\"For an explanation of terms like ``object``, ``stream``, ``xref`` consult\"\n\" the :ref:`Glossary` chapter.\"\nmsgstr \"オブジェクト、ストリーム、xrefなどの用語の詳細については、 :ref:`Glossary`  の章を参照してください。\"\n\n#: ../../tutorial.rst:399 dcb5dc3e6c3a41349a7db5e5052ed2e0\nmsgid \"\"\n\"For example, ``mutool clean -ggggz file.pdf`` yields excellent \"\n\"compression results. It corresponds to ``doc.save(filename, garbage=4, \"\n\"deflate=True)``.\"\nmsgstr \"\"\n\"例えば、 `mutool clean -ggggz file.pdf`  は優れた圧縮結果をもたらします。これは \"\n\"`doc.save(filename, garbage=4, deflate=True)` に対応しています。\"\n\n#: ../../tutorial.rst:402 c79ea0512d3b44e78f142255268af6ac\nmsgid \"Closing\"\nmsgstr \"クローズ\"\n\n#: ../../tutorial.rst:403 f745b8b8cfd64cd0955b6d9c72baa5f3\nmsgid \"\"\n\"It is often desirable to \\\"close\\\" a document to relinquish control of \"\n\"the underlying file to the OS, while your program continues.\"\nmsgstr \"プログラムが継続する間に、基になるファイルの制御をOSに戻すために、ドキュメントを「クローズ」することがしばしば望まれます。\"\n\n#: ../../tutorial.rst:405 6ec44b753b01413a9bcbd6b21a1310d7\nmsgid \"\"\n\"This can be achieved by the :meth:`Document.close` method. Apart from \"\n\"closing the underlying file, buffer areas associated with the document \"\n\"will be freed.\"\nmsgstr \"\"\n\"これは :meth:`Document.close` \"\n\"メソッドによって実現できます。基になるファイルをクローズするだけでなく、ドキュメントに関連するバッファ領域も解放されます。\"\n\n#: ../../tutorial.rst:408 88cb960755d5457da5441939ff0c836d\nmsgid \"Further Reading\"\nmsgstr \"さらなる情報\"\n\n#: ../../tutorial.rst:409 079337447add4588b00679495c0756c6\nmsgid \"\"\n\"Also have a look at PyMuPDF's `Wiki`_ pages. Especially those named in \"\n\"the sidebar under title **\\\"Recipes\\\"** cover over 15 topics written in \"\n\"\\\"How-To\\\" style.\"\nmsgstr \"\"\n\"また、PyMuPDFの `Wiki`_ \"\n\"ページもご覧ください。特に、サイドバーのタイトル「Recipes」の下に名前が挙げられているものは、15以上のトピックが「How-\"\n\"To」スタイルで書かれています。\"\n\n#: ../../tutorial.rst:411 4ff206365d3c46319f8786732294335f\nmsgid \"\"\n\"This document also contains a :ref:`FAQ`. This chapter has close \"\n\"connection to the aforementioned recipes, and it will be extended with \"\n\"more content over time.\"\nmsgstr \":ref:`Recipes: Table of Contents<RecipesTOC>` をご覧ください。\"\n\n#: ../../tutorial.rst:418 8469cb98a4bc46da95e015537403452d\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../tutorial.rst:419 7abfecf3e58542b0859cd575498948f7\nmsgid \"\"\n\"PyMuPDF lets you also open several image file types just like normal \"\n\"documents. See section :ref:`ImageFiles` in chapter :ref:`Pixmap` for \"\n\"more comments.\"\nmsgstr \"\"\n\"PyMuPDFは通常のドキュメントと同様に、いくつかの画像ファイル形式も開くことができます。詳細は、章 :ref:`Pixmap` のセクション \"\n\":ref:`ImageFiles` を参照してください。\"\n\n#: ../../tutorial.rst:421 70b740aad28644b395c85b6a12f20f0e\nmsgid \"\"\n\":meth:`Page.get_text` is a convenience wrapper for several methods of \"\n\"another PyMuPDF class, :ref:`TextPage`. The names of these methods \"\n\"correspond to the argument string passed to :meth:`Page.get_text` \\\\:  \"\n\"*Page.get_text(\\\"dict\\\")* is equivalent to *TextPage.extractDICT()* \\\\.\"\nmsgstr \"\"\n\":meth:`Page.get_text` は、別のPyMuPDFクラス、:ref:`TextPage` \"\n\"のいくつかのメソッドの便利なラッパーです。これらのメソッドの名前は、 :meth:`Page.get_text` \"\n\"に渡された引数文字列に対応しています。例えば、 `Page.get_text(“dict”)`  は  \"\n\"`TextPage.extractDICT()` と同等です。\"\n\n#: ../../tutorial.rst:423 13eddbfd7bd64cd49e523d76972c7368\nmsgid \"\"\n\"\\\"Sequences\\\" are Python objects conforming to the sequence protocol. \"\n\"These objects implement a method named *__getitem__()*. Best known \"\n\"examples are Python tuples and lists. But *array.array*, *numpy.array* \"\n\"and PyMuPDF's \\\"geometry\\\" objects (:ref:`Algebra`) are sequences, too. \"\n\"Refer to :ref:`SequenceTypes` for details.\"\nmsgstr \"\\\"シーケンス\\\"とは、シーケンスプロトコルに準拠したPythonオブジェクトのことを指します。これらのオブジェクトは、getitem()という名前のメソッドを実装しています。よく知られた例としては、Pythonのタプルやリストがあります。しかし、array.array、numpy.array、およびPyMuPDFの「geometry」オブジェクト（幾何オブジェクトのためのオペレーター代数）もシーケンスです。詳細については、「PyMuPDFにおけるPythonシーケンスの引数の使用」を参照してください\"\n\n#: ../../footer.rst:46 34f591e7f8ab491b884b15a32b4f508e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Importing |PyMuPDF| as `fitz` still \"\n#~ \"works however |PyMuPDF| **cannot coexist** \"\n#~ \"with other packages named \\\"fitz\\\" in\"\n#~ \" the same Python environment.\"\n#~ msgstr \"したがって、PyMuPDFは同じPython環境で「fitz」という名前のパッケージと共存することはできません\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/vars.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b5ad9d8dc172425eb69cab3f7d6af3f1\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 469b53fb216c416cab35e3785cb83220\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 3fc4b25efb434bdd9a36d5ea7c1bb7e4\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../vars.rst:5 f49c06cd5a6f4032b8cd339c64a77df1\nmsgid \"Constants and Enumerations\"\nmsgstr \"定数と列挙型\"\n\n#: ../../vars.rst:6 49759909465a4d1794c2b500ea92ef1d\n#, fuzzy\nmsgid \"\"\n\"Constants and enumerations of :title:`MuPDF` as implemented by |PyMuPDF|.\"\n\" Each of the following values is accessible as `pymupdf.value`.\"\nmsgstr \"PyMuPDFによって実装されたMuPDFの定数と列挙型。以下の各変数は、 *pymupdf.variable* としてアクセスできます。\"\n\n#: ../../vars.rst:10 32fc3323ad3f4cdfb477267318e012bc\nmsgid \"Constants\"\nmsgstr \"定数\"\n\n#: ../../vars.rst:14 5b27640ef1ee4e98bea1cf03003160a1\nmsgid \"Predefined Python list of valid :ref:`Base-14-Fonts`.\"\nmsgstr \"PDFベース14フォントの事前定義されたPythonリスト。\"\n\n#: ../../vars.rst 03741e7ad1a44d5299f6572dedaca7b4\n#: 049f7b4ff1974e208b3a904e6026a510 05d7b5730e6142eb96888bc1f1fbcc93\n#: 0651bf5144c1497e884e5c0cc6076c5a 0d7a04755856497fa83f67a8849b2425\n#: 26435fd0d5d24581abb8057002bce4cc 340ebf4c39ec45d4bfe3a768d8345ba6\n#: 4305209c628b41b484db244a821e36a6 441240ad284b456d8fe847ecb191b0f1\n#: 5ba5705e35594ba28d545462f311e0f9 61aa981fd8a346deaaf51a3d4c08d34a\n#: 6ca990f8a13b4358bbabc20892811cc3 771ae51b4e044a81ae255f6c908697fb\n#: 84cd0a4cb52c4fec9fe883c2ad4ace9d 850da1d028064e8191dfa082a3f82827\n#: 8792cce457a84f11b18d64b74d8debc3 8a25036eb68c414abfb7ad4fa62d7229\n#: 92c64e0683614c6c9deb6668c7f4b761 a2004991370a40408515cf83163b6ffb\n#: cdbf08fc2b5b4750b45132b7ec6c2616 d06dea99fa0a4e3cbee4b2b714c43296\n#: f03ecc8098ca4cc181b8356bd7a2bb91 f3646d6d4cee48e0b1af3350ce178eec\n#: f7af32255ccb4f66a37175278b7b7087 fddcade3afa241b8a81b00e45d91f2a4\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../vars.rst:16 669fb77a7bdd4fbcb224507f1b8d7932\nmsgid \"list\"\nmsgstr \"\"\n\n#: ../../vars.rst:20 b3ae8b9f4f43444aa8fdc74de25f17f0\nmsgid \"Predefined RGB colorspace *pymupdf.Colorspace(pymupdf.CS_RGB)*.\"\nmsgstr \"事前定義されたRGBカラースペース *pymupdf.Colorspace(pymupdf.CS_RGB)*。\"\n\n#: ../../vars.rst:22 ../../vars.rst:28 ../../vars.rst:34\n#: 19f89992935a4f8e839adc1511263368 204d25d273a7452cb5ba5e71b6869076\n#: 79e2265294cd409f800e1e4a446e2ccf\nmsgid \":ref:`Colorspace`\"\nmsgstr \":ref:`Colorspace`\"\n\n#: ../../vars.rst:26 6a13d5103eb54565bf88415ab0ddc8c5\nmsgid \"Predefined GRAY colorspace *pymupdf.Colorspace(pymupdf.CS_GRAY)*.\"\nmsgstr \"事前定義されたGRAYカラースペース *pymupdf.Colorspace(pymupdf.CS_GRAY)*。\"\n\n#: ../../vars.rst:32 7321e72d393e42a3b735759e78d1800e\nmsgid \"Predefined CMYK colorspace *pymupdf.Colorspace(pymupdf.CS_CMYK)*.\"\nmsgstr \"事前定義されたCMYKカラースペース *pymupdf.Colorspace(pymupdf.CS_CMYK)*。\"\n\n#: ../../vars.rst:38 69ab2345dd374ad1873f76d16292717c\nmsgid \"1 -- Type of :ref:`Colorspace` is RGBA\"\nmsgstr \"1 – :ref:`Colorspace` のタイプはRGBA\"\n\n#: ../../vars.rst:40 ../../vars.rst:46 ../../vars.rst:52 ../../vars.rst:324\n#: ../../vars.rst:330 ../../vars.rst:339 ../../vars.rst:348 ../../vars.rst:354\n#: ../../vars.rst:360 015aafcf193f4fd986c01b2543bb2157\n#: 0a5dae970bce40d4a3ef066a7b52120d 648ca70552324683a3f2d83756f7f850\n#: 9b976dcffb04497a9119e83b6b78aab2 ab0b93519cea4419af8c90b1cc9d3a36\n#: b6975d022fb6464bb4f18e4ee6bd73fa c2c115fb5ad14e8da9970160f490f151\n#: c3202da1e321403b976247fc2a19756a d3d462436758488a8dab6f328e27425e\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../vars.rst:44 23b50446130242d885968a5027985060\nmsgid \"2 -- Type of :ref:`Colorspace` is GRAY\"\nmsgstr \"2 – :ref:`Colorspace` のタイプはGRAY\"\n\n#: ../../vars.rst:50 9cf5e34e2e83453799d96f7be872aa7b\nmsgid \"3 -- Type of :ref:`Colorspace` is CMYK\"\nmsgstr \"3 – :ref:`Colorspace` のタイプはCMYK\"\n\n#: ../../vars.rst:56 22d14edcfed74d6ba68f180a5162d3bc\nmsgid \"'x.xx.x' -- MuPDF version that is being used by PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../vars.rst:58 ../../vars.rst:70 24ffecb2a7de45fbbce9cac71b9ad2c2\n#: 4162b0bbb82145f5863294fee9b84fcb\nmsgid \"string\"\nmsgstr \"\"\n\n#: ../../vars.rst:62 22fa0f6343d143a783918bf5d77c0101\nmsgid \"MuPDF version as a tuple of integers, `(major, minor, patch)`.\"\nmsgstr \"\"\n\n#: ../../vars.rst:64 ../../vars.rst:76 ../../vars.rst:86\n#: 2f0bacf105574469a7a2f46854047382 ad5b78a4130443e0b9cb7a3e7209521d\n#: d8a2a6e3dcc44d9a96a1324281332fc4\nmsgid \"tuple\"\nmsgstr \"\"\n\n#: ../../vars.rst:68 44158f3deff845c6a420df354f39c1ae\n#, fuzzy\nmsgid \"'x.xx.x' -- PyMuPDF version.\"\nmsgstr \"‘x.xxx’ – MuPDFのバージョン\"\n\n#: ../../vars.rst:74 503076c6013f48dea2d5aff3c0bfffe3\nmsgid \"PyMuPDF version as a tuple of integers, `(major, minor, patch)`.\"\nmsgstr \"\"\n\n#: ../../vars.rst:80 ../../vars.rst:98 60b862b7a373462c8b0819e549788e84\n#: c79955e7841e4b48a637775a61cfbd69\nmsgid \"Disabled (set to None) in 1.26.1.\"\nmsgstr \"\"\n\n#: ../../vars.rst:84 fff27c04ee62442897c643c5bfb60fd8\n#, fuzzy\nmsgid \"\"\n\"(pymupdf_version, mupdf_version, timestamp) -- combined version \"\n\"information where `timestamp` is the generation point in time formatted \"\n\"as \\\"YYYYMMDDhhmmss\\\".\"\nmsgstr \"\"\n\"(VersionBind、VersionFitz、タイムスタンプ) – \"\n\"タイムスタンプは「YYYYMMDDhhmmss」という形式で表される、生成時点の時間情報を結合したバージョン情報。\"\n\n#: ../../vars.rst:90 4fbbccb8f9024a63a332534e6a7d0d2e\nmsgid \"Legacy equivalent to `mupdf_version`.\"\nmsgstr \"\"\n\n#: ../../vars.rst:94 24f0ff9e8cf44c5fba17fe9c4bd63d7f\nmsgid \"Legacy equivalent to `pymupdf_version`.\"\nmsgstr \"\"\n\n#: ../../vars.rst:104 4dce9933f18a45198a4633f8fefe9d07\nmsgid \"Document Permissions\"\nmsgstr \"ドキュメントの許可\"\n\n#: ../../vars.rst:107 ../../vars.rst:125 ../../vars.rst:138\n#: 69c0225036764f13b91eaa9dd3d4b5a1 8e2f223c79664413ba8ac6afd092c3fa\n#: a0a9b218a32347e18401eec3e71b51c6\nmsgid \"Code\"\nmsgstr \"コード\"\n\n#: ../../vars.rst:107 c680e8bb0a64489fbe38ff0350dae277\nmsgid \"Permitted Action\"\nmsgstr \"許可されたアクション\"\n\n#: ../../vars.rst:109 a79221d078824de999e2f0ccf27939da\nmsgid \"PDF_PERM_PRINT\"\nmsgstr \"\"\n\n#: ../../vars.rst:109 634b2c786f6946a99a89687ae863c63d\nmsgid \"Print the document\"\nmsgstr \"文書を印刷する\"\n\n#: ../../vars.rst:110 488e117f6ad841e4b5ebe9ca302ecd70\nmsgid \"PDF_PERM_MODIFY\"\nmsgstr \"\"\n\n#: ../../vars.rst:110 a868ac82b5084146a37a1633ab518c6c\nmsgid \"Modify the document's contents\"\nmsgstr \"文書の内容を変更する\"\n\n#: ../../vars.rst:111 18ef7dd19b374b5ebfdb3cec757c73ac\nmsgid \"PDF_PERM_COPY\"\nmsgstr \"\"\n\n#: ../../vars.rst:111 8f52d72b641b40d285393c8d0bdf12b3\nmsgid \"Copy or otherwise extract text and graphics\"\nmsgstr \"テキストやグラフィックスをコピーしたりその他の抽出を行う\"\n\n#: ../../vars.rst:112 9e025ab3d4f741e2a325152bc6f8a701\nmsgid \"PDF_PERM_ANNOTATE\"\nmsgstr \"\"\n\n#: ../../vars.rst:112 cb0beab224b94270bdabfc3bd1ceacc6\nmsgid \"Add or modify text annotations and interactive form fields\"\nmsgstr \"テキスト注釈やインタラクティブなフォームフィールドを追加または変更する\"\n\n#: ../../vars.rst:113 65f9a8539a38426e9d9edea861734d4d\nmsgid \"PDF_PERM_FORM\"\nmsgstr \"\"\n\n#: ../../vars.rst:113 9880c191956741d1ada6315e712e1df3\nmsgid \"Fill in forms and sign the document\"\nmsgstr \"フォームに記入し、文書に署名する\"\n\n#: ../../vars.rst:114 419137e25c424c91876fed826c5a5bb0\nmsgid \"PDF_PERM_ACCESSIBILITY\"\nmsgstr \"\"\n\n#: ../../vars.rst:114 c90f5be96ba842199ff198fe845a93a8\nmsgid \"Obsolete, always permitted\"\nmsgstr \"廃止されましたが、常に許可されています\"\n\n#: ../../vars.rst:115 2ac0ea137a68490a808035fe357a1eb5\nmsgid \"PDF_PERM_ASSEMBLE\"\nmsgstr \"\"\n\n#: ../../vars.rst:115 ee21ef3d77b543aa83b85d5966fa800c\nmsgid \"Insert, rotate, or delete pages, bookmarks, thumbnail images\"\nmsgstr \"ページの挿入、回転、削除、ブックマーク、サムネイル画像の操作\"\n\n#: ../../vars.rst:116 12f225fa0c204cecae58e07d185ee517\nmsgid \"PDF_PERM_PRINT_HQ\"\nmsgstr \"\"\n\n#: ../../vars.rst:116 40cb4480233843f686a1bb405c551ad8\nmsgid \"High quality printing\"\nmsgstr \"高品質印刷\"\n\n#: ../../vars.rst:122 c7730f8c05a4440dabe25baa7a267683\nmsgid \"PDF Optional Content Codes\"\nmsgstr \"PDFオプショナルコンテンツコード\"\n\n#: ../../vars.rst:125 ../../vars.rst:138 063e2ffd14154f0ebe27a414e68d96c6\n#: fe257d4a0ce0417dba5855c9020e0ca1\nmsgid \"Meaning\"\nmsgstr \"意味\"\n\n#: ../../vars.rst:127 fe2012971224466ea97a0fb2a812c5d5\nmsgid \"PDF_OC_ON\"\nmsgstr \"\"\n\n#: ../../vars.rst:127 420c6f19787341418e8a584a6befd890\nmsgid \"Set an OCG to ON temporarily\"\nmsgstr \"一時的にOCGをONに設定します\"\n\n#: ../../vars.rst:128 2c29aec5886a45cfae0e991402caad13\nmsgid \"PDF_OC_TOGGLE\"\nmsgstr \"\"\n\n#: ../../vars.rst:128 a7ebc40cd09c47a3867c2d73be2fdc36\nmsgid \"Toggle OCG status temporarily\"\nmsgstr \"OCGステータスを一時的に切り替えます\"\n\n#: ../../vars.rst:129 4b06b1f6475a41cb8d448d28fbf5dd24\nmsgid \"PDF_OC_OFF\"\nmsgstr \"\"\n\n#: ../../vars.rst:129 8a6a1199c65a44ba85224f9de436969f\nmsgid \"Set an OCG to OFF temporarily\"\nmsgstr \"一時的にOCGをOFFに設定します\"\n\n#: ../../vars.rst:135 2b7b50430a24457fafc7cd3943e62be7\nmsgid \"PDF encryption method codes\"\nmsgstr \"PDF暗号化方式コード\"\n\n#: ../../vars.rst:140 a3c958105b9a4e8db59f50cb6ab72b3f\nmsgid \"PDF_ENCRYPT_KEEP\"\nmsgstr \"\"\n\n#: ../../vars.rst:140 30102a9f273a4422a20bf1aa06b451e6\nmsgid \"do not change\"\nmsgstr \"変更しない\"\n\n#: ../../vars.rst:141 57fd2541dc9c472e9d50b26ef7cd6daf\nmsgid \"PDF_ENCRYPT_NONE\"\nmsgstr \"\"\n\n#: ../../vars.rst:141 49f9186cb5ae45cd9064cb575b6d5385\nmsgid \"remove any encryption\"\nmsgstr \"暗号化を解除する\"\n\n#: ../../vars.rst:142 49fe127596b048f4a7ea339156fdf19d\nmsgid \"PDF_ENCRYPT_RC4_40\"\nmsgstr \"\"\n\n#: ../../vars.rst:142 5e3374e98bdc43a199f2fd85dcc18580\nmsgid \"RC4 40 bit\"\nmsgstr \"RC4 40ビット\"\n\n#: ../../vars.rst:143 178727ee434846ad808cce5a8aaad74f\nmsgid \"PDF_ENCRYPT_RC4_128\"\nmsgstr \"\"\n\n#: ../../vars.rst:143 a3c8b50a7af8456a966bcd7de122f754\nmsgid \"RC4 128 bit\"\nmsgstr \"RC4 128ビット\"\n\n#: ../../vars.rst:144 1ccff559acbb47a8a81bae717b32c4c8\nmsgid \"PDF_ENCRYPT_AES_128\"\nmsgstr \"\"\n\n#: ../../vars.rst:144 d1fdccc17e4348788f55154c73a66ddd\nmsgid \"*Advanced Encryption Standard* 128 bit\"\nmsgstr \"*Advanced Encryption Standard* 128ビット\"\n\n#: ../../vars.rst:145 6052a9f31b7f4ec0b078312655adc0d5\nmsgid \"PDF_ENCRYPT_AES_256\"\nmsgstr \"\"\n\n#: ../../vars.rst:145 14eb7ccec2184fbbb74c67eb54aeaa93\nmsgid \"*Advanced Encryption Standard* 256 bit\"\nmsgstr \"*Advanced Encryption Standard* 256ビット\"\n\n#: ../../vars.rst:146 0e8a697210064a68a4acb78e4798c066\nmsgid \"PDF_ENCRYPT_UNKNOWN\"\nmsgstr \"\"\n\n#: ../../vars.rst:146 c4ff9f33d8bf406baac59afdedce3393\nmsgid \"unknown\"\nmsgstr \"不明\"\n\n#: ../../vars.rst:152 41ce5d42a96641298f59e62ca328c3ad\nmsgid \"Font File Extensions\"\nmsgstr \"フォントファイルの拡張子\"\n\n#: ../../vars.rst:153 a5aa4b1442b84096a3364986edc00478\nmsgid \"\"\n\"The table show file extensions you should use when saving fontfile \"\n\"buffers extracted from a PDF. This string is returned by \"\n\":meth:`Document.get_page_fonts`, :meth:`Page.get_fonts` and \"\n\":meth:`Document.extract_font`.\"\nmsgstr \"\"\n\"このテーブルは、PDFから抽出されたフォントファイルバッファを保存する際に使用すべきファイル拡張子を示しています。この文字列は、:meth:`Document.get_page_fonts`、:meth:`Page.get_fonts`、および\"\n\" :meth:`Document.extract_font` によって返されます。\"\n\n#: ../../vars.rst:156 0052347b09ef46dd84c581597bacb35f\nmsgid \"Ext\"\nmsgstr \"拡張子\"\n\n#: ../../vars.rst:156 2d2cd27d463f4ff0997dae7caa6b83b6\nmsgid \"Description\"\nmsgstr \"説明\"\n\n#: ../../vars.rst:158 112b17f0de1840a08e0864ed1e9fad0c\nmsgid \"ttf\"\nmsgstr \"\"\n\n#: ../../vars.rst:158 0cb8088360d7427baefcf5281b49766b\nmsgid \"TrueType font\"\nmsgstr \"TrueTypeフォント\"\n\n#: ../../vars.rst:159 c2a6b6d61d0e40d583db103da173e32f\nmsgid \"pfa\"\nmsgstr \"\"\n\n#: ../../vars.rst:159 5a1d03107af64f5981ab318e0360c9af\nmsgid \"Postscript for ASCII font (various subtypes)\"\nmsgstr \"ASCII用のPostscriptフォント（さまざまなサブタイプ）\"\n\n#: ../../vars.rst:160 86be9bafc4174236b68e13a9dac7e5c8\nmsgid \"cff\"\nmsgstr \"\"\n\n#: ../../vars.rst:160 8675d363e0c9499ab403a49e9cda22a1\nmsgid \"Type1C font (compressed font equivalent to Type1)\"\nmsgstr \"Type1Cフォント（Type1と同等の圧縮フォント）\"\n\n#: ../../vars.rst:161 4c60a1421ea7458e81092448bae7a1d8\nmsgid \"cid\"\nmsgstr \"\"\n\n#: ../../vars.rst:161 cf49f17f14d346f89b4ace2ba62a022f\nmsgid \"character identifier font (postscript format)\"\nmsgstr \"文字識別子フォント（Postscript形式）\"\n\n#: ../../vars.rst:162 fc39dc6369a74d13baa2932ca54039b7\nmsgid \"otf\"\nmsgstr \"\"\n\n#: ../../vars.rst:162 e6d68a78565e4efdbdabf3ad08977b53\nmsgid \"OpenType font\"\nmsgstr \"OpenTypeフォント\"\n\n#: ../../vars.rst:163 b7864b379d2a4c898a5538edf898a0a6\nmsgid \"n/a\"\nmsgstr \"\"\n\n#: ../../vars.rst:163 d276c42e480048c98e84446e521418fb\nmsgid \"not extractable, e.g. :ref:`Base-14-Fonts`, Type 3 fonts and others\"\nmsgstr \"抽出できない、 :ref:`PDFベース14フォント <Base-14-Fonts>`  、Type 3フォント、その他\"\n\n#: ../../vars.rst:169 30a554d8b43e4399ac3db70eb4861a79\nmsgid \"Text Alignment\"\nmsgstr \"テキストの配置\"\n\n#: ../../vars.rst:172 c285bb937c45411c9e8428e8cbc6d5ce\nmsgid \"0 -- align left.\"\nmsgstr \"0 – 左揃え。\"\n\n#: ../../vars.rst:176 f6c2ead9ebb844e2a50572a57dbf9a86\nmsgid \"1 -- align center.\"\nmsgstr \"1 – 中央揃え。\"\n\n#: ../../vars.rst:180 8e82db4889224a20909e002199177be8\nmsgid \"2 -- align right.\"\nmsgstr \"2 – 右揃え。\"\n\n#: ../../vars.rst:184 75af6aadfef54289894f0d114de9eeae\nmsgid \"3 -- align justify.\"\nmsgstr \"3 – 両端揃え。\"\n\n#: ../../vars.rst:191 cf47b8894ae04d868274979275d334ee\nmsgid \"Font Properties\"\nmsgstr \"\"\n\n#: ../../vars.rst:192 5c56a8ed6d794191b089c5b738da3cf9\nmsgid \"\"\n\"Please note that the following bits are derived from what a font has to \"\n\"say about its properties. It may not be (and quite often is not) correct.\"\nmsgstr \"\"\n\n#: ../../vars.rst:196 d8f06c39601c4b96bd13ea9e078c40ce\nmsgid \"\"\n\"1 -- the character or span is a superscript. This property is computed by\"\n\" MuPDF and not part of any font information.\"\nmsgstr \"\"\n\n#: ../../vars.rst:200 d21771d5f06e4862a5dc0a350e8a4def\nmsgid \"2 -- the font is italic.\"\nmsgstr \"\"\n\n#: ../../vars.rst:204 c25bebd41297409da31265769924b7c0\nmsgid \"4 -- the font is serifed.\"\nmsgstr \"\"\n\n#: ../../vars.rst:208 b4a15a033d644c66b6b71cd52bef75b0\nmsgid \"8 -- the font is mono-spaced.\"\nmsgstr \"\"\n\n#: ../../vars.rst:212 fd8f231700104de8a26b9fa17f57dca6\nmsgid \"16 -- the font is bold.\"\nmsgstr \"\"\n\n#: ../../vars.rst:215 ae7fc7375fe24bcab9635e7ecaf45788\nmsgid \"Text Extraction Flags\"\nmsgstr \"テキスト抽出フラグ\"\n\n#: ../../vars.rst:216 b53381821bdc40c69b532bc7e53092be\n#, fuzzy\nmsgid \"\"\n\"Option bits controlling the amount of data, that are parsed into a \"\n\":ref:`TextPage`.\"\nmsgstr \":ref:`TextPage` に解析されるデータの量を制御するオプションビット - このクラスは、主にPyMuPDF内部でのみ使用されます。\"\n\n#: ../../vars.rst:218 4e0693fb1e8f4c7e991b270de3d35b6c\n#, fuzzy\nmsgid \"\"\n\"For the PyMuPDF programmer, some combination (using Python's `|` \"\n\"operator, or simply use `+`) of these values are aggregated in the \"\n\"``flags`` integer, a parameter of all text search and text extraction \"\n\"methods. Depending on the individual method, different default \"\n\"combinations of the values are used. Please use a value that meets your \"\n\"situation. Especially make sure to switch off image extraction unless you\"\n\" really need them. The impact on performance and memory is significant!\"\nmsgstr \"\"\n\"PyMuPDFプログラマーにとって、これらの値のいくつかの組み合わせ（Pythonの`|`演算子を使用するか、単純に`+`を使用する）が、すべてのテキスト検索およびテキスト抽出メソッドのパラメータである\"\n\" `flags` \"\n\"整数に集約されます。個々のメソッドによっては、異なる値のデフォルトの組み合わせが使用されます。ご自身の状況に合った値を使用してください。特に、必要がない限り画像抽出をオフにしてください。パフォーマンスとメモリに対する影響が大きいです！\"\n\n#: ../../vars.rst:222 e2a36dbf69d04d888507fc509ee2b720\nmsgid \"\"\n\"1 -- If set, ligatures are passed through to the application in their \"\n\"original form. Otherwise ligatures are expanded into their constituent \"\n\"parts, e.g. the ligature \\\"ffi\\\" is expanded into three  eparate \"\n\"characters f, f and i. Default is \\\"on\\\" in PyMuPDF. MuPDF supports the \"\n\"following 7 ligatures: \\\"ff\\\", \\\"fi\\\", \\\"fl\\\", \\\"ffi\\\", \\\"ffl\\\", , \"\n\"\\\"ft\\\", \\\"st\\\".\"\nmsgstr \"\"\n\"1 – \"\n\"設定されている場合、リガチャは元の形式のままアプリケーションに渡されます。それ以外の場合、リガチャは構成要素に展開されます。例：リガチャ「ffi」は、3つの個別の文字\"\n\" f、f、および i \"\n\"に展開されます。デフォルトはPyMuPDFで「オン」です。MuPDFは以下の7つのリガチャに対応しています：\\\"ff\\\"、\\\"fi\\\"、\\\"fl\\\"、\\\"ffi\\\"、\\\"ffl\\\"、\\\"ft\\\"、\\\"st\\\"。\"\n\n#: ../../vars.rst:226 03ceff6db720488f91e124b08d5a1e41\nmsgid \"\"\n\"2 -- If set, whitespace is passed through. Otherwise any type of \"\n\"horizontal whitespace (including horizontal tabs) will be replaced with \"\n\"space characters of variable width. Default is \\\"on\\\" in PyMuPDF.\"\nmsgstr \"\"\n\"2 – \"\n\"設定されている場合、空白はそのまま渡されます。それ以外の場合、水平空白（水平タブを含む）のいずれかのタイプは可変幅のスペース文字に置き換えられます。デフォルトはPyMuPDFで「オン」です。\"\n\n#: ../../vars.rst:230 cf99390225b04a8996e5580bd96fe830\nmsgid \"\"\n\"4 -- If set, then images will be stored in the :ref:`TextPage`. This \"\n\"causes the presence of (usually large!) binary image content in the \"\n\"output of text extractions of types \\\"blocks\\\", \\\"dict\\\", \\\"json\\\", \"\n\"\\\"rawdict\\\", \\\"rawjson\\\", \\\"html\\\", and \\\"xhtml\\\" and is the default \"\n\"there. If used with \\\"blocks\\\" however, only image metadata will be \"\n\"returned, not the image itself.\"\nmsgstr \"\"\n\"4 – 設定されている場合、画像は :ref:`TextPage` \"\n\"に保存されます。これにより、テキスト抽出の出力に（通常は大きな）バイナリ画像コンテンツが含まれることになります。ただし、これはタイプ「blocks」、「dict」、「json」、「rawdict」、「rawjson」、「html」、および「xhtml」のテキスト抽出にのみ適用され、デフォルトです。ただし、「blocks」とともに使用される場合、画像メタデータのみが返され、画像自体は返されません。\"\n\n#: ../../vars.rst:234 2681e56367fe46aa936b2b5870294639\nmsgid \"\"\n\"8 -- If set, Mupdf will not try to add missing space characters where \"\n\"there are large gaps between characters. In PDF, the creator often does \"\n\"not insert spaces to point to the next character's position, but will \"\n\"provide the direct location address. The default in PyMuPDF is \\\"off\\\" --\"\n\" so spaces **will be generated**.\"\nmsgstr \"\"\n\"8 – \"\n\"設定されている場合、Mupdfは文字間の大きな間隔に欠落したスペース文字を追加しようとしません。PDFでは、作成者はしばしば次の文字の位置を指し示すためにスペースを挿入しませんが、直接の場所のアドレスを提供します。PyMuPDFのデフォルトは「オフ」です\"\n\" - したがって、スペースが生成されます。\"\n\n#: ../../vars.rst:238 cb25cbf3acb74d84824fa410aed54abd\nmsgid \"\"\n\"16 -- Ignore hyphens at line ends and join with next line. Used \"\n\"internally with the text search functions. However, it is generally \"\n\"available: if on, text extractions will return joined text lines (or \"\n\"spans) with the ending hyphen of the first line eliminated. So two \"\n\"separate spans **\\\"first meth-\\\"** and **\\\"od leads to wrong results\\\"** \"\n\"on different lines will be joined to one span **\\\"first method leads to \"\n\"wrong results\\\"** and correspondingly updated bboxes: the characters of \"\n\"the resulting span will no longer have identical y-coordinates.\"\nmsgstr \"\"\n\"16 – \"\n\"行末のハイフンを無視し、次の行に結合します。テキスト検索関数と内部で使用されます。ただし、一般的に使用できます。ONの場合、テキスト抽出は結合されたテキスト行（またはスパン）を返します。最初の行のハイフンが除去されます。異なる行にある「first\"\n\" meth-」と「od leads to wrong results」の2つの個別のスパンが「first method leads to \"\n\"wrong \"\n\"results」として結合され、それに応じて更新されたバウンディングボックス（bbox）：結果のスパンの文字はもはや同じy座標を持ちません。\"\n\n#: ../../vars.rst:242 19c2601d343547ba88a56aac0f0c8ff5\nmsgid \"\"\n\"32 -- Generate a new line for every span. Not used (\\\"off\\\") in PyMuPDF, \"\n\"but available for your use. Every line in \\\"dict\\\", \\\"json\\\", \"\n\"\\\"rawdict\\\", \\\"rawjson\\\" will contain exactly one span.\"\nmsgstr \"\"\n\"32 – \"\n\"各スパンに対して新しい行を生成します。PyMuPDFでは使用されませんが（オフです）、使用可能です。\\\"dict\\\"、\\\"json\\\"、\\\"rawdict\\\"、\\\"rawjson\\\"の各行には正確に1つのスパンが含まれます。\"\n\n#: ../../vars.rst:246 87e941b789f8436e998a2f3801575756\n#, fuzzy\nmsgid \"\"\n\"64 -- Characters entirely outside a page's **mediabox** or contained in \"\n\"other \\\"clipped\\\" areas will be ignored. This is default in PyMuPDF.\"\nmsgstr \"64 – ページのメディアボックス外にある文字は無視されます。これはPyMuPDFのデフォルトです。\"\n\n#: ../../vars.rst:250 befbc341b1674e348a9396c99be1ac8a\nmsgid \"\"\n\"128 -- Use raw character codes instead of U+FFFD. This is the default for\"\n\" **text extraction** in PyMuPDF. If you **want to detect** when encoding \"\n\"information is missing or uncertain, toggle this flag and scan for the \"\n\"presence of U+FFFD (= `chr(0xfffd)`) code points in the resulting text.\"\nmsgstr \"\"\n\n#: ../../vars.rst:254 328eded5e21c495986514848f3acd090\nmsgid \"256 -- Not supported.\"\nmsgstr \"\"\n\n#: ../../vars.rst:258 c2468f6ee1364a9aacd5178c2e2e1f03\nmsgid \"\"\n\"512 -- Ignore metric values of all fonts when computing character \"\n\"boundary boxes -- most prominently the `ascender \"\n\"<https://en.wikipedia.org/wiki/Ascender_(typography)>`_ and `descender \"\n\"<https://en.wikipedia.org/wiki/Descender>`_ values. Instead, follow the \"\n\"drawing commands of each character's glyph and compute its rectangle \"\n\"hull. This is the smallest rectangle wrapping all points used for drawing\"\n\" the visual appearance - see the :ref:`Shape` class for understanding the\"\n\" background. This will especially result in individual character heights.\"\n\" For instance a (white) space will have a **bbox of height 0** (because \"\n\"nothing is drawn) -- in contrast to the non-zero boundary box generated \"\n\"when using font metrics. This option may be useful to cope with getting \"\n\"meaningful boundary boxes even for fonts containing errors. Its use will \"\n\"slow down text extraction somewhat because of the incurred computational \"\n\"effort.\"\nmsgstr \"\"\n\n#: ../../vars.rst:260 0d005cfd39294c549dcb076c7db6a438\nmsgid \"\"\n\"Note that this has no effect by default - one must also disable the \"\n\"global quad corrections setting with \"\n\"`pymupdf.TOOLS.unset_quad_corrections(True)`.\"\nmsgstr \"\"\n\n#: ../../vars.rst:265 26addbea02e84233b6230ff416c3f839\nmsgid \"1024 -- Not supported.\"\nmsgstr \"\"\n\n#: ../../vars.rst:269 71ca80b7b9a0453f96fbe2509cc882f8\nmsgid \"\"\n\"2048 -- Ignore built-in differences between text appearing in e.g. PDF \"\n\"viewers versus text stored in the PDF. See :ref:`AdobeManual`, page 615 \"\n\"for background. If set, the **stored** (\\\"replacement\\\" text) is ignored \"\n\"in favor of the displayed text.\"\nmsgstr \"\"\n\n#: ../../vars.rst:273 a2280aa3922d45a0b01eec12d3b1828e\nmsgid \"4096 -- Attempt to segment page into different regions.\"\nmsgstr \"\"\n\n#: ../../vars.rst:275 6055e0ec2f2640a4a69c769d60051dd1\nmsgid \"\"\n\"The following constants represent the default combinations of the above \"\n\"for text extraction and searching:\"\nmsgstr \"以下の定数は、テキスト抽出と検索のための上記のデフォルトの組み合わせを表します：\"\n\n#: ../../vars.rst:279 ../../vars.rst:283 ../../vars.rst:287 ../../vars.rst:307\n#: 18445061c2274e3094f8e223b2f97d8b 4848e850ecdd4b71ae9e0fe4bd1bd2ab\n#: 7e1253a470a94b4bad14d5086ec64c03 b78142b94eed4f5ca84f11c2fef8b074\nmsgid \"\"\n\"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP \"\n\"| TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\"\nmsgstr \"\"\n\n#: ../../vars.rst:291 ../../vars.rst:295 ../../vars.rst:299 ../../vars.rst:303\n#: 1cef0274d54745cead1031d1bca2799f 2fbf2a5e26ee49eb868428bcbb529499\n#: 9fdd1b123b4e4f2fa9c013d23a2b966c ffe8940542984cda9c70ce1c925581dc\nmsgid \"\"\n\"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP \"\n\"| TEXT_PRESERVE_IMAGES | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\"\nmsgstr \"\"\n\n#: ../../vars.rst:311 bb90ee72173049c7a370c67ba9105b23\nmsgid \"`TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_DEHYPHENATE`\"\nmsgstr \"\"\n\n#: ../../vars.rst:317 f588bfe5d7214e09848d2ea66fc226e0\nmsgid \"Link Destination Kinds\"\nmsgstr \"リンクの目的の種類\"\n\n#: ../../vars.rst:318 25e6f87b871146ab8c9d29979584f4b3\nmsgid \"Possible values of :attr:`linkDest.kind` (link destination kind).\"\nmsgstr \":attr:`linkDest.kind` （リンクの目的の種類）の可能な値。\"\n\n#: ../../vars.rst:322 93386ed82cc246f889866c47a3647e09\nmsgid \"0 -- No destination. Indicates a dummy link.\"\nmsgstr \"0 – 目的地なし。ダミーリンクを示します。\"\n\n#: ../../vars.rst:328 55d8c4d1bc6e4ff7896e13f3fcbbfa74\nmsgid \"1 -- Points to a place in this document.\"\nmsgstr \"1 – このドキュメント内の場所を指します。\"\n\n#: ../../vars.rst:334 17fd7d0b788140929657b02c096290f0\nmsgid \"\"\n\"2 -- Points to a URI -- typically a resource specified with internet \"\n\"syntax.\"\nmsgstr \"2 – URIを指します。通常はインターネット構文で指定されたリソースです。\"\n\n#: ../../vars.rst:336 c2c977e93a6b466686c3ec774112b806\nmsgid \"\"\n\"PyMuPDF treats any external link that contains a colon and does not start\"\n\" with `file:`, as `LINK_URI`.\"\nmsgstr \"PyMuPDFは、コロンを含み、`file:` で始まらない任意の外部リンクを `LINK_URI` として扱います。\"\n\n#: ../../vars.rst:343 f2f74244f1ff419e9d052ead3e767a51\nmsgid \"3 -- Launch (open) another file (of any \\\"executable\\\" type).\"\nmsgstr \"3 – 別のファイル（任意の「実行可能」タイプ）を開きます。\"\n\n#: ../../vars.rst:345 80fd06d08b3a4bbd91c5550c158e44a4\nmsgid \"\"\n\"|PyMuPDF| treats any external link that starts with `file:` or doesn't \"\n\"contain a colon, as `LINK_LAUNCH`.\"\nmsgstr \"PyMuPDFは、 `file:`  で始まるかコロンを含まない外部リンクを `LINK_LAUNCH` として扱います。\"\n\n#: ../../vars.rst:352 953c280a5a2c4081b49b4428360d0b70\nmsgid \"4 -- points to a named location.\"\nmsgstr \"4 – 名前付きの場所を指します。\"\n\n#: ../../vars.rst:358 c2dd6d723df94a729c602ab39198e6e3\nmsgid \"5 -- Points to a place in another PDF document.\"\nmsgstr \"5 – 別のPDFドキュメント内の場所を指します。\"\n\n#: ../../vars.rst:365 13d9db49dc764ad2943a0bd89bf1eccd\nmsgid \"Link Destination Flags\"\nmsgstr \"リンクの目的地フラグ\"\n\n#: ../../vars.rst:367 d3b19de8c19a4cca93ae0614069136aa\nmsgid \"\"\n\"The rightmost byte of this integer is a bit field, so test the truth of \"\n\"these bits with the *&* operator.\"\nmsgstr \"この整数の最も右側のバイトはビットフィールドです。したがって、これらのビットの真偽を *＆* 演算子でテストします。\"\n\n#: ../../vars.rst:371 adfb385a3f204afa96eae840376cfaaf\nmsgid \"1  (bit 0) Top left x value is valid\"\nmsgstr \"1 (ビット 0) 左上の x 値が有効です\"\n\n#: ../../vars.rst:373 ../../vars.rst:379 ../../vars.rst:385 ../../vars.rst:391\n#: ../../vars.rst:397 ../../vars.rst:403 ../../vars.rst:409\n#: 45d5d66079ad4119a37daf32345170ea 68ec9fd7a3194726abc3dd123922506c\n#: 802dc57d84e340dda07eb08e1fa533ea a78880c24f194e0183ba7acb53112b5c\n#: b54e07447ebd48d08adcaa6c2330efd7 cc044f3983144e34b9ec5e221c661f84\n#: de33e1ca908e4329acf8e771d8062395\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../vars.rst:377 f6bb945288e84c2ea7af6535127f5686\nmsgid \"2  (bit 1) Top left y value is valid\"\nmsgstr \"2 (ビット 1) 左上の y 値が有効です\"\n\n#: ../../vars.rst:383 1429f391f08e4098bf3648e649655ce7\nmsgid \"4  (bit 2) Bottom right x value is valid\"\nmsgstr \"4 (ビット 2) 右下の x 値が有効です\"\n\n#: ../../vars.rst:389 dd2f2b2b41774030b5c2a8b95d745273\nmsgid \"8  (bit 3) Bottom right y value is valid\"\nmsgstr \"8 (ビット 3) 右下の y 値が有効です\"\n\n#: ../../vars.rst:395 62df816d97ee45ccab57344fe8d25a10\nmsgid \"16 (bit 4) Horizontal fit\"\nmsgstr \"16 (ビット 4) 水平フィット\"\n\n#: ../../vars.rst:401 78e6492677c146c4a8d9bf5ea9d48be1\nmsgid \"32 (bit 5) Vertical fit\"\nmsgstr \"32 (ビット 5) 垂直フィット\"\n\n#: ../../vars.rst:407 40d05c050d174b918e1b5d3b4e8d4671\nmsgid \"64 (bit 6) Bottom right x is a zoom figure\"\nmsgstr \"64 (ビット 6) 右下の x はズーム値です\"\n\n#: ../../vars.rst:413 136d76a8f9eb46c88e7d3a181650da73\nmsgid \"Annotation Related Constants\"\nmsgstr \"注釈関連の定数\"\n\n#: ../../vars.rst:414 0afb6c758143449fb56a0b04ab704888\nmsgid \"See chapter 8.4.5, pp. 615 of the :ref:`AdobeManual` for details.\"\nmsgstr \"詳細については、:ref:`Adobe PDFリファレンス <AdobeManual>` の第8.4.5章、615ページをご覧ください。\"\n\n#: ../../vars.rst:419 c080cb77d13c409a8faecbcbd760910c\nmsgid \"Annotation Types\"\nmsgstr \"アノテーションタイプ\"\n\n#: ../../vars.rst:420 d20a798f8f554b5d8529e31b8816197f\nmsgid \"\"\n\"These identifiers also cover **links** and **widgets**: the PDF \"\n\"specification technically handles them all in the same way, whereas \"\n\"|MuPDF| (and PyMuPDF) treats them as three basically different types of \"\n\"objects.\"\nmsgstr \"\"\n\"これらの識別子は **リンク** と **ウィジェット** \"\n\"も含みます。PDF仕様では、技術的にはこれらをすべて同じ方法で処理しますが、|MuPDF| \"\n\"（およびPyMuPDF）では、基本的には異なる3つのオブジェクトタイプとして扱われます。\"\n\n#: ../../vars.rst:457 713c32c363bd480cba99fcadd3fa3555\nmsgid \"Annotation Flag Bits\"\nmsgstr \"注釈フラグビット\"\n\n#: ../../vars.rst:474 9fdaae6162c54afea314aa849239b470\nmsgid \"Annotation Line Ending Styles\"\nmsgstr \"注釈の線の終端スタイル\"\n\n#: ../../vars.rst:490 3e407ea8c72444ebba3331d472a6a25a\nmsgid \"Widget Constants\"\nmsgstr \"ウィジェットの定数\"\n\n#: ../../vars.rst:495 96ec99e51a7e4985a737ba02c17541ac\nmsgid \"Widget Types (*field_type*)\"\nmsgstr \"ウィジェットのタイプ（*field_type*）\"\n\n#: ../../vars.rst:508 755546e537074e1aaa1b792a365b879a\nmsgid \"Text Widget Subtypes (*text_format*)\"\nmsgstr \"テキストウィジェットのサブタイプ（*text_format*）\"\n\n#: ../../vars.rst:519 2d435f5842544cc5ad764fc27d6e30db\nmsgid \"Widget flags (*field_flags*)\"\nmsgstr \"ウィジェットフラグ（*field_flags*）\"\n\n#: ../../vars.rst:520 1be2e082d5f24d78b93633d42c3ab6b3\nmsgid \"**Common to all field types**::\"\nmsgstr \"**すべてのフィールドタイプに共通**：\"\n\n#: ../../vars.rst:526 9a70d77fe1724d00a6baf6703369f739\nmsgid \"**Text widgets**::\"\nmsgstr \"**テキストウィジェット**：\"\n\n#: ../../vars.rst:536 a70d3da20a7a4996843ce3b94a65f844\nmsgid \"**Button widgets**::\"\nmsgstr \"**ボタンウィジェット**：\"\n\n#: ../../vars.rst:543 33f39c42d34a4fa49140b193aec55d00\nmsgid \"**Choice widgets**::\"\nmsgstr \"**チョイスウィジェット**：\"\n\n#: ../../vars.rst:556 05602853929445cfb71dfca4dc7fb284\nmsgid \"PDF Standard Blend Modes\"\nmsgstr \"PDF標準ブレンドモード\"\n\n#: ../../vars.rst:558 d1da99abe9c4449e9af156616a68a1c3\nmsgid \"For an explanation see :ref:`AdobeManual`, page 324::\"\nmsgstr \"詳細については、Adobe PDFリファレンスのページ324をご覧ください：\"\n\n#: ../../vars.rst:581 72834b1fb7fb47c6982ed3593f7600d3\nmsgid \"Stamp Annotation Icons\"\nmsgstr \"スタンプ注釈アイコン\"\n\n#: ../../vars.rst:582 71aa56b7b0644cef8475af050d9bccf3\nmsgid \"MuPDF has defined the following icons for **rubber stamp** annotations::\"\nmsgstr \"MuPDFは、ラバースタンプ注釈に次のアイコンを定義しています：\"\n\n#: ../../footer.rst:46 7b627849860f4ae7a235d36a44c7c566\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE \"\n#~ \"| TEXT_MEDIABOX_CLIP`\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE \"\n#~ \"| TEXT_MEDIABOX_CLIP | TEXT_PRESERVE_IMAGES`\"\n#~ msgstr \"\"\n\n#~ msgid \"Return type\"\n#~ msgstr \"戻り値の型\"\n\n#~ msgid \"'x.xx.x' -- version of PyMuPDF (these bindings)\"\n#~ msgstr \"‘x.xx.x’ – PyMuPDF（これらのバインディング）のバージョン\"\n\n#~ msgid \"\"\n#~ \"The docstring of *fitz* contains \"\n#~ \"information of the above which can \"\n#~ \"be retrieved like so: *print(fitz.__doc__)*,\"\n#~ \" and should look like: *PyMuPDF \"\n#~ \"1.10.0: Python bindings for the MuPDF\"\n#~ \" 1.10 library, built on 2016-11-30 \"\n#~ \"13:09:13*.\"\n#~ msgstr \"\"\n#~ \"fitzのドキュストリングには、上記の情報が含まれており、次のようにして取得できます： \"\n#~ \"print(fitz.__doc__)。以下のように表示されるべきです：PyMuPDF 1.10.0：MuPDF \"\n#~ \"1.10ライブラリ用のPythonバインディング、ビルド日時2016-11-30 13:09:13。\"\n\n#~ msgid \"\"\n#~ \"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE \"\n#~ \"| TEXT_MEDIABOX_CLIP | TEXT_DEHYPHENATE`\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"128 -- If set, use raw character\"\n#~ \" codes instead of U+FFFD. This is \"\n#~ \"the default for **text extraction** in\"\n#~ \" PyMuPDF. If you **want to detect**\"\n#~ \" when encoding information is missing \"\n#~ \"or uncertain, toggle this flag and \"\n#~ \"scan for the presence of U+FFFD (=\"\n#~ \" `chr(0xfffd)`) code points in the \"\n#~ \"resulting text.\"\n#~ msgstr \"\"\n#~ \"128 -- 設定されている場合、U+FFFDの代わりに生の文字コードを使用します。これは、PyMuPDFにおける\"\n#~ \" **テキスト抽出** \"\n#~ \"のデフォルトです。エンコーディング情報が不足しているか不確かな場合に**検出したい**場合は、このフラグを切り替えて、結果のテキストにU+FFFD\"\n#~ \" (= `chr(0xfffd)`)コードポイントが存在するかどうかをスキャンします。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"ISO timestamp *YYYY-MM-DD HH:MM:SS* when these bindings were built.\"\n#~ msgstr \"これらのバインディングがビルドされたISOタイムスタンプ YYYY-MM-DD HH:MM:SS。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/version.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../version.rst:1 d1fbe6ff1d5549fb8be875f6d37c584b\nmsgid \"This documentation covers PyMuPDF |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#: ../../version.rst:3 133bf913bb004c8ca82964184ed7628c\nmsgid \"\"\n\"The major and minor versions of PyMuPDF and MuPDF will always be the same. Only the third qualifier (patch level) may deviate from that of MuPDF.\"\nmsgstr \"PyMuPDF と MuPDF のメジャーおよびマイナーバージョンは常に同じになります。第三の修飾子（パッチレベル）のみが MuPDF のものと異なる場合があります。\"\n\n#: ../../version.rst:5 994720d99f72419ebd711b2cf71dcefb\nmsgid \"\"\n\"Typically PyMuPDF is released more frequently than MuPDF so it will often\"\n\" be the case that the patch level of PyMuPDF will be greater than the \"\n\"embedded MuPDF.\"\nmsgstr \"通常、PyMuPDFはMuPDFよりも頻繁にリリースされるため、PyMuPDFのパッチレベルが組み込まれたMuPDFのパッチレベルよりも大きくなることがよくあります。\"\n\n#: ../../version.rst:9 371aa251e8314b9aad7c870f54636f80\nmsgid \"For example PyMuPDF-1.24.5 contains MuPDF-1.24.2.\"\nmsgstr \"例えば、PyMuPDF-1.24.5にはMuPDF-1.24.2が含まれています。\"\n\n#: ../../version.rst:11 7c7d7d87d7e14441959c236fee7d2ee5\nmsgid \"Also see `pymupdf_version` and `mupdf_version`.\"\nmsgstr \"pymupdf_versionとmupdf_versionも参照してください。\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF \"\n#~ \"v1.23.0rc1** features as of **2023-08-10 \"\n#~ \"00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.23.4**\"\n#~ \" features as of **2023-09-26 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.23.5**\"\n#~ \" features as of **2023-10-11 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.23.8**\"\n#~ \" features as of **2023-12-19 00:00:01**.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"This documentation covers **PyMuPDF v1.25.5**\"\n#~ \" features as of **2025-03-31 00:00:01**.\"\n#~ msgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/widget.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 9be7fe8ece684722b20723502ba6e81a\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 4fd0b4c61f30429d928c92ebb1081bc3\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 8395c05a667445b68d678e31a6c9296f\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../widget.rst:7 b5bf7834aa6d4acc80837502b85e97c1\nmsgid \"Widget\"\nmsgstr \"Widget (ウィジェット)\"\n\n#: ../../widget.rst:9 db658752009445c5a3459712f6b25c8f\nmsgid \"|pdf_only_class|\"\nmsgstr \"PDFのみ。\"\n\n#: ../../widget.rst:11 d1312e8bf60148598975d49439011b6c\nmsgid \"\"\n\"This class represents a PDF Form field, also called a \\\"widget\\\". \"\n\"Throughout this documentation, we are using these terms synonymously. \"\n\"Fields technically are a special case of PDF annotations, which allow \"\n\"users with limited permissions to enter information in a PDF. This is \"\n\"primarily used for filling out forms.\"\nmsgstr \"このクラスは、PDFフォームフィールド、または「ウィジェット」とも呼ばれるものを表します。このドキュメンテーション全体で、これらの用語を同義語として使用しています。フィールドは技術的にはPDF注釈の特殊なケースであり、制限付きの権限を持つユーザーがPDFに情報を入力することを可能にします。これは主にフォームの記入に使用されます。\"\n\n#: ../../widget.rst:13 6befe4905ed146a2ab8cfd92d1d923bc\nmsgid \"\"\n\"Like annotations, widgets live on PDF pages. Similar to annotations, the \"\n\"first widget on a page is accessible via :attr:`Page.first_widget` and \"\n\"subsequent widgets can be accessed via the :attr:`Widget.next` property.\"\nmsgstr \"\"\n\"アノテーションと同様に、ウィジェットもPDFページ上に存在します。注釈と同様に、ページ上の最初のウィジェットは \"\n\":attr:`Page.first_widget` 経由でアクセスでき、その後のウィジェットは :attr:`Widget.next` \"\n\"プロパティ経由でアクセスできます。\"\n\n#: ../../widget.rst:15 f5dcbec91e9446b1bc886ab894d9b27c\nmsgid \"\"\n\"Like annotations, widgets also lose connection to their page when the \"\n\"page becomes unavailable, please see `here \"\n\"<https://pymupdf.readthedocs.io/en/latest/app3.html#ensuring-consistency-\"\n\"of-important-objects-in-pymupdf>`_ for details. This is relevant \"\n\"especially when updating the widget: this will fail if the original page \"\n\"object is no longer available.\"\nmsgstr \"\"\n\n#: ../../widget.rst:17 23ea64f7e0164b6788a0c02783469bef\nmsgid \"\"\n\"*(Changed in version 1.16.0)* MuPDF no longer treats widgets as a subset \"\n\"of general annotations. Consequently, :attr:`Page.first_annot` and \"\n\":meth:`Annot.next` will deliver **non-widget annotations exclusively**, \"\n\"and be ``None`` if only form fields exist on a page. Vice versa, \"\n\":attr:`Page.first_widget` and :meth:`Widget.next` will only show widgets.\"\n\" This design decision is purely internal to MuPDF; technically, links, \"\n\"annotations and fields have a lot in common and also continue to share \"\n\"the better part of their code within (Py-) MuPDF.\"\nmsgstr \"\"\n\"*（バージョン1.16.0で変更）* \"\n\"MuPDFはウィジェットを一般的な注釈のサブセットとして扱わなくなりました。したがって、:attr:`Page.first_annot` および \"\n\":meth:`Annot.next` \"\n\"は非ウィジェット注釈のみを返し、ページにフォームフィールドのみが存在する場合はNoneを返します。逆に、:attr:`Page.first_widget`\"\n\" および :meth:`Widget.next` \"\n\"はウィジェットのみを表示します。この設計の決定はMuPDF内部におけるものであり、技術的にはリンク、注釈、およびフィールドは多くの共通点を持ち、また（Py-）MuPDF内でコードの大部分を共有し続けています。\"\n\n#: ../../widget.rst:20 4c382afc381347e990494e4d0e1c78f7\nmsgid \"**Class API**\"\nmsgstr \"クラスAPI\"\n\n#: ../../widget.rst:26 f56bf175166444f7920a252639d09199\nmsgid \"*New in version 1.18.15*\"\nmsgstr \"*バージョン1.18.15で新しく追加*\"\n\n#: ../../widget.rst:28 00cee4b5b9734e0484ff17718afb7614\nmsgid \"\"\n\"Return the names of On / Off (i.e. selected / clicked or not) states a \"\n\"button field may have. While the 'Off' state usually is also named like \"\n\"so, the 'On' state is often given a name relating to the functional \"\n\"context, for example 'Yes', 'Female', etc.\"\nmsgstr \"\"\n\"ボタンフィールドが持つOn / Off（選択/クリックしたかどうか）状態の名前を返します。通常、 'Off'状態も同様に名前が付けられていますが、\"\n\" 'On'状態は機能的なコンテキストに関連する名前がよく付けられます。たとえば、「Yes」、「Female」などです。\"\n\n#: ../../widget.rst:30 7d6a3ae94e2742d5a84bf396789e24e1\nmsgid \"\"\n\"This method helps finding out the possible values of :attr:`field_value` \"\n\"in these cases.\"\nmsgstr \"このメソッドは、これらのケースで :attr:`field_value` の可能な値を調べるのに役立ちます。\"\n\n#: ../../widget.rst 3ba59739b0504accbfb45a04c8b24a7f\n#: ac61f1c8af7547ca9e4696981cd7c001\nmsgid \"returns\"\nmsgstr \"戻り値：\"\n\n#: ../../widget.rst:32 dc0ef726c74e4a249337ee6f20cdd308\nmsgid \"\"\n\"a dictionary with the names of 'On' and 'Off' for the *normal* and the \"\n\"*pressed-down* appearance of button widgets. The following example shows \"\n\"that the \\\"selected\\\" value is \\\"Male\\\":\"\nmsgstr \"\"\n\"*normal* の 状態と *pressed-down* 状態のボタンウィジェットの 'On'と \"\n\"'Off'の名前を持つ辞書。次の例では、「選択された」値は「Male」であることが示されています：\"\n\n#: ../../widget.rst:40 dca66819e96f4f19a12d511c1409a188\nmsgid \"New in version 1.22.2\"\nmsgstr \"新機能（バージョン1.22.2で追加）\"\n\n#: ../../widget.rst:42 72cfa1c4a4794fdebcf176d87534ed11\nmsgid \"\"\n\"Return the value of the \\\"ON\\\" state of check boxes and radio buttons. \"\n\"For check boxes this is always the value \\\"Yes\\\". For radio buttons, this\"\n\" is the value to select / activate the button.\"\nmsgstr \"チェックボックスとラジオボタンの「ON」状態の値を返します。チェックボックスの場合、これは常に「Yes」という値です。ラジオボタンの場合、これはボタンを選択/アクティブ化する値です。\"\n\n#: ../../widget.rst:44 ef6612006aa6463b9f062200357220e8\nmsgid \"\"\n\"the value that sets the button to \\\"selected\\\". For non-checkbox, non-\"\n\"radiobutton fields, always `None` is returned. For check boxes the return\"\n\" is `True`. For radio buttons this is the value \\\"Male\\\" in the following\"\n\" example:\"\nmsgstr \"\"\n\"ボタンを「選択」に設定する値が返されます。非チェックボックス、非ラジオボタンフィールドの場合、常に `None` \"\n\"が返されます。チェックボックスの場合、戻り値は `True` です。ラジオボタンの場合、次の例では値が「Male」です。\"\n\n#: ../../widget.rst:51 149007e65bf84de18e2eb1c2afe8bf71\nmsgid \"\"\n\"So for check boxes and radio buttons, the recommended method to set them \"\n\"to \\\"selected\\\", or to check the state is the following:\"\nmsgstr \"したがって、チェックボックスとラジオボタンの場合、それらを「選択」または状態を確認するための推奨される方法は次のとおりです。\"\n\n#: ../../widget.rst:60 9b42ee70ae144a8b92f71cf466956b05\n#, fuzzy\nmsgid \"\"\n\"After any changes to a widget, this **method must be used** to reflect \"\n\"changes in the PDF [#f1]_.\"\nmsgstr \"ウィジェットに変更が加えられた後、これらの変更をPDFに保存するためにこのメソッドを **使用する必要があります** [#f1]_。\"\n\n#: ../../widget.rst f9afde507f67494fbafed9da093edc2c\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../widget.rst:62 4a0049c3506c40d99e4aba3b7c10c027\nmsgid \"\"\n\"if ``True``, the widget's :attr:`Widget.field_flags` are copied to the \"\n\"``Parent`` object (if present) and all widgets named in its ``Kids`` \"\n\"array. This provides a convenient way to -- for example -- set all \"\n\"instances of the widget to read-only, no matter on which page they may \"\n\"occur [#f2]_.\"\nmsgstr \"\"\n\n#: ../../widget.rst:66 ad4e8312e49447b68aa62039c7138968\nmsgid \"\"\n\"Reset the field's value to its default -- if defined -- or remove it. Do \"\n\"not forget to issue :meth:`update` afterwards.\"\nmsgstr \"\"\n\"フィールドの値をデフォルト値にリセットします。デフォルトが定義されている場合、それを削除します。その後、:meth:`update` \"\n\"を実行するのを忘れないでください。\"\n\n#: ../../widget.rst:70 ac472167a7e14f4290ac8a193c79160c\nmsgid \"\"\n\"Point to the next form field on the page. The last widget returns \"\n\"``None``.\"\nmsgstr \"ページ上の次のフォームフィールドを指します。最後のウィジェットは ``None`` を返します。\"\n\n#: ../../widget.rst:74 1f2d580b4eca4c468f4a0e6592281c85\nmsgid \"\"\n\"A list of up to 4 floats defining the field's border color. Default value\"\n\" is ``None`` which causes border style and border width to be ignored.\"\nmsgstr \"\"\n\"フィールドの境界線の色を定義する最大4つの浮動小数点数のリストです。デフォルト値は ``None`` \"\n\"で、これにより境界線スタイルと境界線の幅が無視されます。\"\n\n#: ../../widget.rst:78 4d75daab990241b7a3b26a0e4ab3a3f3\nmsgid \"\"\n\"A string defining the line style of the field's border. See \"\n\":attr:`Annot.border`. Default is \\\"s\\\" (\\\"Solid\\\") -- a continuous line. \"\n\"Only the first character (upper or lower case) will be regarded when \"\n\"creating a widget.\"\nmsgstr \"\"\n\"フィールドの境界線の線スタイルを定義する文字列です。:attr:`Annot.border` を参照してください。デフォルトは \\\"s\\\" \"\n\"(\\\"Solid\\\") で、連続線です。ウィジェットを作成する際、最初の文字（大文字または小文字）のみが考慮されます。\"\n\n#: ../../widget.rst:82 a3b4c3bbfb544efd99ac42ab92c5d596\nmsgid \"A float defining the width of the border line. Default is 1.\"\nmsgstr \"境界線の幅を定義する浮動小数点数です。デフォルトは1です。\"\n\n#: ../../widget.rst:86 8abf38d7b6a540acb99b929363d614c3\nmsgid \"\"\n\"A list/tuple of integers defining the dash properties of the border line.\"\n\" This is only meaningful if *border_style == \\\"D\\\"* and \"\n\":attr:`border_color` is provided.\"\nmsgstr \"\"\n\"*border_style == \\\"D\\\"* であり、:attr:`border_color` \"\n\"が指定されている場合にのみ意味があります。これは、境界線のダッシュプロパティを定義する整数のリスト/タプルです。\"\n\n#: ../../widget.rst:90 89fa9c260a8c49f0b07ea1b251cece4e\nmsgid \"\"\n\"Python sequence of strings defining the valid choices of list boxes and \"\n\"combo boxes. For these widget types, this property is mandatory and must \"\n\"contain at least two items. Ignored for other types.\"\nmsgstr \"リストボックスとコンボボックスの有効な選択肢を定義するPythonシーケンスの文字列です。これらのウィジェットタイプでは、このプロパティが必須で、少なくとも2つのアイテムを含める必要があります。他のタイプでは無視されます。\"\n\n#: ../../widget.rst:94 d429d2ef1dd644d79f98b280f55ad276\nmsgid \"\"\n\"A mandatory string defining the field's name. No checking for duplicates \"\n\"takes place.\"\nmsgstr \"フィールドの名前を定義する必須の文字列です。重複をチェックしません。\"\n\n#: ../../widget.rst:98 3e1f3a12889b40cdb2687c5e1e275082\nmsgid \"\"\n\"An optional string containing an \\\"alternate\\\" field name. Typically used\"\n\" for any notes, help on field usage, etc. Default is the field name.\"\nmsgstr \"「代替」フィールド名を含むオプションの文字列です。通常、フィールドの使用方法に関するメモ、ヘルプなどに使用されます。デフォルトはフィールド名です。\"\n\n#: ../../widget.rst:102 02bb3f5a570947e98e225720d915a4b5\nmsgid \"The value of the field.\"\nmsgstr \"フィールドの値です。\"\n\n#: ../../widget.rst:106 159866e898664171a44d8b61241d2731\nmsgid \"\"\n\"An integer defining a large amount of properties of a field. Be careful \"\n\"when changing this attribute as this may change the field type.\"\nmsgstr \"フィールドの多くのプロパティを定義する整数です。この属性を変更する際は注意してください。これはフィールドのタイプを変更する可能性があります。\"\n\n#: ../../widget.rst:110 62966a5f68404db5822a72647d202b90\nmsgid \"\"\n\"A mandatory integer defining the field type. This is a value in the range\"\n\" of 0 to 6. It cannot be changed when updating the widget.\"\nmsgstr \"フィールドタイプを定義する必須の整数です。これは0から6の範囲の値です。ウィジェットを更新する際に変更できません。\"\n\n#: ../../widget.rst:114 a9fbed37d8be4f51b900e87522083cb4\nmsgid \"A string describing (and derived from) the field type.\"\nmsgstr \"フィールドタイプを説明する文字列（フィールドタイプから派生）。\"\n\n#: ../../widget.rst:118 0893214230bb4b998907cfb864bf8047\nmsgid \"A list of up to 4 floats defining the field's background color.\"\nmsgstr \"フィールドの背景色を定義する、最大4つの浮動小数点数のリスト。\"\n\n#: ../../widget.rst:122 864cf589b08549bca7920c38f91caa48\nmsgid \"The caption string of a button-type field.\"\nmsgstr \"ボタンタイプのフィールドのキャプション文字列。\"\n\n#: ../../widget.rst:126 d1ed58b8e9784d0f9f5368aa781d8db2\nmsgid \"A bool indicating the signing status of a signature field, else ``None``.\"\nmsgstr \"署名フィールドの署名ステータスを示すブール値。それ以外の場合は ``None``。\"\n\n#: ../../widget.rst:130 fd9f9f5619ec4ae69d780dcfdcaf1cf5\nmsgid \"The rectangle containing the field.\"\nmsgstr \"フィールドを含む矩形。\"\n\n#: ../../widget.rst:134 32a4055906494c169f91575f408fd75e\nmsgid \"\"\n\"A list of **1, 3 or 4 floats** defining the text color. Default value is \"\n\"black (`[0, 0, 0]`).\"\nmsgstr \"テキストの色を定義する、**1、3、または4つの浮動小数点数** のリスト。デフォルト値は黒 (`[0, 0, 0]`)です。\"\n\n#: ../../widget.rst:138 f951f27a175047e6ad58a7ee9d45d202\nmsgid \"\"\n\"A string defining the font to be used. Default and replacement for \"\n\"invalid values is *\\\"Helv\\\"*. For valid font reference names see the \"\n\"table below.\"\nmsgstr \"\"\n\"使用するフォントを定義する文字列。デフォルトおよび無効な値の置換は *「Helv」* \"\n\"です。有効なフォント参照名については以下の表を参照してください。\"\n\n#: ../../widget.rst:142 93d6bab5e8ed4964b445aaff3f5a666e\nmsgid \"\"\n\"A float defining the text :data:`fontsize`. Default value is zero, which \"\n\"causes PDF viewer software to dynamically choose a size suitable for the \"\n\"annotation's rectangle and text amount.\"\nmsgstr \"\"\n\"テキストの :data:`fontsize` \"\n\"を定義する浮動小数点数。デフォルト値はゼロで、PDFビューアソフトウェアが注釈の矩形とテキストの量に適したサイズを動的に選択します。\"\n\n#: ../../widget.rst:146 a1ded660efa640cd9b872d5a1fffdb1f\nmsgid \"\"\n\"An integer defining the maximum number of text characters. PDF viewers \"\n\"will (should) not accept a longer text.\"\nmsgstr \"テキストの最大文字数を定義する整数。PDFビューアは（するはずです）より長いテキストを受け入れません。\"\n\n#: ../../widget.rst:150 68eac259cd954e619832866bde7c37e3\nmsgid \"\"\n\"An integer defining acceptable text types (e.g. numeric, date, time, \"\n\"etc.). For reference only for the time being -- will be ignored when \"\n\"creating or updating widgets.\"\nmsgstr \"許容可能なテキストタイプを定義する整数（例：数値、日付、時刻など）。現時点では参考用のみで、ウィジェットを作成または更新する際には無視されます。\"\n\n#: ../../widget.rst:154 9df210c84ecd4845b952f6d3cc9195cc\nmsgid \"The PDF :data:`xref` of the widget.\"\nmsgstr \"ウィジェットのPDF :data:`xref`。\"\n\n#: ../../widget.rst:158 ../../widget.rst:164 ../../widget.rst:170\n#: ../../widget.rst:176 ../../widget.rst:182 6ac3abf289404eeaafe2d71129cccf4f\n#: 8034826ba5bf458fa878c3dfe0dcb46e 8155dfc13cad413eb75cd134942ce80a\n#: b8eb6a539c4941e6b3212dc4474dfd75 c5b33ed64c7043db966de5404c881830\nmsgid \"New in version 1.16.12\"\nmsgstr \"バージョン1.16.12で新登場\"\n\n#: ../../widget.rst:160 27f8421d8a374cd587fc385b05348e06\nmsgid \"\"\n\"JavaScript text (unicode) for an action associated with the widget, or \"\n\"``None``. This is the only script action supported for **button type** \"\n\"widgets.\"\nmsgstr \"\"\n\"ウィジェットに関連付けられたアクション用のJavaScriptテキスト（Unicode）、または ``None``。これは **ボタンタイプ** \"\n\"のウィジェットに対してサポートされる唯一のスクリプトアクションです。\"\n\n#: ../../widget.rst:166 bbc99abeab574327895dbdfadb016871\nmsgid \"\"\n\"JavaScript text (unicode) to be performed when the user types a key-\"\n\"stroke into a text field or combo box or modifies the selection in a \"\n\"scrollable list box. This action can check the keystroke for validity and\"\n\" reject or modify it. ``None`` if not present.\"\nmsgstr \"\"\n\"JavaScriptテキスト（Unicode）は、ユーザーがテキストフィールドまたはコンボボックスにキーストロークを入力するか、スクロール可能なリストボックスの選択を変更するときに実行されるアクションです。このアクションはキーストロークの妥当性をチェックし、拒否または変更することができます。存在しない場合は\"\n\" ``None`` です。\"\n\n#: ../../widget.rst:172 49c953662fc846e4ab3a5754771075d5\nmsgid \"\"\n\"JavaScript text (unicode) to be performed before the field is formatted \"\n\"to display its current value. This action can modify the field’s value \"\n\"before formatting. ``None`` if not present.\"\nmsgstr \"\"\n\"このアクションは、フィールドが現在の値を表示するためにフォーマットされる前に、フィールドの値を変更するために実行されるJavaScriptテキスト（Unicode）です。存在しない場合は\"\n\" ``None`` です。\"\n\n#: ../../widget.rst:178 f099a7380085444088d138037fc88009\nmsgid \"\"\n\"JavaScript text (unicode) to be performed when the field’s value is \"\n\"changed. This action can check the new value for validity. ``None`` if \"\n\"not present.\"\nmsgstr \"\"\n\"このアクションは、フィールドの値が変更されたときに実行されるJavaScriptテキスト（Unicode）です。このアクションは新しい値の妥当性をチェックすることができます。存在しない場合は\"\n\" ``None`` です。\"\n\n#: ../../widget.rst:184 195412bc8f7645c7af94839cbeef56c7\nmsgid \"\"\n\"JavaScript text (unicode) to be performed to recalculate the value of \"\n\"this field when that of another field changes. ``None`` if not present.\"\nmsgstr \"バージョン1.16.12で新規追\"\n\n#: ../../widget.rst:188 ../../widget.rst:194 be53028b2eeb496e91e645ddedbecf73\n#: caaac82450ae43fd84f1684ee16cc1aa\nmsgid \"New in version 1.22.6\"\nmsgstr \"バージョン1.22.6で新規追加\"\n\n#: ../../widget.rst:190 66757bee21264b4591997469672bf407\nmsgid \"\"\n\"JavaScript text (unicode) to be performed on losing the focus of this \"\n\"field. ``None`` if not present.\"\nmsgstr \"このフィールドからフォーカスを失ったときに実行されるJavaScriptテキスト（Unicode）です。存在しない場合は ``None`` です。\"\n\n#: ../../widget.rst:196 6d86df2f110242b9b322d96488384f39\nmsgid \"\"\n\"JavaScript text (unicode) to be performed on focusing this field. \"\n\"``None`` if not present.\"\nmsgstr \"このフィールドにフォーカスが当たったときに実行されるJavaScriptテキスト（Unicode）です。存在しない場合は ``None`` です。\"\n\n#: ../../widget.rst:200 31230d72253b4583a09b8159f40329f4\nmsgid \"For **adding** or **changing** one of the above scripts,\"\nmsgstr \"上記のいずれかのスクリプトを **追加** または **変更** するには、\"\n\n#: ../../widget.rst:201 3d2a3d82396442afb52dfc4cdd423495\nmsgid \"\"\n\"just put the appropriate JavaScript source code in the widget attribute. \"\n\"To **remove** a script, set the respective attribute to ``None``.\"\nmsgstr \"\"\n\"適切なJavaScriptソースコードをウィジェット属性に配置するだけです。スクリプトを **削除する** には、該当する属性を ``None``\"\n\" に設定します。\"\n\n#: ../../widget.rst:204 8ae6388eebe44c248ddac814e91ade75\nmsgid \"Button fields only support :attr:`script`.\"\nmsgstr \"ボタンフィールドは :attr:`script` をサポートしています\"\n\n#: ../../widget.rst:205 eaf4aaf730aa470bac28fa589c1d9a75\nmsgid \"Other script entries will automatically be set to ``None``.\"\nmsgstr \"他のスクリプトエントリは自動的に ``None`` に設定されます。\"\n\n#: ../../widget.rst:207 1574012d10e54a92850485e41d1ffedf\nmsgid \"\"\n\"It is worthwhile to look at `this \"\n\"<https://experienceleague.adobe.com/docs/experience-manager-\"\n\"learn/assets/FormsAPIReference.pdf?lang=en>`_ manual with lots of \"\n\"information about Adobe's standard scripts for various field types. For \"\n\"example, if you want to add a text field representing a date, you may \"\n\"want to store the following scripts. They will ensure pattern-compatible \"\n\"date formats and display date pickers in supporting viewers::\"\nmsgstr \"\"\n\"Adobeの標準スクリプトに関する多くの情報が含まれている `この \"\n\"<https://experienceleague.adobe.com/docs/experience-manager-\"\n\"learn/assets/FormsAPIReference.pdf?lang=en>`_ \"\n\"マニュアルを確認する価値があります。たとえば、日付を表すテキストフィールドを追加する場合、次のスクリプトを保存することができます。これにより、パターン互換の日付形式が確保され、サポートされているビューアで日付ピッカーが表示されます。\"\n\n#: ../../widget.rst:219 c65b215c2ad34e7488b15662ebd4d3bb\nmsgid \"Standard Fonts for Widgets\"\nmsgstr \"ウィジェット用の標準フォント\"\n\n#: ../../widget.rst:220 cdad1a06914d4e0096cf6f84a03b0434\n#, fuzzy\nmsgid \"\"\n\"Widgets use their own resources object ``/DR``. A widget resources object\"\n\" must at least contain a ``/Font`` object. Widget fonts are independent \"\n\"from page fonts. We currently support the 14 PDF base fonts using the \"\n\"following fixed reference names, or any name of an already existing field\"\n\" font. When specifying a text font for new or changed widgets, **either**\"\n\" choose one in the first table column (upper and lower case supported), \"\n\"**or** one of the already existing form fonts. In the latter case, \"\n\"spelling must exactly match.\"\nmsgstr \"\"\n\"ウィジェットは独自のリソースオブジェクト */DR* を使用します。ウィジェットのリソースオブジェクトには、少なくとも */Font* \"\n\"オブジェクトを含める必要があります。ウィジェットフォントはページフォントとは独立しています。現在、以下の固定参照名を使用して、14のPDFベースフォントをサポートしています。また、既存のフィールドフォントの名前でもかまいません。新しいウィジェットまたは変更されたウィジェットのテキストフォントを指定する際には、最初の表の列（大文字と小文字がサポートされています）から1つを選択するか、既存のフォームフォントの1つを選択してください。後者の場合、スペルは厳密に一致する必要があります。\"\n\n#: ../../widget.rst:222 7fd5734a55b445cc854e109cbc203e17\nmsgid \"\"\n\"To find out already existing field fonts, inspect the list \"\n\":attr:`Document.FormFonts`.\"\nmsgstr \"既存のフィールドフォントを見つけるには、リスト :attr:`Document.FormFonts` を調べてください。\"\n\n#: ../../widget.rst:225 989af4e78c0847918dbff49079157c49\nmsgid \"**Reference**\"\nmsgstr \"**参照**\"\n\n#: ../../widget.rst:225 2a3d30a6f94b40939fd222ac5505a0c3\nmsgid \"**Base14 Fontname**\"\nmsgstr \"**Base14フォント名**\"\n\n#: ../../widget.rst:227 352a551d7b7d4200932f4f74ab639993\nmsgid \"CoBI\"\nmsgstr \"\"\n\n#: ../../widget.rst:227 97b97d88ac2049608397f18450ce94f9\nmsgid \"Courier-BoldOblique\"\nmsgstr \"\"\n\n#: ../../widget.rst:228 5784d31036e8451ea00333ebfc861db7\nmsgid \"CoBo\"\nmsgstr \"\"\n\n#: ../../widget.rst:228 f62fddbdd0ec4ca5a7de461de53b6f58\nmsgid \"Courier-Bold\"\nmsgstr \"\"\n\n#: ../../widget.rst:229 7b2ab33a398843e2b2becf0f64045392\nmsgid \"CoIt\"\nmsgstr \"\"\n\n#: ../../widget.rst:229 053e2cadb71446e3938febe4ef984f31\nmsgid \"Courier-Oblique\"\nmsgstr \"\"\n\n#: ../../widget.rst:230 4f7d11706d4b41ec968dff1ac8fb677f\nmsgid \"Cour\"\nmsgstr \"\"\n\n#: ../../widget.rst:230 bc034dde385b406280bef75f575a2672\nmsgid \"Courier\"\nmsgstr \"\"\n\n#: ../../widget.rst:231 ff774f899f274ee5a81ee1e6d1959b8c\nmsgid \"HeBI\"\nmsgstr \"\"\n\n#: ../../widget.rst:231 172ee9521a2348cd9f506babd8af5f10\nmsgid \"Helvetica-BoldOblique\"\nmsgstr \"\"\n\n#: ../../widget.rst:232 79d0f51c58f54f67a759e45d17d9ffc6\nmsgid \"HeBo\"\nmsgstr \"\"\n\n#: ../../widget.rst:232 467053b50fdf4b6a970d48f6d4cc2e1a\nmsgid \"Helvetica-Bold\"\nmsgstr \"\"\n\n#: ../../widget.rst:233 5abb199e534a4b2985760322156b7819\nmsgid \"HeIt\"\nmsgstr \"\"\n\n#: ../../widget.rst:233 8d472db0bc5a44caa9de71c566f7cb7e\nmsgid \"Helvetica-Oblique\"\nmsgstr \"\"\n\n#: ../../widget.rst:234 d03174f7c84045ea9ef98507a09fa344\nmsgid \"Helv\"\nmsgstr \"\"\n\n#: ../../widget.rst:234 bbec46b6db884fb29167ffc50a0c7dcb\nmsgid \"Helvetica **(default)**\"\nmsgstr \"Helvetica **(デフォルト)**\"\n\n#: ../../widget.rst:235 cd1c089129784daeb903d5ef116ea70b\nmsgid \"Symb\"\nmsgstr \"\"\n\n#: ../../widget.rst:235 81ad28b580f44ba78513b1abebbc40bc\nmsgid \"Symbol\"\nmsgstr \"\"\n\n#: ../../widget.rst:236 de4c92826dc94244b1b8ef026ab90a2e\nmsgid \"TiBI\"\nmsgstr \"\"\n\n#: ../../widget.rst:236 3dc417d13f2d4a6cbb1233643dc93f65\nmsgid \"Times-BoldItalic\"\nmsgstr \"\"\n\n#: ../../widget.rst:237 43969ece08334ca685bd92f021cd1884\nmsgid \"TiBo\"\nmsgstr \"\"\n\n#: ../../widget.rst:237 32b0cc34477144ffb88eb7565f2a0533\nmsgid \"Times-Bold\"\nmsgstr \"\"\n\n#: ../../widget.rst:238 a1252968a11c4601b7341a5c9ad95394\nmsgid \"TiIt\"\nmsgstr \"\"\n\n#: ../../widget.rst:238 8cdd804d025940c8b5d05a9397419bdc\nmsgid \"Times-Italic\"\nmsgstr \"\"\n\n#: ../../widget.rst:239 4d07f298c6d14909b518fad20ea5e681\nmsgid \"TiRo\"\nmsgstr \"\"\n\n#: ../../widget.rst:239 b7c540028a3d4cedb72159dba9849432\nmsgid \"Times-Roman\"\nmsgstr \"\"\n\n#: ../../widget.rst:240 58ea0b46026f4588b999a9ca93163980\nmsgid \"ZaDb\"\nmsgstr \"\"\n\n#: ../../widget.rst:240 2e0483edf38749a1928b25d20ab9055a\nmsgid \"ZapfDingbats\"\nmsgstr \"\"\n\n#: ../../widget.rst:243 a31f0eb06f284c738ae3404fb14e5e42\n#, fuzzy\nmsgid \"\"\n\"You are generally free to use any font for every widget. However, we \"\n\"recommend using ``ZaDb`` (\\\"ZapfDingbats\\\") and :data:`fontsize` 0 for \"\n\"check boxes: typical viewers will put a correctly sized tickmark in the \"\n\"field's rectangle, when it is clicked.\"\nmsgstr \"\"\n\"一般的に、すべてのウィジェットに任意のフォントを使用することができます。ただし、チェックボックスには *ZaDb* \"\n\"（「ZapfDingbats」）フォントと :data:`fontsize`  \"\n\"0を使用することをお勧めします。典型的なビューアは、フィールドの四角形をクリックすると正しくサイズ調整されたチェックマークを配置します。\"\n\n#: ../../widget.rst:246 25ed10dbd2a14216bbd4ed04f57c98cd\nmsgid \"Supported Widget Types\"\nmsgstr \"対応ウィジェットの種類\"\n\n#: ../../widget.rst:247 8cb59d1d5bd14f098f5fc408b8849853\nmsgid \"\"\n\"PyMuPDF supports the creation and update of many, but not all widget \"\n\"types.\"\nmsgstr \"PyMuPDFは、多くのウィジェットタイプの作成および更新をサポートしていますが、すべてのウィジェットタイプには対応していません。\"\n\n#: ../../widget.rst:249 8461bca05ec547fabc82884dedd125bb\nmsgid \"text (`PDF_WIDGET_TYPE_TEXT`)\"\nmsgstr \"テキスト（`PDF_WIDGET_TYPE_TEXT`）\"\n\n#: ../../widget.rst:250 4c1a2929bc174c79bd4b539f47d803f2\nmsgid \"push button (`PDF_WIDGET_TYPE_BUTTON`)\"\nmsgstr \"プッシュボタン（`PDF_WIDGET_TYPE_BUTTON`）\"\n\n#: ../../widget.rst:251 c8546d5d5e834b6bb9bf78579650d52d\nmsgid \"check box (`PDF_WIDGET_TYPE_CHECKBOX`)\"\nmsgstr \"チェックボックス（`PDF_WIDGET_TYPE_CHECKBOX`）\"\n\n#: ../../widget.rst:252 90c82cab0fe4443ab3b6c96bde056ab8\nmsgid \"combo box (`PDF_WIDGET_TYPE_COMBOBOX`)\"\nmsgstr \"コンボボックス（`PDF_WIDGET_TYPE_COMBOBOX`）\"\n\n#: ../../widget.rst:253 466344d91d064ed5a8d839e9b95d1988\nmsgid \"list box (`PDF_WIDGET_TYPE_LISTBOX`)\"\nmsgstr \"リストボックス（`PDF_WIDGET_TYPE_LISTBOX`）\"\n\n#: ../../widget.rst:254 315046b3a75448dd80a03dc3287c68fe\n#, fuzzy\nmsgid \"\"\n\"radio button (`PDF_WIDGET_TYPE_RADIOBUTTON`): PyMuPDF does not currently \"\n\"support the **creation** of groups of (interconnected) radio buttons, \"\n\"where setting one button automatically unsets the other buttons in the \"\n\"group. The widget object also does not reflect the presence of a button \"\n\"group. However: consistently selecting (or unselecting) a radio button is\"\n\" supported. This includes correctly setting the value maintained in the \"\n\"owning button group. Selecting a radio button may be done by either \"\n\"assigning `True` or `field.on_state()` to the field value. **De-\"\n\"selecting** the button should be done assigning `False`.\"\nmsgstr \"\"\n\"ラジオボタン（`PDF_WIDGET_TYPE_RADIOBUTTON`）：PyMuPDFは現在、ラジオボタンのグループ（相互に接続された）の \"\n\"**作成** \"\n\"をサポートしていません。つまり、1つを設定すると、グループ内の他のボタンが自動的に設定解除されるような状態を作成することはできません。また、ウィジェットオブジェクトはボタングループの存在を反映しません。ただし、ラジオボタンを一貫して選択（または選択解除）することはサポートされています。これには、所属するボタングループで維持される値を正しく設定することも含まれます。ラジオボタンを選択するには、フィールドの値に\"\n\" `True`  または `field.on_state()` を割り当てることができます。ボタンの選択解除は、`False` \"\n\"を割り当てることによって行う必要があります。\"\n\n#: ../../widget.rst:255 b7ca95506bb743bf8bc9d51686c700fc\nmsgid \"\"\n\"signature (`PDF_WIDGET_TYPE_SIGNATURE`) **read only** -- no update or \"\n\"creation of signatures.\"\nmsgstr \"\"\n\n#: ../../widget.rst:258 b53b3f3d840749208db6e32b83f6d04d\nmsgid \"Footnotes\"\nmsgstr \"脚注\"\n\n#: ../../widget.rst:259 3eaba62dde8347e2a386454b987a2ed7\nmsgid \"\"\n\"If you intend to re-access a new or updated field (e.g. for making a \"\n\"pixmap), make sure to reload the page first. Either close and re-open the\"\n\" document, or load another page first, or simply do `page = \"\n\"doc.reload_page(page)`.\"\nmsgstr \"\"\n\"新しいまたは更新されたフィールドに再アクセスする意図がある場合（たとえば、ピクセルマップを作成する場合）、まずページを再読み込むことを確認してください。文書を閉じて再度開くか、別のページを読み込むか、または単に\"\n\" `page = doc.reload_page(page)` を実行してください\"\n\n#: ../../widget.rst:261 148f6fb2b3f74450a3f794e012c04772\nmsgid \"\"\n\"Among other purposes, ``Parent`` objects are also used to facilitate \"\n\"multiple occurrences of a field (on the same or on different pages). The \"\n\"``Kids`` array in this ``Parent`` object contains the cross references of\"\n\" all widgets that are \\\"copies\\\" of the same field. Whenever the field \"\n\"value of any \\\"kid\\\" widget is changed, all the other kids are \"\n\"immediately updated too. This is a very efficient way to handle multiple \"\n\"copies of the same field, e.g. for filling out forms. This simultaneous \"\n\"update only happens for :attr:`Widget.field value`. The new parameter \"\n\"``sync_flags`` extends this to :attr:`Widget.field_flags`. This cannot be\"\n\" automated in the same way as for the field value to allow for more \"\n\"flexibility.\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 00e495d1b07b4fb7afe8b0b3fc2b91b4\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n#~ msgid \"signature (`PDF_WIDGET_TYPE_SIGNATURE`) **read only**.\"\n#~ msgstr \"署名（`PDF_WIDGET_TYPE_SIGNATURE`）は **読み取り専用です** 。\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/xml-class.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 35b2e14fdbf9456f870ea5e07c6a1abe\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 9c383ee007cb459a8f5ce0a78b556be8\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 7207641edba74fb79cd09bd543f88a77\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../xml-class.rst:7 5a1acd7449794938872c81139fa8acd0\nmsgid \"Xml\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:11 4ee590d80c2745afaad733bc8ba82e1d\nmsgid \"New in v1.21.0\"\nmsgstr \"v1.21.0で新たに追加\"\n\n#: ../../xml-class.rst:13 8fa4f25d9d5d4b7ea94cc3b663b67d4c\nmsgid \"\"\n\"This represents an HTML or an XML node. It is a helper class intended to \"\n\"access the DOM (Document Object Model) content of a :ref:`Story` object.\"\nmsgstr \"\"\n\"Xmlクラスは、HTMLまたはXMLノードを表します。これは、:ref:`Story` オブジェクトのDOM（Document Object \"\n\"Model）コンテンツにアクセスするためのヘルパークラスです。\"\n\n#: ../../xml-class.rst:15 e5105e52125246098e3b455ef2776456\nmsgid \"\"\n\"There is no need to ever directly construct an :ref:`Xml` object: after \"\n\"creating a :ref:`Story`, simply take :attr:`Story.body` -- which is an \"\n\"Xml node -- and use it to navigate your way through the story's DOM.\"\nmsgstr \"\"\n\":ref:`Xml` オブジェクトを直接構築する必要はありません。:ref:`Story` を作成した後、単に \"\n\":attr:`Story.body` を取得し（これはXmlノードです）、それを使用してストーリーのDOMを操作できます。\"\n\n#: ../../xml-class.rst:19 086ba76b6eaa4206b74c6b525b2ae70b\nmsgid \"**Method / Attribute**\"\nmsgstr \"**メソッド/属性**\"\n\n#: ../../xml-class.rst:19 9b744e4fa0694c9986e2250f2278784d\nmsgid \"**Description**\"\nmsgstr \"**説明**\"\n\n#: ../../xml-class.rst:21 f46174ffaec14c09984d82014f3fc9a4\nmsgid \":meth:`~.add_bullet_list`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:21 eefa1933e3b5485eb89f2e53127bcbf1\nmsgid \"Add a :htmlTag:`ul` tag - bulleted list, context manager.\"\nmsgstr \":htmlTag:`ul` タグを追加します - 箇条書きリスト、コンテキストマネージャ。\"\n\n#: ../../xml-class.rst:22 16936bcd25534da28940c85397594734\nmsgid \":meth:`~.add_codeblock`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:22 fcf17dab1d8645fe9307bbaad85e9a78\nmsgid \"Add a :htmlTag:`pre` tag, context manager.\"\nmsgstr \":htmlTag:`pre` タグを追加します、コンテキストマネージャ。\"\n\n#: ../../xml-class.rst:23 103a3a5af0f14cd1924448b542f62b6b\nmsgid \":meth:`~.add_description_list`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:23 e2f66dd80053480e97b4eeeb1ff42a9c\nmsgid \"Add a :htmlTag:`dl` tag, context manager.\"\nmsgstr \":htmlTag:`dl` タグを追加します、コンテキストマネージャ。\"\n\n#: ../../xml-class.rst:24 b041d519f2b64e188188cddb8b2f4e9b\nmsgid \":meth:`~.add_division`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:24 31129830737949a8bb370681ecfd4d06\nmsgid \"add a :htmlTag:`div` tag (renamed from “section”), context manager.\"\nmsgstr \":htmlTag:`div` タグを追加します（「section」と名前変更）、コンテキストマネージャ。\"\n\n#: ../../xml-class.rst:25 da7da028486141f58cf9c5a7952e1ba0\nmsgid \":meth:`~.add_header`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:25 228124168ce64130ad9d0ff5b13646e0\nmsgid \"Add a header tag (one of :htmlTag:`h1` to :htmlTag:`h6`), context manager.\"\nmsgstr \"headerタグ（:htmlTag:`h1` から :htmlTag:`h6` のいずれか）を追加します、コンテキストマネージャ。\"\n\n#: ../../xml-class.rst:26 806d8bfb5b3b4ce397764e9d4a0dc1d8\nmsgid \":meth:`~.add_horizontal_line`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:26 c07169b784924633a5e1fd68c8af798c\nmsgid \"Add a :htmlTag:`hr` tag.\"\nmsgstr \":htmlTag:`hr` タグを追加します。\"\n\n#: ../../xml-class.rst:27 5a73b0a8f50a496691126bd9d77a5637\nmsgid \":meth:`~.add_image`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:27 340cf98f4f3f4e4a84c228fd7be2e4d6\nmsgid \"Add a :htmlTag:`img` tag.\"\nmsgstr \":htmlTag:`img` タグを追加します。\"\n\n#: ../../xml-class.rst:28 d158603be675421a8b7f39bb5ff0a586\nmsgid \":meth:`~.add_link`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:28 339c28e41d7e44558a1e9b671ba9ef54\nmsgid \"Add a :htmlTag:`a` tag.\"\nmsgstr \":htmlTag:`a` タグを追加します。\"\n\n#: ../../xml-class.rst:29 7f6b79bf740d49b1932cf6a6a6576758\nmsgid \":meth:`~.add_number_list`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:29 0c01f30a42cf4468b8213216a1b3297c\nmsgid \"Add a :htmlTag:`ol` tag, context manager.\"\nmsgstr \":htmlTag:`ol` タグを追加します、コンテキストマネージャ。\"\n\n#: ../../xml-class.rst:30 8f9f02ea8c414d29a83d318465a0ff48\nmsgid \":meth:`~.add_paragraph`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:30 253c26552e274fbeb3da81a3470eec14\nmsgid \"Add a :htmlTag:`p` tag.\"\nmsgstr \":htmlTag:`p` タグを追加します。\"\n\n#: ../../xml-class.rst:31 b2d6acd206bb4cb2a8f6be0b5197c0d8\nmsgid \":meth:`~.add_span`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:31 98fe31d20e7a4ae8af4eba0928d53dd1\nmsgid \"Add a :htmlTag:`span` tag, context manager.\"\nmsgstr \":htmlTag:`span` タグを追加します。コンテキストマネージャーです。\"\n\n#: ../../xml-class.rst:32 50600afc53a74e6c80d8b4eef6b2304e\nmsgid \":meth:`~.add_subscript`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:32 c9cb764e916a4b27afb3c18ae5983896\nmsgid \"\"\n\"Add subscript text(:htmlTag:`sub` tag) - inline element, treated like \"\n\"text.\"\nmsgstr \"添字テキスト（:htmlTag:`sub` タグ）を追加します。行内要素で、テキストのように扱われます。\"\n\n#: ../../xml-class.rst:33 b72843ab592f40e8877c99fe4c941dcb\nmsgid \":meth:`~.add_superscript`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:33 3630b21203814ea190918432f1ca2417\nmsgid \"\"\n\"Add subscript text (:htmlTag:`sup` tag) - inline element, treated like \"\n\"text.\"\nmsgstr \"上付きテキスト（:htmlTag:`sup` タグ）を追加します。行内要素で、テキストのように扱われます。\"\n\n#: ../../xml-class.rst:34 69e9ce07a81841c280b49fa28bd70c97\nmsgid \":meth:`~.add_code`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:34 ../../xml-class.rst:35 ../../xml-class.rst:36\n#: ../../xml-class.rst:37 5c6747963ef74d38b09f3a6fbd934145\n#: 8cd903b064c74812942fc2b54fcb182d aa212076d95d4d34aca0fedfba075d7c\n#: bbf8c37a914547df93d38bbff33c7496\nmsgid \"Add code text (:htmlTag:`code` tag) - inline element, treated like text.\"\nmsgstr \"コードテキスト（:htmlTag:`code` タグ）を追加します。行内要素で、テキストのように扱われます。\"\n\n#: ../../xml-class.rst:35 ed457783f87b4432965ba520310e2912\nmsgid \":meth:`~.add_var`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:36 baa6b54b7dec48428d61ef058714e1c8\nmsgid \":meth:`~.add_samp`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:37 2e681286c7934f9e98e30aeed8f1e058\nmsgid \":meth:`~.add_kbd`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:38 c90afbfd1f2a4432aa57f469ce1aa9c3\nmsgid \":meth:`~.add_text`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:38 ../../xml-class.rst:162\n#: e05cf6e5226b4f768bfb698de671c8db fdddcc02af0b4c43a986178f7ab86439\n#, fuzzy\nmsgid \"Add a text string. Line breaks ``\\\\n`` are honored as :htmlTag:`br` tags.\"\nmsgstr \"テキスト文字列を追加します。改行 ``\\\\n`` は :htmlTag:`br` タグとして認識されます。\"\n\n#: ../../xml-class.rst:39 5ae611e247354be1a46cad16dd7fdf40\nmsgid \":meth:`~.append_child`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:39 f501e0b055984ba48721852e2de6968d\nmsgid \"Append a child node.\"\nmsgstr \"子ノードを追加します。\"\n\n#: ../../xml-class.rst:40 25340d7a99fc4ccf860933df50d0ebec\nmsgid \":meth:`~.clone`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:40 c331f277124c4ee3b8a1e9037493a3db\nmsgid \"Make a copy if this node.\"\nmsgstr \"このノードのコピーを作成します。\"\n\n#: ../../xml-class.rst:41 89bd772f48204020b60419c2db9d5bff\nmsgid \":meth:`~.create_element`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:41 405cddf85d9c49dd8e5b9cd0fcfa855d\nmsgid \"Make a new node with a given tag name.\"\nmsgstr \"指定されたタグ名で新しいノードを作成します。\"\n\n#: ../../xml-class.rst:42 b521f73a8f764b0f87ea954af8981b37\nmsgid \":meth:`~.create_text_node`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:42 ../../xml-class.rst:306\n#: 36b72c94c0534f59897e7d90525f00ab dfd89d799b2a49de8a00c1c68015628f\nmsgid \"Create direct text for the current node.\"\nmsgstr \"現在のノードに直接テキストを作成します。\"\n\n#: ../../xml-class.rst:43 fe2c4c6a496e4c30a74892bf305be0bf\nmsgid \":meth:`~.find`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:43 318cef4b3a694140908577091226c3e3\nmsgid \"Find a sub-node with given properties.\"\nmsgstr \"指定されたプロパティを持つサブノードを検索します。\"\n\n#: ../../xml-class.rst:44 a453fbff3b22420db8f0c51be152f8d6\nmsgid \":meth:`~.find_next`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:44 8a60922fc34041dfa5e21d0caa6fac06\nmsgid \"Repeat previous \\\"find\\\" with the same criteria.\"\nmsgstr \"前回の「find」と同じ条件で繰り返します。\"\n\n#: ../../xml-class.rst:45 e198f0bc22b944d48e40dc5c38223e9b\nmsgid \":meth:`~.insert_after`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:45 8f66fccc674d4dd8ab65c02ac8ba24fc\nmsgid \"Insert an element after current node.\"\nmsgstr \"現在のノードの後に要素を挿入します。\"\n\n#: ../../xml-class.rst:46 9d6b713c56884ee1b369e276ec5102a7\nmsgid \":meth:`~.insert_before`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:46 ae54a30b8bcf44daa6da5370718a075b\nmsgid \"Insert an element before current node.\"\nmsgstr \"現在のノードの前に要素を挿入します。\"\n\n#: ../../xml-class.rst:47 e9116568aee3452182bda7d5810abf1e\nmsgid \":meth:`~.remove`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:47 64bec43c81d140e9bb69363bbdaa051c\nmsgid \"Remove this node.\"\nmsgstr \"このノードを削除します。\"\n\n#: ../../xml-class.rst:48 1ac7caa0aab541d2b460ac445585c6c7\nmsgid \":meth:`~.set_align`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:48 ac6a6fbe13044fd787cd15a2670459ef\nmsgid \"Set the alignment using a CSS style spec. Only works for block-level tags.\"\nmsgstr \"CSS スタイル仕様を使用して配置を設定します。ブロックレベルのタグにのみ適用されます。\"\n\n#: ../../xml-class.rst:49 2c4b7b6457d4484a92058c1de4270fe9\nmsgid \":meth:`~.set_attribute`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:49 ../../xml-class.rst:172\n#: 804a76ddd5074a59b8d94661b6941469 e0a54f2af7784bddb2c2e0baf1536f26\nmsgid \"Set an arbitrary key to some value (which may be empty).\"\nmsgstr \"任意のキーに値（空である可能性があります）を設定します。\"\n\n#: ../../xml-class.rst:50 fa0b42cca1304379b0bcfebdc442dd15\nmsgid \":meth:`~.set_bgcolor`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:50 ../../xml-class.rst:199\n#: 63b3f2fe208b457ab9f31e92c5353ce8 bdaa46d0f4da43fca01a888db16337c7\nmsgid \"Set the background color. Only works for block-level tags.\"\nmsgstr \"背景色を設定します。ブロックレベルのタグにのみ適用されます。\"\n\n#: ../../xml-class.rst:51 ec6d2db5fec44f689ad6be9b934f0a82\nmsgid \":meth:`~.set_bold`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:51 ../../xml-class.rst:205\n#: 9e58087d6ecb42dab3894c28babdec5b bdc6a779999c4686ac0ffe57b93a8bd7\nmsgid \"Set bold on or off or to some string value.\"\nmsgstr \"太字をオンまたはオフに設定するか、ある文字列の値に設定します。\"\n\n#: ../../xml-class.rst:52 de15508d8d384d9da5d0b8cd2b1b780c\nmsgid \":meth:`~.set_color`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:52 9189331756f9457b9a92c047923b268d\nmsgid \"Set text color.\"\nmsgstr \"テキストの色を設定します。\"\n\n#: ../../xml-class.rst:53 9ac5e040ad994771a04fa353c7930b81\nmsgid \":meth:`~.set_columns`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:53 5e49161f1d2d43c889352cd9ff8edfc8\nmsgid \"Set the number of columns. Argument may be any valid number or string.\"\nmsgstr \"列数を設定します。引数は任意の有効な数値または文字列である必要があります。\"\n\n#: ../../xml-class.rst:54 09f99796e853445c8dcf98822e1ac0f7\nmsgid \":meth:`~.set_font`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:54 cf00809415f04821b5afcfb274bc466e\nmsgid \"Set the font-family, e.g. “sans-serif”.\"\nmsgstr \"フォントファミリーを設定します。例: \\\"sans-serif\\\"。\"\n\n#: ../../xml-class.rst:55 b6ea49c8641c4332b9398bef1a6359a3\nmsgid \":meth:`~.set_fontsize`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:55 9fe5840d1b4e4891aa77b55e25a5b1e2\nmsgid \"Set the font size. Either a float or a valid HTML/CSS string.\"\nmsgstr \"フォントサイズを設定します。浮動小数点数または有効なHTML/CSS文字列のいずれかです。\"\n\n#: ../../xml-class.rst:56 893eb791a848403381a5172bc82ba8a2\nmsgid \":meth:`~.set_id`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:56 f2aa328fbed64085b476f3b70fdf3881\nmsgid \"Set a :htmlTag:`id`. A check for uniqueness is performed.\"\nmsgstr \":htmlTag:`id` を設定します。一意性のチェックが実行されます。\"\n\n#: ../../xml-class.rst:57 783861b6af6e44bc8733b76733ec5da5\nmsgid \":meth:`~.set_italic`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:57 0701120232e24ab7a942c75085ee4917\nmsgid \"Set italic on or off or to some string value.\"\nmsgstr \"イタリック体をオンまたはオフ、または一部の文字列値に設定します。\"\n\n#: ../../xml-class.rst:58 309c49d3870449faa199927e29c64b96\nmsgid \":meth:`~.set_leading`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:58 ../../xml-class.rst:249\n#: 040c50bebd594591ae1e863aa20683a6 dd67658b9d3349cc89ede4628205f1df\nmsgid \"\"\n\"Set inter-block text distance (`-mupdf-leading`), only works on block-\"\n\"level nodes.\"\nmsgstr \"インターブロックテキスト間の距離（`-mupdf-leading`）を設定します。ブロックレベルのノードでのみ機能します。\"\n\n#: ../../xml-class.rst:59 2281f01a10cb44209c22340d5f31c661\nmsgid \":meth:`~.set_lineheight`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:59 5fd19f3c7efd41d6be0dd0d482afa714\nmsgid \"Set height of a line. Float like 1.5, which sets to `1.5 * fontsize`.\"\nmsgstr \"行の高さを設定します。1.5のような浮動小数点数は、`1.5 * fontsize` に設定します。\"\n\n#: ../../xml-class.rst:60 da10321480c547bd877d788cbbc17d19\nmsgid \":meth:`~.set_margins`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:60 562e9cf200d04d618d6ce2d9d0199a52\nmsgid \"Set the margin(s), float or string with up to 4 values.\"\nmsgstr \"マージンを設定します。浮動小数点数または最大4つの値を持つ文字列です。\"\n\n#: ../../xml-class.rst:61 7a9720be94704744b9ffc66d54860d47\nmsgid \":meth:`~.set_pagebreak_after`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:61 ../../xml-class.rst:267\n#: 2e26773bf354417d9a1e518e237918a0 b15db1fb04a94a9db2c92c13e5185080\nmsgid \"Insert a page break after this node.\"\nmsgstr \"このノードの後に改ページを挿入します。\"\n\n#: ../../xml-class.rst:62 6f6e3d153b3b4739bb09a561522007a6\nmsgid \":meth:`~.set_pagebreak_before`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:62 ../../xml-class.rst:271\n#: 7136cfd22a9d457a97a7e2513a45846f c2118e0dbcda4f5da4addfd12c35aa83\nmsgid \"Insert a page break before this node.\"\nmsgstr \"このノードの前に改ページを挿入します。\"\n\n#: ../../xml-class.rst:63 1bbac025080541ae80e078311ca65702\nmsgid \":meth:`~.set_properties`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:63 1b2e863de6b347dd9e0815f739335444\nmsgid \"Set any or all desired properties in one call.\"\nmsgstr \"1つの呼び出しで任意またはすべての所望のプロパティを設定します。\"\n\n#: ../../xml-class.rst:64 5b7ad8cc67534183884e12223b204bfb\nmsgid \":meth:`~.add_style`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:64 b48568e9492448fea987302ce3977624\nmsgid \"Set (add) a “style” that is not supported by its own `set_` method.\"\nmsgstr \"独自の `set_` メソッドでサポートされていない \\\"スタイル\\\" を設定（追加）します。\"\n\n#: ../../xml-class.rst:65 eeab444cf1874576b113c84b0127b3e9\nmsgid \":meth:`~.add_class`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:65 c6c3f6a173aa4093ad84ff360356b54b\nmsgid \"Set (add) a “class” attribute.\"\nmsgstr \"\\\"クラス\\\" 属性を設定（追加）します。\"\n\n#: ../../xml-class.rst:66 dacd474bcc8e488ab2843c5b8e98be3a\nmsgid \":meth:`~.set_text_indent`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:66 2a9fa4287d5043b38c543cccd188d907\nmsgid \"\"\n\"Set indentation for first textblock line. Only works for block-level \"\n\"nodes.\"\nmsgstr \"最初のテキストブロック行のインデントを設定します。ブロックレベルのノードでのみ機能します。\"\n\n#: ../../xml-class.rst:67 42123ce0b6f24506853dac4a1af569fa\nmsgid \":attr:`~.tagname`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:67 ../../xml-class.rst:370\n#: 36166f24a5d84c408d14f9f1a2dc2468 b8920a310a044b1987fdc6fed230bf95\nmsgid \"Either the HTML tag name like :htmlTag:`p` or `None` if a text node.\"\nmsgstr \"HTMLタグ名（例: :htmlTag:`p`）またはテキストノードの場合は `None`。\"\n\n#: ../../xml-class.rst:68 66c56dbdcc064ee483ccc6e18e6d9785\nmsgid \":attr:`~.text`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:68 ../../xml-class.rst:374\n#: 28401b8b52b2423a8c4aa49d5fc3591b e4b6e887c7244003973e168bacadf31e\nmsgid \"Either the node's text or `None` if a tag node.\"\nmsgstr \"ノードのテキストまたはテキストノードの場合は `None`。\"\n\n#: ../../xml-class.rst:69 4a66c8e044cb475fa6fb2613a94f66e3\nmsgid \":attr:`~.is_text`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:69 ca0266179d7442349348788c2abfc7fa\nmsgid \"Check if the node is a text.\"\nmsgstr \"ノードがテキストかどうかを確認します。\"\n\n#: ../../xml-class.rst:70 e5f96a9fc17b4e368cfce3ef779be88c\nmsgid \":attr:`~.first_child`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:70 ../../xml-class.rst:382\n#: 2f21de8ea3a74f8e8afccd49d6b046bc 42e3ed28baa943f6a3b5b61eebe41952\nmsgid \"Contains the first node one level below this one (or `None`).\"\nmsgstr \"このノードの1レベル下の最初のノードを含みます（または `None`）。\"\n\n#: ../../xml-class.rst:71 84b9f06f42b04e4782acf1d68068c5b4\nmsgid \":attr:`~.last_child`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:71 ../../xml-class.rst:386\n#: 2c94509d8b3b40b4b94c1944dca9f128 676901a092fc4735b224b379bb0c3f9f\nmsgid \"Contains the last node one level below this one (or `None`).\"\nmsgstr \"このノードの1レベル下の最後のノードを含みます（または `None`）。\"\n\n#: ../../xml-class.rst:72 3dd91ae4326f41568dfd754dde88c7a4\nmsgid \":attr:`~.next`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:72 ../../xml-class.rst:390\n#: cbabeaa3eefd40249b4dd37b701d59cc d36f34064bfa40a0a40827e73a241423\nmsgid \"The next node at the same level (or `None`).\"\nmsgstr \"同じレベルの次のノード（または `None`）。\"\n\n#: ../../xml-class.rst:73 7a0463bd4ac7449dabbfab5a78bbbdd0\nmsgid \":attr:`~.previous`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:73 ../../xml-class.rst:394\n#: 21ccb8eec1544ac69539f5504e1c2572 3bc7b50ddc0d48a1b11a3a42ff6bf3ff\nmsgid \"The previous node at the same level.\"\nmsgstr \"同じレベルの前のノード。\"\n\n#: ../../xml-class.rst:74 d61cc5bbd1f146c7972c2ebfc6200683\nmsgid \":attr:`~.root`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:74 ../../xml-class.rst:398\n#: a71d233f5e2e429eb0443f3879620f09 cd5e5bf55358464abc8f27b0b2c4c712\nmsgid \"The top node of the DOM, which hence has the tagname :htmlTag:`html`.\"\nmsgstr \"DOMのトップノードで、したがって :htmlTag:`html` というタグ名を持っています。\"\n\n#: ../../xml-class.rst:79 7b4df043605440d3bb688f84d119f814\nmsgid \"**Class API**\"\nmsgstr \"**クラスAPI**\"\n\n#: ../../xml-class.rst:85 15f567e4f1754a959a432aa258e0d91d\nmsgid \"\"\n\"Add an :htmlTag:`ul` tag - bulleted list, context manager. See `ul \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul>`_.\"\nmsgstr \"\"\n\":htmlTag:`ul` タグ（箇条書きリスト）を追加します。コンテキスト マネージャーです。詳細は `ul \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul>`_ \"\n\"を参照してください。\"\n\n#: ../../xml-class.rst:89 3c04822b8860402a8b9573c54e5194e3\nmsgid \"\"\n\"Add a :htmlTag:`pre` tag, context manager. See `pre \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre>`_.\"\nmsgstr \"\"\n\":htmlTag:`pre` タグ（コードブロック）を追加します。コンテキスト マネージャーです。詳細は `pre \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre>`_ \"\n\"を参照してください。\"\n\n#: ../../xml-class.rst:93 0ed1cc73e1274f0a9666e87961987c78\nmsgid \"\"\n\"Add a :htmlTag:`dl` tag, context manager. See `dl \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl>`_.\"\nmsgstr \"\"\n\":htmlTag:`dl` タグ（説明リスト）を追加します。コンテキスト マネージャーです。詳細は `dl \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl>`_ \"\n\"を参照してください。\"\n\n#: ../../xml-class.rst:97 0b0a1eaefbc1441fbd61bce939f12692\nmsgid \"\"\n\"Add a :htmlTag:`div` tag, context manager. See `div \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div>`_.\"\nmsgstr \"\"\n\":htmlTag:`div` タグを追加します。コンテキスト マネージャーです。詳細は `div \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div>`_ \"\n\"を参照してください。\"\n\n#: ../../xml-class.rst:101 8be2c66a14014d738a580d04d0c21248\nmsgid \"\"\n\"Add a header tag (one of :htmlTag:`h1` to :htmlTag:`h6`), context \"\n\"manager. See `headings <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/Heading_Elements>`_.\"\nmsgstr \"\"\n\"ヘッダータグ（:htmlTag:`h1` から :htmlTag:`h6` のいずれか）を追加します。コンテキスト マネージャーです。詳細は \"\n\"`見出し <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/Heading_Elements>`_ を参照してください。\"\n\n#: ../../xml-class.rst 06667ae7d009417a97c1ecf590b1a67f\n#: 0aaa5b3f295942ebbbccb8d389cd898a 1aa126b038ed4ce781aecf808c57cdec\n#: 1d2b1dade7d6423bb8e41f0972a59fb3 1d556e1aced24a5a8be36537a9f59e1b\n#: 1e0cf1d1d2054403831bfb69810ee742 255c1340c66245b48f2a3cdf80e4214c\n#: 2c0eea03634e486dabab3f54b424fad2 46aa4928a5604814a92adf164d7fa247\n#: 49455d15a82740859665ec07012100a3 61e61452d3f94579997370f901426bce\n#: 67c4ccac4676478495f011032187051d 6e85e6b82e584e458e9f10f45aeaf176\n#: 9079b60e1ede4c158bdcc07baa224b19 a1450c78b0a74e7a9a133091ddb6e387\n#: a90aa7ae4f834d88b627c22105ee12ce cc4f042b90394b9eb95de870938d8c43\n#: d0e84706994a47c4aad671254c7a85e2 d1095b66b77e4a72a9793960df3fa674\n#: d23494315ac041c791e01f27f2af929e d96c7bfed45740ec810afcba0125a60a\n#: dd18489673354a54a1e8b0d472e4d131 e1d5789d094643a8b45b8b3c59f908b1\n#: e6d0fce46e4a49ef89c56b78e0914a3f edfbbc1dbdd840519996cc595579ac32\n#: f5a2500942f844c3ba7e25042d206f66 f9e99192da7d40888802688752c7595e\nmsgid \"Parameters\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:103 05de048c66ba4b459eb9539250326096\nmsgid \"a value 1 - 6.\"\nmsgstr \"値（1 - 6）。\"\n\n#: ../../xml-class.rst:107 2c297e02768c469799efc10e37822f0e\nmsgid \"\"\n\"Add a :htmlTag:`hr` tag. See `hr <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/hr>`_.\"\nmsgstr \"\"\n\":htmlTag:`hr` タグを追加します。詳細は `hr <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/hr>`_ を参照してください。\"\n\n#: ../../xml-class.rst:111 b970bd7ba2b14e329f30ab7f38392367\nmsgid \"\"\n\"Add an :htmlTag:`img` tag. This causes the inclusion of the named image \"\n\"in the DOM.\"\nmsgstr \":htmlTag:`img` タグを追加します。これにより、指定された名前の画像が DOM に含まれます。\"\n\n#: ../../xml-class.rst:113 9fae2f8598bf4a7b873ba77fe44e109d\nmsgid \"\"\n\"the filename of the image. This **must be the member name** of some entry\"\n\" of the :ref:`Archive` parameter of the :ref:`Story` constructor.\"\nmsgstr \"\"\n\"画像のファイル名。これは :ref:`Story` コンストラクタの :ref:`Archive` パラメータのエントリの \"\n\"**メンバー名である必要があります** 。\"\n\n#: ../../xml-class.rst:114 f86a37a277f94897a82aefd1205cbb77\nmsgid \"\"\n\"if provided, either an absolute (int) value, or a percentage string like \"\n\"\\\"30%\\\". A percentage value refers to the width of the specified `where` \"\n\"rectangle in :meth:`Story.place`. If this value is provided and `height` \"\n\"is omitted, the image will be included keeping its aspect ratio.\"\nmsgstr \"\"\n\"提供された場合、絶対値（int）または「30%」などのパーセンテージ文字列。パーセンテージ値は :meth:`Story.place` \"\n\"で指定された `where` の長方形の幅を指します。この値が提供され、`height` \"\n\"が省略された場合、画像はアスペクト比を保持したまま含まれます。\"\n\n#: ../../xml-class.rst:115 fb3d1d9e2800433b822fc09a4d7e5b38\nmsgid \"\"\n\"if provided, either an absolute (int) value, or a percentage string like \"\n\"\\\"30%\\\". A percentage value refers to the height of the specified `where`\"\n\" rectangle in :meth:`Story.place`. If this value is provided and `width` \"\n\"is omitted, the image's aspect ratio will be honored.\"\nmsgstr \"\"\n\"提供された場合、絶対値（int）または「30%」などのパーセンテージ文字列。パーセンテージ値は :meth:`Story.place` \"\n\"で指定された `where` 長方形の高さを指します。この値が提供され、`width` が省略された場合、画像のアスペクト比が維持されます。\"\n\n#: ../../xml-class.rst:119 7dc5d5cd96ba453683175419ccf0139d\nmsgid \"Add an :htmlTag:`a` tag - inline element, treated like text.\"\nmsgstr \":htmlTag:`a` タグを追加します - インライン要素で、テキストのように扱われます。\"\n\n#: ../../xml-class.rst:121 0e78457bb88a440b916bc48c1587500a\nmsgid \"the URL target.\"\nmsgstr \"URL の対象。\"\n\n#: ../../xml-class.rst:122 29694751dcf94583ab50b52f45eac3c5\nmsgid \"the text to display. If omitted, the `href` text is shown instead.\"\nmsgstr \"表示するテキスト。省略した場合、`href` のテキストが代わりに表示されます。\"\n\n#: ../../xml-class.rst:126 b5e405fe3b834289ba24aee22e844046\nmsgid \"Add an :htmlTag:`ol` tag, context manager.\"\nmsgstr \":htmlTag:`ol` タグを追加します。コンテキストマネージャーです。\"\n\n#: ../../xml-class.rst:130 76fa57288ce94e5f83f0c2179b72bfe6\nmsgid \"Add a :htmlTag:`p` tag, context manager.\"\nmsgstr \":htmlTag:`p` タグを追加します。コンテキストマネージャーです。\"\n\n#: ../../xml-class.rst:134 ab34ee2cc1fd4256ad7020de606ebc05\nmsgid \"Add a :htmlTag:`span` tag, context manager. See `span`_\"\nmsgstr \":htmlTag:`span` タグを追加します。コンテキストマネージャーです。span タグについては `span`_ を参照してください。\"\n\n#: ../../xml-class.rst:138 07628e22868f42ffbcf7ddd9c0ac35d5\nmsgid \"\"\n\"Add \\\"subscript\\\" text(:htmlTag:`sub` tag) - inline element, treated like\"\n\" text.\"\nmsgstr \"\\\"subscript\\\" テキスト（:htmlTag:`sub` タグ）を追加します。テキストと同様に扱われるインライン要素です。\"\n\n#: ../../xml-class.rst:142 dd9903a2ecf4404a9d6accc1e0749f79\nmsgid \"\"\n\"Add \\\"superscript\\\" text (:htmlTag:`sup` tag) - inline element, treated \"\n\"like text.\"\nmsgstr \"\\\"superscript\\\" テキスト（:htmlTag:`sup` タグ）を追加します。テキストと同様に扱われるインライン要素です。\"\n\n#: ../../xml-class.rst:146 ed86a64559ee476a87e5777052bb75fe\nmsgid \"\"\n\"Add \\\"code\\\" text (:htmlTag:`code` tag) - inline element, treated like \"\n\"text.\"\nmsgstr \"\\\"code\\\" テキスト（:htmlTag:`code` タグ）を追加します。テキストと同様に扱われるインライン要素です。\"\n\n#: ../../xml-class.rst:150 23a0e0f64af1407a8d78e8b1fc6eba45\nmsgid \"\"\n\"Add \\\"variable\\\" text (:htmlTag:`var` tag) - inline element, treated like\"\n\" text.\"\nmsgstr \"\\\"variable\\\" テキスト（:htmlTag:`var` タグ）を追加します。テキストと同様に扱われるインライン要素です。\"\n\n#: ../../xml-class.rst:154 16840c2eee994250a111a670c1982c07\nmsgid \"\"\n\"Add \\\"sample output\\\" text (:htmlTag:`samp` tag) - inline element, \"\n\"treated like text.\"\nmsgstr \"\\\"sample output\\\" テキスト（:htmlTag:`samp` タグ）を追加します。テキストと同様に扱われるインライン要素です。\"\n\n#: ../../xml-class.rst:158 c12b71425d2847eb8bde80f536c4c5ca\nmsgid \"\"\n\"Add \\\"keyboard input\\\" text (:htmlTag:`kbd` tag) - inline element, \"\n\"treated like text.\"\nmsgstr \"\\\"keyboard input\\\" テキスト（:htmlTag:`kbd` タグ）を追加します。テキストと同様に扱われるインライン要素です。\"\n\n#: ../../xml-class.rst:166 a0c1e8813cc34b0b905e64b8843960a1\nmsgid \"Set the text alignment. Only works for block-level tags.\"\nmsgstr \"テキストの配置を設定します。ブロックレベルのタグにのみ対応しています。\"\n\n#: ../../xml-class.rst:168 5c1f833338ba45238483066cd6ee050f\nmsgid \"\"\n\"either one of the :ref:`TextAlign` or the `text-align \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/text-align>`_ values.\"\nmsgstr \"\"\n\":ref:`TextAlign` または `text-align <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/text-align>`_ のいずれかの値です。\"\n\n#: ../../xml-class.rst:174 ../../xml-class.rst:187 ../../xml-class.rst:195\n#: 2fe24dbf6c8e491da8d3a7aca96d7db7 a41e1f3d0e3646c4848ce0ef0df0f734\n#: e6ab290bc6c6427aa52cd824b5abcf95\nmsgid \"the name of the attribute.\"\nmsgstr \"属性の名前。\"\n\n#: ../../xml-class.rst:175 d389ba2ac4a34151a91a26102e2b6460\nmsgid \"the (optional) value of the attribute.\"\nmsgstr \"(オプションの) 属性の値。\"\n\n#: ../../xml-class.rst:179 07c3f60cb5574e45abb857f481b45d17\nmsgid \"Retrieve all attributes of the current nodes as a dictionary.\"\nmsgstr \"現在のノードのすべての属性を辞書として取得します。\"\n\n#: ../../xml-class.rst 17192c246086475781cbc2a532fe77f7\n#: 316b287ac38d47998654b66e17120d3c 33b69c8e0c214f7e94b9e785d1d5acb0\n#: 397c2d06aeac40b0a74e6504b51ad4da e796210aabb44877bdc47c5faba1888b\n#: f45ca78bcbb745fd8bf01620b26911ca f470a993feb34859b12a4343388d8e3d\nmsgid \"Returns\"\nmsgstr \"戻り値:\"\n\n#: ../../xml-class.rst:181 9a860899e73444138923297266a09e92\nmsgid \"a dictionary with the attributes and their values of the node.\"\nmsgstr \"ノードの属性とその値を含む辞書。\"\n\n#: ../../xml-class.rst:185 367b3d6b05fe484c8692a5b9fdf0888d\nmsgid \"Get the attribute value of `key`.\"\nmsgstr \"`key` ーの属性値を取得します。\"\n\n#: ../../xml-class.rst:189 0c606e3db4aa43e4b82e63059d8b9056\nmsgid \"a string with the value of `key`.\"\nmsgstr \"`key` ーの値を含む文字列。\"\n\n#: ../../xml-class.rst:193 7ab7a2c9a37a49528c76d65040e92e55\nmsgid \"Remove the attribute `key` from the node.\"\nmsgstr \"ノードから属性 `key` を削除します。\"\n\n#: ../../xml-class.rst:201 4a286ef8c13b4a818402696f63abbbda\nmsgid \"\"\n\"either an RGB value like (255, 0, 0) (for \\\"red\\\") or a valid \"\n\"`background-color <https://developer.mozilla.org/en-US/docs/Web/CSS\"\n\"/background-color>`_ value.\"\nmsgstr \"\"\n\"RGB値（例：(255, 0, 0)、\\\"red\\\"の場合）または有効な `background-color \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/background-color>`_ 値。\"\n\n#: ../../xml-class.rst:207 0c4471f9c34f45e3b376695ecd25ae47\nmsgid \"\"\n\"`True`, `False` or a valid `font-weight <https://developer.mozilla.org\"\n\"/en-US/docs/Web/CSS/font-weight>`_ value.\"\nmsgstr \"\"\n\"`True`、`False`、または有効な `font-weight <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/font-weight>`_ 値。\"\n\n#: ../../xml-class.rst:211 377d0e10d7b548c88d42311255d9ff02\nmsgid \"Set the color of the text following.\"\nmsgstr \"後続するテキストの色を設定します。\"\n\n#: ../../xml-class.rst:213 0596f8f1cc684e51ac8e6a2e58d3f646\nmsgid \"\"\n\"either an RGB value like (255, 0, 0) (for \\\"red\\\") or a valid `color \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/color_value>`_ value.\"\nmsgstr \"\"\n\"RGB値（例：(255, 0, 0)、\\\"red\\\"の場合）または有効な `カラー <https://developer.mozilla.org\"\n\"/en-US/docs/Web/CSS/color_value>`_ 値。\"\n\n#: ../../xml-class.rst:217 9de3ba47655e45ea86e95f7806cc1761\nmsgid \"Set the number of columns.\"\nmsgstr \"列の数を設定します。\"\n\n#: ../../xml-class.rst:219 d767dfd34bba48c2bd824015aedbfce5\nmsgid \"\"\n\"a valid `columns <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/columns>`_ value.\"\nmsgstr \"\"\n\"有効な `columns <https://developer.mozilla.org/en-US/docs/Web/CSS/columns>`_\"\n\" 値。\"\n\n#: ../../xml-class.rst:221 c5ee8d67ed604a779b356ad7a3beb3b6\nmsgid \"Currently ignored - supported in a future MuPDF version.\"\nmsgstr \"現在は無視されており、将来のMuPDFバージョンでサポートされます。\"\n\n#: ../../xml-class.rst:225 a3e16b087cf149fbbf6f316ad7d79880\nmsgid \"Set the font-family.\"\nmsgstr \"フォントファミリーを設定します。\"\n\n#: ../../xml-class.rst:227 56592161ded1480aa5c21631ec00e5ac\nmsgid \"e.g. \\\"sans-serif\\\".\"\nmsgstr \"例：\\\"sans-serif\\\"など。\"\n\n#: ../../xml-class.rst:231 e716de072f9544618374c016b382f40a\nmsgid \"Set the font size for text following.\"\nmsgstr \"後続するテキストのフォントサイズを設定します。\"\n\n#: ../../xml-class.rst:233 4699b76ad7694bccbd943643ee021862\nmsgid \"\"\n\"a float or a valid `font-size <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/font-size>`_ value.\"\nmsgstr \"\"\n\"floatまたは有効な `font-size <https://developer.mozilla.org/en-US/docs/Web/CSS\"\n\"/font-size>`_ 値。\"\n\n#: ../../xml-class.rst:237 8cfd620b051940348ac0556e9ae65033\nmsgid \"\"\n\"Set a :htmlTag:`id`. This serves as a unique identification of the node \"\n\"within the DOM. Use it to easily locate the node to inspect or modify it.\"\n\" A check for uniqueness is performed.\"\nmsgstr \"\"\n\":htmlTag:`id` \"\n\"を設定します。これはDOM内でノードを一意に識別するためのもので、ノードを簡単に見つけて調査または変更するために使用します。一意性のチェックが実行されます。\"\n\n#: ../../xml-class.rst:239 b6042d6da5b14d338da93ff2ac9afdc3\nmsgid \"id string of the node.\"\nmsgstr \"ノードのID文字列。\"\n\n#: ../../xml-class.rst:243 83dcfa78795e4c169619f1b4203a95f7\nmsgid \"Set italic on or off or to some string value for the text following it.\"\nmsgstr \"後続するテキストのイタリックをオンまたはオフ、または一部の有効なフォントスタイル値に設定します。\"\n\n#: ../../xml-class.rst:245 e74b3e4a56714306840b8bd5cdcfb8b6\nmsgid \"\"\n\"`True`, `False` or some valid `font-style <https://developer.mozilla.org\"\n\"/en-US/docs/Web/CSS/font-style>`_ value.\"\nmsgstr \"\"\n\"`True`、`False`、または有効な `font-style <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/font-style>`_ 値。\"\n\n#: ../../xml-class.rst:251 b9a0bdede6124f1fbbde6722313e5c2c\nmsgid \"the distance in points to the previous block.\"\nmsgstr \"前のブロックからの距離（ポイント単位）。\"\n\n#: ../../xml-class.rst:255 f13883ee98f146ca9a924b575b3cc51a\nmsgid \"Set height of a line.\"\nmsgstr \"行の高さを設定します。\"\n\n#: ../../xml-class.rst:257 74dc61a744d94742a7eb18faf8251006\nmsgid \"\"\n\"a float like 1.5 (which sets to `1.5 * fontsize`), or some valid `line-\"\n\"height <https://developer.mozilla.org/en-US/docs/Web/CSS/line-height>`_ \"\n\"value.\"\nmsgstr \"value – 1.5のような浮動小数点数（これは `1.5 * fontsize`に設定されます）または有効な行の高さの値。\"\n\n#: ../../xml-class.rst:261 f4aeb6cd082e4b039f2ef1c241cffc4a\nmsgid \"Set the margin(s).\"\nmsgstr \"マージン（マージン）を設定します。\"\n\n#: ../../xml-class.rst:263 754876b7c7b84370b81e5f3f15bbae21\nmsgid \"\"\n\"float or string with up to 4 values. See `CSS documentation \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/margin>`_.\"\nmsgstr \"\"\n\"floatまたは最大4つの値を含む文字列。`CSSのドキュメンテーション <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/margin>`_ を参照してください。\"\n\n#: ../../xml-class.rst:275 f2da4761cba1404d8c850cf58d8ba28c\nmsgid \"\"\n\"Set any or all desired properties in one call. The meaning of argument \"\n\"values equal the values of the corresponding `set_` methods.\"\nmsgstr \"一度の呼び出しで任意またはすべての所望のプロパティを設定します。引数の値の意味は、対応する `set_` メソッドの値と同じです。\"\n\n#: ../../xml-class.rst:277 c1f136b0c23e4147aef9acbc054decd4\nmsgid \"\"\n\"The properties set by this method are directly attached to the node, \"\n\"whereas every `set_` method generates a new :htmlTag:`span` below the \"\n\"current node that has the respective property. So to e.g. \\\"globally\\\" \"\n\"set some property for the :htmlTag:`body`, this method must be used.\"\nmsgstr \"\"\n\"このメソッドで設定されるプロパティは、直接ノードにアタッチされますが、`set_` メソッドごとに現在のノードの下に対応するプロパティを持つ新しい\"\n\" :htmlTag:`span` \"\n\"が生成されます。したがって、本文のいくつかのプロパティを「グローバルに」設定するには、このメソッドを使用する必要があります。\"\n\n#: ../../xml-class.rst:281 0b00e9cdb0ed42819aad271da3e10621\nmsgid \"Set (add) some style attribute not supported by its own `set_` method.\"\nmsgstr \"独自の `set_` メソッドでサポートされていないスタイル属性を設定（追加）します。\"\n\n#: ../../xml-class.rst:283 457e6d62d41841ee8741782c6bfd201f\nmsgid \"any valid CSS style value.\"\nmsgstr \"有効なCSSスタイル値。\"\n\n#: ../../xml-class.rst:287 996f4ece67a841e59d001f1d260f6571\nmsgid \"Set (add) some \\\"class\\\" attribute.\"\nmsgstr \"いくつかの「class」属性を設定（追加）します。\"\n\n#: ../../xml-class.rst:289 0cd9ff6d9c4640ab90612ca481fb1692\nmsgid \"\"\n\"the name of the class. Must have been defined in either the HTML or the \"\n\"CSS source of the DOM.\"\nmsgstr \"クラスの名前。DOMのHTMLまたはCSSソースで定義されている必要があります。\"\n\n#: ../../xml-class.rst:293 d40d57c4852c46539d9bdf515833a465\nmsgid \"\"\n\"Set indentation for the first textblock line. Only works for block-level \"\n\"nodes.\"\nmsgstr \"最初のテキストブロックの行のインデントを設定します。ブロックレベルのノードでのみ機能します。\"\n\n#: ../../xml-class.rst:295 0d6bee0b55f24569a45c44d5e814b140\nmsgid \"\"\n\"a valid `text-indent <https://developer.mozilla.org/en-US/docs/Web/CSS\"\n\"/text-indent>`_ value. Please note that negative values do not work.\"\nmsgstr \"\"\n\"有効な `text-indent <https://developer.mozilla.org/en-US/docs/Web/CSS/text-\"\n\"indent>`_ 値。負の値は機能しないことに注意してください。\"\n\n#: ../../xml-class.rst:300 762e7d8fde1d4ad3ba5ae1bf4fa34033\nmsgid \"\"\n\"Append a child node. This is a low-level method used by other methods \"\n\"like :meth:`Xml.add_paragraph`.\"\nmsgstr \"子ノードを追加します。これは、:meth:`Xml.add_paragraph` などの他のメソッドで使用される低レベルのメソッドです。\"\n\n#: ../../xml-class.rst:302 8fe5eebdd2b1421fb687a21dfcea9fae\nmsgid \"the :ref:`Xml` node to append.\"\nmsgstr \"追加する :ref:`Xml` ノード。\"\n\n#: ../../xml-class.rst:308 bb3c5252dd3542cc8f263ab35551dedd\nmsgid \"the text to append.\"\nmsgstr \"追加するテキスト。\"\n\n#: ../../xml-class.rst 022bf50af61d4a8a854203e9ba18a1ce\n#: 70b34bf9aef34db599ca63934a722c36 87a8f73cb5e84da286de4cacee92e249\n#: c5fc1a77039842b2a10f66a29dbdb38e\nmsgid \"Return type\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:310 ../../xml-class.rst:319\n#: 14d3d45c8f9f4c94b76c6b34f9156283 e219f8801a92456dacd23c1bab7c5fa4\nmsgid \":ref:`Xml`\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:311 0ed716b5c85d4de4a0457c85b58e194f\nmsgid \"the created element.\"\nmsgstr \"作成された要素。\"\n\n#: ../../xml-class.rst:315 d82360adfca04cbeac23160c0a0c3afa\nmsgid \"\"\n\"Create a new node with a given tag. This a low-level method used by other\"\n\" methods like :meth:`Xml.add_paragraph`.\"\nmsgstr \"\"\n\"指定されたタグで新しいノードを作成します。これは、:meth:`Xml.add_paragraph` \"\n\"などの他のメソッドで使用される低レベルなメソッドです。\"\n\n#: ../../xml-class.rst:317 9d7b1665fb704f00a0416ea1627c3c3a\nmsgid \"the element tag.\"\nmsgstr \"要素のタグ。\"\n\n#: ../../xml-class.rst:320 ea5c614b041341e1be82c8015fbed2ef\nmsgid \"\"\n\"the created element. To actually bind it to the DOM, use \"\n\":meth:`Xml.append_child`.\"\nmsgstr \"作成された要素。実際にDOMにバインドするには、:meth:`Xml.append_child` を使用します。\"\n\n#: ../../xml-class.rst:324 20a9a38c30524aa7bc65ec6cbe680c47\nmsgid \"Insert the given element `elem` before this node.\"\nmsgstr \"指定された要素 `elem` をこのノードの前に挿入します。\"\n\n#: ../../xml-class.rst:326 ../../xml-class.rst:332\n#: 44a6c046ddfd4baa968b358f7db78b0a 848c5fe3c4bb49ffbb4f55cf1fcd0d94\nmsgid \"some :ref:`Xml` element.\"\nmsgstr \"いくつかの :ref:`Xml` 要素。\"\n\n#: ../../xml-class.rst:330 31950c02ed55490db0883f1568fc5528\nmsgid \"Insert the given element `elem` after this node.\"\nmsgstr \"指定された要素 `elem` をこのノードの後に挿入します。\"\n\n#: ../../xml-class.rst:336 9b8dcc0c94654a25a10773d34514557e\nmsgid \"\"\n\"Make a copy of this node, which then may be appended (using \"\n\":meth:`Xml.append_child`) or inserted (using one of \"\n\":meth:`Xml.insert_before`, :meth:`Xml.insert_after`) in this DOM.\"\nmsgstr \"\"\n\"このノードのコピーを作成し、それをこのDOMに追加（:meth:`Xml.append_child` \"\n\"を使用）または挿入（:meth:`Xml.insert_before` 、:meth:`Xml.insert_after` \"\n\"のいずれかを使用）できるようにします。\"\n\n#: ../../xml-class.rst:338 4f1ca41be752476f906e73d07f12fa64\nmsgid \"the clone (:ref:`Xml`) of the current node.\"\nmsgstr \"現在のノードのクローン（:ref:`Xml`）。\"\n\n#: ../../xml-class.rst:342 0cbed49f156d4211b12cb5bbe7060543\nmsgid \"Remove this node from the DOM.\"\nmsgstr \"このノードをDOMから削除します。\"\n\n#: ../../xml-class.rst:347 ef3d6f9aa85c47ca9abe630e29080e81\nmsgid \"For debugging purposes, print this node's structure in a simplified form.\"\nmsgstr \"デバッグ目的で、このノードの構造を簡略化された形式で表示します。\"\n\n#: ../../xml-class.rst:351 b77052465aff4e6c8134c42867815823\nmsgid \"\"\n\"Under the current node, find the first node with the given `tag`, \"\n\"attribute `att` and value `match`.\"\nmsgstr \"現在のノードの下で、指定された `tag` 、属性 `att`、値 `match` を持つ最初のノードを検索します。\"\n\n#: ../../xml-class.rst:353 c3b5cf81b4a8466aaf9a51d9aa91aed8\nmsgid \"restrict search to this tag. May be `None` for unrestricted searches.\"\nmsgstr \"このタグに制限して検索します。無制限の検索の場合は `None` にできます。\"\n\n#: ../../xml-class.rst:354 b3e60cf5c1694489b76c6b061502d815\nmsgid \"check this attribute. May be `None`.\"\nmsgstr \"この属性を確認します。`None` にできます。\"\n\n#: ../../xml-class.rst:355 445027aad8f349d5870b74bc71484e02\nmsgid \"the desired attribute value to match. May be `None`.\"\nmsgstr \"致する属性値を指定します。`None` にできます。\"\n\n#: ../../xml-class.rst:357 ../../xml-class.rst:364\n#: 458a0f17635a4ee3beaeda11ffc6cf06 d2fbb5102700450a865b3f902ceac384\nmsgid \":ref:`Xml`.\"\nmsgstr \"\"\n\n#: ../../xml-class.rst:358 b5de014d478e4703b88e1c98ad4dd9dd\nmsgid \"`None` if nothing found, otherwise the first matching node.\"\nmsgstr \"何も見つからない場合は `None`、それ以外の場合は最初の一致するノード。\"\n\n#: ../../xml-class.rst:362 bfac5489d037476889d72ff8311df153\n#, fuzzy\nmsgid \"\"\n\"Continue a previous :meth:`Xml.find` (or :meth:`find_next`) with the same\"\n\" values.\"\nmsgstr \"以前の :meth:`Xml.find`（または :meth:`find_next` ）を同じ値で継続します。\"\n\n#: ../../xml-class.rst:365 6e37f5e14b8849b1abe7bf97c7015bc2\nmsgid \"`None` if none more found, otherwise the next matching node.\"\nmsgstr \"それ以上見つからない場合は `None`、それ以外の場合は次の一致するノード。\"\n\n#: ../../xml-class.rst:378 b1a7309c8f0f4aebb4c722ef9ac56d8f\nmsgid \"Check if a text node.\"\nmsgstr \"テキストノードであるかどうかを確認します。\"\n\n#: ../../xml-class.rst:402 277f48d6971041c6949eb351109c59a6\nmsgid \"Setting Text properties\"\nmsgstr \"テキストのプロパティを設定する\"\n\n#: ../../xml-class.rst:404 e4aa8bc7dde5406984bba698ad774b6a\nmsgid \"\"\n\"In HTML tags can be nested such that innermost text **inherits \"\n\"properties** from the tag enveloping its parent tag. For example \"\n\"`<p><b>some bold text<i>this is bold and italic</i></b>regular text</p>`.\"\nmsgstr \"\"\n\"HTMLでは、タグはネストされることがあり、最も内側のテキストは親タグに囲まれたタグから **プロパティを継承します** \"\n\"。たとえば、`<p><b>some bold text<i>this is bold and italic</i></b>regular \"\n\"text</p>`。\"\n\n#: ../../xml-class.rst:406 231ae74dcdca47a1af2c04684d880e45\nmsgid \"\"\n\"To achieve the same effect, methods like :meth:`Xml.set_bold` and \"\n\":meth:`Xml.set_italic` each open a temporary :htmlTag:`span` with the \"\n\"desired property underneath the current node.\"\nmsgstr \"\"\n\"同じ効果を得るために、:meth:`Xml.set_bold` や :meth:`Xml.set_italic` \"\n\"などのメソッドは、各々所望のプロパティを持つ一時的な :htmlTag:`span` を現在のノードの下に追加します。\"\n\n#: ../../xml-class.rst:408 703c755313884c3e8e069b836f756d47\nmsgid \"\"\n\"In addition, these methods return there parent node, so they can be \"\n\"concatenated with each other.\"\nmsgstr \"さらに、これらのメソッドは親ノードを返すため、それらを連結することができます。\"\n\n#: ../../xml-class.rst:413 1317fdaa53304e249c7283355ae5ebb4\nmsgid \"Context Manager support\"\nmsgstr \"コンテキストマネージャのサポート\"\n\n#: ../../xml-class.rst:414 66b960c3bdd444e0a671fd3e9b81e5a1\nmsgid \"The standard way to add nodes to a DOM is this::\"\nmsgstr \"DOMにノードを追加する標準的な方法は次のとおりです::\"\n\n#: ../../xml-class.rst:427 945235d10eaf46368506481d321761b5\nmsgid \"\"\n\"Methods that are flagged as \\\"context managers\\\" can conveniently be used\"\n\" in this way::\"\nmsgstr \"コンテキストマネージャとしてフラグが付いているメソッドは、次のように便利に使用できます::\"\n\n#: ../../footer.rst:60 1b8fa4a6d5c14ec9becef06082bce778\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ja/LC_MESSAGES/znames.po",
    "content": "# PyMuPDF Japanese documentation\n# Copyright (C) 2015-2023, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# Jamie Lemon <jamie.lemon@artifex.com>, 2023.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.23.0rc1\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-04-17 15:00+0100\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: Suzan Sanver <suzan.sanver@dijipiji.com>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <suzan.sanver@dijipiji.com>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 0f9441fa95204b209542b6195fa33e94\nmsgid \"Artifex\"\nmsgstr \"\"\n\n#: ../../header.rst:-1 b494c998c5e441c78282bc408dffff8c\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n\n#: ../../header.rst:-1 6067a6dd9e5242e4b0ce1d3b3ce3b293\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n\n#: ../../znames.rst:7 873beb2a37544c07b1a5e70eca5650fe\nmsgid \"Deprecated Names\"\nmsgstr \"非推奨の名前\"\n\n#: ../../znames.rst:9 78ca6b2b094c43dab0f3efb7a1340a0f\nmsgid \"\"\n\"The original naming convention for methods and properties has been \"\n\"\\\"camelCase\\\". Since its creation around 2013, a tremendous increase of \"\n\"functionality has happened in PyMuPDF -- and with it a corresponding \"\n\"increase in classes, methods and properties. In too many cases, this has \"\n\"led to non-intuitive, illogical and ugly names, difficult to memorize or \"\n\"guess.\"\nmsgstr \"メソッドやプロパティの元々の命名規則は「camelCase」でした。その創造以来、PyMuPDFでの機能の著しい増加がありました。それに伴い、クラス、メソッド、プロパティも対応するように増加しました。多くの場合、これにより直感に反した、論理的でなく見栄えのしない名前が生まれ、覚えたり推測したりが難しくなりました。\"\n\n#: ../../znames.rst:11 96fde94d6cb6460bb374c4c18ab3c5f2\nmsgid \"\"\n\"A few versions ago, I therefore decided to shift gears and switch to a \"\n\"\\\"snake_cased\\\" naming standard. This was a major effort, which needed a \"\n\"step-wise approach. I think am done with it now (version 1.18.14).\"\nmsgstr \"数バージョン前、私はゆえに、段階的なアプローチが必要な大規模な取り組みであったにもかかわらず、「snake_cased」の命名規則に切り替えることを決定しました。これは大きな努力が必要でした。今はそれが完了したと思っています（バージョン1.18.14）。\"\n\n#: ../../znames.rst:14 f1aba321b49d4a50b23fd84d5435c403\nmsgid \"\"\n\"The following list maps deprecated names to their new versions. For \"\n\"example, property `pageCount` became `page_count` in the :ref:`Document` \"\n\"class. There also are less obvious name changes, e.g. method `getPNGdata`\"\n\" was renamed to `tobytes` in the :ref:`Pixmap` class.\"\nmsgstr \"\"\n\"以下のリストは、非推奨の名前とそれらの新しいバージョンを対応付けたものです。例えば、プロパティである `pageCount` は、 \"\n\":ref:`Document` クラス内では `page_count` \"\n\"となりました。また、より明らかでない名前の変更もあります。例えば、メソッドである `getPNGdata` は :ref:`Pixmap` \"\n\"クラス内で `tobytes` という名前に変更されました。\"\n\n#: ../../znames.rst:16 da72cacf26b1418ebcdd799307695e7f\nmsgid \"\"\n\"Names of classes (camel case) and package-wide constants (the majority is\"\n\" upper case) remain untouched.\"\nmsgstr \"クラスの名前（キャメルケース）やパッケージ全体の定数（大部分は大文字）については、触れずに残ります。\"\n\n#: ../../znames.rst:18 8caf5f400d46465da41396c978125459\nmsgid \"\"\n\"Old names will remain available as deprecated aliases through MuPDF \"\n\"version 1.19.0 and **be removed** in the version that follows it - \"\n\"probably version 1.20.0, but this depends on upstream decisions (MuPDF).\"\nmsgstr \"\"\n\"古い名前は、MuPDFバージョン1.19.0まで非推奨のエイリアスとして利用可能であり、その後のバージョン（おそらくバージョン1.20.0ですが、これは上流の決定（MuPDF）に依存します）で\"\n\" **削除されます** 。\"\n\n#: ../../znames.rst:20 196848a51a5e49d58753a2b5715c07b8\nmsgid \"\"\n\"Starting with version 1.19.0, we will issue deprecation warnings on \"\n\"`sys.stderr` like `Deprecation: 'newPage' removed from class 'Document' \"\n\"after v1.19.0 - use 'new_page'.` when aliased methods are being used. \"\n\"Using a deprecated property will not cause this type of warning.\"\nmsgstr \"\"\n\"バージョン1.19.0以降、エイリアス化されたメソッドが使用されている場合、 `sys.stderr` に非推奨の警告が表示されます。例 \"\n\"`Deprecation: 'newPage'はクラス 'Document'からv1.19.0以降で削除されました - 'new_page'` \"\n\"を使用してください。非推奨のプロパティを使用した場合、このタイプの警告は発生しません。\"\n\n#: ../../znames.rst:22 fd326a4ad3c94bfb8d5f9569d40f630d\nmsgid \"\"\n\"Starting immediately, all deprecated objects (methods and properties) \"\n\"will show a copy of the original's docstring, **prefixed** with the \"\n\"deprecation message, for example::\"\nmsgstr \"\"\n\"直ちに、すべての非推奨のオブジェクト（メソッドとプロパティ）は、元のドキュメント文字列のコピーが表示され、その前に非推奨のメッセージが \"\n\"**付加されます** 。例：\"\n\n#: ../../znames.rst:39 7ba1507fe4c94e149d0b1642bd1f770f\nmsgid \"\"\n\"There is a utility script `alias-changer.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/alias-changer.py>`_ which can be used to \"\n\"do mass-renames in your scripts. It accepts either a single file or a \"\n\"folder as argument. If a folder is supplied, all its Python files and \"\n\"those of its subfolders are changed. Optionally, backups of the scripts \"\n\"can be taken.\"\nmsgstr \"\"\n\"スクリプト `alias-changer.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/alias-changer.py>` \"\n\"があり、スクリプト内で大量の名前変更を行うために使用できます。単一のファイルまたはフォルダを引数として受け入れます。フォルダが指定された場合、そのフォルダ内のすべてのPythonファイルおよびそのサブフォルダのファイルが変更されます。必要に応じて、スクリプトのバックアップを取ることもできます。\"\n\n#: ../../footer.rst:60 317892866ae648e99963bb6a51525df6\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"このドキュメントは |version| までのすべてのバージョンを対象としています。\"\n\n#~ msgid \"PyMuPDF は、PDF （およびその他の）ドキュメントのデータ抽出、分析、変換、操作のための高性能な Python ライブラリです。\"\n#~ msgstr \"\"\n\n#~ msgid \"PDFテキスト抽出、PDFイメージ抽出、PDF変換、PDFテーブル、PDF分割、PDF作成, Pyodide, PyScript\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Deprecated names are not separately \"\n#~ \"documented. The following list will help\"\n#~ \" you find the documentation of the\"\n#~ \" original.\"\n#~ msgstr \"非推奨の名前は別途文書化されていません。以下のリストは、元のドキュメントの検索に役立ちます。\"\n\n#~ msgid \"\"\n#~ \"This is automatically generated. One or\"\n#~ \" two items refer to yet undocumented\"\n#~ \" methods - please simply ignore them.\"\n#~ msgstr \"これは自動的に生成されたものです。1または2のアイテムはまだ文書化されていないメソッドを参照していますが、無視してください。\"\n\n#~ msgid \":index:`_isWrapped` -- :attr:`Page.is_wrapped`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addCaretAnnot` -- :meth:`Page.add_caret_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addCircleAnnot` -- :meth:`Page.add_circle_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addFileAnnot` -- :meth:`Page.add_file_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addFreetextAnnot` -- :meth:`Page.add_freetext_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addHighlightAnnot` -- :meth:`Page.add_highlight_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addInkAnnot` -- :meth:`Page.add_ink_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addLineAnnot` -- :meth:`Page.add_line_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addPolygonAnnot` -- :meth:`Page.add_polygon_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addPolylineAnnot` -- :meth:`Page.add_polyline_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addRectAnnot` -- :meth:`Page.add_rect_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addRedactAnnot` -- :meth:`Page.add_redact_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addSquigglyAnnot` -- :meth:`Page.add_squiggly_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addStampAnnot` -- :meth:`Page.add_stamp_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addStrikeoutAnnot` -- :meth:`Page.add_strikeout_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addTextAnnot` -- :meth:`Page.add_text_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addUnderlineAnnot` -- :meth:`Page.add_underline_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`addWidget` -- :meth:`Page.add_widget`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`chapterCount` -- :attr:`Document.chapter_count`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`chapterPageCount` -- :meth:`Document.chapter_page_count`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`cleanContents` -- :meth:`Page.clean_contents`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`clearWith` -- :meth:`Pixmap.clear_with`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`convertToPDF` -- :meth:`Document.convert_to_pdf`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`copyPage` -- :meth:`Document.copy_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`copyPixmap` -- :meth:`Pixmap.copy`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`CropBox` -- :attr:`Page.cropbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`CropBoxPosition` -- :attr:`Page.cropbox_position`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`deleteAnnot` -- :meth:`Page.delete_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`deleteLink` -- :meth:`Page.delete_link`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`deletePage` -- :meth:`Document.delete_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`deletePageRange` -- :meth:`Document.delete_pages`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`deleteWidget` -- :meth:`Page.delete_widget`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`derotationMatrix` -- :attr:`Page.derotation_matrix`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawBezier` -- :meth:`Page.draw_bezier`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawBezier` -- :meth:`Shape.draw_bezier`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawCircle` -- :meth:`Page.draw_circle`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawCircle` -- :meth:`Shape.draw_circle`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawCurve` -- :meth:`Page.draw_curve`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawCurve` -- :meth:`Shape.draw_curve`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawLine` -- :meth:`Page.draw_line`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawLine` -- :meth:`Shape.draw_line`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawOval` -- :meth:`Page.draw_oval`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawOval` -- :meth:`Shape.draw_oval`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawPolyline` -- :meth:`Page.draw_polyline`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawPolyline` -- :meth:`Shape.draw_polyline`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawQuad` -- :meth:`Page.draw_quad`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawQuad` -- :meth:`Shape.draw_quad`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawRect` -- :meth:`Page.draw_rect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawRect` -- :meth:`Shape.draw_rect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawSector` -- :meth:`Page.draw_sector`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawSector` -- :meth:`Shape.draw_sector`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawSquiggle` -- :meth:`Page.draw_squiggle`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawSquiggle` -- :meth:`Shape.draw_squiggle`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawZigzag` -- :meth:`Page.draw_zigzag`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`drawZigzag` -- :meth:`Shape.draw_zigzag`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`embeddedFileAdd` -- :meth:`Document.embfile_add`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`embeddedFileCount` -- :meth:`Document.embfile_count`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`embeddedFileDel` -- :meth:`Document.embfile_del`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`embeddedFileGet` -- :meth:`Document.embfile_get`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`embeddedFileInfo` -- :meth:`Document.embfile_info`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`embeddedFileNames` -- :meth:`Document.embfile_names`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`embeddedFileUpd` -- :meth:`Document.embfile_upd`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`extractFont` -- :meth:`Document.extract_font`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`extractImage` -- :meth:`Document.extract_image`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`fileGet` -- :meth:`Annot.get_file`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`fileUpd` -- :meth:`Annot.update_file`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`fillTextbox` -- :meth:`TextWriter.fill_textbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`findBookmark` -- :meth:`Document.find_bookmark`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`firstAnnot` -- :attr:`Page.first_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`firstLink` -- :attr:`Page.first_link`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`firstWidget` -- :attr:`Page.first_widget`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`fullcopyPage` -- :meth:`Document.fullcopy_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`gammaWith` -- :meth:`Pixmap.gamma_with`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getArea` -- :meth:`Rect.get_area`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getArea` -- :meth:`IRect.get_area`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getCharWidths` -- :meth:`Document.get_char_widths`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getContents` -- :meth:`Page.get_contents`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getDisplayList` -- :meth:`Page.get_displaylist`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getDrawings` -- :meth:`Page.get_drawings`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getFontList` -- :meth:`Page.get_fonts`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getImageBbox` -- :meth:`Page.get_image_bbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getImageData` -- :meth:`Pixmap.tobytes`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getImageList` -- :meth:`Page.get_images`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getLinks` -- :meth:`Page.get_links`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getOCGs` -- :meth:`Document.get_ocgs`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPageFontList` -- :meth:`Document.get_page_fonts`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPageImageList` -- :meth:`Document.get_page_images`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPagePixmap` -- :meth:`Document.get_page_pixmap`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPageText` -- :meth:`Document.get_page_text`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPageXObjectList` -- :meth:`Document.get_page_xobjects`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPDFnow` -- :meth:`get_pdf_now`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPDFstr` -- :meth:`get_pdf_str`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPixmap` -- :meth:`Page.get_pixmap`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPixmap` -- :meth:`Annot.get_pixmap`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPixmap` -- :meth:`DisplayList.get_pixmap`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPNGData` -- :meth:`Pixmap.tobytes`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getPNGdata` -- :meth:`Pixmap.tobytes`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getRectArea` -- :meth:`Rect.get_area`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getRectArea` -- :meth:`IRect.get_area`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getSigFlags` -- :meth:`Document.get_sigflags`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getSVGimage` -- :meth:`Page.get_svg_image`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getText` -- :meth:`Page.get_text`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getText` -- :meth:`Annot.get_text`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextBlocks` -- :meth:`Page.get_text_blocks`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextbox` -- :meth:`Page.get_textbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextbox` -- :meth:`Annot.get_textbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextLength` -- :meth:`get_text_length`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextPage` -- :meth:`Page.get_textpage`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextPage` -- :meth:`Annot.get_textpage`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextPage` -- :meth:`DisplayList.get_textpage`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getTextWords` -- :meth:`Page.get_text_words`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getToC` -- :meth:`Document.get_toc`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`getXmlMetadata` -- :meth:`Document.get_xml_metadata`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`ImageProperties` -- :meth:`image_properties`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`includePoint` -- :meth:`Rect.include_point`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`includePoint` -- :meth:`IRect.include_point`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`includeRect` -- :meth:`Rect.include_rect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`includeRect` -- :meth:`IRect.include_rect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertFont` -- :meth:`Page.insert_font`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertImage` -- :meth:`Page.insert_image`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertLink` -- :meth:`Page.insert_link`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertPage` -- :meth:`Document.insert_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertPDF` -- :meth:`Document.insert_pdf`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertText` -- :meth:`Page.insert_text`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertText` -- :meth:`Shape.insert_text`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertTextbox` -- :meth:`Page.insert_textbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`insertTextbox` -- :meth:`Shape.insert_textbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`invertIRect` -- :meth:`Pixmap.invert_irect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isConvex` -- :attr:`Quad.is_convex`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isDirty` -- :attr:`Document.is_dirty`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isEmpty` -- :attr:`Rect.is_empty`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isEmpty` -- :attr:`IRect.is_empty`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isEmpty` -- :attr:`Quad.is_empty`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isFormPDF` -- :attr:`Document.is_form_pdf`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isInfinite` -- :attr:`Rect.is_infinite`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isInfinite` -- :attr:`IRect.is_infinite`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isPDF` -- :attr:`Document.is_pdf`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isRectangular` -- :attr:`Quad.is_rectangular`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isRectilinear` -- :attr:`Matrix.is_rectilinear`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isReflowable` -- :attr:`Document.is_reflowable`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isRepaired` -- :attr:`Document.is_repaired`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`isStream` -- :meth:`Document.is_stream`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`lastLocation` -- :attr:`Document.last_location`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`lineEnds` -- :attr:`Annot.line_ends`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`loadAnnot` -- :meth:`Page.load_annot`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`loadLinks` -- :meth:`Page.load_links`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`loadPage` -- :meth:`Document.load_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`makeBookmark` -- :meth:`Document.make_bookmark`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`MediaBox` -- :attr:`Page.mediabox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`MediaBoxSize` -- :attr:`Page.mediabox_size`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`metadataXML` -- :meth:`Document.xref_xml_metadata`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`movePage` -- :meth:`Document.move_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`needsPass` -- :attr:`Document.needs_pass`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`newPage` -- :meth:`Document.new_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`newShape` -- :meth:`Page.new_shape`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`nextLocation` -- :meth:`Document.next_location`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`pageCount` -- :attr:`Document.page_count`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`pageCropBox` -- :meth:`Document.page_cropbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`pageXref` -- :meth:`Document.page_xref`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`PaperRect` -- :meth:`paper_rect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`PaperSize` -- :meth:`paper_size`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`paperSizes` -- :attr:`paper_sizes`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`PDFCatalog` -- :meth:`Document.pdf_catalog`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`PDFTrailer` -- :meth:`Document.pdf_trailer`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`pillowData` -- :meth:`Pixmap.pil_tobytes`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`pillowWrite` -- :meth:`Pixmap.pil_save`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`planishLine` -- :meth:`planish_line`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`preRotate` -- :meth:`Matrix.prerotate`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`preScale` -- :meth:`Matrix.prescale`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`preShear` -- :meth:`Matrix.preshear`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`preTranslate` -- :meth:`Matrix.pretranslate`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`previousLocation` -- :meth:`Document.prev_location`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`readContents` -- :meth:`Page.read_contents`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`resolveLink` -- :meth:`Document.resolve_link`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`rotationMatrix` -- :attr:`Page.rotation_matrix`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`searchFor` -- :meth:`Page.search_for`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`searchPageFor` -- :meth:`Document.search_page_for`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setAlpha` -- :meth:`Pixmap.set_alpha`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setBlendMode` -- :meth:`Annot.set_blendmode`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setBorder` -- :meth:`Annot.set_border`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setColors` -- :meth:`Annot.set_colors`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setCropBox` -- :meth:`Page.set_cropbox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setFlags` -- :meth:`Annot.set_flags`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setInfo` -- :meth:`Annot.set_info`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setLanguage` -- :meth:`Document.set_language`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setLineEnds` -- :meth:`Annot.set_line_ends`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setMediaBox` -- :meth:`Page.set_mediabox`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setMetadata` -- :meth:`Document.set_metadata`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setName` -- :meth:`Annot.set_name`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setOC` -- :meth:`Annot.set_oc`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setOpacity` -- :meth:`Annot.set_opacity`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setOrigin` -- :meth:`Pixmap.set_origin`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setPixel` -- :meth:`Pixmap.set_pixel`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setRect` -- :meth:`Annot.set_rect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setRect` -- :meth:`Pixmap.set_rect`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setResolution` -- :meth:`Pixmap.set_dpi`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setRotation` -- :meth:`Page.set_rotation`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setToC` -- :meth:`Document.set_toc`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`setXmlMetadata` -- :meth:`Document.set_xml_metadata`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`showPDFpage` -- :meth:`Page.show_pdf_page`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`soundGet` -- :meth:`Annot.get_sound`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`tintWith` -- :meth:`Pixmap.tint_with`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`transformationMatrix` -- :attr:`Page.transformation_matrix`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`updateLink` -- :meth:`Page.update_link`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`updateObject` -- :meth:`Document.update_object`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`updateStream` -- :meth:`Document.update_stream`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`wrapContents` -- :meth:`Page.wrap_contents`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`writeImage` -- :meth:`Pixmap.save`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`writePNG` -- :meth:`Pixmap.save`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`writeText` -- :meth:`Page.write_text`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`writeText` -- :meth:`TextWriter.write_text`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`xrefLength` -- :meth:`Document.xref_length`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`xrefObject` -- :meth:`Document.xref_object`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`xrefStream` -- :meth:`Document.xref_stream`\"\n#~ msgstr \"\"\n\n#~ msgid \":index:`xrefStreamRaw` -- :meth:`Document.xref_stream_raw`\"\n#~ msgstr \"\"\n\n#~ msgid \"Discord logo\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/.readthedocs.yaml",
    "content": "# .readthedocs.yaml\n# Note: We use this dedicated yaml inside the locales/ko folder as RTD was having problems building a PDF\n# This yaml is the same as the main one - it just removes the PDF build option\n\n# Required\nversion: 2\n\n# Set the version of Python and other tools you might need\nbuild:\n  os: ubuntu-20.04\n  tools:\n    python: \"3.9\"\n    # You can also specify other tool versions:\n    # nodejs: \"16\"\n    # rust: \"1.55\"\n    # golang: \"1.17\"\n\n# Build documentation in the docs/ directory with Sphinx\nsphinx:\n   configuration: docs/conf.py\n\n# Optionally declare the Python requirements required to build your docs\npython:\n   install:\n   - requirements: docs/requirements.txt\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/404.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header-404.rst:-1 a1916335a5274785a49dd5e339d92fe7\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header-404.rst:-1 5d84ec96284f4e3f94e9c1b238269f04\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header-404.rst:-1 4576f08a21cd47f79352fb20f6583d87\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../404.rst:4 924f32c8351f4a62978ec14c16c351b5\nmsgid \"404!\"\nmsgstr \"404!\"\n\n#: ../../404.rst:7 6d3e16ada64f4502aa193e221a595c34\nmsgid \"**This page is not available.**\"\nmsgstr \"**이 페이지를 사용할 수 없습니다.**\"\n\n#: ../../404.rst:10 dbddaa0e43f144ebbea819e2466410b9\nmsgid \"Please use the menu or search to find what you are looking for.\"\nmsgstr \"메뉴 또는 검색을 사용하여 찾고 있는 내용을 검색해 주세요.\"\n\n#: ../../footer.rst:46 a4c037a234b44cbe8461dba8e47036a1\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/about-feature-matrix.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/about-performance.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/about.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 16:19+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f19dada9348f4b02a8e7f37161295aed\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 3a2fd52dfdbe4ef0ba2277d3dc5ce9cd\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 6457f182efd342f9971c29ded21b19cd\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../about.rst:10 6bf350a1548242f08f4231816b75ae9e\nmsgid \"Features Comparison\"\nmsgstr \"기능 비교\"\n\n#: ../../about.rst:16 e6e0680f36684a24b35c48e7756b8ee2\nmsgid \"Feature Matrix\"\nmsgstr \"기능 비교표\"\n\n#: ../../about.rst:18 fdad9ebd21e342da9d1b6b35ca5ad4e9\nmsgid \"\"\n\"The following table illustrates how |PyMuPDF| compares with other typical\"\n\" solutions.\"\nmsgstr \"다음 표는 |PyMuPDF| 가 다른 일반적인 솔루션과 어떻게 비교되는지 보여줍니다.\"\n\n#: ../../about.rst:47 5f1d6f3b09ac43e1ae7043dc7a879c02\nmsgid \"\"\n\"A note about **Office** document types (DOCX, XLXS, PPTX) and **Hangul** \"\n\"documents (HWPX). These documents can be loaded into |PyMuPDF| and you \"\n\"will receive a :ref:`Document <Document>` object.\"\nmsgstr \"**Office** 문서 유형(DOCX, XLXS, PPTX) 및 **한글** 문서(HWPX)에 대한 참고사항입니다. 이러한 문서는 |PyMuPDF| 에 로드할 수 있으며 :ref:`Document <Document>` 객체를 받게 됩니다.\"\n\n#: ../../about.rst:49 9add749bf1d7451aabfcb79190677ddb\nmsgid \"There are some caveats:\"\nmsgstr \"다음과 같은 주의사항이 있습니다:\"\n\n#: ../../about.rst:52 a610a8b3f5cf4333938a9e7a75157f1d\nmsgid \"we convert the input to **HTML** to layout the content.\"\nmsgstr \"내용을 배치하기 위해 입력을 **HTML** 로 변환합니다.\"\n\n#: ../../about.rst:53 a71abef4bb604e3b8f1065200afb7907\nmsgid \"because of this the original page separation has gone.\"\nmsgstr \"이로 인해 원본 페이지 구분이 사라집니다.\"\n\n#: ../../about.rst:55 255d6618e34f4f11ae7a1a0f54f57322\nmsgid \"\"\n\"When saving out the result any faithful representation of the original \"\n\"layout cannot be expected.\"\nmsgstr \"결과를 저장할 때 원본 레이아웃의 정확한 표현을 기대할 수 없습니다.\"\n\n#: ../../about.rst:57 59954cbab9914471b64ad43b7eb7a58b\nmsgid \"\"\n\"Therefore input files are mostly in a form that's useful for text \"\n\"extraction.\"\nmsgstr \"따라서 입력 파일은 주로 텍스트 추출에 유용한 형태입니다.\"\n\n#: ../../about.rst:65 f3ad21fdc6c841f090824af510994edb\nmsgid \"Performance\"\nmsgstr \"성능\"\n\n#: ../../about.rst:69 482ba1a4696f429da50d900517f9001b\nmsgid \"\"\n\"To benchmark |PyMuPDF| performance against a range of tasks a test suite \"\n\"with a fixed set of :ref:`8 PDFs with a total of 7,031 \"\n\"pages<Appendix4_Files_Used>` containing text & images is used to obtain \"\n\"performance timings.\"\nmsgstr \"다양한 작업에 대해 |PyMuPDF| 성능을 벤치마크하기 위해 텍스트와 이미지가 포함된 :ref:`총 7,031페이지의 8개 PDF 파일<Appendix4_Files_Used>` 로 구성된 고정된 테스트 스위트를 사용하여 성능 타이밍을 측정합니다.\"\n\n#: ../../about.rst:72 11c5e7e482204c7682f05223297c6488\nmsgid \"Here are current results, grouped by task:\"\nmsgstr \"다음은 작업별로 그룹화된 현재 결과입니다:\"\n\n#: ../../about.rst:81 9f36f4db74ab492ba26cc4fb9946f818\nmsgid \"\"\n\"For more detail regarding the methodology for these performance timings \"\n\"see: :ref:`Performance Comparison Methodology<Appendix4>`.\"\nmsgstr \"이러한 성능 타이밍 방법론에 대한 자세한 내용은 :ref:`성능 비교 방법론<Appendix4>` 을 참조하세요.\"\n\n#: ../../about.rst:89 e86ca33131a544e8a4cc0821737a9a86\nmsgid \"License and Copyright\"\nmsgstr \"라이선스 및 저작권\"\n\n#: ../../about.rst:93 061c6a01a19c40198fd34033af39cc6d\nmsgid \"\"\n\"|PyMuPDF| and |MuPDF| are now available under both, open-source |AGPL| \"\n\"and commercial license agreements. Please read the full text of the \"\n\"|AGPL| license agreement, available in the distribution material (file \"\n\"COPYING) and `on the GNU license page \"\n\"<https://www.gnu.org/licenses/agpl-3.0.html>`_, to ensure that your use \"\n\"case complies with the guidelines of the license. If you determine you \"\n\"cannot meet the requirements of the |AGPL|, please contact `Artifex \"\n\"<https://artifex.com/contact/pymupdf-inquiry.php?utm_source=rtd-\"\n\"pymupdf&utm_medium=rtd&utm_content=inline-link>`_ for more information \"\n\"regarding a commercial license.\"\nmsgstr \"|PyMuPDF| 와 |MuPDF| 는 이제 오픈소스 |AGPL| 및 상용 라이선스 계약 모두에서 사용할 수 있습니다. 사용 사례가 라이선스 지침을 준수하는지 확인하려면 배포 자료(COPYING 파일) 및 `GNU 라이선스 페이지 <https://www.gnu.org/licenses/agpl-3.0.html>`_ 에서 제공되는 |AGPL| 라이선스 계약 전문을 읽어보세요. |AGPL| 의 요구사항을 충족할 수 없다고 판단되는 경우, 상용 라이선스에 대한 자세한 정보는 `Artifex <https://artifex.com/contact/pymupdf-inquiry.php?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=inline-link>`_ 에 문의하세요.\"\n\n#: ../../about.rst:111 0cf7adfbbbe6404aae5016ba8cf4ca79\nmsgid \"\"\n\":title:`Artifex` is the exclusive commercial licensing agent for \"\n\":title:`MuPDF`.\"\nmsgstr \":title:`Artifex` 는 :title:`MuPDF` 의 독점 상용 라이선스 대리인입니다.\"\n\n#: ../../about.rst:113 1206bde366264e91900de44a990e7b13\nmsgid \"\"\n\":title:`Artifex`, the :title:`Artifex` logo, :title:`MuPDF`, and the \"\n\":title:`MuPDF` logo are registered trademarks of :title:`Artifex Software\"\n\" Inc.`\"\nmsgstr \":title:`Artifex`, :title:`Artifex` 로고, :title:`MuPDF`, :title:`MuPDF` 로고는 :title:`Artifex Software Inc.` 의 등록 상표입니다.\"\n\n#: ../../version.rst:1 b23f02d66d164eb195ed6512c8e9ff6c\nmsgid \"This documentation covers PyMuPDF |version|.\"\nmsgstr \"이 문서는 PyMuPDF |version| 을 다룹니다.\"\n\n#: ../../version.rst:3 ca881a8c265b46618c644701ea14c695\nmsgid \"\"\n\"The major and minor versions of PyMuPDF and MuPDF will always be the \"\n\"same. Only the third qualifier (patch level) may deviate from that of \"\n\"MuPDF.\"\nmsgstr \"PyMuPDF와 MuPDF의 주 버전과 부 버전은 항상 동일합니다. 세 번째 한정자(패치 레벨)만 |MuPDF| 와 다를 수 있습니다.\"\n\n#: ../../version.rst:5 a91d12805e42498fb4eebcb3f7923eb8\nmsgid \"\"\n\"Typically PyMuPDF is released more frequently than MuPDF so it will often\"\n\" be the case that the patch level of PyMuPDF will be greater than the \"\n\"embedded MuPDF.\"\nmsgstr \"일반적으로 PyMuPDF는 MuPDF보다 더 자주 릴리스되므로, PyMuPDF의 패치 레벨이 내장된 MuPDF보다 높은 경우가 많습니다.\"\n\n#: ../../version.rst:9 2e3b5e5955fc4cba8aafc25d3d650e7a\nmsgid \"For example PyMuPDF-1.24.5 contains MuPDF-1.24.2.\"\nmsgstr \"예를 들어 PyMuPDF-1.24.5는 MuPDF-1.24.2를 포함합니다.\"\n\n#: ../../version.rst:11 a60af2aa03494194b19ecf8e3bc095fc\nmsgid \"Also see `pymupdf_version` and `mupdf_version`.\"\nmsgstr \"`pymupdf_version` 및 `mupdf_version` 도 참조하세요.\"\n\n#: ../../footer.rst:48 ea2d1136af82416baa3286db6ed38f96\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n#~ msgid \"\"\n#~ \"The major and minor versions of \"\n#~ \"|PyMuPDF| and |MuPDF| will always be \"\n#~ \"the same. Only the third qualifier \"\n#~ \"(patch level) may deviate from that \"\n#~ \"of |MuPDF|.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/algebra.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 1f5ba5d56ddc4a2fa55079bc44f7d2c1\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 03f8222493784e3ca314d8d7abdaff0a\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 e6cbb920023f4b0992f996b108924b94\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../algebra.rst:6 920754cf16444314b9c46d86f31b0f00\nmsgid \"Operator Algebra for Geometry Objects\"\nmsgstr \"기하 객체를 위한 연산자 대수\"\n\n#: ../../algebra.rst:10 dec854bb55b9478eb8cc515d6eaca329\nmsgid \"\"\n\"Instances of classes :ref:`Point`, :ref:`IRect`, :ref:`Rect`, :ref:`Quad`\"\n\" and :ref:`Matrix` are collectively also called \\\"geometry\\\" objects.\"\nmsgstr \":ref:`Point`, :ref:`IRect`, :ref:`Rect`, :ref:`Quad`, :ref:`Matrix` 클래스의 인스턴스는 집합적으로 \\\"geometry\\\" 객체라고도 합니다.\"\n\n#: ../../algebra.rst:12 d199f8882c174dcea71374e8d9993b56\nmsgid \"\"\n\"They all are special cases of Python sequences, see :ref:`SequenceTypes` \"\n\"for more background.\"\nmsgstr \"모두 Python 시퀀스의 특수한 경우입니다. 자세한 내용은 :ref:`SequenceTypes` 를 참조하세요.\"\n\n#: ../../algebra.rst:14 122aaf19e93244b3a259c46eacf945b1\nmsgid \"\"\n\"We have defined operators for these classes that allow dealing with them \"\n\"(almost) like ordinary numbers in terms of addition, subtraction, \"\n\"multiplication, division, and some others.\"\nmsgstr \"이 클래스들에 대해 덧셈, 뺄셈, 곱셈, 나눗셈 및 기타 연산에서 일반 숫자처럼(거의) 다룰 수 있도록 연산자를 정의했습니다.\"\n\n#: ../../algebra.rst:16 84183cdd392441e182408f158d85ab50\nmsgid \"This chapter is a synopsis of what is possible.\"\nmsgstr \"이 장은 가능한 작업의 요약입니다.\"\n\n#: ../../algebra.rst:19 e8894b34cabf472ea53483bffb05e53d\nmsgid \"General Remarks\"\nmsgstr \"일반적인 설명\"\n\n#: ../../algebra.rst:20 0934454c0329461698c27169858d0afb\nmsgid \"\"\n\"Operators can be either **binary** (i.e. involving two objects) or \"\n\"**unary**.\"\nmsgstr \"연산자는 **이항** (즉, 두 객체를 포함) 또는 **단항** 일 수 있습니다.\"\n\n#: ../../algebra.rst:22 68b04e12599f4ce6a527b3d5f4d358aa\nmsgid \"\"\n\"The resulting type of **binary** operations is either a **new object of \"\n\"the left operand's class,** a bool or (for dot products) a float.\"\nmsgstr \"**이항** 연산의 결과 유형은 **왼쪽 피연산자 클래스의 새 객체**, bool 또는(내적의 경우) float입니다.\"\n\n#: ../../algebra.rst:24 b5bdf8532fed412092362d18eeb3dbcd\nmsgid \"\"\n\"The result of **unary** operations is either a **new object** of the same\"\n\" class, a bool or a float.\"\nmsgstr \"**단항** 연산의 결과는 동일한 클래스의 **새 객체**, bool 또는 float입니다.\"\n\n#: ../../algebra.rst:26 c6550b01d863415293570f3c92bcab4f\nmsgid \"\"\n\"The binary operators `+, -, *, /` are defined for all classes. They \"\n\"*roughly* do what you would expect -- **except, that the second operand \"\n\"...**\"\nmsgstr \"이항 연산자 `+, -, *, /` 는 모든 클래스에 대해 정의됩니다. 대략 예상대로 동작합니다 -- **단, 두 번째 피연산자는 ...**\"\n\n#: ../../algebra.rst:28 55195cd58e234294875781acefaa545e\nmsgid \"\"\n\"may always be a number which then performs the operation on every \"\n\"component of the first one,\"\nmsgstr \"항상 숫자일 수 있으며, 그러면 첫 번째 피연산자의 모든 구성 요소에 대해 연산을 수행합니다,\"\n\n#: ../../algebra.rst:29 128012698aa343409977ea7e41b35276\nmsgid \"\"\n\"may always be a numeric sequence of the same length (2, 4 or 6) -- we \"\n\"call such sequences :data:`point_like`, :data:`rect_like`, \"\n\":data:`quad_like` or :data:`matrix_like`, respectively.\"\nmsgstr \"항상 동일한 길이(2, 4 또는 6)의 숫자 시퀀스일 수 있습니다 -- 이러한 시퀀스를 각각 :data:`point_like`, :data:`rect_like`, :data:`quad_like` 또는 :data:`matrix_like` 라고 합니다.\"\n\n#: ../../algebra.rst:31 c34b1b77d5ad43c7adc65443468f835d\nmsgid \"\"\n\"Rectangles support **additional binary** operations: **intersection** \"\n\"(operator `\\\"&\\\"`), **union** (operator `\\\"|\\\"`) and **containment** \"\n\"checking.\"\nmsgstr \"사각형은 **추가 이항** 연산을 지원합니다: **교집합** (연산자 `\\\"&\\\"`), **합집합** (연산자 `\\\"|\\\"`) 및 **포함** 확인.\"\n\n#: ../../algebra.rst:33 25ac1658fe1042febe1cabd928b67c0c\nmsgid \"\"\n\"Binary operators fully support in-place operations. So if \\\"°\\\" is a \"\n\"binary operator then the expression `a °= b` is always valid and the same\"\n\" as `a = a ° b`. Therefore, be careful and do **not** do `p1 *= p2` for \"\n\"two points, because thereafter \\\"p1\\\" is a **float**.\"\nmsgstr \"이항 연산자는 제자리 연산을 완전히 지원합니다. 따라서 \\\"°\\\"가 이항 연산자이면 표현식 `a °= b` 는 항상 유효하며 `a = a ° b` 와 동일합니다. 따라서 두 점에 대해 `p1 *= p2` 를 **하지 마세요**. 그 후 \\\"p1\\\"은 **float** 가 됩니다.\"\n\n#: ../../algebra.rst:37 a3178a19dae843a2a0d880ab3d29b924\nmsgid \"Unary Operations\"\nmsgstr \"단항 연산\"\n\n#: ../../algebra.rst:40 ../../algebra.rst:59 49cce5653ff84ecd9e947c39e0d07c87\n#: c3820b716a6d44b1be18f6133e3b4589\nmsgid \"Oper.\"\nmsgstr \"연산\"\n\n#: ../../algebra.rst:40 ../../algebra.rst:59 69b612ab28c5403698b26e70c7342e08\n#: a4d6a4f7e8074daf86d9c71f76c15e3c\nmsgid \"Result\"\nmsgstr \"결과\"\n\n#: ../../algebra.rst:42 bd8aa928700f4d6da33517c5c44f92d1\nmsgid \"bool(OBJ)\"\nmsgstr \"bool(OBJ)\"\n\n#: ../../algebra.rst:42 3944ae985d32466ba96b36a9d164d059\nmsgid \"is false exactly if all components of OBJ are zero\"\nmsgstr \"OBJ의 모든 구성 요소가 0인 경우에만 false\"\n\n#: ../../algebra.rst:43 77ef179dc26548b3afe5aab5973b1ad3\nmsgid \"abs(OBJ)\"\nmsgstr \"abs(OBJ)\"\n\n#: ../../algebra.rst:43 c040cb90c08c4c24ab34fca940e7a5d3\nmsgid \"the rectangle area -- equal to norm(OBJ) for the other types\"\nmsgstr \"사각형 영역 -- 다른 유형의 경우 norm(OBJ)와 동일\"\n\n#: ../../algebra.rst:44 8e3b6dc21657411cb9b9aec339f7b58b\nmsgid \"norm(OBJ)\"\nmsgstr \"norm(OBJ)\"\n\n#: ../../algebra.rst:44 101cabdb07cc4340a520f882a1412565\nmsgid \"square root of the component squares (Euclidean norm)\"\nmsgstr \"구성 요소 제곱의 제곱근(유클리드 노름)\"\n\n#: ../../algebra.rst:45 7dcf68ad8af544e4ab89a8fb9b2e127f\nmsgid \"+OBJ\"\nmsgstr \"+OBJ\"\n\n#: ../../algebra.rst:45 bb51eef23c134b9abcde315903ab5fa9\nmsgid \"new copy of OBJ\"\nmsgstr \"OBJ의 새 복사본\"\n\n#: ../../algebra.rst:46 fbe1c96a611b41cdbdd3c8fd57b6cffd\nmsgid \"-OBJ\"\nmsgstr \"-OBJ\"\n\n#: ../../algebra.rst:46 bf0e072e4b3b4682b53d14c5d564d191\nmsgid \"new copy of OBJ with negated components\"\nmsgstr \"부정된 구성 요소를 가진 OBJ의 새 복사본\"\n\n#: ../../algebra.rst:47 41d625338bff4d5bba38dc17591c1cd4\nmsgid \"~m\"\nmsgstr \"~m\"\n\n#: ../../algebra.rst:47 e461d45306e940efa0e6c12f0b3a0001\nmsgid \"inverse of matrix \\\"m\\\", or the null matrix if not invertible\"\nmsgstr \"행렬 \\\"m\\\"의 역행렬, 또는 역행렬이 없으면 null 행렬\"\n\n#: ../../algebra.rst:52 6dee1ec3dcbd4abfb2a10eb496fd0db8\nmsgid \"Binary Operations\"\nmsgstr \"이항 연산\"\n\n#: ../../algebra.rst:53 77bb8041546c4d36b40997f8dc509039\nmsgid \"\"\n\"These are expressions like `a ° b` where \\\"°\\\" is any of the operators \"\n\"`+, -, *, /`. Also binary operations are expressions of the form `a == b`\"\n\" and `b in a`.\"\nmsgstr \"이것들은 \\\"°\\\"가 연산자 `+, -, *, /` 중 하나인 `a ° b` 와 같은 표현식입니다. 또한 이항 연산은 `a == b` 및 `b in a` 형식의 표현식입니다.\"\n\n#: ../../algebra.rst:55 665cd59a262c4131b350a1640ca2f42c\nmsgid \"\"\n\"If \\\"b\\\" is a number, then the respective operation is executed for each \"\n\"component of \\\"a\\\". Otherwise, if \\\"b\\\" is **not a number,** then the \"\n\"following happens:\"\nmsgstr \"\\\"b\\\"가 숫자이면 각 구성 요소에 대해 해당 연산이 실행됩니다. 그렇지 않고 \\\"b\\\"가 **숫자가 아니면** 다음이 발생합니다:\"\n\n#: ../../algebra.rst:61 b25c4a3c6bc2413ea4202520e62172d8\nmsgid \"a+b, a-b\"\nmsgstr \"a+b, a-b\"\n\n#: ../../algebra.rst:61 bf714007cfab424dbe07b769f64b1915\nmsgid \"component-wise execution, \\\"b\\\" must be \\\"a-like\\\".\"\nmsgstr \"구성 요소별 실행, \\\"b\\\"는 \\\"a-like\\\"여야 합니다.\"\n\n#: ../../algebra.rst:62 80c4437403a149669f5a019a372b05a9\nmsgid \"a*m, a/m\"\nmsgstr \"a*m, a/m\"\n\n#: ../../algebra.rst:62 9c7dff332f5a488587e7031c72f8a13a\nmsgid \"\"\n\"\\\"a\\\" can be a point, rectangle or matrix and \\\"m\\\" is a \"\n\":data:`matrix_like`. *\\\"a/m\\\"* is treated as *\\\"a*~m\\\"* (see note below \"\n\"for non-invertible matrices). If \\\"a\\\" is a **point** or a **rectangle**,\"\n\" then *\\\"a.transform(m)\\\"* is executed. If \\\"a\\\" is a matrix, then matrix\"\n\" concatenation takes place.\"\nmsgstr \"\\\"a\\\"는 점, 사각형 또는 행렬일 수 있으며 \\\"m\\\"은 :data:`matrix_like` 입니다. *\\\"a/m\\\"* 은 *\\\"a*~m\\\"* 로 처리됩니다(역행렬이 없는 행렬에 대한 참고 사항은 아래 참조). \\\"a\\\"가 **점** 또는 **사각형** 이면 *\\\"a.transform(m)\\\"* 이 실행됩니다. \\\"a\\\"가 행렬이면 행렬 연결이 수행됩니다.\"\n\n#: ../../algebra.rst:67 d01766d058d54714bc45e5e76968d4ea\nmsgid \"a*b\"\nmsgstr \"a*b\"\n\n#: ../../algebra.rst:67 d18a927d83d845ddbd20845807b09e1f\nmsgid \"returns the **vector dot product** for a point \\\"a\\\" and point-like \\\"b\\\".\"\nmsgstr \"점 \\\"a\\\"와 점과 유사한 \\\"b\\\"에 대한 **벡터 내적** 을 반환합니다.\"\n\n#: ../../algebra.rst:68 a49b407604184c13b57152c45ddb58ae\nmsgid \"a&b\"\nmsgstr \"a&b\"\n\n#: ../../algebra.rst:68 7550c08ef54244859c5a00ebed58448c\nmsgid \"\"\n\"**intersection rectangle:** \\\"a\\\" must be a rectangle and \\\"b\\\" \"\n\":data:`rect_like`. Delivers the **largest rectangle** contained in both \"\n\"operands.\"\nmsgstr \"**교집합 사각형:** \\\"a\\\"는 사각형이어야 하며 \\\"b\\\"는 :data:`rect_like` 여야 합니다. 두 피연산자에 모두 포함된 **가장 큰 사각형** 을 제공합니다.\"\n\n#: ../../algebra.rst:71 a60662c06b0643b0a08f75afa24efb29\nmsgid \"a|b\"\nmsgstr \"a|b\"\n\n#: ../../algebra.rst:71 79243f4be19046db9091a2f54eb4b815\nmsgid \"\"\n\"**union rectangle:** \\\"a\\\" must be a rectangle, and \\\"b\\\" may be \"\n\":data:`point_like` or :data:`rect_like`. Delivers the **smallest \"\n\"rectangle** containing both operands.\"\nmsgstr \"**합집합 사각형:** \\\"a\\\"는 사각형이어야 하며 \\\"b\\\"는 :data:`point_like` 또는 :data:`rect_like` 일 수 있습니다. 두 피연산자를 모두 포함하는 **가장 작은 사각형** 을 제공합니다.\"\n\n#: ../../algebra.rst:74 f48f56c4ee6547259acb882e87de433c\nmsgid \"b in a\"\nmsgstr \"b in a\"\n\n#: ../../algebra.rst:74 8f22ca12cfa44a898823836324a3ed99\nmsgid \"\"\n\"if \\\"b\\\" is a number, then `b in tuple(a)` is returned. If \\\"b\\\" is \"\n\":data:`point_like`, :data:`rect_like` or :data:`quad_like`, then \\\"a\\\" \"\n\"must be a rectangle, and `a.contains(b)` is returned.\"\nmsgstr \"\\\"b\\\"가 숫자이면 `b in tuple(a)` 가 반환됩니다. \\\"b\\\"가 :data:`point_like`, :data:`rect_like` 또는 :data:`quad_like` 이면 \\\"a\\\"는 사각형이어야 하며 `a.contains(b)` 가 반환됩니다.\"\n\n#: ../../algebra.rst:77 686725c716014188a79169f7cf3fd1e6\nmsgid \"a == b\"\nmsgstr \"a == b\"\n\n#: ../../algebra.rst:77 634c54d1d21d471fabf558849def45e4\nmsgid \"``True`` if *bool(a-b)* is ``False`` (\\\"b\\\" may be \\\"a-like\\\").\"\nmsgstr \"*bool(a-b)* 가 ``False`` 이면 ``True`` (\\\"b\\\"는 \\\"a-like\\\"일 수 있음).\"\n\n#: ../../algebra.rst:81 d34c2f644c4b4e6090e0e70255dd2ac5\nmsgid \"Please note an important difference to usual arithmetic:\"\nmsgstr \"일반적인 산술과의 중요한 차이점을 참고하세요:\"\n\n#: ../../algebra.rst:83 ed3c97cc627d48b394819eb13306021a\nmsgid \"\"\n\"Matrix multiplication is **not commutative**, i.e. in general we have \"\n\"`m*n != n*m` for two matrices. Also, there are non-zero matrices which \"\n\"have no inverse, for example `m = Matrix(1, 0, 1, 0, 1, 0)`. If you try \"\n\"to divide by any of these, you will receive a `ZeroDivisionError` \"\n\"exception using operator *\\\"/\\\"*, e.g. for the expression \"\n\"`pymupdf.Identity / m`. But if you formulate `pymupdf.Identity * ~m`, the\"\n\" result will be `pymupdf.Matrix()` (the null matrix).\"\nmsgstr \"행렬 곱셈은 **가환적이지 않습니다**. 즉, 일반적으로 두 행렬에 대해 `m*n != n*m` 입니다. 또한 역행렬이 없는 0이 아닌 행렬도 있습니다. 예를 들어 `m = Matrix(1, 0, 1, 0, 1, 0)` 입니다. 이것들 중 하나로 나누려고 하면 연산자 *\\\"/\\\"* 를 사용하여 `ZeroDivisionError` 예외를 받게 됩니다. 예를 들어 표현식 `pymupdf.Identity / m` 의 경우입니다. 하지만 `pymupdf.Identity * ~m` 으로 작성하면 결과는 `pymupdf.Matrix()` (null 행렬)가 됩니다.\"\n\n#: ../../algebra.rst:85 34a95a9718a64ff1a3bea139455bb7f8\nmsgid \"\"\n\"Admittedly, this represents an inconsistency, and we are considering to \"\n\"remove it. For the time being, you can choose to avoid an exception and \"\n\"check whether ~m is the null matrix, or accept a potential \"\n\"*ZeroDivisionError* by using `pymupdf.Identity / m`.\"\nmsgstr \"인정하건대, 이것은 불일치를 나타내며, 우리는 이를 제거하는 것을 고려하고 있습니다. 당분간 예외를 피하고 ~m이 null 행렬인지 확인하거나, `pymupdf.Identity / m` 을 사용하여 잠재적인 *ZeroDivisionError* 를 받아들일 수 있습니다.\"\n\n#: ../../algebra.rst:89 be97480da28d4d4190b9207839fe11f4\nmsgid \"\"\n\"With these conventions, all the usual algebra rules apply. For example, \"\n\"arbitrarily using brackets **(among objects of the same class!)** is \"\n\"possible: if r1, r2 are rectangles and m1, m2 are matrices, you can do \"\n\"this `(r1 + r2) * m1 * m2`.\"\nmsgstr \"이러한 규칙으로 모든 일반적인 대수 규칙이 적용됩니다. 예를 들어, 괄호를 임의로 사용하는 것**(동일한 클래스의 객체 중에서!)** 이 가능합니다: r1, r2가 사각형이고 m1, m2가 행렬이면 `(r1 + r2) * m1 * m2` 를 수행할 수 있습니다.\"\n\n#: ../../algebra.rst:90 511b54d905464bb8ad95bc07423f1ac2\nmsgid \"\"\n\"For all objects of the same class, `a + b + c == (a + b) + c == a + (b + \"\n\"c)` is true.\"\nmsgstr \"동일한 클래스의 모든 객체에 대해 `a + b + c == (a + b) + c == a + (b + c)` 가 참입니다.\"\n\n#: ../../algebra.rst:91 c33b3f88dde84396a57cd45693269bce\nmsgid \"\"\n\"For matrices in addition the following is true: `(m1 + m2) * m3 == m1 * \"\n\"m3 + m2 * m3` (distributivity property).\"\nmsgstr \"행렬의 경우 다음이 참입니다: `(m1 + m2) * m3 == m1 * m3 + m2 * m3` (분배 법칙).\"\n\n#: ../../algebra.rst:92 78e8741acecb42b284d4923e4453fb4d\nmsgid \"\"\n\"**But the sequence of applying matrices is important:** If r is a \"\n\"rectangle and m1, m2 are matrices, then -- **caution!:**\"\nmsgstr \"**하지만 행렬을 적용하는 순서가 중요합니다:** r이 사각형이고 m1, m2가 행렬이면 -- **주의!:**\"\n\n#: ../../algebra.rst:93 f0abf06e26414aa19a371baa59b462f2\nmsgid \"`r * m1 * m2 == (r * m1) * m2 != r * (m1 * m2)`\"\nmsgstr \"`r * m1 * m2 == (r * m1) * m2 != r * (m1 * m2)`\"\n\n#: ../../algebra.rst:96 f4a7e127cb3b40d6bfb3847510e2f35c\nmsgid \"Some Examples\"\nmsgstr \"일부 예제\"\n\n#: ../../algebra.rst:99 15d4cd12242a495384b94b9fc6c95502\nmsgid \"Manipulation with numbers\"\nmsgstr \"숫자로 조작\"\n\n#: ../../algebra.rst:100 fcede45c56364a49abff9441c752c928\nmsgid \"\"\n\"For the usual arithmetic operations, numbers are always allowed as second\"\n\" operand. In addition, you can formulate `\\\"x in OBJ\\\"`, where x is a \"\n\"number. It is implemented as `\\\"x in tuple(OBJ)\\\"`::\"\nmsgstr \"일반적인 산술 연산의 경우 숫자는 항상 두 번째 피연산자로 허용됩니다. 또한 x가 숫자인 경우 `\\\"x in OBJ\\\"` 를 작성할 수 있습니다. 이것은 `\\\"x in tuple(OBJ)\\\"` 로 구현됩니다::\"\n\n#: ../../algebra.rst:108 45094f3eda93464f8d0c9fa9f96154a4\nmsgid \"\"\n\"The following will create the upper left quarter of a document page \"\n\"rectangle::\"\nmsgstr \"다음은 문서 페이지 사각형의 왼쪽 위 사분면을 생성합니다::\"\n\n#: ../../algebra.rst:116 fccb6e938aa14f8c823d2a27fb71bb4e\nmsgid \"\"\n\"The following will deliver the **middle point of a line** that connects \"\n\"two points **p1** and **p2**::\"\nmsgstr \"다음은 두 점 **p1** 과 **p2** 를 연결하는 **선의 중점** 을 제공합니다::\"\n\n#: ../../algebra.rst:125 0c7572c7661544739337b8dcd633678e\nmsgid \"\"\n\"Compute the **vector dot product** of two points. You can compute the \"\n\"**cosine of angles** and check orthogonality.\"\nmsgstr \"두 점의 **벡터 내적** 을 계산합니다. **각도의 코사인** 을 계산하고 직교성을 확인할 수 있습니다.\"\n\n#: ../../algebra.rst:149 9659faf69acb47fd94f2c4d7dbcfd358\nmsgid \"Manipulation with \\\"like\\\" Objects\"\nmsgstr \"\\\"like\\\" 객체로 조작\"\n\n#: ../../algebra.rst:151 f7a23c3a7065470aa9f9ae634cfa4521\nmsgid \"\"\n\"The second operand of a binary operation can always be \\\"like\\\" the left \"\n\"operand. \\\"Like\\\" in this context means \\\"a sequence of numbers of the \"\n\"same length\\\". With the above examples::\"\nmsgstr \"이항 연산의 두 번째 피연산자는 항상 왼쪽 피연산자와 \\\"like\\\"일 수 있습니다. 이 맥락에서 \\\"Like\\\"는 \\\"동일한 길이의 숫자 시퀀스\\\"를 의미합니다. 위의 예제와 함께::\"\n\n#: ../../algebra.rst:162 d40766627f0645a4a9b0f043c79f8df5\nmsgid \"To shift a rectangle for 5 pixels to the right, do this::\"\nmsgstr \"사각형을 오른쪽으로 5픽셀 이동하려면 다음을 수행하세요::\"\n\n#: ../../algebra.rst:168 40356e8f087b4678a490620822d72405\nmsgid \"\"\n\"Points, rectangles and matrices can be *transformed* with matrices. In \"\n\"PyMuPDF, we treat this like a **\\\"multiplication\\\"** (or resp. \"\n\"**\\\"division\\\"**), where the second operand may be \\\"like\\\" a matrix. \"\n\"Division in this context means \\\"multiplication with the inverted \"\n\"matrix\\\"::\"\nmsgstr \"점, 사각형 및 행렬은 행렬로 *변환* 될 수 있습니다. PyMuPDF에서는 이를 **\\\"곱셈\\\"** (또는 각각 **\\\"나눗셈\\\"** )처럼 취급하며, 두 번째 피연산자는 행렬과 \\\"like\\\"일 수 있습니다. 이 맥락에서 나눗셈은 \\\"역행렬과의 곱셈\\\"을 의미합니다::\"\n\n#: ../../algebra.rst:208 ca50582bfe28428c82f4ac0277e2d5be\nmsgid \"As a specialty, rectangles support additional binary operations:\"\nmsgstr \"특수 기능으로, 사각형은 추가 이항 연산을 지원합니다:\"\n\n#: ../../algebra.rst:210 59df6332d27249a28c44c9d4c7278be7\nmsgid \"**intersection** -- the common area of rectangle-likes, operator *\\\"&\\\"*\"\nmsgstr \"**교집합** -- 사각형과 유사한 것들의 공통 영역, 연산자 *\\\"&\\\"*\"\n\n#: ../../algebra.rst:211 de5939af58234aa2be504334193d66d4\nmsgid \"\"\n\"**inclusion** -- enlarge to include a point-like or rect-like, operator \"\n\"*\\\"|\\\"*\"\nmsgstr \"**포함** -- 점과 유사하거나 사각형과 유사한 것을 포함하도록 확대, 연산자 *\\\"|\\\"*\"\n\n#: ../../algebra.rst:212 7c511b27c11240cf9d09ca3e172cf9d2\nmsgid \"**containment** check -- whether a point-like or rect-like is inside\"\nmsgstr \"**포함** 확인 -- 점과 유사하거나 사각형과 유사한 것이 내부에 있는지 여부\"\n\n#: ../../algebra.rst:214 901c1c4b81ce485fa4de1ef6f505e7e3\nmsgid \"\"\n\"Here is an example for creating the smallest rectangle enclosing given \"\n\"points::\"\nmsgstr \"주어진 점을 둘러싸는 가장 작은 사각형을 만드는 예제입니다::\"\n\n#: ../../footer.rst:46 d8841960d4f44b93825542b2759973e3\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/annot.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4ac2fe405aa74919af4d4a1801389523\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 aee68aa3a3cc4589bddde105fa520c68\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 60584b8003094a8b9570ee372d8eab4b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../annot.rst:7 f0fb0074a9b6446f8124c5e84ab64978\nmsgid \"Annot\"\nmsgstr \"Annot (주석)\"\n\n#: ../../annot.rst:9 fafaf69d450d48c5b26a1a93cb2eaa69\nmsgid \"|pdf_only_class|\"\nmsgstr \"PDF 전용 클래스.\"\n\n#: ../../annot.rst:11 4869b122c6834f279f19045fee171ca8\nmsgid \"Quote from the :ref:`AdobeManual`:\"\nmsgstr \":ref:`AdobeManual` 에서 인용:\"\n\n#: ../../annot.rst:13 e7b3050079714378a72611a6fde2125b\nmsgid \"\"\n\"*\\\"An annotation associates an object such as a note, sound, or movie \"\n\"with a location on a page of a PDF document, or provides a way to \"\n\"interact with the user by means of the mouse and keyboard.\\\"*\"\nmsgstr \"*\\\"주석은 노트, 사운드 또는 동영상과 같은 객체를 PDF 문서 페이지의 위치와 연결하거나 마우스와 키보드를 통해 사용자와 상호 작용하는 방법을 제공합니다.\\\"*\"\n\n#: ../../annot.rst:15 5c314b35139f446694f6aca06c7824f1\nmsgid \"\"\n\"There is a parent-child relationship between an annotation and its page. \"\n\"If the page object becomes unusable (closed document, any document \"\n\"structure change, etc.), then so does every of its existing annotation \"\n\"objects -- an exception is raised saying that the object is \\\"orphaned\\\",\"\n\" whenever an annotation property or method is accessed.\"\nmsgstr \"주석과 페이지 사이에는 부모-자식 관계가 있습니다. 페이지 객체가 사용할 수 없게 되면(문서 닫기, 문서 구조 변경 등), 기존의 모든 주석 객체도 사용할 수 없게 됩니다 -- 주석 속성 또는 메서드에 액세스할 때마다 객체가 \\\"고아\\\"라는 예외가 발생합니다.\"\n\n#: ../../annot.rst:18 ce89c615b0d9400e96011970b5b97556\nmsgid \"**Attribute**\"\nmsgstr \"**속성**\"\n\n#: ../../annot.rst:18 715a7d9d0eca46759c21efd06dcef6ad\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../annot.rst:20 46ba2c1aef7f47fb8cf735ab0ab8ca51\nmsgid \":meth:`Annot.delete_responses`\"\nmsgstr \"\"\n\n#: ../../annot.rst:20 542edab529f14f8a90c247c58f61d0e4\nmsgid \"delete all responding annotations\"\nmsgstr \"모든 응답 주석 삭제\"\n\n#: ../../annot.rst:21 d6f4ad7997854c15ba7ef55c7c2df885\nmsgid \":meth:`Annot.get_file`\"\nmsgstr \"\"\n\n#: ../../annot.rst:21 df78c21ef62f4d29b9892ced6ce30eab\nmsgid \"get attached file content\"\nmsgstr \"첨부 파일 내용 가져오기\"\n\n#: ../../annot.rst:22 aaa2f1576e2940d187b785f39fd5d297\nmsgid \":meth:`Annot.get_oc`\"\nmsgstr \"\"\n\n#: ../../annot.rst:22 52de51aa8f364679a043608a648fdb6d\nmsgid \"get :data:`xref` of an :data:`OCG` / :data:`OCMD`\"\nmsgstr \":data:`OCG` / :data:`OCMD` 의 :data:`xref` 가져오기\"\n\n#: ../../annot.rst:23 ba830719161c41318892442d95b2cb34\nmsgid \":meth:`Annot.get_pixmap`\"\nmsgstr \"\"\n\n#: ../../annot.rst:23 558b79769da645e1be5e25ee89f039ab\nmsgid \"image of the annotation as a pixmap\"\nmsgstr \"주석의 이미지를 pixmap으로 가져오기\"\n\n#: ../../annot.rst:24 a7049ccda64e4dd6890da7abe84fabf6\nmsgid \":meth:`Annot.get_sound`\"\nmsgstr \"\"\n\n#: ../../annot.rst:24 374a09b731894e87b56c7e841b17d330\nmsgid \"get the sound of an audio annotation\"\nmsgstr \"오디오 주석의 사운드 가져오기\"\n\n#: ../../annot.rst:25 35a90d1b5a004ad387963f3d9607d749\nmsgid \":meth:`Annot.get_text`\"\nmsgstr \"\"\n\n#: ../../annot.rst:25 ../../annot.rst:26 6131792a9d994335b4444e4823388a9a\n#: f86eecd4858f4cb89a366a146014aee5\nmsgid \"extract annotation text\"\nmsgstr \"주석 텍스트 추출\"\n\n#: ../../annot.rst:26 04cf9bb3fb1442709930c64bc5f6b0bb\nmsgid \":meth:`Annot.get_textbox`\"\nmsgstr \"\"\n\n#: ../../annot.rst:27 19db3425545544fcbcd820ce607ec897\nmsgid \":meth:`Annot.get_textpage`\"\nmsgstr \"\"\n\n#: ../../annot.rst:27 c85fb9dd00d64ff99bd74482953c24bf\nmsgid \"create a TextPage for the annotation\"\nmsgstr \"주석에 대한 TextPage 생성\"\n\n#: ../../annot.rst:28 802ef16921bd4a60800fbad10cc481fd\nmsgid \":meth:`Annot.set_border`\"\nmsgstr \"\"\n\n#: ../../annot.rst:28 2237d589cf4b43f8accb31706b0ac2e1\nmsgid \"set annotation's border properties\"\nmsgstr \"주석의 테두리 속성 설정\"\n\n#: ../../annot.rst:29 d6e3ab0ff8c247faa2df18a3dbd4fb5f\nmsgid \":meth:`Annot.set_blendmode`\"\nmsgstr \"\"\n\n#: ../../annot.rst:29 8ff755a8802d4e4bb4f4c6466fd93439\nmsgid \"set annotation's blend mode\"\nmsgstr \"주석의 블렌드 모드 설정\"\n\n#: ../../annot.rst:30 ff206dc2f63444dfae9fbe12712ba514\nmsgid \":meth:`Annot.set_colors`\"\nmsgstr \"\"\n\n#: ../../annot.rst:30 3a8dce63eadd4ffe82a27bc21a526045\nmsgid \"set annotation's colors\"\nmsgstr \"주석의 색상 설정\"\n\n#: ../../annot.rst:31 ../../annot.rst:341 7c620a1bbb3d466d8c82b9c8817c33ee\n#: a00f8a2d06fa46afb1028c82837e4185\nmsgid \":meth:`Annot.set_flags`\"\nmsgstr \"\"\n\n#: ../../annot.rst:31 37269417aa5845e78bc95975097fddad\nmsgid \"set annotation's flags field\"\nmsgstr \"주석의 플래그 필드 설정\"\n\n#: ../../annot.rst:32 60f6edb527ee49f1935786a1f19697cb\nmsgid \":meth:`Annot.set_irt_xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:32 fe64d8f927974fa7be28efe034d209b8\nmsgid \"define the annotation to being \\\"In Response To\\\"\"\nmsgstr \"주석을 \\\"답변 대상\\\"으로 정의\"\n\n#: ../../annot.rst:33 efcba97648754ee0b6f2bf66c5fb7b3b\nmsgid \":meth:`Annot.set_name`\"\nmsgstr \"\"\n\n#: ../../annot.rst:33 f1f066d0c2da4d5f93f7b21c9e06512b\nmsgid \"set annotation's name field\"\nmsgstr \"주석의 이름 필드 설정\"\n\n#: ../../annot.rst:34 ../../annot.rst:342 068e0ee638a844e4b73d54c8713fd9bb\n#: 444417b076ed4a7f9938de802c9c8687\nmsgid \":meth:`Annot.set_oc`\"\nmsgstr \"\"\n\n#: ../../annot.rst:34 2afdd097e4904b54a8f1ea48f5b61be3\nmsgid \"set :data:`xref` to an :data:`OCG` / :data:`OCMD`\"\nmsgstr \":data:`OCG` / :data:`OCMD` 로 :data:`xref` 설정\"\n\n#: ../../annot.rst:35 c399de4849964e058e1637e53fdef2f9\nmsgid \":meth:`Annot.set_opacity`\"\nmsgstr \"\"\n\n#: ../../annot.rst:35 fff897c6b9cd4cf7bfd2472ea748ca06\nmsgid \"change transparency\"\nmsgstr \"투명도 변경\"\n\n#: ../../annot.rst:36 d97cf692893c4fe7a6b799f4897c0aef\nmsgid \":meth:`Annot.set_open`\"\nmsgstr \"\"\n\n#: ../../annot.rst:36 75aaff0f9c3c458ab962d5b77a5d79d3\nmsgid \"open / close annotation or its Popup\"\nmsgstr \"주석 또는 팝업 열기 / 닫기\"\n\n#: ../../annot.rst:37 39f62e91ffef48ce9321e816caa20faa\nmsgid \":meth:`Annot.set_popup`\"\nmsgstr \"\"\n\n#: ../../annot.rst:37 a674eec367f341508c884d315088746a\nmsgid \"create a Popup for the annotation\"\nmsgstr \"주석에 대한 팝업 생성\"\n\n#: ../../annot.rst:38 ../../annot.rst:340 305b0c54c12a450e8f06569799bb8a9f\n#: f592c57486d9486c86df308aa89526da\nmsgid \":meth:`Annot.set_rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:38 26f28928df154a75b841a456bdfdbf0d\nmsgid \"change annotation rectangle\"\nmsgstr \"주석 사각형 변경\"\n\n#: ../../annot.rst:39 de6a1b1b820b471b86603c34dea03532\nmsgid \":meth:`Annot.set_rotation`\"\nmsgstr \"\"\n\n#: ../../annot.rst:39 9acc32b08f1d4f599b3735e31324426f\nmsgid \"change rotation\"\nmsgstr \"회전 변경\"\n\n#: ../../annot.rst:40 ../../annot.rst:343 18be6c4fae4e4cccb293fd8e12521dae\n#: 5200f1161df84772b72d390ec55d63cc\nmsgid \":meth:`Annot.update_file`\"\nmsgstr \"\"\n\n#: ../../annot.rst:40 c1b5d04cd03e4575a6d8bc9e47a2ac7f\nmsgid \"update attached file content\"\nmsgstr \"첨부 파일 내용 업데이트\"\n\n#: ../../annot.rst:41 736a77ca795b4bffab978f162c15c221\nmsgid \":meth:`Annot.update`\"\nmsgstr \"\"\n\n#: ../../annot.rst:41 53fe58b99d874419bf45e91f443bea49\nmsgid \"apply accumulated annot changes\"\nmsgstr \"누적된 주석 변경 사항 적용\"\n\n#: ../../annot.rst:42 076fef78de8747f98f8de5614822a3a3\nmsgid \":attr:`Annot.blendmode`\"\nmsgstr \"\"\n\n#: ../../annot.rst:42 3663d5144b7e4772a20a3ab76b0b7378\nmsgid \"annotation BlendMode\"\nmsgstr \"주석 BlendMode\"\n\n#: ../../annot.rst:43 209656247f2147b79d61220568d6e982\nmsgid \":attr:`Annot.border`\"\nmsgstr \"\"\n\n#: ../../annot.rst:43 cd995c15bfff4706a84f1d0deeef716c\nmsgid \"border details\"\nmsgstr \"테두리 세부 사항\"\n\n#: ../../annot.rst:44 a5a847e7aa1e4a66a59312e3ad69222e\nmsgid \":attr:`Annot.colors`\"\nmsgstr \"\"\n\n#: ../../annot.rst:44 7b16476edb2c47ee929046394941f61e\nmsgid \"border / background and fill colors\"\nmsgstr \"테두리 / 배경 및 채우기 색상\"\n\n#: ../../annot.rst:45 c79db9da10a34adf8724954ae760d148\nmsgid \":attr:`Annot.file_info`\"\nmsgstr \"\"\n\n#: ../../annot.rst:45 5e6d650320a44ec89edde9ad8443d028\nmsgid \"get attached file information\"\nmsgstr \"첨부 파일 정보 가져오기\"\n\n#: ../../annot.rst:46 830bf8e01251454db4eff541902734e7\nmsgid \":attr:`Annot.flags`\"\nmsgstr \"\"\n\n#: ../../annot.rst:46 d8e2f38116e34d6b8bcc0e11a02f64c4\nmsgid \"annotation flags\"\nmsgstr \"주석 플래그\"\n\n#: ../../annot.rst:47 427dbbb309334a4e938d8526af8aedd7\nmsgid \":attr:`Annot.has_popup`\"\nmsgstr \"\"\n\n#: ../../annot.rst:47 60549aa88002459b888f805a2649e95e\nmsgid \"whether annotation has a Popup\"\nmsgstr \"주석에 팝업이 있는지 여부\"\n\n#: ../../annot.rst:48 91cb2647177c40108aa8a389fbe4baba\nmsgid \":attr:`Annot.irt_xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:48 4b1a08935c844e1b94fd19e67c73c4bf\nmsgid \"annotation to which this one responds\"\nmsgstr \"이 주석이 응답하는 주석\"\n\n#: ../../annot.rst:49 c80c1d9523e54c13bf015a7802006f46\nmsgid \":attr:`Annot.info`\"\nmsgstr \"\"\n\n#: ../../annot.rst:49 e24c29731fb9426296860ef9e14c70f4\nmsgid \"various information\"\nmsgstr \"다양한 정보\"\n\n#: ../../annot.rst:50 9b1bc0b4f5604360a0fb530ee5571f6f\nmsgid \":attr:`Annot.is_open`\"\nmsgstr \"\"\n\n#: ../../annot.rst:50 76000b5c78d64a51b15f2dfb48416053\nmsgid \"whether annotation or its Popup is open\"\nmsgstr \"주석 또는 팝업이 열려 있는지 여부\"\n\n#: ../../annot.rst:51 c908f9af6c5e4097b190ab575189cc0e\nmsgid \":attr:`Annot.line_ends`\"\nmsgstr \"\"\n\n#: ../../annot.rst:51 5b4b1ee3f3ae4f66af35ac09445805c4\nmsgid \"start / end appearance of line-type annotations\"\nmsgstr \"라인 타입 주석의 시작 / 끝 모양\"\n\n#: ../../annot.rst:52 270077d780344f6c94f61715f13de4c2\nmsgid \":attr:`Annot.next`\"\nmsgstr \"\"\n\n#: ../../annot.rst:52 0dd927ea19014ab0ab931ee426aa46a2\nmsgid \"link to the next annotation\"\nmsgstr \"다음 주석에 대한 링크\"\n\n#: ../../annot.rst:53 0642e6954b8f41758e18c9fec902315c\nmsgid \":attr:`Annot.opacity`\"\nmsgstr \"\"\n\n#: ../../annot.rst:53 55103257955240a6b3c311e8e1f97f3c\nmsgid \"the annot's transparency\"\nmsgstr \"주석의 투명도\"\n\n#: ../../annot.rst:54 7528c54e1c664627851d592e77e4359b\nmsgid \":attr:`Annot.parent`\"\nmsgstr \"\"\n\n#: ../../annot.rst:54 d12a83a84aea44868a11feca2fd75f9e\nmsgid \"page object of the annotation\"\nmsgstr \"주석의 페이지 객체\"\n\n#: ../../annot.rst:55 17d31eb890f346608a29bac66b130ede\nmsgid \":attr:`Annot.popup_rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:55 e67d5b1efe1a49f8824bf40d6af292e8\nmsgid \"rectangle of the annotation's Popup\"\nmsgstr \"주석 팝업의 사각형\"\n\n#: ../../annot.rst:56 f5012088621c45f4a0cfa4ff69b400c8\nmsgid \":attr:`Annot.popup_xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:56 3c9f31c943c04997b05236036e58e2a7\nmsgid \"the PDF :data:`xref` number of the annotation's Popup\"\nmsgstr \"주석 팝업의 PDF :data:`xref` 번호\"\n\n#: ../../annot.rst:57 b0aaf4fc5d1d46a69cbca9c8576c4dff\nmsgid \":attr:`Annot.rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:57 a3afa859fcc54f03b9928dd3e3b37411\nmsgid \"rectangle containing the annotation\"\nmsgstr \"주석을 포함하는 사각형\"\n\n#: ../../annot.rst:58 e5405a3d8d6c48e3b0ba2375b00d54fc\nmsgid \":attr:`Annot.type`\"\nmsgstr \"\"\n\n#: ../../annot.rst:58 49ea84134cbd4fcfa71613fdc7c994d4\nmsgid \"type of the annotation\"\nmsgstr \"주석 타입\"\n\n#: ../../annot.rst:59 aedf999133ed4add859f5f25fcfd9c0a\nmsgid \":attr:`Annot.vertices`\"\nmsgstr \"\"\n\n#: ../../annot.rst:59 0328a5222a444a84b329ee20a13d1815\nmsgid \"point coordinates of Polygons, PolyLines, etc.\"\nmsgstr \"폴리곤, 폴리라인 등의 포인트 좌표\"\n\n#: ../../annot.rst:60 593f8d9df1724b5abbabd4b0fb42cb5f\nmsgid \":attr:`Annot.xref`\"\nmsgstr \"\"\n\n#: ../../annot.rst:60 73d760603078437db968d81892fe5450\nmsgid \"the PDF :data:`xref` number\"\nmsgstr \"PDF :data:`xref` 번호\"\n\n#: ../../annot.rst:63 df3b29896fc84aa687b9b3d812b47830\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../annot.rst:75 b763b56670344531ae43994d27d0e054\nmsgid \"Changed in v1.19.2: added support of dpi parameter.\"\nmsgstr \"v1.19.2에서 변경됨: dpi 매개변수 지원 추가.\"\n\n#: ../../annot.rst:77 571f3475af9d4fd8af0faef1dae8b761\nmsgid \"\"\n\"Creates a pixmap from the annotation as it appears on the page in \"\n\"untransformed coordinates. The pixmap's :ref:`IRect` equals \"\n\"*Annot.rect.irect* (see below). **All parameters are keyword only.**\"\nmsgstr \"\"\n\"변환되지 않은 좌표에서 페이지에 표시되는 대로 주석에서 pixmap을 생성합니다. pixmap의 :ref:`IRect` 는 \"\n\"*Annot.rect.irect* 와 같습니다(아래 참조). **모든 매개변수는 키워드 전용입니다.**\"\n\n#: ../../annot.rst 038416b4a91041e89e078df4fe4f5636\n#: 046b68e35745422e8e27b6ad4743720b 0ef49f86e0bd43f78e79e32e94eeea45\n#: 176c3a7acc6e46d38ef37bbfe97eabda 1795f42bf0b242078204d40d7a212c9a\n#: 2ab60eb3db5f4b3594f30a2bb7fd5444 388ae783a9ec418581e0f622c2641963\n#: 43c0bbc7ec774e96973a8f08c6370ebf 4e661fceb8be4c56850376cc43c38594\n#: 5327b6738ac2466a95ae4ef2989536c3 7698812a2a694b63b8da213e56c66c7e\n#: a57f1370f9ac44c2b28c69413752355b a97c7424f15243ca9fa1102ea36941f0\n#: bff13711337448f7809f30648c7765cd c8747aff1faa43f59b605c163d80ed7a\n#: d304c87c1b314f8f8d8449beb2cb9f43 e366806d4cdc4805a5cf6e6605d4c7ab\n#: e6d90ec622494f2cad21e1c4990e3a26 f73c89ed9881402ba2bd06564113f2e8\n#: fe526c08b06a4286849cdeea133c925d\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../annot.rst:79 4ea40779573a4cd48d2f0ca41a27b6cb\nmsgid \"a matrix to be used for image creation. Default is :ref:`Identity`.\"\nmsgstr \"이미지 생성에 사용할 행렬. 기본값은 :ref:`Identity` 입니다.\"\n\n#: ../../annot.rst:81 1ceeea87c25445779a772f81c247bf10\nmsgid \"\"\n\"(new in v1.19.2) desired resolution in dots per inch. If not `None`, the \"\n\"matrix parameter is ignored.\"\nmsgstr \"(v1.19.2의 새로운 기능) 인치당 도트 단위의 원하는 해상도. `None` 이 아니면 matrix 매개변수는 무시됩니다.\"\n\n#: ../../annot.rst:83 17577d5328264f3c8b2c93127b76cb6c\nmsgid \"a colorspace to be used for image creation. Default is ``pymupdf.csRGB``.\"\nmsgstr \"이미지 생성에 사용할 색상 공간. 기본값은 ``pymupdf.csRGB`` 입니다.\"\n\n#: ../../annot.rst:86 93850b04eff54b39a748a09ca5d3e6bd\nmsgid \"whether to include transparency information. Default is ``False``.\"\nmsgstr \"투명도 정보를 포함할지 여부. 기본값은 ``False`` 입니다.\"\n\n#: ../../annot.rst 089309c51cd74976a42c4fcddda08a0a\n#: 09996d0975d243b1bc59b758b7d44173 1b331e1086824733a78f979f849d4845\n#: 4817d4a35c28463eadae53476e0fd0d5 4b59e1c18c4147e69674c7d1e86501d1\n#: 4c64d5922d9847968b2eeaee6487d0d0 4df6734c085c4a6ba495179996cfe92c\n#: 6347f866f7334ddda019820946166705 67048e418fbe44a79f9f63c0d53cb3a5\n#: 7da6735c6b7f428e9eef30245825960b 7e4ad8f3110c429ea89f047da218ee26\n#: 7f141e9ca331471ba531fcb59d32b10d 90d37be980f143b8aa9b4c16f83f6c90\n#: a74cb6e028054b5abf3bcf4af3e18ad5 a838020417bb45188717e971f12c4b8f\n#: a8439c00be7b4164a1bbeae31ecffb57 a88e7e1341604dbf90a4215903761bf1\n#: b193bdba031541f882f6d4d77564f78c bad1047750b244bca5505f7e797508bc\n#: d5d3fd4c788c48d6a3ad00aa4327e554 dc6f3b8d0e814a898c59d6e18c7b6fac\n#: ddc5fc79a0cd4e73a90a35b7de615f40 e556cbfd31a6417f8e4aab208b84c15a\n#: f867cc47820b4df6923b1b5b90969f1b\nmsgid \"Return type\"\nmsgstr \"반환 타입\"\n\n#: ../../annot.rst:88 4081b82925b34d7aa9202a29b34e6645\nmsgid \":ref:`Pixmap`\"\nmsgstr \"\"\n\n#: ../../annot.rst:92 b9b41dd1363b465fb91e965b05c005a3\nmsgid \"\"\n\"If the annotation has just been created or modified, you should \"\n\":meth:`Document.reload_page` the page first via `page = \"\n\"doc.reload_page(page)`.\"\nmsgstr \"주석이 방금 생성되었거나 수정된 경우 `page = doc.reload_page(page)` 를 통해 먼저 :meth:`Document.reload_page` 를 사용해야 합니다.\"\n\n#: ../../annot.rst:94 968363fd034a4b84834bfe008fd58160\nmsgid \"\"\n\"The pixmap will have *\\\"premultiplied\\\"* pixels if `alpha=True`. To learn\"\n\" about some background, e.g. look for \\\"Premultiplied alpha\\\" `in this \"\n\"online glossary \"\n\"<https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\"\nmsgstr \"`alpha=True` 인 경우 픽스맵은 *\\\"premultiplied\\\"* 픽셀을 가집니다. 배경에 대해 알아보려면 예를 들어 `이 온라인 용어집 <https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_ 에서 \\\"Premultiplied alpha\\\"를 찾아보세요.\"\n\n#: ../../annot.rst:112 ../../annot.rst:133 059d5413f3154aaa8134479d9629d7da\n#: 5b109c06581d4245b9034c003ef2e32f\nmsgid \"New in 1.18.0\"\nmsgstr \"*1.18.0의 새로운 기능*\"\n\n#: ../../annot.rst:114 70fc1c944cd84ce18b5f51c59bbb47f0\nmsgid \"\"\n\"Retrieves the content of the annotation in a variety of formats -- much \"\n\"like the same method for :ref:`Page`.. This currently only delivers \"\n\"relevant data for annotation types 'FreeText' and 'Stamp'. Other types \"\n\"return an empty string (or equivalent objects).\"\nmsgstr \"다양한 형식으로 주석의 콘텐츠를 검색합니다 -- :ref:`Page` 의 동일한 메서드와 매우 유사합니다. 현재는 주석 타입 'FreeText' 및 'Stamp'에 대해서만 관련 데이터를 제공합니다. 다른 타입은 빈 문자열(또는 해당 객체)을 반환합니다.\"\n\n#: ../../annot.rst:116 4f2629a0de0d499f8b80783953ee846e\nmsgid \"\"\n\"(positional only) the desired format - one of the following values. \"\n\"Please note that this method works exactly like the same-named method of \"\n\":ref:`Page`.  * \\\"text\\\" -- :meth:`TextPage.extractTEXT`, default * \"\n\"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS` * \\\"words\\\" -- \"\n\":meth:`TextPage.extractWORDS` * \\\"html\\\" -- :meth:`TextPage.extractHTML` \"\n\"* \\\"xhtml\\\" -- :meth:`TextPage.extractXHTML` * \\\"xml\\\" -- \"\n\":meth:`TextPage.extractXML` * \\\"dict\\\" -- :meth:`TextPage.extractDICT` * \"\n\"\\\"json\\\" -- :meth:`TextPage.extractJSON` * \\\"rawdict\\\" -- \"\n\":meth:`TextPage.extractRAWDICT`\"\nmsgstr \"\"\n\n#: ../../annot.rst:116 f5480fbc3f3f42fba82218a8e4aec39e\nmsgid \"\"\n\"(positional only) the desired format - one of the following values. \"\n\"Please note that this method works exactly like the same-named method of \"\n\":ref:`Page`.\"\nmsgstr \"(위치 전용) 원하는 형식 - 다음 값 중 하나. 이 메서드는 :ref:`Page` 의 동일한 이름의 메서드와 정확히 동일하게 작동합니다.\"\n\n#: ../../annot.rst:118 72a5b0cb198a4de4a1b5bd8012921a2d\nmsgid \"\\\"text\\\" -- :meth:`TextPage.extractTEXT`, default\"\nmsgstr \"\\\"text\\\" -- :meth:`TextPage.extractTEXT`, 기본값\"\n\n#: ../../annot.rst:119 a0de89ee87384b559b91cb65e53fd4fe\nmsgid \"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS`\"\nmsgstr \"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS`\"\n\n#: ../../annot.rst:120 abb67ab204e8498a82f39f7786634fa3\nmsgid \"\\\"words\\\" -- :meth:`TextPage.extractWORDS`\"\nmsgstr \"\\\"words\\\" -- :meth:`TextPage.extractWORDS`\"\n\n#: ../../annot.rst:121 2a65cab359de401d84fb6c06d18af7fe\nmsgid \"\\\"html\\\" -- :meth:`TextPage.extractHTML`\"\nmsgstr \"\\\"html\\\" -- :meth:`TextPage.extractHTML`\"\n\n#: ../../annot.rst:122 ebb1a0a333b94886a085c62c2910b11b\nmsgid \"\\\"xhtml\\\" -- :meth:`TextPage.extractXHTML`\"\nmsgstr \"\\\"xhtml\\\" -- :meth:`TextPage.extractXHTML`\"\n\n#: ../../annot.rst:123 039f6bd299a1459984f1378d7506db1d\nmsgid \"\\\"xml\\\" -- :meth:`TextPage.extractXML`\"\nmsgstr \"\\\"xml\\\" -- :meth:`TextPage.extractXML`\"\n\n#: ../../annot.rst:124 def0587d2e904e678a48944fd55d8845\nmsgid \"\\\"dict\\\" -- :meth:`TextPage.extractDICT`\"\nmsgstr \"\\\"dict\\\" -- :meth:`TextPage.extractDICT`\"\n\n#: ../../annot.rst:125 9d446d90b12e480186eb0f5d4d6a88ca\nmsgid \"\\\"json\\\" -- :meth:`TextPage.extractJSON`\"\nmsgstr \"\\\"json\\\" -- :meth:`TextPage.extractJSON`\"\n\n#: ../../annot.rst:126 ba83222452844c0280bc4ca743ec52d2\nmsgid \"\\\"rawdict\\\" -- :meth:`TextPage.extractRAWDICT`\"\nmsgstr \"\\\"rawdict\\\" -- :meth:`TextPage.extractRAWDICT`\"\n\n#: ../../annot.rst:128 fc5b291ff14745a4acd435eba57c0ee4\nmsgid \"\"\n\"(keyword only) restrict the extraction to this area. Should hardly ever \"\n\"be required, defaults to :attr:`Annot.rect`.\"\nmsgstr \"(키워드 전용) 추출을 이 영역으로 제한합니다. 거의 필요하지 않으며, 기본값은 :attr:`Annot.rect` 입니다.\"\n\n#: ../../annot.rst:129 58a7b13ec10244cab579c577a4a02451\nmsgid \"\"\n\"(keyword only) control the amount of data returned. Defaults to simple \"\n\"text extraction.\"\nmsgstr \"(키워드 전용) 반환되는 데이터 양을 제어합니다. 기본값은 간단한 텍스트 추출입니다.\"\n\n#: ../../annot.rst:135 abea461b229f40449176733f81fe3e1f\nmsgid \"\"\n\"Return the annotation text. Mostly (except line breaks) equal to \"\n\":meth:`Annot.get_text` with the \\\"text\\\" option.\"\nmsgstr \"주석 텍스트를 반환합니다. 대부분(줄바꿈 제외) \\\"text\\\" 옵션을 사용하는 :meth:`Annot.get_text` 와 동일합니다.\"\n\n#: ../../annot.rst:137 7769e9ff53bb477581a82b545145ed52\nmsgid \"the area to consider, defaults to :attr:`Annot.rect`.\"\nmsgstr \"고려할 영역, 기본값은 :attr:`Annot.rect` 입니다.\"\n\n#: ../../annot.rst:142 2e28ab6b2bd740c788a328a8a392b3d3\nmsgid \"Create a :ref:`TextPage` for the annotation.\"\nmsgstr \"주석에 대한 :ref:`TextPage` 생성.\"\n\n#: ../../annot.rst:144 ec86c28fbc9c4ea5a4520e3182ebac54\nmsgid \"\"\n\"indicator bits controlling the content available for subsequent text \"\n\"extractions and searches -- see the parameter of :meth:`Annot.get_text`.\"\nmsgstr \"후속 텍스트 추출 및 검색에 사용 가능한 콘텐츠를 제어하는 표시기 비트 -- :meth:`Annot.get_text` 의 매개변수 참조.\"\n\n#: ../../annot.rst:146 f524fdc0ad6649eabe0dcea86d45490d\nmsgid \"restrict extracted text to this area.\"\nmsgstr \"추출된 텍스트를 이 영역으로 제한합니다.\"\n\n#: ../../annot.rst 00ab1155c33d4b8b909387ee865f0f14\n#: 054667c67ee948229ce41dcc4618fb84 70e6a4c25ac54573a0e41c8e5ca39783\n#: 75932b217be7487a9362d25abfb1105c a5e875b7000f42ec9309633efaa12429\n#: c194084f626c4b5799f1d232a00741a2 ffd675b9852a4f828c4dfe677c57a2bf\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../annot.rst:148 195337666ae04da792bf99b2e5fc7381\nmsgid \":ref:`TextPage`\"\nmsgstr \"\"\n\n#: ../../annot.rst:150 c08b99010b1b4e45886ecf4295e20ea1\nmsgid \"|history_begin|\"\nmsgstr \"\"\n\n#: ../../annot.rst:152 b9da3f595018401c8b8eeb0c1529cca7\nmsgid \"v1.25.5: fixed `clip` arg.\"\nmsgstr \"v1.25.5: `clip` 인수 수정.\"\n\n#: ../../annot.rst:154 0201b53debf84074b8cde915dfcee8f4\nmsgid \"|history_end|\"\nmsgstr \"\"\n\n#: ../../annot.rst:158 7980023e59354afead5f160d58e260cb\nmsgid \"Changed in version 1.16.10\"\nmsgstr \"버전 1.16.10에서 변경됨\"\n\n#: ../../annot.rst:160 0b5d367dc98e4a3a9b3fe1c292ce8cb6\nmsgid \"\"\n\"Changes annotation properties. These include dates, contents, subject and\"\n\" author (title). Changes for *name* and *id* will be ignored. The update \"\n\"happens selectively: To leave a property unchanged, set it to ``None``. \"\n\"To delete existing data, use an empty string.\"\nmsgstr \"주석 속성을 변경합니다. 날짜, 내용, 제목 및 작성자(제목)가 포함됩니다. *name* 및 *id* 에 대한 변경은 무시됩니다. 업데이트는 선택적으로 수행됩니다: 속성을 변경하지 않으려면 ``None`` 으로 설정하세요. 기존 데이터를 삭제하려면 빈 문자열을 사용하세요.\"\n\n#: ../../annot.rst:162 82ce1316fe354b898446a0cf7a1713b5\nmsgid \"\"\n\"a dictionary compatible with the *info* property (see below). All entries\"\n\" must be strings. If this argument is not a dictionary, the other \"\n\"arguments are used instead -- else they are ignored.\"\nmsgstr \"*info* 속성과 호환되는 딕셔너리(아래 참조). 모든 항목은 문자열이어야 합니다. 이 인수가 딕셔너리가 아니면 다른 인수가 대신 사용됩니다 -- 그렇지 않으면 무시됩니다.\"\n\n#: ../../annot.rst:163 ../../annot.rst:164 ../../annot.rst:167\n#: 83ea81f2fcaf4733afe8ff369d458b6f 86f02eb815724a3a9d24dd57c593a1a3\n#: c5a737145dcf4d738178459172d94c07\nmsgid \"*(new in v1.16.10)* see description in :attr:`info`.\"\nmsgstr \"*(v1.16.10의 새로운 기능)* :attr:`info` 의 설명을 참조하세요.\"\n\n#: ../../annot.rst:165 5b9616a7ad9147aa931d66313938ba67\nmsgid \"\"\n\"*(new in v1.16.10)* date of annot creation. If given, should be in PDF \"\n\"datetime format.\"\nmsgstr \"*(v1.16.10의 새로운 기능)* 주석 생성 날짜. 주어진 경우 PDF 날짜/시간 형식이어야 합니다.\"\n\n#: ../../annot.rst:166 3764dd0b660a48ecba7d241ddd0c78ef\nmsgid \"\"\n\"*(new in v1.16.10)* date of last modification. If given, should be in PDF\"\n\" datetime format.\"\nmsgstr \"*(v1.16.10의 새로운 기능)* 마지막 수정 날짜. 주어진 경우 PDF 날짜/시간 형식이어야 합니다.\"\n\n#: ../../annot.rst:171 e43517d418724f92aa471da27a597d2b\nmsgid \"\"\n\"Sets an annotation's line ending styles. Each of these annotation types \"\n\"is defined by a list of points which are connected by lines. The symbol \"\n\"identified by *start* is attached to the first point, and *end* to the \"\n\"last point of this list. For unsupported annotation types, a no-operation\"\n\" with a warning message results.\"\nmsgstr \"주석의 라인 끝 스타일을 설정합니다. 이러한 주석 타입 각각은 라인으로 연결된 포인트 목록으로 정의됩니다. *start* 로 식별된 심볼은 첫 번째 포인트에 첨부되고, *end* 는 이 목록의 마지막 포인트에 첨부됩니다. 지원되지 않는 주석 타입의 경우 경고 메시지와 함께 작업이 수행되지 않습니다.\"\n\n#: ../../annot.rst:175 c6f37bfe8f864b7aa70a6677d903fbdc\nmsgid \"\"\n\"Some symbols have an interior area (diamonds, circles, squares, etc.). \"\n\"These areas are filled with the fill color or the stroke color, depending\"\n\" on the annotation type.\"\nmsgstr \"일부 심볼에는 내부 영역(다이아몬드, 원, 사각형 등)이 있습니다. 이러한 영역은 주석 타입에 따라 채우기 색상 또는 스트로크 색상으로 채워집니다.\"\n\n#: ../../annot.rst:177 35d6ef1a79c74b06ab0a9dcf482f9a65\nmsgid \"The symbol number for the first point.\"\nmsgstr \"첫 번째 포인트의 심볼 번호.\"\n\n#: ../../annot.rst:178 458ad87b80944b07b309331fa16a70a2\nmsgid \"The symbol number for the last point.\"\nmsgstr \"마지막 포인트의 심볼 번호.\"\n\n#: ../../annot.rst:182 4fed90be4a2f4f6eb36e2d7f41f31319\nmsgid \"\"\n\"Set the annotation's visibility using PDF optional content mechanisms. \"\n\"This visibility is controlled by the user interface of supporting PDF \"\n\"viewers. It is independent from other attributes like \"\n\":attr:`Annot.flags`.\"\nmsgstr \"PDF 선택적 콘텐츠 메커니즘을 사용하여 주석의 가시성을 설정합니다. 이 가시성은 지원하는 PDF 뷰어의 사용자 인터페이스에 의해 제어됩니다. :attr:`Annot.flags` 와 같은 다른 속성과는 독립적입니다.\"\n\n#: ../../annot.rst:184 613a0a96a3a548efb40200791489f4fd\nmsgid \"\"\n\"the :data:`xref` of an optional contents group (OCG or OCMD). Any \"\n\"previous xref will be overwritten. If zero, a previous entry will be \"\n\"removed. An exception occurs if the xref is not zero and does not point \"\n\"to a valid PDF object.\"\nmsgstr \"선택적 콘텐츠 그룹(OCG 또는 OCMD)의 :data:`xref`. 이전 xref는 덮어씌워집니다. 0이면 이전 항목이 제거됩니다. xref가 0이 아니고 유효한 PDF 객체를 가리키지 않으면 예외가 발생합니다.\"\n\n#: ../../annot.rst:186 55d26af3928947678aaeaa3e33027dcc\nmsgid \"This does **not require executing** :meth:`Annot.update` to take effect.\"\nmsgstr \"이것은 효과를 적용하기 위해 :meth:`Annot.update` **실행이 필요하지 않습니다**.\"\n\n#: ../../annot.rst:190 7e388a9f2b75447d8394d6d36c4a1bf8\nmsgid \"\"\n\"Return the :data:`xref` of an optional content object, or zero if there \"\n\"is none.\"\nmsgstr \"선택적 콘텐츠 객체의 :data:`xref` 를 반환하거나, 없으면 0을 반환합니다.\"\n\n#: ../../annot.rst:192 e8ec795f695645628c3efbfd3915cec6\nmsgid \"zero or the xref of an OCG (or OCMD).\"\nmsgstr \"0 또는 OCG(또는 OCMD)의 xref.\"\n\n#: ../../annot.rst:197 b2f92c06a6294be3bfd5ec01d0e09768\nmsgid \"New in v1.19.3\"\nmsgstr \"*v1.19.3의 새로운 기능*\"\n\n#: ../../annot.rst:199 ad11cb50eb7b4800aec2e137d3accb71\nmsgid \"Set annotation to be \\\"In Response To\\\" another one.\"\nmsgstr \"주석을 다른 주석에 대한 \\\"답변 대상\\\"으로 설정합니다.\"\n\n#: ../../annot.rst:201 7b8bf875b3bc4826aa14c687fb8cd5d0\nmsgid \"\"\n\"The :data:`xref` of another annotation.  .. note:: Must refer to an \"\n\"existing annotation on this page. Setting this property requires no \"\n\"subsequent `update()`.\"\nmsgstr \"\"\n\n#: ../../annot.rst:201 9e9d820407064710884e6a66aa7f7f55\nmsgid \"The :data:`xref` of another annotation.\"\nmsgstr \"다른 주석의 :data:`xref`.\"\n\n#: ../../annot.rst:203 14f320a016824d5198f1d52227d0a926\nmsgid \"\"\n\"Must refer to an existing annotation on this page. Setting this property \"\n\"requires no subsequent `update()`.\"\nmsgstr \"이 페이지의 기존 주석을 참조해야 합니다. 이 속성을 설정하는 데 후속 `update()` 가 필요하지 않습니다.\"\n\n#: ../../annot.rst:208 ../../annot.rst:217 ../../annot.rst:237\n#: 481fa7ca48f54e5598a63178e50438ab a466079f958942378ec240211f031c16\n#: f9ec8616d1df4181aa40e2958d601327\nmsgid \"New in v1.18.4\"\nmsgstr \"*v1.18.4의 새로운 기능*\"\n\n#: ../../annot.rst:210 67cc9664fad84f49a83ba297112ca110\nmsgid \"\"\n\"Set the annotation's Popup annotation to open or closed -- **or** the \"\n\"annotation itself, if its type is 'Text' (\\\"sticky note\\\").\"\nmsgstr \"주석의 Popup 주석을 열거나 닫도록 설정합니다 -- **또는** 타입이 'Text'(\\\"sticky note\\\")인 경우 주석 자체를 설정합니다.\"\n\n#: ../../annot.rst:212 1504f1da1fda45fea8f19f45ffc20d4f\nmsgid \"the desired open state.\"\nmsgstr \"원하는 열림 상태.\"\n\n#: ../../annot.rst:219 c089225b48284823a9b7556a44262d27\nmsgid \"\"\n\"Create a Popup annotation for the annotation and specify its rectangle. \"\n\"If the Popup already exists, only its rectangle is updated.\"\nmsgstr \"주석에 대한 Popup 주석을 생성하고 사각형을 지정합니다. Popup이 이미 존재하면 사각형만 업데이트됩니다.\"\n\n#: ../../annot.rst:221 c34e5022b5454828b58718e9dcbc45fe\nmsgid \"the desired rectangle.\"\nmsgstr \"원하는 사각형.\"\n\n#: ../../annot.rst:227 facb954df51640a7ae7fd3710883dc98\nmsgid \"\"\n\"Set the annotation's transparency. Opacity can also be set in \"\n\":meth:`Annot.update`.\"\nmsgstr \"주석의 투명도를 설정합니다. 불투명도는 :meth:`Annot.update` 에서도 설정할 수 있습니다.\"\n\n#: ../../annot.rst:229 d7989596080e46c987557189dc9c25ff\nmsgid \"\"\n\"a float in range *[0, 1]*. Any value outside is assumed to be 1. E.g. a \"\n\"value of 0.5 sets the transparency to 50%.\"\nmsgstr \"*[0, 1]* 범위의 float. 범위 밖의 값은 1로 간주됩니다. 예를 들어 0.5 값은 투명도를 50%로 설정합니다.\"\n\n#: ../../annot.rst:231 8cd9cbde74a9498aa0f39f1aceeb59c0\nmsgid \"Three overlapping 'Circle' annotations with each opacity set to 0.5:\"\nmsgstr \"각 불투명도가 0.5로 설정된 세 개의 겹치는 'Circle' 주석:\"\n\n#: ../../annot.rst:239 78ea45fdfd8c457285f97ad98ced56cb\nmsgid \"\"\n\"The annotation's blend mode. See :ref:`AdobeManual`, page 324 for \"\n\"explanations.\"\nmsgstr \"주석의 블렌드 모드. 설명은 :ref:`AdobeManual`, 324페이지를 참조하세요.\"\n\n#: ../../annot.rst:242 30d06915799b4a4d993a5b5fca1059fe\nmsgid \"the blend mode or ``None``.\"\nmsgstr \"블렌드 모드 또는 ``None``.\"\n\n#: ../../annot.rst:247 9dce9ac76ca040e1a31d5585a57839f6\nmsgid \"New in v1.16.14\"\nmsgstr \"*v1.16.14의 새로운 기능*\"\n\n#: ../../annot.rst:249 dc743497d0c04f36b92127b326b52323\nmsgid \"\"\n\"Set the annotation's blend mode. See :ref:`AdobeManual`, page 324 for \"\n\"explanations. The blend mode can also be set in :meth:`Annot.update`.\"\nmsgstr \"주석의 블렌드 모드를 설정합니다. 설명은 :ref:`AdobeManual`, 324페이지를 참조하세요. 블렌드 모드는 :meth:`Annot.update` 에서도 설정할 수 있습니다.\"\n\n#: ../../annot.rst:251 4cc8588ee3a54e0ea07306202519e692\nmsgid \"\"\n\"set the blend mode. Use :meth:`Annot.update` to reflect this in the \"\n\"visual appearance. For predefined values see :ref:`BlendModes`. Use \"\n\"`PDF_BM_Normal` to **remove** a blend mode.\"\nmsgstr \"블렌드 모드를 설정합니다. 시각적 모양에 반영하려면 :meth:`Annot.update` 를 사용하세요. 미리 정의된 값은 :ref:`BlendModes` 를 참조하세요. 블렌드 모드를 **제거** 하려면 `PDF_BM_Normal` 을 사용하세요.\"\n\n#: ../../annot.rst:256 f91715c6f8dd45839dff56adcd90fe40\nmsgid \"New in version 1.16.0\"\nmsgstr \"*버전 1.16.0의 새로운 기능*\"\n\n#: ../../annot.rst:258 63628e30584640f485f9216a26cc976e\nmsgid \"\"\n\"Change the name field of any annotation type. For 'FileAttachment' and \"\n\"'Text' annotations, this is the icon name, for 'Stamp' annotations the \"\n\"text in the stamp. The visual result (if any) depends on your PDF viewer.\"\n\" See also :ref:`mupdficons`.\"\nmsgstr \"모든 주석 타입의 이름 필드를 변경합니다. 'FileAttachment' 및 'Text' 주석의 경우 이것은 아이콘 이름이고, 'Stamp' 주석의 경우 스탬프의 텍스트입니다. 시각적 결과(있는 경우)는 PDF 뷰어에 따라 다릅니다. :ref:`mupdficons` 도 참조하세요.\"\n\n#: ../../annot.rst:260 c9956808cf6344fe93a68e352c078f3b\nmsgid \"the new name.\"\nmsgstr \"새 이름.\"\n\n#: ../../annot.rst:262 77d72775e0d649e0aee5cd748dcf35c5\nmsgid \"\"\n\"If you set the name of a 'Stamp' annotation, then this will **not \"\n\"change** the rectangle, nor will the text be layouted in any way. If you \"\n\"choose a standard text from :ref:`StampIcons` (the **exact** name piece \"\n\"after `\\\"STAMP_\\\"`), you should receive the original layout. An \"\n\"**arbitrary text** will not be changed to upper case, but be written in \"\n\"font \\\"Times-Bold\\\" as is, horizontally centered in **one line** and be \"\n\"shortened to fit. To get your text fully displayed, its length using \"\n\":data:`fontsize` 20 must not exceed 190 points. So please make sure that \"\n\"the following inequality is true: `pymupdf.get_text_length(text, \"\n\"fontname=\\\"tibo\\\", fontsize=20) <= 190`.\"\nmsgstr \"'Stamp' 주석의 이름을 설정하면 사각형이 **변경되지 않으며**, 텍스트도 어떤 방식으로도 레이아웃되지 않습니다. :ref:`StampIcons` 에서 표준 텍스트를 선택하는 경우(`\\\"STAMP_\\\"` 뒤의 **정확한** 이름 부분), 원래 레이아웃을 받아야 합니다. **임의의 텍스트** 는 대문자로 변경되지 않지만, 그대로 \\\"Times-Bold\\\" 글꼴로 작성되며 **한 줄** 에 가로로 중앙 정렬되고 맞추기 위해 단축됩니다. 텍스트가 완전히 표시되도록 하려면 :data:`fontsize` 20을 사용한 길이가 190포인트를 초과하지 않아야 합니다. 따라서 다음 부등식이 참인지 확인하세요: `pymupdf.get_text_length(text, fontname=\\\"tibo\\\", fontsize=20) <= 190`.\"\n\n#: ../../annot.rst:266 215783824e424078a9c68252ef072b76\nmsgid \"\"\n\"Change the rectangle of an annotation. The annotation can be moved around\"\n\" and both sides of the rectangle can be independently scaled. However, \"\n\"the annotation appearance will never get rotated, flipped or sheared. \"\n\"This method only affects certain annotation types [#f2]_ and will lead to\"\n\" a message on Python's `sys.stderr` in other cases. No exception will be \"\n\"raised, but `False` will be returned.\"\nmsgstr \"주석의 사각형을 변경합니다. 주석을 이동할 수 있고 사각형의 양쪽을 독립적으로 확장할 수 있습니다. 그러나 주석 모양은 회전, 뒤집기 또는 기울임이 되지 않습니다. 이 메서드는 특정 주석 타입 [#f2]_에만 영향을 미치며 다른 경우에는 Python의 `sys.stderr` 에 메시지가 표시됩니다. 예외는 발생하지 않지만 `False` 가 반환됩니다.\"\n\n#: ../../annot.rst:268 a55821d5ebaa43a79524ea735d7fce30\nmsgid \"\"\n\"the new rectangle of the annotation (finite and not empty). E.g. using a \"\n\"value of *annot.rect + (5, 5, 5, 5)* will shift the annot position 5 \"\n\"pixels to the right and downwards.\"\nmsgstr \"주석의 새 사각형(유한하고 비어 있지 않음). 예를 들어 *annot.rect + (5, 5, 5, 5)* 값을 사용하면 주석 위치가 오른쪽과 아래로 5픽셀 이동합니다.\"\n\n#: ../../annot.rst:270 58ba9ae624c649f59c822a951c81b8d9\nmsgid \"You **need not** invoke :meth:`Annot.update` for activation of the effect.\"\nmsgstr \"효과를 활성화하기 위해 :meth:`Annot.update` 를 **호출할 필요가 없습니다**.\"\n\n#: ../../annot.rst:275 4182447a9b644af7b8fdaadfb8a05d32\nmsgid \"\"\n\"Set the rotation of an annotation. This rotates the annotation rectangle \"\n\"around its center point. Then a **new annotation rectangle** is \"\n\"calculated from the resulting quad.\"\nmsgstr \"주석의 회전을 설정합니다. 이것은 중심점을 중심으로 주석 사각형을 회전시킵니다. 그런 다음 결과 쿼드에서 **새 주석 사각형** 이 계산됩니다.\"\n\n#: ../../annot.rst:277 6fc24fed55494f8fb4a955d4d8a13eba\nmsgid \"\"\n\"rotation angle in degrees. Arbitrary values are possible, but will be \"\n\"clamped to the interval `[0, 360)`.\"\nmsgstr \"도 단위의 회전 각도. 임의의 값이 가능하지만 `[0, 360)` 구간으로 제한됩니다.\"\n\n#: ../../annot.rst:280 e4f887994fc5422f95d07305f9ce1cd5\nmsgid \"You **must invoke** :meth:`Annot.update` to activate the effect.\"\nmsgstr \"효과를 활성화하려면 :meth:`Annot.update` 를 **호출해야 합니다**.\"\n\n#: ../../annot.rst:281 708375ceb35c401f93a653d662ffa946\nmsgid \"\"\n\"For PDF_ANNOT_FREE_TEXT, only one of the values 0, 90, 180 and 270 is \"\n\"possible and will **rotate the text** inside the current rectangle (which\"\n\" remains unchanged). Other values are silently ignored and replaced by 0.\"\nmsgstr \"PDF_ANNOT_FREE_TEXT의 경우 0, 90, 180, 270 값 중 하나만 가능하며 현재 사각형 내에서 **텍스트를 회전** 시킵니다(사각형은 변경되지 않음). 다른 값은 조용히 무시되고 0으로 대체됩니다.\"\n\n#: ../../annot.rst:282 9916c3c0474d42789055dd9fb27df6d5\nmsgid \"\"\n\"Otherwise, only the following :ref:`AnnotationTypes` can be rotated: \"\n\"'Square', 'Circle', 'Caret', 'Text', 'FileAttachment', 'Ink', 'Line', \"\n\"'Polyline', 'Polygon', and 'Stamp'. For all others the method is a no-op.\"\nmsgstr \"그렇지 않으면 다음 :ref:`AnnotationTypes` 만 회전할 수 있습니다: 'Square', 'Circle', 'Caret', 'Text', 'FileAttachment', 'Ink', 'Line', 'Polyline', 'Polygon', 'Stamp'. 다른 모든 경우 메서드는 작업을 수행하지 않습니다.\"\n\n#: ../../annot.rst:287 21f87eefce9f42cd84347e0b9f4c9750\nmsgid \"\"\n\"Changed in version 1.16.9: Allow specification without using a \"\n\"dictionary. The direct parameters are used if *border* is not a \"\n\"dictionary.\"\nmsgstr \"버전 1.16.9에서 변경됨: 딕셔너리를 사용하지 않고 지정할 수 있습니다. *border* 가 딕셔너리가 아니면 직접 매개변수가 사용됩니다.\"\n\n#: ../../annot.rst:289 a5d1d0e5012145d88adb8f0b58ec843d\nmsgid \"Changed in version 1.22.5: Support of the \\\"cloudy\\\" border effect.\"\nmsgstr \"버전 1.22.5에서 변경됨: \\\"cloudy\\\" 테두리 효과 지원.\"\n\n#: ../../annot.rst:291 c189c32c136c4970affbad53b8a4962c\nmsgid \"\"\n\"PDF only: Change border width, dashing, style and cloud effect. See the \"\n\":attr:`Annot.border` attribute for more details.\"\nmsgstr \"PDF 전용: 테두리 너비, 파선, 스타일 및 클라우드 효과를 변경합니다. 자세한 내용은 :attr:`Annot.border` 속성을 참조하세요.\"\n\n#: ../../annot.rst:294 cd430c709f2743de8acc763ed90aa387\nmsgid \"\"\n\"a dictionary as returned by the :attr:`border` property, with keys \"\n\"*\\\"width\\\"* (*float*), *\\\"style\\\"* (*str*),  *\\\"dashes\\\"* (*sequence*) \"\n\"and *clouds* (*int*). Omitted keys will leave the resp. property \"\n\"unchanged. Set the border argument to `None` (the default) to use the \"\n\"other arguments.\"\nmsgstr \":attr:`border` 속성에서 반환된 딕셔너리, 키는 *\\\"width\\\"* (*float*), *\\\"style\\\"* (*str*), *\\\"dashes\\\"* (*sequence*), *clouds* (*int*). 생략된 키는 해당 속성을 변경하지 않습니다. 다른 인수를 사용하려면 border 인수를 `None` (기본값)으로 설정하세요.\"\n\n#: ../../annot.rst:296 39acc9934225448197fcfd592c9d832f\nmsgid \"A non-negative value will change the border line width.\"\nmsgstr \"음수가 아닌 값은 테두리 선 너비를 변경합니다.\"\n\n#: ../../annot.rst:297 a68a775771684101adfaada1b555645a\nmsgid \"A value other than `None` will change this border property.\"\nmsgstr \"`None` 이 아닌 값은 이 테두리 속성을 변경합니다.\"\n\n#: ../../annot.rst:298 6abbfe1e60884753b2f408c6140c1522\nmsgid \"\"\n\"All items of the sequence must be integers, otherwise the parameter is \"\n\"ignored. To remove dashing use: `dashes=[]`. If dashes is a non-empty \"\n\"sequence, \\\"style\\\" will automatically be set to \\\"D\\\" (dashed).\"\nmsgstr \"시퀀스의 모든 항목은 정수여야 하며, 그렇지 않으면 매개변수가 무시됩니다. 파선을 제거하려면 `dashes=[]` 를 사용하세요. dashes가 비어 있지 않은 시퀀스인 경우 \\\"style\\\"이 자동으로 \\\"D\\\"(파선)로 설정됩니다.\"\n\n#: ../../annot.rst:299 a14bf775a9aa4b5690dfa5d75ad9a268\nmsgid \"\"\n\"A value >= 0 will change this property. Use `clouds=0` to remove the \"\n\"cloudy appearance completely. Only annotation types 'Square', 'Circle', \"\n\"and 'Polygon' are supported with this property.\"\nmsgstr \">= 0 값은 이 속성을 변경합니다. 클라우드 모양을 완전히 제거하려면 `clouds=0` 을 사용하세요. 이 속성은 주석 타입 'Square', 'Circle', 'Polygon'에서만 지원됩니다.\"\n\n#: ../../annot.rst:303 ef79e54d0a714869a014c9d730425b72\nmsgid \"Changes the annotation flags. Use the `|` operator to combine several.\"\nmsgstr \"주석 플래그를 변경합니다. 여러 개를 결합하려면 `|` 연산자를 사용하세요.\"\n\n#: ../../annot.rst:305 fd0aa1fe5fa54354942159d69033f3dd\nmsgid \"an integer specifying the required flags.\"\nmsgstr \"필요한 플래그를 지정하는 정수.\"\n\n#: ../../annot.rst:309 6c045aa7fffe4727b0d500917f834af7\nmsgid \"\"\n\"Changes the \\\"stroke\\\" and \\\"fill\\\" colors for supported annotation types\"\n\" -- not all annotation types accept both. **Do not use this method at all\"\n\" for FreeText annotations** because it has its special conventions to \"\n\"deal with up to three colors (border, fill, text).\"\nmsgstr \"지원되는 주석 타입에 대한 \\\"stroke\\\" 및 \\\"fill\\\" 색상을 변경합니다 -- 모든 주석 타입이 둘 다 허용하는 것은 아닙니다. **FreeText 주석에는 이 메서드를 전혀 사용하지 마세요** 최대 3개의 색상(테두리, 채우기, 텍스트)을 처리하는 특별한 규칙이 있기 때문입니다.\"\n\n#: ../../annot.rst:311 db7de1cdaf074887b6a5856f6edce371\nmsgid \"\"\n\"a dictionary containing color specifications. For accepted dictionary \"\n\"keys and values see below. The most practical way should be to first make\"\n\" a copy of the *colors* property and then modify this dictionary as \"\n\"required.\"\nmsgstr \"색상 지정을 포함하는 딕셔너리. 허용되는 딕셔너리 키와 값은 아래를 참조하세요. 가장 실용적인 방법은 먼저 *colors* 속성의 복사본을 만든 다음 필요에 따라 이 딕셔너리를 수정하는 것입니다.\"\n\n#: ../../annot.rst:312 ../../annot.rst:313 75cff1ffb24c4912bfeb81a9ebd1432d\n#: ab1efc57d7bc48e98cf5e1bdb658a212\nmsgid \"see above.\"\nmsgstr \"위를 참조하세요.\"\n\n#: ../../annot.rst:315 7c1a94d49e3646c1acf119c6dbd9d5d2\nmsgid \"\"\n\"To completely remove a color specification, use an empty sequence like \"\n\"`[]`. If you specify `None`, an existing specification will not be \"\n\"changed.\"\nmsgstr \"색상 지정을 완전히 제거하려면 `[]` 와 같은 빈 시퀀스를 사용하세요. `None` 을 지정하면 기존 지정이 변경되지 않습니다.\"\n\n#: ../../annot.rst:320 2a6d90dee7ce4d77b26b92943743267a\nmsgid \"New in version 1.16.12\"\nmsgstr \"*버전 1.16.12의 새로운 기능*\"\n\n#: ../../annot.rst:322 595743ee33354f6db6ea8007f5c683d9\nmsgid \"\"\n\"Delete annotations referring to this one. This includes any 'Popup' \"\n\"annotations and all annotations responding to it.\"\nmsgstr \"이 주석을 참조하는 주석을 삭제합니다. 여기에는 모든 'Popup' 주석과 이에 응답하는 모든 주석이 포함됩니다.\"\n\n#: ../../annot.rst:336 3dd084b1ebf84cde9a0f1628888a078a\nmsgid \"\"\n\"Synchronize the appearance of an annotation with its properties after \"\n\"relevant changes.\"\nmsgstr \"관련 변경 후 주석의 모양을 속성과 동기화합니다.\"\n\n#: ../../annot.rst:338 7fe415cd7d454f189581594f76164856\nmsgid \"You can safely **omit** this method **only** for the following changes:\"\nmsgstr \"다음 변경 사항에 대해서만 이 메서드를 안전하게 **생략** 할 수 있습니다:\"\n\n#: ../../annot.rst:344 fe15053758b14d7199c023e93f5fb1b5\nmsgid \":meth:`Annot.set_info` (except any changes to *\\\"content\\\"*)\"\nmsgstr \":meth:`Annot.set_info` (*\\\"content\\\"* 에 대한 변경 제외)\"\n\n#: ../../annot.rst:346 0073d1e84f5d4733b0ed896ad1863ecc\nmsgid \"\"\n\"All arguments are optional. *(Changed in v1.16.14)* Blend mode and \"\n\"opacity are applicable to **all annotation types**. The other arguments \"\n\"are mostly special use, as described below.\"\nmsgstr \"모든 인수는 선택 사항입니다. *(v1.16.14에서 변경됨)* 블렌드 모드와 불투명도는 **모든 주석 타입** 에 적용됩니다. 다른 인수는 아래에 설명된 대로 대부분 특수 용도입니다.\"\n\n#: ../../annot.rst:348 f2ba4ab0eec14256874f4795f0809515\nmsgid \"\"\n\"Color specifications may be made in the usual format used in PuMuPDF as \"\n\"sequences of floats ranging from 0.0 to 1.0 (including both). The \"\n\"sequence length must be 1, 3 or 4 (supporting GRAY, RGB and CMYK \"\n\"colorspaces respectively). For GRAY, just a float is also acceptable.\"\nmsgstr \"색상 지정은 PyMuPDF에서 사용하는 일반 형식으로 0.0부터 1.0까지(둘 다 포함)의 float 시퀀스로 만들 수 있습니다. 시퀀스 길이는 1, 3 또는 4여야 합니다(각각 GRAY, RGB 및 CMYK 색상 공간 지원). GRAY의 경우 단일 float도 허용됩니다.\"\n\n#: ../../annot.rst:350 f3ccad414cfa4feea70d7d6d4ee37f20\nmsgid \"\"\n\"*(new in v1.16.14)* **valid for all annotation types:** change or set the\"\n\" annotation's transparency. Valid values are *0 <= opacity < 1*.\"\nmsgstr \"*(v1.16.14의 새로운 기능)* **모든 주석 타입에 유효:** 주석의 투명도를 변경하거나 설정합니다. 유효한 값은 *0 <= opacity < 1* 입니다.\"\n\n#: ../../annot.rst:352 04465250dcde4c4c860e257ac3e888cc\nmsgid \"\"\n\"*(new in v1.16.14)* **valid for all annotation types:** change or set the\"\n\" annotation's blend mode. For valid values see :ref:`BlendModes`.\"\nmsgstr \"*(v1.16.14의 새로운 기능)* **모든 주석 타입에 유효:** 주석의 블렌드 모드를 변경하거나 설정합니다. 유효한 값은 :ref:`BlendModes` 를 참조하세요.\"\n\n#: ../../annot.rst:354 9bc27aa105ae42cd82a2451d40ee6e6e\nmsgid \"change :data:`fontsize` of the text. 'FreeText' annotations only.\"\nmsgstr \"텍스트의 :data:`fontsize` 변경. 'FreeText' 주석만 해당.\"\n\n#: ../../annot.rst:356 cf2b46ce81194d3889beefcdf7c9b7bc\nmsgid \"\"\n\"change the text color. 'FreeText' annotations only. This has the same \"\n\"effect as ``border_color``. Note that the text color of rich-text \"\n\"annotations cannot be changed at all because it is set by HTML / CSS \"\n\"syntax and part of the text itself.\"\nmsgstr \"텍스트 색상 변경. 'FreeText' 주석만 해당. 이것은 ``border_color`` 와 동일한 효과를 가집니다. 리치 텍스트 주석의 텍스트 색상은 HTML / CSS 구문에 의해 설정되고 텍스트 자체의 일부이기 때문에 전혀 변경할 수 없습니다.\"\n\n#: ../../annot.rst:358 9573860e39914131a2e6b21985df1d0a\nmsgid \"\"\n\"change the border color. 'FreeText' annotations only. This has the same \"\n\"effect as ``text_color``.\"\nmsgstr \"테두리 색상 변경. 'FreeText' 주석만 해당. 이것은 ``text_color`` 와 동일한 효과를 가집니다.\"\n\n#: ../../annot.rst:360 f201d820422e410380867aef925e12c6\nmsgid \"the fill color.\"\nmsgstr \"채우기 색상.\"\n\n#: ../../annot.rst:362 51b7ae492b9d439ea63ad6e688461680\nmsgid \"\"\n\"*(new in v1.17.2)* add two diagonal lines to the annotation rectangle. \"\n\"'Redact' annotations only. If not desired, ``False`` must be specified \"\n\"even if the annotation was created with ``False``.\"\nmsgstr \"*(v1.17.2의 새로운 기능)* 주석 사각형에 두 개의 대각선을 추가합니다. 'Redact' 주석만 해당. 원하지 않는 경우 주석이 ``False`` 로 생성되었더라도 ``False`` 를 지정해야 합니다.\"\n\n#: ../../annot.rst:364 ca681b7d888b4269b353a917a0251fcc\nmsgid \"\"\n\"new rotation value. Default (-1) means no change. Supports 'FreeText' and\"\n\" several other annotation types (see :meth:`Annot.set_rotation`), [#f1]_.\"\n\" Only choose 0, 90, 180, or 270 degrees for 'FreeText'. Otherwise any \"\n\"integer is acceptable.\"\nmsgstr \"새 회전 값. 기본값(-1)은 변경 없음을 의미합니다. 'FreeText' 및 여러 다른 주석 타입을 지원합니다(:meth:`Annot.set_rotation` 참조), [#f1]_. 'FreeText'의 경우 0, 90, 180 또는 270도만 선택하세요. 그렇지 않으면 모든 정수가 허용됩니다.\"\n\n#: ../../annot.rst:368 60ab5d4e01554e09aa2155cfcf1bd6a4\nmsgid \"\"\n\"This method is the only way to change the colors of a FreeText \"\n\"annotation. You cannot use :meth:`Annot.set_colors` for this purpose. But\"\n\" be aware that for rich-text annotations, the text color is never \"\n\"changed. The text color is set by the ``text_color`` entry of the \"\n\"``info`` dictionary. This is a limitation of |MuPDF| and not a bug.\"\nmsgstr \"이 메서드는 FreeText 주석의 색상을 변경하는 유일한 방법입니다. 이 목적을 위해 :meth:`Annot.set_colors` 를 사용할 수 없습니다. 그러나 리치 텍스트 주석의 경우 텍스트 색상은 절대 변경되지 않습니다. 텍스트 색상은 ``info`` 딕셔너리의 ``text_color`` 항목에 의해 설정됩니다. 이것은 |MuPDF| 의 제한 사항이며 버그가 아닙니다.\"\n\n#: ../../annot.rst:370 1112033b5d6844729cb062a449ec85b1\nmsgid \"\"\n\"Using this method inside a :meth:`Page.annots` loop is **not \"\n\"recommended!** This is because most annotation updates require the owning\"\n\" page to be reloaded -- which cannot be done inside this loop. Please use\"\n\" the example coding pattern given in the documentation of this generator.\"\nmsgstr \":meth:`Page.annots` 루프 내에서 이 메서드를 사용하는 것은 **권장되지 않습니다!** 대부분의 주석 업데이트는 소유 페이지를 다시 로드해야 하기 때문입니다 -- 이 루프 내에서는 수행할 수 없습니다. 이 생성자의 문서에 제공된 예제 코딩 패턴을 사용하세요.\"\n\n#: ../../annot.rst:375 4a926753fff744ec9116dd6ed7183650\nmsgid \"Basic information of the annot's attached file.\"\nmsgstr \"주석의 첨부 파일에 대한 기본 정보.\"\n\n#: ../../annot.rst:378 dff1e3b1a640429fb53eddd0fa92ce69\nmsgid \"\"\n\"a dictionary with keys *filename*, *ufilename*, *desc* (description), \"\n\"*size* (uncompressed file size), *length* (compressed length) for \"\n\"FileAttachment annot types, else ``None``.\"\nmsgstr \"FileAttachment 주석 타입의 경우 *filename*, *ufilename*, *desc* (설명), *size* (압축되지 않은 파일 크기), *length* (압축된 길이) 키를 가진 딕셔너리, 그렇지 않으면 ``None``.\"\n\n#: ../../annot.rst:382 fff1e94235db41658c4a47630907af7b\nmsgid \"Returns attached file content.\"\nmsgstr \"첨부 파일 내용을 반환합니다.\"\n\n#: ../../annot.rst:385 e7858d0b8f274619a0e53226e2ad2558\nmsgid \"the content of the attached file.\"\nmsgstr \"첨부 파일의 내용.\"\n\n#: ../../annot.rst:395 0a6f0f824993411db432fbc73cedbf48\nmsgid \"\"\n\"Updates the content of an attached file. All arguments are optional. No \"\n\"arguments lead to a no-op.\"\nmsgstr \"첨부 파일의 내용을 업데이트합니다. 모든 인수는 선택 사항입니다. 인수가 없으면 작업이 수행되지 않습니다.\"\n\n#: ../../annot.rst:397 14cfd5ce68c443c4b5706490bf7ce62c\nmsgid \"\"\n\"the new file content. Omit to only change meta-information.  *(Changed in\"\n\" version 1.14.13)* *io.BytesIO* is now also supported.\"\nmsgstr \"\"\n\n#: ../../annot.rst:397 13e705e69a1d425184d4be574725693d\nmsgid \"the new file content. Omit to only change meta-information.\"\nmsgstr \"새 파일 내용. 메타 정보만 변경하려면 생략하세요.\"\n\n#: ../../annot.rst:399 a1e92b5db60e4c4599063b1893fd8eed\nmsgid \"*(Changed in version 1.14.13)* *io.BytesIO* is now also supported.\"\nmsgstr \"*(버전 1.14.13에서 변경됨)* *io.BytesIO* 도 이제 지원됩니다.\"\n\n#: ../../annot.rst:401 16d4a6c7354947dc9ed4a1af1e661951\nmsgid \"new filename to associate with the file.\"\nmsgstr \"파일과 연결할 새 파일 이름.\"\n\n#: ../../annot.rst:403 f71c9be54bb649adbc2100b1cf7793e5\nmsgid \"new unicode filename to associate with the file.\"\nmsgstr \"파일과 연결할 새 유니코드 파일 이름.\"\n\n#: ../../annot.rst:405 70d2cec5d76d4b4ca6ac53eb58acf503\nmsgid \"new description of the file content.\"\nmsgstr \"파일 내용에 대한 새 설명.\"\n\n#: ../../annot.rst:409 dfdaec12a2274c30a1f374a77b655ee8\nmsgid \"Return the embedded sound of an audio annotation.\"\nmsgstr \"오디오 주석의 포함된 사운드를 반환합니다.\"\n\n#: ../../annot.rst:412 c7fa04ae49d54d39a39b5d2245c490f0\nmsgid \"\"\n\"the sound audio file and accompanying properties. These are the possible \"\n\"dictionary keys, of which only \\\"rate\\\" and \\\"stream\\\" are always \"\n\"present.  =========== \"\n\"======================================================= Key         \"\n\"Description =========== \"\n\"======================================================= rate        \"\n\"(float, requ.) samples per second channels    (int, opt.) number of sound\"\n\" channels bps         (int, opt.) bits per sample value per channel \"\n\"encoding    (str, opt.) encoding format: Raw, Signed, muLaw, ALaw \"\n\"compression (str, opt.) name of compression filter stream      (bytes, \"\n\"requ.) the sound file content =========== \"\n\"=======================================================\"\nmsgstr \"\"\n\n#: ../../annot.rst:412 df0e243fcf034592a8492436e6e1659a\nmsgid \"\"\n\"the sound audio file and accompanying properties. These are the possible \"\n\"dictionary keys, of which only \\\"rate\\\" and \\\"stream\\\" are always \"\n\"present.\"\nmsgstr \"사운드 오디오 파일 및 관련 속성. 가능한 딕셔너리 키는 다음과 같으며, \\\"rate\\\"와 \\\"stream\\\"만 항상 존재합니다.\"\n\n#: ../../annot.rst:415 12be1c52c4314285af838a6ce29fba9e\nmsgid \"Key\"\nmsgstr \"키\"\n\n#: ../../annot.rst:415 2bdf4ba35cce4815a2a492cf817897c8\nmsgid \"Description\"\nmsgstr \"설명\"\n\n#: ../../annot.rst:417 0d66d09f790c4ff3bc6c27ba0d9b632a\nmsgid \"rate\"\nmsgstr \"rate\"\n\n#: ../../annot.rst:417 c1045c0883214be39172475f75e7f5d0\nmsgid \"(float, requ.) samples per second\"\nmsgstr \"(float, 필수) 초당 샘플 수\"\n\n#: ../../annot.rst:418 8abdaaa9d7fe44dfa74cc67416d30c2b\nmsgid \"channels\"\nmsgstr \"channels\"\n\n#: ../../annot.rst:418 f74b4b35e92846e28327d70e75e25b02\nmsgid \"(int, opt.) number of sound channels\"\nmsgstr \"(int, 선택) 사운드 채널 수\"\n\n#: ../../annot.rst:419 942b2b733eed481b9491bc82bc570e1c\nmsgid \"bps\"\nmsgstr \"bps\"\n\n#: ../../annot.rst:419 7be514225767447a8a8095e8df1f2bc4\nmsgid \"(int, opt.) bits per sample value per channel\"\nmsgstr \"(int, 선택) 채널당 샘플 값당 비트 수\"\n\n#: ../../annot.rst:420 b38f02b791694df2ae7e91f5e18e4b63\nmsgid \"encoding\"\nmsgstr \"encoding\"\n\n#: ../../annot.rst:420 73e6b25cf0da41518e6a2a8c8342f9b9\nmsgid \"(str, opt.) encoding format: Raw, Signed, muLaw, ALaw\"\nmsgstr \"(str, 선택) 인코딩 형식: Raw, Signed, muLaw, ALaw\"\n\n#: ../../annot.rst:421 1969b7bd898244968ec9e8b0ccb1bde7\nmsgid \"compression\"\nmsgstr \"compression\"\n\n#: ../../annot.rst:421 a89ee4a1e5ae438bb9abdf27689f1840\nmsgid \"(str, opt.) name of compression filter\"\nmsgstr \"(str, 선택) 압축 필터 이름\"\n\n#: ../../annot.rst:422 8ae646c528504b2c930d6aeefa18e74b\nmsgid \"stream\"\nmsgstr \"stream\"\n\n#: ../../annot.rst:422 379f471934fe4d5fab7732b175a2bce2\nmsgid \"(bytes, requ.) the sound file content\"\nmsgstr \"(bytes, 필수) 사운드 파일 내용\"\n\n#: ../../annot.rst:428 04846fc70fde4de09324de235eedf132\nmsgid \"\"\n\"The annotation's transparency. If set, it is a value in range *[0, 1]*. \"\n\"The PDF default is 1. However, in an effort to tell the difference, we \"\n\"return *-1.0* if not set.\"\nmsgstr \"주석의 투명도. 설정된 경우 *[0, 1]* 범위의 값입니다. PDF 기본값은 1입니다. 그러나 차이를 구분하기 위해 설정되지 않은 경우 *-1.0* 을 반환합니다.\"\n\n#: ../../annot.rst:434 38341cb4267e49eea899f48c336adc57\nmsgid \"The owning page object of the annotation.\"\nmsgstr \"주석의 소유 페이지 객체.\"\n\n#: ../../annot.rst:436 b69e2ef1768c4682aeceb59e231073e6\nmsgid \":ref:`Page`\"\nmsgstr \"\"\n\n#: ../../annot.rst:440 d8c838f369404f76b51db3fa29590aaf\nmsgid \"The annot rotation.\"\nmsgstr \"주석 회전.\"\n\n#: ../../annot.rst:443 0e4000b23bd0487692990ba93841e11b\nmsgid \"\"\n\"a value [-1, 359]. If rotation is not at all, -1 is returned (and implies\"\n\" a rotation angle of 0). Other possible values are normalized to some \"\n\"value value 0 <= angle < 360.\"\nmsgstr \"[-1, 359] 값. 회전이 전혀 없는 경우 -1이 반환됩니다(회전 각도 0을 의미). 다른 가능한 값은 0 <= angle < 360 값으로 정규화됩니다.\"\n\n#: ../../annot.rst:447 675380b4c5e64bf7bff950dcc720a751\nmsgid \"The rectangle containing the annotation.\"\nmsgstr \"주석을 포함하는 사각형.\"\n\n#: ../../annot.rst:449 ../../annot.rst:549 aebdf20a1fda46b7abc7b4c3e0493882\n#: ec14799005724be998a1275792677a12\nmsgid \":ref:`Rect`\"\nmsgstr \"\"\n\n#: ../../annot.rst:453 c70b9c19d6d84a359b2b1a7396054162\nmsgid \"The next annotation on this page or None.\"\nmsgstr \"이 페이지의 다음 주석 또는 None.\"\n\n#: ../../annot.rst:455 e2f9dcc59c714b54a43f67ec7b62cff8\nmsgid \"*Annot*\"\nmsgstr \"\"\n\n#: ../../annot.rst:459 606bb69f415d48c0a7aad4dac9c69fc3\nmsgid \"\"\n\"A number and one or two strings describing the annotation type, like \"\n\"**[2, 'FreeText', 'FreeTextCallout']**. The second string entry is \"\n\"optional and may be empty. See the appendix :ref:`AnnotationTypes` for a \"\n\"list of possible values and their meanings.\"\nmsgstr \"주석 타입을 설명하는 숫자와 하나 또는 두 개의 문자열, 예: **[2, 'FreeText', 'FreeTextCallout']**. 두 번째 문자열 항목은 선택 사항이며 비어 있을 수 있습니다. 가능한 값과 의미 목록은 부록 :ref:`AnnotationTypes` 를 참조하세요.\"\n\n#: ../../annot.rst:465 814b528ad1594607875ed97510496fe2\nmsgid \"\"\n\"A dictionary containing various information. All fields are optional \"\n\"strings. For information items not provided, an empty string is returned.\"\nmsgstr \"다양한 정보를 포함하는 딕셔너리. 모든 필드는 선택적 문자열입니다. 제공되지 않은 정보 항목의 경우 빈 문자열이 반환됩니다.\"\n\n#: ../../annot.rst:467 132313a5fcff4d5b98ca42e3a4bf5fda\nmsgid \"\"\n\"*name* -- e.g. for 'Stamp' annotations it will contain the stamp text \"\n\"like \\\"Sold\\\" or \\\"Experimental\\\", for other annot types you will see the\"\n\" name of the annot's icon here (\\\"PushPin\\\" for FileAttachment).\"\nmsgstr \"*name* -- 예를 들어 'Stamp' 주석의 경우 \\\"Sold\\\" 또는 \\\"Experimental\\\"와 같은 스탬프 텍스트를 포함하고, 다른 주석 타입의 경우 여기에서 주석 아이콘의 이름을 볼 수 있습니다(FileAttachment의 경우 \\\"PushPin\\\").\"\n\n#: ../../annot.rst:469 bc6c85b50da94924bc357226258bd3fc\nmsgid \"\"\n\"*content* -- a string containing the text for type *Text* and *FreeText* \"\n\"annotations. Commonly used for filling the text field of annotation pop-\"\n\"up windows.\"\nmsgstr \"*content* -- *Text* 및 *FreeText* 주석에 대한 텍스트를 포함하는 문자열. 주석 팝업 창의 텍스트 필드를 채우는 데 일반적으로 사용됩니다.\"\n\n#: ../../annot.rst:471 d7645d31cbb64e3cb699a731902ecb75\nmsgid \"\"\n\"*title* -- a string containing the title of the annotation pop-up window.\"\n\" By convention, this is used for the **annotation author**.\"\nmsgstr \"*title* -- 주석 팝업 창의 제목을 포함하는 문자열. 규칙에 따라 이것은 **주석 작성자** 에 사용됩니다.\"\n\n#: ../../annot.rst:473 ba6e837b12eb4a59b39297c6410293cb\nmsgid \"*creationDate* -- creation timestamp.\"\nmsgstr \"*creationDate* -- 생성 타임스탬프.\"\n\n#: ../../annot.rst:474 dea7337d10874b83bd25f6be18463264\nmsgid \"*modDate* -- last modified timestamp.\"\nmsgstr \"*modDate* -- 마지막 수정 타임스탬프.\"\n\n#: ../../annot.rst:475 affe5f09ffd3424b9ff3466bd9fa10e4\nmsgid \"*subject* -- subject.\"\nmsgstr \"*subject* -- 제목.\"\n\n#: ../../annot.rst:476 2839aeb340104f42b830df272fca2fb6\nmsgid \"\"\n\"*id* -- *(new in version 1.16.10)* a unique identification of the \"\n\"annotation. This is taken from PDF key */NM*. Annotations added by \"\n\"PyMuPDF will have a unique name, which appears here.\"\nmsgstr \"*id* -- *(버전 1.16.10의 새로운 기능)* 주석의 고유 식별자. 이것은 PDF 키 */NM* 에서 가져옵니다. PyMuPDF로 추가된 주석은 여기에 나타나는 고유한 이름을 가집니다.\"\n\n#: ../../annot.rst:483 16616c415f6e46b7a3677cfdd3112ce3\nmsgid \"\"\n\"An integer whose low order bits contain flags for how the annotation \"\n\"should be presented.\"\nmsgstr \"하위 비트에 주석을 표시하는 방법에 대한 플래그를 포함하는 정수.\"\n\n#: ../../annot.rst:489 8339de6110f3442eae85a3e339d2b60f\nmsgid \"\"\n\"A pair of integers specifying start and end symbol of annotations types \"\n\"'FreeText', 'Line', 'PolyLine', and 'Polygon'. ``None`` if not \"\n\"applicable. For possible values and descriptions in this list, see the \"\n\":ref:`AdobeManual`, table 1.76 on page 400.\"\nmsgstr \"'FreeText', 'Line', 'PolyLine', 'Polygon' 주석 타입의 시작 및 끝 심볼을 지정하는 정수 쌍. 적용되지 않는 경우 ``None``. 이 목록의 가능한 값과 설명은 :ref:`AdobeManual`, 400페이지의 표 1.76을 참조하세요.\"\n\n#: ../../annot.rst:495 8bf05b20e751463eae59e5c917d94466\nmsgid \"\"\n\"A list containing a variable number of point (\\\"vertices\\\") coordinates \"\n\"(each given by a pair of floats) for various types of annotations:\"\nmsgstr \"다양한 타입의 주석에 대한 가변 개수의 포인트(\\\"vertices\\\") 좌표(각각 float 쌍으로 제공)를 포함하는 목록:\"\n\n#: ../../annot.rst:497 8912d31ff3344e5e8152219991bcb863\nmsgid \"'Line' -- the starting and ending coordinates (2 float pairs).\"\nmsgstr \"'Line' -- 시작 및 종료 좌표(2개의 float 쌍).\"\n\n#: ../../annot.rst:498 a5b0fa3b850f4856bd236c668f63f1eb\nmsgid \"\"\n\"'FreeText' -- 2 or 3 float pairs designating the starting, the (optional)\"\n\" knee point, and the ending coordinates.\"\nmsgstr \"'FreeText' -- 시작, (선택적) 무릎 포인트, 종료 좌표를 지정하는 2개 또는 3개의 float 쌍.\"\n\n#: ../../annot.rst:499 b0ee60812ba343fea5fc2d15019955f2\nmsgid \"\"\n\"'PolyLine' / 'Polygon' -- the coordinates of the edges connected by line \"\n\"pieces (n float pairs for n points).\"\nmsgstr \"'PolyLine' / 'Polygon' -- 라인 조각으로 연결된 가장자리의 좌표(n개 포인트에 대해 n개의 float 쌍).\"\n\n#: ../../annot.rst:500 8fbc31fb944e4da2868503b7613244d0\nmsgid \"\"\n\"text markup annotations -- 4 float pairs specifying the *QuadPoints* of \"\n\"the marked text span (see :ref:`AdobeManual`, page 403).\"\nmsgstr \"텍스트 마크업 주석 -- 표시된 텍스트 스팬의 *QuadPoints* 를 지정하는 4개의 float 쌍(:ref:`AdobeManual`, 403페이지 참조).\"\n\n#: ../../annot.rst:501 09ceddfd7c4642e187b77e4fe278f331\nmsgid \"\"\n\"'Ink' -- list of one to many sublists of vertex coordinates. Each such \"\n\"sublist represents a separate line in the drawing.\"\nmsgstr \"'Ink' -- 하나에서 많은 개수의 정점 좌표 하위 목록 목록. 각 하위 목록은 그리기의 별도 라인을 나타냅니다.\"\n\n#: ../../annot.rst:508 e363318aa7cb46ff97b34487bc567275\nmsgid \"\"\n\"dictionary of two lists of floats in range *0 <= float <= 1* specifying \"\n\"the \\\"stroke\\\" and the interior (\\\"fill\\\") colors. The stroke color is \"\n\"used for borders and everything that is actively painted or written \"\n\"(\\\"stroked\\\"). The fill color is used for the interior of objects like \"\n\"line ends, circles and squares. The lengths of these lists implicitly \"\n\"determine the colorspaces used: 1 = GRAY, 3 = RGB, 4 = CMYK. So \\\"[1.0, \"\n\"0.0, 0.0]\\\" stands for RGB color red. Both lists can be empty if no color\"\n\" is specified. Be aware about some potentially unexpected cases:\"\nmsgstr \"*0 <= float <= 1* 범위의 float 두 목록으로 \\\"stroke\\\" 및 내부(\\\"fill\\\") 색상을 지정하는 딕셔너리. 스트로크 색상은 테두리와 활성적으로 그려지거나 작성된 모든 것(\\\"stroked\\\")에 사용됩니다. 채우기 색상은 라인 끝, 원 및 사각형과 같은 객체의 내부에 사용됩니다. 이러한 목록의 길이는 암묵적으로 사용되는 색상 공간을 결정합니다: 1 = GRAY, 3 = RGB, 4 = CMYK. 따라서 \\\"[1.0, 0.0, 0.0]\\\"은 RGB 색상 빨강을 나타냅니다. 색상이 지정되지 않은 경우 두 목록 모두 비어 있을 수 있습니다. 잠재적으로 예상치 못한 경우에 유의하세요:\"\n\n#: ../../annot.rst:510 c98f3742209a4834b74c3d4385888358\nmsgid \"\"\n\"The color of Highlight annotations is a **stroke** color, contrary to \"\n\"intuition.\"\nmsgstr \"Highlight 주석의 색상은 직관과 반대로 **stroke** 색상입니다.\"\n\n#: ../../annot.rst:511 2d1b77af92f94df2901498dee3ecf512\nmsgid \"\"\n\"The color if FreeText annotations is a **stroke** color, but appears as \"\n\"the color that fills the rectangle and any applicable line end symbols. \"\n\"Text color and border color cannot be accessed at all.\"\nmsgstr \"FreeText 주석의 색상은 **stroke** 색상이지만, 사각형과 모든 적용 가능한 라인 끝 심볼을 채우는 색상으로 나타납니다. 텍스트 색상과 테두리 색상은 전혀 액세스할 수 없습니다.\"\n\n#: ../../annot.rst:517 5673a83fdd3046e1a25a02e890bf9503\nmsgid \"The PDF :data:`xref`.\"\nmsgstr \"PDF :data:`xref`.\"\n\n#: ../../annot.rst:523 80d30458b0ae4d81a75fccb23e4560df\nmsgid \"\"\n\"The PDF :data:`xref` of an annotation to which this one responds. Return \"\n\"zero if this is no response annotation.\"\nmsgstr \"이 주석이 응답하는 주석의 PDF :data:`xref`. 응답 주석이 아니면 0을 반환합니다.\"\n\n#: ../../annot.rst:529 adc968b773a6471aba76a7111c2340a5\nmsgid \"\"\n\"The PDF :data:`xref` of the associated Popup annotation. Zero if non-\"\n\"existent.\"\nmsgstr \"연결된 Popup 주석의 PDF :data:`xref`. 존재하지 않으면 0.\"\n\n#: ../../annot.rst:535 87e7894e6b484ea3b6e9b676e28d88b3\nmsgid \"Whether the annotation has a Popup annotation.\"\nmsgstr \"주석에 Popup 주석이 있는지 여부.\"\n\n#: ../../annot.rst:541 a5edaf80b163482b844afac753dce499\nmsgid \"\"\n\"Whether the annotation's Popup is open -- **or** the annotation itself \"\n\"('Text' annotations only).\"\nmsgstr \"주석의 Popup이 열려 있는지 여부 -- **또는** 주석 자체('Text' 주석만 해당).\"\n\n#: ../../annot.rst:547 600f5a64e8a4400da0c1ae35c135efd1\nmsgid \"\"\n\"The rectangle of the associated Popup annotation. Infinite rectangle if \"\n\"non-existent.\"\nmsgstr \"연결된 Popup 주석의 사각형. 존재하지 않으면 무한 사각형.\"\n\n#: ../../annot.rst:553 9fd4e2374ea64a4f895272c2450db57b\nmsgid \"\"\n\"A tuple of four floats representing the `/RD` entry of the annotation. \"\n\"The four numbers describe the numerical differences (left, top, -right, \"\n\"-bottom) between two rectangles: the :attr:`rect` of the annotation and a\"\n\" rectangle contained within that rectangle. If the entry is missing, this\"\n\" property is `(0, 0, 0, 0)`. If the annotation border is a normal, \"\n\"straight line, these numbers are typically border width divided by 2. If \"\n\"the annotation has a \\\"cloudy\\\" border, you will see the breadth of the \"\n\"cloud semi-circles here. In general, the numbers need not be identical. \"\n\"To compute the inner rectangle do `a.rect + a.rect_delta`.\"\nmsgstr \"주석의 `/RD` 항목을 나타내는 4개의 float 튜플. 네 숫자는 두 사각형(주석의 :attr:`rect` 와 그 사각형 내에 포함된 사각형) 사이의 수치 차이(왼쪽, 위쪽, -오른쪽, -아래쪽)를 설명합니다. 항목이 없으면 이 속성은 `(0, 0, 0, 0)` 입니다. 주석 테두리가 일반적인 직선인 경우, 이러한 숫자는 일반적으로 테두리 너비를 2로 나눈 값입니다. 주석에 \\\"cloudy\\\" 테두리가 있으면 여기에서 클라우드 반원의 폭을 볼 수 있습니다. 일반적으로 숫자가 동일할 필요는 없습니다. 내부 사각형을 계산하려면 `a.rect + a.rect_delta` 를 수행하세요.\"\n\n#: ../../annot.rst:557 76373f31dcbe446392d079eb34532b34\nmsgid \"\"\n\"A dictionary containing border characteristics. Empty if no border \"\n\"information exists. The following keys may be present:\"\nmsgstr \"테두리 특성을 포함하는 딕셔너리. 테두리 정보가 없으면 비어 있습니다. 다음 키가 있을 수 있습니다:\"\n\n#: ../../annot.rst:559 2a2fab2fdf524b6184a1f5b62304135a\nmsgid \"\"\n\"*width* -- a float indicating the border thickness in points. The value \"\n\"is -1.0 if no width is specified.\"\nmsgstr \"*width* -- 포인트 단위의 테두리 두께를 나타내는 float. 너비가 지정되지 않으면 값은 -1.0입니다.\"\n\n#: ../../annot.rst:561 ee7176832c7e4740b78bb806706a9d04\nmsgid \"\"\n\"*dashes* -- a sequence of integers specifying a line dashing pattern. \"\n\"*[]* means no dashes, *[n]* means equal on-off lengths of *n* points, \"\n\"longer lists will be interpreted as specifying alternating on-off length \"\n\"values. See the :ref:`AdobeManual` page 126 for more details.\"\nmsgstr \"*dashes* -- 라인 파선 패턴을 지정하는 정수 시퀀스. *[]* 는 파선 없음을 의미하고, *[n]* 는 *n* 포인트의 동일한 on-off 길이를 의미하며, 더 긴 목록은 교대 on-off 길이 값을 지정하는 것으로 해석됩니다. 자세한 내용은 :ref:`AdobeManual` 126페이지를 참조하세요.\"\n\n#: ../../annot.rst:563 994ba35808ba4456b6568752b410a28e\nmsgid \"\"\n\"*style* -- 1-byte border style: **\\\"S\\\"** (Solid) = solid line \"\n\"surrounding the annotation, **\\\"D\\\"** (Dashed) = dashed line surrounding \"\n\"the annotation, the dash pattern is specified by the *dashes* entry, \"\n\"**\\\"B\\\"** (Beveled) = a simulated embossed rectangle that appears to be \"\n\"raised above the surface of the page, **\\\"I\\\"** (Inset) = a simulated \"\n\"engraved rectangle that appears to be recessed below the surface of the \"\n\"page, **\\\"U\\\"** (Underline) = a single line along the bottom of the \"\n\"annotation rectangle.\"\nmsgstr \"*style* -- 1바이트 테두리 스타일: **\\\"S\\\"** (Solid) = 주석을 둘러싸는 실선, **\\\"D\\\"** (Dashed) = 주석을 둘러싸는 파선, 파선 패턴은 *dashes* 항목으로 지정됨, **\\\"B\\\"** (Beveled) = 페이지 표면 위에 올라간 것처럼 보이는 시뮬레이션된 볼록 사각형, **\\\"I\\\"** (Inset) = 페이지 표면 아래로 움푹 들어간 것처럼 보이는 시뮬레이션된 조각 사각형, **\\\"U\\\"** (Underline) = 주석 사각형의 하단을 따른 단일 라인.\"\n\n#: ../../annot.rst:565 7700bc48fde44a268bcd7c4a8afa5304\nmsgid \"\"\n\"*clouds* -- an integer indicating a \\\"cloudy\\\" border, where ``n`` is an \"\n\"integer `-1 <= n <= 2`. A value `n = 0` indicates a straight line (no \"\n\"clouds), 1 means small and 2 means large semi-circles, mimicking the \"\n\"cloudy appearance. If -1, then no specification is present.\"\nmsgstr \"*clouds* -- \\\"cloudy\\\" 테두리를 나타내는 정수, 여기서 ``n`` 은 정수 `-1 <= n <= 2`. 값 `n = 0` 은 직선(클라우드 없음)을 나타내고, 1은 작은 반원을, 2는 큰 반원을 의미하여 클라우드 모양을 모방합니다. -1이면 지정이 없습니다.\"\n\n#: ../../annot.rst:573 332ac742d76d48529ceb6b4e40f7295a\nmsgid \"Annotation Icons in MuPDF\"\nmsgstr \"MuPDF의 주석 아이콘\"\n\n#: ../../annot.rst:574 21859a0e63974afa950419ab98ff55e6\nmsgid \"\"\n\"This is a list of icons referenceable by name for annotation types 'Text'\"\n\" and 'FileAttachment'. You can use them via the *icon* parameter when \"\n\"adding an annotation, or use the as argument in :meth:`Annot.set_name`. \"\n\"It is left to your discretion which item to choose when -- no mechanism \"\n\"will keep you from using e.g. the \\\"Speaker\\\" icon for a \"\n\"'FileAttachment'.\"\nmsgstr \"이것은 'Text' 및 'FileAttachment' 주석 타입에 대해 이름으로 참조할 수 있는 아이콘 목록입니다. 주석을 추가할 때 *icon* 매개변수를 통해 사용하거나 :meth:`Annot.set_name` 의 인수로 사용할 수 있습니다. 어떤 항목을 선택할지는 사용자의 재량에 맡겨집니다 -- 예를 들어 'FileAttachment'에 \\\"Speaker\\\" 아이콘을 사용하는 것을 막는 메커니즘은 없습니다.\"\n\n#: ../../annot.rst:580 cb12c1793cdb4341b24fbf6538c60d1c\nmsgid \"Example\"\nmsgstr \"예제\"\n\n#: ../../annot.rst:581 a2296e47889a4fec983f5aa41e485291\nmsgid \"\"\n\"Change the graphical image of an annotation. Also update the \\\"author\\\" \"\n\"and the text to be shown in the popup window::\"\nmsgstr \"주석의 그래픽 이미지를 변경합니다. 또한 팝업 창에 표시될 \\\"author\\\" 및 텍스트를 업데이트합니다::\"\n\n#: ../../annot.rst:604 7bff751c7d604fe38047b43fdeb95933\nmsgid \"\"\n\"This is how the circle annotation looks like before and after the change \"\n\"(pop-up windows displayed using Nitro PDF viewer):\"\nmsgstr \"변경 전후의 원 주석 모습입니다(Nitro PDF 뷰어를 사용하여 표시된 팝업 창):\"\n\n#: ../../annot.rst:606 479b5bc5389b486e92aaf64c6226c673\nmsgid \"|circle|\"\nmsgstr \"\"\n\n#: ../../annot.rst:608 031e9835b5ea4674bd3bcd678ae780a5\n#: 8bea81da58c844a9abeb9a5253d1a9b6\nmsgid \"circle\"\nmsgstr \"circle\"\n\n#: ../../annot.rst:612 a8717fc2c8cd4706b95166aae42c2f9b\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../annot.rst:613 6d03771b774345a5b005846ee4002288\nmsgid \"\"\n\"Rotating an annotation also changes its rectangle. Depending on how the \"\n\"annotation was defined, the original rectangle is **cannot be \"\n\"reconstructed** by setting the rotation value to zero again and will be \"\n\"lost.\"\nmsgstr \"주석을 회전시키면 사각형도 변경됩니다. 주석이 정의된 방식에 따라 원래 사각형은 회전 값을 다시 0으로 설정해도 **재구성할 수 없으며** 손실됩니다.\"\n\n#: ../../annot.rst:615 c6c9d602fa054b6fac8c6ec2c52ad078\nmsgid \"\"\n\"Only the following annotation types support method \"\n\":meth:`Annot.set_rect`: Text, FreeText, Square, Circle, Redact, Stamp, \"\n\"Caret, FileAttachment, Sound, and Movie.\"\nmsgstr \"다음 주석 타입만 :meth:`Annot.set_rect` 메서드를 지원합니다: Text, FreeText, Square, Circle, Redact, Stamp, Caret, FileAttachment, Sound, Movie.\"\n\n#: ../../footer.rst:46 bc670bbcee16481398498b6cc9d3f828\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/app1.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b63e36b67e8a44e789752decae758e83\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 e0da5e0d85184ed69a42ef8e32e4ed85\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 e06822680b004870af6da375e9614933\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../app1.rst:7 4aa59227e1bc4902938be155b3c846ab\nmsgid \"Appendix 1: Details on Text Extraction\"\nmsgstr \"부록 1: 텍스트 추출에 대한 세부사항\"\n\n#: ../../app1.rst:8 c4a15e5247104a09bb9b36ac199c0a28\nmsgid \"\"\n\"This chapter provides background on the text extraction methods of \"\n\"PyMuPDF.\"\nmsgstr \"이 장은 |PyMuPDF| 의 텍스트 추출 메서드에 대한 배경 정보를 제공합니다.\"\n\n#: ../../app1.rst:10 2e9bc8cf9b71428b8520ed5b6afad430\nmsgid \"Information of interest are\"\nmsgstr \"관심 있는 정보는 다음과 같습니다\"\n\n#: ../../app1.rst:12 0deb2f883f5f4387bde429329f1bae7b\nmsgid \"what do they provide?\"\nmsgstr \"그들이 무엇을 제공하는가?\"\n\n#: ../../app1.rst:13 45c9c32702024484bdb3305c7e87faf7\nmsgid \"what do they imply (processing time / data sizes)?\"\nmsgstr \"그들이 무엇을 의미하는가(처리 시간 / 데이터 크기)?\"\n\n#: ../../app1.rst:16 fde4b48bf0784a33849cd72c5d22218c\nmsgid \"General structure of a TextPage\"\nmsgstr \"TextPage의 일반적인 구조\"\n\n#: ../../app1.rst:17 7fc02c7d51cd42079849d6836d102acc\nmsgid \"\"\n\":ref:`TextPage` is one of (Py-) MuPDF's classes. It is normally created \"\n\"(and destroyed again) behind the curtain, when :ref:`Page` text \"\n\"extraction methods are used, but it is also available directly and can be\"\n\" used as a persistent object. Other than its name suggests, images may \"\n\"optionally also be part of a text page::\"\nmsgstr \":ref:`TextPage` 는 (Py-) |MuPDF| 의 클래스 중 하나입니다. 일반적으로 :ref:`Page` 텍스트 추출 메서드가 사용될 때 배후에서 생성(그리고 다시 파괴)되지만, 직접 사용할 수도 있으며 영구 객체로 사용할 수 있습니다. 이름이 시사하는 것과 달리, 이미지는 선택적으로 텍스트 페이지의 일부일 수도 있습니다::\"\n\n#: ../../app1.rst:27 66fcac07e660407fa94a50c99aacdd57\nmsgid \"A **text page** consists of blocks (= roughly paragraphs).\"\nmsgstr \"**텍스트 페이지** 는 블록(= 대략 단락)으로 구성됩니다.\"\n\n#: ../../app1.rst:29 0be706ea23474e148d6ac4453252bd47\nmsgid \"A **block** consists of either lines and their characters, or an image.\"\nmsgstr \"**블록** 은 행과 그 문자, 또는 이미지로 구성됩니다.\"\n\n#: ../../app1.rst:31 c0a517869bb34a7d97003a5aef98fd51\nmsgid \"A **line** consists of spans.\"\nmsgstr \"**행** 은 스팬으로 구성됩니다.\"\n\n#: ../../app1.rst:33 517dd3b2b07645b8b02c39add65933dd\nmsgid \"\"\n\"A **span** consists of adjacent characters with identical font \"\n\"properties: name, size, flags and color.\"\nmsgstr \"**스팬** 은 동일한 글꼴 속성(이름, 크기, 플래그 및 색상)을 가진 인접한 문자로 구성됩니다.\"\n\n#: ../../app1.rst:36 275e9dfe8a8c43eaac52d976da135915\nmsgid \"Plain Text\"\nmsgstr \"일반 텍스트\"\n\n#: ../../app1.rst:38 9d36b5923a304f7a9edbb308a34e087e\nmsgid \"\"\n\"Function :meth:`TextPage.extractText` (or *Page.get_text(\\\"text\\\")*) \"\n\"extracts a page's plain **text in original order** as specified by the \"\n\"creator of the document.\"\nmsgstr \"함수 :meth:`TextPage.extractText` (또는 *Page.get_text(\\\"text\\\")*) 는 문서 작성자가 지정한 대로 페이지의 일반 **텍스트를 원래 순서대로** 추출합니다.\"\n\n#: ../../app1.rst:40 a844cfb991fb44ba922960d023c28deb\nmsgid \"An example output::\"\nmsgstr \"예제 출력::\"\n\n#: ../../app1.rst:45 83c6c339e3924476b41ff9b80c5e50d9\nmsgid \"\"\n\"The output may not equal an accustomed \\\"natural\\\" reading order. \"\n\"However, you can request a reordering following the scheme \\\"top-left to \"\n\"bottom-right\\\" by executing `page.get_text(\\\"text\\\", sort=True)`.\"\nmsgstr \"출력이 익숙한 \\\"자연스러운\\\" 읽기 순서와 같지 않을 수 있습니다. 그러나 `page.get_text(\\\"text\\\", sort=True)` 를 실행하여 \\\"왼쪽 위에서 오른쪽 아래로\\\" 체계에 따라 재정렬을 요청할 수 있습니다.\"\n\n#: ../../app1.rst:49 ../../app1.rst:337 19e4af19f3d74a33909a5898279c5eab\n#: 4eb48dd8cc9e4ac88b8890d5ed10f9a7\nmsgid \"BLOCKS\"\nmsgstr \"BLOCKS\"\n\n#: ../../app1.rst:51 686c7ad1dcf54c52be5a45853aad1f78\nmsgid \"\"\n\"Function :meth:`TextPage.extractBLOCKS` (or *Page.get_text(\\\"blocks\\\")*) \"\n\"extracts a page's text blocks as a list of items like::\"\nmsgstr \"함수 :meth:`TextPage.extractBLOCKS` (또는 *Page.get_text(\\\"blocks\\\")*) 는 페이지의 텍스트 블록을 다음과 같은 항목 목록으로 추출합니다::\"\n\n#: ../../app1.rst:55 c216dd1a83d846b19dfbfc40fbbb3a86\nmsgid \"\"\n\"Where the first 4 items are the float coordinates of the block's bbox. \"\n\"The lines within each block are concatenated by a new-line character.\"\nmsgstr \"여기서 처음 4개 항목은 블록의 bbox의 부동 소수점 좌표입니다. 각 블록 내의 행은 줄바꿈 문자로 연결됩니다.\"\n\n#: ../../app1.rst:57 ac5e7636040b407abf4b4c74f54734e6\nmsgid \"\"\n\"This is a high-speed method, which by default also extracts image meta \"\n\"information: Each image appears as a block with one text line, which \"\n\"contains meta information. The image itself is not shown.\"\nmsgstr \"이것은 고속 메서드이며, 기본적으로 이미지 메타 정보도 추출합니다: 각 이미지는 메타 정보를 포함하는 하나의 텍스트 행이 있는 블록으로 나타납니다. 이미지 자체는 표시되지 않습니다.\"\n\n#: ../../app1.rst:59 493c35f505154b66a5413eb8aae3f20b\nmsgid \"\"\n\"As with simple text output above, the `sort` argument can be used as well\"\n\" to obtain a reading order.\"\nmsgstr \"위의 간단한 텍스트 출력과 마찬가지로 `sort` 인수를 사용하여 읽기 순서를 얻을 수 있습니다.\"\n\n#: ../../app1.rst:61 ../../app1.rst:79 3b27a871707241fab31e8b57d54a181b\n#: 72a6a0bd50b84a369ab338f015c7c0c5\nmsgid \"Example output::\"\nmsgstr \"예제 출력::\"\n\n#: ../../app1.rst:69 ../../app1.rst:338 2b7c8cb324cd43a5935bad475501fbba\n#: ac2182e6a5334397ba4cba52f6a0ecbb\nmsgid \"WORDS\"\nmsgstr \"WORDS\"\n\n#: ../../app1.rst:71 bd891cd06d344be6a34c3533eef6b2b1\nmsgid \"\"\n\"Function :meth:`TextPage.extractWORDS` (or *Page.get_text(\\\"words\\\")*) \"\n\"extracts a page's text **words** as a list of items like::\"\nmsgstr \"함수 :meth:`TextPage.extractWORDS` (또는 *Page.get_text(\\\"words\\\")*) 는 페이지의 텍스트 **단어** 를 다음과 같은 항목 목록으로 추출합니다::\"\n\n#: ../../app1.rst:75 7b33ff6ba92d470f8bab020fcd37037d\nmsgid \"\"\n\"Where the first 4 items are the float coordinates of the words's bbox. \"\n\"The last three integers provide some more information on the word's \"\n\"whereabouts.\"\nmsgstr \"여기서 처음 4개 항목은 단어의 bbox의 부동 소수점 좌표입니다. 마지막 세 정수는 단어의 위치에 대한 추가 정보를 제공합니다.\"\n\n#: ../../app1.rst:77 d553fb9cb8484714ba2faab69dc0c761\nmsgid \"\"\n\"This is a high-speed method. As with the previous methods, argument \"\n\"`sort=True` will reorder the words.\"\nmsgstr \"이것은 고속 메서드입니다. 이전 메서드와 마찬가지로 인수 `sort=True` 는 단어를 재정렬합니다.\"\n\n#: ../../app1.rst:95 ../../app1.rst:341 4c71524cc80240d8a4a615692160ee42\n#: 6e202dc149ab40d4a04fbf729bde5724\nmsgid \"HTML\"\nmsgstr \"HTML\"\n\n#: ../../app1.rst:97 279a64262cf0486490e50a36ebcb9fc4\nmsgid \"\"\n\":meth:`TextPage.extractHTML` (or *Page.get_text(\\\"html\\\")* output fully \"\n\"reflects the structure of the page's ``TextPage`` -- much like DICT / \"\n\"JSON below. This includes images, font information and text positions. If\"\n\" wrapped in HTML header and trailer code, it can readily be displayed by \"\n\"an internet browser. Our above example::\"\nmsgstr \":meth:`TextPage.extractHTML` (또는 *Page.get_text(\\\"html\\\")* 출력은 페이지의 ``TextPage`` 구조를 완전히 반영합니다 -- 아래의 DICT / JSON과 매우 유사합니다. 이것은 이미지, 글꼴 정보 및 텍스트 위치를 포함합니다. HTML 헤더 및 트레일러 코드로 감싸면 인터넷 브라우저에서 쉽게 표시할 수 있습니다. 위의 예제::\"\n\n#: ../../app1.rst:113 a754b6fee5f44c9e9763dd071ea484d3\nmsgid \"Controlling Quality of HTML Output\"\nmsgstr \"HTML 출력 품질 제어\"\n\n#: ../../app1.rst:114 9d69d29a89e34b598cab8061b0df6acb\nmsgid \"\"\n\"While HTML output has improved a lot in MuPDF v1.12.0, it is not yet bug-\"\n\"free: we have found problems in the areas **font support** and **image \"\n\"positioning**.\"\nmsgstr \"|MuPDF| v1.12.0에서 HTML 출력이 많이 개선되었지만, 아직 버그가 없지는 않습니다: **글꼴 지원** 및 **이미지 위치 지정** 영역에서 문제를 발견했습니다.\"\n\n#: ../../app1.rst:116 e323aee6a8184c43b04054264f0ad164\nmsgid \"\"\n\"HTML text contains references to the fonts used of the original document.\"\n\" If these are not known to the browser (a fat chance!), it will replace \"\n\"them with others; the results will probably look awkward. This issue \"\n\"varies greatly by browser -- on my Windows machine, MS Edge worked just \"\n\"fine, whereas Firefox looked horrible.\"\nmsgstr \"HTML 텍스트에는 원본 문서에서 사용된 글꼴에 대한 참조가 포함되어 있습니다. 브라우저가 이를 알지 못하면(가능성은 낮지만!) 다른 것으로 대체할 수 있으며, 결과가 어색해 보일 수 있습니다. 이 문제는 브라우저에 따라 크게 다릅니다 -- Windows 머신에서 MS Edge는 잘 작동했지만 Firefox는 형편없이 보였습니다.\"\n\n#: ../../app1.rst:118 a3e819ae14b54c27a9a077e7e935cb86\nmsgid \"\"\n\"For PDFs with a complex structure, images may not be positioned and / or \"\n\"sized correctly. This seems to be the case for rotated pages and pages, \"\n\"where the various possible page bbox variants do not coincide (e.g. \"\n\"*MediaBox != CropBox*). We do not know yet, how to address this -- we \"\n\"filed a bug at MuPDF's site.\"\nmsgstr \"복잡한 구조를 가진 PDF의 경우 이미지가 올바르게 위치 지정되거나 크기 조정되지 않을 수 있습니다. 이것은 회전된 페이지와 다양한 가능한 페이지 bbox 변형이 일치하지 않는 페이지(예: *MediaBox != CropBox*)의 경우인 것 같습니다. 이것을 해결하는 방법은 아직 알지 못합니다 -- |MuPDF| 사이트에 버그를 제출했습니다.\"\n\n#: ../../app1.rst:120 eb269d37c6994ea68a4d82c390bd674f\nmsgid \"\"\n\"To address the font issue, you can use a simple utility script to scan \"\n\"through the HTML file and replace font references. Here is a little \"\n\"example that replaces all fonts with one of the :ref:`Base-14-Fonts`: \"\n\"serifed fonts will become \\\"Times\\\", non-serifed \\\"Helvetica\\\" and \"\n\"monospaced will become \\\"Courier\\\". Their respective variations for \"\n\"\\\"bold\\\", \\\"italic\\\", etc. are hopefully done correctly by your browser::\"\nmsgstr \"글꼴 문제를 해결하기 위해 HTML 파일을 스캔하고 글꼴 참조를 교체하는 간단한 유틸리티 스크립트를 사용할 수 있습니다. 다음은 모든 글꼴을 :ref:`Base-14-Fonts` 중 하나로 교체하는 작은 예제입니다: 세리프 글꼴은 \\\"Times\\\"가 되고, 비세리프 글꼴은 \\\"Helvetica\\\"가 되며, 고정폭 글꼴은 \\\"Courier\\\"가 됩니다. \\\"bold\\\", \\\"italic\\\" 등에 대한 각각의 변형은 브라우저에서 올바르게 처리되기를 바랍니다::\"\n\n#: ../../app1.rst:160 9a01edbae3494fb6bcfa415551ffe12d\nmsgid \"DICT (or JSON)\"\nmsgstr \"DICT (또는 JSON)\"\n\n#: ../../app1.rst:162 dc5943b2ac244ae3bd4c1c3cced27b9a\nmsgid \"\"\n\":meth:`TextPage.extractDICT` (or *Page.get_text(\\\"dict\\\", sort=False)*) \"\n\"output fully reflects the structure of a ``TextPage`` and provides image \"\n\"content and position detail (*bbox* -- boundary boxes in pixel units) for\"\n\" every block, line and span. Images are stored as *bytes* for DICT output\"\n\" and base64 encoded strings for JSON output.\"\nmsgstr \":meth:`TextPage.extractDICT` (또는 *Page.get_text(\\\"dict\\\", sort=False)*) 출력은 ``TextPage`` 구조를 완전히 반영하며 모든 블록, 행 및 스팬에 대한 이미지 콘텐츠 및 위치 세부 정보(*bbox* -- 픽셀 단위의 경계 상자)를 제공합니다. 이미지는 DICT 출력의 경우 *bytes* 로 저장되고 JSON 출력의 경우 base64 인코딩된 문자열로 저장됩니다.\"\n\n#: ../../app1.rst:164 c83998d97cb54af2a6c9e8ee068e02d3\nmsgid \"\"\n\"For a visualization of the dictionary structure have a look at \"\n\":ref:`textpagedict`.\"\nmsgstr \"딕셔너리 구조의 시각화는 :ref:`textpagedict` 를 참조하세요.\"\n\n#: ../../app1.rst:166 dd7c1a96c694470682bfdfceee248a97\nmsgid \"Here is how this looks like::\"\nmsgstr \"다음은 이것이 어떻게 보이는지입니다::\"\n\n#: ../../app1.rst:192 c2fb2cd52f07453b86d0afd6278fef62\nmsgid \"RAWDICT (or RAWJSON)\"\nmsgstr \"RAWDICT (또는 RAWJSON)\"\n\n#: ../../app1.rst:193 7d7646fe8d554083af47f4d372febdde\nmsgid \"\"\n\":meth:`TextPage.extractRAWDICT` (or *Page.get_text(\\\"rawdict\\\", \"\n\"sort=False)*) is an **information superset of DICT** and takes the detail\"\n\" level one step deeper. It looks exactly like the above, except that the \"\n\"*\\\"text\\\"* items (*string*) in the spans are replaced by the list \"\n\"*\\\"chars\\\"*. Each *\\\"chars\\\"* entry is a character *dict*. For example, \"\n\"here is what you would see in place of item *\\\"text\\\": \\\"Text in black \"\n\"color.\\\"* above::\"\nmsgstr \":meth:`TextPage.extractRAWDICT` (또는 *Page.get_text(\\\"rawdict\\\", sort=False)*) 는 **DICT의 정보 상위 집합** 이며 세부 수준을 한 단계 더 깊게 가져갑니다. 위와 정확히 같아 보이지만, 스팬의 *\\\"text\\\"* 항목(*string*)이 *\\\"chars\\\"* 목록으로 대체됩니다. 각 *\\\"chars\\\"* 항목은 문자 *dict* 입니다. 예를 들어, 위의 *\\\"text\\\": \\\"Text in black color.\\\"* 항목 대신 다음과 같은 것을 볼 수 있습니다::\"\n\n#: ../../app1.rst:224 ../../app1.rst:339 2400046f9c4f49858da21224a19d4b15\n#: 2d3722af4f584209bd8eaab07e032c6d\nmsgid \"XML\"\nmsgstr \"XML\"\n\n#: ../../app1.rst:226 c5a5b0c5667b42278fbebec3ebb83fab\nmsgid \"\"\n\"The :meth:`TextPage.extractXML` (or *Page.get_text(\\\"xml\\\")*) version \"\n\"extracts text (no images) with the detail level of RAWDICT::\"\nmsgstr \":meth:`TextPage.extractXML` (또는 *Page.get_text(\\\"xml\\\")*) 버전은 RAWDICT의 세부 수준으로 텍스트(이미지 없음)를 추출합니다::\"\n\n#: ../../app1.rst:255 76940447ff984e9f8267433f30622b18\nmsgid \"\"\n\"We have successfully tested `lxml <https://pypi.org/project/lxml/>`_ to \"\n\"interpret this output.\"\nmsgstr \"이 출력을 해석하기 위해 `lxml <https://pypi.org/project/lxml/>`_ 를 성공적으로 테스트했습니다.\"\n\n#: ../../app1.rst:258 ../../app1.rst:340 a405be8a4b8c4148920284c0af5d2a21\n#: def99570eabf40eb9a2296563cf87c89\nmsgid \"XHTML\"\nmsgstr \"XHTML\"\n\n#: ../../app1.rst:259 f860ba05b7b84b0cbbd677dfb53ba52c\nmsgid \"\"\n\":meth:`TextPage.extractXHTML` (or *Page.get_text(\\\"xhtml\\\")*) is a \"\n\"variation of TEXT but in HTML format, containing the bare text and images\"\n\" (\\\"semantic\\\" output)::\"\nmsgstr \":meth:`TextPage.extractXHTML` (또는 *Page.get_text(\\\"xhtml\\\")*) 는 TEXT의 변형이지만 HTML 형식이며, 일반 텍스트와 이미지를 포함합니다(\\\"의미론적\\\" 출력)::\"\n\n#: ../../app1.rst:268 0f8064883834458ab08418752216e011\nmsgid \"Text Extraction Flags Defaults\"\nmsgstr \"텍스트 추출 플래그 기본값\"\n\n#: ../../app1.rst:269 8ba849c311aa457d85362ff7f4f1819e\nmsgid \"\"\n\"New in version 1.16.2: Method :meth:`Page.get_text` supports a keyword \"\n\"parameter *flags* *(int)* to control the amount and the quality of \"\n\"extracted data. The following table shows the defaults settings (flags \"\n\"parameter omitted or None) for each extraction variant. If you specify \"\n\"flags with a value other than ``None``, be aware that you must set **all \"\n\"desired** options. A description of the respective bit settings can be \"\n\"found in :ref:`TextPreserve`.\"\nmsgstr \"버전 1.16.2의 새로운 기능: 메서드 :meth:`Page.get_text` 는 추출된 데이터의 양과 품질을 제어하는 키워드 매개변수 *flags* *(int)* 를 지원합니다. 다음 표는 각 추출 변형에 대한 기본 설정(플래그 매개변수 생략 또는 None)을 보여줍니다. ``None`` 이 아닌 값으로 플래그를 지정하는 경우 **모든 원하는** 옵션을 설정해야 합니다. 각 비트 설정에 대한 설명은 :ref:`TextPreserve` 에서 찾을 수 있습니다.\"\n\n#: ../../app1.rst:271 d40d16d07939413e8c75c3dc13b1127c\nmsgid \"\"\n\"New in v1.19.6: The default combinations in the following table are now \"\n\"available as Python constants: :data:`TEXTFLAGS_TEXT`, \"\n\":data:`TEXTFLAGS_WORDS`, :data:`TEXTFLAGS_BLOCKS`, \"\n\":data:`TEXTFLAGS_DICT`, :data:`TEXTFLAGS_RAWDICT`, \"\n\":data:`TEXTFLAGS_HTML`, :data:`TEXTFLAGS_XHTML`, :data:`TEXTFLAGS_XML`, \"\n\"and :data:`TEXTFLAGS_SEARCH`. You can now easily modify a default flag, \"\n\"e.g.\"\nmsgstr \"v1.19.6의 새로운 기능: 다음 표의 기본 조합은 이제 Python 상수로 사용할 수 있습니다: :data:`TEXTFLAGS_TEXT`, :data:`TEXTFLAGS_WORDS`, :data:`TEXTFLAGS_BLOCKS`, :data:`TEXTFLAGS_DICT`, :data:`TEXTFLAGS_RAWDICT`, :data:`TEXTFLAGS_HTML`, :data:`TEXTFLAGS_XHTML`, :data:`TEXTFLAGS_XML`, 및 :data:`TEXTFLAGS_SEARCH`. 이제 기본 플래그를 쉽게 수정할 수 있습니다. 예를 들어:\"\n\n#: ../../app1.rst:273 dc924700aa9b4042894cae14679d63f2\nmsgid \"**include** images in a \\\"blocks\\\" output:\"\nmsgstr \"\\\"blocks\\\" 출력에 이미지를 **포함**:\"\n\n#: ../../app1.rst:275 3d7561abbff8475c825b8d983783bf39\nmsgid \"`flags = TEXTFLAGS_BLOCKS | TEXT_PRESERVE_IMAGES`\"\nmsgstr \"`flags = TEXTFLAGS_BLOCKS | TEXT_PRESERVE_IMAGES`\"\n\n#: ../../app1.rst:277 4ca8d0166e4646bd80fcc1d69f340a95\nmsgid \"**exclude** images from a \\\"dict\\\" output:\"\nmsgstr \"\\\"dict\\\" 출력에서 이미지를 **제외**:\"\n\n#: ../../app1.rst:279 1a2e1663435b4abaa1b188e5d6bd9338\nmsgid \"`flags = TEXTFLAGS_DICT & ~TEXT_PRESERVE_IMAGES`\"\nmsgstr \"`flags = TEXTFLAGS_DICT & ~TEXT_PRESERVE_IMAGES`\"\n\n#: ../../app1.rst:281 d3769cd425ff4854b0e4292af9c3a0e1\nmsgid \"set **dehyphenation off** in text searches:\"\nmsgstr \"텍스트 검색에서 **하이픈 제거를 끔**:\"\n\n#: ../../app1.rst:283 2365979a4e104875a8c468496909f03d\nmsgid \"`flags = TEXTFLAGS_SEARCH & ~TEXT_DEHYPHENATE`\"\nmsgstr \"`flags = TEXTFLAGS_SEARCH & ~TEXT_DEHYPHENATE`\"\n\n#: ../../app1.rst:287 6f7f786332d34c359591ddf8d17a374b\nmsgid \"Indicator\"\nmsgstr \"표시기\"\n\n#: ../../app1.rst:287 5f2792809a9645ccaa7c3103a8c35f60\nmsgid \"text\"\nmsgstr \"text\"\n\n#: ../../app1.rst:287 9330883adb104a8b880b90565531cf78\nmsgid \"html\"\nmsgstr \"html\"\n\n#: ../../app1.rst:287 ead5e0f63b1849fcad0e1d2b7e718887\nmsgid \"xhtml\"\nmsgstr \"xhtml\"\n\n#: ../../app1.rst:287 6c6f9476a4614058833f45708bdc20be\nmsgid \"xml\"\nmsgstr \"xml\"\n\n#: ../../app1.rst:287 0248ca12579948d7a86695462a79fdcb\nmsgid \"dict\"\nmsgstr \"dict\"\n\n#: ../../app1.rst:287 e7d633c232874f17bede991cf837d6c3\nmsgid \"rawdict\"\nmsgstr \"rawdict\"\n\n#: ../../app1.rst:287 7fa4130e9ccf41c4a89237b146f501ef\nmsgid \"words\"\nmsgstr \"words\"\n\n#: ../../app1.rst:287 34941a4200304d7492e796f779d70af9\nmsgid \"blocks\"\nmsgstr \"blocks\"\n\n#: ../../app1.rst:287 29648526b349495e89efdba8501f7d58\nmsgid \"search\"\nmsgstr \"search\"\n\n#: ../../app1.rst:289 a7ced22ad3514aee9d5860e7a63e2585\nmsgid \"preserve ligatures\"\nmsgstr \"합자 유지\"\n\n#: ../../app1.rst:289 ../../app1.rst:290 ../../app1.rst:291 ../../app1.rst:293\n#: ../../app1.rst:294 ../../app1.rst:295 0cb4cd763ef542608c195c6460b399dc\n#: 0f43651d2736498e96beed8c24af63e9 20bddcebf4b543228091164700c68887\n#: 25d6766e4acb4fc49ec8e4fc1eb66529 2bc4aa25150c4d8c9902fd0ce38a2999\n#: 2bd684139d2e454d819cd76bed2bd102 2e7049fda6e14a2ca9a522be96770d00\n#: 2ea03f7b7fb14b7a976160f27232430c 48e9b5e2fdf046c8a01ae4b5cf3d92b7\n#: 51fcf587aa804e63a7afdca232a5123e 530e59a3a9bd4518859c2074f4a8fb16\n#: 5650d9d0ff634f79a775ea6061792d1e 57fc8ce1840144cfac20f2ad74fc2830\n#: 58b687804f9f44f78d42f22ec402f444 592dbaf3091e4acebbebdacbc132c557\n#: 5fe9aa6f8b084af9b13c0b18aabd3924 6a11a4e3a9ea4e17b2f62dac6565c592\n#: 7e477874caf041e4bfdb2b9715ca466b 8558f363af2e463c86807ec68536a6fe\n#: 856d9f908ce4492d9d6e4d9942aeaf71 a030d647ca2549b28cd1f8423e3250ab\n#: a0b1d47cb17f47bf8e80bb4647de9186 a1764775c19e4c57936ebdd4291fc8bb\n#: ad1ab38b1e5448a784ec98ef8c12df3a b06d0e59e44649a28ad4fc081b0cee19\n#: b4f9c2410ff243ecab4fc54dc7d849e9 bfcb17e586004c2886905b1b94eeed1d\n#: c0f6469d6bc44f709be506a3cdd9a339 c96eb459feb14f60ad45b43c108367f9\n#: d53f99316ae94e71b4d4480f84277945 d5838173cacf47a2b9d2d7ab0f3cbab0\n#: d5b75f9369ea4ceba86c82894b7cad40 d87075ec3a7d4392aed8b7b4266e41a4\n#: e13a6d7235c14b3fb15384adaba80ce9 e2ded0a0075c4d9e931b78360a6cef6b\n#: e93caf9105d0420c9d8bb40bbf2cdf90 eab3ab57cb1548baaf7011b0604ed429\n#: f0220244eb534ddda9c6a22290717a50 f7971b72219d4d95b439b84693a28f73\nmsgid \"1\"\nmsgstr \"\"\n\n#: ../../app1.rst:289 ../../app1.rst:291 ../../app1.rst:292 ../../app1.rst:293\n#: ../../app1.rst:295 011c44af019c41c298922bebee1b1c11\n#: 12c4cb08b28542d49005e9339fe0834c 1c35e49b6df44d79bff74df1b4d78b83\n#: 21f7a63996d64dcb83a41b385bdfe468 31af0f63c4434ef3b9b3bf48be4f77a8\n#: 3b439777a243470cbeaa2171bb389696 428e7a5d17e14bd2823284322ebe8792\n#: 43fd32ccc6b84942abf31f7c7066b718 46be00d2353b4350993b3ade6d4555e5\n#: 517834e9ea544ee48a80774f32298485 594207767efc47ac9b5174f8d44bc078\n#: 5fad2f44f76842fdae75090a3d39fe7a 6273d3b284c94893ae7f4cee674e31bf\n#: 9e452b6cb65f4c7ea9fe05f5e312a3e8 a577f5deaa234a9a8a05f26b7c1b7368\n#: b28c3e3b6015418c983c625e5bc7f5b5 b4566a369cf745989dcdde6fb5650bb8\n#: bf6d2bf8b3bf4c26b4f6c86f2dd651a6 c984d40f754d445c9df1e4477d112414\n#: dab827d3d3944e789a78bf1474d0f410 ded8f8ccfe914788a0b031d4fa55fb21\nmsgid \"0\"\nmsgstr \"\"\n\n#: ../../app1.rst:290 d4a8b0082348457c9b3a7f0c83dde31d\nmsgid \"preserve whitespace\"\nmsgstr \"공백 유지\"\n\n#: ../../app1.rst:291 7cff9f000b1f41abbca9effe3a08af35\nmsgid \"preserve images\"\nmsgstr \"이미지 유지\"\n\n#: ../../app1.rst:291 2dbd9b27a6ad426cb7dcc9be3911020b\n#: c63946a2a43041a995ca0fbeb23153ef d209151eb3624d868e0ce8d60b9347b8\nmsgid \"n/a\"\nmsgstr \"해당 없음\"\n\n#: ../../app1.rst:292 5a4bb22be2824af98d9db38f003324d8\nmsgid \"inhibit spaces\"\nmsgstr \"공백 억제\"\n\n#: ../../app1.rst:293 cb5ae3cd443344048f5ddc1e916152df\nmsgid \"dehyphenate\"\nmsgstr \"하이픈 제거\"\n\n#: ../../app1.rst:294 ac1c83a387304202a50381f999e13a9b\nmsgid \"clip to mediabox\"\nmsgstr \"미디어박스로 자르기\"\n\n#: ../../app1.rst:295 0fec3cdc767c4ecc80645956dbdaa050\nmsgid \"use CID instead of U+FFFD\"\nmsgstr \"U+FFFD 대신 CID 사용\"\n\n#: ../../app1.rst:298 3e0abf5ee8404c7c85743a6d0c348e5f\nmsgid \"**search** refers to the text search function.\"\nmsgstr \"**search** 는 텍스트 검색 함수를 나타냅니다.\"\n\n#: ../../app1.rst:299 2063c0aa9e6746fca18404258dea465f\nmsgid \"**\\\"json\\\"** is handled exactly like **\\\"dict\\\"** and is hence left out.\"\nmsgstr \"**\\\"json\\\"** 은 **\\\"dict\\\"** 와 정확히 동일하게 처리되므로 생략되었습니다.\"\n\n#: ../../app1.rst:300 4a5e41e47c864b39a729542c7bb2ae23\nmsgid \"\"\n\"**\\\"rawjson\\\"** is handled exactly like **\\\"rawdict\\\"** and is hence left\"\n\" out.\"\nmsgstr \"**\\\"rawjson\\\"** 은 **\\\"rawdict\\\"** 와 정확히 동일하게 처리되므로 생략되었습니다.\"\n\n#: ../../app1.rst:301 5783eaf8a223417bbb6edf7595657706\nmsgid \"\"\n\"An \\\"n/a\\\" specification means a value of 0 and setting this bit never \"\n\"has any effect on the output (but an adverse effect on performance).\"\nmsgstr \"\\\"n/a\\\" 지정은 값이 0임을 의미하며 이 비트를 설정해도 출력에 영향을 주지 않습니다(하지만 성능에 부정적인 영향을 미칩니다).\"\n\n#: ../../app1.rst:302 b5dddb0dc411425db6bc1a169ff2a8d4\nmsgid \"\"\n\"If you are not interested in images when using an output variant which \"\n\"includes them by default, then by all means set the respective bit off: \"\n\"You will experience a better performance and much lower space \"\n\"requirements.\"\nmsgstr \"기본적으로 이미지를 포함하는 출력 변형을 사용할 때 이미지에 관심이 없다면, 반드시 해당 비트를 끄세요: 더 나은 성능과 훨씬 낮은 공간 요구 사항을 경험할 수 있습니다.\"\n\n#: ../../app1.rst:304 608cc56e35e24516bf555cbdb28b782e\nmsgid \"To show the effect of `TEXT_INHIBIT_SPACES` have a look at this example::\"\nmsgstr \"`TEXT_INHIBIT_SPACES` 의 효과를 보려면 이 예제를 참조하세요::\"\n\n#: ../../app1.rst:324 73de41a5c50b4025bbb2c6a93243d3b7\nmsgid \"Performance\"\nmsgstr \"성능\"\n\n#: ../../app1.rst:325 008bf5834d9c43878d55c1f182c383ad\nmsgid \"\"\n\"The text extraction methods differ significantly both: in terms of \"\n\"information they supply, and in terms of resource requirements and \"\n\"runtimes. Generally, more information of course means, that more \"\n\"processing is required and a higher data volume is generated.\"\nmsgstr \"텍스트 추출 메서드는 제공하는 정보와 리소스 요구 사항 및 실행 시간 측면에서 모두 크게 다릅니다. 일반적으로 더 많은 정보는 더 많은 처리가 필요하고 더 높은 데이터 볼륨이 생성됨을 의미합니다.\"\n\n#: ../../app1.rst:327 aa82ec64134a4f3bbbea8037e3f3835d\n#, python-format\nmsgid \"\"\n\"Especially images have a **very significant** impact. Make sure to \"\n\"exclude them (via the *flags* parameter) whenever you do not need them. \"\n\"To process the below mentioned 2'700 total pages with default flags \"\n\"settings required 160 seconds across all extraction methods. When all \"\n\"images where excluded, less than 50% of that time (77 seconds) were \"\n\"needed.\"\nmsgstr \"특히 이미지는 **매우 큰** 영향을 미칩니다. 필요하지 않을 때는 반드시 제외하세요(*flags* 매개변수를 통해). 기본 플래그 설정으로 아래에 언급된 총 2,700페이지를 처리하는 데 모든 추출 메서드에서 160초가 필요했습니다. 모든 이미지가 제외되면 그 시간의 50% 미만(77초)이 필요했습니다.\"\n\n#: ../../app1.rst:329 74982287fc904cbe9d5f67869c717cff\nmsgid \"\"\n\"To begin with, all methods are **very fast** in relation to other \"\n\"products out there in the market. In terms of processing speed, we are \"\n\"not aware of a faster (free) tool. Even the most detailed method, \"\n\"RAWDICT, processes all 1'310 pages of the :ref:`AdobeManual` in less than\"\n\" 5 seconds (simple text needs less than 2 seconds here).\"\nmsgstr \"우선, 모든 메서드는 시장의 다른 제품과 비교하여 **매우 빠릅니다**. 처리 속도 측면에서 더 빠른(무료) 도구는 알지 못합니다. 가장 상세한 메서드인 RAWDICT조차 :ref:`AdobeManual` 의 모든 1,310페이지를 5초 미만으로 처리합니다(여기서는 간단한 텍스트가 2초 미만이 필요합니다).\"\n\n#: ../../app1.rst:331 83629ccfb7c9414089033b0147642f2e\nmsgid \"\"\n\"The following table shows average relative speeds (\\\"RSpeed\\\", baseline \"\n\"1.00 is TEXT), taken across ca. 1400 text-heavy and 1300 image-heavy \"\n\"pages.\"\nmsgstr \"다음 표는 약 1400페이지의 텍스트 중심 페이지와 1300페이지의 이미지 중심 페이지에서 가져온 평균 상대 속도(\\\"RSpeed\\\", 기준선 1.00은 TEXT)를 보여줍니다.\"\n\n#: ../../app1.rst:334 bc84a1d73aa545a3aca4437e5017ed0e\nmsgid \"Method\"\nmsgstr \"메서드\"\n\n#: ../../app1.rst:334 9368181159ab4fd6a75aae6bdaa5d189\nmsgid \"RSpeed\"\nmsgstr \"RSpeed\"\n\n#: ../../app1.rst:334 7110ef6f2a7c4849a31df08c1bbf7f95\nmsgid \"Comments\"\nmsgstr \"설명\"\n\n#: ../../app1.rst:334 e1c0047fd9194edba834839b48102df9\nmsgid \"no images\"\nmsgstr \"이미지 없음\"\n\n#: ../../app1.rst:336 4b7a66b4248d47dc9f0ac0139eea5321\nmsgid \"TEXT\"\nmsgstr \"TEXT\"\n\n#: ../../app1.rst:336 ../../app1.rst:337 ../../app1.rst:340\n#: 25343a3526d44c7e9147a4b83482b458 5c3d7bcdd77648fea697a40e67bab8fc\n#: 6669d2767e5c49eeb1606eef0ef897e0 e55d755ae5ee4a62bd2e705a1b4974a4\n#: f0dcc7f23fa74accb9461d0e6ad00b34\nmsgid \"1.00\"\nmsgstr \"1.00\"\n\n#: ../../app1.rst:336 74b3bb1df5a74fe7965c9a036c43b0b6\nmsgid \"no images, **plain** text, line breaks\"\nmsgstr \"이미지 없음, **일반** 텍스트, 줄바꿈\"\n\n#: ../../app1.rst:337 db8f0e8c5f874c7bbbc6d938ebde2e18\nmsgid \"image bboxes (only), **block** level text with bboxes, line breaks\"\nmsgstr \"이미지 bbox(만), **블록** 수준 텍스트와 bbox, 줄바꿈\"\n\n#: ../../app1.rst:338 075075d180484d1e9a104abafa5c7123\n#: 18d11064908b48228b89fe3c8c0d242c\nmsgid \"1.02\"\nmsgstr \"1.02\"\n\n#: ../../app1.rst:338 b3d7c61c84a84af98ad596efb0959503\nmsgid \"no images, **word** level text with bboxes\"\nmsgstr \"이미지 없음, **단어** 수준 텍스트와 bbox\"\n\n#: ../../app1.rst:339 0c5c60a2ef4342038c3a2c60d07bd072\n#: ab025008beb540c3af6517c25c3731c8\nmsgid \"2.72\"\nmsgstr \"2.72\"\n\n#: ../../app1.rst:339 233b3e8abb32457bb01d804468cd86e2\nmsgid \"no images, **char** level text, layout and font details\"\nmsgstr \"이미지 없음, **문자** 수준 텍스트, 레이아웃 및 글꼴 세부 정보\"\n\n#: ../../app1.rst:340 495e91c0090643cd9239576c13e8f216\nmsgid \"3.32\"\nmsgstr \"3.32\"\n\n#: ../../app1.rst:340 b4c7e848e2814720ab1d9fbeb303c9f9\nmsgid \"**base64** images, **span** level text, no layout info\"\nmsgstr \"**base64** 이미지, **스팬** 수준 텍스트, 레이아웃 정보 없음\"\n\n#: ../../app1.rst:341 e1c73c9152e644efbed95fc738d1ae9d\nmsgid \"3.54\"\nmsgstr \"3.54\"\n\n#: ../../app1.rst:341 61d71ce102d24fbbb30ff945dc28f207\nmsgid \"**base64** images, **span** level text, layout and font details\"\nmsgstr \"**base64** 이미지, **스팬** 수준 텍스트, 레이아웃 및 글꼴 세부 정보\"\n\n#: ../../app1.rst:341 892ba5e6677e4561bfe9a5dc406e3852\nmsgid \"1.01\"\nmsgstr \"1.01\"\n\n#: ../../app1.rst:342 5b44d6bc99504bb4bc7e4d457aa5509f\nmsgid \"DICT\"\nmsgstr \"DICT\"\n\n#: ../../app1.rst:342 bb46e12ef905445f84a825d968043de6\nmsgid \"3.93\"\nmsgstr \"3.93\"\n\n#: ../../app1.rst:342 426e28067c23452bb6edeb57689a7855\nmsgid \"**binary** images, **span** level text, layout and font details\"\nmsgstr \"**바이너리** 이미지, **스팬** 수준 텍스트, 레이아웃 및 글꼴 세부 정보\"\n\n#: ../../app1.rst:342 16da06be2e1a492c94b26bb12c8c4022\nmsgid \"1.04\"\nmsgstr \"1.04\"\n\n#: ../../app1.rst:343 02cf93b26e5f449e95976162924b980c\nmsgid \"RAWDICT\"\nmsgstr \"RAWDICT\"\n\n#: ../../app1.rst:343 0eddcb199db847968d5f20c520727971\nmsgid \"4.50\"\nmsgstr \"4.50\"\n\n#: ../../app1.rst:343 7ae92e67a9f34967b697139a85969bff\nmsgid \"**binary** images, **char** level text, layout and font details\"\nmsgstr \"**바이너리** 이미지, **문자** 수준 텍스트, 레이아웃 및 글꼴 세부 정보\"\n\n#: ../../app1.rst:343 b31064906dbc405e9e886eab7a219b5f\nmsgid \"1.68\"\nmsgstr \"1.68\"\n\n#: ../../app1.rst:346 bbe02a1a6ecb4053aea6eac932438250\n#, python-format\nmsgid \"\"\n\"As mentioned: when excluding image extraction (last column), the relative\"\n\" speeds are changing drastically: except RAWDICT and XML, the other \"\n\"methods are almost equally fast, and RAWDICT requires 40% less execution \"\n\"time than the **now slowest XML**.\"\nmsgstr \"언급한 대로: 이미지 추출을 제외하면(마지막 열) 상대 속도가 크게 변합니다: RAWDICT와 XML을 제외하고 다른 메서드는 거의 동일하게 빠르며, RAWDICT는 **이제 가장 느린 XML** 보다 40% 적은 실행 시간이 필요합니다.\"\n\n#: ../../app1.rst:348 c9763e96efa94f389c83973e6830f9cc\nmsgid \"Look at chapter **Appendix 1** for more performance information.\"\nmsgstr \"더 많은 성능 정보는 **부록 1** 장을 참조하세요.\"\n\n#: ../../footer.rst:46 ee2a605b55f548d69f51e5e9c010b812\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/app2.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 91d1a3926cf04b7f86982004576a7dac\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 079f5f8f8d67400f8dff2c457815bc6e\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 f3ec318cd565440481d5fc24ebd6dd9d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../app2.rst:7 df962b6f73f94a62944d489a625e02f6\nmsgid \"Appendix 2: Considerations on Embedded Files\"\nmsgstr \"부록 2: 임베디드 파일에 대한 고려사항\"\n\n#: ../../app2.rst:8 fea3691f2b5d49e3be0cdd79daecdb75\nmsgid \"\"\n\"This chapter provides some background on embedded files support in \"\n\"PyMuPDF.\"\nmsgstr \"이 장은 |PyMuPDF| 에서 임베디드 파일 지원에 대한 배경 정보를 제공합니다.\"\n\n#: ../../app2.rst:11 e6abfba16abf44f5b53d5c259c06168e\nmsgid \"General\"\nmsgstr \"일반\"\n\n#: ../../app2.rst:12 2e9ff1e795ec4a80886665b6d98570d1\nmsgid \"\"\n\"Starting with version 1.4, PDF supports embedding arbitrary files as part\"\n\" (\\\"Embedded File Streams\\\") of a PDF document file (see chapter \\\"7.11.4\"\n\" Embedded File Streams\\\", pp. 103 of the :ref:`AdobeManual`).\"\nmsgstr \"버전 1.4부터 PDF는 PDF 문서 파일의 일부로 임의의 파일을 임베딩하는 것을 지원합니다(\\\"Embedded File Streams\\\" 참조, :ref:`AdobeManual` 의 103페이지 \\\"7.11.4 Embedded File Streams\\\" 장 참조).\"\n\n#: ../../app2.rst:15 3740cf26355f419488a18d5c5bf691e2\nmsgid \"\"\n\"In many aspects, this is comparable to concepts also found in ZIP files \"\n\"or the OLE technique in MS Windows. PDF embedded files do, however, *not*\"\n\" support directory structures as does the ZIP format. An embedded file \"\n\"can in turn contain embedded files itself.\"\nmsgstr \"많은 측면에서 이것은 ZIP 파일이나 MS Windows의 OLE 기술에서도 볼 수 있는 개념과 유사합니다. 그러나 PDF 임베디드 파일은 ZIP 형식과 달리 디렉터리 구조를 *지원하지 않습니다*. 임베디드 파일은 차례로 자체적으로 임베디드 파일을 포함할 수 있습니다.\"\n\n#: ../../app2.rst:17 cf0b0ce27ac343a7989b881239cb446f\nmsgid \"\"\n\"Advantages of this concept are that embedded files are under the PDF \"\n\"umbrella, benefitting from its permissions / password protection and \"\n\"integrity aspects: all data, which a PDF may reference or even may be \"\n\"dependent on, can be bundled into it and so form a single, consistent \"\n\"unit of information.\"\nmsgstr \"이 개념의 장점은 임베디드 파일이 PDF의 보호 아래에 있어 권한/비밀번호 보호 및 무결성 측면의 이점을 받는다는 것입니다: PDF가 참조하거나 의존할 수 있는 모든 데이터를 하나로 묶어 단일하고 일관된 정보 단위를 형성할 수 있습니다.\"\n\n#: ../../app2.rst:19 7979fde2425b48d89516fd519a799cb9\nmsgid \"\"\n\"In addition to embedded files, PDF 1.7 adds *collections* to its support \"\n\"range. This is an advanced way of storing and presenting meta information\"\n\" (i.e. arbitrary and extensible properties) of embedded files.\"\nmsgstr \"임베디드 파일 외에도 PDF 1.7은 지원 범위에 *collections* 를 추가합니다. 이것은 임베디드 파일의 메타 정보(즉, 임의의 확장 가능한 속성)를 저장하고 표시하는 고급 방법입니다.\"\n\n#: ../../app2.rst:22 96f7716c2f354c4e9734c53ec68da72d\nmsgid \"MuPDF Support\"\nmsgstr \"|MuPDF| 지원\"\n\n#: ../../app2.rst:23 c829491b2aaa4844aa1c48047af82974\nmsgid \"\"\n\"After adding initial support for collections (portfolios) and \"\n\"*/EmbeddedFiles* in MuPDF version 1.11, this support was dropped again in\"\n\" version 1.15.\"\nmsgstr \"|MuPDF| 버전 1.11에서 컬렉션(포트폴리오) 및 */EmbeddedFiles* 에 대한 초기 지원을 추가한 후, 이 지원은 버전 1.15에서 다시 제거되었습니다.\"\n\n#: ../../app2.rst:25 f683f1fd707f420b90cc13279f35ebc0\nmsgid \"\"\n\"As a consequence, the cli utility *mutool* no longer offers access to \"\n\"embedded files.\"\nmsgstr \"결과적으로 CLI 유틸리티 *mutool* 은 더 이상 임베디드 파일에 대한 액세스를 제공하지 않습니다.\"\n\n#: ../../app2.rst:27 de207c079b314eaea490841b284ea876\nmsgid \"\"\n\"PyMuPDF -- having implemented an */EmbeddedFiles* API in response in its \"\n\"version 1.11.0 -- was therefore forced to change gears starting with its \"\n\"version 1.16.0 (we never published a MuPDF v1.15.x compatible PyMuPDF).\"\nmsgstr \"|PyMuPDF| 는 버전 1.11.0에서 */EmbeddedFiles* API를 구현했기 때문에 버전 1.16.0부터 방향을 전환해야 했습니다(|MuPDF| v1.15.x와 호환되는 |PyMuPDF| 는 발행하지 않았습니다).\"\n\n#: ../../app2.rst:29 73bd7a0c6aef40dea2819f6f52a55ff6\nmsgid \"\"\n\"We are now maintaining our own code basis supporting embedded files. This\"\n\" code makes use of basic MuPDF dictionary and array functions only.\"\nmsgstr \"이제 임베디드 파일을 지원하는 자체 코드 기반을 유지 관리하고 있습니다. 이 코드는 기본 |MuPDF| 딕셔너리 및 배열 함수만 사용합니다.\"\n\n#: ../../app2.rst:32 de313e6dfe7e40e781939fab264fd4e5\nmsgid \"PyMuPDF Support\"\nmsgstr \"|PyMuPDF| 지원\"\n\n#: ../../app2.rst:33 420a4c9141134c469dfb6d107c9bcd58\nmsgid \"\"\n\"We continue to support the full old API with respect to embedded files --\"\n\" with only minor, cosmetic changes.\"\nmsgstr \"임베디드 파일과 관련하여 전체 이전 API를 계속 지원합니다 -- 단지 사소한 외관상의 변경만 있습니다.\"\n\n#: ../../app2.rst:35 66a7d51f81c6402caf1d00e67bd1bfd2\nmsgid \"\"\n\"There even also is a new function, which delivers a list of all names \"\n\"under which embedded data are registered in a PDF, \"\n\":meth:`Document.embfile_names`.\"\nmsgstr \"PDF에 임베디드 데이터가 등록된 모든 이름의 목록을 제공하는 새로운 함수도 있습니다: :meth:`Document.embfile_names`.\"\n\n#: ../../footer.rst:46 c600b715098140b3b7f197c61eb560ac\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/app3.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-03 09:30+0900\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../header.rst:-1 e9b57a556ade45ada6ce4d2157d0a4fb\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 63a9ec4fe01846b68264a6fceec4b355\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 116badf6cf724a168451fdd57616c081\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../app3.rst:7 28fa836c45cd4132be1daf6ef45c58b2\nmsgid \"Appendix 3: Assorted Technical Information\"\nmsgstr \"부록 3: 기타 기술 정보\"\n\n#: ../../app3.rst:8 987ce4249079447cbdd011e22851e60d\nmsgid \"\"\n\"This section deals with various technical topics, that are not \"\n\"necessarily related to each other.\"\nmsgstr \"이 섹션은 서로 관련이 없을 수 있는 다양한 기술 주제를 다룹니다.\"\n\n#: ../../app3.rst:15 df054d36d114464baf858b0b6d6fd5e9\nmsgid \"Image Transformation Matrix\"\nmsgstr \"이미지 변환 행렬\"\n\n#: ../../app3.rst:16 d08d81fa70c1456e8da48b9f7c45564a\nmsgid \"\"\n\"Starting with version 1.18.11, the image transformation matrix is \"\n\"returned by some methods for text and image extraction: \"\n\":meth:`Page.get_text` and :meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\"버전 1.18.11부터 이미지 변환 행렬은 텍스트 및 이미지 추출을 위한 일부 메서드에서 반환됩니다: \"\n\":meth:`Page.get_text` 및 :meth:`Page.get_image_bbox`.\"\n\n#: ../../app3.rst:18 9cc212e2752f49e78b3b1ae4b68f754f\nmsgid \"\"\n\"The transformation matrix contains information about how an image was \"\n\"transformed to fit into the rectangle (its \\\"boundary box\\\" = \\\"bbox\\\") \"\n\"on some document page. By inspecting the image's bbox on the page and \"\n\"this matrix, one can determine for example, whether and how the image is \"\n\"displayed scaled or rotated on a page.\"\nmsgstr \"\"\n\"변환 행렬은 이미지가 문서 페이지의 사각형(그 \\\"경계 상자\\\" = \\\"bbox\\\")에 맞도록 변환된 방법에 대한 정보를 \"\n\"포함합니다. 페이지의 이미지 bbox와 이 행렬을 검사하면 예를 들어 이미지가 페이지에서 확대/축소되거나 회전되어 표시되는지 여부와\"\n\" 방법을 결정할 수 있습니다.\"\n\n#: ../../app3.rst:20 5ff3fcc91d01440280b60dba6a823b73\nmsgid \"\"\n\"The relationship between image dimension and its bbox on a page is the \"\n\"following:\"\nmsgstr \"이미지 크기와 페이지의 bbox 간의 관계는 다음과 같습니다:\"\n\n#: ../../app3.rst:24 38387aac6c4648878635157b4d9ac7ad\nmsgid \"Using the original image's width and height,\"\nmsgstr \"원본 이미지의 너비와 높이를 사용하여,\"\n\n#: ../../app3.rst:23 0658960617334ff1bb152cc26322575b\nmsgid \"define the image rectangle `imgrect = pymupdf.Rect(0, 0, width, height)`\"\nmsgstr \"이미지 사각형을 정의합니다 `imgrect = pymupdf.Rect(0, 0, width, height)`\"\n\n#: ../../app3.rst:24 e018e20b0f5b47c98051fb8fd2bf4309\nmsgid \"\"\n\"define the \\\"shrink matrix\\\" `shrink = pymupdf.Matrix(1/width, 0, 0, \"\n\"1/height, 0, 0)`.\"\nmsgstr \"\\\"축소 행렬\\\"을 정의합니다 `shrink = pymupdf.Matrix(1/width, 0, 0, 1/height, 0, 0)`.\"\n\n#: ../../app3.rst:26 1e5bedf568fb4f28b0c289eba114264e\nmsgid \"\"\n\"Transforming the image rectangle with its shrink matrix, will result in \"\n\"the unit rectangle: `imgrect * shrink = pymupdf.Rect(0, 0, 1, 1)`.\"\nmsgstr \"\"\n\"이미지 사각형을 축소 행렬로 변환하면 단위 사각형이 됩니다: `imgrect * shrink = pymupdf.Rect(0, 0, \"\n\"1, 1)`.\"\n\n#: ../../app3.rst:28 87764bec92d3484da3cb5c4856fa0efe\nmsgid \"\"\n\"Using the image **transformation matrix** \\\"transform\\\", the following \"\n\"steps will compute the bbox::\"\nmsgstr \"이미지 **변환 행렬** \\\"transform\\\"을 사용하면 다음 단계로 bbox를 계산합니다::\"\n\n#: ../../app3.rst:34 eb03509b0e7b443b8123601dca26cd51\nmsgid \"\"\n\"Inspecting the matrix product `shrink * transform` will reveal all \"\n\"information about what happened to the image rectangle to make it fit \"\n\"into the bbox on the page: rotation, scaling of its sides and translation\"\n\" of its origin. Let us look at an example:\"\nmsgstr \"\"\n\"행렬 곱 `shrink * transform` 을 검사하면 이미지 사각형이 페이지의 bbox에 맞도록 변환된 방법에 대한 모든 \"\n\"정보(회전, 변의 크기 조정 및 원점 이동)를 알 수 있습니다. 예제를 살펴보겠습니다:\"\n\n#: ../../app3.rst:71 52e5d34ae16540878399966cea671288\nmsgid \"PDF Base 14 Fonts\"\nmsgstr \"PDF Base 14 글꼴\"\n\n#: ../../app3.rst:72 b1b6cb8420b845c3924bbaccd6738258\nmsgid \"\"\n\"The following 14 builtin font names **must be supported by every PDF \"\n\"viewer** application. They are available as a dictionary, which maps \"\n\"their full names amd their abbreviations in lower case to the full font \"\n\"basename. Wherever a **fontname** must be provided in PyMuPDF, any **key \"\n\"or value** from the dictionary may be used::\"\nmsgstr \"\"\n\"다음 14개의 내장 글꼴 이름은 **모든 PDF 뷰어** 애플리케이션에서 지원되어야 합니다. 이들은 딕셔너리로 제공되며, 전체 \"\n\"이름과 소문자 약어를 전체 글꼴 기본 이름에 매핑합니다. |PyMuPDF| 에서 **fontname** 을 제공해야 하는 곳에서는 \"\n\"딕셔너리의 **키 또는 값** 을 사용할 수 있습니다::\"\n\n#: ../../app3.rst:105 11906948a25d421f9fc5dde554e86b3a\nmsgid \"\"\n\"In contrast to their obligation, not all PDF viewers support these fonts \"\n\"correctly and completely -- this is especially true for Symbol and \"\n\"ZapfDingbats. Also, the glyph (visual) images will be specific to every \"\n\"reader.\"\nmsgstr \"\"\n\"의무와 달리 모든 PDF 뷰어가 이러한 글꼴을 올바르고 완전하게 지원하는 것은 아닙니다 -- 이것은 특히 Symbol과 \"\n\"ZapfDingbats에 해당합니다. 또한 글리프(시각적) 이미지는 각 리더에 따라 다를 수 있습니다.\"\n\n#: ../../app3.rst:107 295160fa982d4747a5187ac69e7c5091\nmsgid \"\"\n\"To see how these fonts can be used -- including the **CJK built-in** \"\n\"fonts -- look at the table in :meth:`Page.insert_font`.\"\nmsgstr \"\"\n\"이러한 글꼴을 사용하는 방법을 보려면 -- **CJK 내장** 글꼴을 포함하여 -- :meth:`Page.insert_font` 의\"\n\" 표를 참조하세요.\"\n\n#: ../../app3.rst:114 08bfb2d1eb8248a59eec7a4cf8c82af6\nmsgid \"Adobe PDF References\"\nmsgstr \"Adobe PDF 참조\"\n\n#: ../../app3.rst:116 f91f72e7328b424584ef9343eb9274ff\nmsgid \"\"\n\"This PDF Reference manual published by Adobe is frequently quoted \"\n\"throughout this documentation. It can be viewed and downloaded from \"\n\"`opensource.adobe.com <https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_.\"\nmsgstr \"\"\n\"Adobe에서 발행한 이 PDF Reference 매뉴얼은 이 문서 전반에 걸쳐 자주 인용됩니다. \"\n\"`opensource.adobe.com <https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_ 에서 볼 수 있고 다운로드할 수 \"\n\"있습니다.\"\n\n#: ../../app3.rst:125 aa1776d20bbe4cfd8afaa0a73e420204\nmsgid \"Using Python Sequences as Arguments in PyMuPDF\"\nmsgstr \"|PyMuPDF| 에서 Python 시퀀스를 인수로 사용하기\"\n\n#: ../../app3.rst:126 c5f3a5e6759b4dfbb449d4d691a10798\nmsgid \"\"\n\"When PyMuPDF objects and methods require a Python **list** of numerical \"\n\"values, other Python **sequence types** are also allowed. Python classes \"\n\"are said to implement the **sequence protocol**, if they have a \"\n\"`__getitem__()` method.\"\nmsgstr \"\"\n\"|PyMuPDF| 객체와 메서드가 숫자 값의 Python **list** 를 요구할 때, 다른 Python **시퀀스 타입** 도 \"\n\"허용됩니다. Python 클래스는 `__getitem__()` 메서드를 가지고 있으면 **시퀀스 프로토콜** 을 구현한다고 합니다.\"\n\n#: ../../app3.rst:128 a2f4065016074783a3e692a5b44a9e6a\nmsgid \"\"\n\"This basically means, you can interchangeably use Python *list* or \"\n\"*tuple* or even *array.array*, *numpy.array* and *bytearray* types in \"\n\"these cases.\"\nmsgstr \"\"\n\"기본적으로 이것은 이러한 경우에 Python *list* 또는 *tuple* 또는 *array.array*, \"\n\"*numpy.array* 및 *bytearray* 타입을 상호 교환하여 사용할 수 있음을 의미합니다.\"\n\n#: ../../app3.rst:130 5eb2ec1d221246a191dd8246f9602573\nmsgid \"For example, specifying a sequence `\\\"s\\\"` in any of the following ways\"\nmsgstr \"예를 들어, 다음 방법 중 하나로 시퀀스 `\\\"s\\\"` 를 지정하면\"\n\n#: ../../app3.rst:132 9eb6b1a57a034a3d939841b3ccd8eb41\nmsgid \"`s = [1, 2]` -- a list\"\nmsgstr \"`s = [1, 2]` -- 리스트\"\n\n#: ../../app3.rst:133 8c499f04e376417882319277967497e2\nmsgid \"`s = (1, 2)` -- a tuple\"\nmsgstr \"`s = (1, 2)` -- 튜플\"\n\n#: ../../app3.rst:134 24338a6cbce547bfa3d4f9cb90ef10ea\nmsgid \"`s = array.array(\\\"i\\\", (1, 2))` -- an array.array\"\nmsgstr \"`s = array.array(\\\"i\\\", (1, 2))` -- array.array\"\n\n#: ../../app3.rst:135 36400eb511c94e05909f03f043285723\nmsgid \"`s = numpy.array((1, 2))` -- a numpy array\"\nmsgstr \"`s = numpy.array((1, 2))` -- numpy 배열\"\n\n#: ../../app3.rst:136 caec64c89cc041fdbd1aa4c558b74a1b\nmsgid \"`s = bytearray((1, 2))` -- a bytearray\"\nmsgstr \"`s = bytearray((1, 2))` -- bytearray\"\n\n#: ../../app3.rst:138 e81f583d516a4bdfa3f77751e81a03d9\nmsgid \"will make it usable in the following example expressions:\"\nmsgstr \"다음 예제 표현식에서 사용할 수 있습니다:\"\n\n#: ../../app3.rst:140 048fdce412374742b5e6d5861df9427c\nmsgid \"`pymupdf.Point(s)`\"\nmsgstr \"`pymupdf.Point(s)`\"\n\n#: ../../app3.rst:141 2a1345de7505441da80ff27558b70357\nmsgid \"`pymupdf.Point(x, y) + s`\"\nmsgstr \"`pymupdf.Point(x, y) + s`\"\n\n#: ../../app3.rst:142 65b15752bc024e088940595dae3215da\nmsgid \"`doc.select(s)`\"\nmsgstr \"`doc.select(s)`\"\n\n#: ../../app3.rst:144 d524e2c9577144908a75e0987c81899f\nmsgid \"\"\n\"Similarly with all geometry objects :ref:`Rect`, :ref:`IRect`, \"\n\":ref:`Matrix` and :ref:`Point`.\"\nmsgstr \"\"\n\"모든 기하 객체 :ref:`Rect`, :ref:`IRect`, :ref:`Matrix` 및 :ref:`Point` 에도 \"\n\"마찬가지입니다.\"\n\n#: ../../app3.rst:146 46b031e6dd8e40808429c33e2729e35d\nmsgid \"\"\n\"Because all PyMuPDF geometry classes themselves are special cases of \"\n\"sequences, they (with the exception of :ref:`Quad` -- see below) can be \"\n\"freely used where numerical sequences can be used, e.g. as arguments for \"\n\"functions like *list()*, *tuple()*, *array.array()* or *numpy.array()*. \"\n\"Look at the following snippet to see this work.\"\nmsgstr \"\"\n\"모든 |PyMuPDF| 기하 클래스 자체가 시퀀스의 특수한 경우이므로, 이들은(:ref:`Quad` 제외 -- 아래 참조) 숫자 \"\n\"시퀀스를 사용할 수 있는 곳에서 자유롭게 사용할 수 있습니다. 예를 들어 *list()*, *tuple()*, \"\n\"*array.array()* 또는 *numpy.array()* 와 같은 함수의 인수로 사용할 수 있습니다. 이것이 작동하는 것을 \"\n\"보려면 다음 코드 조각을 참조하세요.\"\n\n#: ../../app3.rst:163 8c531fc2e99a4086bce80bae4dbeeac7\nmsgid \"\"\n\":ref:`Quad` is a Python sequence object as well and has a length of 4. \"\n\"Its items however are :data:`point_like` -- not numbers. Therefore, the \"\n\"above remarks do not apply.\"\nmsgstr \"\"\n\":ref:`Quad` 도 Python 시퀀스 객체이며 길이가 4입니다. 그러나 항목은 :data:`point_like` 입니다 --\"\n\" 숫자가 아닙니다. 따라서 위의 설명은 적용되지 않습니다.\"\n\n#: ../../app3.rst:170 c359d43e960248c39a6485317dc894d9\nmsgid \"Ensuring Consistency of Important Objects in PyMuPDF\"\nmsgstr \"|PyMuPDF| 에서 중요한 객체의 일관성 보장\"\n\n#: ../../app3.rst:171 57dc6323642f4ed1a681c418dc32446e\nmsgid \"\"\n\"PyMuPDF is a Python binding for the C library MuPDF. While a lot of \"\n\"effort has been invested by MuPDF's creators to approximate some sort of \"\n\"an object-oriented behavior, they certainly could not overcome basic \"\n\"shortcomings of the C language in that respect.\"\nmsgstr \"\"\n\"|PyMuPDF| 는 C 라이브러리 |MuPDF| 에 대한 Python 바인딩입니다. |MuPDF| 의 제작자들이 객체 지향적 \"\n\"동작을 근사하기 위해 많은 노력을 기울였지만, C 언어의 기본적인 한계를 극복할 수는 없었습니다.\"\n\n#: ../../app3.rst:173 4c061032544f42d3b1cbac6ca2994790\nmsgid \"\"\n\"Python on the other hand implements the OO-model in a very clean way. The\"\n\" interface code between PyMuPDF and MuPDF consists of two basic files: \"\n\"*pymupdf.py* and *fitz_wrap.c*. They are created by the excellent SWIG \"\n\"tool for each new version.\"\nmsgstr \"\"\n\"반면 Python은 OO 모델을 매우 깔끔하게 구현합니다. |PyMuPDF| 와 |MuPDF| 사이의 인터페이스 코드는 두 개의 \"\n\"기본 파일로 구성됩니다: *pymupdf.py* 와 *fitz_wrap.c*. 이들은 각 새 버전에 대해 우수한 SWIG 도구로 \"\n\"생성됩니다.\"\n\n#: ../../app3.rst:175 4fb5955ef3f34ff5b12fe9147956933b\nmsgid \"\"\n\"When you use one of PyMuPDF's objects or methods, this will result in \"\n\"execution of some code in *pymupdf.py*, which in turn will call some C \"\n\"code compiled with *fitz_wrap.c*.\"\nmsgstr \"\"\n\"|PyMuPDF| 의 객체나 메서드 중 하나를 사용하면 *pymupdf.py* 의 일부 코드가 실행되고, 이것은 차례로 \"\n\"*fitz_wrap.c* 로 컴파일된 일부 C 코드를 호출합니다.\"\n\n#: ../../app3.rst:177 3846f21a4bb648bd8c4416539fe28a36\nmsgid \"\"\n\"Because SWIG goes a long way to keep the Python and the C level in sync, \"\n\"everything works fine, if a certain set of rules is being strictly \"\n\"followed. For example: **never access** a :ref:`Page` object, after you \"\n\"have closed (or deleted or set to ``None``) the owning :ref:`Document`. \"\n\"Or, less obvious: **never access** a page or any of its children (links \"\n\"or annotations) after you have executed one of the document methods \"\n\"*select()*, *delete_page()*, *insert_page()* ... and more.\"\nmsgstr \"\"\n\"SWIG가 Python과 C 레벨을 동기화하기 위해 많은 노력을 기울이기 때문에, 특정 규칙 집합을 엄격히 따르면 모든 것이 잘 \"\n\"작동합니다. 예를 들어: 소유 :ref:`Document` 를 닫았거나(또는 삭제하거나 ``None`` 으로 설정한 후) \"\n\":ref:`Page` 객체에 **절대 액세스하지 마세요**. 또는 덜 명확한 경우: 문서 메서드 *select()*, \"\n\"*delete_page()*, *insert_page()* 등을 실행한 후 페이지나 그 자식(링크 또는 주석)에 **절대 액세스하지\"\n\" 마세요**.\"\n\n#: ../../app3.rst:179 cd2f0e9f6925457b95a8972e5220b65c\nmsgid \"\"\n\"But just no longer accessing invalidated objects is actually not enough: \"\n\"They should rather be actively deleted entirely, to also free C-level \"\n\"resources (meaning allocated memory).\"\nmsgstr \"\"\n\"그러나 무효화된 객체에 더 이상 액세스하지 않는 것만으로는 충분하지 않습니다: C 레벨 리소스(할당된 메모리)도 해제하기 위해 \"\n\"완전히 삭제해야 합니다.\"\n\n#: ../../app3.rst:181 7bb8910cf6284c37a4acf09d60be5730\nmsgid \"\"\n\"The reason for these rules lies in the fact that there is a hierarchical \"\n\"2-level one-to-many relationship between a document and its pages and \"\n\"also between a page and its links / annotations. To maintain a consistent\"\n\" situation, any of the above actions must lead to a complete reset -- in \"\n\"**Python and, synchronously, in C**.\"\nmsgstr \"\"\n\"이러한 규칙의 이유는 문서와 그 페이지 사이, 그리고 페이지와 그 링크/주석 사이에 계층적 2단계 일대다 관계가 있다는 사실에 \"\n\"있습니다. 일관된 상황을 유지하기 위해 위의 작업 중 하나라도 완전한 재설정으로 이어져야 합니다 -- **Python과 동기적으로 \"\n\"C에서**.\"\n\n#: ../../app3.rst:183 f28fc2db36084f948eed30968297dab5\nmsgid \"SWIG cannot know about this and consequently does not do it.\"\nmsgstr \"SWIG는 이것을 알 수 없으므로 결과적으로 이를 수행하지 않습니다.\"\n\n#: ../../app3.rst:185 9b81f1fa67e34514b59f9bfc0a61a978\nmsgid \"\"\n\"The required logic has therefore been built into PyMuPDF itself in the \"\n\"following way.\"\nmsgstr \"따라서 필요한 로직이 다음과 같은 방식으로 |PyMuPDF| 자체에 내장되었습니다.\"\n\n#: ../../app3.rst:187 2610c09be6134825b39d838bd001108c\nmsgid \"\"\n\"If a page \\\"loses\\\" its owning document or is being deleted itself, all \"\n\"of its currently existing annotations and links will be made unusable in \"\n\"Python, and their C-level counterparts will be deleted and deallocated.\"\nmsgstr \"\"\n\"페이지가 소유 문서를 \\\"잃거나\\\" 자체적으로 삭제되면, 현재 존재하는 모든 주석과 링크가 Python에서 사용할 수 없게 되고, \"\n\"C 레벨의 대응 항목이 삭제되고 할당 해제됩니다.\"\n\n#: ../../app3.rst:189 d188cde23fd047f7a60e9267515903d6\nmsgid \"\"\n\"If a document is closed (or deleted or set to ``None``) or if its \"\n\"structure has changed, then similarly all currently existing pages and \"\n\"their children will be made unusable, and corresponding C-level deletions\"\n\" will take place. \\\"Structure changes\\\" include methods like *select()*, \"\n\"*delePage()*, *insert_page()*, *insert_pdf()* and so on: all of these \"\n\"will result in a cascade of object deletions.\"\nmsgstr \"\"\n\"문서가 닫히거나(또는 삭제되거나 ``None`` 으로 설정되거나) 구조가 변경되면, 마찬가지로 현재 존재하는 모든 페이지와 그 \"\n\"자식이 사용할 수 없게 되고, 해당 C 레벨 삭제가 발생합니다. \\\"구조 변경\\\"에는 *select()*, \"\n\"*delete_page()*, *insert_page()*, *insert_pdf()* 등의 메서드가 포함됩니다: 이들 모두 객체 \"\n\"삭제의 연쇄를 초래합니다.\"\n\n#: ../../app3.rst:191 d57b1ed5501b417391bd09cc0fdcfd39\nmsgid \"\"\n\"The programmer will normally not realize any of this. If he, however, \"\n\"tries to access invalidated objects, exceptions will be raised.\"\nmsgstr \"프로그래머는 일반적으로 이것을 인식하지 못합니다. 그러나 무효화된 객체에 액세스하려고 하면 예외가 발생합니다.\"\n\n#: ../../app3.rst:193 e42075fe1f1f4884a8525e23d50ec80a\nmsgid \"\"\n\"Invalidated objects cannot be directly deleted as with Python statements \"\n\"like *del page* or *page = None*, etc. Instead, their *__del__* method \"\n\"must be invoked.\"\nmsgstr \"\"\n\"무효화된 객체는 *del page* 또는 *page = None* 등의 Python 문으로 직접 삭제할 수 없습니다. 대신 \"\n\"*__del__* 메서드를 호출해야 합니다.\"\n\n#: ../../app3.rst:195 65129ee8ed6347389a03f5c4a0e27118\nmsgid \"\"\n\"All pages, links and annotations have the property *parent*, which points\"\n\" to the owning object. This is the property that can be checked on the \"\n\"application level: if *obj.parent == None* then the object's parent is \"\n\"gone, and any reference to its properties or methods will raise an \"\n\"exception informing about this \\\"orphaned\\\" state.\"\nmsgstr \"\"\n\"모든 페이지, 링크 및 주석은 소유 객체를 가리키는 *parent* 속성을 가집니다. 이것은 애플리케이션 레벨에서 확인할 수 있는 \"\n\"속성입니다: *obj.parent == None* 이면 객체의 부모가 사라진 것이며, 속성이나 메서드에 대한 참조는 이 \\\"고아\\\"\"\n\" 상태에 대해 알리는 예외를 발생시킵니다.\"\n\n#: ../../app3.rst:197 8dd4acfe98f34511830f7c57c6d629ce\nmsgid \"A sample session:\"\nmsgstr \"샘플 세션:\"\n\n#: ../../app3.rst:214 9e147448615c4415832f3e2acb045cfd\nmsgid \"This shows the cascading effect:\"\nmsgstr \"이것은 연쇄 효과를 보여줍니다:\"\n\n#: ../../app3.rst:231 442c30826bf4423aacbb2a4864ce9a88\nmsgid \"\"\n\"Objects outside the above relationship are not included in this \"\n\"mechanism. If you e.g. created a table of contents by *toc = \"\n\"doc.get_toc()*, and later close or change the document, then this cannot \"\n\"and does not change variable *toc* in any way. It is your responsibility \"\n\"to refresh such variables as required.\"\nmsgstr \"\"\n\"위의 관계 외부의 객체는 이 메커니즘에 포함되지 않습니다. 예를 들어 *toc = doc.get_toc()* 로 목차를 만든 후 \"\n\"문서를 닫거나 변경하면, 이것은 변수 *toc* 를 어떤 방식으로도 변경할 수 없고 변경하지 않습니다. 필요에 따라 이러한 변수를 \"\n\"새로 고치는 것은 사용자의 책임입니다.\"\n\n#: ../../app3.rst:238 64b3f76253e64bdcba362aad09efb8f9\nmsgid \"Design of Method :meth:`Page.show_pdf_page`\"\nmsgstr \"메서드 :meth:`Page.show_pdf_page` 의 설계\"\n\n#: ../../app3.rst:241 128d4a5b179f4f858c59282d02e2992d\nmsgid \"Purpose and Capabilities\"\nmsgstr \"목적 및 기능\"\n\n#: ../../app3.rst:243 36e16573a42045a2bf1afeda5ba8b66e\nmsgid \"\"\n\"The method displays an image of a (\\\"source\\\") page of another PDF \"\n\"document within a specified rectangle of the current (\\\"containing\\\", \"\n\"\\\"target\\\") page.\"\nmsgstr \"\"\n\"이 메서드는 다른 PDF 문서의 (\\\"소스\\\") 페이지 이미지를 현재 (\\\"포함\\\", \\\"대상\\\") 페이지의 지정된 사각형 내에 \"\n\"표시합니다.\"\n\n#: ../../app3.rst:245 11b56c7a4353448faba91c8944469b13\nmsgid \"\"\n\"**In contrast** to :meth:`Page.insert_image`, this display is vector-\"\n\"based and hence remains accurate across zooming levels.\"\nmsgstr \"\"\n\":meth:`Page.insert_image` 와 **대조적으로**, 이 표시는 벡터 기반이므로 확대/축소 수준에서도 정확하게 \"\n\"유지됩니다.\"\n\n#: ../../app3.rst:246 b9f69720d39443449a9d85059af697e2\nmsgid \"\"\n\"**Just like** :meth:`Page.insert_image`, the size of the display is \"\n\"adjusted to the given rectangle.\"\nmsgstr \":meth:`Page.insert_image` 와 **마찬가지로**, 표시 크기는 주어진 사각형에 맞게 조정됩니다.\"\n\n#: ../../app3.rst:248 c503b182fc14483589a8e70354d7013d\nmsgid \"The following variations of the display are currently supported:\"\nmsgstr \"다음과 같은 표시 변형이 현재 지원됩니다:\"\n\n#: ../../app3.rst:250 97d286a4d5f74472a14b8d008c4a6e14\nmsgid \"\"\n\"Bool parameter `\\\"keep_proportion\\\"` controls whether to maintain the \"\n\"aspect ratio (default) or not.\"\nmsgstr \"Bool 매개변수 `\\\"keep_proportion\\\"` 은 종횡비를 유지할지 여부를 제어합니다(기본값).\"\n\n#: ../../app3.rst:251 b3ca7e9050f84361a916dd947a4aee68\nmsgid \"\"\n\"Rectangle parameter `\\\"clip\\\"` restricts the visible part of the source \"\n\"page rectangle. Default is the full page.\"\nmsgstr \"사각형 매개변수 `\\\"clip\\\"` 은 소스 페이지 사각형의 보이는 부분을 제한합니다. 기본값은 전체 페이지입니다.\"\n\n#: ../../app3.rst:252 994ff62c446f4ec48980737cb9847a1b\nmsgid \"\"\n\"float `\\\"rotation\\\"` rotates the display by an arbitrary angle (degrees).\"\n\" If the angle is not an integer multiple of 90, only 2 of the 4 corners \"\n\"may be positioned on the target border if also `\\\"keep_proportion\\\"` is \"\n\"true.\"\nmsgstr \"\"\n\"float `\\\"rotation\\\"` 은 표시를 임의의 각도(도)로 회전시킵니다. 각도가 90의 정수 배가 아니고 \"\n\"`\\\"keep_proportion\\\"` 도 true인 경우, 4개 모서리 중 2개만 대상 경계에 위치할 수 있습니다.\"\n\n#: ../../app3.rst:253 df91bedf8d2448b9b6e1d9b0e146b290\nmsgid \"\"\n\"Bool parameter `\\\"overlay\\\"` controls whether to put the image on top \"\n\"(foreground, default) of current page content or not (background).\"\nmsgstr \"Bool 매개변수 `\\\"overlay\\\"` 는 이미지를 현재 페이지 콘텐츠 위(전경, 기본값)에 배치할지 여부를 제어합니다(배경).\"\n\n#: ../../app3.rst:255 7f1ad38d9991450f8326a9f7891e02ed\nmsgid \"Use cases include (but are not limited to) the following:\"\nmsgstr \"사용 사례에는 다음이 포함됩니다(이에 국한되지 않음):\"\n\n#: ../../app3.rst:257 68f2f629805445a3888fea51dad910ae\nmsgid \"\"\n\"\\\"Stamp\\\" a series of pages of the current document with the same image, \"\n\"like a company logo or a watermark.\"\nmsgstr \"회사 로고나 워터마크와 같은 동일한 이미지로 현재 문서의 일련의 페이지에 \\\"스탬프\\\"를 찍습니다.\"\n\n#: ../../app3.rst:258 31e6350216514a078362663c9f252a2f\nmsgid \"\"\n\"Combine arbitrary input pages into one output page to support “booklet” \"\n\"or double-sided printing (known as \\\"4-up\\\", \\\"n-up\\\").\"\nmsgstr \"\"\n\"임의의 입력 페이지를 하나의 출력 페이지로 결합하여 “북렛” 또는 양면 인쇄( \\\"4-up\\\", \\\"n-up\\\" 으로 알려짐)를 \"\n\"지원합니다.\"\n\n#: ../../app3.rst:259 9c80023be1d94d0cbbca8f1314af6a46\nmsgid \"\"\n\"Split up (large) input pages into several arbitrary pieces. This is also \"\n\"called “posterization”, because you e.g. can split an A4 page \"\n\"horizontally and vertically, print the 4 pieces enlarged to separate A4 \"\n\"pages, and end up with an A2 version of your original page.\"\nmsgstr \"\"\n\"(큰) 입력 페이지를 여러 임의의 조각으로 분할합니다. 이것은 “포스터화”라고도 하며, 예를 들어 A4 페이지를 가로와 세로로 \"\n\"분할하고, 4개 조각을 확대하여 별도의 A4 페이지로 인쇄한 다음 원본 페이지의 A2 버전을 얻을 수 있기 때문입니다.\"\n\n#: ../../app3.rst:262 62098c390f3043009fc377ea8e54100a\nmsgid \"Technical Implementation\"\nmsgstr \"기술적 구현\"\n\n#: ../../app3.rst:264 3dfab80881604fef89ec3850557c91ff\nmsgid \"\"\n\"This is done using PDF **\\\"Form XObjects\\\"**, see section 8.10 on page \"\n\"217 of :ref:`AdobeManual`. On execution of a :meth:`Page.show_pdf_page`, \"\n\"the following things happen:\"\nmsgstr \"\"\n\"이것은 PDF **\\\"Form XObjects\\\"** 를 사용하여 수행됩니다. :ref:`AdobeManual` 의 217페이지 \"\n\"섹션 8.10을 참조하세요. :meth:`Page.show_pdf_page` 를 실행하면 다음이 발생합니다:\"\n\n#: ../../app3.rst:266 9d2548f8045f487c895825c9f1f0e965\nmsgid \"\"\n\"The :data:`resources` and :data:`contents` objects of source page in \"\n\"source document are copied over to the target document, jointly creating \"\n\"a new **Form XObject** with the following properties. The PDF \"\n\":data:`xref` number of this object is returned by the method.\"\nmsgstr \"\"\n\"소스 문서의 소스 페이지의 :data:`resources` 및 :data:`contents` 객체가 대상 문서로 복사되어 다음 \"\n\"속성을 가진 새로운 **Form XObject** 를 공동으로 생성합니다. 이 객체의 PDF :data:`xref` 번호는 메서드에\"\n\" 의해 반환됩니다.\"\n\n#: ../../app3.rst:268 bb76e425ccb64473b57788e768f4ec73\nmsgid \"`/BBox` equals `/Mediabox` of the source page\"\nmsgstr \"`/BBox` 는 소스 페이지의 `/Mediabox` 와 같습니다\"\n\n#: ../../app3.rst:269 c31f893de0fc41298d55e90ccf4fe8f8\nmsgid \"`/Matrix` equals the identity matrix.\"\nmsgstr \"`/Matrix` 는 항등 행렬과 같습니다.\"\n\n#: ../../app3.rst:270 b88a10668d6143c8896ff880d6b0a465\nmsgid \"\"\n\"`/Resources` equals that of the source page. This involves a “deep-copy” \"\n\"of hierarchically nested other objects (including fonts, images, etc.). \"\n\"The complexity involved here is covered by MuPDF's grafting [#f1]_ \"\n\"technique functions.\"\nmsgstr \"\"\n\"`/Resources` 는 소스 페이지의 것과 같습니다. 이것은 계층적으로 중첩된 다른 객체(글꼴, 이미지 등 포함)의 \"\n\"deep-copy” 를 포함합니다. 여기에 관련된 복잡성은 |MuPDF| 의 grafting [#f1]_ 기술 함수로 \"\n\"처리됩니다.\"\n\n#: ../../app3.rst:271 012404bf546e41f0a21925ebb840eb7d\nmsgid \"\"\n\"This is a stream object type, and its stream is an exact copy of the \"\n\"combined data of the source page's :data:`contents` objects.\"\nmsgstr \"이것은 스트림 객체 타입이며, 그 스트림은 소스 페이지의 :data:`contents` 객체의 결합된 데이터의 정확한 복사본입니다.\"\n\n#: ../../app3.rst:273 134d89c3ee7d414281d9d706d3f7fca3\nmsgid \"\"\n\"This Form XObject is only executed once per shown source page. Subsequent\"\n\" displays of the same source page will skip this step and only create \"\n\"\\\"pointer\\\" Form XObjects (done in next step) to this object.\"\nmsgstr \"\"\n\"이 Form XObject는 표시된 소스 페이지당 한 번만 실행됩니다. 동일한 소스 페이지의 후속 표시는 이 단계를 건너뛰고 이 \"\n\"객체에 대한 \\\"포인터\\\" Form XObjects만 생성합니다(다음 단계에서 수행).\"\n\n#: ../../app3.rst:275 50987890b05b44a0ab6dce288ad5ab0a\nmsgid \"\"\n\"A second **Form XObject** is then created which the target page uses to \"\n\"invoke the display. This object has the following properties:\"\nmsgstr \"\"\n\"그런 다음 대상 페이지가 표시를 호출하는 데 사용하는 두 번째 **Form XObject** 가 생성됩니다. 이 객체는 다음 속성을\"\n\" 가집니다:\"\n\n#: ../../app3.rst:277 33bd465dbdd047c7816f59b343c2d780\nmsgid \"`/BBox` equals the `/CropBox` of the source page (or `\\\"clip\\\"`).\"\nmsgstr \"`/BBox` 는 소스 페이지의 `/CropBox` (또는 `\\\"clip\\\"`)와 같습니다.\"\n\n#: ../../app3.rst:278 ecaa890ab1e94d268751da3df22cf421\nmsgid \"`/Matrix` represents the mapping of `/BBox` to the target rectangle.\"\nmsgstr \"`/Matrix` 는 `/BBox` 를 대상 사각형으로 매핑하는 것을 나타냅니다.\"\n\n#: ../../app3.rst:279 b7950a1195e54793b9b3b5b911fc150c\nmsgid \"\"\n\"`/XObject` references the previous Form XObject via the fixed name \"\n\"`fullpage`.\"\nmsgstr \"`/XObject` 는 고정된 이름 `fullpage` 를 통해 이전 Form XObject를 참조합니다.\"\n\n#: ../../app3.rst:280 8a89d2b17c624ea39d9d9414c18fceee\nmsgid \"\"\n\"The stream of this object contains exactly one fixed statement: \"\n\"`/fullpage Do`.\"\nmsgstr \"이 객체의 스트림은 정확히 하나의 고정된 문을 포함합니다: `/fullpage Do`.\"\n\n#: ../../app3.rst:281 8071f5c0c01b40ed8d0b3c8e0caea1d5\nmsgid \"\"\n\"If the method's `\\\"oc\\\"` argument is given, its value is assigned to this\"\n\" Form XObject as `/OC`.\"\nmsgstr \"메서드의 `\\\"oc\\\"` 인수가 주어지면, 그 값이 이 Form XObject에 `/OC` 로 할당됩니다.\"\n\n#: ../../app3.rst:283 d0dcf58ed13a453a834e115f4ea0c511\nmsgid \"\"\n\"The :data:`resources` and :data:`contents` objects of the target page are\"\n\" now modified as follows.\"\nmsgstr \"대상 페이지의 :data:`resources` 및 :data:`contents` 객체는 다음과 같이 수정됩니다.\"\n\n#: ../../app3.rst:285 77b2331ffaee4e7b8feca779154bca43\nmsgid \"\"\n\"Add an entry to the `/XObject` dictionary of `/Resources` with the name \"\n\"`fzFrm<n>` (with n chosen such that this entry is unique on the page).\"\nmsgstr \"\"\n\"`/Resources` 의 `/XObject` 딕셔너리에 `fzFrm<n>` 이라는 이름으로 항목을 추가합니다(n은 이 항목이 \"\n\"페이지에서 고유하도록 선택됨).\"\n\n#: ../../app3.rst:286 71da2b0e5eea427e8ef41d4ee9facaf2\nmsgid \"\"\n\"Depending on `\\\"overlay\\\"`, prepend or append a new object to the page's \"\n\"`/Contents` array, containing the statement `q /fzFrm<n> Do Q`.\"\nmsgstr \"\"\n\"`\\\"overlay\\\"` 에 따라 페이지의 `/Contents` 배열에 `q /fzFrm<n> Do Q` 문을 포함하는 새 객체를 \"\n\"앞에 추가하거나 뒤에 추가합니다.\"\n\n#: ../../app3.rst:288 ce7e0186bef54c97a9b29d12c1e6f3a6\nmsgid \"This design approach ensures that:\"\nmsgstr \"이 설계 접근 방식은 다음을 보장합니다:\"\n\n#: ../../app3.rst:290 eb54e5bd84bb498abb3763ee5407a28e\nmsgid \"\"\n\"The (potentially large) source page is only copied once to the target \"\n\"PDF. Only small \\\"pointer\\\" Form XObjects objects are created per each \"\n\"target page to show the source page.\"\nmsgstr \"\"\n\"(잠재적으로 큰) 소스 페이지는 대상 PDF에 한 번만 복사됩니다. 소스 페이지를 표시하기 위해 각 대상 페이지당 작은 \"\n\"\\\"포인터\\\" Form XObjects 객체만 생성됩니다.\"\n\n#: ../../app3.rst:291 9bdd7aac08c848b896a77921ae741fc8\nmsgid \"\"\n\"Each referring target page can have its own `\\\"oc\\\"` parameter to control\"\n\" the source page's visibility individually.\"\nmsgstr \"각 참조 대상 페이지는 소스 페이지의 가시성을 개별적으로 제어하기 위해 자체 `\\\"oc\\\"` 매개변수를 가질 수 있습니다.\"\n\n#: ../../app3.rst:298 38192e7d264e49b9b11f8bff65d9f574\nmsgid \"Diagnostics\"\nmsgstr \"진단\"\n\n#: ../../app3.rst:303 678e61f215bb4b728ec825f020a47ade\nmsgid \"|PyMuPDF| messages\"\nmsgstr \"|PyMuPDF| 메시지\"\n\n#: ../../app3.rst:305 b0163c7491294ddc8e19c68b4a236621\nmsgid \"|PyMuPDF| has a Message system for showing text diagnostics.\"\nmsgstr \"|PyMuPDF| 는 텍스트 진단을 표시하기 위한 메시지 시스템을 가지고 있습니다.\"\n\n#: ../../app3.rst:307 ae5fa773d042458bba579ef11b18c5f1\nmsgid \"\"\n\"By default messages are written to `sys.stdout`. This can be controlled \"\n\"in two ways:\"\nmsgstr \"기본적으로 메시지는 `sys.stdout` 에 기록됩니다. 이것은 두 가지 방법으로 제어할 수 있습니다:\"\n\n#: ../../app3.rst:311 e9874754031f42d2977701bc48a0202a\nmsgid \"Set environment variable `PYMUPDF_MESSAGE` before |PyMuPDF| is imported.\"\nmsgstr \"|PyMuPDF| 를 가져오기 전에 환경 변수 `PYMUPDF_MESSAGE` 를 설정합니다.\"\n\n#: ../../app3.rst:314 752d0f8c25c3400ab0fd25a0bd727e90\nmsgid \"Call `set_messages()`:\"\nmsgstr \"`set_messages()` 를 호출합니다:\"\n\n#: ../../app3.rst:318 c98f984f976c49d7bf561a0bd2ec9dc5\nmsgid \"|MuPDF| errors and warnings\"\nmsgstr \"|MuPDF| 오류 및 경고\"\n\n#: ../../app3.rst:320 ff1b806727194154b4b239fd45add954\nmsgid \"|MuPDF| generates text errors and warnings.\"\nmsgstr \"|MuPDF| 는 텍스트 오류 및 경고를 생성합니다.\"\n\n#: ../../app3.rst:323 0f276711268e409fb82df4ba73696ece\nmsgid \"\"\n\"These errors and warnings are appended to an internal list, accessible \"\n\"with `Tools.mupdf_warnings()`. Also see `Tools.reset_mupdf_warnings()`.\"\nmsgstr \"\"\n\"이러한 오류 및 경고는 내부 목록에 추가되며, `Tools.mupdf_warnings()` 로 액세스할 수 있습니다. \"\n\"`Tools.reset_mupdf_warnings()` 도 참조하세요.\"\n\n#: ../../app3.rst:327 073e0bdb4e0d4e36bb6759931da9f080\nmsgid \"\"\n\"By default these errors and warnings are also sent to the |PyMuPDF| \"\n\"message system.\"\nmsgstr \"기본적으로 이러한 오류 및 경고는 |PyMuPDF| 메시지 시스템에도 전송됩니다.\"\n\n#: ../../app3.rst:330 c438af959e7d416a8bdd12d4a262666f\nmsgid \"\"\n\"This can be controlled with `mupdf_display_errors()` and \"\n\"`mupdf_display_warnings()`.\"\nmsgstr \"이것은 `mupdf_display_errors()` 및 `mupdf_display_warnings()` 로 제어할 수 있습니다.\"\n\n#: ../../app3.rst:334 751a2f790c0c436ba72274b9a9cd2841\nmsgid \"\"\n\"These messages are prefixed with `MuPDF error:` and `MuPDF warning:` \"\n\"respectively.\"\nmsgstr \"이러한 메시지는 각각 `MuPDF error:` 및 `MuPDF warning:` 접두사가 붙습니다.\"\n\n#: ../../app3.rst:337 9d9fa818d46c40c4abd7e99971db02f1\nmsgid \"Some |MuPDF| errors may lead to Python exceptions.\"\nmsgstr \"일부 |MuPDF| 오류는 Python 예외를 유발할 수 있습니다.\"\n\n#: ../../app3.rst:339 305562c6d9974f98a9b2d09d489e294c\nmsgid \"\"\n\"Example output for a **recoverable error**. We are opening a damaged PDF,\"\n\" but MuPDF is able to repair it and gives us a little information on what\"\n\" happened. Then we illustrate how to find out whether the document can \"\n\"later be saved incrementally. Checking the :attr:`Document.is_dirty` \"\n\"attribute at this point also indicates that during `pymupdf.open` the \"\n\"document had to be repaired:\"\nmsgstr \"\"\n\"**복구 가능한 오류** 에 대한 예제 출력입니다. 손상된 PDF를 열고 있지만 |MuPDF| 는 이를 복구할 수 있고 발생한 일에\"\n\" 대한 약간의 정보를 제공합니다. 그런 다음 문서를 나중에 증분 저장할 수 있는지 확인하는 방법을 설명합니다. 이 시점에서 \"\n\":attr:`Document.is_dirty` 속성을 확인하면 `pymupdf.open` 중에 문서를 복구해야 했음을 나타냅니다:\"\n\n#: ../../app3.rst:360 10e13c5dbba64ba7a6bed125229ffea8\nmsgid \"Example output for an **unrecoverable error**:\"\nmsgstr \"**복구 불가능한 오류** 에 대한 예제 출력:\"\n\n#: ../../app3.rst:378 55ce8adbca56443192458ad1412c6eb6\nmsgid \"Coordinates\"\nmsgstr \"좌표\"\n\n#: ../../app3.rst:381 25b2587ee67742f8aab4274ba33aaed0\nmsgid \"\"\n\"This is one of the most frequently used terms in this documentation. A \"\n\"**coordinate** generally means a pair of numbers `(x, y)` referring to \"\n\"some location, like a corner of a rectangle (:ref:`Rect`), a :ref:`Point`\"\n\" and so forth. The two values usually are floats, but there a objects \"\n\"like images which only allow them to be integers.\"\nmsgstr \"\"\n\"이것은 이 문서에서 가장 자주 사용되는 용어 중 하나입니다. **좌표** 는 일반적으로 사각형의 모서리(:ref:`Rect`), \"\n\":ref:`Point` 등과 같은 위치를 나타내는 숫자 쌍 `(x, y)` 를 의미합니다. 두 값은 일반적으로 float이지만, \"\n\"정수만 허용하는 이미지와 같은 객체도 있습니다.\"\n\n#: ../../app3.rst:383 07fa97393cb64575ba7ca3c72e92d3e0\nmsgid \"\"\n\"To actually *find* a coordinate's location, we also need to know the \"\n\"*reference* point for ``x`` and ``y`` - in other words, we must know \"\n\"where location `(0, 0)` is positioned. Once `(0, 0)` (the \\\"origin\\\") is \"\n\"known, we speak of a \\\"coordinate system\\\".\"\nmsgstr \"\"\n\"실제로 좌표의 위치를 *찾으려면*, ``x`` 와 ``y`` 의 *참조* 점도 알아야 합니다 -- 즉, 위치 `(0, 0)` 이 \"\n\"어디에 있는지 알아야 합니다. `(0, 0)` (\\\"원점\\\")이 알려지면 \\\"좌표계\\\"라고 말합니다.\"\n\n#: ../../app3.rst:385 f03d3158dc424965ad72da81750b12cc\nmsgid \"\"\n\"Several coordinate systems exist in document processing. For instance, \"\n\"the coordinate systems of a PDF page and the image created from it are \"\n\"**different**. We therefore need ways to *transform* coordinates from one\"\n\" system to another (and also back occasionally). This is the task of a \"\n\":ref:`Matrix`. It is a mathematical function which works much like a \"\n\"factor that can be \\\"multiplied\\\" with a point or rectangle to give us \"\n\"the corresponding point / rectangle in another coordinate system. The \"\n\"inverse of a transformation matrix can be used to revert the \"\n\"transformation. Much like multiplying by some factor, say 3, can be \"\n\"reverted by dividing the result by 3 (or multiplying it with 1/3).\"\nmsgstr \"\"\n\"문서 처리에는 여러 좌표계가 존재합니다. 예를 들어, PDF 페이지와 그것으로부터 생성된 이미지의 좌표계는 **다릅니다**. 따라서\"\n\" 한 시스템에서 다른 시스템으로 좌표를 *변환* 하는 방법이 필요합니다(때로는 역으로도). 이것이 :ref:`Matrix` 의 \"\n\"작업입니다. 이것은 점이나 사각형과 \\\"곱할\\\" 수 있는 인수처럼 작동하여 다른 좌표계에서 해당 점/사각형을 제공하는 수학 \"\n\"함수입니다. 변환 행렬의 역행렬을 사용하여 변환을 되돌릴 수 있습니다. 예를 들어 3을 곱하는 것을 결과를 3으로 나누거나(또는 \"\n\"1/3을 곱함)하여 되돌릴 수 있는 것과 매우 유사합니다.\"\n\n#: ../../app3.rst:388 2861d34531e741f2899ff1dc71d8b465\nmsgid \"Coordinates and Images\"\nmsgstr \"좌표 및 이미지\"\n\n#: ../../app3.rst:390 2a2c6ebc18e84f02aebc26d7a8e9905d\nmsgid \"\"\n\"Images have a coordinate system with integer coordinates. Origin `(0, 0)`\"\n\" is the top-left point. ``x`` values must be in `range(width)`, and ``y``\"\n\" values in `range(height)`. Therefore, ``y`` values *increase* if we go \"\n\"*downwards*. For every image, there is only a **finite number** of \"\n\"coordinates, namely `width * height`. A location in an image is also \"\n\"called a \\\"pixel\\\".\"\nmsgstr \"\"\n\"이미지는 정수 좌표를 가진 좌표계를 가집니다. 원점 `(0, 0)` 은 왼쪽 위 점입니다. ``x`` 값은 \"\n\"`range(width)` 에 있어야 하고, ``y`` 값은 `range(height)` 에 있어야 합니다. 따라서 *아래로* 가면\"\n\" ``y`` 값이 *증가* 합니다. 모든 이미지에 대해 **유한한 수** 의 좌표만 있습니다. 즉, `width * height` \"\n\"입니다. 이미지의 위치는 \\\"픽셀\\\"이라고도 합니다.\"\n\n#: ../../app3.rst:392 2d1ab7caafc4475bb1e0bb937bd193f5\nmsgid \"\"\n\"How **large** an image will be (in centimeters or inches) when e.g. \"\n\"printed, depends on additional information: the \\\"resolution\\\". This is \"\n\"measured in **DPI** (dots per inch, or pixels per inch). To find the \"\n\"printed size of some image, we therefore must divide its width and its \"\n\"height by the corresponding DPI values (there may separate ones for width\"\n\" and for height) and will get the respective number of inches.\"\nmsgstr \"\"\n\"예를 들어 인쇄할 때 이미지가 **얼마나 큰지** (센티미터 또는 인치)는 추가 정보인 \\\"해상도\\\"에 따라 다릅니다. 이것은 \"\n\"**DPI** (인치당 도트 또는 인치당 픽셀)로 측정됩니다. 따라서 이미지의 인쇄 크기를 찾으려면 너비와 높이를 해당 DPI \"\n\"값으로 나누어야 하며(너비와 높이에 대해 별도의 값이 있을 수 있음) 각각의 인치 수를 얻을 수 있습니다.\"\n\n#: ../../app3.rst:396 861cbf0fef9b49cd9a4c66166b84a606\nmsgid \"Origin Point, Point Size and Y-Axis\"\nmsgstr \"원점, 포인트 크기 및 Y축\"\n\n#: ../../app3.rst:398 40053762c0d549a589c0738ef25485e0\nmsgid \"\"\n\"In |PDF|, the origin `(0, 0)` of a page is located at its **bottom-left \"\n\"point**. In |MuPDF|, the origin `(0, 0)` of a page is located at its \"\n\"**top-left point**.\"\nmsgstr \"\"\n\"|PDF| 에서 페이지의 원점 `(0, 0)` 은 **왼쪽 아래 점** 에 있습니다. |MuPDF| 에서 페이지의 원점 `(0, \"\n\"0)` 은 **왼쪽 위 점** 에 있습니다.\"\n\n#: ../../app3.rst:403 006e004df7614a4e951f99ba46acb439\nmsgid \"Coordinates are float numbers and measured in **points**, where:\"\nmsgstr \"좌표는 float 숫자이며 **포인트** 단위로 측정됩니다. 여기서:\"\n\n#: ../../app3.rst:405 060972242c9c45a399b754799bda2112\nmsgid \"**one point equals 1/72 inches**.\"\nmsgstr \"**1포인트는 1/72인치** 와 같습니다.\"\n\n#: ../../app3.rst:407 32f04e20ba5e41f09c447ba3a79e54c8\nmsgid \"\"\n\"Typical document page sizes are **ISO A4** and **Letter**. A **Letter** \"\n\"page has a size of **8.5 x 11 inches**, corresponding to **612 x 792 \"\n\"points**. In the |PDF| coordinate system, the top-left point of a \"\n\"**Letter** page hence has the coordinate `(0, 792)` as **the y-axis \"\n\"points upwards**. Now we know our document size the |MuPDF| coordinate \"\n\"system for the bottom right would be coordinate `(612, 792)` (and for \"\n\"|PDF| this coordinate would then be `(612,0)`).\"\nmsgstr \"\"\n\"일반적인 문서 페이지 크기는 **ISO A4** 및 **Letter** 입니다. **Letter** 페이지는 **8.5 x \"\n\"11인치** 크기를 가지며, 이는 **612 x 792 포인트** 에 해당합니다. |PDF| 좌표계에서 **Letter** 페이지의\"\n\" 왼쪽 위 점은 **y축이 위를 가리키므로** 좌표 `(0, 792)` 를 가집니다. 이제 문서 크기를 알았으므로 |MuPDF| \"\n\"좌표계에서 오른쪽 아래는 좌표 `(612, 792)` 가 됩니다(|PDF| 에서는 이 좌표가 `(612,0)` 이 됩니다).\"\n\n#: ../../app3.rst:409 1ff227ed19b04762886cbcbc4e4922ad\nmsgid \"\"\n\"Theoretically, there are **infinitely many** coordinate positions on a \"\n\"|PDF| page. In practice however, at most the first 5 decimal places are \"\n\"sufficient for a reasonable precision.\"\nmsgstr \"\"\n\"이론적으로 |PDF| 페이지에는 **무한히 많은** 좌표 위치가 있습니다. 그러나 실제로는 합리적인 정밀도를 위해 최대 처음 5자리\"\n\" 소수점이면 충분합니다.\"\n\n#: ../../app3.rst:412 ccd57b81247849d887f21f917dcf79e1\nmsgid \"\"\n\"In |MuPDF|, multiple document formats are supported - |PDF| just being \"\n\"one among **over a dozen others**. Images are also supported as documents\"\n\" in |MuPDF| (therefore having one page usually). This is one of the \"\n\"reasons why |MuPDF| uses a coordinate system with the origin `(0, 0)` \"\n\"being the **top-left** point of any document page. **The y-axis points \"\n\"downwards**, like with images. Coordinates in |MuPDF| in any case are \"\n\"floats, like in |PDF|.\"\nmsgstr \"\"\n\"|MuPDF| 에서는 여러 문서 형식이 지원됩니다 -- |PDF| 는 **12개 이상의 다른 형식** 중 하나일 뿐입니다. 이미지도\"\n\" |MuPDF| 에서 문서로 지원됩니다(따라서 일반적으로 한 페이지를 가짐). 이것이 |MuPDF| 가 원점 `(0, 0)` 이 \"\n\"모든 문서 페이지의 **왼쪽 위** 점인 좌표계를 사용하는 이유 중 하나입니다. **y축은 아래를 가리킵니다**, 이미지와 \"\n\"마찬가지입니다. |MuPDF| 의 좌표는 어떤 경우든 |PDF| 와 마찬가지로 float입니다.\"\n\n#: ../../app3.rst:414 9657e0b219bd4d518cdcf40a8a6ccc21\nmsgid \"\"\n\"A rectangle `Rect(0, 0, 100, 100)` for instance in |MuPDF| (and thus \"\n\"|PyMuPDF|) therefore is a square with edges of length 100 points (= 1.39 \"\n\"inches or 3.53 centimeters). Its top-left corner is the origin. To switch\"\n\" between the two coordinate systems |PDF| to |MuPDF|, every :ref:`Page` \"\n\"object has a :attr:`Page.transformation_matrix`. Its inverse can be used \"\n\"to compute a rectangle's PDF coordinates. In this way we can conveniently\"\n\" find that `Rect(0, 0, 100, 100)` in |MuPDF| is the same as `Rect(0, 692,\"\n\" 100, 792)` in |PDF|. See this code snippet::\"\nmsgstr \"\"\n\"예를 들어 |MuPDF| (따라서 |PyMuPDF| )에서 `Rect(0, 0, 100, 100)` 사각형은 길이가 100포인트(=\"\n\" 1.39인치 또는 3.53센티미터)인 변을 가진 정사각형입니다. 왼쪽 위 모서리가 원점입니다. 두 좌표계 |PDF| 와 \"\n\"|MuPDF| 사이를 전환하려면 모든 :ref:`Page` 객체는 :attr:`Page.transformation_matrix` 를\"\n\" 가집니다. 그 역행렬을 사용하여 사각형의 PDF 좌표를 계산할 수 있습니다. 이렇게 하면 |MuPDF| 의 `Rect(0, 0, \"\n\"100, 100)` 이 |PDF| 의 `Rect(0, 692, 100, 792)` 와 같다는 것을 편리하게 찾을 수 있습니다. 이 \"\n\"코드 조각을 참조하세요::\"\n\n#: ../../app3.rst:425 59083fb45b414470920471c730d07179\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../app3.rst:426 0164e8d6d2cb4cf98c0101507e790e14\nmsgid \"\"\n\"MuPDF supports \\\"deep-copying\\\" objects between PDF documents. To avoid \"\n\"duplicate data in the target, it uses so-called \\\"graftmaps\\\", like a \"\n\"form of scratchpad: for each object to be copied, its :data:`xref` number\"\n\" is looked up in the graftmap. If found, copying is skipped. Otherwise, \"\n\"the new :data:`xref` is recorded and the copy takes place. PyMuPDF makes \"\n\"use of this technique in two places so far: :meth:`Document.insert_pdf` \"\n\"and :meth:`Page.show_pdf_page`. This process is fast and very efficient, \"\n\"because it prevents multiple copies of typically large and frequently \"\n\"referenced data, like images and fonts. However, you may still want to \"\n\"consider using garbage collection (option 4) in any of the following \"\n\"cases:\"\nmsgstr \"\"\n\"|MuPDF| 는 PDF 문서 간에 객체를 \\\"deep-copying\\\" 하는 것을 지원합니다. 대상에서 중복 데이터를 피하기 위해\"\n\" 스크래치패드 형태의 소위 \\\"graftmaps\\\" 를 사용합니다: 복사할 각 객체에 대해 그 :data:`xref` 번호가 \"\n\"graftmap에서 조회됩니다. 발견되면 복사가 건너뜁니다. 그렇지 않으면 새로운 :data:`xref` 가 기록되고 복사가 \"\n\"수행됩니다. |PyMuPDF| 는 지금까지 두 곳에서 이 기술을 사용합니다: :meth:`Document.insert_pdf` 및 \"\n\":meth:`Page.show_pdf_page`. 이 프로세스는 빠르고 매우 효율적입니다. 왜냐하면 이미지와 글꼴과 같은 일반적으로\"\n\" 크고 자주 참조되는 데이터의 여러 복사본을 방지하기 때문입니다. 그러나 다음 경우 중 하나에서 가비지 수집(옵션 4)을 사용하는 \"\n\"것을 고려할 수 있습니다:\"\n\n#: ../../app3.rst:428 ff64eb6459dd48aab243823d1e5a8733\nmsgid \"\"\n\"The target PDF is not new / empty: grafting does not check for resources \"\n\"that already existed (e.g. images, fonts) in the target document before \"\n\"opening it.\"\nmsgstr \"\"\n\"대상 PDF가 새 것이 아니거나 비어 있지 않음: grafting은 문서를 열기 전에 대상 문서에 이미 존재했던 리소스(예: \"\n\"이미지, 글꼴)를 확인하지 않습니다.\"\n\n#: ../../app3.rst:429 f6431e1f385d4ed89c60d314577c3b72\nmsgid \"\"\n\"Using :meth:`Page.show_pdf_page` for more than one source document: each \"\n\"grafting occurs **within one source** PDF only, not across multiple. So \"\n\"if e.g. the same image exists in pages from different source PDFs, then \"\n\"this will not be detected until garbage collection.\"\nmsgstr \"\"\n\"하나 이상의 소스 문서에 대해 :meth:`Page.show_pdf_page` 사용: 각 grafting은 여러 문서에 걸쳐서가 \"\n\"아니라 **하나의 소스** PDF 내에서만 발생합니다. 따라서 예를 들어 다른 소스 PDF의 페이지에 동일한 이미지가 존재하면, \"\n\"가비지 수집까지 이것이 감지되지 않습니다.\"\n\n#: ../../footer.rst:57 0e66288fd8404701a02732244ee2b635\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/app4.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 613ca8dee3af4e18aee8824f32d62bd7\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 3fb1879bb92640d0b871ed41914b2b0d\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 5800ad4c0c8f4aea8589a92458f2afe9\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../app4.rst:14 452ac8cb00694e9abeae5f9e25ddebf6\nmsgid \"Appendix 4: Performance Comparison Methodology\"\nmsgstr \"부록 4: 성능 비교 방법론\"\n\n#: ../../app4.rst:16 14ceae9e1c7f4b8f8a0319fbb991a23c\nmsgid \"\"\n\"This article documents the approach to measure :title:`PyMuPDF's` \"\n\"performance and the tools and example files used to do comparisons.\"\nmsgstr \"이 문서는 :title:`PyMuPDF's` 성능을 측정하는 접근 방식과 비교에 사용된 도구 및 예제 파일을 설명합니다.\"\n\n#: ../../app4.rst:18 707cf837e27a4490be01f4ff59f3d6e7\nmsgid \"The following three sections deal with different performance aspects:\"\nmsgstr \"다음 세 섹션은 다양한 성능 측면을 다룹니다:\"\n\n#: ../../app4.rst:20 19bf7499dda54ae094b5f694a8ea950f\nmsgid \"\"\n\":ref:`Document Copying<app4_copying>` - This includes opening and parsing\"\n\" :title:`PDFs`, then writing them to an output file. Because the same \"\n\"basic activities are also used for joining (merging) :title:`PDFs`, the \"\n\"results also apply to these use cases.\"\nmsgstr \":ref:`Document Copying<app4_copying>` - 이것은 :title:`PDFs` 를 열고 파싱한 다음 출력 파일에 쓰는 것을 포함합니다. 동일한 기본 활동이 :title:`PDFs` 를 결합(병합)하는 데도 사용되므로, 결과는 이러한 사용 사례에도 적용됩니다.\"\n\n#: ../../app4.rst:21 8902b7d3bdf44cdeb0a02ebaeb788364\nmsgid \"\"\n\":ref:`Text Extraction<app4_text_extraction>` - This extracts plain text \"\n\"from :title:`PDFs` and writes it to an output text file.\"\nmsgstr \":ref:`Text Extraction<app4_text_extraction>` - 이것은 :title:`PDFs` 에서 일반 텍스트를 추출하고 출력 텍스트 파일에 씁니다.\"\n\n#: ../../app4.rst:22 c9e28e548b684c15b6fc6c839fb268d0\nmsgid \"\"\n\":ref:`Page Rendering<app4_page_rendering>` - This converts |PDF| pages to\"\n\" image files looking identical to the pages. This ability is the basic \"\n\"prerequisite for using a tool in :title:`Python GUI` scripts to scroll \"\n\"through documents. We have chosen a medium-quality (resolution 150 DPI) \"\n\"version.\"\nmsgstr \":ref:`Page Rendering<app4_page_rendering>` - 이것은 |PDF| 페이지를 페이지와 동일하게 보이는 이미지 파일로 변환합니다. 이 기능은 :title:`Python GUI` 스크립트에서 문서를 스크롤하기 위해 도구를 사용하는 기본 전제 조건입니다. 중간 품질(해상도 150 DPI) 버전을 선택했습니다.\"\n\n#: ../../app4.rst:24 d8c56f0cbbb4415497587ade558105c9\nmsgid \"\"\n\"Please note that in all cases the actual speed in dealing with |PDF| \"\n\"structures is not directly measured: instead, the timings also include \"\n\"the durations of writing files to the operating system's file system. \"\n\"This cannot be avoided because tools other than |PyMuPDF| do not offer \"\n\"the option to e.g., separate the image **creation** step from the \"\n\"following step, which **writes** the image into a file.\"\nmsgstr \"모든 경우에 |PDF| 구조를 처리하는 실제 속도가 직접 측정되지 않는다는 점에 유의하세요: 대신 타이밍에는 운영 체제의 파일 시스템에 파일을 쓰는 데 걸리는 시간도 포함됩니다. |PyMuPDF| 이외의 도구는 예를 들어 이미지 **생성** 단계를 이미지를 파일에 **쓰는** 다음 단계와 분리하는 옵션을 제공하지 않기 때문에 이것을 피할 수 없습니다.\"\n\n#: ../../app4.rst:26 c95dca0ce6a24b9cbb4e54005da736be\nmsgid \"\"\n\"So all timings documented include a common, OS-oriented base effort. \"\n\"Therefore, performance **differences per tool are actually larger** than \"\n\"the numbers suggest.\"\nmsgstr \"따라서 문서화된 모든 타이밍에는 공통 OS 지향 기본 작업이 포함됩니다. 따라서 도구별 성능 **차이는 실제로 숫자가 시사하는 것보다 큽니다**.\"\n\n#: ../../app4.rst:33 5c8d1822086844e0b5b6e63e24468509\nmsgid \"Files used\"\nmsgstr \"사용된 파일\"\n\n#: ../../app4.rst:35 2439752153d84180a23a0e99527d8073\nmsgid \"\"\n\"A set of eight files is used for the performance testing. With each file \"\n\"we have the following information:\"\nmsgstr \"성능 테스트에 8개의 파일 세트가 사용됩니다. 각 파일에 대해 다음 정보가 있습니다:\"\n\n#: ../../app4.rst:37 b31835ad665241aebc8bce9496462a0b\nmsgid \"**Name** of the file and download **link**.\"\nmsgstr \"파일의 **이름** 및 다운로드 **링크**.\"\n\n#: ../../app4.rst:38 01b0b7ddaf6342b6acea40fc10548232\nmsgid \"**Size** in bytes.\"\nmsgstr \"바이트 단위의 **크기**.\"\n\n#: ../../app4.rst:39 5cefe438dda843c68dd254d3911dbf09\nmsgid \"Total number of **pages** in file.\"\nmsgstr \"파일의 총 **페이지** 수.\"\n\n#: ../../app4.rst:40 245d148da06d4becad20aec51e1fd3bf\nmsgid \"Total number of bookmarks (**Table of Contents** entries).\"\nmsgstr \"책갈피(**목차** 항목)의 총 수.\"\n\n#: ../../app4.rst:41 ff1a2993e3254f7686a848f577c48582\nmsgid \"Total number of **links**.\"\nmsgstr \"**링크** 의 총 수.\"\n\n#: ../../app4.rst:42 fb20f6986d82495e9890d8753eb1f276\nmsgid \"**KB size** per page.\"\nmsgstr \"페이지당 **KB 크기**.\"\n\n#: ../../app4.rst:43 1224aaf0dfde40e1a5c3bc91ef4011ff\nmsgid \"\"\n\"**Textsize per page** is the amount text in the whole file in KB, divided\"\n\" by the number of pages.\"\nmsgstr \"**페이지당 텍스트 크기** 는 전체 파일의 텍스트 양(KB)을 페이지 수로 나눈 값입니다.\"\n\n#: ../../app4.rst:44 8ceb2129883142a09c9d4d383789ed99\nmsgid \"Any **notes** to generally describe the type of file.\"\nmsgstr \"파일 유형을 일반적으로 설명하는 **참고 사항**.\"\n\n#: ../../app4.rst:50 ../../app4.rst:217 ../../app4.rst:295 ../../app4.rst:407\n#: 1b162242a4a54f7dafcae32349b4ed33 930f7531af8b4c2db858b7c3c63f1c57\n#: b459ef8255c34d8bb8f10527b5b13ae0 dd23f2e000014a6ebfbb0df71f4f4550\nmsgid \"**Name**\"\nmsgstr \"**이름**\"\n\n#: ../../app4.rst:51 651fc5cd40134ce993378901eaed782d\nmsgid \"**Size (bytes)**\"\nmsgstr \"**크기 (바이트)**\"\n\n#: ../../app4.rst:52 830651a701b543dd92495f528872e442\nmsgid \"**Pages**\"\nmsgstr \"**페이지**\"\n\n#: ../../app4.rst:53 ad04afd00ac744a8b7c099d48dcdc0c3\nmsgid \"**TOC size**\"\nmsgstr \"**목차 크기**\"\n\n#: ../../app4.rst:54 4286cb4118494c3c97aa7190ce52bbe1\nmsgid \"**Links**\"\nmsgstr \"**링크**\"\n\n#: ../../app4.rst:55 dfccc56073594677aaaf87774c57e911\nmsgid \"**KB/page**\"\nmsgstr \"**KB/페이지**\"\n\n#: ../../app4.rst:56 85615f3120044a3d8f55f0e03fbe8400\nmsgid \"**Textsize/page**\"\nmsgstr \"**텍스트 크기/페이지**\"\n\n#: ../../app4.rst:57 2ed30a8ee08e4381913a180905dc4905\nmsgid \"**Notes**\"\nmsgstr \"**참고 사항**\"\n\n#: ../../app4.rst:58 81403b323ce2471990b6addcb9d327ed\nmsgid \"`adobe.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:59 6dfced8745d04f139c2262964b78cc6c\nmsgid \"32,472,771\"\nmsgstr \"\"\n\n#: ../../app4.rst:60 fe260ad1414a49ad820440768eed3e3d\nmsgid \"1,310\"\nmsgstr \"\"\n\n#: ../../app4.rst:61 aecc68ede79f49e7a2f4965c4d6d21fb\nmsgid \"794\"\nmsgstr \"\"\n\n#: ../../app4.rst:62 19f68930d6b342c8b63282aacdda31ba\nmsgid \"32,096\"\nmsgstr \"\"\n\n#: ../../app4.rst:63 3db3ea234e5e4dbfb2cb18370be6526b\nmsgid \"24\"\nmsgstr \"\"\n\n#: ../../app4.rst:64 df9644ba42384b7f8df8f1a7f9ac9ca6\nmsgid \"1,942\"\nmsgstr \"\"\n\n#: ../../app4.rst:65 9a0b2a88e8d14cbbaa5e220051bc2cbc\nmsgid \"linearized, many links / bookmarks\"\nmsgstr \"\"\n\n#: ../../app4.rst:66 b450a19150554327a540a48702926bd8\nmsgid \"`artifex-website.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:67 f76c22107d8e466e9e9b938d6d2a0c78\nmsgid \"31,570,732\"\nmsgstr \"\"\n\n#: ../../app4.rst:68 121ca9cb77a44f18ae707dc1f62b6828\nmsgid \"47\"\nmsgstr \"\"\n\n#: ../../app4.rst:69 74407cbb0f3b41c8b248f809abe4cf58\nmsgid \"46\"\nmsgstr \"\"\n\n#: ../../app4.rst:70 5a5a12aa804e4285b2c10f71c7b91631\nmsgid \"2,035\"\nmsgstr \"\"\n\n#: ../../app4.rst:71 24d74ed3a9814878b5faa590d81e830c\nmsgid \"656\"\nmsgstr \"\"\n\n#: ../../app4.rst:72 7f66bf0a79ca4e199dd2d27aea8b4e85\nmsgid \"3,538\"\nmsgstr \"\"\n\n#: ../../app4.rst:73 d9c710117eb44abca3a888f45c5f6927\nmsgid \"graphics oriented\"\nmsgstr \"\"\n\n#: ../../app4.rst:74 49bc871f44cb4ddbb8d76e2d42b3155b\nmsgid \"`db-systems.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:75 1a5f0c78435c4c6389a2acd6bd91cd28\nmsgid \"29,326,355\"\nmsgstr \"\"\n\n#: ../../app4.rst:76 f88d9c860ac246f49fdafd12ed4cc62e\nmsgid \"1,241\"\nmsgstr \"\"\n\n#: ../../app4.rst:77 ../../app4.rst:78 ../../app4.rst:117 ../../app4.rst:118\n#: 35384af101fd403ca7b83c7bf3616f8c 48b4936078bd42bab97c666b770093d6\n#: 95853467cdac44e5905fa2aa5f876d2d d6739a13778847ea9c11a2c7b08bc8e0\nmsgid \"0\"\nmsgstr \"\"\n\n#: ../../app4.rst:79 d215b500b52e41cc99c84f24fe3890ec\nmsgid \"23\"\nmsgstr \"\"\n\n#: ../../app4.rst:80 a267452974d549de8748e729075a7ac7\nmsgid \"2,142\"\nmsgstr \"\"\n\n#: ../../app4.rst:82 739b78ec9dc84e99917248ee3622b3b2\nmsgid \"`fontforge.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:83 25bd9632f03d4b2293dc4c8a076d05fa\nmsgid \"8,222,384\"\nmsgstr \"\"\n\n#: ../../app4.rst:84 b567e447fe8f4e0490f62422a2d9d569\nmsgid \"214\"\nmsgstr \"\"\n\n#: ../../app4.rst:85 75588fdd5beb42a78773ef5340ecc1b6\nmsgid \"31\"\nmsgstr \"\"\n\n#: ../../app4.rst:86 0c2001d30c0f4f07963b9f2e38b0f614\nmsgid \"242\"\nmsgstr \"\"\n\n#: ../../app4.rst:87 d6c479c026b5484881aa9197ffc88c6a\nmsgid \"38\"\nmsgstr \"\"\n\n#: ../../app4.rst:88 b9139930537345d284aa9a31220d74c6\nmsgid \"1,058\"\nmsgstr \"\"\n\n#: ../../app4.rst:89 710514866ee04905bf3be46a44b683bf\nmsgid \"mix of text & graphics\"\nmsgstr \"\"\n\n#: ../../app4.rst:90 c8a1f504fd3746ba9397d4e3d6b274a6\nmsgid \"`pandas.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:91 8642835dbf5d4db99a8c4fbca766a571\nmsgid \"10,585,962\"\nmsgstr \"\"\n\n#: ../../app4.rst:92 7b996090e65044c584d83ea7acda42f0\nmsgid \"3,071\"\nmsgstr \"\"\n\n#: ../../app4.rst:93 ff6fdff8d91a417583e2686c79665e97\nmsgid \"536\"\nmsgstr \"\"\n\n#: ../../app4.rst:94 6916626a7d824adfb4b1475a9d0f3eff\nmsgid \"16,554\"\nmsgstr \"\"\n\n#: ../../app4.rst:95 bc0f680837344f68abbb708440827a84\nmsgid \"3\"\nmsgstr \"\"\n\n#: ../../app4.rst:96 bba11b24685d4d8c94deaa5e074e4bcb\nmsgid \"1,539\"\nmsgstr \"\"\n\n#: ../../app4.rst:97 40e65f53ef05490796b7a4aec9577410\nmsgid \"many pages\"\nmsgstr \"\"\n\n#: ../../app4.rst:98 e798c081493c4df095c56e07a50ca1b9\nmsgid \"`pymupdf.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:99 9648e1df46804af395045a08a83de9fe\nmsgid \"6,805,176\"\nmsgstr \"\"\n\n#: ../../app4.rst:100 7f91a57f8a7847b4bd037094e00faa9a\nmsgid \"478\"\nmsgstr \"\"\n\n#: ../../app4.rst:101 226cdbfe630949eab54a52805869a6e7\nmsgid \"276\"\nmsgstr \"\"\n\n#: ../../app4.rst:102 f30b492e535c41748786f54e00e90cb8\nmsgid \"5,277\"\nmsgstr \"\"\n\n#: ../../app4.rst:103 2701b877b410466cb1ae77dd1a2a1e90\nmsgid \"14\"\nmsgstr \"\"\n\n#: ../../app4.rst:104 bcc9d1ef612c4e95b015b553232ad25a\nmsgid \"1,937\"\nmsgstr \"\"\n\n#: ../../app4.rst:105 befe3de8428943f2b55fa3759ae8cbd0\nmsgid \"text oriented\"\nmsgstr \"\"\n\n#: ../../app4.rst:106 1fde26c15a56401eb49e5db71f99cc25\nmsgid \"`pythonbook.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:107 abde300eb8244d23875981f20afdf6ce\nmsgid \"9,983,856\"\nmsgstr \"\"\n\n#: ../../app4.rst:108 f236fb08a1834afeae13579d512733ba\nmsgid \"669\"\nmsgstr \"\"\n\n#: ../../app4.rst:109 d7c1691699514ea893a728c74016301d\nmsgid \"198\"\nmsgstr \"\"\n\n#: ../../app4.rst:110 4af5202a95164d698a13772fb60448a8\nmsgid \"1,953\"\nmsgstr \"\"\n\n#: ../../app4.rst:111 b4141c07d695403e87cedbe5de5863dd\nmsgid \"15\"\nmsgstr \"\"\n\n#: ../../app4.rst:112 72ae61bf2a1b4a52904b806afc0ff6f5\nmsgid \"1,929\"\nmsgstr \"\"\n\n#: ../../app4.rst:114 bb501706366848629a8491cb70e58ec9\nmsgid \"`sample-50-MB-pdf-file.pdf`\"\nmsgstr \"\"\n\n#: ../../app4.rst:115 542f200f9bbd48719bb31d4cf6850f3b\nmsgid \"52,521,850\"\nmsgstr \"\"\n\n#: ../../app4.rst:116 d0db6531af4e488ca48300bebf47246e\nmsgid \"1\"\nmsgstr \"\"\n\n#: ../../app4.rst:119 b80b76ee70584a34977f50acbea06df8\nmsgid \"51,291\"\nmsgstr \"\"\n\n#: ../../app4.rst:120 52119106cfb04a489c5842fab93cd2c5\nmsgid \"23,860\"\nmsgstr \"\"\n\n#: ../../app4.rst:121 513e58b0ccf547edaf2e1b8d4fc09391\nmsgid \"single page, graphics oriented, large file size\"\nmsgstr \"단일 페이지, 그래픽 지향, 큰 파일 크기\"\n\n#: ../../app4.rst:127 b1d1466a4d4f46ee97f9c0c14866930d\nmsgid \"\"\n\"**adobe.pdf** and **pymupdf.pdf** are clearly text oriented, **artifex-\"\n\"website.pdf** and **sample-50-MB-pdf-file.pdf** are graphics oriented. \"\n\"Other files are a mix of both.\"\nmsgstr \"**adobe.pdf** 와 **pymupdf.pdf** 는 명확히 텍스트 지향적이며, **artifex-website.pdf** 와 **sample-50-MB-pdf-file.pdf** 는 그래픽 지향적입니다. 다른 파일들은 둘 다의 혼합입니다.\"\n\n#: ../../app4.rst:131 a46db6b46cbd476c9aa08e828b1899a9\nmsgid \"Tools used\"\nmsgstr \"사용된 도구\"\n\n#: ../../app4.rst:133 eff071706abe45db98dc970ba599955e\nmsgid \"\"\n\"In each section, the same fixed set of |PDF| files is being processed by \"\n\"a set of tools. The set of tools used per performance aspect however \"\n\"varies, depending on the supported tool features.\"\nmsgstr \"각 섹션에서 동일한 고정된 |PDF| 파일 세트가 도구 세트에 의해 처리됩니다. 그러나 성능 측면별로 사용되는 도구 세트는 지원되는 도구 기능에 따라 다릅니다.\"\n\n#: ../../app4.rst:135 e7ff37e32cbd4cdc993c645e7658d227\nmsgid \"\"\n\"All tools are either platform independent, or at least can run on both, \"\n\":title:`Windows` and :title:`Unix` / :title:`Linux`.\"\nmsgstr \"모든 도구는 플랫폼 독립적이거나 최소한 :title:`Windows` 와 :title:`Unix` / :title:`Linux` 모두에서 실행할 수 있습니다.\"\n\n#: ../../app4.rst:141 7507beef7859479e94a8fa9cce614373\nmsgid \"**Tool**\"\nmsgstr \"**도구**\"\n\n#: ../../app4.rst:142 7e5c5082ee244cc1850b389fa76d162b\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../app4.rst:143 ../../app4.rst:172 ../../app4.rst:218 ../../app4.rst:296\n#: ../../app4.rst:368 ../../app4.rst:408 51f2639233354454a2be6c8cf943caae\n#: 75b83e125f444081ac46f5b513ffb434 78511b7a3ae24d7ba242cb9f012c945c\n#: cf82339face445409b1cb2230b1cf737 e2f4e337aa6f46ff9d1a57a84bd40231\n#: ea0496359fd4419f88ac295b9d5a7c35\nmsgid \"|PyMuPDF|\"\nmsgstr \"|PyMuPDF|\"\n\n#: ../../app4.rst:144 265dd2b9a51a4748ae710d0a7781b16c\nmsgid \"The tool of this manual.\"\nmsgstr \"이 매뉴얼의 도구.\"\n\n#: ../../app4.rst:145 0d7018f04c2d4b8b91e09d879a94c489\nmsgid \"PDFrw_\"\nmsgstr \"PDFrw_\"\n\n#: ../../app4.rst:146 1871dfbb59ed44559c1143b8f664ab3b\nmsgid \"\"\n\"A pure :title:`Python` tool, being used by :title:`rst2pdf`, has \"\n\"interface to :title:`ReportLab`.\"\nmsgstr \":title:`rst2pdf` 에서 사용되는 순수 :title:`Python` 도구로, :title:`ReportLab` 에 대한 인터페이스를 가집니다.\"\n\n#: ../../app4.rst:147 db3dc67db0384a4caf25ec3159cc9e8c\nmsgid \"PyPDF2_\"\nmsgstr \"PyPDF2_\"\n\n#: ../../app4.rst:148 f00f0472c11846dd8a6d1cb0ac0237bf\nmsgid \"A pure :title:`Python` tool with a large function set.\"\nmsgstr \"큰 함수 집합을 가진 순수 :title:`Python` 도구.\"\n\n#: ../../app4.rst:149 719bb221eb5b4d34a21a977bfddfa966\nmsgid \"PDFMiner_\"\nmsgstr \"PDFMiner_\"\n\n#: ../../app4.rst:150 7c679bd2a294494c86c754ffaddb5cf3\nmsgid \"A pure :title:`Python` to extract text and other data from |PDF|.\"\nmsgstr \"|PDF| 에서 텍스트 및 기타 데이터를 추출하는 순수 :title:`Python`.\"\n\n#: ../../app4.rst:151 ef3100ff8d5049009f9896ca197346c5\nmsgid \"XPDF_\"\nmsgstr \"XPDF_\"\n\n#: ../../app4.rst:152 89c9c95eccee414e90d74c494ef8fa0c\nmsgid \"A command line utility with multiple functions.\"\nmsgstr \"여러 기능을 가진 명령줄 유틸리티.\"\n\n#: ../../app4.rst:153 3ac8573211c94c1996a3f39372a5c365\nmsgid \"PikePDF_\"\nmsgstr \"PikePDF_\"\n\n#: ../../app4.rst:154 ad269cc30d2f43dbbd44e72f1cfa24e9\nmsgid \"\"\n\"A :title:`Python` package similar to :title:`PDFrw`, but based on \"\n\":title:`C++` library :title:`QPDF`.\"\nmsgstr \":title:`PDFrw` 와 유사한 :title:`Python` 패키지이지만, :title:`C++` 라이브러리 :title:`QPDF` 를 기반으로 합니다.\"\n\n#: ../../app4.rst:155 f7a4dbe832784e9c80a9bec19efd26e4\nmsgid \"PDF2JPG_\"\nmsgstr \"PDF2JPG_\"\n\n#: ../../app4.rst:156 2354f030ddfb48028e2dc5dcdca588bf\nmsgid \"\"\n\"A :title:`Python` package specialized on rendering |PDF| pages to \"\n\":title:`JPG` images.\"\nmsgstr \"|PDF| 페이지를 :title:`JPG` 이미지로 렌더링하는 데 특화된 :title:`Python` 패키지.\"\n\n#: ../../app4.rst:164 20ec5781714e43979415d31bca6e4d91\nmsgid \"Copying / Joining / Merging\"\nmsgstr \"복사 / 결합 / 병합\"\n\n#: ../../app4.rst:166 24e5ae35daf74ce5af40e0c2fc945067\nmsgid \"\"\n\"How fast is a |PDF| file read and its content parsed for further \"\n\"processing? The sheer parsing performance cannot directly be compared, \"\n\"because batch utilities always execute a requested task completely, in \"\n\"one go, front to end. :title:`PDFrw` too, has a *lazy* strategy for \"\n\"parsing, meaning it only parses those parts of a document that are \"\n\"required in any moment.\"\nmsgstr \"|PDF| 파일을 읽고 내용을 추가 처리하기 위해 파싱하는 속도는 얼마나 빠른가? 순수 파싱 성능은 직접 비교할 수 없습니다. 왜냐하면 배치 유틸리티는 항상 요청된 작업을 처음부터 끝까지 한 번에 완전히 실행하기 때문입니다. :title:`PDFrw` 도 *지연* 파싱 전략을 가지며, 이는 언제든지 필요한 문서 부분만 파싱한다는 의미입니다.\"\n\n#: ../../app4.rst:168 9030ee0b64da48c4b6ba3563a6fe7da8\nmsgid \"\"\n\"To find an answer to the question, we therefore measure the time to copy \"\n\"a |PDF| file to an output file with each tool, and do nothing else.\"\nmsgstr \"이 질문에 대한 답을 찾기 위해, 각 도구로 |PDF| 파일을 출력 파일에 복사하는 데 걸리는 시간을 측정하고 다른 작업은 수행하지 않습니다.\"\n\n#: ../../app4.rst:170 ../../app4.rst:365 75c4e9d6b0f94276ad4a46e7ca064b4c\n#: d29245da53b44d4c931cdfd53a686bcb\nmsgid \"These are the :title:`Python` commands for how each tool is used:\"\nmsgstr \"각 도구를 사용하는 방법에 대한 :title:`Python` 명령은 다음과 같습니다:\"\n\n#: ../../app4.rst:180 40554a7aac2c4529a5cea2cb201adc33\nmsgid \":title:`PDFrw`\"\nmsgstr \":title:`PDFrw`\"\n\n#: ../../app4.rst:190 2027a14c030c4dafa9b213b842921038\nmsgid \":title:`PikePDF`\"\nmsgstr \":title:`PikePDF`\"\n\n#: ../../app4.rst:198 0554b1918f0442929d092d7d1aa8c6db\nmsgid \":title:`PyPDF2`\"\nmsgstr \":title:`PyPDF2`\"\n\n#: ../../app4.rst:210 ../../app4.rst:288 ../../app4.rst:399\n#: 0cc77d5085aa42b092a9d28c9f9b93d1 2151ed94f39e42489d9407b0a8ac0ccb\n#: 8e952a6e6d1d46499282ea93f770529c\nmsgid \"**Observations**\"\nmsgstr \"**관찰 결과**\"\n\n#: ../../app4.rst:212 ../../app4.rst:290 ../../app4.rst:401\n#: 190b33a2a1264d58900d557c11876da4 2995f439d6cb495da4b80e31d49c47a7\n#: 536ccc62e0b8415f92d295558b4e0e5b\nmsgid \"\"\n\"These are our run time findings in **seconds** along with a base rate \"\n\"summary compared to |PyMuPDF|:\"\nmsgstr \"다음은 **초** 단위의 실행 시간 결과와 |PyMuPDF| 와 비교한 기준 비율 요약입니다:\"\n\n#: ../../app4.rst:219 a51de26a6852481a8e70a53e96187379\nmsgid \"**PDFrw**\"\nmsgstr \"**PDFrw**\"\n\n#: ../../app4.rst:220 933434ca403749c0a4f630ffec63fbf0\nmsgid \"**PikePDF**\"\nmsgstr \"**PikePDF**\"\n\n#: ../../app4.rst:221 ../../app4.rst:298 93a77920ab2f426481a1d5037c17135f\n#: a5fda08d4d34464ba81569732331f63c\nmsgid \"**PyPDF2**\"\nmsgstr \"**PyPDF2**\"\n\n#: ../../app4.rst:222 ../../app4.rst:300 ../../app4.rst:411\n#: 5544726c03fb43a2afaa6c61866bba6a 5ade818fb72c4831ad8691c9cf811c78\n#: af7a989e3b5144c1a3f9d080bc5aea03\nmsgid \"adobe.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:223 aea85b36f9074c44ac0e480e9feedf9a\nmsgid \"1.75\"\nmsgstr \"\"\n\n#: ../../app4.rst:224 1d5d21531c014823b5bd62db7bc0135e\nmsgid \"5.15\"\nmsgstr \"\"\n\n#: ../../app4.rst:225 29285cb95fbc41c7b91b01dda4181c2d\nmsgid \"22.37\"\nmsgstr \"\"\n\n#: ../../app4.rst:226 68b490eb621f4f4eb992f5e5eb9baff5\nmsgid \"374.05\"\nmsgstr \"\"\n\n#: ../../app4.rst:227 ../../app4.rst:305 ../../app4.rst:415\n#: 00246b4fa6bb413aaecfac538ed32b19 20452d17f0ed4d98ab1d92047ddb55a7\n#: dc633929adc3417d9c90d8be2bf90613\nmsgid \"artifex-website.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:228 3e3d60bb5a06431f8423b7fa72008e45\nmsgid \"0.26\"\nmsgstr \"\"\n\n#: ../../app4.rst:229 ../../app4.rst:243 2ce822ddafa04eacb665dcdd8bb34f25\n#: a0ca8a854b9c428a9257c8dbf52b4590\nmsgid \"0.38\"\nmsgstr \"\"\n\n#: ../../app4.rst:230 63e990f7145f451dac1615b7274b980f\nmsgid \"1.41\"\nmsgstr \"\"\n\n#: ../../app4.rst:231 e5e9ce25649c4a7e87d9cfed1d4c1f0a\nmsgid \"2.81\"\nmsgstr \"\"\n\n#: ../../app4.rst:232 ../../app4.rst:310 ../../app4.rst:419\n#: 1abbb91fd2804bff9cc59d244e834dbe 25ef69a136294635ad82241de488155a\n#: 5c166f9365fb4824bbe295d262a4c695\nmsgid \"db-systems.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:233 dfa580f9d5494073b720002293a6fa82\nmsgid \"0.15\"\nmsgstr \"\"\n\n#: ../../app4.rst:234 0cabf0e69a2e40a8920e44b780f064b6\nmsgid \"0.8\"\nmsgstr \"\"\n\n#: ../../app4.rst:235 1b45bb6fb5384d11863727a44bc772d5\nmsgid \"1.68\"\nmsgstr \"\"\n\n#: ../../app4.rst:236 482704feedf44b168160d5c6bf430e89\nmsgid \"2.46\"\nmsgstr \"\"\n\n#: ../../app4.rst:237 ../../app4.rst:315 ../../app4.rst:423\n#: 28cf3f5a2e644968b1b497d836968533 619f6293468e4a5b9414def4ae968f6a\n#: a54e51785c104643876df4110d7f60fb\nmsgid \"fontforge.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:238 80142473274946b2b76110266168f6d2\nmsgid \"0.09\"\nmsgstr \"\"\n\n#: ../../app4.rst:239 fdeb0d08542549ad94e6f5ff68f639e1\nmsgid \"0.14\"\nmsgstr \"\"\n\n#: ../../app4.rst:240 fa056a25dbc24ce8bbb7206ac25c05ae\nmsgid \"0.28\"\nmsgstr \"\"\n\n#: ../../app4.rst:241 ../../app4.rst:308 4bafecabe76b409d8db8ac377d7f7ea9\n#: 5206ddcbea3c43ab869b569ff3172038\nmsgid \"1.1\"\nmsgstr \"\"\n\n#: ../../app4.rst:242 ../../app4.rst:320 ../../app4.rst:427\n#: 283144343a0949668598a967aab1deef 2bf82f9384f34930a1debf451276e32e\n#: f64eb5e532a04104b1c1491cdd231638\nmsgid \"pandas.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:244 c0f38df2b0cd4082acfb9b25f340902a\nmsgid \"2.21\"\nmsgstr \"\"\n\n#: ../../app4.rst:245 9594837d5d2848c6bd8fc40d23f432db\nmsgid \"2.73\"\nmsgstr \"\"\n\n#: ../../app4.rst:246 d52e2689ad7047df8dcab08a5b7c5417\nmsgid \"70.3\"\nmsgstr \"\"\n\n#: ../../app4.rst:247 ../../app4.rst:325 ../../app4.rst:431\n#: 6adf778936ea4b1bac0e0112c0f3d53a ca7e5c0d37d843a5a058022264ef4838\n#: df12e19f983a4715a95aa5e1c4259037\nmsgid \"pymupdf.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:248 50c706b1c6eb4ba783605c298016ffd9\nmsgid \"0.11\"\nmsgstr \"\"\n\n#: ../../app4.rst:249 e6316c498d704c12a367a5598ce1dfa4\nmsgid \"0.56\"\nmsgstr \"\"\n\n#: ../../app4.rst:250 c9b02d42498945f39b746d182ceef93f\nmsgid \"0.83\"\nmsgstr \"\"\n\n#: ../../app4.rst:251 a866f67188d54c70912cd3e19c35d760\nmsgid \"6.05\"\nmsgstr \"\"\n\n#: ../../app4.rst:252 ../../app4.rst:330 ../../app4.rst:435\n#: 2d6911f21f034fdb99236c6da0e5c8fc ca646d19848a4024b113f84e29e5f016\n#: ddf7610dcd7d4c2085d801cc70dfa46b\nmsgid \"pythonbook.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:253 6f0fe33ac23b4d0baf5009363bc75c5b\nmsgid \"0.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:254 680b3cbd12934d07830711fdf35d8c00\nmsgid \"1.2\"\nmsgstr \"\"\n\n#: ../../app4.rst:255 fbbf220c922f4a53ab16e06f0c5042ee\nmsgid \"1.34\"\nmsgstr \"\"\n\n#: ../../app4.rst:256 e94988b7dbc347c09260a2b8a03dd461\nmsgid \"37.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:257 ../../app4.rst:335 ../../app4.rst:439\n#: a9d4ceb80d2c42e0b7bf4c22de480e63 aa346b20c8c14103ad508c92238ca1a8\n#: b0d041755ac04554a0acc858c79f4516\nmsgid \"sample-50-MB-pdf-file.pdf\"\nmsgstr \"\"\n\n#: ../../app4.rst:258 bcc275d36bf04161834713d6d786e356\nmsgid \"0.12\"\nmsgstr \"\"\n\n#: ../../app4.rst:259 cb526a85171a4e5c924b02fae9f5cff1\nmsgid \"0.1\"\nmsgstr \"\"\n\n#: ../../app4.rst:260 57e608621ccb4404a586b7361b537020\nmsgid \"2.93\"\nmsgstr \"\"\n\n#: ../../app4.rst:261 e280682fa0f048f7bf4a842026ed388c\nmsgid \"0.08\"\nmsgstr \"\"\n\n#: ../../app4.rst:262 ../../app4.rst:340 ../../app4.rst:443\n#: 147889494a0342d39c8d7bc589e777a1 9dde60202b154d62bb5dc5da1b8f3eb4\n#: dcdc53ddede34633afbb78b8cb474780\nmsgid \"**Total**\"\nmsgstr \"**총계**\"\n\n#: ../../app4.rst:263 482ff9ef77514db0a3105d43540c6a79\nmsgid \"**3.05**\"\nmsgstr \"\"\n\n#: ../../app4.rst:264 2f728a892b10493f83a211bbe00dc8c2\nmsgid \"**10.54**\"\nmsgstr \"\"\n\n#: ../../app4.rst:265 8a1310321389468b8eeb7302181de22f\nmsgid \"**33.57**\"\nmsgstr \"\"\n\n#: ../../app4.rst:266 8979d1c755ab4d5480e0e543908439ab\nmsgid \"**494.04**\"\nmsgstr \"\"\n\n#: ../../app4.rst:272 ../../app4.rst:350 ../../app4.rst:451\n#: 39d408ac310b429a9f4630de549c0218 b1cedcb976d7467cb64b4a03e059059f\n#: d60f7ab07be042e9ac4f315656e9d80e\nmsgid \"**Rate compared to PyMuPDF**\"\nmsgstr \"**PyMuPDF 와 비교한 비율**\"\n\n#: ../../app4.rst:273 ../../app4.rst:351 ../../app4.rst:452\n#: 5fe241f7da6f4f1287b2ef598e77e63a a1eabf390faf4118b9fbf1c23bcaa970\n#: ca4532068a8749cebe70ecd680077cff\nmsgid \":green-color:`1.0`\"\nmsgstr \"\"\n\n#: ../../app4.rst:274 4bebef049b2147ec9412439a06413b0c\nmsgid \":orange-color:`3.5`\"\nmsgstr \"\"\n\n#: ../../app4.rst:275 bd4c733cfe544784bfac89860db9068e\nmsgid \":orange-color:`11.0`\"\nmsgstr \"\"\n\n#: ../../app4.rst:276 65a3d5ea7ac842238d61067451bc62b9\nmsgid \":red-color:`162`\"\nmsgstr \"\"\n\n#: ../../app4.rst:283 1cd4fd60fed8493aa0180e6aced6f887\nmsgid \"Text Extraction\"\nmsgstr \"텍스트 추출\"\n\n#: ../../app4.rst:285 43ec059052ef49239504e79c59d48792\nmsgid \"\"\n\"The following table shows plain text extraction durations. All tools have\"\n\" been used with their most basic functionality - i.e. no layout re-\"\n\"arrangements, etc.\"\nmsgstr \"다음 표는 일반 텍스트 추출 기간을 보여줍니다. 모든 도구는 가장 기본적인 기능으로 사용되었습니다 -- 즉, 레이아웃 재배치 등이 없습니다.\"\n\n#: ../../app4.rst:297 ../../app4.rst:409 493d81649a04476aa7e157c8155e8816\n#: c7a4bc884d3e4b39ab49157d277af5e6\nmsgid \"**XPDF**\"\nmsgstr \"**XPDF**\"\n\n#: ../../app4.rst:299 55447e13f7cc43598fde158caf1adfbf\nmsgid \"**PDFMiner**\"\nmsgstr \"**PDFMiner**\"\n\n#: ../../app4.rst:301 71ff39c17b764e46a725f342a082f147\nmsgid \"2.01\"\nmsgstr \"\"\n\n#: ../../app4.rst:302 fce895fddd9544e4b84bbc464bc5d54a\nmsgid \"6.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:303 11d7da5f489c4d5c8f08904e64d58b85\nmsgid \"22.2\"\nmsgstr \"\"\n\n#: ../../app4.rst:304 7a43720209f2409891b79edcb6feebc8\nmsgid \"49.15\"\nmsgstr \"\"\n\n#: ../../app4.rst:306 86da45bd435e4e2fac8f537ac4dc33c6\nmsgid \"0.18\"\nmsgstr \"\"\n\n#: ../../app4.rst:307 9f329e56a13e4944887ba215aadd1c50\nmsgid \"0.3\"\nmsgstr \"\"\n\n#: ../../app4.rst:309 412c97e97e644221bec455efaa9ee865\nmsgid \"4.06\"\nmsgstr \"\"\n\n#: ../../app4.rst:311 3211848a2c7541c4b98431190bc82a51\nmsgid \"1.57\"\nmsgstr \"\"\n\n#: ../../app4.rst:312 7888933412524d77b9710d7c349a6ad8\nmsgid \"4.26\"\nmsgstr \"\"\n\n#: ../../app4.rst:313 78ac7fd7df42471aa6a3ac3bb3b13b4f\nmsgid \"25.75\"\nmsgstr \"\"\n\n#: ../../app4.rst:314 fbda6230814e4005b8c47d862c0364c4\nmsgid \"42.19\"\nmsgstr \"\"\n\n#: ../../app4.rst:316 05c924d4dc1e4feb955b06be14c5e7e7\nmsgid \"0.24\"\nmsgstr \"\"\n\n#: ../../app4.rst:317 eff929019a05485ab7d424571a631738\nmsgid \"0.47\"\nmsgstr \"\"\n\n#: ../../app4.rst:318 d732cff1f2af4741b0cf005af6150933\nmsgid \"2.69\"\nmsgstr \"\"\n\n#: ../../app4.rst:319 d717cab56bbc403fa2d497180e09afac\nmsgid \"4.2\"\nmsgstr \"\"\n\n#: ../../app4.rst:321 6f2bb2d646834a28b637393c83fbe756\nmsgid \"2.41\"\nmsgstr \"\"\n\n#: ../../app4.rst:322 297e3c2d5f354ca6a5f331312ada2eb9\nmsgid \"10.54\"\nmsgstr \"\"\n\n#: ../../app4.rst:323 e7aaee8a7d6d46738acd6d36fd3a1a2b\nmsgid \"25.38\"\nmsgstr \"\"\n\n#: ../../app4.rst:324 22691134bd124353bac936a15dc23c7d\nmsgid \"76.56\"\nmsgstr \"\"\n\n#: ../../app4.rst:326 beb7e60f87f44b00941524176f83234b\nmsgid \"0.49\"\nmsgstr \"\"\n\n#: ../../app4.rst:327 f1987f898ec44e2eae7731378a36d310\nmsgid \"2.34\"\nmsgstr \"\"\n\n#: ../../app4.rst:328 ef61cf5a5cb042fdbb4db7ffb338d866\nmsgid \"6.44\"\nmsgstr \"\"\n\n#: ../../app4.rst:329 22b1b07b84d542088f18ea5fb77ba24f\nmsgid \"13.55\"\nmsgstr \"\"\n\n#: ../../app4.rst:331 0832e852468f492a9ecffee3998af4f2\nmsgid \"0.84\"\nmsgstr \"\"\n\n#: ../../app4.rst:332 3a29ccef7ff44af0bbc12374a5983e38\nmsgid \"2.88\"\nmsgstr \"\"\n\n#: ../../app4.rst:333 be833e3e8322409ba592cc7891bfd260\nmsgid \"9.28\"\nmsgstr \"\"\n\n#: ../../app4.rst:334 fb41a43110744ce98af7eee58740fb05\nmsgid \"24.27\"\nmsgstr \"\"\n\n#: ../../app4.rst:336 81ca0ec15e384df3998d921f54470058\nmsgid \"0.27\"\nmsgstr \"\"\n\n#: ../../app4.rst:337 fe5e6af169c04db999c3003913c8ad6e\nmsgid \"0.44\"\nmsgstr \"\"\n\n#: ../../app4.rst:338 9220f3fa950e47009211a9f69d405117\nmsgid \"8.8\"\nmsgstr \"\"\n\n#: ../../app4.rst:339 a9338bdb413148689255f70fbeead632\nmsgid \"13.29\"\nmsgstr \"\"\n\n#: ../../app4.rst:341 978aa50a4e73446ca6444f7911b99137\nmsgid \"**8.01**\"\nmsgstr \"\"\n\n#: ../../app4.rst:342 c80a0bb069c644938e92b9da92483efa\nmsgid \"**27.42**\"\nmsgstr \"\"\n\n#: ../../app4.rst:343 3aff3e7279a74a2b90e22e23593c2795\nmsgid \"**101.64**\"\nmsgstr \"\"\n\n#: ../../app4.rst:344 4fe0e88c92fd44c7af9bc827ce45422c\nmsgid \"**227.27**\"\nmsgstr \"\"\n\n#: ../../app4.rst:352 63cc33b2658d4c45b2ba8cbe943bd222\nmsgid \":orange-color:`3.42`\"\nmsgstr \"\"\n\n#: ../../app4.rst:353 0533ece4f3e14f7c96cb711e9d3b3fbf\nmsgid \":orange-color:`12.69`\"\nmsgstr \"\"\n\n#: ../../app4.rst:354 1a614a3651e448a9911ab3eedaac4d42\nmsgid \":red-color:`28.37`\"\nmsgstr \"\"\n\n#: ../../app4.rst:360 00b592ac57f64130a8654c00830f154e\nmsgid \"Page Rendering\"\nmsgstr \"페이지 렌더링\"\n\n#: ../../app4.rst:362 f5119aaf183e4f4eb483e9c337c88488\nmsgid \"\"\n\"We have tested rendering speed of |PyMuPDF| against :title:`pdf2jpg` and \"\n\":title:`XPDF` at a resolution of 150 DPI,\"\nmsgstr \"150 DPI 해상도에서 :title:`pdf2jpg` 및 :title:`XPDF` 와 비교하여 |PyMuPDF| 의 렌더링 속도를 테스트했습니다,\"\n\n#: ../../app4.rst:382 02cf04dabcd44b9998f6e4e25bbca5ee\nmsgid \":title:`XPDF`\"\nmsgstr \":title:`XPDF`\"\n\n#: ../../app4.rst:389 90770272b10c416e84826a42e1c212cc\nmsgid \":title:`PDF2JPG`\"\nmsgstr \":title:`PDF2JPG`\"\n\n#: ../../app4.rst:410 c717d43cc70e48e98e87edcf403d8b03\nmsgid \"**PDF2JPG**\"\nmsgstr \"**PDF2JPG**\"\n\n#: ../../app4.rst:412 da606418caee4a099a285d88fdee4bcb\nmsgid \"51.33\"\nmsgstr \"\"\n\n#: ../../app4.rst:413 d42b2bb121b54a939a97fd7c82e60632\nmsgid \"98.16\"\nmsgstr \"\"\n\n#: ../../app4.rst:414 97e1e5c516654f909a445d6158df2fef\nmsgid \"75.71\"\nmsgstr \"\"\n\n#: ../../app4.rst:416 c1a00e6812494e27a1e5513c5dcb6515\nmsgid \"26.35\"\nmsgstr \"\"\n\n#: ../../app4.rst:417 525f071275c846daaccf5b9ad9472c35\nmsgid \"51.28\"\nmsgstr \"\"\n\n#: ../../app4.rst:418 dab5c30a6ab14679837b7c79be1baef5\nmsgid \"54.11\"\nmsgstr \"\"\n\n#: ../../app4.rst:420 6347c08651eb4dfc963827edfe3c2dfa\nmsgid \"84.59\"\nmsgstr \"\"\n\n#: ../../app4.rst:421 9ff9e6ea2bff413e96b7948a6cdd6c2d\nmsgid \"143.16\"\nmsgstr \"\"\n\n#: ../../app4.rst:422 088e57b2eec94b3bbbf1258987f8c664\nmsgid \"405.22\"\nmsgstr \"\"\n\n#: ../../app4.rst:424 b3cf9ee794b34bad8b6dbfe411512b74\nmsgid \"12.23\"\nmsgstr \"\"\n\n#: ../../app4.rst:425 d51b92890c7442579c00adf23e97f279\nmsgid \"22.18\"\nmsgstr \"\"\n\n#: ../../app4.rst:426 3f7b41851cdf4ca493af2c869d25b055\nmsgid \"20.14\"\nmsgstr \"\"\n\n#: ../../app4.rst:428 226831c9dbf7408f9116226b0776dff5\nmsgid \"138.74\"\nmsgstr \"\"\n\n#: ../../app4.rst:429 c0ff7f066efe4586859fcd60916d8201\nmsgid \"241.67\"\nmsgstr \"\"\n\n#: ../../app4.rst:430 c348dd9ee91b448aad5e075ccac79cbc\nmsgid \"202.06\"\nmsgstr \"\"\n\n#: ../../app4.rst:432 5ac66403bf9a49aead460327d7c44f45\nmsgid \"22.35\"\nmsgstr \"\"\n\n#: ../../app4.rst:433 9173e53f1f69448a83d553ded32bb807\nmsgid \"39.11\"\nmsgstr \"\"\n\n#: ../../app4.rst:434 89611809173d45ae8ac3a4f7089ee725\nmsgid \"33.38\"\nmsgstr \"\"\n\n#: ../../app4.rst:436 533943d891b74af491898743b80b7be3\nmsgid \"30.44\"\nmsgstr \"\"\n\n#: ../../app4.rst:437 940113c92ada4f3fabf8932a0ec143e4\nmsgid \"49.12\"\nmsgstr \"\"\n\n#: ../../app4.rst:438 0698ab345b994705a75ccfaddd9670fa\nmsgid \"55.68\"\nmsgstr \"\"\n\n#: ../../app4.rst:440 022d36dd2a304fca9d994fd8aebb4229\nmsgid \"1.01\"\nmsgstr \"\"\n\n#: ../../app4.rst:441 fb7736a3bc7c4ca29f4fce61faf4b788\nmsgid \"1.32\"\nmsgstr \"\"\n\n#: ../../app4.rst:442 dabe4ab239f1407f95b68ad8269a33af\nmsgid \"5.22\"\nmsgstr \"\"\n\n#: ../../app4.rst:444 23819f93562342a8b546fc017760f1c2\nmsgid \"**367.04**\"\nmsgstr \"\"\n\n#: ../../app4.rst:445 1616c1fe2bca4ff2a048b9308c0f246e\nmsgid \"**646**\"\nmsgstr \"\"\n\n#: ../../app4.rst:446 5bdba98414414ff8ac81e89e0e221e71\nmsgid \"**851.52**\"\nmsgstr \"\"\n\n#: ../../app4.rst:453 d581d4e1ac754c2b9e0172b86aeb3edf\nmsgid \":orange-color:`1.76`\"\nmsgstr \"\"\n\n#: ../../app4.rst:454 5a2a9f45f5b14d398c5c1891f3ed968c\nmsgid \":red-color:`2.32`\"\nmsgstr \"\"\n\n#: ../../footer.rst:46 6f6b539ff34a4640ab8af9e5deaeacb0\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/archive-class.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7172941a6af740c8a8c939eeb12aab6f\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 7f24f6f0cd5c48f7b5ef12886e7d3dc2\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 2ce7ac460eea4d7fa274674358f58cb3\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../archive-class.rst:7 4da66911f34043f4b535f63a47cba447\nmsgid \"Archive\"\nmsgstr \"Archive (아카이브)\"\n\n#: ../../archive-class.rst:9 1dbbb103178b492a8c9bf5b05d021272\nmsgid \"New in v1.21.0\"\nmsgstr \"v1.21.0에서 새로 추가됨\"\n\n#: ../../archive-class.rst:11 1e7ee6091313470abe0dcc5c8168a504\nmsgid \"\"\n\"This class represents a generalization of file folders and container \"\n\"files like ZIP and TAR archives. Archives allow accessing arbitrary \"\n\"collections of file folders, ZIP / TAR files and single binary data \"\n\"elements as if they all were part of one hierarchical tree of folders.\"\nmsgstr \"이 클래스는 ZIP 및 TAR 아카이브와 같은 파일 폴더 및 컨테이너 파일의 일반화를 나타냅니다. 아카이브는 파일 폴더, ZIP/TAR 파일 및 단일 바이너리 데이터 요소의 임의 컬렉션에 접근할 수 있게 하며, 모두 하나의 계층적 폴더 트리의 일부인 것처럼 처리합니다.\"\n\n#: ../../archive-class.rst:13 bc799244f4a54577b1ab6043ddcef969\nmsgid \"\"\n\"In PyMuPDF, archives are currently only used by :ref:`Story` objects to \"\n\"specify where to look for fonts, images and other resources.\"\nmsgstr \"|PyMuPDF| 에서 아카이브는 현재 :ref:`Story` 객체에서만 사용되며, 글꼴, 이미지 및 기타 리소스를 찾을 위치를 지정합니다.\"\n\n#: ../../archive-class.rst:16 733307d2ac0c48d5943722db88b66ca3\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../archive-class.rst:16 067a02c3d0eb402e87db2ab8a79cec6a\nmsgid \"**Short Description**\"\nmsgstr \"**간략 설명**\"\n\n#: ../../archive-class.rst:18 917e00b33c264053b763260480ae3cb0\nmsgid \":meth:`Archive.add`\"\nmsgstr \":meth:`Archive.add`\"\n\n#: ../../archive-class.rst:18 5758685d282946d0b76452d8a3d35bf1\nmsgid \"add new data to the archive\"\nmsgstr \"아카이브에 새 데이터 추가\"\n\n#: ../../archive-class.rst:19 96e83a97ca3a4e0d99f2eba9b8dd862c\nmsgid \":meth:`Archive.has_entry`\"\nmsgstr \":meth:`Archive.has_entry`\"\n\n#: ../../archive-class.rst:19 e29b1efc996f43298b3e2c9fd91522a4\nmsgid \"check if given name is a member\"\nmsgstr \"주어진 이름이 멤버인지 확인\"\n\n#: ../../archive-class.rst:20 7e3fbbcec68b4db0b0e06433c33177c1\nmsgid \":meth:`Archive.read_entry`\"\nmsgstr \":meth:`Archive.read_entry`\"\n\n#: ../../archive-class.rst:20 4cbe9ceb4c8744f69ad9da999cf33862\nmsgid \"read the data given by the name\"\nmsgstr \"이름으로 지정된 데이터 읽기\"\n\n#: ../../archive-class.rst:21 40716b5223004d5ba100ffb57f39be5a\nmsgid \":attr:`Archive.entry_list`\"\nmsgstr \":attr:`Archive.entry_list`\"\n\n#: ../../archive-class.rst:21 c6a15b6d228b4c37a9d06697f7992694\nmsgid \"list[dict] of archive items\"\nmsgstr \"아카이브 항목의 list[dict]\"\n\n#: ../../archive-class.rst:24 d96c6d9573704987968f177a3bf7a3ad\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../archive-class.rst:30 d4ac6bed829f43429a56efde53217fce\nmsgid \"Creates a new archive. Without parameters, an empty archive is created.\"\nmsgstr \"새 아카이브를 생성합니다. 매개변수가 없으면 빈 아카이브가 생성됩니다.\"\n\n#: ../../archive-class.rst:32 ce56c558cdfd467bb88c2e5a14edbc06\nmsgid \"If provided, `content` may be one of the following:\"\nmsgstr \"제공되는 경우 `content` 는 다음 중 하나일 수 있습니다:\"\n\n#: ../../archive-class.rst:34 b4730a481ea84967b6cb58ae9fe5ba6e\nmsgid \"another Archive: the archive is being made a sub-archive of the new one.\"\nmsgstr \"다른 Archive: 아카이브가 새 아카이브의 하위 아카이브가 됩니다.\"\n\n#: ../../archive-class.rst:36 5b42f6018b314dbca0ec8d6039baf4d7\nmsgid \"\"\n\"a string: this must be the name of a local folder or file. `pathlib.Path`\"\n\" objects are also supported.\"\nmsgstr \"문자열: 로컬 폴더 또는 파일의 이름이어야 합니다. `pathlib.Path` 객체도 지원됩니다.\"\n\n#: ../../archive-class.rst:38 619d605a712947c2a548c8e110f21c7d\nmsgid \"\"\n\"A **folder** will be converted to a sub-archive, so its files (and any \"\n\"sub-folders) can be accessed by their names.\"\nmsgstr \"**폴더** 는 하위 아카이브로 변환되므로 파일(및 모든 하위 폴더)을 이름으로 접근할 수 있습니다.\"\n\n#: ../../archive-class.rst:39 4cd647737643458d9e392abbb2da302c\nmsgid \"\"\n\"A **file** will be read with mode `\\\"rb\\\"` and these binary data (a \"\n\"`bytes` object) be treated as a single-member sub-archive. In this case, \"\n\"the `path` parameter is **mandatory** and should be the member name under\"\n\" which this item can be found / retrieved.\"\nmsgstr \"**파일** 은 `\\\"rb\\\"` 모드로 읽히며 이 바이너리 데이터(`bytes` 객체)는 단일 멤버 하위 아카이브로 처리됩니다. 이 경우 `path` 매개변수는 **필수** 이며 이 항목을 찾거나 검색할 수 있는 멤버 이름이어야 합니다.\"\n\n#: ../../archive-class.rst:41 6b1e54d53ee048bebe0aa7b13aa24963\nmsgid \"\"\n\"a `zipfile.ZipFile` or `tarfile.TarFile` object: Will be added as a sub-\"\n\"archive.\"\nmsgstr \"`zipfile.ZipFile` 또는 `tarfile.TarFile` 객체: 하위 아카이브로 추가됩니다.\"\n\n#: ../../archive-class.rst:43 3e15f440e05843dc80023b21dca6c101\nmsgid \"\"\n\"a Python binary object (`bytes`, `bytearray`, `io.BytesIO`): this will \"\n\"add a single-member sub-archive. In this case, the `path` parameter is \"\n\"**mandatory** and should be the member name under which this item can be \"\n\"found / retrieved.\"\nmsgstr \"Python 바이너리 객체(`bytes`, `bytearray`, `io.BytesIO`): 단일 멤버 하위 아카이브를 추가합니다. 이 경우 `path` 매개변수는 **필수** 이며 이 항목을 찾거나 검색할 수 있는 멤버 이름이어야 합니다.\"\n\n#: ../../archive-class.rst:45 0d17f917bfaf4703827752f14540c1b0\nmsgid \"\"\n\"a tuple `(data, name)`: This will add a single-member sub-archive with \"\n\"the member name ``name``. ``data`` may be a Python binary object or a \"\n\"local file name (in which case its binary file content is used). Use this\"\n\" format if you need to specify `path`.\"\nmsgstr \"튜플 `(data, name)`: 멤버 이름 ``name`` 을 가진 단일 멤버 하위 아카이브를 추가합니다. ``data`` 는 Python 바이너리 객체이거나 로컬 파일 이름일 수 있습니다(이 경우 바이너리 파일 내용이 사용됨). `path` 를 지정해야 하는 경우 이 형식을 사용하세요.\"\n\n#: ../../archive-class.rst:47 1597cdc3f8254638bf2cdf9bc2309574\nmsgid \"\"\n\"a Python sequence: This is a convenience format to specify any \"\n\"combination of the above.\"\nmsgstr \"Python 시퀀스: 위 항목의 임의 조합을 지정하는 편의 형식입니다.\"\n\n#: ../../archive-class.rst:49 4988de212ed54833a49be91d2d82d21d\nmsgid \"If provided, `path` must be a string.\"\nmsgstr \"제공되는 경우 `path` 는 문자열이어야 합니다.\"\n\n#: ../../archive-class.rst:51 f90f1ba75dbd4b94be663d3d1a03ce47\nmsgid \"\"\n\"If `content` is either binary data or a file name, this parameter is \"\n\"mandatory and must be the name under which the data can be found.\"\nmsgstr \"`content` 가 바이너리 데이터이거나 파일 이름인 경우 이 매개변수는 필수이며 데이터를 찾을 수 있는 이름이어야 합니다.\"\n\n#: ../../archive-class.rst:53 2b3e0332d6b34ab1ad0dd16b095eadfe\nmsgid \"\"\n\"Otherwise this parameter is optional. It can be used to simulate a folder\"\n\" name or a mount point, under which this sub-archive's elements can be \"\n\"found. For example this specification `Archive((data, \\\"name\\\"), \"\n\"\\\"path\\\")` means that `data` will be found using the element name \"\n\"`\\\"path/name\\\"`. Similar is true for other sub-archives: to retrieve \"\n\"members of a ZIP sub-archive, their names must be prefixed with \"\n\"`\\\"path/\\\"`. The main purpose of this parameter probably is to \"\n\"differentiate between duplicate names.\"\nmsgstr \"그렇지 않으면 이 매개변수는 선택 사항입니다. 폴더 이름이나 마운트 포인트를 시뮬레이션하는 데 사용할 수 있으며, 이 하위 아카이브의 요소를 찾을 수 있습니다. 예를 들어 이 사양 `Archive((data, \\\"name\\\"), \\\"path\\\")` 는 `data` 가 요소 이름 `\\\"path/name\\\"` 을 사용하여 찾을 수 있음을 의미합니다. 다른 하위 아카이브도 마찬가지입니다: ZIP 하위 아카이브의 멤버를 검색하려면 이름에 `\\\"path/\\\"` 접두사가 있어야 합니다. 이 매개변수의 주요 목적은 아마도 중복 이름을 구분하는 것입니다.\"\n\n#: ../../archive-class.rst:55 5faa270a9a8e4b1e9cb54ca0b81bec9e\nmsgid \"\"\n\"If duplicate entry names exist in the archive, always the last entry with\"\n\" that name will be found / retrieved. During archive creation, or \"\n\"appending more data to an archive (see :meth:`Archive.add`) no check for \"\n\"duplicates will be made. Use the `path` parameter to prevent this from \"\n\"happening.\"\nmsgstr \"아카이브에 중복 항목 이름이 존재하는 경우 항상 해당 이름의 마지막 항목이 찾아지거나 검색됩니다. 아카이브 생성 중 또는 아카이브에 더 많은 데이터를 추가하는 동안(:meth:`Archive.add` 참조) 중복 확인이 수행되지 않습니다. 이를 방지하려면 `path` 매개변수를 사용하세요.\"\n\n#: ../../archive-class.rst:59 8f8691f33cb24edf8cf015488e88618a\nmsgid \"\"\n\"Append a sub-archive. The meaning of the parameters are exactly the same \"\n\"as explained above. Of course, parameter `content` is not optional here.\"\nmsgstr \"하위 아카이브를 추가합니다. 매개변수의 의미는 위에서 설명한 것과 정확히 같습니다. 물론 여기서는 `content` 매개변수가 선택 사항이 아닙니다.\"\n\n#: ../../archive-class.rst:63 d7d9c4ee5eb44c0b95fe42f32102c97a\nmsgid \"Checks whether an entry exists in any of the sub-archives.\"\nmsgstr \"항목이 하위 아카이브 중 하나에 존재하는지 확인합니다.\"\n\n#: ../../archive-class.rst 5f8828ec2f374296878d56b8bda07845\n#: 8a109a840a9f48f69f8ad6d589cd57ea\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../archive-class.rst:65 ../../archive-class.rst:73\n#: 9a6f2dbd567f43d2bfe08e06091dcabb ed415071f9ec4041bffb1dcf6075f18d\nmsgid \"\"\n\"The fully qualified name of the entry. So must include any `path` prefix \"\n\"under which the entry's sub-archive has been added.\"\nmsgstr \"항목의 정규화된 이름. 항목의 하위 아카이브가 추가된 `path` 접두사를 포함해야 합니다.\"\n\n#: ../../archive-class.rst 77dc263426c34dc88d2d354f2137f0bd\n#: d7ec8d61f7784b09a3583b2731f89a03\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../archive-class.rst:67 82d8554eda284d14be8c15dcd79fb3ca\nmsgid \"`True` or `False`.\"\nmsgstr \"`True` 또는 `False`.\"\n\n#: ../../archive-class.rst:71 a873f11522bd47f09f770c162ec439ca\nmsgid \"Retrieve the data of an entry.\"\nmsgstr \"항목의 데이터를 검색합니다.\"\n\n#: ../../archive-class.rst:75 1dcd801a861448d2bc31a0ae9ab2b9ca\nmsgid \"\"\n\"The binary data (`bytes`) of the entry. If not found, an exception is \"\n\"raised.\"\nmsgstr \"항목의 바이너리 데이터(`bytes`). 찾을 수 없으면 예외가 발생합니다.\"\n\n#: ../../archive-class.rst:79 7e31c0d4b2874e7aa8dd5ae7daa91341\nmsgid \"\"\n\"A list of the archive's sub-archives. Each list item is a dictionary with\"\n\" the following keys:\"\nmsgstr \"아카이브의 하위 아카이브 목록. 각 목록 항목은 다음 키를 가진 딕셔너리입니다:\"\n\n#: ../../archive-class.rst:81 dc6567d9e6a4485690cf0a5f6fb09b30\nmsgid \"`entries` -- a list of (top-level) entry names in this sub-archive.\"\nmsgstr \"`entries` -- 이 하위 아카이브의 (최상위) 항목 이름 목록.\"\n\n#: ../../archive-class.rst:82 78d2dbe9caeb4e6b9ae6de4d14d95e52\nmsgid \"\"\n\"`fmt` -- the format of the sub-archive. This is one of the strings \"\n\"\\\"dir\\\" (file folder), \\\"zip\\\" (ZIP archive), \\\"tar\\\" (TAR archive), or \"\n\"\\\"tree\\\" for single binary entries or file content.\"\nmsgstr \"`fmt` -- 하위 아카이브의 형식. 문자열 \\\"dir\\\"(파일 폴더), \\\"zip\\\"(ZIP 아카이브), \\\"tar\\\"(TAR 아카이브) 또는 단일 바이너리 항목이나 파일 내용의 경우 \\\"tree\\\" 중 하나입니다.\"\n\n#: ../../archive-class.rst:83 8934885694024d44ac1f04c95acb8fae\nmsgid \"\"\n\"`path` -- the value of the `path` parameter under which this sub-archive \"\n\"was added.\"\nmsgstr \"`path` -- 이 하위 아카이브가 추가된 `path` 매개변수의 값.\"\n\n#: ../../archive-class.rst:85 9bd80fbd40594e6da4b7541250d79442\nmsgid \"**Example:**\"\nmsgstr \"**예제:**\"\n\n#: ../../footer.rst:46 23b6293c2dc24cbd87c6de2cd2f05c0c\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/changes.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 22:25+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 9ffb1f48b2494df7b48540af9ba555e5\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 f4528acfe03f4323a54be4f8f1c27047\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| (및 기타) 문서의 데이터 추출, 분석, 변환 및 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 f2a88f7cde9b4e52a457ae00f4060abc\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../../changes.txt:2 4cd69e5be9794686a140129e41fc4b95\nmsgid \"Change Log\"\nmsgstr \"\"\n\n#: ../../../changes.txt:5 1505d60909e543b7809db6369fa0db8f\nmsgid \"**Changes in version 1.26.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:7 ../../../changes.txt:43 ../../../changes.txt:73\n#: ../../../changes.txt:95 ../../../changes.txt:117 ../../../changes.txt:146\n#: ../../../changes.txt:171 ../../../changes.txt:192 ../../../changes.txt:212\n#: ../../../changes.txt:236 ../../../changes.txt:285 ../../../changes.txt:335\n#: ../../../changes.txt:366 ../../../changes.txt:387 ../../../changes.txt:423\n#: ../../../changes.txt:443 ../../../changes.txt:457 ../../../changes.txt:485\n#: ../../../changes.txt:507 ../../../changes.txt:530 ../../../changes.txt:556\n#: ../../../changes.txt:589 ../../../changes.txt:611 ../../../changes.txt:625\n#: ../../../changes.txt:642 ../../../changes.txt:664 ../../../changes.txt:673\n#: ../../../changes.txt:686 ../../../changes.txt:698 ../../../changes.txt:715\n#: ../../../changes.txt:728 ../../../changes.txt:741 ../../../changes.txt:754\n#: ../../../changes.txt:766 ../../../changes.txt:778 ../../../changes.txt:801\n#: ../../../changes.txt:833 ../../../changes.txt:859 ../../../changes.txt:899\n#: ../../../changes.txt:926 ../../../changes.txt:948 ../../../changes.txt:1200\n#: ../../../changes.txt:1334 049a26e13bb94229a79a69f81f7b5fbe\n#: 1f22271ed0b840efae8df95b0ee00fae 223eca2249444ff9ab2190c5225660fc\n#: 287da62560f74d3dab59fced5784a79f 289b8aaf54c746ecad54ca30175d6572\n#: 2a7d7c2ae08a4078a26a35d98478462f 2d7b554ad4614d72aa34334544b1ad84\n#: 3b0c2a7d2f02465d8a435c84b848e950 41d0c2d1b9dc4b92aaee342c76e8f6aa\n#: 4347b8c87fab492bb324cd690a0a5039 45a493f9bbb34d5d86014fc796fc7e5f\n#: 4ac9e175442d4fed9094777114001d05 5294b3baa70340d4b0683ea893cb8227\n#: 55180f0a4ad14d779385728b45523412 56b9abeb67244e568154b0999908dc54\n#: 590720763c4f4b6e944a5b6e9261c46a 5b96e63e430649e09364197f6640d348\n#: 66a4fb9f871646b39fd2935322ff2bd7 681b44b2d00a428f95bec75570a9bd96\n#: 6d3500e7906d4b5b9d5a852686c41f03 77caed4c8cf543c284393db2214dc425\n#: 7930c830c16148e18e377994a974f7f6 8020c55d92a04b68b29f9b5c839563d9\n#: 8dd9e915003d41dbbf42283bf55adefe 959e7f541c2147928cc800dcf3f54fa8\n#: 980c2a259af24fc599c154fab471a6d4 9eeadae797794ba39efcdfe7dd30ea96\n#: a1f33ce2da084e65927b1037ec5431c9 a5748cc98e13464f8d5833fb09a584c6\n#: b003035ab22a486d8191c52df2f18d51 b1ac215bbe134f3e83fc2c3f1315274d\n#: b322fd43be9f42fcb134129f551f03d7 b8505854ea4346dca195196c3c729c8e\n#: baa47c681a164ab190fd710ab752c1e5 be5cdf51439747e9856bf7da70502394\n#: c18708d565ec49bb9b6597c6e4746708 cbe526883f0a481b9e4b1e4727d250df\n#: d23ff8de34d7483c8f2da67985f1837a e53406c760874e3fba6776cc13ce71c4\n#: ea5c09729ad243d1b44e29edb73a3242 f176ccdd28d44b75bfd267fa28648397\n#: f325e778302b4997b940c6c03dc96ae8 fab1e85d6fcb480fba201316c8c6be02\nmsgid \"Other:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:9 eef8efb3b6884f43ada21c5e779231cb\nmsgid \"\"\n\"Retrospectively mark `4756 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4756>`_ as fixed in 1.26.6.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:10 64ed70e9271b4853b276b73970b50572\nmsgid \"\"\n\"Improved safety of `pymupdf embed-extract`. This now refuses to write to \"\n\"an existing file or outside current directory, unless `-output` or new \"\n\"flag `-unsafe` is specified.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:15 f3d0c45b85df4b2e8952e6a2da3389b7\nmsgid \"**Changes in version 1.26.6** (2025-11-05)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:17 f42bfa1ba64243c3bbb367df56f3ac08\nmsgid \"Use MuPDF-1.26.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:19 50c8518a04f0461d92243888e708323a\nmsgid \"Supported Python versions are now 3.10-3.14.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:21 ../../../changes.txt:35 ../../../changes.txt:59\n#: ../../../changes.txt:87 ../../../changes.txt:110 ../../../changes.txt:132\n#: ../../../changes.txt:164 ../../../changes.txt:183 ../../../changes.txt:203\n#: ../../../changes.txt:226 ../../../changes.txt:249 ../../../changes.txt:259\n#: ../../../changes.txt:274 ../../../changes.txt:294 ../../../changes.txt:304\n#: ../../../changes.txt:321 ../../../changes.txt:347 ../../../changes.txt:380\n#: ../../../changes.txt:396 ../../../changes.txt:406 ../../../changes.txt:438\n#: ../../../changes.txt:475 ../../../changes.txt:502 ../../../changes.txt:524\n#: ../../../changes.txt:541 ../../../changes.txt:584 ../../../changes.txt:605\n#: ../../../changes.txt:619 ../../../changes.txt:632 ../../../changes.txt:658\n#: ../../../changes.txt:671 07987b0a21a147d98b3290a64ffa8043\n#: 1f57395ac4ea4c218653cd455c477ae4 21d647e365934565aea69ef24f0cd8f9\n#: 262f48050967468c829ffe26a450be4b 4cef11a8719641dbb922f8aa1573a9c6\n#: 4e96e411a9d04f3394926ff7a164019f 4f462e8fc6bf487c991f26164fb54c0f\n#: 502470bd29ee4a5f910f9b6c271e6371 5fac41e37738489fa8375e221307b3be\n#: 7d9274f30a6d48e080212ec423122787 7fb6e1f0f0a04c768954b3b7aa03e2f1\n#: 8b358fae935541dd89ec020f9bdb1b41 8dbc5997591e480a88aef01fc75581db\n#: 94c9d89ad8d543cb833db162ba31fde4 9b23f29736354e1d8ed1668fd1f388bf\n#: 9e14b9596afa45b3a83e357fbda360af a2ea1d3f01d945e0b1771aa1b29caa0c\n#: a53b73a9f82648878f41f1760093e351 ad004edc4dba484fadde2289418127fe\n#: b70bd970a9944857a416f7ca0c9b1c6b bbd89b8b6e3544ab875a3a6e44ebe68d\n#: c08f485ce1c34a11ba134e40626b051f d727b39943064157a040eb5ba843fe41\n#: d855c86985754c219d04723faa8e0b48 db0403d789674d7aae95b0d2af2dd802\n#: e0509078460b456b924d980a899d39ea e182efb4eac34ad8bac7dece1504bf23\n#: e2459e41e6d84b248942175137234803 e9129fdd854d4510beb02b78caf662e2\n#: f752594e63ac42a1bc09a307033985cb f9a85782009445d9b72155a12a8ec8ed\nmsgid \"Fixed issues:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:23 ae92f1fe5caf4bf1b49a2d9b55379d9c\nmsgid \"\"\n\"**Fixed** `4699 <https://github.com/pymupdf/PyMuPDF/issues/4699>`_: \"\n\"cannot find ExtGState resource\"\nmsgstr \"\"\n\n#: ../../../changes.txt:24 22f8d06dd888459aa4f9fe1120d92dc8\nmsgid \"\"\n\"**Fixed** `4712 <https://github.com/pymupdf/PyMuPDF/issues/4712>`_: Crash\"\n\" with \\\"corrupted double-linked list\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:25 ccf146dfc96a47d3bab7d6102699c73d\nmsgid \"\"\n\"**Fixed** `4720 <https://github.com/pymupdf/PyMuPDF/issues/4720>`_: \"\n\"Memory leaking in rewrite_images?\"\nmsgstr \"\"\n\n#: ../../../changes.txt:26 0f08a4cb18fe493ca72344c67c165f1d\nmsgid \"\"\n\"**Fixed** `4742 <https://github.com/pymupdf/PyMuPDF/issues/4742>`_: \"\n\"'Rect' object has no attribute 'get_area'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:27 e4563a3e5c574da8970663d208888aa7\nmsgid \"\"\n\"**Fixed** `4746 <https://github.com/pymupdf/PyMuPDF/issues/4746>`_: \"\n\"Document.__init__() got an unexpected keyword argument 'encoding'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:28 2b1ad6590a63426bb7c3dc1b135aaf86\nmsgid \"\"\n\"**Fixed** `4756 <https://github.com/pymupdf/PyMuPDF/issues/4756>`_: swig \"\n\"--version doesn't work in all versions of swig; -version should be used \"\n\"instead\"\nmsgstr \"\"\n\n#: ../../../changes.txt:31 f4b0a46bedf54bc695a3074e319c3da7\nmsgid \"**Changes in version 1.26.5** (2025-10-10)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:33 25fffdf714bf48d695db8e6ab1a28c67\nmsgid \"Use MuPDF-1.26.10.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:37 c88a8d28e397405f93d8379d00535d27\nmsgid \"\"\n\"**Fixed** `2883 <https://github.com/pymupdf/PyMuPDF/issues/2883>`_: \"\n\"Improve the Python type annotations for fitz_new\"\nmsgstr \"\"\n\n#: ../../../changes.txt:38 df91056120a24c1caa9c0b77f3fb1984\nmsgid \"\"\n\"**Fixed** `4507 <https://github.com/pymupdf/PyMuPDF/issues/4507>`_: Bugs \"\n\"in pyodide\"\nmsgstr \"\"\n\n#: ../../../changes.txt:39 70703777c2fa401bbc683f91ad94d06f\nmsgid \"\"\n\"**Fixed** `4613 <https://github.com/pymupdf/PyMuPDF/issues/4613>`_: Thai \"\n\"and number blocks are not auto-scaled and get wrong hyphen when using in \"\n\"insert_htmlbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:40 c88bc69f0f244a52ad6f890499799047\nmsgid \"\"\n\"**Fixed** `4700 <https://github.com/pymupdf/PyMuPDF/issues/4700>`_: \"\n\"pymupdf.open() processes .zip file without raising\"\nmsgstr \"\"\n\n#: ../../../changes.txt:41 e323399440274525b34c54f4dec39093\nmsgid \"\"\n\"**Fixed** `4716 <https://github.com/pymupdf/PyMuPDF/issues/4716>`_: \"\n\"Problems with unreadable characters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:45 3abefa34a28e4adf8e2457613ce56b45\nmsgid \"Supported Python versions are now 3.9-3.14.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:46 16783112fa05425cb0e149b83c62e932\nmsgid \"\"\n\"We now define all class methods explicitly instead of with dynamic \"\n\"assignment; this improves type hints.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:47 26f54231a095480aa0f42247a5a89ef4\nmsgid \"Removed `pymupdf.utils.Shape` class, was duplicate of `pymupdf.Shape`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:48 7ecda4cd98c54e6a9b9bf91163eff14b\nmsgid \"Allow use of cibuildwheel to build and test on Pyodide.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:49 93135916c58248c283baf01e7d053cd0\nmsgid \"Fixed various Pyodide bugs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:50 7ecc6290f1054757b942bc4fb105d1eb\nmsgid \"\"\n\"In documentation, added section about Linux wheels and glibc \"\n\"compatibility.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:51 92f2c3d79a944460985276d312eca3e4\nmsgid \"Improved documentation of pymupdf.open()'s <filetype> arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:52 562bb006d36840cdb5aadf8ddd466486\nmsgid \"\"\n\"Retrospectively mark `4544 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4544>`_ as fixed in 1.26.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:55 b67d98ad96244427984fe137baacd5a1\nmsgid \"**Changes in version 1.26.4 (2025-08-25)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:57 6d0728e9c0d245e69d0197ef60d55ff6\nmsgid \"Use MuPDF-1.26.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:61 dae25b5e67ed40678841767ca82960df\nmsgid \"\"\n\"**Fixed** `3806 <https://github.com/pymupdf/PyMuPDF/issues/3806>`_: pdf \"\n\"to image rendering ignore optional content offs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:62 d27cf6acd0904ba3854fc86e793e1b0e\nmsgid \"\"\n\"**Fixed** `4388 <https://github.com/pymupdf/PyMuPDF/issues/4388>`_: \"\n\"Incorrect PixMap from page due to cached data from other PDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:63 2485533a6f1c4ceeab94a3a74ea0040a\nmsgid \"\"\n\"**Fixed** `4457 <https://github.com/pymupdf/PyMuPDF/issues/4457>`_: Wrong\"\n\" characters displayed after font subsetting (w/ native method)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:64 ../../../changes.txt:89\n#: 48034320908941b78280338d69474453 582145c0201942e4a97e4a6715f82496\nmsgid \"\"\n\"**Fixed** `4462 <https://github.com/pymupdf/PyMuPDF/issues/4462>`_: \"\n\"delete_pages() does not accept a single int\"\nmsgstr \"\"\n\n#: ../../../changes.txt:65 ee57c3dd80db447388f6e8ac0d049adb\nmsgid \"\"\n\"**Fixed** `4533 <https://github.com/pymupdf/PyMuPDF/issues/4533>`_: Open \"\n\"PDF error segmentation fault\"\nmsgstr \"\"\n\n#: ../../../changes.txt:66 96cc9c5c43084b5e9cf0162eb38b2dbf\nmsgid \"\"\n\"**Fixed** `4544 <https://github.com/pymupdf/PyMuPDF/issues/4544>`_: About\"\n\" pdf_clip_page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:67 ed6dabd36ac34857a630542ffd191c57\nmsgid \"\"\n\"**Fixed** `4565 <https://github.com/pymupdf/PyMuPDF/issues/4565>`_: MacOS\"\n\" uses Tesseract and not Tesseract-OCR\"\nmsgstr \"\"\n\n#: ../../../changes.txt:68 fb88b0c8cbc84095bf2500c9a32f50ec\nmsgid \"\"\n\"**Fixed** `4571 <https://github.com/pymupdf/PyMuPDF/issues/4571>`_: \"\n\"Broken merged pdfs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:69 ef751fe8798b41eaaf64e166e23768fa\nmsgid \"\"\n\"**Fixed** `4590 <https://github.com/pymupdf/PyMuPDF/issues/4590>`_: \"\n\"TypeError in utils.py scrub(): annot.update_file(buffer=...) is invalid\"\nmsgstr \"\"\n\n#: ../../../changes.txt:70 3b8c0e208f554eaebac0ea6abcd8b46d\nmsgid \"\"\n\"**Fixed** `4614 <https://github.com/pymupdf/PyMuPDF/issues/4614>`_: \"\n\"Intercept bad widgets when inserting to another PDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:71 02cfdc76ab714494bf079b968391320e\nmsgid \"\"\n\"**Fixed** `4639 <https://github.com/pymupdf/PyMuPDF/issues/4639>`_: \"\n\"pymupdf.mupdf.FzErrorGeneric: code=1: Director error: <class \"\n\"'AttributeError'>: 'JM_new_bbox_device_Device' object has no attribute \"\n\"'layer_name'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:75 38712224dd5544e7a462aaeb1e2e304b\nmsgid \"\"\n\"Check that #4392 `Segfault when running with pytest and -Werror` is fixed\"\n\" if PyMuPDF is built with swig>=4.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:76 57972c515886453a932d8eac12c3b328\nmsgid \"Add `Page.clip_to_rect()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:77 586a552aa4af4245b5e12d417ae1f42d\nmsgid \"Improved search for Tesseract data.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:78 9f280d1da9b04eedae2eb7fa58bf1973\nmsgid \"Retrospectively mark #4496 as fixed in 1.26.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:79 3fde7874083c4911a6dd9d05ee3f3e7c\nmsgid \"Retrospectively mark #4503 as fixed in 1.26.3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:80 e25d10cd0c8b485b998c07889f2c2b02\nmsgid \"Added experimental support for Graal.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:83 a4c9e90997aa40e39b6e88a47283df1f\nmsgid \"**Changes in version 1.26.3 (2025-07-02)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:85 f2e0c9ebfbc8436a90fbc5210c2d61c5\nmsgid \"Use MuPDF-1.26.3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:90 88b28524dc38400e86ede8dfd69bda83\nmsgid \"\"\n\"**Fixed** `4503 <https://github.com/pymupdf/PyMuPDF/issues/4503>`_: \"\n\"Undetected character styles\"\nmsgstr \"\"\n\n#: ../../../changes.txt:91 82e1019dfacf4e889e4e2708d5c2ab67\nmsgid \"\"\n\"**Fixed** `4527 <https://github.com/pymupdf/PyMuPDF/issues/4527>`_: \"\n\"Rect.intersects() is much slower than necessary\"\nmsgstr \"\"\n\n#: ../../../changes.txt:92 3195a73537bc44b6be38e2643857a820\nmsgid \"\"\n\"**Fixed** `4564 <https://github.com/pymupdf/PyMuPDF/issues/4564>`_: \"\n\"Possible encoding issue in PDF metadata\"\nmsgstr \"\"\n\n#: ../../../changes.txt:93 ed811f813c204c15a71a72b02b3fc7f7\nmsgid \"\"\n\"**Fixed** `4575 <https://github.com/pymupdf/PyMuPDF/issues/4575>`_: Bug \"\n\"with IRect contains method\"\nmsgstr \"\"\n\n#: ../../../changes.txt:97 80940db1fc98463084fb0536e2a74c75\nmsgid \"Class Shape is now available as pymupdf.Shape.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:98 8d3cbad84fc7406db910769a9e0c49cd\nmsgid \"Added table cell markdown support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:101 979c685df84c433a99b2ce9a6192393e\nmsgid \"**Changes in version 1.26.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:103 6253d76480234ecb99ef69856e2e4d7c\nmsgid \"[Skipped.]\"\nmsgstr \"\"\n\n#: ../../../changes.txt:106 696d62b448d042d7ac4c9ae344c9357e\nmsgid \"**Changes in version 1.26.1 (2025-06-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:108 97fd68cacc0d460ea6453d0f75969b06\nmsgid \"Use MuPDF-1.26.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:112 f027534ba7294a6e8c8c22e759448323\nmsgid \"\"\n\"**Fixed** `4520 <https://github.com/pymupdf/PyMuPDF/issues/4520>`_: \"\n\"show_pdf_page does not like empty pages created by new_page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:113 065f392247ae490ab226f1104d666ddc\nmsgid \"\"\n\"**Fixed** `4524 <https://github.com/pymupdf/PyMuPDF/issues/4524>`_: \"\n\"fitz.get_text ignores 'pages' kwarg\"\nmsgstr \"\"\n\n#: ../../../changes.txt:114 ../../../changes.txt:137\n#: 1c6997f9c6d7494ba9b55c63784e99cf c6a83f4370734e42a4528f25014f39ab\nmsgid \"\"\n\"**Fixed** `4412 <https://github.com/pymupdf/PyMuPDF/issues/4412>`_: \"\n\"Regression? Spurious error? in insert_pdf in v1.25.4\"\nmsgstr \"\"\n\n#: ../../../changes.txt:115 bb0e76951378470a8d36dd42e908266d\nmsgid \"\"\n\"**Fixed** `4496 <https://github.com/pymupdf/PyMuPDF/issues/4496>`_: \"\n\"pymupdf4llm with pymupdfpro\"\nmsgstr \"\"\n\n#: ../../../changes.txt:119 87089d7b25b9490a95ea7686681487c8\nmsgid \"\"\n\"Partial fix for `4503 <https://github.com/pymupdf/PyMuPDF/issues/4503>`_:\"\n\" Undetected character styles\"\nmsgstr \"\"\n\n#: ../../../changes.txt:120 ce6c18a243de4e81b72c53d4fefd499e\nmsgid \"\"\n\"New method `Document.rewrite_images()`, useful for reducing file size, \"\n\"changing image formats, or converting color spaces.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:121 0a3a89d09fd3461ca2a27fcca8f185ed\nmsgid \"`Page.get_text()`: restrict positional args to match docs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:122 1a528cc8a62e43639f658f1f709590c9\nmsgid \"Removed bogus definition of class `Shape`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:123 552b40dd8819435dad4a76eae858df20\nmsgid \"\"\n\"Removed release date from module, docs and changelog. * \"\n\"`pymupdf.pymupdf_date` and `pymupdf.VersionDate` are now both None. * \"\n\"They will be removed in a future release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:128 158c863781294c5c93e9b0a8c8e1f847\nmsgid \"**Changes in version 1.26.0 (2025-05-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:130 18567733eef64ab68965ed498958d670\nmsgid \"Use MuPDF-1.26.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:134 4ea8e6ad2e414e978386c33aad8021d5\nmsgid \"\"\n\"**Fixed** `4324 <https://github.com/pymupdf/PyMuPDF/issues/4324>`_: \"\n\"cluster_drawings() fails to cluster horizontal and vertical thin lines\"\nmsgstr \"\"\n\n#: ../../../changes.txt:135 17554e87f7084cacb19d789d4694754f\nmsgid \"\"\n\"**Fixed** `4363 <https://github.com/pymupdf/PyMuPDF/issues/4363>`_: \"\n\"Trouble with searching\"\nmsgstr \"\"\n\n#: ../../../changes.txt:136 2cb8333bfa3948d0a1e1df290b275159\nmsgid \"\"\n\"**Fixed** `4404 <https://github.com/pymupdf/PyMuPDF/issues/4404>`_: \"\n\"IndexError in page.get_links()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:138 3fb86dc38b76431f8fa289ed24574576\nmsgid \"\"\n\"**Fixed** `4423 <https://github.com/pymupdf/PyMuPDF/issues/4423>`_: \"\n\"pymupdf.mupdf.FzErrorFormat: code=7: cannot find object in xref error \"\n\"encountered after version 1.25.3\"\nmsgstr \"\"\n\n#: ../../../changes.txt:139 e4d0ca8ddf164f08b449dac3a6fa04fa\nmsgid \"\"\n\"**Fixed** `4435 <https://github.com/pymupdf/PyMuPDF/issues/4435>`_: \"\n\"get_pixmap method stuck on one page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:140 73d115f25755496680f56c79674a6351\nmsgid \"\"\n\"**Fixed** `4439 <https://github.com/pymupdf/PyMuPDF/issues/4439>`_: New \"\n\"Xml class from data does not work - bug in code\"\nmsgstr \"\"\n\n#: ../../../changes.txt:141 b25d62127fea4feaa5d944e835c2a666\nmsgid \"\"\n\"**Fixed** `4445 <https://github.com/pymupdf/PyMuPDF/issues/4445>`_: \"\n\"Broken XREF table incorrectly repaired\"\nmsgstr \"\"\n\n#: ../../../changes.txt:142 a0a2ed6ac1354febb9da6afd02bc9b42\nmsgid \"\"\n\"**Fixed** `4447 <https://github.com/pymupdf/PyMuPDF/issues/4447>`_: \"\n\"Stroke color of annotations cannot be correctly set\"\nmsgstr \"\"\n\n#: ../../../changes.txt:143 616298c000ad48cdbc628ef4cdd172d8\nmsgid \"\"\n\"**Fixed** `4479 <https://github.com/pymupdf/PyMuPDF/issues/4479>`_: \"\n\"set_layer_ui_config() toggles all layers rather than just one\"\nmsgstr \"\"\n\n#: ../../../changes.txt:144 b15ec1ffa6f0419c8b5503c50587840c\nmsgid \"\"\n\"**Fixed** `4505 <https://github.com/pymupdf/PyMuPDF/issues/4505>`_: \"\n\"Follow Widget flag values up its parent structure\"\nmsgstr \"\"\n\n#: ../../../changes.txt:148 7b7ea93f30ca49f88b45b05c08ecf10f\nmsgid \"\"\n\"Partial fixed for `4457 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4457>`_: Wrong characters \"\n\"displayed after font subsetting (w/ native method)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:149 b0ae6f4b0bc24e12bd0071f22e599e11\nmsgid \"Support image stamp annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:150 f5f7682cfc6c4abba06ebd809edf0795\nmsgid \"Support recoloring pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:151 01a95f3b08944431b06a9d2e99e50bdf\nmsgid \"\"\n\"Added example of using Django's file storage API to open files with \"\n\"pymupdf.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:152 1ea4d799a2714c90a3ad74a4f03f1ed8\nmsgid \"\"\n\"Clarified FreeText annotation color options. We now raise an exception if\"\n\" an attempt is made to set attributes that can not be supported.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:154 856acd8f3343442bb8ee7254e8b8d062\nmsgid \"Fixed potential segv in Pixmap.is_unicolor().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:155 90dbf6ef976a4d76a799854a5aa774dc\nmsgid \"\"\n\"Added runtime assert that that PyMuPDF and MuPDF were built with \"\n\"compatible NDEBUG settings (related to `4390 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/4390>`_).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:157 0862256c36d142c48444aab07763f645\nmsgid \"Simplified handling of filename/filetype when opening documents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:158 5e85ed11581b46daaf1a09b8a22dcccb\nmsgid \"\"\n\"Removed PDF linearization support. * Calls to `Document.save()` with \"\n\"`linear` set to true will now raise an exception. * See \"\n\"https://artifex.com/blog/mupdf-removes-linearisation for more \"\n\"information.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:162 c7ce1a9bb27545978d6d1d9fed1a4524\nmsgid \"**Changes in version 1.25.5 (2025-03-31)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:166 9548bbf70ba9469e8b935a45f29643ed\nmsgid \"\"\n\"**Fixed** `4372 <https://github.com/pymupdf/PyMuPDF/issues/4372>`_: Text \"\n\"insertion fails due to missing /Resources object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:167 f76e7622a9d7433db1b7b82bc7156145\nmsgid \"\"\n\"**Fixed** `4400 <https://github.com/pymupdf/PyMuPDF/issues/4400>`_: \"\n\"Infinite loop in fill_textbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:168 82f33cb8a6d34f62b854eca17a8c4254\nmsgid \"\"\n\"**Fixed** `4403 <https://github.com/pymupdf/PyMuPDF/issues/4403>`_: \"\n\"Unable to get_text() - layer/clip nesting too deep\"\nmsgstr \"\"\n\n#: ../../../changes.txt:169 84b7b13060424773820d4994525080dc\nmsgid \"\"\n\"**Fixed** `4415 <https://github.com/pymupdf/PyMuPDF/issues/4415>`_: PDF \"\n\"page is mirrored, origin is at bottom-left\"\nmsgstr \"\"\n\n#: ../../../changes.txt:173 74a4792d6a8244eb9dcae4beb4bfe0ee\nmsgid \"Use MuPDF-1.25.6.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:174 d248e14b8c1a4e3fab6235c3cf5c614c\nmsgid \"Fixed MuPDF SEGV on MacOS with particular fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:175 82ea9eb171144077a7870ae7a0b9eeb7\nmsgid \"Fixed `Annot.get_textpage()`'s `clip` arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:176 2fccc9761609452e9d10dac746b11059\nmsgid \"Fixed Python-3.14 (pre-release) build error.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:179 2fbd0061abcd475fafe6ef6a570e0d7a\nmsgid \"**Changes in version 1.25.4 (2025-03-14)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:181 9fa9e7eec7694807a4577e93e3fdb54e\nmsgid \"Use MuPDF-1.25.5.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:185 8f7a4be455684495af9c8e17de5ad09d\nmsgid \"\"\n\"**Fixed** `4079 <https://github.com/pymupdf/PyMuPDF/issues/4079>`_: \"\n\"Unexpected result for apply_redactions()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:186 6d876027b2104b01830654bbbae308e9\nmsgid \"\"\n\"**Fixed** `4224 <https://github.com/pymupdf/PyMuPDF/issues/4224>`_: MuPDF\"\n\" error: format error: negative code in 1d faxd\"\nmsgstr \"\"\n\n#: ../../../changes.txt:187 b7b89a62c35d4608987e21ec0f356173\nmsgid \"\"\n\"**Fixed** `4303 <https://github.com/pymupdf/PyMuPDF/issues/4303>`_: \"\n\"page.get_image_info() returns outdated cached results after replacing \"\n\"image\"\nmsgstr \"\"\n\n#: ../../../changes.txt:188 8b5c375bcfc24c81a1ab34fdfe2e3f87\nmsgid \"\"\n\"**Fixed** `4309 <https://github.com/pymupdf/PyMuPDF/issues/4309>`_: \"\n\"FzErrorFormat Error When Deleting First Page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:189 33ebf7622662470e98f52b0e0681e4b1\nmsgid \"\"\n\"**Fixed** `4336 <https://github.com/pymupdf/PyMuPDF/issues/4336>`_: Major\"\n\" Performance Regression: pix.color_count is 150x slower in version 1.25.3\"\n\" compared to 1.23.8\"\nmsgstr \"\"\n\n#: ../../../changes.txt:190 159061230d824914a6d19ad6d73eeb7c\nmsgid \"\"\n\"**Fixed** `4341 <https://github.com/pymupdf/PyMuPDF/issues/4341>`_: \"\n\"Invalid label retrieval when /Kids is an array of multiple /Nums\"\nmsgstr \"\"\n\n#: ../../../changes.txt:194 37e49743f93f41d9bf5880142941c864\nmsgid \"Fixed handling of duplicate widget names when joining PDFs (PR #4347).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:195 0cac0025172c4dd5baf122fc076da58e\nmsgid \"Improved Pyodide build.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:196 638ca0a27dd548cfa15a4095bd238671\nmsgid \"\"\n\"Avoid SWIG-related build errors with Python-3.13 by disabling \"\n\"PY_LIMITED_API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:199 24df824cc0ed4dcaa55266a462308f72\nmsgid \"**Changes in version 1.25.3 (2025-02-06)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:201 86fbdb38e3ab475cb35bce8474a0517d\nmsgid \"Use MuPDF-1.25.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:205 11404e9f065f46d48c17de3eb0a56b4c\nmsgid \"\"\n\"**Fixed** `4139 <https://github.com/pymupdf/PyMuPDF/issues/4139>`_: Text \"\n\"color numbers change between 1.24.14 and 1.25.0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:206 f54ac127378c40efbea689f95f729a3d\nmsgid \"\"\n\"**Fixed** `4141 <https://github.com/pymupdf/PyMuPDF/issues/4141>`_: Some \"\n\"insertion methods fails for pages without a /Resources object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:207 1debce8303bb430aaf3c754c31d4e54a\nmsgid \"\"\n\"**Fixed** `4180 <https://github.com/pymupdf/PyMuPDF/issues/4180>`_: \"\n\"Search problems\"\nmsgstr \"\"\n\n#: ../../../changes.txt:208 a43078709b894315ab60ab8c8077d919\nmsgid \"\"\n\"**Fixed** `4182 <https://github.com/pymupdf/PyMuPDF/issues/4182>`_: Text \"\n\"coordinate extraction error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:209 2aa654ea699a4754864254e38097fcf4\nmsgid \"\"\n\"**Fixed** `4245 <https://github.com/pymupdf/PyMuPDF/issues/4245>`_: \"\n\"Highlighting issue distorted on recent versions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:210 568c972326294ecab31a4378aee8aef3\nmsgid \"\"\n\"**Fixed** `4254 <https://github.com/pymupdf/PyMuPDF/issues/4254>`_: \"\n\"add_freetext_annot is drawing text outside the annotation box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:214 3b1e13a8a53f41568994b6b10d784dd4\nmsgid \"\"\n\"In annotations: * Added support for subtype FreeTextCallout. * Added \"\n\"support for rich text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:217 20ad825019bc421aa9fa359d4c2cf2b9\nmsgid \"\"\n\"Added miter_limit arg to insert_text*() to allow suppression of spikes \"\n\"caused by long miters.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:218 d8f3a5bd962d420482fbab442a82a337\nmsgid \"Add Widget Support to `Document.insert_pdf()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:219 b25922bccda743b4a462eff61aa2da32\nmsgid \"Add `bibi` to span dicts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:220 16e4de5888954261941fe67d4f618949\nmsgid \"Add `synthetic' to char dict.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:221 ../../../changes.txt:963\n#: 2b958160bd134274b90ba5bd456e66c5 43a26b5aad0e4fe485acf6a41282f421\nmsgid \"Fixed Pyodide builds.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:224 f65069a7584b4f128fa5b7cc86d526ab\nmsgid \"**Changes in version 1.25.2 (2025-01-17)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:228 af70ce0fc1a74152b86dbd49d309fdb9\nmsgid \"\"\n\"**Fixed** `4055 <https://github.com/pymupdf/PyMuPDF/issues/4055>`_: \"\n\"\\\"Yes\\\" for all checkboxes does not work for all PDF rendering engines.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:229 4410d36a900d450c97588b75ccb21628\nmsgid \"\"\n\"**Fixed** `4155 <https://github.com/pymupdf/PyMuPDF/issues/4155>`_: \"\n\"samples_mv is unsafe\"\nmsgstr \"\"\n\n#: ../../../changes.txt:230 61173d64746b46848303884ad4f7c6c2\nmsgid \"\"\n\"**Fixed** `4162 <https://github.com/pymupdf/PyMuPDF/issues/4162>`_: Got \"\n\"AttributeError, when tried to add Signature field\"\nmsgstr \"\"\n\n#: ../../../changes.txt:231 ade3c33dc1bc4fe5a6c9c79ad335b6ca\nmsgid \"\"\n\"**Fixed** `4186 <https://github.com/pymupdf/PyMuPDF/issues/4186>`_: \"\n\"Incorrect handling of JPEG with color space CMYK image extraction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:232 b0f948dd2aec4196879b796a7083ce66\nmsgid \"\"\n\"**Fixed** `4195 <https://github.com/pymupdf/PyMuPDF/issues/4195>`_: \"\n\"Pixmaps that are inverted and have an alpha channel are not rendered \"\n\"properly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:233 f983aaf8e72b40329ef333edb032482d\nmsgid \"\"\n\"**Fixed** `4225 <https://github.com/pymupdf/PyMuPDF/issues/4225>`_: \"\n\"pixmap.pil_save() fails due to colorspace definition\"\nmsgstr \"\"\n\n#: ../../../changes.txt:234 b9f784c7a8e347f0839af27a4aee0957\nmsgid \"\"\n\"**Fixed** `4232 <https://github.com/pymupdf/PyMuPDF/issues/4232>`_: \"\n\"Incorrect Font style and Size\"\nmsgstr \"\"\n\n#: ../../../changes.txt:238 46a2de9de8a84001a08386537fad1cb6\nmsgid \"Use Python's built-in glyphname <> unicode conversion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:239 98aaf3100ca44c3eb46b239c085990ce\nmsgid \"Improve speed of pixmap color inversion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:240 761c1030615e4b9f8837990276cdd4aa\nmsgid \"\"\n\"Add new `char_flags` member to span dictionary, for example allows \"\n\"detection of invisible text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:241 26863d989def4dd6b375f90f90ac816a\nmsgid \"Detect image masks in TextPage output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:242 c106eb1531f34065ac0918f8967d868c\nmsgid \"Added `Pixmap.pil_image()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:245 f2917761f4f342b2b20eb583e456ac86\nmsgid \"**Changes in version 1.25.1 (2024-12-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:247 5d2a2817fc15439e8cff5b48d2993934\nmsgid \"Use MuPDF-1.25.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:251 1aa29c8b332c4f06b69b0f5c16618fed\nmsgid \"\"\n\"**Fixed** `4125 <https://github.com/pymupdf/PyMuPDF/issues/4125>`_: \"\n\"memory leak while convert Pixmap's colorspace\"\nmsgstr \"\"\n\n#: ../../../changes.txt:252 6619cbba93b64266b96af9f2fb26333c\nmsgid \"\"\n\"**Fixed** `4034 <https://github.com/pymupdf/PyMuPDF/issues/4034>`_: \"\n\"Possible regression in pdf cleaning during save.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:255 54ab8ad1ec3246298a9019b2227a46d8\nmsgid \"**Changes in version 1.25.0 (2024-12-05)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:257 0a8714b7f18e45878f7b252f8af10ade\nmsgid \"Use MuPDF-1.25.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:261 686ebe75128d4be9b77bba0ddb563a43\nmsgid \"\"\n\"**Fixed** `4026 <https://github.com/pymupdf/PyMuPDF/issues/4026>`_: \"\n\"page.get_text('blocks') output two piece of very similar text with \"\n\"different bbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:262 efd9decd0d2a4a319ebd830a2c8531bd\nmsgid \"\"\n\"**Fixed** `4004 <https://github.com/pymupdf/PyMuPDF/issues/4004>`_: \"\n\"Segmentation Fault When Updating PDF Form Field Value\"\nmsgstr \"\"\n\n#: ../../../changes.txt:263 ebdb384bd8e4477d80b10127b014145b\nmsgid \"\"\n\"**Fixed** `3887 <https://github.com/pymupdf/PyMuPDF/issues/3887>`_: \"\n\"Subset Fonts problem using Fallback Font\"\nmsgstr \"\"\n\n#: ../../../changes.txt:264 e63e1845d9fb45198345afaff67f30e1\nmsgid \"\"\n\"**Fixed** `3886 <https://github.com/pymupdf/PyMuPDF/issues/3886>`_: \"\n\"Another issue with destroying PDF when inserting html\"\nmsgstr \"\"\n\n#: ../../../changes.txt:265 50adbcf9a18043e68b84aa9286698361\nmsgid \"\"\n\"**Fixed** `3751 <https://github.com/pymupdf/PyMuPDF/issues/3751>`_: \"\n\"apply_redactions causes part of the page content to be hidden / \"\n\"transparent\"\nmsgstr \"\"\n\n#: ../../../changes.txt:270 09e722df03fa4db18c4e0da832e997f7\nmsgid \"**Changes in version 1.24.14 (2024-11-19)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:272 cb8ebd6072bd4e11919080375887f166\nmsgid \"Use MuPDF-1.24.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:276 50b663786ee641cb9687580189342f8d\nmsgid \"\"\n\"**Fixed** `3448 <https://github.com/pymupdf/PyMuPDF/issues/3448>`_: \"\n\"get_pixmap function removes the table and leaves just the content behind\"\nmsgstr \"\"\n\n#: ../../../changes.txt:277 54321b37a7f9420b8567fbb6d1e426a4\nmsgid \"\"\n\"**Fixed** `3758 <https://github.com/pymupdf/PyMuPDF/issues/3758>`_: Got \"\n\"\\\"malloc(): unaligned tcache chunk detected Aborted (core dumped)\\\" while\"\n\" using add_redact_annot/apply_redactions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:278 296dc7d294134423a31f7b6d74f2aeaf\nmsgid \"\"\n\"**Fixed** `3813 <https://github.com/pymupdf/PyMuPDF/issues/3813>`_: \"\n\"Stories: Ordered list count broken with nested unordered list\"\nmsgstr \"\"\n\n#: ../../../changes.txt:279 2215310351ca46c1a25a514468a905a8\nmsgid \"\"\n\"**Fixed** `3933 <https://github.com/pymupdf/PyMuPDF/issues/3933>`_: \"\n\"font.valid_codepoints() - malfunction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:280 ff0631f5b7054df4b90b9fa8739b4ec1\nmsgid \"\"\n\"**Fixed** `4018 <https://github.com/pymupdf/PyMuPDF/issues/4018>`_: \"\n\"PyMuPDF hangs when iterating over zero page PDF pages backwards\"\nmsgstr \"\"\n\n#: ../../../changes.txt:281 a2a87af3e4c84a6abc63ea9d9e914391\nmsgid \"\"\n\"**Fixed** `4043 <https://github.com/pymupdf/PyMuPDF/issues/4043>`_: \"\n\"fullcopypage bug\"\nmsgstr \"\"\n\n#: ../../../changes.txt:282 55686d0fa4674d4299310ada01d1735d\nmsgid \"\"\n\"**Fixed** `4047 <https://github.com/pymupdf/PyMuPDF/issues/4047>`_: \"\n\"Segmentation Fault in add_redact_annot\"\nmsgstr \"\"\n\n#: ../../../changes.txt:283 0c2e617044914d04b642de2fa1587abb\nmsgid \"\"\n\"**Fixed** `4050 <https://github.com/pymupdf/PyMuPDF/issues/4050>`_: \"\n\"Content of dict returned by doc.embfile_info() does not fit to \"\n\"documentation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:287 1bb6617fc61d474c946dbf47c807e5d8\nmsgid \"\"\n\"Ensure that words from `Page.get_text()` never contain RTL/LTR char \"\n\"mixtures.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:288 2171b4b55a384da393be21b8cef7cd46\nmsgid \"Fix building with system MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:289 1b697fc68ecb486aa3b482711dd06c98\nmsgid \"Add dot product for points and vectors.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:292 b3aa2aa2bfbc4c9ba5c5d2c84a823910\nmsgid \"**Changes in version 1.24.13 (2024-10-29)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:296 532324021bbe48718cffa19ecedb034c\nmsgid \"\"\n\"**Fixed** `3848 <https://github.com/pymupdf/PyMuPDF/issues/3848>`_:  \"\n\"Piximap program crash\"\nmsgstr \"\"\n\n#: ../../../changes.txt:297 ../../../changes.txt:308\n#: 2387d394753a42ad872fa2268d7e9a29 cb2a797b491348f58ab3ce4ba98b73d9\nmsgid \"\"\n\"**Fixed** `3950 <https://github.com/pymupdf/PyMuPDF/issues/3950>`_:  \"\n\"Unable to consistently extract field labels from PDFs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:298 51536c1106ea45ac9444978b1684c0c1\nmsgid \"\"\n\"**Fixed** `3981 <https://github.com/pymupdf/PyMuPDF/issues/3981>`_:  \"\n\"PyMuPDF 1.24.12 with pyinstaller throws error.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:299 f44e8a92c6004f9f8c5c59b80ddbf558\nmsgid \"\"\n\"**Fixed** `3994 <https://github.com/pymupdf/PyMuPDF/issues/3994>`_:  \"\n\"pix.color_topusage raise Segmentation fault (core dumped)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:302 6bd1fa6f738340babc3df986bdc5a0a5\nmsgid \"**Changes in version 1.24.12 (2024-10-21)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:306 5174733bb6794f2b8c431f53170d0267\nmsgid \"\"\n\"**Fixed** `3914 <https://github.com/pymupdf/PyMuPDF/issues/3914>`_:  \"\n\"Ability to print MuPDF errors to logging instead of stdout\"\nmsgstr \"\"\n\n#: ../../../changes.txt:307 78495d3820584622819a2d243eabe922\nmsgid \"\"\n\"**Fixed** `3916 <https://github.com/pymupdf/PyMuPDF/issues/3916>`_:  \"\n\"insert_htmlbox error: int too large to convert to float\"\nmsgstr \"\"\n\n#: ../../../changes.txt:310 dc5a73b307bb45128375b3e45f21f804\nmsgid \"Supported Python versions are now 3.9-3.13.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:312 7fa696ad2ff84d4fb6204d9eeaa72eec\nmsgid \"Dropped support for Python-3.8 because end-of-life.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:313 2be21c1bbf164eb88dd5059514d52c40\nmsgid \"Added support for Python-3.13 because now released.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:314 a07d59ffaf6a48c8827e65b703ee0856\nmsgid \"See: https://devguide.python.org/versions/\"\nmsgstr \"\"\n\n#: ../../../changes.txt:317 d5600d2cd45b4009ba4eb42289cee550\nmsgid \"**Changes in version 1.24.11 (2024-10-03)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:319 9d700953907b44fe86d10f2023bda708\nmsgid \"Use MuPDF-1.24.10.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:323 808cd9169aeb4de68aaf51afd0fbff17\nmsgid \"\"\n\"**Fixed** `3624 <https://github.com/pymupdf/PyMuPDF/issues/3624>`_: Pdf \"\n\"file transform to image have a black block\"\nmsgstr \"\"\n\n#: ../../../changes.txt:324 8f414ff010194b2abb249bd69290b7a1\nmsgid \"\"\n\"**Fixed** `3859 <https://github.com/pymupdf/PyMuPDF/issues/3859>`_: \"\n\"doc.need_appearances() fails with \\\"AttributeError: module \"\n\"'pymupdf.mupdf' has no attribute 'PDF_TRUE' \\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:325 144003ab4e5743f1a5a6728e0d572424\nmsgid \"\"\n\"**Fixed** `3863 <https://github.com/pymupdf/PyMuPDF/issues/3863>`_: \"\n\"apply_redactions() does not work as expected\"\nmsgstr \"\"\n\n#: ../../../changes.txt:326 dd7478f2b06449c48d6b3c1bda073aa9\nmsgid \"\"\n\"**Fixed** `3905 <https://github.com/pymupdf/PyMuPDF/issues/3905>`_: open \"\n\"stream can raise a FzErrorFormat error instead of FileDataError\"\nmsgstr \"\"\n\n#: ../../../changes.txt:328 bf8693cc8c1349408cbd9fc992ea196e\nmsgid \"Wheels now use the Python Stable ABI:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:330 efc06a4c0fd84a09a008423f67eee13e\nmsgid \"There is one PyMuPDF wheel for each platform.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:331 4c8dea397efc48d68f2a64b021c76ed0\nmsgid \"Each wheel works with all supported Python versions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:332 1c41329749a64d22b3f9e3b61036f38c\nmsgid \"\"\n\"Each wheel is built using the oldest supported Python version (currently \"\n\"3.8).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:333 2e864bd74a2f4ef98e175a1e44fec4df\nmsgid \"There is no PyMuPDFb wheel.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:337 aa491896b5e04bd582e529c840ead400\nmsgid \"Improvements to get_text_words() with sort=True.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:338 283df97df8874c3fa38c6c9a57f6af06\nmsgid \"Tests now always get the latest versions of required Python packages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:339 f6a1523241f54a9ba84dfed4f6dde3b2\nmsgid \"Removed dependency on setuptools.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:340 1596796af81b476e80835455e0a27a29\nmsgid \"Added item to PyMuPDF-1.24.10 changes below - fix of #3630.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:343 0d1ea2fa95e1430a91731b5c309c154f\nmsgid \"**Changes in version 1.24.10 (2024-09-02)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:345 0fdb57593f1f47f78b61e459d90c4fd0\nmsgid \"Use MuPDF-1.24.9.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:349 4c1b818189074d939767d48fa6ba40e6\nmsgid \"\"\n\"**Fixed** `3450 <https://github.com/pymupdf/PyMuPDF/issues/3450>`_: \"\n\"get_pixmap function takes too long to process\"\nmsgstr \"\"\n\n#: ../../../changes.txt:350 03bc289e1528407b8433671ea3e5587e\nmsgid \"\"\n\"**Fixed** `3569 <https://github.com/pymupdf/PyMuPDF/issues/3569>`_: \"\n\"Invalid OCGs not ignored by SVG image creation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:351 3e64094a0a16437ab1fceb4fd8904883\nmsgid \"\"\n\"**Fixed** `3603 <https://github.com/pymupdf/PyMuPDF/issues/3603>`_: \"\n\"ObjStm compression and PDF linearization doesn't work together\"\nmsgstr \"\"\n\n#: ../../../changes.txt:352 4a6c4d95199b49919c2ec7b76da32a3a\nmsgid \"\"\n\"**Fixed** `3650 <https://github.com/pymupdf/PyMuPDF/issues/3650>`_: \"\n\"Linebreak inserted between each letter\"\nmsgstr \"\"\n\n#: ../../../changes.txt:353 a5fb10f857014368871b0ee0628a1ef1\nmsgid \"\"\n\"**Fixed** `3661 <https://github.com/pymupdf/PyMuPDF/issues/3661>`_: \"\n\"Update Document to check the /XYZ len\"\nmsgstr \"\"\n\n#: ../../../changes.txt:354 77892cd87ca346d381b0b249574312b4\nmsgid \"\"\n\"**Fixed** `3698 <https://github.com/pymupdf/PyMuPDF/issues/3698>`_: \"\n\"documentation issue - old code in the annotations documentation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:355 8a4df3770f95440c870288e5f497cf93\nmsgid \"\"\n\"**Fixed** `3705 <https://github.com/pymupdf/PyMuPDF/issues/3705>`_: \"\n\"Document.select() behaves weirdly in some particular kind of pdf files\"\nmsgstr \"\"\n\n#: ../../../changes.txt:356 575c721454394ef5954021b2e3910c5a\nmsgid \"\"\n\"**Fixed** `3706 <https://github.com/pymupdf/PyMuPDF/issues/3706>`_: \"\n\"extend Document.__getitem__ type annotation to reflect that the method \"\n\"also accepts slices\"\nmsgstr \"\"\n\n#: ../../../changes.txt:357 b4081c4845a3495cab35195cfcbd4e5f\nmsgid \"\"\n\"**Fixed** `3727 <https://github.com/pymupdf/PyMuPDF/issues/3727>`_: \"\n\"Method get_pixmap() make the program exit without any exceptions or \"\n\"messages\"\nmsgstr \"\"\n\n#: ../../../changes.txt:358 4a582d7cc3ca40cfba3314faa5800f56\nmsgid \"\"\n\"**Fixed** `3767 <https://github.com/pymupdf/PyMuPDF/issues/3767>`_: \"\n\"Cannot get Tessdata with Tesseract-OCR 5\"\nmsgstr \"\"\n\n#: ../../../changes.txt:359 9a3c4b91a07e4c118de884a8c386dcfb\nmsgid \"\"\n\"**Fixed** `3773 <https://github.com/pymupdf/PyMuPDF/issues/3773>`_: \"\n\"Link.set_border gives TypeError: '<' not supported between instances of \"\n\"'NoneType' and 'int'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:360 d3028f61318447b68e56290fbd6732cc\nmsgid \"\"\n\"**Fixed** `3774 <https://github.com/pymupdf/PyMuPDF/issues/3774>`_: \"\n\"fitz.__version__` does not work anymore\"\nmsgstr \"\"\n\n#: ../../../changes.txt:361 596c2f50505948db9e84f139ffaea8fa\nmsgid \"\"\n\"**Fixed** `3789 <https://github.com/pymupdf/PyMuPDF/issues/3789>`_: \"\n\"ValueError: not enough values to unpack (expected 3, got 2) is thrown \"\n\"when call insert_pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:362 e99c3b3c69d1484f8ea0b97279da22e4\nmsgid \"\"\n\"**Fixed** `3820 <https://github.com/pymupdf/PyMuPDF/issues/3820>`_: class\"\n\" improves namedDest handling\"\nmsgstr \"\"\n\n#: ../../../changes.txt:364 9c63afe342914710a2f4b27172881a97\nmsgid \"\"\n\"**Fixed** `3630 <https://github.com/pymupdf/PyMuPDF/issues/3630>`_: \"\n\"page.apply_redactions gives unwanted black rectangle\"\nmsgstr \"\"\n\n#: ../../../changes.txt:368 a69ca8bf39fc49c78509e477fc16ec48\nmsgid \"\"\n\"Object streams and linearization cannot be used together; attempting to \"\n\"do so will raise an exception. (#3603)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:370 d667244f9aa14f1d8b25176a013989e0\nmsgid \"Fixed handling of non-existing /Contents object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:373 007020c8bc19452da4cd657fdcba20c0\nmsgid \"**Changes in version 1.24.9 (2024-07-24)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:375 3025163fadb648e88e840b5f088e6d56\nmsgid \"Use MuPDF-1.24.8.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:378 259a038beea8413baaac6ee36c977d21\nmsgid \"**Changes in version 1.24.8 (2024-07-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:382 a3d2403d008e4902bda8c294e7d5b193\nmsgid \"\"\n\"**Fixed** `3636 <https://github.com/pymupdf/PyMuPDF/issues/3636>`_: API \"\n\"documentation for the open function is not obvious to find.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:383 eb0f33456dca477bb49123d26150dbd5\nmsgid \"\"\n\"**Fixed** `3654 <https://github.com/pymupdf/PyMuPDF/issues/3654>`_: docx \"\n\"parsing was broken in 1.24.7\"\nmsgstr \"\"\n\n#: ../../../changes.txt:384 6c8df8e668094aef8d31035e9dc0e65d\nmsgid \"\"\n\"**Fixed** `3677 <https://github.com/pymupdf/PyMuPDF/issues/3677>`_: \"\n\"Unable to extract subset font name using the newer versions of PyMuPDF : \"\n\"1.24.6 and 1.24.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:385 c5b0babed39f440d99efdd7a90d63f4b\nmsgid \"\"\n\"**Fixed** `3687 <https://github.com/pymupdf/PyMuPDF/issues/3687>`_: \"\n\"Page.get_text results in AssertionError for epub files\"\nmsgstr \"\"\n\n#: ../../../changes.txt:389 e245fedf7bb24e8d92d8116cb00ad30e\nmsgid \"Fixed various spelling mistakes spotted by codespell.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:390 764d9b752f59499e856f560908cee6d9\nmsgid \"Improved how we modify MuPDF's default configuration on Windows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:391 6e8cb04f867c4ad59e8be783e217fc4d\nmsgid \"Make text search to work with ligatures.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:394 25efadfa996341b38552789392dbaf74\nmsgid \"**Changes in version 1.24.7 (2024-06-26)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:398 fa9eea5710484750bedce90cc64b9daf\nmsgid \"\"\n\"**Fixed** `3615 <https://github.com/pymupdf/PyMuPDF/issues/3615>`_: \"\n\"Document.pagemode or Document.pagelayout crashes for epub files\"\nmsgstr \"\"\n\n#: ../../../changes.txt:399 795aad875dfc458eb4a6c99bccde0cec\nmsgid \"\"\n\"**Fixed** `3616 <https://github.com/pymupdf/PyMuPDF/issues/3616>`_: not \"\n\"last version reported\"\nmsgstr \"\"\n\n#: ../../../changes.txt:402 b75b54baeb764ed5bfca7d9290d654f6\nmsgid \"**Changes in version 1.24.6 (2024-06-25)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:404 ce8d669017974969859f4cf2c64c5c09\nmsgid \"Use MuPDF-1.24.4\"\nmsgstr \"\"\n\n#: ../../../changes.txt:408 f726a1ab74364bca9e9f707167e9d0af\nmsgid \"\"\n\"**Fixed** `3599 <https://github.com/pymupdf/PyMuPDF/issues/3599>`_: \"\n\"Story.fit_width() has a weird line\"\nmsgstr \"\"\n\n#: ../../../changes.txt:409 8e99b98271ea423bb26bb068ec39ea52\nmsgid \"\"\n\"**Fixed** `3594 <https://github.com/pymupdf/PyMuPDF/issues/3594>`_: \"\n\"Garbled extraction for Amazon Sustainability Report\"\nmsgstr \"\"\n\n#: ../../../changes.txt:410 651a15f12d5043b6b328618180353f68\nmsgid \"\"\n\"**Fixed** `3591 <https://github.com/pymupdf/PyMuPDF/issues/3591>`_: \"\n\"'width' in Page.get_drawings() returns width equal as 0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:411 02fe36631c264c87895576864dc44e43\nmsgid \"\"\n\"**Fixed** `3561 <https://github.com/pymupdf/PyMuPDF/issues/3561>`_: \"\n\"ZeroDivisionError: float division by zero with page.apply_redactions()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:412 99db39151ed74f9d97810a41633d73e2\nmsgid \"\"\n\"**Fixed** `3559 <https://github.com/pymupdf/PyMuPDF/issues/3559>`_: \"\n\"SegFault 11 when empty H1 H2 H3 H4 etc element is used in insert_htmlbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:413 5e95ed936be0415c95c278cf1d1a9999\nmsgid \"\"\n\"**Fixed** `3539 <https://github.com/pymupdf/PyMuPDF/issues/3539>`_: Add \"\n\"dotted gridline detection to table recognition\"\nmsgstr \"\"\n\n#: ../../../changes.txt:414 75ffb0d518004dc2a74244b12b6c97bd\nmsgid \"\"\n\"**Fixed** `3519 <https://github.com/pymupdf/PyMuPDF/issues/3519>`_: \"\n\"get_toc(simple=False) AttributeError: 'Outline' object has no attribute \"\n\"'rect'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:415 495d1b01dfb7457ebb231eca62c7c539\nmsgid \"\"\n\"**Fixed** `3510 <https://github.com/pymupdf/PyMuPDF/issues/3510>`_: \"\n\"page.get_label() gets wrong label on the first page of doc\"\nmsgstr \"\"\n\n#: ../../../changes.txt:416 60f43a90ceb845b2adf2947634af64ac\nmsgid \"\"\n\"**Fixed** `3494 <https://github.com/pymupdf/PyMuPDF/issues/3494>`_: \"\n\"1.24.2/1.24.3: spurious characters introduced when using subset_fonts and\"\n\" insert_pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:417 a4e0010c0d8f45beaae70809abc81039\nmsgid \"\"\n\"**Fixed** `3470 <https://github.com/pymupdf/PyMuPDF/issues/3470>`_: \"\n\"subset_fonts error exit without exception/warning\"\nmsgstr \"\"\n\n#: ../../../changes.txt:418 99fd9bbe5dba43aa9c040b3a77aee77c\nmsgid \"\"\n\"**Fixed** `3400 <https://github.com/pymupdf/PyMuPDF/issues/3400>`_: \"\n\"set_toc alters link coordinates for some rotated pages on pymupdf 1.24.2\"\nmsgstr \"\"\n\n#: ../../../changes.txt:419 82687af929194a6dbf9c19ea545b5e0b\nmsgid \"\"\n\"**Fixed** `3347 <https://github.com/pymupdf/PyMuPDF/issues/3347>`_: \"\n\"Incorrect links to points on pages having different heights\"\nmsgstr \"\"\n\n#: ../../../changes.txt:420 340ce003832a4bf4a832ae0623c2ac19\nmsgid \"\"\n\"**Fixed** `3237 <https://github.com/pymupdf/PyMuPDF/issues/3237>`_: \"\n\"Set_metadata() does not work\"\nmsgstr \"\"\n\n#: ../../../changes.txt:421 ce983433667f4f27a675ad0f4ab90de8\nmsgid \"\"\n\"**Fixed** `3493 <https://github.com/pymupdf/PyMuPDF/discussions/3493>`_: \"\n\"Isolate PyMuPDF from other libraries; issues when PyMuPDF is loaded with \"\n\"other libraries like GdkPixbuf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:425 85db5876f5884fdb94a243fa8cea3bb5\nmsgid \"\"\n\"Fixed concurrent use of PyMuPDF caused by use of constant temporary \"\n\"filenames.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:427 7bc8d5be62d24850bd1a2d0b042c5dc7\nmsgid \"Add musllinux x86_64 wheels to release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:429 8442053275014be3a2961c23d5c1e875\nmsgid \"Added clearer version information:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:431 898d54fe7f294059a365ce4df283fa8e\nmsgid \"`pymupdf.pymupdf_version`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:432 e17b0b91f04f41c49b685ec88163c914\nmsgid \"`pymupdf.mupdf_version`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:433 b2b4d699826c44f3b82cbbffd7b8134e\nmsgid \"`pymupdf.pymupdf_date`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:436 0641d353405748829b979a38171a2825\nmsgid \"**Changes in version 1.24.5 (2024-05-30)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:440 d9b804a172e24fa782e586380589a791\nmsgid \"\"\n\"**Fixed** `3479 <https://github.com/pymupdf/PyMuPDF/issues/3479>`_: \"\n\"regression: fill_textbox: IndexError: pop from empty list\"\nmsgstr \"\"\n\n#: ../../../changes.txt:441 d00ec180a30548e7bd1094a5ff22289b\nmsgid \"\"\n\"**Fixed** `3488 <https://github.com/pymupdf/PyMuPDF/issues/3488>`_: \"\n\"set_toc method error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:445 53a42d7778c84e85ab793f4fc54ce4e8\nmsgid \"Some more fixes to use MuPDF floating formatting.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:446 8feda6eedae84994a727c20e7a2336be\nmsgid \"Removed/disabled some unnecessary diagnostics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:447 e96bd409e11d432aa398f8aeedd58c7a\nmsgid \"Fixed utils.do_links() crash.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:448 24e4d4aed05840ea9abe1c2c2805be34\nmsgid \"\"\n\"Experimental new functions `pymupdf.apply_pages()` and \"\n\"`pymupdf.get_text()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:449 b8a6f1cfb64748d79bc0b69465631b51\nmsgid \"Addresses wrong label generation for label styles \\\"a\\\" and \\\"A\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:452 0ba74ae644a1428d89fe14ef6b0babee\nmsgid \"**Changes in version 1.24.4 (2024-05-16)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:454 8347374b5a5e45b28a7f8f4afb292726\nmsgid \"\"\n\"**Fixed** `3418 <https://github.com/pymupdf/PyMuPDF/issues/3418>`_: Re-\"\n\"introduced bug, text align add_redact_annot\"\nmsgstr \"\"\n\n#: ../../../changes.txt:455 cb6d95a9123f4086b6ac158e88717571\nmsgid \"\"\n\"**Fixed** `3472 <https://github.com/pymupdf/PyMuPDF/issues/3472>`_: \"\n\"insert_pdf gives SystemError\"\nmsgstr \"\"\n\n#: ../../../changes.txt:459 c0361428884345bf8531a84f4780ea38\nmsgid \"\"\n\"Fixed sysinstall test failing to remove all of prior installation before \"\n\"new install.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:461 5889a769a9d6497db5651e5de06b452c\nmsgid \"Fixed `utils.do_links()` crash.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:462 18689db9f7b34a0aada6aabae6348c36\nmsgid \"Correct `TextPage` creation Code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:463 47ec7c100c6c4cb89c0c9032e653d85d\nmsgid \"Unified various diagnostics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:464 0ad11e95e8244ebab3b4e28a268c3b58\nmsgid \"Fix bug in `page_merge()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:467 b8f39f2e163741529a0c07525b38ee4e\nmsgid \"**Changes in version 1.24.3 (2024-05-09)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:470 cad11f9fca1541eda51c5b1ddc360907\nmsgid \"\"\n\"The Python module is now called `pymupdf`. `fitz` is still supported for \"\n\"backwards compatibility.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:473 26ab1d955ad94d82a842066be61b2b45\nmsgid \"Use MuPDF-1.24.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:477 d78b4e742a1540d795b9023df668616a\nmsgid \"\"\n\"**Fixed** `3357 <https://github.com/pymupdf/PyMuPDF/issues/3357>`_: \"\n\"PyMuPDF==1.24.0 will hanging when using page.get_text(\\\"text\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:478 d3a781ba5c1b4e4ea729e32165591767\nmsgid \"\"\n\"**Fixed** `3376 <https://github.com/pymupdf/PyMuPDF/issues/3376>`_: \"\n\"Redacting results are not as expected in 1.24.x.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:479 9d45832a290b4dec88aff88537dbbde6\nmsgid \"\"\n\"**Fixed** `3379 <https://github.com/pymupdf/PyMuPDF/issues/3379>`_: \"\n\"Documentation mismatch for get_text_blocks return value order.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:480 fb62ce84c5d24c1b802be0a91c9592fc\nmsgid \"\"\n\"**Fixed** `3381 <https://github.com/pymupdf/PyMuPDF/issues/3381>`_: \"\n\"Contents stream contains floats in scientific notation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:481 0862ddcf8e644d3ea7ac0a7c60de28d1\nmsgid \"\"\n\"**Fixed** `3402 <https://github.com/pymupdf/PyMuPDF/issues/3402>`_: \"\n\"Cannot add Widgets containing inter-field-calculation JavaScript\"\nmsgstr \"\"\n\n#: ../../../changes.txt:482 3d4f814eb5ec4e72a5adea1bd245b32f\nmsgid \"\"\n\"**Fixed** `3414 <https://github.com/pymupdf/PyMuPDF/issues/3414>`_: \"\n\"missing attribute set_dpi()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:483 cdcbe4b8d58544f0948c1b3c28f9b3d9\nmsgid \"\"\n\"**Fixed** `3430 <https://github.com/pymupdf/PyMuPDF/issues/3430>`_: \"\n\"page.get_text() cause process freeze with certain pdf on v1.24.2\"\nmsgstr \"\"\n\n#: ../../../changes.txt:487 ../../../changes.txt:509\n#: 1034de3f71fc4bd187b3f046c83bedbe 8863ca296ccc4716b6f80e99291be2e5\nmsgid \"New/modified methods:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:489 8cea70e9366142759f75487402e703b3\nmsgid \"\"\n\"`Page.remove_rotation()`: new, set page rotation to zero while keeping \"\n\"appearance.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:491 f1014ad8f9ec4d87968c7de24b7e7f70\nmsgid \"Fixed some problems when checking for PDF properties.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:492 64cfa246e9094b0ebd62758e2eb3598f\nmsgid \"\"\n\"Fixed pip builds from sdist (see discussion `3360 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/3360>`_: Alpine linux \"\n\"docker build failing \\\"No matching distribution found for \"\n\"pymupdfb==1.24.1\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:497 f8ef0c76081a402dbac0efa8b7644241\nmsgid \"**Changes in version 1.24.2 (2024-04-17)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:499 bf95d9b1e5994a2091c8f66685f22854\nmsgid \"\"\n\"Removed obsolete classic implementation from releases (previously \"\n\"available as module `fitz_old`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:504 4a87d3564d3d4cedae93e2b51349aaa2\nmsgid \"\"\n\"**Fixed** `3331 <https://github.com/pymupdf/PyMuPDF/issues/3331>`_: \"\n\"Document.pages() is incorrectly type-hinted\"\nmsgstr \"\"\n\n#: ../../../changes.txt:505 84e9e429e5af4263a7fd5db405b5842a\nmsgid \"\"\n\"**Fixed** `3354 <https://github.com/pymupdf/PyMuPDF/issues/3354>`_: \"\n\"PyMuPDF==1.24.1: AttributeError: property 'metadata' of 'Document' object\"\n\" has no setter\"\nmsgstr \"\"\n\n#: ../../../changes.txt:511 818e26cf4c0f4ce08f1bf68e48eab8b0\nmsgid \"`Document.bake()`: new, make annotations / fields permanent content.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:512 6a0b794fe12f4bb4a005a8f1bdc5c188\nmsgid \"\"\n\"`Page.cluster_drawings()`: new, identifies drawing items (i.e. vector \"\n\"graphics or line-art) that belong together based on their geometrical \"\n\"vicinity.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:515 f1fb556a239a49e6b90a938b0360868a\nmsgid \"`Page.apply_redactions()`: added new parameter `text`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:516 c47d84ec4dd34a6687719bcfafebdb25\nmsgid \"\"\n\"`Document.subset_fonts()`: use MuPDF's `pdf_subset_fonts()` instead of \"\n\"PyMuPDF code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:518 b56ff5e11e894337b35ae03c405c4666\nmsgid \"The `Document` class now supports page numbers specified as slices.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:519 68a2d9fa6804400dbecc0e1d60d85280\nmsgid \"Avoid causing MuPDF warnings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:522 167f53146b304aaf9812103ca9c4e29c\nmsgid \"**Changes in version 1.24.1 (2024-04-02)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:526 9dcf0965da0a489cabf3d2ab88226762\nmsgid \"\"\n\"**Fixed** `3278 <https://github.com/pymupdf/PyMuPDF/issues/3278>`_: \"\n\"apply_redactions moves some unredacted text\"\nmsgstr \"\"\n\n#: ../../../changes.txt:527 c23c377d35194a0094bd6e4beab89d9d\nmsgid \"\"\n\"**Fixed** `3301 <https://github.com/pymupdf/PyMuPDF/issues/3301>`_: Be \"\n\"more permissive when classifying links as kind LINK_URI\"\nmsgstr \"\"\n\n#: ../../../changes.txt:528 c6e16db559364535a9c002bd61adb627\nmsgid \"\"\n\"**Fixed** `3306 <https://github.com/pymupdf/PyMuPDF/issues/3306>`_: Text \"\n\"containing capital 'ET' not appearing as annotation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:532 ae65e5dcbdbb47e7b6182ae2f1e35080\nmsgid \"Use MuPDF-1.24.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:533 606e5f2a82694796b16017c9e6988751\nmsgid \"\"\n\"Support ObjStm Compression. Methods `Document.save()`, \"\n\"`Document.ez_save()` and `Document.write()` now support new parameters \"\n\"`use_objstm`, compression_effort` and `preserve_metadata`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:539 e0d826430dab4605843b857d55556f31\nmsgid \"**Changes in version 1.24.0 (2024-03-21)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:543 56ae3cb3eae74794bf8c66f9478e1eaa\nmsgid \"\"\n\"**Fixed** `3281 <https://github.com/pymupdf/PyMuPDF/issues/3281>`_: \"\n\"Preparing metadata (pyproject.toml) did not run successfully\"\nmsgstr \"\"\n\n#: ../../../changes.txt:544 c2af0005171741dfa062c48305fdff68\nmsgid \"\"\n\"**Fixed** `3279 <https://github.com/pymupdf/PyMuPDF/issues/3279>`_: \"\n\"PyMuPDF no longer builds in Alpine Linux\"\nmsgstr \"\"\n\n#: ../../../changes.txt:545 d9b6c05ed6004aca8f3189adad180c42\nmsgid \"\"\n\"**Fixed** `3257 <https://github.com/pymupdf/PyMuPDF/issues/3257>`_: \"\n\"apply_redactions() deleting text outside of annotated box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:546 8baeb884a8f84d2fbf0d5b17af55639c\nmsgid \"\"\n\"**Fixed** `3216 <https://github.com/pymupdf/PyMuPDF/issues/3216>`_: \"\n\"AttributeError: 'Annot' object has no attribute '__del__'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:547 37068b47c21542ccbcc5d6326e7046f1\nmsgid \"\"\n\"**Fixed** `3207 <https://github.com/pymupdf/PyMuPDF/issues/3207>`_: \"\n\"get_drawings's items is missing line from h path operator\"\nmsgstr \"\"\n\n#: ../../../changes.txt:548 a4e36666ffbc4aca8006de811d305b60\nmsgid \"\"\n\"**Fixed** `3201 <https://github.com/pymupdf/PyMuPDF/issues/3201>`_: \"\n\"Memory leaks when merging PDFs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:549 72cdc09b51ef425ab50c8aae8a380ce6\nmsgid \"\"\n\"**Fixed** `3197 <https://github.com/pymupdf/PyMuPDF/issues/3197>`_: \"\n\"page.get_text() returns hexadecimal text for some characters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:550 055ea678a07b4991b05894009ada4484\nmsgid \"\"\n\"**Fixed** `3196 <https://github.com/pymupdf/PyMuPDF/issues/3196>`_: \"\n\"Remove text not working in 1.23.25 version vs 1.20.2\"\nmsgstr \"\"\n\n#: ../../../changes.txt:551 eebdd0d853a04d7890db0116aeda3b84\nmsgid \"\"\n\"**Fixed** `3172 <https://github.com/pymupdf/PyMuPDF/issues/3172>`_: PDF's\"\n\" 45º lines disappearing in png conversion\"\nmsgstr \"\"\n\n#: ../../../changes.txt:552 fd48b5fe2cf74dbb8772e3ffda26cc5b\nmsgid \"\"\n\"**Fixed** `3135 <https://github.com/pymupdf/PyMuPDF/issues/3135>`_: Do \"\n\"not log warnings to stdout\"\nmsgstr \"\"\n\n#: ../../../changes.txt:553 5a2c034748ca435d97157e0e01631edc\nmsgid \"\"\n\"**Fixed** `3125 <https://github.com/pymupdf/PyMuPDF/issues/3125>`_: \"\n\"get_pixmap method stuck on one page and runs forever\"\nmsgstr \"\"\n\n#: ../../../changes.txt:554 2b0bc004e652473d8424fbaf44acc132\nmsgid \"\"\n\"**Fixed** `2964 <https://github.com/pymupdf/PyMuPDF/issues/2964>`_: There\"\n\" is an issue with the image generated by the page.get_pixmap() function\"\nmsgstr \"\"\n\n#: ../../../changes.txt:558 7489ffec843d457ca500cfb476753615\nmsgid \"Use MuPDF-1.24.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:559 7c55068e2bc44f7a90942db48624c211\nmsgid \"Add support for redacting vector graphics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:560 994636840ff242bb90c2538f8b313764\nmsgid \"Several fixes for table module\"\nmsgstr \"\"\n\n#: ../../../changes.txt:562 1cde4b0108a34c66bcf26a1e69169d92\nmsgid \"Add new method for outputting the table as a markdown string.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:564 9fcf8beb4cbf4808b3636964252fb397\nmsgid \"Address errors in computing the table header object:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:566 466f446d303f45039a8d621fa72be582\nmsgid \"\"\n\"We now allow None as the cell value, because this will be resolved where \"\n\"needed (e.g. in the pandas DataFrame).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:569 b1456724d60f446b99497879dec77edc\nmsgid \"\"\n\"We previously tried to enforce rect-like tuples in all header cell \"\n\"bboxes, however this fails for tables with all-None columns.  This fix \"\n\"enables this and constructs an empty string in the corresponding cell \"\n\"string.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:574 bd966cd782ae48e6bf574d6aa1e75969\nmsgid \"\"\n\"We now correctly include start / stop points of lines in the bbox of the \"\n\"clustered graphic.  We previously joined the line's rectangle - which had\"\n\" no effect because this is always empty.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:578 8b34024dc26b46d6bb00721aee57b203\nmsgid \"Improved exception text if we fail to open document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:579 2ad46d306493434ba2f21cbc55598c4e\nmsgid \"Fixed build with new libclang 18.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:582 e0f45c4d68334077bde30abcb37f442c\nmsgid \"**Changes in version 1.23.26 (2024-02-29)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:586 2f2ec05926254e2f9d6790002f8f0dbb\nmsgid \"\"\n\"**Fixed** `3199 <https://github.com/pymupdf/PyMuPDF/issues/3199>`_: Add \"\n\"entry_points to setuptools configuration to provide command-line console \"\n\"scripts\"\nmsgstr \"\"\n\n#: ../../../changes.txt:587 254166b6829a47ebae52f0d1befd4f8c\nmsgid \"\"\n\"**Fixed** `3209 <https://github.com/pymupdf/PyMuPDF/issues/3209>`_: Empty\"\n\" vertices in ink annotation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:591 72a0f38fcb3f4fadae2a9750a83ecf70\nmsgid \"Improvements to table detection:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:593 70ae893cd45741a59c2a753e1efe9d04\nmsgid \"\"\n\"Improved check for empty tables, fixes bugs when determining table \"\n\"headers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:594 db5ad6c22fa8479fb66f6ada59044c7e\nmsgid \"Improved computation of enveloping vector graphic rectangles.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:595 7f5ea75a3d2b47809b85588c78b70318\nmsgid \"Ignore more meaningless \\\"pseudo\\\" tables\"\nmsgstr \"\"\n\n#: ../../../changes.txt:597 6cd939d409f341f6a264ff3b4624cca6\nmsgid \"Install command-line 'pymupdf' command that runs fitz/__main__.py.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:598 6afb7824085740ccaf2fc01c782dffcb\nmsgid \"Don't overwrite MuPDF's config.h when building on non-Windows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:599 86e24a39bb0541a4ac1e71e88541c698\nmsgid \"\"\n\"Fix `Story` constructor's `archive` arg to match docs - now accepts a \"\n\"single `Archive` constructor arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:600 a3ea96e9f72f483bbf461ca1d128b1e4\nmsgid \"\"\n\"Do not include MuPDF source in sdist; will be downloaded automatically \"\n\"when building.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:603 b80b43ad742c43ab9880dd54056a9973\nmsgid \"**Changes in version 1.23.25 (2024-02-20)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:607 ea65b6e10b4443fd98d4487f8a6227ce\nmsgid \"\"\n\"**Fixed** `3182 <https://github.com/pymupdf/PyMuPDF/issues/3182>`_: \"\n\"Pixmap.invert_irect argument type error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:608 420d27a70b34444aba118e43db9e4802\nmsgid \"\"\n\"**Fixed** `3186 <https://github.com/pymupdf/PyMuPDF/issues/3186>`_: \"\n\"extractText() extracts broken text from pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:609 90aadcf4b788454abbf2665a0b7b8f22\nmsgid \"\"\n\"**Fixed** `3191 <https://github.com/pymupdf/PyMuPDF/issues/3191>`_: Error\"\n\" on .find_tables()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:613 0a5a831494a04b18b50fdfc5d3833038\nmsgid \"\"\n\"When building, be able to specify python-config directly, with \"\n\"environment variable `PIPCL_PYTHON_CONFIG`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:617 93b9bfcd66aa426eaacb92d54e23c667\nmsgid \"**Changes in version 1.23.24 (2024-02-19)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:621 3748e8d370624cd1889b240a694cc72e\nmsgid \"\"\n\"**Fixed** `3148 <https://github.com/pymupdf/PyMuPDF/issues/3148>`_: Table\"\n\" extraction - vertical text not handled correctly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:622 0017cea29f1247be99c102c56a8fabd1\nmsgid \"\"\n\"**Fixed** `3179 <https://github.com/pymupdf/PyMuPDF/issues/3179>`_: Table\"\n\" Detection: Incorrect Separation of Vector Graphics Clusters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:623 dde9c50cb60147428936ac9e5bdacc81\nmsgid \"\"\n\"**Fixed** `3180 <https://github.com/pymupdf/PyMuPDF/issues/3180>`_: \"\n\"Cannot show optional content group: AttributeError: module 'fitz.mupdf' \"\n\"has no attribute 'pdf_array_push_drop'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:627 838816f12e394f49b9e2ef7b4559fd71\nmsgid \"Be able to test system install using `sudo pip install` instead of a venv.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:630 0b4ca8027622493090312b1e74a4839a\nmsgid \"**Changes in version 1.23.23 (2024-02-18)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:634 5c5c4b53219b4e8492fec8aafaa14b7e\nmsgid \"\"\n\"**Fixed** `3126 <https://github.com/pymupdf/PyMuPDF/issues/3126>`_: \"\n\"Initialising Archive with a pathlib.Path fails.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:635 e5745b8508084965a56f4151794f8378\nmsgid \"\"\n\"**Fixed** `3131 <https://github.com/pymupdf/PyMuPDF/issues/3131>`_: \"\n\"Calling the next attribute of an Annot raises a \\\"No attribute .parent\\\" \"\n\"warning\"\nmsgstr \"\"\n\n#: ../../../changes.txt:636 59d2c178ba9c4d47977704a9feccc1ea\nmsgid \"\"\n\"**Fixed** `3134 <https://github.com/pymupdf/PyMuPDF/issues/3134>`_: Using\"\n\" an IRect as clip parameter in Page.get_pixmap no longer works since \"\n\"1.23.9\"\nmsgstr \"\"\n\n#: ../../../changes.txt:637 43be27e8f82c45ef90522a9da30a0a72\nmsgid \"\"\n\"**Fixed** `3140 <https://github.com/pymupdf/PyMuPDF/issues/3140>`_: PDF \"\n\"document stays in use after closing\"\nmsgstr \"\"\n\n#: ../../../changes.txt:638 cbe3a25490474db9973829ac9e661e5b\nmsgid \"\"\n\"**Fixed** `3150 <https://github.com/pymupdf/PyMuPDF/issues/3150>`_: \"\n\"doc.select() hangs on this doc.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:639 b40c96dbbba64f6f82a0dbc3fb5570db\nmsgid \"\"\n\"**Fixed** `3163 <https://github.com/pymupdf/PyMuPDF/issues/3163>`_: \"\n\"AssertionError on using fitz.IRect\"\nmsgstr \"\"\n\n#: ../../../changes.txt:640 5b0e909d8b1c42c4815f57178c08f1d0\nmsgid \"\"\n\"**Fixed** `3177 <https://github.com/pymupdf/PyMuPDF/issues/3177>`_: \"\n\"fitz.Pixmap(None, pix) Unrecognised args for constructing Pixmap\"\nmsgstr \"\"\n\n#: ../../../changes.txt:645 bcff5266d81d44828538dd318c25c548\nmsgid \"\"\n\"Improved `Document.select() by using new MuPDF function \"\n\"`pdf_rearrange_pages()`. This is a more complete (and faster) \"\n\"implementation of what needs to be done here in that not only pages will \"\n\"be rearranged, but also consequential changes will be made to the table \"\n\"of contents, links to removed pages and affected entries in the Optional \"\n\"Content definitions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:651 7e5e70f9786348e485e9f480c4c5f649\nmsgid \"`TextWriter.appendv()`: added `small_caps` arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:652 511da4bdc4cb4d488b5540f7118d05c6\nmsgid \"Fixed some valgrind errors with MuPDF master.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:653 9fa27b2a0f6542779698b58b6ef2797f\nmsgid \"Fixed `Document.insert_image()` when build with MuPDF master.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:656 8215b8e723014b82adeefa3d490e76cf\nmsgid \"**Changes in version 1.23.22 (2024-02-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:660 9499acfbd68c4038bf82444da1a07c47\nmsgid \"\"\n\"**Fixed** `3143 <https://github.com/pymupdf/PyMuPDF/issues/3143>`_: \"\n\"Difference in decoding of OCGs names between doc.get_ocgs() and \"\n\"page.get_drawings()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:662 6a05eddb0f5846589fe4c0086fc9e146\nmsgid \"\"\n\"**Fixed** `3139 <https://github.com/pymupdf/PyMuPDF/issues/3139>`_: \"\n\"Pixmap resizing needs positional arg \\\"clip\\\" - even if None.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:666 9a6bd516b5734957b5d8700fec418b18\nmsgid \"Removed the use of MuPDF function `fz_image_size()` from PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:669 32b339e622b6447890c25a4ab191fd39\nmsgid \"**Changes in version 1.23.21 (2024-02-01)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:675 fab60867577a487b9c3f486166614839\nmsgid \"\"\n\"Fixed bug in set_xml_metadata(), PR `3112 \"\n\"<https://github.com/pymupdf/PyMuPDF/pull/3112>`_: Fix pdf_add_stream \"\n\"metadata error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:676 5db3c0df43d7466bb49c93da76eb7ded\nmsgid \"Fixed lack of `.parent` member in `TextPage` from `Annot.get_textpage()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:677 6886cfc95dcf48449baf3597f9ed5a5b\nmsgid \"Fixed bug in `Page.add_widget()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:680 466b6a96778a400fa703f8a164dc6006\nmsgid \"**Changes in version 1.23.20 (2024-01-29)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:682 ../../../changes.txt:693 ../../../changes.txt:711\n#: ../../../changes.txt:723 ../../../changes.txt:737 ../../../changes.txt:750\n#: ../../../changes.txt:761 ../../../changes.txt:773 ../../../changes.txt:797\n#: ../../../changes.txt:917 ../../../changes.txt:934 ../../../changes.txt:966\n#: ../../../changes.txt:1023 ../../../changes.txt:1099\n#: ../../../changes.txt:1133 ../../../changes.txt:1142\n#: ../../../changes.txt:1151 ../../../changes.txt:1169\n#: ../../../changes.txt:1269 ../../../changes.txt:1308\n#: 10bae71e3a574059884b4f1d5baea65c 11746df9cf7b4144bc9cabc8e95b78a9\n#: 35c5e4be6606427a95322276ca783f0e 4bbb30be5f60421a87e36a340ddbe65f\n#: 524f6c6556b5468c90bac3e6f81b279d 5a44d84debe5475da967de80ba53914b\n#: 5ed487b98bc84f92a08fdb4934e8535b 74166ebee93f4e9e999f1cd22be78aaf\n#: 780c7d9984234abebe430e3254afc4e8 a47d1d46827b45bebe969ac04f21dc0f\n#: a6ae2f8c435749c4a8dc5fbe5c95dff6 a776aae290f74bdfaa636b31d9b933e0\n#: bb6b3124820a4512a56446f360c94404 c7fa8793bb6d44aca1771c6152ac83d8\n#: d22de0587ab24d4ab437626e883261d4 dd73709cf4c74a6e9d9a8eba46753cd2\n#: e4a33a6c03dd49d0a338e5b67900cac8 f7e8261277e44b8abe33e6e0f05bcde7\n#: f98503e4ea7c425391e56ac00fbae870 fc10345ba347482ba6bf7042461f8232\nmsgid \"Bug fixes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:684 e101eae15b004da2849ab4be087a4010\nmsgid \"\"\n\"**Fixed** `3100 <https://github.com/pymupdf/PyMuPDF/issues/3100>`_: Wrong\"\n\" internal property accessed in get_xml_metadata\"\nmsgstr \"\"\n\n#: ../../../changes.txt:688 30795d0573e140c88dd4cf9e6887fbe0\nmsgid \"Significantly improved speed of `Document.get_toc()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:691 f23cca9b1fc84d0ea474332f2e1c6c2c\nmsgid \"**Changes in version 1.23.19 (2024-01-25)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:695 36758073da3a48f5bc485fd6a9fc328e\nmsgid \"\"\n\"**Fixed** `3087 <https://github.com/pymupdf/PyMuPDF/issues/3087>`_: \"\n\"Exception in insert_image with mask specified\"\nmsgstr \"\"\n\n#: ../../../changes.txt:696 202f997680f84ed9b7bf363b2b348028\nmsgid \"\"\n\"**Fixed** `3094 <https://github.com/pymupdf/PyMuPDF/issues/3094>`_: \"\n\"TypeError: '<' not supported between instances of 'FzLocation' and 'int' \"\n\"in doc.delete_pages\"\nmsgstr \"\"\n\n#: ../../../changes.txt:700 b8dceb00014f42ccb7877fe431320209\nmsgid \"When finding tables:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:702 311dca44e7df40e0a0c2ece5cca045f3\nmsgid \"\"\n\"Allow addition of user-defined \\\"virtual\\\" vector graphics when finding \"\n\"tables.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:703 743195d5487f4c79b7dea4defa19efdb\nmsgid \"\"\n\"Confirm that the enveloping bboxes of vector graphics are inside the clip\"\n\" rectangle.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:704 91bcfe988eab4abe82d29ec6a73c24ac\nmsgid \"Avoid slow finding of rectangle intersections.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:706 6fbf98c2146642699598279e74ace969\nmsgid \"Added `Font.bbox` property.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:709 02dd1c5dc69346c3aa052addbe84f62d\nmsgid \"**Changes in version 1.23.18 (2024-01-23)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:713 e98e1fa4a6be43e19c1235f235206973\nmsgid \"\"\n\"**Fixed** `3081 <https://github.com/pymupdf/PyMuPDF/issues/3081>`_: \"\n\"doc.close() not closing the document\"\nmsgstr \"\"\n\n#: ../../../changes.txt:717 da8086b4179148e78eef2c50eb3cd527\nmsgid \"\"\n\"Reduced size of sdist to fit on pypi.org (by reducing size of two test \"\n\"files).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:718 0b7e1df1d1024f52810b0f1778d8d2de\nmsgid \"Fix `Annot.file_info()` if no `Desc` item.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:721 df117a0a6648402e8810ca3b417979b4\nmsgid \"**Changes in version 1.23.17 (2024-01-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:725 37f262e5ed6b4d118a5a82e4beb2b4ad\nmsgid \"\"\n\"**Fixed** `3062 <https://github.com/pymupdf/PyMuPDF/issues/3062>`_: \"\n\"page_rotation_reset does not return page to original rotation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:726 f86ef7904604429884e4c81fcf5ae787\nmsgid \"\"\n\"**Fixed** `3070 <https://github.com/pymupdf/PyMuPDF/issues/3070>`_: \"\n\"update_link(): AttributeError: 'Page' object has no attribute 'super'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:730 6c6a0371126c46b0bcc8ebc5df7be344\nmsgid \"Fixed bug in `Page.links()` (PR #3075).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:731 a9475e5785414f199b597f416d8e1f8d\nmsgid \"Fixed bug in `Page.get_bboxlog()` with layers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:732 8867fda0c26e4548b930e7d40da999bc\nmsgid \"Add support for timeouts in scripts/ and tests/run_compound.py.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:735 50f7599b93df4914acc301398f9fb589\nmsgid \"**Changes in version 1.23.16 (2024-01-18)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:739 98d0c677086e45b8aefb2561c344d108\nmsgid \"\"\n\"**Fixed** `3058 <https://github.com/pymupdf/PyMuPDF/issues/3058>`_: \"\n\"Pixmap created from CMYK JPEG delivers RGB format\"\nmsgstr \"\"\n\n#: ../../../changes.txt:743 6280e0fb16044307be72a98e78055199\nmsgid \"\"\n\"In table detection strategy \\\"lines_strict\\\", exclude fill-only vector \"\n\"graphics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:744 7b87c57e26184d6fab0bf49037ae0ee0\nmsgid \"Fixed sysinstall test failure.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:745 479fcf54b5cc40719b42543c6b8eb8d7\nmsgid \"In documentation, update feature matrix with item about text writing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:748 a58ed680108b456f811bd161fcda9c91\nmsgid \"**Changes in version 1.23.15 (2024-01-16)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:752 db43cbaa428745bbbc155e1449a46274\nmsgid \"\"\n\"**Fixed** `3050 <https://github.com/pymupdf/PyMuPDF/issues/3050>`_: \"\n\"python3.9 pix.set_pixel has something wrong in c.append( ord(i))\"\nmsgstr \"\"\n\n#: ../../../changes.txt:756 85116010a87b4782a3c2cf37d6d3c233\nmsgid \"Improved docs for Page.find_tables().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:759 a0e9d51dec614dd5aad7a32d5195c117\nmsgid \"**Changes in version 1.23.14 (2024-01-15)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:763 a147e66fe72c47f7ab10b2211f76dd3f\nmsgid \"\"\n\"**Fixed** `3038 <https://github.com/pymupdf/PyMuPDF/issues/3038>`_: \"\n\"JM_pixmap_from_display_list > Assertion Error : Checking for wrong type\"\nmsgstr \"\"\n\n#: ../../../changes.txt:764 8e99271499a243a0ad21780cd0aa3b4f\nmsgid \"\"\n\"**Fixed** `3039 <https://github.com/pymupdf/PyMuPDF/issues/3039>`_: Issue\"\n\" with doc.close() not closing the document in PyMuPDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:768 3976a531e434472590b8052395aea031\nmsgid \"\"\n\"Ensure valid \\\"re\\\" rectangles in `Page.get_drawings()` with derotated \"\n\"pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:771 082bdc523e1f473f85543e64d3853ad8\nmsgid \"**Changes in version 1.23.13 (2024-01-15)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:775 797a7ea0082844de9aa334285db2046a\nmsgid \"\"\n\"**Fixed** `2979 <https://github.com/pymupdf/PyMuPDF/issues/2979>`_: list \"\n\"index out of range in to_pandas()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:776 95667931dbcb4237bae8f4c9af83594b\nmsgid \"\"\n\"**Fixed** `3001 <https://github.com/pymupdf/PyMuPDF/issues/3001>`_: \"\n\"Calling find_tables() on one document alters the bounding boxes of a \"\n\"subsequent document\"\nmsgstr \"\"\n\n#: ../../../changes.txt:780 186cd9d07f9b4a58beb7e8e41f3bc17d\nmsgid \"Fixed `Rect.height` and `Rect.width` to never return negative values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:781 27c5d3626f094ec5863b809e2a812c25\nmsgid \"Fixed `TextPage.extractIMGINFO()`'s returned `dictkey_yres` value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:784 8255dfd1b9d149ba8ce261e1ceaff664\nmsgid \"**Changes in version 1.23.12 (2024-01-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:786 5bb9f57d3682407b99532c75233dba1f\nmsgid \"\"\n\"**Fixed** `3027 <https://github.com/pymupdf/PyMuPDF/issues/3027>`_: \"\n\"Page.get_text throws Attribute Error for 'parent'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:789 2dae2447cbb74e1fb8e1a42264ec7e70\nmsgid \"**Changes in version 1.23.11 (2024-01-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:791 cd671647a36347d9b8adbfb7ee2447a9\nmsgid \"Fixed some Pixmap construction bugs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:792 e891dfad684a4752b4e5805a6293dfcf\nmsgid \"Fixed Pixmap.yres().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:795 f131f3b1f3b641e989cfeab5425a3e9c\nmsgid \"**Changes in version 1.23.10 (2024-01-12)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:799 ac50349144d841ab902a3ae407ef8714\nmsgid \"\"\n\"**Fixed** `3020 <https://github.com/pymupdf/PyMuPDF/issues/3020>`_: Can't\"\n\" resize a PixMap\"\nmsgstr \"\"\n\n#: ../../../changes.txt:803 3f395fa335f948a6bf2ec8e7dca4ea01\nmsgid \"Fixed Page.delete_image().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:806 c60fab8d493747628cff1c624cb39043\nmsgid \"**Changes in version 1.23.9 (2024-01-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:808 1fa84ae4248d423485aa5cb183570533\nmsgid \"Default to new \\\"rebased\\\" implementation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:810 950a6848918d4d6b80203a0558ed5266\nmsgid \"\"\n\"The old \\\"classic\\\" implementation is available with `import fitz_old as \"\n\"fitz`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:811 bebd4b40a6314a9b99d384b13f921a74\nmsgid \"\"\n\"For more information about why we are changing to the rebased \"\n\"implementation, see: https://github.com/pymupdf/PyMuPDF/discussions/2680\"\nmsgstr \"\"\n\n#: ../../../changes.txt:814 0a613f5215304e7b922f3fbb0c54ad9c\nmsgid \"Use MuPDF-1.23.9.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:816 ../../../changes.txt:848\n#: 79b8f33e4c684085bbd12543c914a92c ed73712d903c42daa048538222480c72\nmsgid \"Bug fixes (rebased implementation only):\"\nmsgstr \"\"\n\n#: ../../../changes.txt:818 f0a68870dc7e4101b40fb65d25d18b5a\nmsgid \"\"\n\"**Fixed** `2911 <https://github.com/pymupdf/PyMuPDF/issues/2911>`_: \"\n\"Page.derotation_matrix returns a tuple instead of a Matrix with rebased \"\n\"implementation\"\nmsgstr \"\"\n\n#: ../../../changes.txt:819 b056b928a27c4740bfc45a1e268ab0d2\nmsgid \"\"\n\"**Fixed** `2919 <https://github.com/pymupdf/PyMuPDF/issues/2919>`_: \"\n\"Rebased version: KeyError in resolve_names when merging pdfs\"\nmsgstr \"\"\n\n#: ../../../changes.txt:820 736154fa84784e259b795c962116ed21\nmsgid \"\"\n\"**Fixed** `2922 <https://github.com/pymupdf/PyMuPDF/issues/2922>`_: New \"\n\"feature that allows inserting named-destination links doesn't work\"\nmsgstr \"\"\n\n#: ../../../changes.txt:821 bfe6879a0e3449928a0e143e35d1973d\nmsgid \"\"\n\"**Fixed** `2943 <https://github.com/pymupdf/PyMuPDF/issues/2943>`_: \"\n\"ZeroDivisionError: float division by zero when use apply_redactions()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:822 3aea2bcd6a984d8f8e814d25a05ea0cd\nmsgid \"\"\n\"**Fixed** `2950 <https://github.com/pymupdf/PyMuPDF/issues/2950>`_: \"\n\"Shelling out to pip during tests is problematic\"\nmsgstr \"\"\n\n#: ../../../changes.txt:823 64a074a99c094bf2b64bf0a1175cfd6e\nmsgid \"\"\n\"**Fixed** `2954 <https://github.com/pymupdf/PyMuPDF/issues/2954>`_: \"\n\"Replacement unicode character in text extraction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:824 f1ab1e9632c440a1ad3ddceab5970793\nmsgid \"\"\n\"**Fixed** `2957 <https://github.com/pymupdf/PyMuPDF/issues/2957>`_: \"\n\"apply_redactions() moving text\"\nmsgstr \"\"\n\n#: ../../../changes.txt:825 be824c3a45bd4be0b2bc52d892f31652\nmsgid \"\"\n\"**Fixed** `2961 <https://github.com/pymupdf/PyMuPDF/issues/2961>`_: \"\n\"Passing a string as a page number raises IndexError instead of TypeError.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:826 e776dd1532cf4e4b930371d30841afe9\nmsgid \"\"\n\"**Fixed** `2969 <https://github.com/pymupdf/PyMuPDF/issues/2969>`_: \"\n\"annot.next throws AttributeError\"\nmsgstr \"\"\n\n#: ../../../changes.txt:827 ac77c79a100942f8a6159beb24f4e67a\nmsgid \"\"\n\"**Fixed** `2978 <https://github.com/pymupdf/PyMuPDF/issues/2978>`_: \"\n\"1.23.9rc1: module 'fitz.mupdf' has no attribute 'fz_copy_pixmap_rect'\"\nmsgstr \"\"\n\n#: ../../../changes.txt:829 362af45c412f45c39a1d822fab1286b1\nmsgid \"\"\n\"**Fixed** `2907 <https://github.com/pymupdf/PyMuPDF/issues/2907>`_: \"\n\"segfault trying to call clean_contents on certain pdfs with python 3.12\"\nmsgstr \"\"\n\n#: ../../../changes.txt:830 c1135c0939ef4daab6a8385631c53704\nmsgid \"\"\n\"**Fixed** `2905 <https://github.com/pymupdf/PyMuPDF/issues/2905>`_: \"\n\"SystemError: <built-in function TextPage_extractIMGINFO> returned a \"\n\"result with an exception set\"\nmsgstr \"\"\n\n#: ../../../changes.txt:831 a9d0e8515e0c4113af2e60251120838a\nmsgid \"\"\n\"**Fixed** `2742 <https://github.com/pymupdf/PyMuPDF/issues/2742>`_: \"\n\"Segmentation Fault when inserting three (but not two) copies of the same \"\n\"source page into one destination page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:835 bdbbaa0c597e4d8690d2acc01a05a511\nmsgid \"Add optional setting of opacity to `Page.insert_htmlbox()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:836 ec4580cff71a44b881bd2289b03e1e76\nmsgid \"Fixed issue with add_redact_annot() mentioned in #2934.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:837 37a7489f60b24988aabf68ab765c53aa\nmsgid \"\"\n\"Fixed `Page.rotation()` to return 0 for non-PDF documents instead of \"\n\"raising an exception.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:838 c15327390f2c412599adc9f6c2cd41eb\nmsgid \"Fixed internal quad detection to cope with any Python sequence.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:839 b5b25dcbb0e04533b6f266160078d7ac\nmsgid \"\"\n\"Fixed rebased `fitz.pymupdf_version_tuple` - was previously set to mupdf \"\n\"version.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:840 417b49c5b97a43b2884451f91a6ccd72\nmsgid \"\"\n\"Improved support for Linux system installs, including adding regular \"\n\"testing on Github.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:841 dc9b6649df764b6d8bdd0aeb241c8116\nmsgid \"Add missing `flake8` to `scripts/gh_release.py:test_packages`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:842 526255ea77784aa5a86322e409396fbf\nmsgid \"Use newly public functions in MuPDF-1.23.8.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:843 78af7dcf823d4333b745e1411e2535c0\nmsgid \"Improved `scripts/test.py` to help investigation of MuPDF issues.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:846 c4377b33474d4f08b8bb6ea1785e8cae\nmsgid \"**Changes in version 1.23.8 (2023-12-19)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:850 06bc7d28ba624f879fc3f4225f042ebd\nmsgid \"\"\n\"**Fixed** `2634 <https://github.com/pymupdf/PyMuPDF/issues/2634>`_: \"\n\"get_toc and set_toc do not behave consistently for rotated pages\"\nmsgstr \"\"\n\n#: ../../../changes.txt:851 eaabee50b85a41f5a1eee3082375a7d5\nmsgid \"\"\n\"**Fixed** `2861 <https://github.com/pymupdf/PyMuPDF/issues/2861>`_: \"\n\"AttributeError in getLinkDict during PDF Merge\"\nmsgstr \"\"\n\n#: ../../../changes.txt:852 11a45b3c36814980abef6db057685eef\nmsgid \"\"\n\"**Fixed** `2871 <https://github.com/pymupdf/PyMuPDF/issues/2871>`_: \"\n\"KeyError in getLinkDict during PDF merge\"\nmsgstr \"\"\n\n#: ../../../changes.txt:853 f6127a8b2c46475da27184f59e39e7ef\nmsgid \"\"\n\"**Fixed** `2886 <https://github.com/pymupdf/PyMuPDF/issues/2886>`_: Error\"\n\" in Skeleton for Named Link Destinations\"\nmsgstr \"\"\n\n#: ../../../changes.txt:855 ../../../changes.txt:888\n#: 586f106b986842b08028b0f5f627f7ca d8af7ffde72c450d915b0463309a4314\nmsgid \"Bug fixes (rebased and classic implementations):\"\nmsgstr \"\"\n\n#: ../../../changes.txt:857 b33ad6378a46458cb75ad39284db9641\nmsgid \"\"\n\"**Fixed** `2885 <https://github.com/pymupdf/PyMuPDF/issues/2885>`_: \"\n\"pymupdf find tables too slow\"\nmsgstr \"\"\n\n#: ../../../changes.txt:861 ../../../changes.txt:901\n#: 4728a8ecae8e40aa81aac714354f5cd8 dfafbc41ed064d4e9417228eef3b8869\nmsgid \"Rebased implementation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:863 d5e148c0135c420faee01c379333d863\nmsgid \"\"\n\"`Page.insert_htmlbox()`: new, much more powerful alternative to \"\n\"`Page.insert_textbox()` or `TextWriter.fill_textbox()`, using `Story`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:864 61b9573e3d5140e89cab3a5f2306ae99\nmsgid \"`Story.fit*()`: new methods for fitting a Story into an expanded rect.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:865 2c6161c5bc974598a30735ae4181b27c\nmsgid \"`Story.write_with_links()`: add support for external links.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:866 98b4230a54804ef4acb0b180f44e9ae5\nmsgid \"\"\n\"`Document.language()`: fixed to use MuPDF's new \"\n\"`mupdf.fz_string_from_text_language2()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:867 40995750950149ef83a0d8f6ddad76ef\nmsgid \"`Document.subset_fonts()` - fixed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:868 8f0552b58651471a97e511567a32e0c2\nmsgid \"Fixed internal `Archive._add_treeitem()` method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:869 87b1222b024441dea38cf29daba33184\nmsgid \"\"\n\"Fixed `fitz_new.__doc__` to contain PyMuPDF and Python version \"\n\"information, and OS name.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:870 386cb55b9f0c4087ae1996bb06b51a33\nmsgid \"\"\n\"Removed use of `(*args, **kwargs)` in API, we now specify keyword args \"\n\"explicitly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:871 c59b0cc5fecc4bdd9562cd2ce75075d3\nmsgid \"Work with new MuPDF Python exception classes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:873 e3e5a541241440ed9d367ef19430a835\nmsgid \"\"\n\"Fixed bug where `button_states()` returns None when `/AP` points to an \"\n\"indirect object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:874 5af1990cff754cd89a3aa438eb9d383b\nmsgid \"\"\n\"Fixed pillow test to not ignore all errors, and install pillow when \"\n\"testing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:875 1f1299ee32f346b6b3729cf40091e92c\nmsgid \"\"\n\"Added test for `fitz.css_for_pymupdf_font()` (uses package `pymupdf-\"\n\"fonts`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:876 8a8e3b21e7fe474598e60c7c3d327f5b\nmsgid \"Simplified Github Actions test specifications.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:877 285e6db854b84f7fab4a2c650152d2a2\nmsgid \"Updated `tests/README.md`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:880 25533a44e1824331b867fb200db45187\nmsgid \"**Changes in version 1.23.7 (2023-11-30)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:882 583b1de242bb4157b4445d6446ee6bbb\nmsgid \"Bug fixes in rebased implementation, not fixed in classic implementation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:884 235fe8226daa4b0abbac192cae7fd37a\nmsgid \"\"\n\"**Fixed** `2232 <https://github.com/pymupdf/PyMuPDF/issues/2232>`_: \"\n\"Geometry helper classes should support keyword arguments\"\nmsgstr \"\"\n\n#: ../../../changes.txt:885 e575834fcd73477b81b61829f22f495d\nmsgid \"\"\n\"**Fixed** `2788 <https://github.com/pymupdf/PyMuPDF/issues/2788>`_: \"\n\"Problem with get_toc in pymupdf 1.23.6\"\nmsgstr \"\"\n\n#: ../../../changes.txt:886 48886ca53b3d4f75bb21c99311bdb5f3\nmsgid \"\"\n\"**Fixed** `2791 <https://github.com/pymupdf/PyMuPDF/issues/2791>`_: \"\n\"Experiencing small memory leak in save()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:890 10a6b50400ed447497a29b25510f48e4\nmsgid \"\"\n\"**Fixed** `2736 <https://github.com/pymupdf/PyMuPDF/issues/2736>`_: \"\n\"Failure when set cropbox with mediabox negative value\"\nmsgstr \"\"\n\n#: ../../../changes.txt:891 2a0b37db8390439fbb646a9c37103f52\nmsgid \"\"\n\"**Fixed** `2749 <https://github.com/pymupdf/PyMuPDF/issues/2749>`_: \"\n\"RuntimeError: cycle in structure tree\"\nmsgstr \"\"\n\n#: ../../../changes.txt:892 3d06cf904a104c3d90b146fa78bf69ef\nmsgid \"\"\n\"**Fixed** `2753 <https://github.com/pymupdf/PyMuPDF/issues/2753>`_: \"\n\"Story.write_with_links will ignore everything after the first \\\"page \"\n\"break\\\" in the HTML.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:893 8a53b50ea2524665955b3157294a2b2d\nmsgid \"\"\n\"**Fixed** `2812 <https://github.com/pymupdf/PyMuPDF/issues/2812>`_: \"\n\"find_tables on landscape page generates reversed text\"\nmsgstr \"\"\n\n#: ../../../changes.txt:894 888fb15372974a36b1fe3d66ef22e391\nmsgid \"\"\n\"**Fixed** `2829 <https://github.com/pymupdf/PyMuPDF/issues/2829>`_: \"\n\"[cannot create /Annot for kind] is still printed despite #2345 is closed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:895 4bddd57842e24f349a1d201577c84f44\nmsgid \"\"\n\"**Fixed** `2841 <https://github.com/pymupdf/PyMuPDF/issues/2841>`_: \"\n\"Unexpected KeyError when using scrub with fitz_new\"\nmsgstr \"\"\n\n#: ../../../changes.txt:897 94aee473c47b4b39a4c3c4cb53567f41\nmsgid \"Use MuPDF-1.23.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:903 bec49d14f00548e4b548e3392c71e4f9\nmsgid \"Added flake8 code checking to test suite, and made various fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:904 5c2f03ef2da94a85b04bdcaa6b4452b2\nmsgid \"\"\n\"Disable diagnostics during Document constructor to match classic \"\n\"implementation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:906 614caa01606b4df1a5f36c79ba7597dc\nmsgid \"\"\n\"Additional fix to `2553 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/2553>`_: Invalid characters in\"\n\" versions >= 1.22\"\nmsgstr \"\"\n\n#: ../../../changes.txt:907 249c2e20b6584ff5bde073c96d14cef8\nmsgid \"\"\n\"Fixed `MuPDF Bug 707324 \"\n\"<https://bugs.ghostscript.com/show_bug.cgi?id=707324>`_: Story: HTML \"\n\"table row background color repeated incorrectly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:908 40274b78dadb4924955e4fcee62c82e9\nmsgid \"Added `scripts/test.py`, for simple build+test of PyMuPDF git checkout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:909 f4348c71af1f40479d9eb7d08fdba3aa\nmsgid \"Added `fitz.pymupdf_version_tuple`, e.g. `(1, 23, 6)`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:910 0125831c6ca04067b9605b86aefa7ebb\nmsgid \"\"\n\"Restored mistakenly-reverted fix for `2345 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/2345>`_: Turn off print \"\n\"statements in utils.py\"\nmsgstr \"\"\n\n#: ../../../changes.txt:911 ecf3f5029df1424ca67fedcd1eac52e1\nmsgid \"\"\n\"Include any trailing `... repeated <N> times...` text in warnings \"\n\"returned by `mupdf_warnings()` (rebased only).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:915 dae1fc58258f4a368eb9b9e73fdc3418\nmsgid \"**Changes in version 1.23.6 (2023-11-06)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:919 4b44a7b92e344051be42fcb7b2fd86ca\nmsgid \"\"\n\"**Fixed** `2553 <https://github.com/pymupdf/PyMuPDF/issues/2553>`_: \"\n\"Invalid characters in versions >= 1.22\"\nmsgstr \"\"\n\n#: ../../../changes.txt:920 c22c67eda878468e84fdce9860d9470e\nmsgid \"\"\n\"**Fixed** `2608 <https://github.com/pymupdf/PyMuPDF/issues/2608>`_: \"\n\"Incorrect utf32 text extraction (high & low surrogates are split)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:921 ../../../changes.txt:944\n#: 6e09bf78b2e8482189006eea2acba2bb 9836ec3981e942eab17d9cf2073f8760\nmsgid \"\"\n\"**Fixed** `2710 <https://github.com/pymupdf/PyMuPDF/issues/2710>`_: \"\n\"page.rect and text location wrong / differing from older version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:922 cf4d2d380bbc48eb852fc95710f97677\nmsgid \"\"\n\"**Fixed** `2774 <https://github.com/pymupdf/PyMuPDF/issues/2774>`_: wrong\"\n\" encoding for \\\"\\\\?\\\" character when sort=True\"\nmsgstr \"\"\n\n#: ../../../changes.txt:923 1f6c84f41d254543a72dc62354b851c3\nmsgid \"\"\n\"**Fixed** `2775 <https://github.com/pymupdf/PyMuPDF/issues/2775>`_: \"\n\"fitz_new does not work with python3.10 or earlier\"\nmsgstr \"\"\n\n#: ../../../changes.txt:924 87951ce6577046f9b2d94ccd7a8d15cf\nmsgid \"\"\n\"**Fixed** `2777 <https://github.com/pymupdf/PyMuPDF/issues/2777>`_: With \"\n\"fitz_new, wrong type for Page.mediabox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:928 8d946635456d4d35be553ed4ef5c4c20\nmsgid \"Use MuPDF-1.23.5.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:929 f7013808115244fc929c4e70b737e840\nmsgid \"Added Document.resolve_names() (rebased implementation only).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:932 fc23c2f02e0f4d6eaaf921039e93a96f\nmsgid \"**Changes in version 1.23.5 (2023-10-11)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:936 6009b9edb3184a869f2ce12fd73c20bd\nmsgid \"\"\n\"**Fixed** `2341 <https://github.com/pymupdf/PyMuPDF/issues/2341>`_: \"\n\"Handling negative values in the zoom section for LINK_GOTO in linkDest\"\nmsgstr \"\"\n\n#: ../../../changes.txt:937 0dd0674d2f134d99b73659b6f62b19a1\nmsgid \"\"\n\"**Fixed** `2522 <https://github.com/pymupdf/PyMuPDF/issues/2522>`_: Typo \"\n\"in set_layer() - NameError: name 'f' is not defined\"\nmsgstr \"\"\n\n#: ../../../changes.txt:938 c5288d50055d4c5da1a7e0df44a0ac43\nmsgid \"\"\n\"**Fixed** `2548 <https://github.com/pymupdf/PyMuPDF/issues/2548>`_: Fitz \"\n\"freezes on some PDFs when calling the fitz.Page.get_text_blocks method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:939 5ff84b8fb6be4feb8cdbf5edbbb0abaa\nmsgid \"\"\n\"**Fixed** `2596 <https://github.com/pymupdf/PyMuPDF/issues/2596>`_: \"\n\"save(garbage=3) breaks get_pixmap() with side effect\"\nmsgstr \"\"\n\n#: ../../../changes.txt:940 123cb55d916f49108937ed096e7ddb25\nmsgid \"\"\n\"**Fixed** `2635 <https://github.com/pymupdf/PyMuPDF/issues/2635>`_: \"\n\"\\\"clean=True\\\" makes objects invisible in the pdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:941 ../../../changes.txt:969\n#: 7654b31ea4c84890bf69fa4688837d78 8eef4b86cdec4085ae3f96a960c2ce20\nmsgid \"\"\n\"**Fixed** `2637 <https://github.com/pymupdf/PyMuPDF/issues/2637>`_: \"\n\"Page.insert_textbox incorrectly handles the last word if it starts a new \"\n\"line\"\nmsgstr \"\"\n\n#: ../../../changes.txt:942 bcc1d82ed2934ae49084a16db226ddf1\nmsgid \"\"\n\"**Fixed** `2699 <https://github.com/pymupdf/PyMuPDF/issues/2699>`_: \"\n\"extract paragraph with below table\"\nmsgstr \"\"\n\n#: ../../../changes.txt:943 75014a04729c49dd8bc091fb9ba66444\nmsgid \"\"\n\"**Fixed** `2703 <https://github.com/pymupdf/PyMuPDF/issues/2703>`_: Wrong\"\n\" fontsize calculation in corner cases (\\\"page.get_texttrace()\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:945 f469c85d192646e5aab002778053d0a5\nmsgid \"\"\n\"**Fixed** `2723 <https://github.com/pymupdf/PyMuPDF/issues/2723>`_: When \"\n\"will a Python 3.12 wheel be available?\"\nmsgstr \"\"\n\n#: ../../../changes.txt:946 0fa82c24bbeb42d2be8390fbba927f0d\nmsgid \"\"\n\"**Fixed** `2730 <https://github.com/pymupdf/PyMuPDF/issues/2730>`_: \"\n\"persistent get_text() formatting\"\nmsgstr \"\"\n\n#: ../../../changes.txt:950 72690f1bf41e43bda38ccd424aacca3c\nmsgid \"Use MuPDF-1.23.4.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:951 30ff227bd04646bdb17474afeccd9981\nmsgid \"Fix optimisation flags with system installs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:952 6906912e05f34a26b46e5f8c0b9dd6e0\nmsgid \"\"\n\"Fixed the problem that the clip parameter does not take effect during \"\n\"table recognition\"\nmsgstr \"\"\n\n#: ../../../changes.txt:953 70a6a8cd8dcc4c90acf6957467999a4f\nmsgid \"Support Pillow mode \\\"RGBa\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:954 500cf538fcc84a5d88b63e846009e940\nmsgid \"Support extra word delimiters\"\nmsgstr \"\"\n\n#: ../../../changes.txt:955 c5a98d3b81ca4f3b92ee9b55641041eb\nmsgid \"Support checking valid PDF name objects\"\nmsgstr \"\"\n\n#: ../../../changes.txt:958 9780d5d181924c1f98f6e987dee32f09\nmsgid \"**Changes in version 1.23.4 (2023-09-26)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:960 89f0cd5d2bdb4c2a86b8130279eaafbd\nmsgid \"Improved build instructions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:961 ba599b28412843c2b4970a1f78cfe599\nmsgid \"Fixed Tesseract in rebased implementation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:962 ad9696206b1147e8a6e75796ad68f204\nmsgid \"Improvements to build/install with system MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:964 0b8845dfb30c4a3ebf1bab255c2231f3\nmsgid \"Fixed rebased bug in _insert_image().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:968 0c9e490c29db4714af654a120396b8e6\nmsgid \"\"\n\"**Fixed** `2556 <https://github.com/pymupdf/PyMuPDF/issues/2556>`_: \"\n\"Segmentation fault at calling get_cdrawings(extended=True)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:970 b47698c2a99a4d67be8d09ea95ac3f34\nmsgid \"\"\n\"**Fixed** `2683 <https://github.com/pymupdf/PyMuPDF/issues/2683>`_: \"\n\"Windows sdist build failure - non-quoting of path and using UNIX which \"\n\"command\"\nmsgstr \"\"\n\n#: ../../../changes.txt:971 2e8eaa9c953340e3b7f9cab5aa9c144a\nmsgid \"\"\n\"**Fixed** `2691 <https://github.com/pymupdf/PyMuPDF/issues/2691>`_: \"\n\"Page.get_textpage_ocr() bug in rebased fitz_new version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:972 01bf199cda4f40eb80f58292500d052e\nmsgid \"\"\n\"**Fixed** `2692 <https://github.com/pymupdf/PyMuPDF/issues/2692>`_: \"\n\"Page.get_pixmap(clip=Rect()) bug in rebased fitz_new version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:975 e635ca7f3a7144c7b155a0d53f366bc4\nmsgid \"**Changes in version 1.23.3 (2023-08-31)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:977 b622f722651945db8c9065920951a027\nmsgid \"Fixed use of Tesseract for OCR.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:980 0b6d628f664246e1af3613f80ef88e31\nmsgid \"**Changes in version 1.23.2 (2023-08-28)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:982 5b021aef8d8846649ea00de593b61159\nmsgid \"\"\n\"**Fixed** `#2613 <https://github.com/pymupdf/PyMuPDF/issues/2613>`_: \"\n\"release 1.23.0 not MacOS-arm64 compatible\"\nmsgstr \"\"\n\n#: ../../../changes.txt:985 18a26e38b78544d8bed38a8639d031b2\nmsgid \"**Changes in version 1.23.1 (2023-08-24)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:987 e62a756953074ab996467e70681646a5\nmsgid \"Updated README and package summary description.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:990 a21901dee64f4a1899288f13aaebfd95\nmsgid \"\"\n\"Fixed a problem on some Linux installations with Python-3.10 (and \"\n\"possibly earlier versions) where `import fitz` failed with `ImportError: \"\n\"libcrypt.so.2: cannot open shared object file: No such file or \"\n\"directory`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:996 57b658dc047548bbbf4b37367da3eb2a\nmsgid \"Fixed `incompatible architecture` error on MacOS arm64.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:999 d42dcb0953b54804aee03e472206b6ee\nmsgid \"\"\n\"Fixed installation warning from Poetry about missing entry in wheels' \"\n\"RECORD files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1003 d3a8e8bb4f464faf90ac4e4f2d3d4257\nmsgid \"**Changes in version 1.23.0 (2023-08-22)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1005 73d894b0d405493fa197c028fc016e16\nmsgid \"Add method `find_tables()` to the `Page` object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1007 0381413ce0b8400e912c1027cc2af4d5\nmsgid \"\"\n\"This allows locating tables on any supported document page, and \"\n\"extracting table content by cell.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1010 7e8f7d58a9bc4339b09e0b5f9ac4ee2d\nmsgid \"New \\\"rebased\\\" implementation of PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1012 9fc6a3029b014900b58e9338c2babb18\nmsgid \"\"\n\"The rebased implementation is available as Python module `fitz_new`. It \"\n\"can be used as a drop-in replacement with `import fitz_new as fitz`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1017 738d34d7aebd43ff89c69b82aa7d46e8\nmsgid \"\"\n\"Python-independent MuPDF libraries are now in a second wheel called \"\n\"`PyMuPDFb` that will be automatically installed by pip.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1020 bca75d93dfe54dd0b930fe20a80af757\nmsgid \"\"\n\"This is to save space on pypi.org - a full release only needs one \"\n\"`PyMuPDFb` wheel for each OS.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1025 5ea8868d14804747b7a032703ca8e9b5\nmsgid \"\"\n\"**Fixed** `#2542 <https://github.com/pymupdf/PyMuPDF/issues/2542>`_: \"\n\"fitz.utils.scrub AttributeError Annot object has no attribute fileUpd \"\n\"inside\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1026 d834522e9a47458f8df14e8f629b6a80\nmsgid \"\"\n\"**Fixed** `#2533 <https://github.com/pymupdf/PyMuPDF/issues/2533>`_: \"\n\"get_texttrace returned a incorrect character bbox\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1027 fa9e61cc88804262a37529823e6ae230\nmsgid \"\"\n\"**Fixed** `#2537 <https://github.com/pymupdf/PyMuPDF/issues/2537>`_: \"\n\"Validation when setting a grouped RadioButton throws a RuntimeError: path\"\n\" to 'V' has indirects\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1029 ../../../changes.txt:1829\n#: ../../../changes.txt:1993 8bbac0324fdd4e349f9a5fa96e73089b\n#: eaf8cd2128cd4c5c877473f9bd315793 ec5d869f0874493ea625e47c43bf59f8\nmsgid \"Other changes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1031 038268fa0e3d4530b127e02b008b0de5\nmsgid \"Dropped support for Python-3.7.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1033 2f238ba63e474abd882d994c5d8a6c7d\nmsgid \"Fix for wrong page / annot `/Contents` cleaning.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1035 8de4c1abb94c4af0ae76a8bc208f2498\nmsgid \"We need to set `pdf_filter_options::no_update` to zero.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1037 3be90380c41041df9c0e8a4b1514f49a\nmsgid \"Added new function get_tessdata().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1039 e2dd7eb60faf45958693b36439454d65\nmsgid \"Cope with problem `/Annot` arrays.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1041 f3a9365058d14581b262aefd3dc3f5cd\nmsgid \"\"\n\"When copying page annotations in method Document.insert_pdf we previously\"\n\" did not check the validity of members of the `/Annots` array.  For \"\n\"faulty members (like null or non-dictionary items) this could cause \"\n\"unnecessary exceptions. This fix implements more checks and skips such \"\n\"array items.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1047 15b514dde25a435db2d8761712b2b511\nmsgid \"Additional annotation type checks.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1049 3d28a76d5772428ca847e78115435df5\nmsgid \"\"\n\"We did not previously check for annotation type when getting / setting \"\n\"annotation border properties. This is now checked in accordance with \"\n\"MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1053 1db4c46ee27f4603907a8be59ce434bd\nmsgid \"Increase fault tolerance.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1055 cfeadbde1d1a4bd28e4394f298039395\nmsgid \"\"\n\"Avoid exceptions in method `insert_pdf()` when source pages contains \"\n\"invalid items in the `/Annots` array.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1058 e95424ad171f4befacebac209026dccf\nmsgid \"Return empty border dict for applicable annots.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1060 d32e47da50ad4e1bbec4315e5deb475a\nmsgid \"\"\n\"We previously were returning a non-empty border dictionary even for non-\"\n\"applicable annotation types.  We now return the empty dictionary `{}` in \"\n\"these cases. This requires some corresponding changes in the annotation \"\n\"`.update()` method, namely for dashes and border width.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1065 a743fc735f8e4751aa4c9fb35972a0e6\nmsgid \"Restrict `set_rect` to applicable annot types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1067 33dd0a503f44425489708bfc1eba3781\nmsgid \"\"\n\"We were insufficiently excluding non-applicable annotation types from \"\n\"`set_rect()` method.  We now let MuPDF catch unsupported annotations and \"\n\"return `False` in these cases.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1071 3c981f3c14264a87a5e5864716eb590f\nmsgid \"Wrong fontsize computation in `page.get_texttrace()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1073 d2bca3e2d5044d88b32f20c0e92bf049\nmsgid \"\"\n\"When computing the font size we were using the final text transformation \"\n\"matrix, where we should have taken `span->trm` instead.  This is \"\n\"corrected here.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1077 4e4387c698a9431c875e14e61bfe5993\nmsgid \"Updates to cope with changes to latest MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1079 68949888709c441996bba638e370acdd\nmsgid \"`pdf_lookup_anchor()` has been removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1081 8e5efc45233c429083dbb2e7710b8e46\nmsgid \"Update fill_textbox to better respect rect.width\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1083 193ee81062494935a4b6e5f7a2d5d470\nmsgid \"\"\n\"The function norm_words in fill_textbox had a bug in its last loop, \"\n\"appending n+1 characters when actually measuring width of n characters.  \"\n\"It led to a bug in fill_texbox when you tried to write a single word \"\n\"mostly composed of \\\"wide\\\" letters (M,m, W, w...), causing the written \"\n\"text to exceed the given rect.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1089 6719947ef5ad4b44b30317c8cd0d27f0\nmsgid \"The fix was just to replace n+1 by n.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1091 a7647cf90c074ee7bf1e22c92b11aad2\nmsgid \"Add `script_focus` and `script_blur` options to widget.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1095 e7f3a5c65c2a4b4095652b5ee87ecf26\nmsgid \"**Changes in version 1.22.5 (2023-06-21)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1097 e0f897c4559d4185828a667deab0b5e1\nmsgid \"This release uses ``MuPDF-1.22.2``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1101 d01a2996634d4afd910a1b19f88fe54d\nmsgid \"\"\n\"**Fixed** `#2365 <https://github.com/pymupdf/PyMuPDF/issues/2365>`_: \"\n\"Incorrect dictionary values for type \\\"fs\\\" drawings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1102 37372904c5fc4a288d1bcfae3658be44\nmsgid \"\"\n\"**Fixed** `#2391 <https://github.com/pymupdf/PyMuPDF/issues/2391>`_: \"\n\"Check box automatically uncheck when we update same checkbox more than 1 \"\n\"times.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1103 da93bf73beab4c7394a870d6ef00aa74\nmsgid \"\"\n\"**Fixed** `#2400 <https://github.com/pymupdf/PyMuPDF/issues/2400>`_: Gaps\"\n\" within text of same line not filled with spaces.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1104 c7bbdcecf83d4af18820e8854d6ed2f7\nmsgid \"\"\n\"**Fixed** `#2404 <https://github.com/pymupdf/PyMuPDF/issues/2404>`_: \"\n\"Blacklining an image in PDF won't remove underlying content in version \"\n\"1.22.X.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1105 5dab0dae25104c5fac71c4bea81bd2ab\nmsgid \"\"\n\"**Fixed** `#2430 <https://github.com/pymupdf/PyMuPDF/issues/2430>`_: \"\n\"Incorrectly reducing ref count of Py_None.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1106 28dd826ad25d4fe989f269746f3f3beb\nmsgid \"\"\n\"**Fixed** `#2450 <https://github.com/pymupdf/PyMuPDF/issues/2450>`_: \"\n\"Empty fill color and fill opacity for paths with fill and stroke \"\n\"operations with 1.22.*\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1107 6eeb2a8ef825424fad2bdbac330da13d\nmsgid \"\"\n\"**Fixed** `#2462 <https://github.com/pymupdf/PyMuPDF/issues/2462>`_: \"\n\"Error at \\\"get_drawing(extended=True )\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1108 d83cacb33bfb43289ba1cac19694532b\nmsgid \"\"\n\"**Fixed** `#2468 <https://github.com/pymupdf/PyMuPDF/issues/2468>`_: \"\n\"Decode error when trying to get drawings\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1109 6816013f54d4446bb7b60530a6e49ad6\nmsgid \"\"\n\"**Fixed** `#2710 <https://github.com/pymupdf/PyMuPDF/issues/2710>`_: \"\n\"page.rect and text location wrong / differing from older version\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1110 2a55b8aad74742ba905c8261e774e40e\nmsgid \"\"\n\"**Fixed** `#2723 <https://github.com/pymupdf/PyMuPDF/issues/2723>`_: When\"\n\" will a Python 3.12 wheel be available?\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1112 89917a32f35f46348baa0a3c330b174e\nmsgid \"New features:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1114 84e05da539e34fb1b20339210c836492\nmsgid \"\"\n\"**Changed** Annotations now support \\\"cloudy\\\" borders. The \"\n\":attr:`Annot.border` property has the new item `clouds`, and method \"\n\":meth:`Annot.set_border` supports the corresponding `clouds` argument.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1118 bce76d38c410446ba81647f0896ef355\nmsgid \"\"\n\"**Changed** Radio button widgets in the same RB group are now \"\n\"consistently updated **if the group is defined in the standard way**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1121 f53cb26ab76e43dfbbd2f4c2efc5a821\nmsgid \"\"\n\"**Added** Support for the `/Locked` key in PDF Optional Content. This \"\n\"array inside the catalog entry `/OCProperties` can now be extracted and \"\n\"set.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1124 def96ff824944143acfaffad2e689880\nmsgid \"\"\n\"**Added** Support for new parameter `tessdata` in OCR functions. New \"\n\"function :meth:`get_tessdata` locates the language support folder if \"\n\"Tesseract is installed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1129 ab43957ddc794c8a9b04c475426c4984\nmsgid \"**Changes in version 1.22.3 (2023-05-10)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1131 ../../../changes.txt:1140\n#: ../../../changes.txt:1149 ../../../changes.txt:1161\n#: 03ca33346d3944328c25a5c144420613 07f4c427f5f544f5bd7d767983484060\n#: 0fb05318e4944beeb5124143ee76589f d7e781b29559409897126ce3786cd3e7\nmsgid \"This release uses ``MuPDF-1.22.0``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1135 91c90d81ef504a9d8aeaffb101145d25\nmsgid \"\"\n\"**Fixed** `#2333 <https://github.com/pymupdf/PyMuPDF/issues/2333>`_: \"\n\"Unable to set any of button radio group in form\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1138 016b5d8017ec4b46aa0db0ca2575d91b\nmsgid \"**Changes in version 1.22.2 (2023-04-26)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1144 2a883f3384d24cb4b50c413be7b7248d\nmsgid \"\"\n\"**Fixed** `#2369 <https://github.com/pymupdf/PyMuPDF/issues/2369>`_: \"\n\"Image extraction bugs with newer versions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1147 558df7978ec349b98ce43b9afb00b02e\nmsgid \"**Changes in version 1.22.1 (2023-04-18)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1153 2f26d737893143a0b598c60bbf17e7c1\nmsgid \"\"\n\"**Fixed** `#2345 <https://github.com/pymupdf/PyMuPDF/issues/2345>`_: Turn\"\n\" off print statements in utils.py\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1154 88393d4c4b1c4de88301c4a0c889142a\nmsgid \"\"\n\"**Fixed** `#2348 <https://github.com/pymupdf/PyMuPDF/issues/2348>`_: \"\n\"extract_image returns an extension \\\"flate\\\" instead of \\\"png\\\"\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1155 a669f7b9c4be4a208b4f533e8f283873\nmsgid \"\"\n\"**Fixed** `#2350 <https://github.com/pymupdf/PyMuPDF/issues/2350>`_: Can \"\n\"not make widget (checkbox) to read-only by adding flags \"\n\"PDF_FIELD_IS_READ_ONLY\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1156 2b3bdc6748004a1aa84e2d6b31562785\nmsgid \"\"\n\"**Fixed** `#2355 <https://github.com/pymupdf/PyMuPDF/issues/2355>`_: \"\n\"1.22.0 error when using get_toc (AttributeError: 'SwigPyObject' object \"\n\"has no attribute)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1159 350bcb28a30944fdacb28843123738f2\nmsgid \"**Changes in version 1.22.0 (2023-04-14)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1163 44f570ec1df54e41a946bffb631b53c9\nmsgid \"Behavioural changes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1165 3826a16556c6458d8e1e603e51ffd973\nmsgid \"\"\n\"Text extraction now includes glyphs that overlap with clip rect; \"\n\"previously they were included only if they were entirely contained within\"\n\" the clip rect.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1171 3c30c3109974444198cf37e90e8ecabb\nmsgid \"\"\n\"**Fixed** `#1763 <https://github.com/pymupdf/PyMuPDF/issues/1763>`_: \"\n\"Interactive(smartform) form PDF calculation not working in pymupdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1172 af42fd504f0640239d81c483794b7e87\nmsgid \"\"\n\"**Fixed** `#1995 <https://github.com/pymupdf/PyMuPDF/issues/1995>`_: \"\n\"RuntimeError: image is too high for a long paged pdf file when trying\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1173 c1d1a1930cec45f3aeb64999517485da\nmsgid \"\"\n\"**Fixed** `#2093 <https://github.com/pymupdf/PyMuPDF/issues/2093>`_: \"\n\"Image in pdf changes color after applying redactions\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1174 44f1654607db4a3a8bea70e0742f243f\nmsgid \"\"\n\"**Fixed** `#2108 <https://github.com/pymupdf/PyMuPDF/issues/2108>`_: \"\n\"Redaction removing more text than expected\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1175 13a17730caa849b68c2ae08ecb2ca4d8\nmsgid \"\"\n\"**Fixed** `#2141 <https://github.com/pymupdf/PyMuPDF/issues/2141>`_: \"\n\"Failed to read JPX header when trying to get blocks\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1176 59f63490e3084544a37ad382c51db86f\nmsgid \"\"\n\"**Fixed** `#2144 <https://github.com/pymupdf/PyMuPDF/issues/2144>`_: \"\n\"Replace image throws an error\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1177 126c1e66cfb94388a6f083d43390e614\nmsgid \"\"\n\"**Fixed** `#2146 <https://github.com/pymupdf/PyMuPDF/issues/2146>`_: \"\n\"Wrong Handling of Reference Count of \\\"None\\\" Object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1178 c2df8c498e4c4870b10129059c78dc55\nmsgid \"\"\n\"**Fixed** `#2161 <https://github.com/pymupdf/PyMuPDF/issues/2161>`_: \"\n\"Support adding images as pages directly\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1179 fa791f2adef34202b8f713657d47816f\nmsgid \"\"\n\"**Fixed** `#2168 <https://github.com/pymupdf/PyMuPDF/issues/2168>`_: \"\n\"``page.add_highlight_annot(start=pointa, stop=pointb)`` not working\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1180 e34fc762c8864c6db478c2a49d9e26ef\nmsgid \"\"\n\"**Fixed** `#2173 <https://github.com/pymupdf/PyMuPDF/issues/2173>`_: \"\n\"Double free of ``Colorspace`` used in ``Pixmap``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1181 18b7a0bf38a14b94a56b1ba2feea09b9\nmsgid \"\"\n\"**Fixed** `#2179 <https://github.com/pymupdf/PyMuPDF/issues/2179>`_: \"\n\"Incorrect documentation for ``pixmap.tint_with()``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1182 30fdc624e4da4b0da0d438177b35bb4d\nmsgid \"\"\n\"**Fixed** `#2208 <https://github.com/pymupdf/PyMuPDF/issues/2208>`_: \"\n\"Pushbutton widget appears as check box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1183 4d209898906843229670a95f12041360\nmsgid \"\"\n\"**Fixed** `#2210 <https://github.com/pymupdf/PyMuPDF/issues/2210>`_: \"\n\"``apply_redactions()`` move pdf text to right after redaction\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1184 e6423ce2ee3e42cd842814a3ea98cae3\nmsgid \"\"\n\"**Fixed** `#2220 <https://github.com/pymupdf/PyMuPDF/issues/2220>`_: \"\n\"``Page.delete_image()`` | object has no attribute ``is_image``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1185 c6210c2a77804a929b68c35607fa6823\nmsgid \"\"\n\"**Fixed** `#2228 <https://github.com/pymupdf/PyMuPDF/issues/2228>`_: open\"\n\" some pdf cost too much time\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1186 b599a24386c74a8c913ae912d614557a\nmsgid \"\"\n\"**Fixed** `#2238 <https://github.com/pymupdf/PyMuPDF/issues/2238>`_: Bug \"\n\"- can not extract data from file in the newest version 1.21.1\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1187 b350fda19a5149f5848f62509b82c19a\nmsgid \"\"\n\"**Fixed** `#2242 <https://github.com/pymupdf/PyMuPDF/issues/2242>`_: \"\n\"Python quits silently in ``Story.element_positions()`` if callback \"\n\"function prototype is wrong\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1188 e6dc566181194da487883bc82530e4c5\nmsgid \"\"\n\"**Fixed** `#2246 <https://github.com/pymupdf/PyMuPDF/issues/2246>`_: \"\n\"TextWriter write text in a wrong position\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1189 3a1d2b5a77714081819e4147e4876ed9\nmsgid \"\"\n\"**Fixed** `#2248 <https://github.com/pymupdf/PyMuPDF/issues/2248>`_: \"\n\"After redacting the content, the position of the remaining text changes\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1190 be48ed21d0f44f6dba17fab6201c8b78\nmsgid \"\"\n\"**Fixed** `#2250 <https://github.com/pymupdf/PyMuPDF/issues/2250>`_: \"\n\"docs: unclear or broken link in page.rst\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1191 1f64252d8b684958a8360570bc1b540a\nmsgid \"\"\n\"**Fixed** `#2251 <https://github.com/pymupdf/PyMuPDF/issues/2251>`_: \"\n\"mupdf_display_errors does not apply to Pixmap when loading broken image\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1192 e8ac54952809456694e4b366c0992b6d\nmsgid \"\"\n\"**Fixed** `#2270 <https://github.com/pymupdf/PyMuPDF/issues/2270>`_: \"\n\"``Annot.get_text(\\\"words\\\")`` - doesn't return the first line of words\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1193 982ad8c99b6f4f739e357ee11cd3b514\nmsgid \"\"\n\"**Fixed** `#2275 <https://github.com/pymupdf/PyMuPDF/issues/2275>`_: \"\n\"insert_image: document that rotations are counterclockwise\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1194 eb8b181a15924a07abee72fea8a50ce9\nmsgid \"\"\n\"**Fixed** `#2278 <https://github.com/pymupdf/PyMuPDF/issues/2278>`_: Can \"\n\"not make widget (checkbox) to read-only by adding flags \"\n\"PDF_FIELD_IS_READ_ONLY\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1195 2dd5e761dcb94cde9a62d9e95e521f8a\nmsgid \"\"\n\"**Fixed** `#2290 <https://github.com/pymupdf/PyMuPDF/issues/2290>`_: \"\n\"Different image format/data from Page.get_text(\\\"dict\\\") and \"\n\"Fitz.get_page_images()\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1196 b626d2a058c1457bb8fc7b175049d787\nmsgid \"\"\n\"**Fixed** `#2293 <https://github.com/pymupdf/PyMuPDF/issues/2293>`_: 68 \"\n\"failed tests when installing from sdist on my box\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1197 c7c26b4cf78644b98a99810e21c743c5\nmsgid \"\"\n\"**Fixed** `#2300 <https://github.com/pymupdf/PyMuPDF/issues/2300>`_: Too \"\n\"much recursion in tree (parents), makes program terminate\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1198 53cf50d333db4541900b708daa262c2d\nmsgid \"\"\n\"**Fixed** `#2322 <https://github.com/pymupdf/PyMuPDF/issues/2322>`_: \"\n\"add_highlight_annot using clip generates \\\"A Number is Out of Range\\\" \"\n\"error in PDF\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1202 dc34fa0179bf4c0097c613d4e4d7cd5d\nmsgid \"\"\n\"Add key \\\"/AS (Yes)\\\" to the underlying annot object of a selected button\"\n\" form field.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1204 851dc87410c04af3811c1fce6e46d473\nmsgid \"\"\n\"Remove unused ``Document`` methods ``has_xref_streams()`` and \"\n\"``has_old_style_xrefs()`` as MuPDF equivalents have been removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1207 85d63fb357cc4ae6843661251e81671d\nmsgid \"\"\n\"Add new ``Document`` methods and properties for getting/setting \"\n\"``/PageMode``, ``/PageLayout`` and ``/MarkInfo``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1210 4692f2e3d07246f4b715a11b16c41826\nmsgid \"\"\n\"New ``Document`` property ``version_count``, which contains the number of\"\n\" incremental saves plus one.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1213 35dcac5f24064e0aa4e37ed607d7ee66\nmsgid \"\"\n\"New ``Document`` property ``is_fast_webaccess`` which tells whether the \"\n\"document is linearized.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1216 123a5e07f4e14c818cdcd4df6eb3afee\nmsgid \"``DocumentWriter`` is now a context manager.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1218 78db04ba2a9c48b7ad95cf5a7935dbd9\nmsgid \"Add support for ``Pixmap`` JPEG output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1220 75aea400570e4b6e9fec59457f4f883e\nmsgid \"Add support for drawing rectangles with rounded corners.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1222 8f7ef5836f6341ec93a07f437355992f\nmsgid \"``get_drawings()``: added optional ``extended`` arg.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1224 e60534dd491e4153a778b53b862c3666\nmsgid \"\"\n\"Fixed issue where trace devices' state was not being initialised \"\n\"correctly; data returned from things like ``fitz.Page.get_texttrace()`` \"\n\"might be slightly altered, e.g. ``linewidth`` values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1228 5ce1cdb70dd7438d9abe42cb5886dddc\nmsgid \"\"\n\"Output warning to ``stderr`` if it looks like we are being used with \"\n\"current directory containing an invalid ``fitz/`` directory, because this\"\n\" can break import of ``fitz`` module. For example this happens if one \"\n\"attempts to use ``fitz`` when current directory is a PyMuPDF checkout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1234 ../../../changes.txt:1289\n#: 349693fd237b4cbc8a22aa6cf3da10f1 8656870c12324ba69e9770b2a5f4fad6\nmsgid \"Documentation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1236 d223e4e942aa4b40ae6748f3f806de5d\nmsgid \"General rework:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1238 f085940fb9eb4248aa37862aa5ee511f\nmsgid \"Introduces a new home page and new table of contents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1239 7d45f07d7c9f45d085714f462f775464\nmsgid \"Structural update to include new About section.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1240 fbd4e460a3094b4e9f3cbe8bdb120960\nmsgid \"Comparison & performance graphing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1241 42f77bb0503d48488766f5fdb4d19c15\nmsgid \"Includes performance methodology in appendix.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1242 3bc9a3e24e0249a7a103014e58b0cfe0\nmsgid \"Updates conf.py to understand single back-ticks as code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1243 a3e9a116b3fb453fa81fe3081ca9ac28\nmsgid \"Converts double back-ticks to single back-ticks.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1244 dc12d40a4c6148f6b2c2740f969fe028\nmsgid \"Removes redundant files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1246 4b1314b91c0c4a57afc180019e7fcf7f\nmsgid \"Improve ``insert_file()`` documentation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1248 d4504863060147358071d6130ed1d42c\nmsgid \"``get_bboxlog()``: added optional ``layers`` to ``get_bboxlog()``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1249 c11f7f0d2dab4b70968cca0abf587247\nmsgid \"\"\n\"``Page.get_texttrace()``: add new dictionary key ``layer``, name of \"\n\"Optional Content Group.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1251 202373f80f8d415a95fc9f1ab5c7f3c6\nmsgid \"Mention use of Python venv in installation documentation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1253 b7d408d9e1624b44b165a77a64070262\nmsgid \"Added missing fix for #2057 to release 1.21.1's changelog.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1255 e6cde05edeef4042a0657f838649a63c\nmsgid \"Fixes many links to the PyMuPDF-Utilities repo scripts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1257 038857900256474c9fded24cb273f8b5\nmsgid \"Avoid duplication of ``changes.txt`` and ``docs/changes.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1259 e343ebb10ae64a2baebc475af2998387\nmsgid \"Build\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1261 70564fcedaa2459bbccc68bc3d893e47\nmsgid \"Added ``pyproject.toml`` file to improve builds using pip etc.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1265 b1ea3fa1f44849439039e1a63d88a6e4\nmsgid \"**Changes in Version 1.21.1 (2022-12-13)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1267 92d79ae3bac04eae98a0a5093fe8273d\nmsgid \"This release uses ``MuPDF-1.21.1``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1271 3276e784b07a47648e6c6390b6cd3266\nmsgid \"\"\n\"**Fixed** `#2110 <https://github.com/pymupdf/PyMuPDF/issues/2110>`_: \"\n\"Fully embedded font is extracted only partially if it occupies more than \"\n\"one object\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1272 950a39d02c9a4c8b8fa42d3ac1ac9e37\nmsgid \"\"\n\"**Fixed** `#2094 <https://github.com/pymupdf/PyMuPDF/issues/2094>`_: \"\n\"Rectangle Detection Logic\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1273 2f5a46c0803d4b5a9cbbacd71100b204\nmsgid \"\"\n\"**Fixed** `#2088 <https://github.com/pymupdf/PyMuPDF/issues/2088>`_: \"\n\"Destination point not set for named links in toc\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1274 97e2df4608364a7782f5c3a2e5b51f8d\nmsgid \"\"\n\"**Fixed** `#2087 <https://github.com/pymupdf/PyMuPDF/issues/2087>`_: \"\n\"Image with Filter \\\"[/FlateDecode/JPXDecode]\\\" not extracted\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1275 2168171e471542ada426f030b803e71d\nmsgid \"\"\n\"**Fixed** `#2086 <https://github.com/pymupdf/PyMuPDF/issues/2086>`_: \"\n\"Document.save() owner_pw & user_pw has buffer overflow bug\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1276 a23066f8e8654302b8b78db3816529c8\nmsgid \"\"\n\"**Fixed** `#2076 <https://github.com/pymupdf/PyMuPDF/issues/2076>`_: \"\n\"Segfault in fitz.py\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1277 13898161176b4a65990185478cb80a77\nmsgid \"\"\n\"**Fixed** `#2057 <https://github.com/pymupdf/PyMuPDF/issues/2057>`_: \"\n\"Document.save garbage parameter not working in PyMuPDF 1.21.0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1278 9d7d27f10c4946fd8036c536b9c192e1\nmsgid \"\"\n\"**Fixed** `#2051 <https://github.com/pymupdf/PyMuPDF/issues/2051>`_: \"\n\"Missing DPI Parameter\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1279 f53e894aea1048b0b6ea80c4ea26c7c5\nmsgid \"\"\n\"**Fixed** `#2048 <https://github.com/pymupdf/PyMuPDF/issues/2048>`_: \"\n\"Invalid size of TextPage and bbox with newest version 1.21.0\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1280 f969ab18933245a593f97d97ee9ecbf6\nmsgid \"\"\n\"**Fixed** `#2045 <https://github.com/pymupdf/PyMuPDF/issues/2045>`_: \"\n\"SystemError: <built-in function Page_get_texttrace> returned a result \"\n\"with an error set\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1281 1f16bd21e2a8445d9592684ec7ecca51\nmsgid \"\"\n\"**Fixed** `#2039 <https://github.com/pymupdf/PyMuPDF/issues/2039>`_: \"\n\"1.21.0 fails to build against system libmupdf\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1282 3c45097d33ee470a9481317257d311f7\nmsgid \"\"\n\"**Fixed** `#2036 <https://github.com/pymupdf/PyMuPDF/issues/2036>`_: \"\n\"Archive::Archive defined twice\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1284 6533ecdf4d754fe7a4443b4a1b02bb72\nmsgid \"Other\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1286 9b576f8a8de143e3b3b9de9b6368ca18\nmsgid \"Swallow \\\"&zoom=nan\\\" in link uri strings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1287 f70b7dad981d4d249124939b4f1aaaee\nmsgid \"\"\n\"Add new Page utility methods ``Page.replace_image()`` and \"\n\"``Page.delete_image()``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1291 4f89ab38e60b43ea987d07e27961bb7d\nmsgid \"\"\n\"`#2040 <https://github.com/pymupdf/PyMuPDF/issues/2040>`_: Added note \"\n\"about test failure with non-default build of MuPDF, to \"\n\"``tests/README.md``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1292 558ff70ae6224480af3e735540cac2e3\nmsgid \"\"\n\"`#2037 <https://github.com/pymupdf/PyMuPDF/issues/2037>`_: In \"\n\"``docs/installation.rst``, mention incompatibility with chocolatey.org on\"\n\" Windows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1293 397d721cec884107af23df22baffdcb0\nmsgid \"\"\n\"`#2061 <https://github.com/pymupdf/PyMuPDF/issues/2061>`_: Fixed \"\n\"description of ``Annot.file_info``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1294 c6511b374b8b434caf2413b84c80813d\nmsgid \"\"\n\"`#2065 <https://github.com/pymupdf/PyMuPDF/issues/2065>`_: Show how to \"\n\"insert internal PDF link.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1295 6a5f0c4f501b4afd92cfe917137a0758\nmsgid \"Improved description of building from source without an sdist.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1296 67690117d7be41879e6fa66746eefeb1\nmsgid \"Added information about running tests.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1297 49b3f25fb63147c3b4c90a255b9ef648\nmsgid \"\"\n\"`#2084 <https://github.com/pymupdf/PyMuPDF/issues/2084>`_: Fixed broken \"\n\"link to PyMuPDF-Utilities.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1300 575f368bd94e401b9952c6d42b41700d\nmsgid \"**Changes in Version 1.21.0 (2022-11-8)**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1302 673df835349745e7865e5b7f56344a60\nmsgid \"This release uses ``MuPDF-1.21.0``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1304 17bf58b166d24d168b6139c6e77d3a91\nmsgid \"New feature: Stories.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1306 a17fc35b1e5e48ab82510fb0a263af42\nmsgid \"Added wheels for Python-3.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1310 15df913e178e4f6781add4fa251aec7f\nmsgid \"\"\n\"**Fixed** `#1701 <https://github.com/pymupdf/PyMuPDF/issues/1701>`_: \"\n\"Broken custom image insertion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1311 2e7ca2e90f944214af8d8a773028ae37\nmsgid \"\"\n\"**Fixed** `#1854 <https://github.com/pymupdf/PyMuPDF/issues/1854>`_: \"\n\"`Document.delete_pages()` declines keyword arguments.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1312 346bb412bfad447b83a0e599f7336a01\nmsgid \"\"\n\"**Fixed** `#1868 <https://github.com/pymupdf/PyMuPDF/issues/1868>`_: \"\n\"Access Violation Error at `page.apply_redactions()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1313 9284226d16f4445cb9f22941a7e04dab\nmsgid \"\"\n\"**Fixed** `#1909 <https://github.com/pymupdf/PyMuPDF/issues/1909>`_: \"\n\"Adding text with `fontname=\\\"Helvetica\\\"` can silently fail.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1314 c11ff004104f4de1b6e767abc09ba8c4\nmsgid \"\"\n\"**Fixed** `#1913 <https://github.com/pymupdf/PyMuPDF/issues/1913>`_: \"\n\"`draw_rect()`: does not respect width if color is not specified.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1315 0f7b31ba423c48a185bae37f8c31c421\nmsgid \"\"\n\"**Fixed** `#1917 <https://github.com/pymupdf/PyMuPDF/issues/1917>`_: \"\n\"`subset_fonts()`: make it possible to silence the stdout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1316 a785e9b369404f42b2a872e50d17133b\nmsgid \"\"\n\"**Fixed** `#1936 <https://github.com/pymupdf/PyMuPDF/issues/1936>`_: \"\n\"Rectangle detection can be incorrect producing wrong output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1317 08fa2dec869748e4aa0d6b44cb796106\nmsgid \"\"\n\"**Fixed** `#1945 <https://github.com/pymupdf/PyMuPDF/issues/1945>`_: \"\n\"Segmentation fault when saving with `clean=True`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1318 3f1f9499ba9540f090c963df0a8cf1c2\nmsgid \"\"\n\"**Fixed** `#1965 <https://github.com/pymupdf/PyMuPDF/issues/1965>`_: \"\n\"`pdfocr_save()` Hard Crash.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1319 e675868f950a47b89b02bdec849ddfaf\nmsgid \"\"\n\"**Fixed** `#1971 <https://github.com/pymupdf/PyMuPDF/issues/1971>`_: \"\n\"Segmentation fault when using `get_drawings()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1320 9af37195cb0a40ef94d54604e449326c\nmsgid \"\"\n\"**Fixed** `#1946 <https://github.com/pymupdf/PyMuPDF/issues/1946>`_: \"\n\"`block_no` and `block_type` switched in `get_text()` docs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1321 cad632bb6e5347fdb160df1d5e205e7f\nmsgid \"\"\n\"**Fixed** `#2013 <https://github.com/pymupdf/PyMuPDF/issues/2013>`_: \"\n\"AttributeError: 'Widget' object has no attribute '_annot' in delete \"\n\"widget.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1323 c6abbf7c5af64afe8a6d1294f4458a5b\nmsgid \"Misc changes to core code:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1325 bcadf404caaf42199adda95adecf0183\nmsgid \"Fixed various compiler warnings and a sequence-point bug.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1326 1e7ac8c3fc184879954a671e241386ce\nmsgid \"Added support for Memento builds.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1327 2d4b0ca48cff409ab625548ad136c9dd\nmsgid \"Fixed leaks detected by Memento in test suite.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1328 eb361878f2a34aba8443b994d71d171a\nmsgid \"Fixed handling of exceptions in set_name() and set_rect().\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1329 a57b2a7cb8ee4135a049aa057aa122ab\nmsgid \"Allow build with latest MuPDF, for regular testing of PyMuPDF master.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1330 94ed6dc32d87489980b579f7731e909a\nmsgid \"Cope with new MuPDF exceptions when setting rect for some Annot types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1331 0ddc8291d7994c71af6956edb68bd61f\nmsgid \"\"\n\"Reduced cosmetic differences between MuPDF's config.h and PyMuPDF's \"\n\"_config.h.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1332 ca97b466331943fbaf5357ca77d105ff\nmsgid \"Cope with various changes to MuPDF API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1336 ebefa94d051a413c87fa9a3656dcceda\nmsgid \"Fixed various broken links and typos in docs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1337 425cc8bc1fcf4fdaac66e442ee2e5513\nmsgid \"Mention install of `swig-python` on MacOS for #875.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1338 7073906d3d64408c836b7d3de96519aa\nmsgid \"Added (untested) wheels for macos-arm64.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1343 30436208e7954516bb195ab1ea1ed488\nmsgid \"**Changes in Version 1.20.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1345 ccf93339cf7245b2820d527e6e093f20\nmsgid \"This release uses ``MuPDF-1.20.3``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1347 e392d8912dbc4a8596ade19a8161d639\nmsgid \"\"\n\"**Fixed** `#1787 <https://github.com/pymupdf/PyMuPDF/issues/1787>`_. Fix \"\n\"linking issues on Unix systems.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1350 4d180eaf011b4a9fbb8c216aa4a505ec\nmsgid \"\"\n\"**Fixed** `#1824 <https://github.com/pymupdf/PyMuPDF/issues/1824>`_. \"\n\"SegFault when applying redactions overlapping a transparent image. (Fixed\"\n\" in ``MuPDF-1.20.3``.)\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1354 6cb696c83bfc47bbb07c549f1a1f0267\nmsgid \"Improvements to documentation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1356 0ad4a7a79fe54f24869d872723b404e8\nmsgid \"\"\n\"Improved information about building from source in \"\n\"``docs/installation.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1357 81117814315f48efbc87955f9a7ef58d\nmsgid \"Clarified memory allocation setting ``JM_MEMORY` in ``docs/tools.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1358 b488d65744d743c4b1333dacf311664c\nmsgid \"Fixed link to PDF Reference manual in ``docs/app3.rst``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1359 472c19e0e68c4c109bde0bb001020dac\nmsgid \"Fixed building of html documentation on OpenBSD.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1360 c99ee292bc6c46c686c3cad285701923\nmsgid \"Moved old ``docs/faq.rst`` into separate ``docs/recipes-*`` files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1362 5fed1f452c8f47549032bcab7853bdde\nmsgid \"Removed some unused files and directories:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1364 7c310414b4384898a324f2841f54decd\nmsgid \"``installation/``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1365 5e5ae4637cb640d19cd1b1a5305c90d8\nmsgid \"``docs/wheelnames.txt``\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1368 f4d58a60a4f946a69ea863d1d7d30c62\nmsgid \"**Changes in Version 1.20.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1370 23e14128203842beadfff33baa6792ae\nmsgid \"\"\n\"**Fixed** `#1724 <https://github.com/pymupdf/PyMuPDF/issues/1724>`_. Fix \"\n\"for building on FreeBSD.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1373 ca0919e2a72b45eca23b6ffabb073f2d\nmsgid \"\"\n\"**Fixed** `#1771 <https://github.com/pymupdf/PyMuPDF/issues/1771>`_. \"\n\"`linkDest()` had a broken call to `re.match()`, introduced in 1.20.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1376 1acfe9e0464545878372d78884eac896\nmsgid \"\"\n\"**Fixed** `#1751 <https://github.com/pymupdf/PyMuPDF/issues/1751>`_. \"\n\"`get_drawings()` and `get_cdrawings()` previously always returned with \"\n\"`closePath=False`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1379 b1c751d4d6b249f7b1603c75f54e6948\nmsgid \"\"\n\"**Fixed** `#1645 <https://github.com/pymupdf/PyMuPDF/issues/1645>`_. \"\n\"Default FreeText annotation text color is now black.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1382 f7bb3767b4b546a8921290a547e0cf50\nmsgid \"Improvements to sphinx-generated documentation:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1384 a5a5cb7bebe241279daf65c0700e6d10\nmsgid \"Use readthedocs theme with enhancements.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1385 d06c9bab26ef40449327e0f849c88152\nmsgid \"Renamed the `.txt` files to have `.rst` suffixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1389 7af006a5c3a84b03914bc4dcb23055ef\nmsgid \"**Changes in Version 1.20.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1391 c5bccf72f35e4edf807800d879e696ff\nmsgid \"This release uses ``MuPDF-1.20.0``, released 2022-06-15.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1393 68d1b02687f849fab3365ec98f0308d4\nmsgid \"\"\n\"Cope with new MuPDF link uri format, changed from ``#<int>,<int>,<int>`` \"\n\"to ``#page=<int>&zoom=<float>,<float>,<float>``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1395 d17d731c792044cfa0b4bc0486f4c5a8\nmsgid \"\"\n\"In ``tests/test_insertpdf.py``, use new reference output \"\n\"``joined-1.20.pdf``. We also check that new output values are \"\n\"approximately the same as the old ones.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1397 96cbfad0c6cb404db15d7aa8d13c5f65\nmsgid \"\"\n\"**Fixed** `#1738 <https://github.com/pymupdf/PyMuPDF/issues/1738>`_. Leak\"\n\" of `pdf_graft_map`. Also fixed a SEGV issue that this seemed to expose, \"\n\"caused by incorrect freeing of underlying fz_document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1400 a1460a0ec164432ebbe35656a0272c02\nmsgid \"\"\n\"**Fixed** `#1733 <https://github.com/pymupdf/PyMuPDF/issues/1733>`_. \"\n\"Fixed ownership of `Annotation.get_pixmap()`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1402 1fb8672935f346f18177065d4a876d9b\nmsgid \"Changes to build/release process:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1404 d1f37ff28e754e3891af3658a6d2c4f7\nmsgid \"\"\n\"If pip builds from source because an appropriate wheel is not available, \"\n\"we no longer require MuPDF to be pre-installed. Instead the required \"\n\"MuPDF source is embedded in the sdist and automatically built into \"\n\"PyMuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1406 c6743d7a837547bfbd14121f922f188b\nmsgid \"\"\n\"Various changes to ``setup.py`` to download the required MuPDF release as\"\n\" required. See comments at start of setup.py for details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1408 2deed3b348e44634a95976500ca61ff1\nmsgid \"\"\n\"Added ``.github/workflows/build_wheels.yml`` to control building of \"\n\"wheels on Github.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1412 bfd2558d12c24e4ba3c0aee0edff3507\nmsgid \"**Changes in Version 1.19.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1414 e9b569d9e70b42518f53a71536bd4f28\nmsgid \"\"\n\"**Fixed** `#1620 <https://github.com/pymupdf/PyMuPDF/issues/1620>`_. The \"\n\":ref:`TextPage` created by :meth:`Page.get_textpage` will now be freed \"\n\"correctly (removed memory leak).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1415 058f760c8ce740e48a627eb2aee78a56\nmsgid \"\"\n\"**Fixed** `#1601 <https://github.com/pymupdf/PyMuPDF/issues/1601>`_. \"\n\"Document open errors should now be more concise and easier to interpret. \"\n\"In the course of this, two PyMuPDF-specific Python exceptions have been \"\n\"**added:**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1417 15ef5b12f13b4750a9571bf258d1dd43\nmsgid \"\"\n\"``EmptyFileError`` -- raised when trying to create a :ref:`Document` \"\n\"(``fitz.open()``) from an empty file or zero-length memory.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1418 f1c391fa54a1405ba4a28d352d108404\nmsgid \"\"\n\"``FileDataError`` -- raised when MuPDF encounters irrecoverable document \"\n\"structure issues.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1420 56b2878654114138ac79fad54cecad1b\nmsgid \"**Added** :meth:`Page.load_widget` given a PDF field's xref.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1422 c0ece2db951a48efac1849cd7074f28e\nmsgid \"\"\n\"**Added** Dictionary :attr:`pdfcolor` which provide the about 500 colors \"\n\"defined as PDF color values with the lower case color name as key.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1424 f9628cc364244bf3a41e4b3a8c2d40c6\nmsgid \"\"\n\"**Added** algebra functionality to the :ref:`Quad` class. These objects \"\n\"can now also be added and subtracted among themselves, and be multiplied \"\n\"by numbers and matrices.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1426 b66574a55e8d41d7accf7dd33f070642\nmsgid \"\"\n\"**Added** new constants defining the default text extraction flags for \"\n\"more comfortable handling. Their naming convention is like \"\n\":data:`TEXTFLAGS_WORDS` for ``page.get_text(\\\"words\\\")``. See \"\n\":ref:`text_extraction_flags`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1428 8f6f15bc876b4df68cda93624b20a4ea\nmsgid \"\"\n\"**Changed** :meth:`Page.annots` and :meth:`Page.widgets` to detect and \"\n\"prevent reloading the page (illegally) inside the iterator loops via \"\n\":meth:`Document.reload_page`. Doing this brings down the interpreter. \"\n\"Documented clean ways to do annotation and widget mass updates within \"\n\"properly designed loops.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1430 287feb6044a2402d9651e9690ee78512\nmsgid \"\"\n\"**Changed** several internal utility functions to become standalone \"\n\"(\\\"SWIG inline\\\") as opposed to be part of the :ref:`Tools` class. This, \"\n\"among other things, increases the performance of geometry object \"\n\"creation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1432 ec2b054b07e449debcbc15b510c35e5e\nmsgid \"\"\n\"**Changed** :meth:`Document.update_stream` to always accept stream \"\n\"updates - whether or not the dictionary object behind the xref already is\"\n\" a stream. Thus the former ``new`` parameter is now ignored and will be \"\n\"removed in v1.20.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1437 89534acd0d50489793f84d93defb75d9\nmsgid \"**Changes in Version 1.19.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1439 15c312e55ff84d4990200b73b5ab7088\nmsgid \"\"\n\"**Fixed** `#1518 <https://github.com/pymupdf/PyMuPDF/issues/1518>`_. A \"\n\"limited \\\"fix\\\": in some cases, rectangles and quadrupels were not \"\n\"correctly encoded to support re-drawing by :ref:`Shape`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1441 4ba09954c0b641a2926f1026d979da09\nmsgid \"\"\n\"**Fixed** `#1521 <https://github.com/pymupdf/PyMuPDF/issues/1521>`_. This\"\n\" had the same ultimate reason behind issue #1510.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1443 dde5fa3810eb4a82b0aa2e61d8cf863b\nmsgid \"\"\n\"**Fixed** `#1513 <https://github.com/pymupdf/PyMuPDF/issues/1513>`_. Some\"\n\" Optional Content functions did not support non-ASCII characters.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1445 3d2e4740ec0b41b4aaad51d97655f8e9\nmsgid \"\"\n\"**Fixed** `#1510 <https://github.com/pymupdf/PyMuPDF/issues/1510>`_. \"\n\"Support more soft-mask image subtypes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1447 e79ebb09f5ea405a8ed23fbed6aa913a\nmsgid \"\"\n\"**Fixed** `#1507 <https://github.com/pymupdf/PyMuPDF/issues/1507>`_. \"\n\"Immunize against items in the outlines chain, that are ``\\\"null\\\"`` \"\n\"objects.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1449 cd737a2d921f4ee6929d54d756b3ca78\nmsgid \"\"\n\"**Fixed** re-opened `#1417 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1417>`_. (\\\"too many open \"\n\"files\\\"). This was due to insufficient calls to MuPDF's \"\n\"``fz_drop_document()``. This also fixes `#1550 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1550>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1451 10995303e588406895c48eaa98334bdd\nmsgid \"\"\n\"**Fixed** several undocumented issues in relation to incorrectly setting \"\n\"the text span origin :data:`point_like`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1453 c395df4c98a441958d507eaf1a55d6de\nmsgid \"\"\n\"**Fixed** undocumented error computing the character bbox in method \"\n\":meth:`Page.get_texttrace` when text is **flipped** (as opposed to just \"\n\"rotated).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1455 d82b9d2a17b64ddb90e236a9e42f1420\nmsgid \"\"\n\"**Added** items to the dictionary returned by :meth:`image_properties`: \"\n\"``orientation`` and ``transform`` report the natural image orientation \"\n\"(EXIF data).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1457 30117ed837094556807bb67193004816\nmsgid \"\"\n\"**Added** method :meth:`Document.xref_copy`. It will make a given target \"\n\"PDF object an exact copy of a source object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1462 c6cda05060f04f1080faf3f5125286a2\nmsgid \"**Changes in Version 1.19.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1465 b2517533bd4f4096af88ca08d40edf65\nmsgid \"\"\n\"**Fixed** `#1505 <https://github.com/pymupdf/PyMuPDF/issues/1505>`_. \"\n\"Immunize against circular outline items.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1467 a0d1479b30084068bad49749240fac45\nmsgid \"\"\n\"**Fixed** `#1484 <https://github.com/pymupdf/PyMuPDF/issues/1484>`_. \"\n\"Correct CropBox coordinates are now returned in all situations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1469 cf4a7ec57222449f974ef9027151cf36\nmsgid \"**Fixed** `#1479 <https://github.com/pymupdf/PyMuPDF/issues/1479>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1471 89d3111a652d4fe8809050d5c921e6ea\nmsgid \"\"\n\"**Fixed** `#1474 <https://github.com/pymupdf/PyMuPDF/issues/1474>`_. \"\n\"TextPage objects are now properly deleted again.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1473 ae6c28903fab4ede991daa53cbb1c7b1\nmsgid \"\"\n\"**Added** :ref:`Page` methods and attributes for PDF ``/ArtBox``, \"\n\"``/BleedBox``, ``/TrimBox``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1475 d88880cbc50841bfa7c2c78158e9dd46\nmsgid \"\"\n\"**Added** global attribute :attr:`TESSDATA_PREFIX` for easy checking of \"\n\"OCR support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1477 2be427b5e13c407995bd4f89c694dada\nmsgid \"\"\n\"**Changed** :meth:`Document.xref_set_key` such that dictionary keys will \"\n\"physically be removed if set to value ``\\\"null\\\"``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1479 2a9573afceb049e6b671e0432bd529be\nmsgid \"\"\n\"**Changed** :meth:`Document.extract_font` to optionally return a \"\n\"dictionary (instead of a tuple).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1483 4f57093fd45345639ada517bdde872fb\nmsgid \"**Changes in Version 1.19.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1485 18dfed128cbf40c38cad3ea42fd28a79\nmsgid \"\"\n\"This patch version implements minor improvements for :ref:`Pixmap` and \"\n\"also some important fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1487 1296ee8815a942b6b05e865c50765b3b\nmsgid \"\"\n\"**Fixed** `#1351 <https://github.com/pymupdf/PyMuPDF/discussions/1351>`_.\"\n\" Reverted code that introduced the memory growth in v1.18.15.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1489 3fb4097c0d9c45d884b47f003b15344b\nmsgid \"\"\n\"**Fixed** `#1417 <https://github.com/pymupdf/PyMuPDF/discussions/1417>`_.\"\n\" Developed circumvention for growth of open file handles using \"\n\":meth:`Document.insert_pdf`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1491 770e6646f6e74afcb2d4d3dcf9c81366\nmsgid \"\"\n\"**Fixed** `#1418 <https://github.com/pymupdf/PyMuPDF/discussions/1418>`_.\"\n\" Developed circumvention for memory growth using \"\n\":meth:`Document.insert_pdf`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1493 9689f4e9544c4246b896448b2322a17e\nmsgid \"\"\n\"**Fixed** `#1430 <https://github.com/pymupdf/PyMuPDF/discussions/1430>`_.\"\n\" Developed circumvention for mass pixmap generations of document pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1495 056b81d61e89402fb676e8fa87a24efc\nmsgid \"\"\n\"**Fixed** `#1433 <https://github.com/pymupdf/PyMuPDF/discussions/1433>`_.\"\n\" Solves a bbox error for some Type 3 font in PyMuPDF text processing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1497 d99a708337c94a539ed17294cc959f0d\nmsgid \"\"\n\"**Added** :meth:`Pixmap.color_topusage` to determine the share of the \"\n\"most frequently used color. Solves `#1397 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1397>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1499 72e87358c82b4604b24eac87ac4b4a0f\nmsgid \"\"\n\"**Added** :meth:`Pixmap.warp` which makes a new pixmap from a given \"\n\"arbitrary convex quad inside the pixmap.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1501 82fcb8b930d84658abdd8396247c78de\nmsgid \"\"\n\"**Added** :attr:`Annot.irt_xref` and :meth:`Annot.set_irt_xref` to \"\n\"inquire or set the `/IRT` (\\\"In Response To\\\") property of an annotation.\"\n\" Implements `#1450 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1450>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1503 9d4d189ab5d14fb799a720844599254d\nmsgid \"\"\n\"**Added** :meth:`Rect.torect` and :meth:`IRect.torect` which compute a \"\n\"matrix that transforms to a given other rectangle.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1505 4efbe89603de46a59e1fac42a1a66f6a\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.color_count` to also return the count of each \"\n\"color.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1506 d98f12929cce4021be5db663b7606192\nmsgid \"\"\n\"**Changed** :meth:`Page.get_texttrace` to also return correct span and \"\n\"character bboxes if ``span[\\\"dir\\\"] != (1, 0)``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1510 d093ad5f399047259588e551285fd994\nmsgid \"**Changes in Version 1.19.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1512 2de7c1c23ba441aa92a089ee02a4635b\nmsgid \"\"\n\"This patch version implements minor improvements for \"\n\":meth:`Page.get_drawings` and also some important fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1514 79ddabf469564139b54099c248dbd2b3\nmsgid \"\"\n\"**Fixed** `#1388 <https://github.com/pymupdf/PyMuPDF/discussions/1388>`_.\"\n\" Fixed intermittent memory corruption when insert or updating \"\n\"annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1516 3f76bb3657c5462ba1ebcdd58bdd3116\nmsgid \"\"\n\"**Fixed** `#1375 <https://github.com/pymupdf/PyMuPDF/discussions/1375>`_.\"\n\" Inconsistencies between line numbers as returned by the \\\"words\\\" and \"\n\"the \\\"dict\\\" options of :meth:`Page.get_text` have been corrected.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1518 da3c5e5c691b4bf89bac0ae41797880b\nmsgid \"\"\n\"**Fixed** `#1364 <https://github.com/pymupdf/PyMuPDF/issues/1342>`_. The \"\n\"check for being a ``\\\"rawdict\\\"`` span in :meth:`recover_span_quad` now \"\n\"works correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1520 63807063fb894a7e983829cafe298fe5\nmsgid \"\"\n\"**Fixed** `#1342 <https://github.com/pymupdf/PyMuPDF/issues/1364>`_. \"\n\"Corrected the check for rectangle infiniteness in \"\n\":meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1522 517a112dc4114acab7f4f5c1b91d6fa8\nmsgid \"\"\n\"**Changed** :meth:`Page.get_drawings`, :meth:`Page.get_cdrawings` to \"\n\"return an indicator on the area orientation covered by a rectangle. This \"\n\"implements `#1355 <https://github.com/pymupdf/PyMuPDF/issues/1355>`_. \"\n\"Also, the recognition rate for rectangles and quads has been \"\n\"significantly improved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1524 dcddfb46c54741fd8eda15a642648605\nmsgid \"\"\n\"**Changed** all text search and extraction methods to set the new \"\n\"``flags`` option ``TEXT_MEDIABOX_CLIP`` to ON by default. That bit causes\"\n\" the automatic suppression of all characters that are completely outside \"\n\"a page's mediabox (in as far as that notion is supported for a document \"\n\"type). This eliminates the need for using ``clip=page.rect`` or similar \"\n\"for omitting text outside the visible area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1526 f1b34d7957c44c178eece4e7a6585117\nmsgid \"\"\n\"**Added** parameter ``\\\"dpi\\\"`` to :meth:`Page.get_pixmap` and \"\n\":meth:`Annot.get_pixmap`. When given, parameter ``\\\"matrix\\\"`` is \"\n\"ignored, and a :ref:`Pixmap` with the desired dots per inch is created.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1528 1317c20bf9004475b5d9e6eff7531e6d\nmsgid \"\"\n\"**Added** attributes :attr:`Pixmap.is_monochrome` and \"\n\":attr:`Pixmap.is_unicolor` allowing fast checks of pixmap properties. \"\n\"Addresses `#1397 <https://github.com/pymupdf/PyMuPDF/discussions/1397>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1530 2f34d297248a424d9e4bd6390d4abd59\nmsgid \"\"\n\"**Added** method :meth:`Pixmap.color_count` to determine the unique \"\n\"colors in the pixmap.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1532 0eb08456d2ad4e70b01c79a2c2394012\nmsgid \"\"\n\"**Added** boolean parameter ``\\\"compress\\\"`` to PDF document method \"\n\":meth:`Document.update_stream`. Addresses / enables solution for `#1408 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1408>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1536 e801177ed48145dda1d2c1383f2b0ffc\nmsgid \"**Changes in Version 1.19.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1538 57c5fb9887f847ba933543ad12d8a479\nmsgid \"\"\n\"This is the first patch version to support MuPDF v1.19.0. Apart from one \"\n\"bug fix, it includes important improvements for OCR support and the \"\n\"option to **sort extracted text** to the standard reading order \\\"from \"\n\"top-left to bottom-right\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1540 650b810759ce426fb04200ced720f29f\nmsgid \"\"\n\"**Fixed** `#1328 <https://github.com/pymupdf/PyMuPDF/issues/1328>`_. \"\n\"\\\"words\\\" text extraction again returns correct ``(x0, y0)`` coordinates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1542 3ba1314a889d44d78998ee7e4000e490\nmsgid \"\"\n\"**Changed** :meth:`Page.get_textpage_ocr`: it now supports parameter \"\n\"``dpi`` to control OCR quality. It is also possible to choose whether the\"\n\" **full page** should be OCRed or **only the images displayed** by the \"\n\"page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1544 e63faaa903ec48a596466ba7c81be36a\nmsgid \"\"\n\"**Changed** :meth:`Page.get_drawings` and :meth:`Page.get_cdrawings` to \"\n\"automatically convert colors to RGB color tuples. Implements `#1332 \"\n\"<https://github.com/pymupdf/PyMuPDF/discussions/1332>`_. Similar change \"\n\"was applied to :meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1546 478ae75188fb496dbd68e612249a93be\nmsgid \"\"\n\"**Changed** :meth:`Page.get_text` to support a parameter ``sort``. If set\"\n\" to ``True`` the output is conveniently sorted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1551 1fcee4618b1a4606bc1bb1cb00a3c04c\nmsgid \"**Changes in Version 1.19.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1553 ddc73ab2354e49519073ae9c706da26e\nmsgid \"\"\n\"This is the first version supporting MuPDF 1.19.*, published 2021-10-05. \"\n\"It introduces many new features compared to the previous version 1.18.*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1555 b350897b3a7d4af6a0a1184d0161e9f5\nmsgid \"\"\n\"PyMuPDF has now picked up integrated Tesseract OCR support, which was \"\n\"already present in MuPDF v1.18.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1557 35dd462d0329459bb8788ee6118ce5b5\nmsgid \"\"\n\"Supported images can be OCRed via their :ref:`Pixmap` which results in a \"\n\"1-page PDF with a text layer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1558 40eb6a6a0deb477f802cfaa332cd816d\nmsgid \"\"\n\"All supported document pages (i.e. not only PDFs), can be OCRed using \"\n\"specialized text extraction methods. The result is a mixture of standard \"\n\"and OCR text (depending on which part of the page was deemed to require \"\n\"OCRing) that can be searched and extracted without restrictions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1559 734f1859407e4513b2cad5b0b02ac6f4\nmsgid \"\"\n\"All this requires an independent installation of Tesseract. MuPDF \"\n\"actually (only) needs the location of Tesseract's ``\\\"tessdata\\\"`` \"\n\"folder, where its language support data are stored. This location must be\"\n\" available as environment variable ``TESSDATA_PREFIX``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1561 b0bd5ab69f33429697fd89f94ea87403\nmsgid \"\"\n\"A new MuPDF feature is **journalling PDF updates**, which is also \"\n\"supported by this PyMuPDF version. Changes may be logged, rolled back or \"\n\"replayed, allowing to implement a whole new level of control over PDF \"\n\"document integrity -- similar to functions present in modern database \"\n\"systems.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1563 c3bc9664f319416cbfbd764f183ecaf1\nmsgid \"\"\n\"A third feature (unrelated to the new MuPDF version) includes the ability\"\n\" to detect when page **objects cover or hide each other**. It is now e.g.\"\n\" possible to see that text is covered by a drawing or an image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1565 368ec08cb31e489e94e2d8a7e4ee86e4\nmsgid \"\"\n\"**Changed** terminology and meaning of important geometry concepts: \"\n\"Rectangles are now characterized as *finite*, *valid* or *empty*, while \"\n\"the definitions of these terms have also changed. Rectangles specifically\"\n\" are now thought of being \\\"open\\\": not all corners and sides are \"\n\"considered part of the rectangle. Please do read the :ref:`Rect` section \"\n\"for details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1567 6dd7d23a06ad4f14b2021126e1286e49\nmsgid \"\"\n\"**Added** new parameter `\\\"no_new_id\\\"` to :meth:`Document.save` / \"\n\":meth:`Document.tobytes` methods. Use it to suppress updating the second \"\n\"item of the document ``/ID`` which in PDF indicates that the original \"\n\"file has been updated. If the PDF has no ``/ID`` at all yet, then no new \"\n\"one will be created either.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1569 de9906d677934e3c8dbe4a106dce7c74\nmsgid \"\"\n\"**Added** a **journalling facility** for PDF updates. This allows logging\"\n\" changes, undoing or redoing them, or saving the journal for later use. \"\n\"Refer to :meth:`Document.journal_enable` and friends.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1571 c4160924dc184c4b927a1b6297223458\nmsgid \"\"\n\"**Added** new :ref:`Pixmap` methods :meth:`Pixmap.pdfocr_save` and \"\n\":meth:`Pixmap.pdfocr_tobytes`, which generate a 1-page PDF containing the\"\n\" pixmap as PNG image with OCR text layer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1573 0e3c62d627264d9f8ffce673e0023b81\nmsgid \"\"\n\"**Added** :meth:`Page.get_textpage_ocr` which executes optical character \"\n\"recognition for the page, then extracts the results and stores them \"\n\"together with \\\"normal\\\" page content in a :ref:`TextPage`. Use or reuse \"\n\"this object in subsequent text extractions and text searches to avoid \"\n\"multiple efforts. The existing text search and text extraction methods \"\n\"have been extended to support a separately created textpage -- see next \"\n\"item.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1575 04ef1d300161437ba5b4e28ffed12386\nmsgid \"\"\n\"**Added** a new parameter ``textpage`` to text extraction and text search\"\n\" methods. This allows reuse of a previously created :ref:`TextPage` and \"\n\"thus achieves significant runtime benefits -- which is especially \"\n\"important for the new OCR features. But \\\"normal\\\" text extractions can \"\n\"definitely also benefit.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1577 a6d0664ee9d14b07908e08d426ef50e7\nmsgid \"\"\n\"**Added** :meth:`Page.get_texttrace`, a technical method delivering low-\"\n\"level text character properties. It was present before as a private \"\n\"method, but the author felt it now is mature enough to be officially \"\n\"available. It specifically includes a \\\"sequence number\\\" which indicates\"\n\" the page appearance build operation that painted the text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1579 ccb6adfad05549ff96a7d75a2f08de75\nmsgid \"\"\n\"**Added** :meth:`Page.get_bboxlog` which delivers the list of rectangles \"\n\"of page objects like text, images or drawings. Its significance lies in \"\n\"its sequence: rectangles intersecting areas with a lower index are \"\n\"covering or hiding them.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1581 3edfcd55b842410ab082ab50b80e132f\nmsgid \"\"\n\"**Changed** methods :meth:`Page.get_drawings` and \"\n\":meth:`Page.get_cdrawings` to include a \\\"sequence number\\\" indicating \"\n\"the page appearance build operation that created the drawing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1583 d4fd7415a1f44eb0b738d6f5df0af7cb\nmsgid \"\"\n\"**Fixed** `#1311 <https://github.com/pymupdf/PyMuPDF/issues/1311>`_. \"\n\"Field values in comboboxes should now be handled correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1584 7733dd257974437aa148b45f6ada6568\nmsgid \"\"\n\"**Fixed** `#1290 <https://github.com/pymupdf/PyMuPDF/issues/1290>`_. \"\n\"Error was caused by incorrect rectangle emptiness check, which is fixed \"\n\"due to new geometry logic of this version.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1585 f61c1c44cead4da28d5a0d498a515a7c\nmsgid \"\"\n\"**Fixed** `#1286 <https://github.com/pymupdf/PyMuPDF/issues/1286>`_. Text\"\n\" alignment for redact annotations is working again.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1586 bba07d14226e43b498663a99b03b7eb5\nmsgid \"\"\n\"**Fixed** `#1287 <https://github.com/pymupdf/PyMuPDF/issues/1287>`_. \"\n\"Infinite loop issue for non-Windows systems when applying some redactions\"\n\" has been resolved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1587 5324927b491340e983434647e41ce37e\nmsgid \"\"\n\"**Fixed** `#1284 <https://github.com/pymupdf/PyMuPDF/issues/1284>`_. Text\"\n\" layout destruction after applying redactions in some cases has been \"\n\"resolved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1591 29ec5f63fdcc4f7b857449ced614ae34\nmsgid \"**Changes in Version 1.18.18 / 1.18.19**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1593 629737c065e9445f96330c435e44d4dc\nmsgid \"\"\n\"**Fixed** issue `#1266 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1266>`_. Failure to set \"\n\":attr:`Pixmap.samples` in important cases, was hotfixed in a new version \"\n\"1.18.19.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1595 0abe968e8c8349d6991a7e4002c7cc03\nmsgid \"\"\n\"**Fixed** issue `#1257 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1257>`_. Removing the read-\"\n\"only flag from PDF fields is now possible.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1597 d5ee064120c44b55a574eb82a9b65093\nmsgid \"\"\n\"**Fixed** issue `#1252 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1252>`_. Now correctly \"\n\"specifying the ``zoom`` value for PDF link annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1599 a7183e1808424b69a1a92a0c6c19251d\nmsgid \"\"\n\"**Fixed** issue `#1244 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1244>`_. Now correctly \"\n\"computing the transform matrix in :meth:`Page.get_image__bbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1601 5b909b03e5e84a92b114914838261915\nmsgid \"\"\n\"**Fixed** issue `#1241 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1241>`_. Prevent returning \"\n\"artifact characters in :meth:`Page.get_textbox`, which happened in \"\n\"certain constellations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1603 76b7202d83754586a167674467627ca6\nmsgid \"\"\n\"**Fixed** issue `#1234 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1234>`_. Avoid creating \"\n\"infinite rectangles in corner cases -- :meth:`Page.get_drawings`, \"\n\":meth:`Page.get_cdrawings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1605 11277e7c50c84168b89d7c869c0aeb1e\nmsgid \"\"\n\"**Added** test data and test scripts to the source PyPI source \"\n\"distribution.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1609 490bf1a121f24135b3e3256666187363\nmsgid \"**Changes in Version 1.18.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1611 d1e131b0d646485daf1c919e31b766d3\nmsgid \"\"\n\"Focus of this version are major performance improvements of selected \"\n\"functions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1613 03ea6bb0f78c4d679bd6c08b450d9c4e\nmsgid \"\"\n\"**Fixed** issue `#1199 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1199>`_. Using a non-existing \"\n\"page number in :meth:`Document.get_page_images` and friends will no \"\n\"longer lead to segfaults.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1615 0316ddf4a6a14b918ae314d88765508c\nmsgid \"\"\n\"**Changed** :meth:`Page.get_drawings` to now differentiate between \"\n\"\\\"stroke\\\", \\\"fill\\\" and combined paths. Paths containing more than one \"\n\"rectangle (i.e. \\\"re\\\" items) are now supported. Extracting \\\"clipped\\\" \"\n\"paths is now available as an option.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1617 68269b90e4374ece9bcc4beae2a5d8ab\nmsgid \"\"\n\"**Added** :meth:`Page.get_cdrawings`, performance-optimized version of \"\n\":meth:`Page.get_drawings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1619 b9fdb8798cef43d6af0ab313e6117152\nmsgid \"\"\n\"**Added** :attr:`Pixmap.samples_mv`, *memoryview* of a pixmap's pixel \"\n\"area. Does not copy and thus always accesses the current state of that \"\n\"area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1621 b4530586fbcc46de94110b7f601c43dd\nmsgid \"\"\n\"**Added** :attr:`Pixmap.samples_ptr`, Python \\\"pointer\\\" to a pixmap's \"\n\"pixel area. Allows much faster creation (factor 800+) of Qt images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1627 494c735b3a214b2bb172c9afb76b92b1\nmsgid \"**Changes in Version 1.18.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1629 9320ef32a6ec458db091ec9991261f2f\nmsgid \"\"\n\"**Fixed** issue `#1184 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1184>`_. Existing PDF widget \"\n\"fonts in a PDF are now accepted (i.e. not forcedly changed to a Base-14 \"\n\"font).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1631 159b6408c2ea4b86a063f21fcce0b7de\nmsgid \"\"\n\"**Fixed** issue `#1154 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1154>`_. Text search hits \"\n\"should now be correct when ``clip`` is specified.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1633 e98ab6e601d143ab99e23ce8ac756e25\nmsgid \"**Fixed** issue `#1152 <https://github.com/pymupdf/PyMuPDF/issues/1152>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1635 0793a7276f6a47c7833dc4f02c69c59c\nmsgid \"**Fixed** issue `#1146 <https://github.com/pymupdf/PyMuPDF/issues/1146>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1637 634669f89d54425fabf3395cef374ae3\nmsgid \"\"\n\"**Added** :attr:`Link.flags` and :meth:`Link.set_flags` to the \"\n\":ref:`Link` class. Implements enhancement requests `#1187 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1187>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1639 f0c43b248f16409a8f0905afee41db5d\nmsgid \"\"\n\"**Added** option to *simulate* :meth:`TextWriter.fill_textbox` output for\"\n\" predicting the number of lines, that a given text would occupy in the \"\n\"textbox.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1641 7ed434aeca7e4c8283c2ce9ac764e204\nmsgid \"\"\n\"**Added** text output support as subcommand `gettext` to the ``fitz`` CLI\"\n\" module. Most importantly, original **physical text layout** reproduction\"\n\" is now supported.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1646 7a61839613704cb6ba89df11cfd8e0c5\nmsgid \"**Changes in Version 1.18.15**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1648 76b9d70df76946379cb92b397413d1b1\nmsgid \"\"\n\"**Fixed** issue `#1088 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1088>`_. Removing an \"\n\"annotation's fill color should now work again both ways, using the \"\n\"``fill_color=[]`` argument in :meth:`Annot.update` as well as ``fill=[]``\"\n\" in :meth:`Annot.set_colors`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1650 be8edc4369ba4c6d92c42fd279c10a37\nmsgid \"\"\n\"**Fixed** issue `#1081 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1081>`_. \"\n\":meth:`Document.subset_fonts`: fixed an error which created wrong \"\n\"character widths for some fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1652 c86ec8d5f336461a9a82cf58dab23bca\nmsgid \"\"\n\"**Fixed** issue `#1078 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1078>`_. :meth:`Page.get_text`\"\n\" and other methods related to text extraction: changed the default value \"\n\"of the :ref:`TextPage` ``flags`` parameter. All whitespace and \"\n\":data:`ligatures` are now preserved.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1654 6bf853d1b4f24ed3b493acbbaf102307\nmsgid \"\"\n\"**Fixed** issue `#1085 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1085>`_. The old *snake_cased*\"\n\" alias of ``fitz.detTextlength`` is now defined correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1656 0974e8722a4445e0894e2188d5074069\nmsgid \"\"\n\"**Changed** :meth:`Document.subset_fonts` will now correctly prefix font \"\n\"subsets with an appropriate six letter uppercase tag, complying with the \"\n\"PDF specification.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1658 437884a2beb34834be5a5813ff146205\nmsgid \"\"\n\"**Added** new method :meth:`Widget.button_states` which returns the \"\n\"possible values that a button-type field can have when being set to \"\n\"\\\"on\\\" or \\\"off\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1660 e165a6b51c0c42f6ac55bb2164ed36ce\nmsgid \"\"\n\"**Added** support of text with **Small Capital** letters to the \"\n\":ref:`Font` and :ref:`TextWriter` classes. This is reflected by an \"\n\"additional bool parameter ``small_caps`` in various of their methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1665 5fa6df6719ec4a30bc5737a2250ddf26\nmsgid \"**Changes in Version 1.18.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1667 246831ba1ef247c09cc05eb90a12135b\nmsgid \"\"\n\"**Finished** implementing new, \\\"snake_cased\\\" names for methods and \"\n\"properties, that were \\\"camelCased\\\" and awkward in many aspects. At the \"\n\"end of this documentation, there is section :ref:`Deprecated` with more \"\n\"background and a mapping of old to new names.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1669 e9896e6c30074ac28de21b72e13344fd\nmsgid \"\"\n\"**Fixed** issue `#1053 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1053>`_. \"\n\":meth:`Page.insert_image`: when given, include image mask in the hash \"\n\"computation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1671 856342d7e04c4c05ad362a20f30a00c5\nmsgid \"\"\n\"**Fixed** issue `#1043 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1043>`_. Added \"\n\"``Pixmap.getPNGdata`` to the aliases of :meth:`Pixmap.tobytes`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1673 a40ac7bfdd1d4c329450f6a5ba99872e\nmsgid \"\"\n\"**Fixed** an internal error when computing the enveloping rectangle of \"\n\"drawn paths as returned by :meth:`Page.get_drawings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1675 dae13ebf211f48aaa0f6305a01c8c616\nmsgid \"\"\n\"**Fixed** an internal error occasionally causing loops when outputting \"\n\"text via :meth:`TextWriter.fill_textbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1677 944833cd11d14508b1e6e8fa1a487586\nmsgid \"\"\n\"**Added** :meth:`Font.char_lengths`, which returns a tuple of character \"\n\"widths of a string.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1679 4c127faaaa4542d68be1974e72156cdb\nmsgid \"\"\n\"**Added** more ways to specify pages in :meth:`Document.delete_pages`. \"\n\"Now a sequence (list, tuple or range) can be specified, and the Python \"\n\"``del`` statement can be used. In the latter case, Python ``slices`` are \"\n\"also accepted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1681 06fd838ceb61465d9f689dfd3aebbab2\nmsgid \"\"\n\"**Changed** :meth:`Document.del_toc_item`, which disables a single item \"\n\"of the TOC: previously, the title text was removed. Instead, now the \"\n\"complete item will be shown grayed-out by supporting viewers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1686 7a4fd8bb15ab4fbcaaa183993d721089\nmsgid \"**Changes in Version 1.18.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1688 aeb68fdb27db43d68f6b5362aa749391\nmsgid \"**Fixed** issue `#1014 <https://github.com/pymupdf/PyMuPDF/issues/1014>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1689 8ee7d51d2b5941f8b64a7092fe06f789\nmsgid \"\"\n\"**Fixed** an internal memory leak when computing image bboxes -- \"\n\":meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1690 6e3c2aaf0d0b4752b02aa8c91326937e\nmsgid \"\"\n\"**Added** support for low-level access and modification of the PDF \"\n\"trailer. Applies to :meth:`Document.xref_get_keys`, \"\n\":meth:`Document.xref_get_key`, and :meth:`Document.xref_set_key`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1691 d26b610465374b1a95f57d151f841d2e\nmsgid \"**Added** documentation for maintaining private entries in PDF metadata.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1692 49f75a7ada254386acc0d8b341ed91c6\nmsgid \"\"\n\"**Added** documentation for handling transparent image insertions, \"\n\":meth:`Page.insert_image`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1693 457c2b1325b24f60ab107fe02a4e0085\nmsgid \"\"\n\"**Added** :meth:`Page.get_image_rects`, an improved version of \"\n\":meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1694 a7471bfaf29b46c0bf1baba965058c8b\nmsgid \"\"\n\"**Changed** :meth:`Document.delete_pages` to support various ways of \"\n\"specifying pages to delete. Implements `#1042 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/1042>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1695 3f2e525e5db5466cbf2b21ae6e3e9c36\nmsgid \"\"\n\"**Changed** :meth:`Page.insert_image` to also accept the xref of an \"\n\"existing image in the file. This allows \\\"copying\\\" images between pages,\"\n\" and extremely fast multiple insertions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1696 819681238cbc4a129e57b370dfb026fc\nmsgid \"\"\n\"**Changed** :meth:`Page.insert_image` to also accept the integer \"\n\"parameter ``alpha``. To be used for performance improvements.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1697 43b014e80e8041ce88847b0848cd3523\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.set_alpha` to support new parameters for pre-\"\n\"multiplying colors with their alpha values and setting a specific color \"\n\"to fully transparent (e.g. white).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1698 d00c4f08df31471e976b37826d70cb1c\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_add` to automatically set creation \"\n\"and modification date-time. Correspondingly, :meth:`Document.embfile_upd`\"\n\" automatically maintains modification date-time (``/ModDate`` PDF key), \"\n\"and :meth:`Document.embfile_info` correspondingly reports these data. In \"\n\"addition, the embedded file's associated \\\"collection item\\\" is included \"\n\"via its :data:`xref`. This supports the development of PDF portfolio \"\n\"applications.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1702 d6c3f0ac21134173a004ebfa78fe2315\nmsgid \"**Changes in Version 1.18.11 / 1.18.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1704 5c6ecd8a73da4cd6a54e60917ddff07a\nmsgid \"\"\n\"**Fixed** issue `#972 <https://github.com/pymupdf/PyMuPDF/issues/972>`_. \"\n\"Improved layout of source distribution material.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1705 086168881dcc4f639364df509a6877b1\nmsgid \"\"\n\"**Fixed** issue `#962 <https://github.com/pymupdf/PyMuPDF/issues/962>`_. \"\n\"Stabilized Linux distribution detection for generating PyMuPDF from \"\n\"sources.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1706 3a60973423d2463aa5423dc31856ba76\nmsgid \"\"\n\"**Added:** :meth:`Page.get_xobjects` delivers the result of \"\n\":meth:`Document.get_page_xobjects`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1707 a0b89ac75a28458fb93356628c87d9ab\nmsgid \"\"\n\"**Added:** :meth:`Page.get_image_info` delivers meta information for all \"\n\"images shown on the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1708 9e865b21aa37414dbfea24ec37e19b67\nmsgid \"\"\n\"**Added:** :meth:`Tools.mupdf_display_warnings` allows setting on / off \"\n\"the display of MuPDF-generated warnings. The default is off.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1709 e3d2420ee8c24d1aa43455c800972e3c\nmsgid \"\"\n\"**Added:** :meth:`Document.ez_save` convenience alias of \"\n\":meth:`Document.save` with some different defaults.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1710 7007006565b94595b23bf039c3e09338\nmsgid \"\"\n\"**Changed:** Image extractions of document pages now also contain the \"\n\"image's **transformation matrix**. This concerns \"\n\":meth:`Page.get_image_bbox` and the DICT, JSON, RAWDICT, and RAWJSON \"\n\"variants of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1715 62af1c5f6b62467897742422e1590f7d\nmsgid \"**Changes in Version 1.18.10**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1717 922707d45703479bbd67527180a768ec\nmsgid \"\"\n\"**Fixed** issue `#941 <https://github.com/pymupdf/PyMuPDF/issues/941>`_. \"\n\"Added old aliases for :meth:`DisplayList.get_pixmap` and \"\n\":meth:`DisplayList.get_textpage`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1718 5f5903a43c1f44a3bf154f3b1530d64a\nmsgid \"\"\n\"**Fixed** issue `#929 <https://github.com/pymupdf/PyMuPDF/issues/929>`_. \"\n\"Stabilized removal of JavaScript objects with :meth:`Document.scrub`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1719 0972fadf04e741629d46a18515526a9d\nmsgid \"\"\n\"**Fixed** issue `#927 <https://github.com/pymupdf/PyMuPDF/issues/927>`_. \"\n\"Removed a loop in the reworked :meth:`TextWriter.fill_textbox`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1720 033e96b4eceb4014bd5620c1e986198d\nmsgid \"\"\n\"**Changed** :meth:`Document.xref_get_keys` and \"\n\":meth:`Document.xref_get_key` to also allow accessing the PDF trailer \"\n\"dictionary. This can be done by using `-1` as the xref number argument.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1721 74ff56e5727c43138b496604bbfe57f9\nmsgid \"\"\n\"**Added** a number of functions for reconstructing the quads for text \"\n\"lines, spans and characters extracted by :meth:`Page.get_text` options \"\n\"\\\"dict\\\" and \\\"rawdict\\\". See :meth:`recover_quad` and friends.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1722 29aa32686d874d42b22bfa8a3901aa14\nmsgid \"\"\n\"**Added** :meth:`Tools.unset_quad_corrections` to suppress character quad\"\n\" corrections (occasionally required for erroneous fonts).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1726 3a7453ab65404c52984aee45364e6724\nmsgid \"**Changes in Version 1.18.9**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1729 e1b22c2f9fe54eb993a50fcd6112601f\nmsgid \"\"\n\"**Fixed** issue `#888 <https://github.com/pymupdf/PyMuPDF/issues/888>`_. \"\n\"Removed ambiguous statements concerning PyMuPDF's license, which is now \"\n\"clearly stated to be GNU AGPL V3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1730 f4d998abf2364f48a156cb6de76c69b7\nmsgid \"**Fixed** issue `#895 <https://github.com/pymupdf/PyMuPDF/issues/895>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1731 69b074661fb04a1c9748f0ae259d8153\nmsgid \"\"\n\"**Fixed** issue `#896 <https://github.com/pymupdf/PyMuPDF/issues/896>`_. \"\n\"Since v1.17.6 PyMuPDF suppresses the font subset tags and only reports \"\n\"the base fontname in text extraction outputs \\\"dict\\\" / \\\"json\\\" / \"\n\"\\\"rawdict\\\" / \\\"rawjson\\\". Now a new global parameter can request the old\"\n\" behaviour, :meth:`Tools.set_subset_fontnames`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1732 0e51b11e295245bdb5143f3055f5f4c6\nmsgid \"\"\n\"**Fixed** issue `#885 <https://github.com/pymupdf/PyMuPDF/issues/885>`_. \"\n\"Pixmap creation now also works with filenames given as ``pathlib.Paths``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1733 3bfe043f395249f2ad66c8714a4dcd24\nmsgid \"\"\n\"**Changed** :meth:`Document.subset_fonts`: Text is **not rewritten** any \"\n\"more and should therefore **retain all its original properties** -- like \"\n\"being hidden or being controlled by Optional Content mechanisms.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1734 23ad1d2d69494a61b31f3bf6e0d688e0\nmsgid \"\"\n\"**Changed** :ref:`TextWriter` output to also accept text in right to left\"\n\" mode (Arabian, Hebrew): :meth:`TextWriter.fill_textbox`, \"\n\":meth:`TextWriter.append`. These methods now accept a new boolean \"\n\"parameter `right_to_left`, which is *False* by default. Implements `#897 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/897>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1735 27997725f8e4450c87939082e366439e\nmsgid \"\"\n\"**Changed** :meth:`TextWriter.fill_textbox` to return all lines of text, \"\n\"that did not fit in the given rectangle. Also changed the default of the \"\n\"``warn`` parameter to no longer print a warning message in overflow \"\n\"situations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1736 66e2fd480ef348c094149914650471d0\nmsgid \"\"\n\"**Added** a utility function :meth:`recover_quad`, which computes the \"\n\"quadrilateral of a span. This function can be used for correctly marking \"\n\"text extracted with the \\\"dict\\\" or \\\"rawdict\\\" options of \"\n\":meth:`Page.get_text`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1740 dce8476d6a3749f89835fc274cdabd84\nmsgid \"**Changes in Version 1.18.8**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1743 fa20b571b5c14e288bfcba7b82655bee\nmsgid \"\"\n\"This is a bug fix version only. We are publishing early because of the \"\n\"potentially widely used functions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1745 21142c13d0cd44bea29198c954e7f0e6\nmsgid \"\"\n\"**Fixed** issue `#881 <https://github.com/pymupdf/PyMuPDF/issues/881>`_. \"\n\"Fixed a memory leak in :meth:`Page.insert_image` when inserting images \"\n\"from files or memory.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1746 5f457acfd5954696ae76970b611ac49a\nmsgid \"\"\n\"**Fixed** issue `#878 <https://github.com/pymupdf/PyMuPDF/issues/878>`_. \"\n\"``pathlib.Path`` objects should now correctly handle file path \"\n\"hierarchies.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1751 85971c3fb54e449190448842ef48209a\nmsgid \"**Changes in Version 1.18.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1754 fbe2287c70d74d55bfa1dd7a61d1a827\nmsgid \"\"\n\"**Added** an experimental :meth:`Document.subset_fonts` which reduces the\"\n\" size of eligible fonts based on their use by text in the PDF. Implements\"\n\" `#855 <https://github.com/pymupdf/PyMuPDF/discussions/855>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1755 e300f81c0c2a414a95786dc2a5b922be\nmsgid \"\"\n\"**Implemented** request `#870 \"\n\"<https://github.com/pymupdf/PyMuPDF/pull/870>`_: \"\n\":meth:`Document.convert_to_pdf` now also supports PDF documents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1756 8b39542efeb8486782751bc4045f8c45\nmsgid \"\"\n\"**Renamed** ``Document.write`` to :meth:`Document.tobytes` for greater \"\n\"clarity. But the deprecated name remains available for some time.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1757 6717eb5a2cfb422a8b239e698e9d1a4e\nmsgid \"\"\n\"**Implemented** request `#843 \"\n\"<https://github.com/pymupdf/PyMuPDF/Discussions/843>`_: \"\n\":meth:`Document.tobytes` now supports linearized PDF output. \"\n\":meth:`Document.save` now also supports writing to Python **file \"\n\"objects**. In addition, the open function now also supports Python file \"\n\"objects.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1758 318196b9b9f24559b099a5a3b86b61a3\nmsgid \"**Fixed** issue `#844 <https://github.com/pymupdf/PyMuPDF/issues/844>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1759 22303a902c214152a94cf6908eaada79\nmsgid \"**Fixed** issue `#838 <https://github.com/pymupdf/PyMuPDF/issues/838>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1760 8d1575cb41f944d1ab091d1f15fdfe3f\nmsgid \"\"\n\"**Fixed** issue `#823 <https://github.com/pymupdf/PyMuPDF/issues/823>`_. \"\n\"More logic for better support of OCRed text output (Tesseract, ABBYY).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1761 938fa234a4d64b4998e755f30a353917\nmsgid \"**Fixed** issue `#818 <https://github.com/pymupdf/PyMuPDF/issues/818>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1762 5b25601056b641bebbe1fdbe9fbf59fc\nmsgid \"**Fixed** issue `#814 <https://github.com/pymupdf/PyMuPDF/issues/814>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1763 b4352fd5bf734216a09bc2b65068a9a1\nmsgid \"\"\n\"**Added** :meth:`Document.get_page_labels` which returns a list of page \"\n\"label definitions of a PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1764 d10d74d2add045f19432215b68dc5965\nmsgid \"\"\n\"**Added** :meth:`Document.has_annots` and :meth:`Document.has_links` to \"\n\"check whether these object types are present anywhere in a PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1765 344e56b009634edaa8a7654870785c6a\nmsgid \"\"\n\"**Added** expert low-level functions to simplify inquiry and modification\"\n\" of PDF object sources: :meth:`Document.xref_get_keys` lists the keys of \"\n\"object :data:`xref`, :meth:`Document.xref_get_key` returns type and \"\n\"content of a key, and :meth:`Document.xref_set_key` modifies the key's \"\n\"value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1766 97ffd95b565242c8a475c6f2123f9b83\nmsgid \"\"\n\"**Added** parameter ``thumbnails`` to :meth:`Document.scrub` to also \"\n\"allow removing page thumbnail images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1767 be54a84b631a4f539269cea4d2530c10\nmsgid \"\"\n\"**Improved** documentation for how to add valid text marker annotations \"\n\"for non-horizontal text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1769 7ec7306e128341c2a63a9daaf99494bb\nmsgid \"\"\n\"We continued the process of renaming methods and properties from \"\n\"*\\\"mixedCase\\\"* to *\\\"snake_case\\\"*. Documentation usually mentions the \"\n\"new names only, but old, deprecated names remain available for some time.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1775 40b8c78ac8154766b3f786804b70d764\nmsgid \"**Changes in Version 1.18.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1777 099ac66b71ab437b8f793444fbf3c368\nmsgid \"**Fixed** issue `#812 <https://github.com/pymupdf/PyMuPDF/issues/812>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1778 8d754c7625ba4e16b8b1d2da2931571c\nmsgid \"\"\n\"**Fixed** issue `#793 <https://github.com/pymupdf/PyMuPDF/issues/793>`_. \"\n\"Invalid document metadata previously prevented opening some documents at \"\n\"all. This error has been removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1779 b6756d8e13654194ae64028173969354\nmsgid \"\"\n\"**Fixed** issue `#792 <https://github.com/pymupdf/PyMuPDF/issues/792>`_. \"\n\"Text search and text extraction will make no rectangle containment checks\"\n\" at all if the default ``clip=None`` is used.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1780 f3374a74399e41139ae1b0fd15053232\nmsgid \"**Fixed** issue `#785 <https://github.com/pymupdf/PyMuPDF/issues/785>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1781 6f0ad41d3e0845679fc1b7f630d9350e\nmsgid \"\"\n\"**Fixed** issue `#780 <https://github.com/pymupdf/PyMuPDF/issues/780>`_. \"\n\"Corrected a parameter check error.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1782 a9af2b2f5b024f1d90aca0eed1eff596\nmsgid \"\"\n\"**Fixed** issue `#779 <https://github.com/pymupdf/PyMuPDF/issues/779>`_. \"\n\"Fixed typo\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1783 52e2c5d1e3734d0b9c1eafeea70502c0\nmsgid \"\"\n\"**Added** an option to set the desired line height for text boxes. \"\n\"Implements `#804 <https://github.com/pymupdf/PyMuPDF/issues/804>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1784 8a89dd2499fa4288aa2e4376409bc950\nmsgid \"\"\n\"**Changed** text position retrieval to better cope with Tesseract's \"\n\"glyphless font. Implements `#803 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/803>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1785 1c3abaa13d464f07839341b87f7b065c\nmsgid \"\"\n\"**Added** an option to choose the prefix of new annotations, fields and \"\n\"links for providing unique annotation ids. Implements request `#807 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/807>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1786 705f241926b94e4faed825b90187d9a8\nmsgid \"\"\n\"**Added** getting and setting color and text properties for Table of \"\n\"Contents items for PDFs. Implements `#779 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/779>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1787 f290b3e394a643ef92eb166d6ac700ba\nmsgid \"\"\n\"**Added** PDF page label handling: :meth:`Page.get_label()` returns the \"\n\"page label, :meth:`Document.get_page_numbers` return all page numbers \"\n\"having a specified label, and :meth:`Document.set_page_labels` adds or \"\n\"updates a PDF's page label definition.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1792 204e52071aeb4560ad583594170382fc\nmsgid \"\"\n\"This version introduces **Python type hinting**. The goal is to provide \"\n\"each parameter and the return value of all functions and methods with \"\n\"type information. This still is work in progress although the majority of\"\n\" functions has already been handled.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1797 ff861662db5c4fe985c61a23a602d0ab\nmsgid \"**Changes in Version 1.18.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1799 8972338cdcc14af3a7644a3dcddf69e2\nmsgid \"\"\n\"Apart from several fixes, this version also focusses on several minor, \"\n\"but important feature improvements. Among the latter is a more precise \"\n\"computation of proper line heights and insertion points for writing / \"\n\"inserting text. As opposed to using font-agnostic constants, these values\"\n\" are now taken from the font's properties.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1801 f9a9d31367f946218578af60d466b702\nmsgid \"\"\n\"Also note that this is the first version which does no longer provide \"\n\"pregenerated wheels for Python versions older than 3.6. PIP also \"\n\"discontinues support for these by end of this year 2020.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1803 93396822ddee484c904221f0e650bb40\nmsgid \"\"\n\"**Fixed** issue `#771 <https://github.com/pymupdf/PyMuPDF/issues/771>`_. \"\n\"By using \\\"small glyph heights\\\" option, the full page text can be \"\n\"extracted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1804 4283660ecb4e497a8d5f66c223269138\nmsgid \"**Fixed** issue `#768 <https://github.com/pymupdf/PyMuPDF/issues/768>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1805 cb94c9971f18482b8a6116bac1e91eda\nmsgid \"**Fixed** issue `#750 <https://github.com/pymupdf/PyMuPDF/issues/750>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1806 0f4ccdc52d33496780a6883b3eac2040\nmsgid \"\"\n\"**Fixed** issue `#739 <https://github.com/pymupdf/PyMuPDF/issues/739>`_. \"\n\"The \\\"dict\\\", \\\"rawdict\\\" and corresponding JSON output variants now have\"\n\" two new *span* keys: ``\\\"ascender\\\"`` and ``\\\"descender\\\"``. These \"\n\"floats represent special font properties which can be used to compute \"\n\"bboxes of spans or characters of **exactly fontsize height** (as opposed \"\n\"to the default line height). An example algorithm is shown in section \"\n\"\\\"Span Dictionary\\\" `here \"\n\"<https://pymupdf.readthedocs.io/en/latest/textpage.html#dictionary-\"\n\"structure-of-extractdict-and-extractrawdict>`_. Also improved the \"\n\"detection and correction of ill-specified ascender / descender values \"\n\"encountered in some fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1807 46d09243233b47bfabfb624aabe62a7f\nmsgid \"\"\n\"**Added** a new, experimental :meth:`Tools.set_small_glyph_heights` -- \"\n\"also in response to issue `#739 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/739>`_. This method sets or \"\n\"unsets a global parameter to **always compute bboxes with fontsize \"\n\"height**. If \\\"on\\\", text searching and all text extractions will \"\n\"returned rectangles, bboxes and quads with a smaller height.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1808 2348f09c087f4e77a9552300a273b2f9\nmsgid \"**Fixed** issue `#728 <https://github.com/pymupdf/PyMuPDF/issues/728>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1809 24ffb89f8a2847978a993810a34d9d8e\nmsgid \"\"\n\"**Changed** fill color logic of 'Polyline' annotations: this parameter \"\n\"now only pertains to line end symbols -- the annotation itself can no \"\n\"longer have a fill color. Also addresses issue `#727 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/727>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1810 d11988b7d91c474394a305026cbdac36\nmsgid \"\"\n\"**Changed** :meth:`Page.getImageBbox` to also compute the bbox if the \"\n\"image is contained in an XObject.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1811 92be2318a74e44bcbfe6d9d124cc6944\nmsgid \"\"\n\"**Changed** :meth:`Shape.insertTextbox`, resp. \"\n\":meth:`Page.insertTextbox`, resp. :meth:`TextWriter.fillTextbox` to \"\n\"respect font's properties \\\"ascender\\\" / \\\"descender\\\" when computing \"\n\"line height and insertion point. This should no longer lead to line \"\n\"overlaps for multi-line output. These methods used to ignore font \"\n\"specifics and used constant values instead.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1816 726b3c851a2742a08174e040daa6b3fc\nmsgid \"**Changes in Version 1.18.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1818 0669695e181f46b8b1d1c44f84c7cc1e\nmsgid \"\"\n\"This version adds several features to support PDF Optional Content. Among\"\n\" other things, this includes OCMDs (Optional Content Membership \"\n\"Dictionaries) with the full scope of *\\\"visibility expressions\\\"* (PDF \"\n\"key ``/VE``), text insertions (including the :ref:`TextWriter` class) and\"\n\" drawings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1820 298b682a9c8e4b17b5d9c2763ce13305\nmsgid \"\"\n\"**Fixed** issue `#727 <https://github.com/pymupdf/PyMuPDF/issues/727>`_. \"\n\"Freetext annotations now support an uncolored rectangle when \"\n\"``fill_color=None``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1821 2e4c66207d0441dd87fc8dee4d8db80f\nmsgid \"\"\n\"**Fixed** issue `#726 <https://github.com/pymupdf/PyMuPDF/issues/726>`_. \"\n\"UTF-8 encoding errors are now handled for HTML / XML :meth:`Page.getText`\"\n\" output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1822 e3ea52520ca74100aa5db3c1a47bcb22\nmsgid \"\"\n\"**Fixed** issue `#724 <https://github.com/pymupdf/PyMuPDF/issues/724>`_. \"\n\"Empty values are no longer stored in the PDF /Info metadata dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1823 a76c87f209e9404ea2a27260f984c079\nmsgid \"\"\n\"**Added** new methods :meth:`Document.set_oc` and :meth:`Document.get_oc`\"\n\" to set or get optional content references for **existing** image and \"\n\"form XObjects. These methods are similar to the same-named methods of \"\n\":ref:`Annot`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1824 6ae1cf58b5734e2db334370bae53194f\nmsgid \"\"\n\"**Added** :meth:`Document.set_ocmd`, :meth:`Document.get_ocmd` for \"\n\"handling OCMDs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1825 02c47a051f444e57a07a5c2cc00d8ece\nmsgid \"**Added** **Optional Content** support for text insertion and drawing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1826 033f5fd3092446d89a8b4be25eaf8fa5\nmsgid \"\"\n\"**Added** new method :meth:`Page.deleteWidget`, which deletes a form \"\n\"field from a page. This is analogous to deleting annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1827 f3f7aabfa367473eb2a71dd0d3b0c8ef\nmsgid \"\"\n\"**Added** support for Popup annotations. This includes defining the Popup\"\n\" rectangle and setting the Popup to open or closed. Methods / attributes \"\n\":meth:`Annot.set_popup`, :meth:`Annot.set_open`, :attr:`Annot.has_popup`,\"\n\" :attr:`Annot.is_open`, :attr:`Annot.popup_rect`, \"\n\":attr:`Annot.popup_xref`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1831 fff305ae1bfa4fa7a3b33de7de989103\nmsgid \"\"\n\"The **naming of methods and attributes** in PyMuPDF is far from being \"\n\"satisfactory: we have *CamelCases*, *mixedCases* and \"\n\"*lower_case_with_underscores* all over the place. With the :ref:`Annot` \"\n\"as the first candidate, we have started an activity to clean this up step\"\n\" by step, converting to lower case with underscores for methods and \"\n\"attributes while keeping UPPERCASE for the constants.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1833 5a5df8a85edd445a9168a3050257beb0\nmsgid \"\"\n\"Old names will remain available to prevent code breaks, but they will no \"\n\"longer be mentioned in the documentation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1834 d9dd3ce555be40288946b5c7b8684d7d\nmsgid \"\"\n\"New methods and attributes of all classes will be named according to the \"\n\"new standard.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1838 8d1aa669d43242329cb1e644baaea966\nmsgid \"**Changes in Version 1.18.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1840 0cc7942ae4f54d4698a56df9bcfc4df1\nmsgid \"\"\n\"As a major new feature, this version introduces support for PDF's \"\n\"**Optional Content** concept.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1842 eba5a3b05af340fd8d30d56d8053156a\nmsgid \"**Fixed** issue `#714 <https://github.com/pymupdf/PyMuPDF/issues/714>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1843 e0d1304eda394d6a88565ba84484d6fe\nmsgid \"**Fixed** issue `#711 <https://github.com/pymupdf/PyMuPDF/issues/711>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1844 bc199ec49e1945f1947218cd0c858828\nmsgid \"\"\n\"**Fixed** issue `#707 <https://github.com/pymupdf/PyMuPDF/issues/707>`_: \"\n\"if a PDF user password, but no owner password is supplied nor present, \"\n\"then the user password is also used as the owner password.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1845 1e99eff725e24f2f91fffda242611187\nmsgid \"\"\n\"**Fixed** ``expand`` and ``deflate`` parameters of methods \"\n\":meth:`Document.save` and :meth:`Document.write`. Individual image and \"\n\"font compression should now finally work. Addresses issue `#713 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/713>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1846 c7dbcce5af3f4805bc0bff4a3aa999c8\nmsgid \"\"\n\"**Added** a support of PDF optional content. This includes several new \"\n\":ref:`Document` methods for inquiring and setting optional content status\"\n\" and adding optional content configurations and groups. In addition, \"\n\"images, form XObjects and annotations now can be bound to optional \"\n\"content specifications. **Resolved** issue `#709 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/709>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1852 7005feac30d44416a7ae56c3c62aa421\nmsgid \"**Changes in Version 1.18.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1854 2557dd6711e74c5687da189106d7b072\nmsgid \"\"\n\"This version contains some interesting improvements for text searching: \"\n\"any number of search hits is now returned and the **hit_max** parameter \"\n\"was removed. The new **clip** parameter in addition allows to restrict \"\n\"the search area. Searching now detects hyphenations at line breaks and \"\n\"accordingly finds hyphenated words.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1856 f5a9d7fa7c5b434388c99b444417932e\nmsgid \"\"\n\"**Fixed** issue `#575 <https://github.com/pymupdf/PyMuPDF/issues/575>`_: \"\n\"if using ``quads=False`` in text searching, then overlapping rectangles \"\n\"on the same line are joined. Previously, parts of the search string, \"\n\"which belonged to different \\\"marked content\\\" items, each generated \"\n\"their own rectangle -- just as if occurring on separate lines.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1857 fa0f315fcdbb4aa7a85ebd875b0542b2\nmsgid \"\"\n\"**Added** :attr:`Document.isRepaired`, which is true if the PDF was \"\n\"repaired on open.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1858 29939ef23137444db25656ddb5c2a50b\nmsgid \"\"\n\"**Added** :meth:`Document.setXmlMetadata` which either updates or creates\"\n\" PDF XML metadata. Implements issue `#691 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/691>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1859 be99f9d509a84865a76d789e59d88508\nmsgid \"**Added** :meth:`Document.getXmlMetadata` returns PDF XML metadata.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1860 b5792e748a424e2f81526972850dbdf9\nmsgid \"\"\n\"**Changed** creation of PDF documents: they will now always carry a PDF \"\n\"identification (``/ID`` field) in the document trailer. Implements issue \"\n\"`#691 <https://github.com/pymupdf/PyMuPDF/issues/691>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1861 66eda59a33aa45ee88d7c201c85dfd3a\nmsgid \"\"\n\"**Changed** :meth:`Page.searchFor`: a new parameter ``clip`` is accepted \"\n\"to restrict the search to this rectangle. Correspondingly, the attribute \"\n\":attr:`TextPage.rect` is now respected by :meth:`TextPage.search`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1862 40efc3861a01468ba0b65c1950845cde\nmsgid \"\"\n\"**Changed** parameter ``hit_max`` in :meth:`Page.searchFor` and \"\n\":meth:`TextPage.search` is now obsolete: methods will return all hits.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1863 52c4e18a02684b35894a335001e4b449\nmsgid \"\"\n\"**Changed** character **selection criteria** in :meth:`Page.getText`: a \"\n\"character is now considered to be part of a ``clip`` if its bbox is fully\"\n\" contained. Before this, a non-empty intersection was sufficient.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1864 b05dff665c9644849dfb39e3b881dc36\nmsgid \"\"\n\"**Changed** :meth:`Document.scrub` to support a new option \"\n\"`redact_images`. This addresses issue `#697 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/697>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1869 dcb97ced9507410d944ce850f20740d7\nmsgid \"**Changes in Version 1.18.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1871 ba246f3cc40a4c189c06444a474f03c8\nmsgid \"\"\n\"**Fixed** issue `#692 <https://github.com/pymupdf/PyMuPDF/issues/692>`_. \"\n\"PyMuPDF now detects and recovers from more cyclic resource dependencies \"\n\"in PDF pages and for the first time reports them in the MuPDF warnings \"\n\"store.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1872 5ea166e77dfd422487491dc7989ac87b\nmsgid \"**Fixed** issue `#686 <https://github.com/pymupdf/PyMuPDF/issues/686>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1873 24c8bae3003740b3b7ef2f1245674d54\nmsgid \"\"\n\"**Added** opacity options for the :ref:`Shape` class: Stroke and fill \"\n\"colors can now be set to some transparency value. This means that all \"\n\":ref:`Page` draw methods, methods :meth:`Page.insertText`, \"\n\":meth:`Page.insertTextbox`, :meth:`Shape.finish`, \"\n\":meth:`Shape.insertText`, and :meth:`Shape.insertTextbox` support two new\"\n\" parameters: *stroke_opacity* and *fill_opacity*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1874 0eab763d4bde434c99750d05c7744be8\nmsgid \"\"\n\"**Added** new parameter ``mask`` to :meth:`Page.insertImage` for \"\n\"optionally providing an external image mask. Resolves issue `#685 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/685>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1875 d7eb84e2b45346e9805c75ed708951db\nmsgid \"\"\n\"**Added** :meth:`Annot.soundGet` for extracting the sound of an audio \"\n\"annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1879 8a1eef562c944225a15aca32aa0a68d0\nmsgid \"**Changes in Version 1.18.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1881 f828b2f6db734312b557796ab1a48396\nmsgid \"\"\n\"This is the first PyMuPDF version supporting MuPDF v1.18. The focus here \"\n\"is on extending PyMuPDF's own functionality -- apart from bug fixing. \"\n\"Subsequent PyMuPDF patches may address features new in MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1883 a9a5a178f719434b9bd31e65ea52f799\nmsgid \"\"\n\"**Fixed** issue `#519 <https://github.com/pymupdf/PyMuPDF/issues/519>`_. \"\n\"This upstream bug occurred occasionally for some pages only and seems to \"\n\"be fixed now: page layout should no longer be ruined in these cases.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1885 532d4ce5429a41979de31fd798876926\nmsgid \"**Fixed** issue `#675 <https://github.com/pymupdf/PyMuPDF/issues/675>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1887 4afda8086e88434b991c90a40f6b3c63\nmsgid \"\"\n\"Unsuccessful storage allocations should now always lead to exceptions \"\n\"(circumvention of an upstream bug intermittently crashing the \"\n\"interpreter).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1888 9b95a7d89275404592c843e6e1a69d20\nmsgid \"\"\n\":ref:`Pixmap` size is now based on ``size_t`` instead of ``int`` in C and\"\n\" should be correct even for extremely large pixmaps.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1890 50d1e348ab4a420e82ff6163e457c791\nmsgid \"\"\n\"**Fixed** issue `#668 <https://github.com/pymupdf/PyMuPDF/issues/668>`_. \"\n\"Specification of dashes for PDF drawing insertion should now correctly \"\n\"reflect the PDF spec.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1891 e2c585c3927446b58b695299aacefa37\nmsgid \"\"\n\"**Fixed** issue `#669 <https://github.com/pymupdf/PyMuPDF/issues/669>`_. \"\n\"A major source of memory leakage in :meth:`Page.insert_pdf` has been \"\n\"removed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1892 21f99d039e0b406ba748fa27b51b61ab\nmsgid \"\"\n\"**Added** keyword *\\\"images\\\"* to :meth:`Page.apply_redactions` for fine-\"\n\"controlling the handling of images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1893 06f2d99671fb4a4693ac550bbe174f39\nmsgid \"\"\n\"**Added** :meth:`Annot.getText` and :meth:`Annot.getTextbox`, which offer\"\n\" the same functionality as the :ref:`Page` versions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1894 cc38d6a9295a4baabbe0fa91a8729818\nmsgid \"\"\n\"**Added** key *\\\"number\\\"* to the block dictionaries of \"\n\":meth:`Page.getText` / :meth:`Annot.getText` for options \\\"dict\\\" and \"\n\"\\\"rawdict\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1895 95b81b00ad5f4f67abab2d83e62fa830\nmsgid \"\"\n\"**Added** :meth:`glyph_name_to_unicode` and \"\n\":meth:`unicode_to_glyph_name`. Both functions do not really connect to a \"\n\"specific font and are now independently available, too. The data are now \"\n\"based on the `Adobe Glyph List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1896 3435f8b2d002434ea2961e3bfa9e9ef5\nmsgid \"\"\n\"**Added** convenience functions :meth:`adobe_glyph_names` and \"\n\":meth:`adobe_glyph_unicodes` which return the respective available data.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1897 46734bcd601a4c10b224d8af13288ece\nmsgid \"\"\n\"**Added** :meth:`Page.getDrawings` which returns details of drawing \"\n\"operations on a document page. Works for all document types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1898 0a520f7de35d43a992a69aaff5c5b428\nmsgid \"\"\n\"Improved performance of :meth:`Document.insert_pdf`. Multiple object \"\n\"copies are now also suppressed across multiple separate insertions from \"\n\"the same source. This saves time, memory and target file size. Previously\"\n\" this mechanism was only active within each single method execution. The \"\n\"feature can also be suppressed with the new method bool parameter \"\n\"*final=1*, which is the default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1899 61af4c935234421da5ee00ff3ad32977\nmsgid \"\"\n\"For PNG images created from pixmaps, the resolution (dpi) is now \"\n\"automatically set from the respective :attr:`Pixmap.xres` and \"\n\":attr:`Pixmap.yres` values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1904 5787bf266f7743eba6c3ad62840101c8\nmsgid \"**Changes in Version 1.17.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1906 fe5734ffddc1440683824cf9eaeb5f6e\nmsgid \"\"\n\"**Fixed** issue `#651 <https://github.com/pymupdf/PyMuPDF/issues/651>`_. \"\n\"An upstream bug causing interpreter crashes in corner case redaction \"\n\"processings was fixed by backporting MuPDF changes from their development\"\n\" repo.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1907 ebc978213c4446bba6ca783ac6fc99e5\nmsgid \"\"\n\"**Fixed** issue `#645 <https://github.com/pymupdf/PyMuPDF/issues/645>`_. \"\n\"Pixmap top-left coordinates can be set (again) by their own method, \"\n\":meth:`Pixmap.set_origin`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1908 28e1c70a439943fb93756b8877d3f067\nmsgid \"\"\n\"**Fixed** issue `#622 <https://github.com/pymupdf/PyMuPDF/issues/622>`_. \"\n\":meth:`Page.insertImage` again accepts a :data:`rect_like` parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1909 878ea74492ff47559c0f731484ecd4c7\nmsgid \"\"\n\"**Added** several new methods to improve and speed-up table of contents \"\n\"(TOC) handling. Among other things, TOC items can now changed or deleted \"\n\"individually -- without always replacing the complete TOC. Furthermore, \"\n\"access to some PDF page attributes is now possible without first \"\n\"**loading** the page. This has a very significant impact on the \"\n\"performance of TOC manipulation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1910 4808333e353f4b9d9eb4c65d42a50c6d\nmsgid \"\"\n\"**Added** an option to :meth:`Document.insert_pdf` which allows \"\n\"displaying progress messages. Addresses `#640 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/640>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1911 16de294b58a64f549ba7bd27e208d30b\nmsgid \"\"\n\"**Added** :meth:`Page.getTextbox` which extracts text contained in a \"\n\"rectangle. In many cases, this should obsolete writing your own script \"\n\"for this type of thing.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1912 9711b2846e2c49f3bb6c283d0b1d9d67\nmsgid \"\"\n\"**Added** new ``clip`` parameter to :meth:`Page.getText` to simplify and \"\n\"speed up text extraction of page sub areas.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1913 8376ab0f05934f11b21f7fe154f09584\nmsgid \"\"\n\"**Added** :meth:`TextWriter.appendv` to add text in **vertical write \"\n\"mode**. Addresses issue `#653 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/653>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1918 bd8548ec9f5e41a8ad54094881be2323\nmsgid \"**Changes in Version 1.17.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1920 d2312ab353dc4344a3ef174e63c10207\nmsgid \"**Fixed** issue `#605 <https://github.com/pymupdf/PyMuPDF/issues/605>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1921 d52cabcacf8e4c7b8f280b8bb95e5d14\nmsgid \"\"\n\"**Fixed** issue `#600 <https://github.com/pymupdf/PyMuPDF/issues/600>`_ \"\n\"-- text should now be correctly positioned also for pages with a CropBox \"\n\"smaller than MediaBox.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1922 84afef0f9451476d83841dc61e1ae4d6\nmsgid \"\"\n\"**Added** text span dictionary key ``origin`` which contains the lower \"\n\"left coordinate of the first character in that span.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1923 c2104decab38443f85a9f4afbcf59e5f\nmsgid \"**Added** attribute :attr:`Font.buffer`, a *bytes* copy of the font file.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1924 3b8f869df37e4187b691a5636fabbcc4\nmsgid \"\"\n\"**Added** parameter *sanitize* to :meth:`Page.cleanContents`. Allows \"\n\"switching of sanitization, so only syntax cleaning will be done.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1928 79b5769975fc461580fc75e187439f1a\nmsgid \"**Changes in Version 1.17.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1930 c3dee94cf9eb4f8c9c29a712da46feee\nmsgid \"\"\n\"**Fixed** issue `#561 <https://github.com/pymupdf/PyMuPDF/issues/561>`_ \"\n\"-- second go: certain :ref:`TextWriter` usages with many alternating \"\n\"fonts did not work correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1931 b1cd45be4c3e414b9a31943b87ffa257\nmsgid \"**Fixed** issue `#566 <https://github.com/pymupdf/PyMuPDF/issues/566>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1932 c4be58f459d54570a15caabfa48b2fea\nmsgid \"**Fixed** issue `#568 <https://github.com/pymupdf/PyMuPDF/issues/568>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1933 a3a69f69f7e446d190a422fd95946055\nmsgid \"\"\n\"**Fixed** -- opacity is now correctly taken from the :ref:`TextWriter` \"\n\"object, if not given in :meth:`TextWriter.writeText`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1934 60e36a0e76204fc39ca63f66c0e017f0\nmsgid \"\"\n\"**Added** a new global attribute :attr:`fitz_fontdescriptors`. Contains \"\n\"information about usable fonts from repository `pymupdf-fonts \"\n\"<https://github.com/pymupdf/pymupdf-fonts>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1935 c5bbfe6d1dfc44bea3cf4c3d67f6d27d\nmsgid \"\"\n\"**Added** :meth:`Font.valid_codepoints` which returns an array of unicode\"\n\" codepoints for which the font has a glyph.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1936 d2abd73772384a31a507c1e1d6f4988b\nmsgid \"\"\n\"**Added** option ``text_as_path`` to :meth:`Page.getSVGimage`. this \"\n\"implements `#580 <https://github.com/pymupdf/PyMuPDF/issues/580>`_. \"\n\"Generates much smaller SVG files with parseable text if set to *False*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1941 0214e36149a247f698e38dfd899ff4fb\nmsgid \"**Changes in Version 1.17.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1943 e333e2461114401ea23d111aa11cbe48\nmsgid \"\"\n\"**Fixed** issue `#561 <https://github.com/pymupdf/PyMuPDF/issues/561>`_. \"\n\"Handling of more than 10 :ref:`Font` objects on one page should now work \"\n\"correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1944 3dc7e6c23bdb4fa2af06fa690d6c50e1\nmsgid \"\"\n\"**Fixed** issue `#562 <https://github.com/pymupdf/PyMuPDF/issues/562>`_. \"\n\"Annotation pixmaps are no longer derived from the page pixmap, thus \"\n\"avoiding unintended inclusion of page content.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1945 598609fee1c2419f8f22dd734d9e4621\nmsgid \"\"\n\"**Fixed** issue `#559 <https://github.com/pymupdf/PyMuPDF/issues/559>`_. \"\n\"This **MuPDF** bug is being temporarily fixed with a pre-version of \"\n\"MuPDF's next release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1946 2b01a159631746d0b9e27d2f4ee7f2f3\nmsgid \"\"\n\"**Added** utility function :meth:`repair_mono_font` for correcting \"\n\"displayed character spacing for some mono-spaced fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1947 d63409b0745449c5b326f78fcbdb243d\nmsgid \"\"\n\"**Added** utility method :meth:`Document.need_appearances` for fine-\"\n\"controlling Form PDF behavior. Addresses issue `#563 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/563>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1948 261813b8c1164f85bd099615986583b1\nmsgid \"\"\n\"**Added** utility function :meth:`sRGB_to_pdf` to recover the PDF color \"\n\"triple for a given color integer in sRGB format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1949 087525d5979d4e88b699951008f083cd\nmsgid \"\"\n\"**Added** utility function :meth:`sRGB_to_rgb` to recover the (R, G, B) \"\n\"color triple for a given color integer in sRGB format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1950 dfce06d94de945d298f54486d626b557\nmsgid \"\"\n\"**Added** utility function :meth:`make_table` which delivers table cells \"\n\"for a given rectangle and desired numbers of columns and rows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1951 a5085ba0096648a5abdb1bac873f8a91\nmsgid \"\"\n\"**Added** support for optional fonts in repository `pymupdf-fonts \"\n\"<https://github.com/pymupdf/pymupdf-fonts>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1955 6035ab0f4f8f4c22b602c2975ca7a9bb\nmsgid \"**Changes in Version 1.17.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1957 dd9eec4fdfa74a648a0ddfffafa83372\nmsgid \"\"\n\"**Fixed** an undocumented issue, which prevented fully cleaning a PDF \"\n\"page when using :meth:`Page.cleanContents`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1958 0847e901e54e42ab97132b411ad8703a\nmsgid \"\"\n\"**Fixed** issue `#540 <https://github.com/pymupdf/PyMuPDF/issues/540>`_. \"\n\"Text extraction for EPUB should again work correctly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1959 14b815222173483085dcc120dceb9f9b\nmsgid \"\"\n\"**Fixed** issue `#548 <https://github.com/pymupdf/PyMuPDF/issues/548>`_. \"\n\"Documentation now includes ``LINK_NAMED``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1960 f5eb1a9ec46e48479fef6e71d0ce3f21\nmsgid \"\"\n\"**Added** new parameter to control start of text in \"\n\":meth:`TextWriter.fillTextbox`. Implements `#549 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/549>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1961 67cf556f751344f683f697a61d518948\nmsgid \"\"\n\"**Changed** documentation of :meth:`Page.add_redact_annot` to explain the\"\n\" usage of non-builtin fonts.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1965 cc0c58ad8b0b41eda4f8e5716f2b16a8\nmsgid \"**Changes in Version 1.17.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1967 c27ffc8eec8040018fa36d5790749cec\nmsgid \"**Fixed** issue `#533 <https://github.com/pymupdf/PyMuPDF/issues/533>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1968 27350a32fc7840bb8591f6081f20d94d\nmsgid \"\"\n\"**Added** options to modify 'Redact' annotation appearance. Implements \"\n\"`#535 <https://github.com/pymupdf/PyMuPDF/issues/535>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1973 b8bea379222d4215963ee2eb2ffa9049\nmsgid \"**Changes in Version 1.17.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1975 60814804b9f84f3d8b98c3cf2dc5f20c\nmsgid \"**Fixed** issue `#520 <https://github.com/pymupdf/PyMuPDF/issues/520>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1976 9c3b1af133ad4aa9a4f08296f7affa70\nmsgid \"\"\n\"**Fixed** issue `#525 <https://github.com/pymupdf/PyMuPDF/issues/525>`_. \"\n\"Vertices for 'Ink' annots should now be correct.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1977 98b1d51b954b4c56bebe479ae1c44fdb\nmsgid \"\"\n\"**Fixed** issue `#524 <https://github.com/pymupdf/PyMuPDF/issues/524>`_. \"\n\"It is now possible to query and set rotation for applicable annotation \"\n\"types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1979 465b318c922644768dbf6d5a01328404\nmsgid \"\"\n\"Also significantly improved inline documentation for better support of \"\n\"interactive help.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1983 5cd63263f85a4783a6ccfc029201386b\nmsgid \"**Changes in Version 1.17.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1985 b87f5b93bd9b48eeb6c65b06340048e4\nmsgid \"\"\n\"This version is based on MuPDF v1.17. Following are highlights of new and\"\n\" changed features:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1987 b2f1ba6ba94140b98e5cc0fe7a3faa3b\nmsgid \"\"\n\"**Added** extended language support for annotations and widgets: a \"\n\"mixture of Latin, Greece, Russian, Chinese, Japanese and Korean \"\n\"characters can now be used in 'FreeText' annotations and text widgets. No\"\n\" special arrangement is required to use it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1989 e733e136ba8c438db34aca4bb17fc4ef\nmsgid \"\"\n\"Faster page access is implemented for documents supporting a \\\"chapter\\\" \"\n\"structure. This applies to EPUB documents currently. This comes with \"\n\"several new :ref:`Document` methods and changes for \"\n\":meth:`Document.loadPage` and the \\\"indexed\\\" page access *doc[n]*: In \"\n\"addition to specifying a page number as before, a tuple *(chapter, pno)* \"\n\"can be specified to identify the desired page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1991 971b877040f248cdba6abf69baeef371\nmsgid \"\"\n\"**Changed:** Improved support of redaction annotations: images overlapped\"\n\" by redactions are **permanently modified** by erasing the overlap areas.\"\n\" Also links are removed if overlapped by redactions. This is now fully in\"\n\" sync with PDF specifications.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1995 b49d2e2fb4e447e1b521a7c628189360\nmsgid \"\"\n\"**Changed** :meth:`TextWriter.writeText` to support the *\\\"morph\\\"* \"\n\"parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1996 3fc9ed296a4f4010832533bc9a26128c\nmsgid \"\"\n\"**Added** methods :meth:`Rect.morph`, :meth:`IRect.morph`, and \"\n\":meth:`Quad.morph`, which return a new :ref:`Quad`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1997 b20b08f09a414edaacd286b8f526b6f8\nmsgid \"\"\n\"**Changed** :meth:`Page.add_freetext_annot` to support text alignment via\"\n\" a new *\\\"align\\\"* parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1998 2361ff8be9cc46e1b8f08ddefa02efae\nmsgid \"\"\n\"**Fixed** issue `#508 <https://github.com/pymupdf/PyMuPDF/issues/508>`_. \"\n\"Improved image rectangle calculation to hopefully deliver correct values \"\n\"in most if not all cases.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:1999 236cc95410f34fcc89f66e66388bfb9b\nmsgid \"**Fixed** issue `#502 <https://github.com/pymupdf/PyMuPDF/issues/502>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2000 b1667139e4fd40a187d32b0c93485b50\nmsgid \"\"\n\"**Fixed** issue `#500 <https://github.com/pymupdf/PyMuPDF/issues/500>`_. \"\n\":meth:`Document.convertToPDF` should no longer cause memory leaks.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2001 08f135a6cd9f48d68424126027bef590\nmsgid \"\"\n\"**Fixed** issue `#496 <https://github.com/pymupdf/PyMuPDF/issues/496>`_. \"\n\"Annotations and widgets / fields are now added or modified using the \"\n\"coordinates of the **unrotated page**. This behavior is now in sync with \"\n\"other methods modifying PDF pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2002 0129ba9864fa48e3b4ddbc7f32269fc2\nmsgid \"\"\n\"**Added** :attr:`Page.rotationMatrix` and :attr:`Page.derotationMatrix` \"\n\"to support coordinate transformations between the rotated and the \"\n\"original versions of a PDF page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2004 35a97c98b52e49278109e56b99107387\nmsgid \"Potential code breaking changes:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2006 1a3fbe2084e24a759582e9aa05cc4591\nmsgid \"\"\n\"The private method ``Page._getTransformation()`` has been removed. Use \"\n\"the public :attr:`Page.transformationMattrix` instead.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2011 f06ca5ab722a487f87a29410f2bb377a\nmsgid \"**Changes in Version 1.16.18**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2013 75fa0dcdb41144b680ec66bfd4a6bd1a\nmsgid \"\"\n\"This version introduces several new features around PDF text output. The \"\n\"motivation is to simplify this task, while at the same time offering \"\n\"extending features.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2015 13b1f23e60414710b4271079289007c0\nmsgid \"\"\n\"One major achievement is using MuPDF's capabilities to dynamically \"\n\"choosing fallback fonts whenever a character cannot be found in the \"\n\"current one. This seamlessly works for Base-14 fonts in combination with \"\n\"CJK fonts (China, Japan, Korea). So a text may contain **any combination \"\n\"of characters** from the Latin, Greek, Russian, Chinese, Japanese and \"\n\"Korean languages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2017 6ffef279ab3d445ca46586a05c3e8d90\nmsgid \"\"\n\"**Fixed** issue `#493 <https://github.com/pymupdf/PyMuPDF/issues/493>`_. \"\n\"``Pixmap(doc, xref)`` should now again correctly resemble the loaded \"\n\"image object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2018 afdb0475290145d38834c612bbb45088\nmsgid \"\"\n\"**Fixed** issue `#488 <https://github.com/pymupdf/PyMuPDF/issues/488>`_. \"\n\"Widget names are now modifiable.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2019 141ce60e1fc44924a6cbdea1662c8a7d\nmsgid \"**Added** new class :ref:`Font` which represents a font.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2020 819be8edbaf04a2ebe870b12436fdad6\nmsgid \"\"\n\"**Added** new class :ref:`TextWriter` which serves as a container for \"\n\"text to be written on a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2021 be45ac51b3d7415e8150584132c49a33\nmsgid \"\"\n\"**Added** :meth:`Page.writeText` to write one or more :ref:`TextWriter` \"\n\"objects to the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2026 c355f22137584b4cbab6f6354bd95bda\nmsgid \"**Changes in Version 1.16.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2029 f3f07b3f33cc44c5984500283eb306e1\nmsgid \"\"\n\"**Fixed** issue `#479 <https://github.com/pymupdf/PyMuPDF/issues/479>`_. \"\n\"PyMuPDF should now more correctly report image resolutions. This applies \"\n\"to both, images (either from images files or extracted from PDF \"\n\"documents) and pixmaps created from images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2030 96daad3b07ac4308a44d307f62c89c50\nmsgid \"\"\n\"**Added** :meth:`Pixmap.set_dpi` which sets the image resolution in x and\"\n\" y directions.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2034 33fc9fed734a4bf4990dd592129e984c\nmsgid \"**Changes in Version 1.16.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2037 765ca3ee977d42678126cf84057b4e3d\nmsgid \"**Fixed** issue `#477 <https://github.com/pymupdf/PyMuPDF/issues/477>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2038 6240d3c9c41c46be9652ecabcbae2fbb\nmsgid \"**Fixed** issue `#476 <https://github.com/pymupdf/PyMuPDF/issues/476>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2039 d5cd872ddead486aa29ca5b255ba885e\nmsgid \"\"\n\"**Changed** annotation line end symbol coloring and fixed an error \"\n\"coloring the interior of 'Polyline' /'Polygon' annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2043 bb450a98e5e04667aed64c1004529927\nmsgid \"**Changes in Version 1.16.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2046 3228fbb9e5b4467498da27f2ad55fe5b\nmsgid \"\"\n\"**Changed** text marker annotations to accept parameters beyond just \"\n\"quadrilaterals such that now **text lines between two given points can be\"\n\" marked**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2048 a97e5cc2834a4e96b0ede1ad6db5c900\nmsgid \"\"\n\"**Added** :meth:`Document.scrub` which **removes potentially sensitive \"\n\"data** from a PDF. Implements `#453 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/453>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2050 2f3c7cef276444c480a491776e3ef6e8\nmsgid \"\"\n\"**Added** :meth:`Annot.blendMode` which returns the **blend mode** of \"\n\"annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2052 866e4a88a77d48a1b7aafb511b41907c\nmsgid \"\"\n\"**Added** :meth:`Annot.setBlendMode` to set the annotation's blend mode. \"\n\"This resolves issue `#416 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/416>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2053 501eb9ee56e84e60be74f5ba75eaecb4\nmsgid \"\"\n\"**Changed** :meth:`Annot.update` to accept additional parameters for \"\n\"setting blend mode and opacity.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2054 85b91d3af2b944e09ffc418872e3540e\nmsgid \"\"\n\"**Added** advanced graphics features to **control the anti-aliasing \"\n\"values**, :meth:`Tools.set_aa_level`. Resolves `#467 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/467>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2056 60b4c208b1c04edc9d0cc75db8e9b3ab\nmsgid \"**Fixed** issue `#474 <https://github.com/pymupdf/PyMuPDF/issues/474>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2057 4f4fa5bbd4bb45dc965381d06a2c28e1\nmsgid \"**Fixed** issue `#466 <https://github.com/pymupdf/PyMuPDF/issues/466>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2063 c2150d5e98ed4b29a8d7d0e0e049893a\nmsgid \"**Changes in Version 1.16.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2066 6ffa2c895b184d7c9579c04c5e72d6cc\nmsgid \"\"\n\"**Added** :meth:`Document.getPageXObjectList` which returns a list of \"\n\"**Form XObjects** of the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2067 1ad5db1dcf4e406d84fe85e8ac783a34\nmsgid \"\"\n\"**Added** :meth:`Page.setMediaBox` for changing the physical PDF page \"\n\"size.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2068 dc4ffb1b3bba4dd7a2c0b5018278954e\nmsgid \"\"\n\"**Added** :ref:`Page` methods which have been internal before: \"\n\":meth:`Page.cleanContents` (= :meth:`Page._cleanContents`), \"\n\":meth:`Page.getContents` (= :meth:`Page._getContents`), \"\n\":meth:`Page.getTransformation` (= :meth:`Page._getTransformation`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2074 0a926e1f6bb64ff4ab4b4fed8ea0ee89\nmsgid \"**Changes in Version 1.16.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2076 6f5ea75220774bb684dc3fe1dbf48e9b\nmsgid \"**Fixed** issue `#447 <https://github.com/pymupdf/PyMuPDF/issues/447>`_\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2077 71bac266ce3746019c6a08f26d3ec822\nmsgid \"**Fixed** issue `#461 <https://github.com/pymupdf/PyMuPDF/issues/461>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2078 373fc96ec8a54dee8c321088ee944682\nmsgid \"**Fixed** issue `#397 <https://github.com/pymupdf/PyMuPDF/issues/397>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2079 7cf9d00c4d19420abaaf8c58b10147a0\nmsgid \"**Fixed** issue `#463 <https://github.com/pymupdf/PyMuPDF/issues/463>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2080 fe57fdfdfd8d4dbab5eed84540ad2c09\nmsgid \"\"\n\"**Added** JavaScript support to PDF form fields, thereby fixing `#454 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/454>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2081 3eb09d62dd6044afa545088e6207f9f5\nmsgid \"\"\n\"**Added** a new annotation method :meth:`Annot.delete_responses`, which \"\n\"removes 'Popup' and response annotations referring to the current one. \"\n\"Mainly serves data protection purposes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2082 5c849834cfb14620809866c9ac0b1f25\nmsgid \"\"\n\"**Added** a new form field method :meth:`Widget.reset`, which resets the \"\n\"field value to its default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2083 1d43ac4e7dcf4344b0dfdcf700f6d7a5\nmsgid \"\"\n\"**Changed** and extended handling of redactions: images and XObjects are \"\n\"removed if *contained* in a redaction rectangle. Any partial only \"\n\"overlaps will just be covered by the redaction background color. Now an \"\n\"*overlay* text can be specified to be inserted in the rectangle area to \"\n\"**take the place the deleted original** text. This resolves `#434 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/434>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2087 d41286ba5ebd44c280d5f43f2c164594\nmsgid \"**Changes in Version 1.16.11**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2089 74c14cc395804937832a051835d5fecb\nmsgid \"\"\n\"**Added** Support for redaction annotations via method \"\n\":meth:`Page.add_redact_annot` and :meth:`Page.apply_redactions`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2090 68b7efcedf5f4d94964ff855c1baaa83\nmsgid \"**Fixed** issue #426 (\\\"PolygonAnnotation in 1.16.10 version\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2091 247da6da5b67427fab1dc09bed47037f\nmsgid \"\"\n\"**Fixed** documentation only issues `#443 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/443>`_ and `#444 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/444>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2095 ed5a70ba54b5438786c6e36834b30a3d\nmsgid \"**Changes in Version 1.16.10**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2097 9147f50e16864bfe9fc59b9c324a45ca\nmsgid \"\"\n\"**Fixed** issue #421 (\\\"annot.set_rect(rect) has no effect on text \"\n\"Annotation\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2098 2a0e32d4811546f3a036844d15350182\nmsgid \"\"\n\"**Fixed** issue #417 (\\\"Strange behavior for page.deleteAnnot on 1.16.9 \"\n\"compare to 1.13.20\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2099 85979328a4bc4780a1adf5da1b2e3893\nmsgid \"**Fixed** issue #415 (\\\"Annot.setOpacity throws mupdf warnings\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2100 2419b5fdf6bd4e14bf9217b890caa587\nmsgid \"\"\n\"**Changed** all \\\"add annotation / widget\\\" methods to store a unique \"\n\"name in the */NM* PDF key.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2101 9d4a65a638864c41800994ff9674b45a\nmsgid \"\"\n\"**Changed** :meth:`Annot.setInfo` to also accept direct parameters in \"\n\"addition to a dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2102 d7c062a9ce2e4526a3f42e875262dd86\nmsgid \"\"\n\"**Changed** :attr:`Annot.info` to now also show the annotation's unique \"\n\"id (*/NM* PDF key) if present.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2103 e8cff5d5c3c8451381b2fbccf05c6ad9\nmsgid \"\"\n\"**Added** :meth:`Page.annot_names` which returns a list of all annotation\"\n\" names (*/NM* keys).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2104 9e3fa2fe09b54dc29528cfced4d8729f\nmsgid \"\"\n\"**Added** :meth:`Page.load_annot` which loads an annotation given its \"\n\"unique id (*/NM* key).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2105 f5d8b4dd62cf460a9126ea02f116c488\nmsgid \"\"\n\"**Added** :meth:`Document.reload_page` which provides a new copy of a \"\n\"page after finishing any pending updates to it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2110 072a5e68ce9a45629a888405caa5a5d2\nmsgid \"**Changes in Version 1.16.9**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2112 c18c92f84efa4cfa8b797880e17d8bcb\nmsgid \"\"\n\"**Fixed** #412 (\\\"Feature Request: Allow controlling whether TOC entries \"\n\"should be collapsed\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2113 f9a9a45513f74bfa9a4747231296426f\nmsgid \"**Fixed** #411 (\\\"Seg Fault with page.firstWidget\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2114 cbe0b8f39db641068257179e30232c1f\nmsgid \"**Fixed** #407 (\\\"Annot.setOpacity trouble\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2115 c4b9b8f9ef874c7f88678471ea871da9\nmsgid \"\"\n\"**Changed** methods :meth:`Annot.setBorder`, :meth:`Annot.setColors`, \"\n\":meth:`Link.setBorder`, and :meth:`Link.setColors` to also accept direct \"\n\"parameters, and not just cumbersome dictionaries.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2119 d0e24eb6d1f34da0aca34159c1e8309c\nmsgid \"**Changes in Version 1.16.8**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2121 78fe31bc2d304b78a7a2cec103ad3a86\nmsgid \"\"\n\"**Added** several new methods to the :ref:`Document` class, which make \"\n\"dealing with PDF low-level structures easier. I also decided to provide \"\n\"them as \\\"normal\\\" methods (as opposed to private ones starting with an \"\n\"underscore \\\"_\\\"). These are :meth:`Document.xrefObject`, \"\n\":meth:`Document.xrefStream`, :meth:`Document.xrefStreamRaw`, \"\n\":meth:`Document.PDFTrailer`, :meth:`Document.PDFCatalog`, \"\n\":meth:`Document.metadataXML`, :meth:`Document.updateObject`, \"\n\":meth:`Document.updateStream`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2122 f907ccb57c184be2857e9e13341bcf7f\nmsgid \"\"\n\"**Added** :meth:`Tools.mupdf_disply_errors` which sets the display of \"\n\"mupdf errors on *sys.stderr*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2123 462c8d75060e4a88a09ea596464f5368\nmsgid \"\"\n\"**Added** a commandline facility. This a major new feature: you can now \"\n\"invoke several utility functions via *\\\"python -m fitz ...\\\"*. It should \"\n\"obsolete the need for many of the most trivial scripts. Please refer to \"\n\":ref:`Module`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2128 4f1ac7ae88d343e886b0fc8edee75d46\nmsgid \"**Changes in Version 1.16.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2130 59ec1afd2e0b4cd3a5dc260bd354751e\nmsgid \"\"\n\"Minor changes to better synchronize the binary image streams of \"\n\":ref:`TextPage` image blocks and :meth:`Document.extractImage` images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2132 ac25ec6537ba4e92aab44dcf172c4ba8\nmsgid \"\"\n\"**Fixed** issue #394 (\\\"PyMuPDF Segfaults when using \"\n\"TOOLS.mupdf_warnings()\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2133 d9b7bf416f824ce09246787bdda98e63\nmsgid \"\"\n\"**Changed** redirection of MuPDF error messages: apart from writing them \"\n\"to Python *sys.stderr*, they are now also stored with the MuPDF warnings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2134 f40406dcc3f04e31b7a7a9805de02e42\nmsgid \"\"\n\"**Changed** :meth:`Tools.mupdf_warnings` to automatically empty the store\"\n\" (if not deactivated via a parameter).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2135 2299c535d3cb4aa6a186707196175500\nmsgid \"\"\n\"**Changed** :meth:`Page.getImageBbox` to return an **infinite rectangle**\"\n\" if the image could not be located on the page -- instead of raising an \"\n\"exception.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2140 bfbc4d7dee2442f3b0f015ea21421028\nmsgid \"**Changes in Version 1.16.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2142 c28c263feaa6419cb63d73ad8209d28d\nmsgid \"**Fixed** issue #390 (\\\"Incomplete deletion of annotations\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2143 c5219152f7854dc88d39a7689713a4a8\nmsgid \"\"\n\"**Changed** :meth:`Page.searchFor` / :meth:`Document.searchPageFor` to \"\n\"also support the *flags* parameter, which controls the data included in a\"\n\" :ref:`TextPage`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2144 21ea396db0a04f04ac4bf6146ab72b59\nmsgid \"\"\n\"**Changed** :meth:`Document.getPageImageList`, \"\n\":meth:`Document.getPageFontList` and their :ref:`Page` counterparts to \"\n\"support a new parameter *full*. If true, the returned items will contain \"\n\"the :data:`xref` of the *Form XObject* where the font or image is \"\n\"referenced.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2148 69f333b42ed44c918c9378c6632bd3e2\nmsgid \"**Changes in Version 1.16.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2150 9f2ab73d9d874b4784539e77ddee4f5b\nmsgid \"More performance improvements for text extraction.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2152 fb2a1a0548f3424b8d89927d5f5047ee\nmsgid \"**Fixed** second part of issue #381 (see item in v1.16.4).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2153 3f0ac5e4286c4997836ff33e123dbaf4\nmsgid \"\"\n\"**Added** :meth:`Page.getTextPage`, so it is no longer required to create\"\n\" an intermediate display list for text extractions. Page level wrappers \"\n\"for text extraction and text searching are now based on this, which \"\n\"should improve performance by ca. 5%.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2157 9e9865f910ed4d4399d4dfbe3c3d0597\nmsgid \"**Changes in Version 1.16.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2160 e7d84df2ad7448e1880d04a6a7858521\nmsgid \"\"\n\"**Fixed** issue #381 (\\\"TextPage.extractDICT ... failed ... after \"\n\"upgrading ... to 1.16.3\\\")\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2161 17ca6aae522d4d84a5b1c510ca445cc6\nmsgid \"\"\n\"**Added** method :meth:`Document.pages` which delivers a generator \"\n\"iterator over a page range.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2162 b2b7308c362b461bb878fcc1538a0c92\nmsgid \"\"\n\"**Added** method :meth:`Page.links` which delivers a generator iterator \"\n\"over the links of a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2163 765160822cdc4aa9b4b723db791c91b6\nmsgid \"\"\n\"**Added** method :meth:`Page.annots` which delivers a generator iterator \"\n\"over the annotations of a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2164 3eb7fc95d4214c22a621ccb900d1e490\nmsgid \"\"\n\"**Added** method :meth:`Page.widgets` which delivers a generator iterator\"\n\" over the form fields of a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2165 d91d637897d54651a998f7dc0d19dc08\nmsgid \"\"\n\"**Changed** :attr:`Document.is_form_pdf` to now contain the number of \"\n\"widgets, and *False* if not a PDF or this number is zero.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2170 c01be0ed23784665aa2ce10d9ee9e605\nmsgid \"**Changes in Version 1.16.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2172 112fd892e91d4394b0bbd52b9a508533\nmsgid \"\"\n\"Minor changes compared to version 1.16.2. The code of the \\\"dict\\\" and \"\n\"\\\"rawdict\\\" variants of :meth:`Page.getText` has been ported to C which \"\n\"has greatly improved their performance. This improvement is mostly \"\n\"noticeable with text-oriented documents, where they now should execute \"\n\"almost two times faster.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2174 529a6e2ef3a44e7496d36d3b262a6697\nmsgid \"\"\n\"**Fixed** issue #369 (\\\"mupdf: cmsCreateTransform failed\\\") by removing \"\n\"ICC colorspace support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2175 d2e2ed462d9a420181f57a3bf178f0c7\nmsgid \"\"\n\"**Changed** :meth:`Page.getText` to accept additional keywords \\\"blocks\\\"\"\n\" and \\\"words\\\". These will deliver the results of \"\n\":meth:`Page.getTextBlocks` and :meth:`Page.getTextWords`, respectively. \"\n\"So all text extraction methods are now available via a uniform API. \"\n\"Correspondingly, there are now new methods :meth:`TextPage.extractBLOCKS`\"\n\" and :meth:`TextPage.extractWords`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2176 1c333634e45449ce9b326aff470a6f28\nmsgid \"\"\n\"**Changed** :meth:`Page.getText` to default bit indicator \"\n\"*TEXT_INHIBIT_SPACES* to **off**. Insertion of additional spaces is **not\"\n\" suppressed** by default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2180 12e20189c1f143da88f1568d186c2402\nmsgid \"**Changes in Version 1.16.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2182 5b0a0190d48d45a79172681a52191e85\nmsgid \"\"\n\"**Changed** text extraction methods of :ref:`Page` to allow detail \"\n\"control of the amount of extracted data.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2183 26cc0a7bee624a97a6c6ee19ee703703\nmsgid \"\"\n\"**Added** :meth:`planish_line` which maps a given line (defined as a pair\"\n\" of points) to the x-axis.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2184 b3df1c1be11846f9993b323a07181579\nmsgid \"\"\n\"**Fixed** an issue (w/o Github number) which brought down the interpreter\"\n\" when encountering certain non-UTF-8 encodable characters while using \"\n\":meth:`Page.getText` with the \\\"dict\\\" option.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2185 e6ba0bd1a32e4b12891ded9326249a81\nmsgid \"**Fixed** issue #362 (\\\"Memory Leak with getText('rawDICT')\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2189 e9569fdba664447da20f33096718b92f\nmsgid \"**Changes in Version 1.16.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2191 dcc8cf6fc2384f3bb994e03b3a87c729\nmsgid \"\"\n\"**Added** property :attr:`Quad.is_convex` which checks whether a line is \"\n\"contained in the quad if it connects two points of it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2192 cc61e8f19f5e488b8316b4e8235659f5\nmsgid \"\"\n\"**Changed** :meth:`Document.insert_pdf` to now allow dropping or \"\n\"including links and annotations independently during the copy. Fixes \"\n\"issue #352 (\\\"Corrupt PDF data and ...\\\"), which seemed to intermittently\"\n\" occur when using the method for some problematic PDF files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2193 d407b04268d44237912c00860184f190\nmsgid \"\"\n\"**Fixed** a bug which, in matrix division using the syntax *\\\"m1/m2\\\"*, \"\n\"caused matrix *\\\"m1\\\"* to be **replaced** by the result instead of \"\n\"delivering a new matrix.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2194 7817d3234a47487b971b3830ef28ec19\nmsgid \"\"\n\"**Fixed** issue #354 (\\\"SyntaxWarning with Python 3.8\\\"). We now always \"\n\"use *\\\"==\\\"* for literals (instead of the *\\\"is\\\"* Python keyword).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2195 ec50e4c219bd4062ad4ed5c0dddaac86\nmsgid \"\"\n\"**Fixed** issue #353 (\\\"mupdf version check\\\"), to no longer refuse the \"\n\"import when there are only patch level deviations from MuPDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2201 97813723c7e74febb3697d506c0094da\nmsgid \"**Changes in Version 1.16.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2203 2c7908f042184d21a92a433a0dace8f2\nmsgid \"\"\n\"This major new version of MuPDF comes with several nice new or changed \"\n\"features. Some of them imply programming API changes, however. This is a \"\n\"synopsis of what has changed:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2205 a005bf6b6c26445f8a8e708efa7b1e6d\nmsgid \"\"\n\"PDF document encryption and decryption is now **fully supported**. This \"\n\"includes setting **permissions**, **passwords** (user and owner \"\n\"passwords) and the desired encryption method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2206 f64056f6bc3f4c5c9e5716fd5b547a3b\nmsgid \"\"\n\"In response to the new encryption features, PyMuPDF returns an integer \"\n\"(ie. a combination of bits) for document permissions, and no longer a \"\n\"dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2207 12c5b87d97b548be96df9490e4a9b1f8\nmsgid \"\"\n\"Redirection of MuPDF errors and warnings is now natively supported. \"\n\"PyMuPDF redirects error messages from MuPDF to *sys.stderr* and no longer\"\n\" buffers them. Warnings continue to be buffered and will not be \"\n\"displayed. Functions exist to access and reset the warnings buffer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2208 9ee23cc47bf54e33ac5b25ec8bd3a5b0\nmsgid \"Annotations are now **only supported for PDF**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2209 043f8a35721a45789fc958c22ae0db05\nmsgid \"\"\n\"Annotations and widgets (form fields) are now **separate object chains** \"\n\"on a page (although widgets technically still **are** PDF annotations). \"\n\"This means, that you will **never encounter widgets** when using \"\n\":attr:`Page.firstAnnot` or :meth:`Annot.next`. You must use \"\n\":attr:`Page.firstWidget` and :meth:`Widget.next` to access form fields.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2210 98ff046f99264c3aadf74240a8bc473d\nmsgid \"\"\n\"As part of MuPDF's changes regarding widgets, only the following four \"\n\"fonts are supported, when **adding** or **changing** form fields: \"\n\"**Courier, Helvetica, Times-Roman** and **ZapfDingBats**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2212 c153729a2d494ff0ae2def2ff637078a\nmsgid \"List of change details:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2214 b23f45be6d7741b295688a68df3dab61\nmsgid \"\"\n\"**Added** :meth:`Document.can_save_incrementally` which checks conditions\"\n\" that are preventing use of option *incremental=True* of \"\n\":meth:`Document.save`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2215 f4ec8c96484849b498b2ccf6668ed972\nmsgid \"\"\n\"**Added** :attr:`Page.firstWidget` which points to the first field on a \"\n\"page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2216 bcff0ac6bdc749b7b1bdca9295590789\nmsgid \"\"\n\"**Added** :meth:`Page.getImageBbox` which returns the rectangle occupied \"\n\"by an image shown on the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2217 027854d96da7483d84939b2e60db8b94\nmsgid \"\"\n\"**Added** :meth:`Annot.setName` which lets you change the (icon) name \"\n\"field.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2218 bcc01e342bb8486ca3ef80ba6e2007f8\nmsgid \"\"\n\"**Added** outputting the text color in :meth:`Page.getText`: the \"\n\"*\\\"dict\\\"*, *\\\"rawdict\\\"* and *\\\"xml\\\"* options now also show the color \"\n\"in sRGB format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2219 bc0cbfa3b0484956b6eaea0bdb98a8fc\nmsgid \"\"\n\"**Changed** :attr:`Document.permissions` to now contain an integer of \"\n\"bool indicators -- was a dictionary before.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2220 820b45730e5f4cd09d1a94837ecb4e08\nmsgid \"\"\n\"**Changed** :meth:`Document.save`, :meth:`Document.write`, which now \"\n\"fully support password-based decryption and encryption of PDF files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2221 4731ba6ffeda46a2a2d03259b480522f\nmsgid \"\"\n\"**Changed the names of all Python constants** related to annotations and \"\n\"widgets. Please make sure to consult the **Constants and Enumerations** \"\n\"chapter if your script is dealing with these two classes. This decision \"\n\"goes back to the dropped support for non-PDF annotations. The **old \"\n\"names** (starting with \\\"ANNOT_*\\\" or \\\"WIDGET_*\\\") will be available as \"\n\"deprecated synonyms.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2222 238de30d8f3c49d48c79ee5b21a0e5f6\nmsgid \"\"\n\"**Changed** font support for widgets: only *Cour* (Courier), *Helv* \"\n\"(Helvetica, default), *TiRo* (Times-Roman) and *ZaDb* (ZapfDingBats) are \"\n\"accepted when **adding or changing** form fields. Only the plain versions\"\n\" are possible -- not their italic or bold variations. **Reading** \"\n\"widgets, however will show its original font.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2223 e763e7235e744348bb116c13b8db7bfa\nmsgid \"\"\n\"**Changed** the name of the warnings buffer to \"\n\":meth:`Tools.mupdf_warnings` and the function to empty this buffer is now\"\n\" called :meth:`Tools.reset_mupdf_warnings`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2224 e51bbdba4a7f47c99ae6f3828cb8299d\nmsgid \"\"\n\"**Changed** :meth:`Page.getPixmap`, :meth:`Document.get_page_pixmap`: a \"\n\"new bool argument *annots* can now be used to **suppress the rendering of\"\n\" annotations** on the page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2225 caaa515792364bf3902f0f1c3f484995\nmsgid \"\"\n\"**Changed** :meth:`Page.add_file_annot` and :meth:`Page.add_text_annot` \"\n\"to enable setting an icon.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2226 0086e4a6b881460f8c71102f2729bc2d\nmsgid \"\"\n\"**Removed** widget-related methods and attributes from the :ref:`Annot` \"\n\"object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2227 f50931d062644b8f880b652ea90f83f5\nmsgid \"\"\n\"**Removed** :ref:`Document` attributes *openErrCode*, *openErrMsg*, and \"\n\":ref:`Tools` attributes / methods *stderr*, *reset_stderr*, *stdout*, and\"\n\" *reset_stdout*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2228 a67f4a89f4f64dd68267c94b2d73ce86\nmsgid \"\"\n\"**Removed** **thirdparty zlib** dependency in PyMuPDF: there are now \"\n\"compression functions available in MuPDF. Source installers of PyMuPDF \"\n\"may now omit this extra installation step.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2230 42c8303233d940a8bb202082575e9d67\nmsgid \"**No version published for MuPDF v1.15.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2235 0e262b2012e24e66bcbb16697b9750e3\nmsgid \"**Changes in Version 1.14.20 / 1.14.21**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2237 cf8c37c3fab846c3bfc824d30a64fe50\nmsgid \"\"\n\"**Changed** text marker annotations to support multiple rectangles / \"\n\"quadrilaterals. This fixes issue #341 (\\\"Question : How to addhighlight \"\n\"so that a string spread across more than a line is covered by one \"\n\"highlight?\\\") and similar (#285).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2238 cea5aecbd9e84d1aa23aa5d28149aa16\nmsgid \"\"\n\"**Fixed** issue #331 (\\\"Importing PyMuPDF changes warning filtering \"\n\"behaviour globally\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2243 97bdc13f89b8480bb31a7a26ed32a594\nmsgid \"**Changes in Version 1.14.19**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2245 6b2efadb462c476c86b64734cc2f0abe\nmsgid \"**Fixed** issue #319 (\\\"InsertText function error when use custom font\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2246 55649a3c6956439eb948ff4f5d16de35\nmsgid \"\"\n\"**Added** new method :meth:`Document.get_sigflags` which returns \"\n\"information on whether a PDF is signed. Resolves issue #326 (\\\"How to \"\n\"detect signature in a form pdf?\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2251 8b00c1d84be44f0e843dcc2f618a054f\nmsgid \"**Changes in Version 1.14.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2253 bf77aace3abb4d87a3a27f4fde38cdee\nmsgid \"\"\n\"**Added** :meth:`Document.fullcopyPage` to make full page copies within a\"\n\" PDF (not just copied references as :meth:`Document.copyPage` does).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2254 f5f13a70b41041ac94342d177b78283e\nmsgid \"\"\n\"**Changed** :meth:`Page.getPixmap`, :meth:`Document.get_page_pixmap` now \"\n\"use *alpha=False* as default.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2255 0b81e0a298f842cfae56289c691fc8af\nmsgid \"\"\n\"**Changed** text extraction: the span dictionary now (again) contains its\"\n\" rectangle under the *bbox* key.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2256 80171c31ff824cf5a8796464b7f185bd\nmsgid \"\"\n\"**Changed** :meth:`Document.movePage` and :meth:`Document.copyPage` to \"\n\"use direct functions instead of wrapping :meth:`Document.select` -- \"\n\"similar to :meth:`Document.delete_page` in v1.14.16.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2260 2102f0e54ede402daf1c78dac1d0ca26\nmsgid \"**Changes in Version 1.14.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2262 6703d3f0199a482cadb2d9a376aaa7c6\nmsgid \"\"\n\"**Changed** :ref:`Document` methods around PDF */EmbeddedFiles* to no \"\n\"longer use MuPDF's \\\"portfolio\\\" functions. That support will be dropped \"\n\"in MuPDF v1.15 -- therefore another solution was required.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2263 6447adac2fa6472d8d443e4326ffe0f4\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_Count` to be a function (was an \"\n\"attribute).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2264 0f5ec06d87f74cdc82a5f05fa5beae80\nmsgid \"\"\n\"**Added** new method :meth:`Document.embfile_Names` which returns a list \"\n\"of names of embedded files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2265 c99e5b42134b48d28118a34b7b00f400\nmsgid \"\"\n\"**Changed** :meth:`Document.delete_page` and \"\n\":meth:`Document.delete_pages` to internally no longer use \"\n\":meth:`Document.select`, but instead use functions to perform the \"\n\"deletion directly. As it has turned out, the :meth:`Document.select` \"\n\"method yields invalid outline trees (tables of content) for very complex \"\n\"PDFs and sophisticated use of annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2270 d47507f7f3114b71864f6f89dff1d8de\nmsgid \"**Changes in Version 1.14.15**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2272 685a47651ab74ab9baa02751bdfeea45\nmsgid \"\"\n\"**Fixed** issues #301 (\\\"Line cap and Line join\\\"), #300 (\\\"How to draw a\"\n\" shape without outlines\\\") and #298 (\\\"utils.updateRect exception\\\"). \"\n\"These bugs pertain to drawing shapes with PyMuPDF. Drawing shapes without\"\n\" any border is fully supported. Line cap styles and line line join style \"\n\"are now differentiated and support all possible PDF values (0, 1, 2) \"\n\"instead of just being a bool. The previous parameter *roundCap* is \"\n\"deprecated in favor of *lineCap* and *lineJoin* and will be deleted in \"\n\"the next release.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2273 69635ffd084f40da8a77aef036ecbc5b\nmsgid \"\"\n\"**Fixed** issue #290 (\\\"Memory Leak with getText('rawDICT')\\\"). This bug \"\n\"caused memory not being (completely) freed after invoking the \\\"dict\\\", \"\n\"\\\"rawdict\\\" and \\\"json\\\" versions of :meth:`Page.getText`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2278 347daa4b4d614a538c8264a0f7513365\nmsgid \"**Changes in Version 1.14.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2280 fd89b8ffed0e45b4becf36770405f0a5\nmsgid \"\"\n\"**Added** new low-level function :meth:`ImageProperties` to determine a \"\n\"number of characteristics for an image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2281 5b71c3a43a3d4b468a46d3704d1a5fed\nmsgid \"\"\n\"**Added** new low-level function :meth:`Document.is_stream`, which checks\"\n\" whether an object is of stream type.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2282 7704e37dc4954c43891ea6905e994602\nmsgid \"\"\n\"**Changed** low-level functions :meth:`Document._getXrefString` and \"\n\":meth:`Document._getTrailerString` now by default return object \"\n\"definitions in a formatted form which makes parsing easy.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2286 60c8b7ae348144f590caa8dd2b6475b4\nmsgid \"**Changes in Version 1.14.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2288 409b6e7270844e05986a6af2e04bf234\nmsgid \"\"\n\"**Changed** methods working with binary input: while ever supporting \"\n\"bytes and bytearray objects, they now also accept *io.BytesIO* input, \"\n\"using their *getvalue()* method. This pertains to document creation, \"\n\"embedded files, FileAttachment annotations, pixmap creation and others. \"\n\"Fixes issue #274 (\\\"Segfault when using BytesIO as a stream for \"\n\"insertImage\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2289 517a02e2889046a4bf151c5da878dec9\nmsgid \"\"\n\"**Fixed** issue #278 (\\\"Is insertImage(keep_proportion=True) broken?\\\"). \"\n\"Images are now correctly presented when keeping aspect ratio.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2294 d22de33a96de48479a5d908ec0ba6cd2\nmsgid \"**Changes in Version 1.14.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2296 8e8898b2f62f4ccfabbc4633afa8d524\nmsgid \"\"\n\"**Changed** the draw methods of :ref:`Page` and :ref:`Shape` to support \"\n\"not only RGB, but also GRAY and CMYK colorspaces. This solves issue #270 \"\n\"(\\\"Is there a way to use CMYK color to draw shapes?\\\"). This change also \"\n\"applies to text insertion methods of :ref:`Shape`, resp. :ref:`Page`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2297 12008f80180643aeb7c59cd9d81f7b17\nmsgid \"\"\n\"**Fixed** issue #269 (\\\"AttributeError in Document.insert_page()\\\"), \"\n\"which occurred when using :meth:`Document.insert_page` with text \"\n\"insertion.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2302 5926b5208b964e5bb1c6d9aa237e3b25\nmsgid \"**Changes in Version 1.14.11**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2304 7cd2f991658242e0a818633e00e32840\nmsgid \"\"\n\"**Changed** :meth:`Page.show_pdf_page` to always position the source \"\n\"rectangle centered in the target. This method now also supports \"\n\"**rotation by arbitrary angles**. The argument *reuse_xref* has been \"\n\"deprecated: prevention of duplicates is now **handled internally**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2305 92cb4e6a37f04f8fbe1fe50f20b4315e\nmsgid \"\"\n\"**Changed** :meth:`Page.insertImage` to support rotated display of the \"\n\"image and keeping the aspect ratio. Only rotations by multiples of 90 \"\n\"degrees are supported here.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2306 a3321e012bd14420978e83b39fe71692\nmsgid \"\"\n\"**Fixed** issue #265 (\\\"TypeError: insertText() got an unexpected keyword\"\n\" argument 'idx'\\\"). This issue only occurred when using \"\n\":meth:`Document.insert_page` with also inserting text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2310 ce94e552e8634de490994f5a58a88b5a\nmsgid \"**Changes in Version 1.14.10**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2312 91400574def7471c9bcf3e3b784293fa\nmsgid \"\"\n\"**Changed** :meth:`Page.show_pdf_page` to support rotation of the source \"\n\"rectangle. Fixes #261 (\\\"Cannot rotate inserted pages\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2313 373a473d44604ea0a33bee60a4608003\nmsgid \"\"\n\"**Fixed** a bug in :meth:`Page.insertImage` which prevented insertion of \"\n\"multiple images provided as streams.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2318 a745612de5d944648494f2f4fe5a7367\nmsgid \"**Changes in Version 1.14.9**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2320 786372a66f0346f5b2ebf49918ac01fc\nmsgid \"\"\n\"**Added** new low-level method :meth:`Document._getTrailerString`, which \"\n\"returns the trailer object of a PDF. This is much like \"\n\":meth:`Document._getXrefString` except that the PDF trailer has no / \"\n\"needs no :data:`xref` to identify it.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2321 166ee0276f23464790afa4aa78d3fb2b\nmsgid \"\"\n\"**Added** new parameters for text insertion methods. You can now set \"\n\"stroke and fill colors of glyphs (text characters) independently, as well\"\n\" as the thickness of the glyph border. A new parameter *render_mode* \"\n\"controls the use of these colors, and whether the text should be visible \"\n\"at all.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2322 ec5e00cd07f74051b60872c21459da65\nmsgid \"\"\n\"**Fixed** issue #258 (\\\"Copying image streams to new PDF without size \"\n\"increase\\\"): For JPX images embedded in a PDF, \"\n\":meth:`Document.extractImage` will now return them in their original \"\n\"format. Previously, the MuPDF base library was used, which returns them \"\n\"in PNG format (entailing a massive size increase).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2323 9c4df9a330534524ae96733260628fa2\nmsgid \"\"\n\"**Fixed** issue #259 (\\\"Morphing text to fit inside rect\\\"). Clarified \"\n\"use of :meth:`get_text_length` and removed extra line breaks for long \"\n\"words.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2327 40cd0da7bb2c49d28cf036e85d01e73d\nmsgid \"**Changes in Version 1.14.8**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2329 c23dc29674cd4476a5d1ce8bdba7c25b\nmsgid \"\"\n\"**Added** :meth:`Pixmap.set_rect` to change the pixel values in a \"\n\"rectangle. This is also an alternative to setting the color of a complete\"\n\" pixmap (:meth:`Pixmap.clear_with`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2330 647ba02e1ad3448b85b1e417300551d5\nmsgid \"\"\n\"**Fixed** an image extraction issue with JBIG2 (monochrome) encoded PDF \"\n\"images. The issue occurred in :meth:`Page.getText` (parameters \\\"dict\\\" \"\n\"and \\\"rawdict\\\") and in :meth:`Document.extractImage` methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2331 97187008a30a4a7cad0a589358db47c2\nmsgid \"\"\n\"**Fixed** an issue with not correctly clearing a non-alpha :ref:`Pixmap` \"\n\"(:meth:`Pixmap.clear_with`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2332 e8d31f10770246f0a19e29e3fe088dba\nmsgid \"\"\n\"**Fixed** an issue with not correctly inverting colors of a non-alpha \"\n\":ref:`Pixmap` (:meth:`Pixmap.invert_irect`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2336 67dff84982fa4c1680c49d7d32e32cd7\nmsgid \"**Changes in Version 1.14.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2338 7a13d485e8154810a7af7370e7e9252d\nmsgid \"**Added** :meth:`Pixmap.set_pixel` to change one pixel value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2339 4c9debbd3ad14281953bef2ed96535b3\nmsgid \"**Added** documentation for image conversion in the :ref:`FAQ`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2340 78bdc22a5a5e4e64a9d8b4b07bfb1123\nmsgid \"\"\n\"**Added** new function :meth:`get_text_length` to determine the string \"\n\"length for a given font.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2341 a5c814fd37c640aa8a93aa10f85c235c\nmsgid \"\"\n\"**Added** Postscript image output (changed :meth:`Pixmap.save` and \"\n\":meth:`Pixmap.tobytes`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2342 f3c2525369734e7089b7c83e8cf9de47\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.save` and :meth:`Pixmap.tobytes` to ensure \"\n\"valid combinations of colorspace, alpha and output format.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2343 b9e74f4416644fccb65daa7e89c723c3\nmsgid \"\"\n\"**Changed** :meth:`Pixmap.save`: the desired format is now inferred from \"\n\"the filename.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2344 2d75602bfe7c4491afe16b74bc43214f\nmsgid \"\"\n\"**Changed** FreeText annotations can now have a transparent background - \"\n\"see :meth:`Annot.update`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2348 6c3551ae311845ee9b99b03931d18295\nmsgid \"**Changes in Version 1.14.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2350 bf604455e7bc49078d6f8fad925b9c40\nmsgid \"\"\n\"**Changed:** :ref:`Shape` methods now strictly use the transformation \"\n\"matrix of the :ref:`Page` -- instead of \\\"manually\\\" calculating \"\n\"locations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2351 a31dae7889694da7be488d4e185ec9eb\nmsgid \"\"\n\"**Added** method :meth:`Pixmap.pixel` which returns the pixel value (a \"\n\"list) for given pixel coordinates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2352 27fb489fd3c4437dae7d84ea827220f4\nmsgid \"\"\n\"**Added** method :meth:`Pixmap.tobytes` which returns a bytes object \"\n\"representing the pixmap in a variety of formats. Previously, this could \"\n\"be done for PNG outputs only (:meth:`Pixmap.tobytes`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2353 1c71f20d72344b9d92a9db58d371f81b\nmsgid \"\"\n\"**Changed:** output of methods :meth:`Pixmap.save` and (the new) \"\n\":meth:`Pixmap.tobytes` may now also be PSD (Adobe Photoshop Document).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2354 fa29ec91aa714c5f907b7366ffb9a3b9\nmsgid \"\"\n\"**Added** method :meth:`Shape.drawQuad` which draws a :ref:`Quad`. This \"\n\"actually is a shorthand for a :meth:`Shape.drawPolyline` with the edges \"\n\"of the quad.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2355 91031a98d09349dbb69473db2e7329ec\nmsgid \"\"\n\"**Changed** method :meth:`Shape.drawOval`: the argument can now be \"\n\"**either** a rectangle (:data:`rect_like`) **or** a quadrilateral \"\n\"(:data:`quad_like`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2359 0e8436f8a5324f5c854c6da3891f584a\nmsgid \"**Changes in Version 1.14.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2361 f161930e41614a59bd8398be1a48b0c9\nmsgid \"**Fixes** issue #239 \\\"Annotation coordinate consistency\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2366 f717329397b04912b44b761001662800\nmsgid \"**Changes in Version 1.14.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2368 c8623149250744e589dc449330738ae7\nmsgid \"This patch version contains minor bug fixes and CJK font output support.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2370 090ca3d9b2344ba888c0876c7b71ace0\nmsgid \"\"\n\"**Added** support for the four CJK fonts as PyMuPDF generated text \"\n\"output. This pertains to methods :meth:`Page.insertFont`, \"\n\":meth:`Shape.insertText`, :meth:`Shape.insertTextbox`, and corresponding \"\n\":ref:`Page` methods. The new fonts are available under \\\"reserved\\\" \"\n\"fontnames \\\"china-t\\\" (traditional Chinese), \\\"china-s\\\" (simplified \"\n\"Chinese), \\\"japan\\\" (Japanese), and \\\"korea\\\" (Korean).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2371 0883c9f987274b41ae7f270c3f497622\nmsgid \"**Added** full support for the built-in fonts 'Symbol' and 'Zapfdingbats'.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2372 28cecba376654ea4aabaf41a9a9e76a0\nmsgid \"\"\n\"**Changed:** The 14 standard fonts can now each be referenced by a \"\n\"4-letter abbreviation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2376 2af6e8674b4443da9ecbfff548ce5a69\nmsgid \"**Changes in Version 1.14.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2378 b0f0dfdd4d05439fbb192a2fff012afd\nmsgid \"This patch version contains minor performance improvements.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2380 d55c7a1c5617427cae944d98885ab488\nmsgid \"\"\n\"**Added** support for :ref:`Document` filenames given as *pathlib* object\"\n\" by using the Python *str()* function.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2385 8408ffdc08bd4b988e1d1d8706e8852d\nmsgid \"**Changes in Version 1.14.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2387 5e88bed306444855bb7cb18769259f07\nmsgid \"\"\n\"To support MuPDF v1.14.0, massive changes were required in PyMuPDF -- \"\n\"most of them purely technical, with little visibility to developers. But \"\n\"there are also quite a lot of interesting new and improved features. \"\n\"Following are the details:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2389 ddc84ec9e77d406180396849960f6fd3\nmsgid \"**Added** \\\"ink\\\" annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2390 5ef49f9b2028452da946e586194111bd\nmsgid \"**Added** \\\"rubber stamp\\\" annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2391 4a7bb926db894ea39c7f10315f2e825a\nmsgid \"**Added** \\\"squiggly\\\" text marker annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2392 3398303dd33846db9cfde43f06070d2d\nmsgid \"\"\n\"**Added** new class :ref:`Quad` (quadrilateral or tetragon) -- which \"\n\"represents a general four-sided shape in the plane. The special subtype \"\n\"of rectangular, non-empty tetragons is used in text marker annotations \"\n\"and as returned objects in text search methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2393 6c56ac281b924d2fb189ede6e9c8be61\nmsgid \"\"\n\"**Added** a new option \\\"decrypt\\\" to :meth:`Document.save` and \"\n\":meth:`Document.write`. Now you can **keep encryption** when saving a \"\n\"password protected PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2394 b394b2a1574646c89160273346915f47\nmsgid \"\"\n\"**Added** suppression and redirection of unsolicited messages issued by \"\n\"the underlying C-library MuPDF. Consult :ref:`RedirectMessages` for \"\n\"details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2395 47856295d652463f8184801b60dee8a0\nmsgid \"\"\n\"**Changed:** Changes to annotations now **always require** \"\n\":meth:`Annot.update` to become effective.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2396 ef1b316a5b024381bc8ab808d69d2891\nmsgid \"\"\n\"**Changed** free text annotations to support the full Latin character set\"\n\" and range of appearance options.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2397 506d4cd601f04e2c83386b5ec8940898\nmsgid \"\"\n\"**Changed** text searching, :meth:`Page.searchFor`, to optionally return \"\n\":ref:`Quad` instead :ref:`Rect` objects surrounding each search hit.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2398 4fd963295c354372b9e8574e51f097ee\nmsgid \"\"\n\"**Changed** plain text output: we now add a *\\\\n* to each line if it does\"\n\" not itself end with this character.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2399 1db7b0929bbf4596b2a0d22f3ca7b59c\nmsgid \"**Fixed** issue 211 (\\\"Something wrong in the doc\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2400 f1128c764272467f8fb8a6c3a9b0087e\nmsgid \"\"\n\"**Fixed** issue 213 (\\\"Rewritten outline is displayed only by mupdf-based\"\n\" applications\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2401 f7b1e5c7dc7c4676a9bf4838c03b508c\nmsgid \"**Fixed** issue 214 (\\\"PDF decryption GONE!\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2402 7a1c216e3cf04513bac8a38d46fb777a\nmsgid \"**Fixed** issue 215 (\\\"Formatting of links added with pyMuPDF\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2403 9c9ae8e5f826442d8888cefae230e64e\nmsgid \"**Fixed** issue 217 (\\\"extraction through json is failing for my pdf\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2405 5ae51da467b64e26bfb10cf525eb9581\nmsgid \"\"\n\"Behind the curtain, we have changed the implementation of geometry \"\n\"objects: they now purely exist in Python and no longer have \\\"shadow\\\" \"\n\"twins on the C-level (in MuPDF). This has improved processing speed in \"\n\"that area by more than a factor of two.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2407 b5211152c64342a49990467a8d763bd5\nmsgid \"\"\n\"Because of the same reason, most methods involving geometry parameters \"\n\"now also accept the corresponding Python sequence. For example, in method\"\n\" *\\\"page.show_pdf_page(rect, ...)\\\"* parameter *rect* may now be any \"\n\":data:`rect_like` sequence.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2409 79b7deaba4ec49f58fd8987c7e950e28\nmsgid \"\"\n\"We also invested considerable effort to further extend and improve the \"\n\":ref:`FAQ` chapter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2414 fd91322d1a494ed189d8932bb19e425a\nmsgid \"**Changes in Version 1.13.19**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2416 c99f01c86e0f418e8ece858b509f575f\nmsgid \"\"\n\"This version contains some technical / performance improvements and bug \"\n\"fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2418 f6ca673e1a514b8c88882528546fc938\n#, python-format\nmsgid \"\"\n\"**Changed** memory management: for Python 3 builds, Python memory \"\n\"management is exclusively used across all C-level code (i.e. no more \"\n\"native *malloc()* in MuPDF code or PyMuPDF interface code). This leads to\"\n\" improved memory usage profiles and also some runtime improvements: we \"\n\"have seen > 2% shorter runtimes for text extractions and pixmap creations\"\n\" (on Windows machines only to date).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2419 5bfccbbb021842b9abb0b04bf9de48c3\nmsgid \"\"\n\"**Fixed** an error occurring in Python 2.7, which crashed the interpreter\"\n\" when using :meth:`TextPage.extractRAWDICT` (= \"\n\"*Page.getText(\\\"rawdict\\\")*).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2420 0f2cb31dfbf9466fa8a235d46d2c6e8a\nmsgid \"\"\n\"**Fixed** an error occurring in Python 2.7, when creating link \"\n\"destinations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2421 08e34b265b7e454f94220ea943997f4d\nmsgid \"**Extended** the :ref:`FAQ` chapter with more examples.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2425 63b7e43da4034c64859e960033709c83\nmsgid \"**Changes in Version 1.13.18**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2427 cf5beb6e03c54affafc84f316858c9aa\nmsgid \"\"\n\"**Added** method :meth:`TextPage.extractRAWDICT`, and a corresponding new\"\n\" string parameter \\\"rawdict\\\" to method :meth:`Page.getText`. It extracts\"\n\" text and images from a page in Python *dict* form like \"\n\":meth:`TextPage.extractDICT`, but with the detail level of \"\n\":meth:`TextPage.extractXML`, which is position information down to each \"\n\"single character.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2431 9b563f0c8c3a4d1fb8e8fe127bb76d6c\nmsgid \"**Changes in Version 1.13.17**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2433 b3c0162af9db4f608389e2c811c7bc4b\nmsgid \"\"\n\"**Fixed** an error that intermittently caused an exception in \"\n\":meth:`Page.show_pdf_page`, when pages from many different source PDFs \"\n\"were shown.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2434 c35c79318b584e5790dbea763351299b\nmsgid \"\"\n\"**Changed** method :meth:`Document.extractImage` to now return more meta \"\n\"information about the extracted image. Also, its performance has been \"\n\"greatly improved. Several demo scripts have been changed to make use of \"\n\"this method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2435 ef0a501dd401489f8d0796417bf84a65\nmsgid \"\"\n\"**Changed** method :meth:`Document._getXrefStream` to now return *None* \"\n\"if the object is no stream and no longer raise an exception if otherwise.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2436 7032fecda32745aeb0b54febfa6571f7\nmsgid \"\"\n\"**Added** method :meth:`Document._deleteObject` which deletes a PDF \"\n\"object identified by its :data:`xref`. Only to be used by the experienced\"\n\" PDF expert.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2437 64f62a994fb742cf84570443580cf6a2\nmsgid \"\"\n\"**Added** a method :meth:`paper_rect` which returns a :ref:`Rect` for a \"\n\"supplied paper format string. Example: *fitz.paper_rect(\\\"letter\\\") = \"\n\"fitz.Rect(0.0, 0.0, 612.0, 792.0)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2438 31e24169fc6849878acc3c4b81c2931b\nmsgid \"**Added** a :ref:`FAQ` chapter to this document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2442 43d63ac60a0c46a591e1b79f54377917\nmsgid \"**Changes in Version 1.13.16**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2444 d904d04d3cfb4dcda46139c25fe24c71\nmsgid \"\"\n\"**Added** support for correctly setting transparency (opacity) for \"\n\"certain annotation types.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2445 3b7e735489e94623ac095480bdcbc2a5\nmsgid \"\"\n\"**Added** a tool property (:attr:`Tools.fitz_config`) showing the \"\n\"configuration of this PyMuPDF version.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2446 9c879f61145948b188ee8d93c5efe154\nmsgid \"\"\n\"**Fixed** issue #193 ('insertText(overlay=False) gives \\\"cannot resize a \"\n\"buffer with shared storage\\\" error') by avoiding read-only buffers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2450 5d037ed847b44095be41047f123f2c7d\nmsgid \"**Changes in Version 1.13.15**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2452 7b20562ab960458cb2a37834b262bc0a\nmsgid \"\"\n\"**Fixed** issue #189 (\\\"cannot find builtin CJK font\\\"), so we are \"\n\"supporting builtin CJK fonts now (CJK = China, Japan, Korea). This should\"\n\" lead to correctly generated pixmaps for documents using these languages.\"\n\" This change has consequences for our binary file size: it will now range\"\n\" between 8 and 10 MB, depending on the OS.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2453 09714417974d4784bbb8ce28449b0ed4\nmsgid \"\"\n\"**Fixed** issue #191 (\\\"Jupyter notebook kernel dies after ca. 40 \"\n\"pages\\\"), which occurred when modifying the contents of an annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2457 5adc29b99ec94005bffd7ef24998e110\nmsgid \"**Changes in Version 1.13.14**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2459 7f38a7f515424bdf958094ead9ab7ef0\nmsgid \"This patch version contains several improvements, mainly for annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2461 b1c7424aa4d54a5caefae33e0e5f4f84\nmsgid \"\"\n\"**Changed** :attr:`Annot.lineEnds` is now a list of two integers \"\n\"representing the line end symbols. Previously was a *dict* of strings.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2462 641b3d6d6a8f46359ce78aacec1a00fe\nmsgid \"\"\n\"**Added** support of line end symbols for applicable annotations. PyMuPDF\"\n\" now can generate these annotations including the line end symbols.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2463 f00765d5f2434220a9bfa1b43ce083c6\nmsgid \"\"\n\"**Added** :meth:`Annot.setLineEnds` adds line end symbols to applicable \"\n\"annotation types ('Line', 'PolyLine', 'Polygon').\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2464 c43498bf8fbe4da3bbbd2a1b57eb2ade\nmsgid \"\"\n\"**Changed** technical implementation of :meth:`Page.insertImage` and \"\n\":meth:`Page.show_pdf_page`: they now create there own contents objects, \"\n\"thereby avoiding changes of potentially large streams with consequential \"\n\"compression / decompression efforts and high change volumes with \"\n\"incremental updates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2468 6d6106b5cef0412c859b77efff74d76a\nmsgid \"**Changes in Version 1.13.13**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2470 76e178082cef4bbcaf9d02facb74a2a8\nmsgid \"\"\n\"This patch version contains several improvements for embedded files and \"\n\"file attachment annotations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2472 a3ecffcb691f41e18fa492558ef375d5\nmsgid \"\"\n\"**Added** :meth:`Document.embfile_Upd` which allows changing **file \"\n\"content and metadata** of an embedded file. It supersedes the old method \"\n\":meth:`Document.embfile_SetInfo` (which will be deleted in a future \"\n\"version). Content is automatically compressed and metadata may be \"\n\"unicode.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2473 8741c8c5503e49c5a9e436d200d0c70c\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_Add` to now automatically compress \"\n\"file content. Accompanying metadata can now be unicode (had to be ASCII \"\n\"in the past).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2474 c8825e3ce49940899586673a8c1ca760\nmsgid \"\"\n\"**Changed** :meth:`Document.embfile_Del` to now automatically delete \"\n\"**all entries** having the supplied identifying name. The return code is \"\n\"now an integer count of the removed entries (was *None* previously).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2475 4958c06f7c0b4eaca87af2482582ca8c\nmsgid \"\"\n\"**Changed** embedded file methods to now also accept or show the PDF \"\n\"unicode filename as additional parameter *ufilename*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2476 0f95f3527f1a489a9a72167a6cee97cf\nmsgid \"\"\n\"**Added** :meth:`Page.add_file_annot` which adds a new file attachment \"\n\"annotation.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2477 14f2faf502b74997b3e11958e4ffd5dd\nmsgid \"\"\n\"**Changed** :meth:`Annot.fileUpd` (file attachment annot) to now also \"\n\"accept the PDF unicode *ufilename* parameter. The description parameter \"\n\"*desc* correctly works with unicode. Furthermore, **all** parameters are \"\n\"optional, so metadata may be changed without also replacing the file \"\n\"content.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2478 f11e4025175f468fb362dc45b4b459a8\nmsgid \"\"\n\"**Changed** :meth:`Annot.fileInfo` (file attachment annot) to now also \"\n\"show the PDF unicode filename as parameter *ufilename*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2479 96f083ba329841dc866568603f6bf4e0\nmsgid \"\"\n\"**Fixed** issue #180 (\\\"page.getText(output='dict') return invalid \"\n\"bbox\\\") to now also work for vertical text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2480 b9c17d72bfcd4a87983f018daf4d8fd9\nmsgid \"\"\n\"**Fixed** issue #185 (\\\"Can't render the annotations created by \"\n\"PyMuPDF\\\"). The issue's cause was the minimalistic MuPDF approach when \"\n\"creating annotations. Several annotation types have no */AP* \"\n\"(\\\"appearance\\\") object when created by MuPDF functions. MuPDF, \"\n\"SumatraPDF and hence also PyMuPDF cannot render annotations without such \"\n\"an object. This fix now ensures, that an appearance object is always \"\n\"created together with the annotation itself. We still do not support line\"\n\" end styles.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2484 17b80da49d874916b1fa04cbc2e8225e\nmsgid \"**Changes in Version 1.13.12**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2486 16cf3df1aa764ac99837e6ba6929de3a\nmsgid \"\"\n\"**Fixed** issue #180 (\\\"page.getText(output='dict') return invalid \"\n\"bbox\\\"). Note that this is a circumvention of an MuPDF error, which \"\n\"generates zero-height character rectangles in some cases. When this \"\n\"happens, this fix ensures a bbox height of at least fontsize.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2487 61159291a2db420095ce281675ae121e\nmsgid \"\"\n\"**Changed** for ListBox and ComboBox widgets, the attribute list of \"\n\"selectable values has been renamed to :attr:`Widget.choice_values`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2488 bab6778e8c2944089f3b525aa8b0827d\nmsgid \"\"\n\"**Changed** when adding widgets, any missing of the :ref:`Base-14-Fonts` \"\n\"is automatically added to the PDF. Widget text fonts can now also be \"\n\"chosen from existing widget fonts. Any specified field values are now \"\n\"honored and lead to a field with a preset value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2489 30b1813eb102490a896faa64748c1400\nmsgid \"\"\n\"**Added** :meth:`Annot.updateWidget` which allows changing existing form \"\n\"fields -- including the field value.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2493 9bc92bc23e1a46ab8548886763c96d47\nmsgid \"**Changes in Version 1.13.11**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2495 474a1a3d16e74ac7bcfe223ce5d3daad\nmsgid \"\"\n\"While the preceding patch subversions only contained various fixes, this \"\n\"version again introduces major new features:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2497 5edc44b1ecc84b25be1507861ce353f4\nmsgid \"\"\n\"**Added** basic support for PDF widget annotations. You can now add PDF \"\n\"form fields of types Text, CheckBox, ListBox and ComboBox. Where \"\n\"necessary, the PDF is transformed to a Form PDF with the first added \"\n\"widget.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2498 1a904dc65fe64ade80e693aa4edb88ae\nmsgid \"\"\n\"**Fixed** issues #176 (\\\"wrong file embedding\\\"), #177 (\\\"segment fault \"\n\"when invoking page.getText()\\\")and #179 (\\\"Segmentation fault using \"\n\"page.getLinks() on encrypted PDF\\\").\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2503 7b2a31d79daa40d497d99853e692f397\nmsgid \"**Changes in Version 1.13.7**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2505 445d2b1c88854acbb84fecfeeb62cdc1\nmsgid \"\"\n\"**Added** support of variable page sizes for reflowable documents \"\n\"(e-books, HTML, etc.): new parameters *rect* and *fontsize* in \"\n\":ref:`Document` creation (open), and as a separate method \"\n\":meth:`Document.layout`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2506 b16382d708314b4c9ed3ac5b10f9a517\nmsgid \"\"\n\"**Added** :ref:`Annot` creation of many annotations types: sticky notes, \"\n\"free text, circle, rectangle, line, polygon, polyline and text markers.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2507 1444d852579b4d93837b7fe871afbf81\nmsgid \"\"\n\"**Added** support of annotation transparency (:attr:`Annot.opacity`, \"\n\":meth:`Annot.setOpacity`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2508 d544fe252c1f408785338b846f68eb33\nmsgid \"\"\n\"**Changed** :attr:`Annot.vertices`: point coordinates are now grouped as \"\n\"pairs of floats (no longer as separate floats).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2509 d7dd102d5d974b77a860d4ee2a960da8\nmsgid \"\"\n\"**Changed** annotation colors dictionary: the two keys are now named \"\n\"*\\\"stroke\\\"* (formerly *\\\"common\\\"*) and *\\\"fill\\\"*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2510 8ba3ff12895543d4b2b60a1b9a3646d4\nmsgid \"\"\n\"**Added** :attr:`Document.isDirty` which is *True* if a PDF has been \"\n\"changed in this session. Reset to *False* on each :meth:`Document.save` \"\n\"or :meth:`Document.write`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2514 572be3e137d346d1bc831219977e2a47\nmsgid \"**Changes in Version 1.13.6**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2516 32c7a915842343e78b6da4d29061d488\nmsgid \"\"\n\"Fix #173: for memory-resident documents, ensure the stream object will \"\n\"not be garbage-collected by Python before document is closed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2520 dfb8278835404213b0f3e00e10fa6f44\nmsgid \"**Changes in Version 1.13.5**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2522 d0f227e259ff4badbddfa8bc99f77761\nmsgid \"\"\n\"New low-level method :meth:`Page._setContents` defines an object given by\"\n\" its :data:`xref` to serve as the :data:`contents` object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2523 f305bdd0987e4a1f95ef94714cb586b7\nmsgid \"\"\n\"Changed and extended PDF form field support: the attribute *widget_text* \"\n\"has been renamed to :attr:`Annot.widget_value`. Values of all form field \"\n\"types (except signatures) are now supported. A new attribute \"\n\":attr:`Annot.widget_choices` contains the selectable values of listboxes \"\n\"and comboboxes. All these attributes now contain *None* if no value is \"\n\"present.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2527 4fd769eb21f048a19b8230f7e72178ca\nmsgid \"**Changes in Version 1.13.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2529 53ed864ab32f470bb28b858354a50e08\nmsgid \"\"\n\":meth:`Document.convertToPDF` now supports page ranges, reverted page \"\n\"sequences and page rotation. If the document already is a PDF, an \"\n\"exception is raised.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2530 76b57e7db1504c5aba637f3c1da9e11c\nmsgid \"\"\n\"Fixed a bug (introduced with v1.13.0) that prevented \"\n\":meth:`Page.insertImage` for transparent images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2534 2ee92c34815a4f8fb2c8e58d119f4ea1\nmsgid \"**Changes in Version 1.13.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2536 b6964dbe69ac4c14913e804c1db84219\nmsgid \"\"\n\"Introduces a way to convert **any MuPDF supported document** to a PDF. If\"\n\" you ever wanted PDF versions of your XPS, EPUB, CBZ or FB2 files -- here\"\n\" is a way to do this.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2538 3b8c44dc6cc2424186ca83fb933f4d4d\nmsgid \"\"\n\":meth:`Document.convertToPDF` returns a Python *bytes* object in PDF \"\n\"format. Can be opened like normal in PyMuPDF, or be written to disk with \"\n\"the *\\\".pdf\\\"* extension.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2542 a74fa53b1f63473e95f8ae83eadc426f\nmsgid \"**Changes in Version 1.13.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2544 7ebed477136d45edbc0674eaaa9dff08\nmsgid \"\"\n\"The major enhancement is PDF form field support. Form fields are \"\n\"annotations of type *(19, 'Widget')*. There is a new document method to \"\n\"check whether a PDF is a form. The :ref:`Annot` class has new properties \"\n\"describing field details.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2546 6224991d69044aed91933c6ef3db8872\nmsgid \"\"\n\":attr:`Document.is_form_pdf` is true if object type */AcroForm* and at \"\n\"least one form field exists.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2547 3c3eddc4ca6a41179dba2d970ae478cf\nmsgid \"\"\n\":attr:`Annot.widget_type`, :attr:`Annot.widget_text` and \"\n\":attr:`Annot.widget_name` contain the details of a form field (i.e. a \"\n\"\\\"Widget\\\" annotation).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2551 33caa17db3314e8f8ec675dfcc887087\nmsgid \"**Changes in Version 1.13.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2553 9344a01be7c64abbbe4577c065593441\nmsgid \"\"\n\":meth:`TextPage.extractDICT` is a new method to extract the contents of a\"\n\" document page (text and images). All document types are supported as \"\n\"with the other :ref:`TextPage` *extract*()* methods. The returned object \"\n\"is a dictionary of nested lists and other dictionaries, and **exactly \"\n\"equal** to the JSON-deserialization of the old \"\n\":meth:`TextPage.extractJSON`. The difference is that the result is \"\n\"created directly -- no JSON module is used. Because the user needs no \"\n\"JSON module to interpret the information, it should be easier to use, and\"\n\" also have a better performance, because it contains images in their \"\n\"original **binary format** -- they need not be base64-decoded.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2554 a0c4ad5a3c484f91ac0a8e10f14f5e12\nmsgid \"\"\n\":meth:`Page.getText` correspondingly supports the new parameter value \"\n\"*\\\"dict\\\"* to invoke the above method.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2555 093f2f8fbd7d47c8a423fd962433aaf6\nmsgid \"\"\n\":meth:`TextPage.extractJSON` (resp. *Page.getText(\\\"json\\\")*) is still \"\n\"supported for convenience, but its use is expected to decline.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2559 0502f4342d864193843c189056a3f649\nmsgid \"**Changes in Version 1.13.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2561 a1fd3f8dcf7347f0b02e341033bab447\nmsgid \"\"\n\"This version is based on MuPDF v1.13.0. This release is \\\"primarily a bug\"\n\" fix release\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2563 f6293a0c60534e0aa61af056ce5873ab\nmsgid \"\"\n\"In PyMuPDF, we are also doing some bug fixes while introducing minor \"\n\"enhancements. There only very minimal changes to the user's API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2565 112b9e394ace4296b2004b9cc2566a4c\nmsgid \"\"\n\":ref:`Document` construction is more flexible: the new *filetype* \"\n\"parameter allows setting the document type. If specified, any extension \"\n\"in the filename will be ignored. More completely addresses `issue #156 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/156>`_. As part of this, the \"\n\"documentation has been reworked.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2569 1fd37787dc5e4b74860ae968de485c3a\nmsgid \"Changes to :ref:`Pixmap` constructors:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2568 b1dfea15e23f480e9294338557073269\nmsgid \"\"\n\"Colorspace conversion no longer allows dropping the alpha channel: source\"\n\" and target **alpha will now always be the same**. We have seen \"\n\"exceptions and even interpreter crashes when using *alpha = 0*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2569 d13b23318d24436a98e726ab0c700090\nmsgid \"As a replacement, the simple pixmap copy lets you choose the target alpha.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2571 1245466299bd401c91dede79edbe0761\nmsgid \"\"\n\":meth:`Document.save` again offers the full garbage collection range 0 \"\n\"thru 4. Because of a bug in :data:`xref` maintenance, we had to \"\n\"temporarily enforce *garbage > 1*. Finally resolves `issue #148 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/148>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2573 5e0acf1f4a8b4284b68c4664d8506094\nmsgid \"\"\n\":meth:`Document.save` now offers to \\\"prettify\\\" PDF source via an \"\n\"additional argument.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2574 696c719c11ba4d4f8436604179238f4f\nmsgid \"\"\n\":meth:`Page.insertImage` has the additional *stream* \\\\-parameter, \"\n\"specifying a memory area holding an image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2576 083d9194c33f41068f0776f565c79c87\nmsgid \"\"\n\"Issue with garbled PNGs on Linux systems has been resolved (`\\\"Problem \"\n\"writing PNG\\\" #133) <https://github.com/pymupdf/PyMuPDF/issues/133>`_.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2581 98cc7e1927894f43bd5433b0231b3dcf\nmsgid \"**Changes in Version 1.12.4**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2583 7611c52e40a247d499880fc162bf20bb\nmsgid \"This is an extension of 1.12.3.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2585 55de61bfb5954f95b17921dcd4914391\nmsgid \"\"\n\"Fix of `issue #147 <https://github.com/pymupdf/PyMuPDF/issues/147>`_: \"\n\"methods :meth:`Document.getPageFontlist` and \"\n\":meth:`Document.getPageImagelist` now also show fonts and images \"\n\"contained in :data:`resources` nested via \\\"Form XObjects\\\".\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2586 241a50f48e4b403481f23435638646e1\nmsgid \"\"\n\"Temporary fix of `issue #148 \"\n\"<https://github.com/pymupdf/PyMuPDF/issues/148>`_: Saving to new PDF \"\n\"files will now automatically use *garbage = 2* if a lower value is given.\"\n\" Final fix is to be expected with MuPDF's next version. At that point we \"\n\"will remove this circumvention.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2587 d1aeb27a9161455f91a41a0c53d1de52\nmsgid \"\"\n\"Preventive fix of illegally using stencil / image mask pixmaps in some \"\n\"methods.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2588 4d9f3bf7e9db4f75a524f3e201db2d32\nmsgid \"\"\n\"Method :meth:`Document.getPageFontlist` now includes the encoding name \"\n\"for each font in the list.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2589 da72830c7d2c40009f927c37bd604e55\nmsgid \"\"\n\"Method :meth:`Document.getPageImagelist` now includes the decode method \"\n\"name for each image in the list.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2593 b3c6fae68a704c8eb5f4e78304a1d854\nmsgid \"**Changes in Version 1.12.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2595 4c52faae63874d45873aa766f417ab6f\nmsgid \"This is an extension of 1.12.2.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2597 943612aea06749f4962d1ced1418925a\nmsgid \"\"\n\"Many functions now return *None* instead of *0*, if the result has no \"\n\"other meaning than just indicating successful execution \"\n\"(:meth:`Document.close`, :meth:`Document.save`, :meth:`Document.select`, \"\n\":meth:`Pixmap.save` and many others).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2601 6f0d4e2bdd41401d94ed4fe0fd9ec7e8\nmsgid \"**Changes in Version 1.12.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2603 630bed92f4e34421925b88efe1ba42b6\nmsgid \"This is an extension of 1.12.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2605 50a351aa4579484893c9094cda2cfeba\nmsgid \"\"\n\"Method :meth:`Page.show_pdf_page` now accepts the new *clip* argument. \"\n\"This specifies an area of the source page to which the display should be \"\n\"restricted.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2607 80570d982b004e41989292ba7bb4ddb9\nmsgid \"\"\n\"New :attr:`Page.CropBox` and :attr:`Page.MediaBox` have been included for\"\n\" convenience.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2612 54fd6f1c51e04778bac0835de4f0361a\nmsgid \"**Changes in Version 1.12.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2614 db11fc420c4b4bd59ba30cf2a4f190d3\nmsgid \"This is an extension of version 1.12.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2616 82affdfbc4bb42ccabe2c77070a11719\nmsgid \"\"\n\"New method :meth:`Page.show_pdf_page` displays another's PDF page. This \"\n\"is a **vector** image and therefore remains precise across zooming. Both \"\n\"involved documents must be PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2618 f0e7a4343cf14d058e07063707db7b7e\nmsgid \"\"\n\"New method :meth:`Page.getSVGimage` creates an SVG image from the page. \"\n\"In contrast to the raster image of a pixmap, this is a vector image \"\n\"format. The return is a unicode text string, which can be saved in a \"\n\"*.svg* file.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2620 c81d51dc94f646fda815c43c09bab73d\nmsgid \"\"\n\"Method :meth:`Page.getTextBlocks` now accepts an additional bool \"\n\"parameter \\\"images\\\". If set to true (default is false), image blocks \"\n\"(metadata only) are included in the produced list and thus allow \"\n\"detecting areas with rendered images.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2622 5eafe44f47b34527bfff5138b15affd3\nmsgid \"Minor bug fixes.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2624 6bf7252d584b4c8e9b97592fc0d934e4\nmsgid \"\"\n\"\\\"text\\\" result of :meth:`Page.getText` concatenates all lines within a \"\n\"block using a single space character. MuPDF's original uses \\\"\\\\\\\\n\\\" \"\n\"instead, producing a rather ragged output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2626 94bf5fb0e50249e78857f02ebaaff525\nmsgid \"\"\n\"New properties of :ref:`Page` objects :attr:`Page.MediaBoxSize` and \"\n\":attr:`Page.CropBoxPosition` provide more information about a page's \"\n\"dimensions. For non-PDF files (and for most PDF files, too) these will be\"\n\" equal to :attr:`Page.rect.bottom_right`, resp. \"\n\":attr:`Page.rect.top_left`. For example, class :ref:`Shape` makes use of \"\n\"them to correctly position its items.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2630 74d15ecb1b914538a684a22683984be7\nmsgid \"**Changes in Version 1.12.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2632 ac50d19ead2044d4afef9637fadb68d5\nmsgid \"\"\n\"This version is based on and requires MuPDF v1.12.0. The new MuPDF \"\n\"version contains quite a number of changes -- most of them around text \"\n\"extraction. Some of the changes impact the programmer's API.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2634 1b465153b5814abe8ed0d412684e1e54\nmsgid \"\"\n\":meth:`Outline.saveText` and :meth:`Outline.saveXML` have been deleted \"\n\"without replacement. You probably haven't used them much anyway. But if \"\n\"you are looking for a replacement: the output of :meth:`Document.get_toc`\"\n\" can easily be used to produce something equivalent.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2636 b2b48a42c44c4a1dab5f5c66edaf406a\nmsgid \"Class *TextSheet* does no longer exist.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2638 f6faca5ccc3b4ddab529d2c73f600396\nmsgid \"\"\n\"Text \\\"spans\\\" (one of the hierarchy levels of :ref:`TextPage`) no longer\"\n\" contain positioning information (i.e. no \\\"bbox\\\" key). Instead, spans \"\n\"now provide the font information for its text. This impacts our JSON \"\n\"output variant.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2640 cc737a16a9114bea9f2892a3d611d32f\nmsgid \"\"\n\"HTML output has improved very much: it now creates valid documents which \"\n\"can be displayed by browsers to produce a similar view as the original \"\n\"document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2642 88630dce5a784283a7c487d4fd39dfe4\nmsgid \"\"\n\"There is a new output format XHTML, which provides text and images in a \"\n\"browser-readable format. The difference to HTML output is, that no effort\"\n\" is made to reproduce the original layout.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2644 3af5ba7ff439426696f0f07a23e1d8fa\nmsgid \"\"\n\"All output formats of :meth:`Page.getText` now support creating complete,\"\n\" valid documents, by wrapping them with appropriate header and trailer \"\n\"information. If you are interested in using the HTML output, please make \"\n\"sure to read :ref:`HTMLQuality`.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2646 87e42d9c77a54890af57f976c5071ba7\nmsgid \"\"\n\"To support finding text positions, we have added special methods that \"\n\"don't need detours like :meth:`TextPage.extractJSON` or \"\n\":meth:`TextPage.extractXML`: use :meth:`Page.getTextBlocks` or resp. \"\n\":meth:`Page.getTextWords` to create lists of text blocks or resp. words, \"\n\"which are accompanied by their rectangles. This should be much faster \"\n\"than the standard text extraction methods and also avoids using \"\n\"additional packages for interpreting their output.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2651 239ae39492b748df849ea403ef2108f0\nmsgid \"**Changes in Version 1.11.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2653 2c6897b2b1734812a1b0c402d1ba8907\nmsgid \"This is an extension of v1.11.1.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2655 b024b8bd2f954e69a9f3a58c001cc2d8\nmsgid \"\"\n\"New :meth:`Page.insertFont` creates a PDF */Font* object and returns its \"\n\"object number.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2657 17bf32eed08e4af7a9235c26da714f4c\nmsgid \"\"\n\"New :meth:`Document.extractFont` extracts the content of an embedded font\"\n\" given its object number.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2659 8a06bf9858264b8aaddd5dcc4b335cca\nmsgid \"\"\n\"Methods **FontList(...)** items no longer contain the PDF generation \"\n\"number. This value never had any significance. Instead, the font file \"\n\"extension is included (e.g. \\\"pfa\\\" for a \\\"PostScript Font for ASCII\\\"),\"\n\" which is more valuable information.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2661 f45d17bd4282467ca8855a3a25ae091d\nmsgid \"Fonts other than \\\"simple fonts\\\" (Type1) are now also supported.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2663 18c58364a89d48b6aa981d0c901c91ea\nmsgid \"New options to change :ref:`Pixmap` size:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2665 399900b7d04b4cda9bdb0645844fa951\nmsgid \"Method :meth:`Pixmap.shrink` reduces the pixmap proportionally in place.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2667 3c624215a18b4ee5acf3b3f95f7d3b8f\nmsgid \"\"\n\"A new :ref:`Pixmap` copy constructor allows scaling via setting target \"\n\"width and height.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2672 787726e4ea8e4f998d5c45f15750e062\nmsgid \"**Changes in Version 1.11.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2674 3f97c63d1ab042b0938270157fe47048\nmsgid \"This is an extension of v1.11.0.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2676 51d6f21f07544106b1652c72ebc2ffe2\nmsgid \"\"\n\"New class *Shape*. It facilitates and extends the creation of image \"\n\"shapes on PDF pages. It contains multiple methods for creating elementary\"\n\" shapes like lines, rectangles or circles, which can be combined into \"\n\"more complex ones and be given common properties like line width or \"\n\"colors. Combined shapes are handled as a unit and e.g. be \\\"morphed\\\" \"\n\"together. The class can accumulate multiple complex shapes and put them \"\n\"all in the page's foreground or background -- thus also reducing the \"\n\"number of updates to the page's :data:`contents` object.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2678 2d4cfa604e58468ea1577f10209e6280\nmsgid \"All *Page* draw methods now use the new *Shape* class.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2680 fc7ba2646c3448c297ae41f9fadeda05\nmsgid \"\"\n\"Text insertion methods *insertText()* and *insertTextBox()* now support \"\n\"morphing in addition to text rotation. They have become part of the \"\n\"*Shape* class and thus allow text to be freely combined with graphics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2682 737fb07ba7c242ff9478cdcd66f9c5ec\nmsgid \"\"\n\"A new *Pixmap* constructor allows creating pixmap copies with an added \"\n\"alpha channel. A new method also allows directly manipulating alpha \"\n\"values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2684 8ce597ee78ed4486bbf604c79de4b733\nmsgid \"\"\n\"Binary algebraic operations with geometry objects (matrices, rectangles \"\n\"and points) now generally also support lists or tuples as the second \"\n\"operand. You can add a tuple *(x, y)* of numbers to a :ref:`Point`. In \"\n\"this context, such sequences are called \\\":data:`point_like`\\\" (resp. \"\n\":data:`matrix_like`, :data:`rect_like`).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2686 5788fb7d7f784ac09ae37611ece715fa\nmsgid \"\"\n\"Geometry objects now fully support in-place operators. For example, *p /=\"\n\" m* replaces point p with *p * 1/m* for a number, or *p * ~m* for a \"\n\":data:`matrix_like` object *m*. Similarly, if *r* is a rectangle, then *r\"\n\" |= (3, 4)* is the new rectangle that also includes *fitz.Point(3, 4)*, \"\n\"and *r &= (1, 2, 3, 4)* is its intersection with *fitz.Rect(1, 2, 3, 4)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2690 34897b5e1f8042e392f5a46fcd148809\nmsgid \"**Changes in Version 1.11.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2692 d292bd8392b648e4a31cef92ae09f8b5\nmsgid \"This version is based on and requires MuPDF v1.11.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2694 6de44e4ec25b476cb9fc163cdece9c5f\nmsgid \"\"\n\"Though MuPDF has declared it as being mostly a bug fix version, one major\"\n\" new feature is indeed contained: support of embedded files -- also \"\n\"called portfolios or collections. We have extended PyMuPDF functionality \"\n\"to embrace this up to an extent just a little beyond the *mutool* utility\"\n\" as follows.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2696 3f70b50c029542ff87e1112b28bb11f5\nmsgid \"\"\n\"The *Document* class now support embedded files with several new methods \"\n\"and one new property:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2698 1922650fdba747cd960cf08984a60150\nmsgid \"\"\n\"*embfile_Info()* returns metadata information about an entry in the list \"\n\"of embedded files. This is more than *mutool* currently provides: it \"\n\"shows all the information that was used to embed the file (not just the \"\n\"entry's name).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2699 3a1e2417a0dd47e985c0fd31c45e52fa\nmsgid \"\"\n\"*embfile_Get()* retrieves the (decompressed) content of an entry into a \"\n\"*bytes* buffer.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2700 9c68f32b3ab04c2ba2849db67d9b5edc\nmsgid \"\"\n\"*embfile_Add(...)* inserts new content into the PDF portfolio. We (in \"\n\"contrast to *mutool*) **restrict** this to entries with a **new name** \"\n\"(no duplicate names allowed).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2701 274f3e1bbceb4acfb7ceb07d7a164afb\nmsgid \"\"\n\"*embfile_Del(...)* deletes an entry from the portfolio (function not \"\n\"offered in MuPDF).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2702 0a75c5b044d54d62b32f6e6a9c1bb143\nmsgid \"\"\n\"*embfile_SetInfo()* -- changes filename or description of an embedded \"\n\"file.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2703 f80bb0230db84d0fb5d130853430ffb0\nmsgid \"*embfile_Count* -- contains the number of embedded files.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2705 5474da97a2ee44f59d0e2fd58ad55665\nmsgid \"\"\n\"Several enhancements deal with streamlining geometry objects. These are \"\n\"not connected to the new MuPDF version and most of them are also \"\n\"reflected in PyMuPDF v1.10.0. Among them are new properties to identify \"\n\"the corners of rectangles by name (e.g. *Rect.bottom_right*) and new \"\n\"methods to deal with set-theoretic questions like *Rect.contains(x)* or \"\n\"*IRect.intersects(x)*. Special effort focussed on supporting more \"\n\"\\\"Pythonic\\\" language constructs: *if x in rect ...* is equivalent to \"\n\"*rect.contains(x)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2707 2a7db4a61ce24c848f83c0863bad09b7\nmsgid \"\"\n\"The :ref:`Rect` chapter now has more background on empty amd infinite \"\n\"rectangles and how we handle them. The handling itself was also updated \"\n\"for more consistency in this area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2709 33aee8dea574413681caf242adf8da6a\nmsgid \"We have started basic support for **generation** of PDF content:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2711 deb4a2603a53455cb82d849ad34308aa\nmsgid \"\"\n\"*Document.insert_page()* adds a new page into a PDF, optionally \"\n\"containing some text.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2712 f7497c0e1764493a945c64046add98a1\nmsgid \"*Page.insertImage()* places a new image on a PDF page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2713 59797715081c4303a9d023f624eeda19\nmsgid \"*Page.insertText()* puts new text on an existing page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2715 1e1119160b9b47b6838fe3a16078aabc\nmsgid \"\"\n\"For **FileAttachment** annotations, content and name of the attached file\"\n\" can extracted and changed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2719 b6b1a71f6e9c4006ad908aca83e94958\nmsgid \"**Changes in Version 1.10.0**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2721 2d15107ed72748df88b1f193e0590a28\nmsgid \"**MuPDF v1.10 Impact**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2723 bcefb5c4e9884f03a30f600abedbeb81\nmsgid \"\"\n\"MuPDF version 1.10 has a significant impact on our bindings. Some of the \"\n\"changes also affect the API -- in other words, **you** as a PyMuPDF user.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2725 50ef82a6f0904d01b9d131853ef968fe\nmsgid \"\"\n\"Link destination information has been reduced. Several properties of the \"\n\"*linkDest* class no longer contain valuable information. In fact, this \"\n\"class as a whole has been deleted from MuPDF's library and we in PyMuPDF \"\n\"only maintain it to provide compatibility to existing code.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2727 e0f444dd42e048608c890061f2205bab\nmsgid \"\"\n\"In an effort to minimize memory requirements, several improvements have \"\n\"been built into MuPDF v1.10:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2729 dd57640466d6465693ecfa9e6153edb1\nmsgid \"\"\n\"A new *config.h* file can be used to de-select unwanted features in the C\"\n\" base code. Using this feature we have been able to reduce the size of \"\n\"our binary *_fitz.o* / *_fitz.pyd* by about 50% (from 9 MB to 4.5 MB). \"\n\"When UPX-ing this, the size goes even further down to a very handy 2.3 \"\n\"MB.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2731 42d66398d41a44a099a22715ab110b6a\nmsgid \"\"\n\"The alpha (transparency) channel for pixmaps is now optional. Letting \"\n\"alpha default to *False* significantly reduces pixmap sizes (by 20% -- \"\n\"CMYK, 25% -- RGB, 50% -- GRAY). Many *Pixmap* constructors therefore now \"\n\"accept an *alpha* boolean to control inclusion of this channel. Other \"\n\"pixmap constructors (e.g. those for file and image input) create pixmaps \"\n\"with no alpha altogether. On the downside, save methods for pixmaps no \"\n\"longer accept a *savealpha* option: this channel will always be saved \"\n\"when present. To minimize code breaks, we have left this parameter in the\"\n\" call patterns -- it will just be ignored.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2733 58b3832200ca448a9f2942f1ec5f30d9\nmsgid \"\"\n\"*DisplayList* and *TextPage* class constructors now **require the \"\n\"mediabox** of the page they are referring to (i.e. the *page.bound()* \"\n\"rectangle). There is no way to construct this information from other \"\n\"sources, therefore a source code change cannot be avoided in these cases.\"\n\" We assume however, that not many users are actually employing these \"\n\"rather low level classes explicitly. So the impact of that change should \"\n\"be minor.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2735 01de368016c141b1b2553cd585883f58\nmsgid \"**Other Changes compared to Version 1.9.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2737 df26434942574d7da8fc1befaf6d049e\nmsgid \"\"\n\"The new :ref:`Document` method *write()* writes an opened PDF to memory \"\n\"(as opposed to a file, like *save()* does).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2738 5190f090e6f84628be18a2e1c9fd43df\nmsgid \"\"\n\"An annotation can now be scaled and moved around on its page. This is \"\n\"done by modifying its rectangle.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2739 0eb2ec9314ee488196226314519b9129\nmsgid \"\"\n\"Annotations can now be deleted. :ref:`Page` contains the new method \"\n\"*deleteAnnot()*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2740 99724b99bd0548eaa19c8c85f41c3b21\nmsgid \"\"\n\"Various annotation attributes can now be modified, e.g. content, dates, \"\n\"title (= author), border, colors.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2741 d958d6b52dd140669174995b9aa48a2c\nmsgid \"\"\n\"Method *Document.insert_pdf()* now also copies annotations of source \"\n\"pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2742 a77b60cbc9834c8885e873395b2e5293\nmsgid \"\"\n\"The *Pages* class has been deleted. As documents can now be accessed with\"\n\" page numbers as indices (like *doc[n] = doc.loadPage(n)*), and document \"\n\"object can be used as iterators, the benefit of this class was too low to\"\n\" maintain it. See the following comments.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2743 8310daf4e1854f8d93f3fccbab7b350f\nmsgid \"\"\n\"*loadPage(n)* / *doc[n]* now accept arbitrary integers to specify a page \"\n\"number, as long as *n < pageCount*. So, e.g. *doc[-500]* is always valid \"\n\"and will load page *(-500) % pageCount*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2744 1204cbb1b1c544fb9e21c114bb1d1ba0\nmsgid \"\"\n\"A document can now also be used as an iterator like this: *for page in \"\n\"doc: ...<do something with \\\"page\\\"> ...*. This will yield all pages of \"\n\"*doc* as *page*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2745 638b89cc45b748c1871ca2d5aead5130\nmsgid \"\"\n\"The :ref:`Pixmap` method *getSize()* has been replaced with property \"\n\"*size*. As before *Pixmap.size == len(Pixmap)* is true.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2746 08362ae590bb4f6d909e17c344eac186\nmsgid \"\"\n\"In response to transparency (alpha) being optional, several new \"\n\"parameters and properties have been added to :ref:`Pixmap` and \"\n\":ref:`Colorspace` classes to support determining their characteristics.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2747 26af3ec444444862b651b0a46668621b\nmsgid \"\"\n\"The :ref:`Page` class now contains new properties *firstAnnot* and \"\n\"*firstLink* to provide starting points to the respective class chains, \"\n\"where *firstLink* is just a mnemonic synonym to method *loadLinks()* \"\n\"which continues to exist. Similarly, the new property *rect* is a synonym\"\n\" for method *bound()*, which also continues to exist.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2748 ded24a5038154723bb3341c82e3cbf85\nmsgid \"\"\n\":ref:`Pixmap` methods *samplesRGB()* and *samplesAlpha()* have been \"\n\"deleted because pixmaps can now be created without transparency.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2749 0f12d21dba014e89b8c28b88440ddf0d\nmsgid \"\"\n\":ref:`Rect` now has a property *irect* which is a synonym of method \"\n\"*round()*. Likewise, :ref:`IRect` now has property *rect* to deliver a \"\n\":ref:`Rect` which has the same coordinates as floats values.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2750 30d1287837f24dc3b01d070c0235a6b3\nmsgid \"\"\n\"Document has the new method *searchPageFor()* to search for a text \"\n\"string. It works exactly like the corresponding *Page.searchFor()* with \"\n\"page number as additional parameter.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2755 efde2cd3f108453c92668ab6680d8c22\nmsgid \"**Changes in Version 1.9.3**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2757 0ea28511a44f47cbabd5e1818b9aa8aa\nmsgid \"\"\n\"This version is also based on MuPDF v1.9a. Changes compared to version \"\n\"1.9.2:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2759 4e290039221648db96c98c392772b446\nmsgid \"\"\n\"As a major enhancement, annotations are now supported in a similar way as\"\n\" links. Annotations can be displayed (as pixmaps) and their properties \"\n\"can be accessed.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2760 9b2336cd5062432881d29cf06440709d\nmsgid \"\"\n\"In addition to the document *select()* method, some simpler methods can \"\n\"now be used to manipulate a PDF:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2762 8d2322bb4a7d4981a30ae2ec5a2cbdb0\nmsgid \"*copyPage()* copies a page within a document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2763 b7683db8abd54cb09161d5edf19f4bd3\nmsgid \"*movePage()* is similar, but deletes the original.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2764 a4c469e758a1452bb9ab330b06d00638\nmsgid \"*delete_page()* deletes a page\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2765 edfd6b26956f4fbfbe96ae5f0b82abd1\nmsgid \"*delete_pages()* deletes a page range\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2767 39a894ab055d4710b6bd443c6df69890\nmsgid \"\"\n\"*rotation* or *setRotation()* access or change a PDF page's rotation, \"\n\"respectively.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2768 4c32f65b4b694d6bb428aa23ca44e50a\nmsgid \"\"\n\"Available but undocumented before, :ref:`IRect`, :ref:`Rect`, \"\n\":ref:`Point` and :ref:`Matrix` support the *len()* method and their \"\n\"coordinate properties can be accessed via indices, e.g. *IRect.x1 == \"\n\"IRect[2]*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2769 f60011476e35442c8866a3831c378b54\nmsgid \"\"\n\"For convenience, documents now support simple indexing: *doc.loadPage(n) \"\n\"== doc[n]*. The index may however be in range *-pageCount < n < \"\n\"pageCount*, such that *doc[-1]* is the last page of the document.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2773 b923307f30254e48ba8f3dfb4835b05a\nmsgid \"**Changes in Version 1.9.2**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2775 6449dd561a1d46078eff4b1c6983b1ae\nmsgid \"\"\n\"This version is also based on MuPDF v1.9a. Changes compared to version \"\n\"1.9.1:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2777 f9a699d3f70e4d6caed1fb3017bf1f0b\nmsgid \"\"\n\"*fitz.open()* (no parameters) creates a new empty **PDF** document, i.e. \"\n\"if saved afterwards, it must be given a *.pdf* extension.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2778 6d6ed72ba57c49cab25dd46b125a7992\nmsgid \"\"\n\":ref:`Document` now accepts all of the following formats (*Document* and \"\n\"*open* are synonyms):\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2780 a3a89203f10e4adeb3cfe637ceb6fdff\nmsgid \"*open()*,\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2781 adac8cae62784b188b7532c740bb1379\nmsgid \"*open(filename)* (equivalent to *open(filename, None)*),\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2782 5d35476e5dcf46248458a566565f6b6f\nmsgid \"*open(filetype, area)* (equivalent to *open(filetype, stream = area)*).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2784 2fdc6dd492a14cc68fa4d2de4e051cfc\nmsgid \"\"\n\"Type of memory area *stream* may be *bytes* or *bytearray*. Thus, e.g. \"\n\"*area = open(\\\"file.pdf\\\", \\\"rb\\\").read()* may be used directly (without \"\n\"first converting it to bytearray).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2785 ad12c912ac3247a4a7c774429b01c39b\nmsgid \"\"\n\"New method *Document.insert_pdf()* (PDFs only) inserts a range of pages \"\n\"from another PDF.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2786 93f16447ec77443ba90329b70366c78f\nmsgid \"\"\n\"*Document* objects doc now support the *len()* function: ``len(doc) == \"\n\"doc.pageCount``.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2787 b9dfdd6106944a0ab643f64882fa6526\nmsgid \"\"\n\"New method *Document.getPageImageList()* creates a list of images used on\"\n\" a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2788 f2906fa3f14c4f93bddbe0029d43681f\nmsgid \"\"\n\"New method *Document.getPageFontList()* creates a list of fonts \"\n\"referenced by a page.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2789 a053e3c6bd69480aa1a4639e8522af69\nmsgid \"\"\n\"New pixmap constructor *fitz.Pixmap(doc, xref)* creates a pixmap based on\"\n\" an opened PDF document and an :data:`xref` number of the image.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2790 9dfdd7f9d9b14e15963c179646bcbbeb\nmsgid \"\"\n\"New pixmap constructor *fitz.Pixmap(cspace, spix)* creates a pixmap as a \"\n\"copy of another one *spix* with the colorspace converted to *cspace*. \"\n\"This works for all colorspace combinations.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2791 2a61334e5c304e09a3efe93e1daf2a53\nmsgid \"\"\n\"Pixmap constructor *fitz.Pixmap(colorspace, width, height, samples)* now \"\n\"allows *samples* to also be *bytes*, not only *bytearray*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2796 b95080e967b24b66ae4b63c42d239889\nmsgid \"**Changes in Version 1.9.1**\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2798 9273e10701d143069e9c0424e4b6bded\nmsgid \"\"\n\"This version of PyMuPDF is based on MuPDF library source code version \"\n\"1.9a published on April 21, 2016.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2800 517fc4042ed6446e9e7457b0f69e8504\nmsgid \"\"\n\"Please have a look at MuPDF's website to see which changes and \"\n\"enhancements are contained herein.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2802 c70db83bdb1d48d198e4344cae4de7b5\nmsgid \"Changes in version 1.9.1 compared to version 1.8.0 are the following:\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2804 0d6385d834804b7d9b0ab1c6ef0d85b8\nmsgid \"New methods *get_area()* for both *fitz.Rect* and *fitz.IRect*\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2805 85fda6915f8c488cb6fbe936f1ea49ab\nmsgid \"\"\n\"Pixmaps can now be created directly from files using the new constructor \"\n\"*fitz.Pixmap(filename)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2806 d92fe0f7f8304a5190d37c53f89f3a24\nmsgid \"The Pixmap constructor *fitz.Pixmap(image)* has been extended accordingly.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2807 cdaceee4b768492e9110c3d0cd75e175\nmsgid \"\"\n\"*fitz.Rect* can now be created with all possible combinations of points \"\n\"and coordinates.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2808 03f45a90666540d8b5cb4c257457b006\nmsgid \"\"\n\"PyMuPDF classes and methods now all contain  __doc__ strings,  most of \"\n\"them created by SWIG automatically. While the PyMuPDF documentation \"\n\"certainly is more detailed, this feature should help a lot when \"\n\"programming in Python-aware IDEs.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2809 2ddafe376f5e4f4e9ac5c3db523eea26\nmsgid \"\"\n\"A new document method of *getPermits()* returns the permissions \"\n\"associated with the current access to the document (print, edit, \"\n\"annotate, copy), as a Python dictionary.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2810 38dbe8d276f348d6b76c6d0a15d0676f\nmsgid \"The identity matrix *fitz.Identity* is now **immutable**.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2811 fa0425c7b7b04f0bb7c04eec634e2756\nmsgid \"\"\n\"The new document method *select(list)* removes all pages from a document \"\n\"that are not contained in the list. Pages can also be duplicated and re-\"\n\"arranged.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2812 3c561ea70df341be88b491b64dc6f313\nmsgid \"\"\n\"Various improvements and new members in our demo and examples \"\n\"collections. Perhaps most prominently: *PDF_display* now supports \"\n\"scrolling with the mouse wheel, and there is a new example program \"\n\"*wxTableExtract* which allows to graphically identify and extract table \"\n\"data in documents.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2813 4d9bea8a8e514d67958c633b66ca31fb\nmsgid \"*fitz.open()* is now an alias of *fitz.Document()*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2814 f62c2e04dea346d0a23964798a6150e8\nmsgid \"\"\n\"New pixmap method *tobytes()* which will return a bytearray formatted as \"\n\"a PNG image of the pixmap.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2815 691532d03793437899a4b59421388b4c\nmsgid \"\"\n\"New pixmap method *samplesRGB()* providing a *samples* version with alpha\"\n\" bytes stripped off (RGB colorspaces only).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2816 2780806eef3f43b28a7e9601a270e9f2\nmsgid \"\"\n\"New pixmap method *samplesAlpha()* providing the alpha bytes only of the \"\n\"*samples* area.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2817 21fbef3bc0e64a59a9a9b9f5005063e8\nmsgid \"New iterator *fitz.Pages(doc)* over a document's set of pages.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2818 707a5edabf3e4c3cbb66ed5d280d40ae\nmsgid \"\"\n\"New matrix methods *invert()* (calculate inverted matrix), *concat()* \"\n\"(calculate matrix product), *pretranslate()* (perform a shift operation).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2819 cc8cea5eaf77474aa84e90031d6f3318\nmsgid \"\"\n\"New *IRect* methods *intersect()* (intersection with another rectangle), \"\n\"*translate()* (perform a shift operation).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2820 893b259908084462b3a1a85629a6ee06\nmsgid \"\"\n\"New *Rect* methods *intersect()* (intersection with another rectangle), \"\n\"*transform()* (transformation with a matrix), *include_point()* (enlarge \"\n\"rectangle to also contain a point), *include_rect()* (enlarge rectangle \"\n\"to also contain another one).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2821 21838e58f15b4457816e55450382ccb9\nmsgid \"Documented *Point.transform()* (transform a point with a matrix).\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2822 3f2842cba4c044eb99d8d250d9f84740\nmsgid \"\"\n\"*Matrix*, *IRect*, *Rect* and *Point* classes now support compact, \"\n\"algebraic formulations for manipulating such objects.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2823 bb13c21e58c14cf59f36e99322166ac4\nmsgid \"\"\n\"Incremental saves for changes are possible now using the call pattern \"\n\"*doc.save(doc.name, incremental=True)*.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2824 34093067a0274622aa66ca0e40f20da0\nmsgid \"\"\n\"A PDF's metadata can now be deleted, set or changed by document method \"\n\"*set_metadata()*. Supports incremental saves.\"\nmsgstr \"\"\n\n#: ../../../changes.txt:2825 0e2f9f83f2244178a0772a7f0de76b0d\nmsgid \"\"\n\"A PDF's bookmarks (or table of contents) can now be deleted, set or \"\n\"changed with the entries of a list using document method *set_toc(list)*.\"\n\" Supports incremental saves.\"\nmsgstr \"\"\n\n#: ../../footer.rst:48 0555f8605d724eadbe65f9eb27755b4f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/classes.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 72d124a4df2940ae91c02b99f3c82423\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 0da5ffd890c841748068ca615eab3107\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 9d0127c5f1f14daa981562792c65c9b5\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../classes.rst:5 fe9040dd12d946768ce0d27a27fdaf3d\nmsgid \"Classes\"\nmsgstr \"클래스\"\n\n#: ../../footer.rst:46 8ffd075421f949e383a9682ed7ae841d\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/colors.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f7f80c710949468b8bd435236ad8e2c4\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 128dbd8ce067437e9fa9367d9a81490c\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 fc29ad4440c04367a8583f77893f5da0\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../colors.rst:7 904c9bd5c37245ada62e1853d3d3ab41\nmsgid \"Color Database\"\nmsgstr \"색상 데이터베이스\"\n\n#: ../../colors.rst:8 3a6a8c4737a04dff80244d2af0ec3eb5\nmsgid \"\"\n\"Since the introduction of methods involving colors (like \"\n\":meth:`Page.draw_circle`), a requirement may be to have access to \"\n\"predefined colors.\"\nmsgstr \":meth:`Page.draw_circle` 과 같은 색상을 포함하는 메서드가 도입된 이후, 미리 정의된 색상에 액세스할 필요가 있을 수 있습니다.\"\n\n#: ../../colors.rst:10 413288a3680f4de18bf71a5e9d578ce4\nmsgid \"\"\n\"The fabulous GUI package `wxPython <https://wxpython.org/>`_ has a \"\n\"database of over 540 predefined RGB colors, which are given more or less \"\n\"memorizable names. Among them are not only standard names like \\\"green\\\" \"\n\"or \\\"blue\\\", but also \\\"turquoise\\\", \\\"skyblue\\\", and 100 (not only 50 \"\n\"...) shades of \\\"gray\\\", etc.\"\nmsgstr \"훌륭한 GUI 패키지 `wxPython <https://wxpython.org/>`_ 는 540개 이상의 미리 정의된 RGB 색상 데이터베이스를 가지고 있으며, 각각 기억하기 쉬운 이름이 부여되어 있습니다. 그 중에는 \\\"green\\\"이나 \\\"blue\\\"와 같은 표준 이름뿐만 아니라 \\\"turquoise\\\", \\\"skyblue\\\", 그리고 \\\"gray\\\"의 100가지(50가지뿐만 아니라...) 음영 등이 포함되어 있습니다.\"\n\n#: ../../colors.rst:12 14609f03f5aa4aaa8e49243c7e03e485\nmsgid \"\"\n\"We have taken the liberty to copy this database (a list of tuples) \"\n\"modified into PyMuPDF and make its colors available as PDF compatible \"\n\"float triples: for wxPython's *(\\\"WHITE\\\", 255, 255, 255)* we return *(1,\"\n\" 1, 1)*, which can be directly used in *color* and *fill* parameters. We \"\n\"also accept any mixed case of \\\"wHiTe\\\" to find a color.\"\nmsgstr \"이 데이터베이스(튜플 목록)를 PyMuPDF로 복사하여 수정하고 색상을 PDF 호환 float 삼중값으로 사용할 수 있게 했습니다: wxPython의 *(\\\"WHITE\\\", 255, 255, 255)* 에 대해 *(1, 1, 1)* 을 반환하며, 이것은 *color* 및 *fill* 매개변수에서 직접 사용할 수 있습니다. 또한 색상을 찾기 위해 \\\"wHiTe\\\"와 같은 대소문자 혼합도 허용합니다.\"\n\n#: ../../colors.rst:15 9ad1f31ffff5428d982d997142d514ed\nmsgid \"Function *getColor()*\"\nmsgstr \"함수 *getColor()*\"\n\n#: ../../colors.rst:16 a622de02c9de4a36be638603c453810c\nmsgid \"\"\n\"As the color database may not be needed very often, one additional import\"\n\" statement seems acceptable to get access to it::\"\nmsgstr \"색상 데이터베이스가 자주 필요하지 않을 수 있으므로, 액세스하기 위해 하나의 추가 import 문이 허용되는 것으로 보입니다::\"\n\n#: ../../colors.rst:41 77d5cf06ffb64791bf093176968e3823\nmsgid \"Printing the Color Database\"\nmsgstr \"색상 데이터베이스 인쇄\"\n\n#: ../../colors.rst:42 671f64b3cd454ac79241e57967a08885\nmsgid \"\"\n\"If you want to actually see how the many available colors look like, use \"\n\"scripts `print by RGB <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/print-rgb/print.py>`_ or `print by HSV \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/print-\"\n\"hsv/print.py>`_ in the examples directory. They create PDFs (already \"\n\"existing in the same directory) with all these colors. Their only \"\n\"difference is sorting order: one takes the RGB values, the other one the \"\n\"Hue-Saturation-Values as sort criteria. This is a screen print of what \"\n\"these files look like.\"\nmsgstr \"실제로 사용 가능한 많은 색상이 어떻게 보이는지 확인하려면 examples 디렉토리의 `RGB로 인쇄 <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/print-rgb/print.py>`_ 또는 `HSV로 인쇄 <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/print-hsv/print.py>`_ 스크립트를 사용하세요. 이들은 이러한 모든 색상이 포함된 PDF를 생성합니다(이미 같은 디렉토리에 존재). 유일한 차이점은 정렬 순서입니다: 하나는 RGB 값을 사용하고 다른 하나는 색상-채도-값을 정렬 기준으로 사용합니다. 이것은 이러한 파일이 어떻게 보이는지에 대한 화면 인쇄입니다.\"\n\n#: ../../footer.rst:46 8a7d56a546234904856ce9f0b72c1614\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/colorspace.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f549435fd225442b88591b9ea748ccf5\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 26942a499b7a445b90c295eca24482e7\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 af615b1043644e81bbff2aaf9a089159\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../colorspace.rst:7 34c209fdd6e340a2957eb63d18046708\nmsgid \"Colorspace\"\nmsgstr \"Colorspace (색 공간)\"\n\n#: ../../colorspace.rst:9 f977d2d374354205a274599236a85e9e\nmsgid \"Represents the color space of a :ref:`Pixmap`.\"\nmsgstr \":ref:`Pixmap` 의 색 공간을 나타냅니다.\"\n\n#: ../../colorspace.rst:12 1b2a1f6f61a04f109833fcd6f2cd89f6\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../colorspace.rst:18 e6633c622a404083816fea39291502e0\nmsgid \"Constructor\"\nmsgstr \"생성자\"\n\n#: ../../colorspace.rst bb53728a68224c1598e93adba7f88d7b\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../colorspace.rst:20 2f9149a75fe74a3ea8f99ed87ca10a79\nmsgid \"\"\n\"A number identifying the colorspace. Possible values are :data:`CS_RGB`, \"\n\":data:`CS_GRAY` and :data:`CS_CMYK`.\"\nmsgstr \"색 공간을 식별하는 숫자. 가능한 값은 :data:`CS_RGB`, :data:`CS_GRAY`, :data:`CS_CMYK` 입니다.\"\n\n#: ../../colorspace.rst:24 68374fc9f8604e2c9f51ccab76cd667f\nmsgid \"\"\n\"The name identifying the colorspace. Example: *pymupdf.csCMYK.name = \"\n\"'DeviceCMYK'*.\"\nmsgstr \"색 공간을 식별하는 이름. 예: *pymupdf.csCMYK.name = 'DeviceCMYK'*.\"\n\n#: ../../colorspace.rst 2b529cfead5f452aa08c4f0889094f2a\n#: de6bc202909d47c1ac4f59fb0cfd08f4\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../colorspace.rst:26 fae8ee7d418c442591c2744e79c8744d\nmsgid \"str\"\nmsgstr \"str\"\n\n#: ../../colorspace.rst:30 c1510ca299d344e599e43a51f294701f\nmsgid \"\"\n\"The number of bytes required to define the color of one pixel. Example: \"\n\"*pymupdf.csCMYK.n == 4*.\"\nmsgstr \"한 픽셀의 색상을 정의하는 데 필요한 바이트 수. 예: *pymupdf.csCMYK.n == 4*.\"\n\n#: ../../colorspace.rst:32 f102b99da0f947f2ad6e51b936a3be73\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../colorspace.rst:35 38447c5856904db38a697c5fbbac7a22\nmsgid \"**Predefined Colorspaces**\"\nmsgstr \"**사전 정의된 색 공간**\"\n\n#: ../../colorspace.rst:37 050d42a00f5a4101af529f195bc8bb1c\nmsgid \"\"\n\"For saving some typing effort, there exist predefined colorspace objects \"\n\"for the three available cases.\"\nmsgstr \"입력을 간소화하기 위해 세 가지 사용 가능한 경우에 대한 사전 정의된 색 공간 객체가 존재합니다.\"\n\n#: ../../colorspace.rst:39 e4c24c0bade34c0893756619c1ebc542\nmsgid \":data:`csRGB`  = *pymupdf.Colorspace(pymupdf.CS_RGB)*\"\nmsgstr \":data:`csRGB`  = *pymupdf.Colorspace(pymupdf.CS_RGB)*\"\n\n#: ../../colorspace.rst:40 2094a63eb7ee45d9ae81e24499dde735\nmsgid \":data:`csGRAY` = *pymupdf.Colorspace(pymupdf.CS_GRAY)*\"\nmsgstr \":data:`csGRAY` = *pymupdf.Colorspace(pymupdf.CS_GRAY)*\"\n\n#: ../../colorspace.rst:41 055f0bfcd886462d9efd42028ac34cf4\nmsgid \":data:`csCMYK` = *pymupdf.Colorspace(pymupdf.CS_CMYK)*\"\nmsgstr \":data:`csCMYK` = *pymupdf.Colorspace(pymupdf.CS_CMYK)*\"\n\n#: ../../footer.rst:46 db2d1460e2e34af68d7315f27089b57f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/converting-files.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f8990f687e0047c89745e6b15ef5f312\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 606c02d809cb449ab8e5df484cb2149f\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 90891c93f09445feb007b8f80d447d93\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../converting-files.rst:7 153e0c6c14bf4b8bac1dcdc565ac0f16\nmsgid \"Converting Files\"\nmsgstr \"파일 변환\"\n\n#: ../../converting-files.rst:12 9b1bc6f3061c4fd9a084829ef7554c37\nmsgid \"Files to PDF\"\nmsgstr \"파일을 PDF로\"\n\n#: ../../converting-files.rst:14 38d5a093dfc24e72b3627f1a2c952515\nmsgid \"\"\n\":ref:`Document types supported by PyMuPDF<HowToOpenAFile>` can easily be \"\n\"converted to |PDF| by using the :meth:`Document.convert_to_pdf` method. \"\n\"This method returns a buffer of data which can then be utilized by \"\n\"|PyMuPDF| to create a new |PDF|.\"\nmsgstr \":ref:`PyMuPDF 가 지원하는 문서 유형<HowToOpenAFile>` 은 :meth:`Document.convert_to_pdf` 메서드를 사용하여 쉽게 |PDF| 로 변환할 수 있습니다. 이 메서드는 데이터 버퍼를 반환하며, 이를 |PyMuPDF| 에서 사용하여 새로운 |PDF| 를 생성할 수 있습니다.\"\n\n#: ../../converting-files.rst:18 ../../converting-files.rst:38\n#: ../../converting-files.rst:62 ../../converting-files.rst:82\n#: 2eff8f1c0f704e9d9e23a98078353847 7345723f19864e81be97447aab194cd9\n#: c3ae18efff164928b70b884d3a47caac ecdbf8cbbb2d46bc9bf312b716b264af\nmsgid \"**Example**\"\nmsgstr \"**예제**\"\n\n#: ../../converting-files.rst:32 4e3eda1d4bff4593ae1f0333bcc47a5d\nmsgid \"PDF to SVG\"\nmsgstr \"PDF를 SVG로\"\n\n#: ../../converting-files.rst:34 d8f0e0e26f99486485d27038482b5558\nmsgid \"\"\n\"Technically, as SVG files cannot be multipage, we must export each page \"\n\"as an SVG.\"\nmsgstr \"기술적으로 SVG 파일은 다중 페이지를 지원하지 않으므로 각 페이지를 SVG로 내보내야 합니다.\"\n\n#: ../../converting-files.rst:36 45efc8839a1b44e9a877335aa51df1b6\nmsgid \"\"\n\"To get an SVG representation of a page use the :meth:`Page.get_svg_image`\"\n\" method.\"\nmsgstr \"페이지의 SVG 표현을 얻으려면 :meth:`Page.get_svg_image` 메서드를 사용하세요.\"\n\n#: ../../converting-files.rst:58 9249883d41654d3c8041c561743679c6\nmsgid \"PDF to Markdown\"\nmsgstr \"PDF를 Markdown으로\"\n\n#: ../../converting-files.rst:60 9d35a0dc74c742419817cfab8ac5fbb6\nmsgid \"\"\n\"By utlilizing the :doc:`PyMuPDF4LLM API <pymupdf4llm/api>` we are able to\"\n\" convert PDF to a Markdown representation.\"\nmsgstr \":doc:`PyMuPDF4LLM API <pymupdf4llm/api>` 를 활용하여 PDF를 Markdown 표현으로 변환할 수 있습니다.\"\n\n#: ../../converting-files.rst:76 a8c608159d57471c89e55f3c44adafe2\nmsgid \"PDF to DOCX\"\nmsgstr \"PDF를 DOCX로\"\n\n#: ../../converting-files.rst:78 443eb3ec0d3a4ba89f8e4361a7607e16\nmsgid \"\"\n\"Use the pdf2docx_ library which uses |PyMuPDF| to provide document \"\n\"conversion from |PDF| to **DOCX** format.\"\nmsgstr \"|PyMuPDF| 를 사용하여 |PDF| 에서 **DOCX** 형식으로 문서 변환을 제공하는 pdf2docx_ 라이브러리를 사용하세요.\"\n\n#: ../../footer.rst:46 bf92de7cbdc140fba9255f9a43b9932a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/coop_low.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 8d754aed1e2740038b917c525f18b9ca\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 48fc1e2d0d4044849ac51203907c3038\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 9455ddb086974d8fbdb10bf9926ee2c2\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../coop_low.rst:7 1424337399114434a5fcad7ec04fb525\nmsgid \"Working together: DisplayList and TextPage\"\nmsgstr \"함께 작업하기: DisplayList 및 TextPage\"\n\n#: ../../coop_low.rst:8 a3db195fac9545f6bcdb871b180a3157\nmsgid \"Here are some instructions on how to use these classes together.\"\nmsgstr \"이러한 클래스를 함께 사용하는 방법에 대한 지침입니다.\"\n\n#: ../../coop_low.rst:10 0151aabe7884411ab744c548ff37a84f\nmsgid \"\"\n\"In some situations, performance improvements may be achievable, when you \"\n\"fall back to the detail level explained here.\"\nmsgstr \"일부 상황에서는 여기서 설명하는 세부 수준으로 돌아가면 성능 개선을 달성할 수 있습니다.\"\n\n#: ../../coop_low.rst:13 54d7972a1340441eaea756f718523d0b\nmsgid \"Create a DisplayList\"\nmsgstr \"DisplayList 생성\"\n\n#: ../../coop_low.rst:14 c98d7572988c49e6a0b6a9e9719d1774\nmsgid \"\"\n\"A :ref:`DisplayList` represents an interpreted document page. Methods for\"\n\" pixmap creation, text extraction and text search are  -- behind the \"\n\"curtain -- all using the page's display list to perform their tasks. If a\"\n\" page must be rendered several times (e.g. because of changed zoom \"\n\"levels), or if text search and text extraction should both be performed, \"\n\"overhead can be saved, if the display list is created only once and then \"\n\"used for all other tasks.\"\nmsgstr \":ref:`DisplayList` 는 해석된 문서 페이지를 나타냅니다. 픽스맵 생성, 텍스트 추출 및 텍스트 검색 메서드는 모두 -- 배후에서 -- 페이지의 디스플레이 리스트를 사용하여 작업을 수행합니다. 페이지를 여러 번 렌더링해야 하거나(예: 확대/축소 수준 변경), 텍스트 검색과 텍스트 추출을 모두 수행해야 하는 경우, 디스플레이 리스트를 한 번만 생성한 다음 다른 모든 작업에 사용하면 오버헤드를 절약할 수 있습니다.\"\n\n#: ../../coop_low.rst:18 4e74ccb447ad4e808e44350168bf55d2\nmsgid \"\"\n\"You can also create display lists for many pages \\\"on stack\\\" (in a \"\n\"list), may be during document open, during idling times, or you store it \"\n\"when a page is visited for the first time (e.g. in GUI scripts).\"\nmsgstr \"여러 페이지에 대한 디스플레이 리스트를 \\\"스택에\\\"(리스트에) 생성할 수도 있습니다. 문서를 열 때, 유휴 시간 동안, 또는 페이지를 처음 방문할 때(예: GUI 스크립트) 저장할 수 있습니다.\"\n\n#: ../../coop_low.rst:20 12bb2e8c763e4ad3a237fd80266a2543\nmsgid \"\"\n\"Note, that for everything what follows, only the display list is needed \"\n\"-- the corresponding :ref:`Page` object could have been deleted.\"\nmsgstr \"다음의 모든 작업에는 디스플레이 리스트만 필요합니다. 해당 :ref:`Page` 객체는 삭제되었을 수 있습니다.\"\n\n#: ../../coop_low.rst:23 686688813b8745b284b6d509397757da\nmsgid \"Generate Pixmap\"\nmsgstr \"픽스맵 생성\"\n\n#: ../../coop_low.rst:24 d5a176c44d9a4202a1247dbea491d65e\nmsgid \"\"\n\"The following creates a Pixmap from a :ref:`DisplayList`. Parameters are \"\n\"the same as for :meth:`Page.get_pixmap`.\"\nmsgstr \"다음은 :ref:`DisplayList` 에서 픽스맵을 생성합니다. 매개변수는 :meth:`Page.get_pixmap` 과 동일합니다.\"\n\n#: ../../coop_low.rst:28 141a5838b45c4b229d3aa4b5d32e29e6\n#, python-format\nmsgid \"\"\n\"The execution time of this statement may be up to 50% shorter than that \"\n\"of :meth:`Page.get_pixmap`.\"\nmsgstr \"이 문의 실행 시간은 :meth:`Page.get_pixmap` 보다 최대 50% 짧을 수 있습니다.\"\n\n#: ../../coop_low.rst:31 23be506420454ef7b8ccdcabdadf9684\nmsgid \"Perform Text Search\"\nmsgstr \"텍스트 검색 수행\"\n\n#: ../../coop_low.rst:32 304eb217224047588efee4d3a4959ad2\nmsgid \"With the display list from above, we can also search for text.\"\nmsgstr \"위의 디스플레이 리스트를 사용하여 텍스트를 검색할 수도 있습니다.\"\n\n#: ../../coop_low.rst:34 6f3c8ea4c8134e719b9c2c789a52eaf5\nmsgid \"For this we need to create a :ref:`TextPage`.\"\nmsgstr \"이를 위해 :ref:`TextPage` 를 생성해야 합니다.\"\n\n#: ../../coop_low.rst:42 702318fa16304e26a6dbff34f1f56e8c\nmsgid \"Extract Text\"\nmsgstr \"텍스트 추출\"\n\n#: ../../coop_low.rst:43 50018abeea15456b936054a8e8301808\nmsgid \"\"\n\"With the same :ref:`TextPage` object from above, we can now immediately \"\n\"use any or all of the 5 text extraction methods.\"\nmsgstr \"위의 동일한 :ref:`TextPage` 객체를 사용하여 이제 5가지 텍스트 추출 메서드 중 하나 또는 모두를 즉시 사용할 수 있습니다.\"\n\n#: ../../coop_low.rst:45 01c692d0961a48d78607d7cdef1b8734\nmsgid \"\"\n\"Above, we have created our text page without argument. This leads to a \"\n\"default argument of 3 (:data:`ligatures` and white-space are preserved), \"\n\"IAW images will **not** be extracted -- see below.\"\nmsgstr \"위에서 인수 없이 텍스트 페이지를 생성했습니다. 이것은 기본 인수 3(:data:`ligatures` 및 공백이 보존됨)으로 이어지며, 즉 이미지는 **추출되지 않습니다** -- 아래를 참조하세요.\"\n\n#: ../../coop_low.rst:54 15150223bde3445b8a3ddc5a334745ce\nmsgid \"Further Performance improvements\"\nmsgstr \"추가 성능 개선\"\n\n#: ../../coop_low.rst:56 815c6e2e62894b99850c2da374681e5c\nmsgid \"Pixmap\"\nmsgstr \"픽스맵\"\n\n#: ../../coop_low.rst:57 5fa23435785d41b3aa98150e549e6a24\nmsgid \"As explained in the :ref:`Page` chapter:\"\nmsgstr \":ref:`Page` 장에서 설명한 대로:\"\n\n#: ../../coop_low.rst:59 d7489842cfb34a66b6decf4e2c4626a6\n#, python-format\nmsgid \"\"\n\"If you do not need transparency set *alpha = 0* when creating pixmaps. \"\n\"This will save 25% memory (if RGB, the most common case) and possibly 5% \"\n\"execution time (depending on the GUI software).\"\nmsgstr \"투명도가 필요하지 않으면 픽스맵을 생성할 때 *alpha = 0* 을 설정하세요. 이것은 25%의 메모리를 절약하고(RGB인 경우, 가장 일반적인 경우) GUI 소프트웨어에 따라 실행 시간을 약 5% 절약할 수 있습니다.\"\n\n#: ../../coop_low.rst:62 85b6f710f9d440e6a4e7167325c704a1\nmsgid \"TextPage\"\nmsgstr \"TextPage\"\n\n#: ../../coop_low.rst:63 eacc58b3ec3b4895b3defc1f4a0cff2b\nmsgid \"\"\n\"If you do not need images extracted alongside the text of a page, you can\"\n\" set the following option:\"\nmsgstr \"페이지의 텍스트와 함께 이미지를 추출할 필요가 없으면 다음 옵션을 설정할 수 있습니다:\"\n\n#: ../../coop_low.rst:68 494f5310e02d4bc18d9d3742d80c9a1d\n#, python-format\nmsgid \"\"\n\"This will save ca. 25% overall execution time for the HTML, XHTML and \"\n\"JSON text extractions and **hugely** reduce the amount of storage (both, \"\n\"memory and disk space) if the document is graphics oriented.\"\nmsgstr \"이것은 HTML, XHTML 및 JSON 텍스트 추출의 전체 실행 시간을 약 25% 절약하고, 문서가 그래픽 지향적인 경우 스토리지(메모리 및 디스크 공간 모두)의 양을 **대폭** 줄입니다.\"\n\n#: ../../coop_low.rst:70 c7b5ac2b784947f6a4bd325d1474f9b8\nmsgid \"If you however do need images, use a value of 7 for flags:\"\nmsgstr \"하지만 이미지가 필요한 경우 플래그에 7 값을 사용하세요:\"\n\n#: ../../footer.rst:46 74ed18ccd6ca45b28e31f30369c051a8\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/device.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 db41752d7d77475b91dce6987192b03e\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 9d1395b42c0242c2937c063ec31289da\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 c674fa9ee73a4fcf888b701a69a14f4a\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../device.rst:7 d8f699f2197d4cccb1a32e36349536c8\nmsgid \"Device\"\nmsgstr \"Device (디바이스)\"\n\n#: ../../device.rst:9 c03889a987f445ea84d79f3d5abfb84d\nmsgid \"\"\n\"The different format handlers (pdf, xps, etc.) interpret pages to a \"\n\"\\\"device\\\". Devices are the basis for everything that can be done with a \"\n\"page: rendering, text extraction and searching. The device type is \"\n\"determined by the selected construction method.\"\nmsgstr \"다양한 형식 핸들러(pdf, xps 등)는 페이지를 \\\"디바이스\\\"로 해석합니다. 디바이스는 페이지로 수행할 수 있는 모든 작업(렌더링, 텍스트 추출, 검색)의 기반입니다. 디바이스 유형은 선택한 생성 방법에 의해 결정됩니다.\"\n\n#: ../../device.rst:11 5997f573701045499919ec1f18ab7518\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../device.rst:17 4b9fd079e127474e94506fe9eadb79d7\nmsgid \"Constructor for either a pixel map or a display list device.\"\nmsgstr \"픽셀 맵 또는 디스플레이 리스트 디바이스의 생성자.\"\n\n#: ../../device.rst 3029384c54544ad783072064ea96675d\n#: ca7a504aacc440719aba0931b7724c60\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../device.rst:19 9b095106055b4d568344ac7d142034f3\nmsgid \"either a ``Pixmap`` or  a ``DisplayList``.\"\nmsgstr \"``Pixmap`` 또는 ``DisplayList`` 중 하나.\"\n\n#: ../../device.rst:22 30003de713004e58977091af11644238\nmsgid \"\"\n\"An optional `IRect` for ``Pixmap`` devices to restrict rendering to a \"\n\"certain area of the page. If the complete page is required, specify \"\n\"``None``. For display list devices, this parameter must be omitted.\"\nmsgstr \"``Pixmap`` 디바이스의 선택적 `IRect` 로, 페이지의 특정 영역으로 렌더링을 제한합니다. 전체 페이지가 필요한 경우 ``None`` 을 지정하세요. 디스플레이 리스트 디바이스의 경우 이 매개변수는 생략해야 합니다.\"\n\n#: ../../device.rst:27 5a3223623124424ba115721d21086469\nmsgid \"Constructor for a text page device.\"\nmsgstr \"텍스트 페이지 디바이스의 생성자.\"\n\n#: ../../device.rst:29 8f77a7687a804d458ddb9a4be4624d77\nmsgid \"``TextPage`` object\"\nmsgstr \"``TextPage`` 객체\"\n\n#: ../../device.rst:32 53c8b35c8b0e4e488b05cfbe1c988a0d\nmsgid \"\"\n\"control the way how text is parsed into the text page. Currently 3 \"\n\"options can be coded into this parameter, see :ref:`TextPreserve`. To set\"\n\" these options use something like `flags=0 | TEXT_PRESERVE_LIGATURES | \"\n\"...`.\"\nmsgstr \"텍스트가 텍스트 페이지로 파싱되는 방식을 제어하는 플래그입니다. 현재 3가지 옵션을 이 매개변수에 코딩할 수 있으며, :ref:`TextPreserve` 를 참조하세요. 이러한 옵션을 설정하려면 `flags=0 | TEXT_PRESERVE_LIGATURES | ...` 와 같은 형식을 사용하세요.\"\n\n#: ../../footer.rst:46 233763b8ff7c42718f2a5b6285c3802f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/displaylist.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ff003cfb5c0b4ca9ba474a0f6e3841c2\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 c536d6f0052e4f9cbf11534486001461\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 2b6c43a92fad451db1603199ddd7c294\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../displaylist.rst:7 698bbcf656244694aa96f09767a54aa5\nmsgid \"DisplayList\"\nmsgstr \"DisplayList (디스플레이 리스트)\"\n\n#: ../../displaylist.rst:9 2b6a249a9e6a46a482202e8b105e8ddc\nmsgid \"\"\n\"DisplayList is a list containing drawing commands (text, images, etc.). \"\n\"The intent is two-fold:\"\nmsgstr \"DisplayList는 그리기 명령(텍스트, 이미지 등)을 포함하는 리스트입니다. 목적은 두 가지입니다:\"\n\n#: ../../displaylist.rst:11 01de3b874c654c729617cd5a69c98a06\nmsgid \"as a caching-mechanism to reduce parsing of a page\"\nmsgstr \"페이지 파싱을 줄이기 위한 캐싱 메커니즘으로\"\n\n#: ../../displaylist.rst:12 e47cc33899c24e9b8b48607d9cc55aca\nmsgid \"\"\n\"as a data structure in multi-threading setups, where one thread parses \"\n\"the page and another one renders pages. This aspect is currently not \"\n\"supported by PyMuPDF.\"\nmsgstr \"멀티스레딩 설정에서 데이터 구조로, 한 스레드는 페이지를 파싱하고 다른 스레드는 페이지를 렌더링합니다. 이 측면은 현재 PyMuPDF에서 지원되지 않습니다.\"\n\n#: ../../displaylist.rst:14 ff6ed96e5e434d9ab8b7c046b2b5b89e\nmsgid \"\"\n\"A display list is populated with objects from a page, usually by \"\n\"executing :meth:`Page.get_displaylist`. There also exists an independent \"\n\"constructor.\"\nmsgstr \"디스플레이 리스트는 일반적으로 :meth:`Page.get_displaylist` 를 실행하여 페이지의 객체로 채워집니다. 독립적인 생성자도 존재합니다.\"\n\n#: ../../displaylist.rst:16 66dc12118dd1430c91493428b6adb3ca\nmsgid \"\"\n\"\\\"Replay\\\" the list (once or many times) by invoking one of its methods \"\n\":meth:`~DisplayList.run`, :meth:`~DisplayList.get_pixmap` or \"\n\":meth:`~DisplayList.get_textpage`.\"\nmsgstr \"리스트를 \\\"재생\\\"하려면(한 번 또는 여러 번) 메서드 중 하나인 :meth:`~DisplayList.run`, :meth:`~DisplayList.get_pixmap` 또는 :meth:`~DisplayList.get_textpage` 를 호출하세요.\"\n\n#: ../../displaylist.rst:20 c6df8741dd9746c4849b6615f4787387\nmsgid \"**Method**\"\nmsgstr \"**메서드**\"\n\n#: ../../displaylist.rst:20 7f551f0499df4df7ad355142c819deef\nmsgid \"**Short Description**\"\nmsgstr \"**간략 설명**\"\n\n#: ../../displaylist.rst:22 81094ba0fcee4f3dac4c1d13adccd9d9\nmsgid \":meth:`~DisplayList.run`\"\nmsgstr \":meth:`~DisplayList.run`\"\n\n#: ../../displaylist.rst:22 790d819aba1b4a4e89cf7059456f3be1\nmsgid \"Run a display list through a device.\"\nmsgstr \"디스플레이 리스트를 디바이스를 통해 실행합니다.\"\n\n#: ../../displaylist.rst:23 c12a3766ae42430fadfe30df077ebef7\nmsgid \":meth:`~DisplayList.get_pixmap`\"\nmsgstr \":meth:`~DisplayList.get_pixmap`\"\n\n#: ../../displaylist.rst:23 a2c2be7f9085440cb858e4a52c0253c3\nmsgid \"generate a pixmap\"\nmsgstr \"픽스맵 생성\"\n\n#: ../../displaylist.rst:24 2e841e7218aa459b955f952f63f85c7f\nmsgid \":meth:`~DisplayList.get_textpage`\"\nmsgstr \":meth:`~DisplayList.get_textpage`\"\n\n#: ../../displaylist.rst:24 4b5a1849844142eba8b0e00c4ea85c1b\nmsgid \"generate a text page\"\nmsgstr \"텍스트 페이지 생성\"\n\n#: ../../displaylist.rst:25 e7f6a71e64b144b2bb150227a7b7183b\nmsgid \":attr:`~DisplayList.rect`\"\nmsgstr \":attr:`~DisplayList.rect`\"\n\n#: ../../displaylist.rst:25 205d05395d674e39a9e4f0e958d3d06f\nmsgid \"mediabox of the display list\"\nmsgstr \"디스플레이 리스트의 mediabox\"\n\n#: ../../displaylist.rst:29 4a42cea626fe4460b70834ce0af2a4ef\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../displaylist.rst:35 9e9d57cb314843a081adb93c9240ac5f\nmsgid \"Create a new display list.\"\nmsgstr \"새 디스플레이 리스트를 생성합니다.\"\n\n#: ../../displaylist.rst 02a4c577c3194a778a9d75f67212861e\n#: 27616f064af541208365c4cf3260036b 27eb0863e4044881b0a7ef37d0114e28\n#: d4d3d713dc85432f9ebc95eac1f51a09\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../displaylist.rst:37 06aebf2ce5d941adbb8e7aa50ae0b2b8\nmsgid \"The page's rectangle.\"\nmsgstr \"페이지의 사각형.\"\n\n#: ../../displaylist.rst 3e56029375ab4b639b13a2bd6b5dc316\n#: a18c2d343b454f2bb564792a3fc55a17 d0a557e9eef6429c8aa58d2cbac510a6\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../displaylist.rst:40 b8ad61a1e5a44b7587e9e889a0f7b29a\nmsgid \"``DisplayList``\"\nmsgstr \"``DisplayList``\"\n\n#: ../../displaylist.rst:44 ce5a41193477481c88976a823b4ad9d6\nmsgid \"\"\n\"Run the display list through a device. The device will populate the \"\n\"display list with its \\\"commands\\\" (i.e. text extraction or image \"\n\"creation). The display list can later be used to \\\"read\\\" a page many \"\n\"times without having to re-interpret it from the document file.\"\nmsgstr \"디스플레이 리스트를 디바이스를 통해 실행합니다. 디바이스는 디스플레이 리스트를 \\\"명령\\\"(즉, 텍스트 추출 또는 이미지 생성)으로 채웁니다. 디스플레이 리스트는 나중에 문서 파일에서 다시 해석할 필요 없이 페이지를 여러 번 \\\"읽는\\\" 데 사용할 수 있습니다.\"\n\n#: ../../displaylist.rst:46 2dc2aba3d46f4fc4a7820028e1a60253\nmsgid \"\"\n\"You will most probably instead use one of the specialized run methods \"\n\"below -- :meth:`get_pixmap` or :meth:`get_textpage`.\"\nmsgstr \"아래의 특수화된 실행 메서드 중 하나를 사용하는 것이 좋습니다 -- :meth:`get_pixmap` 또는 :meth:`get_textpage`.\"\n\n#: ../../displaylist.rst:48 6e70c4b85f91448c9a7c98c37c0a0ae4\nmsgid \"Device\"\nmsgstr \"Device\"\n\n#: ../../displaylist.rst:51 2f667d2e56bf4e01898f21ff9eb28571\nmsgid \"Transformation matrix to apply to the display list contents.\"\nmsgstr \"디스플레이 리스트 콘텐츠에 적용할 변환 행렬.\"\n\n#: ../../displaylist.rst:54 b64884bb37bd4618a66990bf4733f646\nmsgid \"\"\n\"Only the part visible within this area will be considered when the list \"\n\"is run through the device.\"\nmsgstr \"리스트가 디바이스를 통해 실행될 때 이 영역 내에서 보이는 부분만 고려됩니다.\"\n\n#: ../../displaylist.rst:65 ab527e51c453471f9f60eedf09b9d087\nmsgid \"Run the display list through a draw device and return a pixmap.\"\nmsgstr \"디스플레이 리스트를 그리기 디바이스를 통해 실행하고 픽스맵을 반환합니다.\"\n\n#: ../../displaylist.rst:67 61769985d519468490018723da292d0a\nmsgid \"matrix to use. Default is the identity matrix.\"\nmsgstr \"사용할 행렬. 기본값은 항등 행렬입니다.\"\n\n#: ../../displaylist.rst:70 5932c2f43fdd4b4c8a0f5d2d7c994379\nmsgid \"the desired colorspace. Default is RGB.\"\nmsgstr \"원하는 색 공간. 기본값은 RGB입니다.\"\n\n#: ../../displaylist.rst:73 fbab40e0ab2c491e9dfb956c94981baa\nmsgid \"determine whether or not (0, default) to include a transparency channel.\"\nmsgstr \"투명도 채널을 포함할지 여부를 결정합니다(0, 기본값은 포함하지 않음).\"\n\n#: ../../displaylist.rst:75 466d20a9e3a74fb78536c5cce52c0423\nmsgid \"\"\n\"restrict rendering to the intersection of this area with \"\n\":attr:`DisplayList.rect`.\"\nmsgstr \":attr:`DisplayList.rect` 와 이 영역의 교집합으로 렌더링을 제한합니다.\"\n\n#: ../../displaylist.rst:77 757d1f9a21b041c6ae4ed0b958ce457b\nmsgid \":ref:`Pixmap`\"\nmsgstr \":ref:`Pixmap`\"\n\n#: ../../displaylist.rst 65ed81ab27df4ce49e030837b6f76d44\n#: bc2f03674971487f858250a2cbe58732\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../displaylist.rst:78 ea8ff1cc1cdf40caa3e75151ca6cb92c\nmsgid \"pixmap of the display list.\"\nmsgstr \"디스플레이 리스트의 픽스맵.\"\n\n#: ../../displaylist.rst:82 f854adb186fc469aa47d5bd62e907d4d\nmsgid \"Run the display list through a text device and return a text page.\"\nmsgstr \"디스플레이 리스트를 텍스트 디바이스를 통해 실행하고 텍스트 페이지를 반환합니다.\"\n\n#: ../../displaylist.rst:84 a9b235a2d522430c93c09a55cb019b92\nmsgid \"\"\n\"control which information is parsed into a text page. Default value in \"\n\"PyMuPDF is `3 = TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE`, i.e.\"\n\" :data:`ligatures` are **passed through**, white spaces are **passed \"\n\"through** (not translated to spaces), and images are **not included**. \"\n\"See :ref:`TextPreserve`.\"\nmsgstr \"텍스트 페이지로 파싱되는 정보를 제어하는 플래그입니다. PyMuPDF의 기본값은 `3 = TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE` 입니다. 즉, :data:`ligatures` 는 **그대로 전달** 되고, 공백은 **그대로 전달** 되며(공백으로 변환되지 않음), 이미지는 **포함되지 않습니다**. :ref:`TextPreserve` 를 참조하세요.\"\n\n#: ../../displaylist.rst:86 daf0b2be9b6a4376b53e036006a9a7e3\nmsgid \":ref:`TextPage`\"\nmsgstr \":ref:`TextPage`\"\n\n#: ../../displaylist.rst:87 4d6cd4f91f0e4964b02aad9a3db2ad8a\nmsgid \"text page of the display list.\"\nmsgstr \"디스플레이 리스트의 텍스트 페이지.\"\n\n#: ../../displaylist.rst:91 e4d71370db2d4368b08b17d8436d7747\nmsgid \"\"\n\"Contains the display list's mediabox. This will equal the page's \"\n\"rectangle if it was created via :meth:`Page.get_displaylist`.\"\nmsgstr \"디스플레이 리스트의 mediabox를 포함합니다. :meth:`Page.get_displaylist` 를 통해 생성된 경우 페이지의 사각형과 같습니다.\"\n\n#: ../../displaylist.rst 0b6e65f6961f4c6b9882f9b9dfe93154\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../displaylist.rst:93 f277dc21a3714454ae8f4cf4f1e5113d\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../footer.rst:46 e683ef7401754f0d941d78c8c96788e0\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/document-writer-class.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b5b4277baa2f45589bb33213fe28d133\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 99651177bb7e45218e911de8509ad3d7\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 bfa8a6eb19134fd5a3ed2f7ff3e5a66b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../document-writer-class.rst:7 9ec19dc1ee5e4333ada6ca4a81b20c76\nmsgid \"DocumentWriter\"\nmsgstr \"DocumentWriter\"\n\n#: ../../document-writer-class.rst:9 a8428a7a09fa4d84ba14e57e1cd9933c\nmsgid \"|pdf_only_class|\"\nmsgstr \"|pdf_only_class|\"\n\n#: ../../document-writer-class.rst:12 fdd84ae0909a4d88bcdceeefa2b39965\nmsgid \"New in v1.21.0\"\nmsgstr \"v1.21.0의 새로운 기능\"\n\n#: ../../document-writer-class.rst:14 2d81b86330d54196bb5037872069be5e\nmsgid \"\"\n\"This class represents a utility which can output various :ref:`document \"\n\"types supported by PyMuPDF<Supported_File_Types>`.\"\nmsgstr \"이 클래스는 |PyMuPDF| 가 :ref:`지원하는 다양한 문서 유형<Supported_File_Types>` 을 출력할 수 있는 유틸리티를 나타냅니다.\"\n\n#: ../../document-writer-class.rst:16 f752c28f5ed14d28b92bcff7e31a12f8\nmsgid \"\"\n\"In |PyMuPDF| only used for outputting PDF documents whose pages are \"\n\"populated by :ref:`Story` DOMs.\"\nmsgstr \"|PyMuPDF| 에서는 :ref:`Story` DOM으로 페이지가 채워진 PDF 문서를 출력하는 데만 사용됩니다.\"\n\n#: ../../document-writer-class.rst:18 a51f0f40cbb0442f86dc705ad1fa8132\nmsgid \"\"\n\"Using DocumentWriter_ also for other document types might happen in the \"\n\"future.\"\nmsgstr \"DocumentWriter_ 를 다른 문서 유형에도 사용하는 것은 향후 가능할 수 있습니다.\"\n\n#: ../../document-writer-class.rst:21 8c16e93aa1ce4c6e89c38ba3555943a2\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../document-writer-class.rst:21 078570c061cc494ab88a122d6f975a13\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../document-writer-class.rst:23 e28aaeaab2de42e2be303102f8816b38\nmsgid \":meth:`DocumentWriter.begin_page`\"\nmsgstr \":meth:`DocumentWriter.begin_page`\"\n\n#: ../../document-writer-class.rst:23 46462fa63c0f497ca2b40e3aa34b103a\nmsgid \"start a new output page\"\nmsgstr \"새 출력 페이지 시작\"\n\n#: ../../document-writer-class.rst:24 3fb4972774e64633aeb1fa920d332d0b\nmsgid \":meth:`DocumentWriter.end_page`\"\nmsgstr \":meth:`DocumentWriter.end_page`\"\n\n#: ../../document-writer-class.rst:24 deca462b344444baaba815c62c4ccf49\nmsgid \"finish the current output page\"\nmsgstr \"현재 출력 페이지 완료\"\n\n#: ../../document-writer-class.rst:25 e80c1d8e184c453bbec00d4725057371\nmsgid \":meth:`DocumentWriter.close`\"\nmsgstr \":meth:`DocumentWriter.close`\"\n\n#: ../../document-writer-class.rst:25 82b604112a0849018b6017d0b48a269a\nmsgid \"flush pending output and close the file\"\nmsgstr \"대기 중인 출력을 플러시하고 파일 닫기\"\n\n#: ../../document-writer-class.rst:28 77d9bb485f4345bc9066ac6cbf59d8a9\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../document-writer-class.rst:34 ae20c5fbdb154f71a4aa713c0690c587\nmsgid \"\"\n\"Create a document writer object, passing a Python file pointer or a file \"\n\"path. Options to use when saving the file may also be passed.\"\nmsgstr \"Python 파일 포인터 또는 파일 경로를 전달하여 문서 작성자 객체를 생성합니다. 파일을 저장할 때 사용할 옵션도 전달할 수 있습니다.\"\n\n#: ../../document-writer-class.rst:36 6124d2357c6a4781a34eddaaf0ca7dfa\nmsgid \"This class can also be used as a Python context manager.\"\nmsgstr \"이 클래스는 Python 컨텍스트 관리자로도 사용할 수 있습니다.\"\n\n#: ../../document-writer-class.rst d2e1469751bd4c2e8536b3688da9abc9\n#: e1457a30002847edb1dba253d238fc76\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../document-writer-class.rst:38 3fd7620d0e854ab3bc313135cc0b7a22\nmsgid \"\"\n\"the output file. This may be a string file name, or any Python file \"\n\"pointer.  .. note:: By using a `io.BytesIO()` object as file pointer, a \"\n\"document writer can create a PDF in memory. Subsequently, this PDF can be\"\n\" re-opened for input and be further manipulated. This technique is used \"\n\"by several example scripts in :ref:`Stories recipes<RecipesStories>`.\"\nmsgstr \"\"\n\n#: ../../document-writer-class.rst:38 8206476585d647538a060a35c0be1961\nmsgid \"\"\n\"the output file. This may be a string file name, or any Python file \"\n\"pointer.\"\nmsgstr \"출력 파일. 이것은 문자열 파일 이름이거나 모든 Python 파일 포인터일 수 있습니다.\"\n\n#: ../../document-writer-class.rst:40 5cc894a076804ce4bbaf88cd575d9067\nmsgid \"\"\n\"By using a `io.BytesIO()` object as file pointer, a document writer can \"\n\"create a PDF in memory. Subsequently, this PDF can be re-opened for input\"\n\" and be further manipulated. This technique is used by several example \"\n\"scripts in :ref:`Stories recipes<RecipesStories>`.\"\nmsgstr \"`io.BytesIO()` 객체를 파일 포인터로 사용하면 문서 작성자가 메모리에서 PDF를 생성할 수 있습니다. 그런 다음 이 PDF를 입력용으로 다시 열고 추가로 조작할 수 있습니다. 이 기술은 :ref:`Stories recipes<RecipesStories>` 의 여러 예제 스크립트에서 사용됩니다.\"\n\n#: ../../document-writer-class.rst:42 8e2b505af0b34fec888ef183d42bc55a\nmsgid \"\"\n\"specify saving options for the output PDF. Typical are \\\"compress\\\" or \"\n\"\\\"clean\\\". More possible values may be taken from help output of the \"\n\"`mutool convert` CLI utility.\"\nmsgstr \"출력 PDF의 저장 옵션을 지정합니다. 일반적인 옵션은 \\\"compress\\\" 또는 \\\"clean\\\"입니다. 더 많은 가능한 값은 `mutool convert` CLI 유틸리티의 도움말 출력에서 가져올 수 있습니다.\"\n\n#: ../../document-writer-class.rst:46 f4aad7b430d043e1af763b51fe58f1be\nmsgid \"Start a new output page of a given dimension.\"\nmsgstr \"주어진 크기의 새 출력 페이지를 시작합니다.\"\n\n#: ../../document-writer-class.rst:48 d97df503773b4b5d804d95f381624a79\nmsgid \"\"\n\"a rectangle specifying the page size. After this method, output \"\n\"operations may write content to the page.\"\nmsgstr \"페이지 크기를 지정하는 사각형. 이 메서드 후에 출력 작업이 페이지에 콘텐츠를 쓸 수 있습니다.\"\n\n#: ../../document-writer-class.rst:52 3357a3e14b5c4681a572cf35f2056a51\nmsgid \"\"\n\"Finish a page. This flushes any pending data and appends the page to the \"\n\"output document.\"\nmsgstr \"페이지를 완료합니다. 이것은 대기 중인 모든 데이터를 플러시하고 페이지를 출력 문서에 추가합니다.\"\n\n#: ../../document-writer-class.rst:56 b42cc189417341c8939b89cb1ea93a07\nmsgid \"\"\n\"Close the output file. This method is required for writing any pending \"\n\"data.\"\nmsgstr \"출력 파일을 닫습니다. 대기 중인 데이터를 쓰려면 이 메서드가 필요합니다.\"\n\n#: ../../document-writer-class.rst:58 f5b95d821dfe45629904bb96a9fb09e4\nmsgid \"For usage examples consult the section of :ref:`Story`.\"\nmsgstr \"사용 예제는 :ref:`Story` 섹션을 참조하세요.\"\n\n#: ../../footer.rst:46 de69d88972544cf695683e1f78897d93\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/document.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-03 09:30+0900\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../header.rst:-1 44ccd9af706d4fd09cbe79b42e629a20\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 70ca2976f112470bb748e32924a487bd\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF(및 기타) 문서의 데이터 추출, 분석, 변환 및 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 81b4037c4ad64026a570bc64aa3b9ddb\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../document.rst:7 6f9364c2520544c89caa6bccb4ace73d\nmsgid \"Document\"\nmsgstr \"Document\"\n\n#: ../../document.rst:11 b64bcbba58e84c91858551ce23f6e170\nmsgid \"\"\n\"This class represents a document. It can be constructed from a file or \"\n\"from memory.\"\nmsgstr \"이 클래스는 문서를 나타냅니다. 파일 또는 메모리에서 생성할 수 있습니다.\"\n\n#: ../../document.rst:13 c5a7eb078446487baf15439ed4463a67\nmsgid \"\"\n\"There exists the alias *open* for this class, i.e. \"\n\"`pymupdf.Document(...)` and `pymupdf.open(...)` do exactly the same \"\n\"thing.\"\nmsgstr \"\"\n\"이 클래스에는 *open* 별칭이 있습니다. 즉, `pymupdf.Document(...)` 와 `pymupdf.open(...)`\"\n\" 는 정확히 동일한 작업을 수행합니다.\"\n\n#: ../../document.rst:15 e66711c1a68c4bcb99c4a34100a14cd1\nmsgid \"For details on **embedded files** refer to Appendix 3.\"\nmsgstr \"**임베디드 파일** 에 대한 자세한 내용은 부록 3을 참조하세요.\"\n\n#: ../../document.rst:19 26f0b72a907b4767b496b9a50b705cb7\nmsgid \"\"\n\"Starting with v1.17.0, a new page addressing mechanism for **EPUB files \"\n\"only** is supported. This document type is internally organized in \"\n\"chapters such that pages can most efficiently be found by their so-called\"\n\" \\\"location\\\". The location is a tuple *(chapter, pno)* consisting of the\"\n\" chapter number and the page number **in that chapter**. Both numbers are\"\n\" zero-based.\"\nmsgstr \"\"\n\"v1.17.0부터 **EPUB 파일 전용** 새로운 페이지 주소 지정 메커니즘이 지원됩니다. 이 문서 타입은 내부적으로 장으로 \"\n\"구성되어 있어 페이지를 소위 \\\"location\\\" 으로 가장 효율적으로 찾을 수 있습니다. location은 장 번호와 **해당 \"\n\"장의** 페이지 번호로 구성된 튜플 *(chapter, pno)* 입니다. 두 숫자 모두 0부터 시작합니다.\"\n\n#: ../../document.rst:21 178b2c734378413abc91131145d04d44\nmsgid \"\"\n\"While it is still possible to locate a page via its (absolute) number, \"\n\"doing so may mean that the complete EPUB document must be laid out before\"\n\" the page can be addressed. This may have a significant performance \"\n\"impact if the document is very large. Using the page's *(chapter, pno)* \"\n\"prevents this from happening.\"\nmsgstr \"\"\n\"여전히 (절대) 번호로 페이지를 찾을 수 있지만, 이렇게 하면 페이지를 주소 지정하기 전에 전체 EPUB 문서를 레이아웃해야 할 수\"\n\" 있습니다. 문서가 매우 큰 경우 성능에 상당한 영향을 줄 수 있습니다. 페이지의 *(chapter, pno)* 를 사용하면 이를 \"\n\"방지할 수 있습니다.\"\n\n#: ../../document.rst:23 2159d3254f2042e28d38a6352b880f37\nmsgid \"\"\n\"To maintain a consistent API, PyMuPDF supports the page *location* syntax\"\n\" for **all file types** -- documents without this feature simply have \"\n\"just one chapter. :meth:`Document.load_page` and the equivalent index \"\n\"access now also support a *location* argument.\"\nmsgstr \"\"\n\"일관된 API를 유지하기 위해 |PyMuPDF| 는 **모든 파일 타입** 에 대해 페이지 *location* 구문을 지원합니다. \"\n\"이 기능이 없는 문서는 단순히 하나의 장만 가집니다. :meth:`Document.load_page` 및 동등한 인덱스 액세스는 \"\n\"이제 *location* 인수도 지원합니다.\"\n\n#: ../../document.rst:25 df232cf85be34f7694fc6bae4310265f\nmsgid \"\"\n\"There are a number of methods for converting between page numbers and \"\n\"locations, for determining the chapter count, the page count per chapter,\"\n\" for computing the next and the previous locations, and the last page \"\n\"location of a document.\"\nmsgstr \"\"\n\"페이지 번호와 location 간 변환, 장 수 결정, 장당 페이지 수, 다음 및 이전 location 계산, 문서의 마지막 페이지\"\n\" location을 위한 여러 메서드가 있습니다.\"\n\n#: ../../document.rst:28 46f524c760e44c68ac0212f9fb4848a2\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../document.rst:28 4e9377212f2f4e3082b3e2b410eab114\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../document.rst:30 5b3602e531d94c1db1c6497e9803431f\nmsgid \":meth:`Document.add_layer`\"\nmsgstr \":meth:`Document.add_layer`\"\n\n#: ../../document.rst:30 65d3136ffad541db9619e9893cfdf1f8\nmsgid \"PDF only: make new optional content configuration\"\nmsgstr \"PDF 전용: 새로운 선택적 콘텐츠 구성 만들기\"\n\n#: ../../document.rst:31 3c176560d54742a5b24d578c141af482\nmsgid \":meth:`Document.add_ocg`\"\nmsgstr \":meth:`Document.add_ocg`\"\n\n#: ../../document.rst:31 201b8f9ef3564eb2b643e1d781ba9ebc\nmsgid \"PDF only: add new optional content group\"\nmsgstr \"PDF 전용: 새로운 선택적 콘텐츠 그룹 추가\"\n\n#: ../../document.rst:32 7ddab358521d4686bd9db4941273693b\nmsgid \":meth:`Document.authenticate`\"\nmsgstr \":meth:`Document.authenticate`\"\n\n#: ../../document.rst:32 6e2b79b1ac224cfbb3fb95f4607c5e08\nmsgid \"gain access to an encrypted document\"\nmsgstr \"암호화된 문서에 액세스\"\n\n#: ../../document.rst:33 f23216d1e7344106bf5c998fa4e9fcc1\nmsgid \":meth:`Document.bake`\"\nmsgstr \":meth:`Document.bake`\"\n\n#: ../../document.rst:33 701834a50a9449449b74ed220600c326\nmsgid \"PDF only: make annotations / fields permanent content\"\nmsgstr \"PDF 전용: 주석/필드를 영구 콘텐츠로 만들기\"\n\n#: ../../document.rst:34 1445d611a0f54db29ae05f37b828c0a3\nmsgid \":meth:`Document.can_save_incrementally`\"\nmsgstr \":meth:`Document.can_save_incrementally`\"\n\n#: ../../document.rst:34 9195cef3b66445fea3244e46c710903a\nmsgid \"check if incremental save is possible\"\nmsgstr \"증분 저장이 가능한지 확인\"\n\n#: ../../document.rst:35 06fd6aaf02c146c8ae72f3fab40cd5a5\nmsgid \":meth:`Document.chapter_page_count`\"\nmsgstr \":meth:`Document.chapter_page_count`\"\n\n#: ../../document.rst:35 1b4ca64be4784cfa9d385e411ba4de10\nmsgid \"number of pages in chapter\"\nmsgstr \"장의 페이지 수\"\n\n#: ../../document.rst:36 e22fa04e62c34c00946eff36e3cbf8d2\nmsgid \":meth:`Document.close`\"\nmsgstr \":meth:`Document.close`\"\n\n#: ../../document.rst:36 8dd025a8b44244e2b675ca00ea7467b3\nmsgid \"close the document\"\nmsgstr \"문서 닫기\"\n\n#: ../../document.rst:37 2df8c1ec290848699114b13a06ca7702\nmsgid \":meth:`Document.convert_to_pdf`\"\nmsgstr \":meth:`Document.convert_to_pdf`\"\n\n#: ../../document.rst:37 07ae613bdb784b69adf173fa0bcd3d84\nmsgid \"write a PDF version to memory\"\nmsgstr \"메모리에 PDF 버전 쓰기\"\n\n#: ../../document.rst:38 9130926279ca4df19aec8e03217dfd20\nmsgid \":meth:`Document.copy_page`\"\nmsgstr \":meth:`Document.copy_page`\"\n\n#: ../../document.rst:38 2284f3eeb2104ff5945ac48b6f9dc501\nmsgid \"PDF only: copy a page reference\"\nmsgstr \"PDF 전용: 페이지 참조 복사\"\n\n#: ../../document.rst:39 a4a84dbf2abb4f8b87db310b7e5d6f65\nmsgid \":meth:`Document.del_toc_item`\"\nmsgstr \":meth:`Document.del_toc_item`\"\n\n#: ../../document.rst:39 1d88797ba50244df87c018fbd0a1325c\nmsgid \"PDF only: remove a single TOC item\"\nmsgstr \"PDF 전용: 단일 TOC 항목 제거\"\n\n#: ../../document.rst:40 4b5b2f2193ee40268e3409b60e9d1993\nmsgid \":meth:`Document.delete_page`\"\nmsgstr \":meth:`Document.delete_page`\"\n\n#: ../../document.rst:40 3b0577dd9e9d493eb0b8f2d054e76e32\nmsgid \"PDF only: delete a page\"\nmsgstr \"PDF 전용: 페이지 삭제\"\n\n#: ../../document.rst:41 98476640118346639145607edd0502bb\nmsgid \":meth:`Document.delete_pages`\"\nmsgstr \":meth:`Document.delete_pages`\"\n\n#: ../../document.rst:41 2538d93965d74c58bbbf5e4596c5f25d\nmsgid \"PDF only: delete multiple pages\"\nmsgstr \"PDF 전용: 여러 페이지 삭제\"\n\n#: ../../document.rst:42 61345aebdd664464829398e410a5310b\nmsgid \":meth:`Document.embfile_add`\"\nmsgstr \":meth:`Document.embfile_add`\"\n\n#: ../../document.rst:42 5a68f72c35de4d37b228d5f8346c4580\nmsgid \"PDF only: add a new embedded file from buffer\"\nmsgstr \"PDF 전용: 버퍼에서 새 임베디드 파일 추가\"\n\n#: ../../document.rst:43 18633aec87e94b9ca718ea6ed390688d\nmsgid \":meth:`Document.embfile_count`\"\nmsgstr \":meth:`Document.embfile_count`\"\n\n#: ../../document.rst:43 f033cc2e882b4095a655c775436b4735\nmsgid \"PDF only: number of embedded files\"\nmsgstr \"PDF 전용: 임베디드 파일 수\"\n\n#: ../../document.rst:44 06a7fe3f8efc49909007b9940d51ad20\nmsgid \":meth:`Document.embfile_del`\"\nmsgstr \":meth:`Document.embfile_del`\"\n\n#: ../../document.rst:44 5b16fd13df354ec08ec0e0f2237988a9\nmsgid \"PDF only: delete an embedded file entry\"\nmsgstr \"PDF 전용: 임베디드 파일 항목 삭제\"\n\n#: ../../document.rst:45 60594207c907496aa08c503b3cfe89f6\nmsgid \":meth:`Document.embfile_get`\"\nmsgstr \":meth:`Document.embfile_get`\"\n\n#: ../../document.rst:45 999f103381d34492a8ba2b37a6086938\nmsgid \"PDF only: extract an embedded file buffer\"\nmsgstr \"PDF 전용: 임베디드 파일 버퍼 추출\"\n\n#: ../../document.rst:46 e9bf1793dd2747629395caecc286671a\nmsgid \":meth:`Document.embfile_info`\"\nmsgstr \":meth:`Document.embfile_info`\"\n\n#: ../../document.rst:46 125fea066b3942b08edaad0bc6d3f4a7\nmsgid \"PDF only: metadata of an embedded file\"\nmsgstr \"PDF 전용: 임베디드 파일의 메타데이터\"\n\n#: ../../document.rst:47 76e5c528f0c0400a97717a27fa7c782b\nmsgid \":meth:`Document.embfile_names`\"\nmsgstr \":meth:`Document.embfile_names`\"\n\n#: ../../document.rst:47 afb7511107e34829b92c8dd670340f11\nmsgid \"PDF only: list of embedded files\"\nmsgstr \"PDF 전용: 임베디드 파일 목록\"\n\n#: ../../document.rst:48 95b76c0413ad4f1dbcccefe6473aaed0\nmsgid \":meth:`Document.embfile_upd`\"\nmsgstr \":meth:`Document.embfile_upd`\"\n\n#: ../../document.rst:48 8a1ba2aa97ad4d93b72b824b5972f61d\nmsgid \"PDF only: change an embedded file\"\nmsgstr \"PDF 전용: 임베디드 파일 변경\"\n\n#: ../../document.rst:49 c15752ac19fe4bf3b06f09954bedb276\nmsgid \":meth:`Document.extract_font`\"\nmsgstr \":meth:`Document.extract_font`\"\n\n#: ../../document.rst:49 16b2ad2113eb4c9486a04750afbeb48e\nmsgid \"PDF only: extract a font by :data:`xref`\"\nmsgstr \"PDF 전용: :data:`xref` 로 글꼴 추출\"\n\n#: ../../document.rst:50 9a00f7ac64df4bdc972886fe7daef5f5\nmsgid \":meth:`Document.extract_image`\"\nmsgstr \":meth:`Document.extract_image`\"\n\n#: ../../document.rst:50 231c94516aae4427b026bb5b2d3d9093\nmsgid \"PDF only: extract an embedded image by :data:`xref`\"\nmsgstr \"PDF 전용: :data:`xref` 로 임베디드 이미지 추출\"\n\n#: ../../document.rst:51 baebb0fc699c458984b242b7139e1728\nmsgid \":meth:`Document.ez_save`\"\nmsgstr \":meth:`Document.ez_save`\"\n\n#: ../../document.rst:51 3ce9b54342e7444eaf2b9f3bba3e6f16\nmsgid \"PDF only: :meth:`Document.save` with different defaults\"\nmsgstr \"PDF 전용: 다른 기본값으로 :meth:`Document.save`\"\n\n#: ../../document.rst:52 5cec6b3c172f4656a22121134d433007\nmsgid \":meth:`Document.find_bookmark`\"\nmsgstr \":meth:`Document.find_bookmark`\"\n\n#: ../../document.rst:52 ec569e92de1f4544a945bfaca8347747\nmsgid \"retrieve page location after laid out document\"\nmsgstr \"레이아웃된 문서 후 페이지 location 검색\"\n\n#: ../../document.rst:53 934ec46a1ef84942ae7d272bb00b5de3\nmsgid \":meth:`Document.fullcopy_page`\"\nmsgstr \":meth:`Document.fullcopy_page`\"\n\n#: ../../document.rst:53 af34d7a3cda34a54a4b0722878c745a1\nmsgid \"PDF only: duplicate a page\"\nmsgstr \"PDF 전용: 페이지 복제\"\n\n#: ../../document.rst:54 beac81b115604ae688930966a58178bf\nmsgid \":meth:`Document.get_layer`\"\nmsgstr \":meth:`Document.get_layer`\"\n\n#: ../../document.rst:54 b970ece30e74455f872d4a1f28bd88b4\nmsgid \"PDF only: lists of OCGs in ON, OFF, RBGroups\"\nmsgstr \"PDF 전용: ON, OFF, RBGroups의 OCG 목록\"\n\n#: ../../document.rst:55 8afcf442694c4348be8b13278c5e8443\nmsgid \":meth:`Document.get_layers`\"\nmsgstr \":meth:`Document.get_layers`\"\n\n#: ../../document.rst:55 062661b7effe49e684f1e499084b08b7\nmsgid \"PDF only: list of optional content configurations\"\nmsgstr \"PDF 전용: 선택적 콘텐츠 구성 목록\"\n\n#: ../../document.rst:56 85e0ac74eca046faa7c0556a44b1a8d0\nmsgid \":meth:`Document.get_oc`\"\nmsgstr \":meth:`Document.get_oc`\"\n\n#: ../../document.rst:56 b561cdb739f0443facf651a7b7ab8229\nmsgid \"PDF only: get OCG /OCMD xref of image / form xobject\"\nmsgstr \"PDF 전용: 이미지/폼 xobject의 OCG/OCMD xref 가져오기\"\n\n#: ../../document.rst:57 b09065ba3930470ebf537f0ddb5a498f\nmsgid \":meth:`Document.get_ocgs`\"\nmsgstr \":meth:`Document.get_ocgs`\"\n\n#: ../../document.rst:57 873364f685fb4875bb78e820afa1e216\nmsgid \"PDF only: info on all optional content groups\"\nmsgstr \"PDF 전용: 모든 선택적 콘텐츠 그룹 정보\"\n\n#: ../../document.rst:58 99b8161657d24b2eb4f397ce80f5f36f\nmsgid \":meth:`Document.get_ocmd`\"\nmsgstr \":meth:`Document.get_ocmd`\"\n\n#: ../../document.rst:58 24cde3757ecd4f6683277d7674f33b96\nmsgid \"PDF only: retrieve definition of an :data:`OCMD`\"\nmsgstr \"PDF 전용: :data:`OCMD` 정의 검색\"\n\n#: ../../document.rst:59 1e447980e885431990479bbaac18087f\nmsgid \":meth:`Document.get_page_fonts`\"\nmsgstr \":meth:`Document.get_page_fonts`\"\n\n#: ../../document.rst:59 218a049cce39410cb568fcec949a0cb1\nmsgid \"PDF only: list of fonts referenced by a page\"\nmsgstr \"PDF 전용: 페이지에서 참조하는 글꼴 목록\"\n\n#: ../../document.rst:60 634e95f27afe40aabed15306e6e5f3a8\nmsgid \":meth:`Document.get_page_images`\"\nmsgstr \":meth:`Document.get_page_images`\"\n\n#: ../../document.rst:60 c77477a1f9784f0ab264def72a81bb15\nmsgid \"PDF only: list of images referenced by a page\"\nmsgstr \"PDF 전용: 페이지에서 참조하는 이미지 목록\"\n\n#: ../../document.rst:61 0727d4b995964e10af190dd7cfb897e5\nmsgid \":meth:`Document.get_page_labels`\"\nmsgstr \":meth:`Document.get_page_labels`\"\n\n#: ../../document.rst:61 fa0286f2112a4c94a90c75e6175dbbbe\nmsgid \"PDF only: list of page label definitions\"\nmsgstr \"PDF 전용: 페이지 레이블 정의 목록\"\n\n#: ../../document.rst:62 6221c6245a934039a5818787cf85bee0\nmsgid \":meth:`Document.get_page_numbers`\"\nmsgstr \":meth:`Document.get_page_numbers`\"\n\n#: ../../document.rst:62 9055b20ef77543ccaa348fd85e287813\nmsgid \"PDF only: get page numbers having a given label\"\nmsgstr \"PDF 전용: 주어진 레이블을 가진 페이지 번호 가져오기\"\n\n#: ../../document.rst:63 b890980658c145fc86e2d8453e4dc4bf\nmsgid \":meth:`Document.get_page_pixmap`\"\nmsgstr \":meth:`Document.get_page_pixmap`\"\n\n#: ../../document.rst:63 9bf18031a8264a1195ef48bf05f6ebcd\nmsgid \"create a pixmap of a page by page number\"\nmsgstr \"페이지 번호로 페이지의 pixmap 생성\"\n\n#: ../../document.rst:64 2c3b6eb10d2c443c9e43f14fcf323679\nmsgid \":meth:`Document.get_page_text`\"\nmsgstr \":meth:`Document.get_page_text`\"\n\n#: ../../document.rst:64 e50152ab76234bd199393b23c20e5f2b\nmsgid \"extract the text of a page by page number\"\nmsgstr \"페이지 번호로 페이지의 텍스트 추출\"\n\n#: ../../document.rst:65 6e3dbc70b1af422ba02c5de40db51227\nmsgid \":meth:`Document.get_page_xobjects`\"\nmsgstr \":meth:`Document.get_page_xobjects`\"\n\n#: ../../document.rst:65 03e1a6c888d6428da83be3d52fcc6dc5\nmsgid \"PDF only: list of XObjects referenced by a page\"\nmsgstr \"PDF 전용: 페이지에서 참조하는 XObject 목록\"\n\n#: ../../document.rst:66 d7fed3570628496781e26eea0fb88560\nmsgid \":meth:`Document.get_sigflags`\"\nmsgstr \":meth:`Document.get_sigflags`\"\n\n#: ../../document.rst:66 57ae0f17dfbf46dfbda2134cd4e08b21\nmsgid \"PDF only: determine signature state\"\nmsgstr \"PDF 전용: 서명 상태 확인\"\n\n#: ../../document.rst:67 1b9ec8899eab41e1b6e41764596a29fa\nmsgid \":meth:`Document.get_toc`\"\nmsgstr \":meth:`Document.get_toc`\"\n\n#: ../../document.rst:67 866abb5def4347499ca11de1dbe1a8e1\nmsgid \"extract the table of contents\"\nmsgstr \"목차 추출\"\n\n#: ../../document.rst:68 82845c18f95c434790783d3885e3e58c\nmsgid \":meth:`Document.get_xml_metadata`\"\nmsgstr \":meth:`Document.get_xml_metadata`\"\n\n#: ../../document.rst:68 c6779c10381c4226a246aaf0ed325272\nmsgid \"PDF only: read the XML metadata\"\nmsgstr \"PDF 전용: XML 메타데이터 읽기\"\n\n#: ../../document.rst:69 2a2d620a34c549f187ea62b6f2994726\nmsgid \":meth:`Document.has_annots`\"\nmsgstr \":meth:`Document.has_annots`\"\n\n#: ../../document.rst:69 9998561217d44b509743282a54412d14\nmsgid \"PDF only: check if PDF contains any annots\"\nmsgstr \"PDF 전용: PDF에 주석이 있는지 확인\"\n\n#: ../../document.rst:70 9bfb1faf1cc045bdae83c0bef14cb87a\nmsgid \":meth:`Document.has_links`\"\nmsgstr \":meth:`Document.has_links`\"\n\n#: ../../document.rst:70 b3b5865766b146cba5209502fbdc7016\nmsgid \"PDF only: check if PDF contains any links\"\nmsgstr \"PDF 전용: PDF에 링크가 있는지 확인\"\n\n#: ../../document.rst:71 932fc1b4e64741b0ac7ece1f30469b48\nmsgid \":meth:`Document.insert_page`\"\nmsgstr \":meth:`Document.insert_page`\"\n\n#: ../../document.rst:71 270cba89f81345efa9dafa53163b187b\nmsgid \"PDF only: insert a new page\"\nmsgstr \"PDF 전용: 새 페이지 삽입\"\n\n#: ../../document.rst:72 f5a25046b2c3451ea1a3a6a71ecad26d\nmsgid \":meth:`Document.insert_pdf`\"\nmsgstr \":meth:`Document.insert_pdf`\"\n\n#: ../../document.rst:72 2d42116aae5e442a907b006552760768\nmsgid \"PDF only: insert pages from another PDF\"\nmsgstr \"PDF 전용: 다른 PDF에서 페이지 삽입\"\n\n#: ../../document.rst:73 5e07d2a848454f8ebc0e60f5c15361da\nmsgid \":meth:`Document.insert_file`\"\nmsgstr \":meth:`Document.insert_file`\"\n\n#: ../../document.rst:73 a13c5a83593743148f171785c25abfbe\nmsgid \"PDF only: insert pages from arbitrary document\"\nmsgstr \"PDF 전용: 임의 문서에서 페이지 삽입\"\n\n#: ../../document.rst:74 da81e9fba93c4e02bd963939be7fd721\nmsgid \":meth:`Document.journal_can_do`\"\nmsgstr \":meth:`Document.journal_can_do`\"\n\n#: ../../document.rst:74 f003731191ba400aa315f4d89a7e4496\nmsgid \"PDF only: which journal actions are possible\"\nmsgstr \"PDF 전용: 어떤 저널 작업이 가능한지\"\n\n#: ../../document.rst:75 53afd4fad6684cbcbf998d63695219f6\nmsgid \":meth:`Document.journal_enable`\"\nmsgstr \":meth:`Document.journal_enable`\"\n\n#: ../../document.rst:75 466c85e3cd404f1eb8a1aab4a9eff2ef\nmsgid \"PDF only: enables journalling for the document\"\nmsgstr \"PDF 전용: 문서에 대한 저널링 활성화\"\n\n#: ../../document.rst:76 8a840e1674cb4a8292514219d5233be5\nmsgid \":meth:`Document.journal_load`\"\nmsgstr \":meth:`Document.journal_load`\"\n\n#: ../../document.rst:76 be15f80486ba4b5eb417b7536e7a9c1f\nmsgid \"PDF only: load journal from a file\"\nmsgstr \"PDF 전용: 파일에서 저널 로드\"\n\n#: ../../document.rst:77 c3abfd7dfc684a0eabab17f2154ef1cb\nmsgid \":meth:`Document.journal_op_name`\"\nmsgstr \":meth:`Document.journal_op_name`\"\n\n#: ../../document.rst:77 8f0cf3234beb49a69154166b09198334\nmsgid \"PDF only: return name of a journalling step\"\nmsgstr \"PDF 전용: 저널링 단계의 이름 반환\"\n\n#: ../../document.rst:78 3893cf1fdeb9469b9e6e653eaa9e1c44\nmsgid \":meth:`Document.journal_position`\"\nmsgstr \":meth:`Document.journal_position`\"\n\n#: ../../document.rst:78 0e35098b113747de855c33fde152b50c\nmsgid \"PDF only: return journalling status\"\nmsgstr \"PDF 전용: 저널링 상태 반환\"\n\n#: ../../document.rst:79 52ff8d29e1ff41b5b7a9f6eed3eca524\nmsgid \":meth:`Document.journal_redo`\"\nmsgstr \":meth:`Document.journal_redo`\"\n\n#: ../../document.rst:79 5de38e35b20f4c8c9c7669bf4faff487\nmsgid \"PDF only: redo current operation\"\nmsgstr \"PDF 전용: 현재 작업 다시 실행\"\n\n#: ../../document.rst:80 cb385893200e4bb1ba7ac9d5ed8f9f52\nmsgid \":meth:`Document.journal_save`\"\nmsgstr \":meth:`Document.journal_save`\"\n\n#: ../../document.rst:80 c5827a1af6cd46d0b852b6f8d8c5d013\nmsgid \"PDF only: save journal to a file\"\nmsgstr \"PDF 전용: 파일에 저널 저장\"\n\n#: ../../document.rst:81 5df7cd504f094a9f957f314d8d835bef\nmsgid \":meth:`Document.journal_start_op`\"\nmsgstr \":meth:`Document.journal_start_op`\"\n\n#: ../../document.rst:81 535142a5dd984152a49fee7de70e3625\nmsgid \"PDF only: start an \\\"operation\\\" giving it a name\"\nmsgstr \"PDF 전용: 이름을 지정하여 \\\"작업\\\" 시작\"\n\n#: ../../document.rst:82 d95c10cd751448148b51128e83d187d1\nmsgid \":meth:`Document.journal_stop_op`\"\nmsgstr \":meth:`Document.journal_stop_op`\"\n\n#: ../../document.rst:82 76267fa3c43546d3a8433b9483244816\nmsgid \"PDF only: end current operation\"\nmsgstr \"PDF 전용: 현재 작업 종료\"\n\n#: ../../document.rst:83 6c06ee831e5d492582f709a89de650da\nmsgid \":meth:`Document.journal_undo`\"\nmsgstr \":meth:`Document.journal_undo`\"\n\n#: ../../document.rst:83 48a3042404bc45da9d5b1aa672c5e5e3\nmsgid \"PDF only: undo current operation\"\nmsgstr \"PDF 전용: 현재 작업 실행 취소\"\n\n#: ../../document.rst:84 a7663f4b73274da08256c916f19f008a\nmsgid \":meth:`Document.layer_ui_configs`\"\nmsgstr \":meth:`Document.layer_ui_configs`\"\n\n#: ../../document.rst:84 a5ea77e6f6ec4f50acb131b0cb83fe8e\nmsgid \"PDF only: list of optional content intents\"\nmsgstr \"PDF 전용: 선택적 콘텐츠 의도 목록\"\n\n#: ../../document.rst:85 e25b0824906149399a490263db250b41\nmsgid \":meth:`Document.layout`\"\nmsgstr \":meth:`Document.layout`\"\n\n#: ../../document.rst:85 9d414ccd3311467f9526fbcfb70a3cd4\nmsgid \"re-paginate the document (if supported)\"\nmsgstr \"문서 재페이지화(지원되는 경우)\"\n\n#: ../../document.rst:86 8e8d6694b6434582a77b4d60c4685594\nmsgid \":meth:`Document.load_page`\"\nmsgstr \":meth:`Document.load_page`\"\n\n#: ../../document.rst:86 2a290bf3d63347c69c3bfe1ee7d2c3c8\nmsgid \"read a page\"\nmsgstr \"페이지 읽기\"\n\n#: ../../document.rst:87 b9f9cb023be64cf2a96f7d065646060d\nmsgid \":meth:`Document.make_bookmark`\"\nmsgstr \":meth:`Document.make_bookmark`\"\n\n#: ../../document.rst:87 345855234e20436e8ed4aaa74ef9351a\nmsgid \"create a page pointer in reflowable documents\"\nmsgstr \"재배치 가능한 문서에서 페이지 포인터 생성\"\n\n#: ../../document.rst:88 29d4e91b8ab54e0eaf2d20b0a751f624\nmsgid \":meth:`Document.move_page`\"\nmsgstr \":meth:`Document.move_page`\"\n\n#: ../../document.rst:88 691dccf584bc4853b6e2d5675c80c7d3\nmsgid \"PDF only: move a page to different location in doc\"\nmsgstr \"PDF 전용: 문서 내 다른 위치로 페이지 이동\"\n\n#: ../../document.rst:89 67c910fcd5ed41c9991479c54e306404\nmsgid \":meth:`Document.need_appearances`\"\nmsgstr \":meth:`Document.need_appearances`\"\n\n#: ../../document.rst:89 154d52d4749041489a187968e2b62e29\nmsgid \"PDF only: get/set `/NeedAppearances` property\"\nmsgstr \"PDF 전용: `/NeedAppearances` 속성 가져오기/설정\"\n\n#: ../../document.rst:90 67997ce8145242828157b731aeea5309\nmsgid \":meth:`Document.new_page`\"\nmsgstr \":meth:`Document.new_page`\"\n\n#: ../../document.rst:90 f373235056a94d918bf71a59a4e39fb6\nmsgid \"PDF only: insert a new empty page\"\nmsgstr \"PDF 전용: 새 빈 페이지 삽입\"\n\n#: ../../document.rst:91 2ebb59db0b7c46f5b8372676ec664cc2\nmsgid \":meth:`Document.next_location`\"\nmsgstr \":meth:`Document.next_location`\"\n\n#: ../../document.rst:91 fea286b98cea474ea4dd19ca31d36bf3\nmsgid \"return (chapter, pno) of following page\"\nmsgstr \"다음 페이지의 (chapter, pno) 반환\"\n\n#: ../../document.rst:92 4d9ab9b1b05348f3b04acd8b61454fe9\nmsgid \":meth:`Document.outline_xref`\"\nmsgstr \":meth:`Document.outline_xref`\"\n\n#: ../../document.rst:92 01c12f7a26a74fd5bf9821784d29795e\nmsgid \"PDF only: :data:`xref` a TOC item\"\nmsgstr \"PDF 전용: TOC 항목의 :data:`xref`\"\n\n#: ../../document.rst:93 9768ffa1299a442caccdf7c671b0bf27\nmsgid \":meth:`Document.page_cropbox`\"\nmsgstr \":meth:`Document.page_cropbox`\"\n\n#: ../../document.rst:93 dd064dbd65b448cc9042f887cac6617c\nmsgid \"PDF only: the unrotated page rectangle\"\nmsgstr \"PDF 전용: 회전되지 않은 페이지 사각형\"\n\n#: ../../document.rst:94 b41ff5956b474fa397c37ade86b111ee\nmsgid \":meth:`Document.page_xref`\"\nmsgstr \":meth:`Document.page_xref`\"\n\n#: ../../document.rst:94 0824864d572b403c8674639a069fa531\nmsgid \"PDF only: :data:`xref` of a page number\"\nmsgstr \"PDF 전용: 페이지 번호의 :data:`xref`\"\n\n#: ../../document.rst:95 b8928e6f8083487493c9d650c0907cf7\nmsgid \":meth:`Document.pages`\"\nmsgstr \":meth:`Document.pages`\"\n\n#: ../../document.rst:95 953faf375f4a4467b9cc641f8aa60451\nmsgid \"iterator over a page range\"\nmsgstr \"페이지 범위에 대한 반복자\"\n\n#: ../../document.rst:96 ee1c62d129c843e282a7042ed3b6e72a\nmsgid \":meth:`Document.pdf_catalog`\"\nmsgstr \":meth:`Document.pdf_catalog`\"\n\n#: ../../document.rst:96 48452a6b17f64ea6bbfeb6a5f978d17a\nmsgid \"PDF only: :data:`xref` of catalog (root)\"\nmsgstr \"PDF 전용: 카탈로그(루트)의 :data:`xref`\"\n\n#: ../../document.rst:97 0da14aaa4866451eb1be470696335f35\nmsgid \":meth:`Document.pdf_trailer`\"\nmsgstr \":meth:`Document.pdf_trailer`\"\n\n#: ../../document.rst:97 8fcead81b4a349a89a593a5f87b1f579\nmsgid \"PDF only: trailer source\"\nmsgstr \"PDF 전용: 트레일러 소스\"\n\n#: ../../document.rst:98 52890ca247594e77857e850c264f6bb1\nmsgid \":meth:`Document.prev_location`\"\nmsgstr \":meth:`Document.prev_location`\"\n\n#: ../../document.rst:98 6b4f422f07a04229a6b0cf9f67ec4fd8\nmsgid \"return (chapter, pno) of preceding page\"\nmsgstr \"이전 페이지의 (chapter, pno) 반환\"\n\n#: ../../document.rst:99 d6c679d125c042528e2960090decfc63\nmsgid \":meth:`Document.rewrite_images`\"\nmsgstr \":meth:`Document.rewrite_images`\"\n\n#: ../../document.rst:99 ad80fd7b1a02452f943efeac7a6fe588\nmsgid \"PDF only: rewrite / extra compression for images\"\nmsgstr \"PDF 전용: 이미지 재작성/추가 압축\"\n\n#: ../../document.rst:100 90879d3f9f35492ab438590b55f64080\nmsgid \":meth:`Document.recolor`\"\nmsgstr \":meth:`Document.recolor`\"\n\n#: ../../document.rst:100 048b7aa969ff482397e0f20f2113e309\nmsgid \"PDF only: execute :meth:`Page.recolor` for all pages\"\nmsgstr \"PDF 전용: 모든 페이지에 대해 :meth:`Page.recolor` 실행\"\n\n#: ../../document.rst:101 0420a4b50b874b069c87053bacb087ad\nmsgid \":meth:`Document.reload_page`\"\nmsgstr \":meth:`Document.reload_page`\"\n\n#: ../../document.rst:101 4e23ac1ef56e49d497dd09d1bb07a50a\nmsgid \"PDF only: provide a new copy of a page\"\nmsgstr \"PDF 전용: 페이지의 새 복사본 제공\"\n\n#: ../../document.rst:102 e6f66d0ad9a241a787373320375cb6ea\nmsgid \":meth:`Document.resolve_names`\"\nmsgstr \":meth:`Document.resolve_names`\"\n\n#: ../../document.rst:102 08c8ce45d9934cf486d9652f5351d823\nmsgid \"PDF only: Convert destination names into a Python dict\"\nmsgstr \"PDF 전용: 대상 이름을 Python dict로 변환\"\n\n#: ../../document.rst:103 f53e78a26a26487898548af383ad2b04\nmsgid \":meth:`Document.save`\"\nmsgstr \":meth:`Document.save`\"\n\n#: ../../document.rst:103 e1666396777c469eaa440b91907b4ba4\nmsgid \"PDF only: save the document\"\nmsgstr \"PDF 전용: 문서 저장\"\n\n#: ../../document.rst:104 79410e6cae40486a9e185a468505c1d0\nmsgid \":meth:`Document.saveIncr`\"\nmsgstr \":meth:`Document.saveIncr`\"\n\n#: ../../document.rst:104 e043fb40d0c14b578d219707f0e5c381\nmsgid \"PDF only: save the document incrementally\"\nmsgstr \"PDF 전용: 문서 증분 저장\"\n\n#: ../../document.rst:105 0805ea1a287f460082863449cf526443\nmsgid \":meth:`Document.scrub`\"\nmsgstr \":meth:`Document.scrub`\"\n\n#: ../../document.rst:105 048424aedefa422d99e89d8b18815b9a\nmsgid \"PDF only: remove sensitive data\"\nmsgstr \"PDF 전용: 민감한 데이터 제거\"\n\n#: ../../document.rst:106 f5637e670f41414d9c58af3aa5c3919c\nmsgid \":meth:`Document.search_page_for`\"\nmsgstr \":meth:`Document.search_page_for`\"\n\n#: ../../document.rst:106 954d77ecb8cf4cf7b4259b807d255e5f\nmsgid \"search for a string on a page\"\nmsgstr \"페이지에서 문자열 검색\"\n\n#: ../../document.rst:107 3c98443c81714deaaf66571cdc3aee63\nmsgid \":meth:`Document.select`\"\nmsgstr \":meth:`Document.select`\"\n\n#: ../../document.rst:107 89f0842e40f244f3b1b2beeb03cf8f79\nmsgid \"PDF only: select a subset of pages\"\nmsgstr \"PDF 전용: 페이지 하위 집합 선택\"\n\n#: ../../document.rst:108 ec80d7f1fd6e4ae6bd8fe34235e53d51\nmsgid \":meth:`Document.set_layer_ui_config`\"\nmsgstr \":meth:`Document.set_layer_ui_config`\"\n\n#: ../../document.rst:108 bc3010d7daee494191971416ac2f27a3\nmsgid \"PDF only: set OCG visibility temporarily\"\nmsgstr \"PDF 전용: OCG 가시성 임시 설정\"\n\n#: ../../document.rst:109 0de756b0b7da49cdb45d6ba4d1375de7\nmsgid \":meth:`Document.set_layer`\"\nmsgstr \":meth:`Document.set_layer`\"\n\n#: ../../document.rst:109 062d5ad83cf1469ca236e2542030877b\nmsgid \"PDF only: mass changing OCG states\"\nmsgstr \"PDF 전용: OCG 상태 대량 변경\"\n\n#: ../../document.rst:110 6b915bb80b65485fa37649f3e25f9635\nmsgid \":meth:`Document.set_markinfo`\"\nmsgstr \":meth:`Document.set_markinfo`\"\n\n#: ../../document.rst:110 c9a6ec82888f423897687332e5a6aeb9\nmsgid \"PDF only: set the MarkInfo values\"\nmsgstr \"PDF 전용: MarkInfo 값 설정\"\n\n#: ../../document.rst:111 3e2e221f48e74d36aa62a40e05c5dc44\nmsgid \":meth:`Document.set_metadata`\"\nmsgstr \":meth:`Document.set_metadata`\"\n\n#: ../../document.rst:111 2c0ba8035650467183a0348c174fc768\nmsgid \"PDF only: set the metadata\"\nmsgstr \"PDF 전용: 메타데이터 설정\"\n\n#: ../../document.rst:112 23ab87427be240ec946ceeb5a4f558d7\nmsgid \":meth:`Document.set_oc`\"\nmsgstr \":meth:`Document.set_oc`\"\n\n#: ../../document.rst:112 77f693748ae947f2baba48a8bc881a44\nmsgid \"PDF only: attach OCG/OCMD to image / form xobject\"\nmsgstr \"PDF 전용: 이미지/폼 xobject에 OCG/OCMD 첨부\"\n\n#: ../../document.rst:113 cda51f6dbcec472299a7a16c636f0a12\nmsgid \":meth:`Document.set_ocmd`\"\nmsgstr \":meth:`Document.set_ocmd`\"\n\n#: ../../document.rst:113 20d4b8a0924f4ea29246e027a1f0c007\nmsgid \"PDF only: create or update an :data:`OCMD`\"\nmsgstr \"PDF 전용: :data:`OCMD` 생성 또는 업데이트\"\n\n#: ../../document.rst:114 a7e13374f46740c4822c7a5111703736\nmsgid \":meth:`Document.set_page_labels`\"\nmsgstr \":meth:`Document.set_page_labels`\"\n\n#: ../../document.rst:114 94fe2ff39a9643378567dcb63f367048\nmsgid \"PDF only: add/update page label definitions\"\nmsgstr \"PDF 전용: 페이지 레이블 정의 추가/업데이트\"\n\n#: ../../document.rst:115 60f0adf4c1034acd97a115b10f39646f\nmsgid \":meth:`Document.set_pagemode`\"\nmsgstr \":meth:`Document.set_pagemode`\"\n\n#: ../../document.rst:115 2de11d6c970445279a611a51fde70d09\nmsgid \"PDF only: set the PageMode\"\nmsgstr \"PDF 전용: PageMode 설정\"\n\n#: ../../document.rst:116 6918b302a70047618b1f366d63f56f87\nmsgid \":meth:`Document.set_pagelayout`\"\nmsgstr \":meth:`Document.set_pagelayout`\"\n\n#: ../../document.rst:116 ba12021554e24e189c726510b2ebee5f\nmsgid \"PDF only: set the PageLayout\"\nmsgstr \"PDF 전용: PageLayout 설정\"\n\n#: ../../document.rst:117 1ebdac8147c049f69aa6e0232975466e\nmsgid \":meth:`Document.set_toc_item`\"\nmsgstr \":meth:`Document.set_toc_item`\"\n\n#: ../../document.rst:117 8364d653136141b69b74d53e652719fd\nmsgid \"PDF only: change a single TOC item\"\nmsgstr \"PDF 전용: 단일 TOC 항목 변경\"\n\n#: ../../document.rst:118 2a317675273941beaad2c9211d911be7\nmsgid \":meth:`Document.set_toc`\"\nmsgstr \":meth:`Document.set_toc`\"\n\n#: ../../document.rst:118 5f3982dba4914daaa18904ea68caade2\nmsgid \"PDF only: set the table of contents (TOC)\"\nmsgstr \"PDF 전용: 목차(TOC) 설정\"\n\n#: ../../document.rst:119 94ee47ccf9a1419691946e271ef887e6\nmsgid \":meth:`Document.set_xml_metadata`\"\nmsgstr \":meth:`Document.set_xml_metadata`\"\n\n#: ../../document.rst:119 8ebe617a04564a6a81e3729f7bea6248\nmsgid \"PDF only: create or update document XML metadata\"\nmsgstr \"PDF 전용: 문서 XML 메타데이터 생성 또는 업데이트\"\n\n#: ../../document.rst:120 afc237479de04f878c80f9ca95546260\nmsgid \":meth:`Document.subset_fonts`\"\nmsgstr \":meth:`Document.subset_fonts`\"\n\n#: ../../document.rst:120 74c0da056f3d49229285cdc50fc621fa\nmsgid \"PDF only: create font subsets\"\nmsgstr \"PDF 전용: 글꼴 하위 집합 생성\"\n\n#: ../../document.rst:121 89c3474ebdf8469b8df51d20bf5900fb\nmsgid \":meth:`Document.switch_layer`\"\nmsgstr \":meth:`Document.switch_layer`\"\n\n#: ../../document.rst:121 cd1b6a92de2c4a9cbc956b8cc27d6a0d\nmsgid \"PDF only: activate OC configuration\"\nmsgstr \"PDF 전용: OC 구성 활성화\"\n\n#: ../../document.rst:122 2c4e7b739b374987a9fae13bfbee26eb\nmsgid \":meth:`Document.tobytes`\"\nmsgstr \":meth:`Document.tobytes`\"\n\n#: ../../document.rst:122 2cbda5bb9d9745e08ce126b505a05ca7\nmsgid \"PDF only: writes document to memory\"\nmsgstr \"PDF 전용: 메모리에 문서 쓰기\"\n\n#: ../../document.rst:123 2dff81839c264b1fa86c1b188e9502c1\nmsgid \":meth:`Document.xref_copy`\"\nmsgstr \":meth:`Document.xref_copy`\"\n\n#: ../../document.rst:123 64a39ef729364a0ea13434f870b0f943\nmsgid \"PDF only: copy a PDF dictionary to another :data:`xref`\"\nmsgstr \"PDF 전용: PDF 딕셔너리를 다른 :data:`xref` 로 복사\"\n\n#: ../../document.rst:124 1580d4746a56446d993210e18ea0de6e\nmsgid \":meth:`Document.xref_get_key`\"\nmsgstr \":meth:`Document.xref_get_key`\"\n\n#: ../../document.rst:124 8944519b866243fe8efbe830de8d7255\nmsgid \"PDF only: get the value of a dictionary key\"\nmsgstr \"PDF 전용: 딕셔너리 키의 값 가져오기\"\n\n#: ../../document.rst:125 7173a26e0e9543f48763170017fa9e3b\nmsgid \":meth:`Document.xref_get_keys`\"\nmsgstr \":meth:`Document.xref_get_keys`\"\n\n#: ../../document.rst:125 b310a70e04e6405e8d148fcf54152bbb\nmsgid \"PDF only: list the keys of object at :data:`xref`\"\nmsgstr \"PDF 전용: :data:`xref` 의 객체 키 목록\"\n\n#: ../../document.rst:126 00bdb06b8b5549758da9e1899fb9f342\nmsgid \":meth:`Document.xref_object`\"\nmsgstr \":meth:`Document.xref_object`\"\n\n#: ../../document.rst:126 f884a66ec00e467fa7e27e13ac4e3698\nmsgid \"PDF only: get the definition source of :data:`xref`\"\nmsgstr \"PDF 전용: :data:`xref` 의 정의 소스 가져오기\"\n\n#: ../../document.rst:127 59678d3196fe4a31ae9e8a30b856dd51\nmsgid \":meth:`Document.xref_set_key`\"\nmsgstr \":meth:`Document.xref_set_key`\"\n\n#: ../../document.rst:127 973aa3316e7543f9933bd6dd2396fdde\nmsgid \"PDF only: set the value of a dictionary key\"\nmsgstr \"PDF 전용: 딕셔너리 키의 값 설정\"\n\n#: ../../document.rst:128 68e9aab8d5c748e0bdcc0d0f68c75d0d\nmsgid \":meth:`Document.xref_stream_raw`\"\nmsgstr \":meth:`Document.xref_stream_raw`\"\n\n#: ../../document.rst:128 6a98c4bce47b40fb8b4d4b7c65016f3e\nmsgid \"PDF only: raw stream source at :data:`xref`\"\nmsgstr \"PDF 전용: :data:`xref` 의 원시 스트림 소스\"\n\n#: ../../document.rst:129 90600270debe41fab02700603bd39668\nmsgid \":meth:`Document.xref_xml_metadata`\"\nmsgstr \":meth:`Document.xref_xml_metadata`\"\n\n#: ../../document.rst:129 fe9104e47feb4cde80ae1d21c7f02527\nmsgid \"PDF only: :data:`xref` of XML metadata\"\nmsgstr \"PDF 전용: XML 메타데이터의 :data:`xref`\"\n\n#: ../../document.rst:130 2a38972d01a14963af624e5647cd2437\nmsgid \":attr:`Document.chapter_count`\"\nmsgstr \":attr:`Document.chapter_count`\"\n\n#: ../../document.rst:130 9cffee9fac6b46f58dbb3f15f57f95f4\nmsgid \"number of chapters\"\nmsgstr \"장 수\"\n\n#: ../../document.rst:131 a65efc93b59e40b0919ed0734ea60467\nmsgid \":attr:`Document.FormFonts`\"\nmsgstr \":attr:`Document.FormFonts`\"\n\n#: ../../document.rst:131 31520e4940ce41adb477abd2bd8c1959\nmsgid \"PDF only: list of global widget fonts\"\nmsgstr \"PDF 전용: 전역 위젯 글꼴 목록\"\n\n#: ../../document.rst:132 403f10b0f86247ae9613df5b06ebe74d\nmsgid \":attr:`Document.is_closed`\"\nmsgstr \":attr:`Document.is_closed`\"\n\n#: ../../document.rst:132 56e7e9bcb0b04d82b8e24e904e1d785f\nmsgid \"has document been closed?\"\nmsgstr \"문서가 닫혔나요?\"\n\n#: ../../document.rst:133 8f07cc755bef4cbdab45a3d3a55ae298\nmsgid \":attr:`Document.is_dirty`\"\nmsgstr \":attr:`Document.is_dirty`\"\n\n#: ../../document.rst:133 538d5029daa1469090cf8ca7651b6fe2\nmsgid \"PDF only: has document been changed yet?\"\nmsgstr \"PDF 전용: 문서가 변경되었나요?\"\n\n#: ../../document.rst:134 10e61f565e024e6e90d25c631e429fb8\nmsgid \":attr:`Document.is_encrypted`\"\nmsgstr \":attr:`Document.is_encrypted`\"\n\n#: ../../document.rst:134 3d661d7413174d478ef8e8df9faf68d4\nmsgid \"document (still) encrypted?\"\nmsgstr \"문서가 (여전히) 암호화되어 있나요?\"\n\n#: ../../document.rst:135 3934359bba084c55ac3861d5a21333ab\nmsgid \":attr:`Document.is_fast_webaccess`\"\nmsgstr \":attr:`Document.is_fast_webaccess`\"\n\n#: ../../document.rst:135 3e6aed8f3b8a444e9371093edc090830\nmsgid \"is PDF linearized?\"\nmsgstr \"PDF가 선형화되었나요?\"\n\n#: ../../document.rst:136 db2d0d04655146cab76e2c677c42e6fa\nmsgid \":attr:`Document.is_form_pdf`\"\nmsgstr \":attr:`Document.is_form_pdf`\"\n\n#: ../../document.rst:136 3f8f952ffdf44f89929386cecb8ae090\nmsgid \"is this a Form PDF?\"\nmsgstr \"이것이 Form PDF인가요?\"\n\n#: ../../document.rst:137 d93ff3eb5ef04b868a661bcfa04e5789\nmsgid \":attr:`Document.is_pdf`\"\nmsgstr \":attr:`Document.is_pdf`\"\n\n#: ../../document.rst:137 7091e832546c41e5b2463e8848d6eaff\nmsgid \"is this a PDF?\"\nmsgstr \"이것이 PDF인가요?\"\n\n#: ../../document.rst:138 bcca823f15c242b783f465d7c49dbc08\nmsgid \":attr:`Document.is_reflowable`\"\nmsgstr \":attr:`Document.is_reflowable`\"\n\n#: ../../document.rst:138 126b44ccff1d442281f3bb8aae57fdb0\nmsgid \"is this a reflowable document?\"\nmsgstr \"이것이 재배치 가능한 문서인가요?\"\n\n#: ../../document.rst:139 3eaeba567fa543048ed9a6b7124708ff\nmsgid \":attr:`Document.is_repaired`\"\nmsgstr \":attr:`Document.is_repaired`\"\n\n#: ../../document.rst:139 6a01b1d2a2c543c4bb0a0af64488840c\nmsgid \"PDF only: has this PDF been repaired during open?\"\nmsgstr \"PDF 전용: 이 PDF가 열리는 동안 수리되었나요?\"\n\n#: ../../document.rst:140 70c231a16f1e415d92a69f2825540a3a\nmsgid \":attr:`Document.last_location`\"\nmsgstr \":attr:`Document.last_location`\"\n\n#: ../../document.rst:140 deaff42c88544730a696e276f1ee3356\nmsgid \"(chapter, pno) of last page\"\nmsgstr \"마지막 페이지의 (chapter, pno)\"\n\n#: ../../document.rst:141 2dfa14e25a6945a3a108582a1841c5f2\nmsgid \":attr:`Document.metadata`\"\nmsgstr \":attr:`Document.metadata`\"\n\n#: ../../document.rst:141 3c005bee965a4d6983014f54c70c0745\nmsgid \"metadata\"\nmsgstr \"metadata\"\n\n#: ../../document.rst:142 e2e76a2e26c84bb7abb2a1cf2c3886eb\nmsgid \":attr:`Document.markinfo`\"\nmsgstr \":attr:`Document.markinfo`\"\n\n#: ../../document.rst:142 adf532837b4946519e3adf5658feda0b\nmsgid \"PDF MarkInfo value\"\nmsgstr \"PDF MarkInfo 값\"\n\n#: ../../document.rst:143 c9b166961e114d45bae6093d7b289056\nmsgid \":attr:`Document.name`\"\nmsgstr \":attr:`Document.name`\"\n\n#: ../../document.rst:143 1a00c00be7f545d4b9f8322dac73b7a0\nmsgid \"filename of document\"\nmsgstr \"문서의 파일 이름\"\n\n#: ../../document.rst:144 c1d6eb720bf546b69ac234d91b82c81d\nmsgid \":attr:`Document.needs_pass`\"\nmsgstr \":attr:`Document.needs_pass`\"\n\n#: ../../document.rst:144 844e8ad327bb49ecabd4a2014d08633e\nmsgid \"require password to access data?\"\nmsgstr \"데이터 액세스에 비밀번호가 필요한가요?\"\n\n#: ../../document.rst:145 7a82a24938a444b78c372a8a64c5f6a6\nmsgid \":attr:`Document.outline`\"\nmsgstr \":attr:`Document.outline`\"\n\n#: ../../document.rst:145 51bb30f14a45459aafee41036779aefd\nmsgid \"first `Outline` item\"\nmsgstr \"첫 번째 `Outline` 항목\"\n\n#: ../../document.rst:146 035e8573692143248ff800c690d12a14\nmsgid \":attr:`Document.page_count`\"\nmsgstr \":attr:`Document.page_count`\"\n\n#: ../../document.rst:146 a16b9f3e62be464e99e6e17ee0d89eee\nmsgid \"number of pages\"\nmsgstr \"페이지 수\"\n\n#: ../../document.rst:147 f870fbb0ac57487d95999b5229a01a2c\nmsgid \":attr:`Document.permissions`\"\nmsgstr \":attr:`Document.permissions`\"\n\n#: ../../document.rst:147 ad91c7a04147452bb800342c2b61fa3e\nmsgid \"permissions to access the document\"\nmsgstr \"문서 액세스 권한\"\n\n#: ../../document.rst:148 1ab3ec62dcc849a89d1dfdef6c3f9450\nmsgid \":attr:`Document.pagemode`\"\nmsgstr \":attr:`Document.pagemode`\"\n\n#: ../../document.rst:148 03bd098a7c5b4168a2e597145c81b8b1\nmsgid \"PDF PageMode value\"\nmsgstr \"PDF PageMode 값\"\n\n#: ../../document.rst:149 ac546f38c66f4c619203c1e400047866\nmsgid \":attr:`Document.pagelayout`\"\nmsgstr \":attr:`Document.pagelayout`\"\n\n#: ../../document.rst:149 297c610806504aac9b1439935f9c876c\nmsgid \"PDF PageLayout value\"\nmsgstr \"PDF PageLayout 값\"\n\n#: ../../document.rst:150 c60c4a19eb464863a364d28d0cd6e111\nmsgid \":attr:`Document.version_count`\"\nmsgstr \":attr:`Document.version_count`\"\n\n#: ../../document.rst:150 4b3612a523ae45af99c60a18fb4d114b\nmsgid \"PDF count of versions\"\nmsgstr \"PDF 버전 수\"\n\n#: ../../document.rst:153 d2bdb0fb83164bf0959ae16f5d6dc6dd\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../document.rst:174 6451d24475784d32a99b011cdfcaa9f8\nmsgid \"Create a ``Document`` object.\"\nmsgstr \"``Document`` 객체를 생성합니다.\"\n\n#: ../../document.rst:176 64a565f2ff36449b87d82c1c99493b67\nmsgid \"With default parameters, a **new empty PDF** document will be created.\"\nmsgstr \"기본 매개변수를 사용하면 **새 빈 PDF** 문서가 생성됩니다.\"\n\n#: ../../document.rst:177 50f2c71dcec24699b5940564f67caf86\nmsgid \"If ``stream`` is given, then the document is created from memory.\"\nmsgstr \"``stream`` 이 제공되면 문서가 메모리에서 생성됩니다.\"\n\n#: ../../document.rst:178 33e92cae18af4d17895e380dd9ed6867\nmsgid \"\"\n\"If ``stream`` is `None`, then a document is created from the file given \"\n\"by ``filename``.\"\nmsgstr \"``stream`` 이 `None` 이면 ``filename`` 으로 지정된 파일에서 문서가 생성됩니다.\"\n\n#: ../../document.rst 011ee7615c7b431da28ad4a0f34a15ea\n#: 043e1f7f88294546bb28055113829f3c 05fbe4e150264d8c98845bf991aa451d\n#: 07ccc6435fc443a0b8b3ace5bde8df5d 0aaa1d00d7724cea8d50b7a0d1175fc5\n#: 0dbf133d5966474f80441769534086c9 170025aaca9c4ec8b7d13dec29e5b232\n#: 1ad58de6628f45ed85f92e616d5f1b89 1f8c9ef6c8874776abba5754093edb2b\n#: 1f91d09a2e3a4eb6902e439a24fc85d4 297d42ce6e624bdaab8ccf0148558cea\n#: 29d92736f06749be8093a4152834704f 2e955653fb8443519d7960d32db26bd2\n#: 33feb2dfd464453eb16ec8933f1eac03 3ce32169d9af4e76a0b465264e073258\n#: 3d86e3e54d5d4f0f8ac5cbf4cd3949db 3e5ef652ee204a13b2200d2ff5f1e7e5\n#: 3f473faa03a649c287642f4ba4d971ba 408b5b208d5b49e88dbaf684542bfbfa\n#: 409b8fceac504f4abf1ef1ec7d77eb72 49df8a4b95154193b5df2620f0a275a0\n#: 4bedcac6800d4ae09f2817f3ed1d0e62 4c32267c73b84f9e97295b8c549bbcc4\n#: 4dbed9def0b246b6b317dee344729ac6 4ef2802c907044f692ad144a6b25c4ef\n#: 5163d8880d6b4688b9e93be572d6162e 58ffcea5f2524ad5bdccc8bf017574e4\n#: 63771f4a8438461ea1aa13c8daa905ef 669d28e0f6ac4195bdb67e532d1b819d\n#: 6e395ebc7d9c4cdb8ebfc086b16d8e71 754278aec73b41d698a40b9364c3fb51\n#: 78f440188fe14ece96c38413324756b6 7a359b69c8994a4f9c556dcfbe7a3f3b\n#: 7c13ff43ff5746f29a5067fee7748cca 7d3c575cf7d8441abeb9e17d24ff5b9c\n#: 7eacdc9a402a4d2d94e1c4eb1961a772 8e343c1256444dee9aea92a341606973\n#: 93411fcbe3c64165a55f34297d058d6a 95500979035e4bc38e1e37be369b6f4a\n#: 961048fa2e2b4641ab46db1f4b0f7713 962cc6f293284ada9e7b8ac28a1ae338\n#: 9960f80414664467b52697561ffb7dda 997d6aa772ea479d8b19880effb45444\n#: 9c5ac8955ee944f1a0ab7a60ae6867c3 a00436c513104a7288f6d4cc1f19f5a9\n#: a32902bfa30f4d848b38175e545779a5 a3f306f98e844f58a22519da78bdf879\n#: a7d283f20a2f47349e35ca0d8cc52cd8 ab338f78ff44446eb34411310099834c\n#: ad31c573327c469181938b01534aed1a af00f235420648bab28e6d0b79d4a243\n#: b6df452370724f7e9e15bb7c78273856 ba89cb4ecf3d423d95414de73be52994\n#: bafc21087f4c4e69ad5d5dea423347e9 bbd53cac62e74bec85990b4148d9d8cb\n#: bec305b9b0af437c9cfabb6a81c4bec5 c0870c34fbca44a5b226b996aaee33fe\n#: c28037c809d049299e43f1b9b7fb1d9c cc7b4803acfc4b74840a07530bb2412e\n#: d2a8f4dd5628414db4250530dd010cae d3184e2ca6a34686a5e8c1a90e5b3eb5\n#: d8432653099c4ac989efe85ee548a285 dc42b76dbc5f4e19ab4e6f87bb3b29a4\n#: dc772479597c49be8700b8a5f272edc5 e0923d8b89424ea384e0f5a178804d1b\n#: e51810e9ad3f438298fb77f28bcb042c ec89e80f8b434a17941d0bd8ad34e9a7\n#: eeda58a336794902b520182212b35979 f18fa2a6b3114ecb8802728c1601bb23\n#: f5e02e10e6ac42fbb50930c6df235f8c f758028805654d02a020ffbbad2626f8\n#: fa5511f7a1f448479736a410f199e0c4 fcb76ae90bf847dfb50d5b120e8fd97b\n#: fe71ecaaa4c44a7aaa7b89d0e916ca8f\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../document.rst:180 014acda4567c436291e86a2b00e3fcaa\nmsgid \"\"\n\"A UTF-8 string or ``pathlib.Path`` object containing a file path. The \"\n\"document type is always determined from the file content.  The \"\n\"``filetype`` parameter is ignored, except when content inspection was \"\n\"unsuccessful. This is regularly the case for plain text types like \"\n\"\\\"txt\\\", \\\"html\\\", \\\"xml\\\" etc. with a wrong or missing file extension.\"\nmsgstr \"\"\n\"파일 경로를 포함하는 UTF-8 문자열 또는 ``pathlib.Path`` 객체. 문서 타입은 항상 파일 콘텐츠에서 결정됩니다. \"\n\"``filetype`` 매개변수는 콘텐츠 검사가 실패한 경우를 제외하고 무시됩니다. 잘못되었거나 누락된 파일 확장자를 가진 \"\n\"\\\"txt\\\", \\\"html\\\", \\\"xml\\\" 등과 같은 일반 텍스트 타입의 경우가 일반적입니다.\"\n\n#: ../../document.rst:182 97a008f8fbe04599ad4e4ba4d6bdcaf7\nmsgid \"\"\n\"A memory area containing file data. The document type is always detected \"\n\"from the data content. The ``filetype`` parameter is ignored, except when\"\n\" content inspection was unsuccessful. This is regularly the case for \"\n\"plain text types like \\\"txt\\\", \\\"html\\\", \\\"xml\\\" etc.\"\nmsgstr \"\"\n\"파일 데이터를 포함하는 메모리 영역. 문서 타입은 항상 데이터 콘텐츠에서 감지됩니다. ``filetype`` 매개변수는 콘텐츠 \"\n\"검사가 실패한 경우를 제외하고 무시됩니다. \\\"txt\\\", \\\"html\\\", \\\"xml\\\" 등과 같은 일반 텍스트 타입의 경우가 \"\n\"일반적입니다.\"\n\n#: ../../document.rst:184 f94f9deed99649d4914149d0f84ee237\nmsgid \"\"\n\"A string specifying the type of document. This is only ever needed when \"\n\"file content inspection fails. Text types like \\\"txt\\\", \\\"html\\\", \\\"xml\\\"\"\n\" etc. cannot be disambiguated by their content. When such files are \"\n\"provided in memory or being provided with the wrong file extension, this \"\n\"parameter **must** be used.\"\nmsgstr \"\"\n\"문서 타입을 지정하는 문자열. 파일 콘텐츠 검사가 실패할 때만 필요합니다. \\\"txt\\\", \\\"html\\\", \\\"xml\\\" 등과 \"\n\"같은 텍스트 타입은 콘텐츠로 구분할 수 없습니다. 이러한 파일이 메모리에서 제공되거나 잘못된 파일 확장자로 제공되는 경우 이 \"\n\"매개변수를 **반드시** 사용해야 합니다.\"\n\n#: ../../document.rst:186 4fa028bb7c5642588afa6cc6342c5a88\nmsgid \"\"\n\"a rectangle specifying the desired page size. This parameter is only \"\n\"meaningful for documents with a variable page layout (\\\"reflowable\\\" \"\n\"documents), like e-books or HTML, and ignored otherwise. If specified, it\"\n\" must be a non-empty, finite rectangle with top-left coordinates (0, 0). \"\n\"Together with parameter :data:`fontsize`, each page will be accordingly \"\n\"laid out and hence also determine the number of pages.\"\nmsgstr \"\"\n\"원하는 페이지 크기를 지정하는 사각형. 이 매개변수는 전자책이나 HTML과 같은 가변 페이지 레이아웃(\\\"재배치 가능한\\\" 문서)이\"\n\" 있는 문서에만 의미가 있으며, 그렇지 않으면 무시됩니다. 지정된 경우 왼쪽 위 좌표가 (0, 0)인 비어 있지 않은 유한 \"\n\"사각형이어야 합니다. :data:`fontsize` 매개변수와 함께 각 페이지가 그에 따라 레이아웃되므로 페이지 수도 결정됩니다.\"\n\n#: ../../document.rst:188 0e700acb9750499884fa95729f70533c\nmsgid \"\"\n\"may used together with ``height`` as an alternative to ``rect`` to \"\n\"specify layout information.\"\nmsgstr \"레이아웃 정보를 지정하기 위해 ``height`` 와 함께 ``rect`` 의 대안으로 사용할 수 있습니다.\"\n\n#: ../../document.rst:190 011cb8d1a5e14e1c9362a4977467f8b3\nmsgid \"\"\n\"may used together with ``width`` as an alternative to ``rect`` to specify\"\n\" layout information.\"\nmsgstr \"레이아웃 정보를 지정하기 위해 ``width`` 와 함께 ``rect`` 의 대안으로 사용할 수 있습니다.\"\n\n#: ../../document.rst:192 4811a6a492ef40a09b407d00f0d2e3b9\nmsgid \"\"\n\"the default :data:`fontsize` for reflowable document types. This \"\n\"parameter is ignored if none of the parameters ``rect`` or ``width`` and \"\n\"``height`` are specified. Will be used to calculate the page layout.\"\nmsgstr \"\"\n\"재배치 가능한 문서 타입의 기본 :data:`fontsize`. ``rect`` 또는 ``width`` 및 ``height`` \"\n\"매개변수가 지정되지 않은 경우 이 매개변수는 무시됩니다. 페이지 레이아웃을 계산하는 데 사용됩니다.\"\n\n#: ../../document.rst abcb9a746c2b4f62abeed6ccf8efa17d\n#: f2545763439a4ee594dbd98ad0edf43e\nmsgid \"Raises\"\nmsgstr \"발생\"\n\n#: ../../document.rst:194 f470cca528b745c9a90831df3e861ea2\nmsgid \"if the *type* of any parameter does not conform.\"\nmsgstr \"매개변수의 *타입* 이 적합하지 않은 경우.\"\n\n#: ../../document.rst:195 8c21a351ef83465497530b3df321b248\nmsgid \"\"\n\"if the file / path cannot be found. Re-implemented as subclass of \"\n\"`RuntimeError`.\"\nmsgstr \"파일/경로를 찾을 수 없는 경우. `RuntimeError` 의 하위 클래스로 재구현됨.\"\n\n#: ../../document.rst:196 fffb535dd70c40419e33cb85c3478a56\nmsgid \"\"\n\"if the file / path is empty or the `bytes` object in memory has zero \"\n\"length. A subclass of `FileDataError` and `RuntimeError`.\"\nmsgstr \"\"\n\"파일/경로가 비어 있거나 메모리의 `bytes` 객체 길이가 0인 경우. `FileDataError` 및 `RuntimeError`\"\n\" 의 하위 클래스.\"\n\n#: ../../document.rst:197 2da86a34dee74be2bfc325592465ca50\nmsgid \"if an unknown file type is explicitly specified.\"\nmsgstr \"알 수 없는 파일 타입이 명시적으로 지정된 경우.\"\n\n#: ../../document.rst:198 72d5fd6fabfb4775b794aad117955ffd\nmsgid \"\"\n\"if the document has an invalid structure for the given type -- or is no \"\n\"file at all (but e.g. a folder). A subclass of `RuntimeError`.\"\nmsgstr \"문서가 주어진 타입에 대해 유효하지 않은 구조를 가지거나 파일이 아닌 경우(예: 폴더). `RuntimeError` 의 하위 클래스.\"\n\n#: ../../document.rst 0b9565acff23447ebd391dc02025defd\n#: 0d46c89c1dc84ef7a8b2ce78c73fa2f0 0e133b2b68684e80825b5ffd442964a6\n#: 1ebf59777711413282c7b813e486b14d 22e92858f96749bd979c8b1d97f53141\n#: 2582886835ba484cbc6362bcd0294110 29b3f69d713b4e2baf28c15d8335d4d0\n#: 2daf9297b2b947f59c29603028bdc171 2fbd3af7a9dd47bcb918a2afc3d3d2ae\n#: 333d2ff36ce5424a9a6a9f0ef315e9f6 38e8965bfa884723862a910e35980260\n#: 39f9bc12c5d146b98e014503e81bbeab 43dcb947c54d4e5b813016fcd28911fb\n#: 444b74f48dd74a199f9add5e1f9af762 46303bbfa9d64c1988fe842589733a4b\n#: 46c1cf4166714992b0f5a1a1ccb20835 4865908155da41849fdb6be46efbab80\n#: 5eedd5ec48ec43009b74aa21cb5a4f5e 675da3dffdee4242ad59c756d3d4ec2d\n#: 689c89e5a32f43e09e3ea270734096d9 7adeeadfb8a84b9e8790609ba5bc7765\n#: 7c3cba7c278941deafdcf00e8c3fc7c8 7ff99ed95e934a59b82878c8068a10f8\n#: 81fd28a92da849b894299938c7262571 8f2c0027871d4dbfa63523294209dd4d\n#: 901880de4b364792adbac5aac0281b3b 903ff8cf00ef42a2af64f374cb0cdec3\n#: 912cd9c328854abcac39f0139f5e13da 98a3f5b39c0e4eeb9588b83976f1b954\n#: ab8d5df67c824ec08658e756765d4bb5 b1c55529a2d64de8993763d1ef44d0dd\n#: b31f42a8e4fd414ea57fb4d437cf2e73 c2982953c7264eca9b0074df8d337bce\n#: c762118fd4d842038a9dff91cd1c85cd c77e00acb46640089980b06ee883d005\n#: cc8f358941704f05baab8f5e45775fc8 d3a808fe6600422fbd26e1dc8906851b\n#: d6d5325a2e7f4d798ffd6326d1c898c2 dc36f475c23841168562540b7aa1b81b\n#: e12cf9fc8351457dae9235c1d8b88e4a e2b42ca22d734917b9217f6ad6021891\n#: eac82d309f514f35a8cd27a08ec37d2a efae7f82f4944c26a45f8b40aac6da5a\n#: f504824956a7474fa92c3133ca3ba45c fc84c379722e4558b9622025890c4170\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../document.rst:200 5379105ad1f54307a38807d4a326c24c\nmsgid \"\"\n\"A document object. If the document cannot be created, an exception is \"\n\"raised in the above sequence. Note that PyMuPDF-specific exceptions, \"\n\"`FileNotFoundError`, `EmptyFileError` and `FileDataError` are intercepted\"\n\" if you check for `RuntimeError`.  In case of problems you can see more \"\n\"detail in the internal messages store: \"\n\"`print(pymupdf.TOOLS.mupdf_warnings())` (which will be emptied by this \"\n\"call, but you can also prevent this -- consult \"\n\":meth:`Tools.mupdf_warnings`).\"\nmsgstr \"\"\n\n#: ../../document.rst:200 2b78b15da31c4933938a15d26f37e5a2\nmsgid \"\"\n\"A document object. If the document cannot be created, an exception is \"\n\"raised in the above sequence. Note that PyMuPDF-specific exceptions, \"\n\"`FileNotFoundError`, `EmptyFileError` and `FileDataError` are intercepted\"\n\" if you check for `RuntimeError`.\"\nmsgstr \"\"\n\"문서 객체. 문서를 생성할 수 없으면 위 순서에서 예외가 발생합니다. |PyMuPDF| 전용 예외인 \"\n\"`FileNotFoundError`, `EmptyFileError` 및 `FileDataError` 는 `RuntimeError` \"\n\"를 확인하면 가로채집니다.\"\n\n#: ../../document.rst:202 5cfeca13702a454fa2a279a1c95212cb\nmsgid \"\"\n\"In case of problems you can see more detail in the internal messages \"\n\"store: `print(pymupdf.TOOLS.mupdf_warnings())` (which will be emptied by \"\n\"this call, but you can also prevent this -- consult \"\n\":meth:`Tools.mupdf_warnings`).\"\nmsgstr \"\"\n\"문제가 있는 경우 내부 메시지 저장소에서 더 자세한 내용을 볼 수 있습니다: \"\n\"`print(pymupdf.TOOLS.mupdf_warnings())` (이 호출로 비워지지만, 이를 방지할 수도 있습니다. \"\n\":meth:`Tools.mupdf_warnings` 참조).\"\n\n#: ../../document.rst:204 85a57c6989194e89b1b69856a7d9a394\nmsgid \"Overview of possible forms, note: `open` is a synonym of `Document`::\"\nmsgstr \"가능한 형식 개요, 참고: `open` 은 `Document` 의 동의어입니다::\"\n\n#: ../../document.rst:221 3e33d53ee5224879a1ea5e05123c6739\nmsgid \"\"\n\"Raster images with a wrong (but supported) file extension **are no \"\n\"problem**. MuPDF will determine the correct image type when file \"\n\"**content** is actually accessed and will process it without complaint.\"\nmsgstr \"\"\n\"잘못된(하지만 지원되는) 파일 확장자를 가진 래스터 이미지는 **문제가 되지 않습니다**. |MuPDF| 는 파일 **콘텐츠** 가\"\n\" 실제로 액세스될 때 올바른 이미지 타입을 결정하고 불만 없이 처리합니다.\"\n\n#: ../../document.rst:223 065b06239b8d411e91f31a11cf0b763b\nmsgid \"\"\n\"The Document class can be also be used as a **context manager**. Exiting \"\n\"the content manager will close the document automatically.\"\nmsgstr \"\"\n\"Document 클래스는 **context manager** 로도 사용할 수 있습니다. 콘텐츠 관리자를 종료하면 문서가 자동으로 \"\n\"닫힙니다.\"\n\n#: ../../document.rst:239 ../../document.rst:249 ../../document.rst:309\n#: ../../document.rst:355 590a057c4b6b44d6a0918523f52f6f9d\n#: 8e6e393f5b684e0bafd4caf83d908e86 b5812f621a6c4e63bf0172b3f1d3cc29\n#: fc7e417737a44f688ae8d2191b3b7ab9\nmsgid \"New in v1.18.4\"\nmsgstr \"v1.18.4에서 새로 추가됨\"\n\n#: ../../document.rst:241 7e3878780e334136b767b9359746ea53\nmsgid \"\"\n\"Return the cross reference number of an :data:`OCG` or :data:`OCMD` \"\n\"attached to an image or form xobject.\"\nmsgstr \"이미지 또는 폼 xobject에 첨부된 :data:`OCG` 또는 :data:`OCMD` 의 교차 참조 번호를 반환합니다.\"\n\n#: ../../document.rst:243 02a0e1e835614fec97682f8673d2a44a\nmsgid \"\"\n\"the :data:`xref` of an image or form xobject. Valid such cross reference \"\n\"numbers are returned by :meth:`Document.get_page_images`, resp. \"\n\":meth:`Document.get_page_xobjects`. For invalid numbers, an exception is \"\n\"raised.\"\nmsgstr \"\"\n\"이미지 또는 폼 xobject의 :data:`xref`. 유효한 교차 참조 번호는 \"\n\":meth:`Document.get_page_images` 또는 :meth:`Document.get_page_xobjects` 에 \"\n\"의해 반환됩니다. 유효하지 않은 번호의 경우 예외가 발생합니다.\"\n\n#: ../../document.rst 03106ba1def448ee947cabdaf71b64af\n#: 0323e07d28b34d3db57c8793633c6693 03fa12cfb70346d0a59357cc2fac0b53\n#: 1aba81a7b43b479e8b6c20dfc4b285a7 280115f8654a46c19b9605b53ae5cb25\n#: 293f411b7cde49c9bdcfd193dcdcdcc3 311a57ac78794e2e90319718b2abee35\n#: 3870aff916b940ebae177370b1d79d02 3b8f4617cb6a4273bc5cc5871f6dd926\n#: 3d82dbb2f594402b9a35693796ef923b 42758cfc2b43478abb870a4303f08b46\n#: 4cc5ae419ec54d569bbe6924027803f8 5236a41b0be944409e172dc5b2e4bf86\n#: 5a9aaff08bd04bca832bcab4af64df9c 69766670b3434e69bcd622dc0dc9e27d\n#: 7a81d4febe394e368e4f731ec0edcbd3 7ae03a444f9b4584adfedd95fb3e1832\n#: 7c50040809f54baea13ac5bf14e7b8b5 81e419072a7040609488c69f1a3ee6a9\n#: 8262bfce4d2447748d541f718f81d09f 83054de5a1f24a5e9e84a905db0c8a15\n#: a3d3a8ca642c4433beeef23cc55ccc0c ae294c0d81814ae680474407dc878475\n#: af12de8b069e4c0f89174e9b7b798f8c b591f61bc81144a3be6c8d4ca224d43c\n#: bae2e3773fea460a9bec117512d86b4e d1aabcba697f4ccca6722d874ddc4b91\n#: d1c59ac972354c3bb0e8960dc03143fc d22157f38e4c482b9f059900ceea860e\n#: d41d99df291f4539a09e041db9a01693 e8696467db1a43938ae8baf7d06fbe94\n#: f079281dd45045a98b9fa58f73453901 f165f1911ae248fe8e958ed35a1c95f3\n#: f43b1009cbe1438595747275491e5fb3 fa67f21ad4ba4619b33e9d5e01dd956c\n#: fb20d7ae8e29407a93c1316afa952e4e\nmsgid \"Return type\"\nmsgstr \"반환 타입\"\n\n#: ../../document.rst:245 54f83b65a1444382948e30d8b439e254\nmsgid \"\"\n\"the cross reference number of an optional contents object or zero if \"\n\"there is none.\"\nmsgstr \"선택적 콘텐츠 객체의 교차 참조 번호 또는 없는 경우 0.\"\n\n#: ../../document.rst:251 96b8fa378c624f70997c27f227a1cb0c\nmsgid \"\"\n\"If :data:`xref` represents an image or form xobject, set or remove the \"\n\"cross reference number *ocxref* of an optional contents object.\"\nmsgstr \"\"\n\":data:`xref` 가 이미지 또는 form xobject를 나타내는 경우 선택적 콘텐츠 객체의 교차 참조 번호 *ocxref*\"\n\" 를 설정하거나 제거합니다.\"\n\n#: ../../document.rst:253 ccd437bf85874e6796fd6bc48db22b17\nmsgid \"\"\n\"the :data:`xref` of an image or form xobject [#f5]_. Valid such cross \"\n\"reference numbers are returned by :meth:`Document.get_page_images`, resp.\"\n\" :meth:`Document.get_page_xobjects`. For invalid numbers, an exception is\"\n\" raised.\"\nmsgstr \"\"\n\"이미지 또는 form xobject의 :data:`xref` [#f5]_. 유효한 이러한 교차 참조 번호는 \"\n\":meth:`Document.get_page_images`, 각각 :meth:`Document.get_page_xobjects` \"\n\"에서 반환됩니다. 잘못된 번호의 경우 예외가 발생합니다.\"\n\n#: ../../document.rst:254 01092297808443f49fec83f07bf7c1b1\nmsgid \"\"\n\"the :data:`xref` number of an :data:`OCG` / :data:`OCMD`. If not zero, an\"\n\" invalid reference raises an exception. If zero, any OC reference is \"\n\"removed.\"\nmsgstr \"\"\n\":data:`OCG` / :data:`OCMD` 의 :data:`xref` 번호. 0이 아니면 유효하지 않은 참조가 예외를 \"\n\"발생시킵니다. 0이면 모든 OC 참조가 제거됩니다.\"\n\n#: ../../document.rst:259 ../../document.rst:269 ../../document.rst:280\n#: ../../document.rst:292 ../../document.rst:366 ../../document.rst:378\n#: ../../document.rst:400 ../../document.rst:418 ../../document.rst:434\n#: 0cdb3bd2d31b4b66a2c59a426a908115 11d1e22fc75f4c299aaa32ee9660e732\n#: 651472cf224d4e7cb1c4607e35070f52 7b127219d8df4b649a052c0a2b97c25e\n#: 91ec18953623402d83c21367dfbac24b b1c95139441d4a9cae92305b838dc63e\n#: b3ab1a356e21428fb3c661c2a380695c ed9937dd5d174b9ea28d6f61bcb82e87\n#: fca4c990f25d40c091f29bd4f8738a73\nmsgid \"New in v1.18.3\"\nmsgstr \"v1.18.3에서 새로 추가됨\"\n\n#: ../../document.rst:261 e496afcef3664b1f81d450a3619e61af\nmsgid \"\"\n\"Show optional layer configurations. There always is a standard one, which\"\n\" is not included in the response.\"\nmsgstr \"선택적 레이어 구성을 표시합니다. 항상 표준 구성이 있으며, 응답에 포함되지 않습니다.\"\n\n#: ../../document.rst:271 f799d02d101b4380aaaf1c4db1b48eb6\nmsgid \"\"\n\"Add an optional content configuration. Layers serve as a collection of ON\"\n\" / OFF states for optional content groups and allow fast visibility \"\n\"switches between different views on the same document.\"\nmsgstr \"\"\n\"선택적 콘텐츠 구성을 추가합니다. 레이어는 선택적 콘텐츠 그룹의 ON/OFF 상태 모음 역할을 하며, 동일한 문서의 다른 보기 간 \"\n\"빠른 가시성 전환을 허용합니다.\"\n\n#: ../../document.rst:273 08dc8765d1304fd7b44f572a0744f0f1\nmsgid \"arbitrary name.\"\nmsgstr \"임의의 이름.\"\n\n#: ../../document.rst:274 98d7de11d27e443691ea0949884cd849\nmsgid \"(optional) creating software.\"\nmsgstr \"(선택 사항) 생성 소프트웨어.\"\n\n#: ../../document.rst:275 0d34230a987b46f481e1e00efa0aea08\nmsgid \"\"\n\"a sequence of OCG :data:`xref` numbers which should be set to ON when \"\n\"this layer gets activated. All OCGs not listed here will be set to OFF.\"\nmsgstr \"\"\n\"이 레이어가 활성화될 때 ON으로 설정해야 하는 OCG :data:`xref` 번호 시퀀스. 여기에 나열되지 않은 모든 OCG는 \"\n\"OFF로 설정됩니다.\"\n\n#: ../../document.rst:282 bf8e78a200584541a6aa40bfe589b2cb\nmsgid \"\"\n\"Switch to a document view as defined by the optional layer's \"\n\"configuration number. This is temporary, except if established as \"\n\"default.\"\nmsgstr \"선택적 레이어의 구성 번호로 정의된 문서 보기로 전환합니다. 기본값으로 설정되지 않은 경우 임시입니다.\"\n\n#: ../../document.rst:284 a5c2d8c7581d4bdc8b1aa451802f594f\nmsgid \"config number as returned by :meth:`Document.layer_configs`.\"\nmsgstr \":meth:`Document.layer_configs` 에서 반환된 구성 번호.\"\n\n#: ../../document.rst:285 1bd81b54cedd49f18769be40480ce85d\nmsgid \"make this the default configuration.\"\nmsgstr \"이것을 기본 구성으로 만듭니다.\"\n\n#: ../../document.rst:287 90648b40bc2941c9a74ee11db323a3af\nmsgid \"\"\n\"Activates the ON / OFF states of OCGs as defined in the identified layer.\"\n\" If ``as_default=True``, then additionally all layers, including the \"\n\"standard one, are merged and the result is written back to the standard \"\n\"layer, and **all optional layers are deleted**.\"\nmsgstr \"\"\n\"식별된 레이어에 정의된 대로 OCG의 ON/OFF 상태를 활성화합니다. ``as_default=True`` 이면 표준 레이어를 \"\n\"포함한 모든 레이어가 병합되고 결과가 표준 레이어에 다시 쓰여지며, **모든 선택적 레이어가 삭제됩니다**.\"\n\n#: ../../document.rst:294 64c365c54c204dc9a79d20e140c88f37\nmsgid \"\"\n\"Add an optional content group. An OCG is the most important unit of \"\n\"information to determine object visibility. For a PDF, in order to be \"\n\"regarded as having optional content, at least one OCG must exist.\"\nmsgstr \"\"\n\"선택적 콘텐츠 그룹을 추가합니다. OCG는 객체 가시성을 결정하는 가장 중요한 정보 단위입니다. PDF의 경우 선택적 콘텐츠를 가진\"\n\" 것으로 간주되려면 최소한 하나의 OCG가 있어야 합니다.\"\n\n#: ../../document.rst:296 582c5907afae46aa9917cffb6bbc7e9d\nmsgid \"arbitrary name. Will show up in supporting PDF viewers.\"\nmsgstr \"임의의 이름. 지원하는 PDF 뷰어에 표시됩니다.\"\n\n#: ../../document.rst:297 f3ea3172645446aab9bd34bdaaa95772\nmsgid \"layer configuration number. Default -1 is the standard configuration.\"\nmsgstr \"레이어 구성 번호. 기본값 -1은 표준 구성입니다.\"\n\n#: ../../document.rst:298 17c0cb89e5074470a202a4250ea9f078\nmsgid \"standard visibility status for objects pointing to this OCG.\"\nmsgstr \"이 OCG를 가리키는 객체의 표준 가시성 상태.\"\n\n#: ../../document.rst:299 c62203a85b33422185c8017d9e36af57\nmsgid \"\"\n\"a string or list of strings declaring the visibility intents. There are \"\n\"two PDF standard values to choose from: \\\"View\\\" and \\\"Design\\\". Default \"\n\"is \\\"View\\\". Correct **spelling is important**.\"\nmsgstr \"\"\n\"가시성 의도를 선언하는 문자열 또는 문자열 목록. 선택할 수 있는 두 가지 PDF 표준 값이 있습니다: \\\"View\\\" 와 \"\n\"\\\"Design\\\". 기본값은 \\\"View\\\" 입니다. 올바른 **철자가 중요합니다**.\"\n\n#: ../../document.rst:300 700ecf059c634c4296e822ca1f324ace\nmsgid \"\"\n\"another influencer for OCG visibility. This will become part of the OCG's\"\n\" `/Usage` key. There are two PDF standard values to choose from: \"\n\"\\\"Artwork\\\" and \\\"Technical\\\". Default is \\\"Artwork\\\". Please only change\"\n\" when required.\"\nmsgstr \"\"\n\"OCG 가시성에 영향을 미치는 또 다른 요소. 이것은 OCG의 `/Usage` 키의 일부가 됩니다. 선택할 수 있는 두 가지 PDF\"\n\" 표준 값이 있습니다: \\\"Artwork\\\" 와 \\\"Technical\\\". 기본값은 \\\"Artwork\\\" 입니다. 필요한 경우에만 \"\n\"변경하세요.\"\n\n#: ../../document.rst:302 3145601d35874b718a0c6f74a6a309b8\nmsgid \"\"\n\":data:`xref` of the created OCG. Use as entry for `oc` parameter in \"\n\"supporting objects.\"\nmsgstr \"생성된 OCG의 :data:`xref`. 지원 객체의 `oc` 매개변수 항목으로 사용합니다.\"\n\n#: ../../document.rst:304 4b1189a56ca745249bc4b28c2436ca85\nmsgid \"\"\n\"Multiple OCGs with identical parameters may be created. This will not \"\n\"cause problems. Garbage option 3 of :meth:`Document.save` will get rid of\"\n\" any duplicates.\"\nmsgstr \"\"\n\"동일한 매개변수를 가진 여러 OCG가 생성될 수 있습니다. 이것은 문제를 일으키지 않습니다. :meth:`Document.save`\"\n\" 의 Garbage 옵션 3은 모든 중복을 제거합니다.\"\n\n#: ../../document.rst:311 e5f3f34164f14819912a3b03637210d1\nmsgid \"\"\n\"Create or update an :data:`OCMD`, **Optional Content Membership \"\n\"Dictionary.**\"\nmsgstr \":data:`OCMD`, **Optional Content Membership Dictionary** 를 생성하거나 업데이트합니다.\"\n\n#: ../../document.rst:313 cb1088cf2f894416ae66a48c48f1a083\nmsgid \":data:`xref` of the OCMD to be updated, or 0 for a new OCMD.\"\nmsgstr \"업데이트할 OCMD의 :data:`xref` 또는 새 OCMD의 경우 0.\"\n\n#: ../../document.rst:314 369dd3e1a5934cd1ac9d74315ec46778\nmsgid \"a sequence of :data:`xref` numbers of existing :data:`OCG` PDF objects.\"\nmsgstr \"기존 :data:`OCG` PDF 객체의 :data:`xref` 번호 시퀀스.\"\n\n#: ../../document.rst:315 bf9b40e2e22c4f97953a165672812856\nmsgid \"\"\n\"one of \\\"AnyOn\\\" (default), \\\"AnyOff\\\", \\\"AllOn\\\", \\\"AllOff\\\" (mixed or \"\n\"lower case).\"\nmsgstr \"\\\"AnyOn\\\" (기본값), \\\"AnyOff\\\", \\\"AllOn\\\", \\\"AllOff\\\" 중 하나(대소문자 혼합 또는 소문자).\"\n\n#: ../../document.rst:316 88174bf787d4486d91457a1003cc8d34\nmsgid \"\"\n\"a \\\"visibility expression\\\". This is a list of arbitrarily nested other \"\n\"lists -- see explanation below. Use as an alternative to the combination \"\n\"*ocgs* / *policy* if you need to formulate more complex conditions.\"\nmsgstr \"\"\n\"\\\"가시성 표현식\\\". 이것은 임의로 중첩된 다른 목록의 목록입니다. 아래 설명을 참조하세요. 더 복잡한 조건을 공식화해야 하는 \"\n\"경우 *ocgs* / *policy* 조합의 대안으로 사용합니다.\"\n\n#: ../../document.rst:318 8928d324f6024b2a9bb8500b1ff504f4\nmsgid \"\"\n\":data:`xref` of the OCMD. Use as `oc=xref` parameter in supporting \"\n\"objects, and respectively in :meth:`Document.set_oc` or \"\n\":meth:`Annot.set_oc`.\"\nmsgstr \"\"\n\"OCMD의 :data:`xref`. 지원 객체에서 `oc=xref` 매개변수로 사용하고, 각각 \"\n\":meth:`Document.set_oc` 또는 :meth:`Annot.set_oc` 에서 사용합니다.\"\n\n#: ../../document.rst:322 77b7cd5933544b45be8e20f83eec5ec1\nmsgid \"\"\n\"Like an OCG, an OCMD has a visibility state ON or OFF, and it can be used\"\n\" like an OCG. In contrast to an OCG, the OCMD state is determined by \"\n\"evaluating the state of one or more OCGs via special forms of **boolean \"\n\"expressions.** If the expression evaluates to true, the OCMD state is ON \"\n\"and OFF for false.\"\nmsgstr \"\"\n\"OCG와 마찬가지로 OCMD는 ON 또는 OFF 가시성 상태를 가지며 OCG처럼 사용할 수 있습니다. OCG와 달리 OCMD 상태는\"\n\" **부울 표현식** 의 특수 형식을 통해 하나 이상의 OCG 상태를 평가하여 결정됩니다. 표현식이 true로 평가되면 OCMD \"\n\"상태는 ON이고, false이면 OFF입니다.\"\n\n#: ../../document.rst:324 c5c61ce450e24c5e9ea1fa1bad8b6751\nmsgid \"There are two ways to formulate OCMD visibility:\"\nmsgstr \"OCMD 가시성을 공식화하는 두 가지 방법이 있습니다:\"\n\n#: ../../document.rst:326 462d8be9d3a5420cbd8cb048c7eeb28b\nmsgid \"\"\n\"Use the combination of *ocgs* and *policy*: The *policy* value is \"\n\"interpreted as follows:\"\nmsgstr \"*ocgs* 와 *policy* 조합 사용: *policy* 값은 다음과 같이 해석됩니다:\"\n\n#: ../../document.rst:328 86b63ed8ef38451ebf96d60ec77bce37\nmsgid \"AnyOn -- (default) true if at least one OCG is ON.\"\nmsgstr \"AnyOn -- (기본값) 최소한 하나의 OCG가 ON이면 true.\"\n\n#: ../../document.rst:329 f3f796350ef742cf9d6068183f6bcc38\nmsgid \"AnyOff -- true if at least one OCG is OFF.\"\nmsgstr \"AnyOff -- 최소한 하나의 OCG가 OFF이면 true.\"\n\n#: ../../document.rst:330 adc9429b7f46427dbfb52493bd1c0204\nmsgid \"AllOn -- true if all OCGs are ON.\"\nmsgstr \"AllOn -- 모든 OCG가 ON이면 true.\"\n\n#: ../../document.rst:331 daa610b72ef4437f8457d46428a9a2b1\nmsgid \"AllOff -- true if all OCGs are OFF.\"\nmsgstr \"AllOff -- 모든 OCG가 OFF이면 true.\"\n\n#: ../../document.rst:333 7014ef73277e45d4a51f02398cfaadd8\nmsgid \"\"\n\"Suppose you want two PDF objects be displayed exactly one at a time (if \"\n\"one is ON, then the other one must be OFF):\"\nmsgstr \"두 개의 PDF 객체를 한 번에 정확히 하나씩만 표시하려는 경우(하나가 ON이면 다른 하나는 OFF여야 함):\"\n\n#: ../../document.rst:335 658089c6f0b9489686f71ec565438854\nmsgid \"\"\n\"Solution: use an **OCG** for object 1 and an **OCMD** for object 2. \"\n\"Create the OCMD via `set_ocmd(ocgs=[xref], policy=\\\"AllOff\\\")`, with the \"\n\":data:`xref` of the OCG.\"\nmsgstr \"\"\n\"해결책: 객체 1에 **OCG** 를 사용하고 객체 2에 **OCMD** 를 사용합니다. OCG의 :data:`xref` 로 \"\n\"`set_ocmd(ocgs=[xref], policy=\\\"AllOff\\\")` 를 통해 OCMD를 생성합니다.\"\n\n#: ../../document.rst:337 82ba080d68bb4981b7587f8bab2460c8\nmsgid \"\"\n\"Use the **visibility expression** *ve*: This is a list of two or more \"\n\"items. The **first item** is a logical keyword: one of the strings \"\n\"**\\\"and\\\"**, **\\\"or\\\"**, or **\\\"not\\\"**. The **second** and all \"\n\"subsequent items must either be an integer or another list. An integer \"\n\"must be the :data:`xref` number of an OCG. A list must again have at \"\n\"least two items starting with one of the boolean keywords. This syntax is\"\n\" a bit awkward, but quite powerful:\"\nmsgstr \"\"\n\"**가시성 표현식** *ve* 사용: 이것은 두 개 이상의 항목 목록입니다. **첫 번째 항목** 은 논리 키워드입니다: \"\n\"**\\\"and\\\"**, **\\\"or\\\"**, 또는 **\\\"not\\\"** 중 하나. **두 번째** 및 모든 후속 항목은 정수 또는 \"\n\"다른 목록이어야 합니다. 정수는 OCG의 :data:`xref` 번호여야 합니다. 목록은 부울 키워드 중 하나로 시작하는 최소 두 \"\n\"개의 항목을 다시 가져야 합니다. 이 구문은 약간 어색하지만 매우 강력합니다:\"\n\n#: ../../document.rst:339 8c43a5aff72040a7a6d28e5bb990e66b\nmsgid \"Each list must start with a logical keyword.\"\nmsgstr \"각 목록은 논리 키워드로 시작해야 합니다.\"\n\n#: ../../document.rst:340 19d1f313dc9c49d0a6293fc1ad610021\nmsgid \"\"\n\"If the keyword is a **\\\"not\\\"**, then the list must have exactly two \"\n\"items. If it is **\\\"and\\\"** or **\\\"or\\\"**, any number of other items may \"\n\"follow.\"\nmsgstr \"\"\n\"키워드가 **\\\"not\\\"** 이면 목록은 정확히 두 개의 항목을 가져야 합니다. **\\\"and\\\"** 또는 **\\\"or\\\"** \"\n\"이면 임의의 수의 다른 항목이 올 수 있습니다.\"\n\n#: ../../document.rst:341 bc4958d9848f4d9eb526b661a0948965\nmsgid \"\"\n\"Items following the logical keyword may be either integers or again a \"\n\"list. An *integer* must be the xref of an OCG. A *list* must conform to \"\n\"the previous rules.\"\nmsgstr \"\"\n\"논리 키워드 다음의 항목은 정수이거나 다시 목록일 수 있습니다. *정수* 는 OCG의 xref여야 합니다. *목록* 은 이전 규칙을\"\n\" 준수해야 합니다.\"\n\n#: ../../document.rst:343 909440e89ac14b0583e1721a3248b452\nmsgid \"**Examples:**\"\nmsgstr \"**예제:**\"\n\n#: ../../document.rst:345 39d40410d7484e3e825de23071befbe8\nmsgid \"\"\n\"`set_ocmd(ve=[\\\"or\\\", 4, [\\\"not\\\", 5], [\\\"and\\\", 6, 7]])`. This delivers \"\n\"ON if the following is true: **\\\"4 is ON, or 5 is OFF, or 6 and 7 are \"\n\"both ON\\\"**.\"\nmsgstr \"\"\n\"`set_ocmd(ve=[\\\"or\\\", 4, [\\\"not\\\", 5], [\\\"and\\\", 6, 7]])`. 다음이 true이면 ON을\"\n\" 제공합니다: **\\\"4가 ON이거나, 5가 OFF이거나, 6과 7이 모두 ON\\\"**.\"\n\n#: ../../document.rst:346 97dc40557fcc4158b6cb22c3353018db\nmsgid \"\"\n\"`set_ocmd(ve=[\\\"not\\\", xref])`. This has the same effect as the OCMD \"\n\"example created under 1.\"\nmsgstr \"`set_ocmd(ve=[\\\"not\\\", xref])`. 이것은 1번에서 생성된 OCMD 예제와 동일한 효과를 가집니다.\"\n\n#: ../../document.rst:348 434eb7de1a77405aa34ed1d2e20e1b02\nmsgid \"\"\n\"For more details and examples see page 224 of :ref:`AdobeManual`. Also do\"\n\" have a look at example scripts `here <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/optional-content>`_.\"\nmsgstr \"\"\n\"자세한 내용과 예제는 :ref:`AdobeManual` 의 224페이지를 참조하세요. 또한 예제 스크립트 `여기 \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/optional-\"\n\"content>`_ 도 확인하세요.\"\n\n#: ../../document.rst:350 7658995b2a4549639c7ace90d07d93b3\nmsgid \"\"\n\"Visibility expressions, `/VE`, are part of PDF specification version 1.6.\"\n\" So not all PDF viewers / readers may already support this feature and \"\n\"hence will react in some standard way for those cases.\"\nmsgstr \"\"\n\"가시성 표현식 `/VE` 는 PDF 사양 버전 1.6의 일부입니다. 따라서 모든 PDF 뷰어/리더가 이 기능을 지원하지 않을 수 \"\n\"있으며, 따라서 이러한 경우 표준 방식으로 반응할 수 있습니다.\"\n\n#: ../../document.rst:357 dcfcc58d11a2462ba2c2f22a728129bb\nmsgid \"Retrieve the definition of an :data:`OCMD`.\"\nmsgstr \":data:`OCMD` 의 정의를 검색합니다.\"\n\n#: ../../document.rst:359 7d1bff0a19054f2db6c4bd89fe1bcc2b\nmsgid \"the :data:`xref` of the OCMD.\"\nmsgstr \"OCMD의 :data:`xref`.\"\n\n#: ../../document.rst:361 10a42b8798f54b0280077c1c0449a55e\nmsgid \"a dictionary with the keys :data:`xref`, *ocgs*, *policy* and *ve*.\"\nmsgstr \":data:`xref`, *ocgs*, *policy* 및 *ve* 키를 가진 딕셔너리.\"\n\n#: ../../document.rst:368 a71256dcfa4a4a33b07ae79e240a88e3\nmsgid \"\"\n\"List of optional content groups by status in the specified configuration.\"\n\" This is a dictionary with lists of cross reference numbers for OCGs that\"\n\" occur in the arrays `/ON`, `/OFF` or in some radio button group \"\n\"(`/RBGroups`).\"\nmsgstr \"\"\n\"지정된 구성에서 상태별 선택적 콘텐츠 그룹 목록. 이것은 `/ON`, `/OFF` 배열 또는 일부 라디오 버튼 \"\n\"그룹(`/RBGroups`)에 나타나는 OCG의 교차 참조 번호 목록을 가진 딕셔너리입니다.\"\n\n#: ../../document.rst:370 e1289b8663ed42c88f7aeabecc6d605e\nmsgid \"the configuration layer (default is the standard config layer).\"\nmsgstr \"구성 레이어(기본값은 표준 구성 레이어).\"\n\n#: ../../document.rst:380 6f7007b493e44fba98c65146eb69d34c\nmsgid \"Changed in v1.22.5: Support list of *locked* OCGs.\"\nmsgstr \"v1.22.5에서 변경됨: *잠긴* OCG 목록 지원.\"\n\n#: ../../document.rst:382 ac89d60a2a5f4b48be8c2261db601aa9\nmsgid \"\"\n\"Mass status changes of optional content groups. **Permanently** sets the \"\n\"status of OCGs.\"\nmsgstr \"선택적 콘텐츠 그룹의 대량 상태 변경. OCG 상태를 **영구적으로** 설정합니다.\"\n\n#: ../../document.rst:384 468388be95424c0d8a9b49b756008f0d\nmsgid \"desired configuration layer, choose -1 for the default one.\"\nmsgstr \"원하는 구성 레이어, 기본값의 경우 -1을 선택합니다.\"\n\n#: ../../document.rst:385 ede15b445e8841da94cafafdeb425744\nmsgid \"\"\n\"list of :data:`xref` of OCGs to set ON. Replaces previous values. An \"\n\"empty list will cause no OCG being set to ON anymore. Should be specified\"\n\" if `basestate=\\\"ON\\\"` is used.\"\nmsgstr \"\"\n\"ON으로 설정할 OCG의 :data:`xref` 목록. 이전 값을 대체합니다. 빈 목록은 더 이상 OCG가 ON으로 설정되지 않도록\"\n\" 합니다. `basestate=\\\"ON\\\"` 이 사용되는 경우 지정해야 합니다.\"\n\n#: ../../document.rst:386 8ba93f6ec2554e599cb52b9e35a6871e\nmsgid \"\"\n\"list of :data:`xref` of OCGs to set OFF. Replaces previous values. An \"\n\"empty list will cause no OCG being set to OFF anymore. Should be \"\n\"specified if `basestate=\\\"OFF\\\"` is used.\"\nmsgstr \"\"\n\"OFF로 설정할 OCG의 :data:`xref` 목록. 이전 값을 대체합니다. 빈 목록은 더 이상 OCG가 OFF로 설정되지 않도록\"\n\" 합니다. `basestate=\\\"OFF\\\"` 가 사용되는 경우 지정해야 합니다.\"\n\n#: ../../document.rst:387 85b511fbc799407395e9ee0a53fd3d75\nmsgid \"\"\n\"state of OCGs that are not mentioned in *on* or *off*. Possible values \"\n\"are \\\"ON\\\", \\\"OFF\\\" or \\\"Unchanged\\\". Upper / lower case possible.\"\nmsgstr \"\"\n\"*on* 또는 *off* 에 언급되지 않은 OCG의 상태. 가능한 값은 \\\"ON\\\", \\\"OFF\\\" 또는 \\\"Unchanged\\\" \"\n\"입니다. 대소문자 가능.\"\n\n#: ../../document.rst:388 103c3e8b6c5d4ddea0e0693af1420970\nmsgid \"\"\n\"a list of lists. Replaces previous values. Each sublist should contain \"\n\"two or more OCG xrefs. OCGs in the same sublist are handled like buttons \"\n\"in a radio button group: setting one to ON automatically sets all other \"\n\"group members to OFF.\"\nmsgstr \"\"\n\"목록의 목록. 이전 값을 대체합니다. 각 하위 목록은 두 개 이상의 OCG xref를 포함해야 합니다. 동일한 하위 목록의 OCG는\"\n\" 라디오 버튼 그룹의 버튼처럼 처리됩니다: 하나를 ON으로 설정하면 다른 모든 그룹 구성원이 자동으로 OFF로 설정됩니다.\"\n\n#: ../../document.rst:389 dc1e634515e44d1c9a4d4d3fdd70fcd9\nmsgid \"a list of OCG xref number that cannot be changed by the user interface.\"\nmsgstr \"사용자 인터페이스로 변경할 수 없는 OCG xref 번호 목록.\"\n\n#: ../../document.rst:391 0f646eb8554b43a5b6b2525fb77f6a59\nmsgid \"Values `None` will not change the corresponding PDF array.\"\nmsgstr \"`None` 값은 해당 PDF 배열을 변경하지 않습니다.\"\n\n#: ../../document.rst:402 46f83dd2ff484f27982ec01f17716437\nmsgid \"\"\n\"Details of all optional content groups. This is a dictionary of \"\n\"dictionaries like this (key is the OCG's :data:`xref`):\"\nmsgstr \"모든 선택적 콘텐츠 그룹의 세부 정보. 이것은 다음과 같은 딕셔너리의 딕셔너리입니다(키는 OCG의 :data:`xref`):\"\n\n#: ../../document.rst:420 c417700fcc5b4b1eae4fa6465cba21de\nmsgid \"\"\n\"Show the visibility status of optional content that is modifiable by the \"\n\"user interface of supporting PDF viewers.\"\nmsgstr \"지원하는 PDF 뷰어의 사용자 인터페이스로 수정 가능한 선택적 콘텐츠의 가시성 상태를 표시합니다.\"\n\n#: ../../document.rst:422 4aa5dc6d9637420fbaa9715a0f68a0cc\nmsgid \"\"\n\"Only reports items contained in the currently selected layer \"\n\"configuration.\"\nmsgstr \"현재 선택된 레이어 구성에 포함된 항목만 보고합니다.\"\n\n#: ../../document.rst:429 64cd741b0f154a59882f3ecbad6f6c4d\nmsgid \"The meaning of the dictionary keys is as follows:\"\nmsgstr \"딕셔너리 키의 의미는 다음과 같습니다:\"\n\n#: ../../document.rst:425 a1d441dff29442abbe52ac442fba4857\nmsgid \"*depth:* item's nesting level in the `/Order` array\"\nmsgstr \"*depth:* `/Order` 배열에서 항목의 중첩 수준\"\n\n#: ../../document.rst:426 afed949ed9c94f36b9dc60f092483e05\nmsgid \"*locked:* true if cannot be changed via user interfaces\"\nmsgstr \"*locked:* 사용자 인터페이스를 통해 변경할 수 없으면 true\"\n\n#: ../../document.rst:427 710278fb91c2494cbd5c46259e9fe457\nmsgid \"*number:* running sequence number\"\nmsgstr \"*number:* 실행 시퀀스 번호\"\n\n#: ../../document.rst:428 a2442736222d45c083eb9cad2e3cf565\nmsgid \"*on:* item state\"\nmsgstr \"*on:* 항목 상태\"\n\n#: ../../document.rst:429 92dfbeb754404026afaa90073baff793\nmsgid \"*text:* text string or name field of the originating OCG\"\nmsgstr \"*text:* 원본 OCG의 텍스트 문자열 또는 이름 필드\"\n\n#: ../../document.rst:430 c8d971a7af4b492bbd1fbc73337424ad\nmsgid \"\"\n\"*type:* one of \\\"label\\\" (set by a text string), \\\"checkbox\\\" (set by a \"\n\"single OCG) or \\\"radiobox\\\" (set by a set of connected OCGs)\"\nmsgstr \"\"\n\"*type:* \\\"label\\\" (텍스트 문자열로 설정), \\\"checkbox\\\" (단일 OCG로 설정) 또는 \"\n\"\\\"radiobox\\\" (연결된 OCG 집합으로 설정) 중 하나\"\n\n#: ../../document.rst:436 ca0c2b9b2d704bf4926d5541ce17576a\nmsgid \"\"\n\"Modify OC visibility status of content groups. This is analog to what \"\n\"supporting PDF viewers would offer.\"\nmsgstr \"콘텐츠 그룹의 OC 가시성 상태를 수정합니다. 이것은 지원하는 PDF 뷰어가 제공하는 것과 유사합니다.\"\n\n#: ../../document.rst:438 2d3943b22c954c3e9f6217dc93f52b4c\nmsgid \"\"\n\"Please note that visibility is **not** a property stored with the OCG. It\"\n\" is not even information necessarily present in the PDF document at all. \"\n\"Instead, the current visibility is **temporarily** set using the user \"\n\"interface of some supporting PDF consumer software. The same type of \"\n\"functionality is offered by this method.\"\nmsgstr \"\"\n\"가시성은 OCG와 함께 저장되는 속성이 **아닙니다**. PDF 문서에 반드시 존재하는 정보도 아닙니다. 대신, 현재 가시성은 일부\"\n\" 지원하는 PDF 소비자 소프트웨어의 사용자 인터페이스를 사용하여 **임시로** 설정됩니다. 이 메서드는 동일한 유형의 기능을 \"\n\"제공합니다.\"\n\n#: ../../document.rst:440 4360a90c60fa4f3090c35c0af96d1a99\nmsgid \"To make **permanent** changes, use :meth:`Document.set_layer`.\"\nmsgstr \"**영구적인** 변경을 하려면 :meth:`Document.set_layer` 를 사용하세요.\"\n\n#: ../../document.rst:442 29750667f90046a896bd2ed12b182314\nmsgid \"\"\n\"either the sequence number of the item in list \"\n\":meth:`Document.layer_configs` or the \\\"text\\\" of one of these items.\"\nmsgstr \":meth:`Document.layer_configs` 목록의 항목 시퀀스 번호 또는 이러한 항목 중 하나의 \\\"text\\\".\"\n\n#: ../../document.rst:443 f398780fe9cd4cb9a46fe8eb8c8591f2\nmsgid \"\"\n\"`PDF_OC_ON` = set on (default), `PDF_OC_TOGGLE` = toggle on/off, \"\n\"`PDF_OC_OFF` = set off.\"\nmsgstr \"`PDF_OC_ON` = 켜기(기본값), `PDF_OC_TOGGLE` = 켜기/끄기 전환, `PDF_OC_OFF` = 끄기.\"\n\n#: ../../document.rst:448 bac35af4cb58496282e3f36f790b2d94\nmsgid \"\"\n\"Decrypts the document with the string *password*. If successful, document\"\n\" data can be accessed. For PDF documents, the \\\"owner\\\" and the \\\"user\\\" \"\n\"have different privileges, and hence different passwords may exist for \"\n\"these authorization levels. The method will automatically establish the \"\n\"appropriate (owner or user) access rights for the provided password.\"\nmsgstr \"\"\n\"문자열 *password* 로 문서를 복호화합니다. 성공하면 문서 데이터에 액세스할 수 있습니다. PDF 문서의 경우 \"\n\"\\\"owner\\\" 와 \\\"user\\\" 는 다른 권한을 가지므로 이러한 권한 수준에 대해 다른 비밀번호가 존재할 수 있습니다. 이 \"\n\"메서드는 제공된 비밀번호에 대해 적절한(owner 또는 user) 액세스 권한을 자동으로 설정합니다.\"\n\n#: ../../document.rst:450 d19b070d8c8c4e07bb85b92d121abe18\nmsgid \"owner or user password.\"\nmsgstr \"owner 또는 user 비밀번호.\"\n\n#: ../../document.rst:453 09c81228f6f144ec9e2812177c48be57\nmsgid \"\"\n\"a positive value if successful, zero otherwise (the string does not match\"\n\" either password). If positive, the indicator \"\n\":attr:`Document.is_encrypted` is set to ``False``. **Positive** return \"\n\"codes carry the following information detail:  * 1 => authenticated, but \"\n\"the PDF has neither owner nor user passwords. * 2 => authenticated with \"\n\"the **user** password. * 4 => authenticated with the **owner** password. \"\n\"* 6 => authenticated and both passwords are equal -- probably a rare \"\n\"situation.  .. note::    The document may be protected by an owner, but \"\n\"**not** by a user password. Detect this situation via \"\n\"`doc.authenticate(\\\"\\\") == 2`. This allows opening and reading the \"\n\"document without authentication, but, depending on the \"\n\":attr:`Document.permissions` value, other actions may be prohibited. \"\n\"PyMuPDF (like MuPDF) in this case **ignores those restrictions**. So, -- \"\n\"in contrast to any PDF viewers -- you can for example extract text and \"\n\"add or modify content, even if the respective permission flags \"\n\"`PDF_PERM_COPY`, `PDF_PERM_MODIFY`, `PDF_PERM_ANNOTATE`, etc. are set \"\n\"off! It is your responsibility building a legally compliant application \"\n\"where applicable.\"\nmsgstr \"\"\n\n#: ../../document.rst:453 a27a648e6c744e1c9f93f1717c0ce5e4\nmsgid \"\"\n\"a positive value if successful, zero otherwise (the string does not match\"\n\" either password). If positive, the indicator \"\n\":attr:`Document.is_encrypted` is set to ``False``. **Positive** return \"\n\"codes carry the following information detail:\"\nmsgstr \"\"\n\"성공하면 양수 값, 그렇지 않으면 0(문자열이 두 비밀번호와 일치하지 않음). 양수이면 표시기 \"\n\":attr:`Document.is_encrypted` 가 ``False`` 로 설정됩니다. **양수** 반환 코드는 다음 정보 세부\"\n\" 사항을 포함합니다:\"\n\n#: ../../document.rst:455 ad0771c151124449b3a89661edd657dd\nmsgid \"1 => authenticated, but the PDF has neither owner nor user passwords.\"\nmsgstr \"1 => 인증되었지만 PDF에 owner 또는 user 비밀번호가 없습니다.\"\n\n#: ../../document.rst:456 45d3470658684c13b95b87cc78f20822\nmsgid \"2 => authenticated with the **user** password.\"\nmsgstr \"2 => **user** 비밀번호로 인증되었습니다.\"\n\n#: ../../document.rst:457 3d1ac17d43984900a8e2fa5e25f7faa0\nmsgid \"4 => authenticated with the **owner** password.\"\nmsgstr \"4 => **owner** 비밀번호로 인증되었습니다.\"\n\n#: ../../document.rst:458 971a66bb85bc4ab486ae62db4d6615f7\nmsgid \"\"\n\"6 => authenticated and both passwords are equal -- probably a rare \"\n\"situation.\"\nmsgstr \"6 => 인증되었고 두 비밀번호가 동일합니다. 아마도 드문 상황입니다.\"\n\n#: ../../document.rst:462 b2a20378b0b5427a8d960f26e7b1ecdf\nmsgid \"\"\n\"The document may be protected by an owner, but **not** by a user \"\n\"password. Detect this situation via `doc.authenticate(\\\"\\\") == 2`. This \"\n\"allows opening and reading the document without authentication, but, \"\n\"depending on the :attr:`Document.permissions` value, other actions may be\"\n\" prohibited. PyMuPDF (like MuPDF) in this case **ignores those \"\n\"restrictions**. So, -- in contrast to any PDF viewers -- you can for \"\n\"example extract text and add or modify content, even if the respective \"\n\"permission flags `PDF_PERM_COPY`, `PDF_PERM_MODIFY`, `PDF_PERM_ANNOTATE`,\"\n\" etc. are set off! It is your responsibility building a legally compliant\"\n\" application where applicable.\"\nmsgstr \"\"\n\"문서는 owner로 보호될 수 있지만 user 비밀번호로는 보호되지 **않을** 수 있습니다. \"\n\"`doc.authenticate(\\\"\\\") == 2` 를 통해 이 상황을 감지합니다. 이것은 인증 없이 문서를 열고 읽을 수 있게 \"\n\"하지만, :attr:`Document.permissions` 값에 따라 다른 작업이 금지될 수 있습니다. |PyMuPDF| \"\n\"(|MuPDF| 와 마찬가지로) 이 경우 **이러한 제한을 무시합니다**. 따라서 -- 모든 PDF 뷰어와 달리 -- 예를 들어 \"\n\"해당 권한 플래그 `PDF_PERM_COPY`, `PDF_PERM_MODIFY`, `PDF_PERM_ANNOTATE` 등이 꺼져 \"\n\"있어도 텍스트를 추출하고 콘텐츠를 추가하거나 수정할 수 있습니다! 해당되는 경우 법적으로 준수하는 애플리케이션을 구축하는 것은 \"\n\"귀하의 책임입니다.\"\n\n#: ../../document.rst:466 f77a2af6763a4e99aa429f7e98659d79\nmsgid \"New in v 1.18.6\"\nmsgstr \"v 1.18.6에서 새로 추가됨\"\n\n#: ../../document.rst:468 f4bbff5e7ed442339312ec3c0ef8a04b\nmsgid \"\"\n\"PDF only: Return a list of page numbers that have the specified label -- \"\n\"note that labels may not be unique in a PDF. This implies a sequential \"\n\"search through **all page numbers** to compare their labels.\"\nmsgstr \"\"\n\"PDF 전용: 지정된 레이블을 가진 페이지 번호 목록을 반환합니다. 레이블이 PDF에서 고유하지 않을 수 있습니다. 이것은 레이블을\"\n\" 비교하기 위해 **모든 페이지 번호** 를 순차적으로 검색하는 것을 의미합니다.\"\n\n#: ../../document.rst:470 284419aaa5c14aaf9838d76305b7e6fd\nmsgid \"Implementation detail -- pages are **not loaded** for this purpose.\"\nmsgstr \"구현 세부 사항 -- 이 목적을 위해 페이지는 **로드되지 않습니다**.\"\n\n#: ../../document.rst:472 1fa71ee28df5429f91ab5ed8669e52f8\nmsgid \"the label to look for, e.g. \\\"vii\\\" (Roman number 7).\"\nmsgstr \"찾을 레이블, 예: \\\"vii\\\" (로마 숫자 7).\"\n\n#: ../../document.rst:473 cf505e7ed7bd4f6d90bd2804a9b59277\nmsgid \"\"\n\"stop after first hit. Useful e.g. if labelling is known to be unique, or \"\n\"there are many pages, etc. The default will check every page number.\"\nmsgstr \"\"\n\"첫 번째 일치 후 중지. 레이블링이 고유한 것으로 알려져 있거나 페이지가 많은 경우 등에 유용합니다. 기본값은 모든 페이지 번호를 \"\n\"확인합니다.\"\n\n#: ../../document.rst:475 7fcfbfc46bea4a529ec9a179bf248165\nmsgid \"\"\n\"list of page numbers that have this label. Empty if none found, no labels\"\n\" defined, etc.\"\nmsgstr \"이 레이블을 가진 페이지 번호 목록. 찾을 수 없거나 레이블이 정의되지 않은 경우 비어 있습니다.\"\n\n#: ../../document.rst:480 ../../document.rst:843 ../../document.rst:864\n#: ../../document.rst:1897 ../../document.rst:1921\n#: 0e9d135c2c694491862abf575442c967 544935bd7d614c9db589293891fdce0f\n#: 74efba34b38140e980ef5f9591e33759 b1ba150b171340d88337555ba1cd0b2b\n#: ee0ffb51d237488e9b8a23feb27a244c\nmsgid \"New in v1.18.7\"\nmsgstr \"v1.18.7에서 새로 추가됨\"\n\n#: ../../document.rst:482 d49573b0569d48a1aa0c91946c9138d9\nmsgid \"\"\n\"PDF only: Extract the list of page label definitions. Typically used for \"\n\"modifications before feeding it into :meth:`Document.set_page_labels`.\"\nmsgstr \"\"\n\"PDF 전용: 페이지 레이블 정의 목록을 추출합니다. 일반적으로 :meth:`Document.set_page_labels` 에 \"\n\"전달하기 전에 수정하는 데 사용됩니다.\"\n\n#: ../../document.rst:484 831722188ad841a9947ddd4ed8b6cc3b\nmsgid \"a list of dictionaries as defined in :meth:`Document.set_page_labels`.\"\nmsgstr \":meth:`Document.set_page_labels` 에 정의된 대로 딕셔너리 목록.\"\n\n#: ../../document.rst:488 1ba6ad21168d4d6eb7121d531daa9fe5\nmsgid \"New in v1.18.6\"\nmsgstr \"v1.18.6에서 새로 추가됨\"\n\n#: ../../document.rst:490 9a57871c71864eaa8c4df22898b6c3ba\nmsgid \"PDF only: Add or update the page label definitions of the PDF.\"\nmsgstr \"PDF 전용: PDF의 페이지 레이블 정의를 추가하거나 업데이트합니다.\"\n\n#: ../../document.rst:492 8023f294ed3e465abd9879124efa0c93\n#, python-brace-format\nmsgid \"\"\n\"a list of dictionaries. Each dictionary defines a label building rule and\"\n\" a 0-based \\\"start\\\" page number. That start page is the first for which \"\n\"the label definition is valid. Each dictionary has up to 4 items and \"\n\"looks like `{'startpage': int, 'prefix': str, 'style': str, \"\n\"'firstpagenum': int}` and has the following items.  - `startpage`: (int) \"\n\"the first page number (0-based) to apply the label rule. This key **must \"\n\"be present**. The rule is applied to all subsequent pages until either \"\n\"end of document or superseded by the rule with the next larger page \"\n\"number. - `prefix`: (str) an arbitrary string to start the label with, \"\n\"e.g. \\\"A-\\\". Default is \\\"\\\". - `style`: (str) the numbering style. \"\n\"Available are \\\"D\\\" (decimal), \\\"r\\\"/\\\"R\\\" (Roman numbers, lower / upper \"\n\"case), and \\\"a\\\"/\\\"A\\\" (lower / upper case alphabetical numbering: \\\"a\\\" \"\n\"through \\\"z\\\", then \\\"aa\\\" through \\\"zz\\\", etc.). Default is \\\"\\\". If \"\n\"\\\"\\\", no numbering will take place and the pages in that range will \"\n\"receive the same label consisting of the `prefix` value. If prefix is \"\n\"also omitted, then the label will be \\\"\\\". - `firstpagenum`: (int) start \"\n\"numbering with this value. Default is 1, smaller values are ignored.\"\nmsgstr \"\"\n\n#: ../../document.rst:492 f0236618e0804858971c55deab0fe7fe\n#, python-brace-format\nmsgid \"\"\n\"a list of dictionaries. Each dictionary defines a label building rule and\"\n\" a 0-based \\\"start\\\" page number. That start page is the first for which \"\n\"the label definition is valid. Each dictionary has up to 4 items and \"\n\"looks like `{'startpage': int, 'prefix': str, 'style': str, \"\n\"'firstpagenum': int}` and has the following items.\"\nmsgstr \"\"\n\"딕셔너리 목록. 각 딕셔너리는 레이블 빌딩 규칙과 0 기반 \\\"시작\\\" 페이지 번호를 정의합니다. 해당 시작 페이지는 레이블 정의가\"\n\" 유효한 첫 번째 페이지입니다. 각 딕셔너리는 최대 4개의 항목을 가지며 `{'startpage': int, 'prefix': \"\n\"str, 'style': str, 'firstpagenum': int}` 와 같이 보이며 다음 항목을 가집니다.\"\n\n#: ../../document.rst:494 7ada331695bb454facb941b2016338ac\nmsgid \"\"\n\"`startpage`: (int) the first page number (0-based) to apply the label \"\n\"rule. This key **must be present**. The rule is applied to all subsequent\"\n\" pages until either end of document or superseded by the rule with the \"\n\"next larger page number.\"\nmsgstr \"\"\n\"`startpage`: (int) 레이블 규칙을 적용할 첫 번째 페이지 번호(0 기반). 이 키는 **반드시 있어야 합니다**. \"\n\"규칙은 문서 끝까지 또는 다음 더 큰 페이지 번호를 가진 규칙으로 대체될 때까지 모든 후속 페이지에 적용됩니다.\"\n\n#: ../../document.rst:495 17d1a6d64dc0414d868aaa9ab7317f23\nmsgid \"\"\n\"`prefix`: (str) an arbitrary string to start the label with, e.g. \\\"A-\\\".\"\n\" Default is \\\"\\\".\"\nmsgstr \"`prefix`: (str) 레이블을 시작하는 임의의 문자열, 예: \\\"A-\\\". 기본값은 \\\"\\\" 입니다.\"\n\n#: ../../document.rst:496 912d2eb8b5b24751a0f30b902fd6b532\nmsgid \"\"\n\"`style`: (str) the numbering style. Available are \\\"D\\\" (decimal), \"\n\"\\\"r\\\"/\\\"R\\\" (Roman numbers, lower / upper case), and \\\"a\\\"/\\\"A\\\" (lower /\"\n\" upper case alphabetical numbering: \\\"a\\\" through \\\"z\\\", then \\\"aa\\\" \"\n\"through \\\"zz\\\", etc.). Default is \\\"\\\". If \\\"\\\", no numbering will take \"\n\"place and the pages in that range will receive the same label consisting \"\n\"of the `prefix` value. If prefix is also omitted, then the label will be \"\n\"\\\"\\\".\"\nmsgstr \"\"\n\"`style`: (str) 번호 매기기 스타일. 사용 가능한 것은 \\\"D\\\" (십진수), \\\"r\\\"/\\\"R\\\" (로마 숫자, \"\n\"소문자/대문자), \\\"a\\\"/\\\"A\\\" (소문자/대문자 알파벳 번호 매기기: \\\"a\\\" 부터 \\\"z\\\" 까지, 그 다음 \\\"aa\\\"\"\n\" 부터 \\\"zz\\\" 까지 등). 기본값은 \\\"\\\" 입니다. \\\"\\\" 이면 번호 매기기가 수행되지 않고 해당 범위의 페이지는 \"\n\"`prefix` 값으로 구성된 동일한 레이블을 받습니다. prefix도 생략되면 레이블은 \\\"\\\" 가 됩니다.\"\n\n#: ../../document.rst:497 63acf88f059441f2bc4e4af1e8d8650a\nmsgid \"\"\n\"`firstpagenum`: (int) start numbering with this value. Default is 1, \"\n\"smaller values are ignored.\"\nmsgstr \"`firstpagenum`: (int) 이 값으로 번호 매기기를 시작합니다. 기본값은 1이며, 더 작은 값은 무시됩니다.\"\n\n#: ../../document.rst:499 384ec1a67413470785f411317701132b\nmsgid \"For example::\"\nmsgstr \"예를 들어::\"\n\n#: ../../document.rst:504 b8301b8cf19d4e02ac8a0bcd0352c92d\nmsgid \"\"\n\"will generate the labels \\\"A-10\\\", \\\"A-11\\\", \\\"A-12\\\", \\\"A-13\\\", \\\"1\\\", \"\n\"\\\"2\\\", \\\"3\\\", ... for pages 6, 7 and so on until end of document. Pages 0\"\n\" through 5 will have the label \\\"\\\".\"\nmsgstr \"\"\n\"페이지 6, 7 등 문서 끝까지 \\\"A-10\\\", \\\"A-11\\\", \\\"A-12\\\", \\\"A-13\\\", \\\"1\\\", \\\"2\\\", \"\n\"\\\"3\\\", ... 레이블을 생성합니다. 페이지 0부터 5까지는 레이블이 \\\"\\\" 입니다.\"\n\n#: ../../document.rst:509 ../../document.rst:523\n#: a2b10c378f7a4169a34c80b25fd3b781 dd39cd38852c4114b99d2bd5eb73b6e2\nmsgid \"New in v.1.17.3\"\nmsgstr \"v.1.17.3에서 새로 추가됨\"\n\n#: ../../document.rst:511 6f3e58f86d23447789f879a032a3c941\nmsgid \"\"\n\"Return a page pointer in a reflowable document. After re-layouting the \"\n\"document, the result of this method can be used to find the new location \"\n\"of the page.\"\nmsgstr \"\"\n\"재배치 가능한 문서에서 페이지 포인터를 반환합니다. 문서를 다시 레이아웃한 후 이 메서드의 결과를 사용하여 페이지의 새 위치를 찾을\"\n\" 수 있습니다.\"\n\n#: ../../document.rst:513 9c43c3c696e44b848e88cb43517118b7\nmsgid \"Do not confuse with items of a table of contents, TOC.\"\nmsgstr \"목차(TOC) 항목과 혼동하지 마세요.\"\n\n#: ../../document.rst:515 cd56f6afe2b64b0c85a5cc6be4cfed1d\nmsgid \"page location. Must be a valid *(chapter, pno)*.\"\nmsgstr \"페이지 location. 유효한 *(chapter, pno)* 여야 합니다.\"\n\n#: ../../document.rst:518 de63fa23b9dd457da0f6793091194ee8\nmsgid \"\"\n\"a long integer in pointer format. To be used for finding the new location\"\n\" of the page after re-layouting the document. Do not touch or re-assign.\"\nmsgstr \"포인터 형식의 긴 정수. 문서를 다시 레이아웃한 후 페이지의 새 위치를 찾는 데 사용됩니다. 건드리거나 재할당하지 마세요.\"\n\n#: ../../document.rst:525 913919f58489450c8f242d2cd3216182\nmsgid \"Return the new page location after re-layouting the document.\"\nmsgstr \"문서를 다시 레이아웃한 후 새 페이지 location을 반환합니다.\"\n\n#: ../../document.rst:527 f2193906ae744c47ba74f5923e5f39ea\nmsgid \"created by :meth:`Document.make_bookmark`.\"\nmsgstr \":meth:`Document.make_bookmark` 에 의해 생성됨.\"\n\n#: ../../document.rst:530 6464a8ee1ffd421286788623fe35387a\nmsgid \"the new (chapter, pno) of the page.\"\nmsgstr \"페이지의 새 (chapter, pno).\"\n\n#: ../../document.rst:535 ../../document.rst:547 ../../document.rst:558\n#: 2c2b3d20cfd34f43884f9e342fe74972 432814f8916748ba9f235825511c6890\n#: d0dfb3092bfb48daad9187dcf8ab30b1\nmsgid \"New in v.1.17.0\"\nmsgstr \"v.1.17.0에서 새로 추가됨\"\n\n#: ../../document.rst:537 c0e2a2bf75c542f1a01355c1c674e527\nmsgid \"Return the number of pages of a chapter.\"\nmsgstr \"장의 페이지 수를 반환합니다.\"\n\n#: ../../document.rst:539 022a532a4be94cd9a0a10cdead619a0e\nmsgid \"the 0-based chapter number.\"\nmsgstr \"0 기반 장 번호.\"\n\n#: ../../document.rst:542 9be187716918410591450efaf38f2b01\nmsgid \"\"\n\"number of pages in chapter. Relevant only for document types with chapter\"\n\" support (EPUB currently).\"\nmsgstr \"장의 페이지 수. 장 지원이 있는 문서 타입(현재 EPUB)에만 관련됩니다.\"\n\n#: ../../document.rst:549 e533b993f4aa4e748f7fc650a74d28e6\nmsgid \"Return the location of the following page.\"\nmsgstr \"다음 페이지의 location을 반환합니다.\"\n\n#: ../../document.rst:551 ../../document.rst:562\n#: 2f8ffb9193c540f49c32191e72b9ae2f 7c0ea3575def40a0841b17016db6f227\nmsgid \"\"\n\"the current page id. This must be a tuple *(chapter, pno)* identifying an\"\n\" existing page.\"\nmsgstr \"현재 페이지 id. 이것은 기존 페이지를 식별하는 튜플 *(chapter, pno)* 여야 합니다.\"\n\n#: ../../document.rst:553 32dbdc16dbeb4e8c99445020925a3e38\nmsgid \"\"\n\"The tuple of the following page, i.e. either *(chapter, pno + 1)* or \"\n\"*(chapter + 1, 0)*, **or** the empty tuple *()* if the argument was the \"\n\"last page. Relevant only for document types with chapter support (EPUB \"\n\"currently).\"\nmsgstr \"\"\n\"다음 페이지의 튜플, 즉 *(chapter, pno + 1)* 또는 *(chapter + 1, 0)*, **또는** 인수가 마지막 \"\n\"페이지인 경우 빈 튜플 *()*. 장 지원이 있는 문서 타입(현재 EPUB)에만 관련됩니다.\"\n\n#: ../../document.rst:560 7dae3e783cc443a0a88110bdc72a0cf6\nmsgid \"Return the locator of the preceding page.\"\nmsgstr \"이전 페이지의 위치 지정자를 반환합니다.\"\n\n#: ../../document.rst:564 cb600a2817c449e79741984189d126d4\nmsgid \"\"\n\"The tuple of the preceding page, i.e. either *(chapter, pno - 1)* or the \"\n\"last page of the preceding chapter, **or** the empty tuple *()* if the \"\n\"argument was the first page. Relevant only for document types with \"\n\"chapter support (EPUB currently).\"\nmsgstr \"\"\n\"이전 페이지의 튜플, 즉 *(chapter, pno - 1)* 또는 이전 장의 마지막 페이지, **또는** 인수가 첫 번째 페이지인\"\n\" 경우 빈 튜플 *()*. 장 지원이 있는 문서 타입(현재 EPUB)에만 관련됩니다.\"\n\n#: ../../document.rst:569 7a0fdbda67e34d958f9dbcb0292e9116\nmsgid \"\"\n\"Changed in v1.17.0: For document types supporting a so-called \\\"chapter \"\n\"structure\\\" (like EPUB), pages can also be loaded via the combination of \"\n\"chapter number and relative page number, instead of the absolute page \"\n\"number. This should **significantly speed up access** for large \"\n\"documents.\"\nmsgstr \"\"\n\"v1.17.0에서 변경됨: 소위 \\\"장 구조\\\" (EPUB 등)를 지원하는 문서 타입의 경우, 절대 페이지 번호 대신 장 번호와 \"\n\"상대 페이지 번호의 조합을 통해 페이지를 로드할 수도 있습니다. 이것은 큰 문서에 대해 **액세스를 크게 향상시켜야** 합니다.\"\n\n#: ../../document.rst:571 b2e8b49a32a4477f86470bc9ed51f929\nmsgid \"\"\n\"Create a :ref:`Page` object for further processing (like rendering, text \"\n\"searching, etc.).\"\nmsgstr \"추가 처리(렌더링, 텍스트 검색 등)를 위한 :ref:`Page` 객체를 생성합니다.\"\n\n#: ../../document.rst:573 89dd1233c4cf421f9ff21d9beee9b294\nmsgid \"\"\n\"*(Changed in v1.17.0)*  Either a 0-based page number, or a tuple \"\n\"*(chapter, pno)*. For an **integer**, any `-∞ < page_id < page_count` is \"\n\"acceptable. While page_id is negative, :attr:`page_count` will be added \"\n\"to it. For example: to load the last page, you can use \"\n\"*doc.load_page(-1)*. After this you have page.number = doc.page_count - \"\n\"1.  For a tuple, *chapter* must be in range \"\n\":attr:`Document.chapter_count`, and *pno* must be in range \"\n\":meth:`Document.chapter_page_count` of that chapter. Both values are \"\n\"0-based. Using this notation, :attr:`Page.number` will equal the given \"\n\"tuple. Relevant only for document types with chapter support (EPUB \"\n\"currently).\"\nmsgstr \"\"\n\n#: ../../document.rst:573 e282ccf1b1c343d89ec35cf61d5591b9\nmsgid \"*(Changed in v1.17.0)*\"\nmsgstr \"*(v1.17.0에서 변경됨)*\"\n\n#: ../../document.rst:575 9777eceecadf454084f47700b9be0cb6\nmsgid \"\"\n\"Either a 0-based page number, or a tuple *(chapter, pno)*. For an \"\n\"**integer**, any `-∞ < page_id < page_count` is acceptable. While page_id\"\n\" is negative, :attr:`page_count` will be added to it. For example: to \"\n\"load the last page, you can use *doc.load_page(-1)*. After this you have \"\n\"page.number = doc.page_count - 1.\"\nmsgstr \"\"\n\"0 기반 페이지 번호 또는 튜플 *(chapter, pno)*. **정수** 의 경우 `-∞ < page_id < \"\n\"page_count` 가 허용됩니다. page_id가 음수이면 :attr:`page_count` 가 추가됩니다. 예를 들어: 마지막\"\n\" 페이지를 로드하려면 *doc.load_page(-1)* 를 사용할 수 있습니다. 그 후 page.number = \"\n\"doc.page_count - 1 입니다.\"\n\n#: ../../document.rst:577 74810654696e4baf8bcbdc8c746cc775\nmsgid \"\"\n\"For a tuple, *chapter* must be in range :attr:`Document.chapter_count`, \"\n\"and *pno* must be in range :meth:`Document.chapter_page_count` of that \"\n\"chapter. Both values are 0-based. Using this notation, \"\n\":attr:`Page.number` will equal the given tuple. Relevant only for \"\n\"document types with chapter support (EPUB currently).\"\nmsgstr \"\"\n\"튜플의 경우 *chapter* 는 :attr:`Document.chapter_count` 범위에 있어야 하고, *pno* 는 해당 \"\n\"장의 :meth:`Document.chapter_page_count` 범위에 있어야 합니다. 두 값 모두 0 기반입니다. 이 \"\n\"표기법을 사용하면 :attr:`Page.number` 가 주어진 튜플과 같습니다. 장 지원이 있는 문서 타입(현재 EPUB)에만 \"\n\"관련됩니다.\"\n\n#: ../../document.rst:579 ../../document.rst:683 ../../document.rst:1452\n#: 650ab56d4df54dd8aec8fe0a7592a3bc d3df878a5b5247f1913be4deb5b6649c\n#: f14fc92ab834466f8549257c73ebb9ff\nmsgid \":ref:`Page`\"\nmsgstr \":ref:`Page`\"\n\n#: ../../document.rst:583 59d5cb9d27a84699bf71d6a5f487a61b\nmsgid \"\"\n\"Documents also follow the Python sequence protocol with page numbers as \"\n\"indices: *doc.load_page(n) == doc[n]*.\"\nmsgstr \"문서는 페이지 번호를 인덱스로 사용하는 Python 시퀀스 프로토콜도 따릅니다: *doc.load_page(n) == doc[n]*.\"\n\n#: ../../document.rst:585 e1b05eec25bd4808ad4d6219711d4017\nmsgid \"\"\n\"For **absolute page numbers** only, expressions like *\\\"for page in doc: \"\n\"...\\\"* and *\\\"for page in reversed(doc): ...\\\"* will successively yield \"\n\"the document's pages. Refer to :meth:`Document.pages` which allows \"\n\"processing pages as with slicing.\"\nmsgstr \"\"\n\"**절대 페이지 번호** 에만 해당하는 경우, *\\\"for page in doc: ...\\\"* 및 *\\\"for page in \"\n\"reversed(doc): ...\\\"* 와 같은 표현식이 문서의 페이지를 순차적으로 생성합니다. 슬라이싱과 같이 페이지를 처리할 수\"\n\" 있는 :meth:`Document.pages` 를 참조하세요.\"\n\n#: ../../document.rst:587 a88f8092ff8f4819a3dbc62a28c6bf8f\nmsgid \"\"\n\"You can also use index notation with the new chapter-based page \"\n\"identification: use *page = doc[(5, 2)]* to load the third page of the \"\n\"sixth chapter.\"\nmsgstr \"\"\n\"새로운 장 기반 페이지 식별과 함께 인덱스 표기법을 사용할 수도 있습니다: *page = doc[(5, 2)]* 를 사용하여 여섯 \"\n\"번째 장의 세 번째 페이지를 로드합니다.\"\n\n#: ../../document.rst:589 4664a59b1d8a4c12bcb11bb1222159e2\nmsgid \"\"\n\"To maintain a consistent API, for document types not supporting a chapter\"\n\" structure (like PDFs), :attr:`Document.chapter_count` is 1, and pages \"\n\"can also be loaded via tuples *(0, pno)*. See this [#f3]_ footnote for \"\n\"comments on performance improvements.\"\nmsgstr \"\"\n\"일관된 API를 유지하기 위해 장 구조를 지원하지 않는 문서 타입(예: PDF)의 경우 \"\n\":attr:`Document.chapter_count` 는 1이며, 튜플 *(0, pno)* 를 통해 페이지를 로드할 수도 \"\n\"있습니다. 성능 개선에 대한 설명은 이 [#f3]_ 각주를 참조하세요.\"\n\n#: ../../document.rst:594 98c022087ffe4895a4720631007c2d24\nmsgid \"\"\n\"PDF only: Walk through all images and rewrite them according to the \"\n\"specified parameters. This is useful for reducing file size, changing \"\n\"image formats, or converting color spaces.\"\nmsgstr \"\"\n\"PDF 전용: 모든 이미지를 순회하고 지정된 매개변수에 따라 다시 작성합니다. 파일 크기 줄이기, 이미지 형식 변경 또는 색상 공간\"\n\" 변환에 유용합니다.\"\n\n#: ../../document.rst:596 b2634076489d41739029ea4fc04d66fb\nmsgid \"\"\n\"The typical usage is extra compression of images for significantly \"\n\"reducing the file size of the PDF. When setting quality and the dpi \"\n\"parameters to positive values and accepting defaults for the rest, the \"\n\"following will happen:\"\nmsgstr \"\"\n\"일반적인 사용법은 PDF 파일 크기를 크게 줄이기 위한 이미지의 추가 압축입니다. quality 및 dpi 매개변수를 양수 값으로 \"\n\"설정하고 나머지는 기본값을 사용하면 다음이 발생합니다:\"\n\n#: ../../document.rst:598 dd54469242944d74a52b379438f6cfc5\nmsgid \"\"\n\"Lossy and lossless images will be rewritten as JPEG images \"\n\"(FZ_RECOMPRESS_JPEG) as far as technically possible.\"\nmsgstr \"손실 및 무손실 이미지는 기술적으로 가능한 한 JPEG 이미지(FZ_RECOMPRESS_JPEG)로 다시 작성됩니다.\"\n\n#: ../../document.rst:600 3fd86e19b8184fcea5b0e19beceb7d0e\nmsgid \"\"\n\"Bitonal (monochrome) images will be rewritten in FAX format \"\n\"(FZ_RECOMPRESS_FAX).\"\nmsgstr \"이진(단색) 이미지는 FAX 형식(FZ_RECOMPRESS_FAX)으로 다시 작성됩니다.\"\n\n#: ../../document.rst:602 41c0341ee203444eb721a4bfefa8be54\nmsgid \"Subsampling method is **FZ_SUBSAMPLE_AVERAGE** (see below).\"\nmsgstr \"서브샘플링 방법은 **FZ_SUBSAMPLE_AVERAGE** 입니다(아래 참조).\"\n\n#: ../../document.rst:604 896371b0945e44788072f44b80bdc859\nmsgid \"\"\n\"target DPI value for the resampled images. Ignored if `dpi_threshold` is \"\n\"`None`, otherwise must be less than `dpi_threshold` and positive.\"\nmsgstr \"\"\n\"리샘플링된 이미지의 대상 DPI 값. `dpi_threshold` 가 `None` 이면 무시되고, 그렇지 않으면 \"\n\"`dpi_threshold` 보다 작고 양수여야 합니다.\"\n\n#: ../../document.rst:606 82cca5a2875740f78ab1af43a1df9670\nmsgid \"\"\n\"If None (the default) no resampling takes place. Otherwise images with a \"\n\"DPI value larger than this will be resampled to `dpi_target` (which must \"\n\"be less than `dpi_threshold`).\"\nmsgstr \"\"\n\"None(기본값)이면 리샘플링이 수행되지 않습니다. 그렇지 않으면 이보다 큰 DPI 값을 가진 이미지가 `dpi_target` \"\n\"(이것은 `dpi_threshold` 보다 작아야 함)로 리샘플링됩니다.\"\n\n#: ../../document.rst:608 04ad6d72eb9f455dbc3c3035cd070094\nmsgid \"\"\n\"desired target JPEG quality, a value between 0 and 100. 0 means no \"\n\"quality change, 100 means best quality.\"\nmsgstr \"원하는 대상 JPEG 품질, 0과 100 사이의 값. 0은 품질 변경 없음, 100은 최고 품질을 의미합니다.\"\n\n#: ../../document.rst:610 8f1a2bc154a04ed6a7358524fa961968\nmsgid \"include lossy image types (e.g. JPEG).\"\nmsgstr \"손실 이미지 타입 포함(예: JPEG).\"\n\n#: ../../document.rst:612 da7e5cc3e2a14e5fa0ac5bd81550eafe\nmsgid \"include lossless image types (e.g. PNG).\"\nmsgstr \"무손실 이미지 타입 포함(예: PNG).\"\n\n#: ../../document.rst:614 e7d1e36e44204076baa7694b46d1124e\nmsgid \"include black-and-white images (e.g. FAX).\"\nmsgstr \"흑백 이미지 포함(예: FAX).\"\n\n#: ../../document.rst:616 2fa81fe258354e9f8dd69f3d1c236a06\nmsgid \"include colored images.\"\nmsgstr \"컬러 이미지 포함.\"\n\n#: ../../document.rst:618 609b31a2a0e643b0877791e7c36e8099\nmsgid \"include grayscale images.\"\nmsgstr \"그레이스케일 이미지 포함.\"\n\n#: ../../document.rst:620 ba3be6437eaf4297a72fb3988952b40a\nmsgid \"\"\n\"if True, the PDF will be converted to grayscale by executing \"\n\":meth:`Document.recolor` before all image processing. Please note that \"\n\"this will also change text and vector graphics to grayscale -- not just \"\n\"the images.\"\nmsgstr \"\"\n\"True이면 모든 이미지 처리 전에 :meth:`Document.recolor` 를 실행하여 PDF가 그레이스케일로 변환됩니다. \"\n\"이것은 이미지뿐만 아니라 텍스트와 벡터 그래픽도 그레이스케일로 변경합니다.\"\n\n#: ../../document.rst:622 3273b321899f43edad29c647ab92b4e0\nmsgid \"\"\n\"This parameter is intended for expert users. Except ``set_to_gray``, all \"\n\"other parameters are ignored. It must be an object prepared in the \"\n\"following way: ``options = pymupdf.mupdf.PdfImageRewriterOptions()``. \"\n\"Then attributes of this object can be set to achieve fine-grained \"\n\"control. Following are the adjustable attributes of the ``options`` \"\n\"object and their default (do nothing) values.\"\nmsgstr \"\"\n\"이 매개변수는 전문 사용자를 위한 것입니다. ``set_to_gray`` 를 제외하고 다른 모든 매개변수는 무시됩니다. 다음 \"\n\"방법으로 준비된 객체여야 합니다: ``options = pymupdf.mupdf.PdfImageRewriterOptions()``.\"\n\" 그런 다음 이 객체의 속성을 설정하여 세밀한 제어를 달성할 수 있습니다. 다음은 ``options`` 객체의 조정 가능한 속성과 \"\n\"기본값(아무 작업도 하지 않음)입니다.\"\n\n#: ../../document.rst:652 d66b892761bc466a984fd57fd3e38eb2\nmsgid \"\"\n\"The ``*_recompress_method`` attributes may be one of the values \"\n\"**FZ_RECOMPRESS_NEVER (0), FZ_RECOMPRESS_SAME (1), FZ_RECOMPRESS_LOSSLESS\"\n\" (2), FZ_RECOMPRESS_JPEG (3), FZ_RECOMPRESS_J2K (4), FZ_RECOMPRESS_FAX \"\n\"(5)**. Value FZ_RECOMPRESS_NEVER will skip this image type altogether and\"\n\" FZ_RECOMPRESS_SAME will not change the type. The other values will \"\n\"execute type conversions (as far as technically possible).\"\nmsgstr \"\"\n\"``*_recompress_method`` 속성은 **FZ_RECOMPRESS_NEVER (0), FZ_RECOMPRESS_SAME\"\n\" (1), FZ_RECOMPRESS_LOSSLESS (2), FZ_RECOMPRESS_JPEG (3), \"\n\"FZ_RECOMPRESS_J2K (4), FZ_RECOMPRESS_FAX (5)** 중 하나일 수 있습니다. 값 \"\n\"FZ_RECOMPRESS_NEVER는 이 이미지 타입을 완전히 건너뛰고 FZ_RECOMPRESS_SAME는 타입을 변경하지 \"\n\"않습니다. 다른 값은 타입 변환을 실행합니다(기술적으로 가능한 한).\"\n\n#: ../../document.rst:654 f6ec6ec93320485ebaff083bc3a12743\nmsgid \"\"\n\"The ``*_quality`` values are strings of integers from \\\"0\\\" to \\\"100\\\" or\"\n\" ``None``.\"\nmsgstr \"``*_quality`` 값은 \\\"0\\\" 부터 \\\"100\\\" 까지의 정수 문자열 또는 ``None`` 입니다.\"\n\n#: ../../document.rst:656 73c97c37daf445bb8faa816d1e6c2ba6\nmsgid \"\"\n\"The ``*_subsample_method`` attributes are either **FZ_SUBSAMPLE_AVERAGE \"\n\"(0)** or **FZ_SUBSAMPLE_BICUBIC (1)** and refer to how a pixel value is \"\n\"derived from its neighboring pixels during subsampling. For some \"\n\"background see `this Wikipedia article about bicubic interpolation \"\n\"<https://en.wikipedia.org/wiki/Bicubic_interpolation>`_.\"\nmsgstr \"\"\n\"``*_subsample_method`` 속성은 **FZ_SUBSAMPLE_AVERAGE (0)** 또는 \"\n\"**FZ_SUBSAMPLE_BICUBIC (1)** 이며, 서브샘플링 중 픽셀 값이 인접 픽셀에서 파생되는 방식을 나타냅니다. 배경\"\n\" 정보는 `이 Wikipedia 기사 about bicubic interpolation \"\n\"<https://en.wikipedia.org/wiki/Bicubic_interpolation>`_ 를 참조하세요.\"\n\n#: ../../document.rst:658 3b1ef034e55b417cbc149276289a674f\nmsgid \"\"\n\"Attributes ``*_subsample_threshold`` excludes images from subsampling \"\n\"which have a lower DPI. Participating images will be subsampled to the \"\n\"DPI values given by the ``*_subsample_to`` values. Values of 0 mean that \"\n\"no subsampling will take place.\"\nmsgstr \"\"\n\"속성 ``*_subsample_threshold`` 는 더 낮은 DPI를 가진 이미지를 서브샘플링에서 제외합니다. 참여하는 이미지는\"\n\" ``*_subsample_to`` 값으로 주어진 DPI 값으로 서브샘플링됩니다. 0 값은 서브샘플링이 수행되지 않음을 의미합니다.\"\n\n#: ../../document.rst:660 0d8fc34344494f938fe10a322d66c539\nmsgid \"\"\n\"The ``*_subsample_threshold`` values should be chosen notably larger than\"\n\" the ``*_subsample_to`` values to ensure that there are enough size \"\n\"savings. After all, every subsampling inevitably incurs quality losses.\"\nmsgstr \"\"\n\"``*_subsample_threshold`` 값은 충분한 크기 절감을 보장하기 위해 ``*_subsample_to`` 값보다 \"\n\"상당히 크게 선택해야 합니다. 결국 모든 서브샘플링은 불가피하게 품질 손실을 초래합니다.\"\n\n#: ../../document.rst:662 79510e56339f460e9782beef46bd250d\nmsgid \"An example for a good choice is ``threshold=100`` and ``to=72``.\"\nmsgstr \"좋은 선택의 예는 ``threshold=100`` 및 ``to=72`` 입니다.\"\n\n#: ../../document.rst:667 773a1b450cb1473aa93e0cf41357de02\nmsgid \"\"\n\"PDF only: Change the color component counts for all object types text, \"\n\"images and vector graphics for all pages.\"\nmsgstr \"PDF 전용: 모든 페이지의 모든 객체 타입 텍스트, 이미지 및 벡터 그래픽의 색상 구성 요소 수를 변경합니다.\"\n\n#: ../../document.rst:669 3d7d6e5b619c4faba15d3ba29b0e5c9b\nmsgid \"\"\n\"desired color space indicated by the number of color components: 1 = \"\n\"DeviceGRAY, 3 = DeviceRGB, 4 = DeviceCMYK.\"\nmsgstr \"색상 구성 요소 수로 표시되는 원하는 색상 공간: 1 = DeviceGRAY, 3 = DeviceRGB, 4 = DeviceCMYK.\"\n\n#: ../../document.rst:671 231bbb29ae294db0a5c6b91cedb5bc93\nmsgid \"\"\n\"The typical use case is 1 (DeviceGRAY) which converts the PDF to \"\n\"grayscale.\"\nmsgstr \"일반적인 사용 사례는 PDF를 그레이스케일로 변환하는 1 (DeviceGRAY) 입니다.\"\n\n#: ../../document.rst:676 25493f351a06440fb51cb6d332c4e8ab\nmsgid \"New in v1.16.10\"\nmsgstr \"v1.16.10에서 새로 추가됨\"\n\n#: ../../document.rst:678 a43f270497744fba8c4c60e674ced034\nmsgid \"\"\n\"PDF only: Provide a new copy of a page after finishing and updating all \"\n\"pending changes.\"\nmsgstr \"PDF 전용: 모든 보류 중인 변경 사항을 완료하고 업데이트한 후 페이지의 새 복사본을 제공합니다.\"\n\n#: ../../document.rst:680 eed0d5bbb0e34e5a98d5d7d1347f7563\nmsgid \"page object.\"\nmsgstr \"페이지 객체.\"\n\n#: ../../document.rst:685 5859498b41324ff2904041f7a4135acf\nmsgid \"\"\n\"a new copy of the same page. All pending updates (e.g. to annotations or \"\n\"widgets) will be finalized and a fresh copy of the page will be loaded.  \"\n\".. note:: In a typical use case, a page :ref:`Pixmap` should be taken \"\n\"after annotations / widgets have been added or changed. To force all \"\n\"those changes being reflected in the page structure, this method re-\"\n\"instates a fresh copy while keeping the object hierarchy \\\"document -> \"\n\"page -> annotations/widgets\\\" intact.\"\nmsgstr \"\"\n\n#: ../../document.rst:685 669719b216f545c294672354612d11fa\nmsgid \"\"\n\"a new copy of the same page. All pending updates (e.g. to annotations or \"\n\"widgets) will be finalized and a fresh copy of the page will be loaded.\"\nmsgstr \"동일한 페이지의 새 복사본. 모든 보류 중인 업데이트(예: 주석 또는 위젯)가 완료되고 페이지의 새 복사본이 로드됩니다.\"\n\n#: ../../document.rst:687 c3492c9a84d2493fa5a46a354f97ebb6\nmsgid \"\"\n\"In a typical use case, a page :ref:`Pixmap` should be taken after \"\n\"annotations / widgets have been added or changed. To force all those \"\n\"changes being reflected in the page structure, this method re-instates a \"\n\"fresh copy while keeping the object hierarchy \\\"document -> page -> \"\n\"annotations/widgets\\\" intact.\"\nmsgstr \"\"\n\"일반적인 사용 사례에서 페이지 :ref:`Pixmap` 은 주석/위젯이 추가되거나 변경된 후에 가져와야 합니다. 모든 변경 사항이 \"\n\"페이지 구조에 반영되도록 하려면 이 메서드는 객체 계층 구조 \\\"document -> page -> annotations/widgets\\\" \"\n\"를 그대로 유지하면서 새 복사본을 다시 설정합니다.\"\n\n#: ../../document.rst:692 b7bb34b4f16946e28a2d3112f022c456\nmsgid \"PDF only: Convert destination names into a Python dict.\"\nmsgstr \"PDF 전용: 대상 이름을 Python dict로 변환합니다.\"\n\n#: ../../document.rst:694 2d5cec850cd44110ab3c2074136bd4ce\n#, python-brace-format\nmsgid \"\"\n\"A dictionary with the following layout:  * *key*: (str) the name. * \"\n\"*value*: (dict) with the following layout:     * \\\"page\\\":  target page \"\n\"number (0-based). If no page number found -1.     * \\\"to\\\": (x, y) target\"\n\" point on page. Currently in PDF coordinates,       i.e. point (0,0) is \"\n\"the bottom-left of the page.     * \\\"zoom\\\": (float) the zoom factor.\"\n\"     * \\\"dest\\\": (str) only present if the target location on the page \"\n\"has       not been provided as \\\"/XYZ\\\" or if no page number was found. \"\n\"Examples::      {         '__bookmark_1': {'page': 0, 'to': (0.0, 541.0),\"\n\" 'zoom': 0.0},         '__bookmark_2': {'page': 0, 'to': (0.0, 481.45), \"\n\"'zoom': 0.0},     }  or::      {         \"\n\"'21154a7c20684ceb91f9c9adc3b677c40': {'page': -1, 'dest': '/XYZ 15.75 \"\n\"1486 0'},         ...     }\"\nmsgstr \"\"\n\n#: ../../document.rst:695 4a7ee4c9ba2a4d3a85f45e05d21d7585\nmsgid \"A dictionary with the following layout:\"\nmsgstr \"다음 레이아웃을 가진 딕셔너리:\"\n\n#: ../../document.rst:697 c5edbf04328248a4b31185f38a0a9e88\nmsgid \"*key*: (str) the name.\"\nmsgstr \"*key*: (str) 이름.\"\n\n#: ../../document.rst:703 ce2e9cdb367e4116a485b2e37d0c68a9\nmsgid \"*value*: (dict) with the following layout:\"\nmsgstr \"*value*: (dict) 다음 레이아웃을 가진:\"\n\n#: ../../document.rst:699 36f39015e34140bf9600dc4e0a7dd82a\nmsgid \"\\\"page\\\":  target page number (0-based). If no page number found -1.\"\nmsgstr \"\\\"page\\\": 대상 페이지 번호(0 기반). 페이지 번호를 찾을 수 없으면 -1.\"\n\n#: ../../document.rst:700 1febb4d93dd3459a9e791eb0783deebb\nmsgid \"\"\n\"\\\"to\\\": (x, y) target point on page. Currently in PDF coordinates, i.e. \"\n\"point (0,0) is the bottom-left of the page.\"\nmsgstr \"\\\"to\\\": (x, y) 페이지의 대상 점. 현재 PDF 좌표계를 사용하며, 즉 점 (0,0)은 페이지의 왼쪽 아래입니다.\"\n\n#: ../../document.rst:702 73ea9e5382d746798763ab0603096cbb\nmsgid \"\\\"zoom\\\": (float) the zoom factor.\"\nmsgstr \"\\\"zoom\\\": (float) 확대/축소 인수.\"\n\n#: ../../document.rst:703 1238fa32b21742a79624b48be42151f8\nmsgid \"\"\n\"\\\"dest\\\": (str) only present if the target location on the page has not \"\n\"been provided as \\\"/XYZ\\\" or if no page number was found.\"\nmsgstr \"\\\"dest\\\": (str) 페이지의 대상 위치가 \\\"/XYZ\\\" 로 제공되지 않았거나 페이지 번호를 찾을 수 없는 경우에만 존재합니다.\"\n\n#: ../../document.rst:705 425fb4334a644c2db4c6eb473e93a78e\nmsgid \"Examples::\"\nmsgstr \"예제::\"\n\n#: ../../document.rst:712 a20f62157adf4795a39385d09af8fd54\nmsgid \"or::\"\nmsgstr \"또는::\"\n\n#: ../../document.rst:719 7a833515e8cd42c897ce8167af8a9b8f\nmsgid \"\"\n\"All names found in the catalog under keys \\\"/Dests\\\" and \\\"/Names/Dests\\\"\"\n\" are included.\"\nmsgstr \"카탈로그의 \\\"/Dests\\\" 및 \\\"/Names/Dests\\\" 키 아래에서 찾은 모든 이름이 포함됩니다.\"\n\n#: ../../document.rst:722 3a95051f6b30463e8c0e2ea68b6cc48f\nmsgid \"New in v1.23.6\"\nmsgstr \"v1.23.6에서 새로 추가됨\"\n\n#: ../../document.rst:727 ../../document.rst:737 ../../document.rst:1166\n#: ../../document.rst:1176 ../../document.rst:1188\n#: 318e00602e594f4dbd1ab58104d6d6e6 8ce28861dec241f992672b27eed544d9\n#: cc7d97f955c543a69b42fb763c14b07f ccd76c30264f49b0b6bc13b131a26967\n#: d835c71b1d154bb2be4c1c8efc97af43\nmsgid \"New in v1.17.7\"\nmsgstr \"v1.17.7에서 새로 추가됨\"\n\n#: ../../document.rst:729 1b80bd2d1f5a41419012ecb261a6db97\nmsgid \"\"\n\"PDF only: Return the unrotated page rectangle -- **without loading the \"\n\"page** (via :meth:`Document.load_page`). This is meant for internal \"\n\"purpose requiring best possible performance.\"\nmsgstr \"PDF 전용: 회전되지 않은 페이지 사각형을 반환합니다 -- **페이지를 로드하지 않고** (:meth:`Document.load_page` 를 통해). 최상의 성능이 필요한 내부 목적을 위한 것입니다.\"\n\n#: ../../document.rst:731 ../../document.rst:741\n#: 19f19a11c82e4a50907e74763e0e965d 8c2c15d72ebf4a9990d269ea811b7348\nmsgid \"0-based page number.\"\nmsgstr \"0-기반 페이지 번호.\"\n\n#: ../../document.rst:733 a2e9807b52784408a6d2c65afb8f36de\nmsgid \":ref:`Rect` of the page like :meth:`Page.rect`, but ignoring any rotation.\"\nmsgstr \":meth:`Page.rect` 와 같은 페이지의 :ref:`Rect` 이지만 회전은 무시합니다.\"\n\n#: ../../document.rst:739 2d213ca7d8494aa7b9c8fd1b4e3d4dfd\nmsgid \"\"\n\"PDF only: Return the :data:`xref` of the page -- **without loading the \"\n\"page** (via :meth:`Document.load_page`). This is meant for internal \"\n\"purpose requiring best possible performance.\"\nmsgstr \"PDF 전용: 페이지의 :data:`xref` 를 반환합니다 -- **페이지를 로드하지 않고** (:meth:`Document.load_page` 를 통해). 최상의 성능이 필요한 내부 목적을 위한 것입니다.\"\n\n#: ../../document.rst:743 da21a126d6f04c3abec953dfcc2675ad\nmsgid \":data:`xref` of the page like :attr:`Page.xref`.\"\nmsgstr \":attr:`Page.xref` 와 같은 페이지의 :data:`xref`.\"\n\n#: ../../document.rst:747 71d4791dad1f4445aa3e3040d731738f\nmsgid \"New in v1.16.4\"\nmsgstr \"v1.16.4에서 새로 추가됨\"\n\n#: ../../document.rst:749 b38a2716dd8c424d91d72f843b002a17\nmsgid \"\"\n\"A generator for a range of pages. Parameters have the same meaning as in \"\n\"the built-in function *range()*. Intended for expressions of the form \"\n\"*\\\"for page in doc.pages(start, stop, step): ...\\\"*.\"\nmsgstr \"페이지 범위에 대한 생성자. 매개변수는 내장 함수 *range()* 와 동일한 의미를 가집니다. *\\\"for page in doc.pages(start, stop, step): ...\\\"* 형식의 표현식을 위한 것입니다.\"\n\n#: ../../document.rst:751 616de960867c4972a74ce8066c419f0d\nmsgid \"\"\n\"start iteration with this page number. Default is zero, allowed values \"\n\"are `-∞ < start < page_count`. While this is negative, :attr:`page_count`\"\n\" is added **before** starting the iteration.\"\nmsgstr \"이 페이지 번호로 반복을 시작합니다. 기본값은 0이며, 허용되는 값은 `-∞ < start < page_count` 입니다. 이 값이 음수인 동안 반복을 시작하기 **전에** :attr:`page_count` 가 추가됩니다.\"\n\n#: ../../document.rst:752 ecb933c801174ce48e94a1c20e8f0c8f\nmsgid \"\"\n\"stop iteration at this page number. Default is :attr:`page_count`, \"\n\"possible are `-∞ < stop <= page_count`. Larger values are **silently \"\n\"replaced** by the default. Negative values will cyclically emit the pages\"\n\" in reversed order. As with the built-in *range()*, this is the first \"\n\"page **not** returned.\"\nmsgstr \"이 페이지 번호에서 반복을 중지합니다. 기본값은 :attr:`page_count` 이며, 가능한 값은 `-∞ < stop <= page_count` 입니다. 더 큰 값은 기본값으로 **조용히 대체됩니다**. 음수 값은 역순으로 페이지를 순환적으로 생성합니다. 내장 *range()* 와 마찬가지로 이것은 **반환되지 않는** 첫 번째 페이지입니다.\"\n\n#: ../../document.rst:753 b9ce7f24cc314a7384140aaf41765dcd\nmsgid \"\"\n\"stepping value. Defaults are 1 if start < stop and -1 if start > stop. \"\n\"Zero is not allowed.\"\nmsgstr \"스텝 값. start < stop 이면 기본값은 1이고 start > stop 이면 -1입니다. 0은 허용되지 않습니다.\"\n\n#: ../../document.rst:755 c8272a49a7154ff28e5cd556509e8b79\nmsgid \"\"\n\"a generator iterator over the document's pages. Some examples:  * \"\n\"\\\"doc.pages()\\\" emits all pages. * \\\"doc.pages(4, 9, 2)\\\" emits pages 4, \"\n\"6, 8. * \\\"doc.pages(0, None, 2)\\\" emits all pages with even numbers. * \"\n\"\\\"doc.pages(-2)\\\" emits the last two pages. * \\\"doc.pages(-1, -1)\\\" emits\"\n\" all pages in reversed order. * \\\"doc.pages(-1, -10)\\\" always emits 10 \"\n\"pages in reversed order, starting with the last page -- **repeatedly** if\"\n\" the document has less than 10 pages. So for a 4-page document the \"\n\"following page numbers are emitted: 3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, \"\n\"3.\"\nmsgstr \"\"\n\n#: ../../document.rst:755 a4556cefb645478780d73c0fd90ce03a\nmsgid \"a generator iterator over the document's pages. Some examples:\"\nmsgstr \"문서의 페이지에 대한 생성기 반복자. 몇 가지 예:\"\n\n#: ../../document.rst:757 2d87cebad989408c8cbfc49674333423\nmsgid \"\\\"doc.pages()\\\" emits all pages.\"\nmsgstr \"\\\"doc.pages()\\\" 는 모든 페이지를 생성합니다.\"\n\n#: ../../document.rst:758 0747620460554d40a76ff69a1f360515\nmsgid \"\\\"doc.pages(4, 9, 2)\\\" emits pages 4, 6, 8.\"\nmsgstr \"\\\"doc.pages(4, 9, 2)\\\" 는 페이지 4, 6, 8을 생성합니다.\"\n\n#: ../../document.rst:759 71c55125fd7148589cf44fedef60ce3f\nmsgid \"\\\"doc.pages(0, None, 2)\\\" emits all pages with even numbers.\"\nmsgstr \"\\\"doc.pages(0, None, 2)\\\" 는 짝수 번호의 모든 페이지를 생성합니다.\"\n\n#: ../../document.rst:760 6b7d4859a5b94056a9dbfb03cf0c8b85\nmsgid \"\\\"doc.pages(-2)\\\" emits the last two pages.\"\nmsgstr \"\\\"doc.pages(-2)\\\" 는 마지막 두 페이지를 생성합니다.\"\n\n#: ../../document.rst:761 be1f9733ac2c48febc92b6717fb90069\nmsgid \"\\\"doc.pages(-1, -1)\\\" emits all pages in reversed order.\"\nmsgstr \"\\\"doc.pages(-1, -1)\\\" 는 모든 페이지를 역순으로 생성합니다.\"\n\n#: ../../document.rst:762 6841397d69e848799ce8762dc39001cd\nmsgid \"\"\n\"\\\"doc.pages(-1, -10)\\\" always emits 10 pages in reversed order, starting \"\n\"with the last page -- **repeatedly** if the document has less than 10 \"\n\"pages. So for a 4-page document the following page numbers are emitted: \"\n\"3, 2, 1, 0, 3, 2, 1, 0, 3, 2, 1, 0, 3.\"\nmsgstr \"\"\n\"\\\"doc.pages(-1, -10)\\\" 는 항상 마지막 페이지부터 시작하여 역순으로 10페이지를 생성합니다. 문서가 10페이지 \"\n\"미만이면 **반복적으로** 생성합니다. 따라서 4페이지 문서의 경우 다음 페이지 번호가 생성됩니다: 3, 2, 1, 0, 3, 2,\"\n\" 1, 0, 3, 2, 1, 0, 3.\"\n\n#: ../../document.rst:771 5454d912c78644678b8b4dbeb3f774d8\nmsgid \"\"\n\"Create a PDF version of the current document and write it to memory. \"\n\"**All document types** are supported. The parameters have the same \"\n\"meaning as in :meth:`insert_pdf`. In essence, you can restrict the \"\n\"conversion to a page subset, specify page rotation, and revert page \"\n\"sequence.\"\nmsgstr \"\"\n\"현재 문서의 PDF 버전을 생성하고 메모리에 씁니다. **모든 문서 타입** 이 지원됩니다. 매개변수는 \"\n\":meth:`insert_pdf` 와 동일한 의미를 가집니다. 본질적으로 페이지 하위 집합으로 변환을 제한하고, 페이지 회전을 \"\n\"지정하고, 페이지 순서를 되돌릴 수 있습니다.\"\n\n#: ../../document.rst:773 d0862bd7eb5f45f68b39be608d7ceacc\nmsgid \"first page to copy (0-based). Default is first page.\"\nmsgstr \"복사할 첫 번째 페이지(0 기반). 기본값은 첫 번째 페이지입니다.\"\n\n#: ../../document.rst:775 7ba7a5e06cbc4055830d3f4e5ba74e33\nmsgid \"last page to copy (0-based). Default is last page.\"\nmsgstr \"복사할 마지막 페이지(0 기반). 기본값은 마지막 페이지입니다.\"\n\n#: ../../document.rst:777 32ffc71c0b044be388ae0365845a51f5\nmsgid \"\"\n\"rotation angle. Default is 0 (no rotation). Should be *n * 90* with an \"\n\"integer n (not checked).\"\nmsgstr \"회전 각도. 기본값은 0(회전 없음). 정수 n(확인되지 않음)을 사용한 *n * 90* 이어야 합니다.\"\n\n#: ../../document.rst:780 858d98a578db4243937c2a20d50596c3\nmsgid \"\"\n\"a Python *bytes* object containing a PDF file image. It is created by \"\n\"internally using `tobytes(garbage=4, deflate=True)`. See :meth:`tobytes`.\"\n\" You can output it directly to disk or open it as a PDF. Here are some \"\n\"examples::  >>> # convert an XPS file to PDF >>> xps = \"\n\"pymupdf.open(\\\"some.xps\\\") >>> pdfbytes = xps.convert_to_pdf() >>> >>> # \"\n\"either do this --> >>> pdf = pymupdf.open(\\\"pdf\\\", pdfbytes) >>> \"\n\"pdf.save(\\\"some.pdf\\\") >>> >>> # or this --> >>> pdfout = \"\n\"open(\\\"some.pdf\\\", \\\"wb\\\") >>> pdfout.tobytes(pdfbytes) >>> \"\n\"pdfout.close()  >>> # copy image files to PDF pages >>> # each page will \"\n\"have image dimensions >>> doc = pymupdf.open()                     # new \"\n\"PDF >>> imglist = [ ... image file names ...] # e.g. a directory listing \"\n\">>> for img in imglist:         imgdoc=pymupdf.open(img)           # open\"\n\" image as a document         pdfbytes=imgdoc.convert_to_pdf()  # make a \"\n\"1-page PDF of it         imgpdf=pymupdf.open(\\\"pdf\\\", pdfbytes)         \"\n\"doc.insert_pdf(imgpdf)             # insert the image PDF >>> \"\n\"doc.save(\\\"allmyimages.pdf\\\")\"\nmsgstr \"\"\n\n#: ../../document.rst:780 63c567b2ee504806a11908cc7eda7ddf\nmsgid \"\"\n\"a Python *bytes* object containing a PDF file image. It is created by \"\n\"internally using `tobytes(garbage=4, deflate=True)`. See :meth:`tobytes`.\"\n\" You can output it directly to disk or open it as a PDF. Here are some \"\n\"examples::\"\nmsgstr \"\"\n\"PDF 파일 이미지를 포함하는 Python *bytes* 객체. 내부적으로 `tobytes(garbage=4, \"\n\"deflate=True)` 를 사용하여 생성됩니다. :meth:`tobytes` 를 참조하세요. 디스크에 직접 출력하거나 PDF로 \"\n\"열 수 있습니다. 다음은 몇 가지 예제입니다::\"\n\n#: ../../document.rst:806 f9ec8d426ea1403cb128eaa26c17445f\nmsgid \"\"\n\"The method uses the same logic as the *mutool convert* CLI. This works \"\n\"very well in most cases -- however, beware of the following limitations.\"\nmsgstr \"\"\n\"이 메서드는 *mutool convert* CLI와 동일한 로직을 사용합니다. 대부분의 경우 매우 잘 작동하지만, 다음 제한 사항에\"\n\" 주의하세요.\"\n\n#: ../../document.rst:808 25ee83c2d7134eb2a5c23c62615918c2\nmsgid \"\"\n\"Image files: perfect, no issues detected. However, image transparency is \"\n\"ignored. If you need that (like for a watermark), use \"\n\":meth:`Page.insert_image` instead. Otherwise, this method is recommended \"\n\"for its much better performance.\"\nmsgstr \"\"\n\"이미지 파일: 완벽하며 문제가 감지되지 않았습니다. 그러나 이미지 투명도는 무시됩니다. 그것이 필요한 경우(워터마크 등) 대신 \"\n\":meth:`Page.insert_image` 를 사용하세요. 그렇지 않으면 훨씬 더 나은 성능을 위해 이 메서드를 권장합니다.\"\n\n#: ../../document.rst:809 bd071d7930ef49e88ecd48466915e7e4\nmsgid \"\"\n\"XPS: appearance very good. Links work fine, outlines (bookmarks) are \"\n\"lost, but can easily be recovered [#f2]_.\"\nmsgstr \"XPS: 외관이 매우 좋습니다. 링크는 잘 작동하며, 개요(북마크)는 손실되지만 쉽게 복구할 수 있습니다 [#f2]_.\"\n\n#: ../../document.rst:810 0ce6d56bf96d4f8d9273e7511323fd86\nmsgid \"EPUB, CBZ, FB2: similar to XPS.\"\nmsgstr \"EPUB, CBZ, FB2: XPS와 유사합니다.\"\n\n#: ../../document.rst:811 ca4df8faae724b099cfc58f6b2e0ba4f\nmsgid \"\"\n\"SVG: medium. Roughly comparable to `svglib \"\n\"<https://github.com/deeplook/svglib>`_.\"\nmsgstr \"SVG: 중간. `svglib <https://github.com/deeplook/svglib>`_ 와 대략 비슷합니다.\"\n\n#: ../../document.rst:815 6058dd01aad748969b0759f8d71fdf49\nmsgid \"Creates a table of contents (TOC) out of the document's outline chain.\"\nmsgstr \"문서의 개요 체인에서 목차(TOC)를 생성합니다.\"\n\n#: ../../document.rst:817 3dbca0c298624898acbaf9e5f771ee53\nmsgid \"\"\n\"Indicates whether a simple or a detailed TOC is required. If ``False``, \"\n\"each item of the list also contains a dictionary with :ref:`linkDest` \"\n\"details for each outline entry.\"\nmsgstr \"\"\n\"간단한 TOC 또는 상세한 TOC가 필요한지 나타냅니다. ``False`` 이면 목록의 각 항목에는 각 개요 항목에 대한 \"\n\":ref:`linkDest` 세부 정보를 가진 딕셔너리도 포함됩니다.\"\n\n#: ../../document.rst:821 e90635c4d41840b49b24c4cedd58a56f\nmsgid \"\"\n\"a list of lists. Each entry has the form *[lvl, title, page, dest]*. Its \"\n\"entries have the following meanings:  * *lvl* -- hierarchy level \"\n\"(positive *int*). The first entry is always 1. Entries in a row are \"\n\"either **equal**, **increase** by 1, or **decrease** by any number. * \"\n\"*title* -- title (*str*) * *page* -- 1-based source page number (*int*). \"\n\"`-1` if no destination or outside document. * *dest* -- (*dict*) included\"\n\" only if *simple=False*. Contains details of the TOC item as follows:    \"\n\"- kind: destination kind, see :ref:`linkDest Kinds`.   - file: filename \"\n\"if kind is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.   - page: target \"\n\"page, 0-based, :data:`LINK_GOTOR` or :data:`LINK_GOTO` only.   - to: \"\n\"position on target page (:ref:`Point`).   - zoom: (float) zoom factor on \"\n\"target page.   - xref: :data:`xref` of the item (0 if no PDF).   - color:\"\n\" item color in PDF RGB format `(red, green, blue)`, or omitted (always \"\n\"omitted if no PDF).   - bold: true if bold item text or omitted. PDF \"\n\"only.   - italic: true if italic item text, or omitted. PDF only.   - \"\n\"collapse: true if sub-items are folded, or omitted. PDF only.   - \"\n\"nameddest: target name if kind=4. PDF only. (New in 1.23.7.)\"\nmsgstr \"\"\n\n#: ../../document.rst:821 1f916acfd2114c589944f42fe0849446\nmsgid \"\"\n\"a list of lists. Each entry has the form *[lvl, title, page, dest]*. Its \"\n\"entries have the following meanings:\"\nmsgstr \"리스트의 리스트. 각 항목은 *[lvl, title, page, dest]* 형식을 가집니다. 항목의 의미는 다음과 같습니다:\"\n\n#: ../../document.rst:823 7b36d87b6635435eafda08d85d16b1c8\nmsgid \"\"\n\"*lvl* -- hierarchy level (positive *int*). The first entry is always 1. \"\n\"Entries in a row are either **equal**, **increase** by 1, or **decrease**\"\n\" by any number.\"\nmsgstr \"\"\n\"*lvl* -- 계층 수준(양수 *int*). 첫 번째 항목은 항상 1입니다. 연속된 항목은 **같거나**, 1씩 **증가** \"\n\"하거나, 임의의 수만큼 **감소** 합니다.\"\n\n#: ../../document.rst:824 762b7e29dfec42879ab3702e5193f03c\nmsgid \"*title* -- title (*str*)\"\nmsgstr \"*title* -- 제목 (*str*)\"\n\n#: ../../document.rst:825 508de47267724444b36c28eb365184e6\nmsgid \"\"\n\"*page* -- 1-based source page number (*int*). `-1` if no destination or \"\n\"outside document.\"\nmsgstr \"*page* -- 1 기반 소스 페이지 번호 (*int*). 대상이 없거나 문서 외부인 경우 `-1`.\"\n\n#: ../../document.rst:826 5db26a9f7f3a4086ab52e489302c3e8b\nmsgid \"\"\n\"*dest* -- (*dict*) included only if *simple=False*. Contains details of \"\n\"the TOC item as follows:\"\nmsgstr \"\"\n\"*dest* -- (*dict*) *simple=False* 인 경우에만 포함됩니다. TOC 항목의 세부 정보를 다음과 같이 \"\n\"포함합니다:\"\n\n#: ../../document.rst:828 c6e92e67375d43cfae44581cd7f23c8f\nmsgid \"kind: destination kind, see :ref:`linkDest Kinds`.\"\nmsgstr \"kind: 대상 종류, :ref:`linkDest Kinds` 를 참조하세요.\"\n\n#: ../../document.rst:829 710dde73a6d7419e945fcb5b21e077d5\nmsgid \"file: filename if kind is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.\"\nmsgstr \"file: kind가 :data:`LINK_GOTOR` 또는 :data:`LINK_LAUNCH` 인 경우 파일 이름.\"\n\n#: ../../document.rst:830 a8bac0a6ac9c43eba24ad53403fc47fa\nmsgid \"page: target page, 0-based, :data:`LINK_GOTOR` or :data:`LINK_GOTO` only.\"\nmsgstr \"page: 대상 페이지, 0 기반, :data:`LINK_GOTOR` 또는 :data:`LINK_GOTO` 전용.\"\n\n#: ../../document.rst:831 e9dc7affea7043e08fb2ab93ce8487c3\nmsgid \"to: position on target page (:ref:`Point`).\"\nmsgstr \"to: 대상 페이지의 위치 (:ref:`Point`).\"\n\n#: ../../document.rst:832 16c6f209da8c4387a905b11d0f262c91\nmsgid \"zoom: (float) zoom factor on target page.\"\nmsgstr \"zoom: (float) 대상 페이지의 확대/축소 배율.\"\n\n#: ../../document.rst:833 5b0b0da881014748befd8c9fbe86784b\nmsgid \"xref: :data:`xref` of the item (0 if no PDF).\"\nmsgstr \"xref: 항목의 :data:`xref` (PDF가 없으면 0).\"\n\n#: ../../document.rst:834 ea44c30a773848e4ae4dfc0449224998\nmsgid \"\"\n\"color: item color in PDF RGB format `(red, green, blue)`, or omitted \"\n\"(always omitted if no PDF).\"\nmsgstr \"color: PDF RGB 형식 `(red, green, blue)` 의 항목 색상, 또는 생략됨(PDF가 없으면 항상 생략됨).\"\n\n#: ../../document.rst:835 be0c1730211040fb87559842cb3f7d82\nmsgid \"bold: true if bold item text or omitted. PDF only.\"\nmsgstr \"bold: 굵은 항목 텍스트이면 true 또는 생략됨. PDF 전용.\"\n\n#: ../../document.rst:836 4db8cc6aef9c4e93b5370e0c0703d72b\nmsgid \"italic: true if italic item text, or omitted. PDF only.\"\nmsgstr \"italic: 기울임꼴 항목 텍스트이면 true 또는 생략됨. PDF 전용.\"\n\n#: ../../document.rst:837 dbdf470bbd3343aaa06aa7c92bdfa72b\nmsgid \"collapse: true if sub-items are folded, or omitted. PDF only.\"\nmsgstr \"collapse: 하위 항목이 접혀 있으면 true 또는 생략됨. PDF 전용.\"\n\n#: ../../document.rst:838 bfc462d0fb2e4bd19071f89ef50d7abe\nmsgid \"nameddest: target name if kind=4. PDF only. (New in 1.23.7.)\"\nmsgstr \"nameddest: kind=4인 경우 대상 이름. PDF 전용. (1.23.7에서 새로 추가됨.)\"\n\n#: ../../document.rst:845 c3fc69ce58de4a378d986b0b8c8b03e3\nmsgid \"\"\n\"PDF only: Return the PDF dictionary keys of the :data:`dictionary` object\"\n\" provided by its xref number.\"\nmsgstr \"PDF 전용: xref 번호로 제공된 :data:`dictionary` 객체의 PDF 딕셔너리 키를 반환합니다.\"\n\n#: ../../document.rst:847 e05f361902db4a438e95f2d0b6813501\nmsgid \"\"\n\"the :data:`xref`. *(Changed in v1.18.10)* Use `-1` to access the special \"\n\"dictionary \\\"PDF trailer\\\".\"\nmsgstr \"\"\n\":data:`xref`. *(v1.18.10에서 변경됨)* 특수 딕셔너리 \\\"PDF trailer\\\" 에 액세스하려면 `-1` 을 \"\n\"사용하세요.\"\n\n#: ../../document.rst:849 718fc9b6f9ea4799ad613e5ee06da903\nmsgid \"\"\n\"a tuple of dictionary keys present in object :data:`xref`. Examples:  >>>\"\n\" from pprint import pprint >>> import pymupdf >>> \"\n\"doc=pymupdf.open(\\\"pymupdf.pdf\\\") >>> xref = doc.page_xref(0)  # xref of \"\n\"page 0 >>> pprint(doc.xref_get_keys(xref))  # primary level keys of a \"\n\"page ('Type', 'Contents', 'Resources', 'MediaBox', 'Parent') >>> \"\n\"pprint(doc.xref_get_keys(-1))  # primary level keys of the trailer \"\n\"('Type', 'Index', 'Size', 'W', 'Root', 'Info', 'ID', 'Length', 'Filter') \"\n\">>>\"\nmsgstr \"\"\n\n#: ../../document.rst:849 aa7dc5420dc345bf862b4a857d55b1c9\nmsgid \"a tuple of dictionary keys present in object :data:`xref`. Examples:\"\nmsgstr \"객체 :data:`xref` 에 있는 딕셔너리 키의 튜플. 예:\"\n\n#: ../../document.rst:866 ac624cc28bac472580675edd1acf4436\nmsgid \"\"\n\"PDF only: Return type and value of a PDF dictionary key of a \"\n\":data:`dictionary` object given by its xref.\"\nmsgstr \"PDF 전용: xref로 제공된 :data:`dictionary` 객체의 PDF 딕셔너리 키의 타입과 값을 반환합니다.\"\n\n#: ../../document.rst:868 27544f0e3f84480f9d4ad7fc8619aa5b\nmsgid \"\"\n\"the :data:`xref`. *Changed in v1.18.10:* Use `-1` to access the special \"\n\"dictionary \\\"PDF trailer\\\".\"\nmsgstr \"\"\n\":data:`xref`. *v1.18.10에서 변경됨:* 특수 딕셔너리 \\\"PDF trailer\\\" 에 액세스하려면 `-1` 을 \"\n\"사용하세요.\"\n\n#: ../../document.rst:870 b7b4f4ca5ca84d3f9d6241f19925be5a\nmsgid \"\"\n\"the desired PDF key. Must **exactly** match (case-sensitive) one of the \"\n\"keys contained in :meth:`Document.xref_get_keys`.\"\nmsgstr \"\"\n\"원하는 PDF 키. :meth:`Document.xref_get_keys` 에 포함된 키 중 하나와 **정확히** 일치해야 \"\n\"합니다(대소문자 구분).\"\n\n#: ../../document.rst:874 7b79f18cd28e46c78897483bebddf81d\nmsgid \"\"\n\"A tuple (type, value) of strings, where type is one of \\\"xref\\\", \"\n\"\\\"array\\\", \\\"dict\\\", \\\"int\\\", \\\"float\\\", \\\"null\\\", \\\"bool\\\", \\\"name\\\", \"\n\"\\\"string\\\" or \\\"unknown\\\" (should not occur). Independent of \\\"type\\\", \"\n\"the value of the key is **always** formatted as a string -- see the \"\n\"following example -- and (almost always) a faithful reflection of what is\"\n\" stored in the PDF. In most cases, the format of the value string also \"\n\"gives a clue about the key type:\"\nmsgstr \"\"\n\"문자열의 튜플 (type, value), 여기서 type은 \\\"xref\\\", \\\"array\\\", \\\"dict\\\", \\\"int\\\", \"\n\"\\\"float\\\", \\\"null\\\", \\\"bool\\\", \\\"name\\\", \\\"string\\\" 또는 \\\"unknown\\\" (발생하지 \"\n\"않아야 함) 중 하나입니다. \\\"type\\\" 과 무관하게 키의 값은 **항상** 문자열로 포맷됩니다. 다음 예를 참조하세요. 그리고\"\n\" (거의 항상) PDF에 저장된 내용의 충실한 반영입니다. 대부분의 경우 값 문자열의 형식은 키 타입에 대한 힌트도 제공합니다:\"\n\n#: ../../document.rst:876 ec807984aaac414b99a33ab68d3799b1\nmsgid \"A \\\"name\\\" always starts with a \\\"/\\\" slash.\"\nmsgstr \"\\\"name\\\" 은 항상 \\\"/\\\" 슬래시로 시작합니다.\"\n\n#: ../../document.rst:877 3d6c9be670f643d0962169a4a9e69bba\nmsgid \"An \\\"xref\\\" always ends with \\\" 0 R\\\".\"\nmsgstr \"\\\"xref\\\" 는 항상 \\\" 0 R\\\" 로 끝납니다.\"\n\n#: ../../document.rst:878 cc26f6231b5d40ea99da42fb5fbd6e4e\nmsgid \"An \\\"array\\\" is always enclosed in \\\"[...]\\\" brackets.\"\nmsgstr \"\\\"array\\\" 는 항상 \\\"[...]\\\" 대괄호로 둘러싸여 있습니다.\"\n\n#: ../../document.rst:879 0e703bc78dfa46ef980a0afffddb7caf\nmsgid \"A \\\"dict\\\" is always enclosed in \\\"<<...>>\\\" brackets.\"\nmsgstr \"\\\"dict\\\" 는 항상 \\\"<<...>>\\\" 괄호로 둘러싸여 있습니다.\"\n\n#: ../../document.rst:880 846a9dca0e6c44aa99e0254bdf2882a7\nmsgid \"\"\n\"A \\\"bool\\\", resp. \\\"null\\\" always equal either \\\"true\\\", \\\"false\\\", resp.\"\n\" \\\"null\\\".\"\nmsgstr \"\\\"bool\\\" 또는 \\\"null\\\" 은 항상 \\\"true\\\", \\\"false\\\" 또는 \\\"null\\\" 과 같습니다.\"\n\n#: ../../document.rst:881 214cdbec5d6c4d08a8ec85d70a82023d\nmsgid \"\"\n\"\\\"float\\\" and \\\"int\\\" are represented by their string format -- and are \"\n\"thus not always distinguishable.\"\nmsgstr \"\\\"float\\\" 와 \\\"int\\\" 는 문자열 형식으로 표현되므로 항상 구별할 수 있는 것은 아닙니다.\"\n\n#: ../../document.rst:882 6b54a834dd684348a075258dcc77932e\nmsgid \"\"\n\"A \\\"string\\\" is converted to UTF-8 and may therefore deviate from what is\"\n\" stored in the PDF. For example, the PDF key \\\"Author\\\" may have a value \"\n\"of \\\"<FEFF004A006F0072006A00200058002E0020004D0063004B00690065>\\\" in the \"\n\"file, but the method will return `('string', 'Jorj X. McKie')`.\"\nmsgstr \"\"\n\"\\\"string\\\" 은 UTF-8로 변환되므로 PDF에 저장된 내용과 다를 수 있습니다. 예를 들어, PDF 키 \\\"Author\\\"\"\n\" 는 파일에서 \\\"<FEFF004A006F0072006A00200058002E0020004D0063004B00690065>\\\" 값을\"\n\" 가질 수 있지만, 이 메서드는 `('string', 'Jorj X. McKie')` 를 반환합니다.\"\n\n#: ../../document.rst:911 9cd16976fff44c6fb844b8cec7a2c169\nmsgid \"New in v1.18.7, changed in v 1.18.13\"\nmsgstr \"v1.18.7에서 새로 추가됨, v 1.18.13에서 변경됨\"\n\n#: ../../document.rst:912 0ac083b623a047b4bcf044eae05904aa\nmsgid \"Changed in v1.19.4: remove a key \\\"physically\\\" if set to \\\"null\\\".\"\nmsgstr \"v1.19.4에서 변경됨: \\\"null\\\" 로 설정된 경우 키를 \\\"물리적으로\\\" 제거합니다.\"\n\n#: ../../document.rst:914 64396e0edd7148ca84fae006294159f8\nmsgid \"\"\n\"PDF only: Set (add, update, delete) the value of a PDF key for the \"\n\":data:`dictionary` object given by its xref.\"\nmsgstr \"PDF 전용: xref로 제공된 :data:`dictionary` 객체에 대한 PDF 키의 값을 설정(추가, 업데이트, 삭제)합니다.\"\n\n#: ../../document.rst:916 5794fc8ff702458f9aaefe249a14c2ef\nmsgid \"\"\n\"This is an expert function: if you do not know what you are doing, there \"\n\"is a high risk to render (parts of) the PDF unusable. Please do consult \"\n\":ref:`AdobeManual` about object specification formats (page 18) and the \"\n\"structure of special dictionary types like page objects.\"\nmsgstr \"\"\n\"이것은 전문가용 함수입니다: 무엇을 하고 있는지 모르는 경우 PDF의 (일부)를 사용할 수 없게 만들 위험이 높습니다. 객체 사양 \"\n\"형식(18페이지) 및 페이지 객체와 같은 특수 딕셔너리 타입의 구조에 대해 :ref:`AdobeManual` 을 참조하세요.\"\n\n#: ../../document.rst:918 089d864880fa43b0a3e7c78b23aa1fd5\nmsgid \"\"\n\"the :data:`xref`. *Changed in v1.18.13:* To update the PDF trailer, \"\n\"specify -1.\"\nmsgstr \":data:`xref`. *v1.18.13에서 변경됨:* PDF 트레일러를 업데이트하려면 -1을 지정하세요.\"\n\n#: ../../document.rst:919 15673f6ba0f34016b8ae9065767b7d8b\nmsgid \"\"\n\"the desired PDF key (without leading \\\"/\\\"). Must not be empty. Any valid\"\n\" PDF key -- whether already present in the object (which will be \"\n\"overwritten) -- or new. It is possible to use PDF path notation like \"\n\"`\\\"Resources/ExtGState\\\"` -- which sets the value for key \"\n\"`\\\"/ExtGState\\\"` as a sub-object of `\\\"/Resources\\\"`.\"\nmsgstr \"\"\n\"원하는 PDF 키(앞의 \\\"/\\\" 없음). 비어 있지 않아야 합니다. 객체에 이미 있는(덮어쓰기됨) 유효한 PDF 키 또는 새 키.\"\n\" `\\\"Resources/ExtGState\\\"` 와 같은 PDF 경로 표기법을 사용할 수 있습니다. 이것은 \"\n\"`\\\"/Resources\\\"` 의 하위 객체로 `\\\"/ExtGState\\\"` 키의 값을 설정합니다.\"\n\n#: ../../document.rst:920 933213233ad746ad840f0156b1f94f1a\nmsgid \"\"\n\"the value for the key. It must be a non-empty string and, depending on \"\n\"the desired PDF object type, the following rules must be observed. There \"\n\"is some syntax checking, but **no type checking** and no checking if it \"\n\"makes sense PDF-wise, i.e. **no semantics checking**. Upper / lower case \"\n\"is important!\"\nmsgstr \"\"\n\"키의 값. 비어 있지 않은 문자열이어야 하며, 원하는 PDF 객체 타입에 따라 다음 규칙을 준수해야 합니다. 일부 구문 검사가 \"\n\"있지만 **타입 검사는 없으며** PDF 관점에서 의미가 있는지 확인하지 않습니다. 즉, **의미론 검사는 없습니다**. 대소문자가\"\n\" 중요합니다!\"\n\n#: ../../document.rst:922 88dc206233204bdfba432773e3390307\nmsgid \"\"\n\"*:data:`xref`* -- must be provided as `\\\"nnn 0 R\\\"` with a valid \"\n\":data:`xref` number nnn of the PDF. The suffix \\\"`0 R`\\\" is required to \"\n\"be recognizable as an xref by PDF applications.\"\nmsgstr \"\"\n\"*:data:`xref`* -- PDF의 유효한 :data:`xref` 번호 nnn을 사용하여 `\\\"nnn 0 R\\\"` 로 제공해야\"\n\" 합니다. PDF 애플리케이션에서 xref로 인식할 수 있도록 접미사 \\\"`0 R`\\\" 이 필요합니다.\"\n\n#: ../../document.rst:923 6925d7ed24cb4b64a6e6691de1cc2ad2\nmsgid \"\"\n\"**array** -- a string like `\\\"[a b c d e f]\\\"`. The brackets are \"\n\"required. Array items must be separated by at least one space (not commas\"\n\" like in Python). An empty array `\\\"[]\\\"` is possible and *equivalent* to\"\n\" removing the key. Array items may be any PDF objects, like dictionaries,\"\n\" xrefs, other arrays, etc. Like in Python, array items may be of \"\n\"different types.\"\nmsgstr \"\"\n\"**array** -- `\\\"[a b c d e f]\\\"` 와 같은 문자열. 대괄호가 필요합니다. 배열 항목은 최소한 하나의 \"\n\"공백으로 구분되어야 합니다(Python처럼 쉼표가 아님). 빈 배열 `\\\"[]\\\"` 가 가능하며 키 제거와 *동등* 합니다. 배열 \"\n\"항목은 딕셔너리, xref, 다른 배열 등과 같은 모든 PDF 객체일 수 있습니다. Python처럼 배열 항목은 다른 타입일 수 \"\n\"있습니다.\"\n\n#: ../../document.rst:924 28eb8fae1c82426ead4bb35d11289b23\nmsgid \"\"\n\"**dict** -- a string like `\\\"<< ... >>\\\"`. The brackets are required and \"\n\"must enclose a valid PDF dictionary definition. The empty dictionary \"\n\"`\\\"<<>>\\\"` is possible and *equivalent* to removing the key.\"\nmsgstr \"\"\n\"**dict** -- `\\\"<< ... >>\\\"` 와 같은 문자열. 괄호가 필요하며 유효한 PDF 딕셔너리 정의를 포함해야 합니다.\"\n\" 빈 딕셔너리 `\\\"<<>>\\\"` 가 가능하며 키 제거와 *동등* 합니다.\"\n\n#: ../../document.rst:925 a04a73f6b8654574bbd1a85f0a618a09\nmsgid \"**int** -- an integer formatted **as a string**.\"\nmsgstr \"**int** -- **문자열로** 포맷된 정수.\"\n\n#: ../../document.rst:926 aaaafb8231484e539107d63be48d47d6\nmsgid \"\"\n\"**float** -- a float formatted **as a string**. Scientific notation (with\"\n\" exponents) is **not allowed by PDF**.\"\nmsgstr \"**float** -- **문자열로** 포맷된 부동소수점. 과학적 표기법(지수 포함)은 **PDF에서 허용되지 않습니다**.\"\n\n#: ../../document.rst:927 37b8e833142747c3843fd9b6b6c7847b\nmsgid \"\"\n\"**null** -- the string `\\\"null\\\"`. This is the PDF equivalent to Python's\"\n\" `None` and causes the key to be ignored -- however not necessarily \"\n\"removed, resp. removed on saves with garbage collection. *Changed in \"\n\"v1.19.4:* If the key is no path hierarchy (i.e. contains no slash \\\"/\\\"),\"\n\" then it will be completely removed.\"\nmsgstr \"\"\n\"**null** -- 문자열 `\\\"null\\\"`. 이것은 Python의 `None` 과 동등한 PDF이며 키를 무시하게 만듭니다. \"\n\"그러나 반드시 제거되는 것은 아니며, 가비지 수집과 함께 저장 시 제거됩니다. *v1.19.4에서 변경됨:* 키가 경로 계층이 아닌\"\n\" 경우(즉, 슬래시 \\\"/\\\" 가 없음), 완전히 제거됩니다.\"\n\n#: ../../document.rst:928 216d5b52576143519f482ac216cb8057\nmsgid \"**bool** -- one of the strings `\\\"true\\\"` or `\\\"false\\\"`.\"\nmsgstr \"**bool** -- 문자열 `\\\"true\\\"` 또는 `\\\"false\\\"` 중 하나.\"\n\n#: ../../document.rst:929 f0e1858598fd41c29d7a96791dbc5f24\nmsgid \"\"\n\"**name** -- a valid PDF name with a leading slash like this: \"\n\"`\\\"/PageLayout\\\"`. See page 16 of the :ref:`AdobeManual`.\"\nmsgstr \"\"\n\"**name** -- 앞에 슬래시가 있는 유효한 PDF 이름, 예: `\\\"/PageLayout\\\"`. \"\n\":ref:`AdobeManual` 의 16페이지를 참조하세요.\"\n\n#: ../../document.rst:930 a914ca911c4c4159a3781a52ef7d1f98\nmsgid \"\"\n\"**string** -- a valid PDF string. **All PDF strings must be enclosed by \"\n\"brackets**. Denote the empty string as `\\\"()\\\"`. Depending on its \"\n\"content, the possible brackets are\"\nmsgstr \"\"\n\"**string** -- 유효한 PDF 문자열. **모든 PDF 문자열은 괄호로 둘러싸여야 합니다**. 빈 문자열은 `\\\"()\\\"`\"\n\" 로 표시합니다. 콘텐츠에 따라 가능한 괄호는\"\n\n#: ../../document.rst:932 1ed9166a48c545be82c39b80562dc2da\nmsgid \"\"\n\"\\\"(...)\\\" for ASCII-only text. Reserved PDF characters must be backslash-\"\n\"escaped and non-ASCII characters must be provided as 3-digit backslash-\"\n\"escaped octals -- including leading zeros. Example: 12 = 0x0C must be \"\n\"encoded as `\\\\014`.\"\nmsgstr \"\"\n\"ASCII 전용 텍스트의 경우 \\\"(...)\\\". 예약된 PDF 문자는 백슬래시 이스케이프되어야 하며, 비ASCII 문자는 앞의 \"\n\"0을 포함하여 3자리 백슬래시 이스케이프된 8진수로 제공되어야 합니다. 예: 12 = 0x0C는 `\\\\014` 로 인코딩되어야 \"\n\"합니다.\"\n\n#: ../../document.rst:933 d441845d0a85478fa7fc790d3b118854\nmsgid \"\"\n\"\\\"<...>\\\" for hex-encoded text. Every character must be represented by \"\n\"two hex-digits (lower or upper case).\"\nmsgstr \"16진수 인코딩된 텍스트의 경우 \\\"<...>\\\". 모든 문자는 두 자리 16진수(소문자 또는 대문자)로 표현되어야 합니다.\"\n\n#: ../../document.rst:935 a11c1a8286be4329a17ec5d7c98add0f\nmsgid \"\"\n\"If in doubt, we **strongly recommend** to use :meth:`get_pdf_str`! This \"\n\"function automatically generates the right brackets, escapes, and overall\"\n\" format. It will for example do conversions like these:\"\nmsgstr \"\"\n\"의심스러운 경우 :meth:`get_pdf_str` 사용을 **강력히 권장** 합니다! 이 함수는 올바른 괄호, 이스케이프 및 전체\"\n\" 형식을 자동으로 생성합니다. 예를 들어 다음과 같은 변환을 수행합니다:\"\n\n#: ../../document.rst:947 cf6f6128b6884ccabee6fba67627f2ec\nmsgid \"\"\n\"Creates a pixmap from page *pno* (zero-based). Invokes \"\n\":meth:`Page.get_pixmap`.\"\nmsgstr \"페이지 *pno* (0 기반)에서 pixmap을 생성합니다. :meth:`Page.get_pixmap` 을 호출합니다.\"\n\n#: ../../document.rst:949 f0955fd5487a4e5ea3ac0442b8e90f79\nmsgid \"All parameters except `pno` are *keyword-only.*\"\nmsgstr \"`pno` 를 제외한 모든 매개변수는 *키워드 전용* 입니다.\"\n\n#: ../../document.rst:951 3d8557ce87f14ec781fc2e843670c353\nmsgid \"page number, 0-based in `-∞ < pno < page_count`.\"\nmsgstr \"페이지 번호, `-∞ < pno < page_count` 에서 0 기반.\"\n\n#: ../../document.rst:953 2fd43704060b4800a4b0c48a6d84311a\nmsgid \":ref:`Pixmap`\"\nmsgstr \":ref:`Pixmap`\"\n\n#: ../../document.rst:957 962d634dfd4e4b6b850458e82fe4b7c9\nmsgid \"New in v1.16.13\"\nmsgstr \"v1.16.13에서 새로 추가됨\"\n\n#: ../../document.rst:958 9664b300564b4c1780ac04f4b998b8c2\nmsgid \"Changed in v1.18.11\"\nmsgstr \"v1.18.11에서 변경됨\"\n\n#: ../../document.rst:960 f7da10aa82f7472b861d90418a3c8b90\nmsgid \"PDF only: Return a list of all XObjects referenced by a page.\"\nmsgstr \"PDF 전용: 페이지에서 참조하는 모든 XObject 목록을 반환합니다.\"\n\n#: ../../document.rst:962 ../../document.rst:977 ../../document.rst:1004\n#: 573fd738d1a94d979da34f7c5a090cb7 6a0779fdfff54bad8d6c0b225fef12df\n#: 7ce886aac0b6421395e6edea44f4a2df\nmsgid \"page number, 0-based, `-∞ < pno < page_count`.\"\nmsgstr \"페이지 번호, 0 기반, `-∞ < pno < page_count`.\"\n\n#: ../../document.rst:965 356c31b720a14052a406e595f02cea3f\nmsgid \"\"\n\"a list of (non-image) XObjects. These objects typically represent pages \"\n\"*embedded* (not copied) from other PDFs. For example, \"\n\":meth:`Page.show_pdf_page` will create this type of object. An item of \"\n\"this list has the following layout: `(xref, name, invoker, bbox)`, where\"\n\"  * *:data:`xref`* (*int*) is the XObject's :data:`xref`. * **name** \"\n\"(*str*) is the symbolic name to reference the XObject. * **invoker** \"\n\"(*int*) the :data:`xref` of the invoking XObject or zero if the page \"\n\"directly invokes it. * **bbox** (:ref:`Rect`) the boundary box of the \"\n\"XObject's location on the page **in untransformed coordinates**. To get \"\n\"actual, non-rotated page coordinates, multiply with the page's \"\n\"transformation matrix :attr:`Page.transformation_matrix`. *Changed in \"\n\"v.18.11:* the bbox is now formatted as :ref:`Rect`.\"\nmsgstr \"\"\n\n#: ../../document.rst:965 f5e67a1ceb0f4ee98521899019f091fa\nmsgid \"\"\n\"a list of (non-image) XObjects. These objects typically represent pages \"\n\"*embedded* (not copied) from other PDFs. For example, \"\n\":meth:`Page.show_pdf_page` will create this type of object. An item of \"\n\"this list has the following layout: `(xref, name, invoker, bbox)`, where\"\nmsgstr \"\"\n\"(이미지가 아닌) XObject 목록. 이러한 객체는 일반적으로 다른 PDF에서 *임베디드된* (복사되지 않은) 페이지를 \"\n\"나타냅니다. 예를 들어, :meth:`Page.show_pdf_page` 는 이 타입의 객체를 생성합니다. 이 목록의 항목은 다음 \"\n\"레이아웃을 가집니다: `(xref, name, invoker, bbox)`, 여기서\"\n\n#: ../../document.rst:967 bc10f1fc12174419970454b5396a5f96\nmsgid \"*:data:`xref`* (*int*) is the XObject's :data:`xref`.\"\nmsgstr \"*:data:`xref`* (*int*)는 XObject의 :data:`xref` 입니다.\"\n\n#: ../../document.rst:968 3458baf801f4472197fe7420ec4729d0\nmsgid \"**name** (*str*) is the symbolic name to reference the XObject.\"\nmsgstr \"**name** (*str*)는 XObject를 참조하는 심볼릭 이름입니다.\"\n\n#: ../../document.rst:969 ff1e7f3a7b5b4e1fba920f8368c15ba7\nmsgid \"\"\n\"**invoker** (*int*) the :data:`xref` of the invoking XObject or zero if \"\n\"the page directly invokes it.\"\nmsgstr \"**invoker** (*int*)는 호출하는 XObject의 :data:`xref` 이거나 페이지가 직접 호출하는 경우 0입니다.\"\n\n#: ../../document.rst:970 9b7ba572cd2b43628b51e0eaac25c5f1\nmsgid \"\"\n\"**bbox** (:ref:`Rect`) the boundary box of the XObject's location on the \"\n\"page **in untransformed coordinates**. To get actual, non-rotated page \"\n\"coordinates, multiply with the page's transformation matrix \"\n\":attr:`Page.transformation_matrix`. *Changed in v.18.11:* the bbox is now\"\n\" formatted as :ref:`Rect`.\"\nmsgstr \"\"\n\"**bbox** (:ref:`Rect`)는 페이지에서 XObject 위치의 경계 상자입니다. **변환되지 않은 좌표** 에 \"\n\"있습니다. 실제, 비회전 페이지 좌표를 얻으려면 페이지의 변환 행렬 :attr:`Page.transformation_matrix` \"\n\"와 곱하세요. *v.18.11에서 변경됨:* bbox는 이제 :ref:`Rect` 로 포맷됩니다.\"\n\n#: ../../document.rst:975 0942f5b9705c43be833e3d4d7c9d04bf\nmsgid \"\"\n\"PDF only: Return a list of all images (directly or indirectly) referenced\"\n\" by the page.\"\nmsgstr \"PDF 전용: 페이지에서 참조하는 모든 이미지(직접 또는 간접) 목록을 반환합니다.\"\n\n#: ../../document.rst:978 c102f9d2a04f4397af702822dd6029d1\nmsgid \"\"\n\"whether to also include the referencer's :data:`xref` (which is zero if \"\n\"this is the page).\"\nmsgstr \"참조자의 :data:`xref` 도 포함할지 여부(페이지인 경우 0).\"\n\n#: ../../document.rst:982 9f36391e139a4365ad37835cb1488399\nmsgid \"\"\n\"a list of images **referenced** by this page. Each item looks like:  \"\n\"`(xref, smask, width, height, bpc, colorspace, alt_colorspace, name, \"\n\"filter, referencer)`    * ``xref`` (*int*) is the image object number   *\"\n\" ``smask`` (*int*) is the object number of its soft-mask image   * \"\n\"``width`` (*int*) is the image width   * ``height`` (*int*) is the image \"\n\"height   * ``bpc`` (*int*) denotes the number of bits per component \"\n\"(normally 8)   * ``colorspace`` (*str*) a string naming the colorspace \"\n\"(like **DeviceRGB**)   * ``alt_colorspace`` (*str*) is any alternate \"\n\"colorspace depending on the value of **colorspace**   * ``name`` (*str*) \"\n\"is the symbolic name by which the image is referenced   * ``filter`` \"\n\"(*str*) is the decode filter of the image (:ref:`AdobeManual`, pp. 22).\"\n\"   * ``referencer`` (*int*) the :data:`xref` of the referencer. Zero if \"\n\"directly referenced by the page. Only present if *full=True*.\"\nmsgstr \"\"\n\n#: ../../document.rst:982 60c9f6c338a9474db9353697d0031f1c\nmsgid \"a list of images **referenced** by this page. Each item looks like:\"\nmsgstr \"이 페이지에서 **참조하는** 이미지 목록. 각 항목은 다음과 같습니다:\"\n\n#: ../../document.rst:984 68fa8977fcbf4250bbc0fa671f7c9a29\nmsgid \"\"\n\"`(xref, smask, width, height, bpc, colorspace, alt_colorspace, name, \"\n\"filter, referencer)`\"\nmsgstr \"\"\n\"`(xref, smask, width, height, bpc, colorspace, alt_colorspace, name, \"\n\"filter, referencer)`\"\n\n#: ../../document.rst:986 32a541d5d2124ba38de883af0a8ca8cc\nmsgid \"``xref`` (*int*) is the image object number\"\nmsgstr \"``xref`` (*int*)는 이미지 객체 번호입니다\"\n\n#: ../../document.rst:987 6e6e3aa40a1e47eeb6f7d90e271b6ca8\nmsgid \"``smask`` (*int*) is the object number of its soft-mask image\"\nmsgstr \"``smask`` (*int*)는 소프트 마스크 이미지의 객체 번호입니다\"\n\n#: ../../document.rst:988 ac66e90cb9514167a7387bd5e1dbc28a\nmsgid \"``width`` (*int*) is the image width\"\nmsgstr \"``width`` (*int*)는 이미지 너비입니다\"\n\n#: ../../document.rst:989 e3be6fc835c74598885e920fbe4118aa\nmsgid \"``height`` (*int*) is the image height\"\nmsgstr \"``height`` (*int*)는 이미지 높이입니다\"\n\n#: ../../document.rst:990 814e68df351b4cb2936c13a6692e1877\nmsgid \"``bpc`` (*int*) denotes the number of bits per component (normally 8)\"\nmsgstr \"``bpc`` (*int*)는 구성 요소당 비트 수를 나타냅니다(일반적으로 8)\"\n\n#: ../../document.rst:991 abfea8ca1da54ae39f9becdba855e107\nmsgid \"``colorspace`` (*str*) a string naming the colorspace (like **DeviceRGB**)\"\nmsgstr \"``colorspace`` (*str*)는 색상 공간을 명명하는 문자열(예: **DeviceRGB**)\"\n\n#: ../../document.rst:992 fcaaa4a4cc5f40cb8fcaa678c8ea8d0d\nmsgid \"\"\n\"``alt_colorspace`` (*str*) is any alternate colorspace depending on the \"\n\"value of **colorspace**\"\nmsgstr \"``alt_colorspace`` (*str*)는 **colorspace** 값에 따라 대체 색상 공간입니다\"\n\n#: ../../document.rst:993 1fa8b147b39f418384f1575f3d529a44\nmsgid \"``name`` (*str*) is the symbolic name by which the image is referenced\"\nmsgstr \"``name`` (*str*)는 이미지가 참조되는 심볼릭 이름입니다\"\n\n#: ../../document.rst:994 025346bb27a940e08fadeea999559e4d\nmsgid \"\"\n\"``filter`` (*str*) is the decode filter of the image (:ref:`AdobeManual`,\"\n\" pp. 22).\"\nmsgstr \"``filter`` (*str*)는 이미지의 디코드 필터입니다(:ref:`AdobeManual`, 22페이지).\"\n\n#: ../../document.rst:995 fd32f1661b8a41308edbf4b15af88e2a\nmsgid \"\"\n\"``referencer`` (*int*) the :data:`xref` of the referencer. Zero if \"\n\"directly referenced by the page. Only present if *full=True*.\"\nmsgstr \"\"\n\"``referencer`` (*int*)는 참조자의 :data:`xref` 입니다. 페이지에서 직접 참조하는 경우 0입니다. \"\n\"*full=True* 인 경우에만 존재합니다.\"\n\n#: ../../document.rst:997 fdb38d2934564ddca22fea4df51c70c8\nmsgid \"\"\n\"In general, this is not the list of images that are **actually \"\n\"displayed**. This method only parses several PDF objects to collect \"\n\"references to embedded images. It does not analyse the page's \"\n\":data:`contents`, where all the actual image display commands are \"\n\"defined. To get this information, please use :meth:`Page.get_image_info`.\"\n\" Also have a look at the discussion in section :ref:`textpagedict`.\"\nmsgstr \"\"\n\"일반적으로 이것은 **실제로 표시되는** 이미지 목록이 아닙니다. 이 메서드는 임베디드된 이미지에 대한 참조를 수집하기 위해 여러 \"\n\"PDF 객체만 파싱합니다. 실제 이미지 표시 명령이 정의된 페이지의 :data:`contents` 를 분석하지 않습니다. 이 정보를\"\n\" 얻으려면 :meth:`Page.get_image_info` 를 사용하세요. 또한 :ref:`textpagedict` 섹션의 논의를\"\n\" 참조하세요.\"\n\n#: ../../document.rst:1002 894bfe7ade6b4fe4a158abbb7e8741d3\nmsgid \"\"\n\"PDF only: Return a list of all fonts (directly or indirectly) referenced \"\n\"by the page object definition.\"\nmsgstr \"PDF 전용: 페이지 객체 정의에서 참조하는 모든 폰트(직접 또는 간접) 목록을 반환합니다.\"\n\n#: ../../document.rst:1005 6a819ec56a614676bc2630447ff70565\nmsgid \"\"\n\"whether to also include the referencer's :data:`xref`. If ``True``, the \"\n\"returned items are one entry longer. Use this option if you need to know,\"\n\" whether the page directly references the font. In this case the last \"\n\"entry is 0. If the font is referenced by an `/XObject` of the page, you \"\n\"will find its :data:`xref` here.\"\nmsgstr \"\"\n\"참조자의 :data:`xref` 도 포함할지 여부. ``True`` 인 경우 반환된 항목이 한 항목 더 깁니다. 페이지가 폰트를 \"\n\"직접 참조하는지 알아야 하는 경우 이 옵션을 사용하세요. 이 경우 마지막 항목은 0입니다. 폰트가 페이지의 `/XObject` 에 \"\n\"의해 참조되는 경우 여기서 :data:`xref` 를 찾을 수 있습니다.\"\n\n#: ../../document.rst:1009 c1b26f5bf24a4321bdc6161a80fcf465\nmsgid \"\"\n\"a list of fonts referenced by the object definition of the page. Each \"\n\"entry looks like:  `(xref, ext, type, basefont, name, encoding, \"\n\"referencer)`      * ``xref`` (*int*) is the font object number (may be \"\n\"zero if the PDF uses one of the builtin fonts directly)     * ``ext`` \"\n\"(*str*) font file extension (e.g. \\\"ttf\\\", see :ref:`FontExtensions`)\"\n\"     * ``type`` (*str*) is the font type (like \\\"Type1\\\" or \\\"TrueType\\\" \"\n\"etc.)     * ``basefont`` (*str*) is the base font name,     * ``name`` \"\n\"(*str*) is the symbolic name, by which the font is referenced     * \"\n\"``encoding`` (*str*) the font's character encoding if different from its \"\n\"built-in encoding (:ref:`AdobeManual`, p. 254):     * ``referencer`` \"\n\"(*int* optional) the :data:`xref` of the referencer. Zero if directly \"\n\"referenced by the page, otherwise the xref of an XObject. Only present if\"\n\" *full=True*.\"\nmsgstr \"\"\n\n#: ../../document.rst:1009 c428c98ac9e3451f81ddf6d0e2a46e83\nmsgid \"\"\n\"a list of fonts referenced by the object definition of the page. Each \"\n\"entry looks like:\"\nmsgstr \"페이지 객체 정의에서 참조하는 폰트 목록. 각 항목은 다음과 같습니다:\"\n\n#: ../../document.rst:1011 e355409fb7d5477f963c7379da3ddf0d\nmsgid \"`(xref, ext, type, basefont, name, encoding, referencer)`\"\nmsgstr \"`(xref, ext, type, basefont, name, encoding, referencer)`\"\n\n#: ../../document.rst:1013 f9b1750789b6485eb7a135397b3bb8df\nmsgid \"\"\n\"``xref`` (*int*) is the font object number (may be zero if the PDF uses \"\n\"one of the builtin fonts directly)\"\nmsgstr \"``xref`` (*int*)는 폰트 객체 번호입니다(PDF가 내장 폰트 중 하나를 직접 사용하는 경우 0일 수 있음)\"\n\n#: ../../document.rst:1014 7ce84ff9f475477da824c34563018a4a\nmsgid \"\"\n\"``ext`` (*str*) font file extension (e.g. \\\"ttf\\\", see \"\n\":ref:`FontExtensions`)\"\nmsgstr \"``ext`` (*str*)는 폰트 파일 확장자입니다(예: \\\"ttf\\\", :ref:`FontExtensions` 참조)\"\n\n#: ../../document.rst:1015 6c03df3e7c174603b04400528d105778\nmsgid \"``type`` (*str*) is the font type (like \\\"Type1\\\" or \\\"TrueType\\\" etc.)\"\nmsgstr \"``type`` (*str*)는 폰트 타입입니다(예: \\\"Type1\\\" 또는 \\\"TrueType\\\" 등)\"\n\n#: ../../document.rst:1016 4ce6e2e5a0c0411faf4f4fc0c1adbc1c\nmsgid \"``basefont`` (*str*) is the base font name,\"\nmsgstr \"``basefont`` (*str*)는 기본 폰트 이름입니다,\"\n\n#: ../../document.rst:1017 0765534374664d2985fb156fe239c1d5\nmsgid \"``name`` (*str*) is the symbolic name, by which the font is referenced\"\nmsgstr \"``name`` (*str*)는 폰트가 참조되는 심볼릭 이름입니다\"\n\n#: ../../document.rst:1018 1d6115a28a0e4ae598e1ea94e3b004d6\nmsgid \"\"\n\"``encoding`` (*str*) the font's character encoding if different from its \"\n\"built-in encoding (:ref:`AdobeManual`, p. 254):\"\nmsgstr \"\"\n\"``encoding`` (*str*)는 내장 인코딩과 다른 경우 폰트의 문자 인코딩입니다(:ref:`AdobeManual`, \"\n\"254페이지):\"\n\n#: ../../document.rst:1019 5ebbba5b9e384f76b51b899b9f2d5b16\nmsgid \"\"\n\"``referencer`` (*int* optional) the :data:`xref` of the referencer. Zero \"\n\"if directly referenced by the page, otherwise the xref of an XObject. \"\n\"Only present if *full=True*.\"\nmsgstr \"\"\n\"``referencer`` (*int* 선택적)는 참조자의 :data:`xref` 입니다. 페이지에서 직접 참조하는 경우 0이고, \"\n\"그렇지 않으면 XObject의 xref입니다. *full=True* 인 경우에만 존재합니다.\"\n\n#: ../../document.rst:1021 3569124c76a74beb8c870ef6fa397799\nmsgid \"Example::\"\nmsgstr \"예제::\"\n\n#: ../../document.rst:1034 e2535fc9161242ce8895729b77ec7732\nmsgid \"\"\n\"This list has no duplicate entries: the combination of :data:`xref`, \"\n\"*name* and *referencer* is unique.\"\nmsgstr \"이 목록에는 중복 항목이 없습니다: :data:`xref`, *name* 및 *referencer* 의 조합이 고유합니다.\"\n\n#: ../../document.rst:1035 34a092cc0bf94ff0967f4b7cf77493af\nmsgid \"\"\n\"In general, this is a true superset of the fonts actually in use by this \"\n\"page. The PDF creator may e.g. have specified some global list, of which \"\n\"each page make only partial use.\"\nmsgstr \"\"\n\"일반적으로 이것은 이 페이지에서 실제로 사용 중인 폰트의 진정한 상위 집합입니다. PDF 작성자는 예를 들어 각 페이지가 \"\n\"부분적으로만 사용하는 전역 목록을 지정했을 수 있습니다.\"\n\n#: ../../document.rst:1036 8aa74a27cd3b495589ae7e3354e6b493\nmsgid \"\"\n\"Be aware that font names returned by some variants of \"\n\":meth:`Page.get_text` (respectively :ref:`TextPage` methods) need not \"\n\"(exactly) equal the base font name shown here. Reasons for any \"\n\"differences include:\"\nmsgstr \"\"\n\":meth:`Page.get_text` (각각 :ref:`TextPage` 메서드)의 일부 변형에서 반환하는 폰트 이름이 여기에 \"\n\"표시된 기본 폰트 이름과 (정확히) 같을 필요는 없습니다. 차이점의 이유는 다음과 같습니다:\"\n\n#: ../../document.rst:1038 8eb2bfec0bfc435cadf15cb6ae9d42eb\nmsgid \"\"\n\"This method always shows any subset prefixes (the pattern ``ABCDEF+``), \"\n\"whereas text extractions do not do this by default.\"\nmsgstr \"이 메서드는 항상 모든 서브셋 접두사(패턴 ``ABCDEF+``)를 표시하지만, 텍스트 추출은 기본적으로 이를 수행하지 않습니다.\"\n\n#: ../../document.rst:1039 8fc75b1d2a5846f4a24d5dbcfe0cba93\nmsgid \"\"\n\"Text extractions use the base library to access the font name, which has \"\n\"a length cap of 31 bytes and generally interrogates the font file binary \"\n\"to access the name. Method ``get_page_fonts()`` however looks at the PDF \"\n\"definition source.\"\nmsgstr \"\"\n\"텍스트 추출은 기본 라이브러리를 사용하여 폰트 이름에 액세스하며, 길이 제한이 31바이트이고 일반적으로 폰트 파일 바이너리를 \"\n\"조회하여 이름에 액세스합니다. 그러나 ``get_page_fonts()`` 메서드는 PDF 정의 소스를 살펴봅니다.\"\n\n#: ../../document.rst:1040 4274d5880663459d8b1903e93b4888ef\nmsgid \"\"\n\"Text extractions work for all supported document types in exactly the \"\n\"same way -- not just for PDFs. Consequently they do not contain PDF-\"\n\"specifics.\"\nmsgstr \"\"\n\"텍스트 추출은 PDF뿐만 아니라 지원되는 모든 문서 타입에 대해 정확히 동일한 방식으로 작동합니다. 결과적으로 PDF 특정 사항을 \"\n\"포함하지 않습니다.\"\n\n#: ../../document.rst:1044 9dc35195295741e183d3ad6e0209ae53\nmsgid \"\"\n\"Extracts the text of a page given its page number *pno* (zero-based). \"\n\"Invokes :meth:`Page.get_text`.\"\nmsgstr \"페이지 번호 *pno* (0 기반)가 주어진 페이지의 텍스트를 추출합니다. :meth:`Page.get_text` 를 호출합니다.\"\n\n#: ../../document.rst:1046 9de1724014c8460babe8e3a752d8b7dc\nmsgid \"page number, 0-based, any value `-∞ < pno < page_count`.\"\nmsgstr \"페이지 번호, 0 기반, `-∞ < pno < page_count` 범위의 모든 값.\"\n\n#: ../../document.rst:1048 e3c19d5b184049b89dd66e661a7b4077\nmsgid \"For other parameter refer to the page method.\"\nmsgstr \"다른 매개변수는 페이지 메서드를 참조하세요.\"\n\n#: ../../document.rst:1060 612a3f5ebc8a4f2494f277cd51d74e1a\nmsgid \"\"\n\"Re-paginate (\\\"reflow\\\") the document based on the given page dimension \"\n\"and fontsize. This only affects some document types like e-books and \"\n\"HTML. Ignored if not supported. Supported documents have ``True`` in \"\n\"property :attr:`is_reflowable`.\"\nmsgstr \"\"\n\"주어진 페이지 크기와 폰트 크기를 기반으로 문서를 다시 페이지화(\\\"리플로우\\\")합니다. 이것은 전자책 및 HTML과 같은 일부 \"\n\"문서 타입에만 영향을 줍니다. 지원되지 않으면 무시됩니다. 지원되는 문서는 속성 :attr:`is_reflowable` 에 \"\n\"``True`` 가 있습니다.\"\n\n#: ../../document.rst:1062 b8a887985240427abf836d07cff96aa4\nmsgid \"desired page size. Must be finite, not empty and start at point (0, 0).\"\nmsgstr \"원하는 페이지 크기. 유한하고 비어 있지 않으며 점 (0, 0)에서 시작해야 합니다.\"\n\n#: ../../document.rst:1063 f2f1d7b57dea48e2bc68fc8ca3110104\nmsgid \"use it together with ``height`` as alternative to ``rect``.\"\nmsgstr \"``rect`` 의 대안으로 ``height`` 와 함께 사용합니다.\"\n\n#: ../../document.rst:1064 d6f5b528d21c4db999bceef858c1caca\nmsgid \"use it together with ``width`` as alternative to ``rect``.\"\nmsgstr \"``rect`` 의 대안으로 ``width`` 와 함께 사용합니다.\"\n\n#: ../../document.rst:1065 1a7ba975d0f4440ebed250c00e4038e7\nmsgid \"the desired default fontsize.\"\nmsgstr \"원하는 기본 폰트 크기.\"\n\n#: ../../document.rst:1069 7abc47fb041a44d69a8d57062d16064a\nmsgid \"\"\n\"PDF only: Keeps only those pages of the document whose numbers occur in \"\n\"the list. Empty sequences or elements outside `range(doc.page_count)` \"\n\"will cause a *ValueError*. For more details see remarks at the bottom or \"\n\"this chapter.\"\nmsgstr \"\"\n\"PDF 전용: 목록에 있는 번호의 페이지만 유지합니다. 빈 시퀀스 또는 `range(doc.page_count)` 범위를 벗어난 \"\n\"요소는 *ValueError* 를 발생시킵니다. 자세한 내용은 이 장 하단의 설명을 참조하세요.\"\n\n#: ../../document.rst:1071 bd92b2ecc213478ca936d170a7f34d7c\nmsgid \"\"\n\"The sequence (see :ref:`SequenceTypes`) of page numbers (zero-based) to \"\n\"be included. Pages not in the sequence will be deleted (from memory) and \"\n\"become unavailable until the document is reopened. **Page numbers can \"\n\"occur multiple times and in any order:** the resulting document will \"\n\"reflect the sequence exactly as specified.\"\nmsgstr \"\"\n\"포함할 페이지 번호(0 기반)의 시퀀스(:ref:`SequenceTypes` 참조). 시퀀스에 없는 페이지는 삭제(메모리에서)되며 \"\n\"문서를 다시 열 때까지 사용할 수 없게 됩니다. **페이지 번호는 여러 번 발생할 수 있으며 어떤 순서로든 가능합니다:** 결과 \"\n\"문서는 지정된 대로 시퀀스를 정확히 반영합니다.\"\n\n#: ../../document.rst:1075 24611bb325054f519a6b9ff6cedb6beb\nmsgid \"\"\n\"Page numbers in the sequence need not be unique nor be in any particular \"\n\"order. This makes the method a versatile utility to e.g. select only the \"\n\"even or the odd pages or meeting some other criteria and so forth.\"\nmsgstr \"\"\n\"시퀀스의 페이지 번호는 고유할 필요도 없고 특정 순서일 필요도 없습니다. 이것은 예를 들어 짝수 페이지만 선택하거나 홀수 페이지만 \"\n\"선택하거나 다른 기준을 충족하는 등 다양한 유틸리티로 메서드를 만듭니다.\"\n\n#: ../../document.rst:1077 636a9e8015aa46309e556db665f2746c\nmsgid \"\"\n\"On a technical level, the method will always create a new \"\n\":data:`pagetree`.\"\nmsgstr \"기술적 수준에서 이 메서드는 항상 새로운 :data:`pagetree` 를 생성합니다.\"\n\n#: ../../document.rst:1079 7e0da8188da041d9812450d9b3cafa12\nmsgid \"\"\n\"When dealing with only a few pages, methods :meth:`copy_page`, \"\n\":meth:`move_page`, :meth:`delete_page` are easier to use. In fact, they \"\n\"are also **much faster** -- by at least one order of magnitude when the \"\n\"document has many pages.\"\nmsgstr \"\"\n\"몇 페이지만 다룰 때는 :meth:`copy_page`, :meth:`move_page`, :meth:`delete_page` \"\n\"메서드가 더 쉽게 사용할 수 있습니다. 실제로 문서에 많은 페이지가 있을 때 최소한 한 자릿수 이상 **훨씬 빠릅니다**.\"\n\n#: ../../document.rst:1084 2f7f7e6048f34cac94145baf612aa008\nmsgid \"\"\n\"PDF only: Sets or updates the metadata of the document as specified in \"\n\"*m*, a Python dictionary.\"\nmsgstr \"PDF 전용: Python 딕셔너리인 *m* 에 지정된 대로 문서의 메타데이터를 설정하거나 업데이트합니다.\"\n\n#: ../../document.rst:1086 fb17b12de6804d10baf0442394ea5395\n#, python-brace-format\nmsgid \"\"\n\"A dictionary with the same keys as *metadata* (see below). All keys are \"\n\"optional. A PDF's format and encryption method cannot be set or changed \"\n\"and will be ignored. If any value should not contain data, do not specify\"\n\" its key or set the value to `None`. If you use *{}* all metadata \"\n\"information will be cleared to the string *\\\"none\\\"*. If you want to \"\n\"selectively change only some values, modify a copy of *doc.metadata* and \"\n\"use it as the argument. Arbitrary unicode values are possible if \"\n\"specified as UTF-8-encoded.\"\nmsgstr \"\"\n\"*metadata* (아래 참조)와 동일한 키를 가진 딕셔너리. 모든 키는 선택적입니다. PDF의 형식과 암호화 방법은 설정하거나 \"\n\"변경할 수 없으며 무시됩니다. 값에 데이터가 포함되지 않아야 하는 경우 해당 키를 지정하지 않거나 값을 `None` 으로 \"\n\"설정하세요. *{}* 를 사용하면 모든 메타데이터 정보가 문자열 *\\\"none\\\"* 으로 지워집니다. 일부 값만 선택적으로 \"\n\"변경하려면 *doc.metadata* 의 복사본을 수정하고 인수로 사용하세요. UTF-8로 인코딩된 것으로 지정하면 임의의 유니코드\"\n\" 값이 가능합니다.\"\n\n#: ../../document.rst:1088 0b2b37c69637443f9e21ca0c677ed090\nmsgid \"\"\n\"*(Changed in v1.18.4)* Empty values or \\\"none\\\" are no longer written, \"\n\"but completely omitted.\"\nmsgstr \"*(v1.18.4에서 변경됨)* 빈 값 또는 \\\"none\\\" 은 더 이상 작성되지 않고 완전히 생략됩니다.\"\n\n#: ../../document.rst:1092 494191b897804e449e9c6b8a1a697bc3\nmsgid \"PDF only: Get the document XML metadata.\"\nmsgstr \"PDF 전용: 문서 XML 메타데이터를 가져옵니다.\"\n\n#: ../../document.rst:1095 ef03232dafa34415ab9abc82a7c2da65\nmsgid \"XML metadata of the document. Empty string if not present or not a PDF.\"\nmsgstr \"문서의 XML 메타데이터. 없거나 PDF가 아닌 경우 빈 문자열.\"\n\n#: ../../document.rst:1099 1fa0bae03c40463993e2665f1a49771e\nmsgid \"PDF only: Sets or updates XML metadata of the document.\"\nmsgstr \"PDF 전용: 문서의 XML 메타데이터를 설정하거나 업데이트합니다.\"\n\n#: ../../document.rst:1101 ad90c4fc4fdb4a058d7e1a286f93e70b\nmsgid \"\"\n\"the new XML metadata. Should be XML syntax, however no checking is done \"\n\"by this method and any string is accepted.\"\nmsgstr \"새 XML 메타데이터. XML 구문이어야 하지만 이 메서드는 검사를 수행하지 않으며 모든 문자열이 허용됩니다.\"\n\n#: ../../document.rst:1106 ../../document.rst:1115 ../../document.rst:1124\n#: ../../document.rst:2062 ../../document.rst:2070 ../../document.rst:2078\n#: ../../document.rst:2086 ../../document.rst:2094\n#: 4adf90aedc904bc18c42a1a4109c7006 6b892ab1bef84c2dac64a07ddc45d085\n#: 9b0e72fc7d0d492d85055abb7b229d4f b5c98f9002e143228355beb92946a982\n#: b8c413017fc540269175c20d423a7951 cdd3c3d34b8b4453a89f97769225a597\n#: d7f11258ac994270b4ff26f7a9aaef0d e3495fa87644414c88ff95b4ccdd5cfb\nmsgid \"New in v1.22.2\"\nmsgstr \"v1.22.2에서 새로 추가됨\"\n\n#: ../../document.rst:1108 58ed819517e3447c8b6fca160b416a15\nmsgid \"PDF only: Set the `/PageLayout`.\"\nmsgstr \"PDF 전용: `/PageLayout` 을 설정합니다.\"\n\n#: ../../document.rst:1110 427d37e940fd4b079ecfc93d2ebc2707\nmsgid \"\"\n\"one of the strings \\\"SinglePage\\\", \\\"OneColumn\\\", \\\"TwoColumnLeft\\\", \"\n\"\\\"TwoColumnRight\\\", \\\"TwoPageLeft\\\", \\\"TwoPageRight\\\". Lower case is \"\n\"supported.\"\nmsgstr \"\"\n\"문자열 \\\"SinglePage\\\", \\\"OneColumn\\\", \\\"TwoColumnLeft\\\", \\\"TwoColumnRight\\\",\"\n\" \\\"TwoPageLeft\\\", \\\"TwoPageRight\\\" 중 하나. 소문자가 지원됩니다.\"\n\n#: ../../document.rst:1117 1a85c014b44e470ba7519e90571a2672\nmsgid \"PDF only: Set the `/PageMode`.\"\nmsgstr \"PDF 전용: `/PageMode` 를 설정합니다.\"\n\n#: ../../document.rst:1119 db113fac96c64e41888cc65fff2476e2\nmsgid \"\"\n\"one of the strings \\\"UseNone\\\", \\\"UseOutlines\\\", \\\"UseThumbs\\\", \"\n\"\\\"FullScreen\\\", \\\"UseOC\\\", \\\"UseAttachments\\\". Lower case is supported.\"\nmsgstr \"\"\n\"문자열 \\\"UseNone\\\", \\\"UseOutlines\\\", \\\"UseThumbs\\\", \\\"FullScreen\\\", \"\n\"\\\"UseOC\\\", \\\"UseAttachments\\\" 중 하나. 소문자가 지원됩니다.\"\n\n#: ../../document.rst:1126 5deb2c951d31411794bc3358fc04faf0\nmsgid \"PDF only: Set the `/MarkInfo` values.\"\nmsgstr \"PDF 전용: `/MarkInfo` 값을 설정합니다.\"\n\n#: ../../document.rst:1128 8120c18587bc46eea1126b758658f3f6\n#, python-brace-format\nmsgid \"\"\n\"a dictionary like this one: `{\\\"Marked\\\": False, \\\"UserProperties\\\": \"\n\"False, \\\"Suspects\\\": False}`. This dictionary contains information about \"\n\"the usage of Tagged PDF conventions. For details please see the `PDF \"\n\"specifications <https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_.\"\nmsgstr \"\"\n\"다음과 같은 딕셔너리: `{\\\"Marked\\\": False, \\\"UserProperties\\\": False, \"\n\"\\\"Suspects\\\": False}`. 이 딕셔너리는 Tagged PDF 규칙 사용에 대한 정보를 포함합니다. 자세한 내용은 \"\n\"`PDF 사양 <https://opensource.adobe.com/dc-acrobat-sdk-\"\n\"docs/standards/pdfstandards/pdf/PDF32000_2008.pdf>`_ 을 참조하세요.\"\n\n#: ../../document.rst:1133 72c170bc3e0f43f9ac97af5f1d62753b\nmsgid \"\"\n\"PDF only: Replaces the **complete current outline** tree (table of \"\n\"contents) with the one provided as the argument. After successful \"\n\"execution, the new outline tree can be accessed as usual via \"\n\":meth:`Document.get_toc` or via :attr:`Document.outline`. Like with other\"\n\" output-oriented methods, changes become permanent only via :meth:`save` \"\n\"(incremental save supported). Internally, this method consists of the \"\n\"following two steps. For a demonstration see example below.\"\nmsgstr \"\"\n\"PDF 전용: **현재 개요** 트리(목차)를 인수로 제공된 것으로 완전히 교체합니다. 성공적으로 실행한 후 새 개요 트리는 \"\n\":meth:`Document.get_toc` 또는 :attr:`Document.outline` 을 통해 평소와 같이 액세스할 수 \"\n\"있습니다. 다른 출력 지향 메서드와 마찬가지로 변경 사항은 :meth:`save` 를 통해서만 영구적으로 적용됩니다(증분 저장 \"\n\"지원). 내부적으로 이 메서드는 다음 두 단계로 구성됩니다. 데모는 아래 예제를 참조하세요.\"\n\n#: ../../document.rst:1135 98622e412665444fab7ff8c2eda90595\nmsgid \"Step 1 deletes all existing bookmarks.\"\nmsgstr \"1단계는 기존 북마크를 모두 삭제합니다.\"\n\n#: ../../document.rst:1137 6eedcc83ffe74d67bf4a3b29582462f3\nmsgid \"Step 2 creates a new TOC from the entries contained in *toc*.\"\nmsgstr \"2단계는 *toc* 에 포함된 항목에서 새 TOC를 생성합니다.\"\n\n#: ../../document.rst:1139 cadc625db49a4809b4d70bf9b2a3933b\nmsgid \"\"\n\"A list / tuple with **all bookmark entries** that should form the new \"\n\"table of contents. Output variants of :meth:`get_toc` are acceptable. To \"\n\"completely remove the table of contents specify an empty sequence or \"\n\"None. Each item must be a list with the following format.  * [lvl, title,\"\n\" page [, dest]] where    - **lvl** is the hierarchy level (int > 0) of \"\n\"the item, which **must be 1** for the first item and at most 1 larger \"\n\"than the previous one.    - **title** (str) is the title to be displayed.\"\n\" It is assumed to be UTF-8-encoded (relevant for multibyte code points \"\n\"only).    - **page** (int) is the target page number **(attention: \"\n\"1-based)**. Must be in valid range if positive. Set it to -1 if there is \"\n\"no target, or the target is external.    - **dest** (optional) is a \"\n\"dictionary or a number. If a number, it will be interpreted as the \"\n\"desired height (in points) this entry should point to on the page. Use a \"\n\"dictionary (like the one given as output by `get_toc(False)`) for a \"\n\"detailed control of the bookmark's properties, see \"\n\":meth:`Document.get_toc` for a description.\"\nmsgstr \"\"\n\n#: ../../document.rst:1141 cdb59ec76f7847e3a0cf3a5b77792ed4\nmsgid \"\"\n\"A list / tuple with **all bookmark entries** that should form the new \"\n\"table of contents. Output variants of :meth:`get_toc` are acceptable. To \"\n\"completely remove the table of contents specify an empty sequence or \"\n\"None. Each item must be a list with the following format.\"\nmsgstr \"\"\n\"새 목차를 구성할 **모든 북마크 항목** 이 포함된 리스트/튜플. :meth:`get_toc` 의 출력 변형이 허용됩니다. 목차를 \"\n\"완전히 제거하려면 빈 시퀀스 또는 None을 지정하세요. 각 항목은 다음 형식의 리스트여야 합니다.\"\n\n#: ../../document.rst:1143 626c048ee62e42a0bef1b3584f2589f5\nmsgid \"[lvl, title, page [, dest]] where\"\nmsgstr \"[lvl, title, page [, dest]] 여기서\"\n\n#: ../../document.rst:1145 8bb47b49efa14fc99859d1452d07bf69\nmsgid \"\"\n\"**lvl** is the hierarchy level (int > 0) of the item, which **must be 1**\"\n\" for the first item and at most 1 larger than the previous one.\"\nmsgstr \"\"\n\"**lvl** 은 항목의 계층 수준(int > 0)이며, 첫 번째 항목의 경우 **반드시 1** 이어야 하고 이전 항목보다 최대 \"\n\"1만큼 클 수 있습니다.\"\n\n#: ../../document.rst:1147 f1f7cd98aae94a2e8c0a85f5fbe9d7d6\nmsgid \"\"\n\"**title** (str) is the title to be displayed. It is assumed to be \"\n\"UTF-8-encoded (relevant for multibyte code points only).\"\nmsgstr \"**title** (str)는 표시할 제목입니다. UTF-8로 인코딩된 것으로 가정됩니다(멀티바이트 코드 포인트에만 해당).\"\n\n#: ../../document.rst:1149 092134e22d9345ce9a23c842f343e4ba\nmsgid \"\"\n\"**page** (int) is the target page number **(attention: 1-based)**. Must \"\n\"be in valid range if positive. Set it to -1 if there is no target, or the\"\n\" target is external.\"\nmsgstr \"\"\n\"**page** (int)는 대상 페이지 번호입니다 **(주의: 1 기반)**. 양수인 경우 유효한 범위에 있어야 합니다. 대상이 \"\n\"없거나 대상이 외부인 경우 -1로 설정하세요.\"\n\n#: ../../document.rst:1151 b99ea47aafda42d489c734010b1649d5\nmsgid \"\"\n\"**dest** (optional) is a dictionary or a number. If a number, it will be \"\n\"interpreted as the desired height (in points) this entry should point to \"\n\"on the page. Use a dictionary (like the one given as output by \"\n\"`get_toc(False)`) for a detailed control of the bookmark's properties, \"\n\"see :meth:`Document.get_toc` for a description.\"\nmsgstr \"\"\n\"**dest** (선택적)는 딕셔너리 또는 숫자입니다. 숫자인 경우 이 항목이 페이지에서 가리켜야 하는 원하는 높이(포인트)로 \"\n\"해석됩니다. 북마크 속성을 세부적으로 제어하려면 딕셔너리를 사용하세요(`get_toc(False)` 의 출력과 같은 형식). 설명은\"\n\" :meth:`Document.get_toc` 를 참조하세요.\"\n\n#: ../../document.rst:1153 140d7baa991d45d0af1070c30abc800a\nmsgid \"\"\n\"*(new in v1.16.9)* controls the hierarchy level beyond which outline \"\n\"entries should initially show up collapsed. The default 1 will hence only\"\n\" display level 1, higher levels must be unfolded using the PDF viewer. To\"\n\" unfold everything, specify either a large integer, 0 or None.\"\nmsgstr \"\"\n\"*(v1.16.9에서 새로 추가됨)* 개요 항목이 처음에 접힌 상태로 표시되어야 하는 계층 수준을 제어합니다. 기본값 1은 따라서 \"\n\"레벨 1만 표시하며, 더 높은 레벨은 PDF 뷰어를 사용하여 펼쳐야 합니다. 모든 것을 펼치려면 큰 정수, 0 또는 None을 \"\n\"지정하세요.\"\n\n#: ../../document.rst:1156 94fd3cfe66044726bbc940305f4fedfd\nmsgid \"the number of inserted, resp. deleted items.\"\nmsgstr \"삽입된 항목 수, 각각 삭제된 항목 수.\"\n\n#: ../../document.rst:1158 61bddd5d79224a969e31759461728b07\nmsgid \"\"\n\"Changed in v1.23.8: Destination 'to' coordinates should now be in the \"\n\"same coordinate system as those returned by `get_toc()` (internally they \"\n\"are now transformed with `page.cropbox` and `page.rotation_matrix`). So \"\n\"for example `set_toc(get_toc())` now gives unchanged destination 'to' \"\n\"coordinates.\"\nmsgstr \"\"\n\"v1.23.8에서 변경됨: 대상 'to' 좌표는 이제 `get_toc()` 에서 반환하는 것과 동일한 좌표계에 있어야 \"\n\"합니다(내부적으로 `page.cropbox` 와 `page.rotation_matrix` 로 변환됨). 예를 들어 \"\n\"`set_toc(get_toc())` 는 이제 변경되지 않은 대상 'to' 좌표를 제공합니다.\"\n\n#: ../../document.rst:1168 d2b2c6ea9a0a4e158130c63e477b1548\nmsgid \"\"\n\"PDF only: Return the :data:`xref` of the outline item. This is mainly \"\n\"used for internal purposes.\"\nmsgstr \"PDF 전용: 개요 항목의 :data:`xref` 를 반환합니다. 주로 내부 목적으로 사용됩니다.\"\n\n#: ../../document.rst:1170 41a5cf21e50745f3aba9288a72873f10\nmsgid \"index of the item in list :meth:`Document.get_toc`.\"\nmsgstr \":meth:`Document.get_toc` 리스트의 항목 인덱스.\"\n\n#: ../../document.rst:1172 849479f903f34747a2b708a93d748011\nmsgid \":data:`xref`.\"\nmsgstr \":data:`xref`.\"\n\n#: ../../document.rst:1177 4dd33d7619fc44ecbbe5d72e91d84012\nmsgid \"\"\n\"Changed in v1.18.14: no longer remove the item's text, but show it \"\n\"grayed-out.\"\nmsgstr \"v1.18.14에서 변경됨: 항목의 텍스트를 더 이상 제거하지 않고 회색으로 표시합니다.\"\n\n#: ../../document.rst:1179 f49f270454b7447389c99fbc3c081369\nmsgid \"\"\n\"PDF only: Remove this TOC item. This is a high-speed method, which \"\n\"**disables** the respective item, but leaves the overall TOC structure \"\n\"intact. Physically, the item still exists in the TOC tree, but is shown \"\n\"grayed-out and will no longer point to any destination.\"\nmsgstr \"\"\n\"PDF 전용: 이 TOC 항목을 제거합니다. 이것은 해당 항목을 **비활성화** 하지만 전체 TOC 구조는 그대로 유지하는 고속 \"\n\"메서드입니다. 물리적으로 항목은 여전히 TOC 트리에 존재하지만 회색으로 표시되며 더 이상 어떤 대상도 가리키지 않습니다.\"\n\n#: ../../document.rst:1181 b5b90e9a53374eb4a723ed21fc6f0ac1\nmsgid \"\"\n\"This also implies that you can reassign the item to a new destination \"\n\"using :meth:`Document.set_toc_item`, when required.\"\nmsgstr \"이것은 필요할 때 :meth:`Document.set_toc_item` 을 사용하여 항목을 새 대상에 재할당할 수 있음을 의미합니다.\"\n\n#: ../../document.rst:1183 6d53ee1db74b4a2caa95023d65e00b0e\nmsgid \"the index of the item in list :meth:`Document.get_toc`.\"\nmsgstr \":meth:`Document.get_toc` 리스트의 항목 인덱스.\"\n\n#: ../../document.rst:1189 20ab18dcdb0c4c36a8f7146969f7343a\nmsgid \"Changed in v1.18.6\"\nmsgstr \"v1.18.6에서 변경됨\"\n\n#: ../../document.rst:1191 bea76c094b844e56a30d16649f55b442\nmsgid \"\"\n\"PDF only: Changes the TOC item identified by its index. Change the item \"\n\"**title**, **destination**, **appearance** (color, bold, italic) or \"\n\"collapsing sub-items -- or to remove the item altogether.\"\nmsgstr \"\"\n\"PDF 전용: 인덱스로 식별된 TOC 항목을 변경합니다. 항목의 **제목**, **대상**, **모양** (색상, 굵게, 기울임꼴)\"\n\" 또는 하위 항목 접기 -- 또는 항목을 완전히 제거합니다.\"\n\n#: ../../document.rst:1193 a1abb954511f4decb89272ea3006c663\nmsgid \"\"\n\"Use this method if you need specific changes for selected entries only \"\n\"and want to avoid replacing the complete TOC. This is beneficial \"\n\"especially when dealing with large table of contents.\"\nmsgstr \"\"\n\"선택한 항목에 대해서만 특정 변경이 필요하고 전체 TOC를 교체하는 것을 피하려는 경우 이 메서드를 사용하세요. 특히 큰 목차를 \"\n\"다룰 때 유용합니다.\"\n\n#: ../../document.rst:1195 bf1e8e83220f4e99987d442177c40897\nmsgid \"the index of the entry in the list created by :meth:`Document.get_toc`.\"\nmsgstr \":meth:`Document.get_toc` 로 생성된 리스트의 항목 인덱스.\"\n\n#: ../../document.rst:1196 f97b0254a2a845b7962cca10c78ef12c\nmsgid \"\"\n\"the new destination. A dictionary like the last entry of an item in \"\n\"`doc.get_toc(False)`. Using this as a template is recommended. When \"\n\"given, **all other parameters are ignored** -- except title.\"\nmsgstr \"\"\n\"새 대상. `doc.get_toc(False)` 의 항목 마지막 항목과 같은 딕셔너리. 이것을 템플릿으로 사용하는 것이 권장됩니다.\"\n\" 제공되면 **다른 모든 매개변수는 무시됩니다** -- 제목 제외.\"\n\n#: ../../document.rst:1197 c97e2f7c844f4e64b68ed04c274e7af0\nmsgid \"\"\n\"the link kind, see :ref:`linkDest Kinds`. If :data:`LINK_NONE`, then all \"\n\"remaining parameter will be ignored, and the TOC item will be removed -- \"\n\"same as :meth:`Document.del_toc_item`. If None, then only the title is \"\n\"modified and the remaining parameters are ignored. All other values will \"\n\"lead to making a new destination dictionary using the subsequent \"\n\"arguments.\"\nmsgstr \"\"\n\"링크 종류, :ref:`linkDest Kinds` 참조. :data:`LINK_NONE` 인 경우 나머지 모든 매개변수가 무시되고\"\n\" TOC 항목이 제거됩니다 -- :meth:`Document.del_toc_item` 과 동일. None인 경우 제목만 수정되고 \"\n\"나머지 매개변수는 무시됩니다. 다른 모든 값은 후속 인수를 사용하여 새 대상 딕셔너리를 만듭니다.\"\n\n#: ../../document.rst:1198 d3439567ac7042319ae8dd763512500a\nmsgid \"\"\n\"the 1-based page number, i.e. a value 1 <= pno <= doc.page_count. \"\n\"Required for LINK_GOTO.\"\nmsgstr \"1 기반 페이지 번호, 즉 값 1 <= pno <= doc.page_count. LINK_GOTO에 필요합니다.\"\n\n#: ../../document.rst:1199 5a95d66b5b9a4ae891896126c4591958\nmsgid \"the URL text. Required for LINK_URI.\"\nmsgstr \"URL 텍스트. LINK_URI에 필요합니다.\"\n\n#: ../../document.rst:1200 bd37daff52754143bd1d58d51f64fa0f\nmsgid \"the desired new title. None if no change.\"\nmsgstr \"원하는 새 제목. 변경 없으면 None.\"\n\n#: ../../document.rst:1201 9fb31ce97f374940aa9639c9f54f25a9\nmsgid \"\"\n\"(optional) points to a coordinate on the target page. Relevant for \"\n\"LINK_GOTO. If omitted, a point near the page's top is chosen.\"\nmsgstr \"(선택적) 대상 페이지의 좌표를 가리킵니다. LINK_GOTO와 관련이 있습니다. 생략하면 페이지 상단 근처의 점이 선택됩니다.\"\n\n#: ../../document.rst:1202 5f66a09773424b2dbe81dd4a8fc3c30a\nmsgid \"required for LINK_GOTOR and LINK_LAUNCH.\"\nmsgstr \"LINK_GOTOR 및 LINK_LAUNCH에 필요합니다.\"\n\n#: ../../document.rst:1203 b487f04964a9453baf8d5d209996a7fa\nmsgid \"use this zoom factor when showing the target page.\"\nmsgstr \"대상 페이지를 표시할 때 이 확대/축소 비율을 사용합니다.\"\n\n#: ../../document.rst:1205 462fa8fbb28645c3918464eef6bf19af\nmsgid \"**Example use:** Change the TOC of the SWIG manual to achieve this:\"\nmsgstr \"**사용 예:** SWIG 매뉴얼의 TOC를 변경하여 다음을 달성합니다:\"\n\n#: ../../document.rst:1207 266f767d832b44239b654042eb109117\nmsgid \"\"\n\"Collapse everything below top level and show the chapter on Python \"\n\"support in red, bold and italic::\"\nmsgstr \"최상위 레벨 아래의 모든 항목을 접고 Python 지원 장을 빨간색, 굵게, 기울임꼴로 표시합니다::\"\n\n#: ../../document.rst:1224 dbbb176419574079b65c7d553aca8513\nmsgid \"\"\n\"In the previous example, we have changed only 42 of the 1240 TOC items of\"\n\" the file.\"\nmsgstr \"이전 예제에서 파일의 1240개 TOC 항목 중 42개만 변경했습니다.\"\n\n#: ../../document.rst:1228 9c0eac3df7ec40818cf474ec6d1b90e0\nmsgid \"\"\n\"PDF only: Convert annotations and / or widgets to become permanent parts \"\n\"of the pages. The PDF **will be changed** by this method. If `widgets` is\"\n\" `True`, the document will also no longer be a \\\"Form PDF\\\".\"\nmsgstr \"\"\n\"PDF 전용: 주석 및/또는 위젯을 페이지의 영구 부분으로 변환합니다. 이 메서드로 PDF가 **변경됩니다**. `widgets` \"\n\"가 `True` 인 경우 문서는 더 이상 \\\"Form PDF\\\"가 아닙니다.\"\n\n#: ../../document.rst:1230 bf59f3a2a5f7468f8a28de2522317838\nmsgid \"\"\n\"All pages will look the same, but will no longer have annotations, \"\n\"respectively fields. The visible parts will be converted to standard \"\n\"text, vector graphics or images as required.\"\nmsgstr \"\"\n\"모든 페이지는 동일하게 보이지만 더 이상 주석 또는 필드를 갖지 않습니다. 표시되는 부분은 필요에 따라 표준 텍스트, 벡터 그래픽 \"\n\"또는 이미지로 변환됩니다.\"\n\n#: ../../document.rst:1232 61e967b2174c4737b81e4fbc697f2643\nmsgid \"\"\n\"The method may thus be a viable **alternative for PDF-to-PDF \"\n\"conversions** using :meth:`Document.convert_to_pdf`.\"\nmsgstr \"\"\n\"따라서 이 메서드는 :meth:`Document.convert_to_pdf` 를 사용한 **PDF-to-PDF 변환의 대안** 이 \"\n\"될 수 있습니다.\"\n\n#: ../../document.rst:1234 19d028b19c044458b9d15ce7b68d5d72\nmsgid \"\"\n\"Please consider that annotations are complex objects and may consist of \"\n\"more data \\\"underneath\\\" their visual appearance. Examples are \\\"Text\\\" \"\n\"and \\\"FileAttachment\\\" annotations. When \\\"baking in\\\" annotations / \"\n\"widgets with this method, all this underlying information (attached \"\n\"files, comments, associated PopUp annotations, etc.) will be lost and be \"\n\"removed on next garbage collection.\"\nmsgstr \"\"\n\"주석은 복잡한 객체이며 시각적 모양 \\\"아래\\\"에 더 많은 데이터가 포함될 수 있습니다. 예는 \\\"Text\\\" 및 \"\n\"\\\"FileAttachment\\\" 주석입니다. 이 메서드로 주석/위젯을 \\\"구워 넣을\\\" 때 모든 기본 정보(첨부 파일, 주석, \"\n\"관련 PopUp 주석 등)가 손실되고 다음 가비지 수집 시 제거됩니다.\"\n\n#: ../../document.rst:1236 0f6435c640bd4abd83e3ab107d798d3c\nmsgid \"\"\n\"Use this feature for instance for :meth:`Page.show_pdf_page` (which \"\n\"supports neither annotations nor widgets) when the source pages should \"\n\"look exactly the same in the target.\"\nmsgstr \"\"\n\"소스 페이지가 대상에서 정확히 동일하게 보여야 할 때 예를 들어 :meth:`Page.show_pdf_page` (주석도 위젯도 \"\n\"지원하지 않음)에 이 기능을 사용하세요.\"\n\n#: ../../document.rst:1239 96ef3fe55fbe415fb7e1ba9a12bf11bf\nmsgid \"convert annotations.\"\nmsgstr \"주석을 변환합니다.\"\n\n#: ../../document.rst:1240 7f5d0a321b3940488ca3fb6c8f2943e9\nmsgid \"\"\n\"convert fields / widgets. After execution, the document will no longer be\"\n\" a \\\"Form PDF\\\".\"\nmsgstr \"필드/위젯을 변환합니다. 실행 후 문서는 더 이상 \\\"Form PDF\\\"가 아닙니다.\"\n\n#: ../../document.rst:1245 60d5dfcfd9a74425a9d56d6dbf2c1d2c\nmsgid \"New in v1.16.0\"\nmsgstr \"v1.16.0에서 새로 추가됨\"\n\n#: ../../document.rst:1247 bb7bb5385d2e417bbdfd1f53e52a28d9\nmsgid \"\"\n\"Check whether the document can be saved incrementally. Use it to choose \"\n\"the right option without encountering exceptions.\"\nmsgstr \"문서를 증분 저장할 수 있는지 확인합니다. 예외 없이 올바른 옵션을 선택하는 데 사용하세요.\"\n\n#: ../../document.rst:1251 bc2493d433b7493eacdc1dc5afe9f7a5\nmsgid \"New in v1.16.14\"\nmsgstr \"v1.16.14에서 새로 추가됨\"\n\n#: ../../document.rst:1253 714cf5c63fe148968601af72485159a0\nmsgid \"\"\n\"PDF only: Remove potentially sensitive data from the PDF. This function \"\n\"is inspired by the similar \\\"Sanitize\\\" function in Adobe Acrobat \"\n\"products. The process is configurable by a number of options.\"\nmsgstr \"\"\n\"PDF 전용: PDF에서 잠재적으로 민감한 데이터를 제거합니다. 이 함수는 Adobe Acrobat 제품의 유사한 \"\n\"\\\"Sanitize\\\" 함수에서 영감을 받았습니다. 프로세스는 여러 옵션으로 구성할 수 있습니다.\"\n\n#: ../../document.rst:1255 d59772e9be994beb89b82b6a50277c35\nmsgid \"Search for 'FileAttachment' annotations and remove the file content.\"\nmsgstr \"'FileAttachment' 주석을 검색하고 파일 콘텐츠를 제거합니다.\"\n\n#: ../../document.rst:1256 b0de421c4e9f4532b9e1e53b36cffbb2\nmsgid \"\"\n\"Remove any comments from page painting sources. If this option is set to \"\n\"``False``, then this is also done for *hidden_text* and *redactions*.\"\nmsgstr \"\"\n\"페이지 그리기 소스에서 모든 주석을 제거합니다. 이 옵션이 ``False`` 로 설정되면 *hidden_text* 및 \"\n\"*redactions* 에 대해서도 수행됩니다.\"\n\n#: ../../document.rst:1257 9dc57a2c711d40f3a2f979b1f9b73c45\nmsgid \"Remove embedded files.\"\nmsgstr \"임베디드 파일을 제거합니다.\"\n\n#: ../../document.rst:1258 e259fd77d3b44e3aaf2df616427e9cff\nmsgid \"Remove OCRed text and invisible text [#f7]_.\"\nmsgstr \"OCR된 텍스트와 보이지 않는 텍스트를 제거합니다 [#f7]_.\"\n\n#: ../../document.rst:1259 3050a96f9ed648baa8cc07b5bf30aef0\nmsgid \"Remove JavaScript sources.\"\nmsgstr \"JavaScript 소스를 제거합니다.\"\n\n#: ../../document.rst:1260 242893b3617448a98703d146fc18d440\nmsgid \"Remove PDF standard metadata.\"\nmsgstr \"PDF 표준 메타데이터를 제거합니다.\"\n\n#: ../../document.rst:1261 390e373af5eb4c48829f4f6b53cddc73\nmsgid \"Apply redaction annotations.\"\nmsgstr \"수정 주석을 적용합니다.\"\n\n#: ../../document.rst:1262 4cd57dcd3a694fee956d822ac6b5a852\nmsgid \"\"\n\"how to handle images if applying redactions. One of 0 (ignore), 1 (blank \"\n\"out overlaps) or 2 (remove).\"\nmsgstr \"수정을 적용할 때 이미지를 처리하는 방법. 0(무시), 1(겹침을 비움) 또는 2(제거) 중 하나.\"\n\n#: ../../document.rst:1263 00ef5f77074d44bb82fcda8759ce527b\nmsgid \"Remove all links.\"\nmsgstr \"모든 링크를 제거합니다.\"\n\n#: ../../document.rst:1264 526404ef66ce4cb6862edcb9f410cf85\nmsgid \"Reset all form fields to their defaults.\"\nmsgstr \"모든 양식 필드를 기본값으로 재설정합니다.\"\n\n#: ../../document.rst:1265 2a989b196378452b91c99bb4b36f7458\nmsgid \"Remove all responses from all annotations.\"\nmsgstr \"모든 주석에서 모든 응답을 제거합니다.\"\n\n#: ../../document.rst:1266 1f49855b78e9418d850fe0705af4921a\nmsgid \"Remove thumbnail images from pages.\"\nmsgstr \"페이지에서 썸네일 이미지를 제거합니다.\"\n\n#: ../../document.rst:1267 73db39387008420ebb8ec2ac21beb2bf\nmsgid \"Remove XML metadata.\"\nmsgstr \"XML 메타데이터를 제거합니다.\"\n\n#: ../../document.rst:1272 ../../document.rst:1349\n#: 04276335faaa444494e1bdf6a447a071 40680bdd5180459eb399cc80b91c47c1\nmsgid \"Changed in v1.18.7\"\nmsgstr \"v1.18.7에서 변경됨\"\n\n#: ../../document.rst:1273 ../../document.rst:1350\n#: 7d3e460da3e047e891e251c4b7cfa065 cbd0cf9d3ec94dd9a661a91259f0312b\nmsgid \"Changed in v1.19.0\"\nmsgstr \"v1.19.0에서 변경됨\"\n\n#: ../../document.rst:1274 ../../document.rst:1351\n#: 59e6623e271c4a75bf5f34ff948d1f81 cd2af959721d45009d28f6cd97a4f518\nmsgid \"Changed in v1.24.1\"\nmsgstr \"v1.24.1에서 변경됨\"\n\n#: ../../document.rst:1276 a358c08f51ec4d6a97cc369b80908ba3\nmsgid \"PDF only: Saves the document in its **current state**.\"\nmsgstr \"PDF 전용: 문서를 **현재 상태** 로 저장합니다.\"\n\n#: ../../document.rst:1278 8b66e825ec804b7a91f56a4510709e2a\nmsgid \"\"\n\"The file path, `pathlib.Path` or file object to save to. A file object \"\n\"must have been created before via `open(...)` or `io.BytesIO()`. Choosing\"\n\" `io.BytesIO()` is similar to :meth:`Document.tobytes` below, which \"\n\"equals the `getvalue()` output of an internally created `io.BytesIO()`.\"\nmsgstr \"\"\n\"저장할 파일 경로, `pathlib.Path` 또는 파일 객체. 파일 객체는 `open(...)` 또는 `io.BytesIO()` \"\n\"를 통해 미리 생성되어야 합니다. `io.BytesIO()` 를 선택하는 것은 아래 :meth:`Document.tobytes` 와\"\n\" 유사하며, 내부적으로 생성된 `io.BytesIO()` 의 `getvalue()` 출력과 같습니다.\"\n\n#: ../../document.rst:1280 bec970d0303f4a7caee288540e178d40\nmsgid \"\"\n\"Do garbage collection. Positive values exclude \\\"incremental\\\".  * 0 = \"\n\"none * 1 = remove unused (unreferenced) objects. * 2 = in addition to 1, \"\n\"compact the :data:`xref` table. * 3 = in addition to 2, merge duplicate \"\n\"objects. * 4 = in addition to 3, check :data:`stream` objects for \"\n\"duplication. This may be slow because such data are typically large.\"\nmsgstr \"\"\n\n#: ../../document.rst:1280 a27314cc7f4b477ca9f090f899cff41b\nmsgid \"Do garbage collection. Positive values exclude \\\"incremental\\\".\"\nmsgstr \"가비지 수집을 수행합니다. 양수 값은 \\\"incremental\\\"을 제외합니다.\"\n\n#: ../../document.rst:1282 ../../document.rst:1300\n#: 04eb5f84c28048669c20567fe0e48169 d200a55bded140df93fc1fcc51582d76\nmsgid \"0 = none\"\nmsgstr \"0 = 없음\"\n\n#: ../../document.rst:1283 8be03fa92a78481192962b895c92585d\nmsgid \"1 = remove unused (unreferenced) objects.\"\nmsgstr \"1 = 사용되지 않는(참조되지 않은) 객체를 제거합니다.\"\n\n#: ../../document.rst:1284 6bb26ad0c00642a2a6e3e6ecc079e041\nmsgid \"2 = in addition to 1, compact the :data:`xref` table.\"\nmsgstr \"2 = 1에 추가하여 :data:`xref` 테이블을 압축합니다.\"\n\n#: ../../document.rst:1285 aa51c2a5b852418985e4421a102ccca8\nmsgid \"3 = in addition to 2, merge duplicate objects.\"\nmsgstr \"3 = 2에 추가하여 중복 객체를 병합합니다.\"\n\n#: ../../document.rst:1286 dac3401261ab4ae5aaecdecc10a1d24b\nmsgid \"\"\n\"4 = in addition to 3, check :data:`stream` objects for duplication. This \"\n\"may be slow because such data are typically large.\"\nmsgstr \"4 = 3에 추가하여 :data:`stream` 객체의 중복을 확인합니다. 이러한 데이터는 일반적으로 크기 때문에 느릴 수 있습니다.\"\n\n#: ../../document.rst:1288 97a5b429f80a42baaa67acfaafa3ccd8\nmsgid \"\"\n\"Clean and sanitize content streams [#f1]_. Corresponds to \\\"mutool clean \"\n\"-sc\\\".\"\nmsgstr \"콘텐츠 스트림을 정리하고 정화합니다 [#f1]_. \\\"mutool clean -sc\\\" 에 해당합니다.\"\n\n#: ../../document.rst:1290 25320d9b0afa46a7a2263c5a006d74ce\nmsgid \"Deflate (compress) uncompressed streams.\"\nmsgstr \"압축되지 않은 스트림을 Deflate(압축)합니다.\"\n\n#: ../../document.rst:1291 17c88bde58484f2191ddb9cdc5c7908f\nmsgid \"*(new in v1.18.3)* Deflate (compress) uncompressed image streams [#f4]_.\"\nmsgstr \"*(v1.18.3에서 새로 추가됨)* 압축되지 않은 이미지 스트림을 Deflate(압축)합니다 [#f4]_.\"\n\n#: ../../document.rst:1292 f16362460abf4cb5b19b3a97d5dbb203\nmsgid \"\"\n\"*(new in v1.18.3)* Deflate (compress) uncompressed fontfile streams \"\n\"[#f4]_.\"\nmsgstr \"*(v1.18.3에서 새로 추가됨)* 압축되지 않은 폰트 파일 스트림을 Deflate(압축)합니다 [#f4]_.\"\n\n#: ../../document.rst:1294 2d48d3b453ec453e9a06ecd5a76223e0\nmsgid \"\"\n\"Only save changes to the PDF. Excludes \\\"garbage\\\" and \\\"linear\\\". Can \"\n\"only be used if *outfile* is a string or a `pathlib.Path` and equal to \"\n\":attr:`Document.name`. Cannot be used for files that are decrypted or \"\n\"repaired and also in some other cases. To be sure, check \"\n\":meth:`Document.can_save_incrementally`. If this is false, saving to a \"\n\"new file is required.\"\nmsgstr \"\"\n\"PDF에 변경 사항만 저장합니다. \\\"garbage\\\" 및 \\\"linear\\\"를 제외합니다. *outfile* 이 문자열이거나 \"\n\"`pathlib.Path` 이고 :attr:`Document.name` 과 같을 때만 사용할 수 있습니다. 복호화되거나 복구된 파일\"\n\" 및 일부 다른 경우에는 사용할 수 없습니다. 확인하려면 :meth:`Document.can_save_incrementally` 를\"\n\" 확인하세요. 이것이 false이면 새 파일로 저장해야 합니다.\"\n\n#: ../../document.rst:1296 de1d75d087da4904a87ff4e42c567da2\nmsgid \"convert binary data to ASCII.\"\nmsgstr \"바이너리 데이터를 ASCII로 변환합니다.\"\n\n#: ../../document.rst:1298 73573581067046a2b1d73dadb5784bef\nmsgid \"\"\n\"Decompress objects. Generates versions that can be better read by some \"\n\"other programs and will lead to larger files.  * 0 = none * 1 = images * \"\n\"2 = fonts * 255 = all\"\nmsgstr \"\"\n\n#: ../../document.rst:1298 24b492fbe4214257aab8402badd85f49\nmsgid \"\"\n\"Decompress objects. Generates versions that can be better read by some \"\n\"other programs and will lead to larger files.\"\nmsgstr \"객체를 압축 해제합니다. 일부 다른 프로그램에서 더 잘 읽을 수 있는 버전을 생성하며 더 큰 파일로 이어집니다.\"\n\n#: ../../document.rst:1301 9bb1ccd1f87d4efc973cda0d5dad59b5\nmsgid \"1 = images\"\nmsgstr \"1 = 이미지\"\n\n#: ../../document.rst:1302 f632c4e866254ac4a1f52bdb594e61f0\nmsgid \"2 = fonts\"\nmsgstr \"2 = 폰트\"\n\n#: ../../document.rst:1303 8c01aec5e66e45e586fe77a7d35fabf8\nmsgid \"255 = all\"\nmsgstr \"255 = 모두\"\n\n#: ../../document.rst:1305 cd58f0f1000c408a81e9a604b071d409\nmsgid \"\"\n\"Save a linearised version of the document. This option creates a file \"\n\"format for improved performance for Internet access. Excludes \"\n\"\\\"incremental\\\" and \\\"use_objstms\\\".\"\nmsgstr \"\"\n\"문서의 선형화된 버전을 저장합니다. 이 옵션은 인터넷 액세스를 위한 향상된 성능을 위한 파일 형식을 생성합니다. \"\n\"\\\"incremental\\\" 및 \\\"use_objstms\\\"를 제외합니다.\"\n\n#: ../../document.rst:1307 5e331580fd9448fdbfa0698c6df5fe0a\nmsgid \"\"\n\"Prettify the document source for better readability. PDF objects will be \"\n\"reformatted to look like the default output of \"\n\":meth:`Document.xref_object`.\"\nmsgstr \"\"\n\"가독성을 높이기 위해 문서 소스를 예쁘게 만듭니다. PDF 객체는 :meth:`Document.xref_object` 의 기본 \"\n\"출력처럼 보이도록 재포맷됩니다.\"\n\n#: ../../document.rst:1309 7dd16ad90be84acbaf63def731cbd264\nmsgid \"\"\n\"Suppress the update of the file's `/ID` field. If the file happens to \"\n\"have no such field at all, also suppress creation of a new one. Default \"\n\"is `False`, so every save will lead to an updated file identification.\"\nmsgstr \"\"\n\"파일의 `/ID` 필드 업데이트를 억제합니다. 파일에 해당 필드가 전혀 없는 경우 새 필드 생성도 억제합니다. 기본값은 \"\n\"`False` 이므로 모든 저장은 업데이트된 파일 식별로 이어집니다.\"\n\n#: ../../document.rst:1311 2a716f171a0f421fa85517312a40a191\nmsgid \"\"\n\"*(new in v1.16.0)* Set the desired permission levels. See \"\n\":ref:`PermissionCodes` for possible values. Default is granting all.\"\nmsgstr \"\"\n\"*(v1.16.0에서 새로 추가됨)* 원하는 권한 수준을 설정합니다. 가능한 값은 :ref:`PermissionCodes` 를 \"\n\"참조하세요. 기본값은 모든 권한을 부여하는 것입니다.\"\n\n#: ../../document.rst:1313 c9d3decafb2f4d53b6c2c54c84c22e21\nmsgid \"\"\n\"*(new in v1.16.0)* set the desired encryption method. See \"\n\":ref:`EncryptionMethods` for possible values.\"\nmsgstr \"\"\n\"*(v1.16.0에서 새로 추가됨)* 원하는 암호화 방법을 설정합니다. 가능한 값은 :ref:`EncryptionMethods` 를\"\n\" 참조하세요.\"\n\n#: ../../document.rst:1315 8c5a0443338f4058bc9b39b87a5a1ed5\nmsgid \"\"\n\"*(new in v1.16.0)* set the document's owner password. *(Changed in \"\n\"v1.18.3)* If not provided, the user password is taken if provided. The \"\n\"string length must not exceed 40 characters.\"\nmsgstr \"\"\n\"*(v1.16.0에서 새로 추가됨)* 문서의 소유자 비밀번호를 설정합니다. *(v1.18.3에서 변경됨)* 제공되지 않으면 사용자 \"\n\"비밀번호가 제공된 경우 사용됩니다. 문자열 길이는 40자를 초과할 수 없습니다.\"\n\n#: ../../document.rst:1317 a46b78a4a9ae4766a339e09027197bb8\nmsgid \"\"\n\"*(new in v1.16.0)* set the document's user password. The string length \"\n\"must not exceed 40 characters.\"\nmsgstr \"*(v1.16.0에서 새로 추가됨)* 문서의 사용자 비밀번호를 설정합니다. 문자열 길이는 40자를 초과할 수 없습니다.\"\n\n#: ../../document.rst:1319 481e3dc0b944487ead97aee81e4ba71b\nmsgid \"\"\n\"*(new in v1.24.0)* compression option that converts eligible PDF object \"\n\"definitions to information that is stored in some other object's \"\n\":data:`stream` data. Depending on the `deflate` parameter value, the \"\n\"converted object definitions will be compressed -- which can lead to very\"\n\" significant file size reductions.\"\nmsgstr \"\"\n\"*(v1.24.0에서 새로 추가됨)* 적격 PDF 객체 정의를 다른 객체의 :data:`stream` 데이터에 저장된 정보로 \"\n\"변환하는 압축 옵션. `deflate` 매개변수 값에 따라 변환된 객체 정의가 압축됩니다 -- 이는 매우 큰 파일 크기 감소로 \"\n\"이어질 수 있습니다.\"\n\n#: ../../document.rst:1321 dc9a543907bb4a3fb5f759bc4d9a772a\nmsgid \"\"\n\"The method does not check, whether a file of that name already exists, \"\n\"will hence not ask for confirmation, and overwrite the file. It is your \"\n\"responsibility as a programmer to handle this.\"\nmsgstr \"\"\n\"이 메서드는 해당 이름의 파일이 이미 존재하는지 확인하지 않으므로 확인을 요청하지 않고 파일을 덮어씁니다. 프로그래머로서 이를 \"\n\"처리하는 것은 귀하의 책임입니다.\"\n\n#: ../../document.rst:1325 5b4cab99c9de4187b00ce3a945826cfc\nmsgid \"**File size reduction**\"\nmsgstr \"**파일 크기 감소**\"\n\n#: ../../document.rst:1327 a1964e573f34479da5566208ad76e9d4\nmsgid \"\"\n\"1. Use the save options like `garbage=3|4, deflate=True, \"\n\"use_objstms=True|1`. Do not touch the default values `expand=False|0, \"\n\"clean=False|0, incremental=False|0, linear=False|0`. This is a \"\n\"\\\"lossless\\\" file size reduction. There is a convenience version of this \"\n\"method with these values set by default, :meth:`Document.ez_save` -- \"\n\"please see below.\"\nmsgstr \"\"\n\"1. `garbage=3|4, deflate=True, use_objstms=True|1` 와 같은 저장 옵션을 사용하세요. 기본값\"\n\" `expand=False|0, clean=False|0, incremental=False|0, linear=False|0` 는 \"\n\"건드리지 마세요. 이것은 \\\"무손실\\\" 파일 크기 감소입니다. 이러한 값이 기본적으로 설정된 이 메서드의 편의 버전인 \"\n\":meth:`Document.ez_save` 가 있습니다 -- 아래를 참조하세요.\"\n\n#: ../../document.rst:1330 172936422e304f5b8fd9cfb2460b928b\nmsgid \"\"\n\"\\\"Lossy\\\" file size reduction in essence must give up something with \"\n\"respect to images, like (a) remove all images (b) replace images by their\"\n\" grayscale versions (c) reduce image resolutions. Find examples in the \"\n\"`PyMuPDF Utilities \\\"replace-image\\\" folder <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/examples/replace-image>`_.\"\nmsgstr \"\"\n\"\\\"손실\\\" 파일 크기 감소는 본질적으로 이미지와 관련하여 무언가를 포기해야 합니다. 예: (a) 모든 이미지 제거 (b) 이미지를\"\n\" 그레이스케일 버전으로 교체 (c) 이미지 해상도 감소. 예제는 `PyMuPDF Utilities \\\"replace-image\\\" \"\n\"폴더 <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples\"\n\"/replace-image>`_ 에서 찾을 수 있습니다.\"\n\n#: ../../document.rst:1334 a8c04ed4cd034b1b925922ea043a48c3\nmsgid \"New in v1.18.11\"\nmsgstr \"v1.18.11에서 새로 추가됨\"\n\n#: ../../document.rst:1336 8b017c18d31e4b28b04550143d27f7a4\nmsgid \"\"\n\"PDF only: The same as :meth:`Document.save` but with changed defaults \"\n\"`deflate=True, garbage=3, use_objstms=1`.\"\nmsgstr \"PDF 전용: :meth:`Document.save` 와 동일하지만 기본값이 `deflate=True, garbage=3, use_objstms=1` 로 변경되었습니다.\"\n\n#: ../../document.rst:1340 2c12cc4ba1bf4213b676b7b14fcb2141\nmsgid \"\"\n\"PDF only: saves the document incrementally. This is a convenience \"\n\"abbreviation for ``doc.save(doc.name, incremental=True, \"\n\"encryption=PDF_ENCRYPT_KEEP)``.\"\nmsgstr \"PDF 전용: 문서를 증분적으로 저장합니다. ``doc.save(doc.name, incremental=True, encryption=PDF_ENCRYPT_KEEP)`` 의 편의 약어입니다.\"\n\n#: ../../document.rst:1344 4b41e922b391460dba7ebb7d4c02f035\nmsgid \"\"\n\"Saving incrementally may be required if the document contains verified \"\n\"signatures which would be invalidated by saving to a new file.\"\nmsgstr \"문서에 검증된 서명이 포함되어 있는 경우 새 파일로 저장하면 무효화되므로 증분 저장이 필요할 수 있습니다.\"\n\n#: ../../document.rst:1353 bd79b7c8680c4e8191eee4f9cb511e92\nmsgid \"\"\n\"PDF only: Writes the **current content of the document** to a bytes \"\n\"object instead of to a file. Obviously, you should be wary about memory \"\n\"requirements. The meanings of the parameters exactly equal those in \"\n\":meth:`save`. Chapter :ref:`FAQ` contains an example for using this \"\n\"method as a pre-processor to `pdfrw \"\n\"<https://pypi.python.org/pypi/pdfrw/0.3>`_.\"\nmsgstr \"PDF 전용: 문서의 **현재 콘텐츠** 를 파일 대신 bytes 객체에 씁니다. 명백히 메모리 요구 사항에 주의해야 합니다. 매개변수의 의미는 :meth:`save` 와 정확히 동일합니다. :ref:`FAQ` 장에는 이 메서드를 `pdfrw <https://pypi.python.org/pypi/pdfrw/0.3>`_ 의 전처리기로 사용하는 예제가 포함되어 있습니다.\"\n\n#: ../../document.rst:1355 55f16e8ab0644d56bc5363e89919a50c\nmsgid \"*(Changed in v1.16.0)* for extended encryption support.\"\nmsgstr \"*(v1.16.0에서 변경됨)* 확장된 암호화 지원을 위해.\"\n\n#: ../../document.rst:1358 9f76330059a5422db75889fdc995f329\nmsgid \"a bytes object containing the complete document.\"\nmsgstr \"전체 문서를 포함하는 bytes 객체.\"\n\n#: ../../document.rst:1362 7dd8b6e2ab094eab8120755191d01969\nmsgid \"\"\n\"Search for \\\"text\\\" on page number \\\"pno\\\". Works exactly like the \"\n\"corresponding :meth:`Page.search_for`. Any integer `-∞ < pno < \"\n\"page_count` is acceptable.\"\nmsgstr \"페이지 번호 \\\"pno\\\" 에서 \\\"text\\\" 를 검색합니다. 해당 :meth:`Page.search_for` 와 정확히 동일하게 작동합니다. `-∞ < pno < page_count` 범위의 모든 정수가 허용됩니다.\"\n\n#: ../../document.rst:1380 43082a0a5f124b30970b917bb34650e5\nmsgid \"\"\n\"PDF only: Copy the page range **[from_page, to_page]** (including both) \"\n\"of PDF document *docsrc* into the current one. Inserts will start with \"\n\"page number *start_at*. Value -1 indicates default values. All pages thus\"\n\" copied will be rotated as specified. Links, annotations and widgets can \"\n\"be excluded in the target, see below. All page numbers are 0-based.\"\nmsgstr \"PDF 전용: PDF 문서 *docsrc* 의 페이지 범위 **[from_page, to_page]** (둘 다 포함)를 현재 문서로 복사합니다. 삽입은 페이지 번호 *start_at* 에서 시작합니다. 값 -1은 기본값을 나타냅니다. 이렇게 복사된 모든 페이지는 지정된 대로 회전됩니다. 링크, 주석 및 위젯은 대상에서 제외할 수 있습니다. 아래를 참조하세요. 모든 페이지 번호는 0 기반입니다.\"\n\n#: ../../document.rst:1382 de74f0d7ddaa4321ba9b05f7e6782d7b\nmsgid \"\"\n\"An opened PDF *Document* which must not be the current document. However,\"\n\" it may refer to the same underlying file.\"\nmsgstr \"현재 문서가 아니어야 하는 열린 PDF *Document*. 그러나 동일한 기본 파일을 참조할 수 있습니다.\"\n\n#: ../../document.rst:1385 5d8c2339c1ed44d3a9fd29b7eac353d5\nmsgid \"First page number in *docsrc*. Default is zero.\"\nmsgstr \"*docsrc* 의 첫 번째 페이지 번호. 기본값은 0입니다.\"\n\n#: ../../document.rst:1387 b6f7dfe8073c4e1e93f59ad9c41b7a79\nmsgid \"Last page number in *docsrc* to copy. Defaults to last page.\"\nmsgstr \"복사할 *docsrc* 의 마지막 페이지 번호. 기본값은 마지막 페이지입니다.\"\n\n#: ../../document.rst:1389 83d52f17fb0643119d37044f7ee4f12d\nmsgid \"\"\n\"First copied page, will become page number *start_at* in the target. \"\n\"Default -1 appends the page range to the end. If zero, the page range \"\n\"will be inserted before current first page.\"\nmsgstr \"첫 번째로 복사된 페이지는 대상에서 페이지 번호 *start_at* 이 됩니다. 기본값 -1은 페이지 범위를 끝에 추가합니다. 0이면 페이지 범위가 현재 첫 번째 페이지 앞에 삽입됩니다.\"\n\n#: ../../document.rst:1391 0ffa16d8a4b94f448bc2d8eefd7285f8\nmsgid \"\"\n\"All copied pages will be rotated by the provided value (degrees, integer \"\n\"multiple of 90).\"\nmsgstr \"복사된 모든 페이지는 제공된 값(도, 90의 정수 배수)만큼 회전됩니다.\"\n\n#: ../../document.rst:1393 a4ca40c2a8a14fe587100c9363d2c340\nmsgid \"\"\n\"Choose whether (internal and external) links should be included in the \"\n\"copy. Default is `True`. *Named* links (:data:`LINK_NAMED`) and internal \"\n\"links to outside the copied page range are **always excluded**.\"\nmsgstr \"(내부 및 외부) 링크를 복사본에 포함할지 선택합니다. 기본값은 `True` 입니다. *명명된* 링크(:data:`LINK_NAMED`) 및 복사된 페이지 범위 외부로의 내부 링크는 **항상 제외됩니다**.\"\n\n#: ../../document.rst:1395 f7a2eb67861840798b4bcdaa41872471\nmsgid \"choose whether annotations should be included in the copy.\"\nmsgstr \"주석을 복사본에 포함할지 선택합니다.\"\n\n#: ../../document.rst:1397 d2e9e86dbc054d8595d70da1e19eb60a\nmsgid \"\"\n\"choose whether annotations should be included in the copy. If `True` and \"\n\"at least one of the source pages contains form fields, the target PDF \"\n\"will be turned into a Form PDF (if not already being one).\"\nmsgstr \"주석을 복사본에 포함할지 선택합니다. `True` 이고 소스 페이지 중 하나 이상에 양식 필드가 포함되어 있으면 대상 PDF가 Form PDF로 전환됩니다(아직 그렇지 않은 경우).\"\n\n#: ../../document.rst:1399 a148422f862e4b318976a18499787dd1\nmsgid \"\"\n\"*(New in version 1.25.5)* Choose how to handle duplicate root field names\"\n\" in the source pages. This parameter is ignored if `widgets=False`.  \"\n\"Default is ``False`` which will add unifying strings to the name of those\"\n\" source root fields which have a duplicate in the target. For instance, \"\n\"if \\\"name\\\" already occurs in the target, the source widget's name will \"\n\"be changed to \\\"name [text]\\\" with a suitably chosen string \\\"text\\\".  If\"\n\" ``True``, root fields with duplicate names in source and target will be \"\n\"converted to so-called \\\"Kids\\\" of a \\\"Parent\\\" object (which lists all \"\n\"kid widgets in a PDF array). This will effectively turn those kids into \"\n\"instances of the \\\"same\\\" widget: if e.g. one of the kids is changed, \"\n\"then all its instances will automatically inherit this change -- no \"\n\"matter on which page they happen to be displayed.\"\nmsgstr \"\"\n\n#: ../../document.rst:1399 29fe39aa48044a5a87a3e46722e5dcc2\nmsgid \"\"\n\"*(New in version 1.25.5)* Choose how to handle duplicate root field names\"\n\" in the source pages. This parameter is ignored if `widgets=False`.\"\nmsgstr \"*(버전 1.25.5에서 새로 추가됨)* 소스 페이지에서 중복된 루트 필드 이름을 처리하는 방법을 선택합니다. `widgets=False` 이면 이 매개변수는 무시됩니다.\"\n\n#: ../../document.rst:1401 529b0cbb3d354c4ca55021b991023c34\nmsgid \"\"\n\"Default is ``False`` which will add unifying strings to the name of those\"\n\" source root fields which have a duplicate in the target. For instance, \"\n\"if \\\"name\\\" already occurs in the target, the source widget's name will \"\n\"be changed to \\\"name [text]\\\" with a suitably chosen string \\\"text\\\".\"\nmsgstr \"기본값은 ``False`` 이며, 대상에 중복이 있는 소스 루트 필드의 이름에 통합 문자열을 추가합니다. 예를 들어 \\\"name\\\" 이 이미 대상에 있으면 소스 위젯의 이름이 적절히 선택된 문자열 \\\"text\\\" 와 함께 \\\"name [text]\\\" 로 변경됩니다.\"\n\n#: ../../document.rst:1403 ff97b1ac50a4459b81ac03121569ae66\nmsgid \"\"\n\"If ``True``, root fields with duplicate names in source and target will \"\n\"be converted to so-called \\\"Kids\\\" of a \\\"Parent\\\" object (which lists \"\n\"all kid widgets in a PDF array). This will effectively turn those kids \"\n\"into instances of the \\\"same\\\" widget: if e.g. one of the kids is \"\n\"changed, then all its instances will automatically inherit this change --\"\n\" no matter on which page they happen to be displayed.\"\nmsgstr \"``True`` 인 경우 소스와 대상에 중복 이름이 있는 루트 필드는 \\\"Parent\\\" 객체의 소위 \\\"Kids\\\" 로 변환됩니다(PDF 배열에 모든 자식 위젯을 나열). 이것은 효과적으로 이러한 자식을 \\\"동일한\\\" 위젯의 인스턴스로 만듭니다: 예를 들어 자식 중 하나가 변경되면 모든 인스턴스가 자동으로 이 변경을 상속받습니다 -- 어떤 페이지에 표시되든 상관없이.\"\n\n#: ../../document.rst:1405 952c23aab20d49af9f19214ea9c24063\nmsgid \"\"\n\"*(new in v1.17.7)* specify an interval size greater zero to see progress \"\n\"messages on `sys.stdout`. After each interval, a message like `Inserted \"\n\"30 of 47 pages.` will be printed.\"\nmsgstr \"*(v1.17.7에서 새로 추가됨)* `sys.stdout` 에 진행 메시지를 보려면 0보다 큰 간격 크기를 지정하세요. 각 간격 후에 `Inserted 30 of 47 pages.` 와 같은 메시지가 인쇄됩니다.\"\n\n#: ../../document.rst:1407 2ff6cf0ddbbf4801a6e1c4b587de1a46\nmsgid \"\"\n\"*(new in v1.18.0)* controls whether the list of already copied objects \"\n\"should be **dropped** after this method, default ``True``. Set it to 0 \"\n\"except for the last one of multiple insertions from the same source PDF. \"\n\"This saves target file size and speeds up execution considerably.\"\nmsgstr \"\"\n\"*(v1.18.0에서 새로 추가됨)* 이미 복사된 객체 목록을 이 메서드 후에 **삭제** 할지 제어합니다. 기본값 \"\n\"``True``. 동일한 소스 PDF에서 여러 삽입의 마지막 항목을 제외하고는 0으로 설정하세요. 이것은 대상 파일 크기를 절약하고\"\n\" 실행 속도를 크게 향상시킵니다.\"\n\n#: ../../document.rst:1411 9372e5e0d8e041ac8259407781272ad0\nmsgid \"\"\n\"This is a page-based method. Document-level information of source \"\n\"documents is therefore mostly ignored. Examples include Optional Content,\"\n\" Embedded Files, `StructureElem`, table of contents, page labels, \"\n\"metadata, named destinations (and other named entries) and some more.\"\nmsgstr \"\"\n\"이것은 페이지 기반 메서드입니다. 따라서 소스 문서의 문서 수준 정보는 대부분 무시됩니다. 예로는 Optional Content, \"\n\"Embedded Files, `StructureElem`, 목차, 페이지 레이블, 메타데이터, 명명된 대상(및 기타 명명된 항목) \"\n\"등이 있습니다.\"\n\n#: ../../document.rst:1413 43f4211198a343f48f9021d6315262d3\nmsgid \"\"\n\"If `from_page > to_page`, pages will be **copied in reverse order**. If \"\n\"`0 <= from_page == to_page`, then one page will be copied.\"\nmsgstr \"\"\n\"`from_page > to_page` 인 경우 페이지는 **역순으로 복사됩니다**. `0 <= from_page == \"\n\"to_page` 인 경우 한 페이지가 복사됩니다.\"\n\n#: ../../document.rst:1415 7cc285a8c29d43469d52cb1b3c81c8e3\nmsgid \"\"\n\"`docsrc` TOC entries **will not be copied**. It is easy however, to \"\n\"recover a table of contents for the resulting document. Look at the \"\n\"examples below and at program `join.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py>`_ in the \"\n\"*examples* directory: it can join PDF documents and at the same time \"\n\"piece together respective parts of the tables of contents.\"\nmsgstr \"\"\n\"`docsrc` TOC 항목은 **복사되지 않습니다**. 그러나 결과 문서에 대한 목차를 복구하는 것은 쉽습니다. 아래 예제와 \"\n\"*examples* 디렉토리의 프로그램 `join.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/join-documents/join.py>`_ 을 참조하세요: PDF 문서를\"\n\" 결합하고 동시에 목차의 해당 부분을 함께 구성할 수 있습니다.\"\n\n#: ../../document.rst:1432 d2452152a5034a9ca2daefca1e0824cc\nmsgid \"New in v1.22.0\"\nmsgstr \"v1.22.0에서 새로 추가됨\"\n\n#: ../../document.rst:1434 7373f7c4857c46cf8292d68949ff4f6b\nmsgid \"\"\n\"PDF only: Add an arbitrary supported document to the current PDF. Opens \"\n\"\\\"infile\\\" as a document, converts it to a PDF and then invokes \"\n\":meth:`Document.insert_pdf`. Parameters are the same as for that method. \"\n\"Among other things, this features an easy way to append images as full \"\n\"pages to an output PDF.\"\nmsgstr \"\"\n\"PDF 전용: 임의의 지원되는 문서를 현재 PDF에 추가합니다. \\\"infile\\\" 을 문서로 열고 PDF로 변환한 다음 \"\n\":meth:`Document.insert_pdf` 를 호출합니다. 매개변수는 해당 메서드와 동일합니다. 특히 이것은 이미지를 전체 \"\n\"페이지로 출력 PDF에 추가하는 쉬운 방법을 제공합니다.\"\n\n#: ../../document.rst:1436 f479d2cec81c433ebe02aedeecb37264\nmsgid \"\"\n\"the input document to insert. May be a filename specification as is valid\"\n\" for creating a :ref:`Document` or a :ref:`Pixmap`.\"\nmsgstr \"삽입할 입력 문서. :ref:`Document` 또는 :ref:`Pixmap` 생성에 유효한 파일명 지정일 수 있습니다.\"\n\n#: ../../document.rst:1445 8dcf3ea094984946a1ab40d0ac352086\nmsgid \"PDF only: Insert an empty page.\"\nmsgstr \"PDF 전용: 빈 페이지를 삽입합니다.\"\n\n#: ../../document.rst:1447 00a8d07f6d82488a9575361ef2378659\nmsgid \"\"\n\"page number index (zero-indexed) at which to insert page. Special values \"\n\"-1 and *doc.page_count* insert **after** the last page.\"\nmsgstr \"\"\n\"페이지를 삽입할 페이지 번호 인덱스(0 기반). 특수 값 -1 및 *doc.page_count* 는 마지막 페이지 **뒤에** \"\n\"삽입합니다.\"\n\n#: ../../document.rst:1449 3f3a9a8d80db4350b6aa231d7cc28695\nmsgid \"page width.\"\nmsgstr \"페이지 너비.\"\n\n#: ../../document.rst:1450 7f73155629f24628a3c4e697f5a95326\nmsgid \"page height.\"\nmsgstr \"페이지 높이.\"\n\n#: ../../document.rst:1453 f93d2c1aec874e60af37aecd88602571\nmsgid \"\"\n\"the created page object. Be aware that the page numbers of pages after \"\n\"the inserted one will have changed after method execution. For the same \"\n\"reason, **all existing page objects will be invalidated.** Using them \"\n\"will lead to exceptions.\"\nmsgstr \"\"\n\"생성된 페이지 객체. 삽입된 페이지 이후의 페이지 번호는 메서드 실행 후 변경됩니다. 같은 이유로 **모든 기존 페이지 객체가 \"\n\"무효화됩니다.** 사용하면 예외가 발생합니다.\"\n\n#: ../../document.rst:1465 4fec146cb4a844ac8c297a57c50caac2\nmsgid \"\"\n\"PDF only: Insert a new page and insert some text. Convenience function \"\n\"which combines :meth:`Document.new_page` and (parts of) \"\n\":meth:`Page.insert_text`.\"\nmsgstr \"\"\n\"PDF 전용: 새 페이지를 삽입하고 일부 텍스트를 삽입합니다. :meth:`Document.new_page` 와 \"\n\":meth:`Page.insert_text` (일부)를 결합한 편의 함수입니다.\"\n\n#: ../../document.rst:1467 e3181bddc05248ee94dcee0c6c40a956\nmsgid \"\"\n\"page number index (zero-indexed) at which to insert page. Special values \"\n\"-1 and `doc.page_count` insert **after** the last page.  Changed in \"\n\"v1.14.12    This is now a positional parameter\"\nmsgstr \"\"\n\"\"\n\n#: ../../document.rst:1467 bb201d9d3e05493ca05d394ffe6eb5be\nmsgid \"\"\n\"page number index (zero-indexed) at which to insert page. Special values \"\n\"-1 and `doc.page_count` insert **after** the last page.\"\nmsgstr \"\"\n\"페이지를 삽입할 페이지 번호 인덱스(0 기반). 특수 값 -1 및 `doc.page_count` 는 마지막 페이지 **뒤에** \"\n\"삽입합니다.\"\n\n#: ../../document.rst:1470 690c131f782848fabe1418ba0e89c425\nmsgid \"Changed in v1.14.12\"\nmsgstr \"v1.14.12에서 변경됨\"\n\n#: ../../document.rst:1470 47247eda374945e2ad736398081742d3\nmsgid \"This is now a positional parameter\"\nmsgstr \"이것은 이제 위치 매개변수입니다\"\n\n#: ../../document.rst:1472 b0c0975bac1c45d5994beda8b6775b5b\nmsgid \"For the other parameters, please consult the aforementioned methods.\"\nmsgstr \"다른 매개변수는 위에서 언급한 메서드를 참조하세요.\"\n\n#: ../../document.rst:1475 6d101fcbabdf43b0ac289c175ff53220\nmsgid \"\"\n\"the result of :meth:`Page.insert_text` (number of successfully inserted \"\n\"lines).\"\nmsgstr \":meth:`Page.insert_text` 의 결과(성공적으로 삽입된 줄 수).\"\n\n#: ../../document.rst:1479 ecc50b85f14241d2aa31343b5e5aa5f7\nmsgid \"\"\n\"PDF only: Delete a page given by its 0-based number in `-∞ < pno < \"\n\"page_count`.\"\nmsgstr \"PDF 전용: `-∞ < pno < page_count` 범위의 0 기반 번호로 지정된 페이지를 삭제합니다.\"\n\n#: ../../document.rst:1481 ../../document.rst:1488\n#: 3763d366c7114f2cb92215e4aa36dd9e f9dd271045134befa0cae7b4d29e2b19\nmsgid \"Changed in v1.18.14: support Python's `del` statement.\"\nmsgstr \"v1.18.14에서 변경됨: Python의 `del` 문 지원.\"\n\n#: ../../document.rst:1483 edd90564c56a475480386e44c20c183f\nmsgid \"\"\n\"the page to be deleted. Negative number count backwards from the end of \"\n\"the document (like with indices). Default is the last page.\"\nmsgstr \"삭제할 페이지. 음수는 문서 끝에서 역순으로 계산합니다(인덱스와 같이). 기본값은 마지막 페이지입니다.\"\n\n#: ../../document.rst:1487 885178ede3f341d9977c12eeee0ce39a\nmsgid \"Changed in v1.18.13: more flexibility specifying pages to delete.\"\nmsgstr \"v1.18.13에서 변경됨: 삭제할 페이지 지정의 유연성 향상.\"\n\n#: ../../document.rst:1490 2faf9fc669694bf58fbd3fbda80d6a18\nmsgid \"PDF only: Delete multiple pages given as 0-based numbers.\"\nmsgstr \"PDF 전용: 0 기반 번호로 지정된 여러 페이지를 삭제합니다.\"\n\n#: ../../document.rst:1494 49043c2a25724e858a719fcf64d92c54\nmsgid \"\"\n\"**Format 1:** Use keywords. Represents the old format. A contiguous range\"\n\" of pages is removed.\"\nmsgstr \"**형식 1:** 키워드를 사용합니다. 이전 형식을 나타냅니다. 연속된 페이지 범위가 제거됩니다.\"\n\n#: ../../document.rst:1493 abdf0e27ad514fa4a0a49edfa8166fc0\nmsgid \"\\\"from_page\\\": first page to delete. Zero if omitted.\"\nmsgstr \"\\\"from_page\\\": 삭제할 첫 페이지. 생략하면 0입니다.\"\n\n#: ../../document.rst:1494 272c0a7e9e844ab6925f9d42e326b8dd\nmsgid \"\"\n\"\\\"to_page\\\": last page to delete. Last page in document if omitted. Must \"\n\"not be less then \\\"from_page\\\".\"\nmsgstr \"\"\n\"\\\"to_page\\\": 삭제할 마지막 페이지. 생략하면 문서의 마지막 페이지입니다. \\\"from_page\\\" 보다 작아서는 안 \"\n\"됩니다.\"\n\n#: ../../document.rst:1496 853ec2ac461141488a842564542b01ee\nmsgid \"\"\n\"**Format 2:** Two page numbers as positional parameters. Handled like \"\n\"Format 1.\"\nmsgstr \"**형식 2:** 위치 매개변수로 두 페이지 번호. 형식 1과 같이 처리됩니다.\"\n\n#: ../../document.rst:1498 d11ba0ed8b3448a1b9c698565e879a5c\nmsgid \"\"\n\"**Format 3:** One positional integer parameter. Equivalent to \"\n\":meth:`Page.delete_page`.\"\nmsgstr \"**형식 3:** 하나의 위치 정수 매개변수. :meth:`Page.delete_page` 와 동일합니다.\"\n\n#: ../../document.rst:1500 0023d1389c764262bb87cf7faa1adc43\nmsgid \"\"\n\"**Format 4:** One positional parameter of type *list*, *tuple* or \"\n\"*range()* of page numbers. The items of this sequence may be in any order\"\n\" and may contain duplicates.\"\nmsgstr \"\"\n\"**형식 4:** *list*, *tuple* 또는 *range()* 타입의 페이지 번호 하나의 위치 매개변수. 이 시퀀스의 항목은\"\n\" 어떤 순서든 될 수 있으며 중복을 포함할 수 있습니다.\"\n\n#: ../../document.rst:1502 3a616c07b63341aabad5be2aadd5b519\nmsgid \"\"\n\"**Format 5:** *(New in v1.18.14)* Using the Python `del` statement and \"\n\"index / slice notation is now possible.\"\nmsgstr \"**형식 5:** *(v1.18.14에서 새로 추가됨)* Python `del` 문과 인덱스/슬라이스 표기법을 사용할 수 있습니다.\"\n\n#: ../../document.rst:1506 be81c094406043ae869d72a40ff136e0\nmsgid \"\"\n\"*(Changed in v1.14.17, optimized in v1.17.7)* In an effort to maintain a \"\n\"valid PDF structure, this method and :meth:`delete_page` will also \"\n\"deactivate items in the table of contents which point to deleted pages. \"\n\"\\\"Deactivation\\\" here means, that the bookmark will point to nowhere and \"\n\"the title will be shown grayed-out by supporting PDF viewers. The overall\"\n\" TOC structure is left intact.\"\nmsgstr \"\"\n\"*(v1.14.17에서 변경됨, v1.17.7에서 최적화됨)* 유효한 PDF 구조를 유지하기 위해 이 메서드와 \"\n\":meth:`delete_page` 는 삭제된 페이지를 가리키는 목차 항목도 비활성화합니다. 여기서 \\\"비활성화\\\"는 북마크가 아무\"\n\" 곳도 가리키지 않고 제목이 지원 PDF 뷰어에서 회색으로 표시됨을 의미합니다. 전체 TOC 구조는 그대로 유지됩니다.\"\n\n#: ../../document.rst:1508 d7fcfd0146d14359b986d22c70246218\nmsgid \"\"\n\"It will also remove any **links on remaining pages** which point to a \"\n\"deleted one. This action may have an extended response time for documents\"\n\" with many pages.\"\nmsgstr \"\"\n\"삭제된 페이지를 가리키는 **남은 페이지의 모든 링크** 도 제거합니다. 이 작업은 많은 페이지가 있는 문서에서 응답 시간이 길어질\"\n\" 수 있습니다.\"\n\n#: ../../document.rst:1510 031b85dd387d4fa9ac92c6b66548733c\nmsgid \"Following examples will all delete pages 500 through 519:\"\nmsgstr \"다음 예제는 모두 페이지 500부터 519까지 삭제합니다:\"\n\n#: ../../document.rst:1512 cfe10a0a274d4d18adb6a3bd80a8c1eb\nmsgid \"`doc.delete_pages(500, 519)`\"\nmsgstr \"`doc.delete_pages(500, 519)`\"\n\n#: ../../document.rst:1513 3629419e0fec421e899e07854d3dee86\nmsgid \"`doc.delete_pages(from_page=500, to_page=519)`\"\nmsgstr \"`doc.delete_pages(from_page=500, to_page=519)`\"\n\n#: ../../document.rst:1514 b99266396f9c4f729d682c6591e66fb7\nmsgid \"`doc.delete_pages((500, 501, 502, ... , 519))`\"\nmsgstr \"`doc.delete_pages((500, 501, 502, ... , 519))`\"\n\n#: ../../document.rst:1515 7a5309be435b4725b98df7a5b13abd28\nmsgid \"`doc.delete_pages(range(500, 520))`\"\nmsgstr \"`doc.delete_pages(range(500, 520))`\"\n\n#: ../../document.rst:1516 f81d6cadee344814b046eceef5c80d85\nmsgid \"`del doc[500:520]`\"\nmsgstr \"`del doc[500:520]`\"\n\n#: ../../document.rst:1517 634d0eae36d4441f91c1a42e91f8628f\nmsgid \"`del doc[(500, 501, 502, ... , 519)]`\"\nmsgstr \"`del doc[(500, 501, 502, ... , 519)]`\"\n\n#: ../../document.rst:1518 fafab429d5424ce18f58f1ae4c8dbdfb\nmsgid \"`del doc[range(500, 520)]`\"\nmsgstr \"`del doc[range(500, 520)]`\"\n\n#: ../../document.rst:1520 e32e7365169c4fcb97e6fcce960a23d2\nmsgid \"\"\n\"For the :ref:`AdobeManual` the above takes about 0.6 seconds, because the\"\n\" remaining 1290 pages must be cleaned from invalid links.\"\nmsgstr \"\"\n\":ref:`AdobeManual` 의 경우 위 작업은 약 0.6초가 걸립니다. 남은 1290페이지에서 잘못된 링크를 정리해야 하기 \"\n\"때문입니다.\"\n\n#: ../../document.rst:1522 8cce67b3735c4db09b073f74c42ad5d6\nmsgid \"\"\n\"In general, the performance of this method is dependent on the number of \"\n\"remaining pages -- **not** on the number of deleted pages: in the above \"\n\"example, **deleting all pages except** those 20, will need much less \"\n\"time.\"\nmsgstr \"\"\n\"일반적으로 이 메서드의 성능은 삭제된 페이지 수가 아니라 **남은 페이지 수** 에 따라 달라집니다: 위 예제에서 **그 20개를 \"\n\"제외한 모든 페이지를 삭제** 하면 훨씬 적은 시간이 필요합니다.\"\n\n#: ../../document.rst:1527 583a7be7f7604564b5aea9150f5f1a47\nmsgid \"PDF only: Copy a page reference within the document.\"\nmsgstr \"PDF 전용: 문서 내에서 페이지 참조를 복사합니다.\"\n\n#: ../../document.rst:1529 796aa36a17194091986df564ff5cd031\nmsgid \"the page to be copied. Must be in range `0 <= pno < page_count`.\"\nmsgstr \"복사할 페이지. `0 <= pno < page_count` 범위에 있어야 합니다.\"\n\n#: ../../document.rst:1531 ../../document.rst:1543\n#: 35e41025040645fdb1331ee178e2d324 715bba4c474e466bafbb9855293c69d5\nmsgid \"\"\n\"the page number in front of which to copy. The default inserts **after** \"\n\"the last page.\"\nmsgstr \"복사할 페이지 앞의 페이지 번호. 기본값은 마지막 페이지 **뒤에** 삽입합니다.\"\n\n#: ../../document.rst:1533 f3183958d7134dc7a00e4bfe56a78abb\nmsgid \"\"\n\"Only a new **reference** to the page object will be created -- not a new \"\n\"page object, all copied pages will have identical attribute values, \"\n\"including the :attr:`Page.xref`. This implies that any changes to one of \"\n\"these copies will appear on all of them.\"\nmsgstr \"페이지 객체에 대한 새 **참조** 만 생성됩니다 -- 새 페이지 객체가 아닙니다. 모든 복사된 페이지는 :attr:`Page.xref` 를 포함하여 동일한 속성 값을 가집니다. 이것은 이러한 복사본 중 하나에 대한 변경 사항이 모두에 나타남을 의미합니다.\"\n\n#: ../../document.rst:1537 4f81f7087616448e9a2079171720cc5e\nmsgid \"New in v1.14.17\"\nmsgstr \"v1.14.17에서 새로 추가됨\"\n\n#: ../../document.rst:1539 18edd22eb7b54b58973f27488646277d\nmsgid \"PDF only: Make a full copy (duplicate) of a page.\"\nmsgstr \"PDF 전용: 페이지의 전체 복사본(중복)을 만듭니다.\"\n\n#: ../../document.rst:1541 2be6a8a3c6254c419fffe87ecf3bea2e\nmsgid \"the page to be duplicated. Must be in range `0 <= pno < page_count`.\"\nmsgstr \"중복할 페이지. `0 <= pno < page_count` 범위에 있어야 합니다.\"\n\n#: ../../document.rst:1547 838d6b92f708488bb71ffb9c00ddf20e\nmsgid \"\"\n\"In contrast to :meth:`copy_page`, this method creates a new page object \"\n\"(with a new :data:`xref`), which can be changed independently from the \"\n\"original.\"\nmsgstr \":meth:`copy_page` 와 달리 이 메서드는 원본과 독립적으로 변경할 수 있는 새 페이지 객체(새 :data:`xref` 포함)를 생성합니다.\"\n\n#: ../../document.rst:1549 bf6930ee99a14f56af7c4035128d0a3a\nmsgid \"\"\n\"Any Popup and \\\"IRT\\\" (\\\"in response to\\\") annotations are **not copied**\"\n\" to avoid potentially incorrect situations.\"\nmsgstr \"잠재적으로 잘못된 상황을 피하기 위해 모든 Popup 및 \\\"IRT\\\" (\\\"in response to\\\") 주석은 **복사되지 않습니다**.\"\n\n#: ../../document.rst:1553 03d410f070af4c8ab7946dea0b01ec41\nmsgid \"PDF only: Move (copy and then delete original) a page within the document.\"\nmsgstr \"PDF 전용: 문서 내에서 페이지를 이동합니다(복사한 다음 원본 삭제).\"\n\n#: ../../document.rst:1555 4d77ecb443e649f9940a25cfef2a0225\nmsgid \"the page to be moved. Must be in range `0 <= pno < page_count`.\"\nmsgstr \"이동할 페이지. `0 <= pno < page_count` 범위에 있어야 합니다.\"\n\n#: ../../document.rst:1557 33c20380a2314d1fbb336bedbe0804b3\nmsgid \"\"\n\"the page number in front of which to insert the moved page. The default \"\n\"moves **after** the last page.\"\nmsgstr \"이동된 페이지를 삽입할 페이지 번호 앞. 기본값은 마지막 페이지 **뒤로** 이동합니다.\"\n\n#: ../../document.rst:1562 e1e656e24f2d412588299042a89712e5\nmsgid \"New in v1.17.4\"\nmsgstr \"v1.17.4에서 새로 추가됨\"\n\n#: ../../document.rst:1564 2c50544aa3ca445cb7e7196d1afe9710\nmsgid \"\"\n\"PDF only: Get or set the */NeedAppearances* property of Form PDFs. Quote:\"\n\" *\\\"(Optional) A flag specifying whether to construct appearance streams \"\n\"and appearance dictionaries for all widget annotations in the document \"\n\"... Default value: false.\\\"* This may help controlling the behavior of \"\n\"some readers / viewers.\"\nmsgstr \"PDF 전용: Form PDF의 */NeedAppearances* 속성을 가져오거나 설정합니다. 인용: *\\\"(선택적) 문서의 모든 위젯 주석에 대한 appearance 스트림 및 appearance 딕셔너리를 구성할지 여부를 지정하는 플래그 ... 기본값: false.\\\"* 이것은 일부 리더/뷰어의 동작을 제어하는 데 도움이 될 수 있습니다.\"\n\n#: ../../document.rst:1566 b1652fd4ef124c6a9173defa2306862b\nmsgid \"\"\n\"set the property to this value. If omitted or `None`, inquire the current\"\n\" value.\"\nmsgstr \"속성을 이 값으로 설정합니다. 생략하거나 `None` 이면 현재 값을 조회합니다.\"\n\n#: ../../document.rst:1569 10db7e389c3443749906de632a038e80\nmsgid \"\"\n\"* None: not a Form PDF, or property not defined. * True / False: the \"\n\"value of the property (either just set or existing for inquiries). Has no\"\n\" effect if no Form PDF.\"\nmsgstr \"\"\n\n#: ../../document.rst:1570 20765c4d680e450db6d65401c2d563be\nmsgid \"None: not a Form PDF, or property not defined.\"\nmsgstr \"None: Form PDF가 아니거나 속성이 정의되지 않음.\"\n\n#: ../../document.rst:1571 34e43b74a8f24e9bbe54d44cf4d28ddf\nmsgid \"\"\n\"True / False: the value of the property (either just set or existing for \"\n\"inquiries). Has no effect if no Form PDF.\"\nmsgstr \"True / False: 속성의 값(방금 설정되었거나 조회를 위해 존재함). Form PDF가 없으면 효과가 없습니다.\"\n\n#: ../../document.rst:1577 cf26e7bb7e224490bc8cd693fdc457f9\nmsgid \"\"\n\"PDF only: Return whether the document contains signature fields. This is \"\n\"an optional PDF property: if not present (return value -1), no \"\n\"conclusions can be drawn -- the PDF creator may just not have bothered \"\n\"using it.\"\nmsgstr \"PDF 전용: 문서에 서명 필드가 포함되어 있는지 반환합니다. 이것은 선택적 PDF 속성입니다: 없으면(반환 값 -1) 결론을 내릴 수 없습니다 -- PDF 작성자가 사용하지 않았을 수 있습니다.\"\n\n#: ../../document.rst:1580 6cc1ff6a8526438793161934c9c4b4e9\nmsgid \"\"\n\"* -1: not a Form PDF / no signature fields recorded / no *SigFlags* \"\n\"found. * 1: at least one signature field exists. * 3:  contains \"\n\"signatures that may be invalidated if the file is saved (written) in a \"\n\"way that alters its previous contents, as opposed to an incremental \"\n\"update.\"\nmsgstr \"\"\n\n#: ../../document.rst:1581 49e77b466a9c4b8cae591da940e7bb80\nmsgid \"-1: not a Form PDF / no signature fields recorded / no *SigFlags* found.\"\nmsgstr \"-1: Form PDF가 아님 / 기록된 서명 필드 없음 / *SigFlags* 없음.\"\n\n#: ../../document.rst:1582 3c2d9c0c66ac4186aabeb9505ef62861\nmsgid \"1: at least one signature field exists.\"\nmsgstr \"1: 최소한 하나의 서명 필드가 존재함.\"\n\n#: ../../document.rst:1583 eba9fbffaa5f4a66baada0b97bab393c\nmsgid \"\"\n\"3:  contains signatures that may be invalidated if the file is saved \"\n\"(written) in a way that alters its previous contents, as opposed to an \"\n\"incremental update.\"\nmsgstr \"3: 증분 업데이트와 달리 이전 콘텐츠를 변경하는 방식으로 파일이 저장(쓰기)되면 무효화될 수 있는 서명을 포함함.\"\n\n#: ../../document.rst:1592 4c7b6e1f922e4d48b1e2e0924cfcfbfb\nmsgid \"\"\n\"Changed in v1.14.16: The sequence of positional parameters \\\"name\\\" and \"\n\"\\\"buffer\\\" has been changed to comply with the call pattern of other \"\n\"functions.\"\nmsgstr \"v1.14.16에서 변경됨: 위치 매개변수 \\\"name\\\" 및 \\\"buffer\\\" 의 순서가 다른 함수의 호출 패턴을 준수하도록 변경되었습니다.\"\n\n#: ../../document.rst:1594 7bdd76ccfaa846f285fb18022d6c352b\nmsgid \"\"\n\"PDF only: Embed a new file. All string parameters except the name may be \"\n\"unicode (in previous versions, only ASCII worked correctly). File \"\n\"contents will be compressed (where beneficial).\"\nmsgstr \"PDF 전용: 새 파일을 임베드합니다. 이름을 제외한 모든 문자열 매개변수는 유니코드일 수 있습니다(이전 버전에서는 ASCII만 올바르게 작동함). 파일 콘텐츠는 압축됩니다(유익한 경우).\"\n\n#: ../../document.rst:1596 23a4029a12bf4c439ee7db0580ddba4b\nmsgid \"entry identifier, **must not already exist**.\"\nmsgstr \"항목 식별자, **이미 존재하지 않아야 합니다**.\"\n\n#: ../../document.rst:1597 617e80916a94448494c2f6a114b89372\nmsgid \"\"\n\"file contents.  *(Changed in v1.14.13)* *io.BytesIO* is now also \"\n\"supported.\"\nmsgstr \"\"\n\n#: ../../document.rst:1597 3a52550a9c2e4f309e3ccbc749fc6821\nmsgid \"file contents.\"\nmsgstr \"파일 콘텐츠.\"\n\n#: ../../document.rst:1599 ../../document.rst:1673\n#: 3190704368d346e78d62a922fea40f03 80b30821875b4646a520a962f6d80271\nmsgid \"*(Changed in v1.14.13)* *io.BytesIO* is now also supported.\"\nmsgstr \"*(v1.14.13에서 변경됨)* *io.BytesIO*도 이제 지원됩니다.\"\n\n#: ../../document.rst:1601 df2b2260b10b42a7838460af69e70ce1\nmsgid \"optional filename. Documentation only, will be set to *name* if `None`.\"\nmsgstr \"선택적 파일 이름. 문서화 전용이며, `None` 이면 *name* 으로 설정됩니다.\"\n\n#: ../../document.rst:1602 7e6e3e037eac466f85a5b54dfc900de1\nmsgid \"\"\n\"optional unicode filename. Documentation only, will be set to *filename* \"\n\"if `None`.\"\nmsgstr \"선택적 유니코드 파일 이름. 문서화 전용이며, `None` 이면 *filename* 으로 설정됩니다.\"\n\n#: ../../document.rst:1603 ec21943371c34b05a9a07bec862f7348\nmsgid \"optional description. Documentation only, will be set to *name* if `None`.\"\nmsgstr \"선택적 설명. 문서화 전용이며, `None` 이면 *name* 으로 설정됩니다.\"\n\n#: ../../document.rst:1606 5c90aa58601f4e04b3a8163fe1b2379a\nmsgid \"\"\n\"*(Changed in v1.18.13)* The method now returns the :data:`xref` of the \"\n\"inserted file. In addition, the file object now will be automatically \"\n\"given the PDF keys `/CreationDate` and `/ModDate` based on the current \"\n\"date-time.\"\nmsgstr \"*(v1.18.13에서 변경됨)* 이 메서드는 이제 삽입된 파일의 :data:`xref` 를 반환합니다. 또한 파일 객체는 이제 현재 날짜-시간을 기반으로 PDF 키 `/CreationDate` 및 `/ModDate` 가 자동으로 지정됩니다.\"\n\n#: ../../document.rst:1611 f6b1d2e3c0d540b1b7de75e7fadb748e\nmsgid \"\"\n\"Changed in v1.14.16: This is now a method. In previous versions, this was\"\n\" a property.\"\nmsgstr \"v1.14.16에서 변경됨: 이것은 이제 메서드입니다. 이전 버전에서는 속성이었습니다.\"\n\n#: ../../document.rst:1613 8a7b9828613e4ae4990e91a063c9ee80\nmsgid \"PDF only: Return the number of embedded files.\"\nmsgstr \"PDF 전용: 임베디드 파일 수를 반환합니다.\"\n\n#: ../../document.rst:1617 f19dbbc33b934e2896ad5cc8de4d62b0\nmsgid \"\"\n\"PDF only: Retrieve the content of embedded file by its entry number or \"\n\"name. If the document is not a PDF, or entry cannot be found, an \"\n\"exception is raised.\"\nmsgstr \"\"\n\"PDF 전용: 항목 번호 또는 이름으로 임베디드 파일의 콘텐츠를 검색합니다. 문서가 PDF가 아니거나 항목을 찾을 수 없으면 예외가\"\n\" 발생합니다.\"\n\n#: ../../document.rst:1619 ../../document.rst:1639 ../../document.rst:1670\n#: 0c7fcd8e7e744e80937883ac86d58ec6 1c77829d63c844a48200c5355ead955c\n#: 6688417b9a8e48749073861a1ef5545b\nmsgid \"index or name of entry. An integer must be in `range(embfile_count())`.\"\nmsgstr \"항목의 인덱스 또는 이름. 정수는 `range(embfile_count())` 에 있어야 합니다.\"\n\n#: ../../document.rst:1625 d328e7c757d5492f83a65070c10ccade\nmsgid \"Changed in v1.14.16: Items can now be deleted by index, too.\"\nmsgstr \"v1.14.16에서 변경됨: 항목을 인덱스로도 삭제할 수 있습니다.\"\n\n#: ../../document.rst:1627 3e3eef03b196484388e2abce6a21542f\nmsgid \"\"\n\"PDF only: Remove an entry from `/EmbeddedFiles`. As always, physical \"\n\"deletion of the embedded file content (and file space regain) will occur \"\n\"only when the document is saved to a new file with a suitable garbage \"\n\"option.\"\nmsgstr \"\"\n\"PDF 전용: `/EmbeddedFiles` 에서 항목을 제거합니다. 항상 그렇듯이 임베디드 파일 콘텐츠의 물리적 삭제(및 파일 \"\n\"공간 회수)는 적절한 가비지 옵션으로 문서를 새 파일로 저장할 때만 발생합니다.\"\n\n#: ../../document.rst:1629 082e792e3de04b1ab322c28b8099b497\nmsgid \"index or name of entry.\"\nmsgstr \"항목의 인덱스 또는 이름.\"\n\n#: ../../document.rst:1631 68c79384328c43fba86792538c70c975\nmsgid \"\"\n\"When specifying an entry name, this function will only **delete the first\"\n\" item** with that name. Be aware that PDFs not created with PyMuPDF may \"\n\"contain duplicate names. So you may want to take appropriate precautions.\"\nmsgstr \"\"\n\"항목 이름을 지정할 때 이 함수는 해당 이름을 가진 **첫 번째 항목만 삭제** 합니다. PyMuPDF로 생성되지 않은 PDF에는 \"\n\"중복 이름이 포함될 수 있습니다. 따라서 적절한 예방 조치를 취하는 것이 좋습니다.\"\n\n#: ../../document.rst:1635 cf8233c08ead4522b85da495804c1e6e\nmsgid \"Changed in v1.18.13\"\nmsgstr \"v1.18.13에서 변경됨\"\n\n#: ../../document.rst:1637 ba9d64f33b0446c6a66e20373f94567e\nmsgid \"\"\n\"PDF only: Retrieve information of an embedded file given by its number or\"\n\" by its name.\"\nmsgstr \"PDF 전용: 번호 또는 이름으로 지정된 임베디드 파일의 정보를 검색합니다.\"\n\n#: ../../document.rst:1642 3a582798a4d5409280f2874007ce4a1d\nmsgid \"\"\n\"a dictionary with the following keys:  * ``name`` -- (*str*) name under \"\n\"which this entry is stored * ``filename`` -- (*str*) filename * \"\n\"``ufilename`` -- (*unicode*) filename * ``description`` -- (*str*) \"\n\"description * ``size`` -- (*int*) original file size * ``length`` -- \"\n\"(*int*) compressed file length * ``creationDate`` -- (*str*) date-time of\"\n\" item creation in PDF format * ``modDate`` -- (*str*) date-time of last \"\n\"change in PDF format * ``collection`` -- (*int*) :data:`xref` of the \"\n\"associated PDF portfolio item if any, else zero. * ``checksum`` -- \"\n\"(*str*) a hashcode of the stored file content as a hexadecimal string. \"\n\"Should be MD5 according to PDF specifications, but be prepared to see \"\n\"other hashing algorithms.\"\nmsgstr \"\"\n\n#: ../../document.rst:1642 d35f32e42ce94abaa0187c2a807248f8\nmsgid \"a dictionary with the following keys:\"\nmsgstr \"다음 키를 가진 딕셔너리:\"\n\n#: ../../document.rst:1644 e07b475b88d04c2f85be01b11e172b2a\nmsgid \"``name`` -- (*str*) name under which this entry is stored\"\nmsgstr \"``name`` -- (*str*) 이 항목이 저장되는 이름\"\n\n#: ../../document.rst:1645 ac0ae83d42ca4ae885a61ea6a32cee14\nmsgid \"``filename`` -- (*str*) filename\"\nmsgstr \"``filename`` -- (*str*) 파일명\"\n\n#: ../../document.rst:1646 f6f77d03d7be41ccab1e1297bbb406da\nmsgid \"``ufilename`` -- (*unicode*) filename\"\nmsgstr \"``ufilename`` -- (*unicode*) 파일명\"\n\n#: ../../document.rst:1647 2e10f2dd4b4641cd92c4d4f6cbdaaa84\nmsgid \"``description`` -- (*str*) description\"\nmsgstr \"``description`` -- (*str*) 설명\"\n\n#: ../../document.rst:1648 d99fc2985ce4404eb44a2dcac586736b\nmsgid \"``size`` -- (*int*) original file size\"\nmsgstr \"``size`` -- (*int*) 원본 파일 크기\"\n\n#: ../../document.rst:1649 0ece57be54c548e7bfe5429de67147a8\nmsgid \"``length`` -- (*int*) compressed file length\"\nmsgstr \"``length`` -- (*int*) 압축된 파일 길이\"\n\n#: ../../document.rst:1650 542e3d29e1b048f287dd894589eff4ae\nmsgid \"``creationDate`` -- (*str*) date-time of item creation in PDF format\"\nmsgstr \"``creationDate`` -- (*str*) PDF 형식의 항목 생성 날짜-시간\"\n\n#: ../../document.rst:1651 7472dc1d5e2f48a487fab93a8b23b1cb\nmsgid \"``modDate`` -- (*str*) date-time of last change in PDF format\"\nmsgstr \"``modDate`` -- (*str*) PDF 형식의 마지막 변경 날짜-시간\"\n\n#: ../../document.rst:1652 d2937c070faf4a7483f304c35c4823e5\nmsgid \"\"\n\"``collection`` -- (*int*) :data:`xref` of the associated PDF portfolio \"\n\"item if any, else zero.\"\nmsgstr \"``collection`` -- (*int*) 관련 PDF 포트폴리오 항목이 있으면 :data:`xref`, 그렇지 않으면 0.\"\n\n#: ../../document.rst:1653 445152fe6af241e8a193dbfb7712e713\nmsgid \"\"\n\"``checksum`` -- (*str*) a hashcode of the stored file content as a \"\n\"hexadecimal string. Should be MD5 according to PDF specifications, but be\"\n\" prepared to see other hashing algorithms.\"\nmsgstr \"\"\n\"``checksum`` -- (*str*) 저장된 파일 콘텐츠의 해시코드를 16진수 문자열로. PDF 사양에 따르면 MD5여야 \"\n\"하지만 다른 해싱 알고리즘을 볼 수 있도록 준비하세요.\"\n\n#: ../../document.rst:1657 487c6a0fa0aa4e508875f0aa1e988e66\nmsgid \"\"\n\"PDF only: Return a list of embedded file names. The sequence of the names\"\n\" equals the physical sequence in the document.\"\nmsgstr \"PDF 전용: 임베디드 파일 이름 목록을 반환합니다. 이름의 순서는 문서의 물리적 순서와 같습니다.\"\n\n#: ../../document.rst:1668 57edf8bf1f7d4045980a5b000df9dc96\nmsgid \"\"\n\"PDF only: Change an embedded file given its entry number or name. All \"\n\"parameters are optional. Letting them default leads to a no-operation.\"\nmsgstr \"\"\n\"PDF 전용: 항목 번호 또는 이름으로 지정된 임베디드 파일을 변경합니다. 모든 매개변수는 선택적입니다. 기본값으로 두면 작업이 \"\n\"수행되지 않습니다.\"\n\n#: ../../document.rst:1671 6796cddb078c4d7f937285345d101367\nmsgid \"\"\n\"the new file content.  *(Changed in v1.14.13)* *io.BytesIO* is now also \"\n\"supported.\"\nmsgstr \"새 파일 콘텐츠.  *(v1.14.13에서 변경됨)* *io.BytesIO* 도 이제 지원됩니다.\"\n\n#: ../../document.rst:1671 0f489bbc976d421f88323dc2c920648c\nmsgid \"the new file content.\"\nmsgstr \"새 파일 콘텐츠.\"\n\n#: ../../document.rst:1675 cbeeef5388e44bb69b3ed62d2ac39d77\nmsgid \"the new filename.\"\nmsgstr \"새 파일명.\"\n\n#: ../../document.rst:1676 47ce01e0c6374d4d817de3d942010ace\nmsgid \"the new unicode filename.\"\nmsgstr \"새 유니코드 파일명.\"\n\n#: ../../document.rst:1677 df303b0998a548c2b292678b9add1a9f\nmsgid \"the new description.\"\nmsgstr \"새 설명.\"\n\n#: ../../document.rst:1679 572fcc87be1e4d93a0f5cbff844537a2\nmsgid \"\"\n\"*(Changed in v1.18.13)*  The method now returns the :data:`xref` of the \"\n\"file object.\"\nmsgstr \"*(v1.18.13에서 변경됨)*  이 메서드는 이제 파일 객체의 :data:`xref` 를 반환합니다.\"\n\n#: ../../document.rst:1682 266208e50f2048d39743307d29c7c4fa\nmsgid \"\"\n\"xref of the file object. Automatically, its `/ModDate` PDF key will be \"\n\"updated with the current date-time.\"\nmsgstr \"파일 객체의 xref. 자동으로 `/ModDate` PDF 키가 현재 날짜-시간으로 업데이트됩니다.\"\n\n#: ../../document.rst:1687 bbec30c1104c481282c889f264d8def1\nmsgid \"\"\n\"Release objects and space allocations associated with the document. If \"\n\"created from a file, also closes *filename* (releasing control to the \"\n\"OS). Explicitly closing a document is equivalent to deleting it, `del \"\n\"doc`, or assigning it to something else like `doc = None`.\"\nmsgstr \"\"\n\"문서와 관련된 객체 및 공간 할당을 해제합니다. 파일에서 생성된 경우 *filename* 도 닫습니다(OS에 제어권 해제). 문서를\"\n\" 명시적으로 닫는 것은 삭제하는 것, `del doc`, 또는 `doc = None` 과 같이 다른 것으로 할당하는 것과 \"\n\"동일합니다.\"\n\n#: ../../document.rst:1691 ../../document.rst:1705 ../../document.rst:1712\n#: ../../document.rst:1719 ../../document.rst:1730 ../../document.rst:1739\n#: ../../document.rst:1888 247adcd852824bb58b2f946d80b664ca\n#: 39d0f5a0601d4c96817742c36b72172a 9030fef29e924c53b50ceba2911f2f80\n#: be0981e9321b41c591dd8a531ac79cd2 bec9bb1abedd486cb4490cbd68d87c61\n#: cfbb8fe0689848d6b77591b0178ee148 da6cafddda6341838772449a7a68e09a\nmsgid \"New in v1.16.8\"\nmsgstr \"v1.16.8에서 새로 추가됨\"\n\n#: ../../document.rst:1692 97583d3cb0be42099272c425aa4a8828\nmsgid \"Changed in v1.18.10\"\nmsgstr \"v1.18.10에서 변경됨\"\n\n#: ../../document.rst:1694 3a4c6876a2844008ab4933d87266a75b\nmsgid \"PDF only: Return the definition source of a PDF object.\"\nmsgstr \"PDF 전용: PDF 객체의 정의 소스를 반환합니다.\"\n\n#: ../../document.rst:1696 3efa84c9b26a4a49b7014508567c633e\nmsgid \"\"\n\"the object's :data:`xref`. *Changed in v1.18.10:* A value of `-1` returns\"\n\" the PDF trailer source.\"\nmsgstr \"객체의 :data:`xref`. *v1.18.10에서 변경됨:* `-1` 값은 PDF 트레일러 소스를 반환합니다.\"\n\n#: ../../document.rst:1697 aaf4fbe6e19f49459a59afb370e7437b\nmsgid \"whether to generate a compact output with no line breaks or spaces.\"\nmsgstr \"줄 바꿈이나 공백 없이 압축된 출력을 생성할지 여부.\"\n\n#: ../../document.rst:1698 b0596a3700284e3699129ac3d0dffb85\nmsgid \"whether to ASCII-encode binary data.\"\nmsgstr \"바이너리 데이터를 ASCII로 인코딩할지 여부.\"\n\n#: ../../document.rst:1701 527839cb652440c8b6583d8ab665ebbe\nmsgid \"The object definition source.\"\nmsgstr \"객체 정의 소스.\"\n\n#: ../../document.rst:1707 99c695fbaa8040d28c182ba8b33e3a80\nmsgid \"\"\n\"PDF only: Return the :data:`xref` number of the PDF catalog (or root) \"\n\"object. Use that number with :meth:`Document.xref_object` to see its \"\n\"source.\"\nmsgstr \"\"\n\"PDF 전용: PDF 카탈로그(또는 루트) 객체의 :data:`xref` 번호를 반환합니다. 해당 번호를 \"\n\":meth:`Document.xref_object` 와 함께 사용하여 소스를 확인하세요.\"\n\n#: ../../document.rst:1714 25496e4baa244786951e184999c6d563\nmsgid \"\"\n\"PDF only: Return the trailer source of the PDF,  which is usually located\"\n\" at the PDF file's end. This is :meth:`Document.xref_object` with an \"\n\":data:`xref` argument of -1.\"\nmsgstr \"\"\n\"PDF 전용: PDF의 트레일러 소스를 반환합니다. 일반적으로 PDF 파일의 끝에 있습니다. 이것은 :data:`xref` 인수가 \"\n\"-1인 :meth:`Document.xref_object` 입니다.\"\n\n#: ../../document.rst:1721 4774099f88fd43d6b2aff5bf066476de\nmsgid \"\"\n\"PDF only: Return the **decompressed** contents of the :data:`xref` stream\"\n\" object.\"\nmsgstr \"PDF 전용: :data:`xref` 스트림 객체의 **압축 해제된** 콘텐츠를 반환합니다.\"\n\n#: ../../document.rst:1723 ../../document.rst:1743 ../../document.rst:1762\n#: 61b36d6194a84f7080f16938dbc9891b 7476520cda4f4c27aeb545cf196b943c\n#: 9532ed01c59144319402fae983ecf5c8\nmsgid \":data:`xref` number.\"\nmsgstr \":data:`xref` 번호.\"\n\n#: ../../document.rst:1726 6fc4c5e9e2f449559aeba47da28b65f9\nmsgid \"the (decompressed) stream of the object.\"\nmsgstr \"객체의 (압축 해제된) 스트림.\"\n\n#: ../../document.rst:1732 9bc12dd4862043738d981a86c72cd4ef\nmsgid \"\"\n\"PDF only: Return the **unmodified** (esp. **not decompressed**) contents \"\n\"of the :data:`xref` stream object. Otherwise equal to \"\n\":meth:`Document.xref_stream`.\"\nmsgstr \"\"\n\"PDF 전용: :data:`xref` 스트림 객체의 **수정되지 않은** (특히 **압축 해제되지 않은**) 콘텐츠를 반환합니다. \"\n\"그렇지 않으면 :meth:`Document.xref_stream` 과 동일합니다.\"\n\n#: ../../document.rst:1735 329eab98eb8a4879a9ade3b4cfc2ba8a\nmsgid \"the (original, unmodified) stream of the object.\"\nmsgstr \"객체의 (원본, 수정되지 않은) 스트림.\"\n\n#: ../../document.rst:1741 26685fb8b9594f2db148d7e0c3346e60\nmsgid \"\"\n\"PDF only: Replace object definition of :data:`xref` with the provided \"\n\"string. The xref may also be new, in which case this instruction \"\n\"completes the object definition. If a page object is also given, its \"\n\"links and annotations will be reloaded afterwards.\"\nmsgstr \"\"\n\"PDF 전용: :data:`xref` 의 객체 정의를 제공된 문자열로 교체합니다. xref는 새 것일 수도 있으며, 이 경우 이 \"\n\"지시문이 객체 정의를 완료합니다. 페이지 객체도 제공되면 링크와 주석이 이후에 다시 로드됩니다.\"\n\n#: ../../document.rst:1745 e300685a43d14bc385137c3d5c28e8f3\nmsgid \"a string containing a valid PDF object definition.\"\nmsgstr \"유효한 PDF 객체 정의를 포함하는 문자열.\"\n\n#: ../../document.rst:1747 2b7efd4811764da09018e7cc730abba0\nmsgid \"\"\n\"a page object. If provided, indicates, that annotations of this page \"\n\"should be refreshed (reloaded) to reflect changes incurred with links and\"\n\" / or annotations.\"\nmsgstr \"\"\n\"페이지 객체. 제공되면 이 페이지의 주석이 링크 및/또는 주석으로 인한 변경 사항을 반영하도록 새로고침(다시 로드)되어야 함을 \"\n\"나타냅니다.\"\n\n#: ../../document.rst:1751 e24ddb8f85e0457d818f44d8481297fc\nmsgid \"zero if successful, otherwise an exception will be raised.\"\nmsgstr \"성공하면 0, 그렇지 않으면 예외가 발생합니다.\"\n\n#: ../../document.rst:1756 a88df4afdb3a40c4ac4c87338a6e030c\nmsgid \"New in v.1.16.8\"\nmsgstr \"v.1.16.8에서 새로 추가됨\"\n\n#: ../../document.rst:1757 65d49b625cd74c04ac3170a8db7d36c7\nmsgid \"Changed in v1.19.2: added parameter \\\"compress\\\"\"\nmsgstr \"v1.19.2에서 변경됨: 매개변수 \\\"compress\\\" 추가\"\n\n#: ../../document.rst:1758 eddb5dc06f7740ffb519cd5af8611dbe\nmsgid \"\"\n\"Changed in v1.19.6: deprecated parameter \\\"new\\\". Now confirms that the \"\n\"object is a PDF dictionary object.\"\nmsgstr \"v1.19.6에서 변경됨: 매개변수 \\\"new\\\" 사용 중단. 이제 객체가 PDF 딕셔너리 객체임을 확인합니다.\"\n\n#: ../../document.rst:1760 caaeff35c6a34794a4e9ed38fe88e1cd\nmsgid \"\"\n\"Replace the stream of an object identified by :data:`xref`, which must be\"\n\" a PDF dictionary. If the object is no :data:`stream`, it will be turned \"\n\"into one. The function automatically performs a compress operation \"\n\"(\\\"deflate\\\") where beneficial.\"\nmsgstr \"\"\n\":data:`xref` 로 식별된 객체의 스트림을 교체합니다. 이것은 PDF 딕셔너리여야 합니다. 객체가 :data:`stream`\"\n\" 이 아니면 하나로 변환됩니다. 함수는 유익한 경우 자동으로 압축 작업(\\\"deflate\\\")을 수행합니다.\"\n\n#: ../../document.rst:1764 f71966b2cb6448c58b0b7861d0b9ce0d\nmsgid \"\"\n\"the new content of the stream.  *(Changed in v1.14.13:)* *io.BytesIO* \"\n\"objects are now also supported.\"\nmsgstr \"\"\n\n#: ../../document.rst:1764 c0416641f4ba4bb1a8150bd111049103\nmsgid \"the new content of the stream.\"\nmsgstr \"스트림의 새 콘텐츠.\"\n\n#: ../../document.rst:1766 579c642b3d194151be1211256a2514fd\nmsgid \"*(Changed in v1.14.13:)* *io.BytesIO* objects are now also supported.\"\nmsgstr \"*(v1.14.13에서 변경됨:)* *io.BytesIO* 객체도 이제 지원됩니다.\"\n\n#: ../../document.rst:1768 04840a0ca2d741ee8a068ce722449b8f\nmsgid \"*deprecated* and ignored. Will be removed some time after v1.20.0.\"\nmsgstr \"*사용 중단됨* 및 무시됨. v1.20.0 이후 어느 시점에 제거됩니다.\"\n\n#: ../../document.rst:1769 76eac7eea7cf45a8b748c1df0750fa6f\nmsgid \"\"\n\"whether to compress the inserted stream. If `True` (default), the stream \"\n\"will be inserted using `/FlateDecode` compression (if beneficial), \"\n\"otherwise the stream will inserted as is.\"\nmsgstr \"\"\n\"삽입된 스트림을 압축할지 여부. `True` (기본값)인 경우 스트림은 `/FlateDecode` 압축을 사용하여 삽입됩니다(유익한\"\n\" 경우). 그렇지 않으면 스트림이 있는 그대로 삽입됩니다.\"\n\n#: ../../document.rst:1771 1c65a4a1d1784a75a4bd385360830396\nmsgid \"\"\n\"if :data:`xref` does not represent a PDF :data:`dict`. An empty \"\n\"dictionary ``<<>>`` is accepted. So if you just created the xref and want\"\n\" to give it a stream, first execute `doc.update_object(xref, \\\"<<>>\\\")`, \"\n\"and then insert the stream data with this method.\"\nmsgstr \"\"\n\":data:`xref` 가 PDF :data:`dict` 를 나타내지 않는 경우. 빈 딕셔너리 ``<<>>`` 가 허용됩니다. \"\n\"따라서 xref를 방금 생성했고 스트림을 제공하려면 먼저 `doc.update_object(xref, \\\"<<>>\\\")` 를 실행한\"\n\" 다음 이 메서드로 스트림 데이터를 삽입하세요.\"\n\n#: ../../document.rst:1773 c32751ae2d804e89acfe0c201afa2bec\nmsgid \"\"\n\"The method is primarily (but not exclusively) intended to manipulate \"\n\"streams containing PDF operator syntax (see pp. 643 of the \"\n\":ref:`AdobeManual`) as it is the case for e.g. page content streams.\"\nmsgstr \"\"\n\"이 메서드는 주로(하지만 독점적으로는 아님) PDF 연산자 구문을 포함하는 스트림을 조작하기 위한 것입니다(예: 페이지 콘텐츠 \"\n\"스트림의 경우 :ref:`AdobeManual` 643페이지 참조).\"\n\n#: ../../document.rst:1775 70e15cf836934e74b7aced0a0a9657ea\nmsgid \"\"\n\"If you update a contents stream, consider using save parameter \"\n\"*clean=True* to ensure consistency between PDF operator source and the \"\n\"object structure.\"\nmsgstr \"\"\n\"콘텐츠 스트림을 업데이트하는 경우 PDF 연산자 소스와 객체 구조 간의 일관성을 보장하기 위해 저장 매개변수 *clean=True*\"\n\" 를 사용하는 것을 고려하세요.\"\n\n#: ../../document.rst:1777 66d2dc91f9a14d18b85327a558ec101b\nmsgid \"\"\n\"Example: Let us assume that you no longer want a certain image appear on \"\n\"a page. This can be achieved by deleting the respective reference in its \"\n\"contents source(s) -- and indeed: the image will be gone after reloading \"\n\"the page. But the page's :data:`resources` object would still show the \"\n\"image as being referenced by the page. This save option will clean up any\"\n\" such mismatches.\"\nmsgstr \"\"\n\"예: 특정 이미지가 더 이상 페이지에 나타나지 않기를 원한다고 가정합니다. 이것은 콘텐츠 소스에서 해당 참조를 삭제하여 달성할 수 \"\n\"있습니다 -- 실제로: 페이지를 다시 로드한 후 이미지는 사라집니다. 하지만 페이지의 :data:`resources` 객체는 여전히\"\n\" 이미지가 페이지에서 참조되는 것으로 표시됩니다. 이 저장 옵션은 이러한 불일치를 정리합니다.\"\n\n#: ../../document.rst:1782 101a91a1231a478c9fd1eab7abcf5d90\nmsgid \"New in v1.19.5\"\nmsgstr \"v1.19.5에서 새로 추가됨\"\n\n#: ../../document.rst:1784 cf961e739e78442cb3749aa3d173aa55\nmsgid \"\"\n\"PDF Only: Make ``target`` xref an exact copy of ``source``. If ``source``\"\n\" is a :data:`stream`, then this data is also copied.\"\nmsgstr \"\"\n\"PDF 전용: ``target`` xref를 ``source`` 의 정확한 복사본으로 만듭니다. ``source`` 가 \"\n\":data:`stream` 인 경우 이 데이터도 복사됩니다.\"\n\n#: ../../document.rst:1786 fd753c7c6c994eeb9bc0ec1cdc4bad1d\nmsgid \"the source :data:`xref`. It must be an existing **dictionary** object.\"\nmsgstr \"소스 :data:`xref`. 기존 **딕셔너리** 객체여야 합니다.\"\n\n#: ../../document.rst:1787 18a7800d73384701aad4a34df34bdc06\nmsgid \"\"\n\"the target xref. Must be an existing **dictionary** object. If the xref \"\n\"has just been created, make sure to initialize it as a PDF dictionary \"\n\"with the minimum specification ``<<>>``.\"\nmsgstr \"\"\n\"대상 xref. 기존 **딕셔너리** 객체여야 합니다. xref가 방금 생성된 경우 최소 사양 ``<<>>`` 로 PDF 딕셔너리로\"\n\" 초기화해야 합니다.\"\n\n#: ../../document.rst:1788 cbf0113ba5074e96904620888f4d4e9f\nmsgid \"\"\n\"an optional list of top-level keys in ``target``, that should not be \"\n\"removed in preparation of the copy process.\"\nmsgstr \"복사 프로세스 준비에서 제거되지 않아야 하는 ``target`` 의 최상위 키 선택적 목록.\"\n\n#: ../../document.rst:1792 46b874ab362c4632a7c39375f9efd612\nmsgid \"This method has much in common with Python's *dict* method `copy()`.\"\nmsgstr \"이 메서드는 Python의 *dict* 메서드 `copy()` 와 많은 공통점이 있습니다.\"\n\n#: ../../document.rst:1793 8a33e87774c04f4ea90f5a5c2b58ce5c\nmsgid \"Both xref numbers must represent existing dictionaries.\"\nmsgstr \"두 xref 번호 모두 기존 딕셔너리를 나타내야 합니다.\"\n\n#: ../../document.rst:1794 d884bd5a35df416abe1dfbc33fe26bee\nmsgid \"\"\n\"Before data is copied from *source*, all *target* dictionary keys are \"\n\"deleted. You can specify exceptions from this in the ``keep`` list. If \"\n\"*source* however has a same-named key, its value will still replace the \"\n\"target.\"\nmsgstr \"\"\n\"*source* 에서 데이터가 복사되기 전에 모든 *target* 딕셔너리 키가 삭제됩니다. ``keep`` 목록에서 예외를 지정할\"\n\" 수 있습니다. 그러나 *source* 에 동일한 이름의 키가 있으면 해당 값이 여전히 대상을 교체합니다.\"\n\n#: ../../document.rst:1795 c32a67a043794307be9bb3c0035c2912\nmsgid \"\"\n\"If ``source`` is a :data:`stream` object, then these data will also be \"\n\"copied over, and ``target`` will be converted to a stream object.\"\nmsgstr \"``source`` 가 :data:`stream` 객체인 경우 이 데이터도 복사되고 ``target`` 은 스트림 객체로 변환됩니다.\"\n\n#: ../../document.rst:1796 5b21ae7a30e54f9ca542bf49a4e969e7\nmsgid \"\"\n\"A typical use case is to replace or remove an existing image without \"\n\"using redaction annotations. Example scripts can be seen `in this PyMuPDF\"\n\" Utilities example <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/examples/replace-image>`_.\"\nmsgstr \"\"\n\"일반적인 사용 사례는 수정 주석을 사용하지 않고 기존 이미지를 교체하거나 제거하는 것입니다. 예제 스크립트는 `이 PyMuPDF \"\n\"Utilities 예제 <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/examples/replace-image>`_ 에서 볼 수 있습니다.\"\n\n#: ../../document.rst:1800 1c92b07b6ad24acdbc3e9de705ca6bea\nmsgid \"\"\n\"PDF Only: Extract data and meta information of an image stored in the \"\n\"document. The output can directly be used to be stored as an image file, \"\n\"as input for PIL, :ref:`Pixmap` creation, etc. This method avoids using \"\n\"pixmaps wherever possible to present the image in its original format \"\n\"(e.g. as JPEG).\"\nmsgstr \"\"\n\"PDF 전용: 문서에 저장된 이미지의 데이터 및 메타 정보를 추출합니다. 출력은 이미지 파일로 저장하거나 PIL, \"\n\":ref:`Pixmap` 생성 등의 입력으로 직접 사용할 수 있습니다. 이 메서드는 가능한 한 pixmap 사용을 피하여 원본 \"\n\"형식(예: JPEG)으로 이미지를 표시합니다.\"\n\n#: ../../document.rst:1802 6f93bf4e0d6940f9b39148633ccb02b8\nmsgid \"\"\n\":data:`xref` of an image object. If this is not in `range(1, \"\n\"doc.xref_length())`, or the object is no image or other errors occur, \"\n\"`None` is returned and no exception is raised.\"\nmsgstr \"\"\n\"이미지 객체의 :data:`xref`. 이것이 `range(1, doc.xref_length())` 에 없거나 객체가 이미지가 \"\n\"아니거나 다른 오류가 발생하면 `None` 이 반환되고 예외가 발생하지 않습니다.\"\n\n#: ../../document.rst:1805 da816c3d1bbd4aa08e6d2b71245c5339\nmsgid \"\"\n\"a dictionary with the following keys  * *ext* (*str*) image type (e.g. \"\n\"*'jpeg'*), usable as image file extension * *smask* (*int*) :data:`xref` \"\n\"number of a stencil (/SMask) image or zero * ``width`` (*int*) image \"\n\"width * ``height`` (*int*) image height * *colorspace* (*int*) the \"\n\"image's *colorspace.n* number. * *cs-name* (*str*) the image's \"\n\"*colorspace.name*. * *xres* (*int*) resolution in x direction. Please \"\n\"also see :data:`resolution`. * *yres* (*int*) resolution in y direction. \"\n\"Please also see :data:`resolution`. * *image* (*bytes*) image data, \"\n\"usable as image file content\"\nmsgstr \"\"\n\n#: ../../document.rst:1805 ef447359490d4e5c91399ec554127f12\nmsgid \"a dictionary with the following keys\"\nmsgstr \"다음 키를 가진 딕셔너리\"\n\n#: ../../document.rst:1807 2fd5ae6c09e841e9a37e9f7d00594fcc\nmsgid \"*ext* (*str*) image type (e.g. *'jpeg'*), usable as image file extension\"\nmsgstr \"*ext* (*str*) 이미지 타입(예: *'jpeg'*), 이미지 파일 확장자로 사용 가능\"\n\n#: ../../document.rst:1808 402f7ddd2b5942e7810d7db81101f1bf\nmsgid \"*smask* (*int*) :data:`xref` number of a stencil (/SMask) image or zero\"\nmsgstr \"*smask* (*int*) 스텐실(/SMask) 이미지의 :data:`xref` 번호 또는 0\"\n\n#: ../../document.rst:1809 b4db1fa6c02c4c8b80b28aa8624cf4e0\nmsgid \"``width`` (*int*) image width\"\nmsgstr \"``width`` (*int*) 이미지 너비\"\n\n#: ../../document.rst:1810 f7b7383e8f814a7194b652803c9845a2\nmsgid \"``height`` (*int*) image height\"\nmsgstr \"``height`` (*int*) 이미지 높이\"\n\n#: ../../document.rst:1811 9e360b497ea1447daa86fdd4699adf13\nmsgid \"*colorspace* (*int*) the image's *colorspace.n* number.\"\nmsgstr \"*colorspace* (*int*) 이미지의 *colorspace.n* 번호.\"\n\n#: ../../document.rst:1812 abc5b215c0e6488e8744dcacf7a1c90e\nmsgid \"*cs-name* (*str*) the image's *colorspace.name*.\"\nmsgstr \"\"\n\n#: ../../document.rst:1813 458f54a3d150486db1d2170b249014f4\nmsgid \"\"\n\"*xres* (*int*) resolution in x direction. Please also see \"\n\":data:`resolution`.\"\nmsgstr \"\"\n\n#: ../../document.rst:1814 348d1155299f44ba94d846f7a65184e9\nmsgid \"\"\n\"*yres* (*int*) resolution in y direction. Please also see \"\n\":data:`resolution`.\"\nmsgstr \"\"\n\n#: ../../document.rst:1815 acf6f71949524192988704580634da36\nmsgid \"*image* (*bytes*) image data, usable as image file content\"\nmsgstr \"*image* (*bytes*) 이미지 파일 콘텐츠로 사용 가능한 이미지 데이터\"\n\n#: ../../document.rst:1827 446e0551034642d5ab3cb8ab7b4ad447\nmsgid \"\"\n\"There is a functional overlap with *pix = pymupdf.Pixmap(doc, xref)*, \"\n\"followed by a *pix.tobytes()*. Main differences are that extract_image, \"\n\"**(1)** does not always deliver PNG image formats, **(2)** is **very** \"\n\"much faster with non-PNG images, **(3)** usually results in much less \"\n\"disk storage for extracted images, **(4)** returns `None` in error cases \"\n\"(generates no exception). Look at the following example images within the\"\n\" same PDF.\"\nmsgstr \"\"\n\"*pix = pymupdf.Pixmap(doc, xref)* 다음에 *pix.tobytes()* 를 사용하는 것과 기능적으로 겹칩니다. 주요 차이점은 extract_image가 \"\n\"**(1)** 항상 PNG 이미지 형식을 제공하지 않으며, **(2)** 비 PNG 이미지에서 **매우** 빠르고, **(3)** 추출된 이미지에 대해 \"\n\"일반적으로 훨씬 적은 디스크 저장 공간을 사용하며, **(4)** 오류 경우에 `None` 을 반환한다는 것입니다(예외를 생성하지 않음). 동일한 PDF 내의 \"\n\"다음 예제 이미지를 참조하세요.\"\n\n#: ../../document.rst:1829 a8bc35850faa4346bb55fc7684776232\nmsgid \"xref 1268 is a PNG -- Comparable execution time and identical output::\"\nmsgstr \"xref 1268은 PNG입니다 -- 비교 가능한 실행 시간 및 동일한 출력::\"\n\n#: ../../document.rst:1841 867df59d1f90424092d7c31b14755ab5\nmsgid \"\"\n\"xref 1186 is a JPEG -- :meth:`Document.extract_image` is **many times \"\n\"faster** and produces a **much smaller** output (2.48 MB vs. 0.35 MB)::\"\nmsgstr \"\"\n\"xref 1186은 JPEG입니다 -- :meth:`Document.extract_image` 는 **여러 배 빠르며** **훨씬 작은** 출력을 생성합니다(2.48 MB vs. 0.35 MB)::\"\n\n#: ../../document.rst:1856 e236c029a3ea49058156a22bdd86f213\nmsgid \"Changed in v1.19.4: return a dictionary if `named == True`.\"\nmsgstr \"v1.19.4에서 변경됨: `named == True` 이면 딕셔너리를 반환합니다.\"\n\n#: ../../document.rst:1858 20899e634db84dc9930c742969c15306\nmsgid \"\"\n\"PDF Only: Return an embedded font file's data and appropriate file \"\n\"extension. This can be used to store the font as an external file. The \"\n\"method does not throw exceptions (other than via checking for PDF and \"\n\"valid :data:`xref`).\"\nmsgstr \"\"\n\"PDF 전용: 임베디드 폰트 파일의 데이터와 적절한 파일 확장자를 반환합니다. 이것은 폰트를 외부 파일로 저장하는 데 사용할 수 있습니다. 이 \"\n\"메서드는 예외를 발생시키지 않습니다(PDF 및 유효한 :data:`xref` 확인을 통한 경우 제외).\"\n\n#: ../../document.rst:1860 d7c4c48a28a9455680ecffcf20495b1c\nmsgid \"PDF object number of the font to extract.\"\nmsgstr \"추출할 폰트의 PDF 객체 번호.\"\n\n#: ../../document.rst:1861 77c4185b821f4d71a7dee301908b579b\nmsgid \"\"\n\"only return font information, not the buffer. To be used for information-\"\n\"only purposes, avoids allocation of large buffer areas.\"\nmsgstr \"\"\n\"버퍼가 아닌 폰트 정보만 반환합니다. 정보 전용 목적으로 사용되며, 큰 버퍼 영역 할당을 피합니다.\"\n\n#: ../../document.rst:1862 923895cfb0bf425c8677eed1f5f9a100\nmsgid \"\"\n\"If true, a dictionary with the following keys is returned: 'name' (font \"\n\"base name), 'ext' (font file extension), 'type' (font type), 'content' \"\n\"(font file content).\"\nmsgstr \"\"\n\"true인 경우 다음 키를 가진 딕셔너리가 반환됩니다: 'name'(폰트 기본 이름), 'ext'(폰트 파일 확장자), 'type'(폰트 타입), 'content'(폰트 파일 내용).\"\n\n#: ../../document.rst:1865 d8c2131db2594d699ecf78d17fc1db47\nmsgid \"\"\n\"a tuple `(basename, ext, type, content)`, where *ext* is a 3-byte \"\n\"suggested file extension (*str*), *basename* is the font's name (*str*), \"\n\"*type* is the font's type (e.g. \\\"Type1\\\") and *content* is a bytes \"\n\"object containing the font file's content (or *b\\\"\\\"*). For possible \"\n\"extension values and their meaning see :ref:`FontExtensions`. Return \"\n\"details on error:  * `(\\\"\\\", \\\"\\\", \\\"\\\", b\\\"\\\")` -- invalid xref or xref \"\n\"is not a (valid) font object. * `(basename, \\\"n/a\\\", \\\"Type1\\\", b\\\"\\\")` \"\n\"-- *basename* is not embedded and thus cannot be extracted. This is the \"\n\"case for e.g. the :ref:`Base-14-Fonts` and Type 3 fonts.\"\nmsgstr \"\"\n\n#: ../../document.rst:1865 4b10129dd3f94faabfbdc2cf2806ae66\nmsgid \"\"\n\"a tuple `(basename, ext, type, content)`, where *ext* is a 3-byte \"\n\"suggested file extension (*str*), *basename* is the font's name (*str*), \"\n\"*type* is the font's type (e.g. \\\"Type1\\\") and *content* is a bytes \"\n\"object containing the font file's content (or *b\\\"\\\"*). For possible \"\n\"extension values and their meaning see :ref:`FontExtensions`. Return \"\n\"details on error:\"\nmsgstr \"\"\n\"튜플 `(basename, ext, type, content)` 로, 여기서 *ext* 는 3바이트 제안 파일 확장자(*str*), *basename* 는 폰트 이름(*str*), \"\n\"*type* 는 폰트 타입(예: \\\"Type1\\\"), *content* 는 폰트 파일 내용(또는 *b\\\"\\\"*)을 포함하는 bytes 객체입니다. 가능한 \"\n\"확장자 값과 의미는 :ref:`FontExtensions` 를 참조하세요. 오류 시 반환 세부 사항:\"\n\n#: ../../document.rst:1867 d0cf0693516747a0926d8c334fbf3b49\nmsgid \"\"\n\"`(\\\"\\\", \\\"\\\", \\\"\\\", b\\\"\\\")` -- invalid xref or xref is not a (valid) font\"\n\" object.\"\nmsgstr \"\"\n\"`(\\\"\\\", \\\"\\\", \\\"\\\", b\\\"\\\")` -- 유효하지 않은 xref 또는 xref가 (유효한) 폰트 객체가 아님.\"\n\n#: ../../document.rst:1868 ccf11cf787d44c158c7b4125324789cc\nmsgid \"\"\n\"`(basename, \\\"n/a\\\", \\\"Type1\\\", b\\\"\\\")` -- *basename* is not embedded and\"\n\" thus cannot be extracted. This is the case for e.g. the \"\n\":ref:`Base-14-Fonts` and Type 3 fonts.\"\nmsgstr \"\"\n\"`(basename, \\\"n/a\\\", \\\"Type1\\\", b\\\"\\\")` -- *basename* 이 임베디드되지 않아 추출할 수 없음. 예를 들어 \"\n\":ref:`Base-14-Fonts` 및 Type 3 폰트의 경우입니다.\"\n\n#: ../../document.rst:1870 a82028b2f0544a189cb8c0f7b5c3cc92\nmsgid \"Example:\"\nmsgstr \"예제:\"\n\n#: ../../document.rst:1879 7435e3ad508d4986a5f8845543e7e0df\nmsgid \"\"\n\"The basename is returned unchanged from the PDF. So it may contain \"\n\"characters (such as blanks) which may disqualify it as a filename for \"\n\"your operating system. Take appropriate action.\"\nmsgstr \"\"\n\"basename은 PDF에서 변경되지 않은 채로 반환됩니다. 따라서 운영 체제의 파일명으로 사용하기에 부적합한 문자(예: 공백)가 포함될 수 있습니다. 적절한 조치를 취하세요.\"\n\n#: ../../document.rst:1882 35897c9f8dc5431792eeabe5cfe081ed\nmsgid \"\"\n\"The returned *basename* in general is **not** the original file name, but\"\n\" it probably has some similarity.\"\nmsgstr \"\"\n\"반환된 *basename* 은 일반적으로 원본 파일 이름이 **아니지만** 일부 유사성이 있을 수 있습니다.\"\n\n#: ../../document.rst:1883 576b38dabe894ac781dc4e26c56c5fbc\n#, python-brace-format\nmsgid \"\"\n\"If parameter `named == True`, a dictionary with the following keys is \"\n\"returned: `{'name': 'T1', 'ext': 'n/a', 'type': 'Type3', 'content': \"\n\"b''}`.\"\nmsgstr \"\"\n\"매개변수 `named == True` 인 경우 다음 키를 가진 딕셔너리가 반환됩니다: `{'name': 'T1', 'ext': 'n/a', 'type': 'Type3', 'content': \"\n\"b''}`.\"\n\n#: ../../document.rst:1890 cfbc337f74774c9e873b301a3cadb5af\nmsgid \"PDF only: Return the :data:`xref` of the document's XML metadata.\"\nmsgstr \"PDF 전용: 문서의 XML 메타데이터의 :data:`xref` 를 반환합니다.\"\n\n#: ../../document.rst:1899 0e955bcdf14d4dbcb8657f98cd3631f4\nmsgid \"\"\n\"PDF only: Check whether there are links, resp. annotations anywhere in \"\n\"the document.\"\nmsgstr \"\"\n\"PDF 전용: 문서 어디에든 링크 또는 주석이 있는지 확인합니다.\"\n\n#: ../../document.rst:1901 ddc5e688329046928b55eaea1db04902\nmsgid \"\"\n\"``True`` / ``False``. As opposed to fields, which are also stored in a \"\n\"central place of a PDF document, the existence of links / annotations can\"\n\" only be detected by parsing each page. These methods are tuned to do \"\n\"this efficiently and will immediately return, if the answer is ``True`` \"\n\"for a page. For PDFs with many thousand pages however, an answer may take\"\n\" some time [#f6]_ if no link, resp. no annotation is found.\"\nmsgstr \"\"\n\"``True`` / ``False``. PDF 문서의 중앙 위치에 저장되는 필드와 달리, 링크/주석의 존재는 각 페이지를 구문 분석해야만 감지할 수 있습니다. \"\n\"이 메서드들은 이를 효율적으로 수행하도록 조정되었으며, 페이지에 대한 답변이 ``True`` 이면 즉시 반환합니다. 그러나 수천 페이지가 있는 PDF의 경우, \"\n\"링크 또는 주석이 발견되지 않으면 답변에 시간이 걸릴 수 있습니다 [#f6]_.\"\n\n#: ../../document.rst:1906 ca08446597a942dfb0c8419c0295e50b\nmsgid \"\"\n\"PDF only: Investigate eligible fonts for their use by text in the \"\n\"document. If a font is supported and a size reduction is possible, that \"\n\"font is replaced by a version with a subset of its characters.\"\nmsgstr \"\"\n\"PDF 전용: 문서의 텍스트에서 사용되는 적격 폰트를 조사합니다. 폰트가 지원되고 크기 축소가 가능한 경우, 해당 폰트는 문자 서브셋을 가진 버전으로 대체됩니다.\"\n\n#: ../../document.rst:1908 0a1f089883924faa89e7e8840f138d99\nmsgid \"Use this method immediately before saving the document.\"\nmsgstr \"문서를 저장하기 직전에 이 메서드를 사용하세요.\"\n\n#: ../../document.rst:1910 8000c8e5ca0e4393b5619405bc73211d\nmsgid \"\"\n\"write various progress information to sysout. This currently only has an \"\n\"effect if `fallback` is `True`.\"\nmsgstr \"\"\n\"다양한 진행 정보를 sysout에 기록합니다. 현재는 `fallback` 이 `True` 인 경우에만 효과가 있습니다.\"\n\n#: ../../document.rst:1911 125f3a0b0abe4f5395592a60330670e0\nmsgid \"\"\n\"if `True` use the deprecated algorithm that makes use of package \"\n\"`fontTools <https://pypi.org/project/fonttools/>`_ (which hence must be \"\n\"installed). If using the recommended value `False` (default), MuPDF's \"\n\"native function is used -- which is **very much faster** and can subset a\"\n\" broader range of font types. Package fontTools is not required then.\"\nmsgstr \"\"\n\"`True` 인 경우 패키지 `fontTools <https://pypi.org/project/fonttools/>`_ 를 사용하는 더 이상 사용되지 않는 알고리즘을 사용합니다(따라서 설치되어 있어야 함). 권장 값 `False` (기본값)를 사용하는 경우 MuPDF의 네이티브 함수가 사용됩니다 -- 이것은 **훨씬 빠르며** 더 넓은 범위의 폰트 타입을 서브셋할 수 있습니다. 이 경우 fontTools 패키지가 필요하지 않습니다.\"\n\n#: ../../document.rst:1913 00bacf13890641b88f6f1ad99aff3a06\nmsgid \"\"\n\"The greatest benefit can be achieved when creating new PDFs using large \"\n\"fonts like is typical for Asian scripts. When using the :ref:`Story` \"\n\"class or method :meth:`Page.insert_htmlbox`, multiple fonts may \"\n\"automatically be included -- without the programmer becoming aware of it.\"\nmsgstr \"\"\n\"아시아 스크립트에 일반적인 것처럼 큰 폰트를 사용하여 새 PDF를 생성할 때 가장 큰 이점을 얻을 수 있습니다. :ref:`Story` 클래스 또는 \"\n\":meth:`Page.insert_htmlbox` 메서드를 사용할 때 여러 폰트가 자동으로 포함될 수 있습니다 -- 프로그래머가 인지하지 못한 채로.\"\n\n#: ../../document.rst:1915 d006a2c3965b4769813d244db91fd2e1\nmsgid \"\"\n\"In all these cases, the set of actually used unicodes mostly is very \"\n\"small compared to the number of glyphs available in the used fonts. Using\"\n\" this method can easily reduce the embedded font binaries by two orders \"\n\"of magnitude -- from several megabytes down to a low two-digit kilobyte \"\n\"amount.\"\nmsgstr \"\"\n\"이러한 모든 경우에서 실제로 사용되는 유니코드 집합은 사용된 폰트에서 사용 가능한 글리프 수에 비해 대부분 매우 작습니다. 이 \"\n\"메서드를 사용하면 임베디드 폰트 바이너리를 두 자릿수 크기로 쉽게 줄일 수 있습니다 -- 수 메가바이트에서 낮은 두 자릿수 킬로바이트 \"\n\"양으로.\"\n\n#: ../../document.rst:1917 b2b33791b196412e97c3bd6e588482ab\nmsgid \"\"\n\"Creating font subsets leaves behind a large number of large, now unused \"\n\"PDF objects (\\\"ghosts\\\"). Therefore, make sure to compress and garbage-\"\n\"collect when saving the file. We recommend to use \"\n\":meth:`Document.ez_save`.\"\nmsgstr \"\"\n\"폰트 서브셋을 만들면 많은 수의 큰, 이제 사용되지 않는 PDF 객체(\\\"고스트\\\")가 남습니다. 따라서 파일을 저장할 때 압축 및\"\n\" 가비지 수집을 수행하세요. :meth:`Document.ez_save` 사용을 권장합니다.\"\n\n#: ../../document.rst:1919 328408f7e8dd4fa7bfd094bfd96b99e3\nmsgid \"|history_begin|\"\nmsgstr \"|history_begin|\"\n\n#: ../../document.rst:1922 798460dece6a4ad7886988b394a392f5\nmsgid \"Changed in v1.18.9\"\nmsgstr \"v1.18.9에서 변경됨\"\n\n#: ../../document.rst:1923 ffb32b88708c47bc9a917650930b7177\nmsgid \"Changed in v1.24.2 use native function of MuPDF.\"\nmsgstr \"v1.24.2에서 변경됨: MuPDF의 네이티브 함수 사용.\"\n\n#: ../../document.rst:1925 8a922608125342a7a0fe043997b5731e\nmsgid \"|history_end|\"\nmsgstr \"|history_end|\"\n\n#: ../../document.rst:1930 ../../document.rst:1936 ../../document.rst:1943\n#: ../../document.rst:1950 ../../document.rst:1959 ../../document.rst:1966\n#: ../../document.rst:1975 ../../document.rst:1982 ../../document.rst:1989\n#: ../../document.rst:1998 ../../document.rst:2007\n#: 2a53866190fe49559ea59107b2ab1ed6 70e42b1a98334fe9afab934648d37034\n#: 84ed6cfe188e451ea6f51ecbffac4e7c 917af123d7974a3c8f94f8f458b3e7ce\n#: 91d2e3633a1041c8a9ecce6b3586bd37 bcbe3a3d5ae54bf2a3ae7b756710592a\n#: c5666e0424794a9e82f95bec34fa5e5f ccf2561788a34c0ca38f05ccaf1e22fb\n#: d2fd99018af4450c8ddff8e687633ae0 e919e0a4ef3f4060b9740167dd44e394\n#: f353da33d40e46b5ac39ddff1425ba1c\nmsgid \"New in v1.19.0\"\nmsgstr \"v1.19.0에서 새로 추가됨\"\n\n#: ../../document.rst:1932 6ee29bc23b4d48a79a8c43170676e1eb\nmsgid \"\"\n\"PDF only: Enable journalling. Use this before you start logging \"\n\"operations.\"\nmsgstr \"PDF 전용: 저널링을 활성화합니다. 로깅 작업을 시작하기 전에 이것을 사용하세요.\"\n\n#: ../../document.rst:1938 7d210c47aaa9496797b08af90a645eed\nmsgid \"\"\n\"PDF only: Start journalling an *\\\"operation\\\"* identified by a string \"\n\"\\\"name\\\". Updates will fail for a journal-enabled PDF, if no operation \"\n\"has been started.\"\nmsgstr \"\"\n\"PDF 전용: 문자열 \\\"name\\\" 으로 식별되는 *\\\"작업\\\"* 의 저널링을 시작합니다. 작업이 시작되지 않으면 저널이 활성화된\"\n\" PDF에 대한 업데이트가 실패합니다.\"\n\n#: ../../document.rst:1945 66626f215b2042f59d57c01bc5bc9d9c\nmsgid \"\"\n\"PDF only: Stop the current operation. The updates between start and stop \"\n\"of an operation belong to the same unit of work and will be undone / \"\n\"redone together.\"\nmsgstr \"\"\n\"PDF 전용: 현재 작업을 중지합니다. 작업의 시작과 중지 사이의 업데이트는 동일한 작업 단위에 속하며 함께 실행 취소/다시 \"\n\"실행됩니다.\"\n\n#: ../../document.rst:1952 1a9a7a8aa18c4fe18b9dc769ee6af41b\nmsgid \"\"\n\"PDF only: Return the numbers of the current operation and the total \"\n\"operation count.\"\nmsgstr \"PDF 전용: 현재 작업 번호와 총 작업 수를 반환합니다.\"\n\n#: ../../document.rst:1954 a68f9e659a834894b7ae26a288e36c6a\nmsgid \"\"\n\"a tuple `(step, steps)` containing the current operation number and the \"\n\"total number of operations in the journal. If **step** is 0, we are at \"\n\"the top of the journal. If **step** equals **steps**, we are at the \"\n\"bottom. Updating the PDF with anything other than undo or redo will \"\n\"automatically remove all journal entries after the current one and the \"\n\"new update will become the new last entry in the journal. The updates \"\n\"corresponding to the removed journal entries will be permanently lost.\"\nmsgstr \"\"\n\"현재 작업 번호와 저널의 총 작업 수를 포함하는 튜플 `(step, steps)`. **step** 이 0이면 저널의 맨 위에 \"\n\"있습니다. **step** 이 **steps** 와 같으면 맨 아래에 있습니다. 실행 취소 또는 다시 실행 이외의 것으로 PDF를 \"\n\"업데이트하면 현재 항목 이후의 모든 저널 항목이 자동으로 제거되고 새 업데이트가 저널의 새 마지막 항목이 됩니다. 제거된 저널 \"\n\"항목에 해당하는 업데이트는 영구적으로 손실됩니다.\"\n\n#: ../../document.rst:1961 70b630f906a14f6ba6e8d2f1b63d80bb\nmsgid \"PDF only: Return the name of operation number *step.*\"\nmsgstr \"PDF 전용: 작업 번호 *step.* 의 이름을 반환합니다.\"\n\n#: ../../document.rst:1968 c18d1d246dd349ab8f2fae9bdbcd7f6a\nmsgid \"\"\n\"PDF only: Show whether forward (\\\"redo\\\") and / or backward (\\\"undo\\\") \"\n\"executions are possible from the current journal position.\"\nmsgstr \"PDF 전용: 현재 저널 위치에서 앞으로(\\\"redo\\\") 및/또는 뒤로(\\\"undo\\\") 실행이 가능한지 표시합니다.\"\n\n#: ../../document.rst:1970 026f194ecdb44484a5a846457b3bebec\n#, python-brace-format\nmsgid \"\"\n\"a dictionary `{\\\"undo\\\": bool, \\\"redo\\\": bool}`. The respective method is\"\n\" available if its value is `True`.\"\nmsgstr \"\"\n\"딕셔너리 `{\\\"undo\\\": bool, \\\"redo\\\": bool}`. 해당 메서드는 값이 `True` 인 경우 사용할 수 \"\n\"있습니다.\"\n\n#: ../../document.rst:1977 2a24feb018f8432f91aee80e633040d5\nmsgid \"\"\n\"PDF only: Revert (undo) the current step in the journal. This moves \"\n\"towards the journal's top.\"\nmsgstr \"PDF 전용: 저널의 현재 단계를 되돌립니다(실행 취소). 이것은 저널의 맨 위로 이동합니다.\"\n\n#: ../../document.rst:1984 b8f7aceb49744cb2bb1844ac639ad01c\nmsgid \"\"\n\"PDF only: Re-apply (redo) the current step in the journal. This moves \"\n\"towards the journal's bottom.\"\nmsgstr \"PDF 전용: 저널의 현재 단계를 다시 적용합니다(다시 실행). 이것은 저널의 맨 아래로 이동합니다.\"\n\n#: ../../document.rst:1991 f05f714420554ee9bee4aaf8a9fb46fa\nmsgid \"PDF only: Save the journal to a file.\"\nmsgstr \"PDF 전용: 저널을 파일로 저장합니다.\"\n\n#: ../../document.rst:1993 b9888536d6c84d89852aab0d7219a4d4\nmsgid \"\"\n\"either a filename as string or a file object opened as \\\"wb\\\" (or an \"\n\"`io.BytesIO()` object).\"\nmsgstr \"문자열로 된 파일명 또는 \\\"wb\\\" 로 열린 파일 객체(또는 `io.BytesIO()` 객체).\"\n\n#: ../../document.rst:2000 0c0590abc65e46cda73b5408c9144c3e\nmsgid \"\"\n\"PDF only: Load journal from a file. Enables journalling for the document.\"\n\" If journalling is already enabled, an exception is raised.\"\nmsgstr \"PDF 전용: 파일에서 저널을 로드합니다. 문서에 대한 저널링을 활성화합니다. 저널링이 이미 활성화된 경우 예외가 발생합니다.\"\n\n#: ../../document.rst:2002 ae156f5f2acd4bb6a7052525c9245004\nmsgid \"\"\n\"the filename (str) of the journal or a file object opened as \\\"rb\\\" (or \"\n\"an `io.BytesIO()` object).\"\nmsgstr \"저널의 파일명(str) 또는 \\\"rb\\\" 로 열린 파일 객체(또는 `io.BytesIO()` 객체).\"\n\n#: ../../document.rst:2009 5f940a3e7e834d4bb229807f2f31c126\nmsgid \"\"\n\"PDF only: Saves a \\\"snapshot\\\" of the document. This is a PDF document \"\n\"with a special, incremental-save format compatible with journalling -- \"\n\"therefore no save options are available. Saving a snapshot is not \"\n\"possible for new documents.\"\nmsgstr \"\"\n\"PDF 전용: 문서의 \\\"스냅샷\\\"을 저장합니다. 이것은 저널링과 호환되는 특수한 증분 저장 형식의 PDF 문서입니다 -- 따라서 \"\n\"저장 옵션을 사용할 수 없습니다. 새 문서의 경우 스냅샷 저장이 불가능합니다.\"\n\n#: ../../document.rst:2011 f586116e945545b1a4cad6f484605631\nmsgid \"\"\n\"This is a normal PDF document with no usage restrictions whatsoever. If \"\n\"it is not being changed in any way, it can be used together with its \"\n\"journal to undo / redo operations or continue updating.\"\nmsgstr \"\"\n\"이것은 사용 제한이 전혀 없는 일반 PDF 문서입니다. 어떤 방식으로도 변경되지 않는 경우 저널과 함께 사용하여 작업을 실행 \"\n\"취소/다시 실행하거나 업데이트를 계속할 수 있습니다.\"\n\n#: ../../document.rst:2016 f752b2d996c14e0b8a78c71a0f90f84b\nmsgid \"\"\n\"Contains the first :ref:`Outline` entry of the document (or `None`). Can \"\n\"be used as a starting point to walk through all outline items. Accessing \"\n\"this property for encrypted, not authenticated documents will raise an \"\n\"*AttributeError*.\"\nmsgstr \"\"\n\"문서의 첫 번째 :ref:`Outline` 항목(또는 `None`)을 포함합니다. 모든 개요 항목을 순회하는 시작점으로 사용할 수 \"\n\"있습니다. 암호화되었지만 인증되지 않은 문서에 대해 이 속성에 액세스하면 *AttributeError* 가 발생합니다.\"\n\n#: ../../document.rst 00995fa57979497dadc4c05245df531b\n#: 043530a05a4a4547a0fd3a3dd8ad4a0e 0d7830ff904d4136bd22268be51826f7\n#: 24bacb47a3b845ae9f78d935aaef2dbc 345e810f6046480f9403b08f9f4bcefd\n#: 74e3b6ce6dca44149b9d29443c932045 925d12c293744eff9d30dec6c94968ef\n#: 928860903ad84395aeb563464aa7fa33 95ee7c0c91eb470085cf7a7402a5aca6\n#: 9d01a444f38e4b8fa769e04408682bfa a81724fa96ce4c59904551cc1647204a\n#: b870075b72ee484a8667be1b1f4340cb bed92752ce3a4fd0b268157d0d9196d4\n#: c2b8f936790f45f8a293db8ea34ee5e3 cbcd66fd660f48c98c9982ab8bbea7d2\n#: cfe8e8750ff14e1686c002553098556d d12fbf5f89594bfc97e8aba7e8e002b3\n#: d905df47a8264daa82f71bd16750bae3 d9132afe09b24ff2a3957f60049d362b\n#: e60554c94b2444189ed5a481cec24a26 eb2f0663adb94352b5a04ed93ef624bc\nmsgid \"type\"\nmsgstr \"타입\"\n\n#: ../../document.rst:2018 0a1d5db8723b42fb85c316466e7ffb91\nmsgid \":ref:`Outline`\"\nmsgstr \":ref:`Outline`\"\n\n#: ../../document.rst:2022 3b1a44d3b897441ebdf4f10b248f9a22\nmsgid \"\"\n\"``False`` if document is still open. If closed, most other attributes and\"\n\" methods will have been deleted / disabled. In addition, :ref:`Page` \"\n\"objects referring to this document (i.e. created with \"\n\":meth:`Document.load_page`) and their dependent objects will no longer be\"\n\" usable. For reference purposes, :attr:`Document.name` still exists and \"\n\"will contain the filename of the original document (if applicable).\"\nmsgstr \"\"\n\"문서가 여전히 열려 있으면 ``False``. 닫히면 대부분의 다른 속성과 메서드가 삭제/비활성화됩니다. 또한 이 문서를 참조하는 \"\n\":ref:`Page` 객체(즉, :meth:`Document.load_page` 로 생성된)와 종속 객체는 더 이상 사용할 수 \"\n\"없습니다. 참조 목적으로 :attr:`Document.name` 은 여전히 존재하며 원본 문서의 파일명을 포함합니다(해당하는 \"\n\"경우).\"\n\n#: ../../document.rst:2024 ../../document.rst:2030 ../../document.rst:2036\n#: ../../document.rst:2050 ../../document.rst:2058 ../../document.rst:2066\n#: ../../document.rst:2104 ../../document.rst:2110\n#: 0cc5fd7ca5794cc1b9fbd3cfb3aa27fd 12e50b17b9cb40a48f8695654175db79\n#: 27f4f101c07c46c497d090cb3d8f71ad b1a9944e25c54efcb8ed9e82e88109c7\n#: c26a6856641b4639b862f347625b17af caa9c5b1a6a84e6992520149259beff6\n#: d4a114c416654fe786b4f773ca746d62 ee2dcc70850a4759921e982fb5d6d062\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../document.rst:2028 522e4e6cbfe546ecbc211187c3a94c41\nmsgid \"\"\n\"``True`` if this is a PDF document and contains unsaved changes, else \"\n\"``False``.\"\nmsgstr \"이것이 PDF 문서이고 저장되지 않은 변경 사항이 포함되어 있으면 ``True``, 그렇지 않으면 ``False``.\"\n\n#: ../../document.rst:2034 299c7a35b22d4fbf90828dc6b9cb044e\nmsgid \"``True`` if this is a PDF document, else ``False``.\"\nmsgstr \"이것이 PDF 문서이면 ``True``, 그렇지 않으면 ``False``.\"\n\n#: ../../document.rst:2040 08475f6f36f447c29441b4d3fd76df5d\nmsgid \"\"\n\"``False`` if this is not a PDF or has no form fields, otherwise the \"\n\"number of root form fields (fields with no ancestors).\"\nmsgstr \"이것이 PDF가 아니거나 양식 필드가 없으면 ``False``, 그렇지 않으면 루트 양식 필드 수(조상이 없는 필드).\"\n\n#: ../../document.rst:2042 010f3e3f2e224c74971e9b55d2bdaa7d\nmsgid \"*(Changed in v1.16.4)* Returns the total number of (root) form fields.\"\nmsgstr \"*(v1.16.4에서 변경됨)* (루트) 양식 필드의 총 수를 반환합니다.\"\n\n#: ../../document.rst:2044 b440f9a8184b42ec823bb89ea41d82fb\nmsgid \"bool,int\"\nmsgstr \"bool,int\"\n\n#: ../../document.rst:2048 35914fa669fd405da917712ef53a7e92\nmsgid \"\"\n\"``True`` if document has a variable page layout (like e-books or HTML). \"\n\"In this case you can set the desired page dimensions during document \"\n\"creation (open) or via method :meth:`layout`.\"\nmsgstr \"\"\n\"문서에 가변 페이지 레이아웃(예: 전자책 또는 HTML)이 있으면 ``True``. 이 경우 문서 생성(열기) 중 또는 메서드 \"\n\":meth:`layout` 을 통해 원하는 페이지 크기를 설정할 수 있습니다.\"\n\n#: ../../document.rst:2054 0ce6260a4e3a4baa8ff2828e5a438327\nmsgid \"New in v1.18.2\"\nmsgstr \"v1.18.2에서 새로 추가됨\"\n\n#: ../../document.rst:2056 a6d05b59ff164db98de53893fca7fcdd\nmsgid \"\"\n\"``True`` if PDF has been repaired during open (because of major structure\"\n\" issues). Always ``False`` for non-PDF documents. If true, more details \"\n\"have been stored in `TOOLS.mupdf_warnings()`, and \"\n\":meth:`Document.can_save_incrementally` will return ``False``.\"\nmsgstr \"\"\n\"PDF가 열기 중에 복구되었으면(주요 구조 문제로 인해) ``True``. 비PDF 문서의 경우 항상 ``False``. true인\"\n\" 경우 `TOOLS.mupdf_warnings()` 에 더 자세한 정보가 저장되며 \"\n\":meth:`Document.can_save_incrementally` 는 ``False`` 를 반환합니다.\"\n\n#: ../../document.rst:2064 a9b6d17bc6a64b64a3671e8bf9f83ec9\nmsgid \"``True`` if PDF is in linearized format. ``False`` for non-PDF documents.\"\nmsgstr \"PDF가 선형화 형식이면 ``True``. 비PDF 문서의 경우 ``False``.\"\n\n#: ../../document.rst:2072 e5b2f42393594f9584bc49db8042d6a4\nmsgid \"\"\n\"A dictionary indicating the `/MarkInfo` value. If not specified, the \"\n\"empty dictionary is returned. If not a PDF, `None` is returned.\"\nmsgstr \"`/MarkInfo` 값을 나타내는 딕셔너리. 지정되지 않으면 빈 딕셔너리가 반환됩니다. PDF가 아니면 `None` 이 반환됩니다.\"\n\n#: ../../document.rst:2074 ../../document.rst:2138\n#: 3784f9a4ac6e48878e4c8c36ad21d273 d4410deba0634bce846d5ce0cd9b29c3\nmsgid \"dict\"\nmsgstr \"dict\"\n\n#: ../../document.rst:2080 4271fd12fd1a41bfa48723d762e490a3\nmsgid \"\"\n\"A string containing the `/PageMode` value. If not specified, the default \"\n\"\\\"UseNone\\\" is returned. If not a PDF, `None` is returned.\"\nmsgstr \"\"\n\"`/PageMode` 값을 포함하는 문자열. 지정되지 않으면 기본값 \\\"UseNone\\\" 이 반환됩니다. PDF가 아니면 \"\n\"`None` 이 반환됩니다.\"\n\n#: ../../document.rst:2082 ../../document.rst:2090 ../../document.rst:2144\n#: 453fec96833e4433b835a1ef639e4b60 713b37981b604e8eb17307f1a2449199\n#: cf4e37d7bd7f4c8dba3d4242bbb1f2db\nmsgid \"str\"\nmsgstr \"str\"\n\n#: ../../document.rst:2088 f9d3ccb16f674ace8f055a5063405edc\nmsgid \"\"\n\"A string containing the `/PageLayout` value. If not specified, the \"\n\"default \\\"SinglePage\\\" is returned. If not a PDF, `None` is returned.\"\nmsgstr \"\"\n\"`/PageLayout` 값을 포함하는 문자열. 지정되지 않으면 기본값 \\\"SinglePage\\\" 가 반환됩니다. PDF가 아니면 \"\n\"`None` 이 반환됩니다.\"\n\n#: ../../document.rst:2096 c6a7fa11f6ba45668b3e397c883ba549\nmsgid \"\"\n\"An integer counting the number of versions present in the document. Zero \"\n\"if not a PDF, otherwise the number of incremental saves plus one.\"\nmsgstr \"문서에 있는 버전 수를 계산하는 정수. PDF가 아니면 0, 그렇지 않으면 증분 저장 수에 1을 더한 값.\"\n\n#: ../../document.rst:2098 ../../document.rst:2118 ../../document.rst:2150\n#: ../../document.rst:2158 ../../document.rst:2166\n#: 47a023dd007a4136b8709a8573756722 76fb9a9c4c9a40bebeed09ef0bfb3396\n#: 984c624fe25a4686a77b774cd80a69ab 9c287bb741d44c889f527a422691acc1\n#: fcb19540ceef4b62ad2dccde4b0f7510\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../document.rst:2102 7453a9e5ba024948a4063deb3b871b49\nmsgid \"\"\n\"Indicates whether the document is password-protected against access. This\"\n\" indicator remains unchanged -- **even after the document has been \"\n\"authenticated**. Precludes incremental saves if true.\"\nmsgstr \"\"\n\"문서가 액세스에 대해 비밀번호로 보호되는지 여부를 나타냅니다. 이 표시기는 변경되지 않습니다 -- **문서가 인증된 후에도**. \"\n\"true이면 증분 저장을 제외합니다.\"\n\n#: ../../document.rst:2108 5556027f67ae474bab1a88b005f81bc8\nmsgid \"\"\n\"This indicator initially equals :attr:`Document.needs_pass`. After \"\n\"successful authentication, it is set to ``False`` to reflect the \"\n\"situation.\"\nmsgstr \"\"\n\"이 표시기는 처음에 :attr:`Document.needs_pass` 와 같습니다. 성공적인 인증 후 상황을 반영하도록 \"\n\"``False`` 로 설정됩니다.\"\n\n#: ../../document.rst:2114 271b4315b03a405f8b9789f994bbd44d\nmsgid \"\"\n\"Changed in v1.16.0: This is now an integer comprised of bit indicators. \"\n\"Was a dictionary previously.\"\nmsgstr \"v1.16.0에서 변경됨: 이것은 이제 비트 표시기로 구성된 정수입니다. 이전에는 딕셔너리였습니다.\"\n\n#: ../../document.rst:2116 0a6016a9102f41f98184e468fbc8fcf9\nmsgid \"\"\n\"Contains the permissions to access the document. This is an integer \"\n\"containing bool values in respective bit positions. For example, if \"\n\"*doc.permissions & pymupdf.PDF_PERM_MODIFY > 0*, you may change the \"\n\"document. See :ref:`PermissionCodes` for details.\"\nmsgstr \"\"\n\"문서 액세스 권한을 포함합니다. 이것은 각 비트 위치에 bool 값을 포함하는 정수입니다. 예를 들어 *doc.permissions\"\n\" & pymupdf.PDF_PERM_MODIFY > 0* 이면 문서를 변경할 수 있습니다. 자세한 내용은 \"\n\":ref:`PermissionCodes` 를 참조하세요.\"\n\n#: ../../document.rst:2122 62256c18f0984d2c90bb467782ffeff9\nmsgid \"\"\n\"Contains the document's meta data as a Python dictionary or `None` (if \"\n\"*is_encrypted=True* and *needPass=True*). Keys are *format*, \"\n\"*encryption*, *title*, *author*, *subject*, *keywords*, *creator*, \"\n\"*producer*, *creationDate*, *modDate*, *trapped*. All item values are \"\n\"strings or `None`.\"\nmsgstr \"\"\n\"Python 딕셔너리 또는 `None` (만약 *is_encrypted=True* 및 *needPass=True* 인 경우)로 \"\n\"문서의 메타 데이터를 포함합니다. 키는 *format*, *encryption*, *title*, *author*, \"\n\"*subject*, *keywords*, *creator*, *producer*, *creationDate*, *modDate*, \"\n\"*trapped* 입니다. 모든 항목 값은 문자열 또는 `None` 입니다.\"\n\n#: ../../document.rst:2124 03eee27a933d433fb7db0fce45f47ce5\nmsgid \"\"\n\"Except *format* and *encryption*, for PDF documents, the key names \"\n\"correspond in an obvious way to the PDF keys */Creator*, */Producer*, \"\n\"*/CreationDate*, */ModDate*, */Title*, */Author*, */Subject*, */Trapped* \"\n\"and */Keywords* respectively.\"\nmsgstr \"\"\n\"*format* 및 *encryption* 을 제외하고, PDF 문서의 경우 키 이름은 PDF 키 */Creator*, \"\n\"*/Producer*, */CreationDate*, */ModDate*, */Title*, */Author*, \"\n\"*/Subject*, */Trapped* 및 */Keywords* 와 각각 명확하게 대응합니다.\"\n\n#: ../../document.rst:2126 35b7301ea11d45c690ea3d0cd18e2cbb\nmsgid \"*format* contains the document format (e.g. 'PDF-1.6', 'XPS', 'EPUB').\"\nmsgstr \"*format* 는 문서 형식을 포함합니다(예: 'PDF-1.6', 'XPS', 'EPUB').\"\n\n#: ../../document.rst:2128 d5b947e2ac1a49f59bf2d98bce59ef5f\nmsgid \"\"\n\"*encryption* either contains `None` (no encryption), or a string naming \"\n\"an encryption method (e.g. *'Standard V4 R4 128-bit RC4'*). Note that an \"\n\"encryption method may be specified **even if** *needs_pass=False*. In \"\n\"such cases not all permissions will probably have been granted. Check \"\n\":attr:`Document.permissions` for details.\"\nmsgstr \"\"\n\"*encryption* 는 `None` (암호화 없음) 또는 암호화 방법을 명명하는 문자열(예: *'Standard V4 R4 \"\n\"128-bit RC4'*)을 포함합니다. *needs_pass=False* 인 경우에도 암호화 방법이 지정될 수 있습니다. 이러한 \"\n\"경우 모든 권한이 부여되지 않았을 수 있습니다. 자세한 내용은 :attr:`Document.permissions` 를 확인하세요.\"\n\n#: ../../document.rst:2130 d7ddc57c41dd4f788b7900b6376aa4a1\nmsgid \"\"\n\"If the date fields contain valid data (which need not be the case at \"\n\"all!), they are strings in the PDF-specific timestamp format \"\n\"\\\"D:<TS><TZ>\\\", where\"\nmsgstr \"\"\n\"날짜 필드에 유효한 데이터가 포함되어 있으면(항상 그런 것은 아님!), PDF 특정 타임스탬프 형식 \\\"D:<TS><TZ>\\\" 의 \"\n\"문자열입니다. 여기서\"\n\n#: ../../document.rst:2132 37980944bd074ca5a4faae476976cc12\nmsgid \"\"\n\"<TS> is the 12 character ISO timestamp *YYYYMMDDhhmmss* (*YYYY* - year, \"\n\"*MM* - month, *DD* - day, *hh* - hour, *mm* - minute, *ss* - second), and\"\nmsgstr \"\"\n\"<TS> 는 12자 ISO 타임스탬프 *YYYYMMDDhhmmss* (*YYYY* - 연도, *MM* - 월, *DD* - 일, \"\n\"*hh* - 시, *mm* - 분, *ss* - 초)이며,\"\n\n#: ../../document.rst:2134 3856b3200cce432dbd8947d491439b5a\nmsgid \"\"\n\"<TZ> is a time zone value (time interval relative to GMT) containing a \"\n\"sign ('+' or '-'), the hour (*hh*), and the minute (*'mm'*, note the \"\n\"apostrophes!).\"\nmsgstr \"\"\n\"<TZ> 는 부호('+' 또는 '-'), 시간(*hh*), 분(*'mm'*, 아포스트로피 주의!)을 포함하는 시간대 값(GMT 기준\"\n\" 시간 간격)입니다.\"\n\n#: ../../document.rst:2136 50c3a62c47aa4a0e91767db198d13bc9\nmsgid \"\"\n\"A Paraguayan value might hence look like *D:20150415131602-04'00'*, which\"\n\" corresponds to the timestamp April 15, 2015, at 1:16:02 pm local time \"\n\"Asuncion.\"\nmsgstr \"\"\n\"파라과이 값은 따라서 *D:20150415131602-04'00'* 와 같이 보일 수 있으며, 이것은 2015년 4월 15일 오후 \"\n\"1:16:02 아순시온 현지 시간의 타임스탬프에 해당합니다.\"\n\n#: ../../document.rst:2142 5c4a4b4663dd458ebab9d3d96224ded1\nmsgid \"\"\n\"Contains the *filename* or *filetype* value with which *Document* was \"\n\"created.\"\nmsgstr \"*Document* 가 생성된 *filename* 또는 *filetype* 값을 포함합니다.\"\n\n#: ../../document.rst:2148 1fd9cb078c3b40fa80177d7d3b7cd662\nmsgid \"\"\n\"Contains the number of pages of the document. May return 0 for documents \"\n\"with no pages. Function `len(doc)` will also deliver this result.\"\nmsgstr \"\"\n\"문서의 페이지 수를 포함합니다. 페이지가 없는 문서의 경우 0을 반환할 수 있습니다. 함수 `len(doc)` 도 이 결과를 \"\n\"제공합니다.\"\n\n#: ../../document.rst:2154 ../../document.rst:2162\n#: a3d993a5f1ad4023b11623ba4734ce54 c2709f411db54b3695edf605a69854cd\nmsgid \"New in v1.17.0\"\nmsgstr \"v1.17.0에서 새로 추가됨\"\n\n#: ../../document.rst:2156 ae19f25817824e61a9bb7e1f679b1cd5\nmsgid \"\"\n\"Contains the number of chapters in the document. Always at least 1. \"\n\"Relevant only for document types with chapter support (EPUB currently). \"\n\"Other documents will return 1.\"\nmsgstr \"\"\n\"문서의 장 수를 포함합니다. 항상 최소 1입니다. 장 지원이 있는 문서 타입(현재 EPUB)에만 관련이 있습니다. 다른 문서는 1을\"\n\" 반환합니다.\"\n\n#: ../../document.rst:2164 3b71ca16faf845728a3b6fa856d2ea2a\nmsgid \"\"\n\"Contains (chapter, pno) of the document's last page. Relevant only for \"\n\"document types with chapter support (EPUB currently). Other documents \"\n\"will return `(0, page_count - 1)` and `(0, -1)` if it has no pages.\"\nmsgstr \"\"\n\"문서의 마지막 페이지의 (chapter, pno)를 포함합니다. 장 지원이 있는 문서 타입(현재 EPUB)에만 관련이 있습니다. \"\n\"다른 문서는 `(0, page_count - 1)` 을 반환하고 페이지가 없으면 `(0, -1)` 을 반환합니다.\"\n\n#: ../../document.rst:2170 cd3ec2161abf42f383b85e109737b05f\nmsgid \"\"\n\"A list of form field font names defined in the */AcroForm* object. `None`\"\n\" if not a PDF.\"\nmsgstr \"*/AcroForm* 객체에 정의된 양식 필드 폰트 이름 목록. PDF가 아니면 `None`.\"\n\n#: ../../document.rst:2172 2919fa430028481f824809524809a17c\nmsgid \"list\"\nmsgstr \"list\"\n\n#: ../../document.rst:2174 bc73641d1a9c4850a56dd8d1d90136ef\nmsgid \"\"\n\"For methods that change the structure of a PDF (:meth:`insert_pdf`, \"\n\":meth:`select`, :meth:`copy_page`, :meth:`delete_page` and others), be \"\n\"aware that objects or properties in your program may have been \"\n\"invalidated or orphaned. Examples are :ref:`Page` objects and their \"\n\"children (links, annotations, widgets), variables holding old page \"\n\"counts, tables of content and the like. Remember to keep such variables \"\n\"up to date or delete orphaned objects. Also refer to \"\n\":ref:`ReferenialIntegrity`.\"\nmsgstr \"\"\n\"PDF 구조를 변경하는 메서드(:meth:`insert_pdf`, :meth:`select`, :meth:`copy_page`, \"\n\":meth:`delete_page` 등)의 경우 프로그램의 객체나 속성이 무효화되거나 고아가 되었을 수 있습니다. 예는 \"\n\":ref:`Page` 객체와 그 자식(링크, 주석, 위젯), 이전 페이지 수를 보유하는 변수, 목차 등입니다. 이러한 변수를 최신 \"\n\"상태로 유지하거나 고아 객체를 삭제하세요. 또한 :ref:`ReferenialIntegrity` 를 참조하세요.\"\n\n#: ../../document.rst:2177 29ef52d9092f40e4b161b08377bff9f4\nmsgid \":meth:`set_metadata` Example\"\nmsgstr \":meth:`set_metadata` 예제\"\n\n#: ../../document.rst:2178 9d932a2b03af4a70a7e135168374444b\nmsgid \"\"\n\"Clear metadata information. If you do this out of privacy / data \"\n\"protection concerns, make sure you save the document as a new file with \"\n\"*garbage > 0*. Only then the old */Info* object will also be physically \"\n\"removed from the file. In this case, you may also want to clear any XML \"\n\"metadata inserted by several PDF editors:\"\nmsgstr \"\"\n\"메타데이터 정보를 지웁니다. 개인정보/데이터 보호 우려로 이 작업을 수행하는 경우 *garbage > 0* 로 문서를 새 파일로 \"\n\"저장하세요. 그때만 이전 */Info* 객체도 파일에서 물리적으로 제거됩니다. 이 경우 여러 PDF 편집기에서 삽입한 XML \"\n\"메타데이터도 지우는 것이 좋습니다:\"\n\n#: ../../document.rst:2196 e2eb0b4a72184167a71e581190ebe0ed\nmsgid \":meth:`set_toc` Demonstration\"\nmsgstr \":meth:`set_toc` 데모\"\n\n#: ../../document.rst:2197 54198eb7940a4522a14d500ec0a2b760\nmsgid \"\"\n\"This shows how to modify or add a table of contents. Also have a look at \"\n\"`import.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/import-toc/import.py>`_ and `export.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples\"\n\"/export-toc/export.py>`_ in the examples directory.\"\nmsgstr \"\"\n\"이것은 목차를 수정하거나 추가하는 방법을 보여줍니다. 예제 디렉토리의 `import.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/import-toc/import.py>`_ 및 `export.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/examples/export-toc/export.py>`_ 도 참조하세요.\"\n\n#: ../../document.rst:2217 803cdd302feb4061b6819a0a3f68b43a\nmsgid \":meth:`insert_pdf` Examples\"\nmsgstr \":meth:`insert_pdf` 예제\"\n\n#: ../../document.rst:2218 e1ab62bf3b5d4358b3314a0d663f91a2\nmsgid \"**(1) Concatenate two documents including their TOCs:**\"\nmsgstr \"**(1) TOC를 포함하여 두 문서를 연결합니다:**\"\n\n#: ../../document.rst:2230 66d3a98744254ca8bebc826e6d41788f\nmsgid \"\"\n\"Obviously, similar ways can be found in more general situations. Just \"\n\"make sure that hierarchy levels in a row do not increase by more than \"\n\"one. Inserting dummy bookmarks before and after *toc2* segments would \"\n\"heal such cases. A ready-to-use GUI (wxPython) solution can be found in \"\n\"script `join.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/join-documents/join.py>`_ of the examples \"\n\"directory.\"\nmsgstr \"\"\n\"명백히, 더 일반적인 상황에서도 유사한 방법을 찾을 수 있습니다. 연속된 계층 수준이 1보다 많이 증가하지 않도록 하세요. \"\n\"*toc2* 세그먼트 앞뒤에 더미 북마크를 삽입하면 이러한 경우를 해결할 수 있습니다. 바로 사용할 수 있는 \"\n\"GUI(wxPython) 솔루션은 예제 디렉토리의 스크립트 `join.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py>`_ 에서 찾을 수\"\n\" 있습니다.\"\n\n#: ../../document.rst:2232 fe43ea94f4cf486e93446c386ef6290b\nmsgid \"**(2) More examples:**\"\nmsgstr \"**(2) 추가 예제:**\"\n\n#: ../../document.rst:2244 5589340b632247dcb71322e527a4570f\nmsgid \"Other Examples\"\nmsgstr \"기타 예제\"\n\n#: ../../document.rst:2245 da51858e718249de8fdd7d624f754823\nmsgid \"**Extract all page-referenced images of a PDF into separate PNG files**::\"\nmsgstr \"**PDF의 모든 페이지 참조 이미지를 별도의 PNG 파일로 추출합니다**::\"\n\n#: ../../document.rst:2260 0c04c73b8df34278bf443717821a8217\nmsgid \"**Rotate all pages of a PDF:**\"\nmsgstr \"**PDF의 모든 페이지를 회전합니다:**\"\n\n#: ../../document.rst:2265 1db40e14af84441b834f859b50baabf7\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../document.rst:2266 ad80ce9bb918432f961168d95b5ded0b\nmsgid \"\"\n\"Content streams describe what (e.g. text or images) appears where and how\"\n\" on a page. PDF uses a specialized mini language similar to PostScript to\"\n\" do this (pp. 643 in :ref:`AdobeManual`), which gets interpreted when a \"\n\"page is loaded.\"\nmsgstr \"\"\n\"콘텐츠 스트림은 페이지에서 무엇(예: 텍스트 또는 이미지)이 어디에 어떻게 나타나는지 설명합니다. PDF는 이를 위해 \"\n\"PostScript와 유사한 특수 미니 언어를 사용합니다(:ref:`AdobeManual` 643페이지). 페이지가 로드될 때 \"\n\"해석됩니다.\"\n\n#: ../../document.rst:2268 de6710734193418ca5c9bec0d67eb9a3\nmsgid \"\"\n\"However, you **can** use :meth:`Document.get_toc` and \"\n\":meth:`Page.get_links` (which are available for all document types) and \"\n\"copy this information over to the output PDF. See demo `convert.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/convert-document/convert.py>`_.\"\nmsgstr \"\"\n\"그러나 :meth:`Document.get_toc` 및 :meth:`Page.get_links` (모든 문서 타입에서 사용 가능)를\"\n\" 사용하여 이 정보를 출력 PDF로 복사할 수 있습니다. 데모 `convert.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/convert-document/convert.py>`_ 를 참조하세요.\"\n\n#: ../../document.rst:2270 04f4a2a7a5114f97b1f359310b4e7013\nmsgid \"\"\n\"For applicable (EPUB) document types, loading a page via its absolute \"\n\"number may result in layouting a large part of the document, before the \"\n\"page can be accessed. To avoid this performance impact, prefer chapter-\"\n\"based access. Use convenience methods and attributes \"\n\":meth:`Document.next_location`, :meth:`Document.prev_location` and \"\n\":attr:`Document.last_location` for maintaining a high level of coding \"\n\"efficiency.\"\nmsgstr \"\"\n\"적용 가능한(EPUB) 문서 타입의 경우 절대 번호를 통해 페이지를 로드하면 페이지에 액세스하기 전에 문서의 큰 부분이 레이아웃될 \"\n\"수 있습니다. 이 성능 영향을 피하려면 장 기반 액세스를 선호하세요. 높은 수준의 코딩 효율성을 유지하기 위해 편의 메서드 및 속성\"\n\" :meth:`Document.next_location`, :meth:`Document.prev_location` 및 \"\n\":attr:`Document.last_location` 을 사용하세요.\"\n\n#: ../../document.rst:2272 0cdbae3fcd614e118ad4f020fe0d70f7\nmsgid \"\"\n\"These parameters cause separate handling of stream categories: use it \"\n\"together with `expand` to restrict decompression to streams other than \"\n\"images / fontfiles.\"\nmsgstr \"\"\n\"이 매개변수는 스트림 카테고리의 별도 처리를 유발합니다: 이미지/폰트 파일이 아닌 스트림으로 압축 해제를 제한하려면 `expand`\"\n\" 와 함께 사용하세요.\"\n\n#: ../../document.rst:2274 418afd4e54704148af7cb35c9b73529f\nmsgid \"Examples for \\\"Form XObjects\\\" are created by :meth:`Page.show_pdf_page`.\"\nmsgstr \"\\\"Form XObjects\\\" 예제는 :meth:`Page.show_pdf_page` 로 생성됩니다.\"\n\n#: ../../document.rst:2276 4d9bbbe81fb14c3e82b33b401c51082e\nmsgid \"\"\n\"For a ``False`` the **complete document** must be scanned. Both methods \"\n\"**do not load pages,** but only scan object definitions. This makes them \"\n\"at least 10 times faster than application-level loops (where total \"\n\"response time roughly equals the time for loading all pages). For the \"\n\":ref:`AdobeManual` (756 pages) and the Pandas documentation (over 3070 \"\n\"pages) -- both have no annotations -- the method needs about 11 ms for \"\n\"the answer ``False``. So response times will probably become significant \"\n\"only well beyond this order of magnitude.\"\nmsgstr \"\"\n\"``False`` 의 경우 **전체 문서** 를 스캔해야 합니다. 두 메서드 모두 **페이지를 로드하지 않고** 객체 정의만 \"\n\"스캔합니다. 이것은 애플리케이션 수준 루프(총 응답 시간이 모든 페이지를 로드하는 시간과 거의 같음)보다 최소 10배 빠릅니다. \"\n\":ref:`AdobeManual` (756페이지) 및 Pandas 문서(3070페이지 이상)의 경우 -- 둘 다 주석이 없음 -- \"\n\"메서드는 답변 ``False`` 에 대해 약 11ms가 필요합니다. 따라서 응답 시간은 이 자릿수를 훨씬 넘어서야만 중요해질 \"\n\"것입니다.\"\n\n#: ../../document.rst:2278 e17889162164454eb395d68f5b5f74f8\nmsgid \"\"\n\"This only works under certain conditions. For example, if there is normal\"\n\" text covered by some image on top of it, then this is undetectable and \"\n\"the respective text is **not** removed. Similar is true for white text on\"\n\" white background, and so on.\"\nmsgstr \"\"\n\"이것은 특정 조건에서만 작동합니다. 예를 들어, 일부 이미지로 덮인 일반 텍스트가 있으면 이것은 감지할 수 없으며 해당 텍스트는 \"\n\"**제거되지 않습니다**. 흰색 배경의 흰색 텍스트 등도 마찬가지입니다.\"\n\n#: ../../footer.rst:57 171190eed44c498983f498af56b35570\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/faq.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-03 09:30+0900\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../header.rst:-1 abe8297b843740e8818a779fc28f5e03\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 2a09517c326c4536ad593b77a7c34643\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8e302b086c9d4b94a25e05794331fde6\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../faq.rst:7 7cb40df6997749398b9eb35022cc8f6e\nmsgid \"FAQ\"\nmsgstr \"자주 묻는 질문\"\n\n#: ../../faq.rst:9 e705c9c730c74868ad8d1f1495bccfb2\nmsgid \"A collection of recipes in “How-To” format for using PyMuPDF.\"\nmsgstr \"PyMuPDF 사용을 위한 “사용 방법” 형식의 레시피 모음입니다.\"\n\n#: ../../faq.rst:12 76435ac8e35648f08fd41ecd9c4cf967\nmsgid \"Please see:\"\nmsgstr \"다음을 참조하세요:\"\n\n#: ../../faq.rst:14 8f2e64a1c0fc4275bdecc52010b788ff\nmsgid \":ref:`Recipes: Table of Contents<RecipesTOC>`\"\nmsgstr \":ref:`레시피: 목차<RecipesTOC>`\"\n\n#: ../../footer.rst:57 570a7f5b861040448158d8294efe49f2\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/font.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 e188dde9abe149bc8995bf7a6a0bc7d6\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 3cb714fa525c44bbbbd491bc8f62336e\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 c23c7d47fe3e429dbde810adabc353b6\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../font.rst:7 d2748ea1ae9940f6b22b259ae4533e13\nmsgid \"Font\"\nmsgstr \"Font\"\n\n#: ../../font.rst:9 3bf53a70d692484eaabd5afc3aab44c8\nmsgid \"New in v1.16.18\"\nmsgstr \"*v1.16.18의 새로운 기능*\"\n\n#: ../../font.rst:11 4c18f6c0f2b6494fbf226048ecce0907\nmsgid \"\"\n\"This class represents a font as defined in |MuPDF| (``fz_font_s`` \"\n\"structure). It is required for the new class :ref:`TextWriter` and the \"\n\"new :meth:`Page.write_text`. Currently, it has no connection to how fonts\"\n\" are used in methods :meth:`Page.insert_text` or \"\n\":meth:`Page.insert_textbox`, respectively.\"\nmsgstr \"이 클래스는 |MuPDF| 에서 정의된 글꼴(``fz_font_s`` 구조)을 나타냅니다. 새로운 클래스 :ref:`TextWriter` 및 새로운 :meth:`Page.write_text` 에 필요합니다. 현재는 :meth:`Page.insert_text` 또는 :meth:`Page.insert_textbox` 메서드에서 글꼴이 사용되는 방식과 연결되어 있지 않습니다.\"\n\n#: ../../font.rst:13 2125868871f645fb9fa0d4390f116a1a\nmsgid \"\"\n\"A ``Font`` object also contains useful general information, like the font\"\n\" bbox, the number of defined glyphs, glyph names or the ``bbox`` of a \"\n\"single glyph.\"\nmsgstr \"``Font`` 객체는 글꼴 bbox, 정의된 글리프 수, 글리프 이름 또는 단일 글리프의 ``bbox`` 와 같은 유용한 일반 정보도 포함합니다.\"\n\n#: ../../font.rst:17 842b44a70bf34b07ac2692aa84a193da\nmsgid \"**Method / Attribute**\"\nmsgstr \"**Method / Attribute**\"\n\n#: ../../font.rst:17 f69a466cefe443c3855949e5cc5ffcd6\nmsgid \"**Short Description**\"\nmsgstr \"**Short Description**\"\n\n#: ../../font.rst:19 1bba986439da408a84c24de22da3768d\nmsgid \":meth:`~Font.glyph_advance`\"\nmsgstr \"\"\n\n#: ../../font.rst:19 627a6c4218dd4762ae098709cdb920ad\nmsgid \"Width of a character\"\nmsgstr \"문자 너비\"\n\n#: ../../font.rst:20 6ca041bd76a54c949510e2ed77ca58f0\nmsgid \":meth:`~Font.glyph_bbox`\"\nmsgstr \"\"\n\n#: ../../font.rst:20 d9fb542d691c44a19873b891f02b7812\nmsgid \"Glyph rectangle\"\nmsgstr \"글리프 사각형\"\n\n#: ../../font.rst:21 e7791392edbd4e5d9094df1b320d2c5b\nmsgid \":meth:`~Font.glyph_name_to_unicode`\"\nmsgstr \"\"\n\n#: ../../font.rst:21 13f06c680aba44698114079c036bcdba\nmsgid \"Get unicode from glyph name\"\nmsgstr \"글리프 이름에서 유니코드 가져오기\"\n\n#: ../../font.rst:22 c04368ada6c341f093c2f4872cd5cd52\nmsgid \":meth:`~Font.has_glyph`\"\nmsgstr \"\"\n\n#: ../../font.rst:22 689634c88d144bef9223b78f39009eda\nmsgid \"Return glyph id of unicode\"\nmsgstr \"유니코드의 글리프 ID 반환\"\n\n#: ../../font.rst:23 a369a0e87b4340168dce9cd130684d3c\nmsgid \":meth:`~Font.text_length`\"\nmsgstr \"\"\n\n#: ../../font.rst:23 f20e22d5c6534f99a10aad9ab98d9ae3\nmsgid \"Compute string length\"\nmsgstr \"문자열 길이 계산\"\n\n#: ../../font.rst:24 d46c723021014de19f30cce31dd6fa83\nmsgid \":meth:`~Font.char_lengths`\"\nmsgstr \"\"\n\n#: ../../font.rst:24 2c939c616c2a45d19cef1d2e9148c5f8\nmsgid \"Tuple of char widths of a string\"\nmsgstr \"문자열의 문자 너비 튜플\"\n\n#: ../../font.rst:25 30fcbf0fac8c4137ac05697051b7a487\nmsgid \":meth:`~Font.unicode_to_glyph_name`\"\nmsgstr \"\"\n\n#: ../../font.rst:25 96a805868d65421593f69cabcbdff444\nmsgid \"Get glyph name of a unicode\"\nmsgstr \"유니코드의 글리프 이름 가져오기\"\n\n#: ../../font.rst:26 556560ade52f45878ccd9247ed48b124\nmsgid \":meth:`~Font.valid_codepoints`\"\nmsgstr \"\"\n\n#: ../../font.rst:26 f98352016c9a420597ecdc2d4da47bcd\nmsgid \"Array of supported unicodes\"\nmsgstr \"지원되는 유니코드 배열\"\n\n#: ../../font.rst:27 8046f6ca0658408896ffec620e7c19d2\nmsgid \":attr:`~Font.ascender`\"\nmsgstr \"\"\n\n#: ../../font.rst:27 bdef6c925fd24cd6a8bd423203561e10\nmsgid \"Font ascender\"\nmsgstr \"글꼴 상승부\"\n\n#: ../../font.rst:28 b9972b7d50024c5f92aae461b95e9b9d\nmsgid \":attr:`~Font.descender`\"\nmsgstr \"\"\n\n#: ../../font.rst:28 333b36880ce240299a20b8d485071b31\nmsgid \"Font descender\"\nmsgstr \"글꼴 하강부\"\n\n#: ../../font.rst:29 1ca68d63143c41ae9afaf82231bb0b98\nmsgid \":attr:`~Font.bbox`\"\nmsgstr \"\"\n\n#: ../../font.rst:29 88947fe258eb49d5a4bcd7f9262d6f64\nmsgid \"Font rectangle\"\nmsgstr \"글꼴 사각형\"\n\n#: ../../font.rst:30 70204c08ad4f48bfb90c610ace5e2f16\nmsgid \":attr:`~Font.buffer`\"\nmsgstr \"\"\n\n#: ../../font.rst:30 d8dc88a830a143b69cf9198d43a1d8be\nmsgid \"Copy of the font's binary image\"\nmsgstr \"글꼴의 바이너리 이미지 복사본\"\n\n#: ../../font.rst:31 087ab4d9b8c245329f433d0e0bc1dae2\nmsgid \":attr:`~Font.flags`\"\nmsgstr \"\"\n\n#: ../../font.rst:31 b08397d234cf4d828c277f81b7e5797c\nmsgid \"Collection of font properties\"\nmsgstr \"글꼴 속성 모음\"\n\n#: ../../font.rst:32 1b9e053341ba4bf29f37614365fca44e\nmsgid \":attr:`~Font.glyph_count`\"\nmsgstr \"\"\n\n#: ../../font.rst:32 9266fb9484fe42618bd4b861302ec139\nmsgid \"Number of supported glyphs\"\nmsgstr \"지원되는 글리프 수\"\n\n#: ../../font.rst:33 a1a23dee533f4eb9a0253e7ed4dc2160\nmsgid \":attr:`~Font.name`\"\nmsgstr \"\"\n\n#: ../../font.rst:33 f7c44ea05506418686745a0a8b4ccf1e\nmsgid \"Name of font\"\nmsgstr \"글꼴 이름\"\n\n#: ../../font.rst:34 4d8600344c934dca966561b9b23705a3\nmsgid \":attr:`~Font.is_bold`\"\nmsgstr \"\"\n\n#: ../../font.rst:34 42bd831f9b604a58adec9428f2799d4a\nmsgid \"`True` if bold\"\nmsgstr \"굵게이면 `True`\"\n\n#: ../../font.rst:35 4fd252e5611e4f25ad7279f120909cc1\nmsgid \":attr:`~Font.is_monospaced`\"\nmsgstr \"\"\n\n#: ../../font.rst:35 53567d475247479ebe27771a05253749\nmsgid \"`True` if mono-spaced\"\nmsgstr \"고정폭이면 `True`\"\n\n#: ../../font.rst:36 386c083d80e24cd8889a76d1ed0d655e\nmsgid \":attr:`~Font.is_serif`\"\nmsgstr \"\"\n\n#: ../../font.rst:36 dc515a68d8984513880dd9652137056b\nmsgid \"`True` if serif, `False` if sans-serif\"\nmsgstr \"세리프이면 `True`, 산세리프이면 `False`\"\n\n#: ../../font.rst:37 ef38964ab5634a4a8afc1a4043834bcb\nmsgid \":attr:`~Font.is_italic`\"\nmsgstr \"\"\n\n#: ../../font.rst:37 6ab8b6017630445e8a8d73bd87250888\nmsgid \"`True` if italic\"\nmsgstr \"이탤릭이면 `True`\"\n\n#: ../../font.rst:41 ef6bc7e0d9cf42848d2ea5ec97cad0e8\nmsgid \"**Class API**\"\nmsgstr \"**Class API**\"\n\n#: ../../font.rst:60 07b4413b01ae4ae89132a4d69299fcff\nmsgid \"\"\n\"Font constructor. The large number of parameters are used to locate font,\"\n\" which most closely resembles the requirements. Not all parameters are \"\n\"ever required -- see the below pseudo code explaining the logic how the \"\n\"parameters are evaluated.\"\nmsgstr \"Font 생성자. 많은 매개변수는 요구사항에 가장 가까운 글꼴을 찾는 데 사용됩니다. 모든 매개변수가 항상 필요한 것은 아닙니다 -- 매개변수가 평가되는 방식의 논리를 설명하는 아래 의사 코드를 참조하세요.\"\n\n#: ../../font.rst 51829dd751b848658d1ba228b94ce1de\n#: 6865a3bfb8444b439d877a9d8a59cb0a 722fbb72278d4e3e8bb0df13f398859a\n#: 8cbc7148711c4ee9a078b6a806370c78 a100d7e7206946cda8a733ebb3f80137\n#: c931f89accb14562827a19ea990df0aa f0f58970e4794ad2b4f9ab161b976692\n#: f42510c818544c6180a85f87a852dd28\nmsgid \"Parameters\"\nmsgstr \"Parameters\"\n\n#: ../../font.rst:62 b7c66967af094eed88e4cd0bfa9c0b59\nmsgid \"\"\n\"one of the :ref:`Base-14-Fonts` or CJK fontnames. Also possible are a \"\n\"select few other names like (watch the correct spelling): \\\"Arial\\\", \"\n\"\\\"Times\\\", \\\"Times Roman\\\".  *(Changed in v1.17.5)*  If you have \"\n\"installed `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_, \"\n\"there are also new \\\"reserved\\\" fontnames available, which are listed in \"\n\":attr:`fitz_fonts` and in the table further down.\"\nmsgstr \"\"\n\n#: ../../font.rst:62 4f54e9a21f4e4cdd94eb896e84a11207\nmsgid \"\"\n\"one of the :ref:`Base-14-Fonts` or CJK fontnames. Also possible are a \"\n\"select few other names like (watch the correct spelling): \\\"Arial\\\", \"\n\"\\\"Times\\\", \\\"Times Roman\\\".\"\nmsgstr \":ref:`Base-14-Fonts` 또는 CJK 글꼴 이름 중 하나. (올바른 철자를 주의하세요) \\\"Arial\\\", \\\"Times\\\", \\\"Times Roman\\\"과 같은 몇 가지 다른 이름도 가능합니다.\"\n\n#: ../../font.rst:64 33128ec921644adcb669eed87f58d1ad\nmsgid \"*(Changed in v1.17.5)*\"\nmsgstr \"*(v1.17.5에서 변경됨)*\"\n\n#: ../../font.rst:66 2580ac163f6d40a6a97df2667e044b70\nmsgid \"\"\n\"If you have installed `pymupdf-fonts <https://pypi.org/project/pymupdf-\"\n\"fonts/>`_, there are also new \\\"reserved\\\" fontnames available, which are\"\n\" listed in :attr:`fitz_fonts` and in the table further down.\"\nmsgstr \"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ 를 설치한 경우, :attr:`fitz_fonts` 및 아래 표에 나열된 새로운 \\\"예약된\\\" 글꼴 이름도 사용할 수 있습니다.\"\n\n#: ../../font.rst:68 0115b8805a994350b1e9b88652d9c671\nmsgid \"the filename of a fontfile somewhere on your system [#f1]_.\"\nmsgstr \"시스템 어딘가에 있는 글꼴 파일의 파일 이름 [#f1]_.\"\n\n#: ../../font.rst:69 855671c475ce4d4a95574d50da436fa8\nmsgid \"a fontfile loaded in memory [#f1]_.\"\nmsgstr \"메모리에 로드된 글꼴 파일 [#f1]_.\"\n\n#: ../../font.rst:70 b4cd7e175eb14d658f5faa379b3ef701\nmsgid \"\"\n\"the number of a UCDN script. Currently supported in PyMuPDF are numbers \"\n\"24, and 32 through 35.\"\nmsgstr \"UCDN 스크립트 번호. 현재 |PyMuPDF| 에서 지원되는 번호는 24, 32부터 35까지입니다.\"\n\n#: ../../font.rst:71 d5a5fc15ea7c4e1b8d26964a61b402e8\nmsgid \"\"\n\"one of the values \\\"zh-Hant\\\" (traditional Chinese), \\\"zh-Hans\\\" \"\n\"(simplified Chinese), \\\"ja\\\" (Japanese) and \\\"ko\\\" (Korean). Otherwise, \"\n\"all ISO 639 codes from the subsets 1, 2, 3 and 5 are also possible, but \"\n\"are currently documentary only.\"\nmsgstr \"\\\"zh-Hant\\\"(번체 중국어), \\\"zh-Hans\\\"(간체 중국어), \\\"ja\\\"(일본어), \\\"ko\\\"(한국어) 값 중 하나. 그렇지 않으면 하위 집합 1, 2, 3 및 5의 모든 ISO 639 코드도 가능하지만 현재는 문서화만 되어 있습니다.\"\n\n#: ../../font.rst:72 5b0e786be58c4a09a48eacc61882197e\nmsgid \"an alternative selector for one of the CJK fonts.\"\nmsgstr \"CJK 글꼴 중 하나에 대한 대체 선택자.\"\n\n#: ../../font.rst:73 6af1f2fb252e4071bab746f2ad57c01d\nmsgid \"look for a bold font.\"\nmsgstr \"굵은 글꼴을 찾습니다.\"\n\n#: ../../font.rst:74 6f2bffef2aa94c92b00fa9cf6d97a283\nmsgid \"look for an italic font.\"\nmsgstr \"이탤릭 글꼴을 찾습니다.\"\n\n#: ../../font.rst:75 23ca0f2751ed4b2f834236f7e744dd36\nmsgid \"look for a serifed font.\"\nmsgstr \"세리프 글꼴을 찾습니다.\"\n\n#: ../../font.rst 1d22b29a05e741f387368f96870d4c1b\n#: 1e8b6f0bc4da4c4db71fcd4ce33f7f4d 1ebfff0006a54633b2e48a4cf728c55b\n#: 3126e087ce6d47cbb326a10281420878 3aaf4a67eaa8475e97bebd3b14716268\n#: 3b8e58b5a2034fddbba0b9f34d785351 425ebf256d4842928912c98469178b2e\n#: 455992af6eea4168919f71ca6e0a63e9 7512b5e1267b491c80d9886fcb846c91\nmsgid \"Returns\"\nmsgstr \"Returns\"\n\n#: ../../font.rst:77 d564d7e503224782b914ea4c4d4bd55b\nmsgid \"\"\n\"a |MuPDF| font if successful. This is the overall sequence of checks to \"\n\"determine an appropriate font:  =========== \"\n\"============================================================ Argument    \"\n\"Action =========== \"\n\"============================================================ fontfile?   \"\n\"Create font from file, exception if failure. fontbuffer? Create font from\"\n\" buffer, exception if failure. ordering>=0 Create universal font, always \"\n\"succeeds. fontname?   Create a Base-14 font, universal font, or font\"\n\"             provided by `pymupdf-fonts <https://pypi.org/project\"\n\"/pymupdf-fonts/>`_. See table below. =========== \"\n\"============================================================\"\nmsgstr \"\"\n\n#: ../../font.rst:77 cea38fccea5241229aadba228571f8be\nmsgid \"\"\n\"a |MuPDF| font if successful. This is the overall sequence of checks to \"\n\"determine an appropriate font:\"\nmsgstr \"성공하면 |MuPDF| 글꼴. 적절한 글꼴을 결정하기 위한 전체 확인 순서는 다음과 같습니다:\"\n\n#: ../../font.rst:80 580ec24b97e749299e613764ef3403c6\nmsgid \"Argument\"\nmsgstr \"Argument\"\n\n#: ../../font.rst:80 c41ca6b5584649b586f676f06f22549b\nmsgid \"Action\"\nmsgstr \"Action\"\n\n#: ../../font.rst:82 98333181f4584c9c8bca13c85c415262\nmsgid \"fontfile?\"\nmsgstr \"fontfile?\"\n\n#: ../../font.rst:82 73d6da924f634bc7b6e4fe044072fe6d\nmsgid \"Create font from file, exception if failure.\"\nmsgstr \"파일에서 글꼴 생성, 실패 시 예외 발생.\"\n\n#: ../../font.rst:83 130073b0bea44ffc890479cdb5f5340d\nmsgid \"fontbuffer?\"\nmsgstr \"fontbuffer?\"\n\n#: ../../font.rst:83 a74986c74e6843eea78fcc35d447c3a2\nmsgid \"Create font from buffer, exception if failure.\"\nmsgstr \"버퍼에서 글꼴 생성, 실패 시 예외 발생.\"\n\n#: ../../font.rst:84 29919d8588f5493dafda4cfe7f0555b1\nmsgid \"ordering>=0\"\nmsgstr \"ordering>=0\"\n\n#: ../../font.rst:84 3f0b6b784f1742238213e67a82078abf\nmsgid \"Create universal font, always succeeds.\"\nmsgstr \"범용 글꼴 생성, 항상 성공.\"\n\n#: ../../font.rst:85 fe70636ee76b429da54199e913507119\nmsgid \"fontname?\"\nmsgstr \"fontname?\"\n\n#: ../../font.rst:85 a411aeb787b5416f854bb729f143e0b6\nmsgid \"\"\n\"Create a Base-14 font, universal font, or font provided by `pymupdf-fonts\"\n\" <https://pypi.org/project/pymupdf-fonts/>`_. See table below.\"\nmsgstr \"Base-14 글꼴, 범용 글꼴 또는 `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ 에서 제공하는 글꼴을 생성합니다. 아래 표를 참조하세요.\"\n\n#: ../../font.rst:92 d6d370d9961e418c8c6a25a191d46651\nmsgid \"\"\n\"With the usual reserved names \\\"helv\\\", \\\"tiro\\\", etc., you will create \"\n\"fonts with the expected names \\\"Helvetica\\\", \\\"Times-Roman\\\" and so on. \"\n\"**However**, and in contrast to :meth:`Page.insert_font` and friends,\"\nmsgstr \"일반적인 예약된 이름 \\\"helv\\\", \\\"tiro\\\" 등을 사용하면 예상되는 이름 \\\"Helvetica\\\", \\\"Times-Roman\\\" 등의 글꼴이 생성됩니다. **그러나** :meth:`Page.insert_font` 및 유사한 메서드와 달리,\"\n\n#: ../../font.rst:94 31fed8debc7c42ca9166ee0b1ef74c98\nmsgid \"a font file will **always** be embedded in your PDF,\"\nmsgstr \"글꼴 파일이 **항상** PDF에 임베드됩니다,\"\n\n#: ../../font.rst:95 9b3d8892b4424474889b2416ef13836b\nmsgid \"\"\n\"Greek and Cyrillic characters are supported without needing the \"\n\"*encoding* parameter.\"\nmsgstr \"그리스 문자 및 키릴 문자는 *encoding* 매개변수 없이 지원됩니다.\"\n\n#: ../../font.rst:97 c07988cc48644ac8846d43cf555ae595\nmsgid \"\"\n\"Using *ordering >= 0*, or fontnames \\\"cjk\\\", \\\"china-t\\\", \\\"china-s\\\", \"\n\"\\\"japan\\\" or \\\"korea\\\" will **always create the same \\\"universal\\\"** font\"\n\" **\\\"Droid Sans Fallback Regular\\\"**. This font supports **all Chinese, \"\n\"Japanese, Korean and Latin characters**, including Greek and Cyrillic. \"\n\"This is a sans-serif font.\"\nmsgstr \"*ordering >= 0* 또는 글꼴 이름 \\\"cjk\\\", \\\"china-t\\\", \\\"china-s\\\", \\\"japan\\\" 또는 \\\"korea\\\"를 사용하면 **항상 동일한 \\\"범용\\\"** 글꼴 **\\\"Droid Sans Fallback Regular\\\"** 이 생성됩니다. 이 글꼴은 그리스 문자 및 키릴 문자를 포함하여 **모든 중국어, 일본어, 한국어 및 라틴 문자** 를 지원합니다. 이것은 산세리프 글꼴입니다.\"\n\n#: ../../font.rst:99 6db4519008e44ee682c2a27e4d316f4b\nmsgid \"\"\n\"Actually, you would rarely ever need another sans-serif font than \"\n\"**\\\"Droid Sans Fallback Regular\\\"**. **Except** that this font file is \"\n\"relatively large and adds about 1.65 MB (compressed) to your PDF file \"\n\"size. If you do not need CJK support, stick with specifying \\\"helv\\\", \"\n\"\\\"tiro\\\" etc., and you will get away with about 35 KB compressed.\"\nmsgstr \"실제로 **\\\"Droid Sans Fallback Regular\\\"** 외에 다른 산세리프 글꼴이 필요한 경우는 거의 없습니다. **다만** 이 글꼴 파일은 상대적으로 크며 PDF 파일 크기에 약 1.65 MB(압축됨)를 추가합니다. CJK 지원이 필요하지 않다면 \\\"helv\\\", \\\"tiro\\\" 등을 지정하고 약 35 KB(압축됨)로 처리할 수 있습니다.\"\n\n#: ../../font.rst:101 79c699cd0e0a44828e95752e5f6f2ebe\nmsgid \"\"\n\"If you **know** you have a mixture of CJK and Latin text, consider just \"\n\"using `Font(\\\"cjk\\\")` because this supports everything and also \"\n\"significantly (by a factor of up to three) speeds up execution: MuPDF \"\n\"will always find any character in this single font and never needs to \"\n\"check fallbacks.\"\nmsgstr \"CJK와 라틴 텍스트가 혼합되어 있다는 것을 **알고** 있다면, `Font(\\\"cjk\\\")` 를 사용하는 것을 고려하세요. 이것은 모든 것을 지원하며 실행 속도를 크게(최대 3배까지) 향상시킵니다: MuPDF는 항상 이 단일 글꼴에서 모든 문자를 찾을 수 있으며 대체 글꼴을 확인할 필요가 없습니다.\"\n\n#: ../../font.rst:103 71613c830de34e6f9ecdf39faec59a38\nmsgid \"\"\n\"But if you do use some other font, you will still automatically be able \"\n\"to also write CJK characters: MuPDF detects this situation and silently \"\n\"falls back to the universal font (which will then of course also be \"\n\"embedded in your PDF).\"\nmsgstr \"그러나 다른 글꼴을 사용하는 경우에도 CJK 문자를 자동으로 쓸 수 있습니다: MuPDF는 이 상황을 감지하고 자동으로 범용 글꼴로 대체합니다(그러면 물론 PDF에도 임베드됩니다).\"\n\n#: ../../font.rst:105 f904db70b3d246e1b10894809cb39326\nmsgid \"\"\n\"*(New in v1.17.5)* Optionally, some new \\\"reserved\\\" fontname codes \"\n\"become available if you install `pymupdf-fonts <https://pypi.org/project\"\n\"/pymupdf-fonts/>`_, `pip install pymupdf-fonts`. **\\\"Fira Mono\\\"** is a \"\n\"mono-spaced sans font set and **FiraGO** is another non-serifed \"\n\"\\\"universal\\\" font set which supports all Latin (including Cyrillic and \"\n\"Greek) plus Thai, Arabian, Hewbrew and Devanagari -- but none of the CJK \"\n\"languages. The size of a FiraGO font is only a quarter of the \\\"Droid \"\n\"Sans Fallback\\\" size (compressed 400 KB vs. 1.65 MB) -- **and** it \"\n\"provides the weights bold, italic, bold-italic -- which the universal \"\n\"font doesn't.\"\nmsgstr \"*(v1.17.5의 새로운 기능)* 선택적으로, `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ (`pip install pymupdf-fonts`)를 설치하면 일부 새로운 \\\"예약된\\\" 글꼴 이름 코드를 사용할 수 있습니다. **\\\"Fira Mono\\\"** 는 고정폭 산세리프 글꼴 세트이고 **FiraGO** 는 모든 라틴 문자(키릴 문자 및 그리스 문자 포함)와 태국어, 아랍어, 히브리어 및 데바나가리어를 지원하는 또 다른 비세리프 \\\"범용\\\" 글꼴 세트입니다 -- 하지만 CJK 언어는 지원하지 않습니다. FiraGO 글꼴의 크기는 \\\"Droid Sans Fallback\\\" 크기의 1/4에 불과합니다(압축 시 400 KB vs. 1.65 MB) -- **그리고** 굵게, 이탤릭, 굵은 이탤릭 가중치를 제공합니다 -- 범용 글꼴은 제공하지 않습니다.\"\n\n#: ../../font.rst:107 51115005ef5b45048d055b7507f8bde1\nmsgid \"\"\n\"**\\\"Space Mono\\\"** is another nice and small mono-spaced font from Google\"\n\" Fonts, which supports Latin Extended characters and comes with all 4 \"\n\"important weights.\"\nmsgstr \"**\\\"Space Mono\\\"** 는 Google Fonts의 또 다른 좋고 작은 고정폭 글꼴로, Latin Extended 문자를 지원하며 모든 4가지 중요한 가중치를 제공합니다.\"\n\n#: ../../font.rst:109 96727739a91940c6a331ed087081f309\nmsgid \"\"\n\"The following table maps a fontname code to the corresponding font. For \"\n\"the current content of the package please see its documentation:\"\nmsgstr \"다음 표는 글꼴 이름 코드를 해당 글꼴에 매핑합니다. 패키지의 현재 내용은 해당 문서를 참조하세요:\"\n\n#: ../../font.rst:112 1a8503b417cf4c8fada552e8610a6e75\nmsgid \"Code\"\nmsgstr \"Code\"\n\n#: ../../font.rst:112 2d8f3f6732334560b3d503193be52bed\nmsgid \"Fontname\"\nmsgstr \"Fontname\"\n\n#: ../../font.rst:112 c74b2b12e6aa454b8f2dbb4143ffd7bf\nmsgid \"New in\"\nmsgstr \"New in\"\n\n#: ../../font.rst:112 09250ac84f2f444481bee3de0bd29007\nmsgid \"Comment\"\nmsgstr \"Comment\"\n\n#: ../../font.rst:114 3092d884950f4b6eb710a9de0dd03966\nmsgid \"figo\"\nmsgstr \"figo\"\n\n#: ../../font.rst:114 660c171a6c564814aecb4286056ec31a\nmsgid \"FiraGO Regular\"\nmsgstr \"FiraGO Regular\"\n\n#: ../../font.rst:114 ../../font.rst:115 ../../font.rst:116 ../../font.rst:117\n#: ../../font.rst:118 ../../font.rst:119 3e80c8fdb0dd48d780069b2449ee507f\n#: 410d087d7e1243d1a54c1ae0aab172ac 6f27e46024f84abd97777e835ae6517f\n#: 794afaec71784e91b7e817f22ead4ffe baa94f214aea4d77a1a5fad071d449f1\n#: ed541c0c11684da3bebb342489caa3cb\nmsgid \"v1.0.0\"\nmsgstr \"v1.0.0\"\n\n#: ../../font.rst:114 aababde120ff4dbcbe21832121ff155b\nmsgid \"narrower than Helvetica\"\nmsgstr \"Helvetica보다 좁음\"\n\n#: ../../font.rst:115 01a9c98efef34d0aba6ba3fa0d37813b\nmsgid \"figbo\"\nmsgstr \"figbo\"\n\n#: ../../font.rst:115 b83719e8b5724cd69e516c29b9367ebb\nmsgid \"FiraGO Bold\"\nmsgstr \"FiraGO Bold\"\n\n#: ../../font.rst:116 4bbe563434c7425796dc77766d23c9c8\nmsgid \"figit\"\nmsgstr \"figit\"\n\n#: ../../font.rst:116 480523c94e564e26be18e84adb38e861\nmsgid \"FiraGO Italic\"\nmsgstr \"FiraGO Italic\"\n\n#: ../../font.rst:117 1e31c41d5df44c4fb09a83fdbd89e06d\nmsgid \"figbi\"\nmsgstr \"figbi\"\n\n#: ../../font.rst:117 0e71b818d3cd4256a6f49c7416f6b1ca\nmsgid \"FiraGO Bold Italic\"\nmsgstr \"FiraGO Bold Italic\"\n\n#: ../../font.rst:118 7137d532bea243b482a7189e3a3286f8\nmsgid \"fimo\"\nmsgstr \"fimo\"\n\n#: ../../font.rst:118 d52c3785bf6c4c6c9fa414b6953b3c21\nmsgid \"Fira Mono Regular\"\nmsgstr \"Fira Mono Regular\"\n\n#: ../../font.rst:119 a6bb6a057367406e8c6451c50221bd10\nmsgid \"fimbo\"\nmsgstr \"fimbo\"\n\n#: ../../font.rst:119 a9be831c53d643c381182387817e7347\nmsgid \"Fira Mono Bold\"\nmsgstr \"Fira Mono Bold\"\n\n#: ../../font.rst:120 2ff90048652c45d8ad808bd8e873a930\nmsgid \"spacemo\"\nmsgstr \"spacemo\"\n\n#: ../../font.rst:120 10b17a9bdac441b2a4af57265d22e503\nmsgid \"Space Mono Regular\"\nmsgstr \"Space Mono Regular\"\n\n#: ../../font.rst:120 ../../font.rst:121 ../../font.rst:122 ../../font.rst:123\n#: 71f76d3cde6b47a3b8a7a0a571913454 74e5c245413f43a1b0bcd54884d11f9b\n#: 811a2ce8ecf443c3b7c4a0009f550f69 ad9d314c839645d1b264c21f9d500a5d\nmsgid \"v1.0.1\"\nmsgstr \"v1.0.1\"\n\n#: ../../font.rst:121 cc6628c7c246454785eae18aa76df135\nmsgid \"spacembo\"\nmsgstr \"spacembo\"\n\n#: ../../font.rst:121 899d31ca415d4d60a771344775afb052\nmsgid \"Space Mono Bold\"\nmsgstr \"Space Mono Bold\"\n\n#: ../../font.rst:122 0fa8a8df23aa46a18ebc85a45faef555\nmsgid \"spacemit\"\nmsgstr \"spacemit\"\n\n#: ../../font.rst:122 121e740c51fa4e13b45b780076fdc770\nmsgid \"Space Mono Italic\"\nmsgstr \"Space Mono Italic\"\n\n#: ../../font.rst:123 8c761931925c4c9080802855c8de2158\nmsgid \"spacembi\"\nmsgstr \"spacembi\"\n\n#: ../../font.rst:123 c294981796074117b39f66e1d0fc697f\nmsgid \"Space Mono Bold-Italic\"\nmsgstr \"Space Mono Bold-Italic\"\n\n#: ../../font.rst:124 fb3d22993d774962addb0d5e18962566\nmsgid \"math\"\nmsgstr \"math\"\n\n#: ../../font.rst:124 d72ffadba17c47d98e45bad69d43f48a\nmsgid \"Noto Sans Math Regular\"\nmsgstr \"Noto Sans Math Regular\"\n\n#: ../../font.rst:124 ../../font.rst:125 ../../font.rst:126 ../../font.rst:127\n#: 4a51871589de44a49f3d817a3e4641ca a1e187ea3001421b848c3e15b2da294f\n#: c7f9419b4b474f9990c0e7b2548b89bd f44b20960c864e1a812db6b82ccc7b01\nmsgid \"v1.0.2\"\nmsgstr \"v1.0.2\"\n\n#: ../../font.rst:124 3527017ccae847e198b6aa3fd407bf86\nmsgid \"math symbols\"\nmsgstr \"수학 기호\"\n\n#: ../../font.rst:125 f0c044192be8422bbb062dcfe3fa3867\nmsgid \"music\"\nmsgstr \"music\"\n\n#: ../../font.rst:125 5091921f86b8478b884595a229b30799\nmsgid \"Noto Music Regular\"\nmsgstr \"Noto Music Regular\"\n\n#: ../../font.rst:125 0cfb05fc68a6412895e997a6f27ab557\nmsgid \"musical symbols\"\nmsgstr \"음악 기호\"\n\n#: ../../font.rst:126 198d0ac76851400696fd7bfe7e9c60b3\nmsgid \"symbol1\"\nmsgstr \"symbol1\"\n\n#: ../../font.rst:126 8bf74ea20b3d41c081691ba396ba7ec2\nmsgid \"Noto Sans Symbols Regular\"\nmsgstr \"Noto Sans Symbols Regular\"\n\n#: ../../font.rst:126 96ef9a86cd4c4af9ad70de3493072981\nmsgid \"replacement for \\\"symb\\\"\"\nmsgstr \"\\\"symb\\\"의 대체\"\n\n#: ../../font.rst:127 4eae35b6626f44edb67bbd03f28f00d6\nmsgid \"symbol2\"\nmsgstr \"symbol2\"\n\n#: ../../font.rst:127 b1fdca63e3d74dd29efec985e0b244dc\nmsgid \"Noto Sans Symbols2 Regular\"\nmsgstr \"Noto Sans Symbols2 Regular\"\n\n#: ../../font.rst:127 0bd6d32f20eb48dd988041621b3d5200\nmsgid \"extended symbol set\"\nmsgstr \"확장 기호 세트\"\n\n#: ../../font.rst:128 aa751e08f13849d1a55e72c6aebf8f49\nmsgid \"notos\"\nmsgstr \"notos\"\n\n#: ../../font.rst:128 89dea662c0eb4c7eb232a7fdba6ebc9a\nmsgid \"Noto Sans Regular\"\nmsgstr \"Noto Sans Regular\"\n\n#: ../../font.rst:128 ../../font.rst:129 ../../font.rst:130 ../../font.rst:131\n#: 459d3d0e43ff4bf5aa61c68e8e685e29 67cb7c095cf74781840d29e84aa0034b\n#: 91a98cec9643445d9d588f6c148714f4 d8bd23d980b1436583464316e47308db\nmsgid \"v1.0.3\"\nmsgstr \"v1.0.3\"\n\n#: ../../font.rst:128 6b98b595462b4d478057da307cdea30a\nmsgid \"alternative to Helvetica\"\nmsgstr \"Helvetica의 대체\"\n\n#: ../../font.rst:129 691a807af162494ab0b5af4186c9110c\nmsgid \"notosit\"\nmsgstr \"notosit\"\n\n#: ../../font.rst:129 24201a800ba0419c9bee4bf90edf8825\nmsgid \"Noto Sans Italic\"\nmsgstr \"Noto Sans Italic\"\n\n#: ../../font.rst:130 4dd91c5ba63544bba1ceb32e1fdefd55\nmsgid \"notosbo\"\nmsgstr \"notosbo\"\n\n#: ../../font.rst:130 ff244216f5904a4697fcab3f6d021a6a\nmsgid \"Noto Sans Bold\"\nmsgstr \"Noto Sans Bold\"\n\n#: ../../font.rst:131 aa8c2e1781f54593b3331c086c19b814\nmsgid \"notosbi\"\nmsgstr \"notosbi\"\n\n#: ../../font.rst:131 6857edcacab24c27817264bb11d9bdad\nmsgid \"Noto Sans BoldItalic\"\nmsgstr \"Noto Sans BoldItalic\"\n\n#: ../../font.rst:141 2a37a1a4a1aa4945b8df8dbf7e64e154\nmsgid \"\"\n\"Check whether the unicode ``chr`` exists in the font or (option) some \"\n\"fallback font. May be used to check whether any \\\"TOFU\\\" symbols will \"\n\"appear on output.\"\nmsgstr \"유니코드 ``chr`` 가 글꼴 또는 (선택적으로) 일부 대체 글꼴에 존재하는지 확인합니다. 출력에 \\\"TOFU\\\" 기호가 나타날지 확인하는 데 사용할 수 있습니다.\"\n\n#: ../../font.rst:143 009b9aeb3f9944d596e9f49f9899c324\nmsgid \"the unicode of the character (i.e. ``ord()``).\"\nmsgstr \"문자의 유니코드(즉, ``ord()``).\"\n\n#: ../../font.rst:144 a8641b2b63ec4b07875c388e202271b9\nmsgid \"the language -- currently unused.\"\nmsgstr \"언어 -- 현재 사용되지 않음.\"\n\n#: ../../font.rst:145 1bf9dc08f5954b5f965c6b5ea1570763\nmsgid \"the UCDN script number.\"\nmsgstr \"UCDN 스크립트 번호.\"\n\n#: ../../font.rst:146 c652199037ea41779589cd7c702796e7\nmsgid \"\"\n\"*(new in v1.17.5)* perform an extended search in fallback fonts or \"\n\"restrict to current font (default).\"\nmsgstr \"*(v1.17.5의 새로운 기능)* 대체 글꼴에서 확장 검색을 수행하거나 현재 글꼴로 제한합니다(기본값).\"\n\n#: ../../font.rst:147 97e5feeeb43a4af0bb9163c00cad3e2b\nmsgid \"*(changed in 1.17.7)* the glyph number. Zero indicates no glyph found.\"\nmsgstr \"*(1.17.7에서 변경됨)* 글리프 번호. 0은 글리프를 찾지 못했음을 나타냅니다.\"\n\n#: ../../font.rst:151 fed10a374e2445d1be29d1f78a496de5\nmsgid \"New in v1.17.5\"\nmsgstr \"v1.17.5에서 새로 추가됨\"\n\n#: ../../font.rst:153 290f44f3033a469e89d5444b5d3ec4f9\nmsgid \"Return an array of unicodes supported by this font.\"\nmsgstr \"이 글꼴이 지원하는 유니코드 배열을 반환합니다.\"\n\n#: ../../font.rst:155 ab16e827b27d4022b45b4c90a328da02\n#, python-format\nmsgid \"\"\n\"an ``array.array`` [#f2]_ of length at most :attr:`Font.glyph_count`. \"\n\"I.e. ``chr()`` of every item in this array has a glyph in the font \"\n\"without using fallbacks. This is an example display of the supported \"\n\"glyphs:  >>> import pymupdf >>> font = pymupdf.Font(\\\"math\\\") >>> vuc = \"\n\"font.valid_codepoints() >>> for i in vuc:       print(\\\"%04X %s (%s)\\\" % \"\n\"(i, chr(i), font.unicode_to_glyph_name(i))) 0000 000D   (CR) 0020   \"\n\"(space) 0021 ! (exclam) 0022 \\\" (quotedbl) 0023 # (numbersign) 0024 $ \"\n\"(dollar) 0025 % (percent) ... 00AC ¬ (logicalnot) 00B1 ± (plusminus) ... \"\n\"21D0 ⇐ (arrowdblleft) 21D1 ⇑ (arrowdblup) 21D2 ⇒ (arrowdblright) 21D3 ⇓ \"\n\"(arrowdbldown) 21D4 ⇔ (arrowdblboth) ... 221E ∞ (infinity) ...\"\nmsgstr \"\"\n\n#: ../../font.rst:155 7031be6a1bcf4a65b62350eb968608e6\nmsgid \"\"\n\"an ``array.array`` [#f2]_ of length at most :attr:`Font.glyph_count`. \"\n\"I.e. ``chr()`` of every item in this array has a glyph in the font \"\n\"without using fallbacks. This is an example display of the supported \"\n\"glyphs:\"\nmsgstr \"길이가 최대 :attr:`Font.glyph_count` 인 ``array.array`` [#f2]_. 즉, 이 배열의 모든 항목의 ``chr()`` 는 대체 글꼴을 사용하지 않고 글꼴에 글리프를 가집니다. 지원되는 글리프의 예제 표시는 다음과 같습니다:\"\n\n#: ../../font.rst:183 c5ad65fa71a74dd9a63ab09809f0f9cf\nmsgid \"\"\n\"This method only returns meaningful data for fonts having a CMAP \"\n\"(character map, charmap, the `/ToUnicode` PDF key). Otherwise, this array\"\n\" will have length 1 and contain zero only.\"\nmsgstr \"이 메서드는 CMAP(문자 맵, charmap, `/ToUnicode` PDF 키)가 있는 글꼴에 대해서만 의미 있는 데이터를 반환합니다. 그렇지 않으면 이 배열의 길이는 1이고 0만 포함합니다.\"\n\n#: ../../font.rst:192 af8b042889b54a38b2a5ddd689449328\nmsgid \"Calculate the \\\"width\\\" of the character's glyph (visual representation).\"\nmsgstr \"문자 글리프의 \\\"너비\\\"를 계산합니다(시각적 표현).\"\n\n#: ../../font.rst:194 c1f6c6b34907404e97ad72617e0fc346\nmsgid \"\"\n\"the unicode number of the character. Use ``ord()``, not the character \"\n\"itself. Again, this should normally work even if a character is not \"\n\"supported by that font, because fallback fonts will be checked where \"\n\"necessary.\"\nmsgstr \"문자의 유니코드 번호. 문자 자체가 아닌 ``ord()`` 를 사용하세요. 다시 말하지만, 글꼴이 문자를 지원하지 않더라도 일반적으로 작동해야 합니다. 필요한 경우 대체 글꼴이 확인되기 때문입니다.\"\n\n#: ../../font.rst:195 e838a07682d84a869e2fa1cc89abf58a\nmsgid \"write mode, ``0`` = horizontal, ``1`` = vertical.\"\nmsgstr \"쓰기 모드, ``0`` = 가로, ``1`` = 세로.\"\n\n#: ../../font.rst:197 2dc7e2ceacbb4ef690b919a430d04d1b\nmsgid \"The other parameters are not in use currently.\"\nmsgstr \"다른 매개변수는 현재 사용되지 않습니다.\"\n\n#: ../../font.rst:199 e8423a5397284db1919f456052773ded\nmsgid \"a float representing the glyph's width relative to **fontsize 1**.\"\nmsgstr \"**fontsize 1** 에 상대적인 글리프 너비를 나타내는 float.\"\n\n#: ../../font.rst:203 47dc9dab1b4c4cb8b9e6a069008d81b1\nmsgid \"\"\n\"Return the unicode value for a given glyph name. Use it in conjunction \"\n\"with `chr()` if you want to output e.g. a certain symbol.\"\nmsgstr \"주어진 글리프 이름에 대한 유니코드 값을 반환합니다. 예를 들어 특정 기호를 출력하려면 `chr()` 와 함께 사용하세요.\"\n\n#: ../../font.rst:205 749831c099134aa7bf7ffe282b0836b5\nmsgid \"The name of the glyph.\"\nmsgstr \"글리프의 이름.\"\n\n#: ../../font.rst:207 377293d9901943dbb4c7c31c7985c7d9\nmsgid \"\"\n\"The unicode integer, or 65533 = 0xFFFD if the name is unknown. Examples: \"\n\"`font.glyph_name_to_unicode(\\\"Sigma\\\") = 931`, \"\n\"`font.glyph_name_to_unicode(\\\"sigma\\\") = 963`. Refer to the `Adobe Glyph \"\n\"List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ publication for a list of glyph names \"\n\"and their unicode numbers. Example:  >>> font = pymupdf.Font(\\\"helv\\\") \"\n\">>> font.has_glyph(font.glyph_name_to_unicode(\\\"infinity\\\")) True\"\nmsgstr \"\"\n\n#: ../../font.rst:207 765a70f4e5934d66adf72deeaaad3599\nmsgid \"\"\n\"The unicode integer, or 65533 = 0xFFFD if the name is unknown. Examples: \"\n\"`font.glyph_name_to_unicode(\\\"Sigma\\\") = 931`, \"\n\"`font.glyph_name_to_unicode(\\\"sigma\\\") = 963`. Refer to the `Adobe Glyph \"\n\"List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ publication for a list of glyph names \"\n\"and their unicode numbers. Example:\"\nmsgstr \"유니코드 정수, 또는 이름을 알 수 없는 경우 65533 = 0xFFFD. 예: `font.glyph_name_to_unicode(\\\"Sigma\\\") = 931`, `font.glyph_name_to_unicode(\\\"sigma\\\") = 963`. 글리프 이름과 유니코드 번호 목록은 `Adobe Glyph List <https://github.com/adobe-type-tools/agl-aglfn/blob/master/glyphlist.txt>`_ 출판물을 참조하세요. 예:\"\n\n#: ../../font.rst:219 ceed99f4b1f641ae9879e4ef9b43cfcf\nmsgid \"The glyph rectangle relative to :data:`fontsize` 1.\"\nmsgstr \":data:`fontsize` 1에 상대적인 글리프 사각형.\"\n\n#: ../../font.rst:221 9803fc558ea94924824b3c6f36f33ce5\nmsgid \"``ord()`` of the character.\"\nmsgstr \"문자의 ``ord()``.\"\n\n#: ../../font.rst:223 cae0a18260bf47dcb9d033363ab5176b\nmsgid \"a :ref:`Rect`.\"\nmsgstr \":ref:`Rect`.\"\n\n#: ../../font.rst:228 c530486f148348589a870c1a6fad982d\nmsgid \"Show the name of the character's glyph.\"\nmsgstr \"문자 글리프의 이름을 표시합니다.\"\n\n#: ../../font.rst:230 b33374c8c5234c618bbb03b5c25bd99b\nmsgid \"\"\n\"the unicode number of the character. Use ``ord()``, not the character \"\n\"itself.\"\nmsgstr \"문자의 유니코드 번호. 문자 자체가 아닌 ``ord()`` 를 사용하세요.\"\n\n#: ../../font.rst:232 39265ca9c3774508a81f7b6c33627e8d\nmsgid \"\"\n\"a string representing the glyph's name. E.g. `font.glyph_name(ord(\\\"#\\\"))\"\n\" = \\\"numbersign\\\"`. For an invalid code \\\".notfound\\\" is returned.  .. \"\n\"note:: *(Changed in v1.18.0)* This method and \"\n\":meth:`Font.glyph_name_to_unicode` no longer depend on a font and instead\"\n\" retrieve information from the **Adobe Glyph List**. Also available as \"\n\"`pymupdf.unicode_to_glyph_name()` and resp. \"\n\"`pymupdf.glyph_name_to_unicode()`.\"\nmsgstr \"\"\n\n#: ../../font.rst:232 7b64931c6f244cfca3c0761329de7f73\nmsgid \"\"\n\"a string representing the glyph's name. E.g. `font.glyph_name(ord(\\\"#\\\"))\"\n\" = \\\"numbersign\\\"`. For an invalid code \\\".notfound\\\" is returned.\"\nmsgstr \"글리프 이름을 나타내는 문자열. 예: `font.glyph_name(ord(\\\"#\\\")) = \\\"numbersign\\\"`. 잘못된 코드의 경우 \\\".notfound\\\"가 반환됩니다.\"\n\n#: ../../font.rst:234 20712f7e063243888f6395b18c3acae8\nmsgid \"\"\n\"*(Changed in v1.18.0)* This method and :meth:`Font.glyph_name_to_unicode`\"\n\" no longer depend on a font and instead retrieve information from the \"\n\"**Adobe Glyph List**. Also available as `pymupdf.unicode_to_glyph_name()`\"\n\" and resp. `pymupdf.glyph_name_to_unicode()`.\"\nmsgstr \"*(v1.18.0에서 변경됨)* 이 메서드와 :meth:`Font.glyph_name_to_unicode` 는 더 이상 글꼴에 의존하지 않으며 대신 **Adobe Glyph List** 에서 정보를 검색합니다. `pymupdf.unicode_to_glyph_name()` 및 각각 `pymupdf.glyph_name_to_unicode()` 로도 사용할 수 있습니다.\"\n\n#: ../../font.rst:241 38b6209e6a4344a8b3be848dc476755c\nmsgid \"Calculate the length in points of a unicode string.\"\nmsgstr \"유니코드 문자열의 포인트 단위 길이를 계산합니다.\"\n\n#: ../../font.rst:243 142ac4b87bb644ffa8514275b3e51007\nmsgid \"\"\n\"There is a functional overlap with :meth:`get_text_length` for Base-14 \"\n\"fonts only.\"\nmsgstr \"Base-14 글꼴에 대해서만 :meth:`get_text_length` 와 기능적 중복이 있습니다.\"\n\n#: ../../font.rst:245 ../../font.rst:269 7c8abec195d7425ab74856419d327b59\n#: f31ddd69af474ca98115ec49230627cf\nmsgid \"a text string, UTF-8 encoded.\"\nmsgstr \"UTF-8로 인코딩된 텍스트 문자열.\"\n\n#: ../../font.rst:247 ../../font.rst:271 280e2e6390a84299b1eb50742751cc45\n#: 5880b72ffefe4073a534b44ef82aa00b\nmsgid \"the :data:`fontsize`.\"\nmsgstr \":data:`fontsize`.\"\n\n#: ../../font.rst 24af9fb41f6d40be800f9d6a56909af0\n#: 375fd3e160764b6f97a1b86fc740fe8a 465db7792c4b472f806017a0d364f367\n#: 53682f9b23a84002ab90b511020b49f6 5fa74d99fa99412f91d3a82aefa8e4bf\n#: 70db0a0a767e4ee8867951f816a54be0 9353b0e144af4fc7a2f47be5d63e325b\n#: b579c7fff96e4c608f8eb22666e2666d d2e13bff74024b768ddd4405202d6cab\n#: d3196a22363c47ecb37dd5972f00334e\nmsgid \"Return type\"\nmsgstr \"Return type\"\n\n#: ../../font.rst:251 ec7a7979f9e7418fbdceaeee4f29b39d\nmsgid \"\"\n\"the length of the string in points when stored in the PDF. If a character\"\n\" is not contained in the font, it will automatically be looked up in a \"\n\"fallback font.  .. note:: This method was originally implemented in \"\n\"Python, based on calling :meth:`Font.glyph_advance`. For performance \"\n\"reasons, it has been rewritten in C for v1.18.14. To compute the width of\"\n\" a single character, you can now use either of the following without \"\n\"performance penalty:     1. `font.glyph_advance(ord(\\\"Ä\\\")) * fontsize`\"\n\"    2. `font.text_length(\\\"Ä\\\", fontsize=fontsize)`     For multi-\"\n\"character strings, the method offers a huge performance advantage \"\n\"compared to the previous implementation: instead of about 0.5 \"\n\"microseconds for each character, only 12.5 nanoseconds are required for \"\n\"the second and subsequent ones.\"\nmsgstr \"\"\n\n#: ../../font.rst:251 f41d04198f2341a990157155d7f740b1\nmsgid \"\"\n\"the length of the string in points when stored in the PDF. If a character\"\n\" is not contained in the font, it will automatically be looked up in a \"\n\"fallback font.\"\nmsgstr \"PDF에 저장될 때 포인트 단위의 문자열 길이. 글꼴에 문자가 포함되어 있지 않으면 자동으로 대체 글꼴에서 찾습니다.\"\n\n#: ../../font.rst:253 57ccdf4bd0474e3280e1cdda9d041027\nmsgid \"\"\n\"This method was originally implemented in Python, based on calling \"\n\":meth:`Font.glyph_advance`. For performance reasons, it has been \"\n\"rewritten in C for v1.18.14. To compute the width of a single character, \"\n\"you can now use either of the following without performance penalty:\"\nmsgstr \"이 메서드는 원래 :meth:`Font.glyph_advance` 호출을 기반으로 Python에서 구현되었습니다. 성능상의 이유로 v1.18.14에서 C로 다시 작성되었습니다. 단일 문자의 너비를 계산하려면 성능 저하 없이 다음 중 하나를 사용할 수 있습니다:\"\n\n#: ../../font.rst:255 b485562f46994ef3a76ed0ba8f486f14\nmsgid \"`font.glyph_advance(ord(\\\"Ä\\\")) * fontsize`\"\nmsgstr \"`font.glyph_advance(ord(\\\"Ä\\\")) * fontsize`\"\n\n#: ../../font.rst:256 7b3106bb9bf0498198809c557ab60339\nmsgid \"`font.text_length(\\\"Ä\\\", fontsize=fontsize)`\"\nmsgstr \"`font.text_length(\\\"Ä\\\", fontsize=fontsize)`\"\n\n#: ../../font.rst:258 3724b3d50f664946b0d42d8fab2f84f6\nmsgid \"\"\n\"For multi-character strings, the method offers a huge performance \"\n\"advantage compared to the previous implementation: instead of about 0.5 \"\n\"microseconds for each character, only 12.5 nanoseconds are required for \"\n\"the second and subsequent ones.\"\nmsgstr \"다중 문자 문자열의 경우, 이 메서드는 이전 구현과 비교하여 큰 성능 이점을 제공합니다: 각 문자에 대해 약 0.5 마이크로초 대신 두 번째 및 이후 문자에는 12.5 나노초만 필요합니다.\"\n\n#: ../../font.rst:265 aafd060e84e541abbe7b30af94aa8ded\nmsgid \"*New in v1.18.14*\"\nmsgstr \"*v1.18.14에서 새로 추가됨*\"\n\n#: ../../font.rst:267 7decb74d1d39477b9462d29370e42a35\nmsgid \"Sequence of character lengths in points of a unicode string.\"\nmsgstr \"유니코드 문자열의 포인트 단위 문자 길이 시퀀스.\"\n\n#: ../../font.rst:275 76401a090dc249fcab049f83b6f83cee\nmsgid \"\"\n\"the lengths in points of the characters of a string when stored in the \"\n\"PDF. It works like :meth:`Font.text_length` broken down to single \"\n\"characters. This is a high speed method, used e.g. in \"\n\":meth:`TextWriter.fill_textbox`. The following is true (allowing rounding\"\n\" errors): `font.text_length(text) == sum(font.char_lengths(text))`.  >>> \"\n\"font = pymupdf.Font(\\\"helv\\\") >>> text = \\\"PyMuPDF\\\" >>> \"\n\"font.text_length(text) 50.115999937057495 >>> \"\n\"pymupdf.get_text_length(text, fontname=\\\"helv\\\") 50.115999937057495 >>> \"\n\"sum(font.char_lengths(text)) 50.115999937057495 >>> \"\n\"pprint(font.char_lengths(text)) (7.336999952793121,  # P 5.5,\"\n\"                 # y 9.163000047206879,   # M 6.115999937057495,   # u \"\n\"7.336999952793121,   # P 7.942000031471252,   # D 6.721000015735626)   # \"\n\"F\"\nmsgstr \"\"\n\n#: ../../font.rst:275 1544e745681a4b6da063619a2e9620b7\nmsgid \"\"\n\"the lengths in points of the characters of a string when stored in the \"\n\"PDF. It works like :meth:`Font.text_length` broken down to single \"\n\"characters. This is a high speed method, used e.g. in \"\n\":meth:`TextWriter.fill_textbox`. The following is true (allowing rounding\"\n\" errors): `font.text_length(text) == sum(font.char_lengths(text))`.\"\nmsgstr \"PDF에 저장될 때 문자열 문자의 포인트 단위 길이. :meth:`Font.text_length` 를 단일 문자로 분해한 것처럼 작동합니다. 이것은 고속 메서드이며 예를 들어 :meth:`TextWriter.fill_textbox` 에서 사용됩니다. 다음이 참입니다(반올림 오류 허용): `font.text_length(text) == sum(font.char_lengths(text))`.\"\n\n#: ../../font.rst:297 d80b29e9dd8c454da9c51b26d9cad2fe\nmsgid \"New in v1.17.6\"\nmsgstr \"v1.17.6에서 새로 추가됨\"\n\n#: ../../font.rst:299 30834747dcfd4dc48a79f57ad356cdd3\nmsgid \"Copy of the binary font file content.\"\nmsgstr \"바이너리 글꼴 파일 내용의 복사본.\"\n\n#: ../../font.rst:305 71cd13ec6bab4c46bb9c7dbb8108fb63\nmsgid \"\"\n\"A dictionary with various font properties, each represented as bools. \"\n\"Example for Helvetica::\"\nmsgstr \"각각 bool로 표현되는 다양한 글꼴 속성의 딕셔너리. Helvetica의 예::\"\n\n#: ../../font.rst:325 dbe85241cd3a4910a0da84236fc69d03\nmsgid \"Name of the font. May be \\\"\\\" or \\\"(null)\\\".\"\nmsgstr \"글꼴 이름. \\\"\\\" 또는 \\\"(null)\\\"일 수 있습니다.\"\n\n#: ../../font.rst:329 190864bf642d4836b3e8ed0493dc4672\nmsgid \"The font bbox. This is the maximum of its glyph bboxes.\"\nmsgstr \"글꼴 bbox. 이것은 글리프 bbox의 최대값입니다.\"\n\n#: ../../font.rst:331 33b968a3b28241e9a604dd232bd3bf7c\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../font.rst:337 38e95b49eec642f784ca39d58b0b40df\nmsgid \"The number of glyphs defined in the font.\"\nmsgstr \"글꼴에 정의된 글리프 수.\"\n\n#: ../../font.rst:341 ../../font.rst:349 aa9a0f03418b4adba2109af305a941e1\n#: b18be968a53743bdb4bdab316af4c374\nmsgid \"New in v1.18.0\"\nmsgstr \"v1.18.0에서 새로 추가됨\"\n\n#: ../../font.rst:343 d3c64bfaff7540aa857c6dcc2fc2b0a0\nmsgid \"\"\n\"The ascender value of the font, see `ascender typography \"\n\"<https://en.wikipedia.org/wiki/Ascender_(typography)>`_ for details. \"\n\"Please note that there is a difference to the strict definition: our \"\n\"value includes everything above the baseline -- not just the height \"\n\"difference between upper case \\\"A\\\" and and lower case \\\"a\\\".\"\nmsgstr \"글꼴의 상승부 값, 자세한 내용은 `ascender typography <https://en.wikipedia.org/wiki/Ascender_(typography)>`_ 를 참조하세요. 엄격한 정의와 차이가 있음을 참고하세요: 우리의 값은 기준선 위의 모든 것을 포함합니다 -- 대문자 \\\"A\\\"와 소문자 \\\"a\\\" 사이의 높이 차이만이 아닙니다.\"\n\n#: ../../font.rst:351 7fba1bd77fd74cc1abdb335fe3269fbc\nmsgid \"\"\n\"The descender value of the font, see `descender typography \"\n\"<https://en.wikipedia.org/wiki/Descender>`_ for details. This value \"\n\"always is negative and is the portion that some glyphs descend below the \"\n\"base line, for example \\\"g\\\" or \\\"y\\\". As a consequence, the value \"\n\"`ascender - descender` is the total height, that every glyph of the font \"\n\"fits into. This is true at least for most fonts -- as always, there are \"\n\"exceptions, especially for calligraphic fonts, etc.\"\nmsgstr \"글꼴의 하강부 값, 자세한 내용은 `descender typography <https://en.wikipedia.org/wiki/Descender>`_ 를 참조하세요. 이 값은 항상 음수이며 일부 글리프가 기준선 아래로 내려가는 부분입니다. 예를 들어 \\\"g\\\" 또는 \\\"y\\\". 결과적으로 `ascender - descender` 값은 글꼴의 모든 글리프가 들어맞는 전체 높이입니다. 이것은 적어도 대부분의 글꼴에 대해 참입니다 -- 항상 그렇듯이 예외가 있으며, 특히 필기체 글꼴 등에 해당합니다.\"\n\n#: ../../font.rst:363 4ffede0fc21c4b5fa0f667a903b92e93\nmsgid \"\"\n\"A number of attributes with obvious meanings. Reflect some values of the \"\n\":attr:`Font.flags` dictionary.\"\nmsgstr \"명확한 의미를 가진 여러 속성. :attr:`Font.flags` 딕셔너리의 일부 값을 반영합니다.\"\n\n#: ../../font.rst:368 4bd92baafe77479faa63b31082e0c69a\nmsgid \"Footnotes\"\nmsgstr \"Footnotes\"\n\n#: ../../font.rst:369 d66637c72e2b45aea7edd3cb116ec328\nmsgid \"\"\n\"MuPDF does not support all fontfiles with this feature and will raise \"\n\"exceptions like *\\\"mupdf: FT_New_Memory_Face((null)): unknown file \"\n\"format\\\"*, if it encounters issues.\"\nmsgstr \"MuPDF는 이 기능을 가진 모든 글꼴 파일을 지원하지 않으며 문제가 발생하면 *\\\"mupdf: FT_New_Memory_Face((null)): unknown file format\\\"* 과 같은 예외를 발생시킵니다.\"\n\n#: ../../font.rst:371 7213fcc59c214e508d3da6221ec0d21a\nmsgid \"\"\n\"The built-in Python module `array` has been chosen for its speed and low \"\n\"memory requirement.\"\nmsgstr \"내장 Python 모듈 `array` 는 속도와 낮은 메모리 요구 사항 때문에 선택되었습니다.\"\n\n#: ../../footer.rst:46 3dc04747492b4b4bac6e2c6af8d83002\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/footer.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../footer.rst:46 6174f91a653847f0bf61a4cba1c92a19\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/functions.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-03 09:30+0900\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../header.rst:-1 d5eaf8f36ea24d1fa23ebb1e8e41a90a\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 8b803decc5f34c5fb8ad982980d7c72a\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 e66a1624a18842059b9907685b6c923b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../functions.rst:5 09639c24e337417f91e7de56ce3925a9\nmsgid \"Functions\"\nmsgstr \"함수\"\n\n#: ../../functions.rst:6 d241bcc35bc04fe898c335516878e3b2\nmsgid \"\"\n\"The following are miscellaneous functions and attributes on a fairly low-\"\n\"level technical detail.\"\nmsgstr \"다음은 상당히 낮은 수준의 기술 세부 사항에 대한 다양한 함수 및 속성입니다.\"\n\n#: ../../functions.rst:8 59b2d7e5074348b69fc146b45b000d70\nmsgid \"\"\n\"Some functions provide detail access to PDF structures. Others are \"\n\"stripped-down, high performance versions of other functions which provide\"\n\" more information.\"\nmsgstr \"\"\n\"일부 함수는 PDF 구조에 대한 세부 액세스를 제공합니다. 다른 함수들은 더 많은 정보를 제공하는 다른 함수들의 간소화된 고성능 \"\n\"버전입니다.\"\n\n#: ../../functions.rst:10 ea218c4b21c34a54b5241255f2274c27\nmsgid \"Yet others are handy, general-purpose utilities.\"\nmsgstr \"또 다른 함수들은 편리한 범용 유틸리티입니다.\"\n\n#: ../../functions.rst:14 26226f6d78b94bbfbc116c90ec1b1667\nmsgid \"**Function**\"\nmsgstr \"**함수**\"\n\n#: ../../functions.rst:14 8b717e28bda34d8bb8d5d4a899346921\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../functions.rst:16 4fa827142fed47519193771ca5b08092\nmsgid \":attr:`Annot.apn_bbox`\"\nmsgstr \"\"\n\n#: ../../functions.rst:16 5e724998a2fe42beb8664ac646bf06a5\nmsgid \"PDF only: bbox of the appearance object\"\nmsgstr \"PDF 전용: 외관 객체의 bbox\"\n\n#: ../../functions.rst:17 e888ae87ebb64c36a00f993c271f9619\nmsgid \":attr:`Annot.apn_matrix`\"\nmsgstr \"\"\n\n#: ../../functions.rst:17 fb98b796e0944e88843ee6b73c5462c8\nmsgid \"PDF only: the matrix of the appearance object\"\nmsgstr \"PDF 전용: 외관 객체의 행렬\"\n\n#: ../../functions.rst:18 c82ca559939b4f2999f22b393c9c49c5\nmsgid \":attr:`Page.is_wrapped`\"\nmsgstr \"\"\n\n#: ../../functions.rst:18 8b72a57f280b43758c83633f4cab7d86\nmsgid \"check whether contents wrapping is present\"\nmsgstr \"콘텐츠 래핑이 있는지 확인\"\n\n#: ../../functions.rst:19 5ef421856e0e4d2283f1bfc84b188fff\nmsgid \":meth:`adobe_glyph_names`\"\nmsgstr \"\"\n\n#: ../../functions.rst:19 3472f840e3f842c182821e72f04801f6\nmsgid \"list of glyph names defined in **Adobe Glyph List**\"\nmsgstr \"**Adobe Glyph List** 에 정의된 글리프 이름 목록\"\n\n#: ../../functions.rst:20 752b3e5acbe2461694cdae2a674c5f9f\nmsgid \":meth:`adobe_glyph_unicodes`\"\nmsgstr \"\"\n\n#: ../../functions.rst:20 5328c789e05a4c84bb18faf4f590624c\nmsgid \"list of unicodes defined in **Adobe Glyph List**\"\nmsgstr \"**Adobe Glyph List** 에 정의된 유니코드 목록\"\n\n#: ../../functions.rst:21 31f74aa2555c4a34831b22a7e91f4d78\nmsgid \":meth:`Annot.clean_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:21 2f6aed921d3244e9864151ff2181d926\nmsgid \"PDF only: clean the annot's :data:`contents` object\"\nmsgstr \"PDF 전용: 주석의 :data:`contents` 객체 정리\"\n\n#: ../../functions.rst:22 8b78b1dcdb9e48ec904da6e3afd94f81\nmsgid \":meth:`Annot.set_apn_bbox`\"\nmsgstr \"\"\n\n#: ../../functions.rst:22 1f6854c2e8d647daa789426623c1beb8\nmsgid \"PDF only: set the bbox of the appearance object\"\nmsgstr \"PDF 전용: 외관 객체의 bbox 설정\"\n\n#: ../../functions.rst:23 3857c8ee2f5748ffaa4bb8a896d72d65\nmsgid \":meth:`Annot.set_apn_matrix`\"\nmsgstr \"\"\n\n#: ../../functions.rst:23 8e746324795541b98d2337928d494ac9\nmsgid \"PDF only: set the matrix of the appearance object\"\nmsgstr \"PDF 전용: 외관 객체의 행렬 설정\"\n\n#: ../../functions.rst:24 fe9bc78339d044edb57af998111e0e94\nmsgid \":meth:`ConversionHeader`\"\nmsgstr \"\"\n\n#: ../../functions.rst:24 c9d53709f3ec4313886ef34c2592dc2a\nmsgid \"return header string for *get_text* methods\"\nmsgstr \"*get_text* 메서드에 대한 헤더 문자열 반환\"\n\n#: ../../functions.rst:25 f42819297e9c4f5a9d89b2bd6705b29d\nmsgid \":meth:`ConversionTrailer`\"\nmsgstr \"\"\n\n#: ../../functions.rst:25 6c0ab36cb3184db4a0865841dad35fb3\nmsgid \"return trailer string for *get_text* methods\"\nmsgstr \"*get_text* 메서드에 대한 트레일러 문자열 반환\"\n\n#: ../../functions.rst:26 5e2606a6e2424e1abef37d5a5336d192\nmsgid \":meth:`Document.del_xml_metadata`\"\nmsgstr \"\"\n\n#: ../../functions.rst:26 ed1d451869034ee1818820271d019376\nmsgid \"PDF only: remove XML metadata\"\nmsgstr \"PDF 전용: XML 메타데이터 제거\"\n\n#: ../../functions.rst:27 732e7fffe1c647dab7c6d9fcf6828ce2\nmsgid \":meth:`Document.get_char_widths`\"\nmsgstr \"\"\n\n#: ../../functions.rst:27 351bf40e0c10489fa167be35cbeede88\nmsgid \"PDF only: return a list of glyph widths of a font\"\nmsgstr \"PDF 전용: 글꼴의 글리프 너비 목록 반환\"\n\n#: ../../functions.rst:28 9ec9c0e0a2694a88b5162cedf7e99d3c\nmsgid \":meth:`Document.get_new_xref`\"\nmsgstr \"\"\n\n#: ../../functions.rst:28 8a4cabef920b48208011d74894909090\nmsgid \"PDF only: create and return a new :data:`xref` entry\"\nmsgstr \"PDF 전용: 새로운 :data:`xref` 항목 생성 및 반환\"\n\n#: ../../functions.rst:29 25a750f17eb440d7afc91b91de3c51dc\nmsgid \":meth:`Document.is_stream`\"\nmsgstr \"\"\n\n#: ../../functions.rst:29 80d8b21e19054578869eb0f4170ed472\nmsgid \"PDF only: check whether an :data:`xref` is a stream object\"\nmsgstr \"PDF 전용: :data:`xref` 가 스트림 객체인지 확인\"\n\n#: ../../functions.rst:30 b7e1dc4e790c41619345dbe8ca19c53f\nmsgid \":meth:`Document.xml_metadata_xref`\"\nmsgstr \"\"\n\n#: ../../functions.rst:30 e969dc0606e341eaaa57453eb8eef3fe\nmsgid \"PDF only: return XML metadata :data:`xref` number\"\nmsgstr \"PDF 전용: XML 메타데이터 :data:`xref` 번호 반환\"\n\n#: ../../functions.rst:31 d7b9b54aaece4890a119fc28f0b0213d\nmsgid \":meth:`Document.xref_length`\"\nmsgstr \"\"\n\n#: ../../functions.rst:31 0d5124e0366f4b279c0caecef1badf22\nmsgid \"PDF only: return length of :data:`xref` table\"\nmsgstr \"PDF 전용: :data:`xref` 테이블의 길이 반환\"\n\n#: ../../functions.rst:32 7e5cb32316f046989fdfc51b848af3a5\nmsgid \":meth:`EMPTY_IRECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:32 ../../functions.rst:34\n#: 72f212b14bbe40e991e86ece2cc1c252 db2699336cdf40c7acc4bcbba7fc31cd\nmsgid \"return the (standard) empty / invalid rectangle\"\nmsgstr \"(표준) 빈/유효하지 않은 사각형 반환\"\n\n#: ../../functions.rst:33 18064cd07e9b45088a8b5121afcc373a\nmsgid \":meth:`EMPTY_QUAD`\"\nmsgstr \"\"\n\n#: ../../functions.rst:33 2d74cea507794a8cabc329254264d867\nmsgid \"return the (standard) empty / invalid quad\"\nmsgstr \"(표준) 빈/유효하지 않은 쿼드 반환\"\n\n#: ../../functions.rst:34 ca50d2c7ddf8434698c2247b7063acff\nmsgid \":meth:`EMPTY_RECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:35 89d408ccc68d4ce39653e0d907c85295\nmsgid \":meth:`get_pdf_now`\"\nmsgstr \"\"\n\n#: ../../functions.rst:35 48f14174d2e34dbfb19df27001f24fec\nmsgid \"return the current timestamp in PDF format\"\nmsgstr \"PDF 형식의 현재 타임스탬프 반환\"\n\n#: ../../functions.rst:36 cbcbe41ecf5e43edad6d095ce00f09c1\nmsgid \":meth:`get_pdf_str`\"\nmsgstr \"\"\n\n#: ../../functions.rst:36 39f2a8a1b0c143298f9393ea1ed57297\nmsgid \"return PDF-compatible string\"\nmsgstr \"PDF 호환 문자열 반환\"\n\n#: ../../functions.rst:37 3d87a50d6b304a6191cd03adecdbf8c5\nmsgid \":meth:`get_text_length`\"\nmsgstr \"\"\n\n#: ../../functions.rst:37 8c4282d6eaab449490037c18b06197cc\nmsgid \"return string length for a given font & :data:`fontsize`\"\nmsgstr \"주어진 글꼴 및 :data:`fontsize` 에 대한 문자열 길이 반환\"\n\n#: ../../functions.rst:38 33b7cf546f184f529efbb76c2b68f01c\nmsgid \":meth:`glyph_name_to_unicode`\"\nmsgstr \"\"\n\n#: ../../functions.rst:38 cef00a6424564bb88d7ff3da7f59a57f\nmsgid \"return unicode from a glyph name\"\nmsgstr \"글리프 이름에서 유니코드 반환\"\n\n#: ../../functions.rst:39 b92854863247412db8a57b9e4dec0ff2\nmsgid \":meth:`image_profile`\"\nmsgstr \"\"\n\n#: ../../functions.rst:39 0babe345f56341e08a6ce5c46190ae85\nmsgid \"return a dictionary of basic image properties\"\nmsgstr \"기본 이미지 속성의 딕셔너리 반환\"\n\n#: ../../functions.rst:40 d15b2478761c42778f75793f3b52e20f\nmsgid \":meth:`INFINITE_IRECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:40 ../../functions.rst:42\n#: 531c629266ac4ddf9cf8b93162d99d86 9e3ea8aaed944e1b9dec93f4527643f6\nmsgid \"return the (only existing) infinite rectangle\"\nmsgstr \"(유일하게 존재하는) 무한 사각형 반환\"\n\n#: ../../functions.rst:41 06d5cc18fcbf40d6bb99b294dade3c86\nmsgid \":meth:`INFINITE_QUAD`\"\nmsgstr \"\"\n\n#: ../../functions.rst:41 efe4f04d259c43cfa7a294ef6b37e674\nmsgid \"return the (only existing) infinite quad\"\nmsgstr \"(유일하게 존재하는) 무한 쿼드 반환\"\n\n#: ../../functions.rst:42 4ebe8dc0e1a94750958a022b23527ae7\nmsgid \":meth:`INFINITE_RECT`\"\nmsgstr \"\"\n\n#: ../../functions.rst:43 810dbb2ba3574ea4a2a27ea13faeb3ed\nmsgid \":meth:`make_table`\"\nmsgstr \"\"\n\n#: ../../functions.rst:43 1d2dd96b457c447080a9455ad8ba3d02\nmsgid \"split rectangle in sub-rectangles\"\nmsgstr \"사각형을 하위 사각형으로 분할\"\n\n#: ../../functions.rst:44 4efadc8238ca4c81880285681a275b59\nmsgid \":meth:`Page.clean_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:44 78470e69571940789a87fa57faa9e6db\nmsgid \"PDF only: clean the page's :data:`contents` objects\"\nmsgstr \"PDF 전용: 페이지의 :data:`contents` 객체 정리\"\n\n#: ../../functions.rst:45 6083fb6360c44b32b75dce123ed47366\nmsgid \":meth:`Page.get_bboxlog`\"\nmsgstr \"\"\n\n#: ../../functions.rst:45 73f845fdf7ef46e4971320b572f4db8b\nmsgid \"list of rectangles that envelop text, drawing or image objects\"\nmsgstr \"텍스트, 그리기 또는 이미지 객체를 둘러싸는 사각형 목록\"\n\n#: ../../functions.rst:46 80028783aab041c69b426c082d2aa6df\nmsgid \":meth:`Page.get_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:46 74a19434f8f246f19e61fe238b478907\nmsgid \"PDF only: return a list of content :data:`xref` numbers\"\nmsgstr \"PDF 전용: 콘텐츠 :data:`xref` 번호 목록 반환\"\n\n#: ../../functions.rst:47 019c93458efe4182a147120a0cc10b3e\nmsgid \":meth:`Page.get_displaylist`\"\nmsgstr \"\"\n\n#: ../../functions.rst:47 a44e43abf2dc456f8337f43c185d948e\nmsgid \"create the page's display list\"\nmsgstr \"페이지의 디스플레이 리스트 생성\"\n\n#: ../../functions.rst:48 58150969be474967b037cf952a6c031f\nmsgid \":meth:`Page.get_text_blocks`\"\nmsgstr \"\"\n\n#: ../../functions.rst:48 f0b458ff737845fea22ed316da32926a\nmsgid \"extract text blocks as a Python list\"\nmsgstr \"텍스트 블록을 Python 리스트로 추출\"\n\n#: ../../functions.rst:49 216b4f80f83c4bbcb187c35eb3ee8e40\nmsgid \":meth:`Page.get_text_words`\"\nmsgstr \"\"\n\n#: ../../functions.rst:49 9895bb7c031d4f20b8a5191f4dfd8167\nmsgid \"extract text words as a Python list\"\nmsgstr \"텍스트 단어를 Python 리스트로 추출\"\n\n#: ../../functions.rst:50 1112723c3d914a8eb485016e2e43eb25\nmsgid \":meth:`Page.get_texttrace`\"\nmsgstr \"\"\n\n#: ../../functions.rst:50 7a2b3074f96a4a2284ec5f7fceb0f40f\nmsgid \"low-level text information\"\nmsgstr \"저수준 텍스트 정보\"\n\n#: ../../functions.rst:51 9b6b7e72a5104179aa2df4fd9adbbbcf\nmsgid \":meth:`Page.read_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:51 934be2410e654699924480d3599ec1fb\nmsgid \"PDF only: get complete, concatenated /Contents source\"\nmsgstr \"PDF 전용: 완전하고 연결된 /Contents 소스 가져오기\"\n\n#: ../../functions.rst:52 d3db73a2b79141b0bed19fdd1f6ca764\nmsgid \":meth:`Page.run`\"\nmsgstr \"\"\n\n#: ../../functions.rst:52 4902d89cf4b144069ba225a193fe2332\nmsgid \"run a page through a device\"\nmsgstr \"디바이스를 통해 페이지 실행\"\n\n#: ../../functions.rst:53 0b2357ceef874b5c81bd4ac101078751\nmsgid \":meth:`Page.set_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:53 140d86f801f447ba932d4d0da1636bdf\nmsgid \"PDF only: set page's :data:`contents` to some :data:`xref`\"\nmsgstr \"PDF 전용: 페이지의 :data:`contents` 를 일부 :data:`xref` 로 설정\"\n\n#: ../../functions.rst:54 4607ba0bc87a49029f60b94358164e9a\nmsgid \":meth:`Page.wrap_contents`\"\nmsgstr \"\"\n\n#: ../../functions.rst:54 71d87e984ed1426f994fbda70a1d5acc\nmsgid \"wrap contents with stacking commands\"\nmsgstr \"스택 명령으로 콘텐츠 래핑\"\n\n#: ../../functions.rst:55 eab975358f5e45f88237eb38bf7efcc2\nmsgid \":meth:`css_for_pymupdf_font`\"\nmsgstr \"\"\n\n#: ../../functions.rst:55 7369ac5afa2a4f87af7504d05e2e95ec\nmsgid \"create CSS source for a font in package pymupdf_fonts\"\nmsgstr \"pymupdf_fonts 패키지의 글꼴에 대한 CSS 소스 생성\"\n\n#: ../../functions.rst:56 ea96727f97604aa2be9fd94c2b0e4e99\nmsgid \":meth:`paper_rect`\"\nmsgstr \"\"\n\n#: ../../functions.rst:56 4a64de49215140bb9095a7b744a6b10c\nmsgid \"return rectangle for a known paper format\"\nmsgstr \"알려진 용지 형식에 대한 사각형 반환\"\n\n#: ../../functions.rst:57 63fe68f42d76418396af541b4387963f\nmsgid \":meth:`paper_size`\"\nmsgstr \"\"\n\n#: ../../functions.rst:57 bac6f74069d54638915a9402b2fdd32b\nmsgid \"return width, height for a known paper format\"\nmsgstr \"알려진 용지 형식에 대한 너비, 높이 반환\"\n\n#: ../../functions.rst:58 9d17a64027f048e89712567847e77387\nmsgid \":meth:`paper_sizes`\"\nmsgstr \"\"\n\n#: ../../functions.rst:58 0a3c490c678640d69903658293fb99cd\nmsgid \"dictionary of pre-defined paper formats\"\nmsgstr \"사전 정의된 용지 형식의 딕셔너리\"\n\n#: ../../functions.rst:59 95cabe729c624a44a074886bc5ba5370\nmsgid \":meth:`planish_line`\"\nmsgstr \"\"\n\n#: ../../functions.rst:59 2c80744fd3094705a838e077b3751f09\nmsgid \"matrix to map a line to the x-axis\"\nmsgstr \"선을 x축에 매핑하는 행렬\"\n\n#: ../../functions.rst:60 6d4a42f1a6034615a841e64b17bd95c6\nmsgid \":meth:`recover_char_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:60 7509fe7ee06541f2a83976c0820c751f\nmsgid \"compute the quad of a char (\\\"rawdict\\\")\"\nmsgstr \"문자(\\\"rawdict\\\")의 쿼드 계산\"\n\n#: ../../functions.rst:61 2dd22daf6b254298b3521c5d8c0c2fc1\nmsgid \":meth:`recover_line_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:61 c17fb3f0647848dd9b2d0c9f3375a900\nmsgid \"compute the quad of a subset of line spans\"\nmsgstr \"라인 스팬의 하위 집합의 쿼드 계산\"\n\n#: ../../functions.rst:62 69103e21e70648a2ab8f3cedab21fa40\nmsgid \":meth:`recover_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:62 d6b90efa394f4fc98f8d557ba6118854\nmsgid \"compute the quad of a span (\\\"dict\\\", \\\"rawdict\\\")\"\nmsgstr \"스팬(\\\"dict\\\", \\\"rawdict\\\")의 쿼드 계산\"\n\n#: ../../functions.rst:63 e95190855477414fa2fc9b2a462e4d1f\nmsgid \":meth:`recover_span_quad`\"\nmsgstr \"\"\n\n#: ../../functions.rst:63 dae88b36bbbb4bbcbe86f14575a8c742\nmsgid \"compute the quad of a subset of span characters\"\nmsgstr \"스팬 문자의 하위 집합의 쿼드 계산\"\n\n#: ../../functions.rst:64 a538219c85a948b5bc32b5a86f54ee04\nmsgid \":meth:`set_messages`\"\nmsgstr \"\"\n\n#: ../../functions.rst:64 76a9ba8c6de9444caf517346bcd72399\nmsgid \"set destination of |PyMuPDF| messages.\"\nmsgstr \"|PyMuPDF| 메시지의 대상 설정.\"\n\n#: ../../functions.rst:65 fdb49d59408d4dec91a14dde94092f4f\nmsgid \":meth:`sRGB_to_pdf`\"\nmsgstr \"\"\n\n#: ../../functions.rst:65 f871b9297499486d852fd3f0e8a3676a\nmsgid \"return PDF RGB color tuple from an sRGB integer\"\nmsgstr \"sRGB 정수에서 PDF RGB 색상 튜플 반환\"\n\n#: ../../functions.rst:66 327a435d7e884c0a902aafda1893f6a7\nmsgid \":meth:`sRGB_to_rgb`\"\nmsgstr \"\"\n\n#: ../../functions.rst:66 246a589ca6424f2b9c09f5e823900a8d\nmsgid \"return (R, G, B) color tuple from an sRGB integer\"\nmsgstr \"sRGB 정수에서 (R, G, B) 색상 튜플 반환\"\n\n#: ../../functions.rst:67 c26211e2c9694a568170ed73ec08e6f6\nmsgid \":meth:`unicode_to_glyph_name`\"\nmsgstr \"\"\n\n#: ../../functions.rst:67 d3eb6eb48d2d404eaaa3e9647e0a61f0\nmsgid \"return glyph name from a unicode\"\nmsgstr \"유니코드에서 글리프 이름 반환\"\n\n#: ../../functions.rst:68 ac57370c0a6f47c3bed79dff45b3725c\nmsgid \":meth:`get_tessdata`\"\nmsgstr \"\"\n\n#: ../../functions.rst:68 e421bbfb598845dbb4469660bec7f8ca\nmsgid \"locates the language support of the Tesseract-OCR installation\"\nmsgstr \"Tesseract-OCR 설치의 언어 지원 위치 찾기\"\n\n#: ../../functions.rst:69 30abe7bbaaf24d3ba1760238b668f05b\nmsgid \":meth:`colors_pdf_dict`\"\nmsgstr \"\"\n\n#: ../../functions.rst:69 939ec09248774b08b319cff1387a78b3\nmsgid \"return dict of color names.\"\nmsgstr \"색상 이름의 딕셔너리 반환.\"\n\n#: ../../functions.rst:70 08f7a427489c42dc81382f68ac951d07\nmsgid \":meth:`colors_wx_list`\"\nmsgstr \"\"\n\n#: ../../functions.rst:70 c03e3b32246e48eca7222869de63d165\nmsgid \"return list of color names.\"\nmsgstr \"색상 이름의 리스트 반환.\"\n\n#: ../../functions.rst:71 00ff5455c39348df865165ef97c332e5\nmsgid \":attr:`fitz_fontdescriptors`\"\nmsgstr \"\"\n\n#: ../../functions.rst:71 29c5c32218fe4af9b066941c79193e99\nmsgid \"dictionary of available supplement fonts\"\nmsgstr \"사용 가능한 보조 글꼴의 딕셔너리\"\n\n#: ../../functions.rst:72 5e5557a7d7264b349905502aa39e0262\nmsgid \":attr:`PYMUPDF_MESSAGE`\"\nmsgstr \"\"\n\n#: ../../functions.rst:72 12be48b55f14460a82c486c307066c6b\nmsgid \"destination of |PyMuPDF| messages.\"\nmsgstr \"|PyMuPDF| 메시지의 대상.\"\n\n#: ../../functions.rst:73 93033092a17644e796bdfc012b3fe2ed\nmsgid \":attr:`pdfcolor`\"\nmsgstr \"\"\n\n#: ../../functions.rst:73 e11234c49747439eb115b333174c8a11\nmsgid \"dictionary of almost 500 RGB colors in PDF format.\"\nmsgstr \"PDF 형식의 약 500개의 RGB 색상 딕셔너리.\"\n\n#: ../../functions.rst:78 7731072bafdc4e0e948164d83aac73e6\nmsgid \"\"\n\"Convenience function to return width and height of a known paper format \"\n\"code. These values are given in pixels for the standard resolution 72 \"\n\"pixels = 1 inch.\"\nmsgstr \"\"\n\"알려진 용지 형식 코드의 너비와 높이를 반환하는 편의 함수. 이러한 값은 표준 해상도 72 픽셀 = 1 인치에 대한 픽셀 단위로 \"\n\"제공됩니다.\"\n\n#: ../../functions.rst:80 97f1a71cac764c60a6158645492260ad\nmsgid \"\"\n\"Currently defined formats include **'A0'** through **'A10'**, **'B0'** \"\n\"through **'B10'**, **'C0'** through **'C10'**, **'Card-4x6'**, **'Card-\"\n\"5x7'**, **'Commercial'**, **'Executive'**, **'Invoice'**, **'Ledger'**, \"\n\"**'Legal'**, **'Legal-13'**, **'Letter'**, **'Monarch'** and **'Tabloid-\"\n\"Extra'**, each in either portrait or landscape format.\"\nmsgstr \"\"\n\"현재 정의된 형식에는 **'A0'** 부터 **'A10'**, **'B0'** 부터 **'B10'**, **'C0'** 부터 \"\n\"**'C10'**, **'Card-4x6'**, **'Card-5x7'**, **'Commercial'**, \"\n\"**'Executive'**, **'Invoice'**, **'Ledger'**, **'Legal'**, \"\n\"**'Legal-13'**, **'Letter'**, **'Monarch'** 및 **'Tabloid-Extra'** 가 포함되며,\"\n\" 각각 세로 또는 가로 형식으로 제공됩니다.\"\n\n#: ../../functions.rst:82 dc2a6be14366471dac1a6479494f9346\nmsgid \"\"\n\"A format name must be supplied as a string (case **in** \\\\sensitive), \"\n\"optionally suffixed with \\\"-L\\\" (landscape) or \\\"-P\\\" (portrait). No \"\n\"suffix defaults to portrait.\"\nmsgstr \"\"\n\"형식 이름은 문자열로 제공해야 하며(대소문자 **구분 안 함**), 선택적으로 \\\"-L\\\"(가로) 또는 \\\"-P\\\"(세로) 접미사를\"\n\" 붙일 수 있습니다. 접미사가 없으면 기본값은 세로입니다.\"\n\n#: ../../functions.rst 03018f66ae484e3db8b6ad2826a044cf\n#: 0a0669e521764612bda971525dda452a 12ea19fbec324aef8554866eb1efd555\n#: 17b4cefc4a164f34978aa987685343a9 1b57ba0eba1e416191010aa7a215b711\n#: 1cab8cc500bf48f18a85666579c09fbc 2e96fcb875274281a1347e2eb8addec5\n#: 31229e3f712b437c916b0d922411d521 34b10c8b64ee455e952eb5d9cf6b1a80\n#: 3613e5ea12d44c5ab4fa219e92529752 398a306ab671437a9988c3756ab7f425\n#: 4d5566460617441d84c1f6d527cd4344 509f8e751d5e457699d9a42dc3f0644e\n#: 58d7dd92da694affb15906f8055cb2f3 60884d82c6ed41c6b0fb30f10c530bc3\n#: 6f3e16b01a7e48b7b1286e84bec92f65 70099bc7029b4653a4ce215f5ea21068\n#: a5509eb13e9646f48b334f69990300d2 a89151cf3f0740db85a479f2b9b73349\n#: aba1d83a80594c35822fea6ded9b9e92 abb1fc81a69a4ce39c3973f59c1ad4b4\n#: b2e60629a7ef4d0cb426b6f6e36f1f6f deb835e391664727a28f3d7f49008950\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../functions.rst:84 868bc857e3eb4ca9a79d072abe89f452\nmsgid \"\"\n\"any format name from above in upper or lower case, like *\\\"A4\\\"* or \"\n\"*\\\"letter-l\\\"*.\"\nmsgstr \"위의 형식 이름 중 하나를 대문자 또는 소문자로 지정합니다. 예: *\\\"A4\\\"* 또는 *\\\"letter-l\\\"*.\"\n\n#: ../../functions.rst 022a9111972c43f4ac95797e47e55115\n#: 0c19eadddcc246f6b494636250447fd1 1227b7b4025342248b7726eb436fd672\n#: 1344025ac05b4743ab3452c49485b456 16ed36a80352404c9f6b780307f76f2c\n#: 1a3722844c9c4028b4ca575c633677f8 1e874c6b85ad41ff8d39bd66d4b10459\n#: 20d12996ad564b01a013abcf0a595b1b 20ffe31a11ee480896d6d653dbfabe62\n#: 2b70ab4546fa4726935510a1e9c6ea1e 32862398c7664800a5f7d7e0ac8dd3a4\n#: 468d0e15495548d081abcad8b54b977b 5629f3d073a446cb8a7d2cad64ae5a6e\n#: 72190288375c4d32a56d69d0e5939fe5 741a274045a04f929fcfa2c3b8b92f2d\n#: 88398cfff97c477db1e260b56fb9eb7b 8d70daaf324943269c7d19f63b2cc8fe\n#: 8d9d283148974c8ca3abfd33d28287fe 90882dfe77d24383867c3af45e603974\n#: a3c6fbb9de8a4f588b1c288c68c4cca3 aab4d395713b4379a065a2abb64849de\n#: b546dccfca404e0580e50b1fc6e5ad44 c709831c399146dfb8bd4fe3167a8938\n#: f354716ed65b417ca129e97964f83aa0\nmsgid \"Return type\"\nmsgstr \"반환 타입\"\n\n#: ../../functions.rst 054986a55bd8412684d7d1053e95c27a\n#: 0f142076b64b4989b3743f8c7ef4cc0a 32f469a0c91b4a868a39b83f799dd678\n#: 349444e692d0463e96ec95137f014f3c 3b461c671ee044138d2bdc62333e42d0\n#: 3df66e6bef0d4ea7bf65e4b3638bfb69 5902d0ef2d20466abff84b79b17d8841\n#: 6573f0a01dc743d892cfd7006b7cfd57 71a7252151694deab2d3caf80063f899\n#: 7d76e05a4b3a4af7b9cad032b510bac6 87784bbec007408e8916cc06e9591342\n#: 94c68ca6fcc44b10a660ad293abeeff5 97ee6ea8100b4074aaa5cf8a2c54ab88\n#: 9f4a7c0053e141358a36dadc8edd4499 a181be36d67549dab9959ecd33a5c311\n#: a20bf25fcc4c453cb352fd964286b1a3 a4183c4f8c0f43eb9e5d7c163475b746\n#: a66431d0340e41be826a4392175765a7 b6ec04a4323e457488d3a34c4e2dd176\n#: d2a6377848154565a05fc9112dd958ca db6ae0d1dc96463cb4f8ccf9885b98d0\n#: df98ff1830f843c7b39c5f50c02a93b2 e03a4ce2cc7248f5952c69d5abcf55b9\n#: e532dd33e4cf433a87145131fdb015b3 f4d244d00c2845ec820bba3e866fd756\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../functions.rst:87 b03cca1df3ff43cab3ebafdcc5ea4396\nmsgid \"\"\n\"*(width, height)* of the paper format. For an unknown format *(-1, -1)* \"\n\"is returned. Examples: *pymupdf.paper_size(\\\"A4\\\")* returns *(595, 842)* \"\n\"and *pymupdf.paper_size(\\\"letter-l\\\")* delivers *(792, 612)*.\"\nmsgstr \"\"\n\"용지 형식의 *(너비, 높이)*. 알 수 없는 형식의 경우 *(-1, -1)* 이 반환됩니다. 예: \"\n\"*pymupdf.paper_size(\\\"A4\\\")* 는 *(595, 842)* 를 반환하고 \"\n\"*pymupdf.paper_size(\\\"letter-l\\\")* 는 *(792, 612)* 를 반환합니다.\"\n\n#: ../../functions.rst:93 39ac61c8acfe4795ad45ca2ed8ae6b2a\nmsgid \"Convenience function to return a :ref:`Rect` for a known paper format.\"\nmsgstr \"알려진 용지 형식에 대한 :ref:`Rect` 를 반환하는 편의 함수.\"\n\n#: ../../functions.rst:95 79ce3e075e8047c38fdca8e47040ce19\nmsgid \"any format name supported by :meth:`paper_size`.\"\nmsgstr \":meth:`paper_size` 에서 지원하는 모든 형식 이름.\"\n\n#: ../../functions.rst:97 6a4b32efe8dd4b0bb8cfd7c6d4b2e4d8\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../functions.rst:98 81a23800b837456cbe9205a60c034ab2\nmsgid \"\"\n\"*pymupdf.Rect(0, 0, width, height)* with *width, \"\n\"height=pymupdf.paper_size(s)*.\"\nmsgstr \"\"\n\"*width, height=pymupdf.paper_size(s)* 를 사용한 *pymupdf.Rect(0, 0, width, height)*.\"\n\n#: ../../functions.rst:109 69c645e94932478f9f3362f568160204\nmsgid \"\"\n\"Sets destination of |PyMuPDF| messages to a file descriptor, a file, an \"\n\"existing stream or `Python's logging system \"\n\"<https://docs.python.org/3/library/logging.html>`_.\"\nmsgstr \"\"\n\"|PyMuPDF| 메시지의 대상을 파일 디스크립터, 파일, 기존 스트림 또는 `Python의 로깅 시스템 \"\n\"<https://docs.python.org/3/library/logging.html>`_ 로 설정합니다.\"\n\n#: ../../functions.rst:113 7cbb49615dd5446788c1e7343992b3bd\nmsgid \"Usually one would only set one arg, or one or more `pylogging*` args.\"\nmsgstr \"일반적으로 하나의 인수만 설정하거나 하나 이상의 `pylogging*` 인수를 설정합니다.\"\n\n#: ../../functions.rst:115 41d549d619b941e490f0d67a2715a734\nmsgid \"\"\n\"A text specification of destination; for details see description of \"\n\"environmental variable `PYMUPDF_MESSAGE`.\"\nmsgstr \"대상의 텍스트 사양. 자세한 내용은 환경 변수 `PYMUPDF_MESSAGE` 의 설명을 참조하세요.\"\n\n#: ../../functions.rst:118 489041f4541c47ef9f9e52c6ae05cc96\nmsgid \"Write to file descriptor.\"\nmsgstr \"파일 디스크립터에 쓰기.\"\n\n#: ../../functions.rst:120 47f7f62ceba74f72adcdf0944e9bbb79\nmsgid \"\"\n\"Write to existing stream, which must have methods `.write(text)` and \"\n\"`.flush()`.\"\nmsgstr \"기존 스트림에 쓰기. `.write(text)` 및 `.flush()` 메서드가 있어야 합니다.\"\n\n#: ../../functions.rst:123 deed94f7b3d04f22b1978ac275a22d14\nmsgid \"Write to a file.\"\nmsgstr \"파일에 쓰기.\"\n\n#: ../../functions.rst:125 d6010f301c214ee981634923329e3b3e\nmsgid \"Append to a file.\"\nmsgstr \"파일에 추가.\"\n\n#: ../../functions.rst:127 581212acd9564c1d982afd047cead7b8\nmsgid \"Write to Python's `logging` system.\"\nmsgstr \"Python의 `logging` 시스템에 쓰기.\"\n\n#: ../../functions.rst:129 7082305f15f14e479a4f01f1b5e7cea6\nmsgid \"Write to Python's `logging` system using specified Logger.\"\nmsgstr \"지정된 Logger를 사용하여 Python의 `logging` 시스템에 쓰기.\"\n\n#: ../../functions.rst:131 05eb0dcaf9644b748efa489fccc348d2\nmsgid \"Write to Python's `logging` system using specified level.\"\nmsgstr \"지정된 레벨을 사용하여 Python의 `logging` 시스템에 쓰기.\"\n\n#: ../../functions.rst:133 cedfea3990d24cf1a7929a33284b11a0\nmsgid \"\"\n\"Write to Python's `logging` system using specified logger name. Only used\"\n\" if `pylogging_logger` is ``None``. Default is `pymupdf`.\"\nmsgstr \"\"\n\"지정된 로거 이름을 사용하여 Python의 `logging` 시스템에 쓰기. `pylogging_logger` 가 ``None`` \"\n\"인 경우에만 사용됩니다. 기본값은 `pymupdf` 입니다.\"\n\n#: ../../functions.rst:137 777f45cd7d524f84942d9fe412c18edd\nmsgid \"\"\n\"If any `pylogging*` arg is not ``None``, we write to `Python's logging \"\n\"system <https://docs.python.org/3/library/logging.html>`_.\"\nmsgstr \"\"\n\"`pylogging*` 인수가 ``None`` 이 아니면 `Python의 로깅 시스템 <https://docs.python.org/3/library/logging.html>`_ 에 씁니다.\"\n\n#: ../../functions.rst:144 ../../functions.rst:156 ../../functions.rst:270\n#: 69f05cfe1b654ab19e0011a944260bec 7558bf3ff3b845559657a578039f1ef0\n#: c30fc7f1a9e343bbb4c5e4c8fbbfb032\nmsgid \"*New in v1.17.4*\"\nmsgstr \"*v1.17.4에서 새로 추가됨*\"\n\n#: ../../functions.rst:146 895bc494383147339ecd407d7f8feece\nmsgid \"\"\n\"Convenience function returning a PDF color triple (red, green, blue) for \"\n\"a given sRGB color integer as it occurs in :meth:`Page.get_text` \"\n\"dictionaries \\\"dict\\\" and \\\"rawdict\\\".\"\nmsgstr \"\"\n\":meth:`Page.get_text` 딕셔너리 \\\"dict\\\" 및 \\\"rawdict\\\" 에서 발생하는 것처럼 주어진 sRGB 색상 정수에 대한 PDF 색상 삼중(빨강, 녹색, 파랑)을 반환하는 편의 함수.\"\n\n#: ../../functions.rst:148 ../../functions.rst:160\n#: 017bfb28972946b7afeddc4aa2d96999 7ff4d5ab9e154081be8ea600c0631ffd\nmsgid \"\"\n\"an integer of format RRGGBB, where each color component is an integer in \"\n\"range(255).\"\nmsgstr \"\"\n\"RRGGBB 형식의 정수로, 각 색상 구성 요소는 range(255)의 정수입니다.\"\n\n#: ../../functions.rst:150 37c7bbd5421d4b18b180482fc18889da\nmsgid \"\"\n\"a tuple (red, green, blue) with float items in interval *0 <= item <= 1* \"\n\"representing the same color. Example `sRGB_to_pdf(0xff0000) = (1, 0, 0)` \"\n\"(red).\"\nmsgstr \"\"\n\"동일한 색상을 나타내는 *0 <= item <= 1* 구간의 float 항목을 가진 튜플(빨강, 녹색, 파랑). 예: `sRGB_to_pdf(0xff0000) = (1, 0, 0)` (빨강).\"\n\n#: ../../functions.rst:158 b3779d6ff2064b7191d22f03dc12b37d\nmsgid \"\"\n\"Convenience function returning a color (red, green, blue) for a given \"\n\"*sRGB* color integer.\"\nmsgstr \"\"\n\"주어진 *sRGB* 색상 정수에 대한 색상(빨강, 녹색, 파랑)을 반환하는 편의 함수.\"\n\n#: ../../functions.rst:162 c2e711f095d845dcbbb6d1599bf1d8bb\nmsgid \"\"\n\"a tuple (red, green, blue) with integer items in `range(256)` \"\n\"representing the same color. Example `sRGB_to_pdf(0xff0000) = (255, 0, \"\n\"0)` (red).\"\nmsgstr \"\"\n\"동일한 색상을 나타내는 `range(256)` 의 정수 항목을 가진 튜플(빨강, 녹색, 파랑). 예: `sRGB_to_pdf(0xff0000) = (255, 0, 0)` (빨강).\"\n\n#: ../../functions.rst:168 ../../functions.rst:183 ../../functions.rst:198\n#: ../../functions.rst:211 0330c6db37ba44e7b01d3331832a082a\n#: 59756c59d51a4bf59c7c44211fc57b99 c8e9f36450234d3293d8445774911e5d\n#: d0ad94f8dbd24dd5adb1fc709cde1c9e\nmsgid \"*New in v1.18.0*\"\nmsgstr \"*v1.18.0에서 새로 추가됨*\"\n\n#: ../../functions.rst:170 18f6f71df9e4437e91b15db0811f02e1\nmsgid \"\"\n\"Return the unicode number of a glyph name based on the **Adobe Glyph \"\n\"List**.\"\nmsgstr \"\"\n\"**Adobe Glyph List**를 기반으로 글리프 이름의 유니코드 번호를 반환합니다.\"\n\n#: ../../functions.rst:172 2ea221eaae354e3a8696af8d26a6727c\nmsgid \"\"\n\"the name of some glyph. The function is based on the `Adobe Glyph List \"\n\"<https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_.\"\nmsgstr \"\"\n\"일부 글리프의 이름. 이 함수는 `Adobe Glyph List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ 에 기반합니다.\"\n\n#: ../../functions.rst:175 9cab0f810cd041b7b19a385d41b3de4d\nmsgid \"the unicode. Invalid ``name`` entries return `0xfffd (65533)`.\"\nmsgstr \"유니코드. 유효하지 않은 ``name`` 항목은 `0xfffd (65533)` 을 반환합니다.\"\n\n#: ../../functions.rst:177 ../../functions.rst:205 ../../functions.rst:218\n#: 8ae7164314a54d298a84c72740a19a67 bdcaf136335b4029a886ece439c7db85\n#: e4acb745507b430e8af6df66d695d76c\nmsgid \"\"\n\"A similar functionality is provided by package `fontTools \"\n\"<https://pypi.org/project/fonttools/>`_ in its *agl* sub-package.\"\nmsgstr \"\"\n\"유사한 기능이 `fontTools <https://pypi.org/project/fonttools/>`_ 패키지의 *agl* 하위 패키지에서 제공됩니다.\"\n\n#: ../../functions.rst:185 75a5eea668644ca5ad66e78b8f46f33b\nmsgid \"\"\n\"Return the glyph name of a unicode number, based on the **Adobe Glyph \"\n\"List**.\"\nmsgstr \"\"\n\"**Adobe Glyph List**를 기반으로 유니코드 번호의 글리프 이름을 반환합니다.\"\n\n#: ../../functions.rst:187 65f19a9b48e14e2caf273c0cd10e1127\n#: 96ee3f05d61747f7adbf5b5d3abd3e7a\nmsgid \"\"\n\"the unicode given by e.g. `ord(\\\"ß\\\")`. The function is based on the \"\n\"`Adobe Glyph List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_.\"\nmsgstr \"\"\n\"예를 들어 `ord(\\\"ß\\\")` 로 주어진 유니코드. 이 함수는 `Adobe Glyph List <https://github.com/adobe-type-tools/agl-\"\n\"aglfn/blob/master/glyphlist.txt>`_ 에 기반합니다.\"\n\n#: ../../functions.rst:190 85951f82646148b184f726f54c1aacd6\nmsgid \"\"\n\"the glyph name. E.g. `pymupdf.unicode_to_glyph_name(ord(\\\"Ä\\\"))` returns \"\n\"`'Adieresis'`.\"\nmsgstr \"\"\n\"글리프 이름. 예: `pymupdf.unicode_to_glyph_name(ord(\\\"Ä\\\"))` 는 `'Adieresis'` 를 반환합니다.\"\n\n#: ../../functions.rst:192 bd7a7f8035ae48c1b94b6a14beff47cc\nmsgid \"\"\n\"A similar functionality is provided by package `fontTools \"\n\"<https://pypi.org/project/fonttools/>`_: in its *agl* sub-package.\"\nmsgstr \"\"\n\"유사한 기능은 패키지 `fontTools <https://pypi.org/project/fonttools/>`_ 의 *agl* 하위\"\n\" 패키지에서 제공됩니다.\"\n\n#: ../../functions.rst:200 ea6d8435122e4e03b457b6c4f74f77f2\nmsgid \"Return a list of glyph names defined in the **Adobe Glyph List**.\"\nmsgstr \"**Adobe Glyph List** 에 정의된 글리프 이름 목록을 반환합니다.\"\n\n#: ../../functions.rst:203 67cf198df6114dd3804a1ba80c9c67ce\nmsgid \"list of strings.\"\nmsgstr \"문자열 목록.\"\n\n#: ../../functions.rst:213 0041733db7e64ba8a5350f0ea22c9eec\nmsgid \"\"\n\"Return a list of unicodes for there exists a glyph name in the **Adobe \"\n\"Glyph List**.\"\nmsgstr \"**Adobe Glyph List** 에 글리프 이름이 존재하는 유니코드 목록을 반환합니다.\"\n\n#: ../../functions.rst:216 1a1ca8f4c0ee415cac54b1fbbf966aac\nmsgid \"list of integers.\"\nmsgstr \"정수 목록.\"\n\n#: ../../functions.rst:224 91d0f084f22d40789e29edca8cc4b512\nmsgid \"*New in v1.21.0*\"\nmsgstr \"*v1.21.0의 새로운 기능*\"\n\n#: ../../functions.rst:226 bfdbc87798434761bc202a2afdb0db2a\nmsgid \"**Utility function for use with \\\"Story\\\" applications.**\"\nmsgstr \"**\\\"Story\\\" 애플리케이션에서 사용하기 위한 유틸리티 함수.**\"\n\n#: ../../functions.rst:228 eb5487e982fa40b08c6ef9ec4d4d585f\nmsgid \"\"\n\"Create CSS `@font-face` items for the given fontcode in pymupdf-fonts. \"\n\"Creates a CSS font-family for all fonts starting with string \"\n\"\\\"fontcode\\\".\"\nmsgstr \"\"\n\"pymupdf-fonts에서 주어진 fontcode에 대한 CSS `@font-face` 항목을 생성합니다. 문자열 \"\n\"\\\"fontcode\\\"로 시작하는 모든 글꼴에 대한 CSS font-family를 생성합니다.\"\n\n#: ../../functions.rst:230 136c05d535f84f80ba229db14ba5e027\nmsgid \"\"\n\"The font naming convention in package pymupdf-fonts is \\\"fontcode<sf>\\\", \"\n\"where the suffix \\\"sf\\\" is one of \\\"\\\" (empty), \\\"it\\\"/\\\"i\\\", \"\n\"\\\"bo\\\"/\\\"b\\\" or \\\"bi\\\". These suffixes thus represent the regular, \"\n\"italic, bold or bold-italic variants of that font.\"\nmsgstr \"\"\n\"패키지 pymupdf-fonts의 글꼴 명명 규칙은 \\\"fontcode<sf>\\\"이며, 여기서 접미사 \\\"sf\\\"는 \\\"\\\"(비어 \"\n\"있음), \\\"it\\\"/\\\"i\\\", \\\"bo\\\"/\\\"b\\\" 또는 \\\"bi\\\" 중 하나입니다. 이러한 접미사는 따라서 해당 글꼴의 \"\n\"일반, 기울임꼴, 굵게 또는 굵은 기울임꼴 변형을 나타냅니다.\"\n\n#: ../../functions.rst:232 73f3ec03772745dcb664d3338f909e69\nmsgid \"For example, font code \\\"notos\\\" refers to fonts\"\nmsgstr \"예를 들어, 글꼴 코드 \\\"notos\\\"는 다음 글꼴을 나타냅니다\"\n\n#: ../../functions.rst:234 ab848e07a9544eb0a4a64619cb70670d\nmsgid \"\\\"notos\\\" - \\\"Noto Sans Regular\\\"\"\nmsgstr \"\\\"notos\\\" - \\\"Noto Sans Regular\\\"\"\n\n#: ../../functions.rst:235 f820847aafbf425fa170b1083abd9056\nmsgid \"\\\"notosit\\\" - \\\"Noto Sans Italic\\\"\"\nmsgstr \"\\\"notosit\\\" - \\\"Noto Sans Italic\\\"\"\n\n#: ../../functions.rst:236 524c95238e1f4af6945c40428fea8d5a\nmsgid \"\\\"notosbo\\\" - \\\"Noto Sans Bold\\\"\"\nmsgstr \"\\\"notosbo\\\" - \\\"Noto Sans Bold\\\"\"\n\n#: ../../functions.rst:237 d6a7415ca6e448e0afcac405b692a483\nmsgid \"\\\"notosbi\\\" - \\\"Noto Sans Bold Italic\\\"\"\nmsgstr \"\\\"notosbi\\\" - \\\"Noto Sans Bold Italic\\\"\"\n\n#: ../../functions.rst:239 7682199165a64e699943ec683a5dbae8\nmsgid \"\"\n\"The function creates (up to) four CSS `@font-face` definitions and \"\n\"collectively assigns the `font-family` name \\\"notos\\\" to them (or the \"\n\"\\\"name\\\" value if provided). Associated font buffers are placed / added \"\n\"to the provided archive.\"\nmsgstr \"\"\n\"함수는 (최대) 4개의 CSS `@font-face` 정의를 생성하고 `font-family` 이름 \\\"notos\\\"(또는 제공된 \"\n\"경우 \\\"name\\\" 값)를 집합적으로 할당합니다. 연결된 글꼴 버퍼는 제공된 아카이브에 배치/추가됩니다.\"\n\n#: ../../functions.rst:241 d60c58db166f4865ba6c5a96c0935714\nmsgid \"\"\n\"To use the font in the Python API for :ref:`Story`, execute \"\n\"`.set_font(fontcode)` (or \\\"name\\\" if given). The correct font weight or \"\n\"style will automatically be selected as required.\"\nmsgstr \"\"\n\":ref:`Story` 의 Python API에서 글꼴을 사용하려면 `.set_font(fontcode)` (또는 주어진 경우 \"\n\"\\\"name\\\")를 실행하세요. 올바른 글꼴 두께 또는 스타일이 필요에 따라 자동으로 선택됩니다.\"\n\n#: ../../functions.rst:243 f4c204d386b647d0a61c376c3c13681d\nmsgid \"\"\n\"For example to replace the \\\"sans-serif\\\" HTML standard (i.e. Helvetica) \"\n\"with the above \\\"notos\\\", execute the following. Whenever \\\"sans-serif\\\" \"\n\"is used (whether explicitly or implicitly), the Noto Sans fonts will be \"\n\"selected.\"\nmsgstr \"\"\n\"예를 들어 위의 \\\"notos\\\"로 \\\"sans-serif\\\" HTML 표준(즉, Helvetica)을 대체하려면 다음을 \"\n\"실행하세요. \\\"sans-serif\\\"가 사용될 때마다(명시적으로든 암시적으로든) Noto Sans 글꼴이 선택됩니다.\"\n\n#: ../../functions.rst:245 eabaed48beb946e58d8a1dc9579bb770\nmsgid \"\"\n\"`CSS = pymupdf.css_for_pymupdf_font(\\\"notos\\\", name=\\\"sans-serif\\\", \"\n\"archive=...)`\"\nmsgstr \"\"\n\"`CSS = pymupdf.css_for_pymupdf_font(\\\"notos\\\", name=\\\"sans-serif\\\", \"\n\"archive=...)`\"\n\n#: ../../functions.rst:247 45820ea5c1c34abe9086286b089e5835\nmsgid \"Expects and returns the CSS source, with the new CSS definitions appended.\"\nmsgstr \"CSS 소스를 받아서 새로운 CSS 정의가 추가된 CSS 소스를 반환합니다.\"\n\n#: ../../functions.rst:249 f8e31e8254fc4695a916866897562c67\nmsgid \"\"\n\"one of the font codes present in package `pymupdf-fonts \"\n\"<https://pypi.org/project/pymupdf-fonts/>`_ (usually) representing the \"\n\"regular version of the font family.\"\nmsgstr \"\"\n\"패키지 `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ 에 있는 글꼴 코드\"\n\" 중 하나(일반적으로 글꼴 패밀리의 일반 버전을 나타냄).\"\n\n#: ../../functions.rst:250 92f43cf88a624b93bd22752d8bf64bd1\nmsgid \"\"\n\"any already existing CSS source, or `None`. The function will append its \"\n\"new definitions to this. This is the string that **must be used** as \"\n\"`user_css` when creating the :ref:`Story`.\"\nmsgstr \"\"\n\"기존 CSS 소스 또는 `None`. 함수는 새로운 정의를 여기에 추가합니다. 이것은 :ref:`Story` 를 생성할 때 \"\n\"`user_css` 로 **사용해야 하는** 문자열입니다.\"\n\n#: ../../functions.rst:251 513bb69848834f1b8ee131ac15a8d498\nmsgid \"\"\n\":ref:`Archive`, **mandatory**. All font binaries (i.e. up to four) found \"\n\"for \\\"fontcode\\\" will be added to the archive. This is the archive that \"\n\"**must be used** as `archive` when creating the :ref:`Story`.\"\nmsgstr \"\"\n\":ref:`Archive`, **필수**. \\\"fontcode\\\"에 대해 찾은 모든 글꼴 바이너리(최대 4개)가 아카이브에 \"\n\"추가됩니다. 이것은 :ref:`Story` 를 생성할 때 `archive` 로 **사용해야 하는** 아카이브입니다.\"\n\n#: ../../functions.rst:252 5497d854266c41399b06bd35ad5f9084\nmsgid \"\"\n\"the name under which the \\\"fontcode\\\" fonts should be found. If omitted, \"\n\"\\\"fontcode\\\" will be used.\"\nmsgstr \"\\\"fontcode\\\" 글꼴을 찾을 이름. 생략하면 \\\"fontcode\\\"가 사용됩니다.\"\n\n#: ../../functions.rst:255 f98ee439f50d4dfe8df6c0efbd7b7815\nmsgid \"\"\n\"Modified CSS, with appended `@font-face` statements for each font variant\"\n\" of fontcode. Fontbuffers associated with \\\"fontcode\\\" will have been \"\n\"added to 'archive'. The function will automatically find up to 4 font \"\n\"variants. All pymupdf-fonts (that are no special purpose like math or \"\n\"music, etc.) have regular, bold, italic and bold-italic variants. To see \"\n\"currently available font codes check \"\n\"`pymupdf.fitz_fontdescriptors.keys()`. This will show something like \"\n\"`dict_keys(['cascadia', 'cascadiai', 'cascadiab', 'cascadiabi', 'figbo', \"\n\"'figo', 'figbi', 'figit', 'fimbo', 'fimo', 'spacembo', 'spacembi', \"\n\"'spacemit', 'spacemo', 'math', 'music', 'symbol1', 'symbol2', 'notosbo', \"\n\"'notosbi', 'notosit', 'notos', 'ubuntu', 'ubuntubo', 'ubuntubi', \"\n\"'ubuntuit', 'ubuntm', 'ubuntmbo', 'ubuntmbi', 'ubuntmit'])`.\"\nmsgstr \"\"\n\"fontcode의 각 글꼴 변형에 대한 `@font-face` 문이 추가된 수정된 CSS. \\\"fontcode\\\"와 연결된 \"\n\"Fontbuffers가 'archive'에 추가됩니다. 함수는 자동으로 최대 4개의 글꼴 변형을 찾습니다. 모든 pymupdf-\"\n\"fonts(수학이나 음악 등 특수 목적이 아닌 것)는 일반, 굵게, 기울임꼴 및 굵은 기울임꼴 변형을 가지고 있습니다. 현재 사용 \"\n\"가능한 글꼴 코드를 확인하려면 `pymupdf.fitz_fontdescriptors.keys()` 를 확인하세요. 이것은 \"\n\"`dict_keys(['cascadia', 'cascadiai', 'cascadiab', 'cascadiabi', 'figbo', \"\n\"'figo', 'figbi', 'figit', 'fimbo', 'fimo', 'spacembo', 'spacembi', \"\n\"'spacemit', 'spacemo', 'math', 'music', 'symbol1', 'symbol2', 'notosbo', \"\n\"'notosbi', 'notosit', 'notos', 'ubuntu', 'ubuntubo', 'ubuntubi', \"\n\"'ubuntuit', 'ubuntm', 'ubuntmbo', 'ubuntmbi', 'ubuntmit'])` 와 같은 것을 \"\n\"보여줍니다.\"\n\n#: ../../functions.rst:257 3526f7b9559347458786dc7c33a512d5\nmsgid \"\"\n\"Here is a complete snippet for using the \\\"Noto Sans\\\" font instead of \"\n\"\\\"Helvetica\\\"::\"\nmsgstr \"\\\"Helvetica\\\" 대신 \\\"Noto Sans\\\" 글꼴을 사용하는 완전한 코드 조각입니다::\"\n\n#: ../../functions.rst:272 48272a37d69845059cb56a9a1f7d309d\nmsgid \"\"\n\"Convenience function to split a rectangle into sub-rectangles of equal \"\n\"size. Returns a list of `rows` lists, each containing `cols` :ref:`Rect` \"\n\"items. Each sub-rectangle can then be addressed by its row and column \"\n\"index.\"\nmsgstr \"\"\n\"사각형을 동일한 크기의 하위 사각형으로 분할하는 편의 함수. `rows` 리스트의 리스트를 반환하며, 각 리스트는 `cols` 개의\"\n\" :ref:`Rect` 항목을 포함합니다. 각 하위 사각형은 행 및 열 인덱스로 주소를 지정할 수 있습니다.\"\n\n#: ../../functions.rst:274 5536e164169a48f4bdd4363a4f4836d1\nmsgid \"the rectangle to split.\"\nmsgstr \"분할할 사각형.\"\n\n#: ../../functions.rst:275 5f0d1ca61442423c8f9a62f957ac7d34\nmsgid \"the desired number of columns.\"\nmsgstr \"원하는 열 수.\"\n\n#: ../../functions.rst:276 ee278d86b78145a58993d0a15b118289\nmsgid \"the desired number of rows.\"\nmsgstr \"원하는 행 수.\"\n\n#: ../../functions.rst:277 06fb832e511d432a92019b0b3e60d399\nmsgid \"\"\n\"a list of :ref:`Rect` objects of equal size, whose union equals *rect*. \"\n\"Here is the layout of a 3x4 table created by `cell = \"\n\"pymupdf.make_table(rect, cols=4, rows=3)`:\"\nmsgstr \"\"\n\"동일한 크기의 :ref:`Rect` 객체 리스트. 이들의 합집합은 *rect* 와 같습니다. `cell = \"\n\"pymupdf.make_table(rect, cols=4, rows=3)` 로 생성된 3x4 테이블의 레이아웃은 다음과 같습니다:\"\n\n#: ../../functions.rst:287 8bba6d4c49f7447da9e1223dd3e1e7d7\nmsgid \"New in version 1.16.2)*\"\nmsgstr \"*버전 1.16.2의 새로운 기능*\"\n\n#: ../../functions.rst:289 2442a2770c3c4ff4af3b3eb24a2a6f1c\nmsgid \"\"\n\"Return a matrix which maps the line from p1 to p2 to the x-axis such that\"\n\" p1 will become (0,0) and p2 a point with the same distance to (0,0).\"\nmsgstr \"\"\n\"p1에서 p2로의 선을 x축에 매핑하는 행렬을 반환합니다. p1은 (0,0)이 되고 p2는 (0,0)까지의 동일한 거리를 가진 점이\"\n\" 됩니다.\"\n\n#: ../../functions.rst:291 ea959e9b36794857b92ea27d46682d48\nmsgid \"starting point of the line.\"\nmsgstr \"선의 시작점.\"\n\n#: ../../functions.rst:292 9e2c74d180cb496b89b4fed901585712\nmsgid \"end point of the line.\"\nmsgstr \"선의 끝점.\"\n\n#: ../../functions.rst:294 82cd715a4eaa45dca15ea53c40895156\nmsgid \":ref:`Matrix`\"\nmsgstr \":ref:`Matrix`\"\n\n#: ../../functions.rst:295 b686e23a96744387bcbaa202c667de89\nmsgid \"\"\n\"a matrix which combines a rotation and a translation::     >>> p1 = \"\n\"pymupdf.Point(1, 1)    >>> p2 = pymupdf.Point(4, 5)    >>> abs(p2 - p1)  \"\n\"# distance of points    5.0    >>> m = pymupdf.planish_line(p1, p2)    \"\n\">>> p1 * m    Point(0.0, 0.0)    >>> p2 * m    Point(5.0, \"\n\"-5.960464477539063e-08)    >>> # distance of the resulting points    >>> \"\n\"abs(p2 * m - p1 * m)    5.0   .. image:: images/img-planish.png    \"\n\":scale: 40\"\nmsgstr \"\"\n\n#: ../../functions.rst:295 80b98e912fd147ed91827592eef3d5ad\nmsgid \"a matrix which combines a rotation and a translation::\"\nmsgstr \"회전과 이동을 결합한 행렬::\"\n\n#: ../../functions.rst:319 b8be325123d8488bb925de622de9d53c\nmsgid \"\"\n\"A dictionary of pre-defines paper formats. Used as basis for \"\n\":meth:`paper_size`.\"\nmsgstr \"사전 정의된 용지 형식의 딕셔너리. :meth:`paper_size` 의 기반으로 사용됩니다.\"\n\n#: ../../functions.rst:325 406401efed724a1887a2096b373b32b3\nmsgid \"New in v1.17.5\"\nmsgstr \"*v1.17.5의 새로운 기능*\"\n\n#: ../../functions.rst:327 7a0262b74b314f1fa78cc0f0f957e5b5\nmsgid \"\"\n\"A dictionary of usable fonts from repository `pymupdf-fonts \"\n\"<https://pypi.org/project/pymupdf-fonts/>`_. Items are keyed by their \"\n\"reserved fontname and provide information like this::\"\nmsgstr \"\"\n\"저장소 `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ 에서 사용 가능한 \"\n\"글꼴의 딕셔너리. 항목은 예약된 글꼴 이름으로 키가 지정되며 다음과 같은 정보를 제공합니다::\"\n\n#: ../../functions.rst:343 9187429ec1b74d7ca17a69875896bb76\nmsgid \"If `pymupdf-fonts` is not installed, the dictionary is empty.\"\nmsgstr \"`pymupdf-fonts` 가 설치되지 않은 경우 딕셔너리는 비어 있습니다.\"\n\n#: ../../functions.rst:345 201981860f614a1da8206b560d991027\nmsgid \"\"\n\"The dictionary keys can be used to define a :ref:`Font` via e.g. `font = \"\n\"pymupdf.Font(\\\"fimo\\\")` -- just like you can do it with the builtin fonts\"\n\" \\\"Helvetica\\\" and friends.\"\nmsgstr \"\"\n\"딕셔너리 키는 예를 들어 `font = pymupdf.Font(\\\"fimo\\\")` 를 통해 :ref:`Font` 를 정의하는 데 \"\n\"사용할 수 있습니다 -- 내장 글꼴 \\\"Helvetica\\\" 등과 동일하게 사용할 수 있습니다.\"\n\n#: ../../functions.rst:351 96bc790c2f3c41eab4eb03e2bbb91044\nmsgid \"\"\n\"If in `os.environ` when |PyMuPDF| is imported, sets destination of \"\n\"|PyMuPDF| messages. Otherwise messages are sent to `sys.stdout`.\"\nmsgstr \"\"\n\"|PyMuPDF| 가 가져올 때 `os.environ` 에 있으면 |PyMuPDF| 메시지의 대상을 설정합니다. 그렇지 않으면 \"\n\"메시지는 `sys.stdout` 으로 전송됩니다.\"\n\n#: ../../functions.rst:355 d3a34a5171b84ddc975fd680a2c1d896\nmsgid \"\"\n\"If the value starts with `fd:`, the remaining text should be an integer \"\n\"file descriptor to which messages are written.\"\nmsgstr \"값이 `fd:` 로 시작하면 나머지 텍스트는 메시지가 기록되는 정수 파일 디스크립터여야 합니다.\"\n\n#: ../../functions.rst:358 26b2a3b05c144932bd212022dc818718\nmsgid \"For example `PYMUPDF_MESSAGE=fd:2` will send messages to stderr.\"\nmsgstr \"예를 들어 `PYMUPDF_MESSAGE=fd:2` 는 메시지를 stderr로 보냅니다.\"\n\n#: ../../functions.rst:360 a9af399eca6b4eafacdee7e4514b60ca\nmsgid \"\"\n\"If the value starts with `path:`, the remaining text is the path of a \"\n\"file to which messages are written. If the file already exists, it is \"\n\"truncated.\"\nmsgstr \"값이 `path:` 로 시작하면 나머지 텍스트는 메시지가 기록되는 파일의 경로입니다. 파일이 이미 존재하면 잘립니다.\"\n\n#: ../../functions.rst:364 0d31927b8e434b3680bbc7e7a528b8ba\nmsgid \"\"\n\"If the value starts with `path+:`, the remaining text is the path of file\"\n\" to which messages are written. If the file already exists, we append \"\n\"output.\"\nmsgstr \"값이 `path+:` 로 시작하면 나머지 텍스트는 메시지가 기록되는 파일의 경로입니다. 파일이 이미 존재하면 출력을 추가합니다.\"\n\n#: ../../functions.rst:369 367ef9d38b324a2e92535daa15463fd4\nmsgid \"\"\n\"If the value starts with `logging:`, messages are written to `Python's \"\n\"logging system <https://docs.python.org/3/library/logging.html>`_. The \"\n\"remaining text can contain comma-separated name=value items:\"\nmsgstr \"\"\n\"값이 `logging:` 로 시작하면 메시지는 `Python의 로깅 시스템 \"\n\"<https://docs.python.org/3/library/logging.html>`_ 에 기록됩니다. 나머지 텍스트는 쉼표로 \"\n\"구분된 name=value 항목을 포함할 수 있습니다:\"\n\n#: ../../functions.rst:373 727cdb80e0e9424b82a78c9fcf4131ea\nmsgid \"`level=<int>` sets the logging level.\"\nmsgstr \"`level=<int>` 는 로깅 레벨을 설정합니다.\"\n\n#: ../../functions.rst:374 cbd781fbde1b482097f102a847dc8399\nmsgid \"`name=<str>` sets the logger name (default is `pymupdf`).\"\nmsgstr \"`name=<str>` 는 로거 이름을 설정합니다(기본값은 `pymupdf`).\"\n\n#: ../../functions.rst:376 4f25318185b745a7af1b120f78e29eb8\nmsgid \"Other items are ignored.\"\nmsgstr \"다른 항목은 무시됩니다.\"\n\n#: ../../functions.rst:378 df67601c54d341f5bd7a2d06718b136b\nmsgid \"Other prefixes will cause an error.\"\nmsgstr \"다른 접두사는 오류를 발생시킵니다.\"\n\n#: ../../functions.rst:380 d06c09c69e114e30aa122b24d91ad8c4\nmsgid \"Also see `set_messages()`.\"\nmsgstr \"`set_messages()` 도 참조하세요.\"\n\n#: ../../functions.rst:387 834d76807609499695b186421da0488e\nmsgid \"New in v1.19.6\"\nmsgstr \"*v1.19.6의 새로운 기능*\"\n\n#: ../../functions.rst:389 f0b470d4413e4923a64200e0e1451914\nmsgid \"\"\n\"Contains about 500 RGB colors in PDF format with the color name as key. \"\n\"To see what is there, you can obviously look at \"\n\"`pymupdf.pdfcolor.keys()`.\"\nmsgstr \"\"\n\"색상 이름을 키로 하는 PDF 형식의 약 500개의 RGB 색상을 포함합니다. 내용을 확인하려면 \"\n\"`pymupdf.pdfcolor.keys()` 를 확인할 수 있습니다.\"\n\n#: ../../functions.rst:391 c5aa4f5a3e6541f99de68bb1b49ffc9c\nmsgid \"Examples:\"\nmsgstr \"예제:\"\n\n#: ../../functions.rst:393 6198f065e39e4bdf98f3451ff9481bd5\nmsgid \"`pymupdf.pdfcolor[\\\"red\\\"] = (1.0, 0.0, 0.0)`\"\nmsgstr \"`pymupdf.pdfcolor[\\\"red\\\"] = (1.0, 0.0, 0.0)`\"\n\n#: ../../functions.rst:394 46ae89359e384ceeb868dd2014c8c5a1\nmsgid \"\"\n\"`pymupdf.pdfcolor[\\\"skyblue\\\"] = (0.5294117647058824, 0.807843137254902, \"\n\"0.9215686274509803)`\"\nmsgstr \"\"\n\"`pymupdf.pdfcolor[\\\"skyblue\\\"] = (0.5294117647058824, 0.807843137254902, \"\n\"0.9215686274509803)`\"\n\n#: ../../functions.rst:395 4fba859674ef468190d4d2fa416c1319\nmsgid \"\"\n\"`pymupdf.pdfcolor[\\\"wheat\\\"] = (0.9607843137254902, 0.8705882352941177, \"\n\"0.7019607843137254)`\"\nmsgstr \"\"\n\"`pymupdf.pdfcolor[\\\"wheat\\\"] = (0.9607843137254902, 0.8705882352941177, \"\n\"0.7019607843137254)`\"\n\n#: ../../functions.rst:401 9772c54652e641db860a29f83e7fbe2d\nmsgid \"\"\n\"Convenience function to return the current local timestamp in PDF \"\n\"compatible format, e.g. *D:20170501121525-04'00'* for local datetime May \"\n\"1, 2017, 12:15:25 in a timezone 4 hours westward of the UTC meridian.\"\nmsgstr \"\"\n\"현재 로컬 타임스탬프를 PDF 호환 형식으로 반환하는 편의 함수. 예: UTC 자오선에서 서쪽으로 4시간 떨어진 시간대의 2017년\"\n\" 5월 1일 12:15:25 로컬 날짜/시간에 대한 *D:20170501121525-04'00'*.\"\n\n#: ../../functions.rst:404 5d740fbd9b1d47ff9ed232843a7ff7b5\nmsgid \"current local PDF timestamp.\"\nmsgstr \"현재 로컬 PDF 타임스탬프.\"\n\n#: ../../functions.rst:410 0e8f792a9cd24c8bb5ee20240c898e8a\nmsgid \"New in version 1.14.7\"\nmsgstr \"*버전 1.14.7의 새로운 기능*\"\n\n#: ../../functions.rst:412 0a47fb8a49c04869ba92bff096b077ba\nmsgid \"\"\n\"Calculate the length of text on output with a given **builtin** font, \"\n\":data:`fontsize` and encoding.\"\nmsgstr \"주어진 **내장** 글꼴, :data:`fontsize` 및 인코딩으로 출력 시 텍스트 길이를 계산합니다.\"\n\n#: ../../functions.rst:414 fdc381a3ed7e4fe1aabff23f87dfa215\nmsgid \"the text string.\"\nmsgstr \"텍스트 문자열.\"\n\n#: ../../functions.rst:415 ec72804a2b8d4774987c66c5a1e9040c\nmsgid \"\"\n\"the font name. Must be one of either the :ref:`Base-14-Fonts` or the CJK \"\n\"fonts, identified by their \\\"reserved\\\" fontnames (see table in \"\n\":meth:`Page.insert_font`).\"\nmsgstr \"\"\n\"글꼴 이름. :ref:`Base-14-Fonts` 또는 \\\"예약된\\\" 글꼴 이름으로 식별되는 CJK 글꼴 중 하나여야 \"\n\"합니다(:meth:`Page.insert_font` 의 표 참조).\"\n\n#: ../../functions.rst:416 8bd3348d8d3442778d7f1dae48bc7156\nmsgid \"the :data:`fontsize`.\"\nmsgstr \":data:`fontsize`.\"\n\n#: ../../functions.rst:417 ca5639a68e354aea8a51fc71a8a482e6\nmsgid \"\"\n\"the encoding to use. Besides 0 = Latin, 1 = Greek and 2 = Cyrillic \"\n\"(Russian) are available. Relevant for Base-14 fonts \\\"Helvetica\\\", \"\n\"\\\"Courier\\\" and \\\"Times\\\" and their variants only. Make sure to use the \"\n\"same value as in the corresponding text insertion.\"\nmsgstr \"\"\n\"사용할 인코딩. 0 = Latin 외에 1 = Greek 및 2 = Cyrillic(러시아어)을 사용할 수 있습니다. Base-14\"\n\" 글꼴 \\\"Helvetica\\\", \\\"Courier\\\" 및 \\\"Times\\\"와 그 변형에만 관련됩니다. 해당 텍스트 삽입에서와 \"\n\"동일한 값을 사용해야 합니다.\"\n\n#: ../../functions.rst:419 acc35bea49374d9b96b4a881331de8c3\nmsgid \"\"\n\"the length in points the string will have (e.g. when used in \"\n\":meth:`Page.insert_text`).\"\nmsgstr \"문자열이 가질 포인트 단위의 길이(예: :meth:`Page.insert_text` 에서 사용할 때).\"\n\n#: ../../functions.rst:421 3dd546e78759471eb2f4224830083feb\nmsgid \"\"\n\"This function will only do the calculation -- it won't insert font nor \"\n\"text.\"\nmsgstr \"이 함수는 계산만 수행합니다 -- 글꼴이나 텍스트를 삽입하지 않습니다.\"\n\n#: ../../functions.rst:423 a55852432419412b8ce47fa7e5754945\nmsgid \"\"\n\"The :ref:`Font` class offers a similar method, :meth:`Font.text_length`, \"\n\"which supports Base-14 fonts and any font with a character map (CMap, \"\n\"Type 0 fonts).\"\nmsgstr \"\"\n\":ref:`Font` 클래스는 유사한 메서드 :meth:`Font.text_length` 를 제공하며, Base-14 글꼴과 문자 \"\n\"맵(CMap, Type 0 글꼴)이 있는 모든 글꼴을 지원합니다.\"\n\n#: ../../functions.rst:425 244877b50d8d4d8daf1796a23b9b76bc\nmsgid \"\"\n\"If you use this function to determine the required rectangle width for \"\n\"the (:ref:`Page` or :ref:`Shape`) *insert_textbox* methods, be aware that\"\n\" they calculate on a **by-character level**. Because of rounding effects,\"\n\" this will mostly lead to a slightly larger number: \"\n\"*sum([pymupdf.get_text_length(c) for c in text]) > \"\n\"pymupdf.get_text_length(text)*. So either (1) do the same, or (2) use \"\n\"something like *pymupdf.get_text_length(text + \\\"'\\\")* for your \"\n\"calculation.\"\nmsgstr \"\"\n\"이 함수를 사용하여 (:ref:`Page` 또는 :ref:`Shape`) *insert_textbox* 메서드에 필요한 사각형 \"\n\"너비를 결정하는 경우, 이들은 **문자 단위** 로 계산한다는 점에 유의하세요. 반올림 효과로 인해 대부분 약간 더 큰 숫자가 \"\n\"됩니다: *sum([pymupdf.get_text_length(c) for c in text]) > \"\n\"pymupdf.get_text_length(text)*. 따라서 (1) 동일하게 수행하거나 (2) 계산에 \"\n\"*pymupdf.get_text_length(text + \\\"'\\\")* 와 같은 것을 사용하세요.\"\n\n#: ../../functions.rst:431 27bb3947e15d491f9ae1a90557ac93c6\nmsgid \"\"\n\"Make a PDF-compatible string: if the text contains code points *ord(c) > \"\n\"255*, then it will be converted to UTF-16BE with BOM as a hexadecimal \"\n\"character string enclosed in \\\"<>\\\" brackets like *<feff...>*. Otherwise,\"\n\" it will return the string enclosed in (round) brackets, replacing any \"\n\"characters outside the ASCII range with some special code. Also, every \"\n\"\\\"(\\\", \\\")\\\" or backslash is escaped with a backslash.\"\nmsgstr \"\"\n\"PDF 호환 문자열 생성: 텍스트에 코드 포인트 *ord(c) > 255* 가 포함되어 있으면 BOM이 있는 UTF-16BE로 \"\n\"변환되어 *<feff...>* 와 같이 \\\"<>\\\" 괄호로 둘러싸인 16진수 문자 문자열이 됩니다. 그렇지 않으면 (둥근) 괄호로 \"\n\"둘러싸인 문자열을 반환하며, ASCII 범위 밖의 모든 문자를 특수 코드로 대체합니다. 또한 모든 \\\"(\\\", \\\")\\\" 또는 \"\n\"백슬래시는 백슬래시로 이스케이프됩니다.\"\n\n#: ../../functions.rst:433 b4ad5c5ee1984abb8dd55c5b805e766b\nmsgid \"the object to convert\"\nmsgstr \"변환할 객체\"\n\n#: ../../functions.rst:436 fe9be159fa444a69823866ee3a644680\nmsgid \"PDF-compatible string enclosed in either *()* or *<>*.\"\nmsgstr \"*()* 또는 *<>* 로 둘러싸인 PDF 호환 문자열.\"\n\n#: ../../functions.rst:442 d31809b727e34900979c3b181d3eaad1\nmsgid \"New in v1.16.7\"\nmsgstr \"*v1.16.7의 새로운 기능*\"\n\n#: ../../functions.rst:443 d24cd05f8ec8403d9c6de79d9ab0d3dd\nmsgid \"\"\n\"Changed in v1.19.5: also return natural image orientation extracted from \"\n\"EXIF data if present.\"\nmsgstr \"v1.19.5에서 변경됨: EXIF 데이터가 있으면 추출된 자연 이미지 방향도 반환합니다.\"\n\n#: ../../functions.rst:444 9c4baadc4f9146b19f4058938d9378d0\nmsgid \"\"\n\"Changed in v1.22.5: always return `None` in error cases instead of an \"\n\"empty dictionary.\"\nmsgstr \"v1.22.5에서 변경됨: 오류 경우 빈 딕셔너리 대신 항상 `None` 을 반환합니다.\"\n\n#: ../../functions.rst:446 a4aa625db89144ea89c9a3f2dbf7ffab\nmsgid \"\"\n\"Show important properties of an image provided as a memory area. Its main\"\n\" purpose is to avoid using other Python packages just to determine them.\"\nmsgstr \"\"\n\"메모리 영역으로 제공된 이미지의 중요한 속성을 표시합니다. 주요 목적은 이를 결정하기 위해 다른 Python 패키지를 사용하는 것을\"\n\" 피하는 것입니다.\"\n\n#: ../../functions.rst:448 bd286756e9cf47ccb4c584863393000b\nmsgid \"\"\n\"either an image in memory or an **opened** file. An image in memory may \"\n\"be any of the formats `bytes`, `bytearray` or `io.BytesIO`.\"\nmsgstr \"\"\n\"메모리의 이미지 또는 **열린** 파일. 메모리의 이미지는 `bytes`, `bytearray` 또는 `io.BytesIO` 형식 \"\n\"중 하나일 수 있습니다.\"\n\n#: ../../functions.rst:451 ae650862b48c4011b850d0daa225794c\n#, python-brace-format\nmsgid \"\"\n\"No exception is ever raised. In case of an error, `None` is returned. \"\n\"Otherwise, there are the following items::     In [2]: \"\n\"pymupdf.image_profile(open(\\\"nur-ruhig.jpg\\\", \\\"rb\\\").read())    Out[2]:\"\n\"    {'width': 439,    'height': 501,    'orientation': 0,  # natural \"\n\"orientation (from EXIF)    'transform': (1.0, 0.0, 0.0, 1.0, 0.0, 0.0),  \"\n\"# orientation matrix    'xres': 96,    'yres': 96,    'colorspace': 3,\"\n\"    'bpc': 8,    'ext': 'jpeg',    'cs-name': 'DeviceRGB'}  There is the \"\n\"following relation to **Exif** information encoded in `orientation`, and \"\n\"correspondingly in the `transform` matrix-like (quoted from MuPDF \"\n\"documentation, *ccw* = counter-clockwise):     0. Undefined    1. 0 \"\n\"degree ccw rotation. (Exif = 1)    2. 90 degree ccw rotation. (Exif = 8)\"\n\"    3. 180 degree ccw rotation. (Exif = 3)    4. 270 degree ccw rotation.\"\n\" (Exif = 6)    5. flip on X. (Exif = 2)    6. flip on X, then rotate ccw \"\n\"by 90 degrees. (Exif = 5)    7. flip on X, then rotate ccw by 180 \"\n\"degrees. (Exif = 4)    8. flip on X, then rotate ccw by 270 degrees. \"\n\"(Exif = 7)   .. note::     * For some \\\"exotic\\\" images (FAX encodings, \"\n\"RAW formats and the like), this method will not work. You can however \"\n\"still work with such images in PyMuPDF, e.g. by using \"\n\":meth:`Document.extract_image` or create pixmaps via `Pixmap(doc, xref)`.\"\n\" These methods will automatically convert exotic images to the PNG format\"\n\" before returning results.    * You can also get the properties of images\"\n\" embedded in a PDF, via their :data:`xref`. In this case make sure to \"\n\"extract the raw stream: \"\n\"`pymupdf.image_profile(doc.xref_stream_raw(xref))`.    * Images as \"\n\"returned by the image blocks of :meth:`Page.get_text` using \\\"dict\\\" or \"\n\"\\\"rawdict\\\" options are also supported.\"\nmsgstr \"\"\n\n#: ../../functions.rst:452 f365046aab6a422ab4ee8b73d543f9cd\nmsgid \"\"\n\"No exception is ever raised. In case of an error, `None` is returned. \"\n\"Otherwise, there are the following items::\"\nmsgstr \"예외는 발생하지 않습니다. 오류가 발생하면 `None` 이 반환됩니다. 그렇지 않으면 다음 항목이 있습니다::\"\n\n#: ../../functions.rst:467 0a3c370635a74f479d534ebf96ff9900\nmsgid \"\"\n\"There is the following relation to **Exif** information encoded in \"\n\"`orientation`, and correspondingly in the `transform` matrix-like (quoted\"\n\" from MuPDF documentation, *ccw* = counter-clockwise):\"\nmsgstr \"\"\n\"`orientation` 에 인코딩된 **Exif** 정보 및 이에 해당하는 `transform` 행렬과의 관계는 다음과 \"\n\"같습니다(MuPDF 문서에서 인용, *ccw* = 반시계 방향):\"\n\n#: ../../functions.rst:469 d75fb78e754140279e17dde7e31c4e01\nmsgid \"Undefined\"\nmsgstr \"정의되지 않음\"\n\n#: ../../functions.rst:470 b480ec9529c54f6f9e09c19692e33f54\nmsgid \"0 degree ccw rotation. (Exif = 1)\"\nmsgstr \"0도 반시계 방향 회전. (Exif = 1)\"\n\n#: ../../functions.rst:471 25587535c5224fac9824b413e690ff06\nmsgid \"90 degree ccw rotation. (Exif = 8)\"\nmsgstr \"90도 반시계 방향 회전. (Exif = 8)\"\n\n#: ../../functions.rst:472 f6cf386d1e9e450b8d71f709dcf0eb6f\nmsgid \"180 degree ccw rotation. (Exif = 3)\"\nmsgstr \"180도 반시계 방향 회전. (Exif = 3)\"\n\n#: ../../functions.rst:473 139d003f85c4423c9cbb2eccc8f4c541\nmsgid \"270 degree ccw rotation. (Exif = 6)\"\nmsgstr \"270도 반시계 방향 회전. (Exif = 6)\"\n\n#: ../../functions.rst:474 dc1ea011d6f74d078d9e198ba656d4d0\nmsgid \"flip on X. (Exif = 2)\"\nmsgstr \"X축으로 뒤집기. (Exif = 2)\"\n\n#: ../../functions.rst:475 2d185d52566946e2870d9cb80628b63f\nmsgid \"flip on X, then rotate ccw by 90 degrees. (Exif = 5)\"\nmsgstr \"X축으로 뒤집은 후 90도 반시계 방향 회전. (Exif = 5)\"\n\n#: ../../functions.rst:476 33f9468536364528a46aab5370439e20\nmsgid \"flip on X, then rotate ccw by 180 degrees. (Exif = 4)\"\nmsgstr \"X축으로 뒤집은 후 180도 반시계 방향 회전. (Exif = 4)\"\n\n#: ../../functions.rst:477 424b2838db7f419694385fa5eff04abc\nmsgid \"flip on X, then rotate ccw by 270 degrees. (Exif = 7)\"\nmsgstr \"X축으로 뒤집은 후 270도 반시계 방향 회전. (Exif = 7)\"\n\n#: ../../functions.rst:482 5e9805b4707e468198b7d77d011a26fd\nmsgid \"\"\n\"For some \\\"exotic\\\" images (FAX encodings, RAW formats and the like), \"\n\"this method will not work. You can however still work with such images in\"\n\" PyMuPDF, e.g. by using :meth:`Document.extract_image` or create pixmaps \"\n\"via `Pixmap(doc, xref)`. These methods will automatically convert exotic \"\n\"images to the PNG format before returning results.\"\nmsgstr \"\"\n\"일부 \\\"특수\\\" 이미지(FAX 인코딩, RAW 형식 등)의 경우 이 메서드는 작동하지 않습니다. 그러나 PyMuPDF에서 \"\n\":meth:`Document.extract_image` 를 사용하거나 `Pixmap(doc, xref)` 를 통해 픽스맵을 생성하는\"\n\" 등으로 이러한 이미지를 계속 작업할 수 있습니다. 이러한 메서드는 결과를 반환하기 전에 특수 이미지를 자동으로 PNG 형식으로 \"\n\"변환합니다.\"\n\n#: ../../functions.rst:483 39ee6e4ff50f4fc1bc0a90cf4b141a03\nmsgid \"\"\n\"You can also get the properties of images embedded in a PDF, via their \"\n\":data:`xref`. In this case make sure to extract the raw stream: \"\n\"`pymupdf.image_profile(doc.xref_stream_raw(xref))`.\"\nmsgstr \"\"\n\"PDF에 포함된 이미지의 속성은 :data:`xref` 를 통해 가져올 수도 있습니다. 이 경우 원시 스트림을 추출해야 합니다: \"\n\"`pymupdf.image_profile(doc.xref_stream_raw(xref))`.\"\n\n#: ../../functions.rst:484 5d7229a1558045eab12f2a4a6c855d76\nmsgid \"\"\n\"Images as returned by the image blocks of :meth:`Page.get_text` using \"\n\"\\\"dict\\\" or \\\"rawdict\\\" options are also supported.\"\nmsgstr \"\"\n\"\\\"dict\\\" 또는 \\\"rawdict\\\" 옵션을 사용하는 :meth:`Page.get_text` 의 이미지 블록으로 반환된 \"\n\"이미지도 지원됩니다.\"\n\n#: ../../functions.rst:491 4c052d2131a14058938b56d3418e131d\nmsgid \"\"\n\"Return the header string required to make a valid document out of page \"\n\"text outputs.\"\nmsgstr \"페이지 텍스트 출력으로 유효한 문서를 만들기 위해 필요한 헤더 문자열을 반환합니다.\"\n\n#: ../../functions.rst:493 ../../functions.rst:505\n#: 12aff9588a3141ceb5a3d8365a3228bf e15e0919c03e4689962a3d7f0cbfd1f1\nmsgid \"type of document. Use the same as the output parameter of *get_text()*.\"\nmsgstr \"문서 타입. *get_text()* 의 출력 매개변수와 동일하게 사용하세요.\"\n\n#: ../../functions.rst:495 451d5274d5404d8795385325e59833bb\nmsgid \"optional arbitrary name to use in output types \\\"json\\\" and \\\"xml\\\".\"\nmsgstr \"출력 타입 \\\"json\\\" 및 \\\"xml\\\"에서 사용할 선택적 임의 이름.\"\n\n#: ../../functions.rst:503 89b80fb501af4a16b7a9476a55a22270\nmsgid \"\"\n\"Return the trailer string required to make a valid document out of page \"\n\"text outputs. See :meth:`Page.get_text` for an example.\"\nmsgstr \"\"\n\"페이지 텍스트 출력으로 유효한 문서를 만들기 위해 필요한 트레일러 문자열을 반환합니다. 예제는 \"\n\":meth:`Page.get_text` 를 참조하세요.\"\n\n#: ../../functions.rst:513 74049436f1104036ae9fea6fab3f8454\nmsgid \"\"\n\"Delete an object containing XML-based metadata from the PDF. (Py-) MuPDF \"\n\"does not support XML-based metadata. Use this if you want to make sure \"\n\"that the conventional metadata dictionary will be used exclusively. Many \"\n\"thirdparty PDF programs insert their own metadata in XML format and thus \"\n\"may override what you store in the conventional dictionary. This method \"\n\"deletes any such reference, and the corresponding PDF object will be \"\n\"deleted during next garbage collection of the file.\"\nmsgstr \"\"\n\"PDF에서 XML 기반 메타데이터를 포함하는 객체를 삭제합니다. (Py-) MuPDF는 XML 기반 메타데이터를 지원하지 않습니다.\"\n\" 기존 메타데이터 딕셔너리가 독점적으로 사용되도록 하려면 이것을 사용하세요. 많은 타사 PDF 프로그램이 자체 메타데이터를 XML \"\n\"형식으로 삽입하므로 기존 딕셔너리에 저장한 내용을 덮어쓸 수 있습니다. 이 메서드는 이러한 참조를 삭제하며, 해당 PDF 객체는 \"\n\"다음 파일 가비지 수집 중에 삭제됩니다.\"\n\n#: ../../functions.rst:519 5db2a02465744688ab3e7c8aa58850d4\nmsgid \"\"\n\"Return the XML-based metadata :data:`xref` of the PDF if present -- also \"\n\"refer to :meth:`Document.del_xml_metadata`. You can use it to retrieve \"\n\"the content via :meth:`Document.xref_stream` and then work with it using \"\n\"some XML software.\"\nmsgstr \"\"\n\"PDF의 XML 기반 메타데이터 :data:`xref` 가 있으면 반환합니다 -- \"\n\":meth:`Document.del_xml_metadata` 도 참조하세요. :meth:`Document.xref_stream` 을\"\n\" 통해 콘텐츠를 검색한 다음 일부 XML 소프트웨어를 사용하여 작업할 수 있습니다.\"\n\n#: ../../functions.rst:522 8fbcc03c4196406eacf3af64dba64c1d\nmsgid \":data:`xref` of PDF file level XML metadata -- or 0 if none exists.\"\nmsgstr \"PDF 파일 레벨 XML 메타데이터의 :data:`xref` -- 없으면 0.\"\n\n#: ../../functions.rst:528 6b8b6c79577e42c1a405e89e84d55806\nmsgid \"Run a page through a device.\"\nmsgstr \"디바이스를 통해 페이지 실행.\"\n\n#: ../../functions.rst:530 79f4006550f34f108fbceb98de33b368\nmsgid \"Device, obtained from one of the :ref:`Device` constructors.\"\nmsgstr \"디바이스, :ref:`Device` 생성자 중 하나에서 얻음.\"\n\n#: ../../functions.rst:533 c3fd75078a914ad5a5569e5547dd1af9\nmsgid \"\"\n\"Transformation to apply to the page. Set it to :ref:`Identity` if no \"\n\"transformation is desired.\"\nmsgstr \"페이지에 적용할 변환. 변환이 필요 없으면 :ref:`Identity` 로 설정하세요.\"\n\n#: ../../functions.rst:540 3a6b7151b4a6425ab6f57671e6361a36\nmsgid \"New in v1.19.0\"\nmsgstr \"*v1.19.0의 새로운 기능*\"\n\n#: ../../functions.rst:541 630cdd26bd544107b791cfb24730326a\nmsgid \"\"\n\"Changed in v1.22.0: optionally also return the OCG name applicable to the\"\n\" boundary box.\"\nmsgstr \"v1.22.0에서 변경됨: 선택적으로 경계 상자에 적용 가능한 OCG 이름도 반환합니다.\"\n\n#: ../../functions.rst:543 d9826653f5074292942cba6ac72b5123\nmsgid \"\"\n\"a list of rectangles that envelop text, image or drawing objects. Each \"\n\"item is a tuple `(type, (x0, y0, x1, y1))` where the second tuple \"\n\"consists of rectangle coordinates, and *type* is one of the following \"\n\"values. If `layers=True`, there is a third item containing the OCG name \"\n\"or `None`: `(type, (x0, y0, x1, y1), None)`.  * `\\\"fill-text\\\"` -- normal\"\n\" text (painted without character borders) * `\\\"stroke-text\\\"` -- text \"\n\"showing character borders only * `\\\"ignore-text\\\"` -- text that should \"\n\"not be displayed (e.g. as used by OCR text layers) * `\\\"fill-path\\\"` -- \"\n\"drawing with fill color (and no border) * `\\\"stroke-path\\\"` -- drawing \"\n\"with border (and no fill color) * `\\\"fill-image\\\"` -- displays an image *\"\n\" `\\\"fill-shade\\\"` -- display a shading  The item sequence represents the \"\n\"**sequence in which these commands are executed** to build the page's \"\n\"appearance. Therefore, if an item's bbox intersects or contains that of a\"\n\" previous item, then the previous item may be (partially) covered / \"\n\"hidden.   So this list can be used to detect such situations. An item's \"\n\"index in this list equals the value of a `\\\"seqno\\\"` in dictionaries as \"\n\"returned by :meth:`Page.get_drawings` and :meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\n#: ../../functions.rst:543 cea75236177747a387f9c237fd0cbcdd\nmsgid \"\"\n\"a list of rectangles that envelop text, image or drawing objects. Each \"\n\"item is a tuple `(type, (x0, y0, x1, y1))` where the second tuple \"\n\"consists of rectangle coordinates, and *type* is one of the following \"\n\"values. If `layers=True`, there is a third item containing the OCG name \"\n\"or `None`: `(type, (x0, y0, x1, y1), None)`.\"\nmsgstr \"\"\n\"텍스트, 이미지 또는 그리기 객체를 둘러싸는 사각형 목록. 각 항목은 `(type, (x0, y0, x1, y1))` 튜플이며, 두\"\n\" 번째 튜플은 사각형 좌표로 구성되고 *type* 은 다음 값 중 하나입니다. `layers=True` 인 경우 OCG 이름 또는 \"\n\"`None` 을 포함하는 세 번째 항목이 있습니다: `(type, (x0, y0, x1, y1), None)`.\"\n\n#: ../../functions.rst:545 bd57ae852199441396045da3900fa159\nmsgid \"`\\\"fill-text\\\"` -- normal text (painted without character borders)\"\nmsgstr \"`\\\"fill-text\\\"` -- 일반 텍스트(문자 경계 없이 그려짐)\"\n\n#: ../../functions.rst:546 73652bbb988548bf9aecacbdf1d31641\nmsgid \"`\\\"stroke-text\\\"` -- text showing character borders only\"\nmsgstr \"`\\\"stroke-text\\\"` -- 문자 경계만 표시하는 텍스트\"\n\n#: ../../functions.rst:547 4d516464739349f3a0019a924497c287\nmsgid \"\"\n\"`\\\"ignore-text\\\"` -- text that should not be displayed (e.g. as used by \"\n\"OCR text layers)\"\nmsgstr \"`\\\"ignore-text\\\"` -- 표시되지 않아야 하는 텍스트(예: OCR 텍스트 레이어에서 사용)\"\n\n#: ../../functions.rst:548 3be92a4cabce42a19d1018efd7b77e1a\nmsgid \"`\\\"fill-path\\\"` -- drawing with fill color (and no border)\"\nmsgstr \"`\\\"fill-path\\\"` -- 채우기 색상으로 그리기(경계 없음)\"\n\n#: ../../functions.rst:549 5d82465ff84b4562a2c5ecc802effabd\nmsgid \"`\\\"stroke-path\\\"` -- drawing with border (and no fill color)\"\nmsgstr \"`\\\"stroke-path\\\"` -- 경계로 그리기(채우기 색상 없음)\"\n\n#: ../../functions.rst:550 af1203ba9d33446facef8a91f01f7559\nmsgid \"`\\\"fill-image\\\"` -- displays an image\"\nmsgstr \"`\\\"fill-image\\\"` -- 이미지 표시\"\n\n#: ../../functions.rst:551 650de20fff594c48b1df187a0852978d\nmsgid \"`\\\"fill-shade\\\"` -- display a shading\"\nmsgstr \"`\\\"fill-shade\\\"` -- 음영 표시\"\n\n#: ../../functions.rst:553 ef60b6dd48c44a5b8181df41a22356a2\nmsgid \"\"\n\"The item sequence represents the **sequence in which these commands are \"\n\"executed** to build the page's appearance. Therefore, if an item's bbox \"\n\"intersects or contains that of a previous item, then the previous item \"\n\"may be (partially) covered / hidden.\"\nmsgstr \"\"\n\"항목 시퀀스는 페이지의 모양을 구축하기 위해 **이러한 명령이 실행되는 순서** 를 나타냅니다. 따라서 항목의 bbox가 이전 \"\n\"항목과 교차하거나 포함하는 경우 이전 항목이 (부분적으로) 덮이거나 숨겨질 수 있습니다.\"\n\n#: ../../functions.rst:556 fa7f832dc453447d83d333bd0edaa9aa\nmsgid \"\"\n\"So this list can be used to detect such situations. An item's index in \"\n\"this list equals the value of a `\\\"seqno\\\"` in dictionaries as returned \"\n\"by :meth:`Page.get_drawings` and :meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\"따라서 이 목록을 사용하여 이러한 상황을 감지할 수 있습니다. 이 목록의 항목 인덱스는 \"\n\":meth:`Page.get_drawings` 및 :meth:`Page.get_texttrace` 에서 반환된 딕셔너리의 \"\n\"`\\\"seqno\\\"` 값과 같습니다.\"\n\n#: ../../functions.rst:563 e6e86279727b44108e80bd887f5dec4b\nmsgid \"New in v1.18.16\"\nmsgstr \"*v1.18.16의 새로운 기능*\"\n\n#: ../../functions.rst:564 4a8a69681c1f4dd58e655d55319a42bd\nmsgid \"Changed in v1.19.0: added key \\\"seqno\\\".\"\nmsgstr \"v1.19.0에서 변경됨: 키 \\\"seqno\\\" 추가.\"\n\n#: ../../functions.rst:565 8ec88b876f364e48be39bb7321df5b78\nmsgid \"\"\n\"Changed in v1.19.1: stroke and fill colors now always are either RGB or \"\n\"GRAY\"\nmsgstr \"v1.19.1에서 변경됨: 스트로크 및 채우기 색상이 이제 항상 RGB 또는 GRAY입니다\"\n\n#: ../../functions.rst:566 6262d51351704e3cb0b74e4a397e4d17\nmsgid \"\"\n\"Changed in v1.19.3: span and character bboxes are now also correct if \"\n\"`dir != (1, 0)`.\"\nmsgstr \"v1.19.3에서 변경됨: `dir != (1, 0)` 인 경우에도 스팬 및 문자 bbox가 이제 올바릅니다.\"\n\n#: ../../functions.rst:567 7b239315a5da4ad49a8e0934405a7fd3\nmsgid \"Changed in v1.22.0: add new dictionary key \\\"layer\\\".\"\nmsgstr \"v1.22.0에서 변경됨: 새로운 딕셔너리 키 \\\"layer\\\" 추가.\"\n\n#: ../../functions.rst:570 834e9d9810714938bfbf774e17193982\nmsgid \"\"\n\"Return low-level text information of the page. The method is available \"\n\"for **all** document types. The result is a list of Python dictionaries \"\n\"with the following content::\"\nmsgstr \"\"\n\"페이지의 저수준 텍스트 정보를 반환합니다. 이 메서드는 **모든** 문서 타입에서 사용할 수 있습니다. 결과는 다음 내용을 가진 \"\n\"Python 딕셔너리 목록입니다::\"\n\n#: ../../functions.rst:606 8b58904760d74cf1b106164af7de1954\nmsgid \"Details:\"\nmsgstr \"세부사항:\"\n\n#: ../../functions.rst:608 63e3f59519b34151ba92179d999fb9ee\nmsgid \"\"\n\"Information above tagged with \\\"(1)\\\" has the same meaning and value as \"\n\"explained in :ref:`TextPage`.\"\nmsgstr \"\\\"(1)\\\"로 태그된 위의 정보는 :ref:`TextPage` 에서 설명한 것과 동일한 의미와 값을 가집니다.\"\n\n#: ../../functions.rst:610 adef9c5a97be49e783885187ce3815e0\nmsgid \"\"\n\"Please note that the font ``flags`` value will never contain a \"\n\"*superscript* flag bit: the detection of superscripts is done within \"\n\"MuPDF :ref:`TextPage` code -- it is not a property of any font.\"\nmsgstr \"\"\n\"글꼴 ``flags`` 값에는 *위첨자* 플래그 비트가 포함되지 않습니다: 위첨자 감지는 MuPDF :ref:`TextPage` \"\n\"코드 내에서 수행됩니다 -- 이것은 어떤 글꼴의 속성도 아닙니다.\"\n\n#: ../../functions.rst:611 42e4ea3c18d54211b94b728f0c637564\nmsgid \"\"\n\"Also note, that the text *color* is encoded as the usual tuple of floats \"\n\"0 <= f <= 1 -- not in sRGB format. Depending on `span[\\\"type\\\"]`, \"\n\"interpret this as fill color or stroke color.\"\nmsgstr \"\"\n\"텍스트 *color* 는 일반적인 float 튜플 0 <= f <= 1로 인코딩됩니다 -- sRGB 형식이 아닙니다. \"\n\"`span[\\\"type\\\"]` 에 따라 이를 채우기 색상 또는 스트로크 색상으로 해석하세요.\"\n\n#: ../../functions.rst:613 c064211d745e47be945feb7030afbad2\nmsgid \"There are 3 text span types:\"\nmsgstr \"3가지 텍스트 스팬 타입이 있습니다:\"\n\n#: ../../functions.rst:615 fbf31286bd4548fd975462e964233915\nmsgid \"\"\n\"0: Filled text -- equivalent to PDF text rendering mode 0 (`0 Tr`, the \"\n\"default in PDF), only each character's \\\"inside\\\" is shown.\"\nmsgstr \"\"\n\"0: 채워진 텍스트 -- PDF 텍스트 렌더링 모드 0(`0 Tr`, PDF의 기본값)과 동일하며, 각 문자의 \\\"내부\\\"만 \"\n\"표시됩니다.\"\n\n#: ../../functions.rst:616 941b2c374d584068847e1546fdbdf66c\nmsgid \"\"\n\"1: Stroked text -- equivalent to `1 Tr`, only the character borders are \"\n\"shown.\"\nmsgstr \"1: 스트로크 텍스트 -- `1 Tr` 와 동일하며, 문자 경계만 표시됩니다.\"\n\n#: ../../functions.rst:617 d2fc5c83a61a4d4f8edd462b343a794f\nmsgid \"3: Ignored text -- equivalent to `3 Tr` (hidden text).\"\nmsgstr \"3: 무시된 텍스트 -- `3 Tr` (숨겨진 텍스트)와 동일합니다.\"\n\n#: ../../functions.rst:619 82c0b57a08e74995b7bfc0b18220c635\n#, python-format\nmsgid \"\"\n\"Line width in this context is important only for processing \"\n\"`span[\\\"type\\\"] != 0`: it determines the thickness of the character's \"\n\"border line. This value may not be provided at all with the text data. In\"\n\" this case, a value of 5% of the :data:`fontsize` (`span[\\\"size\\\"] * \"\n\"0,05`) is generated. Often, an \\\"artificial\\\" bold text in PDF is created\"\n\" by `2 Tr`. There is no equivalent span type for this case. Instead, \"\n\"respective text is represented by two consecutive spans -- which are \"\n\"identical in every aspect, except for their types, which are 0, resp 1. \"\n\"It is your responsibility to handle this type of situation - in \"\n\":meth:`Page.get_text`, MuPDF is doing this for you.\"\nmsgstr \"\"\n\"이 맥락에서 선 너비는 `span[\\\"type\\\"] != 0` 처리에만 중요합니다: 문자 경계선의 두께를 결정합니다. 이 값은 \"\n\"텍스트 데이터와 함께 전혀 제공되지 않을 수 있습니다. 이 경우 :data:`fontsize` 의 5% \"\n\"값(`span[\\\"size\\\"] * 0,05`)이 생성됩니다. 종종 PDF의 \\\"인위적인\\\" 굵은 텍스트는 `2 Tr` 로 \"\n\"생성됩니다. 이 경우에 해당하는 스팬 타입은 없습니다. 대신 해당 텍스트는 두 개의 연속된 스팬으로 표현됩니다 -- 타입이 각각 \"\n\"0과 1인 것을 제외하고 모든 면에서 동일합니다. 이러한 상황을 처리하는 것은 사용자의 책임입니다 - \"\n\":meth:`Page.get_text` 에서는 MuPDF가 이를 수행합니다.\"\n\n#: ../../functions.rst:620 b0c07cf4d26348589ec94ed16a6c3372\nmsgid \"\"\n\"For data compactness, the character's unicode is provided here. Use \"\n\"built-in function `chr()` for the character itself.\"\nmsgstr \"데이터 압축을 위해 여기에 문자의 유니코드가 제공됩니다. 문자 자체는 내장 함수 `chr()` 을 사용하세요.\"\n\n#: ../../functions.rst:621 3c60ceeb1f4f4171b04db58fdec4733e\nmsgid \"\"\n\"The alpha / opacity value of the span's text, `0 <= opacity <= 1`, 0 is \"\n\"invisible text, 1 (100%) is intransparent. Depending on `span[\\\"type\\\"]`,\"\n\" interpret this value as *fill* opacity or, resp. *stroke* opacity.\"\nmsgstr \"\"\n\"스팬 텍스트의 알파/불투명도 값, `0 <= opacity <= 1`, 0은 보이지 않는 텍스트, 1(100%)은 불투명합니다. \"\n\"`span[\\\"type\\\"]` 에 따라 이 값을 *fill* 불투명도 또는 *stroke* 불투명도로 해석하세요.\"\n\n#: ../../functions.rst:622 b237cc55d5244595a4d9e0f2faf43ec2\nmsgid \"\"\n\"*(Changed in v1.19.0)* This value is equal or close to `char[\\\"bbox\\\"]` \"\n\"of \\\"rawdict\\\". In particular, the bbox **height** value is always \"\n\"computed as if **\\\"small glyph heights\\\"** had been requested.\"\nmsgstr \"\"\n\"*(v1.19.0에서 변경됨)* 이 값은 \\\"rawdict\\\"의 `char[\\\"bbox\\\"]` 와 같거나 가깝습니다. 특히 bbox\"\n\" **height** 값은 항상 **\\\"small glyph heights\\\"** 가 요청된 것처럼 계산됩니다.\"\n\n#: ../../functions.rst:623 d0aece89209341f4995bd44237ffb0bd\nmsgid \"*(New in v1.19.0)* This is the union of all character bboxes.\"\nmsgstr \"*(v1.19.0의 새로운 기능)* 이것은 모든 문자 bbox의 합집합입니다.\"\n\n#: ../../functions.rst:624 4a2dea33adee4c3f934f477d8961d184\nmsgid \"\"\n\"*(New in v1.19.0)* Enumerates the commands that build up the page's \"\n\"appearance. Can be used to find out whether text is effectively hidden by\"\n\" objects, which are painted \\\"later\\\", or *over* some object. So if there\"\n\" is a drawing or image with a higher sequence number, whose bbox overlaps\"\n\" (parts of) this text span, one may assume that such an object hides the \"\n\"resp. text. Different text spans have identical sequence numbers if they \"\n\"were created in one go.\"\nmsgstr \"\"\n\"*(v1.19.0의 새로운 기능)* 페이지의 모양을 구축하는 명령을 열거합니다. 텍스트가 \\\"나중에\\\" 그려지거나 어떤 객체 \"\n\"*위에* 그려진 객체에 의해 효과적으로 숨겨지는지 확인하는 데 사용할 수 있습니다. 따라서 더 높은 시퀀스 번호를 가진 그리기 또는\"\n\" 이미지가 있고, 그 bbox가 이 텍스트 스팬의 (일부)와 겹치는 경우, 그러한 객체가 해당 텍스트를 숨긴다고 가정할 수 \"\n\"있습니다. 다른 텍스트 스팬은 한 번에 생성된 경우 동일한 시퀀스 번호를 가집니다.\"\n\n#: ../../functions.rst:625 746e13f904994ba1b391640966cb9cce\nmsgid \"\"\n\"*(New in v1.22.0)* The name of the Optional Content Group (OCG) if \"\n\"applicable or `None`.\"\nmsgstr \"*(v1.22.0의 새로운 기능)* 해당하는 경우 Optional Content Group (OCG)의 이름 또는 `None`.\"\n\n#: ../../functions.rst:627 39e39ef69db145bb8fd6d7a429821aa0\nmsgid \"\"\n\"Here is a list of similarities and differences of `page.get_texttrace()` \"\n\"compared to `page.get_text(\\\"rawdict\\\")`:\"\nmsgstr \"\"\n\"`page.get_text(\\\"rawdict\\\")` 와 비교한 `page.get_texttrace()` 의 유사점과 차이점 \"\n\"목록입니다:\"\n\n#: ../../functions.rst:629 917f1c8f176a4ed594b134848132c93c\nmsgid \"\"\n\"The method is up to **twice as fast,** compared to \\\"rawdict\\\" \"\n\"extraction. Depends on the amount of text.\"\nmsgstr \"이 메서드는 \\\"rawdict\\\" 추출과 비교하여 **최대 2배 빠릅니다**. 텍스트 양에 따라 다릅니다.\"\n\n#: ../../functions.rst:630 1bed3805162b46efbe3f575d925a99b2\nmsgid \"\"\n\"The returned data is very **much smaller in size** -- although it \"\n\"provides more information.\"\nmsgstr \"반환된 데이터는 **크기가 훨씬 작습니다** -- 더 많은 정보를 제공하지만.\"\n\n#: ../../functions.rst:631 a1624b170eb441899e89639c83c5bec8\nmsgid \"\"\n\"Additional types of text **invisibility can be detected**: opacity = 0 or\"\n\" type > 1 or overlapping bbox of an object with a higher sequence number.\"\nmsgstr \"\"\n\"추가 유형의 텍스트 **보이지 않음을 감지할 수 있습니다**: opacity = 0 또는 type > 1 또는 더 높은 시퀀스 \"\n\"번호를 가진 객체의 겹치는 bbox.\"\n\n#: ../../functions.rst:632 8a4627bf3e3b4ccdab047276202cf1cc\nmsgid \"\"\n\"If MuPDF returns unicode 0xFFFD (65533) for unrecognized characters, you \"\n\"may still be able to deduct desired information from the glyph id.\"\nmsgstr \"\"\n\"MuPDF가 인식되지 않은 문자에 대해 유니코드 0xFFFD(65533)를 반환하는 경우, 글리프 id에서 원하는 정보를 추론할 수\"\n\" 있을 수 있습니다.\"\n\n#: ../../functions.rst:633 9e5fc14c54d74d61a2dc0d327be33a78\nmsgid \"\"\n\"The `span[\\\"chars\\\"]` **contains no spaces**, **except** the document \"\n\"creator has explicitly coded them. They **will never be generated** like \"\n\"it happens in :meth:`Page.get_text` methods. To provide some help for \"\n\"doing your own computations here, the width of a space character is \"\n\"given. This value is derived from the font where possible. Otherwise the \"\n\"value of a fallback font is taken.\"\nmsgstr \"\"\n\"`span[\\\"chars\\\"]` 는 **공백을 포함하지 않습니다**, **문서 작성자가 명시적으로 코딩한 경우를 제외하고**. \"\n\":meth:`Page.get_text` 메서드에서 발생하는 것처럼 **절대 생성되지 않습니다**. 여기서 자체 계산을 수행하는 데 \"\n\"도움이 되도록 공백 문자의 너비가 제공됩니다. 이 값은 가능한 경우 글꼴에서 파생됩니다. 그렇지 않으면 대체 글꼴의 값이 \"\n\"사용됩니다.\"\n\n#: ../../functions.rst:634 15ac82aad6cb4e3a9170eca749052958\nmsgid \"\"\n\"There is no effort to organize text like it happens for a :ref:`TextPage`\"\n\" (the hierarchy of blocks, lines, spans, and characters). Characters are \"\n\"simply extracted in sequence, one by one, and put in a span. Whenever any\"\n\" of the span's characteristics changes, a new span is started. So you may\"\n\" find characters with different `origin.y` values in the same span (which\"\n\" means they would appear in different lines). You cannot assume, that \"\n\"span characters are sorted in any particular order -- you must make sense\"\n\" of the info yourself, taking `span[\\\"dir\\\"]`, `span[\\\"wmode\\\"]`, etc. \"\n\"into account.\"\nmsgstr \"\"\n\":ref:`TextPage` 에서 발생하는 것처럼 텍스트를 구성하려는 시도가 없습니다(블록, 라인, 스팬 및 문자의 계층 구조). \"\n\"문자는 단순히 순차적으로 하나씩 추출되어 스팬에 배치됩니다. 스팬의 특성이 변경될 때마다 새로운 스팬이 시작됩니다. 따라서 동일한 \"\n\"스팬에서 다른 `origin.y` 값을 가진 문자를 찾을 수 있습니다(이는 다른 라인에 나타날 것임을 의미). 스팬 문자가 특정 \"\n\"순서로 정렬되어 있다고 가정할 수 없습니다 -- `span[\\\"dir\\\"]`, `span[\\\"wmode\\\"]` 등을 고려하여 정보를\"\n\" 직접 이해해야 합니다.\"\n\n#: ../../functions.rst:652 a0c67b42ef3e49e0b1f2ac26995741aa\nmsgid \"Ligatures are represented like this:\"\nmsgstr \"합자는 다음과 같이 표현됩니다:\"\n\n#: ../../functions.rst:636 3c824ed918b34e58861b077c4365477f\nmsgid \"\"\n\"MuPDF handles the following ligatures: \\\"fi\\\", \\\"ff\\\", \\\"fl\\\", \\\"ft\\\", \"\n\"\\\"st\\\", \\\"ffi\\\", and \\\"ffl\\\" (only the first 3 are mostly ever used). If \"\n\"the page contains e.g. ligature \\\"fi\\\", you will find the following two \"\n\"character items subsequent to each other::\"\nmsgstr \"\"\n\"MuPDF는 다음 합자를 처리합니다: \\\"fi\\\", \\\"ff\\\", \\\"fl\\\", \\\"ft\\\", \\\"st\\\", \\\"ffi\\\", \"\n\"\\\"ffl\\\" (처음 3개만 주로 사용됨). 페이지에 예를 들어 합자 \\\"fi\\\"가 포함되어 있으면 다음 두 문자 항목이 서로 \"\n\"연속으로 나타납니다::\"\n\n#: ../../functions.rst:641 bcc79b6581f34f9280c07f51f267b1ba\nmsgid \"\"\n\"This means that the bbox of the first ligature character is the area \"\n\"containing the complete, compound glyph. Subsequent ligature components \"\n\"are recognizable by their glyph value -1 and a bbox of width zero.\"\nmsgstr \"\"\n\"이것은 첫 번째 합자 문자의 bbox가 완전한 복합 글리프를 포함하는 영역임을 의미합니다. 후속 합자 구성 요소는 글리프 값 -1과\"\n\" 너비가 0인 bbox로 인식할 수 있습니다.\"\n\n#: ../../functions.rst:642 7817cb437109492a80ade1f89c34b3cf\nmsgid \"\"\n\"You may want to replace those 2 or 3 char tuples by one, that represents \"\n\"the ligature itself. Use the following mapping of ligatures to unicodes:\"\nmsgstr \"2개 또는 3개의 문자 튜플을 합자 자체를 나타내는 하나로 대체할 수 있습니다. 다음 합자-유니코드 매핑을 사용하세요:\"\n\n#: ../../functions.rst:644 aaebcaafe03144fbb8992f69ed5c8f00\nmsgid \"`\\\"ff\\\" -> 0xFB00`\"\nmsgstr \"`\\\"ff\\\" -> 0xFB00`\"\n\n#: ../../functions.rst:645 939984a5e5e04878ae04eea7858b9f77\nmsgid \"`\\\"fi\\\" -> 0xFB01`\"\nmsgstr \"`\\\"fi\\\" -> 0xFB01`\"\n\n#: ../../functions.rst:646 d3fed8f13cba4ce885dd69100891d76e\nmsgid \"`\\\"fl\\\" -> 0xFB02`\"\nmsgstr \"`\\\"fl\\\" -> 0xFB02`\"\n\n#: ../../functions.rst:647 b9933ebf7ec545d8a6c748b98f667811\nmsgid \"`\\\"ffi\\\" -> 0xFB03`\"\nmsgstr \"`\\\"ffi\\\" -> 0xFB03`\"\n\n#: ../../functions.rst:648 e0514a34957c47a78d18f3dda4d2429d\nmsgid \"`\\\"ffl\\\" -> 0xFB04`\"\nmsgstr \"`\\\"ffl\\\" -> 0xFB04`\"\n\n#: ../../functions.rst:649 37fa3ab049b5470c812eb68f92a34b47\nmsgid \"`\\\"ft\\\" -> 0xFB05`\"\nmsgstr \"`\\\"ft\\\" -> 0xFB05`\"\n\n#: ../../functions.rst:650 837026b002484cd789d83dcb6b644892\nmsgid \"`\\\"st\\\" -> 0xFB06`\"\nmsgstr \"`\\\"st\\\" -> 0xFB06`\"\n\n#: ../../functions.rst:652 50f11c41758d4ce0bf5813b7baecd6c0\nmsgid \"\"\n\"So you may want to replace the two example tuples above by the following \"\n\"single one: `(0xFB01, glyph, (x, y), (x0, y0, x1, y1))` (there is usually\"\n\" no need to lookup the correct glyph id for 0xFB01 in the resp. font, but\"\n\" you may execute `font.has_glyph(0xFB01)` and use its return value).\"\nmsgstr \"\"\n\"따라서 위의 두 예제 튜플을 다음 단일 튜플로 대체할 수 있습니다: `(0xFB01, glyph, (x, y), (x0, y0, \"\n\"x1, y1))` (일반적으로 해당 글꼴에서 0xFB01에 대한 올바른 글리프 id를 조회할 필요는 없지만, \"\n\"`font.has_glyph(0xFB01)` 을 실행하고 반환 값을 사용할 수 있습니다).\"\n\n#: ../../functions.rst:654 222e9b82b659431db35af8eeffb194f6\nmsgid \"\"\n\"**Changed in v1.19.3:** Similar to other text extraction methods, the \"\n\"character and span bboxes envelop the character quads. To recover the \"\n\"quads, follow the same methods :meth:`recover_quad`, \"\n\":meth:`recover_char_quad` or :meth:`recover_span_quad` as explained in \"\n\":ref:`textpagedict`. Use either `None` or `span[\\\"dir\\\"]` for the writing\"\n\" direction.\"\nmsgstr \"\"\n\"**v1.19.3에서 변경됨:** 다른 텍스트 추출 메서드와 유사하게, 문자 및 스팬 bbox는 문자 쿼드를 둘러쌉니다. 쿼드를 \"\n\"복구하려면 :ref:`textpagedict` 에서 설명한 것과 동일한 메서드 :meth:`recover_quad`, \"\n\":meth:`recover_char_quad` 또는 :meth:`recover_span_quad` 를 따르세요. 쓰기 방향에는 \"\n\"`None` 또는 `span[\\\"dir\\\"]` 을 사용하세요.\"\n\n#: ../../functions.rst:656 f5faf881db3d4a9487a05fef55996648\nmsgid \"\"\n\"**Changed in v1.21.1:** If applicable, the name of the OCG is shown in \"\n\"`\\\"layer\\\"`.\"\nmsgstr \"**v1.21.1에서 변경됨:** 해당하는 경우 OCG의 이름이 `\\\"layer\\\"` 에 표시됩니다.\"\n\n#: ../../functions.rst:662 48bf0e585e944bd7b52be8feaac35c5e\nmsgid \"\"\n\"Ensures that the page's so-called graphics state is balanced and new \"\n\"content can be inserted correctly.\"\nmsgstr \"페이지의 소위 그래픽 상태가 균형을 이루고 새 콘텐츠가 올바르게 삽입될 수 있도록 합니다.\"\n\n#: ../../functions.rst:664 eae68e69d2064990b1bf9c7ed594f48c\nmsgid \"\"\n\"In versions 1.24.1+ of PyMuPDF the method was improved and is being \"\n\"executed automatically as required, so you should no longer need to \"\n\"concern yourself with it.\"\nmsgstr \"PyMuPDF 버전 1.24.1+에서 이 메서드가 개선되어 필요에 따라 자동으로 실행되므로 더 이상 신경 쓸 필요가 없습니다.\"\n\n#: ../../functions.rst:666 de7bdd81791342039a777f36b3120609\nmsgid \"We discourage using :meth:`Page.clean_contents` to achieve this.\"\nmsgstr \"이를 달성하기 위해 :meth:`Page.clean_contents` 사용을 권장하지 않습니다.\"\n\n#: ../../functions.rst:672 59ea1ae4764a4a79b7293e1e4acf5bfc\nmsgid \"\"\n\"Indicate whether the page's so-called graphic state is balanced. If \"\n\"`False`, :meth:`Page.wrap_contents` should be executed if new content is \"\n\"inserted (only relevant in `overlay=True` mode). In newer versions \"\n\"(1.24.1+), this check and corresponding adjustments are automatically \"\n\"executed -- you therefore should not be concerned about this anymore.\"\nmsgstr \"\"\n\"페이지의 소위 그래픽 상태가 균형을 이루는지 나타냅니다. `False` 인 경우 새 콘텐츠가 삽입되면 \"\n\":meth:`Page.wrap_contents` 를 실행해야 합니다(`overlay=True` 모드에서만 관련됨). 최신 \"\n\"버전(1.24.1+)에서는 이 확인 및 해당 조정이 자동으로 실행됩니다 -- 따라서 더 이상 신경 쓸 필요가 없습니다.\"\n\n#: ../../functions.rst:680 77bfdbb9ea154021880b68f407cec45e\nmsgid \"\"\n\"Deprecated wrapper for :meth:`TextPage.extractBLOCKS`.  Use \"\n\":meth:`Page.get_text` with the \\\"blocks\\\" option instead.\"\nmsgstr \"\"\n\":meth:`TextPage.extractBLOCKS` 의 더 이상 사용되지 않는 래퍼. 대신 \\\"blocks\\\" 옵션을 사용하는 \"\n\":meth:`Page.get_text` 를 사용하세요.\"\n\n#: ../../functions.rst:688 38ae57f9f7514e3ebe8a9c79b5610c01\nmsgid \"\"\n\"Deprecated wrapper for :meth:`TextPage.extractWORDS`. Use \"\n\":meth:`Page.get_text` with the \\\"words\\\" option instead.\"\nmsgstr \"\"\n\":meth:`TextPage.extractWORDS` 의 더 이상 사용되지 않는 래퍼. 대신 \\\"words\\\" 옵션을 사용하는 \"\n\":meth:`Page.get_text` 를 사용하세요.\"\n\n#: ../../functions.rst:696 3cb9ebe8577f4992ad02eb07f1b73bfe\nmsgid \"Run a page through a list device and return its display list.\"\nmsgstr \"리스트 디바이스를 통해 페이지를 실행하고 디스플레이 리스트를 반환합니다.\"\n\n#: ../../functions.rst:698 25c2a3b94c1848eeb595b0de57aa1246\nmsgid \":ref:`DisplayList`\"\nmsgstr \":ref:`DisplayList`\"\n\n#: ../../functions.rst:699 7c69c8db929044cea53feea2943ed7b7\nmsgid \"the display list of the page.\"\nmsgstr \"페이지의 디스플레이 리스트.\"\n\n#: ../../functions.rst:705 fb125de099214795adc6e298598a8f7c\nmsgid \"\"\n\"PDF only: Retrieve a list of :data:`xref` of :data:`contents` objects of \"\n\"a page. May be empty or contain multiple integers. If the page is cleaned\"\n\" (:meth:`Page.clean_contents`), it will be no more than one entry. The \"\n\"\\\"source\\\" of each `/Contents` object can be individually read by \"\n\":meth:`Document.xref_stream` using an item of this list. Method \"\n\":meth:`Page.read_contents` in contrast walks through this list and \"\n\"concatenates the corresponding sources into one `bytes` object.\"\nmsgstr \"\"\n\"PDF 전용: 페이지의 :data:`contents` 객체의 :data:`xref` 목록을 검색합니다. 비어 있거나 여러 정수를 \"\n\"포함할 수 있습니다. 페이지가 정리된 경우(:meth:`Page.clean_contents`) 항목은 하나 이하입니다. 각 \"\n\"`/Contents` 객체의 \\\"source\\\"는 이 목록의 항목을 사용하여 :meth:`Document.xref_stream` \"\n\"으로 개별적으로 읽을 수 있습니다. 반면 :meth:`Page.read_contents` 메서드는 이 목록을 순회하고 해당 소스를 \"\n\"하나의 `bytes` 객체로 연결합니다.\"\n\n#: ../../functions.rst:713 7fe9d0c499fd470cb67a324f854cddfc\nmsgid \"\"\n\"PDF only: Let the page's `/Contents` key point to this xref. Any \"\n\"previously used contents objects will be ignored and can be removed via \"\n\"garbage collection.\"\nmsgstr \"\"\n\"PDF 전용: 페이지의 `/Contents` 키가 이 xref를 가리키도록 합니다. 이전에 사용된 모든 콘텐츠 객체는 무시되며 \"\n\"가비지 수집을 통해 제거할 수 있습니다.\"\n\n#: ../../functions.rst:719 3aa3a5c37b1c4a4381ccad00ba9b8aa9\nmsgid \"Changed in v1.17.6\"\nmsgstr \"v1.17.6에서 변경됨\"\n\n#: ../../functions.rst:721 60a2a8926c0a40e4b525cb12714eb91a\nmsgid \"\"\n\"PDF only: Clean and concatenate all :data:`contents` objects associated \"\n\"with this page. \\\"Cleaning\\\" includes syntactical corrections, \"\n\"standardizations and \\\"pretty printing\\\" of the contents stream. \"\n\"Discrepancies between :data:`contents` and :data:`resources` objects will\"\n\" also be corrected if sanitize is true. See :meth:`Page.get_contents` for\"\n\" more details.\"\nmsgstr \"\"\n\"PDF 전용: 이 페이지와 연결된 모든 :data:`contents` 객체를 정리하고 연결합니다. \\\"정리\\\"에는 구문 수정, \"\n\"표준화 및 콘텐츠 스트림의 \\\"예쁘게 인쇄\\\"가 포함됩니다. sanitize가 true이면 :data:`contents` 와 \"\n\":data:`resources` 객체 간의 불일치도 수정됩니다. 자세한 내용은 :meth:`Page.get_contents` 를 \"\n\"참조하세요.\"\n\n#: ../../functions.rst:723 cc05b36c964b4065952275eeb2a4f884\nmsgid \"\"\n\"Changed in version 1.16.0 Annotations are no longer implicitly cleaned by\"\n\" this method. Use :meth:`Annot.clean_contents` separately.\"\nmsgstr \"\"\n\"버전 1.16.0에서 변경됨: 주석은 이 메서드에 의해 더 이상 암시적으로 정리되지 않습니다. \"\n\":meth:`Annot.clean_contents` 를 별도로 사용하세요.\"\n\n#: ../../functions.rst:725 cef2a0b0383148ddb6c4fb2a831d9901\nmsgid \"\"\n\"*(new in v1.17.6)* if true, synchronization between resources and their \"\n\"actual use in the contents object is snychronized. For example, if a font\"\n\" is not actually used for any text of the page, then it will be deleted \"\n\"from the `/Resources/Font` object.\"\nmsgstr \"\"\n\"*(v1.17.6의 새로운 기능)* true이면 리소스와 콘텐츠 객체에서의 실제 사용 간의 동기화가 이루어집니다. 예를 들어, \"\n\"글꼴이 페이지의 어떤 텍스트에도 실제로 사용되지 않으면 `/Resources/Font` 객체에서 삭제됩니다.\"\n\n#: ../../functions.rst:727 e719525edd8b42b5adb8783ffc991f7f\nmsgid \"\"\n\"This is a complex function which may generate large amounts of new data \"\n\"and render old data unused. It is **not recommended** using it together \"\n\"with the **incremental save** option. Also note that the resulting \"\n\"singleton new */Contents* object is **uncompressed**. So you should save \"\n\"to a **new file** using options *\\\"deflate=True, garbage=3\\\"*.\"\nmsgstr \"\"\n\"이것은 대량의 새 데이터를 생성하고 이전 데이터를 사용하지 않게 만들 수 있는 복잡한 함수입니다. **증분 저장** 옵션과 함께 \"\n\"사용하는 것은 **권장되지 않습니다**. 또한 결과 단일 */Contents* 객체는 **압축되지 않습니다**. 따라서 \"\n\"*\\\"deflate=True, garbage=3\\\"* 옵션을 사용하여 **새 파일** 에 저장해야 합니다.\"\n\n#: ../../functions.rst:729 1b0ce37aead64fe190eb5958ec06bf93\nmsgid \"\"\n\"Do not any longer use this method to ensure correct insertions on PDF \"\n\"pages. Since PyMuPDF version 1.24.2 this is taken care of automatically.\"\nmsgstr \"\"\n\"PDF 페이지에 올바른 삽입을 보장하기 위해 이 메서드를 더 이상 사용하지 마세요. PyMuPDF 버전 1.24.2부터는 이것이 \"\n\"자동으로 처리됩니다.\"\n\n#: ../../functions.rst:735 159e3c751b6f49b8a75890a4fd563d0a\nmsgid \"\"\n\"*New in version 1.17.0.* Return the concatenation of all :data:`contents`\"\n\" objects associated with the page -- without cleaning or otherwise \"\n\"modifying them. Use this method whenever you need to parse this source in\"\n\" its entirety without having to bother how many separate contents objects\"\n\" exist.\"\nmsgstr \"\"\n\"*버전 1.17.0의 새로운 기능.* 페이지와 연결된 모든 :data:`contents` 객체의 연결을 반환합니다 -- 정리하거나 \"\n\"수정하지 않고. 별도의 콘텐츠 객체가 몇 개나 있는지 신경 쓸 필요 없이 전체 소스를 구문 분석해야 할 때마다 이 메서드를 \"\n\"사용하세요.\"\n\n#: ../../functions.rst:744 f820b3ca222e41ea9342c19ea2280afc\nmsgid \"\"\n\"Clean the :data:`contents` streams associated with the annotation. This \"\n\"is the same type of action which :meth:`Page.clean_contents` performs -- \"\n\"just restricted to this annotation.\"\nmsgstr \"\"\n\"주석과 연결된 :data:`contents` 스트림을 정리합니다. 이것은 :meth:`Page.clean_contents` 가 \"\n\"수행하는 것과 동일한 작업입니다 -- 단지 이 주석으로 제한됩니다.\"\n\n#: ../../functions.rst:751 057944b45dbf427097061759690378f5\nmsgid \"\"\n\"Return a list of character glyphs and their widths for a font that is \"\n\"present in the document. A font must be specified by its PDF cross \"\n\"reference number :data:`xref`. This function is called automatically from\"\n\" :meth:`Page.insert_text` and :meth:`Page.insert_textbox`. So you should \"\n\"rarely need to do this yourself.\"\nmsgstr \"\"\n\"문서에 있는 글꼴에 대한 문자 글리프 및 너비 목록을 반환합니다. 글꼴은 PDF 교차 참조 번호 :data:`xref` 로 지정해야\"\n\" 합니다. 이 함수는 :meth:`Page.insert_text` 및 :meth:`Page.insert_textbox` 에서 \"\n\"자동으로 호출됩니다. 따라서 직접 수행할 필요는 거의 없습니다.\"\n\n#: ../../functions.rst:753 f608a923d1b240efb8dc4a1e2ad76be7\nmsgid \"\"\n\"cross reference number of a font embedded in the PDF. To find a font \"\n\":data:`xref`, use e.g. *doc.get_page_fonts(pno)* of page number *pno* and\"\n\" take the first entry of one of the returned list entries.\"\nmsgstr \"\"\n\"PDF에 포함된 글꼴의 교차 참조 번호. 글꼴 :data:`xref` 를 찾으려면 예를 들어 페이지 번호 *pno* 의 \"\n\"*doc.get_page_fonts(pno)* 를 사용하고 반환된 목록 항목 중 하나의 첫 번째 항목을 가져옵니다.\"\n\n#: ../../functions.rst:755 18a15dfc86674db5b7ddd87e97061c89\nmsgid \"\"\n\"limits the number of returned entries. The default of 256 is enforced for\"\n\" all fonts that only support 1-byte characters, so-called \\\"simple \"\n\"fonts\\\" (checked by this method). All :ref:`Base-14-Fonts` are simple \"\n\"fonts.\"\nmsgstr \"\"\n\"반환된 항목 수를 제한합니다. 256의 기본값은 1바이트 문자만 지원하는 소위 \\\"simple fonts\\\"(이 메서드로 확인됨)에\"\n\" 대해 적용됩니다. 모든 :ref:`Base-14-Fonts` 는 simple fonts입니다.\"\n\n#: ../../functions.rst:758 374d9ca3517b46e79684baafbe452c8a\nmsgid \"\"\n\"a list of *limit* tuples. Each character *c* has an entry  *(g, w)* in \"\n\"this list with an index of *ord(c)*. Entry *g* (integer) of the tuple is \"\n\"the glyph id of the character, and float *w* is its normalized width. The\"\n\" actual width for some :data:`fontsize` can be calculated as *w * \"\n\"fontsize*. For simple fonts, the *g* entry can always be safely ignored. \"\n\"In all other cases *g* is the basis for graphically representing *c*.\"\nmsgstr \"\"\n\"*limit* 튜플 목록. 각 문자 *c* 는 *ord(c)* 인덱스를 가진 이 목록에 *(g, w)* 항목을 가집니다. 튜플의 \"\n\"항목 *g* (정수)는 문자의 글리프 id이고, float *w* 는 정규화된 너비입니다. 일부 :data:`fontsize` 에 \"\n\"대한 실제 너비는 *w * fontsize* 로 계산할 수 있습니다. simple fonts의 경우 *g* 항목은 항상 안전하게 \"\n\"무시할 수 있습니다. 다른 모든 경우 *g* 는 *c* 를 그래픽으로 표현하는 기반입니다.\"\n\n#: ../../functions.rst:760 9a82c0fef9f946ee931dcac730381625\nmsgid \"This function calculates the pixel width of a string called *text*::\"\nmsgstr \"이 함수는 *text* 라는 문자열의 픽셀 너비를 계산합니다::\"\n\n#: ../../functions.rst:772 1d63e80ff1044164bb37ffb75d916ca9\nmsgid \"New in version 1.14.14\"\nmsgstr \"*버전 1.14.14의 새로운 기능*\"\n\n#: ../../functions.rst:774 0499a7e490f54f6f9c36861c661dd5dd\nmsgid \"\"\n\"PDF only: Check whether the object represented by :data:`xref` is a \"\n\":data:`stream` type. Return is ``False`` if not a PDF or if the number is\"\n\" outside the valid xref range.\"\nmsgstr \"\"\n\"PDF 전용: :data:`xref` 로 표현된 객체가 :data:`stream` 타입인지 확인합니다. PDF가 아니거나 숫자가 \"\n\"유효한 xref 범위를 벗어나면 ``False`` 를 반환합니다.\"\n\n#: ../../functions.rst:776 6ece02cfe6fd4a0ebd3c0babd63401bc\nmsgid \":data:`xref` number.\"\nmsgstr \":data:`xref` 번호.\"\n\n#: ../../functions.rst:778 1ae7201b78294f7cb4822bbe2b16c89e\nmsgid \"\"\n\"``True`` if the object definition is followed by data wrapped in keyword \"\n\"pair *stream*, *endstream*.\"\nmsgstr \"객체 정의 뒤에 키워드 쌍 *stream*, *endstream* 으로 둘러싸인 데이터가 오면 ``True``.\"\n\n#: ../../functions.rst:784 824395dad4454308bb3acc094f1e1f49\nmsgid \"\"\n\"Increase the :data:`xref` by one entry and return that number. This can \"\n\"then be used to insert a new object.\"\nmsgstr \":data:`xref` 를 하나의 항목만큼 증가시키고 해당 번호를 반환합니다. 이것은 새 객체를 삽입하는 데 사용할 수 있습니다.\"\n\n#: ../../functions.rst:786 b74f53e6f461419798c38d5d157d1ddb\nmsgid \"\"\n\"int :returns: the number of the new :data:`xref` entry. Please note, that\"\n\" only a new entry in the PDF's cross reference table is created. At this \"\n\"point, there will not yet exist a PDF object associated with it. To \"\n\"create an (empty) object with this number use `doc.update_xref(xref, \"\n\"\\\"<<>>\\\")`.\"\nmsgstr \"\"\n\"int :returns: 새 :data:`xref` 항목의 번호. PDF의 교차 참조 테이블에만 새 항목이 생성됩니다. 이 시점에는\"\n\" 아직 연결된 PDF 객체가 존재하지 않습니다. 이 번호로 (빈) 객체를 생성하려면 `doc.update_xref(xref, \"\n\"\\\"<<>>\\\")` 를 사용하세요.\"\n\n#: ../../functions.rst:793 31b915dba1a44258a1cf9373421e9f58\nmsgid \"Return length of :data:`xref` table.\"\nmsgstr \":data:`xref` 테이블의 길이를 반환합니다.\"\n\n#: ../../functions.rst:796 aeeeacbd76704c80be24a494e9f339de\nmsgid \"the number of entries in the :data:`xref` table.\"\nmsgstr \":data:`xref` 테이블의 항목 수.\"\n\n#: ../../functions.rst:802 994bdeb47ece44ed86fdb81eee8a599d\nmsgid \"\"\n\"Compute the quadrilateral of a text span extracted via options \\\"dict\\\" \"\n\"or \\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\":meth:`Page.get_text` 의 \\\"dict\\\" 또는 \\\"rawdict\\\" 옵션을 통해 추출된 텍스트 스팬의 사각형을 \"\n\"계산합니다.\"\n\n#: ../../functions.rst:804 ff5b2345f37b49ada7b219718699d919\nmsgid \"\"\n\"`line[\\\"dir\\\"]` of the owning line.  Use `None` for a span from \"\n\":meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\"소유 라인의 `line[\\\"dir\\\"]`. :meth:`Page.get_texttrace` 에서 가져온 스팬의 경우 `None` 을\"\n\" 사용하세요.\"\n\n#: ../../functions.rst:805 ../../functions.rst:815 ../../functions.rst:826\n#: 3de95b885fdb4ae3af31bdbf11c40283 4502b3c80d88444093eabb36474662d2\n#: 843e47e4ce234f268a145146bbef3077\nmsgid \"the span.\"\nmsgstr \"스팬.\"\n\n#: ../../functions.rst:806 58171abb89e5477197c19eda22c274ae\nmsgid \"\"\n\"the :ref:`Quad` of the span, usable for text marker annotations \"\n\"('Highlight', etc.).\"\nmsgstr \"스팬의 :ref:`Quad`, 텍스트 마커 주석('Highlight' 등)에 사용 가능.\"\n\n#: ../../functions.rst:812 7ab76daee93b418ead8cbe0eb161c1c0\nmsgid \"\"\n\"Compute the quadrilateral of a text character extracted via option \"\n\"\\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \":meth:`Page.get_text` 의 \\\"rawdict\\\" 옵션을 통해 추출된 텍스트 문자의 사각형을 계산합니다.\"\n\n#: ../../functions.rst:814 ../../functions.rst:825\n#: cbcfe2d2f449448fab8201428f6897c5 d64beaf47b2f47e78d08e91ac32d1e07\nmsgid \"\"\n\"`line[\\\"dir\\\"]` of the owning line. Use `None` for a span from \"\n\":meth:`Page.get_texttrace`.\"\nmsgstr \"\"\n\"소유 라인의 `line[\\\"dir\\\"]`. :meth:`Page.get_texttrace` 에서 가져온 스팬의 경우 `None` 을\"\n\" 사용하세요.\"\n\n#: ../../functions.rst:816 0de58fc1e9b343c2b2d6d719c82d5cc9\nmsgid \"the character.\"\nmsgstr \"문자.\"\n\n#: ../../functions.rst:817 b0444b9caf674df4a28978df8d452580\nmsgid \"\"\n\"the :ref:`Quad` of the character, usable for text marker annotations \"\n\"('Highlight', etc.).\"\nmsgstr \"문자의 :ref:`Quad`, 텍스트 마커 주석('Highlight' 등)에 사용 가능.\"\n\n#: ../../functions.rst:823 2383e87ea4f74ca3b4dbf8fac78fae8c\nmsgid \"\"\n\"Compute the quadrilateral of a subset of characters of a span extracted \"\n\"via option \\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \":meth:`Page.get_text` 의 \\\"rawdict\\\" 옵션을 통해 추출된 스팬의 문자 하위 집합의 사각형을 계산합니다.\"\n\n#: ../../functions.rst:827 fe3fd7ff9c464621843bea5d3d910e20\nmsgid \"\"\n\"the characters to consider. If given, the selected extraction option must\"\n\" be \\\"rawdict\\\".\"\nmsgstr \"고려할 문자. 주어진 경우 선택된 추출 옵션은 \\\"rawdict\\\"여야 합니다.\"\n\n#: ../../functions.rst:828 80bc82b9eab8453389713a6186de07d5\nmsgid \"\"\n\"the :ref:`Quad` of the selected characters, usable for text marker \"\n\"annotations ('Highlight', etc.).\"\nmsgstr \"선택된 문자의 :ref:`Quad`, 텍스트 마커 주석('Highlight' 등)에 사용 가능.\"\n\n#: ../../functions.rst:834 5a8cf6fbcf4d4ef1be7317c9ccef6471\nmsgid \"\"\n\"Compute the quadrilateral of a subset of spans of a text line extracted \"\n\"via options \\\"dict\\\" or \\\"rawdict\\\" of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\":meth:`Page.get_text` 의 \\\"dict\\\" 또는 \\\"rawdict\\\" 옵션을 통해 추출된 텍스트 라인의 스팬 하위 \"\n\"집합의 사각형을 계산합니다.\"\n\n#: ../../functions.rst:836 c22d97f050f94943b1509a1116b1ec58\nmsgid \"the line.\"\nmsgstr \"라인.\"\n\n#: ../../functions.rst:837 93ca3f15067647d68628fc26d746709c\nmsgid \"\"\n\"a sub-list of `line[\\\"spans\\\"]`. If omitted, the full line quad will be \"\n\"returned.\"\nmsgstr \"`line[\\\"spans\\\"]` 의 하위 목록. 생략하면 전체 라인 쿼드가 반환됩니다.\"\n\n#: ../../functions.rst:838 7bd8eeabe2254422bf223a1658cb6d04\nmsgid \"\"\n\"the :ref:`Quad` of the selected line spans, usable for text marker \"\n\"annotations ('Highlight', etc.).\"\nmsgstr \"선택된 라인 스팬의 :ref:`Quad`, 텍스트 마커 주석('Highlight' 등)에 사용 가능.\"\n\n#: ../../functions.rst:844 64e462661be944f3a62a6df56af9d839\nmsgid \"Detect Tesseract language support folder.\"\nmsgstr \"Tesseract 언어 지원 폴더 감지.\"\n\n#: ../../functions.rst:846 36cd291815a54fe890dfc549855cb135\nmsgid \"\"\n\"This function is used to enable OCR via Tesseract even if the language \"\n\"support folder is not specified directly or in environment variable \"\n\"TESSDATA_PREFIX.\"\nmsgstr \"\"\n\"이 함수는 언어 지원 폴더가 직접 또는 환경 변수 TESSDATA_PREFIX에 지정되지 않은 경우에도 Tesseract를 통해 \"\n\"OCR을 활성화하는 데 사용됩니다.\"\n\n#: ../../functions.rst:850 9df72e40b69a45bf8734dc507588842b\nmsgid \"If <tessdata> is set we return it directly.\"\nmsgstr \"<tessdata>가 설정되어 있으면 직접 반환합니다.\"\n\n#: ../../functions.rst:852 6ad23f9268db4f50b930607a1e593e11\nmsgid \"Otherwise we return `os.environ['TESSDATA_PREFIX']` if set.\"\nmsgstr \"그렇지 않으면 설정된 경우 `os.environ['TESSDATA_PREFIX']` 를 반환합니다.\"\n\n#: ../../functions.rst:854 81a272ead43746849c211778e4f173f6\nmsgid \"\"\n\"Otherwise we search for a Tesseract installation and return its language \"\n\"support folder.\"\nmsgstr \"그렇지 않으면 Tesseract 설치를 검색하고 언어 지원 폴더를 반환합니다.\"\n\n#: ../../functions.rst:857 05770e4eb5f248e1b9c0b632023d3c3e\nmsgid \"Otherwise we raise an exception.\"\nmsgstr \"그렇지 않으면 예외를 발생시킵니다.\"\n\n#: ../../functions.rst:867 6165db22dfb447e784347e5fffeb9159\nmsgid \"\"\n\"Return the (unique) infinite rectangle `Rect(-2147483648.0, \"\n\"-2147483648.0, 2147483520.0, 2147483520.0)`, resp. the :ref:`IRect` and \"\n\":ref:`Quad` counterparts. It is the largest possible rectangle: all valid\"\n\" rectangles are contained in it.\"\nmsgstr \"\"\n\"(유일한) 무한 사각형 `Rect(-2147483648.0, -2147483648.0, 2147483520.0, \"\n\"2147483520.0)` 또는 이에 해당하는 :ref:`IRect` 및 :ref:`Quad` 를 반환합니다. 이것은 가능한 가장 \"\n\"큰 사각형입니다: 모든 유효한 사각형이 포함됩니다.\"\n\n#: ../../functions.rst:877 0a193887c7ac4df6b78c43a679165d96\nmsgid \"\"\n\"Return the \\\"standard\\\" empty and invalid rectangle `Rect(2147483520.0, \"\n\"2147483520.0, -2147483648.0, -2147483648.0)` resp. quad. Its top-left and\"\n\" bottom-right point values are reversed compared to the infinite \"\n\"rectangle. It will e.g. be used to indicate empty bboxes in \"\n\"`page.get_text(\\\"dict\\\")` dictionaries. There are however infinitely many\"\n\" empty or invalid rectangles.\"\nmsgstr \"\"\n\"\\\"표준\\\" 빈 및 유효하지 않은 사각형 `Rect(2147483520.0, 2147483520.0, -2147483648.0, \"\n\"-2147483648.0)` 또는 이에 해당하는 쿼드를 반환합니다. 왼쪽 위 및 오른쪽 아래 점 값이 무한 사각형과 비교하여 \"\n\"반대입니다. 예를 들어 `page.get_text(\\\"dict\\\")` 딕셔너리에서 빈 bbox를 나타내는 데 사용됩니다. 그러나 \"\n\"무한히 많은 빈 또는 유효하지 않은 사각형이 있습니다.\"\n\n#: ../../functions.rst:883 57941cc8bfe54662a58baa544596de42\nmsgid \"\"\n\"Returns a dict mapping lower-case color name to `(red, green, blue)` \"\n\"tuple, and `red`, `green`, `blue` are floats in range 0..1.\"\nmsgstr \"\"\n\"소문자 색상 이름을 `(red, green, blue)` 튜플에 매핑하는 딕셔너리를 반환하며, `red`, `green`, \"\n\"`blue` 는 0..1 범위의 float입니다.\"\n\n#: ../../functions.rst:888 501128a84def4aeb9ded0eb35633124b\nmsgid \"\"\n\"Returns a list of `(colorname, red, green, blue)` tuples, where \"\n\"`colorname` is upper case and `red`, `green`, `blue` are integers in \"\n\"range 0..255.\"\nmsgstr \"\"\n\"`(colorname, red, green, blue)` 튜플 목록을 반환하며, 여기서 `colorname` 은 대문자이고 \"\n\"`red`, `green`, `blue` 는 0..255 범위의 정수입니다.\"\n\n#: ../../footer.rst:57 3f2e7072cb5c4a93ab763b29d4244bc2\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/glossary.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 d08d3d2cd62e4347ae2805cfcc06a70f\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 739bd76d85de44ed9317676c5473c0c4\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 4c57e05fc77144dfb8faf379a03cc56b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../glossary.rst:7 28cd3665c98c4ea997db495f331f026c\nmsgid \"Glossary\"\nmsgstr \"용어집\"\n\n#: ../../glossary.rst:11 586bce9bf00e4c89b0241028b3c7ff08\nmsgid \"\"\n\"This is an essential general mathematical / geometrical term for \"\n\"understanding this documentation. Please see this section for a more \"\n\"detailed discussion: :ref:`Coordinates`.\"\nmsgstr \"이것은 이 문서를 이해하기 위한 필수적인 일반적인 수학/기하학 용어입니다. 자세한 내용은 :ref:`Coordinates` 섹션을 참조하세요.\"\n\n#: ../../glossary.rst:15 6bb8cff798704bbb98656190f68b478d\nmsgid \"A Python sequence of 6 numbers.\"\nmsgstr \"6개의 숫자로 구성된 Python 시퀀스입니다.\"\n\n#: ../../glossary.rst:19 4be6452df2ab4c31adadf519dd1f3f3d\nmsgid \"A Python sequence of 4 numbers.\"\nmsgstr \"4개의 숫자로 구성된 Python 시퀀스입니다.\"\n\n#: ../../glossary.rst:23 4f04da6f55df426d9a81f7ddd5cf35a4\nmsgid \"A Python sequence of 4 integers.\"\nmsgstr \"4개의 정수로 구성된 Python 시퀀스입니다.\"\n\n#: ../../glossary.rst:27 0816befe649d4c23ac61285cc1d4c68a\nmsgid \"A Python sequence of 2 numbers.\"\nmsgstr \"2개의 숫자로 구성된 Python 시퀀스입니다.\"\n\n#: ../../glossary.rst:31 4b252ecf18494010ac1b4abf8318014b\nmsgid \"A Python sequence of 4 :data:`point_like` items.\"\nmsgstr \"4개의 :data:`point_like` 항목으로 구성된 Python 시퀀스입니다.\"\n\n#: ../../glossary.rst:35 08979edc495d4e0c8fb3091ac014aeb6\nmsgid \"\"\n\"A number of values in a PDF can inherited by objects further down in a \"\n\"parent-child relationship. The mediabox (physical size) of pages may for \"\n\"example be specified only once or in some node(s) of the :data:`pagetree`\"\n\" and will then be taken as value for all *kids*, that do not specify \"\n\"their own value.\"\nmsgstr \"PDF의 여러 값은 부모-자식 관계에서 하위 객체에 상속될 수 있습니다. 예를 들어 페이지의 mediabox(물리적 크기)는 한 번만 지정되거나 :data:`pagetree` 의 일부 노드에 지정될 수 있으며, 자체 값을 지정하지 않는 모든 *자식* 에 대한 값으로 사용됩니다.\"\n\n#: ../../glossary.rst:41 bd92584d9672427a92de7ae2ca2c9ef5\nmsgid \"\"\n\"A PDF array of 4 floats specifying a physical page size -- \"\n\"(:data:`inheritable`, mandatory). This rectangle should contain all other\"\n\" PDF  -- optional -- page rectangles, which may be specified in addition:\"\n\" CropBox, TrimBox, ArtBox and BleedBox. Please consult :ref:`AdobeManual`\"\n\" for details. The MediaBox is the only rectangle, for which there is no \"\n\"difference between MuPDF and PDF coordinate systems: \"\n\":attr:`Page.mediabox` will always show the same coordinates as the \"\n\"`/MediaBox` key in a page's object definition. For all other rectangles, \"\n\"MuPDF transforms y coordinates such that the **top** border is the point \"\n\"of reference. This can sometimes be confusing -- you may for example \"\n\"encounter a situation like this one:\"\nmsgstr \"물리적 페이지 크기를 지정하는 4개의 float로 구성된 PDF 배열입니다 -- (:data:`inheritable`, 필수). 이 사각형은 추가로 지정할 수 있는 다른 모든 PDF 페이지 사각형(CropBox, TrimBox, ArtBox, BleedBox)을 포함해야 합니다. 자세한 내용은 :ref:`AdobeManual` 을 참조하세요. MediaBox는 MuPDF와 PDF 좌표계 간에 차이가 없는 유일한 사각형입니다: :attr:`Page.mediabox` 는 항상 페이지 객체 정의의 `/MediaBox` 키와 동일한 좌표를 표시합니다. 다른 모든 사각형의 경우, MuPDF는 **상단** 경계가 기준점이 되도록 y 좌표를 변환합니다. 이로 인해 때때로 혼란스러울 수 있습니다 -- 예를 들어 다음과 같은 상황을 만날 수 있습니다:\"\n\n#: ../../glossary.rst:43 c84f72a1ef1a493db58b9912d0b5c864\nmsgid \"\"\n\"The page definition contains the following identical values: `/MediaBox [\"\n\" 36 45 607.5 765 ]`, `/CropBox [ 36 45 607.5 765 ]`.\"\nmsgstr \"페이지 정의에는 다음과 같은 동일한 값이 포함되어 있습니다: `/MediaBox [ 36 45 607.5 765 ]`, `/CropBox [ 36 45 607.5 765 ]`.\"\n\n#: ../../glossary.rst:44 a0a14effa0694f848b4b68f6433c6e41\nmsgid \"\"\n\"PyMuPDF accordingly shows `page.mediabox = Rect(36.0, 45.0, 607.5, \"\n\"765.0)`.\"\nmsgstr \"따라서 PyMuPDF는 `page.mediabox = Rect(36.0, 45.0, 607.5, 765.0)` 을 표시합니다.\"\n\n#: ../../glossary.rst:45 6452ee0315854e7a8d8c7b5ceae4b2f4\nmsgid \"\"\n\"**BUT:** `page.cropbox = Rect(36.0, 0.0, 607.5, 720.0)`, because the two \"\n\"y-coordinates have been transformed (45 subtracted from both of them).\"\nmsgstr \"**하지만:** `page.cropbox = Rect(36.0, 0.0, 607.5, 720.0)` 입니다. 두 y 좌표가 변환되었기 때문입니다(둘 다에서 45가 빼졌습니다).\"\n\n#: ../../glossary.rst:49 54bb2fd6606f42b0b61698e8f5e4264f\nmsgid \"\"\n\"A PDF array of 4 floats specifying a page's visible area -- \"\n\"(:data:`inheritable`, optional). It is the default for TrimBox, ArtBox \"\n\"and BleedBox. If not present, it defaults to MediaBox. This value is \"\n\"**not affected** if the page is rotated -- in contrast to \"\n\":attr:`Page.rect`. Also, other than the page rectangle, the top-left \"\n\"corner of the cropbox may or may not be *(0, 0)*.\"\nmsgstr \"페이지의 보이는 영역을 지정하는 4개의 float로 구성된 PDF 배열입니다 -- (:data:`inheritable`, 선택 사항). TrimBox, ArtBox 및 BleedBox의 기본값입니다. 없으면 MediaBox를 기본값으로 사용합니다. 이 값은 페이지가 회전되어도 **영향을 받지 않습니다** -- :attr:`Page.rect` 와 대조됩니다. 또한 페이지 사각형과 달리 cropbox의 왼쪽 상단 모서리는 *(0, 0)* 일 수도 있고 아닐 수도 있습니다.\"\n\n#: ../../glossary.rst:54 32d13994ea71438cba097ae7ab179529\nmsgid \"\"\n\"A central PDF :data:`dictionary` -- also called the \\\"root\\\" -- \"\n\"containing document-wide parameters and pointers to many other \"\n\"information. Its :data:`xref` is returned by \"\n\":meth:`Document.pdf_catalog`.\"\nmsgstr \"문서 전체 매개변수와 다른 많은 정보에 대한 포인터를 포함하는 중앙 PDF :data:`dictionary` 입니다 -- \\\"root\\\"라고도 합니다. 그 :data:`xref` 는 :meth:`Document.pdf_catalog` 에 의해 반환됩니다.\"\n\n#: ../../glossary.rst:58 5758183571814745904de85f3da96f2c\nmsgid \"\"\n\"More precisely, the **PDF trailer** contains information in \"\n\":data:`dictionary` format. It is usually located at the file's end. In \"\n\"this dictionary, you will find things like the xrefs of the catalog and \"\n\"the metadata, the number of :data:`xref` numbers, etc. Here is the \"\n\"definition of the PDF spec:\"\nmsgstr \"더 정확히 말하면, **PDF trailer** 는 :data:`dictionary` 형식의 정보를 포함합니다. 일반적으로 파일의 끝에 위치합니다. 이 사전에는 카탈로그 및 메타데이터의 xref, :data:`xref` 번호의 개수 등이 포함됩니다. PDF 사양의 정의는 다음과 같습니다:\"\n\n#: ../../glossary.rst:60 0d85c5a6d7454c289824fc58d0a6fdef\nmsgid \"\"\n\"*\\\"The trailer of a PDF file enables an application reading the file to \"\n\"quickly find the cross-reference table and certain special objects. \"\n\"Applications should read a PDF file from its end.\\\"*\"\nmsgstr \"*\\\"PDF 파일의 trailer는 파일을 읽는 애플리케이션이 교차 참조 테이블과 특정 특수 객체를 빠르게 찾을 수 있게 합니다. 애플리케이션은 PDF 파일을 끝에서부터 읽어야 합니다.\\\"*\"\n\n#: ../../glossary.rst:62 5e0b8a538504497aa555e757cfa9f113\nmsgid \"\"\n\"To access the trailer in PyMuPDF, use the usual methods \"\n\":meth:`Document.xref_object`, :meth:`Document.xref_get_key` and \"\n\":meth:`Document.xref_get_keys` with `-1` instead of a positive xref \"\n\"number.\"\nmsgstr \"PyMuPDF에서 trailer에 액세스하려면 일반 메서드 :meth:`Document.xref_object`, :meth:`Document.xref_get_key` 및 :meth:`Document.xref_get_keys` 를 양수 xref 번호 대신 `-1` 과 함께 사용하세요.\"\n\n#: ../../glossary.rst:66 96ea53e1526e4f31b6a7cd5ebbeef7a7\nmsgid \"\"\n\"A **content stream** is a PDF :data:`object` with an attached \"\n\":data:`stream`, whose data consists of a sequence of instructions \"\n\"describing the graphical elements to be painted on a page, see \\\"Stream \"\n\"Objects\\\" on page 19 of :ref:`AdobeManual`. For an overview of the mini-\"\n\"language used in these streams, see chapter \\\"Operator Summary\\\" on page \"\n\"643 of the :ref:`AdobeManual`. A PDF :data:`page` can have none to many \"\n\"contents objects. If it has none, the page is empty (but still may show \"\n\"annotations). If it has several, they will be interpreted in sequence as \"\n\"if their instructions had been present in one such object (i.e. like in a\"\n\" concatenated string). It should be noted that there are more stream \"\n\"object types which use the same syntax: e.g. appearance dictionaries \"\n\"associated with annotations and Form XObjects.\"\nmsgstr \"**content stream** 은 첨부된 :data:`stream` 이 있는 PDF :data:`object` 로, 그 데이터는 페이지에 그려질 그래픽 요소를 설명하는 명령 시퀀스로 구성됩니다. :ref:`AdobeManual` 의 19페이지 \\\"Stream Objects\\\"를 참조하세요. 이러한 스트림에서 사용되는 미니 언어의 개요는 :ref:`AdobeManual` 의 643페이지 \\\"Operator Summary\\\" 장을 참조하세요. PDF :data:`page` 는 0개에서 여러 개의 contents 객체를 가질 수 있습니다. 없으면 페이지가 비어 있습니다(하지만 여전히 주석을 표시할 수 있습니다). 여러 개가 있으면 하나의 객체에 명령이 있는 것처럼 순차적으로 해석됩니다(즉, 연결된 문자열처럼). 동일한 구문을 사용하는 더 많은 스트림 객체 유형이 있습니다: 예를 들어 주석 및 Form XObject와 연결된 appearance dictionary.\"\n\n#: ../../glossary.rst:68 789ecf52493843de99d4baf64aac0706\nmsgid \"PyMuPDF provides a number of methods to deal with contents of PDF pages:\"\nmsgstr \"PyMuPDF는 PDF 페이지의 콘텐츠를 처리하기 위한 여러 메서드를 제공합니다:\"\n\n#: ../../glossary.rst:70 7af31d456e6049c781db775b0d937ce4\nmsgid \"\"\n\":meth:`Page.read_contents()` -- reads and concatenates all page contents \"\n\"into one `bytes` object.\"\nmsgstr \":meth:`Page.read_contents()` -- 모든 페이지 콘텐츠를 읽어서 하나의 `bytes` 객체로 연결합니다.\"\n\n#: ../../glossary.rst:71 ed6a3af3341c4060a1e4a75572b4ddd5\nmsgid \"\"\n\":meth:`Page.clean_contents()` -- a wrapper of a MuPDF function that \"\n\"reads, concatenates and syntax-cleans all page contents. After this, only\"\n\" one `/Contents` object will exist. In addition, page :data:`resources` \"\n\"will have been synchronized with it such that it will contain exactly \"\n\"those images, fonts and other objects that the page actually references.\"\nmsgstr \":meth:`Page.clean_contents()` -- 모든 페이지 콘텐츠를 읽고, 연결하고, 구문을 정리하는 MuPDF 함수의 래퍼입니다. 이후에는 하나의 `/Contents` 객체만 존재합니다. 또한 페이지 :data:`resources` 가 동기화되어 페이지가 실제로 참조하는 이미지, 글꼴 및 기타 객체만 정확히 포함됩니다.\"\n\n#: ../../glossary.rst:72 b5f192573e604b7ab3a23459f4ff8d28\nmsgid \"\"\n\":meth:`Page.get_contents()` -- return a list of :data:`xref` numbers of a\"\n\" page's :data:`contents` objects. May be empty. Use \"\n\":meth:`Document.xref_stream()` with one of these xrefs to read the resp. \"\n\"contents section.\"\nmsgstr \":meth:`Page.get_contents()` -- 페이지의 :data:`contents` 객체의 :data:`xref` 번호 목록을 반환합니다. 비어 있을 수 있습니다. 이러한 xref 중 하나와 함께 :meth:`Document.xref_stream()` 을 사용하여 해당 콘텐츠 섹션을 읽으세요.\"\n\n#: ../../glossary.rst:73 1999ff45a4f744478c87ada7170c63a7\nmsgid \"\"\n\":meth:`Page.set_contents()` -- set a page's `/Contents` key to the \"\n\"provided :data:`xref` number.\"\nmsgstr \":meth:`Page.set_contents()` -- 페이지의 `/Contents` 키를 제공된 :data:`xref` 번호로 설정합니다.\"\n\n#: ../../glossary.rst:77 a33fe5bd332e49fbac0209663f12f749\nmsgid \"\"\n\"A :data:`dictionary` containing references to any resources (like images \"\n\"or fonts) required by a PDF :data:`page` (required, inheritable, \"\n\":ref:`AdobeManual` p. 81) and certain other objects (Form XObjects). This\"\n\" dictionary appears as a sub-dictionary in the object definition under \"\n\"the key */Resources*. Being an inheritable object type, there may exist \"\n\"\\\"parent\\\" resources for all pages or certain subsets of pages.\"\nmsgstr \"PDF :data:`page` 에 필요한 리소스(이미지 또는 글꼴 등)에 대한 참조를 포함하는 :data:`dictionary` 입니다(필수, 상속 가능, :ref:`AdobeManual` p. 81) 및 특정 다른 객체(Form XObject). 이 사전은 키 */Resources* 아래의 객체 정의에 하위 사전으로 나타납니다. 상속 가능한 객체 유형이므로 모든 페이지 또는 특정 페이지 하위 집합에 대한 \\\"부모\\\" 리소스가 존재할 수 있습니다.\"\n\n#: ../../glossary.rst:81 d54465f90aea45f4be640dcb0dd409ab\nmsgid \"\"\n\"A PDF :data:`object` type, which is somewhat comparable to the same-named\"\n\" Python notion: \\\"A dictionary object is an associative table containing \"\n\"pairs of objects, known as the dictionary's entries. The first element of\"\n\" each entry is the key and the second element is the value. The key must \"\n\"be a name (...). The value can be any kind of object, including another \"\n\"dictionary. A dictionary entry whose value is null (...) is equivalent to\"\n\" an absent entry.\\\" (:ref:`AdobeManual` p. 18).\"\nmsgstr \"동일한 이름의 Python 개념과 어느 정도 비교할 수 있는 PDF :data:`object` 유형입니다: \\\"dictionary 객체는 dictionary의 항목으로 알려진 객체 쌍을 포함하는 연관 테이블입니다. 각 항목의 첫 번째 요소는 키이고 두 번째 요소는 값입니다. 키는 이름이어야 합니다(...). 값은 다른 dictionary를 포함하여 모든 종류의 객체일 수 있습니다. 값이 null인 dictionary 항목(...)은 없는 항목과 동일합니다.\\\" (:ref:`AdobeManual` p. 18).\"\n\n#: ../../glossary.rst:83 f8dd50a4a4dd44b2ab3811dde6bd8cf3\nmsgid \"\"\n\"Dictionaries are the most important :data:`object` type in PDF. Here is \"\n\"an example (describing a :data:`page`)::\"\nmsgstr \"Dictionary는 PDF에서 가장 중요한 :data:`object` 유형입니다. 다음은 예제입니다(:data:`page` 설명)::\"\n\n#: ../../glossary.rst:102 b9f82bb7035946b4804cfd94101fd4c4\nmsgid \"\"\n\"*Contents*, *Type*, *MediaBox*, etc. are **keys**, *40 0 R*, *Page*, *[0 \"\n\"0 595.32 841.92]*, etc. are the respective **values**. The strings \"\n\"*\\\"<<\\\"* and *\\\">>\\\"* are used to enclose object definitions.\"\nmsgstr \"*Contents*, *Type*, *MediaBox* 등은 **키** 이고, *40 0 R*, *Page*, *[0 0 595.32 841.92]* 등은 각각의 **값** 입니다. 문자열 *\\\"<<\\\"* 및 *\\\">>\\\"* 는 객체 정의를 묶는 데 사용됩니다.\"\n\n#: ../../glossary.rst:104 b635f1dd09be42db81dc681669f2d25d\nmsgid \"\"\n\"This example also shows the syntax of **nested** dictionary values: \"\n\"*Resources* has an object as its value, which in turn is a dictionary \"\n\"with keys like *ExtGState* (with the value *<</R7 26 0 R>>*, which is \"\n\"another dictionary), etc.\"\nmsgstr \"이 예제는 **중첩된** dictionary 값의 구문도 보여줍니다: *Resources* 는 그 값으로 객체를 가지며, 이 객체는 *ExtGState* (값은 *<</R7 26 0 R>>* 로, 또 다른 dictionary)와 같은 키를 가진 dictionary입니다.\"\n\n#: ../../glossary.rst:108 acf84ed282d0488ca9ec42cb7a8b05cd\nmsgid \"\"\n\"A PDF page is a :data:`dictionary` object which defines one page in a \"\n\"PDF, see :ref:`AdobeManual` p. 71.\"\nmsgstr \"PDF 페이지는 PDF의 한 페이지를 정의하는 :data:`dictionary` 객체입니다. :ref:`AdobeManual` p. 71을 참조하세요.\"\n\n#: ../../glossary.rst:112 2e0101c6f2df4a99a2a341fe77b08849\nmsgid \"\"\n\"The pages of a document are accessed through a structure known as the \"\n\"page tree, which defines the ordering of pages in the document. The tree \"\n\"structure allows PDF consumer applications, using only limited memory, to\"\n\" quickly open a document containing thousands of pages. The tree contains\"\n\" nodes of two types: intermediate nodes, called page tree nodes, and leaf\"\n\" nodes, called page objects. (:ref:`AdobeManual` p. 75).\"\nmsgstr \"문서의 페이지는 페이지 트리라고 하는 구조를 통해 액세스되며, 이는 문서의 페이지 순서를 정의합니다. 트리 구조를 사용하면 제한된 메모리만 사용하여 수천 페이지를 포함하는 문서를 빠르게 열 수 있습니다. 트리에는 두 가지 유형의 노드가 포함됩니다: 중간 노드(페이지 트리 노드라고 함)와 리프 노드(페이지 객체라고 함). (:ref:`AdobeManual` p. 75).\"\n\n#: ../../glossary.rst:114 4d06cfcc4e614225ae5861c899219585\nmsgid \"\"\n\"While it is possible to list all page references in just one array, PDFs \"\n\"with many pages are often created using *balanced tree* structures \"\n\"(\\\"page trees\\\") for faster access to any single page. In relation to the\"\n\" total number of pages, this can reduce the average page access time by \"\n\"page number from a linear to some logarithmic order of magnitude.\"\nmsgstr \"모든 페이지 참조를 하나의 배열에 나열하는 것이 가능하지만, 많은 페이지가 있는 PDF는 단일 페이지에 더 빠르게 액세스하기 위해 *균형 트리* 구조(\\\"페이지 트리\\\")를 사용하여 생성되는 경우가 많습니다. 전체 페이지 수와 관련하여, 이를 통해 페이지 번호별 평균 페이지 액세스 시간을 선형에서 대수적 크기 순서로 줄일 수 있습니다.\"\n\n#: ../../glossary.rst:116 01db9b917bcc4cb89215ac102dda29c9\nmsgid \"\"\n\"For fast page access, MuPDF can use its own array in memory -- \"\n\"independently from what may or may not be present in the document file. \"\n\"This array is indexed by page number and therefore much faster than even \"\n\"the access via a perfectly balanced page tree.\"\nmsgstr \"빠른 페이지 액세스를 위해 MuPDF는 문서 파일에 있을 수도 있고 없을 수도 있는 것과 독립적으로 메모리에서 자체 배열을 사용할 수 있습니다. 이 배열은 페이지 번호로 인덱싱되므로 완벽하게 균형 잡힌 페이지 트리를 통한 액세스보다 훨씬 빠릅니다.\"\n\n#: ../../glossary.rst:120 387b50e08c0a4411b5174a213523a1c0\nmsgid \"\"\n\"Similar to Python, PDF supports the notion *object*, which can come in \"\n\"eight basic types: boolean values (\\\"true\\\" or \\\"false\\\"), integer and \"\n\"real numbers, strings (**always** enclosed in brackets -- either \\\"()\\\", \"\n\"or \\\"<>\\\" to indicate hexadecimal), names (must always start with a \"\n\"\\\"/\\\", e.g. `/Contents`), arrays (enclosed in brackets \\\"[]\\\"), \"\n\"dictionaries (enclosed in brackets \\\"<<>>\\\"), streams (enclosed by \"\n\"keywords \\\"stream\\\" / \\\"endstream\\\"), and the null object (\\\"null\\\") \"\n\"(:ref:`AdobeManual` p. 13). Objects can be made identifiable by assigning\"\n\" a label. This label is then called *indirect* object. PyMuPDF supports \"\n\"retrieving definitions of indirect objects via their cross reference \"\n\"number via :meth:`Document.xref_object`.\"\nmsgstr \"Python과 유사하게, PDF는 *object* 개념을 지원하며, 8가지 기본 유형이 있습니다: 불리언 값(\\\"true\\\" 또는 \\\"false\\\"), 정수 및 실수, 문자열(**항상** 괄호로 묶임 -- \\\"()\\\" 또는 16진수를 나타내는 \\\"<>\\\"), 이름(항상 \\\"/\\\"로 시작해야 함, 예: `/Contents`), 배열(괄호 \\\"[]\\\"로 묶임), dictionary(괄호 \\\"<<>>\\\"로 묶임), 스트림(키워드 \\\"stream\\\" / \\\"endstream\\\"로 묶임), null 객체(\\\"null\\\") (:ref:`AdobeManual` p. 13). 객체는 레이블을 할당하여 식별 가능하게 만들 수 있습니다. 이 레이블은 *indirect* 객체라고 합니다. PyMuPDF는 :meth:`Document.xref_object` 를 통해 교차 참조 번호로 indirect 객체의 정의를 검색하는 것을 지원합니다.\"\n\n#: ../../glossary.rst:124 06fab8191ebd49d98a31a5d42c048ce5\nmsgid \"\"\n\"A PDF :data:`dictionary` :data:`object` type which is followed by a \"\n\"sequence of bytes, similar to Python *bytes*. \\\"However, a PDF \"\n\"application can read a stream incrementally, while a string must be read \"\n\"in its entirety. Furthermore, a stream can be of unlimited length, \"\n\"whereas a string is subject to an implementation limit. For this reason, \"\n\"objects with potentially large amounts of data, such as images and page \"\n\"descriptions, are represented as streams.\\\" \\\"A stream consists of a \"\n\":data:`dictionary` followed by zero or more bytes bracketed between the \"\n\"keywords *stream* and *endstream*\\\"::\"\nmsgstr \"Python *bytes* 와 유사한 바이트 시퀀스가 뒤따르는 PDF :data:`dictionary` :data:`object` 유형입니다. \\\"그러나 PDF 애플리케이션은 스트림을 점진적으로 읽을 수 있지만 문자열은 전체를 읽어야 합니다. 또한 스트림은 무제한 길이일 수 있지만 문자열은 구현 제한이 적용됩니다. 이러한 이유로 이미지 및 페이지 설명과 같이 잠재적으로 많은 양의 데이터를 가진 객체는 스트림으로 표현됩니다.\\\" \\\"스트림은 키워드 *stream* 과 *endstream* 사이에 괄호로 묶인 0개 이상의 바이트가 뒤따르는 :data:`dictionary` 로 구성됩니다\\\"::\"\n\n#: ../../glossary.rst:135 8dc0a34bf972472abef68fc3fe378101\nmsgid \"\"\n\"See :ref:`AdobeManual` p. 19. PyMuPDF supports retrieving stream content \"\n\"via :meth:`Document.xref_stream`. Use :meth:`Document.is_stream` to \"\n\"determine whether an object is of stream type.\"\nmsgstr \":ref:`AdobeManual` p. 19를 참조하세요. PyMuPDF는 :meth:`Document.xref_stream` 을 통해 스트림 콘텐츠를 검색하는 것을 지원합니다. 객체가 스트림 유형인지 확인하려면 :meth:`Document.is_stream` 을 사용하세요.\"\n\n#: ../../glossary.rst:139 d4686fb4f3814da3a119b81f119de382\nmsgid \"\"\n\"A mathematical notion meaning a vector of norm (\\\"length\\\") 1 -- usually \"\n\"the Euclidean norm is implied. In PyMuPDF, this term is restricted to \"\n\":ref:`Point` objects, see :attr:`Point.unit`.\"\nmsgstr \"노름(\\\"길이\\\")이 1인 벡터를 의미하는 수학적 개념입니다 -- 일반적으로 유클리드 노름을 의미합니다. PyMuPDF에서 이 용어는 :ref:`Point` 객체로 제한됩니다. :attr:`Point.unit` 을 참조하세요.\"\n\n#: ../../glossary.rst:143 e286649e7ce1436db8fbb7e65637ba3a\nmsgid \"\"\n\"Abbreviation for cross-reference number: this is an integer unique \"\n\"identification for objects in a PDF. There exists a cross-reference table\"\n\" (which may physically consist of several separate segments) in each PDF,\"\n\" which stores the relative position of each object for quick lookup. The \"\n\"cross-reference table is one entry longer than the number of existing \"\n\"object: item zero is reserved and must not be used in any way. Many \"\n\"PyMuPDF classes have an :data:`xref` attribute (which is zero for non-\"\n\"PDFs), and one can find out the total number of objects in a PDF via \"\n\":meth:`Document.xref_length` *- 1*.\"\nmsgstr \"교차 참조 번호의 약어: PDF의 객체에 대한 고유한 정수 식별자입니다. 각 PDF에는 빠른 조회를 위해 각 객체의 상대 위치를 저장하는 교차 참조 테이블이 있습니다(물리적으로 여러 개의 별도 세그먼트로 구성될 수 있음). 교차 참조 테이블은 기존 객체 수보다 하나 더 긴 항목을 가집니다: 항목 0은 예약되어 있으며 어떤 방식으로도 사용해서는 안 됩니다. 많은 PyMuPDF 클래스에는 :data:`xref` 속성이 있습니다(비PDF의 경우 0). :meth:`Document.xref_length` *- 1* 을 통해 PDF의 객체 총 수를 확인할 수 있습니다.\"\n\n#: ../../glossary.rst:148 6aa968ee6fb249d1bc62117c164aba0c\nmsgid \"\"\n\"When referring to font size this metric is measured in points where 1 \"\n\"inch = 72 points.\"\nmsgstr \"글꼴 크기를 나타낼 때 이 측정값은 포인트로 측정되며, 1인치 = 72포인트입니다.\"\n\n#: ../../glossary.rst:152 8c31d4e0a1d44b928122302b18a161d4\nmsgid \"\"\n\"Images and :ref:`Pixmap` objects may contain resolution information \"\n\"provided as \\\"dots per inch\\\", dpi, in each direction (horizontal and \"\n\"vertical). When MuPDF reads an image from a file or from a PDF object, it\"\n\" will parse this information and put it in :attr:`Pixmap.xres`, \"\n\":attr:`Pixmap.yres`, respectively. If it finds no meaningful information \"\n\"in the input (like non-positive values or values exceeding 4800), it will\"\n\" use \\\"sane\\\" defaults instead. The usual default value is 96, but it may\"\n\" also be 72 in some cases (e.g. for JPX images).\"\nmsgstr \"이미지 및 :ref:`Pixmap` 객체는 각 방향(수평 및 수직)에서 \\\"인치당 도트 수\\\"인 dpi로 제공되는 해상도 정보를 포함할 수 있습니다. MuPDF가 파일 또는 PDF 객체에서 이미지를 읽을 때 이 정보를 구문 분석하여 각각 :attr:`Pixmap.xres`, :attr:`Pixmap.yres` 에 넣습니다. 입력에서 의미 있는 정보를 찾지 못하면(양수가 아닌 값 또는 4800을 초과하는 값 등) 대신 \\\"적절한\\\" 기본값을 사용합니다. 일반적인 기본값은 96이지만 일부 경우(예: JPX 이미지)에는 72일 수도 있습니다.\"\n\n#: ../../glossary.rst:156 3e01cf857dca416c8faa34ba7d94265e\nmsgid \"\"\n\"Optional content properties dictionary - a sub :data:`dictionary` of the \"\n\"PDF :data:`catalog`. The central place to store optional content \"\n\"information, which is identified by the key `/OCProperties`. This \"\n\"dictionary has two required and one optional entry: (1) `/OCGs`, \"\n\"required, an array listing all optional content groups, (2) `/D`, \"\n\"required, the default optional content configuration dictionary (OCCD), \"\n\"(3) `/Configs`, optional, an array of alternative OCCDs.\"\nmsgstr \"선택적 콘텐츠 속성 dictionary - PDF :data:`catalog` 의 하위 :data:`dictionary`. 선택적 콘텐츠 정보를 저장하는 중앙 위치이며, 키 `/OCProperties` 로 식별됩니다. 이 dictionary에는 두 개의 필수 항목과 하나의 선택적 항목이 있습니다: (1) `/OCGs`, 필수, 모든 선택적 콘텐츠 그룹을 나열하는 배열, (2) `/D`, 필수, 기본 선택적 콘텐츠 구성 dictionary(OCCD), (3) `/Configs`, 선택, 대체 OCCD 배열.\"\n\n#: ../../glossary.rst:161 428928e7e81c403491625f300bc7e77c\nmsgid \"\"\n\"Optional content configuration dictionary - a PDF :data:`dictionary` \"\n\"inside the PDF :data:`OCPD`. It stores a setting of ON / OFF states of \"\n\"OCGs and how they are presented to a PDF viewer program. Selecting a \"\n\"configuration is quick way to achieve temporary mass visibility state \"\n\"changes. After opening a PDF, the `/D` configuration of the :data:`OCPD` \"\n\"is always activated. Viewer should offer a way to switch between the \"\n\"`/D`, or one of the optional configurations contained in array \"\n\"`/Configs`.\"\nmsgstr \"선택적 콘텐츠 구성 dictionary - PDF :data:`OCPD` 내부의 PDF :data:`dictionary`. OCG의 ON/OFF 상태 설정과 PDF 뷰어 프로그램에 표시되는 방식을 저장합니다. 구성을 선택하는 것은 일시적인 대량 표시 상태 변경을 빠르게 달성하는 방법입니다. PDF를 연 후 :data:`OCPD` 의 `/D` 구성이 항상 활성화됩니다. 뷰어는 `/D` 또는 배열 `/Configs` 에 포함된 선택적 구성 중 하나 사이를 전환하는 방법을 제공해야 합니다.\"\n\n#: ../../glossary.rst:166 01fc3682e86d471d815772b433b66de6\nmsgid \"\"\n\"Optional content group -- a :data:`dictionary` object used to control the\"\n\" visibility of other PDF objects like images or annotations. \"\n\"Independently on which page they are defined, objects with the same OCG \"\n\"can simultaneously be shown or hidden by setting their OCG to ON or OFF. \"\n\"This can be achieved via the user interface provided by many PDF viewers \"\n\"(Adobe Acrobat), or programmatically.\"\nmsgstr \"선택적 콘텐츠 그룹 -- 이미지 또는 주석과 같은 다른 PDF 객체의 표시를 제어하는 데 사용되는 :data:`dictionary` 객체. 정의된 페이지와 무관하게 동일한 OCG를 가진 객체는 OCG를 ON 또는 OFF로 설정하여 동시에 표시하거나 숨길 수 있습니다. 이는 많은 PDF 뷰어(Adobe Acrobat)가 제공하는 사용자 인터페이스를 통해 또는 프로그래밍 방식으로 달성할 수 있습니다.\"\n\n#: ../../glossary.rst:170 63d877bcd5ef46dbb557f06da22dff6e\nmsgid \"\"\n\"Optional content membership dictionary -- a :data:`dictionary` object \"\n\"which can be used like an :data:`OCG`: it has a visibility state. The \"\n\"visibility of an OCMD is **computed:** it is a logical expression, which \"\n\"uses the state of one or more OCGs to produce a boolean value. The \"\n\"expression's result is interpreted as ON (true) or OFF (false).\"\nmsgstr \"선택적 콘텐츠 멤버십 dictionary -- :data:`OCG` 처럼 사용할 수 있는 :data:`dictionary` 객체: 표시 상태가 있습니다. OCMD의 표시는 **계산됩니다:** 하나 이상의 OCG 상태를 사용하여 불리언 값을 생성하는 논리식입니다. 식의 결과는 ON(true) 또는 OFF(false)로 해석됩니다.\"\n\n#: ../../glossary.rst:174 7685086584e0476aa01c94592195fd87\nmsgid \"\"\n\"Some frequent character combinations are represented by their own special\"\n\" glyphs in more advanced fonts. Typical examples are \\\"fi\\\", \\\"fl\\\", \"\n\"\\\"ffi\\\" and \\\"ffl\\\". These compounds are called *ligatures*. In PyMuPDF \"\n\"text extractions, there is the option to either return the corresponding \"\n\"unicode unchanged, or split ligatures up into their constituent parts: \"\n\"\\\"fi\\\" ==> \\\"f\\\" + \\\"i\\\", etc.\"\nmsgstr \"일부 빈번한 문자 조합은 더 고급 글꼴에서 자체 특수 글리프로 표현됩니다. 일반적인 예는 \\\"fi\\\", \\\"fl\\\", \\\"ffi\\\", \\\"ffl\\\"입니다. 이러한 복합체를 *ligature* 라고 합니다. PyMuPDF 텍스트 추출에서는 해당 유니코드를 변경하지 않고 반환하거나 ligature를 구성 요소로 분할하는 옵션이 있습니다: \\\"fi\\\" ==> \\\"f\\\" + \\\"i\\\" 등.\"\n\n#: ../../footer.rst:46 55f27ea4f801402884fd2fc89352730f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/header-404.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header-404.rst:-1 eeba22b6b6f24accb7aaaf2ca8de91f4\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header-404.rst:-1 32c66b9fa56c4fa3b5b6abcd9f3abcfc\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header-404.rst:-1 6b881eb1ccc64d55990a936130aecf2d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/header.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 2f3a42d58aed4c8d919199a1628e46e5\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 8c5d0e6b475d4acbbd44f0169353b949\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8a0b412ed68e4084a844b1d3978b547f\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/how-to-open-a-file.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 21b5c4028adc463abcc84975940e6301\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 ee82d615395c4e24b8b07395ed871d70\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 1d5b2478c53f433882bce199582d444d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../how-to-open-a-file.rst:7 5ea3d22849e641d897ccb82f8a12500f\nmsgid \"Opening Files\"\nmsgstr \"파일 열기\"\n\n#: ../../how-to-open-a-file.rst:16 395abd8299ba47be838498d680488494\nmsgid \"Supported File Types\"\nmsgstr \"지원되는 파일 유형\"\n\n#: ../../how-to-open-a-file.rst:21 cb3463a996b24a14a008c2fc0ad2b685\nmsgid \"PyMuPDF\"\nmsgstr \"PyMuPDF\"\n\n#: ../../how-to-open-a-file.rst:23 036ac377808741358875a6692e0b2d95\nmsgid \"|PyMuPDF| can open files other than just |PDF|.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 외의 파일도 열 수 있습니다.\"\n\n#: ../../how-to-open-a-file.rst:25 ../../how-to-open-a-file.rst:38\n#: 1a17fc4b2c2e43a9a47e3a2a1ed82bd4 40ef4134dff248bc8869aed36fd176fc\nmsgid \"The following file types are supported:\"\nmsgstr \"다음 파일 유형이 지원됩니다:\"\n\n#: ../../how-to-open-a-file.rst:34 fa9ae965eea142478505848892067bb0\nmsgid \"PyMuPDF Pro\"\nmsgstr \"PyMuPDF Pro\"\n\n#: ../../how-to-open-a-file.rst:36 c4725d269a0e41b0867c5b6b16b8960b\nmsgid \"|PyMuPDF Pro| can open Office files.\"\nmsgstr \"|PyMuPDF Pro| 는 Office 파일을 열 수 있습니다.\"\n\n#: ../../how-to-open-a-file.rst:43 d91d49bc138843188ab0077259cd82ae\nmsgid \"**DOC/DOCX**\"\nmsgstr \"**DOC/DOCX**\"\n\n#: ../../how-to-open-a-file.rst:44 6ff3d492743f45da9b9967b7ac205f1c\nmsgid \"**XLS/XLSX**\"\nmsgstr \"**XLS/XLSX**\"\n\n#: ../../how-to-open-a-file.rst:45 4c317c161ef64bebb742fc17e8e5c6d3\nmsgid \"**PPT/PPTX**\"\nmsgstr \"**PPT/PPTX**\"\n\n#: ../../how-to-open-a-file.rst:46 dfd0df787a6d4a8bada3b55675495889\nmsgid \"**HWP/HWPX**\"\nmsgstr \"**HWP/HWPX**\"\n\n#: ../../how-to-open-a-file.rst:63 61701c1d1007436987106ec058719b82\nmsgid \"How to Open a File\"\nmsgstr \"파일을 여는 방법\"\n\n#: ../../how-to-open-a-file.rst:65 9dd2157acd454f2ea9e62168276399c2\nmsgid \"To open a file, do the following:\"\nmsgstr \"파일을 열려면 다음을 수행하세요:\"\n\n#: ../../how-to-open-a-file.rst:72 284b59b0b7ca41789da44c7d61f81fc7\nmsgid \"\"\n\"The above creates a :ref:`Document`. The instruction `doc = \"\n\"pymupdf.Document(\\\"a.pdf\\\")` does exactly the same. So, `open` is just a \"\n\"convenient alias and you can find its full API documented in that \"\n\"chapter.\"\nmsgstr \"위 코드는 :ref:`Document` 를 생성합니다. `doc = pymupdf.Document(\\\"a.pdf\\\")` 명령도 동일하게 작동합니다. 따라서 `open` 은 편의를 위한 별칭이며, 해당 장에서 전체 API 문서를 확인할 수 있습니다.\"\n\n#: ../../how-to-open-a-file.rst:76 1a5ad0264ff94231899c2caafe461a22\nmsgid \"\"\n\"File Recognizer: Opening with :index:`a Wrong File Extension <pair: \"\n\"wrong; file extension>`\"\nmsgstr \"파일 인식기: 잘못된 파일 확장자로 열기\"\n\n#: ../../how-to-open-a-file.rst:78 90b4fc7ee95f43f49a70a15c890eb8b8\nmsgid \"\"\n\"If you have a document with a wrong file extension for its type, do not \"\n\"worry: it will still be opened correctly, thanks to the integrated file \"\n\"\\\"content recognizer\\\".\"\nmsgstr \"파일 유형과 다른 확장자를 가진 문서가 있어도 걱정하지 마세요: 통합된 파일 \\\"콘텐츠 인식기\\\" 덕분에 여전히 올바르게 열립니다.\"\n\n#: ../../how-to-open-a-file.rst:80 792fc8fc530d4591b0673684e9d0b274\nmsgid \"\"\n\"This component looks at the actual data in the file using a number of \"\n\"heuristics -- independent of the file extension. This of course is also \"\n\"true for file names **without** an extension.\"\nmsgstr \"이 구성 요소는 파일 확장자와 무관하게 여러 휴리스틱을 사용하여 파일의 실제 데이터를 확인합니다. 확장자가 **없는** 파일 이름에도 마찬가지입니다.\"\n\n#: ../../how-to-open-a-file.rst:82 8eec48ad8d35400f93aa9ef384f1baee\nmsgid \"Here is a list of details about how the file content recognizer works:\"\nmsgstr \"파일 콘텐츠 인식기의 작동 방식에 대한 세부사항은 다음과 같습니다:\"\n\n#: ../../how-to-open-a-file.rst:84 999889fc95024292bbe0dc81938a321a\nmsgid \"\"\n\"When opening from a file name, use the ``filetype`` parameter if your \"\n\"file format cannot be determined by content inspection. This is for \"\n\"instance the case for all text files: \\\"txt\\\", \\\"html\\\", \\\"xml\\\" or \"\n\"source files. If the file extension is missing or wrong or the file \"\n\"resides in memory, the ``filetype`` must be used. File formats that can \"\n\"successfully be recognized will be opened even without or wrong \"\n\"extensions, and the ``filetype`` paraneter will be ignored.\"\nmsgstr \"파일 이름에서 열 때, 콘텐츠 검사를 통해 파일 형식을 결정할 수 없는 경우 ``filetype`` 매개변수를 사용하세요. 예를 들어 모든 텍스트 파일(\\\"txt\\\", \\\"html\\\", \\\"xml\\\" 또는 소스 파일)이 이에 해당합니다. 파일 확장자가 없거나 잘못되었거나 파일이 메모리에 있는 경우 ``filetype`` 을 사용해야 합니다. 성공적으로 인식할 수 있는 파일 형식은 확장자가 없거나 잘못되어도 열리며, ``filetype`` 매개변수는 무시됩니다.\"\n\n#: ../../how-to-open-a-file.rst:86 1ac5dd5257eb4ed280e6ec3ed082da31\nmsgid \"\"\n\"Files based on text content do not contain unambiguously recognizable \"\n\"internal structures. This is true for source files (Python, C, etc.) but \"\n\"also HTML, XML and so on. Here, the file extensions and the ``filetype`` \"\n\"parameter continue to play a role and are used to create a \\\"Tex\\\" / \"\n\"\\\"HTML\\\" / ... document. Correspondingly, text files with other / no \"\n\"extensions, can successfully be opened using ``filetype``.\"\nmsgstr \"텍스트 콘텐츠 기반 파일은 명확하게 인식 가능한 내부 구조를 포함하지 않습니다. 소스 파일(Python, C 등)뿐만 아니라 HTML, XML 등도 마찬가지입니다. 이 경우 파일 확장자와 ``filetype`` 매개변수가 계속 역할을 하며 \\\"Tex\\\" / \\\"HTML\\\" / ... 문서를 만드는 데 사용됩니다. 따라서 다른 확장자 또는 확장자가 없는 텍스트 파일은 ``filetype`` 을 사용하여 성공적으로 열 수 있습니다.\"\n\n#: ../../how-to-open-a-file.rst:92 b9b6d23c55ea4547afea0a22f2d79c6d\nmsgid \"Opening Remote Files\"\nmsgstr \"원격 파일 열기\"\n\n#: ../../how-to-open-a-file.rst:95 3b43bf59bfc148328c683743eac1329f\nmsgid \"\"\n\"For remote files on a server (i.e. non-local files), you will need to \"\n\"*stream* the file data to |PyMuPDF|.\"\nmsgstr \"서버의 원격 파일(즉, 로컬이 아닌 파일)의 경우, 파일 데이터를 |PyMuPDF| 로 *스트리밍* 해야 합니다.\"\n\n#: ../../how-to-open-a-file.rst:97 34b7bf2e937a4250810966ed193bdfc8\nmsgid \"\"\n\"For example use the `requests \"\n\"<https://requests.readthedocs.io/en/latest/>`_ library as follows:\"\nmsgstr \"예를 들어 `requests <https://requests.readthedocs.io/en/latest/>`_ 라이브러리를 다음과 같이 사용하세요:\"\n\n#: ../../how-to-open-a-file.rst:110 f259d8091f7242e7bdd2c51ebdd3f925\nmsgid \"Opening Files from Cloud Services\"\nmsgstr \"클라우드 서비스에서 파일 열기\"\n\n#: ../../how-to-open-a-file.rst:112 21d40cb6351a4c69bc14196e1eb014ea\nmsgid \"\"\n\"For further examples which deal with files held on typical cloud services\"\n\" please see these `Cloud Interactions code snippets \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/cloud-\"\n\"interactions>`_.\"\nmsgstr \"일반적인 클라우드 서비스에 저장된 파일을 다루는 추가 예제는 `Cloud Interactions 코드 스니펫 <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/cloud-interactions>`_ 을 참조하세요.\"\n\n#: ../../how-to-open-a-file.rst:120 de92d6a4c46143de86751bded4adc336\nmsgid \"Opening Django Files\"\nmsgstr \"Django 파일 열기\"\n\n#: ../../how-to-open-a-file.rst:122 2a24401c8daf4ec1967ffd20ab41ce1c\nmsgid \"\"\n\"Django implements a `File Storage API \"\n\"<https://docs.djangoproject.com/en/5.1/ref/files/storage/>`_ to store \"\n\"files. The default is the `FileSystemStorage \"\n\"<https://docs.djangoproject.com/en/5.1/ref/files/storage/#the-\"\n\"filesystemstorage-class>`_, but the `django-storages <https://django-\"\n\"storages.readthedocs.io/en/latest/index.html>`_ library provides a number\"\n\" of other storage backends.\"\nmsgstr \"Django는 파일을 저장하기 위해 `File Storage API <https://docs.djangoproject.com/en/5.1/ref/files/storage/>`_ 를 구현합니다. 기본값은 `FileSystemStorage <https://docs.djangoproject.com/en/5.1/ref/files/storage/#the-filesystemstorage-class>`_ 이지만, `django-storages <https://django-storages.readthedocs.io/en/latest/index.html>`_ 라이브러리는 여러 다른 스토리지 백엔드를 제공합니다.\"\n\n#: ../../how-to-open-a-file.rst:124 ce91bc54879b4e0caad6216633c87800\nmsgid \"\"\n\"You can open the file, move the contents into memory, then pass the \"\n\"contents to |PyMuPDF| as a stream.\"\nmsgstr \"파일을 열고, 콘텐츠를 메모리로 이동한 다음, 콘텐츠를 스트림으로 |PyMuPDF| 에 전달할 수 있습니다.\"\n\n#: ../../how-to-open-a-file.rst:139 619bd327f13f4ed1a9204d62ce0a0e40\nmsgid \"Please note that if the file you open is large, you may run out of memory.\"\nmsgstr \"열려는 파일이 큰 경우 메모리가 부족할 수 있습니다.\"\n\n#: ../../how-to-open-a-file.rst:141 e974ef8989724d7ca39ae4e2f528060d\nmsgid \"\"\n\"The File Storage API works well if you're using different storage \"\n\"backends in different environments. If you're only using the \"\n\"`FileSystemStorage`, you can simply use the `obj.file.name` to open the \"\n\"file directly with |PyMuPDF| as shown in an earlier example.\"\nmsgstr \"File Storage API는 다른 환경에서 다른 스토리지 백엔드를 사용하는 경우 잘 작동합니다. `FileSystemStorage` 만 사용하는 경우, 이전 예제에서와 같이 `obj.file.name` 을 사용하여 |PyMuPDF| 로 파일을 직접 열 수 있습니다.\"\n\n#: ../../how-to-open-a-file.rst:149 11fadcb68ef146fc93ca9f4473e140a5\nmsgid \"Opening Files as Text\"\nmsgstr \"파일을 텍스트로 열기\"\n\n#: ../../how-to-open-a-file.rst:152 79658fdcc60c4f62821491708e3874a6\nmsgid \"\"\n\"|PyMuPDF| has the capability to open any plain text file as a document. \"\n\"In order to do this you should provide the `filetype` parameter for the \"\n\"`pymupdf.open` function as `\\\"txt\\\"`.\"\nmsgstr \"|PyMuPDF| 는 모든 일반 텍스트 파일을 문서로 열 수 있는 기능이 있습니다. 이를 수행하려면 `pymupdf.open` 함수의 `filetype` 매개변수를 `\\\"txt\\\"` 로 제공해야 합니다.\"\n\n#: ../../how-to-open-a-file.rst:159 d72a0b8f986843488dfc6ddc257e4f45\nmsgid \"\"\n\"In this way you are able to open a variety of file types and perform the \"\n\"typical **non-PDF** specific features like text searching, text \"\n\"extracting and page rendering. Obviously, once you have rendered your \"\n\"`txt` content, then saving as |PDF| or merging with other |PDF| files is \"\n\"no problem.\"\nmsgstr \"이렇게 하면 다양한 파일 유형을 열고 텍스트 검색, 텍스트 추출 및 페이지 렌더링과 같은 일반적인 **비PDF** 특정 기능을 수행할 수 있습니다. `txt` 콘텐츠를 렌더링한 후에는 |PDF| 로 저장하거나 다른 |PDF| 파일과 병합하는 것도 문제없습니다.\"\n\n#: ../../how-to-open-a-file.rst:163 25cb1a49799b43669b7c520e52fc2e46\nmsgid \"Examples\"\nmsgstr \"예제\"\n\n#: ../../how-to-open-a-file.rst:167 df4ce47e55a94298b344689b280a64df\nmsgid \"Opening a `C#` file\"\nmsgstr \"`C#` 파일 열기\"\n\n#: ../../how-to-open-a-file.rst:176 2f20ca6b671845fca3ae2bceeb25eebd\nmsgid \"Opening an ``XML`` file\"\nmsgstr \"``XML`` 파일 열기\"\n\n#: ../../how-to-open-a-file.rst:184 1c25e62b57d843c9b5b8122f59295144\nmsgid \"Opening a `JSON` file\"\nmsgstr \"`JSON` 파일 열기\"\n\n#: ../../how-to-open-a-file.rst:191 687e69a017bb48b682d8b720ad323f52\nmsgid \"And so on!\"\nmsgstr \"등등!\"\n\n#: ../../how-to-open-a-file.rst:193 f6ae4e85cdb1469bbf04502e1bb02ccd\nmsgid \"\"\n\"As you can imagine many text based file formats can be *very simply \"\n\"opened* and *interpreted* by |PyMuPDF|. This can make data analysis and \"\n\"extraction for a wide range of previously unavailable files possible.\"\nmsgstr \"상상할 수 있듯이 많은 텍스트 기반 파일 형식은 |PyMuPDF| 로 *매우 간단하게 열고* *해석할* 수 있습니다. 이를 통해 이전에 사용할 수 없었던 광범위한 파일에 대한 데이터 분석 및 추출이 가능해집니다.\"\n\n#: ../../footer.rst:46 6894d49c24fc4cfa8f9d99a9257edfdf\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/identity.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 74c1aedfabcd4a5c96f4c2597285c328\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 6b94c7df538e4108a3a5ad33241349ec\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 23ee2c9ef17542ffbf5210e348e9de6a\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../identity.rst:7 ec6871dd23a6408aba45460204127d54\nmsgid \"Identity\"\nmsgstr \"Identity\"\n\n#: ../../identity.rst:9 776ab5a8eb3b4fd5ac5d1b88b17d507a\nmsgid \"\"\n\"Identity is a :ref:`Matrix` that performs no action -- to be used \"\n\"whenever the syntax requires a matrix, but no actual transformation \"\n\"should take place. It has the form *pymupdf.Matrix(1, 0, 0, 1, 0, 0)*.\"\nmsgstr \"Identity는 아무 작업도 수행하지 않는 :ref:`Matrix` 입니다. 구문이 행렬을 요구하지만 실제 변환이 필요하지 않을 때 사용됩니다. 형식은 *pymupdf.Matrix(1, 0, 0, 1, 0, 0)* 입니다.\"\n\n#: ../../identity.rst:11 2260793ef04b4f739e2e3ba60744f1c2\nmsgid \"\"\n\"Identity is a constant, an \\\"immutable\\\" object. So, all of its matrix \"\n\"properties are read-only and its methods are disabled.\"\nmsgstr \"Identity는 상수이며 \\\"불변\\\" 객체입니다. 따라서 모든 행렬 속성은 읽기 전용이고 메서드는 비활성화됩니다.\"\n\n#: ../../identity.rst:13 66677799dfa547a68a4f708a29d071a0\nmsgid \"\"\n\"If you need a **mutable** identity matrix as a starting point, use one of\"\n\" the following statements::\"\nmsgstr \"시작점으로 **변경 가능한** 항등 행렬이 필요하면 다음 문 중 하나를 사용하세요::\"\n\n#: ../../footer.rst:46 62e975eb99a4452285d40da0e91fc76e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../index.rst:39 952c2d69888a45e9b0da6e043ddab148\nmsgid \"About\"\nmsgstr \"소개\"\n\n#: ../../index.rst:50 83a8e5dd2a9b4d099b68e52044113c27\nmsgid \"User Guide\"\nmsgstr \"사용자 가이드\"\n\n#: ../../index.rst:62 d17242cca69d431c8485f8ab5b729f2e\nmsgid \"How to Guide\"\nmsgstr \"사용 방법 가이드\"\n\n#: ../../index.rst:69 7466b8745c424beaac09483b379e1f16\nmsgid \"API Reference\"\nmsgstr \"API 참조\"\n\n#: ../../index.rst:82 b24fcc31226540bc96465c601658ca98\nmsgid \"Other\"\nmsgstr \"기타\"\n\n#: ../../header.rst:-1 43d585d8a38b489ca647a0f6d7ee01dd\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 6af6f9115aea4bcba5a905e65f50def7\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 d0fa97b60e13424eb62997400c445a63\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../index.rst:20 3275915a8da84e58bd47e046c54375d2\nmsgid \"Welcome to |PyMuPDF|\"\nmsgstr \"|PyMuPDF| 에 오신 것을 환영합니다\"\n\n#: ../../index.rst:22 443397ce6ddd47f5b1d2c0008cd4b639\nmsgid \"\"\n\"|PyMuPDF| is a high-performance **Python** library for data extraction, \"\n\"analysis, conversion & manipulation of |PDF| (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작 기능을 제공하는 고성능 **Python** 라이브러리입니다.\"\n\n#: ../../index.rst:24 b09454f69e4247b09e28b65c7744f34a\nmsgid \"\"\n\"|PyMuPDF| is hosted on `GitHub <https://github.com/pymupdf/PyMuPDF>`_ and\"\n\" registered on `PyPI <https://pypi.org/project/PyMuPDF/>`_.\"\nmsgstr \"|PyMuPDF| 는 `GitHub <https://github.com/pymupdf/PyMuPDF>`_ 에 호스팅되고 `PyPI <https://pypi.org/project/PyMuPDF/>`_ 에 등록되어 있습니다.\"\n\n#: ../../footer.rst:46 ../../index.rst:35 9c0239a10d754ddea28f6b0d7597c26f\n#: d10c71ec0c454e0899fc16f6f34f2a83\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/installation.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 16:19+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 96029ef0e2b04d549d1dd8636b516591\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 2e20adf971da4adf8ade567b89099694\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 e225975277fd4141bab6dfb2babcab67\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../installation.rst:6 ../../installation.rst:31\n#: 0e5b938092394f76bb79bd60b8b7bcc8 362130f7ee184277a844a2094e73b166\nmsgid \"Installation\"\nmsgstr \"설치\"\n\n#: ../../installation.rst:9 5756ccf1a8cf47d489d528757b4ff1ed\nmsgid \"Requirements\"\nmsgstr \"요구사항\"\n\n#: ../../installation.rst:11 59418d8369d141eb9ff64af78a5cd0d1\nmsgid \"\"\n\"All the examples below assume that you are running inside a Python \"\n\"virtual environment. See: https://docs.python.org/3/library/venv.html for\"\n\" details. We also assume that `pip` is up to date.\"\nmsgstr \"아래의 모든 예제는 Python 가상 환경 내에서 실행 중이라고 가정합니다. 자세한 내용은 https://docs.python.org/3/library/venv.html 을 참조하세요. 또한 `pip` 가 최신 버전이라고 가정합니다.\"\n\n#: ../../installation.rst:15 c0c567ab87e545dcb02f98a499237cac\nmsgid \"For example:\"\nmsgstr \"예를 들어:\"\n\n#: ../../installation.rst:17 3566b454695c4d74836795503dc32f88\nmsgid \"Windows::\"\nmsgstr \"Windows::\"\n\n#: ../../installation.rst:23 30d9561c3bbd45f79998c3672a481495\nmsgid \"Linux, MacOS::\"\nmsgstr \"Linux, MacOS::\"\n\n#: ../../installation.rst:33 a214d3639973479385b1f7fb97f49eb2\nmsgid \"|PyMuPDF| should be installed using pip with::\"\nmsgstr \"|PyMuPDF| 는 다음 명령으로 pip를 사용하여 설치해야 합니다::\"\n\n#: ../../installation.rst:37 ea5698bf08544d95ab4dfd879681ba77\nmsgid \"\"\n\"This will install from a Python wheel if one is available for your \"\n\"platform.\"\nmsgstr \"플랫폼에 사용 가능한 Python wheel이 있으면 이를 사용하여 설치됩니다.\"\n\n#: ../../installation.rst:41 41710c287f054c699809c8bb0c6be619\nmsgid \"Installation when a suitable wheel is not available\"\nmsgstr \"적합한 wheel 파일을 사용할 수 없는 경우의 설치\"\n\n#: ../../installation.rst:43 edcf8eac64af49bb9cbe25cbe7de7c5a\nmsgid \"\"\n\"If a suitable Python wheel is not available, pip will automatically build\"\n\" from source using a Python sdist.\"\nmsgstr \"적합한 Python wheel 파일을 사용할 수 없는 경우, pip는 Python sdist를 사용하여 소스에서 자동으로 빌드합니다.\"\n\n#: ../../installation.rst:46 10c33b59ba9e4c868ae010f2a7028814\nmsgid \"**This requires C/C++ development tools to be installed**:\"\nmsgstr \"**이를 위해서는 C/C++ 개발 도구가 설치되어 있어야 합니다**:\"\n\n#: ../../installation.rst:48 5ad6beabf5d6474dab9c471133784cb8\nmsgid \"On Windows:\"\nmsgstr \"Windows에서:\"\n\n#: ../../installation.rst:51 c850480032484111ad409c8a6d7cc794\nmsgid \"\"\n\"Install Visual Studio 2019. If not installed in a standard location, set \"\n\"environmental variable `PYMUPDF_SETUP_DEVENV` to the location of the \"\n\"`devenv.com` binary.\"\nmsgstr \"Visual Studio 2019를 설치하세요. 표준 위치에 설치되지 않은 경우, 환경 변수 `PYMUPDF_SETUP_DEVENV` 를 `devenv.com` 바이너리의 위치로 설정하세요.\"\n\n#: ../../installation.rst:56 65947958187d45018d139034858bc083\nmsgid \"\"\n\"Having other installed versions of Visual Studio, for example Visual \"\n\"Studio 2022, can cause problems because one can end up with MuPDF and \"\n\"PyMuPDF code being compiled with different compiler versions.\"\nmsgstr \"Visual Studio 2022와 같은 다른 버전의 Visual Studio가 설치되어 있으면, MuPDF와 PyMuPDF 코드가 서로 다른 컴파일러 버전으로 컴파일될 수 있어 문제가 발생할 수 있습니다.\"\n\n#: ../../installation.rst:60 9e448ffec0c64a40968de3839f6b2855\nmsgid \"The build will automatically download and build MuPDF.\"\nmsgstr \"빌드는 자동으로 MuPDF를 다운로드하고 빌드합니다.\"\n\n#: ../../installation.rst:66 9ea3e134885d4f05a4c3e2a4f5bc1095\nmsgid \"Problems after installation\"\nmsgstr \"설치 후 문제\"\n\n#: ../../installation.rst:68 ../../installation.rst:117\n#: 0d4df66268c544a69e1dba24527b39dc da5b4f00d11844939c6ba2c50436cde5\nmsgid \"On Windows, Python error::\"\nmsgstr \"Windows에서 Python 오류::\"\n\n#: ../../installation.rst:72 05623aa04f7948f1928a5424140c8d9d\nmsgid \"\"\n\"This has been occasionally seen if `MSVCP140.dll` is missing, and appears\"\n\" to be caused by a bug in some versions (2015-2017) of `Microsoft Visual \"\n\"C++ Redistributables`.\"\nmsgstr \"`MSVCP140.dll` 이 누락된 경우 가끔 발생하며, 일부 버전(2015-2017)의 `Microsoft Visual C++ 재배포 가능 패키지` 의 버그로 인한 것으로 보입니다.\"\n\n#: ../../installation.rst:76 9472b21821c84665a04e27961520861f\nmsgid \"\"\n\"It is recommended to search for `MSVCP140.dll` in https://msdn.com to \"\n\"find instructions for how to reinstall it. For example \"\n\"https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist has \"\n\"permalinks to the latest supported versions.\"\nmsgstr \"https://msdn.com 에서 `MSVCP140.dll` 을 검색하여 재설치 방법을 찾는 것이 좋습니다. 예를 들어 https://learn.microsoft.com/cpp/windows/latest-supported-vc-redist 에는 지원되는 최신 버전에 대한 영구 링크가 있습니다.\"\n\n#: ../../installation.rst:81 3007dd23091741939a53721b7d628b74\nmsgid \"See https://github.com/pymupdf/PyMuPDF/issues/2678 for more details.\"\nmsgstr \"자세한 내용은 https://github.com/pymupdf/PyMuPDF/issues/2678 을 참조하세요.\"\n\n#: ../../installation.rst:84 c9a39b500d3d45a1b18d1c3f00c2982e\nmsgid \"Python error::\"\nmsgstr \"Python 오류::\"\n\n#: ../../installation.rst:88 53589cbbfa6944378c7034ed948fa3b4\nmsgid \"\"\n\"This can happen if PyMuPDF's legacy name `fitz` is used (for example \"\n\"`import fitz` instead of `import pymupdf`), and an unrelated Python \"\n\"package called `fitz` (https://pypi.org/project/fitz/) is installed.\"\nmsgstr \"PyMuPDF의 레거시 이름 `fitz` 를 사용하는 경우(예: `import pymupdf` 대신 `import fitz`) 및 관련 없는 Python 패키지 `fitz` (https://pypi.org/project/fitz/)가 설치된 경우 발생할 수 있습니다.\"\n\n#: ../../installation.rst:92 f32677d324ec471f8b25f4becffc62f5\nmsgid \"\"\n\"The fitz package appears to be no longer maintained (the latest release \"\n\"is from 2017), but unfortunately it does not seem possible to remove it \"\n\"from pypi.org. It does not even work on its own, as well as breaking the \"\n\"use of PyMuPDF's legacy name.\"\nmsgstr \"fitz 패키지는 더 이상 유지 관리되지 않는 것으로 보입니다(최신 릴리스는 2017년). 불행히도 pypi.org에서 제거하는 것은 불가능해 보입니다. 자체적으로도 작동하지 않으며 PyMuPDF의 레거시 이름 사용도 방해합니다.\"\n\n#: ../../installation.rst:97 31c58415e64d4285b88f8e33a6d97802\nmsgid \"There are a few ways to avoid this problem:\"\nmsgstr \"이 문제를 피하는 몇 가지 방법이 있습니다:\"\n\n#: ../../installation.rst:100 3f88b66501a544699823982b2254031f\nmsgid \"\"\n\"Use `import pymupdf` instead of `import fitz`, and update one's code to \"\n\"match.\"\nmsgstr \"`import fitz` 대신 `import pymupdf` 를 사용하고 코드를 업데이트하세요.\"\n\n#: ../../installation.rst:103 eb2fe6e966f44853b6678fc67361a0c0\nmsgid \"Or uninstall the `fitz` package and reinstall PyMuPDF::\"\nmsgstr \"또는 `fitz` 패키지를 제거하고 PyMuPDF를 재설치하세요::\"\n\n#: ../../installation.rst:108 f733312e30d5442d8681d28dfc2e0418\nmsgid \"Or use `import pymupdf as fitz`. However this has not been well tested.\"\nmsgstr \"또는 `import pymupdf as fitz` 를 사용하세요. 다만 이 방법은 충분히 테스트되지 않았습니다.\"\n\n#: ../../installation.rst:110 d2942ed579c547888ca1290602ed28cc\nmsgid \"With Jupyter labs on Apple Silicon (arm64), Python error::\"\nmsgstr \"Apple Silicon(arm64)의 Jupyter labs에서 Python 오류::\"\n\n#: ../../installation.rst:114 3dedae1d6af9447eb2192ed96052aa90\nmsgid \"\"\n\"This appears to be a problem in Jupyter labs; see: \"\n\"https://github.com/pymupdf/PyMuPDF/issues/3643#issuecomment-2210588778.\"\nmsgstr \"이는 Jupyter labs의 문제로 보입니다. 자세한 내용은 https://github.com/pymupdf/PyMuPDF/issues/3643#issuecomment-2210588778 을 참조하세요.\"\n\n#: ../../installation.rst:121 7bd3b3ebec5f4f07900684f56429ad36\nmsgid \"\"\n\"This was reported 2025-03-26 in \"\n\"https://github.com/pymupdf/PyMuPDF/issues/4405.\"\nmsgstr \"이 문제는 2025-03-26에 https://github.com/pymupdf/PyMuPDF/issues/4405 에서 보고되었습니다.\"\n\n#: ../../installation.rst:123 b6139c99d78e45a6a9105ecc8404f710\nmsgid \"The fix appears to be to install the latest `VC_redist.x64.exe`.\"\nmsgstr \"해결 방법은 최신 `VC_redist.x64.exe` 를 설치하는 것으로 보입니다.\"\n\n#: ../../installation.rst:127 bccf958282944bd4ac99d1ccf70707d4\nmsgid \"Notes\"\nmsgstr \"참고사항\"\n\n#: ../../installation.rst:130 61583f96dcfd4261a2c77d364470a2ac\nmsgid \"Wheels are available for the following platforms:\"\nmsgstr \"다음 플랫폼에 대해 wheel 파일을 사용할 수 있습니다:\"\n\n#: ../../installation.rst:132 182364ca9ac94666825e7076e6d26a82\nmsgid \"Windows 32-bit Intel.\"\nmsgstr \"Windows 32비트 Intel.\"\n\n#: ../../installation.rst:133 005535b4e858480eb22fb9ed70cd49fe\nmsgid \"Windows 64-bit Intel.\"\nmsgstr \"Windows 64비트 Intel.\"\n\n#: ../../installation.rst:134 7687fad16e9e41379221c5187c01a9f6\nmsgid \"Linux 64-bit Intel.\"\nmsgstr \"Linux 64비트 Intel.\"\n\n#: ../../installation.rst:135 e8bae64d60a44c078ddab450469e771d\nmsgid \"Linux 64-bit ARM.\"\nmsgstr \"Linux 64비트 ARM.\"\n\n#: ../../installation.rst:136 2064ef5679e64d3db0b45c1dfbdff952\nmsgid \"MacOS 64-bit Intel.\"\nmsgstr \"MacOS 64비트 Intel.\"\n\n#: ../../installation.rst:137 2190d152d5d0476b86a7e483d9bf4e00\nmsgid \"MacOS 64-bit ARM.\"\nmsgstr \"MacOS 64비트 ARM.\"\n\n#: ../../installation.rst:139 5ba4832bb0ca40c3a6f960f5b5665e84\nmsgid \"Details:\"\nmsgstr \"세부사항:\"\n\n#: ../../installation.rst:141 41c9bfb953b447c484a012628de54f36\nmsgid \"We release a single wheel for each of the above platforms.\"\nmsgstr \"위 플랫폼 각각에 대해 단일 wheel 파일을 릴리스합니다.\"\n\n#: ../../installation.rst:144 8cf71ef8029a4d07ada650d699bfd1fc\nmsgid \"\"\n\"Each wheel uses the Python Stable ABI of the current oldest supported \"\n\"Python version (currently 3.10), and so works with all later Python \"\n\"versions, including new Python releases.\"\nmsgstr \"각 wheel은 현재 지원되는 가장 오래된 Python 버전(현재 3.10)의 Python Stable ABI를 사용하므로, 새로운 Python 릴리스를 포함한 모든 이후 Python 버전에서 작동합니다.\"\n\n#: ../../installation.rst:149 85f0cb2340464eacb0b93de71ce3a42b\nmsgid \"\"\n\"Wheels are tested on all Python versions currently marked as \"\n\"\\\"Supported\\\" on https://devguide.python.org/versions/, currently \"\n\"|python_versions|.\"\nmsgstr \"Wheel은 https://devguide.python.org/versions/ 에서 현재 \\\"지원됨\\\"으로 표시된 모든 Python 버전에서 테스트되며, 현재 |python_versions| 입니다.\"\n\n#: ../../installation.rst:153 b10deebc967f4ab8bdb0f24ad98ed832\nmsgid \"\"\n\"Wheels are not available for Python installed with `Chocolatey \"\n\"<https://chocolatey.org/>`_ on Windows. Instead install Python using the \"\n\"Windows installer from the python.org website, see: \"\n\"http://www.python.org/downloads\"\nmsgstr \"Windows에서 `Chocolatey <https://chocolatey.org/>`_ 로 설치한 Python에는 wheel 파일을 사용할 수 없습니다. 대신 python.org 웹사이트의 Windows 설치 프로그램을 사용하여 Python을 설치하세요. 자세한 내용은 http://www.python.org/downloads 를 참조하세요.\"\n\n#: ../../installation.rst:159 624bcf09993d4be0ae0f8a75b8353859\nmsgid \"\"\n\"Wheels are not available for Linux-aarch64 with `Musl libc \"\n\"<https://musl.libc.org/>`_ (For example `Alpine Linux \"\n\"<https://alpinelinux.org/>`_ on aarch64), and building from source is \"\n\"known to fail.\"\nmsgstr \"`Musl libc <https://musl.libc.org/>`_ 를 사용하는 Linux-aarch64(예: aarch64의 `Alpine Linux <https://alpinelinux.org/>`_)에는 wheel 파일을 사용할 수 없으며, 소스에서 빌드하는 것은 실패하는 것으로 알려져 있습니다.\"\n\n#: ../../installation.rst:164 efeb850ab27c435e9bdc7b4bfcce4292\nmsgid \"\"\n\"There are no **mandatory** external dependencies. However, some optional \"\n\"feature are available only if additional components are installed:\"\nmsgstr \"**필수** 외부 종속성은 없습니다. 다만 일부 선택적 기능은 추가 구성 요소가 설치된 경우에만 사용할 수 있습니다:\"\n\n#: ../../installation.rst:166 112f6dc0117840bb96de1ccb40383a6e\nmsgid \"\"\n\"`Pillow <https://pypi.org/project/Pillow/>`_ is required for \"\n\":meth:`Pixmap.pil_save` and :meth:`Pixmap.pil_tobytes`.\"\nmsgstr \"`Pillow <https://pypi.org/project/Pillow/>`_ 는 :meth:`Pixmap.pil_save` 및 :meth:`Pixmap.pil_tobytes` 에 필요합니다.\"\n\n#: ../../installation.rst:167 1ee77df6b8b94e6798a002846af1766e\nmsgid \"\"\n\"`fontTools <https://pypi.org/project/fonttools/>`_ is required for \"\n\":meth:`Document.subset_fonts`.\"\nmsgstr \"`fontTools <https://pypi.org/project/fonttools/>`_ 는 :meth:`Document.subset_fonts` 에 필요합니다.\"\n\n#: ../../installation.rst:168 28cbd6c15f344131b911099e680559b0\nmsgid \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ is a \"\n\"collection of nice fonts to be used for text output methods.\"\nmsgstr \"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ 는 텍스트 출력 방법에 사용할 수 있는 좋은 글꼴 모음입니다.\"\n\n#: ../../installation.rst:170 4e52c3cf248c4abcb79594a420fd423f\nmsgid \"\"\n\"`Tesseract-OCR <https://github.com/tesseract-ocr/tesseract>`_ for optical\"\n\" character recognition in images and document pages. Tesseract is \"\n\"separate software, not a Python package. To enable OCR functions in \"\n\"PyMuPDF, Tesseract must be installed and the `tessdata` folder name \"\n\"specified; see below.\"\nmsgstr \"이미지 및 문서 페이지의 광학 문자 인식을 위한 `Tesseract-OCR <https://github.com/tesseract-ocr/tesseract>`_ 입니다. Tesseract는 별도의 소프트웨어이며 Python 패키지가 아닙니다. PyMuPDF에서 OCR 기능을 사용하려면 Tesseract를 설치하고 `tessdata` 폴더 이름을 지정해야 합니다. 아래를 참조하세요.\"\n\n#: ../../installation.rst:176 c26a998174ff490b98bd7883858b8b37\nmsgid \"\"\n\"You can install these additional components at any time -- before or \"\n\"after installing PyMuPDF. PyMuPDF will detect their presence during \"\n\"import or when the respective functions are being used.\"\nmsgstr \"이러한 추가 구성 요소는 언제든지 설치할 수 있습니다 -- PyMuPDF 설치 전후 모두 가능합니다. PyMuPDF는 가져오기 중 또는 해당 함수가 사용될 때 이들의 존재를 감지합니다.\"\n\n#: ../../installation.rst:180 06f197dc89334f00b8fde2aa343e6a2f\nmsgid \"Build and install from a local PyMuPDF source tree\"\nmsgstr \"로컬 PyMuPDF 소스 트리에서 빌드 및 설치\"\n\n#: ../../installation.rst:182 a5b05e1ca807403ba4f04f8b040f4089\nmsgid \"Initial setup:\"\nmsgstr \"초기 설정:\"\n\n#: ../../installation.rst:184 6544cbacb1694401940667fbf45ebbe0\nmsgid \"Install C/C++ development tools as described above.\"\nmsgstr \"위에 설명된 대로 C/C++ 개발 도구를 설치하세요.\"\n\n#: ../../installation.rst:185 0645317ab66746168a76c49a26e93d39\nmsgid \"Enter a Python venv and update pip, as described above.\"\nmsgstr \"위에 설명된 대로 Python venv에 들어가서 pip를 업데이트하세요.\"\n\n#: ../../installation.rst:187 82271eef944e4faf817e14c489cd2c16\nmsgid \"Get a PyMuPDF source tree:\"\nmsgstr \"PyMuPDF 소스 트리 가져오기:\"\n\n#: ../../installation.rst:189 3c67a60c157048679a1dafd0e6abe5fb\nmsgid \"Clone the PyMuPDF git repository::\"\nmsgstr \"PyMuPDF git 저장소 복제::\"\n\n#: ../../installation.rst:194 7b0c1e0a13d44979ab25c04feb345ad1\nmsgid \"\"\n\"Or download and extract a `.zip` or `.tar.gz` source release from \"\n\"https://github.com/pymupdf/PyMuPDF/releases.\"\nmsgstr \"또는 https://github.com/pymupdf/PyMuPDF/releases 에서 `.zip` 또는 `.tar.gz` 소스 릴리스를 다운로드하고 압축을 풀 수 있습니다.\"\n\n#: ../../installation.rst:197 9edcc8838b654d3a9e1882ee8edefa4c\nmsgid \"Then one can build PyMuPDF in two ways:\"\nmsgstr \"그런 다음 PyMuPDF를 두 가지 방법으로 빌드할 수 있습니다:\"\n\n#: ../../installation.rst:199 575e45b815c94f7cad04f1b45e7c3d7f\nmsgid \"Build and install PyMuPDF with default MuPDF version::\"\nmsgstr \"기본 MuPDF 버전으로 PyMuPDF 빌드 및 설치::\"\n\n#: ../../installation.rst:203 bb7099833f204ff3829afd0cd54324cf\nmsgid \"\"\n\"This will automatically download a specific hard-coded MuPDF source \"\n\"release, and build it into PyMuPDF.\"\nmsgstr \"이렇게 하면 특정 하드코딩된 MuPDF 소스 릴리스를 자동으로 다운로드하여 PyMuPDF에 빌드합니다.\"\n\n#: ../../installation.rst:206 86e76ec90c1c4d7a89dcb112d69ccbba\nmsgid \"Or build and install PyMuPDF using a local MuPDF source tree:\"\nmsgstr \"또는 로컬 MuPDF 소스 트리를 사용하여 PyMuPDF 빌드 및 설치:\"\n\n#: ../../installation.rst:208 b9853c693d1f49358428f38af93edc33\nmsgid \"Clone the MuPDF git repository::\"\nmsgstr \"MuPDF git 저장소 복제::\"\n\n#: ../../installation.rst:213 854b5ebfeb9847efb51d37d0f3e4c259\nmsgid \"\"\n\"Build PyMuPDF, specifying the location of the local MuPDF tree with the \"\n\"environmental variables `PYMUPDF_SETUP_MUPDF_BUILD`::\"\nmsgstr \"환경 변수 `PYMUPDF_SETUP_MUPDF_BUILD` 를 사용하여 로컬 MuPDF 트리의 위치를 지정하여 PyMuPDF 빌드::\"\n\n#: ../../installation.rst:218 24b5cda1241e4f36b5aaf31c8df91447\nmsgid \"\"\n\"Also, one can build for different Python versions in the same PyMuPDF \"\n\"tree:\"\nmsgstr \"또한 동일한 PyMuPDF 트리에서 다른 Python 버전용으로 빌드할 수 있습니다:\"\n\n#: ../../installation.rst:221 fc0b1a2699064aaaa377451775502e20\nmsgid \"\"\n\"PyMuPDF will build for the version of Python that is being used to run \"\n\"`pip`. To run `pip` with a specific Python version, use `python -m pip` \"\n\"instead of `pip`.\"\nmsgstr \"PyMuPDF는 `pip` 를 실행하는 데 사용되는 Python 버전에 대해 빌드됩니다. 특정 Python 버전으로 `pip` 를 실행하려면 `pip` 대신 `python -m pip` 를 사용하세요.\"\n\n#: ../../installation.rst:225 dd80aa73dedb4313a237f8c77a2d783d\nmsgid \"So for example on Windows one can build different versions with::\"\nmsgstr \"예를 들어 Windows에서 다음과 같이 다른 버전을 빌드할 수 있습니다::\"\n\n#: ../../installation.rst:229 4fbc355486c04e7fb88bcdd8ffae7059\nmsgid \"or::\"\nmsgstr \"또는::\"\n\n#: ../../installation.rst:235 207c24c76f364447839aefe03523527b\nmsgid \"Running tests\"\nmsgstr \"테스트 실행\"\n\n#: ../../installation.rst:237 052b595cbe1448d79c441e326e94f9d7\nmsgid \"\"\n\"Having a PyMuPDF tree available allows one to run PyMuPDF's `pytest` test\"\n\" suite::\"\nmsgstr \"PyMuPDF 트리를 사용할 수 있으면 PyMuPDF의 `pytest` 테스트 스위트를 실행할 수 있습니다::\"\n\n#: ../../installation.rst:246 795e4545d04f4e04baa8a0527281f16e\nmsgid \"Notes about using a non-default MuPDF\"\nmsgstr \"기본값이 아닌 MuPDF 사용에 대한 참고사항\"\n\n#: ../../installation.rst:248 9a130c5a8a0946668b8885f28af8aa04\nmsgid \"\"\n\"Using a non-default build of MuPDF by setting environmental variable \"\n\"`PYMUPDF_SETUP_MUPDF_BUILD` can cause various things to go wrong and so \"\n\"is not generally supported:\"\nmsgstr \"환경 변수 `PYMUPDF_SETUP_MUPDF_BUILD` 를 설정하여 기본값이 아닌 MuPDF 빌드를 사용하면 다양한 문제가 발생할 수 있으므로 일반적으로 지원되지 않습니다:\"\n\n#: ../../installation.rst:252 79b112fde2cc4475bbef94325d535a3d\nmsgid \"\"\n\"If MuPDF's major version number differs from what PyMuPDF uses by \"\n\"default, PyMuPDF can fail to build, because MuPDF's API can change \"\n\"between major versions.\"\nmsgstr \"MuPDF의 주 버전 번호가 PyMuPDF가 기본적으로 사용하는 것과 다르면, MuPDF의 API가 주 버전 간에 변경될 수 있으므로 PyMuPDF 빌드가 실패할 수 있습니다.\"\n\n#: ../../installation.rst:256 26963aaabb354a0fb893981e3cd6b8d0\nmsgid \"\"\n\"Runtime behaviour of PyMuPDF can change because MuPDF's runtime behaviour\"\n\" changes between different minor releases. This can also break some \"\n\"PyMuPDF tests.\"\nmsgstr \"PyMuPDF의 런타임 동작은 MuPDF의 런타임 동작이 다른 부 버전 간에 변경되기 때문에 변경될 수 있습니다. 이로 인해 일부 PyMuPDF 테스트가 실패할 수도 있습니다.\"\n\n#: ../../installation.rst:260 cf6ea4f83bfa409381276082a6a8bdf9\nmsgid \"\"\n\"If MuPDF was built with its default config instead of PyMuPDF's \"\n\"customised config (for example if MuPDF is a system install), it is \"\n\"possible that `tests/test_textbox.py:test_textbox3()` will fail. One can \"\n\"skip this particular test by adding `-k 'not test_textbox3'` to the \"\n\"`pytest` command line.\"\nmsgstr \"MuPDF가 PyMuPDF의 사용자 정의 구성 대신 기본 구성을 사용하여 빌드된 경우(예: MuPDF가 시스템 설치인 경우), `tests/test_textbox.py:test_textbox3()` 가 실패할 수 있습니다. `pytest` 명령줄에 `-k 'not test_textbox3'` 를 추가하여 이 특정 테스트를 건너뛸 수 있습니다.\"\n\n#: ../../installation.rst:268 700f4d8e58e84935b6c6975860df3b8f\nmsgid \"Official PyMuPDF Linux wheels may not install on older Linux systems\"\nmsgstr \"공식 PyMuPDF Linux wheel 파일이 오래된 Linux 시스템에 설치되지 않을 수 있음\"\n\n#: ../../installation.rst:270 b47547ab827c4869a01099c6505cf69a\nmsgid \"Releases of PyMuPDF are incompatible with older Linux systems.\"\nmsgstr \"PyMuPDF 릴리스는 오래된 Linux 시스템과 호환되지 않습니다.\"\n\n#: ../../installation.rst:272 808eb6388cc546d782e08fad72571c1d\nmsgid \"\"\n\"For example as of 2025-09-03, `pip install pymupdf` does not work on some\"\n\" AWS Lambda systems - see \"\n\"https://github.com/pymupdf/PyMuPDF/discussions/4631.\"\nmsgstr \"예를 들어 2025-09-03 기준으로, 일부 AWS Lambda 시스템에서는 `pip install pymupdf` 가 작동하지 않습니다. 자세한 내용은 https://github.com/pymupdf/PyMuPDF/discussions/4631 을 참조하세요.\"\n\n#: ../../installation.rst:275 debea54d4d7a43c2878628b326c0c3f0\nmsgid \"\"\n\"This is because official PyMuPDF Linux wheels are built with a version of\"\n\" glibc determined by the current Python manylinux environment. These \"\n\"wheels are incompatible with Linux systems that have an older glibc.\"\nmsgstr \"이는 공식 PyMuPDF Linux wheel 파일이 현재 Python manylinux 환경에 의해 결정된 glibc 버전으로 빌드되기 때문입니다. 이러한 wheel 파일은 오래된 glibc를 가진 Linux 시스템과 호환되지 않습니다.\"\n\n#: ../../installation.rst:279 bf75483c6b084df08b1cc5bd8206d1bf\nmsgid \"\"\n\"The official Python manylinux environment is updated periodically to use \"\n\"newer glibc versions, so new releases of PyMuPDF become increasingly \"\n\"incompatible with older Linux systems.\"\nmsgstr \"공식 Python manylinux 환경은 최신 glibc 버전을 사용하도록 주기적으로 업데이트되므로, PyMuPDF의 새 릴리스는 오래된 Linux 시스템과 점점 더 호환되지 않게 됩니다.\"\n\n#: ../../installation.rst:283 91117ed642e046819ecc665f9b6c9b50\nmsgid \"\"\n\"There is nothing that can be done about this, other than updating older \"\n\"Linux systems, or building PyMuPDF locally from source.\"\nmsgstr \"오래된 Linux 시스템을 업데이트하거나 소스에서 로컬로 PyMuPDF를 빌드하는 것 외에는 이에 대해 할 수 있는 일이 없습니다.\"\n\n#: ../../installation.rst:286 e7b222da2a044c2fa1eedf9c819d97ca\nmsgid \"\"\n\"For more details, please see: `Python Packaging Authority \"\n\"<https://www.pypa.io>`_.\"\nmsgstr \"자세한 내용은 `Python Packaging Authority <https://www.pypa.io>`_ 를 참조하세요.\"\n\n#: ../../installation.rst:290 4adbb8931dfd4590a44a57ffb3936e97\nmsgid \"Packaging\"\nmsgstr \"패키징\"\n\n#: ../../installation.rst:292 53c33343b4c24290ad643762f5bbb050\nmsgid \"See :doc:`packaging`.\"\nmsgstr \":doc:`packaging` 을 참조하세요.\"\n\n#: ../../installation.rst:296 477e709115dd4d119aea37fb3a68a54b\nmsgid \"Using with Pyodide\"\nmsgstr \"Pyodide와 함께 사용\"\n\n#: ../../installation.rst:298 28b8424d39f448fd863709fd16271d9a\nmsgid \"See :doc:`pyodide`.\"\nmsgstr \":doc:`pyodide` 를 참조하세요.\"\n\n#: ../../installation.rst:304 05d1ad76d8ff49d8b8be1c318e026ccb\nmsgid \"Enabling Integrated OCR Support\"\nmsgstr \"통합 OCR 지원 활성화\"\n\n#: ../../installation.rst:306 1088128a9ea343a09d2433086fcee140\nmsgid \"\"\n\"If you do not intend to use this feature, skip this step. Otherwise, it \"\n\"is required for both installation paths: **from wheels and from \"\n\"sources.**\"\nmsgstr \"이 기능을 사용하지 않으려면 이 단계를 건너뛰세요. 그렇지 않으면 두 설치 경로 모두에 필요합니다: **wheel 파일에서 및 소스에서.**\"\n\n#: ../../installation.rst:308 18290d46b0854568b242288afd51a0da\nmsgid \"\"\n\"PyMuPDF will already contain all the logic to support OCR functions. But \"\n\"it additionally does need `Tesseract’s language support data \"\n\"<https://github.com/tesseract-ocr/tessdata>`_.\"\nmsgstr \"PyMuPDF에는 이미 OCR 기능을 지원하는 모든 로직이 포함되어 있습니다. 하지만 추가로 `Tesseract의 언어 지원 데이터 <https://github.com/tesseract-ocr/tessdata>`_ 가 필요합니다.\"\n\n#: ../../installation.rst:310 0cbfeba7ee2e4382baa33ea4562e36c3\nmsgid \"\"\n\"If not specified explicitly, PyMuPDF will attempt to find the installed \"\n\"Tesseract's tessdata, but this should probably not be relied upon.\"\nmsgstr \"명시적으로 지정하지 않으면 PyMuPDF는 설치된 Tesseract의 tessdata를 찾으려고 시도하지만, 이에 의존하지 않는 것이 좋습니다.\"\n\n#: ../../installation.rst:313 340c284211c64d04a0a7705bbaed97a1\nmsgid \"\"\n\"Otherwise PyMuPDF requires that Tesseract's language support folder is \"\n\"specified explicitly either in PyMuPDF OCR functions' `tessdata` \"\n\"arguments or `os.environ[\\\"TESSDATA_PREFIX\\\"]`.\"\nmsgstr \"그렇지 않으면 PyMuPDF는 Tesseract의 언어 지원 폴더가 PyMuPDF OCR 함수의 `tessdata` 인수 또는 `os.environ[\\\"TESSDATA_PREFIX\\\"]` 에 명시적으로 지정되어야 합니다.\"\n\n#: ../../installation.rst:317 4050e5d26f8d4fcebd4429bf4468f2c1\nmsgid \"So for a working OCR functionality, make sure to complete this checklist:\"\nmsgstr \"따라서 OCR 기능이 작동하려면 다음 체크리스트를 완료해야 합니다:\"\n\n#: ../../installation.rst:319 ae04b692262d427da4c557773bbb6331\nmsgid \"\"\n\"Locate Tesseract's language support folder. Typically you will find it \"\n\"here:\"\nmsgstr \"Tesseract의 언어 지원 폴더를 찾으세요. 일반적으로 다음 위치에 있습니다:\"\n\n#: ../../installation.rst:321 518b279edc7f426199e22b43bb47488e\nmsgid \"Windows: `C:/Program Files/Tesseract-OCR/tessdata`\"\nmsgstr \"Windows: `C:/Program Files/Tesseract-OCR/tessdata`\"\n\n#: ../../installation.rst:322 2829c0e448b44e639344346371835824\nmsgid \"Unix systems: `/usr/share/tesseract-ocr/4.00/tessdata`\"\nmsgstr \"Unix 시스템: `/usr/share/tesseract-ocr/4.00/tessdata`\"\n\n#: ../../installation.rst:324 d8669511863246a096ce609ebddc096b\nmsgid \"Specify the language support folder when calling PyMuPDF OCR functions:\"\nmsgstr \"PyMuPDF OCR 함수를 호출할 때 언어 지원 폴더를 지정하세요:\"\n\n#: ../../installation.rst:326 2defdb35431444ab8cb2a6832cb3cc88\nmsgid \"Set the `tessdata` argument.\"\nmsgstr \"`tessdata` 인수를 설정하세요.\"\n\n#: ../../installation.rst:327 eda39b64a6ca464d8c23f1eeec197a8f\nmsgid \"Or set `os.environ[\\\"TESSDATA_PREFIX\\\"]` from within Python.\"\nmsgstr \"또는 Python 내에서 `os.environ[\\\"TESSDATA_PREFIX\\\"]` 를 설정하세요.\"\n\n#: ../../installation.rst:328 d711c5765afc4c0cafadc80892c613e9\nmsgid \"\"\n\"Or set environment variable `TESSDATA_PREFIX` before running Python, for \"\n\"example:\"\nmsgstr \"또는 Python을 실행하기 전에 환경 변수 `TESSDATA_PREFIX` 를 설정하세요. 예:\"\n\n#: ../../installation.rst:330 adb02ed301f749c0b70fa768f6279980\nmsgid \"\"\n\"Windows: `setx TESSDATA_PREFIX \\\"C:/Program Files/Tesseract-\"\n\"OCR/tessdata\\\"`\"\nmsgstr \"Windows: `setx TESSDATA_PREFIX \\\"C:/Program Files/Tesseract-OCR/tessdata\\\"`\"\n\n#: ../../installation.rst:331 a7d44e96bab64a1492085fe6649aa5ba\nmsgid \"\"\n\"Unix systems: `declare -x TESSDATA_PREFIX=/usr/share/tesseract-\"\n\"ocr/4.00/tessdata`\"\nmsgstr \"Unix 시스템: `declare -x TESSDATA_PREFIX=/usr/share/tesseract-ocr/4.00/tessdata`\"\n\n#: ../../installation.rst:336 a123b1fc6a474985b09b2e4de3759541\nmsgid \"\"\n\"Find out more on the `official documentation for installing Tesseract \"\n\"website <https://tesseract-ocr.github.io/tessdoc/Installation.html>`_.\"\nmsgstr \"\"\n\n#: ../../footer.rst:48 04ec8ea4e7e743ab9f77de31a752358a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/irect.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 fba66bf65f8244c99a76005b4aa13c77\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 c942dc1ee97843a1823121e8c22c5942\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8e36a463460e419f9787f96dfe806717\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../irect.rst:7 5159d7062cad401c98bbfc419330c03c\nmsgid \"IRect\"\nmsgstr \"IRect\"\n\n#: ../../irect.rst:9 da2f82891e674e9a99975f0e1c77534a\nmsgid \"\"\n\"IRect is a rectangular bounding box, very similar to :ref:`Rect`, except \"\n\"that all corner coordinates are integers. IRect is used to specify an \"\n\"area of pixels, e.g. to receive image data during rendering. Otherwise, \"\n\"e.g. considerations concerning emptiness and validity of rectangles also \"\n\"apply to this class. Methods and attributes have the same names, and in \"\n\"many cases are implemented by re-using the respective :ref:`Rect` \"\n\"counterparts.\"\nmsgstr \"IRect는 :ref:`Rect` 와 매우 유사한 사각형 경계 상자입니다. 단, 모든 모서리 좌표가 정수라는 점이 다릅니다. IRect는 픽셀 영역을 지정하는 데 사용됩니다(예: 렌더링 중 이미지 데이터를 받기 위해). 그 외에도 사각형의 빈 상태 및 유효성에 대한 고려 사항도 이 클래스에 적용됩니다. 메서드와 속성은 동일한 이름을 가지며, 많은 경우 해당 :ref:`Rect` 대응 항목을 재사용하여 구현됩니다.\"\n\n#: ../../irect.rst:12 a2319632991b4392b7ea2363ed3ce3ca\nmsgid \"**Attribute / Method**\"\nmsgstr \"**속성 / 메서드**\"\n\n#: ../../irect.rst:12 985bc4b51a2844cc8c87af7ba3568037\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../irect.rst:14 312b0f5bcbbd40a2bd8e8e1e19229048\nmsgid \":meth:`IRect.contains`\"\nmsgstr \":meth:`IRect.contains`\"\n\n#: ../../irect.rst:14 1ccbbb3d38b14035b18375fea8176585\nmsgid \"checks containment of another object\"\nmsgstr \"다른 객체의 포함 여부 확인\"\n\n#: ../../irect.rst:15 48378afa42394efc9fdbf9eb14494570\nmsgid \":meth:`IRect.get_area`\"\nmsgstr \":meth:`IRect.get_area`\"\n\n#: ../../irect.rst:15 7c5d16bc4f66409496a2544313c511e1\nmsgid \"calculate rectangle area\"\nmsgstr \"사각형 영역 계산\"\n\n#: ../../irect.rst:16 f0ccc3542ac74ea990d056a328e04a38\nmsgid \":meth:`IRect.intersect`\"\nmsgstr \":meth:`IRect.intersect`\"\n\n#: ../../irect.rst:16 1dc1ecaee3494262a0fe5f21fa1f14d9\nmsgid \"common part with another rectangle\"\nmsgstr \"다른 사각형과의 공통 부분\"\n\n#: ../../irect.rst:17 dcc6834c254f4196bae3b0d0fab4ceb1\nmsgid \":meth:`IRect.intersects`\"\nmsgstr \":meth:`IRect.intersects`\"\n\n#: ../../irect.rst:17 4fa770702f6f48ddab2468a3aa6c9af1\nmsgid \"checks for non-empty intersection\"\nmsgstr \"비어 있지 않은 교집합 확인\"\n\n#: ../../irect.rst:18 1475b0caba85400c836e2e24795f6c17\nmsgid \":meth:`IRect.morph`\"\nmsgstr \":meth:`IRect.morph`\"\n\n#: ../../irect.rst:18 185917170ebf4403aecdb06acfbbdb30\nmsgid \"transform with a point and a matrix\"\nmsgstr \"점과 행렬로 변환\"\n\n#: ../../irect.rst:19 f89cd99364a04f8ead7c40c76d334821\nmsgid \":meth:`IRect.torect`\"\nmsgstr \":meth:`IRect.torect`\"\n\n#: ../../irect.rst:19 b73013e1bd9c44e28fb742260bdf0272\nmsgid \"matrix that transforms to another rectangle\"\nmsgstr \"다른 사각형으로 변환하는 행렬\"\n\n#: ../../irect.rst:20 15c7541278e84bb8ab6442f22f75170c\nmsgid \":meth:`IRect.norm`\"\nmsgstr \":meth:`IRect.norm`\"\n\n#: ../../irect.rst:20 5344860eef7b4ebca725b7087c5ba8b1\nmsgid \"the Euclidean norm\"\nmsgstr \"유클리드 노름\"\n\n#: ../../irect.rst:21 b4daf225e3034e7f9a2a7efdb849941e\nmsgid \":meth:`IRect.normalize`\"\nmsgstr \":meth:`IRect.normalize`\"\n\n#: ../../irect.rst:21 da5ac901945f432e951f9ccfbde9a1e3\nmsgid \"makes a rectangle finite\"\nmsgstr \"사각형을 유한하게 만듦\"\n\n#: ../../irect.rst:22 b57e345172924c9f92f87bdeee2b8b3b\nmsgid \":attr:`IRect.bottom_left`\"\nmsgstr \":attr:`IRect.bottom_left`\"\n\n#: ../../irect.rst:22 8de2dbecf83540c2845f6fea2e7ecc7b\nmsgid \"bottom left point, synonym *bl*\"\nmsgstr \"왼쪽 아래 점, 동의어 *bl*\"\n\n#: ../../irect.rst:23 78ac63f7fbd94c12a1bb2853a704964d\nmsgid \":attr:`IRect.bottom_right`\"\nmsgstr \":attr:`IRect.bottom_right`\"\n\n#: ../../irect.rst:23 694a01dd73e044ebb482e19a2d477c0f\nmsgid \"bottom right point, synonym *br*\"\nmsgstr \"오른쪽 아래 점, 동의어 *br*\"\n\n#: ../../irect.rst:24 c996baab80024480b6fa888ba3dae48d\nmsgid \":attr:`IRect.height`\"\nmsgstr \":attr:`IRect.height`\"\n\n#: ../../irect.rst:24 5cfaf1765add470395b5f7e3f9f3af09\nmsgid \"height of the rectangle\"\nmsgstr \"사각형의 높이\"\n\n#: ../../irect.rst:25 1b7c56522528489b89e2c3863d10335b\nmsgid \":attr:`IRect.is_empty`\"\nmsgstr \":attr:`IRect.is_empty`\"\n\n#: ../../irect.rst:25 0f3aefc4a2e247f4909ac53517ac039c\nmsgid \"whether rectangle is empty\"\nmsgstr \"사각형이 비어 있는지 여부\"\n\n#: ../../irect.rst:26 ebba20f4de03492090a9968e1e5dd412\nmsgid \":attr:`IRect.is_infinite`\"\nmsgstr \":attr:`IRect.is_infinite`\"\n\n#: ../../irect.rst:26 9c334c81b9b8415ba1053a2528ecb6ff\nmsgid \"whether rectangle is infinite\"\nmsgstr \"사각형이 무한한지 여부\"\n\n#: ../../irect.rst:27 5001534eb64f471d85cc5b89d7d974a1\nmsgid \":attr:`IRect.rect`\"\nmsgstr \":attr:`IRect.rect`\"\n\n#: ../../irect.rst:27 4b920cbbb5bd436ea5424583f46a971f\nmsgid \"the :ref:`Rect` equivalent\"\nmsgstr \":ref:`Rect` 와 동등한 것\"\n\n#: ../../irect.rst:28 73d2bc3e97c64f5facee96dfcf12b95c\nmsgid \":attr:`IRect.top_left`\"\nmsgstr \":attr:`IRect.top_left`\"\n\n#: ../../irect.rst:28 5806b5f7f43040419aec40fe1ec99f9b\nmsgid \"top left point, synonym *tl*\"\nmsgstr \"왼쪽 위 점, 동의어 *tl*\"\n\n#: ../../irect.rst:29 856082fe624c4dd4b8eeb24285c1a347\nmsgid \":attr:`IRect.top_right`\"\nmsgstr \":attr:`IRect.top_right`\"\n\n#: ../../irect.rst:29 0b985550b8ed4625a72796ab4c754952\nmsgid \"top_right point, synonym *tr*\"\nmsgstr \"오른쪽 위 점, 동의어 *tr*\"\n\n#: ../../irect.rst:30 5cc9d50c8cec4d768741a74eca8abf0b\nmsgid \":attr:`IRect.quad`\"\nmsgstr \":attr:`IRect.quad`\"\n\n#: ../../irect.rst:30 d135c468e28048fc921fdfdf4bbb13cf\nmsgid \":ref:`Quad` made from rectangle corners\"\nmsgstr \"사각형 모서리로 만든 :ref:`Quad`\"\n\n#: ../../irect.rst:31 022996f05c34445fa253e0e774b365a3\nmsgid \":attr:`IRect.width`\"\nmsgstr \":attr:`IRect.width`\"\n\n#: ../../irect.rst:31 0b36bdc4d3bf46afab89889318dc863a\nmsgid \"width of the rectangle\"\nmsgstr \"사각형의 너비\"\n\n#: ../../irect.rst:32 521608cb542c4976ba07f2f56d904ace\nmsgid \":attr:`IRect.x0`\"\nmsgstr \":attr:`IRect.x0`\"\n\n#: ../../irect.rst:32 d0964024870440a58844774693381ec8\nmsgid \"X-coordinate of the top left corner\"\nmsgstr \"왼쪽 위 모서리의 X 좌표\"\n\n#: ../../irect.rst:33 548e8fbd99a442b2b5a586073ff4f2ab\nmsgid \":attr:`IRect.x1`\"\nmsgstr \":attr:`IRect.x1`\"\n\n#: ../../irect.rst:33 30a1db52025e46e0be799ff23b4f2696\nmsgid \"X-coordinate of the bottom right corner\"\nmsgstr \"오른쪽 아래 모서리의 X 좌표\"\n\n#: ../../irect.rst:34 f81b38bd9fde4f54bed975e459d7a9ac\nmsgid \":attr:`IRect.y0`\"\nmsgstr \":attr:`IRect.y0`\"\n\n#: ../../irect.rst:34 2b16ddf8934849fbaab256d3d54e4363\nmsgid \"Y-coordinate of the top left corner\"\nmsgstr \"왼쪽 위 모서리의 Y 좌표\"\n\n#: ../../irect.rst:35 70d84d3ce7a34c4297a1e7700d3f7109\nmsgid \":attr:`IRect.y1`\"\nmsgstr \":attr:`IRect.y1`\"\n\n#: ../../irect.rst:35 b3e0e713d8d046a8968b780c0340f966\nmsgid \"Y-coordinate of the bottom right corner\"\nmsgstr \"오른쪽 아래 모서리의 Y 좌표\"\n\n#: ../../irect.rst:38 2edafd03825b4939bfe6472c41b08bcf\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../irect.rst:50 70995ff946be4d8d84849a0c0b6f16d3\nmsgid \"\"\n\"Overloaded constructors. Also see examples below and those for the \"\n\":ref:`Rect` class.\"\nmsgstr \"오버로드된 생성자. 아래 예제와 :ref:`Rect` 클래스의 예제도 참조하세요.\"\n\n#: ../../irect.rst:52 8f664a86d7374ec9bda83e6905b4e67b\nmsgid \"If another irect is specified, a **new copy** will be made.\"\nmsgstr \"다른 irect가 지정되면 **새 복사본** 이 만들어집니다.\"\n\n#: ../../irect.rst:54 6e6e21909c9c4ae3a9139bde73277f88\nmsgid \"\"\n\"If sequence is specified, it must be a Python sequence type of 4 numbers \"\n\"(see :ref:`SequenceTypes`). Non-integer numbers will be truncated, non-\"\n\"numeric values will raise an exception.\"\nmsgstr \"sequence가 지정되면 4개의 숫자로 구성된 Python 시퀀스 유형이어야 합니다(:ref:`SequenceTypes` 참조). 정수가 아닌 숫자는 잘리고, 숫자가 아닌 값은 예외를 발생시킵니다.\"\n\n#: ../../irect.rst:56 f9a414d271ee415fb26b8f0b142958b7\nmsgid \"The other parameters mean integer coordinates.\"\nmsgstr \"다른 매개변수는 정수 좌표를 의미합니다.\"\n\n#: ../../irect.rst:61 7c84bdc985c64c339d0548802f831996\nmsgid \"\"\n\"Calculates the area of the rectangle and, with no parameter, equals \"\n\"*abs(IRect)*. Like an empty rectangle, the area of an infinite rectangle \"\n\"is also zero.\"\nmsgstr \"사각형의 영역을 계산하며, 매개변수 없이는 *abs(IRect)* 와 같습니다. 빈 사각형과 마찬가지로 무한 사각형의 영역도 0입니다.\"\n\n#: ../../irect.rst 18e4b1fb1da640de88306538351ca10b\n#: 218364ce30ff4c0a9be4541c11fe1e9f 394c5a21898045d19dc3fca6edc763a7\n#: 489a707b54a24c2eb3edb81f8229ef4f 5b5047f52c7a458c90e239164e797307\n#: 6408eafe7a4547e980f6763bd4b559e1\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../irect.rst:63 63bea0a8781c48c49fac02eaeda867ce\nmsgid \"\"\n\"Specify required unit: respective squares of \\\"px\\\" (pixels, default), \"\n\"\\\"in\\\" (inches), \\\"cm\\\" (centimeters), or \\\"mm\\\" (millimeters).\"\nmsgstr \"필요한 단위 지정: \\\"px\\\"(픽셀, 기본값), \\\"in\\\"(인치), \\\"cm\\\"(센티미터) 또는 \\\"mm\\\"(밀리미터)의 각각의 제곱.\"\n\n#: ../../irect.rst 0f9fbd309a584cab995697cae68f899d\n#: 7c2bab6d8e594a5589e33354d18a1796 ba5dbf6b9e214071aaec6e290fac295f\n#: e6ca9e94a86f416a922d607f4943a5a3\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../irect.rst:69 5dc2badf5382432fa2d57f3db0e32119\nmsgid \"\"\n\"The intersection (common rectangular area) of the current rectangle and \"\n\"*ir* is calculated and replaces the current rectangle. If either \"\n\"rectangle is empty, the result is also empty. If either rectangle is \"\n\"infinite, the other one is taken as the result -- and hence also infinite\"\n\" if both rectangles were infinite.\"\nmsgstr \"현재 사각형과 *ir* 의 교집합(공통 사각형 영역)이 계산되어 현재 사각형을 대체합니다. 사각형 중 하나가 비어 있으면 결과도 비어 있습니다. 사각형 중 하나가 무한이면 다른 하나가 결과로 사용됩니다 -- 따라서 두 사각형이 모두 무한이면 결과도 무한입니다.\"\n\n#: ../../irect.rst:71 8af38038c172477b9e9af3e3b7862926\nmsgid \"Second rectangle.\"\nmsgstr \"두 번째 사각형.\"\n\n#: ../../irect.rst:75 e7214be906944cddbd77c8aecdd86d95\nmsgid \"\"\n\"Checks whether *x* is contained in the rectangle. It may be \"\n\":data:`rect_like`, :data:`point_like` or a number. If *x* is an empty \"\n\"rectangle, this is always true. Conversely, if the rectangle is empty \"\n\"this is always ``False``, if *x* is not an empty rectangle and not a \"\n\"number. If *x* is a number, it will be checked to be one of the four \"\n\"components. *x in irect* and *irect.contains(x)* are equivalent.\"\nmsgstr \"*x* 가 사각형에 포함되어 있는지 확인합니다. 이것은 :data:`rect_like`, :data:`point_like` 또는 숫자일 수 있습니다. *x* 가 빈 사각형이면 이것은 항상 true입니다. 반대로, 사각형이 비어 있으면 이것은 항상 ``False`` 입니다. *x* 가 빈 사각형이 아니고 숫자가 아닌 경우. *x* 가 숫자이면 4개의 구성 요소 중 하나인지 확인됩니다. *x in irect* 와 *irect.contains(x)* 는 동일합니다.\"\n\n#: ../../irect.rst:77 7cc8752befc847a9885e54e61f00faee\nmsgid \"the object to check.\"\nmsgstr \"확인할 객체.\"\n\n#: ../../irect.rst:84 41a07fef21a04ff9b1f1c59de07d83d1\nmsgid \"\"\n\"Checks whether the rectangle and the :data:`rect_like` \\\"r\\\" contain a \"\n\"common non-empty :ref:`IRect`. This will always be ``False`` if either is\"\n\" infinite or empty.\"\nmsgstr \"사각형과 :data:`rect_like` \\\"r\\\"이 공통의 비어 있지 않은 :ref:`IRect` 를 포함하는지 확인합니다. 둘 중 하나가 무한이거나 비어 있으면 이것은 항상 ``False`` 입니다.\"\n\n#: ../../irect.rst:86 aa8981e507b44374bd69c86ddf1f7541\nmsgid \"the rectangle to check.\"\nmsgstr \"확인할 사각형.\"\n\n#: ../../irect.rst:92 e0237b4a333a4949bae56a33d349416d\nmsgid \"New in version 1.19.3\"\nmsgstr \"버전 1.19.3에서 새로 추가됨\"\n\n#: ../../irect.rst:94 a8f435e24dcb48e2bdbca8838eca5764\nmsgid \"\"\n\"Compute the matrix which transforms this rectangle to a given one. See \"\n\":meth:`Rect.torect`.\"\nmsgstr \"이 사각형을 주어진 사각형으로 변환하는 행렬을 계산합니다. :meth:`Rect.torect` 를 참조하세요.\"\n\n#: ../../irect.rst:96 d1c97833dc404dbf9a4af4245c9a4541\nmsgid \"the target rectangle. Must not be empty or infinite.\"\nmsgstr \"대상 사각형. 비어 있거나 무한이 아니어야 합니다.\"\n\n#: ../../irect.rst:97 2f2d67d9571f465fa494157309add0d7\nmsgid \":ref:`Matrix`\"\nmsgstr \":ref:`Matrix`\"\n\n#: ../../irect.rst 75c56c65e0e64566a450b019b0cac229\n#: a68dd79a643440fbb2173c54bf9da905\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../irect.rst:98 c705e90002274a80b333b03348c54360\nmsgid \"\"\n\"a matrix `mat` such that `self * mat = rect`. Can for example be used to \"\n\"transform between the page and the pixmap coordinates.\"\nmsgstr \"`self * mat = rect` 가 되는 행렬 `mat`. 예를 들어 페이지와 픽셀맵 좌표 간 변환에 사용할 수 있습니다.\"\n\n#: ../../irect.rst:103 287c04b5d7f141ccb8d6ad779ecaeb1e\nmsgid \"New in version 1.17.0\"\nmsgstr \"버전 1.17.0에서 새로 추가됨\"\n\n#: ../../irect.rst:105 e37ea5bfcc8d496abb5f6decf903b78d\nmsgid \"Return a new quad after applying a matrix to it using a fixed point.\"\nmsgstr \"고정점을 사용하여 행렬을 적용한 후 새 quad를 반환합니다.\"\n\n#: ../../irect.rst:107 05bbb73520154a3181137a24fec1c86f\nmsgid \"the fixed point.\"\nmsgstr \"고정점.\"\n\n#: ../../irect.rst:108 b34bf6b64a6543358399eee20fed216a\nmsgid \"the matrix.\"\nmsgstr \"행렬.\"\n\n#: ../../irect.rst:109 c69142f99a804255b75e2eaf0d41597a\nmsgid \"\"\n\"a new :ref:`Quad`. This a wrapper of the same-named quad method. If \"\n\"infinite, the infinite quad is returned.\"\nmsgstr \"새 :ref:`Quad`. 이것은 동일한 이름의 quad 메서드의 래퍼입니다. 무한이면 무한 quad가 반환됩니다.\"\n\n#: ../../irect.rst:113 1cacf407916d48f49e0c36e73c9d2795\nmsgid \"New in version 1.16.0\"\nmsgstr \"버전 1.16.0에서 새로 추가됨\"\n\n#: ../../irect.rst:115 73cccdef3ba54c138d3c2949905823f1\nmsgid \"\"\n\"Return the Euclidean norm of the rectangle treated as a vector of four \"\n\"numbers.\"\nmsgstr \"4개의 숫자 벡터로 처리된 사각형의 유클리드 노름을 반환합니다.\"\n\n#: ../../irect.rst:119 1e3b3df827f64cdaa8f3e30d20539c21\nmsgid \"\"\n\"Make the rectangle finite. This is done by shuffling rectangle corners. \"\n\"After this, the bottom right corner will indeed be south-eastern to the \"\n\"top left one. See :ref:`Rect` for a more details.\"\nmsgstr \"사각형을 유한하게 만듭니다. 이것은 사각형 모서리를 재배치하여 수행됩니다. 이 작업 후, 오른쪽 아래 모서리는 실제로 왼쪽 위 모서리의 남동쪽이 됩니다. 자세한 내용은 :ref:`Rect` 를 참조하세요.\"\n\n#: ../../irect.rst:125 80fcd714078d4459b6446f7aa881ded8\nmsgid \"Equals *Point(x0, y0)*.\"\nmsgstr \"*Point(x0, y0)* 와 같습니다.\"\n\n#: ../../irect.rst 1185a0d53778409b8eb3beb582b64888\n#: 34743c436e9f444485fae4bae2ddb7f9 352aed9e86654ed0bfb3414c7c9f882a\n#: 451fc25fef3146ae8daf60b87a4dc707 49a176812ba94813ba64a196ce27e163\n#: 4f24b7a2272a40bcb5f1498431a01dff 6692646f4aef49ceb6263730817ee21f\n#: 89ab45a59a934aa39249ed1a86f07ee5 9d4221e962164e72948ac5d4b8d2703c\n#: b2290785b17149418de10d614a0f8eda c787e5b509d24f1b838ac1e121cfc685\n#: d95b0909ef3d4300a206cd4f2b8c8671 f6cdc81509354493aa34a01e5ebc06b4\n#: f97ab05a65224ade959a073fae8e16c2\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../irect.rst:127 ../../irect.rst:135 ../../irect.rst:143\n#: ../../irect.rst:151 88e60a9d15ad4d409f7a85722cd1cb9c\n#: c7e32fdd1a374a44979cdc28e388d038 fb5fa1bba9ab48979d23d8dd6744ca12\n#: fdc51db9a96f4153893929ddb8e95ee3\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../irect.rst:133 305506d4a8894b98b370bfdaf51af233\nmsgid \"Equals *Point(x1, y0)*.\"\nmsgstr \"*Point(x1, y0)* 와 같습니다.\"\n\n#: ../../irect.rst:141 9af3c12519684f28bb4bc50d612e4372\nmsgid \"Equals *Point(x0, y1)*.\"\nmsgstr \"*Point(x0, y1)* 와 같습니다.\"\n\n#: ../../irect.rst:149 ae11bdfc7226476aac26a17b08ad9204\nmsgid \"Equals *Point(x1, y1)*.\"\nmsgstr \"*Point(x1, y1)* 와 같습니다.\"\n\n#: ../../irect.rst:155 6b6c7c24528e4d028bb599bcaba2d291\nmsgid \"The :ref:`Rect` with the same coordinates as floats.\"\nmsgstr \"float와 동일한 좌표를 가진 :ref:`Rect`.\"\n\n#: ../../irect.rst:157 07b31a4170c647d1ae20c438ea29c332\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../irect.rst:161 6d942227a8804d80be71085d59471e1f\nmsgid \"The quadrilateral *Quad(irect.tl, irect.tr, irect.bl, irect.br)*.\"\nmsgstr \"사각형 *Quad(irect.tl, irect.tr, irect.bl, irect.br)*.\"\n\n#: ../../irect.rst:163 21c9866abaed4b9ea6806095673297f4\nmsgid \":ref:`Quad`\"\nmsgstr \":ref:`Quad`\"\n\n#: ../../irect.rst:167 aa41fcfcf80642958f591e2014a05804\nmsgid \"Contains the width of the bounding box. Equals *abs(x1 - x0)*.\"\nmsgstr \"경계 상자의 너비를 포함합니다. *abs(x1 - x0)* 와 같습니다.\"\n\n#: ../../irect.rst:169 ../../irect.rst:175 ../../irect.rst:181\n#: ../../irect.rst:187 ../../irect.rst:193 ../../irect.rst:199\n#: 36d28775650b4893b50c1bb5ecf9c14e 65120d228f2f4ab28e5fa51eb06d8761\n#: a72fd244eafd454380cfe3bc5def6325 f2ef5e017dda4f76ab39cff8b6079d88\n#: fa70673340164af19d538be4a10b59ad fc10d7f00d79406db00d1066e4567571\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../irect.rst:173 e896ac73b5c64e75b7724b41502abd00\nmsgid \"Contains the height of the bounding box. Equals *abs(y1 - y0)*.\"\nmsgstr \"경계 상자의 높이를 포함합니다. *abs(y1 - y0)* 와 같습니다.\"\n\n#: ../../irect.rst:179 29e02c90a309472484e82207f4e2bb94\nmsgid \"X-coordinate of the left corners.\"\nmsgstr \"왼쪽 모서리의 X 좌표.\"\n\n#: ../../irect.rst:185 ec2198ff697e420d9c05f93f973367bb\nmsgid \"Y-coordinate of the top corners.\"\nmsgstr \"위쪽 모서리의 Y 좌표.\"\n\n#: ../../irect.rst:191 e02641fa0cb443a58d8b6f6d447edb7a\nmsgid \"X-coordinate of the right corners.\"\nmsgstr \"오른쪽 모서리의 X 좌표.\"\n\n#: ../../irect.rst:197 2e367ece51d84b1280d4ec05cc038c6a\nmsgid \"Y-coordinate of the bottom corners.\"\nmsgstr \"아래쪽 모서리의 Y 좌표.\"\n\n#: ../../irect.rst:203 900a2545643f4623905b338b7edefd8b\nmsgid \"``True`` if rectangle is infinite, ``False`` otherwise.\"\nmsgstr \"사각형이 무한이면 ``True``, 그렇지 않으면 ``False``.\"\n\n#: ../../irect.rst:205 ../../irect.rst:211 4c1a21a29dfe4414ad6992b3dcc0b117\n#: aec6fc0ebb874b20bfb1a90a68a30dcc\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../irect.rst:209 877573fb6317435ca1b1a73c24606949\nmsgid \"``True`` if rectangle is empty, ``False`` otherwise.\"\nmsgstr \"사각형이 비어 있으면 ``True``, 그렇지 않으면 ``False``.\"\n\n#: ../../irect.rst:216 7cc608bcd141490a9f473438421895b4\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"이 클래스는 Python 시퀀스 프로토콜을 따르므로 구성 요소는 인덱스를 통해 액세스할 수도 있습니다. :ref:`SequenceTypes` 도 참조하세요.\"\n\n#: ../../irect.rst:217 a3c01f53c9ef4d5eb1b84f26294b538b\nmsgid \"\"\n\"Rectangles can be used with arithmetic operators -- see chapter \"\n\":ref:`Algebra`.\"\nmsgstr \"사각형은 산술 연산자와 함께 사용할 수 있습니다 -- :ref:`Algebra` 장을 참조하세요.\"\n\n#: ../../footer.rst:46 512cd6db01a142258a5b31acbcb8a187\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/link.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f61795372a914927a8bb8d2bc7871cd0\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 b6c88945ca3e433796ac09242bcafb92\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 f29d92f907804c35aff5269176052c3a\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../link.rst:7 a2ac83b843064d1690148214e4e62cab\nmsgid \"Link\"\nmsgstr \"Link\"\n\n#: ../../link.rst:8 e3ca00a770434f0896694fc8c2dc8e8d\nmsgid \"\"\n\"Represents a pointer to somewhere (this document, other documents, the \"\n\"internet). Links exist per document page, and they are forward-chained to\"\n\" each other, starting from an initial link which is accessible by the \"\n\":attr:`Page.first_link` property.\"\nmsgstr \"어딘가(이 문서, 다른 문서, 인터넷)를 가리키는 포인터를 나타냅니다. 링크는 문서 페이지마다 존재하며, :attr:`Page.first_link` 속성으로 접근할 수 있는 초기 링크에서 시작하여 서로 순방향으로 연결됩니다.\"\n\n#: ../../link.rst:10 55f719cc6bfa4e1dbdf8bba301fe4110\nmsgid \"\"\n\"There is a parent-child relationship between a link and its page. If the \"\n\"page object becomes unusable (closed document, any document structure \"\n\"change, etc.), then so does every of its existing link objects -- an \"\n\"exception is raised saying that the object is \\\"orphaned\\\", whenever a \"\n\"link property or method is accessed.\"\nmsgstr \"링크와 해당 페이지 사이에는 부모-자식 관계가 있습니다. 페이지 객체가 사용 불가능해지면(문서 닫힘, 문서 구조 변경 등) 해당 페이지의 모든 기존 링크 객체도 사용 불가능해집니다 -- 링크 속성이나 메서드에 접근할 때마다 객체가 \\\"고아\\\" 상태라는 예외가 발생합니다.\"\n\n#: ../../link.rst:13 a4193e607a9145218508afeabe0b4c2e\nmsgid \"**Attribute**\"\nmsgstr \"**속성**\"\n\n#: ../../link.rst:13 af32ee5e21764bdab065a26b66230ad7\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../link.rst:15 9f4a2508022d463a93f91c3406c08ab1\nmsgid \":meth:`Link.set_border`\"\nmsgstr \":meth:`Link.set_border`\"\n\n#: ../../link.rst:15 6a3d66278e124793bee041fb82bd823a\nmsgid \"modify border properties\"\nmsgstr \"테두리 속성 수정\"\n\n#: ../../link.rst:16 ca6e0ec1d2e5409894887ce466dd9c14\nmsgid \":meth:`Link.set_colors`\"\nmsgstr \":meth:`Link.set_colors`\"\n\n#: ../../link.rst:16 ebd1bee66f204d6bbd8e54086d79f55f\nmsgid \"modify color properties\"\nmsgstr \"색상 속성 수정\"\n\n#: ../../link.rst:17 111ec52301b74aac956f980fdfcaf35a\nmsgid \":meth:`Link.set_flags`\"\nmsgstr \":meth:`Link.set_flags`\"\n\n#: ../../link.rst:17 502cb7c9642642f293df7c93f92a2fd6\nmsgid \"modify link flags\"\nmsgstr \"링크 플래그 수정\"\n\n#: ../../link.rst:18 489cb6995acd4a8f9459e84f8e29671e\nmsgid \":attr:`Link.border`\"\nmsgstr \":attr:`Link.border`\"\n\n#: ../../link.rst:18 c61da7b8553c4f35b0de3f5b60a3f9e9\nmsgid \"border characteristics\"\nmsgstr \"테두리 특성\"\n\n#: ../../link.rst:19 5a1564c23ae44405bedf7e18c649d130\nmsgid \":attr:`Link.colors`\"\nmsgstr \":attr:`Link.colors`\"\n\n#: ../../link.rst:19 01a00d5d838a47e3964be170b4b2aca4\nmsgid \"border line color\"\nmsgstr \"테두리 선 색상\"\n\n#: ../../link.rst:20 df6c0ef2a13f47b28ec2cb2b88f5decf\nmsgid \":attr:`Link.dest`\"\nmsgstr \":attr:`Link.dest`\"\n\n#: ../../link.rst:20 2d7f3af920794e158f2472af28c69a4c\nmsgid \"points to destination details\"\nmsgstr \"대상 세부 정보를 가리킴\"\n\n#: ../../link.rst:21 c858c9ac8f3148deb29f863be9b27de6\nmsgid \":attr:`Link.is_external`\"\nmsgstr \":attr:`Link.is_external`\"\n\n#: ../../link.rst:21 df77568aba6c4d24babf4d0d97c19d54\nmsgid \"checks if the link is an external destination\"\nmsgstr \"링크가 외부 대상인지 확인\"\n\n#: ../../link.rst:22 09dcfdc3988d4ab0bb1b56be72905b8a\nmsgid \":attr:`Link.flags`\"\nmsgstr \":attr:`Link.flags`\"\n\n#: ../../link.rst:22 0fb0e2e7ae3944e6aa9886cccd29ba57\nmsgid \"link annotation flags\"\nmsgstr \"링크 주석 플래그\"\n\n#: ../../link.rst:23 8b3432b79e804e8a8467829f70a5504d\nmsgid \":attr:`Link.next`\"\nmsgstr \":attr:`Link.next`\"\n\n#: ../../link.rst:23 482fbb3ecd0442a8bb0a43de75382822\nmsgid \"points to next link\"\nmsgstr \"다음 링크를 가리킴\"\n\n#: ../../link.rst:24 7baaa58c6b184381b9aba640162dfe9b\nmsgid \":attr:`Link.rect`\"\nmsgstr \":attr:`Link.rect`\"\n\n#: ../../link.rst:24 0e0788e18be94b5784f4c8a3d0c8590b\nmsgid \"clickable area in untransformed coordinates\"\nmsgstr \"변환되지 않은 좌표에서 클릭 가능한 영역\"\n\n#: ../../link.rst:25 e8df77ad16fe4114a80eff4b8240b89c\nmsgid \":attr:`Link.uri`\"\nmsgstr \":attr:`Link.uri`\"\n\n#: ../../link.rst:25 502ec4ee36504004bd39daf295626fbc\nmsgid \"link destination\"\nmsgstr \"링크 대상\"\n\n#: ../../link.rst:26 d17729b40a80480caa127d310a3450c2\nmsgid \":attr:`Link.xref`\"\nmsgstr \":attr:`Link.xref`\"\n\n#: ../../link.rst:26 678f619f97a244a0a539107e973f3986\nmsgid \":data:`xref` number of the entry\"\nmsgstr \"항목의 :data:`xref` 번호\"\n\n#: ../../link.rst:29 f76011eb2dd2424bba83dfb242a73eb3\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../link.rst:35 e01c9234e1b24ef4a42fe98da9e3b5b8\nmsgid \"PDF only: Change border width and dashing properties.\"\nmsgstr \"PDF 전용: 테두리 너비 및 점선 속성 변경.\"\n\n#: ../../link.rst:37 00c3ab6e292048be95d9d1e26a0319ce\nmsgid \"\"\n\"*(Changed in version 1.16.9)* Allow specification without using a \"\n\"dictionary. The direct parameters are used if *border* is not a \"\n\"dictionary.\"\nmsgstr \"*(버전 1.16.9에서 변경됨)* 딕셔너리를 사용하지 않고 지정을 허용합니다. *border* 가 딕셔너리가 아니면 직접 매개변수가 사용됩니다.\"\n\n#: ../../link.rst 00e8660458ca4df49c759966985d7ccf\n#: 4560ff2f8db3457ea45107e432c3e7ee\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../link.rst:39 9210f90061d54d20bb40b7811a63e193\nmsgid \"\"\n\"a dictionary as returned by the :attr:`border` property, with keys \"\n\"*\\\"width\\\"* (*float*), *\\\"style\\\"* (*str*) and *\\\"dashes\\\"* (*sequence*).\"\n\" Omitted keys will leave the resp. property unchanged. To e.g. remove \"\n\"dashing use: *\\\"dashes\\\": []*. If dashes is not an empty sequence, \"\n\"\\\"style\\\" will automatically be set to \\\"D\\\" (dashed).\"\nmsgstr \":attr:`border` 속성에 의해 반환되는 딕셔너리로, 키 *\\\"width\\\"* (*float*), *\\\"style\\\"* (*str*) 및 *\\\"dashes\\\"* (*sequence*)를 가집니다. 생략된 키는 해당 속성을 변경하지 않습니다. 예를 들어 점선을 제거하려면: *\\\"dashes\\\": []* 를 사용하세요. dashes가 빈 시퀀스가 아니면 \\\"style\\\"이 자동으로 \\\"D\\\"(점선)로 설정됩니다.\"\n\n#: ../../link.rst:41 ../../link.rst:42 ../../link.rst:43 ../../link.rst:54\n#: 0f652b3dc1754811b0fd20b619f58221 2a2addfc429e4856a5b9d38ccc565155\n#: 4b687a46789e46148cf496194b0b604d 6666190d7e824106bd77ad41db6f0b41\nmsgid \"see above.\"\nmsgstr \"위를 참조하세요.\"\n\n#: ../../link.rst:47 8657681111dc457788d3482a31e7fd86\nmsgid \"PDF only: Changes the \\\"stroke\\\" color.\"\nmsgstr \"PDF 전용: \\\"stroke\\\" 색상 변경.\"\n\n#: ../../link.rst:49 a9f5e77a06364c1a8e73536a14d852c9\nmsgid \"\"\n\"In PDF, links are a subtype of annotations technically and **do not \"\n\"support fill colors**. However, to keep a consistent API, we do allow \"\n\"specifying a `fill=` parameter like with all annotations, which will be \"\n\"ignored with a warning.\"\nmsgstr \"PDF에서 링크는 기술적으로 주석의 하위 유형이며 **채우기 색상을 지원하지 않습니다**. 그러나 일관된 API를 유지하기 위해 모든 주석과 마찬가지로 `fill=` 매개변수를 지정할 수 있지만 경고와 함께 무시됩니다.\"\n\n#: ../../link.rst:51 2f9965cf55cc4fa69cb5dc350c17ad09\nmsgid \"\"\n\"*(Changed in version 1.16.9)* Allow colors to be directly set. These \"\n\"parameters are used if *colors* is not a dictionary.\"\nmsgstr \"*(버전 1.16.9에서 변경됨)* 색상을 직접 설정할 수 있도록 허용합니다. *colors* 가 딕셔너리가 아니면 이 매개변수가 사용됩니다.\"\n\n#: ../../link.rst:53 d1bb1f867e02444ebfbb4a94573959bf\nmsgid \"\"\n\"a dictionary containing color specifications. For accepted dictionary \"\n\"keys and values see below. The most practical way should be to first make\"\n\" a copy of the *colors* property and then modify this dictionary as \"\n\"required.\"\nmsgstr \"색상 사양을 포함하는 딕셔너리. 허용되는 딕셔너리 키와 값은 아래를 참조하세요. 가장 실용적인 방법은 먼저 *colors* 속성의 복사본을 만든 다음 필요에 따라 이 딕셔너리를 수정하는 것입니다.\"\n\n#: ../../link.rst:58 ../../link.rst:65 986b15f24ea54de580c0c662299fe12d\n#: bb27f8be006d4918acba2be1f77e4ee4\nmsgid \"*New in v1.18.16*\"\nmsgstr \"*v1.18.16에서 새로 추가됨*\"\n\n#: ../../link.rst:60 df2a5f5ab5654a15a59600eb3536f242\nmsgid \"\"\n\"Set the PDF `/F` property of the link annotation. See \"\n\":meth:`Annot.set_flags` for details. If not a PDF, this method is a no-\"\n\"op.\"\nmsgstr \"링크 주석의 PDF `/F` 속성을 설정합니다. 자세한 내용은 :meth:`Annot.set_flags` 를 참조하세요. PDF가 아니면 이 메서드는 아무 작업도 수행하지 않습니다.\"\n\n#: ../../link.rst:67 e8cfa36461074dacb4c30dea81b83979\nmsgid \"\"\n\"Return the link annotation flags, an integer (see :attr:`Annot.flags` for\"\n\" details). Zero if not a PDF.\"\nmsgstr \"링크 주석 플래그를 반환합니다. 정수입니다(자세한 내용은 :attr:`Annot.flags` 참조). PDF가 아니면 0입니다.\"\n\n#: ../../link.rst:72 004a6c2778ec462eb43f612d6513adde\nmsgid \"\"\n\"Meaningful for PDF only: A dictionary of two tuples of floats in range `0\"\n\" <= float <= 1` specifying the *stroke* and the interior (*fill*) colors.\"\n\" If not a PDF, ``None`` is returned. As mentioned above, the fill color \"\n\"is always `None` for links. The stroke color is used for the border of \"\n\"the link rectangle. The length of the tuple implicitly determines the \"\n\"colorspace: 1 = GRAY, 3 = RGB, 4 = CMYK. So `(1.0, 0.0, 0.0)` stands for \"\n\"RGB color red. The value of each float *f* is mapped to the integer value\"\n\" *i* in range 0 to 255 via the computation *f = i / 255*.\"\nmsgstr \"PDF에만 의미가 있음: `0 <= float <= 1` 범위의 두 float 튜플 딕셔너리로 *stroke* 및 내부(*fill*) 색상을 지정합니다. PDF가 아니면 ``None`` 이 반환됩니다. 위에서 언급한 대로 링크의 채우기 색상은 항상 `None` 입니다. stroke 색상은 링크 사각형의 테두리에 사용됩니다. 튜플의 길이는 암시적으로 색 공간을 결정합니다: 1 = GRAY, 3 = RGB, 4 = CMYK. 따라서 `(1.0, 0.0, 0.0)` 은 RGB 색상 빨강을 나타냅니다. 각 float *f* 의 값은 계산 *f = i / 255* 를 통해 0에서 255 범위의 정수 값 *i* 에 매핑됩니다.\"\n\n#: ../../link.rst 114960dc31e14f46bd090eb9728c77c2\n#: 4fbd9899261b4dcebb25e7595add5438\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../link.rst:78 3cbc8f0469d241929e34c352e5745bc1\nmsgid \"\"\n\"Meaningful for PDF only: A dictionary containing border characteristics. \"\n\"It will be ``None`` for non-PDFs and an empty dictionary if no border \"\n\"information exists. The following keys can occur:\"\nmsgstr \"PDF에만 의미가 있음: 테두리 특성을 포함하는 딕셔너리. 비-PDF의 경우 ``None`` 이고 테두리 정보가 없으면 빈 딕셔너리입니다. 다음 키가 나타날 수 있습니다:\"\n\n#: ../../link.rst:80 c1ab318b501a47688d2fc6b081566c84\nmsgid \"\"\n\"*width* -- a float indicating the border thickness in points. The value \"\n\"is -1.0 if no width is specified.\"\nmsgstr \"*width* -- 포인트 단위의 테두리 두께를 나타내는 float. 너비가 지정되지 않으면 값은 -1.0입니다.\"\n\n#: ../../link.rst:82 ee2605f02f554ef69ce01c7ce647b5c6\nmsgid \"\"\n\"*dashes* -- a sequence of integers specifying a line dash pattern. *[]* \"\n\"means no dashes, *[n]* means equal on-off lengths of *n* points, longer \"\n\"lists will be interpreted as specifying alternating on-off length values.\"\n\" See the :ref:`AdobeManual` page 126 for more detail.\"\nmsgstr \"*dashes* -- 선 점선 패턴을 지정하는 정수 시퀀스. *[]* 는 점선 없음을 의미하고, *[n]* 는 *n* 포인트의 동일한 on-off 길이를 의미하며, 더 긴 목록은 교대로 on-off 길이 값을 지정하는 것으로 해석됩니다. 자세한 내용은 :ref:`AdobeManual` 126페이지를 참조하세요.\"\n\n#: ../../link.rst:84 b4b27c2220234e3c9f0da44681173211\nmsgid \"\"\n\"*style* -- 1-byte border style: *S* (Solid) = solid rectangle surrounding\"\n\" the annotation, *D* (Dashed) = dashed rectangle surrounding the link, \"\n\"the dash pattern is specified by the *dashes* entry, *B* (Beveled) = a \"\n\"simulated embossed rectangle that appears to be raised above the surface \"\n\"of the page, *I* (Inset) = a simulated engraved rectangle that appears to\"\n\" be recessed below the surface of the page, *U* (Underline) = a single \"\n\"line along the bottom of the annotation rectangle.\"\nmsgstr \"*style* -- 1바이트 테두리 스타일: *S* (Solid) = 주석을 둘러싸는 실선 사각형, *D* (Dashed) = 링크를 둘러싸는 점선 사각형, 점선 패턴은 *dashes* 항목으로 지정됨, *B* (Beveled) = 페이지 표면 위로 올라온 것처럼 보이는 시뮬레이션된 볼록한 사각형, *I* (Inset) = 페이지 표면 아래로 들어간 것처럼 보이는 시뮬레이션된 각인된 사각형, *U* (Underline) = 주석 사각형 하단을 따라가는 단일 선.\"\n\n#: ../../link.rst:90 052b846ac7bf4348bb05373fe93c7f66\nmsgid \"The area that can be clicked in untransformed coordinates.\"\nmsgstr \"변환되지 않은 좌표에서 클릭할 수 있는 영역.\"\n\n#: ../../link.rst 278b7dd100364049a9a0f8a608dfe200\n#: 5b8584b479504935a82003972fba8296 91cdff8cf9e5471f8c8c7ebd105a9694\n#: 92b24b7f7b1d434bab261bfbfc850087 a7dd1626e8024de0a8394b7ac58b00dc\n#: b3fc6b24eede40c5a5ff68c9552eb5d3\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../link.rst:92 b6cde768d2b448d3918fcc2629f09e45\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../link.rst:96 9cbf66013e07421da625a37f62f421af\nmsgid \"\"\n\"A bool specifying whether the link target is outside of the current \"\n\"document.\"\nmsgstr \"링크 대상이 현재 문서 외부에 있는지 여부를 지정하는 bool입니다.\"\n\n#: ../../link.rst:98 3bf7415e10f64b17a00d1894d75abd4d\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../link.rst:102 7722949c512e472da9f50b38d703a9f0\nmsgid \"\"\n\"A string specifying the link target. The meaning of this property should \"\n\"be evaluated in conjunction with property `is_external`:\"\nmsgstr \"링크 대상을 지정하는 문자열입니다. 이 속성의 의미는 `is_external` 속성과 함께 평가해야 합니다:\"\n\n#: ../../link.rst:106 8a85f4db122a4632acda8a79099ab276\nmsgid \"\"\n\"`is_external` is true: `uri` points to some target outside the current \"\n\"PDF, which may be an internet resource (`uri` starts with ``http://`` or \"\n\"similar), another file (`uri` starts with \\\"file:\\\" or \\\"file://\\\") or \"\n\"some other service like an e-mail address (`uri` starts with \"\n\"``mailto:``).\"\nmsgstr \"`is_external` 이 true: `uri` 는 현재 PDF 외부의 대상을 가리키며, 인터넷 리소스(`uri` 가 ``http://`` 또는 유사한 것으로 시작), 다른 파일(`uri` 가 \\\"file:\\\" 또는 \\\"file://\\\"로 시작) 또는 이메일 주소와 같은 기타 서비스(`uri` 가 ``mailto:`` 로 시작)일 수 있습니다.\"\n\n#: ../../link.rst:112 aa85a467ae894a49801187d31376da42\nmsgid \"\"\n\"`is_external` is false: `uri` will be `None` or point to an internal \"\n\"location. In case of PDF documents, this should either be *#nnnn* to \"\n\"indicate a 1-based (!) page number *nnnn*, or a named location. The \"\n\"format varies for other document types, for example \"\n\"\\\"../FixedDoc.fdoc#PG_2_LNK_1\\\" for page number 2 (1-based) in an XPS \"\n\"document.\"\nmsgstr \"`is_external` 이 false: `uri` 는 `None` 이거나 내부 위치를 가리킵니다. PDF 문서의 경우, 이것은 1부터 시작하는(!) 페이지 번호 *nnnn* 을 나타내는 *#nnnn* 이거나 이름이 지정된 위치여야 합니다. 형식은 다른 문서 유형에 따라 다릅니다. 예를 들어 XPS 문서의 페이지 번호 2(1부터 시작)의 경우 \\\"../FixedDoc.fdoc#PG_2_LNK_1\\\"입니다.\"\n\n#: ../../link.rst:119 169f5e74d4d248acaf39fe0e78f64c8c\nmsgid \"str\"\nmsgstr \"str\"\n\n#: ../../link.rst:123 b896a257acf94231987101c53ec2a3ee\nmsgid \"An integer specifying the PDF :data:`xref`. Zero if not a PDF.\"\nmsgstr \"PDF :data:`xref` 를 지정하는 정수입니다. PDF가 아니면 0입니다.\"\n\n#: ../../link.rst:125 0a7066aaee624b82bdccf14c63cbeb5a\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../link.rst:129 3d5c16c89c01444b862176bdfbe17241\nmsgid \"The next link or ``None``.\"\nmsgstr \"다음 링크 또는 ``None``.\"\n\n#: ../../link.rst:131 aeff8c341c48462292eba7bef8c73eeb\nmsgid \"*Link*\"\nmsgstr \"*Link*\"\n\n#: ../../link.rst:135 bc9d0756ee4e4e0c8f03bde2e4a58991\nmsgid \"The link destination details object.\"\nmsgstr \"링크 대상 세부 정보 객체.\"\n\n#: ../../link.rst:137 9b93286e15e64f8f9bc75c6e2a1305bb\nmsgid \":ref:`linkDest`\"\nmsgstr \":ref:`linkDest`\"\n\n#: ../../footer.rst:46 74c752369b354d73af2f7c11e7b19f1f\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/linkdest.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 d57c78d809254da4835f2c2e979be9bf\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 a9ed1908021a4b46ac047f81afa8fd03\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 c383513223a942bea5aee21e50d9b3c2\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../linkdest.rst:7 6f11bc05a63745008c94dda126160905\nmsgid \"linkDest\"\nmsgstr \"linkDest\"\n\n#: ../../linkdest.rst:8 0b3bb1ecff3b4317aaaabd080edb44e8\nmsgid \"\"\n\"Class representing the `dest` property of an outline entry or a link. \"\n\"Describes the destination to which such entries point.\"\nmsgstr \"개요 항목 또는 링크의 `dest` 속성을 나타내는 클래스입니다. 이러한 항목이 가리키는 대상을 설명합니다.\"\n\n#: ../../linkdest.rst:10 c02022acb8024740b76912d137b9899a\nmsgid \"\"\n\"Up to MuPDF v1.9.0 this class existed inside MuPDF and was dropped in \"\n\"version 1.10.0. For backward compatibility, PyMuPDF is still maintaining \"\n\"it, although some of its attributes are no longer backed by data actually\"\n\" available via MuPDF.\"\nmsgstr \"MuPDF v1.9.0까지 이 클래스는 MuPDF 내부에 존재했으며 버전 1.10.0에서 제거되었습니다. 하위 호환성을 위해 PyMuPDF는 여전히 이를 유지하고 있지만, 일부 속성은 더 이상 MuPDF를 통해 실제로 사용 가능한 데이터로 지원되지 않습니다.\"\n\n#: ../../linkdest.rst:13 192d952a7df04c4cb3800c0c6f8b6f99\nmsgid \"**Attribute**\"\nmsgstr \"**속성**\"\n\n#: ../../linkdest.rst:13 71e9a555483944ff92a77001b3d42f49\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../linkdest.rst:15 3ccecaa069ff4226b5794d23afcb6f38\nmsgid \":attr:`linkDest.dest`\"\nmsgstr \":attr:`linkDest.dest`\"\n\n#: ../../linkdest.rst:15 b0182cc143894b7397921f5e6efe2ad8\nmsgid \"destination\"\nmsgstr \"대상\"\n\n#: ../../linkdest.rst:16 94cfb537b2034d95b10812ca82ab0904\nmsgid \":attr:`linkDest.fileSpec`\"\nmsgstr \":attr:`linkDest.fileSpec`\"\n\n#: ../../linkdest.rst:16 8c2d54d1045244c2b2c7be7fe3aff94d\nmsgid \"file specification (path, filename)\"\nmsgstr \"파일 사양(경로, 파일명)\"\n\n#: ../../linkdest.rst:17 c9d87d20c7e34bdcba3e15b52958cc2d\nmsgid \":attr:`linkDest.flags`\"\nmsgstr \":attr:`linkDest.flags`\"\n\n#: ../../linkdest.rst:17 8eab10462616444ca0c07141a25997d1\nmsgid \"descriptive flags\"\nmsgstr \"설명 플래그\"\n\n#: ../../linkdest.rst:18 d3ee936fbf09442985e09022f97346a0\nmsgid \":attr:`linkDest.isMap`\"\nmsgstr \":attr:`linkDest.isMap`\"\n\n#: ../../linkdest.rst:18 6b10fcc4b7024312b80879a046dde7a1\nmsgid \"is this a MAP?\"\nmsgstr \"이것이 MAP입니까?\"\n\n#: ../../linkdest.rst:19 ebd316b494c341949404a1013a0c3716\nmsgid \":attr:`linkDest.isUri`\"\nmsgstr \":attr:`linkDest.isUri`\"\n\n#: ../../linkdest.rst:19 a3d669f5e1b24a5f8817d790b4dfce24\nmsgid \"is this a URI?\"\nmsgstr \"이것이 URI입니까?\"\n\n#: ../../linkdest.rst:20 5f79bf4078184f17aed9690ec43a9e28\nmsgid \":attr:`linkDest.kind`\"\nmsgstr \":attr:`linkDest.kind`\"\n\n#: ../../linkdest.rst:20 da66f3a913634b5197318056882d489c\nmsgid \"kind of destination\"\nmsgstr \"대상 유형\"\n\n#: ../../linkdest.rst:21 a9f255b3361541bbbc58d4b524552874\nmsgid \":attr:`linkDest.lt`\"\nmsgstr \":attr:`linkDest.lt`\"\n\n#: ../../linkdest.rst:21 8696049fe5f14b5e898e8894961de97a\nmsgid \"top left coordinates\"\nmsgstr \"왼쪽 위 좌표\"\n\n#: ../../linkdest.rst:22 e69848891b564b91b789e415193e2599\nmsgid \":attr:`linkDest.named`\"\nmsgstr \":attr:`linkDest.named`\"\n\n#: ../../linkdest.rst:22 3e9e08f3e3f646e39ea6939d38f92ea7\nmsgid \"name if named destination\"\nmsgstr \"이름이 지정된 대상인 경우 이름\"\n\n#: ../../linkdest.rst:23 e55ceb925d38472da5faac759c6c1f39\nmsgid \":attr:`linkDest.newWindow`\"\nmsgstr \":attr:`linkDest.newWindow`\"\n\n#: ../../linkdest.rst:23 9da63baa93924bb3810f8b14cd3c6f08\nmsgid \"name of new window\"\nmsgstr \"새 창 이름\"\n\n#: ../../linkdest.rst:24 3133f4f237c54427b5f38bb9e4ee0870\nmsgid \":attr:`linkDest.page`\"\nmsgstr \":attr:`linkDest.page`\"\n\n#: ../../linkdest.rst:24 4e9fb63bb49e45838a66455c5ee65ae9\nmsgid \"page number\"\nmsgstr \"페이지 번호\"\n\n#: ../../linkdest.rst:25 007c86d9023d40e5bb0e4e5b93d802dd\nmsgid \":attr:`linkDest.rb`\"\nmsgstr \":attr:`linkDest.rb`\"\n\n#: ../../linkdest.rst:25 6eeedea7ed6145018567f08541f89224\nmsgid \"bottom right coordinates\"\nmsgstr \"오른쪽 아래 좌표\"\n\n#: ../../linkdest.rst:26 748aaf1c62434b01970667a3b3033d87\nmsgid \":attr:`linkDest.uri`\"\nmsgstr \":attr:`linkDest.uri`\"\n\n#: ../../linkdest.rst:26 7ad45d4c5bba4618bf6a5964e2571854\nmsgid \"URI\"\nmsgstr \"URI\"\n\n#: ../../linkdest.rst:29 fb8d1e50444c4cd08673dbee32636872\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../linkdest.rst:35 899ccd076a8a486087261429c87c1e49\nmsgid \"\"\n\"Target destination name if :attr:`linkDest.kind` is :data:`LINK_GOTOR` \"\n\"and :attr:`linkDest.page` is *-1*.\"\nmsgstr \":attr:`linkDest.kind` 가 :data:`LINK_GOTOR` 이고 :attr:`linkDest.page` 가 *-1* 인 경우 대상 이름.\"\n\n#: ../../linkdest.rst 04ee6c88174848ac8bab86ad2416c0a3\n#: 1464a774b9d54e0e990c6ebe2da4c6e8 473cf52ca9cf41cf99038dd29cc31c14\n#: 4dd16d523ebf4121a0e9a79f97cd9d11 63054de214a4471fbb6d1ab8f3b7b573\n#: 670cff5c69074cc6a2bc4689ab5393c9 9ddddca25b3d4f75bcfa839cc96b9a21\n#: b44b0784cdb246cfa94a0a2059b94018 b58c6c51b75c480294d940a64089a608\n#: bb350508308a4d99acad49e328495653 e224131ce0fe4fd0a1df5250c0487ca4\n#: e5f8f3174dfc4ff997a1743196c9e4d6\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../linkdest.rst:37 ../../linkdest.rst:43 ../../linkdest.rst:79\n#: ../../linkdest.rst:103 581dcd6df6224fbe8745cc8ab2b07a91\n#: a81ed9ea22224e639705fc5e3839af2f d3182a558fb849428de433c60a1bdad7\n#: f69f354db0e14b7ea4880f6b4e0aa8ff\nmsgid \"str\"\nmsgstr \"str\"\n\n#: ../../linkdest.rst:41 90baaf8b636c4ee591f82da46afacac7\nmsgid \"\"\n\"Contains the filename and path this link points to, if \"\n\":attr:`linkDest.kind` is :data:`LINK_GOTOR` or :data:`LINK_LAUNCH`.\"\nmsgstr \":attr:`linkDest.kind` 가 :data:`LINK_GOTOR` 또는 :data:`LINK_LAUNCH` 인 경우 이 링크가 가리키는 파일명과 경로를 포함합니다.\"\n\n#: ../../linkdest.rst:47 ee1974ce6ace4936a3d8b8b75df71cb3\nmsgid \"\"\n\"A bitfield describing the validity and meaning of the different aspects \"\n\"of the destination. As far as possible, link destinations are constructed\"\n\" such that e.g. :attr:`linkDest.lt` and :attr:`linkDest.rb` can be \"\n\"treated as defining a bounding box. But the flags indicate which of the \"\n\"values were actually specified, see :ref:`linkDest Flags`.\"\nmsgstr \"대상의 다양한 측면의 유효성과 의미를 설명하는 비트 필드입니다. 가능한 한 링크 대상은 예를 들어 :attr:`linkDest.lt` 와 :attr:`linkDest.rb` 가 경계 상자를 정의하는 것으로 처리될 수 있도록 구성됩니다. 하지만 플래그는 실제로 지정된 값들을 나타냅니다. :ref:`linkDest Flags` 를 참조하세요.\"\n\n#: ../../linkdest.rst:49 ../../linkdest.rst:67 ../../linkdest.rst:91\n#: 3b848969f4524896b56f42ff138fb1c9 4f8b0dea71b94d5dbc70216822055473\n#: bcc9a9fb3afa46a898733753cf361878\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../linkdest.rst:53 09670cfe131548ddaff754f8d49d8e50\nmsgid \"\"\n\"This flag specifies whether to track the mouse position when the URI is \"\n\"resolved. Default value: False.\"\nmsgstr \"이 플래그는 URI가 해결될 때 마우스 위치를 추적할지 여부를 지정합니다. 기본값: False.\"\n\n#: ../../linkdest.rst:55 ../../linkdest.rst:61 ../../linkdest.rst:85\n#: 0f0bd710715f40efbacc9b29ff09ea21 44063c7c188e4ce083c47c800c7fe09f\n#: 64522ffbee3a4d4a93db40e43a1b4f85\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../linkdest.rst:59 fbb535a20f504c3e943e5b5a817ff056\nmsgid \"\"\n\"Specifies whether this destination is an internet resource (as opposed to\"\n\" e.g. a local file specification in URI format).\"\nmsgstr \"이 대상이 인터넷 리소스인지 여부를 지정합니다(예: URI 형식의 로컬 파일 사양과 대조).\"\n\n#: ../../linkdest.rst:65 ca4f535dd57b4577b7809ce0b0137464\nmsgid \"\"\n\"Indicates the type of this destination, like a place in this document, a \"\n\"URI, a file launch, an action or a place in another file. Look at \"\n\":ref:`linkDest Kinds` to see the names and numerical values.\"\nmsgstr \"이 문서 내의 위치, URI, 파일 실행, 작업 또는 다른 파일 내의 위치와 같은 이 대상의 유형을 나타냅니다. 이름과 숫자 값을 보려면 :ref:`linkDest Kinds` 를 참조하세요.\"\n\n#: ../../linkdest.rst:71 47371977bcbb41fca7f337d5784b6648\nmsgid \"The top left :ref:`Point` of the destination.\"\nmsgstr \"대상의 왼쪽 위 :ref:`Point`.\"\n\n#: ../../linkdest.rst:73 ../../linkdest.rst:97 8e3bc240ba0743959b8cbaa03d0dcff8\n#: c1283cb2f6344dc99b2a97cb147bba13\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../linkdest.rst:77 c723aab53cf843ebae6f749ce9ff4e59\nmsgid \"\"\n\"This destination refers to some named action to perform (e.g. a \"\n\"javascript, see :ref:`AdobeManual`). Standard actions provided are \"\n\"*NextPage*, *PrevPage*, *FirstPage*,  and *LastPage*.\"\nmsgstr \"이 대상은 수행할 이름이 지정된 작업(예: javascript, :ref:`AdobeManual` 참조)을 나타냅니다. 제공되는 표준 작업은 *NextPage*, *PrevPage*, *FirstPage*, *LastPage* 입니다.\"\n\n#: ../../linkdest.rst:83 1a909731575743f18e88a17658993f9c\nmsgid \"If true, the destination should be launched in a new window.\"\nmsgstr \"true이면 대상은 새 창에서 시작되어야 합니다.\"\n\n#: ../../linkdest.rst:89 09037d0a5d7f4c37a6408b92ec712af6\nmsgid \"\"\n\"The page number (in this or the target document) this destination points \"\n\"to. Only set if :attr:`linkDest.kind` is :data:`LINK_GOTOR` or \"\n\":data:`LINK_GOTO`. May be *-1* if :attr:`linkDest.kind` is \"\n\":data:`LINK_GOTOR`. In this case :attr:`linkDest.dest` contains the \"\n\"**name** of a destination in the target document.\"\nmsgstr \"이 대상이 가리키는 페이지 번호(이 문서 또는 대상 문서 내). :attr:`linkDest.kind` 가 :data:`LINK_GOTOR` 또는 :data:`LINK_GOTO` 인 경우에만 설정됩니다. :attr:`linkDest.kind` 가 :data:`LINK_GOTOR` 이면 *-1* 일 수 있습니다. 이 경우 :attr:`linkDest.dest` 에는 대상 문서의 대상 **이름** 이 포함됩니다.\"\n\n#: ../../linkdest.rst:95 c34d69f4dd99459b8b7b950ce4b817ef\nmsgid \"The bottom right :ref:`Point` of this destination.\"\nmsgstr \"이 대상의 오른쪽 아래 :ref:`Point`.\"\n\n#: ../../linkdest.rst:101 ab5be4b38a0d488996cc185c94c3339d\nmsgid \"The name of the URI this destination points to.\"\nmsgstr \"이 대상이 가리키는 URI의 이름.\"\n\n#: ../../footer.rst:46 fa618bdc623f48169996365910295fee\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/lowlevel.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 218a54ea43ac4940a4a60f2c3a6a2478\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 07e59acd2f254f13ab7d70dabdc0b0e5\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 b0edbb6b219e443c991a8de67143adf0\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../lowlevel.rst:5 ab1b60182cf44f4cbdbc96550824ae06\nmsgid \"Low Level Functions and Classes\"\nmsgstr \"저수준 함수 및 클래스\"\n\n#: ../../lowlevel.rst:6 7cd71eb177ee46c7809cc02f9cf0360a\nmsgid \"\"\n\"Contains a number of functions and classes for the experienced user. To \"\n\"be used for special needs or performance requirements.\"\nmsgstr \"경험 많은 사용자를 위한 여러 함수와 클래스를 포함합니다. 특수한 요구사항이나 성능 요구사항에 사용됩니다.\"\n\n#: ../../footer.rst:46 e5486934644f471b8a6673bf428a5c43\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/matrix.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 22b6a2a0571c4176bce077c545c814b3\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 73c9619ac3ee44d084a65d56842dc380\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 84065a34a4a14808906180f02e2efea2\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../matrix.rst:7 8a040befeffb44ac97583a22b00537bb\nmsgid \"Matrix\"\nmsgstr \"Matrix\"\n\n#: ../../matrix.rst:9 8eb69980d89943bb8e94c77820ab6263\nmsgid \"\"\n\"Matrix is a row-major 3x3 matrix used by image transformations in MuPDF \"\n\"(which complies with the respective concepts laid down in the \"\n\":ref:`AdobeManual`). With matrices you can manipulate the rendered image \"\n\"of a page in a variety of ways: (parts of) the page can be rotated, \"\n\"zoomed, flipped, sheared and shifted by setting some or all of just six \"\n\"float values.\"\nmsgstr \"Matrix는 MuPDF의 이미지 변환에 사용되는 행 우선 3x3 행렬입니다(:ref:`AdobeManual` 에 명시된 해당 개념을 준수). 행렬을 사용하면 페이지의 렌더링된 이미지를 다양한 방식으로 조작할 수 있습니다: 단 6개의 float 값 중 일부 또는 전체를 설정하여 페이지(의 일부)를 회전, 확대/축소, 뒤집기, 기울이기 및 이동할 수 있습니다.\"\n\n#: ../../matrix.rst:12 99311bf26c5b4fd5b0df9afed1d8ff5a\nmsgid \"\"\n\"Since all points or pixels live in a two-dimensional space, one column \"\n\"vector of that matrix is a constant unit vector, and only the remaining \"\n\"six elements are used for manipulations. These six elements are usually \"\n\"represented by `[a, b, c, d, e, f]`. Here is how they are positioned in \"\n\"the matrix:\"\nmsgstr \"모든 점 또는 픽셀이 2차원 공간에 있으므로 해당 행렬의 한 열 벡터는 상수 단위 벡터이며, 나머지 6개 요소만 조작에 사용됩니다. 이 6개 요소는 일반적으로 `[a, b, c, d, e, f]` 로 표시됩니다. 행렬에서의 위치는 다음과 같습니다:\"\n\n#: ../../matrix.rst:17 981036c6e6c24d00adc24601b311399b\nmsgid \"Please note:\"\nmsgstr \"참고:\"\n\n#: ../../matrix.rst:19 f1ae75aa82ce4a989a3afb538b648bd5\nmsgid \"\"\n\"the below methods are just convenience functions -- everything they do, \"\n\"can also be achieved by directly manipulating the six numerical values\"\nmsgstr \"아래 메서드는 편의 함수일 뿐입니다 -- 수행하는 모든 작업은 6개의 숫자 값을 직접 조작하여도 달성할 수 있습니다\"\n\n#: ../../matrix.rst:20 26c41674818040ab9d706c72f62e5b31\nmsgid \"\"\n\"all manipulations can be combined -- you can construct a matrix that \"\n\"rotates **and** shears **and** scales **and** shifts, etc. in one go. If \"\n\"you however choose to do this, do have a look at the **remarks** further \"\n\"down or at the :ref:`AdobeManual`.\"\nmsgstr \"모든 조작을 결합할 수 있습니다 -- 한 번에 회전 **및** 기울이기 **및** 확대/축소 **및** 이동 등을 수행하는 행렬을 구성할 수 있습니다. 하지만 이렇게 하려면 아래의 **참고 사항** 또는 :ref:`AdobeManual` 을 참조하세요.\"\n\n#: ../../matrix.rst:23 afd4ea95b6d34a6e914cc64e20f4259b\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../matrix.rst:23 c34d2903bcee45ddb3cc5e621baefea0\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../matrix.rst:25 11abdcd6cd234d4fa95850fe12580df9\nmsgid \":meth:`Matrix.prerotate`\"\nmsgstr \":meth:`Matrix.prerotate`\"\n\n#: ../../matrix.rst:25 80427e602a66422cac1da53c44af455f\nmsgid \"perform a rotation\"\nmsgstr \"회전 수행\"\n\n#: ../../matrix.rst:26 cad3e578828b433ba7ba0051be2032bf\nmsgid \":meth:`Matrix.prescale`\"\nmsgstr \":meth:`Matrix.prescale`\"\n\n#: ../../matrix.rst:26 a7e0bd6a201641fb912613e9f27fd76f\nmsgid \"perform a scaling\"\nmsgstr \"확대/축소 수행\"\n\n#: ../../matrix.rst:27 50c7f90d06004c62b19c6bff1b5a0ee9\nmsgid \":meth:`Matrix.preshear`\"\nmsgstr \":meth:`Matrix.preshear`\"\n\n#: ../../matrix.rst:27 10745ab48ff842fa86f0dba65a8ac4c9\nmsgid \"perform a shearing (skewing)\"\nmsgstr \"기울이기(왜곡) 수행\"\n\n#: ../../matrix.rst:28 b4c7cc3f2aff4f929fd556b21396c232\nmsgid \":meth:`Matrix.pretranslate`\"\nmsgstr \":meth:`Matrix.pretranslate`\"\n\n#: ../../matrix.rst:28 cefba85880554c02abc66d69a6a32faf\nmsgid \"perform a translation (shifting)\"\nmsgstr \"이동(시프트) 수행\"\n\n#: ../../matrix.rst:29 b3b9abc777594cf8b33d5290836afe88\nmsgid \":meth:`Matrix.concat`\"\nmsgstr \":meth:`Matrix.concat`\"\n\n#: ../../matrix.rst:29 fe1f3aa66e6042309e54265e9b99b18d\nmsgid \"perform a matrix multiplication\"\nmsgstr \"행렬 곱셈 수행\"\n\n#: ../../matrix.rst:30 fb89b2f56f6247ac8fc9b88f34f7e6c1\nmsgid \":meth:`Matrix.invert`\"\nmsgstr \":meth:`Matrix.invert`\"\n\n#: ../../matrix.rst:30 4dab7517ebb647c78b179fbe83285a9f\nmsgid \"calculate the inverted matrix\"\nmsgstr \"역행렬 계산\"\n\n#: ../../matrix.rst:31 3f0c29fd96594bd7824f5d9ab40c0fd7\nmsgid \":meth:`Matrix.norm`\"\nmsgstr \":meth:`Matrix.norm`\"\n\n#: ../../matrix.rst:31 bee6a79c30594e5a9982c37569a07722\nmsgid \"the Euclidean norm\"\nmsgstr \"유클리드 노름\"\n\n#: ../../matrix.rst:32 b0e601bc11b94c5b978faf3969d20262\nmsgid \":attr:`Matrix.a`\"\nmsgstr \":attr:`Matrix.a`\"\n\n#: ../../matrix.rst:32 7bd503f42cb2438da182834d71fb2dd4\nmsgid \"zoom factor X direction\"\nmsgstr \"X 방향 확대/축소 계수\"\n\n#: ../../matrix.rst:33 b20b6e26dcf04b37bf9d3226d6b7720f\nmsgid \":attr:`Matrix.b`\"\nmsgstr \":attr:`Matrix.b`\"\n\n#: ../../matrix.rst:33 dc49e0f4424c40eaa3c9b116b0a0d20f\nmsgid \"shearing effect Y direction\"\nmsgstr \"Y 방향 기울이기 효과\"\n\n#: ../../matrix.rst:34 d2e19dfdd9104ec19d44f40c663bcc03\nmsgid \":attr:`Matrix.c`\"\nmsgstr \":attr:`Matrix.c`\"\n\n#: ../../matrix.rst:34 0a2f7dcd0de34db7a4c69a001674c37a\nmsgid \"shearing effect X direction\"\nmsgstr \"X 방향 기울이기 효과\"\n\n#: ../../matrix.rst:35 c72a8985cba049b487c8ffebefcf9d99\nmsgid \":attr:`Matrix.d`\"\nmsgstr \":attr:`Matrix.d`\"\n\n#: ../../matrix.rst:35 c1fe0a57201a4eb6ad2a830ae1b17b15\nmsgid \"zoom factor Y direction\"\nmsgstr \"Y 방향 확대/축소 계수\"\n\n#: ../../matrix.rst:36 e471bd7cfd92424ab1e5f3e5059d4be9\nmsgid \":attr:`Matrix.e`\"\nmsgstr \":attr:`Matrix.e`\"\n\n#: ../../matrix.rst:36 d19ab3110ade4ac3b17c845a8c80fb37\nmsgid \"horizontal shift\"\nmsgstr \"수평 이동\"\n\n#: ../../matrix.rst:37 4a6eb68a255c4608873196c13298d411\nmsgid \":attr:`Matrix.f`\"\nmsgstr \":attr:`Matrix.f`\"\n\n#: ../../matrix.rst:37 0f0db520282844e9869b27e82d6fba11\nmsgid \"vertical shift\"\nmsgstr \"수직 이동\"\n\n#: ../../matrix.rst:38 e75c12f64eee44059ea4b0762741fdb1\nmsgid \":attr:`Matrix.is_rectilinear`\"\nmsgstr \":attr:`Matrix.is_rectilinear`\"\n\n#: ../../matrix.rst:38 bc57693d7a8c445eb2a7717732d081b9\nmsgid \"true if rect corners will remain rect corners\"\nmsgstr \"사각형 모서리가 사각형 모서리로 유지되면 true\"\n\n#: ../../matrix.rst:41 01aaa6a5cece41dd86f5e6c6f0d08b42\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../matrix.rst:59 56627216de1442368ffe90a40bd40b5a\nmsgid \"Overloaded constructors.\"\nmsgstr \"오버로드된 생성자.\"\n\n#: ../../matrix.rst:61 ab9ade436b794d9cb70e8ec07c59573e\nmsgid \"\"\n\"Without parameters, the zero matrix *Matrix(0.0, 0.0, 0.0, 0.0, 0.0, \"\n\"0.0)* will be created.\"\nmsgstr \"매개변수 없이 영 행렬 *Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)* 이 생성됩니다.\"\n\n#: ../../matrix.rst:63 0ff005031e87475e82c82f509a503432\nmsgid \"\"\n\"*zoom-** and *shear-** specify zoom or shear values (float) and create a \"\n\"zoom or shear matrix, respectively.\"\nmsgstr \"*zoom-** 및 *shear-** 는 확대/축소 또는 기울이기 값(float)을 지정하고 각각 확대/축소 또는 기울이기 행렬을 생성합니다.\"\n\n#: ../../matrix.rst:65 3772827e3c4e46efaa66e0541654fbde\nmsgid \"For \\\"matrix\\\" a **new copy** of another matrix will be made.\"\nmsgstr \"\\\"matrix\\\"의 경우 다른 행렬의 **새 복사본** 이 만들어집니다.\"\n\n#: ../../matrix.rst:67 e0de220e569d4fb192d61776da7cc98d\nmsgid \"\"\n\"Float value \\\"degree\\\" specifies the creation of a rotation matrix which \"\n\"rotates anti-clockwise.\"\nmsgstr \"Float 값 \\\"degree\\\"는 반시계 방향으로 회전하는 회전 행렬의 생성을 지정합니다.\"\n\n#: ../../matrix.rst:69 202fbb08a1534f9b873b978d1ee2f25e\nmsgid \"\"\n\"A \\\"sequence\\\" must be any Python sequence object with exactly 6 float \"\n\"entries (see :ref:`SequenceTypes`).\"\nmsgstr \"\\\"sequence\\\"는 정확히 6개의 float 항목을 가진 모든 Python 시퀀스 객체여야 합니다(:ref:`SequenceTypes` 참조).\"\n\n#: ../../matrix.rst:71 3290c36cfd044349b8b73b9a12b39105\nmsgid \"\"\n\"*pymupdf.Matrix(1, 1)* and *pymupdf.Matrix(pymupdf.Identity)* create \"\n\"modifiable versions of the :ref:`Identity` matrix, which looks like *[1, \"\n\"0, 0, 1, 0, 0]*.\"\nmsgstr \"*pymupdf.Matrix(1, 1)* 및 *pymupdf.Matrix(pymupdf.Identity)* 는 *[1, 0, 0, 1, 0, 0]* 처럼 보이는 :ref:`Identity` 행렬의 수정 가능한 버전을 생성합니다.\"\n\n#: ../../matrix.rst:75 2d27925e056c4beab39284c17c097dc8\nmsgid \"New in version 1.16.0\"\nmsgstr \"버전 1.16.0에서 새로 추가됨\"\n\n#: ../../matrix.rst:77 23099b3eeb904d19a2fca93ba4ff4ac2\nmsgid \"Return the Euclidean norm of the matrix as a vector.\"\nmsgstr \"행렬의 유클리드 노름을 벡터로 반환합니다.\"\n\n#: ../../matrix.rst:81 cf82a48349524343a3a9fb35951b2482\nmsgid \"\"\n\"Modify the matrix to perform a counter-clockwise rotation for positive \"\n\"*deg* degrees, else clockwise. The matrix elements of an identity matrix \"\n\"will change in the following way:\"\nmsgstr \"행렬을 수정하여 양수 *deg* 도에 대해 반시계 방향 회전을 수행하고, 그렇지 않으면 시계 방향으로 회전합니다. 항등 행렬의 행렬 요소는 다음과 같이 변경됩니다:\"\n\n#: ../../matrix.rst:83 a024346df65d49e7bcdef1a35d0f0ea9\nmsgid \"*[1, 0, 0, 1, 0, 0] -> [cos(deg), sin(deg), -sin(deg), cos(deg), 0, 0]*.\"\nmsgstr \"*[1, 0, 0, 1, 0, 0] -> [cos(deg), sin(deg), -sin(deg), cos(deg), 0, 0]*.\"\n\n#: ../../matrix.rst 0e2caa4b969d4e8c883315663dfbb010\n#: 2a76f7fdef494d7cb96fb9bcb0b288a0 44ed05851fab4cd4b3017cd0b82bc4f4\n#: 797389fbee9c42f6a11d44d628804863 c8b2675c06ee43c4abcd46c105be0f19\n#: e6e50d5d62724013ba993ce51b6e65a8\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../matrix.rst:85 34bf9b5e70b9486285ffd6799c5556ca\nmsgid \"\"\n\"The rotation angle in degrees (use conventional notation based on Pi = \"\n\"180 degrees).\"\nmsgstr \"도 단위의 회전 각도(Pi = 180도를 기준으로 한 일반 표기법 사용).\"\n\n#: ../../matrix.rst:89 94eb659613c24f939142b8fc6dd19ab4\nmsgid \"\"\n\"Modify the matrix to scale by the zoom factors sx and sy. Has effects on \"\n\"attributes *a* thru *d* only: *[a, b, c, d, e, f] -> [a*sx, b*sx, c*sy, \"\n\"d*sy, e, f]*.\"\nmsgstr \"행렬을 수정하여 확대/축소 계수 sx 및 sy로 스케일링합니다. 속성 *a* 부터 *d* 에만 영향을 줍니다: *[a, b, c, d, e, f] -> [a*sx, b*sx, c*sy, d*sy, e, f]*.\"\n\n#: ../../matrix.rst:91 72c725939ccb4e8b90b12926ae88abec\nmsgid \"\"\n\"Zoom factor in X direction. For the effect see description of attribute \"\n\"*a*.\"\nmsgstr \"X 방향의 확대/축소 계수. 효과는 속성 *a* 의 설명을 참조하세요.\"\n\n#: ../../matrix.rst:93 2ef911aad48643e18db6f643f2613c9a\nmsgid \"\"\n\"Zoom factor in Y direction. For the effect see description of attribute \"\n\"*d*.\"\nmsgstr \"Y 방향의 확대/축소 계수. 효과는 속성 *d* 의 설명을 참조하세요.\"\n\n#: ../../matrix.rst:97 a47d6e8530894f2aac1846c0416c7f14\nmsgid \"\"\n\"Modify the matrix to perform a shearing, i.e. transformation of \"\n\"rectangles into parallelograms (rhomboids). Has effects on attributes *a*\"\n\" thru *d* only: *[a, b, c, d, e, f] -> [c*sy, d*sy, a*sx, b*sx, e, f]*.\"\nmsgstr \"행렬을 수정하여 기울이기를 수행합니다. 즉, 사각형을 평행사변형(마름모)으로 변환합니다. 속성 *a* 부터 *d* 에만 영향을 줍니다: *[a, b, c, d, e, f] -> [c*sy, d*sy, a*sx, b*sx, e, f]*.\"\n\n#: ../../matrix.rst:99 7af0396c77db4280bd8b6ef9764cab2d\nmsgid \"Shearing effect in X direction. See attribute *c*.\"\nmsgstr \"X 방향의 기울이기 효과. 속성 *c* 를 참조하세요.\"\n\n#: ../../matrix.rst:101 5a8d7d2b58c348f0bf481d54d9ff5b01\nmsgid \"Shearing effect in Y direction. See attribute *b*.\"\nmsgstr \"Y 방향의 기울이기 효과. 속성 *b* 를 참조하세요.\"\n\n#: ../../matrix.rst:105 152c5f45800e42b6a038fee68ba116d4\nmsgid \"\"\n\"Modify the matrix to perform a shifting / translation operation along the\"\n\" x and / or y axis. Has effects on attributes *e* and *f* only: *[a, b, \"\n\"c, d, e, f] -> [a, b, c, d, tx*a + ty*c, tx*b + ty*d]*.\"\nmsgstr \"행렬을 수정하여 x 및/또는 y 축을 따라 이동/변환 작업을 수행합니다. 속성 *e* 및 *f* 에만 영향을 줍니다: *[a, b, c, d, e, f] -> [a, b, c, d, tx*a + ty*c, tx*b + ty*d]*.\"\n\n#: ../../matrix.rst:107 8b15e98fb7734d2fb7d3a90c734616fd\nmsgid \"Translation effect in X direction. See attribute *e*.\"\nmsgstr \"X 방향의 이동 효과. 속성 *e* 를 참조하세요.\"\n\n#: ../../matrix.rst:109 1ac03cdeaadf47039b40d141265dad51\nmsgid \"Translation effect in Y direction. See attribute *f*.\"\nmsgstr \"Y 방향의 이동 효과. 속성 *f* 를 참조하세요.\"\n\n#: ../../matrix.rst:113 a7232949340949e6bee6b5a75b157849\nmsgid \"\"\n\"Calculate the matrix product *m1 * m2* and store the result in the \"\n\"current matrix. Any of *m1* or *m2* may be the current matrix. Be aware \"\n\"that matrix multiplication is not commutative. So the sequence of *m1*, \"\n\"*m2* is important.\"\nmsgstr \"행렬 곱 *m1 * m2* 를 계산하고 결과를 현재 행렬에 저장합니다. *m1* 또는 *m2* 중 하나가 현재 행렬일 수 있습니다. 행렬 곱셈은 가환적이지 않습니다. 따라서 *m1*, *m2* 의 순서가 중요합니다.\"\n\n#: ../../matrix.rst:115 c868c7bce6e24c17aefb279a2b589bad\nmsgid \"First (left) matrix.\"\nmsgstr \"첫 번째(왼쪽) 행렬.\"\n\n#: ../../matrix.rst:118 6a23a720cc824c018154df578fbe2287\nmsgid \"Second (right) matrix.\"\nmsgstr \"두 번째(오른쪽) 행렬.\"\n\n#: ../../matrix.rst:123 c1c62753df994db5a29eaf60b74d5311\nmsgid \"\"\n\"Calculate the matrix inverse of *m* and store the result in the current \"\n\"matrix. Returns *1* if *m* is not invertible (\\\"degenerate\\\"). In this \"\n\"case the current matrix **will not change**. Returns *0* if *m* is \"\n\"invertible, and the current matrix is replaced with the inverted *m*.\"\nmsgstr \"*m* 의 역행렬을 계산하고 결과를 현재 행렬에 저장합니다. *m* 이 역행렬이 없으면(\\\"degenerate\\\") *1* 을 반환합니다. 이 경우 현재 행렬은 **변경되지 않습니다**. *m* 이 역행렬이 있으면 *0* 을 반환하고 현재 행렬은 역행렬 *m* 으로 대체됩니다.\"\n\n#: ../../matrix.rst:125 6f3f8c966b71407b9e3b02488f7f4034\nmsgid \"Matrix to be inverted. If not provided, the current matrix will be used.\"\nmsgstr \"역행렬을 계산할 행렬. 제공되지 않으면 현재 행렬이 사용됩니다.\"\n\n#: ../../matrix.rst e8077cac107d4551bdd9b1c1d14a4952\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../matrix.rst:132 db229e59a31b455b98ea5ccfa578122a\nmsgid \"\"\n\"Scaling in X-direction **(width)**. For example, a value of 0.5 performs \"\n\"a shrink of the **width** by a factor of 2. If a < 0, a left-right flip \"\n\"will (additionally) occur.\"\nmsgstr \"X 방향 **(너비)** 스케일링. 예를 들어, 0.5 값은 **너비** 를 2배로 축소합니다. a < 0이면 좌우 뒤집기가 (추가로) 발생합니다.\"\n\n#: ../../matrix.rst 6fcedf91827d4c289e6a645364d76ea6\n#: 8654b40d08014804b0c0e8c304580291 96cbe6754a4b4f99bb7e0e80e180c0a6\n#: afc20c369a9f4c739bc1f16197754859 c2c0c17a6a334d9daf1a246b0a95ca15\n#: fab66c3105f3412b8e17b401ecfe57ab fceb1d67502e44b49baa260b088dd68f\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../matrix.rst:134 ../../matrix.rst:140 ../../matrix.rst:146\n#: ../../matrix.rst:152 ../../matrix.rst:158 ../../matrix.rst:164\n#: 137024cc37b74d68971a780ab821bb5c 20de69effd914f3f92727bc07f7de025\n#: 5804209069a04b28ae858ceb0466f4d1 5b5b333b8cb346858ac4e11335709c2a\n#: 789de033d5c0443997dabc1c08157dbc 867fd680a9e9402583480286d03e27ca\nmsgid \"float\"\nmsgstr \"float\"\n\n#: ../../matrix.rst:138 c229f8ba4d804490b761e624fe313b6d\nmsgid \"\"\n\"Causes a shearing effect: each `Point(x, y)` will become `Point(x, y - \"\n\"b*x)`. Therefore, horizontal lines will be \\\"tilt\\\".\"\nmsgstr \"기울이기 효과를 발생시킵니다: 각 `Point(x, y)` 는 `Point(x, y - b*x)` 가 됩니다. 따라서 수평선이 \\\"기울어집니다\\\".\"\n\n#: ../../matrix.rst:144 7b98255d69974126bcf901feb1b268f6\nmsgid \"\"\n\"Causes a shearing effect: each `Point(x, y)` will become `Point(x - c*y, \"\n\"y)`. Therefore, vertical lines will be \\\"tilt\\\".\"\nmsgstr \"기울이기 효과를 발생시킵니다: 각 `Point(x, y)` 는 `Point(x - c*y, y)` 가 됩니다. 따라서 수직선이 \\\"기울어집니다\\\".\"\n\n#: ../../matrix.rst:150 ac4f38489ad847b7827dcac0e26521a5\nmsgid \"\"\n\"Scaling in Y-direction **(height)**. For example, a value of 1.5 performs\"\n\" a stretch of the **height** by 50%. If d < 0, an up-down flip will \"\n\"(additionally) occur.\"\nmsgstr \"Y 방향 **(높이)** 스케일링. 예를 들어, 1.5 값은 **높이** 를 50% 늘립니다. d < 0이면 상하 뒤집기가 (추가로) 발생합니다.\"\n\n#: ../../matrix.rst:156 9660c53c0df84ae99b72badb3989dddf\nmsgid \"\"\n\"Causes a horizontal shift effect: Each *Point(x, y)* will become *Point(x\"\n\" + e, y)*. Positive (negative) values of *e* will shift right (left).\"\nmsgstr \"수평 이동 효과를 발생시킵니다: 각 *Point(x, y)* 는 *Point(x + e, y)* 가 됩니다. *e* 의 양수(음수) 값은 오른쪽(왼쪽)으로 이동합니다.\"\n\n#: ../../matrix.rst:162 96c71528239744f1b8cd967c2e46cb62\nmsgid \"\"\n\"Causes a vertical shift effect: Each *Point(x, y)* will become *Point(x, \"\n\"y - f)*. Positive (negative) values of *f* will shift down (up).\"\nmsgstr \"수직 이동 효과를 발생시킵니다: 각 *Point(x, y)* 는 *Point(x, y - f)* 가 됩니다. *f* 의 양수(음수) 값은 아래(위)로 이동합니다.\"\n\n#: ../../matrix.rst:168 fbbefd1680244e43b84002ed9a436dec\nmsgid \"\"\n\"Rectilinear means that no shearing is present and that any rotations are \"\n\"integer multiples of 90 degrees. Usually this is used to confirm that \"\n\"(axis-aligned) rectangles before the transformation are still axis-\"\n\"aligned rectangles afterwards.\"\nmsgstr \"직선형은 기울이기가 없고 모든 회전이 90도의 정수 배수임을 의미합니다. 일반적으로 이것은 변환 전의 (축 정렬) 사각형이 변환 후에도 여전히 축 정렬 사각형임을 확인하는 데 사용됩니다.\"\n\n#: ../../matrix.rst:170 36d4d94103214600af41eafe39212e90\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../matrix.rst:174 90ffe958045f48d090dba5ba44f73165\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"이 클래스는 Python 시퀀스 프로토콜을 따르므로 구성 요소는 인덱스를 통해 액세스할 수도 있습니다. :ref:`SequenceTypes` 도 참조하세요.\"\n\n#: ../../matrix.rst:175 ae28f509b9434158ad3509b43fcadd26\nmsgid \"\"\n\"Matrices can be used with arithmetic operators almost like ordinary \"\n\"numbers: they can be added, subtracted, multiplied or divided -- see \"\n\"chapter :ref:`Algebra`.\"\nmsgstr \"행렬은 일반 숫자처럼 산술 연산자와 함께 사용할 수 있습니다: 더하기, 빼기, 곱하기 또는 나누기를 할 수 있습니다 -- :ref:`Algebra` 장을 참조하세요.\"\n\n#: ../../matrix.rst:176 8bec4a086d304bbb9bfd022e4556dd29\nmsgid \"\"\n\"Matrix multiplication is **not commutative** -- changing the sequence of \"\n\"the multiplicands will change the result in general. So it can quickly \"\n\"become unclear which result a transformation will yield.\"\nmsgstr \"행렬 곱셈은 **가환적이지 않습니다** -- 곱하는 순서를 변경하면 일반적으로 결과가 변경됩니다. 따라서 변환이 어떤 결과를 산출할지 빠르게 불명확해질 수 있습니다.\"\n\n#: ../../matrix.rst:180 281fd31e543c4617a40894e7ac37597e\nmsgid \"Examples\"\nmsgstr \"예제\"\n\n#: ../../matrix.rst:181 401084daabc9429b9009d38c9e0f2aec\nmsgid \"\"\n\"Here are examples that illustrate some of the achievable effects. All \"\n\"pictures show some text, inserted under control of some matrix and \"\n\"relative to a fixed reference point (the red dot).\"\nmsgstr \"달성 가능한 효과 중 일부를 보여주는 예제입니다. 모든 그림은 일부 행렬의 제어 하에 삽입되고 고정된 참조점(빨간 점)을 기준으로 하는 일부 텍스트를 보여줍니다.\"\n\n#: ../../matrix.rst:183 ef95f7140bc84ceb80f3fe9cc5ffe0d2\nmsgid \"The :ref:`Identity` matrix performs no operation.\"\nmsgstr \":ref:`Identity` 행렬은 작업을 수행하지 않습니다.\"\n\n#: ../../matrix.rst:188 a80fc2a091374e8cb6815dfe8672bddd\nmsgid \"\"\n\"The scaling matrix `Matrix(2, 0.5)` stretches by a factor of 2 in \"\n\"horizontal, and shrinks by factor 0.5 in vertical direction.\"\nmsgstr \"스케일링 행렬 `Matrix(2, 0.5)` 는 수평으로 2배 늘리고 수직으로 0.5배 축소합니다.\"\n\n#: ../../matrix.rst:193 9699134c66a146af9068adb90948b8f2\nmsgid \"\"\n\"Attributes :attr:`Matrix.e` and :attr:`Matrix.f` shift horizontally and, \"\n\"respectively vertically. In the following 10 to the right and 20 down.\"\nmsgstr \"속성 :attr:`Matrix.e` 및 :attr:`Matrix.f` 는 각각 수평 및 수직으로 이동합니다. 다음에서는 오른쪽으로 10, 아래로 20 이동합니다.\"\n\n#: ../../matrix.rst:198 168fe9a931a94651ac55f633dffbe987\nmsgid \"A negative :attr:`Matrix.a` causes a left-right flip.\"\nmsgstr \"음수 :attr:`Matrix.a` 는 좌우 뒤집기를 발생시킵니다.\"\n\n#: ../../matrix.rst:203 f2cb4722af2e45f6ac67fda814935ea4\nmsgid \"A negative :attr:`Matrix.d` causes an up-down flip.\"\nmsgstr \"음수 :attr:`Matrix.d` 는 상하 뒤집기를 발생시킵니다.\"\n\n#: ../../matrix.rst:208 28cc582a5ec24205816af0c892b692d1\nmsgid \"Attribute :attr:`Matrix.b` tilts upwards / downwards along the x-axis.\"\nmsgstr \"속성 :attr:`Matrix.b` 는 x축을 따라 위/아래로 기울어집니다.\"\n\n#: ../../matrix.rst:213 a2b77644fc61456690d3603561dae948\nmsgid \"Attribute :attr:`Matrix.c` tilts left / right along the y-axis.\"\nmsgstr \"속성 :attr:`Matrix.c` 는 y축을 따라 왼쪽/오른쪽으로 기울어집니다.\"\n\n#: ../../matrix.rst:218 bd842bfbd48b44509584185764d44373\nmsgid \"\"\n\"Matrix `Matrix(beta)` performs counterclockwise rotations for positive \"\n\"angles `beta`.\"\nmsgstr \"행렬 `Matrix(beta)` 는 양수 각도 `beta` 에 대해 반시계 방향 회전을 수행합니다.\"\n\n#: ../../matrix.rst:223 ac0b2cc97b1347ab9f63fa8f97f50072\nmsgid \"Show some effects on a rectangle::\"\nmsgstr \"사각형에 대한 일부 효과 표시::\"\n\n#: ../../footer.rst:46 2a49496b580540908297c502618954b2\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/module.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 62136ba5c5a74ecfa227336e448d62b5\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 6fc9c3c622e84783910d3b11c3709f37\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 d611277d72c64dd99b3b9f2f8ec96367\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../module.rst:7 f33c4cbb9f05422084dddcddaf87949a\nmsgid \"Command line interface\"\nmsgstr \"명령줄 인터페이스\"\n\n#: ../../module.rst:9 9f557fd4350a42ed9a1df58860be9669\nmsgid \"New in version 1.16.8\"\nmsgstr \"버전 1.16.8의 새로운 기능\"\n\n#: ../../module.rst:11 ecd7d23131464943807a4fb959173755\nmsgid \"\"\n\"PyMuPDF can also be used from the command line to perform utility \"\n\"functions. This feature should obsolete writing some of the most basic \"\n\"scripts.\"\nmsgstr \"|PyMuPDF| 는 명령줄에서 유틸리티 함수를 수행하는 데에도 사용할 수 있습니다. 이 기능은 가장 기본적인 스크립트 작성 중 일부를 대체해야 합니다.\"\n\n#: ../../module.rst:13 20b8d208b65e4c74bf7ad83bfb388393\nmsgid \"\"\n\"Admittedly, there is some functional overlap with the MuPDF CLI `mutool`.\"\n\" On the other hand, PDF embedded files are no longer supported by MuPDF, \"\n\"so PyMuPDF is offering something unique here.\"\nmsgstr \"인정하건대, |MuPDF| CLI `mutool` 과 기능적 중복이 있습니다. 반면, PDF 임베디드 파일은 |MuPDF| 에서 더 이상 지원되지 않으므로, |PyMuPDF| 는 여기서 고유한 기능을 제공합니다.\"\n\n#: ../../module.rst:16 61944c3cbe72440580bdadeeb1269b75\nmsgid \"Invocation\"\nmsgstr \"호출\"\n\n#: ../../module.rst:18 295dfa35e12a40d48e27c0055204d5a7\nmsgid \"The command-line interface can be invoked in two ways.\"\nmsgstr \"명령줄 인터페이스는 두 가지 방법으로 호출할 수 있습니다.\"\n\n#: ../../module.rst:20 7177082a690146019882a6b232aa8853\nmsgid \"Use the installed `pymupdf` command::\"\nmsgstr \"설치된 `pymupdf` 명령을 사용합니다::\"\n\n#: ../../module.rst:24 87e819afc653442caceed77952e1ed58\nmsgid \"Or use Python's `-m` switch with PyMuPDF's `pymupdf` module::\"\nmsgstr \"또는 |PyMuPDF| 의 `pymupdf` 모듈과 함께 Python의 `-m` 스위치를 사용합니다::\"\n\n#: ../../module.rst:31 c1e7f23de6ef452a83faa31ed988d657\nmsgid \"General remarks:\"\nmsgstr \"일반 참고 사항:\"\n\n#: ../../module.rst:33 fd3bac8dc3e9421eb2371c451ec1c3da\nmsgid \"\"\n\"Request help via `\\\"-h\\\"`, resp. command-specific help via `\\\"command \"\n\"-h\\\"`.\"\nmsgstr \"`\\\"-h\\\"` 를 통해 도움말을 요청하거나, `\\\"command -h\\\"` 를 통해 명령별 도움말을 요청합니다.\"\n\n#: ../../module.rst:34 dbd5a72f66d84df5b18b6bec2f4fd2f5\nmsgid \"Parameters may be abbreviated where this does not introduce ambiguities.\"\nmsgstr \"모호함을 유발하지 않는 경우 매개변수를 축약할 수 있습니다.\"\n\n#: ../../module.rst:35 73cd69c626714f7aa1e084d11447cea6\nmsgid \"\"\n\"Several commands support parameters `-pages` and `-xrefs`. They are \"\n\"intended for down-selection. Please note that:\"\nmsgstr \"여러 명령은 `-pages` 및 `-xrefs` 매개변수를 지원합니다. 이들은 하위 선택을 위한 것입니다. 다음을 참고하세요:\"\n\n#: ../../module.rst:37 7ff6972a285a4695baa4e4276641b755\nmsgid \"**page numbers** for this utility must be given **1-based**.\"\nmsgstr \"이 유틸리티의 **페이지 번호** 는 **1부터 시작** 해야 합니다.\"\n\n#: ../../module.rst:38 b9688dc1937342d0a9ba2a88937c6d0a\nmsgid \"valid :data:`xref` numbers start at 1.\"\nmsgstr \"유효한 :data:`xref` 번호는 1부터 시작합니다.\"\n\n#: ../../module.rst:39 7c0c1890d37b41f6820770dd6bed4376\nmsgid \"\"\n\"Specify a comma-separated list of either *single* integers or integer \"\n\"*ranges*. A **range** is a pair of integers separated by one hyphen \"\n\"\\\"-\\\". Integers must not exceed the maximum page, resp. xref number. To \"\n\"specify that maximum, the symbolic variable \\\"N\\\" may be used. Integers \"\n\"or ranges may occur several times, in any sequence and may overlap. If in\"\n\" a range the first number is greater than the second one, the respective \"\n\"items will be processed in reversed order.\"\nmsgstr \"*단일* 정수 또는 정수 *범위* 의 쉼표로 구분된 목록을 지정합니다. **범위** 는 하이픈 \\\"-\\\" 로 구분된 정수 쌍입니다. 정수는 최대 페이지(또는 xref 번호)를 초과하지 않아야 합니다. 최대값을 지정하려면 기호 변수 \\\"N\\\" 을 사용할 수 있습니다. 정수 또는 범위는 여러 번 발생할 수 있으며, 어떤 순서로든 발생할 수 있고 겹칠 수 있습니다. 범위에서 첫 번째 숫자가 두 번째 숫자보다 크면 해당 항목이 역순으로 처리됩니다.\"\n\n#: ../../module.rst:41 ee46edb0ea2b44e98364d207aaa2d1ef\nmsgid \"How to use the module inside your script::\"\nmsgstr \"스크립트 내에서 모듈을 사용하는 방법::\"\n\n#: ../../module.rst:50 123a2e5ad2564826b878adadaf638eeb\nmsgid \"\"\n\"Use the following 2-liner and compile it with `Nuitka \"\n\"<https://pypi.org/project/Nuitka/>`_ in standalone mode. This will give \"\n\"you a CLI executable with all the module's features, that can be used on \"\n\"all compatible platforms without Python, PyMuPDF or MuPDF being \"\n\"installed.\"\nmsgstr \"다음 2줄 코드를 사용하고 `Nuitka <https://pypi.org/project/Nuitka/>`_ 로 standalone 모드에서 컴파일합니다. 이것은 모듈의 모든 기능을 가진 CLI 실행 파일을 제공하며, Python, |PyMuPDF| 또는 |MuPDF| 가 설치되지 않은 모든 호환 플랫폼에서 사용할 수 있습니다.\"\n\n#: ../../module.rst:59 621c5379e7d44e29a5ae735c58352834\nmsgid \"Cleaning and Copying\"\nmsgstr \"정리 및 복사\"\n\n#: ../../module.rst:63 a41c329fb87940c482d0805086ecc3cf\nmsgid \"\"\n\"This command will optimize the PDF and store the result in a new file. \"\n\"You can use it also for encryption, decryption and creating sub \"\n\"documents. It is mostly similar to the MuPDF command line utility \"\n\"*\\\"mutool clean\\\"*::\"\nmsgstr \"이 명령은 PDF를 최적화하고 결과를 새 파일에 저장합니다. 암호화, 복호화 및 하위 문서 생성에도 사용할 수 있습니다. 이것은 |MuPDF| 명령줄 유틸리티 *\\\"mutool clean\\\"* 과 대부분 유사합니다::\"\n\n#: ../../module.rst:96 95c61ecff9474da7a32002be18ff00b3\nmsgid \"\"\n\"If you specify \\\"-pages\\\", be aware that only page-related objects are \"\n\"copied, **no document-level items** like e.g. embedded files.\"\nmsgstr \"\\\"-pages\\\" 를 지정하면 페이지 관련 객체만 복사되며, 예를 들어 임베디드 파일과 같은 **문서 레벨 항목은 복사되지 않습니다**.\"\n\n#: ../../module.rst:98 958ae9bd4e2244ae9cbb5d24a62a8c94\nmsgid \"Please consult :meth:`Document.save` for the parameter meanings.\"\nmsgstr \"매개변수 의미는 :meth:`Document.save` 를 참조하세요.\"\n\n#: ../../module.rst:102 5b59f04532e94259bf5b3ecd530ca408\nmsgid \"Extracting Fonts and Images\"\nmsgstr \"글꼴 및 이미지 추출\"\n\n#: ../../module.rst:103 170896a4fb624362bfbd8172cf909da4\nmsgid \"Extract fonts or images from selected PDF pages to a desired directory::\"\nmsgstr \"선택한 PDF 페이지에서 글꼴 또는 이미지를 원하는 디렉토리로 추출합니다::\"\n\n#: ../../module.rst:123 220fe33385e844f3928ec0625f051414\nmsgid \"\"\n\"**Image filenames** are built according to the naming scheme: **\\\"img-\"\n\"xref.ext\\\"**, where \\\"ext\\\" is the extension associated with the image \"\n\"and \\\"xref\\\" the :data:`xref` of the image PDF object.\"\nmsgstr \"**이미지 파일명** 은 명명 체계에 따라 생성됩니다: **\\\"img-xref.ext\\\"**, 여기서 \\\"ext\\\" 는 이미지와 연결된 확장자이고 \\\"xref\\\" 는 이미지 PDF 객체의 :data:`xref` 입니다.\"\n\n#: ../../module.rst:125 d56994d8f2a8433280e4ef35819f2e7a\nmsgid \"\"\n\"**Font filenames** consist of the fontname and the associated extension. \"\n\"Any spaces in the fontname are replaced with hyphens \\\"-\\\".\"\nmsgstr \"**글꼴 파일명** 은 글꼴 이름과 연결된 확장자로 구성됩니다. 글꼴 이름의 공백은 하이픈 \\\"-\\\" 로 대체됩니다.\"\n\n#: ../../module.rst:127 a8e1a30f5fde401d810825a6e3b01a09\nmsgid \"The output directory must already exist.\"\nmsgstr \"출력 디렉토리는 이미 존재해야 합니다.\"\n\n#: ../../module.rst:129 f2bc1eaf74014a2c9c0473449a9e7b11\nmsgid \"\"\n\"Except for output directory creation, this feature is **functionally \"\n\"equivalent** to and obsoletes `this script <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-\"\n\"pages.py>`_.\"\nmsgstr \"출력 디렉토리 생성 제외, 이 기능은 `이 스크립트 <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_ 와 **기능적으로 동일** 하며 이를 대체합니다.\"\n\n#: ../../module.rst:133 b52a0c02382d4e9abbd491e7b26f50d8\nmsgid \"Joining PDF Documents\"\nmsgstr \"PDF 문서 결합\"\n\n#: ../../module.rst:134 b52dba2292bb478f86d8bd2a68e72d49\nmsgid \"To join several PDF files specify::\"\nmsgstr \"여러 PDF 파일을 결합하려면 다음을 지정합니다::\"\n\n#: ../../module.rst:153 e75a700cceee42eda662850bcb411254\nmsgid \"\"\n\"Each input must be entered as **\\\"filename,password,pages\\\"**. Password \"\n\"and pages are optional.\"\nmsgstr \"각 입력은 **\\\"filename,password,pages\\\"** 형식으로 입력해야 합니다. 비밀번호와 페이지는 선택 사항입니다.\"\n\n#: ../../module.rst:154 5bbc4bbfbbe44ea29ce63dc28468ecde\nmsgid \"\"\n\"The password entry **is required** if the \\\"pages\\\" entry is used. If the\"\n\" PDF needs no password, specify two commas.\"\nmsgstr \"\\\"pages\\\" 항목을 사용하는 경우 비밀번호 항목이 **필수** 입니다. PDF에 비밀번호가 필요하지 않으면 두 개의 쉼표를 지정합니다.\"\n\n#: ../../module.rst:155 24124b66f3f9496c9cba03a6c3987619\nmsgid \"\"\n\"The **\\\"pages\\\"** format is the same as explained at the top of this \"\n\"section.\"\nmsgstr \"**\\\"pages\\\"** 형식은 이 섹션 상단에서 설명한 것과 동일합니다.\"\n\n#: ../../module.rst:156 6c8cd3be3fd844a18d6859e34270344c\nmsgid \"\"\n\"Each input file is immediately closed after use. Therefore you can use \"\n\"one of them as output filename, and thus overwrite it.\"\nmsgstr \"각 입력 파일은 사용 후 즉시 닫힙니다. 따라서 그 중 하나를 출력 파일명으로 사용하여 덮어쓸 수 있습니다.\"\n\n#: ../../module.rst:159 62faf24e6a7143aca5c2f6d4d0a3bd13\nmsgid \"Example: To join the following files\"\nmsgstr \"예제: 다음 파일을 결합하려면\"\n\n#: ../../module.rst:161 088838df3b2545f8801c172c3bc996f0\nmsgid \"**file1.pdf:** all pages, back to front, no password\"\nmsgstr \"**file1.pdf:** 모든 페이지, 뒤에서 앞으로, 비밀번호 없음\"\n\n#: ../../module.rst:162 72f4cc0b55a64f16a43ce016fb9d46a0\nmsgid \"**file2.pdf:** last page, first page, password: \\\"secret\\\"\"\nmsgstr \"**file2.pdf:** 마지막 페이지, 첫 페이지, 비밀번호: \\\"secret\\\"\"\n\n#: ../../module.rst:163 518dcf41451c4ab098ae80c98c705da7\nmsgid \"**file3.pdf:** pages 5 to last, no password\"\nmsgstr \"**file3.pdf:** 페이지 5부터 마지막까지, 비밀번호 없음\"\n\n#: ../../module.rst:165 579e18430ffe47deaf32eb9b5bb856c7\nmsgid \"and store the result as **output.pdf** enter this command:\"\nmsgstr \"결과를 **output.pdf** 로 저장하려면 다음 명령을 입력합니다:\"\n\n#: ../../module.rst:167 945d0c96b4b34fc782a86ae2fcf40aa5\nmsgid \"\"\n\"``pymupdf join -o output.pdf file1.pdf,,N-1 file2.pdf,secret,N,1 \"\n\"file3.pdf,,5-N``\"\nmsgstr \"``pymupdf join -o output.pdf file1.pdf,,N-1 file2.pdf,secret,N,1 file3.pdf,,5-N``\"\n\n#: ../../module.rst:171 45664921245f42c09b294edb251048f5\nmsgid \"Low Level Information\"\nmsgstr \"저수준 정보\"\n\n#: ../../module.rst:173 fdf3d7f12d914afe950de66d094693fa\nmsgid \"\"\n\"Display PDF internal information. Again, there are similarities to \"\n\"*\\\"mutool show\\\"*::\"\nmsgstr \"PDF 내부 정보를 표시합니다. 다시 말하지만, *\\\"mutool show\\\"* 와 유사점이 있습니다::\"\n\n#: ../../module.rst:194 ad5c07b578e24a87b4bdfa72f035288d\nmsgid \"Examples::\"\nmsgstr \"예제::\"\n\n#: ../../module.rst:243 a932285ed88f489cb35fb9fd00084410\nmsgid \"Embedded Files Commands\"\nmsgstr \"임베디드 파일 명령\"\n\n#: ../../module.rst:245 22fe7451356d4b07a68f7b814a48f7db\nmsgid \"\"\n\"The following commands deal with embedded files -- which is a feature \"\n\"completely removed from MuPDF after v1.14, and hence from all its command\"\n\" line tools.\"\nmsgstr \"다음 명령은 임베디드 파일을 다룹니다 -- 이것은 v1.14 이후 |MuPDF| 에서 완전히 제거된 기능이며, 따라서 모든 명령줄 도구에서도 제거되었습니다.\"\n\n#: ../../module.rst:248 031889fce5ba40c8aa00dca7f543935f\nmsgid \"Information\"\nmsgstr \"정보\"\n\n#: ../../module.rst:250 923441e6e99c4679913ea9650bd321f3\nmsgid \"Show the embedded file names (long or short format)::\"\nmsgstr \"임베디드 파일 이름을 표시합니다(긴 형식 또는 짧은 형식)::\"\n\n#: ../../module.rst:266 2938ace8fd974862bd2b852f6d01c1b5\nmsgid \"Example::\"\nmsgstr \"예제::\"\n\n#: ../../module.rst:287 4b906057dfa84c65ba2f7b3875e76f45\nmsgid \"Detailed output would look like this per entry::\"\nmsgstr \"각 항목에 대한 상세 출력은 다음과 같습니다::\"\n\n#: ../../module.rst:297 fa6b969dc09f4e7aa8ddad1a74b85f27\nmsgid \"Extraction\"\nmsgstr \"추출\"\n\n#: ../../module.rst:299 b95b620ad9f548139f65380c81a609eb\nmsgid \"Extract an embedded file like this::\"\nmsgstr \"다음과 같이 임베디드 파일을 추출합니다::\"\n\n#: ../../module.rst:317 b425246653d244139ee6064fef0cce03\nmsgid \"\"\n\"For details consult :meth:`Document.embfile_get`. Example (refer to \"\n\"previous section)::\"\nmsgstr \"자세한 내용은 :meth:`Document.embfile_get` 을 참조하세요. 예제(이전 섹션 참조)::\"\n\n#: ../../module.rst:323 beb7e7b57a2d40d7b80215a90a015016\nmsgid \"Deletion\"\nmsgstr \"삭제\"\n\n#: ../../module.rst:324 a66d4e86731745edabc9c4f4e5e0bb9f\nmsgid \"Delete an embedded file like this::\"\nmsgstr \"다음과 같이 임베디드 파일을 삭제합니다::\"\n\n#: ../../module.rst:340 c7c9134eddaa4ad2b9672122f1aa8fe9\nmsgid \"For details consult :meth:`Document.embfile_del`.\"\nmsgstr \"자세한 내용은 :meth:`Document.embfile_del` 을 참조하세요.\"\n\n#: ../../module.rst:343 8027d6ea455e4050ace1ead2c3a951fb\nmsgid \"Insertion\"\nmsgstr \"삽입\"\n\n#: ../../module.rst:344 05c0ffa1d1fd4495a04887a13fa6a0ff\nmsgid \"Add a new embedded file using this command::\"\nmsgstr \"다음 명령을 사용하여 새 임베디드 파일을 추가합니다::\"\n\n#: ../../module.rst:364 a3ce7e14c5a6493190e34f36253a7b11\nmsgid \"\"\n\"*\\\"NAME\\\"* **must not** already exist in the PDF. For details consult \"\n\":meth:`Document.embfile_add`.\"\nmsgstr \"*\\\"NAME\\\"* 은 PDF에 이미 존재해서는 **안 됩니다**. 자세한 내용은 :meth:`Document.embfile_add` 를 참조하세요.\"\n\n#: ../../module.rst:367 8b7188f7140248f2ace12ff2559a5810\nmsgid \"Updates\"\nmsgstr \"업데이트\"\n\n#: ../../module.rst:368 bf7de82ffcc6488492d7f1ed813a78d7\nmsgid \"Update an existing embedded file using this command::\"\nmsgstr \"다음 명령을 사용하여 기존 임베디드 파일을 업데이트합니다::\"\n\n#: ../../module.rst:393 dfb87b27e010457ea91a44ac1607508d\nmsgid \"\"\n\"Use this method to change meta-information of the file -- just omit the \"\n\"*\\\"PATH\\\"*. For details consult :meth:`Document.embfile_upd`.\"\nmsgstr \"이 메서드를 사용하여 파일의 메타 정보를 변경합니다 -- *\\\"PATH\\\"* 만 생략하면 됩니다. 자세한 내용은 :meth:`Document.embfile_upd` 를 참조하세요.\"\n\n#: ../../module.rst:397 9724107b71a3473586bf932f86556d37\nmsgid \"Copying\"\nmsgstr \"복사\"\n\n#: ../../module.rst:398 320c9dfca9614ce1aad38deec15e2f14\nmsgid \"Copy embedded files between PDFs::\"\nmsgstr \"PDF 간에 임베디드 파일을 복사합니다::\"\n\n#: ../../module.rst:422 4f474c3c92134dbf92a95d04287f6b7c\nmsgid \"Text Extraction\"\nmsgstr \"텍스트 추출\"\n\n#: ../../module.rst:423 10013955206643cdabf54b9427cf9162\nmsgid \"New in v1.18.16\"\nmsgstr \"v1.18.16의 새로운 기능\"\n\n#: ../../module.rst:425 6175e1799fe14be7857049aacbf4f76e\nmsgid \"\"\n\"Extract text from arbitrary :ref:`supported \"\n\"documents<Supported_File_Types>` to a textfile. Currently, there are \"\n\"three output formatting modes available: simple, block sorting and \"\n\"reproduction of physical layout.\"\nmsgstr \"임의의 :ref:`지원 문서<Supported_File_Types>` 에서 텍스트 파일로 텍스트를 추출합니다. 현재 세 가지 출력 형식 모드가 사용 가능합니다: simple, block sorting 및 물리적 레이아웃 재현.\"\n\n#: ../../module.rst:427 104746a6d24348c085e4d1f05530f3c4\nmsgid \"\"\n\"**Simple** text extraction reproduces all text as it appears in the \"\n\"document pages -- no effort is made to rearrange in any particular \"\n\"reading order.\"\nmsgstr \"**Simple** 텍스트 추출은 문서 페이지에 나타나는 대로 모든 텍스트를 재현합니다 -- 특정 읽기 순서로 재배열하려는 시도는 없습니다.\"\n\n#: ../../module.rst:428 46976f7ba91e4ed195d1d2970b450ce8\nmsgid \"\"\n\"**Block sorting** sorts text blocks (as identified by MuPDF) by ascending\"\n\" vertical, then horizontal coordinates. This should be sufficient to \"\n\"establish a \\\"natural\\\" reading order for basic pages of text.\"\nmsgstr \"**Block sorting** 은 텍스트 블록(|MuPDF| 에 의해 식별됨)을 수직 좌표, 그 다음 수평 좌표의 오름차순으로 정렬합니다. 이것은 기본 텍스트 페이지에 대한 \\\"자연스러운\\\" 읽기 순서를 설정하는 데 충분해야 합니다.\"\n\n#: ../../module.rst:429 736d584551084ce0ae8db3ab132de413\nmsgid \"\"\n\"**Layout** strives to reproduce the original appearance of the input \"\n\"pages. You can expect results like this (produced by the command `pymupdf\"\n\" gettext -pages 1 demo1.pdf`):\"\nmsgstr \"**Layout** 은 입력 페이지의 원래 모양을 재현하려고 합니다. 다음과 같은 결과를 기대할 수 있습니다(`pymupdf gettext -pages 1 demo1.pdf` 명령으로 생성됨):\"\n\n#: ../../module.rst:434 50eb59c01b5243e4a1beb240596e9fcf\nmsgid \"\"\n\"The \\\"gettext\\\" command offers a functionality similar to the CLI tool \"\n\"`pdftotext` by XPDF software, http://www.foolabs.com/xpdf/ -- this is \"\n\"especially true for \\\"layout\\\" mode, which combines that tool's `-layout`\"\n\" and `-table` options.\"\nmsgstr \"\\\"gettext\\\" 명령은 XPDF 소프트웨어의 CLI 도구 `pdftotext` (http://www.foolabs.com/xpdf/)와 유사한 기능을 제공합니다 -- 이것은 특히 해당 도구의 `-layout` 및 `-table` 옵션을 결합하는 \\\"layout\\\" 모드에 해당합니다.\"\n\n#: ../../module.rst:438 49563f540be445d984dba68ffffbfe02\nmsgid \"\"\n\"After each page of the output file, a formfeed character, `hex(12)` is \"\n\"written -- even if the input page has no text at all. This behavior can \"\n\"be controlled via options.\"\nmsgstr \"출력 파일의 각 페이지 후에 폼피드 문자 `hex(12)` 가 기록됩니다 -- 입력 페이지에 텍스트가 전혀 없는 경우에도 마찬가지입니다. 이 동작은 옵션을 통해 제어할 수 있습니다.\"\n\n#: ../../module.rst:440 647dbf1080904cb5b86c438feafcb584\nmsgid \"\"\n\"For \\\"layout\\\" mode, **only horizontal, left-to-right, top-to bottom** \"\n\"text is supported, other text is ignored. In this mode, text is also \"\n\"ignored, if its :data:`fontsize` is too small.\"\nmsgstr \"\\\"layout\\\" 모드의 경우, **수평, 왼쪽에서 오른쪽으로, 위에서 아래로** 텍스트만 지원되며 다른 텍스트는 무시됩니다. 이 모드에서 텍스트의 :data:`fontsize` 가 너무 작으면 텍스트도 무시됩니다.\"\n\n#: ../../module.rst:442 baeab1e7bac9497995324b659ebebf03\nmsgid \"\"\n\"\\\"Simple\\\" and \\\"blocks\\\" mode in contrast output **all text** for any \"\n\"text size or orientation.\"\nmsgstr \"대조적으로 \\\"Simple\\\" 및 \\\"blocks\\\" 모드는 모든 텍스트 크기나 방향에 대해 **모든 텍스트** 를 출력합니다.\"\n\n#: ../../module.rst:444 8617ac5a55024a57b4b1d70bdb264ced\nmsgid \"Command::\"\nmsgstr \"명령::\"\n\n#: ../../module.rst:472 f1019c52949f4174acd4b9381a394601\nmsgid \"\"\n\"Command options may be abbreviated as long as no ambiguities are \"\n\"introduced. So the following do the same:\"\nmsgstr \"명령 옵션은 모호함을 유발하지 않는 한 축약할 수 있습니다. 따라서 다음은 동일합니다:\"\n\n#: ../../module.rst:474 d70e9f44b99141809981474f2ff8b052\nmsgid \"\"\n\"`... -output text.txt -noligatures -noformfeed -convert-white -grid 3 \"\n\"-extra-spaces ...`\"\nmsgstr \"`... -output text.txt -noligatures -noformfeed -convert-white -grid 3 -extra-spaces ...`\"\n\n#: ../../module.rst:475 07cb51f3b38747abbb4010f810490249\nmsgid \"`... -o text.txt -nol -nof -c -g 3 -e ...`\"\nmsgstr \"`... -o text.txt -nol -nof -c -g 3 -e ...`\"\n\n#: ../../module.rst:477 f16b9ac2c6c14bd5bb7fcea64f1fcd80\nmsgid \"\"\n\"The output filename defaults to the input with its extension replaced by \"\n\"`.txt`. As with other commands, you can select page ranges **(caution: \"\n\"1-based!)** in `mutool` format, as indicated above.\"\nmsgstr \"출력 파일명은 기본적으로 입력 파일의 확장자가 `.txt` 로 대체된 것입니다. 다른 명령과 마찬가지로 위에서 표시한 대로 `mutool` 형식으로 페이지 범위를 선택할 수 있습니다 **(주의: 1부터 시작!)**.\"\n\n#: ../../module.rst:479 f23822348e0f44868acd1a434c638317\nmsgid \"**mode:** (str) select a formatting mode -- default is \\\"layout\\\".\"\nmsgstr \"**mode:** (str) 형식 모드를 선택합니다 -- 기본값은 \\\"layout\\\" 입니다.\"\n\n#: ../../module.rst:480 34f6f03b6b7c4d14b5b53d480ad19652\nmsgid \"\"\n\"**noligatures:** (bool) corresponds to **not** \"\n\":data:`TEXT_PRESERVE_LIGATURES`. If specified, ligatures (present in \"\n\"advanced fonts: glyphs combining multiple characters like \\\"fi\\\") are \"\n\"split up into their components (i.e. \\\"f\\\", \\\"i\\\"). Default is passing \"\n\"them through.\"\nmsgstr \"**noligatures:** (bool) :data:`TEXT_PRESERVE_LIGATURES` 를 **사용하지 않는** 것에 해당합니다. 지정하면 합자(고급 글꼴에 있음: \\\"fi\\\" 와 같은 여러 문자를 결합하는 글리프)가 구성 요소(즉, \\\"f\\\", \\\"i\\\")로 분할됩니다. 기본값은 통과시킵니다.\"\n\n#: ../../module.rst:481 7ad52df691114a03bf07a72f2434d4a9\nmsgid \"\"\n\"**convert-white:** corresponds to **not** \"\n\":data:`TEXT_PRESERVE_WHITESPACE`. If specified, all white space \"\n\"characters (like tabs) are replaced with one or more spaces. Default is \"\n\"passing them through.\"\nmsgstr \"**convert-white:** :data:`TEXT_PRESERVE_WHITESPACE` 를 **사용하지 않는** 것에 해당합니다. 지정하면 모든 공백 문자(탭 등)가 하나 이상의 공백으로 대체됩니다. 기본값은 통과시킵니다.\"\n\n#: ../../module.rst:482 b925a23489d24b3396cf53888050c32d\nmsgid \"\"\n\"**extra-spaces:**  (bool) corresponds to **not** \"\n\":data:`TEXT_INHIBIT_SPACES`. If specified, large gaps between adjacent \"\n\"characters will be filled with one or more spaces. Default is off.\"\nmsgstr \"**extra-spaces:** (bool) :data:`TEXT_INHIBIT_SPACES` 를 **사용하지 않는** 것에 해당합니다. 지정하면 인접 문자 사이의 큰 간격이 하나 이상의 공백으로 채워집니다. 기본값은 꺼짐입니다.\"\n\n#: ../../module.rst:483 9d95e72389b3445ba510fb682107c642\nmsgid \"\"\n\"**noformfeed:**  (bool) instead of `hex(12)` (formfeed), write linebreaks\"\n\" ``\\\\n`` at end of output pages.\"\nmsgstr \"**noformfeed:** (bool) `hex(12)` (폼피드) 대신 출력 페이지 끝에 줄바꿈 ``\\\\n`` 을 씁니다.\"\n\n#: ../../module.rst:484 703f5774d5234679a03f67da753bc40a\nmsgid \"**skip-empty:**  (bool) skip pages with no text.\"\nmsgstr \"**skip-empty:** (bool) 텍스트가 없는 페이지를 건너뜁니다.\"\n\n#: ../../module.rst:485 8f19a7610cc64fc88819c1b7fc295330\nmsgid \"\"\n\"**grid:** lines with a vertical coordinate difference of no more than \"\n\"this value (in points) will be merged into the same output line. Only \"\n\"relevant for \\\"layout\\\" mode. **Use with care:** 3 or the default 2 \"\n\"should be adequate in most cases. If **too large**, lines that are \"\n\"*intended* to be different in the original may be merged and will result \"\n\"in garbled and / or incomplete output. If **too low**, artifact separate \"\n\"output lines may be generated for some spans in the input line, just \"\n\"because they are coded in a different font with slightly deviating \"\n\"properties.\"\nmsgstr \"**grid:** 이 값(포인트 단위) 이하의 수직 좌표 차이를 가진 줄이 동일한 출력 줄로 병합됩니다. \\\"layout\\\" 모드에만 관련됩니다. **주의해서 사용하세요:** 대부분의 경우 3 또는 기본값 2가 적절합니다. **너무 크면**, 원본에서 *의도적으로* 다른 줄이 병합되어 왜곡되거나 불완전한 출력이 발생할 수 있습니다. **너무 낮으면**, 약간 다른 속성을 가진 다른 글꼴로 코딩되어 있기 때문에 입력 줄의 일부 범위에 대해 인공적인 별도 출력 줄이 생성될 수 있습니다.\"\n\n#: ../../module.rst:486 eac14db14ad14562a3b3b10a76827016\nmsgid \"\"\n\"**fontsize:** include text with :data:`fontsize` larger than this value \"\n\"only (default 3). Only relevant for \\\"layout\\\" option.\"\nmsgstr \"**fontsize:** 이 값보다 큰 :data:`fontsize` 를 가진 텍스트만 포함합니다(기본값 3). \\\"layout\\\" 옵션에만 관련됩니다.\"\n\n#: ../../footer.rst:46 bf24bcacdf454aba8a6c79d83a00209b\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/outline.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 bbc8f87339104f1898b46c688e53d1bf\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 c349cfed692041d1831e68981b1432f3\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 ccc1347133a5468990182905e2e49042\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../outline.rst:7 ac9aff233a8946e286c95d2a2f9a8e13\nmsgid \"Outline\"\nmsgstr \"Outline\"\n\n#: ../../outline.rst:9 7a3be59ed3114a5c8bffd3f17bbb2211\nmsgid \"\"\n\"The document outline (otherwise known as \\\"bookmarks\\\") is a property of \"\n\":ref:`Document` (see :attr:`Document.outline`). If not ``None``, it \"\n\"stands for the first outline item of the document. Its properties in turn\"\n\" define the characteristics of this item and also point to other outline \"\n\"items in \\\"horizontal\\\" or downward direction. The full tree of all \"\n\"outline items for e.g. a conventional table of contents (TOC) can be \"\n\"recovered by following these \\\"pointers\\\".\"\nmsgstr \"문서 개요(또는 \\\"북마크\\\"라고도 함)는 :ref:`Document` 의 속성입니다(:attr:`Document.outline` 참조). ``None`` 이 아니면 문서의 첫 번째 개요 항목을 나타냅니다. 그 속성은 이 항목의 특성을 정의하고 \\\"수평\\\" 또는 아래 방향으로 다른 개요 항목을 가리킵니다. 예를 들어 일반적인 목차(TOC)의 모든 개요 항목의 전체 트리는 이러한 \\\"포인터\\\"를 따라 복구할 수 있습니다.\"\n\n#: ../../outline.rst:12 b45a2c09637c4f3e9d2b01f1ba92a39f\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../outline.rst:12 47ad240edf4f474fa4acbc5fda0372cb\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../outline.rst:14 be403d58c4de4b12a011b9ed0d0e543f\nmsgid \":attr:`Outline.down`\"\nmsgstr \":attr:`Outline.down`\"\n\n#: ../../outline.rst:14 247939926687419fbfef8ca1aca02f0d\nmsgid \"next item downwards\"\nmsgstr \"아래로 다음 항목\"\n\n#: ../../outline.rst:15 96c69672ce3043259545e0e655eb91db\nmsgid \":attr:`Outline.next`\"\nmsgstr \":attr:`Outline.next`\"\n\n#: ../../outline.rst:15 4a5f23f96cf749c7872473b681590785\nmsgid \"next item same level\"\nmsgstr \"같은 레벨의 다음 항목\"\n\n#: ../../outline.rst:16 c573402a06284cd492bec3c1d27d1e3d\nmsgid \":attr:`Outline.page`\"\nmsgstr \":attr:`Outline.page`\"\n\n#: ../../outline.rst:16 506be6a2e42d4302bdbc7b4e28e2394d\nmsgid \"page number (0-based)\"\nmsgstr \"페이지 번호(0부터 시작)\"\n\n#: ../../outline.rst:17 f119da14666b4fd3b371cf4ffc3e472a\nmsgid \":attr:`Outline.title`\"\nmsgstr \":attr:`Outline.title`\"\n\n#: ../../outline.rst:17 76ae4b21a6a6447da64b2d5e96423ea6\nmsgid \"title\"\nmsgstr \"제목\"\n\n#: ../../outline.rst:18 a5fad59c22974e90b9ea8aad24218452\nmsgid \":attr:`Outline.uri`\"\nmsgstr \":attr:`Outline.uri`\"\n\n#: ../../outline.rst:18 841c94119419481b8d836018ece01af9\nmsgid \"string further specifying outline target\"\nmsgstr \"개요 대상을 추가로 지정하는 문자열\"\n\n#: ../../outline.rst:19 8cfeb148873e49c09a78d54e1a2f77c6\nmsgid \":attr:`Outline.is_external`\"\nmsgstr \":attr:`Outline.is_external`\"\n\n#: ../../outline.rst:19 8a8f02b1287645c8905eec8793a1b5b6\nmsgid \"target outside document\"\nmsgstr \"문서 외부 대상\"\n\n#: ../../outline.rst:20 5de9d126a21d480a9e1ca3476bebb4d3\nmsgid \":attr:`Outline.is_open`\"\nmsgstr \":attr:`Outline.is_open`\"\n\n#: ../../outline.rst:20 7fc18da2ba4d4cbe9f3b2a82d39f02da\nmsgid \"whether sub-outlines are open or collapsed\"\nmsgstr \"하위 개요가 열려 있는지 접혀 있는지 여부\"\n\n#: ../../outline.rst:21 6aa64d2eff674fa2890310aecbb14167\nmsgid \":attr:`Outline.dest`\"\nmsgstr \":attr:`Outline.dest`\"\n\n#: ../../outline.rst:21 0a87f99431e642139f4b43d536359abe\nmsgid \"points to destination details object\"\nmsgstr \"대상 세부 정보 객체를 가리킴\"\n\n#: ../../outline.rst:24 5ed102082bf84d049ca1f0ce22437f31\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../outline.rst:30 7b0ddca9a47d4e648ebdab93710cb150\nmsgid \"\"\n\"The next outline item on the next level down. Is ``None`` if the item has\"\n\" no children.\"\nmsgstr \"다음 레벨의 다음 개요 항목. 항목에 자식이 없으면 ``None`` 입니다.\"\n\n#: ../../outline.rst 057e37ce84814a1c8c344aab938047f2\n#: 1e93414e062d488e892d2f22750666de 76ab3bd1d70641f185a95f718ad0bb69\n#: 7bd6079115d0441a82b8de2daaa1f4f9 9ecaaca5f8fd42c5b695d3f7ac9a5477\n#: bc6ef4078c8a4c91a859ae4437517df7 e5dc2bd2705743d59033178491288a7a\n#: ea89654da5734c92aa2797336d8dfbc6\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../outline.rst:32 8b64d66496a54db0908a0f6af0d7969e\nmsgid \":ref:`Outline`\"\nmsgstr \":ref:`Outline`\"\n\n#: ../../outline.rst:36 b8f40bec44ec498a866b8b610465788d\nmsgid \"\"\n\"The next outline item at the same level as this item. Is ``None`` if this\"\n\" is the last one in its level.\"\nmsgstr \"이 항목과 같은 레벨의 다음 개요 항목. 이것이 해당 레벨의 마지막 항목이면 ``None`` 입니다.\"\n\n#: ../../outline.rst:38 78788e777e334a73bb007bf2b10702b8\nmsgid \"`Outline`\"\nmsgstr \"`Outline`\"\n\n#: ../../outline.rst:42 e0f2f185ffc545688e36397b2ab22051\nmsgid \"The page number (0-based) this bookmark points to.\"\nmsgstr \"이 북마크가 가리키는 페이지 번호(0부터 시작).\"\n\n#: ../../outline.rst:44 f47207285d9f4747a109ad0f93928b78\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../outline.rst:48 53ed66d010ce46c8a8afa6580844ac5d\nmsgid \"The item's title as a string or ``None``.\"\nmsgstr \"항목의 제목(문자열) 또는 ``None``.\"\n\n#: ../../outline.rst:50 ../../outline.rst:83 f43c0734193d4aedae69249948755e99\n#: fc9bbc88a2e842c090ac4d2ea7adf221\nmsgid \"str\"\nmsgstr \"str\"\n\n#: ../../outline.rst:54 d0a15fed61c5446e815f91424b141eab\nmsgid \"\"\n\"Indicator showing whether any sub-outlines should be expanded (``True``) \"\n\"or be collapsed (``False``). This information is interpreted by PDF \"\n\"reader software.\"\nmsgstr \"하위 개요가 확장되어야 하는지(``True``) 접혀야 하는지(``False``)를 나타내는 표시기입니다. 이 정보는 PDF 리더 소프트웨어에 의해 해석됩니다.\"\n\n#: ../../outline.rst:56 ../../outline.rst:62 1e2367a870064e0ab9fefe235f8f9199\n#: 309c517aaa49400181d997b03fb6d487\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../outline.rst:60 eabf7026067444bd881e44370ac424e5\nmsgid \"\"\n\"A bool specifying whether the target is outside (``True``) of the current\"\n\" document.\"\nmsgstr \"대상이 현재 문서 외부(``True``)인지 여부를 지정하는 bool입니다.\"\n\n#: ../../outline.rst:66 6e1ed475f293437aa748d4d40f55bbc0\nmsgid \"\"\n\"A string specifying the link target. The meaning of this property should \"\n\"be evaluated in conjunction with property `is_external`:\"\nmsgstr \"링크 대상을 지정하는 문자열입니다. 이 속성의 의미는 `is_external` 속성과 함께 평가해야 합니다:\"\n\n#: ../../outline.rst:70 048200e34ebe4f88b8f6ecdfad9e9724\nmsgid \"\"\n\"`is_external` is true: ``uri`` points to some target outside the current \"\n\"PDF, which may be an internet resource (``uri`` starts with ``http://`` \"\n\"or similar), another file (``uri`` starts with ``file:`` or ``file://``) \"\n\"or some other service like an e-mail address (``uri`` starts with \"\n\"``mailto:``).\"\nmsgstr \"`is_external` 이 true: ``uri`` 는 현재 PDF 외부의 대상을 가리키며, 인터넷 리소스(``uri`` 가 ``http://`` 또는 유사한 것으로 시작), 다른 파일(``uri`` 가 ``file:`` 또는 ``file://`` 로 시작) 또는 이메일 주소와 같은 기타 서비스(``uri`` 가 ``mailto:`` 로 시작)일 수 있습니다.\"\n\n#: ../../outline.rst:76 e2b37e452977480aadfbf5e2b8eb7ced\nmsgid \"\"\n\"`is_external` is false: ``uri`` will be `None` or point to an internal \"\n\"location. In case of PDF documents, this should either be *#nnnn* to \"\n\"indicate a 1-based (!) page number *nnnn*, or a named location. The \"\n\"format varies for other document types, for example \"\n\"\\\"../FixedDoc.fdoc#PG_2_LNK_1\\\" for page number 2 (1-based) in an XPS \"\n\"document.\"\nmsgstr \"`is_external` 이 false: ``uri`` 는 `None` 이거나 내부 위치를 가리킵니다. PDF 문서의 경우, 이것은 1부터 시작하는(!) 페이지 번호 *nnnn* 을 나타내는 *#nnnn* 이거나 이름이 지정된 위치여야 합니다. 형식은 다른 문서 유형에 따라 다릅니다. 예를 들어 XPS 문서의 페이지 번호 2(1부터 시작)의 경우 \\\"../FixedDoc.fdoc#PG_2_LNK_1\\\"입니다.\"\n\n#: ../../outline.rst:87 0774302e2b4a4cc5be36f90e97235665\nmsgid \"The link destination details object.\"\nmsgstr \"링크 대상 세부 정보 객체.\"\n\n#: ../../outline.rst:89 2c95888d87c844888823cf7c4bfbdd8d\nmsgid \":ref:`linkDest`\"\nmsgstr \":ref:`linkDest`\"\n\n#: ../../footer.rst:46 3da3281d20a349b2afbe0ca6afa704a3\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/packaging.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 3c04d07515a94932a13a95ebeb03dd64\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 bfe728bc4ddc474bb035cd55e714eabf\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 cdf2aaae85c74803bd7026f6e124be96\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../packaging.rst:5 348e8764195645e2bf7ae0ae58e6672e\nmsgid \"Packaging for Linux distributions\"\nmsgstr \"Linux 배포판용 패키징\"\n\n#: ../../packaging.rst:9 cb613445a87e445abba22e57ddb58ec7\nmsgid \"Requirements\"\nmsgstr \"요구사항\"\n\n#: ../../packaging.rst:11 b36b1e7d3fc94b0d9d5c31f4cae79c63\nmsgid \"Python\"\nmsgstr \"Python\"\n\n#: ../../packaging.rst:12 4edcec2efc2d4308ad735f013faa422e\nmsgid \"MuPDF checkout (including submodules).\"\nmsgstr \"|MuPDF| 체크아웃(서브모듈 포함).\"\n\n#: ../../packaging.rst:13 c463c998f736479f892c6b4c57f77d89\nmsgid \"PyMuPDF checkout.\"\nmsgstr \"|PyMuPDF| 체크아웃.\"\n\n#: ../../packaging.rst:14 dbadca79b99f4a80ace5240c78bde785\nmsgid \"System packages listed in `scripts/sysinstall.py:g_sys_packages`.\"\nmsgstr \"`scripts/sysinstall.py:g_sys_packages` 에 나열된 시스템 패키지.\"\n\n#: ../../packaging.rst:15 760e1814501643e8ba68b67bc653f179\nmsgid \"Python packages listed in `pyproject.toml`.\"\nmsgstr \"`pyproject.toml` 에 나열된 Python 패키지.\"\n\n#: ../../packaging.rst:17 7b5ae3db64eb472daed8e6bad3fbf7ac\nmsgid \"Extra requirements for running tests:\"\nmsgstr \"테스트 실행을 위한 추가 요구사항:\"\n\n#: ../../packaging.rst:19 c7033e7fd7804ba48daa32be3ccdaa7b\nmsgid \"Python packages listed in `scripts/gh_release.py:test_packages`.\"\nmsgstr \"`scripts/gh_release.py:test_packages` 에 나열된 Python 패키지.\"\n\n#: ../../packaging.rst:23 d087313018614125b4e745ef56fc63d1\nmsgid \"General steps\"\nmsgstr \"일반적인 단계\"\n\n#: ../../packaging.rst:25 ff845be31dc6431c907ec57f88327d5f\nmsgid \"Build and install MuPDF:\"\nmsgstr \"|MuPDF| 빌드 및 설치:\"\n\n#: ../../packaging.rst:27 22584c396cc342bfba772fe8c81ac949\nmsgid \"Install required system packages.\"\nmsgstr \"필요한 시스템 패키지를 설치합니다.\"\n\n#: ../../packaging.rst:28 f7c3f08a80c141d49a7a07a13474c1bb\nmsgid \"\"\n\"Run `make install-shared-python` on MuPDF's `Makefile` with at least \"\n\"these make variables:\"\nmsgstr \"|MuPDF| 의 `Makefile` 에서 최소한 다음 make 변수를 사용하여 `make install-shared-python` 을 실행합니다:\"\n\n#: ../../packaging.rst:31 9d49af42c3a74272b78d5e68b8a53863\nmsgid \"`DESTDIR` set to the install directory, e.g. `/`.\"\nmsgstr \"`DESTDIR` 를 설치 디렉토리로 설정합니다. 예: `/`.\"\n\n#: ../../packaging.rst:33 c80bf2b5d6aa48a3ab8da81dcde780cb\nmsgid \"\"\n\"`prefix` set to location relative to DESTDIR, such as `/usr/local` or \"\n\"`/usr`. Must start with `/`.\"\nmsgstr \"`prefix` 를 DESTDIR에 상대적인 위치로 설정합니다. 예: `/usr/local` 또는 `/usr`. `/` 로 시작해야 합니다.\"\n\n#: ../../packaging.rst:35 11c2299023db4fb19e56a64ef4be5424\nmsgid \"`USE_SYSTEM_LIBS=yes`.\"\nmsgstr \"`USE_SYSTEM_LIBS=yes`.\"\n\n#: ../../packaging.rst:36 1384b7538ae5481a97b504d24690c056\nmsgid \"`HAVE_LEPTONICA=yes`.\"\nmsgstr \"`HAVE_LEPTONICA=yes`.\"\n\n#: ../../packaging.rst:37 06ed0058c43d461db82d505a23ca7094\nmsgid \"`HAVE_TESSERACT=yes`.\"\nmsgstr \"`HAVE_TESSERACT=yes`.\"\n\n#: ../../packaging.rst:39 b3644dcc2c5943bf888d7f8e9dc9edcc\nmsgid \"Build and install PyMuPDF:\"\nmsgstr \"|PyMuPDF| 빌드 및 설치:\"\n\n#: ../../packaging.rst:42 dcf39ffe359c4c03b4de4f59838ee0f0\nmsgid \"\"\n\"Run `pip install ./PyMuPDF` or `pip wheel ./PyMuPDF` with at least these \"\n\"environment variables:\"\nmsgstr \"최소한 다음 환경 변수를 사용하여 `pip install ./PyMuPDF` 또는 `pip wheel ./PyMuPDF` 를 실행합니다:\"\n\n#: ../../packaging.rst:46 93b07ed437f44924bb31820bb149fa1f\nmsgid \"\"\n\"`PYMUPDF_SETUP_MUPDF_BUILD=` (empty string) to prevent download and build\"\n\" of hard-coded MuPDF release.\"\nmsgstr \"`PYMUPDF_SETUP_MUPDF_BUILD=` (빈 문자열)을 설정하여 하드코딩된 |MuPDF| 릴리스의 다운로드 및 빌드를 방지합니다.\"\n\n#: ../../packaging.rst:49 9ca48e9bfca64481b10e5c28ce400a6a\nmsgid \"\"\n\"`CFLAGS`, `CXXFLAGS` and `LDFLAGS` set to allow visibility of the \"\n\"installed MuPDF headers and shared libraries.\"\nmsgstr \"`CFLAGS`, `CXXFLAGS` 및 `LDFLAGS` 를 설정하여 설치된 |MuPDF| 헤더 및 공유 라이브러리의 가시성을 허용합니다.\"\n\n#: ../../packaging.rst:52 4361b9dfe3094baeaee44b1e98a85735\nmsgid \"Run PyMuPDF tests:\"\nmsgstr \"|PyMuPDF| 테스트 실행:\"\n\n#: ../../packaging.rst:54 31da2ee092e74396895c9811cd72275d\nmsgid \"Ensure required Python packages are available.\"\nmsgstr \"필요한 Python 패키지를 사용할 수 있는지 확인합니다.\"\n\n#: ../../packaging.rst:56 027bc04d851d4711a60c825c34fd582c\nmsgid \"Run `pytest -k \\\"not test_color_count and not test_3050\\\" PyMuPDF`\"\nmsgstr \"`pytest -k \\\"not test_color_count and not test_3050\\\" PyMuPDF` 를 실행합니다\"\n\n#: ../../packaging.rst:58 c29cbb8f2791439fb47faf2ea2080ca8\nmsgid \"\"\n\"Test `test_color_count` is known fail if MuPDF is not built with \"\n\"PyMuPDF's custom config.h.\"\nmsgstr \"`test_color_count` 테스트는 |MuPDF| 가 |PyMuPDF| 의 사용자 정의 config.h로 빌드되지 않은 경우 실패하는 것으로 알려져 있습니다.\"\n\n#: ../../packaging.rst:59 366f92e009ee412b9ee326e53365c80b\nmsgid \"\"\n\"Test `test_3050` is known to fail if MuPDF is built without its own \"\n\"third-party libraries.\"\nmsgstr \"`test_3050` 테스트는 |MuPDF| 가 자체 서드파티 라이브러리 없이 빌드된 경우 실패하는 것으로 알려져 있습니다.\"\n\n#: ../../packaging.rst:63 dc265d226e3549d395d1ee9b84d7e9b7\nmsgid \"Use of scripts/sysinstall.py\"\nmsgstr \"scripts/sysinstall.py 사용\"\n\n#: ../../packaging.rst:65 c5ccd53c72ae43e2a8514ab3361d7530\nmsgid \"\"\n\"`scripts/sysinstall.py` provides a useful example of build, install and \"\n\"test commands that are known to to work, because it is run regularly by \"\n\"Github action `.github/workflows/test_sysinstall.yml`.\"\nmsgstr \"`scripts/sysinstall.py` 는 GitHub 액션 `.github/workflows/test_sysinstall.yml` 에 의해 정기적으로 실행되기 때문에 작동하는 것으로 알려진 빌드, 설치 및 테스트 명령의 유용한 예제를 제공합니다.\"\n\n#: ../../packaging.rst:69 82d7e8c0cbc44e7ba2c922716b3572df\nmsgid \"Run with `-h` or look at the doc-string to see detailed usage information.\"\nmsgstr \"`-h` 옵션으로 실행하거나 doc-string을 확인하여 자세한 사용 정보를 확인하세요.\"\n\n#: ../../packaging.rst:70 3e72131ea5f546a3b3328a8e07d2f12c\nmsgid \"It uses Debian-style `apt` commands to install system packages.\"\nmsgstr \"시스템 패키지를 설치하는 데 Debian 스타일의 `apt` 명령을 사용합니다.\"\n\n#: ../../packaging.rst:71 d7d9461807534464806ed713797d4c4a\nmsgid \"By default it assumes local git checkouts `mupdf/` and `PyMuPDF/`.\"\nmsgstr \"기본적으로 로컬 git 체크아웃 `mupdf/` 및 `PyMuPDF/` 를 가정합니다.\"\n\n#: ../../packaging.rst:73 ef0294479d1943c0b9a9320a2d3a26d5\nmsgid \"\"\n\"To run a full build, install and test for both a local fake root and the \"\n\"system root:\"\nmsgstr \"로컬 가짜 루트와 시스템 루트 모두에 대해 전체 빌드, 설치 및 테스트를 실행하려면:\"\n\n#: ../../packaging.rst:81 541b01cd5c274ffdb287b2e4615b1dcc\nmsgid \"To see what commands would be run without actually running them:\"\nmsgstr \"실제로 실행하지 않고 실행될 명령을 보려면:\"\n\n#: ../../packaging.rst:89 a1980a6d8b4e4ff483c5461aa5c7c9a2\nmsgid \"See also\"\nmsgstr \"참고\"\n\n#: ../../packaging.rst:92 8dfdf3477c0c47799dc0f20fc9645ebe\nmsgid \"\"\n\"`setup.py`'s initial doc-comment has detailed information about the \"\n\"environment variables used when building PyMuPDF.\"\nmsgstr \"`setup.py` 의 초기 doc-comment에는 |PyMuPDF| 를 빌드할 때 사용되는 환경 변수에 대한 자세한 정보가 포함되어 있습니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/page.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-03 09:30+0900\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../header.rst:-1 e16c032122ad4e028bed74389ed639aa\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 9732656e336643c0a3688f6451a5d129\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF(및 기타) 문서의 데이터 추출, 분석, 변환 및 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8784bd6bb15a493cb1459dea2fd1c45d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../page.rst:7 ce1211f275594a9799c196eda5262e29\nmsgid \"Page\"\nmsgstr \"Page\"\n\n#: ../../page.rst:9 521a22f6c2494b1d8774bbf21c40a438\nmsgid \"\"\n\"Class representing a document page. A page object is created by \"\n\":meth:`Document.load_page` or, equivalently, via indexing the document \"\n\"like `doc[n]` - it has no independent constructor.\"\nmsgstr \"\"\n\"문서 페이지를 나타내는 클래스. 페이지 객체는 :meth:`Document.load_page` 또는 동등하게 `doc[n]` 과 \"\n\"같이 문서를 인덱싱하여 생성됩니다 - 독립적인 생성자가 없습니다.\"\n\n#: ../../page.rst:11 926d97edf1a148ba86e31fc4a0907173\nmsgid \"\"\n\"There is a parent-child relationship between a document and its pages. If\"\n\" the document is closed or deleted, all page objects (and their \"\n\"respective children, too) in existence will become unusable \"\n\"(\\\"orphaned\\\"): If a page property or method is being used, an exception \"\n\"is raised.\"\nmsgstr \"\"\n\"문서와 페이지 간에는 부모-자식 관계가 있습니다. 문서가 닫히거나 삭제되면 존재하는 모든 페이지 객체(및 각각의 자식도)가 사용 \"\n\"불가능해집니다(\\\"고아\\\"): 페이지 속성이나 메서드가 사용되면 예외가 발생합니다.\"\n\n#: ../../page.rst:13 63842982bdce4d8b9ab736778c00f188\nmsgid \"\"\n\"Several page methods have a :ref:`Document` counterpart for convenience. \"\n\"At the end of this chapter you will find a synopsis.\"\nmsgstr \"편의를 위해 여러 페이지 메서드에는 :ref:`Document` 대응 항목이 있습니다. 이 장의 끝에서 요약을 찾을 수 있습니다.\"\n\n#: ../../page.rst:15 1002d10886004b41a5902ec4640a3912\nmsgid \"\"\n\"Many times in this chapter we are using the term **coordinate**. It is of\"\n\" high importance to have at least a basic understanding of what that is \"\n\"and that you feel comfortable with the section :ref:`Coordinates`.\"\nmsgstr \"\"\n\"이 장에서 여러 번 **좌표** 라는 용어를 사용합니다. 그것이 무엇인지에 대한 기본적인 이해를 갖추고 \"\n\":ref:`Coordinates` 섹션에 익숙해지는 것이 매우 중요합니다.\"\n\n#: ../../page.rst:18 e1df1b1166044863ac89785a4b65c771\nmsgid \"Modifying Pages\"\nmsgstr \"페이지 수정\"\n\n#: ../../page.rst:19 6f307a8c6a02449cbfeb3416e092240f\nmsgid \"\"\n\"Changing page properties and adding or changing page content is available\"\n\" for PDF documents only.\"\nmsgstr \"페이지 속성 변경 및 페이지 콘텐츠 추가 또는 변경은 PDF 문서에서만 사용할 수 있습니다.\"\n\n#: ../../page.rst:21 d491d2d2fb334bafbb8919f76e2e8238\nmsgid \"In a nutshell, this is what you can do with PyMuPDF:\"\nmsgstr \"간단히 말하면, |PyMuPDF| 로 할 수 있는 것은 다음과 같습니다:\"\n\n#: ../../page.rst:23 d90792749a9349219c93cc569263ed38\nmsgid \"Modify page rotation and the visible part (\\\"cropbox\\\") of the page.\"\nmsgstr \"페이지 회전 및 페이지의 보이는 부분(\\\"cropbox\\\")을 수정합니다.\"\n\n#: ../../page.rst:24 58fd1c6d537c448fbd8f5d264a78c21d\nmsgid \"Insert images, other PDF pages, text and simple geometrical objects.\"\nmsgstr \"이미지, 다른 PDF 페이지, 텍스트 및 간단한 기하학적 객체를 삽입합니다.\"\n\n#: ../../page.rst:25 a12337916b2f4e5ab028230f71a556eb\nmsgid \"Add annotations and form fields.\"\nmsgstr \"주석 및 양식 필드를 추가합니다.\"\n\n#: ../../page.rst:29 11cc1d708f504056baa21c4fed8f0b94\nmsgid \"\"\n\"Methods require coordinates (points, rectangles) to put content in \"\n\"desired places. Please be aware that these coordinates **must always** be\"\n\" provided relative to the **unrotated** page (since v1.17.0). The reverse\"\n\" is also true: except :attr:`Page.rect`, resp. :meth:`Page.bound` (both \"\n\"*reflect* when the page is rotated), all coordinates returned by methods \"\n\"and attributes pertain to the unrotated page.\"\nmsgstr \"\"\n\"원하는 위치에 콘텐츠를 배치하기 위해 좌표(점, 사각형)가 필요합니다. 이러한 좌표는 **항상** **회전되지 않은** 페이지를 \"\n\"기준으로 제공되어야 합니다(v1.17.0부터). 역도 마찬가지입니다: :attr:`Page.rect`, 각각 \"\n\":meth:`Page.bound` (둘 다 페이지가 회전될 때 *반영* 됨)를 제외하고, 메서드와 속성에서 반환된 모든 좌표는 \"\n\"회전되지 않은 페이지에 해당합니다.\"\n\n#: ../../page.rst:31 56d8c3ede59e4cd6b94ed6b542aa071f\nmsgid \"\"\n\"So the returned value of e.g. :meth:`Page.get_image_bbox` will not change\"\n\" if you do a :meth:`Page.set_rotation`. The same is true for coordinates \"\n\"returned by :meth:`Page.get_text`, annotation rectangles, and so on. If \"\n\"you want to find out, where an object is located in **rotated \"\n\"coordinates**, multiply the coordinates with \"\n\":attr:`Page.rotation_matrix`. There also is its inverse, \"\n\":attr:`Page.derotation_matrix`, which you can use when interfacing with \"\n\"other readers, which may behave differently in this respect.\"\nmsgstr \"\"\n\"따라서 예를 들어 :meth:`Page.get_image_bbox` 의 반환 값은 :meth:`Page.set_rotation` 을\"\n\" 수행해도 변경되지 않습니다. :meth:`Page.get_text`, 주석 사각형 등에서 반환된 좌표도 마찬가지입니다. 객체가 \"\n\"**회전된 좌표** 에서 어디에 있는지 확인하려면 좌표에 :attr:`Page.rotation_matrix` 를 곱하세요. 역행렬인\"\n\" :attr:`Page.derotation_matrix` 도 있으며, 이 점에서 다르게 동작할 수 있는 다른 리더와 인터페이스할 때\"\n\" 사용할 수 있습니다.\"\n\n#: ../../page.rst:35 5495c71af02f4a8fb149edfa02294e00\nmsgid \"\"\n\"If you add or update annotations, links or form fields on the page and \"\n\"immediately afterwards need to work with them (i.e. **without leaving the\"\n\" page**), you should reload the page using :meth:`Document.reload_page` \"\n\"before referring to these new or updated items.\"\nmsgstr \"\"\n\"페이지에 주석, 링크 또는 양식 필드를 추가하거나 업데이트하고 즉시 작업해야 하는 경우(즉, **페이지를 떠나지 않고**), 이러한\"\n\" 새 항목이나 업데이트된 항목을 참조하기 전에 :meth:`Document.reload_page` 를 사용하여 페이지를 다시 \"\n\"로드해야 합니다.\"\n\n#: ../../page.rst:37 5b62e6a60cbe406cb33ca34fdcdf3756\nmsgid \"\"\n\"Reloading the page is generally recommended -- although not strictly \"\n\"required in all cases. However, some annotation and widget types have \"\n\"extended features in PyMuPDF compared to MuPDF. More of these extensions \"\n\"may also be added in the future.\"\nmsgstr \"\"\n\"페이지 다시 로드는 일반적으로 권장됩니다 -- 모든 경우에 엄격하게 필요하지는 않지만. 그러나 일부 주석 및 위젯 타입은 \"\n\"MuPDF와 비교하여 |PyMuPDF| 에서 확장 기능을 가지고 있습니다. 이러한 확장 기능이 더 추가될 수도 있습니다.\"\n\n#: ../../page.rst:39 9b46165bcb584587982fd25c63ab3c8a\nmsgid \"\"\n\"Releoading the page ensures all your changes have been fully applied to \"\n\"PDF structures, so you can safely create Pixmaps or successfully iterate \"\n\"over annotations, links and form fields.\"\nmsgstr \"\"\n\"페이지를 다시 로드하면 모든 변경 사항이 PDF 구조에 완전히 적용되므로 Pixmap을 안전하게 만들거나 주석, 링크 및 양식 \"\n\"필드를 성공적으로 반복할 수 있습니다.\"\n\n#: ../../page.rst:42 94074d33706748ee9033e7d4bb141a7a\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../page.rst:42 75670f2660794ca6a8f34c6abe09eeed\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../page.rst:44 93d8511e8ebf40a7b1b729cf36aa03d4\nmsgid \":meth:`Page.add_caret_annot`\"\nmsgstr \":meth:`Page.add_caret_annot`\"\n\n#: ../../page.rst:44 fe25471b8e5b4df8b2c71ef4d98cfc43\nmsgid \"PDF only: add a caret annotation\"\nmsgstr \"PDF 전용: 캐럿 주석 추가\"\n\n#: ../../page.rst:45 e3bdedcdb54b4c20aa6a621d8d977bcb\nmsgid \":meth:`Page.add_circle_annot`\"\nmsgstr \":meth:`Page.add_circle_annot`\"\n\n#: ../../page.rst:45 2bccbccc57b34072ada8dedb56d423c3\nmsgid \"PDF only: add a circle annotation\"\nmsgstr \"PDF 전용: 원형 주석 추가\"\n\n#: ../../page.rst:46 1b1436b811974ae8af7345271edb8298\nmsgid \":meth:`Page.add_file_annot`\"\nmsgstr \":meth:`Page.add_file_annot`\"\n\n#: ../../page.rst:46 616bbd5f9f334dd4a3b026d3b6d8f8a6\nmsgid \"PDF only: add a file attachment annotation\"\nmsgstr \"PDF 전용: 파일 첨부 주석 추가\"\n\n#: ../../page.rst:47 58a43a7d9941416683a8baa88d2b0274\nmsgid \":meth:`Page.add_freetext_annot`\"\nmsgstr \":meth:`Page.add_freetext_annot`\"\n\n#: ../../page.rst:47 df78ea811bc646eb900266047ec923a3\nmsgid \"PDF only: add a text annotation\"\nmsgstr \"PDF 전용: 텍스트 주석 추가\"\n\n#: ../../page.rst:48 60250ea28c6647cba024dc476244187f\nmsgid \":meth:`Page.add_highlight_annot`\"\nmsgstr \":meth:`Page.add_highlight_annot`\"\n\n#: ../../page.rst:48 702ae035409c46c5963108c602141009\nmsgid \"PDF only: add a \\\"highlight\\\" annotation\"\nmsgstr \"PDF 전용: \\\"강조\\\" 주석 추가\"\n\n#: ../../page.rst:49 f8da534a97ec46fcabe2fa2776737a67\nmsgid \":meth:`Page.add_ink_annot`\"\nmsgstr \":meth:`Page.add_ink_annot`\"\n\n#: ../../page.rst:49 492961a934c9486b9e9790906dc0363e\nmsgid \"PDF only: add an ink annotation\"\nmsgstr \"PDF 전용: 잉크 주석 추가\"\n\n#: ../../page.rst:50 5c700ca90cfb47c284dc5d12b68f87cf\nmsgid \":meth:`Page.add_line_annot`\"\nmsgstr \":meth:`Page.add_line_annot`\"\n\n#: ../../page.rst:50 3beaa2a61bfe4649b8072d9d7b3db5cf\nmsgid \"PDF only: add a line annotation\"\nmsgstr \"PDF 전용: 선 주석 추가\"\n\n#: ../../page.rst:51 8e3053db158f4cf4a38eaca8f62bf82e\nmsgid \":meth:`Page.add_polygon_annot`\"\nmsgstr \":meth:`Page.add_polygon_annot`\"\n\n#: ../../page.rst:51 c396774dd4ad430180ad8bcd7a870076\nmsgid \"PDF only: add a polygon annotation\"\nmsgstr \"PDF 전용: 다각형 주석 추가\"\n\n#: ../../page.rst:52 899d9130f087402183b36be01e8fd467\nmsgid \":meth:`Page.add_polyline_annot`\"\nmsgstr \":meth:`Page.add_polyline_annot`\"\n\n#: ../../page.rst:52 5b67d817b049400ca64fd45749d2a73a\nmsgid \"PDF only: add a multi-line annotation\"\nmsgstr \"PDF 전용: 다중선 주석 추가\"\n\n#: ../../page.rst:53 ac94a88db1a945ea8624710afea132e3\nmsgid \":meth:`Page.add_rect_annot`\"\nmsgstr \":meth:`Page.add_rect_annot`\"\n\n#: ../../page.rst:53 c822265b995748939fb6f4e1cd832b4c\nmsgid \"PDF only: add a rectangle annotation\"\nmsgstr \"PDF 전용: 사각형 주석 추가\"\n\n#: ../../page.rst:54 00e37d1d767341c68663be9358ecc369\nmsgid \":meth:`Page.add_redact_annot`\"\nmsgstr \":meth:`Page.add_redact_annot`\"\n\n#: ../../page.rst:54 eabcf1844b7c444286ffecdcc20508bc\nmsgid \"PDF only: add a redaction annotation\"\nmsgstr \"PDF 전용: 수정 주석 추가\"\n\n#: ../../page.rst:55 4c82f8bd39eb48039d304e70ecfcc40d\nmsgid \":meth:`Page.add_squiggly_annot`\"\nmsgstr \":meth:`Page.add_squiggly_annot`\"\n\n#: ../../page.rst:55 6424b91d9a5f4e938881c3daf0930076\nmsgid \"PDF only: add a \\\"squiggly\\\" annotation\"\nmsgstr \"PDF 전용: \\\"물결선\\\" 주석 추가\"\n\n#: ../../page.rst:56 0deda877c85844bdb4116e19e446478b\nmsgid \":meth:`Page.add_stamp_annot`\"\nmsgstr \":meth:`Page.add_stamp_annot`\"\n\n#: ../../page.rst:56 60caeb4508d74196b16df227d730dcf9\nmsgid \"PDF only: add a \\\"rubber stamp\\\" annotation\"\nmsgstr \"PDF 전용: \\\"고무 도장\\\" 주석 추가\"\n\n#: ../../page.rst:57 e9bca0a5a98842f6a9fa657758bbde00\nmsgid \":meth:`Page.add_strikeout_annot`\"\nmsgstr \":meth:`Page.add_strikeout_annot`\"\n\n#: ../../page.rst:57 7c3096dd58da4af5a5c81213f8dcea99\nmsgid \"PDF only: add a \\\"strike-out\\\" annotation\"\nmsgstr \"PDF 전용: \\\"취소선\\\" 주석 추가\"\n\n#: ../../page.rst:58 ec81831ff1a34e12933ad4fe97ddfc72\nmsgid \":meth:`Page.add_text_annot`\"\nmsgstr \":meth:`Page.add_text_annot`\"\n\n#: ../../page.rst:58 6166e4c84976477ebbb37a08075be065\nmsgid \"PDF only: add a comment\"\nmsgstr \"PDF 전용: 주석 추가\"\n\n#: ../../page.rst:59 9d9e5d56413243e7acd7bc42faea55a8\nmsgid \":meth:`Page.add_underline_annot`\"\nmsgstr \":meth:`Page.add_underline_annot`\"\n\n#: ../../page.rst:59 0f3e21d031cd4faf9b37cb2a67940487\nmsgid \"PDF only: add an \\\"underline\\\" annotation\"\nmsgstr \"PDF 전용: \\\"밑줄\\\" 주석 추가\"\n\n#: ../../page.rst:60 f5faa32f93624b2487038228f34de580\nmsgid \":meth:`Page.add_widget`\"\nmsgstr \":meth:`Page.add_widget`\"\n\n#: ../../page.rst:60 cb151ecc51ab45a195811c7976e8e869\nmsgid \"PDF only: add a PDF Form field\"\nmsgstr \"PDF 전용: PDF 양식 필드 추가\"\n\n#: ../../page.rst:61 7d757c5dccba4c0fb0941cead965caa8\nmsgid \":meth:`Page.annot_names`\"\nmsgstr \":meth:`Page.annot_names`\"\n\n#: ../../page.rst:61 2af022e1891743f9a93104db2bad5f5e\nmsgid \"PDF only: a list of annotation (and widget) names\"\nmsgstr \"PDF 전용: 주석(및 위젯) 이름 목록\"\n\n#: ../../page.rst:62 460e33003788412a8f6af75cd5edeef8\nmsgid \":meth:`Page.annot_xrefs`\"\nmsgstr \":meth:`Page.annot_xrefs`\"\n\n#: ../../page.rst:62 21f42a813f50480085c3e7d12ae51dde\nmsgid \"PDF only: a list of annotation (and widget) xrefs\"\nmsgstr \"PDF 전용: 주석(및 위젯) xref 목록\"\n\n#: ../../page.rst:63 fe26f7732fc64062b91138d4a3666ff1\nmsgid \":meth:`Page.annots`\"\nmsgstr \":meth:`Page.annots`\"\n\n#: ../../page.rst:63 fa2bca1baaa34e9890095cfbad31d943\nmsgid \"return a generator over the annots on the page\"\nmsgstr \"페이지의 주석에 대한 생성자 반환\"\n\n#: ../../page.rst:64 ef49a8b7ac1f42d7b517b2a72841b523\nmsgid \":meth:`Page.apply_redactions`\"\nmsgstr \":meth:`Page.apply_redactions`\"\n\n#: ../../page.rst:64 6eec33ab83094db09f58d366751d135c\nmsgid \"PDF only: process the redactions of the page\"\nmsgstr \"PDF 전용: 페이지의 수정 처리\"\n\n#: ../../page.rst:65 fffafd8ac71f4946b8d34ddec143fb97\nmsgid \":meth:`Page.clip_to_rect`\"\nmsgstr \":meth:`Page.clip_to_rect`\"\n\n#: ../../page.rst:65 6c00ecf81e9d421d8d4328df5552a335\nmsgid \"PDF only: remove page content outside a rectangle\"\nmsgstr \"PDF 전용: 사각형 외부의 페이지 콘텐츠 제거\"\n\n#: ../../page.rst:66 bc10eac3335e4c7c8aa29962096a4851\nmsgid \":meth:`Page.bound`\"\nmsgstr \":meth:`Page.bound`\"\n\n#: ../../page.rst:66 ../../page.rst:137 1f3d85fc4fa74bdaa0d5458534460fcf\n#: ff6962d922fd4757939ee93378e3df3a\nmsgid \"rectangle of the page\"\nmsgstr \"페이지의 사각형\"\n\n#: ../../page.rst:67 2f6ce14be7ed4e00b009b2eb52d0f7fa\nmsgid \":meth:`Page.cluster_drawings`\"\nmsgstr \":meth:`Page.cluster_drawings`\"\n\n#: ../../page.rst:67 aeca385ef2014bdeaae33e4d3e5405a9\nmsgid \"PDF only: bounding boxes of vector graphics\"\nmsgstr \"PDF 전용: 벡터 그래픽의 경계 상자\"\n\n#: ../../page.rst:68 a3fd94d66c45439186fd3381996fa529\nmsgid \":meth:`Page.delete_annot`\"\nmsgstr \":meth:`Page.delete_annot`\"\n\n#: ../../page.rst:68 fd8317c7a16c4ed3be5d0f91c39d36be\nmsgid \"PDF only: delete an annotation\"\nmsgstr \"PDF 전용: 주석 삭제\"\n\n#: ../../page.rst:69 9722279391474a879dbd9f2a7b590d84\nmsgid \":meth:`Page.delete_image`\"\nmsgstr \":meth:`Page.delete_image`\"\n\n#: ../../page.rst:69 46b28a2de9974570ba0436618b032379\nmsgid \"PDF only: delete an image\"\nmsgstr \"PDF 전용: 이미지 삭제\"\n\n#: ../../page.rst:70 203a1849b02a42c7a891f062cbf52dfb\nmsgid \":meth:`Page.delete_link`\"\nmsgstr \":meth:`Page.delete_link`\"\n\n#: ../../page.rst:70 ccf68e485ea740aea4e49e3cbf147821\nmsgid \"PDF only: delete a link\"\nmsgstr \"PDF 전용: 링크 삭제\"\n\n#: ../../page.rst:71 0d872d8700894747baf6717b43854f1b\nmsgid \":meth:`Page.delete_widget`\"\nmsgstr \":meth:`Page.delete_widget`\"\n\n#: ../../page.rst:71 ce302a0aa96f4ec28810acfee891e36f\nmsgid \"PDF only: delete a widget / field\"\nmsgstr \"PDF 전용: 위젯/필드 삭제\"\n\n#: ../../page.rst:72 f63490db0707495f85356a222d8f2e01\nmsgid \":meth:`Page.draw_bezier`\"\nmsgstr \":meth:`Page.draw_bezier`\"\n\n#: ../../page.rst:72 eff1fa903b8d443e887dc9aec924ce87\nmsgid \"PDF only: draw a cubic Bezier curve\"\nmsgstr \"PDF 전용: 3차 베지어 곡선 그리기\"\n\n#: ../../page.rst:73 8877a067ebb5495db7bf91973ac843de\nmsgid \":meth:`Page.draw_circle`\"\nmsgstr \":meth:`Page.draw_circle`\"\n\n#: ../../page.rst:73 0249f749cc04468db32846e3a91847b1\nmsgid \"PDF only: draw a circle\"\nmsgstr \"PDF 전용: 원 그리기\"\n\n#: ../../page.rst:74 c84553f9888048eab99f9cad82c5ab51\nmsgid \":meth:`Page.draw_curve`\"\nmsgstr \":meth:`Page.draw_curve`\"\n\n#: ../../page.rst:74 e32a35018a0848c99f5c79513317c3d2\nmsgid \"PDF only: draw a special Bezier curve\"\nmsgstr \"PDF 전용: 특수 베지어 곡선 그리기\"\n\n#: ../../page.rst:75 5e4b7f8682084254b71c7302e1dbdd0f\nmsgid \":meth:`Page.draw_line`\"\nmsgstr \":meth:`Page.draw_line`\"\n\n#: ../../page.rst:75 d490933be5ca4395aa5c2fd0582ce268\nmsgid \"PDF only: draw a line\"\nmsgstr \"PDF 전용: 선 그리기\"\n\n#: ../../page.rst:76 05641267e0cf4d989f5f26ad935ec02b\nmsgid \":meth:`Page.draw_oval`\"\nmsgstr \":meth:`Page.draw_oval`\"\n\n#: ../../page.rst:76 86a9acc6ccaa4d4280f3c3fc4d7e9ff6\nmsgid \"PDF only: draw an oval / ellipse\"\nmsgstr \"PDF 전용: 타원 그리기\"\n\n#: ../../page.rst:77 7a3e2be1ddbb41129d4bb8af04a06aca\nmsgid \":meth:`Page.draw_polyline`\"\nmsgstr \":meth:`Page.draw_polyline`\"\n\n#: ../../page.rst:77 97a5670624784f5e918844be3bd01770\nmsgid \"PDF only: connect a point sequence\"\nmsgstr \"PDF 전용: 점 시퀀스 연결\"\n\n#: ../../page.rst:78 71f0edeccebb43d5bb0ecc5da8e92d7b\nmsgid \":meth:`Page.draw_quad`\"\nmsgstr \":meth:`Page.draw_quad`\"\n\n#: ../../page.rst:78 2e390549e54b44b6b7711dc9cc895e16\nmsgid \"PDF only: draw a quad\"\nmsgstr \"PDF 전용: 사각형 그리기\"\n\n#: ../../page.rst:79 635ad324729b4b01bbd2afc6fe1d7bdd\nmsgid \":meth:`Page.draw_rect`\"\nmsgstr \":meth:`Page.draw_rect`\"\n\n#: ../../page.rst:79 4150b075ab48434881a4be110c6fcbf0\nmsgid \"PDF only: draw a rectangle\"\nmsgstr \"PDF 전용: 사각형 그리기\"\n\n#: ../../page.rst:80 cb18274299ec498384ab4c12af0a38e9\nmsgid \":meth:`Page.draw_sector`\"\nmsgstr \":meth:`Page.draw_sector`\"\n\n#: ../../page.rst:80 5239a2bc5fc34be584b6589ae4741cc4\nmsgid \"PDF only: draw a circular sector\"\nmsgstr \"PDF 전용: 원형 섹터 그리기\"\n\n#: ../../page.rst:81 caaaee7ecb354309a8dc66d853b4c91f\nmsgid \":meth:`Page.draw_squiggle`\"\nmsgstr \":meth:`Page.draw_squiggle`\"\n\n#: ../../page.rst:81 72295b9e8a63496b88094039ffbcde6a\nmsgid \"PDF only: draw a squiggly line\"\nmsgstr \"PDF 전용: 물결선 그리기\"\n\n#: ../../page.rst:82 49b04744785948b19597a93786497023\nmsgid \":meth:`Page.draw_zigzag`\"\nmsgstr \":meth:`Page.draw_zigzag`\"\n\n#: ../../page.rst:82 3f21f5eb09354117ad1a536bf3da91fa\nmsgid \"PDF only: draw a zig-zagged line\"\nmsgstr \"PDF 전용: 지그재그 선 그리기\"\n\n#: ../../page.rst:83 fd9907fef5ad4079a071161d66b17561\nmsgid \":meth:`Page.find_tables`\"\nmsgstr \":meth:`Page.find_tables`\"\n\n#: ../../page.rst:83 7c12def340ca4445bb3e0f6f3a4119a4\nmsgid \"locate tables on the page\"\nmsgstr \"페이지에서 테이블 찾기\"\n\n#: ../../page.rst:84 a705386990574b03a0bb5107e2990478\nmsgid \":meth:`Page.get_drawings`\"\nmsgstr \":meth:`Page.get_drawings`\"\n\n#: ../../page.rst:84 116ff841fb514d4288112879d23c244f\nmsgid \"get vector graphics on page\"\nmsgstr \"페이지의 벡터 그래픽 가져오기\"\n\n#: ../../page.rst:85 ../../page.rst:2355 5513869a670140a886b0de7e86105fcc\n#: 89d76a9e191948898a7d4ddcb3108546\nmsgid \":meth:`Page.get_fonts`\"\nmsgstr \":meth:`Page.get_fonts`\"\n\n#: ../../page.rst:85 b623d469785e471aa3c1cb2902c44f17\nmsgid \"PDF only: get list of referenced fonts\"\nmsgstr \"PDF 전용: 참조된 폰트 목록 가져오기\"\n\n#: ../../page.rst:86 032b7938c6354a188828b99422ce4c1b\nmsgid \":meth:`Page.get_image_bbox`\"\nmsgstr \":meth:`Page.get_image_bbox`\"\n\n#: ../../page.rst:86 de0cdf60868d4940a19846bc5c338aa9\nmsgid \"PDF only: get bbox and matrix of embedded image\"\nmsgstr \"PDF 전용: 임베디드 이미지의 bbox 및 행렬 가져오기\"\n\n#: ../../page.rst:87 ea32423fb45a4c829c831fa0302cf4a2\nmsgid \":meth:`Page.get_image_info`\"\nmsgstr \":meth:`Page.get_image_info`\"\n\n#: ../../page.rst:87 458efa2ccf404e7ab44490f1f0a7eebc\nmsgid \"get list of meta information for all used images\"\nmsgstr \"사용된 모든 이미지의 메타 정보 목록 가져오기\"\n\n#: ../../page.rst:88 bef50d6ac750452f87453cddca373460\nmsgid \":meth:`Page.get_image_rects`\"\nmsgstr \":meth:`Page.get_image_rects`\"\n\n#: ../../page.rst:88 0639d98f4696403bab4435ac71e37c56\nmsgid \"PDF only: improved version of :meth:`Page.get_image_bbox`\"\nmsgstr \"PDF 전용: :meth:`Page.get_image_bbox` 의 개선된 버전\"\n\n#: ../../page.rst:89 ../../page.rst:2356 2737569248454d5aad0880abcf86d7ce\n#: 417ddc69f2e84248a5cc652040dc362c\nmsgid \":meth:`Page.get_images`\"\nmsgstr \":meth:`Page.get_images`\"\n\n#: ../../page.rst:89 a0e5ded6cdd146ebb2b5ad6dab673250\nmsgid \"PDF only: get list of referenced images\"\nmsgstr \"PDF 전용: 참조된 이미지 목록 가져오기\"\n\n#: ../../page.rst:90 2c2d56778e154346acc5ed92bd33e033\nmsgid \":meth:`Page.get_label`\"\nmsgstr \":meth:`Page.get_label`\"\n\n#: ../../page.rst:90 8b80f3ad7a864cd496aa891acc3e790a\nmsgid \"PDF only: return the label of the page\"\nmsgstr \"PDF 전용: 페이지의 레이블 반환\"\n\n#: ../../page.rst:91 5cd06210bb4d47c695294ecea67435ab\nmsgid \":meth:`Page.get_links`\"\nmsgstr \":meth:`Page.get_links`\"\n\n#: ../../page.rst:91 5a062b7c81f344cda0c16b1a005477d7\nmsgid \"get all links\"\nmsgstr \"모든 링크 가져오기\"\n\n#: ../../page.rst:92 ../../page.rst:2357 79dd679c248f4983b29496e8e988c628\n#: a4bee007c0454a16ad4e26642efefb05\nmsgid \":meth:`Page.get_pixmap`\"\nmsgstr \":meth:`Page.get_pixmap`\"\n\n#: ../../page.rst:92 1b658d01635b4251a718775d4f5a25b3\nmsgid \"create a page image in raster format\"\nmsgstr \"래스터 형식의 페이지 이미지 생성\"\n\n#: ../../page.rst:93 9f1ce6858bce466ebc9ff6ab0f07cf7b\nmsgid \":meth:`Page.get_svg_image`\"\nmsgstr \":meth:`Page.get_svg_image`\"\n\n#: ../../page.rst:93 67e50df05e064d1a82bed624b6647b09\nmsgid \"create a page image in SVG format\"\nmsgstr \"SVG 형식의 페이지 이미지 생성\"\n\n#: ../../page.rst:94 ../../page.rst:2358 269ce650459d43218f8f2c39da827d08\n#: b9169e61ebdd41fbb8a7c9e3c26d9ce4\nmsgid \":meth:`Page.get_text`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../page.rst:94 a8aaa066102c47ccaafb71449455ec6a\nmsgid \"extract the page's text\"\nmsgstr \"페이지의 텍스트 추출\"\n\n#: ../../page.rst:95 2721ffbd14ab4c188f8d29ee0333a13d\nmsgid \":meth:`Page.get_textbox`\"\nmsgstr \":meth:`Page.get_textbox`\"\n\n#: ../../page.rst:95 12e56111e26244c3b479f67f2a1f1e59\nmsgid \"extract text contained in a rectangle\"\nmsgstr \"사각형에 포함된 텍스트 추출\"\n\n#: ../../page.rst:96 da2862c13a76447d8300c492453071f2\nmsgid \":meth:`Page.get_textpage_ocr`\"\nmsgstr \":meth:`Page.get_textpage_ocr`\"\n\n#: ../../page.rst:96 a94a6c9143a344d6aa67d522fa588026\nmsgid \"create a TextPage with OCR for the page\"\nmsgstr \"페이지에 대한 OCR이 포함된 TextPage 생성\"\n\n#: ../../page.rst:97 6a3ac7a182f44d7fa7a198b16825777d\nmsgid \":meth:`Page.get_textpage`\"\nmsgstr \":meth:`Page.get_textpage`\"\n\n#: ../../page.rst:97 3a2ff15016b94cbda54e0a7e342cdca8\nmsgid \"create a TextPage for the page\"\nmsgstr \"페이지에 대한 TextPage 생성\"\n\n#: ../../page.rst:98 42257e13df044823b5ada20df4cc1f65\nmsgid \":meth:`Page.get_xobjects`\"\nmsgstr \":meth:`Page.get_xobjects`\"\n\n#: ../../page.rst:98 dac370a551e94fd1845762ed141b934c\nmsgid \"PDF only: get list of referenced xobjects\"\nmsgstr \"PDF 전용: 참조된 xobjects 목록 가져오기\"\n\n#: ../../page.rst:99 b455e5d5c0aa4fa7843f679e55dbaf6a\nmsgid \":meth:`Page.insert_font`\"\nmsgstr \":meth:`Page.insert_font`\"\n\n#: ../../page.rst:99 ad790342de2c46229c73dbd2e8549b7d\nmsgid \"PDF only: insert a font for use by the page\"\nmsgstr \"PDF 전용: 페이지에서 사용할 폰트 삽입\"\n\n#: ../../page.rst:100 5769325361e9409291d2de6ff6a74a6f\nmsgid \":meth:`Page.insert_image`\"\nmsgstr \":meth:`Page.insert_image`\"\n\n#: ../../page.rst:100 5fee15b23dc84739b1ab8ce43e9a636a\nmsgid \"PDF only: insert an image\"\nmsgstr \"PDF 전용: 이미지 삽입\"\n\n#: ../../page.rst:101 4a6a82d58c03465dbdecd703f6d7f484\nmsgid \":meth:`Page.insert_link`\"\nmsgstr \":meth:`Page.insert_link`\"\n\n#: ../../page.rst:101 b1e9b94b930141c0bcadb44dfd561924\nmsgid \"PDF only: insert a link\"\nmsgstr \"PDF 전용: 링크 삽입\"\n\n#: ../../page.rst:102 17d5d051bd1d45369ac998a2122e0c62\nmsgid \":meth:`Page.insert_text`\"\nmsgstr \":meth:`Page.insert_text`\"\n\n#: ../../page.rst:102 52672923fad14e51bd5e04a28212d35c\nmsgid \"PDF only: insert text\"\nmsgstr \"PDF 전용: 텍스트 삽입\"\n\n#: ../../page.rst:103 83ba971b1ba9461390deb0d1ab0402f2\nmsgid \":meth:`Page.insert_htmlbox`\"\nmsgstr \":meth:`Page.insert_htmlbox`\"\n\n#: ../../page.rst:103 be5e2559a7d14e57954c56d970906946\nmsgid \"PDF only: insert html text in a rectangle\"\nmsgstr \"PDF 전용: 사각형에 HTML 텍스트 삽입\"\n\n#: ../../page.rst:104 b3109af9729e40d58a40f4edaac0a175\nmsgid \":meth:`Page.insert_textbox`\"\nmsgstr \":meth:`Page.insert_textbox`\"\n\n#: ../../page.rst:104 b350237b8a85495a94ab5623219b134f\nmsgid \"PDF only: insert a text box\"\nmsgstr \"PDF 전용: 텍스트 상자 삽입\"\n\n#: ../../page.rst:105 c688c4af2bb1464aa08e2abfed572208\nmsgid \":meth:`Page.links`\"\nmsgstr \":meth:`Page.links`\"\n\n#: ../../page.rst:105 fa47810199534f1fac3e4acd7b50ea81\nmsgid \"return a generator of the links on the page\"\nmsgstr \"페이지의 링크에 대한 생성자 반환\"\n\n#: ../../page.rst:106 a3a22a08c1c94e718b34bcf0a1c9cc37\nmsgid \":meth:`Page.load_annot`\"\nmsgstr \":meth:`Page.load_annot`\"\n\n#: ../../page.rst:106 38655b86d4994aacbd28bf85316e1534\nmsgid \"PDF only: load a specific annotation\"\nmsgstr \"PDF 전용: 특정 주석 로드\"\n\n#: ../../page.rst:107 eb4c07f56b864d108c056f82854b0931\nmsgid \":meth:`Page.load_widget`\"\nmsgstr \":meth:`Page.load_widget`\"\n\n#: ../../page.rst:107 c9f0a660efb9401abb92c4ddd9071840\nmsgid \"PDF only: load a specific field\"\nmsgstr \"PDF 전용: 특정 필드 로드\"\n\n#: ../../page.rst:108 352c9d2ca82d4804848c4e3b197af6d5\nmsgid \":meth:`Page.load_links`\"\nmsgstr \":meth:`Page.load_links`\"\n\n#: ../../page.rst:108 e8427f8c37e04f1c835b369b5917501d\nmsgid \"return the first link on a page\"\nmsgstr \"페이지의 첫 번째 링크 반환\"\n\n#: ../../page.rst:109 75e71d2fde7b4ef69b2e3b82e8f29afe\nmsgid \":meth:`Page.new_shape`\"\nmsgstr \":meth:`Page.new_shape`\"\n\n#: ../../page.rst:109 2a0c8a834cc546f99d2419597b66e3ba\nmsgid \"PDF only: create a new :ref:`Shape`\"\nmsgstr \"PDF 전용: 새 :ref:`Shape` 생성\"\n\n#: ../../page.rst:110 a2c8cff536ca425ab1da46f6a5559b54\nmsgid \":meth:`Page.recolor`\"\nmsgstr \":meth:`Page.recolor`\"\n\n#: ../../page.rst:110 ddc1dcc46bd94fa2ac362d97b7d7be96\nmsgid \"PDF only: change the colorspace of objects\"\nmsgstr \"PDF 전용: 객체의 색상 공간 변경\"\n\n#: ../../page.rst:111 eb776ad9a91748fa9f4419c19c4b92d2\nmsgid \":meth:`Page.remove_rotation`\"\nmsgstr \":meth:`Page.remove_rotation`\"\n\n#: ../../page.rst:111 a2c31954539c48b8b378628c2cc80e96\nmsgid \"PDF only: set page rotation to 0\"\nmsgstr \"PDF 전용: 페이지 회전을 0으로 설정\"\n\n#: ../../page.rst:112 5057e96ed4734bcbb0133e7ead7a2cab\nmsgid \":meth:`Page.replace_image`\"\nmsgstr \":meth:`Page.replace_image`\"\n\n#: ../../page.rst:112 899c88d73da04ca586624e8dfd412b19\nmsgid \"PDF only: replace an image\"\nmsgstr \"PDF 전용: 이미지 교체\"\n\n#: ../../page.rst:113 ../../page.rst:2359 71be303aad804ff5a6400acf38550aa4\n#: a36ed4e43659431bb9a4bb520578acf9\nmsgid \":meth:`Page.search_for`\"\nmsgstr \":meth:`Page.search_for`\"\n\n#: ../../page.rst:113 62c168ceff884befb1a78b7c8d7407e9\nmsgid \"search for a string\"\nmsgstr \"문자열 검색\"\n\n#: ../../page.rst:114 8583ac949dd54261b60dc1fa600ba5ce\nmsgid \":meth:`Page.set_artbox`\"\nmsgstr \":meth:`Page.set_artbox`\"\n\n#: ../../page.rst:114 f3329d1a5c484f2085f8abfc485d69fd\nmsgid \"PDF only: modify `/ArtBox`\"\nmsgstr \"PDF 전용: `/ArtBox` 수정\"\n\n#: ../../page.rst:115 93b0c3cc50ba4ecba1d9f2ecd0b3516e\nmsgid \":meth:`Page.set_bleedbox`\"\nmsgstr \":meth:`Page.set_bleedbox`\"\n\n#: ../../page.rst:115 f3a89a8d724648b9a11cd098e2c87780\nmsgid \"PDF only: modify `/BleedBox`\"\nmsgstr \"PDF 전용: `/BleedBox` 수정\"\n\n#: ../../page.rst:116 96033ab15bb242d9aebbedeb42f65c22\nmsgid \":meth:`Page.set_cropbox`\"\nmsgstr \":meth:`Page.set_cropbox`\"\n\n#: ../../page.rst:116 5ebf1f7c5f2e4938b6071e31711528e4\nmsgid \"PDF only: modify the :data:`cropbox` (visible page)\"\nmsgstr \"PDF 전용: :data:`cropbox` (보이는 페이지) 수정\"\n\n#: ../../page.rst:117 3c4547592e4148558c3bb7ef9328b953\nmsgid \":meth:`Page.set_mediabox`\"\nmsgstr \":meth:`Page.set_mediabox`\"\n\n#: ../../page.rst:117 70664716c7b44846a2d23c4603794d75\nmsgid \"PDF only: modify `/MediaBox`\"\nmsgstr \"PDF 전용: `/MediaBox` 수정\"\n\n#: ../../page.rst:118 c38c50f5998e43de9073f15108f0b4e9\nmsgid \":meth:`Page.set_rotation`\"\nmsgstr \":meth:`Page.set_rotation`\"\n\n#: ../../page.rst:118 ef1b21b5d28947238b694a70d462305d\nmsgid \"PDF only: set page rotation\"\nmsgstr \"PDF 전용: 페이지 회전 설정\"\n\n#: ../../page.rst:119 6881608670ad44e593239c0b8ca65758\nmsgid \":meth:`Page.set_trimbox`\"\nmsgstr \":meth:`Page.set_trimbox`\"\n\n#: ../../page.rst:119 b79cecdb274042aa9447129dc4256f28\nmsgid \"PDF only: modify `/TrimBox`\"\nmsgstr \"PDF 전용: `/TrimBox` 수정\"\n\n#: ../../page.rst:120 5b977466d1964b72a80eee11dd8e3009\nmsgid \":meth:`Page.show_pdf_page`\"\nmsgstr \":meth:`Page.show_pdf_page`\"\n\n#: ../../page.rst:120 be9781151fb0400485056a8c9cdfc40e\nmsgid \"PDF only: display PDF page image\"\nmsgstr \"PDF 전용: PDF 페이지 이미지 표시\"\n\n#: ../../page.rst:121 f2f2542e611141f38ab79ec47c6b24bc\nmsgid \":meth:`Page.update_link`\"\nmsgstr \":meth:`Page.update_link`\"\n\n#: ../../page.rst:121 5ccc634e9dab4e35b87d9283dd4c459c\nmsgid \"PDF only: modify a link\"\nmsgstr \"PDF 전용: 링크 수정\"\n\n#: ../../page.rst:122 5e672418d9f847e3b5cfb33a73198f4f\nmsgid \":meth:`Page.widgets`\"\nmsgstr \":meth:`Page.widgets`\"\n\n#: ../../page.rst:122 df37c13079364b42bfc84e3b87300cc8\nmsgid \"return a generator over the fields on the page\"\nmsgstr \"페이지의 필드에 대한 생성자 반환\"\n\n#: ../../page.rst:123 c7ecde8ede3a4ff7b6a463a3ba205f4e\nmsgid \":meth:`Page.write_text`\"\nmsgstr \":meth:`Page.write_text`\"\n\n#: ../../page.rst:123 dcef4d9315724d998c25fac935454324\nmsgid \"write one or more :ref:`Textwriter` objects\"\nmsgstr \"하나 이상의 :ref:`Textwriter` 객체 쓰기\"\n\n#: ../../page.rst:124 f7ddf8cbb96f42e2a9509482a6f12578\nmsgid \":attr:`Page.cropbox_position`\"\nmsgstr \":attr:`Page.cropbox_position`\"\n\n#: ../../page.rst:124 e58ae174c1e14bf0929d34c067629692\nmsgid \"displacement of the :data:`cropbox`\"\nmsgstr \":data:`cropbox` 의 변위\"\n\n#: ../../page.rst:125 c3f912e91d574e7ba9eca4ebef4e9038\nmsgid \":attr:`Page.cropbox`\"\nmsgstr \":attr:`Page.cropbox`\"\n\n#: ../../page.rst:125 3106600eed144c0387c3398d559a399b\nmsgid \"the page's :data:`cropbox`\"\nmsgstr \"페이지의 :data:`cropbox`\"\n\n#: ../../page.rst:126 4bcae534f0e442e89bdb09f321571968\nmsgid \":attr:`Page.artbox`\"\nmsgstr \":attr:`Page.artbox`\"\n\n#: ../../page.rst:126 16c7fdc208b94e19ba7cb2729005e69c\nmsgid \"the page's `/ArtBox`\"\nmsgstr \"페이지의 `/ArtBox`\"\n\n#: ../../page.rst:127 bc724a5f20ed468c9cb5537971cd1a67\nmsgid \":attr:`Page.bleedbox`\"\nmsgstr \":attr:`Page.bleedbox`\"\n\n#: ../../page.rst:127 99aa56333f8243c4bcc312acbdda9b66\nmsgid \"the page's `/BleedBox`\"\nmsgstr \"페이지의 `/BleedBox`\"\n\n#: ../../page.rst:128 053890a35a2b4dca970fcce5a35aef43\nmsgid \":attr:`Page.trimbox`\"\nmsgstr \":attr:`Page.trimbox`\"\n\n#: ../../page.rst:128 93749ed391f94e2da79ed77983ad3e89\nmsgid \"the page's `/TrimBox`\"\nmsgstr \"페이지의 `/TrimBox`\"\n\n#: ../../page.rst:129 d91bff725157405e8a4e0702f42a4cea\nmsgid \":attr:`Page.derotation_matrix`\"\nmsgstr \":attr:`Page.derotation_matrix`\"\n\n#: ../../page.rst:129 0c7e82bca054495c87c9e519a1366048\nmsgid \"PDF only: get coordinates in unrotated page space\"\nmsgstr \"PDF 전용: 회전되지 않은 페이지 공간에서 좌표 가져오기\"\n\n#: ../../page.rst:130 fd857f2b70ac411c92518c25887c2f87\nmsgid \":attr:`Page.first_annot`\"\nmsgstr \":attr:`Page.first_annot`\"\n\n#: ../../page.rst:130 3960c3cff7cd4dd7bb4eefa5b00d56a2\nmsgid \"first :ref:`Annot` on the page\"\nmsgstr \"페이지의 첫 번째 :ref:`Annot`\"\n\n#: ../../page.rst:131 6a67a4a11ec6453fa36aa5461c6e06d5\nmsgid \":attr:`Page.first_link`\"\nmsgstr \":attr:`Page.first_link`\"\n\n#: ../../page.rst:131 6c50bbdfa48345e5b46d99fbb87e9f06\nmsgid \"first :ref:`Link` on the page\"\nmsgstr \"페이지의 첫 번째 :ref:`Link`\"\n\n#: ../../page.rst:132 27eb250d66a3438f83fea2b8bfde1e1a\nmsgid \":attr:`Page.first_widget`\"\nmsgstr \":attr:`Page.first_widget`\"\n\n#: ../../page.rst:132 6dcac77284924a208b05753baa2f3993\nmsgid \"first widget (form field) on the page\"\nmsgstr \"페이지의 첫 번째 위젯(양식 필드)\"\n\n#: ../../page.rst:133 3c80190dfd5b48afb1637767a52f2562\nmsgid \":attr:`Page.mediabox_size`\"\nmsgstr \":attr:`Page.mediabox_size`\"\n\n#: ../../page.rst:133 74b552a4e7ff422eb90f67ef1b79c612\nmsgid \"bottom-right point of :data:`mediabox`\"\nmsgstr \":data:`mediabox` 의 오른쪽 아래 점\"\n\n#: ../../page.rst:134 5e616c88bd0a4d80994eebb61393c403\nmsgid \":attr:`Page.mediabox`\"\nmsgstr \":attr:`Page.mediabox`\"\n\n#: ../../page.rst:134 dcb881e86083487d974936ae28de5065\nmsgid \"the page's :data:`mediabox`\"\nmsgstr \"페이지의 :data:`mediabox`\"\n\n#: ../../page.rst:135 60c9628e587e454cb43e0bc7c339cbad\nmsgid \":attr:`Page.number`\"\nmsgstr \":attr:`Page.number`\"\n\n#: ../../page.rst:135 9a9f6b22bdb24d779607ffbe6587a360\nmsgid \"page number\"\nmsgstr \"페이지 번호\"\n\n#: ../../page.rst:136 1a110f454cdb4eccb45642adad58f06a\nmsgid \":attr:`Page.parent`\"\nmsgstr \":attr:`Page.parent`\"\n\n#: ../../page.rst:136 79ef518099464c51a423337cecbcfc17\nmsgid \"owning document object\"\nmsgstr \"소유 문서 객체\"\n\n#: ../../page.rst:137 699d659fe5f64f748fc494f227ca527f\nmsgid \":attr:`Page.rect`\"\nmsgstr \":attr:`Page.rect`\"\n\n#: ../../page.rst:138 41e758f7ff2c4b268ab0de1e5b623c06\nmsgid \":attr:`Page.rotation_matrix`\"\nmsgstr \":attr:`Page.rotation_matrix`\"\n\n#: ../../page.rst:138 b6bea37a07124c5789ba01157e13610a\nmsgid \"PDF only: get coordinates in rotated page space\"\nmsgstr \"PDF 전용: 회전된 페이지 공간에서 좌표 가져오기\"\n\n#: ../../page.rst:139 5a09c49610b24ef58acda89953700aa0\nmsgid \":attr:`Page.rotation`\"\nmsgstr \":attr:`Page.rotation`\"\n\n#: ../../page.rst:139 e2ee37dec6eb40b0b7495c11bdd79f2c\nmsgid \"PDF only: page rotation\"\nmsgstr \"PDF 전용: 페이지 회전\"\n\n#: ../../page.rst:140 7202394f72a249ba90257b4fc00ecf98\nmsgid \":attr:`Page.transformation_matrix`\"\nmsgstr \":attr:`Page.transformation_matrix`\"\n\n#: ../../page.rst:140 7399b7e05f4f4cb38c43a83b361f9743\nmsgid \"PDF only: translate between PDF and MuPDF space\"\nmsgstr \"PDF 전용: PDF와 MuPDF 공간 간 변환\"\n\n#: ../../page.rst:141 e8a15c725b7c4fb7bfdbf6af72da5dcb\nmsgid \":attr:`Page.xref`\"\nmsgstr \":attr:`Page.xref`\"\n\n#: ../../page.rst:141 e63ce001edc14011a2fe173d7cf8ee65\nmsgid \"PDF only: page :data:`xref`\"\nmsgstr \"PDF 전용: 페이지 :data:`xref`\"\n\n#: ../../page.rst:144 ffd2e823bb3644949e18584adce3726f\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../page.rst:150 16405530ac7d4413b7e7d3b1762263f8\nmsgid \"\"\n\"Determine the rectangle of the page. Same as property :attr:`Page.rect`. \"\n\"For PDF documents this **usually** also coincides with :data:`mediabox` \"\n\"and :data:`cropbox`, but not always. For example, if the page is rotated,\"\n\" then this is reflected by this method -- the :attr:`Page.cropbox` \"\n\"however will not change.\"\nmsgstr \"\"\n\"페이지의 사각형을 결정합니다. 속성 :attr:`Page.rect` 와 동일합니다. PDF 문서의 경우 이것은 **일반적으로** \"\n\":data:`mediabox` 및 :data:`cropbox` 와도 일치하지만 항상은 아닙니다. 예를 들어, 페이지가 회전된 경우 \"\n\"이것은 이 메서드에 반영됩니다 -- 그러나 :attr:`Page.cropbox` 는 변경되지 않습니다.\"\n\n#: ../../page.rst 1c7e43371bd048ddbe8a51b1390548b7\n#: 205cf4fe67bc44ce9a698e96b409bf9b 467a474817be469eab9560aba8f753ea\n#: 51d3f9dcd4a8427bac8db808615ff6ec 595478a115434fb6b5084114c00c7983\n#: 5f5110dd40354c749d8523c0c30ba431 667dd2143f1641b8a5db0979f13804ab\n#: 66d7f54209244e6c86e9457ff82cdbd3 6bf04982e9a74268b7286e5a368751ab\n#: 7349c20e85eb40dd9560fb6e7700a2c3 7cde36324f2744389fbdf482fe12c4c8\n#: 7e1f2e5330fd4dbd970bfc7abd346e63 7f20d63bc5d448aabf49085b89db55fa\n#: 83c7c872bd8047c3a7a0939fb05634cc 947b527bf4a547cf956b65b08e6fae28\n#: 96d5484b6c864ada88cae8a16ca3d451 9f166cfc77fd41fda88155824e646c30\n#: a3141c1461ea48319ecaa99986b93664 a340aa9fa69d44e8ae8707efa903a1c1\n#: b477e16d888b4419afa23e619ab80186 b698b81d3295446a8f511570ccc5e7c3\n#: be3f2ae375444bda8db47aaecde509ec cdbe637983804854979d3357277ac7d2\n#: d3dc85ed25374dea8d2969af15ec7f0b d5fda2787f344daa80e2fd9b298b8d18\n#: eec8293f986546c7843eb6b66d7f6a24 f1e13a8c14a5469daa7a4dfe69c5884b\n#: f2d9c25df1544d359ebbd1cb6c79ee05 f4622e9f6466414d93b014a06ff2e078\n#: f757ade36dbc45d88ac62e55fb132ae9\nmsgid \"Return type\"\nmsgstr \"반환 타입\"\n\n#: ../../page.rst:152 ../../page.rst:2200 ../../page.rst:2210\n#: ../../page.rst:2222 ../../page.rst:2283 ../../page.rst:2289\n#: ../../page.rst:2432 ../../page.rst:2492 059602a8c1964a70b776297ba67cadec\n#: 6be39e10fe814f0d8c9fa1b5ddc808be 79af3cb774e04712a49a2ea5c0104c97\n#: aae052a3d76040c18894dff94ce8405d b9f7e0a4775f4917835802a2e3e00c9d\n#: c35f7f08d00d44fc92bfe49f8fdf9f37 cdd61db2adba438dae792f0a00d7c86a\n#: d4f8317a2c804daa8710fba8abdb5a64\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../page.rst:156 cfa67eb14e9e433e98c391fadded0bf9\nmsgid \"\"\n\"PDF only: Add a caret icon. A caret annotation is a visual symbol \"\n\"normally used to indicate the presence of text edits on the page.\"\nmsgstr \"\"\n\"PDF 전용: 캐럿 아이콘을 추가합니다. 캐럿 주석은 일반적으로 페이지에 텍스트 편집이 있음을 나타내는 데 사용되는 시각적 \"\n\"기호입니다.\"\n\n#: ../../page.rst 00ad5e9bcba84fc2b79745d48c6d1af3\n#: 01eb72e00d214526a5c35e8c9512a1f3 0210c580f03c42d89d1a707d35f78b39\n#: 02a47f7a522b4c69b203a9f085012b7a 0415dbfd3a504a92aac74ed7618d0ca5\n#: 0cde509b3c8e4c4382701e4e4fec7e79 105d75640b1043928d8e2ae0bae6ea7e\n#: 1b540529e2c24d5998bb0635160a2e33 211979f067de424fa805ef917f41fd3d\n#: 2c37d3051dee4a3989cac54a11fa306b 34e2bb69e8994ec89859333c4aec2521\n#: 3af0605d86d54cef815ba3d01a9a8a50 4327147145c14eaaae2d2d6c4ad86fa9\n#: 4593092ade8649b797a37e127740daa4 45a507654ad145b997a81d22a95bd958\n#: 466592522da44edfa55c8db0e63c3973 48e27da586d840f499d90fe0b8190a58\n#: 49a2594359bc48ad96d423183ac75834 4cbd4a5a00c94435a3dd21301a6eccf3\n#: 50470958cec14499a78c0c1efad2a171 5911ecb82f3f4a478321f590e394075d\n#: 5cb2760dbdf54503b9607f1d84c4cbb2 5da0c8a182b5473ebcdbaf6c0594488c\n#: 74859be77d7f4033a984cb04e3a92d04 788b0ebe873045dbaedd8a79abaca095\n#: 7abeb91e89ff4c7596ae330d3fa0ad68 7b99587e9cbd43d9977f5470d8e561f9\n#: 7caf03a4ceb44d279e1aa6aacc6df100 890994f53e0f40d4975a462949bfff83\n#: 8dbb9bbaa7e34ceb89e43315d0b7c666 91af70cc23f44f7392743058cc4f8ebf\n#: a22033444ce4409b8bb2df81f3555fdb a2aeaa0d5a1e4dd38adc6fba64259518\n#: a6d3facd39fa416da204664b758c6fb3 a82294ed6014495c928dd45c2f24cd42\n#: aa999a0d269948e6b8cdf81fcda375d6 ac48ed3d77584bcbb62550b3c0eb2498\n#: ad8430a19361470b895dd21a55e1ab14 bef6913eeda048f0988acbe6a4d145c9\n#: c087fad999cd4221886a01597194030e c2cbf37e9f5f4429a2f3f59ed2d69cb6\n#: c9a0590b70c44d34924f9d8278ef6c1e d55cd5a6713f40ac9c9a0e40d6a262ed\n#: d9ce04c2e595471181c6d52278de3cfb dad883c7527d479ab4711f6b92bde5ea\n#: e220e2d77d0142cfb88d73ab31d9c45d e55fcc6423f24904942ab9293da5e5e5\n#: fd950628603d429097cce208f88a4379\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../page.rst:158 37cee59c04de4b4a903e6fe5c245bda3\nmsgid \"\"\n\"the top left point of a 20 x 20 rectangle containing the MuPDF-provided \"\n\"icon.\"\nmsgstr \"MuPDF에서 제공하는 아이콘을 포함하는 20 x 20 사각형의 왼쪽 위 점.\"\n\n#: ../../page.rst:160 ../../page.rst:181 ../../page.rst:240 ../../page.rst:264\n#: ../../page.rst:273 ../../page.rst:284 ../../page.rst:295 ../../page.rst:323\n#: ../../page.rst:388 ../../page.rst:600 ../../page.rst:1923\n#: ../../page.rst:2258 0243863d17c1474faec91d58d7fce506\n#: 147c468214b145898395799c84065546 164f7d8bb1b04753a29dcda0fe18cf06\n#: 257f0462b38a4ddd9cf24447a44a3ea3 785dd2b986dd43d38c430d1d4c3e5033\n#: 7d712e7e3ac54230a227b6c35361621d 7e3cb251dc2542dfaf9e6bd4d593360f\n#: 8b26bafd31fc44c2be39f516b98f084a 9f1c8d3976a441879292d557d6b6bdda\n#: a5c90e9c9aca41a88881f2b1ee1d7493 da6ca25f37ab4753a4dde348c0f77cfb\n#: f38cc53fbed041b688f7ddfe765e9544\nmsgid \":ref:`Annot`\"\nmsgstr \":ref:`Annot`\"\n\n#: ../../page.rst 01874abf007d4bf0841edfda262a5a80\n#: 156f763299934672b6fdfb9cfa494b31 1e02ead69f34470ca14b4e7ec7e15edf\n#: 20c4084afd6c42d28e0d626bbfccbd81 223eb01f06044f8497a2dcc9607f8b5c\n#: 27c832c2b3cd4099a81f9af2fd5dd6ee 2ceceff29c394b378ed1a58c8fece4c5\n#: 36b44d3f175e4e5c9c8a87e956b40b61 380ade06e5774d3a8a5f2c8496569e64\n#: 3aa1968744cd417b8ca4b25fc284b7fb 41c20c60aca54cd2bcd0aa07e04c9a7f\n#: 438ed28c385d4e78be868c5a2836ce98 49b824316b904a0cacf78578eaa5a1dd\n#: 5383a33f0cde4fd2807c8400cc4e8836 5dcf29df4e9b4660b8b08eb409eddcb5\n#: 5e822b4d8cee43b59c158a444c18a8da 650b26fabb1f43d0b0de84d5d60d35ac\n#: 7533219ef1094965bd9f1d8091e9790e 78b53a15df0e4c309f1858b8e4c01a97\n#: 79396917951844af9fa68a25cd231685 7ba40ec72d4f4d7e84ac7aeecdfff789\n#: 8a7be57d9396405aa86619144561d8cd 9337311dbf29452e9bc453a05666dd30\n#: 942c10676e5043ab80ec716e18b3e81a 9ba8444eecc844a19749cb8abce0078f\n#: a2506ef3ea0f4143a4eb89eb14223958 a2badc10b7a74bb4ab079e2f9c3fc6bb\n#: b01cf5b376124ab89cb842acb7a4ca7c b1b50faf962b42c594dc694e4690f284\n#: b32622ff4ede4f8780a156da92c608ec b90a3c54acd04e0fa343d741a51e21fe\n#: b93def862bc44db9a19d8d4642ab9004 d7a26b600e1f45cb867c4af00dc2b7e4\n#: dcd2e2a3eaa642ef8cae8921645ba9fe e0addb3fcc6f409a847f950149d1e5f6\n#: e37c593b2e9c4b52b082cec18ab5d836 eb2728fcd3994507a6c348424d0a779e\n#: f1061adfcda74fb9b08daa7aeaa36651 fa2eb3ba0f0d4f3bbd646cb33bafd830\n#: faa9a893b9b448c39352f0a55e42083b\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../page.rst:161 d41e23d93cec47f0a5e33b061c62a8e6\nmsgid \"\"\n\"the created annotation. Stroke color blue = (0, 0, 1), no fill color \"\n\"support.\"\nmsgstr \"생성된 주석. 선 색상 파란색 = (0, 0, 1), 채우기 색상 지원 없음.\"\n\n#: ../../page.rst:166 ../../page.rst:243 ../../page.rst:328 ../../page.rst:368\n#: ../../page.rst:540 ../../page.rst:613 ../../page.rst:649 ../../page.rst:671\n#: ../../page.rst:696 ../../page.rst:711 ../../page.rst:733 ../../page.rst:761\n#: ../../page.rst:790 ../../page.rst:857 ../../page.rst:894 ../../page.rst:919\n#: ../../page.rst:944 ../../page.rst:968 ../../page.rst:992 ../../page.rst:1017\n#: ../../page.rst:1041 ../../page.rst:1066 ../../page.rst:1090\n#: ../../page.rst:1115 ../../page.rst:1140 ../../page.rst:1321\n#: ../../page.rst:1369 ../../page.rst:1393 ../../page.rst:1451\n#: ../../page.rst:1479 ../../page.rst:1501 ../../page.rst:1542\n#: ../../page.rst:1653 ../../page.rst:1676 ../../page.rst:1735\n#: ../../page.rst:1765 ../../page.rst:1785 ../../page.rst:1800\n#: ../../page.rst:1841 ../../page.rst:1882 ../../page.rst:1896\n#: ../../page.rst:1910 ../../page.rst:1928 ../../page.rst:1945\n#: ../../page.rst:2046 ../../page.rst:2083 ../../page.rst:2107\n#: ../../page.rst:2125 ../../page.rst:2172 0ca6b086be624551b8d5a3bfd5a5c29c\n#: 12468912de284f668b30834e02f4e56e 1a7a7daaee05403dbab563e782d112b3\n#: 1d1d583195544c76a0842f24848325ae 1ff2f4d3d7764928b9d6cbd3ed332911\n#: 2280e88ab4aa440d9df2d4639a07b563 2b7e7d752b444952b8995c12d4b03133\n#: 2fff22fb49c04d2bb4c35f1666c49b30 3266e9100bf64637a033863f4d4b0ecd\n#: 343a36bc5c8b4f86958f75096586f720 3ce4fcaee5ea4f4ca3941a9fe15ceb8e\n#: 3e8d13ba70a1401c975463e0fdf1cc87 3fd2c7c7b03941f1bdd410868d1dfa96\n#: 43af8ec0295947b2908552ffdfaee874 478ec9cc77064d9aaeef46392d935cfb\n#: 4cb7af8d2ce147bab5b26410b8c3d007 5342c4e8c8b3460bab5aee3fd19e8362\n#: 5bb0a7d3e5404686a6dc97681a65f8b1 5e8f1e0e7cd9468a8b05322c1f344190\n#: 5f3926a01acc4e44980e0bc496725dc2 61a500c96c504aca9eb7954201c07d1f\n#: 666ba2b511b941069224d1b093754a83 6778944fad394ba39677af70f67cfd2d\n#: 6a3b0d0adbd9462da9cc53748bf7ccc0 6d6d536701f747e588356741fc404cbb\n#: 73439f7cf4ca413c85d04aca1e27a5f0 7ae311fc9ef74a5ca330213ac583359c\n#: 82dbaad0870c41d8a28b5477b8abe803 9144d51e11884421bbd80a409545f42a\n#: a472f109adf246cd91c1e97351337c31 a57d2ac5e4f848ed80348b8a89f4af51\n#: aadf7e17870442c58916096ef5985781 aaeb6c7f1f494acfb5da432d5c25c42e\n#: af14cf38d5724598933d62513496740c b0c35e8fcd6a4c63969d92a3c6ccaaed\n#: b3ba0143c4c04a9cbb0dd847168c07ed b9d4d559e0af4a868716aef4b1884ff4\n#: baf563b17acf4b328a01d7ceb0a7bc3e bc16481dcb7640b9914a19268857f26e\n#: c42d09416fb34718ad4cf94316454fbd ce97837903984a749034b63b6b1526f2\n#: d310818865ec411eae18a52f5970ef18 d8fa3ad2a57445d1a9aa6a6b5feeb419\n#: d91f916bf7024b1eac0338bb3846c9fb e9af9798bc1b407d8a984f8fd89593c7\n#: f3c57a49b90340f4b79abadc86693b9e f58bd9b3d29542e58d2ec81caf05562f\n#: fde7f05f6f6c4fdda2cc9a2793bf0d55 feb1c7a6d32844deb13a26c3f6e948bf\nmsgid \"|history_begin|\"\nmsgstr \"|history_begin|\"\n\n#: ../../page.rst:168 96db2ff91a834bd5addd88ee554dea59\nmsgid \"New in v1.16.0\"\nmsgstr \"v1.16.0에서 새로 추가됨\"\n\n#: ../../page.rst:170 ../../page.rst:247 ../../page.rst:332 ../../page.rst:376\n#: ../../page.rst:545 ../../page.rst:617 ../../page.rst:653 ../../page.rst:675\n#: ../../page.rst:700 ../../page.rst:715 ../../page.rst:737 ../../page.rst:765\n#: ../../page.rst:794 ../../page.rst:870 ../../page.rst:898 ../../page.rst:923\n#: ../../page.rst:948 ../../page.rst:972 ../../page.rst:996 ../../page.rst:1021\n#: ../../page.rst:1045 ../../page.rst:1070 ../../page.rst:1094\n#: ../../page.rst:1120 ../../page.rst:1144 ../../page.rst:1345\n#: ../../page.rst:1373 ../../page.rst:1397 ../../page.rst:1459\n#: ../../page.rst:1484 ../../page.rst:1506 ../../page.rst:1547\n#: ../../page.rst:1663 ../../page.rst:1684 ../../page.rst:1740\n#: ../../page.rst:1769 ../../page.rst:1793 ../../page.rst:1804\n#: ../../page.rst:1855 ../../page.rst:1886 ../../page.rst:1900\n#: ../../page.rst:1914 ../../page.rst:1932 ../../page.rst:1949\n#: ../../page.rst:2051 ../../page.rst:2090 ../../page.rst:2112\n#: ../../page.rst:2130 ../../page.rst:2176 02ae4ce4ec884ffea3b18987b7a84578\n#: 034dfe1d353e4a6d89a0a90f878677f2 049da9b465da4eab8d6c4253f1b61314\n#: 05d96681089544e8a32b8ed6f1d6f1f3 08108b3dff3041948f4a84ff2ae6176b\n#: 0c11db1b147040b9ba820fe01ae9da58 18914b33eb7f4c3bb79dddca5f56edc0\n#: 1a6d6af8879b46b7974578a3c9d04343 1b554ab0b76541c2a7b9b00d4a5135a0\n#: 1e8c987524d0478b82d2b226a1ae18fd 2051d14fc29240b1b6db669fa35861c5\n#: 21b5cf863bff47bbb8247bbb9dd54fbf 29c2a743ad37445ebe62109322eaad6f\n#: 2e16f94cf83741368836aba335519715 2ea1bff3b8d5453bad453f97699f9975\n#: 318d284c1a4e4df49a2143fdb1a592bb 3846e7e58f594f1ea654c716ce942341\n#: 48fea13b28854a3e8037241f0cac75a3 50687e142e7d4d358acfbee0b7828bd9\n#: 50ff165fbf384a0db135856cc7855894 55907e73b4254f029b6315f76570f3a4\n#: 69269d0e6e2b4321a564891e83d3a972 6974f42beb6443898bffe78925562e7a\n#: 6cb8027b0a7d4a96b1e6f74c36309243 6fd8c635d7b34337b97b84c1ff0ae41d\n#: 7031705e19194108bb39098a839628a6 7176e068f9ad4847a4d7b224a05118de\n#: 718bef9d535d44cbbb56871c7efa2618 7bf1e9ecb2bf4287829db04bad618db7\n#: 7fe57d524c094c27a6a01348c400ef3c 84c5bf1c20d149f4a1680a2157f4eb08\n#: 84dc12790c384757ab4e44c25c0ce58e 875130bb17324e09b192ffbc49f959f0\n#: 9d217d1e2314404291644e771ffe6753 a11e419e262b4a659e133f8d80777b37\n#: a78c54c40f0048c996824600e7415dbf af9e409e31964966a75bd201f959d0d8\n#: afc655f80b444c7b829bcc6170536143 b14005d7053d44ce9732f5265b71d93d\n#: b35ec848aa6646a18a773737a4766df2 c4ca8bf9c34a4c848b3eb518158a02fe\n#: c8f92542a4bc431fb8bbe56eaf71bdea ce742763a46a417ba689244aa10bf44a\n#: d5863e853d39455bb5e5414aa34ed878 daf50cfc40fb4142aec7eb19b1540003\n#: dbfa429a9021430ab3c7f8d80f4ace2f e938d44e132d433aa42ffc35f429d343\n#: f8d308248d98414f933d5194478d6985 faa94ecd4765407a84feaa3a5ba92790\nmsgid \"|history_end|\"\nmsgstr \"|history_end|\"\n\n#: ../../page.rst:174 51bdd00946d148b8953854efd83df01a\nmsgid \"\"\n\"PDF only: Add a comment icon (\\\"sticky note\\\") with accompanying text. \"\n\"Only the icon is visible, the accompanying text is hidden and can be \"\n\"visualized by many PDF viewers by hovering the mouse over the symbol.\"\nmsgstr \"\"\n\"PDF 전용: 텍스트와 함께 주석 아이콘(\\\"스티키 노트\\\")을 추가합니다. 아이콘만 보이고 텍스트는 숨겨져 있으며 많은 PDF \"\n\"뷰어에서 기호 위에 마우스를 올리면 표시할 수 있습니다.\"\n\n#: ../../page.rst:176 54a369191cb44ecbb72939e1cfcc1991\nmsgid \"\"\n\"the top left point of a 20 x 20 rectangle containing the MuPDF-provided \"\n\"\\\"note\\\" icon.\"\nmsgstr \"MuPDF에서 제공하는 \\\"노트\\\" 아이콘을 포함하는 20 x 20 사각형의 왼쪽 위 점.\"\n\n#: ../../page.rst:178 fd77aeb8334442388dd2eec90ebfbe94\nmsgid \"\"\n\"the commentary text. This will be shown on double clicking or hovering \"\n\"over the icon. May contain any Latin characters.\"\nmsgstr \"주석 텍스트. 아이콘을 더블 클릭하거나 마우스를 올리면 표시됩니다. 모든 라틴 문자를 포함할 수 있습니다.\"\n\n#: ../../page.rst:179 456b5d9d70414bb3a75145bb8d68febf\nmsgid \"\"\n\"choose one of \\\"Note\\\" (default), \\\"Comment\\\", \\\"Help\\\", \\\"Insert\\\", \"\n\"\\\"Key\\\", \\\"NewParagraph\\\", \\\"Paragraph\\\" as the visual symbol for the \"\n\"embodied text [#f4]_. (New in v1.16.0)\"\nmsgstr \"\"\n\"\\\"Note\\\" (기본값), \\\"Comment\\\", \\\"Help\\\", \\\"Insert\\\", \\\"Key\\\", \"\n\"\\\"NewParagraph\\\", \\\"Paragraph\\\" 중 하나를 텍스트의 시각적 기호로 선택합니다 [#f4]_. \"\n\"(v1.16.0에서 새로 추가됨)\"\n\n#: ../../page.rst:182 37733ed2d61c4a4d8963c8fa2c20f9f2\nmsgid \"\"\n\"the created annotation. Stroke color yellow = (1, 1, 0), no fill color \"\n\"support.\"\nmsgstr \"생성된 주석. 선 색상 노란색 = (1, 1, 0), 채우기 색상 지원 없음.\"\n\n#: ../../page.rst:202 1c146be34a16419cb8750d19046ac2ab\nmsgid \"\"\n\"PDF only: Add text in a given rectangle. Optionally, the appearance of a \"\n\"\\\"callout\\\" shape can be requested by specifying two or three point-like \"\n\"objects -- see below.\"\nmsgstr \"\"\n\"PDF 전용: 주어진 사각형에 텍스트를 추가합니다. 선택적으로 두 개 또는 세 개의 점과 같은 객체를 지정하여 \\\"말풍선\\\" 모양의\"\n\" 모양을 요청할 수 있습니다 -- 아래 참조.\"\n\n#: ../../page.rst:204 44b8581ef22344d99a19590077f4ce46\nmsgid \"\"\n\"the rectangle into which the text should be inserted. Text is \"\n\"automatically wrapped to a new line at box width. Text portions not \"\n\"fitting into the rectangle will be invisible without warning.\"\nmsgstr \"\"\n\"텍스트가 삽입될 사각형. 텍스트는 상자 너비에서 자동으로 새 줄로 줄바꿈됩니다. 사각형에 맞지 않는 텍스트 부분은 경고 없이 보이지\"\n\" 않습니다.\"\n\n#: ../../page.rst:206 7d331bcc143943c4a9bb8a8a2db24dd5\nmsgid \"\"\n\"the text. May contain any mixture of Latin, Greek, Cyrillic, Chinese, \"\n\"Japanese and Korean characters. If `richtext=True` (see below), the \"\n\"string is interpreted as HTML syntax. This adds a plethora of ways for \"\n\"attractive effects.\"\nmsgstr \"\"\n\"텍스트. 라틴, 그리스, 키릴, 중국어, 일본어 및 한국어 문자의 모든 조합을 포함할 수 있습니다. `richtext=True` \"\n\"(아래 참조)인 경우 문자열은 HTML 구문으로 해석됩니다. 이것은 매력적인 효과를 위한 다양한 방법을 추가합니다.\"\n\n#: ../../page.rst:208 d184d4430ee747d88f8881eb7b24ea82\nmsgid \"the :data:`fontsize`. Default is 11. Ignored if `richtext=True`.\"\nmsgstr \":data:`fontsize`. 기본값은 11입니다. `richtext=True` 인 경우 무시됩니다.\"\n\n#: ../../page.rst:210 4fa1ef6ca2f44a17b6c91719560a60dd\nmsgid \"\"\n\"The font name. Default is \\\"Helv\\\". Ignored if `richtext=True`, otherwise\"\n\" the following **restritions apply:**  * Accepted alternatives are \"\n\"\\\"Helv\\\" (Helvetica), \\\"Cour\\\" (Courier), \\\"TiRo\\\" (Timnes-Roman), \"\n\"\\\"ZaDb\\\" (ZapfDingBats) and \\\"Symb\\\" (Symbol). The name may be \"\n\"abbreviated to the first two characters, like \\\"Co\\\" for \\\"Cour\\\", lower \"\n\"case accepted.  * Bold or italic variants of the fonts are **not \"\n\"supported.**\"\nmsgstr \"\"\n\n#: ../../page.rst:210 cf9b9e8045234c18b29151b3ff723fa6\nmsgid \"\"\n\"The font name. Default is \\\"Helv\\\". Ignored if `richtext=True`, otherwise\"\n\" the following **restritions apply:**\"\nmsgstr \"\"\n\"폰트 이름. 기본값은 \\\"Helv\\\"입니다. `richtext=True` 인 경우 무시되며, 그렇지 않으면 다음 **제한 사항이 \"\n\"적용됩니다:**\"\n\n#: ../../page.rst:212 6b9f7ab0730d4eecbf4ec937dfd826d2\nmsgid \"\"\n\"Accepted alternatives are \\\"Helv\\\" (Helvetica), \\\"Cour\\\" (Courier), \"\n\"\\\"TiRo\\\" (Timnes-Roman), \\\"ZaDb\\\" (ZapfDingBats) and \\\"Symb\\\" (Symbol). \"\n\"The name may be abbreviated to the first two characters, like \\\"Co\\\" for \"\n\"\\\"Cour\\\", lower case accepted.\"\nmsgstr \"\"\n\"허용되는 대안은 \\\"Helv\\\" (Helvetica), \\\"Cour\\\" (Courier), \\\"TiRo\\\" (Times-\"\n\"Roman), \\\"ZaDb\\\" (ZapfDingBats) 및 \\\"Symb\\\" (Symbol)입니다. 이름은 \\\"Cour\\\"의 경우 \"\n\"\\\"Co\\\"와 같이 처음 두 문자로 축약할 수 있으며, 소문자가 허용됩니다.\"\n\n#: ../../page.rst:214 123f4899566d48368c805d9f89b3e331\nmsgid \"Bold or italic variants of the fonts are **not supported.**\"\nmsgstr \"폰트의 굵게 또는 기울임꼴 변형은 **지원되지 않습니다.**\"\n\n#: ../../page.rst:216 6f8ffab38b19408191c5984a0e3f53f9\nmsgid \"the text color. Default is black. Ignored if `richtext=True`.\"\nmsgstr \"텍스트 색상. 기본값은 검은색입니다. `richtext=True` 인 경우 무시됩니다.\"\n\n#: ../../page.rst:218 f19df2fca1f946be8dc7d6eeaaa20718\nmsgid \"\"\n\"the fill color. This is used for ``rect`` and the end point of the \"\n\"callout lines when applicable. Default is ``None``.\"\nmsgstr \"채우기 색상. 이것은 ``rect`` 및 해당하는 경우 말풍선 선의 끝점에 사용됩니다. 기본값은 ``None`` 입니다.\"\n\n#: ../../page.rst:220 548acc7ce2da4307a490d2ec5ba5c350\nmsgid \"\"\n\"This parameter **only has an effect** if `richtext=True`. Otherwise, \"\n\"``text_color`` is used.\"\nmsgstr \"\"\n\"이 매개변수는 `richtext=True` 인 경우에만 **효과가 있습니다**. 그렇지 않으면 ``text_color`` 가 \"\n\"사용됩니다.\"\n\n#: ../../page.rst:222 63943749331c448b8b846ca3551f473d\nmsgid \"\"\n\"the width of border and ``callout`` lines. Default is 0 (no border), in \"\n\"which case callout lines may still appear with some hairline width, \"\n\"depending on the PDF viewer used. In any case, this value must be \"\n\"positive to see a border line.\"\nmsgstr \"\"\n\"테두리 및 ``callout`` 선의 너비. 기본값은 0(테두리 없음)이며, 이 경우 사용된 PDF 뷰어에 따라 말풍선 선이 여전히\"\n\" 얇은 선 너비로 나타날 수 있습니다. 어떤 경우든 테두리 선을 보려면 이 값이 양수여야 합니다.\"\n\n#: ../../page.rst:224 d9a2ef0ede15487f9edfb910a15dcaed\nmsgid \"\"\n\"a list of floats specifying how border and callout lines should be \"\n\"dashed. Default is ``None``.\"\nmsgstr \"테두리 및 말풍선 선을 점선으로 표시하는 방법을 지정하는 float 목록. 기본값은 ``None`` 입니다.\"\n\n#: ../../page.rst:226 c9271c8fdd374e65988f2aaffd340aea\nmsgid \"\"\n\"a list / tuple of two or three :data:`point_like` objects, which will be \"\n\"interpreted as end point [, knee point] and start point (in this \"\n\"sequence) of up to two line segments, converting this annotation into a \"\n\"call-out shape.\"\nmsgstr \"\"\n\"두 개 또는 세 개의 :data:`point_like` 객체의 리스트/튜플로, 최대 두 개의 선분의 끝점 [, 무릎 점] 및 \"\n\"시작점(이 순서로)으로 해석되어 이 주석을 말풍선 모양으로 변환합니다.\"\n\n#: ../../page.rst:228 c33f0a979817431cbd682918b0e62222\nmsgid \"\"\n\"the line end symbol of the call-out line. It is drawn at the first point \"\n\"specified in the `callout` list. Default is an open arrow. For possible \"\n\"values see :ref:`AnnotationLineEnds`.\"\nmsgstr \"\"\n\"말풍선 선의 선 끝 기호. `callout` 목록에 지정된 첫 번째 점에 그려집니다. 기본값은 열린 화살표입니다. 가능한 값은 \"\n\":ref:`AnnotationLineEnds` 를 참조하세요.\"\n\n#: ../../page.rst:230 1d92cdcfd87147edb5f5e0bc43ff50ba\nmsgid \"\"\n\"a float `0 <= opacity < 1` turning the annotation transparent. Default is\"\n\" no transparency.\"\nmsgstr \"주석을 투명하게 만드는 float `0 <= opacity < 1`. 기본값은 투명도 없음입니다.\"\n\n#: ../../page.rst:232 cfc26e251ca346dd905d4712fc2ff181\nmsgid \"\"\n\"text alignment, one of TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, \"\n\"TEXT_ALIGN_RIGHT - justify is **not supported**. Ignored if \"\n\"`richtext=True`.\"\nmsgstr \"\"\n\"텍스트 정렬, TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT 중 하나 - 양쪽 \"\n\"정렬은 **지원되지 않습니다**. `richtext=True` 인 경우 무시됩니다.\"\n\n#: ../../page.rst:234 034b62bc622e49068cee63693843f5a1\nmsgid \"\"\n\"the text orientation. Accepted values are integer multiples of 90°. \"\n\"Invalid entries receive a rotation of 0.\"\nmsgstr \"텍스트 방향. 허용되는 값은 90°의 정수 배수입니다. 잘못된 항목은 회전 0을 받습니다.\"\n\n#: ../../page.rst:236 da57bcf6cd3b4c3d8e9b68d91eedfe24\nmsgid \"\"\n\"treat ``text`` as HTML syntax. This allows to achieve **bold**, *italic*,\"\n\" arbitrary text colors, font sizes, text alignment including justify and \"\n\"more - as far as the PDF subset of HTML and styling instructions supports\"\n\" this. This is similar to what happens in :meth:`Page.insert_htmlbox`. \"\n\"The base library will for example pull in required fonts if it encounters\"\n\" characters not contained in the standard ones. Some parameters are \"\n\"ignored if this option is set, as mentioned above. Default is ``False``.\"\nmsgstr \"\"\n\"``text`` 를 HTML 구문으로 처리합니다. 이것은 **굵게**, *기울임꼴*, 임의의 텍스트 색상, 폰트 크기, 양쪽 정렬을\"\n\" 포함한 텍스트 정렬 등을 달성할 수 있게 합니다 - PDF HTML 서브셋 및 스타일 지시문이 이를 지원하는 한. 이것은 \"\n\":meth:`Page.insert_htmlbox` 에서 일어나는 것과 유사합니다. 기본 라이브러리는 예를 들어 표준 폰트에 포함되지\"\n\" 않은 문자를 만나면 필요한 폰트를 가져옵니다. 이 옵션이 설정되면 위에서 언급한 대로 일부 매개변수가 무시됩니다. 기본값은 \"\n\"``False`` 입니다.\"\n\n#: ../../page.rst:238 32ec7963c0a04bc78b1231ca653e0386\nmsgid \"\"\n\"supply optional HTML styling information in CSS syntax. Ignored if \"\n\"`richtext=False`.\"\nmsgstr \"CSS 구문으로 선택적 HTML 스타일 정보를 제공합니다. `richtext=False` 인 경우 무시됩니다.\"\n\n#: ../../page.rst:241 5984cf38fa2c47028b2e176e5b062090\nmsgid \"the created annotation.\"\nmsgstr \"생성된 주석.\"\n\n#: ../../page.rst:245 7e930f01ce524eddac7121e39875dce0\nmsgid \"Changed in v1.19.6: add border color parameter\"\nmsgstr \"v1.19.6에서 변경됨: 테두리 색상 매개변수 추가\"\n\n#: ../../page.rst:251 0ba858ddf30f47268c90815b704bd8d7\nmsgid \"\"\n\"PDF only: Add a file attachment annotation with a \\\"PushPin\\\" icon at the\"\n\" specified location.\"\nmsgstr \"PDF 전용: 지정된 위치에 \\\"PushPin\\\" 아이콘이 있는 파일 첨부 주석을 추가합니다.\"\n\n#: ../../page.rst:253 952eb34fd29645e3b86fc95af04e12e6\nmsgid \"\"\n\"the top-left point of a 18x18 rectangle containing the MuPDF-provided \"\n\"\\\"PushPin\\\" icon.\"\nmsgstr \"MuPDF에서 제공하는 \\\"PushPin\\\" 아이콘을 포함하는 18x18 사각형의 왼쪽 위 점.\"\n\n#: ../../page.rst:255 33c54f02d9ec4958aac36d4ae87ec8b2\nmsgid \"\"\n\"the data to be stored (actual file content, any data, etc.).  Changed in \"\n\"v1.14.13: *io.BytesIO* is now also supported.\"\nmsgstr \"\"\n\n#: ../../page.rst:255 49a1495385834b0bb8c253a6b035e372\nmsgid \"the data to be stored (actual file content, any data, etc.).\"\nmsgstr \"저장할 데이터(실제 파일 콘텐츠, 모든 데이터 등).\"\n\n#: ../../page.rst:257 9106ac69cad44285868e1db831a4f80b\nmsgid \"Changed in v1.14.13: *io.BytesIO* is now also supported.\"\nmsgstr \"v1.14.13에서 변경됨: *io.BytesIO* 도 이제 지원됩니다.\"\n\n#: ../../page.rst:259 3054cf84528a428d9364a2a12859b693\nmsgid \"the filename to associate with the data.\"\nmsgstr \"데이터와 연결할 파일명.\"\n\n#: ../../page.rst:260 f0ee2128fd164598b042072345e030e6\nmsgid \"the optional PDF unicode version of filename. Defaults to filename.\"\nmsgstr \"파일명의 선택적 PDF 유니코드 버전. 기본값은 파일명입니다.\"\n\n#: ../../page.rst:261 7ed966fa13094c65b1becda615d4f72d\nmsgid \"an optional description of the file. Defaults to filename.\"\nmsgstr \"파일의 선택적 설명. 기본값은 파일명입니다.\"\n\n#: ../../page.rst:262 04c62225b8b74b298de1c93e5d5f135e\nmsgid \"\"\n\"choose one of \\\"PushPin\\\" (default), \\\"Graph\\\", \\\"Paperclip\\\", \\\"Tag\\\" as\"\n\" the visual symbol for the attached data [#f4]_. (New in v1.16.0)\"\nmsgstr \"\"\n\"\\\"PushPin\\\" (기본값), \\\"Graph\\\", \\\"Paperclip\\\", \\\"Tag\\\" 중 하나를 첨부된 데이터의 시각적 \"\n\"기호로 선택합니다 [#f4]_. (v1.16.0에서 새로 추가됨)\"\n\n#: ../../page.rst:265 e780faf60aac4a58992bf36f5c9ef190\nmsgid \"\"\n\"the created annotation.  Stroke color yellow = (1, 1, 0), no fill color \"\n\"support.\"\nmsgstr \"생성된 주석.  선 색상 노란색 = (1, 1, 0), 채우기 색상 지원 없음.\"\n\n#: ../../page.rst:269 d747b4142e74426e9cafa1e1fad1b357\nmsgid \"PDF only: Add a \\\"freehand\\\" scribble annotation.\"\nmsgstr \"PDF 전용: \\\"자유형\\\" 낙서 주석을 추가합니다.\"\n\n#: ../../page.rst:271 14e1a3e9c61047ab82b59eb44e721ebf\nmsgid \"\"\n\"a list of one or more lists, each containing :data:`point_like` items. \"\n\"Each item in these sublists is interpreted as a :ref:`Point` through \"\n\"which a connecting line is drawn. Separate sublists thus represent \"\n\"separate drawing lines.\"\nmsgstr \"\"\n\"하나 이상의 리스트의 리스트로, 각각 :data:`point_like` 항목을 포함합니다. 이러한 하위 리스트의 각 항목은 연결 \"\n\"선이 그려지는 :ref:`Point` 로 해석됩니다. 따라서 별도의 하위 리스트는 별도의 그리기 선을 나타냅니다.\"\n\n#: ../../page.rst:274 c78d5be71625401caa352e4a3546e8d9\nmsgid \"\"\n\"the created annotation in default appearance black =(0, 0, 0),line width \"\n\"1. No fill color support.\"\nmsgstr \"기본 모양 검은색 =(0, 0, 0), 선 너비 1의 생성된 주석. 채우기 색상 지원 없음.\"\n\n#: ../../page.rst:278 83a7dfd91643427b9b3ddae21297d1e0\nmsgid \"PDF only: Add a line annotation.\"\nmsgstr \"PDF 전용: 선 주석을 추가합니다.\"\n\n#: ../../page.rst:280 982abaa9a3b04d7dab7a869c40500ee8\nmsgid \"the starting point of the line.\"\nmsgstr \"선의 시작점.\"\n\n#: ../../page.rst:282 71f3d7598f4a438baa35931f6d2292a1\nmsgid \"the end point of the line.\"\nmsgstr \"선의 끝점.\"\n\n#: ../../page.rst:285 d0d3f8e6caee4c659fef7470860d22be\nmsgid \"\"\n\"the created annotation. It is drawn with line (stroke) color red = (1, 0,\"\n\" 0) and line width 1. No fill color support. The **annot rectangle** is \"\n\"automatically created to contain both points, each one surrounded by a \"\n\"circle of radius 3 * line width to make room for any line end symbols.\"\nmsgstr \"\"\n\"생성된 주석. 선(스트로크) 색상 빨간색 = (1, 0, 0) 및 선 너비 1로 그려집니다. 채우기 색상 지원 없음. **주석 \"\n\"사각형** 은 두 점을 포함하도록 자동으로 생성되며, 각 점은 선 끝 기호를 위한 공간을 만들기 위해 반경 3 * 선 너비의 원으로\"\n\" 둘러싸입니다.\"\n\n#: ../../page.rst:291 c1c26bec4d8a4a449fd8205433749a68\nmsgid \"PDF only: Add a rectangle, resp. circle annotation.\"\nmsgstr \"PDF 전용: 사각형, 각각 원형 주석을 추가합니다.\"\n\n#: ../../page.rst:293 fbd4ba67216045c7863c4d7c09726bdc\nmsgid \"\"\n\"the rectangle in which the circle or rectangle is drawn, must be finite \"\n\"and not empty. If the rectangle is not equal-sided, an ellipse is drawn.\"\nmsgstr \"원 또는 사각형이 그려지는 사각형은 유한하고 비어 있지 않아야 합니다. 사각형이 정사각형이 아니면 타원이 그려집니다.\"\n\n#: ../../page.rst:296 2d270d9060804012bc6a6d6daae01393\nmsgid \"\"\n\"the created annotation. It is drawn with line (stroke) color red = (1, 0,\"\n\" 0), line width 1, fill color is supported.\"\nmsgstr \"생성된 주석. 선(스트로크) 색상 빨간색 = (1, 0, 0), 선 너비 1로 그려지며, 채우기 색상이 지원됩니다.\"\n\n#: ../../page.rst:301 b2d0c457ed934ffa8cc63c9daba01877\nmsgid \"Redactions\"\nmsgstr \"수정\"\n\n#: ../../page.rst:305 83d32da0d6a9408b8f95066f77189a66\nmsgid \"\"\n\"**PDF only**: Add a redaction annotation. A redaction annotation \"\n\"identifies an area whose content should be removed from the document. \"\n\"Adding such an annotation is the first of two steps. It makes visible \"\n\"what will be removed in the subsequent step, \"\n\":meth:`Page.apply_redactions`.\"\nmsgstr \"\"\n\"**PDF 전용**: 수정 주석을 추가합니다. 수정 주석은 콘텐츠가 문서에서 제거되어야 하는 영역을 식별합니다. 이러한 주석을 \"\n\"추가하는 것은 두 단계 중 첫 번째 단계입니다. 다음 단계인 :meth:`Page.apply_redactions` 에서 제거될 \"\n\"내용을 표시합니다.\"\n\n#: ../../page.rst:307 4699fffeef5d4362a039fb781b613690\nmsgid \"\"\n\"specifies the (rectangular) area to be removed which is always equal to \"\n\"the annotation rectangle. This may be a :data:`rect_like` or \"\n\":data:`quad_like` object. If a quad is specified, then the enveloping \"\n\"rectangle is taken.\"\nmsgstr \"\"\n\"제거할 (사각형) 영역을 지정하며 항상 주석 사각형과 같습니다. 이것은 :data:`rect_like` 또는 \"\n\":data:`quad_like` 객체일 수 있습니다. quad가 지정되면 둘러싸는 사각형이 사용됩니다.\"\n\n#: ../../page.rst:309 ba0ad939c6964388bbf9da8a1426e156\nmsgid \"\"\n\"text to be placed in the rectangle after applying the redaction (and thus\"\n\" removing old content). (New in v1.16.12)\"\nmsgstr \"수정을 적용한 후(따라서 이전 콘텐츠를 제거한 후) 사각형에 배치할 텍스트. (v1.16.12에서 새로 추가됨)\"\n\n#: ../../page.rst:311 d2d149590d334bd4877f4fc44334eb88\nmsgid \"\"\n\"the font to use when ``text`` is given, otherwise ignored. Only CJK and \"\n\"the :ref:`Base-14-Fonts` are supported. Apart from this, the same rules \"\n\"apply as for :meth:`Page.insert_textbox` -- which is what the method \"\n\":meth:`Page.apply_redactions` internally invokes.\"\nmsgstr \"\"\n\"``text`` 가 제공될 때 사용할 폰트, 그렇지 않으면 무시됩니다. CJK 및 :ref:`Base-14-Fonts` 만 \"\n\"지원됩니다. 이 외에는 :meth:`Page.insert_textbox` 와 동일한 규칙이 적용됩니다 -- 이것은 메서드 \"\n\":meth:`Page.apply_redactions` 가 내부적으로 호출하는 것입니다.\"\n\n#: ../../page.rst:313 cc4732ea5ec8414ba11322e9735299c3\nmsgid \"\"\n\"the :data:`fontsize` to use for the replacing text. If the text is too \"\n\"large to fit, several insertion attempts will be made, gradually reducing\"\n\" the :data:`fontsize` to no less than 4. If then the text will still not \"\n\"fit, no text insertion will take place at all. (New in v1.16.12)\"\nmsgstr \"\"\n\"교체 텍스트에 사용할 :data:`fontsize`. 텍스트가 너무 커서 맞지 않으면 여러 번 삽입을 시도하며, \"\n\":data:`fontsize` 를 점진적으로 4 이상으로 줄입니다. 그래도 텍스트가 맞지 않으면 텍스트 삽입이 전혀 수행되지 \"\n\"않습니다. (v1.16.12에서 새로 추가됨)\"\n\n#: ../../page.rst:315 c4d7520aac904bb99519e58c6bf2140d\nmsgid \"\"\n\"the horizontal alignment for the replacing text. See \"\n\":meth:`insert_textbox` for available values. The vertical alignment is \"\n\"(approximately) centered.\"\nmsgstr \"\"\n\"교체 텍스트의 수평 정렬. 사용 가능한 값은 :meth:`insert_textbox` 를 참조하세요. 수직 정렬은 (대략) \"\n\"중앙입니다.\"\n\n#: ../../page.rst:317 b3a02eedc12844f68db67a48da623653\nmsgid \"\"\n\"the fill color of the rectangle **after applying** the redaction. The \"\n\"default is *white = (1, 1, 1)*, which is also taken if ``None`` is \"\n\"specified. To suppress a fill color altogether, specify ``False``. In \"\n\"this cases the rectangle remains transparent. (New in v1.16.12)\"\nmsgstr \"\"\n\"수정을 **적용한 후** 사각형의 채우기 색상. 기본값은 *white = (1, 1, 1)* 이며, ``None`` 이 지정된 \"\n\"경우에도 사용됩니다. 채우기 색상을 완전히 억제하려면 ``False`` 를 지정하세요. 이 경우 사각형은 투명하게 유지됩니다. \"\n\"(v1.16.12에서 새로 추가됨)\"\n\n#: ../../page.rst:319 4f1d52476fb54ea7910fb134279060cc\nmsgid \"\"\n\"the color of the replacing text. Default is *black = (0, 0, 0)*. (New in \"\n\"v1.16.12)\"\nmsgstr \"교체 텍스트의 색상. 기본값은 *black = (0, 0, 0)* 입니다. (v1.16.12에서 새로 추가됨)\"\n\n#: ../../page.rst:321 9d20ca01e5ec49d48597ab52ae2429d6\nmsgid \"add two diagonal lines to the annotation rectangle. (New in v1.17.2)\"\nmsgstr \"주석 사각형에 두 개의 대각선을 추가합니다. (v1.17.2에서 새로 추가됨)\"\n\n#: ../../page.rst:324 5d7ae07a1eae47d3af0293d6f1cebff7\nmsgid \"\"\n\"the created annotation. Its standard appearance looks like a red \"\n\"rectangle (no fill color), optionally showing two diagonal lines. Colors,\"\n\" line width, dashing, opacity and blend mode can now be set and applied \"\n\"via :meth:`Annot.update` like with other annotations. (Changed in \"\n\"v1.17.2)\"\nmsgstr \"\"\n\"생성된 주석. 표준 모양은 빨간색 사각형(채우기 색상 없음)이며, 선택적으로 두 개의 대각선을 표시합니다. 색상, 선 너비, 점선,\"\n\" 불투명도 및 블렌드 모드는 이제 다른 주석과 마찬가지로 :meth:`Annot.update` 를 통해 설정하고 적용할 수 \"\n\"있습니다. (v1.17.2에서 변경됨)\"\n\n#: ../../page.rst:330 ../../page.rst:370 8a91d58a85a54e15a0c2a92ab4be3fc8\n#: ffdf3291e16d4f3193e3c0d91e3f2010\nmsgid \"New in v1.16.11\"\nmsgstr \"v1.16.11에서 새로 추가됨\"\n\n#: ../../page.rst:337 3c7a5faae9b0449d91c14474c64d2051\nmsgid \"\"\n\"**PDF only**: Remove all **content** contained in any redaction rectangle\"\n\" on the page.\"\nmsgstr \"**PDF 전용**: 페이지의 모든 수정 사각형에 포함된 **콘텐츠** 를 제거합니다.\"\n\n#: ../../page.rst:339 ee1fc729c3c14392bb729f007f5b6698\nmsgid \"**This method applies and then deletes all redactions from the page.**\"\nmsgstr \"**이 메서드는 모든 수정을 적용한 다음 페이지에서 삭제합니다.**\"\n\n#: ../../page.rst:341 b227244aaa8440a58e165311f3d4e159\nmsgid \"\"\n\"How to redact overlapping images. The default (2) blanks out overlapping \"\n\"pixels. `PDF_REDACT_IMAGE_NONE | 0` ignores, and `PDF_REDACT_IMAGE_REMOVE\"\n\" | 1` completely removes images overlapping any redaction annotation. \"\n\"Option `PDF_REDACT_IMAGE_REMOVE_UNLESS_INVISIBLE | 3` only removes images\"\n\" that are actually visible.\"\nmsgstr \"\"\n\"겹치는 이미지를 수정하는 방법. 기본값(2)은 겹치는 픽셀을 지웁니다. `PDF_REDACT_IMAGE_NONE | 0` 은 \"\n\"무시하고, `PDF_REDACT_IMAGE_REMOVE | 1` 은 수정 주석과 겹치는 이미지를 완전히 제거합니다. 옵션 \"\n\"`PDF_REDACT_IMAGE_REMOVE_UNLESS_INVISIBLE | 3` 은 실제로 보이는 이미지만 제거합니다.\"\n\n#: ../../page.rst:343 732d8771fa524855a96d98bab564cb8f\n#, python-format\nmsgid \"\"\n\"How to redact overlapping vector graphics (also called \\\"line-art\\\" or \"\n\"\\\"drawings\\\"). The default (2) removes any overlapping vector graphics. \"\n\"`PDF_REDACT_LINE_ART_NONE | 0` ignores, and \"\n\"`PDF_REDACT_LINE_ART_REMOVE_IF_COVERED | 1` removes graphics fully \"\n\"contained in a redaction annotation. When removing line-art, please be \"\n\"aware that **stroked** vector graphics (i.e. type \\\"s\\\" or \\\"sf\\\") have a\"\n\" **larger wrapping rectangle** than one might expect: first of all, at \"\n\"least 50% of the path's line width have to be added in each direction to \"\n\"truly include all of the drawing. If a so-called \\\"miter limit\\\" is \"\n\"provided (see page 121 of the PDF specification), the enlarging value is \"\n\"`miter * width / 2`. So, when letting everything default (width = 1, \"\n\"miter = 10), the redaction rectangle should be at least 5 points larger \"\n\"in every direction.\"\nmsgstr \"\"\n\"겹치는 벡터 그래픽(또한 \\\"line-art\\\" 또는 \\\"drawings\\\"라고도 함)을 수정하는 방법. 기본값(2)은 겹치는 모든\"\n\" 벡터 그래픽을 제거합니다. `PDF_REDACT_LINE_ART_NONE | 0` 은 무시하고, \"\n\"`PDF_REDACT_LINE_ART_REMOVE_IF_COVERED | 1` 은 수정 주석에 완전히 포함된 그래픽을 제거합니다. \"\n\"line-art를 제거할 때 **스트로크된** 벡터 그래픽(즉, 타입 \\\"s\\\" 또는 \\\"sf\\\")은 예상보다 **큰 래핑 \"\n\"사각형** 을 가집니다: 먼저, 그림의 모든 부분을 실제로 포함하려면 경로의 선 너비의 최소 50%를 각 방향으로 추가해야 합니다.\"\n\" 소위 \\\"miter limit\\\"이 제공되면(PDF 사양 121페이지 참조), 확대 값은 `miter * width / 2` \"\n\"입니다. 따라서 모든 것을 기본값으로 두면(width = 1, miter = 10), 수정 사각형은 모든 방향으로 최소 5포인트 더\"\n\" 커야 합니다.\"\n\n#: ../../page.rst:345 b034080c271e4abea6940e78ca7c9b9f\nmsgid \"\"\n\"Whether to redact overlapping text. The default `PDF_REDACT_TEXT_REMOVE |\"\n\" 0` removes all characters whose boundary box overlaps any redaction \"\n\"rectangle. This complies with the original legal / data protection \"\n\"intentions of redaction annotations. Other use cases however may require \"\n\"to **keep text** while redacting vector graphics or images. This can be \"\n\"achieved by setting `text=True|PDF_REDACT_TEXT_NONE | 1`. This does **not\"\n\" comply** with the data protection intentions of redaction annotations. \"\n\"**Do so at your own risk.**\"\nmsgstr \"\"\n\"겹치는 텍스트를 수정할지 여부. 기본값 `PDF_REDACT_TEXT_REMOVE | 0` 은 경계 상자가 수정 사각형과 겹치는 \"\n\"모든 문자를 제거합니다. 이것은 수정 주석의 원래 법적/데이터 보호 의도에 부합합니다. 그러나 다른 사용 사례에서는 벡터 그래픽이나\"\n\" 이미지를 수정하는 동안 **텍스트를 유지** 해야 할 수 있습니다. 이것은 \"\n\"`text=True|PDF_REDACT_TEXT_NONE | 1` 로 설정하여 달성할 수 있습니다. 이것은 수정 주석의 데이터 보호\"\n\" 의도에 **부합하지 않습니다**. **자신의 위험으로 수행하세요.**\"\n\n#: ../../page.rst:347 a88c35da262e43b885d7144a0ff5712f\nmsgid \"\"\n\"`True` if at least one redaction annotation has been processed, `False` \"\n\"otherwise.\"\nmsgstr \"최소 하나의 수정 주석이 처리되었으면 `True`, 그렇지 않으면 `False`.\"\n\n#: ../../page.rst:350 fe01d8d5869c414186b762c70b99a4ea\nmsgid \"\"\n\"Text contained in a redaction rectangle will be **physically** removed \"\n\"from the page (assuming :meth:`Document.save` with a suitable garbage \"\n\"option) and will no longer appear in e.g. text extractions or anywhere \"\n\"else. All redaction annotations will also be removed. Other annotations \"\n\"are unaffected.\"\nmsgstr \"\"\n\"수정 사각형에 포함된 텍스트는 페이지에서 **물리적으로** 제거됩니다(적절한 가비지 옵션으로 :meth:`Document.save`\"\n\" 가정) 그리고 예를 들어 텍스트 추출이나 다른 곳에서 더 이상 나타나지 않습니다. 모든 수정 주석도 제거됩니다. 다른 주석은 \"\n\"영향을 받지 않습니다.\"\n\n#: ../../page.rst:352 c550602fc16b4fb8a1296b8ddcc34b9c\nmsgid \"\"\n\"All overlapping links will be removed. If the rectangle of the link was \"\n\"covering text, then only the overlapping part of the text is being \"\n\"removed. Similar applies to images covered by link rectangles.\"\nmsgstr \"\"\n\"모든 겹치는 링크가 제거됩니다. 링크의 사각형이 텍스트를 덮고 있으면 텍스트의 겹치는 부분만 제거됩니다. 링크 사각형으로 덮인 \"\n\"이미지에도 유사하게 적용됩니다.\"\n\n#: ../../page.rst:354 40b2cb822b0647bdae0d55262944a78a\nmsgid \"\"\n\"The overlapping parts of **images** will be blanked-out for default \"\n\"option `PDF_REDACT_IMAGE_PIXELS` (changed in v1.18.0). Option 0 does not \"\n\"touch any images and 1 will remove any image with an overlap.\"\nmsgstr \"\"\n\"**이미지** 의 겹치는 부분은 기본 옵션 `PDF_REDACT_IMAGE_PIXELS` (v1.18.0에서 변경됨)에 대해 \"\n\"지워집니다. 옵션 0은 이미지를 건드리지 않고 1은 겹치는 모든 이미지를 제거합니다.\"\n\n#: ../../page.rst:356 25b61da15edd48a0899311789eb7ce0f\nmsgid \"\"\n\"For option `images=PDF_REDACT_IMAGE_REMOVE` only this page's **references\"\n\" to the images** are removed - not necessarily the images themselves. \"\n\"Images are completely removed from the file only, if no longer referenced\"\n\" at all (assuming suitable garbage collection options).\"\nmsgstr \"\"\n\"옵션 `images=PDF_REDACT_IMAGE_REMOVE` 의 경우 이 페이지의 **이미지에 대한 참조** 만 제거됩니다 - \"\n\"반드시 이미지 자체는 아닙니다. 이미지는 더 이상 전혀 참조되지 않는 경우에만 파일에서 완전히 제거됩니다(적절한 가비지 수집 옵션 \"\n\"가정).\"\n\n#: ../../page.rst:358 16e6a9f129dd4eee890575533deb157d\nmsgid \"\"\n\"For option `images=PDF_REDACT_IMAGE_PIXELS` a new image of format PNG is \"\n\"created, which the page will use in place of the original one. The \"\n\"original image is not deleted or replaced as part of this process, so \"\n\"other pages may still show the original. In addition, the new, modified \"\n\"PNG image currently is **stored uncompressed**. Do keep these aspects in \"\n\"mind when choosing the right garbage collection method and compression \"\n\"options during save.\"\nmsgstr \"\"\n\"옵션 `images=PDF_REDACT_IMAGE_PIXELS` 의 경우 PNG 형식의 새 이미지가 생성되며, 페이지는 원본 대신 \"\n\"이것을 사용합니다. 원본 이미지는 이 프로세스의 일부로 삭제되거나 교체되지 않으므로 다른 페이지는 여전히 원본을 표시할 수 \"\n\"있습니다. 또한 새로 수정된 PNG 이미지는 현재 **압축되지 않은 상태로 저장됩니다**. 저장 중 적절한 가비지 수집 방법과 압축\"\n\" 옵션을 선택할 때 이러한 측면을 염두에 두세요.\"\n\n#: ../../page.rst:360 6836ae0f5eec41e98cc524e3c6d99a04\nmsgid \"\"\n\"**Text removal** is done by character: A character is removed if its bbox\"\n\" has a **non-empty overlap** with a redaction rectangle (changed in MuPDF\"\n\" v1.17). Depending on the font properties and / or the chosen line \"\n\"height, deletion may occur for undesired text parts. Using \"\n\":meth:`Tools.set_small_glyph_heights` with a ``True`` argument before \"\n\"text search may help to prevent this.\"\nmsgstr \"\"\n\"**텍스트 제거** 는 문자별로 수행됩니다: 문자의 bbox가 수정 사각형과 **비어 있지 않은 겹침** 이 있으면 \"\n\"제거됩니다(MuPDF v1.17에서 변경됨). 폰트 속성 및/또는 선택한 줄 높이에 따라 원하지 않는 텍스트 부분에 대한 삭제가 \"\n\"발생할 수 있습니다. 텍스트 검색 전에 ``True`` 인수로 :meth:`Tools.set_small_glyph_heights` \"\n\"를 사용하면 이를 방지하는 데 도움이 될 수 있습니다.\"\n\n#: ../../page.rst:362 d8fd1608b6084336aed580baa042cfaa\nmsgid \"\"\n\"Redactions are a simple way to replace single words in a PDF, or to just \"\n\"physically remove them. Locate the word \\\"secret\\\" using some text \"\n\"extraction or search method and insert a redaction using \\\"xxxxxx\\\" as \"\n\"replacement text for each occurrence.\"\nmsgstr \"\"\n\"수정은 PDF에서 단일 단어를 교체하거나 물리적으로 제거하는 간단한 방법입니다. 텍스트 추출 또는 검색 방법을 사용하여 \"\n\"\\\"secret\\\" 단어를 찾고 각 발생에 대해 \\\"xxxxxx\\\" 를 교체 텍스트로 사용하여 수정을 삽입합니다.\"\n\n#: ../../page.rst:364 47c46c9b96834ac9ad8367ae6450697d\nmsgid \"\"\n\"Be wary if the replacement is longer than the original -- this may lead \"\n\"to an awkward appearance, line breaks or no new text at all.\"\nmsgstr \"교체가 원본보다 긴 경우 주의하세요 -- 이것은 어색한 모양, 줄 바꿈 또는 새 텍스트가 전혀 없을 수 있습니다.\"\n\n#: ../../page.rst:366 8682db4dc4af41178c7504d6e0765c2b\nmsgid \"\"\n\"For a number of reasons, the new text may not exactly be positioned on \"\n\"the same line like the old one -- especially true if the replacement font\"\n\" was not one of CJK or :ref:`Base-14-Fonts`.\"\nmsgstr \"\"\n\"여러 가지 이유로 새 텍스트가 이전 텍스트와 정확히 같은 줄에 위치하지 않을 수 있습니다 -- 특히 교체 폰트가 CJK 또는 \"\n\":ref:`Base-14-Fonts` 중 하나가 아닌 경우.\"\n\n#: ../../page.rst:371 8e9d6723068947caa9c1a7728e5ec00f\nmsgid \"\"\n\"Changed in v1.16.12: The previous *mark* parameter is gone. Instead, the \"\n\"respective rectangles are filled with the individual *fill* color of each\"\n\" redaction annotation. If a *text* was given in the annotation, then \"\n\":meth:`insert_textbox` is invoked to insert it, using parameters provided\"\n\" with the redaction.\"\nmsgstr \"\"\n\"v1.16.12에서 변경됨: 이전 *mark* 매개변수가 제거되었습니다. 대신 각 수정 주석의 개별 *fill* 색상으로 해당 \"\n\"사각형이 채워집니다. 주석에 *text* 가 제공된 경우 :meth:`insert_textbox` 가 수정과 함께 제공된 매개변수를\"\n\" 사용하여 삽입하도록 호출됩니다.\"\n\n#: ../../page.rst:372 46f68e0c832a480ba4bd336ac3910095\nmsgid \"\"\n\"Changed in v1.18.0: added option for handling images that overlap \"\n\"redaction areas.\"\nmsgstr \"v1.18.0에서 변경됨: 수정 영역과 겹치는 이미지를 처리하는 옵션 추가.\"\n\n#: ../../page.rst:373 2465ee7b86d54db8bee38570925d4320\nmsgid \"Changed in v1.23.27: added option for removing graphics as well.\"\nmsgstr \"v1.23.27에서 변경됨: 그래픽 제거 옵션도 추가.\"\n\n#: ../../page.rst:374 c25bbe521c624b7ab8551b69d1b5a92e\nmsgid \"Changed in v1.24.2: added option `keep_text` to leave text untouched.\"\nmsgstr \"v1.24.2에서 변경됨: 텍스트를 그대로 두는 옵션 `keep_text` 추가.\"\n\n#: ../../page.rst:384 5b39575061fd4afaa2313b0f235fed1c\nmsgid \"\"\n\"PDF only: Add an annotation consisting of lines which connect the given \"\n\"points. A **Polygon's** first and last points are automatically \"\n\"connected, which does not happen for a **PolyLine**. The **rectangle** is\"\n\" automatically created as the smallest rectangle containing the points, \"\n\"each one surrounded by a circle of radius 3 (= 3 * line width). The \"\n\"following shows a 'PolyLine' that has been modified with colors and line \"\n\"ends.\"\nmsgstr \"\"\n\"PDF 전용: 주어진 점을 연결하는 선으로 구성된 주석을 추가합니다. **Polygon** 의 첫 번째와 마지막 점은 자동으로 \"\n\"연결되지만, **PolyLine** 에서는 그렇지 않습니다. **사각형** 은 점을 포함하는 가장 작은 사각형으로 자동 생성되며, \"\n\"각 점은 반경 3(= 3 * 선 너비)의 원으로 둘러싸입니다. 다음은 색상과 선 끝으로 수정된 'PolyLine'을 보여줍니다.\"\n\n#: ../../page.rst:386 bf625a70b5dc4b178bf672dc80445d94\nmsgid \"a list of :data:`point_like` objects.\"\nmsgstr \":data:`point_like` 객체의 리스트.\"\n\n#: ../../page.rst:389 3436f7a64b5947eabaebb816d9bed65e\nmsgid \"\"\n\"the created annotation. It is drawn with line color black, line width 1 \"\n\"no fill color but fill color support. Use methods of :ref:`Annot` to make\"\n\" any changes to achieve something like this:\"\nmsgstr \"\"\n\"생성된 주석. 선 색상 검은색, 선 너비 1, 채우기 색상 없음이지만 채우기 색상 지원. 다음과 같은 것을 달성하기 위해 변경하려면\"\n\" :ref:`Annot` 의 메서드를 사용하세요:\"\n\n#: ../../page.rst:402 4dd3a4352c934a608cde37542c01e320\nmsgid \"\"\n\"PDF only: These annotations are normally used for **marking text** which \"\n\"has previously been somehow located (for example via \"\n\":meth:`Page.search_for`). But this is not required: you are free to \"\n\"\\\"mark\\\" just anything.\"\nmsgstr \"\"\n\"PDF 전용: 이러한 주석은 일반적으로 이전에 어떤 방식으로든 찾은(예: :meth:`Page.search_for` 를 통해) \"\n\"**텍스트를 표시** 하는 데 사용됩니다. 하지만 이것은 필수는 아닙니다: 무엇이든 \\\"표시\\\"할 수 있습니다.\"\n\n#: ../../page.rst:404 ea4d8dff219844daa8178bfd53fe0a12\nmsgid \"\"\n\"Standard (stroke only -- no fill color support) colors are chosen per \"\n\"annotation type: **yellow** for highlighting, **red** for striking out, \"\n\"**green** for underlining, and **magenta** for wavy underlining.\"\nmsgstr \"\"\n\"표준(스트로크만 -- 채우기 색상 지원 없음) 색상은 주석 유형별로 선택됩니다: 강조는 **노란색**, 취소선은 **빨간색**, \"\n\"밑줄은 **초록색**, 물결 밑줄은 **자홍색**.\"\n\n#: ../../page.rst:406 fd77f9fb49924c3b983cc2177df9713c\nmsgid \"\"\n\"All these four methods convert the arguments into a list of :ref:`Quad` \"\n\"objects. The **annotation** rectangle is then calculated to envelop all \"\n\"these quadrilaterals.\"\nmsgstr \"\"\n\"이 네 가지 메서드는 모두 인수를 :ref:`Quad` 객체의 리스트로 변환합니다. 그런 다음 **주석** 사각형이 이러한 모든 \"\n\"사각형을 둘러싸도록 계산됩니다.\"\n\n#: ../../page.rst:410 b78e92f1133b4f79b8e187d5fdea27b7\nmsgid \"\"\n\":meth:`search_for` delivers a list of either :ref:`Rect` or :ref:`Quad` \"\n\"objects. Such a list can be directly used as an argument for these \"\n\"annotation types and will deliver **one common annotation** for all \"\n\"occurrences of the search string::\"\nmsgstr \"\"\n\":meth:`search_for` 는 :ref:`Rect` 또는 :ref:`Quad` 객체의 리스트를 제공합니다. 이러한 리스트는 \"\n\"이러한 주석 유형에 대한 인수로 직접 사용할 수 있으며 검색 문자열의 모든 발생에 대해 **하나의 공통 주석** 을 제공합니다::\"\n\n#: ../../page.rst:417 3704912806054f3d84b31c8400d3484c\nmsgid \"\"\n\"Obviously, text marker annotations need to know what is the top, the \"\n\"bottom, the left, and the right side of the area(s) to be marked. If the \"\n\"arguments are quads, this information is given by the sequence of the \"\n\"quad points. In contrast, a rectangle delivers much less information -- \"\n\"this is illustrated by the fact, that 4! = 24 different quads can be \"\n\"constructed with the four corners of a rectangle.\"\nmsgstr \"\"\n\"명백히, 텍스트 마커 주석은 표시할 영역의 위, 아래, 왼쪽, 오른쪽이 무엇인지 알아야 합니다. 인수가 quad인 경우 이 정보는 \"\n\"quad 점의 시퀀스로 제공됩니다. 반면 사각형은 훨씬 적은 정보를 제공합니다 -- 사각형의 네 모서리로 4! = 24개의 서로 \"\n\"다른 quad를 구성할 수 있다는 사실로 설명됩니다.\"\n\n#: ../../page.rst:419 108dfad6a6804b93849fe97049fcbb6b\nmsgid \"\"\n\"Therefore, we **strongly recommend** to use the `quads` option for text \"\n\"searches, to ensure correct annotations. A similar consideration applies \"\n\"to marking **text spans** extracted with the \\\"dict\\\" / \\\"rawdict\\\" \"\n\"options of :meth:`Page.get_text`. For more details on how to compute \"\n\"quadrilaterals in this case, see section \\\"How to Mark Non-horizontal \"\n\"Text\\\" of :ref:`FAQ`.\"\nmsgstr \"\"\n\"따라서 올바른 주석을 보장하기 위해 텍스트 검색에 `quads` 옵션을 사용하는 것을 **강력히 권장** 합니다. \"\n\":meth:`Page.get_text` 의 \\\"dict\\\" / \\\"rawdict\\\" 옵션으로 추출한 **텍스트 범위** 를 표시하는\"\n\" 데도 유사한 고려 사항이 적용됩니다. 이 경우 사각형을 계산하는 방법에 대한 자세한 내용은 :ref:`FAQ` 의 \\\"How to\"\n\" Mark Non-horizontal Text\\\" 섹션을 참조하세요.\"\n\n#: ../../page.rst:421 bfe59f51028a411fa50cabaf2e094b6e\nmsgid \"\"\n\"the location(s) -- rectangle(s) or quad(s) -- to be marked. (Changed in \"\n\"v1.14.20) A list or tuple must consist of :data:`rect_like` or \"\n\":data:`quad_like` items (or even a mixture of either). Every item must be\"\n\" finite, convex and not empty (as applicable). **Set this parameter to** \"\n\"``None`` if you want to use the following arguments (Changed in \"\n\"v1.16.14). And vice versa: if not ``None``, the remaining parameters must\"\n\" be ``None``.\"\nmsgstr \"\"\n\"표시할 위치(들) -- 사각형(들) 또는 quad(들). (v1.14.20에서 변경됨) 리스트 또는 튜플은 \"\n\":data:`rect_like` 또는 :data:`quad_like` 항목(또는 둘의 혼합)으로 구성되어야 합니다. 모든 항목은 \"\n\"유한하고 볼록하며 비어 있지 않아야 합니다(해당하는 경우). 다음 인수를 사용하려면 **이 매개변수를** ``None`` **으로 \"\n\"설정하세요** (v1.16.14에서 변경됨). 반대로 ``None`` 이 아니면 나머지 매개변수는 ``None`` 이어야 합니다.\"\n\n#: ../../page.rst:428 697342726fe34ff398a5409e6779d128\nmsgid \"\"\n\"start text marking at this point. Defaults to the top-left point of \"\n\"*clip*. Must be provided if `quads` is ``None``. (New in v1.16.14)\"\nmsgstr \"\"\n\"이 지점에서 텍스트 표시를 시작합니다. 기본값은 *clip* 의 왼쪽 위 점입니다. `quads` 가 ``None`` 이면 제공해야\"\n\" 합니다. (v1.16.14에서 새로 추가됨)\"\n\n#: ../../page.rst:429 99afe3b4e6cf47ac8ea2a1d1d7b606ae\nmsgid \"\"\n\"stop text marking at this point. Defaults to the bottom-right point of \"\n\"*clip*. Must be used if `quads` is ``None``. (New in v1.16.14)\"\nmsgstr \"\"\n\"이 지점에서 텍스트 표시를 중지합니다. 기본값은 *clip* 의 오른쪽 아래 점입니다. `quads` 가 ``None`` 이면 \"\n\"사용해야 합니다. (v1.16.14에서 새로 추가됨)\"\n\n#: ../../page.rst:430 bea300d1621748ce83ab03b89f2b395e\nmsgid \"\"\n\"only consider text lines intersecting this area. Defaults to the page \"\n\"rectangle. Only use if `start` and `stop` are provided. (New in v1.16.14)\"\nmsgstr \"\"\n\"이 영역과 교차하는 텍스트 줄만 고려합니다. 기본값은 페이지 사각형입니다. `start` 와 `stop` 이 제공된 경우에만 \"\n\"사용하세요. (v1.16.14에서 새로 추가됨)\"\n\n#: ../../page.rst:432 6474b312ac1a4d25852c770d5bdf88d8\nmsgid \":ref:`Annot` or ``None`` (changed in v1.16.14).\"\nmsgstr \":ref:`Annot` 또는 ``None`` (v1.16.14에서 변경됨).\"\n\n#: ../../page.rst:433 74842949adb04e869dce146ffd17a597\nmsgid \"\"\n\"the created annotation. If *quads* is an empty list, **no annotation** is\"\n\" created (changed in v1.16.14).\"\nmsgstr \"생성된 주석. *quads* 가 빈 리스트이면 **주석이 생성되지 않습니다** (v1.16.14에서 변경됨).\"\n\n#: ../../page.rst:436 d493279763eb4f87a14d71a66c32af2f\nmsgid \"\"\n\"You can use parameters *start*, *stop* and *clip* to highlight \"\n\"consecutive lines between the points *start* and *stop* (starting with \"\n\"v1.16.14). Make use of *clip* to further reduce the selected line bboxes \"\n\"and thus deal with e.g. multi-column pages. The following multi-line \"\n\"highlight on a page with three text columns was created by specifying the\"\n\" two red points and setting clip accordingly.\"\nmsgstr \"\"\n\"매개변수 *start*, *stop* 및 *clip* 을 사용하여 점 *start* 와 *stop* 사이의 연속 줄을 강조할 수 \"\n\"있습니다(v1.16.14부터). *clip* 을 사용하여 선택된 줄 bbox를 더 줄여 예를 들어 다중 열 페이지를 처리합니다. 세\"\n\" 개의 텍스트 열이 있는 페이지의 다음 다중 줄 강조는 두 개의 빨간 점을 지정하고 clip을 그에 따라 설정하여 생성되었습니다.\"\n\n#: ../../page.rst:445 d74c77b69420460eb871f194686b3c80\nmsgid \"\"\n\"Cluster vector graphics (synonyms are line-art or drawings) based on \"\n\"their geometrical vicinity. The method walks through the output of \"\n\":meth:`Page.get_drawings` and joins paths whose `path[\\\"rect\\\"]` are \"\n\"closer to each other than some tolerance values (given in the arguments).\"\n\" The result is a list of rectangles that each wrap things like tables \"\n\"(with gridlines), pie charts, bar charts, etc.\"\nmsgstr \"\"\n\"기하학적 근접성을 기반으로 벡터 그래픽(line-art 또는 drawings의 동의어)을 클러스터링합니다. 이 메서드는 \"\n\":meth:`Page.get_drawings` 의 출력을 순회하고 `path[\\\"rect\\\"]` 가 인수에 주어진 일부 허용 오차 \"\n\"값보다 서로 가까운 경로를 결합합니다. 결과는 각각 테이블(격자선 포함), 파이 차트, 막대 차트 등을 래핑하는 사각형의 \"\n\"리스트입니다.\"\n\n#: ../../page.rst:447 ef1d1a3ba8044b5a8123bb549d84a95b\nmsgid \"only consider paths inside this area. The default is the full page.\"\nmsgstr \"이 영역 내의 경로만 고려합니다. 기본값은 전체 페이지입니다.\"\n\n#: ../../page.rst:449 996f2a02107e43a2af1da07cdc4de257\nmsgid \"\"\n\"(optional) provide a previously generated output of \"\n\":meth:`Page.get_drawings`. If `None` the method will execute the method.\"\nmsgstr \"\"\n\"(선택 사항) :meth:`Page.get_drawings` 의 이전에 생성된 출력을 제공합니다. `None` 이면 메서드가 \"\n\"메서드를 실행합니다.\"\n\n#: ../../page.rst:451 2248b6e73ea7456f90b4bfa892920615\nmsgid \"\"\n\"Assume vector graphics to be close enough neighbors for belonging to the \"\n\"same rectangle. Default is 3 points.\"\nmsgstr \"벡터 그래픽이 같은 사각형에 속하기에 충분히 가까운 이웃이라고 가정합니다. 기본값은 3포인트입니다.\"\n\n#: ../../page.rst:453 fc002ef42f2f4c3cb5bd1d64346b1c48\nmsgid \"\"\n\"If `True` (default), the method will to remove rectangles having width or\"\n\" height smaller than the respective tolerance value. If `False` no such \"\n\"filtering is done.\"\nmsgstr \"\"\n\"`True` (기본값)이면 메서드는 너비 또는 높이가 각각의 허용 오차 값보다 작은 사각형을 제거합니다. `False` 이면 이러한\"\n\" 필터링이 수행되지 않습니다.\"\n\n#: ../../page.rst:457 06ada75b5a1e4fb59ff381d81b4677e9\nmsgid \"\"\n\"Find tables on the page and return an object with related information. \"\n\"Typically, the default values of the many parameters will be sufficient. \"\n\"Adjustments should ever only be needed in corner case situations.\"\nmsgstr \"\"\n\"페이지에서 테이블을 찾고 관련 정보가 있는 객체를 반환합니다. 일반적으로 많은 매개변수의 기본값으로 충분합니다. 조정은 극단적인 \"\n\"경우에만 필요해야 합니다.\"\n\n#: ../../page.rst:459 0c9311c5177241cc976d58ebbf05a74b\nmsgid \"\"\n\"specify a region to consider within the page rectangle and ignore the \"\n\"rest. Default is the full page.\"\nmsgstr \"페이지 사각형 내에서 고려할 영역을 지정하고 나머지는 무시합니다. 기본값은 전체 페이지입니다.\"\n\n#: ../../page.rst:461 0849ed084d16401a9405689de88c6028\nmsgid \"\"\n\"Request a **table detection** strategy. Valid values are \\\"lines\\\", \"\n\"\\\"lines_strict\\\" and \\\"text\\\".  Default is **\\\"lines\\\"** which uses all \"\n\"vector graphics on the page to detect grid lines.  Strategy \"\n\"**\\\"lines_strict\\\"** ignores borderless rectangle vector graphics. \"\n\"Sometimes single text pieces have background colors which may lead to \"\n\"false columns or lines. This strategy ignores them and can thus increase \"\n\"detection precision.  If **\\\"text\\\"** is specified, text positions are \"\n\"used to generate \\\"virtual\\\" column and / or row boundaries. Use \"\n\"`min_words_*` to request the number of words for considering their \"\n\"coordinates.  Use parameters `vertical_strategy` and \"\n\"`horizontal_strategy` **instead** for a more fine-grained treatment of \"\n\"the dimensions.\"\nmsgstr \"\"\n\n#: ../../page.rst:461 59bbe23f13b64174be60fb9b13ef829b\nmsgid \"\"\n\"Request a **table detection** strategy. Valid values are \\\"lines\\\", \"\n\"\\\"lines_strict\\\" and \\\"text\\\".\"\nmsgstr \"**테이블 감지** 전략을 요청합니다. 유효한 값은 \\\"lines\\\", \\\"lines_strict\\\" 및 \\\"text\\\"입니다.\"\n\n#: ../../page.rst:463 67630a4262924cc0b8aaebb89659163f\nmsgid \"\"\n\"Default is **\\\"lines\\\"** which uses all vector graphics on the page to \"\n\"detect grid lines.\"\nmsgstr \"기본값은 페이지의 모든 벡터 그래픽을 사용하여 격자선을 감지하는 **\\\"lines\\\"** 입니다.\"\n\n#: ../../page.rst:465 917a16e50aac418b8449496f8539789f\nmsgid \"\"\n\"Strategy **\\\"lines_strict\\\"** ignores borderless rectangle vector \"\n\"graphics. Sometimes single text pieces have background colors which may \"\n\"lead to false columns or lines. This strategy ignores them and can thus \"\n\"increase detection precision.\"\nmsgstr \"\"\n\"전략 **\\\"lines_strict\\\"** 는 테두리 없는 사각형 벡터 그래픽을 무시합니다. 때로는 단일 텍스트 조각에 배경색이 \"\n\"있어 잘못된 열이나 줄을 유발할 수 있습니다. 이 전략은 이를 무시하므로 감지 정밀도를 높일 수 있습니다.\"\n\n#: ../../page.rst:467 6d39e7994a18489c9d4948721b10cb65\nmsgid \"\"\n\"If **\\\"text\\\"** is specified, text positions are used to generate \"\n\"\\\"virtual\\\" column and / or row boundaries. Use `min_words_*` to request \"\n\"the number of words for considering their coordinates.\"\nmsgstr \"\"\n\"**\\\"text\\\"** 가 지정되면 텍스트 위치를 사용하여 \\\"가상\\\" 열 및/또는 행 경계를 생성합니다. `min_words_*`\"\n\" 를 사용하여 좌표를 고려하기 위한 단어 수를 요청합니다.\"\n\n#: ../../page.rst:469 4a9d3be706634b32bfcb3a2d83e20c65\nmsgid \"\"\n\"Use parameters `vertical_strategy` and `horizontal_strategy` **instead** \"\n\"for a more fine-grained treatment of the dimensions.\"\nmsgstr \"\"\n\"차원에 대한 더 세밀한 처리를 위해 매개변수 `vertical_strategy` 및 `horizontal_strategy` 를 \"\n\"**대신** 사용하세요.\"\n\n#: ../../page.rst:471 15e7fe12ec2247fbbb34818a5eff8199\nmsgid \"\"\n\"y-coordinates of rows. If provided, there will be no attempt to identify \"\n\"additional table rows. This influences table detection.\"\nmsgstr \"행의 y 좌표. 제공되면 추가 테이블 행을 식별하려는 시도가 없습니다. 이것은 테이블 감지에 영향을 줍니다.\"\n\n#: ../../page.rst:473 4dc514da6d994fa5baff233b3567f0d4\nmsgid \"\"\n\"x-coordinates of columns. If provided, there will be no attempt to \"\n\"identify additional table columns. This influences table detection.\"\nmsgstr \"열의 x 좌표. 제공되면 추가 테이블 열을 식별하려는 시도가 없습니다. 이것은 테이블 감지에 영향을 줍니다.\"\n\n#: ../../page.rst:475 6a395bf9fe0545ea97c66c3ad92a7ae0\nmsgid \"\"\n\"relevant for vertical strategy option \\\"text\\\": at least this many words \"\n\"must coincide to establish a **virtual column** boundary.\"\nmsgstr \"수직 전략 옵션 \\\"text\\\"와 관련: **가상 열** 경계를 설정하려면 최소 이만큼의 단어가 일치해야 합니다.\"\n\n#: ../../page.rst:477 41131201c866498ab06ef20259e8b494\nmsgid \"\"\n\"relevant for horizontal strategy option \\\"text\\\": at least this many \"\n\"words must coincide to establish a **virtual row** boundary.\"\nmsgstr \"수평 전략 옵션 \\\"text\\\"와 관련: **가상 행** 경계를 설정하려면 최소 이만큼의 단어가 일치해야 합니다.\"\n\n#: ../../page.rst:479 26168ab280dd42a7bb9a4c34a044a502\nmsgid \"\"\n\"Any two horizontal lines whose y-values differ by no more than this value\"\n\" will be **snapped** into one. Accordingly for vertical lines. Default is\"\n\" 3. Separate values can be specified instead for the dimensions, using \"\n\"`snap_x_tolerance` and `snap_y_tolerance`.\"\nmsgstr \"\"\n\"y 값의 차이가 이 값 이하인 두 개의 수평선은 하나로 **스냅** 됩니다. 수직선도 마찬가지입니다. 기본값은 3입니다. 이 값 대신 `snap_x_tolerance` 및 `snap_y_tolerance` 를 사용하여 차원별로 별도의 값을 지정할 수 있습니다.\"\n\n#: ../../page.rst:481 1bce671a9bde42b3bcb301e9dc7929e7\nmsgid \"\"\n\"Any two lines will be **joined** to one if the end and the start points \"\n\"differ by no more than this value (in points). Default is 3. Instead of \"\n\"this value, separate values can be specified for the dimensions using \"\n\"`join_x_tolerance` and `join_y_tolerance`.\"\nmsgstr \"\"\n\"끝점과 시작점의 차이가 이 값(포인트 단위) 이하인 경우 두 선이 하나로 **결합** 됩니다. 기본값은 3입니다. 이 값 대신 `join_x_tolerance` 및 `join_y_tolerance` 를 사용하여 차원별로 별도의 값을 지정할 수 있습니다.\"\n\n#: ../../page.rst:483 00e7c337bf764aa5a2eae76cdd16ae4a\nmsgid \"\"\n\"Ignore a line if its length does not exceed this value (points). Default \"\n\"is 3.\"\nmsgstr \"길이가 이 값(포인트 단위)을 초과하지 않으면 선을 무시합니다. 기본값은 3입니다.\"\n\n#: ../../page.rst:485 0be2257abf46430e99630f4f4a04f230\nmsgid \"\"\n\"When combining lines into cell borders, orthogonal lines must be within \"\n\"this value (points) to be considered intersecting. Default is 3. Instead \"\n\"of this value, separate values can be specified for the dimensions using \"\n\"`intersection_x_tolerance` and `intersection_y_tolerance`.\"\nmsgstr \"\"\n\"선을 셀 경계로 결합할 때 직교하는 선은 교차하는 것으로 간주되려면 이 값(포인트 단위) 이내에 있어야 합니다. 기본값은 3입니다. 이 값 대신 `intersection_x_tolerance` 및 `intersection_y_tolerance` 를 사용하여 차원별로 별도의 값을 지정할 수 있습니다.\"\n\n#: ../../page.rst:487 dedd15f25c9f481997ff9451f0f5eaf6\nmsgid \"\"\n\"Characters will be combined into words only if their distance is no \"\n\"larger than this value (points). Default is 3. Instead of this value, \"\n\"separate values can be specified for the dimensions using \"\n\"`text_x_tolerance` and `text_y_tolerance`.\"\nmsgstr \"\"\n\"문자가 단어로 결합되는 것은 거리가 이 값(포인트 단위) 이하인 경우에만입니다. 기본값은 3입니다. 이 값 대신 `text_x_tolerance` 및 `text_y_tolerance` 를 사용하여 차원별로 별도의 값을 지정할 수 있습니다.\"\n\n#: ../../page.rst:489 f08fd2e9d00f4dac93ce2b4c53ec8d83\nmsgid \"\"\n\"Specify a list of \\\"lines\\\" (i.e. pairs of :data:`point_like` objects) as\"\n\" **additional**, \\\"virtual\\\" vector graphics. These lines may help with \"\n\"table and / or cell detection and will not otherwise influence the \"\n\"detection strategy. Especially, in contrast to parameters \"\n\"`horizontal_lines` and `vertical_lines`, they will not prevent detecting \"\n\"rows or columns in other ways. These lines will be treated exactly like \"\n\"\\\"real\\\" vector graphics in terms of joining, snapping, intersecting, \"\n\"minimum length and containment in the `clip` rectangle. Similarly, lines \"\n\"not parallel to any of the coordinate axes will be ignored.\"\nmsgstr \"\"\n\"\\\"lines\\\"(즉, :data:`point_like` 객체 쌍)의 리스트를 **추가** \\\"가상\\\" 벡터 그래픽으로 지정합니다. 이러한 선은 테이블 및/또는 셀 감지에 도움이 될 수 있으며 감지 전략에는 영향을 주지 않습니다. 특히 `horizontal_lines` 및 `vertical_lines` 매개변수와 달리 다른 방법으로 행이나 열을 감지하는 것을 방지하지 않습니다. 이러한 선은 결합, 스냅, 교차, 최소 길이 및 `clip` 사각형 내 포함 측면에서 \\\"실제\\\" 벡터 그래픽과 정확히 동일하게 처리됩니다. 마찬가지로 좌표축 중 어느 것과도 평행하지 않은 선은 무시됩니다.\"\n\n#: ../../page.rst:491 c0c00b0e2c6a4e68bc1e1d28b6fd62de\nmsgid \"\"\n\"Specify a list of rectangles (:data:`rect_like` objects) as \"\n\"**additional**, \\\"virtual\\\" vector graphics. These rectangles may help \"\n\"with table and / or cell detection and will not otherwise influence the \"\n\"detection strategy. Especially, in contrast to parameters \"\n\"`horizontal_lines` and `vertical_lines`, they will not prevent detecting \"\n\"rows or columns in other ways. These rectangles will be treated exactly \"\n\"like \\\"real\\\" vector graphics in terms of joining, snapping, \"\n\"intersecting, minimum length and containment in the `clip` rectangle.\"\nmsgstr \"\"\n\"사각형(:data:`rect_like` 객체)의 리스트를 **추가** \\\"가상\\\" 벡터 그래픽으로 지정합니다. 이러한 사각형은 테이블 및/또는 셀 감지에 도움이 될 수 있으며 감지 전략에는 영향을 주지 않습니다. 특히 `horizontal_lines` 및 `vertical_lines` 매개변수와 달리 다른 방법으로 행이나 열을 감지하는 것을 방지하지 않습니다. 이러한 사각형은 결합, 스냅, 교차, 최소 길이 및 `clip` 사각형 내 포함 측면에서 \\\"실제\\\" 벡터 그래픽과 정확히 동일하게 처리됩니다.\"\n\n#: ../../page.rst:493 af5ac1f1b1ad4b87b5c8e3c21cea5682\nmsgid \"\"\n\"list of vector graphics in the format as returned be \"\n\":meth:`Page.get_drawings`. Using this parameter will prevent the method \"\n\"to extract vector graphics itself. This is useful if the vector graphics \"\n\"are already available. This can save execution time significantly.\"\nmsgstr \"\"\n\":meth:`Page.get_drawings` 에서 반환되는 형식의 벡터 그래픽 리스트. 이 매개변수를 사용하면 메서드가 벡터 그래픽을 자체적으로 추출하지 않습니다. 벡터 그래픽이 이미 사용 가능한 경우 유용합니다. 이것은 실행 시간을 크게 절약할 수 있습니다.\"\n\n#: ../../page.rst:497 6a7b22cafaa94fd1903b1029979996b7\nmsgid \"\"\n\"a `TableFinder` object that has the following significant attributes:  * \"\n\"`cells`: a list of **all bboxes** on the page, that have been identified \"\n\"as table cells (across all tables). Each cell is a :data:`rect_like` \"\n\"tuple `(x0, y0, x1, y1)` of coordinates or `None`. * `tables`: a list of \"\n\"`Table` objects. This is `[]` if the page has no tables. Single tables \"\n\"can be found as items of this list. But the `TableFinder` object itself \"\n\"is also a sequence of its tables. This means that if `tabs` is a \"\n\"`TableFinder` object, then table \\\"n\\\" is delivered by `tabs.tables[n]` \"\n\"as well as by the shorter `tabs[n]`.   * The `Table` object has the \"\n\"following attributes:    * ``bbox``: the bounding box of the table as a \"\n\"tuple `(x0, y0, x1, y1)`.   * ``cells``: bounding boxes of the table's \"\n\"cells (list of tuples). A cell may also be `None`.   * ``extract()``: \"\n\"this method returns the text content of each table cell as a list of list\"\n\" of strings.   * ``to_markdown()``: this method returns the table as a \"\n\"**string in markdown format** (compatible to Github). Markdown viewers \"\n\"can render the string as a table. This output is optimized for **small \"\n\"token** sizes, which is especially beneficial for LLM/RAG feeds. Pandas \"\n\"DataFrames (see method `to_pandas()` below) offer an equivalent markdown \"\n\"table output which however is better readable for the human eye. Any line\"\n\" breaks (``\\\\n``) in cells are replaced by HTML line breaks tags `<br>`.\"\n\"   * `to_pandas()`: this method returns the table as a `pandas \"\n\"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n\"<https://pandas.pydata.org/docs/reference/frame.html>`_. DataFrames are \"\n\"very versatile objects allowing a plethora of table manipulation methods \"\n\"and outputs to almost 20 well-known formats, among them Excel files, CSV,\"\n\" JSON, markdown-formatted tables and more. `DataFrame.to_markdown()` \"\n\"generates a Github-compatible markdown format optimized for human \"\n\"readability. This method however requires the package `tabulate \"\n\"<https://pypi.org/project/tabulate/>`_ to be installed in addition to \"\n\"pandas itself.   * ``header``: a `TableHeader` object containing header \"\n\"information of the table.   * ``col_count``: an integer containing the \"\n\"number of table columns.   * ``row_count``: an integer containing the \"\n\"number of table rows.   * ``rows``: a list of `TableRow` objects \"\n\"containing two attributes, ``bbox`` is the boundary box of the row, and \"\n\"`cells` is a list of table cells contained in this row.  * The \"\n\"`TableHeader` object has the following attributes:    * ``bbox``: the \"\n\"bounding box of the header.   * `cells`: a list of bounding boxes \"\n\"containing the name of the respective column.   * `names`: a list of \"\n\"strings containing the text of each of the cell bboxes. They represent \"\n\"the column names -- which are used when exporting the table to pandas \"\n\"DataFrames, markdown, etc.   * `external`: a bool indicating whether the \"\n\"header bbox is outside the table body (`True`) or not. Table headers are \"\n\"never identified by the `TableFinder` logic. Therefore, if `external` is \"\n\"true, then the header cells are not part of any cell identified by \"\n\"`TableFinder`. If `external == False`, then the first table row is the \"\n\"header.  Please have a look at these `Jupyter notebooks \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-\"\n\"analysis>`_, which cover standard situations like multiple tables on one \"\n\"page or joining table fragments across multiple pages.  .. caution:: The \"\n\"lifetime of the `TableFinder` object, as well as that of all its tables \"\n\"**equals the lifetime of the page**. If the page object is deleted or \"\n\"reassigned, all tables are no longer valid.     The only way to keep \"\n\"table content beyond the page's availability is to **extract it** via \"\n\"methods `Table.to_markdown()`, `Table.to_pandas()` or a copy of \"\n\"`Table.extract()` (e.g. `Table.extract()[:]`).  .. note::     Once a \"\n\"table has been extracted to a **Pandas DataFrame** with `to_pandas()` it \"\n\"is easy to convert to other file types with the **Pandas API**:     - \"\n\"table to Markdown, use `to_markdown \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_markdown.html#pandas.DataFrame.to_markdown>`_\"\n\"    - table to JSON, use: `to_json \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html>`_\"\n\"    - table to Excel, use: `to_excel \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html>`_\"\n\"    - table to CSV, use: `to_csv \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html>`_\"\n\"    - table to HTML, use: `to_html \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html>`_\"\n\"    - table to SQL, use: `to_sql \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html>`_\"\nmsgstr \"\"\n\n#: ../../page.rst:497 14ce635b23574ea2aa79e06c2f67cb17\nmsgid \"a `TableFinder` object that has the following significant attributes:\"\nmsgstr \"다음 중요한 속성을 가진 `TableFinder` 객체:\"\n\n#: ../../page.rst:499 d2cd90b9f2244722aad190152e8e2c32\nmsgid \"\"\n\"`cells`: a list of **all bboxes** on the page, that have been identified \"\n\"as table cells (across all tables). Each cell is a :data:`rect_like` \"\n\"tuple `(x0, y0, x1, y1)` of coordinates or `None`.\"\nmsgstr \"\"\n\"`cells`: 페이지의 **모든 bbox** 의 리스트로, 테이블 셀로 식별된 것들(모든 테이블에 걸쳐). 각 셀은 \"\n\":data:`rect_like` 좌표 튜플 `(x0, y0, x1, y1)` 또는 `None` 입니다.\"\n\n#: ../../page.rst:500 8631b526108946f0923ac7ccbc41d5a4\nmsgid \"\"\n\"`tables`: a list of `Table` objects. This is `[]` if the page has no \"\n\"tables. Single tables can be found as items of this list. But the \"\n\"`TableFinder` object itself is also a sequence of its tables. This means \"\n\"that if `tabs` is a `TableFinder` object, then table \\\"n\\\" is delivered \"\n\"by `tabs.tables[n]` as well as by the shorter `tabs[n]`.\"\nmsgstr \"\"\n\"`tables`: `Table` 객체의 리스트. 페이지에 테이블이 없으면 이것은 `[]` 입니다. 단일 테이블은 이 리스트의 \"\n\"항목으로 찾을 수 있습니다. 하지만 `TableFinder` 객체 자체는 또한 테이블의 시퀀스입니다. 이것은 `tabs` 가 \"\n\"`TableFinder` 객체이면 테이블 \\\"n\\\"은 `tabs.tables[n]` 뿐만 아니라 더 짧은 `tabs[n]` 으로도 \"\n\"제공된다는 것을 의미합니다.\"\n\n#: ../../page.rst:503 bf87893f818b480584c90a29e1dbfa51\nmsgid \"The `Table` object has the following attributes:\"\nmsgstr \"`Table` 객체는 다음 속성을 가집니다:\"\n\n#: ../../page.rst:505 df3028a1564f40df8e43a1893d30ae4e\nmsgid \"``bbox``: the bounding box of the table as a tuple `(x0, y0, x1, y1)`.\"\nmsgstr \"``bbox``: 튜플 `(x0, y0, x1, y1)` 로서의 테이블의 경계 상자.\"\n\n#: ../../page.rst:506 f5cc4094136b46c08a012633df49c27b\nmsgid \"\"\n\"``cells``: bounding boxes of the table's cells (list of tuples). A cell \"\n\"may also be `None`.\"\nmsgstr \"``cells``: 테이블의 셀의 경계 상자(튜플의 리스트). 셀은 `None` 일 수도 있습니다.\"\n\n#: ../../page.rst:507 b3a304e981ed49d4b70f79e9b07aaaeb\nmsgid \"\"\n\"``extract()``: this method returns the text content of each table cell as\"\n\" a list of list of strings.\"\nmsgstr \"``extract()``: 이 메서드는 각 테이블 셀의 텍스트 콘텐츠를 문자열의 리스트의 리스트로 반환합니다.\"\n\n#: ../../page.rst:508 ce2f7d37a3e741658ddc96d3dc5c24a6\nmsgid \"\"\n\"``to_markdown()``: this method returns the table as a **string in \"\n\"markdown format** (compatible to Github). Markdown viewers can render the\"\n\" string as a table. This output is optimized for **small token** sizes, \"\n\"which is especially beneficial for LLM/RAG feeds. Pandas DataFrames (see \"\n\"method `to_pandas()` below) offer an equivalent markdown table output \"\n\"which however is better readable for the human eye. Any line breaks \"\n\"(``\\\\n``) in cells are replaced by HTML line breaks tags `<br>`.\"\nmsgstr \"\"\n\"``to_markdown()``: 이 메서드는 테이블을 **마크다운 형식의 문자열** (Github과 호환)로 반환합니다. 마크다운\"\n\" 뷰어는 문자열을 테이블로 렌더링할 수 있습니다. 이 출력은 **작은 토큰** 크기에 최적화되어 있으며, 이는 LLM/RAG 피드에\"\n\" 특히 유익합니다. Pandas DataFrames (아래 `to_pandas()` 메서드 참조)는 동등한 마크다운 테이블 출력을 \"\n\"제공하지만 사람이 읽기에 더 좋습니다. 셀의 모든 줄 바꿈(``\\\\n``)은 HTML 줄 바꿈 태그 `<br>` 로 대체됩니다.\"\n\n#: ../../page.rst:509 dc4adc6d410b4f17bc5e500986371e2c\nmsgid \"\"\n\"`to_pandas()`: this method returns the table as a `pandas \"\n\"<https://pypi.org/project/pandas/>`_ `DataFrame \"\n\"<https://pandas.pydata.org/docs/reference/frame.html>`_. DataFrames are \"\n\"very versatile objects allowing a plethora of table manipulation methods \"\n\"and outputs to almost 20 well-known formats, among them Excel files, CSV,\"\n\" JSON, markdown-formatted tables and more. `DataFrame.to_markdown()` \"\n\"generates a Github-compatible markdown format optimized for human \"\n\"readability. This method however requires the package `tabulate \"\n\"<https://pypi.org/project/tabulate/>`_ to be installed in addition to \"\n\"pandas itself.\"\nmsgstr \"\"\n\"`to_pandas()`: 이 메서드는 테이블을 `pandas <https://pypi.org/project/pandas/>`_ \"\n\"`DataFrame <https://pandas.pydata.org/docs/reference/frame.html>`_ 로 \"\n\"반환합니다. DataFrames는 매우 다재다능한 객체로, 다양한 테이블 조작 메서드와 Excel 파일, CSV, JSON, \"\n\"마크다운 형식의 테이블 등을 포함하여 거의 20개의 잘 알려진 형식으로의 출력을 허용합니다. \"\n\"`DataFrame.to_markdown()` 은 사람이 읽기에 최적화된 Github 호환 마크다운 형식을 생성합니다. 그러나 이 \"\n\"메서드는 pandas 자체에 추가로 `tabulate <https://pypi.org/project/tabulate/>`_ 패키지가\"\n\" 설치되어 있어야 합니다.\"\n\n#: ../../page.rst:510 9197d223052b40478ad07f80abf7b1c7\nmsgid \"\"\n\"``header``: a `TableHeader` object containing header information of the \"\n\"table.\"\nmsgstr \"``header``: 테이블의 헤더 정보를 포함하는 `TableHeader` 객체.\"\n\n#: ../../page.rst:511 0136219af3784df8a0ecdc0efae8d13e\nmsgid \"``col_count``: an integer containing the number of table columns.\"\nmsgstr \"``col_count``: 테이블 열 수를 포함하는 정수.\"\n\n#: ../../page.rst:512 7a998ad68618450b8121ca084004080d\nmsgid \"``row_count``: an integer containing the number of table rows.\"\nmsgstr \"``row_count``: 테이블 행 수를 포함하는 정수.\"\n\n#: ../../page.rst:513 0a15078fa0ff449f802c15643224935a\nmsgid \"\"\n\"``rows``: a list of `TableRow` objects containing two attributes, \"\n\"``bbox`` is the boundary box of the row, and `cells` is a list of table \"\n\"cells contained in this row.\"\nmsgstr \"\"\n\"``rows``: 두 가지 속성을 포함하는 `TableRow` 객체의 리스트, ``bbox`` 는 행의 경계 상자이고 `cells`\"\n\" 는 이 행에 포함된 테이블 셀의 리스트입니다.\"\n\n#: ../../page.rst:515 13b8c3920d2a4476a60f5b4097a1db29\nmsgid \"The `TableHeader` object has the following attributes:\"\nmsgstr \"`TableHeader` 객체는 다음 속성을 가집니다:\"\n\n#: ../../page.rst:517 5bbd72ba48c345bc84309a25cc303e84\nmsgid \"``bbox``: the bounding box of the header.\"\nmsgstr \"``bbox``: 헤더의 경계 상자.\"\n\n#: ../../page.rst:518 bd434f2182484c0abbe32315f3e87f58\nmsgid \"\"\n\"`cells`: a list of bounding boxes containing the name of the respective \"\n\"column.\"\nmsgstr \"`cells`: 각 열의 이름을 포함하는 경계 상자의 리스트.\"\n\n#: ../../page.rst:519 7cf71a498dcd4f449eba656e7941013a\nmsgid \"\"\n\"`names`: a list of strings containing the text of each of the cell \"\n\"bboxes. They represent the column names -- which are used when exporting \"\n\"the table to pandas DataFrames, markdown, etc.\"\nmsgstr \"\"\n\"`names`: 각 셀 bbox의 텍스트를 포함하는 문자열의 리스트. 이것들은 열 이름을 나타냅니다 -- 테이블을 pandas \"\n\"DataFrames, 마크다운 등으로 내보낼 때 사용됩니다.\"\n\n#: ../../page.rst:520 eb6106330fdb44c2b44b4648645f7e28\nmsgid \"\"\n\"`external`: a bool indicating whether the header bbox is outside the \"\n\"table body (`True`) or not. Table headers are never identified by the \"\n\"`TableFinder` logic. Therefore, if `external` is true, then the header \"\n\"cells are not part of any cell identified by `TableFinder`. If `external \"\n\"== False`, then the first table row is the header.\"\nmsgstr \"\"\n\"`external`: 헤더 bbox가 테이블 본문 밖에 있는지(`True`) 여부를 나타내는 bool. 테이블 헤더는 \"\n\"`TableFinder` 로직에 의해 식별되지 않습니다. 따라서 `external` 이 true이면 헤더 셀은 \"\n\"`TableFinder` 에 의해 식별된 모든 셀의 일부가 아닙니다. `external == False` 이면 첫 번째 테이블 행이\"\n\" 헤더입니다.\"\n\n#: ../../page.rst:522 7a5884e0d9f84076927207f38c8676ff\nmsgid \"\"\n\"Please have a look at these `Jupyter notebooks \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-\"\n\"analysis>`_, which cover standard situations like multiple tables on one \"\n\"page or joining table fragments across multiple pages.\"\nmsgstr \"\"\n\"한 페이지에 여러 테이블이 있거나 여러 페이지에 걸쳐 테이블 조각을 결합하는 것과 같은 표준 상황을 다루는 이 `Jupyter \"\n\"notebooks <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master\"\n\"/table-analysis>`_ 를 살펴보세요.\"\n\n#: ../../page.rst:524 27f38775b85f46ed9b56fc7858feddc5\nmsgid \"\"\n\"The lifetime of the `TableFinder` object, as well as that of all its \"\n\"tables **equals the lifetime of the page**. If the page object is deleted\"\n\" or reassigned, all tables are no longer valid.\"\nmsgstr \"\"\n\"`TableFinder` 객체의 수명은 모든 테이블의 수명과 마찬가지로 **페이지의 수명과 같습니다**. 페이지 객체가 삭제되거나 \"\n\"재할당되면 모든 테이블이 더 이상 유효하지 않습니다.\"\n\n#: ../../page.rst:526 32b46a3c92844999ac692a3cd9b0e565\nmsgid \"\"\n\"The only way to keep table content beyond the page's availability is to \"\n\"**extract it** via methods `Table.to_markdown()`, `Table.to_pandas()` or \"\n\"a copy of `Table.extract()` (e.g. `Table.extract()[:]`).\"\nmsgstr \"\"\n\"페이지의 가용성을 넘어서 테이블 콘텐츠를 유지하는 유일한 방법은 메서드 `Table.to_markdown()`, \"\n\"`Table.to_pandas()` 또는 `Table.extract()` 의 복사본(예: `Table.extract()[:]`)을 \"\n\"통해 **추출하는** 것입니다.\"\n\n#: ../../page.rst:530 0af5c93cc78342cfba6d9a72d11d1283\nmsgid \"\"\n\"Once a table has been extracted to a **Pandas DataFrame** with \"\n\"`to_pandas()` it is easy to convert to other file types with the **Pandas\"\n\" API**:\"\nmsgstr \"\"\n\"테이블이 `to_pandas()` 로 **Pandas DataFrame** 으로 추출되면 **Pandas API** 로 다른 파일 \"\n\"형식으로 쉽게 변환할 수 있습니다:\"\n\n#: ../../page.rst:532 89be66118eb1404fad9df9edac01c3df\nmsgid \"\"\n\"table to Markdown, use `to_markdown \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_markdown.html#pandas.DataFrame.to_markdown>`_\"\nmsgstr \"\"\n\"테이블을 Markdown으로, `to_markdown \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_markdown.html#pandas.DataFrame.to_markdown>`_\"\n\" 사용\"\n\n#: ../../page.rst:533 92c2673b625246218f1a2c042893181a\nmsgid \"\"\n\"table to JSON, use: `to_json \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html>`_\"\nmsgstr \"\"\n\"테이블을 JSON으로, `to_json \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html>`_\"\n\" 사용\"\n\n#: ../../page.rst:534 157ef119e8044b0c98c73fd91ce91237\nmsgid \"\"\n\"table to Excel, use: `to_excel \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html>`_\"\nmsgstr \"\"\n\"테이블을 Excel로, `to_excel \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html>`_\"\n\" 사용\"\n\n#: ../../page.rst:535 2a6b453da70142089c467203f10917f7\nmsgid \"\"\n\"table to CSV, use: `to_csv \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html>`_\"\nmsgstr \"\"\n\"테이블을 CSV로, `to_csv \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html>`_\"\n\" 사용\"\n\n#: ../../page.rst:536 f1c6b94997bf4e2ca9977927dbd80716\nmsgid \"\"\n\"table to HTML, use: `to_html \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html>`_\"\nmsgstr \"\"\n\"테이블을 HTML로, `to_html \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html>`_\"\n\" 사용\"\n\n#: ../../page.rst:537 c9212bac99ad4a9e90b0fd8672a1f7ee\nmsgid \"\"\n\"table to SQL, use: `to_sql \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html>`_\"\nmsgstr \"\"\n\"테이블을 SQL로, `to_sql \"\n\"<https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html>`_\"\n\" 사용\"\n\n#: ../../page.rst:542 540aa40545614f7293315543269c8972\nmsgid \"New in version 1.23.0\"\nmsgstr \"버전 1.23.0에서 새로 추가됨\"\n\n#: ../../page.rst:543 36f561d72e0e474598eb7c9a62064674\nmsgid \"Changed in version 1.23.19: new argument `add_lines`.\"\nmsgstr \"버전 1.23.19에서 변경됨: 새 인수 `add_lines`.\"\n\n#: ../../page.rst:549 3159f7a5d1f046b9b7b5148107aae428\nmsgid \"\"\n\"There is also the `pdf2docx extract tables method`_ which is capable of \"\n\"table extraction if you prefer.\"\nmsgstr \"선호하는 경우 테이블 추출이 가능한 `pdf2docx extract tables method`_ 도 있습니다.\"\n\n#: ../../page.rst:554 ad10a4360b9a470085a13a03f9583cca\nmsgid \"\"\n\"PDF only: Add a \\\"rubber stamp\\\" annotation to e.g. indicate the \"\n\"document's intended use (\\\"DRAFT\\\", \\\"CONFIDENTIAL\\\", etc.). The \"\n\"parameter may be either an integer to select text from a predefined array\"\n\" of standard texts or an image.\"\nmsgstr \"\"\n\"PDF 전용: 예를 들어 문서의 의도된 용도(\\\"DRAFT\\\", \\\"CONFIDENTIAL\\\" 등)를 나타내기 위해 \\\"고무 \"\n\"도장\\\" 주석을 추가합니다. 매개변수는 표준 텍스트의 미리 정의된 배열에서 텍스트를 선택하는 정수이거나 이미지일 수 있습니다.\"\n\n#: ../../page.rst:556 b726e69c76e54f959d27f308c2c03a6c\nmsgid \"rectangle where to place the annotation.\"\nmsgstr \"주석을 배치할 사각형.\"\n\n#: ../../page.rst:557 dcc92434348946fdab577b695b1c09b6\nmsgid \"\"\n\"The following options are available:  * The id number (int) of the stamp \"\n\"text. For available stamps see :ref:`StampIcons`.  * A string specifying \"\n\"an image file path.  * A ``bytes``, ``bytearray`` or ``io.BytesIO`` \"\n\"object for an image in memory.  * A :ref:`Pixmap`.\"\nmsgstr \"\"\n\n#: ../../page.rst:557 6b4516a638e9428994ebcb405d2a1f09\nmsgid \"The following options are available:\"\nmsgstr \"다음 옵션을 사용할 수 있습니다:\"\n\n#: ../../page.rst:559 05b78849e840483f9d546b8b9cb89785\nmsgid \"\"\n\"The id number (int) of the stamp text. For available stamps see \"\n\":ref:`StampIcons`.\"\nmsgstr \"스탬프 텍스트의 id 번호(int). 사용 가능한 스탬프는 :ref:`StampIcons` 를 참조하세요.\"\n\n#: ../../page.rst:561 9609e86db8ed47fc9c25d4201e538b48\nmsgid \"A string specifying an image file path.\"\nmsgstr \"이미지 파일 경로를 지정하는 문자열.\"\n\n#: ../../page.rst:563 c78dc1111e5d4895aa33e226881ccee6\nmsgid \"\"\n\"A ``bytes``, ``bytearray`` or ``io.BytesIO`` object for an image in \"\n\"memory.\"\nmsgstr \"메모리의 이미지에 대한 ``bytes``, ``bytearray`` 또는 ``io.BytesIO`` 객체.\"\n\n#: ../../page.rst:565 f2fd36bb8d92458188dd831f23ddbbd2\nmsgid \"A :ref:`Pixmap`.\"\nmsgstr \":ref:`Pixmap`.\"\n\n#: ../../page.rst:567 7b8c2a5f5ff6477aa270d0725931d67a\nmsgid \"**Text-based stamps**\"\nmsgstr \"**텍스트 기반 스탬프**\"\n\n#: ../../page.rst:569 7cdfb1bc6f584798b71c7c259befac33\nmsgid \"\"\n\":attr:`Annot.rect` is automatically calculated as the largest rectangle \"\n\"with an aspect ratio of ``width:height = 3.8`` that fits in the provided \"\n\"``rect``. Its position is vertically and horizontally centered.\"\nmsgstr \"\"\n\":attr:`Annot.rect` 는 제공된 ``rect`` 에 맞는 ``width:height = 3.8`` 의 종횡비를 가진 \"\n\"가장 큰 사각형으로 자동 계산됩니다. 위치는 수직 및 수평으로 중앙 정렬됩니다.\"\n\n#: ../../page.rst:570 5187bddcaa8640d8a9ccd88e26edd292\nmsgid \"The font chosen is \\\"Times Bold\\\" and the text will be upper case.\"\nmsgstr \"선택된 폰트는 \\\"Times Bold\\\"이며 텍스트는 대문자가 됩니다.\"\n\n#: ../../page.rst:571 c2a2656315f64270963a4678ec8683a4\nmsgid \"\"\n\"The appearance can be modified using :meth:`Annot.set_opacity` and by \"\n\"setting the \\\"stroke\\\" color. By PDF specification, stamp annotations \"\n\"have no \\\"fill\\\" color.\"\nmsgstr \"\"\n\"외형은 :meth:`Annot.set_opacity` 를 사용하고 \\\"stroke\\\" 색상을 설정하여 수정할 수 있습니다. PDF \"\n\"사양에 따라 스탬프 주석은 \\\"fill\\\" 색상이 없습니다.\"\n\n#: ../../page.rst:575 3dcfbb130adb4f39b2420f2be36cd141\nmsgid \"**Image-based stamps**\"\nmsgstr \"**이미지 기반 스탬프**\"\n\n#: ../../page.rst:577 9593065ae7dc41d5b57c103e9bdc3798\nmsgid \"\"\n\"The image is scaled to fit into the rectangle `rect` such that the \"\n\"image's center and the center of `rect` coincide. The aspect ratio of the\"\n\" image is preserved, so the image may not fill the entire rectangle. \"\n\"However, at least one of the given rectangle's width or height are fully \"\n\"covered.\"\nmsgstr \"\"\n\"이미지는 이미지의 중심과 `rect` 의 중심이 일치하도록 `rect` 에 맞게 크기가 조정됩니다. 이미지의 종횡비가 유지되므로 \"\n\"이미지가 전체 사각형을 채우지 않을 수 있습니다. 그러나 주어진 사각형의 너비 또는 높이 중 하나 이상이 완전히 덮입니다.\"\n\n#: ../../page.rst:578 9099123803334c078412737bf2e61161\nmsgid \"\"\n\"The annotation can be modified via :meth:`Annot.set_opacity`. This method\"\n\" therefore is a way to display images transparently even if no alpha \"\n\"channel is present.\"\nmsgstr \"\"\n\"주석은 :meth:`Annot.set_opacity` 를 통해 수정할 수 있습니다. 따라서 이 메서드는 알파 채널이 없는 경우에도 \"\n\"이미지를 투명하게 표시하는 방법입니다.\"\n\n#: ../../page.rst:579 d1f0df185de3499aac1f209854f3f544\nmsgid \"Setting colors has no effect on image stamps.\"\nmsgstr \"색상 설정은 이미지 스탬프에 영향을 주지 않습니다.\"\n\n#: ../../page.rst:580 957b68c8ae304682b86ad1cf33484142\nmsgid \"\"\n\"Rotating image-based stamps **is not supported**. Setting the rotation \"\n\"may lead to unexpected results.\"\nmsgstr \"이미지 기반 스탬프 회전은 **지원되지 않습니다**. 회전을 설정하면 예상치 못한 결과가 발생할 수 있습니다.\"\n\n#: ../../page.rst:584 08dc10754b5d431da2675e335e0ce9d4\nmsgid \"\"\n\"PDF only: Add a PDF Form field (\\\"widget\\\") to a page. This also **turns \"\n\"the PDF into a Form PDF**. Because of the large amount of different \"\n\"options available for widgets, we have developed a new class \"\n\":ref:`Widget`, which contains the possible PDF field attributes. It must \"\n\"be used for both, form field creation and updates.\"\nmsgstr \"\"\n\"PDF 전용: 페이지에 PDF 양식 필드(\\\"위젯\\\")를 추가합니다. 이것은 또한 **PDF를 양식 PDF로 전환** 합니다. \"\n\"위젯에 사용할 수 있는 다양한 옵션이 많기 때문에, 가능한 PDF 필드 속성을 포함하는 새 클래스 :ref:`Widget` 을 \"\n\"개발했습니다. 양식 필드 생성과 업데이트 모두에 사용해야 합니다.\"\n\n#: ../../page.rst:586 3bc45874507542b99cf2f9fca40aca42\nmsgid \"a :ref:`Widget` object which must have been created upfront.\"\nmsgstr \"사전에 생성해야 하는 :ref:`Widget` 객체.\"\n\n#: ../../page.rst:589 04fd9437e4e14b78b68a9692f4cec067\nmsgid \"a widget annotation.\"\nmsgstr \"위젯 주석.\"\n\n#: ../../page.rst:593 02ff91d382bc4d89a175faad1e927702\nmsgid \"\"\n\"The removal will now include any bound 'Popup' or response annotations \"\n\"and related objects (changed in v1.16.6).\"\nmsgstr \"제거는 이제 연결된 'Popup' 또는 응답 주석과 관련 객체를 포함합니다 (v1.16.6에서 변경됨).\"\n\n#: ../../page.rst:595 5dcf92ac0b684108bb6755751932a302\nmsgid \"PDF only: Delete annotation from the page and return the next one.\"\nmsgstr \"PDF 전용: 페이지에서 주석을 삭제하고 다음 주석을 반환합니다.\"\n\n#: ../../page.rst:597 63cff108bf9545cd8dd48fa9d507fa9f\nmsgid \"the annotation to be deleted.\"\nmsgstr \"삭제할 주석.\"\n\n#: ../../page.rst:601 2d773e7ef8e34abe9cda167207dd2ec2\nmsgid \"\"\n\"the annotation following the deleted one. Please remember that physical \"\n\"removal requires saving to a new file with garbage > 0.\"\nmsgstr \"삭제된 주석 다음의 주석. 물리적 제거는 garbage > 0으로 새 파일에 저장해야 합니다.\"\n\n#: ../../page.rst:605 0d4d0fda3b604a55a4995a5a22bb22b7\nmsgid \"PDF only: Delete field from the page and return the next one.\"\nmsgstr \"PDF 전용: 페이지에서 필드를 삭제하고 다음 필드를 반환합니다.\"\n\n#: ../../page.rst:607 dd15f294da3545fdbb50d95fb99a289b\nmsgid \"the widget to be deleted.\"\nmsgstr \"삭제할 위젯.\"\n\n#: ../../page.rst:610 ../../page.rst:1940 ../../page.rst:2264\n#: 2a1b52b969354be08e1eb2839baeee5e 72454d0b5bf7432f874c41a2addc6110\n#: c0e0b7c7fa7f4451998ab0755364fc6c\nmsgid \":ref:`Widget`\"\nmsgstr \":ref:`Widget`\"\n\n#: ../../page.rst:611 5946066daec546438c26065bdf00da57\nmsgid \"\"\n\"the widget following the deleted one. Please remember that physical \"\n\"removal requires saving to a new file with garbage > 0.\"\nmsgstr \"삭제된 위젯 다음의 위젯. 물리적 제거는 garbage > 0으로 새 파일에 저장해야 합니다.\"\n\n#: ../../page.rst:615 94cc00cf1ef84081b9c1cf0a75e3acf4\nmsgid \"(New in v1.18.4)\"\nmsgstr \"(v1.18.4에서 새로 추가됨)\"\n\n#: ../../page.rst:622 e5d426c154e94c7b984b51f59f16c523\nmsgid \"\"\n\"PDF only: Delete the specified link from the page. The parameter must be \"\n\"an **original item** of :meth:`get_links()`, see \"\n\":ref:`link_dict_description`. The reason for this is the dictionary's \"\n\"*\\\"xref\\\"* key, which identifies the PDF object to be deleted.\"\nmsgstr \"\"\n\"PDF 전용: 페이지에서 지정된 링크를 삭제합니다. 매개변수는 :meth:`get_links()` 의 **원본 항목** 이어야 \"\n\"하며, :ref:`link_dict_description` 을 참조하세요. 이것은 삭제할 PDF 객체를 식별하는 딕셔너리의 \"\n\"*\\\"xref\\\"* 키 때문입니다.\"\n\n#: ../../page.rst:624 a031646e991e4e9895b82ae759c2db66\nmsgid \"the link to be deleted.\"\nmsgstr \"삭제할 링크.\"\n\n#: ../../page.rst:628 76e45868389e4b75832b5fb125c80a93\nmsgid \"\"\n\"PDF only: Insert a new link on this page. The parameter must be a \"\n\"dictionary of format as provided by :meth:`get_links()`, see \"\n\":ref:`link_dict_description`.\"\nmsgstr \"\"\n\"PDF 전용: 이 페이지에 새 링크를 삽입합니다. 매개변수는 :meth:`get_links()` 에서 제공하는 형식의 딕셔너리여야 \"\n\"하며, :ref:`link_dict_description` 을 참조하세요.\"\n\n#: ../../page.rst:630 64e75920afcb48d6a2fc9267af8f0384\nmsgid \"the link to be inserted.\"\nmsgstr \"삽입할 링크.\"\n\n#: ../../page.rst:634 f13dc7c20063441aba1b7b636417de7b\nmsgid \"\"\n\"PDF only: Modify the specified link. The parameter must be a (modified) \"\n\"**original item** of :meth:`get_links()`, see \"\n\":ref:`link_dict_description`. The reason for this is the dictionary's \"\n\"*\\\"xref\\\"* key, which identifies the PDF object to be changed.\"\nmsgstr \"\"\n\"PDF 전용: 지정된 링크를 수정합니다. 매개변수는 :meth:`get_links()` 의 (수정된) **원본 항목** 이어야 \"\n\"하며, :ref:`link_dict_description` 을 참조하세요. 이것은 변경할 PDF 객체를 식별하는 딕셔너리의 \"\n\"*\\\"xref\\\"* 키 때문입니다.\"\n\n#: ../../page.rst:636 a8c4c853e3ba4c6c9d0241071822f03d\nmsgid \"the link to be modified.\"\nmsgstr \"수정할 링크.\"\n\n#: ../../page.rst:638 484ca5ca85d2400f93f6ac66b30c5ffb\nmsgid \"\"\n\"If updating / inserting a URI link (`\\\"kind\\\": LINK_URI`), please make \"\n\"sure to start the value for the `\\\"uri\\\"` key with a disambiguating \"\n\"string like `\\\"http://\\\"`, `\\\"https://\\\"`, `\\\"file://\\\"`, `\\\"ftp://\\\"`, \"\n\"`\\\"mailto:\\\"`, etc. Otherwise -- depending on your browser or other \"\n\"\\\"consumer\\\" software -- unexpected default assumptions may lead to \"\n\"unwanted behaviours.\"\nmsgstr \"\"\n\"URI 링크(`\\\"kind\\\": LINK_URI`)를 업데이트/삽입하는 경우, `\\\"uri\\\"` 키의 값이 \"\n\"`\\\"http://\\\"`, `\\\"https://\\\"`, `\\\"file://\\\"`, `\\\"ftp://\\\"`, `\\\"mailto:\\\"`\"\n\" 등과 같은 명확한 문자열로 시작하도록 하세요. 그렇지 않으면 -- 브라우저나 다른 \\\"소비자\\\" 소프트웨어에 따라 -- 예상치 \"\n\"못한 기본 가정이 원하지 않는 동작을 유발할 수 있습니다.\"\n\n#: ../../page.rst:643 07c4f8dcaffa479cac56b83714185b8f\nmsgid \"PDF only: Return the label for the page.\"\nmsgstr \"PDF 전용: 페이지의 레이블을 반환합니다.\"\n\n#: ../../page.rst:647 ff3152eb66c14216b0b8db26b098505b\nmsgid \"the label string like \\\"vii\\\" for Roman numbering or \\\"\\\" if not defined.\"\nmsgstr \"로마 숫자의 경우 \\\"vii\\\"와 같은 레이블 문자열 또는 정의되지 않은 경우 \\\"\\\".\"\n\n#: ../../page.rst:651 58e643e9e53146d188f0a553b3fda009\nmsgid \"New in v1.18.6\"\nmsgstr \"v1.18.6에서 새로 추가됨\"\n\n#: ../../page.rst:657 bd5b5f45f592480fa60fad9a3255e097\nmsgid \"Retrieves **all** links of a page.\"\nmsgstr \"페이지의 **모든** 링크를 검색합니다.\"\n\n#: ../../page.rst:660 4c03f4b317a74a40a0786a0a0be21164\nmsgid \"\"\n\"A list of dictionaries. For a description of the dictionary entries, see \"\n\":ref:`link_dict_description`. Always use this or the :meth:`Page.links` \"\n\"method if you intend to make changes to the links of a page.\"\nmsgstr \"\"\n\"딕셔너리의 리스트. 딕셔너리 항목에 대한 설명은 :ref:`link_dict_description` 을 참조하세요. 페이지의 링크를\"\n\" 변경하려면 항상 이것 또는 :meth:`Page.links` 메서드를 사용하세요.\"\n\n#: ../../page.rst:664 76949f0001bf42978c2bf318306a909c\nmsgid \"\"\n\"Return a generator over the page's links. The results equal the entries \"\n\"of :meth:`Page.get_links`.\"\nmsgstr \"페이지의 링크에 대한 제너레이터를 반환합니다. 결과는 :meth:`Page.get_links` 의 항목과 같습니다.\"\n\n#: ../../page.rst:666 256c37bf03b649ce921d41b4bd526630\nmsgid \"\"\n\"a sequence of integers to down-select to one or more link kinds. Default \"\n\"is all links. Example: *kinds=(pymupdf.LINK_GOTO,)* will only return \"\n\"internal links.\"\nmsgstr \"\"\n\"하나 이상의 링크 종류로 다운 선택하기 위한 정수 시퀀스. 기본값은 모든 링크입니다. 예: \"\n\"*kinds=(pymupdf.LINK_GOTO,)* 는 내부 링크만 반환합니다.\"\n\n#: ../../page.rst:669 57bac8c9fe03470b8c9fa8a0976374a5\nmsgid \"an entry of :meth:`Page.get_links()` for each iteration.\"\nmsgstr \"각 반복에 대한 :meth:`Page.get_links()` 의 항목.\"\n\n#: ../../page.rst:673 ../../page.rst:698 ../../page.rst:713\n#: 1cfc8ec3d3494a189a5b6fc45f3acc15 b58ceeb1df204612aff9645edd0933c0\n#: bec5ab9dd05545d9b73c9e62de8de068\nmsgid \"New in v1.16.4\"\nmsgstr \"v1.16.4에서 새로 추가됨\"\n\n#: ../../page.rst:679 190a2da56f4d4954a3b921a7a75b5780\nmsgid \"Return a generator over the page's annotations.\"\nmsgstr \"페이지의 주석에 대한 제너레이터를 반환합니다.\"\n\n#: ../../page.rst:681 7e7f0c894f9f43bb88de193161271398\nmsgid \"\"\n\"a sequence of integers to down-select to one or more annotation types. \"\n\"Default is all annotations. Example: `types=(pymupdf.PDF_ANNOT_FREETEXT, \"\n\"pymupdf.PDF_ANNOT_TEXT)` will only return 'FreeText' and 'Text' \"\n\"annotations.\"\nmsgstr \"\"\n\"하나 이상의 주석 유형으로 다운 선택하기 위한 정수 시퀀스. 기본값은 모든 주석입니다. 예: \"\n\"`types=(pymupdf.PDF_ANNOT_FREETEXT, pymupdf.PDF_ANNOT_TEXT)` 는 'FreeText'\"\n\" 및 'Text' 주석만 반환합니다.\"\n\n#: ../../page.rst:684 13e0a4b5e4e14b5e83ce82fc32ea2aba\nmsgid \"\"\n\"an :ref:`Annot` for each iteration.  .. caution::      You **cannot \"\n\"safely update annotations** from within this generator. This is because \"\n\"most annotation updates require reloading the page via `page = \"\n\"doc.reload_page(page)`. To circumvent this restriction, make a list of \"\n\"annotations xref numbers first and then iterate over these numbers::\"\n\"        In [4]: xrefs = [annot.xref for annot in \"\n\"page.annots(types=[...])]       In [5]: for xref in xrefs:          ...:\"\n\"     annot = page.load_annot(xref)          ...:     annot.update()\"\n\"          ...:     page = doc.reload_page(page)       In [6]:\"\nmsgstr \"\"\n\n#: ../../page.rst:684 2ba4670732014e5a829d65d22f631961\nmsgid \"an :ref:`Annot` for each iteration.\"\nmsgstr \"각 반복에 대한 :ref:`Annot`.\"\n\n#: ../../page.rst:687 3fd0c0fee5ef435798110aa4fa398d04\nmsgid \"\"\n\"You **cannot safely update annotations** from within this generator. This\"\n\" is because most annotation updates require reloading the page via `page \"\n\"= doc.reload_page(page)`. To circumvent this restriction, make a list of \"\n\"annotations xref numbers first and then iterate over these numbers::\"\nmsgstr \"\"\n\"이 제너레이터 내에서 주석을 **안전하게 업데이트할 수 없습니다**. 대부분의 주석 업데이트는 `page = \"\n\"doc.reload_page(page)` 를 통해 페이지를 다시 로드해야 하기 때문입니다. 이 제한을 우회하려면 먼저 주석 xref\"\n\" 번호의 리스트를 만든 다음 이 번호들을 반복하세요::\"\n\n#: ../../page.rst:704 66911a756ed04e0d972a5a041606e4e3\nmsgid \"Return a generator over the page's form fields.\"\nmsgstr \"페이지의 양식 필드에 대한 제너레이터를 반환합니다.\"\n\n#: ../../page.rst:706 a882b8ac49a9428eab1e9b6e59f524f2\nmsgid \"\"\n\"a sequence of integers to down-select to one or more widget types. \"\n\"Default is all form fields. Example: \"\n\"`types=(pymupdf.PDF_WIDGET_TYPE_TEXT,)` will only return 'Text' fields.\"\nmsgstr \"\"\n\"하나 이상의 위젯 유형으로 다운 선택하기 위한 정수 시퀀스. 기본값은 모든 양식 필드입니다. 예: \"\n\"`types=(pymupdf.PDF_WIDGET_TYPE_TEXT,)` 는 'Text' 필드만 반환합니다.\"\n\n#: ../../page.rst:709 2ccfcd02080e4811b0752b3ee47baa25\nmsgid \"a :ref:`Widget` for each iteration.\"\nmsgstr \"각 반복에 대한 :ref:`Widget`.\"\n\n#: ../../page.rst:720 871dc7a054b94194a4b4f053de5f9eaf\nmsgid \"\"\n\"PDF only: Write the text of one or more :ref:`Textwriter` objects to the \"\n\"page.\"\nmsgstr \"PDF 전용: 하나 이상의 :ref:`Textwriter` 객체의 텍스트를 페이지에 작성합니다.\"\n\n#: ../../page.rst:722 f649e20d39734681ad8c9588059f42ec\nmsgid \"\"\n\"where to place the text. If omitted, the rectangle union of the text \"\n\"writers is used.\"\nmsgstr \"텍스트를 배치할 위치. 생략하면 텍스트 작성기의 사각형 합집합이 사용됩니다.\"\n\n#: ../../page.rst:723 a62f67512f7641b1b02ab65e2ef0843b\nmsgid \"\"\n\"a non-empty tuple / list of :ref:`TextWriter` objects or a single \"\n\":ref:`TextWriter`.\"\nmsgstr \":ref:`TextWriter` 객체의 비어 있지 않은 튜플/리스트 또는 단일 :ref:`TextWriter`.\"\n\n#: ../../page.rst:724 31da0f58f5974053919718f6e13dea23\nmsgid \"set transparency, overwrites resp. value in the text writers.\"\nmsgstr \"투명도를 설정하고, 텍스트 작성기의 해당 값을 덮어씁니다.\"\n\n#: ../../page.rst:725 972504b7f4eb441ba75e2424782dd55f\nmsgid \"set the text color, overwrites  resp. value in the text writers.\"\nmsgstr \"텍스트 색상을 설정하고, 텍스트 작성기의 해당 값을 덮어씁니다.\"\n\n#: ../../page.rst:726 136dae4fb943495eb982c68a28795ab5\nmsgid \"put the text in foreground or background.\"\nmsgstr \"텍스트를 전경 또는 배경에 배치합니다.\"\n\n#: ../../page.rst:727 acb27d4360a244659bf4cc73141dd567\nmsgid \"maintain the aspect ratio.\"\nmsgstr \"종횡비를 유지합니다.\"\n\n#: ../../page.rst:728 d181ff20c7ea4299bcd22d78f20d6ec9\nmsgid \"rotate the text by an arbitrary angle.\"\nmsgstr \"임의의 각도로 텍스트를 회전합니다.\"\n\n#: ../../page.rst:729 5b44553f2f954d5ab51a6e3cbb9c7c13\nmsgid \"the :data:`xref` of an :data:`OCG` or :data:`OCMD`. (New in v1.18.4)\"\nmsgstr \":data:`OCG` 또는 :data:`OCMD` 의 :data:`xref`. (v1.18.4에서 새로 추가됨)\"\n\n#: ../../page.rst:731 b0f06277a3f140c2ac2f20314e571e28\nmsgid \"\"\n\"Parameters *overlay, keep_proportion, rotate* and *oc* have the same \"\n\"meaning as in :meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\"매개변수 *overlay, keep_proportion, rotate* 및 *oc* 는 \"\n\":meth:`Page.show_pdf_page` 와 동일한 의미를 가집니다.\"\n\n#: ../../page.rst:735 e07a5fc6945442ee887b7c73cf6c2d2e\nmsgid \"New in v1.16.18\"\nmsgstr \"v1.16.18에서 새로 추가됨\"\n\n#: ../../page.rst:759 8e95c840195a4c71a918d0a5e67856ae\nmsgid \"\"\n\"PDF only: Insert text lines starting at :data:`point_like` ``point``. See\"\n\" :meth:`Shape.insert_text`.\"\nmsgstr \"\"\n\"PDF 전용: :data:`point_like` ``point`` 에서 시작하는 텍스트 줄을 삽입합니다. \"\n\":meth:`Shape.insert_text` 를 참조하세요.\"\n\n#: ../../page.rst:763 ../../page.rst:792 ../../page.rst:896 ../../page.rst:921\n#: ../../page.rst:946 ../../page.rst:970 ../../page.rst:994 ../../page.rst:1019\n#: ../../page.rst:1043 ../../page.rst:1068 ../../page.rst:1092\n#: ../../page.rst:1117 ../../page.rst:1142 29cbed1adef2475eb009d3a5de422210\n#: 49f852363925416ea6c234b4c91b6218 5c73ffbadda54fb8bbc88f6430e29130\n#: 73f04a44af8c4854a3a105b737a41804 802c5bc146bb4f9391824c1c3ef39bb6\n#: 8e030f84abaf493db27e55aa2ac8cd62 97c6b58861a445f8b9d5a0e5c3a310ab\n#: a74ef5cf7bf74435a6e61758194b384f dabc787b2b6541969db56d13faf4c89d\n#: df67a6e9ce4048eab88324f5d7e19efe ed3b45533868494381f71199d8329d07\n#: f01049b4b200405aa3c91ce9a1a85bd2 f3b6a366e6db4a2383d8d554eadb7e9b\nmsgid \"Changed in v1.18.4\"\nmsgstr \"v1.18.4에서 변경됨\"\n\n#: ../../page.rst:788 4a878df36e7743f9b6a9d9d9dc06a551\nmsgid \"\"\n\"PDF only: Insert text into the specified :data:`rect_like` *rect*. See \"\n\":meth:`Shape.insert_textbox`.\"\nmsgstr \"\"\n\"PDF 전용: 지정된 :data:`rect_like` *rect* 에 텍스트를 삽입합니다. \"\n\":meth:`Shape.insert_textbox` 를 참조하세요.\"\n\n#: ../../page.rst:810 7a8b95a9ab4d4c769d7c458bea499710\nmsgid \"\"\n\"**PDF only:** Insert text into the specified rectangle. The method has \"\n\"similarities with methods :meth:`Page.insert_textbox` and \"\n\":meth:`TextWriter.fill_textbox`, but is **much more powerful**. This is \"\n\"achieved by letting a :ref:`Story` object do all the required processing.\"\nmsgstr \"\"\n\"**PDF 전용:** 지정된 사각형에 텍스트를 삽입합니다. 이 메서드는 :meth:`Page.insert_textbox` 및 \"\n\":meth:`TextWriter.fill_textbox` 메서드와 유사하지만 **훨씬 더 강력합니다**. 이것은 \"\n\":ref:`Story` 객체가 필요한 모든 처리를 수행하도록 하여 달성됩니다.\"\n\n#: ../../page.rst:812 a0f3fd19bdce48538475a297ca1e344e\nmsgid \"\"\n\"Parameter ``text`` may be a string as in the other methods. But it will \"\n\"be **interpreted as HTML source** and may therefore also contain HTML \"\n\"language elements -- including styling. The `css` parameter may be used \"\n\"to pass in additional styling instructions.\"\nmsgstr \"\"\n\"매개변수 ``text`` 는 다른 메서드와 마찬가지로 문자열일 수 있습니다. 하지만 이것은 **HTML 소스로 해석** 되므로 \"\n\"스타일링을 포함하여 HTML 언어 요소를 포함할 수도 있습니다. `css` 매개변수는 추가 스타일링 지시사항을 전달하는 데 사용할 \"\n\"수 있습니다.\"\n\n#: ../../page.rst:814 ec504617da2d494da64dcf69cd3d1cb8\nmsgid \"\"\n\"Automatic line breaks are generated at word boundaries. The \\\"soft \"\n\"hyphen\\\" character `\\\"&#173;\\\"` (or `&shy;`) can be used to cause \"\n\"hyphenation and thus may also cause line breaks. **Forced** line breaks \"\n\"however are only achievable via the HTML tag ``<br>`` - ``\\\\n`` is \"\n\"ignored and will be treated like a space.\"\nmsgstr \"\"\n\"자동 줄 바꿈은 단어 경계에서 생성됩니다. \\\"소프트 하이픈\\\" 문자 `\\\"&#173;\\\"` (또는 `&shy;`)는 하이픈을 \"\n\"유발하고 줄 바꿈을 유발할 수도 있습니다. 그러나 **강제** 줄 바꿈은 HTML 태그 ``<br>`` 를 통해서만 달성할 수 \"\n\"있습니다 - ``\\\\n`` 은 무시되고 공백처럼 처리됩니다.\"\n\n#: ../../page.rst:816 a923c7fb3c8d42e5b998b610488d15e0\nmsgid \"With this method the following can be achieved:\"\nmsgstr \"이 메서드로 다음을 달성할 수 있습니다:\"\n\n#: ../../page.rst:818 a35f84bf7d2e49a98470b411d03e5d63\nmsgid \"\"\n\"Styling effects like bold, italic, text color, text alignment, font size \"\n\"or font switching.\"\nmsgstr \"굵게, 기울임꼴, 텍스트 색상, 텍스트 정렬, 글꼴 크기 또는 글꼴 전환과 같은 스타일링 효과.\"\n\n#: ../../page.rst:819 d424a5099ce8491aa77a38a61ce5145b\nmsgid \"\"\n\"The text may include arbitrary languages -- **including right-to-left** \"\n\"languages.\"\nmsgstr \"텍스트는 임의의 언어를 포함할 수 있습니다 -- **오른쪽에서 왼쪽** 언어를 포함하여.\"\n\n#: ../../page.rst:820 cbe7429b65de417da4c1b1007c31de84\nmsgid \"\"\n\"Scripts like `Devanagari <https://en.wikipedia.org/wiki/Devanagari>`_ and\"\n\" several others in Asia have a highly complex system of ligatures, where \"\n\"two or more unicodes together yield one glyph. The Story uses the \"\n\"software package `HarfBuzz <https://harfbuzz.github.io/>`_ , to deal with\"\n\" these things and produce correct output.\"\nmsgstr \"\"\n\"`Devanagari <https://en.wikipedia.org/wiki/Devanagari>`_ 및 아시아의 여러 다른 스크립트는 두 개 이상의 유니코드가 함께 하나의 글리프를 생성하는 매우 복잡한 합자 시스템을 가지고 있습니다. Story는 이러한 것들을 처리하고 올바른 출력을 생성하기 위해 소프트웨어 패키지 `HarfBuzz <https://harfbuzz.github.io/>`_ 를 사용합니다.\"\n\n#: ../../page.rst:821 07bf7ced92754725909626e75183a002\nmsgid \"\"\n\"One can also **include images** via HTML tag `<img>` -- the Story will \"\n\"take care of the appropriate layout. This is an alternative option to \"\n\"insert images, compared to :meth:`Page.insert_image`.\"\nmsgstr \"\"\n\"HTML 태그 `<img>` 를 통해 이미지를 **포함** 할 수도 있습니다 -- Story는 적절한 레이아웃을 처리합니다. 이것은\"\n\" :meth:`Page.insert_image` 와 비교하여 이미지를 삽입하는 대안입니다.\"\n\n#: ../../page.rst:822 983d14f0830f41c49ef37af23002df74\nmsgid \"\"\n\"HTML tables (tag `<table>`) may be included in the text and will be \"\n\"handled appropriately.\"\nmsgstr \"HTML 테이블(태그 `<table>`)은 텍스트에 포함될 수 있으며 적절히 처리됩니다.\"\n\n#: ../../page.rst:823 3d7e1d6ede5b46fcbec414adef81ef5b\nmsgid \"Links are automatically generated when present.\"\nmsgstr \"링크가 있으면 자동으로 생성됩니다.\"\n\n#: ../../page.rst:825 c1697502ce9447428c60c2b19a1b4d03\nmsgid \"If content does not fit in the rectangle, the developer has two choices:\"\nmsgstr \"콘텐츠가 사각형에 맞지 않으면 개발자는 두 가지 선택이 있습니다:\"\n\n#: ../../page.rst:827 d5b3273332d0480eb2bfffbc196953f9\nmsgid \"\"\n\"**either** only be informed about this (and accept a no-op, just like \"\n\"with the other textbox insertion methods),\"\nmsgstr \"**또는** 이것에 대해 알림만 받습니다(다른 텍스트 상자 삽입 메서드와 마찬가지로 no-op를 수락),\"\n\n#: ../../page.rst:828 0645d285fa9a4151bdd6d8e92881f0c7\nmsgid \"**or** (`scale_low=0` - the default) scale down the content until it fits.\"\nmsgstr \"**또는** (`scale_low=0` - 기본값) 콘텐츠가 맞을 때까지 축소합니다.\"\n\n#: ../../page.rst:830 ee3b2989599349e79cb1c01ea70ea9cd\nmsgid \"rectangle on page to receive the text.\"\nmsgstr \"텍스트를 받을 페이지의 사각형.\"\n\n#: ../../page.rst:831 b1183b7cce24456fa0d8843b773494bf\nmsgid \"\"\n\"the text to be written. Can contain a mixture of plain text and HTML tags\"\n\" with styling instructions. Alternatively, a :ref:`Story` object may be \"\n\"specified (in which case the internal Story generation step will be \"\n\"omitted). A Story must have been generated with all required styling and \"\n\"Archive information.\"\nmsgstr \"\"\n\"작성할 텍스트. 일반 텍스트와 스타일링 지시사항이 있는 HTML 태그의 혼합을 포함할 수 있습니다. 또는 :ref:`Story` \"\n\"객체를 지정할 수 있습니다(이 경우 내부 Story 생성 단계가 생략됨). Story는 필요한 모든 스타일링과 Archive 정보로\"\n\" 생성되어야 합니다.\"\n\n#: ../../page.rst:832 7b2dc0703c9c4338984056f677d0b80b\nmsgid \"\"\n\"optional string containing additional CSS instructions. This parameter is\"\n\" ignored if ``text`` is a Story.\"\nmsgstr \"추가 CSS 지시사항을 포함하는 선택적 문자열. ``text`` 가 Story이면 이 매개변수는 무시됩니다.\"\n\n#: ../../page.rst:833 bc668be54dab49a29a80fbd31c6d3296\nmsgid \"\"\n\"if necessary, scale down the content until it fits in the target \"\n\"rectangle. This sets the down scaling limit. Default is 0, no limit. A \"\n\"value of 1 means no down-scaling permitted. A value of e.g. 0.2 means \"\n\"maximum down-scaling by 80%.\"\nmsgstr \"\"\n\"필요한 경우 콘텐츠가 대상 사각형에 맞을 때까지 축소합니다. 이것은 축소 제한을 설정합니다. 기본값은 0이며 제한이 없습니다. 값 \"\n\"1은 축소가 허용되지 않음을 의미합니다. 예를 들어 값 0.2는 최대 80% 축소를 의미합니다.\"\n\n#: ../../page.rst:834 31c0b5f5b6d04e68a6878b526636f7eb\nmsgid \"\"\n\"an Archive object that points to locations where to find images or non-\"\n\"standard fonts. If ``text`` refers to images or non-standard fonts, this \"\n\"parameter is required. This parameter is ignored if ``text`` is a Story.\"\nmsgstr \"\"\n\"이미지나 비표준 글꼴을 찾을 위치를 가리키는 Archive 객체. ``text`` 가 이미지나 비표준 글꼴을 참조하면 이 매개변수가\"\n\" 필요합니다. ``text`` 가 Story이면 이 매개변수는 무시됩니다.\"\n\n#: ../../page.rst:835 457ccb06bf974da594ce7e13e776e9b0\nmsgid \"\"\n\"one of the values 0, 90, 180, 270. Depending on this, text will be \"\n\"filled:  - 0: top-left to bottom-right. - 90: bottom-left to top-right. -\"\n\" 180: bottom-right to top-left. - 270: top-right to bottom-left.  .. \"\n\"image:: images/img-rotate.*\"\nmsgstr \"\"\n\n#: ../../page.rst:835 c81c01b196444618b9998f481f5a0e1a\nmsgid \"one of the values 0, 90, 180, 270. Depending on this, text will be filled:\"\nmsgstr \"값 0, 90, 180, 270 중 하나. 이것에 따라 텍스트가 채워집니다:\"\n\n#: ../../page.rst:837 f9ff0f28f0f6456da66b0f0df1302527\nmsgid \"0: top-left to bottom-right.\"\nmsgstr \"0: 왼쪽 위에서 오른쪽 아래로.\"\n\n#: ../../page.rst:838 e384b943e7f842698d77609fa3ff4b8c\nmsgid \"90: bottom-left to top-right.\"\nmsgstr \"90: 왼쪽 아래에서 오른쪽 위로.\"\n\n#: ../../page.rst:839 8cfc7f849a1e4f288352386f958938b2\nmsgid \"180: bottom-right to top-left.\"\nmsgstr \"180: 오른쪽 아래에서 왼쪽 위로.\"\n\n#: ../../page.rst:840 e9c12cd0f43d498da3d4541d7861e582\nmsgid \"270: top-right to bottom-left.\"\nmsgstr \"270: 오른쪽 위에서 왼쪽 아래로.\"\n\n#: ../../page.rst:844 93a83daaec8442ed8087eb65511b113f\nmsgid \"\"\n\"the xref of an :data:`OCG` / :data:`OCMD` or 0. Please refer to \"\n\":meth:`Page.show_pdf_page` for details.\"\nmsgstr \"\"\n\":data:`OCG` / :data:`OCMD` 의 xref 또는 0. 자세한 내용은 \"\n\":meth:`Page.show_pdf_page` 를 참조하세요.\"\n\n#: ../../page.rst:845 bfb65b9ea805491db0d5ed71a7027efa\nmsgid \"\"\n\"set the fill and stroke opacity of the content. Only values `0 <= opacity\"\n\" < 1` are considered.\"\nmsgstr \"콘텐츠의 채우기 및 획 불투명도를 설정합니다. `0 <= opacity < 1` 값만 고려됩니다.\"\n\n#: ../../page.rst:846 905bbba40c974a72a58695ec34c09162\nmsgid \"\"\n\"put the text in front of other content. Please refer to \"\n\":meth:`Page.show_pdf_page` for details.\"\nmsgstr \"텍스트를 다른 콘텐츠 앞에 배치합니다. 자세한 내용은 :meth:`Page.show_pdf_page` 를 참조하세요.\"\n\n#: ../../page.rst:848 92bf9eaf5c3f4c479b4f36be5a1acd93\nmsgid \"\"\n\"A tuple of floats `(spare_height, scale)`.  - spare_height: The \"\n\"(positive) height of the remaining space in `rect` below the   text, or \"\n\"-1 if we failed to fit. - scale: The scaling required; `0 < scale <= 1`. \"\n\"Will be `scale_low`   if we failed to fit.\"\nmsgstr \"\"\n\n#: ../../page.rst:848 2b0c0730afa5444fb7fda28fe1369de8\nmsgid \"A tuple of floats `(spare_height, scale)`.\"\nmsgstr \"부동소수점 튜플 `(spare_height, scale)`.\"\n\n#: ../../page.rst:850 ce7c975eea734b7da832d65e887cc704\nmsgid \"\"\n\"spare_height: The (positive) height of the remaining space in `rect` \"\n\"below the text, or -1 if we failed to fit.\"\nmsgstr \"spare_height: 텍스트 아래 `rect` 에 남은 공간의 (양수) 높이, 또는 맞추지 못하면 -1.\"\n\n#: ../../page.rst:852 816917683f904e518274eb1dd0202535\nmsgid \"\"\n\"scale: The scaling required; `0 < scale <= 1`. Will be `scale_low` if we \"\n\"failed to fit.\"\nmsgstr \"scale: 필요한 스케일링; `0 < scale <= 1`. 맞추지 못하면 `scale_low` 가 됩니다.\"\n\n#: ../../page.rst:855 2559dc387f5a4f2b9b6113b9fbb64cd8\nmsgid \"\"\n\"Please refer to examples in this section of the recipes: \"\n\":ref:`RecipesText_I_c`.\"\nmsgstr \"레시피의 이 섹션에 있는 예제를 참조하세요: :ref:`RecipesText_I_c`.\"\n\n#: ../../page.rst:859 ee15ed3a85e94fb59795c752df7727aa\nmsgid \"New in v1.26.5:\"\nmsgstr \"v1.26.5에서 새로 추가됨:\"\n\n#: ../../page.rst:861 9ebaf4785e394595b1138e09ac1db565\nmsgid \"do additional scaling to fit long words.\"\nmsgstr \"긴 단어에 맞추기 위해 추가 스케일링을 수행합니다.\"\n\n#: ../../page.rst:863 e401bc154829432487340567f7b04879\nmsgid \"\"\n\"If we succeeded and scaled down, the returned `spare_height` is now \"\n\"generally positive instead of being fixed to zero, because the final \"\n\"rect's height is usually not an exact multiple of the font line height.\"\nmsgstr \"\"\n\"성공하고 축소한 경우, 반환된 `spare_height` 는 이제 일반적으로 0으로 고정되는 대신 양수가 됩니다. 최종 rect의 \"\n\"높이가 일반적으로 글꼴 줄 높이의 정확한 배수가 아니기 때문입니다.\"\n\n#: ../../page.rst:867 f3a5f741edf846059890d9018c0211fd\nmsgid \"New in v1.23.8: rebased-only.\"\nmsgstr \"v1.23.8에서 새로 추가됨: rebased-only.\"\n\n#: ../../page.rst:868 91bcebc8a0df4e6fa3bc2c96e6c50749\nmsgid \"New in v1.23.9: `opacity` parameter.\"\nmsgstr \"v1.23.9에서 새로 추가됨: `opacity` 매개변수.\"\n\n#: ../../page.rst:873 5c2e2f42919443729264c6cf723a4a85\nmsgid \"**Drawing Methods**\"\nmsgstr \"**그리기 메서드**\"\n\n#: ../../page.rst:892 c2e73d53842e437399410160042819cd\nmsgid \"\"\n\"PDF only: Draw a line from *p1* to *p2* (:data:`point_like` \\\\s). See \"\n\":meth:`Shape.draw_line`.\"\nmsgstr \"\"\n\"PDF 전용: *p1* 에서 *p2* 로 선을 그립니다 (:data:`point_like` \\\\s). \"\n\":meth:`Shape.draw_line` 참조.\"\n\n#: ../../page.rst:917 590f66dd92694e3d99c4a4c0e6eda74e\nmsgid \"\"\n\"PDF only: Draw a zigzag line from *p1* to *p2* (:data:`point_like` \\\\s). \"\n\"See :meth:`Shape.draw_zigzag`.\"\nmsgstr \"\"\n\"PDF 전용: *p1* 에서 *p2* 로 지그재그 선을 그립니다 (:data:`point_like` \\\\s). \"\n\":meth:`Shape.draw_zigzag` 참조.\"\n\n#: ../../page.rst:942 b7e2518e8f634d33abba9359ea9d5881\nmsgid \"\"\n\"PDF only: Draw a squiggly (wavy, undulated) line from *p1* to *p2* \"\n\"(:data:`point_like` \\\\s). See :meth:`Shape.draw_squiggle`.\"\nmsgstr \"\"\n\"PDF 전용: *p1* 에서 *p2* 로 구불구불한(물결 모양, 파형) 선을 그립니다 (:data:`point_like` \\\\s).\"\n\" :meth:`Shape.draw_squiggle` 참조.\"\n\n#: ../../page.rst:966 a344352656f8495fa26bb886aa41df16\nmsgid \"\"\n\"PDF only: Draw a circle around *center* (:data:`point_like`) with a \"\n\"radius of *radius*. See :meth:`Shape.draw_circle`.\"\nmsgstr \"\"\n\"PDF 전용: 중심(:data:`point_like`)을 기준으로 반지름이  *radius* 인 원을 그립니다. \"\n\":meth:`Shape.draw_circle` 참조.\"\n\n#: ../../page.rst:990 dc78aaf8fe8c46e0987e1e919910b04f\nmsgid \"\"\n\"PDF only: Draw an oval (ellipse) within the given :data:`rect_like` or \"\n\":data:`quad_like`. See :meth:`Shape.draw_oval`.\"\nmsgstr \"\"\n\"PDF 전용: 주어진 :data:`rect_like` 또는 :data:`quad_like` 내에 타원(ellipse)을 그립니다. \"\n\":meth:`Shape.draw_oval` 참조.\"\n\n#: ../../page.rst:1015 efe94da64f144f219b19cf68eae0b77f\nmsgid \"\"\n\"PDF only: Draw a circular sector, optionally connecting the arc to the \"\n\"circle's center (like a piece of pie). See :meth:`Shape.draw_sector`.\"\nmsgstr \"\"\n\"PDF 전용: 원형 섹터를 그립니다. 선택적으로 호를 원의 중심에 연결합니다(파이 조각처럼). \"\n\":meth:`Shape.draw_sector` 참조.\"\n\n#: ../../page.rst:1039 33f62e1f2aff415cb1313cfe79341d7a\nmsgid \"\"\n\"PDF only: Draw several connected lines defined by a sequence of \"\n\":data:`point_like` \\\\s. See :meth:`Shape.draw_polyline`.\"\nmsgstr \"\"\n\"PDF 전용: :data:`point_like` \\\\s의 시퀀스로 정의된 여러 연결된 라인을 그립니다. \"\n\":meth:`Shape.draw_polyline` 참조.\"\n\n#: ../../page.rst:1064 eaf27ae8a0584f5ab83a1175a2565ae3\nmsgid \"\"\n\"PDF only: Draw a cubic Bézier curve from *p1* to *p4* with the control \"\n\"points *p2* and *p3* (all are :data:`point_like` \\\\s). See \"\n\":meth:`Shape.draw_bezier`.\"\nmsgstr \"\"\n\"PDF 전용: 제어점 *p2* 및 *p3* 를 사용하여 *p1* 에서 *p4* 까지의 3차 Bézier 곡선을 그립니다(모두 \"\n\":data:`point_like` \\\\s). :meth:`Shape.draw_bezier` 참조.\"\n\n#: ../../page.rst:1088 5d0be74ed9a240548236f517e0677308\nmsgid \"\"\n\"PDF only: This is a special case of *draw_bezier()*. See \"\n\":meth:`Shape.draw_curve`.\"\nmsgstr \"PDF 전용: 이것은 *draw_bezier()* 의 특수한 경우입니다. :meth:`Shape.draw_curve` 참조.\"\n\n#: ../../page.rst:1113 bf9775fdb63446508a077a79eb46fad1\nmsgid \"PDF only: Draw a rectangle. See :meth:`Shape.draw_rect`.\"\nmsgstr \"PDF 전용: 사각형을 그립니다. :meth:`Shape.draw_rect` 참조.\"\n\n#: ../../page.rst:1118 3847474347db459e9cd9b672283c581b\nmsgid \"Changed in v1.22.0: Added parameter *radius*.\"\nmsgstr \"v1.22.0에서 변경됨: *radius* 매개변수 추가.\"\n\n#: ../../page.rst:1138 fc73cdf7d47c41f1a7e00043867127f4\nmsgid \"PDF only: Draw a quadrilateral. See :meth:`Shape.draw_quad`.\"\nmsgstr \"PDF 전용: 사각형을 그립니다. :meth:`Shape.draw_quad` 참조.\"\n\n#: ../../page.rst:1156 ecb6c858dcbd4178a6aa41405c91adc3\nmsgid \"\"\n\"PDF only: Add a new font to be used by text output methods and return its\"\n\" :data:`xref`. If not already present in the file, the font definition \"\n\"will be added. Supported are the built-in :data:`Base14_Fonts` and the \"\n\"CJK fonts via **\\\"reserved\\\"** fontnames. Fonts can also be provided as a\"\n\" file path or a memory area containing the image of a font file.\"\nmsgstr \"\"\n\"PDF 전용: 텍스트 출력 메서드에서 사용할 새 글꼴을 추가하고 :data:`xref` 를 반환합니다. 파일에 아직 없으면 글꼴 \"\n\"정의가 추가됩니다. 내장 :data:`Base14_Fonts` 및 **\\\"reserved\\\"** 글꼴 이름을 통한 CJK 글꼴이 \"\n\"지원됩니다. 글꼴은 파일 경로 또는 글꼴 파일 이미지를 포함하는 메모리 영역으로 제공할 수도 있습니다.\"\n\n#: ../../page.rst:1158 784ca49abb314196808838c70b6ad0cb\nmsgid \"\"\n\"The name by which this font shall be referenced when outputting text on \"\n\"this page. In general, you have a \\\"free\\\" choice here (but consult the \"\n\":ref:`AdobeManual`, page 16, section 7.3.5 for a formal description of \"\n\"building legal PDF names). However, if it matches one of the \"\n\":data:`Base14_Fonts` or one of the CJK fonts, *fontfile* and *fontbuffer*\"\n\" **are ignored**.  In other words, you cannot insert a font via \"\n\"*fontfile* / *fontbuffer* and also give it a reserved *fontname*.  .. \"\n\"note:: A reserved fontname can be specified in any mixture of upper or \"\n\"lower case and still match the right built-in font definition: fontnames \"\n\"\\\"helv\\\", \\\"Helv\\\", \\\"HELV\\\", \\\"Helvetica\\\", etc. all lead to the same \"\n\"font definition \\\"Helvetica\\\". But from a :ref:`Page` perspective, these \"\n\"are **different references**. You can exploit this fact when using \"\n\"different *encoding* variants (Latin, Greek, Cyrillic) of the same font \"\n\"on a page.\"\nmsgstr \"\"\n\n#: ../../page.rst:1158 e853a8b934d14f3ea02398cad5e939ed\nmsgid \"\"\n\"The name by which this font shall be referenced when outputting text on \"\n\"this page. In general, you have a \\\"free\\\" choice here (but consult the \"\n\":ref:`AdobeManual`, page 16, section 7.3.5 for a formal description of \"\n\"building legal PDF names). However, if it matches one of the \"\n\":data:`Base14_Fonts` or one of the CJK fonts, *fontfile* and *fontbuffer*\"\n\" **are ignored**.\"\nmsgstr \"\"\n\"이 페이지에서 텍스트를 출력할 때 이 글꼴을 참조하는 데 사용할 이름. 일반적으로 여기서는 \\\"자유로운\\\" 선택이 가능합니다(하지만\"\n\" 유효한 PDF 이름을 만드는 것에 대한 공식 설명은 :ref:`AdobeManual`, 16페이지, 섹션 7.3.5 참조). \"\n\"그러나 :data:`Base14_Fonts` 또는 CJK 글꼴 중 하나와 일치하면 *fontfile* 및 *fontbuffer* 는\"\n\" **무시됩니다**.\"\n\n#: ../../page.rst:1160 cf82f15dcf404eadb21b4a1dba93ecb5\nmsgid \"\"\n\"In other words, you cannot insert a font via *fontfile* / *fontbuffer* \"\n\"and also give it a reserved *fontname*.\"\nmsgstr \"\"\n\"즉, *fontfile* / *fontbuffer* 를 통해 글꼴을 삽입하고 동시에 예약된 *fontname* 을 지정할 수 \"\n\"없습니다.\"\n\n#: ../../page.rst:1162 e659c191992e48eb94d7f32ba3c46183\nmsgid \"\"\n\"A reserved fontname can be specified in any mixture of upper or lower \"\n\"case and still match the right built-in font definition: fontnames \"\n\"\\\"helv\\\", \\\"Helv\\\", \\\"HELV\\\", \\\"Helvetica\\\", etc. all lead to the same \"\n\"font definition \\\"Helvetica\\\". But from a :ref:`Page` perspective, these \"\n\"are **different references**. You can exploit this fact when using \"\n\"different *encoding* variants (Latin, Greek, Cyrillic) of the same font \"\n\"on a page.\"\nmsgstr \"\"\n\"예약된 글꼴 이름은 대소문자를 혼합하여 지정할 수 있으며 여전히 올바른 내장 글꼴 정의와 일치합니다: \\\"helv\\\", \"\n\"\\\"Helv\\\", \\\"HELV\\\", \\\"Helvetica\\\" 등의 글꼴 이름은 모두 동일한 글꼴 정의 \\\"Helvetica\\\"로 \"\n\"이어집니다. 하지만 :ref:`Page` 관점에서 이것들은 **다른 참조** 입니다. 페이지에서 동일한 글꼴의 서로 다른 \"\n\"*encoding* 변형(라틴어, 그리스어, 키릴 문자)을 사용할 때 이 사실을 활용할 수 있습니다.\"\n\n#: ../../page.rst:1164 ef07701a528349508e27adfd4b1b8ed5\nmsgid \"\"\n\"a path to a font file. If used, *fontname* must be **different from all \"\n\"reserved names**.\"\nmsgstr \"글꼴 파일의 경로. 사용하는 경우 *fontname* 은 **모든 예약된 이름과 달라야 합니다**.\"\n\n#: ../../page.rst:1166 c56234a1c1bb47d6b53f4c450ee2baaa\nmsgid \"\"\n\"the memory image of a font file. If used, *fontname* must be **different \"\n\"from all reserved names**. This parameter would typically be used with \"\n\":attr:`Font.buffer` for fonts supported / available via :ref:`Font`.\"\nmsgstr \"\"\n\"글꼴 파일의 메모리 이미지. 사용하는 경우 *fontname* 은 **모든 예약된 이름과 달라야 합니다**. 이 매개변수는 \"\n\"일반적으로 :ref:`Font` 를 통해 지원/사용 가능한 글꼴에 대해 :attr:`Font.buffer` 와 함께 사용됩니다.\"\n\n#: ../../page.rst:1168 c829498fc36446f98af9abf805e60b4e\nmsgid \"\"\n\"applicable for *fontfile* / *fontbuffer* cases only: enforce treatment as\"\n\" a \\\"simple\\\" font, i.e. one that only uses character codes up to 255.\"\nmsgstr \"\"\n\"*fontfile* / *fontbuffer* 경우에만 적용: \\\"simple\\\" 글꼴로 처리하도록 강제합니다. 즉, 255까지의 \"\n\"문자 코드만 사용하는 글꼴입니다.\"\n\n#: ../../page.rst:1170 c85e98b3a7994b05a04787dda7a8b07f\nmsgid \"\"\n\"applicable for the \\\"Helvetica\\\", \\\"Courier\\\" and \\\"Times\\\" sets of \"\n\":data:`Base14_Fonts` only. Select one of the available encodings Latin \"\n\"(0), Cyrillic (2) or Greek (1). Only use the default (0 = Latin) for \"\n\"\\\"Symbol\\\" and \\\"ZapfDingBats\\\".\"\nmsgstr \"\"\n\"\\\"Helvetica\\\", \\\"Courier\\\", \\\"Times\\\" 세트의 :data:`Base14_Fonts` 에만 적용됩니다. \"\n\"사용 가능한 인코딩 중 하나를 선택하세요: 라틴어(0), 키릴 문자(2) 또는 그리스어(1). \\\"Symbol\\\" 및 \"\n\"\\\"ZapfDingBats\\\"의 경우 기본값(0 = 라틴어)만 사용하세요.\"\n\n#: ../../page.rst 36550b7edee54c1188ca5609869459d7\nmsgid \"rytpe\"\nmsgstr \"반환 타입\"\n\n#: ../../page.rst:1172 ../../page.rst:2186 ../../page.rst:2270\n#: ../../page.rst:2440 ../../page.rst:2447 2e2e55470cc44eadac95427335597b0d\n#: 90dd8a61e3a94693983ed36666b06529 b79cd61cdba44da2aa18e06e172e512c\n#: d7725f03960a46eab8731060d7c5fbd6 e566747d94314d3c95161b75011eb1b8\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../page.rst:1173 5510866376644f7bbd427e5ef653fa7d\nmsgid \"the :data:`xref` of the installed font.\"\nmsgstr \"설치된 글꼴의 :data:`xref`.\"\n\n#: ../../page.rst:1175 d480db0679494d579d74b4c34d55a73a\nmsgid \"\"\n\"Built-in fonts will not lead to the inclusion of a font file. So the \"\n\"resulting PDF file will remain small. However, your PDF viewer software \"\n\"is responsible for generating an appropriate appearance -- and there \"\n\"**exist** differences on whether or how each one of them does this. This \"\n\"is especially true for the CJK fonts. But also Symbol and ZapfDingbats \"\n\"are incorrectly handled in some cases. Following are the **Font Names** \"\n\"and their correspondingly installed **Base Font** names:\"\nmsgstr \"\"\n\"내장 글꼴은 글꼴 파일 포함을 필요로 하지 않습니다. 따라서 결과 PDF 파일은 작게 유지됩니다. 그러나 PDF 뷰어 소프트웨어는 \"\n\"적절한 외관을 생성할 책임이 있으며, 각각이 이를 수행하는지 여부나 방법에 **차이** 가 있습니다. 이것은 특히 CJK 글꼴에 \"\n\"해당합니다. 하지만 Symbol과 ZapfDingbats도 일부 경우에 잘못 처리됩니다. 다음은 **Font Names** 및 해당\"\n\" 설치된 **Base Font** 이름입니다:\"\n\n#: ../../page.rst:1177 2fc11411f26642cb8e883be2ec988af9\nmsgid \"**Base-14 Fonts** [#f1]_\"\nmsgstr \"**Base-14 Fonts** [#f1]_\"\n\n#: ../../page.rst:1180 ../../page.rst:1201 2b45356e25314be8b5bd94785561fa33\n#: 53f516761abf4a47b377dc0ce82a5ad2\nmsgid \"**Font Name**\"\nmsgstr \"**Font Name**\"\n\n#: ../../page.rst:1180 ../../page.rst:1201 4c08f1380f274a2995cb0532552a27ed\n#: 637b903b10b743fa92e4243d3f65239e\nmsgid \"**Installed Base Font**\"\nmsgstr \"**Installed Base Font**\"\n\n#: ../../page.rst:1180 ../../page.rst:1201 4cff83bd3cf54493b09148347eb75b51\n#: da3707c6048645368c0956ebc887eb2f\nmsgid \"**Comments**\"\nmsgstr \"**Comments**\"\n\n#: ../../page.rst:1182 18293365bcfe4cea8468ce984682e74a\nmsgid \"helv\"\nmsgstr \"\"\n\n#: ../../page.rst:1182 55f64fae05f24262a6bb2c38fbf9628e\nmsgid \"Helvetica\"\nmsgstr \"\"\n\n#: ../../page.rst:1182 ../../page.rst:1186 ../../page.rst:1190\n#: 0e899653f2654c20850bbedf45d3b8b0 593ba869eceb482fb75902f9ad648d45\n#: dceffb7e5907437ba8a334b106176f45\nmsgid \"normal\"\nmsgstr \"\"\n\n#: ../../page.rst:1183 1c5cb11c1c474c6f8f4d043b8dd09291\nmsgid \"heit\"\nmsgstr \"\"\n\n#: ../../page.rst:1183 aa164b95b2d4400f80f650354746f770\nmsgid \"Helvetica-Oblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1183 ../../page.rst:1187 ../../page.rst:1191\n#: 2fdc4b72443d48bf81c8b63240b714d6 d23ef9bf70e742a6bb3230e917321082\n#: ff6f502342704e1b86371e6a7d3aa4c2\nmsgid \"italic\"\nmsgstr \"\"\n\n#: ../../page.rst:1184 8f49bb24a40b4de387dfb0b043baaf9b\nmsgid \"hebo\"\nmsgstr \"\"\n\n#: ../../page.rst:1184 7cbf4e7da59a4718b322603212ee1d57\nmsgid \"Helvetica-Bold\"\nmsgstr \"\"\n\n#: ../../page.rst:1184 ../../page.rst:1188 ../../page.rst:1192\n#: 838ff8b719074bcb9aa6e14ec2895b7a 8c9e2fd138844d85b496e9183c9065a6\n#: 97006eb599164f1a9a2873d2c0af75ad\nmsgid \"bold\"\nmsgstr \"\"\n\n#: ../../page.rst:1185 0c8b5e39b8d843b3954ce0722e56244d\nmsgid \"hebi\"\nmsgstr \"\"\n\n#: ../../page.rst:1185 984cc215aa174fabba3896c4cc3cd988\nmsgid \"Helvetica-BoldOblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1185 ../../page.rst:1189 ../../page.rst:1193\n#: 0bb7be12571e43d48afe5bbd824fbd86 580462e857cc4ae08f5a44c62d007b2f\n#: 6a92795b28d64e4fbb8e44e487e61ae7\nmsgid \"bold-italic\"\nmsgstr \"\"\n\n#: ../../page.rst:1186 5303cf0daa7848a6ac6afdbaa4daef00\nmsgid \"cour\"\nmsgstr \"\"\n\n#: ../../page.rst:1186 ccedc4fb0a5744b99f8c423452738f7f\nmsgid \"Courier\"\nmsgstr \"\"\n\n#: ../../page.rst:1187 16e14eccc0da475e9726a70633179cd5\nmsgid \"coit\"\nmsgstr \"\"\n\n#: ../../page.rst:1187 c98264eab09d44468c0b91851cc4c4a8\nmsgid \"Courier-Oblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1188 e64194c194364645ade04f15f1ef62a7\nmsgid \"cobo\"\nmsgstr \"\"\n\n#: ../../page.rst:1188 e55b1cd2b40543ab9c54d97ade2b9b75\nmsgid \"Courier-Bold\"\nmsgstr \"\"\n\n#: ../../page.rst:1189 1aca6ab6b76a4aed908832e8d0fa1571\nmsgid \"cobi\"\nmsgstr \"\"\n\n#: ../../page.rst:1189 29904bdcfa1e406190e7bea97386c29c\nmsgid \"Courier-BoldOblique\"\nmsgstr \"\"\n\n#: ../../page.rst:1190 8f6db99bec2c453da271d5f2c815f825\nmsgid \"tiro\"\nmsgstr \"\"\n\n#: ../../page.rst:1190 9743271d2a5c46cfb39f130399e1b959\nmsgid \"Times-Roman\"\nmsgstr \"\"\n\n#: ../../page.rst:1191 c8538ccd9183467e9b13a1dd70171f26\nmsgid \"tiit\"\nmsgstr \"\"\n\n#: ../../page.rst:1191 6c5eff126dfa4f07b32035767abd3a3a\nmsgid \"Times-Italic\"\nmsgstr \"\"\n\n#: ../../page.rst:1192 12f1f169bc8d424482ed52c8e0f5c79e\nmsgid \"tibo\"\nmsgstr \"\"\n\n#: ../../page.rst:1192 ab0221cc28944b99b07d7d60aaedfd69\nmsgid \"Times-Bold\"\nmsgstr \"\"\n\n#: ../../page.rst:1193 69bb30b66c774e3e93d7a0849f590e51\nmsgid \"tibi\"\nmsgstr \"\"\n\n#: ../../page.rst:1193 e49be3741ac148ee8b2e7fc41200329f\nmsgid \"Times-BoldItalic\"\nmsgstr \"\"\n\n#: ../../page.rst:1194 f9cce506526e4e5a94056122c567803f\nmsgid \"symb\"\nmsgstr \"\"\n\n#: ../../page.rst:1194 24960e62fc5749b0bc2e3bcc9d141d70\nmsgid \"Symbol\"\nmsgstr \"\"\n\n#: ../../page.rst:1194 ../../page.rst:1195 56a30bd5d1c64f6baa60b7582a72264a\n#: d7f4778c5af3488f8abb49d03780112c\nmsgid \"[#f3]_\"\nmsgstr \"\"\n\n#: ../../page.rst:1195 58d2bbe78bd54b628e30622e27019a91\nmsgid \"zadb\"\nmsgstr \"\"\n\n#: ../../page.rst:1195 d320a00b7b2747d4a1b212fbd9ed5119\nmsgid \"ZapfDingbats\"\nmsgstr \"\"\n\n#: ../../page.rst:1198 74a791ec4c884dc9adc83e26d1751c2b\nmsgid \"**CJK Fonts** [#f2]_ (China, Japan, Korea)\"\nmsgstr \"**CJK Fonts** [#f2]_ (중국, 일본, 한국)\"\n\n#: ../../page.rst:1203 068dbb7a377f4e5faf6e4aa1b3ce3676\nmsgid \"china-s\"\nmsgstr \"\"\n\n#: ../../page.rst:1203 4db5b0c4dc68430cbc0ffcd7a97a70dd\nmsgid \"Heiti\"\nmsgstr \"\"\n\n#: ../../page.rst:1203 9357308deba14c3385c9d72a034f7880\nmsgid \"simplified Chinese\"\nmsgstr \"간체 중국어\"\n\n#: ../../page.rst:1204 6ab7fb2c07cd4c439f9453d2d4af5902\nmsgid \"china-ss\"\nmsgstr \"\"\n\n#: ../../page.rst:1204 13f223fbbe2045eebb63e28239948a77\nmsgid \"Song\"\nmsgstr \"\"\n\n#: ../../page.rst:1204 cd8e8871140d428a9c83c9322ab1b320\nmsgid \"simplified Chinese (serif)\"\nmsgstr \"간체 중국어 (세리프)\"\n\n#: ../../page.rst:1205 03880884fd8b4985b9439d42e3671fc1\nmsgid \"china-t\"\nmsgstr \"\"\n\n#: ../../page.rst:1205 f39bfbec06864f53a9321d89ed47c76a\nmsgid \"Fangti\"\nmsgstr \"\"\n\n#: ../../page.rst:1205 ea0b2ee888694862a655a28eb8dccee6\nmsgid \"traditional Chinese\"\nmsgstr \"번체 중국어\"\n\n#: ../../page.rst:1206 b584de518de04581865eff60a3069d72\nmsgid \"china-ts\"\nmsgstr \"\"\n\n#: ../../page.rst:1206 14094a25049b4446b25d31d2a6ace697\nmsgid \"Ming\"\nmsgstr \"\"\n\n#: ../../page.rst:1206 2c421d836ecb4174ad42a9ccef0eb1a7\nmsgid \"traditional Chinese (serif)\"\nmsgstr \"번체 중국어 (세리프)\"\n\n#: ../../page.rst:1207 e9b2a65d815447e6a82eab64d9891634\nmsgid \"japan\"\nmsgstr \"\"\n\n#: ../../page.rst:1207 b0ff2c611e0b4d709055dae4e541480f\nmsgid \"Gothic\"\nmsgstr \"\"\n\n#: ../../page.rst:1207 d76896751b73458a8c326ad9eded2f3f\nmsgid \"Japanese\"\nmsgstr \"일본어\"\n\n#: ../../page.rst:1208 b9a20234dcc44c96ba614f99a25c1f9f\nmsgid \"japan-s\"\nmsgstr \"\"\n\n#: ../../page.rst:1208 c8bdf8c39ecf43b89c45842d51668900\nmsgid \"Mincho\"\nmsgstr \"\"\n\n#: ../../page.rst:1208 988a1e7ab9cc40e0979ad2d236e4c279\nmsgid \"Japanese (serif)\"\nmsgstr \"일본어 (세리프)\"\n\n#: ../../page.rst:1209 6b69e6244f8549d29911f61d1c8b46bb\nmsgid \"korea\"\nmsgstr \"\"\n\n#: ../../page.rst:1209 dbf67a34442c49dda05b93aca301dd1e\nmsgid \"Dotum\"\nmsgstr \"\"\n\n#: ../../page.rst:1209 488a6626d802450a99c002882eec0366\nmsgid \"Korean\"\nmsgstr \"한국어\"\n\n#: ../../page.rst:1210 3ca620da7a6344078a50bdbb4a038045\nmsgid \"korea-s\"\nmsgstr \"\"\n\n#: ../../page.rst:1210 6d3a35431e6b4be786d3be8f9ceeaf20\nmsgid \"Batang\"\nmsgstr \"\"\n\n#: ../../page.rst:1210 fb704da9b28f473ea4a3f3e2db5c888e\nmsgid \"Korean (serif)\"\nmsgstr \"한국어 (세리프)\"\n\n#: ../../page.rst:1226 c67586c85e2a449fae83d95b4d75cf2f\nmsgid \"\"\n\"PDF only: Put an image inside the given rectangle. The image may already \"\n\"exist in the PDF or be taken from a pixmap, a file, or a memory area.\"\nmsgstr \"\"\n\"PDF 전용: 주어진 사각형 내에 이미지를 배치합니다. 이미지는 이미 PDF에 존재하거나 픽스맵, 파일 또는 메모리 영역에서 가져올\"\n\" 수 있습니다.\"\n\n#: ../../page.rst:1229 04e5d29ccbeb4e709039ad427ff40069\nmsgid \"where to put the image. Must be finite and not empty.\"\nmsgstr \"이미지를 배치할 위치. 유한하고 비어 있지 않아야 합니다.\"\n\n#: ../../page.rst:1230 d72696dae884419390fab43b03412f3b\nmsgid \"deprecated and ignored.\"\nmsgstr \"더 이상 사용되지 않으며 무시됩니다.\"\n\n#: ../../page.rst:1231 9d5780a4200f4ee48da1f4c6c9f4161b\nmsgid \"\"\n\"name of an image file (all formats supported by MuPDF -- see \"\n\":ref:`ImageFiles`).\"\nmsgstr \"이미지 파일 이름(MuPDF에서 지원하는 모든 형식 -- :ref:`ImageFiles` 참조).\"\n\n#: ../../page.rst:1235 85e7a2bc15744184be453270c69da4b4\nmsgid \"maintain the aspect ratio of the image.\"\nmsgstr \"이미지의 종횡비를 유지합니다.\"\n\n#: ../../page.rst:1237 8643882ac247408698bcde17b0a3e2a1\nmsgid \"\"\n\"image in memory -- to be used as image mask (alpha values) for the base \"\n\"image. When specified, the base image must be provided as a filename or a\"\n\" stream -- and must not be an image that already has a mask.\"\nmsgstr \"\"\n\"메모리의 이미지 -- 기본 이미지의 이미지 마스크(알파 값)로 사용됩니다. 지정된 경우 기본 이미지는 파일 이름 또는 스트림으로 \"\n\"제공되어야 하며, 이미 마스크가 있는 이미지가 아니어야 합니다.\"\n\n#: ../../page.rst:1241 e61845a265de4e0f89f8353d7b1bb062\nmsgid \"\"\n\"(:data:`xref`) make image visibility dependent on this :data:`OCG` or \"\n\":data:`OCMD`. Ignored after the first of multiple insertions. The \"\n\"property is stored with the generated PDF image object and therefore \"\n\"controls the image's visibility throughout the PDF.\"\nmsgstr \"\"\n\"(:data:`xref`) 이미지 가시성을 이 :data:`OCG` 또는 :data:`OCMD` 에 종속시킵니다. 여러 번 삽입 시\"\n\" 첫 번째 이후에는 무시됩니다. 이 속성은 생성된 PDF 이미지 객체와 함께 저장되므로 PDF 전체에서 이미지 가시성을 제어합니다.\"\n\n#: ../../page.rst:1246 c4a6133751b74f3399ef5608f0582302\nmsgid \"see :ref:`CommonParms`.\"\nmsgstr \":ref:`CommonParms` 참조.\"\n\n#: ../../page.rst:1247 0d9ca43ecaa7497f8c778182f0bba3ee\nmsgid \"a pixmap containing the image.\"\nmsgstr \"이미지를 포함하는 픽스맵.\"\n\n#: ../../page.rst:1248 94d006c7929d472fa1526111ad2ec5f6\nmsgid \"\"\n\"rotate the image. Must be an integer multiple of 90 degrees. Positive \"\n\"values rotate anti-clockwise. If you need a rotation by an arbitrary \"\n\"angle, consider converting the image to a PDF \"\n\"(:meth:`Document.convert_to_pdf`) first and then use \"\n\":meth:`Page.show_pdf_page` instead.\"\nmsgstr \"\"\n\"이미지를 회전시킵니다. 90도의 정수 배여야 합니다. 양수 값은 반시계 방향으로 회전합니다. 임의의 각도로 회전이 필요한 경우 먼저\"\n\" 이미지를 PDF로 변환(:meth:`Document.convert_to_pdf`)한 다음 \"\n\":meth:`Page.show_pdf_page` 를 사용하는 것을 고려하세요.\"\n\n#: ../../page.rst:1255 a582d71169ef4cd4a5eb4911e45a312e\nmsgid \"image in memory (all formats supported by MuPDF -- see :ref:`ImageFiles`).\"\nmsgstr \"메모리의 이미지(MuPDF에서 지원하는 모든 형식 -- :ref:`ImageFiles` 참조).\"\n\n#: ../../page.rst:1258 cef8b29899b44e368609cdbe39ff4247\nmsgid \"\"\n\"the :data:`xref` of an image already present in the PDF. If given, \"\n\"parameters `filename`, `pixmap`, `stream`, `alpha` and `mask` are \"\n\"ignored. The page will simply receive a reference to the existing image.\"\nmsgstr \"\"\n\"PDF에 이미 존재하는 이미지의 :data:`xref`. 주어진 경우 `filename`, `pixmap`, `stream`, \"\n\"`alpha` 및 `mask` 매개변수는 무시됩니다. 페이지는 기존 이미지에 대한 참조만 받습니다.\"\n\n#: ../../page.rst:1266 8a294a1cb1c14a9b9034df80278ccf95\nmsgid \"\"\n\"The `xref` of the embedded image. This can be used as the `xref` argument\"\n\" for very significant performance boosts, if the image is inserted again.\"\nmsgstr \"삽입된 이미지의 `xref`. 이미지를 다시 삽입하는 경우 `xref` 인수로 사용하면 성능이 크게 향상될 수 있습니다.\"\n\n#: ../../page.rst:1271 429d172dcd0e4214a6c208e57d4e3afb\nmsgid \"This example puts the same image on every page of a document::\"\nmsgstr \"이 예제는 문서의 모든 페이지에 동일한 이미지를 배치합니다::\"\n\n#: ../../page.rst:1286 b2d4bb04c80047959353332f0b2e0ac6\nmsgid \"\"\n\"The method detects multiple insertions of the same image (like in the \"\n\"above example) and will store its data only on the first execution.  This\"\n\" is even true (although less performant), if using the default `xref=0`.\"\nmsgstr \"\"\n\"이 메서드는 동일한 이미지의 여러 번 삽입(위 예제와 같이)을 감지하고 첫 번째 실행 시에만 데이터를 저장합니다. 기본값 \"\n\"`xref=0` 을 사용하는 경우에도 이것은 사실입니다(성능은 낮지만).\"\n\n#: ../../page.rst:1291 f1202c94bfe64affa714aac1ef466862\nmsgid \"\"\n\"The method cannot detect if the same image had already been part of the \"\n\"file before opening it.\"\nmsgstr \"이 메서드는 파일을 열기 전에 동일한 이미지가 이미 파일의 일부였는지 감지할 수 없습니다.\"\n\n#: ../../page.rst:1295 4b883662d2fc4a8ca0bdc17d835f9d84\nmsgid \"\"\n\"You can use this method to provide a background or foreground image for \"\n\"the page, like a copyright or a watermark. Please remember, that \"\n\"watermarks require a transparent image if put in foreground ...\"\nmsgstr \"\"\n\"이 메서드를 사용하여 저작권 표시나 워터마크와 같은 페이지의 배경 또는 전경 이미지를 제공할 수 있습니다. 워터마크는 전경에 \"\n\"배치하는 경우 투명한 이미지가 필요하다는 것을 기억하세요...\"\n\n#: ../../page.rst:1300 65d8b02c83cc4c1db2dd4c6707b37732\nmsgid \"\"\n\"The image may be inserted uncompressed, e.g. if a `Pixmap` is used or if \"\n\"the image has an alpha channel. Therefore, consider using `deflate=True` \"\n\"when saving the file. In addition, there are ways to control the image \"\n\"size -- even if transparency comes into play. Have a look at \"\n\":ref:`RecipesImages_O`.\"\nmsgstr \"\"\n\"이미지는 압축되지 않은 상태로 삽입될 수 있습니다(예: `Pixmap` 이 사용되거나 이미지에 알파 채널이 있는 경우). 따라서 \"\n\"파일을 저장할 때 `deflate=True` 를 사용하는 것을 고려하세요. 또한 투명도가 관련된 경우에도 이미지 크기를 제어하는 \"\n\"방법이 있습니다. :ref:`RecipesImages_O` 를 참조하세요.\"\n\n#: ../../page.rst:1307 605df42da17b4553aa6788fa75e32bd0\nmsgid \"\"\n\"The image is stored in the PDF at its original quality level. This may be\"\n\" much better than what you need for your display. Consider **decreasing \"\n\"the image size** before insertion -- e.g. by using the pixmap option and \"\n\"then shrinking it or scaling it down (see :ref:`Pixmap` chapter). The PIL\"\n\" method `Image.thumbnail()` can also be used for that purpose. The file \"\n\"size savings can be very significant.\"\nmsgstr \"\"\n\"이미지는 원본 품질 수준으로 PDF에 저장됩니다. 이것은 디스플레이에 필요한 것보다 훨씬 좋을 수 있습니다. 삽입 전에 **이미지 \"\n\"크기를 줄이는** 것을 고려하세요 -- 예를 들어 픽스맵 옵션을 사용한 다음 축소하거나 크기를 줄입니다(:ref:`Pixmap` 장\"\n\" 참조). PIL 메서드 `Image.thumbnail()` 도 이 목적에 사용할 수 있습니다. 파일 크기 절감이 매우 클 수 \"\n\"있습니다.\"\n\n#: ../../page.rst:1316 17544a4536244b86b695e7a3aa360e86\nmsgid \"\"\n\"Another efficient way to display the same image on multiple pages is \"\n\"another method: :meth:`show_pdf_page`. Consult \"\n\":meth:`Document.convert_to_pdf` for how to obtain intermediary PDFs \"\n\"usable for that method.\"\nmsgstr \"\"\n\"여러 페이지에 동일한 이미지를 표시하는 또 다른 효율적인 방법은 다른 메서드입니다: :meth:`show_pdf_page`. 해당 \"\n\"메서드에 사용할 수 있는 중간 PDF를 얻는 방법은 :meth:`Document.convert_to_pdf` 를 참조하세요.\"\n\n#: ../../page.rst:1323 8239152d8a2948ae969d5a26895b0f88\nmsgid \"Changed in v1.14.1: By default, the image keeps its aspect ratio.\"\nmsgstr \"v1.14.1에서 변경됨: 기본적으로 이미지는 종횡비를 유지합니다.\"\n\n#: ../../page.rst:1324 cd485cd6ed0447658b17b7b742fb26d1\nmsgid \"Changed in v1.14.11: Added args `keep_proportion`, `rotate`.\"\nmsgstr \"v1.14.11에서 변경됨: `keep_proportion`, `rotate` 인수 추가.\"\n\n#: ../../page.rst:1325 2001b89cf3134a449792eb3d2c50fe8e\nmsgid \"Changed in v1.14.13:\"\nmsgstr \"v1.14.13에서 변경됨:\"\n\n#: ../../page.rst:1328 557eff2950f84c5295ea861bd576884f\nmsgid \"\"\n\"The image is now always placed **centered** in the rectangle, i.e. the \"\n\"centers of image and rectangle are equal.\"\nmsgstr \"이미지는 이제 항상 사각형 내에서 **중앙** 에 배치됩니다. 즉, 이미지와 사각형의 중심이 같습니다.\"\n\n#: ../../page.rst:1330 bf6a4645943d4c91aa882f357fb84ad0\nmsgid \"Added support for `stream` as `io.BytesIO`.\"\nmsgstr \"`stream` 을 `io.BytesIO` 로 지원 추가.\"\n\n#: ../../page.rst:1332 98bae562bc734a7eae573e415c8f54c8\nmsgid \"\"\n\"Changed in v1.17.6: Insertion rectangle no longer needs to have a non-\"\n\"empty intersection with the page's :attr:`Page.cropbox` [#f5]_.\"\nmsgstr \"\"\n\"v1.17.6에서 변경됨: 삽입 사각형이 더 이상 페이지의 :attr:`Page.cropbox` [#f5]_와 비어 있지 않은 \"\n\"교집합을 가질 필요가 없습니다.\"\n\n#: ../../page.rst:1335 89abd8465cd5417b8ee798a837a8650e\nmsgid \"Changed in v1.18.1: Added `mask` arg.\"\nmsgstr \"v1.18.1에서 변경됨: `mask` 인수 추가.\"\n\n#: ../../page.rst:1336 a59cc5282da348c79b5b88c040e4b39a\nmsgid \"Changed in v1.18.3: Added `oc` arg.\"\nmsgstr \"v1.18.3에서 변경됨: `oc` 인수 추가.\"\n\n#: ../../page.rst:1337 d407eb13d420415686a640bb59ed49aa\nmsgid \"Changed in v1.18.13:\"\nmsgstr \"v1.18.13에서 변경됨:\"\n\n#: ../../page.rst:1339 7355cd865e4d497399a73cbf63cca7fe\nmsgid \"Allow providing the image as the xref of an existing one.\"\nmsgstr \"기존 이미지의 xref로 이미지를 제공할 수 있도록 허용.\"\n\n#: ../../page.rst:1340 126a0f9d15384b44bc73f25f7d23e3f1\nmsgid \"Added `xref` arg.\"\nmsgstr \"`xref` 인수 추가.\"\n\n#: ../../page.rst:1341 4baadf25f03c43dfa268278c9ed4fd2b\nmsgid \"Return `xref` of stored image.\"\nmsgstr \"저장된 이미지의 `xref` 반환.\"\n\n#: ../../page.rst:1343 5bd9b05e55c149d79fce515dbf613f38\nmsgid \"Changed in v1.19.3: deprecate and ignore `alpha` arg.\"\nmsgstr \"v1.19.3에서 변경됨: `alpha` 인수를 더 이상 사용하지 않고 무시합니다.\"\n\n#: ../../page.rst:1356 fa99710cc2c94c609e67a7f6c95dba3c\nmsgid \"Replace the image at xref with another one.\"\nmsgstr \"xref의 이미지를 다른 이미지로 교체합니다.\"\n\n#: ../../page.rst:1358 ../../page.rst:1383 b807b4221b3a49ad8d260a6f2acf20df\n#: d10f6e058725472db2c1c7b4026673f0\nmsgid \"the :data:`xref` of the image.\"\nmsgstr \"이미지의 :data:`xref`.\"\n\n#: ../../page.rst:1359 5ed1e953dc324bf58e10b87858d7a47f\nmsgid \"the filename of the new image.\"\nmsgstr \"새 이미지의 파일 이름.\"\n\n#: ../../page.rst:1360 d1b533c8c050499893bb4d123651938b\nmsgid \"the :ref:`Pixmap` of the new image.\"\nmsgstr \"새 이미지의 :ref:`Pixmap`.\"\n\n#: ../../page.rst:1361 d0457bd767a3410c92a383c91ebcbedd\nmsgid \"the memory area containing the new image.\"\nmsgstr \"새 이미지를 포함하는 메모리 영역.\"\n\n#: ../../page.rst:1363 d32714ecc04241a9a4268fac123fb364\nmsgid \"\"\n\"Arguments `filename`, `pixmap`, `stream` have the same meaning as in \"\n\":meth:`Page.insert_image`, especially exactly one of these must be \"\n\"provided.\"\nmsgstr \"\"\n\"인수 `filename`, `pixmap`, `stream` 은 :meth:`Page.insert_image` 와 동일한 의미이며,\"\n\" 특히 이 중 정확히 하나를 제공해야 합니다.\"\n\n#: ../../page.rst:1365 c4946fe5d64d4ac0b4f5b131d9267fc6\nmsgid \"\"\n\"This is a **global replacement:** the new image will also be shown \"\n\"wherever the old one has been displayed throughout the file.\"\nmsgstr \"이것은 **전역 교체** 입니다: 새 이미지는 파일 전체에서 이전 이미지가 표시된 모든 위치에 표시됩니다.\"\n\n#: ../../page.rst:1367 9d59a1496ca54e0dbed9f1249b189632\nmsgid \"\"\n\"This method mainly exists for technical purposes. Typical uses include \"\n\"replacing large images by smaller versions, like a lower resolution, \"\n\"graylevel instead of colored, etc., or changing transparency.\"\nmsgstr \"\"\n\"이 메서드는 주로 기술적 목적으로 존재합니다. 일반적인 사용 사례에는 낮은 해상도, 컬러 대신 그레이스케일 등과 같은 더 작은 \"\n\"버전으로 큰 이미지를 교체하거나 투명도를 변경하는 것이 포함됩니다.\"\n\n#: ../../page.rst:1371 ../../page.rst:1395 8370d57607d948e69e595ebac5f3c631\n#: d876451ff8ad4817ba1b232c6e659a5b\nmsgid \"New in v1.21.0\"\nmsgstr \"*v1.21.0의 새로운 기능*\"\n\n#: ../../page.rst:1381 b276840a105941439de2b273ddff8084\nmsgid \"\"\n\"Delete the image at xref. This is slightly misleading: actually the image\"\n\" is being replaced with a small transparent :ref:`Pixmap` using above \"\n\":meth:`Page.replace_image`. The visible effect however is equivalent.\"\nmsgstr \"\"\n\"xref의 이미지를 삭제합니다. 이것은 약간 오해의 소지가 있습니다: 실제로는 위의 :meth:`Page.replace_image`\"\n\" 를 사용하여 작은 투명한 :ref:`Pixmap` 으로 교체됩니다. 그러나 시각적 효과는 동일합니다.\"\n\n#: ../../page.rst:1385 2a45f7a3dad649239d2434094e3c5898\nmsgid \"\"\n\"This is a **global replacement:** the image will disappear wherever the \"\n\"old one has been displayed throughout the file.\"\nmsgstr \"이것은 **전역 교체** 입니다: 이미지는 파일 전체에서 이전 이미지가 표시된 모든 위치에서 사라집니다.\"\n\n#: ../../page.rst:1387 ae3478603d3944368de35ac28c9151a8\nmsgid \"\"\n\"If you inspect / extract a page's images by methods like \"\n\":meth:`Page.get_images`, :meth:`Page.get_image_info` or \"\n\":meth:`Page.get_text`, the replacing \\\"dummy\\\" image will be detected \"\n\"like so `(45, 47, 1, 1, 8, 'DeviceGray', '', 'Im1', 'FlateDecode')` and \"\n\"also seem to \\\"cover\\\" the same boundary box on the page.\"\nmsgstr \"\"\n\":meth:`Page.get_images`, :meth:`Page.get_image_info` 또는 \"\n\":meth:`Page.get_text` 와 같은 메서드로 페이지의 이미지를 검사/추출하는 경우, 교체된 \\\"dummy\\\" 이미지는 \"\n\"`(45, 47, 1, 1, 8, 'DeviceGray', '', 'Im1', 'FlateDecode')` 와 같이 감지되며 \"\n\"페이지에서 동일한 경계 상자를 \\\"덮는\\\" 것처럼 보입니다.\"\n\n#: ../../page.rst:1418 3484beb579b9420090f7e98d9ea4b47c\nmsgid \"\"\n\"Retrieves the content of a page in a variety of formats. Depending on the\"\n\" ``flags`` value, this may include text, images and several other object \"\n\"types. The method is a wrapper for multiple :ref:`TextPage` methods by \"\n\"choosing the output option `opt` as follows:\"\nmsgstr \"\"\n\"다양한 형식으로 페이지의 콘텐츠를 검색합니다. ``flags`` 값에 따라 텍스트, 이미지 및 기타 여러 객체 타입이 포함될 수 \"\n\"있습니다. 이 메서드는 출력 옵션 `opt` 를 다음과 같이 선택하여 여러 :ref:`TextPage` 메서드에 대한 래퍼입니다:\"\n\n#: ../../page.rst:1420 c3957a9f0e79439992d9d6615f11fe40\nmsgid \"\"\n\"\\\"text\\\" -- :meth:`TextPage.extractTEXT`, default. Always includes **text\"\n\" only.**\"\nmsgstr \"\\\"text\\\" -- :meth:`TextPage.extractTEXT`, 기본값. 항상 **텍스트만** 포함합니다.\"\n\n#: ../../page.rst:1421 c1b7076659a94128a73a82d593aaa4d3\nmsgid \"\"\n\"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS`. Includes text and **may** \"\n\"include image meta information.\"\nmsgstr \"\"\n\"\\\"blocks\\\" -- :meth:`TextPage.extractBLOCKS`. 텍스트를 포함하며 **이미지 메타 정보를 포함할 \"\n\"수 있습니다**.\"\n\n#: ../../page.rst:1422 2da3939e1d7c472e818a36ce516eff17\nmsgid \"\\\"words\\\" -- :meth:`TextPage.extractWORDS`. Always includes **text only.**\"\nmsgstr \"\\\"words\\\" -- :meth:`TextPage.extractWORDS`. 항상 **텍스트만** 포함합니다.\"\n\n#: ../../page.rst:1423 db922a0f8df44faca069430e7f5b192d\nmsgid \"\\\"html\\\" -- :meth:`TextPage.extractHTML`. May include text and images.\"\nmsgstr \"\\\"html\\\" -- :meth:`TextPage.extractHTML`. 텍스트와 이미지를 포함할 수 있습니다.\"\n\n#: ../../page.rst:1424 c4332759c6c5457da53be98773162edc\nmsgid \"\\\"xhtml\\\" -- :meth:`TextPage.extractXHTML`. May include text and images.\"\nmsgstr \"\\\"xhtml\\\" -- :meth:`TextPage.extractXHTML`. 텍스트와 이미지를 포함할 수 있습니다.\"\n\n#: ../../page.rst:1425 820d47e90f8e41ebae909a741e197004\nmsgid \"\\\"xml\\\" -- :meth:`TextPage.extractXML`. Always includes **text only.**\"\nmsgstr \"\\\"xml\\\" -- :meth:`TextPage.extractXML`. 항상 **텍스트만** 포함합니다.\"\n\n#: ../../page.rst:1426 dd6ad63d5d2944349be005282a9132c9\nmsgid \"\\\"dict\\\" -- :meth:`TextPage.extractDICT`. May include text and images.\"\nmsgstr \"\\\"dict\\\" -- :meth:`TextPage.extractDICT`. 텍스트와 이미지를 포함할 수 있습니다.\"\n\n#: ../../page.rst:1427 71fcb8dc2d554939b52630ee6f8995a8\nmsgid \"\\\"json\\\" -- :meth:`TextPage.extractJSON`. May include text and images.\"\nmsgstr \"\\\"json\\\" -- :meth:`TextPage.extractJSON`. 텍스트와 이미지를 포함할 수 있습니다.\"\n\n#: ../../page.rst:1428 ea90fa3efb484e1cb7a8268f72c57bdb\nmsgid \"\"\n\"\\\"rawdict\\\" -- :meth:`TextPage.extractRAWDICT`. May include text and \"\n\"images.\"\nmsgstr \"\\\"rawdict\\\" -- :meth:`TextPage.extractRAWDICT`. 텍스트와 이미지를 포함할 수 있습니다.\"\n\n#: ../../page.rst:1429 6fbdec11ab834609a97b7105008227b8\nmsgid \"\"\n\"\\\"rawjson\\\" -- :meth:`TextPage.extractRAWJSON`. May include text and \"\n\"images.\"\nmsgstr \"\\\"rawjson\\\" -- :meth:`TextPage.extractRAWJSON`. 텍스트와 이미지를 포함할 수 있습니다.\"\n\n#: ../../page.rst:1431 fb947bb8e7d0457c9db932169a26e3e3\nmsgid \"\"\n\"A string indicating the requested format, one of the above. A mixture of \"\n\"upper and lower case is supported. If misspelled, option \\\"text\\\" is \"\n\"silently assumed.\"\nmsgstr \"\"\n\"요청된 형식을 나타내는 문자열, 위 중 하나. 대소문자 혼합이 지원됩니다. 철자가 잘못된 경우 옵션 \\\"text\\\"가 조용히 \"\n\"가정됩니다.\"\n\n#: ../../page.rst:1433 1bd53244773c4a5dadef1ff0bab3eee1\nmsgid \"\"\n\"restrict the extraction to this rectangle. If ``None`` (default), the \"\n\"visible part of the page is taken. Any content (text, images) that is \"\n\"**not fully contained** in ``clip`` will be completely omitted. To avoid \"\n\"clipping altogether use ``clip=pymupdf.INFINITE_RECT()``. Only then the \"\n\"extraction will contain all items. This parameter has **no effect** on \"\n\"options \\\"html\\\", \\\"xhtml\\\" and \\\"xml\\\".\"\nmsgstr \"\"\n\"추출을 이 사각형으로 제한합니다. ``None`` (기본값)인 경우 페이지의 보이는 부분이 사용됩니다. ``clip`` 에 **완전히\"\n\" 포함되지 않은** 모든 콘텐츠(텍스트, 이미지)는 완전히 생략됩니다. 클리핑을 완전히 피하려면 \"\n\"``clip=pymupdf.INFINITE_RECT()`` 를 사용하세요. 그럴 때만 추출에 모든 항목이 포함됩니다. 이 매개변수는\"\n\" 옵션 \\\"html\\\", \\\"xhtml\\\", \\\"xml\\\"에 **효과가 없습니다**.\"\n\n#: ../../page.rst:1435 f73603f823f4483c8d30d0a89f7572f8\nmsgid \"\"\n\"indicator bits to control whether to include images or how text should be\"\n\" handled with respect to white spaces and :data:`ligatures`. See \"\n\":ref:`TextPreserve` for available indicators and \"\n\":ref:`text_extraction_flags` for default settings. (New in v1.16.2)\"\nmsgstr \"\"\n\"이미지를 포함할지 여부 또는 공백 및 :data:`ligatures` 에 대해 텍스트를 처리하는 방법을 제어하는 표시기 비트. 사용\"\n\" 가능한 표시기는 :ref:`TextPreserve` 를 참조하고 기본 설정은 :ref:`text_extraction_flags` \"\n\"를 참조하세요. (v1.16.2의 새로운 기능)\"\n\n#: ../../page.rst:1437 c561e7ef134f498793cc90393da4d1c6\nmsgid \"\"\n\"use a previously created :ref:`TextPage`. This reduces execution time \"\n\"**very significantly:** by more than 50% and up to 95%, depending on the \"\n\"extraction option. If specified, the 'flags' and 'clip' arguments are \"\n\"ignored, because they are textpage-only properties. If omitted, a new, \"\n\"temporary textpage will be created.\"\nmsgstr \"\"\n\"이전에 생성된 :ref:`TextPage` 를 사용합니다. 이것은 실행 시간을 **매우 크게** 줄입니다: 추출 옵션에 따라 50%\"\n\" 이상 최대 95%까지. 지정된 경우 'flags' 및 'clip' 인수는 무시됩니다. 이는 textpage 전용 속성이기 \"\n\"때문입니다. 생략하면 새로운 임시 textpage가 생성됩니다.\"\n\n#: ../../page.rst:1439 f887e407e2af4318822e05c0eff94bc2\nmsgid \"\"\n\"sort the output by vertical, then horizontal coordinates. In many cases, \"\n\"this should suffice to generate a \\\"natural\\\" reading order. Has no \"\n\"effect on (X)HTML and XML. For options \\\"blocks\\\", \\\"dict\\\", \\\"json\\\", \"\n\"\\\"rawdict\\\", \\\"rawjson\\\", sorting happens by coordinates `(y1, x0)` of \"\n\"the respective block bbox. For options \\\"words\\\" and \\\"text\\\", the text \"\n\"lines are completely re-synthesized to follow the reading sequence and \"\n\"appearance in the document -- which even establishes the original layout \"\n\"to some extent.\"\nmsgstr \"\"\n\"세로 좌표, 그 다음 가로 좌표로 출력을 정렬합니다. 많은 경우 이것은 \\\"자연스러운\\\" 읽기 순서를 생성하는 데 충분해야 합니다.\"\n\" (X)HTML 및 XML에는 효과가 없습니다. 옵션 \\\"blocks\\\", \\\"dict\\\", \\\"json\\\", \"\n\"\\\"rawdict\\\", \\\"rawjson\\\"의 경우 각 블록 bbox의 좌표 `(y1, x0)` 로 정렬이 수행됩니다. 옵션 \"\n\"\\\"words\\\" 및 \\\"text\\\"의 경우 텍스트 라인은 읽기 순서와 문서의 모양을 따르도록 완전히 재구성됩니다 -- 이것은 어느\"\n\" 정도 원래 레이아웃을 설정합니다.\"\n\n#: ../../page.rst:1441 95a7095bdcfb4738b0dfd00c84103152\nmsgid \"\"\n\"use these characters as *additional* word separators with the \\\"words\\\" \"\n\"output option (ignored otherwise). By default, all white spaces \"\n\"(including non-breaking space `0xA0`) indicate start and end of a word. \"\n\"Now you can specify more characters causing this. For instance, the \"\n\"default will return `\\\"john.doe@outlook.com\\\"` as **one** word. If you \"\n\"specify `delimiters=\\\"@.\\\"` then the **four** words `\\\"john\\\"`, \"\n\"`\\\"doe\\\"`, `\\\"outlook\\\"`, `\\\"com\\\"` will be returned. Other possible uses\"\n\" include ignoring punctuation characters `delimiters=string.punctuation`.\"\n\" The \\\"word\\\" strings will not contain any delimiting character. (New in \"\n\"v1.23.5)\"\nmsgstr \"\"\n\"\\\"words\\\" 출력 옵션과 함께 이러한 문자를 *추가* 단어 구분자로 사용합니다(그렇지 않으면 무시됨). 기본적으로 모든 \"\n\"공백(줄바꿈 없는 공백 `0xA0` 포함)은 단어의 시작과 끝을 나타냅니다. 이제 이것을 유발하는 더 많은 문자를 지정할 수 \"\n\"있습니다. 예를 들어 기본값은 `\\\"john.doe@outlook.com\\\"` 을 **하나의** 단어로 반환합니다. \"\n\"`delimiters=\\\"@.\\\"` 를 지정하면 **네 개의** 단어 `\\\"john\\\"`, `\\\"doe\\\"`, \"\n\"`\\\"outlook\\\"`, `\\\"com\\\"` 이 반환됩니다. 다른 가능한 사용 사례에는 구두점 문자 무시 \"\n\"`delimiters=string.punctuation` 가 포함됩니다. \\\"word\\\" 문자열은 구분 문자를 포함하지 않습니다. \"\n\"(v1.23.5의 새로운 기능)\"\n\n#: ../../page.rst:1443 8a3314318f1347968fec4dd7e161108f\nmsgid \"*str, list, dict*\"\nmsgstr \"*str, list, dict*\"\n\n#: ../../page.rst:1444 2fda8f36df9a4f43b757eb6b210d6ab2\nmsgid \"\"\n\"The page's content as a string, a list or a dictionary. Refer to the \"\n\"corresponding :ref:`TextPage` method for details.\"\nmsgstr \"문자열, 리스트 또는 딕셔너리로 된 페이지의 콘텐츠. 자세한 내용은 해당 :ref:`TextPage` 메서드를 참조하세요.\"\n\n#: ../../page.rst:1448 87cab378dbb54d2bb87074cf1903d401\nmsgid \"\"\n\"You can use this method as a **document conversion tool** from :ref:`any \"\n\"supported document type<Supported_File_Types>` to one of TEXT, HTML, \"\n\"XHTML or XML documents.\"\nmsgstr \"\"\n\"이 메서드를 :ref:`지원되는 모든 문서 타입<Supported_File_Types>` 에서 TEXT, HTML, XHTML 또는\"\n\" XML 문서 중 하나로 변환하는 **문서 변환 도구**로 사용할 수 있습니다.\"\n\n#: ../../page.rst:1449 e2531f96ce69494d982a5c574b459396\nmsgid \"\"\n\"The inclusion of text via the *clip* parameter is decided on a by-\"\n\"character level: a character becomes part of the output, if its bbox is \"\n\"contained in `clip`. This **deviates** from the algorithm used in \"\n\"redaction annotations: a character will be **removed if its bbox \"\n\"intersects** any redaction annotation.\"\nmsgstr \"\"\n\"*clip* 매개변수를 통한 텍스트 포함은 문자 단위로 결정됩니다: 문자의 bbox가 `clip` 에 포함되면 출력의 일부가 \"\n\"됩니다. 이것은 삭제 주석에 사용되는 알고리즘과 **다릅니다**: 문자의 bbox가 삭제 주석과 **교차하면 제거됩니다**.\"\n\n#: ../../page.rst:1453 1b5b49c1fa4c45508811e8eebee7a190\nmsgid \"Changed in v1.19.0: added `textpage` parameter\"\nmsgstr \"v1.19.0에서 변경됨: `textpage` 매개변수 추가\"\n\n#: ../../page.rst:1454 4bffb71bcae845ccbf0a78d24102fcea\nmsgid \"Changed in v1.19.1: added `sort` parameter\"\nmsgstr \"v1.19.1에서 변경됨: `sort` 매개변수 추가\"\n\n#: ../../page.rst:1455 6f58853b7eb84463a9e605cd638cc751\nmsgid \"\"\n\"Changed in v1.19.6: added new constants for defining default flags per \"\n\"method.\"\nmsgstr \"v1.19.6에서 변경됨: 메서드별 기본 플래그를 정의하는 새로운 상수 추가\"\n\n#: ../../page.rst:1456 0d1821e110d644faa8f8986a696207e8\nmsgid \"Changed in v1.23.5: added `delimiters` parameter\"\nmsgstr \"v1.23.5에서 변경됨: `delimiters` 매개변수 추가\"\n\n#: ../../page.rst:1457 b58734a4980841f7a1c1d465c26b3c9b\nmsgid \"\"\n\"Changed in v1.24.11: changed the effect of `sort_True` for \\\"text\\\" and \"\n\"\\\"words\\\" to closely follow natural reading sequence.\"\nmsgstr \"\"\n\"v1.24.11에서 변경됨: \\\"text\\\" 및 \\\"words\\\"에 대한 `sort_True` 의 효과를 자연스러운 읽기 순서를 \"\n\"밀접하게 따르도록 변경.\"\n\n#: ../../page.rst:1467 8c1c27d5f5854a5994c1d79f6640c6de\nmsgid \"Retrieve the text contained in a rectangle.\"\nmsgstr \"사각형에 포함된 텍스트를 검색합니다.\"\n\n#: ../../page.rst:1469 d4911798adf84f2e912f80ea9d7c1fbc\nmsgid \"rect-like.\"\nmsgstr \"사각형과 유사한.\"\n\n#: ../../page.rst:1470 5f6e40c71fb64050acab8309f49fc2b6\nmsgid \"\"\n\"a :ref:`TextPage` to use. If omitted, a new, temporary textpage will be \"\n\"created.\"\nmsgstr \"사용할 :ref:`TextPage`. 생략하면 새로운 임시 textpage가 생성됩니다.\"\n\n#: ../../page.rst:1472 b5d117f42415497f85e0315decf882bf\nmsgid \"\"\n\"a string with interspersed linebreaks where necessary. It is based on \"\n\"dedicated code (changed in v1.19.0). A typical use is checking the result\"\n\" of :meth:`Page.search_for`:  >>> rl = page.search_for(\\\"currency:\\\") >>>\"\n\" page.get_textbox(rl[0]) 'Currency:' >>>\"\nmsgstr \"\"\n\n#: ../../page.rst:1472 aba080f6928a47bca88bf15e82859c44\nmsgid \"\"\n\"a string with interspersed linebreaks where necessary. It is based on \"\n\"dedicated code (changed in v1.19.0). A typical use is checking the result\"\n\" of :meth:`Page.search_for`:\"\nmsgstr \"\"\n\"필요한 경우 줄바꿈이 삽입된 문자열. 전용 코드를 기반으로 합니다(v1.19.0에서 변경됨). 일반적인 사용 사례는 \"\n\":meth:`Page.search_for` 의 결과를 확인하는 것입니다:\"\n\n#: ../../page.rst:1481 1e92c2a6e6f64f00b15bff149f248e54\nmsgid \"New in v1.17.7\"\nmsgstr \"*v1.17.7의 새로운 기능*\"\n\n#: ../../page.rst:1482 4c2cd3bfa050492fbbcfddb097f00283\nmsgid \"Changed in v1.19.0: add `textpage` parameter\"\nmsgstr \"v1.19.0에서 변경됨: `textpage` 매개변수 추가\"\n\n#: ../../page.rst:1493 552c575ac4154ab99a2685db626069af\nmsgid \"Create a :ref:`TextPage` for the page.\"\nmsgstr \"페이지에 대한 :ref:`TextPage` 생성.\"\n\n#: ../../page.rst:1495 72d281381ba448d2a9296634e86b332f\nmsgid \"\"\n\"indicator bits controlling the content available for subsequent text \"\n\"extractions and searches -- see the parameter of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\"후속 텍스트 추출 및 검색에 사용 가능한 콘텐츠를 제어하는 표시기 비트 -- :meth:`Page.get_text` 의 매개변수 \"\n\"참조.\"\n\n#: ../../page.rst:1497 8e6348dea3124d21ab5c024e64c7b109\nmsgid \"restrict extracted text to this area. (New in v1.17.7)\"\nmsgstr \"추출된 텍스트를 이 영역으로 제한합니다. (v1.17.7의 새로운 기능)\"\n\n#: ../../page.rst:1499 a633ba5141524989bc3d06428d2217f4\nmsgid \":ref:`TextPage`\"\nmsgstr \":ref:`TextPage`\"\n\n#: ../../page.rst:1503 e83f608779fa4b60a3a81132844375ef\nmsgid \"New in v1.16.5\"\nmsgstr \"*v1.16.5의 새로운 기능*\"\n\n#: ../../page.rst:1504 808f46c3859f4dcc927e0b0b14281327\nmsgid \"Changed in v1.17.7: introduced `clip` parameter.\"\nmsgstr \"v1.17.7에서 변경됨: `clip` 매개변수 도입.\"\n\n#: ../../page.rst:1518 c70224150c4f475c99d903492862e1bf\nmsgid \"\"\n\"**Optical Character Recognition** (**OCR**) technology can be used to \"\n\"extract text data for documents where text is in a raster image format \"\n\"throughout the page. Use this method to **OCR** a page for text \"\n\"extraction.\"\nmsgstr \"\"\n\"**Optical Character Recognition** (**OCR**) 기술은 페이지 전체에서 텍스트가 래스터 이미지 형식인\"\n\" 문서의 텍스트 데이터를 추출하는 데 사용할 수 있습니다. 텍스트 추출을 위해 페이지를 **OCR** 하려면 이 메서드를 사용하세요.\"\n\n#: ../../page.rst:1520 b7f86ebe9de0435e82db8aa8bc9af4c0\nmsgid \"\"\n\"This method returns a :ref:`TextPage` for the page that includes OCRed \"\n\"text. MuPDF will invoke Tesseract-OCR if this method is used. Otherwise \"\n\"this is a normal :ref:`TextPage` object.\"\nmsgstr \"\"\n\"이 메서드는 OCR된 텍스트를 포함하는 페이지에 대한 :ref:`TextPage` 를 반환합니다. 이 메서드가 사용되면 MuPDF가\"\n\" Tesseract-OCR을 호출합니다. 그렇지 않으면 이것은 일반 :ref:`TextPage` 객체입니다.\"\n\n#: ../../page.rst:1522 1197bedcf2f24b6fa0d282e2118a8337\nmsgid \"\"\n\"indicator bits controlling the content available for subsequent test \"\n\"extractions and searches -- see the parameter of :meth:`Page.get_text`.\"\nmsgstr \"\"\n\"후속 테스트 추출 및 검색에 사용 가능한 콘텐츠를 제어하는 표시기 비트 -- :meth:`Page.get_text` 의 매개변수 \"\n\"참조.\"\n\n#: ../../page.rst:1523 53262d05af364b3da0927c53aa377bac\nmsgid \"\"\n\"the expected language(s). Use \\\"+\\\"-separated values if multiple \"\n\"languages are expected, \\\"eng+spa\\\" for English and Spanish.\"\nmsgstr \"예상되는 언어. 여러 언어가 예상되는 경우 \\\"+\\\"로 구분된 값을 사용하세요. 영어와 스페인어의 경우 \\\"eng+spa\\\".\"\n\n#: ../../page.rst:1524 5f0307e724b8447bb42be06da94e312a\nmsgid \"\"\n\"the desired resolution in dots per inch. Influences recognition quality \"\n\"(and execution time).\"\nmsgstr \"인치당 도트 단위의 원하는 해상도. 인식 품질(및 실행 시간)에 영향을 줍니다.\"\n\n#: ../../page.rst:1525 fe347ff9506f4484a86d5a50d85ca327\nmsgid \"whether to OCR the full page, or just the displayed images.\"\nmsgstr \"전체 페이지를 OCR할지, 아니면 표시된 이미지만 OCR할지 여부.\"\n\n#: ../../page.rst:1526 48120db50bd44e0cae9dc87701c03cf8\nmsgid \"\"\n\"The name of Tesseract's language support folder `tessdata`. If omitted, \"\n\"this information must be present as environment variable \"\n\"`TESSDATA_PREFIX`. Can be determined by function :meth:`get_tessdata`.\"\nmsgstr \"\"\n\"Tesseract의 언어 지원 폴더 `tessdata` 의 이름. 생략하면 이 정보는 환경 변수 `TESSDATA_PREFIX` 로\"\n\" 제공되어야 합니다. 함수 :meth:`get_tessdata` 로 확인할 수 있습니다.\"\n\n#: ../../page.rst:1528 744d4ab2cad04b2b9d6dc62ee518bac5\nmsgid \"\"\n\"This method does **not** support a clip parameter -- OCR will always \"\n\"happen for the complete page rectangle.\"\nmsgstr \"이 메서드는 clip 매개변수를 **지원하지 않습니다** -- OCR은 항상 전체 페이지 사각형에 대해 수행됩니다.\"\n\n#: ../../page.rst:1530 b027240195914e2f9485d94002565eeb\nmsgid \"\"\n\"a :ref:`TextPage`. Execution may be significantly longer than \"\n\":meth:`Page.get_textpage`.  For a full page OCR, **all text** will have \"\n\"the font \\\"GlyphlessFont\\\" from Tesseract. In case of partial OCR, normal\"\n\" text will keep its properties, and only text coming from images will \"\n\"have the GlyphlessFont.  .. note::     **OCRed text is only available** \"\n\"to PyMuPDF's text extractions and searches if their `textpage` parameter \"\n\"specifies the output of this method.     `This Jupyter notebook \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/jupyter-\"\n\"notebooks/partial-ocr.ipynb>`_ walks through an example for using OCR \"\n\"textpages.\"\nmsgstr \"\"\n\n#: ../../page.rst:1532 8596df79de844fbf890ad989700cdbf8\nmsgid \"\"\n\"a :ref:`TextPage`. Execution may be significantly longer than \"\n\":meth:`Page.get_textpage`.\"\nmsgstr \":ref:`TextPage`. 실행 시간이 :meth:`Page.get_textpage` 보다 훨씬 길 수 있습니다.\"\n\n#: ../../page.rst:1534 02474ff2d6f9486199e495d259a676f5\nmsgid \"\"\n\"For a full page OCR, **all text** will have the font \\\"GlyphlessFont\\\" \"\n\"from Tesseract. In case of partial OCR, normal text will keep its \"\n\"properties, and only text coming from images will have the GlyphlessFont.\"\nmsgstr \"\"\n\"전체 페이지 OCR의 경우 **모든 텍스트** 는 Tesseract의 \\\"GlyphlessFont\\\" 글꼴을 가집니다. 부분 OCR의\"\n\" 경우 일반 텍스트는 속성을 유지하고 이미지에서 나온 텍스트만 GlyphlessFont를 가집니다.\"\n\n#: ../../page.rst:1538 c8b06f1ce9c541c0a7dafa1b5983861d\nmsgid \"\"\n\"**OCRed text is only available** to PyMuPDF's text extractions and \"\n\"searches if their `textpage` parameter specifies the output of this \"\n\"method.\"\nmsgstr \"\"\n\"**OCR된 텍스트는** `textpage` 매개변수가 이 메서드의 출력을 지정하는 경우에만 PyMuPDF의 텍스트 추출 및 검색에\"\n\" **사용할 수 있습니다**.\"\n\n#: ../../page.rst:1540 18093ba01d0e4191a8c741c78d6df301\nmsgid \"\"\n\"`This Jupyter notebook <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/jupyter-notebooks/partial-ocr.ipynb>`_ walks \"\n\"through an example for using OCR textpages.\"\nmsgstr \"\"\n\"`이 Jupyter notebook <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/jupyter-notebooks/partial-ocr.ipynb>`_ 은 OCR \"\n\"textpage 사용 예제를 안내합니다.\"\n\n#: ../../page.rst:1544 f40b2fa4b48d4c1d9f4b65fb126edcee\nmsgid \"New in v.1.19.0\"\nmsgstr \"*v.1.19.0의 새로운 기능*\"\n\n#: ../../page.rst:1545 858d61e097fa41d98f177be970cba353\nmsgid \"Changed in v1.19.1: support full and partial OCRing a page.\"\nmsgstr \"v1.19.1에서 변경됨: 전체 및 부분 페이지 OCR 지원.\"\n\n#: ../../page.rst:1552 c7e3ee200beb4ebd990f650366aad171\nmsgid \"\"\n\"Return the vector graphics of the page. These are instructions which draw\"\n\" lines, rectangles, quadruples or curves, including properties like \"\n\"colors, transparency, line width and dashing, etc. Alternative terms are \"\n\"\\\"line art\\\" and \\\"drawings\\\".\"\nmsgstr \"\"\n\"페이지의 벡터 그래픽을 반환합니다. 이것들은 색상, 투명도, 선 너비 및 파선 등의 속성을 포함하여 선, 사각형, 쿼드 또는 곡선을\"\n\" 그리는 명령입니다. 대체 용어는 \\\"line art\\\" 및 \\\"drawings\\\"입니다.\"\n\n#: ../../page.rst:1554 e64e409f6b2e4e45967c8c6aac0bad56\nmsgid \"\"\n\"a list of dictionaries. Each dictionary item contains one or more single \"\n\"draw commands belonging together: they have the same properties (colors, \"\n\"dashing, etc.). This is called a **\\\"path\\\"** in PDF, so we adopted that \"\n\"name here, but the method **works for all document types**.\"\nmsgstr \"\"\n\"딕셔너리 목록. 각 딕셔너리 항목은 함께 속하는 하나 이상의 단일 그리기 명령을 포함합니다: 동일한 속성(색상, 파선 등)을 \"\n\"가집니다. 이것은 PDF에서 **\\\"path\\\"** 라고 하므로 여기서도 그 이름을 채택했지만, 이 메서드는 **모든 문서 타입에 \"\n\"작동합니다**.\"\n\n#: ../../page.rst:1556 c64685bdd45f4d6bb1cc4ff4068e57b8\nmsgid \"\"\n\"The path dictionary for fill, stroke and fill-stroke paths has been \"\n\"designed to be compatible with class :ref:`Shape`. There are the \"\n\"following keys:\"\nmsgstr \"\"\n\"채우기, 스트로크 및 채우기-스트로크 경로에 대한 경로 딕셔너리는 :ref:`Shape` 클래스와 호환되도록 설계되었습니다. 다음 \"\n\"키가 있습니다:\"\n\n#: ../../page.rst:1559 ../../page.rst:1624 ../../page.rst:1639\n#: b7acf7d868cf4e919562977891f0e0a8 ece6a68246ce4a1e8d4c47faf351884a\n#: fba538fc79d041b7a5a06d8e27da9bb0\nmsgid \"Key\"\nmsgstr \"Key\"\n\n#: ../../page.rst:1559 ../../page.rst:1624 ../../page.rst:1639\n#: 79c927222a1d4571bdb27f8d8e581798 e6dd0c648ea44198b141fa2c5ec474b3\n#: f767d8e05516491292593328f8697ddf\nmsgid \"Value\"\nmsgstr \"Value\"\n\n#: ../../page.rst:1561 ../../page.rst:1626 4c9594dfce96479da55c6061fda83ef6\n#: 843fb4f69f1d49b595bddd522a49b6c4\nmsgid \"closePath\"\nmsgstr \"closePath\"\n\n#: ../../page.rst:1561 ../../page.rst:1568 0bb5485c5b154e28a2a94e0c49a7ab0a\n#: c7cccba55c234feaa7691155b39634d6\nmsgid \"Same as the parameter in :ref:`Shape`.\"\nmsgstr \":ref:`Shape` 의 매개변수와 동일합니다.\"\n\n#: ../../page.rst:1562 cd6c9da5bb2e48648ab4f4b6d71a6c41\nmsgid \"color\"\nmsgstr \"color\"\n\n#: ../../page.rst:1562 c5737caae9ff469ab4ba20ae07489a50\nmsgid \"Stroke color (see :ref:`Shape`).\"\nmsgstr \"스트로크 색상(:ref:`Shape` 참조).\"\n\n#: ../../page.rst:1563 28e58c7532c748e1adb3c0d297b18557\nmsgid \"dashes\"\nmsgstr \"dashes\"\n\n#: ../../page.rst:1563 6cb1db9ecb934543b995bd0c188dfa03\nmsgid \"Dashed line specification (see :ref:`Shape`).\"\nmsgstr \"파선 지정(:ref:`Shape` 참조).\"\n\n#: ../../page.rst:1564 ../../page.rst:1627 706378ca44324162b50fc91701ee84f7\n#: e9ee905de99e4ddd970116c9fa0fad74\nmsgid \"even_odd\"\nmsgstr \"even_odd\"\n\n#: ../../page.rst:1564 eb35285c61bf47c585d1b5dee58e4c02\nmsgid \"Fill colors of area overlaps -- same as the parameter in :ref:`Shape`.\"\nmsgstr \"영역 겹침의 채우기 색상 -- :ref:`Shape` 의 매개변수와 동일합니다.\"\n\n#: ../../page.rst:1565 99a00de114ab446aa9a7156f94788754\nmsgid \"fill\"\nmsgstr \"fill\"\n\n#: ../../page.rst:1565 6541ce13a5374cbdb67442b03c85f36d\nmsgid \"Fill color  (see :ref:`Shape`).\"\nmsgstr \"채우기 색상(:ref:`Shape` 참조).\"\n\n#: ../../page.rst:1566 ../../page.rst:1628 19eb2a71eece4c209ac6cce431b7d19a\n#: 704c355822ab4ee48ccde125a6d2b184\nmsgid \"items\"\nmsgstr \"items\"\n\n#: ../../page.rst:1566 101403480b8b4fc5af798c80802bb355\nmsgid \"List of draw commands: lines, rectangles, quads or curves.\"\nmsgstr \"그리기 명령 목록: 선, 사각형, 쿼드 또는 곡선.\"\n\n#: ../../page.rst:1567 4f48840dea424d8aab46a9fb1644b9e4\nmsgid \"lineCap\"\nmsgstr \"lineCap\"\n\n#: ../../page.rst:1567 fb95c6cfd6f243fa8a9b9dc0a63b09e0\nmsgid \"Number 3-tuple, use its max value on output with :ref:`Shape`.\"\nmsgstr \"숫자 3-튜플, :ref:`Shape` 와 함께 출력에서 최대값을 사용합니다.\"\n\n#: ../../page.rst:1568 acf3d1a551de4b9590f034eeb2ad8061\nmsgid \"lineJoin\"\nmsgstr \"lineJoin\"\n\n#: ../../page.rst:1569 ecb4b729c6f84a02ace66afe9859c83a\nmsgid \"fill_opacity\"\nmsgstr \"fill_opacity\"\n\n#: ../../page.rst:1569 6460170cd1cd493f9d8ad754e5297c40\nmsgid \"fill color transparency (see :ref:`Shape`). (New in v1.18.17)\"\nmsgstr \"채우기 색상 투명도(:ref:`Shape` 참조). (v1.18.17의 새로운 기능)\"\n\n#: ../../page.rst:1570 8546e57d8a2c43abb8a56d1bd331730d\nmsgid \"stroke_opacity\"\nmsgstr \"stroke_opacity\"\n\n#: ../../page.rst:1570 0ff66e45b59f416f99cb0024bb1b4eac\nmsgid \"stroke color transparency  (see :ref:`Shape`). (New in v1.18.17)\"\nmsgstr \"스트로크 색상 투명도(:ref:`Shape` 참조). (v1.18.17의 새로운 기능)\"\n\n#: ../../page.rst:1571 ../../page.rst:1629 ../../page.rst:1641\n#: 32f0c4257df14fbb958c30e8bb8f68ce 500b3e541eb346279410ebffce76e99d\n#: 5c7836fd4fe34492864c89d3aef88790\nmsgid \"rect\"\nmsgstr \"rect\"\n\n#: ../../page.rst:1571 f5c0b4887e6c4e228c4d85da9010cecc\nmsgid \"Page area covered by this path. Information only.\"\nmsgstr \"이 경로가 덮는 페이지 영역. 정보 전용.\"\n\n#: ../../page.rst:1572 ../../page.rst:1630 ../../page.rst:1642\n#: 82477c93961a4598b9ea0b648398124b 9dfc21d0511d4abbb95020a4c71d2271\n#: bf797b35be6e474ba09ca35ab1b39d05\nmsgid \"layer\"\nmsgstr \"layer\"\n\n#: ../../page.rst:1572 867c9e86f09a436ba115aef39ad31ab0\nmsgid \"name of applicable Optional Content Group. (New in v1.22.0)\"\nmsgstr \"적용 가능한 Optional Content Group의 이름. (v1.22.0의 새로운 기능)\"\n\n#: ../../page.rst:1573 ../../page.rst:1631 ../../page.rst:1643\n#: 6e87d742adac4eeba4b6ddd2e8c5532b ce3a5ce2557648dba228a50d2558c061\n#: d0c7e717c97f47cba2ae7c8e2e5af826\nmsgid \"level\"\nmsgstr \"level\"\n\n#: ../../page.rst:1573 aa84b0143529449f8c76b7f0a885b57f\nmsgid \"the hierarchy level if `extended=True`. (New in v1.22.0)\"\nmsgstr \"`extended=True` 인 경우 계층 수준. (v1.22.0의 새로운 기능)\"\n\n#: ../../page.rst:1574 8fc72f3067ca49c4b5b8ec07b54be1c4\nmsgid \"seqno\"\nmsgstr \"seqno\"\n\n#: ../../page.rst:1574 894fd6dd16084fbcb60d629693392547\nmsgid \"command number when building page appearance. (New in v1.19.0)\"\nmsgstr \"페이지 외관을 구축할 때의 명령 번호. (v1.19.0의 새로운 기능)\"\n\n#: ../../page.rst ../../page.rst:1575 ../../page.rst:1633 ../../page.rst:1648\n#: 1fcf757d5dc541d5b3c245d404f73971 20beaee05d194b39b0960d58cecaa93d\n#: 20d5bfd89a42452389d2b3de105004ed 289aced190834f9aa3f7297df81e881e\n#: 2ecf513d3d1d4620a6bd5e1704cfae53 313cd7811c254a20b0514620e173e142\n#: 3b4a71bc2b6148d8be69dc3c70b28e8b 3e570725d89c40db969ad8ebd9bb872d\n#: 42f7acc537fe442c890faba8fd0a5500 44a6bae233764069898e0a55d210a796\n#: 4cfc1480829f48caa473096b2001366c 51a13afa13134b1e814761ce1621369f\n#: 5568b527ff7e45e8b2f583d5f9316d40 59049d73b92545138bdab078af040e1b\n#: 5abe8e3967544950afd9cd7f69e59e37 5f1f0d672a014ca0b2ed58406a5d4302\n#: 5fe9177dd10c4af5ac4fd6d2875144fa 6c479020153047cdbcec75b1f3d90cf2\n#: 7379336f93474e5499eb57d5b9be1b13 886f1301616a47c2a6710633e38e37c2\n#: 89f932d46f3d4b3995682f63b4da6de7 8f9fc672a9bd4fcda41795c11dbb497d\n#: 9112052403704fe3b81a0bf9fef5dab2 9921eb0cfe194c5a86ec7378a612c5e6\n#: 9a2c7607c85348538a85de2db7812879 9a4cfd70928c496f95f0f44eb37acc97\n#: 9bdb2311c124404fae2717faeaa735c7 9fd560313114481fade1548731517884\n#: bc324c734eb1402894e706a42a4c5800 bea09940c9364903ae6b2360dc99567a\n#: bf3f44de2eaa416d883bdb5f1fa99d8f fc0d5d5d24f04d50b0e0e7baa40516ce\n#: fcb92524976849ef90a307fcfe9bd81f\nmsgid \"type\"\nmsgstr \"type\"\n\n#: ../../page.rst:1575 663d54e871934888839844320dc3fdc3\nmsgid \"type of this path. (New in v1.18.17)\"\nmsgstr \"이 경로의 타입. (v1.18.17의 새로운 기능)\"\n\n#: ../../page.rst:1576 ../../page.rst:1719 768f3fc5fb3346bca72ce0b3e0e4a400\n#: abba61c9f8ec49aca51e36f10c201119\nmsgid \"width\"\nmsgstr \"width\"\n\n#: ../../page.rst:1576 2347d6fa83164607b86cd8a23552840b\nmsgid \"Stroke line width. (see :ref:`Shape`).\"\nmsgstr \"스트로크 선 너비. (:ref:`Shape` 참조).\"\n\n#: ../../page.rst:1579 0e51042f7f9649dca6e5ca7c2cde0605\nmsgid \"\"\n\"Key `\\\"opacity\\\"` has been replaced by the new keys `\\\"fill_opacity\\\"` \"\n\"and `\\\"stroke_opacity\\\"`. This is now compatible with the corresponding \"\n\"parameters of :meth:`Shape.finish`. (Changed in v1.18.17)\"\nmsgstr \"\"\n\"키 `\\\"opacity\\\"` 는 새로운 키 `\\\"fill_opacity\\\"` 및 `\\\"stroke_opacity\\\"` 로 \"\n\"대체되었습니다. 이것은 이제 :meth:`Shape.finish` 의 해당 매개변수와 호환됩니다. (v1.18.17에서 변경됨)\"\n\n#: ../../page.rst:1582 8609140c98474ef3abd9a14ace738246\nmsgid \"\"\n\"For paths other than groups or clips, key `\\\"type\\\"` takes one of the \"\n\"following values:\"\nmsgstr \"그룹 또는 클립이 아닌 경로의 경우 키 `\\\"type\\\"` 은 다음 값 중 하나를 가집니다:\"\n\n#: ../../page.rst:1584 cf5d23e35b004933ad6ecf65c9afd033\nmsgid \"\"\n\"**\\\"f\\\"** -- this is a *fill-only* path. Only key-values relevant for \"\n\"this operation have a meaning, not applicable ones are present with a \"\n\"value of ``None``: `\\\"color\\\"`, `\\\"lineCap\\\"`, `\\\"lineJoin\\\"`, \"\n\"`\\\"width\\\"`, `\\\"closePath\\\"`, `\\\"dashes\\\"` and should be ignored.\"\nmsgstr \"\"\n\"**\\\"f\\\"** -- 이것은 *채우기 전용* 경로입니다. 이 작업과 관련된 키-값만 의미가 있으며, 적용할 수 없는 항목은 \"\n\"``None`` 값으로 존재합니다: `\\\"color\\\"`, `\\\"lineCap\\\"`, `\\\"lineJoin\\\"`, \"\n\"`\\\"width\\\"`, `\\\"closePath\\\"`, `\\\"dashes\\\"` 이며 무시해야 합니다.\"\n\n#: ../../page.rst:1585 9c71c83b86054b5bbbd736289eb7042d\nmsgid \"\"\n\"**\\\"s\\\"** -- this is a *stroke-only* path. Similar to previous, key \"\n\"`\\\"fill\\\"` is present with value ``None``.\"\nmsgstr \"\"\n\"**\\\"s\\\"** -- 이것은 *스트로크 전용* 경로입니다. 이전과 유사하게 키 `\\\"fill\\\"` 은 ``None`` 값으로 \"\n\"존재합니다.\"\n\n#: ../../page.rst:1586 097c57e6361e4b2988f97f7007ed0569\nmsgid \"\"\n\"**\\\"fs\\\"** -- this is a path performing combined *fill* and *stroke* \"\n\"operations.\"\nmsgstr \"**\\\"fs\\\"** -- 이것은 결합된 *채우기* 및 *스트로크* 작업을 수행하는 경로입니다.\"\n\n#: ../../page.rst:1588 6c78504d072b453d9fd91f2f1a82caec\nmsgid \"Each item in `path[\\\"items\\\"]` is one of the following:\"\nmsgstr \"`path[\\\"items\\\"]` 의 각 항목은 다음 중 하나입니다:\"\n\n#: ../../page.rst:1590 56e18decb23a451494b4e90318ae5b7e\nmsgid \"`(\\\"l\\\", p1, p2)` - a line from p1 to p2 (:ref:`Point` objects).\"\nmsgstr \"`(\\\"l\\\", p1, p2)` - p1에서 p2로의 선(:ref:`Point` 객체).\"\n\n#: ../../page.rst:1591 26a9972343024dccba36c7e3cd84fcc7\nmsgid \"\"\n\"`(\\\"c\\\", p1, p2, p3, p4)` - cubic Bézier curve **from p1 to p4** (p2 and \"\n\"p3 are the control points). All objects are of type :ref:`Point`.\"\nmsgstr \"\"\n\"`(\\\"c\\\", p1, p2, p3, p4)` - **p1에서 p4로의** 3차 Bézier 곡선(p2 및 p3는 제어점). 모든 \"\n\"객체는 :ref:`Point` 타입입니다.\"\n\n#: ../../page.rst:1592 cdb458944b544837b6fddaef13bf8c3a\nmsgid \"\"\n\"`(\\\"re\\\", rect, orientation)` - a :ref:`Rect`. Multiple rectangles within\"\n\" the same path are now detected (changed in v1.18.17). Integer \"\n\"`orientation` is 1 resp. -1 indicating whether the enclosed area is \"\n\"rotated left (1 = anti-clockwise), or resp. right [#f7]_ (changed in \"\n\"v1.19.2).\"\nmsgstr \"\"\n\"`(\\\"re\\\", rect, orientation)` - :ref:`Rect`. 동일한 경로 내의 여러 사각형이 이제 \"\n\"감지됩니다(v1.18.17에서 변경됨). 정수 `orientation` 은 1 또는 -1로, 둘러싸인 영역이 왼쪽으로 회전(1 = \"\n\"반시계 방향) 또는 오른쪽으로 회전하는지 나타냅니다 [#f7]_ (v1.19.2에서 변경됨).\"\n\n#: ../../page.rst:1593 9c1e4bcf66af446ab5d2a70eff677956\nmsgid \"\"\n\"`(\\\"qu\\\", quad)` - a :ref:`Quad`. 3 or 4 consecutive lines are detected \"\n\"to actually represent a :ref:`Quad` (changed in v1.19.2:). (New in \"\n\"v1.18.17)\"\nmsgstr \"\"\n\"`(\\\"qu\\\", quad)` - :ref:`Quad`. 3개 또는 4개의 연속 선이 실제로 :ref:`Quad` 를 나타내는 \"\n\"것으로 감지됩니다(v1.19.2에서 변경됨). (v1.18.17의 새로운 기능)\"\n\n#: ../../page.rst:1597 d845d91d1f81456fb5e9d7652704f931\nmsgid \"\"\n\"Using class :ref:`Shape`, you should be able to recreate the original \"\n\"drawings on a separate (PDF) page with high fidelity under normal, not \"\n\"too sophisticated circumstances. Please see the following comments on \"\n\"restrictions. A coding draft can be found in :ref:`How to Extract \"\n\"Drawings <RecipesDrawingAndGraphics_Extract_Drawings>`.\"\nmsgstr \"\"\n\":ref:`Shape` 클래스를 사용하면 일반적이고 너무 복잡하지 않은 상황에서 별도의 (PDF) 페이지에서 원본 그림을 높은 \"\n\"충실도로 재현할 수 있어야 합니다. 제한 사항에 대한 다음 주석을 참조하세요. 코딩 초안은 :ref:`How to Extract \"\n\"Drawings <RecipesDrawingAndGraphics_Extract_Drawings>` 에서 찾을 수 있습니다.\"\n\n#: ../../page.rst:1599 131db0437b06494f8659f8d73a40a8c9\nmsgid \"\"\n\"Specifying `extended=True` significantly alters the output. Most \"\n\"importantly, new dictionary types are present: \\\"clip\\\" and \\\"group\\\". \"\n\"All paths will now be organized in a hierarchic structure which is \"\n\"encoded by the new integer key \\\"level\\\", the hierarchy level. Each group\"\n\" or clip establishes a new hierarchy, which applies to all subsequent \"\n\"paths having a *larger* level value. (New in v1.22.0)\"\nmsgstr \"\"\n\"`extended=True` 를 지정하면 출력이 크게 변경됩니다. 가장 중요한 것은 새로운 딕셔너리 타입 \\\"clip\\\" 및 \"\n\"\\\"group\\\"이 존재한다는 것입니다. 모든 경로는 이제 계층 수준인 새로운 정수 키 \\\"level\\\"로 인코딩된 계층 구조로 \"\n\"구성됩니다. 각 그룹 또는 클립은 *더 큰* level 값을 가진 모든 후속 경로에 적용되는 새로운 계층을 설정합니다. \"\n\"(v1.22.0의 새로운 기능)\"\n\n#: ../../page.rst:1601 a847cd281b91455c956e6fe1153f9c9c\nmsgid \"\"\n\"Any path with a smaller level value than its predecessor will end the \"\n\"scope of (at least) the preceding hierarchy level. A \\\"clip\\\" path with \"\n\"the same level as the preceding clip will end the scope of that clip. \"\n\"Same is true for groups. This is best explained by an example::\"\nmsgstr \"\"\n\"이전 항목보다 작은 level 값을 가진 경로는 (최소한) 이전 계층 수준의 범위를 종료합니다. 이전 클립과 동일한 level을 \"\n\"가진 \\\"clip\\\" 경로는 해당 클립의 범위를 종료합니다. 그룹에도 동일하게 적용됩니다. 이것은 예제로 가장 잘 설명됩니다::\"\n\n#: ../../page.rst:1617 1aa3c13c698047e4af893cc4e640e9b4\nmsgid \"\"\n\"The clip in line 0 applies to line including line 7. Group in line 2 \"\n\"applies to lines 3 to 5, clip in line 3 only applies to line 4.\"\nmsgstr \"\"\n\"라인 0의 클립은 라인 7을 포함한 라인에 적용됩니다. 라인 2의 그룹은 라인 3부터 5까지에 적용되고, 라인 3의 클립은 라인 \"\n\"4에만 적용됩니다.\"\n\n#: ../../page.rst:1619 f2517520385341e8a656b8fbb2657ae6\nmsgid \"\"\n\"\\\"stroke\\\" in line 4 is under control of \\\"group\\\" in line 2 and \\\"clip\\\"\"\n\" in line 3 (which in turn is a subset of line 0 clip).\"\nmsgstr \"\"\n\"라인 4의 \\\"stroke\\\"는 라인 2의 \\\"group\\\"과 라인 3의 \\\"clip\\\"(차례로 라인 0 클립의 하위 집합)의 제어\"\n\" 하에 있습니다.\"\n\n#: ../../page.rst:1621 cbf97a7250774947a89a1404e176d5c5\nmsgid \"\"\n\"**\\\"clip\\\"** dictionary. Its values (most importantly \\\"scissor\\\") remain\"\n\" valid / apply as long as following dictionaries have a **larger \"\n\"\\\"level\\\"** value.\"\nmsgstr \"\"\n\"**\\\"clip\\\"** 딕셔너리. 후속 딕셔너리가 **더 큰 \\\"level\\\"** 값을 가진 한 그 값(가장 중요한 \"\n\"\\\"scissor\\\")은 유효/적용됩니다.\"\n\n#: ../../page.rst:1626 ../../page.rst:1627 ../../page.rst:1628\n#: ../../page.rst:1629 ../../page.rst:1630 ../../page.rst:1631\n#: ../../page.rst:1641 ../../page.rst:1642 ../../page.rst:1643\n#: 1d3909e3e75348fa82996235f70385dd 57cdd8b09dda41a1be3654cc9daffec3\n#: 7744821b23f14be28b550932b2158f41 93007be0b3bb4f049a25aff49f06da4e\n#: adda1d05909c4d118797b72d75bacab2 d6adb320f0ec4789a9418a9212a5ac3c\n#: de27d4095ca643cc8e3d1a5b21d78819 ded3d9d6901d4d59817a7ef07fd5a8b3\n#: fe445f13f9734edbaa9eaffd432d9c7e\nmsgid \"Same as in \\\"stroke\\\" or \\\"fill\\\" dictionaries\"\nmsgstr \"\\\"stroke\\\" 또는 \\\"fill\\\" 딕셔너리와 동일\"\n\n#: ../../page.rst:1632 a56abf057dd543c49e547c92066afd44\nmsgid \"scissor\"\nmsgstr \"scissor\"\n\n#: ../../page.rst:1632 31b078ca7ed643e08dd038a1d1f44a6c\nmsgid \"the clip rectangle\"\nmsgstr \"클립 사각형\"\n\n#: ../../page.rst:1633 555c0fc188544a68a0b9c5249e003147\nmsgid \"\\\"clip\\\"\"\nmsgstr \"\\\"clip\\\"\"\n\n#: ../../page.rst:1636 1950d3a1cd754711892e66f62f30d488\nmsgid \"\"\n\"\\\"group\\\" dictionary. Its values remain valid (apply) as long as \"\n\"following dictionaries have a **larger \\\"level\\\"** value. Any dictionary \"\n\"with an equal or lower level end this group.\"\nmsgstr \"\"\n\"\\\"group\\\" 딕셔너리. 후속 딕셔너리가 **더 큰 \\\"level\\\"** 값을 가진 한 그 값은 유효(적용)합니다. 동일하거나 \"\n\"더 낮은 level을 가진 딕셔너리는 이 그룹을 종료합니다.\"\n\n#: ../../page.rst:1644 205fddf2363247ce8151b0d3c364035a\nmsgid \"isolated\"\nmsgstr \"isolated\"\n\n#: ../../page.rst:1644 4d9971e178344c82b26136d679c1ed5d\nmsgid \"(bool) Whether this group is isolated\"\nmsgstr \"(bool) 이 그룹이 격리되었는지 여부\"\n\n#: ../../page.rst:1645 f6ee5e635f9b474e9d1f122ce4045f11\nmsgid \"knockout\"\nmsgstr \"knockout\"\n\n#: ../../page.rst:1645 32061236f29c4751935dd10ede5114c9\nmsgid \"(bool) Whether this is a \\\"Knockout Group\\\"\"\nmsgstr \"(bool) 이것이 \\\"Knockout Group\\\"인지 여부\"\n\n#: ../../page.rst:1646 f9ac0094769243c595cd920e319682f7\nmsgid \"blendmode\"\nmsgstr \"blendmode\"\n\n#: ../../page.rst:1646 d691ceffb0944ac1afcd60cc67f3892a\nmsgid \"Name of the BlendMode, default is \\\"Normal\\\"\"\nmsgstr \"BlendMode의 이름, 기본값은 \\\"Normal\\\"\"\n\n#: ../../page.rst:1647 3fb054893e63424a844e9c3d4c9c088c\nmsgid \"opacity\"\nmsgstr \"opacity\"\n\n#: ../../page.rst:1647 e9e6e02283ef4c8cb769e2becd44a466\nmsgid \"Float value in range [0, 1].\"\nmsgstr \"[0, 1] 범위의 Float 값.\"\n\n#: ../../page.rst:1648 f82a36b717e0488f991404211027f96e\nmsgid \"\\\"group\\\"\"\nmsgstr \"\\\"group\\\"\"\n\n#: ../../page.rst:1651 37a68dc01e0d46e6a14acafe5c1d16ef\nmsgid \"\"\n\"The method is based on the output of :meth:`Page.get_cdrawings` -- which \"\n\"is much faster, but requires somewhat more attention processing its \"\n\"output.\"\nmsgstr \"\"\n\"이 메서드는 :meth:`Page.get_cdrawings` 의 출력을 기반으로 합니다 -- 이것은 훨씬 빠르지만 출력을 처리하는 \"\n\"데 다소 더 많은 주의가 필요합니다.\"\n\n#: ../../page.rst:1655 fc64101d9ee84ff59a3146a7a201220c\nmsgid \"New in v1.18.0\"\nmsgstr \"*v1.18.0의 새로운 기능*\"\n\n#: ../../page.rst:1656 c4d86369f98a403e9d867af9a58910a4\nmsgid \"Changed in v1.18.17\"\nmsgstr \"v1.18.17에서 변경됨\"\n\n#: ../../page.rst:1657 486c4617151845d3876e6f5f3b2088e9\nmsgid \"Changed in v1.19.0: add \\\"seqno\\\" key, remove \\\"clippings\\\" key\"\nmsgstr \"v1.19.0에서 변경됨: \\\"seqno\\\" 키 추가, \\\"clippings\\\" 키 제거\"\n\n#: ../../page.rst:1658 8bed595ac0a34c9cbbba1c5221e9bba5\nmsgid \"\"\n\"Changed in v1.19.1: \\\"color\\\" / \\\"fill\\\" keys now always are either are \"\n\"RGB tuples or `None`. This resolves issues caused by exotic colorspaces.\"\nmsgstr \"\"\n\"v1.19.1에서 변경됨: \\\"color\\\" / \\\"fill\\\" 키는 이제 항상 RGB 튜플이거나 `None` 입니다. 이것은 \"\n\"이국적인 색 공간으로 인한 문제를 해결합니다.\"\n\n#: ../../page.rst:1659 14b87c784ae24c81b897e2234cb96159\nmsgid \"\"\n\"Changed in v1.19.2: add an indicator for the *\\\"orientation\\\"* of the \"\n\"area covered by an \\\"re\\\" item.\"\nmsgstr \"v1.19.2에서 변경됨: \\\"re\\\" 항목이 덮는 영역의 *\\\"orientation\\\"* 에 대한 표시기 추가.\"\n\n#: ../../page.rst:1660 62afbaadfd244d41b02c5d43cfd713e7\nmsgid \"\"\n\"Changed in v1.22.0: add new key `\\\"layer\\\"` which contains the name of \"\n\"the Optional Content Group of the path (or `None`).\"\nmsgstr \"\"\n\"v1.22.0에서 변경됨: 경로의 Optional Content Group 이름(또는 `None`)을 포함하는 새로운 키 \"\n\"`\\\"layer\\\"` 추가.\"\n\n#: ../../page.rst:1661 b9a447c651b94fb3bd9cca432d23bb15\nmsgid \"\"\n\"Changed in v1.22.0: add parameter `extended` to also return clipping and \"\n\"group paths.\"\nmsgstr \"v1.22.0에서 변경됨: 클리핑 및 그룹 경로도 반환하도록 `extended` 매개변수 추가.\"\n\n#: ../../page.rst:1669 3702a72bddbe4940aa9306ff4d7c30f8\nmsgid \"\"\n\"Extract the vector graphics on the page. Apart from following technical \"\n\"differences, functionally equivalent to :meth:`Page.get_drawings`, but \"\n\"much faster:\"\nmsgstr \"\"\n\"페이지의 벡터 그래픽을 추출합니다. 다음 기술적 차이점을 제외하고는 :meth:`Page.get_drawings` 와 기능적으로 \"\n\"동일하지만 훨씬 빠릅니다:\"\n\n#: ../../page.rst:1671 860f6d110f37411399848976d173538b\nmsgid \"\"\n\"Every path type only contains the relevant keys, e.g. a stroke path has \"\n\"no `\\\"fill\\\"` color key. See comment in method :meth:`Page.get_drawings`.\"\nmsgstr \"\"\n\"각 경로 타입은 관련 키만 포함합니다. 예를 들어 stroke 경로에는 `\\\"fill\\\"` 색상 키가 없습니다. \"\n\":meth:`Page.get_drawings` 메서드의 주석을 참조하세요.\"\n\n#: ../../page.rst:1672 6ca768cd73e945298dd50f23c476cc09\nmsgid \"\"\n\"Coordinates are given as :data:`point_like`, :data:`rect_like` and \"\n\":data:`quad_like` **tuples** -- not as :ref:`Point`, :ref:`Rect`, \"\n\":ref:`Quad` objects.\"\nmsgstr \"\"\n\"좌표는 :ref:`Point`, :ref:`Rect`, :ref:`Quad` 객체가 아닌 :data:`point_like`, \"\n\":data:`rect_like`, :data:`quad_like` **튜플** 로 제공됩니다.\"\n\n#: ../../page.rst:1674 42538119b5214715ad10ceec147d9c59\nmsgid \"\"\n\"If performance is a concern, consider using this method: Compared to \"\n\"versions earlier than 1.18.17, you should see much shorter response \"\n\"times. We have seen pages that required 2 seconds then, now only need 200\"\n\" ms with this method.\"\nmsgstr \"\"\n\"성능이 중요한 경우 이 메서드 사용을 고려하세요: 1.18.17 이전 버전과 비교하여 응답 시간이 훨씬 짧아집니다. 이전에 2초가 \"\n\"걸렸던 페이지가 이 메서드로는 200ms만 필요합니다.\"\n\n#: ../../page.rst:1678 bdf91fd7b086456e9d858e5763582a3e\nmsgid \"New in v1.18.17\"\nmsgstr \"*v1.18.17의 새로운 기능*\"\n\n#: ../../page.rst:1679 fb1be55a4b15435884e4d3701791875b\nmsgid \"Changed in v1.19.0: removed \\\"clippings\\\" key, added \\\"seqno\\\" key.\"\nmsgstr \"v1.19.0에서 변경됨: \\\"clippings\\\" 키 제거, \\\"seqno\\\" 키 추가.\"\n\n#: ../../page.rst:1680 6807369fdc33422da5d63cc3a4bfc0d9\nmsgid \"Changed in v1.19.1: always generate RGB color tuples.\"\nmsgstr \"v1.19.1에서 변경됨: 항상 RGB 색상 튜플 생성.\"\n\n#: ../../page.rst:1681 00e1646f78aa4bc8a41fdee57e4b747e\nmsgid \"\"\n\"Changed in v1.22.0: added new key `\\\"layer\\\"` which contains the name of \"\n\"the Optional Content Group of the path (or `None`).\"\nmsgstr \"\"\n\"v1.22.0에서 변경됨: 경로의 Optional Content Group 이름(또는 `None`)을 포함하는 새로운 키 \"\n\"`\\\"layer\\\"` 추가.\"\n\n#: ../../page.rst:1682 3f2c083b24a94aaf9b53114c1dabadaa\nmsgid \"\"\n\"Changed in v1.22.0: added parameter `extended` to also return clipping \"\n\"paths.\"\nmsgstr \"v1.22.0에서 변경됨: 클리핑 경로도 반환하도록 `extended` 매개변수 추가.\"\n\n#: ../../page.rst:1689 0173b2bb8cf94466b53746921fdd8f08\nmsgid \"\"\n\"PDF only: Return a list of fonts referenced by the page. Wrapper for \"\n\":meth:`Document.get_page_fonts`.\"\nmsgstr \"PDF 전용: 페이지에서 참조하는 글꼴 목록을 반환합니다. :meth:`Document.get_page_fonts` 의 래퍼입니다.\"\n\n#: ../../page.rst:1694 37f4c0b79c1d4a10b3525052d6da0dfb\nmsgid \"\"\n\"PDF only: Return a list of images referenced by the page. Wrapper for \"\n\":meth:`Document.get_page_images`.\"\nmsgstr \"\"\n\"PDF 전용: 페이지에서 참조하는 이미지 목록을 반환합니다. :meth:`Document.get_page_images` 의 \"\n\"래퍼입니다.\"\n\n#: ../../page.rst:1703 52268d5050814eeb85f48b722493807b\nmsgid \"\"\n\"Return a list of meta information dictionaries for all images displayed \"\n\"by the page. This works for all document types.\"\nmsgstr \"페이지에 표시된 모든 이미지에 대한 메타 정보 딕셔너리 목록을 반환합니다. 모든 문서 타입에서 작동합니다.\"\n\n#: ../../page.rst:1705 5008c3cdcdc54d49a2fe35f1cbe8e76d\nmsgid \"\"\n\"Compute the MD5 hashcode for each encountered image, which allows \"\n\"identifying image duplicates. This adds the key `\\\"digest\\\"` to the \"\n\"output, whose value is a 16 byte `bytes` object. (New in v1.18.13)\"\nmsgstr \"\"\n\"발견된 각 이미지의 MD5 해시코드를 계산하여 이미지 중복을 식별할 수 있습니다. 이것은 출력에 키 `\\\"digest\\\"` 를 \"\n\"추가하며, 그 값은 16바이트 `bytes` 객체입니다. (v1.18.13의 새로운 기능)\"\n\n#: ../../page.rst:1707 ea3214183b3a4c46b58190bd2bb70da3\nmsgid \"\"\n\"**PDF only.** Try to find the :data:`xref` for each image. Implies \"\n\"`hashes=True`. Adds the `\\\"xref\\\"` key to the dictionary. If not found, \"\n\"the value is 0, which means, the image is either \\\"inline\\\" or its xref \"\n\"is undetectable for some reason. Please note that this option has an \"\n\"extended response time, because the MD5 hashcode will be computed at \"\n\"least two times for each image with an xref. (New in v1.18.13)\"\nmsgstr \"\"\n\"**PDF 전용.** 각 이미지의 :data:`xref` 를 찾으려고 시도합니다. `hashes=True` 를 의미합니다. \"\n\"딕셔너리에 `\\\"xref\\\"` 키를 추가합니다. 찾을 수 없으면 값은 0이며, 이는 이미지가 \\\"inline\\\"이거나 어떤 이유로 \"\n\"xref를 감지할 수 없음을 의미합니다. xref가 있는 각 이미지에 대해 MD5 해시코드가 최소 두 번 계산되므로 이 옵션은 응답\"\n\" 시간이 길어집니다. (v1.18.13의 새로운 기능)\"\n\n#: ../../page.rst:1710 144394c817d34fd49b7e0f8720e7cea2\nmsgid \"\"\n\"A list of dictionaries. This includes information for **exactly those** \"\n\"images, that are shown on the page -- including *\\\"inline images\\\"*. The \"\n\"dictionary layout is similar to that of image blocks in \"\n\"`page.get_text(\\\"dict\\\")`.  In contrast to images included in \"\n\":meth:`Page.get_text`, image **binary content** is not loaded by this \"\n\"method, which drastically reduces memory usage. Another difference is \"\n\"that image detection is not restricted to the visible part of the page or\"\n\" any ``clip`` parameter: method :meth:`Page.get_text` will only extract \"\n\"images **fully contained** in the provided ``clip``.  =============== \"\n\"=============================================================== **Key**\"\n\"             **Value** =============== \"\n\"=============================================================== number\"\n\"          block number (``int``) bbox            image bbox on page, \"\n\":data:`rect_like` width           original image width (``int``) height\"\n\"          original image height (``int``) cs-name         colorspace name\"\n\" (``str``) colorspace      colorspace.n (``int``) xres            \"\n\"resolution in x-direction (``int``) [#f10]_ yres            resolution in\"\n\" y-direction (``int``) [#f10]_ bpc             bits per component \"\n\"(``int``) size            storage occupied by image (``int``) digest\"\n\"          MD5 hashcode (``bytes``), if ``hashes`` is true xref\"\n\"            image :data:`xref` or 0, if *xrefs* is true transform       \"\n\"matrix transforming image rect to bbox, :data:`matrix_like` has-mask\"\n\"        whether the image is transparent and has a mask (``bool``) \"\n\"=============== \"\n\"===============================================================  Multiple\"\n\" occurrences of the same image are always reported. You can detect \"\n\"duplicates by comparing their `digest` values.\"\nmsgstr \"동일한 이미지의 여러 발생은 항상 보고됩니다. `digest` 값을 비교하여 중복을 감지할 수 있습니다.\"\n\n#: ../../page.rst:1710 1b149b16c2b34b64bda0baefddcecb55\nmsgid \"\"\n\"A list of dictionaries. This includes information for **exactly those** \"\n\"images, that are shown on the page -- including *\\\"inline images\\\"*. The \"\n\"dictionary layout is similar to that of image blocks in \"\n\"`page.get_text(\\\"dict\\\")`.\"\nmsgstr \"\"\n\"딕셔너리 목록. 페이지에 표시된 **정확히 그** 이미지들에 대한 정보를 포함합니다 -- *\\\"inline images\\\"* 를 \"\n\"포함합니다. 딕셔너리 레이아웃은 `page.get_text(\\\"dict\\\")` 의 이미지 블록과 유사합니다.\"\n\n#: ../../page.rst:1712 5a27b15d2c204dab8360ff85856af7a5\nmsgid \"\"\n\"In contrast to images included in :meth:`Page.get_text`, image **binary \"\n\"content** is not loaded by this method, which drastically reduces memory \"\n\"usage. Another difference is that image detection is not restricted to \"\n\"the visible part of the page or any ``clip`` parameter: method \"\n\":meth:`Page.get_text` will only extract images **fully contained** in the\"\n\" provided ``clip``.\"\nmsgstr \"\"\n\":meth:`Page.get_text` 에 포함된 이미지와 달리 이 메서드는 이미지 **바이너리 콘텐츠**를 로드하지 않아 메모리 \"\n\"사용량이 크게 줄어듭니다. 또 다른 차이점은 이미지 감지가 페이지의 보이는 부분이나 ``clip`` 매개변수로 제한되지 않는다는 \"\n\"것입니다: :meth:`Page.get_text` 메서드는 제공된 ``clip`` 에 **완전히 포함된** 이미지만 추출합니다.\"\n\n#: ../../page.rst:1715 0b394a9a1cdd432781e149c3892753fd\nmsgid \"**Key**\"\nmsgstr \"**키**\"\n\n#: ../../page.rst:1715 fbef0bc7bd0342239e371f8a09466df1\nmsgid \"**Value**\"\nmsgstr \"**값**\"\n\n#: ../../page.rst:1717 b0f3e604fffb45edb60c2725c31d2ee8\nmsgid \"number\"\nmsgstr \"\"\n\n#: ../../page.rst:1717 0c9af015fefa4419821b69772c75b33e\nmsgid \"block number (``int``)\"\nmsgstr \"블록 번호 (``int``)\"\n\n#: ../../page.rst:1718 4f3a3d19faaf424191cfbea0cc3d3c5a\nmsgid \"bbox\"\nmsgstr \"\"\n\n#: ../../page.rst:1718 584a470c5b8b46c9a03d901abd20de42\nmsgid \"image bbox on page, :data:`rect_like`\"\nmsgstr \"페이지의 이미지 bbox, :data:`rect_like`\"\n\n#: ../../page.rst:1719 6e03ad7f1d6545d09b272ee9b0a60e5d\nmsgid \"original image width (``int``)\"\nmsgstr \"원본 이미지 너비 (``int``)\"\n\n#: ../../page.rst:1720 1aa4ad67a68e4a0eb3b1fa083bf0b326\nmsgid \"height\"\nmsgstr \"\"\n\n#: ../../page.rst:1720 f123e5d62ef44992981d5268e71fa568\nmsgid \"original image height (``int``)\"\nmsgstr \"원본 이미지 높이 (``int``)\"\n\n#: ../../page.rst:1721 daea98d42fac49ae934ef380b1a9153e\nmsgid \"cs-name\"\nmsgstr \"\"\n\n#: ../../page.rst:1721 4f2bab526d8748728ececdba28117ef1\nmsgid \"colorspace name (``str``)\"\nmsgstr \"색 공간 이름 (``str``)\"\n\n#: ../../page.rst:1722 8e5b4fa8b6ac4501b3d7714920a97883\nmsgid \"colorspace\"\nmsgstr \"\"\n\n#: ../../page.rst:1722 28ca4c918d30488c91e6d3e9d3974ba1\nmsgid \"colorspace.n (``int``)\"\nmsgstr \"colorspace.n (``int``)\"\n\n#: ../../page.rst:1723 f7bce3d563f84da19c5a1c3d651a71a1\nmsgid \"xres\"\nmsgstr \"\"\n\n#: ../../page.rst:1723 c698d13249ff4c299622cbf37b33668f\nmsgid \"resolution in x-direction (``int``) [#f10]_\"\nmsgstr \"x 방향 해상도 (``int``) [#f10]_\"\n\n#: ../../page.rst:1724 c5e49fb54a5d4c2abd64840944490fd2\nmsgid \"yres\"\nmsgstr \"\"\n\n#: ../../page.rst:1724 40ea45169c4349899787a90365f53c29\nmsgid \"resolution in y-direction (``int``) [#f10]_\"\nmsgstr \"y 방향 해상도 (``int``) [#f10]_\"\n\n#: ../../page.rst:1725 8322aa0afc5e44408915f7d1a8fcfbdd\nmsgid \"bpc\"\nmsgstr \"\"\n\n#: ../../page.rst:1725 b139da1626704293b366bae2a66fbc56\nmsgid \"bits per component (``int``)\"\nmsgstr \"컴포넌트당 비트 수 (``int``)\"\n\n#: ../../page.rst:1726 edb0973ea574451f875f61b6d70b6fdd\nmsgid \"size\"\nmsgstr \"\"\n\n#: ../../page.rst:1726 92b8e55576b74c20b3f763586e41392c\nmsgid \"storage occupied by image (``int``)\"\nmsgstr \"이미지가 차지하는 저장 공간 (``int``)\"\n\n#: ../../page.rst:1727 07c63cf3e2674d9a8879a1606ad72801\nmsgid \"digest\"\nmsgstr \"\"\n\n#: ../../page.rst:1727 32f2d2022f344bf2bb7956c636e31b1c\nmsgid \"MD5 hashcode (``bytes``), if ``hashes`` is true\"\nmsgstr \"MD5 해시코드 (``bytes``), ``hashes`` 가 true인 경우\"\n\n#: ../../page.rst:1728 9d32331677b648f184a4f3736354bca0\nmsgid \"xref\"\nmsgstr \"\"\n\n#: ../../page.rst:1728 d76fdfd8145041c1b583291078929259\nmsgid \"image :data:`xref` or 0, if *xrefs* is true\"\nmsgstr \"이미지 :data:`xref` 또는 0, *xrefs* 가 true인 경우\"\n\n#: ../../page.rst:1729 1461121625d34ebfa9284f03a0e98873\nmsgid \"transform\"\nmsgstr \"\"\n\n#: ../../page.rst:1729 0180d00af39a43f78b605b04aa54009c\nmsgid \"matrix transforming image rect to bbox, :data:`matrix_like`\"\nmsgstr \"이미지 rect를 bbox로 변환하는 행렬, :data:`matrix_like`\"\n\n#: ../../page.rst:1730 0c574adc2af64b0082e9d605d1cf94ea\nmsgid \"has-mask\"\nmsgstr \"\"\n\n#: ../../page.rst:1730 8d6fa2cf1c0f46b191e21be7fc3cccac\nmsgid \"whether the image is transparent and has a mask (``bool``)\"\nmsgstr \"이미지가 투명하고 마스크가 있는지 여부 (``bool``)\"\n\n#: ../../page.rst:1733 35794dcd87894fcdbc9d7a463e5775c0\nmsgid \"\"\n\"Multiple occurrences of the same image are always reported. You can \"\n\"detect duplicates by comparing their `digest` values.\"\nmsgstr \"동일한 이미지의 여러 발생이 항상 보고됩니다. `digest` 값을 비교하여 중복을 감지할 수 있습니다.\"\n\n#: ../../page.rst:1737 1f46b5881eef4542b3f758f817cf98e0\nmsgid \"New in v1.18.11\"\nmsgstr \"*v1.18.11의 새로운 기능*\"\n\n#: ../../page.rst:1738 c6046c345f124938ac809f67ec47f2ea\nmsgid \"\"\n\"Changed in v1.18.13: added image MD5 hashcode computation and \"\n\":data:`xref` search.\"\nmsgstr \"v1.18.13에서 변경됨: 이미지 MD5 해시코드 계산 및 :data:`xref` 검색 추가.\"\n\n#: ../../page.rst:1745 2819a626e264435b8e422de9b6396ad5\nmsgid \"\"\n\"PDF only: Return a list of Form XObjects referenced by the page. Wrapper \"\n\"for :meth:`Document.get_page_xobjects`.\"\nmsgstr \"\"\n\"PDF 전용: 페이지에서 참조하는 Form XObjects 목록을 반환합니다. \"\n\":meth:`Document.get_page_xobjects` 의 래퍼입니다.\"\n\n#: ../../page.rst:1753 99a5532742734003b2bf616307a32998\nmsgid \"\"\n\"PDF only: Return boundary boxes and transformation matrices of an \"\n\"embedded image. This is an improved version of \"\n\":meth:`Page.get_image_bbox` with the following differences:\"\nmsgstr \"\"\n\"PDF 전용: 삽입된 이미지의 경계 상자와 변환 행렬을 반환합니다. 다음 차이점이 있는 \"\n\":meth:`Page.get_image_bbox` 의 개선된 버전입니다:\"\n\n#: ../../page.rst:1755 ac2fcb7261e34635ad4c75ac12af1689\nmsgid \"\"\n\"There is no restriction on **how** the image is invoked (by the page or \"\n\"one of its Form XObjects). The result is always complete and correct.\"\nmsgstr \"\"\n\"이미지가 **어떻게** 호출되는지(페이지 또는 Form XObjects 중 하나)에 대한 제한이 없습니다. 결과는 항상 완전하고 \"\n\"정확합니다.\"\n\n#: ../../page.rst:1756 3c14d4fb99444135be6811cc8cb07f01\nmsgid \"\"\n\"The result is a list of :ref:`Rect` or (:ref:`Rect`, :ref:`Matrix`) \"\n\"objects -- depending on *transform*. Each list item represents one \"\n\"location of the image on the page. Multiple occurrences might not be \"\n\"detectable by :meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\"결과는 *transform* 에 따라 :ref:`Rect` 또는 (:ref:`Rect`, :ref:`Matrix`) 객체 \"\n\"목록입니다. 각 목록 항목은 페이지에서 이미지의 한 위치를 나타냅니다. 여러 발생은 \"\n\":meth:`Page.get_image_bbox` 로 감지되지 않을 수 있습니다.\"\n\n#: ../../page.rst:1757 3ce396dfb45643b3a2b577396cbfc42a\nmsgid \"\"\n\"The method invokes :meth:`Page.get_image_info` with `xrefs=True` and \"\n\"therefore has a noticeably longer response time than \"\n\":meth:`Page.get_image_bbox`.\"\nmsgstr \"\"\n\"이 메서드는 `xrefs=True` 로 :meth:`Page.get_image_info` 를 호출하므로 \"\n\":meth:`Page.get_image_bbox` 보다 응답 시간이 현저히 깁니다.\"\n\n#: ../../page.rst:1759 104a2121204c4e679a4de6d7aebc23b6\nmsgid \"\"\n\"an item of the list :meth:`Page.get_images`, or the reference **name** \"\n\"entry of such an item (item[7]), or the image :data:`xref`.\"\nmsgstr \"\"\n\":meth:`Page.get_images` 목록의 항목, 또는 해당 항목의 참조 **이름** 항목(item[7]), 또는 이미지 \"\n\":data:`xref`.\"\n\n#: ../../page.rst:1760 97231250d677409c8bcf7f2e5b7be63a\nmsgid \"\"\n\"also return the matrix used to transform the image rectangle to the bbox \"\n\"on the page. If true, then tuples `(bbox, matrix)` are returned.\"\nmsgstr \"\"\n\"이미지 사각형을 페이지의 bbox로 변환하는 데 사용된 행렬도 반환합니다. true이면 튜플 `(bbox, matrix)` 가 \"\n\"반환됩니다.\"\n\n#: ../../page.rst:1763 02c01da8966543a7bd985e5bfd3a23fa\nmsgid \"\"\n\"Boundary boxes and respective transformation matrices for each image \"\n\"occurrence on the page. If the item is not on the page, an empty list \"\n\"`[]` is returned.\"\nmsgstr \"페이지에서 각 이미지 발생에 대한 경계 상자 및 해당 변환 행렬. 항목이 페이지에 없으면 빈 목록 `[]` 이 반환됩니다.\"\n\n#: ../../page.rst:1767 333b89c3033a4043b0372cfe8b568924\nmsgid \"New in v1.18.13\"\nmsgstr \"*v1.18.13의 새로운 기능*\"\n\n#: ../../page.rst:1777 e17c11e271f84b1fa49d8f8a2bb401a4\nmsgid \"\"\n\"PDF only: Return boundary box and transformation matrix of an embedded \"\n\"image.\"\nmsgstr \"PDF 전용: 삽입된 이미지의 경계 상자와 변환 행렬을 반환합니다.\"\n\n#: ../../page.rst:1779 7312ee6f43d64176b708a9703bc38617\nmsgid \"\"\n\"an item of the list :meth:`Page.get_images` with *full=True* specified, \"\n\"or the reference **name** entry of such an item, which is item[-3] (or \"\n\"item[7] respectively).\"\nmsgstr \"\"\n\"*full=True* 로 지정된 :meth:`Page.get_images` 목록의 항목, 또는 해당 항목의 참조 **이름** \"\n\"항목(item[-3] 또는 각각 item[7]).\"\n\n#: ../../page.rst:1780 81977283103f4a54a537b6a7cdb91386\nmsgid \"\"\n\"return the matrix used to transform the image rectangle to the bbox on \"\n\"the page (new in v1.18.11). Default is just the bbox. If true, then a \"\n\"tuple `(bbox, matrix)` is returned.\"\nmsgstr \"\"\n\"이미지 사각형을 페이지의 bbox로 변환하는 데 사용된 행렬을 반환합니다(v1.18.11의 새로운 기능). 기본값은 \"\n\"bbox만입니다. true이면 튜플 `(bbox, matrix)` 가 반환됩니다.\"\n\n#: ../../page.rst:1782 4cc559e506564f04af020bd45227abbd\nmsgid \":ref:`Rect` or (:ref:`Rect`, :ref:`Matrix`)\"\nmsgstr \"\"\n\n#: ../../page.rst:1783 6eb9d4bf86fc4298ba39e61874715631\nmsgid \"\"\n\"the boundary box of the image -- optionally also its transformation \"\n\"matrix.\"\nmsgstr \"\"\n\n#: ../../page.rst:1783 d317d7767fdf4baca1a1c48080281ae3\nmsgid \"\"\n\"the boundary box of the image -- optionally also its transformation \"\n\"matrix.\"\nmsgstr \"이미지의 경계 상자 -- 선택적으로 변환 행렬도 포함.\"\n\n#: ../../page.rst:1787 ea294faeab98449baaa5f2d6bac06e57\nmsgid \"\"\n\"(Changed in v1.16.7): If the page in fact does not display this image, an\"\n\" infinite rectangle is returned now. In previous versions, an exception \"\n\"was raised. Formally invalid parameters still raise exceptions.\"\nmsgstr \"\"\n\"(v1.16.7에서 변경됨): 페이지가 실제로 이 이미지를 표시하지 않는 경우 이제 무한 사각형이 반환됩니다. 이전 버전에서는 \"\n\"예외가 발생했습니다. 형식적으로 잘못된 매개변수는 여전히 예외를 발생시킵니다.\"\n\n#: ../../page.rst:1788 6af68f0315014685ad95f51cd9f03005\nmsgid \"\"\n\"(Changed in v1.17.0): Only images referenced directly by the page are \"\n\"considered. This means that images occurring in embedded PDF pages are \"\n\"ignored and an exception is raised.\"\nmsgstr \"\"\n\"(v1.17.0에서 변경됨): 페이지에서 직접 참조하는 이미지만 고려됩니다. 이것은 삽입된 PDF 페이지에 있는 이미지는 무시되고 \"\n\"예외가 발생함을 의미합니다.\"\n\n#: ../../page.rst:1789 59689223bb4d404b86fed8d5c6db1aaa\nmsgid \"\"\n\"(Changed in v1.18.5): Removed the restriction introduced in v1.17.0: any \"\n\"item of the page's image list may be specified.\"\nmsgstr \"(v1.18.5에서 변경됨): v1.17.0에서 도입된 제한 제거: 페이지의 이미지 목록의 모든 항목을 지정할 수 있습니다.\"\n\n#: ../../page.rst:1790 2c61d167570646d493cf66b7da9b6b44\nmsgid \"\"\n\"(Changed in v1.18.11): Partially re-instated a restriction: only those \"\n\"images are considered, that are either directly referenced by the page or\"\n\" by a Form XObject directly referenced by the page.\"\nmsgstr \"\"\n\"(v1.18.11에서 변경됨): 제한을 부분적으로 재도입: 페이지에서 직접 참조하거나 페이지에서 직접 참조하는 Form \"\n\"XObject에서 참조하는 이미지만 고려됩니다.\"\n\n#: ../../page.rst:1791 e2997fe9aa3040cb9ee18cffaaf7f009\nmsgid \"\"\n\"(Changed in v1.18.11): Optionally also return the transformation matrix \"\n\"together with the bbox as the tuple `(bbox, transform)`.\"\nmsgstr \"(v1.18.11에서 변경됨): 선택적으로 bbox와 함께 변환 행렬을 튜플 `(bbox, transform)` 로 반환합니다.\"\n\n#: ../../page.rst:1797 8cc9d1b6e96c4e90b2c12d9b92e6b283\nmsgid \"\"\n\"Be aware that :meth:`Page.get_images` may contain \\\"dead\\\" entries i.e. \"\n\"images, which the page **does not display**. This is no error, but \"\n\"intended by the PDF creator. No exception will be raised in this case, \"\n\"but an infinite rectangle is returned. You can avoid this from happening \"\n\"by executing :meth:`Page.clean_contents` before this method.\"\nmsgstr \"\"\n\":meth:`Page.get_images` 가 페이지가 **표시하지 않는** 이미지인 \\\"dead\\\" 항목을 포함할 수 있음을 \"\n\"알아두세요. 이것은 오류가 아니라 PDF 작성자의 의도입니다. 이 경우 예외가 발생하지 않지만 무한 사각형이 반환됩니다. 이 메서드\"\n\" 전에 :meth:`Page.clean_contents` 를 실행하여 이를 방지할 수 있습니다.\"\n\n#: ../../page.rst:1798 83a69e80b429439cbdd9dd466683df78\nmsgid \"\"\n\"The image's \\\"transformation matrix\\\" is defined as the matrix, for which\"\n\" the expression `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` is true, \"\n\"lookup details here: :ref:`ImageTransformation`.\"\nmsgstr \"\"\n\"이미지의 \\\"변환 행렬\\\"은 표현식 `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` 이 참인 \"\n\"행렬로 정의됩니다. 자세한 내용은 :ref:`ImageTransformation` 을 참조하세요.\"\n\n#: ../../page.rst:1802 349415b87ba948dd997d3d87247095ac\nmsgid \"Changed in v1.18.11: return image transformation matrix\"\nmsgstr \"v1.18.11에서 변경됨: 이미지 변환 행렬 반환\"\n\n#: ../../page.rst:1811 89bb43ebfacf40f980640179a3aff7f6\nmsgid \"\"\n\"Create an SVG image from the page. Only full page images are currently \"\n\"supported.\"\nmsgstr \"페이지에서 SVG 이미지를 생성합니다. 현재는 전체 페이지 이미지만 지원됩니다.\"\n\n#: ../../page.rst:1813 e4a43470f94740d08b51e1ba9f3a160c\nmsgid \"a matrix, default is :ref:`Identity`.\"\nmsgstr \"행렬, 기본값은 :ref:`Identity` 입니다.\"\n\n#: ../../page.rst:1814 b2f8ee55a2d84526b05eb09a944cad18\nmsgid \"\"\n\"-- controls how text is represented. ``True`` outputs each character as a\"\n\" series of elementary draw commands, which leads to a more precise text \"\n\"display in browsers, but a **very much larger** output for text-oriented \"\n\"pages. Display quality for ``False`` relies on the presence of the \"\n\"referenced fonts on the current system. For missing fonts, the internet \"\n\"browser will fall back to some default -- leading to unpleasant \"\n\"appearances. Choose ``False`` if you want to parse the text of the SVG. \"\n\"(New in v1.17.5)\"\nmsgstr \"\"\n\"-- 텍스트 표현 방식을 제어합니다. ``True`` 는 각 문자를 기본 그리기 명령 시리즈로 출력하여 브라우저에서 더 정확한 \"\n\"텍스트 표시를 제공하지만 텍스트 중심 페이지의 경우 **훨씬 더 큰** 출력을 생성합니다. ``False`` 의 표시 품질은 현재 \"\n\"시스템에 참조된 글꼴의 존재에 의존합니다. 글꼴이 없으면 인터넷 브라우저가 일부 기본값으로 대체되어 불쾌한 외관을 유발합니다. \"\n\"SVG의 텍스트를 구문 분석하려면 ``False`` 를 선택하세요. (v1.17.5의 새로운 기능)\"\n\n#: ../../page.rst:1816 dbc1c9ccf13c42fcb9ce7eac13c202a9\nmsgid \"\"\n\"a UTF-8 encoded string that contains the image. Because SVG has XML \"\n\"syntax it can be saved in a text file, the standard extension is `.svg`.\"\n\"  .. note:: In case of a PDF, you can circumvent the \\\"full page image \"\n\"only\\\" restriction by modifying the page's CropBox before using the \"\n\"method.\"\nmsgstr \"\"\n\n#: ../../page.rst:1816 dee19b2cc5804be0a5d0340c5e05cf46\nmsgid \"\"\n\"a UTF-8 encoded string that contains the image. Because SVG has XML \"\n\"syntax it can be saved in a text file, the standard extension is `.svg`.\"\nmsgstr \"\"\n\"이미지를 포함하는 UTF-8 인코딩 문자열. SVG는 XML 구문을 사용하므로 텍스트 파일로 저장할 수 있으며, 표준 확장자는 \"\n\"`.svg` 입니다.\"\n\n#: ../../page.rst:1818 092cf93cd26a4b0b87d883e43675530d\nmsgid \"\"\n\"In case of a PDF, you can circumvent the \\\"full page image only\\\" \"\n\"restriction by modifying the page's CropBox before using the method.\"\nmsgstr \"PDF의 경우 메서드를 사용하기 전에 페이지의 CropBox를 수정하여 \\\"전체 페이지 이미지만\\\" 제한을 우회할 수 있습니다.\"\n\n#: ../../page.rst:1830 1f0c1497189a433ebf3ba7729b8ca199\nmsgid \"\"\n\"Create a pixmap from the page. This is probably the most often used \"\n\"method to create a :ref:`Pixmap`.\"\nmsgstr \"페이지에서 픽스맵을 생성합니다. 이것은 아마도 :ref:`Pixmap` 을 생성하는 가장 자주 사용되는 메서드입니다.\"\n\n#: ../../page.rst:1832 e9365773d87b437ba06039e6f437c934\nmsgid \"All parameters are *keyword-only.*\"\nmsgstr \"모든 매개변수는 *키워드 전용* 입니다.\"\n\n#: ../../page.rst:1834 bbfd358ca8034538866437eaff12e0e9\nmsgid \"default is :ref:`Identity`.\"\nmsgstr \"기본값은 :ref:`Identity` 입니다.\"\n\n#: ../../page.rst:1835 fbc68083e7894692808b9aa63a89724a\nmsgid \"\"\n\"desired resolution in x and y direction. If not `None`, the `\\\"matrix\\\"` \"\n\"parameter is ignored. (New in v1.19.2)\"\nmsgstr \"\"\n\"x 및 y 방향의 원하는 해상도. `None` 이 아니면 `\\\"matrix\\\"` 매개변수가 무시됩니다. (v1.19.2의 새로운 \"\n\"기능)\"\n\n#: ../../page.rst:1836 4a9e415f557241c79a1f84a5cc8cb7be\nmsgid \"\"\n\"The desired colorspace, one of \\\"GRAY\\\", \\\"RGB\\\" or \\\"CMYK\\\" (case \"\n\"insensitive). Or specify a :ref:`Colorspace`, ie. one of the predefined \"\n\"ones: :data:`csGRAY`, :data:`csRGB` or :data:`csCMYK`.\"\nmsgstr \"\"\n\"원하는 색 공간, \\\"GRAY\\\", \\\"RGB\\\" 또는 \\\"CMYK\\\" 중 하나(대소문자 구분 안 함). 또는 \"\n\":ref:`Colorspace` 를 지정하세요. 즉, 미리 정의된 것 중 하나: :data:`csGRAY`, \"\n\":data:`csRGB` 또는 :data:`csCMYK`.\"\n\n#: ../../page.rst:1838 cc13400f2cb743308a15fa123c832e82\nmsgid \"\"\n\"restrict rendering to the intersection of this area with the page's \"\n\"rectangle.\"\nmsgstr \"이 영역과 페이지 사각형의 교집합으로 렌더링을 제한합니다.\"\n\n#: ../../page.rst:1839 2cf313f7866e4e80ab402ff06c875c12\n#, python-format\nmsgid \"\"\n\"whether to add an alpha channel. Always accept the default ``False`` if \"\n\"you do not really need transparency. This will save a lot of memory (25% \"\n\"in case of RGB ... and pixmaps are typically **large**!), and also \"\n\"processing time. Also note an **important difference** in how the image \"\n\"will be rendered: with ``True`` the pixmap's samples area will be pre-\"\n\"cleared with *0x00*. This results in **transparent** areas where the page\"\n\" is empty. With ``False`` the pixmap's samples will be pre-cleared with \"\n\"*0xff*. This results in **white** where the page has nothing to show.  \"\n\"|history_begin|  Changed in v1.14.17   The default alpha value is now \"\n\"``False``.    * Generated with *alpha=True*    .. image:: images/img-\"\n\"alpha-1.*     * Generated with *alpha=False*    .. image:: images/img-\"\n\"alpha-0.*  |history_end|\"\nmsgstr \"\"\n\n#: ../../page.rst:1839 cc267dfe2643423ba3c71fc24479a19e\n#, python-format\nmsgid \"\"\n\"whether to add an alpha channel. Always accept the default ``False`` if \"\n\"you do not really need transparency. This will save a lot of memory (25% \"\n\"in case of RGB ... and pixmaps are typically **large**!), and also \"\n\"processing time. Also note an **important difference** in how the image \"\n\"will be rendered: with ``True`` the pixmap's samples area will be pre-\"\n\"cleared with *0x00*. This results in **transparent** areas where the page\"\n\" is empty. With ``False`` the pixmap's samples will be pre-cleared with \"\n\"*0xff*. This results in **white** where the page has nothing to show.\"\nmsgstr \"\"\n\"알파 채널을 추가할지 여부. 투명도가 실제로 필요하지 않으면 항상 기본값 ``False`` 를 수락하세요. 이것은 많은 \"\n\"메모리(RGB의 경우 25% ... 그리고 픽스맵은 일반적으로 **큽니다** !)와 처리 시간을 절약합니다. 또한 이미지가 \"\n\"렌더링되는 방식의 **중요한 차이점** 을 참고하세요: ``True`` 로 픽스맵의 샘플 영역은 *0x00* 으로 미리 지워집니다.\"\n\" 이것은 페이지가 비어 있는 곳에 **투명한** 영역을 만듭니다. ``False`` 로 픽스맵의 샘플은 *0xff* 로 미리 \"\n\"지워집니다. 이것은 페이지에 표시할 것이 없을 때 **흰색** 을 만듭니다.\"\n\n#: ../../page.rst:1853 ca4d0cff8b1c49f59d012366959158d7\nmsgid \"Changed in v1.14.17\"\nmsgstr \"v1.14.17에서 변경됨\"\n\n#: ../../page.rst:1844 4ddc731a0e3f4ed9bb960db44fcba835\nmsgid \"The default alpha value is now ``False``.\"\nmsgstr \"기본 알파 값은 이제 ``False`` 입니다.\"\n\n#: ../../page.rst:1846 dc3ac4805cad4db386110c93785c573e\nmsgid \"Generated with *alpha=True*\"\nmsgstr \"*alpha=True* 로 생성됨\"\n\n#: ../../page.rst:1851 80c272dddfea433ba4a5e07661cff5c0\nmsgid \"Generated with *alpha=False*\"\nmsgstr \"*alpha=False* 로 생성됨\"\n\n#: ../../page.rst:1857 3eee36d56ce44e4db1a3cf72e9875331\nmsgid \"\"\n\"*(new in version 1.16.0)* whether to also render annotations or to \"\n\"suppress them. You can create pixmaps for annotations separately.\"\nmsgstr \"*(버전 1.16.0의 새로운 기능)* 주석도 렌더링할지 아니면 억제할지 여부. 주석에 대한 픽스맵을 별도로 생성할 수 있습니다.\"\n\n#: ../../page.rst:1859 a3b15c577a5c4ef3ad45e3c8fca36117\nmsgid \":ref:`Pixmap`\"\nmsgstr \":ref:`Pixmap`\"\n\n#: ../../page.rst:1860 95a5a19a18a4444a8d23700d99f3c342\nmsgid \"\"\n\"Pixmap of the page. For fine-controlling the generated image, the by far \"\n\"most important parameter is **matrix**. E.g. you can increase or decrease\"\n\" the image resolution by using **Matrix(xzoom, yzoom)**. If zoom > 1, you\"\n\" will get a higher resolution: zoom=2 will double the number of pixels in\"\n\" that direction and thus generate a 2 times larger image. Non-positive \"\n\"values will flip horizontally, resp. vertically. Similarly, matrices also\"\n\" let you rotate or shear, and you can combine effects via e.g. matrix \"\n\"multiplication. See the :ref:`Matrix` section to learn more.\"\nmsgstr \"\"\n\"페이지의 픽스맵. 생성된 이미지를 세밀하게 제어하려면 가장 중요한 매개변수는 **matrix** 입니다. 예를 들어 \"\n\"**Matrix(xzoom, yzoom)** 를 사용하여 이미지 해상도를 높이거나 낮출 수 있습니다. zoom > 1이면 더 높은 \"\n\"해상도를 얻습니다: zoom=2는 해당 방향의 픽셀 수를 두 배로 하여 2배 큰 이미지를 생성합니다. 음수가 아닌 값은 각각 수평 \"\n\"또는 수직으로 뒤집습니다. 마찬가지로 행렬을 사용하여 회전하거나 기울일 수 있으며, 예를 들어 행렬 곱셈을 통해 효과를 결합할 수 \"\n\"있습니다. 자세한 내용은 :ref:`Matrix` 섹션을 참조하세요.\"\n\n#: ../../page.rst:1864 ba1441832f284645bcb0cd0256d76dad\nmsgid \"\"\n\"The pixmap will have *\\\"premultiplied\\\"* pixels if `alpha=True`. To learn\"\n\" about some background, e.g. look for \\\"Premultiplied alpha\\\" `here \"\n\"<https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\"\nmsgstr \"\"\n\"`alpha=True` 이면 픽스맵은 *\\\"premultiplied\\\"* 픽셀을 가집니다. 배경에 대한 자세한 내용은 예를 들어 \"\n\"`여기 <https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_ 에서 \"\n\"\\\"Premultiplied alpha\\\"를 찾아보세요.\"\n\n#: ../../page.rst:1866 5ca95bd389a94565be97e23e53935c11\nmsgid \"\"\n\"The method will respect any page rotation and will not exceed the \"\n\"intersection of `clip` and :attr:`Page.cropbox`. If you need the page's \"\n\"mediabox (and if this is a different rectangle), you can use a snippet \"\n\"like the following to achieve this::\"\nmsgstr \"\"\n\"이 메서드는 모든 페이지 회전을 존중하며 `clip` 과 :attr:`Page.cropbox` 의 교집합을 초과하지 않습니다. \"\n\"페이지의 mediabox가 필요한 경우(그리고 이것이 다른 사각형인 경우) 다음과 같은 스니펫을 사용하여 이를 달성할 수 \"\n\"있습니다::\"\n\n#: ../../page.rst:1884 b9a7af8fd114451789f6475d6d413ca8\nmsgid \"Changed in v1.19.2: added support of parameter dpi.\"\nmsgstr \"v1.19.2에서 변경됨: dpi 매개변수 지원 추가.\"\n\n#: ../../page.rst:1892 d38e45c9eb4d45188627dee99647e6b5\nmsgid \"\"\n\"PDF only: return a list of the names of annotations, widgets and links. \"\n\"Technically, these are the */NM* values of every PDF object found in the \"\n\"page's */Annots*  array.\"\nmsgstr \"\"\n\"PDF 전용: 주석, 위젯 및 링크의 이름 목록을 반환합니다. 기술적으로 이것들은 페이지의 */Annots* 배열에서 찾은 모든 \"\n\"PDF 객체의 */NM* 값입니다.\"\n\n#: ../../page.rst:1898 4c2d49dd3d9b4a57ba7cd7543d83679a\nmsgid \"New in v1.16.10\"\nmsgstr \"v1.16.10의 새로운 기능\"\n\n#: ../../page.rst:1905 43b0e664a184459f8f46ced9df2e4d67\nmsgid \"\"\n\"PDF only: return a list of the :data:`xref` numbers of annotations, \"\n\"widgets and links -- technically of all entries found in the page's \"\n\"*/Annots*  array.\"\nmsgstr \"\"\n\"PDF 전용: 주석, 위젯 및 링크의 :data:`xref` 번호 목록을 반환합니다 -- 기술적으로 페이지의 */Annots* \"\n\"배열에서 찾은 모든 항목입니다.\"\n\n#: ../../page.rst:1908 2589ec16e1d545bc804053c44f660fd6\nmsgid \"\"\n\"a list of items *(xref, type)* where type is the annotation type. Use the\"\n\" type to tell apart links, fields and annotations, see \"\n\":ref:`AnnotationTypes`.\"\nmsgstr \"\"\n\"항목 *(xref, type)* 의 목록으로, type은 주석 타입입니다. 타입을 사용하여 링크, 필드 및 주석을 구분하세요. \"\n\":ref:`AnnotationTypes` 참조.\"\n\n#: ../../page.rst:1912 ../../page.rst:1930 265a6dff70594e58bc37576ebd86d1c4\n#: ea22dac92d4e4deba79fc23ace95019a\nmsgid \"New in v1.17.1\"\nmsgstr \"v1.17.1의 새로운 기능\"\n\n#: ../../page.rst:1919 b8c4c4f249b24a629d3b0554f81f71c8\nmsgid \"\"\n\"PDF only: return the annotation identified by *ident*. This may be its \"\n\"unique name (PDF `/NM` key), or its :data:`xref`.\"\nmsgstr \"\"\n\"PDF 전용: *ident* 로 식별된 주석을 반환합니다. 이것은 고유 이름(PDF `/NM` 키) 또는 :data:`xref` 일\"\n\" 수 있습니다.\"\n\n#: ../../page.rst:1921 99d103647d654aa99112b1f2df5fd5e1\nmsgid \"the annotation name or xref.\"\nmsgstr \"주석 이름 또는 xref.\"\n\n#: ../../page.rst:1924 308e3cdaa90a43228e0fff6141198c14\nmsgid \"the annotation or ``None``.\"\nmsgstr \"주석 또는 ``None``.\"\n\n#: ../../page.rst:1926 44c7aaf1a962484ab7df2f56b74b4bf1\nmsgid \"\"\n\"Methods :meth:`Page.annot_names`, :meth:`Page.annot_xrefs` provide lists \"\n\"of names or xrefs, respectively, from where an item may be picked and \"\n\"loaded via this method.\"\nmsgstr \"\"\n\":meth:`Page.annot_names`, :meth:`Page.annot_xrefs` 메서드는 각각 이름 또는 xref 목록을\"\n\" 제공하며, 여기서 항목을 선택하여 이 메서드를 통해 로드할 수 있습니다.\"\n\n#: ../../page.rst:1936 fd10fefbee7c437f8c7b6cf0f981510a\nmsgid \"PDF only: return the field identified by :data:`xref`.\"\nmsgstr \"PDF 전용: :data:`xref` 로 식별된 필드를 반환합니다.\"\n\n#: ../../page.rst:1938 58524de2ecc046d59b68a2c709c3271a\nmsgid \"the field's xref.\"\nmsgstr \"필드의 xref.\"\n\n#: ../../page.rst:1941 381b8423209541b7a3d58b8a6ec5db9f\nmsgid \"the field or ``None``.\"\nmsgstr \"필드 또는 ``None``.\"\n\n#: ../../page.rst:1943 4063b13ef0374b37b8d55e04944132ff\nmsgid \"\"\n\"This is similar to the analogous method :meth:`Page.load_annot` -- except\"\n\" that here only the xref is supported as identifier.\"\nmsgstr \"\"\n\"이것은 유사한 메서드 :meth:`Page.load_annot` 와 유사합니다 -- 여기서는 xref만 식별자로 지원된다는 점을 \"\n\"제외하고.\"\n\n#: ../../page.rst:1947 0438cdbc2ea6414c95089b9e09c4ceb9\nmsgid \"New in v1.19.6\"\nmsgstr \"v1.19.6의 새로운 기능\"\n\n#: ../../page.rst:1953 b6f74196aeee4aacb3f2fd74011a5976\nmsgid \"Return the first link on a page. Synonym of property :attr:`first_link`.\"\nmsgstr \"페이지의 첫 번째 링크를 반환합니다. 속성 :attr:`first_link` 의 동의어입니다.\"\n\n#: ../../page.rst:1955 ../../page.rst:2252 62cca066e58a4a0ab79f7377e948f7c3\n#: d31c53af7516446089fd6f651872dcff\nmsgid \":ref:`Link`\"\nmsgstr \":ref:`Link`\"\n\n#: ../../page.rst:1956 4fb357ed0a6846cda5965057b49118d2\nmsgid \"first link on the page (or ``None``).\"\nmsgstr \"페이지의 첫 번째 링크(또는 ``None``).\"\n\n#: ../../page.rst:1963 6e189460d0b4477dbf6f24a618d34e32\nmsgid \"PDF only: Set the rotation of the page.\"\nmsgstr \"PDF 전용: 페이지의 회전을 설정합니다.\"\n\n#: ../../page.rst:1965 b1f53a50a11149e5b93cd14e3b018bb8\nmsgid \"\"\n\"An integer specifying the required rotation in degrees. Must be an \"\n\"integer multiple of 90. Values will be converted to one of 0, 90, 180, \"\n\"270.\"\nmsgstr \"필요한 회전을 도 단위로 지정하는 정수. 90의 정수 배수여야 합니다. 값은 0, 90, 180, 270 중 하나로 변환됩니다.\"\n\n#: ../../page.rst:1969 652124939d40408f83082ee8d73b98f6\nmsgid \"PDF only: Change the colorspace components of all objects on page.\"\nmsgstr \"PDF 전용: 페이지의 모든 객체의 색 공간 컴포넌트를 변경합니다.\"\n\n#: ../../page.rst:1971 4bb3cbbc9e6a4173bba15172194856ef\nmsgid \"\"\n\"The desired count of color components. Must be one of 1, 3 or 4, which \"\n\"results in color spaces DeviceGray, DeviceRGB or DeviceCMYK respectively.\"\n\" The method affects text, images and vector graphics. For instance, with \"\n\"the default value 1, a page will be converted to grayscale. If a page is \"\n\"already grayscale, the method will not cause visible changes -- \"\n\"independent of the value of ``components``.\"\nmsgstr \"\"\n\"원하는 색상 컴포넌트 수. 1, 3 또는 4 중 하나여야 하며, 각각 색 공간 DeviceGray, DeviceRGB 또는 \"\n\"DeviceCMYK를 생성합니다. 이 메서드는 텍스트, 이미지 및 벡터 그래픽에 영향을 줍니다. 예를 들어, 기본값 1을 사용하면 \"\n\"페이지가 그레이스케일로 변환됩니다. 페이지가 이미 그레이스케일인 경우 이 메서드는 ``components`` 값과 관계없이 눈에 \"\n\"보이는 변경을 일으키지 않습니다.\"\n\n#: ../../page.rst:1973 483d3d2a28a64e1db8c84814f5b62553\nmsgid \"These changes are **permanent** and cannot be reverted.\"\nmsgstr \"이러한 변경 사항은 **영구적** 이며 되돌릴 수 없습니다.\"\n\n#: ../../page.rst:1977 49b350e20d564e5ca4be60761eebd7f6\nmsgid \"\"\n\"PDF only: Permanently remove page content outside the given rectangle. \"\n\"This is similar to :meth:`Page.set_cropbox`, but the page's rectangle \"\n\"will not be changed, only the content outside the rectangle will be \"\n\"removed.\"\nmsgstr \"\"\n\"PDF 전용: 주어진 사각형 외부의 페이지 콘텐츠를 영구적으로 제거합니다. 이것은 :meth:`Page.set_cropbox` 와 \"\n\"유사하지만, 페이지의 사각형은 변경되지 않고 사각형 외부의 콘텐츠만 제거됩니다.\"\n\n#: ../../page.rst:1979 bf753e463def4992b7ab3a5cba587ab6\nmsgid \"\"\n\"The rectangle to clip to. Must be finite and its intersection with the \"\n\"page must not be empty.\"\nmsgstr \"클리핑할 사각형. 유한해야 하며 페이지와의 교집합이 비어 있지 않아야 합니다.\"\n\n#: ../../page.rst:1981 da1c632880b442c599ff83e02a1fee53\nmsgid \"\"\n\"The method works best for text: All text on the page will be removed \"\n\"(decided by single character) that has no intersection with the \"\n\"rectangle. For vector graphics, the method will remove all paths that \"\n\"have no intersection with the rectangle. For images, the method will \"\n\"remove all images that have no intersection with the rectangle. Vectors \"\n\"and images **having** an intersection with the rectangle, will be kept in\"\n\" their entirety.\"\nmsgstr \"\"\n\"이 메서드는 텍스트에 가장 잘 작동합니다: 사각형과 교집합이 없는 페이지의 모든 텍스트가 제거됩니다(단일 문자로 결정). 벡터 \"\n\"그래픽의 경우 이 메서드는 사각형과 교집합이 없는 모든 경로를 제거합니다. 이미지의 경우 이 메서드는 사각형과 교집합이 없는 모든 \"\n\"이미지를 제거합니다. 사각형과 **교집합이 있는** 벡터 및 이미지는 전체가 유지됩니다.\"\n\n#: ../../page.rst:1983 ebdf3ebf7ffa4ae5897bfc0c9e729577\nmsgid \"\"\n\"The method roughly has the same effect as if four redactions had been \"\n\"applied that cover the rectangle's outside.\"\nmsgstr \"이 메서드는 사각형 외부를 덮는 네 개의 교정이 적용된 것과 거의 동일한 효과를 가집니다.\"\n\n#: ../../page.rst:1985 5834a8e7d537400cb60453c1d4852b9a\nmsgid \"New in v1.26.4.\"\nmsgstr \"v1.26.4의 새로운 기능.\"\n\n#: ../../page.rst:1989 0cee26002f6742f798ab8e2f8ded9df9\nmsgid \"\"\n\"PDF only: Set page rotation to 0 while maintaining appearance and page \"\n\"content.\"\nmsgstr \"PDF 전용: 외관과 페이지 콘텐츠를 유지하면서 페이지 회전을 0으로 설정합니다.\"\n\n#: ../../page.rst:1991 1239f6e2692a4bd99008c859cfdc9938\nmsgid \"\"\n\"The inverted matrix used to achieve this change. If the page was not \"\n\"rotated (rotation 0), :ref:`Identity` is returned. The method \"\n\"automatically recomputes the rectangles of any annotations, links and \"\n\"widgets present on the page.  This method may come in handy when e.g. \"\n\"used with :meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\n#: ../../page.rst:1991 6382757f31774362bd5db92ac43822e7\nmsgid \"\"\n\"The inverted matrix used to achieve this change. If the page was not \"\n\"rotated (rotation 0), :ref:`Identity` is returned. The method \"\n\"automatically recomputes the rectangles of any annotations, links and \"\n\"widgets present on the page.\"\nmsgstr \"\"\n\"이 변경을 달성하는 데 사용된 역행렬. 페이지가 회전되지 않은 경우(회전 0), :ref:`Identity` 가 반환됩니다. 이 \"\n\"메서드는 페이지에 있는 모든 주석, 링크 및 위젯의 사각형을 자동으로 다시 계산합니다.\"\n\n#: ../../page.rst:1993 1325f276d0764aac8a21e6d99585710b\nmsgid \"\"\n\"This method may come in handy when e.g. used with \"\n\":meth:`Page.show_pdf_page`.\"\nmsgstr \"이 메서드는 예를 들어 :meth:`Page.show_pdf_page` 와 함께 사용할 때 유용할 수 있습니다.\"\n\n#: ../../page.rst:2003 8dc74477058c480eb73af8efa28193fc\nmsgid \"\"\n\"PDF only: Display a page of another PDF. This is similar to \"\n\":meth:`Page.insert_image` but the source page will appear like a copy of \"\n\"itself and will not be rasterized. This is a multi-purpose method. For \"\n\"example, you can use it to:\"\nmsgstr \"\"\n\"PDF 전용: 다른 PDF의 페이지를 표시합니다. 이것은 :meth:`Page.insert_image` 와 유사하지만 소스 페이지는\"\n\" 자체의 복사본처럼 나타나며 래스터화되지 않습니다. 이것은 다목적 메서드입니다. 예를 들어, 다음에 사용할 수 있습니다:\"\n\n#: ../../page.rst:2005 354740c7f18a43a986458b228303b6d6\nmsgid \"\"\n\"create \\\"n-up\\\" versions of existing PDF files, combining several input \"\n\"pages into **one output page** (see example `combine.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/combine-pages/combine.py>`_),\"\nmsgstr \"\"\n\"기존 PDF 파일의 \\\"n-up\\\" 버전 생성, 여러 입력 페이지를 **하나의 출력 페이지** 로 결합(예제 `combine.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/combine-pages/combine.py>`_ 참조),\"\n\n#: ../../page.rst:2006 783780442f794f0cb6359372ce4d1fb5\nmsgid \"\"\n\"create \\\"posterized\\\" PDF files, i.e. every input page is split up in \"\n\"parts which each create a separate output page (see `posterize.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples\"\n\"/posterize-document/posterize.py>`_),\"\nmsgstr \"\"\n\"\\\"포스터화된\\\" PDF 파일 생성, 즉 모든 입력 페이지가 여러 부분으로 분할되어 각각 별도의 출력 페이지를 생성(예제 \"\n\"`posterize.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/posterize-document/posterize.py>`_ 참조),\"\n\n#: ../../page.rst:2007 cf10ad7db3454757a6226b1377e0f6b6\nmsgid \"\"\n\"include PDF-based vector images like company logos, watermarks, etc., see\"\n\" `svg-logo.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/examples/svg-logo.py>`_, which puts an SVG-based \"\n\"logo on each page.\"\nmsgstr \"\"\n\"회사 로고, 워터마크 등과 같은 PDF 기반 벡터 이미지 포함, 각 페이지에 SVG 기반 로고를 배치하는 `svg-logo.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/svg-\"\n\"logo.py>`_ 참조.\"\n\n#: ../../page.rst:2009 33c0c00be5d74048bed44c2ebe78831d\nmsgid \"\"\n\"where to place the image on current page. Must be finite and its \"\n\"intersection with the page must not be empty.\"\nmsgstr \"현재 페이지에 이미지를 배치할 위치. 유한해야 하며 페이지와의 교집합이 비어 있지 않아야 합니다.\"\n\n#: ../../page.rst:2010 71c6cc3da72244c483db1f62fe33d794\nmsgid \"\"\n\"source PDF document containing the page. Must be a different document \"\n\"object, but may be the same file.\"\nmsgstr \"페이지를 포함하는 소스 PDF 문서. 다른 문서 객체여야 하지만 동일한 파일일 수 있습니다.\"\n\n#: ../../page.rst:2013 adf70c9bce3a4133b9ffdde0c8e97b40\nmsgid \"page number (0-based, in `-∞ < pno < docsrc.page_count`) to be shown.\"\nmsgstr \"표시할 페이지 번호(0 기반, `-∞ < pno < docsrc.page_count`).\"\n\n#: ../../page.rst:2015 d14eefd61c384956a207b09f9ad3c383\nmsgid \"\"\n\"whether to maintain the width-height-ratio (default). If false, all 4 \"\n\"corners are always positioned on the border of the target rectangle -- \"\n\"whatever the rotation value. In general, this will deliver distorted and \"\n\"/or non-rectangular images.\"\nmsgstr \"\"\n\"너비-높이 비율을 유지할지 여부(기본값). false이면 회전 값과 관계없이 4개의 모서리가 모두 대상 사각형의 경계에 배치됩니다.\"\n\" 일반적으로 이것은 왜곡되고/또는 비사각형 이미지를 제공합니다.\"\n\n#: ../../page.rst:2017 aa72d9ab8817411da2f050b7e23bcde4\nmsgid \"put image in foreground (default) or background.\"\nmsgstr \"이미지를 전경(기본값) 또는 배경에 배치합니다.\"\n\n#: ../../page.rst:2019 eeb052672cb248acaaffb0046bf42971\nmsgid \"\"\n\"(:data:`xref`) make visibility dependent on this :data:`OCG` / \"\n\":data:`OCMD` (which must be defined in the target PDF) [#f9]_. (New in \"\n\"v1.18.3)\"\nmsgstr \"\"\n\"(:data:`xref`) 이 :data:`OCG` / :data:`OCMD` 에 따라 가시성을 설정합니다(대상 PDF에 정의되어 \"\n\"있어야 함) [#f9]_. (v1.18.3의 새로운 기능)\"\n\n#: ../../page.rst:2020 96f5420198ff41f89a8c3094e8910629\nmsgid \"\"\n\"show the source rectangle rotated by some angle. Any angle is supported \"\n\"(changed in v1.14.11). (New in v1.14.10)\"\nmsgstr \"\"\n\"소스 사각형을 특정 각도로 회전하여 표시합니다. 모든 각도가 지원됩니다(v1.14.11에서 변경됨). (v1.14.10의 새로운 \"\n\"기능)\"\n\n#: ../../page.rst:2022 d52ff41f1cd14e97a0c6a6dad3d809dd\nmsgid \"\"\n\"choose which part of the source page to show. Default is the full page, \"\n\"else must be finite and its intersection with the source page must not be\"\n\" empty.\"\nmsgstr \"\"\n\"소스 페이지의 어느 부분을 표시할지 선택합니다. 기본값은 전체 페이지이며, 그렇지 않으면 유한해야 하며 소스 페이지와의 교집합이 \"\n\"비어 있지 않아야 합니다.\"\n\n#: ../../page.rst:2024 3aef8119e20e4ffa8d394518498d43af\nmsgid \"\"\n\"In contrast to method :meth:`Document.insert_pdf`, this method does not \"\n\"copy annotations, widgets or links, so these objects are not included in \"\n\"the target [#f6]_. But all its **other resources (text, images, fonts, \"\n\"etc.)** will be imported into the current PDF. They will therefore appear\"\n\" in text extractions and in :meth:`get_fonts` and :meth:`get_images` \"\n\"lists -- even if they are not contained in the visible area given by \"\n\"*clip*.\"\nmsgstr \"\"\n\":meth:`Document.insert_pdf` 메서드와 달리 이 메서드는 주석, 위젯 또는 링크를 복사하지 않으므로 이러한 \"\n\"객체는 대상에 포함되지 않습니다 [#f6]_. 하지만 모든 **기타 리소스(텍스트, 이미지, 글꼴 등)** 는 현재 PDF로 \"\n\"가져옵니다. 따라서 *clip* 으로 지정된 보이는 영역에 포함되지 않더라도 텍스트 추출 및 :meth:`get_fonts` 및 \"\n\":meth:`get_images` 목록에 나타납니다.\"\n\n#: ../../page.rst:2026 5fba7277847b4bc793310bd2e3feece9\nmsgid \"Example: Show the same source page, rotated by 90 and by -90 degrees:\"\nmsgstr \"예제: 동일한 소스 페이지를 90도 및 -90도로 회전하여 표시:\"\n\n#: ../../page.rst:2048 073d99851b794037a8e8f80aed9a6844\nmsgid \"\"\n\"Changed in v1.14.11: Parameter *reuse_xref* has been deprecated. Position\"\n\" the source rectangle centered in target rectangle. Any rotation angle is\"\n\" now supported.\"\nmsgstr \"\"\n\"v1.14.11에서 변경됨: 매개변수 *reuse_xref* 가 더 이상 사용되지 않습니다. 소스 사각형을 대상 사각형의 중앙에 \"\n\"배치합니다. 이제 모든 회전 각도가 지원됩니다.\"\n\n#: ../../page.rst:2049 5c783c076ae74e24ac1476998953fa6e\nmsgid \"Changed in v1.18.3: New parameter `oc`.\"\nmsgstr \"v1.18.3에서 변경됨: 새로운 매개변수 `oc`.\"\n\n#: ../../page.rst:2055 0e3799b8dc0a45ee9cc3f0fa9ed0c555\nmsgid \"PDF only: Create a new :ref:`Shape` object for the page.\"\nmsgstr \"PDF 전용: 페이지에 대한 새로운 :ref:`Shape` 객체를 생성합니다.\"\n\n#: ../../page.rst:2057 1836989d75f0407e86fc7a982cdc99f3\nmsgid \":ref:`Shape`\"\nmsgstr \":ref:`Shape`\"\n\n#: ../../page.rst:2058 846397e4abdf4c3b8e63573909076603\nmsgid \"a new :ref:`Shape` to use for compound drawings. See description there.\"\nmsgstr \"복합 그림에 사용할 새로운 :ref:`Shape`. 설명을 참조하세요.\"\n\n#: ../../page.rst:2069 582bc47d92404cacb9f37e4455d4e925\nmsgid \"Search for *needle* on a page. Wrapper for :meth:`TextPage.search`.\"\nmsgstr \"페이지에서 *needle* 을 검색합니다. :meth:`TextPage.search` 의 래퍼입니다.\"\n\n#: ../../page.rst:2071 8f30cc4067374cefb36176bc93c7b187\nmsgid \"\"\n\"Text to search for. May contain spaces. Upper / lower case is ignored, \"\n\"but only works for ASCII characters: For example, \\\"COMPÉTENCES\\\" will \"\n\"not be found if needle is \\\"compétences\\\" -- \\\"compÉtences\\\" however \"\n\"will. Similar is true for German umlauts and the like.\"\nmsgstr \"\"\n\"검색할 텍스트. 공백을 포함할 수 있습니다. 대소문자는 무시되지만 ASCII 문자에만 작동합니다: 예를 들어, \"\n\"\\\"COMPÉTENCES\\\" 는 needle이 \\\"compétences\\\" 인 경우 찾을 수 없습니다 -- 하지만 \"\n\"\\\"compÉtences\\\" 는 찾을 수 있습니다. 독일어 움라우트 등도 마찬가지입니다.\"\n\n#: ../../page.rst:2072 be9d1f75e4d94af6afd2298e0fcb0d1a\nmsgid \"only search within this area. (New in v1.18.2)\"\nmsgstr \"이 영역 내에서만 검색합니다. (v1.18.2의 새로운 기능)\"\n\n#: ../../page.rst:2073 b4532cd56fb245689ebfe2ad1520d06f\nmsgid \"Return object type :ref:`Quad` instead of :ref:`Rect`.\"\nmsgstr \":ref:`Rect` 대신 :ref:`Quad` 객체 타입을 반환합니다.\"\n\n#: ../../page.rst:2074 fba71b85626a46759cf1e3a4ca5991f5\nmsgid \"\"\n\"Control the data extracted by the underlying :ref:`TextPage`. By default,\"\n\" ligatures and white spaces are kept, and hyphenation [#f8]_ is detected.\"\nmsgstr \"\"\n\"기본 :ref:`TextPage` 에 의해 추출된 데이터를 제어합니다. 기본적으로 합자와 공백이 유지되며 하이픈 연결 [#f8]_ \"\n\"이 감지됩니다.\"\n\n#: ../../page.rst:2075 411c63769a4848319b2cf5c0a356fe7a\nmsgid \"\"\n\"use a previously created :ref:`TextPage`. This reduces execution time \"\n\"**significantly.** If specified, the 'flags' and 'clip' arguments are \"\n\"ignored. If omitted, a temporary textpage will be created. (New in \"\n\"v1.19.0)\"\nmsgstr \"\"\n\"이전에 생성된 :ref:`TextPage` 를 사용합니다. 이것은 실행 시간을 **크게** 줄입니다. 지정하면 'flags' 및 \"\n\"'clip' 인수는 무시됩니다. 생략하면 임시 textpage가 생성됩니다. (v1.19.0의 새로운 기능)\"\n\n#: ../../page.rst:2079 720c33ce38fd4b22963ec128ce4a00bb\nmsgid \"\"\n\"A list of :ref:`Rect` or  :ref:`Quad` objects, each of which  -- \"\n\"**normally!** -- surrounds one occurrence of *needle*. **However:** if \"\n\"parts of *needle* occur on more than one line, then a separate item is \"\n\"generated for each these parts. So, if `needle = \\\"search string\\\"`, two \"\n\"rectangles may be generated.  |history_begin|  Changes in v1.18.2:  * \"\n\"There no longer is a limit on the list length (removal of the `hit_max` \"\n\"parameter). * If a word is **hyphenated** at a line break, it will still \"\n\"be found. E.g. the needle \\\"method\\\" will be found even if hyphenated as \"\n\"\\\"meth-od\\\" at a line break, and two rectangles will be returned: one \"\n\"surrounding \\\"meth\\\" (without the hyphen) and another one surrounding \"\n\"\\\"od\\\".  |history_end|\"\nmsgstr \"\"\n\n#: ../../page.rst:2081 f8d208e58858471b8f92953db79f51c3\nmsgid \"\"\n\"A list of :ref:`Rect` or  :ref:`Quad` objects, each of which  -- \"\n\"**normally!** -- surrounds one occurrence of *needle*. **However:** if \"\n\"parts of *needle* occur on more than one line, then a separate item is \"\n\"generated for each these parts. So, if `needle = \\\"search string\\\"`, two \"\n\"rectangles may be generated.\"\nmsgstr \"\"\n\":ref:`Rect` 또는 :ref:`Quad` 객체의 목록으로, 각각은 -- **일반적으로!** -- *needle* 의 한 \"\n\"발생을 둘러쌉니다. **하지만:** *needle* 의 일부가 여러 줄에 나타나면 각 부분에 대해 별도의 항목이 생성됩니다. 따라서\"\n\" `needle = \\\"search string\\\"` 인 경우 두 개의 사각형이 생성될 수 있습니다.\"\n\n#: ../../page.rst:2085 dbb74981c75a4e0fad63c8a853f37af2\nmsgid \"Changes in v1.18.2:\"\nmsgstr \"v1.18.2의 변경 사항:\"\n\n#: ../../page.rst:2087 fe75a9fa204c408d9bec7cc0681e818b\nmsgid \"\"\n\"There no longer is a limit on the list length (removal of the `hit_max` \"\n\"parameter).\"\nmsgstr \"목록 길이에 더 이상 제한이 없습니다(`hit_max` 매개변수 제거).\"\n\n#: ../../page.rst:2088 31766ebe188f4ee1ae221104e2508841\nmsgid \"\"\n\"If a word is **hyphenated** at a line break, it will still be found. E.g.\"\n\" the needle \\\"method\\\" will be found even if hyphenated as \\\"meth-od\\\" at\"\n\" a line break, and two rectangles will be returned: one surrounding \"\n\"\\\"meth\\\" (without the hyphen) and another one surrounding \\\"od\\\".\"\nmsgstr \"\"\n\"단어가 줄바꿈에서 **하이픈으로 연결** 되어 있어도 여전히 찾을 수 있습니다. 예를 들어, needle \\\"method\\\" 는 \"\n\"줄바꿈에서 \\\"meth-od\\\" 로 하이픈 연결되어 있어도 찾을 수 있으며, 두 개의 사각형이 반환됩니다: 하나는 \\\"meth\\\" \"\n\"(하이픈 없이)를 둘러싸고 다른 하나는 \\\"od\\\" 를 둘러쌉니다.\"\n\n#: ../../page.rst:2092 77b9f7f5f65e44048049b365e391fb62\nmsgid \"\"\n\"The method supports multi-line text marker annotations: you can use the \"\n\"full returned list as **one single** parameter for creating the \"\n\"annotation.\"\nmsgstr \"\"\n\"이 메서드는 다중 줄 텍스트 마커 주석을 지원합니다: 반환된 전체 목록을 주석을 생성하기 위한 **단일** 매개변수로 사용할 수 \"\n\"있습니다.\"\n\n#: ../../page.rst:2096 57554cf44857462a93fa6f8911265cf5\nmsgid \"\"\n\"There is a tricky aspect: the search logic regards **contiguous multiple \"\n\"occurrences** of *needle* as one: assuming *needle* is \\\"abc\\\", and the \"\n\"page contains \\\"abc\\\" and \\\"abcabc\\\", then only **two** rectangles will \"\n\"be returned, one for \\\"abc\\\", and a second one for \\\"abcabc\\\".\"\nmsgstr \"\"\n\"까다로운 측면이 있습니다: 검색 로직은 *needle* 의 **연속된 여러 발생** 을 하나로 간주합니다: *needle* 이 \"\n\"\\\"abc\\\" 이고 페이지에 \\\"abc\\\" 와 \\\"abcabc\\\" 가 포함된 경우, **두 개의** 사각형만 반환됩니다. 하나는 \"\n\"\\\"abc\\\" 에 대한 것이고 두 번째는 \\\"abcabc\\\" 에 대한 것입니다.\"\n\n#: ../../page.rst:2097 abecd36837344b119db60f93d69e4ab5\nmsgid \"\"\n\"You can always use :meth:`Page.get_textbox` to check what text actually \"\n\"is being surrounded by each rectangle.\"\nmsgstr \":meth:`Page.get_textbox` 를 사용하여 각 사각형이 실제로 어떤 텍스트를 둘러싸고 있는지 확인할 수 있습니다.\"\n\n#: ../../page.rst:2099 ae4dd62d990f45049a3d1efab5f6aad6\nmsgid \"\"\n\"A feature repeatedly asked for is supporting **regular expressions** when\"\n\" specifying the `\\\"needle\\\"` string: **There is no way to do this.** If \"\n\"you need something in that direction, first extract text in the desired \"\n\"format and then subselect the result by matching with some regex pattern.\"\n\" Here is an example for matching words::\"\nmsgstr \"\"\n\"반복적으로 요청된 기능은 `\\\"needle\\\"` 문자열을 지정할 때 **정규 표현식** 을 지원하는 것입니다: **이것을 수행할 \"\n\"방법이 없습니다.** 그런 방향이 필요하다면, 먼저 원하는 형식으로 텍스트를 추출한 다음 일부 정규식 패턴과 일치시켜 결과를 하위 \"\n\"선택하세요. 단어를 일치시키는 예제는 다음과 같습니다::\"\n\n#: ../../page.rst:2105 6d2d34e353264e1ca0fc568527af9a70\nmsgid \"\"\n\"The `matches` list will contain the words matching the given pattern. In \"\n\"the same way you can select `span[\\\"text\\\"]` from the output of \"\n\"`page.get_text(\\\"dict\\\")`.\"\nmsgstr \"\"\n\"`matches` 목록에는 주어진 패턴과 일치하는 단어가 포함됩니다. 같은 방식으로 `page.get_text(\\\"dict\\\")` \"\n\"의 출력에서 `span[\\\"text\\\"]` 를 선택할 수 있습니다.\"\n\n#: ../../page.rst:2109 498f8aa809b649cc87bf0051b213dcaa\nmsgid \"\"\n\"Changed in v1.18.2: added `clip` parameter. Remove `hit_max` parameter. \"\n\"Add default \\\"dehyphenate\\\".\"\nmsgstr \"v1.18.2에서 변경됨: `clip` 매개변수 추가. `hit_max` 매개변수 제거. 기본값 \\\"dehyphenate\\\" 추가.\"\n\n#: ../../page.rst:2110 20246746300244b382c5d8a1c9d4126a\nmsgid \"Changed in v1.19.0: added `textpage` parameter.\"\nmsgstr \"v1.19.0에서 변경됨: `textpage` 매개변수 추가.\"\n\n#: ../../page.rst:2117 2692c3f033cf4f2f805f6a7112f70898\nmsgid \"\"\n\"PDF only: Change the physical page dimension by setting :data:`mediabox` \"\n\"in the page's object definition.\"\nmsgstr \"PDF 전용: 페이지 객체 정의에서 :data:`mediabox` 를 설정하여 물리적 페이지 크기를 변경합니다.\"\n\n#: ../../page.rst:2119 a9b2bf70f6b74517aa540d6e83f7bea9\nmsgid \"the new :data:`mediabox` value.\"\nmsgstr \"새로운 :data:`mediabox` 값.\"\n\n#: ../../page.rst:2121 7a6526b2c64d4e3a9bd927b363722d6d\nmsgid \"\"\n\"This method also removes the page's other (optional) rectangles \"\n\"(:data:`cropbox`, ArtBox, TrimBox and Bleedbox) to prevent inconsistent \"\n\"situations. This will cause those to assume their default values.\"\nmsgstr \"\"\n\"이 메서드는 일관성 없는 상황을 방지하기 위해 페이지의 다른 (선택적) 사각형(:data:`cropbox`, ArtBox, \"\n\"TrimBox 및 Bleedbox)도 제거합니다. 이것은 그것들이 기본값을 가정하도록 합니다.\"\n\n#: ../../page.rst:2123 1ab3183f788442cb82b31ca3e697cd7d\nmsgid \"\"\n\"For non-empty pages this may have undesired effects, because the location\"\n\" of all content depends on this value and will therefore change position \"\n\"or even disappear.\"\nmsgstr \"\"\n\"비어 있지 않은 페이지의 경우 이것은 원하지 않는 효과를 가질 수 있습니다. 모든 콘텐츠의 위치가 이 값에 의존하므로 위치가 \"\n\"변경되거나 사라질 수 있기 때문입니다.\"\n\n#: ../../page.rst:2127 2db1401ccd4e4c978f4a0b50365f8a62\nmsgid \"New in v1.16.13\"\nmsgstr \"v1.16.13의 새로운 기능\"\n\n#: ../../page.rst:2128 9f33ae9d37ea49a9af0f2276c2df8490\nmsgid \"Changed in v1.19.4: remove all other rectangle definitions.\"\nmsgstr \"v1.19.4에서 변경됨: 모든 다른 사각형 정의 제거.\"\n\n#: ../../page.rst:2135 e2267e65404e4f89b3f1d7032048a1b9\nmsgid \"PDF only: change the visible part of the page.\"\nmsgstr \"PDF 전용: 페이지의 보이는 부분을 변경합니다.\"\n\n#: ../../page.rst:2137 26dafb91ce2c4c86b79422d5065a7ff1\nmsgid \"\"\n\"the new visible area of the page. Note that this **must** be specified in\"\n\" **unrotated coordinates**, not empty, nor infinite and be completely \"\n\"contained in the :attr:`Page.mediabox`.\"\nmsgstr \"\"\n\"페이지의 새로운 보이는 영역. 이것은 **회전되지 않은 좌표** 로 지정되어야 하며, 비어 있지 않고 무한하지 않으며 \"\n\":attr:`Page.mediabox` 에 완전히 포함되어야 합니다.\"\n\n#: ../../page.rst:2139 1a4ce62ae3164bf9b7d5867e0d15da9f\nmsgid \"\"\n\"After execution **(if the page is not rotated)**, :attr:`Page.rect` will \"\n\"equal this rectangle, but be shifted to the top-left position (0, 0) if \"\n\"necessary. Example session:\"\nmsgstr \"\"\n\"실행 후 **(페이지가 회전되지 않은 경우)**, :attr:`Page.rect` 는 이 사각형과 같지만 필요하면 왼쪽 상단 위치 \"\n\"(0, 0)로 이동합니다. 예제 세션:\"\n\n#: ../../page.rst:2170 487d3f62d0154c43b809962cb834db02\nmsgid \"\"\n\"PDF only: Set the resp. rectangle in the page object. For the meaning of \"\n\"these objects see :ref:`AdobeManual`, page 77. Parameter and restrictions\"\n\" are the same as for :meth:`Page.set_cropbox`.\"\nmsgstr \"\"\n\"PDF 전용: 페이지 객체에서 해당 사각형을 설정합니다. 이러한 객체의 의미는 :ref:`AdobeManual`, 77페이지를 \"\n\"참조하세요. 매개변수와 제한 사항은 :meth:`Page.set_cropbox` 와 동일합니다.\"\n\n#: ../../page.rst:2174 84db1fa5172f42269728027e803083b4\nmsgid \"New in v1.19.4\"\nmsgstr \"v1.19.4의 새로운 기능\"\n\n#: ../../page.rst:2180 f499b299e1a344c192594e6c3347536f\nmsgid \"\"\n\"Contains the rotation of the page in degrees (always 0 for non-PDF \"\n\"types). This is a copy of the value in the PDF file. The PDF \"\n\"documentation says:\"\nmsgstr \"\"\n\"페이지의 회전을 도 단위로 포함합니다(비-PDF 타입의 경우 항상 0). 이것은 PDF 파일의 값 복사본입니다. PDF 문서에 \"\n\"따르면:\"\n\n#: ../../page.rst:2182 40609a90d7294c4386d6b38c137de2e7\nmsgid \"\"\n\"*\\\"The number of degrees by which the page should be rotated clockwise \"\n\"when displayed or printed. The value must be a multiple of 90. Default \"\n\"value: 0.\\\"*\"\nmsgstr \"*\\\"표시되거나 인쇄될 때 페이지가 시계 방향으로 회전해야 하는 도 수. 값은 90의 배수여야 합니다. 기본값: 0.\\\"*\"\n\n#: ../../page.rst:2184 ef02a9bf2df247b79809ffaceff1c539\nmsgid \"\"\n\"In PyMuPDF, we make sure that this attribute is always one of 0, 90, 180 \"\n\"or 270.\"\nmsgstr \"PyMuPDF에서는 이 속성이 항상 0, 90, 180 또는 270 중 하나가 되도록 합니다.\"\n\n#: ../../page.rst:2190 217c654874984e38be9562d0c4b8b436\nmsgid \"\"\n\"Contains the top-left point of the page's `/CropBox` for a PDF, otherwise\"\n\" *Point(0, 0)*.\"\nmsgstr \"PDF의 경우 페이지의 `/CropBox` 의 왼쪽 상단 점을 포함하고, 그렇지 않으면 *Point(0, 0)*.\"\n\n#: ../../page.rst:2192 ../../page.rst:2216 82507dc59ca94b3aa9846470ca6093c8\n#: db796a2e28a84eb0a59bac3ca1348f7b\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../page.rst:2196 51b3952c0e0a4489b270e2f2b48c55fb\nmsgid \"\"\n\"The page's `/CropBox` for a PDF. Always the **unrotated** page rectangle \"\n\"is returned. For a non-PDF this will always equal the page rectangle.\"\nmsgstr \"\"\n\"PDF의 경우 페이지의 `/CropBox`. 항상 **회전되지 않은** 페이지 사각형이 반환됩니다. 비-PDF의 경우 이것은 항상 \"\n\"페이지 사각형과 같습니다.\"\n\n#: ../../page.rst:2198 33482f994ea2453f977561ad97c6e4c0\nmsgid \"\"\n\"In PDF, the relationship between `/MediaBox`, `/CropBox` and page \"\n\"rectangle may sometimes be confusing, please do lookup the glossary for \"\n\":data:`MediaBox`.\"\nmsgstr \"\"\n\"PDF에서 `/MediaBox`, `/CropBox` 및 페이지 사각형 간의 관계는 때때로 혼란스러울 수 있으므로 \"\n\":data:`MediaBox` 에 대한 용어집을 참조하세요.\"\n\n#: ../../page.rst:2208 79b7c13fa8f340dca2a19eb7ce19481c\nmsgid \"\"\n\"The page's `/ArtBox`, `/BleedBox`, `/TrimBox`, respectively. If not \"\n\"provided, defaulting to :attr:`Page.cropbox`.\"\nmsgstr \"\"\n\"페이지의 `/ArtBox`, `/BleedBox`, `/TrimBox` 각각. 제공되지 않은 경우 \"\n\":attr:`Page.cropbox` 로 기본값이 설정됩니다.\"\n\n#: ../../page.rst:2214 527ae95e018f4a37824ed8a2e6e720a7\nmsgid \"\"\n\"Contains the width and height of the page's :attr:`Page.mediabox` for a \"\n\"PDF, otherwise the bottom-right coordinates of :attr:`Page.rect`.\"\nmsgstr \"\"\n\"PDF의 경우 페이지의 :attr:`Page.mediabox` 의 너비와 높이를 포함하고, 그렇지 않으면 \"\n\":attr:`Page.rect` 의 오른쪽 하단 좌표를 포함합니다.\"\n\n#: ../../page.rst:2220 df54f6f570c14da0b9f75f4d3cd19aea\nmsgid \"The page's :data:`mediabox` for a PDF, otherwise :attr:`Page.rect`.\"\nmsgstr \"PDF의 경우 페이지의 :data:`mediabox`, 그렇지 않으면 :attr:`Page.rect`.\"\n\n#: ../../page.rst:2224 58641a6d613248a5a15705b030d9f4cc\nmsgid \"\"\n\"For most PDF documents and for **all other document types**, `page.rect \"\n\"== page.cropbox == page.mediabox` is true. However, for some PDFs the \"\n\"visible page is a true subset of :data:`mediabox`. Also, if the page is \"\n\"rotated, its `Page.rect` may not equal `Page.cropbox`. In these cases the\"\n\" above attributes help to correctly locate page elements.\"\nmsgstr \"\"\n\"대부분의 PDF 문서와 **모든 다른 문서 타입** 의 경우 `page.rect == page.cropbox == \"\n\"page.mediabox` 가 참입니다. 하지만 일부 PDF의 경우 보이는 페이지는 :data:`mediabox` 의 \"\n\"진부분집합입니다. 또한 페이지가 회전된 경우 `Page.rect` 는 `Page.cropbox` 와 같지 않을 수 있습니다. 이러한\"\n\" 경우 위의 속성은 페이지 요소를 올바르게 찾는 데 도움이 됩니다.\"\n\n#: ../../page.rst:2228 691c2b38aaf24491808a5a3aa6056d75\nmsgid \"\"\n\"This matrix translates coordinates from the PDF space to the MuPDF space.\"\n\" For example, in PDF `/Rect [x0 y0 x1 y1]` the pair (x0, y0) specifies \"\n\"the **bottom-left** point of the rectangle -- in contrast to MuPDF's \"\n\"system, where (x0, y0) specify top-left. Multiplying the PDF coordinates \"\n\"with this matrix will deliver the (Py-) MuPDF rectangle version. \"\n\"Obviously, the inverse matrix will again yield the PDF rectangle.\"\nmsgstr \"\"\n\"이 행렬은 좌표를 PDF 공간에서 MuPDF 공간으로 변환합니다. 예를 들어, PDF에서 `/Rect [x0 y0 x1 y1]` 의\"\n\" 쌍 (x0, y0)은 사각형의 **왼쪽 하단** 점을 지정합니다 -- MuPDF 시스템과 대조적으로, 여기서 (x0, y0)는 \"\n\"왼쪽 상단을 지정합니다. PDF 좌표에 이 행렬을 곱하면 (Py-) MuPDF 사각형 버전을 제공합니다. 명백히, 역행렬은 다시 \"\n\"PDF 사각형을 생성합니다.\"\n\n#: ../../page.rst:2230 ../../page.rst:2246 19d6b8bfeb41482fb77511189c87cadb\n#: a708f233bdde4cdaa04aa4ba41af32ed\nmsgid \":ref:`Matrix`\"\nmsgstr \":ref:`Matrix`\"\n\n#: ../../page.rst:2236 619ad68a91444dbda5559a50e7b18870\nmsgid \"\"\n\"These matrices may be used for dealing with rotated PDF pages. When \"\n\"adding / inserting anything to a PDF page, the coordinates of the \"\n\"**unrotated** page are always used. These matrices help translating \"\n\"between the two states. Example: if a page is rotated by 90 degrees -- \"\n\"what would then be the coordinates of the top-left Point(0, 0) of an A4 \"\n\"page?\"\nmsgstr \"\"\n\"이 행렬은 회전된 PDF 페이지를 처리하는 데 사용할 수 있습니다. PDF 페이지에 무언가를 추가/삽입할 때 **회전되지 않은** \"\n\"페이지의 좌표가 항상 사용됩니다. 이 행렬은 두 상태 간의 변환을 돕습니다. 예: 페이지가 90도 회전된 경우 -- A4 페이지의 \"\n\"왼쪽 상단 Point(0, 0)의 좌표는 무엇일까요?\"\n\n#: ../../page.rst:2250 ddbabcc453ad4c789405db548087aed7\nmsgid \"Contains the first :ref:`Link` of a page (or ``None``).\"\nmsgstr \"페이지의 첫 번째 :ref:`Link` 를 포함합니다(또는 ``None``).\"\n\n#: ../../page.rst:2256 8e9b0966949b4b89a06b7c70c1e622fc\nmsgid \"Contains the first :ref:`Annot` of a page (or ``None``).\"\nmsgstr \"페이지의 첫 번째 :ref:`Annot` 를 포함합니다(또는 ``None``).\"\n\n#: ../../page.rst:2262 8a8e6bd51e1b49d68dc68901f8520cc0\nmsgid \"Contains the first :ref:`Widget` of a page (or ``None``).\"\nmsgstr \"페이지의 첫 번째 :ref:`Widget` 를 포함합니다(또는 ``None``).\"\n\n#: ../../page.rst:2268 f1f4e48ddb894011aaba58e324077d17\nmsgid \"The page number.\"\nmsgstr \"페이지 번호.\"\n\n#: ../../page.rst:2274 598a6f8e2b214784be2c4567bd665784\nmsgid \"The owning document object.\"\nmsgstr \"소유 문서 객체.\"\n\n#: ../../page.rst:2276 fc47bb5d9a384a25988d0005179384a0\nmsgid \":ref:`Document`\"\nmsgstr \":ref:`Document`\"\n\n#: ../../page.rst:2281 903928ce2b2d4d85b69ddd0c2953a6cd\nmsgid \"\"\n\"Contains the rectangle of the page. Same as result of \"\n\":meth:`Page.bound()`.\"\nmsgstr \"\"\n\n#: ../../page.rst:2287 db6b044e10064b77a399ca9bf5685897\nmsgid \"The page's PDF :data:`xref`. Zero if not a PDF.\"\nmsgstr \"페이지의 PDF :data:`xref`. PDF가 아니면 0입니다.\"\n\n#: ../../page.rst:2296 65a9c883c60a4f44bbd31db4bb74e649\nmsgid \"Description of *get_links()* Entries\"\nmsgstr \"*get_links()* 엔트리 설명\"\n\n#: ../../page.rst:2297 b1b03f14b2234cd59a58aa04d3f31962\nmsgid \"\"\n\"Each entry of the :meth:`Page.get_links` list is a dictionary with the \"\n\"following keys:\"\nmsgstr \"\"\n\":meth:`Page.get_links` 리스트의 각 엔트리는 다음 키를 가진 딕셔너리입니다:\"\n\n#: ../../page.rst:2299 345a52ebe41749919aa7099360b3523d\nmsgid \"\"\n\"*kind*:  (required) an integer indicating the kind of link. This is one \"\n\"of *LINK_NONE*, *LINK_GOTO*, *LINK_GOTOR*, *LINK_LAUNCH*, or *LINK_URI*. \"\n\"For values and meaning of these names refer to :ref:`linkDest Kinds`.\"\nmsgstr \"\"\n\"*kind*: (필수) 링크 종류를 나타내는 정수. 이것은 *LINK_NONE*, *LINK_GOTO*, *LINK_GOTOR*, *LINK_LAUNCH* 또는 *LINK_URI* 중 하나입니다. 이러한 이름의 값과 의미는 :ref:`linkDest Kinds` 를 참조하세요.\"\n\n#: ../../page.rst:2301 8482a0ea9b60495a97834603a7ea0896\nmsgid \"\"\n\"*from*:  (required) a :ref:`Rect` describing the \\\"hot spot\\\" location on\"\n\" the page's visible representation (where the cursor changes to a hand \"\n\"image, usually).\"\nmsgstr \"\"\n\"*from*: (필수) 페이지의 보이는 표현에서 \\\"핫 스팟\\\" 위치를 설명하는 :ref:`Rect` (일반적으로 커서가 손 이미지로 변경되는 위치).\"\n\n#: ../../page.rst:2303 67493fe07fbb4e2b991f920c746ec961\nmsgid \"\"\n\"*page*:  a 0-based integer indicating the destination page. Required for \"\n\"*LINK_GOTO* and *LINK_GOTOR*, else ignored.\"\nmsgstr \"\"\n\"*page*: 대상 페이지를 나타내는 0 기반 정수. *LINK_GOTO* 및 *LINK_GOTOR* 에 필요하며, 그렇지 않으면 무시됩니다.\"\n\n#: ../../page.rst:2305 80ba8c8c6a844419bb7b03b9b096f0cc\nmsgid \"\"\n\"*to*:   either a *pymupdf.Point*, specifying the destination location on \"\n\"the provided page, default is *pymupdf.Point(0, 0)*, or a symbolic \"\n\"(indirect) name. If an indirect name is specified, *page = -1* is \"\n\"required and the name must be defined in the PDF in order for this to \"\n\"work. Required for *LINK_GOTO* and *LINK_GOTOR*, else ignored.\"\nmsgstr \"\"\n\"*to*: 제공된 페이지의 대상 위치를 지정하는 *pymupdf.Point* (기본값은 *pymupdf.Point(0, 0)*) 또는 기호(간접) 이름. 간접 이름이 지정되면 *page = -1* 이 필요하며 이 이름이 작동하려면 PDF에 정의되어 있어야 합니다. *LINK_GOTO* 및 *LINK_GOTOR* 에 필요하며, 그렇지 않으면 무시됩니다.\"\n\n#: ../../page.rst:2307 e3a21fa1d4b54847a47036cdb423d96f\nmsgid \"\"\n\"*file*: a string specifying the destination file. Required for \"\n\"*LINK_GOTOR* and *LINK_LAUNCH*, else ignored.\"\nmsgstr \"\"\n\"*file*: 대상 파일을 지정하는 문자열. *LINK_GOTOR* 및 *LINK_LAUNCH* 에 필요하며, 그렇지 않으면 무시됩니다.\"\n\n#: ../../page.rst:2309 f1058b6ba67e46c2ad73d8fc9842241f\nmsgid \"\"\n\"*uri*:  a string specifying the destination internet resource. Required \"\n\"for *LINK_URI*, else ignored. You should make sure to start this string \"\n\"with an unambiguous substring, that classifies the subtype of the URL, \"\n\"like `\\\"http://\\\"`, `\\\"https://\\\"`, `\\\"file://\\\"`, `\\\"ftp://\\\"`, \"\n\"`\\\"mailto:\\\"`, etc. Otherwise your browser will try to interpret the text\"\n\" and come to unwanted / unexpected conclusions about the intended URL \"\n\"type.\"\nmsgstr \"\"\n\"*uri*: 대상 인터넷 리소스를 지정하는 문자열. *LINK_URI* 에 필요하며, 그렇지 않으면 무시됩니다. URL의 하위 타입을 분류하는 명확한 하위 문자열로 이 문자열을 시작해야 합니다. 예: `\\\"http://\\\"`, `\\\"https://\\\"`, `\\\"file://\\\"`, `\\\"ftp://\\\"`, `\\\"mailto:\\\"` 등. 그렇지 않으면 브라우저가 텍스트를 해석하려고 시도하고 의도한 URL 타입에 대해 원하지 않거나 예상치 못한 결론에 도달할 수 있습니다.\"\n\n#: ../../page.rst:2311 fb92e47c1bcc495899578761acc32d09\nmsgid \"\"\n\":data:`xref`: an integer specifying the PDF :data:`xref` of the link \"\n\"object. Do not change this entry in any way. Required for link deletion \"\n\"and update, otherwise ignored. For non-PDF documents, this entry contains\"\n\" *-1*. It is also *-1* for **all** entries in the *get_links()* list, if \"\n\"**any** of the links is not supported by MuPDF - see \"\n\":ref:`notes_on_supporting_links`.\"\nmsgstr \"\"\n\":data:`xref`: 링크 객체의 PDF :data:`xref` 를 지정하는 정수. 이 항목을 어떤 방식으로도 변경하지 마세요. 링크 삭제 및 업데이트에 필요하며, 그렇지 않으면 무시됩니다. 비PDF 문서의 경우 이 항목은 *-1* 을 포함합니다. MuPDF에서 지원하지 않는 링크가 **하나라도** 있으면 *get_links()* 리스트의 **모든** 엔트리에 대해 *-1* 입니다 - :ref:`notes_on_supporting_links` 를 참조하세요.\"\n\n#: ../../page.rst:2316 5433fcbb259a455c9591df3957b3a3f8\nmsgid \"Notes on Supporting Links\"\nmsgstr \"링크 지원에 대한 참고사항\"\n\n#: ../../page.rst:2317 7408ebdf3c5c461f90ea45dc48374e34\nmsgid \"\"\n\"MuPDF's support for links has changed in **v1.10a**. These changes affect\"\n\" link types :data:`LINK_GOTO` and :data:`LINK_GOTOR`.\"\nmsgstr \"\"\n\"MuPDF의 링크 지원이 **v1.10a** 에서 변경되었습니다. 이러한 변경 사항은 링크 타입 :data:`LINK_GOTO` 및 :data:`LINK_GOTOR` 에 영향을 줍니다.\"\n\n#: ../../page.rst:2320 64771c6af29e451a9594551d29b5f876\nmsgid \"\"\n\"Reading (pertains to method *get_links()* and the *first_link* property \"\n\"chain)\"\nmsgstr \"\"\n\"읽기 (*get_links()* 메서드 및 *first_link* 속성 체인과 관련)\"\n\n#: ../../page.rst:2322 d23361bc3a824ef0bdd6ab8d1998480b\nmsgid \"\"\n\"If MuPDF detects a link to another file, it will supply either a \"\n\"*LINK_GOTOR* or a *LINK_LAUNCH* link kind. In case of *LINK_GOTOR* \"\n\"destination details may either be given as page number (eventually \"\n\"including position information), or as an indirect destination.\"\nmsgstr \"\"\n\"MuPDF가 다른 파일에 대한 링크를 감지하면 *LINK_GOTOR* 또는 *LINK_LAUNCH* 링크 종류를 제공합니다. *LINK_GOTOR* 의 경우 대상 세부 정보는 페이지 번호(최종적으로 위치 정보 포함) 또는 간접 대상으로 제공될 수 있습니다.\"\n\n#: ../../page.rst:2324 5cc576ca82454037a175c38f660477ee\nmsgid \"\"\n\"If an indirect destination is given, then this is indicated by *page = \"\n\"-1*, and *link.dest.dest* will contain this name. The dictionaries in the\"\n\" *get_links()* list will contain this information as the *to* value.\"\nmsgstr \"\"\n\"간접 대상이 제공되면 이것은 *page = -1* 로 표시되며, *link.dest.dest* 에 이 이름이 포함됩니다. *get_links()* 리스트의 딕셔너리는 이 정보를 *to* 값으로 포함합니다.\"\n\n#: ../../page.rst:2326 0a44a885ed1c4110bb98fa9f94783d3a\nmsgid \"\"\n\"**Internal links are always** of kind *LINK_GOTO*. If an internal link \"\n\"specifies an indirect destination, it **will always be resolved** and the\"\n\" resulting direct destination will be returned. Names are **never \"\n\"returned for internal links**, and undefined destinations will cause the \"\n\"link to be ignored.\"\nmsgstr \"\"\n\"**내부 링크는 항상** *LINK_GOTO* 종류입니다. 내부 링크가 간접 대상을 지정하면 **항상 해결** 되며 결과적인 직접 대상이 반환됩니다. 이름은 **내부 링크에 대해 절대 반환되지 않으며**, 정의되지 않은 대상은 링크가 무시되도록 합니다.\"\n\n#: ../../page.rst:2329 364ae5f61f534e0cb85fe46e668d9750\nmsgid \"Writing\"\nmsgstr \"작성\"\n\n#: ../../page.rst:2331 b3e125859d70416e8b18693ae72bc7c2\nmsgid \"\"\n\"PyMuPDF writes (updates, inserts) links by constructing and writing the \"\n\"appropriate PDF object **source**. This makes it possible to specify \"\n\"indirect destinations for *LINK_GOTOR* **and** *LINK_GOTO* link kinds \"\n\"(pre *PDF 1.2* file formats are **not supported**).\"\nmsgstr \"\"\n\"|PyMuPDF| 는 적절한 PDF 객체 **소스** 를 구성하고 작성하여 링크를 작성(업데이트, 삽입)합니다. 이것은 *LINK_GOTOR* **및** *LINK_GOTO* 링크 종류에 대해 간접 대상을 지정할 수 있게 합니다(*PDF 1.2* 이전 파일 형식은 **지원되지 않습니다**).\"\n\n#: ../../page.rst:2333 e852dc9617584ee58517aec2dc16cf16\nmsgid \"\"\n\"If a *LINK_GOTO* indirect destination specifies an undefined name, this \"\n\"link can later on not be found / read again with MuPDF / PyMuPDF. Other \"\n\"readers however **will** detect it, but flag it as erroneous.\"\nmsgstr \"\"\n\"*LINK_GOTO* 간접 대상이 정의되지 않은 이름을 지정하면 이 링크는 나중에 MuPDF / PyMuPDF 로 찾거나 다시 읽을 수 없습니다. 그러나 다른 리더는 **감지** 하지만 오류로 표시합니다.\"\n\n#: ../../page.rst:2335 3f1aee12b6824cf3b031cec169329f4a\nmsgid \"\"\n\"Indirect *LINK_GOTOR* destinations can in general of course not be \"\n\"checked for validity and are therefore **always accepted**.\"\nmsgstr \"\"\n\"간접 *LINK_GOTOR* 대상은 일반적으로 유효성을 확인할 수 없으므로 **항상 수락됩니다**.\"\n\n#: ../../page.rst:2337 a64fd9e78538459790a5e2a2c922d4ef\nmsgid \"\"\n\"**Example: How to insert a link pointing to another page in the same \"\n\"document**\"\nmsgstr \"\"\n\"**예제: 동일한 문서의 다른 페이지를 가리키는 링크를 삽입하는 방법**\"\n\n#: ../../page.rst:2339 66099395d24e4c07956dd70ca3e49b6d\nmsgid \"\"\n\"Determine the rectangle on the current page, where the link should be \"\n\"placed. This may be the bbox of an image or some text.\"\nmsgstr \"\"\n\"링크가 배치될 현재 페이지의 사각형을 결정합니다. 이것은 이미지 또는 일부 텍스트의 bbox일 수 있습니다.\"\n\n#: ../../page.rst:2341 eee66e0a08254b82833fe8c4bfea4c53\nmsgid \"\"\n\"Determine the target page number (\\\"pno\\\", 0-based) and a :ref:`Point` on\"\n\" it, where the link should be directed to.\"\nmsgstr \"\"\n\"대상 페이지 번호(\\\"pno\\\", 0 기반)와 링크가 향해야 할 그 위의 :ref:`Point` 를 결정합니다.\"\n\n#: ../../page.rst:2343 11f4142d175a4fb6b17070fcf3363118\n#, python-brace-format\nmsgid \"\"\n\"Create a dictionary `d = {\\\"kind\\\": pymupdf.LINK_GOTO, \\\"page\\\": pno, \"\n\"\\\"from\\\": bbox, \\\"to\\\": point}`.\"\nmsgstr \"\"\n\"딕셔너리 `d = {\\\"kind\\\": pymupdf.LINK_GOTO, \\\"page\\\": pno, \\\"from\\\": bbox, \\\"to\\\": point}` 를 생성합니다.\"\n\n#: ../../page.rst:2345 a4dcca662bf242b3a856fe37acc0d604\nmsgid \"Execute `page.insert_link(d)`.\"\nmsgstr \"`page.insert_link(d)` 를 실행합니다.\"\n\n#: ../../page.rst:2349 0382665d56da4efb9be9ff4a73c4d746\nmsgid \"Homologous Methods of :ref:`Document` and :ref:`Page`\"\nmsgstr \":ref:`Document` 및 :ref:`Page` 의 동종 메서드\"\n\n#: ../../page.rst:2350 e4415ec94f5448acbc079d4818b17baf\nmsgid \"\"\n\"This is an overview of homologous methods on the :ref:`Document` and on \"\n\"the :ref:`Page` level.\"\nmsgstr \"\"\n\"이것은 :ref:`Document` 및 :ref:`Page` 수준의 동종 메서드 개요입니다.\"\n\n#: ../../page.rst:2353 3ccac822355b4b54b940ed847bdcb0df\nmsgid \"**Document Level**\"\nmsgstr \"**문서 수준**\"\n\n#: ../../page.rst:2353 19b869eaaf114813a8abeb080e8aadd8\nmsgid \"**Page Level**\"\nmsgstr \"**페이지 수준**\"\n\n#: ../../page.rst:2355 e34587fd22b444f19d97e569757aced3\nmsgid \":meth:`Document.get_page_fonts`\"\nmsgstr \":meth:`Document.get_page_fonts`\"\n\n#: ../../page.rst:2356 9d5b4df7acc4415ca81db0fa50cdbc3a\nmsgid \":meth:`Document.get_page_images`\"\nmsgstr \":meth:`Document.get_page_images`\"\n\n#: ../../page.rst:2357 643565d4b5fb4159a0c4f6cb6eae52f1\nmsgid \":meth:`Document.get_page_pixmap`\"\nmsgstr \":meth:`Document.get_page_pixmap`\"\n\n#: ../../page.rst:2358 27b5577e8ff349ec8f0978b9cb964b62\nmsgid \":meth:`Document.get_page_text`\"\nmsgstr \":meth:`Document.get_page_text`\"\n\n#: ../../page.rst:2359 d901c33d20334d828b2167e39d71168c\nmsgid \":meth:`Document.search_page_for`\"\nmsgstr \":meth:`Document.search_page_for`\"\n\n#: ../../page.rst:2364 6719d58820ca4cbfb5fc796c06e1e36c\nmsgid \"\"\n\"Most document methods (left column) exist for convenience reasons, and \"\n\"are just wrappers for: *Document[pno].<page method>*. So they **load and \"\n\"discard the page** on each execution.\"\nmsgstr \"\"\n\"대부분의 문서 메서드(왼쪽 열)는 편의를 위해 존재하며, *Document[pno].<page method>* 의 래퍼일 뿐입니다. 따라서 각 실행마다 **페이지를 로드하고 버립니다**.\"\n\n#: ../../page.rst:2366 5ce80e9cea8e4daea36d8f585ac861c3\nmsgid \"\"\n\"However, the first two methods work differently. They only need a page's \"\n\"object definition statement - the page itself will **not** be loaded. So \"\n\"e.g. :meth:`Page.get_fonts` is a wrapper the other way round and defined \"\n\"as follows: `page.get_fonts` == \"\n\"`page.parent.get_page_fonts(page.number)`.\"\nmsgstr \"\"\n\"그러나 처음 두 메서드는 다르게 작동합니다. 페이지의 객체 정의 문장만 필요하며 - 페이지 자체는 **로드되지 않습니다**. 따라서 예를 들어 :meth:`Page.get_fonts` 는 반대 방향의 래퍼이며 다음과 같이 정의됩니다: `page.get_fonts` == `page.parent.get_page_fonts(page.number)`.\"\n\n#: ../../page.rst:2369 8622914e93ee422e8ed1fb18a52b3757\nmsgid \"\"\n\"When calling the :ref:`Document` equivalent methods then the page number \"\n\"is sent through as a parameter, e.g.:\"\nmsgstr \"\"\n\":ref:`Document` 동등 메서드를 호출할 때 페이지 번호가 매개변수로 전달됩니다, 예:\"\n\n#: ../../page.rst:2371 6841df7218244a1dbd5c84d575bf0c61\nmsgid \"`Document.get_page_images(pno)` or `Document.get_page_text(pno)`\"\nmsgstr \"`Document.get_page_images(pno)` 또는 `Document.get_page_text(pno)`\"\n\n#: ../../page.rst:2375 9f0d6803a3b34da2a35934a9f4067f2f\nmsgid \"\"\n\"The page number parameter, ``pno``, is a 0-based integer `-∞ < pno < \"\n\"page_count`.\"\nmsgstr \"\"\n\"페이지 번호 매개변수 ``pno`` 는 0 기반 정수 `-∞ < pno < page_count` 입니다.\"\n\n#: ../../page.rst:2382 c7a27a60878d4c9681777a0657f5bfea\nmsgid \"Tables and Related Classes\"\nmsgstr \"테이블 및 관련 클래스\"\n\n#: ../../page.rst:2384 c3180e51a3bd4b778434ca0ae6c63d89\nmsgid \"\"\n\"The `TableFinder` class is returned by :meth:`Page.find_tables` and has \"\n\"related classes as follows:\"\nmsgstr \"\"\n\"`TableFinder` 클래스는 :meth:`Page.find_tables` 에 의해 반환되며 다음과 같은 관련 클래스가 있습니다:\"\n\n#: ../../page.rst:2389 64a011721da24744a543ab64c5a17f12\nmsgid \"\"\n\"An object always returned by :meth:`Page.find_tables`. Attributes of \"\n\"interest:\"\nmsgstr \"\"\n\":meth:`Page.find_tables` 에 의해 항상 반환되는 객체. 관심 있는 속성:\"\n\n#: ../../page.rst:2393 d2d360b0c7714f6eb39099281199a836\nmsgid \"\"\n\"A list of :class:`Table` objects, each of which represents a table found \"\n\"on the page. An empty list if no tables are found.\"\nmsgstr \"\"\n\":class:`Table` 객체의 리스트로, 각각 페이지에서 찾은 테이블을 나타냅니다. 테이블을 찾지 못하면 빈 리스트입니다.\"\n\n#: ../../page.rst:2397 00907877ee1e4ab88a27a827ca45fd8d\nmsgid \"A reference to the :ref:`Page` object.\"\nmsgstr \":ref:`Page` 객체에 대한 참조.\"\n\n#: ../../page.rst:2399 ../../page.rst:2411 4b46496341814f40addafebc3415c77d\n#: 6ccafe77babf49dda8f24e0fd508264d\nmsgid \":ref:`Page`\"\nmsgstr \":ref:`Page`\"\n\n#: ../../page.rst:2404 43201788a0d84d56b0b5c860766e84e2\nmsgid \"An object representing a table found on the page.\"\nmsgstr \"페이지에서 찾은 테이블을 나타내는 객체.\"\n\n#: ../../page.rst:2409 e91dd9e61a4844e68986275924bd2cd4\nmsgid \"A back-reference to the owning page.\"\nmsgstr \"소유 페이지에 대한 역참조.\"\n\n#: ../../page.rst:2415 820b3e94587549d5b34a3b7f1991677f\nmsgid \"An array of `Rect` objects for each cell in the table.\"\nmsgstr \"테이블의 각 셀에 대한 `Rect` 객체 배열.\"\n\n#: ../../page.rst:2417 ../../page.rst:2454 ../../page.rst:2461\n#: ../../page.rst:2498 ../../page.rst:2504 5fc25f510ea64ee1a073674ebe19775f\n#: 72a07ac5bc354429ba5e23029d97a6b2 7a63d658f0414ce6a03dc5da7b6480e6\n#: bd6ad1e8c71041faa53508d47736847a d1886569c90349efbb3e43f245bb097b\nmsgid \"list\"\nmsgstr \"list\"\n\n#: ../../page.rst:2422 56c6a33a1012473d92478e6bf2c37fc1\nmsgid \"A `TableHeader` object.\"\nmsgstr \"`TableHeader` 객체.\"\n\n#: ../../page.rst:2424 4469b33c46164b4db72edb980ccb08a5\nmsgid \"`TableHeader`\"\nmsgstr \"`TableHeader`\"\n\n#: ../../page.rst:2429 add249adfc084030b7eee6e9fb5a5a89\nmsgid \"The bounding box of all cells of the table header.\"\nmsgstr \"테이블 헤더의 모든 셀의 경계 상자.\"\n\n#: ../../page.rst:2438 2981f68aea22477086cc06adb314548f\nmsgid \"Number of rows in the table.\"\nmsgstr \"테이블의 행 수.\"\n\n#: ../../page.rst:2445 0d4f1e4b0c1541b9b30b52975b603789\nmsgid \"Number of columns in the table.\"\nmsgstr \"테이블의 열 수.\"\n\n#: ../../page.rst:2452 532d63f6689e48f08800ad2c8933c45c\nmsgid \"An array of `TableRow` objects for each row in the table.\"\nmsgstr \"테이블의 각 행에 대한 `TableRow` 객체 배열.\"\n\n#: ../../page.rst:2459 deb8a6d99ed24f249ad4d0d4fb8a73b4\nmsgid \"Extracts table cell text data into a list.\"\nmsgstr \"테이블 셀 텍스트 데이터를 리스트로 추출합니다.\"\n\n#: ../../page.rst:2465 75472d11e66d46b78b281cabdde38c94\nmsgid \"Extracts table data into Markdown text format.\"\nmsgstr \"테이블 데이터를 Markdown 텍스트 형식으로 추출합니다.\"\n\n#: ../../page.rst:2468 468354dc37774ae7aba42d9a80c27100\nmsgid \"If ``True`` then markdown syntax is removed from cell content.\"\nmsgstr \"``True`` 이면 셀 콘텐츠에서 markdown 구문이 제거됩니다.\"\n\n#: ../../page.rst:2469 aaa9083f16584794b6e61a2d29bfc670\nmsgid \"\"\n\"If ``True`` then cell content `None` is replaced by the values above \"\n\"(columns) or left (rows) in an effort to approximate row and columns \"\n\"spans.\"\nmsgstr \"\"\n\"``True`` 이면 셀 콘텐츠 `None` 이 행 및 열 스팬을 근사화하기 위해 위(열) 또는 왼쪽(행)의 값으로 대체됩니다.\"\n\n#: ../../page.rst:2472 7a34d01dee7e4826a33b05a0a8bca9cc\nmsgid \"string\"\nmsgstr \"string\"\n\n#: ../../page.rst:2477 7562b710618a431c97aaa09d4f4b34a6\nmsgid \"\"\n\"Return a `pandas DataFrame <https://pypi.org/project/pandas/>`_ \"\n\"`DataFrame <https://pandas.pydata.org/docs/reference/frame.html>`_ \"\n\"version of the table.\"\nmsgstr \"\"\n\"테이블의 `pandas DataFrame <https://pypi.org/project/pandas/>`_ `DataFrame <https://pandas.pydata.org/docs/reference/frame.html>`_ 버전을 반환합니다.\"\n\n#: ../../page.rst:2479 231c710e2ccf4932a300678886594ca6\nmsgid \"pandas DataFrame\"\nmsgstr \"pandas DataFrame\"\n\n#: ../../page.rst:2486 d3ce63902e7f477893ea546d16ae6490\nmsgid \"Dedicated class for table headers.\"\nmsgstr \"테이블 헤더를 위한 전용 클래스.\"\n\n#: ../../page.rst:2490 84e64f2efb644e2b821f471755bc37da\nmsgid \"\"\n\"The bounding box of the union of cells belonging to the table header, \"\n\"given as a tuple (x0, y0, x1, y1). This rectangle contains all table \"\n\"header cells.\"\nmsgstr \"\"\n\"테이블 헤더에 속하는 셀의 합집합의 경계 상자로, 튜플 (x0, y0, x1, y1)로 제공됩니다. 이 사각형은 모든 테이블 헤더 셀을 포함합니다.\"\n\n#: ../../page.rst:2496 8f36b12f2fe14dbd8d044038a58b9af6\nmsgid \"A list of tuples for each bbox of a column header.\"\nmsgstr \"각 열 헤더의 bbox에 대한 튜플 리스트.\"\n\n#: ../../page.rst:2502 9f497b636e214ba0ab62649bdbe7787f\nmsgid \"A list of strings with column header text.\"\nmsgstr \"열 헤더 텍스트가 있는 문자열 리스트.\"\n\n#: ../../page.rst:2508 ae8dc88588404f08b28f6531661b7c8e\nmsgid \"A boolean indicating whether the header is outside the table cells.\"\nmsgstr \"헤더가 테이블 셀 밖에 있는지 여부를 나타내는 불리언.\"\n\n#: ../../page.rst:2510 d3b5a1c6519e465e89e91926ae0aea3c\nmsgid \"`bool`\"\nmsgstr \"`bool`\"\n\n#: ../../page.rst:2515 45925d07fc014a9a99de73f5c477ac73\nmsgid \"Dedicated class for table rows.\"\nmsgstr \"테이블 행을 위한 전용 클래스.\"\n\n#: ../../page.rst:2522 4f1b3b275c9c4913ab0f3b3cfbbec93b\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../page.rst:2523 35b460330e4249f49081cee02ccc6687\nmsgid \"\"\n\"If your existing code already uses the installed base name as a font \"\n\"reference (as it was supported by PyMuPDF versions earlier than 1.14), \"\n\"this will continue to work.\"\nmsgstr \"\"\n\"기존 코드가 이미 설치된 기본 이름을 폰트 참조로 사용하는 경우(1.14 이전 |PyMuPDF| 버전에서 지원되었던 것처럼), 이것은 계속 작동합니다.\"\n\n#: ../../page.rst:2525 1f07318c687247dabdd707f1eaccb7bf\nmsgid \"\"\n\"Not all PDF reader software (including internet browsers and office \"\n\"software) display all of these fonts. And if they do, the difference \"\n\"between the **serifed** and the **non-serifed** version may hardly be \"\n\"noticeable. But serifed and non-serifed versions lead to different \"\n\"installed base fonts, thus providing an option to be displayable with \"\n\"your specific PDF viewer.\"\nmsgstr \"\"\n\"모든 PDF 리더 소프트웨어(인터넷 브라우저 및 오피스 소프트웨어 포함)가 이러한 모든 폰트를 표시하는 것은 아닙니다. 표시하더라도 **세리프** 및 **비세리프** 버전 간의 차이는 거의 눈에 띄지 않을 수 있습니다. 하지만 세리프 및 비세리프 버전은 다른 설치된 기본 폰트로 이어지므로 특정 PDF 뷰어에서 표시 가능한 옵션을 제공합니다.\"\n\n#: ../../page.rst:2527 d9d100e5a3b64091a183af6296efa37c\nmsgid \"\"\n\"Not all PDF readers display these fonts at all. Some others do, but use a\"\n\" wrong character spacing, etc.\"\nmsgstr \"\"\n\"모든 PDF 리더가 이러한 폰트를 표시하는 것은 아닙니다. 일부는 표시하지만 잘못된 문자 간격 등을 사용합니다.\"\n\n#: ../../page.rst:2529 35028b7ef49143b4816821764f1b95cf\nmsgid \"\"\n\"You are generally free to choose any of the :ref:`mupdficons` you \"\n\"consider adequate.\"\nmsgstr \"\"\n\"일반적으로 적절하다고 생각하는 :ref:`mupdficons` 중 하나를 자유롭게 선택할 수 있습니다.\"\n\n#: ../../page.rst:2531 5b91f7ee061349e9ab8627329a680560\nmsgid \"\"\n\"The previous algorithm caused images to be **shrunk** to this \"\n\"intersection. Now the image can be anywhere on :attr:`Page.mediabox`, \"\n\"potentially being invisible or only partially visible if the cropbox \"\n\"(representing the visible page part) is smaller.\"\nmsgstr \"\"\n\"이전 알고리즘은 이미지를 이 교차점으로 **축소** 시켰습니다. 이제 이미지는 :attr:`Page.mediabox` 의 어디에나 있을 수 있으며, cropbox(보이는 페이지 부분을 나타냄)가 더 작으면 보이지 않거나 부분적으로만 보일 수 있습니다.\"\n\n#: ../../page.rst:2533 bb430f8f65514d70b8096713c386f20f\nmsgid \"\"\n\"If you need to also see annotations or fields in the target page, you can\"\n\" convert the source PDF using :meth:`Document.bake`. The underlying MuPDF\"\n\" function of that method will convert these objects to normal page \"\n\"content. Then use :meth:`Page.show_pdf_page` with the converted PDF page.\"\nmsgstr \"\"\n\"대상 페이지에서 주석이나 필드도 보려면 :meth:`Document.bake` 를 사용하여 소스 PDF를 변환할 수 있습니다. 해당 메서드의 기본 MuPDF 함수는 이러한 객체를 일반 페이지 콘텐츠로 변환합니다. 그런 다음 변환된 PDF 페이지와 함께 :meth:`Page.show_pdf_page` 를 사용하세요.\"\n\n#: ../../page.rst:2535 77c93b6fd9f24046b632e932a9401d83\nmsgid \"\"\n\"In PDF, an area enclosed by some lines or curves can have a property \"\n\"called \\\"orientation\\\". This is significant for switching on or off the \"\n\"fill color of that area when there exist multiple area overlaps - see \"\n\"discussion in method :meth:`Shape.finish` using the \\\"non-zero winding \"\n\"number\\\" rule. While orientation of curves, quads, triangles and other \"\n\"shapes enclosed by lines always was detectable, this has been impossible \"\n\"for \\\"re\\\" (rectangle) items in the past. Adding the orientation \"\n\"parameter now delivers the missing information.\"\nmsgstr \"\"\n\"PDF에서 일부 선이나 곡선으로 둘러싸인 영역은 \\\"orientation\\\"(방향)이라는 속성을 가질 수 있습니다. 이것은 여러 영역이 겹칠 때 해당 영역의 채우기 색상을 켜거나 끄는 데 중요합니다 - \\\"non-zero winding number\\\" 규칙을 사용하는 :meth:`Shape.finish` 메서드의 논의를 참조하세요. 선으로 둘러싸인 곡선, 사각형, 삼각형 및 기타 모양의 방향은 항상 감지 가능했지만, 과거에는 \\\"re\\\"(사각형) 항목에 대해 이것이 불가능했습니다. orientation 매개변수를 추가하면 이제 누락된 정보를 제공합니다.\"\n\n#: ../../page.rst:2537 5b3e04359c58461c9c342889056d8ac3\nmsgid \"\"\n\"Hyphenation detection simply means that if the last character of a line \"\n\"is \\\"-\\\", it will be assumed to be a continuation character. That \"\n\"character will not be found by text searching with its default flag \"\n\"setting. Please take note, that a MuPDF *line* may not always be what you\"\n\" expect: words separated by overly large gaps (e.g. caused by text \"\n\"justification) may constitute separate MuPDF lines. If then any of these \"\n\"words ends with a hyphen, it will only be found by text searching if \"\n\"hyphenation is switched off.\"\nmsgstr \"\"\n\"하이픈 감지는 단순히 줄의 마지막 문자가 \\\"-\\\"이면 연속 문자로 간주된다는 의미입니다. 해당 문자는 기본 플래그 설정으로 텍스트 검색에서 찾을 수 없습니다. MuPDF *line* 이 항상 예상하는 것과 같지 않을 수 있습니다: 과도하게 큰 간격(예: 텍스트 정당화로 인한)으로 구분된 단어는 별도의 MuPDF 줄을 구성할 수 있습니다. 그러면 이러한 단어 중 하나가 하이픈으로 끝나면 하이픈이 꺼져 있을 때만 텍스트 검색에서 찾을 수 있습니다.\"\n\n#: ../../page.rst:2539 d8f8e96dd085414a812fda2806633c43\nmsgid \"\"\n\"Objects inside the source page, like images, text or drawings, are never \"\n\"aware of whether their owning page now is under OC control inside the \"\n\"target PDF. If source page objects are OC-controlled in the source PDF, \"\n\"then this will not be retained on the target: they will become \"\n\"unconditionally visible.\"\nmsgstr \"\"\n\"소스 페이지 내의 객체(이미지, 텍스트 또는 그림 등)는 소유 페이지가 대상 PDF 내에서 OC 제어 하에 있는지 여부를 절대 인식하지 않습니다. 소스 페이지 객체가 소스 PDF에서 OC 제어되는 경우 이것은 대상에서 유지되지 않습니다: 무조건 표시됩니다.\"\n\n#: ../../page.rst:2541 ce46471c609a4a6182a93a337f577978\nmsgid \"\"\n\"This value is always 96, the default of the PDF interpreter. It **does \"\n\"not reflect** the resolution of the image itself. If you need the image's\"\n\" resolution, use the :meth:`Pixmap.xres` and :meth:`Pixmap.yres` \"\n\"attributes of the :ref:`Pixmap` created from the image binary.\"\nmsgstr \"\"\n\"이 값은 항상 96이며 PDF 인터프리터의 기본값입니다. 이것은 **이미지 자체의 해상도를 반영하지 않습니다**. 이미지의 해상도가 필요하면 이미지 바이너리에서 생성된 :ref:`Pixmap` 의 :meth:`Pixmap.xres` 및 :meth:`Pixmap.yres` 속성을 사용하세요.\"\n\n#: ../../footer.rst:57 48ae480fd42d45a79c92e95ead866afc\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/pixmap.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 77cdad9d379a4a459fb8f61a5126752b\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 32cc68ce63c240bdb7a2fdfe4d927af7\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 db64d0baaca745e7910c08e63ef36441\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../pixmap.rst:7 e0494509a30b4c1991cc5e57de63e15b\nmsgid \"Pixmap\"\nmsgstr \"Pixmap\"\n\n#: ../../pixmap.rst:9 32dd6915408a408ea1d9db1812927e46\nmsgid \"\"\n\"Pixmaps (\\\"pixel maps\\\") are objects at the heart of MuPDF's rendering \"\n\"capabilities. They represent plane rectangular sets of pixels. Each pixel\"\n\" is described by a number of bytes (\\\"components\\\") defining its color, \"\n\"plus an optional alpha byte defining its transparency.\"\nmsgstr \"픽스맵(\\\"pixel maps\\\")은 MuPDF의 렌더링 기능의 핵심 객체입니다. 평면 사각형 픽셀 집합을 나타냅니다. 각 픽셀은 색상을 정의하는 여러 바이트(\\\"components\\\")와 투명도를 정의하는 선택적 알파 바이트로 설명됩니다.\"\n\n#: ../../pixmap.rst:11 0ae7623584d34b0793a6b1689e2e9ff9\nmsgid \"\"\n\"In PyMuPDF, there exist several ways to create a pixmap. Except the first\"\n\" one, all of them are available as overloaded constructors. A pixmap can \"\n\"be created ...\"\nmsgstr \"PyMuPDF에서는 픽스맵을 생성하는 여러 방법이 있습니다. 첫 번째를 제외하고 모두 오버로드된 생성자로 사용할 수 있습니다. 픽스맵은 다음에서 생성할 수 있습니다...\"\n\n#: ../../pixmap.rst:13 73ba045692a74b84a13ce27f369588ef\nmsgid \"from a document page (method :meth:`Page.get_pixmap`)\"\nmsgstr \"문서 페이지에서 (메서드 :meth:`Page.get_pixmap`)\"\n\n#: ../../pixmap.rst:14 d9db8727d6f34c5ea67a95212b48a901\nmsgid \"empty, based on :ref:`Colorspace` and :ref:`IRect` information\"\nmsgstr \":ref:`Colorspace` 및 :ref:`IRect` 정보를 기반으로 빈 픽스맵\"\n\n#: ../../pixmap.rst:15 3bd37a5d119449b79b2df8e6183899b2\nmsgid \"from a file\"\nmsgstr \"파일에서\"\n\n#: ../../pixmap.rst:16 6c2ae5d2cf9e4e9c8a85876940ac2c65\nmsgid \"from an in-memory image\"\nmsgstr \"메모리 내 이미지에서\"\n\n#: ../../pixmap.rst:17 985854117e77421ab5c08305ad9a7ebc\nmsgid \"from a memory area of plain pixels\"\nmsgstr \"일반 픽셀의 메모리 영역에서\"\n\n#: ../../pixmap.rst:18 51817c0b224a4d79becc251812e52d59\nmsgid \"from an image inside a PDF document\"\nmsgstr \"PDF 문서 내의 이미지에서\"\n\n#: ../../pixmap.rst:19 c50a8dabd5de4315af9f49bd6f4e3300\nmsgid \"as a copy of another pixmap\"\nmsgstr \"다른 픽스맵의 복사본으로\"\n\n#: ../../pixmap.rst:21 a40603d11eae465f98c51d914e3f60f0\nmsgid \"\"\n\"A number of image formats is supported as input for points 3. and 4. \"\n\"above. See section :ref:`ImageFiles`.\"\nmsgstr \"위의 3번과 4번 항목에 대한 입력으로 여러 이미지 형식이 지원됩니다. :ref:`ImageFiles` 섹션을 참조하세요.\"\n\n#: ../../pixmap.rst:23 3bdce298316f4c59aea2dcf926ba360d\nmsgid \"\"\n\"Have a look at the :ref:`FAQ` section to see some pixmap usage \\\"at \"\n\"work\\\".\"\nmsgstr \":ref:`FAQ` 섹션을 확인하여 픽스맵 사용 예제를 살펴보세요.\"\n\n#: ../../pixmap.rst:26 c77d9f0a0ac441569275429f77da5352\nmsgid \"**Method / Attribute**\"\nmsgstr \"**Method / Attribute**\"\n\n#: ../../pixmap.rst:26 0c5aa62f906e4af38c4f3f15dbd58acb\nmsgid \"**Short Description**\"\nmsgstr \"**Short Description**\"\n\n#: ../../pixmap.rst:28 2202b52b548143ffb14aef4ce3088e4e\nmsgid \":meth:`Pixmap.clear_with`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:28 f8c6fd586d294e3194f9966984db1cd7\nmsgid \"clear parts of the pixmap\"\nmsgstr \"픽스맵의 일부 지우기\"\n\n#: ../../pixmap.rst:29 74887257fa9a4ce4bccdc2c054561ab8\nmsgid \":meth:`Pixmap.color_count`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:29 266d94deb7124050adc51b2d0925c285\nmsgid \"determine used colors\"\nmsgstr \"사용된 색상 확인\"\n\n#: ../../pixmap.rst:30 6fa71e0e57754c778d2a793a2d4b5e0c\nmsgid \":meth:`Pixmap.color_topusage`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:30 40a15ae449a04a5fa2c777c1ac0a6175\nmsgid \"determine share of most used color\"\nmsgstr \"가장 많이 사용된 색상의 비율 확인\"\n\n#: ../../pixmap.rst:31 b915ce033980496eb00292ada4fbcca5\nmsgid \":meth:`Pixmap.copy`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:31 8e57cd2829fa414abc482e80c6d4c4d9\nmsgid \"copy parts of another pixmap\"\nmsgstr \"다른 픽스맵의 일부 복사\"\n\n#: ../../pixmap.rst:32 112981a34c4348f8ad862d81cdc02514\nmsgid \":meth:`Pixmap.gamma_with`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:32 f42a9b37c4ac4000a006188d993c87e5\nmsgid \"apply a gamma factor to the pixmap\"\nmsgstr \"픽스맵에 감마 계수 적용\"\n\n#: ../../pixmap.rst:33 01c950df9e2145aa8d39d7760c67ad87\nmsgid \":meth:`Pixmap.invert_irect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:33 8fd44b50652147ff824e5fc414ff6a30\nmsgid \"invert the pixels of a given area\"\nmsgstr \"주어진 영역의 픽셀 반전\"\n\n#: ../../pixmap.rst:34 516fe80e3c4a459a81a150dc6a462f8e\nmsgid \":meth:`Pixmap.pdfocr_save`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:34 ../../pixmap.rst:35 67e410a8f8c842c1944b038c5708de2d\n#: f38b40a1d99c4c509644c872d19b87e2\nmsgid \"save the pixmap as an OCRed 1-page PDF\"\nmsgstr \"픽스맵을 OCR된 1페이지 PDF로 저장\"\n\n#: ../../pixmap.rst:35 be86eecb9ae84058896ab1db4a2fcab1\nmsgid \":meth:`Pixmap.pdfocr_tobytes`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:36 b0881e3fa8064b569e1476c50325b3d7\nmsgid \":meth:`Pixmap.pil_image`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:36 6075a73ecdcb46979d4b836f39403d5f\nmsgid \"create a Pillow Image\"\nmsgstr \"Pillow 이미지 생성\"\n\n#: ../../pixmap.rst:37 c71cca896c4e47509c4fa0e362fa044c\nmsgid \":meth:`Pixmap.pil_save`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:37 4be536342cb047aeb0a6b64adbba1e9a\nmsgid \"save as a Pillow Image\"\nmsgstr \"Pillow 이미지로 저장\"\n\n#: ../../pixmap.rst:38 52b8400d5cce434b87e23399f61d2117\nmsgid \":meth:`Pixmap.pil_tobytes`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:38 bafc4631127f4561936ab5d1e6403a2d\nmsgid \"write to `bytes` as a Pillow Image\"\nmsgstr \"Pillow 이미지로 `bytes` 에 쓰기\"\n\n#: ../../pixmap.rst:39 4002db687ffc4feabe3a41f2274b7804\nmsgid \":meth:`Pixmap.pixel`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:39 efb78dfb56524049a7580e3a15723114\nmsgid \"return the value of a pixel\"\nmsgstr \"픽셀 값 반환\"\n\n#: ../../pixmap.rst:40 e0ffa2a456944476bb6984b064566f95\nmsgid \":meth:`Pixmap.save`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:40 7f4131a6b70d41cd802f09e3f4f6f11f\nmsgid \"save the pixmap in a variety of formats\"\nmsgstr \"다양한 형식으로 픽스맵 저장\"\n\n#: ../../pixmap.rst:41 23956dccd6e94052aef51929b1c393dc\nmsgid \":meth:`Pixmap.set_alpha`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:41 3979119c35f341c694e03dd5db7a0115\nmsgid \"set alpha values\"\nmsgstr \"알파 값 설정\"\n\n#: ../../pixmap.rst:42 80aa084bf73c4f61abbf2f808d42bdcd\nmsgid \":meth:`Pixmap.set_dpi`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:42 881510d8c71545b59d91fb5dac173605\nmsgid \"set the image resolution\"\nmsgstr \"이미지 해상도 설정\"\n\n#: ../../pixmap.rst:43 af00886d005e4a1890d7b7789b93e7e7\nmsgid \":meth:`Pixmap.set_origin`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:43 7e6045d9838046cea1cd1fcb38a15dab\nmsgid \"set pixmap x,y values\"\nmsgstr \"픽스맵 x, y 값 설정\"\n\n#: ../../pixmap.rst:44 cb25eecee8af4917ab427d3cf303152f\nmsgid \":meth:`Pixmap.set_pixel`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:44 23d1909be60a4b269aaec2547ae2aa05\nmsgid \"set color and alpha of a pixel\"\nmsgstr \"픽셀의 색상 및 알파 설정\"\n\n#: ../../pixmap.rst:45 72b4d710dc894939936c377380bbc22e\nmsgid \":meth:`Pixmap.set_rect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:45 0f7af78460a4450da9d9108517b4d4c4\nmsgid \"set color and alpha of all pixels in a rectangle\"\nmsgstr \"사각형 내 모든 픽셀의 색상 및 알파 설정\"\n\n#: ../../pixmap.rst:46 b791b993ad61409eaef1d0b360847ffc\nmsgid \":meth:`Pixmap.shrink`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:46 38e21b2c7aa8493e8bb7266e1e835f69\nmsgid \"reduce size keeping proportions\"\nmsgstr \"비율을 유지하면서 크기 축소\"\n\n#: ../../pixmap.rst:47 be56d7fc15e24cf2826c82badd69df56\nmsgid \":meth:`Pixmap.tint_with`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:47 d5a1e740218c41ceb31d912cae43599f\nmsgid \"tint the pixmap\"\nmsgstr \"픽스맵에 틴트 적용\"\n\n#: ../../pixmap.rst:48 408bd07e5e004c53845a34ccb73684f6\nmsgid \":meth:`Pixmap.tobytes`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:48 dbfd2cd88a2e40689877d688108593b5\nmsgid \"return a memory area in a variety of formats\"\nmsgstr \"다양한 형식으로 메모리 영역 반환\"\n\n#: ../../pixmap.rst:49 73ad7e8e412146939a933bc554653bd9\nmsgid \":meth:`Pixmap.warp`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:49 27dcdd34ccd6434c8be2f3d0cab9f361\nmsgid \"return a pixmap made from a quad inside\"\nmsgstr \"내부의 quad로 만든 픽스맵 반환\"\n\n#: ../../pixmap.rst:50 85defbb4523445e9bfc92785c42fcb0b\nmsgid \":attr:`Pixmap.alpha`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:50 f9f7e74d1a854ce584726e3236d915a4\nmsgid \"transparency indicator\"\nmsgstr \"투명도 표시기\"\n\n#: ../../pixmap.rst:51 fbf1760092864dcf8f5566ac85074c05\nmsgid \":attr:`Pixmap.colorspace`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:51 48b501a974724e6cadfe58ebbfebeb9a\nmsgid \"pixmap's :ref:`Colorspace`\"\nmsgstr \"픽스맵의 :ref:`Colorspace`\"\n\n#: ../../pixmap.rst:52 b766c11c9d60491bb1cd9e4c8cfd9751\nmsgid \":attr:`Pixmap.digest`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:52 3d7b532618f3451896efe2d64d4ffdfe\nmsgid \"MD5 hashcode of the pixmap\"\nmsgstr \"픽스맵의 MD5 해시코드\"\n\n#: ../../pixmap.rst:53 76675540ad27482bada64b6a598d25f9\nmsgid \":attr:`Pixmap.height`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:53 3c22531079e34fa79dddc4e586d958e6\nmsgid \"pixmap height\"\nmsgstr \"픽스맵 높이\"\n\n#: ../../pixmap.rst:54 9182d024c67b490b9fe7855b4f5715d0\nmsgid \":attr:`Pixmap.interpolate`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:54 3688b5e0286840669d320a95bc5a17fb\nmsgid \"interpolation method indicator\"\nmsgstr \"보간 방법 표시기\"\n\n#: ../../pixmap.rst:55 b7b0a90b1ba846e89b22db0ed4553281\nmsgid \":attr:`Pixmap.is_monochrome`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:55 df352c76b67546089f124cbd0e5babb1\nmsgid \"check if only black and white occur\"\nmsgstr \"흑백만 있는지 확인\"\n\n#: ../../pixmap.rst:56 a17ad0a90a7d413c9fb8b1aa83257598\nmsgid \":attr:`Pixmap.is_unicolor`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:56 81dfed8a598641f6ae936549b0e7f7ba\nmsgid \"check if only one color occurs\"\nmsgstr \"단일 색상만 있는지 확인\"\n\n#: ../../pixmap.rst:57 abd7ff4e70754c9daef32d9525250608\nmsgid \":attr:`Pixmap.irect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:57 2791b580e848470a814a376d6e220255\nmsgid \":ref:`IRect` of the pixmap\"\nmsgstr \"픽스맵의 :ref:`IRect`\"\n\n#: ../../pixmap.rst:58 2fec6f3a895d4409b0e482a40f200f22\nmsgid \":attr:`Pixmap.n`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:58 c7b79f65d4494cdb897cc22abe8eff21\nmsgid \"bytes per pixel\"\nmsgstr \"픽셀당 바이트\"\n\n#: ../../pixmap.rst:59 743bc8e881d44773b5fcf7beffc6a3fa\nmsgid \":attr:`Pixmap.samples_mv`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:59 4179ce00d1e746b295e577083af074b0\nmsgid \"`memoryview` of pixel area\"\nmsgstr \"픽셀 영역의 `memoryview`\"\n\n#: ../../pixmap.rst:60 c5ff63d0faaa4137832a944521ce8069\nmsgid \":attr:`Pixmap.samples_ptr`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:60 8116e2e6a5fe470082d7fbdca4673935\nmsgid \"Python pointer to pixel area\"\nmsgstr \"픽셀 영역에 대한 Python 포인터\"\n\n#: ../../pixmap.rst:61 2abc33dc84a348c6ad9b8da90c57e531\nmsgid \":attr:`Pixmap.samples`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:61 060cb94948d84088a5cf7c6d4319fea3\nmsgid \"`bytes` copy of pixel area\"\nmsgstr \"픽셀 영역의 `bytes` 복사본\"\n\n#: ../../pixmap.rst:62 d41ed2ab508249d0ae96e3145e92258b\nmsgid \":attr:`Pixmap.size`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:62 cfe014376f9745ea9c2ce0e7a11bb369\nmsgid \"pixmap's total length\"\nmsgstr \"픽스맵의 전체 길이\"\n\n#: ../../pixmap.rst:63 34fea4631d014515b7406f2f5bb813bc\nmsgid \":attr:`Pixmap.stride`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:63 5a29f36af34340aea9cba617eed85cc6\nmsgid \"size of one image row\"\nmsgstr \"이미지 한 행의 크기\"\n\n#: ../../pixmap.rst:64 62ed9c389676438299a427713f0f7b08\nmsgid \":attr:`Pixmap.width`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:64 70e7618e0783483ea97302b042784152\nmsgid \"pixmap width\"\nmsgstr \"픽스맵 너비\"\n\n#: ../../pixmap.rst:65 e62961e6786e48c796a2e5a23a76654f\nmsgid \":attr:`Pixmap.x`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:65 4e8faa2fe6154453bf50951bfbcbfa0e\nmsgid \"X-coordinate of top-left corner\"\nmsgstr \"왼쪽 위 모서리의 X 좌표\"\n\n#: ../../pixmap.rst:66 d69ccf0ae1844b88aaff3eb7fbfa1973\nmsgid \":attr:`Pixmap.xres`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:66 a1ecbc77214845fea2e4c6cee89a8ce8\nmsgid \"resolution in X-direction\"\nmsgstr \"X 방향 해상도\"\n\n#: ../../pixmap.rst:67 83ca1188acde43af9c9f6c742f8c9fcb\nmsgid \":attr:`Pixmap.y`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:67 b0432d623ef4473aa3515de8b215d9f5\nmsgid \"Y-coordinate of top-left corner\"\nmsgstr \"왼쪽 위 모서리의 Y 좌표\"\n\n#: ../../pixmap.rst:68 b704d755356e4e53903e4306cb1850d6\nmsgid \":attr:`Pixmap.yres`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:68 857aeb5083a44b1795d1ede13f95021f\nmsgid \"resolution in Y-direction\"\nmsgstr \"Y 방향 해상도\"\n\n#: ../../pixmap.rst:71 a006e37a45ad4ed88da3603714dc9820\nmsgid \"**Class API**\"\nmsgstr \"**Class API**\"\n\n#: ../../pixmap.rst:77 046bff7f68fe47dc89b42ec79b63be49\nmsgid \"\"\n\"**New empty pixmap:** Create an empty pixmap of size and origin given by \"\n\"the rectangle. So, *irect.top_left* designates the top left corner of the\"\n\" pixmap, and its width and height are *irect.width* resp. *irect.height*.\"\n\" Note that the image area is **not initialized** and will contain crap \"\n\"data -- use eg. :meth:`clear_with` or :meth:`set_rect` to be sure.\"\nmsgstr \"**새 빈 픽스맵:** 사각형으로 지정된 크기와 원점으로 빈 픽스맵을 생성합니다. 따라서 *irect.top_left* 는 픽스맵의 왼쪽 위 모서리를 지정하고, 너비와 높이는 각각 *irect.width* 및 *irect.height* 입니다. 이미지 영역은 **초기화되지 않으며** 쓰레기 데이터를 포함합니다 -- 예를 들어 :meth:`clear_with` 또는 :meth:`set_rect` 를 사용하여 확실히 하세요.\"\n\n#: ../../pixmap.rst 02b0fea3d9c34817aad000ad9f071590\n#: 054aba92b788492e988045fb104e4481 0eb0df83e45a406cb560af5072cdff86\n#: 2d9ab2f5c1024f7085600fc7ec9dc603 42fca49eb0844237a0b14c72c95e7dbc\n#: 4c84fc0dcb054b659ed6e2dae1b27605 57542313cdbd47cc89f43d9329495cb5\n#: 610dfac6df044219bea31b4eb7ef6b47 63f20c0df7eb4be8be807f287c781d58\n#: 67a50e42c1294501bb59b8b035850481 687444f1e3dc45509b4ec2a7192c0a48\n#: 73fe0913c7364c31916311fc0cffc16e 7e25b63146fa45858f1ff6b966a16913\n#: 8b3e2416c26c445bb9979be602f6adf5 95824bfb86ff41de835e47b77393048f\n#: a5c5caaf10934649be3b74635eb16787 af618a04af8e40efa6512d296a27fb9b\n#: bdfbcea144bd4cfb93f787f52dfadf48 c7f77794bd054561aa08e0b18497e5bd\n#: d044792ccaea48328805a0a6efd678c9 d625b8ee73b34a459873edc513b40002\n#: d81abb686bb542518846ad32bd035b5e dd1276958278455fb3ad0d1ad3b08045\n#: dd4e9e5837dc4c1eb17ec63c8681b4d4 e60d8f4e03c24b918ad9bdf22e21adb0\n#: f1bff3e4b66c4afca6ae66a014ac0fc1 f2e0f5d755134588846f75c89c28b5af\n#: f8a2e37bd2ef4ca79bf827a1a3fe8e70\nmsgid \"Parameters\"\nmsgstr \"Parameters\"\n\n#: ../../pixmap.rst:79 56321802a9014c348fa2d20d4294c9f2\nmsgid \"colorspace.\"\nmsgstr \"색상 공간.\"\n\n#: ../../pixmap.rst:82 3753a76b227f496eb369ca2d40057f0c\nmsgid \"The pixmap's position and dimension.\"\nmsgstr \"픽스맵의 위치 및 크기.\"\n\n#: ../../pixmap.rst:84 0f1256f4866c4a888d73cefe035cfb17\nmsgid \"\"\n\"Specifies whether transparency bytes should be included. Default is \"\n\"``False``.\"\nmsgstr \"투명도 바이트를 포함할지 여부를 지정합니다. 기본값은 ``False`` 입니다.\"\n\n#: ../../pixmap.rst:88 b9326c334f6345fdaf185501bfa27892\nmsgid \"\"\n\"**Copy and set colorspace:** Copy *source* pixmap converting colorspace. \"\n\"Any colorspace combination is possible, but source colorspace must not be\"\n\" ``None``.\"\nmsgstr \"**복사 및 색상 공간 설정:** 색상 공간을 변환하여 *source* 픽스맵을 복사합니다. 모든 색상 공간 조합이 가능하지만 소스 색상 공간은 ``None`` 이 아니어야 합니다.\"\n\n#: ../../pixmap.rst:90 97014f607fba4a5cb553297120c90034\nmsgid \"\"\n\"desired **target** colorspace. This **may also be** ``None``. In this \"\n\"case, a \\\"masking\\\" pixmap is created: its :attr:`Pixmap.samples` will \"\n\"consist of the source's alpha bytes only.\"\nmsgstr \"원하는 **대상** 색상 공간. 이것은 ``None`` 일 수도 있습니다. 이 경우 \\\"마스킹\\\" 픽스맵이 생성됩니다: :attr:`Pixmap.samples` 는 소스의 알파 바이트만으로 구성됩니다.\"\n\n#: ../../pixmap.rst:93 ../../pixmap.rst:112 36ef86e1d48d4c5a9dd2bf95b2fd7b14\n#: 52423174b9b746d2840bdc738fa82069\nmsgid \"the source pixmap.\"\nmsgstr \"소스 픽스맵.\"\n\n#: ../../pixmap.rst:98 1df405a79ae244d1a01b677a84951540\nmsgid \"New in v1.18.18\"\nmsgstr \"v1.18.18에서 새로 추가됨\"\n\n#: ../../pixmap.rst:100 dac52c1c940a488587523e971b8678bb\nmsgid \"\"\n\"**Copy and add image mask:** Copy *source* pixmap, add an alpha channel \"\n\"with transparency data from a mask pixmap.\"\nmsgstr \"**복사 및 이미지 마스크 추가:** *source* 픽스맵을 복사하고 마스크 픽스맵의 투명도 데이터로 알파 채널을 추가합니다.\"\n\n#: ../../pixmap.rst:102 760c74ba53044cbcbdf31aee15f90bca\nmsgid \"pixmap without alpha channel.\"\nmsgstr \"알파 채널이 없는 픽스맵.\"\n\n#: ../../pixmap.rst:105 46e5c3640fcf48d382edee1c823984e6\nmsgid \"a mask pixmap. Must be a graysale pixmap.\"\nmsgstr \"마스크 픽스맵. 그레이스케일 픽스맵이어야 합니다.\"\n\n#: ../../pixmap.rst:110 d9ec3e84c0ea4239b426990e4164290e\nmsgid \"\"\n\"**Copy and scale:** Copy *source* pixmap, scaling new width and height \"\n\"values -- the image will appear stretched or shrunk accordingly. Supports\"\n\" partial copying. The source colorspace may be ``None``.\"\nmsgstr \"**복사 및 크기 조정:** *source* 픽스맵을 복사하고 새로운 너비와 높이 값을 조정합니다 -- 이미지는 그에 따라 늘어나거나 줄어듭니다. 부분 복사를 지원합니다. 소스 색상 공간은 ``None`` 일 수 있습니다.\"\n\n#: ../../pixmap.rst:115 682ea20bf52b4efe901eaeac97e98829\nmsgid \"desired target width.\"\nmsgstr \"원하는 대상 너비.\"\n\n#: ../../pixmap.rst:117 3bf8da6692aa4465bad88ed923353c01\nmsgid \"desired target height.\"\nmsgstr \"원하는 대상 높이.\"\n\n#: ../../pixmap.rst:119 7aa6286551464fc79c589f402e5f4064\nmsgid \"restrict the resulting pixmap to this region of the **scaled** pixmap.\"\nmsgstr \"결과 픽스맵을 **크기 조정된** 픽스맵의 이 영역으로 제한합니다.\"\n\n#: ../../pixmap.rst:121 3be7525712a64bad8e5cc168ff57efeb\nmsgid \"\"\n\"If width or height do not *represent* integers (i.e. `value.is_integer() \"\n\"!= True`), then the resulting pixmap **will have an alpha channel**.\"\nmsgstr \"너비 또는 높이가 정수를 *나타내지* 않으면(즉, `value.is_integer() != True`), 결과 픽스맵은 **알파 채널을 가집니다**.\"\n\n#: ../../pixmap.rst:125 fcd3877dc9924a5098cb10a1fec25153\nmsgid \"\"\n\"**Copy and add or drop alpha:** Copy *source* and add or drop its alpha \"\n\"channel. Identical copy if *alpha* equals *source.alpha*. If an alpha \"\n\"channel is added, its values will be set to 255.\"\nmsgstr \"**복사 및 알파 추가 또는 제거:** *source* 를 복사하고 알파 채널을 추가하거나 제거합니다. *alpha* 가 *source.alpha* 와 같으면 동일한 복사본입니다. 알파 채널이 추가되면 값은 255로 설정됩니다.\"\n\n#: ../../pixmap.rst:127 ../../pixmap.rst:305 29341e581eda460c9963b056957f0057\n#: 6755e67f1ebd4c6397a96a8387727fc0\nmsgid \"source pixmap.\"\nmsgstr \"소스 픽스맵.\"\n\n#: ../../pixmap.rst:130 c616e3541c6f481680da4d95d038b5f5\nmsgid \"\"\n\"whether the target will have an alpha channel, default and mandatory if \"\n\"source colorspace is ``None``.\"\nmsgstr \"대상이 알파 채널을 가질지 여부, 소스 색상 공간이 ``None`` 이면 기본값이며 필수입니다.\"\n\n#: ../../pixmap.rst:132 df4cef61a1c149a39965a6f332bf9f2c\nmsgid \"\"\n\"A typical use includes separation of color and transparency bytes in \"\n\"separate pixmaps. Some applications require this like e.g. \"\n\"*wx.Bitmap.FromBufferAndAlpha()* of *wxPython*:\"\nmsgstr \"일반적인 사용에는 별도의 픽스맵에서 색상 및 투명도 바이트를 분리하는 것이 포함됩니다. 일부 애플리케이션은 예를 들어 *wxPython* 의 *wx.Bitmap.FromBufferAndAlpha()* 와 같이 이를 요구합니다:\"\n\n#: ../../pixmap.rst:142 154d69621fb94872a7ad34eae19ef7aa\nmsgid \"\"\n\"**From a file:** Create a pixmap from *filename*. All properties are \"\n\"inferred from the input. The origin of the resulting pixmap is *(0, 0)*.\"\nmsgstr \"**파일에서:** *filename* 에서 픽스맵을 생성합니다. 모든 속성은 입력에서 추론됩니다. 결과 픽스맵의 원점은 *(0, 0)* 입니다.\"\n\n#: ../../pixmap.rst:144 aedb335cf31242c6807afec841343b05\nmsgid \"Path of the image file.\"\nmsgstr \"이미지 파일의 경로.\"\n\n#: ../../pixmap.rst:148 e21d860e62cb466b8dcd5c58ecd8816a\nmsgid \"\"\n\"**From memory:** Create a pixmap from a memory area. All properties are \"\n\"inferred from the input. The origin of the resulting pixmap is *(0, 0)*.\"\nmsgstr \"**메모리에서:** 메모리 영역에서 픽스맵을 생성합니다. 모든 속성은 입력에서 추론됩니다. 결과 픽스맵의 원점은 *(0, 0)* 입니다.\"\n\n#: ../../pixmap.rst:150 74221d3aec5f41afae36e2b37ac8dfc7\nmsgid \"\"\n\"Data containing a complete, valid image. Could have been created by e.g. \"\n\"*stream = bytearray(open('image.file', 'rb').read())*. Type *bytes* is \"\n\"supported in **Python 3 only**, because *bytes == str* in Python 2 and \"\n\"the method will interpret the stream as a filename.  *Changed in version \"\n\"1.14.13:* *io.BytesIO* is now also supported.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:150 e9ed395c0d8c4b56a458e072bbd347e0\nmsgid \"\"\n\"Data containing a complete, valid image. Could have been created by e.g. \"\n\"*stream = bytearray(open('image.file', 'rb').read())*. Type *bytes* is \"\n\"supported in **Python 3 only**, because *bytes == str* in Python 2 and \"\n\"the method will interpret the stream as a filename.\"\nmsgstr \"완전하고 유효한 이미지를 포함하는 데이터. 예를 들어 *stream = bytearray(open('image.file', 'rb').read())* 로 생성되었을 수 있습니다. *bytes* 타입은 **Python 3에서만** 지원됩니다. Python 2에서는 *bytes == str* 이므로 메서드가 스트림을 파일 이름으로 해석합니다.\"\n\n#: ../../pixmap.rst:152 a162db2d5e5f46a092952a708f6e5469\nmsgid \"*Changed in version 1.14.13:* *io.BytesIO* is now also supported.\"\nmsgstr \"*버전 1.14.13에서 변경됨:* 이제 *io.BytesIO* 도 지원됩니다.\"\n\n#: ../../pixmap.rst:157 016950d3c686415a993d228b20deed87\nmsgid \"\"\n\"**From plain pixels:** Create a pixmap from *samples*. Each pixel must be\"\n\" represented by a number of bytes as controlled by the *colorspace* and \"\n\"*alpha* parameters. The origin of the resulting pixmap is *(0, 0)*. This \"\n\"method is useful when raw image data are provided by some other program \"\n\"-- see :ref:`FAQ`.\"\nmsgstr \"**일반 픽셀에서:** *samples* 에서 픽스맵을 생성합니다. 각 픽셀은 *colorspace* 및 *alpha* 매개변수에 의해 제어되는 여러 바이트로 표현되어야 합니다. 결과 픽스맵의 원점은 *(0, 0)* 입니다. 이 메서드는 다른 프로그램에서 원시 이미지 데이터가 제공될 때 유용합니다 -- :ref:`FAQ` 를 참조하세요.\"\n\n#: ../../pixmap.rst:159 cda1965dbe524b2f958354d3bf86203d\nmsgid \"Colorspace of image.\"\nmsgstr \"이미지의 색상 공간.\"\n\n#: ../../pixmap.rst:162 e4ca43e6639b433195a95bc4b9cff17c\nmsgid \"image width\"\nmsgstr \"이미지 너비\"\n\n#: ../../pixmap.rst:164 e6bd73524bf443928467e7d153097052\nmsgid \"image height\"\nmsgstr \"이미지 높이\"\n\n#: ../../pixmap.rst:166 bc04c5ee0a2f4c219321973a46ca1fec\nmsgid \"\"\n\"an area containing all pixels of the image. Must include alpha values if \"\n\"specified.  *Changed in version 1.14.13:* (1) *io.BytesIO* can now also \"\n\"be used. (2) Data are now **copied** to the pixmap, so may safely be \"\n\"deleted or become unavailable.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:166 882216b59426469ebf0fc58e1a590a22\nmsgid \"\"\n\"an area containing all pixels of the image. Must include alpha values if \"\n\"specified.\"\nmsgstr \"이미지의 모든 픽셀을 포함하는 영역. 지정된 경우 알파 값을 포함해야 합니다.\"\n\n#: ../../pixmap.rst:168 94da32783c284a7c9e5cd26b1aa7aead\nmsgid \"\"\n\"*Changed in version 1.14.13:* (1) *io.BytesIO* can now also be used. (2) \"\n\"Data are now **copied** to the pixmap, so may safely be deleted or become\"\n\" unavailable.\"\nmsgstr \"*버전 1.14.13에서 변경됨:* (1) 이제 *io.BytesIO* 도 사용할 수 있습니다. (2) 데이터가 이제 픽스맵에 **복사** 되므로 안전하게 삭제하거나 사용할 수 없게 만들 수 있습니다.\"\n\n#: ../../pixmap.rst:170 92e53d092aa1464db50b36eb7899219d\nmsgid \"whether a transparency channel is included.\"\nmsgstr \"투명도 채널이 포함되는지 여부.\"\n\n#: ../../pixmap.rst:174 d35de668e91d424ebf94418d892dcbd6\nmsgid \"\"\n\"The following equation **must be true**: *(colorspace.n + alpha) * width \"\n\"* height == len(samples)*.\"\nmsgstr \"다음 방정식이 **참이어야 합니다**: *(colorspace.n + alpha) * width * height == len(samples)*.\"\n\n#: ../../pixmap.rst:175 1c597631a5304c869da76bb9d81e6ed9\nmsgid \"\"\n\"Starting with version 1.14.13, the samples data are **copied** to the \"\n\"pixmap.\"\nmsgstr \"버전 1.14.13부터 samples 데이터가 픽스맵에 **복사** 됩니다.\"\n\n#: ../../pixmap.rst:180 5c8af01ebb9141c4b8de801dd3f3356e\nmsgid \"\"\n\"**From a PDF image:** Create a pixmap from an image **contained in PDF** \"\n\"*doc* identified by its :data:`xref`. All pimap properties are set by the\"\n\" image. Have a look at `extract-img1.py \"\n\"<https://github.com/pymupdf/PyMuPDF/tree/master/demo/extract-img1.py>`_ \"\n\"and `extract-img2.py <https://github.com/pymupdf/PyMuPDF/tree/master/demo\"\n\"/extract-img2.py>`_ to see how this can be used to recover all of a PDF's\"\n\" images.\"\nmsgstr \"**PDF 이미지에서:** :data:`xref` 로 식별되는 |PDF| *doc* 에 **포함된** 이미지에서 픽스맵을 생성합니다. 모든 픽스맵 속성은 이미지에 의해 설정됩니다. `extract-img1.py <https://github.com/pymupdf/PyMuPDF/tree/master/demo/extract-img1.py>`_ 및 `extract-img2.py <https://github.com/pymupdf/PyMuPDF/tree/master/demo/extract-img2.py>`_ 를 확인하여 이것을 사용하여 PDF의 모든 이미지를 복구하는 방법을 참조하세요.\"\n\n#: ../../pixmap.rst:182 83027e8baba3428f9138b9272d50b7c5\nmsgid \"an opened |PDF| document.\"\nmsgstr \"열린 |PDF| 문서.\"\n\n#: ../../pixmap.rst:185 1d115e0cbe8d45c1a12b21ba961b218c\nmsgid \"\"\n\"the :data:`xref` of an image object. For example, you can make a list of \"\n\"images used on a particular page with :meth:`Document.get_page_images`, \"\n\"which also shows the :data:`xref` numbers of each image.\"\nmsgstr \"이미지 객체의 :data:`xref`. 예를 들어 :meth:`Document.get_page_images` 를 사용하여 특정 페이지에서 사용된 이미지 목록을 만들 수 있으며, 이것은 각 이미지의 :data:`xref` 번호도 표시합니다.\"\n\n#: ../../pixmap.rst:189 af2a4e8f44da46f9b6b2a58073bb2cfc\nmsgid \"Initialize the samples area.\"\nmsgstr \"samples 영역을 초기화합니다.\"\n\n#: ../../pixmap.rst:191 e9fa66fe4f434c59baeea5e2c721a40d\nmsgid \"\"\n\"if specified, values from 0 to 255 are valid. Each color byte of each \"\n\"pixel will be set to this value, while alpha will be set to 255 (non-\"\n\"transparent) if present. If omitted, then all bytes (including any alpha)\"\n\" are cleared to *0x00*.\"\nmsgstr \"지정된 경우 0부터 255까지의 값이 유효합니다. 각 픽셀의 각 색상 바이트는 이 값으로 설정되고, 알파가 있으면 255(불투명)로 설정됩니다. 생략하면 모든 바이트(알파 포함)가 *0x00* 으로 지워집니다.\"\n\n#: ../../pixmap.rst:193 bb47605a216946dba119a8bf60a6dcdd\nmsgid \"\"\n\"the area to be cleared. Omit to clear the whole pixmap. Can only be \"\n\"specified, if *value* is also specified.\"\nmsgstr \"지울 영역. 생략하면 전체 픽스맵을 지웁니다. *value* 도 지정된 경우에만 지정할 수 있습니다.\"\n\n#: ../../pixmap.rst:197 78bf5b67f38f46178532a1e37e7ddd72\nmsgid \"\"\n\"Colorize a pixmap by replacing black and / or white with colors given as \"\n\"**sRGB integer** values. Only colorspaces :data:`CS_GRAY` and \"\n\":data:`CS_RGB` are supported, others are ignored with a warning.\"\nmsgstr \"**sRGB 정수** 값으로 주어진 색상으로 검은색 및/또는 흰색을 교체하여 픽스맵을 색칠합니다. 색상 공간 :data:`CS_GRAY` 및 :data:`CS_RGB` 만 지원되며, 다른 것은 경고와 함께 무시됩니다.\"\n\n#: ../../pixmap.rst:199 abae57d0723b4345a89b12f880d933fa\nmsgid \"\"\n\"If the colorspace is :data:`CS_GRAY`, the average *(red + green + \"\n\"blue)/3* will be taken. The pixmap will be changed in place.\"\nmsgstr \"색상 공간이 :data:`CS_GRAY` 인 경우 평균 *(red + green + blue)/3* 이 사용됩니다. 픽스맵은 제자리에서 변경됩니다.\"\n\n#: ../../pixmap.rst:201 04577dadbfbc43a3abbe3d997f6561ab\nmsgid \"replace black with this value. Specifying 0x000000 makes no changes.\"\nmsgstr \"검은색을 이 값으로 교체합니다. 0x000000을 지정하면 변경되지 않습니다.\"\n\n#: ../../pixmap.rst:202 43f498ae78e443a28b06bdcc72789414\nmsgid \"replace white with this value. Specifying 0xFFFFFF makes no changes.\"\nmsgstr \"흰색을 이 값으로 교체합니다. 0xFFFFFF를 지정하면 변경되지 않습니다.\"\n\n#: ../../pixmap.rst:204 391411e29bc24c0183271fc962fc85ae\nmsgid \"Examples:\"\nmsgstr \"Examples:\"\n\n#: ../../pixmap.rst:206 6e89c521384c4c5bbc9619d3efe8b909\nmsgid \"`tint_with(0x000000, 0xFFFFFF)` is a no-op.\"\nmsgstr \"`tint_with(0x000000, 0xFFFFFF)` 는 no-op입니다.\"\n\n#: ../../pixmap.rst:207 64e6d46367ef4feca63cb7fb163d6b63\nmsgid \"\"\n\"`tint_with(0x00FF00, 0xFFFFFF)` changes black to green, leaves white \"\n\"intact.\"\nmsgstr \"`tint_with(0x00FF00, 0xFFFFFF)` 는 검은색을 녹색으로 변경하고 흰색은 그대로 둡니다.\"\n\n#: ../../pixmap.rst:208 8ea3f30122264c92b50ec935ec42fc3c\nmsgid \"`tint_with(0xFF0000, 0x0000FF)` changes black to red and white to blue.\"\nmsgstr \"`tint_with(0xFF0000, 0x0000FF)` 는 검은색을 빨간색으로, 흰색을 파란색으로 변경합니다.\"\n\n#: ../../pixmap.rst:213 ca2f9c12e08649b5870ae3ad64eacd72\nmsgid \"\"\n\"Apply a gamma factor to a pixmap, i.e. lighten or darken it. Pixmaps with\"\n\" colorspace ``None`` are ignored with a warning.\"\nmsgstr \"픽스맵에 감마 계수를 적용합니다. 즉, 밝게 하거나 어둡게 합니다. 색상 공간이 ``None`` 인 픽스맵은 경고와 함께 무시됩니다.\"\n\n#: ../../pixmap.rst:215 f4c36ad3313f4088882a49b8ff1847ec\nmsgid \"\"\n\"*gamma = 1.0* does nothing, *gamma < 1.0* lightens, *gamma > 1.0* darkens\"\n\" the image.\"\nmsgstr \"*gamma = 1.0* 은 아무것도 하지 않으며, *gamma < 1.0* 은 밝게 하고, *gamma > 1.0* 은 이미지를 어둡게 합니다.\"\n\n#: ../../pixmap.rst:219 8543630bd8134fbfbad3e241950d6cea\nmsgid \"\"\n\"Shrink the pixmap by dividing both, its width and height by 2\\\\ \"\n\":sup:``n``.\"\nmsgstr \"너비와 높이를 모두 2\\\\ :sup:``n`` 으로 나누어 픽스맵을 축소합니다.\"\n\n#: ../../pixmap.rst:221 30c7f5ad783249949e9748a49eb7d9f9\nmsgid \"\"\n\"determines the new pixmap (samples) size. For example, a value of 2 \"\n\"divides width and height by 4 and thus results in a size of one 16\\\\ \"\n\":sup:`th` of the original. Values less than 1 are ignored with a warning.\"\nmsgstr \"새 픽스맵(samples) 크기를 결정합니다. 예를 들어 값 2는 너비와 높이를 4로 나누어 원본의 16\\\\ :sup:`분의 1` 크기로 만듭니다. 1보다 작은 값은 경고와 함께 무시됩니다.\"\n\n#: ../../pixmap.rst:223 f45f17093df4420cb6fbc619648afd22\nmsgid \"\"\n\"Use this methods to reduce a pixmap's size retaining its proportion. The \"\n\"pixmap is changed \\\"in place\\\". If you want to keep original and also \"\n\"have more granular choices, use the resp. copy constructor above.\"\nmsgstr \"이 메서드를 사용하여 비율을 유지하면서 픽스맵의 크기를 줄입니다. 픽스맵은 \\\"제자리에서\\\" 변경됩니다. 원본을 유지하고 더 세밀한 선택을 원하면 위의 해당 복사 생성자를 사용하세요.\"\n\n#: ../../pixmap.rst:227 1455e6653c744eeba403a49f543d6fab\nmsgid \"\"\n\"*New in version:: 1.14.5:* Return the value of the pixel at location (x, \"\n\"y) (column, line).\"\nmsgstr \"*버전 1.14.5의 새로운 기능:* 위치 (x, y)(열, 줄)의 픽셀 값을 반환합니다.\"\n\n#: ../../pixmap.rst:229 ../../pixmap.rst:239 4665e9dd65654240abe6ee77bae37183\n#: ffb7d135ed9a41f1b4f0bfa146d6de82\nmsgid \"the column number of the pixel. Must be in `range(pix.width)`.\"\nmsgstr \"픽셀의 열 번호. `range(pix.width)` 에 있어야 합니다.\"\n\n#: ../../pixmap.rst:230 f1efa4c149644cc680d5348ad2c2e068\nmsgid \"the line number of the pixel, Must be in `range(pix.height)`.\"\nmsgstr \"픽셀의 줄 번호. `range(pix.height)` 에 있어야 합니다.\"\n\n#: ../../pixmap.rst 369baee8d7234ef2ab7f82e75e9111ad\n#: a81a4cbd70ad4e0b8fb189a247cfcaaf b3a66cf736f24daea703147e167c320f\n#: cc865d958a3d4c81b2cbd3d3f814714b d2546977b027475993b2df887c1cb6e8\n#: e81aa1c04aa6419da09b400752672904 eb0378b2f08a49a0af740a769d1a6087\nmsgid \"Return type\"\nmsgstr \"Return type\"\n\n#: ../../pixmap.rst 186871c10cae496984d33e4181c189b0\n#: 24ba23b408644b24bd9aa5c5c7695c13 375a4a43a898465fa252490979e2f154\n#: 44939b8c082c4f128aecb10f802bce36 8183d07de46a4c909fc8ff25a1c13b5e\n#: 82dd9565faa544cf8799ce6981d78e02 a7c02e0b9035405a9f75f61d1ef8a011\nmsgid \"Returns\"\nmsgstr \"Returns\"\n\n#: ../../pixmap.rst:233 1c117c2f7320435ab28104a0c9e6b3f0\nmsgid \"\"\n\"a list of color values and, potentially the alpha value. Its length and \"\n\"content depend on the pixmap's colorspace and the presence of an alpha. \"\n\"For RGBA pixmaps the result would e.g. be *[r, g, b, a]*. All items are \"\n\"integers in `range(256)`.\"\nmsgstr \"색상 값 및 잠재적으로 알파 값의 목록. 길이와 내용은 픽스맵의 색상 공간과 알파의 존재에 따라 다릅니다. RGBA 픽스맵의 경우 결과는 예를 들어 *[r, g, b, a]* 가 됩니다. 모든 항목은 `range(256)` 의 정수입니다.\"\n\n#: ../../pixmap.rst:237 4e3d50e363f54e7da5ab00f4aa58fec5\nmsgid \"\"\n\"*New in version 1.14.7:* Manipulate the pixel at location (x, y) (column,\"\n\" line).\"\nmsgstr \"*버전 1.14.7의 새로운 기능:* 위치 (x, y)(열, 줄)의 픽셀을 조작합니다.\"\n\n#: ../../pixmap.rst:240 0dcca10c1c4c4b58b61746cd5da73f43\nmsgid \"the line number of the pixel. Must be in `range(pix.height)`.\"\nmsgstr \"픽셀의 줄 번호. `range(pix.height)` 에 있어야 합니다.\"\n\n#: ../../pixmap.rst:241 eee0a54112754d7db4a0e21facaf19c8\nmsgid \"\"\n\"the desired pixel value given as a sequence of integers in `range(256)`. \"\n\"The length of the sequence must equal :attr:`Pixmap.n`, which includes \"\n\"any alpha byte.\"\nmsgstr \"`range(256)` 의 정수 시퀀스로 주어진 원하는 픽셀 값. 시퀀스의 길이는 알파 바이트를 포함하여 :attr:`Pixmap.n` 과 같아야 합니다.\"\n\n#: ../../pixmap.rst:245 223fcf7f54984d26a1a64657ed00a81d\nmsgid \"*New in version 1.14.8:* Set the pixels of a rectangle to a value.\"\nmsgstr \"*버전 1.14.8의 새로운 기능:* 사각형의 픽셀을 값으로 설정합니다.\"\n\n#: ../../pixmap.rst:247 95d0f97710ba444391fd993ca732bc02\nmsgid \"\"\n\"the rectangle to be filled with the value. The actual area is the \"\n\"intersection of this parameter and :attr:`Pixmap.irect`. For an empty \"\n\"intersection (or an invalid parameter), no change will happen.\"\nmsgstr \"값으로 채울 사각형. 실제 영역은 이 매개변수와 :attr:`Pixmap.irect` 의 교집합입니다. 빈 교집합(또는 잘못된 매개변수)의 경우 변경이 발생하지 않습니다.\"\n\n#: ../../pixmap.rst:248 a8fe7a3cf13a40e6a5abc4a65a481906\nmsgid \"\"\n\"the desired value, given as a sequence of integers in `range(256)`. The \"\n\"length of the sequence must equal :attr:`Pixmap.n`, which includes any \"\n\"alpha byte.\"\nmsgstr \"`range(256)` 의 정수 시퀀스로 주어진 원하는 값. 시퀀스의 길이는 알파 바이트를 포함하여 :attr:`Pixmap.n` 과 같아야 합니다.\"\n\n#: ../../pixmap.rst:251 ef594268cf964435b0f7fae7229908c8\nmsgid \"\"\n\"``False`` if the rectangle was invalid or had an empty intersection with \"\n\":attr:`Pixmap.irect`, else ``True``.\"\nmsgstr \"사각형이 유효하지 않거나 :attr:`Pixmap.irect` 와 빈 교집합이 있으면 ``False``, 그렇지 않으면 ``True``.\"\n\n#: ../../pixmap.rst:255 bcf6532518a34f9c87fe6473f29b283c\nmsgid \"\"\n\"This method is equivalent to :meth:`Pixmap.set_pixel` executed for each \"\n\"pixel in the rectangle, but is obviously **very much faster** if many \"\n\"pixels are involved.\"\nmsgstr \"이 메서드는 사각형의 각 픽셀에 대해 실행되는 :meth:`Pixmap.set_pixel` 과 동일하지만 많은 픽셀이 관련된 경우 **훨씬 빠릅니다**.\"\n\n#: ../../pixmap.rst:256 bc5f1b513a0f4c4fa649296505adae7c\nmsgid \"\"\n\"This method can be used similar to :meth:`Pixmap.clear_with` to \"\n\"initialize a pixmap with a certain color like this: \"\n\"*pix.set_rect(pix.irect, (255, 255, 0))* (RGB example, colors the \"\n\"complete pixmap with yellow).\"\nmsgstr \"이 메서드는 :meth:`Pixmap.clear_with` 와 유사하게 사용하여 픽스맵을 특정 색상으로 초기화할 수 있습니다: *pix.set_rect(pix.irect, (255, 255, 0))* (RGB 예제, 전체 픽스맵을 노란색으로 칠함).\"\n\n#: ../../pixmap.rst:260 a513c003abe849829c11fe1447ebad4c\nmsgid \"New in v1.17.7\"\nmsgstr \"v1.17.7에서 새로 추가됨\"\n\n#: ../../pixmap.rst:262 0b7cc0a788dd40cb8acfbdb60fc95d01\nmsgid \"Set the x and y values of the pixmap's top-left point.\"\nmsgstr \"픽스맵의 왼쪽 위 점의 x 및 y 값을 설정합니다.\"\n\n#: ../../pixmap.rst:264 235e6e23b0b24739bc80e81e21526714\nmsgid \"x coordinate\"\nmsgstr \"x 좌표\"\n\n#: ../../pixmap.rst:265 6abac422a54b4e5bb66a4859637f5a69\nmsgid \"y coordinate\"\nmsgstr \"y 좌표\"\n\n#: ../../pixmap.rst:270 c5527c1032f044a2a640143d01653c61\nmsgid \"New in v1.16.17\"\nmsgstr \"v1.16.17에서 새로 추가됨\"\n\n#: ../../pixmap.rst:272 f49f9e8464474d7cbf7a85f1ba506a82\nmsgid \"\"\n\"Changed in v1.18.0: When saving as a PNG image, these values will be \"\n\"stored now.\"\nmsgstr \"v1.18.0에서 변경됨: PNG 이미지로 저장할 때 이 값들이 이제 저장됩니다.\"\n\n#: ../../pixmap.rst:274 a468673bcf8b49a68b788fd8ae23b5d5\nmsgid \"Set the resolution (dpi) in x and y direction.\"\nmsgstr \"x 및 y 방향의 해상도(dpi)를 설정합니다.\"\n\n#: ../../pixmap.rst:276 0ac91572ffc64e2bba64b0279d3fc7a3\nmsgid \"resolution in x direction.\"\nmsgstr \"x 방향 해상도.\"\n\n#: ../../pixmap.rst:277 1eb356ec57454ca9815ab72ead63956f\nmsgid \"resolution in y direction.\"\nmsgstr \"y 방향 해상도.\"\n\n#: ../../pixmap.rst:282 8623995d2c004b0ba2caf470042846f1\nmsgid \"Changed in v 1.18.13\"\nmsgstr \"v1.18.13에서 변경됨\"\n\n#: ../../pixmap.rst:284 82d487067f8d4ced9ef11d081f5e4ce8\nmsgid \"Change the alpha values. The pixmap must have an alpha channel.\"\nmsgstr \"알파 값을 변경합니다. 픽스맵은 알파 채널을 가져야 합니다.\"\n\n#: ../../pixmap.rst:286 c98fe169c19c487481ca55cd0633f3f8\nmsgid \"\"\n\"the new alpha values. If provided, its length must be at least *width * \"\n\"height*. If omitted (`None`), all alpha values are set to 255 (no \"\n\"transparency). *Changed in version 1.14.13:* *io.BytesIO* is now also \"\n\"accepted.\"\nmsgstr \"새 알파 값. 제공된 경우 길이는 최소 *width * height* 여야 합니다. 생략(`None`)하면 모든 알파 값이 255(투명도 없음)로 설정됩니다. *버전 1.14.13에서 변경됨:* 이제 *io.BytesIO* 도 허용됩니다.\"\n\n#: ../../pixmap.rst:287 e94c3d6b68c141e2b61b6f54ab717d33\nmsgid \"\"\n\"*New in v1.18.13:* whether to premultiply color components with the alpha\"\n\" value.\"\nmsgstr \"*v1.18.13의 새로운 기능:* 색상 구성 요소를 알파 값으로 사전 곱셈할지 여부.\"\n\n#: ../../pixmap.rst:288 fbe9e806927d460389c858b14d4f3644\nmsgid \"\"\n\"ignore the alpha value and set this color to fully transparent. A \"\n\"sequence of integers in `range(256)` with a length of :attr:`Pixmap.n`. \"\n\"Default is ``None``. For example, a typical choice for RGB would be \"\n\"`opaque=(255, 255, 255)` (white).\"\nmsgstr \"알파 값을 무시하고 이 색상을 완전히 투명하게 설정합니다. :attr:`Pixmap.n` 길이의 `range(256)` 정수 시퀀스. 기본값은 ``None`` 입니다. 예를 들어 RGB의 일반적인 선택은 `opaque=(255, 255, 255)` (흰색)입니다.\"\n\n#: ../../pixmap.rst:293 e617ef83731c4689a35511a90c29ceeb\nmsgid \"\"\n\"Invert the color of all pixels in :ref:`IRect` *irect*. Will have no \"\n\"effect if colorspace is ``None``.\"\nmsgstr \":ref:`IRect` *irect* 의 모든 픽셀 색상을 반전합니다. 색상 공간이 ``None`` 이면 효과가 없습니다.\"\n\n#: ../../pixmap.rst:295 b9d38a022bef44f89d241d1964237fbb\nmsgid \"The area to be inverted. Omit to invert everything.\"\nmsgstr \"반전할 영역. 생략하면 모든 것을 반전합니다.\"\n\n#: ../../pixmap.rst:299 e764fb3df0324f5187dbb68ba9a917ba\nmsgid \"\"\n\"Copy the *irect* part of the *source* pixmap into the corresponding area \"\n\"of this one. The two pixmaps may have different dimensions and can each \"\n\"have :data:`CS_GRAY` or :data:`CS_RGB` colorspaces, but they currently \"\n\"**must** have the same alpha property [#f2]_. The copy mechanism \"\n\"automatically adjusts discrepancies between source and target like so:\"\nmsgstr \"*source* 픽스맵의 *irect* 부분을 이 픽스맵의 해당 영역에 복사합니다. 두 픽스맵은 다른 크기를 가질 수 있으며 각각 :data:`CS_GRAY` 또는 :data:`CS_RGB` 색상 공간을 가질 수 있지만 현재 **반드시** 동일한 알파 속성을 가져야 합니다 [#f2]_. 복사 메커니즘은 다음과 같이 소스와 대상 간의 차이를 자동으로 조정합니다:\"\n\n#: ../../pixmap.rst:301 e270f22850b84663930783d1f33ca33c\nmsgid \"\"\n\"If copying from :data:`CS_GRAY` to :data:`CS_RGB`, the source gray-shade \"\n\"value will be put into each of the three rgb component bytes. If the \"\n\"other way round, *(r + g + b) / 3* will be taken as the gray-shade value \"\n\"of the target.\"\nmsgstr \":data:`CS_GRAY` 에서 :data:`CS_RGB` 로 복사하는 경우, 소스 그레이 음영 값이 세 개의 RGB 구성 요소 바이트 각각에 배치됩니다. 반대의 경우, *(r + g + b) / 3* 이 대상의 그레이 음영 값으로 사용됩니다.\"\n\n#: ../../pixmap.rst:303 e29fc4caf130461db1843ba16fe4fc72\nmsgid \"\"\n\"Between *irect* and the target pixmap's rectangle, an \\\"intersection\\\" is\"\n\" calculated at first. This takes into account the rectangle coordinates \"\n\"and the current attribute values :attr:`Pixmap.x` and :attr:`Pixmap.y` \"\n\"(which you are free to modify for this purpose via \"\n\":meth:`Pixmap.set_origin`). Then the corresponding data of this \"\n\"intersection are copied. If the intersection is empty, nothing will \"\n\"happen.\"\nmsgstr \"*irect* 와 대상 픽스맵의 사각형 사이에서 먼저 \\\"교집합\\\"이 계산됩니다. 이것은 사각형 좌표와 현재 속성 값 :attr:`Pixmap.x` 및 :attr:`Pixmap.y` (이 목적을 위해 :meth:`Pixmap.set_origin` 을 통해 자유롭게 수정할 수 있음)를 고려합니다. 그런 다음 이 교집합의 해당 데이터가 복사됩니다. 교집합이 비어 있으면 아무 일도 발생하지 않습니다.\"\n\n#: ../../pixmap.rst:308 fb1b535c8adc44baa4c729c25fec3e14\nmsgid \"The area to be copied.\"\nmsgstr \"복사할 영역.\"\n\n#: ../../pixmap.rst:310 82448c014aa543b68e66cec1b07f3d96\nmsgid \"\"\n\"Example: Suppose you have two pixmaps, `pix1` and `pix2` and you want to \"\n\"copy the lower right quarter of `pix2` to `pix1` such that it starts at \"\n\"the top-left point of `pix1`. Use the following snippet::\"\nmsgstr \"예제: 두 개의 픽스맵 `pix1` 과 `pix2` 가 있고 `pix2` 의 오른쪽 아래 사분면을 `pix1` 의 왼쪽 위 지점에서 시작하도록 `pix1` 에 복사하려는 경우 다음 스니펫을 사용하세요::\"\n\n#: ../../pixmap.rst:329 7fbfff308f9d4627a4a6f2fc60e1651e\nmsgid \"\"\n\"Changed in v1.22.0: Added **direct support of JPEG** images. Image \"\n\"quality can be controlled via parameter \\\"jpg_quality\\\".\"\nmsgstr \"v1.22.0에서 변경됨: **JPEG 이미지 직접 지원** 이 추가되었습니다. 이미지 품질은 \\\"jpg_quality\\\" 매개변수를 통해 제어할 수 있습니다.\"\n\n#: ../../pixmap.rst:331 97bd54f9e597471292898030e2002c7a\nmsgid \"\"\n\"Save pixmap as an image file. Depending on the output chosen, only some \"\n\"or all colorspaces are supported and different file extensions can be \"\n\"chosen. Please see the table below.\"\nmsgstr \"픽스맵을 이미지 파일로 저장합니다. 선택한 출력에 따라 일부 또는 모든 색상 공간이 지원되며 다른 파일 확장자를 선택할 수 있습니다. 아래 표를 참조하세요.\"\n\n#: ../../pixmap.rst:333 9cbb39acd6fd43c7b4231f63399b34d8\nmsgid \"\"\n\"The file to save to. May be provided as a string, as a ``pathlib.Path`` \"\n\"or as a Python file object. In the latter two cases, the filename is \"\n\"taken from the resp. object. The filename's extension determines the \"\n\"image format, which can be overruled by the output parameter.\"\nmsgstr \"저장할 파일. 문자열, ``pathlib.Path`` 또는 Python 파일 객체로 제공할 수 있습니다. 후자 두 경우에는 파일 이름이 해당 객체에서 가져옵니다. 파일 이름의 확장자는 이미지 형식을 결정하며, output 매개변수로 재정의할 수 있습니다.\"\n\n#: ../../pixmap.rst:335 a8f9fb30eb6f4e129ccdb1eb4dfb2d50\nmsgid \"\"\n\"The desired image format. The default is the filename's extension. If \"\n\"both, this value and the file extension are unsupported, an exception is \"\n\"raised. For possible values see :ref:`PixmapOutput`.\"\nmsgstr \"원하는 이미지 형식. 기본값은 파일 이름의 확장자입니다. 이 값과 파일 확장자가 모두 지원되지 않으면 예외가 발생합니다. 가능한 값은 :ref:`PixmapOutput` 을 참조하세요.\"\n\n#: ../../pixmap.rst:336 ../../pixmap.rst:346 57c5e89d61b643828893b09c1506e81c\n#: a4031bcffabf4809bb9b3450054f39ec\nmsgid \"\"\n\"The desired image quality, default 95. Only applies to JPEG images, else \"\n\"ignored. This parameter trades quality against file size. A value of 98 \"\n\"is close to lossless. Higher values should not lead to better quality.\"\nmsgstr \"원하는 이미지 품질, 기본값 95. JPEG 이미지에만 적용되며, 그렇지 않으면 무시됩니다. 이 매개변수는 품질과 파일 크기를 교환합니다. 값 98은 무손실에 가깝습니다. 더 높은 값이 더 나은 품질로 이어지지는 않습니다.\"\n\n#: ../../pixmap.rst 31830ae4676c49a29f6eda0ec74b2cc7\n#: 35f861d76f76416f84ca4a6cfbb9ba36 9e7d20d2ebff48a5a2f12a7bb9cb207f\n#: 9e8d92287683474c8894ca359bc0df3c eaa3f51d3c63445d921c804b8d264fba\nmsgid \"Raises\"\nmsgstr \"Raises\"\n\n#: ../../pixmap.rst:338 ../../pixmap.rst:348 74c8c07d5a4d429180ebc61a6dc88b40\n#: 888fc652cefb483cbc631acba45b2a8c\nmsgid \"For unsupported image formats.\"\nmsgstr \"지원되지 않는 이미지 형식의 경우.\"\n\n#: ../../pixmap.rst:342 3e89ee831b4744b2a7778a6f2ab7d705\nmsgid \"\"\n\"New in version 1.14.5: Return the pixmap as a *bytes* memory object of \"\n\"the specified format -- similar to :meth:`save`.\"\nmsgstr \"버전 1.14.5의 새로운 기능: 지정된 형식의 *bytes* 메모리 객체로 픽스맵을 반환합니다 -- :meth:`save` 와 유사합니다.\"\n\n#: ../../pixmap.rst:343 4dff4d1183ff44f2a456ec123ddad67f\nmsgid \"\"\n\"Changed in v1.22.0: Added **direct JPEG support**. Image quality can be \"\n\"influenced via new parameter \\\"jpg_quality\\\".\"\nmsgstr \"v1.22.0에서 변경됨: **직접 JPEG 지원** 이 추가되었습니다. 이미지 품질은 새로운 매개변수 \\\"jpg_quality\\\"를 통해 조정할 수 있습니다.\"\n\n#: ../../pixmap.rst:345 17d9ad6bf1cd4d0caaf174d46a29b286\nmsgid \"\"\n\"The desired image format. The default is \\\"png\\\". For possible values see\"\n\" :ref:`PixmapOutput`.\"\nmsgstr \"원하는 이미지 형식. 기본값은 \\\"png\\\"입니다. 가능한 값은 :ref:`PixmapOutput` 을 참조하세요.\"\n\n#: ../../pixmap.rst:351 7a4a3392440c413b9549ddfd80aa09e8\nmsgid \"\"\n\"The requested image format. The default is \\\"png\\\". For other possible \"\n\"values see :ref:`PixmapOutput`.\"\nmsgstr \"요청된 이미지 형식. 기본값은 \\\"png\\\"입니다. 다른 가능한 값은 :ref:`PixmapOutput` 을 참조하세요.\"\n\n#: ../../pixmap.rst:355 ../../pixmap.rst:370 024249ef113f468bba659314559663a8\n#: 3ebc661e655c4894a0780bd40d34f1b9\nmsgid \"New in v1.19.0\"\nmsgstr \"v1.19.0에서 새로 추가됨\"\n\n#: ../../pixmap.rst:357 ../../pixmap.rst:372 98399e67142a4ab4bfa0146bb6a938e0\n#: fde150994fb44c0dac805e2d7807ae53\nmsgid \"Changed in v1.22.5: Support of new parameter for Tesseract's tessdata.\"\nmsgstr \"v1.22.5에서 변경됨: Tesseract의 tessdata에 대한 새로운 매개변수 지원.\"\n\n#: ../../pixmap.rst:359 7e216757569f4c4ebb1b9d88f2858c00\nmsgid \"\"\n\"Perform text recognition using Tesseract and save the image as a 1-page \"\n\"PDF with an OCR text layer.\"\nmsgstr \"Tesseract를 사용하여 텍스트 인식을 수행하고 이미지를 OCR 텍스트 레이어가 있는 1페이지 PDF로 저장합니다.\"\n\n#: ../../pixmap.rst:361 9e480852cca4498d8cb34f674e078760\nmsgid \"\"\n\"identifies the file to save to. May be either a string or a pointer to a \"\n\"file opened with \\\"wb\\\" (includes `io.BytesIO()` objects).\"\nmsgstr \"저장할 파일을 식별합니다. 문자열 또는 \\\"wb\\\"로 열린 파일에 대한 포인터(`io.BytesIO()` 객체 포함)일 수 있습니다.\"\n\n#: ../../pixmap.rst:362 739251505f694c69af4730ee2d8f7848\nmsgid \"whether to compress the resulting PDF, default is `True`.\"\nmsgstr \"결과 PDF를 압축할지 여부, 기본값은 `True` 입니다.\"\n\n#: ../../pixmap.rst:363 8c1c54fe56a34bf19f07465936ed9f10\nmsgid \"\"\n\"the languages occurring in the image. This must be specified in Tesseract\"\n\" format. Default is \\\"eng\\\" for English. Use \\\"+\\\"-separated Tesseract \"\n\"language codes for multiple languages, like \\\"eng+spa\\\" for English and \"\n\"Spanish.\"\nmsgstr \"이미지에 나타나는 언어. Tesseract 형식으로 지정해야 합니다. 기본값은 영어의 경우 \\\"eng\\\"입니다. 여러 언어의 경우 \\\"+\\\"로 구분된 Tesseract 언어 코드를 사용하세요(예: 영어와 스페인어의 경우 \\\"eng+spa\\\").\"\n\n#: ../../pixmap.rst:364 fcca47fa76a9459cbec299e7f148dec6\nmsgid \"\"\n\"folder name of Tesseract's language support. If omitted, this information\"\n\" must be present as environment variable `TESSDATA_PREFIX`.\"\nmsgstr \"Tesseract의 언어 지원 폴더 이름. 생략된 경우 이 정보는 환경 변수 `TESSDATA_PREFIX` 로 존재해야 합니다.\"\n\n#: ../../pixmap.rst:366 21a4cf67602b4076b49b985e8aa0c66b\nmsgid \"\"\n\"**Will fail** if Tesseract is not installed or if the environment \"\n\"variable \\\"TESSDATA_PREFIX\\\" is not set to the `tessdata` folder name and\"\n\" not provided as parameter.\"\nmsgstr \"Tesseract가 설치되지 않았거나 환경 변수 \\\"TESSDATA_PREFIX\\\"가 `tessdata` 폴더 이름으로 설정되지 않고 매개변수로 제공되지 않으면 **실패합니다**.\"\n\n#: ../../pixmap.rst:374 32b8acd13d9f48e1bfd79ab1023be929\nmsgid \"\"\n\"Perform text recognition using Tesseract and convert the image to a \"\n\"1-page PDF with an OCR text layer. Internally invokes \"\n\":meth:`Pixmap.pdfocr_save`.\"\nmsgstr \"Tesseract를 사용하여 텍스트 인식을 수행하고 이미지를 OCR 텍스트 레이어가 있는 1페이지 PDF로 변환합니다. 내부적으로 :meth:`Pixmap.pdfocr_save` 를 호출합니다.\"\n\n#: ../../pixmap.rst:376 9e005bf6ab3440c085ee1193ba601f87\nmsgid \"\"\n\"A 1-page PDF file in memory. Could be opened like \"\n\"`doc=pymupdf.open(\\\"pdf\\\", pix.pdfocr_tobytes())`, and text extractions \"\n\"could be performed on its `page=doc[0]`.  .. note::     Another possible \"\n\"use is insertion into some pdf. The following snippet reads the images of\"\n\" a folder and stores them as pages in a new PDF that contain an OCR text \"\n\"layer::        doc = pymupdf.open()       for imgfile in \"\n\"os.listdir(folder):          pix = pymupdf.Pixmap(imgfile)          \"\n\"imgpdf = pymupdf.open(\\\"pdf\\\", pix.pdfocr_tobytes())          \"\n\"doc.insert_pdf(imgpdf)          pix = None          imgpdf.close()       \"\n\"doc.save(\\\"ocr-images.pdf\\\")\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:376 b412ebf7d201478890ec75b641a17871\nmsgid \"\"\n\"A 1-page PDF file in memory. Could be opened like \"\n\"`doc=pymupdf.open(\\\"pdf\\\", pix.pdfocr_tobytes())`, and text extractions \"\n\"could be performed on its `page=doc[0]`.\"\nmsgstr \"메모리의 1페이지 PDF 파일. `doc=pymupdf.open(\\\"pdf\\\", pix.pdfocr_tobytes())` 와 같이 열 수 있으며, `page=doc[0]` 에서 텍스트 추출을 수행할 수 있습니다.\"\n\n#: ../../pixmap.rst:380 2cd418d767ef4149b35f4d0415d14af1\nmsgid \"\"\n\"Another possible use is insertion into some pdf. The following snippet \"\n\"reads the images of a folder and stores them as pages in a new PDF that \"\n\"contain an OCR text layer::\"\nmsgstr \"다른 가능한 사용법은 일부 PDF에 삽입하는 것입니다. 다음 스니펫은 폴더의 이미지를 읽어 OCR 텍스트 레이어가 포함된 새 PDF의 페이지로 저장합니다::\"\n\n#: ../../pixmap.rst:394 efc06e14189c4871827c5261c0623dfa\nmsgid \"Create a Pillow Image from the pixmap. PIL / Pillow must be installed.\"\nmsgstr \"픽스맵에서 Pillow 이미지를 생성합니다. PIL / Pillow가 설치되어 있어야 합니다.\"\n\n#: ../../pixmap.rst:396 ../../pixmap.rst:416 ../../pixmap.rst:424\n#: 3df2560f6e804a789cc70c26deec880b 8087c1edcca942f186efe9ad6be77c16\n#: 85c874d70f274112a51bc6ce56e6e197\nmsgid \"if Pillow is not installed.\"\nmsgstr \"Pillow가 설치되지 않은 경우.\"\n\n#: ../../pixmap.rst:397 69708896f8e44f9eb5a130326ae36b80\nmsgid \"a ``PIL.Image`` object\"\nmsgstr \"``PIL.Image`` 객체\"\n\n#: ../../pixmap.rst:401 3f77a2ee05134b31a570bc40ff704b87\nmsgid \"\"\n\"Write the pixmap as an image file using Pillow. Use this method for \"\n\"output unsupported by MuPDF. Examples are\"\nmsgstr \"Pillow를 사용하여 픽스맵을 이미지 파일로 씁니다. MuPDF에서 지원하지 않는 출력에 이 메서드를 사용하세요. 예는 다음과 같습니다\"\n\n#: ../../pixmap.rst:403 8f8925fd0a1e4868840945ccf3b35017\nmsgid \"Formats JPX, J2K, WebP, etc.\"\nmsgstr \"JPX, J2K, WebP 등의 형식.\"\n\n#: ../../pixmap.rst:404 bd17d3e24fb740469efea4743e5ffb78\nmsgid \"Storing EXIF information.\"\nmsgstr \"EXIF 정보 저장.\"\n\n#: ../../pixmap.rst:405 d7d0bc56bfcb4f179b7f00d2ad59c255\nmsgid \"\"\n\"If you do not provide dpi information, the values *xres*, *yres* stored \"\n\"with the pixmap are automatically used.\"\nmsgstr \"dpi 정보를 제공하지 않으면 픽스맵에 저장된 *xres*, *yres* 값이 자동으로 사용됩니다.\"\n\n#: ../../pixmap.rst:407 20bf1e69dd5147b9a108ab328fe2657e\nmsgid \"\"\n\"A simple example: `pix.pil_save(\\\"some.webp\\\", optimize=True, dpi=(150, \"\n\"150))`.\"\nmsgstr \"간단한 예제: `pix.pil_save(\\\"some.webp\\\", optimize=True, dpi=(150, 150))`.\"\n\n#: ../../pixmap.rst:409 71799e7c62324bbea016ae30eafbc021\nmsgid \"\"\n\"If the pixmap's colorspace is RGB with transparency, the alpha values may\"\n\" or may not already be multiplied into the color components \"\n\"ref/green/blue (called \\\"premultiplied\\\"). To enforce undoing \"\n\"premultiplication, set this parameter to `True`. To learn about some \"\n\"background, e.g. look for `\\\"Premultiplied alpha\\\" on this page \"\n\"<https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\"\nmsgstr \"픽스맵의 색상 공간이 투명도가 있는 RGB인 경우, 알파 값이 이미 색상 구성 요소 빨강/녹색/파랑(소위 \\\"사전 곱셈\\\")에 곱해져 있을 수도 있고 아닐 수도 있습니다. 사전 곱셈을 취소하려면 이 매개변수를 `True` 로 설정하세요. 배경에 대한 자세한 내용은 예를 들어 이 페이지 에서 `\\\"Premultiplied alpha\\\" <https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_ 를 찾아보세요.\"\n\n#: ../../pixmap.rst:412 c5f67c82cc1b4a078d120281dc779a59\nmsgid \"For details on other parameters see the Pillow documentation.\"\nmsgstr \"다른 매개변수에 대한 자세한 내용은 Pillow 문서를 참조하세요.\"\n\n#: ../../pixmap.rst:414 d3f2fde19b034f09971604debcf8e6dc\nmsgid \"\"\n\"Since v1.22.0, PyMuPDF supports JPEG output directly. We recommended to \"\n\"no longer use this method for JPEG output -- for performance reasons and \"\n\"for avoiding unnecessary external dependencies.\"\nmsgstr \"v1.22.0부터 PyMuPDF는 JPEG 출력을 직접 지원합니다. 성능상의 이유와 불필요한 외부 종속성을 피하기 위해 JPEG 출력에는 이 메서드를 더 이상 사용하지 않는 것을 권장합니다.\"\n\n#: ../../pixmap.rst:420 835e9bbf2bc047f2b9657ca7741ec37e\nmsgid \"New in v1.17.3\"\nmsgstr \"v1.17.3에서 새로 추가됨\"\n\n#: ../../pixmap.rst:422 d0177a551753414586749bf415cf6080\nmsgid \"\"\n\"Return an image as a bytes object in the specified format using Pillow. \"\n\"For example `stream = pix.pil_tobytes(format=\\\"WEBP\\\", optimize=True, \"\n\"dpi=(150, 150))`. Also see above. For details on other parameters see the\"\n\" Pillow documentation.\"\nmsgstr \"Pillow를 사용하여 지정된 형식의 bytes 객체로 이미지를 반환합니다. 예를 들어 `stream = pix.pil_tobytes(format=\\\"WEBP\\\", optimize=True, dpi=(150, 150))`. 위 내용도 참조하세요. 다른 매개변수에 대한 자세한 내용은 Pillow 문서를 참조하세요.\"\n\n#: ../../pixmap.rst:431 ../../pixmap.rst:466 68173364cda84dab84fa461435fdec56\n#: b156a10f58714dae92ca5c3163c24112\nmsgid \"New in v1.19.3\"\nmsgstr \"v1.19.3에서 새로 추가됨\"\n\n#: ../../pixmap.rst:433 129930765e83498b8cb4362c41d7fb9a\nmsgid \"\"\n\"Return a new pixmap by \\\"warping\\\" the quad such that the quad corners \"\n\"become the new pixmap's corners. The target pixmap's `irect` will be `(0,\"\n\" 0, width, height)`.\"\nmsgstr \"quad를 \\\"왜곡\\\"하여 quad 모서리가 새 픽스맵의 모서리가 되도록 새 픽스맵을 반환합니다. 대상 픽스맵의 `irect` 는 `(0, 0, width, height)` 가 됩니다.\"\n\n#: ../../pixmap.rst:435 6c6e2bf54f6c4c1cbd3c172dbbfb7712\nmsgid \"\"\n\"a convex quad with coordinates inside :attr:`Pixmap.irect` (including the\"\n\" border points).\"\nmsgstr \":attr:`Pixmap.irect` 내부(경계 점 포함)에 좌표가 있는 볼록 quad.\"\n\n#: ../../pixmap.rst:436 e9644c03761249019390c475ce09eeb9\nmsgid \"desired resulting width.\"\nmsgstr \"원하는 결과 너비.\"\n\n#: ../../pixmap.rst:437 5af3c5ce964244d9ac8c1210ae145777\nmsgid \"desired resulting height.\"\nmsgstr \"원하는 결과 높이.\"\n\n#: ../../pixmap.rst:438 23af53d676c943ab8270f1f4eb3e15f8\nmsgid \"\"\n\"A new pixmap where the quad corners are mapped to the pixmap corners in a\"\n\" clockwise fashion: `quad.ul -> irect.tl`, `quad.ur -> irect.tr`, etc.\"\nmsgstr \"quad 모서리가 시계 방향으로 픽스맵 모서리에 매핑된 새 픽스맵: `quad.ul -> irect.tl`, `quad.ur -> irect.tr` 등.\"\n\n#: ../../pixmap.rst:439 c3fb88fba3f7447889bc2174e90ed4ed\nmsgid \"\"\n\":ref:`Pixmap`  .. image:: images/img-warp.*      :scale: 40      :align: \"\n\"center\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:439 8eb4c765b10a4af0b07fe6d1cd7386d2\nmsgid \":ref:`Pixmap`\"\nmsgstr \":ref:`Pixmap`\"\n\n#: ../../pixmap.rst:448 ../../pixmap.rst:505 ../../pixmap.rst:514\n#: 00c62e32e38c4d82895121b426757269 0149558efd01426095beb5bf88035b73\n#: 5c3eedb1091c4eb1af8d1010e7f2b3f0\nmsgid \"New in v1.19.2\"\nmsgstr \"v1.19.2에서 새로 추가됨\"\n\n#: ../../pixmap.rst:449 b8fe5dd5d0294610a99db8d7ebd6deec\nmsgid \"Changed in v1.19.3\"\nmsgstr \"v1.19.3에서 변경됨\"\n\n#: ../../pixmap.rst:451 c2da2a6121594d6c8b3f4e6e7d643cee\nmsgid \"Determine the pixmap's unique colors and their count.\"\nmsgstr \"픽스맵의 고유 색상과 개수를 확인합니다.\"\n\n#: ../../pixmap.rst:453 992445f66d104d8c89ac2f8297c8e9c4\nmsgid \"\"\n\"*(changed in v1.19.3)* If `True` return a dictionary of color pixels and \"\n\"their usage count, else just the number of unique colors.\"\nmsgstr \"*(v1.19.3에서 변경됨)* `True` 이면 색상 픽셀과 사용 횟수의 딕셔너리를 반환하고, 그렇지 않으면 고유 색상의 개수만 반환합니다.\"\n\n#: ../../pixmap.rst:454 db2ea4eae7a1492dad41fae7951b0160\nmsgid \"\"\n\"a rectangle inside :attr:`Pixmap.irect`. If provided, only those pixels \"\n\"are considered. This allows inspecting sub-rectangles of a given pixmap \"\n\"directly -- instead of building sub-pixmaps.\"\nmsgstr \":attr:`Pixmap.irect` 내부의 사각형. 제공된 경우 해당 픽셀만 고려됩니다. 이를 통해 하위 픽스맵을 구축하는 대신 주어진 픽스맵의 하위 사각형을 직접 검사할 수 있습니다.\"\n\n#: ../../pixmap.rst:456 61a615b057024b7a9b6ac7fe5ff849ab\nmsgid \"\"\n\"either the number of colors, or a dictionary with the items `pixel: \"\n\"count`. The pixel key is a `bytes` object of length :attr:`Pixmap.n`.  ..\"\n\" note:: To recover the **tuple** of a pixel, use \"\n\"`tuple(colors.keys()[i])` for the i-th item.     * The response time \"\n\"depends on the pixmap's samples size and may be more than a second for \"\n\"very large pixmaps.    * Where applicable, pixels with different alpha \"\n\"values will be treated as different colors.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:456 9ad0b09ff1334369af15be4f052a2f6f\nmsgid \"\"\n\"either the number of colors, or a dictionary with the items `pixel: \"\n\"count`. The pixel key is a `bytes` object of length :attr:`Pixmap.n`.\"\nmsgstr \"색상 개수 또는 `pixel: count` 항목이 있는 딕셔너리. 픽셀 키는 :attr:`Pixmap.n` 길이의 `bytes` 객체입니다.\"\n\n#: ../../pixmap.rst:458 d7bdc5a53abc43d6a1041953b5c0c526\nmsgid \"\"\n\"To recover the **tuple** of a pixel, use `tuple(colors.keys()[i])` for \"\n\"the i-th item.\"\nmsgstr \"픽셀의 **튜플** 을 복구하려면 i번째 항목에 대해 `tuple(colors.keys()[i])` 를 사용하세요.\"\n\n#: ../../pixmap.rst:460 260f96dbe8c04ab1a25159255b8b79a7\nmsgid \"\"\n\"The response time depends on the pixmap's samples size and may be more \"\n\"than a second for very large pixmaps.\"\nmsgstr \"응답 시간은 픽스맵의 samples 크기에 따라 달라지며 매우 큰 픽스맵의 경우 1초 이상 걸릴 수 있습니다.\"\n\n#: ../../pixmap.rst:461 1b987ef794b6454eb0d9366a05344070\nmsgid \"\"\n\"Where applicable, pixels with different alpha values will be treated as \"\n\"different colors.\"\nmsgstr \"해당되는 경우 다른 알파 값을 가진 픽셀은 다른 색상으로 처리됩니다.\"\n\n#: ../../pixmap.rst:468 2b6490adea534fa6a8de4eaf1edb354a\nmsgid \"Return the most frequently used color and its relative frequency.\"\nmsgstr \"가장 자주 사용되는 색상과 상대적 빈도를 반환합니다.\"\n\n#: ../../pixmap.rst:470 485c7c5b4da94258b242db7b59b19b53\nmsgid \"\"\n\"A rectangle inside :attr:`Pixmap.irect`. If provided, only those pixels \"\n\"are considered. This allows inspecting sub-rectangles of a given pixmap \"\n\"directly -- instead of building sub-pixmaps.\"\nmsgstr \":attr:`Pixmap.irect` 내부의 사각형. 제공된 경우 해당 픽셀만 고려됩니다. 이를 통해 하위 픽스맵을 구축하는 대신 주어진 픽스맵의 하위 사각형을 직접 검사할 수 있습니다.\"\n\n#: ../../pixmap.rst:472 9110208e27134f02a9b9bcdc7700add8\n#, python-format\nmsgid \"\"\n\"A tuple `(ratio, pixel)` where `0 < ratio <= 1` and *pixel* is the pixel \"\n\"value of the color. Use this to decide if the image is \\\"almost\\\" \"\n\"unicolor: a response `(0.95, b\\\"\\\\x00\\\\x00\\\\x00\\\")` means that 95% of all\"\n\" pixels are black. See an example here :ref:`RecipesImages_P`.\"\nmsgstr \"`0 < ratio <= 1` 이고 *pixel* 이 색상의 픽셀 값인 튜플 `(ratio, pixel)`. 이를 사용하여 이미지가 \\\"거의\\\" 단색인지 결정하세요: 응답 `(0.95, b\\\"\\\\x00\\\\x00\\\\x00\\\")` 는 모든 픽셀의 95%가 검은색임을 의미합니다. 예제는 :ref:`RecipesImages_P` 를 참조하세요.\"\n\n#: ../../pixmap.rst:477 5e93c19118c44e4598fc55ffb9cd04f6\nmsgid \"Indicates whether the pixmap contains transparency information.\"\nmsgstr \"픽스맵에 투명도 정보가 포함되어 있는지 나타냅니다.\"\n\n#: ../../pixmap.rst 09340208613f48af95d9e1d2a3ef91fa\n#: 0cc2b878ea234bfe8d91795141e3924d 0ff51066858f4faaad58612b0fbd5896\n#: 163c7d4bd8d3405ca26c2650fa5d8a10 3eb04a688a904a5eaadf5d79aed68b1a\n#: 4869cfa0cd314211b192a2294838c7dc 5124ac9063654c24a37926de5ab662b6\n#: 557f147c6be94fe083e8082986fa08b6 5ee3e6766dd44d2582e805125e914472\n#: 5f52d2e5c48c47d7aec0c2b7a743fd46 6124bd56d7524796b1aa3c3e18458232\n#: 7c890834a7cf4a088780dfb0e21745a8 84cbd010ada9441a9182c12bbe62059b\n#: 89488e9f1e4c4e3d8c6ca9ce290016a4 8be2b06b344443289085426c1e14fa50\n#: 922e0d0d08124b5081bcbb57569a2aa8 a1b9de76b34b47f9b95c7bb1563b9e5a\n#: d0c0191f32ed43c6a6857c305705698b ead0a6e9dc94433ba020dae746028076\nmsgid \"type\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:479 ../../pixmap.rst:509 ../../pixmap.rst:518\n#: ../../pixmap.rst:633 3d5651d764be40cca15a078b7f2531b8\n#: 694a5ede4c4c43319c089b1737fd0b9c a65782123b144e4186d43ddd5c138a97\n#: cd79fe63f067476c8342570d590c3121\nmsgid \"bool\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:483 98d329d87318478090434465b043c79d\nmsgid \"\"\n\"The MD5 hashcode (16 bytes) of the pixmap. This is a technical value used\"\n\" for unique identifications.\"\nmsgstr \"픽스맵의 MD5 해시코드(16바이트). 고유 식별에 사용되는 기술적 값입니다.\"\n\n#: ../../pixmap.rst:485 ../../pixmap.rst:537 d353d95ffd0249c9985587a89eec06f3\n#: fe9d2fb1853646c9bb567d4a448e58de\nmsgid \"bytes\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:489 94c016ffd0e94ef8a92a913eac909cf0\nmsgid \"\"\n\"The colorspace of the pixmap. This value may be ``None`` if the image is \"\n\"to be treated as a so-called *image mask* or *stencil mask* (currently \"\n\"happens for extracted PDF document images only).\"\nmsgstr \"픽스맵의 색상 공간. 이미지가 소위 *이미지 마스크* 또는 *스텐실 마스크* 로 처리되는 경우(현재 추출된 PDF 문서 이미지에만 적용) 이 값은 ``None`` 일 수 있습니다.\"\n\n#: ../../pixmap.rst:491 b6cfc944281042b38f313e221d8208ee\nmsgid \":ref:`Colorspace`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:495 6a4abc1ca4ea41e5b98e5867969d0aea\nmsgid \"\"\n\"Contains the length of one row of image data in :attr:`Pixmap.samples`. \"\n\"This is primarily used for calculation purposes. The following \"\n\"expressions are true:\"\nmsgstr \":attr:`Pixmap.samples` 의 이미지 데이터 한 행의 길이를 포함합니다. 주로 계산 목적으로 사용됩니다. 다음 표현식이 참입니다:\"\n\n#: ../../pixmap.rst:497 9ef5987d2b004c03a37ac85ebe94eb90\nmsgid \"`len(samples) == height * stride`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:498 ad30730142bb41048a7ad4d99adb37ff\nmsgid \"`width * n == stride`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:500 ../../pixmap.rst:575 ../../pixmap.rst:581\n#: ../../pixmap.rst:589 ../../pixmap.rst:597 ../../pixmap.rst:603\n#: ../../pixmap.rst:609 ../../pixmap.rst:615 ../../pixmap.rst:621\n#: ../../pixmap.rst:627 565eef89a4f1443196235c362117a790\n#: 5790752de4bc4483b7998ab835faa57f 6b853b1effba4f9fa88e23a4ae3e5bf7\n#: a40cc5c113bb4004862e82488bb6ad45 accc4d8148f54c7db1495d30f6c968f0\n#: bca3975d0f204589a21f970e856552f3 d03716e1479c4f6b823e4712bf40c8e9\n#: d2bde8f030b0409d8de6030b27ad0c95 d833bb6cf43f4a109aa43ffba391db0f\n#: d8b756b8057c42329c2c1040697bad3a\nmsgid \"int\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:507 8695567f63d74993b36963cb05639cf6\nmsgid \"Is `True` for a gray pixmap which only has the colors black and white.\"\nmsgstr \"검은색과 흰색만 있는 그레이 픽스맵에 대해 `True` 입니다.\"\n\n#: ../../pixmap.rst:516 b44722fd47e341cb9f851ef65e077148\nmsgid \"\"\n\"Is `True` if all pixels are identical (any colorspace). Where applicable,\"\n\" pixels with different alpha values will be treated as different colors.\"\nmsgstr \"모든 픽셀이 동일한 경우(모든 색상 공간) `True` 입니다. 해당되는 경우 다른 알파 값을 가진 픽셀은 다른 색상으로 처리됩니다.\"\n\n#: ../../pixmap.rst:523 6f074461eb274b3388c6956012c6f942\nmsgid \"Contains the :ref:`IRect` of the pixmap.\"\nmsgstr \"픽스맵의 :ref:`IRect` 를 포함합니다.\"\n\n#: ../../pixmap.rst:525 8f50d53afc654b528e20564902041ddb\nmsgid \":ref:`IRect`\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:529 3abafa8c77804d0482f902d9e46ffb92\nmsgid \"\"\n\"The color and (if :attr:`Pixmap.alpha` is true) transparency values for \"\n\"all pixels. It is an area of `width * height * n` bytes. Each n bytes \"\n\"define one pixel. Each successive n bytes yield another pixel in scanline\"\n\" order. Subsequent scanlines follow each other with no padding. E.g. for \"\n\"an RGBA colorspace this means, *samples* is a sequence of bytes like \"\n\"*..., R, G, B, A, ...*, and the four byte values R, G, B, A define one \"\n\"pixel.\"\nmsgstr \"모든 픽셀의 색상 및 (:attr:`Pixmap.alpha` 가 true인 경우) 투명도 값. `width * height * n` 바이트 영역입니다. 각 n 바이트는 하나의 픽셀을 정의합니다. 연속된 각 n 바이트는 스캔라인 순서로 또 다른 픽셀을 생성합니다. 후속 스캔라인은 패딩 없이 서로 이어집니다. 예를 들어 RGBA 색상 공간의 경우, *samples* 는 *..., R, G, B, A, ...* 와 같은 바이트 시퀀스이며, 네 개의 바이트 값 R, G, B, A가 하나의 픽셀을 정의합니다.\"\n\n#: ../../pixmap.rst:531 4d2c9332a9384bb2ac55549aea165f04\nmsgid \"\"\n\"This area can be passed to other graphics libraries like PIL (Python \"\n\"Imaging Library) to do additional processing like saving the pixmap in \"\n\"other image formats.\"\nmsgstr \"이 영역은 PIL(Python Imaging Library)과 같은 다른 그래픽 라이브러리에 전달하여 다른 이미지 형식으로 픽스맵을 저장하는 등의 추가 처리를 수행할 수 있습니다.\"\n\n#: ../../pixmap.rst:534 44ba67d25a5246c9b5c0fd86fc515d65\nmsgid \"\"\n\"The underlying data is typically a **large** memory area, from which a \"\n\"`bytes` copy is made for this attribute ... each time you access it: for \"\n\"example an RGB-rendered letter page has a samples size of almost 1.4 MB. \"\n\"So consider assigning a new variable to it or use the `memoryview` \"\n\"version :attr:`Pixmap.samples_mv` (new in v1.18.17).\"\nmsgstr \"기본 데이터는 일반적으로 **큰** 메모리 영역이며, 이 속성에 접근할 때마다 `bytes` 복사본이 생성됩니다: 예를 들어 RGB로 렌더링된 레터 페이지는 samples 크기가 거의 1.4MB입니다. 따라서 새 변수에 할당하거나 `memoryview` 버전 :attr:`Pixmap.samples_mv` (v1.18.17에서 새로 추가됨)를 사용하세요.\"\n\n#: ../../pixmap.rst:535 028c2991fa3746d8ba4fcb1363e0ac36\nmsgid \"\"\n\"Any changes to the underlying data are available only after accessing \"\n\"this attribute again. This is different from using the memoryview \"\n\"version.\"\nmsgstr \"기본 데이터에 대한 모든 변경 사항은 이 속성에 다시 접근한 후에만 사용할 수 있습니다. 이것은 memoryview 버전을 사용하는 것과 다릅니다.\"\n\n#: ../../pixmap.rst:541 ../../pixmap.rst:563 6231b732cd664d9ea3f80fe04f0151c9\n#: a54baa772ece47f4b743977662b324a4\nmsgid \"New in v1.18.17\"\nmsgstr \"v1.18.17에서 새로 추가됨\"\n\n#: ../../pixmap.rst:543 090480ef9ce349efab292a2a0fe883b7\nmsgid \"\"\n\"Like :attr:`Pixmap.samples`, but in Python `memoryview` format. It is \"\n\"built pointing to the memory in the pixmap -- not from a copy of it. So \"\n\"its creation speed is independent from the pixmap size, and any changes \"\n\"to pixels will be available immediately.\"\nmsgstr \":attr:`Pixmap.samples` 와 유사하지만 Python `memoryview` 형식입니다. 픽스맵의 메모리를 가리키도록 구축됩니다 -- 복사본이 아닙니다. 따라서 생성 속도는 픽스맵 크기와 무관하며 픽셀에 대한 모든 변경 사항이 즉시 사용 가능합니다.\"\n\n#: ../../pixmap.rst:545 93fdd4817c6d451593bce44eed03a5c1\nmsgid \"\"\n\"Copies like `bytearray(pix.samples_mv)`, or `bytes(pixmap.samples_mv)` \"\n\"are equivalent to and can be used in place of `pix.samples`.\"\nmsgstr \"`bytearray(pix.samples_mv)` 또는 `bytes(pixmap.samples_mv)` 와 같은 복사본은 `pix.samples` 와 동일하며 대신 사용할 수 있습니다.\"\n\n#: ../../pixmap.rst:547 a15d8e7edd204441a7b9a76052a64fac\nmsgid \"We also have `len(pix.samples) == len(pix.samples_mv)`.\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:549 f7663a0870b54e46b8a6d53a9a5d3958\nmsgid \"\"\n\"Look at this example from a 2 MB JPEG: the memoryview is **ten thousand \"\n\"times faster**::\"\nmsgstr \"2MB JPEG의 이 예제를 보세요: memoryview가 **만 배 빠릅니다**::\"\n\n#: ../../pixmap.rst:556 4d36f9e0a4af4491be38efa57f54faf8\nmsgid \"\"\n\"After the Pixmap has been destroyed, any attempt to use the memoryview \"\n\"will fail with ValueError.\"\nmsgstr \"Pixmap이 파괴된 후 memoryview를 사용하려는 시도는 ValueError로 실패합니다.\"\n\n#: ../../pixmap.rst:559 91107ae487b14fe0b83a14f571082c55\nmsgid \"memoryview\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:565 d3bfaae3761a4c0eb851933ffe8701a3\nmsgid \"\"\n\"Python pointer to the pixel area. This is a special integer format, which\"\n\" can be used by supporting applications (such as PyQt) to directly \"\n\"address the samples area and thus build their images extremely fast. For \"\n\"example::\"\nmsgstr \"픽셀 영역에 대한 Python 포인터. 이것은 지원 애플리케이션(예: PyQt)이 samples 영역을 직접 주소 지정하여 이미지를 매우 빠르게 구축할 수 있도록 하는 특수 정수 형식입니다. 예제::\"\n\n#: ../../pixmap.rst:570 92d9db2f39614549b2c8a9605c681e0b\nmsgid \"\"\n\"Both of the above lead to the same Qt image, but (2) can be **many \"\n\"hundred times faster**, because it avoids an additional copy of the pixel\"\n\" area.\"\nmsgstr \"위의 두 가지 모두 동일한 Qt 이미지를 생성하지만 (2)는 픽셀 영역의 추가 복사를 피하기 때문에 **수백 배 빠를 수 있습니다**.\"\n\n#: ../../pixmap.rst:572 37f284851e024d87b4ae3d3f4b495885\nmsgid \"\"\n\"Warning: after the Pixmap has been destroyed, the Python pointer will be \"\n\"invalid and attempting to use it may crash the Python interpreter.\"\nmsgstr \"경고: Pixmap이 파괴된 후 Python 포인터는 무효화되며 사용을 시도하면 Python 인터프리터가 충돌할 수 있습니다.\"\n\n#: ../../pixmap.rst:579 ad8485f478d04d1791c23f7e6c8cf984\nmsgid \"\"\n\"Contains *len(pixmap)*. This will generally equal *len(pix.samples)* plus\"\n\" some platform-specific value for defining other attributes of the \"\n\"object.\"\nmsgstr \"*len(pixmap)* 을 포함합니다. 이것은 일반적으로 *len(pix.samples)* 에 객체의 다른 속성을 정의하는 플랫폼별 값을 더한 것과 같습니다.\"\n\n#: ../../pixmap.rst:587 c1796fc010774081b59146b900edf924\nmsgid \"Width of the region in pixels.\"\nmsgstr \"픽셀 단위의 영역 너비.\"\n\n#: ../../pixmap.rst:595 d21ef5432611489797b4691400ea9d15\nmsgid \"Height of the region in pixels.\"\nmsgstr \"픽셀 단위의 영역 높이.\"\n\n#: ../../pixmap.rst:601 5f88d51c88864babb326d12c5da3c8b4\nmsgid \"\"\n\"X-coordinate of top-left corner in pixels. Cannot directly be changed -- \"\n\"use :meth:`Pixmap.set_origin`.\"\nmsgstr \"픽셀 단위의 왼쪽 위 모서리 X 좌표. 직접 변경할 수 없습니다 -- :meth:`Pixmap.set_origin` 을 사용하세요.\"\n\n#: ../../pixmap.rst:607 d82f9559530f4ed3a33c06c66cd24f3c\nmsgid \"\"\n\"Y-coordinate of top-left corner in pixels. Cannot directly be changed -- \"\n\"use :meth:`Pixmap.set_origin`.\"\nmsgstr \"픽셀 단위의 왼쪽 위 모서리 Y 좌표. 직접 변경할 수 없습니다 -- :meth:`Pixmap.set_origin` 을 사용하세요.\"\n\n#: ../../pixmap.rst:613 26e889e8aa564bbea3553b3d55151e83\nmsgid \"\"\n\"Number of components per pixel. This number depends on colorspace and \"\n\"alpha. If colorspace is not ``None`` (stencil masks), then *Pixmap.n - \"\n\"Pixmap.alpha == pixmap.colorspace.n* is true. If colorspace is ``None``, \"\n\"then *n == alpha == 1*.\"\nmsgstr \"픽셀당 구성 요소 수. 이 숫자는 색상 공간과 알파에 따라 다릅니다. 색상 공간이 ``None`` 이 아니면(스텐실 마스크) *Pixmap.n - Pixmap.alpha == pixmap.colorspace.n* 이 참입니다. 색상 공간이 ``None`` 이면 *n == alpha == 1* 입니다.\"\n\n#: ../../pixmap.rst:619 ddc7c2c6d915466a8673711ed573419a\nmsgid \"\"\n\"Horizontal resolution in dpi (dots per inch). Please also see \"\n\":data:`resolution`. Cannot directly be changed -- use \"\n\":meth:`Pixmap.set_dpi`.\"\nmsgstr \"dpi(인치당 도트) 단위의 수평 해상도. :data:`resolution` 도 참조하세요. 직접 변경할 수 없습니다 -- :meth:`Pixmap.set_dpi` 를 사용하세요.\"\n\n#: ../../pixmap.rst:625 5952023fee854e3f82d65f1dbcc33361\nmsgid \"\"\n\"Vertical resolution in dpi (dots per inch). Please also see \"\n\":data:`resolution`. Cannot directly be changed -- use \"\n\":meth:`Pixmap.set_dpi`.\"\nmsgstr \"dpi(인치당 도트) 단위의 수직 해상도. :data:`resolution` 도 참조하세요. 직접 변경할 수 없습니다 -- :meth:`Pixmap.set_dpi` 를 사용하세요.\"\n\n#: ../../pixmap.rst:631 966a193e7ae14efe944c435e65718b73\nmsgid \"\"\n\"An information-only boolean flag set to ``True`` if the image will be \"\n\"drawn using \\\"linear interpolation\\\". If ``False`` \\\"nearest neighbour \"\n\"sampling\\\" will be used.\"\nmsgstr \"이미지가 \\\"선형 보간\\\"을 사용하여 그려지면 ``True`` 로 설정되는 정보 전용 불리언 플래그. ``False`` 이면 \\\"최근접 샘플링\\\"이 사용됩니다.\"\n\n#: ../../pixmap.rst:638 32f8505442184689838784d6630b61ca\nmsgid \"Supported Input Image Formats\"\nmsgstr \"지원되는 입력 이미지 형식\"\n\n#: ../../pixmap.rst:639 708fca4db2a64b96a2de83796cd396e7\nmsgid \"\"\n\"The following file types are supported as **input** to construct pixmaps:\"\n\" **BMP, JPEG, GIF, TIFF, JXR, JPX**, **PNG**, **PAM** and all of the \"\n\"**Portable Anymap** family (**PBM, PGM, PNM, PPM**). This support is two-\"\n\"fold:\"\nmsgstr \"다음 파일 유형은 픽스맵을 구성하기 위한 **입력** 으로 지원됩니다: **BMP, JPEG, GIF, TIFF, JXR, JPX**, **PNG**, **PAM** 및 모든 **Portable Anymap** 패밀리(**PBM, PGM, PNM, PPM**). 이 지원은 두 가지 방식입니다:\"\n\n#: ../../pixmap.rst:641 4f4eb0bb22404ab184bf7ed8014abcc3\nmsgid \"\"\n\"Directly create a pixmap with *Pixmap(filename)* or *Pixmap(byterray)*. \"\n\"The pixmap will then have properties as determined by the image.\"\nmsgstr \"*Pixmap(filename)* 또는 *Pixmap(bytearray)* 로 직접 픽스맵을 생성합니다. 픽스맵은 이미지에 의해 결정된 속성을 갖게 됩니다.\"\n\n#: ../../pixmap.rst:643 1f9a875b37444d988033c769493f20e4\nmsgid \"\"\n\"Open such files with *pymupdf.open(...)*. The result will then appear as \"\n\"a document containing one single page. Creating a pixmap of this page \"\n\"offers all the options available in this context: apply a matrix, choose \"\n\"colorspace and alpha, confine the pixmap to a clip area, etc.\"\nmsgstr \"*pymupdf.open(...)* 로 이러한 파일을 엽니다. 결과는 단일 페이지를 포함하는 문서로 나타납니다. 이 페이지의 픽스맵을 생성하면 이 컨텍스트에서 사용 가능한 모든 옵션을 제공합니다: 행렬 적용, 색상 공간 및 알파 선택, 픽스맵을 클립 영역으로 제한 등.\"\n\n#: ../../pixmap.rst:645 b8da58f972e349c099d429016189277f\nmsgid \"\"\n\"**SVG images** are only supported via method 2 above, not directly as \"\n\"pixmaps. But remember: the result of this is a **raster image** as is \"\n\"always the case with pixmaps [#f1]_.\"\nmsgstr \"**SVG 이미지** 는 위의 방법 2를 통해서만 지원되며 픽스맵으로 직접 지원되지 않습니다. 하지만 기억하세요: 이것의 결과는 픽스맵의 경우처럼 항상 **래스터 이미지** 입니다 [#f1]_.\"\n\n#: ../../pixmap.rst:650 5eb573904fb7401cb281c16fb4549f3a\nmsgid \"Supported Output Image Formats\"\nmsgstr \"지원되는 출력 이미지 형식\"\n\n#: ../../pixmap.rst:651 e4357173b7ec40d892ee19fcd4f3b83d\nmsgid \"\"\n\"A number of image **output** formats are supported. You have the option \"\n\"to either write an image directly to a file (:meth:`Pixmap.save`), or to \"\n\"generate a bytes object (:meth:`Pixmap.tobytes`). Both methods accept a \"\n\"string identifying the desired format (**Format** column below). Please \"\n\"note that not all combinations of pixmap colorspace, transparency support\"\n\" (alpha) and image format are possible.\"\nmsgstr \"다수의 이미지 **출력** 형식이 지원됩니다. 이미지를 파일에 직접 쓰기(:meth:`Pixmap.save`) 또는 bytes 객체 생성(:meth:`Pixmap.tobytes`) 중 선택할 수 있습니다. 두 메서드 모두 원하는 형식을 식별하는 문자열(아래 **Format** 열)을 허용합니다. 픽스맵 색상 공간, 투명도 지원(알파) 및 이미지 형식의 모든 조합이 가능한 것은 아닙니다.\"\n\n#: ../../pixmap.rst:654 4dbea7a06e2b4187a123a1c604d44efe\nmsgid \"**Format**\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:654 80b26e8d30f3423393a42e35c1a19bb0\nmsgid \"**Colorspaces**\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:654 227b7bee485d4b79a2402f03891614ea\nmsgid \"**alpha**\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:654 9797dfa1d6b74610af214069c4ee23d6\nmsgid \"**Extensions**\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:654 a635c115d504411785c1bf1a3984582a\nmsgid \"**Description**\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 3f28e0c2c0e44d239075c2258795286a\nmsgid \"jpg, jpeg\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 ../../pixmap.rst:657 ../../pixmap.rst:663\n#: ../../pixmap.rst:664 18832c370236476095068f372050837f\n#: 3eb2a94753b44fdd9c7731ef24aef48b 4a67821c83134b4db3e4be1914c17d60\n#: c83309e3c1934fc7ae1a973ebe7d1300\nmsgid \"gray, rgb, cmyk\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 ../../pixmap.rst:658 ../../pixmap.rst:659\n#: ../../pixmap.rst:661 ../../pixmap.rst:662 ../../pixmap.rst:663\n#: 02f9cb78532645d38d5abf940e1679f8 0cdb296b3e59480f8ec76bf53ac1c17b\n#: 2e0bd0a838434201878c609cff82145c 73c34c7c328f4d31af9f2258cc254f0d\n#: 947c1b80c66441799e2aba09091f8adb dd93afdec02947318d933a37f2c15024\nmsgid \"no\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 600504f9efd041ffb5b69ec388b137e9\nmsgid \".jpg, .jpeg\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:656 26fa6ed5043a4a66a2c7adf39eb4e0cf\nmsgid \"Joint Photographic Experts Group\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:657 6f1f99578dd84b0b96b1fb4707aac08b\nmsgid \"pam\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:657 ../../pixmap.rst:660 ../../pixmap.rst:664\n#: 1389030dbadc408693776ddaa02d250f db4043e33252451d9cfa830afcf4325c\n#: eb6f616d9083427b85a8e817b7b3c601\nmsgid \"yes\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:657 2f529016f72342f3ad621590a17c2720\nmsgid \".pam\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:657 e2baced162604080b59bf27d358fda6c\nmsgid \"Portable Arbitrary Map\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 95a9f8727e6846bdad7d42b2756dcf5e\nmsgid \"pbm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 ../../pixmap.rst:659 ../../pixmap.rst:660\n#: ../../pixmap.rst:661 ../../pixmap.rst:662 220d5771addc47059dfafb3b7fd7a809\n#: 68fd8f934dac404f86a38dcab3bb7bc2 91f4a25b5a5148af9a8c601bdc987ee9\n#: 9d56458bd5944b7eab22abdec12c33c6 da23d0d1e79b4239bc3b878fd251ed6f\nmsgid \"gray, rgb\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 10546c5955514cb99a4533ae396c259f\nmsgid \".pbm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:658 3a22578bed7f479ba9f8bd94ddba617b\nmsgid \"Portable Bitmap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:659 12f4977253d34e7fb05ef71f9b6bb875\nmsgid \"pgm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:659 34b5715a5a94481fa5410ee5467f5ae1\nmsgid \".pgm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:659 06d8a88352b54e25b36fc1dbd2289ecc\nmsgid \"Portable Graymap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:660 31684d0764064d42a3a8d884741e85be\nmsgid \"png\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:660 34455c189f334f3ab56545b979560b1b\nmsgid \".png\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:660 682ed1780ad3421e9223fdefb0b8184c\nmsgid \"Portable Network Graphics\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:661 f94a2f8f962f47fc9c9b1a7e2a906e11\nmsgid \"pnm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:661 964f7dfd9ae844129b05d2e56342317d\nmsgid \".pnm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:661 d627891286e44ad3987520c5e705f3a1\nmsgid \"Portable Anymap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:662 3ada12b4d8b84c17aac44fec31492b76\nmsgid \"ppm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:662 29fa1a416b3345479d3cb7258b83155e\nmsgid \".ppm\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:662 9045e7c717ae4d61ae56392d64c8f030\nmsgid \"Portable Pixmap\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:663 b528c16c8d064788976a0d977cf72a73\nmsgid \"ps\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:663 3d3a984cad1f4a1ba8eca7cfbc0af43f\nmsgid \".ps\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:663 f472a32950f140dcbd4258d41e955e95\nmsgid \"Adobe PostScript Image\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:664 d30993e0b1534a1da119de1e713e1fe7\nmsgid \"psd\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:664 c340e5edd2234429989f7c57fcbe6d4f\nmsgid \".psd\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:664 5ad137cb3c0c44fb8491eab0123adabe\nmsgid \"Adobe Photoshop Document\"\nmsgstr \"\"\n\n#: ../../pixmap.rst:668 5b70a01cdd2d49678a5104943c6ceb05\nmsgid \"\"\n\"Not all image file types are supported (or at least common) on all OS \"\n\"platforms. E.g. PAM and the Portable Anymap formats are rare or even \"\n\"unknown on Windows.\"\nmsgstr \"모든 OS 플랫폼에서 모든 이미지 파일 유형이 지원되거나 일반적이지는 않습니다. 예를 들어 PAM 및 Portable Anymap 형식은 Windows에서 드물거나 알려지지 않았습니다.\"\n\n#: ../../pixmap.rst:669 ac24d0029a85434e89d87aea3c768299\nmsgid \"\"\n\"Especially pertaining to CMYK colorspaces, you can always convert a CMYK \"\n\"pixmap to an RGB pixmap with *rgb_pix = pymupdf.Pixmap(pymupdf.csRGB, \"\n\"cmyk_pix)* and then save that in the desired format.\"\nmsgstr \"특히 CMYK 색상 공간에 대해 항상 *rgb_pix = pymupdf.Pixmap(pymupdf.csRGB, cmyk_pix)* 로 CMYK 픽스맵을 RGB 픽스맵으로 변환한 다음 원하는 형식으로 저장할 수 있습니다.\"\n\n#: ../../pixmap.rst:670 0d389b2c11cb4b7dbad0be0409dbf4dc\nmsgid \"\"\n\"As can be seen, MuPDF's image support range is different for input and \"\n\"output. Among those supported both ways, PNG and JPEG are probably the \"\n\"most popular.\"\nmsgstr \"볼 수 있듯이 MuPDF의 이미지 지원 범위는 입력과 출력에 따라 다릅니다. 양쪽 모두 지원되는 것 중에서 PNG와 JPEG가 가장 인기 있을 것입니다.\"\n\n#: ../../pixmap.rst:671 78fe092f468843e984dee90661b2dbac\nmsgid \"\"\n\"We also recommend using \\\"ppm\\\" formats as input to tkinter's \"\n\"*PhotoImage* method like this: *tkimg = \"\n\"tkinter.PhotoImage(data=pix.tobytes(\\\"ppm\\\"))* (also see the tutorial). \"\n\"This is **very** fast (**60 times** faster than PNG).\"\nmsgstr \"tkinter의 *PhotoImage* 메서드에 입력으로 \\\"ppm\\\" 형식을 사용하는 것도 권장합니다: *tkimg = tkinter.PhotoImage(data=pix.tobytes(\\\"ppm\\\"))* (튜토리얼도 참조). 이것은 **매우** 빠릅니다(PNG보다 **60배** 빠름).\"\n\n#: ../../pixmap.rst:676 ae8dd148bf7a4c1ea2de109295f929f5\nmsgid \"Footnotes\"\nmsgstr \"Footnotes\"\n\n#: ../../pixmap.rst:677 b53f5a80a69a41dea8df4b23d4e4be3d\nmsgid \"\"\n\"If you need a **vector image** from the SVG, you must first convert it to\"\n\" a PDF. Try :meth:`Document.convert_to_pdf`. If this is not good enough, \"\n\"look for other SVG-to-PDF conversion tools like the Python packages \"\n\"`svglib <https://pypi.org/project/svglib>`_, `CairoSVG \"\n\"<https://pypi.org/project/cairosvg>`_, `Uniconvertor \"\n\"<https://sk1project.net/modules.php?name=Products&product=uniconvertor&op=download>`_\"\n\" or the Java solution `Apache Batik <https://github.com/apache/batik>`_. \"\n\"Have a look at our Wiki for more examples.\"\nmsgstr \"SVG에서 **벡터 이미지** 가 필요한 경우 먼저 PDF로 변환해야 합니다. :meth:`Document.convert_to_pdf` 를 시도해보세요. 이것으로 충분하지 않으면 Python 패키지 `svglib <https://pypi.org/project/svglib>`_, `CairoSVG <https://pypi.org/project/cairosvg>`_, `Uniconvertor <https://sk1project.net/modules.php?name=Products&product=uniconvertor&op=download>`_ 또는 Java 솔루션 `Apache Batik <https://github.com/apache/batik>`_ 과 같은 다른 SVG-to-PDF 변환 도구를 찾아보세요. 더 많은 예제는 Wiki를 참조하세요.\"\n\n#: ../../pixmap.rst:679 7efc30a117974783984b2f586a774632\nmsgid \"\"\n\"To also set the alpha property, add an additional step to this method by \"\n\"dropping or adding an alpha channel to the result.\"\nmsgstr \"알파 속성도 설정하려면 결과에 알파 채널을 제거하거나 추가하여 이 메서드에 추가 단계를 더하십시오.\"\n\n#: ../../footer.rst:46 e3d72edf62c54080b2839fccccec965e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/point.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ff7f2bbd27574c06a12cfe0f8feaa292\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 a938f9fbdec343399166b697412bd381\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 9b1b01d63ee048cba25d12397c4cbc9c\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../point.rst:7 14b832da77494838a52695d7ed883865\nmsgid \"Point\"\nmsgstr \"Point\"\n\n#: ../../point.rst:9 ee92bfad50f840c592179ff205c48652\nmsgid \"\"\n\"*Point* represents a point in the plane, defined by its x and y \"\n\"coordinates.\"\nmsgstr \"*Point* 는 x 및 y 좌표로 정의되는 평면상의 점을 나타냅니다.\"\n\n#: ../../point.rst:12 d95d005e957741acbcc453b2978ab474\nmsgid \"**Attribute / Method**\"\nmsgstr \"**속성 / 메서드**\"\n\n#: ../../point.rst:12 6cc17250feda46f3895c61daf01ae9ef\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../point.rst:14 41c8142652234b88ac19813753d3307e\nmsgid \":meth:`Point.distance_to`\"\nmsgstr \":meth:`Point.distance_to`\"\n\n#: ../../point.rst:14 261845b5a5b24bf0b064101ff507b23b\nmsgid \"calculate distance to point or rect\"\nmsgstr \"점 또는 사각형까지의 거리 계산\"\n\n#: ../../point.rst:15 4aa6b4f0719c46e498b43fe18d24f3eb\nmsgid \":meth:`Point.norm`\"\nmsgstr \":meth:`Point.norm`\"\n\n#: ../../point.rst:15 bb965571d49042f990f2ce83a5b1d501\nmsgid \"the Euclidean norm\"\nmsgstr \"유클리드 노름\"\n\n#: ../../point.rst:16 8fa73d7331154012aedebe7f5f583ef0\nmsgid \":meth:`Point.transform`\"\nmsgstr \":meth:`Point.transform`\"\n\n#: ../../point.rst:16 513606c9c9c24e929a77cffeb961406c\nmsgid \"transform point with a matrix\"\nmsgstr \"행렬로 점 변환\"\n\n#: ../../point.rst:17 2cb5652a207046aabd4833605b0db9a7\nmsgid \":attr:`Point.abs_unit`\"\nmsgstr \":attr:`Point.abs_unit`\"\n\n#: ../../point.rst:17 a5938582888c4a3bb9c18a1c3f20c2e8\nmsgid \"same as unit, but positive coordinates\"\nmsgstr \"unit과 동일하지만 좌표가 양수\"\n\n#: ../../point.rst:18 3e5b94700abd4e9f9ee59f420160e03b\nmsgid \":attr:`Point.unit`\"\nmsgstr \":attr:`Point.unit`\"\n\n#: ../../point.rst:18 2b7bbc4e8d9b49fd90eba605096d6695\nmsgid \"point coordinates divided by *abs(point)*\"\nmsgstr \"*abs(point)* 로 나눈 점 좌표\"\n\n#: ../../point.rst:19 31b75b9a5271468b91957b2b1e4f4cdc\nmsgid \":attr:`Point.x`\"\nmsgstr \":attr:`Point.x`\"\n\n#: ../../point.rst:19 62613a63800c42a9b2e4b7e25ce06a1b\nmsgid \"the X-coordinate\"\nmsgstr \"X 좌표\"\n\n#: ../../point.rst:20 03bda37b4f4e43d5b2c87664d47e7c88\nmsgid \":attr:`Point.y`\"\nmsgstr \":attr:`Point.y`\"\n\n#: ../../point.rst:20 1f7a039317c9403b9eef49abcffc3c17\nmsgid \"the Y-coordinate\"\nmsgstr \"Y 좌표\"\n\n#: ../../point.rst:23 226585c9d32d4bdda8ea50151987bb6f\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../point.rst:35 52e6fd50060a435cbcd1ea5ea07199d9\nmsgid \"Overloaded constructors.\"\nmsgstr \"오버로드된 생성자.\"\n\n#: ../../point.rst:37 858213bf59564a6493343f329aa59c60\nmsgid \"Without parameters, *Point(0, 0)* will be created.\"\nmsgstr \"매개변수 없이 *Point(0, 0)* 이 생성됩니다.\"\n\n#: ../../point.rst:39 fe4c165d5aa24d3a979783344bfd9ac0\nmsgid \"\"\n\"With another point specified, a **new copy** will be created, \"\n\"\\\"sequence\\\" is a Python sequence of 2 numbers (see \"\n\":ref:`SequenceTypes`).\"\nmsgstr \"다른 점이 지정되면 **새 복사본** 이 생성됩니다. \\\"sequence\\\"는 2개의 숫자로 구성된 Python 시퀀스입니다(:ref:`SequenceTypes` 참조).\"\n\n#: ../../point.rst 0eddda1bb6c54ccaa7d284736b29da50\n#: 3b9ed60226ef48f0a657c5ba46c27350 c7f85b4fbec2467896a422f72188865d\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../point.rst:41 97152760b7ba410cb622804600ef1a35\nmsgid \"x coordinate of the point\"\nmsgstr \"점의 x 좌표\"\n\n#: ../../point.rst:43 7926764c81784f70845fd05cb89d5865\nmsgid \"y coordinate of the point\"\nmsgstr \"점의 y 좌표\"\n\n#: ../../point.rst:47 5c3faa24b7e144068803db83b33fe793\nmsgid \"\"\n\"Calculate the distance to *x*, which may be :data:`point_like` or \"\n\":data:`rect_like`. The distance is given in units of either pixels \"\n\"(default), inches, centimeters or millimeters.\"\nmsgstr \"*x* 까지의 거리를 계산합니다. *x* 는 :data:`point_like` 또는 :data:`rect_like` 일 수 있습니다. 거리는 픽셀(기본값), 인치, 센티미터 또는 밀리미터 단위로 제공됩니다.\"\n\n#: ../../point.rst:49 44d8777c04344d47bc4a9242808880d1\nmsgid \"to which to compute the distance.\"\nmsgstr \"거리를 계산할 대상.\"\n\n#: ../../point.rst:51 91e44f65560e4211accb6c725eebfdd6\nmsgid \"the unit to be measured in. One of \\\"px\\\", \\\"in\\\", \\\"cm\\\", \\\"mm\\\".\"\nmsgstr \"측정 단위. \\\"px\\\", \\\"in\\\", \\\"cm\\\", \\\"mm\\\" 중 하나.\"\n\n#: ../../point.rst 64687f2c94ef4b5ba2750e3eb184ad05\n#: cd80063c5dc9498cbbdd25b759d31cdb\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../point.rst a750839310d34c5d887db8268777489a\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../point.rst:54 bc0f187b31f44a7181e31d08f7c53a82\nmsgid \"\"\n\"the distance to *x*. If this is :data:`rect_like`, then the distance  * \"\n\"is the length of the shortest line connecting to one of the rectangle \"\n\"sides * is calculated to the **finite version** of it * is zero if it \"\n\"**contains** the point\"\nmsgstr \"\"\n\n#: ../../point.rst:54 ae37d128ae1440f3bbd8ed1ea99f2152\nmsgid \"the distance to *x*. If this is :data:`rect_like`, then the distance\"\nmsgstr \"*x* 까지의 거리. 이것이 :data:`rect_like` 인 경우, 거리는\"\n\n#: ../../point.rst:56 9ee6925c977945fe973ed9ab955366b2\nmsgid \"\"\n\"is the length of the shortest line connecting to one of the rectangle \"\n\"sides\"\nmsgstr \"사각형의 한 변에 연결하는 가장 짧은 선의 길이\"\n\n#: ../../point.rst:57 3081d399626b49c987de03dbfa3d0ff5\nmsgid \"is calculated to the **finite version** of it\"\nmsgstr \"그것의 **유한 버전** 에 대해 계산됨\"\n\n#: ../../point.rst:58 c71eaa596c2c423b862c9e70cb89f044\nmsgid \"is zero if it **contains** the point\"\nmsgstr \"점을 **포함** 하면 0\"\n\n#: ../../point.rst:62 a6403033f7bf44a591174a022d0fdf1c\nmsgid \"New in version 1.16.0\"\nmsgstr \"버전 1.16.0에서 새로 추가됨\"\n\n#: ../../point.rst:64 7ece798ec8144d4692eb9a2959a40823\nmsgid \"\"\n\"Return the Euclidean norm (the length) of the point as a vector. Equals \"\n\"result of function *abs()*.\"\nmsgstr \"점의 유클리드 노름(길이)을 벡터로 반환합니다. 함수 *abs()* 의 결과와 같습니다.\"\n\n#: ../../point.rst:68 f946cd0be509442bb0d77202325e2f96\nmsgid \"Apply a matrix to the point and replace it with the result.\"\nmsgstr \"점에 행렬을 적용하고 결과로 대체합니다.\"\n\n#: ../../point.rst:70 97f1624c012a40e1b233376529f768b0\nmsgid \"The matrix to be applied.\"\nmsgstr \"적용할 행렬.\"\n\n#: ../../point.rst:72 ../../point.rst:80 ../../point.rst:86\n#: 18880915c78345d4a3e9807be13f50b7 52b88570e26b4eb5b5d6335523021f5f\n#: aab72bb00a464b30aa87b8638935ebd6\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../point.rst:76 348afd234c5c4c98ba5a47b9d5463fbb\nmsgid \"\"\n\"Result of dividing each coordinate by *norm(point)*, the distance of the \"\n\"point to (0,0). This is a vector of length 1 pointing in the same \"\n\"direction as the point does. Its x, resp. y values are equal to the \"\n\"cosine, resp. sine of the angle this vector (and the point itself) has \"\n\"with the x axis.\"\nmsgstr \"각 좌표를 *norm(point)*, 점에서 (0,0)까지의 거리로 나눈 결과입니다. 이것은 점과 같은 방향을 가리키는 길이 1의 벡터입니다. x, 각각 y 값은 이 벡터(및 점 자체)가 x축과 이루는 각도의 코사인, 각각 사인과 같습니다.\"\n\n#: ../../point.rst 68c8e993f1924162940b72535b1ce094\n#: 74cca4c04a7c48d1a05b1cef455309b7 8ab750f04c354beda9b8193eb29e148a\n#: c3fab6e7e5714f6cb98f51b356a62c80\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../point.rst:84 1c2c3c05d9164c73a34b01b96b77e536\nmsgid \"\"\n\"Same as :attr:`unit` above, replacing the coordinates with their absolute\"\n\" values.\"\nmsgstr \"위의 :attr:`unit` 과 동일하지만 좌표를 절댓값으로 대체합니다.\"\n\n#: ../../point.rst:90 fd219a7540914e5ea48f7ac85865752a\nmsgid \"The x coordinate\"\nmsgstr \"x 좌표\"\n\n#: ../../point.rst:92 ../../point.rst:98 2782c521357b46fcb493227c412705b4\n#: 7c544b58e0744796b55d935cf4074748\nmsgid \"float\"\nmsgstr \"float\"\n\n#: ../../point.rst:96 49f24b3a0ef74f0c936055a979a0c047\nmsgid \"The y coordinate\"\nmsgstr \"y 좌표\"\n\n#: ../../point.rst:102 89afd299e213428fb3ff2efbf34ee8cf\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"이 클래스는 Python 시퀀스 프로토콜을 따르므로 구성 요소는 인덱스를 통해 액세스할 수도 있습니다. :ref:`SequenceTypes` 도 참조하세요.\"\n\n#: ../../point.rst:103 211bda314be541968172253f25a72895\nmsgid \"\"\n\"Rectangles can be used with arithmetic operators -- see chapter \"\n\":ref:`Algebra`.\"\nmsgstr \"사각형은 산술 연산자와 함께 사용할 수 있습니다 -- :ref:`Algebra` 장을 참조하세요.\"\n\n#: ../../footer.rst:46 065c44f95f8c488584785e74c127cd30\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/pymupdf-layout/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 16:19+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 26c7f492ac6349fe997fad9d41aabea5\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 4231d660381d4fa5b43b5d8b068e8dfa\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8bba0218b1e445b192946cba4c548076\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../pymupdf-layout/index.rst:8 65880921881d4c9a95f25a114c1617cc\nmsgid \"PyMuPDF Layout\"\nmsgstr \"PyMuPDF Layout\"\n\n#: ../../pymupdf-layout/index.rst:11 26826b75387e4aadb2a29e8f577d4b8a\nmsgid \"\"\n\"|PyMuPDF Layout| is a lightweight layout analysis extension for |PyMuPDF|\"\n\" that turns PDFs into clean, structured data with minimal setup. It’s \"\n\"fast, accurate, and efficient without any GPU requirement.\"\nmsgstr \"|PyMuPDF Layout| 는 |PyMuPDF| 를 위한 경량 레이아웃 분석 확장으로, 최소한의 설정으로 PDF를 깔끔하고 구조화된 데이터로 변환합니다. GPU 요구 사항 없이 빠르고 정확하며 효율적입니다.\"\n\n#: ../../pymupdf-layout/index.rst:13 20fc4e9d5eae44d58cced93202624c15\nmsgid \"\"\n\"It is an optional, but recommended, addition to the |PyMuPDF| library \"\n\"especially if you are required to more accurately extract structured data\"\n\" with better semantic information.\"\nmsgstr \"이것은 |PyMuPDF| 라이브러리에 대한 선택적이지만 권장되는 추가 기능이며, 특히 더 나은 의미 정보로 구조화된 데이터를 더 정확하게 추출해야 하는 경우에 유용합니다.\"\n\n#: ../../pymupdf-layout/index.rst:17 6cb4d2e97d464990a633d2defd97698e\nmsgid \"Installing\"\nmsgstr \"설치\"\n\n#: ../../pymupdf-layout/index.rst:19 85aefd1baecd485b800f2238aba711c7\nmsgid \"Install from |PyPI| with::\"\nmsgstr \"|PyPI| 에서 설치합니다::\"\n\n#: ../../pymupdf-layout/index.rst:28 5e49fc1022b0491e968e6dac9a6ebd28\nmsgid \"Using\"\nmsgstr \"사용\"\n\n#: ../../pymupdf-layout/index.rst:31 c4caa7b3525f461385db5339599b8e02\nmsgid \"\"\n\"In nutshell, |PyMuPDF Layout| detects the layout to extract, but we need \"\n\"|PyMuPDF4LLM| for the API interface. This provides us with options to \"\n\"extract document content as |Markdown|, |JSON| or |TXT|.\"\nmsgstr \"요약하면, |PyMuPDF Layout| 는 추출할 레이아웃을 감지하지만 API 인터페이스를 위해 |PyMuPDF4LLM| 이 필요합니다. 이것은 문서 콘텐츠를 |Markdown|, |JSON| 또는 |TXT| 로 추출하는 옵션을 제공합니다.\"\n\n#: ../../pymupdf-layout/index.rst:33 2851cd8bd3374a3c8fc60a4a0fe524e8\nmsgid \"\"\n\"Let's set up the Python coding environment to get started and open a PDF \"\n\"then we'll move on to the semantic data extraction.\"\nmsgstr \"시작하기 위해 Python 코딩 환경을 설정하고 PDF를 연 다음 의미 데이터 추출로 넘어가겠습니다.\"\n\n#: ../../pymupdf-layout/index.rst:36 6a1648fb91cc454788a795ffc391432a\nmsgid \"Register packages and open a PDF\"\nmsgstr \"패키지 등록 및 PDF 열기\"\n\n#: ../../pymupdf-layout/index.rst:38 1ba188d096bc425abbfee2ba07430823\nmsgid \"First up let's import the libraries and open a sample document::\"\nmsgstr \"먼저 라이브러리를 가져오고 샘플 문서를 엽니다::\"\n\n#: ../../pymupdf-layout/index.rst:44 d7900ddabe0644c09c53ba9fb57126b0\nmsgid \"\"\n\"Note, in the above code, that |PyMuPDF Layout| must be imported as shown \"\n\"and before importing |PyMuPDF4LLM| to activate |PyMuPDF|'s layout feature\"\n\" and make it available to |PyMuPDF4LLM|.\"\nmsgstr \"위 코드에서 |PyMuPDF Layout| 는 표시된 대로 가져와야 하며, |PyMuPDF| 의 레이아웃 기능을 활성화하고 |PyMuPDF4LLM| 에서 사용할 수 있도록 하려면 |PyMuPDF4LLM| 를 가져오기 전에 가져와야 합니다.\"\n\n#: ../../pymupdf-layout/index.rst:46 7b66dd7c7a164f99b1fd0113f2ccf699\nmsgid \"\"\n\"Omitting the first line would cause execution of standard |PyMuPDF4LLM| -\"\n\" without the layout feature!\"\nmsgstr \"첫 번째 줄을 생략하면 레이아웃 기능 없이 표준 |PyMuPDF4LLM| 이 실행됩니다!\"\n\n#: ../../pymupdf-layout/index.rst:49 a21b9bc7b3844b0ab455c3f364a2057f\nmsgid \"Extract the structured data\"\nmsgstr \"구조화된 데이터 추출\"\n\n#: ../../pymupdf-layout/index.rst:51 35bc60862bb24334a75b7dc95b60156f\nmsgid \"\"\n\"We've activated the |PyMuPDF Layout| library and we've loaded a document,\"\n\" next let's extract the structured data. This is now like a super-charged\"\n\" version of standard |PyMuPDF4LLM| with ``Layout`` working behind the \"\n\"scenes combining heuristics with machine learning - for better extraction\"\n\" results.\"\nmsgstr \"|PyMuPDF Layout| 라이브러리를 활성화하고 문서를 로드했으므로, 이제 구조화된 데이터를 추출하겠습니다. 이것은 이제 휴리스틱과 머신러닝을 결합하여 배후에서 작동하는 ``Layout`` 을 가진 표준 |PyMuPDF4LLM| 의 강화된 버전과 같습니다 -- 더 나은 추출 결과를 위해.\"\n\n#: ../../pymupdf-layout/index.rst:54 8fabaa7045ea40bca50d9b6cf1904b2b\nmsgid \"Extract as Markdown\"\nmsgstr \"Markdown 으로 추출\"\n\n#: ../../pymupdf-layout/index.rst:62 253f86c879cd4cfda51045e1311a3cba\nmsgid \"Extract as JSON\"\nmsgstr \"JSON 으로 추출\"\n\n#: ../../pymupdf-layout/index.rst:70 8da4947d5b974f24803ba5ed16e8cd77\nmsgid \"Extract as TXT\"\nmsgstr \"TXT 로 추출\"\n\n#: ../../pymupdf-layout/index.rst:78 5bbe37c28031413fa4f86978d66b0161\nmsgid \"\"\n\"Please refer top the full :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` for \"\n\"more.\"\nmsgstr \"자세한 내용은 전체 :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` 를 참조하세요.\"\n\n#: ../../pymupdf-layout/index.rst:80 6eedc55b27574fb583b04a9b9f3e3f55\nmsgid \"Finally we can save the output to an external file as follows::\"\nmsgstr \"마지막으로 다음과 같이 출력을 외부 파일에 저장할 수 있습니다::\"\n\n#: ../../pymupdf-layout/index.rst:88 9bdb3f269e1c497e91d97cdc3a687bff\nmsgid \"Headers & Footers\"\nmsgstr \"헤더 및 푸터\"\n\n#: ../../pymupdf-layout/index.rst:91 c239bc0bbbd64d318e6e8fdc55d1efbe\nmsgid \"\"\n\"Many documents will have header and footer information on each page of a \"\n\"PDF which you may or may not want to include. This information can be \"\n\"repetitive and simply not needed ( e.g. the same logo and document title \"\n\"or page number information is not always really important when it comes \"\n\"to extracting the document content ).\"\nmsgstr \"많은 문서는 PDF의 각 페이지에 헤더 및 푸터 정보가 있으며, 이를 포함할 수도 있고 포함하지 않을 수도 있습니다. 이 정보는 반복적일 수 있으며 단순히 필요하지 않을 수 있습니다(예: 동일한 로고 및 문서 제목 또는 페이지 번호 정보는 문서 콘텐츠를 추출할 때 항상 중요하지 않습니다).\"\n\n#: ../../pymupdf-layout/index.rst:93 ee2ea44ed53e4d95860be54bee8ead00\nmsgid \"\"\n\"|PyMuPDF Layout| is trained in detecting these typical document elements \"\n\"and able to omit them.\"\nmsgstr \"|PyMuPDF Layout| 는 이러한 일반적인 문서 요소를 감지하도록 훈련되어 있으며 이를 생략할 수 있습니다.\"\n\n#: ../../pymupdf-layout/index.rst:95 2e53e75f3b83455ab9f885efaae230c7\nmsgid \"\"\n\"So in this case we can adjust our API calls to ignore these elements as \"\n\"follows::\"\nmsgstr \"따라서 이 경우 다음과 같이 API 호출을 조정하여 이러한 요소를 무시할 수 있습니다::\"\n\n#: ../../pymupdf-layout/index.rst:103 fc82782444984a34ab18e40f5123faeb\nmsgid \"\"\n\"Please note that page ``header`` / ``footer`` exclusion is not applicable\"\n\" to JSON output as it aims to always represent all data for the included \"\n\"pages. Please refer to the full :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` \"\n\"for more.\"\nmsgstr \"페이지 ``header`` / ``footer`` 제외는 포함된 페이지의 모든 데이터를 항상 나타내는 것을 목표로 하므로 JSON 출력에는 적용되지 않습니다. 자세한 내용은 전체 :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` 를 참조하세요.\"\n\n#: ../../pymupdf-layout/index.rst:106 a00239ede95b43319833ba01713ce8d7\nmsgid \"Extending Capability\"\nmsgstr \"기능 확장\"\n\n#: ../../pymupdf-layout/index.rst:109 f3bec49e1ee042caad2ba1f1f8d07230\nmsgid \"Using with Pro\"\nmsgstr \"Pro 와 함께 사용\"\n\n#: ../../pymupdf-layout/index.rst:111 1a6a4c0ada2842d588768a849fe3c7f3\nmsgid \"\"\n\"We are able to extend |PyMuPDF Layout| to work with |PyMuPDF Pro| and \"\n\"thus increase our capability by allowing Office documents to be provided \"\n\"as input files. In this case all we have to do is to add the import for \"\n\"|PyMuPDF Pro| and unlock it::\"\nmsgstr \"\"\n\"|PyMuPDF Layout| 를 |PyMuPDF Pro| 와 함께 작동하도록 확장하여 Office 문서를 입력 파일로 제공할 수 있게 하여 기능을 향상시킬 수 있습니다. 이 경우 |PyMuPDF Pro| 를 가져오고 잠금을 해제하기만 하면 됩니다::\"\n\n#: ../../pymupdf-layout/index.rst:118 695ebd9778304b3da362108ea2e9695e\nmsgid \"Now we can happily load Office files and convert them as follows::\"\nmsgstr \"이제 Office 파일을 로드하고 다음과 같이 변환할 수 있습니다::\"\n\n#: ../../pymupdf-layout/index.rst:126 14fdcdcd4aab4335919c50efc4749185\nmsgid \"OCR support\"\nmsgstr \"OCR 지원\"\n\n#: ../../pymupdf-layout/index.rst:128 99eb4f65329d45c7bb6eaf035c255259\nmsgid \"\"\n\"The new layout-sensitive |PyMuPDF4LLM| version also evaluates whether a \"\n\"page would benefit from applying OCR to it. If its heuristics come to \"\n\"this conclusion, the built-in Tesseract-OCR module is automatically \"\n\"invoked. Its results are then handled like normal page content.\"\nmsgstr \"새로운 레이아웃 인식 PyMuPDF4LLM 버전은 페이지에 OCR을 적용하는 것이 유익한지도 평가합니다. 휴리스틱이 이 결론에 도달하면 내장 Tesseract-OCR 모듈이 자동으로 호출됩니다. 그 결과는 일반 페이지 콘텐츠처럼 처리됩니다.\"\n\n#: ../../pymupdf-layout/index.rst:130 cdbf9a9f1f5341cc96aaaa1a6a74434f\nmsgid \"\"\n\"If a page contains (roughly) no text at all, but is covered with images \"\n\"or many character-sized vectors, a check is made using `OpenCV \"\n\"<https://pypi.org/project/opencv-python/>`_ whether text is *probably* \"\n\"detectable on the page at all. This is done to tell apart image-based \"\n\"text from ordinary pictures (like photographs).\"\nmsgstr \"\"\n\"페이지에 (대략적으로) 텍스트가 전혀 없지만 이미지나 많은 문자 크기의 벡터로 덮여 있는 경우, `OpenCV <https://pypi.org/project/opencv-python/>`_ 를 사용하여 페이지에 텍스트가 *아마도* 감지 가능한지 확인합니다. 이것은 이미지 기반 텍스트를 일반 사진(예: 사진)과 구별하기 위해 수행됩니다.\"\n\n#: ../../pymupdf-layout/index.rst:132 8c8ba1c1b2bc4875b04cc60b98293a08\nmsgid \"\"\n\"If the page does contain text but too many characters are unreadable \"\n\"(like \\\"�����\\\"), OCR is also executed, but **for the affected text areas\"\n\" only** -- not the full page. This way, we avoid losing already existing \"\n\"text and other content like images and vectors.\"\nmsgstr \"\"\n\"페이지에 텍스트가 포함되어 있지만 읽을 수 없는 문자가 너무 많은 경우(예: \\\"\\\"), OCR도 실행되지만 **영향을 받은 텍스트 영역에만** -- 전체 페이지가 아닙니다. 이렇게 하면 이미 존재하는 텍스트와 이미지 및 벡터와 같은 다른 콘텐츠를 잃지 않습니다.\"\n\n#: ../../pymupdf-layout/index.rst:134 225a390ebce94321a090f94ab2165c16\nmsgid \"\"\n\"For these heuristics to work we need both, an existing :ref:`Tesseract \"\n\"installation <installation_ocr>` and the availability of `OpenCV \"\n\"<https://pypi.org/project/opencv-python/>`_ in the Python environment. If\"\n\" either is missing, no OCR is attempted at all.\"\nmsgstr \"\"\n\"이러한 휴리스틱이 작동하려면 기존 Tesseract 설치와 Python 환경에서 OpenCV의 가용성이 모두 필요합니다. 둘 중 하나라도 없으면 OCR이 전혀 시도되지 않습니다.\"\n\n#: ../../pymupdf-layout/index.rst:136 08b0b8dca54f41e4a81739a6b2fd1324\nmsgid \"\"\n\"The decision tree for whether OCR is actually used or not depends on the \"\n\"following:\"\nmsgstr \"\"\n\"OCR이 실제로 사용되는지 여부에 대한 결정 트리는 다음에 따라 달라집니다:\"\n\n#: ../../pymupdf-layout/index.rst:138 8cd3ca3cdb2c404eb48ad42a553220de\nmsgid \":ref:`PyMuPDF Layout is imported <pymupdf_layout_using>`\"\nmsgstr \":ref:`PyMuPDF Layout이 가져와짐 <pymupdf_layout_using>`\"\n\n#: ../../pymupdf-layout/index.rst:140 10ee5e795c7446e8b3403d85522a49cd\nmsgid \"\"\n\"In the :ref:`PyMuPDF4LLM API <pymupdf4llm-api>` you have `use_ocr` \"\n\"enabled (this is set to `True` by default)\"\nmsgstr \"\"\n\":ref:`PyMuPDF4LLM API <pymupdf4llm-api>` 에서 `use_ocr` 이 활성화되어 있음(기본값은 `True` 로 설정됨)\"\n\n#: ../../pymupdf-layout/index.rst:142 a91c79870eec43b4b647375636f046ea\nmsgid \":ref:`Tesseract is correctly installed <installation_ocr>`\"\nmsgstr \":ref:`Tesseract가 올바르게 설치됨 <installation_ocr>`\"\n\n#: ../../pymupdf-layout/index.rst:144 32944c44045a42d29563e3e93a1b1d98\nmsgid \"\"\n\"`OpenCV <https://pypi.org/project/opencv-python/>`_ is available in your \"\n\"Python environment\"\nmsgstr \"\"\n\"`OpenCV <https://pypi.org/project/opencv-python/>`_ 가 Python 환경에서 사용 가능함\"\n\n#: ../../pymupdf-layout/index.rst:154 fddcc1ea96e64c658554704bb141490b\nmsgid \"|PyMuPDF Layout| and |PyMuPDF4LLM| parameter caveats\"\nmsgstr \"|PyMuPDF Layout| 및 |PyMuPDF4LLM| 매개변수 주의사항\"\n\n#: ../../pymupdf-layout/index.rst:156 b7f33df2c3974ea1bbead613286f3639\nmsgid \"\"\n\"If you have imported ``pymupdf.layout``, |PyMuPDF4LLM| changes its \"\n\"behavior in various areas quite significantly. New methods become \"\n\"available and also some features are no longer supported. Please visit \"\n\"`this site <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ for\"\n\" a detailed description of the changes. That web site is being kept up to\"\n\" date while we continue to work on improvements.\"\nmsgstr \"\"\n\"``pymupdf.layout`` 를 가져온 경우, |PyMuPDF4LLM| 는 다양한 영역에서 동작이 상당히 크게 변경됩니다. 새로운 메서드가 사용 가능해지고 일부 기능은 더 이상 지원되지 않습니다. 변경 사항에 대한 자세한 설명은 `이 사이트 <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ 를 방문하세요. 개선 작업을 계속하는 동안 해당 웹사이트는 최신 상태로 유지됩니다.\"\n\n#: ../../footer.rst:48 fcc43bbf382644f6928a40bc9aea37c1\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n#~ msgid \"\"\n#~ \"We are able to extend |PyMuPDF \"\n#~ \"Layout| to work with |PyMuPDF Pro| \"\n#~ \"and thus increase our capability by \"\n#~ \"allowing Office documents to be provided\"\n#~ \" as input files. In this case \"\n#~ \"all we have to do is to \"\n#~ \"include the import for |PyMuPDF Pro| \"\n#~ \"and unlock it before we import &\"\n#~ \" activate |PyMuPDF Layout|::\"\n#~ msgstr \"\"\n\n#~ msgid \"If Tesseract is not installed on your platform, no OCR is attempted.\"\n#~ msgstr \"\"\n\n#~ msgid \"PyMuPDF Layout and parameter caveats\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"|PyMuPDF Layout| uses |PyMuPDF4LLM| for \"\n#~ \"its interface. However, if you have \"\n#~ \"imported ``Layout`` then the following \"\n#~ \"caveats apply to the method parameters:\"\n#~ msgstr \"\"\n\n#~ msgid \"Parameter\"\n#~ msgstr \"\"\n\n#~ msgid \"to_markdown\"\n#~ msgstr \"\"\n\n#~ msgid \"to_text\"\n#~ msgstr \"\"\n\n#~ msgid \"to_json\"\n#~ msgstr \"\"\n\n#~ msgid \"Comments\"\n#~ msgstr \"\"\n\n#~ msgid \"doc\"\n#~ msgstr \"\"\n\n#~ msgid \"✔️\"\n#~ msgstr \"\"\n\n#~ msgid \"header\"\n#~ msgstr \"\"\n\n#~ msgid \"ignored\"\n#~ msgstr \"\"\n\n#~ msgid \"**new:** replaces ``margins``\"\n#~ msgstr \"\"\n\n#~ msgid \"footer\"\n#~ msgstr \"\"\n\n#~ msgid \"detect_bg_color\"\n#~ msgstr \"\"\n\n#~ msgid \"❌\"\n#~ msgstr \"\"\n\n#~ msgid \"dpi\"\n#~ msgstr \"\"\n\n#~ msgid \"embed_images\"\n#~ msgstr \"\"\n\n#~ msgid \"extract_words\"\n#~ msgstr \"\"\n\n#~ msgid \"later\"\n#~ msgstr \"\"\n\n#~ msgid \"postponed\"\n#~ msgstr \"\"\n\n#~ msgid \"filename\"\n#~ msgstr \"\"\n\n#~ msgid \"fontsize_limit\"\n#~ msgstr \"\"\n\n#~ msgid \"obsolete\"\n#~ msgstr \"\"\n\n#~ msgid \"force_text\"\n#~ msgstr \"\"\n\n#~ msgid \"text in pictures is always ignored\"\n#~ msgstr \"\"\n\n#~ msgid \"graphics_limit\"\n#~ msgstr \"\"\n\n#~ msgid \"hdr_info\"\n#~ msgstr \"\"\n\n#~ msgid \"ignore_alpha\"\n#~ msgstr \"\"\n\n#~ msgid \"ignore_code\"\n#~ msgstr \"\"\n\n#~ msgid \"ignore_graphics\"\n#~ msgstr \"\"\n\n#~ msgid \"ignore_images\"\n#~ msgstr \"\"\n\n#~ msgid \"image_format\"\n#~ msgstr \"\"\n\n#~ msgid \"image_path\"\n#~ msgstr \"\"\n\n#~ msgid \"image_size_limit\"\n#~ msgstr \"\"\n\n#~ msgid \"margins\"\n#~ msgstr \"\"\n\n#~ msgid \"page_chunks\"\n#~ msgstr \"\"\n\n#~ msgid \"page_height\"\n#~ msgstr \"\"\n\n#~ msgid \"page_separators\"\n#~ msgstr \"\"\n\n#~ msgid \"page_width\"\n#~ msgstr \"\"\n\n#~ msgid \"pages\"\n#~ msgstr \"\"\n\n#~ msgid \"show_progress\"\n#~ msgstr \"\"\n\n#~ msgid \"table_strategy\"\n#~ msgstr \"\"\n\n#~ msgid \"use_glyphs\"\n#~ msgstr \"\"\n\n#~ msgid \"always show &#xfffd;\"\n#~ msgstr \"\"\n\n#~ msgid \"write_images\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"Please note that page ``header`` / \"\n#~ \"``footer`` exclusion is not applicable \"\n#~ \"to JSON output as it aims to \"\n#~ \"always represent all data for the \"\n#~ \"included pages. Please refer top the \"\n#~ \"full :ref:`PyMuPDF4LLM API <pymupdf4llm-api>`\"\n#~ \" for more.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"The new layout-sensitive PyMuPDF4LLM \"\n#~ \"version also evaluates whether a page\"\n#~ \" would benefit from applying OCR to\"\n#~ \" it. If its heuristics come to \"\n#~ \"this conclusion, the built-in \"\n#~ \"Tesseract-OCR module is automatically \"\n#~ \"invoked. Its results are then handled\"\n#~ \" like normal page content.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"If a page contains (roughly) no \"\n#~ \"text at all, but is covered with\"\n#~ \" images or many character-sized \"\n#~ \"vectors, a check is made using \"\n#~ \"`OpenCV <https://pypi.org/project/opencv-python/>`_ \"\n#~ \"whether text is *probably* detectable on\"\n#~ \" the page at all. This is done\"\n#~ \" to tell apart image-based text \"\n#~ \"from ordinary pictures (like photographies).\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"For these heuristics to work we \"\n#~ \"need both, an existing Tesseract \"\n#~ \"installation and the availability of \"\n#~ \"OpenCV in the Python environment. If \"\n#~ \"either is missing, no OCR is \"\n#~ \"attempted at all.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/pymupdf-pro/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ff337a9fa03e4fd6a3d7aaec4930912f\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 b9e1a76b005b46c7a35e27ac36b668dd\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 5b66ad60d8974f3fb8061286f4b23214\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../pymupdf-pro/index.rst:8 07624f1e03dd463c99bf82f95b91a35e\nmsgid \"PyMuPDF Pro\"\nmsgstr \"PyMuPDF Pro\"\n\n#: ../../pymupdf-pro/index.rst:11 879666c817c94726a9df9e5880d5425a\nmsgid \"|PyMuPDF Pro| is a set of *commercial extensions* for |PyMuPDF|.\"\nmsgstr \"|PyMuPDF Pro| 는 |PyMuPDF| 를 위한 *상용 확장* 세트입니다.\"\n\n#: ../../pymupdf-pro/index.rst:13 ae90e3fd121f4e04a0a9ecd747514717\nmsgid \"\"\n\"Enhance |PyMuPDF| capability with **Office** document support & \"\n\"**RAG/LLM** integrations.\"\nmsgstr \"**Office** 문서 지원 및 **RAG/LLM** 통합으로 |PyMuPDF| 기능을 향상시킵니다.\"\n\n#: ../../pymupdf-pro/index.rst:15 aed2c2f793d348d8bf6eb0811eecb47a\nmsgid \"\"\n\"Enables Office document handling, including ``doc``, ``docx``, ``hwp``, \"\n\"``hwpx``, ``ppt``, ``pptx``, ``xls``, ``xlsx``, and others.\"\nmsgstr \"``doc``, ``docx``, ``hwp``, ``hwpx``, ``ppt``, ``pptx``, ``xls``, ``xlsx`` 등을 포함한 Office 문서 처리를 활성화합니다.\"\n\n#: ../../pymupdf-pro/index.rst:16 997a064abea1408d914a30cae0872289\nmsgid \"Supports text and table extraction, document conversion and more.\"\nmsgstr \"텍스트 및 테이블 추출, 문서 변환 등을 지원합니다.\"\n\n#: ../../pymupdf-pro/index.rst:17 7ee872ab1d5c4992b77ebbf8c3cf149c\nmsgid \"Includes the commercial version of |PyMuPDF4LLM|.\"\nmsgstr \"|PyMuPDF4LLM| 의 상용 버전을 포함합니다.\"\n\n#: ../../pymupdf-pro/index.rst:19 83cc2a9a8a854516b90d26d2841aad02\nmsgid \"\"\n\"To enquire about obtaining a commercial license, then `use this contact \"\n\"page <https://artifex.com/contact/>`_.\"\nmsgstr \"상용 라이선스 취득에 대한 문의는 `이 연락처 페이지 <https://artifex.com/contact/>`_ 를 사용하세요.\"\n\n#: ../../pymupdf-pro/index.rst:24 f0a9c51213864c898871ca01453557e1\nmsgid \"\"\n\"A licensed version of |PyMuPDF Pro| also gives you a licensed version of \"\n\"|PyMuPDF4LLM|. If you are interested in using the |PyMuPDF4LLM| package \"\n\"you should install it separately.\"\nmsgstr \"|PyMuPDF Pro| 의 라이선스 버전은 |PyMuPDF4LLM| 의 라이선스 버전도 제공합니다. |PyMuPDF4LLM| 패키지를 사용하려면 별도로 설치해야 합니다.\"\n\n#: ../../pymupdf-pro/index.rst:28 4a1d503fea744f4ba62d54e186f02d87\nmsgid \"Platform support\"\nmsgstr \"플랫폼 지원\"\n\n#: ../../pymupdf-pro/index.rst:30 78076f4c0458474f913d726a0fb0e0bc\nmsgid \"Available for these platforms only:\"\nmsgstr \"다음 플랫폼에서만 사용 가능:\"\n\n#: ../../pymupdf-pro/index.rst:32 ed38f46c156840689524033bf7da829d\nmsgid \"Windows x86_64.\"\nmsgstr \"Windows x86_64.\"\n\n#: ../../pymupdf-pro/index.rst:33 259897daea654cb8a90bc8e65c6e4f76\nmsgid \"Linux x86_64 (glibc).\"\nmsgstr \"Linux x86_64 (glibc).\"\n\n#: ../../pymupdf-pro/index.rst:34 1923df7caa0b4f04a3b259b4c866ba6e\nmsgid \"MacOS x86_64.\"\nmsgstr \"MacOS x86_64.\"\n\n#: ../../pymupdf-pro/index.rst:35 fd5d8bf6fc12467a826ce8202a1d2ec3\nmsgid \"MacOS arm64.\"\nmsgstr \"MacOS arm64.\"\n\n#: ../../pymupdf-pro/index.rst:39 f2952d3e2f47435bb640b83bd15721c4\nmsgid \"Office file support\"\nmsgstr \"Office 파일 지원\"\n\n#: ../../pymupdf-pro/index.rst:41 7c38d85a3c164f3a90d869b52ef96eb1\nmsgid \"\"\n\"In addition to the `standard file types supported by PyMuPDF \"\n\"<Supported_File_Types>`, |PyMuPDF Pro| supports:\"\nmsgstr \"`PyMuPDF 가 지원하는 표준 파일 타입 <Supported_File_Types>` 외에도 |PyMuPDF Pro| 는 다음을 지원합니다:\"\n\n#: ../../pymupdf-pro/index.rst:46 67438064f36f474186aeb4fbfb093d31\nmsgid \"**DOC/DOCX**\"\nmsgstr \"**DOC/DOCX**\"\n\n#: ../../pymupdf-pro/index.rst:47 9ab995c3f8214b9ab04698d96a84b4e2\nmsgid \"**XLS/XLSX**\"\nmsgstr \"**XLS/XLSX**\"\n\n#: ../../pymupdf-pro/index.rst:48 9e2c997d6ac44df79efb09f56a593cbb\nmsgid \"**PPT/PPTX**\"\nmsgstr \"**PPT/PPTX**\"\n\n#: ../../pymupdf-pro/index.rst:49 28e3c375094f40258eea347ffcaf5a8f\nmsgid \"**HWP/HWPX**\"\nmsgstr \"**HWP/HWPX**\"\n\n#: ../../pymupdf-pro/index.rst:66 9ccca49db9fb4df98d9464183c30d68c\nmsgid \"Usage\"\nmsgstr \"사용법\"\n\n#: ../../pymupdf-pro/index.rst:69 edd61111e81a46198c9ef49a53e782b0\nmsgid \"Installation\"\nmsgstr \"설치\"\n\n#: ../../pymupdf-pro/index.rst:71 f961577e8ffd49469227db2bbdcd9bb2\nmsgid \"Install via pip with:\"\nmsgstr \"pip 를 통해 설치합니다:\"\n\n#: ../../pymupdf-pro/index.rst:79 699e6bf8334b4cf8b23793ff0e45ccbf\nmsgid \"Loading an **Office** document\"\nmsgstr \"**Office** 문서 로드\"\n\n#: ../../pymupdf-pro/index.rst:81 08e39b8bfc514665aafb5c1aa211bcfc\nmsgid \"\"\n\"Import |PyMuPDF Pro| and you can then reference **Office** documents \"\n\"directly, e.g.:\"\nmsgstr \"|PyMuPDF Pro| 를 가져오면 **Office** 문서를 직접 참조할 수 있습니다. 예:\"\n\n#: ../../pymupdf-pro/index.rst:92 e21e201731344245a88c7e6bdd9c2dc2\nmsgid \"\"\n\"All standard |PyMuPDF| functionality is exposed as expected - |PyMuPDF \"\n\"Pro| handles the extended **Office** file types\"\nmsgstr \"모든 표준 |PyMuPDF| 기능이 예상대로 노출됩니다 - |PyMuPDF Pro| 는 확장된 **Office** 파일 타입을 처리합니다\"\n\n#: ../../pymupdf-pro/index.rst:95 32d84f02e19a40b5bb42c1d26a81afe5\nmsgid \"\"\n\"From then on you can work with document pages just as you would do \"\n\"normally, but with respect to the `restrictions \"\n\"<PyMuPDFPro_Restrictions>`.\"\nmsgstr \"그때부터 `제한 사항 <PyMuPDFPro_Restrictions>` 을 고려하여 일반적으로 수행하는 것처럼 문서 페이지로 작업할 수 있습니다.\"\n\n#: ../../pymupdf-pro/index.rst:99 36c298b59008468ab926c22842511b25\nmsgid \"Converting an **Office** document to |PDF|\"\nmsgstr \"**Office** 문서를 |PDF| 로 변환\"\n\n#: ../../pymupdf-pro/index.rst:101 c01333a0e65f42d29d469ace26b3fd91\nmsgid \"\"\n\"The following code snippet can convert your **Office** document to |PDF| \"\n\"format:\"\nmsgstr \"다음 코드 조각은 **Office** 문서를 |PDF| 형식으로 변환할 수 있습니다:\"\n\n#: ../../pymupdf-pro/index.rst:119 cd5eb6eaf8094ced89572a48282454ca\nmsgid \"Restrictions\"\nmsgstr \"제한 사항\"\n\n#: ../../pymupdf-pro/index.rst:122 badbfba0a2a0495290e9594585aaefc9\nmsgid \"\"\n\"|PyMuPDF Pro| functionality is restricted without a license key as \"\n\"follows:\"\nmsgstr \"라이선스 키 없이 |PyMuPDF Pro| 기능은 다음과 같이 제한됩니다:\"\n\n#: ../../pymupdf-pro/index.rst:124 0edbc072da504add956116e21d3eebde\nmsgid \"**Only the first 3 pages of any document will be available.**\"\nmsgstr \"**모든 문서의 처음 3페이지만 사용할 수 있습니다.**\"\n\n#: ../../pymupdf-pro/index.rst:126 6fa9f0d4dec94b3db782dacdc632f5a0\nmsgid \"\"\n\"To unlock full functionality you should `obtain a trial key \"\n\"<https://pymupdf.pro/try-pro/>`_.\"\nmsgstr \"전체 기능을 잠금 해제하려면 `시험 키를 받으세요 <https://pymupdf.pro/try-pro/>`_.\"\n\n#: ../../pymupdf-pro/index.rst:132 ff0d00debbdb4746809d8750352f10bc\nmsgid \"Trial keys\"\nmsgstr \"시험 키\"\n\n#: ../../pymupdf-pro/index.rst:134 e689628360fa4b4497ccbb720dd0faca\nmsgid \"\"\n\"To obtain a license key `please fill out the form on this page \"\n\"<https://pymupdf.pro/try-pro/>`_. You will then have the trial key \"\n\"emailled to the address you submitted.\"\nmsgstr \"라이선스 키를 받으려면 `이 페이지의 양식을 작성하세요 <https://pymupdf.pro/try-pro/>`_. 그러면 제출한 주소로 시험 키가 이메일로 전송됩니다.\"\n\n#: ../../pymupdf-pro/index.rst:138 b4af428798424c3baae4771829727b28\nmsgid \"Using a key\"\nmsgstr \"키 사용\"\n\n#: ../../pymupdf-pro/index.rst:141 6766aa2a1d144b81a15c3ad28ce403da\nmsgid \"Initialize |PyMuPDF Pro| with a key as follows:\"\nmsgstr \"다음과 같이 키로 |PyMuPDF Pro| 를 초기화합니다:\"\n\n#: ../../pymupdf-pro/index.rst:149 92e495f1e7934e1e83d346f56ab9833d\nmsgid \"\"\n\"This will allow you to evaluate the product for a limited time. If you \"\n\"want to use |PyMuPDF Pro| after this time you should then `enquire about \"\n\"obtaining a commercial license <https://artifex.com/products/pymupdf-\"\n\"pro/>`_.\"\nmsgstr \"이것은 제한된 시간 동안 제품을 평가할 수 있게 해줍니다. 이 시간 이후에 |PyMuPDF Pro| 를 사용하려면 `상용 라이선스 취득에 대해 문의하세요 <https://artifex.com/products/pymupdf-pro/>`_.\"\n\n#: ../../pymupdf-pro/index.rst:153 a394162132a04de092aabb5d2fcbc814\nmsgid \"Fonts\"\nmsgstr \"글꼴\"\n\n#: ../../pymupdf-pro/index.rst:155 8e2db8a260ac4b8597a804b55d7ab547\nmsgid \"\"\n\"By default `pymupdf.pro.unlock()` searches for all installed font \"\n\"directories.\"\nmsgstr \"기본적으로 `pymupdf.pro.unlock()` 은 설치된 모든 글꼴 디렉토리를 검색합니다.\"\n\n#: ../../pymupdf-pro/index.rst:157 e0cd7217fd79445ea7e79586abad31d1\nmsgid \"This can be controlled with keyword-only args:\"\nmsgstr \"키워드 전용 인수로 제어할 수 있습니다:\"\n\n#: ../../pymupdf-pro/index.rst:159 879866813ec14fd08f5b249e833e7ee7\nmsgid \"\"\n\"`fontpath`: specific font directories, either as a list/tuple or \"\n\"`os.sep`-separated string. If None (the default), we use \"\n\"`os.environ['PYMUPDFPRO_FONT_PATH']` if set.\"\nmsgstr \"`fontpath`: 특정 글꼴 디렉토리, list/tuple 또는 `os.sep` 로 구분된 문자열. None(기본값)인 경우 설정되어 있으면 `os.environ['PYMUPDFPRO_FONT_PATH']` 를 사용합니다.\"\n\n#: ../../pymupdf-pro/index.rst:161 5ca9e3934e6c4c91b603c12662c79cf6\nmsgid \"\"\n\"`fontpath_auto`: Whether to append system font directories. If None (the \"\n\"default) we use true if `os.environ['PYMUPDFPRO_FONT_PATH_AUTO']` is '1'.\"\n\" If true we append all system font directories.\"\nmsgstr \"`fontpath_auto`: 시스템 글꼴 디렉토리를 추가할지 여부. None(기본값)인 경우 `os.environ['PYMUPDFPRO_FONT_PATH_AUTO']` 가 '1'이면 true를 사용합니다. true이면 모든 시스템 글꼴 디렉토리를 추가합니다.\"\n\n#: ../../pymupdf-pro/index.rst:165 5ecf267b5f8f4e68be5f69f1cbee4782\nmsgid \"\"\n\"Function `pymupdf.pro.get_fontpath()` returns a tuple of all font \"\n\"directories used by `unlock()`.\"\nmsgstr \"함수 `pymupdf.pro.get_fontpath()` 는 `unlock()` 에서 사용하는 모든 글꼴 디렉토리의 튜플을 반환합니다.\"\n\n#: ../../footer.rst:46 b26519c017c744e3b52c222b2633f6ed\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/pymupdf4llm/api.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2024, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2024.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.24.10\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 16:19+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ja\\n\"\n\"Language-Team: ja <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 28d86985971f44c9b5c589f8ab54e80c\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 e7a5b73934cd435dbb28ac3030a6bc42\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"\"\n\"|PyMuPDF| 는 PDF(및 기타) 문서의 데이터 추출, 분석, 변환 및 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 92d346afb67b4f3ab88c5a1064a46694\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../pymupdf4llm/api.rst:27 4e5664b1124d48d18fd12e59b727a0bd\nmsgid \"API\"\nmsgstr \"API\"\n\n#: ../../pymupdf4llm/api.rst:30 e4fe663d1ee04cf7bbc808eeb9ce308b\nmsgid \"The |PyMuPDF4LLM| API\"\nmsgstr \"|PyMuPDF4LLM| API\"\n\n#: ../../pymupdf4llm/api.rst:35 4e2df9f8107d4db1a2347a4be75c0272\nmsgid \"Prints the version of the library.\"\nmsgstr \"라이브러리의 버전을 출력합니다.\"\n\n#: ../../pymupdf4llm/api.rst:69 c21d1e47747e4a6eadd73614ff6f800a\nmsgid \"\"\n\"Reads the pages of the file and outputs the text of its pages in \"\n\"|Markdown| format. How this should happen in detail can be influenced by \"\n\"a number of parameters. Please note that **support for building page \"\n\"chunks** from the |Markdown| text is supported.\"\nmsgstr \"\"\n\"파일의 페이지를 읽고 |Markdown| 형식으로 페이지 텍스트를 출력합니다. 세부 사항은 여러 매개변수로 제어할 수 있습니다. |Markdown| 텍스트에서 **페이지 청크 구축 지원** 이 지원됩니다.\"\n\n#: ../../pymupdf4llm/api.rst 13d669ad26754dc0b5dd18b71aaaa6e7\n#: 9f1452580faf4a6282a5888330a95503 9f18803cca3b49628d55a64c7a8473ee\n#: b1bbc30b869d4427932592ee651344a4 c3792e58bf894b75870f21f594a83813\n#: c57820b438a34e958720773d86d8a687\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../pymupdf4llm/api.rst:71 ../../pymupdf4llm/api.rst:163\n#: ../../pymupdf4llm/api.rst:184 1df54be04e4d4aaeac61cce4ba98817f\n#: 4632c24ae65b499e81a55a61b741ffba 835d293ddb884273a0d2f38bfd18e563\nmsgid \"\"\n\"the file, to be specified either as a file path string, or as a |PyMuPDF|\"\n\" :class:`Document` (created via `pymupdf.open`). In order to use \"\n\"`pathlib.Path` specifications, Python file-like objects, documents in \"\n\"memory etc. you **must** use a |PyMuPDF| :class:`Document`.\"\nmsgstr \"\"\n\"파일 경로 문자열 또는 |PyMuPDF| :class:`Document` (`pymupdf.open` 으로 생성)로 지정할 파일입니다. `pathlib.Path` 사양, Python 파일과 같은 객체, 메모리의 문서 등을 사용하려면 **반드시** |PyMuPDF| :class:`Document` 를 사용해야 합니다.\"\n\n#: ../../pymupdf4llm/api.rst:73 5b01dd3e313a4f1183943c524048c4a3\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| does a simple check for the general \"\n\"background color of the pages (default is ``True``). If any text or \"\n\"vector has this color it will be ignored. May increase detection \"\n\"accuracy.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| 페이지의 일반 배경색에 대한 간단한 확인을 수행합니다(기본값은 ``True``). 이 색상을 가진 텍스트나 벡터는 무시됩니다. 감지 정확도를 높일 수 있습니다.\"\n\n#: ../../pymupdf4llm/api.rst:75 f4d01e56b3794441a8802c4a80be94aa\nmsgid \"\"\n\"specify the desired image resolution in dots per inch. Relevant only if \"\n\"`write_images=True` or `embed_images=True`. Default value is 150.\"\nmsgstr \"\"\n\"인치당 도트 수로 원하는 이미지 해상도를 지정합니다. `write_images=True` 또는 `embed_images=True` 인 경우에만 관련됩니다. 기본값은 150입니다.\"\n\n#: ../../pymupdf4llm/api.rst:77 41ff8c59beb54152b76219649e55269d\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Valid| use :ref:`OCR capability \"\n\"<pymupdf_layout_ocr_support>` to help analyse the page.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Valid| 페이지 분석을 돕기 위해 :ref:`OCR 기능 <pymupdf_layout_ocr_support>` 을 사용합니다.\"\n\n#: ../../pymupdf4llm/api.rst:79 d3e8adb5845748eeacc23caba37adfb9\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Valid| specify the desired image resolution in dots \"\n\"per inch for applying OCR to the intermediate image of the page. Default \"\n\"value is 400. Only relevant if the page has been determined to profit \"\n\"from OCR (no or few text, most of the page covered by images or \"\n\"character-like vectors, etc.). Large values may increase the OCR \"\n\"precision but increase memory requirements and processing time. There \"\n\"also is a risk of over-sharpening the image which may decrease OCR \"\n\"precision. So the default value should probably be sufficiently high.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Valid| 페이지의 중간 이미지에 OCR을 적용하기 위한 인치당 도트 수로 원하는 이미지 해상도를 지정합니다. 기본값은 400입니다. 페이지가 OCR로 이익을 얻을 것으로 판단된 경우(텍스트가 없거나 적고, 페이지 대부분이 이미지나 문자와 같은 벡터로 덮인 경우 등)에만 관련됩니다. 큰 값은 OCR 정밀도를 높일 수 있지만 메모리 요구 사항과 처리 시간을 증가시킵니다. 이미지를 과도하게 선명하게 만들어 OCR 정밀도를 떨어뜨릴 위험도 있습니다. 따라서 기본값은 충분히 높아야 합니다.\"\n\n#: ../../pymupdf4llm/api.rst:81 9d41bfc8dacf4906862ed59207d58a4f\nmsgid \"\"\n\"like `write_images`, but images will be included in the markdown text as \"\n\"base64-encoded strings. Mutually exclusive with `write_images` and \"\n\"ignores `image_path`. This may drastically increase the size of your \"\n\"markdown text.\"\nmsgstr \"\"\n\"`write_images` 와 유사하지만 이미지가 base64 인코딩된 문자열로 마크다운 텍스트에 포함됩니다. `write_images` 와 상호 배타적이며 `image_path` 를 무시합니다. 마크다운 텍스트의 크기를 크게 증가시킬 수 있습니다.\"\n\n#: ../../pymupdf4llm/api.rst:83 cbd2e3785be64256b6c64d96627ce87c\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| a value of `True` enforces `page_chunks=True`\"\n\" and adds key \\\"words\\\" to each page dictionary. Its value is a list of \"\n\"words as delivered by PyMuPDF's `Page` method `get_text(\\\"words\\\")`. The \"\n\"sequence of the words in this list is the same as the extracted text.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| `True` 값은 `page_chunks=True` 를 강제하고 각 페이지 딕셔너리에 \\\"words\\\" 키를 추가합니다. 그 값은 |PyMuPDF| 의 `Page` 메서드 `get_text(\\\"words\\\")` 에서 제공하는 단어 목록입니다. 이 목록의 단어 순서는 추출된 텍스트와 동일합니다.\"\n\n#: ../../pymupdf4llm/api.rst:85 a9fcde34b67b4aac85960a2058a8384d\nmsgid \"\"\n\"Overwrites or sets the desired image file name of written images. Useful \"\n\"when the document is provided as a memory object (which has no inherent \"\n\"file name).\"\nmsgstr \"\"\n\"작성된 이미지의 원하는 이미지 파일 이름을 덮어쓰거나 설정합니다. 문서가 메모리 객체로 제공되는 경우(고유한 파일 이름이 없음)에 유용합니다.\"\n\n#: ../../pymupdf4llm/api.rst:87 445155dce88c4e488ea537ff3be59de6\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| limit the font size to consider for text \"\n\"extraction. If the font size is lower than what is set then the text \"\n\"won't be considered for extraction. Default is `3`, meaning only text \"\n\"with a font size `>= 3` will be considered for extraction.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| 텍스트 추출을 위해 고려할 폰트 크기를 제한합니다. 폰트 크기가 설정된 값보다 작으면 텍스트가 추출 대상에서 제외됩니다. 기본값은 `3` 이며, 폰트 크기가 `>= 3` 인 텍스트만 추출 대상으로 고려됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:89 a09091d58eb74cb4953110f6516b8f92\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Valid| boolean to switch on/off page footer content. \"\n\"This parameter controls whether to include or omit footer text from all \"\n\"the document pages. Useful if the document has repetitive footer content \"\n\"which doesn't add any value to the overall extraction data. Default is \"\n\"`True` meaning that footer content will be considered.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Valid| 페이지 푸터 콘텐츠를 켜거나 끄는 부울 값입니다. 이 매개변수는 모든 문서 페이지에서 푸터 텍스트를 포함할지 생략할지를 제어합니다. 문서에 반복적인 푸터 콘텐츠가 있어 전체 추출 데이터에 가치를 추가하지 않는 경우에 유용합니다. 기본값은 `True` 이며 푸터 콘텐츠가 고려됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:91 18670d8b86384ed99d85b86b0328a4ca\nmsgid \"\"\n\"generate text output even when overlapping images / graphics. This text \"\n\"then appears after the respective image.\"\nmsgstr \"\"\n\"이미지/그래픽과 겹치는 경우에도 텍스트 출력을 생성합니다. 이 텍스트는 해당 이미지 뒤에 나타납니다.\"\n\n#: ../../pymupdf4llm/api.rst:93 30d505740e2243e4a965d5bed923e367\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| use this to limit dealing with excess amounts\"\n\" of vector graphics elements. Scientific documents, or pages simulating \"\n\"text via graphics commands may contain tens of thousands of these \"\n\"objects. As vector graphics are analyzed for multiple purposes, runtime \"\n\"may quickly become intolerable. With this parameter, all vector graphics \"\n\"will be ignored if their count exceeds the threshold.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| 과도한 양의 벡터 그래픽 요소를 처리하는 것을 제한하는 데 사용합니다. 과학 문서나 그래픽 명령을 통해 텍스트를 시뮬레이션하는 페이지는 수만 개의 이러한 객체를 포함할 수 있습니다. 벡터 그래픽이 여러 목적으로 분석되므로 실행 시간이 빠르게 견딜 수 없게 될 수 있습니다. 이 매개변수를 사용하면 개수가 임계값을 초과하면 모든 벡터 그래픽이 무시됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:95 f45e892b070e41909fee2c6af82edbe5\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| use this if you want to provide your own \"\n\"header detection logic. This may be a callable or an object having a \"\n\"method named `get_header_id`. It must accept a text span (a span \"\n\"dictionary as contained in :meth:`~.extractDICT`) and a keyword parameter\"\n\" \\\"page\\\" (which is the owning :ref:`Page <page>` object). It must return\"\n\" a string \\\"\\\" or up to 6 \\\"#\\\" characters followed by 1 space. If \"\n\"omitted (`None`), a full document scan will be performed to find the most\"\n\" popular font sizes and derive header levels based on them. To completely\"\n\" avoid this behavior specify `hdr_info=lambda s, page=None: \\\"\\\"` or \"\n\"`hdr_info=False`.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| 자체 헤더 감지 로직을 제공하려면 이것을 사용하세요. 이것은 호출 가능한 객체이거나 `get_header_id` 라는 메서드를 가진 객체일 수 있습니다. 텍스트 스팬(:meth:`~.extractDICT` 에 포함된 스팬 딕셔너리)과 키워드 매개변수 \\\"page\\\"(소유 :ref:`Page <page>` 객체)를 받아야 합니다. 빈 문자열 \\\"\\\" 또는 최대 6개의 \\\"#\\\" 문자 뒤에 공백 1개를 반환해야 합니다. 생략(`None`)하면 전체 문서 스캔을 수행하여 가장 인기 있는 폰트 크기를 찾고 이를 기반으로 헤더 수준을 파생합니다. 이 동작을 완전히 피하려면 `hdr_info=lambda s, page=None: \\\"\\\"` 또는 `hdr_info=False` 를 지정하세요.\"\n\n#: ../../pymupdf4llm/api.rst:97 a35f46ec3a53486fa48b3655d9e9c97d\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Valid| boolean to switch on/off page header content. \"\n\"This parameter controls whether we want to include or omit the header \"\n\"content from all the document pages. Useful if the document has \"\n\"repetitive header content which doesn't add any value to the overall \"\n\"extraction data. Default is `True` meaning that header content will be \"\n\"considered.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Valid| 페이지 헤더 콘텐츠를 켜거나 끄는 부울 값입니다. 이 매개변수는 모든 문서 페이지에서 헤더 콘텐츠를 포함할지 생략할지를 제어합니다. 문서에 반복적인 헤더 콘텐츠가 있어 전체 추출 데이터에 가치를 추가하지 않는 경우에 유용합니다. 기본값은 `True` 이며 헤더 콘텐츠가 고려됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:99 28b04a679d88497e96269ee7f0812e9e\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| if ``True`` includes text even when \"\n\"completely transparent. Default is ``False``: transparent text will be \"\n\"ignored which usually increases detection accuracy.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| ``True`` 이면 완전히 투명한 경우에도 텍스트를 포함합니다. 기본값은 ``False`` 입니다: 투명한 텍스트는 무시되며 일반적으로 감지 정확도를 높입니다.\"\n\n#: ../../pymupdf4llm/api.rst:101 36820cc6604844b2a4d5375a7cd5792f\nmsgid \"\"\n\"if `True` then mono-spaced text lines do not receive special formatting. \"\n\"Code blocks will no longer be generated. This value is set to `True` if \"\n\"`extract_words=True` is used.\"\nmsgstr \"\"\n\"`True` 이면 고정 폭 텍스트 줄이 특별한 형식을 받지 않습니다. 코드 블록이 더 이상 생성되지 않습니다. `extract_words=True` 가 사용되면 이 값은 `True` 로 설정됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:103 bff188eabaf94192af91641c85c1e98d\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| (New in v.0.0.20) Disregard vector graphics \"\n\"on the page. This may help detecting text correctly when pages are very \"\n\"crowded (often the case for documents representing presentation slides). \"\n\"Also speeds up processing time. This automatically prevents table \"\n\"detection.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| (v.0.0.20에서 새로 추가됨) 페이지의 벡터 그래픽을 무시합니다. 페이지가 매우 복잡할 때(프레젠테이션 슬라이드를 나타내는 문서에서 자주 발생) 텍스트를 올바르게 감지하는 데 도움이 될 수 있습니다. 또한 처리 시간을 단축합니다. 이것은 자동으로 테이블 감지를 방지합니다.\"\n\n#: ../../pymupdf4llm/api.rst:105 056587fcf3d04ac29d30bcd3886d95f2\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| (New in v.0.0.20) Disregard images on the \"\n\"page. This may help detecting text correctly when pages are very crowded \"\n\"(often the case for documents representing presentation slides). Also \"\n\"speeds up processing time.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| (v.0.0.20에서 새로 추가됨) 페이지의 이미지를 무시합니다. 페이지가 매우 복잡할 때(프레젠테이션 슬라이드를 나타내는 문서에서 자주 발생) 텍스트를 올바르게 감지하는 데 도움이 될 수 있습니다. 또한 처리 시간을 단축합니다.\"\n\n#: ../../pymupdf4llm/api.rst:107 ecf6dcf203a643bd8e51300ae9ad0a06\nmsgid \"\"\n\"specify the desired image format via its extension. Default is \\\"png\\\" \"\n\"(portable network graphics). Another popular format may be \\\"jpg\\\". \"\n\"Possible values are all :ref:`supported output formats \"\n\"<Supported_File_Types>`.\"\nmsgstr \"\"\n\"확장자를 통해 원하는 이미지 형식을 지정합니다. 기본값은 \\\"png\\\"(portable network graphics)입니다. 다른 인기 있는 형식은 \\\"jpg\\\"일 수 있습니다. 가능한 값은 모든 :ref:`지원되는 출력 형식 <Supported_File_Types>` 입니다.\"\n\n#: ../../pymupdf4llm/api.rst:109 adbd88cd1ca14c1ba5ee08b2109bce36\nmsgid \"\"\n\"store images in this folder. Relevant if `write_images=True`. Default is \"\n\"the path of the script directory.\"\nmsgstr \"\"\n\"이 폴더에 이미지를 저장합니다. `write_images=True` 인 경우 관련됩니다. 기본값은 스크립트 디렉토리의 경로입니다.\"\n\n#: ../../pymupdf4llm/api.rst:111 afeb57cfa94f4015b4e1e6c1c2e6e125\n#, python-format\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| this must be a ``0 <= value < 1``. Images are\"\n\" ignored if `width / page.rect.width <= image_size_limit` or `height / \"\n\"page.rect.height <= image_size_limit`. For instance, the default value \"\n\"0.05 means that to be considered for inclusion, an image's width and \"\n\"height must be larger than 5% of the page's width and height, \"\n\"respectively.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| 이것은 ``0 <= value < 1`` 이어야 합니다. `width / page.rect.width <= image_size_limit` 또는 `height / page.rect.height <= image_size_limit` 이면 이미지가 무시됩니다. 예를 들어, 기본값 0.05는 포함을 고려하려면 이미지의 너비와 높이가 각각 페이지 너비와 높이의 5%보다 커야 함을 의미합니다.\"\n\n#: ../../pymupdf4llm/api.rst:113 85475d5ce25043fe947f058364b6d756\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| a float or a sequence of 2 or 4 floats \"\n\"specifying page borders. Only objects inside the margins will be \"\n\"considered for output.  * `margin=f` yields `(f, f, f, f)` for `(left, \"\n\"top, right, bottom)`. * `(top, bottom)` yields  `(0, top, 0, bottom)`. * \"\n\"To always read full pages **(default)**, use `margins=0`.\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/api.rst:113 3fb6f34f01ff47e3a66ae8c810ee06e0\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| a float or a sequence of 2 or 4 floats \"\n\"specifying page borders. Only objects inside the margins will be \"\n\"considered for output.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| 페이지 여백을 지정하는 float 또는 2개 또는 4개의 float 시퀀스. 여백 내부의 객체만 출력 대상으로 고려됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:115 801899e2be22416aa50f59d49696821f\nmsgid \"`margin=f` yields `(f, f, f, f)` for `(left, top, right, bottom)`.\"\nmsgstr \"`margin=f` 는 `(left, top, right, bottom)` 에 대해 `(f, f, f, f)` 를 생성합니다.\"\n\n#: ../../pymupdf4llm/api.rst:116 387562b55d82431291823c1801fd50a4\nmsgid \"`(top, bottom)` yields  `(0, top, 0, bottom)`.\"\nmsgstr \"`(top, bottom)` 는 `(0, top, 0, bottom)` 를 생성합니다.\"\n\n#: ../../pymupdf4llm/api.rst:117 cdd8cebf2e1948a0a421609fc71375f2\nmsgid \"To always read full pages **(default)**, use `margins=0`.\"\nmsgstr \"항상 전체 페이지를 읽으려면 **(기본값)**, `margins=0` 을 사용하세요.\"\n\n#: ../../pymupdf4llm/api.rst:119 34c0664f16c740c7aca19e3a24e79e08\nmsgid \"\"\n\"if `True` the output will be a list of `Document.page_count` dictionaries\"\n\" (one per page). Each dictionary has the following structure:  - \"\n\"**\\\"metadata\\\"** - a dictionary consisting of the document's metadata \"\n\":attr:`Document.metadata`, enriched with additional keys \"\n\"**\\\"file_path\\\"** (the file name), **\\\"page_count\\\"** (number of pages in\"\n\" document), and **\\\"page_number\\\"** (1-based page number).  - \"\n\"**\\\"toc_items\\\"** - a list of Table of Contents items pointing to this \"\n\"page. Each item of this list has the format `[lvl, title, pagenumber]`, \"\n\"where `lvl` is the hierarchy level, `title` a string and `pagenumber` as \"\n\"a 1-based page number.  - **\\\"tables\\\"** - a list of tables on this page.\"\n\" Each item is a dictionary with keys \\\"bbox\\\", \\\"row_count\\\" and \"\n\"\\\"col_count\\\". Key \\\"bbox\\\" is a `pymupdf.Rect` in tuple format of the \"\n\"table's position on the page.  - **\\\"images\\\"** - \"\n\"|PyMuPDFLayoutMode_EmptyList| a list of images on the page. This a copy \"\n\"of page method :meth:`Page.get_image_info`.  - **\\\"graphics\\\"** - \"\n\"|PyMuPDFLayoutMode_EmptyList| a list of vector graphics rectangles on the\"\n\" page. This is a list of boundary boxes of clustered vector graphics as \"\n\"delivered by method :meth:`Page.cluster_drawings`.  - **\\\"text\\\"** - page\"\n\" content as |Markdown| text.  - **\\\"words\\\"** - \"\n\"|PyMuPDFLayoutMode_EmptyList| if `extract_words=True` was used. This is a\"\n\" list of tuples `(x0, y0, x1, y1, \\\"wordstring\\\", bno, lno, wno)` as \"\n\"delivered by `page.get_text(\\\"words\\\")`. The **sequence** of these tuples\"\n\" however is the same as produced in the markdown text string and thus \"\n\"honors multi-column text. This is also true for text in tables: words are\"\n\" extracted in the sequence of table row cells.\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/api.rst:119 26276a827ba549e7ae6680403a0325be\nmsgid \"\"\n\"if `True` the output will be a list of `Document.page_count` dictionaries\"\n\" (one per page). Each dictionary has the following structure:\"\nmsgstr \"\"\n\"`True` 이면 출력은 `Document.page_count` 딕셔너리 목록(페이지당 하나)이 됩니다. 각 딕셔너리는 다음 구조를 가집니다:\"\n\n#: ../../pymupdf4llm/api.rst:121 412ffcdcfd664b5a9cdca7475bb6c793\nmsgid \"\"\n\"**\\\"metadata\\\"** - a dictionary consisting of the document's metadata \"\n\":attr:`Document.metadata`, enriched with additional keys \"\n\"**\\\"file_path\\\"** (the file name), **\\\"page_count\\\"** (number of pages in\"\n\" document), and **\\\"page_number\\\"** (1-based page number).\"\nmsgstr \"\"\n\"**\\\"metadata\\\"** - 문서의 메타데이터 :attr:`Document.metadata` 로 구성된 딕셔너리이며, 추가 키 **\\\"file_path\\\"** (파일 이름), **\\\"page_count\\\"** (문서의 페이지 수), **\\\"page_number\\\"** (1-기반 페이지 번호)로 보강됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:123 e102e7dfa70942fabc2932205ec555ed\nmsgid \"\"\n\"**\\\"toc_items\\\"** - a list of Table of Contents items pointing to this \"\n\"page. Each item of this list has the format `[lvl, title, pagenumber]`, \"\n\"where `lvl` is the hierarchy level, `title` a string and `pagenumber` as \"\n\"a 1-based page number.\"\nmsgstr \"\"\n\"**\\\"toc_items\\\"** - 이 페이지를 가리키는 목차 항목 목록. 이 목록의 각 항목은 `[lvl, title, pagenumber]` 형식을 가지며, 여기서 `lvl` 은 계층 수준, `title` 은 문자열, `pagenumber` 는 1-기반 페이지 번호입니다.\"\n\n#: ../../pymupdf4llm/api.rst:125 697bc1bf53f943a6a77a7e73b4ed9069\nmsgid \"\"\n\"**\\\"tables\\\"** - a list of tables on this page. Each item is a dictionary\"\n\" with keys \\\"bbox\\\", \\\"row_count\\\" and \\\"col_count\\\". Key \\\"bbox\\\" is a \"\n\"`pymupdf.Rect` in tuple format of the table's position on the page.\"\nmsgstr \"\"\n\"**\\\"tables\\\"** - 이 페이지의 테이블 목록. 각 항목은 \\\"bbox\\\", \\\"row_count\\\", \\\"col_count\\\" 키를 가진 딕셔너리입니다. \\\"bbox\\\" 키는 페이지에서 테이블 위치의 튜플 형식인 `pymupdf.Rect` 입니다.\"\n\n#: ../../pymupdf4llm/api.rst:127 f4902a3e2743455b879b8e485c311e6e\nmsgid \"\"\n\"**\\\"images\\\"** - |PyMuPDFLayoutMode_EmptyList| a list of images on the \"\n\"page. This a copy of page method :meth:`Page.get_image_info`.\"\nmsgstr \"\"\n\"**\\\"images\\\"** - |PyMuPDFLayoutMode_EmptyList| 페이지의 이미지 목록. 이것은 페이지 메서드 :meth:`Page.get_image_info` 의 복사본입니다.\"\n\n#: ../../pymupdf4llm/api.rst:129 247ba43947304db2939158ac691bb939\nmsgid \"\"\n\"**\\\"graphics\\\"** - |PyMuPDFLayoutMode_EmptyList| a list of vector \"\n\"graphics rectangles on the page. This is a list of boundary boxes of \"\n\"clustered vector graphics as delivered by method \"\n\":meth:`Page.cluster_drawings`.\"\nmsgstr \"\"\n\"**\\\"graphics\\\"** - |PyMuPDFLayoutMode_EmptyList| 페이지의 벡터 그래픽 사각형 목록. 이것은 메서드 :meth:`Page.cluster_drawings` 에서 제공하는 클러스터링된 벡터 그래픽의 경계 상자 목록입니다.\"\n\n#: ../../pymupdf4llm/api.rst:131 57d71d3b3a3249569cbda9768c424bda\nmsgid \"**\\\"text\\\"** - page content as |Markdown| text.\"\nmsgstr \"**\\\"text\\\"** - |Markdown| 텍스트로 된 페이지 콘텐츠.\"\n\n#: ../../pymupdf4llm/api.rst:133 5f83592243374620aa76011c7afea0ae\nmsgid \"\"\n\"**\\\"words\\\"** - |PyMuPDFLayoutMode_EmptyList| if `extract_words=True` was\"\n\" used. This is a list of tuples `(x0, y0, x1, y1, \\\"wordstring\\\", bno, \"\n\"lno, wno)` as delivered by `page.get_text(\\\"words\\\")`. The **sequence** \"\n\"of these tuples however is the same as produced in the markdown text \"\n\"string and thus honors multi-column text. This is also true for text in \"\n\"tables: words are extracted in the sequence of table row cells.\"\nmsgstr \"\"\n\"**\\\"words\\\"** - |PyMuPDFLayoutMode_EmptyList| `extract_words=True` 가 사용된 경우. 이것은 `page.get_text(\\\"words\\\")` 에서 제공하는 튜플 `(x0, y0, x1, y1, \\\"wordstring\\\", bno, lno, wno)` 목록입니다. 그러나 이러한 튜플의 **순서** 는 마크다운 텍스트 문자열에서 생성된 것과 동일하므로 다중 열 텍스트를 존중합니다. 테이블의 텍스트에도 적용됩니다: 단어는 테이블 행 셀의 순서로 추출됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:135 a4eb7467e30b421a95b8c99919ecbce6\nmsgid \"\"\n\"specify a desired page height. For relevance see the `page_width` \"\n\"parameter. If using the default `None`, the document will appear as one \"\n\"large page with a width of `page_width`. Consequently in this case, no \"\n\"markdown page separators will occur (except the final one), respectively \"\n\"only one page chunk will be returned.\"\nmsgstr \"\"\n\"원하는 페이지 높이를 지정합니다. 관련성은 `page_width` 매개변수를 참조하세요. 기본값 `None` 을 사용하면 문서가 `page_width` 너비의 하나의 큰 페이지로 나타납니다. 결과적으로 이 경우 마크다운 페이지 구분자가 발생하지 않으며(마지막 것 제외), 각각 하나의 페이지 청크만 반환됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:137 3d9536256eb44ab18b73999b0e0a94ef\nmsgid \"\"\n\"if ``True`` inserts a string ``--- end of page=n ---`` at the end of each\"\n\" page output. Intended for debugging purposes. The page number is \"\n\"0-based. The separator string is wrapped with line breaks. Default is \"\n\"``False``.\"\nmsgstr \"\"\n\"``True`` 이면 각 페이지 출력 끝에 문자열 ``--- end of page=n ---`` 를 삽입합니다. 디버깅 목적으로 사용됩니다. 페이지 번호는 0-기반입니다. 구분자 문자열은 줄바꿈으로 감싸집니다. 기본값은 ``False`` 입니다.\"\n\n#: ../../pymupdf4llm/api.rst:139 9cb78dc09dde4bdb80163561a09b2df7\nmsgid \"\"\n\"specify a desired page width. This is ignored for documents with a fixed \"\n\"page width like PDF, XPS etc. **Reflowable** documents however, like \"\n\"e-books, office [#f2]_ or text files have no fixed page dimensions. They \"\n\"by default are assumed to have Letter format width (612) and an \"\n\"**unlimited** page height. This means that the **full document is treated\"\n\" as one large page.**\"\nmsgstr \"\"\n\"원하는 페이지 너비를 지정합니다. PDF, XPS 등 고정 페이지 너비를 가진 문서에서는 무시됩니다. 그러나 **재배치 가능한** 문서(예: 전자책, 오피스 [#f2]_ 또는 텍스트 파일)는 고정 페이지 크기가 없습니다. 기본적으로 Letter 형식 너비(612)와 **무제한** 페이지 높이를 가진 것으로 가정됩니다. 이것은 **전체 문서가 하나의 큰 페이지로 처리됨** 을 의미합니다.\"\n\n#: ../../pymupdf4llm/api.rst:141 ../../pymupdf4llm/api.rst:171\n#: 951850c1f7ff4f798dca7dda5b985f12 d4db9adce2fe428ab58a3903b6e897f9\nmsgid \"\"\n\"optional, the pages to consider for output (caution: specify 0-based page\"\n\" numbers). If omitted (`None`) all pages are processed. Any Python \"\n\"sequence with integer items is accepted. The sequence is sorted and \"\n\"processed to only contain unique items.\"\nmsgstr \"\"\n\"선택 사항, 출력을 위해 고려할 페이지(주의: 0-기반 페이지 번호 지정). 생략(`None`)하면 모든 페이지가 처리됩니다. 정수 항목이 있는 모든 Python 시퀀스가 허용됩니다. 시퀀스는 정렬되고 고유 항목만 포함하도록 처리됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:143 ../../pymupdf4llm/api.rst:175\n#: 56fb5c28b7784bf8b4a7d4c352ab926b 82e67bb02bfc4cf09bbf354bfaab4eae\n#: 9536a5d8ab5a41c98764cbe8dda15cb9\nmsgid \"\"\n\"Default is `False`. A value of `True` displays a progress bar as pages \"\n\"are being converted. Package `tqdm <https://pypi.org/project/tqdm/>`_ is \"\n\"used if installed, otherwise the built-in text based progress bar is \"\n\"used.\"\nmsgstr \"\"\n\"기본값은 `False` 입니다. `True` 값은 페이지가 변환되는 동안 진행 표시줄을 표시합니다. `tqdm <https://pypi.org/project/tqdm/>`_ 패키지가 설치되어 있으면 사용되고, 그렇지 않으면 내장 텍스트 기반 진행 표시줄이 사용됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:145 2db14405113e40179eb2edf68e69b579\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| see: :meth:`table detection strategy \"\n\"<Page.find_tables>`. Default is `\\\"lines_strict\\\"` which ignores \"\n\"background colors. In some occasions, other strategies may be more \"\n\"successful, for example `\\\"lines\\\"` which uses all vector graphics \"\n\"objects for detection.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| 참조: :meth:`테이블 감지 전략 <Page.find_tables>`. 기본값은 배경색을 무시하는 `\\\"lines_strict\\\"` 입니다. 경우에 따라 다른 전략이 더 성공적일 수 있습니다. 예를 들어 모든 벡터 그래픽 객체를 감지에 사용하는 `\\\"lines\\\"` 입니다.\"\n\n#: ../../pymupdf4llm/api.rst:147 abf44d2845b94d018e86396e471a2797\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Ignored| (New in v.0.0.19) Default is `False`. A value\"\n\" of `True` will use the glyph number of the characters instead of the \"\n\"character itself if the font does not store the Unicode value.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Ignored| (v.0.0.19에서 새로 추가됨) 기본값은 `False` 입니다. `True` 값은 폰트가 유니코드 값을 저장하지 않는 경우 문자 자체 대신 문자의 글리프 번호를 사용합니다.\"\n\n#: ../../pymupdf4llm/api.rst:149 dfec1fde53d145b4a723e9686dc1ad55\nmsgid \"\"\n\"when encountering images or vector graphics, images will be created from \"\n\"the respective page area and stored in the specified folder. |Markdown| \"\n\"references will be generated pointing to these images. Any text contained\"\n\" in these areas will not be included in the text output (but appear as \"\n\"part of the images). Therefore, if for instance your document has text \"\n\"written on full page images, make sure to set this parameter to `False`.\"\n\"  If using :ref:`PyMuPDF Layout <pymupdf-layout>`, boundary boxes that \"\n\"are classified as \\\"picture\\\" by the layout module will be treated as \"\n\"images - independent from the mixture of text, images or vector graphics \"\n\"they may be covering. If `force_text=True` is used, text will still be \"\n\"extracted from these areas and included in the output  after the \"\n\"respective image reference.\"\nmsgstr \"\"\n\n#: ../../pymupdf4llm/api.rst:149 93ccd09a15134624a2ab4a2288ba6171\nmsgid \"\"\n\"when encountering images or vector graphics, images will be created from \"\n\"the respective page area and stored in the specified folder. |Markdown| \"\n\"references will be generated pointing to these images. Any text contained\"\n\" in these areas will not be included in the text output (but appear as \"\n\"part of the images). Therefore, if for instance your document has text \"\n\"written on full page images, make sure to set this parameter to `False`.\"\nmsgstr \"\"\n\"이미지나 벡터 그래픽을 만나면 해당 페이지 영역에서 이미지가 생성되어 지정된 폴더에 저장됩니다. |Markdown| 참조가 이러한 이미지를 가리키도록 생성됩니다. 이러한 영역에 포함된 텍스트는 텍스트 출력에 포함되지 않습니다(이미지의 일부로 나타남). 따라서 예를 들어 문서에 전체 페이지 이미지에 텍스트가 작성된 경우 이 매개변수를 `False` 로 설정해야 합니다.\"\n\n#: ../../pymupdf4llm/api.rst:151 250eaf1b38694043b90736d4d9a821ce\nmsgid \"\"\n\"If using :ref:`PyMuPDF Layout <pymupdf-layout>`, boundary boxes that are \"\n\"classified as \\\"picture\\\" by the layout module will be treated as images \"\n\"- independent from the mixture of text, images or vector graphics they \"\n\"may be covering. If `force_text=True` is used, text will still be \"\n\"extracted from these areas and included in the output  after the \"\n\"respective image reference.\"\nmsgstr \"\"\n\":ref:`PyMuPDF Layout <pymupdf-layout>` 을 사용하는 경우 레이아웃 모듈에 의해 \\\"picture\\\"로 분류된 경계 상자는 이미지로 처리됩니다 - 덮고 있을 수 있는 텍스트, 이미지 또는 벡터 그래픽의 혼합과 무관합니다. `force_text=True` 가 사용되면 텍스트는 여전히 이러한 영역에서 추출되어 해당 이미지 참조 뒤에 출력에 포함됩니다.\"\n\n#: ../../pymupdf4llm/api.rst 0d07c67350cb436fb33e8aad838f6779\n#: 598d4d5d997b46ae9c685c56a12f8d30 6c9887cf2f934da0a3139fe4efef9133\n#: 7cd056f0a5e24e6c9cb9ef3811c9fe21 85a59fb19a314f869c001f8014cb715b\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../pymupdf4llm/api.rst:153 5f63166d8164444791851b4680d313dd\nmsgid \"\"\n\"Either a string of the combined text of all selected document pages, or a\"\n\" list of dictionaries if `page_chunks=True`.\"\nmsgstr \"\"\n\"선택된 모든 문서 페이지의 결합된 텍스트 문자열이거나 `page_chunks=True` 인 경우 딕셔너리 목록입니다.\"\n\n#: ../../pymupdf4llm/api.rst:159 5b52df94b00743b6a3926949923c8769\nmsgid \"\"\n\"Reads the pages of the file and outputs the text of its pages in |TXT| \"\n\"format.\"\nmsgstr \"\"\n\"파일의 페이지를 읽고 |TXT| 형식으로 페이지 텍스트를 출력합니다.\"\n\n#: ../../pymupdf4llm/api.rst:161 ../../pymupdf4llm/api.rst:182\n#: 67252eed1bc0433b86f2f7f7339cf77b b67079733cf74d7ba1d1fbbb866cb359\nmsgid \"\"\n\"|PyMuPDFLayoutMode_Valid|. This method is only available with PyMuPDF \"\n\"Layout.\"\nmsgstr \"\"\n\"|PyMuPDFLayoutMode_Valid|. 이 메서드는 PyMuPDF Layout에서만 사용할 수 있습니다.\"\n\n#: ../../pymupdf4llm/api.rst:165 d3ce63da02ea48dca75f94d50be77f12\nmsgid \"\"\n\"boolean to switch on/off page header content. This parameter controls \"\n\"whether to include or omit the header content from all the document \"\n\"pages. Useful if the document has repetitive header content which doesn't\"\n\" add any value to the overall extraction data. Default is `True` meaning \"\n\"that header content will be written.\"\nmsgstr \"\"\n\"페이지 헤더 콘텐츠를 켜거나 끄는 부울 값입니다. 이 매개변수는 모든 문서 페이지에서 헤더 콘텐츠를 포함할지 생략할지를 제어합니다. 문서에 반복적인 헤더 콘텐츠가 있어 전체 추출 데이터에 가치를 추가하지 않는 경우에 유용합니다. 기본값은 `True` 이며 헤더 콘텐츠가 작성됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:167 67bec0a4a60e463496475cd96362ffeb\nmsgid \"\"\n\"boolean to switch on/off page footer content. This parameter controls \"\n\"whether to include or omit the footer content from all the document \"\n\"pages. Useful if the document has repetitive footer content which doesn't\"\n\" add any value to the overall extraction data. Default is `True` meaning \"\n\"that footer content will be written.\"\nmsgstr \"\"\n\"페이지 푸터 콘텐츠를 켜거나 끄는 부울 값입니다. 이 매개변수는 모든 문서 페이지에서 푸터 콘텐츠를 포함할지 생략할지를 제어합니다. 문서에 반복적인 푸터 콘텐츠가 있어 전체 추출 데이터에 가치를 추가하지 않는 경우에 유용합니다. 기본값은 `True` 이며 푸터 콘텐츠가 작성됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:169 fb77c695d98d4c95aa3263b6b6d780b7\nmsgid \"\"\n\"if `True` then mono-spaced text lines do not receive special formatting. \"\n\"No blocks will be written and text lines will be written continuously.\"\nmsgstr \"\"\n\"`True` 이면 고정 폭 텍스트 줄이 특별한 형식을 받지 않습니다. 블록이 작성되지 않고 텍스트 줄이 연속적으로 작성됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:173 1b962ab25f1847bcbeca72a0b761b13e\nmsgid \"\"\n\"generate text output also when overlapping images / graphics. This text \"\n\"then appears after the respective image reference. Images (i.e. \"\n\"\\\"picture\\\" areas) however will not be written to the text output but \"\n\"appear as a text line in the output like `==> picture [width x height] \"\n\"<==`.\"\nmsgstr \"\"\n\"이미지/그래픽과 겹치는 경우에도 텍스트 출력을 생성합니다. 이 텍스트는 해당 이미지 참조 뒤에 나타납니다. 그러나 이미지(즉, \\\"picture\\\" 영역)는 텍스트 출력에 작성되지 않고 `==> picture [width x height] <==` 와 같은 텍스트 줄로 출력에 나타납니다.\"\n\n#: ../../pymupdf4llm/api.rst:180 5d81ef685e2d4f0db6010c6fe5be7a9d\nmsgid \"\"\n\"Parses the document and the specified pages and converts the result into \"\n\"a |JSON|-formatted string.\"\nmsgstr \"\"\n\"문서와 지정된 페이지를 구문 분석하고 결과를 |JSON| 형식 문자열로 변환합니다.\"\n\n#: ../../pymupdf4llm/api.rst:186 4855882483854c768ca0261d1ae19f75\nmsgid \"\"\n\"specify the desired image resolution in dots per inch. Default value is \"\n\"150. Only relevant if one of the parameters `write_images=True` or \"\n\"`embed_images=True` is used.\"\nmsgstr \"\"\n\"인치당 도트 수로 원하는 이미지 해상도를 지정합니다. 기본값은 150입니다. `write_images=True` 또는 `embed_images=True` 매개변수 중 하나가 사용된 경우에만 관련됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:188 92c49b4e2541455c8fc58a215abe7ded\nmsgid \"\"\n\"specify the desired image format via its extension. Default is \\\"png\\\" \"\n\"(portable network graphics). Another popular format may be \\\"jpg\\\". \"\n\"Possible values are all :ref:`supported output formats \"\n\"<Supported_File_Types>`. Only relevant if one of the parameters \"\n\"`write_images=True` or `embed_images=True` is used.\"\nmsgstr \"\"\n\"확장자를 통해 원하는 이미지 형식을 지정합니다. 기본값은 \\\"png\\\"(portable network graphics)입니다. 다른 인기 있는 형식은 \\\"jpg\\\"일 수 있습니다. 가능한 값은 모든 :ref:`지원되는 출력 형식 <Supported_File_Types>` 입니다. `write_images=True` 또는 `embed_images=True` 매개변수 중 하나가 사용된 경우에만 관련됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:190 1be020ddc3ca4fbe9f5fd73c3298040b\nmsgid \"\"\n\"store images in this folder. Relevant if `write_images=True`. Default is \"\n\"the path of the script directory. Page areas classified as \\\"picture\\\" \"\n\"will be written as image files to the specified location. The image file \"\n\"names will be of the format `{image_path}/{filename}-pagenumber-\"\n\"image_number.{image_format}`.\"\nmsgstr \"\"\n\"이 폴더에 이미지를 저장합니다. `write_images=True` 인 경우 관련됩니다. 기본값은 스크립트 디렉토리의 경로입니다. \\\"picture\\\"로 분류된 페이지 영역은 지정된 위치에 이미지 파일로 작성됩니다. 이미지 파일 이름은 `{image_path}/{filename}-pagenumber-image_number.{image_format}` 형식입니다.\"\n\n#: ../../pymupdf4llm/api.rst:192 984764256bf04d99b89ba80370d8541c\nmsgid \"\"\n\"generate text output for text that is written upon areas that are \"\n\"classified as \\\"picture\\\" by the layout module. This may be especially be\"\n\" useful when picture content is not stored.\"\nmsgstr \"\"\n\"레이아웃 모듈에 의해 \\\"picture\\\"로 분류된 영역에 작성된 텍스트에 대한 텍스트 출력을 생성합니다. 그림 콘텐츠가 저장되지 않은 경우 특히 유용할 수 있습니다.\"\n\n#: ../../pymupdf4llm/api.rst:194 8b5e7a2ba58e4b0da1eed3140c9a2eed\nmsgid \"display a progress bar during processing.\"\nmsgstr \"처리 중 진행 표시줄을 표시합니다.\"\n\n#: ../../pymupdf4llm/api.rst:196 5a55754f73304138814f39a3895fb5db\nmsgid \"\"\n\"store image binaries for \\\"picture\\\" boundary boxes. Base64-encoded \"\n\"images are included in the JSON output. Ignores `image_path` if used. \"\n\"This may drastically increase the size of your JSON text.\"\nmsgstr \"\"\n\"\\\"picture\\\" 경계 상자에 대한 이미지 바이너리를 저장합니다. Base64 인코딩된 이미지가 JSON 출력에 포함됩니다. 사용된 경우 `image_path` 를 무시합니다. 이것은 JSON 텍스트의 크기를 크게 증가시킬 수 있습니다.\"\n\n#: ../../pymupdf4llm/api.rst:198 13a91b7cc1f04969b4e871b8c7920989\nmsgid \"\"\n\"store image files \\\"picture\\\" boundary boxes.when encountering images, \"\n\"image files will be created from the respective page area and stored in \"\n\"the specified folder. Any text contained in these areas will still be \"\n\"included in the text output.\"\nmsgstr \"\"\n\"\\\"picture\\\" 경계 상자에 대한 이미지 파일을 저장합니다. 이미지를 만나면 해당 페이지 영역에서 이미지 파일이 생성되어 지정된 폴더에 저장됩니다. 이러한 영역에 포함된 텍스트는 여전히 텍스트 출력에 포함됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:200 dd0ddcf7925544d4b76e9734667d33f4\nmsgid \"\"\n\"optional, the pages to consider for output (caution: specify 0-based page\"\n\" numbers). If omitted (`None`) all pages are processed. Specify any valid\"\n\" Python sequence containing integers between `0` and `page_count - 1`.\"\nmsgstr \"\"\n\"선택 사항, 출력을 위해 고려할 페이지(주의: 0-기반 페이지 번호 지정). 생략(`None`)하면 모든 페이지가 처리됩니다. `0` 과 `page_count - 1` 사이의 정수를 포함하는 유효한 Python 시퀀스를 지정하세요.\"\n\n#: ../../pymupdf4llm/api.rst:205 47988e45549446179f8420be32191824\nmsgid \"\"\n\"Please see `this site \"\n\"<https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ for more \"\n\"background and the current status of further improvements regarding usage\"\n\" with :ref:`PyMuPDF Layout <pymupdf-layout>`.\"\nmsgstr \"\"\n\":ref:`PyMuPDF Layout <pymupdf-layout>` 사용에 대한 추가 배경 정보 및 개선 사항의 현재 상태는 `이 사이트 <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ 를 참조하세요.\"\n\n#: ../../pymupdf4llm/api.rst:210 8bdedbb86fac4bdca76803ff7f660033\nmsgid \"\"\n\"Create a `pdf_markdown_reader.PDFMarkdownReader` using the `LlamaIndex`_ \"\n\"package. Please note that this package will **not automatically be \"\n\"installed** when installing **pymupdf4llm**.\"\nmsgstr \"\"\n\"`LlamaIndex`_ 패키지를 사용하여 `pdf_markdown_reader.PDFMarkdownReader` 를 생성합니다. 이 패키지는 **pymupdf4llm** 설치 시 **자동으로 설치되지 않습니다**.\"\n\n#: ../../pymupdf4llm/api.rst:212 ac6f0e13b9034f77a6222df6d6f0a966\nmsgid \"\"\n\"For details on the possible arguments, please consult the LlamaIndex \"\n\"documentation [#f1]_.\"\nmsgstr \"\"\n\"가능한 인수에 대한 자세한 내용은 LlamaIndex 문서 [#f1]_ 를 참조하세요.\"\n\n#: ../../pymupdf4llm/api.rst 71aa61f2d1a446ec8dc78203d5e8258b\nmsgid \"raises\"\nmsgstr \"발생\"\n\n#: ../../pymupdf4llm/api.rst:214 f1a663fdbc6e4f06b71256b6a4ef2df9\nmsgid \"`NotImplementedError`: Please install required `LlamaIndex`_ package.\"\nmsgstr \"`NotImplementedError`: 필요한 `LlamaIndex`_ 패키지를 설치하세요.\"\n\n#: ../../pymupdf4llm/api.rst:215 9c61e09aba8942e081d3fc15080f8708\nmsgid \"\"\n\"a `pdf_markdown_reader.PDFMarkdownReader` and issues message \"\n\"\\\"Successfully imported LlamaIndex\\\". Please note that this method needs \"\n\"several seconds to execute. For details on using the markdown reader \"\n\"please see below.\"\nmsgstr \"\"\n\"`pdf_markdown_reader.PDFMarkdownReader` 를 생성하고 \\\"Successfully imported LlamaIndex\\\" 메시지를 발행합니다. 이 메서드는 실행하는 데 몇 초가 필요합니다. 마크다운 리더 사용에 대한 자세한 내용은 아래를 참조하세요.\"\n\n#: ../../pymupdf4llm/api.rst:222 ../../pymupdf4llm/api.rst:350\n#: 59202f45ef284beea61e2fb7c2b74d47 71f2f0dd222a44589ed37b4ae0fd4ad7\nmsgid \"|PyMuPDFLayoutMode_Unavailable|\"\nmsgstr \"|PyMuPDFLayoutMode_Unavailable|\"\n\n#: ../../pymupdf4llm/api.rst:227 36ad491d525c45e3923f3fd43b7ab548\nmsgid \"\"\n\"Create an object which maps text font sizes to the respective number of \"\n\"'#' characters which are used by Markdown syntax to indicate header \"\n\"levels. The object is created by scanning the document for font size \"\n\"\\\"popularity\\\". The most popular font size and all smaller sizes are used\"\n\" for body text. Larger font sizes are mapped to the respective header \"\n\"levels - which correspond to the HTML tags `<h1>` to `<h6>`.\"\nmsgstr \"\"\n\"텍스트 폰트 크기를 마크다운 구문에서 헤더 레벨을 나타내는 데 사용되는 '#' 문자 수에 매핑하는 객체를 생성합니다. 이 객체는 문서에서 폰트 크기 \\\"인기도\\\"를 스캔하여 생성됩니다. 가장 인기 있는 폰트 크기와 모든 작은 크기는 본문 텍스트에 사용됩니다. 더 큰 폰트 크기는 해당 헤더 레벨에 매핑됩니다 - 이는 HTML 태그 `<h1>` 에서 `<h6>` 에 해당합니다.\"\n\n#: ../../pymupdf4llm/api.rst:229 a5f1efbaa3ec4a3fa953b61ecb108cb5\nmsgid \"All font sizes are rounded to integer values.\"\nmsgstr \"모든 폰트 크기는 정수 값으로 반올림됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:231 060cf88a851843848a644386178dfc4f\nmsgid \"\"\n\"If more than 6 header levels would be required, then the largest number \"\n\"smaller than the `<h6>` font size is used for body text.\"\nmsgstr \"\"\n\"6개 이상의 헤더 레벨이 필요한 경우, `<h6>` 폰트 크기보다 작은 가장 큰 숫자가 본문 텍스트에 사용됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:233 4b8c52bf47c0493388a6cae3ddc6dc33\nmsgid \"\"\n\"Please note that creating the object will read and inspect the text of \"\n\"the entire document - independently of reading the document again in the \"\n\"`to_markdown()` method subsequently. Method `to_markdown()` by default \"\n\"**will create this object** if you do not override its `hdr_info=None` \"\n\"parameter.\"\nmsgstr \"\"\n\"객체를 생성하면 문서 전체의 텍스트를 읽고 검사합니다 - 이후 `to_markdown()` 메서드에서 문서를 다시 읽는 것과는 무관하게. `to_markdown()` 메서드는 기본적으로 `hdr_info=None` 매개변수를 재정의하지 않으면 **이 객체를 생성합니다**.\"\n\n#: ../../pymupdf4llm/api.rst:236 8a854caf0428436bb30ff64c0e2b7b99\nmsgid \"\"\n\"the file, to be specified either as a file path string, or as a |PyMuPDF|\"\n\" Document (created via `pymupdf.open`). In order to use `pathlib.Path` \"\n\"specifications, Python file-like objects, documents in memory etc. you \"\n\"**must** use a |PyMuPDF| Document.\"\nmsgstr \"\"\n\"파일 경로 문자열 또는 `pymupdf.open` 을 통해 생성된 |PyMuPDF| Document로 지정할 파일입니다. `pathlib.Path` 사양, Python 파일과 같은 객체, 메모리의 문서 등을 사용하려면 **반드시** |PyMuPDF| Document를 사용해야 합니다.\"\n\n#: ../../pymupdf4llm/api.rst:238 ca89a89858a54fcbbb852141997e973c\nmsgid \"optional, the pages to consider. If omitted all pages are processed.\"\nmsgstr \"선택 사항, 고려할 페이지. 생략하면 모든 페이지가 처리됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:240 28c341c4a1a546bda43c89f339be5704\nmsgid \"\"\n\"the default font size limit for body text. Only used when the document \"\n\"scan does not deliver valid information.\"\nmsgstr \"\"\n\"본문 텍스트의 기본 폰트 크기 제한. 문서 스캔이 유효한 정보를 제공하지 않을 때만 사용됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:242 9f2766b2b7ca488cbd3a37553ff5694f\nmsgid \"\"\n\"the maximum number of header levels to be used. Valid values are in \"\n\"`range(1, 7)`. The default is 6, which corresponds to the HTML tags \"\n\"`<h1>` to `<h6>`. A smaller value will limit the number of generated \"\n\"header levels. For instance, a value of 3 will only generate header tags \"\n\"\\\"#\\\", \\\"##\\\" and \\\"###\\\". Body text will be assumed for all font sizes \"\n\"smaller than the one corresponding to \\\"###\\\".\"\nmsgstr \"\"\n\"사용할 최대 헤더 레벨 수. 유효한 값은 `range(1, 7)` 입니다. 기본값은 6이며, 이는 HTML 태그 `<h1>` 에서 `<h6>` 에 해당합니다. 더 작은 값은 생성되는 헤더 레벨 수를 제한합니다. 예를 들어, 값 3은 헤더 태그 \\\"#\\\", \\\"##\\\", \\\"###\\\"만 생성합니다. 본문 텍스트는 \\\"###\\\"에 해당하는 폰트 크기보다 작은 모든 폰트 크기에 대해 가정됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:247 15756bee4cc048d0804e9ad2b8711c6b\nmsgid \"\"\n\"Return appropriate markdown header prefix. This is either \\\"\\\" or a \"\n\"string of \\\"#\\\" characters followed by a space.\"\nmsgstr \"\"\n\"적절한 마크다운 헤더 접두사를 반환합니다. 이는 빈 문자열이거나 공백이 뒤따르는 \\\"#\\\" 문자열입니다.\"\n\n#: ../../pymupdf4llm/api.rst:249 a58b7b22952e44f6a83e6cbd4945aec1\nmsgid \"\"\n\"Given a text span from a \\\"dict\\\" extraction, determine the markdown \"\n\"header prefix string of 0 to n concatenated '#' characters.\"\nmsgstr \"\"\n\"\\\"dict\\\" 추출에서 텍스트 스팬이 주어지면, 0에서 n까지 연결된 '#' 문자의 마크다운 헤더 접두사 문자열을 결정합니다.\"\n\n#: ../../pymupdf4llm/api.rst:251 ../../pymupdf4llm/api.rst:370\n#: 7a4b3f9199c64c60855e87be06938800 937b8a8741c941fe837306b743b991d2\nmsgid \"\"\n\"a dictionary containing the text span information. This is the same \"\n\"dictionary as returned by `page.get_text(\\\"dict\\\")`.\"\nmsgstr \"\"\n\"`page.get_text(\\\"dict\\\")` 에 의해 반환되는 것과 동일한 텍스트 스팬 정보를 포함하는 딕셔너리입니다.\"\n\n#: ../../pymupdf4llm/api.rst:253 ../../pymupdf4llm/api.rst:372\n#: 3f4de965af784b5aa3bc9c1d0da99386 4fb44301f96d4a76813aaaf15f5dbf3f\nmsgid \"\"\n\"the owning page object. This can be used when additional information \"\n\"needs to be extracted.\"\nmsgstr \"\"\n\"소유 페이지 객체. 추가 정보가 추출되어야 할 때 사용할 수 있습니다.\"\n\n#: ../../pymupdf4llm/api.rst:255 ../../pymupdf4llm/api.rst:374\n#: 1ada9bd96e9e481bbf098e63f0b97a34 4e537632f9824eafa6ea661c5c65813d\nmsgid \"a string of \\\"#\\\" characters followed by a space.\"\nmsgstr \"공백이 뒤따르는 \\\"#\\\" 문자열입니다.\"\n\n#: ../../pymupdf4llm/api.rst:259 e3e73fd9f50a4142a184bd4baa20c90b\nmsgid \"\"\n\"A dictionary mapping (integer) font sizes to Markdown header strings like\"\n\" ``{14: '# ', 12: '## '}``. The dictionary is created by the \"\n\":class:`IdentifyHeaders` constructor. The keys are the font sizes of the \"\n\"text spans in the document. The values are the respective header strings.\"\nmsgstr \"\"\n\"정수 폰트 크기를 ``{14: '# ', 12: '## '}`` 와 같은 마크다운 헤더 문자열에 매핑하는 딕셔너리입니다. 이 딕셔너리는 :class:`IdentifyHeaders` 생성자에 의해 생성됩니다. 키는 문서의 텍스트 스팬 폰트 크기입니다. 값은 해당 헤더 문자열입니다.\"\n\n#: ../../pymupdf4llm/api.rst:263 c5a884c560bc48cfb1e711db69d97d70\nmsgid \"\"\n\"An integer value indicating the font size limit for body text. This is \"\n\"computed as ``min(header_id.keys()) - 1``. In the above example, \"\n\"body_limit would be 11.\"\nmsgstr \"\"\n\"본문 텍스트의 폰트 크기 제한을 나타내는 정수 값. 이는 ``min(header_id.keys()) - 1`` 로 계산됩니다. 위 예시에서 body_limit은 11이 됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:269 18f9b62b612f43cb98b8bc9395d2e91d\nmsgid \"**How to limit header levels (example)**\"\nmsgstr \"**헤더 레벨 제한 방법 (예제)**\"\n\n#: ../../pymupdf4llm/api.rst:271 fdcd8a88e3764fe2beb711dd0f769a93\nmsgid \"Limit the generated header levels to 3::\"\nmsgstr \"생성된 헤더 레벨을 3으로 제한::\"\n\n#: ../../pymupdf4llm/api.rst:281 6922b5601f2b4e85abea7f1588a5242f\nmsgid \"**How to provide your own header logic (example 1)**\"\nmsgstr \"**자체 헤더 로직 제공 방법 (예제 1)**\"\n\n#: ../../pymupdf4llm/api.rst:283 0c5bbcfbc3d54e32afd708445550f723\nmsgid \"Provide your own function which uses pre-determined, fixed font sizes::\"\nmsgstr \"사전 결정된 고정 폰트 크기를 사용하는 자체 함수 제공::\"\n\n#: ../../pymupdf4llm/api.rst:310 b42d96ba59d74b32b1b76a558c18107f\nmsgid \"**How to provide your own header logic (example 2)**\"\nmsgstr \"**자체 헤더 로직 제공 방법 (예제 2)**\"\n\n#: ../../pymupdf4llm/api.rst:312 c06eabeb42df48b0a48defe0031513fe\nmsgid \"\"\n\"This user function uses the document's Table of Contents -- under the \"\n\"assumption that the bookmark text is also present as a header line on the\"\n\" page (which certainly need not be the case!)::\"\nmsgstr \"\"\n\"이 사용자 함수는 문서의 목차를 사용합니다 -- 북마크 텍스트가 페이지의 헤더 줄로도 존재한다는 가정 하에(반드시 그럴 필요는 없습니다!)::\"\n\n#: ../../pymupdf4llm/api.rst:354 7b2f4631e38449c0829b1d5669205310\nmsgid \"\"\n\"Create an object which uses the document's Table of Contents (TOC) to \"\n\"determine header levels. Upon object creation, the table of contents is \"\n\"read via the `Document.get_toc()` method. The TOC data is then used to \"\n\"determine header levels in the `to_markdown()` method.\"\nmsgstr \"\"\n\"문서의 목차(TOC)를 사용하여 헤더 레벨을 결정하는 객체를 생성합니다. 객체 생성 시 `Document.get_toc()` 메서드를 통해 목차를 읽습니다. TOC 데이터는 `to_markdown()` 메서드에서 헤더 레벨을 결정하는 데 사용됩니다.\"\n\n#: ../../pymupdf4llm/api.rst:356 80a339f128134f47b56bdd58fb75a2e7\nmsgid \"\"\n\"This is an alternative to :class:`IdentifyHeaders`. Instead of running \"\n\"through the full document to identify font sizes, it uses the document's \"\n\"Table Of Contents (TOC) to identify headers on pages. Like \"\n\":class:`IdentifyHeaders`, this also is no guarantee to find headers, but \"\n\"for well-built Table of Contents, there is a good chance for more \"\n\"correctly identifying header lines on document pages than the font-size-\"\n\"based approach.\"\nmsgstr \"\"\n\"이것은 :class:`IdentifyHeaders` 의 대안입니다. 전체 문서를 통해 폰트 크기를 식별하는 대신, 문서의 목차(TOC)를 사용하여 페이지의 헤더를 식별합니다. :class:`IdentifyHeaders` 와 마찬가지로, 이것도 헤더를 찾는 것을 보장하지는 않지만, 잘 구성된 목차의 경우 폰트 크기 기반 접근 방식보다 문서 페이지의 헤더 줄을 더 정확하게 식별할 가능성이 높습니다.\"\n\n#: ../../pymupdf4llm/api.rst:358 6ba9148a06a44cd0b05fab409c4283a1\nmsgid \"\"\n\"It also has the advantage of being much faster than the font-size-based \"\n\"approach, as it does not execute a full document scan or even access any \"\n\"of the document pages.\"\nmsgstr \"\"\n\"또한 전체 문서 스캔을 실행하거나 문서 페이지에 액세스하지 않으므로 폰트 크기 기반 접근 방식보다 훨씬 빠르다는 장점이 있습니다.\"\n\n#: ../../pymupdf4llm/api.rst:360 e09d29ea50ee4cb99e1e48f14cb1d419\nmsgid \"\"\n\"Examples where this approach works very well are the Adobe's files on PDF\"\n\" documentation.\"\nmsgstr \"\"\n\"이 접근 방식이 매우 잘 작동하는 예는 Adobe의 PDF 문서 파일입니다.\"\n\n#: ../../pymupdf4llm/api.rst:362 42d005a54259451e84de46008792d588\nmsgid \"\"\n\"Please note that this feature **does not read document pages** where the \"\n\"table of contents may exist as normal standard text. It only accesses \"\n\"data as provided by the `Document.get_toc()` method. It will not identify\"\n\" any headers for documents where the table of contents is not available \"\n\"as a collection of bookmarks.\"\nmsgstr \"\"\n\"이 기능은 목차가 일반 표준 텍스트로 존재할 수 있는 문서 페이지를 **읽지 않습니다**. `Document.get_toc()` 메서드에서 제공하는 데이터에만 액세스합니다. 목차가 북마크 모음으로 제공되지 않는 문서의 헤더는 식별하지 않습니다.\"\n\n#: ../../pymupdf4llm/api.rst:366 9747e3ce0895441493b43d41f4a9df78\nmsgid \"\"\n\"Return appropriate markdown header prefix. This is either an empty string\"\n\" or a string of \\\"#\\\" characters followed by a space.\"\nmsgstr \"\"\n\"적절한 마크다운 헤더 접두사를 반환합니다. 이는 빈 문자열이거나 공백이 뒤따르는 \\\"#\\\" 문자열입니다.\"\n\n#: ../../pymupdf4llm/api.rst:368 59e1904d38f140f0a477ffbb69d1dc7d\nmsgid \"\"\n\"Given a text span from a \\\"dict\\\" extraction variant, determine the \"\n\"markdown header prefix string of 0 to n concatenated \\\"#\\\" characters.\"\nmsgstr \"\"\n\"\\\"dict\\\" 추출 변형에서 텍스트 스팬이 주어지면, 0에서 n까지 연결된 \\\"#\\\" 문자의 마크다운 헤더 접두사 문자열을 결정합니다.\"\n\n#: ../../pymupdf4llm/api.rst:378 4b11b54d62a94df4905acf20c2ad8471\nmsgid \"**How to use class TocHeaders**\"\nmsgstr \"**TocHeaders 클래스 사용 방법**\"\n\n#: ../../pymupdf4llm/api.rst:380 95ea1015ab4c45ab9fdb488b9c270390\nmsgid \"\"\n\"This is a version of previous **example 2** that uses :class:`TocHeaders`\"\n\" for header identification::\"\nmsgstr \"\"\n\"이것은 헤더 식별을 위해 :class:`TocHeaders` 를 사용하는 이전 **예제 2** 의 버전입니다::\"\n\n#: ../../pymupdf4llm/api.rst:398 a4a87f3efb6d472d80ff03a5b8a23c65\nmsgid \"\"\n\"This is the only method of the markdown reader you should currently use \"\n\"to extract markdown data. Please in any case ignore methods \"\n\"`aload_data()` and `lazy_load_data()`. Other methods like \"\n\"`use_doc_meta()` may or may not make sense. For more information, please \"\n\"consult the LlamaIndex documentation [#f1]_.\"\nmsgstr \"\"\n\"이것은 현재 마크다운 데이터를 추출하는 데 사용해야 하는 마크다운 리더의 유일한 메서드입니다. 어떤 경우에도 `aload_data()` 및 `lazy_load_data()` 메서드를 무시하세요. `use_doc_meta()` 와 같은 다른 메서드는 의미가 있을 수도 있고 없을 수도 있습니다. 자세한 내용은 LlamaIndex 문서 [#f1]_ 를 참조하세요.\"\n\n#: ../../pymupdf4llm/api.rst:400 df377eb2611b45ad9e06938903718a76\nmsgid \"Under the hood the method will execute `to_markdown()`.\"\nmsgstr \"내부적으로 메서드는 `to_markdown()` 을 실행합니다.\"\n\n#: ../../pymupdf4llm/api.rst:402 afdbf4a1f22542639e7a55416dbdda7c\nmsgid \"a list of `LlamaIndexDocument` documents - one for each page.\"\nmsgstr \"`LlamaIndexDocument` 문서 목록 - 페이지당 하나씩.\"\n\n#: ../../pymupdf4llm/api.rst:406 fd268aa92d6044ef951c3f708636d48e\nmsgid \"\"\n\"For a list of changes, please see file `CHANGES.md \"\n\"<https://github.com/pymupdf/RAG/blob/main/CHANGES.md>`_.\"\nmsgstr \"\"\n\"변경 사항 목록은 `CHANGES.md <https://github.com/pymupdf/RAG/blob/main/CHANGES.md>`_ 파일을 참조하세요.\"\n\n#: ../../pymupdf4llm/api.rst:409 6446df28273c490c9e143aed82d42276\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../pymupdf4llm/api.rst:410 bbce2a3f10a44b019ed3acaa0a06e6b6\nmsgid \"`LlamaIndex documentation <https://docs.llamaindex.ai/en/stable/>`_\"\nmsgstr \"`LlamaIndex 문서 <https://docs.llamaindex.ai/en/stable/>`_\"\n\n#: ../../pymupdf4llm/api.rst:412 c49adecd61d04edda261abe63966093d\nmsgid \"\"\n\"When using PyMuPDF-Pro, supported office documents are converted \"\n\"internally into a PDF-like format. Therefore, they **will have fixed page\"\n\" dimensions** and be no longer \\\"reflowable\\\". Consequently, the page \"\n\"width and page height specifications will be ignored as well in these \"\n\"cases.\"\nmsgstr \"\"\n\"PyMuPDF-Pro를 사용할 때 지원되는 오피스 문서는 내부적으로 PDF와 유사한 형식으로 변환됩니다. 따라서 **고정 페이지 크기** 를 가지며 더 이상 \\\"재배치 가능\\\"하지 않습니다. 결과적으로 이러한 경우 페이지 너비 및 페이지 높이 사양도 무시됩니다.\"\n\n#: ../../footer.rst:48 1ed68f4bf8fd45fab04f7a49fba09f0a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n#~ msgid \"\"\n#~ \"This class is not available in \"\n#~ \"\\\"layout mode\\\", i.e. if the import \"\n#~ \"of pymupdf4llm has happened **after** \"\n#~ \"the statement ``import pymupdf.layout``.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/pymupdf4llm/index.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 16:19+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7f556c0708ab49cdbc462a525dfa7aff\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 4eb9ac713eaa4bc5a5a44191f5dec7ae\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8c03dba2f9bc41ab84de0114382f5e82\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../pymupdf4llm/index.rst:8 96b9f29894ff49beba7a07931c5c900d\nmsgid \"PyMuPDF4LLM\"\nmsgstr \"PyMuPDF4LLM\"\n\n#: ../../pymupdf4llm/index.rst:10 59d6714b7f6549e0a52c173974da2135\nmsgid \"\"\n\"|PyMuPDF4LLM| is aimed to make it easier to extract |PDF| content in the \"\n\"format you need for **LLM** & **RAG** environments. It supports \"\n\":ref:`Markdown extraction <extracting_as_md>` as well as :ref:`LlamaIndex\"\n\" document output <extracting_as_llamaindex>`.\"\nmsgstr \"|PyMuPDF4LLM| 는 **LLM** 및 **RAG** 환경에 필요한 형식으로 |PDF| 콘텐츠를 더 쉽게 추출할 수 있도록 하는 것을 목표로 합니다. :ref:`Markdown 추출 <extracting_as_md>` 및 :ref:`LlamaIndex 문서 출력 <extracting_as_llamaindex>` 을 지원합니다.\"\n\n#: ../../pymupdf4llm/index.rst:12 8b36d59c925f4a0d93873eeab7e4843a\nmsgid \"\"\n\"When using |PyMuPDF4LLM| with PyMuPDF Layout, page layout detection will \"\n\"be greatly improved. This is true for table detection, but also for the \"\n\"detection of page headers and footers, footnotes, list items and text \"\n\"paragraphs. In addition two new methods become available, `to_json()` and\"\n\" `to_text()`.\"\nmsgstr \"\"\n\"|PyMuPDF4LLM| 를 PyMuPDF Layout과 함께 사용하면 페이지 레이아웃 감지가 크게 향상됩니다. 이것은 테이블 감지뿐만 아니라 페이지 헤더 및 푸터, 각주, 목록 항목 및 텍스트 단락의 감지에도 해당합니다. 또한 두 가지 새로운 메서드 `to_json()` 및 `to_text()` 가 사용 가능해집니다.\"\n\n#: ../../pymupdf4llm/index.rst:16 50bf080e50e64ba58e973f0addf24d73\nmsgid \"\"\n\"You can extend the supported file types to also include **Office** \"\n\"document formats (DOC/DOCX, XLS/XLSX, PPT/PPTX, HWP/HWPX) by :ref:`using \"\n\"PyMuPDF Pro with PyMuPDF4LLM <using_pymupdf4llm_withpymupdfpro>`.\"\nmsgstr \":ref:`PyMuPDF Pro와 PyMuPDF4LLM 함께 사용 <using_pymupdf4llm_withpymupdfpro>` 하여 지원되는 파일 타입을 **Office** 문서 형식(DOC/DOCX, XLS/XLSX, PPT/PPTX, HWP/HWPX)도 포함하도록 확장할 수 있습니다.\"\n\n#: ../../pymupdf4llm/index.rst:19 38428359cdaf4039b439454f5c712ec7\nmsgid \"Features\"\nmsgstr \"기능\"\n\n#: ../../pymupdf4llm/index.rst:21 5f4fb197fcdd4a0ab3ac79607a78a25e\nmsgid \"Support for multi-column pages\"\nmsgstr \"다중 열 페이지 지원\"\n\n#: ../../pymupdf4llm/index.rst:22 7e249663241a4aacb2f9b1fcb4450393\nmsgid \"\"\n\"Support for image and vector graphics extraction (and inclusion of \"\n\"references in the MD text)\"\nmsgstr \"이미지 및 벡터 그래픽 추출 지원(MD 텍스트에 참조 포함)\"\n\n#: ../../pymupdf4llm/index.rst:23 cf659dc9b2da48d69e7ab3d1cda7f132\nmsgid \"Support for page chunking output.\"\nmsgstr \"페이지 청킹 출력 지원.\"\n\n#: ../../pymupdf4llm/index.rst:24 20715d6347fb42b7b485fba224287741\nmsgid \"\"\n\"Direct support for output as :ref:`LlamaIndex Documents \"\n\"<extracting_as_llamaindex>`.\"\nmsgstr \":ref:`LlamaIndex 문서 <extracting_as_llamaindex>` 로 출력하는 직접 지원.\"\n\n#: ../../pymupdf4llm/index.rst:25 42fe53c6392143838058ca9b8b1684a3\nmsgid \"\"\n\"When used with :ref:`PyMuPDF Layout <pymupdf-layout>` : Support for plain\"\n\" text output similar to Markdown\"\nmsgstr \"\"\n\":ref:`PyMuPDF Layout <pymupdf-layout>` 와 함께 사용할 때: Markdown과 유사한 일반 텍스트 출력 지원\"\n\n#: ../../pymupdf4llm/index.rst:26 345e944ae1c54464a70343f8ee2b62e9\nmsgid \"\"\n\"When used with :ref:`PyMuPDF Layout <pymupdf-layout>` : Support for JSON \"\n\"output\"\nmsgstr \"\"\n\":ref:`PyMuPDF Layout <pymupdf-layout>` 와 함께 사용할 때: JSON 출력 지원\"\n\n#: ../../pymupdf4llm/index.rst:30 90f6c12aacd14b7eba944b6c1e013ed5\nmsgid \"Functionality\"\nmsgstr \"기능\"\n\n#: ../../pymupdf4llm/index.rst:32 e63a722974dc41f3928dc372e66da5c0\nmsgid \"\"\n\"This package converts the pages of a file to text in **Markdown** format \"\n\"using |PyMuPDF|.\"\nmsgstr \"이 패키지는 |PyMuPDF| 를 사용하여 파일의 페이지를 **Markdown** 형식의 텍스트로 변환합니다.\"\n\n#: ../../pymupdf4llm/index.rst:34 1504c800279e44568bfbbeef3eb2ba6d\nmsgid \"\"\n\"Standard text and tables are detected, brought in the right reading \"\n\"sequence and then together converted to **GitHub**-compatible \"\n\"**Markdown** text.\"\nmsgstr \"표준 텍스트와 테이블이 감지되고 올바른 읽기 순서로 가져온 다음 **GitHub** 호환 **Markdown** 텍스트로 함께 변환됩니다.\"\n\n#: ../../pymupdf4llm/index.rst:36 4d3e28d4b9654f6889e99f25edeafb6f\nmsgid \"\"\n\"Header lines are identified via the font size and appropriately prefixed \"\n\"with one or more `#` tags.\"\nmsgstr \"헤더 줄은 글꼴 크기를 통해 식별되며 하나 이상의 `#` 태그로 적절히 접두사가 붙습니다.\"\n\n#: ../../pymupdf4llm/index.rst:38 d3dc9c01915e4fd5a47c1784eae70c00\nmsgid \"\"\n\"Bold, italic, mono-spaced text and code blocks are detected and formatted\"\n\" accordingly. Similar applies to ordered and unordered lists.\"\nmsgstr \"굵게, 기울임꼴, 고정폭 텍스트 및 코드 블록이 감지되고 그에 따라 형식화됩니다. 순서 있는 목록과 순서 없는 목록에도 유사하게 적용됩니다.\"\n\n#: ../../pymupdf4llm/index.rst:40 bc9f92950b5b4c038ed82153c462a0c6\nmsgid \"\"\n\"By default, all document pages are processed. If desired, a subset of \"\n\"pages can be specified by providing a list of `0`-based page numbers.\"\nmsgstr \"기본적으로 모든 문서 페이지가 처리됩니다. 원하는 경우 `0` 기반 페이지 번호 목록을 제공하여 페이지 하위 집합을 지정할 수 있습니다.\"\n\n#: ../../pymupdf4llm/index.rst:44 24714fd3cb744a908099e19f1af6ce7e\nmsgid \"Installation\"\nmsgstr \"설치\"\n\n#: ../../pymupdf4llm/index.rst:47 dd73904df42146e18551936620e44355\nmsgid \"Install the package via **pip** with:\"\nmsgstr \"**pip** 를 통해 패키지를 설치합니다:\"\n\n#: ../../pymupdf4llm/index.rst:58 a08840e778fe46379ec9110ad3c3608a\nmsgid \"Extracting a file as **Markdown**\"\nmsgstr \"파일을 **Markdown** 으로 추출\"\n\n#: ../../pymupdf4llm/index.rst:60 98c0760b58c04cbeb1299faf5b79ab3f\nmsgid \"\"\n\"To retrieve your document content in **Markdown** simply install the \"\n\"package and then use a couple of lines of **Python** code to get results.\"\nmsgstr \"**Markdown** 형식으로 문서 콘텐츠를 검색하려면 패키지를 설치한 다음 몇 줄의 **Python** 코드를 사용하여 결과를 얻습니다.\"\n\n#: ../../pymupdf4llm/index.rst:64 6a398956ca7f4c9c9057734393a79743\nmsgid \"Then in your **Python** script do:\"\nmsgstr \"그런 다음 **Python** 스크립트에서 다음을 수행합니다:\"\n\n#: ../../pymupdf4llm/index.rst:75 b227684a017d42e8b88f83ad2a3c673e\nmsgid \"\"\n\"Instead of the filename string as above, one can also provide a \"\n\":ref:`PyMuPDF Document <Document>`. A second parameter may be a list of \"\n\"`0`-based page numbers, e.g. `[0, 1]` would just select the first and \"\n\"second pages of the document.\"\nmsgstr \"위와 같이 파일명 문자열 대신 :ref:`PyMuPDF Document <Document>` 를 제공할 수도 있습니다. 두 번째 매개변수는 `0` 기반 페이지 번호 목록일 수 있습니다. 예를 들어 `[0,1]` 은 문서의 첫 번째와 두 번째 페이지만 선택합니다.\"\n\n#: ../../pymupdf4llm/index.rst:78 a0929decafbc41cb86a00b46905219e0\nmsgid \"\"\n\"If you want to store your **Markdown** file, e.g. store as a UTF8-encoded\"\n\" file, then do:\"\nmsgstr \"**Markdown** 파일을 저장하려면(예: UTF8 인코딩 파일로 저장) 다음을 수행합니다:\"\n\n#: ../../pymupdf4llm/index.rst:91 fe47c11343ec4d278c9f9cc524bccb86\nmsgid \"Extracting a file as a **LlamaIndex** document\"\nmsgstr \"파일을 **LlamaIndex** 문서로 추출\"\n\n#: ../../pymupdf4llm/index.rst:93 6834228bb5524c319b8c3d5dbe8138d6\nmsgid \"\"\n\"|PyMuPDF4LLM| supports direct conversion to a **LLamaIndex** document. A \"\n\"document is first converted into **Markdown** format and then a \"\n\"**LlamaIndex** document is returned as follows:\"\nmsgstr \"|PyMuPDF4LLM| 는 **LlamaIndex** 문서로 직접 변환을 지원합니다. 문서는 먼저 **Markdown** 형식으로 변환된 다음 다음과 같이 **LlamaIndex** 문서가 반환됩니다:\"\n\n#: ../../pymupdf4llm/index.rst:107 e653025ecf1948759d96b33b7902c524\nmsgid \"Using with |PyMuPDF Pro|\"\nmsgstr \"|PyMuPDF Pro| 와 함께 사용\"\n\n#: ../../pymupdf4llm/index.rst:110 9e877b4bd26d43cbaf81821091d51a1b\nmsgid \"\"\n\"For **Office** document support, |PyMuPDF4LLM| works seamlessly with \"\n\"|PyMuPDF Pro|. Assuming you have :doc:`../pymupdf-pro` installed you will\"\n\" be able to work with **Office** documents as expected:\"\nmsgstr \"**Office** 문서 지원을 위해 |PyMuPDF4LLM| 는 |PyMuPDF Pro| 와 원활하게 작동합니다. :doc:`../pymupdf-pro` 가 설치되어 있다고 가정하면 예상대로 **Office** 문서로 작업할 수 있습니다:\"\n\n#: ../../pymupdf4llm/index.rst:121 ff1a10504dbe4b5381a2f6232a21b346\nmsgid \"\"\n\"As you can see |PyMuPDF Pro| functionality will be available within the \"\n\"|PyMuPDF4LLM| context!\"\nmsgstr \"보시다시피 |PyMuPDF Pro| 기능이 |PyMuPDF4LLM| 컨텍스트 내에서 사용 가능합니다!\"\n\n#: ../../pymupdf4llm/index.rst:126 32a7f061e08e4a6ca0f4f3fddb070669\nmsgid \"API\"\nmsgstr \"API\"\n\n#: ../../pymupdf4llm/index.rst:128 b4ebede9414d489da467192cd788038a\nmsgid \"See :ref:`the PyMuPDF4LLM API <pymupdf4llm-api>`.\"\nmsgstr \":ref:`PyMuPDF4LLM API <pymupdf4llm-api>` 를 참조하세요.\"\n\n#: ../../pymupdf4llm/index.rst:131 bb3e7108ffa0474c9130db24bde17039\nmsgid \"Further Resources\"\nmsgstr \"추가 리소스\"\n\n#: ../../pymupdf4llm/index.rst:135 ec0ceb929e634253940d9d8b12c34e12\nmsgid \"Sample code\"\nmsgstr \"샘플 코드\"\n\n#: ../../pymupdf4llm/index.rst:137 f2d41ac1c1d24d9289e6ce68bc9370de\nmsgid \"\"\n\"`Command line RAG Chatbot with PyMuPDF \"\n\"<https://github.com/pymupdf/RAG/tree/main/examples/country-capitals>`_\"\nmsgstr \"`PyMuPDF 를 사용한 명령줄 RAG 챗봇 <https://github.com/pymupdf/RAG/tree/main/examples/country-capitals>`_\"\n\n#: ../../pymupdf4llm/index.rst:138 bf6ddba28b86427ab7c934e3fe869608\nmsgid \"\"\n\"`Example of a Browser Application using Langchain and PyMuPDF \"\n\"<https://github.com/pymupdf/RAG/tree/main/examples/GUI>`_\"\nmsgstr \"`Langchain과 PyMuPDF 를 사용한 브라우저 애플리케이션 예제 <https://github.com/pymupdf/RAG/tree/main/examples/GUI>`_\"\n\n#: ../../pymupdf4llm/index.rst:142 05f33a793ba04dbea19e7a464b4c8cd5\nmsgid \"Blogs\"\nmsgstr \"블로그\"\n\n#: ../../pymupdf4llm/index.rst:144 d6c3173afe6a4dbd880c662d9a8b9e66\nmsgid \"\"\n\"`RAG/LLM and PDF: Enhanced Text Extraction <https://artifex.com/blog/rag-\"\n\"llm-and-pdf-enhanced-text-extraction>`_\"\nmsgstr \"`RAG/LLM 및 PDF: 향상된 텍스트 추출 <https://artifex.com/blog/rag-llm-and-pdf-enhanced-text-extraction>`_\"\n\n#: ../../pymupdf4llm/index.rst:145 2469a1a8ebb649b083d10e876d5b3022\nmsgid \"\"\n\"`Creating a RAG Chatbot with ChatGPT and PyMuPDF \"\n\"<https://artifex.com/blog/creating-a-rag-chatbot-with-chatgpt-and-\"\n\"pymupdf>`_\"\nmsgstr \"`ChatGPT와 PyMuPDF 로 RAG 챗봇 만들기 <https://artifex.com/blog/creating-a-rag-chatbot-with-chatgpt-and-pymupdf>`_\"\n\n#: ../../pymupdf4llm/index.rst:146 750da7ec1111406c9f24fe09151140ae\nmsgid \"\"\n\"`Building a RAG Chatbot GUI with the ChatGPT API and PyMuPDF \"\n\"<https://artifex.com/blog/building-a-rag-chatbot-gui-with-the-chatgpt-\"\n\"api-and-pymupdf>`_\"\nmsgstr \"`ChatGPT API와 PyMuPDF 로 RAG 챗봇 GUI 구축 <https://artifex.com/blog/building-a-rag-chatbot-gui-with-the-chatgpt-api-and-pymupdf>`_\"\n\n#: ../../pymupdf4llm/index.rst:147 d820865d4e2b470b975fd95e67ec0436\nmsgid \"\"\n\"`RAG/LLM and PDF: Conversion to Markdown Text with PyMuPDF \"\n\"<https://artifex.com/blog/rag-llm-and-pdf-conversion-to-markdown-text-\"\n\"with-pymupdf>`_\"\nmsgstr \"`RAG/LLM 및 PDF: PyMuPDF 로 Markdown 텍스트로 변환 <https://artifex.com/blog/rag-llm-and-pdf-conversion-to-markdown-text-with-pymupdf>`_\"\n\n#: ../../footer.rst:48 30b12247e1244acba7a2885245d87849\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n#~ msgid \"\"\n#~ \"Instead of the filename string as \"\n#~ \"above, one can also provide a \"\n#~ \":ref:`PyMuPDF Document <Document>`. A second\"\n#~ \" parameter may be a list of \"\n#~ \"`0`-based page numbers, e.g. `[0,1]` \"\n#~ \"would just select the first and \"\n#~ \"second pages of the document.\"\n#~ msgstr \"\"\n\n#~ msgid \"\"\n#~ \"When using |PyMuPDF4LLM| with PyMuPDF-\"\n#~ \"Layout, page layout detection will be\"\n#~ \" greatly improved. This is true for\"\n#~ \" table detection, but also for the\"\n#~ \" detection of page headers and \"\n#~ \"footers, footnotes, list items and text\"\n#~ \" paragraphs. In addition two new \"\n#~ \"methods become available, `to_json()` and \"\n#~ \"`to_text()`.\"\n#~ msgstr \"\"\n\n#~ msgid \"In \\\"layout mode\\\": Support for plain text output similar to Markdown\"\n#~ msgstr \"\"\n\n#~ msgid \"In \\\"layout mode\\\": Support for JSON output\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/pyodide.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 9e4f1d023e4c4a2f9b1789603aba1601\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 02180e9a6b5e48f88c53ee91a688adb1\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 c68f782efd8344ff9fbda1a7566d3151\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../pyodide.rst:4 b63880b098224734b9b2dc4c700c8ef3\nmsgid \"Pyodide\"\nmsgstr \"Pyodide\"\n\n#: ../../pyodide.rst:8 ef1d306e03734c209cc1de803b563abf\nmsgid \"Overview\"\nmsgstr \"개요\"\n\n#: ../../pyodide.rst:11 a4f52f95cfaf4399817388f7e5cdb9c0\nmsgid \"\"\n\"`Pyodide <https://pyodide.org>`_ is a client-side Python implementation \"\n\"that runs in a web browser.\"\nmsgstr \"`Pyodide <https://pyodide.org>`_ 는 웹 브라우저에서 실행되는 클라이언트 측 Python 구현입니다.\"\n\n#: ../../pyodide.rst:14 414c957de5624f6ba708ad075d3d7a63\nmsgid \"The Pyodide build of PyMuPDF is currently experimental.\"\nmsgstr \"|PyMuPDF| 의 Pyodide 빌드는 현재 실험적입니다.\"\n\n#: ../../pyodide.rst:18 1199cc39832d45bdaa78306e41d821e5\nmsgid \"Building a PyMuPDF wheel for Pyodide\"\nmsgstr \"Pyodide용 |PyMuPDF| 휠 빌드\"\n\n#: ../../pyodide.rst:20 75ac11d9769c49a1afefaeaf2e66c13e\nmsgid \"\"\n\"A PyMuPDF wheel for Pyodide can be built by running \"\n\"`scripts/gh_release.py` with some environmental variable settings. This \"\n\"is regularly tested on Github by `.github/workflows/test_pyodide.yml`.\"\nmsgstr \"일부 환경 변수 설정과 함께 `scripts/gh_release.py` 를 실행하여 Pyodide용 |PyMuPDF| 휠을 빌드할 수 있습니다. 이것은 `.github/workflows/test_pyodide.yml` 에 의해 GitHub에서 정기적으로 테스트됩니다.\"\n\n#: ../../pyodide.rst:24 cf08249abe844603bd188263b0fabb48\nmsgid \"\"\n\"Here is an example of this, a single Linux command (to be run with the \"\n\"current directory set to a PyMuPDF checkout), that builds a Pyodide \"\n\"wheel::\"\nmsgstr \"다음은 |PyMuPDF| 체크아웃으로 현재 디렉토리를 설정한 상태에서 실행할 단일 Linux 명령으로 Pyodide 휠을 빌드하는 예제입니다::\"\n\n#: ../../pyodide.rst:33 9801c86b124048eaa3483bd780ea6964\nmsgid \"This does the following (all inside Python venv's):\"\nmsgstr \"다음 작업을 수행합니다 (모두 Python venv 내부에서):\"\n\n#: ../../pyodide.rst:35 de17df8ffe044736b9751eb4efeb9640\nmsgid \"\"\n\"Download (git clone and pip install) and customise a Pyodide build \"\n\"environment.\"\nmsgstr \"Pyodide 빌드 환경을 다운로드(git clone 및 pip install)하고 사용자 정의합니다.\"\n\n#: ../../pyodide.rst:36 00d95a72eea642cf9a06eea851573b78\nmsgid \"Download (git clone) the latest MuPDF.\"\nmsgstr \"최신 |MuPDF| 를 다운로드(git clone)합니다.\"\n\n#: ../../pyodide.rst:37 25c3416cee3a43639827a6237c3a3012\nmsgid \"Build MuPDF and PyMuPDF in the Pyodide build environment.\"\nmsgstr \"Pyodide 빌드 환경에서 |MuPDF| 와 |PyMuPDF| 를 빌드합니다.\"\n\n#: ../../pyodide.rst:38 096c442727774ebd99b66b131e42786f\nmsgid \"Create a wheel in `dist/`.\"\nmsgstr \"`dist/` 에 휠을 생성합니다.\"\n\n#: ../../pyodide.rst:40 47aca590fd0649b99cc760c1fbb7029d\nmsgid \"\"\n\"For more information, see the comments for functions \"\n\"`build_pyodide_wheel()` and `pyodide_setup()` in `scripts/gh_release.py`.\"\nmsgstr \"자세한 내용은 `scripts/gh_release.py` 의 함수 `build_pyodide_wheel()` 및 `pyodide_setup()` 에 대한 주석을 참조하세요.\"\n\n#: ../../pyodide.rst:45 c4fc80be31774fb2b23cda8d96a10202\nmsgid \"Using a Pyodide wheel\"\nmsgstr \"Pyodide 휠 사용\"\n\n#: ../../pyodide.rst:48 108ac7eb8b964c2cbc563d9761406088\nmsgid \"\"\n\"Upload the wheel (for example \"\n\"`PyMuPDF/dist/PyMuPDF-1.24.2-cp311-cp311-emscripten_3_1_32_wasm32.whl`) \"\n\"to a webserver which has been configured to allow Cross-origin resource \"\n\"sharing (https://en.wikipedia.org/wiki/Cross-origin_resource_sharing).\"\nmsgstr \"휠(예: `PyMuPDF/dist/PyMuPDF-1.24.2-cp311-cp311-emscripten_3_1_32_wasm32.whl`) 을 Cross-origin resource sharing(https://en.wikipedia.org/wiki/Cross-origin_resource_sharing)을 허용하도록 구성된 웹 서버에 업로드합니다.\"\n\n#: ../../pyodide.rst:54 14b102796b7a4d779c994b61aa456eb6\nmsgid \"\"\n\"The wheel can be used in a Pyodide console running in a web browser, or a\"\n\" JupyterLite notebook running in a web browser.\"\nmsgstr \"휠은 웹 브라우저에서 실행되는 Pyodide 콘솔 또는 웹 브라우저에서 실행되는 JupyterLite 노트북에서 사용할 수 있습니다.\"\n\n#: ../../pyodide.rst:57 298d17eab9bf4ac091904aa16a7b051b\nmsgid \"To create a Pyodide console, go to:\"\nmsgstr \"Pyodide 콘솔을 만들려면 다음으로 이동하세요:\"\n\n#: ../../pyodide.rst:59 f04d4a5529e5478090c9afdca37eab57\nmsgid \"https://pyodide.org/en/stable/console.html\"\nmsgstr \"https://pyodide.org/en/stable/console.html\"\n\n#: ../../pyodide.rst:61 2ed99e58360846728a2003c28a75ccce\nmsgid \"To create a JupyterLite notebook, go to:\"\nmsgstr \"JupyterLite 노트북을 만들려면 다음으로 이동하세요:\"\n\n#: ../../pyodide.rst:63 87c3dae4109c4bf4ab0ea41e5f5decfd\nmsgid \"https://jupyterlite.readthedocs.io/en/latest/_static/lab/index.html\"\nmsgstr \"https://jupyterlite.readthedocs.io/en/latest/_static/lab/index.html\"\n\n#: ../../pyodide.rst:66 ae8220ec6a5d45e78e3c2f569bab9574\nmsgid \"\"\n\"In both these cases, one can use the following code to download the wheel\"\n\" (replace `url` with the URL of the uploaded wheel) and import it::\"\nmsgstr \"두 경우 모두 다음 코드를 사용하여 휠을 다운로드(`url` 을 업로드된 휠의 URL로 교체)하고 가져올 수 있습니다::\"\n\n#: ../../pyodide.rst:74 89859ac6e1a347a7b279e57b128fb282\nmsgid \"\"\n\"Note that `micropip.install()` does not work, because of PyMuPDF's use of\"\n\" shared libraries.\"\nmsgstr \"|PyMuPDF| 가 공유 라이브러리를 사용하기 때문에 `micropip.install()` 이 작동하지 않습니다.\"\n\n#: ../../pyodide.rst:79 4fc797af4a414bd8b824e6adf8ea5e56\nmsgid \"Loading a PDF document from a URL into PyMuPDF\"\nmsgstr \"URL에서 |PyMuPDF| 로 PDF 문서 로드\"\n\n#: ../../pyodide.rst:82 df1f0a64f0ec4ac29b93e91709cbb966\nmsgid \"\"\n\"Pyodide browser console does not have generic network access, so for \"\n\"example `urllib.request.urlopen(url)` fails. But Pyodide has a built-in \"\n\"`pyodide.http` module that uses javascript internally, which one can use \"\n\"to download into a `bytes` instance, which can be used to create a \"\n\"PyMuPDF `Document` instance::\"\nmsgstr \"Pyodide 브라우저 콘솔에는 일반 네트워크 액세스가 없으므로 예를 들어 `urllib.request.urlopen(url)` 이 실패합니다. 하지만 Pyodide에는 내부적으로 javascript를 사용하는 내장 `pyodide.http` 모듈이 있어, 이를 사용하여 `bytes` 인스턴스로 다운로드할 수 있으며, 이를 사용하여 |PyMuPDF| `Document` 인스턴스를 만들 수 있습니다::\"\n\n#: ../../pyodide.rst:93 d9380bc488b14d1b863f1225ee39edfe\nmsgid \"It looks like this only works with `https://`, not `http://`.\"\nmsgstr \"이것은 `http://` 가 아닌 `https://` 에서만 작동하는 것 같습니다.\"\n\n#: ../../footer.rst:46 4640d757601c44b9a9490b7d6bff2214\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/quad.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7ec5d7130739408fa2694ff0c2ad75d3\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 5fae259f7fcf42cbb62f1d73baa02e63\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 0cf03cc6db804a65815e8d1e0054e12a\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../quad.rst:7 aa798d4be0214b06853be544b0785b84\nmsgid \"Quad\"\nmsgstr \"Quad\"\n\n#: ../../quad.rst:9 664d52df82ff48e2a329b6746b58b2b1\nmsgid \"\"\n\"Represents a four-sided mathematical shape (also called \\\"quadrilateral\\\"\"\n\" or \\\"tetragon\\\") in the plane, defined as a sequence of four \"\n\":ref:`Point` objects ul, ur, ll, lr (conveniently called upper left, \"\n\"upper right, lower left, lower right).\"\nmsgstr \"평면상의 사각형(또는 \\\"사변형\\\" 또는 \\\"사각형\\\"이라고도 함)을 나타내며, ul, ur, ll, lr(편의상 왼쪽 위, 오른쪽 위, 왼쪽 아래, 오른쪽 아래라고 함)의 4개의 :ref:`Point` 객체 시퀀스로 정의됩니다.\"\n\n#: ../../quad.rst:11 08d263b5866442108b7f33e20416a234\nmsgid \"\"\n\"Quads can **be obtained** as results of text search methods \"\n\"(:meth:`Page.search_for`), and they **are used** to define text marker \"\n\"annotations (see e.g. :meth:`Page.add_squiggly_annot` and friends), and \"\n\"in several draw methods (like :meth:`Page.draw_quad` / \"\n\":meth:`Shape.draw_quad`, :meth:`Page.draw_oval`/ \"\n\":meth:`Shape.draw_quad`).\"\nmsgstr \"Quad는 텍스트 검색 메서드(:meth:`Page.search_for`)의 결과로 **얻을 수 있으며**, 텍스트 마커 주석을 정의하는 데 **사용됩니다** (예: :meth:`Page.add_squiggly_annot` 및 관련 메서드 참조). 또한 여러 그리기 메서드(예: :meth:`Page.draw_quad` / :meth:`Shape.draw_quad`, :meth:`Page.draw_oval` / :meth:`Shape.draw_quad`)에서 사용됩니다.\"\n\n#: ../../quad.rst:15 30cb7b59b1ae4a5ea08731a41542f6bb\nmsgid \"\"\n\"If the corners of a rectangle are transformed with a **rotation**, \"\n\"**scale** or **translation** :ref:`Matrix`, then the resulting quad is \"\n\"**rectangular** (= congruent to a rectangle), i.e. all of its corners \"\n\"again enclose angles of 90 degrees. Property :attr:`Quad.is_rectangular` \"\n\"checks whether a quad can be thought of being the result of such an \"\n\"operation.\"\nmsgstr \"사각형의 모서리가 **회전**, **확대/축소** 또는 **이동** :ref:`Matrix` 로 변환되면 결과 quad는 **직사각형** (= 사각형과 합동)입니다. 즉, 모든 모서리가 다시 90도 각도를 이룹니다. 속성 :attr:`Quad.is_rectangular` 는 quad가 이러한 작업의 결과로 간주될 수 있는지 확인합니다.\"\n\n#: ../../quad.rst:17 3be08077e5cf46e193ba24399731c728\nmsgid \"\"\n\"This is not true for all matrices: e.g. shear matrices produce \"\n\"parallelograms, and non-invertible matrices deliver \\\"degenerate\\\" \"\n\"tetragons like triangles or lines.\"\nmsgstr \"이것은 모든 행렬에 대해 참이 아닙니다: 예를 들어, 기울이기 행렬은 평행사변형을 생성하고, 역행렬이 없는 행렬은 삼각형이나 선과 같은 \\\"퇴화된\\\" 사각형을 제공합니다.\"\n\n#: ../../quad.rst:19 223f177e5a564f43be092c227d86b112\nmsgid \"\"\n\"Attribute :attr:`Quad.rect` obtains the enveloping rectangle. Vice versa,\"\n\" rectangles now have attributes :attr:`Rect.quad`, resp. \"\n\":attr:`IRect.quad` to obtain their respective tetragon versions.\"\nmsgstr \"속성 :attr:`Quad.rect` 는 둘러싸는 사각형을 얻습니다. 반대로, 사각형은 이제 속성 :attr:`Rect.quad`, 각각 :attr:`IRect.quad` 를 가지고 있어 각각의 사각형 버전을 얻을 수 있습니다.\"\n\n#: ../../quad.rst:23 3934fff4cce44ebfac69ca1f1e02500e\nmsgid \"**Methods / Attributes**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../quad.rst:23 cdb016a40be44d93a40ab88520ffa8b3\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../quad.rst:25 791c2e6dfad84f60a324d45c361eb49f\nmsgid \":meth:`Quad.transform`\"\nmsgstr \":meth:`Quad.transform`\"\n\n#: ../../quad.rst:25 b4219d71eccb4873b81cc4d2cbcb6cbb\nmsgid \"transform with a matrix\"\nmsgstr \"행렬로 변환\"\n\n#: ../../quad.rst:26 adeda9365d014af99747c1b84d16d245\nmsgid \":meth:`Quad.morph`\"\nmsgstr \":meth:`Quad.morph`\"\n\n#: ../../quad.rst:26 fcecfd74d9564866958a61afa427072d\nmsgid \"transform with a point and matrix\"\nmsgstr \"점과 행렬로 변환\"\n\n#: ../../quad.rst:27 939ee16703a748c1b7562657da6cc054\nmsgid \":attr:`Quad.ul`\"\nmsgstr \":attr:`Quad.ul`\"\n\n#: ../../quad.rst:27 e89af93b74ba463e80523ab573be725d\nmsgid \"upper left point\"\nmsgstr \"왼쪽 위 점\"\n\n#: ../../quad.rst:28 cab5b3be90554379aae89e7da8ea19e5\nmsgid \":attr:`Quad.ur`\"\nmsgstr \":attr:`Quad.ur`\"\n\n#: ../../quad.rst:28 5f2493216d724836b99e69bb3f2c6ffd\nmsgid \"upper right point\"\nmsgstr \"오른쪽 위 점\"\n\n#: ../../quad.rst:29 d6e7980c18a64485b0f538f30d29d060\nmsgid \":attr:`Quad.ll`\"\nmsgstr \":attr:`Quad.ll`\"\n\n#: ../../quad.rst:29 00ae622c1ee44e99a8dd8ddb76e02b2a\nmsgid \"lower left point\"\nmsgstr \"왼쪽 아래 점\"\n\n#: ../../quad.rst:30 39a814307b8d4e799ac5cab34bed4f55\nmsgid \":attr:`Quad.lr`\"\nmsgstr \":attr:`Quad.lr`\"\n\n#: ../../quad.rst:30 880af62ca8a04aae96037daa38ab12b2\nmsgid \"lower right point\"\nmsgstr \"오른쪽 아래 점\"\n\n#: ../../quad.rst:31 31a8eb5ee9dd4eaf98509da0c412ccfa\nmsgid \":attr:`Quad.is_convex`\"\nmsgstr \":attr:`Quad.is_convex`\"\n\n#: ../../quad.rst:31 c28042739b2a4b60ac6c42f30bd29401\nmsgid \"true if quad is a convex set\"\nmsgstr \"quad가 볼록 집합이면 true\"\n\n#: ../../quad.rst:32 37497d0521974f6b87502804c9456f9d\nmsgid \":attr:`Quad.is_empty`\"\nmsgstr \":attr:`Quad.is_empty`\"\n\n#: ../../quad.rst:32 b051739d6773420e9d1042cf4501fe9e\nmsgid \"true if quad is an empty set\"\nmsgstr \"quad가 빈 집합이면 true\"\n\n#: ../../quad.rst:33 c7afddefaf7f4476977d2523faf20cbc\nmsgid \":attr:`Quad.is_rectangular`\"\nmsgstr \":attr:`Quad.is_rectangular`\"\n\n#: ../../quad.rst:33 df9d56bff733427dbe82f9bab5bba633\nmsgid \"true if quad is congruent to a rectangle\"\nmsgstr \"quad가 사각형과 합동이면 true\"\n\n#: ../../quad.rst:34 bfba7ccca7e84436b2db6a654b9e7208\nmsgid \":attr:`Quad.rect`\"\nmsgstr \":attr:`Quad.rect`\"\n\n#: ../../quad.rst:34 bcc943456152458291d460cd5fc66400\nmsgid \"smallest containing :ref:`Rect`\"\nmsgstr \"포함하는 가장 작은 :ref:`Rect`\"\n\n#: ../../quad.rst:35 9d18f5ed25604421a134ad9c5338e2a8\nmsgid \":attr:`Quad.width`\"\nmsgstr \":attr:`Quad.width`\"\n\n#: ../../quad.rst:35 3d617c28106542cf93d65cd246bb2ee6\nmsgid \"the longest width value\"\nmsgstr \"가장 긴 너비 값\"\n\n#: ../../quad.rst:36 86896dcc8bb845459987fab77ae2fc7e\nmsgid \":attr:`Quad.height`\"\nmsgstr \":attr:`Quad.height`\"\n\n#: ../../quad.rst:36 b00633cc845d40ea8282c89246c89ab9\nmsgid \"the longest height value\"\nmsgstr \"가장 긴 높이 값\"\n\n#: ../../quad.rst:39 963eed1326d34022aab68a6721f147e1\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../quad.rst:51 045248fd98ef41c9a3e88a5e995d0c01\nmsgid \"\"\n\"Overloaded constructors: \\\"ul\\\", \\\"ur\\\", \\\"ll\\\", \\\"lr\\\" stand for \"\n\":data:`point_like` objects (the four corners), \\\"sequence\\\" is a Python \"\n\"sequence with four :data:`point_like` objects.\"\nmsgstr \"오버로드된 생성자: \\\"ul\\\", \\\"ur\\\", \\\"ll\\\", \\\"lr\\\"는 :data:`point_like` 객체(4개의 모서리)를 나타내며, \\\"sequence\\\"는 4개의 :data:`point_like` 객체를 가진 Python 시퀀스입니다.\"\n\n#: ../../quad.rst:53 5af6b11b5ecb4ff19bf862fa90a4a4f2\nmsgid \"If \\\"quad\\\" is specified, the constructor creates a **new copy** of it.\"\nmsgstr \"\\\"quad\\\"가 지정되면 생성자는 그것의 **새 복사본** 을 만듭니다.\"\n\n#: ../../quad.rst:55 cea0afbfe7e446829d6109aee4dc330a\nmsgid \"\"\n\"Without parameters, a quad consisting of 4 copies of *Point(0, 0)* is \"\n\"created.\"\nmsgstr \"매개변수 없이 *Point(0, 0)* 의 4개 복사본으로 구성된 quad가 생성됩니다.\"\n\n#: ../../quad.rst:60 4b16d0be6f9a461f93515a13f6ac07ef\nmsgid \"\"\n\"Modify the quadrilateral by transforming each of its corners with a \"\n\"matrix.\"\nmsgstr \"각 모서리를 행렬로 변환하여 사각형을 수정합니다.\"\n\n#: ../../quad.rst 6ad7d5776f2748a380465099b165536d\n#: fcc95d04edce488f83cc252a7323652c\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../quad.rst:62 ../../quad.rst:69 bed48ffd731349bcb867f40fcbaf8a68\n#: fa657693f6094b69ba8adf946f1d9d4d\nmsgid \"the matrix.\"\nmsgstr \"행렬.\"\n\n#: ../../quad.rst:66 d449536aa4364cfa8d454ab5552538de\nmsgid \"\"\n\"*(New in version 1.17.0)* \\\"Morph\\\" the quad with a matrix-like using a \"\n\"point-like as fixed point.\"\nmsgstr \"*(버전 1.17.0에서 새로 추가됨)* 고정점으로 점과 유사한 것을 사용하여 행렬과 유사한 것으로 quad를 \\\"변형\\\"합니다.\"\n\n#: ../../quad.rst:68 1bc5f7ab62ff46dca6c4085984b1973e\nmsgid \"the point.\"\nmsgstr \"점.\"\n\n#: ../../quad.rst f004f07cfc6543989140c9a712f8318b\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../quad.rst:70 2314249ac3bf4d48af9f5d0c9918f092\nmsgid \"a new quad (no operation if this is the infinite quad).\"\nmsgstr \"새 quad(이것이 무한 quad인 경우 작업 없음).\"\n\n#: ../../quad.rst:75 790caa78886e4aa0a8e169a3884a528c\nmsgid \"\"\n\"The smallest rectangle containing the quad, represented by the blue area \"\n\"in the following picture.\"\nmsgstr \"quad를 포함하는 가장 작은 사각형으로, 다음 그림의 파란색 영역으로 표시됩니다.\"\n\n#: ../../quad.rst 23306adcb7c441c6b4a06d25179f70ff\n#: 29fcd747f839470f9cd452054f5ad2c6 2f60233b58254ddc83846169e9b77814\n#: 5cb78f927dc040ebb6b41e9dbff03a48 78a7d163966f44928813bdcff435e9bd\n#: 9e112f66c76f47ed990ca685b6ccb967 d08887513bee4c03877dc766e67a812e\n#: da27d9920c9247c7b07901d41c25a765 e54af6598b2446f9a18abddbfb930bf4\n#: f5aba2a5d1a04f22b723d0c816c0e825\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../quad.rst:79 7cca1627db0a4c789cb2bfbe34594522\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../quad.rst:83 db740f8e958d416fac479f484e53e7f5\nmsgid \"Upper left point.\"\nmsgstr \"왼쪽 위 점.\"\n\n#: ../../quad.rst:85 ../../quad.rst:91 ../../quad.rst:97 ../../quad.rst:103\n#: 1c8574d31d0343ca90a64a220a722491 325b06978c6644afb11af209b53aef75\n#: 5c193b8c51574a7388be59a99ec9f306 70ea90d3bd5645b8bca7b2e0a066b329\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../quad.rst:89 21467c9a895c4e438d7cb0faf4be00ce\nmsgid \"Upper right point.\"\nmsgstr \"오른쪽 위 점.\"\n\n#: ../../quad.rst:95 b82ee98f3f134593b40af259336342d3\nmsgid \"Lower left point.\"\nmsgstr \"왼쪽 아래 점.\"\n\n#: ../../quad.rst:101 da89c966391948d895f518fc03b9f064\nmsgid \"Lower right point.\"\nmsgstr \"오른쪽 아래 점.\"\n\n#: ../../quad.rst:107 bb5e071792a14d5c9526c8dc57993167\nmsgid \"New in version 1.16.1\"\nmsgstr \"버전 1.16.1에서 새로 추가됨\"\n\n#: ../../quad.rst:109 91bd8cd76c9c4afcbb037ddb9059df47\nmsgid \"\"\n\"Checks if for any two points of the quad, all points on their connecting \"\n\"line also belong to the quad.\"\nmsgstr \"quad의 임의의 두 점에 대해, 연결선 위의 모든 점도 quad에 속하는지 확인합니다.\"\n\n#: ../../quad.rst:114 ../../quad.rst:120 ../../quad.rst:126\n#: 5ae88b9907fb467f84267387a790a3c5 920999ae2e69406995af71a6dae1e8a6\n#: a538f6fd994649c1a7d2009e3e9276f3\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../quad.rst:118 c068cc4b85364edea719e7d034e85295\nmsgid \"\"\n\"True if enclosed area is zero, which means that at least three of the \"\n\"four corners are on the same line. If this is false, the quad may still \"\n\"be degenerate or not look like a tetragon at all (triangles, \"\n\"parallelograms, trapezoids, ...).\"\nmsgstr \"둘러싸인 영역이 0이면 True입니다. 이는 4개의 모서리 중 최소 3개가 같은 선상에 있음을 의미합니다. 이것이 false이면 quad는 여전히 퇴화되었거나 사각형처럼 보이지 않을 수 있습니다(삼각형, 평행사변형, 사다리꼴 등).\"\n\n#: ../../quad.rst:124 9f5e063e47c247c890c6956b98921d91\nmsgid \"\"\n\"True if all corner angles are 90 degrees. This implies that the quad is \"\n\"**convex and not empty**.\"\nmsgstr \"모든 모서리 각도가 90도이면 True입니다. 이것은 quad가 **볼록하고 비어 있지 않음** 을 의미합니다.\"\n\n#: ../../quad.rst:130 71ec407d1b0f4aa4a81edef402aa24df\nmsgid \"The maximum length of the top and the bottom side.\"\nmsgstr \"위쪽과 아래쪽 변의 최대 길이.\"\n\n#: ../../quad.rst:132 ../../quad.rst:138 2ffdd79a0a92446bbaf89d3ea83f1e43\n#: e2e1c5c2ebd0423190583a8ee05f1a84\nmsgid \"float\"\nmsgstr \"float\"\n\n#: ../../quad.rst:136 4c1f38db1cd34add898f6bdf1977db1a\nmsgid \"The maximum length of the left and the right side.\"\nmsgstr \"왼쪽과 오른쪽 변의 최대 길이.\"\n\n#: ../../quad.rst:141 9db22e1b205244fea68bc9fa262c3a44\nmsgid \"Remark\"\nmsgstr \"참고\"\n\n#: ../../quad.rst:142 b1fa23555ac34b80a5bf47ad6ba54cb7\nmsgid \"\"\n\"This class adheres to the sequence protocol, so components can be dealt \"\n\"with via their indices, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"이 클래스는 시퀀스 프로토콜을 따르므로 구성 요소는 인덱스를 통해 처리할 수도 있습니다. :ref:`SequenceTypes` 도 참조하세요.\"\n\n#: ../../quad.rst:145 cf59f6059ec346a4adf6477b2af26440\nmsgid \"Algebra and Containment Checks\"\nmsgstr \"대수 및 포함 확인\"\n\n#: ../../quad.rst:146 d1da8ae52c66485c81bd76a086dda1ed\nmsgid \"\"\n\"Starting with v1.19.6, quads can be used in algebraic expressions like \"\n\"the other geometry object -- the respective restrictions have been \"\n\"lifted. In particular, all the following combinations of containment \"\n\"checking are now possible:\"\nmsgstr \"v1.19.6부터 quad는 다른 기하 객체처럼 대수 표현식에서 사용할 수 있습니다 -- 해당 제한이 해제되었습니다. 특히, 다음 포함 확인 조합이 모두 가능합니다:\"\n\n#: ../../quad.rst:148 de141e1e28bb41bab1a153f2f74dec9c\nmsgid \"`{Point | IRect | Rect | Quad} in {IRect | Rect | Quad}`\"\nmsgstr \"`{Point | IRect | Rect | Quad} in {IRect | Rect | Quad}`\"\n\n#: ../../quad.rst:150 7822fe7129d44ee09c76eff91fe1b539\nmsgid \"Please note the following interesting detail:\"\nmsgstr \"다음 흥미로운 세부 사항을 참고하세요:\"\n\n#: ../../quad.rst:152 323318c4e76344b0a9f47f1f586de2c4\nmsgid \"\"\n\"For a rectangle, only its top-left point belongs to it. Since v1.19.0, \"\n\"rectangles are defined to be \\\"open\\\", such that its bottom and its right\"\n\" edge do not belong to it -- including the respective corners. But for \"\n\"quads there exists no such notion like \\\"openness\\\", so we have the \"\n\"following somewhat surprising implication:\"\nmsgstr \"사각형의 경우, 왼쪽 위 점만 속합니다. v1.19.0부터 사각형은 \\\"열림\\\"으로 정의되어 아래쪽과 오른쪽 가장자리는 속하지 않습니다 -- 해당 모서리 포함. 하지만 quad에는 \\\"열림\\\"과 같은 개념이 없으므로 다음과 같은 다소 놀라운 함의가 있습니다:\"\n\n#: ../../footer.rst:46 e7b27ac0bf7e4265b14be6be7b5ca967\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/rag.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 9ae2958084504b3cbf245bd73a2ab2b9\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 f48bded6e5a0490fbc182596e6c86f50\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 c3968fe2fa604ee2a68fdd576c733553\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../rag.rst:6 d9c164003dda4429a6f39b4abd473e49\nmsgid \"PyMuPDF, LLM & RAG\"\nmsgstr \"PyMuPDF, LLM 및 RAG\"\n\n#: ../../rag.rst:9 f18a0f62e26e4863b32ba327cc3828fe\nmsgid \"\"\n\"Integrating |PyMuPDF| into your :title:`Large Language Model (LLM)` \"\n\"framework and overall :title:`RAG (Retrieval-Augmented Generation`) \"\n\"solution provides the fastest and most reliable way to deliver document \"\n\"data.\"\nmsgstr \"|PyMuPDF| 를 :title:`Large Language Model (LLM)` 프레임워크 및 전체 :title:`RAG (Retrieval-Augmented Generation)` 솔루션에 통합하면 문서 데이터를 제공하는 가장 빠르고 신뢰할 수 있는 방법을 제공합니다.\"\n\n#: ../../rag.rst:11 6e23dfb312db4517ab86e93891470aed\nmsgid \"\"\n\"There are a few well known :title:`LLM` solutions which have their own \"\n\"interfaces with |PyMuPDF| - it is a fast growing area, so please let us \"\n\"know if you discover any more!\"\nmsgstr \"|PyMuPDF| 와 자체 인터페이스를 가진 몇 가지 잘 알려진 :title:`LLM` 솔루션이 있습니다. 빠르게 성장하는 분야이므로 더 발견하시면 알려주세요!\"\n\n#: ../../rag.rst:13 8de65ced808e469d9fac7bd41abaf9cf\nmsgid \"\"\n\"If you need to export to :title:`Markdown` or obtain a \"\n\":title:`LlamaIndex` Document from a file:\"\nmsgstr \":title:`Markdown` 으로 내보내거나 파일에서 :title:`LlamaIndex` 문서를 얻어야 하는 경우:\"\n\n#: ../../rag.rst:31 0e6f773ad0c846eb81ad529f37c724ce\nmsgid \"Integration with :title:`LangChain`\"\nmsgstr \":title:`LangChain` 과의 통합\"\n\n#: ../../rag.rst:33 617c7d9b690c427cb4d5f385dbaea902\nmsgid \"\"\n\"It is simple to integrate directly with :title:`LangChain` by using their\"\n\" dedicated loader as follows:\"\nmsgstr \"다음과 같이 전용 로더를 사용하여 :title:`LangChain` 과 직접 통합하는 것은 간단합니다:\"\n\n#: ../../rag.rst:43 2b8a08a537ff4f0c9d20ccd117cca1c7\nmsgid \"\"\n\"See `LangChain Using PyMuPDF \"\n\"<https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf\"\n\"/#using-pymupdf>`_ for full details.\"\nmsgstr \"자세한 내용은 `LangChain Using PyMuPDF <https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf/#using-pymupdf>`_ 를 참조하세요.\"\n\n#: ../../rag.rst:47 882dd97452644713ade70ec5d297ac45\nmsgid \"Integration with :title:`LlamaIndex`\"\nmsgstr \":title:`LlamaIndex` 와의 통합\"\n\n#: ../../rag.rst:50 0a3eaf04eb9c4726a40af71757d7454d\nmsgid \"\"\n\"Use the dedicated `PyMuPDFReader` from :title:`LlamaIndex` 🦙 to manage \"\n\"your document loading.\"\nmsgstr \":title:`LlamaIndex` 🦙 의 전용 `PyMuPDFReader` 를 사용하여 문서 로딩을 관리하세요.\"\n\n#: ../../rag.rst:58 49e6d30976b047949da389fa02a61f6d\nmsgid \"\"\n\"See `Building RAG from Scratch \"\n\"<https://docs.llamaindex.ai/en/stable/examples/low_level/oss_ingestion_retrieval>`_\"\n\" for more.\"\nmsgstr \"자세한 내용은 `Building RAG from Scratch <https://docs.llamaindex.ai/en/stable/examples/low_level/oss_ingestion_retrieval>`_ 를 참조하세요.\"\n\n#: ../../rag.rst:62 a966faf5a5914f53816c15fa2dc9cf18\nmsgid \"Preparing Data for Chunking\"\nmsgstr \"청킹을 위한 데이터 준비\"\n\n#: ../../rag.rst:64 c943a32cc39448f396304fd518f9a003\nmsgid \"\"\n\"Chunking (or splitting) data is essential to give context to your \"\n\":title:`LLM` data and with :title:`Markdown` output now supported by \"\n\"|PyMuPDF| this means that `Level 3 chunking \"\n\"<https://medium.com/@anuragmishra_27746/five-levels-of-chunking-\"\n\"strategies-in-rag-notes-from-gregs-video-7b735895694d#b123>`_ is \"\n\"supported.\"\nmsgstr \"데이터 청킹(또는 분할)은 :title:`LLM` 데이터에 컨텍스트를 제공하는 데 필수적이며, |PyMuPDF| 가 이제 :title:`Markdown` 출력을 지원하므로 `Level 3 chunking <https://medium.com/@anuragmishra_27746/five-levels-of-chunking-strategies-in-rag-notes-from-gregs-video-7b735895694d#b123>`_ 이 지원됨을 의미합니다.\"\n\n#: ../../rag.rst:71 c1d64297cf6740508697a6569cd86382\nmsgid \"Outputting as :title:`Markdown`\"\nmsgstr \":title:`Markdown` 으로 출력\"\n\n#: ../../rag.rst:73 39636d4fa0cf42edb1f1e408555643f2\nmsgid \"\"\n\"In order to export your document in :title:`Markdown` format you will \"\n\"need a separate helper. Package :doc:`pymupdf4llm/index` is a high-level \"\n\"wrapper of |PyMuPDF| functions which for each page outputs standard and \"\n\"table text in an integrated Markdown-formatted string across all document\"\n\" pages:\"\nmsgstr \":title:`Markdown` 형식으로 문서를 내보내려면 별도의 헬퍼가 필요합니다. 패키지 :doc:`pymupdf4llm/index` 는 |PyMuPDF| 함수의 고수준 래퍼로, 각 페이지에 대해 모든 문서 페이지에 걸쳐 통합된 Markdown 형식 문자열로 표준 텍스트와 테이블 텍스트를 출력합니다:\"\n\n#: ../../rag.rst:87 ab3bd85d9da04f3288b59385ab304c9a\nmsgid \"For further information please refer to: :doc:`pymupdf4llm/index`.\"\nmsgstr \"자세한 내용은 :doc:`pymupdf4llm/index` 를 참조하세요.\"\n\n#: ../../rag.rst:91 0e0368f9987d4fd6989fb56fb6001afd\nmsgid \"How to use :title:`Markdown` output\"\nmsgstr \":title:`Markdown` 출력 사용 방법\"\n\n#: ../../rag.rst:93 7bbbb34419cf4138a90d6f32225fd2c0\nmsgid \"\"\n\"Once you have your data in :title:`Markdown` format you are ready to \"\n\"chunk/split it and supply it to your :title:`LLM`, for example, if this \"\n\"is :title:`LangChain` then do the following:\"\nmsgstr \":title:`Markdown` 형식의 데이터가 준비되면 청킹/분할하여 :title:`LLM` 에 제공할 준비가 됩니다. 예를 들어, 이것이 :title:`LangChain` 인 경우 다음을 수행하세요:\"\n\n#: ../../rag.rst:109 e0cd08f28f6b4684b8212adaecee1134\nmsgid \"\"\n\"For more see `5 Levels of Text Splitting <https://github.com\"\n\"/FullStackRetrieval-\"\n\"com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb>`_\"\nmsgstr \"자세한 내용은 `5 Levels of Text Splitting <https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb>`_ 를 참조하세요.\"\n\n#: ../../rag.rst:113 59da1458c9df47cf875bc76ea4b09c0f\nmsgid \"Related Blogs\"\nmsgstr \"관련 블로그\"\n\n#: ../../rag.rst:115 fc915048dbc24e0fbbb2afab1ec5ea4c\nmsgid \"\"\n\"To find out more about |PyMuPDF|, :title:`LLM` & :title:`RAG` check out \"\n\"our blogs for implementations & tutorials.\"\nmsgstr \"|PyMuPDF|, :title:`LLM` 및 :title:`RAG` 에 대한 자세한 내용은 구현 및 튜토리얼 블로그를 확인하세요.\"\n\n#: ../../rag.rst:119 0122bc55056941f1ab375130d1567c25\nmsgid \"Methodologies to Extract Text\"\nmsgstr \"텍스트 추출 방법론\"\n\n#: ../../rag.rst:121 e7a6690e847f451e86a01250978a6578\nmsgid \"\"\n\"`Enhanced Text Extraction <https://artifex.com/blog/rag-llm-and-pdf-\"\n\"enhanced-text-extraction>`_\"\nmsgstr \"`Enhanced Text Extraction <https://artifex.com/blog/rag-llm-and-pdf-enhanced-text-extraction>`_\"\n\n#: ../../rag.rst:122 04321925122b427b86774ef96ad18527\nmsgid \"\"\n\"`Conversion to Markdown Text with PyMuPDF <https://artifex.com/blog/rag-\"\n\"llm-and-pdf-conversion-to-markdown-text-with-pymupdf>`_\"\nmsgstr \"`Conversion to Markdown Text with PyMuPDF <https://artifex.com/blog/rag-llm-and-pdf-conversion-to-markdown-text-with-pymupdf>`_\"\n\n#: ../../rag.rst:127 60562c518d964c8090b1290cd59e6a19\nmsgid \"Create a Chatbot to discuss your documents\"\nmsgstr \"문서를 논의하기 위한 챗봇 만들기\"\n\n#: ../../rag.rst:129 20a7402279fa4414b283adebd82344bd\nmsgid \"\"\n\"`Make a simple command line Chatbot <https://artifex.com/blog/creating-a\"\n\"-rag-chatbot-with-chatgpt-and-pymupdf>`_\"\nmsgstr \"`Make a simple command line Chatbot <https://artifex.com/blog/creating-a-rag-chatbot-with-chatgpt-and-pymupdf>`_\"\n\n#: ../../rag.rst:130 68ea640af63a45c382ba8d71fc1796ca\nmsgid \"\"\n\"`Make a Chatbot GUI <https://artifex.com/blog/building-a-rag-chatbot-gui-\"\n\"with-the-chatgpt-api-and-pymupdf>`_\"\nmsgstr \"`Make a Chatbot GUI <https://artifex.com/blog/building-a-rag-chatbot-gui-with-the-chatgpt-api-and-pymupdf>`_\"\n\n#: ../../footer.rst:46 e79c14c4775649ff81f129c4ebc2dcb1\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-annotations.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 e39981b2c0484073b422a752a1279263\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 a25bcd51270e4dff8f4dd98b5a7d2ea7\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 ffd0e115b0694217a5c11e90d1c837a8\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../recipes-annotations.rst:7 12ff591c90a64c459b910af4df023591\nmsgid \"Annotations\"\nmsgstr \"주석\"\n\n#: ../../recipes-annotations.rst:12 bc44c8128be246918c791ea26fd73fee\nmsgid \"How to Add and Modify Annotations\"\nmsgstr \"주석 추가 및 수정 방법\"\n\n#: ../../recipes-annotations.rst:14 a59a46aeff5e4ef494d91210cfb5db2a\nmsgid \"\"\n\"In |PyMuPDF|, new annotations can be added via :ref:`Page` methods. Once \"\n\"an annotation exists, it can be modified to a large extent using methods \"\n\"of the :ref:`Annot` class.\"\nmsgstr \"|PyMuPDF| 에서는 :ref:`Page` 메서드를 통해 새로운 주석을 추가할 수 있습니다. 주석이 존재하면 :ref:`Annot` 클래스의 메서드를 사용하여 대부분 수정할 수 있습니다.\"\n\n#: ../../recipes-annotations.rst:16 a3c0373aeefa401f92881e510ad0071c\nmsgid \"\"\n\"Annotations can **only** be inserted in |PDF| pages - other document \"\n\"types do not support annotation insertion.\"\nmsgstr \"주석은 |PDF| 페이지에만 삽입할 수 있습니다. 다른 문서 유형은 주석 삽입을 지원하지 않습니다.\"\n\n#: ../../recipes-annotations.rst:18 46c6f65e527d46acadde2b136d169470\nmsgid \"\"\n\"In contrast to many other tools, initial insert of annotations happens \"\n\"with a minimum number of properties. We leave it to the programmer to \"\n\"e.g. set attributes like author, creation date or subject.\"\nmsgstr \"다른 많은 도구와 달리, 주석의 초기 삽입은 최소한의 속성으로 수행됩니다. 예를 들어 작성자, 생성 날짜 또는 제목과 같은 속성을 설정하는 것은 프로그래머에게 맡깁니다.\"\n\n#: ../../recipes-annotations.rst:20 d729f5e88c444e6c9303c4deddaa0a97\nmsgid \"\"\n\"As an overview for these capabilities, look at the following script that \"\n\"fills a PDF page with most of the available annotations. Look in the next\"\n\" sections for more special situations:\"\nmsgstr \"이러한 기능에 대한 개요로, 사용 가능한 대부분의 주석으로 PDF 페이지를 채우는 다음 스크립트를 참조하세요. 더 특수한 상황에 대해서는 다음 섹션을 참조하세요:\"\n\n#: ../../recipes-annotations.rst:26 b668508bf5a2442aaea6ff355de90c9a\nmsgid \"This script should lead to the following output:\"\nmsgstr \"이 스크립트는 다음과 같은 출력을 생성해야 합니다:\"\n\n#: ../../recipes-annotations.rst:36 8a364e58ae174ad9b402e789c6a65d86\nmsgid \"How to Use FreeText\"\nmsgstr \"FreeText 사용 방법\"\n\n#: ../../recipes-annotations.rst:37 0369d14436b04373b454e0cbe29a65b3\nmsgid \"\"\n\"This script shows a couple of basic ways to deal with 'FreeText' \"\n\"annotations:\"\nmsgstr \"이 스크립트는 'FreeText' 주석을 처리하는 몇 가지 기본 방법을 보여줍니다:\"\n\n#: ../../recipes-annotations.rst:41 ../../recipes-annotations.rst:50\n#: 1a21cf6f40874661841ad5000a08a6fb 3ca839e69a444b2db34029d783dc79c4\nmsgid \"The result looks like this:\"\nmsgstr \"결과는 다음과 같습니다:\"\n\n#: ../../recipes-annotations.rst:46 f9f8bbc9486f42ef87d4c3f349be31d1\nmsgid \"Here is an example for using rich text and call-out lines:\"\nmsgstr \"다음은 서식 있는 텍스트와 설명선을 사용하는 예제입니다:\"\n\n#: ../../recipes-annotations.rst:63 cf8c08007d894233a60344bfbafb0253\nmsgid \"How to Use Ink Annotations\"\nmsgstr \"잉크 주석 사용 방법\"\n\n#: ../../recipes-annotations.rst:64 c0d699327401467ca37c7e4396f3235b\nmsgid \"\"\n\"Ink annotations are used to contain freehand scribbling. A typical \"\n\"example may be an image of your signature consisting of first name and \"\n\"last name. Technically an ink annotation is implemented as a **list of \"\n\"lists of points**. Each point list is regarded as a continuous line \"\n\"connecting the points. Different point lists represent independent line \"\n\"segments of the annotation.\"\nmsgstr \"잉크 주석은 손으로 그린 낙서를 포함하는 데 사용됩니다. 일반적인 예로는 이름과 성으로 구성된 서명 이미지가 있을 수 있습니다. 기술적으로 잉크 주석은 **점 목록의 목록** 으로 구현됩니다. 각 점 목록은 점을 연결하는 연속 선으로 간주됩니다. 서로 다른 점 목록은 주석의 독립적인 선 세그먼트를 나타냅니다.\"\n\n#: ../../recipes-annotations.rst:66 9f3baa89959f4c559f8a04c132d4ef39\nmsgid \"\"\n\"The following script creates an ink annotation with two mathematical \"\n\"curves (sine and cosine function graphs) as line segments:\"\nmsgstr \"다음 스크립트는 두 개의 수학 곡선(사인 및 코사인 함수 그래프)을 선 세그먼트로 사용하여 잉크 주석을 생성합니다:\"\n\n#: ../../recipes-annotations.rst:70 3f0535a897bd412ab755434fe5c5677e\nmsgid \"This is the result:\"\nmsgstr \"결과는 다음과 같습니다:\"\n\n#: ../../footer.rst:46 921b64bf6be94ffdbd4576b585c70ed6\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-common-issues-and-their-solutions.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b2d82d593c664654bc418e7afdf9e7b4\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 b78b5807c07e4a528626a4138223e8de\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 5b3592575d784e428d8d959c1aa99173\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:7\n#: cee0b81d77af4629884ac5a2a380da5c\nmsgid \"Common Issues and their Solutions\"\nmsgstr \"일반적인 문제 및 해결 방법\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:10\n#: 947c39129d6446e094c38d03760b989a\nmsgid \"How To Dynamically Clean Up Corrupt :title:`PDFs`\"\nmsgstr \"손상된 :title:`PDF` 를 동적으로 정리하는 방법\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:12\n#: 984b7de620ae4755bdc3dd0117a5c862\nmsgid \"\"\n\"This shows a potential use of |PyMuPDF| with another Python PDF library \"\n\"(the excellent pure Python package `pdfrw \"\n\"<https://pypi.python.org/pypi/pdfrw>`_ is used here as an example).\"\nmsgstr \"이것은 다른 Python PDF 라이브러리와 함께 |PyMuPDF| 를 사용하는 잠재적 사용 사례를 보여줍니다(여기서는 우수한 순수 Python 패키지 `pdfrw <https://pypi.python.org/pypi/pdfrw>`_ 를 예제로 사용합니다).\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:14\n#: efd17fd3443d4f67899e6f4e8c9bf24e\nmsgid \"\"\n\"If a clean, non-corrupt / decompressed PDF is needed, one could \"\n\"dynamically invoke PyMuPDF to recover from many problems like so::\"\nmsgstr \"깨끗하고 손상되지 않은/압축 해제된 PDF가 필요한 경우, 다음과 같이 |PyMuPDF| 를 동적으로 호출하여 많은 문제에서 복구할 수 있습니다::\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:50\n#: 3936184480104b60b59e5f2d35b8ae89\nmsgid \"\"\n\"With the command line utility *pdftk* (`available \"\n\"<https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/>`_ for Windows \"\n\"only, but reported to also run under `Wine <https://www.winehq.org/>`_) a\"\n\" similar result can be achieved, see `here \"\n\"<http://www.overthere.co.uk/2013/07/22/improving-pypdf2-with-pdftk/>`_. \"\n\"However, you must invoke it as a separate process via *subprocess.Popen*,\"\n\" using stdin and stdout as communication vehicles.\"\nmsgstr \"명령줄 유틸리티 *pdftk* (`available <https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/>`_ 는 Windows 전용이지만 `Wine <https://www.winehq.org/>`_ 에서도 실행된다고 보고됨)를 사용하여 유사한 결과를 얻을 수 있습니다. 자세한 내용은 `here <http://www.overthere.co.uk/2013/07/22/improving-pypdf2-with-pdftk/>`_ 를 참조하세요. 하지만 stdin과 stdout을 통신 수단으로 사용하여 *subprocess.Popen* 을 통해 별도 프로세스로 호출해야 합니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:55\n#: fe7e596e66ca4a86a1fe34324a9a62b4\nmsgid \"How to Convert Any Document to |PDF|\"\nmsgstr \"모든 문서를 |PDF| 로 변환하는 방법\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:57\n#: ac5c06eafcda49af9010b5dfe0e339ba\nmsgid \"\"\n\"Here is a script that converts any |PyMuPDF| :ref:`supported \"\n\"document<Supported_File_Types>` to a |PDF|. These include XPS, EPUB, FB2,\"\n\" CBZ and image formats, including multi-page TIFF images.\"\nmsgstr \"다음은 |PyMuPDF| 가 :ref:`지원하는 문서<Supported_File_Types>` 를 |PDF| 로 변환하는 스크립트입니다. 여기에는 XPS, EPUB, FB2, CBZ 및 다중 페이지 TIFF 이미지를 포함한 이미지 형식이 포함됩니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:59\n#: 256a7ef1c5ab469695bfaa2724670908\nmsgid \"\"\n\"It features maintaining any metadata, table of contents and links \"\n\"contained in the source document::\"\nmsgstr \"소스 문서에 포함된 모든 메타데이터, 목차 및 링크를 유지하는 기능이 있습니다::\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:131\n#: 5aee482ebb684ec799994f2a82dbfc75\nmsgid \"Changing Annotations: Unexpected Behaviour\"\nmsgstr \"주석 변경: 예상치 못한 동작\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:134\n#: cc0c26247fea4639ae1751eb8901a600\nmsgid \"Problem\"\nmsgstr \"문제\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:135\n#: 70437532335143b8b58a1d4c9a8568cb\nmsgid \"There are two scenarios:\"\nmsgstr \"두 가지 시나리오가 있습니다:\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:137\n#: 081715c0d34b4ed6b9e63c8a63a7ac2d\nmsgid \"\"\n\"**Updating** an annotation with PyMuPDF which was created by some other \"\n\"software.\"\nmsgstr \"다른 소프트웨어로 생성된 주석을 |PyMuPDF| 로 **업데이트** 하는 경우.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:138\n#: c4827e1b0a8f4af4ad46ecbb0abffa2b\nmsgid \"\"\n\"**Creating** an annotation with PyMuPDF and later changing it with some \"\n\"other software.\"\nmsgstr \"|PyMuPDF| 로 주석을 **생성** 한 후 다른 소프트웨어로 변경하는 경우.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:140\n#: 4237e934234748d3abf9e524336a4243\nmsgid \"\"\n\"In both cases you may experience unintended changes, like a different \"\n\"annotation icon or text font, the fill color or line dashing have \"\n\"disappeared, line end symbols have changed their size or even have \"\n\"disappeared too, etc.\"\nmsgstr \"두 경우 모두 주석 아이콘이나 텍스트 글꼴이 다르게 표시되거나, 채우기 색상이나 선의 파선이 사라지거나, 선 끝 기호의 크기가 변경되거나 사라지는 등의 의도하지 않은 변경이 발생할 수 있습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:143\n#: ../../recipes-common-issues-and-their-solutions.rst:182\n#: ../../recipes-common-issues-and-their-solutions.rst:195\n#: 0110a2da1aa6417a956feea6fd30428c 32fb7855910549f2ad7c953701ac3c0e\n#: c6624f27d1fa44b2a2f88b1c10495ca9\nmsgid \"Cause\"\nmsgstr \"원인\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:144\n#: 0c44e7ae5501406d90e73396b2cfde02\nmsgid \"\"\n\"Annotation maintenance is handled differently by each PDF maintenance \"\n\"application. Some annotation types may not be supported, or not be \"\n\"supported fully or some details may be handled in a different way than in\"\n\" another application. **There is no standard.**\"\nmsgstr \"주석 유지 관리는 각 PDF 유지 관리 애플리케이션마다 다르게 처리됩니다. 일부 주석 유형은 지원되지 않거나 완전히 지원되지 않을 수 있으며, 일부 세부 사항은 다른 애플리케이션과 다른 방식으로 처리될 수 있습니다. **표준이 없습니다.**\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:146\n#: 11bea0e065f94a779ec3d22653833179\nmsgid \"\"\n\"Almost always a PDF application also comes with its own icons (file \"\n\"attachments, sticky notes and stamps) and its own set of supported text \"\n\"fonts. For example:\"\nmsgstr \"거의 항상 PDF 애플리케이션은 자체 아이콘(파일 첨부, 스티커 메모 및 스탬프)과 자체 지원 텍스트 글꼴 세트를 제공합니다. 예를 들어:\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:148\n#: 54046db1813c480aa6d0dfaafd081e7f\nmsgid \"\"\n\"(Py-) MuPDF only supports these 5 basic fonts for 'FreeText' annotations:\"\n\" Helvetica, Times-Roman, Courier, ZapfDingbats and Symbol -- no italics /\"\n\" no bold variations. When changing a 'FreeText' annotation created by \"\n\"some other app, its font will probably not be recognized nor accepted and\"\n\" be replaced by Helvetica.\"\nmsgstr \"(Py-) |MuPDF| 는 'FreeText' 주석에 대해 다음 5가지 기본 글꼴만 지원합니다: Helvetica, Times-Roman, Courier, ZapfDingbats 및 Symbol -- 기울임꼴/굵게 변형 없음. 다른 앱으로 생성된 'FreeText' 주석을 변경할 때 해당 글꼴은 인식되지 않거나 허용되지 않을 가능성이 높으며 Helvetica로 대체됩니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:150\n#: 0616819cfbea4e98806d1310924671ec\nmsgid \"\"\n\"PyMuPDF supports all PDF text markers (highlight, underline, strikeout, \"\n\"squiggly), but these types cannot be updated with Adobe Acrobat Reader.\"\nmsgstr \"|PyMuPDF| 는 모든 PDF 텍스트 마커(강조, 밑줄, 취소선, 물결선)를 지원하지만, 이러한 유형은 Adobe Acrobat Reader로 업데이트할 수 없습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:152\n#: 7109456d991a465085055b08e8e3e36f\nmsgid \"\"\n\"In most cases there also exists limited support for line dashing which \"\n\"causes existing dashes to be replaced by straight lines. For example:\"\nmsgstr \"대부분의 경우 선 파선에 대한 제한적인 지원이 있어 기존 파선이 직선으로 대체됩니다. 예를 들어:\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:154\n#: 832b05a803034cb2b31a6a163b766c80\nmsgid \"\"\n\"PyMuPDF fully supports all line dashing forms, while other viewers only \"\n\"accept a limited subset.\"\nmsgstr \"|PyMuPDF| 는 모든 선 파선 형식을 완전히 지원하지만, 다른 뷰어는 제한된 하위 집합만 허용합니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:158\n#: 608cca13d68e48038902234a11344e7d\nmsgid \"Solutions\"\nmsgstr \"해결 방법\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:159\n#: f22d020f442e4ee9a04d2d148fb2e24a\nmsgid \"Unfortunately there is not much you can do in most of these cases.\"\nmsgstr \"안타깝게도 대부분의 경우 할 수 있는 일이 많지 않습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:161\n#: 31e1179fb95e4328b53c8cdba8f45e53\nmsgid \"Stay with the same software for **creating and changing** an annotation.\"\nmsgstr \"주석을 **생성하고 변경** 할 때 동일한 소프트웨어를 사용하세요.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:162\n#: 2c32e4727b8b4bd8ab345f1bb2dab832\nmsgid \"\"\n\"When using PyMuPDF to change an \\\"alien\\\" annotation, try to **avoid** \"\n\":meth:`Annot.update`. The following methods **can be used without it,** \"\n\"so that the original appearance should be maintained:\"\nmsgstr \"\\\"외부\\\" 주석을 변경할 때 |PyMuPDF| 를 사용하는 경우 :meth:`Annot.update` 를 **피하세요**. 다음 메서드는 **이것 없이 사용할 수 있으며**, 원래 모양이 유지됩니다:\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:164\n#: 5f2c568a7ab34cd6908429c03002c3b8\nmsgid \":meth:`Annot.set_rect` (location changes)\"\nmsgstr \":meth:`Annot.set_rect` (위치 변경)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:165\n#: f970043a80bc4905bfbc38378bef6cf7\nmsgid \":meth:`Annot.set_flags` (annotation behaviour)\"\nmsgstr \":meth:`Annot.set_flags` (주석 동작)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:166\n#: 89d8eeabb0864857bebb1dbd0b5837ac\nmsgid \":meth:`Annot.set_info` (meta information, except changes to *content*)\"\nmsgstr \":meth:`Annot.set_info` (메타 정보, *content* 변경 제외)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:167\n#: 8d145d703a694245bf8816344d618fca\nmsgid \":meth:`Annot.set_popup` (create popup or change its rect)\"\nmsgstr \":meth:`Annot.set_popup` (팝업 생성 또는 rect 변경)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:168\n#: ec8d39e7fcf1408083026bfb2854b761\nmsgid \"\"\n\":meth:`Annot.set_oc` (add / remove reference to optional content \"\n\"information)\"\nmsgstr \":meth:`Annot.set_oc` (선택적 콘텐츠 정보에 대한 참조 추가/제거)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:169\n#: 6b85081690ed4886ba03d08a836e7b4e\nmsgid \":meth:`Annot.set_open`\"\nmsgstr \":meth:`Annot.set_open`\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:170\n#: 90e51807c8d44cc1861553f1df436100\nmsgid \":meth:`Annot.update_file` (file attachment changes)\"\nmsgstr \":meth:`Annot.update_file` (파일 첨부 변경)\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:174\n#: dee4c83bcb6a49afb8cd17e74037844d\nmsgid \"Missing or Unreadable Extracted Text\"\nmsgstr \"누락되거나 읽을 수 없는 추출된 텍스트\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:175\n#: c1c8dec56daa4bac965e78b95eb48c58\nmsgid \"\"\n\"Fairly often, text extraction does not work text as you would expect: \"\n\"text may be missing, or may not appear in the reading sequence visible on\"\n\" your screen, or contain garbled characters (like a ? or a \\\"TOFU\\\" \"\n\"symbol), etc. This can be caused by a number of different problems.\"\nmsgstr \"텍스트 추출이 예상대로 작동하지 않는 경우가 많습니다: 텍스트가 누락되거나 화면에 표시되는 읽기 순서에 나타나지 않거나 문자 깨짐(예: ? 또는 \\\"TOFU\\\" 기호)이 포함될 수 있습니다. 이것은 여러 다른 문제로 인해 발생할 수 있습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:178\n#: 1339e236dda1461f94aa74a5c03ef680\nmsgid \"Problem: no text is extracted\"\nmsgstr \"문제: 텍스트가 추출되지 않음\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:179\n#: 10f358276c8043138089b5f17c8602a0\nmsgid \"\"\n\"Your PDF viewer does display text, but you cannot select it with your \"\n\"cursor, and text extraction delivers nothing.\"\nmsgstr \"PDF 뷰어는 텍스트를 표시하지만 커서로 선택할 수 없고 텍스트 추출 결과가 없습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:183\n#: f6463d656f7d4526b79aa27ea3adcfd6\nmsgid \"\"\n\"You may be looking at an image embedded in the PDF page (e.g. a scanned \"\n\"PDF).\"\nmsgstr \"PDF 페이지에 포함된 이미지를 보고 있을 수 있습니다(예: 스캔된 PDF).\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:184\n#: 4bda75cc75a84b058bdf9ae2b455a597\nmsgid \"\"\n\"The PDF creator used no font, but **simulated** text by painting it, \"\n\"using little lines and curves. E.g. a capital \\\"D\\\" could be painted by a\"\n\" line \\\"|\\\" and a left-open semi-circle, an \\\"o\\\" by an ellipse, and so \"\n\"on.\"\nmsgstr \"PDF 작성자가 글꼴을 사용하지 않고 작은 선과 곡선을 사용하여 텍스트를 **시뮬레이션** 했습니다. 예를 들어 대문자 \\\"D\\\"는 선 \\\"|\\\"와 왼쪽 열린 반원으로 그려질 수 있고, \\\"o\\\"는 타원으로 그려질 수 있습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:187\n#: ../../recipes-common-issues-and-their-solutions.rst:200\n#: 4c8ffe1feebe4a46ba615d636a0cf8c7 5ba7c372d3a145a2983fe0d7161d79c0\nmsgid \"Solution\"\nmsgstr \"해결 방법\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:188\n#: b4995dfcae78413486e26863052e0649\nmsgid \"\"\n\"Use an OCR software like `OCRmyPDF <https://pypi.org/project/ocrmypdf/>`_\"\n\" to insert a hidden text layer underneath the visible page. The resulting\"\n\" PDF should behave as expected.\"\nmsgstr \"`OCRmyPDF <https://pypi.org/project/ocrmypdf/>`_ 와 같은 OCR 소프트웨어를 사용하여 표시되는 페이지 아래에 숨겨진 텍스트 레이어를 삽입하세요. 결과 PDF는 예상대로 작동해야 합니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:191\n#: 1288979557ce452bb405ebe625a9fe85\nmsgid \"Problem: unreadable text\"\nmsgstr \"문제: 읽을 수 없는 텍스트\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:192\n#: b9738107688a468fb12503d2923c9223\nmsgid \"\"\n\"Text extraction does not deliver the text in readable order, duplicates \"\n\"some text, or is otherwise garbled.\"\nmsgstr \"텍스트 추출이 읽을 수 있는 순서로 텍스트를 제공하지 않거나, 일부 텍스트가 중복되거나, 그렇지 않으면 문자 깨짐이 발생합니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:196\n#: 1287dd9e37d94aae87d08382d28337b0\nmsgid \"\"\n\"The single characters are readable as such (no \\\"<?>\\\" symbols), but the \"\n\"sequence in which the text is **coded in the file** deviates from the \"\n\"reading order. The motivation behind may be technical or protection of \"\n\"data against unwanted copies.\"\nmsgstr \"개별 문자는 읽을 수 있지만( \\\"<?>\\\" 기호 없음), 텍스트가 **파일에 인코딩된** 순서가 읽기 순서와 다릅니다. 그 배경에는 기술적 이유나 원치 않는 복사로부터 데이터를 보호하려는 의도가 있을 수 있습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:197\n#: f63ebf6449ee40bdaa62ce0cbe979f7b\nmsgid \"\"\n\"Many \\\"<?>\\\" symbols occur, indicating MuPDF could not interpret these \"\n\"characters. The font may indeed be unsupported by MuPDF, or the PDF \"\n\"creator may haved used a font that displays readable text, but on purpose\"\n\" obfuscates the originating corresponding unicode character.\"\nmsgstr \"많은 \\\"<?>\\\" 기호가 발생하여 |MuPDF| 가 이러한 문자를 해석할 수 없음을 나타냅니다. 글꼴이 실제로 |MuPDF| 에서 지원되지 않을 수 있거나, PDF 작성자가 읽을 수 있는 텍스트를 표시하지만 의도적으로 원본 해당 유니코드 문자를 난독화하는 글꼴을 사용했을 수 있습니다.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:201\n#: 70176f300c204737999ad6e71bb79baa\nmsgid \"Use layout preserving text extraction: `python -m fitz gettext file.pdf`.\"\nmsgstr \"레이아웃을 유지하는 텍스트 추출을 사용하세요: `python -m fitz gettext file.pdf`.\"\n\n#: ../../recipes-common-issues-and-their-solutions.rst:202\n#: 4b4ceb3c473b47a9b06e9bb658885b14\nmsgid \"\"\n\"If other text extraction tools also don't work, then the only solution \"\n\"again is OCRing the page.\"\nmsgstr \"다른 텍스트 추출 도구도 작동하지 않으면, 다시 유일한 해결책은 페이지를 OCR 처리하는 것입니다.\"\n\n#: ../../footer.rst:46 07c9714719d541aeb1f5ae9b443f8e23\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-drawing-and-graphics.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 a59582325d1e4587841306a803482970\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 90e5418f2a4041ddb379751a155076c1\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 cbdc25861a8d484890d2227e3494b661\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../recipes-drawing-and-graphics.rst:7 dab2a6c85f334d099e76c1c25fc379f3\nmsgid \"Drawing and Graphics\"\nmsgstr \"그리기 및 그래픽\"\n\n#: ../../recipes-drawing-and-graphics.rst:11 a70f821282c64602b5f57347f8a0bae4\nmsgid \"\"\n\"When the terms \\\"Drawings\\\" or \\\"Graphics\\\" are mentioned here we are \"\n\"referring to \\\"Vector Graphics\\\" or \\\"Line Art\\\".\"\nmsgstr \"여기서 \\\"Drawings\\\" 또는 \\\"Graphics\\\"라는 용어가 언급될 때는 \\\"벡터 그래픽\\\" 또는 \\\"선화\\\"를 의미합니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:13 93510784237c4c4b885dc832f8aaeb1f\nmsgid \"Therefore please consider these terms as being synonymous!\"\nmsgstr \"따라서 이러한 용어를 동의어로 간주하세요!\"\n\n#: ../../recipes-drawing-and-graphics.rst:16 df755690b5be464ab98f1f6014fc5132\nmsgid \"\"\n\"PDF files support elementary drawing operations as part of their syntax. \"\n\"These are **vector graphics** and include basic geometrical objects like \"\n\"lines, curves, circles, rectangles including specifying colors.\"\nmsgstr \"PDF 파일은 구문의 일부로 기본 그리기 작업을 지원합니다. 이것들은 **벡터 그래픽** 이며 선, 곡선, 원, 사각형과 같은 기본 기하학적 객체를 포함하며 색상 지정도 포함합니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:18 a7dfbdbdeeb54c68afa0bbf219b2f3ba\nmsgid \"\"\n\"The syntax for such operations is defined in \\\"A Operator Summary\\\" on \"\n\"page 643 of the :ref:`AdobeManual`. Specifying these operators for a PDF \"\n\"page happens in its :data:`contents` objects.\"\nmsgstr \"이러한 작업의 구문은 :ref:`AdobeManual` 의 643페이지의 \\\"A Operator Summary\\\"에 정의되어 있습니다. PDF 페이지에 대한 이러한 연산자 지정은 해당 :data:`contents` 객체에서 수행됩니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:20 463f264141f64e68b6fbe2cd2f02fbbb\nmsgid \"\"\n\"|PyMuPDF| implements a large part of the available features via its \"\n\":ref:`Shape` class, which is comparable to notions like \\\"canvas\\\" in \"\n\"other packages (e.g. `reportlab <https://pypi.org/project/reportlab/>`_).\"\nmsgstr \"|PyMuPDF| 는 :ref:`Shape` 클래스를 통해 사용 가능한 기능의 대부분을 구현하며, 이는 다른 패키지(예: `reportlab <https://pypi.org/project/reportlab/>`_)의 \\\"canvas\\\"와 같은 개념과 유사합니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:22 d166a046958a49a8a28311049458c79a\nmsgid \"\"\n\"A shape is always created as a **child of a page**, usually with an \"\n\"instruction like `shape = page.new_shape()`. The class defines numerous \"\n\"methods that perform drawing operations on the page's area. For example, \"\n\"`last_point = shape.draw_rect(rect)` draws a rectangle along the borders \"\n\"of a suitably defined `rect = pymupdf.Rect(...)`.\"\nmsgstr \"Shape는 항상 **페이지의 자식** 으로 생성되며, 일반적으로 `shape = page.new_shape()` 와 같은 명령으로 생성됩니다. 이 클래스는 페이지 영역에서 그리기 작업을 수행하는 여러 메서드를 정의합니다. 예를 들어, `last_point = shape.draw_rect(rect)` 는 적절히 정의된 `rect = pymupdf.Rect(...)` 의 경계를 따라 사각형을 그립니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:24 4b3375c816d64b008ab7d1854be54f7a\nmsgid \"\"\n\"The returned *last_point* **always** is the :ref:`Point` where drawing \"\n\"operation ended (\\\"last point\\\"). Every such elementary drawing requires \"\n\"a subsequent :meth:`Shape.finish` to \\\"close\\\" it, but there may be \"\n\"multiple drawings which have one common ``finish()`` method.\"\nmsgstr \"반환된 *last_point* 는 **항상** 그리기 작업이 끝난 :ref:`Point` (\\\"마지막 점\\\")입니다. 이러한 모든 기본 그리기는 \\\"닫기\\\"를 위해 후속 :meth:`Shape.finish` 가 필요하지만, 하나의 공통 ``finish()`` 메서드를 가진 여러 그리기가 있을 수 있습니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:26 f14edc2fb2be4ab8ba19ffdb3740738d\nmsgid \"\"\n\"In fact, :meth:`Shape.finish` *defines* a group of preceding draw \"\n\"operations to form one -- potentially rather complex -- graphics object. \"\n\"|PyMuPDF| provides several predefined graphics in `shapes_and_symbols.py \"\n\"<https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/shapes/shapes_and_symbols.py>`_ which demonstrate \"\n\"how this works.\"\nmsgstr \"실제로 :meth:`Shape.finish` 는 앞선 그리기 작업 그룹을 하나의 잠재적으로 복잡한 그래픽 객체로 형성하도록 *정의* 합니다. |PyMuPDF| 는 이것이 어떻게 작동하는지 보여주는 `shapes_and_symbols.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/shapes/shapes_and_symbols.py>`_ 에 여러 사전 정의된 그래픽을 제공합니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:28 c9bdfffa82e64c1d8431f654e9925619\nmsgid \"\"\n\"If you import this script, you can also directly use its graphics as in \"\n\"the following example::\"\nmsgstr \"이 스크립트를 가져오면 다음 예제와 같이 그래픽을 직접 사용할 수도 있습니다::\"\n\n#: ../../recipes-drawing-and-graphics.rst:86 e4c7e6930be54525bd756ddc32d931d2\nmsgid \"This is the script's outcome:\"\nmsgstr \"이것은 스크립트의 결과입니다:\"\n\n#: ../../recipes-drawing-and-graphics.rst:97 63f4873345ad4432a9dcf2f213c921ca\nmsgid \"How to Extract Drawings\"\nmsgstr \"그리기 추출 방법\"\n\n#: ../../recipes-drawing-and-graphics.rst:99 c269bccda59e4ce1be7bfbb7665979a2\nmsgid \"New in v1.18.0\"\nmsgstr \"v1.18.0의 새로운 기능\"\n\n#: ../../recipes-drawing-and-graphics.rst:101 99437db9d3344f56937dc3ef539d724e\nmsgid \"\"\n\"Drawing commands (**vector graphics**) issued by a page can be extracted \"\n\"as a list of dictionaries. Interestingly, this is possible for :ref:`all \"\n\"supported document types<Supported_File_Types>` -- not just PDF: so you \"\n\"can use it for XPS, EPUB and others as well.\"\nmsgstr \"페이지에서 발행한 그리기 명령(**벡터 그래픽**)은 딕셔너리 목록으로 추출할 수 있습니다. 흥미롭게도 이것은 :ref:`모든 지원 문서 유형<Supported_File_Types>` 에 대해 가능합니다. PDF뿐만 아니라 XPS, EPUB 등에도 사용할 수 있습니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:103 9746769ddda943309de190bcae0ff9fe\nmsgid \"\"\n\"Page method, :meth:`Page.get_drawings()` accesses draw commands and \"\n\"converts them into a list of Python dictionaries. Each dictionary -- \"\n\"called a \\\"path\\\" -- represents a separate drawing -- it may be simple \"\n\"like a single line, or a complex combination of lines and curves \"\n\"representing one of the shapes of the previous section.\"\nmsgstr \"페이지 메서드 :meth:`Page.get_drawings()` 는 그리기 명령에 액세스하여 Python 딕셔너리 목록으로 변환합니다. 각 딕셔너리( \\\"path\\\" 라고 함)는 별도의 그리기를 나타냅니다. 단일 선과 같이 간단할 수도 있고, 이전 섹션의 모양 중 하나를 나타내는 선과 곡선의 복잡한 조합일 수도 있습니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:105 3a7f618513034c8e9ef3833145ea41c1\nmsgid \"\"\n\"The *path* dictionary has been designed such that it can easily be used \"\n\"by the :ref:`Shape` class and its methods. Here is an example for a page \"\n\"with one path, that draws a red-bordered yellow circle inside rectangle \"\n\"`Rect(100, 100, 200, 200)`::\"\nmsgstr \"*path* 딕셔너리는 :ref:`Shape` 클래스와 그 메서드에서 쉽게 사용할 수 있도록 설계되었습니다. 다음은 하나의 경로를 가진 페이지의 예로, `Rect(100, 100, 200, 200)` 내부에 빨간색 테두리의 노란색 원을 그립니다::\"\n\n#: ../../recipes-drawing-and-graphics.rst:140 0de0ff2bcd1b4aa4bc87691ca4f375c5\nmsgid \"\"\n\"You need (at least) 4 Bézier curves (of 3rd order) to draw a circle with \"\n\"acceptable precision. See this `Wikipedia article \"\n\"<https://en.wikipedia.org/wiki/B%C3%A9zier_curve>`_ for some background.\"\nmsgstr \"허용 가능한 정밀도로 원을 그리려면 (최소한) 4개의 3차 베지어 곡선이 필요합니다. 배경 정보는 이 `Wikipedia article <https://en.wikipedia.org/wiki/B%C3%A9zier_curve>`_ 를 참조하세요.\"\n\n#: ../../recipes-drawing-and-graphics.rst:143 b621ef3cc79448109301a7679857a685\nmsgid \"\"\n\"The following is a code snippet which extracts the drawings of a page and\"\n\" re-draws them on a new page::\"\nmsgstr \"다음은 페이지의 그리기를 추출하여 새 페이지에 다시 그리는 코드 스니펫입니다::\"\n\n#: ../../recipes-drawing-and-graphics.rst:194 f4c89adbb0a8490d8e03b50a712dcc58\nmsgid \"\"\n\"As can be seen, there is a high congruence level with the :ref:`Shape` \"\n\"class. With one exception: For technical reasons `lineCap` is a tuple of \"\n\"3 numbers here, whereas it is an integer in :ref:`Shape` (and in PDF). So\"\n\" we simply take the maximum value of that tuple.\"\nmsgstr \"보시다시피, :ref:`Shape` 클래스와 높은 일치 수준이 있습니다. 한 가지 예외가 있습니다. 기술적 이유로 여기서는 `lineCap` 이 3개의 숫자 튜플이지만, :ref:`Shape` (및 PDF)에서는 정수입니다. 따라서 해당 튜플의 최대값을 사용합니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:196 782e233251fb459883d5a1434c5a2365\nmsgid \"\"\n\"Here is a comparison between input and output of an example page, created\"\n\" by the previous script:\"\nmsgstr \"다음은 이전 스크립트로 생성된 예제 페이지의 입력과 출력 비교입니다:\"\n\n#: ../../recipes-drawing-and-graphics.rst:201 ceca22c756464670adafb8f59a266f9f\nmsgid \"\"\n\"The reconstruction of graphics, like shown here, is not perfect. The \"\n\"following aspects will not be reproduced as of this version:\"\nmsgstr \"여기에 표시된 것과 같은 그래픽 재구성은 완벽하지 않습니다. 다음 측면은 이 버전에서 재현되지 않습니다:\"\n\n#: ../../recipes-drawing-and-graphics.rst:203 4859b04375644a9da37b4c2c286032e9\nmsgid \"\"\n\"Page definitions can be complex and include instructions for not showing \"\n\"/ hiding certain areas to keep them invisible. Things like this are \"\n\"ignored by :meth:`Page.get_drawings` - it will always return all paths.\"\nmsgstr \"페이지 정의는 복잡할 수 있으며 특정 영역을 보이지 않게 유지하기 위해 표시하지 않거나 숨기는 지시를 포함할 수 있습니다. 이러한 사항은 :meth:`Page.get_drawings` 에 의해 무시됩니다. 항상 모든 경로를 반환합니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:205 0823be3f9f0b4512b042dd4c974406ca\nmsgid \"\"\n\"You can use the path list to make your own lists of e.g. all lines or all\"\n\" rectangles on the page and subselect them by criteria, like color or \"\n\"position on the page etc.\"\nmsgstr \"경로 목록을 사용하여 예를 들어 페이지의 모든 선 또는 모든 사각형 목록을 만들고 색상이나 페이지의 위치 등의 기준으로 하위 선택할 수 있습니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:210 882f949ade2d4b528fbe0a18f15aa51e\nmsgid \"How to Delete Drawings\"\nmsgstr \"그리기 삭제 방법\"\n\n#: ../../recipes-drawing-and-graphics.rst:212 d9a69d70bb29499381afbb9347fa3ec5\nmsgid \"\"\n\"To delete drawings/vector graphics we must use a :ref:`Redaction \"\n\"Annotation <The_Basics_Redacting>` with the bounding box of the drawing \"\n\"and then **add and apply** a redaction to it to delete it.\"\nmsgstr \"그리기/벡터 그래픽을 삭제하려면 그리기의 경계 상자를 사용하여 :ref:`Redaction Annotation <The_Basics_Redacting>` 을 사용한 다음 **추가하고 적용** 하여 삭제해야 합니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:215 486d33c08c624da1ba4d3f8b61cf54e2\nmsgid \"\"\n\"The following code shows an example of deleting the first drawing found \"\n\"on the page::\"\nmsgstr \"다음 코드는 페이지에서 찾은 첫 번째 그리기를 삭제하는 예제를 보여줍니다::\"\n\n#: ../../recipes-drawing-and-graphics.rst:225 74954d428a74469bae0a628b09803ec9\nmsgid \"\"\n\"See :meth:`Page.apply_redactions` for the parameter options which can be \"\n\"sent - you are able to apply deletion options to image, drawing and text \"\n\"objects which are bound by the annotation area.\"\nmsgstr \"전송할 수 있는 매개변수 옵션은 :meth:`Page.apply_redactions` 를 참조하세요. 주석 영역에 의해 경계가 지정된 이미지, 그리기 및 텍스트 객체에 삭제 옵션을 적용할 수 있습니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:229 0e3b851a469b4f34b686a303776ff667\nmsgid \"How to Draw Graphics\"\nmsgstr \"그래픽 그리기 방법\"\n\n#: ../../recipes-drawing-and-graphics.rst:231 903bdff31610401eba4df3faa0747295\nmsgid \"\"\n\"Drawing graphics is as simple as calling the type of :meth:`Drawing \"\n\"Method <Page.draw_line>` you may want. You can draw graphics directly on \"\n\"pages or within shape objects.\"\nmsgstr \"그래픽을 그리는 것은 원하는 :meth:`Drawing Method <Page.draw_line>` 유형을 호출하는 것만큼 간단합니다. 페이지에 직접 또는 shape 객체 내에서 그래픽을 그릴 수 있습니다.\"\n\n#: ../../recipes-drawing-and-graphics.rst:234 c8c7da7541804af39da538bd86a48706\nmsgid \"For example, to draw a circle::\"\nmsgstr \"예를 들어, 원을 그리려면::\"\n\n#: ../../recipes-drawing-and-graphics.rst:245 a58742fee8a64d88a569cc24aa989eac\nmsgid \"\"\n\"The :ref:`Shape` object can be used to combine multiple drawings that \"\n\"should receive common properties as specified by :meth:`Shape.finish`.\"\nmsgstr \":ref:`Shape` 객체는 :meth:`Shape.finish` 에서 지정한 공통 속성을 받아야 하는 여러 그리기를 결합하는 데 사용할 수 있습니다.\"\n\n#: ../../footer.rst:46 b08a651f11954075811284b1a70b5a8c\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-images.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 a5170acfd12b43adbefd8dfbe853d226\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 cb2bde859c1349828bd247664168fdad\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 becd9c25862646c28f77d71822cc2c8b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../recipes-images.rst:7 4710064fae7342178423b005970103b5\nmsgid \"Images\"\nmsgstr \"Images\"\n\n#: ../../recipes-images.rst:14 4e4cf4f2971d49878a83873ab5b972f7\nmsgid \"How to Make Images from Document Pages\"\nmsgstr \"문서 페이지에서 이미지 만들기\"\n\n#: ../../recipes-images.rst:16 e9a6e38305b94ba1b80f9f8c8e22ffd0\nmsgid \"\"\n\"This little script will take a document filename and generate a PNG file \"\n\"from each of its pages.\"\nmsgstr \"이 작은 스크립트는 문서 파일 이름을 받아 각 페이지에서 PNG 파일을 생성합니다.\"\n\n#: ../../recipes-images.rst:18 308acb4260244cb889d8b5e5e696bc88\nmsgid \"The document can be any :ref:`supported type<Supported_File_Types>`.\"\nmsgstr \"문서는 :ref:`지원되는 모든 타입<Supported_File_Types>` 일 수 있습니다.\"\n\n#: ../../recipes-images.rst:20 a3082189c02c48da807760245885aa8a\nmsgid \"\"\n\"The script works as a command line tool which expects the filename being \"\n\"supplied as a parameter. The generated image files (1 per page) are \"\n\"stored in the directory of the script::\"\nmsgstr \"스크립트는 매개변수로 제공된 파일 이름을 기대하는 명령줄 도구로 작동합니다. 생성된 이미지 파일(페이지당 1개)은 스크립트 디렉토리에 저장됩니다::\"\n\n#: ../../recipes-images.rst:29 b7e5e6dd24f045f4a09c4f91b7d4fea8\nmsgid \"\"\n\"The script directory will now contain PNG image files named *page-0.png*,\"\n\" *page-1.png*, etc. Pictures have the dimension of their pages with width\"\n\" and height rounded to integers, e.g. 595 x 842 pixels for an A4 portrait\"\n\" sized page. They will have a resolution of 96 dpi in x and y dimension \"\n\"and have no transparency. You can change all that -- for how to do this, \"\n\"read the next sections.\"\nmsgstr \"스크립트 디렉토리에는 이제 *page-0.png*, *page-1.png* 등의 PNG 이미지 파일이 포함됩니다. 그림은 페이지의 크기를 가지며 너비와 높이는 정수로 반올림됩니다. 예를 들어 A4 세로 크기 페이지의 경우 595 x 842 픽셀입니다. x 및 y 차원에서 96 dpi의 해상도를 가지며 투명도가 없습니다. 모든 것을 변경할 수 있습니다 -- 방법은 다음 섹션을 참조하세요.\"\n\n#: ../../recipes-images.rst:37 a572d7ea36d948ea96eded0ff8001773\nmsgid \"How to Increase :index:`Image Resolution <pair: image; resolution>`\"\nmsgstr \":index:`이미지 해상도 <pair: image; resolution>` 높이는 방법\"\n\n#: ../../recipes-images.rst:39 11a284ffaf7742f6a03127e4d1240761\nmsgid \"\"\n\"The image of a document page is represented by a :ref:`Pixmap`, and the \"\n\"simplest way to create a pixmap is via method :meth:`Page.get_pixmap`.\"\nmsgstr \"문서 페이지의 이미지는 :ref:`Pixmap` 으로 표현되며, 픽스맵을 생성하는 가장 간단한 방법은 :meth:`Page.get_pixmap` 메서드를 사용하는 것입니다.\"\n\n#: ../../recipes-images.rst:41 feae2612c8c0499e90d765be25a00eac\nmsgid \"\"\n\"This method has many options to influence the result. The most important \"\n\"among them is the :ref:`Matrix`, which lets you :index:`zoom`, rotate, \"\n\"distort or mirror the outcome.\"\nmsgstr \"이 메서드는 결과에 영향을 주는 많은 옵션이 있습니다. 그 중 가장 중요한 것은 :index:`확대`, 회전, 왜곡 또는 미러링을 가능하게 하는 :ref:`Matrix` 입니다.\"\n\n#: ../../recipes-images.rst:43 b12ee8c226f44cbaaa494b318449f822\nmsgid \"\"\n\":meth:`Page.get_pixmap` by default will use the :ref:`Identity` matrix, \"\n\"which does nothing.\"\nmsgstr \":meth:`Page.get_pixmap` 은 기본적으로 아무것도 하지 않는 :ref:`Identity` 행렬을 사용합니다.\"\n\n#: ../../recipes-images.rst:45 1b9e0cde360b4b86b79e4a5560753ac9\nmsgid \"\"\n\"In the following, we apply a :index:`zoom factor <pair: resolution;zoom>`\"\n\" of 2 to each dimension, which will generate an image with a four times \"\n\"better resolution for us (and also about 4 times the size)::\"\nmsgstr \"다음에서는 각 차원에 :index:`확대 배율 <pair: resolution;zoom>` 2를 적용하여 4배 더 나은 해상도의 이미지를 생성합니다(크기도 약 4배)::\"\n\n#: ../../recipes-images.rst:53 4b841620223b468290813f2c76bf2f57\nmsgid \"\"\n\"Since version 1.19.2 there is a more direct way to set the resolution: \"\n\"Parameter `\\\"dpi\\\"` (dots per inch) can be used in place of `\\\"matrix\\\"`.\"\n\" To create a 300 dpi image of a page specify `pix = \"\n\"page.get_pixmap(dpi=300)`. Apart from notation brevity, this approach has\"\n\" the additional advantage that the **dpi value is saved with the image** \"\n\"file -- which does not happen automatically when using the Matrix \"\n\"notation.\"\nmsgstr \"\"\n\"버전 1.19.2부터 해상도를 설정하는 더 직접적인 방법이 있습니다: `\\\"dpi\\\"` (인치당 도트 수) 매개변수를 \"\n\"`\\\"matrix\\\"` 대신 사용할 수 있습니다. 페이지의 300 dpi 이미지를 만들려면 `pix = \"\n\"page.get_pixmap(dpi=300)` 을 지정하세요. 표기법의 간결함 외에도, 이 방법의 추가 장점은 **dpi 값이 이미지 \"\n\"파일과 함께 저장된다는** 것입니다 -- Matrix 표기법을 사용할 때는 자동으로 발생하지 않습니다.\"\n\n#: ../../recipes-images.rst:61 31bbb7951f74400fb93921872432755d\nmsgid \"How to Create :index:`Partial Pixmaps` (Clips)\"\nmsgstr \":index:`부분 픽스맵 <Partial Pixmaps>` (클립) 생성 방법\"\n\n#: ../../recipes-images.rst:62 fbadb2ef5dbd470f8a7e831854d224d8\nmsgid \"\"\n\"You do not always need or want the full image of a page. This is the case\"\n\" e.g. when you display the image in a GUI and would like to fill the \"\n\"respective window with a zoomed part of the page.\"\nmsgstr \"\"\n\"항상 페이지의 전체 이미지가 필요하거나 원하는 것은 아닙니다. 예를 들어 GUI에서 이미지를 표시하고 해당 창을 페이지의 확대된 부분으로 \"\n\"채우고 싶을 때가 그런 경우입니다.\"\n\n#: ../../recipes-images.rst:64 85f7bd7eb0b042c0813c26e94f741bf2\nmsgid \"\"\n\"Let's assume your GUI window has room to display a full document page, \"\n\"but you now want to fill this room with the bottom right quarter of your \"\n\"page, thus using a four times better resolution.\"\nmsgstr \"\"\n\"GUI 창에 전체 문서 페이지를 표시할 공간이 있다고 가정하지만, 이제 이 공간을 페이지의 오른쪽 아래 사분면으로 채워 4배 더 나은 \"\n\"해상도를 사용하고 싶다고 가정합니다.\"\n\n#: ../../recipes-images.rst:66 29dbb31ae3f94b88b955a6b089ae6df5\nmsgid \"\"\n\"To achieve this, define a rectangle equal to the area you want to appear \"\n\"in the GUI and call it \\\"clip\\\". One way of constructing rectangles in \"\n\"PyMuPDF is by providing two diagonally opposite corners, which is what we\"\n\" are doing here.\"\nmsgstr \"\"\n\"이를 달성하려면 GUI에 표시하려는 영역과 같은 사각형을 정의하고 \\\"clip\\\"이라고 부르세요. PyMuPDF에서 사각형을 구성하는 \"\n\"방법 중 하나는 대각선으로 반대편에 있는 두 모서리를 제공하는 것이며, 여기서도 그렇게 합니다.\"\n\n#: ../../recipes-images.rst:79 27b90a5d3a3c45eca6798eb33e10e442\nmsgid \"\"\n\"In the above we construct *clip* by specifying two diagonally opposite \"\n\"points: the middle point *mp* of the page rectangle, and its bottom \"\n\"right, *rect.br*.\"\nmsgstr \"\"\n\"위에서는 두 개의 대각선 반대편 점을 지정하여 *clip* 을 구성합니다: 페이지 사각형의 중간점 *mp* 와 그 오른쪽 아래 \"\n\"*rect.br* 입니다.\"\n\n#: ../../recipes-images.rst:87 bb7f676a34c54b28a8067fefa1aacd1b\nmsgid \"How to Zoom a Clip to a GUI Window\"\nmsgstr \"클립을 GUI 창에 맞게 확대하는 방법\"\n\n#: ../../recipes-images.rst:88 3c061aaed37648d081263d96cee3321a\nmsgid \"\"\n\"Please also read the previous section. This time we want to **compute the\"\n\" zoom factor** for a clip, such that its image best fits a given GUI \"\n\"window. This means, that the image's width or height (or both) will equal\"\n\" the window dimension. For the following code snippet you need to provide\"\n\" the WIDTH and HEIGHT of your GUI's window that should receive the page's\"\n\" clip rectangle.\"\nmsgstr \"\"\n\"이전 섹션도 읽어보세요. 이번에는 클립의 **확대 배율을 계산** 하여 이미지가 주어진 GUI 창에 가장 잘 맞도록 합니다. 즉, \"\n\"이미지의 너비 또는 높이(또는 둘 다)가 창 크기와 같아집니다. 다음 코드 스니펫을 위해서는 페이지의 클립 사각형을 받을 GUI \"\n\"창의 WIDTH와 HEIGHT를 제공해야 합니다.\"\n\n#: ../../recipes-images.rst:105 b3a9b91ee3804e7b8c64ed8a2205e309\nmsgid \"\"\n\"For the other way round, now assume you **have** the zoom factor and need\"\n\" to **compute the fitting clip**.\"\nmsgstr \"반대로, 이제 **확대 배율이 있고** **맞는 클립을 계산** 해야 한다고 가정합니다.\"\n\n#: ../../recipes-images.rst:107 8ecba4f1cc2d4ce6b5472a6b7d1f6778\nmsgid \"\"\n\"In this case we have `zoom = HEIGHT/clip.height = WIDTH/clip.width`, so \"\n\"we must set `clip.height = HEIGHT/zoom` and, `clip.width = WIDTH/zoom`. \"\n\"Choose the top-left point `tl` of the clip on the page to compute the \"\n\"right pixmap::\"\nmsgstr \"\"\n\"이 경우 `zoom = HEIGHT/clip.height = WIDTH/clip.width` 이므로, `clip.height = \"\n\"HEIGHT/zoom` 과 `clip.width = WIDTH/zoom` 을 설정해야 합니다. 올바른 픽스맵을 계산하려면 페이지에서 \"\n\"클립의 왼쪽 위 지점 `tl` 을 선택하세요::\"\n\n#: ../../recipes-images.rst:124 a9179194547c43379baf5fb667307041\nmsgid \"How to Create or Suppress Annotation Images\"\nmsgstr \"주석 이미지 생성 또는 억제 방법\"\n\n#: ../../recipes-images.rst:125 9cc92f685bcf4d2bafef5da546fbac00\nmsgid \"\"\n\"Normally, the pixmap of a page also shows the page's annotations. \"\n\"Occasionally, this may not be desirable.\"\nmsgstr \"일반적으로 페이지의 픽스맵은 페이지의 주석도 표시합니다. 때로는 이것이 바람직하지 않을 수 있습니다.\"\n\n#: ../../recipes-images.rst:127 1079c45bc5474873945edff781094f65\nmsgid \"\"\n\"To suppress the annotation images on a rendered page, just specify \"\n\"`annots=False` in :meth:`Page.get_pixmap`.\"\nmsgstr \"렌더링된 페이지에서 주석 이미지를 억제하려면 :meth:`Page.get_pixmap` 에서 `annots=False` 를 지정하세요.\"\n\n#: ../../recipes-images.rst:129 b141c29860864fde93d41fedac0919b0\nmsgid \"\"\n\"You can also render annotations separately: they have their own \"\n\":meth:`Annot.get_pixmap` method. The resulting pixmap has the same \"\n\"dimensions as the annotation rectangle.\"\nmsgstr \"\"\n\"주석을 별도로 렌더링할 수도 있습니다: 주석에는 자체 :meth:`Annot.get_pixmap` 메서드가 있습니다. 결과 픽스맵은 주석 \"\n\"사각형과 동일한 크기를 가집니다.\"\n\n#: ../../recipes-images.rst:141 5f7013ae1124470a83fa5df727f719d1\nmsgid \"How to Extract Images: Non-PDF Documents\"\nmsgstr \"이미지 추출 방법: 비 PDF 문서\"\n\n#: ../../recipes-images.rst:143 3b4b1649fadc41cea019b924cd517adc\nmsgid \"\"\n\"In contrast to the previous sections, this section deals with \"\n\"**extracting** images **contained** in documents, so they can be \"\n\"displayed as part of one or more pages.\"\nmsgstr \"\"\n\"이전 섹션과 달리, 이 섹션은 문서에 **포함된** 이미지를 **추출** 하는 것을 다루므로, 하나 이상의 페이지의 일부로 표시할 수 \"\n\"있습니다.\"\n\n#: ../../recipes-images.rst:145 cd906454fde6400783d50eb0297c5b39\nmsgid \"\"\n\"If you want to recreate the original image in file form or as a memory \"\n\"area, you have basically two options:\"\nmsgstr \"원본 이미지를 파일 형식 또는 메모리 영역으로 재생성하려면 기본적으로 두 가지 옵션이 있습니다:\"\n\n#: ../../recipes-images.rst:147 dda6ef39b73f40f8b4b566ccb3d6011e\nmsgid \"\"\n\"Convert your document to a PDF, and then use one of the PDF-only \"\n\"extraction methods. This snippet will convert a document to PDF::\"\nmsgstr \"문서를 PDF로 변환한 다음 PDF 전용 추출 방법 중 하나를 사용하세요. 이 스니펫은 문서를 PDF로 변환합니다::\"\n\n#: ../../recipes-images.rst:153 d9d2f8dd08d6424f8418f2300c013bcd\nmsgid \"\"\n\"Use :meth:`Page.get_text` with the \\\"dict\\\" parameter. This works for all\"\n\" document types. It will extract all text and images shown on the page, \"\n\"formatted as a Python dictionary. Every image will occur in an image \"\n\"block, containing meta information and **the binary image data**. For \"\n\"details of the dictionary's structure, see :ref:`TextPage`. The method \"\n\"works equally well for PDF files. This creates a list of all images shown\"\n\" on a page::\"\nmsgstr \"\"\n\"\\\"dict\\\" 매개변수와 함께 :meth:`Page.get_text` 를 사용하세요. 이것은 모든 문서 유형에 작동합니다. 페이지에 표시된 \"\n\"모든 텍스트와 이미지를 Python 딕셔너리 형식으로 추출합니다. 각 이미지는 메타 정보와 **바이너리 이미지 데이터** 를 포함하는 이미지 \"\n\"블록에 나타납니다. 딕셔너리 구조의 세부 사항은 :ref:`TextPage` 를 참조하세요. 이 방법은 PDF 파일에도 동일하게 \"\n\"작동합니다. 이것은 페이지에 표시된 모든 이미지의 목록을 생성합니다::\"\n\n#: ../../recipes-images.rst:182 44ce44e54f6a4d52b8fa3e4377314037\nmsgid \"How to Extract Images: PDF Documents\"\nmsgstr \"이미지 추출 방법: PDF 문서\"\n\n#: ../../recipes-images.rst:184 121c432a4e1b4f0da9d62f1686089fe3\nmsgid \"\"\n\"Like any other \\\"object\\\" in a PDF, images are identified by a cross \"\n\"reference number (:data:`xref`, an integer). If you know this number, you\"\n\" have two ways to access the image's data:\"\nmsgstr \"\"\n\"PDF의 다른 \\\"객체\\\"와 마찬가지로, 이미지는 교차 참조 번호(:data:`xref`, 정수)로 식별됩니다. 이 번호를 알고 있으면 \"\n\"이미지 데이터에 액세스하는 두 가지 방법이 있습니다:\"\n\n#: ../../recipes-images.rst:186 65a8bdab9a754e05bb94c1a31c2dc6c3\nmsgid \"\"\n\"**Create** a :ref:`Pixmap` of the image with instruction *pix = \"\n\"pymupdf.Pixmap(doc, xref)*. This method is **very** fast (single digit \"\n\"micro-seconds). The pixmap's properties (width, height, ...) will reflect\"\n\" the ones of the image. In this case there is no way to tell which image \"\n\"format the embedded original has.\"\nmsgstr \"\"\n\"*pix = pymupdf.Pixmap(doc, xref)* 지시로 이미지의 :ref:`Pixmap` 을 **생성** 합니다. 이 방법은 \"\n\"**매우** 빠릅니다(한 자리 마이크로초). 픽스맵의 속성(너비, 높이 등)은 이미지의 속성을 반영합니다. 이 경우 임베드된 원본의 \"\n\"이미지 형식을 알 수 있는 방법이 없습니다.\"\n\n#: ../../recipes-images.rst:188 1270aa02e2f747a8a27ef8e3820b2c51\nmsgid \"\"\n\"**Extract** the image with *img = doc.extract_image(xref)*. This is a \"\n\"dictionary containing the binary image data as *img[\\\"image\\\"]*. A number\"\n\" of meta data are also provided -- mostly the same as you would find in \"\n\"the pixmap of the image. The major difference is string *img[\\\"ext\\\"]*, \"\n\"which specifies the image format: apart from \\\"png\\\", strings like \"\n\"\\\"jpeg\\\", \\\"bmp\\\", \\\"tiff\\\", etc. can also occur. Use this string as the \"\n\"file extension if you want to store to disk. The execution speed of this \"\n\"method should be compared to the combined speed of the statements *pix = \"\n\"pymupdf.Pixmap(doc, xref);pix.tobytes()*. If the embedded image is in PNG\"\n\" format, the speed of :meth:`Document.extract_image` is about the same \"\n\"(and the binary image data are identical). Otherwise, this method is \"\n\"**thousands of times faster**, and the **image data is much smaller**.\"\nmsgstr \"\"\n\"*img = doc.extract_image(xref)* 로 이미지를 **추출** 합니다. 이것은 *img[\\\"image\\\"]* 로 바이너리 \"\n\"이미지 데이터를 포함하는 딕셔너리입니다. 많은 메타데이터도 제공됩니다 -- 대부분 이미지의 픽스맵에서 찾을 수 있는 것과 동일합니다. \"\n\"주요 차이점은 이미지 형식을 지정하는 문자열 *img[\\\"ext\\\"]* 입니다: \\\"png\\\" 외에도 \\\"jpeg\\\", \"\n\"\\\"bmp\\\", \\\"tiff\\\" 등의 문자열이 나타날 수 있습니다. 디스크에 저장하려면 이 문자열을 파일 확장자로 사용하세요. 이 \"\n\"방법의 실행 속도는 *pix = pymupdf.Pixmap(doc, xref);pix.tobytes()* 문의 결합 속도와 비교해야 합니다. \"\n\"임베드된 이미지가 PNG 형식인 경우, :meth:`Document.extract_image` 의 속도는 거의 동일합니다(바이너리 이미지 \"\n\"데이터도 동일). 그렇지 않으면 이 방법이 **수천 배 더 빠르고**, **이미지 데이터가 훨씬 작습니다**.\"\n\n#: ../../recipes-images.rst:190 c7235a839397415b88cc200813afa335\nmsgid \"\"\n\"The question remains: **\\\"How do I know those 'xref' numbers of \"\n\"images?\\\"**. There are two answers to this:\"\nmsgstr \"질문은 남아 있습니다: **\\\"이미지의 'xref' 번호를 어떻게 알 수 있나요?\\\"**. 이에 대한 두 가지 답변이 있습니다:\"\n\n#: ../../recipes-images.rst:192 24b9f0cac5e8493794473b40e99d6fff\nmsgid \"\"\n\"**\\\"Inspect the page objects:\\\"** Loop through the items of \"\n\":meth:`Page.get_images`. It is a list of list, and its items look like \"\n\"*[xref, smask, ...]*, containing the :data:`xref` of an image. This \"\n\":data:`xref` can then be used with one of the above methods. Use this \"\n\"method for **valid (undamaged)** documents. Be wary however, that the \"\n\"same image may be referenced multiple times (by different pages), so you \"\n\"might want to provide a mechanism avoiding multiple extracts.\"\nmsgstr \"\"\n\"**\\\"페이지 객체 검사:\\\"** :meth:`Page.get_images` 의 항목을 반복합니다. 이것은 리스트의 리스트이며, 항목은 \"\n\"*[xref, smask, ...]* 와 같이 보이며 이미지의 :data:`xref` 를 포함합니다. 그런 다음 이 :data:`xref` \"\n\"를 위의 방법 중 하나와 함께 사용할 수 있습니다. **유효한(손상되지 않은)** 문서에 이 방법을 사용하세요. 그러나 동일한 이미지가 \"\n\"여러 번 참조될 수 있으므로(다른 페이지에서) 여러 번 추출을 피하는 메커니즘을 제공하는 것이 좋습니다.\"\n\n#: ../../recipes-images.rst:193 90acb0b07ce44df5809cc83032fab4d6\nmsgid \"\"\n\"**\\\"No need to know:\\\"** Loop through the list of **all xrefs** of the \"\n\"document and perform a :meth:`Document.extract_image` for each one. If \"\n\"the returned dictionary is empty, then continue -- this :data:`xref` is \"\n\"no image. Use this method if the PDF is **damaged (unusable pages)**. \"\n\"Note that a PDF often contains \\\"pseudo-images\\\" (\\\"stencil masks\\\") with\"\n\" the special purpose of defining the transparency of some other image. \"\n\"You may want to provide logic to exclude those from extraction. Also have\"\n\" a look at the next section.\"\nmsgstr \"\"\n\"**\\\"알 필요 없음:\\\"** 문서의 **모든 xref** 목록을 반복하고 각각에 대해 :meth:`Document.extract_image` \"\n\"를 수행합니다. 반환된 딕셔너리가 비어 있으면 계속합니다 -- 이 :data:`xref` 는 이미지가 아닙니다. PDF가 **손상된(사용 \"\n\"불가능한 페이지)** 경우 이 방법을 사용하세요. PDF에는 종종 다른 이미지의 투명도를 정의하는 특수 목적의 \\\"의사 이미지\\\"(\\\"스텐실 \"\n\"마스크\\\")가 포함되어 있습니다. 추출에서 이를 제외하는 로직을 제공하는 것이 좋습니다. 다음 섹션도 살펴보세요.\"\n\n#: ../../recipes-images.rst:195 12c15b841d0c40e5bf38fd3252a5c82f\nmsgid \"\"\n\"For both extraction approaches, there exist ready-to-use general purpose \"\n\"scripts:\"\nmsgstr \"두 추출 방법 모두에 대해 즉시 사용 가능한 범용 스크립트가 있습니다:\"\n\n#: ../../recipes-images.rst:197 ae5e3ffd1ec342fdbedcedbd9585539f\nmsgid \"\"\n\"`extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_ \"\n\"extracts images page by page:\"\nmsgstr \"\"\n\"`extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-\"\n\"images/extract-from-pages.py>`_ 는 페이지별로 이미지를 추출합니다:\"\n\n#: ../../recipes-images.rst:202 116fc9d92a524d5fbef97898d73400ef\nmsgid \"\"\n\"and `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_ \"\n\"extracts images by xref table:\"\nmsgstr \"\"\n\"그리고 `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-\"\n\"images/extract-from-xref.py>`_ 는 xref 테이블로 이미지를 추출합니다:\"\n\n#: ../../recipes-images.rst:213 27941620eff34254b2f1df365e86c504\nmsgid \"How to Handle Image Masks\"\nmsgstr \"이미지 마스크 처리 방법\"\n\n#: ../../recipes-images.rst:214 06e8942247e04ca18cbb0a2e166e63e0\nmsgid \"\"\n\"Some images in PDFs are accompanied by **image masks**. In their simplest\"\n\" form, masks represent alpha (transparency) bytes stored as separate \"\n\"images. In order to reconstruct the original of an image, which has a \"\n\"mask, it must be \\\"enriched\\\" with transparency bytes taken from its \"\n\"mask.\"\nmsgstr \"\"\n\"PDF의 일부 이미지에는 **이미지 마스크** 가 함께 제공됩니다. 가장 간단한 형태에서 마스크는 별도의 이미지로 저장된 알파(투명도) \"\n\"바이트를 나타냅니다. 마스크가 있는 이미지의 원본을 재구성하려면 마스크에서 가져온 투명도 바이트로 \\\"보강\\\"해야 합니다.\"\n\n#: ../../recipes-images.rst:216 6956e284f58a455894dad036a8d732f4\nmsgid \"\"\n\"Whether an image does have such a mask can be recognized in one of two \"\n\"ways in PyMuPDF:\"\nmsgstr \"이미지에 그러한 마스크가 있는지는 PyMuPDF에서 두 가지 방법 중 하나로 인식할 수 있습니다:\"\n\n#: ../../recipes-images.rst:218 8f7b0eb999094613b1ec4e9642a0c45a\nmsgid \"\"\n\"An item of :meth:`Document.get_page_images` has the general format \"\n\"`(xref, smask, ...)`, where :data:`xref` is the image's :data:`xref` and \"\n\"*smask*, if positive, then it is the :data:`xref` of a mask.\"\nmsgstr \"\"\n\":meth:`Document.get_page_images` 의 항목은 일반 형식 `(xref, smask, ...)` 을 가지며, 여기서 \"\n\":data:`xref` 는 이미지의 :data:`xref` 이고 *smask* 가 양수이면 마스크의 :data:`xref` 입니다.\"\n\n#: ../../recipes-images.rst:219 76639fa3068e459eb26f660440a3b239\nmsgid \"\"\n\"The (dictionary) results of :meth:`Document.extract_image` have a key \"\n\"*\\\"smask\\\"*, which also contains any mask's :data:`xref` if positive.\"\nmsgstr \"\"\n\":meth:`Document.extract_image` 의 (딕셔너리) 결과에는 *\\\"smask\\\"* 키가 있으며, 양수이면 마스크의 \"\n\":data:`xref` 도 포함합니다.\"\n\n#: ../../recipes-images.rst:221 46e1113696e24d6ba6ff91a314912958\nmsgid \"\"\n\"If *smask == 0* then the image encountered via :data:`xref` can be \"\n\"processed as it is.\"\nmsgstr \"*smask == 0* 이면 :data:`xref` 를 통해 발견된 이미지는 그대로 처리할 수 있습니다.\"\n\n#: ../../recipes-images.rst:223 65ebef4703d447a9b3116690abc567cd\nmsgid \"\"\n\"To recover the original image using PyMuPDF, the procedure depicted as \"\n\"follows must be executed:\"\nmsgstr \"PyMuPDF를 사용하여 원본 이미지를 복구하려면 다음에 설명된 절차를 실행해야 합니다:\"\n\n#: ../../recipes-images.rst:232 6a6811e1d3974ca493ec08e4a67eca0f\nmsgid \"\"\n\"Step (1) creates a pixmap of the basic image. Step (2) does the same with\"\n\" the image mask. Step (3) adds an alpha channel and fills it with \"\n\"transparency information.\"\nmsgstr \"\"\n\"단계 (1)은 기본 이미지의 픽스맵을 생성합니다. 단계 (2)는 이미지 마스크에 대해 동일한 작업을 수행합니다. 단계 (3)는 알파 \"\n\"채널을 추가하고 투명도 정보로 채웁니다.\"\n\n#: ../../recipes-images.rst:234 0f019370007b48829a5c384c1d511b38\nmsgid \"\"\n\"The scripts `extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_, \"\n\"and `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_ \"\n\"above also contain this logic.\"\nmsgstr \"\"\n\"위의 `extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-\"\n\"images/extract-from-pages.py>`_ 및 `extract-from-xref.py \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-\"\n\"xref.py>`_ 스크립트에도 이 로직이 포함되어 있습니다.\"\n\n#: ../../recipes-images.rst:250 e6cc7c95f595417399c8af124895022f\nmsgid \"How to Make one PDF of all your Pictures (or Files)\"\nmsgstr \"모든 사진(또는 파일)을 하나의 PDF로 만드는 방법\"\n\n#: ../../recipes-images.rst:251 0e5cc72aa12e4c159cee3caf5b124a72\nmsgid \"\"\n\"We show here **three scripts** that take a list of (image and other) \"\n\"files and put them all in one PDF.\"\nmsgstr \"여기서는 (이미지 및 기타) 파일 목록을 받아 모두 하나의 PDF에 넣는 **세 가지 스크립트** 를 보여줍니다.\"\n\n#: ../../recipes-images.rst:253 23141b711e854c0fb09b4da836e870c4\nmsgid \"**Method 1: Inserting Images as Pages**\"\nmsgstr \"**방법 1: 이미지를 페이지로 삽입**\"\n\n#: ../../recipes-images.rst:255 6b5ea11f2ac6474da5bc139a540e80fc\nmsgid \"\"\n\"The first one converts each image to a PDF page with the same dimensions.\"\n\" The result will be a PDF with one page per image. It will only work for \"\n\":ref:`supported image<Supported_File_Types>` file formats::\"\nmsgstr \"\"\n\"첫 번째는 각 이미지를 동일한 크기의 PDF 페이지로 변환합니다. 결과는 이미지당 한 페이지의 PDF가 됩니다. \"\n\":ref:`지원되는 이미지<Supported_File_Types>` 파일 형식에서만 작동합니다::\"\n\n#: ../../recipes-images.rst:278 5d5f4b70e6ad473b98f0b67b8dd864ee\nmsgid \"\"\n\"This will generate a PDF only marginally larger than the combined \"\n\"pictures' size. Some numbers on performance:\"\nmsgstr \"이것은 결합된 그림 크기보다 약간만 큰 PDF를 생성합니다. 성능에 대한 일부 수치:\"\n\n#: ../../recipes-images.rst:280 c29ed63a41334d08bd31d57a51745ab1\nmsgid \"\"\n\"The above script needed about 1 minute on my machine for 149 pictures \"\n\"with a total size of 514 MB (and about the same resulting PDF size).\"\nmsgstr \"위 스크립트는 총 크기가 514 MB인 149개의 그림에 대해 내 컴퓨터에서 약 1분이 걸렸습니다(결과 PDF 크기도 거의 동일).\"\n\n#: ../../recipes-images.rst:285 90edd65fe7324ee6a8c2c256f5dad5b3\nmsgid \"\"\n\"Look `here <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/insert-images/insert.py>`_ for a more \"\n\"complete source code: it offers a directory selection dialog and skips \"\n\"unsupported files and non-file entries.\"\nmsgstr \"\"\n\"더 완전한 소스 코드는 `여기 <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/insert-\"\n\"images/insert.py>`_ 를 참조하세요: 디렉토리 선택 대화 상자를 제공하고 지원되지 않는 파일과 비파일 항목을 건너뜁니다.\"\n\n#: ../../recipes-images.rst:287 66dd4d051e7b4d12816c624eee514c5e\nmsgid \"\"\n\"We might have used :meth:`Page.insert_image` instead of \"\n\":meth:`Page.show_pdf_page`, and the result would have been a similar \"\n\"looking file. However, depending on the image type, it may store **images\"\n\" uncompressed**. Therefore, the save option *deflate = True* must be used\"\n\" to achieve a reasonable file size, which hugely increases the runtime \"\n\"for large numbers of images. So this alternative **cannot be \"\n\"recommended** here.\"\nmsgstr \"\"\n\":meth:`Page.show_pdf_page` 대신 :meth:`Page.insert_image` 를 사용했을 수도 있으며, 결과는 비슷해 보이는 \"\n\"파일이었을 것입니다. 그러나 이미지 유형에 따라 **이미지를 압축하지 않고** 저장할 수 있습니다. 따라서 합리적인 파일 크기를 \"\n\"달성하려면 저장 옵션 *deflate = True* 를 사용해야 하며, 이는 많은 수의 이미지에 대해 실행 시간을 크게 증가시킵니다. \"\n\"따라서 이 대안은 여기서 **권장할 수 없습니다**.\"\n\n#: ../../recipes-images.rst:289 31ee78dae4e846c59e2bd4c8213760da\nmsgid \"**Method 2: Embedding Files**\"\nmsgstr \"**방법 2: 파일 임베드**\"\n\n#: ../../recipes-images.rst:291 d485e0eb28084b90a6b28a8ee7cef448\nmsgid \"\"\n\"The second script **embeds** arbitrary files -- not only images. The \"\n\"resulting PDF will have just one (empty) page, required for technical \"\n\"reasons. To later access the embedded files again, you would need a \"\n\"suitable PDF viewer that can display and / or extract embedded files::\"\nmsgstr \"\"\n\"두 번째 스크립트는 이미지뿐만 아니라 임의의 파일을 **임베드** 합니다. 결과 PDF는 기술적 이유로 하나의(빈) 페이지만 있습니다. \"\n\"나중에 임베드된 파일에 다시 액세스하려면 임베드된 파일을 표시하고/또는 추출할 수 있는 적절한 PDF 뷰어가 필요합니다::\"\n\n#: ../../recipes-images.rst:316 c94ada8bd9e04598aaf5ab16502b491d\nmsgid \"\"\n\"This is by far the fastest method, and it also produces the smallest \"\n\"possible output file size. The above pictures needed 20 seconds on my \"\n\"machine and yielded a PDF size of 510 MB. Look `here \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/embed-\"\n\"images/embed.py>`_ for a more complete source code: it offers a directory\"\n\" selection dialog and skips non-file entries.\"\nmsgstr \"\"\n\"이것은 지금까지 가장 빠른 방법이며 가능한 가장 작은 출력 파일 크기도 생성합니다. 위의 그림은 내 컴퓨터에서 20초가 걸렸고 \"\n\"510 MB 크기의 PDF를 생성했습니다. 더 완전한 소스 코드는 `여기 \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/embed-images/embed.py>`_ \"\n\"를 참조하세요: 디렉토리 선택 대화 상자를 제공하고 비파일 항목을 건너뜁니다.\"\n\n#: ../../recipes-images.rst:318 9d6d6606772743a0b3d7948c5256f795\nmsgid \"**Method 3: Attaching Files**\"\nmsgstr \"**방법 3: 파일 첨부**\"\n\n#: ../../recipes-images.rst:320 bcaa4036cb074aa2975925493b912887\nmsgid \"\"\n\"A third way to achieve this task is **attaching files** via page \"\n\"annotations see `here <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/attach-images/attach.py>`_ for the \"\n\"complete source code.\"\nmsgstr \"\"\n\"이 작업을 달성하는 세 번째 방법은 페이지 주석을 통해 파일을 **첨부** 하는 것입니다. 전체 소스 코드는 `여기 \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/attach-images/attach.py>`_ \"\n\"를 참조하세요.\"\n\n#: ../../recipes-images.rst:322 436939e68a27496f95bf3ba627243f13\nmsgid \"\"\n\"This has a similar performance as the previous script and it also \"\n\"produces a similar file size. It will produce PDF pages which show a \"\n\"'FileAttachment' icon for each attached file.\"\nmsgstr \"\"\n\"이것은 이전 스크립트와 유사한 성능을 가지며 유사한 파일 크기도 생성합니다. 각 첨부 파일에 대해 'FileAttachment' 아이콘을 \"\n\"표시하는 PDF 페이지를 생성합니다.\"\n\n#: ../../recipes-images.rst:326 9ea52a5b17d243b5867452d1793d07b7\nmsgid \"\"\n\"Both, the **embed** and the **attach** methods can be used for \"\n\"**arbitrary files** -- not just images.\"\nmsgstr \"**임베드** 와 **첨부** 방법 모두 이미지뿐만 아니라 **임의의 파일** 에 사용할 수 있습니다.\"\n\n#: ../../recipes-images.rst:328 034f2966cc014086a05a35dc70520940\nmsgid \"\"\n\"We strongly recommend using the awesome package `PySimpleGUI \"\n\"<https://pypi.org/project/PySimpleGUI/>`_ to display a progress meter for\"\n\" tasks that may run for an extended time span. It's pure Python, uses \"\n\"Tkinter (no additional GUI package) and requires just one more line of \"\n\"code!\"\nmsgstr \"\"\n\"장시간 실행될 수 있는 작업에 대해 진행 표시기를 표시하려면 `PySimpleGUI \"\n\"<https://pypi.org/project/PySimpleGUI/>`_ 패키지 사용을 강력히 권장합니다. 순수 Python이며 \"\n\"Tkinter를 사용합니다(추가 GUI 패키지 없음) 그리고 코드 한 줄만 더 필요합니다!\"\n\n#: ../../recipes-images.rst:342 f8cabd46ec6d45f09659866a69d91b45\nmsgid \"How to Create Vector Images\"\nmsgstr \"벡터 이미지 생성 방법\"\n\n#: ../../recipes-images.rst:343 f469c239c3464680bb9794d9b17a101b\nmsgid \"\"\n\"The usual way to create an image from a document page is \"\n\":meth:`Page.get_pixmap`. A pixmap represents a raster image, so you must \"\n\"decide on its quality (i.e. resolution) at creation time. It cannot be \"\n\"changed later.\"\nmsgstr \"\"\n\"문서 페이지에서 이미지를 만드는 일반적인 방법은 :meth:`Page.get_pixmap` 입니다. 픽스맵은 래스터 이미지를 나타내므로 \"\n\"생성 시 품질(즉, 해상도)을 결정해야 합니다. 나중에 변경할 수 없습니다.\"\n\n#: ../../recipes-images.rst:345 39ff1890e34045f0bdaebaf77376c7a6\nmsgid \"\"\n\"PyMuPDF also offers a way to create a **vector image** of a page in SVG \"\n\"format (scalable vector graphics, defined in XML syntax). SVG images \"\n\"remain precise across zooming levels (of course with the exception of any\"\n\" raster graphic elements embedded therein).\"\nmsgstr \"\"\n\"PyMuPDF는 또한 SVG 형식(확장 가능한 벡터 그래픽, XML 구문으로 정의됨)으로 페이지의 **벡터 이미지** 를 만드는 방법을 \"\n\"제공합니다. SVG 이미지는 확대/축소 수준에서 정확성을 유지합니다(물론 그 안에 임베드된 래스터 그래픽 요소는 제외).\"\n\n#: ../../recipes-images.rst:347 9f178ef03b574e8297104f71a80c68ea\nmsgid \"\"\n\"Instruction *svg = page.get_svg_image(matrix=pymupdf.Identity)* delivers \"\n\"a UTF-8 string *svg* which can be stored with extension \\\".svg\\\".\"\nmsgstr \"\"\n\"지시 *svg = page.get_svg_image(matrix=pymupdf.Identity)* 는 확장자 \\\".svg\\\" 로 저장할 수 있는 \"\n\"UTF-8 문자열 *svg* 를 제공합니다.\"\n\n#: ../../recipes-images.rst:363 b15d36501a88442697fbeeba5b5bb55f\nmsgid \"How to Convert Images\"\nmsgstr \"이미지 변환 방법\"\n\n#: ../../recipes-images.rst:364 9c9044f3d0894de0812ab73694a00aca\nmsgid \"\"\n\"Just as a feature among others, PyMuPDF's image conversion is easy. It \"\n\"may avoid using other graphics packages like PIL/Pillow in many cases.\"\nmsgstr \"\"\n\"다른 기능과 마찬가지로 PyMuPDF의 이미지 변환은 쉽습니다. 많은 경우 PIL/Pillow와 같은 다른 그래픽 패키지를 사용하지 \"\n\"않아도 될 수 있습니다.\"\n\n#: ../../recipes-images.rst:366 f0648a404f50475e9fbc97705bcf53d2\nmsgid \"Notwithstanding that interfacing with Pillow is almost trivial.\"\nmsgstr \"그럼에도 불구하고 Pillow와의 인터페이싱은 거의 사소합니다.\"\n\n#: ../../recipes-images.rst:369 51147cdb2eb848a59946a784bc3f94a1\nmsgid \"**Input Formats**\"\nmsgstr \"**입력 형식**\"\n\n#: ../../recipes-images.rst:369 6e77d3be370148e2a5bce129911da566\nmsgid \"**Output Formats**\"\nmsgstr \"**출력 형식**\"\n\n#: ../../recipes-images.rst:369 cf281244182e4d06a258fbbb823081c2\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../recipes-images.rst:371 530dd206bde5448eb1361b263e3af56b\nmsgid \"BMP\"\nmsgstr \"BMP\"\n\n#: ../../recipes-images.rst:371 ../../recipes-images.rst:373\n#: ../../recipes-images.rst:374 ../../recipes-images.rst:375\n#: ../../recipes-images.rst:376 ../../recipes-images.rst:383\n#: ../../recipes-images.rst:384 0a22e6da6c0e4628bcba466b598c7755\n#: 132ea5283e9446b6bef2088214506462 309ee5eed19245778c6c15a0523ba0ec\n#: 5ee5770cfadd46c0bc090de19200296e 7002bf7646f84d808f1d5f5e672b0559\n#: a37b99d8b7f547ee9f63392896f7e2d7 c69685da95a6452a83e40f26243b207b\nmsgid \".\"\nmsgstr \"\"\n\n#: ../../recipes-images.rst:371 e8fc53116fb14428812ab304c72fcdaf\nmsgid \"Windows Bitmap\"\nmsgstr \"Windows Bitmap\"\n\n#: ../../recipes-images.rst:372 03735a46d7ff47c291751487299a3f1e\n#: 17c492d6f34d4470b1aa86f58b11ca2e\nmsgid \"JPEG\"\nmsgstr \"JPEG\"\n\n#: ../../recipes-images.rst:372 7d1770830b8a487f8c91ea91bd6474eb\nmsgid \"Joint Photographic Experts Group\"\nmsgstr \"Joint Photographic Experts Group\"\n\n#: ../../recipes-images.rst:373 23fe9f08f0c74644b077b0cf444d3358\nmsgid \"JXR\"\nmsgstr \"JXR\"\n\n#: ../../recipes-images.rst:373 f548e4952b8b416689c5ce6bc9f95f33\nmsgid \"JPEG Extended Range\"\nmsgstr \"JPEG Extended Range\"\n\n#: ../../recipes-images.rst:374 684a27b7d2874c2b87911e269b40f2d0\nmsgid \"JPX/JP2\"\nmsgstr \"JPX/JP2\"\n\n#: ../../recipes-images.rst:374 14493ac2be944a018bff6dbd8ae2bac5\nmsgid \"JPEG 2000\"\nmsgstr \"JPEG 2000\"\n\n#: ../../recipes-images.rst:375 7e15ddbcb0ae4375b206202c12d586c7\nmsgid \"GIF\"\nmsgstr \"GIF\"\n\n#: ../../recipes-images.rst:375 9978971d8ce4454d86b805ab8d47cfa9\nmsgid \"Graphics Interchange Format\"\nmsgstr \"Graphics Interchange Format\"\n\n#: ../../recipes-images.rst:376 13363ae60931495a837cbc8baf5970fc\nmsgid \"TIFF\"\nmsgstr \"TIFF\"\n\n#: ../../recipes-images.rst:376 10d71cf9bb9e453cb0dcdea2659abd95\nmsgid \"Tagged Image File Format\"\nmsgstr \"Tagged Image File Format\"\n\n#: ../../recipes-images.rst:377 05f4cb19c0a34596814f731af32ea876\n#: 7931ab4e2d304558895b4c7ce5c29979\nmsgid \"PNG\"\nmsgstr \"PNG\"\n\n#: ../../recipes-images.rst:377 62b451811d4e476c8ae5dd6d849a54a4\nmsgid \"Portable Network Graphics\"\nmsgstr \"Portable Network Graphics\"\n\n#: ../../recipes-images.rst:378 c1d7da490b554e84a7204e6c99fe37ef\n#: f730284031c54916ac361e6304056bcb\nmsgid \"PNM\"\nmsgstr \"PNM\"\n\n#: ../../recipes-images.rst:378 561bb44f8a6f4ec6a424777a37eef460\nmsgid \"Portable Anymap\"\nmsgstr \"Portable Anymap\"\n\n#: ../../recipes-images.rst:379 3eb2b8341ba14a0ca14b367fb547e28d\n#: 57b7760ff7804df8b3a3d1bad69d6b15\nmsgid \"PGM\"\nmsgstr \"PGM\"\n\n#: ../../recipes-images.rst:379 21eeb4db595f461792110aec2d8ecea9\nmsgid \"Portable Graymap\"\nmsgstr \"Portable Graymap\"\n\n#: ../../recipes-images.rst:380 13aa92582d5d4474abf412bdfe3d0c28\n#: 4c893f1c9fcb4388a360d103c115f4ee\nmsgid \"PBM\"\nmsgstr \"PBM\"\n\n#: ../../recipes-images.rst:380 30f2520397de4b9eb325877a3a507bbf\nmsgid \"Portable Bitmap\"\nmsgstr \"Portable Bitmap\"\n\n#: ../../recipes-images.rst:381 14f81272a872402b9c2a813dcdf1adbd\n#: 958c5a3c6c9f445f8782e01f89dc6eb2\nmsgid \"PPM\"\nmsgstr \"PPM\"\n\n#: ../../recipes-images.rst:381 b047b29cb5924074b6edcc64ac2f21d4\nmsgid \"Portable Pixmap\"\nmsgstr \"Portable Pixmap\"\n\n#: ../../recipes-images.rst:382 8b7545df28fe4e84a4f6e5b4eaa96994\n#: b4a70161776d47b9ae8a64cdf4733492\nmsgid \"PAM\"\nmsgstr \"PAM\"\n\n#: ../../recipes-images.rst:382 99b6482f875c4216be23cd14e3b55579\nmsgid \"Portable Arbitrary Map\"\nmsgstr \"Portable Arbitrary Map\"\n\n#: ../../recipes-images.rst:383 a5f2249d2d1d484f87fad69069bc2941\nmsgid \"PSD\"\nmsgstr \"PSD\"\n\n#: ../../recipes-images.rst:383 5aa71e0042e440b8a2ae7d1232ae1da7\nmsgid \"Adobe Photoshop Document\"\nmsgstr \"Adobe Photoshop Document\"\n\n#: ../../recipes-images.rst:384 9f13c58a08324e2a9a956e0c7481fdb6\nmsgid \"PS\"\nmsgstr \"PS\"\n\n#: ../../recipes-images.rst:384 f7d3f16fd29d4f2e873705fa491cdaab\nmsgid \"Adobe Postscript\"\nmsgstr \"Adobe Postscript\"\n\n#: ../../recipes-images.rst:387 47aac2499f2743ea83430c735ea35f6d\nmsgid \"The general scheme is just the following two lines::\"\nmsgstr \"일반적인 방식은 다음 두 줄입니다::\"\n\n#: ../../recipes-images.rst:392 b7f3421a215d4d909a51a70302130d37\nmsgid \"**Remarks**\"\nmsgstr \"**비고**\"\n\n#: ../../recipes-images.rst:394 7a47fbda67ec43d7914f6405319663fa\nmsgid \"\"\n\"The **input** argument of *pymupdf.Pixmap(arg)* can be a file or a bytes \"\n\"/ io.BytesIO object containing an image.\"\nmsgstr \"*pymupdf.Pixmap(arg)* 의 **입력** 인수는 이미지를 포함하는 파일 또는 bytes / io.BytesIO 객체일 수 있습니다.\"\n\n#: ../../recipes-images.rst:395 58b740eb05e34db9a556c68fe43e7b90\nmsgid \"\"\n\"Instead of an output **file**, you can also create a bytes object via \"\n\"*pix.tobytes(\\\"yyy\\\")* and pass this around.\"\nmsgstr \"출력 **파일** 대신 *pix.tobytes(\\\"yyy\\\")* 를 통해 bytes 객체를 생성하고 이를 전달할 수도 있습니다.\"\n\n#: ../../recipes-images.rst:396 c3b285b2e78146219bd78577d12d121a\nmsgid \"\"\n\"As a matter of course, input and output formats must be compatible in \"\n\"terms of colorspace and transparency. The ``Pixmap`` class has batteries \"\n\"included if adjustments are needed.\"\nmsgstr \"\"\n\"당연히 입력 및 출력 형식은 색 공간 및 투명도 측면에서 호환되어야 합니다. ``Pixmap`` 클래스는 조정이 필요한 경우 내장 기능을 \"\n\"포함하고 있습니다.\"\n\n#: ../../recipes-images.rst:399 e67f10d9438447479868be73be60c969\nmsgid \"**Convert JPEG to Photoshop**::\"\nmsgstr \"**JPEG를 Photoshop으로 변환**::\"\n\n#: ../../recipes-images.rst:405 69af5be5c5e042739b6b881440591067\nmsgid \"\"\n\"Convert **JPEG to Tkinter PhotoImage**. Any **RGB / no-alpha** image \"\n\"works exactly the same. Conversion to one of the **Portable Anymap** \"\n\"formats (PPM, PGM, etc.) does the trick, because they are supported by \"\n\"all Tkinter versions::\"\nmsgstr \"\"\n\"**JPEG를 Tkinter PhotoImage로 변환** 합니다. 모든 **RGB / 알파 없음** 이미지도 정확히 동일하게 작동합니다. \"\n\"**Portable Anymap** 형식(PPM, PGM 등) 중 하나로 변환하면 효과가 있습니다. 모든 Tkinter 버전에서 지원되기 \"\n\"때문입니다::\"\n\n#: ../../recipes-images.rst:412 95cfd29f810e445da70d90c145d8615a\nmsgid \"\"\n\"Convert **PNG with alpha** to Tkinter PhotoImage. This requires \"\n\"**removing the alpha bytes**, before we can do the PPM conversion::\"\nmsgstr \"\"\n\"**알파가 있는 PNG** 를 Tkinter PhotoImage로 변환합니다. PPM 변환을 수행하기 전에 **알파 바이트를 제거** 해야 \"\n\"합니다::\"\n\n#: ../../recipes-images.rst:429 1911e5e8b8924c1a8b4f22e5163ab54f\nmsgid \"How to Use Pixmaps: Gluing Images\"\nmsgstr \"픽스맵 사용 방법: 이미지 붙이기\"\n\n#: ../../recipes-images.rst:431 7bec2fa27c4e409498516974d3af1a08\nmsgid \"\"\n\"This shows how pixmaps can be used for purely graphical, non-document \"\n\"purposes. The script reads an image file and creates a new image which \"\n\"consist of 3 * 4 tiles of the original::\"\nmsgstr \"\"\n\"이것은 픽스맵이 순수하게 그래픽적이고 문서가 아닌 목적으로 사용될 수 있는 방법을 보여줍니다. 스크립트는 이미지 파일을 읽고 원본의 \"\n\"3 * 4 타일로 구성된 새 이미지를 생성합니다::\"\n\n#: ../../recipes-images.rst:451 5e629a692db5492494234aeaa2c9e000\nmsgid \"This is the input picture:\"\nmsgstr \"이것이 입력 그림입니다:\"\n\n#: ../../recipes-images.rst:456 0eb66869c4e049f18880e64efa606cb7\nmsgid \"Here is the output:\"\nmsgstr \"출력은 다음과 같습니다:\"\n\n#: ../../recipes-images.rst:473 193131d4ef064104aca816c9fb1b8eda\nmsgid \"How to Use Pixmaps: Making a Fractal\"\nmsgstr \"픽스맵 사용 방법: 프랙탈 만들기\"\n\n#: ../../recipes-images.rst:475 94c73f5e5e844ef29a6937bacf69e134\nmsgid \"\"\n\"Here is another Pixmap example that creates **Sierpinski's Carpet** -- a \"\n\"fractal generalizing the **Cantor Set** to two dimensions. Given a square\"\n\" carpet, mark its 9 sub-suqares (3 times 3) and cut out the one in the \"\n\"center. Treat each of the remaining eight sub-squares in the same way, \"\n\"and continue *ad infinitum*. The end result is a set with area zero and \"\n\"fractal dimension 1.8928...\"\nmsgstr \"\"\n\"다음은 **시에르핀스키 카펫** 을 생성하는 또 다른 픽스맵 예제입니다 -- **칸토어 집합** 을 2차원으로 일반화한 프랙탈입니다. 정사각형 \"\n\"카펫이 주어지면 9개의 하위 사각형(3 x 3)을 표시하고 중앙의 것을 잘라냅니다. 나머지 8개의 하위 사각형 각각에 대해 동일한 \"\n\"방식으로 처리하고 *무한히* 계속합니다. 최종 결과는 면적이 0이고 프랙탈 차원이 1.8928...인 집합입니다.\"\n\n#: ../../recipes-images.rst:477 56abcac9cb974ce6ae22fd649ca0859f\nmsgid \"\"\n\"This script creates an approximate image of it as a PNG, by going down to\"\n\" one-pixel granularity. To increase the image precision, change the value\"\n\" of n (precision)::\"\nmsgstr \"\"\n\"이 스크립트는 1픽셀 단위까지 내려가서 PNG로 근사 이미지를 생성합니다. 이미지 정밀도를 높이려면 n(정밀도) 값을 변경하세요::\"\n\n#: ../../recipes-images.rst:531 c2a2453f8f7b4dbdb1a88b9ab6e6be44\nmsgid \"The result should look something like this:\"\nmsgstr \"결과는 다음과 같아야 합니다:\"\n\n#: ../../recipes-images.rst:541 7b65b42e069e44c4acda5058a222b54c\nmsgid \"How to Interface with NumPy\"\nmsgstr \"NumPy와 인터페이스하는 방법\"\n\n#: ../../recipes-images.rst:543 4737dca0e38f4d0391a1712b9196eeb8\nmsgid \"\"\n\"This shows how to create a PNG file from a numpy array (several times \"\n\"faster than most other methods)::\"\nmsgstr \"이것은 numpy 배열에서 PNG 파일을 만드는 방법을 보여줍니다(대부분의 다른 방법보다 몇 배 빠름)::\"\n\n#: ../../recipes-images.rst:570 86677e790d2c4f67807e8699c758c3b8\nmsgid \"How to Add Images to a PDF Page\"\nmsgstr \"PDF 페이지에 이미지 추가 방법\"\n\n#: ../../recipes-images.rst:572 8b806d59869144378fcd5066d1490f5c\nmsgid \"\"\n\"There are two methods to add images to a PDF page: \"\n\":meth:`Page.insert_image` and :meth:`Page.show_pdf_page`. Both methods \"\n\"have things in common, but there are also differences.\"\nmsgstr \"\"\n\"PDF 페이지에 이미지를 추가하는 두 가지 방법이 있습니다: :meth:`Page.insert_image` 와 \"\n\":meth:`Page.show_pdf_page`. 두 방법 모두 공통점이 있지만 차이점도 있습니다.\"\n\n#: ../../recipes-images.rst:575 2c8c48d1aa0b4d95ba46f51b58d654d6\nmsgid \"**Criterion**\"\nmsgstr \"**기준**\"\n\n#: ../../recipes-images.rst:575 7d8993132b2b4a42a0cf8d794f2992d0\nmsgid \":meth:`Page.insert_image`\"\nmsgstr \":meth:`Page.insert_image`\"\n\n#: ../../recipes-images.rst:575 8a3e9ca045d64f2e8d891f008fec70a3\nmsgid \":meth:`Page.show_pdf_page`\"\nmsgstr \":meth:`Page.show_pdf_page`\"\n\n#: ../../recipes-images.rst:577 5bd36cce5edc4839bb92e31c9c76b006\nmsgid \"displayable content\"\nmsgstr \"표시 가능한 콘텐츠\"\n\n#: ../../recipes-images.rst:577 6abadbc464324e72b3412212af08ddd5\nmsgid \"image file, image in memory, pixmap\"\nmsgstr \"이미지 파일, 메모리의 이미지, 픽스맵\"\n\n#: ../../recipes-images.rst:577 fe5a852c20eb446f96ab83f04f7f4a93\nmsgid \"PDF page\"\nmsgstr \"PDF 페이지\"\n\n#: ../../recipes-images.rst:578 204fbfd1f4dd47b9b874c7093d251715\nmsgid \"display resolution\"\nmsgstr \"표시 해상도\"\n\n#: ../../recipes-images.rst:578 6877443fc21f4ae29b20fa83d0845e7f\nmsgid \"image resolution\"\nmsgstr \"이미지 해상도\"\n\n#: ../../recipes-images.rst:578 3259783ac12241b39f8d13f3ae0773d6\nmsgid \"vectorized (except raster page content)\"\nmsgstr \"벡터화됨(래스터 페이지 콘텐츠 제외)\"\n\n#: ../../recipes-images.rst:579 0a170d4e27b74f7ba12e8e015f247437\nmsgid \"rotation\"\nmsgstr \"회전\"\n\n#: ../../recipes-images.rst:579 809287424df744108ab05380b655171e\nmsgid \"0, 90, 180 or 270 degrees\"\nmsgstr \"0, 90, 180 또는 270도\"\n\n#: ../../recipes-images.rst:579 da8c599cd42840bbac1e77a82693730a\nmsgid \"any angle\"\nmsgstr \"임의의 각도\"\n\n#: ../../recipes-images.rst:580 f40e820c9fb14438ae80fc9bde7f8a98\nmsgid \"clipping\"\nmsgstr \"클리핑\"\n\n#: ../../recipes-images.rst:580 4573b228aad144ed96c21fc96b46d235\nmsgid \"no (full image only)\"\nmsgstr \"아니오(전체 이미지만)\"\n\n#: ../../recipes-images.rst:580 ../../recipes-images.rst:585\n#: 451bef807fb34d769267984ed465f6dc cca26d0a49b6435a81557dc0961b5744\nmsgid \"yes\"\nmsgstr \"예\"\n\n#: ../../recipes-images.rst:581 cfbb20540a0b4c778339a005d689e7b8\nmsgid \"keep aspect ratio\"\nmsgstr \"종횡비 유지\"\n\n#: ../../recipes-images.rst:581 9088023618154cb2b1a12c0ddf19f1a2\n#: f0b3417bf2a7468f8f23939745c86e02\nmsgid \"yes (default option)\"\nmsgstr \"예(기본 옵션)\"\n\n#: ../../recipes-images.rst:582 5f19b1705d7c458d9132e003453cbec7\nmsgid \"transparency (water marking)\"\nmsgstr \"투명도(워터마킹)\"\n\n#: ../../recipes-images.rst:582 99fc40d08cd448d4a3d5157524c2fed1\nmsgid \"depends on the image\"\nmsgstr \"이미지에 따라 다름\"\n\n#: ../../recipes-images.rst:582 4953bd2dbe474a6a95444caaec0f8e00\nmsgid \"depends on the page\"\nmsgstr \"페이지에 따라 다름\"\n\n#: ../../recipes-images.rst:583 800220a1afe84937ab054dd04a19a8c8\nmsgid \"location / placement\"\nmsgstr \"위치 / 배치\"\n\n#: ../../recipes-images.rst:583 3d7142d3e8b844178ad964a906047c57\n#: 6f79b41a8b7f44d0b808c73f0bca9bbf\nmsgid \"scaled to fit target rectangle\"\nmsgstr \"대상 사각형에 맞게 크기 조정\"\n\n#: ../../recipes-images.rst:584 bcd9bfd74c0e4791b173eea29559bf7c\nmsgid \"performance\"\nmsgstr \"성능\"\n\n#: ../../recipes-images.rst:584 709fb304b9de44d69140fb3994966d0b\n#: aa53a4c8c09a4cfba0e8f1a66a28bb65\nmsgid \"automatic prevention of duplicates;\"\nmsgstr \"중복 자동 방지;\"\n\n#: ../../recipes-images.rst:585 0937b39761af40238a7534454037df7f\nmsgid \"multi-page image support\"\nmsgstr \"다중 페이지 이미지 지원\"\n\n#: ../../recipes-images.rst:585 14f432eb978947a8aeab98f966d2d10f\nmsgid \"no\"\nmsgstr \"아니오\"\n\n#: ../../recipes-images.rst:586 925c5122b94f48c5b30dceafcb918523\nmsgid \"ease of use\"\nmsgstr \"사용 편의성\"\n\n#: ../../recipes-images.rst:586 570bc160fd964dfd90f9efc5d183be86\nmsgid \"simple, intuitive;\"\nmsgstr \"간단하고 직관적;\"\n\n#: ../../recipes-images.rst:586 7cf88dffae244d2ab3bda778f8a61657\nmsgid \"\"\n\"simple, intuitive; **usable for all document types** (including images!) \"\n\"after conversion to PDF via :meth:`Document.convert_to_pdf`\"\nmsgstr \"\"\n\"간단하고 직관적; :meth:`Document.convert_to_pdf` 를 통해 PDF로 변환 후 **모든 문서 유형** (이미지 포함!)에 \"\n\"사용 가능\"\n\n#: ../../recipes-images.rst:592 6ad1ea7eaa8f47249a3a73f2bd375d6e\nmsgid \"\"\n\"Basic code pattern for :meth:`Page.insert_image`. **Exactly one** of the \"\n\"parameters **filename / stream / pixmap** must be given, if not re-\"\n\"inserting an existing image::\"\nmsgstr \"\"\n\":meth:`Page.insert_image` 의 기본 코드 패턴. 기존 이미지를 다시 삽입하지 않는 경우 **filename / stream / \"\n\"pixmap** 매개변수 중 **정확히 하나** 를 제공해야 합니다::\"\n\n#: ../../recipes-images.rst:607 324876f64fbe4c44ab53d2a63fa13939\nmsgid \"\"\n\"Basic code pattern for :meth:`Page.show_pdf_page`. Source and target PDF \"\n\"must be different :ref:`Document` objects (but may be opened from the \"\n\"same file)::\"\nmsgstr \"\"\n\":meth:`Page.show_pdf_page` 의 기본 코드 패턴. 소스 및 대상 PDF는 서로 다른 :ref:`Document` 객체여야 \"\n\"합니다(같은 파일에서 열 수 있음)::\"\n\n#: ../../recipes-images.rst:623 3fb681b8dd954d6191b33bb9379c5769\nmsgid \"How to Use Pixmaps: Checking Text Visibility\"\nmsgstr \"픽스맵 사용 방법: 텍스트 가시성 확인\"\n\n#: ../../recipes-images.rst:625 f6738eb5b3944be59ab375f9b7eb965f\nmsgid \"\"\n\"Whether or not a given piece of text is actually visible on a page \"\n\"depends on a number of factors:\"\nmsgstr \"주어진 텍스트가 페이지에서 실제로 보이는지는 여러 요인에 따라 다릅니다:\"\n\n#: ../../recipes-images.rst:627 1e747fae38a041ceab9962bed078d738\nmsgid \"\"\n\"Text is not covered by another object but may have the same color as the \"\n\"background i.e., white-on-white etc.\"\nmsgstr \"텍스트가 다른 객체에 의해 덮이지 않았지만 배경과 같은 색상일 수 있습니다. 예: 흰색 위의 흰색 등.\"\n\n#: ../../recipes-images.rst:628 f335376e08db4247a18b81df59e129c8\nmsgid \"\"\n\"Text may be covered by an image or vector graphics. Detecting this is an \"\n\"important capability, for example to uncover badly anonymized legal \"\n\"documents.\"\nmsgstr \"\"\n\"텍스트가 이미지나 벡터 그래픽에 의해 덮일 수 있습니다. 이를 감지하는 것은 중요한 기능입니다. 예를 들어 잘못 익명화된 법률 문서를 \"\n\"발견하는 데 사용됩니다.\"\n\n#: ../../recipes-images.rst:629 c13633a208484210b9ae568ec9ba0f68\nmsgid \"\"\n\"Text is created hidden. This technique is usually used by OCR tools to \"\n\"store the recognized text in an invisible layer on the page.\"\nmsgstr \"\"\n\"텍스트가 숨겨진 상태로 생성됩니다. 이 기술은 일반적으로 OCR 도구가 인식된 텍스트를 페이지의 보이지 않는 레이어에 저장하는 데 \"\n\"사용됩니다.\"\n\n#: ../../recipes-images.rst:631 15e4b37ca4e743d9ace6bbddf7721b12\nmsgid \"\"\n\"The following shows how to detect situation 1. above, or situation 2. if \"\n\"the covering object is unicolor::\"\nmsgstr \"\"\n\"다음은 위의 상황 1을 감지하는 방법 또는 덮는 객체가 단색인 경우 상황 2를 감지하는 방법을 보여줍니다::\"\n\n#: ../../recipes-images.rst:645 83c1b504293642219a2e1c7034fa13ef\nmsgid \"\"\n\"Method :meth:`Pixmap.color_topusage` returns a tuple `(ratio, pixel)` \"\n\"where 0 < ratio <= 1 and *pixel* is the pixel value of the color. Please \"\n\"note that we create a **pixmap only once**. This can save a lot of \"\n\"processing time if there are multiple hit rectangles.\"\nmsgstr \"\"\n\":meth:`Pixmap.color_topusage` 메서드는 `(ratio, pixel)` 튜플을 반환합니다. 여기서 0 < ratio <= \"\n\"1이고 *pixel* 은 색상의 픽셀 값입니다. **픽스맵을 한 번만 생성** 합니다. 여러 히트 사각형이 있는 경우 처리 시간을 많이 \"\n\"절약할 수 있습니다.\"\n\n#: ../../recipes-images.rst:647 a5240ef02f1b474ca0cc0911c89fca25\nmsgid \"\"\n\"The logic of the above code is: If the needle's rectangle is (\\\"almost\\\":\"\n\" > 95%) unicolor, then the text cannot be visible. A typical result for \"\n\"visible text returns the color of the background (mostly white) and a \"\n\"ratio around 0.7 to 0.8, for example `(0.685, b'\\\\xff\\\\xff\\\\xff')`.\"\nmsgstr \"\"\n\"위 코드의 로직은 다음과 같습니다: 바늘이 가리키는 사각형이 (\\\"거의\\\": > 95%) 단색이면 텍스트가 보일 수 없습니다. \"\n\"보이는 텍스트의 일반적인 결과는 배경 색상(대부분 흰색)과 약 0.7~0.8의 비율을 반환합니다. 예: `(0.685, \"\n\"b'\\\\xff\\\\xff\\\\xff')`.\"\n\n#: ../../footer.rst:46 069c8258eace4a40a1b85ff062eeb067\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-journalling.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 25048fda51ce418c9d015f1246e746af\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 797ac5efa9e24c438fafe7f71ce832da\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 753e44f114514b2e927f9c1cf789d18c\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../recipes-journalling.rst:7 b01dda5af224433398494559bf0ada58\nmsgid \"Journalling\"\nmsgstr \"저널링\"\n\n#: ../../recipes-journalling.rst:10 f1543a90864a42ea86fe641d52d33bea\nmsgid \"\"\n\"Starting with version 1.19.0, journalling is possible when updating PDF \"\n\"documents.\"\nmsgstr \"버전 1.19.0부터 PDF 문서를 업데이트할 때 저널링이 가능합니다.\"\n\n#: ../../recipes-journalling.rst:12 1456c9ef805443c79a0bd76d2471b773\nmsgid \"\"\n\"Journalling is a logging mechanism which permits either **reverting** or \"\n\"**re-applying** changes to a PDF. Similar to LUWs \\\"Logical Units of \"\n\"Work\\\" in modern database systems, one can group a set of updates into an\"\n\" \\\"operation\\\". In MuPDF journalling, an operation plays the role of a \"\n\"LUW.\"\nmsgstr \"저널링은 PDF에 대한 변경 사항을 **되돌리거나** **다시 적용** 할 수 있게 하는 로깅 메커니즘입니다. 현대 데이터베이스 시스템의 LUW \\\"Logical Units of Work\\\"와 유사하게, 일련의 업데이트를 \\\"작업\\\"으로 그룹화할 수 있습니다. |MuPDF| 저널링에서 작업은 LUW의 역할을 합니다.\"\n\n#: ../../recipes-journalling.rst:14 aa605819004a494da8700c4dbb499ca3\nmsgid \"\"\n\"In contrast to LUW implementations found in database systems, MuPDF \"\n\"journalling happens on a **per document level**. There is no support for \"\n\"simultaneous updates across multiple PDFs: one would have to establish \"\n\"one's own logic here.\"\nmsgstr \"데이터베이스 시스템의 LUW 구현과 달리, |MuPDF| 저널링은 **문서별 수준** 에서 발생합니다. 여러 PDF에 걸친 동시 업데이트는 지원되지 않습니다. 여기서는 자체 로직을 구축해야 합니다.\"\n\n#: ../../recipes-journalling.rst:16 cabd8aa10cf746e6b10fc9fd0a9d7182\nmsgid \"\"\n\"Journalling must be *enabled* via a document method. Journalling is \"\n\"possible for existing or new documents. Journalling **can be disabled \"\n\"only** by closing the file.\"\nmsgstr \"저널링은 문서 메서드를 통해 *활성화* 해야 합니다. 기존 문서나 새 문서 모두에서 저널링이 가능합니다. 저널링은 파일을 닫는 경우에만 **비활성화** 할 수 있습니다.\"\n\n#: ../../recipes-journalling.rst:17 1090ca7dc7904871b61188430e85d1a1\nmsgid \"\"\n\"Once enabled, every change must happen inside an *operation* -- otherwise\"\n\" an exception is raised. An operation is started and stopped via document\"\n\" methods. Updates happening between these two calls form an LUW and can \"\n\"thus collectively be rolled back or re-applied, or, in MuPDF terminology \"\n\"\\\"undone\\\" resp. \\\"redone\\\".\"\nmsgstr \"활성화되면 모든 변경은 *작업* 내에서 발생해야 합니다. 그렇지 않으면 예외가 발생합니다. 작업은 문서 메서드를 통해 시작되고 중지됩니다. 이 두 호출 사이에 발생하는 업데이트는 LUW를 형성하므로 집합적으로 롤백하거나 다시 적용할 수 있으며, |MuPDF| 용어로는 각각 \\\"실행 취소\\\" 및 \\\"다시 실행\\\"입니다.\"\n\n#: ../../recipes-journalling.rst:18 c31321fa1fc14929871630087cdd8b8b\nmsgid \"\"\n\"At any point, the journalling status can be queried: whether journalling \"\n\"is active, how many operations have been recorded, whether \\\"undo\\\" or \"\n\"\\\"redo\\\" is possible, the current position inside the journal, etc.\"\nmsgstr \"언제든지 저널링 상태를 쿼리할 수 있습니다: 저널링이 활성화되어 있는지, 몇 개의 작업이 기록되었는지, \\\"실행 취소\\\" 또는 \\\"다시 실행\\\"이 가능한지, 저널 내 현재 위치 등입니다.\"\n\n#: ../../recipes-journalling.rst:19 5748ec5bd69741daaecd28651e5b67b8\nmsgid \"\"\n\"The journal can be **saved to** or **loaded from** a file. These are \"\n\"document methods.\"\nmsgstr \"저널은 파일에 **저장** 하거나 파일에서 **로드** 할 수 있습니다. 이것들은 문서 메서드입니다.\"\n\n#: ../../recipes-journalling.rst:20 2a1ee018fa1144fba3f9e32e294bcd4e\nmsgid \"\"\n\"When loading a journal file, compatibility with the document is checked \"\n\"and journalling is automatically enabled upon success.\"\nmsgstr \"저널 파일을 로드할 때 문서와의 호환성이 확인되며, 성공 시 저널링이 자동으로 활성화됩니다.\"\n\n#: ../../recipes-journalling.rst:21 359a67deba6d45c7b2870adfc40b92b5\nmsgid \"\"\n\"For an **existing** PDF being journalled, a special new save method is \"\n\"available: :meth:`Document.save_snapshot`. This performs a special \"\n\"incremental save that includes all journalled updates so far. If its \"\n\"journal is saved at the same time (immediately after the document \"\n\"snapshot), then document and journal are in sync and can later on be used\"\n\" together to undo or redo operations or to continue journalled updates --\"\n\" just as if there had been no interruption.\"\nmsgstr \"저널링 중인 **기존** PDF의 경우 특별한 새 저장 메서드인 :meth:`Document.save_snapshot` 를 사용할 수 있습니다. 이것은 지금까지의 모든 저널링된 업데이트를 포함하는 특별한 증분 저장을 수행합니다. 저널이 동시에 저장되면(문서 스냅샷 직후) 문서와 저널이 동기화되어 나중에 작업을 실행 취소하거나 다시 실행하거나 저널링된 업데이트를 계속하는 데 함께 사용할 수 있습니다. 마치 중단이 없었던 것처럼.\"\n\n#: ../../recipes-journalling.rst:22 2371ef9364394ab18af8172ee2fbd84c\nmsgid \"\"\n\"The snapshot PDF is a valid PDF in every aspect and fully usable. If the \"\n\"document is however changed in any way without using its journal file, \"\n\"then a desynchronization will take place and the journal is rendered \"\n\"unusable.\"\nmsgstr \"스냅샷 PDF는 모든 측면에서 유효한 PDF이며 완전히 사용 가능합니다. 하지만 저널 파일을 사용하지 않고 문서가 어떤 방식으로든 변경되면 동기화가 해제되고 저널이 사용 불가능해집니다.\"\n\n#: ../../recipes-journalling.rst:23 88b4f9365d4e41919901f2e3341b68b3\nmsgid \"\"\n\"Snapshot files are structured like incremental updates. Nevertheless, the\"\n\" internal journalling logic requires, that saving **must happen to a new \"\n\"file**. So the user should develop a file naming convention to support \"\n\"recognizable relationships between an original PDF, like `original.pdf` \"\n\"and its snapshot sets, like `original-snap1.pdf` / `original-snap1.log`, \"\n\"`original-snap2.pdf` / `original-snap2.log`, etc.\"\nmsgstr \"스냅샷 파일은 증분 업데이트처럼 구조화됩니다. 그럼에도 불구하고 내부 저널링 로직은 저장이 **새 파일에** 발생해야 합니다. 따라서 사용자는 원본 PDF(예: `original.pdf`)와 스냅샷 세트(예: `original-snap1.pdf` / `original-snap1.log`, `original-snap2.pdf` / `original-snap2.log` 등) 간의 인식 가능한 관계를 지원하는 파일 명명 규칙을 개발해야 합니다.\"\n\n#: ../../recipes-journalling.rst:26 86cb216c0b2c49ad82e67e5dcd1dad33\nmsgid \"Example Session 1\"\nmsgstr \"예제 세션 1\"\n\n#: ../../recipes-journalling.rst:27 ../../recipes-journalling.rst:98\n#: 623199d65f524b49925fac870071c962 e45525e109c54fde88b07c36ca5ae547\nmsgid \"Description:\"\nmsgstr \"설명:\"\n\n#: ../../recipes-journalling.rst:29 64be3df2712342b6b3a07eb934808271\nmsgid \"\"\n\"Make a new PDF and enable journalling. Then add a page and some text \"\n\"lines -- each as a separate operation.\"\nmsgstr \"새 PDF를 만들고 저널링을 활성화합니다. 그런 다음 페이지와 일부 텍스트 줄을 추가합니다. 각각을 별도의 작업으로 수행합니다.\"\n\n#: ../../recipes-journalling.rst:30 f87700abdc524bcf98d294a44fcb2e9d\nmsgid \"\"\n\"Navigate within the journal, undoing and redoing these updates and \"\n\"displaying status and file results::\"\nmsgstr \"저널 내에서 이동하며 이러한 업데이트를 실행 취소하고 다시 실행하며 상태와 파일 결과를 표시합니다::\"\n\n#: ../../recipes-journalling.rst:97 f540b437628341a68f1d143da3561958\nmsgid \"Example Session 2\"\nmsgstr \"예제 세션 2\"\n\n#: ../../recipes-journalling.rst:100 e49f0638f47e40cfa88e8a2e5c342dc4\nmsgid \"\"\n\"Similar to previous, but after undoing some operations, we now add a \"\n\"different update. This will cause:\"\nmsgstr \"이전과 유사하지만 일부 작업을 실행 취소한 후 다른 업데이트를 추가합니다. 이것은 다음을 유발합니다:\"\n\n#: ../../recipes-journalling.rst:102 aeb2a12789f44076a21e14f5e8edbdf0\nmsgid \"permanent removal of the undone journal entries\"\nmsgstr \"실행 취소된 저널 항목의 영구 제거\"\n\n#: ../../recipes-journalling.rst:103 039d45dbbda9472596a7e3eab31cb2f1\nmsgid \"the new update operation will become the new last entry.\"\nmsgstr \"새 업데이트 작업이 새로운 마지막 항목이 됩니다.\"\n\n#: ../../footer.rst:46 5ed33c2c15454dd7b2014d897f80427a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-low-level-interfaces.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 75434c61000b4a94a1404a3d68f178d3\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 ddfdaa7abef4454c84dd019f11c20c87\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 903f0a7765df4517bf839cf576bb4cd7\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../recipes-low-level-interfaces.rst:7 876f381a92644748ae6580657c5d6371\nmsgid \"Low-Level Interfaces\"\nmsgstr \"저수준 인터페이스\"\n\n#: ../../recipes-low-level-interfaces.rst:10 56a6762686bb479a903f22b76be1b5e4\nmsgid \"\"\n\"Numerous methods are available to access and manipulate PDF files on a \"\n\"fairly low level. Admittedly, a clear distinction between \\\"low level\\\" \"\n\"and \\\"normal\\\" functionality is not always possible or subject to \"\n\"personal taste.\"\nmsgstr \"PDF 파일에 상당히 낮은 수준으로 액세스하고 조작할 수 있는 많은 메서드가 있습니다. 인정하건대, \\\"낮은 수준\\\"과 \\\"일반\\\" 기능 간의 명확한 구분이 항상 가능한 것은 아니며 개인 취향에 따라 다를 수 있습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:12 509bc82d522c4d62bd7cf935e205a083\nmsgid \"\"\n\"It also may happen, that functionality previously deemed low-level is \"\n\"later on assessed as being part of the normal interface. This has \"\n\"happened in v1.14.0 for the class :ref:`Tools` - you now find it as an \"\n\"item in the Classes chapter.\"\nmsgstr \"이전에 낮은 수준으로 간주되었던 기능이 나중에 일반 인터페이스의 일부로 평가될 수도 있습니다. 이것은 v1.14.0에서 :ref:`Tools` 클래스에 대해 발생했습니다 -- 이제 Classes 장에서 항목으로 찾을 수 있습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:14 20061f0fd15a4e39ad5408b30f02ea0d\nmsgid \"\"\n\"It is a matter of documentation only in which chapter of the \"\n\"documentation you find what you are looking for. Everything is available \"\n\"and always via the same interface.\"\nmsgstr \"문서의 어느 장에서 찾고 있는 것을 찾을 수 있는지는 문서화의 문제일 뿐입니다. 모든 것이 사용 가능하며 항상 동일한 인터페이스를 통해 제공됩니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:19 3d2eebf5f47c48afb777b5e1cbe85fa9\nmsgid \"How to Iterate through the :data:`xref` Table\"\nmsgstr \":data:`xref` 테이블을 반복하는 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:20 c9233e278f7a44a5b599e88a0848f67a\nmsgid \"\"\n\"A PDF's :data:`xref` table is a list of all objects defined in the file. \"\n\"This table may easily contain many thousands of entries -- the manual \"\n\":ref:`AdobeManual` for example has 127,000 objects. Table entry \\\"0\\\" is \"\n\"reserved and must not be touched. The following script loops through the \"\n\":data:`xref` table and prints each object's definition::\"\nmsgstr \"PDF의 :data:`xref` 테이블은 파일에 정의된 모든 객체의 목록입니다. 이 테이블은 수천 개의 항목을 쉽게 포함할 수 있습니다 -- 예를 들어 :ref:`AdobeManual` 에는 127,000개의 객체가 있습니다. 테이블 항목 \\\"0\\\"은 예약되어 있으며 건드리면 안 됩니다. 다음 스크립트는 :data:`xref` 테이블을 반복하고 각 객체의 정의를 인쇄합니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:32 b93c9745639841dabd4c68c0cc52e782\nmsgid \"This produces the following output::\"\nmsgstr \"이것은 다음 출력을 생성합니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:72 d3c70e3964ee4a28b58534c83ad26bbc\nmsgid \"A PDF object definition is an ordinary ASCII string.\"\nmsgstr \"PDF 객체 정의는 일반 ASCII 문자열입니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:77 493207cb244546a59a72c418fd16281c\nmsgid \"How to Handle Object Streams\"\nmsgstr \"객체 스트림 처리 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:78 e736d6692a344e6280ec68ba8aa262da\nmsgid \"\"\n\"Some object types contain additional data apart from their object \"\n\"definition. Examples are images, fonts, embedded files or commands \"\n\"describing the appearance of a page.\"\nmsgstr \"일부 객체 유형은 객체 정의 외에 추가 데이터를 포함합니다. 예로는 이미지, 글꼴, 임베디드 파일 또는 페이지 모양을 설명하는 명령이 있습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:80 cabdb524e1d849448046bf6e2d206342\nmsgid \"\"\n\"Objects of these types are called \\\"stream objects\\\". PyMuPDF allows \"\n\"reading an object's stream via method :meth:`Document.xref_stream` with \"\n\"the object's :data:`xref` as an argument. It is also possible to write \"\n\"back a modified version of a stream using :meth:`Document.update_stream`.\"\nmsgstr \"이러한 유형의 객체를 \\\"스트림 객체\\\"라고 합니다. |PyMuPDF| 는 객체의 :data:`xref` 를 인수로 사용하여 :meth:`Document.xref_stream` 메서드를 통해 객체의 스트림을 읽을 수 있게 합니다. :meth:`Document.update_stream` 을 사용하여 수정된 스트림 버전을 다시 쓸 수도 있습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:82 ba7bea2d5ccf47818f2fbbdf71fff7fd\nmsgid \"\"\n\"Assume that the following snippet wants to read all streams of a PDF for \"\n\"whatever reason::\"\nmsgstr \"다음 코드 조각이 어떤 이유로든 PDF의 모든 스트림을 읽고 싶다고 가정합니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:91 9047c6fd5efa437b8bc7bc5353205ab2\nmsgid \"\"\n\":meth:`Document.xref_stream` automatically returns a stream decompressed \"\n\"as a bytes object -- and :meth:`Document.update_stream` automatically \"\n\"compresses it if beneficial.\"\nmsgstr \":meth:`Document.xref_stream` 은 스트림을 자동으로 압축 해제하여 bytes 객체로 반환합니다 -- 그리고 :meth:`Document.update_stream` 은 유리한 경우 자동으로 압축합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:96 5546055dde52483fab745bbc48f96b0f\nmsgid \"How to Handle Page Contents\"\nmsgstr \"페이지 콘텐츠 처리 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:97 9e0c2c1ba3df4e1d8317099f96c3c0a6\nmsgid \"\"\n\"A PDF page can have zero or multiple :data:`contents` objects. These are \"\n\"stream objects describing **what** appears **where** and **how** on a \"\n\"page (like text and images). They are written in a special mini-language \"\n\"described e.g. in chapter \\\"APPENDIX A - Operator Summary\\\" on page 643 \"\n\"of the :ref:`AdobeManual`.\"\nmsgstr \"PDF 페이지는 0개 또는 여러 개의 :data:`contents` 객체를 가질 수 있습니다. 이것들은 페이지에서 **무엇** 이 **어디에** 그리고 **어떻게** 나타나는지(텍스트 및 이미지와 같은) 설명하는 스트림 객체입니다. 이것들은 :ref:`AdobeManual` 의 643페이지 \\\"APPENDIX A - Operator Summary\\\" 장에 설명된 특수 미니 언어로 작성됩니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:99 386e5519cf9249b2ba829b533c775316\nmsgid \"\"\n\"Every PDF reader application must be able to interpret the contents \"\n\"syntax to reproduce the intended appearance of the page.\"\nmsgstr \"모든 PDF 리더 애플리케이션은 페이지의 의도된 모양을 재현하기 위해 콘텐츠 구문을 해석할 수 있어야 합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:101 28d8cbd998214286ac22c11bab9374a1\nmsgid \"\"\n\"If multiple :data:`contents` objects are provided, they must be \"\n\"interpreted in the specified sequence in exactly the same way as if they \"\n\"were provided as a concatenation of the several.\"\nmsgstr \"여러 :data:`contents` 객체가 제공되는 경우, 여러 개의 연결로 제공된 것과 정확히 동일한 방식으로 지정된 순서로 해석되어야 합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:103 d47ff2ffa881474caad92f60fd6bdb53\nmsgid \"\"\n\"There are good technical arguments for having multiple :data:`contents` \"\n\"objects:\"\nmsgstr \"여러 :data:`contents` 객체를 갖는 것에 대한 좋은 기술적 논거가 있습니다:\"\n\n#: ../../recipes-low-level-interfaces.rst:105 0a53f856d8904323aef9b42981091b99\nmsgid \"\"\n\"It is a lot easier and faster to just add new :data:`contents` objects \"\n\"than maintaining a single big one (which entails reading, decompressing, \"\n\"modifying, recompressing, and rewriting it for each change).\"\nmsgstr \"하나의 큰 객체를 유지하는 것(각 변경에 대해 읽기, 압축 해제, 수정, 재압축 및 다시 쓰기를 수반함)보다 새로운 :data:`contents` 객체를 추가하는 것이 훨씬 쉽고 빠릅니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:106 fcbe0dac945345dd948d48f71cb2211d\nmsgid \"\"\n\"When working with incremental updates, a modified big :data:`contents` \"\n\"object will bloat the update delta and can thus easily negate the \"\n\"efficiency of incremental saves.\"\nmsgstr \"\"\n\"증분 업데이트로 작업할 때 수정된 큰 :data:`contents` 객체는 업데이트 델타를 부풀려서 증분 저장의 효율성을 쉽게 무효화할 \"\n\"수 있습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:108 0d451f51c5ee4fd7a0f796fedca1aaef\nmsgid \"\"\n\"For example, PyMuPDF adds new, small :data:`contents` objects in methods \"\n\":meth:`Page.insert_image`, :meth:`Page.show_pdf_page` and the \"\n\":ref:`Shape` methods.\"\nmsgstr \"\"\n\"예를 들어, |PyMuPDF| 는 :meth:`Page.insert_image`, :meth:`Page.show_pdf_page` 및 \"\n\":ref:`Shape` 메서드에서 새로운 작은 :data:`contents` 객체를 추가합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:110 89445c95103d4a92beb375bccb7fa5ab\nmsgid \"\"\n\"However, there are also situations when a **single** :data:`contents` \"\n\"object is beneficial: it is easier to interpret and more compressible \"\n\"than multiple smaller ones.\"\nmsgstr \"\"\n\"그러나 **단일** :data:`contents` 객체가 유리한 상황도 있습니다: 여러 개의 작은 객체보다 해석하기 쉽고 압축률이 \"\n\"더 높습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:112 2a0b4642b4364684a16adb1d39489ec3\nmsgid \"Here are two ways of combining multiple contents of a page::\"\nmsgstr \"다음은 페이지의 여러 콘텐츠를 결합하는 두 가지 방법입니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:124 6057b6061a91411ea964bce99b20537e\nmsgid \"\"\n\"The clean function :meth:`Page.clean_contents` does a lot more than just \"\n\"glueing :data:`contents` objects: it also corrects and optimizes the PDF \"\n\"operator syntax of the page and removes any inconsistencies with the \"\n\"page's object definition.\"\nmsgstr \"\"\n\"정리 함수 :meth:`Page.clean_contents` 는 :data:`contents` 객체를 결합하는 것 이상의 작업을 수행합니다: \"\n\"페이지의 PDF 연산자 구문을 수정하고 최적화하며 페이지 객체 정의와의 불일치를 제거합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:129 844f10a12b4048188390d4080ce7c9c3\nmsgid \"How to Access the PDF Catalog\"\nmsgstr \"PDF 카탈로그 액세스 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:130 fb4cc97df02e4b7dabd01a2eb37ac0ce\nmsgid \"\"\n\"This is a central (\\\"root\\\") object of a PDF. It serves as a starting \"\n\"point to reach important other objects and it also contains some global \"\n\"options for the PDF::\"\nmsgstr \"\"\n\"이것은 PDF의 중앙(\\\"루트\\\") 객체입니다. 중요한 다른 객체에 도달하기 위한 시작점 역할을 하며 PDF에 대한 일부 전역 옵션도 \"\n\"포함합니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:146 1a3be34ec5154f478840f9583752a6dd\nmsgid \"\"\n\"Indentation, line breaks and comments are inserted here for clarification\"\n\" purposes only and will not normally appear. For more information on the \"\n\"PDF catalog see section 7.7.2 on page 71 of the :ref:`AdobeManual`.\"\nmsgstr \"\"\n\"들여쓰기, 줄 바꿈 및 주석은 설명 목적으로만 여기에 삽입되었으며 일반적으로 나타나지 않습니다. PDF 카탈로그에 대한 자세한 \"\n\"내용은 :ref:`AdobeManual` 의 71페이지 섹션 7.7.2를 참조하세요.\"\n\n#: ../../recipes-low-level-interfaces.rst:151 f6cb282ffd654805b67324bd72b4ae19\nmsgid \"How to Access the PDF File Trailer\"\nmsgstr \"PDF 파일 트레일러 액세스 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:152 2f99555ea9464790998c72d9bb928af6\nmsgid \"\"\n\"The trailer of a PDF file is a :data:`dictionary` located towards the end\"\n\" of the file. It contains special objects, and pointers to important \"\n\"other information. See :ref:`AdobeManual` p. 42. Here is an overview:\"\nmsgstr \"\"\n\"PDF 파일의 트레일러는 파일 끝 부분에 위치한 :data:`dictionary` 입니다. 특수 객체와 중요한 다른 정보에 대한 포인터를 \"\n\"포함합니다. :ref:`AdobeManual` 42페이지를 참조하세요. 다음은 개요입니다:\"\n\n#: ../../recipes-low-level-interfaces.rst:155 04bff59ce53f4b8fa7cc2d5c1e5eea13\nmsgid \"**Key**\"\nmsgstr \"**키**\"\n\n#: ../../recipes-low-level-interfaces.rst:155 8e89e5f4179345d481243a717e85c672\nmsgid \"**Type**\"\nmsgstr \"**유형**\"\n\n#: ../../recipes-low-level-interfaces.rst:155 903806d55c7b4a6ba366a2fb6723087b\nmsgid \"**Value**\"\nmsgstr \"**값**\"\n\n#: ../../recipes-low-level-interfaces.rst:157 3f86ae718b944400beb0abe4e3c0ffc6\nmsgid \"Size\"\nmsgstr \"Size\"\n\n#: ../../recipes-low-level-interfaces.rst:157\n#: ../../recipes-low-level-interfaces.rst:158\n#: ../../recipes-low-level-interfaces.rst:163 0151f1cab4e14722a6078e4d9d1ef692\n#: 65f366157b6d48fd9a44282c78eeb3fb f3e5b4c1111842a3bdd6a8d28b0ace69\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../recipes-low-level-interfaces.rst:157 b687a9563e5445e1a4a96170f23fd4ed\nmsgid \"Number of entries in the cross-reference table + 1.\"\nmsgstr \"교차 참조 테이블의 항목 수 + 1.\"\n\n#: ../../recipes-low-level-interfaces.rst:158 c04f76c59d18423996a207301fe05b6c\nmsgid \"Prev\"\nmsgstr \"Prev\"\n\n#: ../../recipes-low-level-interfaces.rst:158 f3def7a36286442a9177758486e19b60\nmsgid \"Offset to previous :data:`xref` section (indicates incremental updates).\"\nmsgstr \"이전 :data:`xref` 섹션으로의 오프셋(증분 업데이트를 나타냄).\"\n\n#: ../../recipes-low-level-interfaces.rst:159 c31d927f0f504e1eab1cc5069c67fb84\nmsgid \"Root\"\nmsgstr \"Root\"\n\n#: ../../recipes-low-level-interfaces.rst:159\n#: ../../recipes-low-level-interfaces.rst:160\n#: ../../recipes-low-level-interfaces.rst:161 46c865d65cb54d6a9bd3680eadccc9e2\n#: 4cac1014b9f949de8a9fea7b1ec825d4 71dd8129bfe3455c9ba485dee7df486a\nmsgid \"dictionary\"\nmsgstr \"dictionary\"\n\n#: ../../recipes-low-level-interfaces.rst:159 7ce50eec5fcd45bf8ec4c639257e81f2\nmsgid \"(indirect) Pointer to the catalog. See previous section.\"\nmsgstr \"(간접) 카탈로그에 대한 포인터. 이전 섹션을 참조하세요.\"\n\n#: ../../recipes-low-level-interfaces.rst:160 076ac475747440afa77a21c7e831af71\nmsgid \"Encrypt\"\nmsgstr \"Encrypt\"\n\n#: ../../recipes-low-level-interfaces.rst:160 dbd95d95d21d4d63b464a548435e60f7\nmsgid \"Pointer to encryption object (encrypted files only).\"\nmsgstr \"암호화 객체에 대한 포인터(암호화된 파일만 해당).\"\n\n#: ../../recipes-low-level-interfaces.rst:161 d3a696bffe5c47e68d3282ffcd42bdbd\nmsgid \"Info\"\nmsgstr \"Info\"\n\n#: ../../recipes-low-level-interfaces.rst:161 4005b1fad3e54caf9398edeb6a5903d2\nmsgid \"(indirect) Pointer to information (metadata).\"\nmsgstr \"(간접) 정보(메타데이터)에 대한 포인터.\"\n\n#: ../../recipes-low-level-interfaces.rst:162 5fab0c7955d749a48d2a3b763b7c9670\nmsgid \"ID\"\nmsgstr \"ID\"\n\n#: ../../recipes-low-level-interfaces.rst:162 6898db1a22a3477fa753166d2cbe3164\nmsgid \"array\"\nmsgstr \"array\"\n\n#: ../../recipes-low-level-interfaces.rst:162 6b2347ffb47c4b0081aa8acde158dcc0\nmsgid \"File identifier consisting of two byte strings.\"\nmsgstr \"두 개의 바이트 문자열로 구성된 파일 식별자.\"\n\n#: ../../recipes-low-level-interfaces.rst:163 8139050a469b4720a0c241492831b167\nmsgid \"XRefStm\"\nmsgstr \"XRefStm\"\n\n#: ../../recipes-low-level-interfaces.rst:163 05d57dc7bf91480f8003a6fc80f999f0\nmsgid \"Offset of a cross-reference stream. See :ref:`AdobeManual` p. 49.\"\nmsgstr \"교차 참조 스트림의 오프셋. :ref:`AdobeManual` 49페이지를 참조하세요.\"\n\n#: ../../recipes-low-level-interfaces.rst:166 6202cb8493b044fab435b3e03390cc72\nmsgid \"\"\n\"Access this information via PyMuPDF with :meth:`Document.pdf_trailer` or,\"\n\" equivalently, via :meth:`Document.xref_object` using -1 instead of a \"\n\"valid :data:`xref` number.\"\nmsgstr \"\"\n\"|PyMuPDF| 에서 :meth:`Document.pdf_trailer` 또는 동등하게 유효한 :data:`xref` 번호 대신 -1을 \"\n\"사용하는 :meth:`Document.xref_object` 를 통해 이 정보에 액세스합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:187 9471214cc8bf436a85a288b50896bcec\nmsgid \"How to Access XML Metadata\"\nmsgstr \"XML 메타데이터 액세스 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:188 11166fcb45b742b390422fc68e337f42\nmsgid \"\"\n\"A PDF may contain XML metadata in addition to the standard metadata \"\n\"format. In fact, most PDF viewer or modification software adds this type \"\n\"of information when saving the PDF (Adobe, Nitro PDF, PDF-XChange, etc.).\"\nmsgstr \"\"\n\"PDF는 표준 메타데이터 형식 외에 XML 메타데이터를 포함할 수 있습니다. 실제로 대부분의 PDF 뷰어 또는 수정 소프트웨어는 PDF를 \"\n\"저장할 때 이 유형의 정보를 추가합니다(Adobe, Nitro PDF, PDF-XChange 등).\"\n\n#: ../../recipes-low-level-interfaces.rst:190 66fa949fa3734abc94308b18f181168d\nmsgid \"\"\n\"PyMuPDF has no way to **interpret or change** this information directly, \"\n\"because it contains no XML features. XML metadata is however stored as a \"\n\":data:`stream` object, so it can be read, modified with appropriate \"\n\"software and written back.\"\nmsgstr \"\"\n\"|PyMuPDF| 는 XML 기능을 포함하지 않기 때문에 이 정보를 직접 **해석하거나 변경** 할 수 있는 방법이 없습니다. 그러나 XML \"\n\"메타데이터는 :data:`stream` 객체로 저장되므로 읽고, 적절한 소프트웨어로 수정하고, 다시 쓸 수 있습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:202 d89d8b8d321c4343b58807d0a6abb8f3\nmsgid \"\"\n\"Using some XML package, the XML data can be interpreted and / or modified\"\n\" and then stored back. The following also works, if the PDF previously \"\n\"had no XML metadata::\"\nmsgstr \"\"\n\"일부 XML 패키지를 사용하여 XML 데이터를 해석 및/또는 수정한 다음 다시 저장할 수 있습니다. PDF에 이전에 XML 메타데이터가 \"\n\"없었던 경우에도 다음이 작동합니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:213 1c05939e6ce141669a782bf9f395e2e3\nmsgid \"How to Extend PDF Metadata\"\nmsgstr \"PDF 메타데이터 확장 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:214 3c73d296caa64f959f4462e689310160\nmsgid \"\"\n\"Attribute :attr:`Document.metadata` is designed so it works for all \"\n\":ref:`supported document types<Supported_File_Types>` in the same way: it\"\n\" is a Python dictionary with a **fixed set of key-value pairs**. \"\n\"Correspondingly, :meth:`Document.set_metadata` only accepts standard \"\n\"keys.\"\nmsgstr \"\"\n\"속성 :attr:`Document.metadata` 는 모든 :ref:`지원되는 문서 유형<Supported_File_Types>` 에 대해 \"\n\"동일한 방식으로 작동하도록 설계되었습니다: **고정된 키-값 쌍 집합** 이 있는 Python 딕셔너리입니다. 따라서 \"\n\":meth:`Document.set_metadata` 는 표준 키만 허용합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:216 2d338508ee9d4183a1e01a0ddc4913fb\nmsgid \"\"\n\"However, PDFs may contain items not accessible like this. Also, there may\"\n\" be reasons to store additional information, like copyrights. Here is a \"\n\"way to handle **arbitrary metadata items** by using PyMuPDF low-level \"\n\"functions.\"\nmsgstr \"\"\n\"그러나 PDF에는 이렇게 액세스할 수 없는 항목이 포함될 수 있습니다. 또한 저작권과 같은 추가 정보를 저장할 이유가 있을 수 \"\n\"있습니다. 다음은 |PyMuPDF| 저수준 함수를 사용하여 **임의의 메타데이터 항목** 을 처리하는 방법입니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:218 4b3358b8f8ae445d967cb16ecb41155b\nmsgid \"As an example, look at this standard metadata output of some PDF::\"\nmsgstr \"예를 들어, 일부 PDF의 표준 메타데이터 출력을 살펴보세요::\"\n\n#: ../../recipes-low-level-interfaces.rst:237 3e9c31875d914679be24d654087376b7\nmsgid \"\"\n\"Use the following code to see **all items** stored in the metadata \"\n\"object::\"\nmsgstr \"다음 코드를 사용하여 메타데이터 객체에 저장된 **모든 항목** 을 확인하세요::\"\n\n#: ../../recipes-low-level-interfaces.rst:265 9044da7dae9243488a9b55198969056f\nmsgid \"\"\n\"*Vice versa*, you can also **store private metadata items** in a PDF. It \"\n\"is your responsibility to make sure that these items conform to PDF \"\n\"specifications - especially they must be (unicode) strings. Consult \"\n\"section 14.3 (p. 548) of the :ref:`AdobeManual` for details and caveats::\"\nmsgstr \"\"\n\"*반대로*, PDF에 **개인 메타데이터 항목** 을 저장할 수도 있습니다. 이러한 항목이 PDF 사양을 준수하는지 확인하는 것은 \"\n\"귀하의 책임입니다. 특히 (유니코드) 문자열이어야 합니다. 자세한 내용과 주의사항은 :ref:`AdobeManual` 의 섹션 \"\n\"14.3(548페이지)을 참조하세요::\"\n\n#: ../../recipes-low-level-interfaces.rst:287 02817b654e9b436b88b8c0bb4315843c\nmsgid \"\"\n\"To delete selected keys, use `doc.xref_set_key(xref, \\\"mykey\\\", \"\n\"\\\"null\\\")`. As explained in the next section, string \\\"null\\\" is the PDF \"\n\"equivalent to Python's `None`. A key with that value will be treated as \"\n\"not being specified -- and physically removed in garbage collections.\"\nmsgstr \"\"\n\"선택한 키를 삭제하려면 `doc.xref_set_key(xref, \\\"mykey\\\", \\\"null\\\")` 을 사용하세요. 다음 섹션에서 설명한 \"\n\"대로 문자열 \\\"null\\\" 은 Python의 `None` 에 해당하는 PDF입니다. 해당 값을 가진 키는 지정되지 않은 것으로 \"\n\"처리되며 가비지 수집에서 물리적으로 제거됩니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:292 1b30dcfaa7584ec7ad6ea741fcef3f3d\nmsgid \"How to Read and Update PDF Objects\"\nmsgstr \"PDF 객체 읽기 및 업데이트 방법\"\n\n#: ../../recipes-low-level-interfaces.rst:297 3d42ddab6e0142cebbd430aa2e5703b5\nmsgid \"\"\n\"There also exist granular, elegant ways to access and manipulate selected\"\n\" PDF :data:`dictionary` keys.\"\nmsgstr \"선택한 PDF :data:`dictionary` 키에 액세스하고 조작하는 세밀하고 우아한 방법도 있습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:299 0ae387a252ac402cbd803641d93dffb8\nmsgid \"\"\n\":meth:`Document.xref_get_keys` returns the PDF keys of the object at \"\n\":data:`xref`::\"\nmsgstr \":meth:`Document.xref_get_keys` 는 :data:`xref` 의 객체의 PDF 키를 반환합니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:308 3e72f7b183cd4b33906cc3039c3d5231\nmsgid \"Compare with the full object definition::\"\nmsgstr \"전체 객체 정의와 비교하세요::\"\n\n#: ../../recipes-low-level-interfaces.rst:319 3e65febdd754494e963713aa6ab4e707\nmsgid \"\"\n\"Single keys can also be accessed directly via \"\n\":meth:`Document.xref_get_key`. The value **always is a string** together \"\n\"with type information, that helps with interpreting it::\"\nmsgstr \"\"\n\"단일 키는 :meth:`Document.xref_get_key` 를 통해 직접 액세스할 수도 있습니다. 값은 **항상 문자열** 이며 \"\n\"해석에 도움이 되는 유형 정보와 함께 제공됩니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:324 05f684fed3f04de4bb45d40de217b49d\nmsgid \"Here is a full listing of the above page keys::\"\nmsgstr \"다음은 위의 페이지 키의 전체 목록입니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:335 9a78976524a4487aa10951cc475ba498\nmsgid \"\"\n\"An undefined key inquiry returns `('null', 'null')` -- PDF object type \"\n\"`null` corresponds to `None` in Python. Similar for the booleans `true` \"\n\"and `false`.\"\nmsgstr \"\"\n\"정의되지 않은 키 조회는 `('null', 'null')` 을 반환합니다 -- PDF 객체 유형 `null` 은 Python의 `None` \"\n\"에 해당합니다. 부울 `true` 및 `false` 도 유사합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:336 a799622cee4441148aa30dadcc2c66b8\nmsgid \"\"\n\"Let us add a new key to the page definition that sets its rotation to 90 \"\n\"degrees (you are aware that there actually exists \"\n\":meth:`Page.set_rotation` for this?)::\"\nmsgstr \"\"\n\"페이지 정의에 회전을 90도로 설정하는 새 키를 추가해 보겠습니다(이를 위해 실제로 :meth:`Page.set_rotation` 이 \"\n\"존재한다는 것을 알고 계신가요?)::\"\n\n#: ../../recipes-low-level-interfaces.rst:351 8bf57e3c458a40379cf2dacf4867c307\nmsgid \"\"\n\"This method can also be used to remove a key from the :data:`xref` \"\n\"dictionary by setting its value to `null`: The following will remove the \"\n\"rotation specification from the page: `doc.xref_set_key(page.xref, \"\n\"\\\"Rotate\\\", \\\"null\\\")`. Similarly, to remove all links, annotations and \"\n\"fields from a page, use `doc.xref_set_key(page.xref, \\\"Annots\\\", \"\n\"\\\"null\\\")`. Because `Annots` by definition is an array, setting en empty \"\n\"array with the statement `doc.xref_set_key(page.xref, \\\"Annots\\\", \"\n\"\\\"[]\\\")` would do the same job in this case.\"\nmsgstr \"\"\n\"이 메서드는 값을 `null` 로 설정하여 :data:`xref` 딕셔너리에서 키를 제거하는 데에도 사용할 수 있습니다: 다음은 \"\n\"페이지에서 회전 사양을 제거합니다: `doc.xref_set_key(page.xref, \\\"Rotate\\\", \\\"null\\\")`. \"\n\"마찬가지로 페이지에서 모든 링크, 주석 및 필드를 제거하려면 `doc.xref_set_key(page.xref, \\\"Annots\\\", \"\n\"\\\"null\\\")` 을 사용하세요. `Annots` 는 정의상 배열이므로 `doc.xref_set_key(page.xref, \\\"Annots\\\", \"\n\"\\\"[]\\\")` 문으로 빈 배열을 설정하면 이 경우 동일한 작업을 수행합니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:353 eb61cb57cb054fbcba0a0e87011b9704\nmsgid \"\"\n\"PDF dictionaries can be hierarchically nested. In the following page \"\n\"object definition both, `Font` and `XObject` are subdictionaries of \"\n\"`Resources`::\"\nmsgstr \"\"\n\"PDF 딕셔너리는 계층적으로 중첩될 수 있습니다. 다음 페이지 객체 정의에서 `Font` 와 `XObject` 는 모두 `Resources` 의 \"\n\"하위 딕셔너리입니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:373 53a1a5f64c1b46b6a11637fe7a037f27\nmsgid \"\"\n\"The above situation **is supported** by methods \"\n\":meth:`Document.xref_set_key` and :meth:`Document.xref_get_key`: use a \"\n\"path-like notation to point at the required key. For example, to retrieve\"\n\" the value of key `Im1` above, specify the complete chain of dictionaries\"\n\" \\\"above\\\" it in the key argument: `\\\"Resources/XObject/Im1\\\"`::\"\nmsgstr \"\"\n\"위의 상황은 :meth:`Document.xref_set_key` 및 :meth:`Document.xref_get_key` 메서드로 \"\n\"**지원됩니다**: 필요한 키를 가리키는 경로와 같은 표기법을 사용하세요. 예를 들어 위의 키 `Im1` 의 값을 검색하려면 키 \"\n\"인수에 그 위의 딕셔너리 전체 체인을 지정하세요: `\\\"Resources/XObject/Im1\\\"`::\"\n\n#: ../../recipes-low-level-interfaces.rst:378 29393cc04fc94daf8a80dff959cc95d5\nmsgid \"\"\n\"The path notation can also be used to **directly set a value**: use the \"\n\"following to let `Im1` point to a different object::\"\nmsgstr \"\"\n\"경로 표기법은 **값을 직접 설정** 하는 데에도 사용할 수 있습니다: 다음을 사용하여 `Im1` 이 다른 객체를 가리키도록 \"\n\"하세요::\"\n\n#: ../../recipes-low-level-interfaces.rst:399 e8cf3e8fbf4a429d8ad7ad100f97899d\nmsgid \"\"\n\"Be aware, that **no semantic checks** whatsoever will take place here: if\"\n\" the PDF has no xref 9999, it won't be detected at this point.\"\nmsgstr \"\"\n\"**의미론적 검사** 가 전혀 수행되지 않는다는 점에 유의하세요: PDF에 xref 9999가 없으면 이 시점에서 감지되지 \"\n\"않습니다.\"\n\n#: ../../recipes-low-level-interfaces.rst:401 d43960f2d29045d6995ad727a6a18ef6\nmsgid \"\"\n\"If a key does not exist, it will be created by setting its value. \"\n\"Moreover, if any intermediate keys do not exist either, they will also be\"\n\" created as necessary. The following creates an array `D` several levels \"\n\"below the existing dictionary `A`. Intermediate dictionaries `B` and `C` \"\n\"are automatically created::\"\nmsgstr \"\"\n\"키가 존재하지 않으면 값을 설정하여 생성됩니다. 또한 중간 키가 존재하지 않으면 필요에 따라 생성됩니다. 다음은 기존 딕셔너리 \"\n\"`A` 아래 여러 레벨에 배열 `D` 를 만듭니다. 중간 딕셔너리 `B` 와 `C` 가 자동으로 생성됩니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:421 bba82e04d29a431c8cfaa0c81a8422c0\nmsgid \"\"\n\"When setting key values, basic **PDF syntax checking** will be done by \"\n\"MuPDF. For example, new keys can only be created **below a dictionary**. \"\n\"The following tries to create some new string item `E` below the \"\n\"previously created array `D`::\"\nmsgstr \"\"\n\"키 값을 설정할 때 기본 **PDF 구문 검사** 가 MuPDF에 의해 수행됩니다. 예를 들어 새 키는 **딕셔너리 아래에만** 생성할 수 \"\n\"있습니다. 다음은 이전에 생성된 배열 `D` 아래에 새 문자열 항목 `E` 를 만들려고 시도합니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:429 b3e5658efb1847799ff226694699b334\nmsgid \"\"\n\"It is also **not possible**, to create a key if some higher level key is \"\n\"an **\\\"indirect\\\"** object, i.e. an xref. In other words, xrefs can only \"\n\"be modified directly and not implicitly via other objects referencing \"\n\"them::\"\nmsgstr \"\"\n\"상위 레벨 키가 **\\\"간접\\\"** 객체(즉, xref)인 경우 키를 만드는 것도 **불가능합니다**. 즉, xref는 직접적으로만 수정할 \"\n\"수 있으며 이를 참조하는 다른 객체를 통해 암시적으로 수정할 수 없습니다::\"\n\n#: ../../recipes-low-level-interfaces.rst:442 7cb0c4e7fe9e4eb580372473612bca3c\nmsgid \"\"\n\"These are expert functions! There are no validations as to whether valid \"\n\"PDF objects, xrefs, etc. are specified. As with other low-level methods \"\n\"there is the risk to render the PDF, or parts of it unusable.\"\nmsgstr \"\"\n\"이것들은 전문가용 함수입니다! 유효한 PDF 객체, xref 등이 지정되었는지에 대한 검증이 없습니다. 다른 저수준 메서드와 \"\n\"마찬가지로 PDF 또는 그 일부를 사용할 수 없게 만들 위험이 있습니다.\"\n\n#: ../../footer.rst:46 cdf69554bc5f45a1bcc753bd3326f80b\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-multiprocessing.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7e6f40d7964249e79b04c3d1e97663f7\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 0b0e7728efd643f2af88f9a10132b4db\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 fcd448c0f08b44ca81698f910e7f182b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../recipes-multiprocessing.rst:17 c6783e6e6a79406dbcc4279e7db0acff\nmsgid \"Multiprocessing\"\nmsgstr \"멀티프로세싱\"\n\n#: ../../recipes-multiprocessing.rst:19 3440ee5e309146219a07e286636ee246\nmsgid \"\"\n\"|PyMuPDF| does not support running on multiple threads - doing so may \"\n\"cause incorrect behaviour or even crash Python itself.\"\nmsgstr \"|PyMuPDF| 는 여러 스레드에서 실행을 지원하지 않습니다. 그렇게 하면 잘못된 동작이 발생하거나 Python 자체가 충돌할 수 있습니다.\"\n\n#: ../../recipes-multiprocessing.rst:21 c2e5df4ee4234d12ae3febd77e85fbe3\nmsgid \"\"\n\"However, there is the option to use :title:`Python's` *multiprocessing* \"\n\"module in a variety of ways.\"\nmsgstr \"하지만 :title:`Python의` *multiprocessing* 모듈을 다양한 방법으로 사용할 수 있는 옵션이 있습니다.\"\n\n#: ../../recipes-multiprocessing.rst:23 bf58d753cc3b40d7a405acc1f719c73c\nmsgid \"\"\n\"If you are looking to speed up page-oriented processing for a large \"\n\"document, use this script as a starting point. It should be at least \"\n\"twice as fast as the corresponding sequential processing.\"\nmsgstr \"큰 문서에 대한 페이지 지향 처리를 가속화하려면 이 스크립트를 시작점으로 사용하세요. 해당 순차 처리보다 최소 2배 빠르게 동작해야 합니다.\"\n\n#: ../../recipes-multiprocessing.rst:26 ../../recipes-multiprocessing.rst:37\n#: c80ee239863c4c828445463631c1e884 f7c061f68ffd4ceeb32612aadf8d455e\nmsgid \"|toggleStart|\"\nmsgstr \"|toggleStart|\"\n\n#: ../../recipes-multiprocessing.rst:31 ../../recipes-multiprocessing.rst:42\n#: 591531fd1bc740dcb7a6d96399fe0ae1 71adac329d5748839c5c665b80e4d71d\nmsgid \"|toggleEnd|\"\nmsgstr \"|toggleEnd|\"\n\n#: ../../recipes-multiprocessing.rst:34 29a0399816a94d87be2670a44b7590db\nmsgid \"\"\n\"Here is a more complex example involving inter-process communication \"\n\"between a main process (showing a GUI) and a child process doing \"\n\"|PyMuPDF| access to a document.\"\nmsgstr \"다음은 메인 프로세스(GUI 표시)와 문서에 대한 |PyMuPDF| 액세스를 수행하는 자식 프로세스 간의 프로세스 간 통신을 포함하는 더 복잡한 예제입니다.\"\n\n#: ../../footer.rst:46 bd8b258b125f42cda799e69f58599037\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-ocr.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 5b2b2477e1b643fe878fe480ca8a5a5c\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 9af1355de6074c539e4b51e5dd6b1657\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8dcf3faef7104a2cafff9541cb4c8daf\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../recipes-ocr.rst:17 d523ae4d9ab8407a9cf5b861f5297e31\nmsgid \"OCR - Optical Character Recognition\"\nmsgstr \"OCR - 광학 문자 인식\"\n\n#: ../../recipes-ocr.rst:19 ad0635e0379e4e30a03ba26654ccd626\nmsgid \"\"\n\"|PyMuPDF| has integrated support for OCR (Optical Character Recognition).\"\n\" It is possible to use OCR for both, images (via the :ref:`Pixmap` class)\"\n\" and for document pages.\"\nmsgstr \"|PyMuPDF| 는 OCR(광학 문자 인식)에 대한 통합 지원을 제공합니다. 이미지(:ref:`Pixmap` 클래스를 통해)와 문서 페이지 모두에 OCR을 사용할 수 있습니다.\"\n\n#: ../../recipes-ocr.rst:21 0e099596d02b489e9ad0b0acde488005\nmsgid \"\"\n\"The feature is currently based on Tesseract-OCR which must be installed \"\n\"as a separate application -- see the :ref:`installation_ocr`.\"\nmsgstr \"이 기능은 현재 Tesseract-OCR을 기반으로 하며 별도의 애플리케이션으로 설치해야 합니다. 자세한 내용은 :ref:`installation_ocr` 을 참조하세요.\"\n\n#: ../../recipes-ocr.rst:24 ea8b233238a54196add63aa017b42543\nmsgid \"How to OCR an Image\"\nmsgstr \"이미지 OCR 방법\"\n\n#: ../../recipes-ocr.rst:25 a44323f4b0df47da98d91ac1a37d6b21\nmsgid \"\"\n\"A supported image must first be converted to a :ref:`Pixmap`. The Pixmap \"\n\"can then be saved to a 1-page PDF. This page will look like the original \"\n\"image with the same width and height. It will contain a layer of text as \"\n\"recognized by Tesseract.\"\nmsgstr \"지원되는 이미지는 먼저 :ref:`Pixmap` 으로 변환해야 합니다. 그런 다음 Pixmap을 1페이지 PDF로 저장할 수 있습니다. 이 페이지는 원본 이미지와 동일한 너비와 높이를 가집니다. Tesseract가 인식한 텍스트 레이어가 포함됩니다.\"\n\n#: ../../recipes-ocr.rst:27 fb8760d9d7144f5786b17ead972a9a1f\nmsgid \"\"\n\"The PDF can be generated via one of the methods \"\n\":meth:`Pixmap.pdfocr_save` or :meth:`Pixmap.pdfocr_tobytes`, as a file on\"\n\" disk or as a PDF in memory.\"\nmsgstr \"PDF는 :meth:`Pixmap.pdfocr_save` 또는 :meth:`Pixmap.pdfocr_tobytes` 메서드 중 하나를 통해 디스크의 파일로 또는 메모리의 PDF로 생성할 수 있습니다.\"\n\n#: ../../recipes-ocr.rst:29 1f42a8e44a1d4d17b7f75da5f822e8aa\nmsgid \"\"\n\"The text can be extracted and searched with the usual text extraction and\"\n\" search methods (:meth:`Page.get_text`, :meth:`Page.search_for`, etc.). \"\n\"Please also note the following important facts and prerequisites:\"\nmsgstr \"텍스트는 일반적인 텍스트 추출 및 검색 메서드(:meth:`Page.get_text`, :meth:`Page.search_for` 등)로 추출하고 검색할 수 있습니다. 다음 중요한 사실과 전제 조건도 참고하세요:\"\n\n#: ../../recipes-ocr.rst:31 44371b59458b49ce97c3a0a6cc2e6b26\nmsgid \"\"\n\"When converting the image to a Pixmap, please confirm that the color \"\n\"space is RGB and alpha is `False` (no transparency). Convert the original\"\n\" Pixmap if necessary.\"\nmsgstr \"이미지를 Pixmap으로 변환할 때 색 공간이 RGB이고 alpha가 `False` (투명도 없음)인지 확인하세요. 필요하면 원본 Pixmap을 변환하세요.\"\n\n#: ../../recipes-ocr.rst:32 30e5cba3998c418688b3fea3b830296b\nmsgid \"\"\n\"All text is written as \\\"hidden\\\" with Tesseract's own `GlyphLessFont`, a\"\n\" mono-spaced font with metrics comparable to Courier.\"\nmsgstr \"모든 텍스트는 Tesseract 자체 `GlyphLessFont` 로 \\\"숨김\\\"으로 작성되며, Courier와 유사한 메트릭을 가진 고정폭 글꼴입니다.\"\n\n#: ../../recipes-ocr.rst:33 6ac9d9f5b2824a4890be1cf73715c091\nmsgid \"\"\n\"All text has the properties regular and black (i.e. no bold, no italic, \"\n\"no information about the original fonts).\"\nmsgstr \"모든 텍스트는 일반 및 검은색 속성을 가집니다(즉, 굵게, 기울임꼴 없음, 원본 글꼴 정보 없음).\"\n\n#: ../../recipes-ocr.rst:34 a08272a3cc18432f9cc35cdd8591c309\nmsgid \"\"\n\"Tesseract does not recognize vector graphics (i.e. no drawings / line-\"\n\"art).\"\nmsgstr \"Tesseract는 벡터 그래픽을 인식하지 않습니다(즉, 그림/선화 없음).\"\n\n#: ../../recipes-ocr.rst:36 35e883700cc148b98f8d79dcf362ad4e\nmsgid \"This approach is also recommended to OCR a complete scanned PDF:\"\nmsgstr \"이 방법은 전체 스캔된 PDF를 OCR하는 데도 권장됩니다:\"\n\n#: ../../recipes-ocr.rst:38 d47d8fca90fb4141932d00dd7353c53a\nmsgid \"Render each page to a :ref:`Pixmap` with desired resolution\"\nmsgstr \"각 페이지를 원하는 해상도로 :ref:`Pixmap` 에 렌더링\"\n\n#: ../../recipes-ocr.rst:39 666549a157cb4d1eae9cfaa445aa6b78\nmsgid \"Append the resulting 1-page PDF to the output PDF\"\nmsgstr \"결과 1페이지 PDF를 출력 PDF에 추가\"\n\n#: ../../recipes-ocr.rst:42 df250dae4cd34a3e9b289c490a3cde65\nmsgid \"How to OCR a Document Page\"\nmsgstr \"문서 페이지 OCR 방법\"\n\n#: ../../recipes-ocr.rst:43 9a152c4ead1343cf86489d1427003811\nmsgid \"\"\n\"Any supported document page can be OCR-ed -- either the complete page or \"\n\"only the image areas on it.\"\nmsgstr \"지원되는 모든 문서 페이지를 OCR할 수 있습니다. 페이지 전체 또는 해당 페이지의 이미지 영역만 OCR할 수 있습니다.\"\n\n#: ../../recipes-ocr.rst:45 75c8b08c675a49f2bf0d5425b06d171a\nmsgid \"\"\n\"Because optical character recognition is about one thousand times slower \"\n\"than standard text extraction, we make sure to do OCR only once per page \"\n\"and store the result in a :ref:`TextPage`. Using this TextPage for all \"\n\"subsequent extractions and text searches will then happen with \"\n\"|PyMuPDF|'s usual top speed.\"\nmsgstr \"광학 문자 인식은 표준 텍스트 추출보다 약 1,000배 느리기 때문에, 페이지당 한 번만 OCR을 수행하고 결과를 :ref:`TextPage` 에 저장합니다. 이후 모든 추출 및 텍스트 검색에 이 TextPage를 사용하면 |PyMuPDF| 의 일반적인 최고 속도로 처리됩니다.\"\n\n#: ../../recipes-ocr.rst:47 96c380b987f94acbbfb8ac4450e43dce\nmsgid \"To OCR a document page, follow this approach:\"\nmsgstr \"문서 페이지를 OCR하려면 다음 방법을 따르세요:\"\n\n#: ../../recipes-ocr.rst:49 39681da9450c49058ca2763173465812\nmsgid \"\"\n\"Determine whether OCR is needed / beneficial at all. A number of criteria\"\n\" can be used for this decision, like:\"\nmsgstr \"OCR이 필요한지/유익한지 판단하세요. 다음과 같은 여러 기준을 사용할 수 있습니다:\"\n\n#: ../../recipes-ocr.rst:51 671903164c6c495da5a353e4d7e1a112\nmsgid \"page is completely covered by an image\"\nmsgstr \"페이지가 이미지로 완전히 덮여 있음\"\n\n#: ../../recipes-ocr.rst:52 67a0e6d81030439db6adb2f9c61737d4\nmsgid \"no text exists on the page\"\nmsgstr \"페이지에 텍스트가 없음\"\n\n#: ../../recipes-ocr.rst:53 95a2141830a64bd6b31d96005eb2207b\nmsgid \"thousands of small vector graphics (indicating *simulated* text)\"\nmsgstr \"수천 개의 작은 벡터 그래픽(*시뮬레이션된* 텍스트를 나타냄)\"\n\n#: ../../recipes-ocr.rst:55 a56ae19e7c8a4d0bb37016395d9ab63c\nmsgid \"\"\n\"OCR the page and store result in a :ref:`TextPage` object using an \"\n\"instruction like `tp = page.get_textpage_ocr(...)`.\"\nmsgstr \"`tp = page.get_textpage_ocr(...)` 와 같은 명령을 사용하여 페이지를 OCR하고 결과를 :ref:`TextPage` 객체에 저장합니다.\"\n\n#: ../../recipes-ocr.rst:57 4e0d85d010b04df58a9c1169c5d8b553\nmsgid \"\"\n\"Refer to the produced :ref:`TextPage` in all subsequent text extractions \"\n\"and searches via the `textpage=tp` parameter.\"\nmsgstr \"이후 모든 텍스트 추출 및 검색에서 `textpage=tp` 매개변수를 통해 생성된 :ref:`TextPage` 를 참조하세요.\"\n\n#: ../../footer.rst:46 1536d96897a04a48b4b90ead47380207\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-optional-content.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 f427b4b5c89c434aa431d0105a3b4ced\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 25ffbcd722b944a087a274a8e9d2f119\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 29a19d98cec64f3488930f81e11e93e7\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../recipes-optional-content.rst:7 700c319fd483491eb9c651ce164689cf\nmsgid \"Optional Content Support\"\nmsgstr \"선택적 콘텐츠 지원\"\n\n#: ../../recipes-optional-content.rst:9 5ecf5ebcfe42415bb96d754f39769237\nmsgid \"\"\n\"This document explains PyMuPDF's support of the PDF concept **\\\"Optional \"\n\"Content\\\"**.\"\nmsgstr \"이 문서는 |PyMuPDF| 가 지원하는 PDF 개념 **\\\"선택적 콘텐츠\\\"** 에 대해 설명합니다.\"\n\n#: ../../recipes-optional-content.rst:12 2d6ce70234fa4a51b645e6eb697c23c1\nmsgid \"Introduction: The Optional Content Concept\"\nmsgstr \"소개: 선택적 콘텐츠 개념\"\n\n#: ../../recipes-optional-content.rst:13 a1bba7af8cee41cabc8aa14f83c25097\nmsgid \"\"\n\"*Optional Content* in PDF is a way to show or hide parts of a document \"\n\"based on certain conditions: Parameters that can be set to ON or to OFF \"\n\"when using a supporting PDF consumer (viewer), or programmatically.\"\nmsgstr \"PDF의 *선택적 콘텐츠* 는 특정 조건에 따라 문서의 일부를 표시하거나 숨기는 방법입니다. 지원하는 PDF 소비자(뷰어)를 사용할 때 또는 프로그래밍 방식으로 ON 또는 OFF로 설정할 수 있는 매개변수입니다.\"\n\n#: ../../recipes-optional-content.rst:15 cab765ef09a444c5baccc6ecba041e6e\nmsgid \"\"\n\"This capability is useful in items such as CAD drawings, layered artwork,\"\n\" maps, and multi-language documents. Typical uses include showing or \"\n\"hiding details of complex vector graphics like geographical maps, \"\n\"technical devices, architectural designs and similar, including \"\n\"automatically switching between different zooming levels. Other use cases\"\n\" may be to automatically show different detail levels when displaying a \"\n\"document on screen as opposed to printing it.\"\nmsgstr \"이 기능은 CAD 도면, 레이어 아트워크, 지도, 다국어 문서와 같은 항목에서 유용합니다. 일반적인 용도에는 지리적 지도, 기술 장치, 건축 설계 등과 같은 복잡한 벡터 그래픽의 세부 정보 표시 또는 숨기기, 다양한 확대/축소 수준 간의 자동 전환이 포함됩니다. 다른 사용 사례는 문서를 인쇄하는 것과 달리 화면에 표시할 때 자동으로 다른 세부 수준을 표시하는 것일 수 있습니다.\"\n\n#: ../../recipes-optional-content.rst:17 a3cf8bb5edc04658bcc5b018e1302847\nmsgid \"\"\n\"Special PDF objects, so-called **Optional Content Groups** (OCGs) are \"\n\"used to define these different *layers* of content.\"\nmsgstr \"특수 PDF 객체인 **선택적 콘텐츠 그룹** (OCG)을 사용하여 이러한 다양한 콘텐츠 *레이어* 를 정의합니다.\"\n\n#: ../../recipes-optional-content.rst:19 11067de9260f444189d97ae6ae624654\nmsgid \"\"\n\"Assigning an OCG to a \\\"normal\\\" PDF object (like a text or an image) \"\n\"causes that object to be visible or hidden, depending on the current \"\n\"state of the assigned OCG.\"\nmsgstr \"OCG를 \\\"일반\\\" PDF 객체(텍스트 또는 이미지 등)에 할당하면 할당된 OCG의 현재 상태에 따라 해당 객체가 표시되거나 숨겨집니다.\"\n\n#: ../../recipes-optional-content.rst:21 95e830e21e764c0a949cb7ed0a33fc95\nmsgid \"\"\n\"To ease definition of the overall configuration of a PDF's Optional \"\n\"Content, OCGs can be organized in higher level groupings, called **OC \"\n\"Configurations**. Each configuration being a collection of OCGs, together\"\n\" with each OCG's desired initial visibility state. Selecting one of these\"\n\" configurations (via the PDF viewer or programmatically) causes a \"\n\"corresponding visibility change of all affected PDF objects throughout \"\n\"the document.\"\nmsgstr \"PDF의 선택적 콘텐츠 전체 구성을 쉽게 정의하기 위해 OCG는 **OC 구성** 이라는 상위 수준 그룹으로 구성할 수 있습니다. 각 구성은 각 OCG의 원하는 초기 표시 상태와 함께 OCG 컬렉션입니다. 이러한 구성 중 하나를 선택하면(PDF 뷰어를 통해 또는 프로그래밍 방식으로) 문서 전체에서 영향을 받는 모든 PDF 객체의 표시 상태가 해당 상태로 변경됩니다.\"\n\n#: ../../recipes-optional-content.rst:23 b707fd22852842e89a0e8e78a296ef39\nmsgid \"Except for the default one, OC Configurations are optional.\"\nmsgstr \"기본 구성 외에는 OC 구성은 선택 사항입니다.\"\n\n#: ../../recipes-optional-content.rst:25 0844d7f44e964e409fefe8c054f52b6d\nmsgid \"\"\n\"For more explanations and additional background please refer to PDF \"\n\"specification manuals.\"\nmsgstr \"자세한 설명과 추가 배경 정보는 PDF 사양 매뉴얼을 참조하세요.\"\n\n#: ../../recipes-optional-content.rst:28 6133510bc73140a4b17bbf8cda929189\nmsgid \"PyMuPDF Support for PDF Optional Content\"\nmsgstr \"PDF 선택적 콘텐츠에 대한 |PyMuPDF| 지원\"\n\n#: ../../recipes-optional-content.rst:29 ee3f36d2819e41d2aeabc811bdfcddb2\nmsgid \"\"\n\"PyMuPDF offers full support for viewing, defining, changing and deleting \"\n\"Option Content Groups, Configurations, maintaining the assignment of OCGs\"\n\" to PDF objects and programmatically switching between OC Configurations \"\n\"and the visibility states of each single OCG.\"\nmsgstr \"|PyMuPDF| 는 선택적 콘텐츠 그룹 및 구성의 보기, 정의, 변경, 삭제, OCG를 PDF 객체에 할당하는 것의 유지, OC 구성 간의 프로그래밍 방식 전환 및 각 단일 OCG의 표시 상태에 대한 완전한 지원을 제공합니다.\"\n\n#: ../../recipes-optional-content.rst:32 6c810e8459dd45b499132c9ef8a2ec30\nmsgid \"How to Add Optional Content\"\nmsgstr \"선택적 콘텐츠 추가 방법\"\n\n#: ../../recipes-optional-content.rst:33 ddc6af20e120444c8d6bcbef96f4ab41\nmsgid \"\"\n\"This is as simple as adding an Optional Content Group, OCG, to a PDF: \"\n\":meth:`Document.add_ocg`.\"\nmsgstr \"PDF에 선택적 콘텐츠 그룹(OCG)을 추가하는 것만큼 간단합니다: :meth:`Document.add_ocg`.\"\n\n#: ../../recipes-optional-content.rst:35 247da2498372479cbcf5c1e211c93b70\nmsgid \"\"\n\"If previously the PDF had no OC support at all, the required setup (like \"\n\"defining the default OC Configuration) will be done at this point \"\n\"automatically.\"\nmsgstr \"이전에 PDF에 OC 지원이 전혀 없었다면, 필요한 설정(기본 OC 구성 정의 등)이 이 시점에서 자동으로 수행됩니다.\"\n\n#: ../../recipes-optional-content.rst:37 f3673e60584d40d08730a4d5183a4393\nmsgid \"\"\n\"The method returns an :data:`xref` of the created OCG. Use this xref to \"\n\"associate (mark) any PDF object with it, that you want to make dependent \"\n\"on this OCG's state. For example, you can insert an image on a page and \"\n\"refer to the xref like this::\"\nmsgstr \"이 메서드는 생성된 OCG의 :data:`xref` 를 반환합니다. 이 xref를 사용하여 이 OCG의 상태에 종속되도록 만들고자 하는 모든 PDF 객체를 연결(표시)합니다. 예를 들어, 페이지에 이미지를 삽입하고 다음과 같이 xref를 참조할 수 있습니다::\"\n\n#: ../../recipes-optional-content.rst:41 f4a0a4f56cf343ce93de964daa847414\nmsgid \"\"\n\"If you want to put an **existing** image under the control of an OCG, you\"\n\" must first find out the image's xref number (called `img_xref` here) and\"\n\" then do `doc.set_oc(img_xref, xref)`. After this, the image will be \"\n\"(in-) visible everywhere throughout the document if the OCG's state is \"\n\"\\\"ON\\\", respectively \\\"OFF\\\". You can also assign a different OCG with \"\n\"this method.\"\nmsgstr \"**기존** 이미지를 OCG의 제어 하에 두려면 먼저 이미지의 xref 번호(여기서는 `img_xref` 라고 함)를 찾은 다음 `doc.set_oc(img_xref, xref)` 를 수행해야 합니다. 그 후 OCG의 상태가 \\\"ON\\\" 또는 \\\"OFF\\\"이면 이미지는 문서 전체에서 (비)표시됩니다. 이 메서드를 사용하여 다른 OCG를 할당할 수도 있습니다.\"\n\n#: ../../recipes-optional-content.rst:43 876cc7ea11954c498741a87e7e7f2e81\nmsgid \"To **remove** an OCG from an image, do `doc.set_oc(img_xref, 0)`.\"\nmsgstr \"이미지에서 OCG를 **제거** 하려면 `doc.set_oc(img_xref, 0)` 를 수행하세요.\"\n\n#: ../../recipes-optional-content.rst:45 148754aebd804196a3832628dcd22df6\nmsgid \"\"\n\"One single OCG can be assigned to multiple PDF objects to control their \"\n\"visibility.\"\nmsgstr \"단일 OCG를 여러 PDF 객체에 할당하여 표시 여부를 제어할 수 있습니다.\"\n\n#: ../../recipes-optional-content.rst:48 654180253edf46a797c215677cb22eba\nmsgid \"How to Define Complex Optional Content Conditions\"\nmsgstr \"복잡한 선택적 콘텐츠 조건 정의 방법\"\n\n#: ../../recipes-optional-content.rst:50 be5af920b1f64a559cac7f324ea6f913\nmsgid \"\"\n\"Sophisticated logical conditions can be established to address complex \"\n\"visibility needs.\"\nmsgstr \"복잡한 표시 요구사항을 해결하기 위해 정교한 논리 조건을 설정할 수 있습니다.\"\n\n#: ../../recipes-optional-content.rst:52 78345b4a7695447a871af9b3d7dc1352\nmsgid \"\"\n\"For example, you might want to create a multi-language document, so the \"\n\"user may switch between languages as required.\"\nmsgstr \"예를 들어, 사용자가 필요에 따라 언어를 전환할 수 있도록 다국어 문서를 만들 수 있습니다.\"\n\n#: ../../recipes-optional-content.rst:54 2975f48b256e4d7f954291ed0f71b2e4\nmsgid \"Please have a look at `this Jupyter Notebook`_ and execute it as desired.\"\nmsgstr \"`이 Jupyter Notebook`_ 을 확인하고 원하는 대로 실행하세요.\"\n\n#: ../../recipes-optional-content.rst:56 5a66d6db462b491488acb6e94488a590\nmsgid \"\"\n\"Certainly, your requirements may even be more complex and involve \"\n\"multiple OCGs with ON/OFF states that are connected by some kind of \"\n\"logical relationship -- but it should give you an impression of what is \"\n\"possible and how to plan your next steps.\"\nmsgstr \"물론 요구사항이 더 복잡할 수 있으며 논리적 관계로 연결된 여러 ON/OFF 상태의 OCG를 포함할 수 있지만, 가능한 것과 다음 단계를 계획하는 방법에 대한 인상을 제공해야 합니다.\"\n\n#: ../../footer.rst:46 348e850342ec47b1a57c9045cb6713c3\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-stories.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b5d193bc1b274d55b812ca653ec68fad\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 2bc267634e2a46b2a13b54c6aadda8c0\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 1629ae10629c4c9fbbd1776a5b603010\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../recipes-stories.rst:18 8314345d0647437d82e4ab3dfd98d5d1\nmsgid \"Stories\"\nmsgstr \"Stories\"\n\n#: ../../recipes-stories.rst:20 595796cef87c4b7ab7031798c86047a5\nmsgid \"\"\n\"This document showcases some typical use cases for \"\n\":ref:`Stories<WorkingWithStories>`.\"\nmsgstr \"이 문서는 :ref:`Stories<WorkingWithStories>` 의 일반적인 사용 사례를 보여줍니다.\"\n\n#: ../../recipes-stories.rst:22 995d0e959c2c43259e09def294ea1759\nmsgid \"\"\n\"As mentioned in the :ref:`tutorial<WorkingWithStories>`, stories may be \"\n\"created using up to three input sources: HTML, CSS and Archives -- all of\"\n\" which are optional and which, respectively, can be provided \"\n\"programmatically.\"\nmsgstr \":ref:`튜토리얼<WorkingWithStories>` 에서 언급한 대로, 스토리는 최대 세 가지 입력 소스(HTML, CSS 및 Archives)를 사용하여 생성할 수 있습니다. 모두 선택 사항이며 각각 프로그래밍 방식으로 제공할 수 있습니다.\"\n\n#: ../../recipes-stories.rst:24 f48c55a3c4bd4c2f81e39c6ed5117f22\nmsgid \"The following examples will showcase combinations for using these inputs.\"\nmsgstr \"다음 예제는 이러한 입력을 사용하는 조합을 보여줍니다.\"\n\n#: ../../recipes-stories.rst:28 f931abd31c8f473b8a30402b72d2037a\nmsgid \"\"\n\"Many of these recipe's source code are included as examples in the `docs`\"\n\" folder.\"\nmsgstr \"이러한 레시피의 많은 소스 코드가 `docs` 폴더의 예제로 포함되어 있습니다.\"\n\n#: ../../recipes-stories.rst:34 052173f8f2be4dc9938bc267e8d774b8\nmsgid \"How to Add a Line of Text with Some Formatting\"\nmsgstr \"일부 서식이 있는 텍스트 줄 추가 방법\"\n\n#: ../../recipes-stories.rst:36 eeb1b6e720474b3ba8158d228da8e939\nmsgid \"Here is the inevitable \\\"Hello World\\\" example. We will show two variants:\"\nmsgstr \"다음은 필수적인 \\\"Hello World\\\" 예제입니다. 두 가지 변형을 보여드리겠습니다:\"\n\n#: ../../recipes-stories.rst:38 c71486f3b5194a389a39bbe61b8a3dd8\nmsgid \"Create using existing HTML source [#f1]_, that may come from anywhere.\"\nmsgstr \"어디서든 올 수 있는 기존 HTML 소스 [#f1]_를 사용하여 생성합니다.\"\n\n#: ../../recipes-stories.rst:39 3477752d744d4d17972620ffab3621ae\nmsgid \"Create using the Python API.\"\nmsgstr \"Python API를 사용하여 생성합니다.\"\n\n#: ../../recipes-stories.rst:43 a4855e116ed84da28c0c7f0adb1ba452\nmsgid \"\"\n\"Variant using an existing HTML source [#f1]_ -- which in this case is \"\n\"defined as a constant in the script::\"\nmsgstr \"기존 HTML 소스 [#f1]_를 사용하는 변형 -- 이 경우 스크립트에서 상수로 정의됩니다::\"\n\n#: ../../recipes-stories.rst:69 54989c4eb624422c9343633c849a172d\nmsgid \"\"\n\"The above effect (sans-serif and blue text) could have been achieved by \"\n\"using a separate CSS source like so::\"\nmsgstr \"위의 효과(산세리프 및 파란색 텍스트)는 다음과 같이 별도의 CSS 소스를 사용하여 달성할 수 있었습니다::\"\n\n#: ../../recipes-stories.rst:90 d640d05290e44092bef652b25473bfae\nmsgid \"The Python API variant -- everything is created programmatically::\"\nmsgstr \"Python API 변형 -- 모든 것이 프로그래밍 방식으로 생성됩니다::\"\n\n#: ../../recipes-stories.rst:114 8e4d50be827247b7974656d7de688f75\nmsgid \"Both variants will produce the same output PDF.\"\nmsgstr \"두 변형 모두 동일한 출력 PDF를 생성합니다.\"\n\n#: ../../recipes-stories.rst:122 069e5a16feed4b3ba04b7f545ff25868\nmsgid \"How to use Images\"\nmsgstr \"이미지 사용 방법\"\n\n#: ../../recipes-stories.rst:124 d14be063cc6f47e89f14211f41113abb\nmsgid \"\"\n\"Images can be referenced in the provided HTML source, or the reference to\"\n\" a desired image can also be stored via the Python API. In any case, this\"\n\" requires using an :ref:`Archive`, which refers to the place where the \"\n\"image can be found.\"\nmsgstr \"\"\n\"이미지는 제공된 HTML 소스에서 참조할 수 있거나, 원하는 이미지에 대한 참조를 Python API를 통해 저장할 수도 \"\n\"있습니다. 어떤 경우든 이미지를 찾을 수 있는 위치를 가리키는 :ref:`Archive` 를 사용해야 합니다.\"\n\n#: ../../recipes-stories.rst:126 097753bc282141dc9c12d4462a635a6a\nmsgid \"\"\n\"Images with the binary content embedded in the HTML source are **not \"\n\"supported** by stories.\"\nmsgstr \"HTML 소스에 바이너리 콘텐츠가 포함된 이미지는 스토리에서 **지원되지 않습니다**.\"\n\n#: ../../recipes-stories.rst:128 5325dfa364c947ee83aa589fc95cff1e\nmsgid \"\"\n\"We extend our \\\"Hello World\\\" example from above and display an image of \"\n\"our planet right after the text. Assuming the image has the name \"\n\"\\\"world.jpg\\\" and is present in the script's folder, then this is the \"\n\"modified version of the above Python API variant::\"\nmsgstr \"\"\n\"위의 \\\"Hello World\\\" 예제를 확장하여 텍스트 바로 다음에 지구 이미지를 표시합니다. 이미지 이름이 \"\n\"\\\"world.jpg\\\"이고 스크립트 폴더에 있다고 가정하면, 다음은 위의 Python API 변형의 수정된 버전입니다::\"\n\n#: ../../recipes-stories.rst:168 615eea37135744afb2f7306c69fcfa53\nmsgid \"How to Read External HTML and CSS for a Story\"\nmsgstr \"스토리를 위한 외부 HTML 및 CSS 읽기 방법\"\n\n#: ../../recipes-stories.rst:170 3e62969f6ef34607a59289d3c5a2b616\nmsgid \"These cases are fairly straightforward.\"\nmsgstr \"이러한 경우는 매우 간단합니다.\"\n\n#: ../../recipes-stories.rst:172 9e79a62cf0f8448594719c149f421fe4\nmsgid \"\"\n\"As a general recommendation, HTML and CSS sources should be **read as \"\n\"binary files** and decoded before using them in a story. The Python \"\n\"`pathlib.Path` provides convenient ways to do this::\"\nmsgstr \"\"\n\"일반적인 권장 사항으로, HTML 및 CSS 소스는 **바이너리 파일로 읽어서** 스토리에서 사용하기 전에 디코딩해야 합니다. \"\n\"Python `pathlib.Path` 는 이를 수행하는 편리한 방법을 제공합니다::\"\n\n#: ../../recipes-stories.rst:193 424a5680167f4243bfdae2bc11a6a865\nmsgid \"How to Output Database Content with Story Templates\"\nmsgstr \"스토리 템플릿으로 데이터베이스 콘텐츠 출력 방법\"\n\n#: ../../recipes-stories.rst:195 75230534b810462489a2c0543f108196\nmsgid \"\"\n\"This script demonstrates how to report SQL database content using an \"\n\"**HTML template**.\"\nmsgstr \"이 스크립트는 **HTML 템플릿** 을 사용하여 SQL 데이터베이스 콘텐츠를 보고하는 방법을 보여줍니다.\"\n\n#: ../../recipes-stories.rst:199 573a4db0337c431ba12822e512233a72\nmsgid \"The example SQL database contains two tables:\"\nmsgstr \"예제 SQL 데이터베이스에는 두 개의 테이블이 포함되어 있습니다:\"\n\n#: ../../recipes-stories.rst:201 d12453e5387d4c86aef125b1c917cdc5\nmsgid \"\"\n\"Table \\\"films\\\" contains one row per film with the fields **\\\"title\\\"**, \"\n\"**\\\"director\\\"** and (release) **\\\"year\\\"**.\"\nmsgstr \"\"\n\"테이블 \\\"films\\\" 는 필드 **\\\"title\\\"**, **\\\"director\\\"** 및 (개봉) **\\\"year\\\"** 가 있는 영화당 \"\n\"하나의 행을 포함합니다.\"\n\n#: ../../recipes-stories.rst:202 48c7c2781fa04d22ad47bdd68f0e7430\nmsgid \"\"\n\"Table \\\"actors\\\" contains one row per actor and film title (fields \"\n\"(actor) **\\\"name\\\"** and (film) **\\\"title\\\"**).\"\nmsgstr \"\"\n\"테이블 \\\"actors\\\" 는 배우 및 영화 제목당 하나의 행을 포함합니다(필드 (actor) **\\\"name\\\"** 및 (film) \"\n\"**\\\"title\\\"**).\"\n\n#: ../../recipes-stories.rst:204 29aa52738ef94cbfb71a5e58eb4207f9\nmsgid \"\"\n\"The story DOM consists of a template for one film, which reports film \"\n\"data together with a list of casted actors.\"\nmsgstr \"스토리 DOM은 하나의 영화에 대한 템플릿으로 구성되며, 영화 데이터와 출연 배우 목록을 함께 보고합니다.\"\n\n#: ../../recipes-stories.rst:206 ../../recipes-stories.rst:231\n#: ../../recipes-stories.rst:257 ../../recipes-stories.rst:309\n#: ../../recipes-stories.rst:343 ../../recipes-stories.rst:377\n#: ../../recipes-stories.rst:398 ../../recipes-stories.rst:433\n#: ../../recipes-stories.rst:467 ../../recipes-stories.rst:497\n#: ../../recipes-stories.rst:531 08c1a4e126cb48978f4f6d8d01328a9d\n#: 1f86ef58d3744dc6b95fcda088603493 252df0b354254037b866b630e74e2da8\n#: 4e6c2eefb4e04eb1af7f436651caf09b 703c6ee5dcb04da88e0551d3b09617ad\n#: 7ab440172c9b492d83a77e8c6b3a5ce3 7e9d0135ecac455194beff5db8e97383\n#: c3d8138b12a64495b66fc448295bdf87 d783b1de9b01428d87a0f12d8bc86213\n#: e6786c9897324e95a0694f81946c35c6 f4a5a290b11645758f555fb83ad91ec4\nmsgid \"**Files:**\"\nmsgstr \"**파일:**\"\n\n#: ../../recipes-stories.rst:208 76f13a564fe44af38d30607e6903e0e8\nmsgid \"`docs/samples/filmfestival-sql.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:209 0011f520db504866869f4fc79f37465a\nmsgid \"`docs/samples/filmfestival-sql.db`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:212 ../../recipes-stories.rst:235\n#: ../../recipes-stories.rst:263 ../../recipes-stories.rst:316\n#: ../../recipes-stories.rst:347 ../../recipes-stories.rst:360\n#: ../../recipes-stories.rst:381 ../../recipes-stories.rst:402\n#: ../../recipes-stories.rst:437 ../../recipes-stories.rst:471\n#: ../../recipes-stories.rst:501 ../../recipes-stories.rst:535\n#: 1d8920d6cfac4577be9b37a82329452a 278a24defbbf496193211fdfb1c2a54a\n#: 40ab396528814a3fac246a5a00c34f65 5723b2a904ba47b9860b557379721ae1\n#: 9707ab332af04a1a9cb72a3ab89fffd3 9ea47fe98a8844ffaf1223a3e33e1bb8\n#: ae83566d84a2413980f2a252c0940048 be88afb45b4948b18b486920f53daf2e\n#: c004e3f49ac3466c8c9ef9888157f02d c942e3a7452248f58a5bddc23570027c\n#: f3dbc504b00e4947ac703f22b8109786 f8ece455a9d6481eae9b3f6faac7ac53\nmsgid \"|toggleStart|\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:216 ../../recipes-stories.rst:239\n#: ../../recipes-stories.rst:267 ../../recipes-stories.rst:320\n#: ../../recipes-stories.rst:351 ../../recipes-stories.rst:364\n#: ../../recipes-stories.rst:385 ../../recipes-stories.rst:406\n#: ../../recipes-stories.rst:441 ../../recipes-stories.rst:475\n#: ../../recipes-stories.rst:505 ../../recipes-stories.rst:539\n#: 092f94a8817948c8abafc3734fcf198b 4a98f729722249cd982f858648efc237\n#: 62d1782a6ea04c2db57ab1ee0ca4fe5f 8ba4cffc6b654792918dc7b1dd969a30\n#: 8c53e41912464fc1be6bbe4c83f4028f 9ddbc2dae3a649e1ba30b92fc174fbe4\n#: caf97ca2ef514514bc825397ac3bf0d9 e3ff13ae3b40495fabcf13c543af9d12\n#: eaf1260e02b949b79eed85f34153be91 ec1850ab1501425c8a0bd816f0817878\n#: ef3d65dc1872490f8de2efc2cc2a90b2 fef63adfa7c341ffbbf5c7407c27a06f\nmsgid \"|toggleEnd|\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:225 18a13135616545bfad20fd11639e4c84\nmsgid \"How to Integrate with Existing PDFs\"\nmsgstr \"기존 PDF와 통합하는 방법\"\n\n#: ../../recipes-stories.rst:227 f03491738dc64176a90468adac627ab0\nmsgid \"\"\n\"Because a :ref:`DocumentWriter` can only write to a new file, stories \"\n\"cannot be placed on existing pages. This script demonstrates a \"\n\"circumvention of this restriction.\"\nmsgstr \"\"\n\":ref:`DocumentWriter` 는 새 파일에만 쓸 수 있으므로 스토리는 기존 페이지에 배치할 수 없습니다. 이 스크립트는 \"\n\"이 제한을 우회하는 방법을 보여줍니다.\"\n\n#: ../../recipes-stories.rst:229 96c37297327d48c0bd3a2b2e00278cee\nmsgid \"\"\n\"The basic idea is letting :ref:`DocumentWriter` output to a PDF in \"\n\"memory. Once the story has finished, we re-open this memory PDF and put \"\n\"its pages to desired locations on **existing** pages via method \"\n\":meth:`Page.show_pdf_page`.\"\nmsgstr \"\"\n\"기본 아이디어는 :ref:`DocumentWriter` 가 메모리의 PDF에 출력하도록 하는 것입니다. 스토리가 완료되면 이 메모리 \"\n\"PDF를 다시 열고 :meth:`Page.show_pdf_page` 메서드를 통해 **기존** 페이지의 원하는 위치에 페이지를 \"\n\"배치합니다.\"\n\n#: ../../recipes-stories.rst:233 4f5ee88727ea49c296c840ca51c75e45\nmsgid \"`docs/samples/showpdf-page.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:248 563332f15b53462da0c68cde0c1beb09\nmsgid \"\"\n\"How to Make Multi-Columned Layouts and Access Fonts from Package \"\n\"`pymupdf-fonts`_\"\nmsgstr \"다단 레이아웃 만들기 및 패키지 `pymupdf-fonts`_ 에서 폰트 액세스 방법\"\n\n#: ../../recipes-stories.rst:250 c67e2e9e13c4449cb12ec6a84c9d23ea\nmsgid \"\"\n\"This script outputs an article (taken from Wikipedia) that contains text \"\n\"and multiple images and uses a 2-column page layout.\"\nmsgstr \"이 스크립트는 텍스트와 여러 이미지를 포함하는 기사(Wikipedia에서 가져옴)를 출력하며 2단 페이지 레이아웃을 사용합니다.\"\n\n#: ../../recipes-stories.rst:252 e5c809facc4047608e51c439efe8f7a6\nmsgid \"\"\n\"In addition, two \\\"Ubuntu\\\" font families from package `pymupdf-fonts`_ \"\n\"are used instead of defaulting to Base-14 fonts.\"\nmsgstr \"\"\n\"또한 패키지 `pymupdf-fonts`_ 에서 두 개의 \\\"Ubuntu\\\" 폰트 패밀리가 Base-14 폰트를 기본값으로 사용하는 대신 \"\n\"사용됩니다.\"\n\n#: ../../recipes-stories.rst:254 710ea657eaed417790c2b2e1408ff46a\nmsgid \"\"\n\"Yet another feature used here is that all data -- the images and the \"\n\"article HTML -- are jointly stored in a ZIP file.\"\nmsgstr \"여기서 사용되는 또 다른 기능은 모든 데이터(이미지 및 기사 HTML)가 ZIP 파일에 함께 저장된다는 것입니다.\"\n\n#: ../../recipes-stories.rst:259 baca45cc5cea40718096fd055c4c6f29\nmsgid \"`docs/samples/quickfox.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:260 ../../recipes-stories.rst:313\n#: 279ba9d3da96462d9521b6401f261ffc 79489cda481541c5af08712bcd696dcf\nmsgid \"`docs/samples/quickfox.zip`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:276 0f2bd834af8f474bb16581d5edd338b8\nmsgid \"How to Make a Layout which Wraps Around a Predefined \\\"no go area\\\" Layout\"\nmsgstr \"사전 정의된 \\\"금지 영역\\\" 레이아웃 주위로 감싸는 레이아웃 만들기 방법\"\n\n#: ../../recipes-stories.rst:279 dbd26e7d6a2f4abaa6462e796a1208bb\nmsgid \"\"\n\"This is a demo script using PyMuPDF's Story class to output text as a PDF\"\n\" with a two-column page layout.\"\nmsgstr \"이것은 |PyMuPDF| 의 Story 클래스를 사용하여 텍스트를 2단 페이지 레이아웃으로 PDF로 출력하는 데모 스크립트입니다.\"\n\n#: ../../recipes-stories.rst:282 2eb13f3738a8491b97fe654a99f8ce3a\nmsgid \"The script demonstrates the following features:\"\nmsgstr \"스크립트는 다음 기능을 보여줍니다:\"\n\n#: ../../recipes-stories.rst:284 25765b0dd11a43508066ab08e902d66f\nmsgid \"Layout text around images of an existing (\\\"target\\\") PDF.\"\nmsgstr \"기존(\\\"대상\\\") PDF의 이미지 주위에 텍스트 레이아웃.\"\n\n#: ../../recipes-stories.rst:285 e472244ac7ad455690ffc3c6049d7bc3\nmsgid \"\"\n\"Based on a few global parameters, areas on each page are identified, that\"\n\" can be used to receive text layouted by a Story.\"\nmsgstr \"몇 가지 전역 매개변수를 기반으로 각 페이지의 영역이 식별되며, 이 영역은 Story에 의해 레이아웃된 텍스트를 받는 데 사용할 수 있습니다.\"\n\n#: ../../recipes-stories.rst:287 51459bb508b34fa1adb8a3b05cb25082\nmsgid \"\"\n\"These global parameters are not stored anywhere in the target PDF and \"\n\"must therefore be provided in some way:\"\nmsgstr \"이러한 전역 매개변수는 대상 PDF의 어디에도 저장되지 않으므로 어떤 방식으로든 제공되어야 합니다:\"\n\n#: ../../recipes-stories.rst:290 9c4f7ed7210f4d129f08fc68b1449c1b\nmsgid \"The width of the border(s) on each page.\"\nmsgstr \"각 페이지의 테두리 너비.\"\n\n#: ../../recipes-stories.rst:291 2adfda4cd7994235b17faaaa456c4645\nmsgid \"\"\n\"The fontsize to use for text. This value determines whether the provided \"\n\"text will fit in the empty spaces of the (fixed) pages of target PDF. It \"\n\"cannot be predicted in any way. The script ends with an exception if \"\n\"target PDF has not enough pages, and prints a warning message if not all \"\n\"pages receive at least some text. In both cases, the FONTSIZE value can \"\n\"be changed (a float value).\"\nmsgstr \"\"\n\"텍스트에 사용할 글꼴 크기. 이 값은 제공된 텍스트가 대상 PDF의 (고정된) 페이지의 빈 공간에 맞는지 여부를 결정합니다. 어떤 \"\n\"방식으로도 예측할 수 없습니다. 대상 PDF에 페이지가 충분하지 않으면 스크립트는 예외로 종료되고, 모든 페이지가 최소한 일부 텍스트를 \"\n\"받지 못하면 경고 메시지를 인쇄합니다. 두 경우 모두 FONTSIZE 값을 변경할 수 있습니다(부동 소수점 값).\"\n\n#: ../../recipes-stories.rst:297 ef8d9dc888f04ea18e29d8deec8eebc7\nmsgid \"Use of a 2-column page layout for the text.\"\nmsgstr \"텍스트에 2단 페이지 레이아웃 사용.\"\n\n#: ../../recipes-stories.rst:298 0dc84c7986d740dea5c0d99ee3cd5965\nmsgid \"\"\n\"The layout creates a temporary (memory) PDF. Its produced page content \"\n\"(the text) is used to overlay the corresponding target page. If text \"\n\"requires more pages than are available in target PDF, an exception is \"\n\"raised. If not all target pages receive at least some text, a warning is \"\n\"printed.\"\nmsgstr \"\"\n\"레이아웃은 임시(메모리) PDF를 생성합니다. 생성된 페이지 콘텐츠(텍스트)는 해당 대상 페이지에 오버레이하는 데 사용됩니다. 텍스트가 \"\n\"대상 PDF에서 사용 가능한 페이지보다 더 많은 페이지를 필요로 하면 예외가 발생합니다. 모든 대상 페이지가 최소한 일부 텍스트를 받지 \"\n\"못하면 경고가 인쇄됩니다.\"\n\n#: ../../recipes-stories.rst:302 76e3c6f16fca4501a3d6b09051f5c6fc\nmsgid \"\"\n\"The script reads \\\"image-no-go.pdf\\\" in its own folder. This is the \"\n\"\\\"target\\\" PDF. It contains 2 pages with each 2 images (from the original\"\n\" article), which are positioned at places that create a broad overall \"\n\"test coverage. Otherwise the pages are empty.\"\nmsgstr \"\"\n\"스크립트는 자체 폴더에서 \\\"image-no-go.pdf\\\" 를 읽습니다. 이것이 \\\"대상\\\" PDF입니다. 원본 기사에서 각각 2개의 \"\n\"이미지가 있는 2페이지를 포함하며, 광범위한 전체 테스트 커버리지를 만드는 위치에 배치됩니다. 그렇지 않으면 페이지가 비어 있습니다.\"\n\n#: ../../recipes-stories.rst:306 5feb7616d6454982b6c9c0803bed70ec\nmsgid \"\"\n\"The script produces \\\"quickfox-image-no-go.pdf\\\" which contains the \"\n\"original pages and image positions, but with the original article text \"\n\"laid out around them.\"\nmsgstr \"\"\n\"스크립트는 원본 페이지와 이미지 위치를 포함하지만 원본 기사 텍스트가 그 주위에 배치된 \\\"quickfox-image-no-go.pdf\\\" \"\n\"를 생성합니다.\"\n\n#: ../../recipes-stories.rst:311 2d87632d8f7d4b999f854a81b2e80541\nmsgid \"`docs/samples/quickfox-image-no-go.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:312 cab8c8e6552e4a2f88203240822139a2\nmsgid \"`docs/samples/quickfox-image-no-go.pdf`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:329 07ad707123e64f328f43969ff77a58f7\nmsgid \"How to Output an HTML Table\"\nmsgstr \"HTML 테이블 출력 방법\"\n\n#: ../../recipes-stories.rst:331 6cd7587dab1f4b6aa7013a9ab05d5131\nmsgid \"Outputting HTML tables is supported as follows:\"\nmsgstr \"HTML 테이블 출력은 다음과 같이 지원됩니다:\"\n\n#: ../../recipes-stories.rst:333 a094cc112239433e8f1c4e235bd1c1d7\nmsgid \"\"\n\"Flat table layouts are supported (\\\"rows x columns\\\"), no support of the \"\n\"\\\"colspan\\\" / \\\"rowspan\\\" attributes.\"\nmsgstr \"평면 테이블 레이아웃(\\\"행 x 열\\\")이 지원되며, \\\"colspan\\\" / \\\"rowspan\\\" 속성은 지원되지 않습니다.\"\n\n#: ../../recipes-stories.rst:334 3e3366cef2bc44d29a1f557f36e98bd3\nmsgid \"\"\n\"Table header tag :htmlTag:`th` supports attribute \\\"scope\\\" with values \"\n\"\\\"row\\\" or \\\"col\\\". Applicable text will be bold by default.\"\nmsgstr \"\"\n\"테이블 헤더 태그 :htmlTag:`th` 는 값이 \\\"row\\\" 또는 \\\"col\\\" 인 \\\"scope\\\" 속성을 지원합니다. 적용 가능한 \"\n\"텍스트는 기본적으로 굵게 표시됩니다.\"\n\n#: ../../recipes-stories.rst:335 533fc1b4bbf248e2b203786ae6c443b7\nmsgid \"\"\n\"Column widths are computed automatically based on column content. They \"\n\"cannot be directly set.\"\nmsgstr \"열 너비는 열 콘텐츠를 기반으로 자동으로 계산됩니다. 직접 설정할 수 없습니다.\"\n\n#: ../../recipes-stories.rst:336 76c98b7342de4fd38e793274a40bfee5\nmsgid \"\"\n\"Table **cells may contain images** which will be considered in the column\"\n\" width calculation magic.\"\nmsgstr \"테이블 **셀에 이미지가 포함될 수 있으며** 열 너비 계산에 고려됩니다.\"\n\n#: ../../recipes-stories.rst:337 2444753418ed48efbdaf659f55ebd3d9\nmsgid \"\"\n\"Row heights are computed automatically based on row content - leading to \"\n\"multi-line rows where needed.\"\nmsgstr \"행 높이는 행 콘텐츠를 기반으로 자동으로 계산되어 필요한 경우 여러 줄 행이 생성됩니다.\"\n\n#: ../../recipes-stories.rst:338 c66ef7c08bce47369611cd47d34761ad\nmsgid \"\"\n\"The potentially multiple lines of a table row will always be kept \"\n\"together on one page (respectively \\\"where\\\" rectangle) and not be split.\"\nmsgstr \"\"\n\"테이블 행의 잠재적으로 여러 줄은 항상 한 페이지(각각 \\\"where\\\" 사각형)에 함께 유지되며 분할되지 않습니다.\"\n\n#: ../../recipes-stories.rst:339 88f98486ab714f12834b175e3270a938\nmsgid \"\"\n\"Table header rows are only **shown on the first page / \\\"where\\\" \"\n\"rectangle.**\"\nmsgstr \"테이블 헤더 행은 **첫 번째 페이지 / \\\"where\\\" 사각형에만 표시됩니다.**\"\n\n#: ../../recipes-stories.rst:340 10bdfdc885fb4f9297afc239193cbda7\nmsgid \"\"\n\"The \\\"style\\\" attribute is ignored when given directly in HTML table \"\n\"elements. Styling for a table and its elements must happen separately, in\"\n\" CSS source or within the :htmlTag:`style` tag.\"\nmsgstr \"\"\n\"\\\"style\\\" 속성은 HTML 테이블 요소에 직접 제공될 때 무시됩니다. 테이블과 그 요소의 스타일링은 CSS 소스 또는 \"\n\":htmlTag:`style` 태그 내에서 별도로 수행해야 합니다.\"\n\n#: ../../recipes-stories.rst:341 482d5b34b15a4a9c9f4b7ece5d79a9ce\nmsgid \"\"\n\"Styling for :htmlTag:`tr` elements is not supported and ignored. \"\n\"Therefore, a table-wide grid or alternating row background colors are not\"\n\" supported. One of the following example scripts however shows an easy \"\n\"way to deal with this limitation.\"\nmsgstr \"\"\n\":htmlTag:`tr` 요소의 스타일링은 지원되지 않으며 무시됩니다. 따라서 테이블 전체 그리드 또는 교대로 나타나는 행 배경색은 \"\n\"지원되지 않습니다. 그러나 다음 예제 스크립트 중 하나는 이 제한을 처리하는 쉬운 방법을 보여줍니다.\"\n\n#: ../../recipes-stories.rst:345 8345e9575f6844029b2999b8b6fed76f\nmsgid \"`docs/samples/table01.py` This script reflects basic features.\"\nmsgstr \"`docs/samples/table01.py` 이 스크립트는 기본 기능을 반영합니다.\"\n\n#: ../../recipes-stories.rst:353 e5188ccc429743cab9f17635eaab8002\nmsgid \"\"\n\"`docs/samples/national-capitals.py` Advanced script extending table \"\n\"output options using simple additional code:\"\nmsgstr \"`docs/samples/national-capitals.py` 간단한 추가 코드를 사용하여 테이블 출력 옵션을 확장하는 고급 스크립트:\"\n\n#: ../../recipes-stories.rst:355 d786bb83c47a488a86e7603d731dac6b\nmsgid \"Multi-page output simulating **repeating header rows**\"\nmsgstr \"**반복되는 헤더 행** 을 시뮬레이션하는 다중 페이지 출력\"\n\n#: ../../recipes-stories.rst:356 64263c3cea7742dcafd285f9c1d9a690\nmsgid \"Alternating table row background colors\"\nmsgstr \"교대로 나타나는 테이블 행 배경색\"\n\n#: ../../recipes-stories.rst:357 291f158657964fed93655aa568365aca\nmsgid \"Table rows and columns delimited by gridlines\"\nmsgstr \"격자선으로 구분된 테이블 행과 열\"\n\n#: ../../recipes-stories.rst:358 5f5af232f8f34e9f9f06b6bc48f9b935\nmsgid \"Table rows dynamically generated / filled with data from an SQL database\"\nmsgstr \"SQL 데이터베이스의 데이터로 동적으로 생성/채워진 테이블 행\"\n\n#: ../../recipes-stories.rst:373 8de5b747eeee4c49a2ff9b5f6659192a\nmsgid \"How to Create a Simple Grid Layout\"\nmsgstr \"간단한 그리드 레이아웃 만들기 방법\"\n\n#: ../../recipes-stories.rst:375 2f9c6ef2b7224c718c51897ec71e2722\nmsgid \"\"\n\"By creating a sequence of :ref:`Story` objects within a grid created via \"\n\"the :ref:`make_table<Functions_make_table>` function a developer can \"\n\"create grid layouts as required.\"\nmsgstr \"\"\n\":ref:`make_table<Functions_make_table>` 함수를 통해 생성된 그리드 내에서 :ref:`Story` 객체의 시퀀스를 \"\n\"만들면 개발자는 필요에 따라 그리드 레이아웃을 만들 수 있습니다.\"\n\n#: ../../recipes-stories.rst:379 ef7f8c1036ed43a287e48b4719422ffd\nmsgid \"`docs/samples/simple-grid.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:394 d33c94d00852413d800e1a8cc6dce372\nmsgid \"How to Generate a Table of Contents\"\nmsgstr \"목차 생성 방법\"\n\n#: ../../recipes-stories.rst:396 30c4a1111f18493d8276608dbce4e4cb\nmsgid \"\"\n\"This script lists the source code of all Python scripts that live in the \"\n\"script's directory.\"\nmsgstr \"이 스크립트는 스크립트 디렉토리에 있는 모든 Python 스크립트의 소스 코드를 나열합니다.\"\n\n#: ../../recipes-stories.rst:400 2b3106d169114915b35cfabdb62e4820\nmsgid \"`docs/samples/code-printer.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:409 b512515de19446c1b6c1d11c09f1d286\nmsgid \"It features the following capabilities:\"\nmsgstr \"다음 기능을 제공합니다:\"\n\n#: ../../recipes-stories.rst:411 d8bc94329c9d42799b70240e483a9535\nmsgid \"\"\n\"Automatic generation of a Table of Contents (TOC) on separately numbered \"\n\"pages at the start of the document - using a specialized :ref:`Story`.\"\nmsgstr \"\"\n\"문서 시작 부분에 별도로 번호가 매겨진 페이지에 목차(TOC) 자동 생성 - 특수화된 :ref:`Story` 를 사용합니다.\"\n\n#: ../../recipes-stories.rst:413 1b625819dde2421ca9d1f8556c5b03cd\nmsgid \"\"\n\"Use of 3 separate :ref:`Story` objects per page: header story, footer \"\n\"story and the story for printing the Python sources.\"\nmsgstr \"\"\n\"페이지당 3개의 별도 :ref:`Story` 객체 사용: 헤더 스토리, 푸터 스토리 및 Python 소스 인쇄용 스토리.\"\n\n#: ../../recipes-stories.rst:415 ba47006f7ad743bab33a577e74e7dac7\nmsgid \"\"\n\"The page **footer is automatically changed** to show the name of the \"\n\"current Python file.\"\nmsgstr \"페이지 **푸터가 자동으로 변경되어** 현재 Python 파일 이름을 표시합니다.\"\n\n#: ../../recipes-stories.rst:417 3723e3ea0ce3414c99483f90f6315678\nmsgid \"\"\n\"Use of :meth:`Story.element_positions` to collect the data for the TOC \"\n\"and for the dynamic adjustment of page footers. This is an example of a \"\n\"**bidirectional communication** between the story output process and the \"\n\"script.\"\nmsgstr \"\"\n\":meth:`Story.element_positions` 를 사용하여 TOC 데이터를 수집하고 페이지 푸터를 동적으로 조정합니다. 이것은 \"\n\"스토리 출력 프로세스와 스크립트 간의 **양방향 통신** 예제입니다.\"\n\n#: ../../recipes-stories.rst:419 5d56f451e2e44b589a69c8d6faa0dc16\nmsgid \"\"\n\"The main PDF with the Python sources is being written to memory by its \"\n\":ref:`DocumentWriter`. Another :ref:`Story` / :ref:`DocumentWriter` pair \"\n\"is then used to create a (memory) PDF for the TOC pages. Finally, both \"\n\"these PDFs are joined and the result stored to disk.\"\nmsgstr \"\"\n\"Python 소스가 포함된 메인 PDF는 :ref:`DocumentWriter` 에 의해 메모리에 기록됩니다. 그런 다음 다른 \"\n\":ref:`Story` / :ref:`DocumentWriter` 쌍을 사용하여 TOC 페이지용 (메모리) PDF를 만듭니다. 마지막으로 \"\n\"이 두 PDF가 결합되어 결과가 디스크에 저장됩니다.\"\n\n#: ../../recipes-stories.rst:428 3e0fa770cc3b415fa27affd8b6659042\nmsgid \"How to Display a List from JSON Data\"\nmsgstr \"JSON 데이터에서 목록 표시 방법\"\n\n#: ../../recipes-stories.rst:430 fc54ff1f63294ae3880c28ae96b73d3d\nmsgid \"\"\n\"This example takes some JSON data input which it uses to populate a \"\n\":ref:`Story`. It also contains some visual text formatting and shows how \"\n\"to add links.\"\nmsgstr \"\"\n\"이 예제는 :ref:`Story` 를 채우는 데 사용하는 일부 JSON 데이터 입력을 가져옵니다. 또한 일부 시각적 텍스트 서식이 \"\n\"포함되어 있으며 링크를 추가하는 방법을 보여줍니다.\"\n\n#: ../../recipes-stories.rst:435 96d6b1d5632348d8a2d1a067ea7b5e30\nmsgid \"`docs/samples/json-example.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:451 d389b54283c647c2aa18c6cac96e2679\nmsgid \"Using the Alternative :meth:`Story.write*()` functions\"\nmsgstr \"대체 :meth:`Story.write*()` 함수 사용\"\n\n#: ../../recipes-stories.rst:453 97c0d297b7de4f52be883dd1fe9ec6da\nmsgid \"\"\n\"The :meth:`Story.write*()` functions provide a different way to use the \"\n\":ref:`Story` functionality, removing the need for calling code to \"\n\"implement a loop that calls :meth:`Story.place()` and \"\n\":meth:`Story.draw()` etc, at the expense of having to provide at least a \"\n\"`rectfn()` callback.\"\nmsgstr \"\"\n\":meth:`Story.write*()` 함수는 :ref:`Story` 기능을 사용하는 다른 방법을 제공하여 호출 코드가 \"\n\":meth:`Story.place()` 및 :meth:`Story.draw()` 등을 호출하는 루프를 구현할 필요를 제거하지만, 최소한 \"\n\"`rectfn()` 콜백을 제공해야 합니다.\"\n\n#: ../../recipes-stories.rst:462 c5a3507786364d729ce97e31af0be224\nmsgid \"How to do Basic Layout with :meth:`Story.write()`\"\nmsgstr \":meth:`Story.write()` 로 기본 레이아웃 수행 방법\"\n\n#: ../../recipes-stories.rst:464 d1aac41eb76d486c8b6ef2a9bf8c1862\nmsgid \"\"\n\"This script lays out multiple copies of its own source code, into four \"\n\"rectangles per page.\"\nmsgstr \"이 스크립트는 자체 소스 코드의 여러 복사본을 페이지당 4개의 사각형으로 배치합니다.\"\n\n#: ../../recipes-stories.rst:469 0af6a8efdd4b4f829b827d3fdfe7b1a0\nmsgid \"`docs/samples/story-write.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:484 022633dfece24abd830b877bb6eb3083\nmsgid \"\"\n\"How to do Iterative Layout for a Table of Contents with \"\n\":meth:`Story.write_stabilized()`\"\nmsgstr \":meth:`Story.write_stabilized()` 로 목차 반복 레이아웃 수행 방법\"\n\n#: ../../recipes-stories.rst:486 cc0bf853cf404c9bbebe6a560eb9c1d7\nmsgid \"\"\n\"This script creates html content dynamically, adding a contents section \"\n\"based on :ref:`ElementPosition` items that have non-zero `.heading` \"\n\"values.\"\nmsgstr \"\"\n\"이 스크립트는 HTML 콘텐츠를 동적으로 생성하며, 0이 아닌 `.heading` 값을 가진 :ref:`ElementPosition` 항목을 \"\n\"기반으로 목차 섹션을 추가합니다.\"\n\n#: ../../recipes-stories.rst:489 99707707c94744dda5a7c265feb53666\nmsgid \"\"\n\"The contents section is at the start of the document, so modifications to\"\n\" the contents can change page numbers in the rest of the document, which \"\n\"in turn can cause page numbers in the contents section to be incorrect.\"\nmsgstr \"\"\n\"목차 섹션은 문서 시작 부분에 있으므로 목차에 대한 수정은 문서의 나머지 부분의 페이지 번호를 변경할 수 있으며, 이로 인해 목차 \"\n\"섹션의 페이지 번호가 잘못될 수 있습니다.\"\n\n#: ../../recipes-stories.rst:493 641abbf30eac459daee550983498c0d2\nmsgid \"\"\n\"So the script uses :meth:`Story.write_stabilized()` to repeatedly lay \"\n\"things out until things are stable.\"\nmsgstr \"따라서 스크립트는 :meth:`Story.write_stabilized()` 를 사용하여 안정화될 때까지 반복적으로 레이아웃을 수행합니다.\"\n\n#: ../../recipes-stories.rst:499 3be99332904c4113a7541cd214abf180\nmsgid \"`docs/samples/story-write-stabilized.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:514 524e644a3c994d5aa854cd8bddbe82d5\nmsgid \"\"\n\"How to do Iterative Layout and Create PDF Links with \"\n\":meth:`Story.write_stabilized_links()`\"\nmsgstr \":meth:`Story.write_stabilized_links()` 로 반복 레이아웃 및 PDF 링크 생성 방법\"\n\n#: ../../recipes-stories.rst:516 ddff6a045e8d43fca2d9144a4d8433a4\nmsgid \"\"\n\"This script is similar to the one described in \\\"How to use \"\n\":meth:`Story.write_stabilized()`\\\" above, except that the generated PDF \"\n\"also contains links that correspond to the internal links in the original\"\n\" html.\"\nmsgstr \"\"\n\"이 스크립트는 위의 \\\":meth:`Story.write_stabilized()` 사용 방법\\\"에서 설명한 것과 유사하지만, 생성된 PDF에 \"\n\"원본 HTML의 내부 링크에 해당하는 링크도 포함됩니다.\"\n\n#: ../../recipes-stories.rst:520 b9678b083c9c4ba788c436e3d5e8c3fb\nmsgid \"\"\n\"This is done by using :meth:`Story.write_stabilized_links()`; this is \"\n\"slightly different from :meth:`Story.write_stabilized()`:\"\nmsgstr \"\"\n\"이것은 :meth:`Story.write_stabilized_links()` 를 사용하여 수행됩니다. 이것은 \"\n\":meth:`Story.write_stabilized()` 와 약간 다릅니다:\"\n\n#: ../../recipes-stories.rst:523 31f9c57387284c839d1085d91cb625b2\nmsgid \"It does not take a :ref:`DocumentWriter` `writer` arg.\"\nmsgstr \":ref:`DocumentWriter` `writer` 인수를 사용하지 않습니다.\"\n\n#: ../../recipes-stories.rst:524 9c7bd5e90df443cdbe61b132c03467b2\nmsgid \"It returns a PDF :ref:`Document` instance.\"\nmsgstr \"PDF :ref:`Document` 인스턴스를 반환합니다.\"\n\n#: ../../recipes-stories.rst:526 d8ba37b0defe4b7eb40aa17b6e2d8356\nmsgid \"\"\n\"[The reasons for this are a little involved; for example a \"\n\":ref:`DocumentWriter` is not necessarily a PDF writer, so doesn't really \"\n\"work in a PDF-specific API.]\"\nmsgstr \"\"\n\"[이에 대한 이유는 약간 복잡합니다. 예를 들어 :ref:`DocumentWriter` 는 반드시 PDF 작성자가 아니므로 PDF 전용 \"\n\"API에서는 실제로 작동하지 않습니다.]\"\n\n#: ../../recipes-stories.rst:533 bdb356f1c6e6499c9a9ed3fa8c0d6721\nmsgid \"`docs/samples/story-write-stabilized-links.py`\"\nmsgstr \"\"\n\n#: ../../recipes-stories.rst:547 9b7cb4775a4e44f2881def8ce1ca8369\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../recipes-stories.rst:548 9c133ed7af7a4415b60b9ed96ac04830\nmsgid \"HTML & CSS support\"\nmsgstr \"HTML 및 CSS 지원\"\n\n#: ../../recipes-stories.rst:552 b1da3ee4c5a3436a8a6b46802918e564\nmsgid \"\"\n\"At the time of writing the HTML engine for Stories is fairly basic and \"\n\"supports a subset of CSS2 attributes.\"\nmsgstr \"작성 시점에서 Stories의 HTML 엔진은 상당히 기본적이며 CSS2 속성의 하위 집합을 지원합니다.\"\n\n#: ../../recipes-stories.rst:554 01ac3d98abae4349b9b5c28d6a74755e\nmsgid \"Some important CSS support to consider:\"\nmsgstr \"고려해야 할 중요한 CSS 지원:\"\n\n#: ../../recipes-stories.rst:556 b91cde3adf67437fb80037c56700f274\nmsgid \"The only available layout is relative layout.\"\nmsgstr \"사용 가능한 유일한 레이아웃은 상대 레이아웃입니다.\"\n\n#: ../../recipes-stories.rst:557 e4be54e31399436792c52c7fda0353d1\nmsgid \"`background` is unavailable, use `background-color` instead.\"\nmsgstr \"`background` 는 사용할 수 없으며, 대신 `background-color` 를 사용하세요.\"\n\n#: ../../recipes-stories.rst:558 2e7a1ffef1e64856a8bac73062d1051f\nmsgid \"`float` is unavailable.\"\nmsgstr \"`float` 는 사용할 수 없습니다.\"\n\n#: ../../footer.rst:46 e3f4dcf0211e47ab91f9299fb7f43fd1\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes-text.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 aacd92b247384bf48857a075d285a561\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 dbeb3e790165465a99d5c54f8c3d8ead\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 c0909ea966bf494c8da17ef86ca44a3b\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../recipes-text.rst:7 05ae1dd8d9f44a9481a79f9e3b1d86d7\nmsgid \"Text\"\nmsgstr \"Text\"\n\n#: ../../recipes-text.rst:13 7caab8ee2fd2466083df37b5e33d293a\nmsgid \"How to Extract all Document Text\"\nmsgstr \"모든 문서 텍스트 추출 방법\"\n\n#: ../../recipes-text.rst:15 8c1e407daf5546229fd685147c64ce69\nmsgid \"\"\n\"This script will take a document filename and generate a text file from \"\n\"all of its text.\"\nmsgstr \"이 스크립트는 문서 파일 이름을 받아 모든 텍스트에서 텍스트 파일을 생성합니다.\"\n\n#: ../../recipes-text.rst:17 32ad66847ecb4784aabbcd72e5132bcc\nmsgid \"The document can be any :ref:`supported type<Supported_File_Types>`.\"\nmsgstr \"문서는 :ref:`지원되는 모든 타입<Supported_File_Types>` 일 수 있습니다.\"\n\n#: ../../recipes-text.rst:19 81db58eeb7da49e8ac352d7290a9895b\nmsgid \"\"\n\"The script works as a command line tool which expects the document \"\n\"filename supplied as a parameter. It generates one text file named \"\n\"\\\"filename.txt\\\" in the script directory. Text of pages is separated by a\"\n\" form feed character::\"\nmsgstr \"스크립트는 매개변수로 제공된 문서 파일 이름을 기대하는 명령줄 도구로 작동합니다. 스크립트 디렉토리에 \\\"filename.txt\\\"라는 하나의 텍스트 파일을 생성합니다. 페이지의 텍스트는 폼 피드 문자로 구분됩니다::\"\n\n#: ../../recipes-text.rst:28 34acce45dea14d438a205400310b647d\nmsgid \"\"\n\"The output will be plain text as it is coded in the document. No effort \"\n\"is made to prettify in any way. Specifically for PDF, this may mean \"\n\"output not in usual reading order, unexpected line breaks and so forth.\"\nmsgstr \"출력은 문서에 코딩된 대로 일반 텍스트입니다. 어떤 방식으로도 예쁘게 만들려는 시도는 없습니다. 특히 PDF의 경우, 이것은 일반적인 읽기 순서가 아닌 출력, 예상치 못한 줄바꿈 등을 의미할 수 있습니다.\"\n\n#: ../../recipes-text.rst:30 d85615155c024325ba277a5ca1e1ccc0\nmsgid \"\"\n\"You have many options to rectify this -- see chapter :ref:`Appendix2`. \"\n\"Among them are:\"\nmsgstr \"이를 수정하는 많은 옵션이 있습니다 -- :ref:`Appendix2` 장을 참조하세요. 그 중에는 다음이 있습니다:\"\n\n#: ../../recipes-text.rst:32 9f7a0c712a724bcb8f46594a0696a485\nmsgid \"\"\n\"Extract text in HTML format and store it as a HTML document, so it can be\"\n\" viewed in any browser.\"\nmsgstr \"HTML 형식으로 텍스트를 추출하고 HTML 문서로 저장하여 모든 브라우저에서 볼 수 있도록 합니다.\"\n\n#: ../../recipes-text.rst:33 14d8db3ab4354b208d1b10a44164247a\nmsgid \"\"\n\"Extract text as a list of text blocks via *Page.get_text(\\\"blocks\\\")*. \"\n\"Each item of this list contains position information for its text, which \"\n\"can be used to establish a convenient reading order.\"\nmsgstr \"*Page.get_text(\\\"blocks\\\")* 를 통해 텍스트 블록 목록으로 텍스트를 추출합니다. 이 목록의 각 항목은 텍스트에 대한 위치 정보를 포함하며, 이를 사용하여 편리한 읽기 순서를 설정할 수 있습니다.\"\n\n#: ../../recipes-text.rst:34 a737dbb5f0df4394b85c682d11c5fbc7\nmsgid \"\"\n\"Extract a list of single words via *Page.get_text(\\\"words\\\")*. Its items \"\n\"are words with position information. Use it to determine text contained \"\n\"in a given rectangle -- see next section.\"\nmsgstr \"*Page.get_text(\\\"words\\\")* 를 통해 단일 단어 목록을 추출합니다. 항목은 위치 정보가 있는 단어입니다. 주어진 사각형에 포함된 텍스트를 확인하는 데 사용하세요 -- 다음 섹션을 참조하세요.\"\n\n#: ../../recipes-text.rst:36 1eecb5d77eb545a89b29bbbe32c68b52\nmsgid \"See the following two sections for examples and further explanations.\"\nmsgstr \"예제 및 추가 설명은 다음 두 섹션을 참조하세요.\"\n\n#: ../../recipes-text.rst:44 5d550fa30f214c0ab6daaa5da9d1d56b\nmsgid \"How to Extract Text as Markdown\"\nmsgstr \"Markdown 형식으로 텍스트 추출 방법\"\n\n#: ../../recipes-text.rst:46 3a0e63deebbf4416a1fea6b96c24774a\nmsgid \"\"\n\"This is especially useful for :title:`RAG/LLM` environments - please see \"\n\":ref:`Outputting as Markdown <rag_outputting_as_md>`.\"\nmsgstr \"\"\n\"이는 특히 :title:`RAG/LLM` 환경에 유용합니다 - :ref:`Outputting as Markdown \"\n\"<rag_outputting_as_md>` 를 참조하세요.\"\n\n#: ../../recipes-text.rst:52 76343110228443c691bf59b95ab056c9\nmsgid \"How to Extract Key-Value Pairs from a Page\"\nmsgstr \"페이지에서 키-값 쌍 추출 방법\"\n\n#: ../../recipes-text.rst:53 34f319f64a034da383333b8c516bb6fc\nmsgid \"\"\n\"If the layout of a page is *\\\"predictable\\\"* in some sense, then there is\"\n\" a simple way to find the values for a given set of keywords fast and \"\n\"easily -- without using regular expressions. Please see `this example \"\n\"script <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/text-\"\n\"extraction/lookup-keywords.py>`_.\"\nmsgstr \"\"\n\"페이지 레이아웃이 어느 정도 *\\\"예측 가능한\\\"* 경우, 정규 표현식을 사용하지 않고도 특정 키워드 집합에 대한 값을 빠르고 쉽게 찾는 간단한 방법이 있습니다. `이 예제 스크립트 \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/text-extraction/lookup-\"\n\"keywords.py>`_ 를 참조하세요.\"\n\n#: ../../recipes-text.rst:55 0b02d215083344e3bafc3ec057536e9f\nmsgid \"\\\"Predictable\\\" in this context means:\"\nmsgstr \"여기서 \\\"예측 가능한\\\" 이란 다음을 의미합니다:\"\n\n#: ../../recipes-text.rst:57 312afbe84baa4bdf84138e6f35377145\nmsgid \"\"\n\"Every keyword is followed by its value -- no other text is present in \"\n\"between them.\"\nmsgstr \"각 키워드 뒤에는 그 값이 이어집니다 -- 그 사이에 다른 텍스트는 없습니다.\"\n\n#: ../../recipes-text.rst:58 fd6c255cc6164834b85534e21a47f8c3\nmsgid \"\"\n\"The bottom of the value's boundary box is **not above** the one of the \"\n\"keyword.\"\nmsgstr \"값의 경계 상자 하단이 키워드의 경계 상자보다 **위에 있지 않습니다**.\"\n\n#: ../../recipes-text.rst:59 3a28328449d0465298d40e600034845d\nmsgid \"\"\n\"There are **no other restrictions**: the page layout may or may not be \"\n\"fixed, and the text may also have been stored as one string. Key and \"\n\"value may have any distance from each other.\"\nmsgstr \"\"\n\"**다른 제한은 없습니다**: 페이지 레이아웃이 고정되어 있을 수도 있고 아닐 수도 있으며, 텍스트가 하나의 문자열로 저장되었을 수도 있습니다. 키와 값은 서로 어떤 거리든 가질 수 있습니다.\"\n\n#: ../../recipes-text.rst:61 d4fc0262f0d74fcd8ab3810ea67fcabd\nmsgid \"\"\n\"For example, the following five key-value pairs will be correctly \"\n\"identified::\"\nmsgstr \"예를 들어, 다음 다섯 개의 키-값 쌍이 올바르게 식별됩니다::\"\n\n#: ../../recipes-text.rst:77 193e5336ec2f43b2a832b43d6a58d308\nmsgid \"How to Extract Text from within a Rectangle\"\nmsgstr \"사각형 내부에서 텍스트 추출 방법\"\n\n#: ../../recipes-text.rst:78 4c4438f1bc044009b24645d65ce8ab60\nmsgid \"\"\n\"There is now (v1.18.0) more than one way to achieve this. We therefore \"\n\"have created a `folder <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/textbox-extraction>`_ in the PyMuPDF-Utilities \"\n\"repository specifically dealing with this topic.\"\nmsgstr \"\"\n\"이제 (v1.18.0) 이를 달성하는 방법이 여러 가지 있습니다. 따라서 이 주제를 다루는 `폴더 \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/textbox-extraction>`_ 를 \"\n\"PyMuPDF-Utilities 저장소에 만들었습니다.\"\n\n#: ../../recipes-text.rst:88 742b2388b2764f87a7e62ef6bfa73dd6\nmsgid \"How to Extract Text in Natural Reading Order\"\nmsgstr \"자연스러운 읽기 순서로 텍스트 추출 방법\"\n\n#: ../../recipes-text.rst:90 0e8c0fee0d084b9883b573ad87009d6e\nmsgid \"\"\n\"One of the common issues with PDF text extraction is, that text may not \"\n\"appear in any particular reading order.\"\nmsgstr \"PDF 텍스트 추출의 일반적인 문제 중 하나는 텍스트가 특정 읽기 순서로 나타나지 않을 수 있다는 것입니다.\"\n\n#: ../../recipes-text.rst:92 371d80a5d01448afa0dd235c5b575b74\nmsgid \"\"\n\"This is the responsibility of the PDF creator (software or a human). For \"\n\"example, page headers may have been inserted in a separate step -- after \"\n\"the document had been produced. In such a case, the header text will \"\n\"appear at the end of a page text extraction (although it will be \"\n\"correctly shown by PDF viewer software). For example, the following \"\n\"snippet will add some header and footer lines to an existing PDF::\"\nmsgstr \"\"\n\"이는 PDF 생성자(소프트웨어 또는 사람)의 책임입니다. 예를 들어, 페이지 헤더는 문서가 생성된 후 별도의 단계에서 삽입되었을 수 있습니다. \"\n\"이 경우 헤더 텍스트는 페이지 텍스트 추출의 끝에 나타납니다(하지만 PDF 뷰어 소프트웨어에서는 올바르게 표시됩니다). 예를 들어, 다음 스니펫은 기존 \"\n\"PDF에 일부 헤더 및 푸터 줄을 추가합니다::\"\n\n#: ../../recipes-text.rst:104 4e580c24666243d38d3b31b8c81cd144\nmsgid \"\"\n\"The text sequence extracted from a page modified in this way will look \"\n\"like this:\"\nmsgstr \"이런 방식으로 수정된 페이지에서 추출된 텍스트 시퀀스는 다음과 같습니다:\"\n\n#: ../../recipes-text.rst:106 0dc07ee4abb14a8591e99d17d219a66e\nmsgid \"original text\"\nmsgstr \"원본 텍스트\"\n\n#: ../../recipes-text.rst:107 a16785675c2e42889b217e4366030fc0\nmsgid \"header line\"\nmsgstr \"헤더 줄\"\n\n#: ../../recipes-text.rst:108 799554ad7a954b8f9f8b0a65b45eb2ef\nmsgid \"footer line\"\nmsgstr \"푸터 줄\"\n\n#: ../../recipes-text.rst:110 6dfbb78929994320a0792e1e879361b4\nmsgid \"\"\n\"PyMuPDF has several means to re-establish some reading sequence or even \"\n\"to re-generate a layout close to the original:\"\nmsgstr \"PyMuPDF는 읽기 순서를 재구성하거나 원본에 가까운 레이아웃을 재생성하는 여러 가지 방법을 제공합니다:\"\n\n#: ../../recipes-text.rst:112 3c8a07a9513e4d6faa6519684db819d5\nmsgid \"\"\n\"Use `sort` parameter of :meth:`Page.get_text`. It will sort the output \"\n\"from top-left to bottom-right (ignored for XHTML, HTML and XML output).\"\nmsgstr \"\"\n\":meth:`Page.get_text` 의 `sort` 매개변수를 사용하세요. 출력을 왼쪽 위에서 오른쪽 아래로 정렬합니다 (XHTML, \"\n\"HTML 및 XML 출력에는 무시됨).\"\n\n#: ../../recipes-text.rst:113 ec3f668329044785b2d980019e4279e2\nmsgid \"\"\n\"Use the `pymupdf` module in CLI: `python -m pymupdf gettext ...`, which \"\n\"produces a text file where text has been re-arranged in layout-preserving\"\n\" mode. Many options are available to control the output.\"\nmsgstr \"\"\n\"CLI에서 `pymupdf` 모듈을 사용하세요: `python -m pymupdf gettext ...`, 이는 레이아웃을 보존하는 모드로 \"\n\"텍스트가 재배열된 텍스트 파일을 생성합니다. 출력을 제어하는 많은 옵션이 있습니다.\"\n\n#: ../../recipes-text.rst:115 e9acdb536bca4568ad8b4d1ec10d61ea\nmsgid \"\"\n\"You can also use the above mentioned `script \"\n\"<https://github.com/pymupdf/PyMuPDF/wiki/How-to-extract-text-\"\n\"from-a-rectangle>`_ with your modifications.\"\nmsgstr \"\"\n\"위에서 언급한 `스크립트 <https://github.com/pymupdf/PyMuPDF/wiki/How-to-extract-text-from-a-\"\n\"rectangle>`_ 를 수정하여 사용할 수도 있습니다.\"\n\n#: ../../recipes-text.rst:122 e855c66968e14c8292b797d093cd0b65\nmsgid \"\"\n\"How to :index:`Extract Table Content <pair: extract; table>` from \"\n\"Documents\"\nmsgstr \"문서에서 :index:`테이블 내용 추출 <pair: extract; table>` 방법\"\n\n#: ../../recipes-text.rst:123 44f6d95fd2764808af666701bb7f19a0\nmsgid \"\"\n\"If you see a table in a document, you are normally not looking at \"\n\"something like an embedded Excel or other identifiable object. It usually\"\n\" is just normal, standard text, formatted to appear as tabular data.\"\nmsgstr \"\"\n\"문서에서 테이블을 볼 때, 일반적으로 Excel 같은 임베드된 객체나 다른 식별 가능한 객체를 보는 것이 아닙니다. 보통은 표 형식 데이터로 \"\n\"보이도록 포맷된 일반적인 표준 텍스트일 뿐입니다.\"\n\n#: ../../recipes-text.rst:125 d16f360542d940e5a852c0aa8564e344\nmsgid \"\"\n\"Extracting tabular data from such a page area therefore means that you \"\n\"must find a way to **identify** the table area (i.e. its boundary box), \"\n\"then **(1)** graphically indicate table and column borders, and **(2)** \"\n\"then extract text based on this information.\"\nmsgstr \"\"\n\"따라서 이러한 페이지 영역에서 표 형식 데이터를 추출하려면 테이블 영역(즉, 경계 상자)을 **식별** 하는 방법을 찾은 다음 **(1)** \"\n\"테이블 및 열 경계를 그래픽으로 표시하고 **(2)** 이 정보를 기반으로 텍스트를 추출해야 합니다.\"\n\n#: ../../recipes-text.rst:127 a113658ef8c641279d0583854610b700\nmsgid \"\"\n\"This can be a very complex task, depending on details like the presence \"\n\"or absence of lines, rectangles or other supporting vector graphics.\"\nmsgstr \"\"\n\"이는 선, 사각형 또는 기타 지원 벡터 그래픽의 존재 여부와 같은 세부 사항에 따라 매우 복잡한 작업이 될 수 있습니다.\"\n\n#: ../../recipes-text.rst:129 591bba39c0464acda49f9fc542563e38\nmsgid \"\"\n\"Method :meth:`Page.find_tables` does all that for you, with a high table \"\n\"detection precision. Its great advantage is that there are no external \"\n\"library dependencies, nor the need to employ artificial intelligence or \"\n\"machine learning technologies. It also provides an integrated interface \"\n\"to the well-known Python package for data analysis `pandas \"\n\"<https://pypi.org/project/pandas/>`_.\"\nmsgstr \"\"\n\":meth:`Page.find_tables` 메서드는 높은 테이블 감지 정밀도로 모든 작업을 수행합니다. 큰 장점은 외부 라이브러리 의존성이 없고 \"\n\"인공 지능이나 머신 러닝 기술을 사용할 필요가 없다는 것입니다. 또한 데이터 분석을 위한 잘 알려진 Python 패키지 `pandas \"\n\"<https://pypi.org/project/pandas/>`_ 에 대한 통합 인터페이스를 제공합니다.\"\n\n#: ../../recipes-text.rst:131 0ec9741148044d23b6fe82ee829207a2\nmsgid \"\"\n\"Please have a look at example `Jupyter notebooks \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-\"\n\"analysis>`_, which cover standard situations like multiple tables on one \"\n\"page or joining table fragments across multiple pages.\"\nmsgstr \"\"\n\"한 페이지에 여러 테이블이 있거나 여러 페이지에 걸친 테이블 조각을 결합하는 것과 같은 표준 상황을 다루는 예제 `Jupyter 노트북 \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-analysis>`_ \"\n\"를 살펴보세요.\"\n\n#: ../../recipes-text.rst:138 b1f926e82a76494a9f56c7876863ca93\nmsgid \"How to Mark Extracted Text\"\nmsgstr \"추출된 텍스트 표시 방법\"\n\n#: ../../recipes-text.rst:139 1e973eca86874445943029692b1f158c\nmsgid \"\"\n\"There is a standard search function to search for arbitrary text on a \"\n\"page: :meth:`Page.search_for`. It returns a list of :ref:`Rect` objects \"\n\"which surround a found occurrence. These rectangles can for example be \"\n\"used to automatically insert annotations which visibly mark the found \"\n\"text.\"\nmsgstr \"\"\n\"페이지에서 임의의 텍스트를 검색하는 표준 검색 함수가 있습니다: :meth:`Page.search_for`. 발견된 항목을 둘러싸는 \"\n\":ref:`Rect` 객체 목록을 반환합니다. 이러한 사각형은 예를 들어 발견된 텍스트를 시각적으로 표시하는 주석을 자동으로 삽입하는 데 사용할 수 있습니다.\"\n\n#: ../../recipes-text.rst:141 dc031cd749464364bf765bac0417b4b0\nmsgid \"This method has advantages and drawbacks. Pros are:\"\nmsgstr \"이 방법에는 장점과 단점이 있습니다. 장점은 다음과 같습니다:\"\n\n#: ../../recipes-text.rst:143 86833cccc89c42c3895307b65c1b8961\nmsgid \"The search string can contain blanks and wrap across lines\"\nmsgstr \"검색 문자열은 공백을 포함할 수 있고 여러 줄에 걸칠 수 있습니다\"\n\n#: ../../recipes-text.rst:144 fbcd0df95b764ad0a6fc7a6e5cf28042\nmsgid \"Upper or lower case characters are treated equal\"\nmsgstr \"대문자 또는 소문자 문자가 동일하게 처리됩니다\"\n\n#: ../../recipes-text.rst:145 5c86c01b36574cb1ac96a3d8134e20f7\nmsgid \"Word hyphenation at line ends is detected and resolved\"\nmsgstr \"줄 끝의 단어 하이픈 연결이 감지되고 해결됩니다\"\n\n#: ../../recipes-text.rst:146 3c530d96cd524a0f93975a14b9e1802b\nmsgid \"\"\n\"Return may also be a list of :ref:`Quad` objects to precisely locate text\"\n\" that is **not parallel** to either axis -- using :ref:`Quad` output is \"\n\"also recommended, when page rotation is not zero.\"\nmsgstr \"\"\n\"반환값은 어느 축에도 **평행하지 않은** 텍스트를 정확히 찾기 위한 :ref:`Quad` 객체 목록일 수도 있습니다 -- 페이지 회전이 \"\n\"0이 아닐 때는 :ref:`Quad` 출력 사용을 권장합니다.\"\n\n#: ../../recipes-text.rst:148 d23bafdfe40a49d6bf4bb9a1b76b0938\nmsgid \"But you also have other options::\"\nmsgstr \"하지만 다른 옵션도 있습니다::\"\n\n#: ../../recipes-text.rst:182 80855b0c68a2478481c53a15e79cac96\nmsgid \"\"\n\"This script uses `Page.get_text(\\\"words\\\")` to look for a string, handed \"\n\"in via cli parameter. This method separates a page's text into \\\"words\\\" \"\n\"using white spaces as delimiters. Further remarks:\"\nmsgstr \"\"\n\"이 스크립트는 CLI 매개변수를 통해 전달된 문자열을 찾기 위해 `Page.get_text(\\\"words\\\")` 를 사용합니다. 이 방법은 \"\n\"페이지의 텍스트를 공백을 구분자로 사용하여 \\\"단어\\\"로 분리합니다. 추가 설명:\"\n\n#: ../../recipes-text.rst:184 1de65ffefd864dd3aba7fd7e18895779\nmsgid \"\"\n\"If found, the **complete word containing the string** is marked \"\n\"(underlined) -- not only the search string.\"\nmsgstr \"발견되면, 검색 문자열뿐만 아니라 **문자열을 포함하는 전체 단어** 가 표시됩니다(밑줄).\"\n\n#: ../../recipes-text.rst:185 2b3e71fdbd4147a499e2a703e50786fd\nmsgid \"\"\n\"The search string may **not contain word delimiters**. By default, word \"\n\"delimiters are white spaces and the non-breaking space `chr(0xA0)`. If \"\n\"you use extra delimiting characters like `page.get_text(\\\"words\\\", \"\n\"delimiters=\\\"./,\\\")` then none of these characters should be included in \"\n\"your search string either.\"\nmsgstr \"\"\n\"검색 문자열에는 **단어 구분자를 포함할 수 없습니다**. 기본적으로 단어 구분자는 공백과 줄바꿈 없는 공백 `chr(0xA0)` \"\n\"입니다. `page.get_text(\\\"words\\\", delimiters=\\\"./,\\\")` 와 같이 추가 구분 문자를 사용하는 경우, 이러한 \"\n\"문자 중 어느 것도 검색 문자열에 포함되어서는 안 됩니다.\"\n\n#: ../../recipes-text.rst:186 adbf6633cd5e4ad488040e4cc264ca3c\nmsgid \"\"\n\"As shown here, upper / lower cases are **respected**. But this can be \"\n\"changed by using the string method *lower()* (or even regular \"\n\"expressions) in function *mark_word*.\"\nmsgstr \"\"\n\"여기서 보여주듯이, 대문자/소문자가 **구분됩니다**. 하지만 *mark_word* 함수에서 문자열 메서드 *lower()* (또는 정규 \"\n\"표현식)를 사용하여 이를 변경할 수 있습니다.\"\n\n#: ../../recipes-text.rst:187 96993cd9b8a9474da6785f2edc5b39a5\nmsgid \"There is **no upper limit**: all occurrences will be detected.\"\nmsgstr \"**상한이 없습니다**: 모든 항목이 감지됩니다.\"\n\n#: ../../recipes-text.rst:188 0e9d7915b8cc4de6861f917e3f3412e6\nmsgid \"\"\n\"You can use **anything** to mark the word: 'Underline', 'Highlight', \"\n\"'StrikeThrough' or 'Square' annotations, etc.\"\nmsgstr \"\"\n\"단어를 표시하는 데 **어떤 것** 이든 사용할 수 있습니다: 'Underline', 'Highlight', 'StrikeThrough' 또는 \"\n\"'Square' 주석 등.\"\n\n#: ../../recipes-text.rst:189 d0f23f19d8d74f58b65405672d5ef654\nmsgid \"\"\n\"Here is an example snippet of a page of this manual, where \\\"MuPDF\\\" has \"\n\"been used as the search string. Note that all strings **containing \"\n\"\\\"MuPDF\\\"** have been completely underlined (not just the search string).\"\nmsgstr \"\"\n\"이 매뉴얼 페이지의 예제 스니펫입니다. \\\"MuPDF\\\" 가 검색 문자열로 사용되었습니다. **\\\"MuPDF\\\"를 포함하는** 모든 문자열이 \"\n\"완전히 밑줄 처리되었습니다(검색 문자열뿐만 아니라).\"\n\n#: ../../recipes-text.rst:200 e7ff4483e8b34bd3b6aa194e55963507\nmsgid \"How to Mark Searched Text\"\nmsgstr \"검색된 텍스트 표시 방법\"\n\n#: ../../recipes-text.rst:204 7c7b2708f7d045ebb7a03223d6f8ea9d\nmsgid \"This script searches for text and marks it::\"\nmsgstr \"이 스크립트는 텍스트를 검색하고 표시합니다::\"\n\n#: ../../recipes-text.rst:230 e211931535cf4266a427d5b731c8a73e\nmsgid \"The result looks like this:\"\nmsgstr \"결과는 다음과 같습니다:\"\n\n#: ../../recipes-text.rst:241 9c36d575753f422cbdc4614a787057ab\nmsgid \"How to Mark Non-horizontal Text\"\nmsgstr \"수평이 아닌 텍스트 표시 방법\"\n\n#: ../../recipes-text.rst:242 1e52760d0e514e19ba6ab20d5f1fb0d7\nmsgid \"\"\n\"The previous section already shows an example for marking non-horizontal \"\n\"text, that was detected by text **searching**.\"\nmsgstr \"이전 섹션에서는 텍스트 **검색** 으로 감지된 수평이 아닌 텍스트를 표시하는 예제를 이미 보여주었습니다.\"\n\n#: ../../recipes-text.rst:244 ded1ab547046433489a3f24860ad56dc\nmsgid \"\"\n\"But text **extraction** with the \\\"dict\\\" / \\\"rawdict\\\" options of \"\n\":meth:`Page.get_text` may also return text with a non-zero angle to the \"\n\"x-axis. This is indicated by the value of the line dictionary's `\\\"dir\\\"`\"\n\" key: it is the tuple `(cosine, sine)` for that angle. If `line[\\\"dir\\\"] \"\n\"!= (1, 0)`, then the text of all its spans is rotated by (the same) angle\"\n\" != 0.\"\nmsgstr \"\"\n\"하지만 :meth:`Page.get_text` 의 \\\"dict\\\" / \\\"rawdict\\\" 옵션을 사용한 텍스트 **추출** 은 x축에 대해 \"\n\"0이 아닌 각도를 가진 텍스트도 반환할 수 있습니다. 이는 줄 딕셔너리의 `\\\"dir\\\"` 키 값으로 표시됩니다: 해당 각도의 튜플 \"\n\"`(cosine, sine)` 입니다. `line[\\\"dir\\\"] != (1, 0)` 이면, 모든 스팬의 텍스트가 (동일한) 각도 != 0으로 \"\n\"회전됩니다.\"\n\n#: ../../recipes-text.rst:246 806b832583d84ccc93707076ad170901\nmsgid \"\"\n\"The \\\"bboxes\\\" returned by the method however are rectangles only -- not \"\n\"quads. So, to mark span text correctly, its quad must be recovered from \"\n\"the data contained in the line and span dictionary. Do this with the \"\n\"following utility function (new in v1.18.9)::\"\nmsgstr \"\"\n\"하지만 이 메서드가 반환하는 \\\"bboxes\\\"는 사각형일 뿐입니다 -- 쿼드가 아닙니다. 따라서 스팬 텍스트를 올바르게 표시하려면, 줄 및 \"\n\"스팬 딕셔너리에 포함된 데이터에서 쿼드를 복구해야 합니다. 다음 유틸리티 함수를 사용하세요 (v1.18.9에서 새로 추가됨)::\"\n\n#: ../../recipes-text.rst:251 374483caf365491888ccd4a28c1034f8\nmsgid \"\"\n\"If you want to **mark the complete line** or a subset of its spans in one\"\n\" go, use the following snippet (works for v1.18.10 or later)::\"\nmsgstr \"\"\n\"**전체 줄** 또는 스팬의 하위 집합을 한 번에 표시하려면 다음 스니펫을 사용하세요 (v1.18.10 이상에서 작동)::\"\n\n#: ../../recipes-text.rst:258 1257febf78464c89b484b1cf6071bec4\nmsgid \"\"\n\"The `spans` argument above may specify any sub-list of `line[\\\"spans\\\"]`.\"\n\" In the example above, the second to second-to-last span are marked. If \"\n\"omitted, the complete line is taken.\"\nmsgstr \"\"\n\"위의 `spans` 인수는 `line[\\\"spans\\\"]` 의 임의의 하위 목록을 지정할 수 있습니다. 위 예제에서는 두 번째부터 \"\n\"마지막에서 두 번째까지의 스팬이 표시됩니다. 생략하면 전체 줄이 사용됩니다.\"\n\n#: ../../recipes-text.rst:265 73fd41c1a1a94a5db20497ae5b6e3c38\nmsgid \"How to Analyze Font Characteristics\"\nmsgstr \"폰트 특성 분석 방법\"\n\n#: ../../recipes-text.rst:266 7643d48b4b834ad5a18337b0d8dda127\nmsgid \"\"\n\"To analyze the characteristics of text in a PDF use this elementary \"\n\"script as a starting point:\"\nmsgstr \"PDF의 텍스트 특성을 분석하려면 이 기본 스크립트를 시작점으로 사용하세요:\"\n\n#: ../../recipes-text.rst:271 be40eabfee1c41e68990b36a6e79a16f\nmsgid \"Here is the PDF page and the script output:\"\nmsgstr \"PDF 페이지와 스크립트 출력은 다음과 같습니다:\"\n\n#: ../../recipes-text.rst:282 f7cca7fc650940c6b739a5e09938bbdd\nmsgid \"How to Insert Text\"\nmsgstr \"텍스트 삽입 방법\"\n\n#: ../../recipes-text.rst:283 dacb14e969f44d09b2a5487775dd63ea\nmsgid \"\"\n\"PyMuPDF provides ways to insert text on new or existing PDF pages with \"\n\"the following features:\"\nmsgstr \"PyMuPDF는 다음 기능을 사용하여 새 PDF 페이지나 기존 PDF 페이지에 텍스트를 삽입하는 방법을 제공합니다:\"\n\n#: ../../recipes-text.rst:285 f1dd495e1caa4902a8e5c782e9c679b5\nmsgid \"\"\n\"choose the font, including built-in fonts and fonts that are available as\"\n\" files\"\nmsgstr \"파일로 사용 가능한 폰트를 포함하여 내장 폰트와 폰트를 선택\"\n\n#: ../../recipes-text.rst:286 4b098043ef3245699c145e6b99254bfb\nmsgid \"choose text characteristics like bold, italic, font size, font color, etc.\"\nmsgstr \"굵게, 기울임, 폰트 크기, 폰트 색상 등의 텍스트 특성 선택\"\n\n#: ../../recipes-text.rst:287 a7d20d40102b4dd987941eec0fe2059b\nmsgid \"position the text in multiple ways:\"\nmsgstr \"여러 방법으로 텍스트 위치 지정:\"\n\n#: ../../recipes-text.rst:289 ebb1742c954f43b6b40e7dd5c8eefbc2\nmsgid \"either as simple line-oriented output starting at a certain point,\"\nmsgstr \"특정 지점에서 시작하는 간단한 줄 지향 출력으로,\"\n\n#: ../../recipes-text.rst:290 caf3e77d02db4d88ba4b4ce0df67f82b\nmsgid \"\"\n\"or fitting text in a box provided as a rectangle, in which case text \"\n\"alignment choices are also available,\"\nmsgstr \"또는 사각형으로 제공된 상자에 텍스트를 맞추는 경우, 이 경우 텍스트 정렬 선택도 사용 가능,\"\n\n#: ../../recipes-text.rst:291 08f04e2e5fff428aad600459aeae779f\nmsgid \"\"\n\"choose whether text should be put in foreground (overlay existing \"\n\"content),\"\nmsgstr \"텍스트를 전경에 배치할지 선택(기존 콘텐츠 위에 오버레이),\"\n\n#: ../../recipes-text.rst:292 1899456d8c24474f8bcd5e172b2cde12\nmsgid \"\"\n\"all text can be arbitrarily \\\"morphed\\\", i.e. its appearance can be \"\n\"changed via a :ref:`Matrix`, to achieve effects like scaling, shearing or\"\n\" mirroring,\"\nmsgstr \"\"\n\"모든 텍스트를 임의로 \\\"변형\\\"할 수 있습니다. 즉, :ref:`Matrix` 를 통해 모양을 변경하여 확대/축소, 기울이기 또는 미러링과 \"\n\"같은 효과를 얻을 수 있습니다,\"\n\n#: ../../recipes-text.rst:293 86bfde1660ba41f499e89840e1564a90\nmsgid \"\"\n\"independently from morphing and in addition to that, text can be rotated \"\n\"by integer multiples of 90 degrees.\"\nmsgstr \"변형과 독립적으로, 추가로 텍스트를 90도의 정수 배로 회전할 수 있습니다.\"\n\n#: ../../recipes-text.rst:295 be111c03edb84cf2a94e8762714cc0eb\nmsgid \"\"\n\"All of the above is provided by three basic :ref:`Page`, resp. \"\n\":ref:`Shape` methods:\"\nmsgstr \"위의 모든 것은 세 가지 기본 :ref:`Page`, 각각 :ref:`Shape` 메서드로 제공됩니다:\"\n\n#: ../../recipes-text.rst:297 72cb967325024d41a8ffa1c2ab753fd4\nmsgid \"\"\n\":meth:`Page.insert_font` -- install a font for the page for later \"\n\"reference. The result is reflected in the output of \"\n\":meth:`Document.get_page_fonts`. The font can be:\"\nmsgstr \"\"\n\":meth:`Page.insert_font` -- 나중에 참조할 수 있도록 페이지에 폰트를 설치합니다. 결과는 \"\n\":meth:`Document.get_page_fonts` 의 출력에 반영됩니다. 폰트는 다음 중 하나일 수 있습니다:\"\n\n#: ../../recipes-text.rst:299 b76fff0661ed480cb05480c7a9a31ddd\nmsgid \"provided as a file,\"\nmsgstr \"파일로 제공되거나,\"\n\n#: ../../recipes-text.rst:300 7c635389b9dd4de28b6bfd73e66eb774\nmsgid \"via :ref:`Font` (then use :attr:`Font.buffer`)\"\nmsgstr \":ref:`Font` 를 통해 (그런 다음 :attr:`Font.buffer` 사용) 또는\"\n\n#: ../../recipes-text.rst:301 58c5c49b72314f1fbef5a7fdb829811d\nmsgid \"already present somewhere in **this or another** PDF, or\"\nmsgstr \"**이 PDF 또는 다른** PDF의 어딘가에 이미 있거나,\"\n\n#: ../../recipes-text.rst:302 f6a2b00d975e4ffbb57171c37d4127bb\nmsgid \"be a **built-in** font.\"\nmsgstr \"**내장** 폰트일 수 있습니다.\"\n\n#: ../../recipes-text.rst:304 a44d01d2b9bb4d3686811c70f9b9271a\nmsgid \"\"\n\":meth:`Page.insert_text` -- write some lines of text. Internally, this \"\n\"uses :meth:`Shape.insert_text`.\"\nmsgstr \"\"\n\":meth:`Page.insert_text` -- 텍스트 줄을 작성합니다. 내부적으로는 :meth:`Shape.insert_text` 를 \"\n\"사용합니다.\"\n\n#: ../../recipes-text.rst:306 bfd1f9b3c2b741b29c87208a1a66d28e\nmsgid \"\"\n\":meth:`Page.insert_textbox` -- fit text in a given rectangle. Here you \"\n\"can choose text alignment features (left, right, centered, justified) and\"\n\" you keep control as to whether text actually fits. Internally, this uses\"\n\" :meth:`Shape.insert_textbox`.\"\nmsgstr \"\"\n\":meth:`Page.insert_textbox` -- 주어진 사각형에 텍스트를 맞춥니다. 여기서 텍스트 정렬 기능(왼쪽, 오른쪽, \"\n\"가운데, 양쪽 정렬)을 선택할 수 있으며 텍스트가 실제로 맞는지 제어할 수 있습니다. 내부적으로는 :meth:`Shape.insert_textbox` \"\n\"를 사용합니다.\"\n\n#: ../../recipes-text.rst:308 be171eb050b94f58b9cd1b5e0262f4c9\nmsgid \"Both text insertion methods automatically install the font as necessary.\"\nmsgstr \"두 텍스트 삽입 방법 모두 필요에 따라 폰트를 자동으로 설치합니다.\"\n\n#: ../../recipes-text.rst:314 b5fff0f0c7634c4b944d6adf15b57a63\nmsgid \"How to Write Text Lines\"\nmsgstr \"텍스트 줄 작성 방법\"\n\n#: ../../recipes-text.rst:315 cb73fdfc91be42e784e9bdd13d791bc0\nmsgid \"Output some text lines on a page::\"\nmsgstr \"페이지에 텍스트 줄 출력::\"\n\n#: ../../recipes-text.rst:336 93ea55096a814bf78d67323eff265e39\nmsgid \"\"\n\"With this method, only the **number of lines** will be controlled to not \"\n\"go beyond page height. Surplus lines will not be written and the number \"\n\"of actual lines will be returned. The calculation uses a line height \"\n\"calculated from the :data:`fontsize` and 36 points (0.5 inches) as bottom\"\n\" margin.\"\nmsgstr \"\"\n\"이 방법을 사용하면 **줄 수** 만 페이지 높이를 초과하지 않도록 제어됩니다. 초과 줄은 작성되지 않으며 실제 줄 수가 반환됩니다. 계산은 \"\n\":data:`fontsize` 와 하단 여백으로 36포인트(0.5인치)에서 계산된 줄 높이를 사용합니다.\"\n\n#: ../../recipes-text.rst:338 d32561da58f04605a11ea899f3142f80\nmsgid \"\"\n\"Line **width is ignored**. The surplus part of a line will simply be \"\n\"invisible.\"\nmsgstr \"줄 **너비는 무시됩니다**. 줄의 초과 부분은 단순히 보이지 않습니다.\"\n\n#: ../../recipes-text.rst:340 be87d53797fa4459b5ccf3c4131594e4\nmsgid \"\"\n\"However, for built-in fonts there are ways to calculate the line width \"\n\"beforehand - see :meth:`get_text_length`.\"\nmsgstr \"하지만 내장 폰트의 경우 사전에 줄 너비를 계산하는 방법이 있습니다 - :meth:`get_text_length` 를 참조하세요.\"\n\n#: ../../recipes-text.rst:342 f9e73fbbab774c2caa85bbed776cc956\nmsgid \"\"\n\"Here is another example. It inserts 4 text strings using the four \"\n\"different rotation options, and thereby explains, how the text insertion \"\n\"point must be chosen to achieve the desired result::\"\nmsgstr \"\"\n\"다른 예제입니다. 네 가지 다른 회전 옵션을 사용하여 4개의 텍스트 문자열을 삽입하고, 원하는 결과를 얻기 위해 텍스트 삽입 지점을 어떻게 \"\n\"선택해야 하는지 설명합니다::\"\n\n#: ../../recipes-text.rst:378 0213c8bab6154d30805d62976edc9a19\nmsgid \"This is the result:\"\nmsgstr \"결과는 다음과 같습니다:\"\n\n#: ../../recipes-text.rst:390 f3944598e7174b5c84183c27d9976e7d\nmsgid \"How to Fill a Text Box\"\nmsgstr \"텍스트 상자 채우기 방법\"\n\n#: ../../recipes-text.rst:391 432bedd774af4765abc17063d64bbff5\nmsgid \"\"\n\"This script fills 4 different rectangles with text, each time choosing a \"\n\"different rotation value::\"\nmsgstr \"이 스크립트는 텍스트로 4개의 다른 사각형을 채우며, 매번 다른 회전 값을 선택합니다::\"\n\n#: ../../recipes-text.rst:428 b57fefc0582d49269895485a9f9f2d81\nmsgid \"\"\n\"Some default values were used above: font size 11 and text alignment \"\n\"\\\"left\\\". The result will look like this:\"\nmsgstr \"위에서는 일부 기본값이 사용되었습니다: 폰트 크기 11 및 텍스트 정렬 \\\"left\\\". 결과는 다음과 같습니다:\"\n\n#: ../../recipes-text.rst:438 1b2793a104ab4b5688254d0c742bdce1\nmsgid \"How to Fill a Box with HTML Text\"\nmsgstr \"HTML 텍스트로 상자 채우기 방법\"\n\n#: ../../recipes-text.rst:439 19e59b0993924e4c95225686d9cc0d88\nmsgid \"\"\n\"Method :meth:`Page.insert_htmlbox` offers a **much more powerful** way to\"\n\" insert text in a rectangle.\"\nmsgstr \":meth:`Page.insert_htmlbox` 메서드는 사각형에 텍스트를 삽입하는 **훨씬 더 강력한** 방법을 제공합니다.\"\n\n#: ../../recipes-text.rst:441 35f57808a8794c8e9e19787c2c32e112\nmsgid \"\"\n\"Instead of simple, plain text, this method accepts HTML source, which may\"\n\" not only contain HTML tags but also styling instructions to influence \"\n\"things like font, font weight (bold) and style (italic), color and much \"\n\"more.\"\nmsgstr \"\"\n\"간단한 일반 텍스트 대신, 이 메서드는 HTML 소스를 받아들입니다. HTML 태그뿐만 아니라 폰트, 폰트 굵기(굵게), 스타일(기울임), \"\n\"색상 등을 제어하는 스타일 지시문도 포함할 수 있습니다.\"\n\n#: ../../recipes-text.rst:443 71ac810a548442d29907981f132dccbf\nmsgid \"\"\n\"It is also possible to mix multiple fonts and languages, to output HTML \"\n\"tables and to insert images and URI links.\"\nmsgstr \"여러 폰트와 언어를 혼합하고, HTML 테이블을 출력하며, 이미지와 URI 링크를 삽입할 수도 있습니다.\"\n\n#: ../../recipes-text.rst:445 0b4174d507754388b32a80b165012df6\nmsgid \"\"\n\"For even more styling flexibility, an additional CSS source may also be \"\n\"given.\"\nmsgstr \"더 많은 스타일링 유연성을 위해 추가 CSS 소스를 제공할 수도 있습니다.\"\n\n#: ../../recipes-text.rst:447 ef0b305a96e04f7b82deb24dacac92d1\nmsgid \"\"\n\"The method is based on the :ref:`Story` class. Therefore, complex script \"\n\"systems like Devanagari, Nepali, Tamil and many are supported and written\"\n\" correctly thanks to using the HarfBuzz library - which provides this so-\"\n\"called **\\\"text shaping\\\"** feature.\"\nmsgstr \"\"\n\"이 메서드는 :ref:`Story` 클래스를 기반으로 합니다. 따라서 Devanagari, Nepali, Tamil 등과 같은 복잡한 \"\n\"문자 체계가 지원되며 HarfBuzz 라이브러리를 사용하여 올바르게 작성됩니다 - 이는 소위 **\\\"텍스트 셰이핑\\\"** 기능을 제공합니다.\"\n\n#: ../../recipes-text.rst:449 1260a458a7e544b1aa67b8755b17c8ec\nmsgid \"\"\n\"Any required fonts to output characters are automatically pulled in from \"\n\"the Google NOTO font library - as a fallback (when the -- optionally \"\n\"supplied -- user font(s) do not contain some glyphs).\"\nmsgstr \"\"\n\"문자를 출력하는 데 필요한 모든 폰트는 Google NOTO 폰트 라이브러리에서 자동으로 가져옵니다 - 폴백으로 (선택적으로 제공된 \"\n\"-- 사용자 폰트에 일부 글리프가 없는 경우).\"\n\n#: ../../recipes-text.rst:451 fcaf38aee6714a809439a7e41809456a\nmsgid \"\"\n\"As a small glimpse into the features offered here, we will output the \"\n\"following HTML-enriched text::\"\nmsgstr \"여기서 제공되는 기능을 간단히 살펴보기 위해 다음 HTML이 풍부한 텍스트를 출력합니다::\"\n\n#: ../../recipes-text.rst:476 9c59a952ce374072a5f1980b9e94e9e5\nmsgid \"\"\n\"Please note how the \\\"css\\\" parameter is used to globally select the \"\n\"default \\\"sans-serif\\\" font and a font size of 14.\"\nmsgstr \"\\\"css\\\" 매개변수가 기본 \\\"sans-serif\\\" 폰트와 폰트 크기 14를 전역적으로 선택하는 데 어떻게 사용되는지 주목하세요.\"\n\n#: ../../recipes-text.rst:478 ../../recipes-text.rst:546\n#: 7e28c391edc0498e9f137492e4579c8b d1d571d5e2a543f1960a767a55013650\nmsgid \"The result will look like this:\"\nmsgstr \"결과는 다음과 같습니다:\"\n\n#: ../../recipes-text.rst:483 ed1313ec473f4a6abdbea7c7fdbc2bc3\nmsgid \"How to output HTML tables and images\"\nmsgstr \"HTML 테이블 및 이미지 출력 방법\"\n\n#: ../../recipes-text.rst:485 d915167d0a8a487ca0714949823727f9\nmsgid \"\"\n\"Here is another example that outputs a table with this method. This time,\"\n\" we are including all the styling in the HTML source itself. Please also \"\n\"note, how it works to include an image - even within a table cell::\"\nmsgstr \"\"\n\"이 메서드로 테이블을 출력하는 또 다른 예제입니다. 이번에는 모든 스타일링을 HTML 소스 자체에 포함합니다. 이미지를 포함하는 방법(테이블 \"\n\"셀 내부에서도)도 주목하세요::\"\n\n#: ../../recipes-text.rst:552 8a1001c5f5074d4ba6c32b464a047fe3\nmsgid \"How to Output Languages of the World\"\nmsgstr \"세계 언어 출력 방법\"\n\n#: ../../recipes-text.rst:554 694851da42974f849ae4f15fb8583d84\nmsgid \"\"\n\"Our third example will demonstrate the automatic multi-language support. \"\n\"It includes automatic **text shaping** for complex scripting systems like\"\n\" Devanagari and right-to-left languages::\"\nmsgstr \"\"\n\"세 번째 예제는 자동 다국어 지원을 보여줍니다. Devanagari 및 오른쪽에서 왼쪽으로 쓰는 언어와 같은 복잡한 문자 체계에 대한 자동 \"\n\"**텍스트 셰이핑** 을 포함합니다::\"\n\n#: ../../recipes-text.rst:584 11883d2c3225403c9efe9db6404e0614\nmsgid \"And this is the output:\"\nmsgstr \"그리고 이것이 출력입니다:\"\n\n#: ../../recipes-text.rst:589 1694d9848471473387efc178c64d1ac3\nmsgid \"How to Specify your Own Fonts\"\nmsgstr \"자신의 폰트 지정 방법\"\n\n#: ../../recipes-text.rst:591 e24039a16e614bad9521e9f98300ca0a\nmsgid \"\"\n\"Define your font files in CSS syntax using the `@font-face` statement. \"\n\"You need a separate `@font-face` for every combination of font weight and\"\n\" font style (e.g. bold or italic) you want to be supported. The following\"\n\" example uses the famous MS Comic Sans font in its four variants regular,\"\n\" bold, italic and bold-italic.\"\nmsgstr \"\"\n\"`@font-face` 문을 사용하여 CSS 구문으로 폰트 파일을 정의하세요. 지원하려는 폰트 굵기와 폰트 스타일(예: 굵게 또는 기울임)의 \"\n\"모든 조합에 대해 별도의 `@font-face` 가 필요합니다. 다음 예제는 유명한 MS Comic Sans 폰트를 일반, 굵게, \"\n\"기울임, 굵은 기울임의 네 가지 변형으로 사용합니다.\"\n\n#: ../../recipes-text.rst:593 b2b6a21607d34d64a2c7e188ebc89771\nmsgid \"\"\n\"As these four font files are located in the system's folder \"\n\"`C:/Windows/Fonts` the method needs an :ref:`Archive` definition that \"\n\"points to that folder::\"\nmsgstr \"\"\n\"이 네 개의 폰트 파일이 시스템 폴더 `C:/Windows/Fonts` 에 있으므로, 메서드는 해당 폴더를 가리키는 :ref:`Archive` \"\n\"정의가 필요합니다::\"\n\n#: ../../recipes-text.rst:642 e0f58841406a42738934f9d5496b3b1a\nmsgid \"How to Request Text Alignment\"\nmsgstr \"텍스트 정렬 요청 방법\"\n\n#: ../../recipes-text.rst:644 fe05e68776a74af9bbef92af559109dd\nmsgid \"This example combines multiple requirements:\"\nmsgstr \"이 예제는 여러 요구사항을 결합합니다:\"\n\n#: ../../recipes-text.rst:646 e70a8667e3944fd9b0816777acb87234\nmsgid \"Rotate the text by 90 degrees anti-clockwise.\"\nmsgstr \"텍스트를 90도 반시계 방향으로 회전합니다.\"\n\n#: ../../recipes-text.rst:647 d9cf7d46a2d346b2a4f74a171faa1447\nmsgid \"\"\n\"Use a font from package `pymupdf-fonts <https://pypi.org/project/pymupdf-\"\n\"fonts/>`_. You will see that the respective CSS definitions are a lot \"\n\"easier in this case.\"\nmsgstr \"\"\n\"`pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_ 패키지의 폰트를 사용합니다. 이 \"\n\"경우 해당 CSS 정의가 훨씬 더 쉬운 것을 볼 수 있습니다.\"\n\n#: ../../recipes-text.rst:648 bd33916fceb54e72962046e30a682445\nmsgid \"Align the text with the \\\"justify\\\" option.\"\nmsgstr \"\\\"justify\\\" 옵션으로 텍스트를 정렬합니다.\"\n\n#: ../../recipes-text.rst:698 77fa2772ac8f4569be51c8e5f85dfc85\nmsgid \"How to Extract Text with Color\"\nmsgstr \"색상이 있는 텍스트 추출 방법\"\n\n#: ../../recipes-text.rst:700 9b6a414568c14a82b047478e4a84f66a\nmsgid \"\"\n\"Iterate through your text blocks and find the spans of text you need for \"\n\"this information.\"\nmsgstr \"텍스트 블록을 반복하고 이 정보에 필요한 텍스트 스팬을 찾으세요.\"\n\n#: ../../footer.rst:46 bdb1928a7ce24b5a9d8c30e00a139e48\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/recipes.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 5df69fce57964130a8f7ba6f591f56a4\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 948de28e8d244748b064cfd92a1bbcfd\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 11790f3e587e4e6bb551d9ae399cc35e\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../footer.rst:46 3bdca21fa122440dad23d3c3a493ace9\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/rect.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 3c227dada5ad4b709a49770ee170baa6\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 8f56716e037546c8b467b98c68c725a0\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 dfa0342751984e2f98c9f67f7362520d\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../rect.rst:7 ad45c59577c04e0d97cd0d7904581921\nmsgid \"Rect\"\nmsgstr \"Rect\"\n\n#: ../../rect.rst:9 7f5d586f3c114edaa7ba458bfd6acb19\nmsgid \"\"\n\"*Rect* represents a rectangle defined by four floating point numbers x0, \"\n\"y0, x1, y1. They are treated as being coordinates of two diagonally \"\n\"opposite points. The first two numbers are regarded as the \\\"top left\\\" \"\n\"corner P\\\\ :sub:`(x0,y0)` and P\\\\ :sub:`(x1,y1)` as the \\\"bottom right\\\" \"\n\"one. However, these two properties need not coincide with their intuitive\"\n\" meanings -- read on.\"\nmsgstr \"*Rect* 는 4개의 부동 소수점 숫자 x0, y0, x1, y1로 정의된 사각형을 나타냅니다. 이것들은 대각선으로 반대편에 있는 두 점의 좌표로 처리됩니다. 처음 두 숫자는 \\\"왼쪽 위\\\" 모서리 P\\\\ :sub:`(x0,y0)` 로 간주되고 P\\\\ :sub:`(x1,y1)` 는 \\\"오른쪽 아래\\\" 모서리로 간주됩니다. 그러나 이 두 속성은 직관적인 의미와 일치할 필요가 없습니다 -- 계속 읽어보세요.\"\n\n#: ../../rect.rst:11 dafcd3bc742b4bf98df8a2d355642314\nmsgid \"The following remarks are also valid for :ref:`IRect` objects:\"\nmsgstr \"다음 설명은 :ref:`IRect` 객체에도 유효합니다:\"\n\n#: ../../rect.rst:13 be324158236b4de8923841e0b42e8290\nmsgid \"\"\n\"A rectangle in the sense of (Py-) MuPDF **(and PDF)** always has \"\n\"**borders parallel to the x- resp. y-axis**. A general orthogonal \"\n\"tetragon **is not a rectangle** -- in contrast to the mathematical \"\n\"definition.\"\nmsgstr \"(Py-) MuPDF **(및 PDF)** 의 의미에서 사각형은 항상 **x축 및 y축에 평행한 경계** 를 가집니다. 일반적인 직교 사각형은 **사각형이 아닙니다** -- 수학적 정의와 대조적으로.\"\n\n#: ../../rect.rst:14 03d260254e054fa0874151431af0b147\nmsgid \"\"\n\"The constructing points can be (almost! -- see below) anywhere in the \"\n\"plane -- they need not even be different, and e.g. \\\"top left\\\" need not \"\n\"be the geometrical \\\"north-western\\\" point.\"\nmsgstr \"구성 점은 평면의 어디에나 있을 수 있습니다(거의! -- 아래 참조) -- 서로 다를 필요도 없으며, 예를 들어 \\\"왼쪽 위\\\"가 기하학적으로 \\\"북서쪽\\\" 점일 필요는 없습니다.\"\n\n#: ../../rect.rst:15 fe6fa15cf8b7439aa597e5fcf5b13134\nmsgid \"Units are in points, where 72 points is 1 inch.\"\nmsgstr \"단위는 포인트이며, 72포인트는 1인치입니다.\"\n\n#: ../../rect.rst:20 130a99f1057240a98f97beb4238fadbc\nmsgid \"\"\n\"For any given quadruple of numbers, the geometrically \\\"same\\\" rectangle \"\n\"can be defined in four different ways:\"\nmsgstr \"주어진 4개의 숫자에 대해 기하학적으로 \\\"동일한\\\" 사각형은 4가지 다른 방법으로 정의할 수 있습니다:\"\n\n#: ../../rect.rst:17 03ee461b9fd7463e92b92b0999c2952b\nmsgid \"Rect(P\\\\ :sub:`(x0,y0)`, P\\\\ :sub:`(x1,y1)`\\\\ )\"\nmsgstr \"Rect(P\\\\ :sub:`(x0,y0)`, P\\\\ :sub:`(x1,y1)`\\\\ )\"\n\n#: ../../rect.rst:18 4e4f6956c7774df98b15fe8f1f149cef\nmsgid \"Rect(P\\\\ :sub:`(x1,y1)`, P\\\\ :sub:`(x0,y0)`\\\\ )\"\nmsgstr \"Rect(P\\\\ :sub:`(x1,y1)`, P\\\\ :sub:`(x0,y0)`\\\\ )\"\n\n#: ../../rect.rst:19 7b63166e1f914252a70101cc5e25c590\nmsgid \"Rect(P\\\\ :sub:`(x0,y1)`, P\\\\ :sub:`(x1,y0)`\\\\ )\"\nmsgstr \"Rect(P\\\\ :sub:`(x0,y1)`, P\\\\ :sub:`(x1,y0)`\\\\ )\"\n\n#: ../../rect.rst:20 baae5ac330ae44adb90f80708b977873\nmsgid \"Rect(P\\\\ :sub:`(x1,y0)`, P\\\\ :sub:`(x0,y1)`\\\\ )\"\nmsgstr \"Rect(P\\\\ :sub:`(x1,y0)`, P\\\\ :sub:`(x0,y1)`\\\\ )\"\n\n#: ../../rect.rst:22 3775def55ff3492ea62cba278b2ff00e\nmsgid \"**(Changed in v1.19.0)** Hence some classification:\"\nmsgstr \"**(v1.19.0에서 변경됨)** 따라서 다음과 같은 분류가 있습니다:\"\n\n#: ../../rect.rst:24 005b82343a4c4d4282a0fc3d8a056830\nmsgid \"\"\n\"A rectangle is called **valid** if `x0 <= x1` and `y0 <= y1` (i.e. the \"\n\"bottom right point is \\\"south-eastern\\\" to the top left one), otherwise \"\n\"**invalid**. Of the four alternatives above, **only the first** is valid.\"\n\" Please take into account, that in MuPDF's coordinate system, the y-axis \"\n\"is oriented from **top to bottom**. Invalid rectangles have been called \"\n\"infinite in earlier versions.\"\nmsgstr \"사각형은 `x0 <= x1` 이고 `y0 <= y1` 인 경우(즉, 오른쪽 아래 점이 왼쪽 위 점의 \\\"남동쪽\\\"에 있는 경우) **유효** 라고 하며, 그렇지 않으면 **무효** 입니다. 위의 4가지 대안 중 **첫 번째만** 유효합니다. MuPDF의 좌표계에서 y축은 **위에서 아래로** 향한다는 점을 고려하세요. 무효한 사각형은 이전 버전에서 무한이라고 불렸습니다.\"\n\n#: ../../rect.rst:26 50cc1e1a23b7410e9b40d9e4a22e2552\nmsgid \"\"\n\"A rectangle is called **empty** if `x0 >= x1` or `y0 >= y1`. This \"\n\"implies, that **invalid rectangles are also always empty.** And `width` \"\n\"(resp. `height`) is **set to zero** if `x0 > x1` (resp. `y0 > y1`). In \"\n\"previous versions, a rectangle was empty only if one of width or height \"\n\"was zero.\"\nmsgstr \"사각형은 `x0 >= x1` 또는 `y0 >= y1` 인 경우 **비어 있음** 이라고 합니다. 이것은 **무효한 사각형도 항상 비어 있음** 을 의미합니다. 그리고 `x0 > x1` (각각 `y0 > y1`)인 경우 `width` (각각 `height`)는 **0으로 설정** 됩니다. 이전 버전에서는 너비 또는 높이 중 하나가 0인 경우에만 사각형이 비어 있었습니다.\"\n\n#: ../../rect.rst:28 6b8c92c5c94146e38742390553f50ad5\nmsgid \"\"\n\"Rectangle coordinates **cannot be outside** the number range from \"\n\"`FZ_MIN_INF_RECT = -2147483648` to `FZ_MAX_INF_RECT = 2147483520`. Both \"\n\"values have been chosen, because they are the smallest / largest 32bit \"\n\"integers that survive C float conversion roundtrips. In previous versions\"\n\" there was no limit for coordinate values.\"\nmsgstr \"사각형 좌표는 `FZ_MIN_INF_RECT = -2147483648` 부터 `FZ_MAX_INF_RECT = 2147483520` 까지의 숫자 범위 **밖에 있을 수 없습니다**. 두 값은 C float 변환 왕복에서 살아남는 가장 작은/가장 큰 32비트 정수이기 때문에 선택되었습니다. 이전 버전에서는 좌표 값에 제한이 없었습니다.\"\n\n#: ../../rect.rst:30 f7c36d56736842c7b5057e7ce77215f1\nmsgid \"\"\n\"There is **exactly one \\\"infinite\\\" rectangle**, defined by `x0 = y0 = \"\n\"FZ_MIN_INF_RECT` and `x1 = y1 = FZ_MAX_INF_RECT`. It contains every other\"\n\" rectangle. It is mainly used for technical purposes -- e.g. when a \"\n\"function call should ignore a formally required rectangle argument. This \"\n\"rectangle is not empty.\"\nmsgstr \"**정확히 하나의 \\\"무한\\\" 사각형** 이 있으며, `x0 = y0 = FZ_MIN_INF_RECT` 및 `x1 = y1 = FZ_MAX_INF_RECT` 로 정의됩니다. 이것은 다른 모든 사각형을 포함합니다. 이것은 주로 기술적 목적으로 사용됩니다 -- 예를 들어 함수 호출이 형식적으로 필요한 사각형 인수를 무시해야 할 때. 이 사각형은 비어 있지 않습니다.\"\n\n#: ../../rect.rst:32 3fd9c878f8a345649eececf661fa6d0d\nmsgid \"\"\n\"**Rectangles are (semi-) open:** The right and the bottom edges \"\n\"(including the resp. corners) are not considered part of the rectangle. \"\n\"This implies, that only the top-left corner `(x0, y0)` can ever belong to\"\n\" the rectangle - the other three corners never do. An empty rectangle \"\n\"contains no corners at all.\"\nmsgstr \"**사각형은 (반)열림:** 오른쪽과 아래쪽 가장자리(각각의 모서리 포함)는 사각형의 일부로 간주되지 않습니다. 이것은 왼쪽 위 모서리 `(x0, y0)` 만 사각형에 속할 수 있음을 의미합니다 -- 다른 세 모서리는 절대 속하지 않습니다. 빈 사각형은 모서리가 전혀 없습니다.\"\n\n#: ../../rect.rst:38 e57daedf444e46e1b812656ca7832537\nmsgid \"Here is an overview of the changes.\"\nmsgstr \"다음은 변경 사항의 개요입니다.\"\n\n#: ../../rect.rst:41 d393f3a6d9de4c8fa2e06182c5f78760\nmsgid \"Notion\"\nmsgstr \"개념\"\n\n#: ../../rect.rst:41 d97438c124b14f35aa198e1ddfb8cfd0\nmsgid \"Versions < 1.19.0\"\nmsgstr \"버전 < 1.19.0\"\n\n#: ../../rect.rst:41 7af7abdfb7bc4aa4b28ed21073d90bea\nmsgid \"Versions 1.19.*\"\nmsgstr \"버전 1.19.*\"\n\n#: ../../rect.rst:43 e4224c064e3f4f68bbb16f57e9a1c844\nmsgid \"empty\"\nmsgstr \"비어 있음\"\n\n#: ../../rect.rst:43 48dde36927434fceacc3a177956672c7\nmsgid \"x0 = x1 or y0 = y1\"\nmsgstr \"x0 = x1 또는 y0 = y1\"\n\n#: ../../rect.rst:43 3835fcc0738d40929f1271a1c05290b9\nmsgid \"x0 >= x1 or y0 >= y1 -- includes invalid rects\"\nmsgstr \"x0 >= x1 또는 y0 >= y1 -- 무효한 사각형 포함\"\n\n#: ../../rect.rst:44 f6c28fec698849cf9309e6c849791287\nmsgid \"valid\"\nmsgstr \"유효\"\n\n#: ../../rect.rst:44 754108a5de3646168f6a70e07a111bd9\nmsgid \"n/a\"\nmsgstr \"해당 없음\"\n\n#: ../../rect.rst:44 e09f640fd0134a039d61766e33a9c329\nmsgid \"x0 <= x1 and y0 <= y1\"\nmsgstr \"x0 <= x1 및 y0 <= y1\"\n\n#: ../../rect.rst:45 17a59c383cd546c8adfe6a7d8ef48da9\nmsgid \"infinite\"\nmsgstr \"무한\"\n\n#: ../../rect.rst:45 65113a7b423f4f98b9ce9fcada710d50\nmsgid \"all rects where x0 > x1 or y1 > y0\"\nmsgstr \"x0 > x1 또는 y1 > y0인 모든 사각형\"\n\n#: ../../rect.rst:45 41c40bda2ada47e085b2f7f2004a8b76\nmsgid \"**exactly one infinite rect / irect!**\"\nmsgstr \"**정확히 하나의 무한 rect / irect!**\"\n\n#: ../../rect.rst:46 4f4ac3d83ad64ebba6176c33b68c4cb3\nmsgid \"coordinate values\"\nmsgstr \"좌표 값\"\n\n#: ../../rect.rst:46 453a3c51c1434dc5b1579f747187deb0\nmsgid \"all numbers\"\nmsgstr \"모든 숫자\"\n\n#: ../../rect.rst:46 4ca5d71efdb04d8693a83e57697d9d37\nmsgid \"`FZ_MIN_INF_RECT <= number <= FZ_MAX_INF_RECT`\"\nmsgstr \"`FZ_MIN_INF_RECT <= number <= FZ_MAX_INF_RECT`\"\n\n#: ../../rect.rst:47 2209987532a249858e55c63d07e52b9c\nmsgid \"borders, corners\"\nmsgstr \"경계, 모서리\"\n\n#: ../../rect.rst:47 b6ae01c480064de9b11987d6892db4ca\nmsgid \"are parts of the rectangle\"\nmsgstr \"사각형의 일부\"\n\n#: ../../rect.rst:47 8ef673ab0bbc4257baaeffbe19220f28\nmsgid \"right and bottom corners and edges **are outside**\"\nmsgstr \"오른쪽 및 아래쪽 모서리와 가장자리는 **외부**\"\n\n#: ../../rect.rst:50 e3e932700fd949daa0353b543c8a1a4c\nmsgid \"\"\n\"There are new top level functions defining infinite and standard empty \"\n\"rectangles and quads, see :meth:`INFINITE_RECT` and friends.\"\nmsgstr \"무한 및 표준 빈 사각형과 quad를 정의하는 새로운 최상위 함수가 있습니다. :meth:`INFINITE_RECT` 및 관련 항목을 참조하세요.\"\n\n#: ../../rect.rst:54 81a610b0aa1f472b8ae9fea35a2a2c01\nmsgid \"**Methods / Attributes**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../rect.rst:54 4ed08c7116224212b88dc25acd42d0b0\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../rect.rst:56 5981a119a05e4daa876289ac03fc5a13\nmsgid \":meth:`Rect.contains`\"\nmsgstr \":meth:`Rect.contains`\"\n\n#: ../../rect.rst:56 3b511deb4033483dbea1c5c304c2ec6f\nmsgid \"checks containment of point_likes and rect_likes\"\nmsgstr \"point_like 및 rect_like의 포함 여부 확인\"\n\n#: ../../rect.rst:57 9f5f335e79444316a8a3c6dea665cf95\nmsgid \":meth:`Rect.get_area`\"\nmsgstr \":meth:`Rect.get_area`\"\n\n#: ../../rect.rst:57 1de8d41280804dcf9822b29195cfe5fe\nmsgid \"calculate rectangle area\"\nmsgstr \"사각형 영역 계산\"\n\n#: ../../rect.rst:58 7a22090e4a0d467a8ad2400c55ed9f2f\nmsgid \":meth:`Rect.include_point`\"\nmsgstr \":meth:`Rect.include_point`\"\n\n#: ../../rect.rst:58 0526b2070f7e45feab7a311c9ee31128\nmsgid \"enlarge rectangle to also contain a point\"\nmsgstr \"점도 포함하도록 사각형 확대\"\n\n#: ../../rect.rst:59 5d2792546865489e8ac28d97886676fb\nmsgid \":meth:`Rect.include_rect`\"\nmsgstr \":meth:`Rect.include_rect`\"\n\n#: ../../rect.rst:59 d9b74ad40df64c1da33f10578102b172\nmsgid \"enlarge rectangle to also contain another one\"\nmsgstr \"다른 사각형도 포함하도록 사각형 확대\"\n\n#: ../../rect.rst:60 a084869227454408971a27d515578280\nmsgid \":meth:`Rect.intersect`\"\nmsgstr \":meth:`Rect.intersect`\"\n\n#: ../../rect.rst:60 fc0d24eaf262443a9767ab3a639a91cf\nmsgid \"common part with another rectangle\"\nmsgstr \"다른 사각형과의 공통 부분\"\n\n#: ../../rect.rst:61 783c6bb9f98a4c9a9173a33426e15261\nmsgid \":meth:`Rect.intersects`\"\nmsgstr \":meth:`Rect.intersects`\"\n\n#: ../../rect.rst:61 48c32f08f9bd4fcaba35388fa46ffb7d\nmsgid \"checks for non-empty intersections\"\nmsgstr \"비어 있지 않은 교집합 확인\"\n\n#: ../../rect.rst:62 54b41e15307745659f567a94fe69654b\nmsgid \":meth:`Rect.morph`\"\nmsgstr \":meth:`Rect.morph`\"\n\n#: ../../rect.rst:62 2724138758314afea0cd2a6f82c22cdd\nmsgid \"transform with a point and a matrix\"\nmsgstr \"점과 행렬로 변환\"\n\n#: ../../rect.rst:63 fa29117650a04cf992bfbf167039b34d\nmsgid \":meth:`Rect.torect`\"\nmsgstr \":meth:`Rect.torect`\"\n\n#: ../../rect.rst:63 a1b856036d3a4a869c4bfef61e84bc7d\nmsgid \"the matrix that transforms to another rectangle\"\nmsgstr \"다른 사각형으로 변환하는 행렬\"\n\n#: ../../rect.rst:64 eb541dbc3c38455b94ddf221f6366d80\nmsgid \":meth:`Rect.norm`\"\nmsgstr \":meth:`Rect.norm`\"\n\n#: ../../rect.rst:64 61a0e738f2784973be15065b6e9b3bf2\nmsgid \"the Euclidean norm\"\nmsgstr \"유클리드 노름\"\n\n#: ../../rect.rst:65 e9cec2f1207b4e358bcb22df6331bb76\nmsgid \":meth:`Rect.normalize`\"\nmsgstr \":meth:`Rect.normalize`\"\n\n#: ../../rect.rst:65 8ba545c6dd824fd08fd072a2c568c6db\nmsgid \"makes a rectangle valid\"\nmsgstr \"사각형을 유효하게 만듦\"\n\n#: ../../rect.rst:66 ebfc99cce7a74afabc7adf051e9804cc\nmsgid \":meth:`Rect.round`\"\nmsgstr \":meth:`Rect.round`\"\n\n#: ../../rect.rst:66 a5ff1b1dfaf54324b20c6908d06f2c7e\nmsgid \"create smallest :ref:`Irect` containing rectangle\"\nmsgstr \"사각형을 포함하는 가장 작은 :ref:`Irect` 생성\"\n\n#: ../../rect.rst:67 9c630cfbce96430dbd549ce3edbf5de2\nmsgid \":meth:`Rect.transform`\"\nmsgstr \":meth:`Rect.transform`\"\n\n#: ../../rect.rst:67 3294ada857004ea2801a93dcdcae9cbb\nmsgid \"transform rectangle with a matrix\"\nmsgstr \"행렬로 사각형 변환\"\n\n#: ../../rect.rst:68 00f6aca11ba74d9290a39ae6e4d9abdb\nmsgid \":attr:`Rect.bottom_left`\"\nmsgstr \":attr:`Rect.bottom_left`\"\n\n#: ../../rect.rst:68 d8d4c9d808554a389d40caa0c16d5a69\nmsgid \"bottom left point, synonym *bl*\"\nmsgstr \"왼쪽 아래 점, 동의어 *bl*\"\n\n#: ../../rect.rst:69 82732f58f72f413b869e3dbe3fc017dd\nmsgid \":attr:`Rect.bottom_right`\"\nmsgstr \":attr:`Rect.bottom_right`\"\n\n#: ../../rect.rst:69 25213177c72349529fffc2b8650278c6\nmsgid \"bottom right point, synonym *br*\"\nmsgstr \"오른쪽 아래 점, 동의어 *br*\"\n\n#: ../../rect.rst:70 dee76b0bf2084300ae141c9fc27008bb\nmsgid \":attr:`Rect.height`\"\nmsgstr \":attr:`Rect.height`\"\n\n#: ../../rect.rst:70 7fec492b654e4a6c8f203435ebdcb0e3\nmsgid \"rectangle height\"\nmsgstr \"사각형 높이\"\n\n#: ../../rect.rst:71 948cec288c54453aa28f00e584acce0b\nmsgid \":attr:`Rect.irect`\"\nmsgstr \":attr:`Rect.irect`\"\n\n#: ../../rect.rst:71 a1899a79673d49c5a4273f091b474322\nmsgid \"equals result of method *round()*\"\nmsgstr \"메서드 *round()* 의 결과와 같음\"\n\n#: ../../rect.rst:72 d60c028c8e234efe9a338e184bb6bc55\nmsgid \":attr:`Rect.is_empty`\"\nmsgstr \":attr:`Rect.is_empty`\"\n\n#: ../../rect.rst:72 95f758bc9cc644d6a61e703bee39b954\nmsgid \"whether rectangle is empty\"\nmsgstr \"사각형이 비어 있는지 여부\"\n\n#: ../../rect.rst:73 3d96f5aae5a54e4eac8a41dc8027ebe2\nmsgid \":attr:`Rect.is_valid`\"\nmsgstr \":attr:`Rect.is_valid`\"\n\n#: ../../rect.rst:73 0d07626ab6d5457c93ed36d852fe9dc5\nmsgid \"whether rectangle is valid\"\nmsgstr \"사각형이 유효한지 여부\"\n\n#: ../../rect.rst:74 ec6784767db149e1af2d3bed517a3154\nmsgid \":attr:`Rect.is_infinite`\"\nmsgstr \":attr:`Rect.is_infinite`\"\n\n#: ../../rect.rst:74 e2775e5155c94511a9a0b4351aa5aeed\nmsgid \"whether rectangle is infinite\"\nmsgstr \"사각형이 무한한지 여부\"\n\n#: ../../rect.rst:75 27198e6de32c47129ff1d90e9bcd052b\nmsgid \":attr:`Rect.top_left`\"\nmsgstr \":attr:`Rect.top_left`\"\n\n#: ../../rect.rst:75 991fbeb519074c779da08190535db4a5\nmsgid \"top left point, synonym *tl*\"\nmsgstr \"왼쪽 위 점, 동의어 *tl*\"\n\n#: ../../rect.rst:76 ee1026c3112e4ce5ace785e6dbd51983\nmsgid \":attr:`Rect.top_right`\"\nmsgstr \":attr:`Rect.top_right`\"\n\n#: ../../rect.rst:76 a429e926fb354c3eacca067673ad17f3\nmsgid \"top_right point, synonym *tr*\"\nmsgstr \"오른쪽 위 점, 동의어 *tr*\"\n\n#: ../../rect.rst:77 5a5eef69cfdd4fc1b267e64d1899c83d\nmsgid \":attr:`Rect.quad`\"\nmsgstr \":attr:`Rect.quad`\"\n\n#: ../../rect.rst:77 39bf27b7ec18496996041d704db52fa2\nmsgid \":ref:`Quad` made from rectangle corners\"\nmsgstr \"사각형 모서리로 만든 :ref:`Quad`\"\n\n#: ../../rect.rst:78 b77feb74e6d84afe86da1aa9ffd1d688\nmsgid \":attr:`Rect.width`\"\nmsgstr \":attr:`Rect.width`\"\n\n#: ../../rect.rst:78 ba35625a52bb44278539861d0133f079\nmsgid \"rectangle width\"\nmsgstr \"사각형 너비\"\n\n#: ../../rect.rst:79 38859d042e6f49b88c35544ec6e4ed3c\nmsgid \":attr:`Rect.x0`\"\nmsgstr \":attr:`Rect.x0`\"\n\n#: ../../rect.rst:79 7e53ad8c6a824feca26905c64f3e0ea3\nmsgid \"left corners' x coordinate\"\nmsgstr \"왼쪽 모서리의 x 좌표\"\n\n#: ../../rect.rst:80 f4f68e6053a840c2a566cf242d7f05b1\nmsgid \":attr:`Rect.x1`\"\nmsgstr \":attr:`Rect.x1`\"\n\n#: ../../rect.rst:80 b53b5091498c454d88765a544d585de5\nmsgid \"right corners' x -coordinate\"\nmsgstr \"오른쪽 모서리의 x 좌표\"\n\n#: ../../rect.rst:81 91c7514c010f464098de9b6e9007f4a8\nmsgid \":attr:`Rect.y0`\"\nmsgstr \":attr:`Rect.y0`\"\n\n#: ../../rect.rst:81 119b6bb77d59497fa78ea76552d86acd\nmsgid \"top corners' y coordinate\"\nmsgstr \"위쪽 모서리의 y 좌표\"\n\n#: ../../rect.rst:82 45436c8c00564776b422a0208c48ae3d\nmsgid \":attr:`Rect.y1`\"\nmsgstr \":attr:`Rect.y1`\"\n\n#: ../../rect.rst:82 251741ae294247ddadf61d053276d89f\nmsgid \"bottom corners' y coordinate\"\nmsgstr \"아래쪽 모서리의 y 좌표\"\n\n#: ../../rect.rst:85 d211a7b97cc54d93b48553a9425130b9\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../rect.rst:103 01827e33142142419f360c9f35834288\nmsgid \"\"\n\"Overloaded constructors: *top_left*, *bottom_right* stand for \"\n\":data:`point_like` objects, \\\"sequence\\\" is a Python sequence type of 4 \"\n\"numbers (see :ref:`SequenceTypes`), \\\"rect\\\" means another \"\n\":data:`rect_like`, while the other parameters mean coordinates.\"\nmsgstr \"오버로드된 생성자: *top_left*, *bottom_right* 는 :data:`point_like` 객체를 나타내고, \\\"sequence\\\"는 4개의 숫자로 구성된 Python 시퀀스 유형(:ref:`SequenceTypes` 참조)이며, \\\"rect\\\"는 다른 :data:`rect_like` 를 의미하고, 다른 매개변수는 좌표를 의미합니다.\"\n\n#: ../../rect.rst:105 e075a06a3e264a5fbf6aea37d81f20d9\nmsgid \"If \\\"rect\\\" is specified, the constructor creates a **new copy** of it.\"\nmsgstr \"\\\"rect\\\"가 지정되면 생성자는 그것의 **새 복사본** 을 만듭니다.\"\n\n#: ../../rect.rst:107 1f9d77ad703345a2a3964ae75caea048\nmsgid \"\"\n\"Without parameters, the empty rectangle ``Rect(0.0, 0.0, 0.0, 0.0)`` is \"\n\"created.\"\nmsgstr \"매개변수 없이 빈 사각형 ``Rect(0.0, 0.0, 0.0, 0.0)`` 이 생성됩니다.\"\n\n#: ../../rect.rst:111 f10e380576a7412d80886a3b8a51700e\nmsgid \"\"\n\"Creates the smallest containing :ref:`IRect`. This is **not the same** as\"\n\" simply rounding the rectangle's edges: The top left corner is rounded \"\n\"upwards and to the left while the bottom right corner is rounded \"\n\"downwards and to the right.\"\nmsgstr \"가장 작은 포함 :ref:`IRect` 를 생성합니다. 이것은 단순히 사각형의 가장자리를 반올림하는 것과 **동일하지 않습니다**: 왼쪽 위 모서리는 위쪽과 왼쪽으로 반올림되고 오른쪽 아래 모서리는 아래쪽과 오른쪽으로 반올림됩니다.\"\n\n#: ../../rect.rst:116 552d25bc341a48aba138b957a55b9e83\nmsgid \"If the rectangle is **empty**, the result is also empty.\"\nmsgstr \"사각형이 **비어 있으면** 결과도 비어 있습니다.\"\n\n#: ../../rect.rst:117 df26f93d58284c6a970ae3863ef681bb\nmsgid \"\"\n\"**Possible paradox:** The result may be empty, **even if** the rectangle \"\n\"is **not** empty! In such cases, the result obviously does **not** \"\n\"contain the rectangle. This is because MuPDF's algorithm allows for a \"\n\"small tolerance (1e-3). Example:\"\nmsgstr \"**가능한 역설:** 사각형이 **비어 있지 않아도** 결과가 비어 있을 수 있습니다! 이러한 경우 결과는 명백히 사각형을 **포함하지 않습니다**. 이것은 MuPDF의 알고리즘이 작은 허용 오차(1e-3)를 허용하기 때문입니다. 예:\"\n\n#: ../../rect.rst 223b51190466453684b2185f3dfc69c0\n#: 297e474bcf4f49858a23f80dd7128c65 388342f8d94e4d26b238b48872bd5511\n#: 4f188f0a74b347a8ba82283a386abbde 6c7f84d51c1c4b3b9dcf69c73a6d6715\n#: 6f729bc4a8b948998da46a928feb54e6 96b897da73d141458d7b0fa47bb6846a\n#: f8ae67a6da5847d7838f6d57ffbba97e\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../rect.rst:127 31c287fef6e3445cafe94d866b5e73bf\nmsgid \":ref:`IRect`\"\nmsgstr \":ref:`IRect`\"\n\n#: ../../rect.rst:131 c8c2cfc194a8468fa9550492f440f872\nmsgid \"\"\n\"Transforms the rectangle with a matrix and **replaces the original**. If \"\n\"the rectangle is empty or infinite, this is a no-operation.\"\nmsgstr \"행렬로 사각형을 변환하고 **원본을 대체** 합니다. 사각형이 비어 있거나 무한이면 아무 작업도 수행하지 않습니다.\"\n\n#: ../../rect.rst 1769e651f3b64df78e388f49683edfc2\n#: 312414a60f5241d7abaee3b012e0c7f4 54d06860552f4fa4bf1e92782d2b517a\n#: aecbea35a63240b7bb02c03f083daacf d9b739a44f4b427b9772f8da4198b7b3\n#: dca5e2461b874ed6ac599ed5bf67591e dd42b3800611490e9091e6942a813e85\n#: e64ab107750d4908974794940a14b516 f9eb8fc37f314b86bb12b6037ad64aca\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../rect.rst:133 17bbbee58ca246578928bb7c3f404ef5\nmsgid \"The matrix for the transformation.\"\nmsgstr \"변환을 위한 행렬.\"\n\n#: ../../rect.rst:136 5b54b6fd35e047b9b19b8e92d649c886\nmsgid \"``Rect``\"\nmsgstr \"``Rect``\"\n\n#: ../../rect.rst ad2d6666f58d4edab133c0b63812dad1\n#: ee287750d1ff4757a1f4aab28350cc3f f617b587a6e84a1d879ad6eb2a4b8163\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../rect.rst:137 9310c42c457243d2adf6a8ef7e65abb4\nmsgid \"the smallest rectangle that contains the transformed original.\"\nmsgstr \"변환된 원본을 포함하는 가장 작은 사각형.\"\n\n#: ../../rect.rst:141 515fef48ca8a47adbebb14b402eb85f4\nmsgid \"\"\n\"The intersection (common rectangular area, largest rectangle contained in\"\n\" both) of the current rectangle and *r* is calculated and **replaces the \"\n\"current** rectangle. If either rectangle is empty, the result is also \"\n\"empty. If *r* is infinite, this is a no-operation. If the rectangles are \"\n\"(mathematically) disjoint sets, then the result is invalid. If the result\"\n\" is valid but empty, then the rectangles touch each other in a corner or \"\n\"(part of) a side.\"\nmsgstr \"현재 사각형과 *r* 의 교집합(공통 사각형 영역, 둘 다에 포함된 가장 큰 사각형)이 계산되어 **현재** 사각형을 **대체** 합니다. 사각형 중 하나가 비어 있으면 결과도 비어 있습니다. *r* 이 무한이면 아무 작업도 수행하지 않습니다. 사각형이 (수학적으로) 서로소 집합이면 결과는 무효입니다. 결과가 유효하지만 비어 있으면 사각형은 모서리 또는 (일부) 변에서 서로 접촉합니다.\"\n\n#: ../../rect.rst:143 ../../rect.rst:150 5ae4d4eaacb44add974c0aa6cf33f6f8\n#: cb94768c038d40d6be30db81f8988f9e\nmsgid \"Second rectangle\"\nmsgstr \"두 번째 사각형\"\n\n#: ../../rect.rst:148 db7d498e829c4302919da10e026d8ac5\nmsgid \"\"\n\"The smallest rectangle containing the current one and ``r`` is calculated\"\n\" and **replaces the current** one. If either rectangle is infinite, the \"\n\"result is also infinite. If ``r`` is empty, the current rectangle remains\"\n\" unchanged. Else if the current rectangle is empty, it is replaced by \"\n\"``r``.\"\nmsgstr \"현재 사각형과 ``r`` 을 포함하는 가장 작은 사각형이 계산되어 **현재** 사각형을 **대체** 합니다. 사각형 중 하나가 무한이면 결과도 무한입니다. ``r`` 이 비어 있으면 현재 사각형은 변경되지 않습니다. 현재 사각형이 비어 있으면 ``r`` 로 대체됩니다.\"\n\n#: ../../rect.rst:155 d539db24271d4c00bd98e51fb2c3f2ab\nmsgid \"\"\n\"The smallest rectangle containing the current one and :data:`point_like` \"\n\"``p`` is calculated and **replaces the current** one. **The infinite \"\n\"rectangle remains unchanged.** To create the rectangle that wraps a \"\n\"sequence of points, start with :meth:`EMPTY_RECT` and successively \"\n\"include the members of the sequence.\"\nmsgstr \"현재 사각형과 :data:`point_like` ``p`` 를 포함하는 가장 작은 사각형이 계산되어 **현재** 사각형을 **대체** 합니다. **무한 사각형은 변경되지 않습니다.** 점 시퀀스를 감싸는 사각형을 만들려면 :meth:`EMPTY_RECT` 로 시작하여 시퀀스의 멤버를 순차적으로 포함하세요.\"\n\n#: ../../rect.rst:157 6a72290dd49345a0a63b3757d59663ca\nmsgid \"Point to include.\"\nmsgstr \"포함할 점.\"\n\n#: ../../rect.rst:163 ba33391fc40040a4a994136d913ee366\nmsgid \"\"\n\"Calculate the area of the rectangle and, with no parameter, equals \"\n\"*abs(rect)*. Like an empty rectangle, the area of an infinite rectangle \"\n\"is also zero. So, at least one of *pymupdf.Rect(p1, p2)* and \"\n\"*pymupdf.Rect(p2, p1)* has a zero area.\"\nmsgstr \"사각형의 영역을 계산하며, 매개변수 없이는 *abs(rect)* 와 같습니다. 빈 사각형과 마찬가지로 무한 사각형의 영역도 0입니다. 따라서 *pymupdf.Rect(p1, p2)* 와 *pymupdf.Rect(p2, p1)* 중 적어도 하나는 영역이 0입니다.\"\n\n#: ../../rect.rst:165 6f367ec895b04a5282f232e658390010\nmsgid \"\"\n\"Specify required unit: respective squares of *px* (pixels, default), *in*\"\n\" (inches), *cm* (centimeters), or *mm* (millimeters).\"\nmsgstr \"필요한 단위 지정: *px* (픽셀, 기본값), *in* (인치), *cm* (센티미터) 또는 *mm* (밀리미터)의 각각의 제곱.\"\n\n#: ../../rect.rst:170 f1fdbdae13644bca9624eea1bed293ba\nmsgid \"\"\n\"Checks whether *x* is contained in the rectangle. It may be an *IRect*, \"\n\"*Rect*, *Point* or number. If *x* is an empty rectangle, this is always \"\n\"true. If the rectangle is empty this is always ``False`` for all non-\"\n\"empty rectangles and for all points. `x in rect` and `rect.contains(x)` \"\n\"are equivalent.\"\nmsgstr \"*x* 가 사각형에 포함되어 있는지 확인합니다. 이것은 *IRect*, *Rect*, *Point* 또는 숫자일 수 있습니다. *x* 가 빈 사각형이면 이것은 항상 true입니다. 사각형이 비어 있으면 모든 비어 있지 않은 사각형과 모든 점에 대해 이것은 항상 ``False`` 입니다. `x in rect` 와 `rect.contains(x)` 는 동일합니다.\"\n\n#: ../../rect.rst:172 ca3270a90eac40a4bbb2ec88e8547446\nmsgid \"the object to check.\"\nmsgstr \"확인할 객체.\"\n\n#: ../../rect.rst:179 a2c14b05b36d4decbe4367b3aa764e2f\nmsgid \"\"\n\"Checks whether the rectangle and a :data:`rect_like` \\\"r\\\" contain a \"\n\"common non-empty :ref:`Rect`. This will always be ``False`` if either is \"\n\"infinite or empty.\"\nmsgstr \"사각형과 :data:`rect_like` \\\"r\\\"이 공통의 비어 있지 않은 :ref:`Rect` 를 포함하는지 확인합니다. 둘 중 하나가 무한이거나 비어 있으면 이것은 항상 ``False`` 입니다.\"\n\n#: ../../rect.rst:181 fd7c3c60afa7402f98f4d782416f106d\nmsgid \"the rectangle to check.\"\nmsgstr \"확인할 사각형.\"\n\n#: ../../rect.rst:187 a9fe2a547ab44768a39b47d8d9ef868e\nmsgid \"New in version 1.19.3\"\nmsgstr \"버전 1.19.3에서 새로 추가됨\"\n\n#: ../../rect.rst:189 d15a89c433be470288ee2017503a040f\nmsgid \"Compute the matrix which transforms this rectangle to a given one.\"\nmsgstr \"이 사각형을 주어진 사각형으로 변환하는 행렬을 계산합니다.\"\n\n#: ../../rect.rst:191 7492eabbe7d24bdba52f9f8ead663bcd\nmsgid \"the target rectangle. Must not be empty or infinite.\"\nmsgstr \"대상 사각형. 비어 있거나 무한이 아니어야 합니다.\"\n\n#: ../../rect.rst:192 1d5dde507c8b434e94689248050663f0\nmsgid \":ref:`Matrix`\"\nmsgstr \":ref:`Matrix`\"\n\n#: ../../rect.rst:193 fc8cb54b6f794b9ca05b2b2fb57c5290\nmsgid \"\"\n\"a matrix `mat` such that `self * mat = rect`. Can for example be used to \"\n\"transform between the page and the pixmap coordinates. See an example use\"\n\" here :ref:`RecipesImages_P`.\"\nmsgstr \"`self * mat = rect` 가 되는 행렬 `mat`. 예를 들어 페이지와 픽셀맵 좌표 간 변환에 사용할 수 있습니다. 사용 예는 :ref:`RecipesImages_P` 를 참조하세요.\"\n\n#: ../../rect.rst:197 6bfb5ec48e4742898de3cb22ba429c99\nmsgid \"New in version 1.17.0\"\nmsgstr \"버전 1.17.0에서 새로 추가됨\"\n\n#: ../../rect.rst:199 33c676862f1241db9159e7a0b76a9f67\nmsgid \"\"\n\"Return a new quad after applying a matrix to the rectangle using the \"\n\"fixed point `fixpoint`.\"\nmsgstr \"고정점 `fixpoint` 를 사용하여 사각형에 행렬을 적용한 후 새 quad를 반환합니다.\"\n\n#: ../../rect.rst:201 c4251e2f175d41d48a4e66ee81b8a2a0\nmsgid \"the fixed point.\"\nmsgstr \"고정점.\"\n\n#: ../../rect.rst:202 3597e1c1f5d84296b016ca74793b5554\nmsgid \"the matrix.\"\nmsgstr \"행렬.\"\n\n#: ../../rect.rst:203 e7dca746738f46ff95c1c3f83513868b\nmsgid \"\"\n\"a new :ref:`Quad`. This a wrapper for the same-named quad method. If \"\n\"infinite, the infinite quad is returned.\"\nmsgstr \"새 :ref:`Quad`. 이것은 동일한 이름의 quad 메서드의 래퍼입니다. 무한이면 무한 quad가 반환됩니다.\"\n\n#: ../../rect.rst:207 f0e8c79473044506bfc164d658cd0559\nmsgid \"New in version 1.16.0\"\nmsgstr \"버전 1.16.0에서 새로 추가됨\"\n\n#: ../../rect.rst:209 5675696559db481c8264784ff3dc7467\nmsgid \"\"\n\"Return the Euclidean norm of the rectangle treated as a vector of four \"\n\"numbers.\"\nmsgstr \"4개의 숫자 벡터로 처리된 사각형의 유클리드 노름을 반환합니다.\"\n\n#: ../../rect.rst:213 d5b4c7b243b04370ad7717618f6af173\nmsgid \"\"\n\"**Replace** the rectangle with its valid version. This is done by \"\n\"shuffling the rectangle corners. After completion of this method, the \"\n\"bottom right corner will indeed be south-eastern to the top left one (but\"\n\" may still be empty).\"\nmsgstr \"사각형을 유효한 버전으로 **대체** 합니다. 이것은 사각형 모서리를 재배치하여 수행됩니다. 이 메서드 완료 후, 오른쪽 아래 모서리는 실제로 왼쪽 위 모서리의 남동쪽이 됩니다(하지만 여전히 비어 있을 수 있습니다).\"\n\n#: ../../rect.rst:217 55f5202f243c431cb4a6aae82d228176\nmsgid \"Equals result of method *round()*.\"\nmsgstr \"메서드 *round()* 의 결과와 같습니다.\"\n\n#: ../../rect.rst:223 8ce16ab6c7df44f5abb8f92883c8d5c5\nmsgid \"Equals *Point(x0, y0)*.\"\nmsgstr \"*Point(x0, y0)* 와 같습니다.\"\n\n#: ../../rect.rst 140ba1c8d224453686c608739d150b66\n#: 17b10802a6f2405c86d6e263e499d22f 5444bac90c254f1c84d6fe7c0e28890d\n#: 5bacf55f6fdc41e0a4eaecf91679d95d 5e0076fec68344b9b5094a29a7778e51\n#: 6362dacd20114c8e8d8beda49463e502 7bdb41b9074b4fe8b70f89b3feb982f8\n#: 8b32b0a8f85c488f8622250501ee942a 9ebaad019109481ebcf4ddd743d67f01\n#: d8d182de61d74096abf1ed76f13825b2 dd68eb47fe4f425fb08826a909877002\n#: f6c692b144934eb0ba0bbce5f99825bf\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../rect.rst:225 ../../rect.rst:233 ../../rect.rst:241 ../../rect.rst:249\n#: 3bb0a2aad0b34e11b52697850a333f20 403eb084f6f64eb590a9e0627f324bc1\n#: 8690457d8ba940b09ec2249670a3ef5b 93767b206e804fd582e4db28c1eb3219\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../rect.rst:231 62f995500f554a04a83c5d7392c75231\nmsgid \"Equals `Point(x1, y0)`.\"\nmsgstr \"`Point(x1, y0)` 와 같습니다.\"\n\n#: ../../rect.rst:239 4b524e88114c4a3d9795ac77e101aac6\nmsgid \"Equals `Point(x0, y1)`.\"\nmsgstr \"`Point(x0, y1)` 와 같습니다.\"\n\n#: ../../rect.rst:247 c781f4a98d33484a8fd5eeb72de6719e\nmsgid \"Equals `Point(x1, y1)`.\"\nmsgstr \"`Point(x1, y1)` 와 같습니다.\"\n\n#: ../../rect.rst:253 4fdbb1259b894b85abf811e41bf30f7f\nmsgid \"The quadrilateral `Quad(rect.tl, rect.tr, rect.bl, rect.br)`.\"\nmsgstr \"사각형 `Quad(rect.tl, rect.tr, rect.bl, rect.br)`.\"\n\n#: ../../rect.rst:255 a29713ba4e8a43c290093038d033627b\nmsgid \":ref:`Quad`\"\nmsgstr \":ref:`Quad`\"\n\n#: ../../rect.rst:259 a19815eed800437580d69960abffb442\nmsgid \"Width of the rectangle. Equals `max(x1 - x0, 0)`.\"\nmsgstr \"사각형의 너비. `max(x1 - x0, 0)` 와 같습니다.\"\n\n#: ../../rect.rst:265 19c9fc7532244739bb242fc281fe9ab4\nmsgid \"Height of the rectangle. Equals `max(y1 - y0, 0)`.\"\nmsgstr \"사각형의 높이. `max(y1 - y0, 0)` 와 같습니다.\"\n\n#: ../../rect.rst:271 e9d9d68a615844588179b0a9c4ddb63d\nmsgid \"X-coordinate of the left corners.\"\nmsgstr \"왼쪽 모서리의 X 좌표.\"\n\n#: ../../rect.rst:273 ../../rect.rst:279 ../../rect.rst:285 ../../rect.rst:291\n#: 3159fff4ace944f5b28b66c85c40a391 595d30cddc2441798812da3e6aa60405\n#: 7d4d519c37524ecd93c59a92f14a52ee c3f30ece20574d289dd0729b1555cb67\nmsgid \"float\"\nmsgstr \"float\"\n\n#: ../../rect.rst:277 ef85ef105e694e3faab5ca56c0e0eecb\nmsgid \"Y-coordinate of the top corners.\"\nmsgstr \"위쪽 모서리의 Y 좌표.\"\n\n#: ../../rect.rst:283 01de9b8a52134ea9893026eb6219e2ed\nmsgid \"X-coordinate of the right corners.\"\nmsgstr \"오른쪽 모서리의 X 좌표.\"\n\n#: ../../rect.rst:289 0324e83243014e8facb3691297c10edd\nmsgid \"Y-coordinate of the bottom corners.\"\nmsgstr \"아래쪽 모서리의 Y 좌표.\"\n\n#: ../../rect.rst:295 63c3980c456449ab98ca919497d7ee18\nmsgid \"`True` if this is the infinite rectangle.\"\nmsgstr \"이것이 무한 사각형이면 `True`.\"\n\n#: ../../rect.rst:297 ../../rect.rst:303 ../../rect.rst:309\n#: 84e580180c7c4388939f1b2876f6eb67 9aaf58f7198848dc9acfe4b42c84ad6f\n#: b9b7f26129e94195801107367cb7fbcc\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../rect.rst:301 18ecd70d16ed40779b23464233b589ed\nmsgid \"`True` if rectangle is empty.\"\nmsgstr \"사각형이 비어 있으면 `True`.\"\n\n#: ../../rect.rst:307 472d89b6e5324c3487cd59bb9818711c\nmsgid \"`True` if rectangle is valid.\"\nmsgstr \"사각형이 유효하면 `True`.\"\n\n#: ../../rect.rst:313 9531f9684b3d4fe5add3912c57ef0e6a\nmsgid \"\"\n\"This class adheres to the Python sequence protocol, so components can be \"\n\"accessed via their index, too. Also refer to :ref:`SequenceTypes`.\"\nmsgstr \"이 클래스는 Python 시퀀스 프로토콜을 따르므로 구성 요소는 인덱스를 통해 액세스할 수도 있습니다. :ref:`SequenceTypes` 도 참조하세요.\"\n\n#: ../../rect.rst:314 a8f439886c4540a88cfb3aa32cee5363\nmsgid \"\"\n\"Rectangles can be used with arithmetic operators -- see chapter \"\n\":ref:`Algebra`.\"\nmsgstr \"사각형은 산술 연산자와 함께 사용할 수 있습니다 -- :ref:`Algebra` 장을 참조하세요.\"\n\n#: ../../footer.rst:46 7bc9c45a377e4124a0eb39872343423a\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/resources.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 ed18d6f38b3341f2bde92874aa4bc5d5\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 e9efbd58e1724907a6662c6a6d1443ed\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 f0d9191b949d4c7aaf99c05b1e804afe\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../resources.rst:6 29588c8ac283422b8882c226d20d5624\nmsgid \"Resources\"\nmsgstr \"리소스\"\n\n#: ../../resources.rst:9 226156d6aa574ae49ebbc29f7cc0ef0d\nmsgid \"**PyMuPDF Pro**\"\nmsgstr \"**PyMuPDF Pro**\"\n\n#: ../../resources.rst:12 67c0d5d5d80c4878907a81eb3091f9c3\nmsgid \"For **Office** file support `try PyMuPDF Pro <pymupdf-pro>`.\"\nmsgstr \"**Office** 파일 지원을 위해 `PyMuPDF Pro <pymupdf-pro>` 를 사용해 보세요.\"\n\n#: ../../resources.rst:20 28881f0ff7624205aac76bf0a54670e2\nmsgid \"Find out about **PyMuPDF Utilities**\"\nmsgstr \"**PyMuPDF Utilities** 에 대해 알아보기\"\n\n#: ../../resources.rst:22 a5cac2a3beb04e638f4ab889c042bce1\nmsgid \"\"\n\"The :title:`GitHub` repository `PyMuPDF-Utilities \"\n\"<https://github.com/pymupdf/PyMuPDF-Utilities>`_ contains a full range of\"\n\" examples, demonstrations and use cases.\"\nmsgstr \":title:`GitHub` 저장소 `PyMuPDF-Utilities <https://github.com/pymupdf/PyMuPDF-Utilities>`_ 에는 다양한 예제, 데모 및 사용 사례가 포함되어 있습니다.\"\n\n#: ../../resources.rst:31 ae915eee85a646ed938c77e4ca278e0f\nmsgid \"Do you need |PDF| to **DOCX** conversion?\"\nmsgstr \"|PDF| 를 **DOCX** 로 변환이 필요하신가요?\"\n\n#: ../../resources.rst:33 38b205c29ae545f79e6de0b8dda5b6a8\nmsgid \"\"\n\"We recommend the pdf2docx_ library which uses |PyMuPDF| and the **python-\"\n\"docx** library to provide simple document conversion from |PDF| to \"\n\"**DOCX** format.\"\nmsgstr \"|PDF| 에서 **DOCX** 형식으로의 간단한 문서 변환을 제공하기 위해 |PyMuPDF| 와 **python-docx** 라이브러리를 사용하는 pdf2docx_ 라이브러리를 권장합니다.\"\n\n#: ../../footer.rst:46 26ed59be763d4fe5a9384c80731d8341\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/shape.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 7909b1fec71a4bb1918715ca5918f604\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 87466d36d4244b14b06775988b5a86da\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 c4e019a1ef45475794222706f39fa6bd\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../shape.rst:6 a9435293f59542b2850588abf5b6a5c0\nmsgid \"Shape\"\nmsgstr \"Shape\"\n\n#: ../../shape.rst:8 c22618002fb44404a4ac660d7663c2a9\nmsgid \"|pdf_only_class|\"\nmsgstr \"|pdf_only_class|\"\n\n#: ../../shape.rst:10 83f7ae44343b4e29b36be26c67c582a7\nmsgid \"\"\n\"This class allows creating interconnected graphical elements on a PDF \"\n\"page. Its methods have the same meaning and name as the corresponding \"\n\":ref:`Page` methods.\"\nmsgstr \"이 클래스는 PDF 페이지에서 상호 연결된 그래픽 요소를 생성할 수 있게 합니다. 메서드는 해당 :ref:`Page` 메서드와 동일한 의미와 이름을 가집니다.\"\n\n#: ../../shape.rst:12 1687c125d94c4a889d4123d18b33a654\nmsgid \"\"\n\"In fact, each :ref:`Page` draw method is just a convenience wrapper for \"\n\"(1) one shape draw method, (2) the :meth:`Shape.finish` method, and (3) \"\n\"the :meth:`Shape.commit` method. For page text insertion, only the \"\n\":meth:`Shape.commit` method is invoked. If many draw and text operations \"\n\"are executed for a page, you should always consider using a Shape object.\"\nmsgstr \"실제로 각 :ref:`Page` draw 메서드는 (1) 하나의 shape draw 메서드, (2) :meth:`Shape.finish` 메서드, (3) :meth:`Shape.commit` 메서드에 대한 편의 래퍼입니다. 페이지 텍스트 삽입의 경우 :meth:`Shape.commit` 메서드만 호출됩니다. 페이지에 많은 그리기 및 텍스트 작업이 실행되는 경우 항상 Shape 객체 사용을 고려해야 합니다.\"\n\n#: ../../shape.rst:14 61eb314053054e4e9a36e36845c74ae6\nmsgid \"\"\n\"Several draw methods can be executed in a row and each one of them will \"\n\"contribute to one drawing. Once the drawing is complete, the \"\n\":meth:`Shape.finish` method must be invoked to apply color, dashing, \"\n\"width, morphing and other attributes.\"\nmsgstr \"여러 draw 메서드를 연속으로 실행할 수 있으며 각각이 하나의 그림에 기여합니다. 그림이 완료되면 :meth:`Shape.finish` 메서드를 호출하여 색상, 대시, 너비, 변형 및 기타 속성을 적용해야 합니다.\"\n\n#: ../../shape.rst:16 f3481ff5d87c41998cb0f7de7874cbee\nmsgid \"\"\n\"**Draw** methods of this class (and :meth:`Shape.insert_textbox`) are \"\n\"logging the area they are covering in a rectangle (:attr:`Shape.rect`). \"\n\"This property can for instance be used to set \"\n\":attr:`Page.cropbox_position`.\"\nmsgstr \"이 클래스의 **Draw** 메서드(및 :meth:`Shape.insert_textbox`)는 사각형(:attr:`Shape.rect`)에서 덮고 있는 영역을 기록합니다. 이 속성은 예를 들어 :attr:`Page.cropbox_position` 을 설정하는 데 사용할 수 있습니다.\"\n\n#: ../../shape.rst:18 93fc8032a8144e439538867e5d7d9ff1\nmsgid \"\"\n\"**Text insertions** :meth:`Shape.insert_text` and \"\n\":meth:`Shape.insert_textbox` implicitly execute a \\\"finish\\\" and \"\n\"therefore only require :meth:`Shape.commit` to become effective. As a \"\n\"consequence, both include parameters for controlling properties like \"\n\"colors, etc.\"\nmsgstr \"**텍스트 삽입** :meth:`Shape.insert_text` 및 :meth:`Shape.insert_textbox` 는 암시적으로 \\\"finish\\\"를 실행하므로 효과를 발휘하려면 :meth:`Shape.commit` 만 필요합니다. 결과적으로 둘 다 색상 등의 속성을 제어하는 매개변수를 포함합니다.\"\n\n#: ../../shape.rst:21 7753ef6a86874229bc626bf090e7fd68\nmsgid \"**Method / Attribute**\"\nmsgstr \"**Method / Attribute**\"\n\n#: ../../shape.rst:21 21306cc0a07a4be8b729f6d593a2a25e\nmsgid \"**Description**\"\nmsgstr \"**Description**\"\n\n#: ../../shape.rst:23 76875c2923b44844919d4f7dbc4ff2ae\nmsgid \":meth:`Shape.commit`\"\nmsgstr \"\"\n\n#: ../../shape.rst:23 b6e101dde14a4c0399c2d1e32dfae0e3\nmsgid \"update the page's contents\"\nmsgstr \"페이지의 콘텐츠 업데이트\"\n\n#: ../../shape.rst:24 68e32b027b2a42519c263a5d79f0aca5\nmsgid \":meth:`Shape.draw_bezier`\"\nmsgstr \"\"\n\n#: ../../shape.rst:24 cfd73fa2818546d897d3cc7dbf43cb7f\nmsgid \"draw a cubic Bezier curve\"\nmsgstr \"3차 Bezier 곡선 그리기\"\n\n#: ../../shape.rst:25 4f7b9a227586442b8c80cfc50bb5d2f6\nmsgid \":meth:`Shape.draw_circle`\"\nmsgstr \"\"\n\n#: ../../shape.rst:25 9f885ddec57646dc9618b9b296ef806e\nmsgid \"draw a circle around a point\"\nmsgstr \"점 주위에 원 그리기\"\n\n#: ../../shape.rst:26 aa0ac0a299bb4cacbdb189b821d1057f\nmsgid \":meth:`Shape.draw_curve`\"\nmsgstr \"\"\n\n#: ../../shape.rst:26 444333668308404a995780c7c2ffd1e8\nmsgid \"draw a cubic Bezier using one helper point\"\nmsgstr \"하나의 보조 점을 사용하여 3차 Bezier 그리기\"\n\n#: ../../shape.rst:27 1b7d6cc35258460398a82cc2ea5f5017\nmsgid \":meth:`Shape.draw_line`\"\nmsgstr \"\"\n\n#: ../../shape.rst:27 0a76a1b23d26472bb46eaef1b0b11d37\nmsgid \"draw a line\"\nmsgstr \"선 그리기\"\n\n#: ../../shape.rst:28 eea95a7b69df4cc6a775a0d4015d87f5\nmsgid \":meth:`Shape.draw_oval`\"\nmsgstr \"\"\n\n#: ../../shape.rst:28 34529e37e99440538218de68e175f373\nmsgid \"draw an ellipse\"\nmsgstr \"타원 그리기\"\n\n#: ../../shape.rst:29 8817f8a373594a85a5b96f2658e31d98\nmsgid \":meth:`Shape.draw_polyline`\"\nmsgstr \"\"\n\n#: ../../shape.rst:29 3b98bc2fd12c456c8a2410d43daa8912\nmsgid \"connect a sequence of points\"\nmsgstr \"점 시퀀스 연결\"\n\n#: ../../shape.rst:30 4022cf63cc3a496696d3f62c0a2805ab\nmsgid \":meth:`Shape.draw_quad`\"\nmsgstr \"\"\n\n#: ../../shape.rst:30 bde0f7baa3e145cda4e9d029099dda80\nmsgid \"draw a quadrilateral\"\nmsgstr \"사각형 그리기\"\n\n#: ../../shape.rst:31 c4addcda29c140a6b1975890737ead18\nmsgid \":meth:`Shape.draw_rect`\"\nmsgstr \"\"\n\n#: ../../shape.rst:31 2b173978a5c64357ac1aabcc6e976c73\nmsgid \"draw a rectangle\"\nmsgstr \"직사각형 그리기\"\n\n#: ../../shape.rst:32 7f7f34efc2e944109b6c07df81c75430\nmsgid \":meth:`Shape.draw_sector`\"\nmsgstr \"\"\n\n#: ../../shape.rst:32 d5d4937a74fb42b7b20852638b500044\nmsgid \"draw a circular sector or piece of pie\"\nmsgstr \"원형 섹터 또는 파이 조각 그리기\"\n\n#: ../../shape.rst:33 880b0c8a153e48fdaa1029e9be76e520\nmsgid \":meth:`Shape.draw_squiggle`\"\nmsgstr \"\"\n\n#: ../../shape.rst:33 da68180d030a4b1fb309de94d47743b1\nmsgid \"draw a squiggly line\"\nmsgstr \"구불구불한 선 그리기\"\n\n#: ../../shape.rst:34 9fe45650af3d4e0ca97f2b9d25d87789\nmsgid \":meth:`Shape.draw_zigzag`\"\nmsgstr \"\"\n\n#: ../../shape.rst:34 63c2fdb3045d4b81ae22677572e74fbe\nmsgid \"draw a zigzag line\"\nmsgstr \"지그재그 선 그리기\"\n\n#: ../../shape.rst:35 c22ba5f6783649118106601684861498\nmsgid \":meth:`Shape.finish`\"\nmsgstr \"\"\n\n#: ../../shape.rst:35 7c247cc071c04f4383953864f5d543ee\nmsgid \"finish a set of draw commands\"\nmsgstr \"그리기 명령 세트 완료\"\n\n#: ../../shape.rst:36 0ba068100e264e0b9e9ec1f368662d1d\nmsgid \":meth:`Shape.insert_text`\"\nmsgstr \"\"\n\n#: ../../shape.rst:36 5dd5770c7a054a66ab3b70a9d530c6f3\nmsgid \"insert text lines\"\nmsgstr \"텍스트 줄 삽입\"\n\n#: ../../shape.rst:37 fa4216d497f9485cb9c79fc192a851bf\nmsgid \":meth:`Shape.insert_textbox`\"\nmsgstr \"\"\n\n#: ../../shape.rst:37 47ec8b14ef6c4a6d97b355006a0b0b62\nmsgid \"fit text into a rectangle\"\nmsgstr \"사각형에 텍스트 맞추기\"\n\n#: ../../shape.rst:38 f1252e5521e147f5bb1c776091ef3328\nmsgid \":attr:`Shape.doc`\"\nmsgstr \"\"\n\n#: ../../shape.rst:38 7f05739c6d0d459aa0631c532353654e\nmsgid \"stores the page's document\"\nmsgstr \"페이지의 문서 저장\"\n\n#: ../../shape.rst:39 61f46d3f420545e684f380815c9730f3\nmsgid \":attr:`Shape.draw_cont`\"\nmsgstr \"\"\n\n#: ../../shape.rst:39 8a19e4b60bd145ceaa799130f96ab50f\nmsgid \"draw commands since last :meth:`Shape.finish`\"\nmsgstr \"마지막 :meth:`Shape.finish` 이후의 그리기 명령\"\n\n#: ../../shape.rst:40 dbc1fe5e22804f4291fdc27abafe492f\nmsgid \":attr:`Shape.height`\"\nmsgstr \"\"\n\n#: ../../shape.rst:40 a1b344bfa62b474dbecc168b7566abfd\nmsgid \"stores the page's height\"\nmsgstr \"페이지의 높이 저장\"\n\n#: ../../shape.rst:41 98c50cf9d34b4f1fac07407191336a46\nmsgid \":attr:`Shape.lastPoint`\"\nmsgstr \"\"\n\n#: ../../shape.rst:41 d744e08ab64c4be89b54b91da06292ad\nmsgid \"stores the current point\"\nmsgstr \"현재 점 저장\"\n\n#: ../../shape.rst:42 3c7b42195cfb495cba0b78bee8af7989\nmsgid \":attr:`Shape.page`\"\nmsgstr \"\"\n\n#: ../../shape.rst:42 94b8094277504a3e865c3fc7a2fbadcf\nmsgid \"stores the owning page\"\nmsgstr \"소유 페이지 저장\"\n\n#: ../../shape.rst:43 74e41af07b7e49dfb9e8897106da6072\nmsgid \":attr:`Shape.rect`\"\nmsgstr \"\"\n\n#: ../../shape.rst:43 2fd72b972ba64904b71bf6a28bf4aa69\nmsgid \"rectangle surrounding drawings\"\nmsgstr \"그림을 둘러싸는 사각형\"\n\n#: ../../shape.rst:44 d662c10c7b284e1a9e8fb0cfacc0af7e\nmsgid \":attr:`Shape.text_cont`\"\nmsgstr \"\"\n\n#: ../../shape.rst:44 260872b329274794a91fbe27de9d0fd7\nmsgid \"accumulated text insertions\"\nmsgstr \"누적된 텍스트 삽입\"\n\n#: ../../shape.rst:45 260f168374084a0389735532a415f968\nmsgid \":attr:`Shape.totalcont`\"\nmsgstr \"\"\n\n#: ../../shape.rst:45 cca60781247448a6bef1b019d5b03005\nmsgid \"accumulated string to be stored in :data:`contents`\"\nmsgstr \":data:`contents` 에 저장될 누적 문자열\"\n\n#: ../../shape.rst:46 bf5489e997644d1b86ef1a304a20a630\nmsgid \":attr:`Shape.width`\"\nmsgstr \"\"\n\n#: ../../shape.rst:46 320f315bc7e34fb9a224c8104c0490ba\nmsgid \"stores the page's width\"\nmsgstr \"페이지의 너비 저장\"\n\n#: ../../shape.rst:49 bb77ff1beb1643f1a32fbeb881764556\nmsgid \"**Class API**\"\nmsgstr \"**Class API**\"\n\n#: ../../shape.rst:55 f849eb8fe4ea4d84ae176a3bfaddbc5d\nmsgid \"\"\n\"Create a new drawing. During importing PyMuPDF, the *pymupdf.Page* object\"\n\" is being given the convenience method *new_shape()* to construct a \"\n\"*Shape* object. During instantiation, a check will be made whether we do \"\n\"have a PDF page. An exception is otherwise raised.\"\nmsgstr \"새로운 그림을 생성합니다. |PyMuPDF| 를 가져오는 동안 *pymupdf.Page* 객체에 *Shape* 객체를 구성하기 위한 편의 메서드 *new_shape()* 가 제공됩니다. 인스턴스화 중에 PDF 페이지가 있는지 확인합니다. 그렇지 않으면 예외가 발생합니다.\"\n\n#: ../../shape.rst 1c33018ebf664e5c82016942d1b106b9\n#: 1ffb902ffb054dea81b4421598d73d3b 2c7222c93878455593e199cee35f9bc0\n#: 526e0601602e4ad294c77828899ee151 652ecb786383456887f3e684eb50a16f\n#: 8351d111f6ba44c5a48d07b45ecd69ec 8512993c092848e68b405672b0329a5f\n#: 97750b106384485e9da4b3a178fc8b8a bdcf123cefb04a72ac000f1e6d213cab\n#: d33f1cb5159441b288aacd2ccae007dd d522a8dc82fa46aaa1bf98571addfab6\n#: ec2e6f2b47e543f780ac5d88287a15e3 f4f238ef2bbb4c60a0db78dc6ba48ae3\n#: fc6fd8d86630442eac29f0ee69909dd3\nmsgid \"Parameters\"\nmsgstr \"Parameters\"\n\n#: ../../shape.rst:57 7af1e6f9a6c54700a96a634680458cf7\nmsgid \"an existing page of a PDF document.\"\nmsgstr \"PDF 문서의 기존 페이지.\"\n\n#: ../../shape.rst:62 76f377d8f0084511ba9e8ab03be15272\nmsgid \"Draw a line from :data:`point_like` objects *p1* to *p2*.\"\nmsgstr \":data:`point_like` 객체 *p1* 에서 *p2* 까지 선을 그립니다.\"\n\n#: ../../shape.rst:64 ../../shape.rst:78 ../../shape.rst:114\n#: 0bd9ca4fa2034c02bba75a1ed84436e8 67a3775d53744800bce979bd9509dae4\n#: 6fdeeec1ae7344738df476d7c0995efd\nmsgid \"starting point\"\nmsgstr \"시작점\"\n\n#: ../../shape.rst:66 ../../shape.rst:80 ../../shape.rst:116\n#: 233bc3b5db494f95bd617855177b0ba3 b9a33dfd5ad0434bb5d1681c4ef5477f\n#: d7a11d5e2d0843bf98b67ccb4c5a1b5c\nmsgid \"end point\"\nmsgstr \"끝점\"\n\n#: ../../shape.rst 00c99cce86684724a7484f034aead4b9\n#: 11b2ce9eb7ac446288dfe432b6af2d66 37b1db5fc557483698f96296fca977a1\n#: 398f16080c7c485daf19f594085b75e3 4fb89ac12ab341e98fd2fbfde502762f\n#: 79c3be157132461c91fbd43f577c6960 7f449ff12a28486c9377d3eae5881abe\n#: 86a6ff3345b34b99a0b2846ce9b63f97 87752e32bcb84c439a39262387ed43ad\n#: 8ce97810f50346f1963cb9045d0e3bc9 9a9e08e465d642609b4034f0ac585738\n#: e06a173ede194c2499189e3f4ea96d22 f8c5c0c193bf4857a6d61a7fe76a58a0\nmsgid \"Return type\"\nmsgstr \"Return type\"\n\n#: ../../shape.rst:68 ../../shape.rst:84 ../../shape.rst:120\n#: ../../shape.rst:129 ../../shape.rst:138 ../../shape.rst:157\n#: ../../shape.rst:173 ../../shape.rst:185 ../../shape.rst:207\n#: ../../shape.rst:224 ../../shape.rst:233 ../../shape.rst:448\n#: 02178d1d64304122974cdd7d2eda4e9a 04e3fd71585f46408e34e1b5d2918e9d\n#: 1b90b951d85a446a9b18d2751aa79908 258641b6956c4c2ebb65129fbc72ae92\n#: 2c6a3892b51541d9b2bc4f6aa0613353 318dc522d9764a2e9e4ad48a39be4ebb\n#: 60c74e5979e14e0e8d70ebeb78df14b9 6b818606a66c4dc494a2fe410d34be22\n#: 6f503a8ab6474890be0934600cf2de3b 881f284fe0a54cc180a7ff765822eb7e\n#: 8b84d3286ddb4519bb3afc99075e83fb f570f468b63940e4b0b9f5890f13db63\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../shape.rst 19bca25aa417451a9d8eb8425f4d7fe5\n#: 2d7984c3e8b24f9cacf4f90e2f10a7e0 42bcff3c5d7c4b3ea0f0cff8b94a1936\n#: 5725a8009d724bfda07948d7fdd6a975 5ab553dbd9a245ef85863361d3458c06\n#: 5baa94cd077f42439269059c4560779d a0d4f65446c742a5b9f88f747fecf574\n#: a8b9ec9227c447c7b5b7e475f0ad137b b93d921a09e2475eb2dfecc00159859c\n#: c9221ebfa6724c35be3fe1b3043dcc84 edda77c9978d4bdc8e49a11220f628de\n#: fda0a5dbf3e44f70993141cd223cda9f ffd43af87088494c8ab238422d4affeb\nmsgid \"Returns\"\nmsgstr \"Returns\"\n\n#: ../../shape.rst:69 ../../shape.rst:85 ../../shape.rst:121\n#: 03c2703f4c2c4c488c6e1dd5a8bde13f 54fc79ebcc5547368af108398f088aa1\n#: d5a893ea1f9f4e6cb959502504cda257\nmsgid \"the end point, *p2*.\"\nmsgstr \"끝점 *p2*.\"\n\n#: ../../shape.rst:76 eed928e2a53b4d0db6454fc9a3031e88\nmsgid \"\"\n\"Draw a squiggly (wavy, undulated) line from :data:`point_like` objects \"\n\"*p1* to *p2*. An integer number of full wave periods will always be \"\n\"drawn, one period having a length of *4 * breadth*. The breadth parameter\"\n\" will be adjusted as necessary to meet this condition. The drawn line \"\n\"will always turn \\\"left\\\" when leaving *p1* and always join *p2* from the\"\n\" \\\"right\\\".\"\nmsgstr \":data:`point_like` 객체 *p1* 에서 *p2* 까지 구불구불한(물결치는, 파형의) 선을 그립니다. 항상 정수 개의 전체 파형 주기가 그려지며, 한 주기의 길이는 *4 * breadth* 입니다. 이 조건을 충족하기 위해 breadth 매개변수가 필요에 따라 조정됩니다. 그려진 선은 *p1* 을 떠날 때 항상 \\\"왼쪽\\\"으로 돌고 항상 \\\"오른쪽\\\"에서 *p2* 에 합류합니다.\"\n\n#: ../../shape.rst:82 cbee403daaee4a56b9b2f131ff95afb9\nmsgid \"\"\n\"the amplitude of each wave. The condition *2 * breadth < abs(p2 - p1)* \"\n\"must be true to fit in at least one wave. See the following picture, \"\n\"which shows two points connected by one full period.\"\nmsgstr \"각 파형의 진폭. 최소한 하나의 파형을 맞추려면 조건 *2 * breadth < abs(p2 - p1)* 이 참이어야 합니다. 하나의 전체 주기로 연결된 두 점을 보여주는 다음 그림을 참조하세요.\"\n\n#: ../../shape.rst:89 c61f3a8ac2e84d7e88c065f6a80328ac\nmsgid \"\"\n\"Here is an example of three connected lines, forming a closed, filled \"\n\"triangle. Little arrows indicate the stroking direction.\"\nmsgstr \"다음은 닫힌 채워진 삼각형을 형성하는 세 개의 연결된 선의 예입니다. 작은 화살표는 스트로크 방향을 나타냅니다.\"\n\n#: ../../shape.rst:105 3b09c6c0299043ad9e407b82096dc07f\nmsgid \"\"\n\"Waves drawn are **not** trigonometric (sine / cosine). If you need that, \"\n\"have a look at `draw.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/draw-sines/draw.py>`_.\"\nmsgstr \"그려진 파형은 **삼각함수** (사인/코사인)가 **아닙니다**. 그것이 필요하다면 `draw.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/draw-sines/draw.py>`_ 를 참조하세요.\"\n\n#: ../../shape.rst:112 e6d38796d27441ac9eb554ae3567f070\nmsgid \"\"\n\"Draw a zigzag line from :data:`point_like` objects *p1* to *p2*. \"\n\"Otherwise works exactly like :meth:`Shape.draw_squiggle`.\"\nmsgstr \":data:`point_like` 객체 *p1* 에서 *p2* 까지 지그재그 선을 그립니다. 그 외에는 :meth:`Shape.draw_squiggle` 과 정확히 동일하게 작동합니다.\"\n\n#: ../../shape.rst:118 2686f76e3e56495ca08bdd2711d1c28e\nmsgid \"\"\n\"the amplitude of the movement. The condition *2 * breadth < abs(p2 - p1)*\"\n\" must be true to fit in at least one period.\"\nmsgstr \"이동의 진폭. 최소한 하나의 주기를 맞추려면 조건 *2 * breadth < abs(p2 - p1)* 이 참이어야 합니다.\"\n\n#: ../../shape.rst:125 bfb5a00ac07547bf822e4b2d95c0f3d7\nmsgid \"\"\n\"Draw several connected lines between points contained in the sequence \"\n\"*points*. This can be used for creating arbitrary polygons by setting the\"\n\" last item equal to the first one.\"\nmsgstr \"시퀀스 *points* 에 포함된 점들 사이에 여러 개의 연결된 선을 그립니다. 마지막 항목을 첫 번째 항목과 같게 설정하여 임의의 다각형을 만드는 데 사용할 수 있습니다.\"\n\n#: ../../shape.rst:127 9afa3278382745228b82849acc3d1db1\nmsgid \"\"\n\"a sequence of :data:`point_like` objects. Its length must at least be 2 \"\n\"(in which case it is equivalent to *draw_line()*).\"\nmsgstr \":data:`point_like` 객체의 시퀀스. 길이는 최소 2여야 합니다(이 경우 *draw_line()* 와 동일함).\"\n\n#: ../../shape.rst:130 b0f8276e3be04c6996c165c83ed3fdbd\nmsgid \"*points[-1]* -- the last point in the argument sequence.\"\nmsgstr \"*points[-1]* -- 인수 시퀀스의 마지막 점.\"\n\n#: ../../shape.rst:134 bf9fc4f7ee704353953bbb497b85a344\nmsgid \"\"\n\"Draw a standard cubic Bézier curve from *p1* to *p4*, using *p2* and *p3*\"\n\" as control points.\"\nmsgstr \"*p2* 와 *p3* 를 제어점으로 사용하여 *p1* 에서 *p4* 까지 표준 3차 Bézier 곡선을 그립니다.\"\n\n#: ../../shape.rst:136 65ae6d8fa1ca4696b5ceec6e6a33a484\nmsgid \"All arguments are :data:`point_like` objects.\"\nmsgstr \"모든 인수는 :data:`point_like` 객체입니다.\"\n\n#: ../../shape.rst:139 c3bc7d17a1564a259bbccff931fbceb4\nmsgid \"the end point, *p4*.\"\nmsgstr \"끝점 *p4*.\"\n\n#: ../../shape.rst:141 540f633870214c57b214a2d3dc6fad47\nmsgid \"\"\n\"The points do not need to be different -- experiment a bit with some of \"\n\"them being equal!\"\nmsgstr \"점들이 달라야 할 필요는 없습니다 -- 일부가 같도록 실험해보세요!\"\n\n#: ../../shape.rst:143 cc32f6b9b719471e990541995cb91d8a\nmsgid \"Example:\"\nmsgstr \"Example:\"\n\n#: ../../shape.rst:149 3cd13feab216456fb40eabb0f87476f2\nmsgid \"\"\n\"Draw an \\\"ellipse\\\" inside the given tetragon (quadrilateral). If it is a\"\n\" square, a regular circle is drawn, a general rectangle will result in an\"\n\" ellipse. If a quadrilateral is used instead, a plethora of shapes can be\"\n\" the result.\"\nmsgstr \"주어진 사각형(사변형) 내에 \\\"타원\\\"을 그립니다. 정사각형이면 일반 원이 그려지고, 일반 직사각형이면 타원이 됩니다. 사변형을 사용하면 다양한 모양이 결과가 될 수 있습니다.\"\n\n#: ../../shape.rst:151 3beef81862054f6c9dcfb27abe73062b\nmsgid \"\"\n\"The drawing starts and ends at the middle point of the line `bottom-left \"\n\"-> top-left` corners in an anti-clockwise movement.\"\nmsgstr \"그리기는 반시계 방향으로 `왼쪽 아래 -> 왼쪽 위` 모서리 선의 중간점에서 시작하고 끝납니다.\"\n\n#: ../../shape.rst:153 dbc5cddf46e74369a4ec90c4aba4a510\nmsgid \"\"\n\":data:`rect_like` or :data:`quad_like`.  *Changed in version 1.14.5:*  \"\n\"Quads are now also supported.\"\nmsgstr \"\"\n\n#: ../../shape.rst:153 0704abfebefe4fe78ed8116b1a8491c3\nmsgid \":data:`rect_like` or :data:`quad_like`.\"\nmsgstr \":data:`rect_like` 또는 :data:`quad_like`.\"\n\n#: ../../shape.rst:155 b5056fbc16ad42e4b786c5a89beddb09\nmsgid \"*Changed in version 1.14.5:*  Quads are now also supported.\"\nmsgstr \"*버전 1.14.5에서 변경됨:* 이제 Quads도 지원됩니다.\"\n\n#: ../../shape.rst:158 913c4e5f92e8407f8da84ba1fbe6cb29\nmsgid \"\"\n\"the middle point of line `rect.bl -> rect.tl`, or resp. `quad.ll -> \"\n\"quad.ul`. Look at just a few examples here, or at the *quad-show?.py* \"\n\"scripts in the PyMuPDF-Utilities repository.\"\nmsgstr \"선 `rect.bl -> rect.tl` 또는 각각 `quad.ll -> quad.ul` 의 중간점. 여기서 몇 가지 예제를 보거나 PyMuPDF-Utilities 저장소의 *quad-show?.py* 스크립트를 참조하세요.\"\n\n#: ../../shape.rst:165 e10d02b00d77481699e5ed1c3824246d\nmsgid \"\"\n\"Draw a circle given its center and radius. The drawing starts and ends at\"\n\" point `center - (radius, 0)` in an **anti-clockwise** movement. This \"\n\"point is the middle of the enclosing square's left side.\"\nmsgstr \"중심과 반지름이 주어진 원을 그립니다. 그리기는 **반시계 방향** 으로 점 `center - (radius, 0)` 에서 시작하고 끝납니다. 이 점은 둘러싸는 정사각형의 왼쪽 변의 중간입니다.\"\n\n#: ../../shape.rst:167 ab7929d6c83247179ab99962d0e45182\nmsgid \"\"\n\"This is a shortcut for `draw_sector(center, start, 360, \"\n\"fullSector=False)`. To draw the same circle in a **clockwise** movement, \"\n\"use `-360` as degrees.\"\nmsgstr \"이것은 `draw_sector(center, start, 360, fullSector=False)` 의 바로가기입니다. **시계 방향** 으로 동일한 원을 그리려면 각도로 `-360` 을 사용하세요.\"\n\n#: ../../shape.rst:169 ../../shape.rst:199 6f2705ad71a74c2b917e39246bc2698d\n#: bd872730dfb6401aa65d5bf0dcfa4a1d\nmsgid \"the center of the circle.\"\nmsgstr \"원의 중심.\"\n\n#: ../../shape.rst:171 5b6ab9084a254ee998a1d680ac1e0240\nmsgid \"the radius of the circle. Must be positive.\"\nmsgstr \"원의 반지름. 양수여야 합니다.\"\n\n#: ../../shape.rst:174 7c4ce467661b468b8439dadac7926f6a\nmsgid \"\"\n\"`Point(center.x - radius, center.y)`.  .. image:: images/img-drawcircle.*\"\n\"    :scale: 60\"\nmsgstr \"\"\n\n#: ../../shape.rst:174 2debffa3cd414df1912ce3b384b1301c\nmsgid \"`Point(center.x - radius, center.y)`.\"\nmsgstr \"`Point(center.x - radius, center.y)`.\"\n\n#: ../../shape.rst:181 ee66694536bb4ca4a6a74521eab10648\nmsgid \"\"\n\"A special case of *draw_bezier()*: Draw a cubic Bezier curve from *p1* to\"\n\" *p3*. On each of the two lines `p1 -> p2` and `p3 -> p2` one control \"\n\"point is generated. Both control points will therefore be on the same \"\n\"side of the line `p1 -> p3`. This guaranties that the curve's curvature \"\n\"does not change its sign. If the lines to p2 intersect with an angle of \"\n\"90 degrees, then the resulting curve is a quarter ellipse (resp. quarter \"\n\"circle, if of same length).\"\nmsgstr \"*draw_bezier()* 의 특수한 경우: *p1* 에서 *p3* 까지 3차 Bezier 곡선을 그립니다. 두 선 `p1 -> p2` 와 `p3 -> p2` 각각에 하나의 제어점이 생성됩니다. 따라서 두 제어점은 모두 선 `p1 -> p3` 의 같은 쪽에 있습니다. 이것은 곡선의 곡률이 부호를 변경하지 않도록 보장합니다. p2로의 선이 90도 각도로 교차하면 결과 곡선은 1/4 타원(또는 같은 길이인 경우 1/4 원)이 됩니다.\"\n\n#: ../../shape.rst:183 b9aa05d9515a4765ba0ed43ffaf7fdc8\nmsgid \"All arguments are :data:`point_like`.\"\nmsgstr \"모든 인수는 :data:`point_like` 입니다.\"\n\n#: ../../shape.rst:186 17f64971541f45cd813e80d02b9a38f9\nmsgid \"\"\n\"the end point, *p3*. The following is a filled quarter ellipse segment. \"\n\"The yellow area is oriented **clockwise:**  .. image:: images/img-\"\n\"drawCurve.png    :align: center\"\nmsgstr \"\"\n\n#: ../../shape.rst:186 13f26770deb8487da263851084fcf4e9\nmsgid \"\"\n\"the end point, *p3*. The following is a filled quarter ellipse segment. \"\n\"The yellow area is oriented **clockwise:**\"\nmsgstr \"끝점 *p3*. 다음은 채워진 1/4 타원 세그먼트입니다. 노란색 영역은 **시계 방향** 으로 향합니다:\"\n\n#: ../../shape.rst:197 e52f58c73f024ab492a6b26bf05ef6d1\nmsgid \"\"\n\"Draw a circular sector, optionally connecting the arc to the circle's \"\n\"center (like a piece of pie).\"\nmsgstr \"원형 섹터를 그립니다. 선택적으로 호를 원의 중심에 연결합니다(파이 조각처럼).\"\n\n#: ../../shape.rst:201 4a4f8fd9d4ae4e9f9d879279d68a23eb\nmsgid \"\"\n\"one of the two end points of the pie's arc segment. The other one is \"\n\"calculated from the *angle*.\"\nmsgstr \"파이의 호 세그먼트의 두 끝점 중 하나. 다른 하나는 *angle* 에서 계산됩니다.\"\n\n#: ../../shape.rst:203 cde4d3b5b77e4714a1e8229d3a7d5901\nmsgid \"\"\n\"the angle of the sector in degrees. Used to calculate the other end point\"\n\" of the arc. Depending on its sign, the arc is drawn anti-clockwise \"\n\"(positive) or clockwise.\"\nmsgstr \"섹터의 각도(도 단위). 호의 다른 끝점을 계산하는 데 사용됩니다. 부호에 따라 호는 반시계 방향(양수) 또는 시계 방향으로 그려집니다.\"\n\n#: ../../shape.rst:205 240361925857465eae04d2b1fb29fe7f\nmsgid \"\"\n\"whether to draw connecting lines from the ends of the arc to the circle \"\n\"center. If a fill color is specified, the full \\\"pie\\\" is colored, \"\n\"otherwise just the sector.\"\nmsgstr \"호의 끝에서 원의 중심까지 연결선을 그릴지 여부. 채우기 색상이 지정되면 전체 \\\"파이\\\"가 색칠되고, 그렇지 않으면 섹터만 색칠됩니다.\"\n\n#: ../../shape.rst:208 be7cd89a7589439eb4d78244412304ad\nmsgid \"\"\n\"the other end point of the arc. Can be used as starting point for a \"\n\"following invocation to create logically connected pies charts. Examples:\"\n\"  .. image:: images/img-drawSector1.*  .. image:: images/img-\"\n\"drawSector2.*\"\nmsgstr \"\"\n\n#: ../../shape.rst:208 0043e2c7a86744b4a2bc4d7f0bce8a4b\nmsgid \"\"\n\"the other end point of the arc. Can be used as starting point for a \"\n\"following invocation to create logically connected pies charts. Examples:\"\nmsgstr \"호의 다른 끝점. 논리적으로 연결된 파이 차트를 만들기 위한 후속 호출의 시작점으로 사용할 수 있습니다. 예:\"\n\n#: ../../shape.rst:217 5fb3a670ab80402c9dcadb97fd8823f0\nmsgid \"Changed in v1.22.0: Added parameter *radius*.\"\nmsgstr \"v1.22.0에서 변경됨: 매개변수 *radius* 추가.\"\n\n#: ../../shape.rst:219 d0e527f29d634bf6a4487b2594b804af\nmsgid \"\"\n\"Draw a rectangle. The drawing starts and ends at the top-left corner in \"\n\"an anti-clockwise movement.\"\nmsgstr \"직사각형을 그립니다. 그리기는 반시계 방향으로 왼쪽 위 모서리에서 시작하고 끝납니다.\"\n\n#: ../../shape.rst:221 9f2b7555b1844871bbf67f60773f3566\nmsgid \"where to put the rectangle on the page.\"\nmsgstr \"페이지에서 직사각형을 배치할 위치.\"\n\n#: ../../shape.rst:222 67f101fa3c674ce7b113450e58af1ac1\n#, python-format\nmsgid \"\"\n\"draw rounded rectangle corners. If not `None`, specifies the radius of \"\n\"the curvature as a percentage of a rectangle side length. This must one \"\n\"or (a tuple of) two floats `0 < radius <= 0.5`, where 0.5 corresponds to \"\n\"50% of the respective side. If a float, the radius of the curvature is \"\n\"computed as `radius * min(width, height)`, drawing the corner's perimeter\"\n\" as a quarter circle. If a tuple `(rx, ry)` is given, then the curvature \"\n\"is asymmetric with respect to the horizontal and vertical directions. A \"\n\"value of `radius=(0.5, 0.5)` draws an ellipse.\"\nmsgstr \"둥근 직사각형 모서리를 그립니다. `None` 이 아니면 직사각형 변 길이의 백분율로 곡률의 반지름을 지정합니다. 이것은 하나 또는 (튜플의) 두 개의 float `0 < radius <= 0.5` 여야 하며, 여기서 0.5는 해당 변의 50%에 해당합니다. float인 경우 곡률의 반지름은 `radius * min(width, height)` 로 계산되며, 모서리의 둘레를 1/4 원으로 그립니다. 튜플 `(rx, ry)` 가 주어지면 곡률은 수평 및 수직 방향에 대해 비대칭입니다. `radius=(0.5, 0.5)` 값은 타원을 그립니다.\"\n\n#: ../../shape.rst:225 6c3047af9341428fb1852d642a8d8fb3\nmsgid \"top-left corner of the rectangle.\"\nmsgstr \"직사각형의 왼쪽 위 모서리.\"\n\n#: ../../shape.rst:229 654bd0a3b7ce4bf78f0d2d85b1d37414\nmsgid \"\"\n\"Draw a quadrilateral. The drawing starts and ends at the top-left corner \"\n\"(:attr:`Quad.ul`) in an anti-clockwise movement. It is a shortcut of \"\n\":meth:`Shape.draw_polyline` with the argument `(ul, ll, lr, ur, ul)`.\"\nmsgstr \"사변형을 그립니다. 그리기는 반시계 방향으로 왼쪽 위 모서리(:attr:`Quad.ul`)에서 시작하고 끝납니다. 인수 `(ul, ll, lr, ur, ul)` 을 사용하는 :meth:`Shape.draw_polyline` 의 바로가기입니다.\"\n\n#: ../../shape.rst:231 046262682daf47c8be64f00f93f9acba\nmsgid \"where to put the tetragon on the page.\"\nmsgstr \"페이지에서 사각형을 배치할 위치.\"\n\n#: ../../shape.rst:234 3fe224acf6924b1085f1052564c9423f\nmsgid \":attr:`Quad.ul`.\"\nmsgstr \":attr:`Quad.ul`.\"\n\n#: ../../shape.rst:253 0de6d95816a442d3b9408559071e8954\nmsgid \"\"\n\"Finish a set of *draw*()* methods by applying :ref:`CommonParms` to all \"\n\"of them.\"\nmsgstr \":ref:`CommonParms` 를 모두에 적용하여 *draw*()* 메서드 세트를 완료합니다.\"\n\n#: ../../shape.rst:255 56332b3691544dfbaf0fd9e731231bc5\nmsgid \"\"\n\"It has **no effect on** :meth:`Shape.insert_text` and \"\n\":meth:`Shape.insert_textbox`.\"\nmsgstr \":meth:`Shape.insert_text` 및 :meth:`Shape.insert_textbox` 에는 **영향을 주지 않습니다**.\"\n\n#: ../../shape.rst:257 549c8c7eeb8344aaa7576d3e8a534e9c\nmsgid \"\"\n\"The method also supports **morphing the compound drawing** using \"\n\":ref:`Point` *fixpoint* and :ref:`matrix` *matrix*.\"\nmsgstr \"이 메서드는 :ref:`Point` *fixpoint* 및 :ref:`matrix` *matrix* 를 사용하여 **복합 그림 변형** 도 지원합니다.\"\n\n#: ../../shape.rst:259 dba0c80e395c4f9992d5e84ad7225ffd\nmsgid \"\"\n\"morph the text or the compound drawing around some arbitrary :ref:`Point`\"\n\" *fixpoint* by applying :ref:`Matrix` *matrix* to it. This implies that \"\n\"*fixpoint* is a **fixed point** of this operation: it will not change its\"\n\" position. Default is no morphing (``None``). The matrix can contain any \"\n\"values in its first 4 components, *matrix.e == matrix.f == 0* must be \"\n\"true, however. This means that any combination of scaling, shearing, \"\n\"rotating, flipping, etc. is possible, but translations are not.\"\nmsgstr \"임의의 :ref:`Point` *fixpoint* 주변의 텍스트 또는 복합 그림을 :ref:`Matrix` *matrix* 를 적용하여 변형합니다. 이것은 *fixpoint* 가 이 작업의 **고정점** 임을 의미합니다: 위치가 변경되지 않습니다. 기본값은 변형 없음(``None``)입니다. 행렬은 처음 4개 구성 요소에 임의의 값을 포함할 수 있지만, *matrix.e == matrix.f == 0* 이 참이어야 합니다. 이것은 확대/축소, 기울이기, 회전, 뒤집기 등의 조합이 가능하지만 이동은 불가능함을 의미합니다.\"\n\n#: ../../shape.rst:261 5dafa22688dd4869b353c3ba9d3b07f7\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for stroke colors. Value < 0 or > 1 \"\n\"will be ignored. Default is 1 (intransparent).\"\nmsgstr \"*(v1.18.1의 새로운 기능)* 스트로크 색상의 투명도를 설정합니다. 값 < 0 또는 > 1은 무시됩니다. 기본값은 1(불투명)입니다.\"\n\n#: ../../shape.rst:262 ccec6b24043c40a28e9532eddd90bdce\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for fill colors. Default is 1 \"\n\"(intransparent).\"\nmsgstr \"*(v1.18.1의 새로운 기능)* 채우기 색상의 투명도를 설정합니다. 기본값은 1(불투명)입니다.\"\n\n#: ../../shape.rst:264 df15c1363a6a46538ab6875019646cbd\nmsgid \"\"\n\"request the **\\\"even-odd rule\\\"** for filling operations. Default is \"\n\"``False``, so that the **\\\"nonzero winding number rule\\\"** is used. These\"\n\" rules are alternative methods to apply the fill color where areas \"\n\"overlap. Only with fairly complex shapes a different behavior is to be \"\n\"expected with these rules. For an in-depth explanation, see \"\n\":ref:`AdobeManual`, pp. 137 ff. Here is an example to demonstrate the \"\n\"difference.\"\nmsgstr \"채우기 작업에 **\\\"even-odd rule\\\"** 을 요청합니다. 기본값은 ``False`` 이므로 **\\\"nonzero winding number rule\\\"** 이 사용됩니다. 이러한 규칙은 영역이 겹치는 곳에 채우기 색상을 적용하는 대체 방법입니다. 상당히 복잡한 모양에서만 이러한 규칙으로 다른 동작이 예상됩니다. 자세한 설명은 :ref:`AdobeManual` 137페이지 이하를 참조하세요. 차이를 보여주는 예제는 다음과 같습니다.\"\n\n#: ../../shape.rst:266 c674e567b1e5433eaf84acd80acc23dc\nmsgid \"\"\n\"*(new in v1.18.4)* the :data:`xref` number of an :data:`OCG` or \"\n\":data:`OCMD` to make this drawing conditionally displayable.\"\nmsgstr \"*(v1.18.4의 새로운 기능)* 이 그림을 조건부로 표시 가능하게 하는 :data:`OCG` 또는 :data:`OCMD` 의 :data:`xref` 번호.\"\n\n#: ../../shape.rst:270 63c92f36394847c489986e7f2afbb97a\nmsgid \"For each pixel in a shape, the following will happen:\"\nmsgstr \"모양의 각 픽셀에 대해 다음이 발생합니다:\"\n\n#: ../../shape.rst:272 36c14ed50f0445be999e611bc169aa24\nmsgid \"\"\n\"Rule **\\\"even-odd\\\"** counts, how many areas contain the pixel. If this \"\n\"count is **odd,** the pixel is regarded **inside** the shape, if it is \"\n\"**even**, the pixel is **outside**.\"\nmsgstr \"규칙 **\\\"even-odd\\\"** 는 픽셀을 포함하는 영역의 수를 계산합니다. 이 카운트가 **홀수** 이면 픽셀은 모양 **내부** 로 간주되고, **짝수** 이면 픽셀은 **외부** 로 간주됩니다.\"\n\n#: ../../shape.rst:274 3effcfe2b7fe4980b3622d1cc2555db9\nmsgid \"\"\n\"The default rule **\\\"nonzero winding\\\"** in addition looks at the \"\n\"*\\\"orientation\\\"* of each area containing the pixel: it **adds 1** if an \"\n\"area is drawn anti-clockwise and it **subtracts 1** for clockwise areas. \"\n\"If the result is zero, the pixel is regarded **outside,** pixels with a \"\n\"non-zero count are **inside** the shape.\"\nmsgstr \"기본 규칙 **\\\"nonzero winding\\\"** 은 추가로 픽셀을 포함하는 각 영역의 *\\\"방향\\\"* 을 봅니다: 영역이 반시계 방향으로 그려지면 **1을 더하고** 시계 방향 영역에 대해서는 **1을 뺍니다**. 결과가 0이면 픽셀은 **외부** 로 간주되고, 0이 아닌 카운트를 가진 픽셀은 모양 **내부** 에 있습니다.\"\n\n#: ../../shape.rst:276 b72f9a0a9d6a42fba11e06941aaae289\nmsgid \"\"\n\"Of the four shapes in above image, the top two each show three circles \"\n\"drawn in standard manner (anti-clockwise, look at the arrows). The lower \"\n\"two shapes contain one (the top-left) circle drawn clockwise. As can be \"\n\"seen, area orientation is irrelevant for the right column (even-odd \"\n\"rule).\"\nmsgstr \"위 이미지의 네 모양 중 위쪽 두 개는 각각 표준 방식(반시계 방향, 화살표 참조)으로 그려진 세 개의 원을 보여줍니다. 아래쪽 두 모양은 시계 방향으로 그려진 하나(왼쪽 위)의 원을 포함합니다. 보시다시피 영역 방향은 오른쪽 열(even-odd 규칙)과 무관합니다.\"\n\n#: ../../shape.rst:297 a50a3db9c4f74b3aaed7c91f010f050f\nmsgid \"Insert text lines starting at ``point``.\"\nmsgstr \"``point`` 에서 시작하는 텍스트 줄을 삽입합니다.\"\n\n#: ../../shape.rst:299 d60ae29ad0ca4e709ff2c72d7bf5c264\nmsgid \"\"\n\"the bottom-left position of the first character of *text* in pixels. It \"\n\"is important to understand, how this works in conjunction with the \"\n\"*rotate* parameter. Please have a look at the following picture. The \"\n\"small red dots indicate the positions of *point* in each of the four \"\n\"possible cases.  .. image:: images/img-inserttext.*    :scale: 33\"\nmsgstr \"\"\n\n#: ../../shape.rst:299 1521f8f6fbea43a0be0deb7904e4623c\nmsgid \"\"\n\"the bottom-left position of the first character of *text* in pixels. It \"\n\"is important to understand, how this works in conjunction with the \"\n\"*rotate* parameter. Please have a look at the following picture. The \"\n\"small red dots indicate the positions of *point* in each of the four \"\n\"possible cases.\"\nmsgstr \"픽셀 단위로 *text* 의 첫 번째 문자의 왼쪽 아래 위치. 이것이 *rotate* 매개변수와 함께 어떻게 작동하는지 이해하는 것이 중요합니다. 다음 그림을 참조하세요. 작은 빨간 점은 네 가지 가능한 경우 각각에서 *point* 의 위치를 나타냅니다.\"\n\n#: ../../shape.rst:304 c50197a3ee954fc4b17e16da50350320\nmsgid \"\"\n\"the text to be inserted. May be specified as either a string type or as a\"\n\" sequence type. For sequences, or strings containing line breaks ``\\\\n``,\"\n\" several lines will be inserted. No care will be taken if lines are too \"\n\"wide, but the number of inserted lines will be limited by \\\"vertical\\\" \"\n\"space on the page (in the sense of reading direction as established by \"\n\"the *rotate* parameter). Any rest of *text* is discarded -- the return \"\n\"code however contains the number of inserted lines.\"\nmsgstr \"삽입할 텍스트. 문자열 타입 또는 시퀀스 타입으로 지정할 수 있습니다. 시퀀스 또는 줄바꿈 ``\\\\n`` 을 포함하는 문자열의 경우 여러 줄이 삽입됩니다. 줄이 너무 넓어도 처리하지 않지만, 삽입된 줄 수는 페이지의 \\\"수직\\\" 공간(*rotate* 매개변수에 의해 설정된 읽기 방향의 의미에서)에 의해 제한됩니다. *text* 의 나머지는 버려집니다 -- 그러나 반환 코드는 삽입된 줄 수를 포함합니다.\"\n\n#: ../../shape.rst:306 ../../shape.rst:346 a2bce94fcad44fc08799f6d16a27e19d\n#: f75a16cbc40142c5a8ce2199eb87b25c\nmsgid \"\"\n\"a factor to override the line height calculated from font properties. If \"\n\"not `None`, a line height of `fontsize * lineheight` will be used.\"\nmsgstr \"글꼴 속성에서 계산된 줄 높이를 재정의하는 요소. `None` 이 아니면 `fontsize * lineheight` 의 줄 높이가 사용됩니다.\"\n\n#: ../../shape.rst:307 1ecd328d935546d38c4621a762982871\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for stroke colors (the **border \"\n\"line** of a character). Only  `0 <= value <= 1` will be considered. \"\n\"Default is 1 (intransparent).\"\nmsgstr \"*(v1.18.1의 새로운 기능)* 스트로크 색상(문자의 **테두리 선**)의 투명도를 설정합니다. `0 <= value <= 1` 만 고려됩니다. 기본값은 1(불투명)입니다.\"\n\n#: ../../shape.rst:308 ../../shape.rst:351 168d47f1a50e45efbddb4be1a0a28d1c\n#: 7029b8b04590494a850f9bf97c737317\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for fill colors. Default is 1 \"\n\"(intransparent). Use this value to control transparency of the text \"\n\"color. Stroke opacity **only** affects the border line of characters.\"\nmsgstr \"*(v1.18.1의 새로운 기능)* 채우기 색상의 투명도를 설정합니다. 기본값은 1(불투명)입니다. 이 값을 사용하여 텍스트 색상의 투명도를 제어합니다. 스트로크 불투명도는 **문자의 테두리 선에만** 영향을 줍니다.\"\n\n#: ../../shape.rst:310 bc253669783d43fbbcea827f904f8df7\nmsgid \"\"\n\"determines whether to rotate the text. Acceptable values are multiples of\"\n\" 90 degrees. Default is 0 (no rotation), meaning horizontal text lines \"\n\"oriented from left to right. 180 means text is shown upside down from \"\n\"**right to left**. 90 means anti-clockwise rotation, text running \"\n\"**upwards**. 270 (or -90) means clockwise rotation, text running \"\n\"**downwards**. In any case, *point* specifies the bottom-left coordinates\"\n\" of the first character's rectangle. Multiple lines, if present, always \"\n\"follow the reading direction established by this parameter. So line 2 is \"\n\"located **above** line 1 in case of `rotate = 180`, etc.\"\nmsgstr \"텍스트를 회전할지 여부를 결정합니다. 허용되는 값은 90도의 배수입니다. 기본값은 0(회전 없음)이며, 왼쪽에서 오른쪽으로 향하는 수평 텍스트 줄을 의미합니다. 180은 텍스트가 **오른쪽에서 왼쪽** 으로 거꾸로 표시됨을 의미합니다. 90은 반시계 방향 회전, 텍스트가 **위쪽** 으로 실행됨을 의미합니다. 270(또는 -90)은 시계 방향 회전, 텍스트가 **아래쪽** 으로 실행됨을 의미합니다. 어떤 경우든 *point* 는 첫 번째 문자의 사각형의 왼쪽 아래 좌표를 지정합니다. 여러 줄이 있는 경우 항상 이 매개변수에 의해 설정된 읽기 방향을 따릅니다. 따라서 `rotate = 180` 인 경우 줄 2는 줄 1 **위에** 위치합니다.\"\n\n#: ../../shape.rst:312 ../../shape.rst:355 68906f83108042f0b104b462a3b39709\n#: 9759f8b8a55448eb88645d85395ee4e8\nmsgid \"\"\n\"*(new in v1.18.4)* the :data:`xref` number of an :data:`OCG` or \"\n\":data:`OCMD` to make this text conditionally displayable.\"\nmsgstr \"*(v1.18.4의 새로운 기능)* 이 텍스트를 조건부로 표시 가능하게 하는 :data:`OCG` 또는 :data:`OCMD` 의 :data:`xref` 번호.\"\n\n#: ../../shape.rst:315 ed86c6cd4572455ba92ae3ff42b41fdf\nmsgid \"number of lines inserted.\"\nmsgstr \"삽입된 줄 수.\"\n\n#: ../../shape.rst:317 ../../shape.rst:367 4a40110f016f4c7bb3e919ac462d14e3\n#: 785b22c9fbc5484186666fbe76c0f207\nmsgid \"For a description of the other parameters see :ref:`CommonParms`.\"\nmsgstr \"다른 매개변수에 대한 설명은 :ref:`CommonParms` 를 참조하세요.\"\n\n#: ../../shape.rst:338 32569db0897946de8f8338dcc82e3dd3\nmsgid \"\"\n\"PDF only: Insert text into the specified rectangle. The text will be \"\n\"split into lines and words and then filled into the available space, \"\n\"starting from one of the four rectangle corners, which depends on \"\n\"`rotate`. Line feeds and multiple space will be respected.\"\nmsgstr \"PDF 전용: 지정된 사각형에 텍스트를 삽입합니다. 텍스트는 줄과 단어로 분할된 다음 사용 가능한 공간에 채워지며, `rotate` 에 따라 사각형의 네 모서리 중 하나에서 시작합니다. 줄바꿈과 여러 공백이 존중됩니다.\"\n\n#: ../../shape.rst:340 c50da8ee249d416084e826f0a8a2efd6\nmsgid \"the area to use. It must be finite and not empty.\"\nmsgstr \"사용할 영역. 유한하고 비어 있지 않아야 합니다.\"\n\n#: ../../shape.rst:342 7990001f1d8a482696c3ea94ee3b11c5\nmsgid \"\"\n\"the text to be inserted. Must be specified as a string or a sequence of \"\n\"strings. Line breaks are respected also when occurring in a sequence \"\n\"entry.\"\nmsgstr \"삽입할 텍스트. 문자열 또는 문자열 시퀀스로 지정해야 합니다. 시퀀스 항목에 발생하는 경우에도 줄바꿈이 존중됩니다.\"\n\n#: ../../shape.rst:344 8bfa2ed038884962a70ceb3e0459dc06\nmsgid \"\"\n\"align each text line. Default is 0 (left). Centered, right and justified \"\n\"are the other supported options, see :ref:`TextAlign`. Please note that \"\n\"the effect of parameter value *TEXT_ALIGN_JUSTIFY* is only achievable \"\n\"with \\\"simple\\\" (single-byte) fonts (including the :ref:`Base-14-Fonts`).\"\nmsgstr \"각 텍스트 줄을 정렬합니다. 기본값은 0(왼쪽)입니다. 중앙, 오른쪽 및 양쪽 정렬은 다른 지원 옵션입니다. :ref:`TextAlign` 을 참조하세요. 매개변수 값 *TEXT_ALIGN_JUSTIFY* 의 효과는 \\\"simple\\\"(단일 바이트) 글꼴(:ref:`Base-14-Fonts` 포함)에서만 달성할 수 있습니다.\"\n\n#: ../../shape.rst:348 9adb4b3bbe094da8a624bd552fc13f21\nmsgid \"\"\n\"controls handling of tab characters ``\\\\t`` using the \"\n\"`string.expandtabs()` method **per each line**.\"\nmsgstr \"**각 줄마다** `string.expandtabs()` 메서드를 사용하여 탭 문자 ``\\\\t`` 의 처리를 제어합니다.\"\n\n#: ../../shape.rst:350 67177b4ade6c4da5a4523395d6bd4bf4\nmsgid \"\"\n\"*(new in v1.18.1)* set transparency for stroke colors. Negative values \"\n\"and values > 1 will be ignored. Default is 1 (intransparent).\"\nmsgstr \"*(v1.18.1의 새로운 기능)* 스트로크 색상의 투명도를 설정합니다. 음수 값과 값 > 1은 무시됩니다. 기본값은 1(불투명)입니다.\"\n\n#: ../../shape.rst:353 d5edb13ac13b4ab4ba9d26fa3d3a6d82\nmsgid \"\"\n\"requests text to be rotated in the rectangle. This value must be a \"\n\"multiple of 90 degrees. Default is 0 (no rotation). Effectively, the four\"\n\" values `0`, `90`, `180` and `270` (= `-90`) are processed, each causing \"\n\"the text to start in a different rectangle corner. Bottom-left is `90`, \"\n\"bottom-right is `180`, and `-90 / 270` is top-right. See the example how \"\n\"text is filled in a rectangle. This argument takes precedence over \"\n\"morphing. See the second example, which shows text first rotated left by \"\n\"`90` degrees and then the whole rectangle rotated clockwise around is \"\n\"lower left corner.\"\nmsgstr \"사각형에서 텍스트를 회전하도록 요청합니다. 이 값은 90도의 배수여야 합니다. 기본값은 0(회전 없음)입니다. 효과적으로 네 가지 값 `0`, `90`, `180` 및 `270` (= `-90`)이 처리되며, 각각 텍스트가 다른 사각형 모서리에서 시작하도록 합니다. 왼쪽 아래는 `90`, 오른쪽 아래는 `180`, `-90 / 270` 은 오른쪽 위입니다. 텍스트가 사각형에 채워지는 방법의 예제를 참조하세요. 이 인수는 변형보다 우선합니다. 텍스트가 먼저 `90` 도 왼쪽으로 회전한 다음 전체 사각형이 왼쪽 아래 모서리를 중심으로 시계 방향으로 회전하는 두 번째 예제를 참조하세요.\"\n\n#: ../../shape.rst:358 c9924f296b104dcb885e423a8329287a\nmsgid \"\"\n\"**If positive or zero**: successful execution. The value returned is the \"\n\"unused rectangle line space in pixels. This may safely be ignored -- or \"\n\"be used to optimize the rectangle, position subsequent items, etc.  **If \"\n\"negative**: no execution. The value returned is the space deficit to \"\n\"store text lines. Enlarge rectangle, decrease *fontsize*, decrease text \"\n\"amount, etc.\"\nmsgstr \"\"\n\n#: ../../shape.rst:359 ff434ea0b01748d3a22351b8914d1de9\nmsgid \"\"\n\"**If positive or zero**: successful execution. The value returned is the \"\n\"unused rectangle line space in pixels. This may safely be ignored -- or \"\n\"be used to optimize the rectangle, position subsequent items, etc.\"\nmsgstr \"**양수 또는 0인 경우**: 성공적인 실행. 반환된 값은 픽셀 단위의 사용되지 않은 사각형 줄 공간입니다. 이것은 안전하게 무시할 수 있습니다 -- 또는 사각형을 최적화하고 후속 항목을 배치하는 데 사용할 수 있습니다.\"\n\n#: ../../shape.rst:361 2d7f62a0c5ec468eb58daea2b7b74842\nmsgid \"\"\n\"**If negative**: no execution. The value returned is the space deficit to\"\n\" store text lines. Enlarge rectangle, decrease *fontsize*, decrease text \"\n\"amount, etc.\"\nmsgstr \"**음수인 경우**: 실행되지 않음. 반환된 값은 텍스트 줄을 저장하기 위한 공간 부족입니다. 사각형을 확대하고, *fontsize* 를 줄이고, 텍스트 양을 줄이는 등을 수행하세요.\"\n\n#: ../../shape.rst:375 f65e40d3ebec4535af01faa79e3c04db\nmsgid \"\"\n\"Update the page's :data:`contents` with the accumulated drawings, \"\n\"followed by any text insertions. If text overlaps drawings, it will be \"\n\"written on top of the drawings.\"\nmsgstr \"누적된 그림으로 페이지의 :data:`contents` 를 업데이트한 다음 텍스트 삽입을 수행합니다. 텍스트가 그림과 겹치면 그림 위에 기록됩니다.\"\n\n#: ../../shape.rst:377 3cc36436278147c4bf9af8031f1046a3\nmsgid \"**Do not forget to execute this method:**\"\nmsgstr \"**이 메서드를 실행하는 것을 잊지 마세요:**\"\n\n#: ../../shape.rst:379 44ccc171888e476f88b7c3ce68d54ad9\nmsgid \"\"\n\"If a shape is **not committed, it will be ignored and the page will not \"\n\"be changed!**\"\nmsgstr \"shape가 **커밋되지 않으면 무시되고 페이지가 변경되지 않습니다!**\"\n\n#: ../../shape.rst:381 8911998982cf45e6b4d61df722ae0084\nmsgid \"\"\n\"The method will reset attributes :attr:`Shape.rect`, :attr:`lastPoint`, \"\n\":attr:`draw_cont`, :attr:`text_cont` and :attr:`totalcont`. Afterwards, \"\n\"the shape object can be reused for the **same page**.\"\nmsgstr \"이 메서드는 속성 :attr:`Shape.rect`, :attr:`lastPoint`, :attr:`draw_cont`, :attr:`text_cont` 및 :attr:`totalcont` 를 재설정합니다. 이후 shape 객체는 **동일한 페이지** 에 대해 재사용할 수 있습니다.\"\n\n#: ../../shape.rst:383 90b57d6cc3344abaa5ae796d17518c78\nmsgid \"\"\n\"determine whether to put content in foreground (default) or background. \"\n\"Relevant only, if the page already has a non-empty :data:`contents` \"\n\"object.\"\nmsgstr \"콘텐츠를 전경(기본값) 또는 배경에 배치할지 결정합니다. 페이지에 이미 비어 있지 않은 :data:`contents` 객체가 있는 경우에만 관련됩니다.\"\n\n#: ../../shape.rst:385 555f29f07330465799e60c983380d945\nmsgid \"**---------- Attributes ----------**\"\nmsgstr \"**---------- Attributes ----------**\"\n\n#: ../../shape.rst:389 bcd84d9d71fe4ab7a75882c2f6ea55ee\nmsgid \"For reference only: the page's document.\"\nmsgstr \"참조용: 페이지의 문서.\"\n\n#: ../../shape.rst 4bc5f78dcd47499499d993fc76937923\n#: 51e0e906798c404999816e887c14725e 583eb30bb6764d82886dcee5ecc5ef23\n#: 7da907572dab4cdd850b1f99866f1208 84fee03ff02a47de895a2e76a85339b0\n#: 8ad67482ac084e4e8acd77c771ac9813 bd1c39ed922a4dba9f34104a29bd9bd6\n#: dc8385568c9641d9bb717e0218bc356a f04ca533ba0f465e9baafc622227ff3a\nmsgid \"type\"\nmsgstr \"type\"\n\n#: ../../shape.rst:391 d4a7179efc87417687ed54512b5fd372\nmsgid \":ref:`Document`\"\nmsgstr \":ref:`Document`\"\n\n#: ../../shape.rst:395 e50d0793a5eb432bb3c2ca8ea196f4c2\nmsgid \"For reference only: the owning page.\"\nmsgstr \"참조용: 소유 페이지.\"\n\n#: ../../shape.rst:397 a88ee833273045f299c35dd3ead948a4\nmsgid \":ref:`Page`\"\nmsgstr \":ref:`Page`\"\n\n#: ../../shape.rst:401 2bad01b347624c13a0c42fc3970fc1b5\nmsgid \"Copy of the page's height\"\nmsgstr \"페이지 높이의 복사본\"\n\n#: ../../shape.rst:403 ../../shape.rst:409 a1d7f49541cb48ab8a1087635dffe627\n#: ee0e76b01d494167bc804a4bcb20168e\nmsgid \"float\"\nmsgstr \"\"\n\n#: ../../shape.rst:407 ae4a0df9e57c45dd99dc05694d71194d\nmsgid \"Copy of the page's width.\"\nmsgstr \"페이지 너비의 복사본.\"\n\n#: ../../shape.rst:413 36e04a92b85b455f986d86cf86a84b9d\nmsgid \"\"\n\"Accumulated command buffer for **draw methods** since last finish. Every \"\n\"finish method will append its commands to :attr:`Shape.totalcont`.\"\nmsgstr \"마지막 finish 이후 **draw 메서드** 의 누적 명령 버퍼. 모든 finish 메서드는 명령을 :attr:`Shape.totalcont` 에 추가합니다.\"\n\n#: ../../shape.rst:415 ../../shape.rst:421 ../../shape.rst:442\n#: 0e691c52a692459fb3651063bbd96fa1 3bd5e87273ea409ba3861ff7a5df3fba\n#: 6131e3edacf44d948d0f06ae76196fb4\nmsgid \"str\"\nmsgstr \"\"\n\n#: ../../shape.rst:419 1c7cc423d0b647cc8b976e70594d7e5a\nmsgid \"\"\n\"Accumulated text buffer. All **text insertions** go here. This buffer \"\n\"will be appended to :attr:`totalcont` :meth:`Shape.commit`, so that text \"\n\"will never be covered by drawings in the same Shape.\"\nmsgstr \"누적된 텍스트 버퍼. 모든 **텍스트 삽입** 이 여기로 갑니다. 이 버퍼는 :meth:`Shape.commit` 에서 :attr:`totalcont` 에 추가되므로 텍스트가 같은 Shape의 그림에 의해 덮이지 않습니다.\"\n\n#: ../../shape.rst:425 31e0348adf3949dea03c7e108eec0e9a\nmsgid \"\"\n\"Rectangle surrounding drawings. This attribute is at your disposal and \"\n\"may be changed at any time. Its value is set to ``None`` when a shape is \"\n\"created or committed. Every *draw** method, and \"\n\":meth:`Shape.insert_textbox` update this property (i.e. **enlarge** the \"\n\"rectangle as needed). **Morphing** operations, however \"\n\"(:meth:`Shape.finish`, :meth:`Shape.insert_textbox`) are ignored.\"\nmsgstr \"그림을 둘러싸는 사각형. 이 속성은 사용자가 자유롭게 사용할 수 있으며 언제든지 변경할 수 있습니다. shape가 생성되거나 커밋될 때 값이 ``None`` 으로 설정됩니다. 모든 *draw** 메서드와 :meth:`Shape.insert_textbox` 는 이 속성을 업데이트합니다(즉, 필요에 따라 사각형을 **확대**). 하지만 **Morphing** 작업(:meth:`Shape.finish`, :meth:`Shape.insert_textbox`)은 무시됩니다.\"\n\n#: ../../shape.rst:427 58e3a175f61343beb779d52d6f9a968a\nmsgid \"\"\n\"A typical use of this attribute would be setting \"\n\":attr:`Page.cropbox_position` to this value, when you are creating shapes\"\n\" for later or external use. If you have not manipulated the attribute \"\n\"yourself, it should reflect a rectangle that contains all drawings so \"\n\"far.\"\nmsgstr \"이 속성의 일반적인 사용은 나중에 사용하거나 외부에서 사용하기 위해 shape를 생성할 때 :attr:`Page.cropbox_position` 을 이 값으로 설정하는 것입니다. 속성을 직접 조작하지 않은 경우 지금까지의 모든 그림을 포함하는 사각형을 반영해야 합니다.\"\n\n#: ../../shape.rst:429 bde3111f6fcb4fde8ae6d94e2b784878\nmsgid \"\"\n\"If you have used morphing and need a rectangle containing the morphed \"\n\"objects, use the following code::\"\nmsgstr \"변형을 사용했고 변형된 객체를 포함하는 사각형이 필요한 경우 다음 코드를 사용하세요::\"\n\n#: ../../shape.rst:436 8b59162d4cdc4453a1a62c884c29d8c5\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../shape.rst:440 70f79c2bf0624368be25e43a4b7a3c3f\nmsgid \"\"\n\"Total accumulated command buffer for draws and text insertions. This will\"\n\" be used by :meth:`Shape.commit`.\"\nmsgstr \"그리기 및 텍스트 삽입을 위한 총 누적 명령 버퍼. 이것은 :meth:`Shape.commit` 에서 사용됩니다.\"\n\n#: ../../shape.rst:446 2a512a35544e4ff4bc0908226c3f1474\nmsgid \"\"\n\"For reference only: the current point of the drawing path. It is ``None``\"\n\" at *Shape* creation and after each *finish()* and *commit()*.\"\nmsgstr \"참조용: 그리기 경로의 현재 점. *Shape* 생성 시 및 각 *finish()* 및 *commit()* 후에 ``None`` 입니다.\"\n\n#: ../../shape.rst:451 5f43e7fa99ee464a8f4e310b6073e35b\nmsgid \"Usage\"\nmsgstr \"사용법\"\n\n#: ../../shape.rst:452 a35b85f2df424fe5a8123cbd236b49c9\nmsgid \"\"\n\"A drawing object is constructed by *shape = page.new_shape()*. After \"\n\"this, as many draw, finish and text insertions methods as required may \"\n\"follow. Each sequence of draws must be finished before the drawing is \"\n\"committed. The overall coding pattern looks like this::\"\nmsgstr \"그리기 객체는 *shape = page.new_shape()* 로 구성됩니다. 그 후 필요한 만큼 많은 draw, finish 및 텍스트 삽입 메서드가 올 수 있습니다. 그리기가 커밋되기 전에 각 draw 시퀀스가 완료되어야 합니다. 전체 코딩 패턴은 다음과 같습니다::\"\n\n#: ../../shape.rst:471 7d0392c130464a54a962cc95cad3ce9d\nmsgid \"\"\n\"Each *finish()* combines the preceding draws into one logical shape, \"\n\"giving it common colors, line width, morphing, etc. If *closePath* is \"\n\"specified, it will also connect the end point of the last draw with the \"\n\"starting point of the first one.\"\nmsgstr \"각 *finish()* 는 앞의 그리기를 하나의 논리적 모양으로 결합하여 공통 색상, 선 너비, 변형 등을 제공합니다. *closePath* 가 지정되면 마지막 그리기의 끝점을 첫 번째 그리기의 시작점과 연결합니다.\"\n\n#: ../../shape.rst:473 d909c60fe1834c8eb1936c81f4fe8a7c\nmsgid \"\"\n\"To successfully create compound graphics, let each draw method use the \"\n\"end point of the previous one as its starting point. In the above pseudo \"\n\"code, *draw2* should hence use the returned :ref:`Point` of *draw1* as \"\n\"its starting point. Failing to do so, would automatically start a new \"\n\"path and *finish()* may not work as expected (but it won't complain \"\n\"either).\"\nmsgstr \"복합 그래픽을 성공적으로 만들려면 각 draw 메서드가 이전 메서드의 끝점을 시작점으로 사용하도록 하세요. 위의 의사 코드에서 *draw2* 는 따라서 *draw1* 의 반환된 :ref:`Point` 를 시작점으로 사용해야 합니다. 그렇게 하지 않으면 자동으로 새 경로가 시작되고 *finish()* 가 예상대로 작동하지 않을 수 있습니다(하지만 불평하지도 않습니다).\"\n\n#: ../../shape.rst:475 fb42b4b00cfd4c8f9bc125398e78d941\nmsgid \"\"\n\"Text insertions may occur anywhere before the commit (they neither touch \"\n\":attr:`Shape.draw_cont` nor :attr:`Shape.lastPoint`). They are appended \"\n\"to *Shape.totalcont* directly, whereas draws will be appended by \"\n\"*Shape.finish*.\"\nmsgstr \"텍스트 삽입은 커밋 전 어디서든 발생할 수 있습니다(:attr:`Shape.draw_cont` 나 :attr:`Shape.lastPoint` 를 건드리지 않습니다). 이것들은 *Shape.totalcont* 에 직접 추가되는 반면, 그리기는 *Shape.finish* 에 의해 추가됩니다.\"\n\n#: ../../shape.rst:477 f1ba4537b82747479d0306c9e87f4f4c\nmsgid \"\"\n\"Each *commit* takes all text insertions and shapes and places them in \"\n\"foreground or background on the page -- thus providing a way to control \"\n\"graphical layers.\"\nmsgstr \"각 *commit* 은 모든 텍스트 삽입과 모양을 가져와 페이지의 전경 또는 배경에 배치합니다 -- 따라서 그래픽 레이어를 제어하는 방법을 제공합니다.\"\n\n#: ../../shape.rst:479 f54933082b2d4eff99e12a13fc1482a9\nmsgid \"\"\n\"**Only** *commit* **will update** the page's contents, the other methods \"\n\"are basically string manipulations.\"\nmsgstr \"**오직** *commit* 만 페이지의 콘텐츠를 **업데이트** 하며, 다른 메서드는 기본적으로 문자열 조작입니다.\"\n\n#: ../../shape.rst:482 278641dcb46d4baf936c58e97dcd5458\nmsgid \"Examples\"\nmsgstr \"예제\"\n\n#: ../../shape.rst:483 eb1041462daa4eaea29f2c68f9820833\nmsgid \"Create a full circle of pieces of pie in different colors::\"\nmsgstr \"다양한 색상의 파이 조각으로 전체 원 만들기::\"\n\n#: ../../shape.rst:498 eaebaebe3baa4f09947553ff9e26c2a1\nmsgid \"Here is an example for 5 colors:\"\nmsgstr \"다음은 5가지 색상의 예제입니다:\"\n\n#: ../../shape.rst:502 3cf653254d684532a9c3aba1c78bfd12\nmsgid \"\"\n\"Create a regular n-edged polygon (fill yellow, red border). We use \"\n\"*draw_sector()* only to calculate the points on the circumference, and \"\n\"empty the draw command buffer again before drawing the polygon::\"\nmsgstr \"정규 n각형 만들기(노란색 채우기, 빨간색 테두리). 원주 위의 점을 계산하기 위해 *draw_sector()* 만 사용하고, 다각형을 그리기 전에 그리기 명령 버퍼를 다시 비웁니다::\"\n\n#: ../../shape.rst:517 e093071b33a14f6ca8a50b7e9ef6d3b1\nmsgid \"Here is the polygon for n = 7:\"\nmsgstr \"다음은 n = 7인 다각형입니다:\"\n\n#: ../../shape.rst:524 32cfdbeb116244d09f20318c9cbaa2ac\nmsgid \"Common Parameters\"\nmsgstr \"공통 매개변수\"\n\n#: ../../shape.rst:526 e8e32aa90b154bf9b1f9186f60ab584a\nmsgid \"**fontname** (*str*)\"\nmsgstr \"**fontname** (*str*)\"\n\n#: ../../shape.rst:528 77ba86666bd24c11b1d1d22120f706a7\nmsgid \"In general, there are three options:\"\nmsgstr \"일반적으로 세 가지 옵션이 있습니다:\"\n\n#: ../../shape.rst:530 02905b80e6194c4eacf48669a2b4862d\nmsgid \"\"\n\"Use one of the standard :ref:`Base-14-Fonts`. In this case, *fontfile* \"\n\"**must not** be specified and *\\\"Helvetica\\\"* is used if this parameter \"\n\"is omitted, too.\"\nmsgstr \"표준 :ref:`Base-14-Fonts` 중 하나를 사용합니다. 이 경우 *fontfile* 을 **지정하면 안 되며** 이 매개변수도 생략하면 *\\\"Helvetica\\\"* 가 사용됩니다.\"\n\n#: ../../shape.rst:531 e643b83ac7934c6a8daf143d5e6ea969\nmsgid \"\"\n\"Choose a font already in use by the page. Then specify its **reference** \"\n\"name prefixed with a slash \\\"/\\\", see example below.\"\nmsgstr \"페이지에서 이미 사용 중인 글꼴을 선택합니다. 그런 다음 슬래시 \\\"/\\\" 로 시작하는 **참조** 이름을 지정하세요. 아래 예제를 참조하세요.\"\n\n#: ../../shape.rst:532 1aa96eb291154994b5334cb249b357b8\nmsgid \"\"\n\"Specify a font file present on your system. In this case choose an \"\n\"arbitrary, but new name for this parameter (without \\\"/\\\" prefix).\"\nmsgstr \"시스템에 있는 글꼴 파일을 지정합니다. 이 경우 이 매개변수에 대해 임의의 새 이름을 선택하세요(\\\"/\\\" 접두사 없이).\"\n\n#: ../../shape.rst:534 42e52261eb524d2984f6a0c4332a2f24\nmsgid \"\"\n\"If inserted text should re-use one of the page's fonts, use its reference\"\n\" name appearing in :meth:`Page.get_fonts` like so:\"\nmsgstr \"삽입된 텍스트가 페이지의 글꼴 중 하나를 재사용해야 하는 경우 :meth:`Page.get_fonts` 에 나타나는 참조 이름을 다음과 같이 사용하세요:\"\n\n#: ../../shape.rst:536 17c14b3525c343518ae06671819af5b8\nmsgid \"\"\n\"Suppose the font list has the item *[1024, 0, 'Type1', 'NimbusMonL-Bold',\"\n\" 'R366']*, then specify *fontname = \\\"/R366\\\", fontfile = None* to use \"\n\"font *NimbusMonL-Bold*.\"\nmsgstr \"글꼴 목록에 항목 *[1024, 0, 'Type1', 'NimbusMonL-Bold', 'R366']* 가 있다고 가정하면, 글꼴 *NimbusMonL-Bold* 를 사용하기 위해 *fontname = \\\"/R366\\\", fontfile = None* 을 지정하세요.\"\n\n#: ../../shape.rst:540 30272688bae040099e4f10745899bb73\nmsgid \"**fontfile** (*str*)\"\nmsgstr \"**fontfile** (*str*)\"\n\n#: ../../shape.rst:542 c86a2afe0b8040a3841ecc108e5f0c2a\nmsgid \"\"\n\"File path of a font existing on your computer. If you specify *fontfile*,\"\n\" make sure you use a *fontname* **not occurring** in the above list. This\"\n\" new font will be embedded in the PDF upon *doc.save()*. Similar to new \"\n\"images, a font file will be embedded only once. A table of MD5 codes for \"\n\"the binary font contents is used to ensure this.\"\nmsgstr \"컴퓨터에 있는 글꼴의 파일 경로. *fontfile* 을 지정하는 경우 위 목록에 **나타나지 않는** *fontname* 을 사용해야 합니다. 이 새 글꼴은 *doc.save()* 시 PDF에 포함됩니다. 새 이미지와 유사하게 글꼴 파일은 한 번만 포함됩니다. 바이너리 글꼴 콘텐츠의 MD5 코드 테이블을 사용하여 이를 보장합니다.\"\n\n#: ../../shape.rst:546 de497e62ab204c48ae01fa7ac3ed1c32\nmsgid \"**set_simple** (*bool*)\"\nmsgstr \"**set_simple** (*bool*)\"\n\n#: ../../shape.rst:548 8620026ea526446e8ef1ca19f9760737\nmsgid \"\"\n\"Fonts installed from files are installed as **Type0** fonts by default. \"\n\"If you want to use 1-byte characters only, set this to true. This setting\"\n\" cannot be reverted. Subsequent changes are ignored.\"\nmsgstr \"파일에서 설치된 글꼴은 기본적으로 **Type0** 글꼴로 설치됩니다. 1바이트 문자만 사용하려면 이것을 true로 설정하세요. 이 설정은 되돌릴 수 없습니다. 후속 변경 사항은 무시됩니다.\"\n\n#: ../../shape.rst:552 3981f48a75204dc09ff6f422f689ffa4\nmsgid \"**fontsize** (*float*)\"\nmsgstr \"**fontsize** (*float*)\"\n\n#: ../../shape.rst:554 30ac30c13b44417bbeb1b66ed6d98114\nmsgid \"Font size of text, see: :data:`fontsize`.\"\nmsgstr \"텍스트의 글꼴 크기, 참조: :data:`fontsize`.\"\n\n#: ../../shape.rst:558 4d0dc80686d94b4c88776c39286aa523\nmsgid \"**dashes** (*str*)\"\nmsgstr \"**dashes** (*str*)\"\n\n#: ../../shape.rst:560 47655eea2c2e46188c15bd1c75c4117a\nmsgid \"\"\n\"Causes lines to be drawn dashed. The general format is `\\\"[n m] p\\\"` of \"\n\"(up to) 3 floats denoting pixel lengths. ``n`` is the dash length, ``m`` \"\n\"(optional) is the subsequent gap length, and ``p`` (the \\\"phase\\\" - \"\n\"**required**, even if 0!) specifies how many pixels should be skipped \"\n\"before the dashing starts. If ``m`` is omitted, it defaults to ``n``.\"\nmsgstr \"선을 점선으로 그리도록 합니다. 일반 형식은 픽셀 길이를 나타내는 (최대) 3개의 float `\\\"[n m] p\\\"` 입니다. ``n`` 은 대시 길이이고, ``m`` (선택 사항)은 후속 간격 길이이며, ``p`` (\\\"phase\\\" - **필수**, 0이어도!)는 대시가 시작되기 전에 건너뛸 픽셀 수를 지정합니다. ``m`` 이 생략되면 기본값은 ``n`` 입니다.\"\n\n#: ../../shape.rst:562 c003ae76596a4f938a7fd5de9cb061a3\nmsgid \"\"\n\"A continuous line (no dashes) is drawn with `\\\"[] 0\\\"` or ``None`` or \"\n\"`\\\"\\\"`. Examples:\"\nmsgstr \"연속 선(대시 없음)은 `\\\"[] 0\\\"` 또는 ``None`` 또는 `\\\"\\\"` 로 그려집니다. 예제:\"\n\n#: ../../shape.rst:564 e6cbda6711694eb8b100b5a9792385ef\nmsgid \"\"\n\"Specifying `\\\"[3 4] 0\\\"` means dashes of 3 and gaps of 4 pixels following\"\n\" each other.\"\nmsgstr \"`\\\"[3 4] 0\\\"` 을 지정하면 3픽셀 대시와 4픽셀 간격이 연속으로 이어집니다.\"\n\n#: ../../shape.rst:565 3391c97c4550433782ec215117a6557d\nmsgid \"`\\\"[3 3] 0\\\"` and `\\\"[3] 0\\\"` do the same thing.\"\nmsgstr \"`\\\"[3 3] 0\\\"` 과 `\\\"[3] 0\\\"` 은 동일한 작업을 수행합니다.\"\n\n#: ../../shape.rst:567 f068a3fa466545ecaf2d248a20fc2739\nmsgid \"\"\n\"For (the rather complex) details on how to achieve sophisticated dashing \"\n\"effects, see :ref:`AdobeManual`, page 217.\"\nmsgstr \"정교한 대시 효과를 얻는 방법에 대한 (상당히 복잡한) 세부 사항은 :ref:`AdobeManual`, 217페이지를 참조하세요.\"\n\n#: ../../shape.rst:571 82aa9894181a4fe3b697261487bbfe7e\nmsgid \"**color / fill** (*list, tuple*)\"\nmsgstr \"**color / fill** (*list, tuple*)\"\n\n#: ../../shape.rst:573 3ed2643ec6df4cc28a73683cb286285e\nmsgid \"\"\n\"Stroke and fill colors can be specified as tuples or list of of floats \"\n\"from 0 to 1. These sequences must have a length of 1 (GRAY), 3 (RGB) or 4\"\n\" (CMYK). For GRAY colorspace, a single float instead of the unwieldy \"\n\"*(float,)* or *[float]* is also accepted. Accept (default) or use `None` \"\n\"to not use the parameter.\"\nmsgstr \"스트로크 및 채우기 색상은 0부터 1까지의 float 튜플 또는 리스트로 지정할 수 있습니다. 이러한 시퀀스는 길이가 1(GRAY), 3(RGB) 또는 4(CMYK)여야 합니다. GRAY 색 공간의 경우 다루기 어려운 *(float,)* 또는 *[float]* 대신 단일 float도 허용됩니다. 기본값을 수락하거나 `None` 을 사용하여 매개변수를 사용하지 않습니다.\"\n\n#: ../../shape.rst:575 06bd406c862d430d8527a7a38b17df9b\nmsgid \"\"\n\"To simplify color specification, method *getColor()* in *pymupdf.utils* \"\n\"may be used to get predefined RGB color triples by name. It accepts a \"\n\"string as the name of the color and returns the corresponding triple. The\"\n\" method knows over 540 color names -- see section :ref:`ColorDatabase`.\"\nmsgstr \"색상 지정을 단순화하기 위해 *pymupdf.utils* 의 메서드 *getColor()* 를 사용하여 이름으로 미리 정의된 RGB 색상 삼중항을 가져올 수 있습니다. 색상 이름으로 문자열을 받아 해당 삼중항을 반환합니다. 이 메서드는 540개 이상의 색상 이름을 알고 있습니다 -- 섹션 :ref:`ColorDatabase` 를 참조하세요.\"\n\n#: ../../shape.rst:577 3313c7d4006745a8b2fc466404404f63\nmsgid \"\"\n\"Please note that the term *color* usually means \\\"stroke\\\" color when \"\n\"used in conjunction with fill color.\"\nmsgstr \"*color* 라는 용어는 채우기 색상과 함께 사용될 때 일반적으로 \\\"스트로크\\\" 색상을 의미합니다.\"\n\n#: ../../shape.rst:579 0a6d8ba9500941c4bc6aa00352d41451\nmsgid \"\"\n\"If letting default a color parameter to `None`, then no resp. color \"\n\"selection command will be generated. If *fill* and *color* are both \"\n\"`None`, then the drawing will contain no color specification. But it will\"\n\" still be \\\"stroked\\\", which causes PDF's default color \\\"black\\\" be used\"\n\" by Adobe Acrobat and all other viewers.\"\nmsgstr \"색상 매개변수의 기본값을 `None` 으로 두면 해당 색상 선택 명령이 생성되지 않습니다. *fill* 과 *color* 가 모두 `None` 이면 그리기에는 색상 사양이 포함되지 않습니다. 하지만 여전히 \\\"스트로크\\\"되며, 이로 인해 Adobe Acrobat 및 기타 모든 뷰어에서 PDF의 기본 색상 \\\"black\\\" 이 사용됩니다.\"\n\n#: ../../shape.rst:583 2e5246304d274dfaa37af742928af0ea\nmsgid \"**width** (*float*)\"\nmsgstr \"**width** (*float*)\"\n\n#: ../../shape.rst:585 77b8db9870114d7f91f971f5aaa99512\nmsgid \"\"\n\"The stroke (\\\"border\\\") width of the elements in a shape (if applicable).\"\n\" The default value is 1. The values width, color and fill have the \"\n\"following relationship / dependency:\"\nmsgstr \"shape의 요소의 스트로크(\\\"테두리\\\") 너비(해당하는 경우). 기본값은 1입니다. width, color 및 fill 값은 다음과 같은 관계/의존성을 가집니다:\"\n\n#: ../../shape.rst:587 bd3f3d47979d4ba6967fc689176d7873\nmsgid \"\"\n\"If `fill=None` shape elements will always be drawn with a border - even \"\n\"if `color=None` (in which case black is taken) or `width=0` (in which \"\n\"case 1 is taken).\"\nmsgstr \"`fill=None` 이면 shape 요소는 항상 테두리와 함께 그려집니다 -- `color=None` (이 경우 검은색이 사용됨)이거나 `width=0` (이 경우 1이 사용됨)인 경우에도 마찬가지입니다.\"\n\n#: ../../shape.rst:588 50e316e85bee43f3ae23b6e8bf36459e\nmsgid \"\"\n\"Shapes without border can only be achieved if a fill color is specified \"\n\"(which may be white of course). To achieve this, specify `width=0`. In \"\n\"this case, the ``color`` parameter is ignored.\"\nmsgstr \"테두리 없는 shape는 채우기 색상이 지정된 경우에만 달성할 수 있습니다(물론 흰색일 수 있음). 이를 달성하려면 `width=0` 을 지정하세요. 이 경우 ``color`` 매개변수는 무시됩니다.\"\n\n#: ../../shape.rst:592 dbf0b7aa242944fd9c3dba05b0a5476c\nmsgid \"**stroke_opacity / fill_opacity** (*floats*)\"\nmsgstr \"**stroke_opacity / fill_opacity** (*floats*)\"\n\n#: ../../shape.rst:594 f10fd732b18e4d06882b251b866820ed\nmsgid \"\"\n\"Both values are floats in range [0, 1]. Negative values or values > 1 \"\n\"will ignored (in most cases). Both set the transparency such that a value\"\n\" 0.5 corresponds to 50% transparency, 0 means invisible and 1 means \"\n\"intransparent. For e.g. a rectangle the stroke opacity applies to its \"\n\"border and fill opacity to its interior.\"\nmsgstr \"두 값 모두 [0, 1] 범위의 float입니다. 음수 값 또는 값 > 1은 (대부분의 경우) 무시됩니다. 둘 다 투명도를 설정하므로 값 0.5는 50% 투명도에 해당하고, 0은 보이지 않음을 의미하며 1은 불투명을 의미합니다. 예를 들어 사각형의 경우 스트로크 불투명도는 테두리에 적용되고 채우기 불투명도는 내부에 적용됩니다.\"\n\n#: ../../shape.rst:596 908ef08674a94047bf811e5db7824042\nmsgid \"\"\n\"For text insertions (:meth:`Shape.insert_text` and \"\n\":meth:`Shape.insert_textbox`), use *fill_opacity* for the text. At first \"\n\"sight this seems surprising, but it becomes obvious when you look further\"\n\" down to `render_mode`: `fill_opacity` applies to the yellow and \"\n\"`stroke_opacity` applies to the blue color.\"\nmsgstr \"텍스트 삽입(:meth:`Shape.insert_text` 및 :meth:`Shape.insert_textbox`)의 경우 텍스트에 *fill_opacity* 를 사용합니다. 처음에는 놀라울 수 있지만 `render_mode` 를 보면 명확해집니다: `fill_opacity` 는 노란색에 적용되고 `stroke_opacity` 는 파란색에 적용됩니다.\"\n\n#: ../../shape.rst:600 807dedb850524343a44713165dc92d74\nmsgid \"**border_width** (*float*)\"\nmsgstr \"**border_width** (*float*)\"\n\n#: ../../shape.rst:602 7c05f5b49a074002a9a8e24fa16e09c0\nmsgid \"\"\n\"Set the border width for text insertions. New in v1.14.9. Relevant only \"\n\"if the render mode argument is used with a value greater zero.\"\nmsgstr \"텍스트 삽입의 테두리 너비를 설정합니다. v1.14.9의 새로운 기능. 렌더 모드 인수가 0보다 큰 값으로 사용되는 경우에만 관련됩니다.\"\n\n#: ../../shape.rst:606 e8f74369b5414cf39c02c7bdc84d0278\nmsgid \"**render_mode** (*int*)\"\nmsgstr \"**render_mode** (*int*)\"\n\n#: ../../shape.rst:608 07e11204dc2b4479bd2e65c3e33aad8d\nmsgid \"\"\n\"*New in version 1.14.9:* Integer in `range(8)` which controls the text \"\n\"appearance (:meth:`Shape.insert_text` and :meth:`Shape.insert_textbox`). \"\n\"See page 246 in :ref:`AdobeManual`. New in v1.14.9. These methods now \"\n\"also differentiate between fill and stroke colors.\"\nmsgstr \"*버전 1.14.9의 새로운 기능:* 텍스트 모양을 제어하는 `range(8)` 의 정수(:meth:`Shape.insert_text` 및 :meth:`Shape.insert_textbox`). :ref:`AdobeManual` 246페이지를 참조하세요. v1.14.9의 새로운 기능. 이 메서드는 이제 채우기 색상과 스트로크 색상을 구분합니다.\"\n\n#: ../../shape.rst:610 69a9ed429520483291966e04bc134827\nmsgid \"\"\n\"For default 0, only the text fill color is used to paint the text. For \"\n\"backward compatibility, using the *color* parameter instead also works.\"\nmsgstr \"기본값 0의 경우 텍스트를 그리는 데 텍스트 채우기 색상만 사용됩니다. 하위 호환성을 위해 *color* 매개변수를 대신 사용해도 작동합니다.\"\n\n#: ../../shape.rst:611 92f8238398a445de9ac634455065140b\nmsgid \"\"\n\"For render mode 1, only the border of each glyph (i.e. text character) is\"\n\" drawn with a thickness as set in argument *border_width*. The color \"\n\"chosen in the *color* argument is taken for this, the *fill* parameter is\"\n\" ignored.\"\nmsgstr \"렌더 모드 1의 경우 각 글리프(즉, 텍스트 문자)의 테두리만 인수 *border_width* 에 설정된 두께로 그려집니다. *color* 인수에서 선택한 색상이 사용되며 *fill* 매개변수는 무시됩니다.\"\n\n#: ../../shape.rst:612 6dd3e1055d934657ae6fbe17f98f1b7b\nmsgid \"\"\n\"For render mode 2, the glyphs are filled and stroked, using both color \"\n\"parameters and the specified border width. You can use this value to \"\n\"simulate **bold text** without using another font: choose the same value \"\n\"for *fill* and *color* and an appropriate value for *border_width*.\"\nmsgstr \"렌더 모드 2의 경우 글리프가 채워지고 스트로크되며, 두 색상 매개변수와 지정된 테두리 너비를 사용합니다. 다른 글꼴을 사용하지 않고 **굵은 텍스트** 를 시뮬레이션하려면 이 값을 사용할 수 있습니다: *fill* 과 *color* 에 동일한 값을 선택하고 *border_width* 에 적절한 값을 선택하세요.\"\n\n#: ../../shape.rst:613 44ab50cc9488478cbafcd5e8d9859763\nmsgid \"\"\n\"For render mode 3, the glyphs are neither stroked nor filled: the text \"\n\"becomes invisible.\"\nmsgstr \"렌더 모드 3의 경우 글리프가 스트로크되지도 채워지지도 않습니다: 텍스트가 보이지 않게 됩니다.\"\n\n#: ../../shape.rst:615 e59e76826913438ea50a2cc075ab7cd2\nmsgid \"\"\n\"The following examples use border_width=0.3, together with a fontsize of \"\n\"15. Stroke color is blue and fill color is some yellow.\"\nmsgstr \"다음 예제는 border_width=0.3과 함께 fontsize 15를 사용합니다. 스트로크 색상은 파란색이고 채우기 색상은 노란색입니다.\"\n\n#: ../../shape.rst:621 082047ee68a54ee3ae920d7817052247\nmsgid \"**miter_limit** (*float*)\"\nmsgstr \"**miter_limit** (*float*)\"\n\n#: ../../shape.rst:623 5df811fb349949d38e4160fbc8097077\nmsgid \"\"\n\"A float specifying the maximum acceptable value of the quotient `miter-\"\n\"length / line-width` (\\\"miter quotient\\\"). Used in text output methods. \"\n\"This is only relevant for non-zero render mode values -- then, characters\"\n\" are written with border lines (i.e. \\\"stroked\\\").\"\nmsgstr \"몫 `miter-length / line-width` (\\\"miter quotient\\\")의 최대 허용 값을 지정하는 float. 텍스트 출력 메서드에서 사용됩니다. 이것은 0이 아닌 렌더 모드 값에만 관련됩니다 -- 그런 경우 문자는 테두리 선(즉, \\\"스트로크\\\")으로 작성됩니다.\"\n\n#: ../../shape.rst:625 fcdf5a0b4b05400fabcc68e71bbfe4a3\nmsgid \"\"\n\"If two lines stroking some character meet at a sharp (<= 90°) angle and \"\n\"the line width is large enough, then \\\"spikes\\\" may become visible -- \"\n\"causing an ugly appearance as shown below. For more background, see page \"\n\"126 of the :ref:`AdobeManual`.\"\nmsgstr \"일부 문자를 스트로크하는 두 선이 날카로운 (<= 90°) 각도로 만나고 선 너비가 충분히 크면 \\\"스파이크\\\"가 보일 수 있습니다 -- 아래와 같이 보기 흉한 모양을 만듭니다. 더 자세한 내용은 :ref:`AdobeManual` 126페이지를 참조하세요.\"\n\n#: ../../shape.rst:627 61ef12d76d4c44a5971fbe5f377e42cd\nmsgid \"\"\n\"For instance, when joins meet at 90°, then the miter length is ``sqrt(2) \"\n\"* line-width``, so the miter quotient is ``sqrt(2)``.\"\nmsgstr \"예를 들어, 조인이 90°에서 만나면 miter 길이는 ``sqrt(2) * line-width`` 이므로 miter 몫은 ``sqrt(2)`` 입니다.\"\n\n#: ../../shape.rst:629 6e57edd425af46cab1f0544ea9fb09d6\nmsgid \"\"\n\"If ``miter_limit`` is exceeded, then all joins with a larger qotient will\"\n\" appear as beveled (\\\"butt\\\" appearance).\"\nmsgstr \"``miter_limit`` 이 초과되면 더 큰 몫을 가진 모든 조인이 베벨 처리된 것처럼(\\\"butt\\\" 모양) 나타납니다.\"\n\n#: ../../shape.rst:631 1b9c88426fad4881993b42f8df4e29ba\nmsgid \"\"\n\"The default value 1 (and any smaller value) will ensure that all joins \"\n\"are rendered as a butt. A value of ``None`` will use the PDF default \"\n\"value.\"\nmsgstr \"기본값 1(및 더 작은 값)은 모든 조인이 butt로 렌더링되도록 보장합니다. ``None`` 값은 PDF 기본값을 사용합니다.\"\n\n#: ../../shape.rst:633 6c5240d22b91424eb8a99f3f6cdd9e61\nmsgid \"Example text showing spikes (``miter_limit=None``):\"\nmsgstr \"스파이크를 보여주는 예제 텍스트 (``miter_limit=None``):\"\n\n#: ../../shape.rst:637 22b2f2ab87704749865bf8654f86f486\nmsgid \"Example text suppressing spikes (``miter_limit=1``):\"\nmsgstr \"스파이크를 억제하는 예제 텍스트 (``miter_limit=1``):\"\n\n#: ../../shape.rst:643 ef72de748a3241f494828889b778a5c3\nmsgid \"**overlay** (*bool*)\"\nmsgstr \"**overlay** (*bool*)\"\n\n#: ../../shape.rst:645 1a50148614e94b0f9e09a72b981ba540\nmsgid \"Causes the item to appear in foreground (default) or background.\"\nmsgstr \"항목이 전경(기본값) 또는 배경에 나타나도록 합니다.\"\n\n#: ../../shape.rst:649 f9c30f5c9a0245e5acbf5d0126b40609\nmsgid \"**morph** (*sequence*)\"\nmsgstr \"**morph** (*sequence*)\"\n\n#: ../../shape.rst:651 5029b952e1be402ea4aea727b6c5334a\nmsgid \"\"\n\"Causes \\\"morphing\\\" of either a shape, created by the *draw*()* methods, \"\n\"or the text inserted by page methods *insert_textbox()* / \"\n\"*insert_text()*. If not ``None``, it must be a pair *(fixpoint, matrix)*,\"\n\" where *fixpoint* is a :ref:`Point` and *matrix* is a :ref:`Matrix`. The \"\n\"matrix can be anything except translations, i.e. *matrix.e == matrix.f ==\"\n\" 0* must be true. The point is used as a fixed point for the matrix \"\n\"operation. For example, if *matrix* is a rotation or scaling, then \"\n\"*fixpoint* is its center. Similarly, if *matrix* is a left-right or up-\"\n\"down flip, then the mirroring axis will be the vertical, respectively \"\n\"horizontal line going through *fixpoint*, etc.\"\nmsgstr \"*draw*()* 메서드로 생성된 shape 또는 페이지 메서드 *insert_textbox()* / *insert_text()* 로 삽입된 텍스트의 \\\"변형\\\"을 일으킵니다. ``None`` 이 아니면 *(fixpoint, matrix)* 쌍이어야 하며, 여기서 *fixpoint* 는 :ref:`Point` 이고 *matrix* 는 :ref:`Matrix` 입니다. 행렬은 이동을 제외한 모든 것이 될 수 있습니다. 즉, *matrix.e == matrix.f == 0* 이 참이어야 합니다. 점은 행렬 작업의 고정점으로 사용됩니다. 예를 들어, *matrix* 가 회전 또는 확대/축소이면 *fixpoint* 는 중심입니다. 마찬가지로, *matrix* 가 좌우 또는 상하 뒤집기이면 미러링 축은 각각 *fixpoint* 를 통과하는 수직 또는 수평선이 됩니다.\"\n\n#: ../../shape.rst:653 b02e3c71c8f64fc68a15b90bf3c129ea\nmsgid \"\"\n\"Several methods contain checks whether the to be inserted items will \"\n\"actually fit into the page (like :meth:`Shape.insert_text`, or \"\n\":meth:`Shape.draw_rect`). For the result of a morphing operation there is\"\n\" however no such guaranty: this is entirely the programmer's \"\n\"responsibility.\"\nmsgstr \"여러 메서드는 삽입될 항목이 실제로 페이지에 맞는지 확인합니다(:meth:`Shape.insert_text` 또는 :meth:`Shape.draw_rect` 등). 하지만 변형 작업의 결과에 대해서는 그러한 보장이 없습니다: 이것은 전적으로 프로그래머의 책임입니다.\"\n\n#: ../../shape.rst:657 62281c77ca8f47188d63f20f3712a5b0\nmsgid \"**lineCap (deprecated: \\\"roundCap\\\")** (*int*)\"\nmsgstr \"**lineCap (더 이상 사용되지 않음: \\\"roundCap\\\")** (*int*)\"\n\n#: ../../shape.rst:659 cd5b630baa744b1189ae847e6e8286fd\nmsgid \"\"\n\"Controls the look of line ends. The default value 0 lets each line end at\"\n\" exactly the given coordinate in a sharp edge. A value of 1 adds a semi-\"\n\"circle to the ends, whose center is the end point and whose diameter is \"\n\"the line width. Value 2 adds a semi-square with an edge length of line \"\n\"width and a center of the line end.\"\nmsgstr \"선 끝의 모양을 제어합니다. 기본값 0은 각 선이 날카로운 가장자리에서 정확히 주어진 좌표에서 끝나도록 합니다. 값 1은 끝에 반원을 추가하며, 중심은 끝점이고 지름은 선 너비입니다. 값 2는 선 너비의 가장자리 길이와 선 끝의 중심을 가진 반사각형을 추가합니다.\"\n\n#: ../../shape.rst:661 6026a44a326145afa3e7a6f376a1bbf6\nmsgid \"*Changed in version 1.14.15*\"\nmsgstr \"*버전 1.14.15에서 변경됨*\"\n\n#: ../../shape.rst:665 2e6dced4dc3b49d0bfc6d15aba362eba\nmsgid \"**lineJoin** (*int*)\"\nmsgstr \"**lineJoin** (*int*)\"\n\n#: ../../shape.rst:667 66fbb0a47a7648efa567adac178985a1\nmsgid \"\"\n\"*New in version 1.14.15:* Controls the way how line connections look \"\n\"like. This may be either as a sharp edge (0), a rounded join (1), or a \"\n\"cut-off edge (2, \\\"butt\\\").\"\nmsgstr \"*버전 1.14.15의 새로운 기능:* 선 연결의 모양을 제어합니다. 이것은 날카로운 가장자리(0), 둥근 조인(1) 또는 잘린 가장자리(2, \\\"butt\\\")일 수 있습니다.\"\n\n#: ../../shape.rst:671 82bab1c6af0a4d169a36b68529a2ab41\nmsgid \"**closePath** (*bool*)\"\nmsgstr \"**closePath** (*bool*)\"\n\n#: ../../shape.rst:673 991347c321464275b6f78b81a2f89e09\nmsgid \"\"\n\"Causes the end point of a drawing to be automatically connected with the \"\n\"starting point (by a straight line).\"\nmsgstr \"그리기의 끝점을 시작점과 자동으로 연결합니다(직선으로).\"\n\n#: ../../footer.rst:46 703f5e6cdc364cd898823615d897ea50\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/story-class.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 4450760445994835a9f3775bc9c6f0d5\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 418de775a4634f88837f5ac77a451b10\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 497384ace3f84fa19412dac9da22148c\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../story-class.rst:7 8fafdeea9e5940c28193c7e4fca942c5\nmsgid \"Story\"\nmsgstr \"Story\"\n\n#: ../../story-class.rst:11 ce4d16eaf6e64bc59264c0a812630ed7\nmsgid \"New in v1.21.0\"\nmsgstr \"v1.21.0 에서 새로 추가됨\"\n\n#: ../../story-class.rst:14 9b7cd17b7b8b43e89336e41091ffd8db\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../story-class.rst:14 306881cbd8ff40e98c769bdad361af16\nmsgid \"**Short Description**\"\nmsgstr \"**간단한 설명**\"\n\n#: ../../story-class.rst:16 87f3b530a2174677808e6a73c8c7c3d4\nmsgid \":meth:`Story.reset`\"\nmsgstr \":meth:`Story.reset`\"\n\n#: ../../story-class.rst:16 986c1b4812b34f7b90447c9b85c00515\nmsgid \"\\\"rewind\\\" story output to its beginning\"\nmsgstr \"스토리 출력을 시작 부분으로 \\\"되감기\\\"\"\n\n#: ../../story-class.rst:17 acfb8788456043e98e066d8b7f232242\nmsgid \":meth:`Story.place`\"\nmsgstr \":meth:`Story.place`\"\n\n#: ../../story-class.rst:17 71dd7b0f8852455eb72f274d589300e5\nmsgid \"compute story content to fit in provided rectangle\"\nmsgstr \"제공된 사각형에 맞도록 스토리 콘텐츠 계산\"\n\n#: ../../story-class.rst:18 f37a1cf6b3d447fcb752828907626437\nmsgid \":meth:`Story.draw`\"\nmsgstr \":meth:`Story.draw`\"\n\n#: ../../story-class.rst:18 44a1f29ca77c4ed281ff70a784a28d92\nmsgid \"write the computed content to current page\"\nmsgstr \"계산된 콘텐츠를 현재 페이지에 쓰기\"\n\n#: ../../story-class.rst:19 fc8ae71a62484786b2548b2f0715d3e7\nmsgid \":meth:`Story.element_positions`\"\nmsgstr \":meth:`Story.element_positions`\"\n\n#: ../../story-class.rst:19 78ea4b34e9924ea0b59ec0f387db8d9f\nmsgid \"callback function logging currently processed story content\"\nmsgstr \"현재 처리 중인 스토리 콘텐츠를 로깅하는 콜백 함수\"\n\n#: ../../story-class.rst:20 5703135b6e844a53859347624fb3ba8e\nmsgid \":attr:`Story.body`\"\nmsgstr \":attr:`Story.body`\"\n\n#: ../../story-class.rst:20 8074d90f9db0473c9f78fde5598d87a0\nmsgid \"the story's underlying :htmlTag:`body`\"\nmsgstr \"스토리의 기본 :htmlTag:`body`\"\n\n#: ../../story-class.rst:21 b7007d57a5f0478da333d3b7defa34da\nmsgid \":meth:`Story.write`\"\nmsgstr \":meth:`Story.write`\"\n\n#: ../../story-class.rst:21 529c592a049543488f766ea64af4aef6\nmsgid \"places and draws Story to a DocumentWriter\"\nmsgstr \"Story를 DocumentWriter에 배치하고 그리기\"\n\n#: ../../story-class.rst:22 48189b1970a944249727deeaab30767a\nmsgid \":meth:`Story.write_stabilized`\"\nmsgstr \":meth:`Story.write_stabilized`\"\n\n#: ../../story-class.rst:22 c71c16dc9e434b81ae25d7e81791842c\nmsgid \"iterative layout of html content to a DocumentWriter\"\nmsgstr \"HTML 콘텐츠를 DocumentWriter에 반복 레이아웃\"\n\n#: ../../story-class.rst:23 926f2a550c3b4cb3856a305b4c499249\nmsgid \":meth:`Story.write_with_links`\"\nmsgstr \":meth:`Story.write_with_links`\"\n\n#: ../../story-class.rst:23 ea4c862bdeb84b94a80868a8fa1d6d3c\nmsgid \"like `write()` but also creates PDF links\"\nmsgstr \"`write()` 와 유사하지만 PDF 링크도 생성\"\n\n#: ../../story-class.rst:24 355d937b5c4a4d2ea430c50ed160c9a9\nmsgid \":meth:`Story.write_stabilized_with_links`\"\nmsgstr \":meth:`Story.write_stabilized_with_links`\"\n\n#: ../../story-class.rst:24 ff1a2e0bd3b942a9825101dc74641ab4\nmsgid \"like `write_stabilized()` but also creates PDF links\"\nmsgstr \"`write_stabilized()` 와 유사하지만 PDF 링크도 생성\"\n\n#: ../../story-class.rst:25 98afa53a01d5479fb9a84e798fc75af0\nmsgid \":meth:`Story.fit`\"\nmsgstr \":meth:`Story.fit`\"\n\n#: ../../story-class.rst:25 ../../story-class.rst:252\n#: 08f697738e6841388fafdd24e5a00d7d f9fb3d7fc30744c5a4bcf19dc86ef076\nmsgid \"Finds optimal rect that contains the story `self`.\"\nmsgstr \"스토리 `self` 를 포함하는 최적의 rect를 찾습니다.\"\n\n#: ../../story-class.rst:26 071db5186e824d7fad400d8f4d4621cc\nmsgid \":meth:`Story.fit_scale`\"\nmsgstr \":meth:`Story.fit_scale`\"\n\n#: ../../story-class.rst:27 29faf46f8f304213baacc284272e99ba\nmsgid \":meth:`Story.fit_height`\"\nmsgstr \":meth:`Story.fit_height`\"\n\n#: ../../story-class.rst:28 2063bec0fd3d4a00af6338d93189ee72\nmsgid \":meth:`Story.fit_width`\"\nmsgstr \":meth:`Story.fit_width`\"\n\n#: ../../story-class.rst:31 35c3d645808f404fb3d0ac4e2995d443\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../story-class.rst:37 49eb5559ce2b4b13a47f5ad496e9d111\nmsgid \"\"\n\"Create a **story**, optionally providing HTML and CSS source. The HTML is\"\n\" parsed, and held within the Story as a DOM (Document Object Model).\"\nmsgstr \"**스토리** 를 생성하며, 선택적으로 HTML 및 CSS 소스를 제공합니다. HTML은 파싱되어 Story 내에서 DOM(Document Object Model)로 유지됩니다.\"\n\n#: ../../story-class.rst:40 bf2f904ab1c24ea9aa46205eca2718ea\nmsgid \"\"\n\"This structure may be modified: content (text, images) may be added, \"\n\"copied, modified or removed by using methods of the :ref:`Xml` class.\"\nmsgstr \"이 구조는 수정할 수 있습니다: :ref:`Xml` 클래스의 메서드를 사용하여 콘텐츠(텍스트, 이미지)를 추가, 복사, 수정 또는 제거할 수 있습니다.\"\n\n#: ../../story-class.rst:43 1e855bc531eb4f55a7c51053f068d9ab\nmsgid \"\"\n\"When finished, the **story** can be written to any device; in typical \"\n\"usage the device may be provided by a :ref:`DocumentWriter` to make new \"\n\"pages.\"\nmsgstr \"완료되면 **스토리** 는 모든 장치에 쓸 수 있습니다. 일반적인 사용에서 장치는 :ref:`DocumentWriter` 에 의해 제공되어 새 페이지를 만듭니다.\"\n\n#: ../../story-class.rst:46 c090bdee02db4f288f710c647c45c161\nmsgid \"Here are some general remarks:\"\nmsgstr \"다음은 일반적인 설명입니다:\"\n\n#: ../../story-class.rst:48 3110c6455944434ca9ae1a71696896a3\nmsgid \"\"\n\"The :ref:`Story` constructor parses and validates the provided HTML to \"\n\"create the DOM.\"\nmsgstr \":ref:`Story` 생성자는 제공된 HTML을 파싱하고 검증하여 DOM을 생성합니다.\"\n\n#: ../../story-class.rst:49 4d9f69c5792d489b85a3b9d41d525d79\nmsgid \"\"\n\"PyMuPDF provides a number of ways to manipulate the HTML source by \"\n\"providing access to the *nodes* of the underlying DOM. Documents can be \"\n\"completely built from ground up programmatically, or the existing DOM can\"\n\" be modified pretty arbitrarily. For details of this interface, please \"\n\"see the :ref:`Xml` class.\"\nmsgstr \"|PyMuPDF| 는 기본 DOM의 *노드* 에 대한 액세스를 제공하여 HTML 소스를 조작하는 여러 방법을 제공합니다. 문서는 프로그래밍 방식으로 처음부터 완전히 구축할 수 있거나, 기존 DOM을 거의 임의로 수정할 수 있습니다. 이 인터페이스의 세부 사항은 :ref:`Xml` 클래스를 참조하세요.\"\n\n#: ../../story-class.rst:54 ac1a27756a8945c8b1dbf9b6e9da921b\nmsgid \"\"\n\"If no (or no more) changes to the DOM are required, the story is ready to\"\n\" be laid out and to be fed to a series of devices (typically devices \"\n\"provided by a :ref:`DocumentWriter` to produce new pages).\"\nmsgstr \"DOM에 대한 변경이 더 이상 필요하지 않으면 스토리는 레이아웃되고 일련의 장치(일반적으로 새 페이지를 생성하기 위해 :ref:`DocumentWriter` 에 의해 제공되는 장치)에 공급할 준비가 됩니다.\"\n\n#: ../../story-class.rst:57 43fe3dfc3cf348098a32b05485bde654\nmsgid \"\"\n\"The next step is to place the story and write it out. This can either be \"\n\"done directly, by looping around calling `place()` and `draw()`, or \"\n\"alternatively, the looping can handled for you using the `write()` or \"\n\"`write_stabilised()` methods. Which method you choose is largely a matter\"\n\" of taste.\"\nmsgstr \"다음 단계는 스토리를 배치하고 쓰는 것입니다. 이것은 `place()` 및 `draw()` 호출을 반복하는 루프로 직접 수행하거나, 대신 `write()` 또는 `write_stabilised()` 메서드를 사용하여 루프를 처리할 수 있습니다. 어떤 방법을 선택할지는 주로 취향의 문제입니다.\"\n\n#: ../../story-class.rst:63 f4b32731d97b4d2a84d306de1e33820a\nmsgid \"To work in the first of these styles, the following loop should be used:\"\nmsgstr \"이러한 스타일 중 첫 번째로 작업하려면 다음 루프를 사용해야 합니다:\"\n\n#: ../../story-class.rst:65 1ae96b31b4494e6b907dcec02c2fdea5\nmsgid \"\"\n\"Obtain a suitable device to write to; typically by requesting a new, \"\n\"empty page from a :ref:`DocumentWriter`.\"\nmsgstr \"쓰기에 적합한 장치를 얻습니다. 일반적으로 :ref:`DocumentWriter` 에서 새 빈 페이지를 요청합니다.\"\n\n#: ../../story-class.rst:68 73b9d54af347493b94d1d93c72bb7e84\nmsgid \"\"\n\"Determine one or more rectangles on the page, that should receive \"\n\"**story** data. Note that not every page needs to have the same set of \"\n\"rectangles.\"\nmsgstr \"페이지에서 **스토리** 데이터를 받을 하나 이상의 사각형을 결정합니다. 모든 페이지가 동일한 사각형 세트를 가질 필요는 없습니다.\"\n\n#: ../../story-class.rst:71 f486ccb350994671b7e2380f3a839e86\nmsgid \"\"\n\"Pass each rectangle to the **story** to place it, learning what part of \"\n\"that rectangle has been filled, and whether there is more story data that\"\n\" did not fit. This step can be repeated several times with adjusted \"\n\"rectangles until the caller is happy with the results.\"\nmsgstr \"각 사각형을 **스토리** 에 전달하여 배치하고, 해당 사각형의 어느 부분이 채워졌는지, 맞지 않는 더 많은 스토리 데이터가 있는지 확인합니다. 이 단계는 호출자가 결과에 만족할 때까지 조정된 사각형으로 여러 번 반복할 수 있습니다.\"\n\n#: ../../story-class.rst:76 ff1738fc7d2d4f969c58dcf423696458\nmsgid \"\"\n\"Optionally, at this point, we can request details of where interesting \"\n\"items have been placed, by calling the `element_positions()` method. \"\n\"Items are deemed to be interesting if their integer `heading` attribute \"\n\"is a non-zero (corresponding to HTML tags :htmlTag:`h1` - :htmlTag:`h6`),\"\n\" if their `id` attribute is not `None` (corresponding to HTML tag \"\n\":htmlTag:`id`), or if their `href` attribute is not `None` (responding to\"\n\" HTML tag :htmlTag:`href`). This can conveniently be used for automatic \"\n\"generation of a Table of Contents, an index of images or the like.\"\nmsgstr \"선택적으로 이 시점에서 `element_positions()` 메서드를 호출하여 흥미로운 항목이 배치된 위치에 대한 세부 정보를 요청할 수 있습니다. 항목은 정수 `heading` 속성이 0이 아닌 경우(HTML 태그 :htmlTag:`h1` - :htmlTag:`h6` 에 해당), `id` 속성이 `None` 이 아닌 경우(HTML 태그 :htmlTag:`id` 에 해당), 또는 `href` 속성이 `None` 이 아닌 경우(HTML 태그 :htmlTag:`href` 에 해당) 흥미로운 것으로 간주됩니다. 이것은 목차, 이미지 인덱스 등의 자동 생성에 편리하게 사용할 수 있습니다.\"\n\n#: ../../story-class.rst:85 b921780cdb2e45e389e9a40859c21b25\nmsgid \"Next, draw that rectangle out to the device with the `draw()` method.\"\nmsgstr \"다음으로 `draw()` 메서드를 사용하여 해당 사각형을 장치에 그립니다.\"\n\n#: ../../story-class.rst:86 7c8805ef770e4dde8806474fd720a74d\nmsgid \"\"\n\"If the most recent call to `place()` indicated that all the story data \"\n\"had fitted, stop now.\"\nmsgstr \"`place()` 에 대한 가장 최근 호출이 모든 스토리 데이터가 맞았다고 표시하면 지금 중지합니다.\"\n\n#: ../../story-class.rst:88 c13e1999d6654790a96926efb47a4809\nmsgid \"\"\n\"Otherwise, we can loop back. If there are more rectangles to be placed on\"\n\" the current device (page), we jump back to step 3 - if not, we jump back\"\n\" to step 1 to get a new device.\"\nmsgstr \"그렇지 않으면 루프로 돌아갈 수 있습니다. 현재 장치(페이지)에 배치할 더 많은 사각형이 있으면 3단계로 돌아가고, 그렇지 않으면 새 장치를 얻기 위해 1단계로 돌아갑니다.\"\n\n#: ../../story-class.rst:91 4038804e871b4c1bbe32c9a13c9ec423\nmsgid \"\"\n\"Alternatively, in the case where you are using a :ref:`DocumentWriter`, \"\n\"the `write()` or `write_stabilized()` methods can be used. These handle \"\n\"all the looping for you, in exchange for being provided with callbacks \"\n\"that control the behaviour (notably a callback that enumerates the \"\n\"rectangles/pages to use).\"\nmsgstr \"대안으로 :ref:`DocumentWriter` 를 사용하는 경우 `write()` 또는 `write_stabilized()` 메서드를 사용할 수 있습니다. 이것들은 동작을 제어하는 콜백(특히 사용할 사각형/페이지를 열거하는 콜백)을 제공하는 대가로 모든 루프를 처리합니다.\"\n\n#: ../../story-class.rst:96 ee657bc17cb9479098b79a0775f10c3a\nmsgid \"\"\n\"Which part of the **story** will land on which rectangle / which page, is\"\n\" fully under control of the :ref:`Story` object and cannot be predicted.\"\nmsgstr \"**스토리** 의 어느 부분이 어떤 사각형/어떤 페이지에 배치될지는 :ref:`Story` 객체의 완전한 제어 하에 있으며 예측할 수 없습니다.\"\n\n#: ../../story-class.rst:98 2373c29f02c449119f61da189826bc09\nmsgid \"\"\n\"Images may be part of a **story**. They will be placed together with any \"\n\"surrounding text.\"\nmsgstr \"이미지는 **스토리** 의 일부일 수 있습니다. 주변 텍스트와 함께 배치됩니다.\"\n\n#: ../../story-class.rst:99 30316b2b832342268461f6c7d74a9197\nmsgid \"\"\n\"Multiple stories may - independently from each other - write to the same \"\n\"page. For example, one may have separate stories for page header, page \"\n\"footer, regular text, comment boxes, etc.\"\nmsgstr \"여러 스토리는 서로 독립적으로 같은 페이지에 쓸 수 있습니다. 예를 들어 페이지 헤더, 페이지 푸터, 일반 텍스트, 주석 상자 등에 대해 별도의 스토리를 가질 수 있습니다.\"\n\n#: ../../story-class.rst 3bc54fe727d84b0fb5ec6f5a505593d7\n#: 632479f010e74a7fa705e9873fc201e2 6bae93af6e1f4bcd9f975e3dbf237a8f\n#: 76b91680f9494dcda1b320b971f127f3 835ef3aac08946a7b21892dd5d446841\n#: 9faeb1de8c834831b2eefc6ba27d02c6 a7f1db20a98f4acd8ac3a50281de1d54\n#: b092aa952799492ab41859def37221e6 c431629c4269486e838a6416b26f8a06\n#: ecb562eb477f4178bbbac8624595e806\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../story-class.rst:103 7a7770ae27444f9cbae197749eec78ab\nmsgid \"\"\n\"HTML source code. If omitted, a basic minimum is generated (see below). \"\n\"If provided, not a complete HTML document is needed. The in-built source \"\n\"parser will forgive (many / most) HTML syntax errors and also accepts \"\n\"HTML fragments like `\\\"<b>Hello, <i>World!</i></b>\\\"`.\"\nmsgstr \"HTML 소스 코드. 생략하면 기본 최소값이 생성됩니다(아래 참조). 제공된 경우 완전한 HTML 문서가 필요하지 않습니다. 내장 소스 파서는 (많은/대부분의) HTML 구문 오류를 용서하며 `\\\"<b>Hello, <i>World!</i></b>\\\"` 와 같은 HTML 조각도 허용합니다.\"\n\n#: ../../story-class.rst:108 998745be0a874eeb8f4d73e3411eb0cc\nmsgid \"CSS source code. If provided, must contain valid CSS specifications.\"\nmsgstr \"CSS 소스 코드. 제공된 경우 유효한 CSS 사양을 포함해야 합니다.\"\n\n#: ../../story-class.rst:109 2bfac39f7a0745239025903a70202169\nmsgid \"the default text font size.\"\nmsgstr \"기본 텍스트 글꼴 크기.\"\n\n#: ../../story-class.rst:110 78219d1129fc40ab9949caef213ed7a5\nmsgid \"\"\n\"an :ref:`Archive` from which to load resources for rendering. Currently \"\n\"supported resource types are images and text fonts. If omitted, the story\"\n\" will not try to look up any such data and may thus produce incomplete \"\n\"output.  .. note:: Instead of an actual archive, valid arguments for \"\n\"**creating** an :ref:`Archive` can also be provided -- in which case an \"\n\"archive will temporarily be constructed. So, instead of `story = \"\n\"pymupdf.Story(archive=pymupdf.Archive(\\\"myfolder\\\"))`, one can also \"\n\"shorter write `story = pymupdf.Story(archive=\\\"myfolder\\\")`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:110 4050936d618a42da8eecf6ab4e063d8b\nmsgid \"\"\n\"an :ref:`Archive` from which to load resources for rendering. Currently \"\n\"supported resource types are images and text fonts. If omitted, the story\"\n\" will not try to look up any such data and may thus produce incomplete \"\n\"output.\"\nmsgstr \"렌더링을 위한 리소스를 로드할 :ref:`Archive`. 현재 지원되는 리소스 타입은 이미지와 텍스트 글꼴입니다. 생략하면 스토리는 이러한 데이터를 찾으려고 시도하지 않으므로 불완전한 출력을 생성할 수 있습니다.\"\n\n#: ../../story-class.rst:112 dbafa089e71b405c8505fe068f111435\nmsgid \"\"\n\"Instead of an actual archive, valid arguments for **creating** an \"\n\":ref:`Archive` can also be provided -- in which case an archive will \"\n\"temporarily be constructed. So, instead of `story = \"\n\"pymupdf.Story(archive=pymupdf.Archive(\\\"myfolder\\\"))`, one can also \"\n\"shorter write `story = pymupdf.Story(archive=\\\"myfolder\\\")`.\"\nmsgstr \"실제 아카이브 대신 :ref:`Archive` 를 **생성** 하기 위한 유효한 인수도 제공할 수 있습니다. 이 경우 아카이브가 임시로 구성됩니다. 따라서 `story = pymupdf.Story(archive=pymupdf.Archive(\\\"myfolder\\\"))` 대신 `story = pymupdf.Story(archive=\\\"myfolder\\\")` 로 더 짧게 쓸 수도 있습니다.\"\n\n#: ../../story-class.rst:116 38e199a574974c68a5789c3487298702\nmsgid \"\"\n\"Calculate that part of the story's content, that will fit in the provided\"\n\" rectangle. The method maintains a pointer which part of the story's \"\n\"content has already been written and upon the next invocation resumes \"\n\"from that pointer's position.\"\nmsgstr \"제공된 사각형에 맞는 스토리 콘텐츠의 일부를 계산합니다. 이 메서드는 스토리 콘텐츠의 어느 부분이 이미 쓰여졌는지에 대한 포인터를 유지하며, 다음 호출 시 해당 포인터 위치에서 재개합니다.\"\n\n#: ../../story-class.rst:118 9204c5de62594877a0b9554fe46dd00d\nmsgid \"\"\n\"layout the current part of the content to fit into this rectangle. This \"\n\"must be a sub-rectangle of the page's :ref:`MediaBox<Glossary_MediaBox>`.\"\nmsgstr \"콘텐츠의 현재 부분을 이 사각형에 맞도록 레이아웃합니다. 이것은 페이지의 :ref:`MediaBox<Glossary_MediaBox>` 의 하위 사각형이어야 합니다.\"\n\n#: ../../story-class.rst f63a283a6c88499ead37123b58293124\nmsgid \"Return type\"\nmsgstr \"반환 타입\"\n\n#: ../../story-class.rst 94bc5676fca747a28908e39b08f758dd\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../story-class.rst:121 cfc9d87ae2c0427fb812923a5380f63e\nmsgid \"\"\n\"a bool (int) `more` and a rectangle `filled`. If `more == 0`, all content\"\n\" of the story has been written, otherwise more is waiting to be written \"\n\"to subsequent rectangles / pages. Rectangle `filled` is the part of \"\n\"`where` that has actually been filled.\"\nmsgstr \"bool(int) `more` 와 사각형 `filled`. `more == 0` 이면 스토리의 모든 콘텐츠가 쓰여진 것이고, 그렇지 않으면 더 많은 콘텐츠가 후속 사각형/페이지에 쓰이기를 기다리고 있습니다. 사각형 `filled` 는 실제로 채워진 `where` 의 부분입니다.\"\n\n#: ../../story-class.rst:125 6813b9d6cf0a4992aac607d827be601c\nmsgid \"Write the content part prepared by :meth:`Story.place` to the page.\"\nmsgstr \":meth:`Story.place` 로 준비된 콘텐츠 부분을 페이지에 씁니다.\"\n\n#: ../../story-class.rst:127 883fc316b5194fbebc4f2e1002d07a4a\nmsgid \"\"\n\"the :ref:`Device` created by `dev = writer.begin_page(mediabox)`. The \"\n\"device knows how to call all MuPDF functions needed to write the content.\"\nmsgstr \"`dev = writer.begin_page(mediabox)` 로 생성된 :ref:`Device`. 장치는 콘텐츠를 쓰는 데 필요한 모든 MuPDF 함수를 호출하는 방법을 알고 있습니다.\"\n\n#: ../../story-class.rst:128 15d1012c1f36445b97b2245366f1fe29\nmsgid \"\"\n\"a matrix for transforming content when writing to the page. An example \"\n\"may be writing rotated text. The default means no transformation (i.e. \"\n\"the :ref:`Identity` matrix).\"\nmsgstr \"페이지에 쓸 때 콘텐츠를 변환하는 행렬. 예를 들어 회전된 텍스트를 쓰는 것입니다. 기본값은 변환 없음(즉, :ref:`Identity` 행렬)을 의미합니다.\"\n\n#: ../../story-class.rst:132 a4b6e0a215c74c77bc15ee4a585a753c\nmsgid \"\"\n\"Let the Story provide positioning information about certain HTML elements\"\n\" once their place on the current page has been computed - i.e. invoke \"\n\"this method **directly after** :meth:`Story.place`.\"\nmsgstr \"Story가 현재 페이지에서의 위치가 계산된 후 특정 HTML 요소에 대한 위치 정보를 제공하도록 합니다. 즉, :meth:`Story.place` **직후에** 이 메서드를 호출합니다.\"\n\n#: ../../story-class.rst:134 132b23607fe24fd4b386d921fa955b1f\nmsgid \"\"\n\"*Story* will pass position information to *function*. This information \"\n\"can for example be used to generate a Table of Contents.\"\nmsgstr \"*Story* 는 위치 정보를 *function* 에 전달합니다. 이 정보는 예를 들어 목차를 생성하는 데 사용할 수 있습니다.\"\n\n#: ../../story-class.rst:136 9b62cdc7c4734ce9bd97fd06ae689ced\nmsgid \"\"\n\"a Python function accepting an :class:`ElementPosition` object. It will \"\n\"be invoked by the Story object to process positioning information. The \"\n\"function **must** be a callable accepting exactly one argument.\"\nmsgstr \":class:`ElementPosition` 객체를 받는 Python 함수. Story 객체에 의해 호출되어 위치 정보를 처리합니다. 함수는 **반드시** 정확히 하나의 인수를 받는 호출 가능한 객체여야 합니다.\"\n\n#: ../../story-class.rst:137 95c635a4d01544919b451835ba7cfb5e\nmsgid \"\"\n\"an optional dictionary with any **additional** information that should be\"\n\" added to the :class:`ElementPosition` instance passed to `function`. \"\n\"Like for example the current output page number. Every key in this \"\n\"dictionary must be a string that conforms to the rules for a valid Python\"\n\" identifier. The complete set of information is explained below.\"\nmsgstr \"`function` 에 전달되는 :class:`ElementPosition` 인스턴스에 추가되어야 하는 **추가** 정보가 있는 선택적 딕셔너리. 예를 들어 현재 출력 페이지 번호입니다. 이 딕셔너리의 모든 키는 유효한 Python 식별자 규칙을 준수하는 문자열이어야 합니다. 전체 정보 세트는 아래에 설명되어 있습니다.\"\n\n#: ../../story-class.rst:146 d1a8ec5e26534fb08b5644c78bdd0f35\nmsgid \"Rewind the story's document to the beginning for starting over its output.\"\nmsgstr \"출력을 다시 시작하기 위해 스토리 문서를 시작 부분으로 되감습니다.\"\n\n#: ../../story-class.rst:150 99e9fa88415b44008dfa1a9212359a94\nmsgid \"\"\n\"The :htmlTag:`body` part of the story's DOM. This attribute contains the \"\n\":ref:`Xml` node of :htmlTag:`body`. All relevant content for PDF \"\n\"production is contained between \\\"<body>\\\" and \\\"</body>\\\".\"\nmsgstr \"스토리 DOM의 :htmlTag:`body` 부분. 이 속성은 :htmlTag:`body` 의 :ref:`Xml` 노드를 포함합니다. PDF 생성을 위한 모든 관련 콘텐츠는 \\\"<body>\\\" 와 \\\"</body>\\\" 사이에 포함됩니다.\"\n\n#: ../../story-class.rst:154 41b172bf34d0440fadc8322fad80b439\nmsgid \"\"\n\"Places and draws Story to a `DocumentWriter`. Avoids the need for calling\"\n\" code to implement a loop that calls `Story.place()` and `Story.draw()` \"\n\"etc, at the expense of having to provide at least the `rectfn()` \"\n\"callback.\"\nmsgstr \"Story를 `DocumentWriter` 에 배치하고 그립니다. `Story.place()` 및 `Story.draw()` 등을 호출하는 루프를 구현하는 호출 코드의 필요성을 피하지만, 최소한 `rectfn()` 콜백을 제공해야 합니다.\"\n\n#: ../../story-class.rst:159 f45d6bee9274444588f63a947cb04ff9\nmsgid \"a `DocumentWriter` or None.\"\nmsgstr \"`DocumentWriter` 또는 None.\"\n\n#: ../../story-class.rst:160 0a82dd0477cc4e6aba46d8bde1ff66cb\nmsgid \"\"\n\"a callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:  * mediabox: None or rect for new page. * rect: \"\n\"The next rect into which content should be placed. * ctm: None or a \"\n\"`Matrix`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:160 09db40fd97944cc3bdc056101682d345\nmsgid \"\"\n\"a callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:\"\nmsgstr \"`(rect_num: int, filled: Rect)` 를 받아 `(mediabox, rect, ctm)` 를 반환하는 호출 가능한 객체:\"\n\n#: ../../story-class.rst:163 ../../story-class.rst:204\n#: 195039e86a0a453b80a1947c0d982191 cc6afdff529d4b18bf96bab124b071b0\nmsgid \"mediabox: None or rect for new page.\"\nmsgstr \"mediabox: 새 페이지의 None 또는 rect.\"\n\n#: ../../story-class.rst:164 ../../story-class.rst:205\n#: 25c7020d98834950b5d94ff65444d7dd 66c0ba4ebccc4299ab74abd2a830ae53\nmsgid \"rect: The next rect into which content should be placed.\"\nmsgstr \"rect: 콘텐츠가 배치될 다음 rect.\"\n\n#: ../../story-class.rst:165 15dd25041536413eb3b45f6c0546d4c9\nmsgid \"ctm: None or a `Matrix`.\"\nmsgstr \"ctm: None 또는 `Matrix`.\"\n\n#: ../../story-class.rst:166 00bf180b2a0c4c8d85c03815119541f1\nmsgid \"\"\n\"None, or a callable taking `(position: ElementPosition)`:  * position:\"\n\"     An `ElementPosition` with an extra `.page_num` member. Typically \"\n\"called multiple times as we generate elements that are headings or have \"\n\"an id.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:166 25928f4a5c5f491488b15662e26bc608\nmsgid \"None, or a callable taking `(position: ElementPosition)`:\"\nmsgstr \"None 또는 `(position: ElementPosition)` 를 받는 호출 가능한 객체:\"\n\n#: ../../story-class.rst:168 2dd05e9f8b994f32855896af88fa138a\nmsgid \"position:\"\nmsgstr \"position:\"\n\n#: ../../story-class.rst:169 e39ff5907e3f417a840c59e64a0ce9d8\nmsgid \"An `ElementPosition` with an extra `.page_num` member.\"\nmsgstr \"추가 `.page_num` 멤버를 가진 `ElementPosition`.\"\n\n#: ../../story-class.rst:170 4892cafe0f7d41f0985e89860b77823a\nmsgid \"\"\n\"Typically called multiple times as we generate elements that are headings\"\n\" or have an id.\"\nmsgstr \"일반적으로 제목이거나 id를 가진 요소를 생성할 때 여러 번 호출됩니다.\"\n\n#: ../../story-class.rst:172 3fa53b922faa4eda8ba2cba1ac636ca9\nmsgid \"\"\n\"None, or a callable taking `(page_num, mediabox, dev, after)`; called at \"\n\"start (`after=0`) and end (`after=1`) of each page.\"\nmsgstr \"None 또는 `(page_num, mediabox, dev, after)` 를 받는 호출 가능한 객체. 각 페이지의 시작(`after=0`)과 끝(`after=1`)에서 호출됩니다.\"\n\n#: ../../story-class.rst:178 dd5221f0ed8740b9870aee56024e5b7b\nmsgid \"\"\n\"Static method that does iterative layout of html content to a \"\n\"`DocumentWriter`.\"\nmsgstr \"HTML 콘텐츠를 `DocumentWriter` 에 반복 레이아웃하는 정적 메서드.\"\n\n#: ../../story-class.rst:181 30078c22673b4583b6668ac47bc366ff\nmsgid \"\"\n\"For example this allows one to add a table of contents section while \"\n\"ensuring that page numbers are patched up until stable.\"\nmsgstr \"예를 들어 이것은 페이지 번호가 안정될 때까지 패치되도록 하면서 목차 섹션을 추가할 수 있게 합니다.\"\n\n#: ../../story-class.rst:184 c06d6f0e11c445a79282ea1b2b0ad535\nmsgid \"\"\n\"Repeatedly creates a new `Story` from `(contentfn(), user_css, em, \"\n\"archive)` and lays it out with internal call to `Story.write()`; uses a \"\n\"None writer and extracts the list of `ElementPosition`'s which is passed \"\n\"to the next call of `contentfn()`.\"\nmsgstr \"`(contentfn(), user_css, em, archive)` 로부터 새 `Story` 를 반복적으로 생성하고 `Story.write()` 내부 호출로 레이아웃합니다. None writer를 사용하고 `ElementPosition` 목록을 추출하여 `contentfn()` 의 다음 호출에 전달합니다.\"\n\n#: ../../story-class.rst:190 44779b3ded2c4ee6874e7b1ae2bff004\nmsgid \"\"\n\"When the html from `contentfn()` becomes unchanged, we do a final \"\n\"iteration using `writer`.\"\nmsgstr \"`contentfn()` 의 HTML이 변경되지 않으면 `writer` 를 사용하여 최종 반복을 수행합니다.\"\n\n#: ../../story-class.rst:193 0f2c4d433e064304a49d4bd0a6ebfe73\nmsgid \"A `DocumentWriter`.\"\nmsgstr \"`DocumentWriter`.\"\n\n#: ../../story-class.rst:195 368d195d03b147fc837acd54849c93e0\nmsgid \"\"\n\"A function taking a list of `ElementPositions` and returning a string \"\n\"containing html. The returned html can depend on the list of positions, \"\n\"for example with a table of contents near the start.\"\nmsgstr \"`ElementPositions` 목록을 받아 HTML을 포함하는 문자열을 반환하는 함수. 반환된 HTML은 위치 목록에 따라 달라질 수 있습니다. 예를 들어 시작 부분 근처에 목차가 있습니다.\"\n\n#: ../../story-class.rst:200 1cf1064d178a4eb5abc44f35d1b26213\nmsgid \"\"\n\"A callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:  * mediabox: None or rect for new page. * rect: \"\n\"The next rect into which content should be placed. * ctm: A `Matrix`.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:201 9c7835ef50c04228a8a373880c57f7ec\nmsgid \"\"\n\"A callable taking `(rect_num: int, filled: Rect)` and returning \"\n\"`(mediabox, rect, ctm)`:\"\nmsgstr \"`(rect_num: int, filled: Rect)` 를 받아 `(mediabox, rect, ctm)` 를 반환하는 호출 가능한 객체:\"\n\n#: ../../story-class.rst:206 ee9f39495b5e42c8abe6db31752b059c\nmsgid \"ctm: A `Matrix`.\"\nmsgstr \"ctm: `Matrix`.\"\n\n#: ../../story-class.rst:207 0e5bb33450b440519eaa4678352a268d\nmsgid \"\"\n\"None, or a callable taking `(page_num, medibox, dev, after)`; called at \"\n\"start (`after=0`) and end (`after=1`) of each page.\"\nmsgstr \"None 또는 `(page_num, medibox, dev, after)` 를 받는 호출 가능한 객체. 각 페이지의 시작(`after=0`)과 끝(`after=1`)에서 호출됩니다.\"\n\n#: ../../story-class.rst:212 1e4fd7df55fb49df898e449e0f6cc1d4\nmsgid \"\"\n\"If true, we add unique ids to all header tags that don't already have an \"\n\"id. This can help automatic generation of tables of contents.\"\nmsgstr \"true이면 id가 아직 없는 모든 헤더 태그에 고유 id를 추가합니다. 이것은 목차의 자동 생성에 도움이 될 수 있습니다.\"\n\n#: ../../story-class.rst:216 5855dd1c0eb74ba680d81ec3bd7ab855\nmsgid \"Returns:\"\nmsgstr \"반환값:\"\n\n#: ../../story-class.rst:217 b8d9d14cc3f7420cbfcb12cdd3784c27\nmsgid \"None.\"\nmsgstr \"None.\"\n\n#: ../../story-class.rst:221 22ec8dffec4842c2b36b31e44c148e9b\nmsgid \"\"\n\"Similar to `write()` except that we don't have a `writer` arg and we \"\n\"return a PDF `Document` in which links have been created for each \"\n\"internal html link.\"\nmsgstr \"`write()` 와 유사하지만 `writer` 인수가 없고 각 내부 HTML 링크에 대해 링크가 생성된 PDF `Document` 를 반환합니다.\"\n\n#: ../../story-class.rst:227 cb292a6045f4454589078e45beb372b8\nmsgid \"\"\n\"Similar to `write_stabilized()` except that we don't have a `writer` arg \"\n\"and instead return a PDF `Document` in which links have been created for \"\n\"each internal html link.\"\nmsgstr \"`write_stabilized()` 와 유사하지만 `writer` 인수가 없고 대신 각 내부 HTML 링크에 대해 링크가 생성된 PDF `Document` 를 반환합니다.\"\n\n#: ../../story-class.rst:233 79e6df9feb764d49bb6c4880d7985f6e\nmsgid \"The result from a `Story.fit*()` method.\"\nmsgstr \"`Story.fit*()` 메서드의 결과.\"\n\n#: ../../story-class.rst:235 2a76b4161e5f46ca816faca601040d90\nmsgid \"Members:\"\nmsgstr \"멤버:\"\n\n#: ../../story-class.rst:237 035ed3847947402d887364c7d5c447e9\nmsgid \"`big_enough`:\"\nmsgstr \"`big_enough`:\"\n\n#: ../../story-class.rst:238 bf717872d31642deaf8eb1605a3012a6\nmsgid \"`True` if the fit succeeded.\"\nmsgstr \"적합이 성공하면 `True`.\"\n\n#: ../../story-class.rst:239 7320376b01af4fa9a8fa3ae295bbda83\nmsgid \"`filled`:\"\nmsgstr \"`filled`:\"\n\n#: ../../story-class.rst:240 17cc4e2057bd41cc8e2633814392b385\nmsgid \"From the last call to `Story.place()`.\"\nmsgstr \"`Story.place()` 에 대한 마지막 호출에서.\"\n\n#: ../../story-class.rst:241 e24cc834373e411587bbb7bfa0414333\nmsgid \"`more`:\"\nmsgstr \"`more`:\"\n\n#: ../../story-class.rst:242 4a3e937b059041a7b3a20e0d429f503c\nmsgid \"`False` if the fit succeeded.\"\nmsgstr \"적합이 성공하면 `False`.\"\n\n#: ../../story-class.rst:243 bbbe1925cdb245ad87cc43c74cf72b73\nmsgid \"`numcalls`:\"\nmsgstr \"`numcalls`:\"\n\n#: ../../story-class.rst:244 9e3bcaa3dbf8478a98ff6e4241532bb6\nmsgid \"Number of calls made to `self.place()`.\"\nmsgstr \"`self.place()` 에 대한 호출 횟수.\"\n\n#: ../../story-class.rst:245 169f3c8877c640d8aa7fb28ee47ab520\nmsgid \"`parameter`:\"\nmsgstr \"`parameter`:\"\n\n#: ../../story-class.rst:246 985d429bb06144c6bcfa903f4c388ebf\nmsgid \"The successful parameter value, or the largest failing value.\"\nmsgstr \"성공한 매개변수 값 또는 가장 큰 실패 값.\"\n\n#: ../../story-class.rst:247 42a31d9fef9248d9a8d194383c59191d\nmsgid \"`rect`:\"\nmsgstr \"`rect`:\"\n\n#: ../../story-class.rst:248 902774936ea0439f89fd8ff5b6dfc8e4\nmsgid \"The rect created from `parameter`.\"\nmsgstr \"`parameter` 로부터 생성된 rect.\"\n\n#: ../../story-class.rst:254 ../../story-class.rst:282\n#: ../../story-class.rst:304 ../../story-class.rst:325\n#: 696c11bfa76d489093846a7c247a4851 853a35b41b0d4e92a0abce39320b0d0b\n#: 8e63b26bcbe146e994f59d0598d8ae81 f109c3abb97c461c90ef5083439ae6b7\nmsgid \"Returns a `Story.FitResult` instance.\"\nmsgstr \"`Story.FitResult` 인스턴스를 반환합니다.\"\n\n#: ../../story-class.rst:256 18ef28643cd147a3a66b0e495f27b656\nmsgid \"\"\n\"On success, the last call to `self.place()` will have been with the \"\n\"returned rectangle, so `self.draw()` can be used directly.\"\nmsgstr \"성공 시 `self.place()` 에 대한 마지막 호출은 반환된 사각형으로 수행되므로 `self.draw()` 를 직접 사용할 수 있습니다.\"\n\n#: ../../story-class.rst:259 fcc258b789cf4618a282896268872c2f\nmsgid \"\"\n\"A callable taking a floating point `parameter` and returning a \"\n\"`pymupdf.Rect()`. If the rect is empty, we assume the story will not fit \"\n\"and do not call `self.place()`.  Must guarantee that `self.place()` \"\n\"behaves monotonically when given rect `fn(parameter`) as `parameter` \"\n\"increases. This usually means that both width and height increase or stay\"\n\" unchanged as `parameter` increases.\"\nmsgstr \"\"\n\n#: ../../story-class.rst:260 c6955c50c2ba4885973d0c3f04c0e2c5\nmsgid \"\"\n\"A callable taking a floating point `parameter` and returning a \"\n\"`pymupdf.Rect()`. If the rect is empty, we assume the story will not fit \"\n\"and do not call `self.place()`.\"\nmsgstr \"부동 소수점 `parameter` 를 받아 `pymupdf.Rect()` 를 반환하는 호출 가능한 객체. rect가 비어 있으면 스토리가 맞지 않는다고 가정하고 `self.place()` 를 호출하지 않습니다.\"\n\n#: ../../story-class.rst:264 d7e59ae0c80245ab9c009b98fd8b45c0\nmsgid \"\"\n\"Must guarantee that `self.place()` behaves monotonically when given rect \"\n\"`fn(parameter`) as `parameter` increases. This usually means that both \"\n\"width and height increase or stay unchanged as `parameter` increases.\"\nmsgstr \"`parameter` 가 증가할 때 rect `fn(parameter`)가 주어지면 `self.place()` 가 단조롭게 동작하도록 보장해야 합니다. 이것은 일반적으로 `parameter` 가 증가할 때 너비와 높이가 모두 증가하거나 변경되지 않음을 의미합니다.\"\n\n#: ../../story-class.rst:268 11dc2ac2cfa948f9b5a1f9820e2552e5\nmsgid \"Minimum parameter to consider; `None` for -infinity.\"\nmsgstr \"고려할 최소 매개변수. `None` 이면 -무한대.\"\n\n#: ../../story-class.rst:270 318cf2242b354dcfaf2261319967a6e2\nmsgid \"Maximum parameter to consider; `None` for +infinity.\"\nmsgstr \"고려할 최대 매개변수. `None` 이면 +무한대.\"\n\n#: ../../story-class.rst:272 c04b8320d63941998719b704f3829f97\nmsgid \"Maximum error in returned `parameter`.\"\nmsgstr \"반환된 `parameter` 의 최대 오류.\"\n\n#: ../../story-class.rst:274 ../../story-class.rst:295\n#: ../../story-class.rst:317 ../../story-class.rst:338\n#: 04ed040f1f414b7c8386ffe687178265 470693ef9de2469a8028547ee1f19ddd\n#: 8b4b77e4979541f0a4121fe75de9674d aed40072033645edb4aa0fbcdb14816f\nmsgid \"If true we output diagnostics.\"\nmsgstr \"true이면 진단 정보를 출력합니다.\"\n\n#: ../../story-class.rst:279 44286dc4a32a44f390cb28a04e6cf752\nmsgid \"\"\n\"Finds smallest value `scale` in range `scale_min..scale_max` where `scale\"\n\" * rect` is large enough to contain the story `self`.\"\nmsgstr \"`scale * rect` 가 스토리 `self` 를 포함할 수 있을 만큼 큰 `scale_min..scale_max` 범위에서 가장 작은 값 `scale` 을 찾습니다.\"\n\n#: ../../story-class.rst:284 ../../story-class.rst:306\n#: bc70968d12674cddba38101f99cb1fbd fdda159f6afc401ebac759335fb3dfec\nmsgid \"width of rect.\"\nmsgstr \"rect의 너비.\"\n\n#: ../../story-class.rst:286 ../../story-class.rst:327\n#: 3ee0663bbd3d4788b49acf35a5a11b7e b17196b122de4057b9427222b9a3e7f4\nmsgid \"height of rect.\"\nmsgstr \"rect의 높이.\"\n\n#: ../../story-class.rst:288 198e10d6fd8b4243a6c9e1051223c22e\nmsgid \"Minimum scale to consider; must be >= 0.\"\nmsgstr \"고려할 최소 스케일. >= 0 이어야 합니다.\"\n\n#: ../../story-class.rst:290 8fb7f93b830e4d5bb7de7c76d7c7e540\nmsgid \"Maximum scale to consider, must be >= scale_min or `None` for infinite.\"\nmsgstr \"고려할 최대 스케일. >= scale_min 이어야 하거나 무한대의 경우 `None`.\"\n\n#: ../../story-class.rst:293 f423b2cdc42a427f978455fb05d8b7df\nmsgid \"Maximum error in returned scale.\"\nmsgstr \"반환된 스케일의 최대 오류.\"\n\n#: ../../story-class.rst:300 9dc7b774a8d94c71b557ecfbb9976265\nmsgid \"\"\n\"Finds smallest height in range `height_min..height_max` where a rect with\"\n\" size `(width, height)` is large enough to contain the story `self`.\"\nmsgstr \"크기 `(width, height)` 의 rect가 스토리 `self` 를 포함할 수 있을 만큼 큰 `height_min..height_max` 범위에서 가장 작은 높이를 찾습니다.\"\n\n#: ../../story-class.rst:308 85ff87d9747942168779a4df514ba339\nmsgid \"Minimum height to consider; must be >= 0.\"\nmsgstr \"고려할 최소 높이. >= 0 이어야 합니다.\"\n\n#: ../../story-class.rst:310 912d526c91f243f18cb6395c816ca9bc\nmsgid \"Maximum height to consider, must be >= height_min or `None` for infinite.\"\nmsgstr \"고려할 최대 높이. >= height_min 이어야 하거나 무한대의 경우 `None`.\"\n\n#: ../../story-class.rst:313 ../../story-class.rst:334\n#: c1f7875eb4ae4239a6376368ebf24647 c7cca120f409456097470b299bdfb49a\nmsgid \"`(x0, y0)` of rect.\"\nmsgstr \"rect의 `(x0, y0)`.\"\n\n#: ../../story-class.rst:315 f67d83462abe4bbcaff9a80b51a5978f\nmsgid \"Maximum error in returned height.\"\nmsgstr \"반환된 높이의 최대 오류.\"\n\n#: ../../story-class.rst:322 acf77aa0831f4a0386314816cc6f06aa\nmsgid \"\"\n\"Finds smallest width in range `width_min..width_max` where a rect with \"\n\"size `(width, height)` is large enough to contain the story `self`.\"\nmsgstr \"크기 `(width, height)` 의 rect가 스토리 `self` 를 포함할 수 있을 만큼 큰 `width_min..width_max` 범위에서 가장 작은 너비를 찾습니다.\"\n\n#: ../../story-class.rst:329 9bd900ad77c545e490768485d91fc7c8\nmsgid \"Minimum width to consider; must be >= 0.\"\nmsgstr \"고려할 최소 너비. >= 0 이어야 합니다.\"\n\n#: ../../story-class.rst:331 ff7c27444b38461aa0606500f65534c2\nmsgid \"Maximum width to consider, must be >= width_min or `None` for infinite.\"\nmsgstr \"고려할 최대 너비. >= width_min 이어야 하거나 무한대의 경우 `None`.\"\n\n#: ../../story-class.rst:336 0b2941234085492388b7df6476fba23f\nmsgid \"Maximum error in returned width.\"\nmsgstr \"반환된 너비의 최대 오류.\"\n\n#: ../../story-class.rst:343 b1ca57aa343940a18c8a31095aa158c9\nmsgid \"Element Positioning CallBack function\"\nmsgstr \"요소 위치 지정 콜백 함수\"\n\n#: ../../story-class.rst:345 091fadf161344745a01b68eb9c135c89\nmsgid \"\"\n\"The callback function can be used to log information about story output. \"\n\"The function's access to the information is read-only: it has no way to \"\n\"influence the story's output.\"\nmsgstr \"콜백 함수는 스토리 출력에 대한 정보를 로깅하는 데 사용할 수 있습니다. 함수의 정보 액세스는 읽기 전용입니다. 스토리 출력에 영향을 줄 수 있는 방법이 없습니다.\"\n\n#: ../../story-class.rst:347 6228d7d0c75448809d16fd4e876f667e\nmsgid \"\"\n\"A typical loop for executing a story with using this method would look \"\n\"like this::\"\nmsgstr \"이 메서드를 사용하여 스토리를 실행하는 일반적인 루프는 다음과 같습니다::\"\n\n#: ../../story-class.rst:379 ae147d021aa143be82a1e049deb89061\nmsgid \"Attributes of the ElementPosition class\"\nmsgstr \"ElementPosition 클래스의 속성\"\n\n#: ../../story-class.rst:380 c1fbd0b7565542d1b95f8c57a58016bd\nmsgid \"\"\n\"Exactly one parameter must be passed to the function provided by \"\n\":meth:`Story.element_positions`. It is an object with the following \"\n\"attributes:\"\nmsgstr \":meth:`Story.element_positions` 에 의해 제공되는 함수에는 정확히 하나의 매개변수가 전달되어야 합니다. 다음 속성을 가진 객체입니다:\"\n\n#: ../../story-class.rst:382 db748bf0d1de49da994057c0c9813003\nmsgid \"\"\n\"The parameter passed to the `recorder` function is an object with the \"\n\"following attributes:\"\nmsgstr \"`recorder` 함수에 전달되는 매개변수는 다음 속성을 가진 객체입니다:\"\n\n#: ../../story-class.rst:384 332f4d6df2e849cda1fb558f9f1bc52e\nmsgid \"`elpos.depth` (int) -- depth of this element in the box structure.\"\nmsgstr \"`elpos.depth` (int) -- 박스 구조에서 이 요소의 깊이.\"\n\n#: ../../story-class.rst:386 43ebf06ffd544102857d5d1e63b02e5e\nmsgid \"\"\n\"`elpos.heading` (int) -- the header level, 0 if no header, 1-6 for \"\n\":htmlTag:`h1` - :htmlTag:`h6`.\"\nmsgstr \"`elpos.heading` (int) -- 헤더 레벨, 헤더가 없으면 0, :htmlTag:`h1` - :htmlTag:`h6` 의 경우 1-6.\"\n\n#: ../../story-class.rst:388 fd08004f2ef1497584d8af90ce1c5a41\nmsgid \"\"\n\"`elpos.href` (str) -- value of the `href` attribute, or None if not \"\n\"defined.\"\nmsgstr \"`elpos.href` (str) -- `href` 속성의 값, 정의되지 않았으면 None.\"\n\n#: ../../story-class.rst:390 d75122312d1142dc8e2d75061746ee48\nmsgid \"`elpos.id` (str) -- value of the `id` attribute, or None if not defined.\"\nmsgstr \"`elpos.id` (str) -- `id` 속성의 값, 정의되지 않았으면 None.\"\n\n#: ../../story-class.rst:392 f0d4a253cad54310a3c431f54e394f96\nmsgid \"`elpos.rect` (tuple) -- element position on page.\"\nmsgstr \"`elpos.rect` (tuple) -- 페이지에서의 요소 위치.\"\n\n#: ../../story-class.rst:394 a66c52c844ca4388889b38841925a406\nmsgid \"`elpos.text` (str) -- immediate text of the element.\"\nmsgstr \"`elpos.text` (str) -- 요소의 직접 텍스트.\"\n\n#: ../../story-class.rst:396 bed702a812984188bb16fc3565c6d75a\nmsgid \"\"\n\"`elpos.open_close` (int bit field) -- bit 0 set: opens element, bit 1 \"\n\"set: closes element. Relevant for elements that may contain other \"\n\"elements and thus may not immediately be closed after being created / \"\n\"opened.\"\nmsgstr \"`elpos.open_close` (int 비트 필드) -- 비트 0 설정: 요소 열기, 비트 1 설정: 요소 닫기. 다른 요소를 포함할 수 있어 생성/열린 후 즉시 닫히지 않을 수 있는 요소와 관련됩니다.\"\n\n#: ../../story-class.rst:398 9c020d958f7e41739d4c89fc24c82271\nmsgid \"`elpos.rect_num` (int) -- count of rectangles filled by the story so far.\"\nmsgstr \"`elpos.rect_num` (int) -- 지금까지 스토리로 채워진 사각형의 개수.\"\n\n#: ../../story-class.rst:400 64579e878d5a4437b0267944543f75dc\nmsgid \"\"\n\"`elpos.page_num` (int) -- page number; only present when using \"\n\"`pymupdf.Story.write*()` functions.\"\nmsgstr \"`elpos.page_num` (int) -- 페이지 번호. `pymupdf.Story.write*()` 함수를 사용할 때만 존재합니다.\"\n\n#: ../../footer.rst:46 a8171a5060434652be4eadd0eef0baa1\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/supported-files-table.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/textpage.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 a689d6f014ae4b3e996f4ea1430fd7e2\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 fcaf663acdd64264ba54a9b09a7a053d\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 2384969b3a1a48ecb481ced21413e4ab\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../textpage.rst:7 b50883dcbbd2424db737f428b4204dc7\nmsgid \"TextPage\"\nmsgstr \"TextPage\"\n\n#: ../../textpage.rst:9 6e81bba1ccf7481d8fc21ba0651cd715\nmsgid \"\"\n\"This class represents text and images shown on a document page. All \"\n\":ref:`MuPDF document types<Supported_File_Types>` are supported.\"\nmsgstr \"이 클래스는 문서 페이지에 표시된 텍스트와 이미지를 나타냅니다. 모든 :ref:`MuPDF 문서 타입<Supported_File_Types>` 이 지원됩니다.\"\n\n#: ../../textpage.rst:11 214a6f0b55b94183bb1a4fee5b003e96\nmsgid \"\"\n\"The usual ways to create a textpage are :meth:`DisplayList.get_textpage` \"\n\"and :meth:`Page.get_textpage`. Because there is a limited set of methods \"\n\"in this class, there exist wrappers in :ref:`Page` which are handier to \"\n\"use. The last column of this table shows these corresponding :ref:`Page` \"\n\"methods.\"\nmsgstr \"텍스트 페이지를 생성하는 일반적인 방법은 :meth:`DisplayList.get_textpage` 와 :meth:`Page.get_textpage` 입니다. 이 클래스의 메서드 세트가 제한적이므로, 더 편리하게 사용할 수 있는 :ref:`Page` 에 래퍼가 존재합니다. 이 테이블의 마지막 열은 이러한 해당 :ref:`Page` 메서드를 보여줍니다.\"\n\n#: ../../textpage.rst:13 8974c23cb16b4aa1b56189eff275c6fe\nmsgid \"For a description of what this class is all about, see Appendix 2.\"\nmsgstr \"이 클래스에 대한 설명은 부록 2를 참조하세요.\"\n\n#: ../../textpage.rst:16 a2ef271a41f24f089f82cb6c12de5544\nmsgid \"**Method**\"\nmsgstr \"**메서드**\"\n\n#: ../../textpage.rst:16 5b00ef707e3f4637b40a48d5d422e544\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../textpage.rst:16 c508a7963cbb4c77ab691615841f72fb\nmsgid \"page get_text or search method\"\nmsgstr \"페이지 get_text 또는 search 메서드\"\n\n#: ../../textpage.rst:18 24790f911d6d4af491f3f0d4a90c5e4e\nmsgid \":meth:`~.extractText`\"\nmsgstr \":meth:`~.extractText`\"\n\n#: ../../textpage.rst:18 56f3e18347124df290f5bb60a9c6ab6f\nmsgid \"extract plain text\"\nmsgstr \"일반 텍스트 추출\"\n\n#: ../../textpage.rst:18 ../../textpage.rst:19 292888a082e041b8820ab5b47243fa82\n#: 587fc832f8b941329c209fc49dd67b0b\nmsgid \"\\\"text\\\"\"\nmsgstr \"\\\"text\\\"\"\n\n#: ../../textpage.rst:19 062786889a8a4ad586cea1bcbfa2bb0d\nmsgid \":meth:`~.extractTEXT`\"\nmsgstr \":meth:`~.extractTEXT`\"\n\n#: ../../textpage.rst:19 e0b7b72c38c746a4b7c512c66b738f1c\nmsgid \"synonym of previous\"\nmsgstr \"이전의 동의어\"\n\n#: ../../textpage.rst:20 98ed5aa1b9884de7858b147ee2bd2f0c\nmsgid \":meth:`~.extractBLOCKS`\"\nmsgstr \":meth:`~.extractBLOCKS`\"\n\n#: ../../textpage.rst:20 35f208a1af3c4c5c8f17069788e702ca\nmsgid \"plain text grouped in blocks\"\nmsgstr \"블록으로 그룹화된 일반 텍스트\"\n\n#: ../../textpage.rst:20 6318f67c8f964981b4a354142092e102\nmsgid \"\\\"blocks\\\"\"\nmsgstr \"\\\"blocks\\\"\"\n\n#: ../../textpage.rst:21 07a1408ddaf24b158ac6dc5d9fcc8115\nmsgid \":meth:`~.extractWORDS`\"\nmsgstr \":meth:`~.extractWORDS`\"\n\n#: ../../textpage.rst:21 52e0458f76ee4231a07829bb051b29ac\nmsgid \"all words with their bbox\"\nmsgstr \"바운딩 박스를 포함한 모든 단어\"\n\n#: ../../textpage.rst:21 2efe7bf211e74dc4a731d81393a6e10c\nmsgid \"\\\"words\\\"\"\nmsgstr \"\\\"words\\\"\"\n\n#: ../../textpage.rst:22 7c9da76988c243e0b79a0f2a5c23cee7\nmsgid \":meth:`~.extractHTML`\"\nmsgstr \":meth:`~.extractHTML`\"\n\n#: ../../textpage.rst:22 269dcb92057443e096b0cd366dd7ba29\nmsgid \"page content in HTML format\"\nmsgstr \"HTML 형식의 페이지 콘텐츠\"\n\n#: ../../textpage.rst:22 d24ee0e44d5c45e59f125aacaccf3465\nmsgid \"\\\"html\\\"\"\nmsgstr \"\\\"html\\\"\"\n\n#: ../../textpage.rst:23 388abf5016ba455c959cdd56009a4499\nmsgid \":meth:`~.extractXHTML`\"\nmsgstr \":meth:`~.extractXHTML`\"\n\n#: ../../textpage.rst:23 b09f5acedceb4611bc7ea51121eb9bb2\nmsgid \"page content in XHTML format\"\nmsgstr \"XHTML 형식의 페이지 콘텐츠\"\n\n#: ../../textpage.rst:23 416a7019408e492da02693ffd6949a7a\nmsgid \"\\\"xhtml\\\"\"\nmsgstr \"\\\"xhtml\\\"\"\n\n#: ../../textpage.rst:24 ee85d9810eff41caa760d9ffb2a4fed2\nmsgid \":meth:`~.extractXML`\"\nmsgstr \":meth:`~.extractXML`\"\n\n#: ../../textpage.rst:24 8ab1b023d2cc42b6ae74cb3b92b8d797\nmsgid \"page text in XML format\"\nmsgstr \"XML 형식의 페이지 텍스트\"\n\n#: ../../textpage.rst:24 fd3d4026c2c045b6a5dc724cd3c1cd16\nmsgid \"\\\"xml\\\"\"\nmsgstr \"\\\"xml\\\"\"\n\n#: ../../textpage.rst:25 a0d67d42d20d483ba2dc7c60232c4262\nmsgid \":meth:`~.extractDICT`\"\nmsgstr \":meth:`~.extractDICT`\"\n\n#: ../../textpage.rst:25 ../../textpage.rst:27 1867105a7ef841cd809711e47e335c93\n#: 8cfc8dba8d384e489e2948bcbd7adaca\nmsgid \"page content in *dict* format\"\nmsgstr \"*dict* 형식의 페이지 콘텐츠\"\n\n#: ../../textpage.rst:25 8159466e656146a38f47f43f6bdcb810\nmsgid \"\\\"dict\\\"\"\nmsgstr \"\\\"dict\\\"\"\n\n#: ../../textpage.rst:26 1d75b88f1edb442898ea8017de3492d7\nmsgid \":meth:`~.extractJSON`\"\nmsgstr \":meth:`~.extractJSON`\"\n\n#: ../../textpage.rst:26 ../../textpage.rst:28 7480fba67d534ecc8956acf7902d5aed\n#: 82d01a9dbb1d488198ecd836fed442ff\nmsgid \"page content in JSON format\"\nmsgstr \"JSON 형식의 페이지 콘텐츠\"\n\n#: ../../textpage.rst:26 78d2d0b851b240db8420aa1f8c823676\nmsgid \"\\\"json\\\"\"\nmsgstr \"\\\"json\\\"\"\n\n#: ../../textpage.rst:27 1ade4b09c9674544bb58977574f5d593\nmsgid \":meth:`~.extractRAWDICT`\"\nmsgstr \":meth:`~.extractRAWDICT`\"\n\n#: ../../textpage.rst:27 3155e2902bcd4713aa47e4919ec46081\nmsgid \"\\\"rawdict\\\"\"\nmsgstr \"\\\"rawdict\\\"\"\n\n#: ../../textpage.rst:28 b5f0e031790f497694abb5caa6eee204\nmsgid \":meth:`~.extractRAWJSON`\"\nmsgstr \":meth:`~.extractRAWJSON`\"\n\n#: ../../textpage.rst:28 9b7e2e49823242bf83ea6a25986488d0\nmsgid \"\\\"rawjson\\\"\"\nmsgstr \"\\\"rawjson\\\"\"\n\n#: ../../textpage.rst:29 c2c9458e9c4a490087a519b61ecc5b19\nmsgid \":meth:`~.search`\"\nmsgstr \":meth:`~.search`\"\n\n#: ../../textpage.rst:29 ee8c8a71aa524335969fbb8af60b211e\nmsgid \"Search for a string in the page\"\nmsgstr \"페이지에서 문자열 검색\"\n\n#: ../../textpage.rst:29 f79465ca7ff14a0a80fc365911c70bf6\nmsgid \":meth:`Page.search_for`\"\nmsgstr \":meth:`Page.search_for`\"\n\n#: ../../textpage.rst:32 083eef252c154937ae0bc85aa81aff68\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../textpage.rst:40 f33111b086ad4d72980c782edd305dd0\nmsgid \"\"\n\"Return a string of the page's complete text. The text is UTF-8 unicode \"\n\"and in the same sequence as specified at the time of document creation.\"\nmsgstr \"페이지의 전체 텍스트 문자열을 반환합니다. 텍스트는 UTF-8 유니코드이며 문서 생성 시 지정된 순서와 동일합니다.\"\n\n#: ../../textpage.rst 3e9d1669f2fe4f15ab3177563f0420e3\n#: 4bd4b9fa21ed426188fe213d2241f4ac 720def9977a743fdb77d7caeb93f8e63\n#: aea747bd7d624e70bc7def00d62df838 ca24753a6b21474daba199227cbdb7cd\n#: d0072bc05d7144aca56767bfde82c6a9 e1647eb182054d70be24b2cc9c6381ca\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../textpage.rst:42 ../../textpage.rst:85 ../../textpage.rst:93\n#: ../../textpage.rst:113 ../../textpage.rst:121\n#: 053cd209c0cd44b08367efe95d323dcb 2e3408186db64af29672df98a2541c3a\n#: 88f4b7d0b3014f8ab6a88c7157c764d9 eafc202f0101431bbd82bb8f066f24c2\n#: f7da0622405347bcb10099abdba152a3\nmsgid \"\"\n\"(new in v1.19.1) sort the output by vertical, then horizontal \"\n\"coordinates. In many cases, this should suffice to generate a \\\"natural\\\"\"\n\" reading order.\"\nmsgstr \"(v1.19.1에서 새로 추가됨) 출력을 수직 좌표, 그 다음 수평 좌표로 정렬합니다. 많은 경우 이것으로 \\\"자연스러운\\\" 읽기 순서를 생성할 수 있습니다.\"\n\n#: ../../textpage.rst 07f5f0a7fa5f4efbb1093cd496e1425a\n#: 0f27872a10dd46fda6c8e7ecaf77c92b 34621dc4778249c49fbd4c5f8fd2fd39\n#: 4c8745e920b8430fadff84a8e977a147 5081234f6b32451d915cc94583c1d60e\n#: 9a9a5268dcfc421cb4ca9b69e5030ee1 9f3241fa28914e49a481723379042cd8\n#: c0b2e445162446e1b4a2e0eb834ac7ca f3b8d685f26e44edbe5e23bac745020d\n#: f63537f76faf47c884089748bdcbcd8b f8803c61a6fc41fe89a08237112d6d49\nmsgid \"Return type\"\nmsgstr \"반환 타입\"\n\n#: ../../textpage.rst:49 63307d556a584ea19173a54596c7f880\nmsgid \"\"\n\"Textpage content as a list of text lines grouped by block. Each list \"\n\"items looks like this::\"\nmsgstr \"블록별로 그룹화된 텍스트 줄 목록으로 된 텍스트 페이지 콘텐츠. 각 목록 항목은 다음과 같습니다::\"\n\n#: ../../textpage.rst:53 78718be495234f9dbfa93e48e16d1e13\nmsgid \"\"\n\"The first four entries are the block's bbox coordinates, *block_type* is \"\n\"1 for an image block, 0 for text. *block_no* is the block sequence \"\n\"number. Multiple text lines are joined via line breaks.\"\nmsgstr \"처음 네 개 항목은 블록의 bbox 좌표이며, *block_type* 은 이미지 블록의 경우 1, 텍스트의 경우 0입니다. *block_no* 는 블록 시퀀스 번호입니다. 여러 텍스트 줄은 줄바꿈으로 연결됩니다.\"\n\n#: ../../textpage.rst:55 12f402e2e12346f8b7dd871f590f3197\nmsgid \"\"\n\"For an image block, its bbox and a text line with some image meta \"\n\"information is included -- **not the image content**.\"\nmsgstr \"이미지 블록의 경우 bbox와 일부 이미지 메타 정보가 포함된 텍스트 줄이 포함됩니다. **이미지 콘텐츠는 포함되지 않습니다**.\"\n\n#: ../../textpage.rst:57 fb2f6c324124423bb74dbd2e4b974806\nmsgid \"\"\n\"This is a high-speed method with just enough information to output plain \"\n\"text in desired reading sequence.\"\nmsgstr \"원하는 읽기 순서로 일반 텍스트를 출력하기에 충분한 정보를 제공하는 고속 메서드입니다.\"\n\n#: ../../textpage.rst:63 cfb05f044359435fb061d158cb6ef21e\nmsgid \"Changed in v1.23.5: added `delimiters` parameter\"\nmsgstr \"v1.23.5에서 변경됨: `delimiters` 매개변수 추가\"\n\n#: ../../textpage.rst:65 e3116b1baa374ce2b67b6002aaae107d\nmsgid \"\"\n\"Textpage content as a list of single words with bbox information. An item\"\n\" of this list looks like this::\"\nmsgstr \"bbox 정보가 있는 단일 단어 목록으로 된 텍스트 페이지 콘텐츠. 이 목록의 항목은 다음과 같습니다::\"\n\n#: ../../textpage.rst:69 6f56fac0469e45afa313a96110815e53\nmsgid \"\"\n\"(new in v1.23.5) use these characters as *additional* word separators. By\"\n\" default, all white spaces (including the non-breaking space `0xA0`) \"\n\"indicate start and end of a word. Now you can specify more characters \"\n\"causing this. For instance, the default will return \"\n\"`\\\"john.doe@outlook.com\\\"` as **one** word. If you specify \"\n\"`delimiters=\\\"@.\\\"` then the **four** words `\\\"john\\\"`, `\\\"doe\\\"`, \"\n\"`\\\"outlook\\\"`, `\\\"com\\\"` will be returned. Other possible uses include \"\n\"ignoring punctuation characters `delimiters=string.punctuation`. The \"\n\"\\\"word\\\" strings will not contain any delimiting character.\"\nmsgstr \"(v1.23.5에서 새로 추가됨) 이러한 문자를 *추가* 단어 구분자로 사용합니다. 기본적으로 모든 공백(줄바꿈 없는 공백 `0xA0` 포함)은 단어의 시작과 끝을 나타냅니다. 이제 이를 유발하는 더 많은 문자를 지정할 수 있습니다. 예를 들어 기본값은 `\\\"john.doe@outlook.com\\\"` 을 **하나의** 단어로 반환합니다. `delimiters=\\\"@.\\\"` 를 지정하면 **네 개의** 단어 `\\\"john\\\"`, `\\\"doe\\\"`, `\\\"outlook\\\"`, `\\\"com\\\"` 이 반환됩니다. 다른 가능한 용도로는 구두점 문자 무시 `delimiters=string.punctuation` 가 있습니다. \\\"word\\\" 문자열에는 구분 문자가 포함되지 않습니다.\"\n\n#: ../../textpage.rst:71 f122cb9dbcfb43fb8cd911d4aabb4817\nmsgid \"\"\n\"This is a high-speed method which e.g. allows extracting text from within\"\n\" given areas or recovering the text reading sequence.\"\nmsgstr \"이것은 예를 들어 주어진 영역 내에서 텍스트를 추출하거나 텍스트 읽기 순서를 복구할 수 있게 하는 고속 메서드입니다.\"\n\n#: ../../textpage.rst:77 9fd59d1b4ce240e7ab72d24d4bfe0b1d\nmsgid \"\"\n\"Textpage content as a string in HTML format. This version contains \"\n\"complete formatting and positioning information. Images are included \"\n\"(encoded as base64 strings). You need an HTML package to interpret the \"\n\"output in Python. Your internet browser should be able to adequately \"\n\"display this information, but see :ref:`HTMLQuality`.\"\nmsgstr \"HTML 형식의 문자열로 된 텍스트 페이지 콘텐츠. 이 버전은 완전한 서식 및 위치 정보를 포함합니다. 이미지가 포함됩니다(base64 문자열로 인코딩됨). Python에서 출력을 해석하려면 HTML 패키지가 필요합니다. 인터넷 브라우저가 이 정보를 적절히 표시할 수 있어야 하지만 :ref:`HTMLQuality` 를 참조하세요.\"\n\n#: ../../textpage.rst:83 a07e225c4bf3412585128a2fb86b8200\nmsgid \"\"\n\"Textpage content as a Python dictionary. Provides same information detail\"\n\" as HTML. See below for the structure.\"\nmsgstr \"Python 딕셔너리로 된 텍스트 페이지 콘텐츠. HTML과 동일한 정보 세부 사항을 제공합니다. 구조는 아래를 참조하세요.\"\n\n#: ../../textpage.rst:91 3c7dcaacfe924c9ab076958b43f75600\nmsgid \"\"\n\"Textpage content as a JSON string. Created by \"\n\"`json.dumps(TextPage.extractDICT())`. It is included for backlevel \"\n\"compatibility. You will probably use this method ever only for outputting\"\n\" the result to some file. The  method detects binary image data and \"\n\"converts them to base64 encoded strings.\"\nmsgstr \"JSON 문자열로 된 텍스트 페이지 콘텐츠. `json.dumps(TextPage.extractDICT())` 로 생성됩니다. 하위 호환성을 위해 포함되었습니다. 이 메서드는 아마도 결과를 파일로 출력하는 용도로만 사용할 것입니다. 이 메서드는 바이너리 이미지 데이터를 감지하고 base64 인코딩된 문자열로 변환합니다.\"\n\n#: ../../textpage.rst:99 87f36a88ced6410383dcdafa2979eae5\nmsgid \"\"\n\"Textpage content as a string in XHTML format. Text information detail is \"\n\"comparable with :meth:`extractTEXT`, but also contains images (base64 \"\n\"encoded). This method makes no attempt to re-create the original visual \"\n\"appearance.\"\nmsgstr \"XHTML 형식의 문자열로 된 텍스트 페이지 콘텐츠. 텍스트 정보 세부 사항은 :meth:`extractTEXT` 와 유사하지만 이미지도 포함합니다(base64 인코딩됨). 이 메서드는 원본 시각적 모양을 재현하려고 시도하지 않습니다.\"\n\n#: ../../textpage.rst:105 ce4a584473674c4e91533c25a532fe15\nmsgid \"\"\n\"Textpage content as a string in XML format. This contains complete \"\n\"formatting information about every single character on the page: font, \"\n\"size, line, paragraph, location, color, etc. Contains no images. You need\"\n\" an XML package to interpret the output in Python.\"\nmsgstr \"XML 형식의 문자열로 된 텍스트 페이지 콘텐츠. 이것은 페이지의 모든 단일 문자에 대한 완전한 서식 정보를 포함합니다: 글꼴, 크기, 줄, 단락, 위치, 색상 등. 이미지는 포함되지 않습니다. Python에서 출력을 해석하려면 XML 패키지가 필요합니다.\"\n\n#: ../../textpage.rst:111 53dc5f5e5cc04c54a952877ba4755541\nmsgid \"\"\n\"Textpage content as a Python dictionary -- technically similar to \"\n\":meth:`extractDICT`, and it contains that information as a subset \"\n\"(including any images). It provides additional detail down to each \"\n\"character, which makes using XML obsolete in many cases. See below for \"\n\"the structure.\"\nmsgstr \"Python 딕셔너리로 된 텍스트 페이지 콘텐츠. 기술적으로 :meth:`extractDICT` 와 유사하며, 해당 정보를 하위 집합으로 포함합니다(이미지 포함). 각 문자까지 추가 세부 정보를 제공하므로 많은 경우 XML 사용을 불필요하게 만듭니다. 구조는 아래를 참조하세요.\"\n\n#: ../../textpage.rst:119 33863035deb9499b8feb6d00b3064acb\nmsgid \"\"\n\"Textpage content as a JSON string. Created by \"\n\"`json.dumps(TextPage.extractRAWDICT())`. You will probably use this \"\n\"method ever only for outputting the result to some file. The  method \"\n\"detects binary image data and converts them to base64 encoded strings.\"\nmsgstr \"JSON 문자열로 된 텍스트 페이지 콘텐츠. `json.dumps(TextPage.extractRAWDICT())` 로 생성됩니다. 이 메서드는 아마도 결과를 파일로 출력하는 용도로만 사용할 것입니다. 이 메서드는 바이너리 이미지 데이터를 감지하고 base64 인코딩된 문자열로 변환합니다.\"\n\n#: ../../textpage.rst:127 209053b84b6545e3994a163287facefa\nmsgid \"Changed in v1.18.2\"\nmsgstr \"v1.18.2에서 변경됨\"\n\n#: ../../textpage.rst:129 05ffbacb61c7489882f082b48886e8d5\nmsgid \"Search for *string* and return a list of found locations.\"\nmsgstr \"*string* 을 검색하고 찾은 위치 목록을 반환합니다.\"\n\n#: ../../textpage.rst:131 c71683b946f54d84aff575da2005613b\nmsgid \"\"\n\"the string to search for. Upper and lower cases will all match if needle \"\n\"consists of ASCII letters only -- it does not yet work for \\\"Ä\\\" versus \"\n\"\\\"ä\\\", etc.\"\nmsgstr \"검색할 문자열. needle이 ASCII 문자로만 구성된 경우 대소문자가 모두 일치합니다. \\\"Ä\\\" 와 \\\"ä\\\" 등에는 아직 작동하지 않습니다.\"\n\n#: ../../textpage.rst:132 0f1af98486ec43429066d8c48e3dc958\nmsgid \"return quadrilaterals instead of rectangles.\"\nmsgstr \"사각형 대신 사각형을 반환합니다.\"\n\n#: ../../textpage.rst 943e3f54b51f470ba6d34411ccdabcd3\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../textpage.rst:134 89e19eb80ccd4b318611f268b0f75d7e\nmsgid \"\"\n\"a list of :ref:`Rect` or :ref:`Quad` objects, each surrounding a found \"\n\"*needle* occurrence. As the search string may contain spaces, its parts \"\n\"may be found on different lines. In this case, more than one rectangle \"\n\"(resp. quadrilateral) are returned. **(Changed in v1.18.2)** The method \"\n\"**now supports dehyphenation**, so it will find e.g. \\\"method\\\", even if \"\n\"it was hyphenated in two parts \\\"meth-\\\" and \\\"od\\\" across two lines. The\"\n\" two returned rectangles will contain \\\"meth\\\" (no hyphen) and \\\"od\\\".\"\nmsgstr \":ref:`Rect` 또는 :ref:`Quad` 객체 목록으로, 각각 찾은 *needle* 발생을 둘러쌉니다. 검색 문자열에 공백이 포함될 수 있으므로 해당 부분이 다른 줄에서 발견될 수 있습니다. 이 경우 둘 이상의 사각형(또는 사각형)이 반환됩니다. **(v1.18.2에서 변경됨)** 이 메서드는 **이제 하이픈 제거를 지원** 하므로 두 줄에 걸쳐 \\\"meth-\\\" 와 \\\"od\\\" 로 하이픈 처리된 경우에도 예를 들어 \\\"method\\\" 를 찾을 수 있습니다. 반환된 두 사각형에는 \\\"meth\\\" (하이픈 없음)와 \\\"od\\\" 가 포함됩니다.\"\n\n#: ../../textpage.rst:136 c134a9fb178648ae8bab433d54e37e2b\nmsgid \"**Overview of changes in v1.18.2:**\"\nmsgstr \"**v1.18.2의 변경 사항 개요:**\"\n\n#: ../../textpage.rst:138 d9a3438955224e5685de548903667d74\nmsgid \"The `hit_max` parameter has been removed: all hits are always returned.\"\nmsgstr \"`hit_max` 매개변수가 제거되었습니다. 모든 히트가 항상 반환됩니다.\"\n\n#: ../../textpage.rst:139 c687c9305d954f6eaea257e2fe5bbe58\nmsgid \"\"\n\"The `rect` parameter of the :ref:`TextPage` is now respected: only text \"\n\"inside this area is examined. Only characters with fully contained bboxes\"\n\" are considered. The wrapper method :meth:`Page.search_for` \"\n\"correspondingly supports a *clip* parameter.\"\nmsgstr \":ref:`TextPage` 의 `rect` 매개변수가 이제 존중됩니다. 이 영역 내의 텍스트만 검사됩니다. 완전히 포함된 bbox를 가진 문자만 고려됩니다. 래퍼 메서드 :meth:`Page.search_for` 는 이에 따라 *clip* 매개변수를 지원합니다.\"\n\n#: ../../textpage.rst:140 ec9e270e430341a88939c174a0e838a3\nmsgid \"**Hyphenated words** are now found.\"\nmsgstr \"**하이픈 처리된 단어** 가 이제 찾아집니다.\"\n\n#: ../../textpage.rst:141 595b14cd29774ef49fd1666b1d37dbb7\nmsgid \"\"\n\"**Overlapping rectangles** in the same line are now automatically joined.\"\n\" We assume that such separations are an artifact created by multiple \"\n\"marked content groups, containing parts of the same search needle.\"\nmsgstr \"같은 줄의 **겹치는 사각형** 이 이제 자동으로 결합됩니다. 이러한 분리는 동일한 검색 needle의 일부를 포함하는 여러 표시된 콘텐츠 그룹에 의해 생성된 아티팩트라고 가정합니다.\"\n\n#: ../../textpage.rst:143 7b283f04f24544e18dc95d6f698f1a39\nmsgid \"\"\n\"Example Quad versus Rect: when searching for needle \\\"pymupdf\\\", then the\"\n\" corresponding entry will either be the blue rectangle, or, if *quads* \"\n\"was specified, the quad *Quad(ul, ur, ll, lr)*.\"\nmsgstr \"Quad 대 Rect 예시: needle \\\"pymupdf\\\" 를 검색할 때 해당 항목은 파란색 사각형이 되거나, *quads* 가 지정된 경우 사각형 *Quad(ul, ur, ll, lr)* 가 됩니다.\"\n\n#: ../../textpage.rst:149 22015cb6553240db9caee4c5d4d0a06b\nmsgid \"\"\n\"The rectangle associated with the text page. This either equals the \"\n\"rectangle of the creating page or the `clip` parameter of \"\n\":meth:`Page.get_textpage` and text extraction / searching methods.\"\nmsgstr \"텍스트 페이지와 연결된 사각형. 이것은 생성 페이지의 사각형이거나 :meth:`Page.get_textpage` 및 텍스트 추출/검색 메서드의 `clip` 매개변수와 같습니다.\"\n\n#: ../../textpage.rst:151 e4d7797e393d49f38a2ad6066b720a21\nmsgid \"\"\n\"The output of text searching and most text extractions **is restricted to\"\n\" this rectangle**. (X)HTML and XML output will however always extract the\"\n\" full page.\"\nmsgstr \"텍스트 검색 및 대부분의 텍스트 추출 출력은 **이 사각형으로 제한됩니다**. 그러나 (X)HTML 및 XML 출력은 항상 전체 페이지를 추출합니다.\"\n\n#: ../../textpage.rst:156 746d4f0331d74f5eb4b706ab194b8b02\nmsgid \"Structure of Dictionary Outputs\"\nmsgstr \"딕셔너리 출력 구조\"\n\n#: ../../textpage.rst:157 ae8559712aa84a3b8f3abc14fba42605\nmsgid \"\"\n\"Methods :meth:`TextPage.extractDICT`, :meth:`TextPage.extractJSON`, \"\n\":meth:`TextPage.extractRAWDICT`, and :meth:`TextPage.extractRAWJSON` \"\n\"return dictionaries, containing the page's text and image content. The \"\n\"dictionary structures of all four methods are almost equal. They strive \"\n\"to map the text page's information hierarchy of blocks, lines, spans and \"\n\"characters as precisely as possible, by representing each of these by its\"\n\" own sub-dictionary:\"\nmsgstr \":meth:`TextPage.extractDICT`, :meth:`TextPage.extractJSON`, :meth:`TextPage.extractRAWDICT`, :meth:`TextPage.extractRAWJSON` 메서드는 페이지의 텍스트 및 이미지 콘텐츠를 포함하는 딕셔너리를 반환합니다. 네 가지 메서드의 딕셔너리 구조는 거의 동일합니다. 각각을 자체 하위 딕셔너리로 표현하여 텍스트 페이지의 블록, 줄, 범위 및 문자 정보 계층을 가능한 한 정확하게 매핑합니다:\"\n\n#: ../../textpage.rst:159 1fc549b40ec54504aba36b49e614c7cc\nmsgid \"A **page** consists of a list of **block dictionaries**.\"\nmsgstr \"**페이지** 는 **블록 딕셔너리** 목록으로 구성됩니다.\"\n\n#: ../../textpage.rst:160 531deb445eda49c78ee0170f577f2f93\nmsgid \"A (text) **block** consists of a list of **line dictionaries**.\"\nmsgstr \"(텍스트) **블록** 은 **줄 딕셔너리** 목록으로 구성됩니다.\"\n\n#: ../../textpage.rst:161 5d0d26a55df64fb0bc4619f73f865415\nmsgid \"A **line** consists of a list of **span dictionaries**.\"\nmsgstr \"**줄** 은 **범위 딕셔너리** 목록으로 구성됩니다.\"\n\n#: ../../textpage.rst:162 d297bff2aae540828c971d533f6fe3bb\nmsgid \"\"\n\"A **span** either consists of the text itself or, for the RAW variants, a\"\n\" list of **character dictionaries**.\"\nmsgstr \"**범위** 는 텍스트 자체로 구성되거나 RAW 변형의 경우 **문자 딕셔너리** 목록으로 구성됩니다.\"\n\n#: ../../textpage.rst:163 37000c1f71684c77a812407e7849a0e0\nmsgid \"\"\n\"RAW variants: a **character** is a dictionary of its origin, bbox and \"\n\"unicode.\"\nmsgstr \"RAW 변형: **문자** 는 원본, bbox 및 유니코드의 딕셔너리입니다.\"\n\n#: ../../textpage.rst:165 192df2422b5e482bbb29f7afc93e8cdc\nmsgid \"\"\n\"All PyMuPDF geometry objects herein (points, rectangles, matrices) are \"\n\"represented by there **\\\"like\\\"** formats: a :data:`rect_like` *tuple* is\"\n\" used instead of a :ref:`Rect`, etc. The reasons for this are performance\"\n\" and memory considerations:\"\nmsgstr \"여기에 포함된 모든 |PyMuPDF| 기하 객체(점, 사각형, 행렬)는 **\\\"like\\\"** 형식으로 표현됩니다: :ref:`Rect` 대신 :data:`rect_like` *tuple* 이 사용됩니다. 그 이유는 성능 및 메모리 고려 사항입니다:\"\n\n#: ../../textpage.rst:167 517e734e4772478cb6b1bc32cab2ab16\nmsgid \"\"\n\"This code is written in C, where Python tuples can easily be generated. \"\n\"The geometry objects on the other hand are defined in Python source only.\"\n\" A conversion of each Python tuple into its corresponding geometry object\"\n\" would add significant -- and largely unnecessary -- execution time.\"\nmsgstr \"이 코드는 C로 작성되었으며, Python 튜플을 쉽게 생성할 수 있습니다. 반면 기하 객체는 Python 소스에만 정의되어 있습니다. 각 Python 튜플을 해당 기하 객체로 변환하면 상당한 실행 시간이 추가됩니다(대부분 불필요함).\"\n\n#: ../../textpage.rst:168 a7f4b55b2bb84753bc138ab3a04c2f8a\nmsgid \"\"\n\"A 4-tuple needs about 168 bytes, the corresponding :ref:`Rect` 472 bytes \"\n\"- almost three times the size. A \\\"dict\\\" dictionary for a text-heavy \"\n\"page contains 300+ bbox objects -- which thus require about 50 KB storage\"\n\" as 4-tuples versus 140 KB as :ref:`Rect` objects. A \\\"rawdict\\\" output \"\n\"for such a page will however contain **4 to 5 thousand** bboxes, so in \"\n\"this case we talk about 750 KB versus 2 MB.\"\nmsgstr \"4-tuple은 약 168바이트가 필요하고, 해당 :ref:`Rect` 는 472바이트입니다. 거의 3배 크기입니다. 텍스트가 많은 페이지의 \\\"dict\\\" 딕셔너리에는 300개 이상의 bbox 객체가 포함되어 있습니다. 따라서 4-tuple로 약 50KB, :ref:`Rect` 객체로 140KB의 저장 공간이 필요합니다. 그러나 이러한 페이지의 \\\"rawdict\\\" 출력에는 **4천~5천 개** 의 bbox가 포함되므로, 이 경우 750KB 대 2MB를 말하는 것입니다.\"\n\n#: ../../textpage.rst:170 bbdd6aa883a447c5b6bbb24a389b7944\nmsgid \"\"\n\"Please also note, that only **bboxes** (= :data:`rect_like` 4-tuples) are\"\n\" returned, whereas a :ref:`TextPage` actually has the **full position \"\n\"information** -- in :ref:`Quad` format. The reason for this decision is \"\n\"again a memory consideration: a :data:`quad_like` needs 488 bytes (3 \"\n\"times the size of a :data:`rect_like`). Given the mentioned amounts of \"\n\"generated bboxes, returning :data:`quad_like` information would have a \"\n\"significant impact.\"\nmsgstr \"또한 **bboxes** (= :data:`rect_like` 4-tuple)만 반환되지만, :ref:`TextPage` 는 실제로 **전체 위치 정보** 를 가지고 있습니다. :ref:`Quad` 형식입니다. 이 결정의 이유는 다시 메모리 고려 사항입니다: :data:`quad_like` 는 488바이트(:data:`rect_like` 크기의 3배)가 필요합니다. 생성된 bbox의 양을 고려하면 :data:`quad_like` 정보를 반환하면 상당한 영향을 미칩니다.\"\n\n#: ../../textpage.rst:172 d2d5ce2b47bc4940b491f08fbbaa0027\nmsgid \"\"\n\"In the vast majority of cases, we are dealing with **horizontal text \"\n\"only**, where bboxes provide entirely sufficient information.\"\nmsgstr \"대부분의 경우 **수평 텍스트만** 다루며, bbox가 완전히 충분한 정보를 제공합니다.\"\n\n#: ../../textpage.rst:174 feb1b497d7a04358ac4fc4f59750eb21\nmsgid \"\"\n\"In addition, **the full quad information is not lost**: it can be \"\n\"recovered as needed for lines, spans, and characters by using the \"\n\"appropriate function from the following list:\"\nmsgstr \"또한 **전체 quad 정보는 손실되지 않습니다**: 다음 목록의 적절한 함수를 사용하여 줄, 범위 및 문자에 대해 필요에 따라 복구할 수 있습니다:\"\n\n#: ../../textpage.rst:176 e89548afd6dc44168e0b77628a3cba31\nmsgid \":meth:`recover_quad` -- the quad of a complete span\"\nmsgstr \":meth:`recover_quad` -- 전체 범위의 quad\"\n\n#: ../../textpage.rst:177 27d71bee525843278a01adf552fa7a36\nmsgid \":meth:`recover_span_quad` -- the quad of a character subset of a span\"\nmsgstr \":meth:`recover_span_quad` -- 범위의 문자 하위 집합의 quad\"\n\n#: ../../textpage.rst:178 041a2862fe3d48ac95055a9328f85989\nmsgid \":meth:`recover_line_quad` -- the quad of a line\"\nmsgstr \":meth:`recover_line_quad` -- 줄의 quad\"\n\n#: ../../textpage.rst:179 66ae40921c104d34aba6daaf7127f04f\nmsgid \":meth:`recover_char_quad` -- the quad of a character\"\nmsgstr \":meth:`recover_char_quad` -- 문자의 quad\"\n\n#: ../../textpage.rst:181 727a2901b16c4ddd96ae14b244c5424a\nmsgid \"\"\n\"As mentioned, using these functions is ever only needed, if the text is \"\n\"**not written horizontally** -- `line[\\\"dir\\\"] != (1, 0)` -- and you need\"\n\" the quad for text marker annotations (:meth:`Page.add_highlight_annot` \"\n\"and friends).\"\nmsgstr \"언급한 대로, 이러한 함수 사용은 텍스트가 **수평으로 작성되지 않은** 경우(`line[\\\"dir\\\"] != (1, 0)`)에만 필요하며, 텍스트 마커 주석(:meth:`Page.add_highlight_annot` 등)에 quad가 필요한 경우입니다.\"\n\n#: ../../textpage.rst:191 7805ac6076c748d18288314bba88341d\nmsgid \"Page Dictionary\"\nmsgstr \"페이지 딕셔너리\"\n\n#: ../../textpage.rst:194 ../../textpage.rst:208 ../../textpage.rst:251\n#: ../../textpage.rst:263 ../../textpage.rst:285 ../../textpage.rst:369\n#: 29f9782130d642a8b2fddc4dfd20716c 70f3d2461fad4b3fadb0fc3afaea9f2e\n#: 975906fdd1184ad3ad3fd3d27e4993b0 baf341562d684245aa92ddd993c2dd48\n#: bf7900e8b9b5405a8f0d4d83a8bf0411 c6778ca210f143f38e1b9841a02401e9\nmsgid \"**Key**\"\nmsgstr \"**키**\"\n\n#: ../../textpage.rst:194 ../../textpage.rst:208 ../../textpage.rst:251\n#: ../../textpage.rst:263 ../../textpage.rst:285 ../../textpage.rst:369\n#: 264a4f1acc10474eb5e78fe3b5e5823b b4b639c47a4a414db8f8f3bb50ee8dc9\n#: cc9c466c5ba84957921e1ff86a57d116 d94353036c5b40c1846dd829e554f27f\n#: f0dc2d1c0f2f41dea26d6f56aa6b3a26 fe805e2ac2f84c418cdee9f01871d787\nmsgid \"**Value**\"\nmsgstr \"**값**\"\n\n#: ../../textpage.rst:196 ../../textpage.rst:214\n#: 07aa10194d0d48eb97c6202f508f7705 8f326282fbe8407aa66c61b1d8bcd062\nmsgid \"width\"\nmsgstr \"width\"\n\n#: ../../textpage.rst:196 f244c49149a243688a1885d014c7a1bb\nmsgid \"width of the `clip` rectangle *(float)*\"\nmsgstr \"`clip` 사각형의 너비 *(float)*\"\n\n#: ../../textpage.rst:197 ../../textpage.rst:215\n#: b8882d43fa804c8a9c251b3ec47cef6d bcccca2b99b94b7ea01f4de3b4b7c85a\nmsgid \"height\"\nmsgstr \"height\"\n\n#: ../../textpage.rst:197 3100ead6fa2e45f5b61d6969928e4877\nmsgid \"height of the `clip` rectangle *(float)*\"\nmsgstr \"`clip` 사각형의 높이 *(float)*\"\n\n#: ../../textpage.rst:198 c5935e75747b42e799fe04c7f318b0da\nmsgid \"blocks\"\nmsgstr \"blocks\"\n\n#: ../../textpage.rst:198 30ab779a07894b089542bb81604f9b47\nmsgid \"*list* of block dictionaries\"\nmsgstr \"블록 딕셔너리의 *list*\"\n\n#: ../../textpage.rst:202 db462c15f35c46f5b52a233a3beed4d0\nmsgid \"Block Dictionaries\"\nmsgstr \"블록 딕셔너리\"\n\n#: ../../textpage.rst:203 952d964d7a5e43c2848616b970e2716c\nmsgid \"\"\n\"Block dictionaries come in two different formats for **image blocks** and\"\n\" for **text blocks**.\"\nmsgstr \"블록 딕셔너리는 **이미지 블록** 과 **텍스트 블록** 에 대해 두 가지 다른 형식으로 제공됩니다.\"\n\n#: ../../textpage.rst:205 238f68f9676441f1bdcff950557a856e\nmsgid \"**Image block:**\"\nmsgstr \"**이미지 블록:**\"\n\n#: ../../textpage.rst:210 ../../textpage.rst:253\n#: 800a3c27effc460f9480726ec3a5c729 d35d41a494c04f6285bda0eace697528\nmsgid \"type\"\nmsgstr \"type\"\n\n#: ../../textpage.rst:210 6328d3cec703451097bfaa7cf7f6c65f\nmsgid \"1 = image (``int``)\"\nmsgstr \"1 = 이미지 (``int``)\"\n\n#: ../../textpage.rst:211 ../../textpage.rst:254 ../../textpage.rst:265\n#: ../../textpage.rst:287 ../../textpage.rst:372\n#: 13e6c3dfe54549b9b050cea92d99d01a 322f2d6f5b2b44ed9706ad2f98ad459c\n#: 4f766fcb9538433a8d4db8a39a80ff3c bc56648f4c414b1eb1faa55dba01ab98\n#: db0fdf56b2254240a588914bece3c707\nmsgid \"bbox\"\nmsgstr \"bbox\"\n\n#: ../../textpage.rst:211 ff4d18f9a8d24d16a31d552e95f6e589\nmsgid \"image bbox on page (:data:`rect_like`)\"\nmsgstr \"페이지의 이미지 bbox (:data:`rect_like`)\"\n\n#: ../../textpage.rst:212 ../../textpage.rst:255\n#: 4c56479091544270885701e21d3794c0 5d311b7030c74d77b291641b825cabc0\nmsgid \"number\"\nmsgstr \"number\"\n\n#: ../../textpage.rst:212 044f427c89414858935273b873628617\nmsgid \"block count (``int``)\"\nmsgstr \"블록 개수 (``int``)\"\n\n#: ../../textpage.rst:213 d457db3dffd648f5b421b9dabda513e8\nmsgid \"ext\"\nmsgstr \"ext\"\n\n#: ../../textpage.rst:213 9a1b2497c15747ccae408e2908b03716\nmsgid \"image type (``str``), as file extension, see below\"\nmsgstr \"이미지 타입 (``str``), 파일 확장자로, 아래 참조\"\n\n#: ../../textpage.rst:214 65917d8aff0a47ae97e1c880700ae5b9\nmsgid \"original image width (``int``)\"\nmsgstr \"원본 이미지 너비 (``int``)\"\n\n#: ../../textpage.rst:215 ef1b2983b8484b67aea4e7c52ec94c5e\nmsgid \"original image height (``int``)\"\nmsgstr \"원본 이미지 높이 (``int``)\"\n\n#: ../../textpage.rst:216 cdbc1a0fe83a45878f7d57c8195c2541\nmsgid \"colorspace\"\nmsgstr \"colorspace\"\n\n#: ../../textpage.rst:216 0768d9dd62e74b518365212bb8f2d509\nmsgid \"colorspace component count (``int``)\"\nmsgstr \"색 공간 구성 요소 개수 (``int``)\"\n\n#: ../../textpage.rst:217 c72ef151fd0843acbf96ee02c0b50384\nmsgid \"xres\"\nmsgstr \"xres\"\n\n#: ../../textpage.rst:217 2b798798946e43259c410f01235ab8cf\nmsgid \"resolution in x-direction (``int``) [#f3]_\"\nmsgstr \"x 방향 해상도 (``int``) [#f3]_\"\n\n#: ../../textpage.rst:218 711945f5b34049a1b07317557513f490\nmsgid \"yres\"\nmsgstr \"yres\"\n\n#: ../../textpage.rst:218 91a31d61290640b8988418d1a9ebb3ba\nmsgid \"resolution in y-direction (``int``) [#f3]_\"\nmsgstr \"y 방향 해상도 (``int``) [#f3]_\"\n\n#: ../../textpage.rst:219 c247c45f267c4a6281d20687be8c99af\nmsgid \"bpc\"\nmsgstr \"bpc\"\n\n#: ../../textpage.rst:219 8934e38405664f3fa8f78d65d3a6dba5\nmsgid \"bits per component (``int``)\"\nmsgstr \"구성 요소당 비트 수 (``int``)\"\n\n#: ../../textpage.rst:220 2db498cd52714dd8b5097aa444b17ac0\nmsgid \"transform\"\nmsgstr \"transform\"\n\n#: ../../textpage.rst:220 c07a01fdd4744863a7e7b665d9066376\nmsgid \"matrix transforming image rect to bbox (:data:`matrix_like`)\"\nmsgstr \"이미지 rect를 bbox로 변환하는 행렬 (:data:`matrix_like`)\"\n\n#: ../../textpage.rst:221 ../../textpage.rst:292\n#: 416da7dc62f34728a5e65a5b6eccec10 e5bfbe8873ce4531a1a93eea31b542ab\nmsgid \"size\"\nmsgstr \"size\"\n\n#: ../../textpage.rst:221 ef114c513c0140809c273a1fca277935\nmsgid \"size of the image in bytes (``int``)\"\nmsgstr \"바이트 단위의 이미지 크기 (``int``)\"\n\n#: ../../textpage.rst:222 b4442e7378f340ad9bbc40a5bda85f94\nmsgid \"image\"\nmsgstr \"image\"\n\n#: ../../textpage.rst:222 44de8974cd434bbca7c4dea100e9987f\nmsgid \"image content (``bytes``)\"\nmsgstr \"이미지 콘텐츠 (``bytes``)\"\n\n#: ../../textpage.rst:223 ce697bda1a494d35a92a1a9b886f4a53\nmsgid \"mask\"\nmsgstr \"mask\"\n\n#: ../../textpage.rst:223 203d79f1d981499da21d8cae601cef42\nmsgid \"image mask content (``bytes``) for transparent images\"\nmsgstr \"투명 이미지의 이미지 마스크 콘텐츠 (``bytes``)\"\n\n#: ../../textpage.rst:226 7b2748f1df1342538dd7b750dd6db1db\nmsgid \"\"\n\"Possible values of the \\\"ext\\\" key are \\\"bmp\\\", \\\"gif\\\", \\\"jpeg\\\", \"\n\"\\\"jpx\\\" (JPEG 2000), \\\"jxr\\\" (JPEG XR), \\\"png\\\", \\\"pnm\\\", and \\\"tiff\\\".\"\nmsgstr \"\\\"ext\\\" 키의 가능한 값은 \\\"bmp\\\", \\\"gif\\\", \\\"jpeg\\\", \\\"jpx\\\" (JPEG 2000), \\\"jxr\\\" (JPEG XR), \\\"png\\\", \\\"pnm\\\", \\\"tiff\\\" 입니다.\"\n\n#: ../../textpage.rst:230 f165771e95ce4de587ef46d0281ce182\nmsgid \"\"\n\"An image block is generated for **all and every image occurrence** on the\"\n\" page. Hence there may be duplicates, if an image is shown at different \"\n\"locations.\"\nmsgstr \"페이지의 **모든 이미지 발생** 에 대해 이미지 블록이 생성됩니다. 따라서 이미지가 다른 위치에 표시되면 중복이 있을 수 있습니다.\"\n\n#: ../../textpage.rst:232 34122c8c572a45d7a4acfd1f2cbbbe55\nmsgid \"\"\n\":ref:`TextPage` and corresponding method :meth:`Page.get_text` are \"\n\"**available for all document types**. Only for PDF documents, methods \"\n\":meth:`Document.get_page_images` / :meth:`Page.get_images` offer some \"\n\"overlapping functionality as far as image lists are concerned. But both \"\n\"lists **may or may not** contain the same items. Any differences are most\"\n\" probably caused by one of the following:\"\nmsgstr \":ref:`TextPage` 및 해당 메서드 :meth:`Page.get_text` 는 **모든 문서 타입에 사용 가능합니다**. PDF 문서의 경우에만 :meth:`Document.get_page_images` / :meth:`Page.get_images` 메서드가 이미지 목록과 관련하여 일부 중복 기능을 제공합니다. 그러나 두 목록은 **같은 항목을 포함할 수도 있고 포함하지 않을 수도 있습니다**. 차이점은 다음 중 하나로 인한 것일 가능성이 높습니다:\"\n\n#: ../../textpage.rst:234 87715f6d6a82452b8ef41b7cbb3b917c\nmsgid \"\"\n\"\\\"Inline\\\" images (see page 214 of the :ref:`AdobeManual`) of a PDF page \"\n\"are contained in a textpage, but **do not appear** in \"\n\":meth:`Page.get_images`.\"\nmsgstr \"PDF 페이지의 \\\"인라인\\\" 이미지(:ref:`AdobeManual` 214페이지 참조)는 텍스트 페이지에 포함되지만 :meth:`Page.get_images` 에는 **나타나지 않습니다**.\"\n\n#: ../../textpage.rst:235 7671c8c4e14e4452a9de51d3be9f9a57\nmsgid \"\"\n\"Annotations may also contain images -- these will **not appear** in \"\n\":meth:`Page.get_images`.\"\nmsgstr \"주석에도 이미지가 포함될 수 있습니다. 이것들은 :meth:`Page.get_images` 에 **나타나지 않습니다**.\"\n\n#: ../../textpage.rst:236 528e4366c2844284b6b3e06d85663c2c\nmsgid \"\"\n\"Image blocks in a textpage are generated for **every** image location -- \"\n\"whether or not there are any duplicates. This is in contrast to \"\n\":meth:`Page.get_images`, which will list each image only once (per \"\n\"reference name).\"\nmsgstr \"텍스트 페이지의 이미지 블록은 **모든** 이미지 위치에 대해 생성됩니다. 중복이 있는지 여부와 관계없이. 이것은 각 이미지를 한 번만 나열하는 :meth:`Page.get_images` (참조 이름당)와 대조됩니다.\"\n\n#: ../../textpage.rst:237 6ba5259a29524a72bae31a85c368deb0\nmsgid \"\"\n\"Images mentioned in the page's :data:`object` definition will **always** \"\n\"appear in :meth:`Page.get_images` [#f1]_. But it may happen, that there \"\n\"is no \\\"display\\\" command in the page's :data:`contents` (erroneously or \"\n\"on purpose). In this case the image will **not appear** in the textpage.\"\nmsgstr \"페이지의 :data:`object` 정의에 언급된 이미지는 **항상** :meth:`Page.get_images` [#f1]_ 에 나타납니다. 그러나 페이지의 :data:`contents` 에 \\\"display\\\" 명령이 없을 수 있습니다(오류 또는 의도적으로). 이 경우 이미지는 텍스트 페이지에 **나타나지 않습니다**.\"\n\n#: ../../textpage.rst:239 e7f81738e67441429325db9963571f7d\nmsgid \"\"\n\"The image's \\\"transformation matrix\\\" is defined as the matrix, for which\"\n\" the expression `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` is true, \"\n\"lookup details here: :ref:`ImageTransformation`.\"\nmsgstr \"이미지의 \\\"변환 행렬\\\" 은 표현식 `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` 가 참인 행렬로 정의됩니다. 자세한 내용은 :ref:`ImageTransformation` 을 참조하세요.\"\n\n#: ../../textpage.rst:241 57bed7561cd444e0b640b95c35da2f85\nmsgid \"\"\n\"A transparent image may be accompanied by a mask image. This is stored \"\n\"under key `\\\"mask\\\"` and has the format of a `DeviceGray` PNG image. \"\n\"Otherwise the value of this key is ``None``. If present, you may be able \"\n\"to recover (an equivalent of) the original image -- i.e. with \"\n\"transparency -- by creating :ref:`Pixmap` objects from the \\\"image\\\", \"\n\"respectively \\\"mask\\\" values and overlay them. This is not guaranteed to \"\n\"always work because mask images come in multiple formats, of which not \"\n\"all qualify for the conditions under which overlaying Pixmaps are \"\n\"supported. Here is a code snippet:\"\nmsgstr \"투명 이미지에는 마스크 이미지가 함께 제공될 수 있습니다. 이것은 키 `\\\"mask\\\"` 아래에 저장되며 `DeviceGray` PNG 이미지 형식을 가집니다. 그렇지 않으면 이 키의 값은 ``None`` 입니다. 있는 경우 \\\"image\\\" 및 \\\"mask\\\" 값에서 :ref:`Pixmap` 객체를 생성하고 오버레이하여 원본 이미지(즉, 투명도 포함)를 복구할 수 있습니다. 마스크 이미지는 여러 형식으로 제공되며, 모든 형식이 Pixmap 오버레이가 지원되는 조건을 충족하지는 않기 때문에 항상 작동한다고 보장할 수는 없습니다. 다음은 코드 스니펫입니다:\"\n\n#: ../../textpage.rst:248 4615f23b245b4db39e8ea23b4d176464\nmsgid \"**Text block:**\"\nmsgstr \"**텍스트 블록:**\"\n\n#: ../../textpage.rst:253 db5d3f31fc8d4153b8fafecfdf3d1727\nmsgid \"0 = text *(int)*\"\nmsgstr \"0 = 텍스트 *(int)*\"\n\n#: ../../textpage.rst:254 6964cf3c7ba24458aae29d347f3f603a\nmsgid \"block rectangle, :data:`rect_like`\"\nmsgstr \"블록 사각형, :data:`rect_like`\"\n\n#: ../../textpage.rst:255 731cf949720a4619b5ea681f7764d295\nmsgid \"block count *(int)*\"\nmsgstr \"블록 개수 *(int)*\"\n\n#: ../../textpage.rst:256 3a23e4510e7949e29bf987d16327eb49\nmsgid \"lines\"\nmsgstr \"lines\"\n\n#: ../../textpage.rst:256 ede4e782ec014752989f15767a43462d\nmsgid \"*list* of text line dictionaries\"\nmsgstr \"텍스트 줄 딕셔너리의 *list*\"\n\n#: ../../textpage.rst:260 647d1430aba549968a23caa9bd2bf178\nmsgid \"Line Dictionary\"\nmsgstr \"줄 딕셔너리\"\n\n#: ../../textpage.rst:265 88d566f6551a42a29f62a0819ecbed64\nmsgid \"line rectangle, :data:`rect_like`\"\nmsgstr \"줄 사각형, :data:`rect_like`\"\n\n#: ../../textpage.rst:266 bc961e945f144c85a9e1a2193c3a4443\nmsgid \"wmode\"\nmsgstr \"wmode\"\n\n#: ../../textpage.rst:266 220a8c26dda34ae4b15fb120791f0296\nmsgid \"writing mode *(int)*: 0 = horizontal, 1 = vertical\"\nmsgstr \"쓰기 모드 *(int)*: 0 = 수평, 1 = 수직\"\n\n#: ../../textpage.rst:267 b23571753e8641b391f1c7bd3d666faf\nmsgid \"dir\"\nmsgstr \"dir\"\n\n#: ../../textpage.rst:267 f040c814bf3643e0b50bb1889d157bc2\nmsgid \"writing direction, :data:`point_like`\"\nmsgstr \"쓰기 방향, :data:`point_like`\"\n\n#: ../../textpage.rst:268 f4df6d31bea14f7d9133d10fe217a237\nmsgid \"spans\"\nmsgstr \"spans\"\n\n#: ../../textpage.rst:268 d2626131157f45bda11a0a0240ae20e0\nmsgid \"*list* of span dictionaries\"\nmsgstr \"범위 딕셔너리의 *list*\"\n\n#: ../../textpage.rst:271 827a258f7a314424b22d7d3077bc4795\nmsgid \"\"\n\"The value of key *\\\"dir\\\"* is the **unit vector** `dir = (cosine, -sine)`\"\n\" of the angle, which the text has relative to the x-axis [#f2]_. See the \"\n\"following picture: The word in each quadrant (counter-clockwise from top-\"\n\"right to bottom-right) is rotated by 30, 120, 210 and 300 degrees \"\n\"respectively.\"\nmsgstr \"키 *\\\"dir\\\"* 의 값은 텍스트가 x축에 대해 가진 각도의 **단위 벡터** `dir = (cosine, -sine)` 입니다 [#f2]_. 다음 그림을 참조하세요: 각 사분면(오른쪽 위에서 오른쪽 아래로 반시계 방향)의 단어는 각각 30, 120, 210, 300도 회전됩니다.\"\n\n#: ../../textpage.rst:277 76e3be33b8eb4d20a040a290a7493044\nmsgid \"Span Dictionary\"\nmsgstr \"범위 딕셔너리\"\n\n#: ../../textpage.rst:279 44e867372fca4010ae8c117e6f57244a\nmsgid \"\"\n\"Spans contain the actual text. A line contains **more than one span \"\n\"only**, if it contains text with different font properties.\"\nmsgstr \"범위에는 실제 텍스트가 포함됩니다. 줄은 다른 글꼴 속성을 가진 텍스트를 포함하는 경우에만 **하나 이상의 범위** 를 포함합니다.\"\n\n#: ../../textpage.rst:281 2484e6f332594c488b1ab6e8e45e8358\nmsgid \"Changed in version 1.14.17 Spans now also have a *bbox* key (again).\"\nmsgstr \"버전 1.14.17에서 변경됨: 범위에 이제 *bbox* 키가 다시 있습니다.\"\n\n#: ../../textpage.rst:282 fe2deeccb3484496b06cee9c45979177\nmsgid \"Changed in version 1.17.6 Spans now also have an *origin* key.\"\nmsgstr \"버전 1.17.6에서 변경됨: 범위에 이제 *origin* 키가 있습니다.\"\n\n#: ../../textpage.rst:287 24917424394140498d62e12db012d491\nmsgid \"span rectangle, :data:`rect_like`\"\nmsgstr \"범위 사각형, :data:`rect_like`\"\n\n#: ../../textpage.rst:288 ../../textpage.rst:371\n#: d062895875c246f08ce11e156a46fe6c e4eadb2bf3fd4656a1dcaea2aa762fb2\nmsgid \"origin\"\nmsgstr \"origin\"\n\n#: ../../textpage.rst:288 49dcac4791f7495283b181cd85e5cb96\nmsgid \"the first character's origin, :data:`point_like`\"\nmsgstr \"첫 번째 문자의 원점, :data:`point_like`\"\n\n#: ../../textpage.rst:289 a039c803b12f44f2b903bfd72ff968f0\nmsgid \"font\"\nmsgstr \"font\"\n\n#: ../../textpage.rst:289 e59d2678453347c3b2290c87101bee41\nmsgid \"font name *(str)*\"\nmsgstr \"글꼴 이름 *(str)*\"\n\n#: ../../textpage.rst:290 9789271ef0d44ca8b8b7753a47109329\nmsgid \"ascender\"\nmsgstr \"ascender\"\n\n#: ../../textpage.rst:290 bae202ea90f340c08117616fba695605\nmsgid \"ascender of the font *(float)*\"\nmsgstr \"글꼴의 상승부 *(float)*\"\n\n#: ../../textpage.rst:291 f04de1e03bc64ecb932178642bbf28a2\nmsgid \"descender\"\nmsgstr \"descender\"\n\n#: ../../textpage.rst:291 cab39571402145599cd516740c2cd5e3\nmsgid \"descender of the font *(float)*\"\nmsgstr \"글꼴의 하강부 *(float)*\"\n\n#: ../../textpage.rst:292 7bb34b245d0e4a7a807d37f771540973\nmsgid \"font size *(float)*\"\nmsgstr \"글꼴 크기 *(float)*\"\n\n#: ../../textpage.rst:293 728b3550893a43df91864ece6b6a6c75\nmsgid \"flags\"\nmsgstr \"flags\"\n\n#: ../../textpage.rst:293 d4144f5c31e240ca8a9bc6a9902c4b40\nmsgid \"font characteristics *(int)*\"\nmsgstr \"글꼴 특성 *(int)*\"\n\n#: ../../textpage.rst:294 4ab488b7a402495f924066ec5fa0901d\nmsgid \"char_flags\"\nmsgstr \"char_flags\"\n\n#: ../../textpage.rst:294 ac689e1eb3bd44c196f5a43696910e9c\nmsgid \"char characteristics *(int)*\"\nmsgstr \"문자 특성 *(int)*\"\n\n#: ../../textpage.rst:295 70dfc6783fdb4c5a8a1e0ad9b92b44fc\nmsgid \"color\"\nmsgstr \"color\"\n\n#: ../../textpage.rst:295 0c21ca835d2f477e934a8f5cec1f8a4c\nmsgid \"text color in sRGB format 0xRRGGBB *(int)*.\"\nmsgstr \"sRGB 형식의 텍스트 색상 0xRRGGBB *(int)*.\"\n\n#: ../../textpage.rst:296 8e921b08a2ba477497897d70a87f4977\nmsgid \"alpha\"\nmsgstr \"alpha\"\n\n#: ../../textpage.rst:296 ec794a253afb48ea90cf9d7494caa03b\nmsgid \"text opacity 0..255 *(int)*.\"\nmsgstr \"텍스트 불투명도 0..255 *(int)*.\"\n\n#: ../../textpage.rst:297 72dbc8f290b94f6c88700e6a5df12717\nmsgid \"text\"\nmsgstr \"text\"\n\n#: ../../textpage.rst:297 42bc9c7faaed433c9e3868ab04254f3f\nmsgid \"(only for :meth:`extractDICT`) text *(str)*\"\nmsgstr \"(:meth:`extractDICT` 전용) 텍스트 *(str)*\"\n\n#: ../../textpage.rst:298 6c4e864e58554766a1c930bd0e32e581\nmsgid \"chars\"\nmsgstr \"chars\"\n\n#: ../../textpage.rst:298 287db5214934490ba0764caaa9ee699d\nmsgid \"(only for :meth:`extractRAWDICT`) *list* of character dictionaries\"\nmsgstr \"(:meth:`extractRAWDICT` 전용) 문자 딕셔너리의 *list*\"\n\n#: ../../textpage.rst:301 6a3a9323a60541ca97db64597a2a451a\nmsgid \"|history_begin|\"\nmsgstr \"|history_begin|\"\n\n#: ../../textpage.rst:303 e0b8ee67e36546b0b5b8b155e00eeb45\nmsgid \"*(New in version 1.25.3.0):* Added *\\\"alpha\\\"* item.\"\nmsgstr \"*(버전 1.25.3.0에서 새로 추가됨):* *\\\"alpha\\\"* 항목 추가.\"\n\n#: ../../textpage.rst:305 04010301eebf4c2dbf6989108e207ae9\nmsgid \"\"\n\"*(New in version 1.16.0):* *\\\"color\\\"* is the text color encoded in sRGB \"\n\"(int) format, e.g. 0xFF0000 for red. There are functions for converting \"\n\"this integer back to formats (r, g, b) (PDF with float values from 0 to \"\n\"1) :meth:`sRGB_to_pdf`, or (R, G, B), :meth:`sRGB_to_rgb` (with integer \"\n\"values from 0 to 255).\"\nmsgstr \"*(버전 1.16.0에서 새로 추가됨):* *\\\"color\\\"* 는 sRGB (int) 형식으로 인코딩된 텍스트 색상입니다. 예: 빨간색의 경우 0xFF0000. 이 정수를 다시 형식으로 변환하는 함수가 있습니다: (r, g, b) (0에서 1까지의 float 값, PDF) :meth:`sRGB_to_pdf`, 또는 (R, G, B) :meth:`sRGB_to_rgb` (0에서 255까지의 정수 값).\"\n\n#: ../../textpage.rst:307 744bef29da2f4dbc90404a35ef0fd253\nmsgid \"\"\n\"*(New in v1.18.5):* *\\\"ascender\\\"* and *\\\"descender\\\"* are font \"\n\"properties, provided relative to :data:`fontsize` 1. Note that descender \"\n\"is a negative value. The following picture shows the relationship to \"\n\"other values and properties.\"\nmsgstr \"*(v1.18.5에서 새로 추가됨):* *\\\"ascender\\\"* 와 *\\\"descender\\\"* 는 :data:`fontsize` 1에 상대적인 글꼴 속성입니다. descender는 음수 값입니다. 다음 그림은 다른 값 및 속성과의 관계를 보여줍니다.\"\n\n#: ../../textpage.rst:309 e0a8a997405247f6bb89749ab0b624b7\nmsgid \"|history_end|\"\nmsgstr \"|history_end|\"\n\n#: ../../textpage.rst:314 9b180b7db6ac43e489b8d8e9ccb31622\nmsgid \"\"\n\"These numbers may be used to compute the minimum height of a character \"\n\"(or span) -- as opposed to the standard height provided in the \\\"bbox\\\" \"\n\"values (which actually represents the **line height**). The following \"\n\"code recalculates the span bbox to have a height of **fontsize** exactly \"\n\"fitting the text inside:\"\nmsgstr \"이 숫자는 문자(또는 범위)의 최소 높이를 계산하는 데 사용할 수 있습니다. \\\"bbox\\\" 값에 제공된 표준 높이(실제로 **줄 높이** 를 나타냄)와 대조됩니다. 다음 코드는 범위 bbox를 **fontsize** 높이로 재계산하여 내부 텍스트에 정확히 맞도록 합니다:\"\n\n#: ../../textpage.rst:324 91c353d85b0a45d7bde9987e275b50b5\nmsgid \"\"\n\"The above calculation may deliver a **larger** height! This may e.g. \"\n\"happen for OCRed documents, where the risk of all sorts of text artifacts\"\n\" is high. MuPDF tries to come up with a reasonable bbox height, \"\n\"independently from the :data:`fontsize` found in the PDF. So please \"\n\"ensure that the height of `span[\\\"bbox\\\"]` is **larger** than \"\n\"`span[\\\"size\\\"]`.\"\nmsgstr \"위 계산은 **더 큰** 높이를 제공할 수 있습니다! 예를 들어 OCR된 문서에서 이런 일이 발생할 수 있으며, 모든 종류의 텍스트 아티팩트 위험이 높습니다. |MuPDF| 는 PDF에서 찾은 :data:`fontsize` 와 독립적으로 합리적인 bbox 높이를 제시하려고 합니다. 따라서 `span[\\\"bbox\\\"]` 의 높이가 `span[\\\"size\\\"]` 보다 **큰지** 확인하세요.\"\n\n#: ../../textpage.rst:326 cfa2fe9816d741889a16e7a98228f45f\nmsgid \"\"\n\"You may request PyMuPDF to do all of the above automatically by executing\"\n\" `pymupdf.TOOLS.set_small_glyph_heights(True)`. This sets a global \"\n\"parameter so that all subsequent text searches and text extractions are \"\n\"based on reduced glyph heights, where meaningful.\"\nmsgstr \"`pymupdf.TOOLS.set_small_glyph_heights(True)` 를 실행하여 |PyMuPDF| 가 위의 모든 작업을 자동으로 수행하도록 요청할 수 있습니다. 이것은 전역 매개변수를 설정하여 모든 후속 텍스트 검색 및 텍스트 추출이 의미 있는 경우 감소된 글리프 높이를 기반으로 하도록 합니다.\"\n\n#: ../../textpage.rst:328 dcd3f3103b3a404ea59ed88e1020efbe\nmsgid \"\"\n\"The following shows the original span rectangle in red and the rectangle \"\n\"with re-computed height in blue.\"\nmsgstr \"다음은 빨간색으로 표시된 원본 범위 사각형과 파란색으로 표시된 재계산된 높이의 사각형을 보여줍니다.\"\n\n#: ../../textpage.rst:334 c4897a84054b4b60ab66d79b8388e431\nmsgid \"\"\n\"*\\\"flags\\\"* is an integer, which represents font properties except for \"\n\"the first bit 0. They are to be interpreted like this:\"\nmsgstr \"*\\\"flags\\\"* 는 첫 번째 비트 0을 제외한 글꼴 속성을 나타내는 정수입니다. 다음과 같이 해석됩니다:\"\n\n#: ../../textpage.rst:336 817f541495b84011b646fb0f5a0c1eff\nmsgid \"\"\n\"bit 0: superscripted (:data:`TEXT_FONT_SUPERSCRIPT`) -- not a font \"\n\"property, detected by MuPDF code.\"\nmsgstr \"비트 0: 위첨자 (:data:`TEXT_FONT_SUPERSCRIPT`) -- 글꼴 속성이 아니며 MuPDF 코드에 의해 감지됩니다.\"\n\n#: ../../textpage.rst:337 4966d75813f448898822b04faffbe380\nmsgid \"bit 1: italic (:data:`TEXT_FONT_ITALIC`)\"\nmsgstr \"비트 1: 기울임꼴 (:data:`TEXT_FONT_ITALIC`)\"\n\n#: ../../textpage.rst:338 31205a9cd37941e0ac7c7fbbfb19ffc1\nmsgid \"bit 2: serifed (:data:`TEXT_FONT_SERIFED`)\"\nmsgstr \"비트 2: 세리프 (:data:`TEXT_FONT_SERIFED`)\"\n\n#: ../../textpage.rst:339 f887f5fcd078467cbd8ea212d8133aa3\nmsgid \"bit 3: monospaced (:data:`TEXT_FONT_MONOSPACED`)\"\nmsgstr \"비트 3: 고정폭 (:data:`TEXT_FONT_MONOSPACED`)\"\n\n#: ../../textpage.rst:340 075ed56b276245c096a3204cc111339a\nmsgid \"bit 4: bold (:data:`TEXT_FONT_BOLD`)\"\nmsgstr \"비트 4: 굵게 (:data:`TEXT_FONT_BOLD`)\"\n\n#: ../../textpage.rst:342 fafa4c4a530a43fa8278e455dd07640f\nmsgid \"Test these characteristics like so:\"\nmsgstr \"다음과 같이 이러한 특성을 테스트합니다:\"\n\n#: ../../textpage.rst:348 ffbc346b79aa4a6189253e08eeb6280f\nmsgid \"\"\n\"Bits 1 thru 4 are font properties, i.e. encoded in the font program. \"\n\"Please note, that this information is not necessarily correct or \"\n\"complete: fonts quite often contain wrong data here.\"\nmsgstr \"비트 1부터 4까지는 글꼴 속성, 즉 글꼴 프로그램에 인코딩된 것입니다. 이 정보가 반드시 정확하거나 완전하지는 않습니다. 글꼴은 여기에 잘못된 데이터를 포함하는 경우가 많습니다.\"\n\n#: ../../textpage.rst:350 67a56b648e48459abc86b3d71dded7d7\nmsgid \"\"\n\"*\\\"char_flags\\\"* is an integer, which represents extra character \"\n\"properties:\"\nmsgstr \"*\\\"char_flags\\\"* 는 추가 문자 속성을 나타내는 정수입니다:\"\n\n#: ../../textpage.rst:352 16e54aeb7318448cb0edbbce096027cc\nmsgid \"bit 0: strikeout.\"\nmsgstr \"비트 0: 취소선.\"\n\n#: ../../textpage.rst:353 f36bc128a5084f419c7b735cc7a5caeb\nmsgid \"bit 1: underline.\"\nmsgstr \"비트 1: 밑줄.\"\n\n#: ../../textpage.rst:354 05f6a81ee7234929b145f42b0eaeb4ee\nmsgid \"bit 2: synthetic (always 0, see char dictionary).\"\nmsgstr \"비트 2: 합성 (항상 0, 문자 딕셔너리 참조).\"\n\n#: ../../textpage.rst:355 2d7d278b9b7b46479144808b701ed7da\nmsgid \"bit 3: filled.\"\nmsgstr \"비트 3: 채움.\"\n\n#: ../../textpage.rst:356 a0b8d460dd8a42e69537652330a1f9ee\nmsgid \"bit 4: stroked.\"\nmsgstr \"비트 4: 획.\"\n\n#: ../../textpage.rst:357 430da53ed561403d90a8c2c28cc01a90\nmsgid \"bit 5: clipped.\"\nmsgstr \"비트 5: 클리핑.\"\n\n#: ../../textpage.rst:359 26fc27f279ca42fba75113be40e54d40\nmsgid \"\"\n\"For example if not filled and not stroked (`if not (char_flags & 2**3 & \"\n\"2**4): ...`) then the text will be invisible.\"\nmsgstr \"예를 들어 채워지지 않고 획이 없으면 (`if not (char_flags & 2**3 & 2**4): ...`) 텍스트가 보이지 않습니다.\"\n\n#: ../../textpage.rst:362 f68e611505354310ab256d5f4ac755f3\nmsgid \"(`char_flags` is new in v1.25.2.)\"\nmsgstr \"(`char_flags` 는 v1.25.2에서 새로 추가됨.)\"\n\n#: ../../textpage.rst:366 2b6029a504d149d0b74200b8dd10b461\nmsgid \"Character Dictionary for :meth:`extractRAWDICT`\"\nmsgstr \":meth:`extractRAWDICT` 의 문자 딕셔너리\"\n\n#: ../../textpage.rst:371 e3322f02de66484cb59d9ddf2e914bcb\nmsgid \"character's left baseline point, :data:`point_like`\"\nmsgstr \"문자의 왼쪽 기준선 점, :data:`point_like`\"\n\n#: ../../textpage.rst:372 3a206190a9b4495299d14480848ee306\nmsgid \"character rectangle, :data:`rect_like`\"\nmsgstr \"문자 사각형, :data:`rect_like`\"\n\n#: ../../textpage.rst:373 7925e02a5e07443895c900f6450205fa\nmsgid \"synthetic\"\nmsgstr \"synthetic\"\n\n#: ../../textpage.rst:373 d557f7b009724b00a3418fb77e4943ce\nmsgid \"bool.\"\nmsgstr \"bool.\"\n\n#: ../../textpage.rst:374 fb692a970116495a977cac2daff0d94b\nmsgid \"c\"\nmsgstr \"c\"\n\n#: ../../textpage.rst:374 30e9a39551314a14a169ee11d34c575f\nmsgid \"the character (unicode)\"\nmsgstr \"문자 (유니코드)\"\n\n#: ../../textpage.rst:377 504a88fbf1324f19a3ed16c3f2c0c942\nmsgid \"(`synthetic` is new in v1.25.3.)\"\nmsgstr \"(`synthetic` 는 v1.25.3에서 새로 추가됨.)\"\n\n#: ../../textpage.rst:379 9d820af6f3ac446a912245d16d5e7bdd\nmsgid \"\"\n\"This image shows the relationship between a character's bbox and its \"\n\"quad: |textpagechar|\"\nmsgstr \"이 이미지는 문자의 bbox와 quad 간의 관계를 보여줍니다: |textpagechar|\"\n\n#: ../../textpage.rst:381 64023f700298486f98b566eac340e37b\n#: 7901af22526f478cb0ba76a7cc56288e\nmsgid \"textpagechar\"\nmsgstr \"textpagechar\"\n\n#: ../../textpage.rst:386 ab41f5e333004a04a46c0505e9d7bebf\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../textpage.rst:387 9c3377a336cd4477b8afbd4528d4dee0\nmsgid \"\"\n\"Image specifications for a PDF page are done in a page's (sub-) \"\n\":data:`dictionary`, called `/Resources`. Resource dictionaries can be \"\n\"**inherited** from any of the page's parent objects (usually the \"\n\":data:`catalog` -- the top-level parent). The PDF creator may e.g. define\"\n\" one `/Resources` on file level, naming all images and / or all fonts \"\n\"ever used by any page. In these cases, :meth:`Page.get_images` and \"\n\":meth:`Page.get_fonts` will consequently return the same lists for all \"\n\"pages. If desired, this situation can be reverted using \"\n\":meth:`Page.clean_contents`. After execution, the page's object \"\n\"definition will show fonts and images that are actually used.\"\nmsgstr \"PDF 페이지의 이미지 사양은 `/Resources` 라는 페이지의 (하위) :data:`dictionary` 에서 수행됩니다. 리소스 딕셔너리는 페이지의 부모 객체(일반적으로 :data:`catalog` -- 최상위 부모) 중 하나에서 **상속** 될 수 있습니다. PDF 생성자는 예를 들어 파일 수준에서 하나의 `/Resources` 를 정의하여 모든 페이지에서 사용된 모든 이미지 및/또는 모든 글꼴을 명명할 수 있습니다. 이 경우 :meth:`Page.get_images` 와 :meth:`Page.get_fonts` 는 결과적으로 모든 페이지에 대해 동일한 목록을 반환합니다. 원하는 경우 :meth:`Page.clean_contents` 를 사용하여 이 상황을 되돌릴 수 있습니다. 실행 후 페이지의 객체 정의는 실제로 사용되는 글꼴과 이미지를 표시합니다.\"\n\n#: ../../textpage.rst:389 8ebe9e78accc4c87b80eb50757ed695f\nmsgid \"\"\n\"The coordinate systems of MuPDF and PDF are different in that MuPDF uses \"\n\"the page's top-left point as `(0, 0)`. In PDF, this is the bottom-left \"\n\"point. Therefore, the positive direction for MuPDF's y-axis is **from top\"\n\" to bottom**. This causes the sign change for the sine value here: a \"\n\"**negative** value indicates anti-clockwise rotation of the text.\"\nmsgstr \"|MuPDF| 와 PDF의 좌표계는 |MuPDF| 가 페이지의 왼쪽 위 점을 `(0, 0)` 으로 사용한다는 점에서 다릅니다. PDF에서는 이것이 왼쪽 아래 점입니다. 따라서 |MuPDF| 의 y축의 양의 방향은 **위에서 아래로** 입니다. 이것은 여기서 사인 값의 부호 변경을 유발합니다: **음수** 값은 텍스트의 반시계 방향 회전을 나타냅니다.\"\n\n#: ../../textpage.rst:391 9bfe3c4bcdac45eb9b746197c51d2a7a\nmsgid \"\"\n\"This value is always 96, the default of the PDF interpreter. It **does \"\n\"not reflect** the resolution of the image itself. If you need the image's\"\n\" resolution, use the :meth:`Pixmap.xres` and :meth:`Pixmap.yres` \"\n\"attributes of the :ref:`Pixmap` created from the returned image binary.\"\nmsgstr \"이 값은 항상 96이며, PDF 인터프리터의 기본값입니다. 이것은 **이미지 자체의 해상도를 반영하지 않습니다**. 이미지의 해상도가 필요한 경우 반환된 이미지 바이너리에서 생성된 :ref:`Pixmap` 의 :meth:`Pixmap.xres` 및 :meth:`Pixmap.yres` 속성을 사용하세요.\"\n\n#: ../../footer.rst:46 909bafb54f4646cd8842c5ccd34ceeef\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/textwriter.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 95c1ee7365714a268b45d71ca863b7ee\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 8dbea99845b74a23bde58d46198a17ac\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 cf3d095401604af48e44cc3a35d66bff\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, Pyodide, PyScript\"\n\n#: ../../textwriter.rst:7 e9730367b10a49359e1d45817a7f7880\nmsgid \"TextWriter\"\nmsgstr \"TextWriter (텍스트 라이터)\"\n\n#: ../../textwriter.rst:9 cda3eb15a6fe4186b26bf8276092c97f\nmsgid \"|pdf_only_class|\"\nmsgstr \"|pdf_only_class|\"\n\n#: ../../textwriter.rst:11 db627f8740eb4561a5527a9d4ca4e25f\nmsgid \"New in v1.16.18\"\nmsgstr \"v1.16.18에서 새로 추가됨\"\n\n#: ../../textwriter.rst:13 67e48f18fa9440238b3a1969be763ace\nmsgid \"\"\n\"This class represents a MuPDF *text* object. The basic idea is to \"\n\"**decouple (1) text preparation, and (2) text output** to PDF pages.\"\nmsgstr \"이 클래스는 MuPDF *text* 객체를 나타냅니다. 기본 아이디어는 **(1) 텍스트 준비와 (2) PDF 페이지로의 텍스트 출력을 분리** 하는 것입니다.\"\n\n#: ../../textwriter.rst:15 5a301b5eac7846a6a95cae297b7806a2\nmsgid \"\"\n\"During **preparation**, a text writer stores any number of text pieces \"\n\"(\\\"spans\\\") together with their positions and individual font \"\n\"information. The **output** of the writer's prepared content may happen \"\n\"multiple times to any PDF page with a compatible page size.\"\nmsgstr \"**준비** 중에 텍스트 라이터는 임의의 수의 텍스트 조각(\\\"스팬\\\")을 위치 및 개별 글꼴 정보와 함께 저장합니다. 라이터의 준비된 콘텐츠의 **출력** 은 호환되는 페이지 크기를 가진 모든 PDF 페이지에 여러 번 수행될 수 있습니다.\"\n\n#: ../../textwriter.rst:17 7cf591fcc0cf40af9d587a72b702b960\nmsgid \"\"\n\"A text writer is an elegant alternative to methods \"\n\":meth:`Page.insert_text` and friends:\"\nmsgstr \"텍스트 라이터는 :meth:`Page.insert_text` 및 유사한 메서드에 대한 우아한 대안입니다:\"\n\n#: ../../textwriter.rst:19 8d88b6d0545142bc9885b1dcbb44a4ea\nmsgid \"\"\n\"**Improved text positioning:** Choose any point where insertion of text \"\n\"should start. Storing text returns the \\\"cursor position\\\" after the \"\n\"*last character* of the span.\"\nmsgstr \"**개선된 텍스트 위치 지정:** 텍스트 삽입이 시작되어야 하는 임의의 지점을 선택합니다. 텍스트 저장은 스팬의 *마지막 문자* 이후의 \\\"커서 위치\\\"를 반환합니다.\"\n\n#: ../../textwriter.rst:20 4014fff4490f449991524305bfef1c4b\nmsgid \"\"\n\"**Free font choice:** Each text span has its own font and \"\n\":data:`fontsize`. This lets you easily switch when composing a larger \"\n\"text.\"\nmsgstr \"**자유로운 글꼴 선택:** 각 텍스트 스팬은 자체 글꼴과 :data:`fontsize` 를 가집니다. 이를 통해 더 큰 텍스트를 구성할 때 쉽게 전환할 수 있습니다.\"\n\n#: ../../textwriter.rst:21 96e0cdf2386340edafe0ed3b9aa2a211\nmsgid \"\"\n\"**Automatic fallback fonts:** If a character is not supported by the \"\n\"chosen font, alternative fonts are automatically searched. This \"\n\"significantly reduces the risk of seeing unprintable symbols in the \"\n\"output (\\\"TOFUs\\\" -- looking like a small rectangle). PyMuPDF now also \"\n\"comes with the **universal font \\\"Droid Sans Fallback Regular\\\"**, which \"\n\"supports **all Latin** characters (including Cyrillic and Greek), and \"\n\"**all CJK** characters (Chinese, Japanese, Korean).\"\nmsgstr \"**자동 대체 글꼴:** 선택한 글꼴이 문자를 지원하지 않으면 대체 글꼴이 자동으로 검색됩니다. 이는 출력에서 인쇄할 수 없는 기호(\\\"TOFUs\\\" -- 작은 사각형처럼 보임)를 볼 위험을 크게 줄입니다. |PyMuPDF| 는 이제 **모든 라틴** 문자(키릴 문자 및 그리스 문자 포함)와 **모든 CJK** 문자(중국어, 일본어, 한국어)를 지원하는 **범용 글꼴 \\\"Droid Sans Fallback Regular\\\"** 를 제공합니다.\"\n\n#: ../../textwriter.rst:22 89a8833cb85e46909d178dc372f5aaac\nmsgid \"\"\n\"**Cyrillic and Greek Support:** The :ref:`Base-14-fonts` have integrated \"\n\"support of Cyrillic and Greek characters **without specifying encoding.**\"\n\" Your text may be a mixture of Latin, Greek and Cyrillic.\"\nmsgstr \"**키릴 문자 및 그리스 문자 지원:** :ref:`Base-14-fonts` 는 **인코딩을 지정하지 않고** 키릴 문자 및 그리스 문자에 대한 통합 지원을 제공합니다. 텍스트는 라틴 문자, 그리스 문자 및 키릴 문자의 혼합일 수 있습니다.\"\n\n#: ../../textwriter.rst:23 939bfd358cb14ee1ac3d682b4310030f\nmsgid \"\"\n\"**Transparency support:** Parameter *opacity* is supported. This offers a\"\n\" handy way to create watermark-style text.\"\nmsgstr \"**투명도 지원:** *opacity* 매개변수가 지원됩니다. 이를 통해 워터마크 스타일의 텍스트를 만드는 편리한 방법을 제공합니다.\"\n\n#: ../../textwriter.rst:24 36106b9c863b43c39d4d348af9680b3e\nmsgid \"\"\n\"**Justified text:** Supported for any font -- not just simple fonts as in\"\n\" :meth:`Page.insert_textbox`.\"\nmsgstr \"**양쪽 정렬 텍스트:** :meth:`Page.insert_textbox` 와 같은 단순 글꼴뿐만 아니라 모든 글꼴에 대해 지원됩니다.\"\n\n#: ../../textwriter.rst:25 88d0bcdd76b94defb985b51bd7050a50\nmsgid \"\"\n\"**Reusability:** A TextWriter object exists independent from PDF pages. \"\n\"It can be written multiple times, either to the same or to other pages, \"\n\"in the same or in different PDFs, choosing different colors or \"\n\"transparency.\"\nmsgstr \"**재사용성:** TextWriter 객체는 PDF 페이지와 독립적으로 존재합니다. 동일한 페이지 또는 다른 페이지, 동일한 PDF 또는 다른 PDF에 여러 번 작성할 수 있으며, 다른 색상이나 투명도를 선택할 수 있습니다.\"\n\n#: ../../textwriter.rst:27 6ef8000439b141009aae765ba8c24479\nmsgid \"Using this object entails three steps:\"\nmsgstr \"이 객체를 사용하려면 세 단계가 필요합니다:\"\n\n#: ../../textwriter.rst:29 55dea84332984f3ca477041ec762edcf\nmsgid \"\"\n\"When **created**, a TextWriter requires a fixed **page rectangle** in \"\n\"relation to which it calculates text positions. A text writer can write \"\n\"to pages of this size only.\"\nmsgstr \"**생성** 시 TextWriter는 텍스트 위치를 계산하기 위한 고정된 **페이지 사각형** 이 필요합니다. 텍스트 라이터는 이 크기의 페이지에만 쓸 수 있습니다.\"\n\n#: ../../textwriter.rst:30 57f72fe6a49d41c7be7ed160f47f3019\nmsgid \"\"\n\"Store text in the TextWriter using methods :meth:`TextWriter.append`, \"\n\":meth:`TextWriter.appendv` and :meth:`TextWriter.fill_textbox` as often \"\n\"as is desired.\"\nmsgstr \"원하는 만큼 :meth:`TextWriter.append`, :meth:`TextWriter.appendv` 및 :meth:`TextWriter.fill_textbox` 메서드를 사용하여 TextWriter에 텍스트를 저장합니다.\"\n\n#: ../../textwriter.rst:31 ac5cfe5c0bf548bf8358a2cc4efa279b\nmsgid \"Output the TextWriter object on some PDF page(s).\"\nmsgstr \"일부 PDF 페이지에 TextWriter 객체를 출력합니다.\"\n\n#: ../../textwriter.rst:35 a70f239f39dc44bcbbcc7f367f4f04e8\nmsgid \"\"\n\"Starting with version 1.17.0, TextWriters **do support** text rotation \"\n\"via the *morph* parameter of :meth:`TextWriter.write_text`.\"\nmsgstr \"버전 1.17.0부터 TextWriter는 :meth:`TextWriter.write_text` 의 *morph* 매개변수를 통한 텍스트 회전을 **지원합니다**.\"\n\n#: ../../textwriter.rst:37 39efcbe7af8242d59a6e61a1577bd093\nmsgid \"\"\n\"There also exists :meth:`Page.write_text` which combines one or more \"\n\"TextWriters and jointly writes them to a given rectangle and with a given\"\n\" rotation angle -- much like :meth:`Page.show_pdf_page`.\"\nmsgstr \":meth:`Page.write_text` 도 존재하며, 하나 이상의 TextWriter를 결합하여 주어진 사각형과 주어진 회전 각도로 공동으로 작성합니다 -- :meth:`Page.show_pdf_page` 와 매우 유사합니다.\"\n\n#: ../../textwriter.rst:41 58759c7fac7b4e859398a94c56641cf5\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../textwriter.rst:41 f8b99b262c4e479daa04854b10a8ca62\nmsgid \"**Short Description**\"\nmsgstr \"**간략 설명**\"\n\n#: ../../textwriter.rst:43 5aef1526d3ed401ebe84391dae14eb4e\nmsgid \":meth:`~TextWriter.append`\"\nmsgstr \":meth:`~TextWriter.append`\"\n\n#: ../../textwriter.rst:43 8a1f849d010e4a069dd84d412203d33f\nmsgid \"Add text in horizontal write mode\"\nmsgstr \"수평 쓰기 모드에서 텍스트 추가\"\n\n#: ../../textwriter.rst:44 a3aab120ca1545a79fce7af51ccd1964\nmsgid \":meth:`~TextWriter.appendv`\"\nmsgstr \":meth:`~TextWriter.appendv`\"\n\n#: ../../textwriter.rst:44 30601ff66d064e7bbc6b0711078114c1\nmsgid \"Add text in vertical write mode\"\nmsgstr \"수직 쓰기 모드에서 텍스트 추가\"\n\n#: ../../textwriter.rst:45 665726b1a2f74150b2cf20b54f5d3864\nmsgid \":meth:`~TextWriter.fill_textbox`\"\nmsgstr \":meth:`~TextWriter.fill_textbox`\"\n\n#: ../../textwriter.rst:45 79bdf8fe196e481f9e0f7e6b6d83fa39\nmsgid \"Fill rectangle (horizontal write mode)\"\nmsgstr \"사각형 채우기 (수평 쓰기 모드)\"\n\n#: ../../textwriter.rst:46 50d2cf2d0f664964ad637397d702ba01\nmsgid \":meth:`~TextWriter.write_text`\"\nmsgstr \":meth:`~TextWriter.write_text`\"\n\n#: ../../textwriter.rst:46 e17f4b99e3a3451090107da06c63083d\nmsgid \"Output TextWriter to a PDF page\"\nmsgstr \"TextWriter를 PDF 페이지로 출력\"\n\n#: ../../textwriter.rst:47 b1dd0ce95c524931a45226c559b5fc7f\nmsgid \":attr:`~TextWriter.color`\"\nmsgstr \":attr:`~TextWriter.color`\"\n\n#: ../../textwriter.rst:47 977d247f29344daebbc7eb2edad63dda\nmsgid \"Text color (can be changed)\"\nmsgstr \"텍스트 색상 (변경 가능)\"\n\n#: ../../textwriter.rst:48 a702a69b27f04a1a8bf416872181b83c\nmsgid \":attr:`~TextWriter.last_point`\"\nmsgstr \":attr:`~TextWriter.last_point`\"\n\n#: ../../textwriter.rst:48 9c6a85c298f542b0ad83608987c80d7c\nmsgid \"Last written character ends here\"\nmsgstr \"마지막으로 작성된 문자가 여기서 끝남\"\n\n#: ../../textwriter.rst:49 85bb365488064af39728ae2cff15a95e\nmsgid \":attr:`~TextWriter.opacity`\"\nmsgstr \":attr:`~TextWriter.opacity`\"\n\n#: ../../textwriter.rst:49 360143b334e144b188b4fc4606f37cd1\nmsgid \"Text opacity (can be changed)\"\nmsgstr \"텍스트 투명도 (변경 가능)\"\n\n#: ../../textwriter.rst:50 44cf6996b53b4136925af2dd23e6d3c3\nmsgid \":attr:`~TextWriter.rect`\"\nmsgstr \":attr:`~TextWriter.rect`\"\n\n#: ../../textwriter.rst:50 a79f2dca7b614eaaa5682eae3f4fa368\nmsgid \"Page rectangle used by this TextWriter\"\nmsgstr \"이 TextWriter가 사용하는 페이지 사각형\"\n\n#: ../../textwriter.rst:51 86888b68bbf045c8a8e10712005c4259\nmsgid \":attr:`~TextWriter.text_rect`\"\nmsgstr \":attr:`~TextWriter.text_rect`\"\n\n#: ../../textwriter.rst:51 cd277f06068040caa6fda7759192bbd3\nmsgid \"Area occupied so far\"\nmsgstr \"지금까지 차지한 영역\"\n\n#: ../../textwriter.rst:55 07466a577be94bd3ab53ccdfc689e759\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../textwriter.rst 0671bfe1c02041f88c29cf3ea4be264b\n#: 7841a29906a944f189e7e759b6592a97 7cb374b81c074ac69a19656e5756ce8c\n#: 800737d8455c4751bf6f9476b3e4a8df ffbf23da457b4c1fbab7452f6745e439\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../textwriter.rst:61 1156a360315c4f6cab4971ea0b50224f\nmsgid \"rectangle internally used for text positioning computations.\"\nmsgstr \"텍스트 위치 계산에 내부적으로 사용되는 사각형.\"\n\n#: ../../textwriter.rst:62 51fad4a4f8034a198c2666a029ac959b\nmsgid \"\"\n\"sets the transparency for the text to store here. Values outside the \"\n\"interval `[0, 1)` will be ignored. A value of e.g. 0.5 means 50% \"\n\"transparency.\"\nmsgstr \"여기에 저장할 텍스트의 투명도를 설정합니다. `[0, 1)` 구간 밖의 값은 무시됩니다. 예를 들어 0.5 값은 50% 투명도를 의미합니다.\"\n\n#: ../../textwriter.rst:63 6b628abb5ffe4a5585ddb2b56255b5dd\nmsgid \"\"\n\"the color of the text. All colors are specified as floats *0 <= color <= \"\n\"1*. A single float represents some gray level, a sequence implies the \"\n\"colorspace via its length.\"\nmsgstr \"텍스트의 색상. 모든 색상은 부동 소수점 *0 <= color <= 1* 로 지정됩니다. 단일 부동 소수점은 일부 회색 레벨을 나타내고, 시퀀스는 길이를 통해 색 공간을 암시합니다.\"\n\n#: ../../textwriter.rst:68 0fa13673da764fdaab29ebfad67bf44c\nmsgid \"*Changed in v1.18.9*\"\nmsgstr \"*v1.18.9에서 변경됨*\"\n\n#: ../../textwriter.rst:69 ../../textwriter.rst:100\n#: 08713255cee94718b3bc26b0dda8f233 be3763dd7a294137b65bf5a1770830d3\nmsgid \"*Changed in v1.18.15*\"\nmsgstr \"*v1.18.15에서 변경됨*\"\n\n#: ../../textwriter.rst:71 6f8eddc35363416184aad7c44e5d01ef\nmsgid \"Add some new text in horizontal writing.\"\nmsgstr \"수평 쓰기로 일부 새 텍스트를 추가합니다.\"\n\n#: ../../textwriter.rst:73 ../../textwriter.rst:104\n#: 31e8d87141cf44c5890e5151a73047f4 f7e1346516c8429f9cafb3010a03a215\nmsgid \"start position of the text, the bottom left point of the first character.\"\nmsgstr \"텍스트의 시작 위치, 첫 번째 문자의 왼쪽 하단 점.\"\n\n#: ../../textwriter.rst:74 3b2200db94814c6b84f09e2a67431714\nmsgid \"\"\n\"a string of arbitrary length. It will be written starting at position \"\n\"\\\"pos\\\".\"\nmsgstr \"임의 길이의 문자열. \\\"pos\\\" 위치에서 시작하여 작성됩니다.\"\n\n#: ../../textwriter.rst:75 ../../textwriter.rst:106\n#: 6080d699b79c4e7cabc81e6632904644 8f2fdb3f4ec442f4b7703714fb642f4c\nmsgid \"a :ref:`Font`. If omitted, `pymupdf.Font(\\\"helv\\\")` will be used.\"\nmsgstr \":ref:`Font`. 생략하면 `pymupdf.Font(\\\"helv\\\")` 가 사용됩니다.\"\n\n#: ../../textwriter.rst:76 09fbce8fe4ee46b0a95710e2b4761014\nmsgid \"the :data:`fontsize`, a positive number, default 11.\"\nmsgstr \":data:`fontsize`, 양수, 기본값 11.\"\n\n#: ../../textwriter.rst:77 ../../textwriter.rst:108\n#: 4483c3fec8c3452cac52b7d831f281c1 87ccb28c8f1b4453af79b92ad4c5aabd\nmsgid \"\"\n\"the language to use, e.g. \\\"en\\\" for English. Meaningful values should be\"\n\" compliant with the ISO 639 standards 1, 2, 3 or 5. Reserved for future \"\n\"use: currently has no effect as far as we know.\"\nmsgstr \"사용할 언어, 예: 영어의 경우 \\\"en\\\". 의미 있는 값은 ISO 639 표준 1, 2, 3 또는 5를 준수해야 합니다. 향후 사용을 위해 예약됨: 현재로서는 알려진 바에 따르면 효과가 없습니다.\"\n\n#: ../../textwriter.rst:78 d8bd68ad24da40269a51cc710d5053e8\nmsgid \"\"\n\"*(New in v1.18.9)* whether the text should be written from right to left.\"\n\" Applicable for languages like Arabian or Hebrew. Default is ``False``. \"\n\"If ``True``, any Latin parts within the text will automatically \"\n\"converted. There are no other consequences, i.e. \"\n\":attr:`TextWriter.last_point` will still be the rightmost character, and \"\n\"there neither is any alignment taking place. Hence you may want to use \"\n\":meth:`TextWriter.fill_textbox` instead.\"\nmsgstr \"*(v1.18.9에서 새로 추가)* 텍스트를 오른쪽에서 왼쪽으로 작성할지 여부. 아랍어나 히브리어와 같은 언어에 적용됩니다. 기본값은 ``False`` 입니다. ``True`` 인 경우 텍스트 내의 모든 라틴 문자 부분이 자동으로 변환됩니다. 다른 결과는 없습니다. 즉, :attr:`TextWriter.last_point` 는 여전히 가장 오른쪽 문자이며 정렬도 수행되지 않습니다. 따라서 :meth:`TextWriter.fill_textbox` 를 대신 사용하는 것이 좋을 수 있습니다.\"\n\n#: ../../textwriter.rst:79 75daea05a2a449aa9e600dc6f54efa72\nmsgid \"\"\n\"*(New in v1.18.15)* look for the character's Small Capital version in the\"\n\" font. If present, take that value instead. Otherwise the original \"\n\"character (this font or the fallback font) will be taken. The fallback \"\n\"font will never return small caps. For example, this snippet::  >>> doc =\"\n\" pymupdf.open() >>> page = doc.new_page() >>> text = \\\"PyMuPDF: the \"\n\"Python bindings for MuPDF\\\" >>> font = pymupdf.Font(\\\"figo\\\")  # choose a\"\n\" font with small caps >>> tw = pymupdf.TextWriter(page.rect) >>> \"\n\"tw.append((50,100), text, font=font, small_caps=True) >>> \"\n\"tw.write_text(page) >>> doc.ez_save(\\\"x.pdf\\\")  will produce this PDF \"\n\"text:  .. image:: images/img-smallcaps.*\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:79 46eb184e73ae4219ac1e4bed06322f56\nmsgid \"\"\n\"*(New in v1.18.15)* look for the character's Small Capital version in the\"\n\" font. If present, take that value instead. Otherwise the original \"\n\"character (this font or the fallback font) will be taken. The fallback \"\n\"font will never return small caps. For example, this snippet::\"\nmsgstr \"*(v1.18.15에서 새로 추가)* 글꼴에서 문자의 작은 대문자 버전을 찾습니다. 존재하면 해당 값을 사용합니다. 그렇지 않으면 원래 문자(이 글꼴 또는 대체 글꼴)가 사용됩니다. 대체 글꼴은 작은 대문자를 반환하지 않습니다. 예를 들어, 이 코드 조각::\"\n\n#: ../../textwriter.rst:90 973003c33fe84aa69d42e2c43c861a09\nmsgid \"will produce this PDF text:\"\nmsgstr \"이 PDF 텍스트를 생성합니다:\"\n\n#: ../../textwriter.rst 031973dcb92c46dfb30974b0b0277dbb\n#: 56067c1753344901a2a112d292086782 6fe2f7cc1d5b405588798ce1725db0d6\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../textwriter.rst:95 ../../textwriter.rst:111\n#: 2916a5791a9446a1be47d9bdde016b5b 2d57d9c3e3404a1b8aaedf35dc4f6d7d\nmsgid \"\"\n\":attr:`text_rect` and :attr:`last_point`. *(Changed in v1.18.0:)* Raises \"\n\"an exception for an unsupported font -- checked via \"\n\":attr:`Font.is_writable`.\"\nmsgstr \":attr:`text_rect` 및 :attr:`last_point`. *(v1.18.0에서 변경:)* 지원되지 않는 글꼴에 대해 예외를 발생시킵니다 -- :attr:`Font.is_writable` 을 통해 확인됩니다.\"\n\n#: ../../textwriter.rst:102 53cbfa2552fa46b2837c5848f6ae7eed\nmsgid \"Add some new text in vertical, top-to-bottom writing.\"\nmsgstr \"수직, 위에서 아래로 쓰기로 일부 새 텍스트를 추가합니다.\"\n\n#: ../../textwriter.rst:105 77e2561d4b4a448caf4a7b3ecbc624ce\nmsgid \"a string. It will be written starting at position \\\"pos\\\".\"\nmsgstr \"문자열. \\\"pos\\\" 위치에서 시작하여 작성됩니다.\"\n\n#: ../../textwriter.rst:107 1195a41741cd44ca8653fce3a3c8b23f\nmsgid \"the :data:`fontsize`, a positive float, default 11.\"\nmsgstr \":data:`fontsize`, 양수 부동 소수점, 기본값 11.\"\n\n#: ../../textwriter.rst:109 ../../textwriter.rst:133\n#: 48cdfcdb373b4a939b9ac2491aaf9f76 a007fa3bc26e4925bac3b3884fa1d6f4\nmsgid \"*(New in v1.18.15)* see :meth:`append`.\"\nmsgstr \"*(v1.18.15에서 새로 추가)* :meth:`append` 를 참조하세요.\"\n\n#: ../../textwriter.rst:115 131d2ddda39f47e5b8750ce4e02aacf1\nmsgid \"\"\n\"Changed in 1.17.3: New parameter `pos` to specify where to start writing \"\n\"within rectangle.\"\nmsgstr \"1.17.3에서 변경: 사각형 내에서 쓰기를 시작할 위치를 지정하는 새 매개변수 `pos`.\"\n\n#: ../../textwriter.rst:116 29062b4cba8b458c9715b63563932eea\nmsgid \"\"\n\"Changed in v1.18.9: Return list of lines which do not fit in rectangle. \"\n\"Support writing right-to-left (e.g. Arabian, Hebrew).\"\nmsgstr \"v1.18.9에서 변경: 사각형에 맞지 않는 줄 목록을 반환합니다. 오른쪽에서 왼쪽으로 쓰기 지원(예: 아랍어, 히브리어).\"\n\n#: ../../textwriter.rst:117 1af15893d8c0406eaba47e8cbc605623\nmsgid \"Changed in v1.18.15: Prefer small caps if supported by the font.\"\nmsgstr \"v1.18.15에서 변경: 글꼴에서 지원하는 경우 작은 대문자를 선호합니다.\"\n\n#: ../../textwriter.rst:119 557382b2514d472bbe73f5017c792395\nmsgid \"\"\n\"Fill a given rectangle with text in horizontal writing mode. This is a \"\n\"convenience method to use as an alternative for :meth:`append`.\"\nmsgstr \"수평 쓰기 모드로 주어진 사각형을 텍스트로 채웁니다. 이는 :meth:`append` 의 대안으로 사용할 수 있는 편의 메서드입니다.\"\n\n#: ../../textwriter.rst:121 cef4e997c224414e95918704fa70b178\nmsgid \"the area to fill. No part of the text will appear outside of this.\"\nmsgstr \"채울 영역. 텍스트의 어떤 부분도 이 영역 밖에 나타나지 않습니다.\"\n\n#: ../../textwriter.rst:122 eb9a1f87715c476190b440d505b21385\nmsgid \"\"\n\"the text. Can be specified as a (UTF-8) string or a list / tuple of \"\n\"strings. A string will first be converted to a list using *splitlines()*.\"\n\" Every list item will begin on a new line (forced line breaks).\"\nmsgstr \"텍스트. (UTF-8) 문자열 또는 문자열의 리스트/튜플로 지정할 수 있습니다. 문자열은 먼저 *splitlines()* 를 사용하여 리스트로 변환됩니다. 각 리스트 항목은 새 줄에서 시작합니다(강제 줄바꿈).\"\n\n#: ../../textwriter.rst:123 adaa607ca4b34119b1413a21aa5d5703\nmsgid \"\"\n\"*(new in v1.17.3)* start storing at this point. Default is a point near \"\n\"rectangle top-left.\"\nmsgstr \"*(v1.17.3에서 새로 추가)* 이 지점에서 저장을 시작합니다. 기본값은 사각형 왼쪽 상단 근처의 점입니다.\"\n\n#: ../../textwriter.rst:124 093d30283065429a8003316402078989\nmsgid \"the :ref:`Font`, default `pymupdf.Font(\\\"helv\\\")`.\"\nmsgstr \":ref:`Font`, 기본값 `pymupdf.Font(\\\"helv\\\")`.\"\n\n#: ../../textwriter.rst:125 fa67844b1bdc4fd5b33c77ea89ae7619\nmsgid \"the :data:`fontsize`.\"\nmsgstr \":data:`fontsize`.\"\n\n#: ../../textwriter.rst:126 a3f0cf660cc34b2aa6461b460ccc9fd7\nmsgid \"\"\n\"text alignment. Use one of TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, \"\n\"TEXT_ALIGN_RIGHT or TEXT_ALIGN_JUSTIFY.\"\nmsgstr \"텍스트 정렬. TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT 또는 TEXT_ALIGN_JUSTIFY 중 하나를 사용합니다.\"\n\n#: ../../textwriter.rst:127 fab2e37b003c4547a135db4871ab87f9\nmsgid \"\"\n\"*(New in v1.18.9)* whether the text should be written from right to left.\"\n\" Applicable for languages like Arabian or Hebrew. Default is ``False``. \"\n\"If ``True``, any Latin parts are automatically reverted. You must still \"\n\"set the alignment (if you want right alignment), it does not happen \"\n\"automatically -- the other alignment options remain available as well.\"\nmsgstr \"*(v1.18.9에서 새로 추가)* 텍스트를 오른쪽에서 왼쪽으로 작성할지 여부. 아랍어나 히브리어와 같은 언어에 적용됩니다. 기본값은 ``False`` 입니다. ``True`` 인 경우 모든 라틴 문자 부분이 자동으로 반전됩니다. 정렬(오른쪽 정렬을 원하는 경우)을 여전히 설정해야 하며, 자동으로 발생하지 않습니다 -- 다른 정렬 옵션도 계속 사용할 수 있습니다.\"\n\n#: ../../textwriter.rst:128 fbd4a0182852411d9c83784e6421be47\nmsgid \"\"\n\"on text overflow do nothing, warn, or raise an exception. Overflow text \"\n\"will never be written. **Changed in v1.18.9:**  * Default is ``None``. * \"\n\"The list of overflow lines will be returned.\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:128 0e6db582f2eb4eb28e4c2efbd9fb40e1\nmsgid \"\"\n\"on text overflow do nothing, warn, or raise an exception. Overflow text \"\n\"will never be written. **Changed in v1.18.9:**\"\nmsgstr \"텍스트 오버플로우 시 아무 작업도 하지 않거나 경고를 표시하거나 예외를 발생시킵니다. 오버플로우 텍스트는 절대 작성되지 않습니다. **v1.18.9에서 변경:**\"\n\n#: ../../textwriter.rst:130 cdae6e2706854c9e826f849d936c11ee\nmsgid \"Default is ``None``.\"\nmsgstr \"기본값은 ``None`` 입니다.\"\n\n#: ../../textwriter.rst:131 1bda032411484b10b23479232b916047\nmsgid \"The list of overflow lines will be returned.\"\nmsgstr \"오버플로우 줄 목록이 반환됩니다.\"\n\n#: ../../textwriter.rst 035f3f34d091461bbe3cc1d030bfe153\n#: 1871d0ab981b44759c8973a335232ef3 6459020d5302480fb99a57af3fd39d02\n#: 92e14712db2944b694cdf765796b471d d0a0b9758d76412fb2a1f68276a1f782\n#: f3e6dee2f74245bfa95d18620e9bd73d\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../textwriter.rst:136 396c812b4c0346d69cbc578eaae29744\nmsgid \"\"\n\"*New in v1.18.9* -- List of lines that did not fit in the rectangle. Each\"\n\" item is a tuple `(text, length)` containing a string and its length (on \"\n\"the page).\"\nmsgstr \"*v1.18.9에서 새로 추가* -- 사각형에 맞지 않는 줄 목록. 각 항목은 문자열과 그 길이(페이지에서)를 포함하는 튜플 `(text, length)` 입니다.\"\n\n#: ../../textwriter.rst:138 cd3a09fa82ee40e399e27a6aa0c1235d\nmsgid \"\"\n\"Use these methods as often as is required -- there is no technical limit \"\n\"(except memory constraints of your system). You can also mix \"\n\":meth:`append` and text boxes and have multiple of both. Text positioning\"\n\" is exclusively controlled by the insertion point. Therefore there is no \"\n\"need to adhere to any order. *(Changed in v1.18.0:)* Raise an exception \"\n\"for an unsupported font -- checked via :attr:`Font.is_writable`.\"\nmsgstr \"필요한 만큼 자주 이 메서드를 사용하세요 -- 기술적 제한은 없습니다(시스템의 메모리 제약 제외). :meth:`append` 와 텍스트 상자를 혼합하고 둘 다 여러 개를 가질 수 있습니다. 텍스트 위치 지정은 삽입 지점에 의해서만 제어됩니다. 따라서 순서를 따를 필요가 없습니다. *(v1.18.0에서 변경:)* 지원되지 않는 글꼴에 대해 예외를 발생시킵니다 -- :attr:`Font.is_writable` 을 통해 확인됩니다.\"\n\n#: ../../textwriter.rst:143 54709b98b30a47ac89166f31faf2772a\nmsgid \"\"\n\"Write the TextWriter text to a page, which is the only mandatory \"\n\"parameter. The other parameters can be used to temporarily override the \"\n\"values used when the TextWriter was created.\"\nmsgstr \"TextWriter 텍스트를 페이지에 작성합니다. 이는 유일한 필수 매개변수입니다. 다른 매개변수는 TextWriter가 생성될 때 사용된 값을 임시로 재정의하는 데 사용할 수 있습니다.\"\n\n#: ../../textwriter.rst:145 59f4fdcbbc44452680ba4c0c95aa5cff\nmsgid \"write to this :ref:`Page`.\"\nmsgstr \"이 :ref:`Page` 에 작성합니다.\"\n\n#: ../../textwriter.rst:146 ../../textwriter.rst:147\n#: 376b4dcec8264f3db2f6be76d778904b d45c4d5a07474ef4a0cd683fdd04bcdc\nmsgid \"override the value of the TextWriter for this output.\"\nmsgstr \"이 출력에 대해 TextWriter의 값을 재정의합니다.\"\n\n#: ../../textwriter.rst:148 ee07ac03480b41539d94053d359dd9d3\nmsgid \"\"\n\"modify the text appearance by applying a matrix to it. If provided, this \"\n\"must be a sequence *(fixpoint, matrix)* with a point-like *fixpoint* and \"\n\"a matrix-like *matrix*. A typical example is rotating the text around \"\n\"*fixpoint*.\"\nmsgstr \"행렬을 적용하여 텍스트 모양을 수정합니다. 제공된 경우 이것은 점과 같은 *fixpoint* 와 행렬과 같은 *matrix* 를 가진 시퀀스 *(fixpoint, matrix)* 여야 합니다. 일반적인 예는 *fixpoint* 주위로 텍스트를 회전하는 것입니다.\"\n\n#: ../../textwriter.rst:149 b45dc013b8e740f9bef33593ed5c8711\nmsgid \"put in foreground (default) or background.\"\nmsgstr \"전경(기본값) 또는 배경에 배치합니다.\"\n\n#: ../../textwriter.rst:150 ba9cfbd9695340699d7179b74412ef18\nmsgid \"*(new in v1.18.4)* the :data:`xref` of an :data:`OCG` or :data:`OCMD`.\"\nmsgstr \"*(v1.18.4에서 새로 추가)* :data:`OCG` 또는 :data:`OCMD` 의 :data:`xref`.\"\n\n#: ../../textwriter.rst:151 9523549f48f246a3ae03b7bc5f901456\nmsgid \"\"\n\"The PDF `Tr` operator value. Values: 0 (default), 1, 2, 3 (invisible).  \"\n\".. image:: images/img-rendermode.*\"\nmsgstr \"\"\n\n#: ../../textwriter.rst:151 78528b40a6544fe0a046dee8ae6857ef\nmsgid \"The PDF `Tr` operator value. Values: 0 (default), 1, 2, 3 (invisible).\"\nmsgstr \"PDF `Tr` 연산자 값. 값: 0 (기본값), 1, 2, 3 (보이지 않음).\"\n\n#: ../../textwriter.rst:158 525f73853e924927ad796c65943a368d\nmsgid \"The area currently occupied.\"\nmsgstr \"현재 차지하고 있는 영역.\"\n\n#: ../../textwriter.rst:160 ../../textwriter.rst:184\n#: ba565ed25cdd42f7862fcb93e757cf70 be5a7d304fd0479ea3d522fa0b628537\nmsgid \":ref:`Rect`\"\nmsgstr \":ref:`Rect`\"\n\n#: ../../textwriter.rst:164 87ebb8ff55c24240abc1589af86e4a9a\nmsgid \"\"\n\"The \\\"cursor position\\\" -- a :ref:`Point` -- after the last written \"\n\"character (its bottom-right).\"\nmsgstr \"\\\"커서 위치\\\" -- 마지막으로 작성된 문자(오른쪽 하단) 이후의 :ref:`Point`.\"\n\n#: ../../textwriter.rst:166 ac55d30024ef4851bc1e890d44698e93\nmsgid \":ref:`Point`\"\nmsgstr \":ref:`Point`\"\n\n#: ../../textwriter.rst:170 3f90c9a1dc4c4511a85d2dd1d614e275\nmsgid \"The text opacity (modifiable).\"\nmsgstr \"텍스트 투명도 (수정 가능).\"\n\n#: ../../textwriter.rst:176 40b6c71ad92443f69b941e2ae68ef65d\nmsgid \"The text color (modifiable).\"\nmsgstr \"텍스트 색상 (수정 가능).\"\n\n#: ../../textwriter.rst:182 c8c0cc26dcc643b4b7a36449cc37508b\nmsgid \"\"\n\"The page rectangle for which this TextWriter was created. Must not be \"\n\"modified.\"\nmsgstr \"이 TextWriter가 생성된 페이지 사각형. 수정하면 안 됩니다.\"\n\n#: ../../textwriter.rst:187 96d56c1eedc9403da49260989a4dc7c5\nmsgid \"\"\n\"To see some demo scripts dealing with TextWriter, have a look at `the \"\n\"TextWriter demo scripts <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/tree/master/textwriter>`_.\"\nmsgstr \"TextWriter를 다루는 일부 데모 스크립트를 보려면 `TextWriter 데모 스크립트 <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/textwriter>`_ 를 참조하세요.\"\n\n#: ../../textwriter.rst:189 86f5ad85ef9f430798003667a5d4bba8\nmsgid \"Opacity and color apply to **all the text** in this object.\"\nmsgstr \"투명도와 색상은 이 객체의 **모든 텍스트** 에 적용됩니다.\"\n\n#: ../../textwriter.rst:190 3fd56e7645674dd592624498a3b40033\nmsgid \"\"\n\"If you need different colors / transparency, you must create a separate \"\n\"TextWriter. Whenever you determine the color should change, simply append\"\n\" the text to the respective TextWriter using the previously returned \"\n\":attr:`last_point` as position for the new text span.\"\nmsgstr \"다른 색상/투명도가 필요한 경우 별도의 TextWriter를 생성해야 합니다. 색상이 변경되어야 한다고 판단할 때마다 이전에 반환된 :attr:`last_point` 를 새 텍스트 스팬의 위치로 사용하여 해당 TextWriter에 텍스트를 추가하세요.\"\n\n#: ../../textwriter.rst:191 473cca9e82e445e7a947ffeaead9f1d6\nmsgid \"\"\n\"Appending items or text boxes can occur in arbitrary order: only the \"\n\"position parameter controls where text appears.\"\nmsgstr \"항목이나 텍스트 상자를 추가하는 것은 임의의 순서로 발생할 수 있습니다: 위치 매개변수만 텍스트가 나타나는 위치를 제어합니다.\"\n\n#: ../../textwriter.rst:192 e86c99a3e580410c80b33c1b9273d1e5\nmsgid \"\"\n\"Font and :data:`fontsize` can freely vary within the same TextWriter. \"\n\"This can be used to let text with different properties appear on the same\"\n\" displayed line: just specify *pos* accordingly, and e.g. set it to \"\n\":attr:`last_point` of the previously added item.\"\nmsgstr \"글꼴과 :data:`fontsize` 는 동일한 TextWriter 내에서 자유롭게 변경할 수 있습니다. 이를 사용하여 다른 속성을 가진 텍스트가 동일한 표시 줄에 나타나도록 할 수 있습니다: *pos* 를 그에 따라 지정하고, 예를 들어 이전에 추가된 항목의 :attr:`last_point` 로 설정하세요.\"\n\n#: ../../textwriter.rst:193 0dd912f04fa84ab7832bd944567f6dc1\nmsgid \"\"\n\"You can use the *pos* argument of :meth:`TextWriter.fill_textbox` to set \"\n\"the position of the first text character. This allows filling the same \"\n\"textbox with contents from different :ref:`TextWriter` objects, thus \"\n\"allowing for multiple colors, opacities, etc.\"\nmsgstr \":meth:`TextWriter.fill_textbox` 의 *pos* 인수를 사용하여 첫 번째 텍스트 문자의 위치를 설정할 수 있습니다. 이를 통해 다른 :ref:`TextWriter` 객체의 콘텐츠로 동일한 텍스트 상자를 채울 수 있으므로 여러 색상, 투명도 등을 허용합니다.\"\n\n#: ../../textwriter.rst:194 46ddcc45b9594214860870dcb571f619\nmsgid \"\"\n\"MuPDF does not support all fonts with this feature, e.g. no Type3 fonts. \"\n\"Starting with v1.18.0 this can be checked via the font attribute \"\n\":attr:`Font.is_writable`. This attribute is also checked when using \"\n\":ref:`TextWriter` methods.\"\nmsgstr \"|MuPDF| 는 이 기능으로 모든 글꼴을 지원하지 않습니다. 예를 들어 Type3 글꼴은 지원하지 않습니다. v1.18.0부터는 글꼴 속성 :attr:`Font.is_writable` 을 통해 이를 확인할 수 있습니다. 이 속성은 :ref:`TextWriter` 메서드를 사용할 때도 확인됩니다.\"\n\n#: ../../footer.rst:46 b6d5682a116d45b9b5a6850c9cfd6f9e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/the-basics.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 16:19+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 909f9969c815483692de0eeae2b2c6b8\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 7c546c172c3049238925a5d3d154deac\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 d775abfe51ed4aae97e87841af09650c\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../the-basics.rst:8 b573d287df3a4994ab9fc76c334671ff\nmsgid \"The Basics\"\nmsgstr \"기초\"\n\n#: ../../the-basics.rst:13 f7ad136a192c476f8006b215bda74aeb\nmsgid \"Opening a File\"\nmsgstr \"파일 열기\"\n\n#: ../../the-basics.rst:16 02f1cd284e354ff99efcff59db44a1d3\nmsgid \"To open a file, do the following:\"\nmsgstr \"파일을 열려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:27 ../../the-basics.rst:58 ../../the-basics.rst:119\n#: ../../the-basics.rst:149 ../../the-basics.rst:199 ../../the-basics.rst:249\n#: ../../the-basics.rst:287 ../../the-basics.rst:377 ../../the-basics.rst:416\n#: ../../the-basics.rst:465 ../../the-basics.rst:551 ../../the-basics.rst:636\n#: ../../the-basics.rst:692 ../../the-basics.rst:884 ../../the-basics.rst:1068\n#: 0068950bcad54023968e3f762f5f517f 05774a0919aa4c5c9c36f6bac5d452ef\n#: 0e7e23d4b7bc416cae884504c277d711 1225e0c609dc479ca2f4b881424a32ac\n#: 2222ebbac6364d5b9b08e76451ddf9a1 47f2b0f15354473b88fd164c09ab6f50\n#: 4830de8bf34d47e6a2ffef8fe914a53f 7efa68f16195464b9faadc6def36171f\n#: 86a29e64e6a24ade8a8ac4da891c7f28 8daf9faca165448ba7a882a6b2cdb4e2\n#: 9f4f8da64538439287fec0bfd34094c4 b84230e6f2734b0b8af4a50458974ebf\n#: d5c2e1f3166846bf85914a88c378cfc2 da8824eb7edf4d73aa56dc95df1dd1d1\n#: f53b94d6fdab4636b68a2e80cfc9f035\nmsgid \"**Taking it further**\"\nmsgstr \"**더 알아보기**\"\n\n#: ../../the-basics.rst:29 89354d4f696a4471b78c43ab5c2a5c2a\nmsgid \"\"\n\"See the :ref:`list of supported file types<Supported_File_Types>` and \"\n\":ref:`The How to Guide on Opening Files <HowToOpenAFile>` for more \"\n\"advanced options.\"\nmsgstr \"더 고급 옵션은 :ref:`지원되는 파일 타입 목록<Supported_File_Types>` 및 :ref:`파일 열기 방법 가이드 <HowToOpenAFile>` 를 참조하세요.\"\n\n#: ../../the-basics.rst:38 5cac62e394ac45989dbc0d2e8dd159be\nmsgid \"Extract text from a |PDF|\"\nmsgstr \"|PDF| 에서 텍스트 추출\"\n\n#: ../../the-basics.rst:40 a0d1eb5ca0da4ab8951f1b2b8623289d\nmsgid \"To extract all the text from a |PDF| file, do the following:\"\nmsgstr \"|PDF| 파일에서 모든 텍스트를 추출하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:54 883a6098a76f43d1a5ac736b2cce28a8\nmsgid \"\"\n\"Of course it is not just |PDF| which can have text extracted - all the \"\n\":ref:`supported document file formats <About_Feature_Matrix>` such as \"\n\":title:`MOBI`, :title:`EPUB`, :title:`TXT` can have their text extracted.\"\nmsgstr \"물론 텍스트를 추출할 수 있는 것은 |PDF| 만이 아닙니다 - :ref:`지원되는 문서 파일 형식 <About_Feature_Matrix>` (예: :title:`MOBI`, :title:`EPUB`, :title:`TXT`) 모두에서 텍스트를 추출할 수 있습니다.\"\n\n#: ../../the-basics.rst:60 20545bb8acee4ab784b06e10f8f6c531\nmsgid \"\"\n\"If your document contains image based text content the use OCR on the \"\n\"page for subsequent text extraction:\"\nmsgstr \"문서에 이미지 기반 텍스트 콘텐츠가 포함된 경우 후속 텍스트 추출을 위해 페이지에서 OCR을 사용합니다:\"\n\n#: ../../the-basics.rst:67 ../../the-basics.rst:121\n#: a3622ac2d3a8426eb4bf51fd86910cc2 e6467ed2be7e4603bb2d779b91c7f5b3\nmsgid \"\"\n\"There are many more examples which explain how to extract text from \"\n\"specific areas or how to extract tables from documents. Please refer to \"\n\"the :ref:`How to Guide for Text<RecipesText>`.\"\nmsgstr \"특정 영역에서 텍스트를 추출하거나 문서에서 테이블을 추출하는 방법을 설명하는 더 많은 예제가 있습니다. :ref:`텍스트 가이드 <RecipesText>` 를 참조하세요.\"\n\n#: ../../the-basics.rst:69 707cbcbf6a784fb39564f16a7e3dc032\nmsgid \"\"\n\"You can now also :ref:`extract text in Markdown \"\n\"format<rag_outputting_as_md>`.\"\nmsgstr \"이제 :ref:`Markdown 형식으로 텍스트 추출 <rag_outputting_as_md>` 도 할 수 있습니다.\"\n\n#: ../../the-basics.rst:71 ../../the-basics.rst:123 ../../the-basics.rst:153\n#: ../../the-basics.rst:208 ../../the-basics.rst:255 ../../the-basics.rst:291\n#: ../../the-basics.rst:318 ../../the-basics.rst:343 ../../the-basics.rst:383\n#: ../../the-basics.rst:420 ../../the-basics.rst:472 ../../the-basics.rst:498\n#: ../../the-basics.rst:525 ../../the-basics.rst:606 ../../the-basics.rst:657\n#: ../../the-basics.rst:696 ../../the-basics.rst:760 ../../the-basics.rst:819\n#: ../../the-basics.rst:896 ../../the-basics.rst:926 ../../the-basics.rst:962\n#: ../../the-basics.rst:988 ../../the-basics.rst:1072\n#: 07855b8e74cf474bb2c22f4ea1486b77 14463d4aca01470b9aeb4b607b17f5c9\n#: 1c3978a5519a4d36b5e656a91c01ecdf 2c0ea7a221bc482c9799c3a352cb1eb9\n#: 5c80f9f1865449309e09d88d691bb68a 5efa802d04ed4ed89cd05d92421170f6\n#: 67c48e5b292f4e9b9dd54a97ff4accf5 890c419a3008426abe76d049f182b2f8\n#: 89defd51bf04459e9d7361784de9c261 8fd41167904a409080c488f71c5f60e3\n#: 97e7e736a10449a9bb80fe64abc4572d 9a7f26aa2f0a4af2aefe5dbe1f4bd77f\n#: a017d665ee0942bc950c27a6f1261a1d a3129d1fc34c489dbce01f464dab1fec\n#: a42c9f54e3c1452ba53a839adc35e52c bda2261d0d2e4a559d33aa934c6fc244\n#: bda7623fd6574e8a9c992679676465a3 c499bd5e8117498eb20b5ad1d95592b0\n#: cce4af742f274d3096ca85a76a595aba d7b4b9ff758e46f99007f97eb4ff95c7\n#: dbcf27434c3f43c1850b747a56c81c6d e9ad6ac85a8243b7837a2ba0a008093e\n#: fe8941aaa58649e6b9bbe06143ba9fa4\nmsgid \"**API reference**\"\nmsgstr \"**API 참조**\"\n\n#: ../../the-basics.rst:73 b7bf2d8223824a34a302b49fe4ee31fb\nmsgid \":meth:`Page.get_text`\"\nmsgstr \":meth:`Page.get_text`\"\n\n#: ../../the-basics.rst:85 9ada4b1ef4a24e7493857603dcd93d75\nmsgid \"Extract images from a |PDF|\"\nmsgstr \"|PDF| 에서 이미지 추출\"\n\n#: ../../the-basics.rst:87 5ed12b425f01418ba06929d7c6d08a32\nmsgid \"To extract all the images from a |PDF| file, do the following:\"\nmsgstr \"|PDF| 파일에서 모든 이미지를 추출하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:125 b8190e106cd745da99ebfa71d6dc7550\nmsgid \":meth:`Page.get_images`\"\nmsgstr \":meth:`Page.get_images`\"\n\n#: ../../the-basics.rst:126 a75e43c33c564cf6a23b07e3f3d7b4f3\nmsgid \":ref:`Pixmap<Pixmap>`\"\nmsgstr \":ref:`Pixmap<Pixmap>`\"\n\n#: ../../the-basics.rst:133 6faa94d7643a453791a62048e151e9f6\nmsgid \"Extract vector graphics\"\nmsgstr \"벡터 그래픽 추출\"\n\n#: ../../the-basics.rst:135 4f09604cb7f64a9f8e72293ed907ad38\nmsgid \"To extract all the vector graphics from a document page, do the following:\"\nmsgstr \"문서 페이지에서 모든 벡터 그래픽을 추출하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:145 2a5a383743524b57b81c68a8b6342599\nmsgid \"\"\n\"This will return a dictionary of paths for any vector drawings found on \"\n\"the page.\"\nmsgstr \"이것은 페이지에서 발견된 모든 벡터 그림에 대한 경로 딕셔너리를 반환합니다.\"\n\n#: ../../the-basics.rst:151 225e28d931034158a41317ebaea841d5\nmsgid \"\"\n\"Please refer to: :ref:`How to Extract \"\n\"Drawings<RecipesDrawingAndGraphics_Extract_Drawings>`.\"\nmsgstr \":ref:`그림 추출 방법 <RecipesDrawingAndGraphics_Extract_Drawings>` 를 참조하세요.\"\n\n#: ../../the-basics.rst:155 6f4863d999e44206b34be29b3deb363e\nmsgid \":meth:`Page.get_drawings`\"\nmsgstr \":meth:`Page.get_drawings`\"\n\n#: ../../the-basics.rst:166 810da3e647c342ef9dc50496dad28ba4\nmsgid \"Merging |PDF| files\"\nmsgstr \"|PDF| 파일 병합\"\n\n#: ../../the-basics.rst:168 f5160b79b89244d8a6045b6cbdd53e39\nmsgid \"To merge |PDF| files, do the following:\"\nmsgstr \"|PDF| 파일을 병합하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:182 fdc9cd0b81044db2822c364c5561f18d\nmsgid \"Merging |PDF| files with other types of file\"\nmsgstr \"다른 타입의 파일과 |PDF| 파일 병합\"\n\n#: ../../the-basics.rst:184 44edda88e0bb4b66bb4b3f4271487f7b\nmsgid \"\"\n\"With :meth:`Document.insert_file` you can invoke the method to merge \"\n\":ref:`supported files<Supported_File_Types>` with |PDF|. For example:\"\nmsgstr \":meth:`Document.insert_file` 메서드를 사용하여 :ref:`지원되는 파일<Supported_File_Types>` 을 |PDF| 와 병합할 수 있습니다. 예:\"\n\n#: ../../the-basics.rst:201 af6d68b7867f4c02b0b25a870eb70be1\nmsgid \"\"\n\"It is easy to join PDFs with :meth:`Document.insert_pdf` & \"\n\":meth:`Document.insert_file`. Given open |PDF| documents, you can copy \"\n\"page ranges from one to the other. You can select the point where the \"\n\"copied pages should be placed, you can revert the page sequence and also \"\n\"change page rotation.\"\nmsgstr \":meth:`Document.insert_pdf` 및 :meth:`Document.insert_file` 로 PDF를 쉽게 결합할 수 있습니다. 열린 |PDF| 문서가 주어지면 한 문서에서 다른 문서로 페이지 범위를 복사할 수 있습니다. 복사된 페이지가 배치될 지점을 선택하고, 페이지 순서를 되돌리고, 페이지 회전을 변경할 수도 있습니다.\"\n\n#: ../../the-basics.rst:203 8c29c60b2e3944278d03602d769f8c7c\nmsgid \"\"\n\"The GUI script `join.py <https://github.com/pymupdf/PyMuPDF-\"\n\"Utilities/blob/master/examples/join-documents/join.py>`_ uses this method\"\n\" to join a list of files while also joining the respective table of \"\n\"contents segments. It looks like this:\"\nmsgstr \"GUI 스크립트 `join.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py>`_ 는 이 메서드를 사용하여 파일 목록을 결합하면서 각 목차 세그먼트도 결합합니다. 다음과 같습니다:\"\n\n#: ../../the-basics.rst:210 dfc7e6e8e50b40d19288f88e51710867\nmsgid \":meth:`Document.insert_pdf`\"\nmsgstr \":meth:`Document.insert_pdf`\"\n\n#: ../../the-basics.rst:211 3c85c393fc9a47d1a1f4d4bd44f71f7d\nmsgid \":meth:`Document.insert_file`\"\nmsgstr \":meth:`Document.insert_file`\"\n\n#: ../../the-basics.rst:218 5374c164503d49308ea222d3f1f4ac68\nmsgid \"Working with Coordinates\"\nmsgstr \"좌표 작업\"\n\n#: ../../the-basics.rst:220 32ef87567fbf4591aa33613a467efc43\nmsgid \"\"\n\"There is one *mathematical term* that you should feel comfortable with \"\n\"when using |PyMuPDF| -  **\\\"coordinates\\\"**. Please have a quick look at \"\n\"the :ref:`Coordinates` section to understand the coordinate system to \"\n\"help you with positioning objects and understand your document space.\"\nmsgstr \"|PyMuPDF| 를 사용할 때 익숙해야 할 *수학 용어* 가 하나 있습니다 - **\\\"좌표\\\"** 입니다. 객체를 배치하고 문서 공간을 이해하는 데 도움이 되도록 좌표계를 이해하기 위해 :ref:`Coordinates` 섹션을 빠르게 살펴보세요.\"\n\n#: ../../the-basics.rst:229 808c51c176874e4f8e4f561f56a7e050\nmsgid \"Adding a watermark to a |PDF|\"\nmsgstr \"|PDF| 에 워터마크 추가\"\n\n#: ../../the-basics.rst:231 e3bd1bcc59dd4871843542cffb69e4d9\nmsgid \"To add a watermark to a |PDF| file, do the following:\"\nmsgstr \"|PDF| 파일에 워터마크를 추가하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:251 a02e5eacf1034f0fae2054ffe20904e8\nmsgid \"\"\n\"Adding watermarks is essentially as simple as adding an image at the base\"\n\" of each |PDF| page. You should ensure that the image has the required \"\n\"opacity and aspect ratio to make it look the way you need it to.\"\nmsgstr \"워터마크 추가는 기본적으로 각 |PDF| 페이지 하단에 이미지를 추가하는 것만큼 간단합니다. 필요한 불투명도와 종횡비를 갖도록 이미지를 확인해야 합니다.\"\n\n#: ../../the-basics.rst:253 d20d708a49884eba9914d117e2f10133\nmsgid \"\"\n\"In the example above a new image is created from each file reference, but\"\n\" to be more performant (by saving memory and file size) this image data \"\n\"should be referenced only once - see the code example and explanation on \"\n\":meth:`Page.insert_image` for the implementation.\"\nmsgstr \"위 예제에서는 각 파일 참조에서 새 이미지가 생성되지만, 더 성능을 높이려면(메모리와 파일 크기를 절약하기 위해) 이 이미지 데이터는 한 번만 참조해야 합니다 - 구현에 대한 코드 예제 및 설명은 :meth:`Page.insert_image` 를 참조하세요.\"\n\n#: ../../the-basics.rst:257 3d33f6e4d88f4ad0934fe5db402cbd31\nmsgid \":meth:`Page.bound`\"\nmsgstr \":meth:`Page.bound`\"\n\n#: ../../the-basics.rst:258 ../../the-basics.rst:294\n#: 289513e33a19434b93565b65bb3c2d5c fe5190d74fae437cbe633bd7b771d7ef\nmsgid \":meth:`Page.insert_image`\"\nmsgstr \":meth:`Page.insert_image`\"\n\n#: ../../the-basics.rst:267 13c93c134b884caa94bdb24bcf268c12\nmsgid \"Adding an image to a |PDF|\"\nmsgstr \"|PDF| 에 이미지 추가\"\n\n#: ../../the-basics.rst:269 4c1ed375c4bf445fbb7cbc313de62c6d\nmsgid \"To add an image to a |PDF| file, for example a logo, do the following:\"\nmsgstr \"|PDF| 파일에 이미지(예: 로고)를 추가하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:289 de096300347c4213ba1adacf5f0db3f9\nmsgid \"\"\n\"As with the watermark example you should ensure to be more performant by \"\n\"only referencing the image once if possible - see the code example and \"\n\"explanation on :meth:`Page.insert_image`.\"\nmsgstr \"워터마크 예제와 마찬가지로 가능한 경우 이미지를 한 번만 참조하여 성능을 높이도록 해야 합니다 - 코드 예제 및 설명은 :meth:`Page.insert_image` 를 참조하세요.\"\n\n#: ../../the-basics.rst:293 8945f4f902264ba6b1269f807ddfd71e\nmsgid \":ref:`Rect<Rect>`\"\nmsgstr \":ref:`Rect<Rect>`\"\n\n#: ../../the-basics.rst:303 71949133fcb94c6f98465813be0eb404\nmsgid \"Rotating a |PDF|\"\nmsgstr \"|PDF| 회전\"\n\n#: ../../the-basics.rst:305 7e3ebb344a7348c2bf946c4795d74d92\nmsgid \"To add a rotation to a page, do the following:\"\nmsgstr \"페이지에 회전을 추가하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:320 3d4e339ae052429bb76f09916c436436\nmsgid \":meth:`Page.set_rotation`\"\nmsgstr \":meth:`Page.set_rotation`\"\n\n#: ../../the-basics.rst:328 6e2d701fd5f047cda7216925fec76fc7\nmsgid \"Cropping a |PDF|\"\nmsgstr \"|PDF| 자르기\"\n\n#: ../../the-basics.rst:330 b7c23f5face54c169824a13ca7b42f15\nmsgid \"To crop a page to a defined :ref:`Rect<Rect>`, do the following:\"\nmsgstr \"페이지를 정의된 :ref:`Rect<Rect>` 로 자르려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:345 a6b1cd0d8cad41189d7c67fabc5f334b\nmsgid \":meth:`Page.set_cropbox`\"\nmsgstr \":meth:`Page.set_cropbox`\"\n\n#: ../../the-basics.rst:354 d575dbec6b32487f8b9cf82c6e30d10c\nmsgid \":index:`Attaching Files <triple: attach;embed;file>`\"\nmsgstr \":index:`파일 첨부 <triple: attach;embed;file>`\"\n\n#: ../../the-basics.rst:356 c9c54ff0348c471ead7ff5c1018b7d28\nmsgid \"To attach another file to a page, do the following:\"\nmsgstr \"페이지에 다른 파일을 첨부하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:379 3314a0f701fc46868da9fe2bf79bdca5\nmsgid \"\"\n\"When adding the file with :meth:`Page.add_file_annot` note that the third\"\n\" parameter for the `filename` should include the actual file extension. \"\n\"Without this the attachment possibly will not be able to be recognized as\"\n\" being something which can be opened. For example, if the `filename` is \"\n\"just *\\\"attachment\\\"* when view the resulting PDF and attempting to open \"\n\"the attachment you may well get an error. However, with \"\n\"*\\\"attachment.pdf\\\"* this can be recognized and opened by PDF viewers as \"\n\"a valid file type.\"\nmsgstr \":meth:`Page.add_file_annot` 로 파일을 추가할 때 `filename` 의 세 번째 매개변수에는 실제 파일 확장자가 포함되어야 합니다. 이것이 없으면 첨부 파일이 열 수 있는 것으로 인식되지 않을 수 있습니다. 예를 들어, `filename` 이 단순히 *\\\"attachment\\\"* 인 경우 결과 PDF를 보고 첨부 파일을 열려고 하면 오류가 발생할 수 있습니다. 그러나 *\\\"attachment.pdf\\\"* 인 경우 PDF 뷰어에서 유효한 파일 타입으로 인식하고 열 수 있습니다.\"\n\n#: ../../the-basics.rst:381 b376de22c21a4a678e98898f240e4e68\nmsgid \"\"\n\"The default icon for the attachment is by default a \\\"push pin\\\", however\"\n\" you can change this by setting the `icon` parameter.\"\nmsgstr \"첨부 파일의 기본 아이콘은 기본적으로 \\\"push pin\\\" 이지만, `icon` 매개변수를 설정하여 변경할 수 있습니다.\"\n\n#: ../../the-basics.rst:385 ddad44834e324cef9b0c5a12b15fb49e\nmsgid \":ref:`Point<Point>`\"\nmsgstr \":ref:`Point<Point>`\"\n\n#: ../../the-basics.rst:386 ../../the-basics.rst:422\n#: b75a50b64e26476e944aa8754f20bf2f f27fcc6d362c42cda221464725dea5af\nmsgid \":meth:`Document.tobytes`\"\nmsgstr \":meth:`Document.tobytes`\"\n\n#: ../../the-basics.rst:387 0a0ed0f4324040aa8e444b4b4434a966\nmsgid \":meth:`Page.add_file_annot`\"\nmsgstr \":meth:`Page.add_file_annot`\"\n\n#: ../../the-basics.rst:396 2c6b15690e394abebe55eb54a8f0e9b4\nmsgid \":index:`Embedding Files <triple: attach;embed;file>`\"\nmsgstr \":index:`파일 임베드 <triple: attach;embed;file>`\"\n\n#: ../../the-basics.rst:398 566061a4f08642cf8ce04c7d8822cfb5\nmsgid \"To embed a file to a document, do the following:\"\nmsgstr \"문서에 파일을 임베드하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:418 c7fc5f4b49a94065be458d831ec56a8d\nmsgid \"\"\n\"As with :ref:`attaching files<The_Basics_Attaching_Files>`, when adding \"\n\"the file with :meth:`Document.embfile_add` note that the first parameter \"\n\"for the `filename` should include the actual file extension.\"\nmsgstr \":ref:`파일 첨부<The_Basics_Attaching_Files>` 와 마찬가지로 :meth:`Document.embfile_add` 로 파일을 추가할 때 `filename` 의 첫 번째 매개변수에는 실제 파일 확장자가 포함되어야 합니다.\"\n\n#: ../../the-basics.rst:423 e86602ef585c432bab7857de813ba158\nmsgid \":meth:`Document.embfile_add`\"\nmsgstr \":meth:`Document.embfile_add`\"\n\n#: ../../the-basics.rst:433 1dadf897eed34352b65305be6227cc68\nmsgid \"Deleting Pages\"\nmsgstr \"페이지 삭제\"\n\n#: ../../the-basics.rst:435 b2ec142ee4284464bac65150b104a3c8\nmsgid \"To delete a page from a document, do the following:\"\nmsgstr \"문서에서 페이지를 삭제하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:445 26bcb9712b45488d81fcd37a2c5338dc\nmsgid \"To delete a multiple pages from a document, do the following:\"\nmsgstr \"문서에서 여러 페이지를 삭제하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:457 2a651424c7104dda8fccdeb738d8f3d4\nmsgid \"What happens if I delete a page referred to by bookmarks or hyperlinks?\"\nmsgstr \"책갈피나 하이퍼링크가 참조하는 페이지를 삭제하면 어떻게 되나요?\"\n\n#: ../../the-basics.rst:459 268000ef67c644459cb4d5f0f21c3a0f\nmsgid \"\"\n\"A bookmark (entry in the Table of Contents) will become inactive and will\"\n\" no longer navigate to any page.\"\nmsgstr \"책갈피(목차 항목)는 비활성화되어 더 이상 어떤 페이지로도 이동하지 않습니다.\"\n\n#: ../../the-basics.rst:461 c9da611cc8bd48d69c43c3418cd4dba8\nmsgid \"\"\n\"A hyperlink will be removed from the page that contains it. The visible \"\n\"content on that page will not otherwise be changed in any way.\"\nmsgstr \"하이퍼링크는 포함된 페이지에서 제거됩니다. 해당 페이지의 표시된 콘텐츠는 다른 방식으로 변경되지 않습니다.\"\n\n#: ../../the-basics.rst:467 691f875a941741d08cb1049a5fd7fea0\nmsgid \"\"\n\"The page index is zero-based, so to delete page 10 of a document you \"\n\"would do the following `doc.delete_page(9)`.\"\nmsgstr \"페이지 인덱스는 0 기반이므로 문서의 10페이지를 삭제하려면 `doc.delete_page(9)` 를 수행합니다.\"\n\n#: ../../the-basics.rst:469 471029bcec864d5c83b56258d14c9a6b\nmsgid \"\"\n\"Similarly, `doc.delete_pages(from_page=9, to_page=14)` will delete pages \"\n\"10 - 15 inclusive.\"\nmsgstr \"마찬가지로 `doc.delete_pages(from_page=9, to_page=14)` 는 10-15페이지를 포함하여 삭제합니다.\"\n\n#: ../../the-basics.rst:474 a6edabe8375f47aab6ecea141c9de9ef\nmsgid \":meth:`Document.delete_page`\"\nmsgstr \":meth:`Document.delete_page`\"\n\n#: ../../the-basics.rst:475 dc08fba2f443449d9604c358be0f59b2\nmsgid \":meth:`Document.delete_pages`\"\nmsgstr \":meth:`Document.delete_pages`\"\n\n#: ../../the-basics.rst:483 94049f92c8ad4d6b8b0024d436ab9235\nmsgid \"Re-Arranging Pages\"\nmsgstr \"페이지 재배열\"\n\n#: ../../the-basics.rst:485 82cc8c6d56974119a12c0c709d30c2d0\nmsgid \"To change the sequence of pages, i.e. re-arrange pages, do the following:\"\nmsgstr \"페이지 순서를 변경하려면(즉, 페이지를 재배열하려면) 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:500 4c1a980fdd2442ae896528a2b043b4d7\nmsgid \":meth:`Document.move_page`\"\nmsgstr \":meth:`Document.move_page`\"\n\n#: ../../the-basics.rst:509 1b6a6d6430b64d2fa81c618aa5a36c2a\nmsgid \"Copying Pages\"\nmsgstr \"페이지 복사\"\n\n#: ../../the-basics.rst:512 703c6c326a244e3f95a5f9308a4db9f8\nmsgid \"To copy pages, do the following:\"\nmsgstr \"페이지를 복사하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:527 e0f411a53f464a6cb29477e745869390\nmsgid \":meth:`Document.copy_page`\"\nmsgstr \":meth:`Document.copy_page`\"\n\n#: ../../the-basics.rst:535 3f3ac486797b4e59a03d43dfd13d0ae9\nmsgid \"Selecting Pages\"\nmsgstr \"페이지 선택\"\n\n#: ../../the-basics.rst:538 c5e43d6789904283afdfc2c3e31f4b3e\nmsgid \"To select pages, do the following:\"\nmsgstr \"페이지를 선택하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:553 0c1c3c72d9c542d5a9fd994ca426390d\nmsgid \"\"\n\"With |PyMuPDF| you have all options to copy, move, delete or re-arrange \"\n\"the pages of a |PDF|. Intuitive methods exist that allow you to do this \"\n\"on a page-by-page level, like the :meth:`Document.copy_page` method.\"\nmsgstr \"|PyMuPDF| 를 사용하면 |PDF| 의 페이지를 복사, 이동, 삭제 또는 재배열할 수 있는 모든 옵션이 있습니다. :meth:`Document.copy_page` 메서드와 같이 페이지별로 수행할 수 있는 직관적인 메서드가 있습니다.\"\n\n#: ../../the-basics.rst:555 99b4ed9af68646628e27f7fd50ed6026\nmsgid \"\"\n\"Or you alternatively prepare a complete new page layout in form of a \"\n\":title:`Python` sequence, that contains the page numbers you want, in the\"\n\" sequence you want, and as many times as you want each page. The \"\n\"following may illustrate what can be done with :meth:`Document.select`\"\nmsgstr \"또는 원하는 페이지 번호를 원하는 순서로, 각 페이지를 원하는 횟수만큼 포함하는 :title:`Python` 시퀀스 형식으로 완전히 새로운 페이지 레이아웃을 준비할 수도 있습니다. 다음은 :meth:`Document.select` 로 수행할 수 있는 작업을 보여줍니다\"\n\n#: ../../the-basics.rst:562 6807a098f55f41e08049ad773d010494\nmsgid \"\"\n\"Now let's prepare a PDF for double-sided printing (on a printer not \"\n\"directly supporting this):\"\nmsgstr \"이제 양면 인쇄를 위한 PDF를 준비하겠습니다(이를 직접 지원하지 않는 프린터에서):\"\n\n#: ../../the-basics.rst:564 2bd6434b882a4d8db3c304ffbd3aa687\nmsgid \"\"\n\"The number of pages is given by `len(doc)` (equal to `doc.page_count`). \"\n\"The following lists represent the even and the odd page numbers, \"\n\"respectively:\"\nmsgstr \"페이지 수는 `len(doc)` (또는 `doc.page_count` 와 동일)로 제공됩니다. 다음 목록은 각각 짝수 및 홀수 페이지 번호를 나타냅니다:\"\n\n#: ../../the-basics.rst:571 293d86f017734a8ebc3c3f116fd93ed9\nmsgid \"\"\n\"This snippet creates the respective sub documents which can then be used \"\n\"to print the document:\"\nmsgstr \"이 코드 조각은 문서를 인쇄하는 데 사용할 수 있는 각 하위 문서를 생성합니다:\"\n\n#: ../../the-basics.rst:583 7c03acb1833d4a7e835b8d14d71d52a1\nmsgid \"\"\n\"For more information also have a look at this Wiki `article \"\n\"<https://github.com/pymupdf/PyMuPDF/wiki/Rearranging-Pages-of-a-PDF>`_.\"\nmsgstr \"자세한 내용은 이 Wiki `문서 <https://github.com/pymupdf/PyMuPDF/wiki/Rearranging-Pages-of-a-PDF>`_ 도 참조하세요.\"\n\n#: ../../the-basics.rst:586 54ec68649c0e4b609bbc4f4ad4e005cb\nmsgid \"\"\n\"The following example will reverse the order of all pages (**extremely \"\n\"fast:** sub-second time for the 756 pages of the :ref:`AdobeManual`):\"\nmsgstr \"다음 예제는 모든 페이지의 순서를 반대로 합니다(**매우 빠름:** :ref:`AdobeManual` 의 756페이지에 대해 1초 미만):\"\n\n#: ../../the-basics.rst:596 bb40e1408cac4faa8820273561325390\nmsgid \"\"\n\"This snippet duplicates the PDF with itself so that it will contain the \"\n\"pages *0, 1, ..., n, 0, 1, ..., n* **(extremely fast and without \"\n\"noticeably increasing the file size!)**:\"\nmsgstr \"이 코드 조각은 PDF를 자체와 중복시켜 *0, 1, ..., n, 0, 1, ..., n* 페이지를 포함하도록 합니다**(매우 빠르고 파일 크기가 눈에 띄게 증가하지 않음!)**\"\n\n#: ../../the-basics.rst:608 2c346b1ac6fe452d96ab804a995e9039\nmsgid \":meth:`Document.select`\"\nmsgstr \":meth:`Document.select`\"\n\n#: ../../the-basics.rst:619 0c4e94066fe44ad499c54211fe16aae6\nmsgid \"Adding Blank Pages\"\nmsgstr \"빈 페이지 추가\"\n\n#: ../../the-basics.rst:621 b2cff0e96799476d884ceb9a27a0a394\nmsgid \"To add a blank page, do the following:\"\nmsgstr \"빈 페이지를 추가하려면 다음을 수행합니다:\"\n\n#: ../../the-basics.rst:638 ce36fc6b536c46d4b1f018b19e714a4d\nmsgid \"Use this to create the page with another pre-defined paper format:\"\nmsgstr \"다른 사전 정의된 용지 형식으로 페이지를 만들려면 다음을 사용합니다:\"\n\n#: ../../the-basics.rst:646 7d2dc00bc025437295e6e7ac8de51e61\nmsgid \"\"\n\"The convenience function :meth:`paper_size` knows over 40 industry \"\n\"standard paper formats to choose from. To see them, inspect dictionary \"\n\":attr:`paperSizes`. Pass the desired dictionary key to :meth:`paper_size`\"\n\" to retrieve the paper dimensions. Upper and lower case is supported. If \"\n\"you append \\\"-L\\\" to the format name, the landscape version is returned.\"\nmsgstr \"편의 함수 :meth:`paper_size` 는 선택할 수 있는 40개 이상의 산업 표준 용지 형식을 알고 있습니다. 이를 보려면 딕셔너리 :attr:`paperSizes` 를 검사하세요. 원하는 딕셔너리 키를 :meth:`paper_size` 에 전달하여 용지 크기를 검색합니다. 대소문자가 지원됩니다. 형식 이름에 \\\"-L\\\" 을 추가하면 가로 방향 버전이 반환됩니다.\"\n\n#: ../../the-basics.rst:648 b44282f4ada544d1b18a337f793bbdfb\nmsgid \"\"\n\"Here is a 3-liner that creates a |PDF|: with one empty page. Its file \"\n\"size is 460 bytes:\"\nmsgstr \"다음은 빈 페이지 하나가 있는 |PDF| 를 생성하는 3줄 코드입니다. 파일 크기는 460바이트입니다:\"\n\n#: ../../the-basics.rst:659 af312c05560c44ba8fb88cf29ece1e12\nmsgid \":meth:`Document.new_page`\"\nmsgstr \":meth:`Document.new_page`\"\n\n#: ../../the-basics.rst:660 055ca7bfd52e46bda58c8e862bd8e592\nmsgid \":attr:`paperSizes`\"\nmsgstr \":attr:`paperSizes`\"\n\n#: ../../the-basics.rst:669 6ec80ca2c8344ab1b10072ee1e7ecfdf\nmsgid \"Inserting Pages with Text Content\"\nmsgstr \"텍스트 콘텐츠가 있는 페이지 삽입\"\n\n#: ../../the-basics.rst:671 7c9a1501fb5d405a9f5ad46a99f0b474\nmsgid \"\"\n\"Using the :meth:`Document.insert_page` method also inserts a new page and\"\n\" accepts the same ``width`` and ``height`` parameters. But it lets you \"\n\"also insert arbitrary text into the new page and returns the number of \"\n\"inserted lines.\"\nmsgstr \":meth:`Document.insert_page` 메서드를 사용하면 새 페이지도 삽입되고 동일한 `width` 및 `height` 매개변수를 허용합니다. 하지만 새 페이지에 임의의 텍스트를 삽입할 수 있으며 삽입된 줄 수를 반환합니다.\"\n\n#: ../../the-basics.rst:694 815fd32c08dc43ed939c0022fe0cb355\nmsgid \"\"\n\"The text parameter can be a (sequence of) string (assuming UTF-8 \"\n\"encoding). Insertion will start at :ref:`Point` (50, 72), which is one \"\n\"inch below top of page and 50 points from the left. The number of \"\n\"inserted text lines is returned.\"\nmsgstr \"텍스트 매개변수는 문자열(또는 문자열 시퀀스)일 수 있습니다(UTF-8 인코딩 가정). 삽입은 :ref:`Point` (50, 72)에서 시작되며, 이는 페이지 상단에서 1인치 아래, 왼쪽에서 50포인트입니다. 삽입된 텍스트 줄 수가 반환됩니다.\"\n\n#: ../../the-basics.rst:698 ee1877c30f20440d928f255b6b27ec30\nmsgid \":meth:`Document.insert_page`\"\nmsgstr \":meth:`Document.insert_page`\"\n\n#: ../../the-basics.rst:709 3399cdc8dfc44101b644bcf9d0619529\nmsgid \"Splitting Single Pages\"\nmsgstr \"단일 페이지 분할\"\n\n#: ../../the-basics.rst:711 1f3717fc854a40d5a0fd9753b49a88a0\nmsgid \"\"\n\"This deals with splitting up pages of a |PDF| in arbitrary pieces. For \"\n\"example, you may have a |PDF| with *Letter* format pages which you want \"\n\"to print with a magnification factor of four: each page is split up in 4 \"\n\"pieces which each going to a separate |PDF| page in *Letter* format \"\n\"again.\"\nmsgstr \"이것은 |PDF| 의 페이지를 임의의 조각으로 분할하는 것을 다룹니다. 예를 들어, 4배 확대 인쇄하려는 *Letter* 형식 페이지가 있는 |PDF| 가 있을 수 있습니다: 각 페이지는 4개 조각으로 분할되며, 각 조각은 다시 *Letter* 형식의 별도 |PDF| 페이지로 이동합니다.\"\n\n#: ../../the-basics.rst:754 ../../the-basics.rst:812\n#: 0ece8212e7b845609bb12d9e90ea10a7 e15f29ebe62e4a60a0bbbb8de5608f21\nmsgid \"Example:\"\nmsgstr \"예제:\"\n\n#: ../../the-basics.rst:762 ../../the-basics.rst:821\n#: aca3faccb4c045c097b9959629642eef b75fa5b0807b4f56bffef5b96e756cdd\nmsgid \":meth:`Page.cropbox_position`\"\nmsgstr \":meth:`Page.cropbox_position`\"\n\n#: ../../the-basics.rst:763 ../../the-basics.rst:822\n#: 0ffa92661611435b91fb6a7e14df8701 2322a38c63f947d589e9b2ec7f1f17f2\nmsgid \":meth:`Page.show_pdf_page`\"\nmsgstr \":meth:`Page.show_pdf_page`\"\n\n#: ../../the-basics.rst:773 e866676a9e9f4db28f98f0921db8b45f\nmsgid \"Combining Single Pages\"\nmsgstr \"단일 페이지 결합\"\n\n#: ../../the-basics.rst:775 66702d857bfe496f8bd6f6120c0c5137\nmsgid \"\"\n\"This deals with joining |PDF| pages to form a new |PDF| with pages each \"\n\"combining two or four original ones (also called \\\"2-up\\\", \\\"4-up\\\", \"\n\"etc.). This could be used to create booklets or thumbnail-like overviews.\"\nmsgstr \"이것은 |PDF| 페이지를 결합하여 원본 두 개 또는 네 개를 각각 결합한 페이지가 있는 새 |PDF| 를 만드는 것을 다룹니다(\\\"2-up\\\", \\\"4-up\\\" 등이라고도 함). 이것은 소책자나 썸네일 같은 개요를 만드는 데 사용할 수 있습니다.\"\n\n#: ../../the-basics.rst:831 dd61fd34be574893bee88166ee3d19f3\nmsgid \"|PDF| Encryption & Decryption\"\nmsgstr \"|PDF| 암호화 및 복호화\"\n\n#: ../../the-basics.rst:834 16ea9b1cd9f949fdab48b3c4210a4d72\nmsgid \"\"\n\"Starting with version 1.16.0, |PDF| decryption and encryption (using \"\n\"passwords) are fully supported. You can do the following:\"\nmsgstr \"버전 1.16.0부터 |PDF| 복호화 및 암호화(비밀번호 사용)가 완전히 지원됩니다. 다음을 수행할 수 있습니다:\"\n\n#: ../../the-basics.rst:836 3b6def2609e44c32be069c6362839e2f\nmsgid \"\"\n\"Check whether a document is password protected / (still) encrypted \"\n\"(:attr:`Document.needs_pass`, :attr:`Document.is_encrypted`).\"\nmsgstr \"문서가 비밀번호로 보호되어 있는지/(여전히) 암호화되어 있는지 확인합니다(:attr:`Document.needs_pass`, :attr:`Document.is_encrypted`).\"\n\n#: ../../the-basics.rst:837 ce41ab81ce8b4386a83878a416a7940a\nmsgid \"Gain access authorization to a document (:meth:`Document.authenticate`).\"\nmsgstr \"문서에 대한 액세스 권한을 얻습니다(:meth:`Document.authenticate`).\"\n\n#: ../../the-basics.rst:838 b189a7d59fa543a19cf3c17b16f8d694\nmsgid \"\"\n\"Set encryption details for PDF files using :meth:`Document.save` or \"\n\":meth:`Document.write` and\"\nmsgstr \":meth:`Document.save` 또는 :meth:`Document.write` 를 사용하여 PDF 파일의 암호화 세부 정보를 설정하고\"\n\n#: ../../the-basics.rst:840 d636f0b456a045fe96ded79e540924a6\nmsgid \"decrypt or encrypt the content\"\nmsgstr \"콘텐츠 복호화 또는 암호화\"\n\n#: ../../the-basics.rst:841 c02d51458a324504be651a75c4b42da7\nmsgid \"set password(s)\"\nmsgstr \"비밀번호 설정\"\n\n#: ../../the-basics.rst:842 a9dbedfc3d3840d2b0ddef263073ee71\nmsgid \"set the encryption method\"\nmsgstr \"암호화 방법 설정\"\n\n#: ../../the-basics.rst:843 8613c50a6710457fb64b656501a9ed53\nmsgid \"set permission details\"\nmsgstr \"권한 세부 정보 설정\"\n\n#: ../../the-basics.rst:845 4d78b28e7d8c479bb687ad0b04fea32f\nmsgid \"A PDF document may have two different passwords:\"\nmsgstr \"PDF 문서는 두 가지 다른 비밀번호를 가질 수 있습니다:\"\n\n#: ../../the-basics.rst:847 17b762c8cf4d4efba56eae14ccf0e0e6\nmsgid \"\"\n\"The **owner password** provides full access rights, including changing \"\n\"passwords, encryption method, or permission detail.\"\nmsgstr \"**소유자 비밀번호** 는 비밀번호, 암호화 방법 또는 권한 세부 정보 변경을 포함한 전체 액세스 권한을 제공합니다.\"\n\n#: ../../the-basics.rst:848 25b92c66fe7843978232636bf038bea9\nmsgid \"\"\n\"The **user password** provides access to document content according to \"\n\"the established permission details. If present, opening the |PDF| in a \"\n\"viewer will require providing it.\"\nmsgstr \"**사용자 비밀번호** 는 설정된 권한 세부 정보에 따라 문서 콘텐츠에 대한 액세스를 제공합니다. 있는 경우 뷰어에서 |PDF| 를 열려면 이를 제공해야 합니다.\"\n\n#: ../../the-basics.rst:850 1fc241ab15944159a3e960c912753d85\nmsgid \"\"\n\"Method :meth:`Document.authenticate` will automatically establish access \"\n\"rights according to the password used.\"\nmsgstr \":meth:`Document.authenticate` 메서드는 사용된 비밀번호에 따라 액세스 권한을 자동으로 설정합니다.\"\n\n#: ../../the-basics.rst:852 5a8ee082646145f0af795201a5cf3f2c\nmsgid \"\"\n\"The following snippet creates a new |PDF| and encrypts it with separate \"\n\"user and owner passwords. Permissions are granted to print, copy and \"\n\"annotate, but no changes are allowed to someone authenticating with the \"\n\"user password.\"\nmsgstr \"다음 코드 조각은 새 |PDF| 를 생성하고 별도의 사용자 및 소유자 비밀번호로 암호화합니다. 인쇄, 복사 및 주석 달기 권한이 부여되지만 사용자 비밀번호로 인증하는 사람에게는 변경이 허용되지 않습니다.\"\n\n#: ../../the-basics.rst:886 bc1d33f5c72f4b7c91414475ea9319ad\nmsgid \"\"\n\"Opening this document with some viewer (Nitro Reader 5) reflects these \"\n\"settings:\"\nmsgstr \"일부 뷰어(Nitro Reader 5)로 이 문서를 열면 이러한 설정이 반영됩니다:\"\n\n#: ../../the-basics.rst:890 8d0714fc6e9b483da17392fad5a08ef9\nmsgid \"\"\n\"**Decrypting** will automatically happen on save as before when no \"\n\"encryption parameters are provided.\"\nmsgstr \"**복호화** 는 암호화 매개변수가 제공되지 않으면 이전과 같이 저장 시 자동으로 발생합니다.\"\n\n#: ../../the-basics.rst:892 5ad13206208e4f04ab1f73c460b95b06\nmsgid \"\"\n\"To **keep the encryption method** of a PDF save it using \"\n\"`encryption=pymupdf.PDF_ENCRYPT_KEEP`. If `doc.can_save_incrementally() \"\n\"== True`, an incremental save is also possible.\"\nmsgstr \"PDF의 **암호화 방법을 유지** 하려면 `encryption=pymupdf.PDF_ENCRYPT_KEEP` 를 사용하여 저장합니다. `doc.can_save_incrementally() == True` 인 경우 증분 저장도 가능합니다.\"\n\n#: ../../the-basics.rst:894 ea683283b4ae4990996434cbfc824108\nmsgid \"\"\n\"To **change the encryption method** specify the full range of options \"\n\"above (`encryption`, `owner_pw`, `user_pw`, `permissions`). An \"\n\"incremental save is **not possible** in this case.\"\nmsgstr \"**암호화 방법을 변경** 하려면 위의 전체 옵션 범위(`encryption`, `owner_pw`, `user_pw`, `permissions`)를 지정합니다. 이 경우 증분 저장은 **불가능** 합니다.\"\n\n#: ../../the-basics.rst:898 6b214aa29bc543f4acbac8c3cd3481b0\nmsgid \":meth:`Document.save`\"\nmsgstr \":meth:`Document.save`\"\n\n#: ../../the-basics.rst:907 a57f259ce92445d6a5d6c2862dc3cf54\nmsgid \"Extracting Tables from a :title:`Page`\"\nmsgstr \":title:`Page` 에서 테이블 추출\"\n\n#: ../../the-basics.rst:909 6f9e7f86d5ac46e3b9825c17b82571e4\nmsgid \"Tables can be found and extracted from any document :ref:`Page`.\"\nmsgstr \"테이블은 모든 문서 :ref:`Page` 에서 찾고 추출할 수 있습니다.\"\n\n#: ../../the-basics.rst:928 b7494b5442a14995a5d2119082615ca8\nmsgid \":meth:`Page.find_tables`\"\nmsgstr \":meth:`Page.find_tables`\"\n\n#: ../../the-basics.rst:933 c890052d477340849a65eeee67960e53\nmsgid \"\"\n\"There is also the `pdf2docx extract tables method`_ which is capable of \"\n\"table extraction if you prefer.\"\nmsgstr \"원하는 경우 테이블 추출이 가능한 `pdf2docx extract tables method`_ 도 있습니다.\"\n\n#: ../../the-basics.rst:942 a282cebe140b45f5b2ed5299e377820a\nmsgid \"Getting Page Links\"\nmsgstr \"페이지 링크 가져오기\"\n\n#: ../../the-basics.rst:944 65729bc707934b5eb43017e9a7ccf13f\nmsgid \"Links can be extracted from a :ref:`Page` to return :ref:`Link` objects.\"\nmsgstr \"링크는 :ref:`Page` 에서 추출하여 :ref:`Link` 객체를 반환할 수 있습니다.\"\n\n#: ../../the-basics.rst:964 a413c62db71c4a03bcf604d1cbb23495\nmsgid \":meth:`Page.first_link`\"\nmsgstr \":meth:`Page.first_link`\"\n\n#: ../../the-basics.rst:973 9c52975671c8427abba8f3c2386f6cfd\nmsgid \"Getting All Annotations from a Document\"\nmsgstr \"문서에서 모든 주석 가져오기\"\n\n#: ../../the-basics.rst:975 6c049fc7e04c48738c8b0a947179c35a\nmsgid \"\"\n\"Annotations (:ref:`Annot`) on pages can be retrieved with the \"\n\"`page.annots()` method.\"\nmsgstr \"페이지의 주석(:ref:`Annot`)은 `page.annots()` 메서드로 검색할 수 있습니다.\"\n\n#: ../../the-basics.rst:990 02ac755f074b4ae28b2dde5d67b4474f\nmsgid \":meth:`Page.annots`\"\nmsgstr \":meth:`Page.annots`\"\n\n#: ../../the-basics.rst:1000 3d4556c1d28240f2aa6a1c395fc1a1a9\nmsgid \"Redacting content from a |PDF|\"\nmsgstr \"|PDF| 에서 콘텐츠 편집\"\n\n#: ../../the-basics.rst:1002 d99eb5ab89464e8d97d4fc7e46651604\nmsgid \"\"\n\"Redactions are special types of annotations which can be marked onto a \"\n\"document page to denote an area on the page which should be securely \"\n\"removed. After marking an area with a rectangle then this area will be \"\n\"marked for *redaction*, once the redaction is *applied* then the content \"\n\"is securely removed.\"\nmsgstr \"편집은 문서 페이지에 표시되어 안전하게 제거해야 하는 페이지 영역을 나타내는 특수한 유형의 주석입니다. 사각형으로 영역을 표시한 후 이 영역은 *편집* 으로 표시되며, 편집이 *적용* 되면 콘텐츠가 안전하게 제거됩니다.\"\n\n#: ../../the-basics.rst:1004 223f6cd8cecb4da98e5dd318031c8fda\nmsgid \"\"\n\"For example if we wanted to redact all instances of the name \\\"Jane Doe\\\"\"\n\" from a document we could do the following:\"\nmsgstr \"예를 들어 문서에서 이름 \\\"Jane Doe\\\" 의 모든 인스턴스를 편집하려면 다음을 수행할 수 있습니다:\"\n\n#: ../../the-basics.rst:1032 62dd2d2bb85640b2b62115053f61669a\nmsgid \"\"\n\"Another example could be redacting an area of a page, but not to redact \"\n\"any line art (i.e. vector graphics) within the defined area, by setting a\"\n\" parameter flag as follows:\"\nmsgstr \"다른 예제는 페이지의 영역을 편집하되, 다음처럼 매개변수 플래그를 설정하여 정의된 영역 내의 선 아트(즉, 벡터 그래픽)는 편집하지 않는 것입니다:\"\n\n#: ../../the-basics.rst:1063 d9d9f830754d466387849b71b4085d14\nmsgid \"\"\n\"Once a redacted version of a document is saved then the redacted content \"\n\"in the |PDF| is *irretrievable*. Thus, a redacted area in a document \"\n\"removes text and graphics completely from that area.\"\nmsgstr \"문서의 편집된 버전이 저장되면 |PDF| 의 편집된 콘텐츠는 *복구할 수 없습니다*. 따라서 문서의 편집된 영역은 해당 영역에서 텍스트와 그래픽을 완전히 제거합니다.\"\n\n#: ../../the-basics.rst:1070 946a2796985d485fb5e2ed7acc4289e8\nmsgid \"\"\n\"The are a few options for creating and applying redactions to a page, for\"\n\" the full API details to understand the parameters to control these \"\n\"options refer to the API reference.\"\nmsgstr \"페이지에 편집을 생성하고 적용하는 몇 가지 옵션이 있습니다. 이러한 옵션을 제어하는 매개변수를 이해하려면 전체 API 세부 정보는 API 참조를 참조하세요.\"\n\n#: ../../the-basics.rst:1074 548f9c1e5ac243f8b4055e2a34c65166\nmsgid \":meth:`Page.add_redact_annot`\"\nmsgstr \":meth:`Page.add_redact_annot`\"\n\n#: ../../the-basics.rst:1076 47c9ad1997a44ad7b9d0ef477ee10755\nmsgid \":meth:`Page.apply_redactions`\"\nmsgstr \":meth:`Page.apply_redactions`\"\n\n#: ../../the-basics.rst:1086 1a162b81c4bf4f65abc57893d5ffe457\nmsgid \"Converting PDF Documents\"\nmsgstr \"PDF 문서 변환\"\n\n#: ../../the-basics.rst:1088 72cd004015184e5c91130763bcf42e8b\nmsgid \"\"\n\"We recommend the pdf2docx_ library which uses |PyMuPDF| and the **python-\"\n\"docx** library to provide simple document conversion from |PDF| to \"\n\"**DOCX** format.\"\nmsgstr \"|PyMuPDF| 와 **python-docx** 라이브러리를 사용하여 |PDF| 에서 **DOCX** 형식으로 간단한 문서 변환을 제공하는 pdf2docx_ 라이브러리를 권장합니다.\"\n\n#: ../../footer.rst:48 3e0afdfbfd574b1daaa229594686200d\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n#~ msgid \"\"\n#~ \"Using the :meth:`Document.insert_page` method \"\n#~ \"also inserts a new page and \"\n#~ \"accepts the same `width` and `height`\"\n#~ \" parameters. But it lets you also \"\n#~ \"insert arbitrary text into the new \"\n#~ \"page and returns the number of \"\n#~ \"inserted lines.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/tools.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 0d73a14a6d9b419f84fde1e0a7e33dfb\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 921ceade773644d4b48019b5e3890fb7\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 a82f7fcc28444c4fb146f56d5780eff7\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../tools.rst:6 bf1306c6f8b244acaf911ab721a197e6\nmsgid \"Tools\"\nmsgstr \"Tools\"\n\n#: ../../tools.rst:8 d6c5d72a09a14bd5b21c5508eee3c250\nmsgid \"\"\n\"This class is a collection of utility methods and attributes, mainly \"\n\"around memory management. To simplify and speed up its use, it is \"\n\"automatically instantiated under the name *TOOLS* when PyMuPDF is \"\n\"imported.\"\nmsgstr \"이 클래스는 주로 메모리 관리와 관련된 유틸리티 메서드 및 속성의 모음입니다. 사용을 단순화하고 속도를 높이기 위해 PyMuPDF가 가져올 때 *TOOLS* 라는 이름으로 자동 인스턴스화됩니다.\"\n\n#: ../../tools.rst:11 9f4695034d1a41088a1a1d353f6e4809\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../tools.rst:11 f90fa89b5ac8455297a7e999b318a95d\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../tools.rst:13 3b8fa8bde4af4703bd9f495bf42f0357\nmsgid \":meth:`Tools.gen_id`\"\nmsgstr \":meth:`Tools.gen_id`\"\n\n#: ../../tools.rst:13 f4df8c5ade854c22b113521c4432ad43\nmsgid \"generate a unique identifier\"\nmsgstr \"고유 식별자 생성\"\n\n#: ../../tools.rst:14 f8432b4a73fd4daebad6cf69ee75d4d4\nmsgid \":meth:`Tools.store_shrink`\"\nmsgstr \":meth:`Tools.store_shrink`\"\n\n#: ../../tools.rst:14 8e71bc4d1dff4fffab79133c5adb84ef\nmsgid \"shrink the storables cache [#f1]_\"\nmsgstr \"저장 가능한 캐시 축소 [#f1]_\"\n\n#: ../../tools.rst:15 00c0e3852ea44f5ea91c82ec35aed5c6\nmsgid \":meth:`Tools.mupdf_warnings`\"\nmsgstr \":meth:`Tools.mupdf_warnings`\"\n\n#: ../../tools.rst:15 6c729a59131c47e3991d378e1a1d7cf5\nmsgid \"return the accumulated MuPDF warnings\"\nmsgstr \"누적된 MuPDF 경고 반환\"\n\n#: ../../tools.rst:16 7c9ee72296df4159918174ed60bb239f\nmsgid \":meth:`Tools.mupdf_display_errors`\"\nmsgstr \":meth:`Tools.mupdf_display_errors`\"\n\n#: ../../tools.rst:16 ad79443c20664a909cafe94ef8993c2e\nmsgid \"control whether MuPDF errors are displayed as messages.\"\nmsgstr \"MuPDF 오류를 메시지로 표시할지 제어합니다.\"\n\n#: ../../tools.rst:17 a3c989deda0d478a8f40594bf7839b13\nmsgid \":meth:`Tools.mupdf_display_warnings`\"\nmsgstr \":meth:`Tools.mupdf_display_warnings`\"\n\n#: ../../tools.rst:17 3331b000061f4a199137b54996d28f55\nmsgid \"control whether MuPDF warnings are displayed as messages.\"\nmsgstr \"MuPDF 경고를 메시지로 표시할지 제어합니다.\"\n\n#: ../../tools.rst:18 f77ae8fb589148f0bf492ce7a1e42572\nmsgid \":meth:`Tools.reset_mupdf_warnings`\"\nmsgstr \":meth:`Tools.reset_mupdf_warnings`\"\n\n#: ../../tools.rst:18 2cd40e7b15e749f7ba4befb2c7516c7e\nmsgid \"empty MuPDF warnings/errors message buffer.\"\nmsgstr \"MuPDF 경고/오류 메시지 버퍼 비우기.\"\n\n#: ../../tools.rst:19 4447fb5926bd4ba7bec76e747bab9297\nmsgid \":meth:`Tools.set_aa_level`\"\nmsgstr \":meth:`Tools.set_aa_level`\"\n\n#: ../../tools.rst:19 2e6c524419ac41e9a6900f4809d65d99\nmsgid \"set the anti-aliasing values\"\nmsgstr \"안티앨리어싱 값 설정\"\n\n#: ../../tools.rst:20 a2dafc1f04fb468e927711809b1b4abb\nmsgid \":meth:`Tools.set_annot_stem`\"\nmsgstr \":meth:`Tools.set_annot_stem`\"\n\n#: ../../tools.rst:20 ee82321884b340e6a4b6fcffc62f8557\nmsgid \"set the prefix of new annotation / link ids\"\nmsgstr \"새 주석/링크 ID의 접두사 설정\"\n\n#: ../../tools.rst:21 c1bc06eb490b40dab6174b41d9a9ee6c\nmsgid \":meth:`Tools.set_small_glyph_heights`\"\nmsgstr \":meth:`Tools.set_small_glyph_heights`\"\n\n#: ../../tools.rst:21 15946a92e17a460a9c36b31c32fe3247\nmsgid \"search and extract using small bbox heights\"\nmsgstr \"작은 bbox 높이를 사용하여 검색 및 추출\"\n\n#: ../../tools.rst:22 8ecbbd2dd4e14e78a91df8d330c13ff6\nmsgid \":meth:`Tools.set_subset_fontnames`\"\nmsgstr \":meth:`Tools.set_subset_fontnames`\"\n\n#: ../../tools.rst:22 4fa566e4c99645d999c63acedee77f82\nmsgid \"control suppression of subset fontname tags\"\nmsgstr \"서브셋 글꼴 이름 태그 억제 제어\"\n\n#: ../../tools.rst:23 61d6e34abc994469a66c945c3a08e615\nmsgid \":meth:`Tools.show_aa_level`\"\nmsgstr \":meth:`Tools.show_aa_level`\"\n\n#: ../../tools.rst:23 a7fd746934534e9d831b150cfe0481c9\nmsgid \"return the anti-aliasing values\"\nmsgstr \"안티앨리어싱 값 반환\"\n\n#: ../../tools.rst:24 c9363164a1784bcaa8761a54aff46d1d\nmsgid \":meth:`Tools.unset_quad_corrections`\"\nmsgstr \":meth:`Tools.unset_quad_corrections`\"\n\n#: ../../tools.rst:24 5f3c02c8cfbd421e94b18e090cd74703\nmsgid \"disable PyMuPDF-specific code\"\nmsgstr \"PyMuPDF 전용 코드 비활성화\"\n\n#: ../../tools.rst:25 651ff5c6373f471e8d008e9c405305ab\nmsgid \":attr:`Tools.fitz_config`\"\nmsgstr \":attr:`Tools.fitz_config`\"\n\n#: ../../tools.rst:25 b9e06f68f97a4ae1bbd309ad39720d5d\nmsgid \"configuration settings of PyMuPDF\"\nmsgstr \"PyMuPDF의 구성 설정\"\n\n#: ../../tools.rst:26 4df2a633c6da421f9959024a3d94fa3f\nmsgid \":attr:`Tools.store_maxsize`\"\nmsgstr \":attr:`Tools.store_maxsize`\"\n\n#: ../../tools.rst:26 122b22e68967478289e3a595b9e4e8f7\nmsgid \"maximum storables cache size\"\nmsgstr \"최대 저장 가능한 캐시 크기\"\n\n#: ../../tools.rst:27 d7402c339e7e41708fd85b9e49948078\nmsgid \":attr:`Tools.store_size`\"\nmsgstr \":attr:`Tools.store_size`\"\n\n#: ../../tools.rst:27 14ccf353f0934125951cc340919573ee\nmsgid \"current storables cache size\"\nmsgstr \"현재 저장 가능한 캐시 크기\"\n\n#: ../../tools.rst:30 2128d557bf1f4f3d9d16ad8e9dba7f05\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../tools.rst:36 189938171e2b49469e4180e2f35aa327\nmsgid \"\"\n\"A convenience method returning a unique positive integer which will \"\n\"increase by 1 on every invocation. Example usages include creating unique\"\n\" keys in databases - its creation should be faster than using timestamps \"\n\"by an order of magnitude.\"\nmsgstr \"호출할 때마다 1씩 증가하는 고유한 양의 정수를 반환하는 편의 메서드입니다. 사용 예에는 데이터베이스에서 고유 키 생성이 포함됩니다. 생성은 타임스탬프 사용보다 한 자릿수 빠를 수 있습니다.\"\n\n#: ../../tools.rst:38 695deea765974c6fad7f3e3815d0a10f\nmsgid \"\"\n\"MuPDF has dropped support for this in v1.14.0, so we have re-implemented \"\n\"a similar function with the following differences:\"\nmsgstr \"MuPDF는 v1.14.0에서 이것에 대한 지원을 중단했으므로 다음과 같은 차이점이 있는 유사한 함수를 다시 구현했습니다:\"\n\n#: ../../tools.rst:40 a683185479de4917b28d0da3b150aeb8\nmsgid \"\"\n\"It is not part of MuPDF's global context and not threadsafe (not an issue\"\n\" because we do not support threads in PyMuPDF anyway).\"\nmsgstr \"MuPDF의 전역 컨텍스트의 일부가 아니며 스레드 안전하지 않습니다(PyMuPDF에서 어쨌든 스레드를 지원하지 않으므로 문제가 되지 않습니다).\"\n\n#: ../../tools.rst:41 1b2ba6f48de24451a18b344a30157fbd\nmsgid \"\"\n\"It is implemented as *int*. This means that the maximum number is \"\n\"*sys.maxsize*. Should this number ever be exceeded, the counter starts \"\n\"over again at 1.\"\nmsgstr \"*int* 로 구현됩니다. 즉, 최대 숫자는 *sys.maxsize* 입니다. 이 숫자가 초과되면 카운터가 1부터 다시 시작합니다.\"\n\n#: ../../tools.rst 4a3706449679419cbfe46da4fca67368\n#: 4b21a59b097141b5aaf0f44b355bd101 5672ab6b4aba48c892de4d5bb4e0f0b9\n#: 6669bbdf4a3e4020a1d9b48bff99e268 957464664fbc40f0af479085467effc0\n#: 9990614cbe3041348193e004172104db 999752762ad24ea4bf641bfb8ad2f43f\n#: c24f35275eaf4e4192cf718cc1f06dbc e55479e7313947a092977c725c75a395\n#: e919810950e6418e9d92a82349a27cc5\nmsgid \"Return type\"\nmsgstr \"반환 유형\"\n\n#: ../../tools.rst 07f96f9c40e24f1993747e0c10a8eff6\n#: 226fe9b32c914b299f5fbc681e42ffc1 22d12df8c6e44432b1b8c0ca643fe26b\n#: 6bd8faa6d20a40a2a3317b0b6c56695c 95ff0c78ce0449998879214817772a0f\n#: a12efba073594882b138ec467749be24 b15ef08627884b7d9cb926fae2c74680\n#: d317ebc8557f4d41bb1a58c902624a43 de51e2f78e304d46be9085659f5175b0\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../tools.rst:44 cf26039ee2174ec4a0622c0822a413bb\nmsgid \"a unique positive integer.\"\nmsgstr \"고유한 양의 정수.\"\n\n#: ../../tools.rst:49 329f36f70579439ea15f22b38c11d02a\nmsgid \"New in v1.18.6\"\nmsgstr \"v1.18.6에서 새로 추가됨\"\n\n#: ../../tools.rst:51 9db0524a2e0b4842a9c038c8912cd9d8\nmsgid \"Set or inquire the prefix for the id of new annotations, fields or links.\"\nmsgstr \"새 주석, 필드 또는 링크의 ID 접두사를 설정하거나 조회합니다.\"\n\n#: ../../tools.rst 07fc0d2c71f440218ad32d0fa55bd668\n#: 0ac957fb86d34012bc3ca235b75a2815 13711810c96c4b3eba0c108d0199a0a7\n#: 1d1396015b5247a5bd6c115fb3673828 3c06afcb1d6a424383b91978fc6206bc\n#: 631e43e526dd46998258d5316be56c67 6605936ea7ec4e80b4bbea17b256c74d\n#: 6fee094bef9d4193923a723c70f17922 ddd35b40d05a410cb68e69625771ba39\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../tools.rst:53 4b1ab23b0f98420db4907311dec28fb1\nmsgid \"\"\n\"if omitted, the current value is returned, default is \\\"fitz\\\". \"\n\"Annotations, fields / widgets and links technically are subtypes of the \"\n\"same type of object (`/Annot`) in PDF documents. An `/Annot` object may \"\n\"be given a unique identifier within a page. For each of the applicable \"\n\"subtypes, PyMuPDF generates identifiers \\\"stem-Annn\\\", \\\"stem-Wnnn\\\" or \"\n\"\\\"stem-Lnnn\\\" respectively. The number \\\"nnn\\\" is used to enforce the \"\n\"required uniqueness.\"\nmsgstr \"생략하면 현재 값이 반환되며, 기본값은 \\\"fitz\\\"입니다. 주석, 필드/위젯 및 링크는 기술적으로 PDF 문서에서 동일한 객체 유형(`/Annot`)의 하위 유형입니다. `/Annot` 객체는 페이지 내에서 고유 식별자를 가질 수 있습니다. 각 적용 가능한 하위 유형에 대해 PyMuPDF는 각각 \\\"stem-Annn\\\", \\\"stem-Wnnn\\\" 또는 \\\"stem-Lnnn\\\" 식별자를 생성합니다. 숫자 \\\"nnn\\\"은 필요한 고유성을 강제하는 데 사용됩니다.\"\n\n#: ../../tools.rst:56 4f61028eee9146b292fb1b2405da09d1\nmsgid \"the current value.\"\nmsgstr \"현재 값.\"\n\n#: ../../tools.rst:61 3cb17a9bd0814e1687e04154eec0593c\nmsgid \"New in v1.18.5\"\nmsgstr \"v1.18.5에서 새로 추가됨\"\n\n#: ../../tools.rst:63 217da1303cbb4b13b6837e9ca5541ce0\nmsgid \"\"\n\"Set or inquire reduced bbox heights in text extract and text search \"\n\"methods.\"\nmsgstr \"텍스트 추출 및 텍스트 검색 메서드에서 축소된 bbox 높이를 설정하거나 조회합니다.\"\n\n#: ../../tools.rst:65 56c84534f6434dc8841353567d8b453e\nmsgid \"\"\n\"if omitted or `None`, the current setting is returned. For other values \"\n\"the *bool()* function is applied to set a global variable. If `True`, \"\n\":meth:`Page.search_for` and :meth:`Page.get_text` methods return \"\n\"character, span, line or block bboxes that have a height of *font size*. \"\n\"If `False` (standard setting when PyMuPDF is imported), bbox height will \"\n\"be based on font properties and normally equal *line height*.\"\nmsgstr \"생략하거나 `None` 이면 현재 설정이 반환됩니다. 다른 값의 경우 *bool()* 함수가 적용되어 전역 변수가 설정됩니다. `True` 인 경우 :meth:`Page.search_for` 및 :meth:`Page.get_text` 메서드는 *글꼴 크기* 의 높이를 가진 문자, 스팬, 줄 또는 블록 bbox를 반환합니다. `False` 인 경우(PyMuPDF를 가져올 때의 표준 설정) bbox 높이는 글꼴 속성을 기반으로 하며 일반적으로 *줄 높이* 와 같습니다.\"\n\n#: ../../tools.rst:68 ../../tools.rst:81 ../../tools.rst:95\n#: a176f0944378445b9d91fe21cb93ad4d d1b2c5f192854ac09a19db50d3b38655\n#: f628ee815a1c4d908896ef7b8f14b847\nmsgid \"``True`` or ``False``.\"\nmsgstr \"``True`` 또는 ``False``.\"\n\n#: ../../tools.rst:70 808cb746a7f74b23b2eccf918a1aee94\nmsgid \"\"\n\"Text extraction options \\\"xml\\\", \\\"xhtml\\\" and \\\"html\\\", which directly \"\n\"wrap MuPDF code, are not influenced by this.\"\nmsgstr \"MuPDF 코드를 직접 래핑하는 텍스트 추출 옵션 \\\"xml\\\", \\\"xhtml\\\" 및 \\\"html\\\"은 이것의 영향을 받지 않습니다.\"\n\n#: ../../tools.rst:74 897746f738b94bc295467ea1ebcea01b\nmsgid \"New in v1.18.9\"\nmsgstr \"v1.18.9에서 새로 추가됨\"\n\n#: ../../tools.rst:76 744e708191de4faa9c2a7dade121573a\nmsgid \"Control suppression of subset fontname tags in text extractions.\"\nmsgstr \"텍스트 추출에서 서브셋 글꼴 이름 태그 억제를 제어합니다.\"\n\n#: ../../tools.rst:78 59d2a8ce838b418a8dc500d85140932e\nmsgid \"\"\n\"if omitted / `None`, the current setting is returned. Arguments \"\n\"evaluating to `True` or `False` set a global variable. If `True`, options\"\n\" \\\"dict\\\", \\\"json\\\", \\\"rawdict\\\" and \\\"rawjson\\\" will return e.g. \"\n\"`\\\"NOHSJV+Calibri-Light\\\"`, otherwise only `\\\"Calibri-Light\\\"` (the \"\n\"default). The setting remains in effect until changed again.\"\nmsgstr \"생략/`None` 이면 현재 설정이 반환됩니다. `True` 또는 `False` 로 평가되는 인수는 전역 변수를 설정합니다. `True` 인 경우 옵션 \\\"dict\\\", \\\"json\\\", \\\"rawdict\\\" 및 \\\"rawjson\\\"은 예를 들어 `\\\"NOHSJV+Calibri-Light\\\"` 를 반환하고, 그렇지 않으면 `\\\"Calibri-Light\\\"` 만 반환합니다(기본값). 설정은 다시 변경될 때까지 유효합니다.\"\n\n#: ../../tools.rst:83 d6465691fb404e9f9138143abb284794\nmsgid \"\"\n\"Except mentioned above, no other text extraction variants are influenced \"\n\"by this. This is especially true for the options \\\"xml\\\", \\\"xhtml\\\" and \"\n\"\\\"html\\\", which are based on MuPDF code. They extract the font name \"\n\"`\\\"Calibri-Light\\\"`, or even just the **family** name -- `Calibri` in \"\n\"this example.\"\nmsgstr \"위에서 언급한 것 외에는 다른 텍스트 추출 변형은 이것의 영향을 받지 않습니다. 이것은 특히 MuPDF 코드를 기반으로 하는 옵션 \\\"xml\\\", \\\"xhtml\\\" 및 \\\"html\\\"에 해당합니다. 이들은 글꼴 이름 `\\\"Calibri-Light\\\"` 또는 **패밀리** 이름만 추출합니다 -- 이 예에서는 `Calibri` 입니다.\"\n\n#: ../../tools.rst:88 d588b77e57cf47edadda3e5a2bd2640c\nmsgid \"New in v1.18.10\"\nmsgstr \"v1.18.10에서 새로 추가됨\"\n\n#: ../../tools.rst:90 a2f363e88df54db6bf8ab0004f895156\nmsgid \"\"\n\"Enable / disable PyMuPDF-specific code, that tries to rebuild valid \"\n\"character quads when encountering nonsense in :meth:`Page.get_text` text \"\n\"extractions. This code depends on certain font properties (ascender and \"\n\"descender), which do not exist in rare situations and cause segmentation \"\n\"faults when trying to access them. This method sets a global parameter in\"\n\" PyMuPDF, which suppresses execution of this code.\"\nmsgstr \"PyMuPDF 전용 코드를 활성화/비활성화합니다. 이 코드는 :meth:`Page.get_text` 텍스트 추출에서 의미 없는 내용을 만날 때 유효한 문자 quad를 재구성하려고 시도합니다. 이 코드는 특정 글꼴 속성(ascender 및 descender)에 의존하며, 이는 드문 상황에서 존재하지 않으며 접근하려고 할 때 세그멘테이션 오류를 일으킵니다. 이 메서드는 PyMuPDF에서 전역 매개변수를 설정하여 이 코드의 실행을 억제합니다.\"\n\n#: ../../tools.rst:92 d5e3272b930e4822a2e6c4d5e66a011b\nmsgid \"\"\n\"if omitted or `None`, the current setting is returned. For other values \"\n\"the *bool()* function is applied to set a global variable. If `True`, \"\n\"PyMuPDF will not try to access the resp. font properties and use values \"\n\"`ascender=0.8` and `descender=-0.2` instead.\"\nmsgstr \"생략하거나 `None` 이면 현재 설정이 반환됩니다. 다른 값의 경우 *bool()* 함수가 적용되어 전역 변수가 설정됩니다. `True` 인 경우 PyMuPDF는 해당 글꼴 속성에 접근하려고 시도하지 않고 대신 `ascender=0.8` 및 `descender=-0.2` 값을 사용합니다.\"\n\n#: ../../tools.rst:100 333a61c7d142433ab4fd0f13a7aabc3c\nmsgid \"Reduce the storables cache by a percentage of its current size.\"\nmsgstr \"저장 가능한 캐시를 현재 크기의 백분율로 줄입니다.\"\n\n#: ../../tools.rst:102 5790eaa60b4f4f4cadc19ece9d505603\nmsgid \"\"\n\"the percentage of current size to free. If 100+ the store will be \"\n\"emptied, if zero, nothing will happen. MuPDF's caching strategy is \"\n\"\\\"least recently used\\\", so low-usage elements get deleted first.\"\nmsgstr \"해제할 현재 크기의 백분율. 100 이상이면 저장소가 비워지고, 0이면 아무 일도 일어나지 않습니다. MuPDF의 캐싱 전략은 \\\"최근에 사용되지 않은 것\\\"이므로 사용 빈도가 낮은 요소가 먼저 삭제됩니다.\"\n\n#: ../../tools.rst:105 1b9c6e1ac6134c118b552c8a38a7587a\nmsgid \"\"\n\"the new current store size. Depending on the situation, the size \"\n\"reduction may be larger than the requested percentage.\"\nmsgstr \"새로운 현재 저장소 크기. 상황에 따라 크기 감소가 요청된 백분율보다 클 수 있습니다.\"\n\n#: ../../tools.rst:109 ../../tools.rst:119 5be5f274ce2740e89346b52c7e37e06a\n#: b90faa6a9e97498798492c9d79a9bf6d\nmsgid \"New in version 1.16.14\"\nmsgstr \"버전 1.16.14에서 새로 추가됨\"\n\n#: ../../tools.rst:111 1f5fae3d0c1e48c8a312f344dfa41fc0\nmsgid \"\"\n\"Return the current anti-aliasing values. These values control the \"\n\"rendering quality of graphics and text elements.\"\nmsgstr \"현재 안티앨리어싱 값을 반환합니다. 이 값들은 그래픽 및 텍스트 요소의 렌더링 품질을 제어합니다.\"\n\n#: ../../tools.rst:114 e6976bc95bab4023b63ca1064c6a68ca\nmsgid \"\"\n\"A dictionary with the following initial content: `{'graphics': 8, 'text':\"\n\" 8, 'graphics_min_line_width': 0.0}`.\"\nmsgstr \"다음 초기 내용을 가진 딕셔너리: `{'graphics': 8, 'text': 8, 'graphics_min_line_width': 0.0}`.\"\n\n#: ../../tools.rst:121 911a1d5a1cb24741a60e13fc35d16874\nmsgid \"\"\n\"Set the new number of bits to use for anti-aliasing. The same value is \"\n\"taken currently for graphics and text rendering. This might change in a \"\n\"future MuPDF release.\"\nmsgstr \"안티앨리어싱에 사용할 새로운 비트 수를 설정합니다. 현재 그래픽 및 텍스트 렌더링에 동일한 값이 사용됩니다. 이것은 향후 MuPDF 릴리스에서 변경될 수 있습니다.\"\n\n#: ../../tools.rst:123 926fa10830264d0c8cfbe04143b5486e\nmsgid \"\"\n\"an integer ranging between 0 and 8. Value outside this range will be \"\n\"silently changed to valid values. The value will remain in effect \"\n\"throughout the current session or until changed again.\"\nmsgstr \"0과 8 사이의 정수. 이 범위를 벗어난 값은 자동으로 유효한 값으로 변경됩니다. 값은 현재 세션 동안 또는 다시 변경될 때까지 유효합니다.\"\n\n#: ../../tools.rst:128 ../../tools.rst:167 144d6b730a8649498527dfd19b461f43\n#: 3a2e5f71bfd04dd5a13298d81dc0c38c\nmsgid \"New in version 1.16.0\"\nmsgstr \"버전 1.16.0에서 새로 추가됨\"\n\n#: ../../tools.rst:130 2d91e313160b448ea59abdf6c66b4a0d\nmsgid \"Empty MuPDF warnings message buffer.\"\nmsgstr \"MuPDF 경고 메시지 버퍼 비우기.\"\n\n#: ../../tools.rst:135 92b7764848884178b4a41b5d1ff2caa3\nmsgid \"Control whether MuPDF errors should be displayed as |PyMuPDF| messages.\"\nmsgstr \"MuPDF 오류를 |PyMuPDF| 메시지로 표시할지 제어합니다.\"\n\n#: ../../tools.rst:138 ../../tools.rst:154 1d6bb3c5c84647d58a7d5ed4b5a92b2c\n#: e72ab3692a3e4261b45203c6bfa6fd63\nmsgid \"If `None`, the current setting is left unchanged.\"\nmsgstr \"`None` 이면 현재 설정이 변경되지 않습니다.\"\n\n#: ../../tools.rst:139 c2abcce114b8497dae07e3ea0bc60591\nmsgid \"\"\n\"Otherwise changes the current setting to `bool(value)`; if ``True``, \"\n\"future MuPDF errors will be shown as :ref:`Messages`.\"\nmsgstr \"그렇지 않으면 현재 설정을 `bool(value)` 로 변경합니다. ``True`` 인 경우 향후 MuPDF 오류가 :ref:`Messages` 로 표시됩니다.\"\n\n#: ../../tools.rst:141 a4be68a89b5d4042996ecf157036e027\nmsgid \"\"\n\"Regardless of this setting, MuPDF errors will always be stored in the \"\n\"warnings store.\"\nmsgstr \"이 설정과 관계없이 MuPDF 오류는 항상 경고 저장소에 저장됩니다.\"\n\n#: ../../tools.rst:142 ../../tools.rst:158 23ee905f3f0e48319c7c3638b644070d\n#: b94e26874cea438aa7f0653a55f1414f\nmsgid \"Upon import of |PyMuPDF| this value is ``True``.\"\nmsgstr \"|PyMuPDF| 를 가져올 때 이 값은 ``True`` 입니다.\"\n\n#: ../../tools.rst:144 ../../tools.rst:160 380a472c7f0440deadd5f2a66e36cd6d\n#: ec3080d72d284985b697f158380df6b2\nmsgid \"The current setting as ``True`` or ``False``.\"\nmsgstr \"``True`` 또는 ``False`` 로 표시된 현재 설정.\"\n\n#: ../../tools.rst:146 ../../tools.rst:162 7482f516a78043879c8c3e587e6ecbe6\n#: c135c85d22654225b7e4564087de3d01\nmsgid \"New in version 1.16.8\"\nmsgstr \"버전 1.16.8에서 새로 추가됨\"\n\n#: ../../tools.rst:151 35926b1a764d48ae80b23f5dd83f3451\nmsgid \"Control whether MuPDF warnings should be displayed as |PyMuPDF| messages.\"\nmsgstr \"MuPDF 경고를 |PyMuPDF| 메시지로 표시할지 제어합니다.\"\n\n#: ../../tools.rst:155 16b5294227bd4af28cbe50a51eb464b5\nmsgid \"\"\n\"Otherwise changes the current setting to `bool(value)`; if ``True``, \"\n\"future MuPDF warnings will be shown as :ref:`Messages`.\"\nmsgstr \"그렇지 않으면 현재 설정을 `bool(value)` 로 변경합니다. ``True`` 인 경우 향후 MuPDF 경고가 :ref:`Messages` 로 표시됩니다.\"\n\n#: ../../tools.rst:157 f7cf6d0e1c1543b09eed6f3596cc274c\nmsgid \"\"\n\"Regardless of this setting, MuPDF warnings will always be stored in the \"\n\"warnings store.\"\nmsgstr \"이 설정과 관계없이 MuPDF 경고는 항상 경고 저장소에 저장됩니다.\"\n\n#: ../../tools.rst:169 a3f7042644dd47c383bcc0f2188e0677\nmsgid \"\"\n\"Return all stored MuPDF messages as a string with interspersed line-\"\n\"breaks.\"\nmsgstr \"줄바꿈이 섞인 문자열로 저장된 모든 MuPDF 메시지를 반환합니다.\"\n\n#: ../../tools.rst:171 287a6a8e83ba40cebec9beb0cce433ad\nmsgid \"*(new in version 1.16.7)* whether to automatically empty the store.\"\nmsgstr \"*(버전 1.16.7에서 새로 추가됨)* 저장소를 자동으로 비울지 여부.\"\n\n#: ../../tools.rst:176 0b1e9109776c417d9631077a29280c56\nmsgid \"\"\n\"A dictionary containing the actual values used for configuring PyMuPDF \"\n\"and MuPDF. Also refer to the installation chapter. This is an overview of\"\n\" the keys, each of which describes the status of a support aspect.\"\nmsgstr \"PyMuPDF 및 MuPDF 구성에 사용되는 실제 값을 포함하는 딕셔너리. 설치 장도 참조하세요. 이것은 각 키가 지원 측면의 상태를 설명하는 키의 개요입니다.\"\n\n#: ../../tools.rst:179 29eef430a5db42389b1ed5ded77ee8dc\nmsgid \"**Key**\"\nmsgstr \"**키**\"\n\n#: ../../tools.rst:179 8ec8d2564994434abd178d4f3c3f4c27\nmsgid \"**Support included for ...**\"\nmsgstr \"**다음에 대한 지원 포함 ...**\"\n\n#: ../../tools.rst:181 b78162547f5b4e87a989c50674465ac3\nmsgid \"plotter-g\"\nmsgstr \"plotter-g\"\n\n#: ../../tools.rst:181 a6e78ff6069e4d3ba0c8d22a1dd3e306\nmsgid \"Gray colorspace rendering\"\nmsgstr \"회색 색 공간 렌더링\"\n\n#: ../../tools.rst:182 018d6608637142b39977343ce2007a00\nmsgid \"plotter-rgb\"\nmsgstr \"plotter-rgb\"\n\n#: ../../tools.rst:182 e760fa73ba9244e5a70d3038f62eedc0\nmsgid \"RGB colorspace rendering\"\nmsgstr \"RGB 색 공간 렌더링\"\n\n#: ../../tools.rst:183 0ebf2b22dcae46a4ac0e108cd380d920\nmsgid \"plotter-cmyk\"\nmsgstr \"plotter-cmyk\"\n\n#: ../../tools.rst:183 219cf41f7248407fb5018ae49943793b\nmsgid \"CMYK colorspcae rendering\"\nmsgstr \"CMYK 색 공간 렌더링\"\n\n#: ../../tools.rst:184 3c60e398c9bf4ea1a21599b87752ff86\nmsgid \"plotter-n\"\nmsgstr \"plotter-n\"\n\n#: ../../tools.rst:184 769eb710317c41a480dbc570a4cee0f1\nmsgid \"overprint rendering\"\nmsgstr \"오버프린트 렌더링\"\n\n#: ../../tools.rst:185 de0c1cb2bd6e4d3f9218813213738b89\nmsgid \"pdf\"\nmsgstr \"pdf\"\n\n#: ../../tools.rst:185 0eb90b0c563943b092427c844fa84d82\nmsgid \"PDF documents\"\nmsgstr \"PDF 문서\"\n\n#: ../../tools.rst:186 b99df5adf3fa4e9f9146cf0f5b29995a\nmsgid \"xps\"\nmsgstr \"xps\"\n\n#: ../../tools.rst:186 9489b74272084bbeb3d2c279e697ecf2\nmsgid \"XPS documents\"\nmsgstr \"XPS 문서\"\n\n#: ../../tools.rst:187 d2a4ee5c893b4b87a0166bbe1856cda6\nmsgid \"svg\"\nmsgstr \"svg\"\n\n#: ../../tools.rst:187 e551c61cd7e441449280f9359dec7dc7\nmsgid \"SVG documents\"\nmsgstr \"SVG 문서\"\n\n#: ../../tools.rst:188 577bc099e8ac44c9b26c26942341b2c7\nmsgid \"cbz\"\nmsgstr \"cbz\"\n\n#: ../../tools.rst:188 ebc6a4b501dc4f6b962a645852e681d1\nmsgid \"CBZ documents\"\nmsgstr \"CBZ 문서\"\n\n#: ../../tools.rst:189 64ec1daad09243c88803ed7eb5709835\nmsgid \"img\"\nmsgstr \"img\"\n\n#: ../../tools.rst:189 7d744907b35241c78b99cc180e6b9113\nmsgid \"IMG documents\"\nmsgstr \"IMG 문서\"\n\n#: ../../tools.rst:190 bb12f79a20f04779acd3ed438cfbbc96\nmsgid \"html\"\nmsgstr \"html\"\n\n#: ../../tools.rst:190 bb3a4a4575c943969b56f0af2d838d7e\nmsgid \"HTML documents\"\nmsgstr \"HTML 문서\"\n\n#: ../../tools.rst:191 ab3d19b472154fce925a82f813fe20c5\nmsgid \"epub\"\nmsgstr \"epub\"\n\n#: ../../tools.rst:191 44a8aabb49ac41458e987ca800cc7eac\nmsgid \"EPUB documents\"\nmsgstr \"EPUB 문서\"\n\n#: ../../tools.rst:192 4a9f9a0ca3fe4cc79bc5b83c962ebe17\nmsgid \"jpx\"\nmsgstr \"jpx\"\n\n#: ../../tools.rst:192 5ab6d3192a344c83a9666aadf1016b5b\nmsgid \"JPEG2000 images\"\nmsgstr \"JPEG2000 이미지\"\n\n#: ../../tools.rst:193 b74ed5834b3d4fd081414ff7634e74ec\nmsgid \"js\"\nmsgstr \"js\"\n\n#: ../../tools.rst:193 36672693f4374487a530bf0c3af9832c\nmsgid \"JavaScript\"\nmsgstr \"JavaScript\"\n\n#: ../../tools.rst:194 adc238844f2c4040bbd4a86abbf6039a\nmsgid \"tofu\"\nmsgstr \"tofu\"\n\n#: ../../tools.rst:194 558f9de6ca4f46dd808cfbf415f7ce06\nmsgid \"all TOFU fonts\"\nmsgstr \"모든 TOFU 글꼴\"\n\n#: ../../tools.rst:195 3f1c381eadc64b8db7d515ae9eba3984\nmsgid \"tofu-cjk\"\nmsgstr \"tofu-cjk\"\n\n#: ../../tools.rst:195 ea40b88f4fdd4d1eb43a2a6bf6e8f5ba\nmsgid \"CJK font subset (China, Japan, Korea)\"\nmsgstr \"CJK 글꼴 서브셋 (중국, 일본, 한국)\"\n\n#: ../../tools.rst:196 a4f1e69f4b814edb83e603a1355259dc\nmsgid \"tofu-cjk-ext\"\nmsgstr \"tofu-cjk-ext\"\n\n#: ../../tools.rst:196 c377019167934982a83d55627ae3ba2c\nmsgid \"CJK font extensions\"\nmsgstr \"CJK 글꼴 확장\"\n\n#: ../../tools.rst:197 0fc7a1646f7646738d72ec2061e7691c\nmsgid \"tofu-cjk-lang\"\nmsgstr \"tofu-cjk-lang\"\n\n#: ../../tools.rst:197 66d5555a5824418a9f35c3b2b71e4b88\nmsgid \"CJK font language extensions\"\nmsgstr \"CJK 글꼴 언어 확장\"\n\n#: ../../tools.rst:198 1b5d5d0dbd32445593b767b2483e3060\nmsgid \"tofu-emoji\"\nmsgstr \"tofu-emoji\"\n\n#: ../../tools.rst:198 0cdbcf60f7d64d39b197db2579600064\nmsgid \"TOFU emoji fonts\"\nmsgstr \"TOFU 이모지 글꼴\"\n\n#: ../../tools.rst:199 7fc6679d779c41719fccabfb090325fa\nmsgid \"tofu-historic\"\nmsgstr \"tofu-historic\"\n\n#: ../../tools.rst:199 9cbba9254c32429899b6b2dac733f20d\nmsgid \"TOFU historic fonts\"\nmsgstr \"TOFU 역사적 글꼴\"\n\n#: ../../tools.rst:200 2ef2e1b8fab04ed5b5cf6812262986b0\nmsgid \"tofu-symbol\"\nmsgstr \"tofu-symbol\"\n\n#: ../../tools.rst:200 70b9a0a97d0f47deb48c32f026c189b8\nmsgid \"TOFU symbol fonts\"\nmsgstr \"TOFU 기호 글꼴\"\n\n#: ../../tools.rst:201 84425b54341d4ddf86a53d5636ce6d6c\nmsgid \"tofu-sil\"\nmsgstr \"tofu-sil\"\n\n#: ../../tools.rst:201 eb589864b3f14b24adedd043685a8f64\nmsgid \"TOFU SIL fonts\"\nmsgstr \"TOFU SIL 글꼴\"\n\n#: ../../tools.rst:202 755f0012ad0c4aea8e9a52a0776c2c81\nmsgid \"icc\"\nmsgstr \"icc\"\n\n#: ../../tools.rst:202 5358baa2b811434fb799602302fdbe35\nmsgid \"ICC profiles\"\nmsgstr \"ICC 프로필\"\n\n#: ../../tools.rst:203 1ea2192091824ca8a0a392c9dc10f890\nmsgid \"py-memory\"\nmsgstr \"py-memory\"\n\n#: ../../tools.rst:203 9cb31e10c386492c9cbb9a5e2265ace3\nmsgid \"using Python memory management [#f2]_\"\nmsgstr \"Python 메모리 관리 사용 [#f2]_\"\n\n#: ../../tools.rst:204 dec087f849db4162a867ce6d93c08a53\nmsgid \"base14\"\nmsgstr \"base14\"\n\n#: ../../tools.rst:204 69f5e80bd30c411d97af4b8a75e364ec\nmsgid \"Base-14 fonts (should always be true)\"\nmsgstr \"Base-14 글꼴 (항상 true여야 함)\"\n\n#: ../../tools.rst:207 3a669d605b904f36b9308d04b1fad7df\nmsgid \"\"\n\"For an explanation of the term \\\"TOFU\\\" see `this Wikipedia article \"\n\"<https://en.wikipedia.org/wiki/Noto_fonts>`_::\"\nmsgstr \"\\\"TOFU\\\" 용어에 대한 설명은 `이 위키피디아 기사 <https://en.wikipedia.org/wiki/Noto_fonts>`_ 를 참조하세요::\"\n\n#: ../../tools.rst:241 bf3651fc67ee458a8794cf46e18bdaa0\nmsgid \"\"\n\"Maximum storables cache size in bytes. |PyMuPDF| is generated with a \"\n\"value of 268'435'456 (256 MB, the default value), which you should \"\n\"therefore always see here. If this value is zero, then an \\\"unlimited\\\" \"\n\"growth is permitted.\"\nmsgstr \"최대 저장 가능한 캐시 크기(바이트). |PyMuPDF| 는 268'435'456(256 MB, 기본값) 값으로 생성되므로 여기서 항상 이 값을 볼 수 있습니다. 이 값이 0이면 \\\"무제한\\\" 증가가 허용됩니다.\"\n\n#: ../../tools.rst:247 cd118310efc74373a064388fb69baf0b\nmsgid \"\"\n\"Current storables cache size in bytes. This value may change (and will \"\n\"usually increase) with every use of a |PyMuPDF| function. It will \"\n\"(automatically) decrease only when :attr:`Tools.store_maxsize` is going \"\n\"to be exceeded: in this case, |MuPDF| will evict low-usage objects until \"\n\"the value is again in range.\"\nmsgstr \"현재 저장 가능한 캐시 크기(바이트). 이 값은 |PyMuPDF| 함수를 사용할 때마다 변경될 수 있으며(일반적으로 증가) :attr:`Tools.store_maxsize` 가 초과될 때만 (자동으로) 감소합니다. 이 경우 |MuPDF| 는 값이 다시 범위 내에 있을 때까지 사용 빈도가 낮은 객체를 제거합니다.\"\n\n#: ../../tools.rst:252 eb29156bef9747b0801b3a3a7cb7b827\nmsgid \"Example Session\"\nmsgstr \"예제 세션\"\n\n#: ../../tools.rst:288 4ea509ba0cce45108ae592589157ef48\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../tools.rst:289 eac7cbc90f544d38b17f9aaecb25533b\nmsgid \"\"\n\"This memory area is internally used by MuPDF, and it serves as a cache \"\n\"for objects that have already been read and interpreted, thus improving \"\n\"performance. The most bulky object types are images and also fonts. When \"\n\"an application starts up the MuPDF library (in our case this happens as \"\n\"part of *import pymupdf*), it must specify a maximum size for this area. \"\n\"PyMuPDF's uses the default value (256 MB) to limit memory consumption. \"\n\"Use the methods here to control or investigate store usage. For example: \"\n\"even after a document has been closed and all related objects have been \"\n\"deleted, the store usage may still not drop down to zero. So you might \"\n\"want to enforce that before opening another document.\"\nmsgstr \"이 메모리 영역은 MuPDF에서 내부적으로 사용되며, 이미 읽고 해석된 객체에 대한 캐시 역할을 하여 성능을 향상시킵니다. 가장 큰 객체 유형은 이미지와 글꼴입니다. 애플리케이션이 MuPDF 라이브러리를 시작할 때(*import pymupdf* 의 일부로 발생) 이 영역에 대한 최대 크기를 지정해야 합니다. PyMuPDF는 기본값(256 MB)을 사용하여 메모리 소비를 제한합니다. 여기서 메서드를 사용하여 저장소 사용을 제어하거나 조사하세요. 예를 들어: 문서가 닫히고 관련 객체가 모두 삭제된 후에도 저장소 사용량이 여전히 0으로 떨어지지 않을 수 있습니다. 따라서 다른 문서를 열기 전에 이를 강제로 실행할 수 있습니다.\"\n\n#: ../../tools.rst:291 762bd894d82742c9b21223dc22c6390d\nmsgid \"\"\n\"By default PyMuPDF and MuPDF use `malloc()`/`free()` for dynamic memory \"\n\"management. One can instead force them to use the Python allocation \"\n\"functions `PyMem_New()`/`PyMem_Del()`, by modifying *fitz/fitz.i* to do \"\n\"`#define JM_MEMORY 1` and rebuilding PyMuPDF.\"\nmsgstr \"기본적으로 PyMuPDF와 MuPDF는 동적 메모리 관리에 `malloc()`/`free()` 를 사용합니다. 대신 *fitz/fitz.i* 를 수정하여 `#define JM_MEMORY 1` 을 수행하고 PyMuPDF를 다시 빌드하여 Python 할당 함수 `PyMem_New()`/`PyMem_Del()` 을 사용하도록 강제할 수 있습니다.\"\n\n#: ../../footer.rst:46 78ca850d896b41bda3d3e7d7c4795819\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/tutorial.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 af1c872c0c8149488a828ec57db0d05a\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 5f296e40a5a84c7db71c20c23cf034c9\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 PDF(및 기타) 문서의 데이터 추출, 분석, 변환 및 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 6ce8107c629e456a909666cce87fe6bd\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../tutorial.rst:8 939af6d1c28b485eb4ff9f7d7027d32c\nmsgid \"Tutorial\"\nmsgstr \"튜토리얼\"\n\n#: ../../tutorial.rst:12 4f39e913a37d45aaaae25d581b6b21a5\nmsgid \"\"\n\"This tutorial will show you the use of |PyMuPDF|, |MuPDF| in Python, step\"\n\" by step.\"\nmsgstr \"이 튜토리얼은 Python에서 |PyMuPDF|, |MuPDF| 사용법을 단계별로 보여줍니다.\"\n\n#: ../../tutorial.rst:14 5a427c507e6b44479862e8eb2c0a69ba\nmsgid \"\"\n\"Because |MuPDF| supports not only PDF, but also XPS, OpenXPS, CBZ, CBR, \"\n\"FB2 and EPUB formats, so does |PyMuPDF| [#f1]_. Nevertheless, for the \"\n\"sake of brevity we will only talk about PDF files. At places where indeed\"\n\" only PDF files are supported, this will be mentioned explicitly.\"\nmsgstr \"|MuPDF| 가 PDF뿐만 아니라 XPS, OpenXPS, CBZ, CBR, FB2, EPUB 형식도 지원하므로 |PyMuPDF| 도 마찬가지입니다 [#f1]_. 그러나 간결성을 위해 PDF 파일만 다룹니다. PDF 파일만 지원되는 경우에는 명시적으로 언급합니다.\"\n\n#: ../../tutorial.rst:16 b2c324e1eda6484681a5b98002f9f022\nmsgid \"\"\n\"In addition to this introduction, please do visit PyMuPDF's `YouTube \"\n\"Channel <https://www.youtube.com/@PyMuPDF>`_ which covers most of the \"\n\"following in the form of YouTube \\\"Shorts\\\" and longer videos.\"\nmsgstr \"이 소개 외에도 |PyMuPDF| 의 `YouTube 채널 <https://www.youtube.com/@PyMuPDF>`_ 을 방문하시기 바랍니다. YouTube \\\"Shorts\\\" 및 더 긴 비디오 형식으로 대부분의 내용을 다루고 있습니다.\"\n\n#: ../../tutorial.rst:19 c23da3317c5d43fdadba3fa7c99c3afc\nmsgid \"Importing the Bindings\"\nmsgstr \"바인딩 가져오기\"\n\n#: ../../tutorial.rst:20 a04dcd4a09c3420f950b46d664276cd8\nmsgid \"\"\n\"The Python bindings to MuPDF are made available by this import statement.\"\n\" We also show here how your version can be checked::\"\nmsgstr \"이 import 문으로 |MuPDF| 에 대한 Python 바인딩을 사용할 수 있습니다. 여기서 버전을 확인하는 방법도 보여줍니다::\"\n\n#: ../../tutorial.rst:30 56adbb5b22484758912815cc290316d8\nmsgid \"Note on the Name *fitz*\"\nmsgstr \"*fitz* 이름에 대한 참고사항\"\n\n#: ../../tutorial.rst:32 3b2a413d1d2040d38bbc841d83f98d16\nmsgid \"\"\n\"Old versions of |PyMuPDF| had their **Python** import name as `fitz`. \"\n\"Newer versions use `pymupdf` instead, and offer `fitz` as a fallback so \"\n\"that old code will still work.\"\nmsgstr \"이전 버전의 |PyMuPDF| 는 **Python** import 이름이 `fitz` 였습니다. 최신 버전은 대신 `pymupdf` 를 사용하며, 이전 코드가 계속 작동하도록 `fitz` 를 대체 옵션으로 제공합니다.\"\n\n#: ../../tutorial.rst:34 e7ad072736bc434da33243355f43a143\nmsgid \"The reason for the name `fitz` is a historical curiosity:\"\nmsgstr \"`fitz` 라는 이름의 이유는 역사적인 호기심입니다:\"\n\n#: ../../tutorial.rst:36 0a1388985e214bc8803f67a3cdc99664\nmsgid \"The original rendering library for MuPDF was called *Libart*.\"\nmsgstr \"|MuPDF| 의 원래 렌더링 라이브러리는 *Libart* 라고 불렸습니다.\"\n\n#: ../../tutorial.rst:38 6bb98d1d5fd843a9a823b5a023f389e8\nmsgid \"\"\n\"*\\\"After Artifex Software acquired the MuPDF project, the development \"\n\"focus shifted on writing a new modern graphics library called \\\"Fitz\\\". \"\n\"Fitz was originally intended as an R&D project to replace the aging \"\n\"Ghostscript graphics library, but has instead become the rendering engine\"\n\" powering MuPDF.\\\"* (Quoted from `Wikipedia \"\n\"<https://en.wikipedia.org/wiki/MuPDF>`_).\"\nmsgstr \"*\\\"Artifex Software가 MuPDF 프로젝트를 인수한 후, 개발 초점은 \\\"Fitz\\\"라는 새로운 현대적인 그래픽 라이브러리 작성으로 옮겨졌습니다. Fitz는 원래 노후화된 Ghostscript 그래픽 라이브러리를 대체하기 위한 R&D 프로젝트로 의도되었지만, 대신 MuPDF를 구동하는 렌더링 엔진이 되었습니다.\\\"* (`Wikipedia <https://en.wikipedia.org/wiki/MuPDF>`_ 에서 인용).\"\n\n#: ../../tutorial.rst:42 f0b608072e0948f0a8d5019e86f78ae4\nmsgid \"\"\n\"Use of legacy name `fitz` can fail if defunct pypi.org package `fitz` is \"\n\"installed; see :ref:`problems-after-installation`.\"\nmsgstr \"사용되지 않는 pypi.org 패키지 `fitz` 가 설치된 경우 레거시 이름 `fitz` 사용이 실패할 수 있습니다. :ref:`problems-after-installation` 을 참조하세요.\"\n\n#: ../../tutorial.rst:48 5b6f4f47d3d14b3dabbafb6419e1bfd3\nmsgid \"Opening a Document\"\nmsgstr \"문서 열기\"\n\n#: ../../tutorial.rst:50 bad87b705ed349689aeb233740a2a4dd\nmsgid \"\"\n\"To access a :ref:`supported document<Supported_File_Types>`, it must be \"\n\"opened with the following statement::\"\nmsgstr \":ref:`지원되는 문서<Supported_File_Types>` 에 액세스하려면 다음 문으로 열어야 합니다::\"\n\n#: ../../tutorial.rst:54 8ee29d11c6664eaba2d74e39fe256992\nmsgid \"\"\n\"This creates the :ref:`Document` object *doc*. *filename* must be a \"\n\"Python string (or a `pathlib.Path`) specifying the name of an existing \"\n\"file.\"\nmsgstr \"이것은 :ref:`Document` 객체 *doc* 을 생성합니다. *filename* 은 기존 파일의 이름을 지정하는 Python 문자열(또는 `pathlib.Path`)이어야 합니다.\"\n\n#: ../../tutorial.rst:56 fd7dc22114c4467ea703f11c5e4ddad9\nmsgid \"\"\n\"It is also possible to open a document from memory data, or to create a \"\n\"new, empty PDF. See :ref:`Document` for details. You can also use \"\n\":ref:`Document` as a *context manager*.\"\nmsgstr \"메모리 데이터에서 문서를 열거나 새로운 빈 PDF를 생성할 수도 있습니다. 자세한 내용은 :ref:`Document` 를 참조하세요. :ref:`Document` 를 *context manager* 로 사용할 수도 있습니다.\"\n\n#: ../../tutorial.rst:58 e53b2ee3b09744bba7d0a597e3110a06\nmsgid \"\"\n\"A document contains many attributes and functions. Among them are meta \"\n\"information (like \\\"author\\\" or \\\"subject\\\"), number of total pages, \"\n\"outline and encryption information.\"\nmsgstr \"문서에는 많은 속성과 함수가 포함되어 있습니다. 그 중에는 메타 정보(\\\"author\\\" 또는 \\\"subject\\\" 등), 총 페이지 수, 개요 및 암호화 정보가 있습니다.\"\n\n#: ../../tutorial.rst:61 ed2d7a85b35c446faacb3600235eef21\nmsgid \"Some :ref:`Document` Methods and Attributes\"\nmsgstr \"일부 :ref:`Document` 메서드 및 속성\"\n\n#: ../../tutorial.rst:64 3b4470725538483087f6877a0b238a75\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../tutorial.rst:64 348a919c08be4e7bacbcbdebf6aadceb\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../tutorial.rst:66 3c58bb5e0cfd4357bf595f5730c490f5\nmsgid \":attr:`Document.page_count`\"\nmsgstr \":attr:`Document.page_count`\"\n\n#: ../../tutorial.rst:66 71bcf48456184a0a864819c5c6c6b639\nmsgid \"the number of pages (*int*)\"\nmsgstr \"페이지 수 (*int*)\"\n\n#: ../../tutorial.rst:67 a9ca3bea8587466696f8c3a412c51474\nmsgid \":attr:`Document.metadata`\"\nmsgstr \":attr:`Document.metadata`\"\n\n#: ../../tutorial.rst:67 5d63c2f5c2bf442da412566cddc8f0da\nmsgid \"the metadata (*dict*)\"\nmsgstr \"메타데이터 (*dict*)\"\n\n#: ../../tutorial.rst:68 3a230f9d11cf49c8abaabfc21332281a\nmsgid \":meth:`Document.get_toc`\"\nmsgstr \":meth:`Document.get_toc`\"\n\n#: ../../tutorial.rst:68 670c25d439184b3d864535494e4bc345\nmsgid \"get the table of contents (*list*)\"\nmsgstr \"목차 가져오기 (*list*)\"\n\n#: ../../tutorial.rst:69 4dbf36bdcc774cfe94f6fe488e23ab70\nmsgid \":meth:`Document.load_page`\"\nmsgstr \":meth:`Document.load_page`\"\n\n#: ../../tutorial.rst:69 6a5260a61382415882e9d006c179fe90\nmsgid \"read a :ref:`Page`\"\nmsgstr \":ref:`Page` 읽기\"\n\n#: ../../tutorial.rst:73 d6bc5b209b1c4e7aa5b367e616992438\nmsgid \"Accessing Meta Data\"\nmsgstr \"메타데이터 액세스\"\n\n#: ../../tutorial.rst:74 5eeb7a67a3834701bda60567079af358\nmsgid \"\"\n\"PyMuPDF fully supports standard metadata. :attr:`Document.metadata` is a \"\n\"Python dictionary with the following keys. It is available for **all \"\n\"document types**, though not all entries may always contain data. For \"\n\"details of their meanings and formats consult the respective manuals, \"\n\"e.g. :ref:`AdobeManual` for PDF. Further information can also be found in\"\n\" chapter :ref:`Document`. The meta data fields are strings or ``None`` if\"\n\" not otherwise indicated. Also be aware that not all of them always \"\n\"contain meaningful data -- even if they are not ``None``.\"\nmsgstr \"|PyMuPDF| 는 표준 메타데이터를 완전히 지원합니다. :attr:`Document.metadata` 는 다음 키를 가진 Python 딕셔너리입니다. **모든 문서 타입** 에서 사용할 수 있지만, 모든 항목이 항상 데이터를 포함하지는 않을 수 있습니다. 의미와 형식에 대한 자세한 내용은 각 매뉴얼(예: PDF의 경우 :ref:`AdobeManual`)을 참조하세요. 추가 정보는 :ref:`Document` 장에서도 찾을 수 있습니다. 메타데이터 필드는 달리 표시되지 않는 한 문자열 또는 ``None`` 입니다. 또한 모든 필드가 항상 의미 있는 데이터를 포함하는 것은 아니라는 점에 유의하세요. ``None`` 이 아니더라도 그렇습니다.\"\n\n#: ../../tutorial.rst:77 6c9a21d704a241029ce9b7f001b7bac5\nmsgid \"Key\"\nmsgstr \"키\"\n\n#: ../../tutorial.rst:77 8400973337594bcf8e3da33817744ccf\nmsgid \"Value\"\nmsgstr \"값\"\n\n#: ../../tutorial.rst:79 6aa5ce470f8642c4af491e28af8bc999\nmsgid \"producer\"\nmsgstr \"producer\"\n\n#: ../../tutorial.rst:79 52ee9d5cf1d94e4e824f1486804c0a49\nmsgid \"producer (producing software)\"\nmsgstr \"생성자(생성 소프트웨어)\"\n\n#: ../../tutorial.rst:80 85a0fa96090940f499052abc68aac361\nmsgid \"format\"\nmsgstr \"format\"\n\n#: ../../tutorial.rst:80 cd1a7dc5cfca479ca59b0e5e2b00f5bb\nmsgid \"format: 'PDF-1.4', 'EPUB', etc.\"\nmsgstr \"형식: 'PDF-1.4', 'EPUB' 등\"\n\n#: ../../tutorial.rst:81 96773e4fde41492a8fbc9d8e0dfffe01\nmsgid \"encryption\"\nmsgstr \"encryption\"\n\n#: ../../tutorial.rst:81 4b242b9f88fb40e4847a8ad0358789ec\nmsgid \"encryption method used if any\"\nmsgstr \"사용된 암호화 방법(있는 경우)\"\n\n#: ../../tutorial.rst:82 520e1f5cffc3419faccbecacb778ad88\n#: adc5542c41534ce68fe9d02192b1f9e0\nmsgid \"author\"\nmsgstr \"author\"\n\n#: ../../tutorial.rst:83 d593bfa2f3f1464ca98020a5d8cc2d74\nmsgid \"modDate\"\nmsgstr \"modDate\"\n\n#: ../../tutorial.rst:83 49db626a877e41699ba02058512b97d9\nmsgid \"date of last modification\"\nmsgstr \"마지막 수정 날짜\"\n\n#: ../../tutorial.rst:84 ac0f4c311d9d4f91b366556afa0eac07\n#: cad667882e9247ed9a8465e9e8f6f30e\nmsgid \"keywords\"\nmsgstr \"keywords\"\n\n#: ../../tutorial.rst:85 4a12c1d082794891871985009346217e\n#: 9afee53342a24f749bd6b1695ceba4ca\nmsgid \"title\"\nmsgstr \"title\"\n\n#: ../../tutorial.rst:86 0659f2376ae84f0694559432c6acc6ab\nmsgid \"creationDate\"\nmsgstr \"creationDate\"\n\n#: ../../tutorial.rst:86 c3e9c7f2af964de1a4ea55d6dfc87ae7\nmsgid \"date of creation\"\nmsgstr \"생성 날짜\"\n\n#: ../../tutorial.rst:87 f7336bfddb6c47da8c979a965fd0e200\nmsgid \"creator\"\nmsgstr \"creator\"\n\n#: ../../tutorial.rst:87 cde7dc3a8d604edeb4df81869876cc12\nmsgid \"creating application\"\nmsgstr \"생성 애플리케이션\"\n\n#: ../../tutorial.rst:88 59f646e95f21440aab80a6d9eaee2cb5\n#: dfcc9986b7404e3ea4869973f3300afb\nmsgid \"subject\"\nmsgstr \"subject\"\n\n#: ../../tutorial.rst:91 e212f47f482f4ba086c347c1ee602818\nmsgid \"\"\n\"Apart from these standard metadata, **PDF documents** starting from PDF \"\n\"version 1.4 may also contain so-called *\\\"metadata streams\\\"* (see also \"\n\":data:`stream`). Information in such streams is coded in XML. PyMuPDF \"\n\"deliberately contains no XML components for this purpose (the \"\n\":ref:`PyMuPDF Xml class<Xml>` is a helper class intended to access the \"\n\"DOM content of a :ref:`Story` object), so we do not directly support \"\n\"access to information contained therein. But you can extract the stream \"\n\"as a whole, inspect or modify it using a package like `lxml`_ and then \"\n\"store the result back into the PDF. If you want, you can also delete this\"\n\" data altogether.\"\nmsgstr \"이러한 표준 메타데이터 외에도 PDF 버전 1.4부터 시작하는 **PDF 문서** 는 소위 *\\\"metadata streams\\\"* (:data:`stream` 도 참조)를 포함할 수도 있습니다. 이러한 스트림의 정보는 XML로 인코딩됩니다. |PyMuPDF| 는 의도적으로 이 목적을 위한 XML 구성 요소를 포함하지 않습니다(:ref:`PyMuPDF Xml class<Xml>` 는 :ref:`Story` 객체의 DOM 콘텐츠에 액세스하기 위한 헬퍼 클래스입니다). 따라서 그 안에 포함된 정보에 대한 직접 액세스를 지원하지 않습니다. 그러나 스트림 전체를 추출하고 `lxml`_ 같은 패키지를 사용하여 검사하거나 수정한 다음 결과를 PDF에 다시 저장할 수 있습니다. 원하는 경우 이 데이터를 완전히 삭제할 수도 있습니다.\"\n\n#: ../../tutorial.rst:93 5ec202ac5c494be3bf62e68bf5ba28b1\nmsgid \"\"\n\"There are two utility scripts in the repository that `metadata import \"\n\"(PDF only)`_ resp. `metadata export`_ metadata from resp. to CSV files.\"\nmsgstr \"저장소에는 CSV 파일에서 메타데이터를 가져오거나(`metadata import (PDF only)`_) CSV 파일로 내보내는(`metadata export`_) 두 가지 유틸리티 스크립트가 있습니다.\"\n\n#: ../../tutorial.rst:96 1d31369f6b884d08a61b700b01e9e7b1\nmsgid \"Working with Outlines\"\nmsgstr \"개요 작업\"\n\n#: ../../tutorial.rst:97 fe8e22242a324f349fca363f8d0f6348\nmsgid \"\"\n\"The easiest way to get all outlines (also called \\\"bookmarks\\\") of a \"\n\"document, is by loading its *table of contents*::\"\nmsgstr \"문서의 모든 개요(\\\"bookmarks\\\"라고도 함)를 가져오는 가장 쉬운 방법은 *목차* 를 로드하는 것입니다::\"\n\n#: ../../tutorial.rst:101 4fe54a9ca0244cd9871ba72a155cbe95\nmsgid \"\"\n\"This will return a Python list of lists *[[lvl, title, page, ...], ...]* \"\n\"which looks much like a conventional table of contents found in books.\"\nmsgstr \"이것은 책에서 볼 수 있는 일반적인 목차와 매우 유사한 Python 리스트의 리스트 *[[lvl, title, page, ...], ...]* 를 반환합니다.\"\n\n#: ../../tutorial.rst:103 a0df1526a42e4d88bf1fb24bf14c2392\nmsgid \"\"\n\"*lvl* is the hierarchy level of the entry (starting from 1), *title* is \"\n\"the entry's title, and *page* the page number (1-based!). Other \"\n\"parameters describe details of the bookmark target.\"\nmsgstr \"*lvl* 은 항목의 계층 레벨(1부터 시작), *title* 은 항목의 제목, *page* 는 페이지 번호(1 기반!)입니다. 다른 매개변수는 북마크 대상의 세부 정보를 설명합니다.\"\n\n#: ../../tutorial.rst:105 f60efb5302364edfb64c7775c185929b\nmsgid \"\"\n\"There are two utility scripts in the repository that `toc import (PDF \"\n\"only)`_ resp. `toc export`_ table of contents from resp. to CSV files.\"\nmsgstr \"저장소에는 CSV 파일에서 목차를 가져오거나(`toc import (PDF only)`_) CSV 파일로 내보내는(`toc export`_) 두 가지 유틸리티 스크립트가 있습니다.\"\n\n#: ../../tutorial.rst:108 f7e0d8ac5cd64bbfb19d5a7680f37840\nmsgid \"Working with Pages\"\nmsgstr \"페이지 작업\"\n\n#: ../../tutorial.rst:109 bea68ab57a6a4ec49fa98a57625daec3\nmsgid \":ref:`Page` handling is at the core of MuPDF's functionality.\"\nmsgstr \":ref:`Page` 처리는 |MuPDF| 기능의 핵심입니다.\"\n\n#: ../../tutorial.rst:111 705fbd37cfd04f5eb2725ee74973716c\nmsgid \"\"\n\"You can render a page into a raster or vector (SVG) image, optionally \"\n\"zooming, rotating, shifting or shearing it.\"\nmsgstr \"페이지를 래스터 또는 벡터(SVG) 이미지로 렌더링할 수 있으며, 선택적으로 확대/축소, 회전, 이동 또는 기울이기를 할 수 있습니다.\"\n\n#: ../../tutorial.rst:112 07346e73ca2f4851bcb7243ed707f0c5\nmsgid \"\"\n\"You can extract a page's text and images in many formats and search for \"\n\"text strings.\"\nmsgstr \"페이지의 텍스트와 이미지를 여러 형식으로 추출하고 텍스트 문자열을 검색할 수 있습니다.\"\n\n#: ../../tutorial.rst:113 b10390460b7e469d933d4b0bca64cbd8\nmsgid \"\"\n\"For PDF documents many more methods are available to add text or images \"\n\"to pages.\"\nmsgstr \"PDF 문서의 경우 페이지에 텍스트나 이미지를 추가하는 더 많은 메서드를 사용할 수 있습니다.\"\n\n#: ../../tutorial.rst:115 634af7e840c34aba910ebc8b50aac6b1\nmsgid \"\"\n\"First, a :ref:`Page` must be created. This is a method of \"\n\":ref:`Document`::\"\nmsgstr \"먼저 :ref:`Page` 를 생성해야 합니다. 이것은 :ref:`Document` 의 메서드입니다::\"\n\n#: ../../tutorial.rst:120 e13781020ec34c48a1d29405c5d4063b\nmsgid \"\"\n\"Any integer `-∞ < pno < page_count` is possible here. Negative numbers \"\n\"count backwards from the end, so *doc[-1]* is the last page, like with \"\n\"Python sequences.\"\nmsgstr \"여기서는 `-∞ < pno < page_count` 범위의 정수가 가능합니다. 음수는 끝에서 역순으로 계산되므로 Python 시퀀스와 같이 *doc[-1]* 은 마지막 페이지입니다.\"\n\n#: ../../tutorial.rst:122 4e28316907e444489cfbf10a12e27bba\nmsgid \"\"\n\"Some more advanced way would be using the document as an **iterator** \"\n\"over its pages::\"\nmsgstr \"더 고급 방법은 문서를 페이지에 대한 **반복자** 로 사용하는 것입니다::\"\n\n#: ../../tutorial.rst:136 84e73234fd424852a2b36c0bc15b2d9d\nmsgid \"Once you have your page, here is what you would typically do with it:\"\nmsgstr \"페이지를 얻으면 일반적으로 다음과 같은 작업을 수행합니다:\"\n\n#: ../../tutorial.rst:139 088737b71af34948b17fbe30a60a9dc4\nmsgid \"Inspecting the Links, Annotations or Form Fields of a Page\"\nmsgstr \"페이지의 링크, 주석 또는 양식 필드 검사\"\n\n#: ../../tutorial.rst:140 80600b8ed5664159a8aad4e5b6706037\nmsgid \"\"\n\"Links are shown as \\\"hot areas\\\" when a document is displayed with some \"\n\"viewer software. If you click while your cursor shows a hand symbol, you \"\n\"will usually be taken to the target that is encoded in that hot area. \"\n\"Here is how to get all links::\"\nmsgstr \"링크는 문서가 뷰어 소프트웨어로 표시될 때 \\\"hot areas\\\"로 표시됩니다. 커서가 손 기호를 표시하는 동안 클릭하면 일반적으로 해당 hot area에 인코딩된 대상으로 이동합니다. 모든 링크를 가져오는 방법은 다음과 같습니다::\"\n\n#: ../../tutorial.rst:145 5b90391005b24d46b953ffde747dbd80\nmsgid \"\"\n\"*links* is a Python list of dictionaries. For details see \"\n\":meth:`Page.get_links`.\"\nmsgstr \"*links* 는 딕셔너리의 Python 리스트입니다. 자세한 내용은 :meth:`Page.get_links` 를 참조하세요.\"\n\n#: ../../tutorial.rst:147 19b388140fd44ace88779d4d2f85e3f5\nmsgid \"You can also use an iterator which emits one link at a time::\"\nmsgstr \"한 번에 하나의 링크를 생성하는 반복자를 사용할 수도 있습니다::\"\n\n#: ../../tutorial.rst:152 972adb409c6b4d1781d1976cb040f944\nmsgid \"\"\n\"If dealing with a PDF document page, there may also exist annotations \"\n\"(:ref:`Annot`) or form fields (:ref:`Widget`), each of which have their \"\n\"own iterators::\"\nmsgstr \"PDF 문서 페이지를 다루는 경우 주석(:ref:`Annot`) 또는 양식 필드(:ref:`Widget`)가 있을 수도 있으며, 각각 고유한 반복자를 가집니다::\"\n\n#: ../../tutorial.rst:162 354960511fbd4e299b3561f27464ffa6\nmsgid \"Rendering a Page\"\nmsgstr \"페이지 렌더링\"\n\n#: ../../tutorial.rst:163 4b29e0e4b9f04b54a4b12db45462cebe\nmsgid \"This example creates a **raster** image of a page's content::\"\nmsgstr \"이 예제는 페이지 콘텐츠의 **래스터** 이미지를 생성합니다::\"\n\n#: ../../tutorial.rst:167 b23c4b5d3b5345f0add5cb0dffaa6255\nmsgid \"\"\n\"``pix`` is a :ref:`Pixmap` object which (in this case) contains an \"\n\"**RGB** image of the page, ready to be used for many purposes. Method \"\n\":meth:`Page.get_pixmap` offers lots of variations for controlling the \"\n\"image: resolution / DPI, colorspace (e.g. to produce a grayscale image or\"\n\" an image with a subtractive color scheme), transparency, rotation, \"\n\"mirroring, shifting, shearing, etc. For example: to create an **RGBA** \"\n\"image (i.e. containing an alpha channel), specify *pix = \"\n\"page.get_pixmap(alpha=True)*.\"\nmsgstr \"``pix`` 는 (이 경우) 페이지의 **RGB** 이미지를 포함하는 :ref:`Pixmap` 객체로, 다양한 용도로 사용할 준비가 되어 있습니다. :meth:`Page.get_pixmap` 메서드는 이미지를 제어하기 위한 많은 변형을 제공합니다: 해상도/DPI, 색 공간(예: 그레이스케일 이미지 또는 감산 색상 체계의 이미지 생성), 투명도, 회전, 미러링, 이동, 기울이기 등. 예를 들어: **RGBA** 이미지(즉, 알파 채널 포함)를 생성하려면 *pix = page.get_pixmap(alpha=True)* 를 지정하세요.\"\n\n#: ../../tutorial.rst:169 e2331fb68ff848cab6245b27ba5f4079\nmsgid \"\"\n\"A :ref:`Pixmap` contains a number of methods and attributes which are \"\n\"referenced below. Among them are the integers ``width``, ``height`` (each\"\n\" in pixels) and ``stride`` (number of bytes of one horizontal image \"\n\"line). Attribute ``samples`` represents a rectangular area of bytes \"\n\"representing the image data (a Python ``bytes`` object).\"\nmsgstr \":ref:`Pixmap` 은 아래에서 참조되는 많은 메서드와 속성을 포함합니다. 그 중에는 정수 ``width``, ``height`` (각각 픽셀 단위) 및 ``stride`` (한 수평 이미지 라인의 바이트 수)가 있습니다. 속성 ``samples`` 는 이미지 데이터를 나타내는 바이트의 사각형 영역(Python ``bytes`` 객체)을 나타냅니다.\"\n\n#: ../../tutorial.rst:171 03e8c67cd34a4299bbacfe8abd40de63\nmsgid \"\"\n\"You can also create a **vector** image of a page by using \"\n\":meth:`Page.get_svg_image`. Refer to this `Vector Image Support page`_ \"\n\"for details.\"\nmsgstr \":meth:`Page.get_svg_image` 를 사용하여 페이지의 **벡터** 이미지를 생성할 수도 있습니다. 자세한 내용은 `Vector Image Support page`_ 를 참조하세요.\"\n\n#: ../../tutorial.rst:174 c887d409be174ceca947d6b32e881d03\nmsgid \"Saving the Page Image in a File\"\nmsgstr \"파일에 페이지 이미지 저장\"\n\n#: ../../tutorial.rst:175 5e39659faf42451083abd892ba3bdb4e\nmsgid \"We can simply store the image in a PNG file::\"\nmsgstr \"이미지를 PNG 파일에 간단히 저장할 수 있습니다::\"\n\n#: ../../tutorial.rst:180 7ef7b19218354906a6c5d511a0672a1f\nmsgid \"Displaying the Image in GUIs\"\nmsgstr \"GUI에서 이미지 표시\"\n\n#: ../../tutorial.rst:181 f6651c84f3d54689abdaff0d00a3095e\nmsgid \"\"\n\"We can also use it in GUI dialog managers. :attr:`Pixmap.samples` \"\n\"represents an area of bytes of all the pixels as a Python bytes object. \"\n\"Here are some examples, find more in the `examples`_ directory.\"\nmsgstr \"GUI 대화 상자 관리자에서도 사용할 수 있습니다. :attr:`Pixmap.samples` 는 모든 픽셀의 바이트 영역을 Python bytes 객체로 나타냅니다. 다음은 몇 가지 예입니다. `examples`_ 디렉토리에서 더 많은 예를 찾을 수 있습니다.\"\n\n#: ../../tutorial.rst:184 93b0ff029516467ca4a36bb526aeb687\nmsgid \"wxPython\"\nmsgstr \"wxPython\"\n\n#: ../../tutorial.rst:185 6f03843027834dda8394ee85d04238d5\nmsgid \"\"\n\"Consult their documentation for adjustments to RGB(A) pixmaps and, \"\n\"potentially, specifics for your wxPython release::\"\nmsgstr \"RGB(A) pixmap 조정 및 wxPython 릴리스별 세부 사항에 대해서는 해당 문서를 참조하세요::\"\n\n#: ../../tutorial.rst:193 b6f1e9b15675411e9bd7023777e4b99a\nmsgid \"Tkinter\"\nmsgstr \"Tkinter\"\n\n#: ../../tutorial.rst:194 c11e72b65c0e4368a0fe00c748909105\nmsgid \"Please also see section 3.19 of the `Pillow documentation`_::\"\nmsgstr \"`Pillow documentation`_ 의 섹션 3.19도 참조하세요::\"\n\n#: ../../tutorial.rst:203 41e53493133b4606b75fc48aa4b02d6b\nmsgid \"The following **avoids using Pillow**::\"\nmsgstr \"다음은 **Pillow 사용을 피합니다**::\"\n\n#: ../../tutorial.rst:210 2d36aa26bccf4e5ba49ede95aef20a49\nmsgid \"\"\n\"If you are looking for a complete Tkinter script paging through **any \"\n\"supported** document, `here it is!`_. It can also zoom into pages, and it\"\n\" runs under Python 2 or 3. It requires the extremely handy `PySimpleGUI`_\"\n\" pure Python package.\"\nmsgstr \"**지원되는 모든** 문서를 페이지로 나누는 완전한 Tkinter 스크립트를 찾고 있다면 `여기 있습니다!`_. 페이지 확대도 가능하며 Python 2 또는 3에서 실행됩니다. 매우 편리한 `PySimpleGUI`_ 순수 Python 패키지가 필요합니다.\"\n\n#: ../../tutorial.rst:213 9a88cb97b2d9452ab197250569501e5f\nmsgid \"PyQt4, PyQt5, PySide\"\nmsgstr \"PyQt4, PyQt5, PySide\"\n\n#: ../../tutorial.rst:214 daeac83261ba4066a7dc604d3aa562f2\nmsgid \"Please also see section 3.16 of the `Pillow documentation`_::\"\nmsgstr \"`Pillow documentation`_ 의 섹션 3.16도 참조하세요::\"\n\n#: ../../tutorial.rst:223 b85add3e93e4499b89e82f1646430a26\nmsgid \"\"\n\"Again, you also can get along **without using Pillow.** Qt's `QImage` \"\n\"luckily supports native Python pointers, so the following is the \"\n\"recommended way to create Qt images::\"\nmsgstr \"다시 말하지만, **Pillow를 사용하지 않고도** 진행할 수 있습니다. Qt의 `QImage` 는 다행히 네이티브 Python 포인터를 지원하므로 다음은 Qt 이미지를 생성하는 권장 방법입니다::\"\n\n#: ../../tutorial.rst:233 0fcb7bc54009424fa20575e22fb06d0e\nmsgid \"Extracting Text and Images\"\nmsgstr \"텍스트 및 이미지 추출\"\n\n#: ../../tutorial.rst:234 f5900cc6c4924334a0f4bf4d1bdae4ae\nmsgid \"\"\n\"We can also extract all text, images and other information of a page in \"\n\"many different forms, and levels of detail::\"\nmsgstr \"페이지의 모든 텍스트, 이미지 및 기타 정보를 다양한 형식과 세부 수준으로 추출할 수도 있습니다::\"\n\n#: ../../tutorial.rst:238 48bff694040b45549010d3b53435733b\nmsgid \"\"\n\"Use one of the following strings for *opt* to obtain different formats \"\n\"[#f2]_:\"\nmsgstr \"다양한 형식을 얻으려면 *opt* 에 다음 문자열 중 하나를 사용하세요 [#f2]_:\"\n\n#: ../../tutorial.rst:240 3c9203fe338a46629695295936dc44a4\nmsgid \"\"\n\"**\\\"text\\\"**: (default) plain text with line breaks. No formatting, no \"\n\"text position details, no images.\"\nmsgstr \"**\\\"text\\\"**: (기본값) 줄바꿈이 있는 일반 텍스트. 서식 없음, 텍스트 위치 세부 정보 없음, 이미지 없음.\"\n\n#: ../../tutorial.rst:242 ef523faacbb4433e9599b78451f9a623\nmsgid \"**\\\"blocks\\\"**: generate a list of text blocks (= paragraphs).\"\nmsgstr \"**\\\"blocks\\\"**: 텍스트 블록(= 단락) 목록 생성.\"\n\n#: ../../tutorial.rst:244 494f2cbaf4dc4d3595b54a18d8165a4f\nmsgid \"**\\\"words\\\"**: generate a list of words (strings not containing spaces).\"\nmsgstr \"**\\\"words\\\"**: 단어 목록 생성(공백을 포함하지 않는 문자열).\"\n\n#: ../../tutorial.rst:246 f95d696f7efa4e48a4fe4018638ee139\nmsgid \"\"\n\"**\\\"html\\\"**: creates a full visual version of the page including any \"\n\"images. This can be displayed with your internet browser.\"\nmsgstr \"**\\\"html\\\"**: 이미지를 포함한 페이지의 전체 시각적 버전 생성. 인터넷 브라우저로 표시할 수 있습니다.\"\n\n#: ../../tutorial.rst:248 8f24748d78b04cc6b92c29fcae8ff8ca\nmsgid \"\"\n\"**\\\"dict\\\"** / **\\\"json\\\"**: same information level as HTML, but provided\"\n\" as a Python dictionary or resp. JSON string. See \"\n\":meth:`TextPage.extractDICT` for details of its structure.\"\nmsgstr \"**\\\"dict\\\"** / **\\\"json\\\"**: HTML과 동일한 정보 수준이지만 Python 딕셔너리 또는 JSON 문자열로 제공됩니다. 구조에 대한 자세한 내용은 :meth:`TextPage.extractDICT` 를 참조하세요.\"\n\n#: ../../tutorial.rst:250 266283a205584bb98dd88e0282b81b8a\nmsgid \"\"\n\"**\\\"rawdict\\\"** / **\\\"rawjson\\\"**: a super-set of **\\\"dict\\\"** / \"\n\"**\\\"json\\\"**. It additionally provides character detail information like \"\n\"XML. See :meth:`TextPage.extractRAWDICT` for details of its structure.\"\nmsgstr \"**\\\"rawdict\\\"** / **\\\"rawjson\\\"**: **\\\"dict\\\"** / **\\\"json\\\"** 의 상위 집합. XML과 같은 문자 세부 정보를 추가로 제공합니다. 구조에 대한 자세한 내용은 :meth:`TextPage.extractRAWDICT` 를 참조하세요.\"\n\n#: ../../tutorial.rst:252 be5015a7daf84be89659b718295dcaf6\nmsgid \"\"\n\"**\\\"xhtml\\\"**: text information level as the TEXT version but includes \"\n\"images. Can also be displayed by internet browsers.\"\nmsgstr \"**\\\"xhtml\\\"**: TEXT 버전과 동일한 텍스트 정보 수준이지만 이미지를 포함합니다. 인터넷 브라우저로도 표시할 수 있습니다.\"\n\n#: ../../tutorial.rst:254 6a9fccccc2af470dbe418b64d95196fb\nmsgid \"\"\n\"**\\\"xml\\\"**: contains no images, but full position and font information \"\n\"down to each single text character. Use an XML module to interpret.\"\nmsgstr \"**\\\"xml\\\"**: 이미지는 포함하지 않지만 각 단일 텍스트 문자까지 전체 위치 및 글꼴 정보를 포함합니다. XML 모듈을 사용하여 해석합니다.\"\n\n#: ../../tutorial.rst:256 c2fb29629d574544ba6240118706a993\nmsgid \"\"\n\"To give you an idea about the output of these alternatives, we did text \"\n\"example extracts. See :ref:`Appendix1`.\"\nmsgstr \"이러한 대안의 출력에 대한 아이디어를 제공하기 위해 텍스트 예제 추출을 수행했습니다. :ref:`Appendix1` 을 참조하세요.\"\n\n#: ../../tutorial.rst:259 6fcbe8fa549f4672940aa6a7baa43298\nmsgid \"Searching for Text\"\nmsgstr \"텍스트 검색\"\n\n#: ../../tutorial.rst:260 055f0da706d34efba1868870cc7ac25e\nmsgid \"You can find out, exactly where on a page a certain text string appears::\"\nmsgstr \"페이지에서 특정 텍스트 문자열이 정확히 어디에 나타나는지 확인할 수 있습니다::\"\n\n#: ../../tutorial.rst:264 fa6460b021d44b8aba602b1940777f99\nmsgid \"\"\n\"This delivers a list of rectangles (see :ref:`Rect`), each of which \"\n\"surrounds one occurrence of the string \\\"mupdf\\\" (case insensitive). You \"\n\"could use this information to e.g. highlight those areas (PDF only) or \"\n\"create a cross reference of the document.\"\nmsgstr \"이것은 사각형 목록(:ref:`Rect` 참조)을 제공하며, 각각은 문자열 \\\"mupdf\\\" 의 한 번 발생을 둘러쌉니다(대소문자 구분 안 함). 이 정보를 사용하여 예를 들어 해당 영역을 강조 표시하거나(PDF만) 문서의 상호 참조를 생성할 수 있습니다.\"\n\n#: ../../tutorial.rst:266 9602ff0fbee54febb5a9bce0eb7643a8\nmsgid \"\"\n\"Please also do have a look at chapter :ref:`cooperation` and at demo \"\n\"programs `demo.py`_ and `demo-lowlevel.py`_. Among other things they \"\n\"contain details on how the :ref:`TextPage`, :ref:`Device` and \"\n\":ref:`DisplayList` classes can be used for a more direct control, e.g. \"\n\"when performance considerations suggest it.\"\nmsgstr \":ref:`cooperation` 장과 데모 프로그램 `demo.py`_ 및 `demo-lowlevel.py`_ 도 살펴보세요. 특히 성능 고려 사항이 제안될 때 :ref:`TextPage`, :ref:`Device` 및 :ref:`DisplayList` 클래스를 더 직접적으로 제어하는 방법에 대한 세부 정보를 포함합니다.\"\n\n#: ../../tutorial.rst:273 d532b1e3d0b249d5863b7d1af292f56f\nmsgid \"Stories: Generating PDF from HTML Source\"\nmsgstr \"Stories: HTML 소스에서 PDF 생성\"\n\n#: ../../tutorial.rst:275 416352710d134781921a3400fd5b5ef0\nmsgid \"\"\n\"The :ref:`Story` class is a new feature of PyMuPDF version 1.21.0. It \"\n\"represents support for MuPDF's **\\\"story\\\"** interface.\"\nmsgstr \":ref:`Story` 클래스는 |PyMuPDF| 버전 1.21.0의 새로운 기능입니다. |MuPDF| 의 **\\\"story\\\"** 인터페이스 지원을 나타냅니다.\"\n\n#: ../../tutorial.rst:277 accd3e3fc6d547b78b274237642033d6\nmsgid \"\"\n\"The following is a quote from the book `\\\"MuPDF Explored\\\"`_ by Robin \"\n\"Watts from `Artifex`_:\"\nmsgstr \"다음은 `Artifex`_ 의 Robin Watts가 쓴 `\\\"MuPDF Explored\\\"`_ 책에서 인용한 내용입니다:\"\n\n#: ../../tutorial.rst:281 47e500970eb842949a968db6adee0910\nmsgid \"\"\n\"*Stories provide a way to easily layout styled content for use with \"\n\"devices, such as those offered by Document Writers (...). The concept of \"\n\"a story comes from desktop publishing, which in turn (...) gets it from \"\n\"newspapers. If you consider a traditional newspaper layout, it will \"\n\"consist of various news articles (stories) that are laid out into \"\n\"multiple columns, possibly across multiple pages.*\"\nmsgstr \"*Stories는 Document Writers가 제공하는 것과 같은 장치에서 사용할 수 있도록 스타일이 지정된 콘텐츠를 쉽게 레이아웃하는 방법을 제공합니다(...). story의 개념은 데스크톱 출판에서 나왔으며, 이는 차례로(...) 신문에서 가져온 것입니다. 전통적인 신문 레이아웃을 고려하면 여러 열로 배치되고 여러 페이지에 걸칠 수 있는 다양한 뉴스 기사(stories)로 구성됩니다.*\"\n\n#: ../../tutorial.rst:283 27ebf650cfb746b6ae9e42bdde508478\nmsgid \"\"\n\"*Accordingly, MuPDF uses a story to represent a flow of text with styling\"\n\" information. The user of the story can then supply a sequence of \"\n\"rectangles into which the story will be laid out, and the positioned text\"\n\" can then be drawn to an output device. This keeps the concept of the \"\n\"text itself (the story) to be separated from the areas into which the \"\n\"text should be flowed (the layout).*\"\nmsgstr \"*따라서 |MuPDF| 는 스타일 정보가 있는 텍스트 흐름을 나타내기 위해 story를 사용합니다. story 사용자는 story가 배치될 사각형 시퀀스를 제공할 수 있으며, 배치된 텍스트는 출력 장치에 그려질 수 있습니다. 이것은 텍스트 자체(story)의 개념을 텍스트가 흐를 영역(레이아웃)과 분리된 상태로 유지합니다.*\"\n\n#: ../../tutorial.rst:287 7da64d937fe84390a33b56158c76d219\nmsgid \"\"\n\"A Story works somewhat similar to an internet browser: It faithfully \"\n\"parses and renders HTML hypertext and also optional stylesheets (CSS). \"\n\"But its **output is a PDF** -- not web pages.\"\nmsgstr \"Story는 인터넷 브라우저와 다소 유사하게 작동합니다: HTML 하이퍼텍스트와 선택적 스타일시트(CSS)를 충실하게 구문 분석하고 렌더링합니다. 그러나 **출력은 PDF** 입니다. 웹 페이지가 아닙니다.\"\n\n#: ../../tutorial.rst:290 290d5414b6754a0a8cec4ef553811e70\nmsgid \"\"\n\"When creating a :ref:`Story`, the input from up to three different \"\n\"information sources is taken into account. All these items are optional.\"\nmsgstr \":ref:`Story` 를 생성할 때 최대 세 가지 다른 정보 소스의 입력이 고려됩니다. 이러한 항목은 모두 선택 사항입니다.\"\n\n#: ../../tutorial.rst:292 b76811f3a6e94ca48849af027b1e4aa7\nmsgid \"\"\n\"HTML source code, either a Python string or **created by the script** \"\n\"using methods of :ref:`Xml`.\"\nmsgstr \"HTML 소스 코드, Python 문자열이거나 :ref:`Xml` 의 메서드를 사용하여 **스크립트로 생성된** 것.\"\n\n#: ../../tutorial.rst:294 631005d36d9d478eb1222c6746a62f78\nmsgid \"\"\n\"CSS (Cascaded Style Sheet) source code, provided as a Python string. CSS \"\n\"can be used to provide styling information (text font size, color, etc.) \"\n\"like it would happen for web pages. Obviously, this string may also be \"\n\"read from a file.\"\nmsgstr \"CSS(Cascaded Style Sheet) 소스 코드, Python 문자열로 제공됩니다. CSS는 웹 페이지에서와 같이 스타일 정보(텍스트 글꼴 크기, 색상 등)를 제공하는 데 사용할 수 있습니다. 명백히 이 문자열은 파일에서 읽을 수도 있습니다.\"\n\n#: ../../tutorial.rst:296 b555903aaf064df4ac02bf4379ecd84b\nmsgid \"\"\n\"An :ref:`Archive` **must be used** whenever the DOM references images, or\"\n\" uses text fonts except the standard :ref:`Base-14-Fonts`, CJK fonts and \"\n\"the NOTO fonts generated into the PyMuPDF binary.\"\nmsgstr \"DOM이 이미지를 참조하거나 표준 :ref:`Base-14-Fonts`, CJK 글꼴 및 |PyMuPDF| 바이너리에 생성된 NOTO 글꼴을 제외한 텍스트 글꼴을 사용할 때마다 :ref:`Archive` **를 사용해야 합니다**.\"\n\n#: ../../tutorial.rst:299 5a5a7775caf44157ab99d4fb18a08da0\nmsgid \"\"\n\"The :ref:`API<Xml>` allows creating DOMs completely from scratch, \"\n\"including desired styling information. It can also be used to modify or \"\n\"extend **provided** HTML: text can be deleted or replaced, or its styling\"\n\" can be changed. Text -- for example extracted from databases -- can also\"\n\" be added and fill template-like HTML documents.\"\nmsgstr \":ref:`API<Xml>` 는 원하는 스타일 정보를 포함하여 처음부터 DOM을 생성할 수 있게 합니다. 또한 **제공된** HTML을 수정하거나 확장하는 데 사용할 수 있습니다: 텍스트를 삭제하거나 교체하거나 스타일을 변경할 수 있습니다. 데이터베이스에서 추출한 것과 같은 텍스트도 추가하고 템플릿과 같은 HTML 문서를 채울 수 있습니다.\"\n\n#: ../../tutorial.rst:301 eff1f356f57a4a5baa32893df82ccc7f\nmsgid \"\"\n\"It is **not required** to provide syntactically complete HTML documents: \"\n\"snippets like `<b>Hello <i>World!</i></b>` are fully accepted, and many /\"\n\" most syntax errors are automatically corrected.\"\nmsgstr \"구문적으로 완전한 HTML 문서를 제공할 **필요는 없습니다**: `<b>Hello <i>World!</i></b>` 와 같은 스니펫이 완전히 허용되며 많은/대부분의 구문 오류가 자동으로 수정됩니다.\"\n\n#: ../../tutorial.rst:303 365fa2cc06434ed8ad7429aaf3a63265\nmsgid \"\"\n\"After the HTML is considered complete, it can be used to create a PDF \"\n\"document. This happens via the new :ref:`DocumentWriter` class. The \"\n\"programmer calls its methods to create a new empty page, and passes \"\n\"rectangles to the Story to fill them.\"\nmsgstr \"HTML이 완료된 것으로 간주되면 PDF 문서를 생성하는 데 사용할 수 있습니다. 이것은 새로운 :ref:`DocumentWriter` 클래스를 통해 수행됩니다. 프로그래머는 메서드를 호출하여 새로운 빈 페이지를 만들고 Story에 사각형을 전달하여 채웁니다.\"\n\n#: ../../tutorial.rst:305 3291ca47108e47b19f4b0bc0a5a4027b\nmsgid \"\"\n\"The story in turn will return completion codes indicating whether or not \"\n\"more content is waiting to be written. Which part of the content will \"\n\"land in which rectangle or on which page is automatically determined by \"\n\"the story itself -- it cannot be influenced other than by providing the \"\n\"rectangles.\"\nmsgstr \"story는 차례로 더 많은 콘텐츠가 작성되기를 기다리고 있는지 여부를 나타내는 완료 코드를 반환합니다. 콘텐츠의 어느 부분이 어떤 사각형이나 어떤 페이지에 배치될지는 story 자체에 의해 자동으로 결정됩니다. 사각형을 제공하는 것 외에는 영향을 줄 수 없습니다.\"\n\n#: ../../tutorial.rst:307 bd9d9dd769be42d4b2431ad4fac946e4\nmsgid \"\"\n\"Please see the :ref:`Stories recipes<RecipesStories>` for a number of \"\n\"typical use cases.\"\nmsgstr \"일반적인 사용 사례는 :ref:`Stories recipes<RecipesStories>` 를 참조하세요.\"\n\n#: ../../tutorial.rst:311 b4514f2b40064533bbf026420a0260d7\nmsgid \"PDF Maintenance\"\nmsgstr \"PDF 유지보수\"\n\n#: ../../tutorial.rst:312 76f8cae636954def812f6bd6aa4d9077\nmsgid \"\"\n\"PDFs are the only document type that can be **modified** using PyMuPDF. \"\n\"Other file types are read-only.\"\nmsgstr \"PDF는 |PyMuPDF| 를 사용하여 **수정** 할 수 있는 유일한 문서 타입입니다. 다른 파일 타입은 읽기 전용입니다.\"\n\n#: ../../tutorial.rst:314 6d192d43c9e24232be29c65e1e0c1018\nmsgid \"\"\n\"However, you can convert **any document** (including images) to a PDF and\"\n\" then apply all PyMuPDF features to the conversion result. Find out more \"\n\"here :meth:`Document.convert_to_pdf`, and also look at the demo script \"\n\"`pdf-converter.py`_ which can convert any :ref:`supported \"\n\"document<Supported_File_Types>` to PDF.\"\nmsgstr \"그러나 **모든 문서** (이미지 포함)를 PDF로 변환한 다음 변환 결과에 모든 |PyMuPDF| 기능을 적용할 수 있습니다. 자세한 내용은 :meth:`Document.convert_to_pdf` 를 참조하고, 모든 :ref:` 지원되는 문서<Supported_File_Types>` 를 PDF로 변환할 수 있는 데모 스크립트 `pdf-converter.py`_ 도 살펴보세요.\"\n\n#: ../../tutorial.rst:316 05d7bbe4027a4e9b98372c4707c22cd4\nmsgid \"\"\n\":meth:`Document.save()` always stores a PDF in its current (potentially \"\n\"modified) state on disk.\"\nmsgstr \":meth:`Document.save()` 는 항상 PDF를 현재(잠재적으로 수정된) 상태로 디스크에 저장합니다.\"\n\n#: ../../tutorial.rst:318 400c516b51f0441a9c6ac7d433101329\nmsgid \"\"\n\"You normally can choose whether to save to a new file, or just append \"\n\"your modifications to the existing one (\\\"incremental save\\\"), which \"\n\"often is very much faster.\"\nmsgstr \"일반적으로 새 파일에 저장할지 또는 기존 파일에 수정 사항만 추가할지(\\\"incremental save\\\") 선택할 수 있으며, 후자가 종종 훨씬 빠릅니다.\"\n\n#: ../../tutorial.rst:320 57fdfcd11a1245249d7e837f37b43094\nmsgid \"\"\n\"The following describes ways how you can manipulate PDF documents. This \"\n\"description is by no means complete: much more can be found in the \"\n\"following chapters.\"\nmsgstr \"다음은 PDF 문서를 조작하는 방법을 설명합니다. 이 설명은 결코 완전하지 않습니다. 다음 장에서 더 많은 내용을 찾을 수 있습니다.\"\n\n#: ../../tutorial.rst:323 ec4c85ec57124203b67f52652f082b88\nmsgid \"Modifying, Creating, Re-arranging and Deleting Pages\"\nmsgstr \"페이지 수정, 생성, 재배열 및 삭제\"\n\n#: ../../tutorial.rst:324 625ab390c172404fbdc7aa9520874495\nmsgid \"\"\n\"There are several ways to manipulate the so-called **page tree** (a \"\n\"structure describing all the pages) of a PDF:\"\nmsgstr \"PDF의 소위 **페이지 트리** (모든 페이지를 설명하는 구조)를 조작하는 여러 방법이 있습니다:\"\n\n#: ../../tutorial.rst:326 159259eb9e4145daa6c13b2ad767f12e\nmsgid \"\"\n\":meth:`Document.delete_page` and :meth:`Document.delete_pages` delete \"\n\"pages.\"\nmsgstr \":meth:`Document.delete_page` 및 :meth:`Document.delete_pages` 는 페이지를 삭제합니다.\"\n\n#: ../../tutorial.rst:328 473d5897fff649019f539d6232e91f44\nmsgid \"\"\n\":meth:`Document.copy_page`, :meth:`Document.fullcopy_page` and \"\n\":meth:`Document.move_page` copy or move a page to other locations within \"\n\"the same document.\"\nmsgstr \":meth:`Document.copy_page`, :meth:`Document.fullcopy_page` 및 :meth:`Document.move_page` 는 페이지를 같은 문서 내의 다른 위치로 복사하거나 이동합니다.\"\n\n#: ../../tutorial.rst:330 1e6c19e64c734426bec58da4dfbe7e0b\nmsgid \"\"\n\":meth:`Document.select` shrinks a PDF down to selected pages. Parameter \"\n\"is a sequence [#f3]_ of the page numbers that you want to keep. These \"\n\"integers must all be in range *0 <= i < page_count*. When executed, all \"\n\"pages **missing** in this list will be deleted. Remaining pages will \"\n\"occur **in the sequence and as many times (!) as you specify them**.\"\nmsgstr \":meth:`Document.select` 는 PDF를 선택한 페이지로 축소합니다. 매개변수는 유지하려는 페이지 번호의 시퀀스 [#f3]_ 입니다. 이러한 정수는 모두 *0 <= i < page_count* 범위에 있어야 합니다. 실행되면 이 목록에 **없는** 모든 페이지가 삭제됩니다. 남은 페이지는 **시퀀스에서 지정한 횟수만큼(!) 나타납니다**.\"\n\n#: ../../tutorial.rst:332 1032d54636274cfab2c769409afa76e0\nmsgid \"So you can easily create new PDFs with\"\nmsgstr \"따라서 다음과 같은 새 PDF를 쉽게 만들 수 있습니다:\"\n\n#: ../../tutorial.rst:334 e8415caf00594110bef2b948c89abcbd\nmsgid \"the first or last 10 pages,\"\nmsgstr \"처음 또는 마지막 10페이지,\"\n\n#: ../../tutorial.rst:335 fc336f721207413b95dce987329adfad\nmsgid \"only the odd or only the even pages (for doing double-sided printing),\"\nmsgstr \"홀수 페이지만 또는 짝수 페이지만(양면 인쇄용),\"\n\n#: ../../tutorial.rst:336 3a6929bd1e7d4e178ef1549c9c67d87a\nmsgid \"pages that **do** or **don't** contain a given text,\"\nmsgstr \"주어진 텍스트를 **포함하는** 또는 **포함하지 않는** 페이지,\"\n\n#: ../../tutorial.rst:337 968ba746356447208207a1cee391ea52\nmsgid \"reverse the page sequence, ...\"\nmsgstr \"페이지 시퀀스 반전, ...\"\n\n#: ../../tutorial.rst:339 1c2ed724e9564be1a8841011462e53a1\nmsgid \"... whatever you can think of.\"\nmsgstr \"... 생각할 수 있는 모든 것.\"\n\n#: ../../tutorial.rst:341 3a7dc1aa206e4858a930d0cc0ce437cf\nmsgid \"\"\n\"The saved new document will contain links, annotations and bookmarks that\"\n\" are still valid (i.a.w. either pointing to a selected page or to some \"\n\"external resource).\"\nmsgstr \"저장된 새 문서는 여전히 유효한 링크, 주석 및 북마크를 포함합니다(즉, 선택한 페이지 또는 일부 외부 리소스를 가리킴).\"\n\n#: ../../tutorial.rst:343 62273df02f3a43edaca93b7b9899b551\nmsgid \"\"\n\":meth:`Document.insert_page` and :meth:`Document.new_page` insert new \"\n\"pages.\"\nmsgstr \":meth:`Document.insert_page` 및 :meth:`Document.new_page` 는 새 페이지를 삽입합니다.\"\n\n#: ../../tutorial.rst:345 62ec5bdcc4854cc0ab7b5a9c5de8295e\nmsgid \"\"\n\"Pages themselves can moreover be modified by a range of methods (e.g. \"\n\"page rotation, annotation and link maintenance, text and image \"\n\"insertion).\"\nmsgstr \"페이지 자체는 다양한 메서드(예: 페이지 회전, 주석 및 링크 유지보수, 텍스트 및 이미지 삽입)로 수정할 수 있습니다.\"\n\n#: ../../tutorial.rst:348 f481a1f85523458ba716bfffa017ecc2\nmsgid \"Joining and Splitting PDF Documents\"\nmsgstr \"PDF 문서 결합 및 분할\"\n\n#: ../../tutorial.rst:350 5c4f9e715c364f99ab85e02a35390a54\nmsgid \"\"\n\"Method :meth:`Document.insert_pdf` copies pages **between different** PDF\"\n\" documents. Here is a simple **joiner** example (*doc1* and *doc2* being \"\n\"opened PDFs)::\"\nmsgstr \":meth:`Document.insert_pdf` 메서드는 **다른** PDF 문서 간에 페이지를 복사합니다. 다음은 간단한 **결합** 예제입니다(*doc1* 및 *doc2* 는 열린 PDF)::\"\n\n#: ../../tutorial.rst:355 76e1ca6378be4c7780b008c6aa0147b1\nmsgid \"\"\n\"Here is a snippet that **splits** *doc1*. It creates a new document of \"\n\"its first and its last 10 pages::\"\nmsgstr \"다음은 *doc1* 을 **분할** 하는 스니펫입니다. 처음 10페이지와 마지막 10페이지로 새 문서를 만듭니다::\"\n\n#: ../../tutorial.rst:362 425d928677684aaebd2c13acc306cc3a\nmsgid \"\"\n\"More can be found in the :ref:`Document` chapter. Also have a look at \"\n\"`PDFjoiner.py`_.\"\nmsgstr \"더 많은 내용은 :ref:`Document` 장에서 찾을 수 있습니다. `PDFjoiner.py`_ 도 살펴보세요.\"\n\n#: ../../tutorial.rst:365 3a32f81f55af4ff2942e6a5bda5351e4\nmsgid \"Embedding Data\"\nmsgstr \"데이터 임베딩\"\n\n#: ../../tutorial.rst:367 e8c1a07274464e69b5716d2cfcd333a2\nmsgid \"\"\n\"PDFs can be used as containers for arbitrary data (executables, other \"\n\"PDFs, text or binary files, etc.) much like ZIP archives.\"\nmsgstr \"PDF는 ZIP 아카이브와 매우 유사하게 임의의 데이터(실행 파일, 다른 PDF, 텍스트 또는 바이너리 파일 등)의 컨테이너로 사용할 수 있습니다.\"\n\n#: ../../tutorial.rst:369 e53116859c304e5d8cae52bca7615d49\nmsgid \"\"\n\"PyMuPDF fully supports this feature via :ref:`Document` ``embfile_*`` \"\n\"methods and attributes. For some detail read :ref:`Appendix 3`, consult \"\n\"the Wiki on `dealing with embedding files`_, or the example scripts \"\n\"`embedded-copy.py`_, `embedded-export.py`_, `embedded-import.py`_, and \"\n\"`embedded-list.py`_.\"\nmsgstr \"|PyMuPDF| 는 :ref:`Document` ``embfile_*`` 메서드 및 속성을 통해 이 기능을 완전히 지원합니다. 자세한 내용은 :ref:`Appendix 3` 을 읽거나, `dealing with embedding files`_ 에 대한 Wiki를 참조하거나, 예제 스크립트 `embedded-copy.py`_, `embedded-export.py`_, `embedded-import.py`_, `embedded-list.py`_ 를 살펴보세요.\"\n\n#: ../../tutorial.rst:373 7e063cc85bf74b67af328699883eabcd\nmsgid \"Saving\"\nmsgstr \"저장\"\n\n#: ../../tutorial.rst:375 ddc980f323444d9a888df621e5e4413a\nmsgid \"\"\n\"As mentioned above, :meth:`Document.save` will **always** save the \"\n\"document in its current state.\"\nmsgstr \"위에서 언급한 대로 :meth:`Document.save` 는 **항상** 문서를 현재 상태로 저장합니다.\"\n\n#: ../../tutorial.rst:377 938eb4bca93d44e7ad9d9db6a21b0197\nmsgid \"\"\n\"You can write changes back to the **original PDF** by specifying option \"\n\"``incremental=True``. This process is (usually) **extremely fast**, since\"\n\" changes are **appended to the original file** without completely \"\n\"rewriting it.\"\nmsgstr \"``incremental=True`` 옵션을 지정하여 변경 사항을 **원본 PDF** 에 다시 쓸 수 있습니다. 이 프로세스는 (일반적으로) **매우 빠릅니다**. 파일을 완전히 다시 쓰지 않고 변경 사항을 **원본 파일에 추가** 하기 때문입니다.\"\n\n#: ../../tutorial.rst:379 34a90e8b41204457b27c7bf4c896ed07\nmsgid \"\"\n\":meth:`Document.save` options correspond to options of MuPDF's command \"\n\"line utility *mutool clean*, see the following table.\"\nmsgstr \":meth:`Document.save` 옵션은 |MuPDF| 의 명령줄 유틸리티 *mutool clean* 의 옵션에 해당합니다. 다음 표를 참조하세요.\"\n\n#: ../../tutorial.rst:382 1163070c3e2e478c9edfeeef99960201\nmsgid \"**Save Option**\"\nmsgstr \"**저장 옵션**\"\n\n#: ../../tutorial.rst:382 94311b1ebca3478a8d7bf6f6d522fd8b\nmsgid \"**mutool**\"\nmsgstr \"**mutool**\"\n\n#: ../../tutorial.rst:382 962d3ef8846c431c8e9dfdf9d487bfb1\nmsgid \"**Effect**\"\nmsgstr \"**효과**\"\n\n#: ../../tutorial.rst:384 b65cf8acc8bc476f8334931a4c8a17b8\nmsgid \"garbage=1\"\nmsgstr \"garbage=1\"\n\n#: ../../tutorial.rst:384 6b4221531c1b4915975145d5a46840f9\nmsgid \"g\"\nmsgstr \"g\"\n\n#: ../../tutorial.rst:384 b773213735d5433a912d7d50de094b58\nmsgid \"garbage collect unused objects\"\nmsgstr \"사용하지 않는 객체 가비지 수집\"\n\n#: ../../tutorial.rst:385 9bb3557107484b32b9d48ee883975e41\nmsgid \"garbage=2\"\nmsgstr \"garbage=2\"\n\n#: ../../tutorial.rst:385 e5d8266ec4434156843ae8d329cb1234\nmsgid \"gg\"\nmsgstr \"gg\"\n\n#: ../../tutorial.rst:385 5d1cd64ee4a44495b52e5808a4c51ebf\nmsgid \"in addition to 1, compact :data:`xref` tables\"\nmsgstr \"1에 추가하여 :data:`xref` 테이블 압축\"\n\n#: ../../tutorial.rst:386 5846a30c454d494b9cb77c2612b7e3ba\nmsgid \"garbage=3\"\nmsgstr \"garbage=3\"\n\n#: ../../tutorial.rst:386 8499a2c0b7254ddfbc44cba627532452\nmsgid \"ggg\"\nmsgstr \"ggg\"\n\n#: ../../tutorial.rst:386 349d1afd120c468c8663d3467baf0a1d\nmsgid \"in addition to 2, merge duplicate objects\"\nmsgstr \"2에 추가하여 중복 객체 병합\"\n\n#: ../../tutorial.rst:387 f97513200d184db2818ef3272e06659d\nmsgid \"garbage=4\"\nmsgstr \"garbage=4\"\n\n#: ../../tutorial.rst:387 8818b59f9bf3464e8ff2acae77c152f2\nmsgid \"gggg\"\nmsgstr \"gggg\"\n\n#: ../../tutorial.rst:387 c284ddf0b0794e979bfa728c57373d83\nmsgid \"in addition to 3, merge duplicate stream content\"\nmsgstr \"3에 추가하여 중복 스트림 콘텐츠 병합\"\n\n#: ../../tutorial.rst:388 7874a21a2a374610abddf1cbd7efb717\nmsgid \"clean=True\"\nmsgstr \"clean=True\"\n\n#: ../../tutorial.rst:388 c1e6bac1097a452a8399150c1e9c8279\nmsgid \"cs\"\nmsgstr \"cs\"\n\n#: ../../tutorial.rst:388 9ddc64830c9040ed8451f02ed2741816\nmsgid \"clean and sanitize content streams\"\nmsgstr \"콘텐츠 스트림 정리 및 정화\"\n\n#: ../../tutorial.rst:389 c2f486c396c84db0ba07db1c9ee5a7ae\nmsgid \"deflate=True\"\nmsgstr \"deflate=True\"\n\n#: ../../tutorial.rst:389 49a98a67d15747c98e6ca70bb53f3c51\nmsgid \"z\"\nmsgstr \"z\"\n\n#: ../../tutorial.rst:389 37e910e46f2247d3a69e36dbd0748d94\nmsgid \"deflate uncompressed streams\"\nmsgstr \"압축되지 않은 스트림 압축\"\n\n#: ../../tutorial.rst:390 7ffbd7aa96264ff1902b58f73b4fd092\nmsgid \"deflate_images=True\"\nmsgstr \"deflate_images=True\"\n\n#: ../../tutorial.rst:390 83ea4c4b317d488092885540eb84f939\nmsgid \"i\"\nmsgstr \"i\"\n\n#: ../../tutorial.rst:390 4e719956c06a4d49bb8d10a19576ee42\nmsgid \"deflate image streams\"\nmsgstr \"이미지 스트림 압축\"\n\n#: ../../tutorial.rst:391 c33f6052e9494538ae7f4e1191c64fd2\nmsgid \"deflate_fonts=True\"\nmsgstr \"deflate_fonts=True\"\n\n#: ../../tutorial.rst:391 9786f972e1be4a16b85ffee8b754ec19\nmsgid \"f\"\nmsgstr \"f\"\n\n#: ../../tutorial.rst:391 79fefb0533874ecb8a096e7db7f10332\nmsgid \"deflate fontfile streams\"\nmsgstr \"글꼴 파일 스트림 압축\"\n\n#: ../../tutorial.rst:392 423d166f2fc54b4498a9377a2dd30960\nmsgid \"ascii=True\"\nmsgstr \"ascii=True\"\n\n#: ../../tutorial.rst:392 a67143a6cbe040c590ae0a63a0fe9234\nmsgid \"a\"\nmsgstr \"a\"\n\n#: ../../tutorial.rst:392 59590f861522439b8f81250d3941e06c\nmsgid \"convert binary data to ASCII format\"\nmsgstr \"바이너리 데이터를 ASCII 형식으로 변환\"\n\n#: ../../tutorial.rst:393 86236a9e66cf4150970d92080d6e1583\nmsgid \"linear=True\"\nmsgstr \"linear=True\"\n\n#: ../../tutorial.rst:393 5893e24f2faa4060ba0c43aa63dbd263\nmsgid \"l\"\nmsgstr \"l\"\n\n#: ../../tutorial.rst:393 0dec5675398e49978e78651893a99395\nmsgid \"create a linearized version\"\nmsgstr \"선형화된 버전 생성\"\n\n#: ../../tutorial.rst:394 febbe58d4b104f8bbe950ccccccb1859\nmsgid \"expand=True\"\nmsgstr \"expand=True\"\n\n#: ../../tutorial.rst:394 ef0e028a01314e21a0d744ca0d2ad01f\nmsgid \"d\"\nmsgstr \"d\"\n\n#: ../../tutorial.rst:394 09ec7a0736e34a67aa68a9542195d17e\nmsgid \"decompress all streams\"\nmsgstr \"모든 스트림 압축 해제\"\n\n#: ../../tutorial.rst:397 e917b060c085407fb80a474e3bec75e9\nmsgid \"\"\n\"For an explanation of terms like ``object``, ``stream``, ``xref`` consult\"\n\" the :ref:`Glossary` chapter.\"\nmsgstr \"``object``, ``stream``, ``xref`` 와 같은 용어에 대한 설명은 :ref:`Glossary` 장을 참조하세요.\"\n\n#: ../../tutorial.rst:399 dcb5dc3e6c3a41349a7db5e5052ed2e0\nmsgid \"\"\n\"For example, ``mutool clean -ggggz file.pdf`` yields excellent \"\n\"compression results. It corresponds to ``doc.save(filename, garbage=4, \"\n\"deflate=True)``.\"\nmsgstr \"예를 들어 ``mutool clean -ggggz file.pdf`` 는 우수한 압축 결과를 제공합니다. 이것은 ``doc.save(filename, garbage=4, deflate=True)`` 에 해당합니다.\"\n\n#: ../../tutorial.rst:402 c79ea0512d3b44e78f142255268af6ac\nmsgid \"Closing\"\nmsgstr \"닫기\"\n\n#: ../../tutorial.rst:403 f745b8b8cfd64cd0955b6d9c72baa5f3\nmsgid \"\"\n\"It is often desirable to \\\"close\\\" a document to relinquish control of \"\n\"the underlying file to the OS, while your program continues.\"\nmsgstr \"프로그램이 계속 실행되는 동안 기본 파일에 대한 제어를 OS에 반환하기 위해 문서를 \\\"닫는\\\" 것이 종종 바람직합니다.\"\n\n#: ../../tutorial.rst:405 6ec44b753b01413a9bcbd6b21a1310d7\nmsgid \"\"\n\"This can be achieved by the :meth:`Document.close` method. Apart from \"\n\"closing the underlying file, buffer areas associated with the document \"\n\"will be freed.\"\nmsgstr \"이것은 :meth:`Document.close` 메서드로 달성할 수 있습니다. 기본 파일을 닫는 것 외에도 문서와 연결된 버퍼 영역이 해제됩니다.\"\n\n#: ../../tutorial.rst:408 88cb960755d5457da5441939ff0c836d\nmsgid \"Further Reading\"\nmsgstr \"추가 읽기\"\n\n#: ../../tutorial.rst:409 079337447add4588b00679495c0756c6\nmsgid \"\"\n\"Also have a look at PyMuPDF's `Wiki`_ pages. Especially those named in \"\n\"the sidebar under title **\\\"Recipes\\\"** cover over 15 topics written in \"\n\"\\\"How-To\\\" style.\"\nmsgstr \"|PyMuPDF| 의 `Wiki`_ 페이지도 살펴보세요. 특히 사이드바의 **\\\"Recipes\\\"** 제목 아래에 나열된 항목은 \\\"How-To\\\" 스타일로 작성된 15개 이상의 주제를 다룹니다.\"\n\n#: ../../tutorial.rst:411 4ff206365d3c46319f8786732294335f\nmsgid \"\"\n\"This document also contains a :ref:`FAQ`. This chapter has close \"\n\"connection to the aforementioned recipes, and it will be extended with \"\n\"more content over time.\"\nmsgstr \"이 문서에는 :ref:`FAQ` 도 포함되어 있습니다. 이 장은 앞서 언급한 recipes와 밀접한 관련이 있으며, 시간이 지나면서 더 많은 콘텐츠로 확장될 것입니다.\"\n\n#: ../../tutorial.rst:418 8469cb98a4bc46da95e015537403452d\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../tutorial.rst:419 7abfecf3e58542b0859cd575498948f7\nmsgid \"\"\n\"PyMuPDF lets you also open several image file types just like normal \"\n\"documents. See section :ref:`ImageFiles` in chapter :ref:`Pixmap` for \"\n\"more comments.\"\nmsgstr \"|PyMuPDF| 는 일반 문서처럼 여러 이미지 파일 타입을 열 수 있게 합니다. 자세한 내용은 :ref:`Pixmap` 장의 :ref:`ImageFiles` 섹션을 참조하세요.\"\n\n#: ../../tutorial.rst:421 70b740aad28644b395c85b6a12f20f0e\nmsgid \"\"\n\":meth:`Page.get_text` is a convenience wrapper for several methods of \"\n\"another PyMuPDF class, :ref:`TextPage`. The names of these methods \"\n\"correspond to the argument string passed to :meth:`Page.get_text` \\\\:  \"\n\"*Page.get_text(\\\"dict\\\")* is equivalent to *TextPage.extractDICT()* \\\\.\"\nmsgstr \":meth:`Page.get_text` 는 다른 |PyMuPDF| 클래스인 :ref:`TextPage` 의 여러 메서드에 대한 편의 래퍼입니다. 이러한 메서드의 이름은 :meth:`Page.get_text` 에 전달된 인수 문자열에 해당합니다: *Page.get_text(\\\"dict\\\")* 는 *TextPage.extractDICT()* 와 동일합니다.\"\n\n#: ../../tutorial.rst:423 13eddbfd7bd64cd49e523d76972c7368\nmsgid \"\"\n\"\\\"Sequences\\\" are Python objects conforming to the sequence protocol. \"\n\"These objects implement a method named *__getitem__()*. Best known \"\n\"examples are Python tuples and lists. But *array.array*, *numpy.array* \"\n\"and PyMuPDF's \\\"geometry\\\" objects (:ref:`Algebra`) are sequences, too. \"\n\"Refer to :ref:`SequenceTypes` for details.\"\nmsgstr \"\\\"Sequences\\\"는 시퀀스 프로토콜을 준수하는 Python 객체입니다. 이러한 객체는 *__getitem__()* 이라는 메서드를 구현합니다. 가장 잘 알려진 예는 Python 튜플과 리스트입니다. 그러나 *array.array*, *numpy.array* 및 |PyMuPDF| 의 \\\"geometry\\\" 객체(:ref:`Algebra`)도 시퀀스입니다. 자세한 내용은 :ref:`SequenceTypes` 를 참조하세요.\"\n\n#: ../../footer.rst:46 34f591e7f8ab491b884b15a32b4f508e\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/vars.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 b5ad9d8dc172425eb69cab3f7d6af3f1\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 469b53fb216c416cab35e3785cb83220\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 3fc4b25efb434bdd9a36d5ea7c1bb7e4\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../vars.rst:5 f49c06cd5a6f4032b8cd339c64a77df1\nmsgid \"Constants and Enumerations\"\nmsgstr \"상수 및 열거형\"\n\n#: ../../vars.rst:6 49759909465a4d1794c2b500ea92ef1d\nmsgid \"\"\n\"Constants and enumerations of :title:`MuPDF` as implemented by |PyMuPDF|.\"\n\" Each of the following values is accessible as `pymupdf.value`.\"\nmsgstr \"|PyMuPDF| 에서 구현한 :title:`MuPDF` 의 상수 및 열거형. 다음 각 값은 `pymupdf.value` 로 접근할 수 있습니다.\"\n\n#: ../../vars.rst:10 32fc3323ad3f4cdfb477267318e012bc\nmsgid \"Constants\"\nmsgstr \"상수\"\n\n#: ../../vars.rst:14 5b27640ef1ee4e98bea1cf03003160a1\nmsgid \"Predefined Python list of valid :ref:`Base-14-Fonts`.\"\nmsgstr \"유효한 :ref:`Base-14-Fonts` 의 사전 정의된 Python 목록.\"\n\n#: ../../vars.rst 03741e7ad1a44d5299f6572dedaca7b4\n#: 049f7b4ff1974e208b3a904e6026a510 05d7b5730e6142eb96888bc1f1fbcc93\n#: 0651bf5144c1497e884e5c0cc6076c5a 0d7a04755856497fa83f67a8849b2425\n#: 26435fd0d5d24581abb8057002bce4cc 340ebf4c39ec45d4bfe3a768d8345ba6\n#: 4305209c628b41b484db244a821e36a6 441240ad284b456d8fe847ecb191b0f1\n#: 5ba5705e35594ba28d545462f311e0f9 61aa981fd8a346deaaf51a3d4c08d34a\n#: 6ca990f8a13b4358bbabc20892811cc3 771ae51b4e044a81ae255f6c908697fb\n#: 84cd0a4cb52c4fec9fe883c2ad4ace9d 850da1d028064e8191dfa082a3f82827\n#: 8792cce457a84f11b18d64b74d8debc3 8a25036eb68c414abfb7ad4fa62d7229\n#: 92c64e0683614c6c9deb6668c7f4b761 a2004991370a40408515cf83163b6ffb\n#: cdbf08fc2b5b4750b45132b7ec6c2616 d06dea99fa0a4e3cbee4b2b714c43296\n#: f03ecc8098ca4cc181b8356bd7a2bb91 f3646d6d4cee48e0b1af3350ce178eec\n#: f7af32255ccb4f66a37175278b7b7087 fddcade3afa241b8a81b00e45d91f2a4\nmsgid \"type\"\nmsgstr \"유형\"\n\n#: ../../vars.rst:16 669fb77a7bdd4fbcb224507f1b8d7932\nmsgid \"list\"\nmsgstr \"list\"\n\n#: ../../vars.rst:20 b3ae8b9f4f43444aa8fdc74de25f17f0\nmsgid \"Predefined RGB colorspace *pymupdf.Colorspace(pymupdf.CS_RGB)*.\"\nmsgstr \"사전 정의된 RGB 색 공간 *pymupdf.Colorspace(pymupdf.CS_RGB)*.\"\n\n#: ../../vars.rst:22 ../../vars.rst:28 ../../vars.rst:34\n#: 19f89992935a4f8e839adc1511263368 204d25d273a7452cb5ba5e71b6869076\n#: 79e2265294cd409f800e1e4a446e2ccf\nmsgid \":ref:`Colorspace`\"\nmsgstr \":ref:`Colorspace`\"\n\n#: ../../vars.rst:26 6a13d5103eb54565bf88415ab0ddc8c5\nmsgid \"Predefined GRAY colorspace *pymupdf.Colorspace(pymupdf.CS_GRAY)*.\"\nmsgstr \"사전 정의된 GRAY 색 공간 *pymupdf.Colorspace(pymupdf.CS_GRAY)*.\"\n\n#: ../../vars.rst:32 7321e72d393e42a3b735759e78d1800e\nmsgid \"Predefined CMYK colorspace *pymupdf.Colorspace(pymupdf.CS_CMYK)*.\"\nmsgstr \"사전 정의된 CMYK 색 공간 *pymupdf.Colorspace(pymupdf.CS_CMYK)*.\"\n\n#: ../../vars.rst:38 69ab2345dd374ad1873f76d16292717c\nmsgid \"1 -- Type of :ref:`Colorspace` is RGBA\"\nmsgstr \"1 -- :ref:`Colorspace` 유형은 RGBA\"\n\n#: ../../vars.rst:40 ../../vars.rst:46 ../../vars.rst:52 ../../vars.rst:324\n#: ../../vars.rst:330 ../../vars.rst:339 ../../vars.rst:348 ../../vars.rst:354\n#: ../../vars.rst:360 015aafcf193f4fd986c01b2543bb2157\n#: 0a5dae970bce40d4a3ef066a7b52120d 648ca70552324683a3f2d83756f7f850\n#: 9b976dcffb04497a9119e83b6b78aab2 ab0b93519cea4419af8c90b1cc9d3a36\n#: b6975d022fb6464bb4f18e4ee6bd73fa c2c115fb5ad14e8da9970160f490f151\n#: c3202da1e321403b976247fc2a19756a d3d462436758488a8dab6f328e27425e\nmsgid \"int\"\nmsgstr \"int\"\n\n#: ../../vars.rst:44 23b50446130242d885968a5027985060\nmsgid \"2 -- Type of :ref:`Colorspace` is GRAY\"\nmsgstr \"2 -- :ref:`Colorspace` 유형은 GRAY\"\n\n#: ../../vars.rst:50 9cf5e34e2e83453799d96f7be872aa7b\nmsgid \"3 -- Type of :ref:`Colorspace` is CMYK\"\nmsgstr \"3 -- :ref:`Colorspace` 유형은 CMYK\"\n\n#: ../../vars.rst:56 22d14edcfed74d6ba68f180a5162d3bc\nmsgid \"'x.xx.x' -- MuPDF version that is being used by PyMuPDF.\"\nmsgstr \"'x.xx.x' -- PyMuPDF에서 사용 중인 MuPDF 버전.\"\n\n#: ../../vars.rst:58 ../../vars.rst:70 24ffecb2a7de45fbbce9cac71b9ad2c2\n#: 4162b0bbb82145f5863294fee9b84fcb\nmsgid \"string\"\nmsgstr \"string\"\n\n#: ../../vars.rst:62 22fa0f6343d143a783918bf5d77c0101\nmsgid \"MuPDF version as a tuple of integers, `(major, minor, patch)`.\"\nmsgstr \"정수 튜플로 표현된 MuPDF 버전, `(major, minor, patch)`.\"\n\n#: ../../vars.rst:64 ../../vars.rst:76 ../../vars.rst:86\n#: 2f0bacf105574469a7a2f46854047382 ad5b78a4130443e0b9cb7a3e7209521d\n#: d8a2a6e3dcc44d9a96a1324281332fc4\nmsgid \"tuple\"\nmsgstr \"tuple\"\n\n#: ../../vars.rst:68 44158f3deff845c6a420df354f39c1ae\nmsgid \"'x.xx.x' -- PyMuPDF version.\"\nmsgstr \"'x.xx.x' -- PyMuPDF 버전.\"\n\n#: ../../vars.rst:74 503076c6013f48dea2d5aff3c0bfffe3\nmsgid \"PyMuPDF version as a tuple of integers, `(major, minor, patch)`.\"\nmsgstr \"정수 튜플로 표현된 PyMuPDF 버전, `(major, minor, patch)`.\"\n\n#: ../../vars.rst:80 ../../vars.rst:98 60b862b7a373462c8b0819e549788e84\n#: c79955e7841e4b48a637775a61cfbd69\nmsgid \"Disabled (set to None) in 1.26.1.\"\nmsgstr \"1.26.1에서 비활성화됨(None으로 설정).\"\n\n#: ../../vars.rst:84 fff27c04ee62442897c643c5bfb60fd8\nmsgid \"\"\n\"(pymupdf_version, mupdf_version, timestamp) -- combined version \"\n\"information where `timestamp` is the generation point in time formatted \"\n\"as \\\"YYYYMMDDhhmmss\\\".\"\nmsgstr \"(pymupdf_version, mupdf_version, timestamp) -- 결합된 버전 정보. `timestamp` 는 \\\"YYYYMMDDhhmmss\\\" 형식의 생성 시점입니다.\"\n\n#: ../../vars.rst:90 4fbbccb8f9024a63a332534e6a7d0d2e\nmsgid \"Legacy equivalent to `mupdf_version`.\"\nmsgstr \"`mupdf_version` 과 동일한 레거시.\"\n\n#: ../../vars.rst:94 24f0ff9e8cf44c5fba17fe9c4bd63d7f\nmsgid \"Legacy equivalent to `pymupdf_version`.\"\nmsgstr \"`pymupdf_version` 과 동일한 레거시.\"\n\n#: ../../vars.rst:104 4dce9933f18a45198a4633f8fefe9d07\nmsgid \"Document Permissions\"\nmsgstr \"문서 권한\"\n\n#: ../../vars.rst:107 ../../vars.rst:125 ../../vars.rst:138\n#: 69c0225036764f13b91eaa9dd3d4b5a1 8e2f223c79664413ba8ac6afd092c3fa\n#: a0a9b218a32347e18401eec3e71b51c6\nmsgid \"Code\"\nmsgstr \"코드\"\n\n#: ../../vars.rst:107 c680e8bb0a64489fbe38ff0350dae277\nmsgid \"Permitted Action\"\nmsgstr \"허용된 작업\"\n\n#: ../../vars.rst:109 a79221d078824de999e2f0ccf27939da\nmsgid \"PDF_PERM_PRINT\"\nmsgstr \"PDF_PERM_PRINT\"\n\n#: ../../vars.rst:109 634b2c786f6946a99a89687ae863c63d\nmsgid \"Print the document\"\nmsgstr \"문서 인쇄\"\n\n#: ../../vars.rst:110 488e117f6ad841e4b5ebe9ca302ecd70\nmsgid \"PDF_PERM_MODIFY\"\nmsgstr \"PDF_PERM_MODIFY\"\n\n#: ../../vars.rst:110 a868ac82b5084146a37a1633ab518c6c\nmsgid \"Modify the document's contents\"\nmsgstr \"문서 내용 수정\"\n\n#: ../../vars.rst:111 18ef7dd19b374b5ebfdb3cec757c73ac\nmsgid \"PDF_PERM_COPY\"\nmsgstr \"PDF_PERM_COPY\"\n\n#: ../../vars.rst:111 8f52d72b641b40d285393c8d0bdf12b3\nmsgid \"Copy or otherwise extract text and graphics\"\nmsgstr \"텍스트 및 그래픽 복사 또는 추출\"\n\n#: ../../vars.rst:112 9e025ab3d4f741e2a325152bc6f8a701\nmsgid \"PDF_PERM_ANNOTATE\"\nmsgstr \"PDF_PERM_ANNOTATE\"\n\n#: ../../vars.rst:112 cb0beab224b94270bdabfc3bd1ceacc6\nmsgid \"Add or modify text annotations and interactive form fields\"\nmsgstr \"텍스트 주석 및 대화형 양식 필드 추가 또는 수정\"\n\n#: ../../vars.rst:113 65f9a8539a38426e9d9edea861734d4d\nmsgid \"PDF_PERM_FORM\"\nmsgstr \"PDF_PERM_FORM\"\n\n#: ../../vars.rst:113 9880c191956741d1ada6315e712e1df3\nmsgid \"Fill in forms and sign the document\"\nmsgstr \"양식 작성 및 문서 서명\"\n\n#: ../../vars.rst:114 419137e25c424c91876fed826c5a5bb0\nmsgid \"PDF_PERM_ACCESSIBILITY\"\nmsgstr \"PDF_PERM_ACCESSIBILITY\"\n\n#: ../../vars.rst:114 c90f5be96ba842199ff198fe845a93a8\nmsgid \"Obsolete, always permitted\"\nmsgstr \"사용 중단됨, 항상 허용됨\"\n\n#: ../../vars.rst:115 2ac0ea137a68490a808035fe357a1eb5\nmsgid \"PDF_PERM_ASSEMBLE\"\nmsgstr \"PDF_PERM_ASSEMBLE\"\n\n#: ../../vars.rst:115 ee21ef3d77b543aa83b85d5966fa800c\nmsgid \"Insert, rotate, or delete pages, bookmarks, thumbnail images\"\nmsgstr \"페이지, 책갈피, 썸네일 이미지 삽입, 회전 또는 삭제\"\n\n#: ../../vars.rst:116 12f225fa0c204cecae58e07d185ee517\nmsgid \"PDF_PERM_PRINT_HQ\"\nmsgstr \"PDF_PERM_PRINT_HQ\"\n\n#: ../../vars.rst:116 40cb4480233843f686a1bb405c551ad8\nmsgid \"High quality printing\"\nmsgstr \"고품질 인쇄\"\n\n#: ../../vars.rst:122 c7730f8c05a4440dabe25baa7a267683\nmsgid \"PDF Optional Content Codes\"\nmsgstr \"PDF 선택적 콘텐츠 코드\"\n\n#: ../../vars.rst:125 ../../vars.rst:138 063e2ffd14154f0ebe27a414e68d96c6\n#: fe257d4a0ce0417dba5855c9020e0ca1\nmsgid \"Meaning\"\nmsgstr \"의미\"\n\n#: ../../vars.rst:127 fe2012971224466ea97a0fb2a812c5d5\nmsgid \"PDF_OC_ON\"\nmsgstr \"PDF_OC_ON\"\n\n#: ../../vars.rst:127 420c6f19787341418e8a584a6befd890\nmsgid \"Set an OCG to ON temporarily\"\nmsgstr \"OCG를 일시적으로 ON으로 설정\"\n\n#: ../../vars.rst:128 2c29aec5886a45cfae0e991402caad13\nmsgid \"PDF_OC_TOGGLE\"\nmsgstr \"PDF_OC_TOGGLE\"\n\n#: ../../vars.rst:128 a7ebc40cd09c47a3867c2d73be2fdc36\nmsgid \"Toggle OCG status temporarily\"\nmsgstr \"OCG 상태를 일시적으로 토글\"\n\n#: ../../vars.rst:129 4b06b1f6475a41cb8d448d28fbf5dd24\nmsgid \"PDF_OC_OFF\"\nmsgstr \"PDF_OC_OFF\"\n\n#: ../../vars.rst:129 8a6a1199c65a44ba85224f9de436969f\nmsgid \"Set an OCG to OFF temporarily\"\nmsgstr \"OCG를 일시적으로 OFF로 설정\"\n\n#: ../../vars.rst:135 2b7b50430a24457fafc7cd3943e62be7\nmsgid \"PDF encryption method codes\"\nmsgstr \"PDF 암호화 방법 코드\"\n\n#: ../../vars.rst:140 a3c958105b9a4e8db59f50cb6ab72b3f\nmsgid \"PDF_ENCRYPT_KEEP\"\nmsgstr \"PDF_ENCRYPT_KEEP\"\n\n#: ../../vars.rst:140 30102a9f273a4422a20bf1aa06b451e6\nmsgid \"do not change\"\nmsgstr \"변경하지 않음\"\n\n#: ../../vars.rst:141 57fd2541dc9c472e9d50b26ef7cd6daf\nmsgid \"PDF_ENCRYPT_NONE\"\nmsgstr \"PDF_ENCRYPT_NONE\"\n\n#: ../../vars.rst:141 49f9186cb5ae45cd9064cb575b6d5385\nmsgid \"remove any encryption\"\nmsgstr \"모든 암호화 제거\"\n\n#: ../../vars.rst:142 49fe127596b048f4a7ea339156fdf19d\nmsgid \"PDF_ENCRYPT_RC4_40\"\nmsgstr \"PDF_ENCRYPT_RC4_40\"\n\n#: ../../vars.rst:142 5e3374e98bdc43a199f2fd85dcc18580\nmsgid \"RC4 40 bit\"\nmsgstr \"RC4 40비트\"\n\n#: ../../vars.rst:143 178727ee434846ad808cce5a8aaad74f\nmsgid \"PDF_ENCRYPT_RC4_128\"\nmsgstr \"PDF_ENCRYPT_RC4_128\"\n\n#: ../../vars.rst:143 a3c8b50a7af8456a966bcd7de122f754\nmsgid \"RC4 128 bit\"\nmsgstr \"RC4 128비트\"\n\n#: ../../vars.rst:144 1ccff559acbb47a8a81bae717b32c4c8\nmsgid \"PDF_ENCRYPT_AES_128\"\nmsgstr \"PDF_ENCRYPT_AES_128\"\n\n#: ../../vars.rst:144 d1fdccc17e4348788f55154c73a66ddd\nmsgid \"*Advanced Encryption Standard* 128 bit\"\nmsgstr \"*고급 암호화 표준* 128비트\"\n\n#: ../../vars.rst:145 6052a9f31b7f4ec0b078312655adc0d5\nmsgid \"PDF_ENCRYPT_AES_256\"\nmsgstr \"PDF_ENCRYPT_AES_256\"\n\n#: ../../vars.rst:145 14eb7ccec2184fbbb74c67eb54aeaa93\nmsgid \"*Advanced Encryption Standard* 256 bit\"\nmsgstr \"*고급 암호화 표준* 256비트\"\n\n#: ../../vars.rst:146 0e8a697210064a68a4acb78e4798c066\nmsgid \"PDF_ENCRYPT_UNKNOWN\"\nmsgstr \"PDF_ENCRYPT_UNKNOWN\"\n\n#: ../../vars.rst:146 c4ff9f33d8bf406baac59afdedce3393\nmsgid \"unknown\"\nmsgstr \"알 수 없음\"\n\n#: ../../vars.rst:152 41ce5d42a96641298f59e62ca328c3ad\nmsgid \"Font File Extensions\"\nmsgstr \"글꼴 파일 확장자\"\n\n#: ../../vars.rst:153 a5aa4b1442b84096a3364986edc00478\nmsgid \"\"\n\"The table show file extensions you should use when saving fontfile \"\n\"buffers extracted from a PDF. This string is returned by \"\n\":meth:`Document.get_page_fonts`, :meth:`Page.get_fonts` and \"\n\":meth:`Document.extract_font`.\"\nmsgstr \"이 표는 PDF에서 추출한 글꼴 파일 버퍼를 저장할 때 사용해야 하는 파일 확장자를 보여줍니다. 이 문자열은 :meth:`Document.get_page_fonts`, :meth:`Page.get_fonts` 및 :meth:`Document.extract_font` 에 의해 반환됩니다.\"\n\n#: ../../vars.rst:156 0052347b09ef46dd84c581597bacb35f\nmsgid \"Ext\"\nmsgstr \"확장자\"\n\n#: ../../vars.rst:156 2d2cd27d463f4ff0997dae7caa6b83b6\nmsgid \"Description\"\nmsgstr \"설명\"\n\n#: ../../vars.rst:158 112b17f0de1840a08e0864ed1e9fad0c\nmsgid \"ttf\"\nmsgstr \"ttf\"\n\n#: ../../vars.rst:158 0cb8088360d7427baefcf5281b49766b\nmsgid \"TrueType font\"\nmsgstr \"TrueType 글꼴\"\n\n#: ../../vars.rst:159 c2a6b6d61d0e40d583db103da173e32f\nmsgid \"pfa\"\nmsgstr \"pfa\"\n\n#: ../../vars.rst:159 5a1d03107af64f5981ab318e0360c9af\nmsgid \"Postscript for ASCII font (various subtypes)\"\nmsgstr \"ASCII 글꼴용 Postscript (다양한 하위 유형)\"\n\n#: ../../vars.rst:160 86be9bafc4174236b68e13a9dac7e5c8\nmsgid \"cff\"\nmsgstr \"cff\"\n\n#: ../../vars.rst:160 8675d363e0c9499ab403a49e9cda22a1\nmsgid \"Type1C font (compressed font equivalent to Type1)\"\nmsgstr \"Type1C 글꼴 (Type1과 동등한 압축 글꼴)\"\n\n#: ../../vars.rst:161 4c60a1421ea7458e81092448bae7a1d8\nmsgid \"cid\"\nmsgstr \"cid\"\n\n#: ../../vars.rst:161 cf49f17f14d346f89b4ace2ba62a022f\nmsgid \"character identifier font (postscript format)\"\nmsgstr \"문자 식별자 글꼴 (postscript 형식)\"\n\n#: ../../vars.rst:162 fc39dc6369a74d13baa2932ca54039b7\nmsgid \"otf\"\nmsgstr \"otf\"\n\n#: ../../vars.rst:162 e6d68a78565e4efdbdabf3ad08977b53\nmsgid \"OpenType font\"\nmsgstr \"OpenType 글꼴\"\n\n#: ../../vars.rst:163 b7864b379d2a4c898a5538edf898a0a6\nmsgid \"n/a\"\nmsgstr \"해당 없음\"\n\n#: ../../vars.rst:163 d276c42e480048c98e84446e521418fb\nmsgid \"not extractable, e.g. :ref:`Base-14-Fonts`, Type 3 fonts and others\"\nmsgstr \"추출할 수 없음, 예: :ref:`Base-14-Fonts`, Type 3 글꼴 및 기타\"\n\n#: ../../vars.rst:169 30a554d8b43e4399ac3db70eb4861a79\nmsgid \"Text Alignment\"\nmsgstr \"텍스트 정렬\"\n\n#: ../../vars.rst:172 c285bb937c45411c9e8428e8cbc6d5ce\nmsgid \"0 -- align left.\"\nmsgstr \"0 -- 왼쪽 정렬.\"\n\n#: ../../vars.rst:176 f6c2ead9ebb844e2a50572a57dbf9a86\nmsgid \"1 -- align center.\"\nmsgstr \"1 -- 가운데 정렬.\"\n\n#: ../../vars.rst:180 8e82db4889224a20909e002199177be8\nmsgid \"2 -- align right.\"\nmsgstr \"2 -- 오른쪽 정렬.\"\n\n#: ../../vars.rst:184 75af6aadfef54289894f0d114de9eeae\nmsgid \"3 -- align justify.\"\nmsgstr \"3 -- 양쪽 정렬.\"\n\n#: ../../vars.rst:191 cf47b8894ae04d868274979275d334ee\nmsgid \"Font Properties\"\nmsgstr \"글꼴 속성\"\n\n#: ../../vars.rst:192 5c56a8ed6d794191b089c5b738da3cf9\nmsgid \"\"\n\"Please note that the following bits are derived from what a font has to \"\n\"say about its properties. It may not be (and quite often is not) correct.\"\nmsgstr \"다음 비트는 글꼴이 자신의 속성에 대해 말하는 내용에서 파생됩니다. 정확하지 않을 수 있으며(그리고 종종 그렇습니다).\"\n\n#: ../../vars.rst:196 d8f06c39601c4b96bd13ea9e078c40ce\nmsgid \"\"\n\"1 -- the character or span is a superscript. This property is computed by\"\n\" MuPDF and not part of any font information.\"\nmsgstr \"1 -- 문자 또는 스팬이 위첨자입니다. 이 속성은 MuPDF에 의해 계산되며 글꼴 정보의 일부가 아닙니다.\"\n\n#: ../../vars.rst:200 d21771d5f06e4862a5dc0a350e8a4def\nmsgid \"2 -- the font is italic.\"\nmsgstr \"2 -- 글꼴이 이탤릭체입니다.\"\n\n#: ../../vars.rst:204 c25bebd41297409da31265769924b7c0\nmsgid \"4 -- the font is serifed.\"\nmsgstr \"4 -- 글꼴이 세리프입니다.\"\n\n#: ../../vars.rst:208 b4a15a033d644c66b6b71cd52bef75b0\nmsgid \"8 -- the font is mono-spaced.\"\nmsgstr \"8 -- 글꼴이 고정폭입니다.\"\n\n#: ../../vars.rst:212 fd8f231700104de8a26b9fa17f57dca6\nmsgid \"16 -- the font is bold.\"\nmsgstr \"16 -- 글꼴이 굵게입니다.\"\n\n#: ../../vars.rst:215 ae7fc7375fe24bcab9635e7ecaf45788\nmsgid \"Text Extraction Flags\"\nmsgstr \"텍스트 추출 플래그\"\n\n#: ../../vars.rst:216 b53381821bdc40c69b532bc7e53092be\nmsgid \"\"\n\"Option bits controlling the amount of data, that are parsed into a \"\n\":ref:`TextPage`.\"\nmsgstr \":ref:`TextPage` 로 파싱되는 데이터 양을 제어하는 옵션 비트.\"\n\n#: ../../vars.rst:218 4e0693fb1e8f4c7e991b270de3d35b6c\nmsgid \"\"\n\"For the PyMuPDF programmer, some combination (using Python's `|` \"\n\"operator, or simply use `+`) of these values are aggregated in the \"\n\"``flags`` integer, a parameter of all text search and text extraction \"\n\"methods. Depending on the individual method, different default \"\n\"combinations of the values are used. Please use a value that meets your \"\n\"situation. Especially make sure to switch off image extraction unless you\"\n\" really need them. The impact on performance and memory is significant!\"\nmsgstr \"PyMuPDF 프로그래머의 경우, 이러한 값의 일부 조합(Python의 `|` 연산자를 사용하거나 단순히 `+` 사용)이 모든 텍스트 검색 및 텍스트 추출 메서드의 매개변수인 ``flags`` 정수에 집계됩니다. 개별 메서드에 따라 다른 기본 값 조합이 사용됩니다. 상황에 맞는 값을 사용하세요. 특히 실제로 필요하지 않은 경우 이미지 추출을 끄는 것이 중요합니다. 성능과 메모리에 미치는 영향이 큽니다!\"\n\n#: ../../vars.rst:222 e2a36dbf69d04d888507fc509ee2b720\nmsgid \"\"\n\"1 -- If set, ligatures are passed through to the application in their \"\n\"original form. Otherwise ligatures are expanded into their constituent \"\n\"parts, e.g. the ligature \\\"ffi\\\" is expanded into three  eparate \"\n\"characters f, f and i. Default is \\\"on\\\" in PyMuPDF. MuPDF supports the \"\n\"following 7 ligatures: \\\"ff\\\", \\\"fi\\\", \\\"fl\\\", \\\"ffi\\\", \\\"ffl\\\", , \"\n\"\\\"ft\\\", \\\"st\\\".\"\nmsgstr \"1 -- 설정되면 합자가 원래 형태로 애플리케이션에 전달됩니다. 그렇지 않으면 합자가 구성 요소로 확장됩니다. 예를 들어 합자 \\\"ffi\\\"는 세 개의 별도 문자 f, f, i로 확장됩니다. PyMuPDF의 기본값은 \\\"on\\\"입니다. MuPDF는 다음 7개의 합자를 지원합니다: \\\"ff\\\", \\\"fi\\\", \\\"fl\\\", \\\"ffi\\\", \\\"ffl\\\", \\\"ft\\\", \\\"st\\\".\"\n\n#: ../../vars.rst:226 03ceff6db720488f91e124b08d5a1e41\nmsgid \"\"\n\"2 -- If set, whitespace is passed through. Otherwise any type of \"\n\"horizontal whitespace (including horizontal tabs) will be replaced with \"\n\"space characters of variable width. Default is \\\"on\\\" in PyMuPDF.\"\nmsgstr \"2 -- 설정되면 공백이 그대로 전달됩니다. 그렇지 않으면 모든 유형의 수평 공백(수평 탭 포함)이 가변 너비의 공백 문자로 대체됩니다. PyMuPDF의 기본값은 \\\"on\\\"입니다.\"\n\n#: ../../vars.rst:230 cf99390225b04a8996e5580bd96fe830\nmsgid \"\"\n\"4 -- If set, then images will be stored in the :ref:`TextPage`. This \"\n\"causes the presence of (usually large!) binary image content in the \"\n\"output of text extractions of types \\\"blocks\\\", \\\"dict\\\", \\\"json\\\", \"\n\"\\\"rawdict\\\", \\\"rawjson\\\", \\\"html\\\", and \\\"xhtml\\\" and is the default \"\n\"there. If used with \\\"blocks\\\" however, only image metadata will be \"\n\"returned, not the image itself.\"\nmsgstr \"4 -- 설정되면 이미지가 :ref:`TextPage` 에 저장됩니다. 이것은 \\\"blocks\\\", \\\"dict\\\", \\\"json\\\", \\\"rawdict\\\", \\\"rawjson\\\", \\\"html\\\", \\\"xhtml\\\" 유형의 텍스트 추출 출력에 (보통 큰!) 바이너리 이미지 콘텐츠가 포함되게 하며, 여기서 기본값입니다. 그러나 \\\"blocks\\\"와 함께 사용하면 이미지 자체가 아닌 이미지 메타데이터만 반환됩니다.\"\n\n#: ../../vars.rst:234 2681e56367fe46aa936b2b5870294639\nmsgid \"\"\n\"8 -- If set, Mupdf will not try to add missing space characters where \"\n\"there are large gaps between characters. In PDF, the creator often does \"\n\"not insert spaces to point to the next character's position, but will \"\n\"provide the direct location address. The default in PyMuPDF is \\\"off\\\" --\"\n\" so spaces **will be generated**.\"\nmsgstr \"8 -- 설정되면 MuPDF는 문자 사이에 큰 간격이 있는 곳에 누락된 공백 문자를 추가하려고 시도하지 않습니다. PDF에서 작성자는 종종 다음 문자 위치를 가리키는 공백을 삽입하지 않고 직접 위치 주소를 제공합니다. PyMuPDF의 기본값은 \\\"off\\\"입니다 -- 따라서 공백이 **생성됩니다**.\"\n\n#: ../../vars.rst:238 cb25cbf3acb74d84824fa410aed54abd\nmsgid \"\"\n\"16 -- Ignore hyphens at line ends and join with next line. Used \"\n\"internally with the text search functions. However, it is generally \"\n\"available: if on, text extractions will return joined text lines (or \"\n\"spans) with the ending hyphen of the first line eliminated. So two \"\n\"separate spans **\\\"first meth-\\\"** and **\\\"od leads to wrong results\\\"** \"\n\"on different lines will be joined to one span **\\\"first method leads to \"\n\"wrong results\\\"** and correspondingly updated bboxes: the characters of \"\n\"the resulting span will no longer have identical y-coordinates.\"\nmsgstr \"16 -- 줄 끝의 하이픈을 무시하고 다음 줄과 결합합니다. 텍스트 검색 함수와 함께 내부적으로 사용됩니다. 그러나 일반적으로 사용 가능합니다: 켜면 텍스트 추출은 첫 번째 줄의 끝 하이픈이 제거된 결합된 텍스트 줄(또는 스팬)을 반환합니다. 따라서 다른 줄에 있는 두 개의 별도 스팬 **\\\"first meth-\\\"** 및 **\\\"od leads to wrong results\\\"** 는 하나의 스팬 **\\\"first method leads to wrong results\\\"** 로 결합되고 그에 따라 bbox가 업데이트됩니다: 결과 스팬의 문자는 더 이상 동일한 y 좌표를 가지지 않습니다.\"\n\n#: ../../vars.rst:242 19c2601d343547ba88a56aac0f0c8ff5\nmsgid \"\"\n\"32 -- Generate a new line for every span. Not used (\\\"off\\\") in PyMuPDF, \"\n\"but available for your use. Every line in \\\"dict\\\", \\\"json\\\", \"\n\"\\\"rawdict\\\", \\\"rawjson\\\" will contain exactly one span.\"\nmsgstr \"32 -- 각 스팬에 대해 새 줄을 생성합니다. PyMuPDF에서는 사용되지 않지만(\\\"off\\\") 사용할 수 있습니다. \\\"dict\\\", \\\"json\\\", \\\"rawdict\\\", \\\"rawjson\\\"의 모든 줄은 정확히 하나의 스팬을 포함합니다.\"\n\n#: ../../vars.rst:246 87e941b789f8436e998a2f3801575756\nmsgid \"\"\n\"64 -- Characters entirely outside a page's **mediabox** or contained in \"\n\"other \\\"clipped\\\" areas will be ignored. This is default in PyMuPDF.\"\nmsgstr \"64 -- 페이지의 **mediabox** 완전히 밖에 있거나 다른 \\\"클리핑된\\\" 영역에 포함된 문자는 무시됩니다. 이것은 PyMuPDF의 기본값입니다.\"\n\n#: ../../vars.rst:250 befbc341b1674e348a9396c99be1ac8a\nmsgid \"\"\n\"128 -- Use raw character codes instead of U+FFFD. This is the default for\"\n\" **text extraction** in PyMuPDF. If you **want to detect** when encoding \"\n\"information is missing or uncertain, toggle this flag and scan for the \"\n\"presence of U+FFFD (= `chr(0xfffd)`) code points in the resulting text.\"\nmsgstr \"128 -- U+FFFD 대신 원시 문자 코드를 사용합니다. 이것은 PyMuPDF에서 **텍스트 추출** 의 기본값입니다. 인코딩 정보가 누락되거나 불확실할 때 **감지하려면** 이 플래그를 토글하고 결과 텍스트에서 U+FFFD(= `chr(0xfffd)`) 코드 포인트의 존재를 스캔하세요.\"\n\n#: ../../vars.rst:254 328eded5e21c495986514848f3acd090\nmsgid \"256 -- Not supported.\"\nmsgstr \"256 -- 지원되지 않음.\"\n\n#: ../../vars.rst:258 c2468f6ee1364a9aacd5178c2e2e1f03\nmsgid \"\"\n\"512 -- Ignore metric values of all fonts when computing character \"\n\"boundary boxes -- most prominently the `ascender \"\n\"<https://en.wikipedia.org/wiki/Ascender_(typography)>`_ and `descender \"\n\"<https://en.wikipedia.org/wiki/Descender>`_ values. Instead, follow the \"\n\"drawing commands of each character's glyph and compute its rectangle \"\n\"hull. This is the smallest rectangle wrapping all points used for drawing\"\n\" the visual appearance - see the :ref:`Shape` class for understanding the\"\n\" background. This will especially result in individual character heights.\"\n\" For instance a (white) space will have a **bbox of height 0** (because \"\n\"nothing is drawn) -- in contrast to the non-zero boundary box generated \"\n\"when using font metrics. This option may be useful to cope with getting \"\n\"meaningful boundary boxes even for fonts containing errors. Its use will \"\n\"slow down text extraction somewhat because of the incurred computational \"\n\"effort.\"\nmsgstr \"\"\n\"512 -- 문자 경계 상자를 계산할 때 모든 글꼴의 메트릭 값을 무시합니다 -- 가장 \"\n\"두드러지게 `ascender \"\n\"<https://en.wikipedia.org/wiki/Ascender_(typography)>`_ 및 `descender \"\n\"<https://en.wikipedia.org/wiki/Descender>`_ 값입니다. 대신 각 문자의 글리프의 \"\n\"그리기 명령을 따르고 해당 사각형 경계를 계산합니다. 이것은 시각적 모양을 그리는 \"\n\"데 사용된 모든 점을 감싸는 가장 작은 사각형입니다 - 배경을 이해하려면 \"\n\":ref:`Shape` 클래스를 참조하세요. 이것은 특히 개별 문자 높이를 초래합니다. \"\n\"예를 들어 (흰색) 공백은 **높이가 0인 bbox** 를 가집니다(아무것도 그려지지 않기 \"\n\"때문) -- 글꼴 메트릭을 사용할 때 생성되는 0이 아닌 경계 상자와 대조됩니다. 이 \"\n\"옵션은 오류가 포함된 글꼴에 대해서도 의미 있는 경계 상자를 얻는 데 유용할 수 \"\n\"있습니다. 발생하는 계산 작업으로 인해 사용 시 텍스트 추출 속도가 다소 느려집니다.\"\n\n#: ../../vars.rst:260 0d005cfd39294c549dcb076c7db6a438\nmsgid \"\"\n\"Note that this has no effect by default - one must also disable the \"\n\"global quad corrections setting with \"\n\"`pymupdf.TOOLS.unset_quad_corrections(True)`.\"\nmsgstr \"기본적으로는 효과가 없습니다 - `pymupdf.TOOLS.unset_quad_corrections(True)` 로 전역 quad 보정 설정도 비활성화해야 합니다.\"\n\n#: ../../vars.rst:265 26addbea02e84233b6230ff416c3f839\nmsgid \"1024 -- Not supported.\"\nmsgstr \"1024 -- 지원되지 않음.\"\n\n#: ../../vars.rst:269 71ca80b7b9a0453f96fbe2509cc882f8\nmsgid \"\"\n\"2048 -- Ignore built-in differences between text appearing in e.g. PDF \"\n\"viewers versus text stored in the PDF. See :ref:`AdobeManual`, page 615 \"\n\"for background. If set, the **stored** (\\\"replacement\\\" text) is ignored \"\n\"in favor of the displayed text.\"\nmsgstr \"\"\n\"2048 -- PDF 뷰어 등에 나타나는 텍스트와 PDF에 저장된 텍스트 간의 내장된 \"\n\"차이를 무시합니다. 배경은 :ref:`AdobeManual` 615페이지를 참조하세요. 설정되면 \"\n\"**저장된** (\\\"대체\\\" 텍스트)이 무시되고 표시된 텍스트가 우선됩니다.\"\n\n#: ../../vars.rst:273 a2280aa3922d45a0b01eec12d3b1828e\nmsgid \"4096 -- Attempt to segment page into different regions.\"\nmsgstr \"4096 -- 페이지를 다른 영역으로 분할하려고 시도합니다.\"\n\n#: ../../vars.rst:275 6055e0ec2f2640a4a69c769d60051dd1\nmsgid \"\"\n\"The following constants represent the default combinations of the above \"\n\"for text extraction and searching:\"\nmsgstr \"다음 상수는 텍스트 추출 및 검색을 위한 위의 기본 조합을 나타냅니다:\"\n\n#: ../../vars.rst:279 ../../vars.rst:283 ../../vars.rst:287 ../../vars.rst:307\n#: 18445061c2274e3094f8e223b2f97d8b 4848e850ecdd4b71ae9e0fe4bd1bd2ab\n#: 7e1253a470a94b4bad14d5086ec64c03 b78142b94eed4f5ca84f11c2fef8b074\nmsgid \"\"\n\"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP \"\n\"| TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\"\nmsgstr \"\"\n\"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP \"\n\"| TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\"\n\n#: ../../vars.rst:291 ../../vars.rst:295 ../../vars.rst:299 ../../vars.rst:303\n#: 1cef0274d54745cead1031d1bca2799f 2fbf2a5e26ee49eb868428bcbb529499\n#: 9fdd1b123b4e4f2fa9c013d23a2b966c ffe8940542984cda9c70ce1c925581dc\nmsgid \"\"\n\"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP \"\n\"| TEXT_PRESERVE_IMAGES | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\"\nmsgstr \"\"\n\"`TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP \"\n\"| TEXT_PRESERVE_IMAGES | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\"\n\n#: ../../vars.rst:311 bb90ee72173049c7a370c67ba9105b23\nmsgid \"`TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_DEHYPHENATE`\"\nmsgstr \"`TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_DEHYPHENATE`\"\n\n#: ../../vars.rst:317 f588bfe5d7214e09848d2ea66fc226e0\nmsgid \"Link Destination Kinds\"\nmsgstr \"링크 대상 종류\"\n\n#: ../../vars.rst:318 25e6f87b871146ab8c9d29979584f4b3\nmsgid \"Possible values of :attr:`linkDest.kind` (link destination kind).\"\nmsgstr \":attr:`linkDest.kind` (링크 대상 종류)의 가능한 값.\"\n\n#: ../../vars.rst:322 93386ed82cc246f889866c47a3647e09\nmsgid \"0 -- No destination. Indicates a dummy link.\"\nmsgstr \"0 -- 대상 없음. 더미 링크를 나타냅니다.\"\n\n#: ../../vars.rst:328 55d8c4d1bc6e4ff7896e13f3fcbbfa74\nmsgid \"1 -- Points to a place in this document.\"\nmsgstr \"1 -- 이 문서의 위치를 가리킵니다.\"\n\n#: ../../vars.rst:334 17fd7d0b788140929657b02c096290f0\nmsgid \"\"\n\"2 -- Points to a URI -- typically a resource specified with internet \"\n\"syntax.\"\nmsgstr \"2 -- URI를 가리킵니다 -- 일반적으로 인터넷 구문으로 지정된 리소스.\"\n\n#: ../../vars.rst:336 c2c977e93a6b466686c3ec774112b806\nmsgid \"\"\n\"PyMuPDF treats any external link that contains a colon and does not start\"\n\" with `file:`, as `LINK_URI`.\"\nmsgstr \"PyMuPDF는 콜론을 포함하고 `file:` 로 시작하지 않는 모든 외부 링크를 `LINK_URI` 로 처리합니다.\"\n\n#: ../../vars.rst:343 f2f74244f1ff419e9d052ead3e767a51\nmsgid \"3 -- Launch (open) another file (of any \\\"executable\\\" type).\"\nmsgstr \"3 -- 다른 파일(모든 \\\"실행 가능한\\\" 유형)을 실행(열기)합니다.\"\n\n#: ../../vars.rst:345 80fd06d08b3a4bbd91c5550c158e44a4\nmsgid \"\"\n\"|PyMuPDF| treats any external link that starts with `file:` or doesn't \"\n\"contain a colon, as `LINK_LAUNCH`.\"\nmsgstr \"|PyMuPDF| 는 `file:` 로 시작하거나 콜론을 포함하지 않는 모든 외부 링크를 `LINK_LAUNCH` 로 처리합니다.\"\n\n#: ../../vars.rst:352 953c280a5a2c4081b49b4428360d0b70\nmsgid \"4 -- points to a named location.\"\nmsgstr \"4 -- 명명된 위치를 가리킵니다.\"\n\n#: ../../vars.rst:358 c2dd6d723df94a729c602ab39198e6e3\nmsgid \"5 -- Points to a place in another PDF document.\"\nmsgstr \"5 -- 다른 PDF 문서의 위치를 가리킵니다.\"\n\n#: ../../vars.rst:365 13d9db49dc764ad2943a0bd89bf1eccd\nmsgid \"Link Destination Flags\"\nmsgstr \"링크 대상 플래그\"\n\n#: ../../vars.rst:367 d3b19de8c19a4cca93ae0614069136aa\nmsgid \"\"\n\"The rightmost byte of this integer is a bit field, so test the truth of \"\n\"these bits with the *&* operator.\"\nmsgstr \"이 정수의 가장 오른쪽 바이트는 비트 필드이므로 *&* 연산자로 이러한 비트의 참을 테스트하세요.\"\n\n#: ../../vars.rst:371 adfb385a3f204afa96eae840376cfaaf\nmsgid \"1  (bit 0) Top left x value is valid\"\nmsgstr \"1  (비트 0) 왼쪽 상단 x 값이 유효함\"\n\n#: ../../vars.rst:373 ../../vars.rst:379 ../../vars.rst:385 ../../vars.rst:391\n#: ../../vars.rst:397 ../../vars.rst:403 ../../vars.rst:409\n#: 45d5d66079ad4119a37daf32345170ea 68ec9fd7a3194726abc3dd123922506c\n#: 802dc57d84e340dda07eb08e1fa533ea a78880c24f194e0183ba7acb53112b5c\n#: b54e07447ebd48d08adcaa6c2330efd7 cc044f3983144e34b9ec5e221c661f84\n#: de33e1ca908e4329acf8e771d8062395\nmsgid \"bool\"\nmsgstr \"bool\"\n\n#: ../../vars.rst:377 f6bb945288e84c2ea7af6535127f5686\nmsgid \"2  (bit 1) Top left y value is valid\"\nmsgstr \"2  (비트 1) 왼쪽 상단 y 값이 유효함\"\n\n#: ../../vars.rst:383 1429f391f08e4098bf3648e649655ce7\nmsgid \"4  (bit 2) Bottom right x value is valid\"\nmsgstr \"4  (비트 2) 오른쪽 하단 x 값이 유효함\"\n\n#: ../../vars.rst:389 dd2f2b2b41774030b5c2a8b95d745273\nmsgid \"8  (bit 3) Bottom right y value is valid\"\nmsgstr \"8  (비트 3) 오른쪽 하단 y 값이 유효함\"\n\n#: ../../vars.rst:395 62df816d97ee45ccab57344fe8d25a10\nmsgid \"16 (bit 4) Horizontal fit\"\nmsgstr \"16 (비트 4) 수평 맞춤\"\n\n#: ../../vars.rst:401 78e6492677c146c4a8d9bf5ea9d48be1\nmsgid \"32 (bit 5) Vertical fit\"\nmsgstr \"32 (비트 5) 수직 맞춤\"\n\n#: ../../vars.rst:407 40d05c050d174b918e1b5d3b4e8d4671\nmsgid \"64 (bit 6) Bottom right x is a zoom figure\"\nmsgstr \"64 (비트 6) 오른쪽 하단 x는 확대/축소 수치\"\n\n#: ../../vars.rst:413 136d76a8f9eb46c88e7d3a181650da73\nmsgid \"Annotation Related Constants\"\nmsgstr \"주석 관련 상수\"\n\n#: ../../vars.rst:414 0afb6c758143449fb56a0b04ab704888\nmsgid \"See chapter 8.4.5, pp. 615 of the :ref:`AdobeManual` for details.\"\nmsgstr \"자세한 내용은 :ref:`AdobeManual` 615페이지의 8.4.5장을 참조하세요.\"\n\n#: ../../vars.rst:419 c080cb77d13c409a8faecbcbd760910c\nmsgid \"Annotation Types\"\nmsgstr \"주석 유형\"\n\n#: ../../vars.rst:420 d20a798f8f554b5d8529e31b8816197f\nmsgid \"\"\n\"These identifiers also cover **links** and **widgets**: the PDF \"\n\"specification technically handles them all in the same way, whereas \"\n\"|MuPDF| (and PyMuPDF) treats them as three basically different types of \"\n\"objects.\"\nmsgstr \"이 식별자는 **링크** 및 **위젯** 도 포함합니다: PDF 사양은 기술적으로 모두 동일한 방식으로 처리하지만, |MuPDF| (및 PyMuPDF)는 이를 기본적으로 세 가지 다른 유형의 객체로 처리합니다.\"\n\n#: ../../vars.rst:457 713c32c363bd480cba99fcadd3fa3555\nmsgid \"Annotation Flag Bits\"\nmsgstr \"주석 플래그 비트\"\n\n#: ../../vars.rst:474 9fdaae6162c54afea314aa849239b470\nmsgid \"Annotation Line Ending Styles\"\nmsgstr \"주석 선 끝 스타일\"\n\n#: ../../vars.rst:490 3e407ea8c72444ebba3331d472a6a25a\nmsgid \"Widget Constants\"\nmsgstr \"위젯 상수\"\n\n#: ../../vars.rst:495 96ec99e51a7e4985a737ba02c17541ac\nmsgid \"Widget Types (*field_type*)\"\nmsgstr \"위젯 유형 (*field_type*)\"\n\n#: ../../vars.rst:508 755546e537074e1aaa1b792a365b879a\nmsgid \"Text Widget Subtypes (*text_format*)\"\nmsgstr \"텍스트 위젯 하위 유형 (*text_format*)\"\n\n#: ../../vars.rst:519 2d435f5842544cc5ad764fc27d6e30db\nmsgid \"Widget flags (*field_flags*)\"\nmsgstr \"위젯 플래그 (*field_flags*)\"\n\n#: ../../vars.rst:520 1be2e082d5f24d78b93633d42c3ab6b3\nmsgid \"**Common to all field types**::\"\nmsgstr \"**모든 필드 유형에 공통**::\"\n\n#: ../../vars.rst:526 9a70d77fe1724d00a6baf6703369f739\nmsgid \"**Text widgets**::\"\nmsgstr \"**텍스트 위젯**::\"\n\n#: ../../vars.rst:536 a70d3da20a7a4996843ce3b94a65f844\nmsgid \"**Button widgets**::\"\nmsgstr \"**버튼 위젯**::\"\n\n#: ../../vars.rst:543 33f39c42d34a4fa49140b193aec55d00\nmsgid \"**Choice widgets**::\"\nmsgstr \"**선택 위젯**::\"\n\n#: ../../vars.rst:556 05602853929445cfb71dfca4dc7fb284\nmsgid \"PDF Standard Blend Modes\"\nmsgstr \"PDF 표준 블렌드 모드\"\n\n#: ../../vars.rst:558 d1da99abe9c4449e9af156616a68a1c3\nmsgid \"For an explanation see :ref:`AdobeManual`, page 324::\"\nmsgstr \"설명은 :ref:`AdobeManual` 324페이지를 참조하세요::\"\n\n#: ../../vars.rst:581 72834b1fb7fb47c6982ed3593f7600d3\nmsgid \"Stamp Annotation Icons\"\nmsgstr \"스탬프 주석 아이콘\"\n\n#: ../../vars.rst:582 71aa56b7b0644cef8475af050d9bccf3\nmsgid \"MuPDF has defined the following icons for **rubber stamp** annotations::\"\nmsgstr \"MuPDF는 **고무 스탬프** 주석에 대해 다음 아이콘을 정의했습니다::\"\n\n#: ../../footer.rst:46 7b627849860f4ae7a235d36a44c7c566\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/version.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-02 16:19+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../version.rst:1 d1fbe6ff1d5549fb8be875f6d37c584b\nmsgid \"This documentation covers PyMuPDF |version|.\"\nmsgstr \"이 문서는 PyMuPDF |version| 을 다룹니다.\"\n\n#: ../../version.rst:3 133bf913bb004c8ca82964184ed7628c\nmsgid \"\"\n\"The major and minor versions of PyMuPDF and MuPDF will always be the \"\n\"same. Only the third qualifier (patch level) may deviate from that of \"\n\"MuPDF.\"\nmsgstr \"|PyMuPDF| 와 |MuPDF| 의 주 버전과 부 버전은 항상 동일합니다. 세 번째 한정자(패치 레벨)만 |MuPDF| 와 다를 수 있습니다.\"\n\n#: ../../version.rst:5 994720d99f72419ebd711b2cf71dcefb\nmsgid \"\"\n\"Typically PyMuPDF is released more frequently than MuPDF so it will often\"\n\" be the case that the patch level of PyMuPDF will be greater than the \"\n\"embedded MuPDF.\"\nmsgstr \"일반적으로 PyMuPDF는 MuPDF보다 더 자주 릴리스되므로, PyMuPDF의 패치 레벨이 내장된 MuPDF보다 높은 경우가 많습니다.\"\n\n#: ../../version.rst:9 371aa251e8314b9aad7c870f54636f80\nmsgid \"For example PyMuPDF-1.24.5 contains MuPDF-1.24.2.\"\nmsgstr \"예를 들어 PyMuPDF-1.24.5는 MuPDF-1.24.2를 포함합니다.\"\n\n#: ../../version.rst:11 7c7d7d87d7e14441959c236fee7d2ee5\nmsgid \"Also see `pymupdf_version` and `mupdf_version`.\"\nmsgstr \"`pymupdf_version` 및 `mupdf_version` 도 참조하세요.\"\n\n#~ msgid \"\"\n#~ \"The major and minor versions of \"\n#~ \"|PyMuPDF| and |MuPDF| will always be \"\n#~ \"the same. Only the third qualifier \"\n#~ \"(patch level) may deviate from that \"\n#~ \"of |MuPDF|.\"\n#~ msgstr \"\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/widget.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 9be7fe8ece684722b20723502ba6e81a\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 4fd0b4c61f30429d928c92ebb1081bc3\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 8395c05a667445b68d678e31a6c9296f\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../widget.rst:7 b5bf7834aa6d4acc80837502b85e97c1\nmsgid \"Widget\"\nmsgstr \"Widget (위젯)\"\n\n#: ../../widget.rst:9 db658752009445c5a3459712f6b25c8f\nmsgid \"|pdf_only_class|\"\nmsgstr \"|pdf_only_class|\"\n\n#: ../../widget.rst:11 d1312e8bf60148598975d49439011b6c\nmsgid \"\"\n\"This class represents a PDF Form field, also called a \\\"widget\\\". \"\n\"Throughout this documentation, we are using these terms synonymously. \"\n\"Fields technically are a special case of PDF annotations, which allow \"\n\"users with limited permissions to enter information in a PDF. This is \"\n\"primarily used for filling out forms.\"\nmsgstr \"이 클래스는 PDF 폼 필드(또한 \\\"위젯\\\"이라고도 함)를 나타냅니다. 이 문서 전체에서 이 용어들을 동의어로 사용합니다. 필드는 기술적으로 PDF 주석의 특수한 경우이며, 제한된 권한을 가진 사용자가 PDF에 정보를 입력할 수 있게 합니다. 이것은 주로 양식 작성에 사용됩니다.\"\n\n#: ../../widget.rst:13 6befe4905ed146a2ab8cfd92d1d923bc\nmsgid \"\"\n\"Like annotations, widgets live on PDF pages. Similar to annotations, the \"\n\"first widget on a page is accessible via :attr:`Page.first_widget` and \"\n\"subsequent widgets can be accessed via the :attr:`Widget.next` property.\"\nmsgstr \"주석과 마찬가지로 위젯은 PDF 페이지에 존재합니다. 주석과 유사하게, 페이지의 첫 번째 위젯은 :attr:`Page.first_widget` 를 통해 접근할 수 있으며, 이후 위젯은 :attr:`Widget.next` 속성을 통해 접근할 수 있습니다.\"\n\n#: ../../widget.rst:15 f5dcbec91e9446b1bc886ab894d9b27c\nmsgid \"\"\n\"Like annotations, widgets also lose connection to their page when the \"\n\"page becomes unavailable, please see `here \"\n\"<https://pymupdf.readthedocs.io/en/latest/app3.html#ensuring-consistency-\"\n\"of-important-objects-in-pymupdf>`_ for details. This is relevant \"\n\"especially when updating the widget: this will fail if the original page \"\n\"object is no longer available.\"\nmsgstr \"주석과 마찬가지로 위젯도 페이지를 사용할 수 없게 되면 페이지와의 연결을 잃습니다. 자세한 내용은 `여기 <https://pymupdf.readthedocs.io/en/latest/app3.html#ensuring-consistency-of-important-objects-in-pymupdf>`_ 를 참조하세요. 이것은 특히 위젯을 업데이트할 때 관련이 있습니다: 원본 페이지 객체를 더 이상 사용할 수 없으면 실패합니다.\"\n\n#: ../../widget.rst:17 23ea64f7e0164b6788a0c02783469bef\nmsgid \"\"\n\"*(Changed in version 1.16.0)* MuPDF no longer treats widgets as a subset \"\n\"of general annotations. Consequently, :attr:`Page.first_annot` and \"\n\":meth:`Annot.next` will deliver **non-widget annotations exclusively**, \"\n\"and be ``None`` if only form fields exist on a page. Vice versa, \"\n\":attr:`Page.first_widget` and :meth:`Widget.next` will only show widgets.\"\n\" This design decision is purely internal to MuPDF; technically, links, \"\n\"annotations and fields have a lot in common and also continue to share \"\n\"the better part of their code within (Py-) MuPDF.\"\nmsgstr \"*(버전 1.16.0에서 변경)* |MuPDF| 는 더 이상 위젯을 일반 주석의 하위 집합으로 처리하지 않습니다. 결과적으로 :attr:`Page.first_annot` 및 :meth:`Annot.next` 는 **위젯이 아닌 주석만** 제공하며, 페이지에 폼 필드만 존재하는 경우 ``None`` 이 됩니다. 반대로 :attr:`Page.first_widget` 및 :meth:`Widget.next` 는 위젯만 표시합니다. 이 설계 결정은 순전히 |MuPDF| 내부적인 것입니다. 기술적으로 링크, 주석 및 필드는 많은 공통점이 있으며 (Py-) |MuPDF| 내에서 코드의 대부분을 계속 공유합니다.\"\n\n#: ../../widget.rst:20 4c382afc381347e990494e4d0e1c78f7\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../widget.rst:26 f56bf175166444f7920a252639d09199\nmsgid \"*New in version 1.18.15*\"\nmsgstr \"*버전 1.18.15에서 새로 추가됨*\"\n\n#: ../../widget.rst:28 00cee4b5b9734e0484ff17718afb7614\nmsgid \"\"\n\"Return the names of On / Off (i.e. selected / clicked or not) states a \"\n\"button field may have. While the 'Off' state usually is also named like \"\n\"so, the 'On' state is often given a name relating to the functional \"\n\"context, for example 'Yes', 'Female', etc.\"\nmsgstr \"버튼 필드가 가질 수 있는 On/Off(즉, 선택/클릭 여부) 상태의 이름을 반환합니다. 'Off' 상태는 일반적으로 그렇게 명명되지만, 'On' 상태는 기능적 맥락과 관련된 이름(예: 'Yes', 'Female' 등)이 자주 지정됩니다.\"\n\n#: ../../widget.rst:30 7d6a3ae94e2742d5a84bf396789e24e1\nmsgid \"\"\n\"This method helps finding out the possible values of :attr:`field_value` \"\n\"in these cases.\"\nmsgstr \"이 메서드는 이러한 경우 :attr:`field_value` 의 가능한 값을 찾는 데 도움이 됩니다.\"\n\n#: ../../widget.rst 3ba59739b0504accbfb45a04c8b24a7f\n#: ac61f1c8af7547ca9e4696981cd7c001\nmsgid \"returns\"\nmsgstr \"반환값\"\n\n#: ../../widget.rst:32 dc0ef726c74e4a249337ee6f20cdd308\nmsgid \"\"\n\"a dictionary with the names of 'On' and 'Off' for the *normal* and the \"\n\"*pressed-down* appearance of button widgets. The following example shows \"\n\"that the \\\"selected\\\" value is \\\"Male\\\":\"\nmsgstr \"*normal* 및 *pressed-down* 모양의 버튼 위젯에 대한 'On' 및 'Off' 이름을 가진 딕셔너리. 다음 예제는 \\\"selected\\\" 값이 \\\"Male\\\"임을 보여줍니다:\"\n\n#: ../../widget.rst:40 dca66819e96f4f19a12d511c1409a188\nmsgid \"New in version 1.22.2\"\nmsgstr \"버전 1.22.2에서 새로 추가됨\"\n\n#: ../../widget.rst:42 72cfa1c4a4794fdebcf176d87534ed11\nmsgid \"\"\n\"Return the value of the \\\"ON\\\" state of check boxes and radio buttons. \"\n\"For check boxes this is always the value \\\"Yes\\\". For radio buttons, this\"\n\" is the value to select / activate the button.\"\nmsgstr \"체크박스 및 라디오 버튼의 \\\"ON\\\" 상태 값을 반환합니다. 체크박스의 경우 이것은 항상 \\\"Yes\\\" 값입니다. 라디오 버튼의 경우 이것은 버튼을 선택/활성화하는 값입니다.\"\n\n#: ../../widget.rst:44 ef6612006aa6463b9f062200357220e8\nmsgid \"\"\n\"the value that sets the button to \\\"selected\\\". For non-checkbox, non-\"\n\"radiobutton fields, always `None` is returned. For check boxes the return\"\n\" is `True`. For radio buttons this is the value \\\"Male\\\" in the following\"\n\" example:\"\nmsgstr \"버튼을 \\\"selected\\\"로 설정하는 값. 체크박스가 아니고 라디오 버튼이 아닌 필드의 경우 항상 `None` 이 반환됩니다. 체크박스의 경우 반환값은 `True` 입니다. 라디오 버튼의 경우 다음 예제에서 값은 \\\"Male\\\"입니다:\"\n\n#: ../../widget.rst:51 149007e65bf84de18e2eb1c2afe8bf71\nmsgid \"\"\n\"So for check boxes and radio buttons, the recommended method to set them \"\n\"to \\\"selected\\\", or to check the state is the following:\"\nmsgstr \"따라서 체크박스 및 라디오 버튼의 경우 \\\"selected\\\"로 설정하거나 상태를 확인하는 권장 방법은 다음과 같습니다:\"\n\n#: ../../widget.rst:60 9b42ee70ae144a8b92f71cf466956b05\nmsgid \"\"\n\"After any changes to a widget, this **method must be used** to reflect \"\n\"changes in the PDF [#f1]_.\"\nmsgstr \"위젯에 대한 변경 사항이 있은 후, PDF에 변경 사항을 반영하려면 이 **메서드를 사용해야 합니다** [#f1]_.\"\n\n#: ../../widget.rst f9afde507f67494fbafed9da093edc2c\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../widget.rst:62 4a0049c3506c40d99e4aba3b7c10c027\nmsgid \"\"\n\"if ``True``, the widget's :attr:`Widget.field_flags` are copied to the \"\n\"``Parent`` object (if present) and all widgets named in its ``Kids`` \"\n\"array. This provides a convenient way to -- for example -- set all \"\n\"instances of the widget to read-only, no matter on which page they may \"\n\"occur [#f2]_.\"\nmsgstr \"``True`` 인 경우 위젯의 :attr:`Widget.field_flags` 가 ``Parent`` 객체(존재하는 경우)와 ``Kids`` 배열에 명명된 모든 위젯에 복사됩니다. 이를 통해 예를 들어 위젯의 모든 인스턴스를 읽기 전용으로 설정할 수 있는 편리한 방법을 제공합니다. 어떤 페이지에 나타나든 상관없이 [#f2]_.\"\n\n#: ../../widget.rst:66 ad4e8312e49447b68aa62039c7138968\nmsgid \"\"\n\"Reset the field's value to its default -- if defined -- or remove it. Do \"\n\"not forget to issue :meth:`update` afterwards.\"\nmsgstr \"필드 값을 기본값으로 재설정합니다(정의된 경우) 또는 제거합니다. 이후 :meth:`update` 를 호출하는 것을 잊지 마세요.\"\n\n#: ../../widget.rst:70 ac472167a7e14f4290ac8a193c79160c\nmsgid \"\"\n\"Point to the next form field on the page. The last widget returns \"\n\"``None``.\"\nmsgstr \"페이지의 다음 폼 필드를 가리킵니다. 마지막 위젯은 ``None`` 을 반환합니다.\"\n\n#: ../../widget.rst:74 1f2d580b4eca4c468f4a0e6592281c85\nmsgid \"\"\n\"A list of up to 4 floats defining the field's border color. Default value\"\n\" is ``None`` which causes border style and border width to be ignored.\"\nmsgstr \"필드의 테두리 색상을 정의하는 최대 4개의 float 목록. 기본값은 ``None`` 으로, 테두리 스타일과 테두리 너비가 무시됩니다.\"\n\n#: ../../widget.rst:78 4d75daab990241b7a3b26a0e4ab3a3f3\nmsgid \"\"\n\"A string defining the line style of the field's border. See \"\n\":attr:`Annot.border`. Default is \\\"s\\\" (\\\"Solid\\\") -- a continuous line. \"\n\"Only the first character (upper or lower case) will be regarded when \"\n\"creating a widget.\"\nmsgstr \"필드 테두리의 선 스타일을 정의하는 문자열. :attr:`Annot.border` 를 참조하세요. 기본값은 \\\"s\\\"(\\\"Solid\\\") -- 연속선입니다. 위젯을 생성할 때 첫 번째 문자(대문자 또는 소문자)만 고려됩니다.\"\n\n#: ../../widget.rst:82 a3b4c3bbfb544efd99ac42ab92c5d596\nmsgid \"A float defining the width of the border line. Default is 1.\"\nmsgstr \"테두리 선의 너비를 정의하는 float. 기본값은 1입니다.\"\n\n#: ../../widget.rst:86 8abf38d7b6a540acb99b929363d614c3\nmsgid \"\"\n\"A list/tuple of integers defining the dash properties of the border line.\"\n\" This is only meaningful if *border_style == \\\"D\\\"* and \"\n\":attr:`border_color` is provided.\"\nmsgstr \"테두리 선의 대시 속성을 정의하는 정수 목록/튜플. *border_style == \\\"D\\\"* 이고 :attr:`border_color` 가 제공된 경우에만 의미가 있습니다.\"\n\n#: ../../widget.rst:90 89fa9c260a8c49f0b07ea1b251cece4e\nmsgid \"\"\n\"Python sequence of strings defining the valid choices of list boxes and \"\n\"combo boxes. For these widget types, this property is mandatory and must \"\n\"contain at least two items. Ignored for other types.\"\nmsgstr \"리스트 박스 및 콤보 박스의 유효한 선택 항목을 정의하는 문자열의 Python 시퀀스. 이러한 위젯 유형의 경우 이 속성은 필수이며 최소 두 개의 항목을 포함해야 합니다. 다른 유형에서는 무시됩니다.\"\n\n#: ../../widget.rst:94 d429d2ef1dd644d79f98b280f55ad276\nmsgid \"\"\n\"A mandatory string defining the field's name. No checking for duplicates \"\n\"takes place.\"\nmsgstr \"필드 이름을 정의하는 필수 문자열. 중복 확인은 수행되지 않습니다.\"\n\n#: ../../widget.rst:98 3e1f3a12889b40cdb2687c5e1e275082\nmsgid \"\"\n\"An optional string containing an \\\"alternate\\\" field name. Typically used\"\n\" for any notes, help on field usage, etc. Default is the field name.\"\nmsgstr \"\\\"대체\\\" 필드 이름을 포함하는 선택적 문자열. 일반적으로 필드 사용에 대한 메모, 도움말 등에 사용됩니다. 기본값은 필드 이름입니다.\"\n\n#: ../../widget.rst:102 02bb3f5a570947e98e225720d915a4b5\nmsgid \"The value of the field.\"\nmsgstr \"필드의 값.\"\n\n#: ../../widget.rst:106 159866e898664171a44d8b61241d2731\nmsgid \"\"\n\"An integer defining a large amount of properties of a field. Be careful \"\n\"when changing this attribute as this may change the field type.\"\nmsgstr \"필드의 많은 속성을 정의하는 정수. 이 속성을 변경할 때는 주의하세요. 필드 유형이 변경될 수 있습니다.\"\n\n#: ../../widget.rst:110 62966a5f68404db5822a72647d202b90\nmsgid \"\"\n\"A mandatory integer defining the field type. This is a value in the range\"\n\" of 0 to 6. It cannot be changed when updating the widget.\"\nmsgstr \"필드 유형을 정의하는 필수 정수. 이것은 0부터 6까지의 범위 값입니다. 위젯을 업데이트할 때 변경할 수 없습니다.\"\n\n#: ../../widget.rst:114 a9fbed37d8be4f51b900e87522083cb4\nmsgid \"A string describing (and derived from) the field type.\"\nmsgstr \"필드 유형을 설명하는(및 필드 유형에서 파생된) 문자열.\"\n\n#: ../../widget.rst:118 0893214230bb4b998907cfb864bf8047\nmsgid \"A list of up to 4 floats defining the field's background color.\"\nmsgstr \"필드의 배경색을 정의하는 최대 4개의 float 목록.\"\n\n#: ../../widget.rst:122 864cf589b08549bca7920c38f91caa48\nmsgid \"The caption string of a button-type field.\"\nmsgstr \"버튼 유형 필드의 캡션 문자열.\"\n\n#: ../../widget.rst:126 d1ed58b8e9784d0f9f5368aa781d8db2\nmsgid \"A bool indicating the signing status of a signature field, else ``None``.\"\nmsgstr \"서명 필드의 서명 상태를 나타내는 bool, 그렇지 않으면 ``None``.\"\n\n#: ../../widget.rst:130 fd9f9f5619ec4ae69d780dcfdcaf1cf5\nmsgid \"The rectangle containing the field.\"\nmsgstr \"필드를 포함하는 사각형.\"\n\n#: ../../widget.rst:134 32a4055906494c169f91575f408fd75e\nmsgid \"\"\n\"A list of **1, 3 or 4 floats** defining the text color. Default value is \"\n\"black (`[0, 0, 0]`).\"\nmsgstr \"텍스트 색상을 정의하는 **1, 3 또는 4개의 float** 목록. 기본값은 검은색(`[0, 0, 0]`)입니다.\"\n\n#: ../../widget.rst:138 f951f27a175047e6ad58a7ee9d45d202\nmsgid \"\"\n\"A string defining the font to be used. Default and replacement for \"\n\"invalid values is *\\\"Helv\\\"*. For valid font reference names see the \"\n\"table below.\"\nmsgstr \"사용할 글꼴을 정의하는 문자열. 기본값 및 잘못된 값의 대체값은 *\\\"Helv\\\"* 입니다. 유효한 글꼴 참조 이름은 아래 표를 참조하세요.\"\n\n#: ../../widget.rst:142 93d6bab5e8ed4964b445aaff3f5a666e\nmsgid \"\"\n\"A float defining the text :data:`fontsize`. Default value is zero, which \"\n\"causes PDF viewer software to dynamically choose a size suitable for the \"\n\"annotation's rectangle and text amount.\"\nmsgstr \"텍스트 :data:`fontsize` 를 정의하는 float. 기본값은 0이며, PDF 뷰어 소프트웨어가 주석의 사각형과 텍스트 양에 적합한 크기를 동적으로 선택하도록 합니다.\"\n\n#: ../../widget.rst:146 a1ded660efa640cd9b872d5a1fffdb1f\nmsgid \"\"\n\"An integer defining the maximum number of text characters. PDF viewers \"\n\"will (should) not accept a longer text.\"\nmsgstr \"텍스트 문자의 최대 개수를 정의하는 정수. PDF 뷰어는 더 긴 텍스트를 받아들이지 않습니다(받아들이지 않아야 합니다).\"\n\n#: ../../widget.rst:150 68eac259cd954e619832866bde7c37e3\nmsgid \"\"\n\"An integer defining acceptable text types (e.g. numeric, date, time, \"\n\"etc.). For reference only for the time being -- will be ignored when \"\n\"creating or updating widgets.\"\nmsgstr \"허용 가능한 텍스트 유형(예: 숫자, 날짜, 시간 등)을 정의하는 정수. 현재는 참고용으로만 사용되며 위젯을 생성하거나 업데이트할 때 무시됩니다.\"\n\n#: ../../widget.rst:154 9df210c84ecd4845b952f6d3cc9195cc\nmsgid \"The PDF :data:`xref` of the widget.\"\nmsgstr \"위젯의 PDF :data:`xref`.\"\n\n#: ../../widget.rst:158 ../../widget.rst:164 ../../widget.rst:170\n#: ../../widget.rst:176 ../../widget.rst:182 6ac3abf289404eeaafe2d71129cccf4f\n#: 8034826ba5bf458fa878c3dfe0dcb46e 8155dfc13cad413eb75cd134942ce80a\n#: b8eb6a539c4941e6b3212dc4474dfd75 c5b33ed64c7043db966de5404c881830\nmsgid \"New in version 1.16.12\"\nmsgstr \"버전 1.16.12에서 새로 추가됨\"\n\n#: ../../widget.rst:160 27f8421d8a374cd587fc385b05348e06\nmsgid \"\"\n\"JavaScript text (unicode) for an action associated with the widget, or \"\n\"``None``. This is the only script action supported for **button type** \"\n\"widgets.\"\nmsgstr \"위젯과 연결된 동작에 대한 JavaScript 텍스트(유니코드) 또는 ``None``. 이것은 **버튼 유형** 위젯에서 지원하는 유일한 스크립트 동작입니다.\"\n\n#: ../../widget.rst:166 bbc99abeab574327895dbdfadb016871\nmsgid \"\"\n\"JavaScript text (unicode) to be performed when the user types a key-\"\n\"stroke into a text field or combo box or modifies the selection in a \"\n\"scrollable list box. This action can check the keystroke for validity and\"\n\" reject or modify it. ``None`` if not present.\"\nmsgstr \"사용자가 텍스트 필드나 콤보 박스에 키 입력을 하거나 스크롤 가능한 리스트 박스에서 선택을 수정할 때 실행할 JavaScript 텍스트(유니코드). 이 동작은 키 입력의 유효성을 확인하고 거부하거나 수정할 수 있습니다. 존재하지 않으면 ``None``.\"\n\n#: ../../widget.rst:172 49c953662fc846e4ab3a5754771075d5\nmsgid \"\"\n\"JavaScript text (unicode) to be performed before the field is formatted \"\n\"to display its current value. This action can modify the field’s value \"\n\"before formatting. ``None`` if not present.\"\nmsgstr \"필드가 현재 값을 표시하기 위해 포맷되기 전에 실행할 JavaScript 텍스트(유니코드). 이 동작은 포맷하기 전에 필드 값을 수정할 수 있습니다. 존재하지 않으면 ``None``.\"\n\n#: ../../widget.rst:178 f099a7380085444088d138037fc88009\nmsgid \"\"\n\"JavaScript text (unicode) to be performed when the field’s value is \"\n\"changed. This action can check the new value for validity. ``None`` if \"\n\"not present.\"\nmsgstr \"필드 값이 변경될 때 실행할 JavaScript 텍스트(유니코드). 이 동작은 새 값의 유효성을 확인할 수 있습니다. 존재하지 않으면 ``None``.\"\n\n#: ../../widget.rst:184 195412bc8f7645c7af94839cbeef56c7\nmsgid \"\"\n\"JavaScript text (unicode) to be performed to recalculate the value of \"\n\"this field when that of another field changes. ``None`` if not present.\"\nmsgstr \"다른 필드의 값이 변경될 때 이 필드의 값을 다시 계산하기 위해 실행할 JavaScript 텍스트(유니코드). 존재하지 않으면 ``None``.\"\n\n#: ../../widget.rst:188 ../../widget.rst:194 be53028b2eeb496e91e645ddedbecf73\n#: caaac82450ae43fd84f1684ee16cc1aa\nmsgid \"New in version 1.22.6\"\nmsgstr \"버전 1.22.6에서 새로 추가됨\"\n\n#: ../../widget.rst:190 66757bee21264b4591997469672bf407\nmsgid \"\"\n\"JavaScript text (unicode) to be performed on losing the focus of this \"\n\"field. ``None`` if not present.\"\nmsgstr \"이 필드의 포커스를 잃을 때 실행할 JavaScript 텍스트(유니코드). 존재하지 않으면 ``None``.\"\n\n#: ../../widget.rst:196 6d86df2f110242b9b322d96488384f39\nmsgid \"\"\n\"JavaScript text (unicode) to be performed on focusing this field. \"\n\"``None`` if not present.\"\nmsgstr \"이 필드에 포커스를 맞출 때 실행할 JavaScript 텍스트(유니코드). 존재하지 않으면 ``None``.\"\n\n#: ../../widget.rst:200 31230d72253b4583a09b8159f40329f4\nmsgid \"For **adding** or **changing** one of the above scripts,\"\nmsgstr \"위의 스크립트 중 하나를 **추가** 하거나 **변경** 하려면,\"\n\n#: ../../widget.rst:201 3d2a3d82396442afb52dfc4cdd423495\nmsgid \"\"\n\"just put the appropriate JavaScript source code in the widget attribute. \"\n\"To **remove** a script, set the respective attribute to ``None``.\"\nmsgstr \"위젯 속성에 적절한 JavaScript 소스 코드를 넣으세요. 스크립트를 **제거** 하려면 해당 속성을 ``None`` 으로 설정하세요.\"\n\n#: ../../widget.rst:204 8ae6388eebe44c248ddac814e91ade75\nmsgid \"Button fields only support :attr:`script`.\"\nmsgstr \"버튼 필드는 :attr:`script` 만 지원합니다.\"\n\n#: ../../widget.rst:205 eaf4aaf730aa470bac28fa589c1d9a75\nmsgid \"Other script entries will automatically be set to ``None``.\"\nmsgstr \"다른 스크립트 항목은 자동으로 ``None`` 으로 설정됩니다.\"\n\n#: ../../widget.rst:207 1574012d10e54a92850485e41d1ffedf\nmsgid \"\"\n\"It is worthwhile to look at `this \"\n\"<https://experienceleague.adobe.com/docs/experience-manager-\"\n\"learn/assets/FormsAPIReference.pdf?lang=en>`_ manual with lots of \"\n\"information about Adobe's standard scripts for various field types. For \"\n\"example, if you want to add a text field representing a date, you may \"\n\"want to store the following scripts. They will ensure pattern-compatible \"\n\"date formats and display date pickers in supporting viewers::\"\nmsgstr \"다양한 필드 유형에 대한 Adobe의 표준 스크립트에 대한 많은 정보가 포함된 `이 매뉴얼 <https://experienceleague.adobe.com/docs/experience-manager-learn/assets/FormsAPIReference.pdf?lang=en>`_ 을 살펴보는 것이 좋습니다. 예를 들어, 날짜를 나타내는 텍스트 필드를 추가하려면 다음 스크립트를 저장할 수 있습니다. 이것들은 패턴 호환 날짜 형식을 보장하고 지원하는 뷰어에서 날짜 선택기를 표시합니다::\"\n\n#: ../../widget.rst:219 c65b215c2ad34e7488b15662ebd4d3bb\nmsgid \"Standard Fonts for Widgets\"\nmsgstr \"위젯용 표준 글꼴\"\n\n#: ../../widget.rst:220 cdad1a06914d4e0096cf6f84a03b0434\nmsgid \"\"\n\"Widgets use their own resources object ``/DR``. A widget resources object\"\n\" must at least contain a ``/Font`` object. Widget fonts are independent \"\n\"from page fonts. We currently support the 14 PDF base fonts using the \"\n\"following fixed reference names, or any name of an already existing field\"\n\" font. When specifying a text font for new or changed widgets, **either**\"\n\" choose one in the first table column (upper and lower case supported), \"\n\"**or** one of the already existing form fonts. In the latter case, \"\n\"spelling must exactly match.\"\nmsgstr \"위젯은 자체 리소스 객체 ``/DR`` 를 사용합니다. 위젯 리소스 객체는 최소한 ``/Font`` 객체를 포함해야 합니다. 위젯 글꼴은 페이지 글꼴과 독립적입니다. 현재 다음 고정 참조 이름을 사용하여 14개의 PDF 기본 글꼴을 지원하거나, 이미 존재하는 필드 글꼴의 이름을 사용합니다. 새 위젯이나 변경된 위젯에 대한 텍스트 글꼴을 지정할 때 **첫 번째 테이블 열에서 하나를 선택하거나** (대소문자 지원), **이미 존재하는 폼 글꼴 중 하나를 선택** 하세요. 후자의 경우 철자가 정확히 일치해야 합니다.\"\n\n#: ../../widget.rst:222 7fd5734a55b445cc854e109cbc203e17\nmsgid \"\"\n\"To find out already existing field fonts, inspect the list \"\n\":attr:`Document.FormFonts`.\"\nmsgstr \"이미 존재하는 필드 글꼴을 확인하려면 :attr:`Document.FormFonts` 목록을 검사하세요.\"\n\n#: ../../widget.rst:225 989af4e78c0847918dbff49079157c49\nmsgid \"**Reference**\"\nmsgstr \"**참조**\"\n\n#: ../../widget.rst:225 2a3d30a6f94b40939fd222ac5505a0c3\nmsgid \"**Base14 Fontname**\"\nmsgstr \"**Base14 글꼴 이름**\"\n\n#: ../../widget.rst:227 352a551d7b7d4200932f4f74ab639993\nmsgid \"CoBI\"\nmsgstr \"CoBI\"\n\n#: ../../widget.rst:227 97b97d88ac2049608397f18450ce94f9\nmsgid \"Courier-BoldOblique\"\nmsgstr \"Courier-BoldOblique\"\n\n#: ../../widget.rst:228 5784d31036e8451ea00333ebfc861db7\nmsgid \"CoBo\"\nmsgstr \"CoBo\"\n\n#: ../../widget.rst:228 f62fddbdd0ec4ca5a7de461de53b6f58\nmsgid \"Courier-Bold\"\nmsgstr \"Courier-Bold\"\n\n#: ../../widget.rst:229 7b2ab33a398843e2b2becf0f64045392\nmsgid \"CoIt\"\nmsgstr \"CoIt\"\n\n#: ../../widget.rst:229 053e2cadb71446e3938febe4ef984f31\nmsgid \"Courier-Oblique\"\nmsgstr \"Courier-Oblique\"\n\n#: ../../widget.rst:230 4f7d11706d4b41ec968dff1ac8fb677f\nmsgid \"Cour\"\nmsgstr \"Cour\"\n\n#: ../../widget.rst:230 bc034dde385b406280bef75f575a2672\nmsgid \"Courier\"\nmsgstr \"Courier\"\n\n#: ../../widget.rst:231 ff774f899f274ee5a81ee1e6d1959b8c\nmsgid \"HeBI\"\nmsgstr \"HeBI\"\n\n#: ../../widget.rst:231 172ee9521a2348cd9f506babd8af5f10\nmsgid \"Helvetica-BoldOblique\"\nmsgstr \"Helvetica-BoldOblique\"\n\n#: ../../widget.rst:232 79d0f51c58f54f67a759e45d17d9ffc6\nmsgid \"HeBo\"\nmsgstr \"HeBo\"\n\n#: ../../widget.rst:232 467053b50fdf4b6a970d48f6d4cc2e1a\nmsgid \"Helvetica-Bold\"\nmsgstr \"Helvetica-Bold\"\n\n#: ../../widget.rst:233 5abb199e534a4b2985760322156b7819\nmsgid \"HeIt\"\nmsgstr \"HeIt\"\n\n#: ../../widget.rst:233 8d472db0bc5a44caa9de71c566f7cb7e\nmsgid \"Helvetica-Oblique\"\nmsgstr \"Helvetica-Oblique\"\n\n#: ../../widget.rst:234 d03174f7c84045ea9ef98507a09fa344\nmsgid \"Helv\"\nmsgstr \"Helv\"\n\n#: ../../widget.rst:234 bbec46b6db884fb29167ffc50a0c7dcb\nmsgid \"Helvetica **(default)**\"\nmsgstr \"Helvetica **(기본값)**\"\n\n#: ../../widget.rst:235 cd1c089129784daeb903d5ef116ea70b\nmsgid \"Symb\"\nmsgstr \"Symb\"\n\n#: ../../widget.rst:235 81ad28b580f44ba78513b1abebbc40bc\nmsgid \"Symbol\"\nmsgstr \"Symbol\"\n\n#: ../../widget.rst:236 de4c92826dc94244b1b8ef026ab90a2e\nmsgid \"TiBI\"\nmsgstr \"TiBI\"\n\n#: ../../widget.rst:236 3dc417d13f2d4a6cbb1233643dc93f65\nmsgid \"Times-BoldItalic\"\nmsgstr \"Times-BoldItalic\"\n\n#: ../../widget.rst:237 43969ece08334ca685bd92f021cd1884\nmsgid \"TiBo\"\nmsgstr \"TiBo\"\n\n#: ../../widget.rst:237 32b0cc34477144ffb88eb7565f2a0533\nmsgid \"Times-Bold\"\nmsgstr \"Times-Bold\"\n\n#: ../../widget.rst:238 a1252968a11c4601b7341a5c9ad95394\nmsgid \"TiIt\"\nmsgstr \"TiIt\"\n\n#: ../../widget.rst:238 8cdd804d025940c8b5d05a9397419bdc\nmsgid \"Times-Italic\"\nmsgstr \"Times-Italic\"\n\n#: ../../widget.rst:239 4d07f298c6d14909b518fad20ea5e681\nmsgid \"TiRo\"\nmsgstr \"TiRo\"\n\n#: ../../widget.rst:239 b7c540028a3d4cedb72159dba9849432\nmsgid \"Times-Roman\"\nmsgstr \"Times-Roman\"\n\n#: ../../widget.rst:240 58ea0b46026f4588b999a9ca93163980\nmsgid \"ZaDb\"\nmsgstr \"ZaDb\"\n\n#: ../../widget.rst:240 2e0483edf38749a1928b25d20ab9055a\nmsgid \"ZapfDingbats\"\nmsgstr \"ZapfDingbats\"\n\n#: ../../widget.rst:243 a31f0eb06f284c738ae3404fb14e5e42\nmsgid \"\"\n\"You are generally free to use any font for every widget. However, we \"\n\"recommend using ``ZaDb`` (\\\"ZapfDingbats\\\") and :data:`fontsize` 0 for \"\n\"check boxes: typical viewers will put a correctly sized tickmark in the \"\n\"field's rectangle, when it is clicked.\"\nmsgstr \"일반적으로 모든 위젯에 대해 어떤 글꼴이든 자유롭게 사용할 수 있습니다. 그러나 체크박스의 경우 ``ZaDb`` (\\\"ZapfDingbats\\\") 및 :data:`fontsize` 0을 사용하는 것을 권장합니다: 일반적인 뷰어는 클릭할 때 필드의 사각형에 올바른 크기의 체크 표시를 넣습니다.\"\n\n#: ../../widget.rst:246 25ed10dbd2a14216bbd4ed04f57c98cd\nmsgid \"Supported Widget Types\"\nmsgstr \"지원되는 위젯 유형\"\n\n#: ../../widget.rst:247 8cb59d1d5bd14f098f5fc408b8849853\nmsgid \"\"\n\"PyMuPDF supports the creation and update of many, but not all widget \"\n\"types.\"\nmsgstr \"|PyMuPDF| 는 많은 위젯 유형의 생성 및 업데이트를 지원하지만, 모든 위젯 유형을 지원하는 것은 아닙니다.\"\n\n#: ../../widget.rst:249 8461bca05ec547fabc82884dedd125bb\nmsgid \"text (`PDF_WIDGET_TYPE_TEXT`)\"\nmsgstr \"텍스트 (`PDF_WIDGET_TYPE_TEXT`)\"\n\n#: ../../widget.rst:250 4c1a2929bc174c79bd4b539f47d803f2\nmsgid \"push button (`PDF_WIDGET_TYPE_BUTTON`)\"\nmsgstr \"푸시 버튼 (`PDF_WIDGET_TYPE_BUTTON`)\"\n\n#: ../../widget.rst:251 c8546d5d5e834b6bb9bf78579650d52d\nmsgid \"check box (`PDF_WIDGET_TYPE_CHECKBOX`)\"\nmsgstr \"체크박스 (`PDF_WIDGET_TYPE_CHECKBOX`)\"\n\n#: ../../widget.rst:252 90c82cab0fe4443ab3b6c96bde056ab8\nmsgid \"combo box (`PDF_WIDGET_TYPE_COMBOBOX`)\"\nmsgstr \"콤보 박스 (`PDF_WIDGET_TYPE_COMBOBOX`)\"\n\n#: ../../widget.rst:253 466344d91d064ed5a8d839e9b95d1988\nmsgid \"list box (`PDF_WIDGET_TYPE_LISTBOX`)\"\nmsgstr \"리스트 박스 (`PDF_WIDGET_TYPE_LISTBOX`)\"\n\n#: ../../widget.rst:254 315046b3a75448dd80a03dc3287c68fe\nmsgid \"\"\n\"radio button (`PDF_WIDGET_TYPE_RADIOBUTTON`): PyMuPDF does not currently \"\n\"support the **creation** of groups of (interconnected) radio buttons, \"\n\"where setting one button automatically unsets the other buttons in the \"\n\"group. The widget object also does not reflect the presence of a button \"\n\"group. However: consistently selecting (or unselecting) a radio button is\"\n\" supported. This includes correctly setting the value maintained in the \"\n\"owning button group. Selecting a radio button may be done by either \"\n\"assigning `True` or `field.on_state()` to the field value. **De-\"\n\"selecting** the button should be done assigning `False`.\"\nmsgstr \"라디오 버튼 (`PDF_WIDGET_TYPE_RADIOBUTTON`): |PyMuPDF| 는 현재 (상호 연결된) 라디오 버튼 그룹의 **생성** 을 지원하지 않습니다. 한 버튼을 설정하면 그룹의 다른 버튼이 자동으로 해제됩니다. 위젯 객체는 버튼 그룹의 존재를 반영하지 않습니다. 그러나: 라디오 버튼을 일관되게 선택(또는 선택 해제)하는 것은 지원됩니다. 여기에는 소유 버튼 그룹에서 유지되는 값을 올바르게 설정하는 것이 포함됩니다. 라디오 버튼을 선택하는 것은 필드 값에 `True` 또는 `field.on_state()` 를 할당하여 수행할 수 있습니다. 버튼 **선택 해제** 는 `False` 를 할당하여 수행해야 합니다.\"\n\n#: ../../widget.rst:255 b7ca95506bb743bf8bc9d51686c700fc\nmsgid \"\"\n\"signature (`PDF_WIDGET_TYPE_SIGNATURE`) **read only** -- no update or \"\n\"creation of signatures.\"\nmsgstr \"서명 (`PDF_WIDGET_TYPE_SIGNATURE`) **읽기 전용** -- 서명 업데이트 또는 생성 없음.\"\n\n#: ../../widget.rst:258 b53b3f3d840749208db6e32b83f6d04d\nmsgid \"Footnotes\"\nmsgstr \"각주\"\n\n#: ../../widget.rst:259 3eaba62dde8347e2a386454b987a2ed7\nmsgid \"\"\n\"If you intend to re-access a new or updated field (e.g. for making a \"\n\"pixmap), make sure to reload the page first. Either close and re-open the\"\n\" document, or load another page first, or simply do `page = \"\n\"doc.reload_page(page)`.\"\nmsgstr \"새 필드나 업데이트된 필드에 다시 접근하려는 경우(예: 픽스맵 생성) 먼저 페이지를 다시 로드해야 합니다. 문서를 닫고 다시 열거나, 다른 페이지를 먼저 로드하거나, 간단히 `page = doc.reload_page(page)` 를 수행하세요.\"\n\n#: ../../widget.rst:261 148f6fb2b3f74450a3f794e012c04772\nmsgid \"\"\n\"Among other purposes, ``Parent`` objects are also used to facilitate \"\n\"multiple occurrences of a field (on the same or on different pages). The \"\n\"``Kids`` array in this ``Parent`` object contains the cross references of\"\n\" all widgets that are \\\"copies\\\" of the same field. Whenever the field \"\n\"value of any \\\"kid\\\" widget is changed, all the other kids are \"\n\"immediately updated too. This is a very efficient way to handle multiple \"\n\"copies of the same field, e.g. for filling out forms. This simultaneous \"\n\"update only happens for :attr:`Widget.field value`. The new parameter \"\n\"``sync_flags`` extends this to :attr:`Widget.field_flags`. This cannot be\"\n\" automated in the same way as for the field value to allow for more \"\n\"flexibility.\"\nmsgstr \"다른 목적 중에서 ``Parent`` 객체는 필드의 여러 발생(같은 페이지 또는 다른 페이지에)을 용이하게 하는 데에도 사용됩니다. 이 ``Parent`` 객체의 ``Kids`` 배열은 동일한 필드의 \\\"복사본\\\"인 모든 위젯의 교차 참조를 포함합니다. \\\"kid\\\" 위젯의 필드 값이 변경될 때마다 다른 모든 kids도 즉시 업데이트됩니다. 이것은 같은 필드의 여러 복사본을 처리하는 매우 효율적인 방법입니다. 예를 들어 양식 작성에 사용됩니다. 이 동시 업데이트는 :attr:`Widget.field value` 에 대해서만 발생합니다. 새 매개변수 ``sync_flags`` 는 이를 :attr:`Widget.field_flags` 로 확장합니다. 더 많은 유연성을 허용하기 위해 필드 값과 동일한 방식으로 자동화할 수 없습니다.\"\n\n#: ../../footer.rst:46 00e495d1b07b4fb7afe8b0b3fc2b91b4\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/xml-class.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-12-03 09:30+0900\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.17.0\\n\"\n\n#: ../../header.rst:-1 ed98a333448b4887914630a5de49f19a\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 cda7864bd6cb46cd906155fc2d06eb89\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"|PyMuPDF| 는 |PDF| 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 b693e8da5abe4227a083012cc8103fca\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"\"\n\"|PDF| 텍스트 추출, |PDF| 이미지 추출, |PDF| 변환, |PDF| 테이블, |PDF| 분할, |PDF| 생성, \"\n\"Pyodide, PyScript\"\n\n#: ../../xml-class.rst:7 e50ebb3c4d5c4feda9d8282fdc5ffaeb\nmsgid \"Xml\"\nmsgstr \"Xml\"\n\n#: ../../xml-class.rst:11 8459b446e9bd4af5a330a44105902123\nmsgid \"New in v1.21.0\"\nmsgstr \"v1.21.0 에서 새로 추가됨\"\n\n#: ../../xml-class.rst:13 d2debef004f14adfb792ab0d1ea7ea88\nmsgid \"\"\n\"This represents an HTML or an XML node. It is a helper class intended to \"\n\"access the DOM (Document Object Model) content of a :ref:`Story` object.\"\nmsgstr \"\"\n\"이것은 HTML 또는 XML 노드를 나타냅니다. :ref:`Story` 객체의 DOM(Document Object Model) \"\n\"콘텐츠에 액세스하기 위한 헬퍼 클래스입니다.\"\n\n#: ../../xml-class.rst:15 14ab416bec2a4f7eb7f16bde88da3ce2\nmsgid \"\"\n\"There is no need to ever directly construct an :ref:`Xml` object: after \"\n\"creating a :ref:`Story`, simply take :attr:`Story.body` -- which is an \"\n\"Xml node -- and use it to navigate your way through the story's DOM.\"\nmsgstr \"\"\n\":ref:`Xml` 객체를 직접 생성할 필요는 없습니다: :ref:`Story` 를 생성한 후 단순히 \"\n\":attr:`Story.body` (Xml 노드)를 가져와 스토리의 DOM을 탐색하는 데 사용하세요.\"\n\n#: ../../xml-class.rst:19 1ff0c788ff7545fb96b56af99ee3e0a7\nmsgid \"**Method / Attribute**\"\nmsgstr \"**메서드 / 속성**\"\n\n#: ../../xml-class.rst:19 c32ff8180e3148f5ac8a1a0e4fbd44be\nmsgid \"**Description**\"\nmsgstr \"**설명**\"\n\n#: ../../xml-class.rst:21 bed67d61200b4f0aacbf74acccda80e3\nmsgid \":meth:`~.add_bullet_list`\"\nmsgstr \":meth:`~.add_bullet_list`\"\n\n#: ../../xml-class.rst:21 58a9340e599b4537a98193837f61ed21\nmsgid \"Add a :htmlTag:`ul` tag - bulleted list, context manager.\"\nmsgstr \":htmlTag:`ul` 태그 추가 - 불릿 목록, 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:22 9c06610248694be19672bc74726fe7a1\nmsgid \":meth:`~.add_codeblock`\"\nmsgstr \":meth:`~.add_codeblock`\"\n\n#: ../../xml-class.rst:22 e03fce97fc1c4485b4ed438dcfa589ea\nmsgid \"Add a :htmlTag:`pre` tag, context manager.\"\nmsgstr \":htmlTag:`pre` 태그 추가, 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:23 3343ffac757b42c0a4b4f8d2ca00aaef\nmsgid \":meth:`~.add_description_list`\"\nmsgstr \":meth:`~.add_description_list`\"\n\n#: ../../xml-class.rst:23 23c0254efb6d4087bfa74d7ca410ec92\nmsgid \"Add a :htmlTag:`dl` tag, context manager.\"\nmsgstr \":htmlTag:`dl` 태그 추가, 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:24 9119362458ae4f17a2ef89f729f32373\nmsgid \":meth:`~.add_division`\"\nmsgstr \":meth:`~.add_division`\"\n\n#: ../../xml-class.rst:24 7e04a7789665496db5078e87d6c81350\nmsgid \"add a :htmlTag:`div` tag (renamed from “section”), context manager.\"\nmsgstr \":htmlTag:`div` 태그 추가(“section”에서 이름 변경), 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:25 70fbc87b6be8435583e12d042de78491\nmsgid \":meth:`~.add_header`\"\nmsgstr \":meth:`~.add_header`\"\n\n#: ../../xml-class.rst:25 7a4857be283545b1a78b05d4a7a0467b\nmsgid \"Add a header tag (one of :htmlTag:`h1` to :htmlTag:`h6`), context manager.\"\nmsgstr \"헤더 태그 추가(:htmlTag:`h1` ~ :htmlTag:`h6` 중 하나), 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:26 6d66e3e04e534e5581b83b86bfb1a802\nmsgid \":meth:`~.add_horizontal_line`\"\nmsgstr \":meth:`~.add_horizontal_line`\"\n\n#: ../../xml-class.rst:26 23f5482c4a9c4b7d875751cb669e52fd\nmsgid \"Add a :htmlTag:`hr` tag.\"\nmsgstr \":htmlTag:`hr` 태그 추가.\"\n\n#: ../../xml-class.rst:27 e52a5dae28dd4513b88d05c0a4397237\nmsgid \":meth:`~.add_image`\"\nmsgstr \":meth:`~.add_image`\"\n\n#: ../../xml-class.rst:27 7dd038f55d0941249c97a617a6075c4f\nmsgid \"Add a :htmlTag:`img` tag.\"\nmsgstr \":htmlTag:`img` 태그 추가.\"\n\n#: ../../xml-class.rst:28 12026fdfd30347fb90a89a426dfa6843\nmsgid \":meth:`~.add_link`\"\nmsgstr \":meth:`~.add_link`\"\n\n#: ../../xml-class.rst:28 c0d7d501bcfa4bf19e55d60774ed8346\nmsgid \"Add a :htmlTag:`a` tag.\"\nmsgstr \":htmlTag:`a` 태그 추가.\"\n\n#: ../../xml-class.rst:29 0c874d7eb4a24776b75476759d792ac3\nmsgid \":meth:`~.add_number_list`\"\nmsgstr \":meth:`~.add_number_list`\"\n\n#: ../../xml-class.rst:29 8f48fb94a00a4274aa70418af5a315d8\nmsgid \"Add a :htmlTag:`ol` tag, context manager.\"\nmsgstr \":htmlTag:`ol` 태그 추가, 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:30 0d7d7fd6a8f442e3b330d2ed8e2d3ae1\nmsgid \":meth:`~.add_paragraph`\"\nmsgstr \":meth:`~.add_paragraph`\"\n\n#: ../../xml-class.rst:30 e494547a61e44f3d9ea45f067f3de220\nmsgid \"Add a :htmlTag:`p` tag.\"\nmsgstr \":htmlTag:`p` 태그 추가.\"\n\n#: ../../xml-class.rst:31 ec19e6cf23634df79dde0434e20e634a\nmsgid \":meth:`~.add_span`\"\nmsgstr \":meth:`~.add_span`\"\n\n#: ../../xml-class.rst:31 5d96649419b84f9d9df8c0181ca44fb7\nmsgid \"Add a :htmlTag:`span` tag, context manager.\"\nmsgstr \":htmlTag:`span` 태그 추가, 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:32 9c5bbdc52ebf49b79197d08b06938f09\nmsgid \":meth:`~.add_subscript`\"\nmsgstr \":meth:`~.add_subscript`\"\n\n#: ../../xml-class.rst:32 8c9a0c7d7e4d451fa071ed2e4743cc20\nmsgid \"\"\n\"Add subscript text(:htmlTag:`sub` tag) - inline element, treated like \"\n\"text.\"\nmsgstr \"아래첨자 텍스트 추가(:htmlTag:`sub` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:33 56eea7a8c34c4e85bf3e08779e96b5ea\nmsgid \":meth:`~.add_superscript`\"\nmsgstr \":meth:`~.add_superscript`\"\n\n#: ../../xml-class.rst:33 ab759e84a2c3405eb25d36a03dd85997\nmsgid \"\"\n\"Add subscript text (:htmlTag:`sup` tag) - inline element, treated like \"\n\"text.\"\nmsgstr \"위첨자 텍스트 추가(:htmlTag:`sup` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:34 6b9f3b0a71c84eeb8e13ba521a67288c\nmsgid \":meth:`~.add_code`\"\nmsgstr \":meth:`~.add_code`\"\n\n#: ../../xml-class.rst:34 ../../xml-class.rst:35 ../../xml-class.rst:36\n#: ../../xml-class.rst:37 5bcb0d50e2bb46b2a6f792e3f82f23c0\n#: 6286fc4f2bf34d939839ab3897974dac 663faea7bc304553a7c5bd23ae2ca42a\n#: 9d4732e3cf3447dbab81a3764aa04b3d\nmsgid \"Add code text (:htmlTag:`code` tag) - inline element, treated like text.\"\nmsgstr \"코드 텍스트 추가(:htmlTag:`code` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:35 36bddbf021b2409fb2aa99cf1356df2b\nmsgid \":meth:`~.add_var`\"\nmsgstr \":meth:`~.add_var`\"\n\n#: ../../xml-class.rst:36 05699304cc954f389932529cb4bc06b3\nmsgid \":meth:`~.add_samp`\"\nmsgstr \":meth:`~.add_samp`\"\n\n#: ../../xml-class.rst:37 119929ceb54c4bd0922ef4710c88b67a\nmsgid \":meth:`~.add_kbd`\"\nmsgstr \":meth:`~.add_kbd`\"\n\n#: ../../xml-class.rst:38 fa67c459b1a94b2bb9d528bb4d279866\nmsgid \":meth:`~.add_text`\"\nmsgstr \":meth:`~.add_text`\"\n\n#: ../../xml-class.rst:38 ../../xml-class.rst:162\n#: 69ad3795bdff49a6a4c840098fbd1c8b c0627134be5440cd804e621517945927\nmsgid \"Add a text string. Line breaks ``\\\\n`` are honored as :htmlTag:`br` tags.\"\nmsgstr \"텍스트 문자열 추가. 줄바꿈 ``\\\\n`` 은 :htmlTag:`br` 태그로 처리됩니다.\"\n\n#: ../../xml-class.rst:39 a98056baf3e04d2cb661f2078c05704a\nmsgid \":meth:`~.append_child`\"\nmsgstr \":meth:`~.append_child`\"\n\n#: ../../xml-class.rst:39 18c4dca5a6574be987d4c4161650ca4b\nmsgid \"Append a child node.\"\nmsgstr \"자식 노드를 추가합니다.\"\n\n#: ../../xml-class.rst:40 4809359e7dbf47d0a5f5134d701b689a\nmsgid \":meth:`~.clone`\"\nmsgstr \":meth:`~.clone`\"\n\n#: ../../xml-class.rst:40 d333be626baf48a8ac39807b83cdd8be\nmsgid \"Make a copy if this node.\"\nmsgstr \"이 노드의 복사본을 만듭니다.\"\n\n#: ../../xml-class.rst:41 9a1130d2be3142909ea7c0912166a0f2\nmsgid \":meth:`~.create_element`\"\nmsgstr \":meth:`~.create_element`\"\n\n#: ../../xml-class.rst:41 1a46a86ef6e84eceb1c268058f46cd85\nmsgid \"Make a new node with a given tag name.\"\nmsgstr \"주어진 태그 이름으로 새 노드를 만듭니다.\"\n\n#: ../../xml-class.rst:42 db997b2687de482b83f5bc357fc4b215\nmsgid \":meth:`~.create_text_node`\"\nmsgstr \":meth:`~.create_text_node`\"\n\n#: ../../xml-class.rst:42 ../../xml-class.rst:306\n#: 0c24293c6f454cf8ac5e9e378e6d49df ab5a32784a7244a0b2c1a1bbdd20c908\nmsgid \"Create direct text for the current node.\"\nmsgstr \"현재 노드에 대한 직접 텍스트를 생성합니다.\"\n\n#: ../../xml-class.rst:43 b53e49d497e340ba8d87d21bca63ee08\nmsgid \":meth:`~.find`\"\nmsgstr \":meth:`~.find`\"\n\n#: ../../xml-class.rst:43 54e83a9f44b545e9bfe1a2b06258a179\nmsgid \"Find a sub-node with given properties.\"\nmsgstr \"주어진 속성을 가진 하위 노드를 찾습니다.\"\n\n#: ../../xml-class.rst:44 279258dff67b40a986c18f707623ce7b\nmsgid \":meth:`~.find_next`\"\nmsgstr \":meth:`~.find_next`\"\n\n#: ../../xml-class.rst:44 54393fb756ce48a1935a45fa6c483fd9\nmsgid \"Repeat previous \\\"find\\\" with the same criteria.\"\nmsgstr \"동일한 기준으로 이전 \\\"find\\\" 를 반복합니다.\"\n\n#: ../../xml-class.rst:45 536488e527e642478653b6c87079f25d\nmsgid \":meth:`~.insert_after`\"\nmsgstr \":meth:`~.insert_after`\"\n\n#: ../../xml-class.rst:45 3c35e0b8245c4d3894e3e33f8c437b0c\nmsgid \"Insert an element after current node.\"\nmsgstr \"현재 노드 뒤에 요소를 삽입합니다.\"\n\n#: ../../xml-class.rst:46 f8abe4048c244c3dbdc13b3c4e5ad69a\nmsgid \":meth:`~.insert_before`\"\nmsgstr \":meth:`~.insert_before`\"\n\n#: ../../xml-class.rst:46 297894701e8b45be843568131def067b\nmsgid \"Insert an element before current node.\"\nmsgstr \"현재 노드 앞에 요소를 삽입합니다.\"\n\n#: ../../xml-class.rst:47 8dfc91e812d545cc915f8fe33c6b5fbf\nmsgid \":meth:`~.remove`\"\nmsgstr \":meth:`~.remove`\"\n\n#: ../../xml-class.rst:47 5d36ebaefdd54b1982ac6726613e2112\nmsgid \"Remove this node.\"\nmsgstr \"이 노드를 제거합니다.\"\n\n#: ../../xml-class.rst:48 96abe1793f174eec994fb30aab4effea\nmsgid \":meth:`~.set_align`\"\nmsgstr \":meth:`~.set_align`\"\n\n#: ../../xml-class.rst:48 a55a6f5e66e2493cbd7dbc5b956f1a3e\nmsgid \"Set the alignment using a CSS style spec. Only works for block-level tags.\"\nmsgstr \"CSS 스타일 사양을 사용하여 정렬을 설정합니다. 블록 레벨 태그에만 작동합니다.\"\n\n#: ../../xml-class.rst:49 ea21515c71e24b0188b60a1a70913497\nmsgid \":meth:`~.set_attribute`\"\nmsgstr \":meth:`~.set_attribute`\"\n\n#: ../../xml-class.rst:49 ../../xml-class.rst:172\n#: c52ac8e27b044dd68190bd1c067c3c3e cb302d2f3079458ca8d3ceb266e47cbd\nmsgid \"Set an arbitrary key to some value (which may be empty).\"\nmsgstr \"임의의 키를 일부 값(비어 있을 수 있음)으로 설정합니다.\"\n\n#: ../../xml-class.rst:50 03813ecb5505495185805991093ca9d3\nmsgid \":meth:`~.set_bgcolor`\"\nmsgstr \":meth:`~.set_bgcolor`\"\n\n#: ../../xml-class.rst:50 ../../xml-class.rst:199\n#: 7b89b00dcad741248713dda7ba5d06d0 994f5e2b0df34266bde8fc8388e3045e\nmsgid \"Set the background color. Only works for block-level tags.\"\nmsgstr \"배경색을 설정합니다. 블록 레벨 태그에만 작동합니다.\"\n\n#: ../../xml-class.rst:51 7352b4b42f8a4f8392bc82e0c98aba56\nmsgid \":meth:`~.set_bold`\"\nmsgstr \":meth:`~.set_bold`\"\n\n#: ../../xml-class.rst:51 ../../xml-class.rst:205\n#: 756c1471bfe7439482da584fb5e10c44 8ba71a63948e473599b07b28a86a490c\nmsgid \"Set bold on or off or to some string value.\"\nmsgstr \"굵게를 켜거나 끄거나 일부 문자열 값으로 설정합니다.\"\n\n#: ../../xml-class.rst:52 11e420e055184eb8b13706473ad5a325\nmsgid \":meth:`~.set_color`\"\nmsgstr \":meth:`~.set_color`\"\n\n#: ../../xml-class.rst:52 43619286063e475b9ca8e799b0ed6b26\nmsgid \"Set text color.\"\nmsgstr \"텍스트 색상을 설정합니다.\"\n\n#: ../../xml-class.rst:53 cf8a517ba10a451d9578a9c6a0f414b6\nmsgid \":meth:`~.set_columns`\"\nmsgstr \":meth:`~.set_columns`\"\n\n#: ../../xml-class.rst:53 f418d11d24d44223a434608e1ae690f8\nmsgid \"Set the number of columns. Argument may be any valid number or string.\"\nmsgstr \"열 수를 설정합니다. 인수는 유효한 숫자 또는 문자열일 수 있습니다.\"\n\n#: ../../xml-class.rst:54 4c848bf493914ddcbfd8d32d1526f510\nmsgid \":meth:`~.set_font`\"\nmsgstr \":meth:`~.set_font`\"\n\n#: ../../xml-class.rst:54 362b271a59604e4f957f8702d7ef2b53\nmsgid \"Set the font-family, e.g. “sans-serif”.\"\nmsgstr \"글꼴 패밀리를 설정합니다. 예: “sans-serif”.\"\n\n#: ../../xml-class.rst:55 ff571b94a01a477fba4693ef0a1b492f\nmsgid \":meth:`~.set_fontsize`\"\nmsgstr \":meth:`~.set_fontsize`\"\n\n#: ../../xml-class.rst:55 e94b2ea525e24124a168317cd6071fdc\nmsgid \"Set the font size. Either a float or a valid HTML/CSS string.\"\nmsgstr \"글꼴 크기를 설정합니다. float 또는 유효한 HTML/CSS 문자열입니다.\"\n\n#: ../../xml-class.rst:56 1feb11c650204bb0bfece8527099e866\nmsgid \":meth:`~.set_id`\"\nmsgstr \":meth:`~.set_id`\"\n\n#: ../../xml-class.rst:56 4b5b5816aa62459e9d8baab00f0edc99\nmsgid \"Set a :htmlTag:`id`. A check for uniqueness is performed.\"\nmsgstr \":htmlTag:`id` 를 설정합니다. 고유성 검사가 수행됩니다.\"\n\n#: ../../xml-class.rst:57 ce34ec1e82914fb1b1b90bb31d40470d\nmsgid \":meth:`~.set_italic`\"\nmsgstr \":meth:`~.set_italic`\"\n\n#: ../../xml-class.rst:57 4e45de6be07840af90c12e676fd9c5ae\nmsgid \"Set italic on or off or to some string value.\"\nmsgstr \"기울임꼴을 켜거나 끄거나 일부 문자열 값으로 설정합니다.\"\n\n#: ../../xml-class.rst:58 11c92dcf021e4d5cbb52560db075d9fe\nmsgid \":meth:`~.set_leading`\"\nmsgstr \":meth:`~.set_leading`\"\n\n#: ../../xml-class.rst:58 ../../xml-class.rst:249\n#: 0313848222a04025b98a78e2faf28cf8 269609b91bb44ac7880bff03d7847f2a\nmsgid \"\"\n\"Set inter-block text distance (`-mupdf-leading`), only works on block-\"\n\"level nodes.\"\nmsgstr \"블록 간 텍스트 거리(`-mupdf-leading`)를 설정합니다. 블록 레벨 노드에만 작동합니다.\"\n\n#: ../../xml-class.rst:59 15f03bc6829c4d129ca26b81e84a6eb6\nmsgid \":meth:`~.set_lineheight`\"\nmsgstr \":meth:`~.set_lineheight`\"\n\n#: ../../xml-class.rst:59 01673ca076f64027883cfb4fe9c97046\nmsgid \"Set height of a line. Float like 1.5, which sets to `1.5 * fontsize`.\"\nmsgstr \"줄 높이를 설정합니다. 1.5와 같은 float는 `1.5 * fontsize` 로 설정됩니다.\"\n\n#: ../../xml-class.rst:60 41bdd81afe8e46d1a7038efdc95fb1f4\nmsgid \":meth:`~.set_margins`\"\nmsgstr \":meth:`~.set_margins`\"\n\n#: ../../xml-class.rst:60 ffba6357a0f54dfa979916919ace72b6\nmsgid \"Set the margin(s), float or string with up to 4 values.\"\nmsgstr \"여백을 설정합니다. 최대 4개의 값을 가진 float 또는 문자열입니다.\"\n\n#: ../../xml-class.rst:61 19d802eea7664074a119a0ca9611d63a\nmsgid \":meth:`~.set_pagebreak_after`\"\nmsgstr \":meth:`~.set_pagebreak_after`\"\n\n#: ../../xml-class.rst:61 ../../xml-class.rst:267\n#: 635579fb8b334ef496c13d09aa9b2a24 bbb7b82028684c03935a74cc78c43f79\nmsgid \"Insert a page break after this node.\"\nmsgstr \"이 노드 뒤에 페이지 나누기를 삽입합니다.\"\n\n#: ../../xml-class.rst:62 d9f038d12f844c37bba8348d97d4c4a4\nmsgid \":meth:`~.set_pagebreak_before`\"\nmsgstr \":meth:`~.set_pagebreak_before`\"\n\n#: ../../xml-class.rst:62 ../../xml-class.rst:271\n#: 5c16b15d44844c4dacb4a296d0ebf537 83dfe30bd4c54eeaa4fc51696b2e4189\nmsgid \"Insert a page break before this node.\"\nmsgstr \"이 노드 앞에 페이지 나누기를 삽입합니다.\"\n\n#: ../../xml-class.rst:63 4986e5fa09f34f80a02ffebc470181cb\nmsgid \":meth:`~.set_properties`\"\nmsgstr \":meth:`~.set_properties`\"\n\n#: ../../xml-class.rst:63 8aa5fb55e133414bb1a07fa48f8c495a\nmsgid \"Set any or all desired properties in one call.\"\nmsgstr \"한 번의 호출로 원하는 모든 속성을 설정합니다.\"\n\n#: ../../xml-class.rst:64 8bd74a9264e847218ff74d28819f9b3a\nmsgid \":meth:`~.add_style`\"\nmsgstr \":meth:`~.add_style`\"\n\n#: ../../xml-class.rst:64 696084f4662f4afa8f1d2f9fe9803858\nmsgid \"Set (add) a “style” that is not supported by its own `set_` method.\"\nmsgstr \"자체 `set_` 메서드로 지원되지 않는 “style” 을 설정(추가)합니다.\"\n\n#: ../../xml-class.rst:65 6783ab89d34e4bb1beacc5d2ebee9ba1\nmsgid \":meth:`~.add_class`\"\nmsgstr \":meth:`~.add_class`\"\n\n#: ../../xml-class.rst:65 26d405ede2ea47bf85cdce1edf045fe7\nmsgid \"Set (add) a “class” attribute.\"\nmsgstr \"“class” 속성을 설정(추가)합니다.\"\n\n#: ../../xml-class.rst:66 0de080acfdf143efbf77e424fd977b61\nmsgid \":meth:`~.set_text_indent`\"\nmsgstr \":meth:`~.set_text_indent`\"\n\n#: ../../xml-class.rst:66 a7815d341b0d4bec895b0cc65db7a8a9\nmsgid \"\"\n\"Set indentation for first textblock line. Only works for block-level \"\n\"nodes.\"\nmsgstr \"첫 번째 텍스트 블록 줄의 들여쓰기를 설정합니다. 블록 레벨 노드에만 작동합니다.\"\n\n#: ../../xml-class.rst:67 73ba9526545c47ae8c78f869547404a1\nmsgid \":attr:`~.tagname`\"\nmsgstr \":attr:`~.tagname`\"\n\n#: ../../xml-class.rst:67 ../../xml-class.rst:370\n#: 48584833c9fe4ca985f37c45ad2c3d76 d9381cddd5514b6fadcac87352ef53c1\nmsgid \"Either the HTML tag name like :htmlTag:`p` or `None` if a text node.\"\nmsgstr \":htmlTag:`p` 와 같은 HTML 태그 이름이거나 텍스트 노드인 경우 `None` 입니다.\"\n\n#: ../../xml-class.rst:68 6abc57bcb9f4408d90fa105b05243e71\nmsgid \":attr:`~.text`\"\nmsgstr \":attr:`~.text`\"\n\n#: ../../xml-class.rst:68 ../../xml-class.rst:374\n#: 4cf7d8eb06994aaf8da0a99630a2b88f dd52e4753283435ab62a4e5cf08c3c67\nmsgid \"Either the node's text or `None` if a tag node.\"\nmsgstr \"노드의 텍스트이거나 태그 노드인 경우 `None` 입니다.\"\n\n#: ../../xml-class.rst:69 c80ecae6e2374362bda69ab5f6f83bb5\nmsgid \":attr:`~.is_text`\"\nmsgstr \":attr:`~.is_text`\"\n\n#: ../../xml-class.rst:69 7058d637f998456c9acd2330b63e694d\nmsgid \"Check if the node is a text.\"\nmsgstr \"노드가 텍스트인지 확인합니다.\"\n\n#: ../../xml-class.rst:70 1866cee8d0c84959a92ba46715af839b\nmsgid \":attr:`~.first_child`\"\nmsgstr \":attr:`~.first_child`\"\n\n#: ../../xml-class.rst:70 ../../xml-class.rst:382\n#: 238d1286994b4be289304b0355f413cf 6fcf64063e504c83874560e24334da81\nmsgid \"Contains the first node one level below this one (or `None`).\"\nmsgstr \"이 노드보다 한 단계 아래의 첫 번째 노드를 포함합니다(또는 `None`).\"\n\n#: ../../xml-class.rst:71 851a9238caa94b969efa1adb031498b6\nmsgid \":attr:`~.last_child`\"\nmsgstr \":attr:`~.last_child`\"\n\n#: ../../xml-class.rst:71 ../../xml-class.rst:386\n#: 0048d0bc3d6642349608efc96461213e 7f4b0ba5d00f4ce2baef3b1f449e84bc\nmsgid \"Contains the last node one level below this one (or `None`).\"\nmsgstr \"이 노드보다 한 단계 아래의 마지막 노드를 포함합니다(또는 `None`).\"\n\n#: ../../xml-class.rst:72 e31062e64395499283472e5f0cce8591\nmsgid \":attr:`~.next`\"\nmsgstr \":attr:`~.next`\"\n\n#: ../../xml-class.rst:72 ../../xml-class.rst:390\n#: 74da4c4190d2452ea26e9a031c65d9c0 76197938be5e4a7cb15873e3587d6473\nmsgid \"The next node at the same level (or `None`).\"\nmsgstr \"같은 레벨의 다음 노드(또는 `None`).\"\n\n#: ../../xml-class.rst:73 00b770d5e9494151944f8ca72875704f\nmsgid \":attr:`~.previous`\"\nmsgstr \":attr:`~.previous`\"\n\n#: ../../xml-class.rst:73 ../../xml-class.rst:394\n#: de9653bc4d6d46fdb546a8b1020ade72 f0b4ecf139a546ab893551141166f15b\nmsgid \"The previous node at the same level.\"\nmsgstr \"같은 레벨의 이전 노드.\"\n\n#: ../../xml-class.rst:74 324f133ed2e54ac28e45a08cd4deb6ee\nmsgid \":attr:`~.root`\"\nmsgstr \":attr:`~.root`\"\n\n#: ../../xml-class.rst:74 ../../xml-class.rst:398\n#: 5ee16878f554413ab4a0ef55e762dd20 b84698fd03b74ab2a6bf011ec67a7c31\nmsgid \"The top node of the DOM, which hence has the tagname :htmlTag:`html`.\"\nmsgstr \"DOM의 최상위 노드로, 따라서 태그 이름이 :htmlTag:`html` 입니다.\"\n\n#: ../../xml-class.rst:79 9cc8e3fdf4f345fabd4b30db4fa7b2df\nmsgid \"**Class API**\"\nmsgstr \"**클래스 API**\"\n\n#: ../../xml-class.rst:85 2e41fcde489d4a928300d15f33e3e110\nmsgid \"\"\n\"Add an :htmlTag:`ul` tag - bulleted list, context manager. See `ul \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul>`_.\"\nmsgstr \"\"\n\":htmlTag:`ul` 태그 추가 - 불릿 목록, 컨텍스트 매니저. `ul <https://developer.mozilla.org\"\n\"/en-US/docs/Web/HTML/Element/ul>`_ 를 참조하세요.\"\n\n#: ../../xml-class.rst:89 8cbdd27873fd4c138f660770ffd885c0\nmsgid \"\"\n\"Add a :htmlTag:`pre` tag, context manager. See `pre \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre>`_.\"\nmsgstr \"\"\n\":htmlTag:`pre` 태그 추가, 컨텍스트 매니저. `pre <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/pre>`_ 를 참조하세요.\"\n\n#: ../../xml-class.rst:93 4c52e991f2d1486fb520ada7b65ecf60\nmsgid \"\"\n\"Add a :htmlTag:`dl` tag, context manager. See `dl \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl>`_.\"\nmsgstr \"\"\n\":htmlTag:`dl` 태그 추가, 컨텍스트 매니저. `dl <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/dl>`_ 를 참조하세요.\"\n\n#: ../../xml-class.rst:97 97dd62a837dc41eaa3e350af10039f9e\nmsgid \"\"\n\"Add a :htmlTag:`div` tag, context manager. See `div \"\n\"<https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div>`_.\"\nmsgstr \"\"\n\":htmlTag:`div` 태그 추가, 컨텍스트 매니저. `div <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/div>`_ 를 참조하세요.\"\n\n#: ../../xml-class.rst:101 75c8952433194970b978abc00b3b97b8\nmsgid \"\"\n\"Add a header tag (one of :htmlTag:`h1` to :htmlTag:`h6`), context \"\n\"manager. See `headings <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/Heading_Elements>`_.\"\nmsgstr \"\"\n\"헤더 태그 추가(:htmlTag:`h1` ~ :htmlTag:`h6` 중 하나), 컨텍스트 매니저. `headings \"\n\"<https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/Heading_Elements>`_ 를 참조하세요.\"\n\n#: ../../xml-class.rst 071ee6894c3048e98dcde2ce36b62fe0\n#: 07f4e7a4d07742a09eb64bac4f8e7f47 18d5dca41f9148d989d31b098cc7068b\n#: 2513b123c6ad435aaf40448eb9661ffd 2552e11c47ee4b3083c32e3e42fd2227\n#: 2b9417956fe4424d9bdc4167f4fe27f0 4b45aea1b75e4f5a8493bb97947f7670\n#: 5a7226878eaf4bf4a8d146aefd9fc6c2 6c8408dac31f401ca4b20970c770d909\n#: 6ecf5c2861b5443e8422f34c3df4c6d4 7175254a32ea4b3a969c0812d221bcc0\n#: 8160ce73204e4f67a9c2729a2ae2fe0a 8430e36693a446708867badbfd49b16f\n#: 8db3cbff4c56472d9086e987c0ff90d5 8f2186fb783d4c99b915b40831a80551\n#: 9fee7d00425e495a9ea52cdcdb1105df a0e8644184de4688befedd1b1f6b1f48\n#: a936bac1d8f84238927172f0c1b1a9f9 ac6183c17f40424fbf98f29ac05b6d7c\n#: ad072640a531401a90210d2c5ddcb035 bcc06f6598a5432cbef93a7b8e8f51ab\n#: bd8f12e471e54f19a3231352d44d77e8 d643adfc3ba14ca9a6eb51fd2e03a7bd\n#: ec41031277d64f758e22602fd6090f70 f0477f34f1c24a31976ab44e62cf544b\n#: f58492282617408fbf640c0870739c87 fc36c0decdf847d59b50e8f8db732c05\nmsgid \"Parameters\"\nmsgstr \"매개변수\"\n\n#: ../../xml-class.rst:103 512df5124cdc4ee9b171d85403bf5626\nmsgid \"a value 1 - 6.\"\nmsgstr \"1 - 6 사이의 값.\"\n\n#: ../../xml-class.rst:107 1d8612c571cf4a7b9374d9ace7b2f9db\nmsgid \"\"\n\"Add a :htmlTag:`hr` tag. See `hr <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/hr>`_.\"\nmsgstr \"\"\n\":htmlTag:`hr` 태그 추가. `hr <https://developer.mozilla.org/en-\"\n\"US/docs/Web/HTML/Element/hr>`_ 를 참조하세요.\"\n\n#: ../../xml-class.rst:111 c7287c022bd74ffb8a4456a54fbab923\nmsgid \"\"\n\"Add an :htmlTag:`img` tag. This causes the inclusion of the named image \"\n\"in the DOM.\"\nmsgstr \":htmlTag:`img` 태그 추가. 이것은 DOM에 명명된 이미지를 포함시킵니다.\"\n\n#: ../../xml-class.rst:113 803faa071c22481ca0eb93e0dfe4a50c\nmsgid \"\"\n\"the filename of the image. This **must be the member name** of some entry\"\n\" of the :ref:`Archive` parameter of the :ref:`Story` constructor.\"\nmsgstr \"이미지의 파일명. 이것은 :ref:`Story` 생성자의 :ref:`Archive` 매개변수 항목의 **멤버 이름** 이어야 합니다.\"\n\n#: ../../xml-class.rst:114 e30e974b6d8f40e2a1f1ee4faf38c16e\nmsgid \"\"\n\"if provided, either an absolute (int) value, or a percentage string like \"\n\"\\\"30%\\\". A percentage value refers to the width of the specified `where` \"\n\"rectangle in :meth:`Story.place`. If this value is provided and `height` \"\n\"is omitted, the image will be included keeping its aspect ratio.\"\nmsgstr \"\"\n\"제공된 경우 절대(int) 값 또는 \\\"30%\\\" 와 같은 백분율 문자열입니다. 백분율 값은 :meth:`Story.place` 의\"\n\" 지정된 `where` 사각형의 너비를 나타냅니다. 이 값이 제공되고 `height` 가 생략되면 이미지는 종횡비를 유지하면서 \"\n\"포함됩니다.\"\n\n#: ../../xml-class.rst:115 c0a019f0782f47a5941d4ff3a82604c2\nmsgid \"\"\n\"if provided, either an absolute (int) value, or a percentage string like \"\n\"\\\"30%\\\". A percentage value refers to the height of the specified `where`\"\n\" rectangle in :meth:`Story.place`. If this value is provided and `width` \"\n\"is omitted, the image's aspect ratio will be honored.\"\nmsgstr \"\"\n\"제공된 경우 절대(int) 값 또는 \\\"30%\\\" 와 같은 백분율 문자열입니다. 백분율 값은 :meth:`Story.place` 의\"\n\" 지정된 `where` 사각형의 높이를 나타냅니다. 이 값이 제공되고 `width` 가 생략되면 이미지의 종횡비가 유지됩니다.\"\n\n#: ../../xml-class.rst:119 6222aa6b43c84a56996f4df07038c376\nmsgid \"Add an :htmlTag:`a` tag - inline element, treated like text.\"\nmsgstr \":htmlTag:`a` 태그 추가 - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:121 fdb4bad9f0de43c296f9e0a510b0be66\nmsgid \"the URL target.\"\nmsgstr \"URL 대상.\"\n\n#: ../../xml-class.rst:122 f986906bddca4fce889f02adb8c3edfa\nmsgid \"the text to display. If omitted, the `href` text is shown instead.\"\nmsgstr \"표시할 텍스트. 생략하면 `href` 텍스트가 대신 표시됩니다.\"\n\n#: ../../xml-class.rst:126 92be3d9375f54667873b6fe8ca12fa51\nmsgid \"Add an :htmlTag:`ol` tag, context manager.\"\nmsgstr \":htmlTag:`ol` 태그 추가, 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:130 f4d77e1cdb65420fa7405be7460b249f\nmsgid \"Add a :htmlTag:`p` tag, context manager.\"\nmsgstr \":htmlTag:`p` 태그 추가, 컨텍스트 매니저.\"\n\n#: ../../xml-class.rst:134 29eaf25ddba343e692000d7110886a16\nmsgid \"Add a :htmlTag:`span` tag, context manager. See `span`_\"\nmsgstr \":htmlTag:`span` 태그 추가, 컨텍스트 매니저. `span`_ 를 참조하세요\"\n\n#: ../../xml-class.rst:138 dccc012fd1c245d9a82d12506448b061\nmsgid \"\"\n\"Add \\\"subscript\\\" text(:htmlTag:`sub` tag) - inline element, treated like\"\n\" text.\"\nmsgstr \"\\\"아래첨자\\\" 텍스트 추가(:htmlTag:`sub` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:142 cf804acbbb5f464b8f6397266f166088\nmsgid \"\"\n\"Add \\\"superscript\\\" text (:htmlTag:`sup` tag) - inline element, treated \"\n\"like text.\"\nmsgstr \"\\\"위첨자\\\" 텍스트 추가(:htmlTag:`sup` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:146 8dc97f93b0274ec5bce1de3b4ff37925\nmsgid \"\"\n\"Add \\\"code\\\" text (:htmlTag:`code` tag) - inline element, treated like \"\n\"text.\"\nmsgstr \"\\\"코드\\\" 텍스트 추가(:htmlTag:`code` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:150 7ba6387f382a47489d0ce8bcdcf295b7\nmsgid \"\"\n\"Add \\\"variable\\\" text (:htmlTag:`var` tag) - inline element, treated like\"\n\" text.\"\nmsgstr \"\\\"변수\\\" 텍스트 추가(:htmlTag:`var` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:154 f838fe3c409c4c24b69164831b3e719a\nmsgid \"\"\n\"Add \\\"sample output\\\" text (:htmlTag:`samp` tag) - inline element, \"\n\"treated like text.\"\nmsgstr \"\\\"샘플 출력\\\" 텍스트 추가(:htmlTag:`samp` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:158 e0ac1ab1ff06451286d193648fa3012e\nmsgid \"\"\n\"Add \\\"keyboard input\\\" text (:htmlTag:`kbd` tag) - inline element, \"\n\"treated like text.\"\nmsgstr \"\\\"키보드 입력\\\" 텍스트 추가(:htmlTag:`kbd` 태그) - 인라인 요소, 텍스트처럼 처리됩니다.\"\n\n#: ../../xml-class.rst:166 fb7159ea6f3e454687d447905e1fb63e\nmsgid \"Set the text alignment. Only works for block-level tags.\"\nmsgstr \"텍스트 정렬을 설정합니다. 블록 레벨 태그에만 작동합니다.\"\n\n#: ../../xml-class.rst:168 66bce7c8f20f4b2987deadc2e78c5e17\nmsgid \"\"\n\"either one of the :ref:`TextAlign` or the `text-align \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/text-align>`_ values.\"\nmsgstr \"\"\n\":ref:`TextAlign` 중 하나 또는 `text-align <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/text-align>`_ 값.\"\n\n#: ../../xml-class.rst:174 ../../xml-class.rst:187 ../../xml-class.rst:195\n#: d7aad8433d4b4ae28b02feced7823c68 ed342f6d55a241d08a69381dee663b2f\n#: efe9866f00ec4947a478509974de173a\nmsgid \"the name of the attribute.\"\nmsgstr \"속성의 이름.\"\n\n#: ../../xml-class.rst:175 830437471d0e48c785ca5e15b55e435f\nmsgid \"the (optional) value of the attribute.\"\nmsgstr \"속성의 (선택적) 값.\"\n\n#: ../../xml-class.rst:179 60d418fba6084ff28607414510c9266a\nmsgid \"Retrieve all attributes of the current nodes as a dictionary.\"\nmsgstr \"현재 노드의 모든 속성을 딕셔너리로 검색합니다.\"\n\n#: ../../xml-class.rst 2a701f48413144dab311db1561eb1c0e\n#: c37952141e1f421b8ce9ae427841107e cc52891e847543b59823983f02b914d4\n#: da7ccff444ac4cea98762959deb04bf2 dfda8cf8c928444b9a36c099258dcd98\n#: e957c78900eb4dc6b0ef81f303dc9a49 f1f773fbd025444c85403f7249ce73a3\nmsgid \"Returns\"\nmsgstr \"반환값\"\n\n#: ../../xml-class.rst:181 03d7a82f94c4440ca4de7313573c205e\nmsgid \"a dictionary with the attributes and their values of the node.\"\nmsgstr \"노드의 속성과 값이 있는 딕셔너리.\"\n\n#: ../../xml-class.rst:185 64fde0623dc74f35a18bdd2e5f525e1a\nmsgid \"Get the attribute value of `key`.\"\nmsgstr \"`key` 의 속성 값을 가져옵니다.\"\n\n#: ../../xml-class.rst:189 75de20320c6e4393bd9bb242e39953b5\nmsgid \"a string with the value of `key`.\"\nmsgstr \"`key` 의 값을 가진 문자열.\"\n\n#: ../../xml-class.rst:193 60c7b6c3758a4d87ae2aba6bbd8119d9\nmsgid \"Remove the attribute `key` from the node.\"\nmsgstr \"노드에서 속성 `key` 를 제거합니다.\"\n\n#: ../../xml-class.rst:201 e5de65082c214d558cbb52a710140364\nmsgid \"\"\n\"either an RGB value like (255, 0, 0) (for \\\"red\\\") or a valid \"\n\"`background-color <https://developer.mozilla.org/en-US/docs/Web/CSS\"\n\"/background-color>`_ value.\"\nmsgstr \"\"\n\"(255, 0, 0)(\\\"red\\\"의 경우)와 같은 RGB 값 또는 유효한 `background-color \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/background-color>`_ 값.\"\n\n#: ../../xml-class.rst:207 cc773c1679604ba6b0c57266774838b3\nmsgid \"\"\n\"`True`, `False` or a valid `font-weight <https://developer.mozilla.org\"\n\"/en-US/docs/Web/CSS/font-weight>`_ value.\"\nmsgstr \"\"\n\"`True`, `False` 또는 유효한 `font-weight <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/font-weight>`_ 값.\"\n\n#: ../../xml-class.rst:211 d90edf95aa3c4c75b9e7500594da74b2\nmsgid \"Set the color of the text following.\"\nmsgstr \"다음 텍스트의 색상을 설정합니다.\"\n\n#: ../../xml-class.rst:213 dd4f443acc6e4824b8cbe2bfe79d6923\nmsgid \"\"\n\"either an RGB value like (255, 0, 0) (for \\\"red\\\") or a valid `color \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/color_value>`_ value.\"\nmsgstr \"\"\n\"(255, 0, 0)(\\\"red\\\"의 경우)와 같은 RGB 값 또는 유효한 `color \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/color_value>`_ 값.\"\n\n#: ../../xml-class.rst:217 d077d7854b80478dacf03fa0669683dd\nmsgid \"Set the number of columns.\"\nmsgstr \"열 수를 설정합니다.\"\n\n#: ../../xml-class.rst:219 96343b27b1504159919805d5df4e0f45\nmsgid \"\"\n\"a valid `columns <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/columns>`_ value.\"\nmsgstr \"\"\n\"유효한 `columns <https://developer.mozilla.org/en-US/docs/Web/CSS/columns>`_\"\n\" 값.\"\n\n#: ../../xml-class.rst:221 74ba294325804581ab5480e351d416dc\nmsgid \"Currently ignored - supported in a future MuPDF version.\"\nmsgstr \"현재 무시됨 - 향후 MuPDF 버전에서 지원됩니다.\"\n\n#: ../../xml-class.rst:225 cc957f31c573429db439f0f119f8b79a\nmsgid \"Set the font-family.\"\nmsgstr \"글꼴 패밀리를 설정합니다.\"\n\n#: ../../xml-class.rst:227 2ee787378e4543f8aa556edc1b69e9f4\nmsgid \"e.g. \\\"sans-serif\\\".\"\nmsgstr \"예: \\\"sans-serif\\\".\"\n\n#: ../../xml-class.rst:231 2c45062745bc4642a19aa67d3d79273b\nmsgid \"Set the font size for text following.\"\nmsgstr \"다음 텍스트의 글꼴 크기를 설정합니다.\"\n\n#: ../../xml-class.rst:233 ec2f8b7640cf481eb1fa289645417c1f\nmsgid \"\"\n\"a float or a valid `font-size <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/font-size>`_ value.\"\nmsgstr \"\"\n\"float 또는 유효한 `font-size <https://developer.mozilla.org/en-US/docs/Web/CSS\"\n\"/font-size>`_ 값.\"\n\n#: ../../xml-class.rst:237 febde85bc5fd4f8ea34b31ed63f36672\nmsgid \"\"\n\"Set a :htmlTag:`id`. This serves as a unique identification of the node \"\n\"within the DOM. Use it to easily locate the node to inspect or modify it.\"\n\" A check for uniqueness is performed.\"\nmsgstr \"\"\n\":htmlTag:`id` 를 설정합니다. 이것은 DOM 내에서 노드의 고유 식별자 역할을 합니다. 노드를 쉽게 찾아 검사하거나 \"\n\"수정하는 데 사용하세요. 고유성 검사가 수행됩니다.\"\n\n#: ../../xml-class.rst:239 e37b1314ab6d42b0a2ec907c5db6d0dd\nmsgid \"id string of the node.\"\nmsgstr \"노드의 id 문자열.\"\n\n#: ../../xml-class.rst:243 aa326115828c452382e6d09902d27dab\nmsgid \"Set italic on or off or to some string value for the text following it.\"\nmsgstr \"다음 텍스트에 대해 기울임꼴을 켜거나 끄거나 일부 문자열 값으로 설정합니다.\"\n\n#: ../../xml-class.rst:245 5fb40161298741eb829c7b4bd4131f42\nmsgid \"\"\n\"`True`, `False` or some valid `font-style <https://developer.mozilla.org\"\n\"/en-US/docs/Web/CSS/font-style>`_ value.\"\nmsgstr \"\"\n\"`True`, `False` 또는 유효한 `font-style <https://developer.mozilla.org/en-\"\n\"US/docs/Web/CSS/font-style>`_ 값.\"\n\n#: ../../xml-class.rst:251 2ff6178aa7a4490cb0b3b797e692f3b3\nmsgid \"the distance in points to the previous block.\"\nmsgstr \"이전 블록까지의 거리(포인트 단위).\"\n\n#: ../../xml-class.rst:255 aa0c45b2f59b4dba8ff847821f1805b3\nmsgid \"Set height of a line.\"\nmsgstr \"줄 높이를 설정합니다.\"\n\n#: ../../xml-class.rst:257 816223093e62465d9c778a7599f93b30\nmsgid \"\"\n\"a float like 1.5 (which sets to `1.5 * fontsize`), or some valid `line-\"\n\"height <https://developer.mozilla.org/en-US/docs/Web/CSS/line-height>`_ \"\n\"value.\"\nmsgstr \"\"\n\"1.5와 같은 float(`1.5 * fontsize` 로 설정됨) 또는 유효한 `line-height \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/line-height>`_ 값.\"\n\n#: ../../xml-class.rst:261 ab5060c3426c487d9c1f1b68eb6d3c69\nmsgid \"Set the margin(s).\"\nmsgstr \"여백을 설정합니다.\"\n\n#: ../../xml-class.rst:263 eb0e87c661e741e7ac93e7749a905007\nmsgid \"\"\n\"float or string with up to 4 values. See `CSS documentation \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/margin>`_.\"\nmsgstr \"\"\n\"최대 4개의 값을 가진 float 또는 문자열. `CSS documentation \"\n\"<https://developer.mozilla.org/en-US/docs/Web/CSS/margin>`_ 를 참조하세요.\"\n\n#: ../../xml-class.rst:275 0157cb04fc7e41299f0dc0a351924d25\nmsgid \"\"\n\"Set any or all desired properties in one call. The meaning of argument \"\n\"values equal the values of the corresponding `set_` methods.\"\nmsgstr \"한 번의 호출로 원하는 모든 속성을 설정합니다. 인수 값의 의미는 해당 `set_` 메서드의 값과 같습니다.\"\n\n#: ../../xml-class.rst:277 0bd79cbc338f46fb9d6dbca48839d876\nmsgid \"\"\n\"The properties set by this method are directly attached to the node, \"\n\"whereas every `set_` method generates a new :htmlTag:`span` below the \"\n\"current node that has the respective property. So to e.g. \\\"globally\\\" \"\n\"set some property for the :htmlTag:`body`, this method must be used.\"\nmsgstr \"\"\n\"이 메서드로 설정된 속성은 노드에 직접 연결되지만, 모든 `set_` 메서드는 해당 속성을 가진 새 :htmlTag:`span` 을\"\n\" 현재 노드 아래에 생성합니다. 따라서 예를 들어 :htmlTag:`body` 에 대해 일부 속성을 \\\"전역적으로\\\" 설정하려면 이\"\n\" 메서드를 사용해야 합니다.\"\n\n#: ../../xml-class.rst:281 d0e7dcd50d50443298496ec86ea5f06f\nmsgid \"Set (add) some style attribute not supported by its own `set_` method.\"\nmsgstr \"자체 `set_` 메서드로 지원되지 않는 일부 스타일 속성을 설정(추가)합니다.\"\n\n#: ../../xml-class.rst:283 89724c2b528143acb5bf27d647496828\nmsgid \"any valid CSS style value.\"\nmsgstr \"유효한 CSS 스타일 값.\"\n\n#: ../../xml-class.rst:287 5d883179b1f24ccb981b1a229346ba04\nmsgid \"Set (add) some \\\"class\\\" attribute.\"\nmsgstr \"\\\"class\\\" 속성을 설정(추가)합니다.\"\n\n#: ../../xml-class.rst:289 3389956444bb4b60ad401df187e94d35\nmsgid \"\"\n\"the name of the class. Must have been defined in either the HTML or the \"\n\"CSS source of the DOM.\"\nmsgstr \"클래스의 이름. DOM의 HTML 또는 CSS 소스에 정의되어 있어야 합니다.\"\n\n#: ../../xml-class.rst:293 c56792aa596943509620fa4f964b76df\nmsgid \"\"\n\"Set indentation for the first textblock line. Only works for block-level \"\n\"nodes.\"\nmsgstr \"첫 번째 텍스트 블록 줄의 들여쓰기를 설정합니다. 블록 레벨 노드에만 작동합니다.\"\n\n#: ../../xml-class.rst:295 a8dbb4085cbe4b2a8faf0e4dedeaac64\nmsgid \"\"\n\"a valid `text-indent <https://developer.mozilla.org/en-US/docs/Web/CSS\"\n\"/text-indent>`_ value. Please note that negative values do not work.\"\nmsgstr \"\"\n\"유효한 `text-indent <https://developer.mozilla.org/en-US/docs/Web/CSS/text-\"\n\"indent>`_ 값. 음수 값은 작동하지 않습니다.\"\n\n#: ../../xml-class.rst:300 34b0b40691834d299f9242060c378272\nmsgid \"\"\n\"Append a child node. This is a low-level method used by other methods \"\n\"like :meth:`Xml.add_paragraph`.\"\nmsgstr \"자식 노드를 추가합니다. 이것은 :meth:`Xml.add_paragraph` 와 같은 다른 메서드에서 사용하는 저수준 메서드입니다.\"\n\n#: ../../xml-class.rst:302 4c13861f3a074b469917e2e88ad6c284\nmsgid \"the :ref:`Xml` node to append.\"\nmsgstr \"추가할 :ref:`Xml` 노드.\"\n\n#: ../../xml-class.rst:308 96d40261c6e84cceaf10bd528d633399\nmsgid \"the text to append.\"\nmsgstr \"추가할 텍스트.\"\n\n#: ../../xml-class.rst 474ed85eaea94b85a254b07bf5054bf1\n#: 72f9935368ec4cb5b008689ec052a3a5 7be3b6d6eee5465187b72a87498fa9c7\n#: d92af6de71cf4f6b9697f66106f46df6\nmsgid \"Return type\"\nmsgstr \"반환 타입\"\n\n#: ../../xml-class.rst:310 ../../xml-class.rst:319\n#: 248a06ef868840be803afcb1c276fbfa 69466f3d8b5847bd8ddfddfc7474f0d6\nmsgid \":ref:`Xml`\"\nmsgstr \":ref:`Xml`\"\n\n#: ../../xml-class.rst:311 17a38613ac3c4a1a8c69cf5d7140b0b2\nmsgid \"the created element.\"\nmsgstr \"생성된 요소.\"\n\n#: ../../xml-class.rst:315 e3a170c5762240faba5225ad0ad8a408\nmsgid \"\"\n\"Create a new node with a given tag. This a low-level method used by other\"\n\" methods like :meth:`Xml.add_paragraph`.\"\nmsgstr \"\"\n\"주어진 태그로 새 노드를 생성합니다. 이것은 :meth:`Xml.add_paragraph` 와 같은 다른 메서드에서 사용하는 저수준\"\n\" 메서드입니다.\"\n\n#: ../../xml-class.rst:317 f16e668926f44a5ebc013218d888af8b\nmsgid \"the element tag.\"\nmsgstr \"요소 태그.\"\n\n#: ../../xml-class.rst:320 50c7ac51012d41ef83aca12b4c6bfd13\nmsgid \"\"\n\"the created element. To actually bind it to the DOM, use \"\n\":meth:`Xml.append_child`.\"\nmsgstr \"생성된 요소. 실제로 DOM에 바인딩하려면 :meth:`Xml.append_child` 를 사용하세요.\"\n\n#: ../../xml-class.rst:324 a74da9bcb64a4677bdab647d12b9698d\nmsgid \"Insert the given element `elem` before this node.\"\nmsgstr \"주어진 요소 `elem` 을 이 노드 앞에 삽입합니다.\"\n\n#: ../../xml-class.rst:326 ../../xml-class.rst:332\n#: a03dabcd2f5e44909735e0fa454a622a ac47ac263e2644b9a6a056f2b71dd185\nmsgid \"some :ref:`Xml` element.\"\nmsgstr \"일부 :ref:`Xml` 요소.\"\n\n#: ../../xml-class.rst:330 2285051e65084c86bdb3ac4c50b6ee73\nmsgid \"Insert the given element `elem` after this node.\"\nmsgstr \"주어진 요소 `elem` 을 이 노드 뒤에 삽입합니다.\"\n\n#: ../../xml-class.rst:336 efebb24cc65b4bf7810de7852eee4bb3\nmsgid \"\"\n\"Make a copy of this node, which then may be appended (using \"\n\":meth:`Xml.append_child`) or inserted (using one of \"\n\":meth:`Xml.insert_before`, :meth:`Xml.insert_after`) in this DOM.\"\nmsgstr \"\"\n\"이 노드의 복사본을 만듭니다. 그런 다음 이 DOM에 추가( :meth:`Xml.append_child` 사용)하거나 삽입( \"\n\":meth:`Xml.insert_before`, :meth:`Xml.insert_after` 중 하나 사용)할 수 있습니다.\"\n\n#: ../../xml-class.rst:338 443c529ea1eb4979bac6aa87b07e5ae5\nmsgid \"the clone (:ref:`Xml`) of the current node.\"\nmsgstr \"현재 노드의 복제본(:ref:`Xml`).\"\n\n#: ../../xml-class.rst:342 47ec6b03e3584446a21cae3e9dfc740e\nmsgid \"Remove this node from the DOM.\"\nmsgstr \"이 노드를 DOM에서 제거합니다.\"\n\n#: ../../xml-class.rst:347 436c60e603974335862d86319e3ad149\nmsgid \"For debugging purposes, print this node's structure in a simplified form.\"\nmsgstr \"디버깅 목적으로 이 노드의 구조를 간소화된 형태로 출력합니다.\"\n\n#: ../../xml-class.rst:351 6eb8a8f3e0e242169288042ca92620ce\nmsgid \"\"\n\"Under the current node, find the first node with the given `tag`, \"\n\"attribute `att` and value `match`.\"\nmsgstr \"현재 노드 아래에서 주어진 `tag`, 속성 `att` 및 값 `match` 를 가진 첫 번째 노드를 찾습니다.\"\n\n#: ../../xml-class.rst:353 15e37abf37614b23be73a14603937165\nmsgid \"restrict search to this tag. May be `None` for unrestricted searches.\"\nmsgstr \"이 태그로 검색을 제한합니다. 제한 없는 검색의 경우 `None` 일 수 있습니다.\"\n\n#: ../../xml-class.rst:354 f745373d2e69452e985e2dac159ea5c2\nmsgid \"check this attribute. May be `None`.\"\nmsgstr \"이 속성을 확인합니다. `None` 일 수 있습니다.\"\n\n#: ../../xml-class.rst:355 165356d315d24c0a8ed99526c1b01dd7\nmsgid \"the desired attribute value to match. May be `None`.\"\nmsgstr \"일치시킬 원하는 속성 값. `None` 일 수 있습니다.\"\n\n#: ../../xml-class.rst:357 ../../xml-class.rst:364\n#: 01f3aba4e08b4252b10413f4311480f2 f48e420675664a59bc388c905451c4fc\nmsgid \":ref:`Xml`.\"\nmsgstr \":ref:`Xml`.\"\n\n#: ../../xml-class.rst:358 ccbc86d49fc74fa5b0de1f0336c0fce8\nmsgid \"`None` if nothing found, otherwise the first matching node.\"\nmsgstr \"찾은 것이 없으면 `None`, 그렇지 않으면 첫 번째 일치하는 노드.\"\n\n#: ../../xml-class.rst:362 b0c5a67c416d423d838e1bf344e4819d\nmsgid \"\"\n\"Continue a previous :meth:`Xml.find` (or :meth:`find_next`) with the same\"\n\" values.\"\nmsgstr \"동일한 값으로 이전 :meth:`Xml.find` (또는 :meth:`find_next`) 를 계속합니다.\"\n\n#: ../../xml-class.rst:365 57c7ab6c7b504406b51c6e8574ddec4b\nmsgid \"`None` if none more found, otherwise the next matching node.\"\nmsgstr \"더 이상 찾은 것이 없으면 `None`, 그렇지 않으면 다음 일치하는 노드.\"\n\n#: ../../xml-class.rst:378 89934d92ed6140979716d32f3cc7a713\nmsgid \"Check if a text node.\"\nmsgstr \"텍스트 노드인지 확인합니다.\"\n\n#: ../../xml-class.rst:402 400a4f578b98416091fc04c3e3347a91\nmsgid \"Setting Text properties\"\nmsgstr \"텍스트 속성 설정\"\n\n#: ../../xml-class.rst:404 3fa3fea9963b4eba99ff8e83ed31ee32\nmsgid \"\"\n\"In HTML tags can be nested such that innermost text **inherits \"\n\"properties** from the tag enveloping its parent tag. For example \"\n\"`<p><b>some bold text<i>this is bold and italic</i></b>regular text</p>`.\"\nmsgstr \"\"\n\"HTML에서 태그는 가장 안쪽 텍스트가 부모 태그를 감싸는 태그로부터 **속성을 상속** 하도록 중첩될 수 있습니다. 예: \"\n\"`<p><b>some bold text<i>this is bold and italic</i></b>regular text</p>`.\"\n\n#: ../../xml-class.rst:406 eed0c2145e1647ee82f831b11a407df7\nmsgid \"\"\n\"To achieve the same effect, methods like :meth:`Xml.set_bold` and \"\n\":meth:`Xml.set_italic` each open a temporary :htmlTag:`span` with the \"\n\"desired property underneath the current node.\"\nmsgstr \"\"\n\"동일한 효과를 얻기 위해 :meth:`Xml.set_bold` 및 :meth:`Xml.set_italic` 와 같은 메서드는 각각 \"\n\"현재 노드 아래에 원하는 속성을 가진 임시 :htmlTag:`span` 을 엽니다.\"\n\n#: ../../xml-class.rst:408 f93907c09e2e4f8983b02e2797060870\nmsgid \"\"\n\"In addition, these methods return there parent node, so they can be \"\n\"concatenated with each other.\"\nmsgstr \"또한 이러한 메서드는 부모 노드를 반환하므로 서로 연결할 수 있습니다.\"\n\n#: ../../xml-class.rst:413 6c46240a1795450497d3b9f26c22b085\nmsgid \"Context Manager support\"\nmsgstr \"컨텍스트 매니저 지원\"\n\n#: ../../xml-class.rst:414 ebbde3aa8eae44eaa2eb7717c33fd3c7\nmsgid \"The standard way to add nodes to a DOM is this::\"\nmsgstr \"DOM에 노드를 추가하는 표준 방법은 다음과 같습니다::\"\n\n#: ../../xml-class.rst:427 aa6e31a0372e4c5082cdb4ff60b21766\nmsgid \"\"\n\"Methods that are flagged as \\\"context managers\\\" can conveniently be used\"\n\" in this way::\"\nmsgstr \"\\\"컨텍스트 매니저\\\" 로 표시된 메서드는 다음과 같이 편리하게 사용할 수 있습니다::\"\n\n#: ../../footer.rst:57 3237dfa1d64d4115b40cd8888565be39\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/locales/ko/LC_MESSAGES/znames.po",
    "content": "# SOME DESCRIPTIVE TITLE.\n# Copyright (C) 2015-2025, Artifex\n# This file is distributed under the same license as the PyMuPDF package.\n# FIRST AUTHOR <EMAIL@ADDRESS>, 2025.\n#\n#, fuzzy\nmsgid \"\"\nmsgstr \"\"\n\"Project-Id-Version: PyMuPDF 1.26.7\\n\"\n\"Report-Msgid-Bugs-To: \\n\"\n\"POT-Creation-Date: 2025-11-25 23:33+0000\\n\"\n\"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\\n\"\n\"Last-Translator: FULL NAME <EMAIL@ADDRESS>\\n\"\n\"Language: ko\\n\"\n\"Language-Team: ko <LL@li.org>\\n\"\n\"Plural-Forms: nplurals=1; plural=0;\\n\"\n\"MIME-Version: 1.0\\n\"\n\"Content-Type: text/plain; charset=utf-8\\n\"\n\"Content-Transfer-Encoding: 8bit\\n\"\n\"Generated-By: Babel 2.10.3\\n\"\n\n#: ../../header.rst:-1 0eb4a369e5b94c7489997eb18eb43347\nmsgid \"Artifex\"\nmsgstr \"Artifex\"\n\n#: ../../header.rst:-1 d0b7be7b87414f0dacea935473d04f43\nmsgid \"\"\n\"PyMuPDF is a high-performance Python library for data extraction, \"\n\"analysis, conversion & manipulation of PDF (and other) documents.\"\nmsgstr \"PyMuPDF는 PDF 및 기타 문서의 데이터 추출, 분석, 변환, 조작을 위한 고성능 Python 라이브러리입니다.\"\n\n#: ../../header.rst:-1 caca777a734049198ad1a788ab3304f9\nmsgid \"\"\n\"PDF Text Extraction, PDF Image Extraction, PDF Conversion, PDF Tables, \"\n\"PDF Splitting, PDF Creation, Pyodide, PyScript\"\nmsgstr \"PDF 텍스트 추출, PDF 이미지 추출, PDF 변환, PDF 테이블, PDF 분할, PDF 생성, Pyodide, PyScript\"\n\n#: ../../znames.rst:7 083b7e0a5a2b460f8da6d411d620371a\nmsgid \"Deprecated Names\"\nmsgstr \"사용 중단된 이름\"\n\n#: ../../znames.rst:9 e3a203bb6f834ba0a39fa9d32da05a58\nmsgid \"\"\n\"The original naming convention for methods and properties has been \"\n\"\\\"camelCase\\\". Since its creation around 2013, a tremendous increase of \"\n\"functionality has happened in PyMuPDF -- and with it a corresponding \"\n\"increase in classes, methods and properties. In too many cases, this has \"\n\"led to non-intuitive, illogical and ugly names, difficult to memorize or \"\n\"guess.\"\nmsgstr \"메서드와 속성의 원래 명명 규칙은 \\\"camelCase\\\"였습니다. 2013년경 생성 이후 PyMuPDF에서 기능이 크게 증가했고, 이에 따라 클래스, 메서드, 속성도 증가했습니다. 많은 경우 직관적이지 않고 논리적이지 않으며 기억하거나 추측하기 어려운 이름이 생겼습니다.\"\n\n#: ../../znames.rst:11 d001aeecdacb4bd59a62961dbc1370dd\nmsgid \"\"\n\"A few versions ago, I therefore decided to shift gears and switch to a \"\n\"\\\"snake_cased\\\" naming standard. This was a major effort, which needed a \"\n\"step-wise approach. I think am done with it now (version 1.18.14).\"\nmsgstr \"몇 버전 전, 단계적 접근이 필요한 큰 작업이었지만 \\\"snake_cased\\\" 명명 표준으로 전환하기로 했습니다. 이제는 완료된 것으로 봅니다(버전 1.18.14).\"\n\n#: ../../znames.rst:14 6f07346687c14dbb83e38186df94b743\nmsgid \"\"\n\"The following list maps deprecated names to their new versions. For \"\n\"example, property `pageCount` became `page_count` in the :ref:`Document` \"\n\"class. There also are less obvious name changes, e.g. method `getPNGdata`\"\n\" was renamed to `tobytes` in the :ref:`Pixmap` class.\"\nmsgstr \"다음 목록은 사용 중단된 이름을 새 버전에 매핑합니다. 예를 들어, 속성 `pageCount` 는 :ref:`Document` 클래스에서 `page_count` 가 되었습니다. 덜 명확한 이름 변경도 있습니다. 예를 들어 메서드 `getPNGdata` 는 :ref:`Pixmap` 클래스에서 `tobytes` 로 이름이 변경되었습니다.\"\n\n#: ../../znames.rst:16 cc7e51d7a5144cd290ff0b79249d442c\nmsgid \"\"\n\"Names of classes (camel case) and package-wide constants (the majority is\"\n\" upper case) remain untouched.\"\nmsgstr \"클래스 이름(카멜 케이스)과 패키지 전체 상수(대부분 대문자)는 변경되지 않았습니다.\"\n\n#: ../../znames.rst:18 6e79bdebc3d2434394db7e65ce997c71\nmsgid \"\"\n\"Old names will remain available as deprecated aliases through MuPDF \"\n\"version 1.19.0 and **be removed** in the version that follows it - \"\n\"probably version 1.20.0, but this depends on upstream decisions (MuPDF).\"\nmsgstr \"이전 이름은 MuPDF 버전 1.19.0까지 사용 중단된 별칭으로 사용 가능하며, 그 이후 버전(아마도 버전 1.20.0이지만, 이는 상류 결정(MuPDF)에 따라 다름)에서 **제거됩니다**.\"\n\n#: ../../znames.rst:20 dbf4b6c8f3134ca596bd0a822ffd2e9b\nmsgid \"\"\n\"Starting with version 1.19.0, we will issue deprecation warnings on \"\n\"`sys.stderr` like `Deprecation: 'newPage' removed from class 'Document' \"\n\"after v1.19.0 - use 'new_page'.` when aliased methods are being used. \"\n\"Using a deprecated property will not cause this type of warning.\"\nmsgstr \"버전 1.19.0부터 별칭 메서드가 사용될 때 `sys.stderr` 에 `Deprecation: 'newPage' removed from class 'Document' after v1.19.0 - use 'new_page'.` 와 같은 사용 중단 경고를 발행합니다. 사용 중단된 속성을 사용해도 이 유형의 경고는 발생하지 않습니다.\"\n\n#: ../../znames.rst:22 2f0d5cce9e2e4f5e8541eb4b6fc686ed\nmsgid \"\"\n\"Starting immediately, all deprecated objects (methods and properties) \"\n\"will show a copy of the original's docstring, **prefixed** with the \"\n\"deprecation message, for example::\"\nmsgstr \"즉시부터 모든 사용 중단된 객체(메서드 및 속성)는 원본의 docstring 복사본을 표시하며, 사용 중단 메시지가 **접두사** 로 붙습니다. 예:\"\n\n#: ../../znames.rst:39 8e4f2cae0e38499bbf0543f4bdfb1885\nmsgid \"\"\n\"There is a utility script `alias-changer.py <https://github.com/pymupdf\"\n\"/PyMuPDF-Utilities/tree/master/alias-changer.py>`_ which can be used to \"\n\"do mass-renames in your scripts. It accepts either a single file or a \"\n\"folder as argument. If a folder is supplied, all its Python files and \"\n\"those of its subfolders are changed. Optionally, backups of the scripts \"\n\"can be taken.\"\nmsgstr \"스크립트에서 대량 이름 변경을 수행하는 데 사용할 수 있는 유틸리티 스크립트 `alias-changer.py <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/alias-changer.py>`_ 가 있습니다. 단일 파일 또는 폴더를 인수로 받습니다. 폴더가 제공되면 해당 폴더의 모든 Python 파일과 하위 폴더의 파일이 변경됩니다. 선택적으로 스크립트의 백업을 만들 수 있습니다.\"\n\n#: ../../footer.rst:46 52ab1685187a4ce284f0a14818fcf934\nmsgid \"This documentation covers all versions up to |version|.\"\nmsgstr \"이 문서는 |version| 버전까지의 모든 버전을 다룹니다.\"\n\n"
  },
  {
    "path": "docs/lowlevel.rst",
    "content": ".. include:: header.rst\n\n=================================\nLow Level Functions and Classes\n=================================\nContains a number of functions and classes for the experienced user. To be used for special needs or performance requirements.\n\n.. toctree::\n   :maxdepth: 1\n\n   functions\n   device\n   coop_low\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/matrix.rst",
    "content": ".. include:: header.rst\n\n.. _Matrix:\n\n==========\nMatrix\n==========\n\nMatrix is a row-major 3x3 matrix used by image transformations in MuPDF (which complies with the respective concepts laid down in the :ref:`AdobeManual`). With matrices you can manipulate the rendered image of a page in a variety of ways: (parts of) the page can be rotated, zoomed, flipped, sheared and shifted by setting some or all of just six float values.\n\n\nSince all points or pixels live in a two-dimensional space, one column vector of that matrix is a constant unit vector, and only the remaining six elements are used for manipulations. These six elements are usually represented by `[a, b, c, d, e, f]`. Here is how they are positioned in the matrix:\n\n.. image:: images/img-matrix.*\n\n\nPlease note:\n\n    * the below methods are just convenience functions -- everything they do, can also be achieved by directly manipulating the six numerical values\n    * all manipulations can be combined -- you can construct a matrix that rotates **and** shears **and** scales **and** shifts, etc. in one go. If you however choose to do this, do have a look at the **remarks** further down or at the :ref:`AdobeManual`.\n\n================================ ==============================================\n**Method / Attribute**             **Description**\n================================ ==============================================\n:meth:`Matrix.prerotate`         perform a rotation\n:meth:`Matrix.prescale`          perform a scaling\n:meth:`Matrix.preshear`          perform a shearing (skewing)\n:meth:`Matrix.pretranslate`      perform a translation (shifting)\n:meth:`Matrix.concat`            perform a matrix multiplication\n:meth:`Matrix.invert`            calculate the inverted matrix\n:meth:`Matrix.norm`              the Euclidean norm\n:attr:`Matrix.a`                 zoom factor X direction\n:attr:`Matrix.b`                 shearing effect Y direction\n:attr:`Matrix.c`                 shearing effect X direction\n:attr:`Matrix.d`                 zoom factor Y direction\n:attr:`Matrix.e`                 horizontal shift\n:attr:`Matrix.f`                 vertical shift\n:attr:`Matrix.is_rectilinear`    true if rect corners will remain rect corners\n================================ ==============================================\n\n**Class API**\n\n.. class:: Matrix\n\n   .. method:: __init__(self)\n\n   .. method:: __init__(self, zoom-x, zoom-y)\n\n   .. method:: __init__(self, shear-x, shear-y, 1)\n\n   .. method:: __init__(self, a, b, c, d, e, f)\n\n   .. method:: __init__(self, matrix)\n\n   .. method:: __init__(self, degree)\n\n   .. method:: __init__(self, sequence)\n\n      Overloaded constructors.\n\n      Without parameters, the zero matrix *Matrix(0.0, 0.0, 0.0, 0.0, 0.0, 0.0)* will be created.\n\n      *zoom-** and *shear-** specify zoom or shear values (float) and create a zoom or shear matrix, respectively.\n\n      For \"matrix\" a **new copy** of another matrix will be made.\n\n      Float value \"degree\" specifies the creation of a rotation matrix which rotates anti-clockwise.\n\n      A \"sequence\" must be any Python sequence object with exactly 6 float entries (see :ref:`SequenceTypes`).\n\n      *pymupdf.Matrix(1, 1)* and *pymupdf.Matrix(pymupdf.Identity)* create modifiable versions of the :ref:`Identity` matrix, which looks like *[1, 0, 0, 1, 0, 0]*.\n\n   .. method:: norm()\n\n      * New in version 1.16.0\n      \n      Return the Euclidean norm of the matrix as a vector.\n\n   .. method:: prerotate(deg)\n\n      Modify the matrix to perform a counter-clockwise rotation for positive *deg* degrees, else clockwise. The matrix elements of an identity matrix will change in the following way:\n\n      *[1, 0, 0, 1, 0, 0] -> [cos(deg), sin(deg), -sin(deg), cos(deg), 0, 0]*.\n\n      :arg float deg: The rotation angle in degrees (use conventional notation based on Pi = 180 degrees).\n\n   .. method:: prescale(sx, sy)\n\n      Modify the matrix to scale by the zoom factors sx and sy. Has effects on attributes *a* thru *d* only: *[a, b, c, d, e, f] -> [a*sx, b*sx, c*sy, d*sy, e, f]*.\n\n      :arg float sx: Zoom factor in X direction. For the effect see description of attribute *a*.\n\n      :arg float sy: Zoom factor in Y direction. For the effect see description of attribute *d*.\n\n   .. method:: preshear(sx, sy)\n\n      Modify the matrix to perform a shearing, i.e. transformation of rectangles into parallelograms (rhomboids). Has effects on attributes *a* thru *d* only: *[a, b, c, d, e, f] -> [c*sy, d*sy, a*sx, b*sx, e, f]*.\n\n      :arg float sx: Shearing effect in X direction. See attribute *c*.\n\n      :arg float sy: Shearing effect in Y direction. See attribute *b*.\n\n   .. method:: pretranslate(tx, ty)\n\n      Modify the matrix to perform a shifting / translation operation along the x and / or y axis. Has effects on attributes *e* and *f* only: *[a, b, c, d, e, f] -> [a, b, c, d, tx*a + ty*c, tx*b + ty*d]*.\n\n      :arg float tx: Translation effect in X direction. See attribute *e*.\n\n      :arg float ty: Translation effect in Y direction. See attribute *f*.\n\n   .. method:: concat(m1, m2)\n\n      Calculate the matrix product *m1 * m2* and store the result in the current matrix. Any of *m1* or *m2* may be the current matrix. Be aware that matrix multiplication is not commutative. So the sequence of *m1*, *m2* is important.\n\n      :arg m1: First (left) matrix.\n      :type m1: :ref:`Matrix`\n\n      :arg m2: Second (right) matrix.\n      :type m2: :ref:`Matrix`\n\n   .. method:: invert(m = None)\n\n      Calculate the matrix inverse of *m* and store the result in the current matrix. Returns *1* if *m* is not invertible (\"degenerate\"). In this case the current matrix **will not change**. Returns *0* if *m* is invertible, and the current matrix is replaced with the inverted *m*.\n\n      :arg m: Matrix to be inverted. If not provided, the current matrix will be used.\n      :type m: :ref:`Matrix`\n\n      :rtype: int\n\n   .. attribute:: a\n\n      Scaling in X-direction **(width)**. For example, a value of 0.5 performs a shrink of the **width** by a factor of 2. If a < 0, a left-right flip will (additionally) occur.\n\n      :type: float\n\n   .. attribute:: b\n\n      Causes a shearing effect: each `Point(x, y)` will become `Point(x, y - b*x)`. Therefore, horizontal lines will be \"tilt\".\n\n      :type: float\n\n   .. attribute:: c\n\n      Causes a shearing effect: each `Point(x, y)` will become `Point(x - c*y, y)`. Therefore, vertical lines will be \"tilt\".\n\n      :type: float\n\n   .. attribute:: d\n\n      Scaling in Y-direction **(height)**. For example, a value of 1.5 performs a stretch of the **height** by 50%. If d < 0, an up-down flip will (additionally) occur.\n\n      :type: float\n\n   .. attribute:: e\n\n      Causes a horizontal shift effect: Each *Point(x, y)* will become *Point(x + e, y)*. Positive (negative) values of *e* will shift right (left).\n\n      :type: float\n\n   .. attribute:: f\n\n      Causes a vertical shift effect: Each *Point(x, y)* will become *Point(x, y - f)*. Positive (negative) values of *f* will shift down (up).\n\n      :type: float\n\n   .. attribute:: is_rectilinear\n\n      Rectilinear means that no shearing is present and that any rotations are integer multiples of 90 degrees. Usually this is used to confirm that (axis-aligned) rectangles before the transformation are still axis-aligned rectangles afterwards.\n\n      :type: bool\n\n.. note::\n\n   * This class adheres to the Python sequence protocol, so components can be accessed via their index, too. Also refer to :ref:`SequenceTypes`.\n   * Matrices can be used with arithmetic operators almost like ordinary numbers: they can be added, subtracted, multiplied or divided -- see chapter :ref:`Algebra`.\n   * Matrix multiplication is **not commutative** -- changing the sequence of the multiplicands will change the result in general. So it can quickly become unclear which result a transformation will yield.\n\n\nExamples\n-------------\nHere are examples that illustrate some of the achievable effects. All pictures show some text, inserted under control of some matrix and relative to a fixed reference point (the red dot).\n\n1. The :ref:`Identity` matrix performs no operation.\n\n.. image:: images/img-matrix-0.*\n   :scale: 66\n\n2. The scaling matrix `Matrix(2, 0.5)` stretches by a factor of 2 in horizontal, and shrinks by factor 0.5 in vertical direction.\n\n.. image:: images/img-matrix-1.*\n   :scale: 66\n\n3. Attributes :attr:`Matrix.e` and :attr:`Matrix.f` shift horizontally and, respectively vertically. In the following 10 to the right and 20 down.\n\n.. image:: images/img-matrix-2.*\n   :scale: 66\n\n4. A negative :attr:`Matrix.a` causes a left-right flip.\n\n.. image:: images/img-matrix-3.*\n   :scale: 66\n\n5. A negative :attr:`Matrix.d` causes an up-down flip.\n\n.. image:: images/img-matrix-4.*\n   :scale: 66\n\n6. Attribute :attr:`Matrix.b` tilts upwards / downwards along the x-axis.\n\n.. image:: images/img-matrix-5.*\n   :scale: 66\n\n7. Attribute :attr:`Matrix.c` tilts left / right along the y-axis.\n\n.. image:: images/img-matrix-6.*\n   :scale: 66\n\n8. Matrix `Matrix(beta)` performs counterclockwise rotations for positive angles `beta`.\n\n.. image:: images/img-matrix-7.*\n   :scale: 66\n\n9. Show some effects on a rectangle::\n\n      import pymupdf\n      \n      # just definitions and a temp PDF\n      RED = (1, 0, 0)\n      BLUE = (0, 0, 1)\n      GREEN = (0, 1, 0)\n      doc = pymupdf.open()\n      page = doc.new_page()\n      \n      # rectangle\n      r1 = pymupdf.Rect(100, 100, 200, 200)\n      \n      # scales down by 50% in x- and up by 50% in y-direction\n      mat1 = pymupdf.Matrix(0.5, 1.5)\n      \n      # shifts by 50 in both directions\n      mat2 = pymupdf.Matrix(1, 0, 0, 1, 50, 50)\n      \n      # draw corresponding rectangles\n      page.draw_rect(r1, color=RED)  # original\n      page.draw_rect(r1 * mat1, color=GREEN)  # scaled\n      page.draw_rect(r1 * mat2, color=BLUE)  # shifted\n      doc.ez_save(\"matrix-effects.pdf\")\n\n\n.. image:: images/img-matrix-9.*\n   :scale: 66\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/module.rst",
    "content": ".. include:: header.rst\n\n.. _Module:\n\n============================\nCommand line interface\n============================\n\n* New in version 1.16.8\n\nPyMuPDF can also be used from the command line to perform utility functions. This feature should obsolete writing some of the most basic scripts.\n\nAdmittedly, there is some functional overlap with the MuPDF CLI `mutool`. On the other hand, PDF embedded files are no longer supported by MuPDF, so PyMuPDF is offering something unique here.\n\nInvocation\n-----------\n\nThe command-line interface can be invoked in two ways.\n\n* Use the installed `pymupdf` command::\n\n    pymupdf <command and parameters>\n\n* Or use Python's `-m` switch with PyMuPDF's `pymupdf` module::\n\n    python -m pymupdf <command and parameters>\n\n\n.. highlight:: python\n\nGeneral remarks:\n\n* Request help via `\"-h\"`, resp. command-specific help via `\"command -h\"`.\n* Parameters may be abbreviated where this does not introduce ambiguities.\n* Several commands support parameters `-pages` and `-xrefs`. They are intended for down-selection. Please note that:\n\n    - **page numbers** for this utility must be given **1-based**.\n    - valid :data:`xref` numbers start at 1.\n    - Specify a comma-separated list of either *single* integers or integer *ranges*. A **range** is a pair of integers separated by one hyphen \"-\". Integers must not exceed the maximum page, resp. xref number. To specify that maximum, the symbolic variable \"N\" may be used. Integers or ranges may occur several times, in any sequence and may overlap. If in a range the first number is greater than the second one, the respective items will be processed in reversed order.\n\n* How to use the module inside your script::\n\n    >>> import pymupdf.__main__\n    >>> cmd = \"clean input.pdf output.pdf -pages 1,N\".split()  # prepare command line\n    >>> saved_parms = sys.argv[1:]  # save original command line\n    >>> sys.argv[1:] = cmd  # store new command line\n    >>> pymupdf.__main__.()  # execute module\n    >>> sys.argv[1:] = saved_parms  # restore original command line\n\n* Use the following 2-liner and compile it with `Nuitka <https://pypi.org/project/Nuitka/>`_ in standalone mode. This will give you a CLI executable with all the module's features, that can be used on all compatible platforms without Python, PyMuPDF or MuPDF being installed.\n\n::\n\n    from pymupdf.__main__ import main\n    main()\n\n\nCleaning and Copying\n----------------------\n\n.. highlight:: text\n\nThis command will optimize the PDF and store the result in a new file. You can use it also for encryption, decryption and creating sub documents. It is mostly similar to the MuPDF command line utility *\"mutool clean\"*::\n\n    pymupdf clean -h\n    usage: pymupdf clean [-h] [-password PASSWORD]\n                    [-encryption {keep,none,rc4-40,rc4-128,aes-128,aes-256}]\n                    [-owner OWNER] [-user USER] [-garbage {0,1,2,3,4}]\n                    [-compress] [-ascii] [-linear] [-permission PERMISSION]\n                    [-sanitize] [-pretty] [-pages PAGES]\n                    input output\n\n    -------------- optimize PDF or create sub-PDF if pages given --------------\n\n    positional arguments:\n    input                 PDF filename\n    output                output PDF filename\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -password PASSWORD    password\n    -encryption {keep,none,rc4-40,rc4-128,aes-128,aes-256}\n                          encryption method\n    -owner OWNER          owner password\n    -user USER            user password\n    -garbage {0,1,2,3,4}  garbage collection level\n    -compress             compress (deflate) output\n    -ascii                ASCII encode binary data\n    -linear               format for fast web display\n    -permission PERMISSION\n                          integer with permission levels\n    -sanitize             sanitize / clean contents\n    -pretty               prettify PDF structure\n    -pages PAGES          output selected pages, format: 1,5-7,50-N\n\nIf you specify \"-pages\", be aware that only page-related objects are copied, **no document-level items** like e.g. embedded files.\n\nPlease consult :meth:`Document.save` for the parameter meanings.\n\n\nExtracting Fonts and Images\n----------------------------\nExtract fonts or images from selected PDF pages to a desired directory::\n\n    pymupdf extract -h\n    usage: pymupdf extract [-h] [-images] [-fonts] [-output OUTPUT] [-password PASSWORD]\n                        [-pages PAGES]\n                        input\n\n    --------------------- extract images and fonts to disk --------------------\n\n    positional arguments:\n    input                 PDF filename\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -images               extract images\n    -fonts                extract fonts\n    -output OUTPUT        output directory, defaults to current\n    -password PASSWORD    password\n    -pages PAGES          only consider these pages, format: 1,5-7,50-N\n\n**Image filenames** are built according to the naming scheme: **\"img-xref.ext\"**, where \"ext\" is the extension associated with the image and \"xref\" the :data:`xref` of the image PDF object.\n\n**Font filenames** consist of the fontname and the associated extension. Any spaces in the fontname are replaced with hyphens \"-\".\n\nThe output directory must already exist.\n\n.. note:: Except for output directory creation, this feature is **functionally equivalent** to and obsoletes `this script <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_.\n\n\nJoining PDF Documents\n-----------------------\nTo join several PDF files specify::\n\n    pymupdf join -h\n    usage: pymupdf join [-h] -output OUTPUT [input [input ...]]\n\n    ---------------------------- join PDF documents ---------------------------\n\n    positional arguments:\n    input           input filenames\n\n    optional arguments:\n    -h, --help      show this help message and exit\n    -output OUTPUT  output filename\n\n    specify each input as 'filename[,password[,pages]]'\n\n\n.. note::\n\n    1. Each input must be entered as **\"filename,password,pages\"**. Password and pages are optional.\n    2. The password entry **is required** if the \"pages\" entry is used. If the PDF needs no password, specify two commas.\n    3. The **\"pages\"** format is the same as explained at the top of this section.\n    4. Each input file is immediately closed after use. Therefore you can use one of them as output filename, and thus overwrite it.\n\n\nExample: To join the following files\n\n1. **file1.pdf:** all pages, back to front, no password\n2. **file2.pdf:** last page, first page, password: \"secret\"\n3. **file3.pdf:** pages 5 to last, no password\n\nand store the result as **output.pdf** enter this command:\n\n``pymupdf join -o output.pdf file1.pdf,,N-1 file2.pdf,secret,N,1 file3.pdf,,5-N``\n\n\nLow Level Information\n----------------------\n\nDisplay PDF internal information. Again, there are similarities to *\"mutool show\"*::\n\n    pymupdf show -h\n    usage: pymupdf show [-h] [-password PASSWORD] [-catalog] [-trailer] [-metadata]\n                    [-xrefs XREFS] [-pages PAGES]\n                    input\n\n    ------------------------- display PDF information -------------------------\n\n    positional arguments:\n    input               PDF filename\n\n    optional arguments:\n    -h, --help          show this help message and exit\n    -password PASSWORD  password\n    -catalog            show PDF catalog\n    -trailer            show PDF trailer\n    -metadata           show PDF metadata\n    -xrefs XREFS        show selected objects, format: 1,5-7,N\n    -pages PAGES        show selected pages, format: 1,5-7,50-N\n\nExamples::\n\n    pymupdf show x.pdf\n    PDF is password protected\n\n    pymupdf show x.pdf -pass hugo\n    authentication unsuccessful\n\n    pymupdf show x.pdf -pass jorjmckie\n    authenticated as owner\n    file 'x.pdf', pages: 1, objects: 19, 58 MB, PDF 1.4, encryption: Standard V5 R6 256-bit AES\n    Document contains 15 embedded files.\n\n    pymupdf show FDA-1572_508_R6_FINAL.pdf -tr -m\n    'FDA-1572_508_R6_FINAL.pdf', pages: 2, objects: 1645, 1.4 MB, PDF 1.6, encryption: Standard V4 R4 128-bit AES\n    document contains 740 root form fields and is signed\n\n    ------------------------------- PDF metadata ------------------------------\n           format: PDF 1.6\n            title: FORM FDA 1572\n           author: PSC Publishing Services\n          subject: Statement of Investigator\n         keywords: None\n          creator: PScript5.dll Version 5.2.2\n         producer: Acrobat Distiller 9.0.0 (Windows)\n     creationDate: D:20130522104413-04'00'\n          modDate: D:20190718154905-07'00'\n       encryption: Standard V4 R4 128-bit AES\n\n    ------------------------------- PDF trailer -------------------------------\n    <<\n    /DecodeParms <<\n        /Columns 5\n        /Predictor 12\n    >>\n    /Encrypt 1389 0 R\n    /Filter /FlateDecode\n    /ID [ <9252E9E39183F2A0B0C51BE557B8A8FC> <85227BE9B84B724E8F678E1529BA8351> ]\n    /Index [ 1388 258 ]\n    /Info 1387 0 R\n    /Length 253\n    /Prev 1510559\n    /Root 1390 0 R\n    /Size 1646\n    /Type /XRef\n    /W [ 1 3 1 ]\n    >>\n\nEmbedded Files Commands\n------------------------\n\nThe following commands deal with embedded files -- which is a feature completely removed from MuPDF after v1.14, and hence from all its command line tools.\n\nInformation\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nShow the embedded file names (long or short format)::\n\n    pymupdf embed-info -h\n    usage: pymupdf embed-info [-h] [-name NAME] [-detail] [-password PASSWORD] input\n\n    --------------------------- list embedded files ---------------------------\n\n    positional arguments:\n    input               PDF filename\n\n    optional arguments:\n    -h, --help          show this help message and exit\n    -name NAME          if given, report only this one\n    -detail             show detail information\n    -password PASSWORD  password\n\nExample::\n\n    pymupdf embed-info some.pdf\n    'some.pdf' contains the following 15 embedded files.\n\n    20110813_180956_0002.jpg\n    20110813_181009_0003.jpg\n    20110813_181012_0004.jpg\n    20110813_181131_0005.jpg\n    20110813_181144_0006.jpg\n    20110813_181306_0007.jpg\n    20110813_181307_0008.jpg\n    20110813_181314_0009.jpg\n    20110813_181315_0010.jpg\n    20110813_181324_0011.jpg\n    20110813_181339_0012.jpg\n    20110813_181913_0013.jpg\n    insta-20110813_180944_0001.jpg\n    markiert-20110813_180944_0001.jpg\n    neue.datei\n\nDetailed output would look like this per entry::\n\n        name: neue.datei\n    filename: text-tester.pdf\n   ufilename: text-tester.pdf\n        desc: nur zum Testen!\n        size: 4639\n      length: 1566\n\nExtraction\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nExtract an embedded file like this::\n\n    pymupdf embed-extract -h\n    usage: pymupdf embed-extract [-h] -name NAME [-password PASSWORD] [-unsafe] [-output OUTPUT]\n                            input\n\n    ---------------------- extract embedded file to disk ----------------------\n\n    positional arguments:\n    input                 PDF filename\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -name NAME            name of entry\n    -password PASSWORD    password\n    -unsafe               allow write to stored name even if an existing file or outside current directory\n    -output OUTPUT        output filename, default is stored name\n\nFor details consult :meth:`Document.embfile_get`. Example (refer to previous section)::\n\n    pymupdf embed-extract some.pdf -name neue.datei\n    Saved entry 'neue.datei' as 'text-tester.pdf'\n\nDeletion\n~~~~~~~~~~~~~~~~~~~~~~~~\nDelete an embedded file like this::\n\n    pymupdf embed-del -h\n    usage: pymupdf embed-del [-h] [-password PASSWORD] [-output OUTPUT] -name NAME input\n\n    --------------------------- delete embedded file --------------------------\n\n    positional arguments:\n    input                 PDF filename\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -password PASSWORD    password\n    -output OUTPUT        output PDF filename, incremental save if none\n    -name NAME            name of entry to delete\n\nFor details consult :meth:`Document.embfile_del`.\n\nInsertion\n~~~~~~~~~~~~~~~~~~~~~~~~\nAdd a new embedded file using this command::\n\n    pymupdf embed-add -h\n    usage: pymupdf embed-add [-h] [-password PASSWORD] [-output OUTPUT] -name NAME -path\n                        PATH [-desc DESC]\n                        input\n\n    ---------------------------- add embedded file ----------------------------\n\n    positional arguments:\n    input                 PDF filename\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -password PASSWORD    password\n    -output OUTPUT        output PDF filename, incremental save if none\n    -name NAME            name of new entry\n    -path PATH            path to data for new entry\n    -desc DESC            description of new entry\n\n*\"NAME\"* **must not** already exist in the PDF. For details consult :meth:`Document.embfile_add`.\n\nUpdates\n~~~~~~~~~~~~~~~~~~~~~~~\nUpdate an existing embedded file using this command::\n\n    pymupdf embed-upd -h\n    usage: pymupdf embed-upd [-h] -name NAME [-password PASSWORD] [-output OUTPUT]\n                        [-path PATH] [-filename FILENAME] [-ufilename UFILENAME]\n                        [-desc DESC]\n                        input\n\n    --------------------------- update embedded file --------------------------\n\n    positional arguments:\n    input                 PDF filename\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -name NAME            name of entry\n    -password PASSWORD    password\n    -output OUTPUT        Output PDF filename, incremental save if none\n    -path PATH            path to new data for entry\n    -filename FILENAME    new filename to store in entry\n    -ufilename UFILENAME  new unicode filename to store in entry\n    -desc DESC            new description to store in entry\n\n    except '-name' all parameters are optional\n\nUse this method to change meta-information of the file -- just omit the *\"PATH\"*. For details consult :meth:`Document.embfile_upd`.\n\n\nCopying\n~~~~~~~~~~~~~~~~~~~~~~~\nCopy embedded files between PDFs::\n\n    pymupdf embed-copy -h\n    usage: pymupdf embed-copy [-h] [-password PASSWORD] [-output OUTPUT] -source\n                        SOURCE [-pwdsource PWDSOURCE]\n                        [-name [NAME [NAME ...]]]\n                        input\n\n    --------------------- copy embedded files between PDFs --------------------\n\n    positional arguments:\n    input                 PDF to receive embedded files\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -password PASSWORD    password of input\n    -output OUTPUT        output PDF, incremental save to 'input' if omitted\n    -source SOURCE        copy embedded files from here\n    -pwdsource PWDSOURCE  password of 'source' PDF\n    -name [NAME [NAME ...]]\n                          restrict copy to these entries\n\n\nText Extraction \n----------------\n* New in v1.18.16\n\nExtract text from arbitrary :ref:`supported documents<Supported_File_Types>` to a textfile. Currently, there are three output formatting modes available: simple, block sorting and reproduction of physical layout.\n\n* **Simple** text extraction reproduces all text as it appears in the document pages -- no effort is made to rearrange in any particular reading order.\n* **Block sorting** sorts text blocks (as identified by MuPDF) by ascending vertical, then horizontal coordinates. This should be sufficient to establish a \"natural\" reading order for basic pages of text.\n* **Layout** strives to reproduce the original appearance of the input pages. You can expect results like this (produced by the command `pymupdf gettext -pages 1 demo1.pdf`):\n\n.. image:: images/img-layout-text.*\n    :scale: 60\n\n.. note:: The \"gettext\" command offers a functionality similar to the CLI tool `pdftotext` by XPDF software, http://www.foolabs.com/xpdf/ -- this is especially true for \"layout\" mode, which combines that tool's `-layout` and `-table` options.\n\n\n\nAfter each page of the output file, a formfeed character, `hex(12)` is written -- even if the input page has no text at all. This behavior can be controlled via options.\n\n.. note:: For \"layout\" mode, **only horizontal, left-to-right, top-to bottom** text is supported, other text is ignored. In this mode, text is also ignored, if its :data:`fontsize` is too small.\n\n   \"Simple\" and \"blocks\" mode in contrast output **all text** for any text size or orientation.\n\nCommand::\n\n    pymupdf gettext -h\n    usage: pymupdf gettext [-h] [-password PASSWORD] [-mode {simple,blocks,layout}] [-pages PAGES] [-noligatures]\n                        [-convert-white] [-extra-spaces] [-noformfeed] [-skip-empty] [-output OUTPUT] [-grid GRID]\n                        [-fontsize FONTSIZE]\n                        input\n\n    ----------------- extract text in various formatting modes ----------------\n\n    positional arguments:\n    input                 input document filename\n\n    optional arguments:\n    -h, --help            show this help message and exit\n    -password PASSWORD    password for input document\n    -mode {simple,blocks,layout}\n                            mode: simple, block sort, or layout (default)\n    -pages PAGES          select pages, format: 1,5-7,50-N\n    -noligatures          expand ligature characters (default False)\n    -convert-white        convert whitespace characters to space (default False)\n    -extra-spaces         fill gaps with spaces (default False)\n    -noformfeed           write linefeeds, no formfeeds (default False)\n    -skip-empty           suppress pages with no text (default False)\n    -output OUTPUT        store text in this file (default inputfilename.txt)\n    -grid GRID            merge lines if closer than this (default 2)\n    -fontsize FONTSIZE    only include text with a larger :data:`fontsize` (default 3)\n\n.. note:: Command options may be abbreviated as long as no ambiguities are introduced. So the following do the same:\n\n    * `... -output text.txt -noligatures -noformfeed -convert-white -grid 3 -extra-spaces ...`\n    * `... -o text.txt -nol -nof -c -g 3 -e ...`\n\n  The output filename defaults to the input with its extension replaced by `.txt`. As with other commands, you can select page ranges **(caution: 1-based!)** in `mutool` format, as indicated above.\n\n* **mode:** (str) select a formatting mode -- default is \"layout\".\n* **noligatures:** (bool) corresponds to **not** :data:`TEXT_PRESERVE_LIGATURES`. If specified, ligatures (present in advanced fonts: glyphs combining multiple characters like \"fi\") are split up into their components (i.e. \"f\", \"i\"). Default is passing them through.\n* **convert-white:** corresponds to **not** :data:`TEXT_PRESERVE_WHITESPACE`. If specified, all white space characters (like tabs) are replaced with one or more spaces. Default is passing them through.\n* **extra-spaces:**  (bool) corresponds to **not** :data:`TEXT_INHIBIT_SPACES`. If specified, large gaps between adjacent characters will be filled with one or more spaces. Default is off.\n* **noformfeed:**  (bool) instead of `hex(12)` (formfeed), write linebreaks ``\\n`` at end of output pages.\n* **skip-empty:**  (bool) skip pages with no text.\n* **grid:** lines with a vertical coordinate difference of no more than this value (in points) will be merged into the same output line. Only relevant for \"layout\" mode. **Use with care:** 3 or the default 2 should be adequate in most cases. If **too large**, lines that are *intended* to be different in the original may be merged and will result in garbled and / or incomplete output. If **too low**, artifact separate output lines may be generated for some spans in the input line, just because they are coded in a different font with slightly deviating properties.\n* **fontsize:** include text with :data:`fontsize` larger than this value only (default 3). Only relevant for \"layout\" option.\n\n\n.. highlight:: python\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/ocr/tesseract-language-packs.rst",
    "content": "\n.. include:: ../header.rst\n\n.. _pymupdf-pro:\n\n.. raw:: html\n\n    <script>\n        document.getElementById(\"headerSearchWidget\").action = '../search.html';\n    </script>\n\n\n.. _tesseract-language-packs:\n\nTesseract Language Packs\n========================\n\n.. meta::\n   :description: How to install additional Tesseract language packs on macOS, Linux, and Windows.\n\nOverview\n--------\n\nTesseract identifies languages using three-letter `ISO 639-2 <https://en.wikipedia.org/wiki/List_of_ISO_639-2_codes>`_ codes. English (``eng``) is installed by default on most platforms. For any other language, you need to install the corresponding language pack before pymupdf4llm can use it for OCR.\n\nA full list of supported language codes is available on the `Tesseract tessdata repository <https://github.com/tesseract-ocr/tessdata>`_.\n\n.. tip::\n\n   To see which languages are already installed on your system, run ``tesseract --list-langs`` in your terminal.\n\n----\n\nLinux\n-----\n\nLanguage pack installation varies slightly by distribution.\n\n**Ubuntu / Debian**\n\n.. code-block:: bash\n\n   # List all available language packs\n   apt-cache search tesseract-ocr\n\n   # Install a specific language (e.g. German)\n   sudo apt install tesseract-ocr-deu\n\n   # Install all available languages at once\n   sudo apt install tesseract-ocr-all\n\nLanguage packages follow the naming pattern ``tesseract-ocr-<langcode>``, for example ``tesseract-ocr-fra`` for French or ``tesseract-ocr-chi-sim`` for Simplified Chinese.\n\n**Fedora / RHEL**\n\n.. code-block:: bash\n\n   # Search for available language packs\n   dnf search tesseract\n\n   # Install a specific language (e.g. German)\n   sudo dnf install tesseract-langpack-deu\n\n   # Install all language packs\n   sudo dnf install tesseract-langpack-*\n\nOn Fedora, packages are named ``tesseract-langpack-<langcode>``.\n\n**Arch Linux**\n\n.. code-block:: bash\n\n   # Search for available language packs\n   pacman -Ss tesseract-data\n\n   # Install a specific language (e.g. German)\n   sudo pacman -S tesseract-data-deu\n\nOn Arch, packages are named ``tesseract-data-<langcode>``.\n\nManual Installation (All Distros)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf a language pack is not available through your package manager, download the ``.traineddata`` file directly from GitHub and copy it to your Tesseract data directory:\n\n.. code-block:: bash\n\n   # Download language pack (e.g. French)\n   curl -L https://github.com/tesseract-ocr/tessdata/raw/main/fra.traineddata \\\n     -o fra.traineddata\n\n   # Copy to tessdata directory (path varies by distro)\n   sudo cp fra.traineddata /usr/share/tesseract-ocr/4.00/tessdata/\n   # or\n   sudo cp fra.traineddata /usr/share/tessdata/\n\nCommon tessdata locations on Linux:\n\n.. list-table::\n   :header-rows: 1\n   :widths: 40 60\n\n   * - Distribution\n     - Path\n   * - Ubuntu / Debian\n     - ``/usr/share/tesseract-ocr/4.00/tessdata/``\n   * - Fedora / RHEL\n     - ``/usr/share/tesseract/tessdata/``\n   * - Arch Linux\n     - ``/usr/share/tessdata/``\n\n----\n\nWindows\n-------\n\nDuring Installation (Recommended)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe Tesseract Windows installer from `UB Mannheim <https://github.com/UB-Mannheim/tesseract/wiki>`_ lets you select additional language packs during setup. When you reach the **Choose Components** screen, expand **Additional language data** and tick the languages you need.\n\nAfter Installation (Manual)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf Tesseract is already installed, download language packs manually:\n\n1. Go to `github.com/tesseract-ocr/tessdata <https://github.com/tesseract-ocr/tessdata>`_\n2. Download the ``.traineddata`` file for your language (e.g. ``fra.traineddata`` for French)\n3. Copy the file into your Tesseract ``tessdata`` folder, typically:\n\n.. code-block:: text\n\n   C:\\Program Files\\Tesseract-OCR\\tessdata\\\n\n.. note::\n\n   The Chocolatey (``choco install tesseract``) package only includes English. All additional languages must be added manually using the steps above.\n\nVerify the Install\n~~~~~~~~~~~~~~~~~~\n\nOpen Command Prompt or PowerShell and run:\n\n.. code-block:: powershell\n\n   tesseract --list-langs\n\nYour newly installed language should appear in the output.\n\n----\n\nmacOS\n-----\n\nThe recommended approach on macOS is `Homebrew <https://brew.sh>`_. There are two options depending on how much disk space you want to use.\n\nInstall All Languages at Once\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe ``tesseract-lang`` formula bundles Tesseract with every available language pack:\n\n.. code-block:: bash\n\n   brew install tesseract-lang\n\nInstall Specific Languages\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you only need a few languages, install ``tesseract`` first and then manually download the ``.traineddata`` files you need:\n\n.. code-block:: bash\n\n   # Install Tesseract engine only\n   brew install tesseract\n\n   # Find the tessdata directory\n   brew info tesseract\n   # Look for a line like: /opt/homebrew/share/tessdata\n\n   # Download a specific language pack (e.g. French)\n   curl -L https://github.com/tesseract-ocr/tessdata/raw/main/fra.traineddata \\\n     -o /opt/homebrew/share/tessdata/fra.traineddata\n\nReplace ``fra`` with your target language code and adjust the tessdata path to match what ``brew info tesseract`` reports on your machine.\n\n.. note::\n\n   If you installed Tesseract via MacPorts instead of Homebrew, use ``port install tesseract-<langcode>``, for example ``sudo port install tesseract-fra``.\n\n----\n\nUsing a Language with pymupdf4llm\n----------------------------------\n\nOnce a language pack is installed, pass its code to ``to_markdown()`` via the ``ocr_language`` parameter:\n\n.. code-block:: python\n\n   import pymupdf4llm\n\n   # Single language\n   md = pymupdf4llm.to_markdown(\"document.pdf\", ocr_language=\"fra\")\n\n   # Multiple languages\n   md = pymupdf4llm.to_markdown(\"document.pdf\", ocr_language=\"eng+fra+deu\")\n\n----\n\nCommon Language Codes\n---------------------\n\n.. list-table::\n   :header-rows: 1\n   :widths: 50 50\n\n   * - Language\n     - Code\n   * - English\n     - ``eng``\n   * - French\n     - ``fra``\n   * - German\n     - ``deu``\n   * - Spanish\n     - ``spa``\n   * - Italian\n     - ``ita``\n   * - Portuguese\n     - ``por``\n   * - Simplified Chinese\n     - ``chi_sim``\n   * - Traditional Chinese\n     - ``chi_tra``\n   * - Japanese\n     - ``jpn``\n   * - Korean\n     - ``kor``\n   * - Arabic\n     - ``ara``\n   * - Russian\n     - ``rus``\n   * - Hindi\n     - ``hin``\n\nFor the full list of supported languages and their codes, see the `Tesseract tessdata repository <https://github.com/tesseract-ocr/tessdata>`_.\n\n\n\n.. include:: ../footer.rst\n\n\n"
  },
  {
    "path": "docs/outline.rst",
    "content": ".. include:: header.rst\n\n.. _Outline:\n\n================\nOutline\n================\n\nThe document outline (otherwise known as \"bookmarks\") is a property of :ref:`Document` (see :attr:`Document.outline`). If not ``None``, it stands for the first outline item of the document. Its properties in turn define the characteristics of this item and also point to other outline items in \"horizontal\" or downward direction. The full tree of all outline items for e.g. a conventional table of contents (TOC) can be recovered by following these \"pointers\".\n\n============================ ==================================================\n**Method / Attribute**       **Short Description**\n============================ ==================================================\n:attr:`Outline.down`         next item downwards\n:attr:`Outline.next`         next item same level\n:attr:`Outline.page`         page number (0-based)\n:attr:`Outline.title`        title\n:attr:`Outline.uri`          string further specifying outline target\n:attr:`Outline.is_external`  target outside document\n:attr:`Outline.is_open`      whether sub-outlines are open or collapsed\n:attr:`Outline.dest`         points to destination details object\n============================ ==================================================\n\n**Class API**\n\n.. class:: Outline\n\n   .. attribute:: down\n\n      The next outline item on the next level down. Is ``None`` if the item has no children.\n\n      :type: :ref:`Outline`\n\n   .. attribute:: next\n\n      The next outline item at the same level as this item. Is ``None`` if this is the last one in its level.\n\n      :type: `Outline`\n\n   .. attribute:: page\n\n      The page number (0-based) this bookmark points to.\n\n      :type: int\n\n   .. attribute:: title\n\n      The item's title as a string or ``None``.\n\n      :type: str\n\n   .. attribute:: is_open\n\n      Indicator showing whether any sub-outlines should be expanded (``True``) or be collapsed (``False``). This information is interpreted by PDF reader software.\n\n      :type: bool\n\n   .. attribute:: is_external\n\n      A bool specifying whether the target is outside (``True``) of the current document.\n\n      :type: bool\n\n   .. attribute:: uri\n\n      A string specifying the link target. The meaning of this property should\n      be evaluated in conjunction with property `is_external`:\n      \n      *\n        `is_external` is true: ``uri`` points to some target outside the current\n        PDF, which may be an internet resource (``uri`` starts with ``http://`` or\n        similar), another file (``uri`` starts with ``file:`` or ``file://``) or some\n        other service like an e-mail address (``uri`` starts with ``mailto:``).\n\n      *\n        `is_external` is false: ``uri`` will be `None` or point to an\n        internal location. In case of PDF documents, this should either be\n        *#nnnn* to indicate a 1-based (!) page number *nnnn*, or a named\n        location. The format varies for other document types, for example\n        \"../FixedDoc.fdoc#PG_2_LNK_1\" for page number 2 (1-based) in an XPS\n        document.\n\n      :type: str\n\n   .. attribute:: dest\n\n      The link destination details object.\n\n      :type: :ref:`linkDest`\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/packaging.rst",
    "content": ".. include:: header.rst\n\n\nPackaging for Linux distributions\n=================================\n\n\nRequirements\n------------\n\n* Python\n* MuPDF checkout (including submodules).\n* PyMuPDF checkout.\n* System packages listed in `scripts/sysinstall.py:g_sys_packages`.\n* Python packages listed in `pyproject.toml`.\n\nExtra requirements for running tests:\n\n* Python packages listed in `scripts/gh_release.py:test_packages`.\n\n\nGeneral steps\n-------------\n\n* Build and install MuPDF:\n  \n  * Install required system packages.\n  * Run `make install-shared-python` on MuPDF's `Makefile` with at least\n    these make variables:\n  \n    * `DESTDIR` set to the install directory, e.g. `/`.\n    *\n      `prefix` set to location relative to DESTDIR, such as `/usr/local` or\n      `/usr`. Must start with `/`.\n    * `USE_SYSTEM_LIBS=yes`.\n    * `HAVE_LEPTONICA=yes`.\n    * `HAVE_TESSERACT=yes`.\n\n* Build and install PyMuPDF:\n\n  *\n    Run `pip install ./PyMuPDF` or `pip wheel ./PyMuPDF` with at least these\n    environment variables:\n    \n    *\n      `PYMUPDF_SETUP_MUPDF_BUILD=` (empty string) to prevent download and build\n      of hard-coded MuPDF release.\n    *\n      `CFLAGS`, `CXXFLAGS` and `LDFLAGS` set to allow visibility of the\n      installed MuPDF headers and shared libraries.\n\n* Run PyMuPDF tests:\n\n  * Ensure required Python packages are available.\n  *\n    Run `pytest -k \"not test_color_count and not test_3050\" PyMuPDF`\n    \n    * Test `test_color_count` is known fail if MuPDF is not built with PyMuPDF's custom config.h.\n    * Test `test_3050` is known to fail if MuPDF is built without its own third-party libraries.\n\n\nUse of scripts/sysinstall.py\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n`scripts/sysinstall.py` provides a useful example of build, install and test\ncommands that are known to to work, because it is run regularly by Github\naction `.github/workflows/test_sysinstall.yml`.\n\n* Run with `-h` or look at the doc-string to see detailed usage information.\n* It uses Debian-style `apt` commands to install system packages.\n* By default it assumes local git checkouts `mupdf/` and `PyMuPDF/`.\n\nTo run a full build, install and test for both a local fake root and the system\nroot:\n\n.. code-block:: shell\n\n    ./PyMuPDF/scripts/sysinstall.py\n    ./PyMuPDF/scripts/sysinstall.py --root /\n\nTo see what commands would be run without actually running them:\n\n.. code-block:: shell\n\n    ./PyMuPDF/scripts/sysinstall.py -m 0 -p 0 -t 0\n\n\nSee also\n--------\n\n*\n  `setup.py`'s initial doc-comment has detailed information about the\n  environment variables used when building PyMuPDF.\n"
  },
  {
    "path": "docs/page.rst",
    "content": ".. include:: header.rst\n\n.. _Page:\n\n================\nPage\n================\n\nClass representing a document page. A page object is created by :meth:`Document.load_page` or, equivalently, via indexing the document like `doc[n]` - it has no independent constructor.\n\nThere is a parent-child relationship between a document and its pages. If the document is closed or deleted, all page objects (and their respective children, too) in existence will become unusable (\"orphaned\"): If a page property or method is being used, an exception is raised.\n\nSeveral page methods have a :ref:`Document` counterpart for convenience. At the end of this chapter you will find a synopsis.\n\n.. note:: Many times in this chapter we are using the term **coordinate**. It is of high importance to have at least a basic understanding of what that is and that you feel comfortable with the section :ref:`Coordinates`.\n\nModifying Pages\n---------------\nChanging page properties and adding or changing page content is available for PDF documents only.\n\nIn a nutshell, this is what you can do with PyMuPDF:\n\n* Modify page rotation and the visible part (\"cropbox\") of the page.\n* Insert images, other PDF pages, text and simple geometrical objects.\n* Add annotations and form fields.\n\n.. note::\n\n   Methods require coordinates (points, rectangles) to put content in desired places. Please be aware that these coordinates **must always** be provided relative to the **unrotated** page (since v1.17.0). The reverse is also true: except :attr:`Page.rect`, resp. :meth:`Page.bound` (both *reflect* when the page is rotated), all coordinates returned by methods and attributes pertain to the unrotated page.\n\n   So the returned value of e.g. :meth:`Page.get_image_bbox` will not change if you do a :meth:`Page.set_rotation`. The same is true for coordinates returned by :meth:`Page.get_text`, annotation rectangles, and so on. If you want to find out, where an object is located in **rotated coordinates**, multiply the coordinates with :attr:`Page.rotation_matrix`. There also is its inverse, :attr:`Page.derotation_matrix`, which you can use when interfacing with other readers, which may behave differently in this respect.\n\n.. note::\n\n   If you add or update annotations, links or form fields on the page and immediately afterwards need to work with them (i.e. **without leaving the page**), you should reload the page using :meth:`Document.reload_page` before referring to these new or updated items.\n\n   Reloading the page is generally recommended -- although not strictly required in all cases. However, some annotation and widget types have extended features in PyMuPDF compared to MuPDF. More of these extensions may also be added in the future.\n\n   Releoading the page ensures all your changes have been fully applied to PDF structures, so you can safely create Pixmaps or successfully iterate over annotations, links and form fields.\n\n================================== =======================================================\n**Method / Attribute**             **Short Description**\n================================== =======================================================\n:meth:`Page.add_caret_annot`       PDF only: add a caret annotation\n:meth:`Page.add_circle_annot`      PDF only: add a circle annotation\n:meth:`Page.add_file_annot`        PDF only: add a file attachment annotation\n:meth:`Page.add_freetext_annot`    PDF only: add a text annotation\n:meth:`Page.add_highlight_annot`   PDF only: add a \"highlight\" annotation\n:meth:`Page.add_ink_annot`         PDF only: add an ink annotation\n:meth:`Page.add_line_annot`        PDF only: add a line annotation\n:meth:`Page.add_polygon_annot`     PDF only: add a polygon annotation\n:meth:`Page.add_polyline_annot`    PDF only: add a multi-line annotation\n:meth:`Page.add_rect_annot`        PDF only: add a rectangle annotation\n:meth:`Page.add_redact_annot`      PDF only: add a redaction annotation\n:meth:`Page.add_squiggly_annot`    PDF only: add a \"squiggly\" annotation\n:meth:`Page.add_stamp_annot`       PDF only: add a \"rubber stamp\" annotation\n:meth:`Page.add_strikeout_annot`   PDF only: add a \"strike-out\" annotation\n:meth:`Page.add_text_annot`        PDF only: add a comment\n:meth:`Page.add_underline_annot`   PDF only: add an \"underline\" annotation\n:meth:`Page.add_widget`            PDF only: add a PDF Form field\n:meth:`Page.annot_names`           PDF only: a list of annotation (and widget) names\n:meth:`Page.annot_xrefs`           PDF only: a list of annotation (and widget) xrefs\n:meth:`Page.annots`                return a generator over the annots on the page\n:meth:`Page.apply_redactions`      PDF only: process the redactions of the page\n:meth:`Page.clip_to_rect`          PDF only: remove page content outside a rectangle\n:meth:`Page.bound`                 rectangle of the page\n:meth:`Page.cluster_drawings`      PDF only: bounding boxes of vector graphics\n:meth:`Page.delete_annot`          PDF only: delete an annotation\n:meth:`Page.delete_image`          PDF only: delete an image\n:meth:`Page.delete_link`           PDF only: delete a link\n:meth:`Page.delete_widget`         PDF only: delete a widget / field\n:meth:`Page.draw_bezier`           PDF only: draw a cubic Bezier curve\n:meth:`Page.draw_circle`           PDF only: draw a circle\n:meth:`Page.draw_curve`            PDF only: draw a special Bezier curve\n:meth:`Page.draw_line`             PDF only: draw a line\n:meth:`Page.draw_oval`             PDF only: draw an oval / ellipse\n:meth:`Page.draw_polyline`         PDF only: connect a point sequence\n:meth:`Page.draw_quad`             PDF only: draw a quad\n:meth:`Page.draw_rect`             PDF only: draw a rectangle\n:meth:`Page.draw_sector`           PDF only: draw a circular sector\n:meth:`Page.draw_squiggle`         PDF only: draw a squiggly line\n:meth:`Page.draw_zigzag`           PDF only: draw a zig-zagged line\n:meth:`Page.find_tables`           locate tables on the page\n:meth:`Page.get_drawings`          get vector graphics on page\n:meth:`Page.get_fonts`             PDF only: get list of referenced fonts\n:meth:`Page.get_image_bbox`        PDF only: get bbox and matrix of embedded image\n:meth:`Page.get_image_info`        get list of meta information for all used images\n:meth:`Page.get_image_rects`       PDF only: improved version of :meth:`Page.get_image_bbox`\n:meth:`Page.get_images`            PDF only: get list of referenced images\n:meth:`Page.get_label`             PDF only: return the label of the page\n:meth:`Page.get_links`             get all links\n:meth:`Page.get_pixmap`            create a page image in raster format\n:meth:`Page.get_svg_image`         create a page image in SVG format\n:meth:`Page.get_text`              extract the page's text\n:meth:`Page.get_textbox`           extract text contained in a rectangle\n:meth:`Page.get_textpage_ocr`      create a TextPage with OCR for the page\n:meth:`Page.get_textpage`          create a TextPage for the page\n:meth:`Page.get_xobjects`          PDF only: get list of referenced xobjects\n:meth:`Page.insert_font`           PDF only: insert a font for use by the page\n:meth:`Page.insert_image`          PDF only: insert an image\n:meth:`Page.insert_link`           PDF only: insert a link\n:meth:`Page.insert_text`           PDF only: insert text\n:meth:`Page.insert_htmlbox`        PDF only: insert html text in a rectangle\n:meth:`Page.insert_textbox`        PDF only: insert a text box\n:meth:`Page.links`                 return a generator of the links on the page\n:meth:`Page.load_annot`            PDF only: load a specific annotation\n:meth:`Page.load_widget`           PDF only: load a specific field\n:meth:`Page.load_links`            return the first link on a page\n:meth:`Page.new_shape`             PDF only: create a new :ref:`Shape`\n:meth:`Page.recolor`               PDF only: change the colorspace of objects\n:meth:`Page.remove_rotation`       PDF only: set page rotation to 0\n:meth:`Page.replace_image`         PDF only: replace an image\n:meth:`Page.search_for`            search for a string\n:meth:`Page.set_artbox`            PDF only: modify `/ArtBox`\n:meth:`Page.set_bleedbox`          PDF only: modify `/BleedBox`\n:meth:`Page.set_cropbox`           PDF only: modify the :data:`cropbox` (visible page)\n:meth:`Page.set_mediabox`          PDF only: modify `/MediaBox`\n:meth:`Page.set_rotation`          PDF only: set page rotation\n:meth:`Page.set_trimbox`           PDF only: modify `/TrimBox`\n:meth:`Page.show_pdf_page`         PDF only: display PDF page image\n:meth:`Page.update_link`           PDF only: modify a link\n:meth:`Page.widgets`               return a generator over the fields on the page\n:meth:`Page.write_text`            write one or more :ref:`Textwriter` objects\n:attr:`Page.cropbox_position`      displacement of the :data:`cropbox`\n:attr:`Page.cropbox`               the page's :data:`cropbox`\n:attr:`Page.artbox`                the page's `/ArtBox`\n:attr:`Page.bleedbox`              the page's `/BleedBox`\n:attr:`Page.trimbox`               the page's `/TrimBox`\n:attr:`Page.derotation_matrix`     PDF only: get coordinates in unrotated page space\n:attr:`Page.first_annot`           first :ref:`Annot` on the page\n:attr:`Page.first_link`            first :ref:`Link` on the page\n:attr:`Page.first_widget`          first widget (form field) on the page\n:attr:`Page.mediabox_size`         bottom-right point of :data:`mediabox`\n:attr:`Page.mediabox`              the page's :data:`mediabox`\n:attr:`Page.number`                page number\n:attr:`Page.parent`                owning document object\n:attr:`Page.rect`                  rectangle of the page\n:attr:`Page.rotation_matrix`       PDF only: get coordinates in rotated page space\n:attr:`Page.rotation`              PDF only: page rotation\n:attr:`Page.transformation_matrix` PDF only: translate between PDF and MuPDF space\n:attr:`Page.xref`                  PDF only: page :data:`xref`\n================================== =======================================================\n\n**Class API**\n\n.. class:: Page\n\n   .. method:: bound()\n\n      Determine the rectangle of the page. Same as property :attr:`Page.rect`. For PDF documents this **usually** also coincides with :data:`mediabox` and :data:`cropbox`, but not always. For example, if the page is rotated, then this is reflected by this method -- the :attr:`Page.cropbox` however will not change.\n\n      :rtype: :ref:`Rect`\n\n   .. method:: add_caret_annot(point)\n\n      PDF only: Add a caret icon. A caret annotation is a visual symbol normally used to indicate the presence of text edits on the page.\n\n      :arg point_like point: the top left point of a 20 x 20 rectangle containing the MuPDF-provided icon.\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation. Stroke color blue = (0, 0, 1), no fill color support.\n\n      .. image:: images/img-caret-annot.*\n         :scale: 70\n\n      |history_begin|\n\n      * New in v1.16.0\n\n      |history_end|\n\n   .. method:: add_text_annot(point, text, icon=\"Note\")\n\n      PDF only: Add a comment icon (\"sticky note\") with accompanying text. Only the icon is visible, the accompanying text is hidden and can be visualized by many PDF viewers by hovering the mouse over the symbol.\n\n      :arg point_like point: the top left point of a 20 x 20 rectangle containing the MuPDF-provided \"note\" icon.\n\n      :arg str text: the commentary text. This will be shown on double clicking or hovering over the icon. May contain any Latin characters.\n      :arg str icon: choose one of \"Note\" (default), \"Comment\", \"Help\", \"Insert\", \"Key\", \"NewParagraph\", \"Paragraph\" as the visual symbol for the embodied text [#f4]_. (New in v1.16.0)\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation. Stroke color yellow = (1, 1, 0), no fill color support.\n\n   .. index::\n      pair: rect; add_freetext_annot\n      pair: fontsize; add_freetext_annot\n      pair: fontname; add_freetext_annot\n      pair: text_color; add_freetext_annot\n      pair: fill_color; add_freetext_annot\n      pair: border_width; add_freetext_annot\n      pair: dashes; add_freetext_annot\n      pair: callout; add_freetext_annot\n      pair: line_end; add_freetext_annot\n      pair: opacity; add_freetext_annot\n      pair: align; add_freetext_annot\n      pair: rotate; add_freetext_annot\n      pair: richtext; add_freetext_annot\n      pair: style; add_freetext_annot\n\n   .. method:: add_freetext_annot(rect, text, *, fontsize=11, fontname=\"helv\", text_color=0, fill_color=None, border_width=0, dashes=None, callout=None, line_end=PDF_ANNOT_LE_OPEN_ARROW, opacity=1, align=TEXT_ALIGN_LEFT, rotate=0, richtext=False, style=None)\n\n      PDF only: Add text in a given rectangle. Optionally, the appearance of a \"callout\" shape can be requested by specifying two or three point-like objects -- see below.\n\n      :arg rect_like rect: the rectangle into which the text should be inserted. Text is automatically wrapped to a new line at box width. Text portions not fitting into the rectangle will be invisible without warning.\n\n      :arg str text: the text. May contain any mixture of Latin, Greek, Cyrillic, Chinese, Japanese and Korean characters. If `richtext=True` (see below), the string is interpreted as HTML syntax. This adds a plethora of ways for attractive effects.\n\n      :arg float fontsize: the :data:`fontsize`. Default is 11. Ignored if `richtext=True`.\n\n      :arg str fontname: The font name. Default is \"Helv\". Ignored if `richtext=True`, otherwise the following **restritions apply:**\n        \n        * Accepted alternatives are \"Helv\" (Helvetica), \"Cour\" (Courier), \"TiRo\" (Timnes-Roman), \"ZaDb\" (ZapfDingBats) and \"Symb\" (Symbol). The name may be abbreviated to the first two characters, like \"Co\" for \"Cour\", lower case accepted.\n\n        * Bold or italic variants of the fonts are **not supported.**\n        \n      :arg list,tuple,float text_color: the text color. Default is black. Ignored if `richtext=True`.\n\n      :arg list,tuple,float fill_color: the fill color. This is used for ``rect`` and the end point of the callout lines when applicable. Default is ``None``.\n\n      :arg list,tuple,float border_color:  This parameter **only has an effect** if `richtext=True`. Otherwise, ``text_color`` is used.\n      \n      :arg float border_width: the width of border and ``callout`` lines. Default is 0 (no border), in which case callout lines may still appear with some hairline width, depending on the PDF viewer used. In any case, this value must be positive to see a border line.\n      \n      :arg list,tuple dashes: a list of floats specifying how border and callout lines should be dashed. Default is ``None``.\n      \n      :arg list,tuple callout: a list / tuple of two or three :data:`point_like` objects, which will be interpreted as end point [, knee point] and start point (in this sequence) of up to two line segments, converting this annotation into a call-out shape.\n      \n      :arg int line_end: the line end symbol of the call-out line. It is drawn at the first point specified in the `callout` list. Default is an open arrow. For possible values see :ref:`AnnotationLineEnds`.\n      \n      :arg float opacity: a float `0 <= opacity < 1` turning the annotation transparent. Default is no transparency.\n      \n      :arg int align: text alignment, one of TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT - justify is **not supported**. Ignored if `richtext=True`.\n      \n      :arg int rotate: the text orientation. Accepted values are integer multiples of 90°. Invalid entries receive a rotation of 0.\n      \n      :arg bool richtext: treat ``text`` as HTML syntax. This allows to achieve **bold**, *italic*, arbitrary text colors, font sizes, text alignment including justify and more - as far as the PDF subset of HTML and styling instructions supports this. This is similar to what happens in :meth:`Page.insert_htmlbox`. The base library will for example pull in required fonts if it encounters characters not contained in the standard ones. Some parameters are ignored if this option is set, as mentioned above. Default is ``False``.\n      \n      :arg str style: supply optional HTML styling information in CSS syntax. Ignored if `richtext=False`.\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation.\n\n      |history_begin|\n\n      * Changed in v1.19.6: add border color parameter\n\n      |history_end|\n\n   .. method:: add_file_annot(point, buffer_, filename, ufilename=None, desc=None, icon=\"PushPin\")\n\n      PDF only: Add a file attachment annotation with a \"PushPin\" icon at the specified location.\n\n      :arg point_like pos: the top-left point of a 18x18 rectangle containing the MuPDF-provided \"PushPin\" icon.\n\n      :arg bytes,bytearray,BytesIO buffer: the data to be stored (actual file content, any data, etc.).\n\n         Changed in v1.14.13: *io.BytesIO* is now also supported.\n\n      :arg str filename: the filename to associate with the data.\n      :arg str ufilename: the optional PDF unicode version of filename. Defaults to filename.\n      :arg str desc: an optional description of the file. Defaults to filename.\n      :arg str icon: choose one of \"PushPin\" (default), \"Graph\", \"Paperclip\", \"Tag\" as the visual symbol for the attached data [#f4]_. (New in v1.16.0)\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation.  Stroke color yellow = (1, 1, 0), no fill color support.\n\n   .. method:: add_ink_annot(list)\n\n      PDF only: Add a \"freehand\" scribble annotation.\n\n      :arg sequence list: a list of one or more lists, each containing :data:`point_like` items. Each item in these sublists is interpreted as a :ref:`Point` through which a connecting line is drawn. Separate sublists thus represent separate drawing lines.\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation in default appearance black =(0, 0, 0),line width 1. No fill color support.\n\n   .. method:: add_line_annot(p1, p2)\n\n      PDF only: Add a line annotation.\n\n      :arg point_like p1: the starting point of the line.\n\n      :arg point_like p2: the end point of the line.\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation. It is drawn with line (stroke) color red = (1, 0, 0) and line width 1. No fill color support. The **annot rectangle** is automatically created to contain both points, each one surrounded by a circle of radius 3 * line width to make room for any line end symbols.\n\n   .. method:: add_rect_annot(rect)\n\n   .. method:: add_circle_annot(rect)\n\n      PDF only: Add a rectangle, resp. circle annotation.\n\n      :arg rect_like rect: the rectangle in which the circle or rectangle is drawn, must be finite and not empty. If the rectangle is not equal-sided, an ellipse is drawn.\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation. It is drawn with line (stroke) color red = (1, 0, 0), line width 1, fill color is supported.\n\n   ---------\n\n   Redactions\n   ~~~~~~~~~~~\n\n   .. method:: add_redact_annot(quad, text=None, fontname=None, fontsize=11, align=TEXT_ALIGN_LEFT, fill=(1, 1, 1), text_color=(0, 0, 0), cross_out=True)\n      \n      **PDF only**: Add a redaction annotation. A redaction annotation identifies an area whose content should be removed from the document. Adding such an annotation is the first of two steps. It makes visible what will be removed in the subsequent step, :meth:`Page.apply_redactions`.\n\n      :arg quad_like,rect_like quad: specifies the (rectangular) area to be removed which is always equal to the annotation rectangle. This may be a :data:`rect_like` or :data:`quad_like` object. If a quad is specified, then the enveloping rectangle is taken.\n\n      :arg str text: text to be placed in the rectangle after applying the redaction (and thus removing old content). (New in v1.16.12)\n\n      :arg str fontname: the font to use when ``text`` is given, otherwise ignored. Only CJK and the :ref:`Base-14-Fonts` are supported. Apart from this, the same rules apply as for :meth:`Page.insert_textbox` -- which is what the method :meth:`Page.apply_redactions` internally invokes. \n\n      :arg float fontsize: the :data:`fontsize` to use for the replacing text. If the text is too large to fit, several insertion attempts will be made, gradually reducing the :data:`fontsize` to no less than 4. If then the text will still not fit, no text insertion will take place at all. (New in v1.16.12)\n\n      :arg int align: the horizontal alignment for the replacing text. See :meth:`insert_textbox` for available values. The vertical alignment is (approximately) centered.\n\n      :arg sequence fill: the fill color of the rectangle **after applying** the redaction. The default is *white = (1, 1, 1)*, which is also taken if ``None`` is specified. To suppress a fill color altogether, specify ``False``. In this cases the rectangle remains transparent. (New in v1.16.12)\n\n      :arg sequence text_color: the color of the replacing text. Default is *black = (0, 0, 0)*. (New in v1.16.12)\n\n      :arg bool cross_out: add two diagonal lines to the annotation rectangle. (New in v1.17.2)\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation. Its standard appearance looks like a red rectangle (no fill color), optionally showing two diagonal lines. Colors, line width, dashing, opacity and blend mode can now be set and applied via :meth:`Annot.update` like with other annotations. (Changed in v1.17.2)\n\n      .. image:: images/img-redact.*\n\n      |history_begin|\n\n      * New in v1.16.11\n\n      |history_end|\n\n\n   .. method:: apply_redactions(images=PDF_REDACT_IMAGE_PIXELS|2, graphics=PDF_REDACT_LINE_ART_REMOVE_IF_COVERED|1, text=PDF_REDACT_TEXT_REMOVE|0)\n\n      **PDF only**: Remove all **content** contained in any redaction rectangle on the page.\n\n      **This method applies and then deletes all redactions from the page.**\n\n      :arg int images: How to redact overlapping images. The default `PDF_REDACT_IMAGE_PIXELS | 2` blanks out overlapping pixels. `PDF_REDACT_IMAGE_NONE | 0` ignores, and `PDF_REDACT_IMAGE_REMOVE | 1` completely removes images overlapping any redaction annotation. Option `PDF_REDACT_IMAGE_REMOVE_UNLESS_INVISIBLE | 3` only removes images that are actually visible.\n\n      :arg int graphics: How to redact overlapping vector graphics (also called \"line-art\" or \"drawings\"). The default `PDF_REDACT_LINE_ART_REMOVE_IF_COVERED | 1` removes any overlapping vector graphics. `PDF_REDACT_LINE_ART_NONE | 0` ignores, and `PDF_REDACT_LINE_ART_REMOVE_IF_TOUCHED | 2` removes graphics fully contained in a redaction annotation. When removing line-art, please be aware that **stroked** vector graphics (i.e. type \"s\" or \"sf\") have a **larger wrapping rectangle** than one might expect: first of all, at least 50% of the path's line width have to be added in each direction to truly include all of the drawing. If a so-called \"miter limit\" is provided (see page 121 of the PDF specification), the enlarging value is `miter * width / 2`. So, when letting everything default (width = 1, miter = 10), the redaction rectangle should be at least 5 points larger in every direction.\n\n      :arg int text: Whether to redact overlapping text. The default `PDF_REDACT_TEXT_REMOVE | 0` removes all characters whose boundary box overlaps any redaction rectangle. This complies with the original legal / data protection intentions of redaction annotations. Other use cases however may require to **keep text** while redacting vector graphics or images. This can be achieved by setting `text=True|PDF_REDACT_TEXT_NONE | 1`. This does **not comply** with the data protection intentions of redaction annotations. **Do so at your own risk.**\n\n      :returns: `True` if at least one redaction annotation has been processed, `False` otherwise.\n\n      .. note::\n         * Text contained in a redaction rectangle will be **physically** removed from the page (assuming :meth:`Document.save` with a suitable garbage option) and will no longer appear in e.g. text extractions or anywhere else. All redaction annotations will also be removed. Other annotations are unaffected.\n\n         * All overlapping links will be removed. If the rectangle of the link was covering text, then only the overlapping part of the text is being removed. Similar applies to images covered by link rectangles.\n\n         * The overlapping parts of **images** will be blanked-out for default option `PDF_REDACT_IMAGE_PIXELS` (changed in v1.18.0). Option 0 does not touch any images and 1 will remove any image with an overlap.\n\n         * For option `images=PDF_REDACT_IMAGE_REMOVE` only this page's **references to the images** are removed - not necessarily the images themselves. Images are completely removed from the file only, if no longer referenced at all (assuming suitable garbage collection options).\n\n         * For option `images=PDF_REDACT_IMAGE_PIXELS` a new image of format PNG is created, which the page will use in place of the original one. The original image is not deleted or replaced as part of this process, so other pages may still show the original. In addition, the new, modified PNG image currently is **stored uncompressed**. Do keep these aspects in mind when choosing the right garbage collection method and compression options during save.\n\n         * **Text removal** is done by character: A character is removed if its bbox has a **non-empty overlap** with a redaction rectangle (changed in MuPDF v1.17). Depending on the font properties and / or the chosen line height, deletion may occur for undesired text parts. Using :meth:`Tools.set_small_glyph_heights` with a ``True`` argument before text search may help to prevent this.\n\n         * Redactions are a simple way to replace single words in a PDF, or to just physically remove them. Locate the word \"secret\" using some text extraction or search method and insert a redaction using \"xxxxxx\" as replacement text for each occurrence.\n\n           - Be wary if the replacement is longer than the original -- this may lead to an awkward appearance, line breaks or no new text at all.\n\n           - For a number of reasons, the new text may not exactly be positioned on the same line like the old one -- especially true if the replacement font was not one of CJK or :ref:`Base-14-Fonts`.\n\n      |history_begin|\n\n      * New in v1.16.11\n      * Changed in v1.16.12: The previous *mark* parameter is gone. Instead, the respective rectangles are filled with the individual *fill* color of each redaction annotation. If a *text* was given in the annotation, then :meth:`insert_textbox` is invoked to insert it, using parameters provided with the redaction.\n      * Changed in v1.18.0: added option for handling images that overlap redaction areas.\n      * Changed in v1.23.27: added option for removing graphics as well.\n      * Changed in v1.24.2: added option `keep_text` to leave text untouched.\n\n      |history_end|\n\n      ---------\n\n   .. method:: add_polyline_annot(points)\n\n   .. method:: add_polygon_annot(points)\n\n      PDF only: Add an annotation consisting of lines which connect the given points. A **Polygon's** first and last points are automatically connected, which does not happen for a **PolyLine**. The **rectangle** is automatically created as the smallest rectangle containing the points, each one surrounded by a circle of radius 3 (= 3 * line width). The following shows a 'PolyLine' that has been modified with colors and line ends.\n\n      :arg list points: a list of :data:`point_like` objects.\n\n      :rtype: :ref:`Annot`\n      :returns: the created annotation. It is drawn with line color black, line width 1 no fill color but fill color support. Use methods of :ref:`Annot` to make any changes to achieve something like this:\n\n      .. image:: images/img-polyline.*\n         :scale: 70\n\n   .. method:: add_underline_annot(quads=None, start=None, stop=None, clip=None)\n\n   .. method:: add_strikeout_annot(quads=None, start=None, stop=None, clip=None)\n\n   .. method:: add_squiggly_annot(quads=None, start=None, stop=None, clip=None)\n\n   .. method:: add_highlight_annot(quads=None, start=None, stop=None, clip=None)\n\n      PDF only: These annotations are normally used for **marking text** which has previously been somehow located (for example via :meth:`Page.search_for`). But this is not required: you are free to \"mark\" just anything.\n\n      Standard (stroke only -- no fill color support) colors are chosen per annotation type: **yellow** for highlighting, **red** for striking out, **green** for underlining, and **magenta** for wavy underlining.\n\n      All these four methods convert the arguments into a list of :ref:`Quad` objects. The **annotation** rectangle is then calculated to envelop all these quadrilaterals.\n\n      .. note::\n\n        :meth:`search_for` delivers a list of either :ref:`Rect` or :ref:`Quad` objects. Such a list can be directly used as an argument for these annotation types and will deliver **one common annotation** for all occurrences of the search string::\n\n           >>> # prefer quads=True in text searching for annotations!\n           >>> quads = page.search_for(\"pymupdf\", quads=True)\n           >>> page.add_highlight_annot(quads)\n\n      .. note::\n        Obviously, text marker annotations need to know what is the top, the bottom, the left, and the right side of the area(s) to be marked. If the arguments are quads, this information is given by the sequence of the quad points. In contrast, a rectangle delivers much less information -- this is illustrated by the fact, that 4! = 24 different quads can be constructed with the four corners of a rectangle.\n\n        Therefore, we **strongly recommend** to use the `quads` option for text searches, to ensure correct annotations. A similar consideration applies to marking **text spans** extracted with the \"dict\" / \"rawdict\" options of :meth:`Page.get_text`. For more details on how to compute quadrilaterals in this case, see section \"How to Mark Non-horizontal Text\" of :ref:`FAQ`.\n\n      :arg rect_like,quad_like,list,tuple quads:\n        the location(s) -- rectangle(s) or quad(s) -- to be marked. (Changed in v1.14.20)\n        A list or tuple must consist of :data:`rect_like` or :data:`quad_like` items (or even a mixture of either).\n        Every item must be finite, convex and not empty (as applicable).\n        **Set this parameter to** ``None`` if you want to use the following arguments (Changed in v1.16.14).\n        And vice versa: if not ``None``, the remaining parameters must be ``None``.\n        \n      :arg point_like start: start text marking at this point. Defaults to the top-left point of *clip*. Must be provided if `quads` is ``None``. (New in v1.16.14)\n      :arg point_like stop: stop text marking at this point. Defaults to the bottom-right point of *clip*. Must be used if `quads` is ``None``. (New in v1.16.14)\n      :arg rect_like clip: only consider text lines intersecting this area. Defaults to the page rectangle. Only use if `start` and `stop` are provided. (New in v1.16.14)\n\n      :rtype: :ref:`Annot` or ``None`` (changed in v1.16.14).\n      :returns: the created annotation. If *quads* is an empty list, **no annotation** is created (changed in v1.16.14).\n\n      .. note::\n        You can use parameters *start*, *stop* and *clip* to highlight consecutive lines between the points *start* and *stop* (starting with v1.16.14).\n        Make use of *clip* to further reduce the selected line bboxes and thus deal with e.g. multi-column pages.\n        The following multi-line highlight on a page with three text columns was created by specifying the two red points and setting clip accordingly.\n\n      .. image:: images/img-markers.*\n         :scale: 100\n\n   .. method:: cluster_drawings(clip=None, drawings=None, x_tolerance=3, y_tolerance=3, final_filter=True)\n\n      Cluster vector graphics (synonyms are line-art or drawings) based on their geometrical vicinity. The method walks through the output of :meth:`Page.get_drawings` and joins paths whose `path[\"rect\"]` are closer to each other than some tolerance values (given in the arguments). The result is a list of rectangles that each wrap things like tables (with gridlines), pie charts, bar charts, etc.\n\n      :arg rect_like clip: only consider paths inside this area. The default is the full page.\n\n      :arg list drawings: (optional) provide a previously generated output of :meth:`Page.get_drawings`. If `None` the method will execute the method.\n\n      :arg float x_tolerance / y_tolerance: Assume vector graphics to be close enough neighbors for belonging to the same rectangle. Default is 3 points.\n\n      :arg bool final_filter: If `True` (default), the method will to remove rectangles having width or height smaller than the respective tolerance value. If `False` no such filtering is done.\n\n   .. method:: find_tables(clip=None, strategy=None, vertical_strategy=None, horizontal_strategy=None, vertical_lines=None, horizontal_lines=None, snap_tolerance=None, snap_x_tolerance=None, snap_y_tolerance=None, join_tolerance=None, join_x_tolerance=None, join_y_tolerance=None, edge_min_length=3, min_words_vertical=3, min_words_horizontal=1, intersection_tolerance=None, intersection_x_tolerance=None, intersection_y_tolerance=None, text_tolerance=None, text_x_tolerance=None, text_y_tolerance=None, add_lines=None, add_boxes=None, paths=None)\n\n      Find tables on the page and return an object with related information. Typically, the default values of the many parameters will be sufficient. Adjustments should ever only be needed in corner case situations.\n\n      :arg rect_like clip: specify a region to consider within the page rectangle and ignore the rest. Default is the full page.\n\n      :arg str strategy: Request a **table detection** strategy. Valid values are \"lines\", \"lines_strict\" and \"text\".\n      \n         Default is **\"lines\"** which uses all vector graphics on the page to detect grid lines.\n         \n         Strategy **\"lines_strict\"** ignores borderless rectangle vector graphics. Sometimes single text pieces have background colors which may lead to false columns or lines. This strategy ignores them and can thus increase detection precision.\n         \n         If **\"text\"** is specified, text positions are used to generate \"virtual\" column and / or row boundaries. Use `min_words_*` to request the number of words for considering their coordinates.\n         \n         Use parameters `vertical_strategy` and `horizontal_strategy` **instead** for a more fine-grained treatment of the dimensions.\n\n      :arg sequence[floats] horizontal_lines: y-coordinates of rows. If provided, there will be no attempt to identify additional table rows. This influences table detection.\n\n      :arg sequence[floats] vertical_lines: x-coordinates of columns. If provided, there will be no attempt to identify additional table columns. This influences table detection.\n\n      :arg int min_words_vertical: relevant for vertical strategy option \"text\": at least this many words must coincide to establish a **virtual column** boundary.\n\n      :arg int min_words_horizontal: relevant for horizontal strategy option \"text\": at least this many words must coincide to establish a **virtual row** boundary.\n\n      :arg float snap_tolerance: Any two horizontal lines whose y-values differ by no more than this value will be **snapped** into one. Accordingly for vertical lines. Default is 3. Separate values can be specified instead for the dimensions, using `snap_x_tolerance` and `snap_y_tolerance`.\n\n      :arg float join_tolerance: Any two lines will be **joined** to one if the end and the start points differ by no more than this value (in points). Default is 3. Instead of this value, separate values can be specified for the dimensions using `join_x_tolerance` and `join_y_tolerance`.\n\n      :arg float edge_min_length: Ignore a line if its length does not exceed this value (points). Default is 3.\n\n      :arg float intersection_tolerance: When combining lines into cell borders, orthogonal lines must be within this value (points) to be considered intersecting. Default is 3. Instead of this value, separate values can be specified for the dimensions using `intersection_x_tolerance` and `intersection_y_tolerance`.\n\n      :arg float text_tolerance: Characters will be combined into words only if their distance is no larger than this value (points). Default is 3. Instead of this value, separate values can be specified for the dimensions using `text_x_tolerance` and `text_y_tolerance`.\n\n      :arg tuple,list add_lines: Specify a list of \"lines\" (i.e. pairs of :data:`point_like` objects) as **additional**, \"virtual\" vector graphics. These lines may help with table and / or cell detection and will not otherwise influence the detection strategy. Especially, in contrast to parameters `horizontal_lines` and `vertical_lines`, they will not prevent detecting rows or columns in other ways. These lines will be treated exactly like \"real\" vector graphics in terms of joining, snapping, intersecting, minimum length and containment in the `clip` rectangle. Similarly, lines not parallel to any of the coordinate axes will be ignored.\n\n      :arg tuple,list add_boxes: Specify a list of rectangles (:data:`rect_like` objects) as **additional**, \"virtual\" vector graphics. These rectangles may help with table and / or cell detection and will not otherwise influence the detection strategy. Especially, in contrast to parameters `horizontal_lines` and `vertical_lines`, they will not prevent detecting rows or columns in other ways. These rectangles will be treated exactly like \"real\" vector graphics in terms of joining, snapping, intersecting, minimum length and containment in the `clip` rectangle.\n\n      :arg list paths: list of vector graphics in the format as returned be :meth:`Page.get_drawings`. Using this parameter will prevent the method to extract vector graphics itself. This is useful if the vector graphics are already available. This can save execution time significantly.\n\n      .. image:: images/img-findtables.*\n\n      :returns: a `TableFinder` object that has the following significant attributes:\n\n         * `cells`: a list of **all bboxes** on the page, that have been identified as table cells (across all tables). Each cell is a :data:`rect_like` tuple `(x0, y0, x1, y1)` of coordinates or `None`.\n         * `tables`: a list of `Table` objects. This is `[]` if the page has no tables. Single tables can be found as items of this list. But the `TableFinder` object itself is also a sequence of its tables. This means that if `tabs` is a `TableFinder` object, then table \"n\" is delivered by `tabs.tables[n]` as well as by the shorter `tabs[n]`.\n\n\n         * The `Table` object has the following attributes:\n\n           * ``bbox``: the bounding box of the table as a tuple `(x0, y0, x1, y1)`.\n           * ``cells``: bounding boxes of the table's cells (list of tuples). A cell may also be `None`.\n           * ``extract()``: this method returns the text content of each table cell as a list of list of strings.\n           * ``to_markdown()``: this method returns the table as a **string in markdown format** (compatible to Github). Markdown viewers can render the string as a table. This output is optimized for **small token** sizes, which is especially beneficial for LLM/RAG feeds. Pandas DataFrames (see method `to_pandas()` below) offer an equivalent markdown table output which however is better readable for the human eye. Any line breaks (``\\n``) in cells are replaced by HTML line breaks tags `<br>`.\n           * `to_pandas()`: this method returns the table as a `pandas <https://pypi.org/project/pandas/>`_ `DataFrame <https://pandas.pydata.org/docs/reference/frame.html>`_. DataFrames are very versatile objects allowing a plethora of table manipulation methods and outputs to almost 20 well-known formats, among them Excel files, CSV, JSON, markdown-formatted tables and more. `DataFrame.to_markdown()` generates a Github-compatible markdown format optimized for human readability. This method however requires the package `tabulate <https://pypi.org/project/tabulate/>`_ to be installed in addition to pandas itself.\n           * ``header``: a `TableHeader` object containing header information of the table.\n           * ``col_count``: an integer containing the number of table columns.\n           * ``row_count``: an integer containing the number of table rows.\n           * ``rows``: a list of `TableRow` objects containing two attributes, ``bbox`` is the boundary box of the row, and `cells` is a list of table cells contained in this row.\n\n         * The `TableHeader` object has the following attributes:\n\n           * ``bbox``: the bounding box of the header.\n           * `cells`: a list of bounding boxes containing the name of the respective column.\n           * `names`: a list of strings containing the text of each of the cell bboxes. They represent the column names -- which are used when exporting the table to pandas DataFrames, markdown, etc.\n           * `external`: a bool indicating whether the header bbox is outside the table body (`True`) or not. Table headers are never identified by the `TableFinder` logic. Therefore, if `external` is true, then the header cells are not part of any cell identified by `TableFinder`. If `external == False`, then the first table row is the header.\n\n         Please have a look at these `Jupyter notebooks <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-analysis>`_, which cover standard situations like multiple tables on one page or joining table fragments across multiple pages.\n\n         .. caution:: The lifetime of the `TableFinder` object, as well as that of all its tables **equals the lifetime of the page**. If the page object is deleted or reassigned, all tables are no longer valid.\n         \n            The only way to keep table content beyond the page's availability is to **extract it** via methods `Table.to_markdown()`, `Table.to_pandas()` or a copy of `Table.extract()` (e.g. `Table.extract()[:]`).\n\n         .. note::\n\n            Once a table has been extracted to a **Pandas DataFrame** with `to_pandas()` it is easy to convert to other file types with the **Pandas API**:\n\n            - table to Markdown, use `to_markdown <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_markdown.html#pandas.DataFrame.to_markdown>`_\n            - table to JSON, use: `to_json <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_json.html>`_\n            - table to Excel, use: `to_excel <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_excel.html>`_\n            - table to CSV, use: `to_csv <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_csv.html>`_\n            - table to HTML, use: `to_html <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_html.html>`_\n            - table to SQL, use: `to_sql <https://pandas.pydata.org/docs/reference/api/pandas.DataFrame.to_sql.html>`_\n\n\n      |history_begin|\n\n      * New in version 1.23.0\n      * Changed in version 1.23.19: new argument `add_lines`.\n\n      |history_end|\n\n      .. important::\n\n         There is also the `pdf2docx extract tables method`_ which is capable of table extraction if you prefer.\n\n\n   .. method:: add_stamp_annot(rect, stamp=0)\n\n      PDF only: Add a \"rubber stamp\" annotation to e.g. indicate the document's intended use (\"DRAFT\", \"CONFIDENTIAL\", etc.). The parameter may be either an integer to select text from a predefined array of standard texts or an image.\n\n      :arg rect_like rect: rectangle where to place the annotation.\n      :arg multiple stamp: The following options are available:\n      \n         * The id number (int) of the stamp text. For available stamps see :ref:`StampIcons`.\n   \n         * A string specifying an image file path.\n\n         * A ``bytes``, ``bytearray`` or ``io.BytesIO`` object for an image in memory.\n\n         * A :ref:`Pixmap`.\n         \n      1. **Text-based stamps**\n\n         * :attr:`Annot.rect` is automatically calculated as the largest rectangle with an aspect ratio of ``width:height = 3.8`` that fits in the provided ``rect``. Its position is vertically and horizontally centered.\n         * The font chosen is \"Times Bold\" and the text will be upper case.\n         * The appearance can be modified using :meth:`Annot.set_opacity` and by setting the \"stroke\" color. By PDF specification, stamp annotations have no \"fill\" color.\n\n         .. image:: images/img-stampannot.*\n\n      2. **Image-based stamps**\n\n         * The image is scaled to fit into the rectangle `rect` such that the image's center and the center of `rect` coincide. The aspect ratio of the image is preserved, so the image may not fill the entire rectangle. However, at least one of the given rectangle's width or height are fully covered.\n         * The annotation can be modified via :meth:`Annot.set_opacity`. This method therefore is a way to display images transparently even if no alpha channel is present.\n         * Setting colors has no effect on image stamps.\n         * Rotating image-based stamps **is not supported**. Setting the rotation may lead to unexpected results.\n         \n   .. method:: add_widget(widget)\n\n      PDF only: Add a PDF Form field (\"widget\") to a page. This also **turns the PDF into a Form PDF**. Because of the large amount of different options available for widgets, we have developed a new class :ref:`Widget`, which contains the possible PDF field attributes. It must be used for both, form field creation and updates.\n\n      :arg widget: a :ref:`Widget` object which must have been created upfront.\n      :type widget: :ref:`Widget`\n\n      :returns: a widget annotation.\n\n   .. method:: delete_annot(annot)\n\n      * The removal will now include any bound 'Popup' or response annotations and related objects (changed in v1.16.6).\n\n      PDF only: Delete annotation from the page and return the next one.\n\n      :arg annot: the annotation to be deleted.\n      :type annot: :ref:`Annot`\n\n      :rtype: :ref:`Annot`\n      :returns: the annotation following the deleted one. Please remember that physical removal requires saving to a new file with garbage > 0.\n\n   .. method:: delete_widget(widget)\n\n      PDF only: Delete field from the page and return the next one.\n\n      :arg widget: the widget to be deleted.\n      :type widget: :ref:`Widget`\n\n      :rtype: :ref:`Widget`\n      :returns: the widget following the deleted one. Please remember that physical removal requires saving to a new file with garbage > 0.\n\n      |history_begin|\n\n      (New in v1.18.4)\n\n      |history_end|\n\n\n   .. method:: delete_link(linkdict)\n\n      PDF only: Delete the specified link from the page. The parameter must be an **original item** of :meth:`get_links()`, see :ref:`link_dict_description`. The reason for this is the dictionary's *\"xref\"* key, which identifies the PDF object to be deleted.\n\n      :arg dict linkdict: the link to be deleted.\n\n   .. method:: insert_link(linkdict)\n\n      PDF only: Insert a new link on this page. The parameter must be a dictionary of format as provided by :meth:`get_links()`, see :ref:`link_dict_description`.\n\n      :arg dict linkdict: the link to be inserted.\n\n   .. method:: update_link(linkdict)\n\n      PDF only: Modify the specified link. The parameter must be a (modified) **original item** of :meth:`get_links()`, see :ref:`link_dict_description`. The reason for this is the dictionary's *\"xref\"* key, which identifies the PDF object to be changed.\n\n      :arg dict linkdict: the link to be modified.\n\n      .. warning:: If updating / inserting a URI link (`\"kind\": LINK_URI`), please make sure to start the value for the `\"uri\"` key with a disambiguating string like `\"http://\"`, `\"https://\"`, `\"file://\"`, `\"ftp://\"`, `\"mailto:\"`, etc. Otherwise -- depending on your browser or other \"consumer\" software -- unexpected default assumptions may lead to unwanted behaviours.\n\n\n   .. method:: get_label()\n\n      PDF only: Return the label for the page.\n\n      :rtype: str\n\n      :returns: the label string like \"vii\" for Roman numbering or \"\" if not defined.\n\n      |history_begin|\n\n      * New in v1.18.6\n\n      |history_end|\n\n   .. method:: get_links()\n\n      Retrieves **all** links of a page.\n\n      :rtype: list\n      :returns: A list of dictionaries. For a description of the dictionary entries, see :ref:`link_dict_description`. Always use this or the :meth:`Page.links` method if you intend to make changes to the links of a page.\n\n   .. method:: links(kinds=None)\n\n      Return a generator over the page's links. The results equal the entries of :meth:`Page.get_links`.\n\n      :arg sequence kinds: a sequence of integers to down-select to one or more link kinds. Default is all links. Example: *kinds=(pymupdf.LINK_GOTO,)* will only return internal links.\n\n      :rtype: generator\n      :returns: an entry of :meth:`Page.get_links()` for each iteration.\n\n      |history_begin|\n\n      * New in v1.16.4\n\n      |history_end|\n\n   .. method:: annots(types=None)\n\n      Return a generator over the page's annotations.\n\n      :arg sequence types: a sequence of integers to down-select to one or more annotation types. Default is all annotations. Example: `types=(pymupdf.PDF_ANNOT_FREETEXT, pymupdf.PDF_ANNOT_TEXT)` will only return 'FreeText' and 'Text' annotations.\n\n      :rtype: generator\n      :returns: an :ref:`Annot` for each iteration.\n\n         .. caution::\n              You **cannot safely update annotations** from within this generator. This is because most annotation updates require reloading the page via `page = doc.reload_page(page)`. To circumvent this restriction, make a list of annotations xref numbers first and then iterate over these numbers::\n\n               In [4]: xrefs = [annot.xref for annot in page.annots(types=[...])]\n               In [5]: for xref in xrefs:\n                  ...:     annot = page.load_annot(xref)\n                  ...:     annot.update()\n                  ...:     page = doc.reload_page(page)\n               In [6]:\n\n      |history_begin|\n\n      * New in v1.16.4\n\n      |history_end|\n\n   .. method:: widgets(types=None)\n\n      Return a generator over the page's form fields.\n\n      :arg sequence types: a sequence of integers to down-select to one or more widget types. Default is all form fields. Example: `types=(pymupdf.PDF_WIDGET_TYPE_TEXT,)` will only return 'Text' fields.\n\n      :rtype: generator\n      :returns: a :ref:`Widget` for each iteration.\n\n      |history_begin|\n\n      * New in v1.16.4\n\n      |history_end|\n\n\n   .. method:: write_text(rect=None, writers=None, overlay=True, color=None, opacity=None, keep_proportion=True, rotate=0, oc=0)\n\n      PDF only: Write the text of one or more :ref:`Textwriter` objects to the page.\n\n      :arg rect_like rect: where to place the text. If omitted, the rectangle union of the text writers is used.\n      :arg sequence writers: a non-empty tuple / list of :ref:`TextWriter` objects or a single :ref:`TextWriter`.\n      :arg float opacity: set transparency, overwrites resp. value in the text writers.\n      :arg sequ color: set the text color, overwrites  resp. value in the text writers.\n      :arg bool overlay: put the text in foreground or background.\n      :arg bool keep_proportion: maintain the aspect ratio.\n      :arg float rotate: rotate the text by an arbitrary angle.\n      :arg int oc: the :data:`xref` of an :data:`OCG` or :data:`OCMD`. (New in v1.18.4)\n\n      .. note:: Parameters *overlay, keep_proportion, rotate* and *oc* have the same meaning as in :meth:`Page.show_pdf_page`.\n\n      |history_begin|\n\n      * New in v1.16.18\n\n      |history_end|\n\n\n   .. index::\n      pair: border_width; insert_text\n      pair: color; insert_text\n      pair: encoding; insert_text\n      pair: fill; insert_text\n      pair: fontfile; insert_text\n      pair: fontname; insert_text\n      pair: fontsize; insert_text\n      pair: morph; insert_text\n      pair: overlay; insert_text\n      pair: render_mode; insert_text\n      pair: miter_limit; insert_text\n      pair: rotate; insert_text\n      pair: stroke_opacity; insert_text\n      pair: fill_opacity; insert_text\n      pair: oc; insert_text\n\n   .. method:: insert_text(point, text, *, fontsize=11, fontname=\"helv\", fontfile=None, idx=0, color=None, fill=None, render_mode=0, miter_limit=1, border_width=0.05, encoding=TEXT_ENCODING_LATIN, rotate=0, morph=None, stroke_opacity=1, fill_opacity=1, overlay=True, oc=0)\n\n      PDF only: Insert text lines starting at :data:`point_like` ``point``. See :meth:`Shape.insert_text`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: align; insert_textbox\n      pair: border_width; insert_textbox\n      pair: color; insert_textbox\n      pair: encoding; insert_textbox\n      pair: expandtabs; insert_textbox\n      pair: fill; insert_textbox\n      pair: fontfile; insert_textbox\n      pair: fontname; insert_textbox\n      pair: fontsize; insert_textbox\n      pair: morph; insert_textbox\n      pair: overlay; insert_textbox\n      pair: render_mode; insert_textbox\n      pair: miter_limit; insert_textbox\n      pair: rotate; insert_textbox\n      pair: stroke_opacity; insert_textbox\n      pair: fill_opacity; insert_textbox\n      pair: oc; insert_textbox\n\n   .. method:: insert_textbox(rect, buffer, \\\n                *, \\\n                align=TEXT_ALIGN_LEFT, \\\n                border_width=1, \\\n                color=None, \\\n                encoding=TEXT_ENCODING_LATIN, \\\n                expandtabs=8, \\\n                fill=None, \\\n                fill_opacity=1, \\\n                fontfile=None, \\\n                fontname=\"helv\", \\\n                fontsize=11, \\\n                lineheight=None, \\\n                miter_limit=1, \\\n                morph=None, \\\n                oc=0, \\\n                overlay=True, \\\n                render_mode=0, \\\n                rotate=0, \\\n                set_simple=False, \\\n                stroke_opacity=1, \\\n                )\n\n      PDF only: Insert text into the specified :data:`rect_like` *rect*.\n      \n      :arg overlay: see :meth:`Shape.commit`.\n      \n      For other args, see `Shape.insert_textbox`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: rect; insert_htmlbox\n      pair: text; insert_htmlbox\n      pair: css; insert_htmlbox\n      pair: adjust; insert_htmlbox\n      pair: archive; insert_htmlbox\n      pair: overlay; insert_htmlbox\n      pair: rotate; insert_htmlbox\n      pair: oc; insert_htmlbox\n      pair: opacity; insert_htmlbox\n      pair: morph; insert_htmlbox\n\n   .. method:: insert_htmlbox(rect, text, *, css=None, scale_low=0, archive=None, rotate=0, oc=0, opacity=1, overlay=True)\n\n      **PDF only:** Insert text into the specified rectangle. The method has similarities with methods :meth:`Page.insert_textbox` and :meth:`TextWriter.fill_textbox`, but is **much more powerful**. This is achieved by letting a :ref:`Story` object do all the required processing.\n\n      * Parameter ``text`` may be a string as in the other methods. But it will be **interpreted as HTML source** and may therefore also contain HTML language elements -- including styling. The `css` parameter may be used to pass in additional styling instructions.\n\n      * Automatic line breaks are generated at word boundaries. The \"soft hyphen\" character `\"&#173;\"` (or `&shy;`) can be used to cause hyphenation and thus may also cause line breaks. **Forced** line breaks however are only achievable via the HTML tag ``<br>`` - ``\\n`` is ignored and will be treated like a space.\n\n      * With this method the following can be achieved:\n\n        - Styling effects like bold, italic, text color, text alignment, font size or font switching.\n        - The text may include arbitrary languages -- **including right-to-left** languages.\n        - Scripts like `Devanagari <https://en.wikipedia.org/wiki/Devanagari>`_ and several others in Asia have a highly complex system of ligatures, where two or more unicodes together yield one glyph. The Story uses the software package `HarfBuzz <https://harfbuzz.github.io/>`_ , to deal with these things and produce correct output.\n        - One can also **include images** via HTML tag `<img>` -- the Story will take care of the appropriate layout. This is an alternative option to insert images, compared to :meth:`Page.insert_image`.\n        - HTML tables (tag `<table>`) may be included in the text and will be handled appropriately.\n        - Links are automatically generated when present.\n\n      * If content does not fit in the rectangle, the developer has two choices:\n         \n        - **either** only be informed about this (and accept a no-op, just like with the other textbox insertion methods), \n        - **or** (`scale_low=0` - the default) scale down the content until it fits.\n\n      :arg rect_like rect: rectangle on page to receive the text.\n      :arg str,Story text: the text to be written. Can contain a mixture of plain text and HTML tags with styling instructions. Alternatively, a :ref:`Story` object may be specified (in which case the internal Story generation step will be omitted). A Story must have been generated with all required styling and Archive information.\n      :arg str css: optional string containing additional CSS instructions. This parameter is ignored if ``text`` is a Story.\n      :arg float scale_low: if necessary, scale down the content until it fits in the target rectangle. This sets the down scaling limit. Default is 0, no limit. A value of 1 means no down-scaling permitted. A value of e.g. 0.2 means maximum down-scaling by 80%.\n      :arg Archive archive: an Archive object that points to locations where to find images or non-standard fonts. If ``text`` refers to images or non-standard fonts, this parameter is required. This parameter is ignored if ``text`` is a Story.\n      :arg int rotate: one of the values 0, 90, 180, 270. Depending on this, text will be filled:\n      \n          - 0: top-left to bottom-right.\n          - 90: bottom-left to top-right.\n          - 180: bottom-right to top-left.\n          - 270: top-right to bottom-left.\n\n          .. image:: images/img-rotate.*\n\n      :arg int oc:  the xref of an :data:`OCG` / :data:`OCMD` or 0. Please refer to :meth:`Page.show_pdf_page` for details.\n      :arg float opacity: set the fill and stroke opacity of the content. Only values `0 <= opacity < 1` are considered.\n      :arg bool overlay: put the text in front of other content. Please refer to :meth:`Page.show_pdf_page` for details.\n\n      :returns: A tuple of floats `(spare_height, scale)`.\n\n          - spare_height: The (positive) height of the remaining space in `rect` below the\n            text, or -1 if we failed to fit.\n          - scale: The scaling required; `0 < scale <= 1`. Will be `scale_low`\n            if we failed to fit.\n\n      Please refer to examples in this section of the recipes: :ref:`RecipesText_I_c`.\n\n      |history_begin|\n\n      * New in v1.26.5:\n        \n        * do additional scaling to fit long words.\n        *\n          If we succeeded and scaled down, the returned `spare_height` is now\n          generally positive instead of being fixed to zero, because the final\n          rect's height is usually not an exact multiple of the font line\n          height.\n      * New in v1.23.8: rebased-only.\n      * New in v1.23.9: `opacity` parameter.\n\n      |history_end|\n      \n\n   **Drawing Methods**\n\n   .. index::\n      pair: closePath; draw_line\n      pair: color; draw_line\n      pair: dashes; draw_line\n      pair: fill; draw_line\n      pair: lineCap; draw_line\n      pair: lineJoin; draw_line\n      pair: lineJoin; draw_line\n      pair: morph; draw_line\n      pair: overlay; draw_line\n      pair: width; draw_line\n      pair: stroke_opacity; draw_line\n      pair: fill_opacity; draw_line\n      pair: oc; draw_line\n\n   .. method:: draw_line(p1, p2, color=(0,), width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw a line from *p1* to *p2* (:data:`point_like` \\s). See :meth:`Shape.draw_line`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: breadth; draw_zigzag\n      pair: closePath; draw_zigzag\n      pair: color; draw_zigzag\n      pair: dashes; draw_zigzag\n      pair: fill; draw_zigzag\n      pair: lineCap; draw_zigzag\n      pair: lineJoin; draw_zigzag\n      pair: morph; draw_zigzag\n      pair: overlay; draw_zigzag\n      pair: width; draw_zigzag\n      pair: stroke_opacity; draw_zigzag\n      pair: fill_opacity; draw_zigzag\n      pair: oc; draw_zigzag\n\n   .. method:: draw_zigzag(p1, p2, breadth=2, color=(0,), width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw a zigzag line from *p1* to *p2* (:data:`point_like` \\s). See :meth:`Shape.draw_zigzag`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: breadth; draw_squiggle\n      pair: closePath; draw_squiggle\n      pair: color; draw_squiggle\n      pair: dashes; draw_squiggle\n      pair: fill; draw_squiggle\n      pair: lineCap; draw_squiggle\n      pair: lineJoin; draw_squiggle\n      pair: morph; draw_squiggle\n      pair: overlay; draw_squiggle\n      pair: width; draw_squiggle\n      pair: stroke_opacity; draw_squiggle\n      pair: fill_opacity; draw_squiggle\n      pair: oc; draw_squiggle\n\n   .. method:: draw_squiggle(p1, p2, breadth=2, color=(0,), width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw a squiggly (wavy, undulated) line from *p1* to *p2* (:data:`point_like` \\s). See :meth:`Shape.draw_squiggle`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: closePath; draw_circle\n      pair: color; draw_circle\n      pair: dashes; draw_circle\n      pair: fill; draw_circle\n      pair: lineCap; draw_circle\n      pair: lineJoin; draw_circle\n      pair: morph; draw_circle\n      pair: overlay; draw_circle\n      pair: width; draw_circle\n      pair: stroke_opacity; draw_circle\n      pair: fill_opacity; draw_circle\n      pair: oc; draw_circle\n\n   .. method:: draw_circle(center, radius, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw a circle around *center* (:data:`point_like`) with a radius of *radius*. See :meth:`Shape.draw_circle`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: closePath; draw_oval\n      pair: color; draw_oval\n      pair: dashes; draw_oval\n      pair: fill; draw_oval\n      pair: lineCap; draw_oval\n      pair: lineJoin; draw_oval\n      pair: morph; draw_oval\n      pair: overlay; draw_oval\n      pair: width; draw_oval\n      pair: stroke_opacity; draw_oval\n      pair: fill_opacity; draw_oval\n      pair: oc; draw_oval\n\n   .. method:: draw_oval(quad, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw an oval (ellipse) within the given :data:`rect_like` or :data:`quad_like`. See :meth:`Shape.draw_oval`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: closePath; draw_sector\n      pair: color; draw_sector\n      pair: dashes; draw_sector\n      pair: fill; draw_sector\n      pair: fullSector; draw_sector\n      pair: lineCap; draw_sector\n      pair: lineJoin; draw_sector\n      pair: morph; draw_sector\n      pair: overlay; draw_sector\n      pair: width; draw_sector\n      pair: stroke_opacity; draw_sector\n      pair: fill_opacity; draw_sector\n      pair: oc; draw_sector\n\n   .. method:: draw_sector(center, point, angle, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, fullSector=True, overlay=True, closePath=False, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw a circular sector, optionally connecting the arc to the circle's center (like a piece of pie). See :meth:`Shape.draw_sector`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: closePath; draw_polyline\n      pair: color; draw_polyline\n      pair: dashes; draw_polyline\n      pair: fill; draw_polyline\n      pair: lineCap; draw_polyline\n      pair: lineJoin; draw_polyline\n      pair: morph; draw_polyline\n      pair: overlay; draw_polyline\n      pair: width; draw_polyline\n      pair: stroke_opacity; draw_polyline\n      pair: fill_opacity; draw_polyline\n      pair: oc; draw_polyline\n\n   .. method:: draw_polyline(points, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, closePath=False, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw several connected lines defined by a sequence of :data:`point_like` \\s. See :meth:`Shape.draw_polyline`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n\n   .. index::\n      pair: closePath; draw_bezier\n      pair: color; draw_bezier\n      pair: dashes; draw_bezier\n      pair: fill; draw_bezier\n      pair: lineCap; draw_bezier\n      pair: lineJoin; draw_bezier\n      pair: morph; draw_bezier\n      pair: overlay; draw_bezier\n      pair: width; draw_bezier\n      pair: stroke_opacity; draw_bezier\n      pair: fill_opacity; draw_bezier\n      pair: oc; draw_bezier\n\n   .. method:: draw_bezier(p1, p2, p3, p4, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, closePath=False, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw a cubic Bézier curve from *p1* to *p4* with the control points *p2* and *p3* (all are :data:`point_like` \\s). See :meth:`Shape.draw_bezier`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: closePath; draw_curve\n      pair: color; draw_curve\n      pair: dashes; draw_curve\n      pair: fill; draw_curve\n      pair: lineCap; draw_curve\n      pair: lineJoin; draw_curve\n      pair: morph; draw_curve\n      pair: overlay; draw_curve\n      pair: width; draw_curve\n      pair: stroke_opacity; draw_curve\n      pair: fill_opacity; draw_curve\n      pair: oc; draw_curve\n\n   .. method:: draw_curve(p1, p2, p3, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, closePath=False, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: This is a special case of *draw_bezier()*. See :meth:`Shape.draw_curve`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n   .. index::\n      pair: closePath; draw_rect\n      pair: color; draw_rect\n      pair: dashes; draw_rect\n      pair: fill; draw_rect\n      pair: lineCap; draw_rect\n      pair: lineJoin; draw_rect\n      pair: morph; draw_rect\n      pair: overlay; draw_rect\n      pair: width; draw_rect\n      pair: stroke_opacity; draw_rect\n      pair: fill_opacity; draw_rect\n      pair: radius; draw_rect\n      pair: oc; draw_rect\n\n   .. method:: draw_rect(rect, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, morph=None, stroke_opacity=1, fill_opacity=1, radius=None, oc=0)\n\n      PDF only: Draw a rectangle. See :meth:`Shape.draw_rect`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n      * Changed in v1.22.0: Added parameter *radius*.\n\n      |history_end|\n\n   .. index::\n      pair: closePath; draw_quad\n      pair: color; draw_quad\n      pair: dashes; draw_quad\n      pair: fill; draw_quad\n      pair: lineCap; draw_quad\n      pair: lineJoin; draw_quad\n      pair: morph; draw_quad\n      pair: overlay; draw_quad\n      pair: width; draw_quad\n      pair: stroke_opacity; draw_quad\n      pair: fill_opacity; draw_quad\n      pair: oc; draw_quad\n\n   .. method:: draw_quad(quad, color=(0,), fill=None, width=1, dashes=None, lineCap=0, lineJoin=0, overlay=True, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      PDF only: Draw a quadrilateral. See :meth:`Shape.draw_quad`.\n\n      |history_begin|\n\n      * Changed in v1.18.4\n\n      |history_end|\n\n\n   .. index::\n      pair: encoding; insert_font\n      pair: fontbuffer; insert_font\n      pair: fontfile; insert_font\n      pair: fontname; insert_font\n      pair: set_simple; insert_font\n\n   .. method:: insert_font(fontname=\"helv\", fontfile=None, fontbuffer=None, set_simple=False, encoding=TEXT_ENCODING_LATIN)\n\n      PDF only: Add a new font to be used by text output methods and return its :data:`xref`. If not already present in the file, the font definition will be added. Supported are the built-in :data:`Base14_Fonts` and the CJK fonts via **\"reserved\"** fontnames. Fonts can also be provided as a file path or a memory area containing the image of a font file.\n\n      :arg str fontname: The name by which this font shall be referenced when outputting text on this page. In general, you have a \"free\" choice here (but consult the :ref:`AdobeManual`, page 16, section 7.3.5 for a formal description of building legal PDF names). However, if it matches one of the :data:`Base14_Fonts` or one of the CJK fonts, *fontfile* and *fontbuffer* **are ignored**.\n\n        In other words, you cannot insert a font via *fontfile* / *fontbuffer* and also give it a reserved *fontname*.\n\n        .. note:: A reserved fontname can be specified in any mixture of upper or lower case and still match the right built-in font definition: fontnames \"helv\", \"Helv\", \"HELV\", \"Helvetica\", etc. all lead to the same font definition \"Helvetica\". But from a :ref:`Page` perspective, these are **different references**. You can exploit this fact when using different *encoding* variants (Latin, Greek, Cyrillic) of the same font on a page.\n\n      :arg str fontfile: a path to a font file. If used, *fontname* must be **different from all reserved names**.\n\n      :arg bytes/bytearray fontbuffer: the memory image of a font file. If used, *fontname* must be **different from all reserved names**. This parameter would typically be used with :attr:`Font.buffer` for fonts supported / available via :ref:`Font`.\n\n      :arg int set_simple: applicable for *fontfile* / *fontbuffer* cases only: enforce treatment as a \"simple\" font, i.e. one that only uses character codes up to 255.\n\n      :arg int encoding: applicable for the \"Helvetica\", \"Courier\" and \"Times\" sets of :data:`Base14_Fonts` only. Select one of the available encodings Latin (0), Cyrillic (2) or Greek (1). Only use the default (0 = Latin) for \"Symbol\" and \"ZapfDingBats\".\n\n      :rytpe: int\n      :returns: the :data:`xref` of the installed font.\n\n      .. note:: Built-in fonts will not lead to the inclusion of a font file. So the resulting PDF file will remain small. However, your PDF viewer software is responsible for generating an appropriate appearance -- and there **exist** differences on whether or how each one of them does this. This is especially true for the CJK fonts. But also Symbol and ZapfDingbats are incorrectly handled in some cases. Following are the **Font Names** and their correspondingly installed **Base Font** names:\n\n         **Base-14 Fonts** [#f1]_\n\n         ============= ============================ =========================================\n         **Font Name** **Installed Base Font**      **Comments**\n         ============= ============================ =========================================\n         helv          Helvetica                    normal\n         heit          Helvetica-Oblique            italic\n         hebo          Helvetica-Bold               bold\n         hebi          Helvetica-BoldOblique        bold-italic\n         cour          Courier                      normal\n         coit          Courier-Oblique              italic\n         cobo          Courier-Bold                 bold\n         cobi          Courier-BoldOblique          bold-italic\n         tiro          Times-Roman                  normal\n         tiit          Times-Italic                 italic\n         tibo          Times-Bold                   bold\n         tibi          Times-BoldItalic             bold-italic\n         symb          Symbol                       [#f3]_\n         zadb          ZapfDingbats                 [#f3]_\n         ============= ============================ =========================================\n\n         **CJK Fonts** [#f2]_ (China, Japan, Korea)\n\n         ============= ============================ =========================================\n         **Font Name** **Installed Base Font**      **Comments**\n         ============= ============================ =========================================\n         china-s       Heiti                        simplified Chinese\n         china-ss      Song                         simplified Chinese (serif)\n         china-t       Fangti                       traditional Chinese\n         china-ts      Ming                         traditional Chinese (serif)\n         japan         Gothic                       Japanese\n         japan-s       Mincho                       Japanese (serif)\n         korea         Dotum                        Korean\n         korea-s       Batang                       Korean (serif)\n         ============= ============================ =========================================\n\n   .. index::\n      pair: filename; insert_image\n      pair: keep_proportion; insert_image\n      pair: overlay; insert_image\n      pair: pixmap; insert_image\n      pair: rotate; insert_image\n      pair: stream; insert_image\n      pair: mask; insert_image\n      pair: oc; insert_image\n      pair: xref; insert_image\n\n   .. method:: insert_image(rect, *, alpha=-1, filename=None, height=0, keep_proportion=True, mask=None, oc=0, overlay=True, pixmap=None, rotate=0, stream=None, width=0, xref=0)\n\n      PDF only: Put an image inside the given rectangle. The image may already\n      exist in the PDF or be taken from a pixmap, a file, or a memory area.\n\n      :arg rect_like rect: where to put the image. Must be finite and not empty.\n      :arg int alpha: deprecated and ignored.\n      :arg str filename:\n        name of an image file (all formats supported by MuPDF -- see\n        :ref:`ImageFiles`).\n      :arg int height:\n      :arg bool keep_proportion:\n        maintain the aspect ratio of the image.\n      :arg bytes,bytearray,io.BytesIO mask:\n        image in memory -- to be used as image mask (alpha values) for the base\n        image. When specified, the base image must be provided as a filename or\n        a stream -- and must not be an image that already has a mask.\n      :arg int oc:\n        (:data:`xref`) make image visibility dependent on this :data:`OCG`\n        or :data:`OCMD`. Ignored after the first of multiple insertions. The\n        property is stored with the generated PDF image object and therefore\n        controls the image's visibility throughout the PDF.\n      :arg overlay: see :ref:`CommonParms`.\n      :arg pixmap: a pixmap containing the image.\n      :arg int rotate: rotate the image.\n        Must be an integer multiple of 90 degrees.\n        Positive values rotate anti-clockwise.\n        If you need a rotation by an arbitrary angle,\n        consider converting the image to a PDF\n        (:meth:`Document.convert_to_pdf`)\n        first and then use :meth:`Page.show_pdf_page` instead.\n      :arg bytes,bytearray,io.BytesIO stream:\n        image in memory (all formats supported by MuPDF -- see :ref:`ImageFiles`).\n      :arg int width:\n      :arg int xref:\n        the :data:`xref` of an image already present in the PDF. If given,\n        parameters `filename`, `pixmap`, `stream`, `alpha` and `mask` are\n        ignored. The page will simply receive a reference to the existing\n        image.\n\n      :type pixmap: :ref:`Pixmap`\n      \n      :returns:\n        The `xref` of the embedded image. This can be used as the `xref`\n        argument for very significant performance boosts, if the image is\n        inserted again.\n\n      This example puts the same image on every page of a document::\n\n         >>> doc = pymupdf.open(...)\n         >>> rect = pymupdf.Rect(0, 0, 50, 50)       # put thumbnail in upper left corner\n         >>> img = open(\"some.jpg\", \"rb\").read()  # an image file\n         >>> img_xref = 0                         # first execution embeds the image\n         >>> for page in doc:\n               img_xref = page.insert_image(rect, stream=img,\n                          xref=img_xref,  2nd time reuses existing image\n                   )\n         >>> doc.save(...)\n\n      .. note::\n\n         1.\n           The method detects multiple insertions of the same image (like\n           in the above example) and will store its data only on the first\n           execution.  This is even true (although less performant), if using\n           the default `xref=0`.\n         2.\n           The method cannot detect if the same image had already been part of\n           the file before opening it.\n\n         3.\n           You can use this method to provide a background or foreground image\n           for the page, like a copyright or a watermark. Please remember, that\n           watermarks require a transparent image if put in foreground ...\n\n         4.\n           The image may be inserted uncompressed, e.g. if a `Pixmap` is used\n           or if the image has an alpha channel. Therefore, consider using\n           `deflate=True` when saving the file. In addition, there are ways to\n           control the image size -- even if transparency comes into play. Have\n           a look at :ref:`RecipesImages_O`.\n\n         5.\n           The image is stored in the PDF at its original quality level. This\n           may be much better than what you need for your display. Consider\n           **decreasing the image size** before insertion -- e.g. by using\n           the pixmap option and then shrinking it or scaling it down (see\n           :ref:`Pixmap` chapter). The PIL method `Image.thumbnail()` can\n           also be used for that purpose. The file size savings can be very\n           significant.\n\n         6.\n           Another efficient way to display the same image on multiple\n           pages is another method: :meth:`show_pdf_page`. Consult\n           :meth:`Document.convert_to_pdf` for how to obtain intermediary PDFs\n           usable for that method.\n\n      |history_begin|\n\n      * Changed in v1.14.1: By default, the image keeps its aspect ratio.\n      * Changed in v1.14.11: Added args `keep_proportion`, `rotate`.\n      * Changed in v1.14.13:\n\n        *\n          The image is now always placed **centered** in the rectangle, i.e.\n          the centers of image and rectangle are equal.\n        * Added support for `stream` as `io.BytesIO`.\n      \n      * Changed in v1.17.6:\n        Insertion rectangle no longer needs to have a non-empty intersection\n        with the page's :attr:`Page.cropbox` [#f5]_.\n      * Changed in v1.18.1: Added `mask` arg.\n      * Changed in v1.18.3: Added `oc` arg.\n      * Changed in v1.18.13:\n        \n        * Allow providing the image as the xref of an existing one.\n        * Added `xref` arg.\n        * Return `xref` of stored image.\n      \n      * Changed in v1.19.3: deprecate and ignore `alpha` arg.\n\n      |history_end|\n\n   \n   .. index::\n      pair: filename; replace_image\n      pair: pixmap; replace_image\n      pair: stream; replace_image\n      pair: xref; replace_image\n\n   .. method:: replace_image(xref, filename=None, pixmap=None, stream=None)\n\n      Replace the image at xref with another one.\n\n      :arg int xref: the :data:`xref` of the image.\n      :arg filename: the filename of the new image.\n      :arg pixmap: the :ref:`Pixmap` of the new image.\n      :arg stream: the memory area containing the new image.\n\n      Arguments `filename`, `pixmap`, `stream` have the same meaning as in :meth:`Page.insert_image`, especially exactly one of these must be provided.\n\n      This is a **global replacement:** the new image will also be shown wherever the old one has been displayed throughout the file.\n\n      This method mainly exists for technical purposes. Typical uses include replacing large images by smaller versions, like a lower resolution, graylevel instead of colored, etc., or changing transparency.\n\n      |history_begin|\n\n      * New in v1.21.0\n\n      |history_end|\n   \n   \n   .. index::\n      pair: xref; delete_image\n\n   .. method:: delete_image(xref)\n\n      Delete the image at xref. This is slightly misleading: actually the image is being replaced with a small transparent :ref:`Pixmap` using above :meth:`Page.replace_image`. The visible effect however is equivalent.\n\n      :arg int xref: the :data:`xref` of the image.\n\n      This is a **global replacement:** the image will disappear wherever the old one has been displayed throughout the file.\n   \n      If you inspect / extract a page's images by methods like :meth:`Page.get_images`,\n      :meth:`Page.get_image_info` or :meth:`Page.get_text`,\n      the replacing \"dummy\" image will be detected like so\n      `(45, 47, 1, 1, 8, 'DeviceGray', '', 'Im1', 'FlateDecode')`\n      and also seem to \"cover\" the same boundary box on the page.\n\n      |history_begin|\n\n      * New in v1.21.0\n\n      |history_end|\n\n   \n   .. index::\n      pair: blocks; Page.get_text\n      pair: dict; Page.get_text\n      pair: clip; Page.get_text\n      pair: flags; Page.get_text\n      pair: html; Page.get_text\n      pair: json; Page.get_text\n      pair: rawdict; Page.get_text\n      pair: text; Page.get_text\n      pair: words; Page.get_text\n      pair: xhtml; Page.get_text\n      pair: xml; Page.get_text\n      pair: textpage; Page.get_text\n      pair: sort; Page.get_text\n      pair: delimiters; Page.get_text\n\n   .. method:: get_text(option,*, clip=None, flags=None, textpage=None, sort=False, delimiters=None)\n\n      Retrieves the content of a page in a variety of formats. Depending on the ``flags`` value, this may include text, images and several other object types. The method is a wrapper for multiple :ref:`TextPage` methods by choosing the output option `opt` as follows:\n\n      * \"text\" -- :meth:`TextPage.extractTEXT`, default. Always includes **text only.**\n      * \"blocks\" -- :meth:`TextPage.extractBLOCKS`. Includes text and **may** include image meta information.\n      * \"words\" -- :meth:`TextPage.extractWORDS`. Always includes **text only.**\n      * \"html\" -- :meth:`TextPage.extractHTML`. May include text and images.\n      * \"xhtml\" -- :meth:`TextPage.extractXHTML`. May include text and images.\n      * \"xml\" -- :meth:`TextPage.extractXML`. Always includes **text only.**\n      * \"dict\" -- :meth:`TextPage.extractDICT`. May include text and images.\n      * \"json\" -- :meth:`TextPage.extractJSON`. May include text and images.\n      * \"rawdict\" -- :meth:`TextPage.extractRAWDICT`. May include text and images.\n      * \"rawjson\" -- :meth:`TextPage.extractRAWJSON`. May include text and images.\n\n      :arg str opt: A string indicating the requested format, one of the above. A mixture of upper and lower case is supported. If misspelled, option \"text\" is silently assumed.\n\n      :arg rect-like clip: restrict the extraction to this rectangle. If ``None`` (default), the visible part of the page is taken. Any content (text, images) that is **not fully contained** in ``clip`` will be completely omitted. To avoid clipping altogether use ``clip=pymupdf.INFINITE_RECT()``. Only then the extraction will contain all items. This parameter has **no effect** on options \"html\", \"xhtml\" and \"xml\".\n\n      :arg int flags: indicator bits to control whether to include images or how text should be handled with respect to white spaces and :data:`ligatures`. See :ref:`TextPreserve` for available indicators and :ref:`text_extraction_flags` for default settings. (New in v1.16.2)\n\n      :arg textpage: use a previously created :ref:`TextPage`. This reduces execution time **very significantly:** by more than 50% and up to 95%, depending on the extraction option. If specified, the 'flags' and 'clip' arguments are ignored, because they are textpage-only properties. If omitted, a new, temporary textpage will be created.\n\n      :arg bool sort: sort the output by vertical, then horizontal coordinates. In many cases, this should suffice to generate a \"natural\" reading order. Has no effect on (X)HTML and XML. For options \"blocks\", \"dict\", \"json\", \"rawdict\", \"rawjson\", sorting happens by coordinates `(y1, x0)` of the respective block bbox. For options \"words\" and \"text\", the text lines are completely re-synthesized to follow the reading sequence and appearance in the document -- which even establishes the original layout to some extent.\n\n      :arg str delimiters: use these characters as *additional* word separators with the \"words\" output option (ignored otherwise). By default, all white spaces (including non-breaking space `0xA0`) indicate start and end of a word. Now you can specify more characters causing this. For instance, the default will return `\"john.doe@outlook.com\"` as **one** word. If you specify `delimiters=\"@.\"` then the **four** words `\"john\"`, `\"doe\"`, `\"outlook\"`, `\"com\"` will be returned. Other possible uses include ignoring punctuation characters `delimiters=string.punctuation`. The \"word\" strings will not contain any delimiting character. (New in v1.23.5)\n\n      :rtype: *str, list, dict*\n      :returns: The page's content as a string, a list or a dictionary. Refer to the corresponding :ref:`TextPage` method for details.\n\n      .. note::\n\n        1. You can use this method as a **document conversion tool** from :ref:`any supported document type<Supported_File_Types>` to one of TEXT, HTML, XHTML or XML documents.\n        2. The inclusion of text via the *clip* parameter is decided on a by-character level: a character becomes part of the output, if its bbox is contained in `clip`. This **deviates** from the algorithm used in redaction annotations: a character will be **removed if its bbox intersects** any redaction annotation.\n\n      |history_begin|\n\n      * Changed in v1.19.0: added `textpage` parameter\n      * Changed in v1.19.1: added `sort` parameter\n      * Changed in v1.19.6: added new constants for defining default flags per method.\n      * Changed in v1.23.5: added `delimiters` parameter\n      * Changed in v1.24.11: changed the effect of `sort_True` for \"text\" and \"words\" to closely follow natural reading sequence.\n\n      |history_end|\n\n   .. index::\n      pair: rect; get_textbox\n      pair: textpage; get_textbox\n\n   .. method:: get_textbox(rect, textpage=None)\n\n      Retrieve the text contained in a rectangle.\n\n      :arg rect-like rect: rect-like.\n      :arg textpage: a :ref:`TextPage` to use. If omitted, a new, temporary textpage will be created.\n\n      :returns: a string with interspersed linebreaks where necessary. It is based on dedicated code (changed in v1.19.0). A typical use is checking the result of :meth:`Page.search_for`:\n\n        >>> rl = page.search_for(\"currency:\")\n        >>> page.get_textbox(rl[0])\n        'Currency:'\n        >>>\n\n      |history_begin|\n\n      * New in v1.17.7\n      * Changed in v1.19.0: add `textpage` parameter\n\n      |history_end|\n\n\n   .. index::\n      pair: flags; get_textpage\n      pair: clip; get_textpage\n\n   .. method:: get_textpage(clip=None, flags=3)\n\n      Create a :ref:`TextPage` for the page.\n\n      :arg int flags: indicator bits controlling the content available for subsequent text extractions and searches -- see the parameter of :meth:`Page.get_text`.\n\n      :arg rect-like clip: restrict extracted text to this area. (New in v1.17.7)\n\n      :returns: :ref:`TextPage`\n\n      |history_begin|\n\n      * New in v1.16.5\n      * Changed in v1.17.7: introduced `clip` parameter.\n\n      |history_end|\n\n\n   .. index::\n      pair: flags; get_textpage_ocr\n      pair: language; get_textpage_ocr\n      pair: dpi; get_textpage_ocr\n      pair: full; get_textpage_ocr\n      pair: tessdata; get_textpage_ocr\n\n   .. method:: get_textpage_ocr(flags=3, language=\"eng\", dpi=72, full=False, tessdata=None)\n\n      **Optical Character Recognition** (**OCR**) technology can be used to extract text data for pages where text is in raster image or vector graphic format. Use this method to **OCR** a page for subsequent text extraction.\n\n      This method returns a :ref:`TextPage` for the page that includes OCRed text. MuPDF will invoke Tesseract-OCR if this method is used.\n\n      :arg int flags: indicator bits controlling the content available for subsequent test extractions and searches -- see the parameter of :meth:`Page.get_text`.\n      :arg str language: the expected language(s). Use \"+\"-separated values if multiple languages are expected, \"eng+spa\" for English and Spanish.\n      :arg int dpi: the desired resolution in dots per inch. Influences recognition quality (and execution time).\n      :arg bool full: whether to OCR the full page, or only page areas that contain no legible text.\n      :arg str tessdata: The name of Tesseract's language support folder `tessdata`. If omitted, the name is determined using function :meth:`get_tessdata`.\n\n      .. note:: This method does **not** support a clip parameter -- OCR (full or partial) will always happen for the complete page rectangle.\n\n      :returns:\n      \n         a :ref:`TextPage`. Execution may be significantly longer than :meth:`Page.get_textpage`.\n\n      For ``full=True`` OCR, **all text** will have the font \"GlyphLessFont\" from Tesseract. In case of partial OCR (``full=False``), legible normal text will keep its properties, and only recognized text will have the GlyphLessFont.\n\n      Recognized / OCR text will follow (legible) normal text for partial OCR and will thus not be in reading order. Establishing reading order is -- as always -- your responsibility.\n\n      .. note::\n      \n         Text extraction results, including any OCR, are stored in the returned :ref:`TextPage`. To access them, you must use the ``textpage`` parameter in all subsequent text extraction and search methods.\n\n         `This Jupyter notebook <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/jupyter-notebooks/partial-ocr.ipynb>`_ walks through an example for using OCR textpages.\n\n      |history_begin|\n\n      * New in v.1.19.0\n      * Changed in v1.19.1: support full and partial OCRing a page.\n      * changed in v1.27.2: For partial OCR, **all** page areas outside legible text are now OCRed, not just those within images. This means that OCR will now also be performed for vector graphics, and for text containing illegible characters.\n\n      |history_end|\n\n\n   .. method:: get_drawings(extended=False)\n\n      Return the vector graphics of the page. These are instructions which draw lines, rectangles, quadruples or curves, including properties like colors, transparency, line width and dashing, etc. Alternative terms are \"line art\" and \"drawings\".\n\n      :returns: a list of dictionaries. Each dictionary item contains one or more single draw commands belonging together: they have the same properties (colors, dashing, etc.). This is called a **\"path\"** in PDF, so we adopted that name here, but the method **works for all document types**.\n\n      The path dictionary for fill, stroke and fill-stroke paths has been designed to be compatible with class :ref:`Shape`. There are the following keys:\n\n      ============== ============================================================================\n      Key            Value\n      ============== ============================================================================\n      closePath      Same as the parameter in :ref:`Shape`.\n      color          Stroke color (see :ref:`Shape`).\n      dashes         Dashed line specification (see :ref:`Shape`).\n      even_odd       Fill colors of area overlaps -- same as the parameter in :ref:`Shape`.\n      fill           Fill color  (see :ref:`Shape`).\n      items          List of draw commands: lines, rectangles, quads or curves.\n      lineCap        Number 3-tuple, use its max value on output with :ref:`Shape`.\n      lineJoin       Same as the parameter in :ref:`Shape`.\n      fill_opacity   fill color transparency (see :ref:`Shape`). (New in v1.18.17)\n      stroke_opacity stroke color transparency  (see :ref:`Shape`). (New in v1.18.17)\n      rect           Page area covered by this path. Information only.\n      layer          name of applicable Optional Content Group. (New in v1.22.0)\n      level          the hierarchy level if `extended=True`. (New in v1.22.0)\n      seqno          command number when building page appearance. (New in v1.19.0)\n      type           type of this path. (New in v1.18.17)\n      width          Stroke line width. (see :ref:`Shape`).\n      ============== ============================================================================\n\n      Key `\"opacity\"` has been replaced by the new keys `\"fill_opacity\"` and `\"stroke_opacity\"`. This is now compatible with the corresponding parameters of :meth:`Shape.finish`. (Changed in v1.18.17)\n\n\n      For paths other than groups or clips, key `\"type\"` takes one of the following values:\n\n      * **\"f\"** -- this is a *fill-only* path. Only key-values relevant for this operation have a meaning, not applicable ones are present with a value of ``None``: `\"color\"`, `\"lineCap\"`, `\"lineJoin\"`, `\"width\"`, `\"closePath\"`, `\"dashes\"` and should be ignored.\n      * **\"s\"** -- this is a *stroke-only* path. Similar to previous, key `\"fill\"` is present with value ``None``.\n      * **\"fs\"** -- this is a path performing combined *fill* and *stroke* operations.\n\n      Each item in `path[\"items\"]` is one of the following:\n\n      * `(\"l\", p1, p2)` - a line from p1 to p2 (:ref:`Point` objects).\n      * `(\"c\", p1, p2, p3, p4)` - cubic Bézier curve **from p1 to p4** (p2 and p3 are the control points). All objects are of type :ref:`Point`.\n      * `(\"re\", rect, orientation)` - a :ref:`Rect`. Multiple rectangles within the same path are now detected (changed in v1.18.17). Integer `orientation` is 1 resp. -1 indicating whether the enclosed area is rotated left (1 = anti-clockwise), or resp. right [#f7]_ (changed in v1.19.2).\n      * `(\"qu\", quad)` - a :ref:`Quad`. 3 or 4 consecutive lines are detected to actually represent a :ref:`Quad` (changed in v1.19.2:). (New in v1.18.17)\n\n      .. note::, quads and rectangles are more reliably recognized as such. (Starting with v1.19.2)\n\n      Using class :ref:`Shape`, you should be able to recreate the original drawings on a separate (PDF) page with high fidelity under normal, not too sophisticated circumstances. Please see the following comments on restrictions. A coding draft can be found in :ref:`How to Extract Drawings <RecipesDrawingAndGraphics_Extract_Drawings>`.\n\n      Specifying `extended=True` significantly alters the output. Most importantly, new dictionary types are present: \"clip\" and \"group\". All paths will now be organized in a hierarchic structure which is encoded by the new integer key \"level\", the hierarchy level. Each group or clip establishes a new hierarchy, which applies to all subsequent paths having a *larger* level value. (New in v1.22.0)\n\n      Any path with a smaller level value than its predecessor will end the scope of (at least) the preceding hierarchy level. A \"clip\" path with the same level as the preceding clip will end the scope of that clip. Same is true for groups. This is best explained by an example::\n\n         +------+------+--------+------+--------+\n         | line | lvl0 | lvl1   | lvl2 |  lvl3  |\n         +------+------+--------+------+--------+\n         |  0   | clip |        |      |        |\n         |  1   |      | fill   |      |        |\n         |  2   |      | group  |      |        |\n         |  3   |      |        | clip |        |\n         |  4   |      |        |      | stroke |\n         |  5   |      |        | fill |        |  ends scope of clip in line 3\n         |  6   |      | stroke |      |        |  ends scope of group in line 2\n         |  7   |      | clip   |      |        |\n         |  8   | fill |        |      |        |  ends scope of line 0\n         +------+------+--------+------+--------+\n\n      The clip in line 0 applies to line including line 7. Group in line 2 applies to lines 3 to 5, clip in line 3 only applies to line 4.\n\n      \"stroke\" in line 4 is under control of \"group\" in line 2 and \"clip\" in line 3 (which in turn is a subset of line 0 clip).\n\n      * **\"clip\"** dictionary. Its values (most importantly \"scissor\") remain valid / apply as long as following dictionaries have a **larger \"level\"** value.\n\n        ============== ============================================================================\n        Key            Value\n        ============== ============================================================================\n        closePath      Same as in \"stroke\" or \"fill\" dictionaries\n        even_odd       Same as in \"stroke\" or \"fill\" dictionaries\n        items          Same as in \"stroke\" or \"fill\" dictionaries\n        rect           Same as in \"stroke\" or \"fill\" dictionaries\n        layer          Same as in \"stroke\" or \"fill\" dictionaries\n        level          Same as in \"stroke\" or \"fill\" dictionaries\n        scissor        the clip rectangle\n        type           \"clip\"\n        ============== ============================================================================\n\n      * \"group\" dictionary. Its values remain valid (apply) as long as following dictionaries have a **larger \"level\"** value. Any dictionary with an equal or lower level end this group.\n\n        ============== ============================================================================\n        Key            Value\n        ============== ============================================================================\n        rect           Same as in \"stroke\" or \"fill\" dictionaries\n        layer          Same as in \"stroke\" or \"fill\" dictionaries\n        level          Same as in \"stroke\" or \"fill\" dictionaries\n        isolated       (bool) Whether this group is isolated\n        knockout       (bool) Whether this is a \"Knockout Group\"\n        blendmode      Name of the BlendMode, default is \"Normal\"\n        opacity        Float value in range [0, 1].\n        type           \"group\"\n        ============== ============================================================================\n\n      .. note:: The method is based on the output of :meth:`Page.get_cdrawings` -- which is much faster, but requires somewhat more attention processing its output.\n\n      |history_begin|\n      \n      * New in v1.18.0\n      * Changed in v1.18.17\n      * Changed in v1.19.0: add \"seqno\" key, remove \"clippings\" key\n      * Changed in v1.19.1: \"color\" / \"fill\" keys now always are either are RGB tuples or `None`. This resolves issues caused by exotic colorspaces.\n      * Changed in v1.19.2: add an indicator for the *\"orientation\"* of the area covered by an \"re\" item.\n      * Changed in v1.22.0: add new key `\"layer\"` which contains the name of the Optional Content Group of the path (or `None`).\n      * Changed in v1.22.0: add parameter `extended` to also return clipping and group paths.\n      \n      |history_end|\n\n\n\n   .. method:: get_cdrawings(extended=False)\n\n      Extract the vector graphics on the page. Apart from following technical differences, functionally equivalent to :meth:`Page.get_drawings`, but much faster:\n\n      * Every path type only contains the relevant keys, e.g. a stroke path has no `\"fill\"` color key. See comment in method :meth:`Page.get_drawings`.\n      * Coordinates are given as :data:`point_like`, :data:`rect_like` and :data:`quad_like` **tuples** -- not as :ref:`Point`, :ref:`Rect`, :ref:`Quad` objects.\n\n      If performance is a concern, consider using this method: Compared to versions earlier than 1.18.17, you should see much shorter response times. We have seen pages that required 2 seconds then, now only need 200 ms with this method.\n\n      |history_begin|\n\n      * New in v1.18.17\n      * Changed in v1.19.0: removed \"clippings\" key, added \"seqno\" key.\n      * Changed in v1.19.1: always generate RGB color tuples.\n      * Changed in v1.22.0: added new key `\"layer\"` which contains the name of the Optional Content Group of the path (or `None`).\n      * Changed in v1.22.0: added parameter `extended` to also return clipping paths.\n      \n      |history_end|\n\n\n   .. method:: get_fonts(full=False)\n\n      PDF only: Return a list of fonts referenced by the page. Wrapper for :meth:`Document.get_page_fonts`.\n\n\n   .. method:: get_images(full=False)\n\n      PDF only: Return a list of images referenced by the page. Wrapper for :meth:`Document.get_page_images`.\n\n\n   .. index::\n      pair: hashes; get_image_info\n      pair: xrefs; get_image_info\n\n   .. method:: get_image_info(hashes=False, xrefs=False)\n\n      Return a list of meta information dictionaries for all images displayed by the page. This works for all document types.\n\n      :arg bool hashes: Compute the MD5 hashcode for each encountered image, which allows identifying image duplicates. This adds the key `\"digest\"` to the output, whose value is a 16 byte `bytes` object. (New in v1.18.13)\n\n      :arg bool xrefs: **PDF only.** Try to find the :data:`xref` for each image. Implies `hashes=True`. Adds the `\"xref\"` key to the dictionary. If not found, the value is 0, which means, the image is either \"inline\" or its xref is undetectable for some reason. Please note that this option has an extended response time, because the MD5 hashcode will be computed at least two times for each image with an xref. (New in v1.18.13)\n\n      :rtype: list[dict]\n      :returns: A list of dictionaries. This includes information for **exactly those** images, that are shown on the page -- including *\"inline images\"*. The dictionary layout is similar to that of image blocks in `page.get_text(\"dict\")`.\n      \n         In contrast to images included in :meth:`Page.get_text`, image **binary content** is not loaded by this method, which drastically reduces memory usage. Another difference is that image detection is not restricted to the visible part of the page or any ``clip`` parameter: method :meth:`Page.get_text` will only extract images **fully contained** in the provided ``clip``.\n\n         =============== ===============================================================\n         **Key**             **Value**\n         =============== ===============================================================\n         number          block number (``int``)\n         bbox            image bbox on page, :data:`rect_like`\n         width           original image width (``int``)\n         height          original image height (``int``)\n         cs-name         colorspace name (``str``)\n         colorspace      colorspace.n (``int``)\n         xres            resolution in x-direction (``int``) [#f10]_\n         yres            resolution in y-direction (``int``) [#f10]_\n         bpc             bits per component (``int``)\n         size            storage occupied by image (``int``)\n         digest          MD5 hashcode (``bytes``), if ``hashes`` is true\n         xref            image :data:`xref` or 0, if *xrefs* is true\n         transform       matrix transforming image rect to bbox, :data:`matrix_like`\n         has-mask        whether the image is transparent and has a mask (``bool``)\n         =============== ===============================================================\n\n         Multiple occurrences of the same image are always reported. You can detect duplicates by comparing their `digest` values.\n\n      |history_begin|\n\n      * New in v1.18.11\n      * Changed in v1.18.13: added image MD5 hashcode computation and :data:`xref` search.\n\n      |history_end|\n\n\n   .. method:: get_xobjects()\n\n      PDF only: Return a list of Form XObjects referenced by the page. Wrapper for :meth:`Document.get_page_xobjects`.\n\n\n   .. index::\n      pair: transform; get_image_rects\n\n   .. method:: get_image_rects(item, transform=False)\n\n      PDF only: Return boundary boxes and transformation matrices of an embedded image. This is an improved version of :meth:`Page.get_image_bbox` with the following differences:\n\n      * There is no restriction on **how** the image is invoked (by the page or one of its Form XObjects). The result is always complete and correct.\n      * The result is a list of :ref:`Rect` or (:ref:`Rect`, :ref:`Matrix`) objects -- depending on *transform*. Each list item represents one location of the image on the page. Multiple occurrences might not be detectable by :meth:`Page.get_image_bbox`.\n      * The method invokes :meth:`Page.get_image_info` with `xrefs=True` and therefore has a noticeably longer response time than :meth:`Page.get_image_bbox`.\n\n      :arg list,str,int item: an item of the list :meth:`Page.get_images`, or the reference **name** entry of such an item (item[7]), or the image :data:`xref`.\n      :arg bool transform: also return the matrix used to transform the image rectangle to the bbox on the page. If true, then tuples `(bbox, matrix)` are returned.\n\n      :rtype: list\n      :returns: Boundary boxes and respective transformation matrices for each image occurrence on the page. If the item is not on the page, an empty list `[]` is returned.\n\n      |history_begin|\n\n      New in v1.18.13\n\n      |history_end|\n\n\n   .. index::\n      pair: transform; get_image_bbox\n\n   .. method:: get_image_bbox(item, transform=False)\n\n      PDF only: Return boundary box and transformation matrix of an embedded image.\n\n      :arg list,str item: an item of the list :meth:`Page.get_images` with *full=True* specified, or the reference **name** entry of such an item, which is item[-3] (or item[7] respectively).\n      :arg bool transform: return the matrix used to transform the image rectangle to the bbox on the page (new in v1.18.11). Default is just the bbox. If true, then a tuple `(bbox, matrix)` is returned.\n\n      :rtype: :ref:`Rect` or (:ref:`Rect`, :ref:`Matrix`)\n      :returns: the boundary box of the image -- optionally also its transformation matrix.\n\n        |history_begin|\n        \n        * (Changed in v1.16.7): If the page in fact does not display this image, an infinite rectangle is returned now. In previous versions, an exception was raised. Formally invalid parameters still raise exceptions.\n        * (Changed in v1.17.0): Only images referenced directly by the page are considered. This means that images occurring in embedded PDF pages are ignored and an exception is raised.\n        * (Changed in v1.18.5): Removed the restriction introduced in v1.17.0: any item of the page's image list may be specified.\n        * (Changed in v1.18.11): Partially re-instated a restriction: only those images are considered, that are either directly referenced by the page or by a Form XObject directly referenced by the page.\n        * (Changed in v1.18.11): Optionally also return the transformation matrix together with the bbox as the tuple `(bbox, transform)`.\n\n        |history_end|\n\n      .. note::\n\n         1. Be aware that :meth:`Page.get_images` may contain \"dead\" entries i.e. images, which the page **does not display**. This is no error, but intended by the PDF creator. No exception will be raised in this case, but an infinite rectangle is returned. You can avoid this from happening by executing :meth:`Page.clean_contents` before this method.\n         2. The image's \"transformation matrix\" is defined as the matrix, for which the expression `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` is true, lookup details here: :ref:`ImageTransformation`.\n\n      |history_begin|\n\n      * Changed in v1.18.11: return image transformation matrix\n\n      |history_end|\n\n   .. index::\n      pair: matrix; get_svg_image\n\n   .. method:: get_svg_image(matrix=pymupdf.Identity, text_as_path=True)\n\n     Create an SVG image from the page. Only full page images are currently supported.\n\n     :arg matrix_like matrix: a matrix, default is :ref:`Identity`.\n     :arg bool text_as_path: -- controls how text is represented. ``True`` outputs each character as a series of elementary draw commands, which leads to a more precise text display in browsers, but a **very much larger** output for text-oriented pages. Display quality for ``False`` relies on the presence of the referenced fonts on the current system. For missing fonts, the internet browser will fall back to some default -- leading to unpleasant appearances. Choose ``False`` if you want to parse the text of the SVG. (New in v1.17.5)\n\n     :returns: a UTF-8 encoded string that contains the image. Because SVG has XML syntax it can be saved in a text file, the standard extension is `.svg`.\n\n         .. note:: In case of a PDF, you can circumvent the \"full page image only\" restriction by modifying the page's CropBox before using the method.\n\n   .. index::\n      pair: alpha; get_pixmap\n      pair: annots; get_pixmap\n      pair: clip; get_pixmap\n      pair: colorspace; get_pixmap\n      pair: matrix; get_pixmap\n      pair: dpi; get_pixmap\n\n   .. method:: get_pixmap(*, matrix=pymupdf.Identity, dpi=None, colorspace=pymupdf.csRGB, clip=None, alpha=False, annots=True)\n\n     Create a pixmap from the page. This is probably the most often used method to create a :ref:`Pixmap`.\n\n     All parameters are *keyword-only.*\n\n     :arg matrix_like matrix: default is :ref:`Identity`.\n     :arg int dpi: desired resolution in x and y direction. If not `None`, the `\"matrix\"` parameter is ignored. (New in v1.19.2)\n     :arg colorspace: The desired colorspace, one of \"GRAY\", \"RGB\" or \"CMYK\" (case insensitive). Or specify a :ref:`Colorspace`, ie. one of the predefined ones: :data:`csGRAY`, :data:`csRGB` or :data:`csCMYK`.\n     :type colorspace: str or :ref:`Colorspace`\n     :arg irect_like clip: restrict rendering to the intersection of this area with the page's rectangle.\n     :arg bool alpha: whether to add an alpha channel. Always accept the default ``False`` if you do not really need transparency. This will save a lot of memory (25% in case of RGB ... and pixmaps are typically **large**!), and also processing time. Also note an **important difference** in how the image will be rendered: with ``True`` the pixmap's samples area will be pre-cleared with *0x00*. This results in **transparent** areas where the page is empty. With ``False`` the pixmap's samples will be pre-cleared with *0xff*. This results in **white** where the page has nothing to show.\n\n       |history_begin|\n      \n       Changed in v1.14.17\n         The default alpha value is now ``False``.\n\n         * Generated with *alpha=True*\n\n         .. image:: images/img-alpha-1.*\n\n\n         * Generated with *alpha=False*\n\n         .. image:: images/img-alpha-0.*\n\n       |history_end|\n\n     :arg bool annots: *(new in version 1.16.0)* whether to also render annotations or to suppress them. You can create pixmaps for annotations separately.\n\n     :rtype: :ref:`Pixmap`\n     :returns: Pixmap of the page. For fine-controlling the generated image, the by far most important parameter is **matrix**. E.g. you can increase or decrease the image resolution by using **Matrix(xzoom, yzoom)**. If zoom > 1, you will get a higher resolution: zoom=2 will double the number of pixels in that direction and thus generate a 2 times larger image. Non-positive values will flip horizontally, resp. vertically. Similarly, matrices also let you rotate or shear, and you can combine effects via e.g. matrix multiplication. See the :ref:`Matrix` section to learn more.\n\n     .. note::\n\n         * The pixmap will have *\"premultiplied\"* pixels if `alpha=True`. To learn about some background, e.g. look for \"Premultiplied alpha\" `here <https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\n\n         * The method will respect any page rotation and will not exceed the intersection of `clip` and :attr:`Page.cropbox`. If you need the page's mediabox (and if this is a different rectangle), you can use a snippet like the following to achieve this::\n\n            In [1]: import pymupdf\n            In [2]: doc=pymupdf.open(\"demo1.pdf\")\n            In [3]: page=doc[0]\n            In [4]: rotation = page.rotation\n            In [5]: cropbox = page.cropbox\n            In [6]: page.set_cropbox(page.mediabox)\n            In [7]: page.set_rotation(0)\n            In [8]: pix = page.get_pixmap()\n            In [9]: page.set_cropbox(cropbox)\n            In [10]: if rotation != 0:\n               ...:     page.set_rotation(rotation)\n               ...:\n            In [11]:\n\n     |history_begin|\n\n     * Changed in v1.19.2: added support of parameter dpi.\n\n     |history_end|\n\n\n\n   .. method:: annot_names()\n\n      PDF only: return a list of the names of annotations, widgets and links. Technically, these are the */NM* values of every PDF object found in the page's */Annots*  array.\n\n      :rtype: list\n\n      |history_begin|\n\n      * New in v1.16.10\n\n      |history_end|\n\n\n   .. method:: annot_xrefs()\n\n      PDF only: return a list of the :data:`xref` numbers of annotations, widgets and links -- technically of all entries found in the page's */Annots*  array.\n\n      :rtype: list\n      :returns: a list of items *(xref, type)* where type is the annotation type. Use the type to tell apart links, fields and annotations, see :ref:`AnnotationTypes`.\n\n      |history_begin|\n\n      * New in v1.17.1\n\n      |history_end|\n\n\n   .. method:: load_annot(ident)\n\n      PDF only: return the annotation identified by *ident*. This may be its unique name (PDF `/NM` key), or its :data:`xref`.\n\n      :arg str,int ident: the annotation name or xref.\n\n      :rtype: :ref:`Annot`\n      :returns: the annotation or ``None``.\n\n      .. note:: Methods :meth:`Page.annot_names`, :meth:`Page.annot_xrefs` provide lists of names or xrefs, respectively, from where an item may be picked and loaded via this method.\n\n      |history_begin|\n\n      * New in v1.17.1\n\n      |history_end|\n\n   .. method:: load_widget(xref)\n\n      PDF only: return the field identified by :data:`xref`.\n\n      :arg int xref: the field's xref.\n\n      :rtype: :ref:`Widget`\n      :returns: the field or ``None``.\n\n      .. note:: This is similar to the analogous method :meth:`Page.load_annot` -- except that here only the xref is supported as identifier.\n\n      |history_begin|\n\n      * New in v1.19.6\n\n      |history_end|\n\n   .. method:: load_links()\n\n      Return the first link on a page. Synonym of property :attr:`first_link`.\n\n      :rtype: :ref:`Link`\n      :returns: first link on the page (or ``None``).\n\n   .. index::\n      pair: rotate; set_rotation\n\n   .. method:: set_rotation(rotate)\n\n      PDF only: Set the rotation of the page.\n\n      :arg int rotate: An integer specifying the required rotation in degrees. Must be an integer multiple of 90. Values will be converted to one of 0, 90, 180, 270.\n\n   .. method:: recolor(components=1)\n\n      PDF only: Change the colorspace components of all objects on page.\n\n      :arg int components: The desired count of color components. Must be one of 1, 3 or 4, which results in color spaces DeviceGray, DeviceRGB or DeviceCMYK respectively. The method affects text, images and vector graphics. For instance, with the default value 1, a page will be converted to grayscale. If a page is already grayscale, the method will not cause visible changes -- independent of the value of ``components``.\n\n      These changes are **permanent** and cannot be reverted.\n\n   .. method:: clip_to_rect(rect)\n\n      PDF only: Permanently remove page content outside the given rectangle. This is similar to :meth:`Page.set_cropbox`, but the page's rectangle will not be changed, only the content outside the rectangle will be removed.\n\n      :arg rect_like rect: The rectangle to clip to. Must be finite and its intersection with the page must not be empty.\n\n      The method works best for text: All text on the page will be removed (decided by single character) that has no intersection with the rectangle. For vector graphics, the method will remove all paths that have no intersection with the rectangle. For images, the method will remove all images that have no intersection with the rectangle. Vectors and images **having** an intersection with the rectangle, will be kept in their entirety.\n\n      The method roughly has the same effect as if four redactions had been applied that cover the rectangle's outside.\n      \n      * New in v1.26.4.\n\n   .. method:: remove_rotation()\n\n      PDF only: Set page rotation to 0 while maintaining appearance and page content.\n\n      :returns: The inverted matrix used to achieve this change. If the page was not rotated (rotation 0), :ref:`Identity` is returned. The method automatically recomputes the rectangles of any annotations, links and widgets present on the page.\n\n         This method may come in handy when e.g. used with :meth:`Page.show_pdf_page`.\n\n   .. index::\n      pair: clip; show_pdf_page\n      pair: keep_proportion; show_pdf_page\n      pair: overlay; show_pdf_page\n      pair: rotate; show_pdf_page\n\n   .. method:: show_pdf_page(rect, docsrc, pno=0, keep_proportion=True, overlay=True, oc=0, rotate=0, clip=None)\n\n      PDF only: Display a page of another PDF. This is similar to :meth:`Page.insert_image` but the source page will appear like a copy of itself and will not be rasterized. This is a multi-purpose method. For example, you can use it to:\n\n      * create \"n-up\" versions of existing PDF files, combining several input pages into **one output page** (see example `combine.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/combine-pages/combine.py>`_),\n      * create \"posterized\" PDF files, i.e. every input page is split up in parts which each create a separate output page (see `posterize.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/posterize-document/posterize.py>`_),\n      * include PDF-based vector images like company logos, watermarks, etc., see `svg.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/insert-logo/svg.py>`_, which puts an SVG-based logo on each page.\n\n      :arg rect_like rect: where to place the image on current page. Must be finite and its intersection with the page must not be empty.\n      :arg docsrc: source PDF document containing the page. Must be a different document object, but may be the same file.\n      :type docsrc: :ref:`Document`\n\n      :arg int pno: page number (0-based, in `-∞ < pno < docsrc.page_count`) to be shown.\n\n      :arg bool keep_proportion: whether to maintain the width-height-ratio (default). If false, all 4 corners are always positioned on the border of the target rectangle -- whatever the rotation value. In general, this will deliver distorted and /or non-rectangular images.\n\n      :arg bool overlay: put image in foreground (default) or background.\n\n      :arg int oc: (:data:`xref`) make visibility dependent on this :data:`OCG` / :data:`OCMD` (which must be defined in the target PDF) [#f9]_. (New in v1.18.3)\n      :arg float rotate: show the source rectangle rotated by some angle. Any angle is supported (changed in v1.14.11). (New in v1.14.10)\n\n      :arg rect_like clip: choose which part of the source page to show. Default is the full page, else must be finite and its intersection with the source page must not be empty.\n\n      .. note:: In contrast to method :meth:`Document.insert_pdf`, this method does not copy annotations, widgets or links, so these objects are not included in the target [#f6]_. But all its **other resources (text, images, fonts, etc.)** will be imported into the current PDF. They will therefore appear in text extractions and in :meth:`get_fonts` and :meth:`get_images` lists -- even if they are not contained in the visible area given by *clip*.\n\n      Example: Show the same source page, rotated by 90 and by -90 degrees:\n\n      >>> doc = pymupdf.open()  # new empty PDF\n      >>> page=doc.new_page()  # new page in A4 format\n      >>>\n      >>> # upper half page\n      >>> r1 = pymupdf.Rect(0, 0, page.rect.width, page.rect.height/2)\n      >>>\n      >>> # lower half page\n      >>> r2 = r1 + (0, page.rect.height/2, 0, page.rect.height/2)\n      >>>\n      >>> src = pymupdf.open(\"PyMuPDF.pdf\")  # show page 0 of this\n      >>>\n      >>> page.show_pdf_page(r1, src, 0, rotate=90)\n      >>> page.show_pdf_page(r2, src, 0, rotate=-90)\n      >>> doc.save(\"show.pdf\")\n\n      .. image:: images/img-showpdfpage.*\n         :scale: 70\n\n      |history_begin|\n\n      * Changed in v1.14.11: Parameter *reuse_xref* has been deprecated. Position the source rectangle centered in target rectangle. Any rotation angle is now supported.\n      * Changed in v1.18.3: New parameter `oc`.\n\n      |history_end|\n\n   .. method:: new_shape()\n\n      PDF only: Create a new :ref:`Shape` object for the page.\n\n      :rtype: :ref:`Shape`\n      :returns: a new :ref:`Shape` to use for compound drawings. See description there.\n\n\n   .. index::\n      pair: flags; search_for\n      pair: quads; search_for\n      pair: clip; search_for\n      pair: textpage; search_for\n\n   .. method:: search_for(needle, *, clip=None, quads=False, flags=TEXT_DEHYPHENATE | TEXT_PRESERVE_WHITESPACE | TEXT_PRESERVE_LIGATURES | TEXT_MEDIABOX_CLIP, textpage=None)\n\n      Search for *needle* on a page. Wrapper for :meth:`TextPage.search`.\n\n      :arg str needle: Text to search for. May contain spaces. Upper / lower case is ignored, but only works for ASCII characters: For example, \"COMPÉTENCES\" will not be found if needle is \"compétences\" -- \"compÉtences\" however will. Similar is true for German umlauts and the like.\n      :arg rect_like clip: only search within this area. (New in v1.18.2)\n      :arg bool quads: Return object type :ref:`Quad` instead of :ref:`Rect`.\n      :arg int flags: Control the data extracted by the underlying :ref:`TextPage`. By default, ligatures and white spaces are kept, and hyphenation [#f8]_ is detected.\n      :arg textpage: use a previously created :ref:`TextPage`. This reduces execution time **significantly.** If specified, the 'flags' and 'clip' arguments are ignored. If omitted, a temporary textpage will be created. (New in v1.19.0)\n\n      :rtype: list\n\n      :returns:\n\n        A list of :ref:`Rect` or  :ref:`Quad` objects, each of which  -- **normally!** -- surrounds one occurrence of *needle*. **However:** if parts of *needle* occur on more than one line, then a separate item is generated for each these parts. So, if `needle = \"search string\"`, two rectangles may be generated.\n\n        |history_begin|\n        \n        Changes in v1.18.2:\n\n        * There no longer is a limit on the list length (removal of the `hit_max` parameter).\n        * If a word is **hyphenated** at a line break, it will still be found. E.g. the needle \"method\" will be found even if hyphenated as \"meth-od\" at a line break, and two rectangles will be returned: one surrounding \"meth\" (without the hyphen) and another one surrounding \"od\".\n\n        |history_end|\n\n      .. note:: The method supports multi-line text marker annotations: you can use the full returned list as **one single** parameter for creating the annotation.\n\n      .. caution::\n\n         * There is a tricky aspect: the search logic regards **contiguous multiple occurrences** of *needle* as one: assuming *needle* is \"abc\", and the page contains \"abc\" and \"abcabc\", then only **two** rectangles will be returned, one for \"abc\", and a second one for \"abcabc\".\n         * You can always use :meth:`Page.get_textbox` to check what text actually is being surrounded by each rectangle.\n\n      .. note:: A feature repeatedly asked for is supporting **regular expressions** when specifying the `\"needle\"` string: **There is no way to do this.** If you need something in that direction, first extract text in the desired format and then subselect the result by matching with some regex pattern. Here is an example for matching words::\n\n         >>> pattern = re.compile(r\"...\")  # the regex pattern\n         >>> words = page.get_text(\"words\")  # extract words on page\n         >>> matches = [w for w in words if pattern.search(w[4])]\n\n         The `matches` list will contain the words matching the given pattern. In the same way you can select `span[\"text\"]` from the output of `page.get_text(\"dict\")`.\n\n      |history_begin|\n\n      * Changed in v1.18.2: added `clip` parameter. Remove `hit_max` parameter. Add default \"dehyphenate\".\n      * Changed in v1.19.0: added `textpage` parameter.\n\n      |history_end|\n\n\n   .. method:: set_mediabox(r)\n\n      PDF only: Change the physical page dimension by setting :data:`mediabox` in the page's object definition.\n\n      :arg rect-like r: the new :data:`mediabox` value.\n\n      .. note:: This method also removes the page's other (optional) rectangles (:data:`cropbox`, ArtBox, TrimBox and Bleedbox) to prevent inconsistent situations. This will cause those to assume their default values.\n\n      .. caution:: For non-empty pages this may have undesired effects, because the location of all content depends on this value and will therefore change position or even disappear.\n\n      |history_begin|\n\n      * New in v1.16.13\n      * Changed in v1.19.4: remove all other rectangle definitions.\n\n      |history_end|\n\n\n   .. method:: set_cropbox(r)\n\n      PDF only: change the visible part of the page.\n\n      :arg rect_like r: the new visible area of the page. Note that this **must** be specified in **unrotated coordinates**, not empty, nor infinite and be completely contained in the :attr:`Page.mediabox`.\n\n      After execution **(if the page is not rotated)**, :attr:`Page.rect` will equal this rectangle, but be shifted to the top-left position (0, 0) if necessary. Example session:\n\n      >>> page = doc.new_page()\n      >>> page.rect\n      pymupdf.Rect(0.0, 0.0, 595.0, 842.0)\n      >>>\n      >>> page.cropbox  # cropbox and mediabox still equal\n      pymupdf.Rect(0.0, 0.0, 595.0, 842.0)\n      >>>\n      >>> # now set cropbox to a part of the page\n      >>> page.set_cropbox(pymupdf.Rect(100, 100, 400, 400))\n      >>> # this will also change the \"rect\" property:\n      >>> page.rect\n      pymupdf.Rect(0.0, 0.0, 300.0, 300.0)\n      >>>\n      >>> # but mediabox remains unaffected\n      >>> page.mediabox\n      pymupdf.Rect(0.0, 0.0, 595.0, 842.0)\n      >>>\n      >>> # revert CropBox change\n      >>> # either set it to MediaBox\n      >>> page.set_cropbox(page.mediabox)\n      >>> # or 'refresh' MediaBox: will remove all other rectangles\n      >>> page.set_mediabox(page.mediabox)\n\n   .. method:: set_artbox(r)\n\n   .. method:: set_bleedbox(r)\n\n   .. method:: set_trimbox(r)\n\n      PDF only: Set the resp. rectangle in the page object. For the meaning of these objects see :ref:`AdobeManual`, page 77. Parameter and restrictions are the same as for :meth:`Page.set_cropbox`.\n\n      |history_begin|\n\n      * New in v1.19.4\n\n      |history_end|\n\n   .. attribute:: rotation\n\n      Contains the rotation of the page in degrees (always 0 for non-PDF types). This is a copy of the value in the PDF file. The PDF documentation says:\n      \n         *\"The number of degrees by which the page should be rotated clockwise when displayed or printed. The value must be a multiple of 90. Default value: 0.\"*\n\n         In PyMuPDF, we make sure that this attribute is always one of 0, 90, 180 or 270.\n\n      :type: int\n\n   .. attribute:: cropbox_position\n\n      Contains the top-left point of the page's `/CropBox` for a PDF, otherwise *Point(0, 0)*.\n\n      :type: :ref:`Point`\n\n   .. attribute:: cropbox\n\n      The page's `/CropBox` for a PDF. Always the **unrotated** page rectangle is returned. For a non-PDF this will always equal the page rectangle.\n\n      .. note:: In PDF, the relationship between `/MediaBox`, `/CropBox` and page rectangle may sometimes be confusing, please do lookup the glossary for :data:`MediaBox`.\n\n      :type: :ref:`Rect`\n\n   .. attribute:: artbox\n\n   .. attribute:: bleedbox\n\n   .. attribute:: trimbox\n\n      The page's `/ArtBox`, `/BleedBox`, `/TrimBox`, respectively. If not provided, defaulting to :attr:`Page.cropbox`.\n\n      :type: :ref:`Rect`\n\n   .. attribute:: mediabox_size\n\n      Contains the width and height of the page's :attr:`Page.mediabox` for a PDF, otherwise the bottom-right coordinates of :attr:`Page.rect`.\n\n      :type: :ref:`Point`\n\n   .. attribute:: mediabox\n\n      The page's :data:`mediabox` for a PDF, otherwise :attr:`Page.rect`.\n\n      :type: :ref:`Rect`\n\n      .. note:: For most PDF documents and for **all other document types**, `page.rect == page.cropbox == page.mediabox` is true. However, for some PDFs the visible page is a true subset of :data:`mediabox`. Also, if the page is rotated, its `Page.rect` may not equal `Page.cropbox`. In these cases the above attributes help to correctly locate page elements.\n\n   .. attribute:: transformation_matrix\n\n      This matrix translates coordinates from the PDF space to the MuPDF space. For example, in PDF `/Rect [x0 y0 x1 y1]` the pair (x0, y0) specifies the **bottom-left** point of the rectangle -- in contrast to MuPDF's system, where (x0, y0) specify top-left. Multiplying the PDF coordinates with this matrix will deliver the (Py-) MuPDF rectangle version. Obviously, the inverse matrix will again yield the PDF rectangle.\n\n      :type: :ref:`Matrix`\n\n   .. attribute:: rotation_matrix\n\n   .. attribute:: derotation_matrix\n\n      These matrices may be used for dealing with rotated PDF pages. When adding / inserting anything to a PDF page, the coordinates of the **unrotated** page are always used. These matrices help translating between the two states. Example: if a page is rotated by 90 degrees -- what would then be the coordinates of the top-left Point(0, 0) of an A4 page?\n\n         >>> page.set_rotation(90)  # rotate an ISO A4 page\n         >>> page.rect\n         Rect(0.0, 0.0, 842.0, 595.0)\n         >>> p = pymupdf.Point(0, 0)  # where did top-left point land?\n         >>> p * page.rotation_matrix\n         Point(842.0, 0.0)\n         >>>\n\n      :type: :ref:`Matrix`\n\n   .. attribute:: first_link\n\n      Contains the first :ref:`Link` of a page (or ``None``).\n\n      :type: :ref:`Link`\n\n   .. attribute:: first_annot\n\n      Contains the first :ref:`Annot` of a page (or ``None``).\n\n      :type: :ref:`Annot`\n\n   .. attribute:: first_widget\n\n      Contains the first :ref:`Widget` of a page (or ``None``).\n\n      :type: :ref:`Widget`\n\n   .. attribute:: number\n\n      The page number.\n\n      :type: int\n\n   .. attribute:: parent\n\n      The owning document object.\n\n      :type: :ref:`Document`\n\n\n   .. attribute:: rect\n\n      Contains the rectangle of the page. Same as result of :meth:`Page.bound()`.\n\n      :type: :ref:`Rect`\n\n   .. attribute:: xref\n\n      The page's PDF :data:`xref`. Zero if not a PDF.\n\n      :type: :ref:`Rect`\n\n-----\n\n.. _link_dict_description:\n\nDescription of *get_links()* Entries\n----------------------------------------\nEach entry of the :meth:`Page.get_links` list is a dictionary with the following keys:\n\n* *kind*:  (required) an integer indicating the kind of link. This is one of *LINK_NONE*, *LINK_GOTO*, *LINK_GOTOR*, *LINK_LAUNCH*, or *LINK_URI*. For values and meaning of these names refer to :ref:`linkDest Kinds`.\n\n* *from*:  (required) a :ref:`Rect` describing the \"hot spot\" location on the page's visible representation (where the cursor changes to a hand image, usually).\n\n* *page*:  a 0-based integer indicating the destination page. Required for *LINK_GOTO* and *LINK_GOTOR*, else ignored.\n\n* *to*:   either a *pymupdf.Point*, specifying the destination location on the provided page, default is *pymupdf.Point(0, 0)*, or a symbolic (indirect) name. If an indirect name is specified, *page = -1* is required and the name must be defined in the PDF in order for this to work. Required for *LINK_GOTO* and *LINK_GOTOR*, else ignored.\n\n* *file*: a string specifying the destination file. Required for *LINK_GOTOR* and *LINK_LAUNCH*, else ignored.\n\n* *uri*:  a string specifying the destination internet resource. Required for *LINK_URI*, else ignored. You should make sure to start this string with an unambiguous substring, that classifies the subtype of the URL, like `\"http://\"`, `\"https://\"`, `\"file://\"`, `\"ftp://\"`, `\"mailto:\"`, etc. Otherwise your browser will try to interpret the text and come to unwanted / unexpected conclusions about the intended URL type.\n\n* :data:`xref`: an integer specifying the PDF :data:`xref` of the link object. Do not change this entry in any way. Required for link deletion and update, otherwise ignored. For non-PDF documents, this entry contains *-1*. It is also *-1* for **all** entries in the *get_links()* list, if **any** of the links is not supported by MuPDF - see :ref:`notes_on_supporting_links`.\n\n.. _notes_on_supporting_links:\n\nNotes on Supporting Links\n---------------------------\nMuPDF's support for links has changed in **v1.10a**. These changes affect link types :data:`LINK_GOTO` and :data:`LINK_GOTOR`.\n\nReading (pertains to method *get_links()* and the *first_link* property chain)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf MuPDF detects a link to another file, it will supply either a *LINK_GOTOR* or a *LINK_LAUNCH* link kind. In case of *LINK_GOTOR* destination details may either be given as page number (eventually including position information), or as an indirect destination.\n\nIf an indirect destination is given, then this is indicated by *page = -1*, and *link.dest.dest* will contain this name. The dictionaries in the *get_links()* list will contain this information as the *to* value.\n\n**Internal links are always** of kind *LINK_GOTO*. If an internal link specifies an indirect destination, it **will always be resolved** and the resulting direct destination will be returned. Names are **never returned for internal links**, and undefined destinations will cause the link to be ignored.\n\nWriting\n~~~~~~~~~\n\nPyMuPDF writes (updates, inserts) links by constructing and writing the appropriate PDF object **source**. This makes it possible to specify indirect destinations for *LINK_GOTOR* **and** *LINK_GOTO* link kinds (pre *PDF 1.2* file formats are **not supported**).\n\n.. warning:: If a *LINK_GOTO* indirect destination specifies an undefined name, this link can later on not be found / read again with MuPDF / PyMuPDF. Other readers however **will** detect it, but flag it as erroneous.\n\nIndirect *LINK_GOTOR* destinations can in general of course not be checked for validity and are therefore **always accepted**.\n\n**Example: How to insert a link pointing to another page in the same document**\n\n1. Determine the rectangle on the current page, where the link should be placed. This may be the bbox of an image or some text.\n\n2. Determine the target page number (\"pno\", 0-based) and a :ref:`Point` on it, where the link should be directed to.\n\n3. Create a dictionary `d = {\"kind\": pymupdf.LINK_GOTO, \"page\": pno, \"from\": bbox, \"to\": point}`.\n\n4. Execute `page.insert_link(d)`.\n\n\nHomologous Methods of :ref:`Document` and :ref:`Page`\n--------------------------------------------------------\nThis is an overview of homologous methods on the :ref:`Document` and on the :ref:`Page` level.\n\n====================================== =====================================\n**Document Level**                     **Page Level**\n====================================== =====================================\n:meth:`Document.get_page_fonts`        :meth:`Page.get_fonts`\n:meth:`Document.get_page_images`       :meth:`Page.get_images`\n:meth:`Document.get_page_pixmap`       :meth:`Page.get_pixmap`\n:meth:`Document.get_page_text`         :meth:`Page.get_text`\n:meth:`Document.search_page_for`       :meth:`Page.search_for`\n====================================== =====================================\n\n.. note::\n\n   Most document methods (left column) exist for convenience reasons, and are just wrappers for: *Document[pno].<page method>*. So they **load and discard the page** on each execution.\n\n   However, the first two methods work differently. They only need a page's object definition statement - the page itself will **not** be loaded. So e.g. :meth:`Page.get_fonts` is a wrapper the other way round and defined as follows: `page.get_fonts` == `page.parent.get_page_fonts(page.number)`.\n\n\nWhen calling the :ref:`Document` equivalent methods then the page number is sent through as a parameter, e.g.:\n\n`Document.get_page_images(pno)` or `Document.get_page_text(pno)`\n\n.. tip::\n\n   The page number parameter, ``pno``, is a 0-based integer `-∞ < pno < page_count`.\n\n\n\n\n\nTables and Related Classes\n------------------------------------\n\nThe `TableFinder` class is returned by :meth:`Page.find_tables` and has related classes as follows:\n\n\n.. class:: TableFinder\n\n   An object always returned by :meth:`Page.find_tables`. Attributes of interest:\n\n   .. attribute:: tables\n\n      A list of :class:`Table` objects, each of which represents a table found on the page. An empty list if no tables are found.\n\n   .. attribute:: page\n\n      A reference to the :ref:`Page` object.\n\n      :type: :ref:`Page`\n\n\n.. class:: Table\n\n   An object representing a table found on the page.\n\n\n   .. attribute:: page\n\n      A back-reference to the owning page.\n\n      :type: :ref:`Page`\n\n   .. attribute:: cells\n\n      An array of `Rect` objects for each cell in the table.\n\n      :type: list\n\n\n   .. attribute:: header\n\n      A `TableHeader` object.\n\n      :type: `TableHeader`\n\n\n   .. attribute:: bbox\n\n      The bounding box of all cells of the table header.\n\n\n      :type: :ref:`Rect`\n\n\n\n   .. attribute:: row_count\n\n      Number of rows in the table.\n\n      :type: int\n\n\n   .. attribute:: col_count\n\n      Number of columns in the table.\n\n      :type: int\n\n\n   .. attribute:: rows\n\n      An array of `TableRow` objects for each row in the table.\n\n      :type: list\n\n\n   .. method:: extract()\n\n      Extracts table cell text data into a list.\n\n      :type: list\n\n   .. method:: to_markdown(clean=False, fill_empty=True)\n\n      Extracts table data into Markdown text format.\n\n\n      :arg bool clean: If ``True`` then markdown syntax is removed from cell content.\n      :arg bool fill_empty: If ``True`` then cell content `None` is replaced by the values above (columns) or left (rows) in an effort to approximate row and columns spans.\n\n\n      :type: string\n\n\n   .. method:: to_pandas()\n\n      Return a `pandas DataFrame <https://pypi.org/project/pandas/>`_ `DataFrame <https://pandas.pydata.org/docs/reference/frame.html>`_ version of the table.\n\n      :type: pandas DataFrame\n\n\n\n.. class:: TableHeader\n\n\n   Dedicated class for table headers.\n\n   .. attribute:: bbox\n\n      The bounding box of the union of cells belonging to the table header, given as a tuple (x0, y0, x1, y1). This rectangle contains all table header cells.\n\n      :type: :ref:`Rect`\n\n   .. attribute:: cells\n\n      A list of tuples for each bbox of a column header.\n\n      :type: list\n\n   .. attribute:: names\n\n      A list of strings with column header text.\n\n      :type: list\n\n   .. attribute:: external\n\n      A boolean indicating whether the header is outside the table cells.\n\n      :type: `bool`\n\n\n.. class:: TableRow\n\n   Dedicated class for table rows.\n\n\n----\n\n\n.. rubric:: Footnotes\n\n.. [#f1] If your existing code already uses the installed base name as a font reference (as it was supported by PyMuPDF versions earlier than 1.14), this will continue to work.\n\n.. [#f2] Not all PDF reader software (including internet browsers and office software) display all of these fonts. And if they do, the difference between the **serifed** and the **non-serifed** version may hardly be noticeable. But serifed and non-serifed versions lead to different installed base fonts, thus providing an option to be displayable with your specific PDF viewer.\n\n.. [#f3] Not all PDF readers display these fonts at all. Some others do, but use a wrong character spacing, etc.\n\n.. [#f4] You are generally free to choose any of the :ref:`mupdficons` you consider adequate.\n\n.. [#f5] The previous algorithm caused images to be **shrunk** to this intersection. Now the image can be anywhere on :attr:`Page.mediabox`, potentially being invisible or only partially visible if the cropbox (representing the visible page part) is smaller.\n\n.. [#f6] If you need to also see annotations or fields in the target page, you can convert the source PDF using :meth:`Document.bake`. The underlying MuPDF function of that method will convert these objects to normal page content. Then use :meth:`Page.show_pdf_page` with the converted PDF page.\n\n.. [#f7] In PDF, an area enclosed by some lines or curves can have a property called \"orientation\". This is significant for switching on or off the fill color of that area when there exist multiple area overlaps - see discussion in method :meth:`Shape.finish` using the \"non-zero winding number\" rule. While orientation of curves, quads, triangles and other shapes enclosed by lines always was detectable, this has been impossible for \"re\" (rectangle) items in the past. Adding the orientation parameter now delivers the missing information.\n\n.. [#f8] Hyphenation detection simply means that if the last character of a line is \"-\", it will be assumed to be a continuation character. That character will not be found by text searching with its default flag setting. Please take note, that a MuPDF *line* may not always be what you expect: words separated by overly large gaps (e.g. caused by text justification) may constitute separate MuPDF lines. If then any of these words ends with a hyphen, it will only be found by text searching if hyphenation is switched off.\n\n.. [#f9] Objects inside the source page, like images, text or drawings, are never aware of whether their owning page now is under OC control inside the target PDF. If source page objects are OC-controlled in the source PDF, then this will not be retained on the target: they will become unconditionally visible.\n\n.. [#f10] This value is always 96, the default of the PDF interpreter. It **does not reflect** the resolution of the image itself. If you need the image's resolution, use the :meth:`Pixmap.xres` and :meth:`Pixmap.yres` attributes of the :ref:`Pixmap` created from the image binary.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/pixmap.rst",
    "content": ".. include:: header.rst\n\n.. _Pixmap:\n\n================\nPixmap\n================\n\nPixmaps (\"pixel maps\") are objects at the heart of MuPDF's rendering capabilities. They represent plane rectangular sets of pixels. Each pixel is described by a number of bytes (\"components\") defining its color, plus an optional alpha byte defining its transparency.\n\nIn PyMuPDF, there exist several ways to create a pixmap. Except the first one, all of them are available as overloaded constructors. A pixmap can be created ...\n\n1. from a document page (method :meth:`Page.get_pixmap`)\n2. empty, based on :ref:`Colorspace` and :ref:`IRect` information\n3. from a file\n4. from an in-memory image\n5. from a memory area of plain pixels\n6. from an image inside a PDF document\n7. as a copy of another pixmap\n\n.. note:: A number of image formats is supported as input for points 3. and 4. above. See section :ref:`ImageFiles`.\n\nHave a look at the :ref:`FAQ` section to see some pixmap usage \"at work\".\n\n================================ ===================================================\n**Method / Attribute**           **Short Description**\n================================ ===================================================\n:meth:`Pixmap.clear_with`        clear parts of the pixmap\n:meth:`Pixmap.color_count`       determine used colors\n:meth:`Pixmap.color_topusage`    determine share of most used color\n:meth:`Pixmap.copy`              copy parts of another pixmap\n:meth:`Pixmap.gamma_with`        apply a gamma factor to the pixmap\n:meth:`Pixmap.invert_irect`      invert the pixels of a given area\n:meth:`Pixmap.pdfocr_save`       save the pixmap as an OCRed 1-page PDF\n:meth:`Pixmap.pdfocr_tobytes`    save the pixmap as an OCRed 1-page PDF\n:meth:`Pixmap.pil_image`         create a Pillow Image\n:meth:`Pixmap.pil_save`          save as a Pillow Image\n:meth:`Pixmap.pil_tobytes`       write to `bytes` as a Pillow Image\n:meth:`Pixmap.pixel`             return the value of a pixel\n:meth:`Pixmap.save`              save the pixmap in a variety of formats\n:meth:`Pixmap.set_alpha`         set alpha values\n:meth:`Pixmap.set_dpi`           set the image resolution\n:meth:`Pixmap.set_origin`        set pixmap x,y values\n:meth:`Pixmap.set_pixel`         set color and alpha of a pixel\n:meth:`Pixmap.set_rect`          set color and alpha of all pixels in a rectangle\n:meth:`Pixmap.shrink`            reduce size keeping proportions\n:meth:`Pixmap.tint_with`         tint the pixmap\n:meth:`Pixmap.tobytes`           return a memory area in a variety of formats\n:meth:`Pixmap.warp`              return a pixmap made from a quad inside\n:attr:`Pixmap.alpha`             transparency indicator\n:attr:`Pixmap.colorspace`        pixmap's :ref:`Colorspace`\n:attr:`Pixmap.digest`            MD5 hashcode of the pixmap\n:attr:`Pixmap.height`            pixmap height\n:attr:`Pixmap.interpolate`       interpolation method indicator\n:attr:`Pixmap.is_monochrome`     check if only black and white occur\n:attr:`Pixmap.is_unicolor`       check if only one color occurs\n:attr:`Pixmap.irect`             :ref:`IRect` of the pixmap\n:attr:`Pixmap.n`                 bytes per pixel\n:attr:`Pixmap.samples_mv`        `memoryview` of pixel area\n:attr:`Pixmap.samples_ptr`       Python pointer to pixel area\n:attr:`Pixmap.samples`           `bytes` copy of pixel area\n:attr:`Pixmap.size`              pixmap's total length\n:attr:`Pixmap.stride`            size of one image row\n:attr:`Pixmap.width`             pixmap width\n:attr:`Pixmap.x`                 X-coordinate of top-left corner\n:attr:`Pixmap.xres`              resolution in X-direction\n:attr:`Pixmap.y`                 Y-coordinate of top-left corner\n:attr:`Pixmap.yres`              resolution in Y-direction\n================================ ===================================================\n\n**Class API**\n\n.. class:: Pixmap\n\n   .. method:: __init__(self, colorspace, irect, alpha=False)\n\n      **New empty pixmap:** Create an empty pixmap of size and origin given by the rectangle. So, *irect.top_left* designates the top left corner of the pixmap, and its width and height are *irect.width* resp. *irect.height*. Note that the image area is **not initialized** and will contain crap data -- use eg. :meth:`clear_with` or :meth:`set_rect` to be sure.\n\n      :arg colorspace: colorspace.\n      :type colorspace: :ref:`Colorspace`\n\n      :arg irect_like irect: The pixmap's position and dimension.\n\n      :arg bool alpha: Specifies whether transparency bytes should be included. Default is ``False``.\n\n   .. method:: __init__(self, colorspace, source)\n\n      **Copy and set colorspace:** Copy *source* pixmap converting colorspace. Any colorspace combination is possible, but source colorspace must not be ``None``.\n\n      :arg colorspace: desired **target** colorspace. This **may also be** ``None``. In this case, a \"masking\" pixmap is created: its :attr:`Pixmap.samples` will consist of the source's alpha bytes only.\n      :type colorspace: :ref:`Colorspace`\n\n      :arg source: the source pixmap.\n      :type source: :ref:`Pixmap`.\n\n   .. method:: __init__(self, source, mask)\n\n      * New in v1.18.18\n\n      **Copy and add image mask:** Copy *source* pixmap, add an alpha channel with transparency data from a mask pixmap.\n\n      :arg source: pixmap without alpha channel.\n      :type source: :ref:`Pixmap`.\n\n      :arg mask: a mask pixmap. Must be a graysale pixmap.\n      :type mask: :ref:`Pixmap`.\n\n   .. method:: __init__(self, source, width, height, [clip])\n\n      **Copy and scale:** Copy *source* pixmap, scaling new width and height values -- the image will appear stretched or shrunk accordingly. Supports partial copying. The source colorspace may be ``None``.\n\n      :arg source: the source pixmap.\n      :type source: :ref:`Pixmap`.\n\n      :arg float width: desired target width.\n\n      :arg float height: desired target height.\n\n      :arg irect_like clip: restrict the resulting pixmap to this region of the **scaled** pixmap.\n\n      .. note:: If width or height do not *represent* integers (i.e. `value.is_integer() != True`), then the resulting pixmap **will have an alpha channel**.\n\n   .. method:: __init__(self, source, alpha=1)\n\n      **Copy and add or drop alpha:** Copy *source* and add or drop its alpha channel. Identical copy if *alpha* equals *source.alpha*. If an alpha channel is added, its values will be set to 255.\n\n      :arg source: source pixmap.\n      :type source: :ref:`Pixmap`.\n\n      :arg bool alpha: whether the target will have an alpha channel, default and mandatory if source colorspace is ``None``.\n\n      .. note:: A typical use includes separation of color and transparency bytes in separate pixmaps. Some applications require this like e.g. *wx.Bitmap.FromBufferAndAlpha()* of *wxPython*:\n\n         >>> # 'pix' is an RGBA pixmap\n         >>> pixcolors = pymupdf.Pixmap(pix, 0)    # extract the RGB part (drop alpha)\n         >>> pixalpha = pymupdf.Pixmap(None, pix)  # extract the alpha part\n         >>> bm = wx.Bitmap.FromBufferAndAlpha(pix.width, pix.height, pixcolors.samples, pixalpha.samples)\n\n\n   .. method:: __init__(self, filename)\n\n      **From a file:** Create a pixmap from *filename*. All properties are inferred from the input. The origin of the resulting pixmap is *(0, 0)*.\n\n      :arg str filename: Path of the image file.\n\n   .. method:: __init__(self, stream)\n\n      **From memory:** Create a pixmap from a memory area. All properties are inferred from the input. The origin of the resulting pixmap is *(0, 0)*.\n\n      :arg bytes,bytearray,BytesIO stream: Data containing a complete, valid image. Could have been created by e.g. *stream = bytearray(open('image.file', 'rb').read())*. Type *bytes* is supported in **Python 3 only**, because *bytes == str* in Python 2 and the method will interpret the stream as a filename.\n\n         *Changed in version 1.14.13:* *io.BytesIO* is now also supported.\n\n\n   .. method:: __init__(self, colorspace, width, height, samples, alpha)\n\n      **From plain pixels:** Create a pixmap from *samples*. Each pixel must be represented by a number of bytes as controlled by the *colorspace* and *alpha* parameters. The origin of the resulting pixmap is *(0, 0)*. This method is useful when raw image data are provided by some other program -- see :ref:`FAQ`.\n\n      :arg colorspace: Colorspace of image.\n      :type colorspace: :ref:`Colorspace`\n\n      :arg int width: image width\n\n      :arg int height: image height\n\n      :arg bytes,bytearray,BytesIO samples:  an area containing all pixels of the image. Must include alpha values if specified.\n\n         *Changed in version 1.14.13:* (1) *io.BytesIO* can now also be used. (2) Data are now **copied** to the pixmap, so may safely be deleted or become unavailable.\n\n      :arg bool alpha: whether a transparency channel is included.\n\n      .. note::\n\n         1. The following equation **must be true**: *(colorspace.n + alpha) * width * height == len(samples)*.\n         2. Starting with version 1.14.13, the samples data are **copied** to the pixmap.\n\n\n   .. method:: __init__(self, doc, xref)\n\n      **From a PDF image:** Create a pixmap from an image **contained in PDF** *doc* identified by its :data:`xref`. All pimap properties are set by the image. Have a look at `extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_ and `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_ to see how this can be used to recover all of a PDF's images.\n\n      :arg doc: an opened |PDF| document.\n      :type doc: :ref:`Document`\n\n      :arg int xref: the :data:`xref` of an image object. For example, you can make a list of images used on a particular page with :meth:`Document.get_page_images`, which also shows the :data:`xref` numbers of each image.\n\n   .. method:: clear_with([value [, irect]])\n\n      Initialize the samples area.\n\n      :arg int value: if specified, values from 0 to 255 are valid. Each color byte of each pixel will be set to this value, while alpha will be set to 255 (non-transparent) if present. If omitted, then all bytes (including any alpha) are cleared to *0x00*.\n\n      :arg irect_like irect: the area to be cleared. Omit to clear the whole pixmap. Can only be specified, if *value* is also specified.\n\n   .. method:: tint_with(black, white)\n\n      Colorize a pixmap by replacing black and / or white with colors given as **sRGB integer** values. Only colorspaces :data:`CS_GRAY` and :data:`CS_RGB` are supported, others are ignored with a warning.\n\n      If the colorspace is :data:`CS_GRAY`, the average *(red + green + blue)/3* will be taken. The pixmap will be changed in place.\n\n      :arg int black: replace black with this value. Specifying 0x000000 makes no changes.\n      :arg int white: replace white with this value. Specifying 0xFFFFFF makes no changes.\n\n      Examples:\n\n         * `tint_with(0x000000, 0xFFFFFF)` is a no-op.\n         * `tint_with(0x00FF00, 0xFFFFFF)` changes black to green, leaves white intact.\n         * `tint_with(0xFF0000, 0x0000FF)` changes black to red and white to blue.\n\n\n   .. method:: gamma_with(gamma)\n\n      Apply a gamma factor to a pixmap, i.e. lighten or darken it. Pixmaps with colorspace ``None`` are ignored with a warning.\n\n      :arg float gamma: *gamma = 1.0* does nothing, *gamma < 1.0* lightens, *gamma > 1.0* darkens the image.\n\n   .. method:: shrink(n)\n\n      Shrink the pixmap by dividing both, its width and height by 2\\ :sup:``n``.\n\n      :arg int n: determines the new pixmap (samples) size. For example, a value of 2 divides width and height by 4 and thus results in a size of one 16\\ :sup:`th` of the original. Values less than 1 are ignored with a warning.\n\n      .. note:: Use this methods to reduce a pixmap's size retaining its proportion. The pixmap is changed \"in place\". If you want to keep original and also have more granular choices, use the resp. copy constructor above.\n\n   .. method:: pixel(x, y)\n\n      *New in version:: 1.14.5:* Return the value of the pixel at location (x, y) (column, line).\n\n      :arg int x: the column number of the pixel. Must be in `range(pix.width)`.\n      :arg int y: the line number of the pixel, Must be in `range(pix.height)`.\n\n      :rtype: list\n      :returns: a list of color values and, potentially the alpha value. Its length and content depend on the pixmap's colorspace and the presence of an alpha. For RGBA pixmaps the result would e.g. be *[r, g, b, a]*. All items are integers in `range(256)`.\n\n   .. method:: set_pixel(x, y, color)\n\n      *New in version 1.14.7:* Manipulate the pixel at location (x, y) (column, line).\n\n      :arg int x: the column number of the pixel. Must be in `range(pix.width)`.\n      :arg int y: the line number of the pixel. Must be in `range(pix.height)`.\n      :arg sequence color: the desired pixel value given as a sequence of integers in `range(256)`. The length of the sequence must equal :attr:`Pixmap.n`, which includes any alpha byte.\n\n   .. method:: set_rect(irect, color)\n\n      *New in version 1.14.8:* Set the pixels of a rectangle to a value.\n\n      :arg irect_like irect: the rectangle to be filled with the value. The actual area is the intersection of this parameter and :attr:`Pixmap.irect`. For an empty intersection (or an invalid parameter), no change will happen.\n      :arg sequence color: the desired value, given as a sequence of integers in `range(256)`. The length of the sequence must equal :attr:`Pixmap.n`, which includes any alpha byte.\n\n      :rtype: bool\n      :returns: ``False`` if the rectangle was invalid or had an empty intersection with :attr:`Pixmap.irect`, else ``True``.\n\n      .. note::\n\n         1. This method is equivalent to :meth:`Pixmap.set_pixel` executed for each pixel in the rectangle, but is obviously **very much faster** if many pixels are involved.\n         2. This method can be used similar to :meth:`Pixmap.clear_with` to initialize a pixmap with a certain color like this: *pix.set_rect(pix.irect, (255, 255, 0))* (RGB example, colors the complete pixmap with yellow).\n\n   .. method:: set_origin(x, y)\n\n      * New in v1.17.7\n      \n      Set the x and y values of the pixmap's top-left point.\n\n      :arg int x: x coordinate\n      :arg int y: y coordinate\n\n\n   .. method:: set_dpi(xres, yres)\n\n      * New in v1.16.17\n\n      * Changed in v1.18.0: When saving as a PNG image, these values will be stored now.\n\n      Set the resolution (dpi) in x and y direction.\n\n      :arg int xres: resolution in x direction.\n      :arg int yres: resolution in y direction.\n\n\n   .. method:: set_alpha(alphavalues, premultiply=1, opaque=None)\n\n      * Changed in v 1.18.13\n\n      Change the alpha values. The pixmap must have an alpha channel.\n\n      :arg bytes,bytearray,BytesIO alphavalues: the new alpha values. If provided, its length must be at least *width * height*. If omitted (`None`), all alpha values are set to 255 (no transparency). *Changed in version 1.14.13:* *io.BytesIO* is now also accepted.\n      :arg bool premultiply: *New in v1.18.13:* whether to premultiply color components with the alpha value.\n      :arg list,tuple opaque: ignore the alpha value and set this color to fully transparent. A sequence of integers in `range(256)` with a length of :attr:`Pixmap.n`. Default is ``None``. For example, a typical choice for RGB would be `opaque=(255, 255, 255)` (white).\n\n\n   .. method:: invert_irect([irect])\n\n      Invert the color of all pixels in :ref:`IRect` *irect*. Will have no effect if colorspace is ``None``.\n\n      :arg irect_like irect: The area to be inverted. Omit to invert everything.\n\n   .. method:: copy(source, irect)\n\n      Copy the *irect* part of the *source* pixmap into the corresponding area of this one. The two pixmaps may have different dimensions and can each have :data:`CS_GRAY` or :data:`CS_RGB` colorspaces, but they currently **must** have the same alpha property [#f2]_. The copy mechanism automatically adjusts discrepancies between source and target like so:\n\n      If copying from :data:`CS_GRAY` to :data:`CS_RGB`, the source gray-shade value will be put into each of the three rgb component bytes. If the other way round, *(r + g + b) / 3* will be taken as the gray-shade value of the target.\n\n      Between *irect* and the target pixmap's rectangle, an \"intersection\" is calculated at first. This takes into account the rectangle coordinates and the current attribute values :attr:`Pixmap.x` and :attr:`Pixmap.y` (which you are free to modify for this purpose via :meth:`Pixmap.set_origin`). Then the corresponding data of this intersection are copied. If the intersection is empty, nothing will happen.\n\n      :arg source: source pixmap.\n      :type source: :ref:`Pixmap`\n\n      :arg irect_like irect: The area to be copied.\n\n      .. note:: Example: Suppose you have two pixmaps, `pix1` and `pix2` and you want to copy the lower right quarter of `pix2` to `pix1` such that it starts at the top-left point of `pix1`. Use the following snippet::\n\n         >>> # safeguard: set top-left of pix1 and pix2 to (0, 0)\n         >>> pix1.set_origin(0, 0)\n         >>> pix2.set_origin(0, 0)\n         >>> # compute top-left coordinates of pix2 region to copy\n         >>> x1 = int(pix2.width / 2)\n         >>> y1 = int(pix2.height / 2)\n         >>> # shift top-left of pix2 such, that the to-be-copied\n         >>> # area starts at (0, 0):\n         >>> pix2.set_origin(-x1, -y1)\n         >>> # now copy ...\n         >>> pix1.copy(pix2, (0, 0, x1, y1))\n\n         .. image:: images/img-pixmapcopy.*\n             :scale: 20\n\n   .. method:: save(filename, output=None, jpg_quality=95)\n\n      * Changed in v1.22.0: Added **direct support of JPEG** images. Image quality can be controlled via parameter \"jpg_quality\".\n\n      Save pixmap as an image file. Depending on the output chosen, only some or all colorspaces are supported and different file extensions can be chosen. Please see the table below.\n\n      :arg str,Path,file filename: The file to save to. May be provided as a string, as a ``pathlib.Path`` or as a Python file object. In the latter two cases, the filename is taken from the resp. object. The filename's extension determines the image format, which can be overruled by the output parameter.\n\n      :arg str output: The desired image format. The default is the filename's extension. If both, this value and the file extension are unsupported, an exception is raised. For possible values see :ref:`PixmapOutput`.\n      :arg int jpg_quality: The desired image quality, default 95. Only applies to JPEG images, else ignored. This parameter trades quality against file size. A value of 98 is close to lossless. Higher values should not lead to better quality.\n\n      :raises ValueError: For unsupported image formats.\n\n   .. method:: tobytes(output=\"png\", jpg_quality=95)\n\n      * New in version 1.14.5: Return the pixmap as a *bytes* memory object of the specified format -- similar to :meth:`save`.\n      * Changed in v1.22.0: Added **direct JPEG support**. Image quality can be influenced via new parameter \"jpg_quality\".\n\n      :arg str output: The desired image format. The default is \"png\". For possible values see :ref:`PixmapOutput`.\n      :arg int jpg_quality: The desired image quality, default 95. Only applies to JPEG images, else ignored. This parameter trades quality against file size. A value of 98 is close to lossless. Higher values should not lead to better quality.\n\n      :raises ValueError: For unsupported image formats.\n      :rtype: bytes\n\n      :arg str output: The requested image format. The default is \"png\". For other possible values see :ref:`PixmapOutput`.\n\n   .. method:: pdfocr_save(filename, compress=True, language=\"eng\", tessdata=None)\n\n      * New in v1.19.0\n\n      * Changed in v1.22.5: Support of new parameter for Tesseract's tessdata.\n\n      Perform text recognition using Tesseract and save the image as a 1-page PDF with an OCR text layer.\n\n      :arg str,fp filename: identifies the file to save to. May be either a string or a pointer to a file opened with \"wb\" (includes `io.BytesIO()` objects).\n      :arg bool compress: whether to compress the resulting PDF, default is `True`.\n      :arg str language: the languages occurring in the image. This must be specified in Tesseract format. Default is \"eng\" for English. Use \"+\"-separated Tesseract language codes for multiple languages, like \"eng+spa\" for English and Spanish.\n      :arg str tessdata: folder name of Tesseract's language support. If omitted, this information must be present as environment variable `TESSDATA_PREFIX`.\n\n      .. note:: **Will fail** if Tesseract is not installed or if the environment variable \"TESSDATA_PREFIX\" is not set to the `tessdata` folder name and not provided as parameter.\n\n   .. method:: pdfocr_tobytes(compress=True, language=\"eng\", tessdata=None)\n\n      * New in v1.19.0\n\n      * Changed in v1.22.5: Support of new parameter for Tesseract's tessdata.\n\n      Perform text recognition using Tesseract and convert the image to a 1-page PDF with an OCR text layer. Internally invokes :meth:`Pixmap.pdfocr_save`.\n\n      :returns: A 1-page PDF file in memory. Could be opened like `doc=pymupdf.open(\"pdf\", pix.pdfocr_tobytes())`, and text extractions could be performed on its `page=doc[0]`.\n      \n         .. note::\n         \n            Another possible use is insertion into some pdf. The following snippet reads the images of a folder and stores them as pages in a new PDF that contain an OCR text layer::\n\n               doc = pymupdf.open()\n               for imgfile in os.listdir(folder):\n                  pix = pymupdf.Pixmap(imgfile)\n                  imgpdf = pymupdf.open(\"pdf\", pix.pdfocr_tobytes())\n                  doc.insert_pdf(imgpdf)\n                  pix = None\n                  imgpdf.close()\n               doc.save(\"ocr-images.pdf\")\n\n\n   ..  method:: pil_image()\n\n      Create a Pillow Image from the pixmap. PIL / Pillow must be installed.\n\n      :raises ImportError: if Pillow is not installed.\n      :returns: a ``PIL.Image`` object\n\n   ..  method:: pil_save(*args, unmultiply=False, **kwargs)\n\n      Write the pixmap as an image file using Pillow. Use this method for output unsupported by MuPDF. Examples are\n\n      * Formats JPX, J2K, WebP, etc.\n      * Storing EXIF information.\n      * If you do not provide dpi information, the values *xres*, *yres* stored with the pixmap are automatically used.\n\n      A simple example: `pix.pil_save(\"some.webp\", optimize=True, dpi=(150, 150))`.\n      \n      :arg bool unmultiply: If the pixmap's colorspace is RGB with transparency, the alpha values may or may not already be multiplied into the color components ref/green/blue (called \"premultiplied\"). To enforce undoing premultiplication, set this parameter to `True`. To learn about some background, e.g. look for `\"Premultiplied alpha\" on this page <https://en.wikipedia.org/wiki/Glossary_of_computer_graphics#P>`_.\n\n\n      For details on other parameters see the Pillow documentation.\n\n      Since v1.22.0, PyMuPDF supports JPEG output directly. We recommended to no longer use this method for JPEG output -- for performance reasons and for avoiding unnecessary external dependencies.\n\n      :raises ImportError: if Pillow is not installed.\n\n   ..  method:: pil_tobytes(*args, unmultiply=False, **kwargs)\n\n      * New in v1.17.3\n\n      Return an image as a bytes object in the specified format using Pillow. For example `stream = pix.pil_tobytes(format=\"WEBP\", optimize=True, dpi=(150, 150))`. Also see above. For details on other parameters see the Pillow documentation.\n      \n      :raises ImportError: if Pillow is not installed.\n\n      :rtype: bytes\n\n\n   ..  method:: warp(quad, width, height)\n\n      * New in v1.19.3\n\n      Return a new pixmap by \"warping\" the quad such that the quad corners become the new pixmap's corners. The target pixmap's `irect` will be `(0, 0, width, height)`.\n\n      :arg quad_like quad: a convex quad with coordinates inside :attr:`Pixmap.irect` (including the border points).\n      :arg int width: desired resulting width.\n      :arg int height: desired resulting height.\n      :returns: A new pixmap where the quad corners are mapped to the pixmap corners in a clockwise fashion: `quad.ul -> irect.tl`, `quad.ur -> irect.tr`, etc.\n      :rtype: :ref:`Pixmap`\n\n         .. image:: images/img-warp.*\n              :scale: 40\n              :align: center\n\n\n   ..  method:: color_count(colors=False, clip=None)\n\n      * New in v1.19.2\n      * Changed in v1.19.3\n\n      Determine the pixmap's unique colors and their count.\n\n      :arg bool colors: *(changed in v1.19.3)* If `True` return a dictionary of color pixels and their usage count, else just the number of unique colors.\n      :arg rect_like clip: a rectangle inside :attr:`Pixmap.irect`. If provided, only those pixels are considered. This allows inspecting sub-rectangles of a given pixmap directly -- instead of building sub-pixmaps.\n      :rtype: dict or int\n      :returns: either the number of colors, or a dictionary with the items `pixel: count`. The pixel key is a `bytes` object of length :attr:`Pixmap.n`.\n      \n         .. note:: To recover the **tuple** of a pixel, use `tuple(colors.keys()[i])` for the i-th item.\n\n            * The response time depends on the pixmap's samples size and may be more than a second for very large pixmaps.\n            * Where applicable, pixels with different alpha values will be treated as different colors.\n\n\n   ..  method:: color_topusage(clip=None)\n\n      * New in v1.19.3\n\n      Return the most frequently used color and its relative frequency.\n\n      :arg rect_like clip: A rectangle inside :attr:`Pixmap.irect`. If provided, only those pixels are considered. This allows inspecting sub-rectangles of a given pixmap directly -- instead of building sub-pixmaps.\n      :rtype: tuple\n      :returns: A tuple `(ratio, pixel)` where `0 < ratio <= 1` and *pixel* is the pixel value of the color. Use this to decide if the image is \"almost\" unicolor: a response `(0.95, b\"\\x00\\x00\\x00\")` means that 95% of all pixels are black. See an example here :ref:`RecipesImages_P`.\n\n\n   .. attribute:: alpha\n\n      Indicates whether the pixmap contains transparency information.\n\n      :type: bool\n\n   .. attribute:: digest\n\n      The MD5 hashcode (16 bytes) of the pixmap. This is a technical value used for unique identifications.\n\n      :type: bytes\n\n   .. attribute:: colorspace\n\n      The colorspace of the pixmap. This value may be ``None`` if the image is to be treated as a so-called *image mask* or *stencil mask* (currently happens for extracted PDF document images only).\n\n      :type: :ref:`Colorspace`\n\n   .. attribute:: stride\n\n      Contains the length of one row of image data in :attr:`Pixmap.samples`. This is primarily used for calculation purposes. The following expressions are true:\n\n      * `len(samples) == height * stride`\n      * `width * n == stride`\n\n      :type: int\n\n\n   .. attribute:: is_monochrome\n\n      * New in v1.19.2\n\n      Is `True` for a gray pixmap which only has the colors black and white.\n\n      :type: bool\n\n\n   .. attribute:: is_unicolor\n\n      * New in v1.19.2\n\n      Is `True` if all pixels are identical (any colorspace). Where applicable, pixels with different alpha values will be treated as different colors.\n\n      :type: bool\n\n\n   .. attribute:: irect\n\n      Contains the :ref:`IRect` of the pixmap.\n\n      :type: :ref:`IRect`\n\n   .. attribute:: samples\n\n      The color and (if :attr:`Pixmap.alpha` is true) transparency values for all pixels. It is an area of `width * height * n` bytes. Each n bytes define one pixel. Each successive n bytes yield another pixel in scanline order. Subsequent scanlines follow each other with no padding. E.g. for an RGBA colorspace this means, *samples* is a sequence of bytes like *..., R, G, B, A, ...*, and the four byte values R, G, B, A define one pixel.\n\n      This area can be passed to other graphics libraries like PIL (Python Imaging Library) to do additional processing like saving the pixmap in other image formats.\n\n      .. note::\n         * The underlying data is typically a **large** memory area, from which a `bytes` copy is made for this attribute ... each time you access it: for example an RGB-rendered letter page has a samples size of almost 1.4 MB. So consider assigning a new variable to it or use the `memoryview` version :attr:`Pixmap.samples_mv` (new in v1.18.17).\n         * Any changes to the underlying data are available only after accessing this attribute again. This is different from using the memoryview version.\n\n      :type: bytes\n\n   .. attribute:: samples_mv\n\n      * New in v1.18.17\n\n      Like :attr:`Pixmap.samples`, but in Python `memoryview` format. It is built pointing to the memory in the pixmap -- not from a copy of it. So its creation speed is independent from the pixmap size, and any changes to pixels will be available immediately.\n\n      Copies like `bytearray(pix.samples_mv)`, or `bytes(pixmap.samples_mv)` are equivalent to and can be used in place of `pix.samples`.\n      \n      We also have `len(pix.samples) == len(pix.samples_mv)`.\n      \n      Look at this example from a 2 MB JPEG: the memoryview is **ten thousand times faster**::\n\n         In [3]: %timeit len(pix.samples_mv)\n         367 ns ± 1.75 ns per loop (mean ± std. dev. of 7 runs, 1000000 loops each)\n         In [4]: %timeit len(pix.samples)\n         3.52 ms ± 57.5 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)\n      \n      After the Pixmap has been destroyed, any attempt to use the memoryview\n      will fail with ValueError.\n\n      :type: memoryview\n\n   .. attribute:: samples_ptr\n\n      * New in v1.18.17\n\n      Python pointer to the pixel area. This is a special integer format, which can be used by supporting applications (such as PyQt) to directly address the samples area and thus build their images extremely fast. For example::\n\n         img = QtGui.QImage(pix.samples, pix.width, pix.height, format) # (1)\n         img = QtGui.QImage(pix.samples_ptr, pix.width, pix.height, format) # (2)\n\n      Both of the above lead to the same Qt image, but (2) can be **many hundred times faster**, because it avoids an additional copy of the pixel area.\n      \n      Warning: after the Pixmap has been destroyed, the Python pointer will be\n      invalid and attempting to use it may crash the Python interpreter.\n\n      :type: int\n\n   .. attribute:: size\n\n      Contains *len(pixmap)*. This will generally equal *len(pix.samples)* plus some platform-specific value for defining other attributes of the object.\n\n      :type: int\n\n   .. attribute:: width\n\n   .. attribute:: w\n\n      Width of the region in pixels.\n\n      :type: int\n\n   .. attribute:: height\n\n   .. attribute:: h\n\n      Height of the region in pixels.\n\n      :type: int\n\n   .. attribute:: x\n\n      X-coordinate of top-left corner in pixels. Cannot directly be changed -- use :meth:`Pixmap.set_origin`.\n\n      :type: int\n\n   .. attribute:: y\n\n      Y-coordinate of top-left corner in pixels. Cannot directly be changed -- use :meth:`Pixmap.set_origin`.\n\n      :type: int\n\n   .. attribute:: n\n\n      Number of components per pixel. This number depends on colorspace and alpha. If colorspace is not ``None`` (stencil masks), then *Pixmap.n - Pixmap.alpha == pixmap.colorspace.n* is true. If colorspace is ``None``, then *n == alpha == 1*.\n\n      :type: int\n\n   .. attribute:: xres\n\n      Horizontal resolution in dpi (dots per inch). Please also see :data:`resolution`. Cannot directly be changed -- use :meth:`Pixmap.set_dpi`.\n\n      :type: int\n\n   .. attribute:: yres\n\n      Vertical resolution in dpi (dots per inch). Please also see :data:`resolution`. Cannot directly be changed -- use :meth:`Pixmap.set_dpi`.\n\n      :type: int\n\n   .. attribute:: interpolate\n\n      An information-only boolean flag set to ``True`` if the image will be drawn using \"linear interpolation\". If ``False`` \"nearest neighbour sampling\" will be used.\n\n      :type: bool\n\n.. _ImageFiles:\n\nSupported Input Image Formats\n-----------------------------------------------\nThe following file types are supported as **input** to construct pixmaps: **BMP, JPEG, GIF, TIFF, JXR, JPX**, **PNG**, **PAM** and all of the **Portable Anymap** family (**PBM, PGM, PNM, PPM**). This support is two-fold:\n\n1. Directly create a pixmap with *Pixmap(filename)* or *Pixmap(byterray)*. The pixmap will then have properties as determined by the image.\n\n2. Open such files with *pymupdf.open(...)*. The result will then appear as a document containing one single page. Creating a pixmap of this page offers all the options available in this context: apply a matrix, choose colorspace and alpha, confine the pixmap to a clip area, etc.\n\n**SVG images** are only supported via method 2 above, not directly as pixmaps. But remember: the result of this is a **raster image** as is always the case with pixmaps [#f1]_.\n\n.. _PixmapOutput:\n\nSupported Output Image Formats\n---------------------------------------------------------------------------\nA number of image **output** formats are supported. You have the option to either write an image directly to a file (:meth:`Pixmap.save`), or to generate a bytes object (:meth:`Pixmap.tobytes`). Both methods accept a string identifying the desired format (**Format** column below). Please note that not all combinations of pixmap colorspace, transparency support (alpha) and image format are possible.\n\n========== =============== ========= ============== =================================\n**Format** **Colorspaces** **alpha** **Extensions** **Description**\n========== =============== ========= ============== =================================\njpg, jpeg  gray, rgb, cmyk no        .jpg, .jpeg    Joint Photographic Experts Group \npam        gray, rgb, cmyk yes       .pam           Portable Arbitrary Map\npbm        gray, rgb       no        .pbm           Portable Bitmap\npgm        gray, rgb       no        .pgm           Portable Graymap\npng        gray, rgb       yes       .png           Portable Network Graphics\npnm        gray, rgb       no        .pnm           Portable Anymap\nppm        gray, rgb       no        .ppm           Portable Pixmap\nps         gray, rgb, cmyk no        .ps            Adobe PostScript Image\npsd        gray, rgb, cmyk yes       .psd           Adobe Photoshop Document\n========== =============== ========= ============== =================================\n\n.. note::\n    * Not all image file types are supported (or at least common) on all OS platforms. E.g. PAM and the Portable Anymap formats are rare or even unknown on Windows.\n    * Especially pertaining to CMYK colorspaces, you can always convert a CMYK pixmap to an RGB pixmap with *rgb_pix = pymupdf.Pixmap(pymupdf.csRGB, cmyk_pix)* and then save that in the desired format.\n    * As can be seen, MuPDF's image support range is different for input and output. Among those supported both ways, PNG and JPEG are probably the most popular.\n    * We also recommend using \"ppm\" formats as input to tkinter's *PhotoImage* method like this: *tkimg = tkinter.PhotoImage(data=pix.tobytes(\"ppm\"))* (also see the tutorial). This is **very** fast (**60 times** faster than PNG).\n\n\n\n.. rubric:: Footnotes\n\n.. [#f1] If you need a **vector image** from the SVG, you must first convert it to a PDF. Try :meth:`Document.convert_to_pdf`. If this is not good enough, look for other SVG-to-PDF conversion tools like the Python packages `svglib <https://pypi.org/project/svglib>`_, `CairoSVG <https://pypi.org/project/cairosvg>`_, `Uniconvertor <https://sk1project.net/uc2/download/>`_ or the Java solution `Apache Batik <https://github.com/apache/batik>`_. Have a look at our Wiki for more examples.\n\n.. [#f2] To also set the alpha property, add an additional step to this method by dropping or adding an alpha channel to the result.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/point.rst",
    "content": ".. include:: header.rst\n\n.. _Point:\n\n================\nPoint\n================\n\n*Point* represents a point in the plane, defined by its x and y coordinates.\n\n============================ ============================================\n**Attribute / Method**       **Description**\n============================ ============================================\n:meth:`Point.distance_to`    calculate distance to point or rect\n:meth:`Point.norm`           the Euclidean norm\n:meth:`Point.transform`      transform point with a matrix\n:attr:`Point.abs_unit`       same as unit, but positive coordinates\n:attr:`Point.unit`           point coordinates divided by *abs(point)*\n:attr:`Point.x`              the X-coordinate\n:attr:`Point.y`              the Y-coordinate\n============================ ============================================\n\n**Class API**\n\n.. class:: Point\n\n   .. method:: __init__(self)\n\n   .. method:: __init__(self, x, y)\n\n   .. method:: __init__(self, point)\n\n   .. method:: __init__(self, sequence)\n\n      Overloaded constructors.\n\n      Without parameters, *Point(0, 0)* will be created.\n\n      With another point specified, a **new copy** will be created, \"sequence\" is a Python sequence of 2 numbers (see :ref:`SequenceTypes`).\n\n     :arg float x: x coordinate of the point\n\n     :arg float y: y coordinate of the point\n\n   .. method:: distance_to(x [, unit])\n\n      Calculate the distance to *x*, which may be :data:`point_like` or :data:`rect_like`. The distance is given in units of either pixels (default), inches, centimeters or millimeters.\n\n     :arg point_like,rect_like x: to which to compute the distance.\n\n     :arg str unit: the unit to be measured in. One of \"px\", \"in\", \"cm\", \"mm\".\n\n     :rtype: float\n     :returns: the distance to *x*. If this is :data:`rect_like`, then the distance\n\n         * is the length of the shortest line connecting to one of the rectangle sides\n         * is calculated to the **finite version** of it\n         * is zero if it **contains** the point\n\n   .. method:: norm()\n\n      * New in version 1.16.0\n      \n      Return the Euclidean norm (the length) of the point as a vector. Equals result of function *abs()*.\n\n   .. method:: transform(m)\n\n      Apply a matrix to the point and replace it with the result.\n\n     :arg matrix_like m: The matrix to be applied.\n\n     :rtype: :ref:`Point`\n\n   .. attribute:: unit\n\n      Result of dividing each coordinate by *norm(point)*, the distance of the point to (0,0). This is a vector of length 1 pointing in the same direction as the point does. Its x, resp. y values are equal to the cosine, resp. sine of the angle this vector (and the point itself) has with the x axis.\n\n      .. image:: images/img-point-unit.*\n\n      :type: :ref:`Point`\n\n   .. attribute:: abs_unit\n\n      Same as :attr:`unit` above, replacing the coordinates with their absolute values.\n\n      :type: :ref:`Point`\n\n   .. attribute:: x\n\n      The x coordinate\n\n      :type: float\n\n   .. attribute:: y\n\n      The y coordinate\n\n      :type: float\n\n.. note::\n\n   * This class adheres to the Python sequence protocol, so components can be accessed via their index, too. Also refer to :ref:`SequenceTypes`.\n   * Rectangles can be used with arithmetic operators -- see chapter :ref:`Algebra`.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/pymupdf-pro/index.rst",
    "content": "\n.. include:: ../header.rst\n\n.. _pymupdf-pro:\n\n.. raw:: html\n\n    <script>\n        document.getElementById(\"headerSearchWidget\").action = '../search.html';\n    </script>\n\nPyMuPDF Pro\n=============\n\n\n|PyMuPDF Pro| is a set of *commercial extensions* for |PyMuPDF|.\n\nEnhance |PyMuPDF| capability with **Office** document support & **RAG/LLM** integrations.\n\n- Enables Office document handling, including ``doc``, ``docx``, ``hwp``, ``hwpx``, ``ppt``, ``pptx``, ``xls``, ``xlsx``, and others.\n- Supports text and table extraction, document conversion and more.\n- Includes the commercial version of |PyMuPDF4LLM|.\n\nTo enquire about obtaining a commercial license, then `use this contact page <https://artifex.com/contact/>`_.\n\n\n.. note::\n\n    A licensed version of |PyMuPDF Pro| also gives you a licensed version of |PyMuPDF4LLM|. If you are interested in using the |PyMuPDF4LLM| package you should install it separately.\n\n\nPlatform support\n--------------------\n\nAvailable for these platforms only:\n\n- Windows x86_64.\n- Linux x86_64 (glibc).\n- MacOS x86_64.\n- MacOS arm64.\n\n\nOffice file support\n----------------------\n\nIn addition to the `standard file types supported by PyMuPDF <Supported_File_Types>`, |PyMuPDF Pro| supports:\n\n.. list-table::\n   :header-rows: 1\n\n   * - **DOC/DOCX**\n     - **XLS/XLSX**\n     - **PPT/PPTX**\n     - **HWP/HWPX**\n   * - .. image:: ../images/icons/icon-docx.svg\n          :width: 40\n          :height: 40\n     - .. image:: ../images/icons/icon-xlsx.svg\n          :width: 40\n          :height: 40\n     - .. image:: ../images/icons/icon-pptx.svg\n          :width: 40\n          :height: 40\n     - .. image:: ../images/icons/icon-hangul.svg\n          :width: 40\n          :height: 40\n\n\n\nUsage\n--------------\n\nInstallation\n~~~~~~~~~~~~~~~~~~\n\nInstall via pip with:\n\n.. code-block:: bash\n\n    pip install pymupdfpro\n\n\nLoading an **Office** document\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nImport |PyMuPDF Pro| and you can then reference **Office** documents directly, e.g.:\n\n.. code-block:: python\n\n    import pymupdf.pro\n    pymupdf.pro.unlock()\n    # PyMuPDF has now been extended with PyMuPDF Pro features, with some restrictions.\n    doc = pymupdf.open(\"my-office-doc.xls\")\n\n.. note::\n\n    All standard |PyMuPDF| functionality is exposed as expected - |PyMuPDF Pro| handles the extended **Office** file types\n\n\nFrom then on you can work with document pages just as you would do normally, but with respect to the `restrictions <PyMuPDFPro_Restrictions>`.\n\n\nConverting an **Office** document to |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe following code snippet can convert your **Office** document to |PDF| format:\n\n.. code-block:: python\n\n    import pymupdf.pro\n    pymupdf.pro.unlock()\n\n    doc = pymupdf.open(\"my-office-doc.xlsx\")\n\n    pdfdata = doc.convert_to_pdf()\n    with open('output.pdf', 'wb') as f:\n        f.write(pdfdata)\n\n\n\n.. _PyMuPDFPro_Restrictions:\n\nRestrictions\n~~~~~~~~~~~~~~~~~~~~\n\n\n|PyMuPDF Pro| functionality is restricted without a license key as follows:\n\n    **Only the first 3 pages of any document will be available.**\n\nTo unlock full functionality you should `obtain a trial key <https://pymupdf.pro/try-pro/>`_.\n\n\n.. _PyMuPDFPro_TrialKeys:\n\nTrial keys\n-----------------------\n\nTo obtain a license key `please fill out the form on this page <https://pymupdf.pro/try-pro/>`_. You will then have the trial key emailled to the address you submitted.\n\n\nUsing a key\n~~~~~~~~~~~~~~~~\n\n\nInitialize |PyMuPDF Pro| with a key as follows:\n\n.. code-block:: python\n\n    import pymupdf.pro\n    pymupdf.pro.unlock(my_key)\n    # PyMuPDF has now been extended with PyMuPDF Pro features.\n\nThis will allow you to evaluate the product for a limited time. If you want to use |PyMuPDF Pro| after this time you should then `enquire about obtaining a commercial license <https://artifex.com/products/pymupdf-pro/>`_.\n\n\nFonts\n-----------------------\n\nBy default `pymupdf.pro.unlock()` searches for all installed font directories.\n\nThis can be controlled with keyword-only args:\n\n* `fontpath`: specific font directories, either as a list/tuple or `os.sep`-separated string.\n  If None (the default), we use `os.environ['PYMUPDFPRO_FONT_PATH']` if set.\n* `fontpath_auto`: Whether to append system font directories.\n  If None (the default) we use true if `os.environ['PYMUPDFPRO_FONT_PATH_AUTO']` is '1'.\n  If true we append all system font directories.\n\nFunction `pymupdf.pro.get_fontpath()` returns a tuple of all font directories used by `unlock()`.\n\n\n.. raw:: html\n\n   <button id=\"findOutAboutPyMuPDFPro\" class=\"cta orange\" onclick=\"window.location='https://pymupdf.pro/try-pro/?utm_source=rtd-pymupdf&utm_medium=rtd&utm_content=cta-button'\">Ready to try PyMuPDF Pro?</button>\n\n\n\n.. include:: ../footer.rst\n"
  },
  {
    "path": "docs/pymupdf4llm/api.rst",
    "content": ".. include:: ../header.rst\n\n\n.. |PyMuPDFLayoutMode_Ignored| raw:: html\n\n    <cite style=\"font-size:12px;color:#c0c0c0;background:transparent;border:1px solid #c0c0c0;border-radius:5px;padding:3px;\"><a href=\"#pymupdf4llm-api-layout\">use_layout()</a> must be <span style=\"font-family:monospace;\">False</span></cite>\n\n.. |PyMuPDFLayoutMode_Valid| raw:: html\n\n    <span></span>\n\n.. |PyMuPDFLayoutMode_EmptyList| raw:: html\n\n    <cite style=\"font-size:12px;color:#c0c0c0;background:transparent;border:1px solid #c0c0c0;border-radius:5px;padding:3px;\">Only if <a href=\"#pymupdf4llm-api-layout\">use_layout()</a> is <span style=\"font-family:monospace;\">False</span></cite>\n\n.. |PyMuPDFLayoutMode_Unavailable| raw:: html\n\n    <cite style=\"font-size:12px;color:#c0c0c0;background:transparent;border:1px solid #c0c0c0;border-radius:5px;padding:3px;\">Only if <a href=\"#pymupdf4llm-api-layout\">use_layout()</a> is <span style=\"font-family:monospace;\">False</span></cite>\n\n.. _pymupdf4llm-api:\n\n\n\n\nThe PyMuPDF4LLM API\n===========================================================================\n\n\n.. property:: version\n\n    Prints the version of the library.\n\n\n.. method:: to_markdown(doc: pymupdf.Document | str, *, \\\n    detect_bg_color: bool = True, \\\n    dpi: int = 150, \\\n    embed_images: bool = False, \\\n    extract_words: bool = False, \\\n    filename: str | None = None, \\\n    fontsize_limit: float = 3, \\\n    footer: bool = True, \\\n    force_ocr: bool = False, \\\n    force_text: bool = True, \\\n    graphics_limit: int = None, \\\n    hdr_info: Any = None, \\\n    header: bool = True, \\\n    ignore_alpha: bool = False, \\\n    ignore_code: bool = False, \\\n    ignore_graphics: bool = False, \\\n    ignore_images: bool = False, \\\n    image_format: str = \"png\", \\\n    image_path: str = \"\", \\\n    image_size_limit: float = 0.05, \\\n    margins: float | list = 0, \\\n    ocr_dpi: int = 300, \\\n    ocr_function: callable = None, \\\n    ocr_language: str = \"eng\", \\\n    page_chunks: bool = False, \\\n    page_height: float = None, \\\n    page_separators: bool = False, \\\n    page_width: float = 612, \\\n    pages: list | range | None = None, \\\n    show_progress: bool = False, \\\n    table_strategy: str = \"lines_strict\", \\\n    use_glyphs: bool = False, \\\n    use_ocr: bool = True, \\\n    write_images: bool = False) -> str | list[dict]\n\n    Reads the pages of the file and outputs the text of its pages in |Markdown| format. How this should happen in detail can be influenced by a number of parameters. Please note that **support for building page chunks** from the |Markdown| text is supported.\n\n    :arg Document,str doc: the file, to be specified either as a file path string, or as a |PyMuPDF| :class:`Document` (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| :class:`Document`.\n\n    :arg bool detect_bg_color: |PyMuPDFLayoutMode_Ignored| does a simple check for the general background color of the pages (default is ``True``). If any text or vector has this color it will be ignored. May increase detection accuracy.\n\n    :arg int dpi: specify the desired image resolution in dots per inch. Relevant only if `write_images=True` or `embed_images=True`. Default value is 150.\n\n    :arg bool embed_images: like `write_images`, but images will be included in the markdown text as base64-encoded strings. Mutually exclusive with `write_images` and ignores `image_path`. This may drastically increase the size of your markdown text.\n\n    :arg bool extract_words: |PyMuPDFLayoutMode_Ignored| a value of `True` enforces `page_chunks=True` and adds key \"words\" to each page dictionary. Its value is a list of words as delivered by PyMuPDF's `Page` method `get_text(\"words\")`. The sequence of the words in this list is the same as the extracted text.\n\n    :arg str filename: Overwrites or sets the desired image file name of written images. Useful when the document is provided as a memory object (which has no inherent file name).\n\n    :arg float fontsize_limit: |PyMuPDFLayoutMode_Ignored| limit the font size to consider for text extraction. If the font size is lower than what is set then the text won't be considered for extraction. Default is `3`, meaning only text with a font size `>= 3` will be considered for extraction.\n\n    :arg bool footer: |PyMuPDFLayoutMode_Valid| boolean to switch on/off page footer content. This parameter controls whether to include or omit footer text from all the document pages. Useful if the document has repetitive footer content which doesn't add any value to the overall extraction data. Default is `True` meaning that footer content will be considered.\n\n    :arg bool force_ocr: |PyMuPDFLayoutMode_Valid| if `True`, OCR will be applied to all pages regardless of their content.\n        \n        This may be useful for documents which are known to be image-based and thus profit from OCR, but which do not meet the default criteria for applying OCR. Default is `False` meaning that OCR will only be applied to pages which meet the default criteria.\n\n        .. warning:: \n            Requires that either one of the default supported OCR engines is installed or `ocr_function` specifies a callable OCR function. Otherwise, an exception will be raised.\n\n    :arg bool force_text: generate text output even when overlapping images / graphics. This text then appears after the respective image.\n\n    :arg int graphics_limit: |PyMuPDFLayoutMode_Ignored| use this to limit dealing with excess amounts of vector graphics elements. Scientific documents, or pages simulating text via graphics commands may contain tens of thousands of these objects. As vector graphics are analyzed for multiple purposes, runtime may quickly become intolerable. With this parameter, all vector graphics will be ignored if their count exceeds the threshold.\n\n    :arg hdr_info: |PyMuPDFLayoutMode_Ignored| use this if you want to provide your own header detection logic. This may be a callable or an object having a method named `get_header_id`. It must accept a text span (a span dictionary as contained in :meth:`~.extractDICT`) and a keyword parameter \"page\" (which is the owning :ref:`Page <page>` object). It must return a string \"\" or up to 6 \"#\" characters followed by 1 space. If omitted (`None`), a full document scan will be performed to find the most popular font sizes and derive header levels based on them. To completely avoid this behavior specify `hdr_info=lambda s, page=None: \"\"` or `hdr_info=False`.\n\n    :arg bool header: |PyMuPDFLayoutMode_Valid| boolean to switch on/off page header content. This parameter controls whether we want to include or omit the header content from all the document pages. Useful if the document has repetitive header content which doesn't add any value to the overall extraction data. Default is `True` meaning that header content will be considered.\n\n    :arg bool ignore_alpha: |PyMuPDFLayoutMode_Ignored| if ``True`` includes text even when completely transparent. Default is ``False``: transparent text will be ignored which usually increases detection accuracy.\n\n    :arg bool ignore_code: if `True` then mono-spaced text lines do not receive special formatting. Code blocks will no longer be generated. This value is set to `True` if `extract_words=True` is used.\n\n    :arg bool ignore_graphics: |PyMuPDFLayoutMode_Ignored| (New in v.0.0.20) Disregard vector graphics on the page. This may help detecting text correctly when pages are very crowded (often the case for documents representing presentation slides). Also speeds up processing time. This automatically prevents table detection.\n\n    :arg bool ignore_images: |PyMuPDFLayoutMode_Ignored| (New in v.0.0.20) Disregard images on the page. This may help detecting text correctly when pages are very crowded (often the case for documents representing presentation slides). Also speeds up processing time.\n\n    :arg str image_format: specify the desired image format via its extension. Default is \"png\" (portable network graphics). Another popular format may be \"jpg\". Possible values are all :ref:`supported output formats <Supported_File_Types>`.\n\n    :arg str image_path: store images in this folder. Relevant if `write_images=True`. Default is the path of the script directory.\n\n    :arg float image_size_limit: |PyMuPDFLayoutMode_Ignored| this must be a ``0 <= value < 1``. Images are ignored if `width / page.rect.width <= image_size_limit` or `height / page.rect.height <= image_size_limit`. For instance, the default value 0.05 means that to be considered for inclusion, an image's width and height must be larger than 5% of the page's width and height, respectively.\n\n    :arg float,list margins: |PyMuPDFLayoutMode_Ignored| a float or a sequence of 2 or 4 floats specifying page borders. Only objects inside the margins will be considered for output.\n\n        * `margin=f` yields `(f, f, f, f)` for `(left, top, right, bottom)`.\n        * `(top, bottom)` yields  `(0, top, 0, bottom)`.\n        * To always read full pages **(default)**, use `margins=0`.\n\n    :arg int ocr_dpi: |PyMuPDFLayoutMode_Valid| specify the desired image resolution in dots per inch for applying OCR to the intermediate image of the page. Default value is 300. Only relevant if the page has been determined to profit from OCR (no or few text, most of the page covered by images or character-like vectors, etc.). Larger values do not usually increase the OCR precision. There also is a risk of over-sharpening the image which may decrease OCR precision. So the default value should probably be sufficiently high - in many cases you should see satisfactory results already with values of 150 or 200. Be aware that processing time and memory requirements grow quadratically with this value (an O(ocr_dpi²) impact). \n\n    :arg callable ocr_function: |PyMuPDFLayoutMode_Valid| if you want to provide your own :ref:`OCR function <pymupdf_layout_ocr_engines>`, specify it here. If omitted (`None`), one of the available built-in OCR engines will be used.\n\n    :arg str ocr_language: |PyMuPDFLayoutMode_Valid| specify the language to be used by the Tesseract OCR engine. Default is \"eng\" (English). Make sure that the respective language data files are installed. Remember to use correct Tesseract language codes. Multiple languages can be specified by concatenating the respective codes with a plus sign \"+\", for example \"eng+deu\" for English and German.\n\n    :arg bool page_chunks: if `True` the output will be a list of `Document.page_count` dictionaries (one per page). Each dictionary has the following structure:\n\n        - **\"metadata\"** - a dictionary consisting of the document's metadata :attr:`Document.metadata`, enriched with additional keys **\"file_path\"** (the file name), **\"page_count\"** (number of pages in document), and **\"page_number\"** (1-based page number).\n\n        - **\"toc_items\"** - a list of Table of Contents items pointing to this page. Each item of this list has the format `[lvl, title, pagenumber]`, where `lvl` is the hierarchy level, `title` a string and `pagenumber` as a 1-based page number.\n\n        - **\"tables\"** - |PyMuPDFLayoutMode_EmptyList| a list of tables on this page. Each item is a dictionary with keys \"bbox\", \"row_count\" and \"col_count\". Key \"bbox\" is a `pymupdf.Rect` in tuple format of the table's position on the page.\n\n        - **\"images\"** - |PyMuPDFLayoutMode_EmptyList| a list of images on the page. This a copy of page method :meth:`Page.get_image_info`.\n\n        - **\"graphics\"** - |PyMuPDFLayoutMode_EmptyList| a list of vector graphics rectangles on the page. This is a list of boundary boxes of clustered vector graphics as delivered by method :meth:`Page.cluster_drawings`.\n\n        - **\"text\"** - page content as |Markdown| text.\n\n        - **\"words\"** - |PyMuPDFLayoutMode_EmptyList| if `extract_words=True` was used. This is a list of tuples `(x0, y0, x1, y1, \"wordstring\", bno, lno, wno)` as delivered by `page.get_text(\"words\")`. The **sequence** of these tuples however is the same as produced in the markdown text string and thus honors multi-column text. This is also true for text in tables: words are extracted in the sequence of table row cells.\n\n        - **\"text\"** - page content as |Markdown| text.\n\n        - **\"page_boxes\"** - |PyMuPDFLayoutMode_Valid| a list of dictionaries representing the layout boundary boxes. Each dictionary has the following structure::\n\n            {\n                \"index\": int,              # 0-based integer index of the box in reading sequence\n                \"class\": str,              # one of \"text\", \"picture\", \"table\", etc.\n                \"bbox\": [x0, y0, x1, y1],  # boundary box coordinates\n                \"pos\": (start, stop),      # 0-based integers: bbox_text = chunk[\"text\"][start:stop]\n            }\n\n    :arg float page_height: specify a desired page height. For relevance see the `page_width` parameter. If using the default `None`, the document will appear as one large page with a width of `page_width`. Consequently in this case, no markdown page separators will occur (except the final one), respectively only one page chunk will be returned.\n\n    :arg bool page_separators: if ``True`` inserts a string ``--- end of page=n ---`` at the end of each page output. Intended for debugging purposes. The page number is 0-based. The separator string is wrapped with line breaks. Default is ``False``.\n\n    :arg float page_width: specify a desired page width. This is ignored for documents with a fixed page width like PDF, XPS etc. **Reflowable** documents however, like e-books, office [#f2]_ or text files have no fixed page dimensions. They by default are assumed to have Letter format width (612) and an **unlimited** page height. This means that the **full document is treated as one large page.**\n\n    :arg list pages: optional, the pages to consider for output (caution: specify 0-based page numbers). If omitted (`None`) all pages are processed. Any Python sequence with integer items is accepted. The sequence is sorted and processed to only contain unique items.\n\n    :arg bool show_progress: Default is `False`. A value of `True` displays a progress bar as pages are being converted. Package `tqdm <https://pypi.org/project/tqdm/>`_ is used if installed, otherwise the built-in text based progress bar is used.\n\n    :arg str table_strategy: |PyMuPDFLayoutMode_Ignored| see: :meth:`table detection strategy <Page.find_tables>`. Default is `\"lines_strict\"` which ignores background colors. In some occasions, other strategies may be more successful, for example `\"lines\"` which uses all vector graphics objects for detection.\n\n    :arg bool use_glyphs: |PyMuPDFLayoutMode_Ignored| (New in v.0.0.19) Default is `False`. A value of `True` will use the glyph number of the characters instead of the character itself if the font does not store the Unicode value.\n\n    :arg bool use_ocr: |PyMuPDFLayoutMode_Valid| use :ref:`OCR capability <pymupdf_layout_ocr_support>` to help analyse the page. This will OCR pages as determined by the default criteria.\n\n    :arg bool write_images: when encountering images or vector graphics, images will be created from the respective page area and stored in the specified folder. |Markdown| references will be generated pointing to these images. Any text contained in these areas will not be included in the text output (but appear as part of the images). Therefore, if for instance your document has text written on full page images, make sure to set this parameter to `False`.\n\n        If using :ref:`PyMuPDF Layout <pymupdf-layout>`, boundary boxes that are classified as \"picture\" by the layout module will be treated as images - independent from the mixture of text, images or vector graphics they may be covering. If `force_text=True` is used, text will still be extracted from these areas and included in the output  after the respective image reference.\n\n    :returns: Either a string of the combined text of all selected document pages, or a list of dictionaries if `page_chunks=True`.\n\n\n.. method:: to_text(doc: pymupdf.Document | str, *, **kwargs) -> str\n\n    Reads the pages of the file and outputs the text of its pages in plain text (|TXT|) format.\n\n    :arg Document,str doc: the file, to be specified either as a file path string, or as a |PyMuPDF| :class:`Document` (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| :class:`Document`.\n\n    :arg bool use_ocr: |PyMuPDFLayoutMode_Valid| use :ref:`OCR capability <pymupdf_layout_ocr_support>` to help analyse the page.\n\n    :arg str ocr_language: |PyMuPDFLayoutMode_Valid| specify the language to be used by the Tesseract OCR engine. Default is \"eng\" (English). Make sure that the respective language data files are installed. Remember to use correct Tesseract language codes. Multiple languages can be specified by concatenating the respective codes with a plus sign \"+\", for example \"eng+deu\" for English and German.\n\n    :arg int ocr_dpi: |PyMuPDFLayoutMode_Valid| specify the desired image resolution in dots per inch for applying OCR to the intermediate image of the page. Default value is 400. Only relevant if the page has been determined to profit from OCR (no or few text, most of the page covered by images or character-like vectors, etc.). Large values may increase the OCR precision but increase memory requirements and processing time. There also is a risk of over-sharpening the image which may decrease OCR precision. So the default value should probably be sufficiently high.\n\n    :arg bool header: boolean to switch on/off page header content. This parameter controls whether to include or omit the header content from all the document pages. Useful if the document has repetitive header content which doesn't add any value to the overall extraction data. Default is `True` meaning that header content will be written.\n\n    :arg bool footer: boolean to switch on/off page footer content. This parameter controls whether to include or omit the footer content from all the document pages. Useful if the document has repetitive footer content which doesn't add any value to the overall extraction data. Default is `True` meaning that footer content will be written.\n\n    :arg bool ignore_code: if `True` then mono-spaced text lines do not receive special formatting. No blocks will be written and text lines will be written continuously.\n\n    :arg list pages: optional, the pages to consider for output (caution: specify 0-based page numbers). If omitted (`None`) all pages are processed. Any Python sequence with integer items is accepted. The sequence is sorted and processed to only contain unique items.\n\n    :arg bool force_text: generate text output also when overlapping images / graphics. This text then appears after the respective image reference. Images (i.e. \"picture\" areas) however will not be written to the text output but appear as a text line in the output like `==> picture [width x height] <==`.\n\n    :arg bool show_progress: Default is `False`. A value of `True` displays a progress bar as pages are being converted. Package `tqdm <https://pypi.org/project/tqdm/>`_ is used if installed, otherwise the built-in text based progress bar is used.\n    \n    :arg bool page_chunks: if `True` the output will be a list of `Document.page_count` dictionaries (one per page). Each dictionary has the following structure:\n\n        - **\"metadata\"** - a dictionary consisting of the document's metadata :attr:`Document.metadata`, enriched with additional keys **\"file_path\"** (the file name), **\"page_count\"** (number of pages in document), and **\"page_number\"** (1-based page number).\n\n        - **\"toc_items\"** - a list of Table of Contents items pointing to this page. Each item of this list has the format `[lvl, title, pagenumber]`, where `lvl` is the hierarchy level, `title` a string and `pagenumber` as a 1-based page number.\n\n        - **\"tables\"** - empty list.\n        - **\"images\"** - empty list.\n        - **\"graphics\"** - empty list.\n        - **\"words\"** - empty list.\n\n        - **\"text\"** - page content as plain text.\n\n        - **\"page_boxes\"** - a list of dictionaries representing the layout boundary boxes. Each dictionary has the following structure::\n\n            {\n                \"index\": int,              # 0-based integer index of the box in reading sequence\n                \"class\": str,              # one of \"text\", \"picture\", \"table\", etc.\n                \"bbox\": [x0, y0, x1, y1],  # boundary box coordinates\n                \"pos\": (start, stop),      # 0-based integers: bbox_text = chunk[\"text\"][start:stop]\n            }\n\n\n.. method:: to_json(doc: pymupdf.Document | str, *, **kwargs) -> str\n\n    Parses the document and the specified pages and converts the result into a |JSON|-formatted string.\n\n    :arg Document,str doc: the file, to be specified either as a file path string, or as a |PyMuPDF| :class:`Document` (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| :class:`Document`.\n\n    :arg bool use_ocr: |PyMuPDFLayoutMode_Valid| use :ref:`OCR capability <pymupdf_layout_ocr_support>` to help analyse the page.\n\n    :arg str ocr_language: |PyMuPDFLayoutMode_Valid| specify the language to be used by the Tesseract OCR engine. Default is \"eng\" (English). Make sure that the respective language data files are installed. Remember to use correct Tesseract language codes. Multiple languages can be specified by concatenating the respective codes with a plus sign \"+\", for example \"eng+deu\" for English and German.\n\n    :arg int ocr_dpi: |PyMuPDFLayoutMode_Valid| specify the desired image resolution in dots per inch for applying OCR to the intermediate image of the page. Default value is 400. Only relevant if the page has been determined to profit from OCR (no or few text, most of the page covered by images or character-like vectors, etc.). Large values may increase the OCR precision but increase memory requirements and processing time. There also is a risk of over-sharpening the image which may decrease OCR precision. So the default value should probably be sufficiently high.\n\n    :arg int image_dpi: specify the desired image resolution in dots per inch. Default value is 150. Only relevant if one of the parameters `write_images=True` or `embed_images=True` is used.\n\n    :arg str image_format: specify the desired image format via its extension. Default is \"png\" (portable network graphics). Another popular format may be \"jpg\". Possible values are all :ref:`supported output formats <Supported_File_Types>`. Only relevant if one of the parameters `write_images=True` or `embed_images=True` is used.\n\n    :arg str image_path: store images in this folder. Relevant if `write_images=True`. Default is the path of the script directory. Page areas classified as \"picture\" will be written as image files to the specified location. The image file names will be of the format `{image_path}/{filename}-pagenumber-image_number.{image_format}`.\n\n    :arg bool force_text: generate text output for text that is written upon areas that are classified as \"picture\" by the layout module. This may be especially be useful when picture content is not stored.\n\n    :arg bool show_progress: display a progress bar during processing.\n\n    :arg bool embed_images: store image binaries for \"picture\" boundary boxes. Base64-encoded images are included in the JSON output. Ignores `image_path` if used. This may drastically increase the size of your JSON text.\n\n    :arg bool write_images: store image files \"picture\" boundary boxes.when encountering images, image files will be created from the respective page area and stored in the specified folder. Any text contained in these areas will still be included in the text output.\n\n    :arg list pages: optional, the pages to consider for output (caution: specify 0-based page numbers). If omitted (`None`) all pages are processed. Specify any valid Python sequence containing integers between `0` and `page_count - 1`.\n\n\n.. _pymupdf4llm-api-layout:\n\n\n.. method:: use_layout(yes: bool = True)\n\n    Switch on/off the use of the :ref:`PyMuPDF Layout module <pymupdf4llm_and_layout>`. \n    \n    If `yes=True` (default), the layout module will be used for page analysis for optimal results. If `yes=False`, the layout module will not be used.\n\n\n.. method:: get_key_values(doc: pymupdf.Document | str) -> list[dict]\n\n    Parse the document if it is a **Form PDF** and extract key-value pairs from all form fields (widgets).\n    \n    Please note that this method is only relevant for PDF documents that contain widgets. Otherwise, an empty list will be returned.\n\n    The function is always available -- independently of whether you are using the PyMuPDF Layout module or not.\n\n    Each dictionary item has the following structure::\n\n        {\n            \"field_name\": str,      # the full name of the form field, components separated by dots\n            {\n                \"value\": str,       # the field value as string\n                \"pages\": list,      # list of 0-based page numbers where the field appears\n            }\n        }    \n\n.. note::\n\n    Please see `this site <https://github.com/pymupdf/pymupdf4llm/discussions/327>`_ for more background and the current status of further improvements regarding usage with :ref:`PyMuPDF Layout <pymupdf-layout>`.\n\n\n.. method:: LlamaMarkdownReader(*args, **kwargs)\n\n    Create a `pdf_markdown_reader.PDFMarkdownReader` using the `LlamaIndex`_ package. Please note that this package will **not automatically be installed** when installing **pymupdf4llm**.\n\n    For details on the possible arguments, please consult the LlamaIndex documentation [#f1]_.\n\n    :raises: `NotImplementedError`: Please install required `LlamaIndex`_ package.\n    :returns: a `pdf_markdown_reader.PDFMarkdownReader` and issues message \"Successfully imported LlamaIndex\". Please note that this method needs several seconds to execute. For details on using the markdown reader please see below.\n\n----\n\n\n.. class:: IdentifyHeaders\n\n    .. note:: |PyMuPDFLayoutMode_Unavailable|\n\n\n    .. method:: __init__(self, doc: pymupdf.Document | str, *, pages: list | range | None = None, body_limit: float = 11, max_levels: int = 6)\n\n        Create an object which maps text font sizes to the respective number of '#' characters which are used by Markdown syntax to indicate header levels. The object is created by scanning the document for font size \"popularity\". The most popular font size and all smaller sizes are used for body text. Larger font sizes are mapped to the respective header levels - which correspond to the HTML tags `<h1>` to `<h6>`.\n\n        All font sizes are rounded to integer values.\n\n        If more than 6 header levels would be required, then the largest number smaller than the `<h6>` font size is used for body text.\n\n        Please note that creating the object will read and inspect the text of the entire document - independently of reading the document again in the `to_markdown()` method subsequently. Method `to_markdown()` by default **will create this object** if you do not override its `hdr_info=None` parameter.\n        \n\n        :arg Document,str doc: the file, to be specified either as a file path string, or as a |PyMuPDF| Document (created via `pymupdf.open`). In order to use `pathlib.Path` specifications, Python file-like objects, documents in memory etc. you **must** use a |PyMuPDF| Document.\n\n        :arg list pages: optional, the pages to consider. If omitted all pages are processed.\n\n        :arg float body_limit: the default font size limit for body text. Only used when the document scan does not deliver valid information.\n\n        :arg int max_levels: the maximum number of header levels to be used. Valid values are in `range(1, 7)`. The default is 6, which corresponds to the HTML tags `<h1>` to `<h6>`. A smaller value will limit the number of generated header levels. For instance, a value of 3 will only generate header tags \"#\", \"##\" and \"###\". Body text will be assumed for all font sizes smaller than the one corresponding to \"###\".\n\n\n    .. method:: get_header_id(self, span: dict, page=None) -> str\n    \n        Return appropriate markdown header prefix. This is either \"\" or a string of \"#\" characters followed by a space.\n\n        Given a text span from a \"dict\" extraction, determine the markdown header prefix string of 0 to n concatenated '#' characters.\n\n        :arg dict span: a dictionary containing the text span information. This is the same dictionary as returned by `page.get_text(\"dict\")`.\n\n        :arg Page page: the owning page object. This can be used when additional information needs to be extracted.\n\n        :returns: a string of \"#\" characters followed by a space.\n\n    .. attribute:: header_id\n    \n        A dictionary mapping (integer) font sizes to Markdown header strings like ``{14: '# ', 12: '## '}``. The dictionary is created by the :class:`IdentifyHeaders` constructor. The keys are the font sizes of the text spans in the document. The values are the respective header strings.\n\n    .. attribute:: body_limit\n\n        An integer value indicating the font size limit for body text. This is computed as ``min(header_id.keys()) - 1``. In the above example, body_limit would be 11.\n\n\n----\n\n\n**How to limit header levels (example)**\n\nLimit the generated header levels to 3::\n\n    import pymupdf, pymupdf4llm\n\n    filename = \"input.pdf\"\n    doc = pymupdf.open(filename)  # use a Document for subsequent processing\n    my_headers = pymupdf4llm.IdentifyHeaders(doc, max_levels=3)  # generate header info\n    md_text = pymupdf4llm.to_markdown(doc, hdr_info=my_headers)\n\n\n**How to provide your own header logic (example 1)**\n\nProvide your own function which uses pre-determined, fixed font sizes::\n\n    import pymupdf, pymupdf4llm\n\n    filename = \"input.pdf\"\n    doc = pymupdf.open(filename)  # use a Document for subsequent processing\n\n    def my_headers(span, page=None):\n        \"\"\"\n        Provide some custom header logic.\n        This is a callable which accepts a text span and the page.\n        Could be extended to check for other properties of the span, for\n        instance the font name, text color and other attributes.\n        \"\"\"\n        # header level is h1 if font size is larger than 14\n        # header level is h2 if font size is larger than 10\n        # otherwise it is body text\n        if span[\"size\"] > 14:\n            return \"# \"\n        elif span[\"size\"] > 10:\n            return \"## \"\n        else:\n            return \"\"\n    \n    # this will *NOT* scan the document for font sizes!\n    md_text = pymupdf4llm.to_markdown(doc, hdr_info=my_headers)\n\n**How to provide your own header logic (example 2)**\n\nThis user function uses the document's Table of Contents -- under the assumption that the bookmark text is also present as a header line on the page (which certainly need not be the case!)::\n\n    import pymupdf, pymupdf4llm\n\n    filename = \"input.pdf\"\n    doc = pymupdf.open(filename)  # use a Document for subsequent processing\n    TOC = doc.get_toc()  # use the table of contents for determining headers\n\n    def my_headers(span, page=None):\n        \"\"\"\n        Provide some custom header logic (experimental!).\n        This callable checks whether the span text matches any of the\n        TOC titles on this page.\n        If so, use TOC hierarchy level as header level.\n        \"\"\"\n        # TOC items on this page:\n        toc = [t for t in TOC if t[-1] == page.number + 1]\n\n        if not toc:  # no TOC items on this page\n            return \"\"\n\n        # look for a match in the TOC items\n        for lvl, title, _ in toc:\n            if span[\"text\"].startswith(title):\n                return \"#\" * lvl + \" \"\n            if title.startswith(span[\"text\"]):\n                return \"#\" * lvl + \" \"\n        \n        return \"\"\n    \n    # this will *NOT* scan the document for font sizes!\n    md_text = pymupdf4llm.to_markdown(doc, hdr_info=my_headers)\n\n----\n\n\n.. class:: TocHeaders\n\n    .. note:: |PyMuPDFLayoutMode_Unavailable|\n\n    .. method:: __init__(self, doc: pymupdf.Document | str)\n\n        Create an object which uses the document's Table of Contents (TOC) to determine header levels. Upon object creation, the table of contents is read via the `Document.get_toc()` method. The TOC data is then used to determine header levels in the `to_markdown()` method.\n\n        This is an alternative to :class:`IdentifyHeaders`. Instead of running through the full document to identify font sizes, it uses the document's Table Of Contents (TOC) to identify headers on pages. Like :class:`IdentifyHeaders`, this also is no guarantee to find headers, but for well-built Table of Contents, there is a good chance for more correctly identifying header lines on document pages than the font-size-based approach.\n\n        It also has the advantage of being much faster than the font-size-based approach, as it does not execute a full document scan or even access any of the document pages.\n\n        Examples where this approach works very well are the Adobe's files on PDF documentation.\n\n        Please note that this feature **does not read document pages** where the table of contents may exist as normal standard text. It only accesses data as provided by the `Document.get_toc()` method. It will not identify any headers for documents where the table of contents is not available as a collection of bookmarks.\n\n    .. method:: get_header_id(self, span: dict, page=None) -> str\n    \n        Return appropriate markdown header prefix. This is either an empty string or a string of \"#\" characters followed by a space.\n\n        Given a text span from a \"dict\" extraction variant, determine the markdown header prefix string of 0 to n concatenated \"#\" characters.\n\n        :arg dict span: a dictionary containing the text span information. This is the same dictionary as returned by `page.get_text(\"dict\")`.\n\n        :arg Page page: the owning page object. This can be used when additional information needs to be extracted.\n\n        :returns: a string of \"#\" characters followed by a space.\n\n\n\n**How to use class TocHeaders**\n\nThis is a version of previous **example 2** that uses :class:`TocHeaders` for header identification::\n\n    import pymupdf, pymupdf4llm\n\n    filename = \"input.pdf\"\n\n    doc = pymupdf.open(filename)  # use a Document for subsequent processing\n    my_headers = pymupdf4llm.TocHeaders(doc)  # use the table of contents for determining headers\n    \n    # this will *NOT* scan the document for font sizes!\n    md_text = pymupdf4llm.to_markdown(doc, hdr_info=my_headers)\n\n-----\n\n.. class:: pdf_markdown_reader.PDFMarkdownReader\n\n    .. method:: load_data(file_path: Union[Path, str], extra_info: Optional[Dict] = None, **load_kwargs: Any) -> List[LlamaIndexDocument]\n\n        This is the only method of the markdown reader you should currently use to extract markdown data. Please in any case ignore methods `aload_data()` and `lazy_load_data()`. Other methods like `use_doc_meta()` may or may not make sense. For more information, please consult the LlamaIndex documentation [#f1]_.\n\n        Under the hood the method will execute `to_markdown()`.\n\n        :returns: a list of `LlamaIndexDocument` documents - one for each page.\n\n-----\n\nFor a list of changes, please see file `CHANGES.md <https://github.com/pymupdf/pymupdf4llm/blob/main/CHANGES.md>`_.\n\n.. rubric:: Footnotes\n\n.. [#f1] `LlamaIndex documentation <https://docs.llamaindex.ai/en/stable/>`_\n\n.. [#f2] When using PyMuPDF-Pro, supported office documents are converted internally into a PDF-like format. Therefore, they **will have fixed page dimensions** and be no longer \"reflowable\". Consequently, the page width and page height specifications will be ignored as well in these cases.\n\n\n\n\n.. include:: ../footer.rst\n\n.. _LlamaIndex: https://pypi.org/project/llama-index/\n\n\n.. raw:: html\n\n    /* this script is used to adjust the search widget and to add line breaks after parameters in the signature blocks for better readability */\n    <script>\n        document.getElementById(\"headerSearchWidget\").action = '../search.html';\n        const params = document.querySelectorAll('.sig-param')\n        \n        params.forEach((param, index) => {\n            const next = param.nextSibling;\n            if (next && next.nodeType === 3) { // 3 = text node\n                const span = document.createElement('span');\n                if (index === params.length - 1) {\n                    span.className = 'sig-comma-last';\n                } else {\n                    param.classList.add('has-comma');\n                    span.className = 'sig-comma';\n                }\n                span.textContent = next.textContent;\n                next.replaceWith(span);\n            }    \n        });\n    </script>\n\n    <style>\n        .sig-comma {\n            display: none;\n        }\n        dt .sig-param.has-comma::after {\n            content: \",\\A\";\n            white-space: pre;\n        }\n    </style>\n"
  },
  {
    "path": "docs/pymupdf4llm/index.rst",
    "content": "\n.. include:: ../header.rst\n\n.. _pymupdf4llm:\n\n\n.. raw:: html\n\n    <script>\n        document.getElementById(\"headerSearchWidget\").action = '../search.html';\n    </script>\n\n\nPyMuPDF4LLM\n===========================================================================\n\n|PyMuPDF4LLM| is a lightweight extension for |PyMuPDF| that turns PDFs into clean, structured data with minimal setup. It includes layout analysis *without* any GPU requirement.\n\n\n|PyMuPDF4LLM| makes it easy to extract document content in the format you need for **LLM** & **RAG** environments. It supports structured data extraction to :ref:`Markdown <extracting_as_md>`, :ref:`JSON <extracting_as_json>` and :ref:`TXT <extracting_as_txt>`, as well as :ref:`LlamaIndex <integration_with_llamaindex>` and :ref:`LangChain <integration_with_langchain>` integration.\n\n\n.. important::\n\n    You can also extend the supported file types to also include **Office** document formats (DOC/DOCX, XLS/XLSX, PPT/PPTX, HWP/HWPX) by :ref:`using PyMuPDF Pro with PyMuPDF4LLM <using_pymupdf4llm_with_pymupdfpro>`.\n\nFeatures\n-------------------------------\n\n    - Support for Markdown, JSON and plain text output formats.\n    - Support for multi-column pages.\n    - Support for image and vector graphics extraction.\n    - Layout analysis for better semantic understanding of document structure.\n    - Support for page chunking output.\n    - Automatic detection of pages which profit from OCR and support for various OCR engines.\n    - Integration with :ref:`LlamaIndex <integration_with_llamaindex>` & :ref:`LangChain <integration_with_langchain>`.\n\nAPI\n-------\n\nSee: :doc:`api`.\n\n\nInstallation\n----------------\n\n\nInstall the package via **pip** with:\n\n\n.. code-block:: bash\n\n    pip install pymupdf4llm\n\n\nExtracting\n-------------------------------\n\n\n.. _extracting_as_md:\n\nAs **Markdown**\n~~~~~~~~~~~~~~~~~~~~~~~\n\nTo retrieve your document content in **Markdown** use the :meth:`to_markdown` method as follows:\n\n.. code-block:: python\n\n    import pymupdf4llm\n    md = pymupdf4llm.to_markdown(\"input.pdf\")\n\n\n\n.. _extracting_as_json: \n\nAs **JSON**\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo retrieve your document content in **JSON** use the :meth:`to_json` method as follows:\n\n.. code-block:: python\n\n    import pymupdf4llm\n    json = pymupdf4llm.to_json(\"input.pdf\")\n\nThe JSON export will give you bounding box information and layout data for each element on the page. This can be used to create your own custom output formats or to simply have more detailed information about the document structure for RAG workflows & LLM integrations.\n\n\n.. _extracting_as_txt:\n\nAs **TXT**\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo retrieve your document content in **TXT** use the :meth:`to_text` method as follows:\n\n.. code-block:: python\n\n    import pymupdf4llm\n    txt = pymupdf4llm.to_text(\"input.pdf\")\n\n\n\n----\n\n.. note::\n    Instead of using filename strings as above, one can also provide a :ref:`PyMuPDF Document <Document>`.\n\n    Finally we can save the output to an external file as follows::\n\n        from pathlib import Path\n        suffix = \".md\" # or \".json\" or \".txt\"\n        Path(doc.name).with_suffix(suffix).write_bytes(md.encode())\n\nHeaders & Footers\n~~~~~~~~~~~~~~~~~~~~~~~\n\n\nMany documents will have header and footer information on each page of a PDF which you may or may not want to include. This information can be repetitive and simply not needed ( e.g. the same logo and document title or page number information is not always required when it comes to extracting the document content ).\n\n|PyMuPDF4LLM| is trained in detecting these typical document elements and able to omit them.\n\nSo in this case we can adjust our API calls to ignore these elements as follows::\n\n    md = pymupdf4llm.to_markdown(doc, header=False, footer=False)\n\n\n.. note::\n\n    Please note that page ``header`` / ``footer`` exclusion is not applicable to JSON output as it aims to always represent all data for the included pages. Please refer to :doc:`api` for more.\n\n\nIntegrations\n-------------------------------\n\n.. _integration_with_llamaindex:\n\nWith **LlamaIndex**\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n|PyMuPDF4LLM| supports direct conversion to a **LlamaIndex** document. A document is first converted into **Markdown** format and then a **LlamaIndex** document is returned as follows:\n\n\n.. code-block:: python\n\n    import pymupdf4llm\n    llama_reader = pymupdf4llm.LlamaMarkdownReader()\n    llama_docs = llama_reader.load_data(\"input.pdf\") \n\n\n.. _integration_with_langchain:\n\nWith **LangChain** \n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n|PyMuPDF4LLM| also supports **LangChain** integration, see the `PyMuPDF4LLM Document Loader`_ for more details.\n\n\n.. _using_pymupdf4llm_with_pymupdfpro:\n\nUsing with |PyMuPDF Pro|\n---------------------------\n\n\nFor **Office** document support, |PyMuPDF4LLM| works seamlessly with |PyMuPDF Pro|. Assuming you have :doc:`../pymupdf-pro/index` installed you will be able to work with **Office** documents as expected:\n\n\n.. code-block:: python\n\n    import pymupdf4llm\n    import pymupdf.pro\n    pymupdf.pro.unlock()\n    md = pymupdf4llm.to_markdown(\"sample.doc\")\n\n\n.. _pymupdf4llm_and_layout:\n\nPyMuPDF4LLM & PyMuPDF Layout\n-----------------------------------\n\nBy default |PyMuPDF4LLM| includes a `layout analysis module`_ to enhance output results. To disable this module you can do so by calling the :meth:`use_layout` method.\n\n\n\nOCR\n--------\n\nPyMuPDF4LLM includes built-in OCR support for scanned documents and image-based PDFs. By default, OCR runs **automatically** when needed — you don't have to opt in. For more control, you can force OCR on specific pages, disable it entirely, or swap in a different OCR engine using the adaptor interface.\n\n.. note::\n\n   If you want to use an OCR engine other than Tesseract, see :ref:`OCR Engines <ocr-engines>` for details.\n\n\nHybrid OCR strategy\n~~~~~~~~~~~~~~~~~~~~~~~~~\n\nPyMuPDF4LLM applies OCR only when it is genuinely required to obtain the complete text of a PDF page. If a page already contains sufficient extractable text, OCR is skipped entirely — avoiding unnecessary work and eliminating the risk of degrading high-quality digital text.\n\nWhen OCR is needed, PyMuPDF4LLM automatically selects the most suitable OCR plugin available in the runtime environment, balancing detection accuracy with processing speed.\n\nIts built-in OCR plugins implement a Hybrid OCR strategy: only those regions lacking extractable, legible text are passed to the OCR engine. This selective approach typically reduces OCR processing time by around 50% while improving recognition accuracy, since the engine focuses exclusively on the problematic regions. The recognized text is then merged back into the original page, enriching it without disturbing existing digital content.\n\n\n----\n\n\nAuto-OCR Behaviour\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nPyMuPDF4LLM inspects each page before extracting text. If a page contains **no selectable text** — meaning all content is rasterised into images — OCR is triggered automatically for that page.\n\nPages that contain native text only are never sent through OCR. This keeps processing fast and avoids degrading already-clean text.\n\n.. code-block:: python\n\n   import pymupdf4llm\n\n   # OCR runs automatically on any page with no selectable text\n   md_text = pymupdf4llm.to_markdown(\"scanned-document.pdf\")\n\nThe resulting Markdown is seamless — pages extracted via OCR and pages extracted natively are combined into a single output with no distinction between them.\n\n----\n\nHow OCR is Triggered\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThere are two scenarios where OCR is applied automatically:\n\n**No text at all** — if a page contains roughly no text but is covered with images or many character-sized vectors, PyMuPDF4LLM checks whether text is *probably* detectable on the page. This distinguishes image-based text (e.g. a scanned document) from ordinary pictures like photographs.\n\n**Garbled text** — if a page does contain text but too many characters are unreadable (e.g. ``\"�����\"``), OCR is applied **for the affected text areas only**, not the full page. This preserves already-readable text, images, and vectors while recovering only what is broken.\n\n\n----\n\nForcing OCR\n~~~~~~~~~~~~~\n\nIn some cases you may want to force OCR even on pages that contain selectable text — for example, when the native text layer is corrupt, misencoded, or misaligned with the visual content.\n\nUse ``force_ocr=True`` to bypass the auto-detection check entirely:\n\n.. code-block:: python\n\n   md_text = pymupdf4llm.to_markdown(\"document.pdf\", force_ocr=True)\n\n.. warning::\n\n   Forcing OCR on clean, text-based PDFs will slow down processing significantly and may reduce output quality. Only use ``force_ocr=True`` when you have reason to distrust the native text layer.\n\nYou can also force OCR on specific pages rather than the whole document:\n\n.. code-block:: python\n\n   md_text = pymupdf4llm.to_markdown(\n       \"document.pdf\",\n       pages=[2, 3, 4],\n       force_ocr=True\n   )\n\n----\n\nDisabling OCR\n~~~~~~~~~~~~~\n\nTo prevent OCR from running at all — even on pages with no selectable text — set ``use_ocr=False``:\n\n.. code-block:: python\n\n   md_text = pymupdf4llm.to_markdown(\"document.pdf\", use_ocr=False)\n\nPages with no selectable text will return empty strings in this mode. This is useful when you know your documents are always text-based, or when you want to handle OCR yourself in a downstream step.\n\n----\n\n.. _ocr-adaptors:\n.. _ocr-engines:\n.. _ocr-plugins:\n\nOCR Engines\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOther OCR Engines (OCR Adaptors or Plugins) can be used with PyMuPDF4LLM.\n\nSee :doc:`ocr-plugins` for details on how to use different OCR engines with PyMuPDF4LLM, including Tesseract, RapidOCR, and how to implement your own custom OCR function.\n\n\n\nOCR Language Support\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhen using the default Tesseract adaptor, you can specify one or more languages using Tesseract's language codes.\n\nSpecify the language to be used by the Tesseract OCR engine. Default is ``\"eng\"`` (English). Make sure that the respective language data files are installed. Remember to use correct Tesseract language codes. Multiple languages can be specified by concatenating the respective codes with a plus sign ``\"+\"``, for example ``\"eng+deu\"`` for English and German.\n\n.. code-block:: python\n\n   md_text = pymupdf4llm.to_markdown(\"multilingual.pdf\",\n                                      ocr_language=\"eng+deu\")\n\nTesseract language packs must be installed on your system. For example, on Ubuntu:\n\n.. code-block:: bash\n\n   sudo apt install tesseract-ocr-deu tesseract-ocr-fra\n\nSee the page on :ref:`installing Tesseract language packs <tesseract-language-packs>` for further details.\n\n----\n\nPerformance Tips\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOCR is the most compute-intensive part of the extraction pipeline. A few ways to keep it fast:\n\n- **Process only the pages you need** using the ``pages`` parameter to avoid running OCR on the entire document.\n- **Cache results** — write the output to disk after the first run so you don't re-process the same file.\n- **Use** ``force_ocr=False`` (the default) so clean pages skip OCR entirely.\n- **Resize images before passing to OCR** — very high DPI scans can slow Tesseract down without improving accuracy.\n\n----\n\n\nFurther Resources\n-------------------\n\n\nSample code\n~~~~~~~~~~~~~~~\n\n- `Command line RAG Chatbot with PyMuPDF <https://github.com/pymupdf/RAG/tree/main/examples/country-capitals>`_\n- `Example of a Browser Application using LangChain and PyMuPDF <https://github.com/pymupdf/RAG/tree/main/examples/GUI>`_\n\n\nBlogs\n~~~~~~~~~~~~~~\n\n- `RAG/LLM and PDF: Enhanced Text Extraction <https://artifex.com/blog/rag-llm-and-pdf-enhanced-text-extraction>`_\n- `Creating a RAG Chatbot with ChatGPT and PyMuPDF <https://artifex.com/blog/creating-a-rag-chatbot-with-chatgpt-and-pymupdf>`_\n- `Building a RAG Chatbot GUI with the ChatGPT API and PyMuPDF <https://artifex.com/blog/building-a-rag-chatbot-gui-with-the-chatgpt-api-and-pymupdf>`_\n- `RAG/LLM and PDF: Conversion to Markdown Text with PyMuPDF <https://artifex.com/blog/rag-llm-and-pdf-conversion-to-markdown-text-with-pymupdf>`_\n\n.. include:: ../footer.rst\n\n\n.. _PyMuPDF4LLM Document Loader: https://docs.langchain.com/oss/python/integrations/providers/pymupdf4llm/\n\n.. _layout analysis module: https://pypi.org/project/pymupdf-layout/\n"
  },
  {
    "path": "docs/pymupdf4llm/ocr-plugins.rst",
    "content": ".. include:: ../header.rst\n\n\nOCR Plugins\n======================\n\nPyMuPDF4LLM supports default OCR functions. They come in the form of plugins that are present in its `ocr` subpackage. They are based on currently 3 popular OCR engines, Tesseract OCR, RapidOCR and PaddleOCR. Some engines can be combined to make use of their strengths and mitigate their weaknesses. For example, Tesseract OCR is very good at **recognizing** text, while RapidOCR is better at **detecting** text bounding boxes in images with complex backgrounds. By combining the two engines, we can achieve better overall OCR results while at the same time also reducing the overall OCR processing time.\n\nHere is an overview of the available default plugins:\n\n============== ========================= =================================================================================\nPlugin Name    Engines                   Description\n============== ========================= =================================================================================\nrapidocr_api   RapidOCR                  Uses RapidOCR for both text **detection** and text **recognition**\npaddleocr_api  PaddleOCR                 Uses PaddleOCR for both text **detection** and text **recognition**\ntesseract_api  Tesseract OCR             Uses Tesseract OCR for both text **detection** and text **recognition**\nrapidtess_api  RapidOCR + Tesseract OCR  Uses RapidOCR for text **detection** and Tesseract OCR for text **recognition**\npaddletess_api PaddleOCR + Tesseract OCR Uses PaddleOCR for text **detection** and Tesseract OCR for text **recognition**\n============== ========================= =================================================================================\n\nIf not explicitly selected via the `ocr_function` parameter, PyMuPDF4LLM will check the availability of the three OCR engines and pick one of the above plugins in the following order of preference:\n\n1. `rapidtess_api` (if both RapidOCR and Tesseract OCR are available)\n2. `paddletess_api` (if both PaddleOCR and Tesseract OCR are available)\n3. `rapidocr_api` (if RapidOCR is available, but not Tesseract OCR)\n4. `paddleocr_api` (if PaddleOCR is available, but not Tesseract OCR)\n5. `tesseract_api` (if Tesseract OCR is available, but neither RapidOCR nor PaddleOCR are available)\n\nIf none of these engines is available (and no own plugin is provided), no OCR will be performed at all. If the `force_ocr` parameter is ``True``, an error will be raised. Otherwise, the document will be processed without OCR and a warning will be displayed.\n\nThe chosen plugin is displayed as an information message.\n\nHow Default Plugins Work\n------------------------\n\nThe provided default plugins use the following **\"hybrid\"** OCR approach:\n\n1. Each page is cleaned from any existing standard text content.\n2. The remaining page is rendered as an image and passed to the OCR engine for text detection and recognition.\n3. Only the detected text is inserted back into the original page as standard text content.\n\nIn this way, all original content (text and other elements) is preserved and only **augmented** with the newly recognized text. This allows for a more accurate and complete text extraction while also preserving the original document structure and formatting as much as possible. It also allows for a more efficient OCR processing since only the non-extractable text is processed by the OCR engine. This can significantly reduce the overall processing time.\n\nIt also increases the chances for a successful layout detection, because other original content like vectors remain intact and will not be rendered to pixels.\n\nForcing the Choice of a Default Plugin\n---------------------------------------\nThe default plugins are designed to be used as is, without any need for configuration. \n\nHowever, if you want to use a specific plugin, you can do so by using the following approach (which enforces for instance using RapidOCR and skipping the above selection process). Please note that all plugins have a function named `exec_ocr` that does the actual OCR.\n\n\nRapidOCR\n~~~~~~~~~\n\nIf `RapidOCR <https://github.com/RapidAI/RapidOCR?tab=readme-ov-file>`_ and the RapidOCR ONNX Runtime are available, you can use a pre-made callable OCR function for it, which is provided in the ``pymupdf4llm.ocr`` module as ``rapidocr_api.exec_ocr``.\n\n.. code-block:: python\n\n    import pymupdf4llm\n    from pymupdf4llm.ocr import rapidocr_api\n\n    my_ocr_function = rapidocr_api.exec_ocr\n\n    # Use my_ocr_function as the OCR function in PyMuPDF4LLM\n    md_text = pymupdf4llm.to_markdown(\"input.pdf\", ocr_function=my_ocr_function)\n\n\nRapidOCR & Tesseract Side-by-Side\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIf you want to use both OCR engines side-by-side, you can do so by implementing a custom OCR function which calls both OCR engines — one for bbox recognition (RapidOCR) and the other for text recognition (Tesseract) — and then combines their results.\n\nThis pre-made callable OCR function can be found in the ``pymupdf4llm.ocr`` module as ``rapidtess_api.exec_ocr()``.\n\n**Example**\n\n.. code-block:: python\n\n   from pymupdf4llm.ocr import rapidtess_api\n\n   md = pymupdf4llm.to_markdown(\n       doc,\n       ocr_function=rapidtess_api.exec_ocr,\n       force_ocr=True\n   )\n\n.. list-table::\n   :header-rows: 1\n   :widths: 35 25 40\n\n   * - Adaptor\n     - Engines\n     - Notes\n   * - ``rapidocr_api.exec_ocr``\n     - RapidOCR\n     - Requires RapidOCR and ONNX Runtime\n   * - ``rapidtess_api.exec_ocr``\n     - RapidOCR & Tesseract\n     - Better accuracy for bounding box detection and text recognition\n\n\nProviding your Own Plugin\n-------------------------\n\nIf you want to use your own OCR function, you can do so as follows::\n\n    import pymupdf4llm\n\n    def my_ocr_function(page, pixmap=None, dpi=300, language=\"eng\"):\n        # Your OCR implementation here\n        return None\n\n    # Use my_ocr_function as the OCR function in PyMuPDF4LLM\n    md_text = pymupdf4llm.to_markdown(\"input.pdf\", ocr_function=my_ocr_function)\n\nYour plugin must accept at least the ``page`` parameter which is a PyMuPDF Page object. The other parameters are optional. The plugin must create (or extend) the text of the passed-in page object by simply inserting text (using any of PyMuPDF's text insertion methods). No return values expected.\n\nBe prepared to accept ``None`` or a PyMuPDF Pixmap object as the `pixmap` parameter, which is the rendered image of the page if provided. Parameters ``dpi`` and ``language`` are passed through from the respective function parameters.\n\n\nSelecting Pages for OCR\n------------------------\n\nUsually in document processing, the vast majority of pages contain extractable text and do not require OCR. PyMuPDF4LLM contains logic that analyzes the content based on a number of criteria including (but not restricted to) the following:\n\n* Presence of extractable and legible (!) text\n* Presence of images that appear to contain text\n* Presence of vector graphics that simulate text\n* Presence of text generated by previous OCR activities\n\nThe OCR decision is internally based on the results of the following function::\n\n    from pymupdf4llm.helpers.utils import analyze_page\n\n    analysis = analyze_page(page)\n\nThe result ``analysis`` is a dictionary with the following keys and values. The area-related float values are computed as fractions of the total covered area.\n\n* \"covered\": pymupdf.Rect, page area covered by content\n* \"img_joins\": float, fraction of area of the joined images\n* \"img_area\": float, fraction of **sum** of image area sizes\n* \"txt_joins\": float, fraction of area of the joined text spans\n* \"txt_area\": float, fraction of **sum** of text span bbox area sizes\n* \"vec_joins\": float, fraction of area of the joined vector characters\n* \"vec_area\": float, fraction of **sum** of vector character area sizes\n* \"chars_total\": int, count of visible characters\n* \"chars_bad\": int, count of Replacement Unicode characters\n* \"ocr_spans\": int, count: text spans with ignored text (render mode 3)\n* \"img_var\": float, area-weighted image variance\n* \"img_edges\": float, area-weighted image edge energy\n* \"vec_suspicious\": int, minimum number of suspected vector-based glyphs\n* \"reason\": str, reason for the OCR decision, else ``None``\n* \"needs_ocr\": bool, OCR decision (recommendation)\n\nThe reason is one of the following values:\n* \"chars_bad\": more than 10% of all characters are illegible (i.e. Replacement Unicode characters)\n* \"ocr_spans\": there exist text spans created from previous OCR executions (render mode 3)\n* \"vec_text\": there exist suspected vector-based glyphs\n* \"img_text\": there exist images which (probably) contain recognizable text\n\nBased on this analysis, PyMuPDF4LLM will decide whether to invoke or skip OCR for a page. This is done to optimize processing time and resource usage by only performing OCR when it is likely to yield additional text content that cannot be extracted by other means.\n\nYou can override this logic in the following ways:\n\n1. By setting `force_ocr=True` in the output functions (`to_markdown`, `to_text`, `to_json`). All pages will then be OCRed with the selected or provided OCR function regardless of their content. This will obviously have a massive impact on your execution time: expect several seconds duration per each page.\n\n2. Do as before, but add your own selection logic to the OCR plugin::\n\n    import pymupdf4llm\n    from pymupdf4llm.ocr import rapidocr_api\n    from pymupdf4llm.helpers.utils import analyze_page\n\n    def my_ocr_function(page, pixmap=None, dpi=300, language=\"eng\"):\n        # analyze the page content and perform OCR only if necessary\n        analysis = analyze_page(page)\n\n        # inspect the items of the analysis dictionary to make your own\n        # decision about whether to perform OCR or not, e.g.:\n        if not analysis[\"needs_ocr\"]:\n            # accept decision NOT to perform OCR:\n            return None\n\n        # if OCR is recommended, you can decide differently based on\n        # your own insights, e.g. we might want to accept previous OCR\n        # results and skip OCR if there are already text spans created\n        # from previous OCR executions (render mode 3):\n        if analysis[\"reason\"] == \"ocr_spans\":\n            return None\n\n        # execute desired OCR engine\n        rapidocr_api.exec_ocr(page, pixmap=pixmap, dpi=dpi, language=language)\n        return None\n\n    md_text = pymupdf4llm.to_markdown(\"input.pdf\", force_ocr=True, ocr_function=my_ocr_function, ...)\n\n.. include:: ../footer.rst\n"
  },
  {
    "path": "docs/pyodide.rst",
    "content": ".. include:: header.rst\n\nPyodide\n=======\n\n\nOverview\n--------\n\n*\n  `Pyodide <https://pyodide.org>`_ is a client-side Python implementation that\n  runs in a web browser.\n\n* The Pyodide build of PyMuPDF is currently experimental.\n\n\nBuilding a PyMuPDF wheel for Pyodide\n------------------------------------\n\nA PyMuPDF wheel for Pyodide can be built by running `scripts/gh_release.py`\nwith some environmental variable settings. This is regularly tested on Github\nby `.github/workflows/test_pyodide.yml`.\n\nHere is an example of this, a single Linux command (to be run with the current\ndirectory set to a PyMuPDF checkout), that builds a Pyodide wheel::\n\n    inputs_sdist=0 \\\n    inputs_PYMUPDF_SETUP_MUPDF_BUILD=\"git:--recursive --depth 1 --shallow-submodules --branch master https://github.com/ArtifexSoftware/mupdf.git\" \\\n    inputs_wheels_default=0 \\\n    inputs_wheels_linux_pyodide=1 \\\n    ./scripts/gh_release.py build\n\nThis does the following (all inside Python venv's):\n\n* Download (git clone and pip install) and customise a Pyodide build environment.\n* Download (git clone) the latest MuPDF.\n* Build MuPDF and PyMuPDF in the Pyodide build environment.\n* Create a wheel in `dist/`.\n\nFor more information, see the comments for functions `build_pyodide_wheel()`\nand `pyodide_setup()` in `scripts/gh_release.py`.\n\n\nUsing a Pyodide wheel\n---------------------\n\n*\n  Upload the wheel (for example\n  `PyMuPDF/dist/PyMuPDF-1.24.2-cp311-cp311-emscripten_3_1_32_wasm32.whl`) to a\n  webserver which has been configured to allow Cross-origin resource sharing\n  (https://en.wikipedia.org/wiki/Cross-origin_resource_sharing).\n\n*\n  The wheel can be used in a Pyodide console running in a web browser, or a\n  JupyterLite notebook running in a web browser.\n\n  * To create a Pyodide console, go to:\n\n    https://pyodide.org/en/stable/console.html\n\n  * To create a JupyterLite notebook, go to:\n\n    https://jupyterlite.readthedocs.io/en/latest/_static/lab/index.html\n\n*\n  In both these cases, one can use the following code to download the wheel\n  (replace `url` with the URL of the uploaded wheel) and import it::\n\n      import pyodide_js\n      await pyodide_js.loadPackage(url)\n      import pymupdf\n\n  *\n    Note that `micropip.install()` does not work, because of PyMuPDF's use of\n    shared libraries.\n\n\nLoading a PDF document from a URL into PyMuPDF\n----------------------------------------------\n\n*\n  Pyodide browser console does not have generic network access, so for\n  example `urllib.request.urlopen(url)` fails. But Pyodide has a built-in\n  `pyodide.http` module that uses javascript internally, which one can use\n  to download into a `bytes` instance, which can be used to create a PyMuPDF\n  `Document` instance::\n\n      import pyodide.http\n      r = await pyodide.http.pyfetch('https://...')\n      data = await r.bytes()\n      doc = pymupdf.Document(stream=data)\n\n* It looks like this only works with `https://`, not `http://`.\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/quad.rst",
    "content": ".. include:: header.rst\n\n.. _Quad:\n\n==========\nQuad\n==========\n\nRepresents a four-sided mathematical shape (also called \"quadrilateral\" or \"tetragon\") in the plane, defined as a sequence of four :ref:`Point` objects ul, ur, ll, lr (conveniently called upper left, upper right, lower left, lower right).\n\nQuads can **be obtained** as results of text search methods (:meth:`Page.search_for`), and they **are used** to define text marker annotations (see e.g. :meth:`Page.add_squiggly_annot` and friends), and in several draw methods (like :meth:`Page.draw_quad` / :meth:`Shape.draw_quad`, :meth:`Page.draw_oval`/ :meth:`Shape.draw_quad`).\n\n.. note::\n\n   * If the corners of a rectangle are transformed with a **rotation**, **scale** or **translation** :ref:`Matrix`, then the resulting quad is **rectangular** (= congruent to a rectangle), i.e. all of its corners again enclose angles of 90 degrees. Property :attr:`Quad.is_rectangular` checks whether a quad can be thought of being the result of such an operation.\n\n   * This is not true for all matrices: e.g. shear matrices produce parallelograms, and non-invertible matrices deliver \"degenerate\" tetragons like triangles or lines.\n\n   * Attribute :attr:`Quad.rect` obtains the enveloping rectangle. Vice versa, rectangles now have attributes :attr:`Rect.quad`, resp. :attr:`IRect.quad` to obtain their respective tetragon versions.\n\n\n============================= =======================================================\n**Methods / Attributes**      **Short Description**\n============================= =======================================================\n:meth:`Quad.transform`        transform with a matrix\n:meth:`Quad.morph`            transform with a point and matrix\n:attr:`Quad.ul`               upper left point\n:attr:`Quad.ur`               upper right point\n:attr:`Quad.ll`               lower left point\n:attr:`Quad.lr`               lower right point\n:attr:`Quad.is_convex`        true if quad is a convex set\n:attr:`Quad.is_empty`         true if quad is an empty set\n:attr:`Quad.is_rectangular`   true if quad is congruent to a rectangle\n:attr:`Quad.rect`             smallest containing :ref:`Rect`\n:attr:`Quad.width`            the longest width value\n:attr:`Quad.height`           the longest height value\n============================= =======================================================\n\n**Class API**\n\n.. class:: Quad\n\n   .. method:: __init__(self)\n\n   .. method:: __init__(self, ul, ur, ll, lr)\n\n   .. method:: __init__(self, quad)\n\n   .. method:: __init__(self, sequence)\n\n      Overloaded constructors: \"ul\", \"ur\", \"ll\", \"lr\" stand for :data:`point_like` objects (the four corners), \"sequence\" is a Python sequence with four :data:`point_like` objects.\n\n      If \"quad\" is specified, the constructor creates a **new copy** of it.\n\n      Without parameters, a quad consisting of 4 copies of *Point(0, 0)* is created.\n\n\n   .. method:: transform(matrix)\n\n      Modify the quadrilateral by transforming each of its corners with a matrix.\n\n      :arg matrix_like matrix: the matrix.\n\n   .. method:: morph(fixpoint, matrix)\n\n      *(New in version 1.17.0)* \"Morph\" the quad with a matrix-like using a point-like as fixed point.\n\n      :arg point_like fixpoint: the point.\n      :arg matrix_like matrix: the matrix.\n      :returns: a new quad (no operation if this is the infinite quad).\n\n\n   .. attribute:: rect\n\n      The smallest rectangle containing the quad, represented by the blue area in the following picture.\n\n      .. image:: images/img-quads.*\n\n      :type: :ref:`Rect`\n\n   .. attribute:: ul\n\n      Upper left point.\n\n      :type: :ref:`Point`\n\n   .. attribute:: ur\n\n      Upper right point.\n\n      :type: :ref:`Point`\n\n   .. attribute:: ll\n\n      Lower left point.\n\n      :type: :ref:`Point`\n\n   .. attribute:: lr\n\n      Lower right point.\n\n      :type: :ref:`Point`\n\n   .. attribute:: is_convex\n\n      * New in version 1.16.1\n\n      Checks if for any two points of the quad, all points on their connecting line also belong to the quad.\n\n         .. image:: images/img-convexity.*\n            :scale: 30\n\n      :type: bool\n\n   .. attribute:: is_empty\n\n      True if enclosed area is zero, which means that at least three of the four corners are on the same line. If this is false, the quad may still be degenerate or not look like a tetragon at all (triangles, parallelograms, trapezoids, ...).\n\n      :type: bool\n\n   .. attribute:: is_rectangular\n\n      True if all corner angles are 90 degrees. This implies that the quad is **convex and not empty**.\n\n      :type: bool\n\n   .. attribute:: width\n\n      The maximum length of the top and the bottom side.\n\n      :type: float\n\n   .. attribute:: height\n\n      The maximum length of the left and the right side.\n\n      :type: float\n\nRemark\n------\nThis class adheres to the sequence protocol, so components can be dealt with via their indices, too. Also refer to :ref:`SequenceTypes`.\n\nAlgebra and Containment Checks\n-------------------------------\nStarting with v1.19.6, quads can be used in algebraic expressions like the other geometry object -- the respective restrictions have been lifted. In particular, all the following combinations of containment checking are now possible:\n\n`{Point | IRect | Rect | Quad} in {IRect | Rect | Quad}`\n\nPlease note the following interesting detail:\n\nFor a rectangle, only its top-left point belongs to it. Since v1.19.0, rectangles are defined to be \"open\", such that its bottom and its right edge do not belong to it -- including the respective corners. But for quads there exists no such notion like \"openness\", so we have the following somewhat surprising implication:\n\n   >>> rect.br in rect\n   False\n   >>> # but:\n   >>> rect.br in rect.quad\n   True\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/rag.rst",
    "content": "\n.. include:: header.rst\n\n\nPyMuPDF, LLM & RAG\n============================\n\n\nIntegrating |PyMuPDF| into your :title:`Large Language Model (LLM)` framework and overall :title:`RAG (Retrieval-Augmented Generation`) solution provides the fastest and most reliable way to deliver document data.\n\nThere are a few well known :title:`LLM` solutions which have their own interfaces with |PyMuPDF| - it is a fast growing area, so please let us know if you discover any more!\n\nIf you need to export to :title:`Markdown` or obtain a :title:`LlamaIndex` Document from a file:\n\n.. raw:: html\n\n   <button id=\"pymupdf4llmButton\" class=\"cta orange\" style=\"text-transform: none;\" onclick=\"window.location='pymupdf4llm/'\">Try PyMuPDF4LLM</button>\n   <p></p>\n\n   <script>\n      let lang = document.getElementsByTagName('html')[0].getAttribute('lang');\n\n      if (lang==\"ja\") {\n         document.getElementById(\"pymupdf4llmButton\").innerHTML = \"PyMuPDF4LLM を試してみる\";\n      }\n\n   </script>\n\n\nIntegration with :title:`LangChain`\n-------------------------------------\n\nIt is simple to integrate directly with :title:`LangChain` by using their dedicated loader as follows:\n\n\n.. code-block:: python\n\n    from langchain_community.document_loaders import PyMuPDFLoader\n    loader = PyMuPDFLoader(\"example.pdf\")\n    data = loader.load()\n\n\nSee `LangChain Using PyMuPDF <https://python.langchain.com/docs/modules/data_connection/document_loaders/pdf/#using-pymupdf>`_ for full details.\n\n\nIntegration with :title:`LlamaIndex`\n---------------------------------------\n\n\nUse the dedicated `PyMuPDFReader` from :title:`LlamaIndex` 🦙 to manage your document loading.\n\n.. code-block:: python\n\n    from llama_index.readers.file import PyMuPDFReader\n    loader = PyMuPDFReader()\n    documents = loader.load(file_path=\"example.pdf\")\n\nSee `Building RAG from Scratch <https://docs.llamaindex.ai/en/stable/examples/low_level/oss_ingestion_retrieval>`_ for more.\n\n\nPreparing Data for Chunking\n-----------------------------\n\nChunking (or splitting) data is essential to give context to your :title:`LLM` data and with :title:`Markdown` output now supported by |PyMuPDF| this means that `Level 3 chunking <https://medium.com/@anuragmishra_27746/five-levels-of-chunking-strategies-in-rag-notes-from-gregs-video-7b735895694d#b123>`_ is supported.\n\n\n\n.. _rag_outputting_as_md:\n\nOutputting as :title:`Markdown`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIn order to export your document in :title:`Markdown` format you will need a separate helper. Package :doc:`pymupdf4llm/index` is a high-level wrapper of |PyMuPDF| functions which for each page outputs standard and table text in an integrated Markdown-formatted string across all document pages:\n\n\n.. code-block:: python\n\n    # convert the document to markdown\n    import pymupdf4llm\n    md_text = pymupdf4llm.to_markdown(\"input.pdf\")\n\n    # Write the text to some file in UTF8-encoding\n    import pathlib\n    pathlib.Path(\"output.md\").write_bytes(md_text.encode())\n\n\nFor further information please refer to: :doc:`pymupdf4llm/index`.\n\n\nHow to use :title:`Markdown` output\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOnce you have your data in :title:`Markdown` format you are ready to chunk/split it and supply it to your :title:`LLM`, for example, if this is :title:`LangChain` then do the following:\n\n.. code-block:: python\n\n    import pymupdf4llm\n    from langchain.text_splitter import MarkdownTextSplitter\n\n    # Get the MD text\n    md_text = pymupdf4llm.to_markdown(\"input.pdf\")  # get markdown for all pages\n\n    splitter = MarkdownTextSplitter(chunk_size=40, chunk_overlap=0)\n\n    splitter.create_documents([md_text])\n\n\n\nFor more see `5 Levels of Text Splitting <https://github.com/FullStackRetrieval-com/RetrievalTutorials/blob/main/tutorials/LevelsOfTextSplitting/5_Levels_Of_Text_Splitting.ipynb>`_\n\n\nRelated Blogs\n--------------------\n\nTo find out more about |PyMuPDF|, :title:`LLM` & :title:`RAG` check out our blogs for implementations & tutorials.\n\n\nMethodologies to Extract Text\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n- `Enhanced Text Extraction <https://artifex.com/blog/rag-llm-and-pdf-enhanced-text-extraction>`_\n- `Conversion to Markdown Text with PyMuPDF <https://artifex.com/blog/rag-llm-and-pdf-conversion-to-markdown-text-with-pymupdf>`_\n\n\n\nCreate a Chatbot to discuss your documents\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n- `Make a simple command line Chatbot <https://artifex.com/blog/creating-a-rag-chatbot-with-chatgpt-and-pymupdf>`_\n- `Make a Chatbot GUI <https://artifex.com/blog/building-a-rag-chatbot-gui-with-the-chatgpt-api-and-pymupdf>`_\n\n\n\n\n\n\n\n\n.. include:: footer.rst"
  },
  {
    "path": "docs/recipes-annotations.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesAnnotations:\n\n==============================\nAnnotations\n==============================\n\n.. _RecipesAnnotations_A:\n\nHow to Add and Modify Annotations\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIn |PyMuPDF|, new annotations can be added via :ref:`Page` methods. Once an annotation exists, it can be modified to a large extent using methods of the :ref:`Annot` class.\n\nAnnotations can **only** be inserted in |PDF| pages - other document types do not support annotation insertion.\n\nIn contrast to many other tools, initial insert of annotations happens with a minimum number of properties. We leave it to the programmer to e.g. set attributes like author, creation date or subject.\n\nAs an overview for these capabilities, look at the following script that fills a PDF page with most of the available annotations. Look in the next sections for more special situations:\n\n.. literalinclude:: samples/new-annots.py\n   :language: python\n\n\nThis script should lead to the following output:\n\n.. image:: images/img-annots.*\n   :scale: 80\n\n------------------------------\n\n.. _RecipesAnnotations_B:\n\nHow to Use FreeText\n~~~~~~~~~~~~~~~~~~~~~\nThis script shows a couple of basic ways to deal with 'FreeText' annotations:\n\n.. literalinclude:: samples/annotations-freetext1.py\n\nThe result looks like this:\n\n.. image:: images/img-freetext1.*\n   :scale: 80\n\nHere is an example for using rich text and call-out lines:\n\n.. literalinclude:: samples/annotations-freetext2.py\n\nThe result looks like this:\n\n.. image:: images/img-freetext2.*\n   :scale: 80\n\n\n------------------------------\n\n\n\n.. _RecipesAnnotations_C:\n\nHow to Use Ink Annotations\n~~~~~~~~~~~~~~~~~~~~~~~~~~~\nInk annotations are used to contain freehand scribbling. A typical example may be an image of your signature consisting of first name and last name. Technically an ink annotation is implemented as a **list of lists of points**. Each point list is regarded as a continuous line connecting the points. Different point lists represent independent line segments of the annotation.\n\nThe following script creates an ink annotation with two mathematical curves (sine and cosine function graphs) as line segments:\n\n.. literalinclude:: samples/annotations-ink.py\n\nThis is the result:\n\n.. image:: images/img-inkannot.*\n    :scale: 50\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-common-issues-and-their-solutions.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesCommonIssuesAndTheirSolutions:\n\n==========================================\nCommon Issues and their Solutions\n==========================================\n\nHow To Dynamically Clean Up Corrupt :title:`PDFs`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis shows a potential use of |PyMuPDF| with another Python PDF library (the excellent pure Python package `pdfrw <https://pypi.python.org/pypi/pdfrw>`_ is used here as an example).\n\nIf a clean, non-corrupt / decompressed PDF is needed, one could dynamically invoke PyMuPDF to recover from many problems like so::\n\n import sys\n from io import BytesIO\n from pdfrw import PdfReader\n import pymupdf\n\n #---------------------------------------\n # 'Tolerant' PDF reader\n #---------------------------------------\n def reader(fname, password = None):\n     idata = open(fname, \"rb\").read()  # read the PDF into memory and\n     ibuffer = BytesIO(idata)  # convert to stream\n     if password is None:\n         try:\n             return PdfReader(ibuffer)  # if this works: fine!\n         except:\n             pass\n\n     # either we need a password or it is a problem-PDF\n     # create a repaired / decompressed / decrypted version\n     doc = pymupdf.open(\"pdf\", ibuffer)\n     if password is not None:  # decrypt if password provided\n         rc = doc.authenticate(password)\n         if not rc > 0:\n             raise ValueError(\"wrong password\")\n     c = doc.tobytes(garbage=3, deflate=True)\n     del doc  # close & delete doc\n     return PdfReader(BytesIO(c))  # let pdfrw retry\n #---------------------------------------\n # Main program\n #---------------------------------------\n pdf = reader(\"pymupdf.pdf\", password = None) # include a password if necessary\n print pdf.Info\n # do further processing\n\nWith the command line utility *pdftk* (`available <https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/>`_ for Windows only, but reported to also run under `Wine <https://www.winehq.org/>`_) a similar result can be achieved, see `here <http://www.overthere.co.uk/2013/07/22/improving-pypdf2-with-pdftk/>`_. However, you must invoke it as a separate process via *subprocess.Popen*, using stdin and stdout as communication vehicles.\n\n\n\nHow to Convert Any Document to |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nHere is a script that converts any |PyMuPDF| :ref:`supported document<Supported_File_Types>` to a |PDF|. These include XPS, EPUB, FB2, CBZ and image formats, including multi-page TIFF images.\n\nIt features maintaining any metadata, table of contents and links contained in the source document::\n\n    \"\"\"\n    Demo script: Convert input file to a PDF\n    -----------------------------------------\n    Intended for multi-page input files like XPS, EPUB etc.\n\n    Features:\n    ---------\n    Recovery of table of contents and links of input file.\n    While this works well for bookmarks (outlines, table of contents),\n    links will only work if they are not of type \"LINK_NAMED\".\n    This link type is skipped by the script.\n\n    For XPS and EPUB input, internal links however **are** of type \"LINK_NAMED\".\n    Base library MuPDF does not resolve them to page numbers.\n\n    So, for anyone expert enough to know the internal structure of these\n    document types, can further interpret and resolve these link types.\n\n    Dependencies\n    --------------\n    PyMuPDF v1.14.0+\n    \"\"\"\n    import sys\n    import pymupdf\n    if not (list(map(int, pymupdf.VersionBind.split(\".\"))) >= [1,14,0]):\n        raise SystemExit(\"need PyMuPDF v1.14.0+\")\n    fn = sys.argv[1]\n\n    print(f\"Converting '{fn}' to '{fn}.pdf'\")\n\n    doc = pymupdf.open(fn)\n\n    b = doc.convert_to_pdf()  # convert to pdf\n    pdf = pymupdf.open(\"pdf\", b)  # open as pdf\n\n    toc= doc.get_toc()  # table of contents of input\n    pdf.set_toc(toc)  # simply set it for output\n    meta = doc.metadata  # read and set metadata\n    if not meta[\"producer\"]:\n        meta[\"producer\"] = \"PyMuPDF v\" + pymupdf.VersionBind\n\n    if not meta[\"creator\"]:\n        meta[\"creator\"] = \"PyMuPDF PDF converter\"\n    meta[\"modDate\"] = pymupdf.get_pdf_now()\n    meta[\"creationDate\"] = meta[\"modDate\"]\n    pdf.set_metadata(meta)\n\n    # now process the links\n    link_cnti = 0\n    link_skip = 0\n    for pinput in doc:  # iterate through input pages\n        links = pinput.get_links()  # get list of links\n        link_cnti += len(links)  # count how many\n        pout = pdf[pinput.number]  # read corresp. output page\n        for l in links:  # iterate though the links\n            if l[\"kind\"] == pymupdf.LINK_NAMED:  # we do not handle named links\n                print(\"named link page\", pinput.number, l)\n                link_skip += 1  # count them\n                continue\n            pout.insert_link(l)  # simply output the others\n\n    # save the conversion result\n    pdf.save(fn + \".pdf\", garbage=4, deflate=True)\n    # say how many named links we skipped\n    if link_cnti > 0:\n        print(f\"Skipped {link_skip} named links of a total of {link_cnti} in input.\")\n\n\n\nChanging Annotations: Unexpected Behaviour\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nProblem\n^^^^^^^^^\nThere are two scenarios:\n\n1. **Updating** an annotation with PyMuPDF which was created by some other software.\n2. **Creating** an annotation with PyMuPDF and later changing it with some other software.\n\nIn both cases you may experience unintended changes, like a different annotation icon or text font, the fill color or line dashing have disappeared, line end symbols have changed their size or even have disappeared too, etc.\n\nCause\n^^^^^^\nAnnotation maintenance is handled differently by each PDF maintenance application. Some annotation types may not be supported, or not be supported fully or some details may be handled in a different way than in another application. **There is no standard.**\n\nAlmost always a PDF application also comes with its own icons (file attachments, sticky notes and stamps) and its own set of supported text fonts. For example:\n\n* (Py-) MuPDF only supports these 5 basic fonts for 'FreeText' annotations: Helvetica, Times-Roman, Courier, ZapfDingbats and Symbol -- no italics / no bold variations. When changing a 'FreeText' annotation created by some other app, its font will probably not be recognized nor accepted and be replaced by Helvetica.\n\n* PyMuPDF supports all PDF text markers (highlight, underline, strikeout, squiggly), but these types cannot be updated with Adobe Acrobat Reader.\n\nIn most cases there also exists limited support for line dashing which causes existing dashes to be replaced by straight lines. For example:\n\n* PyMuPDF fully supports all line dashing forms, while other viewers only accept a limited subset.\n\n\nSolutions\n^^^^^^^^^^\nUnfortunately there is not much you can do in most of these cases.\n\n1. Stay with the same software for **creating and changing** an annotation.\n2. When using PyMuPDF to change an \"alien\" annotation, try to **avoid** :meth:`Annot.update`. The following methods **can be used without it,** so that the original appearance should be maintained:\n\n  * :meth:`Annot.set_rect` (location changes)\n  * :meth:`Annot.set_flags` (annotation behaviour)\n  * :meth:`Annot.set_info` (meta information, except changes to *content*)\n  * :meth:`Annot.set_popup` (create popup or change its rect)\n  * :meth:`Annot.set_oc` (add / remove reference to optional content information)\n  * :meth:`Annot.set_open`\n  * :meth:`Annot.update_file` (file attachment changes)\n\n\nMissing or Unreadable Extracted Text\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nFairly often, text extraction does not work text as you would expect: text may be missing, or may not appear in the reading sequence visible on your screen, or contain garbled characters (like a ? or a \"TOFU\" symbol), etc. This can be caused by a number of different problems.\n\nProblem: no text is extracted\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nYour PDF viewer does display text, but you cannot select it with your cursor, and text extraction delivers nothing.\n\nCause\n^^^^^^\n1. You may be looking at an image embedded in the PDF page (e.g. a scanned PDF).\n2. The PDF creator used no font, but **simulated** text by painting it, using little lines and curves. E.g. a capital \"D\" could be painted by a line \"|\" and a left-open semi-circle, an \"o\" by an ellipse, and so on.\n\nSolution\n^^^^^^^^^^\nUse an OCR software like `OCRmyPDF <https://pypi.org/project/ocrmypdf/>`_ to insert a hidden text layer underneath the visible page. The resulting PDF should behave as expected.\n\nProblem: unreadable text\n^^^^^^^^^^^^^^^^^^^^^^^^\nText extraction does not deliver the text in readable order, duplicates some text, or is otherwise garbled.\n\nCause\n^^^^^^\n1. The single characters are readable as such (no \"<?>\" symbols), but the sequence in which the text is **coded in the file** deviates from the reading order. The motivation behind may be technical or protection of data against unwanted copies.\n2. Many \"<?>\" symbols occur, indicating MuPDF could not interpret these characters. The font may indeed be unsupported by MuPDF, or the PDF creator may haved used a font that displays readable text, but on purpose obfuscates the originating corresponding unicode character.\n\nSolution\n^^^^^^^^\n1. Use layout preserving text extraction: `python -m fitz gettext file.pdf`.\n2. If other text extraction tools also don't work, then the only solution again is OCRing the page.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-drawing-and-graphics.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesDrawingAndGraphics:\n\n==============================\nDrawing and Graphics\n==============================\n\n.. note::\n\n    When the terms \"Drawings\" or \"Graphics\" are mentioned here we are referring to \"Vector Graphics\" or \"Line Art\".\n\n    Therefore please consider these terms as being synonymous!\n\n\nPDF files support elementary drawing operations as part of their syntax. These are **vector graphics** and include basic geometrical objects like lines, curves, circles, rectangles including specifying colors.\n\nThe syntax for such operations is defined in \"A Operator Summary\" on page 643 of the :ref:`AdobeManual`. Specifying these operators for a PDF page happens in its :data:`contents` objects.\n\n|PyMuPDF| implements a large part of the available features via its :ref:`Shape` class, which is comparable to notions like \"canvas\" in other packages (e.g. `reportlab <https://pypi.org/project/reportlab/>`_).\n\nA shape is always created as a **child of a page**, usually with an instruction like `shape = page.new_shape()`. The class defines numerous methods that perform drawing operations on the page's area. For example, `last_point = shape.draw_rect(rect)` draws a rectangle along the borders of a suitably defined `rect = pymupdf.Rect(...)`.\n\nThe returned *last_point* **always** is the :ref:`Point` where drawing operation ended (\"last point\"). Every such elementary drawing requires a subsequent :meth:`Shape.finish` to \"close\" it, but there may be multiple drawings which have one common ``finish()`` method.\n\nIn fact, :meth:`Shape.finish` *defines* a group of preceding draw operations to form one -- potentially rather complex -- graphics object. |PyMuPDF| provides several predefined graphics in `shapes_and_symbols.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/shapes/shapes_and_symbols.py>`_ which demonstrate how this works.\n\nIf you import this script, you can also directly use its graphics as in the following example::\n\n    # -*- coding: utf-8 -*-\n    \"\"\"\n    Created on Sun Dec  9 08:34:06 2018\n\n    @author: Jorj\n    @license: GNU AFFERO GPL V3\n\n    Create a list of available symbols defined in shapes_and_symbols.py\n\n    This also demonstrates an example usage: how these symbols could be used\n    as bullet-point symbols in some text.\n\n    \"\"\"\n\n    import pymupdf\n    import shapes_and_symbols as sas\n\n    # list of available symbol functions and their descriptions\n    tlist = [\n             (sas.arrow, \"arrow (easy)\"),\n             (sas.caro, \"caro (easy)\"),\n             (sas.clover, \"clover (easy)\"),\n             (sas.diamond, \"diamond (easy)\"),\n             (sas.dontenter, \"do not enter (medium)\"),\n             (sas.frowney, \"frowney (medium)\"),\n             (sas.hand, \"hand (complex)\"),\n             (sas.heart, \"heart (easy)\"),\n             (sas.pencil, \"pencil (very complex)\"),\n             (sas.smiley, \"smiley (easy)\"),\n             ]\n\n    r = pymupdf.Rect(50, 50, 100, 100)  # first rect to contain a symbol\n    d = pymupdf.Rect(0, r.height + 10, 0, r.height + 10)  # displacement to next rect\n    p = (15, -r.height * 0.2)  # starting point of explanation text\n    rlist = [r]  # rectangle list\n\n    for i in range(1, len(tlist)):  # fill in all the rectangles\n        rlist.append(rlist[i-1] + d)\n\n    doc = pymupdf.open()  # create empty PDF\n    page = doc.new_page()  # create an empty page\n    shape = page.new_shape()  # start a Shape (canvas)\n\n    for i, r in enumerate(rlist):\n        tlist[i][0](shape, rlist[i])  # execute symbol creation\n        shape.insert_text(rlist[i].br + p,  # insert description text\n                       tlist[i][1], fontsize=r.height/1.2)\n\n    # store everything to the page's /Contents object\n    shape.commit()\n\n    import os\n    scriptdir = os.path.dirname(__file__)\n    doc.save(os.path.join(scriptdir, \"symbol-list.pdf\"))  # save the PDF\n\n\nThis is the script's outcome:\n\n.. image:: images/img-symbols.*\n   :scale: 50\n\n------------------------------\n\n\n.. _RecipesDrawingAndGraphics_Extract_Drawings:\n\nHow to Extract Drawings\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n* New in v1.18.0\n\nDrawing commands (**vector graphics**) issued by a page can be extracted as a list of dictionaries. Interestingly, this is possible for :ref:`all supported document types<Supported_File_Types>` -- not just PDF: so you can use it for XPS, EPUB and others as well.\n\nPage method, :meth:`Page.get_drawings()` accesses draw commands and converts them into a list of Python dictionaries. Each dictionary -- called a \"path\" -- represents a separate drawing -- it may be simple like a single line, or a complex combination of lines and curves representing one of the shapes of the previous section.\n\nThe *path* dictionary has been designed such that it can easily be used by the :ref:`Shape` class and its methods. Here is an example for a page with one path, that draws a red-bordered yellow circle inside rectangle `Rect(100, 100, 200, 200)`::\n\n    >>> pprint(page.get_drawings())\n    [{'closePath': True,\n    'color': [1.0, 0.0, 0.0],\n    'dashes': '[] 0',\n    'even_odd': False,\n    'fill': [1.0, 1.0, 0.0],\n    'items': [('c',\n                Point(100.0, 150.0),\n                Point(100.0, 177.614013671875),\n                Point(122.38600158691406, 200.0),\n                Point(150.0, 200.0)),\n                ('c',\n                Point(150.0, 200.0),\n                Point(177.61399841308594, 200.0),\n                Point(200.0, 177.614013671875),\n                Point(200.0, 150.0)),\n                ('c',\n                Point(200.0, 150.0),\n                Point(200.0, 122.385986328125),\n                Point(177.61399841308594, 100.0),\n                Point(150.0, 100.0)),\n                ('c',\n                Point(150.0, 100.0),\n                Point(122.38600158691406, 100.0),\n                Point(100.0, 122.385986328125),\n                Point(100.0, 150.0))],\n    'lineCap': (0, 0, 0),\n    'lineJoin': 0,\n    'opacity': 1.0,\n    'rect': Rect(100.0, 100.0, 200.0, 200.0),\n    'width': 1.0}]\n    >>>\n\n.. note:: You need (at least) 4 Bézier curves (of 3rd order) to draw a circle with acceptable precision. See this `Wikipedia article <https://en.wikipedia.org/wiki/B%C3%A9zier_curve>`_ for some background.\n\n\nThe following is a code snippet which extracts the drawings of a page and re-draws them on a new page::\n\n    import pymupdf\n    doc = pymupdf.open(\"some.file\")\n    page = doc[0]\n    paths = page.get_drawings()  # extract existing drawings\n    # this is a list of \"paths\", which can directly be drawn again using Shape\n    # -------------------------------------------------------------------------\n    #\n    # define some output page with the same dimensions\n    outpdf = pymupdf.open()\n    outpage = outpdf.new_page(width=page.rect.width, height=page.rect.height)\n    shape = outpage.new_shape()  # make a drawing canvas for the output page\n    # --------------------------------------\n    # loop through the paths and draw them\n    # --------------------------------------\n    for path in paths:\n        # ------------------------------------\n        # draw each entry of the 'items' list\n        # ------------------------------------\n        for item in path[\"items\"]:  # these are the draw commands\n            if item[0] == \"l\":  # line\n                shape.draw_line(item[1], item[2])\n            elif item[0] == \"re\":  # rectangle\n                shape.draw_rect(item[1])\n            elif item[0] == \"qu\":  # quad\n                shape.draw_quad(item[1])\n            elif item[0] == \"c\":  # curve\n                shape.draw_bezier(item[1], item[2], item[3], item[4])\n            else:\n                raise ValueError(\"unhandled drawing\", item)\n        # ------------------------------------------------------\n        # all items are drawn, now apply the common properties\n        # to finish the path\n        # ------------------------------------------------------\n        shape.finish(\n            fill=path[\"fill\"],  # fill color\n            color=path[\"color\"],  # line color\n            dashes=path[\"dashes\"],  # line dashing\n            even_odd=path.get(\"even_odd\", True),  # control color of overlaps\n            closePath=path[\"closePath\"],  # whether to connect last and first point\n            lineJoin=path[\"lineJoin\"],  # how line joins should look like\n            lineCap=max(path[\"lineCap\"]),  # how line ends should look like\n            width=path[\"width\"],  # line width\n            stroke_opacity=path.get(\"stroke_opacity\", 1),  # same value for both\n            fill_opacity=path.get(\"fill_opacity\", 1),  # opacity parameters\n            )\n    # all paths processed - commit the shape to its page\n    shape.commit()\n    outpdf.save(\"drawings-page-0.pdf\")\n\nAs can be seen, there is a high congruence level with the :ref:`Shape` class. With one exception: For technical reasons `lineCap` is a tuple of 3 numbers here, whereas it is an integer in :ref:`Shape` (and in PDF). So we simply take the maximum value of that tuple.\n\nHere is a comparison between input and output of an example page, created by the previous script:\n\n.. image:: images/img-getdrawings.png\n   :scale: 50\n\n.. note:: The reconstruction of graphics, like shown here, is not perfect. The following aspects will not be reproduced as of this version:\n\n   * Page definitions can be complex and include instructions for not showing / hiding certain areas to keep them invisible. Things like this are ignored by :meth:`Page.get_drawings` - it will always return all paths.\n\n.. note:: You can use the path list to make your own lists of e.g. all lines or all rectangles on the page and subselect them by criteria, like color or position on the page etc.\n\n.. _RecipesDrawingAndGraphics_Delete_Drawings:\n\nHow to Delete Drawings\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo delete drawings/vector graphics we must use a :ref:`Redaction Annotation <The_Basics_Redacting>` with the bounding box of the drawing and then **add and apply** a redaction to it to delete it.\n\n\nThe following code shows an example of deleting the first drawing found on the page::\n\n    paths = page.get_drawings()\n    rect = paths[0][\"rect\"]  # rectangle of the 1st drawing\n    page.add_redact_annot(rect)\n    page.apply_redactions(0,2,1)  # potentially set options for any of images, drawings, text\n\n\n.. note::\n\n    See :meth:`Page.apply_redactions` for the parameter options which can be sent - you are able to apply deletion options to image, drawing and text objects which are bound by the annotation area.\n\n\nHow to Draw Graphics\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nDrawing graphics is as simple as calling the type of :meth:`Drawing Method <Page.draw_line>` you may want. You can draw graphics directly on pages or within shape objects.\n\n\nFor example, to draw a circle::\n\n    # Draw a circle on the page using the Page method\n    page.draw_circle((center_x, center_y), radius, color=(1, 0, 0), width=2)\n\n    # Draw a circle on the page using a Shape object\n    shape = page.new_shape()\n    shape.draw_circle((center_x, center_y), radius)\n    shape.finish(color=(1, 0, 0), width=2)\n    shape.commit(overlay=True)\n\nThe :ref:`Shape` object can be used to combine multiple drawings that should receive common properties as specified by :meth:`Shape.finish`.\n\n\n\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-images.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesImages:\n\n==============================\nImages\n==============================\n\n\n\n.. _RecipesImages_A:\n\nHow to Make Images from Document Pages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis little script will take a document filename and generate a PNG file from each of its pages.\n\nThe document can be any :ref:`supported type<Supported_File_Types>`.\n\nThe script works as a command line tool which expects the filename being supplied as a parameter. The generated image files (1 per page) are stored in the directory of the script::\n\n    import sys, pymupdf  # import the bindings\n    fname = sys.argv[1]  # get filename from command line\n    doc = pymupdf.open(fname)  # open document\n    for page in doc:  # iterate through the pages\n        pix = page.get_pixmap()  # render page to an image\n        pix.save(f\"page-{page.number}.png\")  # store image as a PNG\n\nThe script directory will now contain PNG image files named *page-0.png*, *page-1.png*, etc. Pictures have the dimension of their pages with width and height rounded to integers, e.g. 595 x 842 pixels for an A4 portrait sized page. They will have a resolution of 96 dpi in x and y dimension and have no transparency. You can change all that -- for how to do this, read the next sections.\n\n----------\n\n\n.. _RecipesImages_B:\n\nHow to Increase :index:`Image Resolution <pair: image; resolution>`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe image of a document page is represented by a :ref:`Pixmap`, and the simplest way to create a pixmap is via method :meth:`Page.get_pixmap`.\n\nThis method has many options to influence the result. The most important among them is the :ref:`Matrix`, which lets you :index:`zoom`, rotate, distort or mirror the outcome.\n\n:meth:`Page.get_pixmap` by default will use the :ref:`Identity` matrix, which does nothing.\n\nIn the following, we apply a :index:`zoom factor <pair: resolution;zoom>` of 2 to each dimension, which will generate an image with a four times better resolution for us (and also about 4 times the size)::\n\n    zoom_x = 2.0  # horizontal zoom\n    zoom_y = 2.0  # vertical zoom\n    mat = pymupdf.Matrix(zoom_x, zoom_y)  # zoom factor 2 in each dimension\n    pix = page.get_pixmap(matrix=mat)  # use 'mat' instead of the identity matrix\n\n\nSince version 1.19.2 there is a more direct way to set the resolution: Parameter `\"dpi\"` (dots per inch) can be used in place of `\"matrix\"`. To create a 300 dpi image of a page specify `pix = page.get_pixmap(dpi=300)`. Apart from notation brevity, this approach has the additional advantage that the **dpi value is saved with the image** file -- which does not happen automatically when using the Matrix notation.\n\n----------\n\n\n.. _RecipesImages_C:\n\nHow to Create :index:`Partial Pixmaps` (Clips)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nYou do not always need or want the full image of a page. This is the case e.g. when you display the image in a GUI and would like to fill the respective window with a zoomed part of the page.\n\nLet's assume your GUI window has room to display a full document page, but you now want to fill this room with the bottom right quarter of your page, thus using a four times better resolution.\n\nTo achieve this, define a rectangle equal to the area you want to appear in the GUI and call it \"clip\". One way of constructing rectangles in PyMuPDF is by providing two diagonally opposite corners, which is what we are doing here.\n\n.. image:: images/img-clip.*\n   :width: 50%\n\n::\n\n    mat = pymupdf.Matrix(2, 2)  # zoom factor 2 in each direction\n    rect = page.rect  # the page rectangle\n    mp = (rect.tl + rect.br) / 2  # its middle point, becomes top-left of clip\n    clip = pymupdf.Rect(mp, rect.br)  # the area we want\n    pix = page.get_pixmap(matrix=mat, clip=clip)\n\nIn the above we construct *clip* by specifying two diagonally opposite points: the middle point *mp* of the page rectangle, and its bottom right, *rect.br*.\n\n----------\n\n\n.. _RecipesImages_D:\n\nHow to Zoom a Clip to a GUI Window\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nPlease also read the previous section. This time we want to **compute the zoom factor** for a clip, such that its image best fits a given GUI window. This means, that the image's width or height (or both) will equal the window dimension. For the following code snippet you need to provide the WIDTH and HEIGHT of your GUI's window that should receive the page's clip rectangle.\n\n::\n\n    # WIDTH: width of the GUI window\n    # HEIGHT: height of the GUI window\n    # clip: a subrectangle of the document page\n    # compare width/height ratios of image and window\n\n    if clip.width / clip.height < WIDTH / HEIGHT:\n        # clip is narrower: zoom to window HEIGHT\n        zoom = HEIGHT / clip.height\n    else:  # clip is broader: zoom to window WIDTH\n        zoom = WIDTH / clip.width\n    mat = pymupdf.Matrix(zoom, zoom)\n    pix = page.get_pixmap(matrix=mat, clip=clip)\n\nFor the other way round, now assume you **have** the zoom factor and need to **compute the fitting clip**.\n\nIn this case we have `zoom = HEIGHT/clip.height = WIDTH/clip.width`, so we must set `clip.height = HEIGHT/zoom` and, `clip.width = WIDTH/zoom`. Choose the top-left point `tl` of the clip on the page to compute the right pixmap::\n\n    width = WIDTH / zoom\n    height = HEIGHT / zoom\n    clip = pymupdf.Rect(tl, tl.x + width, tl.y + height)\n    # ensure we still are inside the page\n    clip &= page.rect\n    mat = pymupdf.Matrix(zoom, zoom)\n    pix = pymupdf.Pixmap(matrix=mat, clip=clip)\n\n\n----------\n\n\n.. _RecipesImages_E:\n\nHow to Create or Suppress Annotation Images\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nNormally, the pixmap of a page also shows the page's annotations. Occasionally, this may not be desirable.\n\nTo suppress the annotation images on a rendered page, just specify `annots=False` in :meth:`Page.get_pixmap`.\n\nYou can also render annotations separately: they have their own :meth:`Annot.get_pixmap` method. The resulting pixmap has the same dimensions as the annotation rectangle.\n\n----------\n\n.. index::\n   triple: extract;image;non-PDF\n   pair: convert_to_pdf;examples\n\n\n.. _RecipesImages_F:\n\nHow to Extract Images: Non-PDF Documents\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIn contrast to the previous sections, this section deals with **extracting** images **contained** in documents, so they can be displayed as part of one or more pages.\n\nIf you want to recreate the original image in file form or as a memory area, you have basically two options:\n\n1. Convert your document to a PDF, and then use one of the PDF-only extraction methods. This snippet will convert a document to PDF::\n\n    >>> pdfbytes = doc.convert_to_pdf()  # this a bytes object\n    >>> pdf = pymupdf.open(\"pdf\", pdfbytes)  # open it as a PDF document\n    >>> # now use 'pdf' like any PDF document\n\n2. Use :meth:`Page.get_text` with the \"dict\" parameter. This works for all document types. It will extract all text and images shown on the page, formatted as a Python dictionary. Every image will occur in an image block, containing meta information and **the binary image data**. For details of the dictionary's structure, see :ref:`TextPage`. The method works equally well for PDF files. This creates a list of all images shown on a page::\n\n    >>> d = page.get_text(\"dict\")\n    >>> blocks = d[\"blocks\"]  # the list of block dictionaries\n    >>> imgblocks = [b for b in blocks if b[\"type\"] == 1]\n    >>> pprint(imgblocks[0])\n    {'bbox': (100.0, 135.8769989013672, 300.0, 364.1230163574219),\n     'bpc': 8,\n     'colorspace': 3,\n     'ext': 'jpeg',\n     'height': 501,\n     'image': b'\\xff\\xd8\\xff\\xe0\\x00\\x10JFIF\\...',  # CAUTION: LARGE!\n     'size': 80518,\n     'transform': (200.0, 0.0, -0.0, 228.2460174560547, 100.0, 135.8769989013672),\n     'type': 1,\n     'width': 439,\n     'xres': 96,\n     'yres': 96}\n\n----------\n\n.. index::\n   triple: extract;image;PDF\n   pair: extract_image;examples\n\n\n.. _RecipesImages_G:\n\nHow to Extract Images: PDF Documents\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nLike any other \"object\" in a PDF, images are identified by a cross reference number (:data:`xref`, an integer). If you know this number, you have two ways to access the image's data:\n\n1. **Create** a :ref:`Pixmap` of the image with instruction *pix = pymupdf.Pixmap(doc, xref)*. This method is **very** fast (single digit micro-seconds). The pixmap's properties (width, height, ...) will reflect the ones of the image. In this case there is no way to tell which image format the embedded original has.\n\n2. **Extract** the image with *img = doc.extract_image(xref)*. This is a dictionary containing the binary image data as *img[\"image\"]*. A number of meta data are also provided -- mostly the same as you would find in the pixmap of the image. The major difference is string *img[\"ext\"]*, which specifies the image format: apart from \"png\", strings like \"jpeg\", \"bmp\", \"tiff\", etc. can also occur. Use this string as the file extension if you want to store to disk. The execution speed of this method should be compared to the combined speed of the statements *pix = pymupdf.Pixmap(doc, xref);pix.tobytes()*. If the embedded image is in PNG format, the speed of :meth:`Document.extract_image` is about the same (and the binary image data are identical). Otherwise, this method is **thousands of times faster**, and the **image data is much smaller**.\n\nThe question remains: **\"How do I know those 'xref' numbers of images?\"**. There are two answers to this:\n\na. **\"Inspect the page objects:\"** Loop through the items of :meth:`Page.get_images`. It is a list of list, and its items look like *[xref, smask, ...]*, containing the :data:`xref` of an image. This :data:`xref` can then be used with one of the above methods. Use this method for **valid (undamaged)** documents. Be wary however, that the same image may be referenced multiple times (by different pages), so you might want to provide a mechanism avoiding multiple extracts.\nb. **\"No need to know:\"** Loop through the list of **all xrefs** of the document and perform a :meth:`Document.extract_image` for each one. If the returned dictionary is empty, then continue -- this :data:`xref` is no image. Use this method if the PDF is **damaged (unusable pages)**. Note that a PDF often contains \"pseudo-images\" (\"stencil masks\") with the special purpose of defining the transparency of some other image. You may want to provide logic to exclude those from extraction. Also have a look at the next section.\n\nFor both extraction approaches, there exist ready-to-use general purpose scripts:\n\n`extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_ extracts images page by page:\n\n.. image:: images/img-extract-imga.*\n   :scale: 80\n\nand `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_ extracts images by xref table:\n\n.. image:: images/img-extract-imgb.*\n   :scale: 80\n\n----------\n\n\n.. _RecipesImages_H:\n\nHow to Handle Image Masks\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSome images in PDFs are accompanied by **image masks**. In their simplest form, masks represent alpha (transparency) bytes stored as separate images. In order to reconstruct the original of an image, which has a mask, it must be \"enriched\" with transparency bytes taken from its mask.\n\nWhether an image does have such a mask can be recognized in one of two ways in PyMuPDF:\n\n1. An item of :meth:`Document.get_page_images` has the general format `(xref, smask, ...)`, where :data:`xref` is the image's :data:`xref` and *smask*, if positive, then it is the :data:`xref` of a mask.\n2. The (dictionary) results of :meth:`Document.extract_image` have a key *\"smask\"*, which also contains any mask's :data:`xref` if positive.\n\nIf *smask == 0* then the image encountered via :data:`xref` can be processed as it is.\n\nTo recover the original image using PyMuPDF, the procedure depicted as follows must be executed:\n\n.. image:: images/img-stencil.*\n   :scale: 60\n\n>>> pix1 = pymupdf.Pixmap(doc.extract_image(xref)[\"image\"])    # (1) pixmap of image w/o alpha\n>>> mask = pymupdf.Pixmap(doc.extract_image(smask)[\"image\"])   # (2) mask pixmap\n>>> pix = pymupdf.Pixmap(pix1, mask)                           # (3) copy of pix1, image mask added\n\nStep (1) creates a pixmap of the basic image. Step (2) does the same with the image mask. Step (3) adds an alpha channel and fills it with transparency information.\n\nThe scripts `extract-from-pages.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-pages.py>`_, and `extract-from-xref.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/extract-images/extract-from-xref.py>`_ above also contain this logic.\n\n----------\n\n.. index::\n   triple: picture;embed;PDF\n   pair: show_pdf_page;examples\n   pair: insert_image;examples\n   pair: embfile_add;examples\n   pair: add_file_annot;examples\n\n\n.. _RecipesImages_I:\n\n\nHow to Make one PDF of all your Pictures (or Files)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nWe show here **three scripts** that take a list of (image and other) files and put them all in one PDF.\n\n**Method 1: Inserting Images as Pages**\n\nThe first one converts each image to a PDF page with the same dimensions. The result will be a PDF with one page per image. It will only work for :ref:`supported image<Supported_File_Types>` file formats::\n\n import os, pymupdf\n import PySimpleGUI as psg  # for showing a progress bar\n doc = pymupdf.open()  # PDF with the pictures\n imgdir = \"D:/2012_10_05\"  # where the pics are\n imglist = os.listdir(imgdir)  # list of them\n imgcount = len(imglist)  # pic count\n\n for i, f in enumerate(imglist):\n     img = pymupdf.open(os.path.join(imgdir, f))  # open pic as document\n     rect = img[0].rect  # pic dimension\n     pdfbytes = img.convert_to_pdf()  # make a PDF stream\n     img.close()  # no longer needed\n     imgPDF = pymupdf.open(\"pdf\", pdfbytes)  # open stream as PDF\n     page = doc.new_page(width = rect.width,  # new page with ...\n                        height = rect.height)  # pic dimension\n     page.show_pdf_page(rect, imgPDF, 0)  # image fills the page\n     psg.EasyProgressMeter(\"Import Images\",  # show our progress\n         i+1, imgcount)\n\n doc.save(\"all-my-pics.pdf\")\n\nThis will generate a PDF only marginally larger than the combined pictures' size. Some numbers on performance:\n\nThe above script needed about 1 minute on my machine for 149 pictures with a total size of 514 MB (and about the same resulting PDF size).\n\n.. image:: images/img-import-progress.*\n   :scale: 80\n\nLook `here <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/insert-images/insert.py>`_ for a more complete source code: it offers a directory selection dialog and skips unsupported files and non-file entries.\n\n.. note:: We might have used :meth:`Page.insert_image` instead of :meth:`Page.show_pdf_page`, and the result would have been a similar looking file. However, depending on the image type, it may store **images uncompressed**. Therefore, the save option *deflate = True* must be used to achieve a reasonable file size, which hugely increases the runtime for large numbers of images. So this alternative **cannot be recommended** here.\n\n**Method 2: Embedding Files**\n\nThe second script **embeds** arbitrary files -- not only images. The resulting PDF will have just one (empty) page, required for technical reasons. To later access the embedded files again, you would need a suitable PDF viewer that can display and / or extract embedded files::\n\n import os, pymupdf\n import PySimpleGUI as psg  # for showing progress bar\n doc = pymupdf.open()  # PDF with the pictures\n imgdir = \"D:/2012_10_05\"  # where my files are\n\n imglist = os.listdir(imgdir)  # list of pictures\n imgcount = len(imglist)  # pic count\n imglist.sort()  # nicely sort them\n\n for i, f in enumerate(imglist):\n     img = open(os.path.join(imgdir,f), \"rb\").read()  # make pic stream\n     doc.embfile_add(img, f, filename=f,  # and embed it\n                         ufilename=f, desc=f)\n     psg.EasyProgressMeter(\"Embedding Files\",  # show our progress\n         i+1, imgcount)\n\n page = doc.new_page()  # at least 1 page is needed\n\n doc.save(\"all-my-pics-embedded.pdf\")\n\n.. image:: images/img-embed-progress.*\n   :scale: 80\n\nThis is by far the fastest method, and it also produces the smallest possible output file size. The above pictures needed 20 seconds on my machine and yielded a PDF size of 510 MB. Look `here <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples/embed-images/embed.py>`_ for a more complete source code: it offers a directory selection dialog and skips non-file entries.\n\n**Method 3: Attaching Files**\n\nA third way to achieve this task is **attaching files** via page annotations see `here <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/attach-images/attach.py>`_ for the complete source code.\n\nThis has a similar performance as the previous script and it also produces a similar file size. It will produce PDF pages which show a 'FileAttachment' icon for each attached file.\n\n.. image:: images/img-attach-result.*\n\n.. note:: Both, the **embed** and the **attach** methods can be used for **arbitrary files** -- not just images.\n\n.. note:: We strongly recommend using the awesome package `PySimpleGUI <https://pypi.org/project/PySimpleGUI/>`_ to display a progress meter for tasks that may run for an extended time span. It's pure Python, uses Tkinter (no additional GUI package) and requires just one more line of code!\n\n----------\n\n.. index::\n   triple: vector;image;SVG\n   pair: show_pdf_page;examples\n   pair: insert_image;examples\n   pair: embfile_add;examples\n\n\n.. _RecipesImages_J:\n\nHow to Create Vector Images\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe usual way to create an image from a document page is :meth:`Page.get_pixmap`. A pixmap represents a raster image, so you must decide on its quality (i.e. resolution) at creation time. It cannot be changed later.\n\nPyMuPDF also offers a way to create a **vector image** of a page in SVG format (scalable vector graphics, defined in XML syntax). SVG images remain precise across zooming levels (of course with the exception of any raster graphic elements embedded therein).\n\nInstruction *svg = page.get_svg_image(matrix=pymupdf.Identity)* delivers a UTF-8 string *svg* which can be stored with extension \".svg\".\n\n----------\n\n.. index::\n   pair: save;examples\n   pair: tobytes;examples\n   pair: Photoshop;examples\n   pair: Postscript;examples\n   pair: JPEG;examples\n   pair: PhotoImage;examples\n\n\n.. _RecipesImages_K:\n\nHow to Convert Images\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nJust as a feature among others, PyMuPDF's image conversion is easy. It may avoid using other graphics packages like PIL/Pillow in many cases.\n\nNotwithstanding that interfacing with Pillow is almost trivial.\n\n================= ================== =========================================\n**Input Formats** **Output Formats** **Description**\n================= ================== =========================================\nBMP               .                  Windows Bitmap\nJPEG              JPEG               Joint Photographic Experts Group\nJXR               .                  JPEG Extended Range\nJPX/JP2           .                  JPEG 2000\nGIF               .                  Graphics Interchange Format\nTIFF              .                  Tagged Image File Format\nPNG               PNG                Portable Network Graphics\nPNM               PNM                Portable Anymap\nPGM               PGM                Portable Graymap\nPBM               PBM                Portable Bitmap\nPPM               PPM                Portable Pixmap\nPAM               PAM                Portable Arbitrary Map\n.                 PSD                Adobe Photoshop Document\n.                 PS                 Adobe Postscript\n================= ================== =========================================\n\nThe general scheme is just the following two lines::\n\n    pix = pymupdf.Pixmap(\"input.xxx\")  # any supported input format\n    pix.save(\"output.yyy\")  # any supported output format\n\n**Remarks**\n\n1. The **input** argument of *pymupdf.Pixmap(arg)* can be a file or a bytes / io.BytesIO object containing an image.\n2. Instead of an output **file**, you can also create a bytes object via *pix.tobytes(\"yyy\")* and pass this around.\n3. As a matter of course, input and output formats must be compatible in terms of colorspace and transparency. The ``Pixmap`` class has batteries included if adjustments are needed.\n\n.. note::\n        **Convert JPEG to Photoshop**::\n\n          pix = pymupdf.Pixmap(\"myfamily.jpg\")\n          pix.save(\"myfamily.psd\")\n\n.. note::\n        Convert **JPEG to Tkinter PhotoImage**. Any **RGB / no-alpha** image works exactly the same. Conversion to one of the **Portable Anymap** formats (PPM, PGM, etc.) does the trick, because they are supported by all Tkinter versions::\n\n          import tkinter as tk\n          pix = pymupdf.Pixmap(\"input.jpg\")  # or any RGB / no-alpha image\n          tkimg = tk.PhotoImage(data=pix.tobytes(\"ppm\"))\n\n.. note::\n        Convert **PNG with alpha** to Tkinter PhotoImage. This requires **removing the alpha bytes**, before we can do the PPM conversion::\n\n          import tkinter as tk\n          pix = pymupdf.Pixmap(\"input.png\")  # may have an alpha channel\n          if pix.alpha:  # we have an alpha channel!\n              pix = pymupdf.Pixmap(pix, 0)  # remove it\n          tkimg = tk.PhotoImage(data=pix.tobytes(\"ppm\"))\n\n----------\n\n.. index::\n   pair: copy;examples\n\n\n.. _RecipesImages_L:\n\nHow to Use Pixmaps: Gluing Images\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis shows how pixmaps can be used for purely graphical, non-document purposes. The script reads an image file and creates a new image which consist of 3 * 4 tiles of the original::\n\n import pymupdf\n src = pymupdf.Pixmap(\"img-7edges.png\")      # create pixmap from a picture\n col = 3                                  # tiles per row\n lin = 4                                  # tiles per column\n tar_w = src.width * col                  # width of target\n tar_h = src.height * lin                 # height of target\n\n # create target pixmap\n tar_pix = pymupdf.Pixmap(src.colorspace, (0, 0, tar_w, tar_h), src.alpha)\n\n # now fill target with the tiles\n for i in range(col):\n     for j in range(lin):\n         src.set_origin(src.width * i, src.height * j)\n         tar_pix.copy(src, src.irect) # copy input to new loc\n\n tar_pix.save(\"tar.png\")\n\nThis is the input picture:\n\n.. image:: images/img-7edges.png\n   :scale: 33\n\nHere is the output:\n\n.. image:: images/img-target.png\n   :scale: 33\n\n----------\n\n.. index::\n   pair: set_rect;examples\n   pair: invert_irect;examples\n   pair: copy;examples\n   pair: save;examples\n\n\n.. _RecipesImages_M:\n\nHow to Use Pixmaps: Making a Fractal\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nHere is another Pixmap example that creates **Sierpinski's Carpet** -- a fractal generalizing the **Cantor Set** to two dimensions. Given a square carpet, mark its 9 sub-suqares (3 times 3) and cut out the one in the center. Treat each of the remaining eight sub-squares in the same way, and continue *ad infinitum*. The end result is a set with area zero and fractal dimension 1.8928...\n\nThis script creates an approximate image of it as a PNG, by going down to one-pixel granularity. To increase the image precision, change the value of n (precision)::\n\n    import pymupdf, time\n    if not list(map(int, pymupdf.VersionBind.split(\".\"))) >= [1, 14, 8]:\n        raise SystemExit(\"need PyMuPDF v1.14.8 for this script\")\n    n = 6                             # depth (precision)\n    d = 3**n                          # edge length\n\n    t0 = time.perf_counter()\n    ir = (0, 0, d, d)                 # the pixmap rectangle\n\n    pm = pymupdf.Pixmap(pymupdf.csRGB, ir, False)\n    pm.set_rect(pm.irect, (255,255,0)) # fill it with some background color\n\n    color = (0, 0, 255)               # color to fill the punch holes\n\n    # alternatively, define a 'fill' pixmap for the punch holes\n    # this could be anything, e.g. some photo image ...\n    fill = pymupdf.Pixmap(pymupdf.csRGB, ir, False) # same size as 'pm'\n    fill.set_rect(fill.irect, (0, 255, 255))   # put some color in\n\n    def punch(x, y, step):\n        \"\"\"Recursively \"punch a hole\" in the central square of a pixmap.\n\n        Arguments are top-left coords and the step width.\n\n        Some alternative punching methods are commented out.\n        \"\"\"\n        s = step // 3                 # the new step\n        # iterate through the 9 sub-squares\n        # the central one will be filled with the color\n        for i in range(3):\n            for j in range(3):\n                if i != j or i != 1:  # this is not the central cube\n                    if s >= 3:        # recursing needed?\n                        punch(x+i*s, y+j*s, s)       # recurse\n                else:                 # punching alternatives are:\n                    pm.set_rect((x+s, y+s, x+2*s, y+2*s), color)     # fill with a color\n                    #pm.copy(fill, (x+s, y+s, x+2*s, y+2*s))  # copy from fill\n                    #pm.invert_irect((x+s, y+s, x+2*s, y+2*s))       # invert colors\n\n        return\n\n    #==============================================================================\n    # main program\n    #==============================================================================\n    # now start punching holes into the pixmap\n    punch(0, 0, d)\n    t1 = time.perf_counter()\n    pm.save(\"sierpinski-punch.png\")\n    t2 = time.perf_counter()\n    print (f\"{round(t1-t0,3)} sec to create / fill the pixmap\")\n    print (f\"{round(t2-t1,3)} sec to save the image\")\n\nThe result should look something like this:\n\n.. image:: images/img-sierpinski.png\n   :scale: 33\n\n----------\n\n.. _RecipesImages_N:\n\nHow to Interface with NumPy\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis shows how to create a PNG file from a numpy array (several times faster than most other methods)::\n\n import numpy as np\n import pymupdf\n #==============================================================================\n # create a fun-colored width * height PNG with pymupdf and numpy\n #==============================================================================\n height = 150\n width  = 100\n bild = np.ndarray((height, width, 3), dtype=np.uint8)\n\n for i in range(height):\n     for j in range(width):\n         # one pixel (some fun coloring)\n         bild[i, j] = [(i+j)%256, i%256, j%256]\n\n samples = bytearray(bild.tostring())    # get plain pixel data from numpy array\n pix = pymupdf.Pixmap(pymupdf.csRGB, width, height, samples, alpha=False)\n pix.save(\"test.png\")\n\n\n----------\n\n\n.. _RecipesImages_O:\n\nHow to Add Images to a PDF Page\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThere are two methods to add images to a PDF page: :meth:`Page.insert_image` and :meth:`Page.show_pdf_page`. Both methods have things in common, but there are also differences.\n\n============================== ===================================== =========================================\n**Criterion**                  :meth:`Page.insert_image`              :meth:`Page.show_pdf_page`\n============================== ===================================== =========================================\ndisplayable content            image file, image in memory, pixmap   PDF page\ndisplay resolution             image resolution                      vectorized (except raster page content)\nrotation                       0, 90, 180 or 270 degrees             any angle\nclipping                       no (full image only)                  yes\nkeep aspect ratio              yes (default option)                  yes (default option)\ntransparency (water marking)   depends on the image                  depends on the page\nlocation / placement           scaled to fit target rectangle        scaled to fit target rectangle\nperformance                    automatic prevention of duplicates;   automatic prevention of duplicates;\nmulti-page image support       no                                    yes\nease of use                    simple, intuitive;                    simple, intuitive;\n                                                                     **usable for all document types**\n                                                                     (including images!) after conversion to\n                                                                     PDF via :meth:`Document.convert_to_pdf`\n============================== ===================================== =========================================\n\nBasic code pattern for :meth:`Page.insert_image`. **Exactly one** of the parameters **filename / stream / pixmap** must be given, if not re-inserting an existing image::\n\n    page.insert_image(\n        rect,                  # where to place the image (rect-like)\n        filename=None,         # image in a file\n        stream=None,           # image in memory (bytes)\n        pixmap=None,           # image from pixmap\n        mask=None,             # specify alpha channel separately\n        rotate=0,              # rotate (int, multiple of 90)\n        xref=0,                # re-use existing image\n        oc=0,                  # control visibility via OCG / OCMD\n        keep_proportion=True,  # keep aspect ratio\n        overlay=True,          # put in foreground\n    )\n\nBasic code pattern for :meth:`Page.show_pdf_page`. Source and target PDF must be different :ref:`Document` objects (but may be opened from the same file)::\n\n    page.show_pdf_page(\n        rect,                  # where to place the image (rect-like)\n        src,                   # source PDF\n        pno=0,                 # page number in source PDF\n        clip=None,             # only display this area (rect-like)\n        rotate=0,              # rotate (float, any value)\n        oc=0,                  # control visibility via OCG / OCMD\n        keep_proportion=True,  # keep aspect ratio\n        overlay=True,          # put in foreground\n    )\n\n.. _RecipesImages_P:\n\nHow to Use Pixmaps: Checking Text Visibility\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWhether or not a given piece of text is actually visible on a page depends on a number of factors:\n\n1. Text is not covered by another object but may have the same color as the background i.e., white-on-white etc.\n2. Text may be covered by an image or vector graphics. Detecting this is an important capability, for example to uncover badly anonymized legal documents.\n3. Text is created hidden. This technique is usually used by OCR tools to store the recognized text in an invisible layer on the page.\n\nThe following shows how to detect situation 1. above, or situation 2. if the covering object is unicolor::\n\n    pix = page.get_pixmap(dpi=150)  # make page image with a decent resolution\n     \n    # the following matrix transforms page to pixmap coordinates\n    mat = page.rect.torect(pix.irect)\n     \n    # search for some string \"needle\"\n    rlist = page.search_for(\"needle\")\n    # check the visibility for each hit rectangle\n    for rect in rlist:\n        if pix.color_topusage(clip=rect * mat)[0] > 0.95:\n            print(\"'needle' is invisible here:\", rect)\n\nMethod :meth:`Pixmap.color_topusage` returns a tuple `(ratio, pixel)` where 0 < ratio <= 1 and *pixel* is the pixel value of the color. Please note that we create a **pixmap only once**. This can save a lot of processing time if there are multiple hit rectangles.\n\nThe logic of the above code is: If the needle's rectangle is (\"almost\": > 95%) unicolor, then the text cannot be visible. A typical result for visible text returns the color of the background (mostly white) and a ratio around 0.7 to 0.8, for example `(0.685, b'\\xff\\xff\\xff')`.\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-journalling.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesJournalling:\n\n=========================================\nJournalling\n=========================================\n\n\nStarting with version 1.19.0, journalling is possible when updating PDF documents.\n\nJournalling is a logging mechanism which permits either **reverting** or **re-applying** changes to a PDF. Similar to LUWs \"Logical Units of Work\" in modern database systems, one can group a set of updates into an \"operation\". In MuPDF journalling, an operation plays the role of a LUW.\n\n.. note:: In contrast to LUW implementations found in database systems, MuPDF journalling happens on a **per document level**. There is no support for simultaneous updates across multiple PDFs: one would have to establish one's own logic here.\n\n* Journalling must be *enabled* via a document method. Journalling is possible for existing or new documents. Journalling **can be disabled only** by closing the file.\n* Once enabled, every change must happen inside an *operation* -- otherwise an exception is raised. An operation is started and stopped via document methods. Updates happening between these two calls form an LUW and can thus collectively be rolled back or re-applied, or, in MuPDF terminology \"undone\" resp. \"redone\".\n* At any point, the journalling status can be queried: whether journalling is active, how many operations have been recorded, whether \"undo\" or \"redo\" is possible, the current position inside the journal, etc.\n* The journal can be **saved to** or **loaded from** a file. These are document methods.\n* When loading a journal file, compatibility with the document is checked and journalling is automatically enabled upon success.\n* For an **existing** PDF being journalled, a special new save method is available: :meth:`Document.save_snapshot`. This performs a special incremental save that includes all journalled updates so far. If its journal is saved at the same time (immediately after the document snapshot), then document and journal are in sync and can later on be used together to undo or redo operations or to continue journalled updates -- just as if there had been no interruption.\n* The snapshot PDF is a valid PDF in every aspect and fully usable. If the document is however changed in any way without using its journal file, then a desynchronization will take place and the journal is rendered unusable.\n* Snapshot files are structured like incremental updates. Nevertheless, the internal journalling logic requires, that saving **must happen to a new file**. So the user should develop a file naming convention to support recognizable relationships between an original PDF, like `original.pdf` and its snapshot sets, like `original-snap1.pdf` / `original-snap1.log`, `original-snap2.pdf` / `original-snap2.log`, etc.\n\nExample Session 1\n~~~~~~~~~~~~~~~~~~\nDescription:\n\n* Make a new PDF and enable journalling. Then add a page and some text lines -- each as a separate operation.\n* Navigate within the journal, undoing and redoing these updates and displaying status and file results::\n\n    >>> import pymupdf\n    >>> doc=pymupdf.open()\n    >>> doc.journal_enable()\n\n    >>> # try update without an operation:\n    >>> page = doc.new_page()\n    mupdf: No journalling operation started\n    ... omitted lines\n    RuntimeError: No journalling operation started\n\n    >>> doc.journal_start_op(\"op1\")\n    >>> page = doc.new_page()\n    >>> doc.journal_stop_op()\n\n    >>> doc.journal_start_op(\"op2\")\n    >>> page.insert_text((100,100), \"Line 1\")\n    >>> doc.journal_stop_op()\n\n    >>> doc.journal_start_op(\"op3\")\n    >>> page.insert_text((100,120), \"Line 2\")\n    >>> doc.journal_stop_op()\n\n    >>> doc.journal_start_op(\"op4\")\n    >>> page.insert_text((100,140), \"Line 3\")\n    >>> doc.journal_stop_op()\n\n    >>> # show position in journal\n    >>> doc.journal_position()\n    (4, 4)\n    >>> # 4 operations recorded - positioned at bottom\n    >>> # what can we do?\n    >>> doc.journal_can_do()\n    {'undo': True, 'redo': False}\n    >>> # currently only undos are possible. Print page content:\n    >>> print(page.get_text())\n    Line 1\n    Line 2\n    Line 3\n\n    >>> # undo last insert:\n    >>> doc.journal_undo()\n    >>> # show combined status again:\n    >>> doc.journal_position();doc.journal_can_do()\n    (3, 4)\n    {'undo': True, 'redo': True}\n    >>> print(page.get_text())\n    Line 1\n    Line 2\n\n    >>> # our position is now second to last\n    >>> # last text insertion was reverted\n    >>> # but we can redo / move forward as well:\n    >>> doc.journal_redo()\n    >>> # our combined status:\n    >>> doc.journal_position();doc.journal_can_do()\n    (4, 4)\n    {'undo': True, 'redo': False}\n    >>> print(page.get_text())\n    Line 1\n    Line 2\n    Line 3\n    >>> # line 3 has appeared again!\n\n\nExample Session 2\n~~~~~~~~~~~~~~~~~~\nDescription:\n\n* Similar to previous, but after undoing some operations, we now add a different update. This will cause:\n\n    - permanent removal of the undone journal entries\n    - the new update operation will become the new last entry.\n\n\n    >>> doc=pymupdf.open()\n    >>> doc.journal_enable()\n    >>> doc.journal_start_op(\"Page insert\")\n    >>> page=doc.new_page()\n    >>> doc.journal_stop_op()\n    >>> for i in range(5):\n            doc.journal_start_op(f\"insert-{i}\")\n            page.insert_text((100, 100 + 20*i), f\"text line {i}\")\n            doc.journal_stop_op()\n\n    >>> # combined status info:\n    >>> doc.journal_position();doc.journal_can_do()\n    (6, 6)\n    {'undo': True, 'redo': False}\n\n    >>> for i in range(3):  # revert last three operations\n            doc.journal_undo()\n    >>> doc.journal_position();doc.journal_can_do()\n    (3, 6)\n    {'undo': True, 'redo': True}\n\n    >>> # now do a different update:\n    >>> doc.journal_start_op(\"Draw some line\")\n    >>> page.draw_line((100,150), (300,150))\n    Point(300.0, 150.0)\n    >>> doc.journal_stop_op()\n    >>> doc.journal_position();doc.journal_can_do()\n    (4, 4)\n    {'undo': True, 'redo': False}\n\n    >>> # this has changed the journal:\n    >>> # previous last 3 text line operations were removed, and\n    >>> # we have only 4 operations: drawing the line is the new last one\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-low-level-interfaces.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesLowLevelInterfaces:\n\n=========================================\nLow-Level Interfaces\n=========================================\n\n\nNumerous methods are available to access and manipulate PDF files on a fairly low level. Admittedly, a clear distinction between \"low level\" and \"normal\" functionality is not always possible or subject to personal taste.\n\nIt also may happen, that functionality previously deemed low-level is later on assessed as being part of the normal interface. This has happened in v1.14.0 for the class :ref:`Tools` - you now find it as an item in the Classes chapter.\n\nIt is a matter of documentation only in which chapter of the documentation you find what you are looking for. Everything is available and always via the same interface.\n\n----------------------------------\n\nHow to Iterate through the :data:`xref` Table\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nA PDF's :data:`xref` table is a list of all objects defined in the file. This table may easily contain many thousands of entries -- the manual :ref:`AdobeManual` for example has 127,000 objects. Table entry \"0\" is reserved and must not be touched.\nThe following script loops through the :data:`xref` table and prints each object's definition::\n\n    >>> xreflen = doc.xref_length()  # length of objects table\n    >>> for xref in range(1, xreflen):  # skip item 0!\n            print(\"\")\n            print(f\"object {xref} (stream: {doc.xref_is_stream(xref)})\")\n            print(doc.xref_object(xref, compressed=False))\n\n\n.. highlight:: text\n\nThis produces the following output::\n\n    object 1 (stream: False)\n    <<\n        /ModDate (D:20170314122233-04'00')\n        /PXCViewerInfo (PDF-XChange Viewer;2.5.312.1;Feb  9 2015;12:00:06;D:20170314122233-04'00')\n    >>\n\n    object 2 (stream: False)\n    <<\n        /Type /Catalog\n        /Pages 3 0 R\n    >>\n\n    object 3 (stream: False)\n    <<\n        /Kids [ 4 0 R 5 0 R ]\n        /Type /Pages\n        /Count 2\n    >>\n\n    object 4 (stream: False)\n    <<\n        /Type /Page\n        /Annots [ 6 0 R ]\n        /Parent 3 0 R\n        /Contents 7 0 R\n        /MediaBox [ 0 0 595 842 ]\n        /Resources 8 0 R\n    >>\n    ...\n    object 7 (stream: True)\n    <<\n        /Length 494\n        /Filter /FlateDecode\n    >>\n    ...\n\n.. highlight:: python\n\nA PDF object definition is an ordinary ASCII string.\n\n----------------------------------\n\nHow to Handle Object Streams\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nSome object types contain additional data apart from their object definition. Examples are images, fonts, embedded files or commands describing the appearance of a page.\n\nObjects of these types are called \"stream objects\". PyMuPDF allows reading an object's stream via method :meth:`Document.xref_stream` with the object's :data:`xref` as an argument. It is also possible to write back a modified version of a stream using :meth:`Document.update_stream`.\n\nAssume that the following snippet wants to read all streams of a PDF for whatever reason::\n\n    >>> xreflen = doc.xref_length() # number of objects in file\n    >>> for xref in range(1, xreflen): # skip item 0!\n            if stream := doc.xref_stream(xref):\n                # do something with it (it is a bytes object or None)\n                # e.g. just write it back:\n                doc.update_stream(xref, stream)\n\n:meth:`Document.xref_stream` automatically returns a stream decompressed as a bytes object -- and :meth:`Document.update_stream` automatically compresses it if beneficial.\n\n----------------------------------\n\nHow to Handle Page Contents\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nA PDF page can have zero or multiple :data:`contents` objects. These are stream objects describing **what** appears **where** and **how** on a page (like text and images). They are written in a special mini-language described e.g. in chapter \"APPENDIX A - Operator Summary\" on page 643 of the :ref:`AdobeManual`.\n\nEvery PDF reader application must be able to interpret the contents syntax to reproduce the intended appearance of the page.\n\nIf multiple :data:`contents` objects are provided, they must be interpreted in the specified sequence in exactly the same way as if they were provided as a concatenation of the several.\n\nThere are good technical arguments for having multiple :data:`contents` objects:\n\n* It is a lot easier and faster to just add new :data:`contents` objects than maintaining a single big one (which entails reading, decompressing, modifying, recompressing, and rewriting it for each change).\n* When working with incremental updates, a modified big :data:`contents` object will bloat the update delta and can thus easily negate the efficiency of incremental saves.\n\nFor example, PyMuPDF adds new, small :data:`contents` objects in methods :meth:`Page.insert_image`, :meth:`Page.show_pdf_page` and the :ref:`Shape` methods.\n\nHowever, there are also situations when a **single** :data:`contents` object is beneficial: it is easier to interpret and more compressible than multiple smaller ones.\n\nHere are two ways of combining multiple contents of a page::\n\n    >>> # method 1: use the MuPDF clean function\n    >>> page.clean_contents()  # cleans and combines multiple Contents\n    >>> xref = page.get_contents()[0]  # only one /Contents now!\n    >>> cont = doc.xref_stream(xref)\n    >>> # this has also reformatted the PDF commands\n\n    >>> # method 2: extract concatenated contents\n    >>> cont = page.read_contents()\n    >>> # the /Contents source itself is unmodified\n\nThe clean function :meth:`Page.clean_contents` does a lot more than just glueing :data:`contents` objects: it also corrects and optimizes the PDF operator syntax of the page and removes any inconsistencies with the page's object definition.\n\n----------------------------------\n\nHow to Access the PDF Catalog\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis is a central (\"root\") object of a PDF. It serves as a starting point to reach important other objects and it also contains some global options for the PDF::\n\n    >>> import pymupdf\n    >>> doc=pymupdf.open(\"PyMuPDF.pdf\")\n    >>> cat = doc.pdf_catalog()  # get xref of the /Catalog\n    >>> print(doc.xref_object(cat))  # print object definition\n    <<\n        /Type/Catalog                 % object type\n        /Pages 3593 0 R               % points to page tree\n        /OpenAction 225 0 R           % action to perform on open\n        /Names 3832 0 R               % points to global names tree\n        /PageMode /UseOutlines        % initially show the TOC\n        /PageLabels<</Nums[0<</S/D>>2<</S/r>>8<</S/D>>]>> % labels given to pages\n        /Outlines 3835 0 R            % points to outline tree\n    >>\n\n.. note:: Indentation, line breaks and comments are inserted here for clarification purposes only and will not normally appear. For more information on the PDF catalog see section 7.7.2 on page 71 of the :ref:`AdobeManual`.\n\n----------------------------------\n\nHow to Access the PDF File Trailer\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe trailer of a PDF file is a :data:`dictionary` located towards the end of the file. It contains special objects, and pointers to important other information. See :ref:`AdobeManual` p. 42. Here is an overview:\n\n======= =========== ===================================================================================\n**Key** **Type**    **Value**\n======= =========== ===================================================================================\nSize    int         Number of entries in the cross-reference table + 1.\nPrev    int         Offset to previous :data:`xref` section (indicates incremental updates).\nRoot    dictionary  (indirect) Pointer to the catalog. See previous section.\nEncrypt dictionary  Pointer to encryption object (encrypted files only).\nInfo    dictionary  (indirect) Pointer to information (metadata).\nID      array       File identifier consisting of two byte strings.\nXRefStm int         Offset of a cross-reference stream. See :ref:`AdobeManual` p. 49.\n======= =========== ===================================================================================\n\nAccess this information via PyMuPDF with :meth:`Document.pdf_trailer` or, equivalently, via :meth:`Document.xref_object` using -1 instead of a valid :data:`xref` number.\n\n    >>> import pymupdf\n    >>> doc=pymupdf.open(\"PyMuPDF.pdf\")\n    >>> print(doc.xref_object(-1))  # or: print(doc.pdf_trailer())\n    <<\n    /Type /XRef\n    /Index [ 0 8263 ]\n    /Size 8263\n    /W [ 1 3 1 ]\n    /Root 8260 0 R\n    /Info 8261 0 R\n    /ID [ <4339B9CEE46C2CD28A79EBDDD67CC9B3> <4339B9CEE46C2CD28A79EBDDD67CC9B3> ]\n    /Length 19883\n    /Filter /FlateDecode\n    >>\n    >>>\n\n----------------------------------\n\nHow to Access XML Metadata\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nA PDF may contain XML metadata in addition to the standard metadata format. In fact, most PDF viewer or modification software adds this type of information when saving the PDF (Adobe, Nitro PDF, PDF-XChange, etc.).\n\nPyMuPDF has no way to **interpret or change** this information directly, because it contains no XML features. XML metadata is however stored as a :data:`stream` object, so it can be read, modified with appropriate software and written back.\n\n    >>> xmlmetadata = doc.get_xml_metadata()\n    >>> print(xmlmetadata)\n    <?xpacket begin=\"\\ufeff\" id=\"W5M0MpCehiHzreSzNTczkc9d\"?>\n    <x:xmpmeta xmlns:x=\"adobe:ns:meta/\" x:xmptk=\"3.1-702\">\n    <rdf:RDF xmlns:rdf=\"http://www.w3.org/1999/02/22-rdf-syntax-ns#\">\n    ...\n    omitted data\n    ...\n    <?xpacket end=\"w\"?>\n\nUsing some XML package, the XML data can be interpreted and / or modified and then stored back. The following also works, if the PDF previously had no XML metadata::\n\n    >>> # write back modified XML metadata:\n    >>> doc.set_xml_metadata(xmlmetadata)\n    >>>\n    >>> # XML metadata can be deleted like this:\n    >>> doc.del_xml_metadata()\n\n----------------------------------\n\nHow to Extend PDF Metadata\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nAttribute :attr:`Document.metadata` is designed so it works for all :ref:`supported document types<Supported_File_Types>` in the same way: it is a Python dictionary with a **fixed set of key-value pairs**. Correspondingly, :meth:`Document.set_metadata` only accepts standard keys.\n\nHowever, PDFs may contain items not accessible like this. Also, there may be reasons to store additional information, like copyrights. Here is a way to handle **arbitrary metadata items** by using PyMuPDF low-level functions.\n\nAs an example, look at this standard metadata output of some PDF::\n\n    # ---------------------\n    # standard metadata\n    # ---------------------\n    pprint(doc.metadata)\n    {'author': 'PRINCE',\n     'creationDate': \"D:2010102417034406'-30'\",\n     'creator': 'PrimoPDF http://www.primopdf.com/',\n     'encryption': None,\n     'format': 'PDF 1.4',\n     'keywords': '',\n     'modDate': \"D:20200725062431-04'00'\",\n     'producer': 'macOS Version 10.15.6 (Build 19G71a) Quartz PDFContext, '\n                 'AppendMode 1.1',\n     'subject': '',\n     'title': 'Full page fax print',\n     'trapped': ''}\n\nUse the following code to see **all items** stored in the metadata object::\n\n    # ----------------------------------\n    # metadata including private items\n    # ----------------------------------\n    metadata = {}  # make my own metadata dict\n    what, value = doc.xref_get_key(-1, \"Info\")  # /Info key in the trailer\n    if what != \"xref\":\n        pass  # PDF has no metadata\n    else:\n        xref = int(value.replace(\"0 R\", \"\"))  # extract the metadata xref\n        for key in doc.xref_get_keys(xref):\n            metadata[key] = doc.xref_get_key(xref, key)[1]\n    pprint(metadata)\n    {'Author': 'PRINCE',\n     'CreationDate': \"D:2010102417034406'-30'\",\n     'Creator': 'PrimoPDF http://www.primopdf.com/',\n     'ModDate': \"D:20200725062431-04'00'\",\n     'PXCViewerInfo': 'PDF-XChange Viewer;2.5.312.1;Feb  9 '\n                     \"2015;12:00:06;D:20200725062431-04'00'\",\n     'Producer': 'macOS Version 10.15.6 (Build 19G71a) Quartz PDFContext, '\n                 'AppendMode 1.1',\n     'Title': 'Full page fax print'}\n    # ---------------------------------------------------------------\n    # note the additional 'PXCViewerInfo' key - ignored in standard!\n    # ---------------------------------------------------------------\n\n\n*Vice versa*, you can also **store private metadata items** in a PDF. It is your responsibility to make sure that these items conform to PDF specifications - especially they must be (unicode) strings. Consult section 14.3 (p. 548) of the :ref:`AdobeManual` for details and caveats::\n\n    what, value = doc.xref_get_key(-1, \"Info\")  # /Info key in the trailer\n    if what != \"xref\":\n        raise ValueError(\"PDF has no metadata\")\n    xref = int(value.replace(\"0 R\", \"\"))  # extract the metadata xref\n    # add some private information\n    doc.xref_set_key(xref, \"mykey\", pymupdf.get_pdf_str(\"北京 is Beijing\"))\n    #\n    # after executing the previous code snippet, we will see this:\n    pprint(metadata)\n    {'Author': 'PRINCE',\n     'CreationDate': \"D:2010102417034406'-30'\",\n     'Creator': 'PrimoPDF http://www.primopdf.com/',\n     'ModDate': \"D:20200725062431-04'00'\",\n     'PXCViewerInfo': 'PDF-XChange Viewer;2.5.312.1;Feb  9 '\n                      \"2015;12:00:06;D:20200725062431-04'00'\",\n     'Producer': 'macOS Version 10.15.6 (Build 19G71a) Quartz PDFContext, '\n                 'AppendMode 1.1',\n     'Title': 'Full page fax print',\n     'mykey': '北京 is Beijing'}\n\nTo delete selected keys, use `doc.xref_set_key(xref, \"mykey\", \"null\")`. As explained in the next section, string \"null\" is the PDF equivalent to Python's `None`. A key with that value will be treated as not being specified -- and physically removed in garbage collections.\n\n----------------------------------\n\nHow to Read and Update PDF Objects\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. highlight:: python\n\n\nThere also exist granular, elegant ways to access and manipulate selected PDF :data:`dictionary` keys.\n\n* :meth:`Document.xref_get_keys` returns the PDF keys of the object at :data:`xref`::\n\n    In [1]: import pymupdf\n    In [2]: doc = pymupdf.open(\"pymupdf.pdf\")\n    In [3]: page = doc[0]\n    In [4]: from pprint import pprint\n    In [5]: pprint(doc.xref_get_keys(page.xref))\n    ('Type', 'Contents', 'Resources', 'MediaBox', 'Parent')\n\n* Compare with the full object definition::\n\n    In [6]: print(doc.xref_object(page.xref))\n    <<\n      /Type /Page\n      /Contents 1297 0 R\n      /Resources 1296 0 R\n      /MediaBox [ 0 0 612 792 ]\n      /Parent 1301 0 R\n    >>\n\n* Single keys can also be accessed directly via :meth:`Document.xref_get_key`. The value **always is a string** together with type information, that helps with interpreting it::\n\n    In [7]: doc.xref_get_key(page.xref, \"MediaBox\")\n    Out[7]: ('array', '[0 0 612 792]')\n\n* Here is a full listing of the above page keys::\n\n    In [9]: for key in doc.xref_get_keys(page.xref):\n    ...:        print(f\"{key} = {doc.xref_get_key(page.xref, key)}\")\n    ...:\n    Type = ('name', '/Page')\n    Contents = ('xref', '1297 0 R')\n    Resources = ('xref', '1296 0 R')\n    MediaBox = ('array', '[0 0 612 792]')\n    Parent = ('xref', '1301 0 R')\n\n* An undefined key inquiry returns `('null', 'null')` -- PDF object type `null` corresponds to `None` in Python. Similar for the booleans `true` and `false`.\n* Let us add a new key to the page definition that sets its rotation to 90 degrees (you are aware that there actually exists :meth:`Page.set_rotation` for this?)::\n\n    In [11]: doc.xref_get_key(page.xref, \"Rotate\")  # no rotation set:\n    Out[11]: ('null', 'null')\n    In [12]: doc.xref_set_key(page.xref, \"Rotate\", \"90\")  # insert a new key\n    In [13]: print(doc.xref_object(page.xref))  # confirm success\n    <<\n      /Type /Page\n      /Contents 1297 0 R\n      /Resources 1296 0 R\n      /MediaBox [ 0 0 612 792 ]\n      /Parent 1301 0 R\n      /Rotate 90\n    >>\n\n* This method can also be used to remove a key from the :data:`xref` dictionary by setting its value to `null`: The following will remove the rotation specification from the page: `doc.xref_set_key(page.xref, \"Rotate\", \"null\")`. Similarly, to remove all links, annotations and fields from a page, use `doc.xref_set_key(page.xref, \"Annots\", \"null\")`. Because `Annots` by definition is an array, setting en empty array with the statement `doc.xref_set_key(page.xref, \"Annots\", \"[]\")` would do the same job in this case.\n\n* PDF dictionaries can be hierarchically nested. In the following page object definition both, `Font` and `XObject` are subdictionaries of `Resources`::\n\n    In [15]: print(doc.xref_object(page.xref))\n    <<\n      /Type /Page\n      /Contents 1297 0 R\n      /Resources <<\n        /XObject <<\n          /Im1 1291 0 R\n        >>\n        /Font <<\n          /F39 1299 0 R\n          /F40 1300 0 R\n        >>\n      >>\n      /MediaBox [ 0 0 612 792 ]\n      /Parent 1301 0 R\n      /Rotate 90\n    >>\n\n* The above situation **is supported** by methods :meth:`Document.xref_set_key` and :meth:`Document.xref_get_key`: use a path-like notation to point at the required key. For example, to retrieve the value of key `Im1` above, specify the complete chain of dictionaries \"above\" it in the key argument: `\"Resources/XObject/Im1\"`::\n\n    In [16]: doc.xref_get_key(page.xref, \"Resources/XObject/Im1\")\n    Out[16]: ('xref', '1291 0 R')\n\n* The path notation can also be used to **directly set a value**: use the following to let `Im1` point to a different object::\n\n    In [17]: doc.xref_set_key(page.xref, \"Resources/XObject/Im1\", \"9999 0 R\")\n    In [18]: print(doc.xref_object(page.xref))  # confirm success:\n    <<\n      /Type /Page\n      /Contents 1297 0 R\n      /Resources <<\n        /XObject <<\n          /Im1 9999 0 R\n        >>\n        /Font <<\n          /F39 1299 0 R\n          /F40 1300 0 R\n        >>\n      >>\n      /MediaBox [ 0 0 612 792 ]\n      /Parent 1301 0 R\n      /Rotate 90\n    >>\n\n  Be aware, that **no semantic checks** whatsoever will take place here: if the PDF has no xref 9999, it won't be detected at this point.\n\n* If a key does not exist, it will be created by setting its value. Moreover, if any intermediate keys do not exist either, they will also be created as necessary. The following creates an array `D` several levels below the existing dictionary `A`. Intermediate dictionaries `B` and `C` are automatically created::\n\n    In [5]: print(doc.xref_object(xref))  # some existing PDF object:\n    <<\n      /A <<\n      >>\n    >>\n    In [6]: # the following will create 'B', 'C' and 'D'\n    In [7]: doc.xref_set_key(xref, \"A/B/C/D\", \"[1 2 3 4]\")\n    In [8]: print(doc.xref_object(xref))  # check out what happened:\n    <<\n      /A <<\n        /B <<\n          /C <<\n            /D [ 1 2 3 4 ]\n          >>\n        >>\n      >>\n    >>\n\n* When setting key values, basic **PDF syntax checking** will be done by MuPDF. For example, new keys can only be created **below a dictionary**. The following tries to create some new string item `E` below the previously created array `D`::\n\n    In [9]: # 'D' is an array, no dictionary!\n    In [10]: doc.xref_set_key(xref, \"A/B/C/D/E\", \"(hello)\")\n    mupdf: not a dict (array)\n    --- ... ---\n    RuntimeError: not a dict (array)\n\n* It is also **not possible**, to create a key if some higher level key is an **\"indirect\"** object, i.e. an xref. In other words, xrefs can only be modified directly and not implicitly via other objects referencing them::\n\n    In [13]: # the following object points to an xref\n    In [14]: print(doc.xref_object(4))\n    <<\n      /E 3 0 R\n    >>\n    In [15]: # 'E' is an indirect object and cannot be modified here!\n    In [16]: doc.xref_set_key(4, \"E/F\", \"90\")\n    mupdf: path to 'F' has indirects\n    --- ... ---\n    RuntimeError: path to 'F' has indirects\n\n.. caution:: These are expert functions! There are no validations as to whether valid PDF objects, xrefs, etc. are specified. As with other low-level methods there is the risk to render the PDF, or parts of it unusable.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-multiprocessing.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesMultiprocessing:\n\n\n.. |toggleStart| raw:: html\n\n   <details>\n   <summary><a>See code</a></summary>\n\n.. |toggleEnd| raw:: html\n\n   </details>\n\n==============================\nMultiprocessing\n==============================\n\n|PyMuPDF| does not support running on multiple threads - doing so may cause incorrect behaviour or even crash Python itself.\n\nHowever, there is the option to use :title:`Python's` *multiprocessing* module in a variety of ways.\n\nIf you are looking to speed up page-oriented processing for a large document, use this script as a starting point. It should be at least twice as fast as the corresponding sequential processing.\n\n\n|toggleStart|\n\n.. literalinclude:: samples/multiprocess-render.py\n   :language: python\n\n|toggleEnd|\n\n\nHere is a more complex example involving inter-process communication between a main process (showing a GUI) and a child process doing |PyMuPDF| access to a document.\n\n\n|toggleStart|\n\n.. literalinclude:: samples/multiprocess-gui.py\n   :language: python\n\n|toggleEnd|\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-ocr.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesOCR:\n\n\n.. |toggleStart| raw:: html\n\n   <details>\n   <summary><a>See code</a></summary>\n\n.. |toggleEnd| raw:: html\n\n   </details>\n\n====================================\nOCR - Optical Character Recognition\n====================================\n\n|PyMuPDF| has integrated support for OCR (Optical Character Recognition). It is possible to use OCR for both, images (via the :ref:`Pixmap` class) and for document pages.\n\nThe feature is currently based on Tesseract-OCR which must be installed as a separate application -- see the :ref:`installation_ocr`.\n\nHow to OCR an Image \n--------------------\nA supported image must first be converted to a :ref:`Pixmap`. The Pixmap can then be saved to a 1-page PDF. This page will look like the original image with the same width and height. It will contain a layer of text as recognized by Tesseract.\n\nThe PDF can be generated via one of the methods :meth:`Pixmap.pdfocr_save` or :meth:`Pixmap.pdfocr_tobytes`, as a file on disk or as a PDF in memory.\n\nThe text can be extracted and searched with the usual text extraction and search methods (:meth:`Page.get_text`, :meth:`Page.search_for`, etc.). Please also note the following important facts and prerequisites:\n\n* When converting the image to a Pixmap, please confirm that the color space is RGB and alpha is `False` (no transparency). Convert the original Pixmap if necessary.\n* All text is written as \"hidden\" with Tesseract's own `GlyphLessFont`, a mono-spaced font with metrics comparable to Courier.\n* All text has the properties regular and black (i.e. no bold, no italic, no information about the original fonts).\n* Tesseract does not recognize vector graphics (i.e. no drawings / line-art).\n\nThis approach is also recommended to OCR a complete scanned PDF:\n\n* Render each page to a :ref:`Pixmap` with desired resolution\n* Append the resulting 1-page PDF to the output PDF\n\nHow to OCR a Document Page\n----------------------------\nAny supported document page can be OCR-ed -- either the complete page or only the image areas on it.\n\nBecause optical character recognition is about one thousand times slower than standard text extraction, we make sure to do OCR only once per page and store the result in a :ref:`TextPage`. Using this TextPage for all subsequent extractions and text searches will then happen with |PyMuPDF|'s usual top speed.\n\nTo OCR a document page, follow this approach:\n\n1. Determine whether OCR is needed / beneficial at all. A number of criteria can be used for this decision, like:\n\n  * page is completely covered by an image\n  * no text exists on the page\n  * thousands of small vector graphics (indicating *simulated* text)\n\n2. OCR the page and store result in a :ref:`TextPage` object using an instruction like `tp = page.get_textpage_ocr(...)`.\n\n3. Refer to the produced :ref:`TextPage` in all subsequent text extractions and searches via the `textpage=tp` parameter.\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes-optional-content.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesOptionalContent:\n\n==============================\nOptional Content Support\n==============================\n\nThis document explains PyMuPDF's support of the PDF concept **\"Optional Content\"**.\n\nIntroduction: The Optional Content Concept\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n*Optional Content* in PDF is a way to show or hide parts of a document based on certain conditions: Parameters that can be set to ON or to OFF when using a supporting PDF consumer (viewer), or programmatically.\n\nThis capability is useful in items such as CAD drawings, layered artwork, maps, and multi-language documents. Typical uses include showing or hiding details of complex vector graphics like geographical maps, technical devices, architectural designs and similar, including automatically switching between different zooming levels. Other use cases may be to automatically show different detail levels when displaying a document on screen as opposed to printing it.\n\nSpecial PDF objects, so-called **Optional Content Groups** (OCGs) are used to define these different *layers* of content.\n\nAssigning an OCG to a \"normal\" PDF object (like a text or an image) causes that object to be visible or hidden, depending on the current state of the assigned OCG.\n\nTo ease definition of the overall configuration of a PDF's Optional Content, OCGs can be organized in higher level groupings, called **OC Configurations**. Each configuration being a collection of OCGs, together with each OCG's desired initial visibility state. Selecting one of these configurations (via the PDF viewer or programmatically) causes a corresponding visibility change of all affected PDF objects throughout the document.\n\nExcept for the default one, OC Configurations are optional.\n\nFor more explanations and additional background please refer to PDF specification manuals.\n\nPyMuPDF Support for PDF Optional Content\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nPyMuPDF offers full support for viewing, defining, changing and deleting Option Content Groups, Configurations, maintaining the assignment of OCGs to PDF objects and programmatically switching between OC Configurations and the visibility states of each single OCG.\n\nHow to Add Optional Content\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThis is as simple as adding an Optional Content Group, OCG, to a PDF: :meth:`Document.add_ocg`.\n\nIf previously the PDF had no OC support at all, the required setup (like defining the default OC Configuration) will be done at this point automatically.\n\nThe method returns an :data:`xref` of the created OCG. Use this xref to associate (mark) any PDF object with it, that you want to make dependent on this OCG's state. For example, you can insert an image on a page and refer to the xref like this::\n\n    img_xref = page.insert_image(rect, filename=\"image.file\", oc=xref)\n\nIf you want to put an **existing** image under the control of an OCG, you must first find out the image's xref number (called `img_xref` here) and then do `doc.set_oc(img_xref, xref)`. After this, the image will be (in-) visible everywhere throughout the document if the OCG's state is \"ON\", respectively \"OFF\". You can also assign a different OCG with this method.\n\nTo **remove** an OCG from an image, do `doc.set_oc(img_xref, 0)`.\n\nOne single OCG can be assigned to multiple PDF objects to control their visibility.\n\nHow to Define Complex Optional Content Conditions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nSophisticated logical conditions can be established to address complex visibility needs.\n\nFor example, you might want to create a multi-language document, so the user may switch between languages as required.\n\nPlease have a look at `this Jupyter Notebook`_ and execute it as desired.\n\nCertainly, your requirements may even be more complex and involve multiple OCGs with ON/OFF states that are connected by some kind of logical relationship -- but it should give you an impression of what is possible and how to plan your next steps.\n\n.. include:: footer.rst\n\n.. External Links:\n\n.. _this Jupyter Notebook: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/jupyter-notebooks/optional-content.ipynb\n\n\n\n"
  },
  {
    "path": "docs/recipes-stories.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesStories:\n\n.. role:: htmlTag(emphasis)\n\n.. |toggleStart| raw:: html\n\n   <details>\n   <summary><a>See recipe</a></summary>\n\n.. |toggleEnd| raw:: html\n\n   </details>\n\n==============================\nStories\n==============================\n\nThis document showcases some typical use cases for :ref:`Stories<WorkingWithStories>`.\n\nAs mentioned in the :ref:`tutorial<WorkingWithStories>`, stories may be created using up to three input sources: HTML, CSS and Archives -- all of which are optional and which, respectively, can be provided programmatically.\n\nThe following examples will showcase combinations for using these inputs.\n\n.. note::\n\n        Many of these recipe's source code are included as examples in the `docs` folder.\n\n\n.. _RecipesStories_A:\n\nHow to Add a Line of Text with Some Formatting\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nHere is the inevitable \"Hello World\" example. We will show two variants:\n\n1. Create using existing HTML source [#f1]_, that may come from anywhere.\n2. Create using the Python API.\n\n-----\n\nVariant using an existing HTML source [#f1]_ -- which in this case is defined as a constant in the script::\n\n    import pymupdf\n\n    HTML = \"\"\"\n    <p style=\"font-family: sans-serif;color: blue\">Hello World!</p>\n    \"\"\"\n\n    MEDIABOX = pymupdf.paper_rect(\"letter\")  # output page format: Letter\n    WHERE = MEDIABOX + (36, 36, -36, -36)  # leave borders of 0.5 inches\n\n    story = pymupdf.Story(html=HTML)  # create story from HTML\n    writer = pymupdf.DocumentWriter(\"output.pdf\")  # create the writer\n    \n    more = 1  # will indicate end of input once it is set to 0\n\n    while more:  # loop outputting the story\n        device = writer.begin_page(MEDIABOX)  # make new page\n        more, _ = story.place(WHERE)  # layout into allowed rectangle\n        story.draw(device)  # write on page\n        writer.end_page()  # finish page\n    \n    writer.close()  # close output file\n\n.. note::\n    \n    The above effect (sans-serif and blue text) could have been achieved by using a separate CSS source like so::\n\n        import pymupdf\n\n        CSS = \"\"\"\n        body {\n            font-family: sans-serif;\n            color: blue;\n        }\n        \"\"\"\n\n        HTML = \"\"\"\n        <p>Hello World!</p>\n        \"\"\"\n\n        # the story would then be created like this:\n        story = pymupdf.Story(html=HTML, user_css=CSS)\n\n\n-----\n\nThe Python API variant -- everything is created programmatically::\n\n    import pymupdf\n    \n    MEDIABOX = pymupdf.paper_rect(\"letter\")\n    WHERE = MEDIABOX + (36, 36, -36, -36)\n\n    story = pymupdf.Story()  # create an empty story\n    body = story.body  # access the body of its DOM\n    with body.add_paragraph() as para:  # store desired content\n        para.set_font(\"sans-serif\").set_color(\"blue\").add_text(\"Hello World!\")\n\n    writer = pymupdf.DocumentWriter(\"output.pdf\")\n    \n    more = 1\n\n    while more:\n        device = writer.begin_page(MEDIABOX)\n        more, _ = story.place(WHERE)\n        story.draw(device)\n        writer.end_page()\n\n    writer.close()\n\nBoth variants will produce the same output PDF.\n\n-----\n\n.. _RecipesStories_B:\n\n\nHow to use Images\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nImages can be referenced in the provided HTML source, or the reference to a desired image can also be stored via the Python API. In any case, this requires using an :ref:`Archive`, which refers to the place where the image can be found.\n\n.. note:: Images with the binary content embedded in the HTML source are **not supported** by stories.\n\nWe extend our \"Hello World\" example from above and display an image of our planet right after the text. Assuming the image has the name \"world.jpg\" and is present in the script's folder, then this is the modified version of the above Python API variant::\n\n    import pymupdf\n\n    MEDIABOX = pymupdf.paper_rect(\"letter\")\n    WHERE = MEDIABOX + (36, 36, -36, -36)\n\n    # create story, let it look at script folder for resources\n    story = pymupdf.Story(archive=\".\")\n    body = story.body  # access the body of its DOM\n\n    with body.add_paragraph() as para:\n        # store desired content\n        para.set_font(\"sans-serif\").set_color(\"blue\").add_text(\"Hello World!\")\n\n    # another paragraph for our image:\n    with body.add_paragraph() as para:\n        # store image in another paragraph\n        para.add_image(\"world.jpg\")\n\n    writer = pymupdf.DocumentWriter(\"output.pdf\")\n\n    more = 1\n\n    while more:\n        device = writer.begin_page(MEDIABOX)\n        more, _ = story.place(WHERE)\n        story.draw(device)\n        writer.end_page()\n\n    writer.close()\n\n\n-----\n\n\n.. _RecipesStories_C:\n\n\nHow to Read External HTML and CSS for a Story\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThese cases are fairly straightforward.\n\nAs a general recommendation, HTML and CSS sources should be **read as binary files** and decoded before using them in a story. The Python `pathlib.Path` provides convenient ways to do this::\n\n    import pathlib\n    import pymupdf\n\n    htmlpath = pathlib.Path(\"myhtml.html\")\n    csspath = pathlib.Path(\"mycss.css\")\n\n    HTML = htmlpath.read_bytes().decode()\n    CSS = csspath.read_bytes().decode()\n\n    story = pymupdf.Story(html=HTML, user_css=CSS)\n\n\n-----\n\n\n.. _RecipesStories_D:\n\n\nHow to Output Database Content with Story Templates\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis script demonstrates how to report SQL database content using an **HTML template**.\n\n\n\nThe example SQL database contains two tables:\n\n1. Table \"films\" contains one row per film with the fields **\"title\"**, **\"director\"** and (release) **\"year\"**.\n2. Table \"actors\" contains one row per actor and film title (fields (actor) **\"name\"** and (film) **\"title\"**).\n\nThe story DOM consists of a template for one film, which reports film data together with a list of casted actors.\n\n**Files:**\n\n* `docs/samples/filmfestival-sql.py`\n* `docs/samples/filmfestival-sql.db`\n\n\n|toggleStart|\n\n.. literalinclude:: samples/filmfestival-sql.py\n\n|toggleEnd|\n\n\n-----\n\n\n.. _RecipesStories_E:\n\nHow to Integrate with Existing PDFs\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nBecause a :ref:`DocumentWriter` can only write to a new file, stories cannot be placed on existing pages. This script demonstrates a circumvention of this restriction.\n\nThe basic idea is letting :ref:`DocumentWriter` output to a PDF in memory. Once the story has finished, we re-open this memory PDF and put its pages to desired locations on **existing** pages via method :meth:`Page.show_pdf_page`.\n\n**Files:**\n\n* `docs/samples/showpdf-page.py`\n\n|toggleStart|\n\n.. literalinclude:: samples/showpdf-page.py\n\n|toggleEnd|\n\n\n-----\n\n\n.. _RecipesStories_F:\n\nHow to Make Multi-Columned Layouts and Access Fonts from Package `pymupdf-fonts`_\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis script outputs an article (taken from Wikipedia) that contains text and multiple images and uses a 2-column page layout.\n\nIn addition, two \"Ubuntu\" font families from package `pymupdf-fonts`_ are used instead of defaulting to Base-14 fonts.\n\nYet another feature used here is that all data -- the images and the article HTML -- are jointly stored in a ZIP file.\n\n\n**Files:**\n\n* `docs/samples/quickfox.py`\n* `docs/samples/quickfox.zip`\n\n\n|toggleStart|\n\n.. literalinclude:: samples/quickfox.py\n\n|toggleEnd|\n\n\n-----\n\n\n.. _RecipesStories_G:\n\nHow to Make a Layout which Wraps Around a Predefined \"no go area\" Layout\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\nThis is a demo script using PyMuPDF's Story class to output text as a PDF with\na two-column page layout.\n\nThe script demonstrates the following features:\n\n* Layout text around images of an existing (\"target\") PDF.\n* Based on a few global parameters, areas on each page are identified, that\n  can be used to receive text layouted by a Story.\n* These global parameters are not stored anywhere in the target PDF and\n  must therefore be provided in some way:\n\n  - The width of the border(s) on each page.\n  - The fontsize to use for text. This value determines whether the provided\n    text will fit in the empty spaces of the (fixed) pages of target PDF. It\n    cannot be predicted in any way. The script ends with an exception if\n    target PDF has not enough pages, and prints a warning message if not all\n    pages receive at least some text. In both cases, the FONTSIZE value\n    can be changed (a float value).\n  - Use of a 2-column page layout for the text.\n* The layout creates a temporary (memory) PDF. Its produced page content\n  (the text) is used to overlay the corresponding target page. If text\n  requires more pages than are available in target PDF, an exception is raised.\n  If not all target pages receive at least some text, a warning is printed.\n* The script reads \"image-no-go.pdf\" in its own folder. This is the \"target\" PDF.\n  It contains 2 pages with each 2 images (from the original article), which are\n  positioned at places that create a broad overall test coverage. Otherwise the\n  pages are empty.\n* The script produces \"quickfox-image-no-go.pdf\" which contains the original pages\n  and image positions, but with the original article text laid out around them.\n\n**Files:**\n\n* `docs/samples/quickfox-image-no-go.py`\n* `docs/samples/quickfox-image-no-go.pdf`\n* `docs/samples/quickfox.zip`\n\n\n|toggleStart|\n\n.. literalinclude:: samples/quickfox-image-no-go.py\n\n|toggleEnd|\n\n\n-----\n\n\n.. _RecipesStories_H:\n\nHow to Output an HTML Table\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOutputting HTML tables is supported as follows:\n\n* Flat table layouts are supported (\"rows x columns\"), no support of the \"colspan\" / \"rowspan\" attributes.\n* Table header tag :htmlTag:`th` supports attribute \"scope\" with values \"row\" or \"col\". Applicable text will be bold by default.\n* Column widths are computed automatically based on column content. They cannot be directly set.\n* Table **cells may contain images** which will be considered in the column width calculation magic.\n* Row heights are computed automatically based on row content - leading to multi-line rows where needed.\n* The potentially multiple lines of a table row will always be kept together on one page (respectively \"where\" rectangle) and not be split.\n* Table header rows are only **shown on the first page / \"where\" rectangle.**\n* The \"style\" attribute is ignored when given directly in HTML table elements. Styling for a table and its elements must happen separately, in CSS source or within the :htmlTag:`style` tag.\n* Styling for :htmlTag:`tr` elements is not supported and ignored. Therefore, a table-wide grid or alternating row background colors are not supported. One of the following example scripts however shows an easy way to deal with this limitation.\n\n**Files:**\n\n* `docs/samples/table01.py` This script reflects basic features.\n\n|toggleStart|\n\n.. literalinclude:: samples/table01.py\n\n|toggleEnd|\n\n* `docs/samples/national-capitals.py` Advanced script extending table output options using simple additional code:\n\n    - Multi-page output simulating **repeating header rows**\n    - Alternating table row background colors\n    - Table rows and columns delimited by gridlines\n    - Table rows dynamically generated / filled with data from an SQL database\n\n|toggleStart|\n\n.. literalinclude:: samples/national-capitals.py\n\n|toggleEnd|\n\n\n-----\n\n\n.. _RecipesStories_I:\n\nHow to Create a Simple Grid Layout\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nBy creating a sequence of :ref:`Story` objects within a grid created via the :ref:`make_table<Functions_make_table>` function a developer can create grid layouts as required.\n\n**Files:**\n\n* `docs/samples/simple-grid.py`\n\n|toggleStart|\n\n.. literalinclude:: samples/simple-grid.py\n\n|toggleEnd|\n\n\n-----\n\n\n.. _RecipesStories_J:\n\nHow to Generate a Table of Contents\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis script lists the source code of all Python scripts that live in the script's directory.\n\n**Files:**\n\n* `docs/samples/code-printer.py`\n\n|toggleStart|\n\n.. literalinclude:: samples/code-printer.py\n\n|toggleEnd|\n\n\nIt features the following capabilities:\n\n* Automatic generation of a Table of Contents (TOC) on separately numbered pages at the start of the document - using a specialized :ref:`Story`.\n\n* Use of 3 separate :ref:`Story` objects per page: header story, footer story and the story for printing the Python sources.\n\n    - The page **footer is automatically changed** to show the name of the current Python file.\n\n* Use of :meth:`Story.element_positions` to collect the data for the TOC and for the dynamic adjustment of page footers. This is an example of a **bidirectional communication** between the story output process and the script.\n\n* The main PDF with the Python sources is being written to memory by its :ref:`DocumentWriter`. Another :ref:`Story` / :ref:`DocumentWriter` pair is then used to create a (memory) PDF for the TOC pages. Finally, both these PDFs are joined and the result stored to disk.\n\n\n-----\n\n\n.. _RecipesStories_K:\n\nHow to Display a List from JSON Data\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis example takes some JSON data input which it uses to populate a :ref:`Story`. It also contains some visual text formatting and shows how to add links.\n\n\n**Files:**\n\n* `docs/samples/json-example.py`\n\n|toggleStart|\n\n.. literalinclude:: samples/json-example.py\n\n|toggleEnd|\n\n\n\n-----\n\n\n.. _RecipesStories_L:\n\nUsing the Alternative :meth:`Story.write*()` functions\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThe :meth:`Story.write*()` functions provide a different way to use the\n:ref:`Story` functionality, removing the need for calling code to implement\na loop that calls :meth:`Story.place()` and :meth:`Story.draw()` etc, at the\nexpense of having to provide at least a `rectfn()` callback.\n\n\n.. _RecipesStories_L_a:\n\nHow to do Basic Layout with :meth:`Story.write()`\n-------------------------------------------------\n\nThis script lays out multiple copies of its own source code, into four\nrectangles per page.\n\n**Files:**\n\n* `docs/samples/story-write.py`\n\n|toggleStart|\n\n.. literalinclude:: samples/story-write.py\n\n|toggleEnd|\n\n\n-----\n\n\n.. _RecipesStories_L_b:\n\nHow to do Iterative Layout for a Table of Contents with :meth:`Story.write_stabilized()`\n----------------------------------------------------------------------------------------\n\nThis script creates html content dynamically, adding a contents section based\non :ref:`ElementPosition` items that have non-zero `.heading` values.\n\nThe contents section is at the start of the document, so modifications to the\ncontents can change page numbers in the rest of the document, which in turn can\ncause page numbers in the contents section to be incorrect.\n\nSo the script uses :meth:`Story.write_stabilized()` to repeatedly lay things\nout until things are stable.\n\n\n**Files:**\n\n* `docs/samples/story-write-stabilized.py`\n\n|toggleStart|\n\n.. literalinclude:: samples/story-write-stabilized.py\n\n|toggleEnd|\n\n\n\n-----\n\n.. _RecipesStories_L_c:\n\nHow to do Iterative Layout and Create PDF Links with :meth:`Story.write_stabilized_links()`\n-------------------------------------------------------------------------------------------\n\nThis script is similar to the one described in \"How to use\n:meth:`Story.write_stabilized()`\" above, except that the generated PDF also\ncontains links that correspond to the internal links in the original html.\n\nThis is done by using :meth:`Story.write_stabilized_links()`; this is slightly\ndifferent from :meth:`Story.write_stabilized()`:\n\n* It does not take a :ref:`DocumentWriter` `writer` arg.\n* It returns a PDF :ref:`Document` instance.\n\n[The reasons for this are a little involved; for example a\n:ref:`DocumentWriter` is not necessarily a PDF writer, so doesn't really work\nin a PDF-specific API.]\n\n\n**Files:**\n\n* `docs/samples/story-write-stabilized-links.py`\n\n|toggleStart|\n\n.. literalinclude:: samples/story-write-stabilized-links.py\n\n|toggleEnd|\n\n\n\n-----\n\n\n.. rubric:: Footnotes\n\n.. [#f1] HTML & CSS support\n\n    .. note::\n\n        At the time of writing the HTML engine for Stories is fairly basic and supports a subset of CSS2 attributes.\n\n    Some important CSS support to consider:\n\n    - The only available layout is relative layout.\n    - `background` is unavailable, use `background-color` instead.\n    - `float` is unavailable.\n\n\n.. include:: footer.rst\n\n.. External Links:\n\n.. _pymupdf-fonts: https://github.com/pymupdf/pymupdf-fonts\n\n\n\n"
  },
  {
    "path": "docs/recipes-text.rst",
    "content": ".. include:: header.rst\n\n.. _RecipesText:\n\n==============================\nText\n==============================\n\n\n.. _RecipesText_A:\n\nHow to Extract all Document Text\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis script will take a document filename and generate a text file from all of its text.\n\nThe document can be any :ref:`supported type<Supported_File_Types>`.\n\nThe script works as a command line tool which expects the document filename supplied as a parameter. It generates one text file named \"filename.txt\" in the script directory. Text of pages is separated by a form feed character::\n\n    import sys, pathlib, pymupdf\n    fname = sys.argv[1]  # get document filename\n    with pymupdf.open(fname) as doc:  # open document\n        text = chr(12).join([page.get_text() for page in doc])\n    # write as a binary file to support non-ASCII characters\n    pathlib.Path(fname + \".txt\").write_bytes(text.encode())\n\nThe output will be plain text as it is coded in the document. No effort is made to prettify in any way. Specifically for PDF, this may mean output not in usual reading order, unexpected line breaks and so forth.\n\nYou have many options to rectify this -- see chapter :ref:`Appendix2`. Among them are:\n\n1. Extract text in HTML format and store it as a HTML document, so it can be viewed in any browser.\n2. Extract text as a list of text blocks via *Page.get_text(\"blocks\")*. Each item of this list contains position information for its text, which can be used to establish a convenient reading order.\n3. Extract a list of single words via *Page.get_text(\"words\")*. Its items are words with position information. Use it to determine text contained in a given rectangle -- see next section.\n\nSee the following two sections for examples and further explanations.\n\n\n.. index::\n   triple: lookup;text;key-value\n\n\nHow to Extract Text as Markdown\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis is especially useful for :title:`RAG/LLM` environments - please see :ref:`Outputting as Markdown <rag_outputting_as_md>`.\n\n\n.. _RecipesText_A1:\n\nHow to Extract Key-Value Pairs from a Page\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nIf the layout of a page is *\"predictable\"* in some sense, then there is a simple way to find the values for a given set of keywords fast and easily -- without using regular expressions. Please see `this example script <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/text-extraction/lookup-keywords.py>`_.\n\n\"Predictable\" in this context means:\n\n* Every keyword is followed by its value -- no other text is present in between them.\n* The bottom of the value's boundary box is **not above** the one of the keyword.\n* There are **no other restrictions**: the page layout may or may not be fixed, and the text may also have been stored as one string. Key and value may have any distance from each other.\n\nFor example, the following five key-value pairs will be correctly identified::\n\n   key1               value1\n   key2\n   value2\n   key3\n          value3 blah, blah, blah key4 value4 some other text key5 value5 ...\n\n\n.. index::\n   triple: extract;text;rectangle\n\n\n.. _RecipesText_B:\n\nHow to Extract Text from within a Rectangle\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThere is now (v1.18.0) more than one way to achieve this. We therefore have created a `folder <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/textbox-extraction>`_ in the PyMuPDF-Utilities repository specifically dealing with this topic.\n\n----------\n\n.. index::\n    pair: text;reading order\n\n.. _RecipesText_C:\n\nHow to Extract Text in Natural Reading Order\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nOne of the common issues with PDF text extraction is, that text may not appear in any particular reading order.\n\nThis is the responsibility of the PDF creator (software or a human). For example, page headers may have been inserted in a separate step -- after the document had been produced. In such a case, the header text will appear at the end of a page text extraction (although it will be correctly shown by PDF viewer software). For example, the following snippet will add some header and footer lines to an existing PDF::\n\n    doc = pymupdf.open(\"some.pdf\")\n    header = \"Header\"  # text in header\n    for page in doc:\n        page.insert_text((50, 50), header)  # insert header\n        page.insert_text(  # insert footer 50 points above page bottom\n            (50, page.rect.height - 50),\n            f\"Page {page.number + 1} of {doc.page_count}\", # text in footer\n        )\n\nThe text sequence extracted from a page modified in this way will look like this:\n\n1. original text\n2. header line\n3. footer line\n\nPyMuPDF has several means to re-establish some reading sequence or even to re-generate a layout close to the original:\n\n1. Use `sort` parameter of :meth:`Page.get_text`. It will sort the output from top-left to bottom-right (ignored for XHTML, HTML and XML output).\n2. Use the `pymupdf` module in CLI: `python -m pymupdf gettext ...`, which produces a text file where text has been re-arranged in layout-preserving mode. Many options are available to control the output.\n\nYou can also use the above mentioned `script <https://github.com/pymupdf/PyMuPDF/wiki/How-to-extract-text-from-a-rectangle>`_ with your modifications.\n\n----------\n\n.. _RecipesText_D:\n\nHow to :index:`Extract Table Content <pair: extract; table>` from Documents\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nIf you see a table in a document, you are normally not looking at something like an embedded Excel or other identifiable object. It usually is just normal, standard text, formatted to appear as tabular data.\n\nExtracting tabular data from such a page area therefore means that you must find a way to **identify** the table area (i.e. its boundary box), then **(1)** graphically indicate table and column borders, and **(2)** then extract text based on this information.\n\nThis can be a very complex task, depending on details like the presence or absence of lines, rectangles or other supporting vector graphics.\n\nMethod :meth:`Page.find_tables` does all that for you, with a high table detection precision. Its great advantage is that there are no external library dependencies, nor the need to employ artificial intelligence or machine learning technologies. It also provides an integrated interface to the well-known Python package for data analysis `pandas <https://pypi.org/project/pandas/>`_.\n\nPlease have a look at example `Jupyter notebooks <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/table-analysis>`_, which cover standard situations like multiple tables on one page or joining table fragments across multiple pages.\n\n----------\n\n.. _RecipesText_E:\n\nHow to Mark Extracted Text\n~~~~~~~~~~~~~~~~~~~~~~~~~~\nThere is a standard search function to search for arbitrary text on a page: :meth:`Page.search_for`. It returns a list of :ref:`Rect` objects which surround a found occurrence. These rectangles can for example be used to automatically insert annotations which visibly mark the found text.\n\nThis method has advantages and drawbacks. Pros are:\n\n* The search string can contain blanks and wrap across lines\n* Upper or lower case characters are treated equal\n* Word hyphenation at line ends is detected and resolved\n* Return may also be a list of :ref:`Quad` objects to precisely locate text that is **not parallel** to either axis -- using :ref:`Quad` output is also recommended, when page rotation is not zero.\n\nBut you also have other options::\n\n import sys\n import pymupdf\n\n def mark_word(page, text):\n     \"\"\"Underline each word that contains 'text'.\n     \"\"\"\n     found = 0\n     wlist = page.get_text(\"words\", delimiters=None)  # make the word list\n     for w in wlist:  # scan through all words on page\n         if text in w[4]:  # w[4] is the word's string\n             found += 1  # count\n             r = pymupdf.Rect(w[:4])  # make rect from word bbox\n             page.add_underline_annot(r)  # underline\n     return found\n\n fname = sys.argv[1]  # filename\n text = sys.argv[2]  # search string\n doc = pymupdf.open(fname)\n\n print(f\"underlining words containing '{word}' in document '{doc.name}'\")\n\n new_doc = False  # indicator if anything found at all\n\n for page in doc:  # scan through the pages\n     found = mark_word(page, text)  # mark the page's words\n     if found:  # if anything found ...\n         new_doc = True\n         print(f\"found '{text}' {found} times on page {page.number + 1}\")\n\n if new_doc:\n     doc.save(\"marked-\" + doc.name)\n\nThis script uses `Page.get_text(\"words\")` to look for a string, handed in via cli parameter. This method separates a page's text into \"words\" using white spaces as delimiters. Further remarks:\n\n* If found, the **complete word containing the string** is marked (underlined) -- not only the search string.\n* The search string may **not contain word delimiters**. By default, word delimiters are white spaces and the non-breaking space `chr(0xA0)`. If you use extra delimiting characters like `page.get_text(\"words\", delimiters=\"./,\")` then none of these characters should be included in your search string either.\n* As shown here, upper / lower cases are **respected**. But this can be changed by using the string method *lower()* (or even regular expressions) in function *mark_word*.\n* There is **no upper limit**: all occurrences will be detected.\n* You can use **anything** to mark the word: 'Underline', 'Highlight', 'StrikeThrough' or 'Square' annotations, etc.\n* Here is an example snippet of a page of this manual, where \"MuPDF\" has been used as the search string. Note that all strings **containing \"MuPDF\"** have been completely underlined (not just the search string).\n\n.. image:: images/img-markedpdf.*\n   :scale: 60\n\n----------------------------------------------\n\n\n.. _RecipesText_F:\n\nHow to Mark Searched Text\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n.. codespell:ignore-begin\n\nThis script searches for text and marks it::\n\n    # -*- coding: utf-8 -*-\n    import pymupdf\n\n    # the document to annotate\n    doc = pymupdf.open(\"tilted-text.pdf\")\n\n    # the text to be marked\n    needle = \"¡La práctica hace el campeón!\"\n\n    # work with first page only\n    page = doc[0]\n\n    # get list of text locations\n    # we use \"quads\", not rectangles because text may be tilted!\n    rl = page.search_for(needle, quads=True)\n\n    # mark all found quads with one annotation\n    page.add_squiggly_annot(rl)\n\n    # save to a new PDF\n    doc.save(\"a-squiggly.pdf\")\n\n.. codespell:ignore-end\n\nThe result looks like this:\n\n.. image:: images/img-textmarker.*\n   :scale: 80\n\n----------------------------------------------\n\n\n.. _RecipesText_G:\n\nHow to Mark Non-horizontal Text\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nThe previous section already shows an example for marking non-horizontal text, that was detected by text **searching**.\n\nBut text **extraction** with the \"dict\" / \"rawdict\" options of :meth:`Page.get_text` may also return text with a non-zero angle to the x-axis. This is indicated by the value of the line dictionary's `\"dir\"` key: it is the tuple `(cosine, sine)` for that angle. If `line[\"dir\"] != (1, 0)`, then the text of all its spans is rotated by (the same) angle != 0.\n\nThe \"bboxes\" returned by the method however are rectangles only -- not quads. So, to mark span text correctly, its quad must be recovered from the data contained in the line and span dictionary. Do this with the following utility function (new in v1.18.9)::\n\n    span_quad = pymupdf.recover_quad(line[\"dir\"], span)\n    annot = page.add_highlight_annot(span_quad)  # this will mark the complete span text\n\nIf you want to **mark the complete line** or a subset of its spans in one go, use the following snippet (works for v1.18.10 or later)::\n\n    line_quad = pymupdf.recover_line_quad(line, spans=line[\"spans\"][1:-1])\n    page.add_highlight_annot(line_quad)\n\n.. image:: images/img-linequad.*\n\nThe `spans` argument above may specify any sub-list of `line[\"spans\"]`. In the example above, the second to second-to-last span are marked. If omitted, the complete line is taken.\n\n------------------------------\n\n.. _RecipesText_H:\n\nHow to Analyze Font Characteristics\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nTo analyze the characteristics of text in a PDF use this elementary script as a starting point:\n\n.. literalinclude:: samples/text-lister.py\n   :language: python\n\nHere is the PDF page and the script output:\n\n.. image:: images/img-pdftext.*\n   :scale: 80\n\n-----------------------------------------\n\n\n.. _RecipesText_I:\n\nHow to Insert Text\n~~~~~~~~~~~~~~~~~~~~\nPyMuPDF provides ways to insert text on new or existing PDF pages with the following features:\n\n* choose the font, including built-in fonts and fonts that are available as files\n* choose text characteristics like bold, italic, font size, font color, etc.\n* position the text in multiple ways:\n\n    - either as simple line-oriented output starting at a certain point,\n    - or fitting text in a box provided as a rectangle, in which case text alignment choices are also available,\n    - choose whether text should be put in foreground (overlay existing content),\n    - all text can be arbitrarily \"morphed\", i.e. its appearance can be changed via a :ref:`Matrix`, to achieve effects like scaling, shearing or mirroring,\n    - independently from morphing and in addition to that, text can be rotated by integer multiples of 90 degrees.\n\nAll of the above is provided by three basic :ref:`Page`, resp. :ref:`Shape` methods:\n\n* :meth:`Page.insert_font` -- install a font for the page for later reference. The result is reflected in the output of :meth:`Document.get_page_fonts`. The font can be:\n\n    - provided as a file,\n    - via :ref:`Font` (then use :attr:`Font.buffer`)\n    - already present somewhere in **this or another** PDF, or\n    - be a **built-in** font.\n\n* :meth:`Page.insert_text` -- write some lines of text. Internally, this uses :meth:`Shape.insert_text`.\n\n* :meth:`Page.insert_textbox` -- fit text in a given rectangle. Here you can choose text alignment features (left, right, centered, justified) and you keep control as to whether text actually fits. Internally, this uses :meth:`Shape.insert_textbox`.\n\n.. note:: Both text insertion methods automatically install the font as necessary.\n\n\n.. _RecipesText_I_a:\n\nHow to Write Text Lines\n^^^^^^^^^^^^^^^^^^^^^^^^^^\nOutput some text lines on a page::\n\n    import pymupdf\n    doc = pymupdf.open(...)  # new or existing PDF\n    page = doc.new_page()  # new or existing page via doc[n]\n    p = pymupdf.Point(50, 72)  # start point of 1st line\n\n    text = \"Some text,\\nspread across\\nseveral lines.\"\n    # the same result is achievable by\n    # text = [\"Some text\", \"spread across\", \"several lines.\"]\n\n    rc = page.insert_text(p,  # bottom-left of 1st char\n                         text,  # the text (honors '\\n')\n                         fontname = \"helv\",  # the default font\n                         fontsize = 11,  # the default font size\n                         rotate = 0,  # also available: 90, 180, 270\n                         )\n    print(f\"{rc} lines printed on page {page.number}.\")\n\n    doc.save(\"text.pdf\")\n\nWith this method, only the **number of lines** will be controlled to not go beyond page height. Surplus lines will not be written and the number of actual lines will be returned. The calculation uses a line height calculated from the :data:`fontsize` and 36 points (0.5 inches) as bottom margin.\n\nLine **width is ignored**. The surplus part of a line will simply be invisible.\n\nHowever, for built-in fonts there are ways to calculate the line width beforehand - see :meth:`get_text_length`.\n\nHere is another example. It inserts 4 text strings using the four different rotation options, and thereby explains, how the text insertion point must be chosen to achieve the desired result::\n\n    import pymupdf\n    doc = pymupdf.open()\n    page = doc.new_page()\n    # the text strings, each having 3 lines\n    text1 = \"rotate=0\\nLine 2\\nLine 3\"\n    text2 = \"rotate=90\\nLine 2\\nLine 3\"\n    text3 = \"rotate=-90\\nLine 2\\nLine 3\"\n    text4 = \"rotate=180\\nLine 2\\nLine 3\"\n    red = (1, 0, 0) # the color for the red dots\n    # the insertion points, each with a 25 pix distance from the corners\n    p1 = pymupdf.Point(25, 25)\n    p2 = pymupdf.Point(page.rect.width - 25, 25)\n    p3 = pymupdf.Point(25, page.rect.height - 25)\n    p4 = pymupdf.Point(page.rect.width - 25, page.rect.height - 25)\n    # create a Shape to draw on\n    shape = page.new_shape()\n\n    # draw the insertion points as red, filled dots\n    shape.draw_circle(p1,1)\n    shape.draw_circle(p2,1)\n    shape.draw_circle(p3,1)\n    shape.draw_circle(p4,1)\n    shape.finish(width=0.3, color=red, fill=red)\n\n    # insert the text strings\n    shape.insert_text(p1, text1)\n    shape.insert_text(p3, text2, rotate=90)\n    shape.insert_text(p2, text3, rotate=-90)\n    shape.insert_text(p4, text4, rotate=180)\n\n    # store our work to the page\n    shape.commit()\n    doc.save(...)\n\nThis is the result:\n\n.. image:: images/img-inserttext.*\n   :scale: 33\n\n\n\n------------------------------------------\n\n.. _RecipesText_I_b:\n\nHow to Fill a Text Box\n^^^^^^^^^^^^^^^^^^^^^^^^^^\nThis script fills 4 different rectangles with text, each time choosing a different rotation value::\n\n    import pymupdf\n\n    doc = pymupdf.open()  # new or existing PDF\n    page = doc.new_page()  # new page, or choose doc[n]\n\n    # write in this overall area\n    rect = pymupdf.Rect(100, 100, 300, 150)\n\n    # partition the area in 4 equal sub-rectangles\n    CELLS = pymupdf.make_table(rect, cols=4, rows=1)\n\n    t1 = \"text with rotate = 0.\"  # these texts we will written\n    t2 = \"text with rotate = 90.\"\n    t3 = \"text with rotate = 180.\"\n    t4 = \"text with rotate = 270.\"\n    text = [t1, t2, t3, t4]\n    red = pymupdf.pdfcolor[\"red\"]  # some colors\n    gold = pymupdf.pdfcolor[\"gold\"]\n    blue = pymupdf.pdfcolor[\"blue\"]\n    \"\"\"\n    We use a Shape object (something like a canvas) to output the text and\n    the rectangles surrounding it for demonstration.\n    \"\"\"\n    shape = page.new_shape()  # create Shape\n    for i in range(len(CELLS[0])):\n        shape.draw_rect(CELLS[0][i])  # draw rectangle\n        shape.insert_textbox(\n            CELLS[0][i], text[i], fontname=\"hebo\", color=blue, rotate=90 * i\n        )\n\n    shape.finish(width=0.3, color=red, fill=gold)\n\n    shape.commit()  # write all stuff to the page\n    doc.ez_save(__file__.replace(\".py\", \".pdf\"))\n\nSome default values were used above: font size 11 and text alignment \"left\". The result will look like this:\n\n.. image:: images/img-rotate.*\n   :scale: 50\n\n------------------------------------------\n\n.. _RecipesText_I_c:\n\nHow to Fill a Box with HTML Text\n^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\nMethod :meth:`Page.insert_htmlbox` offers a **much more powerful** way to insert text in a rectangle.\n\nInstead of simple, plain text, this method accepts HTML source, which may not only contain HTML tags but also styling instructions to influence things like font, font weight (bold) and style (italic), color and much more.\n\nIt is also possible to mix multiple fonts and languages, to output HTML tables and to insert images and URI links.\n\nFor even more styling flexibility, an additional CSS source may also be given.\n\nThe method is based on the :ref:`Story` class. Therefore, complex script systems like Devanagari, Nepali, Tamil and many are supported and written correctly thanks to using the HarfBuzz library - which provides this so-called **\"text shaping\"** feature.\n\nAny required fonts to output characters are automatically pulled in from the Google NOTO font library - as a fallback (when the -- optionally supplied -- user font(s) do not contain some glyphs).\n\nAs a small glimpse into the features offered here, we will output the following HTML-enriched text::\n\n    import pymupdf\n\n\n    rect = pymupdf.Rect(100, 100, 400, 300)\n\n    text = \"\"\"Lorem ipsum dolor sit amet, consectetur adipisici elit, sed\n        eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad\n        minim veniam, quis nostrud exercitation <b>ullamco <i>laboris</i></b> \n        nisi ut aliquid ex ea commodi consequat. Quis aute iure \n        <span style=\"color: #f00;\">reprehenderit</span> \n        in <span style=\"color: #0f0;font-weight:bold;\">voluptate</span> velit \n        esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat \n        cupiditat non proident, sunt in culpa qui \n        <a href=\"https://www.artifex.com\">officia</a> deserunt mollit anim id \n        est laborum.\"\"\"\n\n    doc = pymupdf.Document()\n\n    page = doc.new_page()\n    page.insert_htmlbox(rect, text, css=\"* {font-family: sans-serif;font-size:14px;}\")\n\n    doc.ez_save(__file__.replace(\".py\", \".pdf\"))\n\nPlease note how the \"css\" parameter is used to globally select the default \"sans-serif\" font and a font size of 14.\n\nThe result will look like this:\n\n.. image:: images/img-htmlbox1.*\n\nHow to output HTML tables and images\n.......................................\n\nHere is another example that outputs a table with this method. This time, we are including all the styling in the HTML source itself. Please also note, how it works to include an image - even within a table cell::\n\n    import pymupdf\n    import os\n\n    filedir = os.path.dirname(__file__)\n\n\n    text = \"\"\"\n    <style>\n    body {\n        font-family: sans-serif;\n    }\n\n    td,\n    th {\n        border: 1px solid blue;\n        border-right: none;\n        border-bottom: none;\n        padding: 5px;\n        text-align: center;\n    }\n\n    table {\n        border-right: 1px solid blue;\n        border-bottom: 1px solid blue;\n        border-spacing: 0;\n    }\n    </style>\n\n    <body>\n    <p><b>Some Colors</b></p>\n    <table>\n        <tr>\n        <th>Lime</th>\n        <th>Lemon</th>\n        <th>Image</th>\n        <th>Mauve</th>\n        </tr>\n        <tr>\n        <td>Green</td>\n        <td>Yellow</td>\n        <td><img src=\"img-cake.png\" width=50></td>\n        <td>Between<br>Gray and Purple</td>\n        </tr>\n    </table>\n    </body>\n    \"\"\"\n\n    doc = pymupdf.Document()\n\n    page = doc.new_page()\n    rect = page.rect + (36, 36, -36, -36)\n\n    # we must specify an Archive because of the image\n    page.insert_htmlbox(rect, text, archive=pymupdf.Archive(\".\"))\n\n    doc.ez_save(__file__.replace(\".py\", \".pdf\"))\n\n\n\nThe result will look like this:\n\n.. image:: images/img-htmlbox2.*\n\n\nHow to Output Languages of the World\n.......................................\n\nOur third example will demonstrate the automatic multi-language support. It includes automatic **text shaping** for complex scripting systems like Devanagari and right-to-left languages::\n\n    import pymupdf\n\n    greetings = (\n        \"Hello, World!\",  # english\n        \"Hallo, Welt!\",  # german\n        \"سلام دنیا!\",  # persian\n        \"வணக்கம், உலகம்!\",  # tamil\n        \"สวัสดีชาวโลก!\",  # thai\n        \"Привіт Світ!\",  # ucranian\n        \"שלום עולם!\",  # hebrew\n        \"ওহে বিশ্ব!\",  # bengali\n        \"你好世界！\",  # chinese\n        \"こんにちは世界！\",  # japanese\n        \"안녕하세요, 월드!\",  # korean\n        \"नमस्कार, विश्व !\",  # sanskrit\n        \"हैलो वर्ल्ड!\",  # hindi\n    )\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = (50, 50, 200, 500)\n\n    # join greetings into one text string\n    text = \" ... \".join([t for t in greetings])\n\n    # the output of the above is simple:\n    page.insert_htmlbox(rect, text)\n    doc.save(__file__.replace(\".py\", \".pdf\"))\n\nAnd this is the output:\n\n.. image:: images/img-htmlbox3.*\n\nHow to Specify your Own Fonts\n.................................\n\nDefine your font files in CSS syntax using the `@font-face` statement. You need a separate `@font-face` for every combination of font weight and font style (e.g. bold or italic) you want to be supported. The following example uses the famous MS Comic Sans font in its four variants regular, bold, italic and bold-italic.\n\nAs these four font files are located in the system's folder `C:/Windows/Fonts` the method needs an :ref:`Archive` definition that points to that folder::\n\n    \"\"\"\n    How to use your own fonts with method Page.insert_htmlbox().\n    \"\"\"\n    import pymupdf\n\n    # Example text\n    text = \"\"\"Lorem ipsum dolor sit amet, consectetur adipisici elit, sed\n        eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad\n        minim veniam, quis nostrud exercitation <b>ullamco <i>laboris</i></b> \n        nisi ut aliquid ex ea commodi consequat. Quis aute iure \n        <span style=\"color: red;\">reprehenderit</span> \n        in <span style=\"color: green;font-weight:bold;\">voluptate</span> velit \n        esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat \n        cupiditat non proident, sunt in culpa qui \n        <a href=\"https://www.artifex.com\">officia</a> deserunt mollit anim id \n        est laborum.\"\"\"\n\n    \"\"\"\n    We need an Archive object to show where font files are located.\n    We intend to use the font family \"MS Comic Sans\".\n    \"\"\"\n    arch = pymupdf.Archive(\"C:/Windows/Fonts\")\n\n    # These statements define which font file to use for regular, bold,\n    # italic and bold-italic text.\n    # We assign an arbitrary common font-family for all 4 font files.\n    # The Story algorithm will select the right file as required.\n    # We request to use \"comic\" throughout the text.\n    css = \"\"\"\n    @font-face {font-family: comic; src: url(comic.ttf);}\n    @font-face {font-family: comic; src: url(comicbd.ttf);font-weight: bold;}\n    @font-face {font-family: comic; src: url(comicz.ttf);font-weight: bold;font-style: italic;}\n    @font-face {font-family: comic; src: url(comici.ttf);font-style: italic;}\n    * {font-family: comic;}\n    \"\"\"\n\n    doc = pymupdf.Document()\n    page = doc.new_page(width=150, height=150)  # make small page\n\n    page.insert_htmlbox(page.rect, text, css=css, archive=arch)\n\n    doc.subset_fonts(verbose=True)  # build subset fonts to reduce file size\n    doc.ez_save(__file__.replace(\".py\", \".pdf\"))\n\n.. image:: images/img-htmlbox4.*\n\nHow to Request Text Alignment\n................................\n\nThis example combines multiple requirements:\n\n* Rotate the text by 90 degrees anti-clockwise.\n* Use a font from package `pymupdf-fonts <https://pypi.org/project/pymupdf-fonts/>`_. You will see that the respective CSS definitions are a lot easier in this case.\n* Align the text with the \"justify\" option.\n\n::\n\n    \"\"\"\n    How to use a pymupdf font with method Page.insert_htmlbox().\n    \"\"\"\n    import pymupdf\n\n    # Example text\n    text = \"\"\"Lorem ipsum dolor sit amet, consectetur adipisici elit, sed\n        eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad\n        minim veniam, quis nostrud exercitation <b>ullamco <i>laboris</i></b> \n        nisi ut aliquid ex ea commodi consequat. Quis aute iure \n        <span style=\"color: red;\">reprehenderit</span> \n        in <span style=\"color: green;font-weight:bold;\">voluptate</span> velit \n        esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat \n        cupiditat non proident, sunt in culpa qui \n        <a href=\"https://www.artifex.com\">officia</a> deserunt mollit anim id \n        est laborum.\"\"\"\n\n    \"\"\"\n    This is similar to font file support. However, we can use a convenience\n    function for creating required CSS definitions.\n    We still need an Archive for finding the font binaries.\n    \"\"\"\n    arch = pymupdf.Archive()\n\n    # We request to use \"myfont\" throughout the text.\n    css = pymupdf.css_for_pymupdf_font(\"ubuntu\", archive=arch, name=\"myfont\")\n    css += \"* {font-family: myfont;text-align: justify;}\"\n\n    doc = pymupdf.Document()\n\n    page = doc.new_page(width=150, height=150)\n\n    page.insert_htmlbox(page.rect, text, css=css, archive=arch, rotate=90)\n\n    doc.subset_fonts(verbose=True)\n    doc.ez_save(__file__.replace(\".py\", \".pdf\"))\n\n.. image:: images/img-htmlbox5.*\n\n\n|\n\n.. _RecipesText_J:\n\n\nHow to Extract Text with Color\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nIterate through your text blocks and find the spans of text you need for this information.\n\n::\n\n    for page in doc:\n        text_blocks = page.get_text(\"dict\", flags=pymupdf.TEXTFLAGS_TEXT)[\"blocks\"]\n        for block in text_blocks:\n            for line in block[\"lines\"]:\n                for span in line[\"spans\"]:\n                    text = span[\"text\"]\n                    color = pymupdf.sRGB_to_rgb(span[\"color\"])\n                    print(f\"Text: {text}, Color: {color}\")\n\n\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/recipes.rst",
    "content": ".. include:: header.rst\n\n.. title:: PyMuPDF: How to Guide\n\n\n.. _RecipesTOC:\n\n\n.. toctree::\n\n   how-to-open-a-file.rst\n\n----\n\n.. toctree::\n\n   converting-files.rst\n\n----\n\n.. toctree::\n\n   recipes-ocr.rst\n\n----\n\n.. toctree::\n\n   recipes-text.rst\n\n----\n\n.. toctree::\n\n   recipes-images.rst\n\n----\n\n.. toctree::\n\n   recipes-annotations.rst\n\n----\n\n.. toctree::\n\n   recipes-drawing-and-graphics.rst\n\n----\n\n.. toctree::\n\n   recipes-stories.rst\n\n----\n\n.. toctree::\n\n   recipes-journalling.rst\n\n----\n\n.. toctree::\n\n   recipes-multiprocessing.rst\n\n----\n\n\n.. toctree::\n\n   recipes-optional-content.rst\n\n----\n\n.. toctree::\n\n   recipes-low-level-interfaces.rst\n\n----\n\n.. toctree::\n\n   recipes-common-issues-and-their-solutions.rst\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/rect.rst",
    "content": ".. include:: header.rst\n\n.. _Rect:\n\n==========\nRect\n==========\n\n*Rect* represents a rectangle defined by four floating point numbers x0, y0, x1, y1. They are treated as being coordinates of two diagonally opposite points. The first two numbers are regarded as the \"top left\" corner P\\ :sub:`(x0,y0)` and P\\ :sub:`(x1,y1)` as the \"bottom right\" one. However, these two properties need not coincide with their intuitive meanings -- read on.\n\nThe following remarks are also valid for :ref:`IRect` objects:\n\n* A rectangle in the sense of (Py-) MuPDF **(and PDF)** always has **borders parallel to the x- resp. y-axis**. A general orthogonal tetragon **is not a rectangle** -- in contrast to the mathematical definition.\n* The constructing points can be (almost! -- see below) anywhere in the plane -- they need not even be different, and e.g. \"top left\" need not be the geometrical \"north-western\" point.\n* Units are in points, where 72 points is 1 inch.\n* For any given quadruple of numbers, the geometrically \"same\" rectangle can be defined in four different ways:\n   1. Rect(P\\ :sub:`(x0,y0)`, P\\ :sub:`(x1,y1)`\\ )\n   2. Rect(P\\ :sub:`(x1,y1)`, P\\ :sub:`(x0,y0)`\\ )\n   3. Rect(P\\ :sub:`(x0,y1)`, P\\ :sub:`(x1,y0)`\\ )\n   4. Rect(P\\ :sub:`(x1,y0)`, P\\ :sub:`(x0,y1)`\\ )\n\n**(Changed in v1.19.0)** Hence some classification:\n\n* A rectangle is called **valid** if `x0 <= x1` and `y0 <= y1` (i.e. the bottom right point is \"south-eastern\" to the top left one), otherwise **invalid**. Of the four alternatives above, **only the first** is valid. Please take into account, that in MuPDF's coordinate system, the y-axis is oriented from **top to bottom**. Invalid rectangles have been called infinite in earlier versions.\n\n* A rectangle is called **empty** if `x0 >= x1` or `y0 >= y1`. This implies, that **invalid rectangles are also always empty.** And `width` (resp. `height`) is **set to zero** if `x0 > x1` (resp. `y0 > y1`). In previous versions, a rectangle was empty only if one of width or height was zero.\n\n* Rectangle coordinates **cannot be outside** the number range from `FZ_MIN_INF_RECT = -2147483648` to `FZ_MAX_INF_RECT = 2147483520`. Both values have been chosen, because they are the smallest / largest 32bit integers that survive C float conversion roundtrips. In previous versions there was no limit for coordinate values.\n\n* There is **exactly one \"infinite\" rectangle**, defined by `x0 = y0 = FZ_MIN_INF_RECT` and `x1 = y1 = FZ_MAX_INF_RECT`. It contains every other rectangle. It is mainly used for technical purposes -- e.g. when a function call should ignore a formally required rectangle argument. This rectangle is not empty.\n\n* **Rectangles are (semi-) open:** The right and the bottom edges (including the resp. corners) are not considered part of the rectangle. This implies, that only the top-left corner `(x0, y0)` can ever belong to the rectangle - the other three corners never do. An empty rectangle contains no corners at all.\n\n   .. image:: images/img-rect-contains.*\n      :scale: 30\n      :align: center\n\n* Here is an overview of the changes.\n\n   ================= =================================== ==================================================\n   Notion            Versions < 1.19.0                   Versions 1.19.*\n   ================= =================================== ==================================================\n   empty             x0 = x1 or y0 = y1                  x0 >= x1 or y0 >= y1 -- includes invalid rects\n   valid             n/a                                 x0 <= x1 and y0 <= y1\n   infinite          all rects where x0 > x1 or y1 > y0  **exactly one infinite rect / irect!**\n   coordinate values all numbers                         `FZ_MIN_INF_RECT <= number <= FZ_MAX_INF_RECT`\n   borders, corners  are parts of the rectangle          right and bottom corners and edges **are outside**\n   ================= =================================== ==================================================\n\n* There are new top level functions defining infinite and standard empty rectangles and quads, see :meth:`INFINITE_RECT` and friends.\n\n\n============================= =======================================================\n**Methods / Attributes**      **Short Description**\n============================= =======================================================\n:meth:`Rect.contains`         checks containment of point_likes and rect_likes\n:meth:`Rect.get_area`         calculate rectangle area\n:meth:`Rect.include_point`    enlarge rectangle to also contain a point\n:meth:`Rect.include_rect`     enlarge rectangle to also contain another one\n:meth:`Rect.intersect`        common part with another rectangle\n:meth:`Rect.intersects`       checks for non-empty intersections\n:meth:`Rect.morph`            transform with a point and a matrix\n:meth:`Rect.torect`           the matrix that transforms to another rectangle\n:meth:`Rect.norm`             the Euclidean norm\n:meth:`Rect.normalize`        makes a rectangle valid\n:meth:`Rect.round`            create smallest :ref:`Irect` containing rectangle\n:meth:`Rect.transform`        transform rectangle with a matrix\n:attr:`Rect.bottom_left`      bottom left point, synonym *bl*\n:attr:`Rect.bottom_right`     bottom right point, synonym *br*\n:attr:`Rect.height`           rectangle height\n:attr:`Rect.irect`            equals result of method *round()*\n:attr:`Rect.is_empty`         whether rectangle is empty\n:attr:`Rect.is_valid`         whether rectangle is valid\n:attr:`Rect.is_infinite`      whether rectangle is infinite\n:attr:`Rect.top_left`         top left point, synonym *tl*\n:attr:`Rect.top_right`        top_right point, synonym *tr*\n:attr:`Rect.quad`             :ref:`Quad` made from rectangle corners\n:attr:`Rect.width`            rectangle width\n:attr:`Rect.x0`               left corners' x coordinate\n:attr:`Rect.x1`               right corners' x -coordinate\n:attr:`Rect.y0`               top corners' y coordinate\n:attr:`Rect.y1`               bottom corners' y coordinate\n============================= =======================================================\n\n**Class API**\n\n.. class:: Rect\n\n   .. method:: __init__(self)\n\n   .. method:: __init__(self, x0, y0, x1, y1)\n\n   .. method:: __init__(self, top_left, bottom_right)\n\n   .. method:: __init__(self, top_left, x1, y1)\n\n   .. method:: __init__(self, x0, y0, bottom_right)\n\n   .. method:: __init__(self, rect)\n\n   .. method:: __init__(self, sequence)\n\n      Overloaded constructors: *top_left*, *bottom_right* stand for :data:`point_like` objects, \"sequence\" is a Python sequence type of 4 numbers (see :ref:`SequenceTypes`), \"rect\" means another :data:`rect_like`, while the other parameters mean coordinates.\n\n      If \"rect\" is specified, the constructor creates a **new copy** of it.\n\n      Without parameters, the empty rectangle ``Rect(0.0, 0.0, 0.0, 0.0)`` is created.\n\n   .. method:: round()\n\n      Creates the smallest containing :ref:`IRect`. This is **not the same** as simply rounding the rectangle's edges: The top left corner is rounded upwards and to the left while the bottom right corner is rounded downwards and to the right.\n\n      >>> pymupdf.Rect(0.5, -0.01, 123.88, 455.123456).round()\n      IRect(0, -1, 124, 456)\n\n      1. If the rectangle is **empty**, the result is also empty.\n      2. **Possible paradox:** The result may be empty, **even if** the rectangle is **not** empty! In such cases, the result obviously does **not** contain the rectangle. This is because MuPDF's algorithm allows for a small tolerance (1e-3). Example:\n\n      >>> r = pymupdf.Rect(100, 100, 200, 100.001)\n      >>> r.is_empty  # rect is NOT empty\n      False\n      >>> r.round()  # but its irect IS empty!\n      pymupdf.IRect(100, 100, 200, 100)\n      >>> r.round().is_empty\n      True\n\n      :rtype: :ref:`IRect`\n\n   .. method:: transform(m)\n\n      Transforms the rectangle with a matrix and **replaces the original**. If the rectangle is empty or infinite, this is a no-operation.\n\n      :arg m: The matrix for the transformation.\n      :type m: :data:`matrix_like`\n\n      :rtype: ``Rect``\n      :returns: the smallest rectangle that contains the transformed original.\n\n   .. method:: intersect(r)\n\n      The intersection (common rectangular area, largest rectangle contained in both) of the current rectangle and *r* is calculated and **replaces the current** rectangle. If either rectangle is empty, the result is also empty. If *r* is infinite, this is a no-operation. If the rectangles are (mathematically) disjoint sets, then the result is invalid. If the result is valid but empty, then the rectangles touch each other in a corner or (part of) a side.\n\n      :arg r: Second rectangle\n      :type r: :data:`rect_like`\n\n   .. method:: include_rect(r)\n\n      The smallest rectangle containing the current one and ``r`` is calculated and **replaces the current** one. If either rectangle is infinite, the result is also infinite. If ``r`` is empty, the current rectangle remains unchanged. Else if the current rectangle is empty, it is replaced by ``r``.\n\n      :arg r: Second rectangle\n      :type r: :data:`rect_like`\n\n   .. method:: include_point(p)\n\n      The smallest rectangle containing the current one and :data:`point_like` ``p`` is calculated and **replaces the current** one. **The infinite rectangle remains unchanged.** To create the rectangle that wraps a sequence of points, start with :meth:`EMPTY_RECT` and successively include the members of the sequence.\n\n      :arg p: Point to include.\n      :type p: :data:`point_like`\n\n\n   .. method:: get_area([unit])\n\n      Calculate the area of the rectangle and, with no parameter, equals *abs(rect)*. Like an empty rectangle, the area of an infinite rectangle is also zero. So, at least one of *pymupdf.Rect(p1, p2)* and *pymupdf.Rect(p2, p1)* has a zero area.\n\n      :arg str unit: Specify required unit: respective squares of *px* (pixels, default), *in* (inches), *cm* (centimeters), or *mm* (millimeters).\n      :rtype: float\n\n   .. method:: contains(x)\n\n      Checks whether *x* is contained in the rectangle. It may be an *IRect*, *Rect*, *Point* or number. If *x* is an empty rectangle, this is always true. If the rectangle is empty this is always ``False`` for all non-empty rectangles and for all points. `x in rect` and `rect.contains(x)` are equivalent.\n\n      :arg x: the object to check.\n      :type x: :data:`rect_like` or :data:`point_like`.\n\n      :rtype: bool\n\n   .. method:: intersects(r)\n\n      Checks whether the rectangle and a :data:`rect_like` \"r\" contain a common non-empty :ref:`Rect`. This will always be ``False`` if either is infinite or empty.\n\n      :arg rect_like r: the rectangle to check.\n\n      :rtype: bool\n\n   .. method:: torect(rect)\n\n      * New in version 1.19.3\n      \n      Compute the matrix which transforms this rectangle to a given one.\n\n      :arg rect_like rect: the target rectangle. Must not be empty or infinite.\n      :rtype: :ref:`Matrix`\n      :returns: a matrix `mat` such that `self * mat = rect`. Can for example be used to transform between the page and the pixmap coordinates. See an example use here :ref:`RecipesImages_P`.\n\n   .. method:: morph(fixpoint, matrix)\n\n      * New in version 1.17.0\n      \n      Return a new quad after applying a matrix to the rectangle using the fixed point `fixpoint`.\n\n      :arg point_like fixpoint: the fixed point.\n      :arg matrix_like matrix: the matrix.\n      :returns: a new :ref:`Quad`. This a wrapper for the same-named quad method. If infinite, the infinite quad is returned.\n\n   .. method:: norm()\n\n      * New in version 1.16.0\n      \n      Return the Euclidean norm of the rectangle treated as a vector of four numbers.\n\n   .. method:: normalize()\n\n      **Replace** the rectangle with its valid version. This is done by shuffling the rectangle corners. After completion of this method, the bottom right corner will indeed be south-eastern to the top left one (but may still be empty).\n\n   .. attribute:: irect\n\n      Equals result of method *round()*.\n\n   .. attribute:: top_left\n\n   .. attribute:: tl\n\n      Equals *Point(x0, y0)*.\n\n      :type: :ref:`Point`\n\n   .. attribute:: top_right\n\n   .. attribute:: tr\n\n      Equals `Point(x1, y0)`.\n\n      :type: :ref:`Point`\n\n   .. attribute:: bottom_left\n\n   .. attribute:: bl\n\n      Equals `Point(x0, y1)`.\n\n      :type: :ref:`Point`\n\n   .. attribute:: bottom_right\n\n   .. attribute:: br\n\n      Equals `Point(x1, y1)`.\n\n      :type: :ref:`Point`\n\n   .. attribute:: quad\n\n      The quadrilateral `Quad(rect.tl, rect.tr, rect.bl, rect.br)`.\n\n      :type: :ref:`Quad`\n\n   .. attribute:: width\n\n      Width of the rectangle. Equals `max(x1 - x0, 0)`.\n\n      :rtype: float\n\n   .. attribute:: height\n\n      Height of the rectangle. Equals `max(y1 - y0, 0)`.\n\n      :rtype: float\n\n   .. attribute:: x0\n\n      X-coordinate of the left corners.\n\n      :type: float\n\n   .. attribute:: y0\n\n      Y-coordinate of the top corners.\n\n      :type: float\n\n   .. attribute:: x1\n\n      X-coordinate of the right corners.\n\n      :type: float\n\n   .. attribute:: y1\n\n      Y-coordinate of the bottom corners.\n\n      :type: float\n\n   .. attribute:: is_infinite\n\n      `True` if this is the infinite rectangle.\n\n      :type: bool\n\n   .. attribute:: is_empty\n\n      `True` if rectangle is empty.\n\n      :type: bool\n\n   .. attribute:: is_valid\n\n      `True` if rectangle is valid.\n\n      :type: bool\n\n.. note::\n\n   * This class adheres to the Python sequence protocol, so components can be accessed via their index, too. Also refer to :ref:`SequenceTypes`.\n   * Rectangles can be used with arithmetic operators -- see chapter :ref:`Algebra`.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/requirements.txt",
    "content": "rst2pdf\n\n# define sphinx versioning\nsphinx==8.1.3\nfuro\nreadthedocs-sphinx-search==0.3.2\nsphinx_copybutton\nsphinx-notfound-page\nsphinxcontrib-googleanalytics\n"
  },
  {
    "path": "docs/resources.rst",
    "content": "\n.. include:: header.rst\n\n\nResources\n=============\n\n**PyMuPDF Pro**\n--------------------\n\n\nFor **Office** file support `try PyMuPDF Pro <pymupdf-pro>`.\n\n\n|\n----\n\n\nFind out about **PyMuPDF Utilities**\n-------------------------------------------------\n\nThe :title:`GitHub` repository `PyMuPDF-Utilities <https://github.com/pymupdf/PyMuPDF-Utilities>`_ contains a full range of examples, demonstrations and use cases.\n\n|\n----\n\n\n.. _pdf2docx_conversion:\n\nDo you need |PDF| to **DOCX** conversion?\n--------------------------------------------------\n\nWe recommend the pdf2docx_ library which uses |PyMuPDF| and the **python-docx** library to provide simple document conversion from |PDF| to **DOCX** format.\n\n\n\n\n\n.. include:: footer.rst"
  },
  {
    "path": "docs/samples/annotations-freetext1.py",
    "content": "# -*- coding: utf-8 -*-\nimport pymupdf\n\n# some colors\nblue = (0, 0, 1)\ngreen = (0, 1, 0)\nred = (1, 0, 0)\ngold = (1, 1, 0)\n\n# a new PDF with 1 page\ndoc = pymupdf.open()\npage = doc.new_page()\n\n# 3 rectangles, same size, above each other\nr1 = pymupdf.Rect(100, 100, 200, 150)\nr2 = r1 + (0, 75, 0, 75)\nr3 = r2 + (0, 75, 0, 75)\n\n# the text, Latin alphabet\nt = \"¡Un pequeño texto para practicar!\"\n\n# add 3 annots, modify the last one somewhat\na1 = page.add_freetext_annot(r1, t, text_color=red)\na2 = page.add_freetext_annot(r2, t, fontname=\"Ti\", text_color=blue)\na3 = page.add_freetext_annot(r3, t, fontname=\"Co\", text_color=blue, rotate=90)\na3.set_border(width=0)\na3.update(fontsize=8, fill_color=gold)\n\n# save the PDF\ndoc.save(\"a-freetext.pdf\")\n"
  },
  {
    "path": "docs/samples/annotations-freetext2.py",
    "content": "import pymupdf\n\n\"\"\"Use rich text for FreeText annotations\"\"\"\n\n# define an overall styling\nds = \"\"\"font-size: 11pt; font-family: sans-serif;\"\"\"\n\n# some special characters\nbullet = chr(0x2610) + chr(0x2611) + chr(0x2612)\n\n# the annotation text with HTML and styling syntax\ntext = f\"\"\"<p style=\"text-align:justify;margin-top:-25px;\">\nPyMuPDF <span style=\"color: red;\">འདི་ ཡིག་ཆ་བཀྲམ་སྤེལ་གྱི་དོན་ལུ་ པའི་ཐོན་ཐུམ་སྒྲིལ་དྲག་ཤོས་དང་མགྱོགས་ཤོས་ཅིག་ཨིན།</span>\n<span style=\"color:blue;\">Here is some <b>bold</b> and <i>italic</i> text, followed by <b><i>bold-italic</i></b>. Text-based check boxes: {bullet}.</span>\n </p>\"\"\"\n\n# here are some colors\ngold = (1, 1, 0)\ngreen = (0, 1, 0)\n\n# new/empty PDF\ndoc = pymupdf.open()\n\n# make a page in ISO-A4 format\npage = doc.new_page()\n\n# text goes into this:\nrect = pymupdf.Rect(100, 100, 350, 200)\n\n# define some points for callout lines\np2 = rect.tr + (50, 30)\np3 = p2 + (0, 30)\n\n# define the annotation\nannot = page.add_freetext_annot(\n    rect,\n    text,\n    fill_color=gold,  # fill color\n    opacity=1,  # non-transparent\n    rotate=0,  # no rotation\n    border_width=1,  # border and callout line width\n    dashes=None,  # no dashing\n    richtext=True,  # this is rich text\n    style=ds,  # my styling default\n    callout=(p3, p2, rect.tr),  # define end, knee, start points\n    line_end=pymupdf.PDF_ANNOT_LE_OPEN_ARROW,  # symbol shown at p3\n    border_color=green,\n)\n\ndoc.save(__file__.replace(\".py\", \".pdf\"), pretty=True)\n"
  },
  {
    "path": "docs/samples/annotations-ink.py",
    "content": "import math\nimport pymupdf\n\n#------------------------------------------------------------------------------\n# preliminary stuff: create function value lists for sine and cosine\n#------------------------------------------------------------------------------\nw360 = math.pi * 2  # go through full circle\ndeg = w360 / 360  # 1 degree as radians\nrect = pymupdf.Rect(100,200, 300, 300)  # use this rectangle\nfirst_x = rect.x0  # x starts from left\nfirst_y = rect.y0 + rect.height / 2.  # rect middle means y = 0\nx_step = rect.width / 360  # rect width means 360 degrees\ny_scale = rect.height / 2.  # rect height means 2\nsin_points = []  # sine values go here\ncos_points = []  # cosine values go here\nfor x in range(362):  # now fill in the values\n    x_coord = x * x_step + first_x  # current x coordinate\n    y = -math.sin(x * deg)  # sine\n    p = (x_coord, y * y_scale + first_y)  # corresponding point\n    sin_points.append(p)  # append\n    y = -math.cos(x * deg)  # cosine\n    p = (x_coord, y * y_scale + first_y)  # corresponding point\n    cos_points.append(p)  # append\n\n#------------------------------------------------------------------------------\n# create the document with one page\n#------------------------------------------------------------------------------\ndoc = pymupdf.open()  # make new PDF\npage = doc.new_page()  # give it a page\n\n#------------------------------------------------------------------------------\n# add the Ink annotation, consisting of 2 curve segments\n#------------------------------------------------------------------------------\nannot = page.add_ink_annot((sin_points, cos_points))\n# let it look a little nicer\nannot.set_border(width=0.3, dashes=[1,])  # line thickness, some dashing\nannot.set_colors(stroke=(0,0,1))  # make the lines blue\nannot.update()  # update the appearance\n\npage.draw_rect(rect, width=0.3)  # only to demonstrate we did OK\n\ndoc.save(\"a-inktest.pdf\")\n"
  },
  {
    "path": "docs/samples/code-printer.py",
    "content": "\"\"\"\nDemo script PyMuPDF Story class\n-------------------------------\n\nRead the Python sources in the script directory and create a PDF of all their\nsource codes.\n\nThe following features are included as a specialty:\n1. HTML source for pymupdf.Story created via Python API exclusively\n2. Separate Story objects for page headers and footers\n3. Use of HTML \"id\" elements for identifying source start pages\n4. Generate a Table of Contents pointing to source file starts. This\n   - uses the new Stoy callback feature\n   - uses Story also for making the TOC page(s)\n\n\"\"\"\nimport io\nimport os\nimport time\n\nimport pymupdf\n\nTHISDIR = os.path.dirname(os.path.abspath(__file__))\nTOC = []  # this will contain the TOC list items\nCURRENT_ID = \"\"  # currently processed filename - stored by recorder func\nMEDIABOX = pymupdf.paper_rect(\"a4-l\")  # chosen page size\nWHERE = MEDIABOX + (36, 50, -36, -36)  # sub rectangle for source content\n# location of the header rectangle\nHDR_WHERE = (36, 5, MEDIABOX.width - 36, 40)\n# location of the footer rectangle\nFTR_WHERE = (36, MEDIABOX.height - 36, MEDIABOX.width - 36, MEDIABOX.height)\n\n\ndef recorder(elpos):\n    \"\"\"Callback function invoked during story.place().\n    This function generates / collects all TOC items and updates the value of\n    CURRENT_ID - which is used to update the footer line of each page.\n    \"\"\"\n    global TOC, CURRENT_ID\n    if not elpos.open_close & 1:  # only consider \"open\" items\n        return\n    level = elpos.heading\n    y0 = elpos.rect[1]  # top of written rectangle (use for TOC)\n    if level > 0:  # this is a header (h1 - h6)\n        pno = elpos.page + 1  # the page number\n        TOC.append(\n            (\n                level,\n                elpos.text,\n                elpos.page + 1,\n                y0,\n            )\n        )\n        return\n\n    CURRENT_ID = elpos.id if elpos.id else \"\"  # update for footer line\n    return\n\n\ndef header_story(text):\n    \"\"\"Make the page header\"\"\"\n    header = pymupdf.Story()\n    hdr_body = header.body\n    hdr_body.add_paragraph().set_properties(\n        align=pymupdf.TEXT_ALIGN_CENTER,\n        bgcolor=\"#eee\",\n        font=\"sans-serif\",\n        bold=True,\n        fontsize=12,\n        color=\"green\",\n    ).add_text(text)\n    return header\n\n\ndef footer_story(text):\n    \"\"\"Make the page footer\"\"\"\n    footer = pymupdf.Story()\n    ftr_body = footer.body\n    ftr_body.add_paragraph().set_properties(\n        bgcolor=\"#eee\",\n        align=pymupdf.TEXT_ALIGN_CENTER,\n        color=\"blue\",\n        fontsize=10,\n        font=\"sans-serif\",\n    ).add_text(text)\n    return footer\n\n\ndef code_printer(outfile):\n    \"\"\"Output the generated PDF to outfile.\"\"\"\n    global MAX_TITLE_LEN\n    where = +WHERE\n    writer = pymupdf.DocumentWriter(outfile, \"\")\n    print_time = time.strftime(\"%Y-%m-%d %H:%M:%S (%z)\")\n    thispath = os.path.abspath(os.curdir)\n    basename = os.path.basename(thispath)\n\n    story = pymupdf.Story()\n    body = story.body\n    body.set_properties(font=\"sans-serif\")\n\n    text = f\"Python sources in folder '{THISDIR}'\"\n\n    body.add_header(1).add_text(text)  # the only h1 item in the story\n\n    files = os.listdir(THISDIR)  # list / select Python files in our directory\n    i = 1\n    for code_file in files:\n        if not code_file.endswith(\".py\"):\n            continue\n\n        # read Python file source\n        fileinput = open(os.path.join(THISDIR, code_file), \"rb\")\n        text = fileinput.read().decode()\n        fileinput.close()\n\n        # make level 2 header\n        hdr = body.add_header(2)\n        if i > 1:\n            hdr.set_pagebreak_before()\n        hdr.add_text(f\"{i}. Listing of file '{code_file}'\")\n\n        # Write the file code\n        body.add_codeblock().set_bgcolor((240, 255, 210)).set_color(\"blue\").set_id(\n            code_file\n        ).set_fontsize(10).add_text(text)\n\n        # Indicate end of a source file\n        body.add_paragraph().set_align(pymupdf.TEXT_ALIGN_CENTER).add_text(\n            f\"---------- End of File '{code_file}' ----------\"\n        )\n        i += 1  # update file counter\n\n    i = 0\n    while True:\n        i += 1\n        device = writer.begin_page(MEDIABOX)\n        # create Story objects for header, footer and the rest.\n        header = header_story(f\"Python Files in '{THISDIR}'\")\n        hdr_ok, _ = header.place(HDR_WHERE)\n        if hdr_ok != 0:\n            raise ValueError(\"header does not fit\")\n        header.draw(device, None)\n\n        # --------------------------------------------------------------\n        # Write the file content.\n        # --------------------------------------------------------------\n        more, filled = story.place(where)\n        # Inform the callback function\n        # Args:\n        #   recorder: the Python function to call\n        #   {}: dictionary containing anything - we pass the page number\n        story.element_positions(recorder, {\"page\": i - 1})\n        story.draw(device, None)\n\n        # --------------------------------------------------------------\n        # Make / write page footer.\n        # We MUST have a paragraph b/o background color / alignment\n        # --------------------------------------------------------------\n        if CURRENT_ID:\n            text = f\"File '{CURRENT_ID}' printed at {print_time}{chr(160)*5}{'-'*10}{chr(160)*5}Page {i}\"\n        else:\n            text = f\"Printed at {print_time}{chr(160)*5}{'-'*10}{chr(160)*5}Page {i}\"\n        footer = footer_story(text)\n        # write the page footer\n        ftr_ok, _ = footer.place(FTR_WHERE)\n        if ftr_ok != 0:\n            raise ValueError(\"footer does not fit\")\n        footer.draw(device, None)\n\n        writer.end_page()\n        if more == 0:\n            break\n    writer.close()\n\n\nif __name__ == \"__main__\" or os.environ.get('PYTEST_CURRENT_TEST'):\n    fileptr1 = io.BytesIO()\n    t0 = time.perf_counter()\n    code_printer(fileptr1)  # make the PDF\n    t1 = time.perf_counter()\n    doc = pymupdf.open(\"pdf\", fileptr1)\n    old_count = doc.page_count\n    # -----------------------------------------------------------------------------\n    # Post-processing step to make / insert the toc\n    # This also works using pymupdf.Story:\n    # - make a new PDF in memory which contains pages with the TOC text\n    # - add these TOC pages to the end of the original file\n    # - search item text on the inserted pages and cover each with a PDF link\n    # - move the TOC pages to the front of the document\n    # -----------------------------------------------------------------------------\n    story = pymupdf.Story()\n    body = story.body\n    body.add_header(1).set_font(\"sans-serif\").add_text(\"Table of Contents\")\n    # prefix TOC with an entry pointing to this page\n    TOC.insert(0, [1, \"Table of Contents\", old_count + 1, 36])\n\n    for item in TOC[1:]:  # write the file name headers as TOC lines\n        body.add_paragraph().set_font(\"sans-serif\").add_text(\n            item[1] + f\" - ({item[2]})\"\n        )\n    fileptr2 = io.BytesIO()  # put TOC pages to a separate PDF initially\n    writer = pymupdf.DocumentWriter(fileptr2)\n    i = 1\n    more = 1\n    while more:\n        device = writer.begin_page(MEDIABOX)\n        header = header_story(f\"Python Files in '{THISDIR}'\")\n        # write the page header\n        hdr_ok, _ = header.place(HDR_WHERE)\n        header.draw(device, None)\n\n        more, filled = story.place(WHERE)\n        story.draw(device, None)\n\n        footer = footer_story(f\"TOC-{i}\")  # separate page numbering scheme\n        # write the page footer\n        ftr_ok, _ = footer.place(FTR_WHERE)\n        footer.draw(device, None)\n        writer.end_page()\n        i += 1\n\n    writer.close()\n    doc2 = pymupdf.open(\"pdf\", fileptr2)  # open TOC pages as another PDF\n    doc.insert_pdf(doc2)  # and append to the main PDF\n    new_range = range(old_count, doc.page_count)  # the TOC page numbers\n    pages = [doc[i] for i in new_range]  # these are the TOC pages within main PDF\n    for item in TOC:  # search for TOC item text to get its rectangle\n        for page in pages:\n            rl = page.search_for(item[1], flags=pymupdf.TEXTFLAGS_SEARCH)\n            if rl != []:  # this text must be on next page\n                break\n        else:\n            assert 0, f'Cannot find {item[1]=} in {len(pages)=}.'\n        rect = rl[0]  # rectangle of TOC item text\n        link = {  # make a link from it\n            \"kind\": pymupdf.LINK_GOTO,\n            \"from\": rect,\n            \"to\": pymupdf.Point(0, item[3]),\n            \"page\": item[2] - 1,\n        }\n        page.insert_link(link)\n\n    # insert the TOC in the main PDF\n    doc.set_toc(TOC)\n    # move all the TOC pages to the desired place (1st page here)\n    for i in new_range:\n        doc.move_page(doc.page_count - 1, 0)\n    doc.ez_save(__file__.replace(\".py\", \".pdf\"))\n"
  },
  {
    "path": "docs/samples/filmfestival-sql.py",
    "content": "\"\"\"\nThis is a demo script for using PyMuPDF with its \"Story\" feature.\n\nThe following aspects are being covered here:\n\n* The script produces a report of films that are stored in an SQL database\n* The report format is provided as a HTML template\n\nThe SQL database contains two tables:\n1. Table \"films\" which has the columns \"title\" (film title, str), \"director\"\n   (str) and \"year\" (year of release, int).\n2. Table \"actors\" which has the columns \"name\" (actor name, str) and \"title\"\n   (the film title where the actor had been casted, str).\n\nThe script reads all content of the \"films\" table. For each film title it\nreads all rows from table \"actors\" which took part in that film.\n\nComment 1\n---------\nTo keep things easy and free from pesky technical detail, the relevant file\nnames inherit the name of this script:\n- the database's filename is the script name with \".py\" extension replaced\n  by \".db\".\n- the output PDF similarly has script file name with extension \".pdf\".\n\nComment 2\n---------\nThe SQLITE database has been created using https://sqlitebrowser.org/, a free\nmulti-platform tool to maintain or manipulate SQLITE databases.\n\"\"\"\nimport os\nimport sqlite3\n\nimport pymupdf\n\n# ----------------------------------------------------------------------\n# HTML template for the film report\n# There are four placeholders coded as \"id\" attributes.\n# One \"id\" allows locating the template part itself, the other three\n# indicate where database text should be inserted.\n# ----------------------------------------------------------------------\nfestival_template = (\n    \"<html><head><title>Just some arbitrary text</title></head>\"\n    '<body><h1 style=\"text-align:center\">Hook Norton Film Festival</h1>'\n    \"<ol>\"\n    '<li id=\"filmtemplate\">'\n    '<b id=\"filmtitle\"></b>'\n    \"<dl>\"\n    '<dt>Director<dd id=\"director\">'\n    '<dt>Release Year<dd id=\"filmyear\">'\n    '<dt>Cast<dd id=\"cast\">'\n    \"</dl>\"\n    \"</li>\"\n    \"</ol>\"\n    \"</body></html\"\n)\n\n# -------------------------------------------------------------------\n# define database access\n# -------------------------------------------------------------------\ndbfilename = __file__.replace(\".py\", \".db\")  # the SQLITE database file name\nassert os.path.isfile(dbfilename), f'{dbfilename}'\ndatabase = sqlite3.connect(dbfilename)  # open database\ncursor_films = database.cursor()  # cursor for selecting the films\ncursor_casts = database.cursor()  # cursor for selecting actors per film\n\n# select statement for the films - let SQL also sort it for us\nselect_films = \"\"\"SELECT title, director, year FROM films ORDER BY title\"\"\"\n\n# select stament for actors, a skeleton: sub-select by film title\nselect_casts = \"\"\"SELECT name FROM actors WHERE film = ? ORDER BY name\"\"\"\n# -------------------------------------------------------------------\n# define the HTML Story and fill it with database data\n# -------------------------------------------------------------------\nstory = pymupdf.Story(festival_template)\nbody = story.body  # access the HTML body detail\ntemplate = body.find(None, \"id\", \"filmtemplate\")  # find the template part\n\n# read the films from the database and put them all in one Python list\n# NOTE: instead we might fetch rows one by one (advisable for large volumes)\ncursor_films.execute(select_films)  # execute cursor, and ...\nfilms = cursor_films.fetchall()  # read out what was found\n\nfor title, director, year in films:  # iterate through the films\n    film = template.clone()  # clone template to report each film\n    film.find(None, \"id\", \"filmtitle\").add_text(title)  # put title in templ\n    film.find(None, \"id\", \"director\").add_text(director)  # put director\n    film.find(None, \"id\", \"filmyear\").add_text(str(year))  # put year\n\n    # the actors reside in their own table - find the ones for this film title\n    cursor_casts.execute(select_casts, (title,))  # execute cursor\n    casts = cursor_casts.fetchall()  # read actors for the film\n    # each actor name appears in its own tuple, so extract it from there\n    film.find(None, \"id\", \"cast\").add_text(\"\\n\".join([c[0] for c in casts]))\n    body.append_child(film)\n\ntemplate.remove()  # remove the template\n\n# -------------------------------------------------------------------\n# generate the PDF\n# -------------------------------------------------------------------\nwriter = pymupdf.DocumentWriter(__file__.replace(\".py\", \".pdf\"), \"compress\")\nmediabox = pymupdf.paper_rect(\"a4\")  # use pages in ISO-A4 format\nwhere = mediabox + (72, 36, -36, -72)  # leave page borders\n\nmore = 1  # end of output indicator\n\nwhile more:\n    dev = writer.begin_page(mediabox)  # make a new page\n    more, filled = story.place(where)  # arrange content for this page\n    story.draw(dev, None)  # write content to page\n    writer.end_page()  # finish the page\n\nwriter.close()  # close the PDF\n"
  },
  {
    "path": "docs/samples/json-example.py",
    "content": "import pymupdf\nimport json\n\nmy_json =  \"\"\"\n[\n    {\n         \"name\" :           \"Five-storied Pagoda\",\n         \"temple\" :         \"Rurikō-ji\",\n         \"founded\" :        \"middle Muromachi period, 1442\",\n         \"region\" :         \"Yamaguchi, Yamaguchi\",\n         \"position\" :       \"34.190181,131.472917\"\n     },\n     {\n         \"name\" :           \"Founder's Hall\",\n         \"temple\" :         \"Eihō-ji\",\n         \"founded\" :        \"early Muromachi period\",\n         \"region\" :         \"Tajimi, Gifu\",\n         \"position\" :       \"35.346144,137.129189\"\n     },\n     {\n         \"name\" :           \"Fudōdō\",\n         \"temple\" :         \"Kongōbu-ji\",\n         \"founded\" :        \"early Kamakura period\",\n         \"region\" :         \"Kōya, Wakayama\",\n         \"position\" :       \"34.213103,135.580397\"\n     },\n     {\n         \"name\" :           \"Goeidō\",\n         \"temple\" :         \"Nishi Honganji\",\n         \"founded\" :        \"Edo period, 1636\",\n         \"region\" :         \"Kyoto\",\n         \"position\" :       \"34.991394,135.751689\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Murō-ji\",\n         \"founded\" :        \"early Heian period\",\n         \"region\" :         \"Uda, Nara\",\n         \"position\" :       \"34.536586819357986,136.0395548452301\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Fudō-in\",\n         \"founded\" :        \"late Muromachi period, 1540\",\n         \"region\" :         \"Hiroshima\",\n         \"position\" :       \"34.427014,132.471117\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Ninna-ji\",\n         \"founded\" :        \"Momoyama period, 1613\",\n         \"region\" :         \"Kyoto\",\n         \"position\" :       \"35.031078,135.713811\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Mii-dera\",\n         \"founded\" :        \"Momoyama period, 1599\",\n         \"region\" :         \"Ōtsu, Shiga\",\n         \"position\" :       \"35.013403,135.852861\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Tōshōdai-ji\",\n         \"founded\" :        \"Nara period, 8th century\",\n         \"region\" :         \"Nara, Nara\",\n         \"position\" :       \"34.675619,135.784842\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Tō-ji\",\n         \"founded\" :        \"Momoyama period, 1603\",\n         \"region\" :         \"Kyoto\",\n         \"position\" :       \"34.980367,135.747686\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Tōdai-ji\",\n         \"founded\" :        \"middle Edo period, 1705\",\n         \"region\" :         \"Nara, Nara\",\n         \"position\" :       \"34.688992,135.839822\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Hōryū-ji\",\n         \"founded\" :        \"Asuka period, by 693\",\n         \"region\" :         \"Ikaruga, Nara\",\n         \"position\" :       \"34.614317,135.734458\"\n     },\n     {\n         \"name\" :           \"Golden Hall\",\n         \"temple\" :         \"Daigo-ji\",\n         \"founded\" :        \"late Heian period\",\n         \"region\" :         \"Kyoto\",\n         \"position\" :       \"34.951481,135.821747\"\n     },\n     {\n         \"name\" :           \"Keigū-in Main Hall\",\n         \"temple\" :         \"Kōryū-ji\",\n         \"founded\" :        \"early Kamakura period, before 1251\",\n         \"region\" :         \"Kyoto\",\n         \"position\" :       \"35.015028,135.705425\"\n     },\n     {\n         \"name\" :           \"Konpon-chūdō\",\n         \"temple\" :         \"Enryaku-ji\",\n         \"founded\" :        \"early Edo period, 1640\",\n         \"region\" :         \"Ōtsu, Shiga\",\n         \"position\" :       \"35.070456,135.840942\"\n     },\n     {\n         \"name\" :           \"Korō\",\n         \"temple\" :         \"Tōshōdai-ji\",\n         \"founded\" :        \"early Kamakura period, 1240\",\n         \"region\" :         \"Nara, Nara\",\n         \"position\" :       \"34.675847,135.785069\"\n     },\n     {\n         \"name\" :           \"Kōfūzō\",\n         \"temple\" :         \"Hōryū-ji\",\n         \"founded\" :        \"early Heian period\",\n         \"region\" :         \"Ikaruga, Nara\",\n         \"position\" :       \"34.614439,135.735428\"\n     },\n     {\n         \"name\" :           \"Large Lecture Hall\",\n         \"temple\" :         \"Hōryū-ji\",\n         \"founded\" :        \"middle Heian period, 990\",\n         \"region\" :         \"Ikaruga, Nara\",\n         \"position\" :       \"34.614783,135.734175\"\n     },\n     {\n         \"name\" :           \"Lecture Hall\",\n         \"temple\" :         \"Zuiryū-ji\",\n         \"founded\" :        \"early Edo period, 1655\",\n         \"region\" :         \"Takaoka, Toyama\",\n         \"position\" :       \"36.735689,137.010019\"\n     },\n     {\n         \"name\" :           \"Lecture Hall\",\n         \"temple\" :         \"Tōshōdai-ji\",\n         \"founded\" :        \"Nara period, 763\",\n         \"region\" :         \"Nara, Nara\",\n         \"position\" :       \"34.675933,135.784842\"\n     },\n     {\n         \"name\" :           \"Lotus Flower Gate\",\n         \"temple\" :         \"Tō-ji\",\n         \"founded\" :        \"early Kamakura period\",\n         \"region\" :         \"Kyoto\",\n         \"position\" :       \"34.980678,135.746314\"\n     },\n     {\n         \"name\" :           \"Main Hall\",\n         \"temple\" :         \"Akishinodera\",\n         \"founded\" :        \"early Kamakura period\",\n         \"region\" :         \"Nara, Nara\",\n         \"position\" :       \"34.703769,135.776189\"\n     }\n]\n\n\"\"\"\n\n# the result is a Python dictionary:\nmy_dict = json.loads(my_json)\n\nMEDIABOX = pymupdf.paper_rect(\"letter\")  # output page format: Letter\nWHERE = MEDIABOX + (36, 36, -36, -36)\nwriter = pymupdf.DocumentWriter(\"json-example.pdf\")  # create the writer\n\nstory = pymupdf.Story()\nbody = story.body\n\nfor i, entry in enumerate(my_dict):\n\n    for attribute, value in entry.items():\n        para = body.add_paragraph()\n\n        if attribute == \"position\":\n            para.set_fontsize(10)\n            para.add_link(f\"www.google.com/maps/@{value},14z\")\n        else:\n            para.add_span()\n            para.set_color(\"#990000\")\n            para.set_fontsize(14)\n            para.set_bold()\n            para.add_text(f\"{attribute} \")\n            para.add_span()\n            para.set_fontsize(18)\n            para.add_text(f\"{value}\")\n\n    body.add_horizontal_line()\n\n# This while condition will check a value from the Story `place` method\n# for whether all content for the story has been written (0), otherwise\n# more content is waiting to be written (1)\nmore = 1\nwhile more:\n    device = writer.begin_page(MEDIABOX)  # make new page\n    more, _ = story.place(WHERE)\n    story.draw(device)\n    writer.end_page()  # finish page\n\nwriter.close()  # close output file\n\ndel story\n"
  },
  {
    "path": "docs/samples/multiprocess-gui.py",
    "content": "\"\"\"\nCreated on 2019-05-01\n\n@author: yinkaisheng@live.com\n@copyright: 2019 yinkaisheng@live.com\n@license: GNU AFFERO GPL 3.0\n\nDemonstrate the use of multiprocessing with PyMuPDF\n-----------------------------------------------------\nThis example shows some more advanced use of multiprocessing.\nThe main process show a Qt GUI and establishes a 2-way communication with\nanother process, which accesses a supported document.\n\"\"\"\nimport os\nimport sys\nimport time\nimport multiprocessing as mp\nimport queue\nimport pymupdf\n\n''' PyQt and PySide namespace unifier shim\n    https://www.pythonguis.com/faq/pyqt6-vs-pyside6/\n    simple \"if 'PyQt6' in sys.modules:\" test fails for me, so the more complex pkgutil use\n    overkill for most people who might have one or the other, why both?\n'''\n\nfrom pkgutil import iter_modules\n\ndef module_exists(module_name):\n    return module_name in (name for loader, name, ispkg in iter_modules())\n\nif  module_exists(\"PyQt6\"):\n    # PyQt6\n    from PyQt6 import QtGui, QtWidgets, QtCore\n    from PyQt6.QtCore import pyqtSignal as Signal, pyqtSlot as Slot\n    wrapper = \"PyQt6\"\n\nelif module_exists(\"PySide6\"):\n    # PySide6\n    from PySide6 import QtGui, QtWidgets, QtCore\n    from PySide6.QtCore import Signal, Slot\n    wrapper = \"PySide6\"\n\n\nmy_timer = time.clock if str is bytes else time.perf_counter\n\n\nclass DocForm(QtWidgets.QWidget):\n    def __init__(self):\n        super().__init__()\n        self.process = None\n        self.queNum = mp.Queue()\n        self.queDoc = mp.Queue()\n        self.page_count = 0\n        self.curPageNum = 0\n        self.lastDir = \"\"\n        self.timerSend = QtCore.QTimer(self)\n        self.timerSend.timeout.connect(self.onTimerSendPageNum)\n        self.timerGet = QtCore.QTimer(self)\n        self.timerGet.timeout.connect(self.onTimerGetPage)\n        self.timerWaiting = QtCore.QTimer(self)\n        self.timerWaiting.timeout.connect(self.onTimerWaiting)\n        self.initUI()\n\n    def initUI(self):\n        vbox = QtWidgets.QVBoxLayout()\n        self.setLayout(vbox)\n\n        hbox = QtWidgets.QHBoxLayout()\n        self.btnOpen = QtWidgets.QPushButton(\"OpenDocument\", self)\n        self.btnOpen.clicked.connect(self.openDoc)\n        hbox.addWidget(self.btnOpen)\n\n        self.btnPlay = QtWidgets.QPushButton(\"PlayDocument\", self)\n        self.btnPlay.clicked.connect(self.playDoc)\n        hbox.addWidget(self.btnPlay)\n\n        self.btnStop = QtWidgets.QPushButton(\"Stop\", self)\n        self.btnStop.clicked.connect(self.stopPlay)\n        hbox.addWidget(self.btnStop)\n\n        self.label = QtWidgets.QLabel(\"0/0\", self)\n        self.label.setFont(QtGui.QFont(\"Verdana\", 20))\n        hbox.addWidget(self.label)\n\n        vbox.addLayout(hbox)\n\n        self.labelImg = QtWidgets.QLabel(\"Document\", self)\n        sizePolicy = QtWidgets.QSizePolicy(\n            QtWidgets.QSizePolicy.Policy.Preferred, QtWidgets.QSizePolicy.Policy.Expanding\n        )\n        self.labelImg.setSizePolicy(sizePolicy)\n        vbox.addWidget(self.labelImg)\n\n        self.setGeometry(100, 100, 400, 600)\n        self.setWindowTitle(\"PyMuPDF Document Player\")\n        self.show()\n\n    def openDoc(self):\n        path, _ = QtWidgets.QFileDialog.getOpenFileName(\n            self,\n            \"Open Document\",\n            self.lastDir,\n            \"All Supported Files (*.pdf;*.epub;*.xps;*.oxps;*.cbz;*.fb2);;PDF Files (*.pdf);;EPUB Files (*.epub);;XPS Files (*.xps);;OpenXPS Files (*.oxps);;CBZ Files (*.cbz);;FB2 Files (*.fb2)\",\n            #options=QtWidgets.QFileDialog.Options(),\n        )\n        if path:\n            self.lastDir, self.file = os.path.split(path)\n            if self.process:\n                self.queNum.put(-1)  # use -1 to notify the process to exit\n            self.timerSend.stop()\n            self.curPageNum = 0\n            self.page_count = 0\n            self.process = mp.Process(\n                target=openDocInProcess, args=(path, self.queNum, self.queDoc)\n            )\n            self.process.start()\n            self.timerGet.start(40)\n            self.label.setText(\"0/0\")\n            self.queNum.put(0)\n            self.startTime = time.perf_counter()\n            self.timerWaiting.start(40)\n\n    def playDoc(self):\n        self.timerSend.start(500)\n\n    def stopPlay(self):\n        self.timerSend.stop()\n\n    def onTimerSendPageNum(self):\n        if self.curPageNum < self.page_count - 1:\n            self.queNum.put(self.curPageNum + 1)\n        else:\n            self.timerSend.stop()\n\n    def onTimerGetPage(self):\n        try:\n            ret = self.queDoc.get(False)\n            if isinstance(ret, int):\n                self.timerWaiting.stop()\n                self.page_count = ret\n                self.label.setText(\"{}/{}\".format(self.curPageNum + 1, self.page_count))\n            else:  # tuple, pixmap info\n                num, samples, width, height, stride, alpha = ret\n                self.curPageNum = num\n                self.label.setText(\"{}/{}\".format(self.curPageNum + 1, self.page_count))\n                fmt = (\n                    QtGui.QImage.Format.Format_RGBA8888\n                    if alpha\n                    else QtGui.QImage.Format.Format_RGB888\n                )\n                qimg = QtGui.QImage(samples, width, height, stride, fmt)\n                self.labelImg.setPixmap(QtGui.QPixmap.fromImage(qimg))\n        except queue.Empty as ex:\n            pass\n\n    def onTimerWaiting(self):\n        self.labelImg.setText(\n            'Loading \"{}\", {:.2f}s'.format(\n                self.file, time.perf_counter() - self.startTime\n            )\n        )\n\n    def closeEvent(self, event):\n        self.queNum.put(-1)\n        event.accept()\n\n\ndef openDocInProcess(path, queNum, quePageInfo):\n    start = my_timer()\n    doc = pymupdf.open(path)\n    end = my_timer()\n    quePageInfo.put(doc.page_count)\n    while True:\n        num = queNum.get()\n        if num < 0:\n            break\n        page = doc.load_page(num)\n        pix = page.get_pixmap()\n        quePageInfo.put(\n            (num, pix.samples, pix.width, pix.height, pix.stride, pix.alpha)\n        )\n    doc.close()\n    print(\"process exit\")\n\n\nif __name__ == \"__main__\":\n    app = QtWidgets.QApplication(sys.argv)\n    form = DocForm()\n    sys.exit(app.exec())\n"
  },
  {
    "path": "docs/samples/multiprocess-render.py",
    "content": "\"\"\"\nDemonstrate the use of multiprocessing with PyMuPDF.\n\nDepending on the  number of CPUs, the document is divided in page ranges.\nEach range is then worked on by one process.\nThe type of work would typically be text extraction or page rendering. Each\nprocess must know where to put its results, because this processing pattern\ndoes not include inter-process communication or data sharing.\n\nCompared to sequential processing, speed improvements in range of 100% (ie.\ntwice as fast) or better can be expected.\n\"\"\"\nfrom __future__ import print_function, division\nimport sys\nimport os\nimport time\nfrom multiprocessing import Pool, cpu_count\nimport pymupdf\n\n# choose a version specific timer function (bytes == str in Python 2)\nmytime = time.clock if str is bytes else time.perf_counter\n\n\ndef render_page(vector):\n    \"\"\"Render a page range of a document.\n\n    Notes:\n        The PyMuPDF document cannot be part of the argument, because that\n        cannot be pickled. So we are being passed in just its filename.\n        This is no performance issue, because we are a separate process and\n        need to open the document anyway.\n        Any page-specific function can be processed here - rendering is just\n        an example - text extraction might be another.\n        The work must however be self-contained: no inter-process communication\n        or synchronization is possible with this design.\n        Care must also be taken with which parameters are contained in the\n        argument, because it will be passed in via pickling by the Pool class.\n        So any large objects will increase the overall duration.\n    Args:\n        vector: a list containing required parameters.\n    \"\"\"\n    # recreate the arguments\n    idx = vector[0]  # this is the segment number we have to process\n    cpu = vector[1]  # number of CPUs\n    filename = vector[2]  # document filename\n    mat = vector[3]  # the matrix for rendering\n    doc = pymupdf.open(filename)  # open the document\n    num_pages = doc.page_count  # get number of pages\n\n    # pages per segment: make sure that cpu * seg_size >= num_pages!\n    seg_size = int(num_pages / cpu + 1)\n    seg_from = idx * seg_size  # our first page number\n    seg_to = min(seg_from + seg_size, num_pages)  # last page number\n\n    for i in range(seg_from, seg_to):  # work through our page segment\n        page = doc[i]\n        # page.get_text(\"rawdict\")  # use any page-related type of work here, eg\n        pix = page.get_pixmap(alpha=False, matrix=mat)\n        # store away the result somewhere ...\n        # pix.save(\"p-%i.png\" % i)\n    print(f\"Processed page numbers {seg_from} through {seg_to - 1}\")\n\n\nif __name__ == \"__main__\":\n    t0 = mytime()  # start a timer\n    filename = sys.argv[1]\n    mat = pymupdf.Matrix(0.2, 0.2)  # the rendering matrix: scale down to 20%\n    cpu = cpu_count()\n\n    # make vectors of arguments for the processes\n    vectors = [(i, cpu, filename, mat) for i in range(cpu)]\n    print(f\"Starting {cpu} processes for '{filename}'.\")\n\n    pool = Pool()  # make pool of 'cpu_count()' processes\n    pool.map(render_page, vectors, 1)  # start processes passing each a vector\n\n    t1 = mytime()  # stop the timer\n    print(f\"Total time {round(t1 - t0, 2):g} seconds\")\n"
  },
  {
    "path": "docs/samples/national-capitals.py",
    "content": "\"\"\"\nDemo script using (Py-) MuPDF \"Story\" feature.\n\nThe following features are implemented:\n\n* Use of Story \"template\" feature to provide row content\n* Use database access (SQLITE) to fetch row content\n* Use ElementPosition feature to locate cell positions on page\n* Simulate feature \"Table Header Repeat\"\n* Simulate feature \"Cell Grid Lines\"\n\n\"\"\"\nimport io\nimport sqlite3\nimport sys\n\nimport pymupdf\n\n\"\"\"\nTable data. Used to populate a temporary SQL database, which will be processed by the script.\nIts only purpose is to avoid carrying around a separate database file.\n\"\"\"\n# codespell:ignore-begin\ntable_data = \"\"\"China;Beijing;21542000;1.5%;2018\nJapan;Tokyo;13921000;11.2%;2019\nDR Congo;Kinshasa;12691000;13.2%;2017\nRussia;Moscow;12655050;8.7%;2021\nIndonesia;Jakarta;10562088;3.9%;2020\nEgypt;Cairo;10107125;9.3%;2022\nSouth Korea;Seoul;9508451;18.3%;2022\nMexico;Mexico City;9209944;7.3%;2020\nUnited Kingdom;London;9002488;13.4%;2020\nBangladesh;Dhaka;8906039;5.3%;2011\nPeru;Lima;8852000;26.3%;2012\nIran;Tehran;8693706;9.9%;2016\nThailand;Bangkok;8305218;11.6%;2010\nVietnam;Hanoi;8053663;8.3%;2019\nIraq;Baghdad;7682136;17.6%;2021\nSaudi Arabia;Riyadh;7676654;21.4%;2018\nHong Kong;Hong Kong;7291600;100%;2022\nColombia;Bogotá;7181469;13.9%;2011\nChile;Santiago;6310000;32.4%;2012\nTurkey;Ankara;5747325;6.8%;2021\nSingapore;Singapore;5453600;91.8%;2021\nAfghanistan;Kabul;4601789;11.5%;2021\nKenya;Nairobi;4397073;8.3%;2019\nJordan;Amman;4061150;36.4%;2021\nAlgeria;Algiers;3915811;8.9%;2011\nGermany;Berlin;3677472;4.4%;2021\nSpain;Madrid;3305408;7.0%;2021\nEthiopia;Addis Ababa;3040740;2.5%;2012\nKuwait;Kuwait City;2989000;70.3%;2018\nGuatemala;Guatemala City;2934841;16.7%;2020\nSouth Africa;Pretoria;2921488;4.9%;2011\nUkraine;Kyiv;2920873;6.7%;2021\nArgentina;Buenos Aires;2891082;6.4%;2010\nNorth Korea;Pyongyang;2870000;11.1%;2016\nUzbekistan;Tashkent;2860600;8.4%;2022\nItaly;Rome;2761632;4.7%;2022\nEcuador;Quito;2800388;15.7%;2020\nCameroon;Yaoundé;2765568;10.2%;2015\nZambia;Lusaka;2731696;14.0%;2020\nSudan;Khartoum;2682431;5.9%;2012\nBrazil;Brasília;2648532;1.2%;2012\nTaiwan;Taipei (de facto);2608332;10.9%;2020\nYemen;Sanaa;2575347;7.8%;2012\nAngola;Luanda;2571861;7.5%;2020\nBurkina Faso;Ouagadougou;2453496;11.1%;2019\nGhana;Accra;2388000;7.3%;2017\nSomalia;Mogadishu;2388000;14.0%;2021\nAzerbaijan;Baku;2303100;22.3%;2022\nCambodia;Phnom Penh;2281951;13.8%;2019\nVenezuela;Caracas;2245744;8.0%;2016\nFrance;Paris;2139907;3.3%;2022\nCuba;Havana;2132183;18.9%;2020\nZimbabwe;Harare;2123132;13.3%;2012\nSyria;Damascus;2079000;9.7%;2019\nBelarus;Minsk;1996553;20.8%;2022\nAustria;Vienna;1962779;22.0%;2022\nPoland;Warsaw;1863056;4.9%;2021\nPhilippines;Manila;1846513;1.6%;2020\nMali;Bamako;1809106;8.3%;2009\nMalaysia;Kuala Lumpur;1782500;5.3%;2019\nRomania;Bucharest;1716983;8.9%;2021\nHungary;Budapest;1706851;17.6%;2022\nCongo;Brazzaville;1696392;29.1%;2015\nSerbia;Belgrade;1688667;23.1%;2021\nUganda;Kampala;1680600;3.7%;2019\nGuinea;Conakry;1660973;12.3%;2014\nMongolia;Ulaanbaatar;1466125;43.8%;2020\nHonduras;Tegucigalpa;1444085;14.0%;2021\nSenegal;Dakar;1438725;8.5%;2021\nNiger;Niamey;1334984;5.3%;2020\nUruguay;Montevideo;1319108;38.5%;2011\nBulgaria;Sofia;1307439;19.0%;2021\nOman;Muscat;1294101;28.6%;2021\nCzech Republic;Prague;1275406;12.1%;2022\nMadagascar;Antananarivo;1275207;4.4%;2018\nKazakhstan;Astana;1239900;6.5%;2022\nNigeria;Abuja;1235880;0.6%;2011\nGeorgia;Tbilisi;1201769;32.0%;2022\nMauritania;Nouakchott;1195600;25.9%;2019\nQatar;Doha;1186023;44.1%;2020\nLibya;Tripoli;1170000;17.4%;2019\nMyanmar;Naypyidaw;1160242;2.2%;2014\nRwanda;Kigali;1132686;8.4%;2012\nMozambique;Maputo;1124988;3.5%;2020\nDominican Republic;Santo Domingo;1111838;10.0%;2010\nArmenia;Yerevan;1096100;39.3%;2021\nKyrgyzstan;Bishkek;1074075;16.5%;2021\nSierra Leone;Freetown;1055964;12.5%;2015\nNicaragua;Managua;1055247;15.4%;2020\nCanada;Ottawa;1017449;2.7%;2021\nPakistan;Islamabad;1014825;0.4%;2017\nLiberia;Monrovia;1010970;19.5%;2008\nUnited Arab Emirates;Abu Dhabi;1010092;10.8%;2020\nMalawi;Lilongwe;989318;5.0%;2018\nHaiti;Port-au-Prince;987310;8.6%;2015\nSweden;Stockholm;978770;9.4%;2021\nEritrea;Asmara;963000;26.6%;2020\nIsrael;Jerusalem;936425;10.5%;2019\nLaos;Vientiane;927724;12.5%;2019\nChad;N'Djamena;916000;5.3%;2009\nNetherlands;Amsterdam;905234;5.2%;2022\nCentral African Republic;Bangui;889231;16.3%;2020\nPanama;Panama City;880691;20.2%;2013\nTajikistan;Dushanbe;863400;8.9%;2020\nNepal;Kathmandu;845767;2.8%;2021\nTogo;Lomé;837437;9.7%;2010\nTurkmenistan;Ashgabat;791000;12.5%;2017\nMoldova;Chişinău;779300;25.5%;2019\nCroatia;Zagreb;769944;19.0%;2021\nGabon;Libreville;703904;30.1%;2013\nNorway;Oslo;697010;12.9%;2021\nMacau;Macau;671900;97.9%;2022\nUnited States;Washington D.C.;670050;0.2%;2021\nJamaica;Kingston;662491;23.4%;2019\nFinland;Helsinki;658864;11.9%;2021\nTunisia;Tunis;638845;5.2%;2014\nDenmark;Copenhagen;638117;10.9%;2021\nGreece;Athens;637798;6.1%;2021\nLatvia;Riga;605802;32.3%;2021\nDjibouti;Djibouti (city);604013;54.6%;2012\nIreland;Dublin;588233;11.8%;2022\nMorocco;Rabat;577827;1.6%;2014\nLithuania;Vilnius;576195;20.7%;2022\nEl Salvador;San Salvador;570459;9.0%;2019\nAlbania;Tirana;557422;19.5%;2011\nNorth Macedonia;Skopje;544086;25.9%;2015\nSouth Sudan;Juba;525953;4.9%;2017\nParaguay;Asunción;521559;7.8%;2020\nPortugal;Lisbon;509614;5.0%;2020\nGuinea-Bissau;Bissau;492004;23.9%;2015\nSlovakia;Bratislava;440948;8.1%;2020\nEstonia;Tallinn;438341;33.0%;2021\nAustralia;Canberra;431380;1.7%;2020\nNamibia;Windhoek;431000;17.0%;2020\nTanzania;Dodoma;410956;0.6%;2012\nPapua New Guinea;Port Moresby;364145;3.7%;2011\nIvory Coast;Yamoussoukro;361893;1.3%;2020\nLebanon;Beirut;361366;6.5%;2014\nBolivia;Sucre;360544;3.0%;2022\nPuerto Rico (US);San Juan;342259;10.5%;2020\nCosta Rica;San José;342188;6.6%;2018\nLesotho;Maseru;330760;14.5%;2016\nCyprus;Nicosia;326739;26.3%;2016\nEquatorial Guinea;Malabo;297000;18.2%;2018\nSlovenia;Ljubljana;285604;13.5%;2021\nEast Timor;Dili;277279;21.0%;2015\nBosnia and Herzegovina;Sarajevo;275524;8.4%;2013\nBahamas;Nassau;274400;67.3%;2016\nBotswana;Gaborone;273602;10.6%;2020\nBenin;Porto-Novo;264320;2.0%;2013\nSuriname;Paramaribo;240924;39.3%;2012\nIndia;New Delhi;249998;0.0%;2011\nSahrawi Arab Democratic Republic;Laayoune (claimed) - Tifariti (de facto);217732 - 3000;—;2014\nNew Zealand;Wellington;217000;4.2%;2021\nBahrain;Manama;200000;13.7%;2020\nKosovo;Pristina;198897;12.0%;2011\nMontenegro;Podgorica;190488;30.3%;2020\nBelgium;Brussels;187686;1.6%;2022\nCape Verde;Praia;159050;27.1%;2017\nMauritius;Port Louis;147066;11.3%;2018\nCuraçao (Netherlands);Willemstad;136660;71.8%;2011\nBurundi;Gitega;135467;1.1%;2020\nSwitzerland;Bern (de facto);134591;1.5%;2020\nTransnistria;Tiraspol;133807;38.5%;2015\nMaldives;Malé;133412;25.6%;2014\nIceland;Reykjavík;133262;36.0%;2021\nLuxembourg;Luxembourg City;124509;19.5%;2021\nGuyana;Georgetown;118363;14.7%;2012\nBhutan;Thimphu;114551;14.7%;2017\nComoros;Moroni;111326;13.5%;2016\nBarbados;Bridgetown;110000;39.1%;2014\nSri Lanka;Sri Jayawardenepura Kotte;107925;0.5%;2012\nBrunei;Bandar Seri Begawan;100700;22.6%;2007\nEswatini;Mbabane;94874;8.0%;2010\nNew Caledonia (France);Nouméa;94285;32.8%;2019\nFiji;Suva;93970;10.2%;2017\nSolomon Islands;Honiara;92344;13.0%;2021\nRepublic of Artsakh;Stepanakert;75000;62.5%;2021\nGambia;Banjul;73000;2.8%;2013\nSão Tomé and Príncipe;São Tomé;71868;32.2%;2015\nKiribati;Tarawa;70480;54.7%;2020\nVanuatu;Port Vila;51437;16.1%;2016\nNorthern Mariana Islands (USA);Saipan;47565;96.1%;2017\nSamoa;Apia;41611;19.0%;2021\nPalestine;Ramallah (de facto);38998;0.8%;2017\nMonaco;Monaco;38350;104.5%;2020\nJersey (UK);Saint Helier;37540;34.2%;2018\nTrinidad and Tobago;Port of Spain;37074;2.4%;2011\nCayman Islands (UK);George Town;34399;50.5%;2021\nGibraltar (UK);Gibraltar;34003;104.1%;2020\nGrenada;St. George's;33734;27.1%;2012\nAruba (Netherlands);Oranjestad;28294;26.6%;2010\nIsle of Man (UK);Douglas;27938;33.2%;2011\nMarshall Islands;Majuro;27797;66.1%;2011\nTonga;Nukuʻalofa;27600;26.0%;2022\nSeychelles;Victoria;26450;24.8%;2010\nFrench Polynesia (France);Papeete;26926;8.9%;2017\nAndorra;Andorra la Vella;22873;28.9%;2022\nFaroe Islands (Denmark);Tórshavn;22738;43.0%;2022\nAntigua and Barbuda;St. John's;22219;23.8%;2011\nBelize;Belmopan;20621;5.2%;2016\nSaint Lucia;Castries;20000;11.1%;2013\nGuernsey (UK);Saint Peter Port;18958;30.1%;2019\nGreenland (Denmark);Nuuk;18800;33.4%;2021\nDominica;Roseau;14725;20.3%;2011\nSaint Kitts and Nevis;Basseterre;14000;29.4%;2018\nSaint Vincent and the Grenadines;Kingstown;12909;12.4%;2012\nBritish Virgin Islands (UK);Road Town;12603;40.5%;2012\nÅland (Finland);Mariehamn;11736;39.0%;2021\nU.S. Virgin Islands (US);Charlotte Amalie;14477;14.5%;2020\nMicronesia;Palikir;6647;5.9%;2010\nTuvalu;Funafuti;6320;56.4%;2017\nMalta;Valletta;5827;1.1%;2019\nLiechtenstein;Vaduz;5774;14.8%;2021\nSaint Pierre and Miquelon (France);Saint-Pierre;5394;91.7%;2019\nCook Islands (NZ);Avarua;4906;28.9%;2016\nSan Marino;City of San Marino;4061;12.0%;2021\nTurks and Caicos Islands (UK);Cockburn Town;3720;8.2%;2016\nAmerican Samoa (USA);Pago Pago;3656;8.1%;2010\nSaint Martin (France);Marigot;3229;10.1%;2017\nSaint Barthélemy (France);Gustavia;2615;24.1%;2010\nFalkland Islands (UK);Stanley;2460;65.4%;2016\nSvalbard (Norway);Longyearbyen;2417;82.2%;2020\nSint Maarten (Netherlands);Philipsburg;1894;4.3%;2011\nChristmas Island (Australia);Flying Fish Cove;1599;86.8%;2016\nAnguilla (UK);The Valley;1067;6.8%;2011\nGuam (US);Hagåtña;1051;0.6%;2010\nWallis and Futuna (France);Mata Utu;1029;8.9%;2018\nBermuda (UK);Hamilton;854;1.3%;2016\nNauru;Yaren (de facto);747;6.0%;2011\nSaint Helena (UK);Jamestown;629;11.6%;2016\nNiue (NZ);Alofi;597;30.8%;2017\nTokelau (NZ);Atafu;541;29.3%;2016\nVatican City;Vatican City (city-state);453;100%;2019\nMontserrat (UK);Brades (de facto) - Plymouth (de jure);449 - 0;-;2011\nNorfolk Island (Australia);Kingston;341;-;2015\nPalau;Ngerulmud;271;1.5%;2010\nCocos (Keeling) Islands (Australia);West Island;134;24.6%;2011\nPitcairn Islands (UK);Adamstown;40;100.0%;2021\nSouth Georgia and the South Sandwich Islands (UK);King Edward Point;22;73.3%;2018\"\"\"\n# codespell:ignore-end\n\n# -------------------------------------------------------------------\n# HTML template for the report. We define no table header <th> items\n# because this is done in post processing.\n# The actual template part is the table row, identified by id \"row\".\n# The content of each cell will be filled using the respective id.\n# -------------------------------------------------------------------\nHTML = \"\"\"\n    <h1 style=\"text-align:center\">World Capital Cities</h1>\n    <p><i>Percent \"%\" is city population as a percentage of the country, as of \"Year\".</i>\n    </p><p></p>\n    <table>\n    <tr id=\"row\">\n        <td id=\"country\"></td>\n        <td id=\"capital\"></td>\n        <td id=\"population\"></td>\n        <td id=\"percent\"></td>\n        <td id=\"year\"></td>\n    </tr>\n    </table>\n\"\"\"\n\n# -------------------------------------------------------------------\n# Sets font-family globally to sans-serif, and text-align to right\n# for the numerical table columns.\n# -------------------------------------------------------------------\nCSS = \"\"\"\nbody {\n    font-family: sans-serif;\n}\ntd[id=\"population\"], td[id=\"percent\"], td[id=\"year\"] {\n    text-align: right;\n    padding-right: 2px;\n}\"\"\"\n\n# -------------------------------------------------------------------\n# recorder function for cell positions\n# -------------------------------------------------------------------\ncoords = {}  # stores cell gridline coordinates\n\n\ndef recorder(elpos):\n    \"\"\"We only record positions of table rows and cells.\n\n    Information is stored in \"coords\" with page number as key.\n    \"\"\"\n    global coords  # dictionary of row and cell coordinates per page\n    if elpos.open_close != 2:  # only consider coordinates provided at \"close\"\n        return\n    if elpos.id not in (\"row\", \"country\", \"capital\", \"population\", \"percent\", \"year\"):\n        return  # only look at row / cell content\n\n    rect = pymupdf.Rect(elpos.rect)  # cell rectangle\n    if rect.y1 > elpos.filled:  # ignore stuff below the filled rectangle\n        return\n\n    # per page, we store the floats top-most y, right-most x, column left\n    # and row bottom borders.\n    x, y, x1, y0 = coords.get(elpos.page, (set(), set(), 0, sys.maxsize))\n\n    if elpos.id != \"row\":\n        x.add(rect.x0)  # add cell left border coordinate\n        if rect.x1 > x1:  # store right-most cell border on page\n            x1 = rect.x1\n    else:\n        y.add(rect.y1)  # add row bottom border coordinate\n        if rect.y0 < y0:  # store top-most cell border per page\n            y0 = rect.y0\n\n    coords[elpos.page] = (x, y, x1, y0)  # write back info per page\n    return\n\n\n# -------------------------------------------------------------------\n# define database access: make an intermediate memory database for\n# our demo purposes.\n# -------------------------------------------------------------------\ndbfilename = \":memory:\"  # the SQLITE database file name\ndatabase = sqlite3.connect(dbfilename)  # open database\ncursor = database.cursor()  # multi-purpose database cursor\n\n# Define and fill the SQLITE database\ncursor.execute(\n    \"\"\"CREATE TABLE capitals (Country text, Capital text, Population text, Percent text, Year text)\"\"\"\n)\n\nfor value in table_data.splitlines():\n    cursor.execute(\"INSERT INTO capitals VALUES (?,?,?,?,?)\", value.split(\";\"))\n\n# select statement for the rows - let SQL also sort it for us\nselect = \"\"\"SELECT * FROM capitals ORDER BY \"Country\" \"\"\"\n\n# -------------------------------------------------------------------\n# define the HTML Story and fill it with database data\n# -------------------------------------------------------------------\nstory = pymupdf.Story(HTML, user_css=CSS)\nbody = story.body  # access the HTML body detail\n\ntemplate = body.find(None, \"id\", \"row\")  # find the template part\ntable = body.find(\"table\", None, None)  # find start of table\n\n# read the rows from the database and put them all in one Python list\n# NOTE: instead, we might fetch rows one by one (advisable for large volumes)\n\ncursor.execute(select)  # execute cursor, and ...\nrows = cursor.fetchall()  # read out what was found\ndatabase.close()  # no longer needed\n\nfor country, capital, population, percent, year in rows:  # iterate through the row\n    row = template.clone()  # clone the template to report each row\n    row.find(None, \"id\", \"country\").add_text(country)\n    row.find(None, \"id\", \"capital\").add_text(capital)\n    row.find(None, \"id\", \"population\").add_text(population)\n    row.find(None, \"id\", \"percent\").add_text(percent)\n    row.find(None, \"id\", \"year\").add_text(year)\n\n    table.append_child(row)\n\ntemplate.remove()  # remove the template\n\n# -------------------------------------------------------------------\n# generate the PDF and write it to memory\n# -------------------------------------------------------------------\nfp = io.BytesIO()\nwriter = pymupdf.DocumentWriter(fp)\nmediabox = pymupdf.paper_rect(\"letter\")  # use pages in Letter format\nwhere = mediabox + (36, 36, -36, -72)  # leave page borders\nmore = True\npage = 0\nwhile more:\n    dev = writer.begin_page(mediabox)  # make a new page\n    if page > 0:  # leave room above the cells for inserting header row\n        delta = (0, 20, 0, 0)\n    else:\n        delta = (0, 0, 0, 0)\n    more, filled = story.place(where + delta)  # arrange content on this rectangle\n    story.element_positions(recorder, {\"page\": page, \"filled\": where.y1})\n    story.draw(dev)  # write content to page\n    writer.end_page()  # finish the page\n    page += 1\nwriter.close()  # close the PDF\n\n# -------------------------------------------------------------------\n# re-open memory PDF for inserting gridlines and header rows\n# -------------------------------------------------------------------\ndoc = pymupdf.open(\"pdf\", fp)\nfor page in doc:\n    page.wrap_contents()  # ensure all \"cm\" commands are properly wrapped\n    x, y, x1, y0 = coords[page.number]  # read coordinates of the page\n    x = sorted(list(x)) + [x1]  # list of cell left-right borders\n    y = [y0] + sorted(list(y))  # list of cell top-bottom borders\n    shape = page.new_shape()  # make a canvas to draw upon\n\n    for item in y:  # draw horizontal lines (one under each row)\n        shape.draw_line((x[0] - 2, item), (x[-1] + 2, item))\n\n    for i in range(len(y)):  # alternating row coloring\n        if i % 2:\n            rect = (x[0] - 2, y[i - 1], x[-1] + 2, y[i])\n            shape.draw_rect(rect)\n\n    for i in range(len(x)):  # draw vertical lines\n        d = 2 if i == len(x) - 1 else -2\n        shape.draw_line((x[i] + d, y[0]), (x[i] + d, y[-1]))\n\n    # Write header row above table content\n    y0 -= 5  # bottom coord for header row text\n    shape.insert_text((x[0], y0), \"Country\", fontname=\"hebo\", fontsize=12)\n    shape.insert_text((x[1], y0), \"Capital\", fontname=\"hebo\", fontsize=12)\n    shape.insert_text((x[2], y0), \"Population\", fontname=\"hebo\", fontsize=12)\n    shape.insert_text((x[3], y0), \"  %\", fontname=\"hebo\", fontsize=12)\n    shape.insert_text((x[4], y0), \"Year\", fontname=\"hebo\", fontsize=12)\n\n    # Write page footer\n    y0 = page.rect.height - 50  # top coordinate of footer bbox\n    bbox = pymupdf.Rect(0, y0, page.rect.width, y0 + 20)  # footer bbox\n    page.insert_textbox(\n        bbox,\n        f\"World Capital Cities, Page {page.number+1} of {doc.page_count}\",\n        align=pymupdf.TEXT_ALIGN_CENTER,\n    )\n    shape.finish(width=0.3, color=0.5, fill=0.9)  # rectangles and gray lines\n    shape.commit(overlay=False)  # put the drawings in background\n\ndoc.subset_fonts()\ndoc.save(__file__.replace(\".py\", \".pdf\"), deflate=True, garbage=4, pretty=True)\ndoc.close()\n"
  },
  {
    "path": "docs/samples/new-annots.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"\n-------------------------------------------------------------------------------\nDemo script showing how annotations can be added to a PDF using PyMuPDF.\n\nIt contains the following annotation types:\nCaret, Text, FreeText, text markers (underline, strike-out, highlight,\nsquiggle), Circle, Square, Line, PolyLine, Polygon, FileAttachment, Stamp\nand Redaction.\nThere is some effort to vary appearances by adding colors, line ends,\nopacity, rotation, dashed lines, etc.\n\nDependencies\n------------\nPyMuPDF v1.17.0\n-------------------------------------------------------------------------------\n\"\"\"\nfrom __future__ import print_function\n\nimport gc\nimport sys\n\nimport pymupdf\n\nprint(pymupdf.__doc__)\nif pymupdf.VersionBind.split(\".\") < [\"1\", \"17\", \"0\"]:\n    sys.exit(\"PyMuPDF v1.17.0+ is needed.\")\n\ngc.set_debug(gc.DEBUG_UNCOLLECTABLE)\n\nhighlight = \"this text is highlighted\"\nunderline = \"this text is underlined\"\nstrikeout = \"this text is striked out\"\nsquiggled = \"this text is zigzag-underlined\"\nred = (1, 0, 0)\nblue = (0, 0, 1)\ngold = (1, 1, 0)\ngreen = (0, 1, 0)\n\ndispl = pymupdf.Rect(0, 50, 0, 50)\nr = pymupdf.Rect(72, 72, 220, 100)\nt1 = u\"têxt üsès Lätiñ charß,\\nEUR: €, mu: µ, super scripts: ²³!\"\n\n\ndef print_descr(annot):\n    \"\"\"Print a short description to the right of each annot rect.\"\"\"\n    annot.parent.insert_text(\n        annot.rect.br + (10, -5), f\"{annot.type[1]} annotation\", color=red)\n\n\ndoc = pymupdf.open()\npage = doc.new_page()\n\npage.set_rotation(0)\n\nannot = page.add_caret_annot(r.tl)\nprint_descr(annot)\n\nr = r + displ\nannot = page.add_freetext_annot(\n    r,\n    t1,\n    fontsize=10,\n    rotate=90,\n    text_color=blue,\n    fill_color=gold,\n    align=pymupdf.TEXT_ALIGN_CENTER,\n)\nannot.set_border(width=0.3, dashes=[2])\nannot.update(text_color=blue, fill_color=gold)\nprint_descr(annot)\n\nr = annot.rect + displ\nannot = page.add_text_annot(r.tl, t1)\nprint_descr(annot)\n\n# Adding text marker annotations:\n# first insert a unique text, then search for it, then mark it\npos = annot.rect.tl + displ.tl\npage.insert_text(\n    pos,  # insertion point\n    highlight,  # inserted text\n    morph=(pos, pymupdf.Matrix(-5)),  # rotate around insertion point\n)\nrl = page.search_for(highlight, quads=True)  # need a quad b/o tilted text\nannot = page.add_highlight_annot(rl[0])\nprint_descr(annot)\n\npos = annot.rect.bl  # next insertion point\npage.insert_text(pos, underline, morph=(pos, pymupdf.Matrix(-10)))\nrl = page.search_for(underline, quads=True)\nannot = page.add_underline_annot(rl[0])\nprint_descr(annot)\n\npos = annot.rect.bl\npage.insert_text(pos, strikeout, morph=(pos, pymupdf.Matrix(-15)))\nrl = page.search_for(strikeout, quads=True)\nannot = page.add_strikeout_annot(rl[0])\nprint_descr(annot)\n\npos = annot.rect.bl\npage.insert_text(pos, squiggled, morph=(pos, pymupdf.Matrix(-20)))\nrl = page.search_for(squiggled, quads=True)\nannot = page.add_squiggly_annot(rl[0])\nprint_descr(annot)\n\npos = annot.rect.bl\nr = pymupdf.Rect(pos, pos.x + 75, pos.y + 35) + (0, 20, 0, 20)\nannot = page.add_polyline_annot([r.bl, r.tr, r.br, r.tl])  # 'Polyline'\nannot.set_border(width=0.3, dashes=[2])\nannot.set_colors(stroke=blue, fill=green)\nannot.set_line_ends(pymupdf.PDF_ANNOT_LE_CLOSED_ARROW, pymupdf.PDF_ANNOT_LE_R_CLOSED_ARROW)\nannot.update(fill_color=(1, 1, 0))\nprint_descr(annot)\n\nr += displ\nannot = page.add_polygon_annot([r.bl, r.tr, r.br, r.tl])  # 'Polygon'\nannot.set_border(width=0.3, dashes=[2])\nannot.set_colors(stroke=blue, fill=gold)\nannot.set_line_ends(pymupdf.PDF_ANNOT_LE_DIAMOND, pymupdf.PDF_ANNOT_LE_CIRCLE)\nannot.update()\nprint_descr(annot)\n\nr += displ\nannot = page.add_line_annot(r.tr, r.bl)  # 'Line'\nannot.set_border(width=0.3, dashes=[2])\nannot.set_colors(stroke=blue, fill=gold)\nannot.set_line_ends(pymupdf.PDF_ANNOT_LE_DIAMOND, pymupdf.PDF_ANNOT_LE_CIRCLE)\nannot.update()\nprint_descr(annot)\n\nr += displ\nannot = page.add_rect_annot(r)  # 'Square'\nannot.set_border(width=1, dashes=[1, 2])\nannot.set_colors(stroke=blue, fill=gold)\nannot.update(opacity=0.5)\nprint_descr(annot)\n\nr += displ\nannot = page.add_circle_annot(r)  # 'Circle'\nannot.set_border(width=0.3, dashes=[2])\nannot.set_colors(stroke=blue, fill=gold)\nannot.update()\nprint_descr(annot)\n\nr += displ\nannot = page.add_file_annot(\n    r.tl, b\"just anything for testing\", \"testdata.txt\"  # 'FileAttachment'\n)\nprint_descr(annot)  # annot.rect\n\nr += displ\nannot = page.add_stamp_annot(r, stamp=10)  # 'Stamp'\nannot.set_colors(stroke=green)\nannot.update()\nprint_descr(annot)\n\nr += displ + (0, 0, 50, 10)\nrc = page.insert_textbox(\n    r,\n    \"This content will be removed upon applying the redaction.\",\n    color=blue,\n    align=pymupdf.TEXT_ALIGN_CENTER,\n)\nannot = page.add_redact_annot(r)\nprint_descr(annot)\n\ndoc.save(__file__.replace(\".py\", f\"-{page.rotation:d}.pdf\"), deflate=True)\n"
  },
  {
    "path": "docs/samples/quickfox-image-no-go.py",
    "content": "\"\"\"\r\nThis is a demo script using PyMuPDF's Story class to output text as a PDF with\r\na two-column page layout.\r\n\r\nThe script demonstrates the following features:\r\n* Layout text around images of an existing (\"target\") PDF.\r\n* Based on a few global parameters, areas on each page are identified, that\r\n  can be used to receive text layouted by a Story.\r\n* These global parameters are not stored anywhere in the target PDF and\r\n  must therefore be provided in some way.\r\n  - The width of the border(s) on each page.\r\n  - The fontsize to use for text. This value determines whether the provided\r\n    text will fit in the empty spaces of the (fixed) pages of target PDF. It\r\n    cannot be predicted in any way. The script ends with an exception if\r\n    target PDF has not enough pages, and prints a warning message if not all\r\n    pages receive at least some text. In both cases, the FONTSIZE value\r\n    can be changed (a float value).\r\n  - Use of a 2-column page layout for the text.\r\n* The layout creates a temporary (memory) PDF. Its produced page content\r\n  (the text) is used to overlay the corresponding target page. If text\r\n  requires more pages than are available in target PDF, an exception is raised.\r\n  If not all target pages receive at least some text, a warning is printed.\r\n* The script reads \"image-no-go.pdf\" in its own folder. This is the \"target\" PDF.\r\n  It contains 2 pages with each 2 images (from the original article), which are\r\n  positioned at places that create a broad overall test coverage. Otherwise the\r\n  pages are empty.\r\n* The script produces \"quickfox-image-no-go.pdf\" which contains the original pages\r\n  and image positions, but with the original article text laid out around them.\r\n\r\nNote:\r\n--------------\r\nThis script version uses just image positions to derive \"No-Go areas\" for\r\nlayouting the text. Other PDF objects types are detectable by PyMuPDF and may\r\nbe taken instead or in addition, without influencing the layouting.\r\nThe following are candidates for other such \"No-Go areas\". Each can be detected\r\nand located by PyMuPDF:\r\n* Annotations\r\n* Drawings\r\n* Existing text\r\n\r\n--------------\r\nThe text and images are taken from the somewhat modified Wikipedia article\r\nhttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog.\r\n--------------\r\n\"\"\"\r\n\r\nimport io\r\nimport os\r\nimport zipfile\r\nimport pymupdf\r\n\r\n\r\nthisdir = os.path.dirname(os.path.abspath(__file__))\r\nmyzip = zipfile.ZipFile(os.path.join(thisdir, \"quickfox.zip\"))\r\n\r\ndocname = os.path.join(thisdir, \"image-no-go.pdf\")  # \"no go\" input PDF file name\r\noutname = os.path.join(thisdir, \"quickfox-image-no-go.pdf\")  # output PDF file name\r\nBORDER = 36  # global parameter\r\nFONTSIZE = 12.5  # global parameter\r\nCOLS = 2  # number of text columns, global parameter\r\n\r\n\r\ndef analyze_page(page):\r\n    \"\"\"Compute MediaBox and rectangles on page that are free to receive text.\r\n\r\n    Notes:\r\n        Assume a BORDER around the page, make 2 columns of the resulting\r\n        sub-rectangle and extract the rectangles of all images on page.\r\n        For demo purposes, the image rectangles are taken as \"NO-GO areas\"\r\n        on the page when writing text with the Story.\r\n        The function returns free areas for each of the columns.\r\n\r\n    Returns:\r\n        (page.number, mediabox, CELLS), where CELLS is a list of free cells.\r\n    \"\"\"\r\n    prect = page.rect  # page rectangle - will be our MEDIABOX later\r\n    where = prect + (BORDER, BORDER, -BORDER, -BORDER)\r\n    TABLE = pymupdf.make_table(where, rows=1, cols=COLS)\r\n\r\n    # extract rectangles covered by images on this page\r\n    IMG_RECTS = sorted(  # image rects on page (sort top-left to bottom-right)\r\n        [pymupdf.Rect(item[\"bbox\"]) for item in page.get_image_info()],\r\n        key=lambda b: (b.y1, b.x0),\r\n    )\r\n\r\n    def free_cells(column):\r\n        \"\"\"Return free areas in this column.\"\"\"\r\n        free_stripes = []  # y-value pairs wrapping a free area stripe\r\n        # intersecting images: block complete intersecting column stripe\r\n        col_imgs = [(b.y0, b.y1) for b in IMG_RECTS if abs(b & column) > 0]\r\n        s_y0 = column.y0  # top y-value of column\r\n        for y0, y1 in col_imgs:  # an image stripe\r\n            if y0 > s_y0 + FONTSIZE:  # image starts below last free btm value\r\n                free_stripes.append((s_y0, y0))  # store as free stripe\r\n            s_y0 = y1  # start of next free stripe\r\n\r\n        if s_y0 + FONTSIZE < column.y1:  # enough room to column bottom\r\n            free_stripes.append((s_y0, column.y1))\r\n\r\n        if free_stripes == []:  # covers \"no image in this column\"\r\n            free_stripes.append((column.y0, column.y1))\r\n\r\n        # make available cells of this column\r\n        CELLS = [pymupdf.Rect(column.x0, y0, column.x1, y1) for (y0, y1) in free_stripes]\r\n        return CELLS\r\n\r\n    # collection of available Story rectangles on page\r\n    CELLS = []\r\n    for i in range(COLS):\r\n        CELLS.extend(free_cells(TABLE[0][i]))\r\n\r\n    return page.number, prect, CELLS\r\n\r\n\r\nHTML = myzip.read(\"quickfox.html\").decode()\r\n\r\n# --------------------------------------------------------------\r\n# Make the Story object\r\n# --------------------------------------------------------------\r\nstory = pymupdf.Story(HTML)\r\n\r\n# modify the DOM somewhat\r\nbody = story.body  # access HTML body\r\nbody.set_properties(font=\"sans-serif\")  # and give it our font globally\r\n\r\n# modify certain nodes\r\npara = body.find(\"p\", None, None)  # find relevant nodes (here: paragraphs)\r\nwhile para != None:\r\n    para.set_properties(  # method MUST be used for existing nodes\r\n        indent=15,\r\n        fontsize=FONTSIZE,\r\n    )\r\n    para = para.find_next(\"p\", None, None)\r\n\r\n# we remove all image references, because the target PDF already has them\r\nimg = body.find(\"img\", None, None)\r\nwhile img != None:\r\n    next_img = img.find_next(\"img\", None, None)\r\n    img.remove()\r\n    img = next_img\r\n\r\npage_info = {}  # contains MEDIABOX and free CELLS per page\r\ndoc = pymupdf.open(docname)\r\nfor page in doc:\r\n    pno, mediabox, cells = analyze_page(page)\r\n    page_info[pno] = (mediabox, cells)\r\ndoc.close()  # close target PDF for now - re-open later\r\n\r\nfileobject = io.BytesIO()  # let DocumentWriter write to memory\r\nwriter = pymupdf.DocumentWriter(fileobject)  # define output writer\r\n\r\nmore = 1  # stop if this ever becomes zero\r\npno = 0  # count output pages\r\nwhile more:  # loop until all HTML text has been written\r\n    try:\r\n        MEDIABOX, CELLS = page_info[pno]\r\n    except KeyError:  # too much text space required: reduce fontsize?\r\n        raise ValueError(\"text does not fit on target PDF\")\r\n    dev = writer.begin_page(MEDIABOX)  # prepare a new output page\r\n    for cell in CELLS:  # iterate over free cells on this page\r\n        if not more:  # need to check this for every cell\r\n            continue\r\n        more, _ = story.place(cell)\r\n        story.draw(dev)\r\n    writer.end_page()  # finish the PDF page\r\n    pno += 1\r\n\r\nwriter.close()  # close DocumentWriter output\r\n\r\n# Re-open writer output, read its pages and overlay target pages with them.\r\n# The generated pages have same dimension as their targets.\r\nsrc = pymupdf.open(\"pdf\", fileobject)\r\ndoc = pymupdf.open(doc.name)\r\nfor page in doc:  # overlay every target page with the prepared text\r\n    if page.number >= src.page_count:\r\n        print(f\"Text only uses {src.page_count} target pages!\")\r\n        continue  # story did not need all target pages?\r\n\r\n    # overlay target page\r\n    page.show_pdf_page(page.rect, src, page.number)\r\n\r\n    # DEBUG start --- draw the text rectangles\r\n    # mb, cells = page_info[page.number]\r\n    # for cell in cells:\r\n    #     page.draw_rect(cell, color=(1, 0, 0))\r\n    # DEBUG stop ---\r\n\r\ndoc.ez_save(outname)\r\n"
  },
  {
    "path": "docs/samples/quickfox.py",
    "content": "\"\"\"\nThis is a demo script using PyMuPDF's Story class to output text as a PDF with\na two-column page layout.\n\nThe script demonstrates the following features:\n* How to fill columns or table cells of complex page layouts\n* How to embed images\n* How to modify existing, given HTML sources for output (text indent, font size)\n* How to use fonts defined in package \"pymupdf-fonts\"\n* How to use ZIP files as Archive\n\n--------------\nThe example is taken from the somewhat modified Wikipedia article\nhttps://en.wikipedia.org/wiki/The_quick_brown_fox_jumps_over_the_lazy_dog.\n--------------\n\"\"\"\n\nimport io\nimport os\nimport zipfile\nimport pymupdf\n\n\nthisdir = os.path.dirname(os.path.abspath(__file__))\nmyzip = zipfile.ZipFile(os.path.join(thisdir, \"quickfox.zip\"))\narch = pymupdf.Archive(myzip)\n\nif pymupdf.fitz_fontdescriptors:\n    # we want to use the Ubuntu fonts for sans-serif and for monospace\n    CSS = pymupdf.css_for_pymupdf_font(\"ubuntu\", archive=arch, name=\"sans-serif\")\n    CSS = pymupdf.css_for_pymupdf_font(\"ubuntm\", CSS=CSS, archive=arch, name=\"monospace\")\nelse:\n    # No pymupdf-fonts available.\n    CSS=\"\"\n\ndocname = __file__.replace(\".py\", \".pdf\")  # output PDF file name\n\nHTML = myzip.read(\"quickfox.html\").decode()\n\n# make the Story object\nstory = pymupdf.Story(HTML, user_css=CSS, archive=arch)\n\n# --------------------------------------------------------------\n# modify the DOM somewhat\n# --------------------------------------------------------------\nbody = story.body  # access HTML body\nbody.set_properties(font=\"sans-serif\")  # and give it our font globally\n\n# modify certain nodes\npara = body.find(\"p\", None, None)  # find relevant nodes (here: paragraphs)\nwhile para != None:\n    para.set_properties(  # method MUST be used for existing nodes\n        indent=15,\n        fontsize=13,\n    )\n    para = para.find_next(\"p\", None, None)\n\n# choose PDF page size\nMEDIABOX = pymupdf.paper_rect(\"letter\")\n# text appears only within this subrectangle\nWHERE = MEDIABOX + (36, 36, -36, -36)\n\n# --------------------------------------------------------------\n# define page layout within the WHERE rectangle\n# --------------------------------------------------------------\nCOLS = 2  # layout: 2 cols 1 row\nROWS = 1\nTABLE = pymupdf.make_table(WHERE, cols=COLS, rows=ROWS)\n# fill the cells of each page in this sequence:\nCELLS = [TABLE[i][j] for i in range(ROWS) for j in range(COLS)]\n\nfileobject = io.BytesIO()  # let DocumentWriter write to memory\nwriter = pymupdf.DocumentWriter(fileobject)  # define the writer\n\nmore = 1\nwhile more:  # loop until all input text has been written out\n    dev = writer.begin_page(MEDIABOX)  # prepare a new output page\n    for cell in CELLS:\n        # content may be complete after any cell, ...\n        if more:  # so check this status first\n            more, _ = story.place(cell)\n            story.draw(dev)\n    writer.end_page()  # finish the PDF page\n\nwriter.close()  # close DocumentWriter output\n\n# for housekeeping work re-open from memory\ndoc = pymupdf.open(\"pdf\", fileobject)\ndoc.ez_save(docname)\n"
  },
  {
    "path": "docs/samples/showpdf-page.py",
    "content": "\"\"\"\nDemo of Story class in PyMuPDF\n-------------------------------\n\nThis script demonstrates how to the results of a pymupdf.Story output can be\nplaced in a rectangle of an existing (!) PDF page.\n\n\"\"\"\nimport io\nimport os\n\nimport pymupdf\n\n\ndef make_pdf(fileptr, text, rect, font=\"sans-serif\", archive=None):\n    \"\"\"Make a memory DocumentWriter from HTML text and a rect.\n\n    Args:\n        fileptr: a Python file object. For example an io.BytesIO().\n        text: the text to output (HTML format)\n        rect: the target rectangle. Will use its width / height as mediabox\n        font: (str) font family name, default sans-serif\n        archive: pymupdf.Archive parameter. To be used if e.g. images or special\n                fonts should be used.\n    Returns:\n        The matrix to convert page rectangles of the created PDF back\n        to rectangle coordinates in the parameter \"rect\".\n        Normal use will expect to fit all the text in the given rect.\n        However, if an overflow occurs, this function will output multiple\n        pages, and the caller may decide to either accept or retry with\n        changed parameters.\n    \"\"\"\n    # use input rectangle as the page dimension\n    mediabox = pymupdf.Rect(0, 0, rect.width, rect.height)\n    # this matrix converts mediabox back to input rect\n    matrix = mediabox.torect(rect)\n\n    story = pymupdf.Story(text, archive=archive)\n    body = story.body\n    body.set_properties(font=font)\n    writer = pymupdf.DocumentWriter(fileptr)\n    while True:\n        device = writer.begin_page(mediabox)\n        more, _ = story.place(mediabox)\n        story.draw(device)\n        writer.end_page()\n        if not more:\n            break\n    writer.close()\n    return matrix\n\n\n# -------------------------------------------------------------\n# We want to put this in a given rectangle of an existing page\n# -------------------------------------------------------------\nHTML = \"\"\"\n<p>PyMuPDF is a great package! And it still improves significantly from one version to the next one!</p>\n<p>It is a Python binding for <b>MuPDF</b>, a lightweight PDF, XPS, and E-book viewer, renderer, and toolkit.<br> Both are maintained and developed by Artifex Software, Inc.</p>\n<p>Via MuPDF it can access files in PDF, XPS, OpenXPS, CBZ, EPUB, MOBI and FB2 (e-books) formats,<br> and it is known for its top\n<b><i>performance</i></b> and <b><i>rendering quality.</p>\"\"\"\n\n# Make a PDF page for demo purposes\nroot = os.path.abspath( f\"{__file__}/..\")\ndoc = pymupdf.open(f\"{root}/mupdf-title.pdf\")\npage = doc[0]\n\nWHERE = pymupdf.Rect(50, 100, 250, 500)  # target rectangle on existing page\n\nfileptr = io.BytesIO()  # let DocumentWriter use this as its file\n\n# -------------------------------------------------------------------\n# call DocumentWriter and Story to fill our rectangle\nmatrix = make_pdf(fileptr, HTML, WHERE)\n# -------------------------------------------------------------------\nsrc = pymupdf.open(\"pdf\", fileptr)  # open DocumentWriter output PDF\nif src.page_count > 1:  # target rect was too small\n    raise ValueError(\"target WHERE too small\")\n\n# its page 0 contains our result\npage.show_pdf_page(WHERE, src, 0)\n\ndoc.ez_save(f\"{root}/mupdf-title-after.pdf\")\n"
  },
  {
    "path": "docs/samples/simple-grid.py",
    "content": "import pymupdf\n\nMEDIABOX = pymupdf.paper_rect(\"letter\")  # output page format: Letter\nGRIDSPACE = pymupdf.Rect(100, 100, 400, 400)\nGRID = pymupdf.make_table(GRIDSPACE, rows=2, cols=2)\nCELLS = [GRID[i][j] for i in range(2) for j in range(2)]\ntext_table = (\"A\", \"B\", \"C\", \"D\")\nwriter = pymupdf.DocumentWriter(__file__.replace(\".py\", \".pdf\"))  # create the writer\n\ndevice = writer.begin_page(MEDIABOX)  # make new page\nfor i, text in enumerate(text_table):\n    story = pymupdf.Story(em=1)\n    body = story.body\n    with body.add_paragraph() as para:\n        para.set_bgcolor(\"#ecc\")\n        para.set_pagebreak_after()  # fills whole cell with bgcolor\n        para.set_align(\"center\")\n        para.set_fontsize(16)\n        para.add_text(f\"\\n\\n\\n{text}\")\n    story.place(CELLS[i])\n    story.draw(device)\n    del story\n\nwriter.end_page()  # finish page\n\nwriter.close()  # close output file\n"
  },
  {
    "path": "docs/samples/story-write-stabilized-links.py",
    "content": "\"\"\"\nDemo script for PyMuPDF's `pymupdf.Story.write_stabilized_with_links()`.\n\n`pymupdf.Story.write_stabilized_links()` is similar to\n`pymupdf.Story.write_stabilized()` except that it creates a PDF `pymupdf.Document`\nthat contains PDF links generated from all internal links in the original html.\n\"\"\"\n\nimport textwrap\n\nimport pymupdf\n\n\ndef rectfn(rect_num, filled):\n    '''\n    We return one rect per page.\n    '''\n    rect = pymupdf.Rect(10, 20, 290, 380)\n    mediabox = pymupdf.Rect(0, 0, 300, 400)\n    #print(f'rectfn(): rect_num={rect_num} filled={filled}')\n    return mediabox, rect, None\n\n\ndef contentfn(positions):\n    '''\n    Returns html content, with a table of contents derived from `positions`.\n    '''\n    ret = ''\n    ret += textwrap.dedent('''\n            <!DOCTYPE html>\n            <body>\n            <h2>Contents</h2>\n            <ul>\n            ''')\n    \n    # Create table of contents with links to all <h1..6> sections in the\n    # document.\n    for position in positions:\n        if position.heading and (position.open_close & 1):\n            text = position.text if position.text else ''\n            if position.id:\n                ret += f\"    <li><a href=\\\"#{position.id}\\\">{text}</a>\\n\"\n            else:\n                ret += f\"    <li>{text}\\n\"\n            ret += f\"        <ul>\\n\"\n            ret += f\"        <li>page={position.page_num}\\n\"\n            ret += f\"        <li>depth={position.depth}\\n\"\n            ret += f\"        <li>heading={position.heading}\\n\"\n            ret += f\"        <li>id={position.id!r}\\n\"\n            ret += f\"        <li>href={position.href!r}\\n\"\n            ret += f\"        <li>rect={position.rect}\\n\"\n            ret += f\"        <li>text={text!r}\\n\"\n            ret += f\"        <li>open_close={position.open_close}\\n\"\n            ret += f\"        </ul>\\n\"\n    \n    ret += '</ul>\\n'\n    \n    # Main content.\n    ret += textwrap.dedent(f'''\n    \n            <h1>First section</h1>\n            <p>Contents of first section.\n            <ul>\n            <li>External <a href=\"https://artifex.com/\">link to https://artifex.com/</a>.\n            <li><a href=\"#idtest\">Link to IDTEST</a>.\n            <li><a href=\"#nametest\">Link to NAMETEST</a>.\n            </ul>\n            \n            <h1>Second section</h1>\n            <p>Contents of second section.\n            <h2>Second section first subsection</h2>\n            \n            <p>Contents of second section first subsection.\n            <p id=\"idtest\">IDTEST\n            \n            <h1>Third section</h1>\n            <p>Contents of third section.\n            <p><a name=\"nametest\">NAMETEST</a>.\n            \n            </body>\n            ''')\n    ret = ret.strip()\n    with open(__file__.replace('.py', '.html'), 'w') as f:\n        f.write(ret)\n    return ret;\n\n\nout_path = __file__.replace('.py', '.pdf')\ndocument = pymupdf.Story.write_stabilized_with_links(contentfn, rectfn)\ndocument.save(out_path)\n"
  },
  {
    "path": "docs/samples/story-write-stabilized.py",
    "content": "\"\"\"\nDemo script for PyMuPDF's `pymupdf.Story.write_stabilized()`.\n\n`pymupdf.Story.write_stabilized()` is similar to `pymupdf.Story.write()`,\nexcept instead of taking a fixed html document, it does iterative layout\nof dynamically-generated html content (provided by a callback) to a\n`pymupdf.DocumentWriter`.\n\nFor example this allows one to add a dynamically-generated table of contents\nsection while ensuring that page numbers are patched up until stable.\n\"\"\"\n\nimport textwrap\n\nimport pymupdf\n\n\ndef rectfn(rect_num, filled):\n    '''\n    We return one rect per page.\n    '''\n    rect = pymupdf.Rect(10, 20, 290, 380)\n    mediabox = pymupdf.Rect(0, 0, 300, 400)\n    #print(f'rectfn(): rect_num={rect_num} filled={filled}')\n    return mediabox, rect, None\n\n\ndef contentfn(positions):\n    '''\n    Returns html content, with a table of contents derived from `positions`.\n    '''\n    ret = ''\n    ret += textwrap.dedent('''\n            <!DOCTYPE html>\n            <body>\n            <h2>Contents</h2>\n            <ul>\n            ''')\n    \n    # Create table of contents with links to all <h1..6> sections in the\n    # document.\n    for position in positions:\n        if position.heading and (position.open_close & 1):\n            text = position.text if position.text else ''\n            if position.id:\n                ret += f\"    <li><a href=\\\"#{position.id}\\\">{text}</a>\\n\"\n            else:\n                ret += f\"    <li>{text}\\n\"\n            ret += f\"        <ul>\\n\"\n            ret += f\"        <li>page={position.page_num}\\n\"\n            ret += f\"        <li>depth={position.depth}\\n\"\n            ret += f\"        <li>heading={position.heading}\\n\"\n            ret += f\"        <li>id={position.id!r}\\n\"\n            ret += f\"        <li>href={position.href!r}\\n\"\n            ret += f\"        <li>rect={position.rect}\\n\"\n            ret += f\"        <li>text={text!r}\\n\"\n            ret += f\"        <li>open_close={position.open_close}\\n\"\n            ret += f\"        </ul>\\n\"\n    \n    ret += '</ul>\\n'\n    \n    # Main content.\n    ret += textwrap.dedent(f'''\n    \n            <h1>First section</h1>\n            <p>Contents of first section.\n            \n            <h1>Second section</h1>\n            <p>Contents of second section.\n            <h2>Second section first subsection</h2>\n            \n            <p>Contents of second section first subsection.\n            \n            <h1>Third section</h1>\n            <p>Contents of third section.\n            \n            </body>\n            ''')\n    ret = ret.strip()\n    with open(__file__.replace('.py', '.html'), 'w') as f:\n        f.write(ret)\n    return ret;\n\n\nout_path = __file__.replace('.py', '.pdf')\nwriter = pymupdf.DocumentWriter(out_path)\npymupdf.Story.write_stabilized(writer, contentfn, rectfn)\nwriter.close()\n"
  },
  {
    "path": "docs/samples/story-write.py",
    "content": "\"\"\"\nDemo script for PyMuPDF's `Story.write()` method.\n\nThis is a way of laying out a story into a PDF document, that avoids the need\nto write a loop that calls `story.place()` and `story.draw()`.\n\nInstead just a single function call is required, albeit with a `rectfn()`\ncallback that returns the rectangles into which the story is placed.\n\"\"\"\n\nimport html\n\nimport pymupdf\n\n\n# Create html containing multiple copies of our own source code.\n#\nwith open(__file__) as f:\n    text = f.read()\ntext = html.escape(text)\nhtml = f'''\n<!DOCTYPE html>\n<body>\n\n<h1>Contents of {__file__}</h1>\n\n<h2>Normal</h2>\n<pre>\n{text}\n</pre>\n\n<h2>Strong</h2>\n<strong>\n<pre>\n{text}\n</pre>\n</strong>\n\n<h2>Em</h2>\n<em>\n<pre>\n{text}\n</pre>\n</em>\n\n</body>\n'''\n\n\ndef rectfn(rect_num, filled):\n    '''\n    We return four rectangles per page in this order:\n    \n        1 3\n        2 4\n    '''\n    page_w = 800\n    page_h = 600\n    margin = 50\n    rect_w = (page_w - 3*margin) / 2\n    rect_h = (page_h - 3*margin) / 2\n    \n    if rect_num % 4 == 0:\n        # New page.\n        mediabox = pymupdf.Rect(0, 0, page_w, page_h)\n    else:\n        mediabox = None\n    # Return one of four rects in turn.\n    rect_x = margin + (rect_w+margin) * ((rect_num // 2) % 2)\n    rect_y = margin + (rect_h+margin) * (rect_num % 2)\n    rect = pymupdf.Rect(rect_x, rect_y, rect_x + rect_w, rect_y + rect_h)\n    #print(f'rectfn(): rect_num={rect_num} filled={filled}. Returning: rect={rect}')\n    return mediabox, rect, None\n\nstory = pymupdf.Story(html, em=8)\n\nout_path = __file__.replace('.py', '.pdf')\nwriter = pymupdf.DocumentWriter(out_path)\n\nstory.write(writer, rectfn)\nwriter.close()\n"
  },
  {
    "path": "docs/samples/table01.py",
    "content": "\"\"\"\nDemo script for basic HTML table support in Story objects\n\nOutputs a table with three columns that fits on one Letter page.\nThe content of each row is filled via the Story's template mechanism.\nColumn widths and row heights are automatically computed by MuPDF.\nSome styling via a CSS source is also demonstrated:\n\n- The table header row has a gray background\n- Each cell shows a border at its top\n- The Story's body uses the sans-serif font family\n- The text of one of the columns is set to blue\n\nDependencies\n-------------\nPyMuPDF v1.22.0 or later\n\"\"\"\nimport pymupdf\n\ntable_text = (  # the content of each table row\n    (\n        \"Length\",\n        \"integer\",\n        \"\"\"(Required) The number of bytes from the beginning of the line following the keyword stream to the last byte just before the keyword endstream. (There may be an additional EOL marker, preceding endstream, that is not included in the count and is not logically part of the stream data.) See “Stream Extent,” above, for further discussion.\"\"\",\n    ),\n    (\n        \"Filter\",\n        \"name or array\",\n        \"\"\"(Optional) The name of a filter to be applied in processing the stream data found between the keywords stream and endstream, or an array of such names. Multiple filters should be specified in the order in which they are to be applied.\"\"\",\n    ),\n    (\n        \"FFilter\",\n        \"name or array\",\n        \"\"\"(Optional; PDF 1.2) The name of a filter to be applied in processing the data found in the stream's external file, or an array of such names. The same rules apply as for Filter.\"\"\",\n    ),\n    (\n        \"FDecodeParms\",\n        \"dictionary or array\",\n        \"\"\"(Optional; PDF 1.2) A parameter dictionary, or an array of such dictionaries, used by the filters specified by FFilter. The same rules apply as for DecodeParms.\"\"\",\n    ),\n    (\n        \"DecodeParms\",\n        \"dictionary or array\",\n        \"\"\"(Optional) A parameter dictionary or an array of such dictionaries, used by the filters specified by Filter. If there is only one filter and that filter has parameters, DecodeParms must be set to the filter's parameter dictionary unless all the filter's parameters have their default values, in which case the DecodeParms entry may be omitted. If there are multiple filters and any of the filters has parameters set to nondefault values, DecodeParms must be an array with one entry for each filter: either the parameter dictionary for that filter, or the null object if that filter has no parameters (or if all of its parameters have their default values). If none of the filters have parameters, or if all their parameters have default values, the DecodeParms entry may be omitted. (See implementation note 7 in Appendix H.)\"\"\",\n    ),\n    (\n        \"DL\",\n        \"integer\",\n        \"\"\"(Optional; PDF 1.5) A non-negative integer representing the number of bytes in the decoded (defiltered) stream. It can be used to determine, for example, whether enough disk space is available to write a stream to a file.\\nThis value should be considered a hint only; for some stream filters, it may not be possible to determine this value precisely.\"\"\",\n    ),\n    (\n        \"F\",\n        \"file specification\",\n        \"\"\"(Optional; PDF 1.2) The file containing the stream data. If this entry is present, the bytes between stream and endstream are ignored, the filters are specified by FFilter rather than Filter, and the filter parameters are specified by FDecodeParms rather than DecodeParms. However, the Length entry should still specify the number of those bytes. (Usually, there are no bytes and Length is 0.) (See implementation note 46 in Appendix H.)\"\"\",\n    ),\n)\n\n# Only a minimal HTML source is required to provide the Story's working\nHTML = \"\"\"\n<html>\n<body><h2>TABLE 3.4 Entries common to all stream dictionaries</h2>\n<table>\n    <tr>\n        <th>KEY</th><th>TYPE</th><th>VALUE</th>\n    </tr>\n    <tr id=\"row\">\n        <td id=\"col0\"></td><td id=\"col1\"></td><td id=\"col2\"></td>\n    </tr>\n\"\"\"\n\n\"\"\"\n---------------------------------------------------------------------\nJust for demo purposes, set:\n- header cell background to gray\n- text color in col1 to blue\n- a border line at the top of all table cells\n- all text to the sans-serif font\n---------------------------------------------------------------------\n\"\"\"\nCSS = \"\"\"th {\n    background-color: #aaa;\n}\n\ntd[id=\"col1\"] {\n    color: blue;\n}\n\ntd, tr {\n    border: 1px solid black;\n    border-right-width: 0px;\n    border-left-width: 0px;\n    border-bottom-width: 0px;\n}\nbody {\n    font-family: sans-serif;\n}\n\"\"\"\n\nstory = pymupdf.Story(HTML, user_css=CSS)  # define the Story\nbody = story.body  # access the HTML <body> of it\ntemplate = body.find(None, \"id\", \"row\")  # find the template with name \"row\"\nparent = template.parent  # access its parent i.e., the <table>\n\nfor col0, col1, col2 in table_text:\n    row = template.clone()  # make a clone of the row template\n    # add text to each cell in the duplicated row\n    row.find(None, \"id\", \"col0\").add_text(col0)\n    row.find(None, \"id\", \"col1\").add_text(col1)\n    row.find(None, \"id\", \"col2\").add_text(col2)\n    parent.append_child(row)  # add new row to <table>\ntemplate.remove()  # remove the template\n\n# Story is ready - output it via a writer\nwriter = pymupdf.DocumentWriter(__file__.replace(\".py\", \".pdf\"), \"compress\")\nmediabox = pymupdf.paper_rect(\"letter\")  # size of one output page\nwhere = mediabox + (36, 36, -36, -36)  # use this sub-area for the content\n\nmore = True  # detects end of output\nwhile more:\n    dev = writer.begin_page(mediabox)  # start a page, returning a device\n    more, filled = story.place(where)  # compute content fitting into \"where\"\n    story.draw(dev)  # output it to the page\n    writer.end_page()  # finalize the page\nwriter.close()  # close the output\n"
  },
  {
    "path": "docs/samples/text-lister.py",
    "content": "import sys\n\nimport pymupdf\n\n\ndef flags_decomposer(flags):\n    \"\"\"Make font flags human readable.\"\"\"\n    l = []\n    if flags & 2 ** 0:\n        l.append(\"superscript\")\n    if flags & 2 ** 1:\n        l.append(\"italic\")\n    if flags & 2 ** 2:\n        l.append(\"serifed\")\n    else:\n        l.append(\"sans\")\n    if flags & 2 ** 3:\n        l.append(\"monospaced\")\n    else:\n        l.append(\"proportional\")\n    if flags & 2 ** 4:\n        l.append(\"bold\")\n    return \", \".join(l)\n\n\ndoc = pymupdf.open(sys.argv[1])\npage = doc[0]\n\n# read page text as a dictionary, suppressing extra spaces in CJK fonts\nblocks = page.get_text(\"dict\", flags=11)[\"blocks\"]\nfor b in blocks:  # iterate through the text blocks\n    for l in b[\"lines\"]:  # iterate through the text lines\n        for s in l[\"spans\"]:  # iterate through the text spans\n            print(\"\")\n            s_font = s['font']\n            s_flags = flags_decomposer(s['flags'])\n            s_size = s['size']\n            s_color = s['color']\n            print(f\"Text: '{s['text']}'\")  # simple print of text\n            print(f\"Font: '{s_font}' ({s_flags}), size {s_size}, color #{s_color:06x}\")\n"
  },
  {
    "path": "docs/shape.rst",
    "content": ".. include:: header.rst\n\n.. _Shape:\n\nShape\n================\n\n|pdf_only_class|\n\nThis class allows creating interconnected graphical elements on a PDF page. Its methods have the same meaning and name as the corresponding :ref:`Page` methods.\n\nIn fact, each :ref:`Page` draw method is just a convenience wrapper for (1) one shape draw method, (2) the :meth:`Shape.finish` method, and (3) the :meth:`Shape.commit` method. For page text insertion, only the :meth:`Shape.commit` method is invoked. If many draw and text operations are executed for a page, you should always consider using a Shape object.\n\nSeveral draw methods can be executed in a row and each one of them will contribute to one drawing. Once the drawing is complete, the :meth:`Shape.finish` method must be invoked to apply color, dashing, width, morphing and other attributes.\n\n**Draw** methods of this class (and :meth:`Shape.insert_textbox`) are logging the area they are covering in a rectangle (:attr:`Shape.rect`). This property can for instance be used to set :attr:`Page.cropbox_position`.\n\n**Text insertions** :meth:`Shape.insert_text` and :meth:`Shape.insert_textbox` implicitly execute a \"finish\" and therefore only require :meth:`Shape.commit` to become effective. As a consequence, both include parameters for controlling properties like colors, etc.\n\n================================ =====================================================\n**Method / Attribute**             **Description**\n================================ =====================================================\n:meth:`Shape.commit`             update the page's contents\n:meth:`Shape.draw_bezier`        draw a cubic Bezier curve\n:meth:`Shape.draw_circle`        draw a circle around a point\n:meth:`Shape.draw_curve`         draw a cubic Bezier using one helper point\n:meth:`Shape.draw_line`          draw a line\n:meth:`Shape.draw_oval`          draw an ellipse\n:meth:`Shape.draw_polyline`      connect a sequence of points\n:meth:`Shape.draw_quad`          draw a quadrilateral\n:meth:`Shape.draw_rect`          draw a rectangle\n:meth:`Shape.draw_sector`        draw a circular sector or piece of pie\n:meth:`Shape.draw_squiggle`      draw a squiggly line\n:meth:`Shape.draw_zigzag`        draw a zigzag line\n:meth:`Shape.finish`             finish a set of draw commands\n:meth:`Shape.insert_text`        insert text lines\n:meth:`Shape.insert_textbox`     fit text into a rectangle\n:attr:`Shape.doc`                stores the page's document\n:attr:`Shape.draw_cont`          draw commands since last :meth:`Shape.finish`\n:attr:`Shape.height`             stores the page's height\n:attr:`Shape.lastPoint`          stores the current point\n:attr:`Shape.page`               stores the owning page\n:attr:`Shape.rect`               rectangle surrounding drawings\n:attr:`Shape.text_cont`          accumulated text insertions\n:attr:`Shape.totalcont`          accumulated string to be stored in :data:`contents`\n:attr:`Shape.width`              stores the page's width\n================================ =====================================================\n\n**Class API**\n\n.. class:: Shape\n\n   .. method:: __init__(self, page)\n\n      Create a new drawing. During importing PyMuPDF, the *pymupdf.Page* object is being given the convenience method *new_shape()* to construct a *Shape* object. During instantiation, a check will be made whether we do have a PDF page. An exception is otherwise raised.\n\n      :arg page: an existing page of a PDF document.\n      :type page: :ref:`Page`\n\n   .. method:: draw_line(p1, p2)\n\n      Draw a line from :data:`point_like` objects *p1* to *p2*.\n\n      :arg point_like p1: starting point\n\n      :arg point_like p2: end point\n\n      :rtype: :ref:`Point`\n      :returns: the end point, *p2*.\n\n   .. index::\n      pair: breadth; draw_squiggle\n\n   .. method:: draw_squiggle(p1, p2, breadth=2)\n\n      Draw a squiggly (wavy, undulated) line from :data:`point_like` objects *p1* to *p2*. An integer number of full wave periods will always be drawn, one period having a length of *4 * breadth*. The breadth parameter will be adjusted as necessary to meet this condition. The drawn line will always turn \"left\" when leaving *p1* and always join *p2* from the \"right\".\n\n      :arg point_like p1: starting point\n\n      :arg point_like p2: end point\n\n      :arg float breadth: the amplitude of each wave. The condition *2 * breadth < abs(p2 - p1)* must be true to fit in at least one wave. See the following picture, which shows two points connected by one full period.\n\n      :rtype: :ref:`Point`\n      :returns: the end point, *p2*.\n\n      .. image:: images/img-breadth.*\n\n      Here is an example of three connected lines, forming a closed, filled triangle. Little arrows indicate the stroking direction.\n\n         >>> import pymupdf\n         >>> doc=pymupdf.open()\n         >>> page=doc.new_page()\n         >>> r = pymupdf.Rect(100, 100, 300, 200)\n         >>> shape=page.new_shape()\n         >>> shape.draw_squiggle(r.tl, r.tr)\n         >>> shape.draw_squiggle(r.tr, r.br)\n         >>> shape.draw_squiggle(r.br, r.tl)\n         >>> shape.finish(color=(0, 0, 1), fill=(1, 1, 0))\n         >>> shape.commit()\n         >>> doc.save(\"x.pdf\")\n\n      .. image:: images/img-squiggly.*\n\n      .. note:: Waves drawn are **not** trigonometric (sine / cosine). If you need that, have a look at `draw.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/draw-sines/draw.py>`_.\n\n   .. index::\n      pair: breadth; draw_zigzag\n\n   .. method:: draw_zigzag(p1, p2, breadth=2)\n\n      Draw a zigzag line from :data:`point_like` objects *p1* to *p2*. Otherwise works exactly like :meth:`Shape.draw_squiggle`.\n\n      :arg point_like p1: starting point\n\n      :arg point_like p2: end point\n\n      :arg float breadth: the amplitude of the movement. The condition *2 * breadth < abs(p2 - p1)* must be true to fit in at least one period.\n\n      :rtype: :ref:`Point`\n      :returns: the end point, *p2*.\n\n   .. method:: draw_polyline(points)\n\n      Draw several connected lines between points contained in the sequence *points*. This can be used for creating arbitrary polygons by setting the last item equal to the first one.\n\n      :arg sequence points: a sequence of :data:`point_like` objects. Its length must at least be 2 (in which case it is equivalent to *draw_line()*).\n\n      :rtype: :ref:`Point`\n      :returns: *points[-1]* -- the last point in the argument sequence.\n\n   .. method:: draw_bezier(p1, p2, p3, p4)\n\n      Draw a standard cubic Bézier curve from *p1* to *p4*, using *p2* and *p3* as control points.\n\n      All arguments are :data:`point_like` objects.\n\n      :rtype: :ref:`Point`\n      :returns: the end point, *p4*.\n\n      .. note:: The points do not need to be different -- experiment a bit with some of them being equal!\n\n      Example:\n\n      .. image:: images/img-drawBezier.*\n\n   .. method:: draw_oval(tetra)\n\n      Draw an \"ellipse\" inside the given tetragon (quadrilateral). If it is a square, a regular circle is drawn, a general rectangle will result in an ellipse. If a quadrilateral is used instead, a plethora of shapes can be the result.\n\n      The drawing starts and ends at the middle point of the line `bottom-left -> top-left` corners in an anti-clockwise movement.\n\n      :arg rect_like,quad_like tetra: :data:`rect_like` or :data:`quad_like`.\n\n          *Changed in version 1.14.5:*  Quads are now also supported.\n\n      :rtype: :ref:`Point`\n      :returns: the middle point of line `rect.bl -> rect.tl`, or resp. `quad.ll -> quad.ul`. Look at just a few examples here, or at the *quad-show?.py* scripts in the PyMuPDF-Utilities repository.\n\n      .. image:: images/img-drawquad.*\n         :scale: 50\n\n   .. method:: draw_circle(center, radius)\n\n      Draw a circle given its center and radius. The drawing starts and ends at point `center - (radius, 0)` in an **anti-clockwise** movement. This point is the middle of the enclosing square's left side.\n\n      This is a shortcut for `draw_sector(center, start, 360, fullSector=False)`. To draw the same circle in a **clockwise** movement, use `-360` as degrees.\n\n      :arg point_like center: the center of the circle.\n\n      :arg float radius: the radius of the circle. Must be positive.\n\n      :rtype: :ref:`Point`\n      :returns: `Point(center.x - radius, center.y)`.\n\n         .. image:: images/img-drawcircle.*\n            :scale: 60\n\n   .. method:: draw_curve(p1, p2, p3)\n\n      A special case of *draw_bezier()*: Draw a cubic Bezier curve from *p1* to *p3*. On each of the two lines `p1 -> p2` and `p3 -> p2` one control point is generated. Both control points will therefore be on the same side of the line `p1 -> p3`. This guaranties that the curve's curvature does not change its sign. If the lines to p2 intersect with an angle of 90 degrees, then the resulting curve is a quarter ellipse (resp. quarter circle, if of same length).\n\n      All arguments are :data:`point_like`.\n\n      :rtype: :ref:`Point`\n      :returns: the end point, *p3*. The following is a filled quarter ellipse segment. The yellow area is oriented **clockwise:**\n\n         .. image:: images/img-drawCurve.png\n            :align: center\n\n\n   .. index::\n      pair: fullSector; draw_sector\n\n   .. method:: draw_sector(center, point, angle, fullSector=True)\n\n      Draw a circular sector, optionally connecting the arc to the circle's center (like a piece of pie).\n\n      :arg point_like center: the center of the circle.\n\n      :arg point_like point: one of the two end points of the pie's arc segment. The other one is calculated from the *angle*.\n\n      :arg float angle: the angle of the sector in degrees. Used to calculate the other end point of the arc. Depending on its sign, the arc is drawn anti-clockwise (positive) or clockwise.\n\n      :arg bool fullSector: whether to draw connecting lines from the ends of the arc to the circle center. If a fill color is specified, the full \"pie\" is colored, otherwise just the sector.\n\n      :rtype: :ref:`Point`\n      :returns: the other end point of the arc. Can be used as starting point for a following invocation to create logically connected pies charts. Examples:\n\n         .. image:: images/img-drawSector1.*\n\n         .. image:: images/img-drawSector2.*\n\n\n   .. method:: draw_rect(rect, *, radius=None)\n\n      * Changed in v1.22.0: Added parameter *radius*.\n\n      Draw a rectangle. The drawing starts and ends at the top-left corner in an anti-clockwise movement.\n\n      :arg rect_like rect: where to put the rectangle on the page.\n      :arg multiple radius: draw rounded rectangle corners. If not `None`, specifies the radius of the curvature as a percentage of a rectangle side length. This must one or (a tuple of) two floats `0 < radius <= 0.5`, where 0.5 corresponds to 50% of the respective side. If a float, the radius of the curvature is computed as `radius * min(width, height)`, drawing the corner's perimeter as a quarter circle. If a tuple `(rx, ry)` is given, then the curvature is asymmetric with respect to the horizontal and vertical directions. A value of `radius=(0.5, 0.5)` draws an ellipse.\n\n      :rtype: :ref:`Point`\n      :returns: top-left corner of the rectangle.\n\n   .. method:: draw_quad(quad)\n\n      Draw a quadrilateral. The drawing starts and ends at the top-left corner (:attr:`Quad.ul`) in an anti-clockwise movement. It is a shortcut of :meth:`Shape.draw_polyline` with the argument `(ul, ll, lr, ur, ul)`.\n\n      :arg quad_like quad: where to put the tetragon on the page.\n\n      :rtype: :ref:`Point`\n      :returns: :attr:`Quad.ul`.\n\n   .. index::\n      pair: closePath; finish\n      pair: color; finish\n      pair: dashes; finish\n      pair: even_odd; finish\n      pair: fill; finish\n      pair: lineCap; finish\n      pair: lineJoin; finish\n      pair: morph; finish\n      pair: width; finish\n      pair: stroke_opacity; finish\n      pair: fill_opacity; finish\n      pair: oc; finish\n\n\n   .. method:: finish(width=1, color=(0,), fill=None, lineCap=0, lineJoin=0, dashes=None, closePath=True, even_odd=False, morph=(fixpoint, matrix), stroke_opacity=1, fill_opacity=1, oc=0)\n\n      Finish a set of *draw*()* methods by applying :ref:`CommonParms` to all of them.\n      \n      It has **no effect on** :meth:`Shape.insert_text` and :meth:`Shape.insert_textbox`.\n\n      The method also supports **morphing the compound drawing** using :ref:`Point` *fixpoint* and :ref:`matrix` *matrix*.\n\n      :arg sequence morph: morph the text or the compound drawing around some arbitrary :ref:`Point` *fixpoint* by applying :ref:`Matrix` *matrix* to it. This implies that *fixpoint* is a **fixed point** of this operation: it will not change its position. Default is no morphing (``None``). The matrix can contain any values in its first 4 components, *matrix.e == matrix.f == 0* must be true, however. This means that any combination of scaling, shearing, rotating, flipping, etc. is possible, but translations are not.\n\n      :arg float stroke_opacity: *(new in v1.18.1)* set transparency for stroke colors. Value < 0 or > 1 will be ignored. Default is 1 (intransparent).\n      :arg float fill_opacity: *(new in v1.18.1)* set transparency for fill colors. Default is 1 (intransparent).\n\n      :arg bool even_odd: request the **\"even-odd rule\"** for filling operations. Default is ``False``, so that the **\"nonzero winding number rule\"** is used. These rules are alternative methods to apply the fill color where areas overlap. Only with fairly complex shapes a different behavior is to be expected with these rules. For an in-depth explanation, see :ref:`AdobeManual`, pp. 137 ff. Here is an example to demonstrate the difference.\n\n      :arg int oc: *(new in v1.18.4)* the :data:`xref` number of an :data:`OCG` or :data:`OCMD` to make this drawing conditionally displayable.\n\n      .. image:: images/img-even-odd.*\n\n      .. note:: For each pixel in a shape, the following will happen:\n\n         1. Rule **\"even-odd\"** counts, how many areas contain the pixel. If this count is **odd,** the pixel is regarded **inside** the shape, if it is **even**, the pixel is **outside**.\n\n         2. The default rule **\"nonzero winding\"** in addition looks at the *\"orientation\"* of each area containing the pixel: it **adds 1** if an area is drawn anti-clockwise and it **subtracts 1** for clockwise areas. If the result is zero, the pixel is regarded **outside,** pixels with a non-zero count are **inside** the shape.\n\n         Of the four shapes in above image, the top two each show three circles drawn in standard manner (anti-clockwise, look at the arrows). The lower two shapes contain one (the top-left) circle drawn clockwise. As can be seen, area orientation is irrelevant for the right column (even-odd rule).\n\n   .. index::\n      pair: border_width; insert_text\n      pair: color; insert_text\n      pair: encoding; insert_text\n      pair: fill; insert_text\n      pair: fontfile; insert_text\n      pair: fontname; insert_text\n      pair: fontsize; insert_text\n      pair: lineheight; insert_text\n      pair: morph; insert_text\n      pair: render_mode; insert_text\n      pair: miter_limit; insert_text\n      pair: rotate; insert_text\n      pair: stroke_opacity; insert_text\n      pair: fill_opacity; insert_text\n      pair: oc; insert_text\n\n   .. method:: insert_text(point, text, *, fontsize=11, fontname=\"helv\", fontfile=None, set_simple=False, encoding=TEXT_ENCODING_LATIN, color=None, lineheight=None, fill=None, render_mode=0, miter_limit=1, border_width=1, rotate=0, morph=None, stroke_opacity=1, fill_opacity=1, oc=0)\n\n      Insert text lines starting at ``point``.\n\n      :arg point_like point: the bottom-left position of the first character of *text* in pixels. It is important to understand, how this works in conjunction with the *rotate* parameter. Please have a look at the following picture. The small red dots indicate the positions of *point* in each of the four possible cases.\n\n         .. image:: images/img-inserttext.*\n            :scale: 33\n\n      :arg str/sequence text: the text to be inserted. May be specified as either a string type or as a sequence type. For sequences, or strings containing line breaks ``\\n``, several lines will be inserted. No care will be taken if lines are too wide, but the number of inserted lines will be limited by \"vertical\" space on the page (in the sense of reading direction as established by the *rotate* parameter). Any rest of *text* is discarded -- the return code however contains the number of inserted lines.\n\n      :arg float lineheight: a factor to override the line height calculated from font properties. If not `None`, a line height of `fontsize * lineheight` will be used.\n      :arg float stroke_opacity: *(new in v1.18.1)* set transparency for stroke colors (the **border line** of a character). Only  `0 <= value <= 1` will be considered. Default is 1 (intransparent).\n      :arg float fill_opacity: *(new in v1.18.1)* set transparency for fill colors. Default is 1 (intransparent). Use this value to control transparency of the text color. Stroke opacity **only** affects the border line of characters.\n\n      :arg int rotate: determines whether to rotate the text. Acceptable values are multiples of 90 degrees. Default is 0 (no rotation), meaning horizontal text lines oriented from left to right. 180 means text is shown upside down from **right to left**. 90 means anti-clockwise rotation, text running **upwards**. 270 (or -90) means clockwise rotation, text running **downwards**. In any case, *point* specifies the bottom-left coordinates of the first character's rectangle. Multiple lines, if present, always follow the reading direction established by this parameter. So line 2 is located **above** line 1 in case of `rotate = 180`, etc.\n\n      :arg int oc: *(new in v1.18.4)* the :data:`xref` number of an :data:`OCG` or :data:`OCMD` to make this text conditionally displayable.\n\n      :rtype: int\n      :returns: number of lines inserted.\n\n      For a description of the other parameters see :ref:`CommonParms`.\n\n   .. index::\n      pair: align; insert_textbox\n      pair: border_width; insert_textbox\n      pair: color; insert_textbox\n      pair: encoding; insert_textbox\n      pair: expandtabs; insert_textbox\n      pair: fill; insert_textbox\n      pair: fontfile; insert_textbox\n      pair: fontname; insert_textbox\n      pair: fontsize; insert_textbox\n      pair: lineheight; insert_textbox\n      pair: morph; insert_textbox\n      pair: render_mode; insert_textbox\n      pair: miter_limit; insert_textbox\n      pair: rotate; insert_textbox\n      pair: oc; insert_textbox\n\n   .. method:: insert_textbox( \\\n                rect, \\\n                buffer, \\\n                *, \\\n                align=TEXT_ALIGN_LEFT, \\\n                border_width=1, \\\n                color=None, \\\n                encoding=TEXT_ENCODING_LATIN, \\\n                expandtabs=8, \\\n                fill=None, \\\n                fill_opacity=1, \\\n                fontfile=None, \\\n                fontname=\"helv\", \\\n                fontsize=11, \\\n                lineheight=None, \\\n                miter_limit=1, \\\n                morph=None, \\\n                oc=0, \\\n                render_mode=0, \\\n                rotate=0, \\\n                set_simple=False, \\\n                stroke_opacity=1, \\\n                )\n      \n      PDF only: Insert text into the specified rectangle. The text will be split into lines and words and then filled into the available space, starting from one of the four rectangle corners, which depends on `rotate`. Line feeds and multiple space will be respected.\n\n      :arg rect_like rect: the area to use. It must be finite and not empty.\n\n      :arg str/sequence buffer: the text to be inserted. Must be specified as a string or a sequence of strings. Line breaks are respected also when occurring in a sequence entry.\n\n      :arg int align: align each text line. Default is 0 (left). Centered, right and justified are the other supported options, see :ref:`TextAlign`. Please note that the effect of parameter value *TEXT_ALIGN_JUSTIFY* is only achievable with \"simple\" (single-byte) fonts (including the :ref:`Base-14-Fonts`).\n\n      :arg int expandtabs: controls handling of tab characters ``\\t`` using the `string.expandtabs()` method **per each line**.\n\n      :arg float fill_opacity: *(new in v1.18.1)* set transparency for fill colors. Default is 1 (intransparent). Use this value to control transparency of the text color. Stroke opacity **only** affects the border line of characters.\n\n      :arg float lineheight: a factor to override the line height calculated from font properties. If not `None`, a line height of `fontsize * lineheight` will be used.\n\n      :arg int oc: *(new in v1.18.4)* the :data:`xref` number of an :data:`OCG` or :data:`OCMD` to make this text conditionally displayable.\n\n      :arg int rotate: requests text to be rotated in the rectangle. This value must be a multiple of 90 degrees. Default is 0 (no rotation). Effectively, the four values `0`, `90`, `180` and `270` (= `-90`) are processed, each causing the text to start in a different rectangle corner. Bottom-left is `90`, bottom-right is `180`, and `-90 / 270` is top-right. See the example how text is filled in a rectangle. This argument takes precedence over morphing. See the second example, which shows text first rotated left by `90` degrees and then the whole rectangle rotated clockwise around is lower left corner.\n\n      :arg float stroke_opacity: *(new in v1.18.1)* set transparency for stroke colors. Negative values and values > 1 will be ignored. Default is 1 (intransparent).\n      \n      :rtype: float\n      :returns:\n          **If positive or zero**: successful execution. The value returned is the unused rectangle line space in pixels. This may safely be ignored -- or be used to optimize the rectangle, position subsequent items, etc.\n\n          **If negative**: no execution. The value returned is the space deficit to store text lines. Enlarge rectangle, decrease *fontsize*, decrease text amount, etc.\n\n      .. image:: images/img-rotate.*\n\n      .. image:: images/img-rot+morph.*\n\n      For a description of the other parameters see :ref:`CommonParms`.\n\n\n   .. index::\n      pair: overlay; commit\n\n   .. method:: commit(overlay=True)\n\n      Update the page's :data:`contents` with the accumulated drawings, followed by any text insertions. If text overlaps drawings, it will be written on top of the drawings.\n      \n      .. warning:: **Do not forget to execute this method:**\n      \n            If a shape is **not committed, it will be ignored and the page will not be changed!**\n\n      The method will reset attributes :attr:`Shape.rect`, :attr:`lastPoint`, :attr:`draw_cont`, :attr:`text_cont` and :attr:`totalcont`. Afterwards, the shape object can be reused for the **same page**.\n\n      :arg bool overlay: determine whether to put content in foreground (default) or background. Relevant only, if the page already has a non-empty :data:`contents` object.\n\n   **---------- Attributes ----------**\n\n   .. attribute:: doc\n\n      For reference only: the page's document.\n\n      :type: :ref:`Document`\n\n   .. attribute:: page\n\n      For reference only: the owning page.\n\n      :type: :ref:`Page`\n\n   .. attribute:: height\n\n      Copy of the page's height\n\n      :type: float\n\n   .. attribute:: width\n\n      Copy of the page's width.\n\n      :type: float\n\n   .. attribute:: draw_cont\n\n      Accumulated command buffer for **draw methods** since last finish. Every finish method will append its commands to :attr:`Shape.totalcont`.\n\n      :type: str\n\n   .. attribute:: text_cont\n\n      Accumulated text buffer. All **text insertions** go here. This buffer will be appended to :attr:`totalcont` :meth:`Shape.commit`, so that text will never be covered by drawings in the same Shape.\n\n      :type: str\n\n   .. attribute:: rect\n\n      Rectangle surrounding drawings. This attribute is at your disposal and may be changed at any time. Its value is set to ``None`` when a shape is created or committed. Every *draw** method, and :meth:`Shape.insert_textbox` update this property (i.e. **enlarge** the rectangle as needed). **Morphing** operations, however (:meth:`Shape.finish`, :meth:`Shape.insert_textbox`) are ignored.\n\n      A typical use of this attribute would be setting :attr:`Page.cropbox_position` to this value, when you are creating shapes for later or external use. If you have not manipulated the attribute yourself, it should reflect a rectangle that contains all drawings so far.\n\n      If you have used morphing and need a rectangle containing the morphed objects, use the following code::\n\n         >>> # assuming ...\n         >>> morph = (point, matrix)\n         >>> # ... recalculate the shape rectangle like so:\n         >>> shape.rect = (shape.rect - pymupdf.Rect(point, point)) * ~matrix + pymupdf.Rect(point, point)\n\n      :type: :ref:`Rect`\n\n   .. attribute:: totalcont\n\n      Total accumulated command buffer for draws and text insertions. This will be used by :meth:`Shape.commit`.\n\n      :type: str\n\n   .. attribute:: lastPoint\n\n      For reference only: the current point of the drawing path. It is ``None`` at *Shape* creation and after each *finish()* and *commit()*.\n\n      :type: :ref:`Point`\n\nUsage\n------\nA drawing object is constructed by *shape = page.new_shape()*. After this, as many draw, finish and text insertions methods as required may follow. Each sequence of draws must be finished before the drawing is committed. The overall coding pattern looks like this::\n\n   >>> shape = page.new_shape()\n   >>> shape.draw1(...)\n   >>> shape.draw2(...)\n   >>> ...\n   >>> shape.finish(width=..., color=..., fill=..., morph=...)\n   >>> shape.draw3(...)\n   >>> shape.draw4(...)\n   >>> ...\n   >>> shape.finish(width=..., color=..., fill=..., morph=...)\n   >>> ...\n   >>> shape.insert_text*\n   >>> ...\n   >>> shape.commit()\n   >>> ....\n\n.. note::\n\n   1. Each *finish()* combines the preceding draws into one logical shape, giving it common colors, line width, morphing, etc. If *closePath* is specified, it will also connect the end point of the last draw with the starting point of the first one.\n\n   2. To successfully create compound graphics, let each draw method use the end point of the previous one as its starting point. In the above pseudo code, *draw2* should hence use the returned :ref:`Point` of *draw1* as its starting point. Failing to do so, would automatically start a new path and *finish()* may not work as expected (but it won't complain either).\n\n   3. Text insertions may occur anywhere before the commit (they neither touch :attr:`Shape.draw_cont` nor :attr:`Shape.lastPoint`). They are appended to *Shape.totalcont* directly, whereas draws will be appended by *Shape.finish*.\n\n   4. Each *commit* takes all text insertions and shapes and places them in foreground or background on the page -- thus providing a way to control graphical layers.\n\n   5. **Only** *commit* **will update** the page's contents, the other methods are basically string manipulations.\n\nExamples\n---------\n1. Create a full circle of pieces of pie in different colors::\n\n      shape = page.new_shape()  # start a new shape\n      cols = (...)  # a sequence of RGB color triples\n      pieces = len(cols)  # number of pieces to draw\n      beta = 360. / pieces  # angle of each piece of pie\n      center = pymupdf.Point(...)  # center of the pie\n      p0 = pymupdf.Point(...)  # starting point\n      for i in range(pieces):\n          p0 = shape.draw_sector(center, p0, beta,\n                                fullSector=True) # draw piece\n          # now fill it but do not connect ends of the arc\n          shape.finish(fill=cols[i], closePath=False)\n      shape.commit()  # update the page\n\nHere is an example for 5 colors:\n\n.. image:: images/img-cake.*\n\n2. Create a regular n-edged polygon (fill yellow, red border). We use *draw_sector()* only to calculate the points on the circumference, and empty the draw command buffer again before drawing the polygon::\n\n      shape = page.new_shape() # start a new shape\n      beta = -360.0 / n  # our angle, drawn clockwise\n      center = pymupdf.Point(...)  # center of circle\n      p0 = pymupdf.Point(...)  # start here (1st edge)\n      points = [p0]  # store polygon edges\n      for i in range(n):  # calculate the edges\n          p0 = shape.draw_sector(center, p0, beta)\n          points.append(p0)\n      shape.draw_cont = \"\"  # do not draw the circle sectors\n      shape.draw_polyline(points)  # draw the polygon\n      shape.finish(color=(1,0,0), fill=(1,1,0), closePath=False)\n      shape.commit()\n\nHere is the polygon for n = 7:\n\n.. image:: images/img-7edges.*\n\n.. _CommonParms:\n\nCommon Parameters\n-------------------\n\n**fontname** (*str*)\n\n  In general, there are three options:\n\n  1. Use one of the standard :ref:`Base-14-Fonts`. In this case, *fontfile* **must not** be specified and *\"Helvetica\"* is used if this parameter is omitted, too.\n  2. Choose a font already in use by the page. Then specify its **reference** name prefixed with a slash \"/\", see example below.\n  3. Specify a font file present on your system. In this case choose an arbitrary, but new name for this parameter (without \"/\" prefix).\n\n  If inserted text should re-use one of the page's fonts, use its reference name appearing in :meth:`Page.get_fonts` like so:\n\n  Suppose the font list has the item *[1024, 0, 'Type1', 'NimbusMonL-Bold', 'R366']*, then specify *fontname = \"/R366\", fontfile = None* to use font *NimbusMonL-Bold*.\n\n----\n\n**fontfile** (*str*)\n\n  File path of a font existing on your computer. If you specify *fontfile*, make sure you use a *fontname* **not occurring** in the above list. This new font will be embedded in the PDF upon *doc.save()*. Similar to new images, a font file will be embedded only once. A table of MD5 codes for the binary font contents is used to ensure this.\n\n----\n\n**set_simple** (*bool*)\n\n  Fonts installed from files are installed as **Type0** fonts by default. If you want to use 1-byte characters only, set this to true. This setting cannot be reverted. Subsequent changes are ignored.\n\n----\n\n**fontsize** (*float*)\n\n  Font size of text, see: :data:`fontsize`.\n\n----\n\n**dashes** (*str*)\n\n  Causes lines to be drawn dashed. The general format is `\"[n m] p\"` of (up to) 3 floats denoting pixel lengths. ``n`` is the dash length, ``m`` (optional) is the subsequent gap length, and ``p`` (the \"phase\" - **required**, even if 0!) specifies how many pixels should be skipped before the dashing starts. If ``m`` is omitted, it defaults to ``n``.\n  \n  A continuous line (no dashes) is drawn with `\"[] 0\"` or ``None`` or `\"\"`. Examples:\n  \n  * Specifying `\"[3 4] 0\"` means dashes of 3 and gaps of 4 pixels following each other.\n  * `\"[3 3] 0\"` and `\"[3] 0\"` do the same thing.\n  \n  For (the rather complex) details on how to achieve sophisticated dashing effects, see :ref:`AdobeManual`, page 217.\n\n----\n\n**color / fill** (*list, tuple*)\n\n  Stroke and fill colors can be specified as tuples or list of of floats from 0 to 1. These sequences must have a length of 1 (GRAY), 3 (RGB) or 4 (CMYK). For GRAY colorspace, a single float instead of the unwieldy *(float,)* or *[float]* is also accepted. Accept (default) or use `None` to not use the parameter.\n\n  To simplify color specification, method *getColor()* in *pymupdf.utils* may be used to get predefined RGB color triples by name. It accepts a string as the name of the color and returns the corresponding triple. The method knows over 540 color names -- see section :ref:`ColorDatabase`.\n\n  Please note that the term *color* usually means \"stroke\" color when used in conjunction with fill color.\n\n  If letting default a color parameter to `None`, then no resp. color selection command will be generated. If *fill* and *color* are both `None`, then the drawing will contain no color specification. But it will still be \"stroked\", which causes PDF's default color \"black\" be used by Adobe Acrobat and all other viewers.\n\n----\n\n**width** (*float*)\n\n  The stroke (\"border\") width of the elements in a shape (if applicable). The default value is 1. The values width, color and fill have the following relationship / dependency:\n\n  * If `fill=None` shape elements will always be drawn with a border - even if `color=None` (in which case black is taken) or `width=0` (in which case 1 is taken).\n  * Shapes without border can only be achieved if a fill color is specified (which may be white of course). To achieve this, specify `width=0`. In this case, the ``color`` parameter is ignored.\n\n----\n\n**stroke_opacity / fill_opacity** (*floats*)\n\n  Both values are floats in range [0, 1]. Negative values or values > 1 will ignored (in most cases). Both set the transparency such that a value 0.5 corresponds to 50% transparency, 0 means invisible and 1 means intransparent. For e.g. a rectangle the stroke opacity applies to its border and fill opacity to its interior.\n\n  For text insertions (:meth:`Shape.insert_text` and :meth:`Shape.insert_textbox`), use *fill_opacity* for the text. At first sight this seems surprising, but it becomes obvious when you look further down to `render_mode`: `fill_opacity` applies to the yellow and `stroke_opacity` applies to the blue color.\n\n----\n\n**border_width** (*float*)\n\n  Set the border width for text insertions. New in v1.14.9. Relevant only if the render mode argument is used with a value greater zero.\n\n----\n\n**render_mode** (*int*)\n\n  *New in version 1.14.9:* Integer in `range(8)` which controls the text appearance (:meth:`Shape.insert_text` and :meth:`Shape.insert_textbox`). See page 246 in :ref:`AdobeManual`. New in v1.14.9. These methods now also differentiate between fill and stroke colors.\n\n  * For default 0, only the text fill color is used to paint the text. For backward compatibility, using the *color* parameter instead also works.\n  * For render mode 1, only the border of each glyph (i.e. text character) is drawn with a thickness as set in argument *border_width*. The color chosen in the *color* argument is taken for this, the *fill* parameter is ignored.\n  * For render mode 2, the glyphs are filled and stroked, using both color parameters and the specified border width. You can use this value to simulate **bold text** without using another font: choose the same value for *fill* and *color* and an appropriate value for *border_width*.\n  * For render mode 3, the glyphs are neither stroked nor filled: the text becomes invisible.\n\n  The following examples use border_width=0.3, together with a fontsize of 15. Stroke color is blue and fill color is some yellow.\n\n  .. image:: images/img-rendermode.*\n\n----\n\n**miter_limit** (*float*)\n\n  A float specifying the maximum acceptable value of the quotient `miter-length / line-width` (\"miter quotient\"). Used in text output methods. This is only relevant for non-zero render mode values -- then, characters are written with border lines (i.e. \"stroked\").\n  \n  If two lines stroking some character meet at a sharp (<= 90°) angle and the line width is large enough, then \"spikes\" may become visible -- causing an ugly appearance as shown below. For more background, see page 126 of the :ref:`AdobeManual`.\n    \n  For instance, when joins meet at 90°, then the miter length is ``sqrt(2) * line-width``, so the miter quotient is ``sqrt(2)``.\n  \n  If ``miter_limit`` is exceeded, then all joins with a larger qotient will appear as beveled (\"butt\" appearance).\n    \n  The default value 1 (and any smaller value) will ensure that all joins are rendered as a butt. A value of ``None`` will use the PDF default value.\n  \n  Example text showing spikes (``miter_limit=None``):\n\n  .. image:: images/spikes-yes.*\n\n  Example text suppressing spikes (``miter_limit=1``):\n\n  .. image:: images/spikes-no.*\n\n----\n\n**overlay** (*bool*)\n\n  Causes the item to appear in foreground (default) or background.\n\n----\n\n**morph** (*sequence*)\n\n  Causes \"morphing\" of either a shape, created by the *draw*()* methods, or the text inserted by page methods *insert_textbox()* / *insert_text()*. If not ``None``, it must be a pair *(fixpoint, matrix)*, where *fixpoint* is a :ref:`Point` and *matrix* is a :ref:`Matrix`. The matrix can be anything except translations, i.e. *matrix.e == matrix.f == 0* must be true. The point is used as a fixed point for the matrix operation. For example, if *matrix* is a rotation or scaling, then *fixpoint* is its center. Similarly, if *matrix* is a left-right or up-down flip, then the mirroring axis will be the vertical, respectively horizontal line going through *fixpoint*, etc.\n\n  .. note:: Several methods contain checks whether the to be inserted items will actually fit into the page (like :meth:`Shape.insert_text`, or :meth:`Shape.draw_rect`). For the result of a morphing operation there is however no such guaranty: this is entirely the programmer's responsibility.\n\n----\n\n**lineCap (deprecated: \"roundCap\")** (*int*)\n\n  Controls the look of line ends. The default value 0 lets each line end at exactly the given coordinate in a sharp edge. A value of 1 adds a semi-circle to the ends, whose center is the end point and whose diameter is the line width. Value 2 adds a semi-square with an edge length of line width and a center of the line end.\n\n  *Changed in version 1.14.15*\n\n----\n\n**lineJoin** (*int*)\n\n  *New in version 1.14.15:* Controls the way how line connections look like. This may be either as a sharp edge (0), a rounded join (1), or a cut-off edge (2, \"butt\").\n\n----\n\n**closePath** (*bool*)\n\n  Causes the end point of a drawing to be automatically connected with the starting point (by a straight line).\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/story-class.rst",
    "content": ".. include:: header.rst\n\n.. _Story:\n\n================\nStory\n================\n\n.. role:: htmlTag(emphasis)\n\n* New in v1.21.0\n\n=========================================== =============================================================\n**Method / Attribute**                      **Short Description**\n=========================================== =============================================================\n:meth:`Story.reset`                         \"rewind\" story output to its beginning\n:meth:`Story.place`                         compute story content to fit in provided rectangle\n:meth:`Story.draw`                          write the computed content to current page\n:meth:`Story.element_positions`             callback function logging currently processed story content\n:attr:`Story.body`                          the story's underlying :htmlTag:`body`\n:meth:`Story.write`                         places and draws Story to a DocumentWriter\n:meth:`Story.write_stabilized`              iterative layout of html content to a DocumentWriter\n:meth:`Story.write_with_links`              like `write()` but also creates PDF links\n:meth:`Story.write_stabilized_with_links`   like `write_stabilized()` but also creates PDF links\n:meth:`Story.fit`                           Finds optimal rect that contains the story `self`.\n:meth:`Story.fit_scale`                     \n:meth:`Story.fit_height`\n:meth:`Story.fit_width`\n=========================================== =============================================================\n\n**Class API**\n\n.. class:: Story\n\n   .. method:: __init__(self, html=None, user_css=None, em=12, archive=None)\n\n      Create a **story**, optionally providing HTML and CSS source.\n      The HTML is parsed, and held within the Story as a DOM (Document Object Model).\n\n      This structure may be modified: content (text, images) may be added,\n      copied, modified or removed by using methods of the :ref:`Xml` class.\n\n      When finished, the **story** can be written to any device;\n      in typical usage the device may be provided by a :ref:`DocumentWriter` to make new pages.\n\n      Here are some general remarks:\n\n      * The :ref:`Story` constructor parses and validates the provided HTML to create the DOM.\n      * PyMuPDF provides a number of ways to manipulate the HTML source by\n        providing access to the *nodes* of the underlying DOM.\n        Documents can be completely built from ground up programmatically,\n        or the existing DOM can be modified pretty arbitrarily.\n        For details of this interface, please see the :ref:`Xml` class.\n      * If no (or no more) changes to the DOM are required,\n        the story is ready to be laid out and to be fed to a series of devices\n        (typically devices provided by a :ref:`DocumentWriter` to produce new pages).\n      * The next step is to place the story and write it out.\n        This can either be done directly, by looping around calling `place()` and `draw()`,\n        or alternatively,\n        the looping can handled for you using the `write()` or `write_stabilised()` methods.\n        Which method you choose is largely a matter of taste.\n        \n        * To work in the first of these styles, the following loop should be used:\n        \n          1. Obtain a suitable device to write to;\n             typically by requesting a new,\n             empty page from a :ref:`DocumentWriter`.\n          2. Determine one or more rectangles on the page,\n             that should receive **story** data.\n             Note that not every page needs to have the same set of rectangles.\n          3. Pass each rectangle to the **story** to place it,\n             learning what part of that rectangle has been filled,\n             and whether there is more story data that did not fit.\n             This step can be repeated several times with adjusted rectangles\n             until the caller is happy with the results. \n          4. Optionally, at this point,\n             we can request details of where interesting items have been placed,\n             by calling the `element_positions()` method.\n             Items are deemed to be interesting if their integer `heading` attribute is a non-zero\n             (corresponding to HTML tags :htmlTag:`h1` - :htmlTag:`h6`),\n             if their `id` attribute is not `None` (corresponding to HTML tag :htmlTag:`id`),\n             or if their `href` attribute is not `None` (responding to HTML tag :htmlTag:`href`).\n             This can conveniently be used for automatic generation of a Table of Contents,\n             an index of images or the like.\n          5. Next, draw that rectangle out to the device with the `draw()` method.\n          6. If the most recent call to `place()` indicated that all the story data had fitted,\n             stop now.\n          7. Otherwise, we can loop back.\n             If there are more rectangles to be placed on the current device (page),\n             we jump back to step 3 - if not, we jump back to step 1 to get a new device.\n        * Alternatively, in the case where you are using a :ref:`DocumentWriter`,\n          the `write()` or `write_stabilized()` methods can be used.\n          These handle all the looping for you,\n          in exchange for being provided with callbacks that control the behaviour\n          (notably a callback that enumerates the rectangles/pages to use).\n      * Which part of the **story** will land on which rectangle / which page,\n        is fully under control of the :ref:`Story` object and cannot be predicted.\n      * Images may be part of a **story**. They will be placed together with any surrounding text.\n      * Multiple stories may - independently from each other - write to the same page.\n        For example, one may have separate stories for page header,\n        page footer, regular text, comment boxes, etc.\n\n      :arg str html: HTML source code. If omitted, a basic minimum is generated (see below).\n        If provided, not a complete HTML document is needed.\n        The in-built source parser will forgive (many / most)\n        HTML syntax errors and also accepts HTML fragments like\n        `\"<b>Hello, <i>World!</i></b>\"`.\n      :arg str user_css: CSS source code. If provided, must contain valid CSS specifications.\n      :arg float em: the default text font size.\n      :arg archive: an :ref:`Archive` from which to load resources for rendering. Currently supported resource types are images and text fonts. If omitted, the story will not try to look up any such data and may thus produce incomplete output.\n      \n         .. note:: Instead of an actual archive, valid arguments for **creating** an :ref:`Archive` can also be provided -- in which case an archive will temporarily be constructed. So, instead of `story = pymupdf.Story(archive=pymupdf.Archive(\"myfolder\"))`, one can also shorter write `story = pymupdf.Story(archive=\"myfolder\")`.\n\n   .. method:: place(where)\n\n      Calculate that part of the story's content, that will fit in the provided rectangle. The method maintains a pointer which part of the story's content has already been written and upon the next invocation resumes from that pointer's position.\n\n      :arg rect_like where: layout the current part of the content to fit into this rectangle. This must be a sub-rectangle of the page's :ref:`MediaBox<Glossary_MediaBox>`.\n\n      :rtype: tuple[bool, rect_like]\n      :returns: a bool (int) `more` and a rectangle `filled`. If `more == 0`, all content of the story has been written, otherwise more is waiting to be written to subsequent rectangles / pages. Rectangle `filled` is the part of `where` that has actually been filled.\n\n   .. method:: draw(dev, matrix=None)\n\n      Write the content part prepared by :meth:`Story.place` to the page.\n\n      :arg dev: the :ref:`Device` created by `dev = writer.begin_page(mediabox)`. The device knows how to call all MuPDF functions needed to write the content.\n      :arg matrix_like matrix: a matrix for transforming content when writing to the page. An example may be writing rotated text. The default means no transformation (i.e. the :ref:`Identity` matrix).\n\n   .. method:: element_positions(function, args=None)\n\n      Let the Story provide positioning information about certain HTML elements once their place on the current page has been computed - i.e. invoke this method **directly after** :meth:`Story.place`.\n\n      *Story* will pass position information to *function*. This information can for example be used to generate a Table of Contents.\n\n      :arg callable function: a Python function accepting an :class:`ElementPosition` object. It will be invoked by the Story object to process positioning information. The function **must** be a callable accepting exactly one argument.\n      :arg dict args: an optional dictionary with any **additional** information\n        that should be added to the :class:`ElementPosition` instance passed to `function`.\n        Like for example the current output page number.\n        Every key in this dictionary must be a string that conforms to the rules for a valid Python identifier.\n        The complete set of information is explained below.\n\n\n   .. method:: reset()\n\n      Rewind the story's document to the beginning for starting over its output.\n\n   .. attribute:: body\n\n      The :htmlTag:`body` part of the story's DOM. This attribute contains the :ref:`Xml` node of :htmlTag:`body`. All relevant content for PDF production is contained between \"<body>\" and \"</body>\".\n\n   .. method:: write(writer, rectfn, positionfn=None, pagefn=None)\n\n        Places and draws Story to a `DocumentWriter`. Avoids the need for\n        calling code to implement a loop that calls `Story.place()` and\n        `Story.draw()` etc, at the expense of having to provide at least the\n        `rectfn()` callback.\n       \n        :arg writer: a `DocumentWriter` or None.\n        :arg rectfn: a callable taking `(rect_num: int, filled: Rect)` and\n            returning `(mediabox, rect, ctm)`:\n            \n            * mediabox: None or rect for new page.\n            * rect: The next rect into which content should be placed.\n            * ctm: None or a `Matrix`.\n        :arg positionfn: None, or a callable taking `(position: ElementPosition)`:\n            \n            * position:\n                An `ElementPosition` with an extra `.page_num` member.\n            Typically called multiple times as we generate elements that\n            are headings or have an id.\n        :arg pagefn:\n            None, or a callable taking `(page_num, mediabox, dev, after)`;\n            called at start (`after=0`) and end (`after=1`) of each page.\n\n   .. staticmethod:: write_stabilized(writer, contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True)\n   \n        Static method that does iterative layout of html content to a\n        `DocumentWriter`.\n\n        For example this allows one to add a table of contents section\n        while ensuring that page numbers are patched up until stable.\n\n        Repeatedly creates a new `Story` from `(contentfn(),\n        user_css, em, archive)` and lays it out with internal call\n        to `Story.write()`; uses a None writer and extracts the list\n        of `ElementPosition`'s which is passed to the next call of\n        `contentfn()`.\n\n        When the html from `contentfn()` becomes unchanged, we do a\n        final iteration using `writer`.\n\n        :arg writer:\n            A `DocumentWriter`.\n        :arg contentfn:\n            A function taking a list of `ElementPositions` and\n            returning a string containing html. The returned html\n            can depend on the list of positions, for example with a\n            table of contents near the start.\n        :arg rectfn:\n            A callable taking `(rect_num: int, filled: Rect)` and\n            returning `(mediabox, rect, ctm)`:\n\n            * mediabox: None or rect for new page.\n            * rect: The next rect into which content should be placed.\n            * ctm: A `Matrix`.\n        :arg pagefn:\n            None, or a callable taking `(page_num, medibox,\n            dev, after)`; called at start (`after=0`) and end\n            (`after=1`) of each page.\n        :arg archive:\n        :arg add_header_ids:\n            If true, we add unique ids to all header tags that\n            don't already have an id. This can help automatic\n            generation of tables of contents.\n        Returns:\n            None.\n       \n   .. method:: write_with_links(rectfn, positionfn=None, pagefn=None)\n\n        Similar to `write()` except that we don't have a `writer` arg\n        and we return a PDF `Document` in which links have been created\n        for each internal html link.\n\n   .. staticmethod:: write_stabilized_with_links(contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True)\n\n        Similar to `write_stabilized()` except that we don't have a `writer`\n        arg and instead return a PDF `Document` in which links have been\n        created for each internal html link.\n    \n   .. class:: Story.FitResult\n    \n        The result from a `Story.fit*()` method.\n        \n        Members:\n        \n        `big_enough`:\n            `True` if the fit succeeded.\n        `filled`:\n            From the last call to `Story.place()`.\n        `more`:\n            `False` if the fit succeeded.\n        `numcalls`:\n            Number of calls made to `self.place()`.\n        `parameter`:\n            The successful parameter value, or the largest failing value.\n        `rect`:\n            The rect created from `parameter`.\n        \n   .. method:: fit(self, fn, pmin=None, pmax=None, delta=0.001, verbose=False)\n\n        Finds optimal rect that contains the story `self`.\n        \n        Returns a `Story.FitResult` instance.\n            \n        On success, the last call to `self.place()` will have been with the\n        returned rectangle, so `self.draw()` can be used directly.\n        \n        :arg fn:\n            A callable taking a floating point `parameter` and returning a\n            `pymupdf.Rect()`. If the rect is empty, we assume the story will\n            not fit and do not call `self.place()`.\n\n            Must guarantee that `self.place()` behaves monotonically when\n            given rect `fn(parameter`) as `parameter` increases. This\n            usually means that both width and height increase or stay\n            unchanged as `parameter` increases.\n        :arg pmin:\n            Minimum parameter to consider; `None` for -infinity.\n        :arg pmax:\n            Maximum parameter to consider; `None` for +infinity.\n        :arg delta:\n            Maximum error in returned `parameter`.\n        :arg verbose:\n            If true we output diagnostics.\n\n   .. method:: fit_scale(self, rect, scale_min=0, scale_max=None, delta=0.001, verbose=False)\n\n        Finds smallest value `scale` in range `scale_min..scale_max` where\n        `scale * rect` is large enough to contain the story `self`.\n\n        Returns a `Story.FitResult` instance.\n\n        :arg width:\n            width of rect.\n        :arg height:\n            height of rect.\n        :arg scale_min:\n            Minimum scale to consider; must be >= 0.\n        :arg scale_max:\n            Maximum scale to consider, must be >= scale_min or `None` for\n            infinite.\n        :arg delta:\n            Maximum error in returned scale.\n        :arg verbose:\n            If true we output diagnostics.\n\n   .. method:: fit_height(self, width, height_min=0, height_max=None, origin=(0, 0), delta=0.001, verbose=False)\n\n        Finds smallest height in range `height_min..height_max` where a rect\n        with size `(width, height)` is large enough to contain the story\n        `self`.\n\n        Returns a `Story.FitResult` instance.\n\n        :arg width:\n            width of rect.\n        :arg height_min:\n            Minimum height to consider; must be >= 0.\n        :arg height_max:\n            Maximum height to consider, must be >= height_min or `None` for\n            infinite.\n        :arg origin:\n            `(x0, y0)` of rect.\n        :arg delta:\n            Maximum error in returned height.\n        :arg verbose:\n            If true we output diagnostics.\n\n   .. method:: fit_width(self, height, width_min=0, width_max=None, origin=(0, 0), delta=0.001, verbose=False)\n\n        Finds smallest width in range `width_min..width_max` where a rect with size\n        `(width, height)` is large enough to contain the story `self`.\n\n        Returns a `Story.FitResult` instance.\n\n        :arg height:\n            height of rect.\n        :arg width_min:\n            Minimum width to consider; must be >= 0.\n        :arg width_max:\n            Maximum width to consider, must be >= width_min or `None` for\n            infinite.\n        :arg origin:\n            `(x0, y0)` of rect.\n        :arg delta:\n            Maximum error in returned width.\n        :arg verbose:\n            If true we output diagnostics.\n\n\nElement Positioning CallBack function\n--------------------------------------\n\nThe callback function can be used to log information about story output. The function's access to the information is read-only: it has no way to influence the story's output.\n\nA typical loop for executing a story with using this method would look like this::\n\n    HTML = \"\"\"\n    <html>\n        <head></head>\n        <body>\n            <h1>Header level 1</h1>\n            <h2>Header level 2</h2>\n            <p>Hello MuPDF!</p>\n        </body>\n    </html>\n    \"\"\"\n    MEDIABOX = pymupdf.paper_rect(\"letter\")  # size of a page\n    WHERE = MEDIABOX + (36, 36, -36, -36)  # leave borders of 0.5 inches\n    story =  pymupdf.Story(html=HTML)  # make the story\n    writer = pymupdf.DocumentWriter(\"test.pdf\")  # make the writer\n    pno = 0 # current page number\n    more = 1  # will be set to 0 when done\n    while more:  # loop until all story content is processed\n        dev = writer.begin_page(MEDIABOX)  # make a device to write on the page\n        more, filled = story.place(WHERE)  # compute content positions on page\n        story.element_positions(recorder, {\"page\": pno})  # provide page number in addition\n        story.draw(dev)\n        writer.end_page()\n        pno += 1  # increase page number\n    writer.close()  # close output file\n\n    def recorder(elpos):\n        pass\n\n\nAttributes of the ElementPosition class\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\nExactly one parameter must be passed to the function provided by :meth:`Story.element_positions`. It is an object with the following attributes:\n\nThe parameter passed to the `recorder` function is an object with the following attributes:\n\n* `elpos.depth` (int) -- depth of this element in the box structure.\n\n* `elpos.heading` (int) -- the header level, 0 if no header, 1-6 for :htmlTag:`h1` - :htmlTag:`h6`.\n\n* `elpos.href` (str) -- value of the `href` attribute, or None if not defined.\n\n* `elpos.id` (str) -- value of the `id` attribute, or None if not defined.\n\n* `elpos.rect` (tuple) -- element position on page.\n\n* `elpos.text` (str) -- immediate text of the element.\n\n* `elpos.open_close` (int bit field) -- bit 0 set: opens element, bit 1 set: closes element. Relevant for elements that may contain other elements and thus may not immediately be closed after being created / opened.\n\n* `elpos.rect_num` (int) -- count of rectangles filled by the story so far.\n\n* `elpos.page_num` (int) -- page number; only present when using `pymupdf.Story.write*()` functions.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/supported-files-table.rst",
    "content": ".. raw:: html\n\n    <style>\n\n        table {\n            border-style: hidden;\n        }\n\n        #feature-matrix th {\n            border: 1px #999 solid;\n            padding: 10px;\n            background-color: #007aff;\n            color: white;\n        }\n\n        #feature-matrix tr {\n\n        }\n\n        #feature-matrix td {\n            border: 1px #999 solid;\n            padding: 10px;\n        }\n\n        #feature-matrix tr td.yes {\n            background-color: #83e57c !important;\n            color: #000;\n        }\n\n        #feature-matrix tr td.yes::before {\n            content: \"✔︎ \";\n        }\n\n        #feature-matrix tr td.no {\n            background-color: #e5887c !important;\n            color: #000;\n        }\n\n        #feature-matrix tr td.no::before {\n            content: \"✕ \";\n        }\n\n        #feature-matrix tr td.limited {\n            background-color: #e4c07b !important;\n            color: #000;\n        }\n\n        #feature-matrix .icon-holder {\n            line-height: 40px;\n        }\n\n        #feature-matrix .icon {\n            text-indent: 45px;\n            line-height: 40px;\n            width: 100px;\n            height: 40px;\n        }\n\n        #feature-matrix .icon.pdf {\n            background: url(\"_images/icon-pdf.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.xps {\n            background: url(\"_images/icon-xps.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.epub {\n            background: url(\"_images/icon-epub.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.mobi {\n            background: url(\"_images/icon-mobi.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.fb2 {\n            background: url(\"_images/icon-fb2.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.cbz {\n            background: url(\"_images/icon-cbz.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.svg {\n            background: url(\"_images/icon-svg.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.image {\n            background: url(\"_images/icon-image.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n        #feature-matrix .icon.txt {\n            background: url(\"_images/icon-txt.svg\") 0 0 transparent no-repeat;\n            background-size: 40px 40px;\n        }\n\n    </style>\n\n\n\n    <table id=\"feature-matrix\" border=\"0\" cellpadding=\"0\" cellspacing=\"0\">\n        <tr>\n            <th style=\"width:20%;\"></th>\n            <th style=\"width:20%;\"><div id=\"trans1\"></div></th>\n        </tr>\n\n        <tr>\n            <td><cite><div id=\"trans2\"></div></cite></td>\n            <td>\n                <span class=\"icon pdf\"><cite>PDF</cite></span>\n                <span class=\"icon xps\"><cite>XPS</cite></span>\n                <span class=\"icon epub\"><cite>EPUB</cite></span>\n                <span class=\"icon mobi\"><cite>MOBI</cite></span>\n                <span class=\"icon fb2\"><cite>FB2</cite></span>\n                <span class=\"icon cbz\"><cite>CBZ</cite></span>\n                <span class=\"icon svg\"><cite>SVG</cite></span>\n                <span class=\"icon txt\"><cite>TXT</cite></span>\n            </td>\n        </tr>\n\n        <tr>\n            <td><cite><div id=\"trans3\"></div></cite></td>\n            <td>\n                <span class=\"icon image\"></span>\n                <div><u><div id=\"trans4\"></div></u> <cite>JPG/JPEG, PNG, BMP, GIF, TIFF, PNM, PGM, PBM, PPM, PAM, JXR, JPX/JP2, PSD</cite></div>\n                <div><u><div id=\"trans5\"></div></u> <cite>JPG/JPEG, PNG, PNM, PGM, PBM, PPM, PAM, PSD, PS</cite></div>\n            </td>\n        </tr>\n\n    </table>\n\n    <script>\n\n        let lang = document.getElementsByTagName('html')[0].getAttribute('lang');\n\n        function getTranslation(str) {\n            if (lang == \"ja\") {\n                if (str==\"File type\") {\n                    return \"ファイルタイプ\";\n                } else if (str==\"Document Formats\") {\n                    return \"文書のフォーマット\";\n                } else if (str==\"Image Formats\") {\n                    return \"画像のフォーマット\";\n                } else if (str==\"Input formats\") {\n                    return \"入力フォーマット\";\n                } else if (str==\"Output formats\") {\n                    return \"出力フォーマット\";\n                }\n\n            } else if (lang == \"ko\") {\n                if (str==\"File type\") {\n                    return \"파일 유형\";\n                } else if (str==\"Document Formats\") {\n                    return \"문서 형식\";\n                } else if (str==\"Image Formats\") {\n                    return \"이미지 형식\";\n                } else if (str==\"Input formats\") {\n                    return \"입력 형식\";\n                } else if (str==\"Output formats\") {\n                    return \"출력 형식\";\n                }\n            }\n\n            return str;\n        }\n\n        document.getElementById(\"trans1\").innerHTML = getTranslation(\"File type\");\n        document.getElementById(\"trans2\").innerHTML = getTranslation(\"Document Formats\");\n        document.getElementById(\"trans3\").innerHTML = getTranslation(\"Image Formats\");\n        document.getElementById(\"trans4\").innerHTML = getTranslation(\"Input formats\");\n        document.getElementById(\"trans5\").innerHTML = getTranslation(\"Output formats\");\n\n    </script>\n"
  },
  {
    "path": "docs/textpage.rst",
    "content": ".. include:: header.rst\n\n.. _TextPage:\n\n================\nTextPage\n================\n\nThis class represents text and images shown on a document page. All :ref:`MuPDF document types<Supported_File_Types>` are supported.\n\nThe usual ways to create a textpage are :meth:`DisplayList.get_textpage` and :meth:`Page.get_textpage`. Because there is a limited set of methods in this class, there exist wrappers in :ref:`Page` which are handier to use. The last column of this table shows these corresponding :ref:`Page` methods.\n\nFor a description of what this class is all about, see Appendix 2.\n\n======================== ================================ ==============================\n**Method**               **Description**                  page get_text or search method\n======================== ================================ ==============================\n:meth:`~.extractText`    extract plain text               \"text\"\n:meth:`~.extractTEXT`    synonym of previous              \"text\"\n:meth:`~.extractBLOCKS`  plain text grouped in blocks     \"blocks\"\n:meth:`~.extractWORDS`   all words with their bbox        \"words\"\n:meth:`~.extractHTML`    page content in HTML format      \"html\"\n:meth:`~.extractXHTML`   page content in XHTML format     \"xhtml\"\n:meth:`~.extractXML`     page text in XML format          \"xml\"\n:meth:`~.extractDICT`    page content in *dict* format    \"dict\"\n:meth:`~.extractJSON`    page content in JSON format      \"json\"\n:meth:`~.extractRAWDICT` page content in *dict* format    \"rawdict\"\n:meth:`~.extractRAWJSON` page content in JSON format      \"rawjson\"\n:meth:`~.search`         Search for a string in the page  :meth:`Page.search_for`\n======================== ================================ ==============================\n\n**Class API**\n\n.. class:: TextPage\n\n   .. method:: extractText(sort=False)\n\n   .. method:: extractTEXT(sort=False)\n\n      Return a string of the page's complete text. The text is UTF-8 unicode and in the same sequence as specified at the time of document creation.\n\n      :arg bool sort: (new in v1.19.1) sort the output by vertical, then horizontal coordinates. In many cases, this should suffice to generate a \"natural\" reading order.\n\n      :rtype: str\n\n\n   .. method:: extractBLOCKS\n\n      Textpage content as a list of text lines grouped by block. Each list items looks like this::\n\n         ``(x0, y0, x1, y1, \"lines in the block\", block_no, block_type)``\n\n      The first four entries are the block's bbox coordinates, *block_type* is 1 for an image block, 3 for a vector block, and 0 for text. *block_no* is the block sequence number. Multiple text lines are joined via line breaks.\n\n      For an **image block**, its bbox and a text line with some image meta information is included -- not the image **content**. Image blocks are included only if the extraction flag bit :data:`TEXT_PRESERVE_IMAGES` is set. An image block tuple will look like this::\n\n         ``(x0, y0, x1, y1, \"<image: colorspace-name, w: width, h: height, bpc: bits_per_component>\\n\", block_no, 1)``\n\n      For a **vector block**, the following item will be included. Vector blocks are included only if the extraction flag bit :data:`TEXT_COLLECT_VECTORS` is set. A vector block tuple will look like this::\n\n         ``(x0, y0, x1, y1, \"<vector stroked, color: #rrggbb, alpha: 255, is-rect: true, continues: false>\\n\", block_no, 3)``\n\n      The keyword \"vector\" is followed by either \"stroked\" or \"filled\". The color is given in HTML (hexadecimal RGB) format. Property ``is-rect`` is true, if the vector is not a curve and parallel to the x- or y-axis. So in essence is either a real rectangle or a line segment. Property ``continues`` indicates whether the vector is part of a path (and not the first item).\n\n      .. note:: When no further details are needed (as provided by :meth:`Page.get_drawings`), then this is an **inexpensive** way to extract basic vector graphics information. Another major advantage is that all block types (text, images and vectors) are included in the output in the same order as they are present in the page's :data:`contents` stream.\n\n      This is a high-speed method with just enough information to output plain text in desired reading sequence.\n\n      :rtype: list\n\n   .. method:: extractWORDS(delimiters=None)\n\n      * Changed in v1.23.5: added `delimiters` parameter\n\n      Textpage content as a list of single words with bbox information. An item of this list looks like this::\n\n         (x0, y0, x1, y1, \"word\", block_no, line_no, word_no)\n\n      :arg str delimiters: (new in v1.23.5) use these characters as *additional* word separators. By default, all white spaces (including the non-breaking space `0xA0`) indicate start and end of a word. Now you can specify more characters causing this. For instance, the default will return `\"john.doe@outlook.com\"` as **one** word. If you specify `delimiters=\"@.\"` then the **four** words `\"john\"`, `\"doe\"`, `\"outlook\"`, `\"com\"` will be returned. Other possible uses include ignoring punctuation characters `delimiters=string.punctuation`. The \"word\" strings will not contain any delimiting character.\n\n      This is a high-speed method which e.g. allows extracting text from within given areas or recovering the text reading sequence.\n\n      :rtype: list\n\n   .. method:: extractHTML\n\n      Textpage content as a string in HTML format. This version contains complete formatting and positioning information. Images are included (encoded as base64 strings). You need an HTML package to interpret the output in Python. Your internet browser should be able to adequately display this information, but see :ref:`HTMLQuality`.\n\n      :rtype: str\n\n   .. method:: extractDICT(sort=False)\n\n      Textpage content as a Python dictionary. Provides same information detail as HTML. See below for the structure.\n\n      :arg bool sort: (new in v1.19.1) sort the output by vertical, then horizontal coordinates. In many cases, this should suffice to generate a \"natural\" reading order.\n\n      :rtype: dict\n\n   .. method:: extractJSON(sort=False)\n\n      Textpage content as a JSON string. Created by `json.dumps(TextPage.extractDICT())`. It is included for backlevel compatibility. You will probably use this method ever only for outputting the result to some file. The  method detects binary image data and converts them to base64 encoded strings.\n\n      :arg bool sort: (new in v1.19.1) sort the output by vertical, then horizontal coordinates. In many cases, this should suffice to generate a \"natural\" reading order.\n\n      :rtype: str\n\n   .. method:: extractXHTML\n\n      Textpage content as a string in XHTML format. Text information detail is comparable with :meth:`extractTEXT`, but also contains images (base64 encoded). This method makes no attempt to re-create the original visual appearance.\n\n      :rtype: str\n\n   .. method:: extractXML\n\n      Textpage content as a string in XML format. This contains complete formatting information about every single character on the page: font, size, line, paragraph, location, color, etc. Contains no images. You need an XML package to interpret the output in Python.\n\n      :rtype: str\n\n   .. method:: extractRAWDICT(sort=False)\n\n      Textpage content as a Python dictionary -- technically similar to :meth:`extractDICT`, and it contains that information as a subset (including any images). It provides additional detail down to each character, which makes using XML obsolete in many cases. See below for the structure.\n\n      :arg bool sort: (new in v1.19.1) sort the output by vertical, then horizontal coordinates. In many cases, this should suffice to generate a \"natural\" reading order.\n\n      :rtype: dict\n\n   .. method:: extractRAWJSON(sort=False)\n\n      Textpage content as a JSON string. Created by `json.dumps(TextPage.extractRAWDICT())`. You will probably use this method ever only for outputting the result to some file. The  method detects binary image data and converts them to base64 encoded strings.\n\n      :arg bool sort: (new in v1.19.1) sort the output by vertical, then horizontal coordinates. In many cases, this should suffice to generate a \"natural\" reading order.\n\n      :rtype: str\n\n   .. method:: search(needle, quads=False)\n\n      * Changed in v1.18.2\n\n      Search for *string* and return a list of found locations.\n\n      :arg str needle: the string to search for. Upper and lower cases will all match if needle consists of ASCII letters only -- it does not yet work for \"Ä\" versus \"ä\", etc.\n      :arg bool quads: return quadrilaterals instead of rectangles.\n      :rtype: list\n      :returns: a list of :ref:`Rect` or :ref:`Quad` objects, each surrounding a found *needle* occurrence. As the search string may contain spaces, its parts may be found on different lines. In this case, more than one rectangle (resp. quadrilateral) are returned. **(Changed in v1.18.2)** The method **now supports dehyphenation**, so it will find e.g. \"method\", even if it was hyphenated in two parts \"meth-\" and \"od\" across two lines. The two returned rectangles will contain \"meth\" (no hyphen) and \"od\".\n\n      .. note:: **Overview of changes in v1.18.2:**\n\n        1. The `hit_max` parameter has been removed: all hits are always returned.\n        2. The `rect` parameter of the :ref:`TextPage` is now respected: only text inside this area is examined. Only characters with fully contained bboxes are considered. The wrapper method :meth:`Page.search_for` correspondingly supports a *clip* parameter.\n        3. **Hyphenated words** are now found.\n        4. **Overlapping rectangles** in the same line are now automatically joined. We assume that such separations are an artifact created by multiple marked content groups, containing parts of the same search needle.\n\n      Example Quad versus Rect: when searching for needle \"pymupdf\", then the corresponding entry will either be the blue rectangle, or, if *quads* was specified, the quad *Quad(ul, ur, ll, lr)*.\n\n      .. image:: images/img-quads.*\n\n   .. attribute:: rect\n\n      The rectangle associated with the text page. This either equals the rectangle of the creating page or the `clip` parameter of :meth:`Page.get_textpage` and text extraction / searching methods.\n\n      .. note:: The output of text searching and most text extractions **is restricted to this rectangle**. (X)HTML and XML output will however always extract the full page.\n\n.. _textpagedict:\n\nStructure of Dictionary Outputs\n--------------------------------\nMethods :meth:`TextPage.extractDICT`, :meth:`TextPage.extractJSON`, :meth:`TextPage.extractRAWDICT`, and :meth:`TextPage.extractRAWJSON` return dictionaries, containing the page's text and image content. The dictionary structures of all four methods are almost equal. They strive to map the text page's information hierarchy of blocks, lines, spans and characters as precisely as possible, by representing each of these by its own sub-dictionary:\n\n* A **page** consists of a list of **block dictionaries**.\n* A (text) **block** consists of a list of **line dictionaries**.\n* A **line** consists of a list of **span dictionaries**.\n* A **span** either consists of the text itself or, for the RAW variants, a list of **character dictionaries**.\n* RAW variants: a **character** is a dictionary of its origin, bbox and unicode.\n\nAll PyMuPDF geometry objects herein (points, rectangles, matrices) are represented by there **\"like\"** formats: a :data:`rect_like` *tuple* is used instead of a :ref:`Rect`, etc. The reasons for this are performance and memory considerations:\n\n* This code is written in C, where Python tuples can easily be generated. The geometry objects on the other hand are defined in Python source only. A conversion of each Python tuple into its corresponding geometry object would add significant -- and largely unnecessary -- execution time.\n* A 4-tuple needs about 168 bytes, the corresponding :ref:`Rect` 472 bytes - almost three times the size. A \"dict\" dictionary for a text-heavy page contains 300+ bbox objects -- which thus require about 50 KB storage as 4-tuples versus 140 KB as :ref:`Rect` objects. A \"rawdict\" output for such a page will however contain **4 to 5 thousand** bboxes, so in this case we talk about 750 KB versus 2 MB.\n\nPlease also note, that only **bboxes** (= :data:`rect_like` 4-tuples) are returned, whereas a :ref:`TextPage` actually has the **full position information** -- in :ref:`Quad` format. The reason for this decision is again a memory consideration: a :data:`quad_like` needs 488 bytes (3 times the size of a :data:`rect_like`). Given the mentioned amounts of generated bboxes, returning :data:`quad_like` information would have a significant impact.\n\nIn the vast majority of cases, we are dealing with **horizontal text only**, where bboxes provide entirely sufficient information.\n\nIn addition, **the full quad information is not lost**: it can be recovered as needed for lines, spans, and characters by using the appropriate function from the following list:\n\n* :meth:`recover_quad` -- the quad of a complete span\n* :meth:`recover_span_quad` -- the quad of a character subset of a span\n* :meth:`recover_line_quad` -- the quad of a line\n* :meth:`recover_char_quad` -- the quad of a character\n\nAs mentioned, using these functions is ever only needed, if the text is **not written horizontally** -- `line[\"dir\"] != (1, 0)` -- and you need the quad for text marker annotations (:meth:`Page.add_highlight_annot` and friends).\n\n\n.. image:: images/img-textpage.*\n\n..\n  We used to do `:scale: 66` here, but current (2024-04-22) sphinx messes up\n  the aspect ratio.\n\nPage Dictionary\n~~~~~~~~~~~~~~~~~\n\n=============== ============================================\n**Key**         **Value**\n=============== ============================================\nwidth           width of the `clip` rectangle *(float)*\nheight          height of the `clip` rectangle *(float)*\nblocks          *list* of block dictionaries\n=============== ============================================\n\nBlock Dictionaries\n~~~~~~~~~~~~~~~~~~\nBlock dictionaries come in different formats for **vector blocks**, **image blocks** and **text blocks**. Vector blocks are included only if the extraction flag bit :data:`TEXT_COLLECT_VECTORS` is set. Image blocks are included only if the extraction flag bit :data:`TEXT_PRESERVE_IMAGES` is set.\n\n**Vector block:**\n\n=============== =========================================================================================================================\n**Key**             **Value**\n=============== =========================================================================================================================\ntype            3 = vector (``int``)\nbbox            vector bbox on page (:data:`rect_like`)\nnumber          block count (``int``)\nstroked         either stroked (``True``) or filled (``False``) (``bool``)\nisrect          whether the vector is axis-parallel (``bool``). Can be a line or a rectangle. Curves or diagonal lines are ``False``.\ncontinues       whether the vector is (not the last) part of a sequence of vectors in a *path* (``bool``).\ncolor           sRGB integer, e.g. 0xRRGGBB (``int``).\nalpha           Transparency, a value in ``range(256)`` (``int``).\n=============== =========================================================================================================================\n\nThis information is a true subset of the output of :meth:`Page.get_drawings`. Its advantage is its speed (because it is extracted alongside one :ref:`TextPage` creation) and the fact that vector blocks are included in the overall page content sequence together with text and images.\n\n**Image block:**\n\n=============== ===============================================================\n**Key**             **Value**\n=============== ===============================================================\ntype            1 = image (``int``)\nbbox            image bbox on page (:data:`rect_like`)\nnumber          block count (``int``)\next             image type (``str``), as file extension, see below\nwidth           original image width (``int``)\nheight          original image height (``int``)\ncolorspace      colorspace component count (``int``)\nxres            resolution in x-direction (``int``) [#f3]_\nyres            resolution in y-direction (``int``) [#f3]_\nbpc             bits per component (``int``)\ntransform       matrix transforming image rect to bbox (:data:`matrix_like`)\nsize            size of the image in bytes (``int``)\nimage           image content (``bytes``)\nmask            image mask content (``bytes``) for transparent images\n=============== ===============================================================\n\nPossible values of the \"ext\" key are \"bmp\", \"gif\", \"jpeg\", \"jpx\" (JPEG 2000), \"jxr\" (JPEG XR), \"png\", \"pnm\", and \"tiff\".\n\n.. note::\n\n   1. An image block is generated for **all and every image occurrence** on the page. Hence there may be duplicates, if an image is shown at different locations.\n\n   2. :ref:`TextPage` and corresponding method :meth:`Page.get_text` are **available for all document types**. Only for PDF documents, methods :meth:`Document.get_page_images` / :meth:`Page.get_images` offer some overlapping functionality as far as image lists are concerned. But both lists **may or may not** contain the same items. Any differences are most probably caused by one of the following:\n\n       - \"Inline\" images (see page 214 of the :ref:`AdobeManual`) of a PDF page are contained in a textpage, but **do not appear** in :meth:`Page.get_images`.\n       - Annotations may also contain images -- these will **not appear** in :meth:`Page.get_images`.\n       - Image blocks in a textpage are generated for **every** image location -- whether or not there are any duplicates. This is in contrast to :meth:`Page.get_images`, which will list each image only once (per reference name).\n       - Images mentioned in the page's :data:`object` definition will **always** appear in :meth:`Page.get_images` [#f1]_. But it may happen, that there is no \"display\" command in the page's :data:`contents` (erroneously or on purpose). In this case the image will **not appear** in the textpage.\n\n   3. The image's \"transformation matrix\" is defined as the matrix, for which the expression `bbox / transform == pymupdf.Rect(0, 0, 1, 1)` is true, lookup details here: :ref:`ImageTransformation`.\n\n   4. A transparent image may be accompanied by a mask image. This is stored under key `\"mask\"` and has the format of a `DeviceGray` PNG image. Otherwise the value of this key is ``None``. If present, you may be able to recover (an equivalent of) the original image -- i.e. with transparency -- by creating :ref:`Pixmap` objects from the \"image\", respectively \"mask\" values and overlay them. This is not guaranteed to always work because mask images come in multiple formats, of which not all qualify for the conditions under which overlaying Pixmaps are supported. Here is a code snippet:\n\n   >>> base = pymupdf.Pixmap(block[\"image\"])\n   >>> mask = pymupdf.Pixmap(block[\"mask\"])\n   >>> result = pymupdf.Pixmap(base, mask)\n\n\n**Text block:**\n\n=============== ====================================================\n**Key**             **Value**\n=============== ====================================================\ntype            0 = text *(int)*\nbbox            block rectangle, :data:`rect_like`\nnumber          block count *(int)*\nlines           *list* of text line dictionaries\n=============== ====================================================\n\nLine Dictionary\n~~~~~~~~~~~~~~~~~\n\n=============== =====================================================\n**Key**             **Value**\n=============== =====================================================\nbbox            line rectangle, :data:`rect_like`\nwmode           writing mode *(int)*: 0 = horizontal, 1 = vertical\ndir             writing direction, :data:`point_like`\nspans           *list* of span dictionaries\n=============== =====================================================\n\nThe value of key *\"dir\"* is the **unit vector** `dir = (cosine, -sine)` of the angle, which the text has relative to the x-axis [#f2]_. See the following picture: The word in each quadrant (counter-clockwise from top-right to bottom-right) is rotated by 30, 120, 210 and 300 degrees respectively.\n\n.. image:: images/img-line-dir.*\n   :scale: 100\n\nSpan Dictionary\n~~~~~~~~~~~~~~~~~\n\nSpans contain the actual text. A line contains **more than one span only**, if it contains text with different font properties.\n\n* Changed in version 1.14.17 Spans now also have a *bbox* key (again).\n* Changed in version 1.17.6 Spans now also have an *origin* key.\n\n=============== =====================================================================\n**Key**             **Value**\n=============== =====================================================================\nbbox            span rectangle, :data:`rect_like`\norigin          the first character's origin, :data:`point_like`\nfont            font name *(str)*\nascender        ascender of the font *(float)*\ndescender       descender of the font *(float)*\nsize            font size *(float)*\nflags           font characteristics *(int)*\nchar_flags      char characteristics *(int)*\ncolor           text color in sRGB format 0xRRGGBB *(int)*.\nalpha           text opacity 0..255 *(int)*.\ntext            (only for :meth:`extractDICT`) text *(str)*\nchars           (only for :meth:`extractRAWDICT`) *list* of character dictionaries\n=============== =====================================================================\n\n|history_begin|\n\n*(New in version 1.25.3.0):* Added *\"alpha\"* item.\n\n*(New in version 1.16.0):* *\"color\"* is the text color encoded in sRGB (int) format, e.g. 0xFF0000 for red. There are functions for converting this integer back to formats (r, g, b) (PDF with float values from 0 to 1) :meth:`sRGB_to_pdf`, or (R, G, B), :meth:`sRGB_to_rgb` (with integer values from 0 to 255).\n\n*(New in v1.18.5):* *\"ascender\"* and *\"descender\"* are font properties, provided relative to :data:`fontsize` 1. Note that descender is a negative value. The following picture shows the relationship to other values and properties.\n\n|history_end|\n\n.. image:: images/img-asc-desc.*\n   :scale: 60\n\nThese numbers may be used to compute the minimum height of a character (or span) -- as opposed to the standard height provided in the \"bbox\" values (which actually represents the **line height**). The following code recalculates the span bbox to have a height of **fontsize** exactly fitting the text inside:\n\n>>> a = span[\"ascender\"]\n>>> d = span[\"descender\"]\n>>> r = pymupdf.Rect(span[\"bbox\"])\n>>> o = pymupdf.Point(span[\"origin\"])  # its y-value is the baseline\n>>> r.y1 = o.y - span[\"size\"] * d / (a - d)\n>>> r.y0 = r.y1 - span[\"size\"]\n>>> # r now is a rectangle of height 'fontsize'\n\n.. caution:: The above calculation may deliver a **larger** height! This may e.g. happen for OCRed documents, where the risk of all sorts of text artifacts is high. MuPDF tries to come up with a reasonable bbox height, independently from the :data:`fontsize` found in the PDF. So please ensure that the height of `span[\"bbox\"]` is **larger** than `span[\"size\"]`.\n\n.. note:: You may request PyMuPDF to do all of the above automatically by executing `pymupdf.TOOLS.set_small_glyph_heights(True)`. This sets a global parameter so that all subsequent text searches and text extractions are based on reduced glyph heights, where meaningful.\n\nThe following shows the original span rectangle in red and the rectangle with re-computed height in blue.\n\n.. image:: images/img-span-rect.*\n   :scale: 200\n\n\n*\"flags\"* is an integer, which represents font properties except for the first bit 0. They are to be interpreted like this:\n\n* bit 0: superscripted (:data:`TEXT_FONT_SUPERSCRIPT`) -- not a font property, detected by MuPDF code.\n* bit 1: italic (:data:`TEXT_FONT_ITALIC`)\n* bit 2: serifed (:data:`TEXT_FONT_SERIFED`)\n* bit 3: monospaced (:data:`TEXT_FONT_MONOSPACED`)\n* bit 4: bold (:data:`TEXT_FONT_BOLD`)\n\nTest these characteristics like so:\n\n>>> if flags & pymupdf.TEXT_FONT_BOLD & pymupdf.TEXT_FONT_ITALIC:\n        print(f\"{span['text']=} is bold and italic\")\n\n\nBits 1 thru 4 are font properties, i.e. encoded in the font program. Please note, that this information is not necessarily correct or complete: fonts quite often contain wrong data here.\n\n*\"char_flags\"* is an integer, which represents extra character properties:\n\n* bit 0: strikeout.\n* bit 1: underline.\n* bit 2: synthetic (always 0, see char dictionary).\n* bit 3: filled.\n* bit 4: stroked.\n* bit 5: clipped.\n\nFor example if not filled and not stroked (`if not (char_flags & 2**3 & 2**4):\n...`) then the text will be invisible.\n\n(`char_flags` is new in v1.25.2.)\n\n\nCharacter Dictionary for :meth:`extractRAWDICT`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n=============== ===========================================================\n**Key**             **Value**\n=============== ===========================================================\norigin          character's left baseline point, :data:`point_like`\nbbox            character rectangle, :data:`rect_like`\nsynthetic       bool.\nc               the character (unicode)\n=============== ===========================================================\n\n(`synthetic` is new in v1.25.3.)\n\nThis image shows the relationship between a character's bbox and its quad: |textpagechar|\n\n.. |textpagechar| image:: images/img-textpage-char.*\n   :align: top\n   :scale: 66\n\n.. rubric:: Footnotes\n\n.. [#f1] Image specifications for a PDF page are done in a page's (sub-) :data:`dictionary`, called `/Resources`. Resource dictionaries can be **inherited** from any of the page's parent objects (usually the :data:`catalog` -- the top-level parent). The PDF creator may e.g. define one `/Resources` on file level, naming all images and / or all fonts ever used by any page. In these cases, :meth:`Page.get_images` and :meth:`Page.get_fonts` will consequently return the same lists for all pages. If desired, this situation can be reverted using :meth:`Page.clean_contents`. After execution, the page's object definition will show fonts and images that are actually used.\n\n.. [#f2] The coordinate systems of MuPDF and PDF are different in that MuPDF uses the page's top-left point as `(0, 0)`. In PDF, this is the bottom-left point. Therefore, the positive direction for MuPDF's y-axis is **from top to bottom**. This causes the sign change for the sine value here: a **negative** value indicates anti-clockwise rotation of the text.\n\n.. [#f3] This value is always 96, the default of the PDF interpreter. It **does not reflect** the resolution of the image itself. If you need the image's resolution, use the :meth:`Pixmap.xres` and :meth:`Pixmap.yres` attributes of the :ref:`Pixmap` created from the returned image binary.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/textwriter.rst",
    "content": ".. include:: header.rst\n\n.. _TextWriter:\n\n================\nTextWriter\n================\n\n|pdf_only_class|\n\n* New in v1.16.18\n\nThis class represents a MuPDF *text* object. The basic idea is to **decouple (1) text preparation, and (2) text output** to PDF pages.\n\nDuring **preparation**, a text writer stores any number of text pieces (\"spans\") together with their positions and individual font information. The **output** of the writer's prepared content may happen multiple times to any PDF page with a compatible page size.\n\nA text writer is an elegant alternative to methods :meth:`Page.insert_text` and friends:\n\n* **Improved text positioning:** Choose any point where insertion of text should start. Storing text returns the \"cursor position\" after the *last character* of the span.\n* **Free font choice:** Each text span has its own font and :data:`fontsize`. This lets you easily switch when composing a larger text.\n* **Automatic fallback fonts:** If a character is not supported by the chosen font, alternative fonts are automatically searched. This significantly reduces the risk of seeing unprintable symbols in the output (\"TOFUs\" -- looking like a small rectangle). PyMuPDF now also comes with the **universal font \"Droid Sans Fallback Regular\"**, which supports **all Latin** characters (including Cyrillic and Greek), and **all CJK** characters (Chinese, Japanese, Korean).\n* **Cyrillic and Greek Support:** The :ref:`Base-14-fonts` have integrated support of Cyrillic and Greek characters **without specifying encoding.** Your text may be a mixture of Latin, Greek and Cyrillic.\n* **Transparency support:** Parameter *opacity* is supported. This offers a handy way to create watermark-style text.\n* **Justified text:** Supported for any font -- not just simple fonts as in :meth:`Page.insert_textbox`.\n* **Reusability:** A TextWriter object exists independent from PDF pages. It can be written multiple times, either to the same or to other pages, in the same or in different PDFs, choosing different colors or transparency.\n\nUsing this object entails three steps:\n\n1. When **created**, a TextWriter requires a fixed **page rectangle** in relation to which it calculates text positions. A text writer can write to pages of this size only.\n2. Store text in the TextWriter using methods :meth:`TextWriter.append`, :meth:`TextWriter.appendv` and :meth:`TextWriter.fill_textbox` as often as is desired.\n3. Output the TextWriter object on some PDF page(s).\n\n.. note::\n\n   * Starting with version 1.17.0, TextWriters **do support** text rotation via the *morph* parameter of :meth:`TextWriter.write_text`.\n\n   * There also exists :meth:`Page.write_text` which combines one or more TextWriters and jointly writes them to a given rectangle and with a given rotation angle -- much like :meth:`Page.show_pdf_page`.\n\n\n================================ ============================================\n**Method / Attribute**           **Short Description**\n================================ ============================================\n:meth:`~TextWriter.append`       Add text in horizontal write mode\n:meth:`~TextWriter.appendv`      Add text in vertical write mode\n:meth:`~TextWriter.fill_textbox` Fill rectangle (horizontal write mode)\n:meth:`~TextWriter.write_text`   Output TextWriter to a PDF page\n:attr:`~TextWriter.color`        Text color (can be changed)\n:attr:`~TextWriter.last_point`   Last written character ends here\n:attr:`~TextWriter.opacity`      Text opacity (can be changed)\n:attr:`~TextWriter.rect`         Page rectangle used by this TextWriter\n:attr:`~TextWriter.text_rect`    Area occupied so far\n================================ ============================================\n\n\n**Class API**\n\n.. class:: TextWriter\n\n   .. method:: __init__(self, rect, opacity=1, color=None)\n\n      :arg rect-like rect: rectangle internally used for text positioning computations.\n      :arg float opacity: sets the transparency for the text to store here. Values outside the interval `[0, 1)` will be ignored. A value of e.g. 0.5 means 50% transparency.\n      :arg float,sequ color: the color of the text. All colors are specified as floats *0 <= color <= 1*. A single float represents some gray level, a sequence implies the colorspace via its length.\n\n\n   .. method:: append(pos, text, font=None, fontsize=11, language=None, right_to_left=False, small_caps=0)\n\n      * *Changed in v1.18.9*\n      * *Changed in v1.18.15*\n\n      Add some new text in horizontal writing.\n\n      :arg point_like pos: start position of the text, the bottom left point of the first character.\n      :arg str text: a string of arbitrary length. It will be written starting at position \"pos\".\n      :arg font: a :ref:`Font`. If omitted, `pymupdf.Font(\"helv\")` will be used.\n      :arg float fontsize: the :data:`fontsize`, a positive number, default 11.\n      :arg str language: the language to use, e.g. \"en\" for English. Meaningful values should be compliant with the ISO 639 standards 1, 2, 3 or 5. Reserved for future use: currently has no effect as far as we know.\n      :arg bool right_to_left: *(New in v1.18.9)* whether the text should be written from right to left. Applicable for languages like Arabian or Hebrew. Default is ``False``. If ``True``, any Latin parts within the text will automatically converted. There are no other consequences, i.e. :attr:`TextWriter.last_point` will still be the rightmost character, and there neither is any alignment taking place. Hence you may want to use :meth:`TextWriter.fill_textbox` instead.\n      :arg bool small_caps: *(New in v1.18.15)* look for the character's Small Capital version in the font. If present, take that value instead. Otherwise the original character (this font or the fallback font) will be taken. The fallback font will never return small caps. For example, this snippet::\n\n         >>> doc = pymupdf.open()\n         >>> page = doc.new_page()\n         >>> text = \"PyMuPDF: the Python bindings for MuPDF\"\n         >>> font = pymupdf.Font(\"figo\")  # choose a font with small caps\n         >>> tw = pymupdf.TextWriter(page.rect)\n         >>> tw.append((50,100), text, font=font, small_caps=True)\n         >>> tw.write_text(page)\n         >>> doc.ez_save(\"x.pdf\")\n\n         will produce this PDF text:\n\n         .. image:: images/img-smallcaps.*\n\n\n      :returns: :attr:`text_rect` and :attr:`last_point`. *(Changed in v1.18.0:)* Raises an exception for an unsupported font -- checked via :attr:`Font.is_writable`.\n\n\n   .. method:: appendv(pos, text, font=None, fontsize=11, language=None, small_caps=0)\n\n      *Changed in v1.18.15*\n\n      Add some new text in vertical, top-to-bottom writing.\n\n      :arg point_like pos: start position of the text, the bottom left point of the first character.\n      :arg str text: a string. It will be written starting at position \"pos\".\n      :arg font: a :ref:`Font`. If omitted, `pymupdf.Font(\"helv\")` will be used.\n      :arg float fontsize: the :data:`fontsize`, a positive float, default 11.\n      :arg str language: the language to use, e.g. \"en\" for English. Meaningful values should be compliant with the ISO 639 standards 1, 2, 3 or 5. Reserved for future use: currently has no effect as far as we know.\n      :arg bool small_caps: *(New in v1.18.15)* see :meth:`append`.\n\n      :returns: :attr:`text_rect` and :attr:`last_point`. *(Changed in v1.18.0:)* Raises an exception for an unsupported font -- checked via :attr:`Font.is_writable`.\n\n   .. method:: fill_textbox(rect, text, *, pos=None, font=None, fontsize=11, align=0, right_to_left=False, warn=None, small_caps=0)\n\n      * Changed in 1.17.3: New parameter `pos` to specify where to start writing within rectangle.\n      * Changed in v1.18.9: Return list of lines which do not fit in rectangle. Support writing right-to-left (e.g. Arabian, Hebrew).\n      * Changed in v1.18.15: Prefer small caps if supported by the font.\n\n      Fill a given rectangle with text in horizontal writing mode. This is a convenience method to use as an alternative for :meth:`append`.\n\n      :arg rect_like rect: the area to fill. No part of the text will appear outside of this.\n      :arg str,sequ text: the text. Can be specified as a (UTF-8) string or a list / tuple of strings. A string will first be converted to a list using *splitlines()*. Every list item will begin on a new line (forced line breaks).\n      :arg point_like pos: *(new in v1.17.3)* start storing at this point. Default is a point near rectangle top-left.\n      :arg font: the :ref:`Font`, default `pymupdf.Font(\"helv\")`.\n      :arg float fontsize: the :data:`fontsize`.\n      :arg int align: text alignment. Use one of TEXT_ALIGN_LEFT, TEXT_ALIGN_CENTER, TEXT_ALIGN_RIGHT or TEXT_ALIGN_JUSTIFY.\n      :arg bool right_to_left: *(New in v1.18.9)* whether the text should be written from right to left. Applicable for languages like Arabian or Hebrew. Default is ``False``. If ``True``, any Latin parts are automatically reverted. You must still set the alignment (if you want right alignment), it does not happen automatically -- the other alignment options remain available as well.\n      :arg bool warn: on text overflow do nothing (``None``), warn (``True``), or raise an exception (``False``). Overflow text will never be written. **Changed in v1.18.9:**\n\n        * Default is ``None``.\n        * The list of overflow lines will be returned.\n        * When ``None`` or ``True`` the partial text will be written.\n        * When ``False``, and an exception is raised, the text *will not* be written.\n\n      :arg bool small_caps: *(New in v1.18.15)* see :meth:`append`.\n\n      :rtype: list\n      :returns: *New in v1.18.9* -- List of lines that did not fit in the rectangle. Each item is a tuple `(text, length)` containing a string and its length (on the page).\n\n   .. note:: Use these methods as often as is required -- there is no technical limit (except memory constraints of your system). You can also mix :meth:`append` and text boxes and have multiple of both. Text positioning is exclusively controlled by the insertion point. Therefore there is no need to adhere to any order. *(Changed in v1.18.0:)* Raise an exception for an unsupported font -- checked via :attr:`Font.is_writable`.\n\n\n   .. method:: write_text(page, opacity=None, color=None, morph=None, overlay=True, oc=0, render_mode=0)\n\n      Write the TextWriter text to a page, which is the only mandatory parameter. The other parameters can be used to temporarily override the values used when the TextWriter was created.\n\n      :arg page: write to this :ref:`Page`.\n      :arg float opacity: override the value of the TextWriter for this output.\n      :arg sequ color: override the value of the TextWriter for this output.\n      :arg sequ morph: modify the text appearance by applying a matrix to it. If provided, this must be a sequence *(fixpoint, matrix)* with a point-like *fixpoint* and a matrix-like *matrix*. A typical example is rotating the text around *fixpoint*.\n      :arg bool overlay: put in foreground (default) or background.\n      :arg int oc: *(new in v1.18.4)* the :data:`xref` of an :data:`OCG` or :data:`OCMD`.\n      :arg int render_mode: The PDF `Tr` operator value. Values: 0 (default), 1, 2, 3 (invisible).\n\n         .. image:: images/img-rendermode.*\n\n\n   .. attribute:: text_rect\n\n      The area currently occupied.\n\n      :rtype: :ref:`Rect`\n\n   .. attribute:: last_point\n\n      The \"cursor position\" -- a :ref:`Point` -- after the last written character (its bottom-right).\n\n      :rtype: :ref:`Point`\n\n   .. attribute:: opacity\n\n      The text opacity (modifiable).\n\n      :rtype: float\n\n   .. attribute:: color\n\n      The text color (modifiable).\n\n      :rtype: float,tuple\n\n   .. attribute:: rect\n\n      The page rectangle for which this TextWriter was created. Must not be modified.\n\n      :rtype: :ref:`Rect`\n\n\n.. note:: To see some demo scripts dealing with TextWriter, have a look at `the TextWriter demo scripts <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/textwriter>`_.\n\n  1. Opacity and color apply to **all the text** in this object.\n  2. If you need different colors / transparency, you must create a separate TextWriter. Whenever you determine the color should change, simply append the text to the respective TextWriter using the previously returned :attr:`last_point` as position for the new text span.\n  3. Appending items or text boxes can occur in arbitrary order: only the position parameter controls where text appears.\n  4. Font and :data:`fontsize` can freely vary within the same TextWriter. This can be used to let text with different properties appear on the same displayed line: just specify *pos* accordingly, and e.g. set it to :attr:`last_point` of the previously added item.\n  5. You can use the *pos* argument of :meth:`TextWriter.fill_textbox` to set the position of the first text character. This allows filling the same textbox with contents from different :ref:`TextWriter` objects, thus allowing for multiple colors, opacities, etc.\n  6. MuPDF does not support all fonts with this feature, e.g. no Type3 fonts. Starting with v1.18.0 this can be checked via the font attribute :attr:`Font.is_writable`. This attribute is also checked when using :ref:`TextWriter` methods.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/the-basics.rst",
    "content": ".. include:: header.rst\n\n.. _TheBasics:\n\n\n==============================\nThe Basics\n==============================\n\n.. _The_Basics_Opening_Files:\n\nOpening a File\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\nTo open a file, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"a.pdf\") # open a document\n\n\n.. note::\n\n    **Taking it further**\n\n    See the :ref:`list of supported file types<Supported_File_Types>` and :ref:`The How to Guide on Opening Files <HowToOpenAFile>` for more advanced options.\n\n\n----------\n\n\n.. _The_Basics_Extracting_Text:\n\nExtract text from a |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo extract all the text from a |PDF| file, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"a.pdf\") # open a document\n    out = open(\"output.txt\", \"wb\") # create a text output\n    for page in doc: # iterate the document pages\n        text = page.get_text().encode(\"utf8\") # get plain text (is in UTF-8)\n        out.write(text) # write text of page\n        out.write(bytes((12,))) # write page delimiter (form feed 0x0C)\n    out.close()\n\nOf course it is not just |PDF| which can have text extracted - all the :ref:`supported document file formats <About_Feature_Matrix>` such as :title:`MOBI`, :title:`EPUB`, :title:`TXT` can have their text extracted.\n\n.. note::\n\n    **Taking it further**\n\n    If your document contains image based text content the use OCR on the page for subsequent text extraction:\n\n    .. code-block:: python\n\n        tp = page.get_textpage_ocr()\n        text = page.get_text(textpage=tp)\n\n    There are many more examples which explain how to extract text from specific areas or how to extract tables from documents. Please refer to the :ref:`How to Guide for Text<RecipesText>`.\n\n    You can now also :ref:`extract text in Markdown format<rag_outputting_as_md>`.\n\n    **API reference**\n\n    - :meth:`Page.get_text`\n\n\n\n\n\n----------\n\n\n.. _The_Basics_Extracting_Images:\n\nExtract images from a |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo extract all the images from a |PDF| file, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open a document\n\n    for page_index in range(len(doc)): # iterate over pdf pages\n        page = doc[page_index] # get the page\n        image_list = page.get_images()\n\n        # print the number of images found on the page\n        if image_list:\n            print(f\"Found {len(image_list)} images on page {page_index}\")\n        else:\n            print(\"No images found on page\", page_index)\n\n        for image_index, img in enumerate(image_list, start=1): # enumerate the image list\n            xref = img[0] # get the XREF of the image\n            pix = pymupdf.Pixmap(doc, xref) # create a Pixmap\n\n            if pix.n - pix.alpha > 3: # CMYK: convert to RGB first\n                pix = pymupdf.Pixmap(pymupdf.csRGB, pix)\n\n            pix.save(f\"page_{page_index}-image_{image_index}.png\") # save the image as png\n            pix = None\n\n\n\n.. note::\n\n    **Taking it further**\n\n    There are many more examples which explain how to extract text from specific areas or how to extract tables from documents. Please refer to the :ref:`How to Guide for Text<RecipesText>`.\n\n    **API reference**\n\n    - :meth:`Page.get_images`\n    - :ref:`Pixmap<Pixmap>`\n\n\n\n.. _The_Basics_Extracting_Vector_Graphics:\n\nExtract vector graphics\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo extract all the vector graphics from a document page, do the following:\n\n\n.. code-block:: python\n\n    doc = pymupdf.open(\"some.file\")\n    page = doc[0]\n    paths = page.get_drawings()\n\n\nThis will return a dictionary of paths for any vector drawings found on the page.\n\n.. note::\n\n    **Taking it further**\n\n    Please refer to: :ref:`How to Extract Drawings<RecipesDrawingAndGraphics_Extract_Drawings>`.\n\n    **API reference**\n\n    - :meth:`Page.get_drawings`\n\n\n\n----------\n\n.. _The_Basics_Merging_PDF:\n.. _merge PDF:\n.. _join PDF:\n\nMerging |PDF| files\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo merge |PDF| files, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc_a = pymupdf.open(\"a.pdf\") # open the 1st document\n    doc_b = pymupdf.open(\"b.pdf\") # open the 2nd document\n\n    doc_a.insert_pdf(doc_b) # merge the docs\n    doc_a.save(\"a+b.pdf\") # save the merged document with a new filename\n\n\nMerging |PDF| files with other types of file\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\nWith :meth:`Document.insert_file` you can invoke the method to merge :ref:`supported files<Supported_File_Types>` with |PDF|. For example:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc_a = pymupdf.open(\"a.pdf\") # open the 1st document\n    doc_b = pymupdf.open(\"b.svg\") # open the 2nd document\n\n    doc_a.insert_file(doc_b) # merge the docs\n    doc_a.save(\"a+b.pdf\") # save the merged document with a new filename\n\n\n.. note::\n\n    **Taking it further**\n\n    It is easy to join PDFs with :meth:`Document.insert_pdf` & :meth:`Document.insert_file`. Given open |PDF| documents, you can copy page ranges from one to the other. You can select the point where the copied pages should be placed, you can revert the page sequence and also change page rotation.\n\n    The GUI script `join.py <https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py>`_ uses this method to join a list of files while also joining the respective table of contents segments. It looks like this:\n\n    .. image:: images/img-pdfjoiner.*\n       :scale: 60\n\n    **API reference**\n\n    - :meth:`Document.insert_pdf`\n    - :meth:`Document.insert_file`\n\n\n----------\n\n\nWorking with Coordinates\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThere is one *mathematical term* that you should feel comfortable with when using |PyMuPDF| -  **\"coordinates\"**. Please have a quick look at the :ref:`Coordinates` section to understand the coordinate system to help you with positioning objects and understand your document space.\n\n\n\n----------\n\n.. _The_Basics_Watermarks:\n\nAdding a watermark to a |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo add a watermark to a |PDF| file, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"document.pdf\") # open a document\n\n    for page_index in range(len(doc)): # iterate over pdf pages\n        page = doc[page_index] # get the page\n\n        # insert an image watermark from a file name to fit the page bounds\n        page.insert_image(page.bound(),filename=\"watermark.png\", overlay=False)\n\n    doc.save(\"watermarked-document.pdf\") # save the document with a new filename\n\n.. note::\n\n    **Taking it further**\n\n    Adding watermarks is essentially as simple as adding an image at the base of each |PDF| page. You should ensure that the image has the required opacity and aspect ratio to make it look the way you need it to.\n\n    In the example above a new image is created from each file reference, but to be more performant (by saving memory and file size) this image data should be referenced only once - see the code example and explanation on :meth:`Page.insert_image` for the implementation.\n\n    **API reference**\n\n    - :meth:`Page.bound`\n    - :meth:`Page.insert_image`\n\n\n----------\n\n\n.. _The_Basics_Images:\n\nAdding an image to a |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo add an image to a |PDF| file, for example a logo, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"document.pdf\") # open a document\n\n    for page_index in range(len(doc)): # iterate over pdf pages\n        page = doc[page_index] # get the page\n\n        # insert an image logo from a file name at the top left of the document\n        page.insert_image(pymupdf.Rect(0,0,50,50),filename=\"my-logo.png\")\n\n    doc.save(\"logo-document.pdf\") # save the document with a new filename\n\n.. note::\n\n    **Taking it further**\n\n    As with the watermark example you should ensure to be more performant by only referencing the image once if possible - see the code example and explanation on :meth:`Page.insert_image`.\n\n    **API reference**\n\n    - :ref:`Rect<Rect>`\n    - :meth:`Page.insert_image`\n\n\n----------\n\n\n.. _The_Basics_Rotating:\n\nRotating a |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo add a rotation to a page, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open document\n    page = doc[0] # get the 1st page of the document\n    page.set_rotation(90) # rotate the page\n    doc.save(\"rotated-page-1.pdf\")\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Page.set_rotation`\n\n\n----------\n\n.. _The_Basics_Cropping:\n\nCropping a |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo crop a page to a defined :ref:`Rect<Rect>`, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open document\n    page = doc[0] # get the 1st page of the document\n    page.set_cropbox(pymupdf.Rect(100, 100, 400, 400)) # set a cropbox for the page\n    doc.save(\"cropped-page-1.pdf\")\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Page.set_cropbox`\n\n\n----------\n\n\n.. _The_Basics_Attaching_Files:\n\n:index:`Attaching Files <triple: attach;embed;file>`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo attach another file to a page, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open main document\n    attachment = pymupdf.open(\"my-attachment.pdf\") # open document you want to attach\n\n    page = doc[0] # get the 1st page of the document\n    point = pymupdf.Point(100, 100) # create the point where you want to add the attachment\n    attachment_data = attachment.tobytes() # get the document byte data as a buffer\n\n    # add the file annotation with the point, data and the file name\n    file_annotation = page.add_file_annot(point, attachment_data, \"attachment.pdf\")\n\n    doc.save(\"document-with-attachment.pdf\") # save the document\n\n\n.. note::\n\n    **Taking it further**\n\n    When adding the file with :meth:`Page.add_file_annot` note that the third parameter for the `filename` should include the actual file extension. Without this the attachment possibly will not be able to be recognized as being something which can be opened. For example, if the `filename` is just *\"attachment\"* when view the resulting PDF and attempting to open the attachment you may well get an error. However, with *\"attachment.pdf\"* this can be recognized and opened by PDF viewers as a valid file type.\n\n    The default icon for the attachment is by default a \"push pin\", however you can change this by setting the `icon` parameter.\n\n    **API reference**\n\n    - :ref:`Point<Point>`\n    - :meth:`Document.tobytes`\n    - :meth:`Page.add_file_annot`\n\n\n----------\n\n\n.. _The_Basics_Embedding_Files:\n\n:index:`Embedding Files <triple: attach;embed;file>`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo embed a file to a document, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open main document\n    embedded_doc = pymupdf.open(\"my-embed.pdf\") # open document you want to embed\n\n    embedded_data = embedded_doc.tobytes() # get the document byte data as a buffer\n\n    # embed with the file name and the data\n    doc.embfile_add(\"my-embedded_file.pdf\", embedded_data)\n\n    doc.save(\"document-with-embed.pdf\") # save the document\n\n.. note::\n\n    **Taking it further**\n\n    As with :ref:`attaching files<The_Basics_Attaching_Files>`, when adding the file with :meth:`Document.embfile_add` note that the first parameter for the `filename` should include the actual file extension.\n\n    **API reference**\n\n    - :meth:`Document.tobytes`\n    - :meth:`Document.embfile_add`\n\n\n----------\n\n\n\n.. _The_Basics_Deleting_Pages:\n\nDeleting Pages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo delete a page from a document, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open a document\n    doc.delete_page(0) # delete the 1st page of the document\n    doc.save(\"test-deleted-page-one.pdf\") # save the document\n\nTo delete a multiple pages from a document, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open a document\n    doc.delete_pages(from_page=9, to_page=14) # delete a page range from the document\n    doc.save(\"test-deleted-pages.pdf\") # save the document\n\n\nWhat happens if I delete a page referred to by bookmarks or hyperlinks?\n\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\"\n\n- A bookmark (entry in the Table of Contents) will become inactive and will no longer navigate to any page.\n\n- A hyperlink will be removed from the page that contains it. The visible content on that page will not otherwise be changed in any way.\n\n.. note::\n\n    **Taking it further**\n\n    The page index is zero-based, so to delete page 10 of a document you would do the following `doc.delete_page(9)`.\n\n    Similarly, `doc.delete_pages(from_page=9, to_page=14)` will delete pages 10 - 15 inclusive.\n\n\n    **API reference**\n\n    - :meth:`Document.delete_page`\n    - :meth:`Document.delete_pages`\n\n----------\n\n\n.. _The_Basics_Rearrange_Pages:\n\nRe-Arranging Pages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTo change the sequence of pages, i.e. re-arrange pages, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open a document\n    doc.move_page(1,0) # move the 2nd page of the document to the start of the document\n    doc.save(\"test-page-moved.pdf\") # save the document\n\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Document.move_page`\n\n----------\n\n\n\n.. _The_Basics_Copying_Pages:\n\nCopying Pages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\nTo copy pages, do the following:\n\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open a document\n    doc.copy_page(0) # copy the 1st page and puts it at the end of the document\n    doc.save(\"test-page-copied.pdf\") # save the document\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Document.copy_page`\n\n\n----------\n\n.. _The_Basics_Selecting_Pages:\n\nSelecting Pages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\nTo select pages, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(\"test.pdf\") # open a document\n    doc.select([0, 1]) # select the 1st & 2nd page of the document\n    doc.save(\"just-page-one-and-two.pdf\") # save the document\n\n\n.. note::\n\n    **Taking it further**\n\n    With |PyMuPDF| you have all options to copy, move, delete or re-arrange the pages of a |PDF|. Intuitive methods exist that allow you to do this on a page-by-page level, like the :meth:`Document.copy_page` method.\n\n    Or you alternatively prepare a complete new page layout in form of a :title:`Python` sequence, that contains the page numbers you want, in the sequence you want, and as many times as you want each page. The following may illustrate what can be done with :meth:`Document.select`\n\n    .. code-block:: python\n\n        doc.select([1, 1, 1, 5, 4, 9, 9, 9, 0, 2, 2, 2])\n\n\n    Now let's prepare a PDF for double-sided printing (on a printer not directly supporting this):\n\n    The number of pages is given by `len(doc)` (equal to `doc.page_count`). The following lists represent the even and the odd page numbers, respectively:\n\n    .. code-block:: python\n\n        p_even = [p in range(doc.page_count) if p % 2 == 0]\n        p_odd  = [p in range(doc.page_count) if p % 2 == 1]\n\n    This snippet creates the respective sub documents which can then be used to print the document:\n\n    .. code-block:: python\n\n        doc.select(p_even) # only the even pages left over\n        doc.save(\"even.pdf\") # save the \"even\" PDF\n        doc.close() # recycle the file\n        doc = pymupdf.open(doc.name) # re-open\n        doc.select(p_odd) # and do the same with the odd pages\n        doc.save(\"odd.pdf\")\n\n\n    For more information also have a look at this Wiki `article <https://github.com/pymupdf/PyMuPDF/wiki/Rearranging-Pages-of-a-PDF>`_.\n\n\n    The following example will reverse the order of all pages (**extremely fast:** sub-second time for the 756 pages of the :ref:`AdobeManual`):\n\n    .. code-block:: python\n\n        lastPage = doc.page_count - 1\n        for i in range(lastPage):\n            doc.move_page(lastPage, i) # move current last page to the front\n\n\n\n    This snippet duplicates the PDF with itself so that it will contain the pages *0, 1, ..., n, 0, 1, ..., n* **(extremely fast and without noticeably increasing the file size!)**:\n\n    .. code-block:: python\n\n        page_count = len(doc)\n        for i in range(page_count):\n            doc.copy_page(i) # copy this page to after last page\n\n\n\n    **API reference**\n\n    - :meth:`Document.select`\n\n----------\n\n\n.. _The_Basics_Adding_Blank_Pages:\n\n\n\n\nAdding Blank Pages\n~~~~~~~~~~~~~~~~~~~~~\n\nTo add a blank page, do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(...) # some new or existing PDF document\n    page = doc.new_page(-1, # insertion point: end of document\n                        width = 595, # page dimension: A4 portrait\n                        height = 842)\n    doc.save(\"doc-with-new-blank-page.pdf\") # save the document\n\n\n.. note::\n\n    **Taking it further**\n\n    Use this to create the page with another pre-defined paper format:\n\n    .. code-block:: python\n\n        w, h = pymupdf.paper_size(\"letter-l\")  # 'Letter' landscape\n        page = doc.new_page(width = w, height = h)\n\n\n    The convenience function :meth:`paper_size` knows over 40 industry standard paper formats to choose from. To see them, inspect dictionary :attr:`paperSizes`. Pass the desired dictionary key to :meth:`paper_size` to retrieve the paper dimensions. Upper and lower case is supported. If you append \"-L\" to the format name, the landscape version is returned.\n\n    Here is a 3-liner that creates a |PDF|: with one empty page. Its file size is 460 bytes:\n\n    .. code-block:: python\n\n        doc = pymupdf.open()\n        doc.new_page()\n        doc.save(\"A4.pdf\")\n\n\n    **API reference**\n\n    - :meth:`Document.new_page`\n    - :attr:`paperSizes`\n\n\n----------\n\n\n.. _The_Basics_Inserting_Pages:\n\nInserting Pages with Text Content\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nUsing the :meth:`Document.insert_page` method also inserts a new page and accepts the same ``width`` and ``height`` parameters. But it lets you also insert arbitrary text into the new page and returns the number of inserted lines.\n\n.. code-block:: python\n\n    import pymupdf\n\n    doc = pymupdf.open(...)  # some new or existing PDF document\n    n = doc.insert_page(-1, # default insertion point\n                        text = \"The quick brown fox jumped over the lazy dog\",\n                        fontsize = 11,\n                        width = 595,\n                        height = 842,\n                        fontname = \"Helvetica\", # default font\n                        fontfile = None, # any font file name\n                        color = (0, 0, 0)) # text color (RGB)\n\n\n\n\n.. note::\n\n    **Taking it further**\n\n    The text parameter can be a (sequence of) string (assuming UTF-8 encoding). Insertion will start at :ref:`Point` (50, 72), which is one inch below top of page and 50 points from the left. The number of inserted text lines is returned.\n\n    **API reference**\n\n    - :meth:`Document.insert_page`\n\n\n\n----------\n\n\n\n.. _The_Basics_Spliting_Single_Pages:\n\nSplitting Single Pages\n~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis deals with splitting up pages of a |PDF| in arbitrary pieces. For example, you may have a |PDF| with *Letter* format pages which you want to print with a magnification factor of four: each page is split up in 4 pieces which each going to a separate |PDF| page in *Letter* format again.\n\n\n\n.. code-block:: python\n\n    import pymupdf\n\n    src = pymupdf.open(\"test.pdf\")\n    doc = pymupdf.open()  # empty output PDF\n\n    for spage in src:  # for each page in input\n        r = spage.rect  # input page rectangle\n        d = pymupdf.Rect(spage.cropbox_position,  # CropBox displacement if not\n                      spage.cropbox_position)  # starting at (0, 0)\n        #--------------------------------------------------------------------------\n        # example: cut input page into 2 x 2 parts\n        #--------------------------------------------------------------------------\n        r1 = r / 2  # top left rect\n        r2 = r1 + (r1.width, 0, r1.width, 0)  # top right rect\n        r3 = r1 + (0, r1.height, 0, r1.height)  # bottom left rect\n        r4 = pymupdf.Rect(r1.br, r.br)  # bottom right rect\n        rect_list = [r1, r2, r3, r4]  # put them in a list\n\n        for rx in rect_list:  # run thru rect list\n            rx += d  # add the CropBox displacement\n            page = doc.new_page(-1,  # new output page with rx dimensions\n                               width = rx.width,\n                               height = rx.height)\n            page.show_pdf_page(\n                    page.rect,  # fill all new page with the image\n                    src,  # input document\n                    spage.number,  # input page number\n                    clip = rx,  # which part to use of input page\n                )\n\n    # that's it, save output file\n    doc.save(\"poster-\" + src.name,\n             garbage=3,  # eliminate duplicate objects\n             deflate=True,  # compress stuff where possible\n    )\n\n\nExample:\n\n.. image:: images/img-posterize.png\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Page.cropbox_position`\n    - :meth:`Page.show_pdf_page`\n\n\n--------------------------\n\n\n.. _The_Basics_Combining_Single_Pages:\n\n\nCombining Single Pages\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nThis deals with joining |PDF| pages to form a new |PDF| with pages each combining two or four original ones (also called \"2-up\", \"4-up\", etc.). This could be used to create booklets or thumbnail-like overviews.\n\n\n.. code-block:: python\n\n    import pymupdf\n\n    src = pymupdf.open(\"test.pdf\")\n    doc = pymupdf.open()  # empty output PDF\n\n    width, height = pymupdf.paper_size(\"a4\")  # A4 portrait output page format\n    r = pymupdf.Rect(0, 0, width, height)\n\n    # define the 4 rectangles per page\n    r1 = r / 2  # top left rect\n    r2 = r1 + (r1.width, 0, r1.width, 0)  # top right\n    r3 = r1 + (0, r1.height, 0, r1.height)  # bottom left\n    r4 = pymupdf.Rect(r1.br, r.br)  # bottom right\n\n    # put them in a list\n    r_tab = [r1, r2, r3, r4]\n\n    # now copy input pages to output\n    for spage in src:\n        if spage.number % 4 == 0:  # create new output page\n            page = doc.new_page(-1,\n                          width = width,\n                          height = height)\n        # insert input page into the correct rectangle\n        page.show_pdf_page(r_tab[spage.number % 4],  # select output rect\n                         src,  # input document\n                         spage.number)  # input page number\n\n    # by all means, save new file using garbage collection and compression\n    doc.save(\"4up.pdf\", garbage=3, deflate=True)\n\n\nExample:\n\n.. image:: images/img-4up.png\n\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Page.cropbox_position`\n    - :meth:`Page.show_pdf_page`\n\n--------------------------\n\n\n.. _The_Basics_Encryption_and_Decryption:\n\n\n|PDF| Encryption & Decryption\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\n\nStarting with version 1.16.0, |PDF| decryption and encryption (using passwords) are fully supported. You can do the following:\n\n* Check whether a document is password protected / (still) encrypted (:attr:`Document.needs_pass`, :attr:`Document.is_encrypted`).\n* Gain access authorization to a document (:meth:`Document.authenticate`).\n* Set encryption details for PDF files using :meth:`Document.save` or :meth:`Document.write` and\n\n    - decrypt or encrypt the content\n    - set password(s)\n    - set the encryption method\n    - set permission details\n\n.. note:: A PDF document may have two different passwords:\n\n   * The **owner password** provides full access rights, including changing passwords, encryption method, or permission detail.\n   * The **user password** provides access to document content according to the established permission details. If present, opening the |PDF| in a viewer will require providing it.\n\n   Method :meth:`Document.authenticate` will automatically establish access rights according to the password used.\n\nThe following snippet creates a new |PDF| and encrypts it with separate user and owner passwords. Permissions are granted to print, copy and annotate, but no changes are allowed to someone authenticating with the user password.\n\n\n.. code-block:: python\n\n    import pymupdf\n\n    text = \"some secret information\" # keep this data secret\n    perm = int(\n        pymupdf.PDF_PERM_ACCESSIBILITY # always use this\n        | pymupdf.PDF_PERM_PRINT # permit printing\n        | pymupdf.PDF_PERM_COPY # permit copying\n        | pymupdf.PDF_PERM_ANNOTATE # permit annotations\n    )\n    owner_pass = \"owner\" # owner password\n    user_pass = \"user\" # user password\n    encrypt_meth = pymupdf.PDF_ENCRYPT_AES_256 # strongest algorithm\n    doc = pymupdf.open() # empty pdf\n    page = doc.new_page() # empty page\n    page.insert_text((50, 72), text) # insert the data\n    doc.save(\n        \"secret.pdf\",\n        encryption=encrypt_meth, # set the encryption method\n        owner_pw=owner_pass, # set the owner password\n        user_pw=user_pass, # set the user password\n        permissions=perm, # set permissions\n    )\n\n\n\n.. note::\n\n    **Taking it further**\n\n    Opening this document with some viewer (Nitro Reader 5) reflects these settings:\n\n    .. image:: images/img-encrypting.*\n\n    **Decrypting** will automatically happen on save as before when no encryption parameters are provided.\n\n    To **keep the encryption method** of a PDF save it using `encryption=pymupdf.PDF_ENCRYPT_KEEP`. If `doc.can_save_incrementally() == True`, an incremental save is also possible.\n\n    To **change the encryption method** specify the full range of options above (`encryption`, `owner_pw`, `user_pw`, `permissions`). An incremental save is **not possible** in this case.\n\n    **API reference**\n\n    - :meth:`Document.save`\n\n--------------------------\n\n\n\n.. _The_Basics_Extracting_Tables:\n\nExtracting Tables from a :title:`Page`\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nTables can be found and extracted from any document :ref:`Page`.\n\n.. code-block:: python\n\n    import pymupdf\n    from pprint import pprint\n\n    doc = pymupdf.open(\"test.pdf\") # open document\n    page = doc[0] # get the 1st page of the document\n    tabs = page.find_tables() # locate and extract any tables on page\n    print(f\"{len(tabs.tables)} found on {page}\") # display number of found tables\n\n    if tabs.tables:  # at least one table found?\n       pprint(tabs[0].extract())  # print content of first table\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Page.find_tables`\n\n\n.. important::\n\n    There is also the `pdf2docx extract tables method`_ which is capable of table extraction if you prefer.\n\n\n--------------------------\n\n\n.. _The_Basics_Get_Page_Links:\n\nGetting Page Links\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nLinks can be extracted from a :ref:`Page` to return :ref:`Link` objects.\n\n\n.. code-block:: python\n\n    import pymupdf\n\n    for page in doc: # iterate the document pages\n        link = page.first_link  # a `Link` object or `None`\n\n        while link: # iterate over the links on page\n            # do something with the link, then:\n            link = link.next # get next link, last one has `None` in its `next`\n\n\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Page.first_link`\n\n\n-----------------------------\n\n\n.. _The_Basics_Get_All_Annotations:\n\nGetting All Annotations from a Document\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nAnnotations (:ref:`Annot`) on pages can be retrieved with the `page.annots()` method.\n\n.. code-block:: python\n\n    import pymupdf\n\n    for page in doc:\n        for annot in page.annots():\n            print(f'Annotation on page: {page.number} with type: {annot.type} and rect: {annot.rect}')\n\n\n.. note::\n\n    **API reference**\n\n    - :meth:`Page.annots`\n\n\n--------------------------\n\n\n\n.. _The_Basics_Redacting:\n\nRedacting content from a |PDF|\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nRedactions are special types of annotations which can be marked onto a document page to denote an area on the page which should be securely removed. After marking an area with a rectangle then this area will be marked for *redaction*, once the redaction is *applied* then the content is securely removed.\n\nFor example if we wanted to redact all instances of the name \"Jane Doe\" from a document we could do the following:\n\n.. code-block:: python\n\n    import pymupdf\n\n    # Open the PDF document\n    doc = pymupdf.open('test.pdf')\n\n    # Iterate over each page of the document\n    for page in doc:\n        # Find all instances of \"Jane Doe\" on the current page\n        instances = page.search_for(\"Jane Doe\")\n\n        # Redact each instance of \"Jane Doe\" on the current page\n        for inst in instances:\n            page.add_redact_annot(inst)\n\n        # Apply the redactions to the current page\n        page.apply_redactions()\n\n    # Save the modified document\n    doc.save('redacted_document.pdf')\n\n    # Close the document\n    doc.close()\n\n\nAnother example could be redacting an area of a page, but not to redact any line art (i.e. vector graphics) within the defined area, by setting a parameter flag as follows:\n\n\n.. code-block:: python\n\n    import pymupdf\n\n    # Open the PDF document\n    doc = pymupdf.open('test.pdf')\n\n    # Get the first page\n    page = doc[0]\n\n    # Add an area to redact\n    rect = [0,0,200,200]\n\n    # Add a redacction annotation which will have a red fill color\n    page.add_redact_annot(rect, fill=(1,0,0))\n\n    # Apply the redactions to the current page, but ignore vector graphics\n    page.apply_redactions(graphics=0)\n\n    # Save the modified document\n    doc.save('redactied_document.pdf')\n\n    # Close the document\n    doc.close()\n\n\n.. warning::\n\n    Once a redacted version of a document is saved then the redacted content in the |PDF| is *irretrievable*. Thus, a redacted area in a document removes text and graphics completely from that area.\n\n\n.. note::\n\n    **Taking it further**\n\n    The are a few options for creating and applying redactions to a page, for the full API details to understand the parameters to control these options refer to the API reference.\n\n    **API reference**\n\n    - :meth:`Page.add_redact_annot`\n\n    - :meth:`Page.apply_redactions`\n\n\n--------------------------\n\n\n\n.. _The Basics_Coverting_PDF_Documents:\n\nConverting PDF Documents\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n\nWe recommend the pdf2docx_ library which uses |PyMuPDF| and the **python-docx** library to provide simple document conversion from |PDF| to **DOCX** format.\n\n\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/tools.rst",
    "content": ".. include:: header.rst\n\n.. _Tools:\n\nTools\n================\n\nThis class is a collection of utility methods and attributes, mainly around memory management. To simplify and speed up its use, it is automatically instantiated under the name *TOOLS* when PyMuPDF is imported.\n\n====================================== =================================================\n**Method / Attribute**                 **Description**\n====================================== =================================================\n:meth:`Tools.gen_id`                   generate a unique identifier\n:meth:`Tools.store_shrink`             shrink the storables cache [#f1]_\n:meth:`Tools.mupdf_warnings`           return the accumulated MuPDF warnings\n:meth:`Tools.mupdf_display_errors`     control whether MuPDF errors are displayed as messages.\n:meth:`Tools.mupdf_display_warnings`   control whether MuPDF warnings are displayed as messages.\n:meth:`Tools.reset_mupdf_warnings`     empty MuPDF warnings/errors message buffer.\n:meth:`Tools.set_aa_level`             set the anti-aliasing values\n:meth:`Tools.set_annot_stem`           set the prefix of new annotation / link ids\n:meth:`Tools.set_small_glyph_heights`  search and extract using small bbox heights\n:meth:`Tools.set_subset_fontnames`     control suppression of subset fontname tags\n:meth:`Tools.show_aa_level`            return the anti-aliasing values\n:meth:`Tools.unset_quad_corrections`   disable PyMuPDF-specific code\n:attr:`Tools.fitz_config`              configuration settings of PyMuPDF\n:attr:`Tools.store_maxsize`            maximum storables cache size\n:attr:`Tools.store_size`               current storables cache size\n====================================== =================================================\n\n**Class API**\n\n.. class:: Tools\n\n   .. method:: gen_id()\n\n      A convenience method returning a unique positive integer which will increase by 1 on every invocation. Example usages include creating unique keys in databases - its creation should be faster than using timestamps by an order of magnitude.\n\n      .. note:: MuPDF has dropped support for this in v1.14.0, so we have re-implemented a similar function with the following differences:\n\n            * It is not part of MuPDF's global context and not threadsafe (not an issue because we do not support threads in PyMuPDF anyway).\n            * It is implemented as *int*. This means that the maximum number is *sys.maxsize*. Should this number ever be exceeded, the counter starts over again at 1.\n\n      :rtype: int\n      :returns: a unique positive integer.\n\n\n   .. method:: set_annot_stem(stem=None)\n\n      * New in v1.18.6\n\n      Set or inquire the prefix for the id of new annotations, fields or links.\n\n      :arg str stem: if omitted, the current value is returned, default is \"fitz\". Annotations, fields / widgets and links technically are subtypes of the same type of object (`/Annot`) in PDF documents. An `/Annot` object may be given a unique identifier within a page. For each of the applicable subtypes, PyMuPDF generates identifiers \"stem-Annn\", \"stem-Wnnn\" or \"stem-Lnnn\" respectively. The number \"nnn\" is used to enforce the required uniqueness.\n\n      :rtype: str\n      :returns: the current value.\n\n\n   .. method:: set_small_glyph_heights(on=None)\n\n      * New in v1.18.5\n\n      Set or inquire reduced bbox heights in text extract and text search methods.\n\n      :arg bool on: if omitted or `None`, the current setting is returned. For other values the *bool()* function is applied to set a global variable. If `True`, :meth:`Page.search_for` and :meth:`Page.get_text` methods return character, span, line or block bboxes that have a height of *font size*. If `False` (standard setting when PyMuPDF is imported), bbox height will be based on font properties and normally equal *line height*.\n\n      :rtype: bool\n      :returns: ``True`` or ``False``.\n\n      .. note:: Text extraction options \"xml\", \"xhtml\" and \"html\", which directly wrap MuPDF code, are not influenced by this.\n\n   .. method:: set_subset_fontnames(on=None)\n\n      * New in v1.18.9\n\n      Control suppression of subset fontname tags in text extractions.\n\n      :arg bool on: if omitted / `None`, the current setting is returned. Arguments evaluating to `True` or `False` set a global variable. If `True`, options \"dict\", \"json\", \"rawdict\" and \"rawjson\" will return e.g. `\"NOHSJV+Calibri-Light\"`, otherwise only `\"Calibri-Light\"` (the default). The setting remains in effect until changed again.\n\n      :rtype: bool\n      :returns: ``True`` or ``False``.\n\n      .. note:: Except mentioned above, no other text extraction variants are influenced by this. This is especially true for the options \"xml\", \"xhtml\" and \"html\", which are based on MuPDF code. They extract the font name `\"Calibri-Light\"`, or even just the **family** name -- `Calibri` in this example.\n\n\n   .. method:: unset_quad_corrections(on=None)\n\n      * New in v1.18.10\n\n      Enable / disable PyMuPDF-specific code, that tries to rebuild valid character quads when encountering nonsense in :meth:`Page.get_text` text extractions. This code depends on certain font properties (ascender and descender), which do not exist in rare situations and cause segmentation faults when trying to access them. This method sets a global parameter in PyMuPDF, which suppresses execution of this code.\n\n      :arg bool on: if omitted or `None`, the current setting is returned. For other values the *bool()* function is applied to set a global variable. If `True`, PyMuPDF will not try to access the resp. font properties and use values `ascender=0.8` and `descender=-0.2` instead.\n\n      :rtype: bool\n      :returns: ``True`` or ``False``.\n\n\n   .. method:: store_shrink(percent)\n\n      Reduce the storables cache by a percentage of its current size.\n\n      :arg int percent: the percentage of current size to free. If 100+ the store will be emptied, if zero, nothing will happen. MuPDF's caching strategy is \"least recently used\", so low-usage elements get deleted first.\n\n      :rtype: int\n      :returns: the new current store size. Depending on the situation, the size reduction may be larger than the requested percentage.\n\n   .. method:: show_aa_level()\n\n      * New in version 1.16.14\n      \n      Return the current anti-aliasing values. These values control the rendering quality of graphics and text elements.\n\n      :rtype: dict\n      :returns: A dictionary with the following initial content: `{'graphics': 8, 'text': 8, 'graphics_min_line_width': 0.0}`.\n\n\n   .. method:: set_aa_level(level)\n\n      * New in version 1.16.14\n      \n      Set the new number of bits to use for anti-aliasing. The same value is taken currently for graphics and text rendering. This might change in a future MuPDF release.\n\n      :arg int level: an integer ranging between 0 and 8. Value outside this range will be silently changed to valid values. The value will remain in effect throughout the current session or until changed again.\n\n\n   .. method:: reset_mupdf_warnings()\n\n      * New in version 1.16.0\n\n      Empty MuPDF warnings message buffer.\n\n\n   .. method:: mupdf_display_errors(value=None)\n\n      Control whether MuPDF errors should be displayed as |PyMuPDF| messages.\n\n      :arg value:\n      * If `None`, the current setting is left unchanged.\n      * Otherwise changes the current setting to `bool(value)`;\n        if ``True``, future MuPDF errors will be shown as :ref:`Messages`.\n      * Regardless of this setting, MuPDF errors will always be stored in the warnings store.\n      * Upon import of |PyMuPDF| this value is ``True``.\n\n      :returns: The current setting as ``True`` or ``False``.\n\n      * New in version 1.16.8\n\n\n   .. method:: mupdf_display_warnings(value=None)\n\n      Control whether MuPDF warnings should be displayed as |PyMuPDF| messages.\n\n      :arg value:\n      * If `None`, the current setting is left unchanged.\n      * Otherwise changes the current setting to `bool(value)`;\n        if ``True``, future MuPDF warnings will be shown as :ref:`Messages`.\n      * Regardless of this setting, MuPDF warnings will always be stored in the warnings store.\n      * Upon import of |PyMuPDF| this value is ``True``.\n\n      :returns: The current setting as ``True`` or ``False``.\n\n      * New in version 1.16.8\n\n\n   .. method:: mupdf_warnings(reset=True)\n\n      * New in version 1.16.0\n\n      Return all stored MuPDF messages as a string with interspersed line-breaks.\n\n      :arg bool reset: *(new in version 1.16.7)* whether to automatically empty the store.\n\n\n   .. attribute:: fitz_config\n\n      A dictionary containing the actual values used for configuring PyMuPDF and MuPDF. Also refer to the installation chapter. This is an overview of the keys, each of which describes the status of a support aspect.\n\n      ================= ===================================================\n      **Key**           **Support included for ...**\n      ================= ===================================================\n      plotter-g         Gray colorspace rendering\n      plotter-rgb       RGB colorspace rendering\n      plotter-cmyk      CMYK colorspcae rendering\n      plotter-n         overprint rendering\n      pdf               PDF documents\n      xps               XPS documents\n      svg               SVG documents\n      cbz               CBZ documents\n      img               IMG documents\n      html              HTML documents\n      epub              EPUB documents\n      jpx               JPEG2000 images\n      js                JavaScript\n      tofu              all TOFU fonts\n      tofu-cjk          CJK font subset (China, Japan, Korea)\n      tofu-cjk-ext      CJK font extensions\n      tofu-cjk-lang     CJK font language extensions\n      tofu-emoji        TOFU emoji fonts\n      tofu-historic     TOFU historic fonts\n      tofu-symbol       TOFU symbol fonts\n      tofu-sil          TOFU SIL fonts\n      icc               ICC profiles\n      py-memory         using Python memory management [#f2]_\n      base14            Base-14 fonts (should always be true)\n      ================= ===================================================\n\n      For an explanation of the term \"TOFU\" see `this Wikipedia article <https://en.wikipedia.org/wiki/Noto_fonts>`_::\n\n       In [1]: import pymupdf\n       In [2]: TOOLS.fitz_config\n       Out[2]:\n       {'plotter-g': True,\n        'plotter-rgb': True,\n        'plotter-cmyk': True,\n        'plotter-n': True,\n        'pdf': True,\n        'xps': True,\n        'svg': True,\n        'cbz': True,\n        'img': True,\n        'html': True,\n        'epub': True,\n        'jpx': True,\n        'js': True,\n        'tofu': False,\n        'tofu-cjk': True,\n        'tofu-cjk-ext': False,\n        'tofu-cjk-lang': False,\n        'tofu-emoji': False,\n        'tofu-historic': False,\n        'tofu-symbol': False,\n        'tofu-sil': False,\n        'icc': True,\n        'py-memory': False,\n        'base14': True}\n\n      :rtype: dict\n\n   .. attribute:: store_maxsize\n\n      Maximum storables cache size in bytes. |PyMuPDF| is generated with a value of 268'435'456 (256 MB, the default value), which you should therefore always see here. If this value is zero, then an \"unlimited\" growth is permitted.\n\n      :rtype: int\n\n   .. attribute:: store_size\n\n      Current storables cache size in bytes. This value may change (and will usually increase) with every use of a |PyMuPDF| function. It will (automatically) decrease only when :attr:`Tools.store_maxsize` is going to be exceeded: in this case, |MuPDF| will evict low-usage objects until the value is again in range.\n\n      :rtype: int\n\nExample Session\n----------------\n\n.. code-block:: python\n\n   >>> import pymupdf\n   # print the maximum and current cache sizes\n   >>> pymupdf.TOOLS.store_maxsize\n   268435456\n   >>> pymupdf.TOOLS.store_size\n   0\n   >>> doc = pymupdf.open(\"demo1.pdf\")\n   # pixmap creation puts lots of object in cache (text, images, fonts),\n   # apart from the pixmap itself\n   >>> pix = doc[0].get_pixmap(alpha=False)\n   >>> pymupdf.TOOLS.store_size\n   454519\n   # release (at least) 50% of the storage\n   >>> pymupdf.TOOLS.store_shrink(50)\n   13471\n   >>> pymupdf.TOOLS.store_size\n   13471\n   # get a few unique numbers\n   >>> pymupdf.TOOLS.gen_id()\n   1\n   >>> pymupdf.TOOLS.gen_id()\n   2\n   >>> pymupdf.TOOLS.gen_id()\n   3\n   # close document and see how much cache is still in use\n   >>> doc.close()\n   >>> pymupdf.TOOLS.store_size\n   0\n   >>>\n\n\n.. rubric:: Footnotes\n\n.. [#f1] This memory area is internally used by MuPDF, and it serves as a cache for objects that have already been read and interpreted, thus improving performance. The most bulky object types are images and also fonts. When an application starts up the MuPDF library (in our case this happens as part of *import pymupdf*), it must specify a maximum size for this area. PyMuPDF's uses the default value (256 MB) to limit memory consumption. Use the methods here to control or investigate store usage. For example: even after a document has been closed and all related objects have been deleted, the store usage may still not drop down to zero. So you might want to enforce that before opening another document.\n\n.. [#f2] By default PyMuPDF and MuPDF use `malloc()`/`free()` for dynamic memory management. One can instead force them to use the Python allocation functions `PyMem_New()`/`PyMem_Del()`, by modifying *fitz/fitz.i* to do `#define JM_MEMORY 1` and rebuilding PyMuPDF.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/tutorial.rst",
    "content": ".. include:: header.rst\n\n.. _Tutorial:\n\n\n=========\nTutorial\n=========\n\n.. highlight:: python\n\nThis tutorial will show you the use of |PyMuPDF|, |MuPDF| in Python, step by step.\n\nBecause |MuPDF| supports not only PDF, but also XPS, OpenXPS, CBZ, CBR, FB2 and EPUB formats, so does |PyMuPDF| [#f1]_. Nevertheless, for the sake of brevity we will only talk about PDF files. At places where indeed only PDF files are supported, this will be mentioned explicitly.\n\nIn addition to this introduction, please do visit PyMuPDF's `YouTube Channel <https://www.youtube.com/@PyMuPDF>`_ which covers most of the following in the form of YouTube \"Shorts\" and longer videos.\n\nImporting the Bindings\n==========================\nThe Python bindings to MuPDF are made available by this import statement. We also show here how your version can be checked::\n\n    >>> import pymupdf\n    >>> print(pymupdf.__doc__)\n    PyMuPDF 1.16.0: Python bindings for the MuPDF 1.16.0 library.\n    Version date: 2019-07-28 07:30:14.\n    Built for Python 3.7 on win32 (64-bit).\n\n\nNote on the Name *fitz*\n--------------------------\n\nOld versions of |PyMuPDF| had their **Python** import name as `fitz`. Newer versions use `pymupdf` instead, and offer `fitz` as a fallback so that old code will still work.\n\nThe reason for the name `fitz` is a historical curiosity:\n\nThe original rendering library for MuPDF was called *Libart*.\n\n*\"After Artifex Software acquired the MuPDF project, the development focus shifted on writing a new modern graphics library called \"Fitz\". Fitz was originally intended as an R&D project to replace the aging Ghostscript graphics library, but has instead become the rendering engine powering MuPDF.\"* (Quoted from `Wikipedia <https://en.wikipedia.org/wiki/MuPDF>`_).\n\n.. note::\n\n  Use of legacy name `fitz` can fail if defunct pypi.org package `fitz` is installed; see :ref:`problems-after-installation`.\n\n\n.. _Tutorial_Opening_a_Document:\n\nOpening a Document\n======================\n\nTo access a :ref:`supported document<Supported_File_Types>`, it must be opened with the following statement::\n\n    doc = pymupdf.open(filename)  # or pymupdf.Document(filename)\n\nThis creates the :ref:`Document` object *doc*. *filename* must be a Python string (or a `pathlib.Path`) specifying the name of an existing file.\n\nIt is also possible to open a document from memory data, or to create a new, empty PDF. See :ref:`Document` for details. You can also use :ref:`Document` as a *context manager*.\n\nA document contains many attributes and functions. Among them are meta information (like \"author\" or \"subject\"), number of total pages, outline and encryption information.\n\nSome :ref:`Document` Methods and Attributes\n=============================================\n\n=========================== ==========================================\n**Method / Attribute**      **Description**\n=========================== ==========================================\n:attr:`Document.page_count`  the number of pages (*int*)\n:attr:`Document.metadata`   the metadata (*dict*)\n:meth:`Document.get_toc`    get the table of contents (*list*)\n:meth:`Document.load_page`   read a :ref:`Page`\n=========================== ==========================================\n\nAccessing Meta Data\n========================\nPyMuPDF fully supports standard metadata. :attr:`Document.metadata` is a Python dictionary with the following keys. It is available for **all document types**, though not all entries may always contain data. For details of their meanings and formats consult the respective manuals, e.g. :ref:`AdobeManual` for PDF. Further information can also be found in chapter :ref:`Document`. The meta data fields are strings or ``None`` if not otherwise indicated. Also be aware that not all of them always contain meaningful data -- even if they are not ``None``.\n\n============== =================================\nKey            Value\n============== =================================\nproducer       producer (producing software)\nformat         format: 'PDF-1.4', 'EPUB', etc.\nencryption     encryption method used if any\nauthor         author\nmodDate        date of last modification\nkeywords       keywords\ntitle          title\ncreationDate   date of creation\ncreator        creating application\nsubject        subject\n============== =================================\n\n.. note:: Apart from these standard metadata, **PDF documents** starting from PDF version 1.4 may also contain so-called *\"metadata streams\"* (see also :data:`stream`). Information in such streams is coded in XML. PyMuPDF deliberately contains no XML components for this purpose (the :ref:`PyMuPDF Xml class<Xml>` is a helper class intended to access the DOM content of a :ref:`Story` object), so we do not directly support access to information contained therein. But you can extract the stream as a whole, inspect or modify it using a package like `lxml`_ and then store the result back into the PDF. If you want, you can also delete this data altogether.\n\n.. note:: There are two utility scripts in the repository that `metadata import (PDF only)`_ resp. `metadata export`_ metadata from resp. to CSV files.\n\nWorking with Outlines\n=========================\nThe easiest way to get all outlines (also called \"bookmarks\") of a document, is by loading its *table of contents*::\n\n    toc = doc.get_toc()\n\nThis will return a Python list of lists *[[lvl, title, page, ...], ...]* which looks much like a conventional table of contents found in books.\n\n*lvl* is the hierarchy level of the entry (starting from 1), *title* is the entry's title, and *page* the page number (1-based!). Other parameters describe details of the bookmark target.\n\n.. note:: There are two utility scripts in the repository that `toc import (PDF only)`_ resp. `toc export`_ table of contents from resp. to CSV files.\n\nWorking with Pages\n======================\n:ref:`Page` handling is at the core of MuPDF's functionality.\n\n* You can render a page into a raster or vector (SVG) image, optionally zooming, rotating, shifting or shearing it.\n* You can extract a page's text and images in many formats and search for text strings.\n* For PDF documents many more methods are available to add text or images to pages.\n\nFirst, a :ref:`Page` must be created. This is a method of :ref:`Document`::\n\n    page = doc.load_page(pno)  # loads page number 'pno' of the document (0-based)\n    page = doc[pno]  # the short form\n\nAny integer `-∞ < pno < page_count` is possible here. Negative numbers count backwards from the end, so *doc[-1]* is the last page, like with Python sequences.\n\nSome more advanced way would be using the document as an **iterator** over its pages::\n\n    for page in doc:\n        # do something with 'page'\n\n    # ... or read backwards\n    for page in reversed(doc):\n        # do something with 'page'\n\n    # ... or even use 'slicing'\n    for page in doc.pages(start, stop, step):\n        # do something with 'page'\n\n\nOnce you have your page, here is what you would typically do with it:\n\nInspecting the Links, Annotations or Form Fields of a Page\n-----------------------------------------------------------\nLinks are shown as \"hot areas\" when a document is displayed with some viewer software. If you click while your cursor shows a hand symbol, you will usually be taken to the target that is encoded in that hot area. Here is how to get all links::\n\n    # get all links on a page\n    links = page.get_links()\n\n*links* is a Python list of dictionaries. For details see :meth:`Page.get_links`.\n\nYou can also use an iterator which emits one link at a time::\n\n    for link in page.links():\n        # do something with 'link'\n\nIf dealing with a PDF document page, there may also exist annotations (:ref:`Annot`) or form fields (:ref:`Widget`), each of which have their own iterators::\n\n    for annot in page.annots():\n        # do something with 'annot'\n\n    for field in page.widgets():\n        # do something with 'field'\n\n\nRendering a Page\n-----------------------\nThis example creates a **raster** image of a page's content::\n\n    pix = page.get_pixmap()\n\n``pix`` is a :ref:`Pixmap` object which (in this case) contains an **RGB** image of the page, ready to be used for many purposes. Method :meth:`Page.get_pixmap` offers lots of variations for controlling the image: resolution / DPI, colorspace (e.g. to produce a grayscale image or an image with a subtractive color scheme), transparency, rotation, mirroring, shifting, shearing, etc. For example: to create an **RGBA** image (i.e. containing an alpha channel), specify *pix = page.get_pixmap(alpha=True)*.\n\nA :ref:`Pixmap` contains a number of methods and attributes which are referenced below. Among them are the integers ``width``, ``height`` (each in pixels) and ``stride`` (number of bytes of one horizontal image line). Attribute ``samples`` represents a rectangular area of bytes representing the image data (a Python ``bytes`` object).\n\n.. note:: You can also create a **vector** image of a page by using :meth:`Page.get_svg_image`. Refer to this `Vector Image Support page`_ for details.\n\nSaving the Page Image in a File\n-----------------------------------\nWe can simply store the image in a PNG file::\n\n    pix.save(f\"page-{page.number}.png\")\n\nDisplaying the Image in GUIs\n-------------------------------------------\nWe can also use it in GUI dialog managers. :attr:`Pixmap.samples` represents an area of bytes of all the pixels as a Python bytes object. Here are some examples, find more in the `examples`_ directory.\n\nwxPython\n~~~~~~~~~~~~~\nConsult their documentation for adjustments to RGB(A) pixmaps and, potentially, specifics for your wxPython release::\n\n    if pix.alpha:\n        bitmap = wx.Bitmap.FromBufferRGBA(pix.width, pix.height, pix.samples)\n    else:\n        bitmap = wx.Bitmap.FromBuffer(pix.width, pix.height, pix.samples)\n\nTkinter\n~~~~~~~~~~\nPlease also see section 3.19 of the `Pillow documentation`_::\n\n    from PIL import Image, ImageTk\n\n    # set the mode depending on alpha\n    mode = \"RGBA\" if pix.alpha else \"RGB\"\n    img = Image.frombytes(mode, [pix.width, pix.height], pix.samples)\n    tkimg = ImageTk.PhotoImage(img)\n\nThe following **avoids using Pillow**::\n\n    # remove alpha if present\n    pix1 = pymupdf.Pixmap(pix, 0) if pix.alpha else pix  # PPM does not support transparency\n    imgdata = pix1.tobytes(\"ppm\")  # extremely fast!\n    tkimg = tkinter.PhotoImage(data = imgdata)\n\nIf you are looking for a complete Tkinter script paging through **any supported** document, `here it is!`_. It can also zoom into pages, and it runs under Python 2 or 3. It requires the extremely handy `PySimpleGUI`_ pure Python package.\n\nPyQt4, PyQt5, PySide\n~~~~~~~~~~~~~~~~~~~~~\nPlease also see section 3.16 of the `Pillow documentation`_::\n\n    from PIL import Image, ImageQt\n\n    # set the mode depending on alpha\n    mode = \"RGBA\" if pix.alpha else \"RGB\"\n    img = Image.frombytes(mode, [pix.width, pix.height], pix.samples)\n    qtimg = ImageQt.ImageQt(img)\n\nAgain, you also can get along **without using Pillow.** Qt's `QImage` luckily supports native Python pointers, so the following is the recommended way to create Qt images::\n\n    from PyQt5.QtGui import QImage\n\n    # set the correct QImage format depending on alpha\n    fmt = QImage.Format_RGBA8888 if pix.alpha else QImage.Format_RGB888\n    qtimg = QImage(pix.samples_ptr, pix.width, pix.height, fmt)\n\n\nExtracting Text and Images\n---------------------------\nWe can also extract all text, images and other information of a page in many different forms, and levels of detail::\n\n    text = page.get_text(opt)\n\nUse one of the following strings for *opt* to obtain different formats [#f2]_:\n\n* **\"text\"**: (default) plain text with line breaks. No formatting, no text position details, no images.\n\n* **\"blocks\"**: generate a list of text blocks (= paragraphs).\n\n* **\"words\"**: generate a list of words (strings not containing spaces).\n\n* **\"html\"**: creates a full visual version of the page including any images. This can be displayed with your internet browser.\n\n* **\"dict\"** / **\"json\"**: same information level as HTML, but provided as a Python dictionary or resp. JSON string. See :meth:`TextPage.extractDICT` for details of its structure.\n\n* **\"rawdict\"** / **\"rawjson\"**: a super-set of **\"dict\"** / **\"json\"**. It additionally provides character detail information like XML. See :meth:`TextPage.extractRAWDICT` for details of its structure.\n\n* **\"xhtml\"**: text information level as the TEXT version but includes images. Can also be displayed by internet browsers.\n\n* **\"xml\"**: contains no images, but full position and font information down to each single text character. Use an XML module to interpret.\n\nTo give you an idea about the output of these alternatives, we did text example extracts. See :ref:`Appendix1`.\n\nSearching for Text\n-------------------\nYou can find out, exactly where on a page a certain text string appears::\n\n    areas = page.search_for(\"mupdf\")\n\nThis delivers a list of rectangles (see :ref:`Rect`), each of which surrounds one occurrence of the string \"mupdf\" (case insensitive). You could use this information to e.g. highlight those areas (PDF only) or create a cross reference of the document.\n\nPlease also do have a look at chapter :ref:`cooperation` and at demo programs `demo.py`_ and `demo-lowlevel.py`_. Among other things they contain details on how the :ref:`TextPage`, :ref:`Device` and :ref:`DisplayList` classes can be used for a more direct control, e.g. when performance considerations suggest it.\n\n\n\n.. _WorkingWithStories:\n\nStories: Generating PDF from HTML Source\n=========================================\n\nThe :ref:`Story` class is a new feature of PyMuPDF version 1.21.0. It represents support for MuPDF's **\"story\"** interface.\n\nThe following is a quote from the book `\"MuPDF Explored\"`_ by Robin Watts from `Artifex`_:\n\n-----\n\n*Stories provide a way to easily layout styled content for use with devices, such as those offered by Document Writers (...). The concept of a story comes from desktop publishing, which in turn (...) gets it from newspapers. If you consider a traditional newspaper layout, it will consist of various news articles (stories) that are laid out into multiple columns, possibly across multiple pages.*\n\n*Accordingly, MuPDF uses a story to represent a flow of text with styling information. The user of the story can then supply a sequence of rectangles into which the story will be laid out, and the positioned text can then be drawn to an output device. This keeps the concept of the text itself (the story) to be separated from the areas into which the text should be flowed (the layout).*\n\n-----\n\n.. note:: A Story works somewhat similar to an internet browser: It faithfully parses and renders HTML hypertext and also optional stylesheets (CSS). But its **output is a PDF** -- not web pages.\n\n\nWhen creating a :ref:`Story`, the input from up to three different information sources is taken into account. All these items are optional.\n\n1. HTML source code, either a Python string or **created by the script** using methods of :ref:`Xml`.\n\n2. CSS (Cascaded Style Sheet) source code, provided as a Python string. CSS can be used to provide styling information (text font size, color, etc.) like it would happen for web pages. Obviously, this string may also be read from a file.\n\n3. An :ref:`Archive` **must be used** whenever the DOM references images, or uses text fonts except the standard :ref:`Base-14-Fonts`, CJK fonts and the NOTO fonts generated into the PyMuPDF binary.\n\n\nThe :ref:`API<Xml>` allows creating DOMs completely from scratch, including desired styling information. It can also be used to modify or extend **provided** HTML: text can be deleted or replaced, or its styling can be changed. Text -- for example extracted from databases -- can also be added and fill template-like HTML documents.\n\nIt is **not required** to provide syntactically complete HTML documents: snippets like `<b>Hello <i>World!</i></b>` are fully accepted, and many / most syntax errors are automatically corrected.\n\nAfter the HTML is considered complete, it can be used to create a PDF document. This happens via the new :ref:`DocumentWriter` class. The programmer calls its methods to create a new empty page, and passes rectangles to the Story to fill them.\n\nThe story in turn will return completion codes indicating whether or not more content is waiting to be written. Which part of the content will land in which rectangle or on which page is automatically determined by the story itself -- it cannot be influenced other than by providing the rectangles.\n\nPlease see the :ref:`Stories recipes<RecipesStories>` for a number of typical use cases.\n\n\nPDF Maintenance\n==================\nPDFs are the only document type that can be **modified** using PyMuPDF. Other file types are read-only.\n\nHowever, you can convert **any document** (including images) to a PDF and then apply all PyMuPDF features to the conversion result. Find out more here :meth:`Document.convert_to_pdf`, and also look at the demo script `pdf-converter.py`_ which can convert any :ref:`supported document<Supported_File_Types>` to PDF.\n\n:meth:`Document.save()` always stores a PDF in its current (potentially modified) state on disk.\n\nYou normally can choose whether to save to a new file, or just append your modifications to the existing one (\"incremental save\"), which often is very much faster.\n\nThe following describes ways how you can manipulate PDF documents. This description is by no means complete: much more can be found in the following chapters.\n\nModifying, Creating, Re-arranging and Deleting Pages\n-------------------------------------------------------\nThere are several ways to manipulate the so-called **page tree** (a structure describing all the pages) of a PDF:\n\n:meth:`Document.delete_page` and :meth:`Document.delete_pages` delete pages.\n\n:meth:`Document.copy_page`, :meth:`Document.fullcopy_page` and :meth:`Document.move_page` copy or move a page to other locations within the same document.\n\n:meth:`Document.select` shrinks a PDF down to selected pages. Parameter is a sequence [#f3]_ of the page numbers that you want to keep. These integers must all be in range *0 <= i < page_count*. When executed, all pages **missing** in this list will be deleted. Remaining pages will occur **in the sequence and as many times (!) as you specify them**.\n\nSo you can easily create new PDFs with\n\n* the first or last 10 pages,\n* only the odd or only the even pages (for doing double-sided printing),\n* pages that **do** or **don't** contain a given text,\n* reverse the page sequence, ...\n\n... whatever you can think of.\n\nThe saved new document will contain links, annotations and bookmarks that are still valid (i.a.w. either pointing to a selected page or to some external resource).\n\n:meth:`Document.insert_page` and :meth:`Document.new_page` insert new pages.\n\nPages themselves can moreover be modified by a range of methods (e.g. page rotation, annotation and link maintenance, text and image insertion).\n\nJoining and Splitting PDF Documents\n------------------------------------\n\nMethod :meth:`Document.insert_pdf` copies pages **between different** PDF documents. Here is a simple **joiner** example (*doc1* and *doc2* being opened PDFs)::\n\n    # append complete doc2 to the end of doc1\n    doc1.insert_pdf(doc2)\n\nHere is a snippet that **splits** *doc1*. It creates a new document of its first and its last 10 pages::\n\n    doc2 = pymupdf.open()                 # new empty PDF\n    doc2.insert_pdf(doc1, to_page = 9)  # first 10 pages\n    doc2.insert_pdf(doc1, from_page = len(doc1) - 10) # last 10 pages\n    doc2.save(\"first-and-last-10.pdf\")\n\nMore can be found in the :ref:`Document` chapter. Also have a look at `PDFjoiner.py`_.\n\nEmbedding Data\n---------------\n\nPDFs can be used as containers for arbitrary data (executables, other PDFs, text or binary files, etc.) much like ZIP archives.\n\nPyMuPDF fully supports this feature via :ref:`Document` ``embfile_*`` methods and attributes. For some detail read :ref:`Appendix2`, consult the Wiki on `dealing with embedding files`_, or the example scripts `embedded-copy.py`_, `embedded-export.py`_, `embedded-import.py`_, and `embedded-list.py`_.\n\n\nSaving\n-------\n\nAs mentioned above, :meth:`Document.save` will **always** save the document in its current state.\n\nYou can write changes back to the **original PDF** by specifying option ``incremental=True``. This process is (usually) **extremely fast**, since changes are **appended to the original file** without completely rewriting it.\n\n:meth:`Document.save` options correspond to options of MuPDF's command line utility *mutool clean*, see the following table.\n\n=================== =========== ==================================================\n**Save Option**     **mutool**  **Effect**\n=================== =========== ==================================================\ngarbage=1           g           garbage collect unused objects\ngarbage=2           gg          in addition to 1, compact :data:`xref` tables\ngarbage=3           ggg         in addition to 2, merge duplicate objects\ngarbage=4           gggg        in addition to 3, merge duplicate stream content\nclean=True          cs          clean and sanitize content streams\ndeflate=True        z           deflate uncompressed streams\ndeflate_images=True i           deflate image streams\ndeflate_fonts=True  f           deflate fontfile streams\nascii=True          a           convert binary data to ASCII format\nlinear=True         l           create a linearized version\nexpand=True         d           decompress all streams\n=================== =========== ==================================================\n\n.. note:: For an explanation of terms like ``object``, ``stream``, ``xref`` consult the :ref:`Glossary` chapter.\n\nFor example, ``mutool clean -ggggz file.pdf`` yields excellent compression results. It corresponds to ``doc.save(filename, garbage=4, deflate=True)``.\n\nClosing\n=========\nIt is often desirable to \"close\" a document to relinquish control of the underlying file to the OS, while your program continues.\n\nThis can be achieved by the :meth:`Document.close` method. Apart from closing the underlying file, buffer areas associated with the document will be freed.\n\nFurther Reading\n================\nAlso have a look at PyMuPDF's `Wiki`_ pages. Especially those named in the sidebar under title **\"Recipes\"** cover over 15 topics written in \"How-To\" style.\n\nThis document also contains a :ref:`FAQ`. This chapter has close connection to the aforementioned recipes, and it will be extended with more content over time.\n\n\n-----\n\n\n.. rubric:: Footnotes\n\n.. [#f1] PyMuPDF lets you also open several image file types just like normal documents. See section :ref:`ImageFiles` in chapter :ref:`Pixmap` for more comments.\n\n.. [#f2] :meth:`Page.get_text` is a convenience wrapper for several methods of another PyMuPDF class, :ref:`TextPage`. The names of these methods correspond to the argument string passed to :meth:`Page.get_text` \\:  *Page.get_text(\"dict\")* is equivalent to *TextPage.extractDICT()* \\.\n\n.. [#f3] \"Sequences\" are Python objects conforming to the sequence protocol. These objects implement a method named *__getitem__()*. Best known examples are Python tuples and lists. But *array.array*, *numpy.array* and PyMuPDF's \"geometry\" objects (:ref:`Algebra`) are sequences, too. Refer to :ref:`SequenceTypes` for details.\n\n\n.. include:: footer.rst\n\n.. External links:\n\n\n.. _lxml: https://pypi.org/project/lxml/\n.. _metadata import (PDF only): https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/import-metadata/import.py\n.. _metadata export: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/export-metadata/export.py\n.. _toc import (PDF only): https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/import-toc/import.py\n.. _toc export: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/export-toc/export.py\n.. _Vector Image Support page: https://github.com/pymupdf/PyMuPDF/wiki/Vector-Image-Support\n.. _examples: https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/examples\n.. _Pillow documentation: https://Pillow.readthedocs.io\n.. _here it is!: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/browse-document/browse.py\n.. _PySimpleGUI: https://pypi.org/project/PySimpleGUI/\n.. _demo.py: https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/demo/demo.py\n.. _demo-lowlevel.py: https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/demo/demo-lowlevel.py\n.. _\"MuPDF Explored\": https://mupdf.com/docs/mupdf_explored.pdf\n.. _Artifex: https://www.artifex.com\n.. _pdf-converter.py: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/convert-document/convert.py\n.. _PDFjoiner.py: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/join-documents/join.py\n.. _dealing with embedding files: https://github.com/pymupdf/PyMuPDF/wiki/Dealing-with-Embedded-Files\n.. _embedded-copy.py: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/copy-embedded/copy.py\n.. _embedded-export.py: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/export-embedded/export.py\n.. _embedded-import.py: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/import-embedded/import.py\n.. _embedded-list.py: https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/examples/list-embedded/list.py\n.. _Wiki: https://github.com/pymupdf/PyMuPDF/wiki\n\n\n"
  },
  {
    "path": "docs/vars.rst",
    "content": ".. include:: header.rst\n\n===============================\nConstants and Enumerations\n===============================\nConstants and enumerations of :title:`MuPDF` as implemented by |PyMuPDF|. Each of the following values is accessible as `pymupdf.value`.\n\n\nConstants\n---------\n\n.. py:data:: Base14_Fonts\n\n    Predefined Python list of valid :ref:`Base-14-Fonts`.\n\n    :type: list\n\n.. py:data:: csRGB\n\n    Predefined RGB colorspace *pymupdf.Colorspace(pymupdf.CS_RGB)*.\n\n    :type: :ref:`Colorspace`\n\n.. py:data:: csGRAY\n\n    Predefined GRAY colorspace *pymupdf.Colorspace(pymupdf.CS_GRAY)*.\n\n    :type: :ref:`Colorspace`\n\n.. py:data:: csCMYK\n\n    Predefined CMYK colorspace *pymupdf.Colorspace(pymupdf.CS_CMYK)*.\n\n    :type: :ref:`Colorspace`\n\n.. py:data:: CS_RGB\n\n    1 -- Type of :ref:`Colorspace` is RGBA\n\n    :type: int\n\n.. py:data:: CS_GRAY\n\n    2 -- Type of :ref:`Colorspace` is GRAY\n\n    :type: int\n\n.. py:data:: CS_CMYK\n\n    3 -- Type of :ref:`Colorspace` is CMYK\n\n    :type: int\n\n.. py:data:: mupdf_version\n\n    'x.xx.x' -- MuPDF version that is being used by PyMuPDF.\n\n    :type: string\n\n.. py:data:: mupdf_version_tuple\n\n    MuPDF version as a tuple of integers, `(major, minor, patch)`.\n    \n    :type: tuple\n\n.. py:data:: pymupdf_version\n\n    'x.xx.x' -- PyMuPDF version.\n\n    :type: string\n\n.. py:data:: pymupdf_version_tuple\n\n    PyMuPDF version as a tuple of integers, `(major, minor, patch)`.\n    \n    :type: tuple\n\n.. py:data:: pymupdf_date\n\n    Disabled (set to None) in 1.26.1.\n    \n.. py:data:: version\n\n    (pymupdf_version, mupdf_version, timestamp) -- combined version information where `timestamp` is the generation point in time formatted as \"YYYYMMDDhhmmss\".\n\n    :type: tuple\n\n.. py:data:: VersionBind\n\n    Legacy equivalent to `mupdf_version`.\n\n.. py:data:: VersionFitz\n\n    Legacy equivalent to `pymupdf_version`.\n\n.. py:data:: VersionDate\n\n    Disabled (set to None) in 1.26.1.\n\n\n.. _PermissionCodes:\n\nDocument Permissions\n----------------------------\n\n====================== =======================================================================\nCode                   Permitted Action\n====================== =======================================================================\nPDF_PERM_PRINT         Print the document\nPDF_PERM_MODIFY        Modify the document's contents\nPDF_PERM_COPY          Copy or otherwise extract text and graphics\nPDF_PERM_ANNOTATE      Add or modify text annotations and interactive form fields\nPDF_PERM_FORM          Fill in forms and sign the document\nPDF_PERM_ACCESSIBILITY Obsolete, always permitted\nPDF_PERM_ASSEMBLE      Insert, rotate, or delete pages, bookmarks, thumbnail images\nPDF_PERM_PRINT_HQ      High quality printing\n====================== =======================================================================\n\n.. _OptionalContentCodes:\n\nPDF Optional Content Codes\n----------------------------\n\n====================== =======================================================================\nCode                   Meaning\n====================== =======================================================================\nPDF_OC_ON              Set an OCG to ON temporarily\nPDF_OC_TOGGLE          Toggle OCG status temporarily\nPDF_OC_OFF             Set an OCG to OFF temporarily\n====================== =======================================================================\n\n.. _EncryptionMethods:\n\nPDF encryption method codes\n----------------------------\n\n=================== ====================================================\nCode                Meaning\n=================== ====================================================\nPDF_ENCRYPT_KEEP    do not change\nPDF_ENCRYPT_NONE    remove any encryption\nPDF_ENCRYPT_RC4_40  RC4 40 bit\nPDF_ENCRYPT_RC4_128 RC4 128 bit\nPDF_ENCRYPT_AES_128 *Advanced Encryption Standard* 128 bit\nPDF_ENCRYPT_AES_256 *Advanced Encryption Standard* 256 bit\nPDF_ENCRYPT_UNKNOWN unknown\n=================== ====================================================\n\n.. _FontExtensions:\n\nFont File Extensions\n-----------------------\nThe table show file extensions you should use when saving fontfile buffers extracted from a PDF. This string is returned by :meth:`Document.get_page_fonts`, :meth:`Page.get_fonts` and :meth:`Document.extract_font`.\n\n==== ============================================================================\nExt  Description\n==== ============================================================================\nttf  TrueType font\npfa  Postscript for ASCII font (various subtypes)\ncff  Type1C font (compressed font equivalent to Type1)\ncid  character identifier font (postscript format)\notf  OpenType font\nn/a  not extractable, e.g. :ref:`Base-14-Fonts`, Type 3 fonts and others\n==== ============================================================================\n\n.. _TextAlign:\n\nText Alignment\n-----------------------\n.. py:data:: TEXT_ALIGN_LEFT\n\n    0 -- align left.\n\n.. py:data:: TEXT_ALIGN_CENTER\n\n    1 -- align center.\n\n.. py:data:: TEXT_ALIGN_RIGHT\n\n    2 -- align right.\n\n.. py:data:: TEXT_ALIGN_JUSTIFY\n\n    3 -- align justify.\n\n.. _TextPreserve:\n\n.. _FontProperties:\n\nFont Properties\n-----------------------\nPlease note that the following bits are derived from what a font has to say about its properties. It may not be (and quite often is not) correct.\n\n.. py:data:: TEXT_FONT_SUPERSCRIPT\n\n    1 -- the character or span is a superscript. This property is computed by MuPDF and not part of any font information.\n\n.. py:data:: TEXT_FONT_ITALIC\n\n    2 -- the font is italic.\n\n.. py:data:: TEXT_FONT_SERIFED\n\n    4 -- the font is serifed.\n\n.. py:data:: TEXT_FONT_MONOSPACED\n\n    8 -- the font is mono-spaced.\n\n.. py:data:: TEXT_FONT_BOLD\n\n    16 -- the font is bold.\n\nText Extraction Flags\n---------------------\nOption bits controlling the amount of data, that are parsed into a :ref:`TextPage`.\n\nFor the PyMuPDF programmer, some combination (using Python's `|` operator, or simply use `+`) of these values are aggregated in the ``flags`` integer, a parameter of all text search and text extraction methods. Depending on the individual method, different default combinations of the values are used. Please use a value that meets your situation. Especially make sure to switch off image extraction unless you really need them. The impact on performance and memory is significant!\n\n.. py:data:: TEXT_PRESERVE_LIGATURES\n\n    1 -- If set, ligatures are passed through to the application in their original form. Otherwise ligatures are expanded into their constituent parts, e.g. the ligature \"ffi\" is expanded into three  eparate characters f, f and i. Default is \"on\" in PyMuPDF. MuPDF supports the following 7 ligatures: \"ff\", \"fi\", \"fl\", \"ffi\", \"ffl\", , \"ft\", \"st\".\n\n.. py:data:: TEXT_PRESERVE_WHITESPACE\n\n    2 -- If set, whitespace is passed through. Otherwise any type of horizontal whitespace (including horizontal tabs) will be replaced with space characters of variable width. Default is \"on\" in PyMuPDF.\n\n.. py:data:: TEXT_PRESERVE_IMAGES\n\n    4 -- If set, then images will be stored in the :ref:`TextPage`. This causes the presence of (usually large!) binary image content in the output of text extractions of types \"blocks\", \"dict\", \"json\", \"rawdict\", \"rawjson\", \"html\", and \"xhtml\" and is the default there. If used with \"blocks\" however, only image metadata will be returned, not the image itself.\n\n.. py:data:: TEXT_INHIBIT_SPACES\n\n    8 -- If set, Mupdf will not try to add missing space characters where there are large gaps between characters. In PDF, the creator often does not insert spaces to point to the next character's position, but will provide the direct location address. The default in PyMuPDF is \"off\" -- so spaces **will be generated**.\n\n.. py:data:: TEXT_DEHYPHENATE\n\n    16 -- Ignore hyphens at line ends and join with next line. Used internally with the text search functions. However, it is generally available: if on, text extractions will return joined text lines (or spans) with the ending hyphen of the first line eliminated. So two separate spans **\"first meth-\"** and **\"od leads to wrong results\"** on different lines will be joined to one span **\"first method leads to wrong results\"** and correspondingly updated bboxes: the characters of the resulting span will no longer have identical y-coordinates.\n\n.. py:data:: TEXT_PRESERVE_SPANS\n\n    32 -- Generate a new line for every span. Not used (\"off\") in PyMuPDF, but available for your use. Every line in \"dict\", \"json\", \"rawdict\", \"rawjson\" will contain exactly one span.\n\n.. py:data:: TEXT_CLIP, TEXT_MEDIABOX_CLIP\n\n    64 -- Characters entirely outside a page's **mediabox** or contained in other \"clipped\" areas will be ignored. This is default in PyMuPDF. (TEXT_MEDIABOX_CLIP is an old alias.)\n\n.. py:data:: TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n\n    128 -- Use raw character codes instead of U+FFFD. This is the default for **text extraction** in PyMuPDF. If you **want to detect** when encoding information is missing or uncertain, toggle this flag and scan for the presence of U+FFFD (= `chr(0xfffd)`) code points in the resulting text.\n\n.. py:data:: TEXT_COLLECT_STRUCTURE\n\n    256 -- Extract or generate the :ref:`Document` structure. Detail documentation pending.\n\n.. py:data:: TEXT_ACCURATE_BBOXES\n\n    512 -- Ignore metric values of all fonts when computing character boundary boxes -- most prominently the `ascender <https://en.wikipedia.org/wiki/Ascender_(typography)>`_ and `descender <https://en.wikipedia.org/wiki/Descender>`_ values. Instead, follow the drawing commands of each character's glyph and compute their rectangle hull as the bbox. This is the smallest rectangle wrapping all points used for drawing the visual appearance - see the :ref:`Shape` class for understanding the background. This will especially result in individual character heights. For instance a (white) space will have a **bbox of zero height** (because nothing is drawn) -- in contrast to the non-zero boundary box generated when using font metrics. This option may be useful to cope with failures of getting meaningful boundary boxes, even for fonts containing errors. Its use will slow down text extraction somewhat because of the incurred computational effort.\n    \n    Note that this has no effect by default - one must also disable the global quad corrections setting with `pymupdf.TOOLS.unset_quad_corrections(True)`.\n\n.. py:data:: TEXT_COLLECT_VECTORS\n\n    1024 -- Collect vector drawings into the :ref:`TextPage`. These are stored as blocks alongside text and image blocks, depending on other extraction flags. See :meth:`TextPage.extractBLOCKS` and :meth:`TextPage.extractDICT` for details. Beyond these two methods, vector graphics extraction is also available for :meth:`TextPage.extractJSON`, :meth:`TextPage.extractRAWDICT`, :meth:`TextPage.extractRAWJSON` and :meth:`TextPage.extractXML`.\n\n.. py:data:: TEXT_IGNORE_ACTUALTEXT\n\n    2048 -- Ignore built-in differences between text appearing in e.g. PDF viewers versus text stored in the PDF. See :ref:`AdobeManual`, page 615 for background. If set, the **stored** (\"replacement\" text) is ignored in favor of the displayed text.\n\n.. py:data:: TEXT_SEGMENT\n\n    4096 -- Attempt to segment page into different regions. Detail documentation pending.\n\n.. py:data:: TEXT_COLLECT_STYLES\n\n    32768 -- Request collecting text **decoration** properties. This includes text underlining and strikeout. In contrast to public awareness, these are not font properties, but are drawn separately as vector graphics or annotations on top of the text. In addition, the flag bit will also cause MuPDF to detect \"fake bold\" text. In many cases, Document creators **simulate bold** text by printing the same text multiple times with slight offsets. If this flag is set, such text will be marked as bold in the resulting text spans.\n\n.. py:data:: TEXT_LAZY_VECTORS\n\n    1048576 -- Delay vector blocks in the extraction slightly to avoid breaking what would otherwise be continuous lines of text.\n\n.. py:data:: TEXT_FUZZY_VECTORS\n\n    2097152 -- \tIf this option is set, we 'fuzzily' collect rectangular vectors of the same colour together. This enables us to spot where 'pixels' or 'slices' of vectors are used to create the appearance of characters on the page without exploding the storage and processing time requirements.\n\nThe following constants represent the default combinations of the above for text extraction and searching:\n\n.. py:data:: TEXTFLAGS_TEXT\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_WORDS\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_BLOCKS\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_DICT\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_PRESERVE_IMAGES | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_RAWDICT\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_PRESERVE_IMAGES | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_HTML\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_PRESERVE_IMAGES | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_XHTML\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_PRESERVE_IMAGES | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_XML\n\n    `TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_USE_CID_FOR_UNKNOWN_UNICODE`\n\n.. py:data:: TEXTFLAGS_SEARCH\n\n    `TEXT_PRESERVE_WHITESPACE | TEXT_MEDIABOX_CLIP | TEXT_DEHYPHENATE`\n\n\n.. _linkDest Kinds:\n\nLink Destination Kinds\n-----------------------\nPossible values of :attr:`linkDest.kind` (link destination kind).\n\n.. py:data:: LINK_NONE\n\n    0 -- No destination. Indicates a dummy link.\n\n    :type: int\n\n.. py:data:: LINK_GOTO\n\n    1 -- Points to a place in this document.\n\n    :type: int\n\n.. py:data:: LINK_URI\n\n    2 -- Points to a URI -- typically a resource specified with internet syntax.\n    \n    * PyMuPDF treats any external link that contains a colon and does not start\n      with `file:`, as `LINK_URI`.\n\n    :type: int\n\n.. py:data:: LINK_LAUNCH\n\n    3 -- Launch (open) another file (of any \"executable\" type).\n    \n    * |PyMuPDF| treats any external link that starts with `file:` or doesn't\n      contain a colon, as `LINK_LAUNCH`.\n\n    :type: int\n\n.. py:data:: LINK_NAMED\n\n    4 -- points to a named location.\n\n    :type: int\n\n.. py:data:: LINK_GOTOR\n\n    5 -- Points to a place in another PDF document.\n\n    :type: int\n\n.. _linkDest Flags:\n\nLink Destination Flags\n-------------------------\n\n.. Note:: The rightmost byte of this integer is a bit field, so test the truth of these bits with the *&* operator.\n\n.. py:data:: LINK_FLAG_L_VALID\n\n    1  (bit 0) Top left x value is valid\n\n    :type: bool\n\n.. py:data:: LINK_FLAG_T_VALID\n\n    2  (bit 1) Top left y value is valid\n\n    :type: bool\n\n.. py:data:: LINK_FLAG_R_VALID\n\n    4  (bit 2) Bottom right x value is valid\n\n    :type: bool\n\n.. py:data:: LINK_FLAG_B_VALID\n\n    8  (bit 3) Bottom right y value is valid\n\n    :type: bool\n\n.. py:data:: LINK_FLAG_FIT_H\n\n    16 (bit 4) Horizontal fit\n\n    :type: bool\n\n.. py:data:: LINK_FLAG_FIT_V\n\n    32 (bit 5) Vertical fit\n\n    :type: bool\n\n.. py:data:: LINK_FLAG_R_IS_ZOOM\n\n    64 (bit 6) Bottom right x is a zoom figure\n\n    :type: bool\n\n\nAnnotation Related Constants\n-----------------------------\nSee chapter 8.4.5, pp. 615 of the :ref:`AdobeManual` for details.\n\n.. _AnnotationTypes:\n\nAnnotation Types\n~~~~~~~~~~~~~~~~~\nThese identifiers also cover **links** and **widgets**: the PDF specification technically handles them all in the same way, whereas |MuPDF| (and PyMuPDF) treats them as three basically different types of objects.\n\n::\n\n    PDF_ANNOT_TEXT 0\n    PDF_ANNOT_LINK 1  # <=== Link object in PyMuPDF\n    PDF_ANNOT_FREE_TEXT 2\n    PDF_ANNOT_LINE 3\n    PDF_ANNOT_SQUARE 4\n    PDF_ANNOT_CIRCLE 5\n    PDF_ANNOT_POLYGON 6\n    PDF_ANNOT_POLY_LINE 7\n    PDF_ANNOT_HIGHLIGHT 8\n    PDF_ANNOT_UNDERLINE 9\n    PDF_ANNOT_SQUIGGLY 10\n    PDF_ANNOT_STRIKE_OUT 11\n    PDF_ANNOT_REDACT 12\n    PDF_ANNOT_STAMP 13\n    PDF_ANNOT_CARET 14\n    PDF_ANNOT_INK 15\n    PDF_ANNOT_POPUP 16\n    PDF_ANNOT_FILE_ATTACHMENT 17\n    PDF_ANNOT_SOUND 18\n    PDF_ANNOT_MOVIE 19\n    PDF_ANNOT_RICH_MEDIA 20\n    PDF_ANNOT_WIDGET 21  # <=== Widget object in PyMuPDF\n    PDF_ANNOT_SCREEN 22\n    PDF_ANNOT_PRINTER_MARK 23\n    PDF_ANNOT_TRAP_NET 24\n    PDF_ANNOT_WATERMARK 25\n    PDF_ANNOT_3D 26\n    PDF_ANNOT_PROJECTION 27\n    PDF_ANNOT_UNKNOWN -1\n\n.. _AnnotationFlags:\n\nAnnotation Flag Bits\n~~~~~~~~~~~~~~~~~~~~~\n::\n\n    PDF_ANNOT_IS_INVISIBLE 1 << (1-1)\n    PDF_ANNOT_IS_HIDDEN 1 << (2-1)\n    PDF_ANNOT_IS_PRINT 1 << (3-1)\n    PDF_ANNOT_IS_NO_ZOOM 1 << (4-1)\n    PDF_ANNOT_IS_NO_ROTATE 1 << (5-1)\n    PDF_ANNOT_IS_NO_VIEW 1 << (6-1)\n    PDF_ANNOT_IS_READ_ONLY 1 << (7-1)\n    PDF_ANNOT_IS_LOCKED 1 << (8-1)\n    PDF_ANNOT_IS_TOGGLE_NO_VIEW 1 << (9-1)\n    PDF_ANNOT_IS_LOCKED_CONTENTS 1 << (10-1)\n\n.. _AnnotationLineEnds:\n\nAnnotation Line Ending Styles\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n::\n\n    PDF_ANNOT_LE_NONE 0\n    PDF_ANNOT_LE_SQUARE 1\n    PDF_ANNOT_LE_CIRCLE 2\n    PDF_ANNOT_LE_DIAMOND 3\n    PDF_ANNOT_LE_OPEN_ARROW 4\n    PDF_ANNOT_LE_CLOSED_ARROW 5\n    PDF_ANNOT_LE_BUTT 6\n    PDF_ANNOT_LE_R_OPEN_ARROW 7\n    PDF_ANNOT_LE_R_CLOSED_ARROW 8\n    PDF_ANNOT_LE_SLASH 9\n\n\nWidget Constants\n-----------------\n\n.. _WidgetTypes:\n\nWidget Types (*field_type*)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n::\n\n    PDF_WIDGET_TYPE_UNKNOWN 0\n    PDF_WIDGET_TYPE_BUTTON 1\n    PDF_WIDGET_TYPE_CHECKBOX 2\n    PDF_WIDGET_TYPE_COMBOBOX 3\n    PDF_WIDGET_TYPE_LISTBOX 4\n    PDF_WIDGET_TYPE_RADIOBUTTON 5\n    PDF_WIDGET_TYPE_SIGNATURE 6\n    PDF_WIDGET_TYPE_TEXT 7\n\nText Widget Subtypes (*text_format*)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n::\n\n    PDF_WIDGET_TX_FORMAT_NONE 0\n    PDF_WIDGET_TX_FORMAT_NUMBER 1\n    PDF_WIDGET_TX_FORMAT_SPECIAL 2\n    PDF_WIDGET_TX_FORMAT_DATE 3\n    PDF_WIDGET_TX_FORMAT_TIME 4\n\n\nWidget flags (*field_flags*)\n~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~\n**Common to all field types**::\n\n    PDF_FIELD_IS_READ_ONLY 1\n    PDF_FIELD_IS_REQUIRED 1 << 1\n    PDF_FIELD_IS_NO_EXPORT 1 << 2\n\n**Text widgets**::\n\n    PDF_TX_FIELD_IS_MULTILINE  1 << 12\n    PDF_TX_FIELD_IS_PASSWORD  1 << 13\n    PDF_TX_FIELD_IS_FILE_SELECT  1 << 20\n    PDF_TX_FIELD_IS_DO_NOT_SPELL_CHECK  1 << 22\n    PDF_TX_FIELD_IS_DO_NOT_SCROLL  1 << 23\n    PDF_TX_FIELD_IS_COMB  1 << 24\n    PDF_TX_FIELD_IS_RICH_TEXT  1 << 25\n\n**Button widgets**::\n\n    PDF_BTN_FIELD_IS_NO_TOGGLE_TO_OFF  1 << 14\n    PDF_BTN_FIELD_IS_RADIO  1 << 15\n    PDF_BTN_FIELD_IS_PUSHBUTTON  1 << 16\n    PDF_BTN_FIELD_IS_RADIOS_IN_UNISON  1 << 25\n\n**Choice widgets**::\n\n    PDF_CH_FIELD_IS_COMBO  1 << 17\n    PDF_CH_FIELD_IS_EDIT  1 << 18\n    PDF_CH_FIELD_IS_SORT  1 << 19\n    PDF_CH_FIELD_IS_MULTI_SELECT  1 << 21\n    PDF_CH_FIELD_IS_DO_NOT_SPELL_CHECK  1 << 22\n    PDF_CH_FIELD_IS_COMMIT_ON_SEL_CHANGE  1 << 26\n\n\n.. _BlendModes:\n\nPDF Standard Blend Modes\n----------------------------\n\nFor an explanation see :ref:`AdobeManual`, page 324::\n\n    PDF_BM_Color \"Color\"\n    PDF_BM_ColorBurn \"ColorBurn\"\n    PDF_BM_ColorDodge \"ColorDodge\"\n    PDF_BM_Darken \"Darken\"\n    PDF_BM_Difference \"Difference\"\n    PDF_BM_Exclusion \"Exclusion\"\n    PDF_BM_HardLight \"HardLight\"\n    PDF_BM_Hue \"Hue\"\n    PDF_BM_Lighten \"Lighten\"\n    PDF_BM_Luminosity \"Luminosity\"\n    PDF_BM_Multiply \"Multiply\"\n    PDF_BM_Normal \"Normal\"\n    PDF_BM_Overlay \"Overlay\"\n    PDF_BM_Saturation \"Saturation\"\n    PDF_BM_Screen \"Screen\"\n    PDF_BM_SoftLight \"Softlight\"\n\n\n.. _StampIcons:\n\nStamp Annotation Icons\n----------------------------\nMuPDF has defined the following icons for **rubber stamp** annotations::\n\n    STAMP_Approved 0\n    STAMP_AsIs 1\n    STAMP_Confidential 2\n    STAMP_Departmental 3\n    STAMP_Experimental 4\n    STAMP_Expired 5\n    STAMP_Final 6\n    STAMP_ForComment 7\n    STAMP_ForPublicRelease 8\n    STAMP_NotApproved 9\n    STAMP_NotForPublicRelease 10\n    STAMP_Sold 11\n    STAMP_TopSecret 12\n    STAMP_Draft 13\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/version.rst",
    "content": "This documentation covers PyMuPDF |version|.\n\nThe major and minor versions of PyMuPDF and MuPDF will always be the same. Only the third qualifier (patch level) may deviate from that of MuPDF.\n\nTypically PyMuPDF is released more frequently than MuPDF so it will often be\nthe case that the patch level of PyMuPDF will be greater than the embedded\nMuPDF.\n\nFor example PyMuPDF-1.24.5 contains MuPDF-1.24.2.\n\nAlso see `pymupdf_version` and `mupdf_version`.\n"
  },
  {
    "path": "docs/widget.rst",
    "content": ".. include:: header.rst\n\n.. _Widget:\n\n================\nWidget\n================\n\n|pdf_only_class|\n\nThis class represents a PDF Form field, also called a \"widget\". Throughout this documentation, we are using these terms synonymously. Fields technically are a special case of PDF annotations, which allow users with limited permissions to enter information in a PDF. This is primarily used for filling out forms.\n\nLike annotations, widgets live on PDF pages. Similar to annotations, the first widget on a page is accessible via :attr:`Page.first_widget` and subsequent widgets can be accessed via the :attr:`Widget.next` property.\n\nLike annotations, widgets also lose connection to their page when the page becomes unavailable, please see `here <https://pymupdf.readthedocs.io/en/latest/app3.html#ensuring-consistency-of-important-objects-in-pymupdf>`_ for details. This is relevant especially when updating the widget: this will fail if the original page object is no longer available.\n\n*(Changed in version 1.16.0)* MuPDF no longer treats widgets as a subset of general annotations. Consequently, :attr:`Page.first_annot` and :meth:`Annot.next` will deliver **non-widget annotations exclusively**, and be ``None`` if only form fields exist on a page. Vice versa, :attr:`Page.first_widget` and :meth:`Widget.next` will only show widgets. This design decision is purely internal to MuPDF; technically, links, annotations and fields have a lot in common and also continue to share the better part of their code within (Py-) MuPDF.\n\n\n**Class API**\n\n.. class:: Widget\n\n    .. method:: button_states\n\n      *New in version 1.18.15*\n\n       Return the names of On / Off (i.e. selected / clicked or not) states a button field may have. While the 'Off' state usually is also named like so, the 'On' state is often given a name relating to the functional context, for example 'Yes', 'Female', etc.\n\n       This method helps finding out the possible values of :attr:`field_value` in these cases.\n\n       :returns: a dictionary with the names of 'On' and 'Off' for the *normal* and the *pressed-down* appearance of button widgets. The following example shows that the \"selected\" value is \"Male\":\n\n         >>> print(field.field_name, field.button_states())\n         Gender Second person {'down': ['Male', 'Off'], 'normal': ['Male', 'Off']}\n\n\n    .. method:: on_state\n\n      * New in version 1.22.2\n\n       Return the value of the \"ON\" state of check boxes and radio buttons. For check boxes this is always the value \"Yes\". For radio buttons, this is the value to select / activate the button.\n\n       :returns: the value that sets the button to \"selected\". For non-checkbox, non-radiobutton fields, always `None` is returned. For check boxes the return is `True`. For radio buttons this is the value \"Male\" in the following example:\n\n         >>> print(field.field_name, field.button_states())\n         Gender Second person {'down': ['Male', 'Off'], 'normal': ['Male', 'Off']}\n         >>> print(field.on_state())\n         Male\n\n        So for check boxes and radio buttons, the recommended method to set them to \"selected\", or to check the state is the following:\n        \n         >>> field.field_value = field.on_state()\n         >>> field.field_value == field.on_state()\n         True\n\n\n    .. method:: update(sync_flags=False)\n\n       After any changes to a widget, this **method must be used** to reflect changes in the PDF [#f1]_.\n\n       :arg bool sync_flags: if ``True``, the widget's :attr:`Widget.field_flags` are copied to the ``Parent`` object (if present) and all widgets named in its ``Kids`` array. This provides a convenient way to -- for example -- set all instances of the widget to read-only, no matter on which page they may occur [#f2]_.\n\n    .. method:: reset\n\n       Reset the field's value to its default -- if defined -- or remove it. Do not forget to issue :meth:`update` afterwards.\n\n    .. attribute:: next\n\n       Point to the next form field on the page. The last widget returns ``None``.\n\n    .. attribute:: border_color\n\n       A list of up to 4 floats defining the field's border color. Default value is ``None`` which causes border style and border width to be ignored.\n\n    .. attribute:: border_style\n\n       A string defining the line style of the field's border. See :attr:`Annot.border`. Default is \"s\" (\"Solid\") -- a continuous line. Only the first character (upper or lower case) will be regarded when creating a widget.\n\n    .. attribute:: border_width\n\n       A float defining the width of the border line. Default is 1.\n\n    .. attribute:: border_dashes\n\n       A list/tuple of integers defining the dash properties of the border line. This is only meaningful if *border_style == \"D\"* and :attr:`border_color` is provided.\n\n    .. attribute:: choice_values\n\n       Python sequence of strings defining the valid choices of list boxes and combo boxes. For these widget types, this property is mandatory and must contain at least two items. Ignored for other types.\n\n    .. attribute:: field_name\n\n       A mandatory string defining the field's name. No checking for duplicates takes place.\n\n    .. attribute:: field_label\n\n       An optional string containing an \"alternate\" field name. Typically used for any notes, help on field usage, etc. Default is the field name.\n\n    .. attribute:: field_value\n\n       The value of the field.\n\n    .. attribute:: field_flags\n\n       An integer defining a large amount of properties of a field. Be careful when changing this attribute as this may change the field type.\n\n    .. attribute:: field_type\n\n       A mandatory integer defining the field type. This is a value in the range of 0 to 6. It cannot be changed when updating the widget.\n\n    .. attribute:: field_type_string\n\n       A string describing (and derived from) the field type.\n\n    .. attribute:: fill_color\n\n       A list of up to 4 floats defining the field's background color.\n\n    .. attribute:: button_caption\n\n       The caption string of a button-type field.\n\n    .. attribute:: is_signed\n\n       A bool indicating the signing status of a signature field, else ``None``.\n\n    .. attribute:: rect\n\n       The rectangle containing the field.\n\n    .. attribute:: text_color\n\n       A list of **1, 3 or 4 floats** defining the text color. Default value is black (`[0, 0, 0]`).\n\n    .. attribute:: text_font\n\n       A string defining the font to be used. Default and replacement for invalid values is *\"Helv\"*. For valid font reference names see the table below.\n\n    .. attribute:: text_fontsize\n\n       A float defining the text :data:`fontsize`. Default value is zero, which causes PDF viewer software to dynamically choose a size suitable for the annotation's rectangle and text amount.\n\n    .. attribute:: text_maxlen\n\n       An integer defining the maximum number of text characters. PDF viewers will (should) not accept a longer text.\n\n    .. attribute:: text_type\n\n       An integer defining acceptable text types (e.g. numeric, date, time, etc.). For reference only for the time being -- will be ignored when creating or updating widgets.\n\n    .. attribute:: xref\n\n       The PDF :data:`xref` of the widget.\n\n    .. attribute:: script\n\n       * New in version 1.16.12\n       \n       JavaScript text (unicode) for an action associated with the widget, or ``None``. This is the only script action supported for **button type** widgets.\n\n    .. attribute:: script_stroke\n\n       * New in version 1.16.12\n       \n       JavaScript text (unicode) to be performed when the user types a key-stroke into a text field or combo box or modifies the selection in a scrollable list box. This action can check the keystroke for validity and reject or modify it. ``None`` if not present.\n\n    .. attribute:: script_format\n\n       * New in version 1.16.12\n       \n       JavaScript text (unicode) to be performed before the field is formatted to display its current value. This action can modify the field’s value before formatting. ``None`` if not present.\n\n    .. attribute:: script_change\n\n       * New in version 1.16.12\n       \n       JavaScript text (unicode) to be performed when the field’s value is changed. This action can check the new value for validity. ``None`` if not present.\n\n    .. attribute:: script_calc\n\n       * New in version 1.16.12\n       \n       JavaScript text (unicode) to be performed to recalculate the value of this field when that of another field changes. ``None`` if not present.\n\n    .. attribute:: script_blur\n\n       * New in version 1.22.6\n       \n       JavaScript text (unicode) to be performed on losing the focus of this field. ``None`` if not present.\n\n    .. attribute:: script_focus\n\n       * New in version 1.22.6\n       \n       JavaScript text (unicode) to be performed on focusing this field. ``None`` if not present.\n\n    .. note::\n\n       1. For **adding** or **changing** one of the above scripts,\n         just put the appropriate JavaScript source code in the widget attribute.\n         To **remove** a script, set the respective attribute to ``None``.\n\n       2. Button fields only support :attr:`script`.\n         Other script entries will automatically be set to ``None``.\n\n       3. It is worthwhile to look at\n          `this <https://experienceleague.adobe.com/docs/experience-manager-learn/assets/FormsAPIReference.pdf?lang=en>`_\n          manual with lots of information about Adobe's standard scripts for various field types.\n          For example, if you want to add a text field representing a date,\n          you may want to store the following scripts.\n          They will ensure pattern-compatible date formats and display date pickers in supporting viewers::\n\n              widget.script_format = 'AFDate_FormatEx(\"mm/dd/yyyy\");'\n              widget.script_stroke = 'AFDate_KeystrokeEx(\"mm/dd/yyyy\");'\n\n\nStandard Fonts for Widgets\n----------------------------------\nWidgets use their own resources object ``/DR``. A widget resources object must at least contain a ``/Font`` object. Widget fonts are independent from page fonts. We currently support the 14 PDF base fonts using the following fixed reference names, or any name of an already existing field font. When specifying a text font for new or changed widgets, **either** choose one in the first table column (upper and lower case supported), **or** one of the already existing form fonts. In the latter case, spelling must exactly match.\n\nTo find out already existing field fonts, inspect the list :attr:`Document.FormFonts`.\n\n============= =======================\n**Reference** **Base14 Fontname**\n============= =======================\nCoBI          Courier-BoldOblique\nCoBo          Courier-Bold\nCoIt          Courier-Oblique\nCour          Courier\nHeBI          Helvetica-BoldOblique\nHeBo          Helvetica-Bold\nHeIt          Helvetica-Oblique\nHelv          Helvetica **(default)**\nSymb          Symbol\nTiBI          Times-BoldItalic\nTiBo          Times-Bold\nTiIt          Times-Italic\nTiRo          Times-Roman\nZaDb          ZapfDingbats\n============= =======================\n\nYou are generally free to use any font for every widget. However, we recommend using ``ZaDb`` (\"ZapfDingbats\") and :data:`fontsize` 0 for check boxes: typical viewers will put a correctly sized tickmark in the field's rectangle, when it is clicked.\n\nSupported Widget Types\n-----------------------\nPyMuPDF supports the creation and update of many, but not all widget types.\n\n* text (`PDF_WIDGET_TYPE_TEXT`)\n* push button (`PDF_WIDGET_TYPE_BUTTON`)\n* check box (`PDF_WIDGET_TYPE_CHECKBOX`)\n* combo box (`PDF_WIDGET_TYPE_COMBOBOX`)\n* list box (`PDF_WIDGET_TYPE_LISTBOX`)\n* radio button (`PDF_WIDGET_TYPE_RADIOBUTTON`): PyMuPDF does not currently support the **creation** of groups of (interconnected) radio buttons, where setting one button automatically unsets the other buttons in the group. The widget object also does not reflect the presence of a button group. However: consistently selecting (or unselecting) a radio button is supported. This includes correctly setting the value maintained in the owning button group. Selecting a radio button may be done by either assigning `True` or `field.on_state()` to the field value. **De-selecting** the button should be done assigning `False`.\n* signature (`PDF_WIDGET_TYPE_SIGNATURE`) **read only** -- no update or creation of signatures.\n\n.. rubric:: Footnotes\n\n.. [#f1] If you intend to re-access a new or updated field (e.g. for making a pixmap), make sure to reload the page first. Either close and re-open the document, or load another page first, or simply do `page = doc.reload_page(page)`.\n\n.. [#f2] Among other purposes, ``Parent`` objects are also used to facilitate multiple occurrences of a field (on the same or on different pages). The ``Kids`` array in this ``Parent`` object contains the cross references of all widgets that are \"copies\" of the same field. Whenever the field value of any \"kid\" widget is changed, all the other kids are immediately updated too. This is a very efficient way to handle multiple copies of the same field, e.g. for filling out forms. This simultaneous update only happens for :attr:`Widget.field value`. The new parameter ``sync_flags`` extends this to :attr:`Widget.field_flags`. This cannot be automated in the same way as for the field value to allow for more flexibility.\n\n.. include:: footer.rst\n"
  },
  {
    "path": "docs/xml-class.rst",
    "content": ".. include:: header.rst\n\n.. _Xml:\n\n================\nXml\n================\n\n.. role:: htmlTag(emphasis)\n\n* New in v1.21.0\n\nThis represents an HTML or an XML node. It is a helper class intended to access the DOM (Document Object Model) content of a :ref:`Story` object.\n\nThere is no need to ever directly construct an :ref:`Xml` object: after creating a :ref:`Story`, simply take :attr:`Story.body` -- which is an Xml node -- and use it to navigate your way through the story's DOM.\n\n\n================================ ===========================================================================================\n**Method / Attribute**             **Description**\n================================ ===========================================================================================\n:meth:`~.add_bullet_list`        Add a :htmlTag:`ul` tag - bulleted list, context manager.\n:meth:`~.add_codeblock`          Add a :htmlTag:`pre` tag, context manager.\n:meth:`~.add_description_list`   Add a :htmlTag:`dl` tag, context manager.\n:meth:`~.add_division`           add a :htmlTag:`div` tag (renamed from “section”), context manager.\n:meth:`~.add_header`             Add a header tag (one of :htmlTag:`h1` to :htmlTag:`h6`), context manager.\n:meth:`~.add_horizontal_line`    Add a :htmlTag:`hr` tag.\n:meth:`~.add_image`              Add a :htmlTag:`img` tag.\n:meth:`~.add_link`               Add a :htmlTag:`a` tag.\n:meth:`~.add_number_list`        Add a :htmlTag:`ol` tag, context manager.\n:meth:`~.add_paragraph`          Add a :htmlTag:`p` tag.\n:meth:`~.add_span`               Add a :htmlTag:`span` tag, context manager.\n:meth:`~.add_subscript`          Add subscript text(:htmlTag:`sub` tag) - inline element, treated like text.\n:meth:`~.add_superscript`        Add subscript text (:htmlTag:`sup` tag) - inline element, treated like text.\n:meth:`~.add_code`               Add code text (:htmlTag:`code` tag) - inline element, treated like text.\n:meth:`~.add_var`                Add code text (:htmlTag:`code` tag) - inline element, treated like text.\n:meth:`~.add_samp`               Add code text (:htmlTag:`code` tag) - inline element, treated like text.\n:meth:`~.add_kbd`                Add code text (:htmlTag:`code` tag) - inline element, treated like text.\n:meth:`~.add_text`               Add a text string. Line breaks ``\\n`` are honored as :htmlTag:`br` tags.\n:meth:`~.append_child`           Append a child node.\n:meth:`~.clone`                  Make a copy if this node.\n:meth:`~.create_element`         Make a new node with a given tag name.\n:meth:`~.create_text_node`       Create direct text for the current node.\n:meth:`~.find`                   Find a sub-node with given properties.\n:meth:`~.find_next`              Repeat previous \"find\" with the same criteria.\n:meth:`~.insert_after`           Insert an element after current node.\n:meth:`~.insert_before`          Insert an element before current node.\n:meth:`~.remove`                 Remove this node.\n:meth:`~.set_align`              Set the alignment using a CSS style spec. Only works for block-level tags.\n:meth:`~.set_attribute`          Set an arbitrary key to some value (which may be empty).\n:meth:`~.set_bgcolor`            Set the background color. Only works for block-level tags.\n:meth:`~.set_bold`               Set bold on or off or to some string value.\n:meth:`~.set_color`              Set text color.\n:meth:`~.set_columns`            Set the number of columns. Argument may be any valid number or string.\n:meth:`~.set_font`               Set the font-family, e.g. “sans-serif”.\n:meth:`~.set_fontsize`           Set the font size. Either a float or a valid HTML/CSS string.\n:meth:`~.set_id`                 Set a :htmlTag:`id`. A check for uniqueness is performed.\n:meth:`~.set_italic`             Set italic on or off or to some string value.\n:meth:`~.set_leading`            Set inter-block text distance (`-mupdf-leading`), only works on block-level nodes.\n:meth:`~.set_lineheight`         Set height of a line. Float like 1.5, which sets to `1.5 * fontsize`.\n:meth:`~.set_margins`            Set the margin(s), float or string with up to 4 values.\n:meth:`~.set_pagebreak_after`    Insert a page break after this node.\n:meth:`~.set_pagebreak_before`   Insert a page break before this node.\n:meth:`~.set_properties`         Set any or all desired properties in one call.\n:meth:`~.add_style`              Set (add) a “style” that is not supported by its own `set_` method.\n:meth:`~.add_class`              Set (add) a “class” attribute.\n:meth:`~.set_text_indent`        Set indentation for first textblock line. Only works for block-level nodes.\n:attr:`~.tagname`                Either the HTML tag name like :htmlTag:`p` or `None` if a text node.\n:attr:`~.text`                   Either the node's text or `None` if a tag node.\n:attr:`~.is_text`                Check if the node is a text.\n:attr:`~.first_child`            Contains the first node one level below this one (or `None`).\n:attr:`~.last_child`             Contains the last node one level below this one (or `None`).\n:attr:`~.next`                   The next node at the same level (or `None`).\n:attr:`~.previous`               The previous node at the same level.\n:attr:`~.root`                   The top node of the DOM, which hence has the tagname :htmlTag:`html`.\n================================ ===========================================================================================\n\n\n\n**Class API**\n\n.. class:: Xml\n\n    .. method:: add_bullet_list\n\n       Add an :htmlTag:`ul` tag - bulleted list, context manager. See `ul <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/ul>`_.\n\n    .. method:: add_codeblock\n\n       Add a :htmlTag:`pre` tag, context manager. See `pre <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/pre>`_.\n\n    .. method:: add_description_list\n\n       Add a :htmlTag:`dl` tag, context manager. See `dl <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/dl>`_.\n\n    .. method:: add_division\n\n       Add a :htmlTag:`div` tag, context manager. See `div <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/div>`_.\n\n    .. method:: add_header(value)\n\n       Add a header tag (one of :htmlTag:`h1` to :htmlTag:`h6`), context manager. See `headings <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/Heading_Elements>`_.\n\n       :arg int value: a value 1 - 6.\n\n    .. method:: add_horizontal_line\n\n       Add a :htmlTag:`hr` tag. See `hr <https://developer.mozilla.org/en-US/docs/Web/HTML/Element/hr>`_.\n\n    .. method:: add_image(name, width=None, height=None)\n\n       Add an :htmlTag:`img` tag. This causes the inclusion of the named image in the DOM.\n\n       :arg str name: the filename of the image. This **must be the member name** of some entry of the :ref:`Archive` parameter of the :ref:`Story` constructor.\n       :arg width: if provided, either an absolute (int) value, or a percentage string like \"30%\". A percentage value refers to the width of the specified `where` rectangle in :meth:`Story.place`. If this value is provided and `height` is omitted, the image will be included keeping its aspect ratio.\n       :arg height: if provided, either an absolute (int) value, or a percentage string like \"30%\". A percentage value refers to the height of the specified `where` rectangle in :meth:`Story.place`. If this value is provided and `width` is omitted, the image's aspect ratio will be honored.\n\n    .. method:: add_link(href, text=None)\n\n       Add an :htmlTag:`a` tag - inline element, treated like text.\n\n       :arg str href: the URL target.\n       :arg str text: the text to display. If omitted, the `href` text is shown instead.\n\n    .. method:: add_number_list\n\n       Add an :htmlTag:`ol` tag, context manager.\n\n    .. method:: add_paragraph\n\n       Add a :htmlTag:`p` tag, context manager.\n\n    .. method:: add_span\n\n       Add a :htmlTag:`span` tag, context manager. See `span`_\n\n    .. method:: add_subscript(text)\n\n       Add \"subscript\" text(:htmlTag:`sub` tag) - inline element, treated like text.\n\n    .. method:: add_superscript(text)\n\n       Add \"superscript\" text (:htmlTag:`sup` tag) - inline element, treated like text.\n\n    .. method:: add_code(text)\n\n       Add \"code\" text (:htmlTag:`code` tag) - inline element, treated like text.\n\n    .. method:: add_var(text)\n\n       Add \"variable\" text (:htmlTag:`var` tag) - inline element, treated like text.\n\n    .. method:: add_samp(text)\n\n       Add \"sample output\" text (:htmlTag:`samp` tag) - inline element, treated like text.\n\n    .. method:: add_kbd(text)\n\n       Add \"keyboard input\" text (:htmlTag:`kbd` tag) - inline element, treated like text.\n\n    .. method:: add_text(text)\n\n       Add a text string. Line breaks ``\\n`` are honored as :htmlTag:`br` tags.\n\n    .. method:: set_align(value)\n\n       Set the text alignment. Only works for block-level tags.\n\n       :arg value: either one of the :ref:`TextAlign` or the `text-align <https://developer.mozilla.org/en-US/docs/Web/CSS/text-align>`_ values.\n\n    .. method:: set_attribute(key, value=None)\n\n       Set an arbitrary key to some value (which may be empty).\n\n       :arg str key: the name of the attribute.\n       :arg str value: the (optional) value of the attribute.\n\n    .. method:: get_attributes()\n\n       Retrieve all attributes of the current nodes as a dictionary.\n\n       :returns: a dictionary with the attributes and their values of the node.\n\n    .. method:: get_attribute_value(key)\n\n       Get the attribute value of `key`.\n\n       :arg str key: the name of the attribute.\n\n       :returns: a string with the value of `key`.\n\n    .. method:: remove_attribute(key)\n\n       Remove the attribute `key` from the node.\n\n       :arg str key: the name of the attribute.\n\n    .. method:: set_bgcolor(value)\n\n       Set the background color. Only works for block-level tags.\n\n       :arg value: either an RGB value like (255, 0, 0) (for \"red\") or a valid `background-color <https://developer.mozilla.org/en-US/docs/Web/CSS/background-color>`_ value.\n\n    .. method:: set_bold(value)\n\n       Set bold on or off or to some string value.\n\n       :arg value: `True`, `False` or a valid `font-weight <https://developer.mozilla.org/en-US/docs/Web/CSS/font-weight>`_ value.\n\n    .. method:: set_color(value)\n\n       Set the color of the text following.\n\n       :arg value: either an RGB value like (255, 0, 0) (for \"red\") or a valid `color <https://developer.mozilla.org/en-US/docs/Web/CSS/color_value>`_ value.\n\n    .. method:: set_columns(value)\n\n       Set the number of columns.\n\n       :arg value: a valid `columns <https://developer.mozilla.org/en-US/docs/Web/CSS/columns>`_ value.\n\n       .. note:: Currently ignored - supported in a future MuPDF version.\n\n    .. method:: set_font(value)\n\n       Set the font-family.\n\n       :arg str value: e.g. \"sans-serif\".\n\n    .. method:: set_fontsize(value)\n\n       Set the font size for text following.\n\n       :arg value: a float or a valid `font-size <https://developer.mozilla.org/en-US/docs/Web/CSS/font-size>`_ value.\n\n    .. method:: set_id(unqid)\n\n       Set a :htmlTag:`id`. This serves as a unique identification of the node within the DOM. Use it to easily locate the node to inspect or modify it. A check for uniqueness is performed.\n\n       :arg str unqid: id string of the node.\n\n    .. method:: set_italic(value)\n\n       Set italic on or off or to some string value for the text following it.\n\n       :arg value: `True`, `False` or some valid `font-style <https://developer.mozilla.org/en-US/docs/Web/CSS/font-style>`_ value.\n\n    .. method:: set_leading(value)\n\n       Set inter-block text distance (`-mupdf-leading`), only works on block-level nodes.\n\n       :arg float value: the distance in points to the previous block.\n\n    .. method:: set_lineheight(value)\n\n       Set height of a line.\n\n       :arg value:  a float like 1.5 (which sets to `1.5 * fontsize`), or some valid `line-height <https://developer.mozilla.org/en-US/docs/Web/CSS/line-height>`_ value.\n\n    .. method:: set_margins(value)\n\n       Set the margin(s).\n\n       :arg value: float or string with up to 4 values. See `CSS documentation <https://developer.mozilla.org/en-US/docs/Web/CSS/margin>`_.\n\n    .. method:: set_pagebreak_after\n\n       Insert a page break after this node.\n\n    .. method:: set_pagebreak_before\n\n       Insert a page break before this node.\n\n    .. method:: set_properties(align=None, bgcolor=None, bold=None, color=None, columns=None, font=None, fontsize=None, indent=None, italic=None, leading=None, lineheight=None, margins=None, pagebreak_after=False, pagebreak_before=False, unqid=None, cls=None)\n\n       Set any or all desired properties in one call. The meaning of argument values equal the values of the corresponding `set_` methods.\n\n       .. note:: The properties set by this method are directly attached to the node, whereas every `set_` method generates a new :htmlTag:`span` below the current node that has the respective property. So to e.g. \"globally\" set some property for the :htmlTag:`body`, this method must be used.\n\n    .. method:: add_style(value)\n\n       Set (add) some style attribute not supported by its own `set_` method.\n\n       :arg str value: any valid CSS style value.\n\n    .. method:: add_class(value)\n\n       Set (add) some \"class\" attribute.\n\n       :arg str value: the name of the class. Must have been defined in either the HTML or the CSS source of the DOM.\n\n    .. method:: set_text_indent(value)\n\n       Set indentation for the first textblock line. Only works for block-level nodes.\n\n       :arg value: a valid `text-indent <https://developer.mozilla.org/en-US/docs/Web/CSS/text-indent>`_ value. Please note that negative values do not work.\n\n\n    .. method:: append_child(node)\n\n       Append a child node. This is a low-level method used by other methods like :meth:`Xml.add_paragraph`.\n\n       :arg node: the :ref:`Xml` node to append.\n\n    .. method:: create_text_node(text)\n\n       Create direct text for the current node.\n\n       :arg str text: the text to append.\n\n       :rtype: :ref:`Xml`\n       :returns: the created element.\n\n    .. method:: create_element(tag)\n\n       Create a new node with a given tag. This a low-level method used by other methods like :meth:`Xml.add_paragraph`.\n\n       :arg str tag: the element tag.\n\n       :rtype: :ref:`Xml`\n       :returns: the created element. To actually bind it to the DOM, use :meth:`Xml.append_child`.\n\n    .. method:: insert_before(elem)\n\n       Insert the given element `elem` before this node.\n\n       :arg elem: some :ref:`Xml` element.\n\n    .. method:: insert_after(elem)\n\n       Insert the given element `elem` after this node.\n\n       :arg elem: some :ref:`Xml` element.\n\n    .. method:: clone()\n\n       Make a copy of this node, which then may be appended (using :meth:`Xml.append_child`) or inserted (using one of :meth:`Xml.insert_before`, :meth:`Xml.insert_after`) in this DOM.\n\n       :returns: the clone (:ref:`Xml`) of the current node.\n\n    .. method:: remove()\n\n       Remove this node from the DOM.\n\n\n    .. method:: debug()\n\n       For debugging purposes, print this node's structure in a simplified form.\n\n    .. method:: find(tag, att, match)\n\n       Under the current node, find the first node with the given `tag`, attribute `att` and value `match`.\n\n       :arg str tag: restrict search to this tag. May be `None` for unrestricted searches.\n       :arg str att: check this attribute. May be `None`.\n       :arg str match: the desired attribute value to match. May be `None`.\n\n       :rtype: :ref:`Xml`.\n       :returns: `None` if nothing found, otherwise the first matching node.\n\n    .. method:: find_next( tag, att, match)\n\n       Continue a previous :meth:`Xml.find` (or :meth:`find_next`) with the same values.\n\n       :rtype: :ref:`Xml`.\n       :returns: `None` if none more found, otherwise the next matching node.\n\n\n    .. attribute:: tagname\n\n       Either the HTML tag name like :htmlTag:`p` or `None` if a text node.\n\n    .. attribute:: text\n\n       Either the node's text or `None` if a tag node.\n\n    .. attribute:: is_text\n\n       Check if a text node.\n\n    .. attribute:: first_child\n\n       Contains the first node one level below this one (or `None`).\n\n    .. attribute:: last_child\n\n       Contains the last node one level below this one (or `None`).\n\n    .. attribute:: next\n\n       The next node at the same level (or `None`).\n\n    .. attribute:: previous\n\n       The previous node at the same level.\n\n    .. attribute:: root\n\n       The top node of the DOM, which hence has the tagname :htmlTag:`html`.\n\n\nSetting Text properties\n------------------------\n\nIn HTML tags can be nested such that innermost text **inherits properties** from the tag enveloping its parent tag. For example `<p><b>some bold text<i>this is bold and italic</i></b>regular text</p>`.\n\nTo achieve the same effect, methods like :meth:`Xml.set_bold` and :meth:`Xml.set_italic` each open a temporary :htmlTag:`span` with the desired property underneath the current node.\n\nIn addition, these methods return there parent node, so they can be concatenated with each other.\n\n\n\nContext Manager support\n------------------------\nThe standard way to add nodes to a DOM is this::\n\n   body = story.body\n   para = body.add_paragraph()  # add a paragraph\n   para.set_bold()  # text that follows will be bold\n   para.add_text(\"some bold text\")\n   para.set_italic()  # text that follows will additionally be italic\n   para.add_txt(\"this is bold and italic\")\n   para.set_italic(False).set_bold(False)  # all following text will be regular\n   para.add_text(\"regular text\")\n\n\n\nMethods that are flagged as \"context managers\" can conveniently be used in this way::\n\n   body = story.body\n   with body.add_paragraph() as para:\n      para.set_bold().add_text(\"some bold text\")\n      para.set_italic().add_text(\"this is bold and italic\")\n      para.set_italic(False).set_bold(False).add_text(\"regular text\")\n      para.add_text(\"more regular text\")\n\n.. include:: footer.rst\n\n.. External links:\n\n.. _span: https://developer.mozilla.org/en-US/docs/Web/HTML/Element/span\n"
  },
  {
    "path": "docs/znames.rst",
    "content": ".. include:: header.rst\n\n.. _Deprecated:\n\n================\nDeprecated Names\n================\n\nThe original naming convention for methods and properties has been \"camelCase\". Since its creation around 2013, a tremendous increase of functionality has happened in PyMuPDF -- and with it a corresponding increase in classes, methods and properties. In too many cases, this has led to non-intuitive, illogical and ugly names, difficult to memorize or guess.\n\nA few versions ago, I therefore decided to shift gears and switch to a \"snake_cased\" naming standard.\nThis was a major effort, which needed a step-wise approach. I think am done with it now (version 1.18.14).\n\nThe following list maps deprecated names to their new versions. For example, property `pageCount` became `page_count` in the :ref:`Document` class. There also are less obvious name changes, e.g. method `getPNGdata` was renamed to `tobytes` in the :ref:`Pixmap` class.\n\nNames of classes (camel case) and package-wide constants (the majority is upper case) remain untouched.\n\nOld names will remain available as deprecated aliases through MuPDF version 1.19.0 and **be removed** in the version that follows it - probably version 1.20.0, but this depends on upstream decisions (MuPDF).\n\nStarting with version 1.19.0, we will issue deprecation warnings on `sys.stderr` like `Deprecation: 'newPage' removed from class 'Document' after v1.19.0 - use 'new_page'.` when aliased methods are being used. Using a deprecated property will not cause this type of warning.\n\nStarting immediately, all deprecated objects (methods and properties) will show a copy of the original's docstring, **prefixed** with the deprecation message, for example::\n\n    >>> print(pymupdf.Document.pageCount.__doc__)\n    *** Deprecated and removed in version following 1.19.0 - use 'page_count'. ***\n    Number of pages.\n    >>> print(pymupdf.Document.newPage.__doc__)\n    *** Deprecated and removed in version following 1.19.0 - use 'new_page'. ***\n    Create and return a new page object.\n\n        Args:\n            pno: (int) insert before this page. Default: after last page.\n            width: (float) page width in points. Default: 595 (ISO A4 width).\n            height: (float) page height in points. Default 842 (ISO A4 height).\n        Returns:\n            A Page object.\n        \n\nThere is a utility script `alias-changer.py <https://github.com/pymupdf/PyMuPDF-Utilities/tree/master/alias-changer.py>`_ which can be used to do mass-renames in your scripts. It accepts either a single file or a folder as argument. If a folder is supplied, all its Python files and those of its subfolders are changed. Optionally, backups of the scripts can be taken.\n\n\n.. include:: footer.rst\n"
  },
  {
    "path": "pyproject.toml",
    "content": "[build-system]\n    requires = ['pipcl']\n    build-backend = \"setup\"\n    backend-path = [\".\"]\n"
  },
  {
    "path": "pytest.ini",
    "content": "[pytest]\npython_files =\n    tests/test_*.py\naddopts = --tb=native\n"
  },
  {
    "path": "scripts/gh_release.py",
    "content": "#! /usr/bin/env python3\n\n'''\nBuild+test script for PyMuPDF using cibuildwheel. Mostly for use with github\nbuilds.\n\nWe run cibuild manually, in order to build and test PyMuPDF wheels.\n\nAs of 2024-10-08 we also support the old two wheel flavours that make up\nPyMuPDF:\n\n    PyMuPDFb\n        Not specific to particular versions of Python. Contains shared\n        libraries for the MuPDF C and C++ bindings.\n    PyMuPDF\n        Specific to particular versions of Python. Contains the rest of\n        the PyMuPDF implementation.\n\nArgs:\n    build\n        Build using cibuildwheel.\n    build-devel\n        Build using cibuild with `--platform` set.\n    pip_install <prefix>\n        For internal use. Runs `pip install <prefix>-*<platform_tag>.whl`,\n        where `platform_tag` will be things like 'win32', 'win_amd64',\n        'x86_64`, depending on the python we are running on.\n    venv\n        Run with remaining args inside a venv.\n    test\n        Internal.\n\nWe also look at specific items in the environment. This allows use with Github\naction inputs, which can't be easily translated into command-line arguments.\n\n    inputs_flavours\n        If '0' or unset, build complete PyMuPDF wheels.\n        If '1', build separate PyMuPDF and PyMuPDFb wheels.\n    inputs_sdist\n    inputs_skeleton\n        Build minimal wheel; for testing only.\n    inputs_wheels_cps:\n        Python versions to build for. E.g. 'cp39* cp313*'.\n    inputs_wheels_default\n        Default value for other inputs_wheels_* if unset.\n    inputs_wheels_linux_aarch64\n    inputs_wheels_linux_auto\n    inputs_wheels_linux_pyodide\n    inputs_wheels_macos_arm64\n    inputs_wheels_macos_auto\n    inputs_wheels_windows_auto\n        If '1' we build the relevant wheels.\n    inputs_PYMUPDF_SETUP_MUPDF_BUILD\n        Used to directly set PYMUPDF_SETUP_MUPDF_BUILD.\n        E.g. 'git:--recursive --depth 1 --shallow-submodules --branch master https://github.com/ArtifexSoftware/mupdf.git'\n    inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE\n        Used to directly set PYMUPDF_SETUP_MUPDF_BUILD_TYPE. Note that as of\n        2024-09-10 .github/workflows/build_wheels.yml does not set this.\n    PYMUPDF_SETUP_PY_LIMITED_API\n        If not '0' we build a single wheel for all python versions using the\n        Python Limited API.\n\nBuilding for Pyodide\n\n    If `inputs_wheels_linux_pyodide` is true and we are on Linux, we build a\n    Pyodide wheel, using scripts/test.py.\n\nSet up for use outside Github\n\n    sudo apt install docker.io\n    sudo usermod -aG docker $USER\n\nExample usage:\n\n     PYMUPDF_SETUP_MUPDF_BUILD=../mupdf py -3.9-32 PyMuPDF/scripts/gh_release.py venv build-devel\n'''\n\nimport glob\nimport inspect\nimport os\nimport platform\nimport re\nimport shlex\nimport subprocess\nimport sys\nimport textwrap\n\nimport test as test_py\n\npymupdf_dir = os.path.abspath( f'{__file__}/../..')\n\nsys.path.insert(0, f'{pymupdf_dir}/src')\nimport pipcl\ndel sys.path[0]\n\nlog = pipcl.log0\nrun = pipcl.run\n\n\ndef main():\n\n    log( '### main():')\n    log(f'{platform.platform()=}')\n    log(f'{platform.python_version()=}')\n    log(f'{platform.architecture()=}')\n    log(f'{platform.machine()=}')\n    log(f'{platform.processor()=}')\n    log(f'{platform.release()=}')\n    log(f'{platform.system()=}')\n    log(f'{platform.version()=}')\n    log(f'{platform.uname()=}')\n    log(f'{sys.executable=}')\n    log(f'{sys.maxsize=}')\n    log(f'sys.argv ({len(sys.argv)}):')\n    for i, arg in enumerate(sys.argv):\n        log(f'    {i}: {arg!r}')\n    log(f'os.environ ({len(os.environ)}):')\n    for k in sorted( os.environ.keys()):\n        v = os.environ[ k]\n        log( f'    {k}: {v!r}')\n    \n    if test_py.github_workflow_unimportant():\n        return\n    \n    valgrind = False\n    if len( sys.argv) == 1:\n        args = iter( ['build'])\n    else:\n        args = iter( sys.argv[1:])\n    while 1:\n        try:\n            arg = next(args)\n        except StopIteration:\n            break\n        if arg == 'build':\n            build(valgrind=valgrind)\n        elif arg == 'build-devel':\n            if platform.system() == 'Linux':\n                p = 'linux'\n            elif platform.system() == 'Windows':\n                p = 'windows'\n            elif platform.system() == 'Darwin':\n                p = 'macos'\n            else:\n                assert 0, f'Unrecognised {platform.system()=}'\n            build(platform_=p)\n        elif arg == 'pip_install':\n            prefix = next(args)\n            d = os.path.dirname(prefix)\n            log( f'{prefix=}')\n            log( f'{d=}')\n            for leaf in os.listdir(d):\n                log( f'    {d}/{leaf}')\n            pattern = f'{prefix}-*{platform_tag()}.whl'\n            paths = glob.glob( pattern)\n            log( f'{pattern=} {paths=}')\n            # Follow pipcl.py and look at AUDITWHEEL_PLAT. This allows us to\n            # cope if building for both musl and normal linux.\n            awp = os.environ.get('AUDITWHEEL_PLAT')\n            if awp:\n                paths = [i for i in paths if awp in i]\n                log(f'After selecting AUDITWHEEL_PLAT={awp!r}, {paths=}.')\n            paths = ' '.join( paths)\n            run( f'pip install {paths}')\n        elif arg == 'venv':\n            command = ['python', sys.argv[0]]\n            for arg in args:\n                command.append( arg)\n            venv( command, packages = 'cibuildwheel')\n        elif arg == 'test':\n            project = next(args)\n            package = next(args)\n            test( project, package, valgrind=valgrind)\n        elif arg == '--valgrind':\n            valgrind = int(next(args))\n        else:\n            assert 0, f'Unrecognised {arg=}'\n\n\ndef build( platform_=None, valgrind=False): \n    log( '### build():')   \n    \n    platform_arg = f' --platform {platform_}' if platform_ else ''\n    \n    # Parameters are in os.environ, as that seems to be the only way that\n    # Github workflow .yml files can encode them.\n    #\n    def get_bool(name, default=0):\n        v = os.environ.get(name)\n        if v in ('1', 'true'):\n            return 1\n        elif v in ('0', 'false'):\n            return 0\n        elif v is None:\n            return default\n        else:\n            assert 0, f'Bad environ {name=} {v=}'\n    inputs_flavours = get_bool('inputs_flavours', 1)\n    inputs_sdist = get_bool('inputs_sdist')\n    inputs_skeleton = os.environ.get('inputs_skeleton')\n    inputs_wheels_default = get_bool('inputs_wheels_default', 1)\n    inputs_wheels_linux_aarch64 = get_bool('inputs_wheels_linux_aarch64', inputs_wheels_default)\n    inputs_wheels_linux_auto = get_bool('inputs_wheels_linux_auto', inputs_wheels_default)\n    inputs_wheels_linux_pyodide = get_bool('inputs_wheels_linux_pyodide', 0)\n    inputs_wheels_macos_arm64 = get_bool('inputs_wheels_macos_arm64', 0)\n    inputs_wheels_macos_auto = get_bool('inputs_wheels_macos_auto', inputs_wheels_default)\n    inputs_wheels_windows_auto = get_bool('inputs_wheels_windows_auto', inputs_wheels_default)\n    inputs_wheels_cps = os.environ.get('inputs_wheels_cps')\n    inputs_PYMUPDF_SETUP_MUPDF_BUILD = os.environ.get('inputs_PYMUPDF_SETUP_MUPDF_BUILD')\n    inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE = os.environ.get('inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE')\n    \n    PYMUPDF_SETUP_PY_LIMITED_API = os.environ.get('PYMUPDF_SETUP_PY_LIMITED_API')\n    \n    log( f'{inputs_flavours=}')\n    log( f'{inputs_sdist=}')\n    log( f'{inputs_skeleton=}')\n    log( f'{inputs_wheels_default=}')\n    log( f'{inputs_wheels_linux_aarch64=}')\n    log( f'{inputs_wheels_linux_auto=}')\n    log( f'{inputs_wheels_linux_pyodide=}')\n    log( f'{inputs_wheels_macos_arm64=}')\n    log( f'{inputs_wheels_macos_auto=}')\n    log( f'{inputs_wheels_windows_auto=}')\n    log( f'{inputs_wheels_cps=}')\n    log( f'{inputs_PYMUPDF_SETUP_MUPDF_BUILD=}')\n    log( f'{inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE=}')\n    log( f'{PYMUPDF_SETUP_PY_LIMITED_API=}')\n    \n    # Build Pyodide wheel if specified.\n    #\n    if platform.system() == 'Linux' and inputs_wheels_linux_pyodide:\n        # Pyodide wheels are built by running scripts/test.py, not\n        # cibuildwheel.\n        command = f'{sys.executable} scripts/test.py -P 1'\n        if inputs_PYMUPDF_SETUP_MUPDF_BUILD:\n            command += f' -m {shlex.quote(inputs_PYMUPDF_SETUP_MUPDF_BUILD)}'\n        command += ' pyodide_wheel'\n        run(command)\n    \n    # Build sdist(s).\n    #\n    if inputs_sdist:\n        if pymupdf_dir != os.path.abspath( os.getcwd()):\n            log( f'Changing dir to {pymupdf_dir=}')\n            os.chdir( pymupdf_dir)\n        # Create PyMuPDF sdist.\n        run(f'{sys.executable} setup.py sdist')\n        assert glob.glob('dist/pymupdf-*.tar.gz')\n        if inputs_flavours:\n            # Create PyMuPDFb sdist.\n            run(\n                    f'{sys.executable} setup.py sdist',\n                    env_extra=dict(PYMUPDF_SETUP_FLAVOUR='b'),\n                    )\n            assert glob.glob('dist/pymupdfb-*.tar.gz')\n    \n    # Build wheels.\n    #\n    if (0\n            or inputs_wheels_linux_aarch64\n            or inputs_wheels_linux_auto\n            or inputs_wheels_macos_arm64\n            or inputs_wheels_macos_auto\n            or inputs_wheels_windows_auto\n            ):\n        env_extra = dict()\n    \n        def set_if_unset(name, value):\n            v = os.environ.get(name)\n            if v is None:\n                log( f'Setting environment {name=} to {value=}')\n                env_extra[ name] = value\n            else:\n                log( f'Not changing {name}={v!r} to {value!r}')\n        set_if_unset( 'CIBW_BUILD_VERBOSITY', '1')\n        # We exclude pp* because of `fitz_wrap.obj : error LNK2001: unresolved\n        # external symbol PyUnicode_DecodeRawUnicodeEscape`.\n        # 2024-06-05: musllinux on aarch64 fails because libclang cannot find\n        # libclang.so.\n        #\n        # Note that we had to disable cp313-win32 when 3.13 was experimental\n        # because there was no 64-bit Python-3.13 available via `py\n        # -3.13`. (Win32 builds need to use win64 Python because win32\n        # libclang is broken.)\n        #\n        set_if_unset( 'CIBW_SKIP', 'pp* *i686 cp36* cp37* *musllinux*aarch64*')\n    \n        def make_string(*items):\n            ret = list()\n            for item in items:\n                if item:\n                    ret.append(item)\n            return ' '.join(ret)\n    \n        cps = inputs_wheels_cps if inputs_wheels_cps else 'cp39* cp310* cp311* cp312* cp313*'\n        set_if_unset( 'CIBW_BUILD', cps)\n        for cp in cps.split():\n            m = re.match('cp([0-9]+)[*]', cp)\n            assert m, f'{cps=} {cp=}'\n            v = int(m.group(1))\n            if v == 314:\n                # Need to set CIBW_PRERELEASE_PYTHONS, otherwise cibuildwheel\n                # will refuse.\n                log(f'Setting CIBW_PRERELEASE_PYTHONS for Python version {cp=}.')\n                set_if_unset( 'CIBW_PRERELEASE_PYTHONS', '1')\n    \n        if platform.system() == 'Linux':\n            set_if_unset(\n                    'CIBW_ARCHS_LINUX',\n                    make_string(\n                        'auto64' * inputs_wheels_linux_auto,\n                        'aarch64' * inputs_wheels_linux_aarch64,\n                        ),\n                    )\n            if env_extra.get('CIBW_ARCHS_LINUX') == '':\n                log(f'Not running cibuildwheel because CIBW_ARCHS_LINUX is empty string.')\n                return\n    \n        if platform.system() == 'Windows':\n            set_if_unset(\n                    'CIBW_ARCHS_WINDOWS',\n                    make_string(\n                        'auto' * inputs_wheels_windows_auto,\n                        ),\n                    )\n            if env_extra.get('CIBW_ARCHS_WINDOWS') == '':\n                log(f'Not running cibuildwheel because CIBW_ARCHS_WINDOWS is empty string.')\n                return\n    \n        if platform.system() == 'Darwin':\n            set_if_unset(\n                    'CIBW_ARCHS_MACOS',\n                    make_string(\n                        'auto' * inputs_wheels_macos_auto,\n                        'arm64' * inputs_wheels_macos_arm64,\n                        ),\n                    )\n            if env_extra.get('CIBW_ARCHS_MACOS') == '':\n                log(f'Not running cibuildwheel because CIBW_ARCHS_MACOS is empty string.')\n                return\n    \n        def env_pass(name):\n            '''\n            Adds `name` to CIBW_ENVIRONMENT_PASS_LINUX if required to be available\n            when building wheel with cibuildwheel.\n            '''\n            if platform.system() == 'Linux':\n                v = env_extra.get('CIBW_ENVIRONMENT_PASS_LINUX', '')\n                if v:\n                    v += ' '\n                v += name\n                env_extra['CIBW_ENVIRONMENT_PASS_LINUX'] = v\n    \n        def env_set(name, value, pass_=False):\n            assert isinstance( value, str)\n            if not name.startswith('CIBW'):\n                assert pass_, f'Non-CIBW* name requires `pass_` to be true. {name=} {value=}.'\n            env_extra[ name] = value\n            if pass_:\n                env_pass(name)\n\n        env_pass('PYMUPDF_SETUP_PY_LIMITED_API')\n        \n        if os.environ.get('PYMUPDF_SETUP_LIBCLANG'):\n            env_pass('PYMUPDF_SETUP_LIBCLANG')\n    \n        if inputs_skeleton:\n            env_set('PYMUPDF_SETUP_SKELETON', inputs_skeleton, pass_=1)\n    \n        if inputs_PYMUPDF_SETUP_MUPDF_BUILD not in ('-', None):\n            log(f'Setting PYMUPDF_SETUP_MUPDF_BUILD to {inputs_PYMUPDF_SETUP_MUPDF_BUILD!r}.')\n            env_set('PYMUPDF_SETUP_MUPDF_BUILD', inputs_PYMUPDF_SETUP_MUPDF_BUILD, pass_=True)\n            env_set('PYMUPDF_SETUP_MUPDF_TGZ', '', pass_=True)   # Don't put mupdf in sdist.\n    \n        if inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE not in ('-', None):\n            log(f'Setting PYMUPDF_SETUP_MUPDF_BUILD_TYPE to {inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE!r}.')\n            env_set('PYMUPDF_SETUP_MUPDF_BUILD_TYPE', inputs_PYMUPDF_SETUP_MUPDF_BUILD_TYPE, pass_=True)\n    \n        def set_cibuild_test():\n            log( f'set_cibuild_test(): {inputs_skeleton=}')\n            valgrind_text = ''\n            if valgrind:\n                valgrind_text = ' --valgrind 1'\n            env_set('CIBW_TEST_COMMAND', f'python {{project}}/scripts/gh_release.py{valgrind_text} test {{project}} {{package}}')\n    \n        if pymupdf_dir != os.path.abspath( os.getcwd()):\n            log( f'Changing dir to {pymupdf_dir=}')\n            os.chdir( pymupdf_dir)\n    \n        run('pip install cibuildwheel')\n    \n        # We include MuPDF build-time files.\n        flavour_d = True\n        \n        if PYMUPDF_SETUP_PY_LIMITED_API != '0':\n            # Build one wheel with oldest python, then fake build with other python\n            # versions so we test everything.\n            log(f'{PYMUPDF_SETUP_PY_LIMITED_API=}')\n            env_pass('PYMUPDF_SETUP_PY_LIMITED_API')\n            CIBW_BUILD_old = env_extra.get('CIBW_BUILD')\n            assert CIBW_BUILD_old is not None\n            cp = cps.split()[0]\n            env_set('CIBW_BUILD', cp)\n            log(f'Building single wheel.')\n            run( f'cibuildwheel{platform_arg}', env_extra=env_extra)\n            \n            # Fake-build with all python versions, using the wheel we have\n            # just created. This works by setting PYMUPDF_SETUP_URL_WHEEL\n            # which makes PyMuPDF's setup.py copy an existing wheel instead\n            # of building a wheel itself; it also copes with existing\n            # wheels having extra platform tags (from cibuildwheel's use of\n            # auditwheel).\n            #\n            env_set('PYMUPDF_SETUP_URL_WHEEL', f'file://wheelhouse/', pass_=True)\n            \n            set_cibuild_test()\n            env_set('CIBW_BUILD', CIBW_BUILD_old)\n            \n            # Disable cibuildwheels use of auditwheel. The wheel was repaired\n            # when it was created above so we don't need to do so again. This\n            # also avoids problems with musl wheels on a Linux glibc host where\n            # auditwheel fails with: `ValueError: Cannot repair wheel, because\n            # required library \"libgcc_s-a3a07607.so.1\" could not be located`.\n            #\n            env_set('CIBW_REPAIR_WHEEL_COMMAND', '')\n            \n            if platform.system() == 'Linux' and env_extra.get('CIBW_ARCHS_LINUX') == 'aarch64':\n                log(f'Testing all Python versions on linux-aarch64 is too slow and is killed by github after 6h.')\n                log(f'Testing on restricted python versions using wheels in wheelhouse/.')\n                # Testing only on first and last python versions.\n                cp1 = cps.split()[0]\n                cp2 = cps.split()[-1]\n                cp = cp1 if cp1 == cp2 else f'{cp1} {cp2}'\n                env_set('CIBW_BUILD', cp)\n            else:\n                log(f'Testing on all python versions using wheels in wheelhouse/.')\n            run( f'cibuildwheel{platform_arg}', env_extra=env_extra)\n            \n        elif inputs_flavours:\n            # Build and test PyMuPDF and PyMuPDFb wheels.\n            #\n        \n            # First build PyMuPDFb wheel. cibuildwheel will build a single wheel\n            # here, which will work with any python version on current OS.\n            #\n            flavour = 'b'\n            if flavour_d:\n                # Include MuPDF build-time files.\n                flavour += 'd'\n            env_set( 'PYMUPDF_SETUP_FLAVOUR', flavour, pass_=1)\n            run( f'cibuildwheel{platform_arg}', env_extra=env_extra)\n            run( 'echo after {flavour=}')\n            run( 'ls -l wheelhouse')\n\n            # Now set environment to build PyMuPDF wheels. cibuildwheel will build\n            # one for each Python version.\n            #\n        \n            # Tell cibuildwheel not to use `auditwheel`, because it cannot cope\n            # with us deliberately putting required libraries into a different\n            # wheel.\n            #\n            # Also, `auditwheel addtag` says `No tags to be added` and terminates\n            # with non-zero. See: https://github.com/pypa/auditwheel/issues/439.\n            #\n            env_set('CIBW_REPAIR_WHEEL_COMMAND_LINUX', '')\n            env_set('CIBW_REPAIR_WHEEL_COMMAND_MACOS', '')\n        \n            # We tell cibuildwheel to test these wheels, but also set\n            # CIBW_BEFORE_TEST to make it first run ourselves with the\n            # `pip_install` arg to install the PyMuPDFb wheel. Otherwise\n            # installation of PyMuPDF would fail because it lists the\n            # PyMuPDFb wheel as a prerequisite. We need to use `pip_install`\n            # because wildcards do not work on Windows, and we want to be\n            # careful to avoid incompatible wheels, e.g. 32 vs 64-bit wheels\n            # coexist during Windows builds.\n            #\n            env_set('CIBW_BEFORE_TEST', f'python scripts/gh_release.py pip_install wheelhouse/pymupdfb')\n        \n            set_cibuild_test()\n        \n            # Build main PyMuPDF wheel.\n            flavour = 'p'\n            env_set( 'PYMUPDF_SETUP_FLAVOUR', flavour, pass_=1)\n            run( f'cibuildwheel{platform_arg}', env_extra=env_extra)\n        \n        else:\n            # Build and test wheels which contain everything.\n            #\n            flavour = 'pb'\n            if flavour_d:\n                flavour += 'd'\n            set_cibuild_test()\n            env_set( 'PYMUPDF_SETUP_FLAVOUR', flavour, pass_=1)\n    \n            run( f'cibuildwheel{platform_arg}', env_extra=env_extra)\n    \n        run( 'ls -lt wheelhouse')\n\n\ndef cpu_bits():\n    return 32 if sys.maxsize == 2**31 - 1 else 64\n\n\n# Name of venv used by `venv()`.\n#\nvenv_name = f'venv-pymupdf-{platform.python_version()}-{cpu_bits()}'\n\ndef venv( command=None, packages=None, quick=False, system_site_packages=False):\n    '''\n    Runs remaining args, or the specified command if present, in a venv.\n    \n    command:\n        Command as string or list of args. Should usually start with 'python'\n        to run the venv's python.\n    packages:\n        List of packages (or comma-separated string) to install.\n    quick:\n        If true and venv directory already exists, we don't recreate venv or\n        install Python packages in it.\n    '''\n    command2 = ''\n    if platform.system() == 'OpenBSD':\n        # libclang not available from pypi.org, but system py3-llvm package\n        # works. `pip install` should be run with --no-build-isolation and\n        # explicit `pip install swig psutil`.\n        system_site_packages = True\n        #ssp = ' --system-site-packages'\n        log(f'OpenBSD: libclang not available from pypi.org.')\n        log(f'OpenBSD: system package `py3-llvm` must be installed.')\n        log(f'OpenBSD: creating venv with --system-site-packages.')\n        log(f'OpenBSD: `pip install .../PyMuPDF` must be preceded by install of swig etc.')\n    ssp = ' --system-site-packages' if system_site_packages else ''\n    if quick and os.path.isdir(venv_name):\n        log(f'{quick=}: Not creating venv because directory already exists: {venv_name}')\n        command2 += 'true'\n    else:\n        quick = False\n        command2 += f'{sys.executable} -m venv{ssp} {venv_name}'\n    if platform.system() == 'Windows':\n        command2 += f' && {venv_name}\\\\Scripts\\\\activate'\n    else:\n        command2 += f' && . {venv_name}/bin/activate'\n    if quick:\n        log(f'{quick=}: Not upgrading pip or installing packages.')\n    else:\n        command2 += ' && python -m pip install --upgrade pip'\n        if packages:\n            if isinstance(packages, str):\n                packages = packages.split(',')\n            command2 += ' && pip install ' + ' '.join(packages)\n    command2 += ' &&'\n    if isinstance( command, str):\n        command2 += ' ' + command\n    else:\n        for arg in command:\n            command2 += ' ' + shlex.quote(arg)\n    \n    run( command2)\n\n\ndef test( project, package, valgrind):\n    \n    run(f'pip install {test_packages}')\n    if valgrind:\n        log('Installing valgrind.')\n        run(f'sudo apt update')\n        run(f'sudo apt install valgrind')\n        run(f'valgrind --version')\n        \n        log('Running PyMuPDF tests under valgrind.')\n        # We ignore memory leaks.\n        run(\n                f'{sys.executable} {project}/tests/run_compound.py'\n                    f' valgrind --suppressions={project}/valgrind.supp --error-exitcode=100 --errors-for-leak-kinds=none --fullpath-after='\n                    f' pytest {project}/tests'\n                    ,\n                env_extra=dict(\n                    PYTHONMALLOC='malloc',\n                    PYMUPDF_RUNNING_ON_VALGRIND='1',\n                    ),\n                )\n    else:\n        run(f'{sys.executable} {project}/tests/run_compound.py pytest {project}/tests')\n\n\nif platform.system() == 'Windows':\n    def relpath(path, start=None):\n        try:\n            return os.path.relpath(path, start)\n        except ValueError:\n            # os.path.relpath() fails if trying to change drives.\n            return os.path.abspath(path)\nelse:\n    def relpath(path, start=None):\n        return os.path.relpath(path, start)\n\n\ndef platform_tag():\n    bits = cpu_bits()\n    if platform.system() == 'Windows':\n        return 'win32' if bits==32 else 'win_amd64'\n    elif platform.system() in ('Linux', 'Darwin'):\n        assert bits == 64\n        return platform.machine()\n        #return 'x86_64'\n    else:\n        assert 0, f'Unrecognised: {platform.system()=}'\n\n\ntest_packages = 'pytest fontTools pymupdf-fonts flake8 pylint codespell'\nif platform.system() == 'Windows' and cpu_bits() == 32:\n    # No pillow wheel available, and doesn't build easily.\n    pass\nelse:\n    test_packages += ' pillow'\nif platform.system().startswith('MSYS_NT-'):\n    # psutil not available on msys2.\n    pass\nelse:\n    test_packages += ' psutil'\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "scripts/sysinstall.py",
    "content": "#! /usr/bin/env python3\n\n'''\nTest for Linux system install of MuPDF and PyMuPDF.\n\nWe build and install MuPDF and PyMuPDF into a root directory, then use\nscripts/test.py to run PyMuPDF's pytest tests with LD_PRELOAD_PATH and\nPYTHONPATH set.\n\nPyMuPDF itself is installed using `python -m install` with a wheel created with\n`pip wheel`.\n\nWe run install commands with `sudo` if `--root /` is used.\n\nNote that we run some commands with sudo; it's important that these use the\nsame python as non-sudo, otherwise things can be build and installed for\ndifferent python versions. For example when we are run from a github action, it\nshould not do `- uses: actions/setup-python@v5` but instead use whatever system\npython is already defined.\n\nArgs:\n\n    --gdb 0|1\n    --mupdf-dir <mupdf_dir>\n        Path of MuPDF checkout; default is 'mupdf'.\n    --mupdf-do 0|1\n        Whether to build and install mupdf.\n    --mupdf-git <git_args>\n        Get or update `mupdf_dir` using git. If `mupdf_dir` already\n        exists we run `git pull` in it; otherwise we run `git\n        clone` with `<git_args> <mupdf_dir>`. For example:\n            --mupdf-git \"--branch master https://github.com/ArtifexSoftware/mupdf.git\"\n    --mupdf-so-mode <mode>\n        Used with `install -m <mode> ...` when installing MuPDF. For example\n        `--mupdf-so-mode 744`.\n    --packages 0|1\n        If 1 (the default) we install required system packages such as\n        `libfreetype-dev`.\n    --pip 0|venv|sudo\n        Whether/how to install Python packages.\n        If '0' we assume required packages are already available.\n        If 'sudo' we install required Python packages using `sudo pip install\n        ...`.\n        If 'venv' (the default) we install Python packages and run installer\n        and test commands inside venv's.\n    --prefix:\n        Directory within `root`; default is `/usr/local`. Must start with `/`.\n    --pymupdf-dir <pymupdf_dir>\n        Path of PyMuPDF checkout; default is 'PyMuPDF'.\n    --pymupdf-do 0|1\n        Whether to build and install pymupdf.\n    --root <root>\n        Root of install directory; default is 'pymupdf-sysinstall-test-root'.\n    --tesseract5 0|1\n        If 1 (the default), we force installation of libtesseract-dev version\n        5 (which is not available as a default package in Ubuntu-22.04) from\n        package repository ppa:alex-p/tesseract-ocr-devel.\n    --test-venv <test_venv>\n        Set the name of the venv in which we run tests (only with `--pip\n        venv`); the default is a hard-coded venv name. The venv will be\n        created, and required packages installed using `pip`.\n    --use-installer 0|1\n        If 1 (the default), we use `python -m installer` to install PyMuPDF\n        from a generated wheel. [Otherwise we use `pip install`, which refuses\n        to do a system install with `--root /`, referencing PEP-668.]\n    -i <implementations>\n        Passed through to scripts/test.py. Default is 'rR'.\n    -f <test-fitz>\n        Passed through to scripts/test.py. Default is '1'.\n    -p <pytest-options>\n        Passed through to scripts/test.py.\n    -t <names>\n        Passed through to scripts/test.py.\n\nTo only show what commands would be run, but not actually run them, specify `-m\n0 -p 0 -t 0`.\n'''\n\nimport glob\nimport multiprocessing\nimport os\nimport platform\nimport shlex\nimport subprocess\nimport sys\nimport sysconfig\n\nimport test as test_py\n\npymupdf_dir = os.path.abspath( f'{__file__}/../..')\n\nsys.path.insert(0, f'{pymupdf_dir}/src')\nimport pipcl\ndel sys.path[0]\n\nlog = pipcl.log0\n\n# Requirements for a system build and install:\n#\n# system packages (Debian names):\n#\ng_sys_packages = [\n        'libfreetype-dev',\n        'libgumbo-dev',\n        'libharfbuzz-dev',\n        'libjbig2dec-dev',\n        'libjpeg-dev',\n        'libleptonica-dev',\n        'libopenjp2-7-dev',\n        ]\n# We also need libtesseract-dev version 5.\n#\n\n\ndef main():\n    \n    if 1:\n        log(f'## {__file__}: Starting.')\n        log(f'{sys.executable=}')\n        log(f'{platform.python_version()=}')\n        log(f'{__file__=}')\n        log(f'{os.environ.get(\"PYMUDF_SCRIPTS_SYSINSTALL_ARGS_PRE\")=}')\n        log(f'{os.environ.get(\"PYMUDF_SCRIPTS_SYSINSTALL_ARGS_POST\")=}')\n        log(f'{sys.argv=}')\n        log(f'{sysconfig.get_path(\"platlib\")=}')\n        run_command(f'python -V', check=0)\n        run_command(f'python3 -V', check=0)\n        run_command(f'sudo python -V', check=0)\n        run_command(f'sudo python3 -V', check=0)\n        run_command(f'sudo PATH={os.environ[\"PATH\"]} python -V', check=0)\n        run_command(f'sudo PATH={os.environ[\"PATH\"]} python3 -V', check=0)\n    \n    if test_py.github_workflow_unimportant():\n        return\n    \n    # Set default behaviour.\n    #\n    gdb = False\n    use_installer = True\n    mupdf_do = True\n    mupdf_dir = 'mupdf'\n    mupdf_git = None\n    mupdf_so_mode = None\n    packages = True\n    prefix = '/usr/local'\n    pymupdf_do = True\n    root = 'pymupdf-sysinstall-test-root'\n    tesseract5 = True\n    pytest_args = None\n    pytest_do = True\n    pytest_name = None\n    test_venv = 'venv-pymupdf-sysinstall-test'\n    pip = 'venv'\n    test_fitz = '1'\n    test_implementations = 'rR'\n    \n    # Parse command-line.\n    #\n    env_args_pre = shlex.split(os.environ.get('PYMUDF_SCRIPTS_SYSINSTALL_ARGS_PRE', ''))\n    env_args_post = shlex.split(os.environ.get('PYMUDF_SCRIPTS_SYSINSTALL_ARGS_POST', ''))\n    args = iter(env_args_pre + sys.argv[1:] + env_args_post)\n    while 1:\n        try:\n            arg = next(args)\n        except StopIteration:\n            break\n        if arg in ('-h', '--help'):\n            log(__doc__)\n            return\n        elif arg == '--gdb':            gdb = int(next(args))\n        elif arg == '--mupdf-do':       mupdf_do = int(next(args))\n        elif arg == '--mupdf-dir':      mupdf_dir = next(args)\n        elif arg == '--mupdf-git':      mupdf_git = next(args)\n        elif arg == '--mupdf-so-mode':  mupdf_so_mode = next(args)\n        elif arg == '--packages':       packages = int(next(args))\n        elif arg == '--prefix':         prefix = next(args)\n        elif arg == '--pymupdf-do':     pymupdf_do = int(next(args))\n        elif arg == '--root':           root = next(args)\n        elif arg == '--tesseract5':     tesseract5 = int(next(args))\n        elif arg == '--pytest-do':      pytest_do = int(next(args))\n        elif arg == '--test-venv':      test_venv = next(args)\n        elif arg == '--use-installer':  use_installer = int(next(args))\n        elif arg == '--pip':            pip = next(args)\n        elif arg == '-f':               test_fitz = next(args)\n        elif arg == '-i':               test_implementations = next(args)\n        elif arg == '-p':               pytest_args = next(args)\n        elif arg == '-t':               pytest_name = next(args)\n        else:\n            assert 0, f'Unrecognised arg: {arg!r}'\n    \n    assert prefix.startswith('/')\n    pip_values = ('0', 'sudo', 'venv')\n    assert pip in pip_values, f'Unrecognised --pip value {pip!r} should be one of: {pip_values!r}'\n    root = os.path.abspath(root)\n    root_prefix = f'{root}{prefix}'.replace('//', '/')\n    \n    sudo = ''\n    if root == '/':\n        sudo = f'sudo PATH={os.environ[\"PATH\"]} '\n    def run(command, env_extra=None):\n        return run_command(command, doit=mupdf_do, env_extra=env_extra)\n    # Get MuPDF from git if specified.\n    #\n    if mupdf_git:\n        # Update existing checkout or do `git clone`.\n        if os.path.exists(mupdf_dir):\n            log(f'## Update MuPDF checkout {mupdf_dir}.')\n            run(f'cd {mupdf_dir} && git pull && git submodule update --init')\n        else:\n            # No existing git checkout, so do a fresh clone.\n            log(f'## Clone MuPDF into {mupdf_dir}.')\n            run(f'git clone --recursive --depth 1 --shallow-submodules {mupdf_git} {mupdf_dir}')\n    \n    if packages:\n        # Install required system packages. We assume a Debian package system.\n        #\n        log('## Install system packages required by MuPDF.')\n        run(f'sudo apt update')\n        run(f'sudo apt install {\" \".join(g_sys_packages)}')\n        # Ubuntu-22.04 has freeglut3-dev, not libglut-dev.\n        run(f'sudo apt install libglut-dev | sudo apt install freeglut3-dev')\n        if tesseract5:\n            log(f'## Force installation of libtesseract-dev version 5.')\n            # https://stackoverflow.com/questions/76834972/how-can-i-run-pytesseract-python-library-in-ubuntu-22-04\n            #\n            run('sudo apt install -y software-properties-common')\n            run('sudo add-apt-repository ppa:alex-p/tesseract-ocr-devel')\n            run('sudo apt update')\n            run('sudo apt install -y libtesseract-dev')\n        else:\n            run('sudo apt install libtesseract-dev')\n    \n    # Build+install MuPDF. We use mupd:Makefile's install-shared-python target.\n    #\n    if pip == 'sudo':\n        log('## Installing Python packages required for building MuPDF and PyMuPDF.')\n        #run(f'sudo pip install --upgrade pip') # Breaks on Github see: https://github.com/pypa/get-pip/issues/226.\n        # We need to install psutil and pillow as system packages, otherwise things like `import psutil`\n        # fail, seemingly because of pip warning:\n        #\n        #   WARNING: Running pip as the 'root' user can result in broken\n        #   permissions and conflicting behaviour with the system package\n        #   manager. It is recommended to use a virtual environment instead:\n        #   https://pip.pypa.io/warnings/venv\n        #\n        names = test_py.wrap_get_requires_for_build_wheel(f'{__file__}/../..')\n        names = names.split(' ')\n        names = [n for n in names if n not in ('psutil', 'pillow')]\n        names = ' '.join(names)\n        run(f'sudo pip install {names}')\n        run(f'sudo apt install python3-psutil python3-pillow')\n    \n    log('## Build and install MuPDF.')\n    command = f'cd {mupdf_dir}'\n    command += f' && {sudo}make'\n    command += f' -j {multiprocessing.cpu_count()}'\n    #command += f' EXE_LDFLAGS=-Wl,--trace' # Makes linker generate diagnostics as it runs.\n    command += f' DESTDIR={root}'\n    command += f' HAVE_LEPTONICA=yes'\n    command += f' HAVE_TESSERACT=yes'\n    command += f' USE_SYSTEM_LIBS=yes'\n    # We need latest zxingcpp so system version not ok.\n    command += f' USE_SYSTEM_ZXINGCPP=no'\n    command += f' barcode=yes'\n    command += f' VENV_FLAG={\"--venv\" if pip == \"venv\" else \"\"}'\n    if mupdf_so_mode:\n        command += f' SO_INSTALL_MODE={mupdf_so_mode}'\n    command += f' build_prefix=system-libs-'\n    command += f' prefix={prefix}'\n    command += f' verbose=yes'\n    command += f' install-shared-python'\n    command += f' INSTALL_MODE=755'\n    run( command)\n    \n    # Build+install PyMuPDF.\n    #\n    log('## Build and install PyMuPDF.')\n    def run(command):\n        return run_command(command, doit=pymupdf_do)\n    flags_freetype2 = run_command('pkg-config --cflags freetype2', capture=1)\n    compile_flags = f'-I {root_prefix}/include {flags_freetype2}'\n    link_flags = f'-L {root_prefix}/lib'\n    env = ''\n    env += f'CFLAGS=\"{compile_flags}\" '\n    env += f'CXXFLAGS=\"{compile_flags}\" '\n    env += f'LDFLAGS=\"-L {root}/{prefix}/lib\" '\n    env += f'PYMUPDF_SETUP_MUPDF_BUILD= '       # Use system MuPDF.\n    if use_installer:\n        log(f'## Building wheel.')\n        if pip == 'venv':\n            venv_name = 'venv-pymupdf-sysinstall'\n        run(f'pwd')\n        run(f'rm dist/* || true')\n        if pip == 'venv':\n            run(f'{sys.executable} -m venv {venv_name}')\n            run(f'. {venv_name}/bin/activate && pip install --upgrade pip')\n            run(f'. {venv_name}/bin/activate && pip install --upgrade installer')\n            run(f'{env} {venv_name}/bin/python -m pip wheel -vv -w dist {os.path.abspath(pymupdf_dir)}')\n        elif pip == 'sudo':\n            #run(f'sudo pip install --upgrade pip') # Breaks on Github see: https://github.com/pypa/get-pip/issues/226.\n            run(f'sudo pip install installer')\n            run(f'{env} pip wheel -vv -w dist {os.path.abspath(pymupdf_dir)}')\n        else:\n            log(f'Not installing \"installer\" because {pip=}.')\n        wheel = glob.glob(f'dist/*')\n        assert len(wheel) == 1, f'{wheel=}'\n        wheel = wheel[0]\n        log(f'## Installing wheel using `installer`.')\n        pv = '.'.join(platform.python_version_tuple()[:2])\n        p = f'{root_prefix}/lib/python{pv}'\n        # `python -m installer` fails to overwrite existing files.\n        run(f'{sudo}rm -r {p}/site-packages/pymupdf || true')\n        run(f'{sudo}rm -r {p}/site-packages/pymupdf.py || true')\n        run(f'{sudo}rm -r {p}/site-packages/fitz || true')\n        run(f'{sudo}rm -r {p}/site-packages/fitz.py || true')\n        run(f'{sudo}rm -r {p}/site-packages/pymupdf-*.dist-info || true')\n        run(f'{sudo}rm -r {root_prefix}/bin/pymupdf || true')\n        if pip == 'venv':\n            run(f'{sudo}{venv_name}/bin/python -m installer --destdir {root} --prefix {prefix} {wheel}')\n        else:\n            run(f'{sudo}{sys.executable} -m installer --destdir {root} --prefix {prefix} {wheel}')\n        # It seems that MuPDF Python bindings are installed into\n        # `.../dist-packages` (from mupdf:Mafile's call of `$(shell python3\n        # -c \"import sysconfig; print(sysconfig.get_path('platlib'))\")` while\n        # `python -m installer` installs PyMuPDF into `.../site-packages`.\n        #\n        # This might be because `sysconfig.get_path('platlib')` returns\n        # `.../site-packages` if run in a venv, otherwise `.../dist-packages`.\n        #\n        # And on github ubuntu-latest, sysconfig.get_path(\"platlib\") is\n        #   /opt/hostedtoolcache/Python/3.11.7/x64/lib/python3.11/site-packages\n        #\n        # So we set pythonpath (used later) to import from all\n        # `pythonX.Y/site-packages/` and `pythonX.Y/dist-packages` directories\n        # within `root_prefix`:\n        #\n        pv = platform.python_version().split('.')\n        pv = f'python{pv[0]}.{pv[1]}'\n        pythonpath = list()\n        for dirpath, dirnames, filenames in os.walk(root_prefix):\n            if os.path.basename(dirpath) == pv:\n                for leaf in 'site-packages', 'dist-packages':\n                    if leaf in dirnames:\n                        pythonpath.append(os.path.join(dirpath, leaf))\n        pythonpath = ':'.join(pythonpath)\n        log(f'{pythonpath=}')\n    else:\n        command = f'{env} pip install -vv --root {root} {os.path.abspath(pymupdf_dir)}'\n        run( command)\n        pythonpath = pipcl.install_dir(root)\n    \n    # Show contents of installation directory. This is very slow on github,\n    # where /usr/local contains lots of things.\n    #run(f'find {root_prefix}|sort')\n        \n    # Run pytest tests.\n    #\n    log('## Run PyMuPDF pytest tests.')\n    def run(command, env_extra=None):\n        return run_command(command, doit=pytest_do, env_extra=env_extra, caller=1)\n    import gh_release\n    if pip == 'venv':\n        # Create venv.\n        run(f'{sys.executable} -m venv {test_venv}')\n        # Install required packages.\n        command = f'. {test_venv}/bin/activate'\n        command += f' && pip install --upgrade pip'\n        command += f' && pip install --upgrade {gh_release.test_packages}'\n        run(command)\n    elif pip == 'sudo':\n        names = gh_release.test_packages\n        names = names.split(' ')\n        names = [n for n in names if n not in ('psutil', 'pillow')]\n        names = ' '.join(names)\n        run(f'sudo pip install --upgrade {names}')\n    else:\n        log(f'Not installing packages for testing because {pip=}.')\n    # Run pytest.\n    #\n    # We need to set PYTHONPATH and LD_LIBRARY_PATH. In particular we\n    # use pipcl.install_dir() to find where pipcl will have installed\n    # PyMuPDF.\n    command = ''\n    if pip == 'venv':\n        command += f'. {test_venv}/bin/activate &&'\n    command += f' LD_LIBRARY_PATH={root_prefix}/lib PYTHONPATH={pythonpath} PATH=$PATH:{root_prefix}/bin'\n    run(f'ls -l {root_prefix}/bin/')\n    # 2024-03-20: Not sure whether/where `pymupdf` binary is installed, so we\n    # disable the test_cli* tests.\n    command += f' {pymupdf_dir}/scripts/test.py'\n    if gdb:\n        command += ' --gdb 1'\n    command += f' -v 0'\n    if pytest_name is None:\n        excluded_tests = (\n                'test_color_count',\n                'test_3050',\n                'test_cli',\n                'test_cli_out',\n                'test_pylint',\n                'test_textbox3',\n                'test_3493',\n                'test_4180',\n                'test_4767',\n                )\n        excluded_tests = ' and not '.join(excluded_tests)\n        if not pytest_args:\n            pytest_args = ''\n        pytest_args += f' -k \\'not {excluded_tests}\\''\n    else:\n        command += f' -t {pytest_name}'\n    if test_fitz:\n        command += f' -f {test_fitz}'\n    if test_implementations:\n        command += f' -i {test_implementations}'\n    if pytest_args:\n        command += f' -p {shlex.quote(pytest_args)}'\n    if pytest_do:\n        command += ' test'\n    run(command, env_extra=dict(PYMUPDF_SYSINSTALL_TEST='1'))\n\n\ndef run_command(command, capture=False, check=True, doit=True, env_extra=None, caller=0):\n    if doit:\n        return pipcl.run(command, capture=capture, check=check, caller=caller+2, env_extra=env_extra)\n    else:\n        log(f'## Would have run: {command}', caller=2)\n\n\nif __name__ == '__main__':\n    main()\n"
  },
  {
    "path": "scripts/test.py",
    "content": "#! /usr/bin/env python3\n\n'''Developer build/test script for PyMuPDF.\n\nExamples:\n\n    ./PyMuPDF/scripts/test.py -m mupdf build test\n        Build and test with pre-existing local mupdf/ checkout.\n\n    ./PyMuPDF/scripts/test.py build test\n        Build and test with default internal download of mupdf.\n\n    ./PyMuPDF/scripts/test.py -m 'git:https://git.ghostscript.com/mupdf.git' build test\n        Build and test with internal checkout of MuPDF master.\n\n    ./PyMuPDF/scripts/test.py -m ':1.27.x' build test\n        Build and test using internal checkout of mupdf 1.27.x branch from\n        Github.\n\n    ./PyMuPDF/scripts/test.py install test -i 1.26.3 -k test_2596\n        Install pymupdf-1.26.3 from pupi.org and test only test_2596.\n\nUsage:\n\n* Command line arguments are called parameters if they start with `-`,\n  otherwise they are called commands.\n* Parameters are evaluated first in the order that they were specified.\n* Then commands are run in the order in which they were specified.\n* Usually command `test` would be specified after a `build`, `install` or\n  `wheel` command.\n* Parameters and commands can be interleaved but it may be clearer to separate\n  them on the command line.\n\nOther:\n\n* If we are not already running inside a Python venv, we automatically create a\n  venv and re-run ourselves inside it (also see the -v option).\n* Build/wheel/install commands always install into the venv.\n* Tests use whatever PyMuPDF/MuPDF is currently installed in the venv.\n* We run tests with pytest.\n\n* One can generate call traces by setting environment variables in debug\n  builds. For details see:\n  https://mupdf.readthedocs.io/en/latest/language-bindings.html#environmental-variables\n\nCommand line args:\n\n    -a <env_name>\n        Read next space-separated argument(s) from environmental variable\n        <env_name>.\n        * Does nothing if <env_name> is unset.\n        * Useful when running via Github action.\n    \n    -b <build>\n        Set build type for `build` commands. `<build>` should be one of\n        'release', 'debug', 'memento'. [This makes `build` set environment\n        variable `PYMUPDF_SETUP_MUPDF_BUILD_TYPE`, which is used by PyMuPDF's\n        `setup.py`.]\n    \n    --build-flavour <build_flavour>\n        [Obsolete.]\n        Combination of 'p', 'b', 'd'. See ../setup.py's description of\n        PYMUPDF_SETUP_FLAVOUR. Default is 'pbd', i.e. self-contained PyMuPDF\n        wheels including MuPDF build-time files.\n    \n    --build-isolation 0|1\n        If true (the default on non-OpenBSD systems), we let pip create and use\n        its own new venv to build PyMuPDF. Otherwise we force pip to use the\n        current venv.\n    \n    --cibw-archs-linux <archs>\n        Set CIBW_ARCHS_LINUX, e.g. to `auto64 aarch64`. Default is `auto64` so\n        this allows control over whether to build linux-aarch64 wheels.\n    \n    --cibw-name <cibw_name>\n        Name to use when installing cibuildwheel, e.g.:\n            --cibw-name cibuildwheel==3.0.0b1\n            --cibw-name git+https://github.com/pypa/cibuildwheel\n        Default is `cibuildwheel`, i.e. the current release.\n    \n    --cibw-pyodide 0|1\n         Experimental, make `cibw` command build a pyodide wheel.\n         2025-05-27: this fails when building mupdf C API - `ld -r -b binary\n         ...` fails with:\n            emcc: error: binary: No such file or directory (\"binary\" was expected to be an input file, based on the commandline arguments provided)\n\n    --cibw-pyodide-version <cibw_pyodide_version>\n        Override default Pyodide version to use with `cibuildwheel` command. If\n        empty string we use cibuildwheel's default.\n    \n    --cibw-release-1\n        Set up so that `cibw` builds all wheels except linux-aarch64, and sdist\n        if on Linux.\n    \n    --cibw-release-2\n        Set up so that `cibw` builds only linux-aarch64 wheel.\n    \n    --cibw-skip-add-defaults 0|1\n        If 1 (the default) we add defaults to CIBW_SKIP such as `pp*` (to\n        exclude pypy) and `cp3??t-*` (to exclude free-threading).\n    \n    --cibw-test-project 0|1\n         If 1, command `cibw` will use a minimal test project instead of the\n         PyMuPDF directory itself.\n         \n         The test project uses setjmp/longjmp and C++ throw/catch.\n         \n         The test checks for current behaviour, so with `--cibw-pyodide 1` it\n         succeeds if the cibw command fails with the expected error message.\n         \n         2025-08-22:\n            Builds ok on Linux.\n            \n            Fails at runtime with --cibw-pyodide 1:\n            \n                With compile/link flags ``:\n                    (+45.0s): remote.py:233:main: jules-devuan: Pyodide has suffered a fatal error. Please report this to the Pyodide maintainers.\n                    (+45.1s): remote.py:233:main: jules-devuan: Stack (most recent call first):\n                    (+45.1s): remote.py:233:main: jules-devuan:   File \"/tmp/cibw-run-h_pfo0wf/cp312-pyodide_wasm32/venv-test/lib/python3.12/site-packages/foo/__init__.py\", line 63 in bar\n                    (+45.1s): remote.py:233:main: jules-devuan:   File \"<string>The cause of the fatal error was:\n                    (+45.1s): remote.py:233:main: jules-devuan: CppException std::runtime_error: deliberate exception\n                    (+45.1s): remote.py:233:main: jules-devuan:     at convertCppException (/home/jules/.cache/cibuildwheel/pyodide-build-0.30.7/0.27.7/xbuildenv/pyodide-root/dist/pyodide.asm.js:10:48959)\n                    (+45.1s): remote.py:233:main: jules-devuan:     at API.fatal_error (/home/jules/.cache/cibuildwheel/pyodide-build-0.30.7/0.27.7/xbuildenv/pyodide-root/dist/pyodide.asm.js:10:49253)\n                    (+45.1s): remote.py:233:main: jules-devuan:     at main (file:///home/jules/.cache/cibuildwheel/pyodide-build-0.30.7/0.27.7/xbuildenv/pyodide-root/dist/python_cli_entry.mjs:149:13) {\n                    (+45.1s): remote.py:233:main: jules-devuan:   ty: 'std::runtime_error',\n                    (+45.1s): remote.py:233:main: jules-devuan:   pyodide_fatal_error: true\n                    (+45.1s): remote.py:233:main: jules-devuan: }\n                    (+45.1s): remote.py:233:main: jules-devuan: \", line 1 in <module>\n                    (+45.1s): remote.py:233:main: jules-devuan: CppException std::runtime_error: deliberate exception\n                    (+45.1s): remote.py:233:main: jules-devuan:     at convertCppException (/home/jules/.cache/cibuildwheel/pyodide-build-0.30.7/0.27.7/xbuildenv/pyodide-root/dist/pyodide.asm.js:10:48959)\n                    (+45.1s): remote.py:233:main: jules-devuan:     at API.fatal_error (/home/jules/.cache/cibuildwheel/pyodide-build-0.30.7/0.27.7/xbuildenv/pyodide-root/dist/pyodide.asm.js:10:49253)\n                    (+45.1s): remote.py:233:main: jules-devuan:     at main (file:///home/jules/.cache/cibuildwheel/pyodide-build-0.30.7/0.27.7/xbuildenv/pyodide-root/dist/python_cli_entry.mjs:149:13) {\n                    (+45.1s): remote.py:233:main: jules-devuan:   ty: 'std::runtime_error',\n                    (+45.1s): remote.py:233:main: jules-devuan:   pyodide_fatal_error: true\n                    (+45.1s): remote.py:233:main: jules-devuan: }\n\n                With compile/link flags `-fwasm-exceptions`:\n                    [LinkError: WebAssembly.instantiate(): Import #60 module=\"env\" function=\"__c_longjmp\": tag import requires a WebAssembly.Tag]\n\n                With compile/link flags `-fwasm-exceptions -sSUPPORT_LONGJMP=wasm`:\n                    [LinkError: WebAssembly.instantiate(): Import #60 module=\"env\" function=\"__c_longjmp\": tag import requires a WebAssembly.Tag]\n\n    --cibw-test-project-setjmp 0|1\n        If 1, --cibw-test-project builds a project that uses\n        setjmp/longjmp. Default is 0 (Windows builds fail when attempting to\n        compile the output from swig).\n    \n    -d\n        Equivalent to `-b debug`.\n    \n    --dummy\n        Sets PYMUPDF_SETUP_DUMMY=1 which makes setup.py build a dummy wheel\n        with no content. For internal testing only.\n    \n    -e <name>=<value>\n        Add to environment used in build and test commands. Can be specified\n        multiple times.\n    \n    -f 0|1\n        If 1 we also test alias `fitz` as well as `pymupdf`. Default is '0'.\n    \n    --graal\n        Use graal - run inside a Graal VM instead of a Python venv.\n        \n        As of 2025-08-04, if specified:\n        * We assert-fail if cibw and non-cibw commands are specified.\n        * If `cibw` is specified:\n            * We use a conventional venv.\n            * We set CIBW_ENABLE=graalpy.\n            * We set CIBW_BUILD = 'gp*'.\n        * Otherwise:\n            * We don't create a conventional venv.\n            * Clone the latest pyenv and build it.\n            * Use pyenv to install graalpy.\n            * Use graalpy to create venv.\n        \n        [After the first time, suggest `-v 1` to avoid delay from\n        updating/building pyenv and recreating the graal venv.]\n    \n    --help\n    -h\n        Show help.\n    \n    -I <implementations>\n        Set PyMuPDF implementations to test.\n        <implementations> must contain only these individual characters:\n             'r' - rebased.\n             'R' - rebased without optimisations.\n            Default is 'r'. Also see `PyMuPDF:tests/run_compound.py`.\n    \n    -i <install_version>\n        Controls behaviour of `install` command:\n        \n        * If <install_version> ends with `.whl` we use `pip install\n          <install_version>`.\n        * If <install_version> starts with == or >= or >, we use `pip install\n          pymupdf<install_version>`.\n        * Otherwise we use `pip install pymupdf==<install_version>`.\n    \n    -k <expression>\n        Specify which test(s) to run; passed straight through to pytest's `-k`.\n        For example `-k test_3354`.\n    \n    -m <location> | --mupdf <location>\n        Location of mupdf as local directory or remote git, to be used when\n        building PyMuPDF.\n        \n        This sets environment variable PYMUPDF_SETUP_MUPDF_BUILD, which is used\n        by PyMuPDF/setup.py. If not specified PyMuPDF will download its default\n        mupdf .tgz.\n        \n        Additionally if <location> starts with ':' we use the remaining text as\n        the branch name and add https://github.com/ArtifexSoftware/mupdf.git.\n        \n        For example:\n        \n            -m \"git:--branch master https://github.com/ArtifexSoftware/mupdf.git\"\n            -m :master\n            \n            -m \"git:--branch 1.27.x https://github.com/ArtifexSoftware/mupdf.git\"\n            -m :1.27.x\n            \n    --mupdf-clean 0|1\n        If 1 we do a clean MuPDF build.\n    \n    -M 0|1\n    --build-mupdf 0|1\n        Whether to rebuild mupdf when we build PyMuPDF. Default is 1.\n    \n    -o <os_names>\n        Control whether we do nothing on the current platform.\n        * <os_names> is a comma-separated list of names.\n        * If <os_names> is empty (the default), we always run normally.\n        * Otherwise we only run if an item in <os_names> matches (case\n          insensitive) platform.system().\n        * For example `-o linux,darwin` will do nothing unless on Linux or\n          MacOS.\n    \n    -p <pytest-options>\n        Set pytest options; default is ''.\n    \n    -P 0|1\n        If 1, automatically install required system packages such as\n        Valgrind. Default is 1 if running as Github action, otherwise 0.\n    \n    --pybind 0|1\n        Experimental, for investigating\n        https://github.com/pymupdf/PyMuPDF/issues/3869. Runs run basic code\n        inside C++ pybind. Requires `sudo apt install pybind11-dev` or similar.\n    \n    --pyodide-build-version <version>\n        Version of Python package pyodide-build to use with `pyodide` command.\n        \n        If None (the default) `pyodide` uses the latest available version.\n        2025-02-13: pyodide_build_version='0.29.3' works.\n    \n    -s 0 | 1\n        If 1 (the default), build with Python Limited API/Stable ABI.\n        [This simply sSets $PYMUPDF_SETUP_PY_LIMITED_API, which is used by\n        PyMuPDF/setup.py.]\n    \n    --show-args:\n        Show sys.argv and exit. For debugging.\n    \n    --sync-paths <path>\n        Do not run anything, instead write required files/directories/checkouts\n        to <path>, one per line. This is to help with automated running on\n        remote machines.\n    \n    --system-site-packages 0|1\n        If 1, use `--system-site-packages` when creating venv. Defaults is 0.\n    \n    --swig <swig>\n        Use <swig> instead of the `swig` command.\n        \n        Unix only:\n            Clone/update/build swig from a git repository using 'git:' prefix.\n        \n            We default to https://github.com/swig/swig.git branch master, so these\n            are all equivalent:\n\n                --swig 'git:--branch master https://github.com/swig/swig.git'\n                --swig 'git:--branch master'\n                --swig git:\n            \n            2025-08-18: This fixes building with py_limited_api on python-3.13.\n    \n    --swig-quick 0|1\n        If 1 and `--swig` starts with 'git:', we do not update/build swig if\n        already present.\n        \n        See description of PYMUPDF_SETUP_SWIG_QUICK in setup.py.\n    \n    -t <names>\n        Pytest test names, comma-separated. Should be relative to PyMuPDF\n        directory. For example:\n            -t tests/test_general.py\n            -t tests/test_general.py::test_subset_fonts\n        To specify multiple tests, use comma-separated list and/or multiple `-t\n        <names>` args.\n    \n    --timeout <seconds>\n        Sets timeout when running tests.\n    \n    -T <prefix>\n        Use specified prefix when running pytest, must be one of:\n            gdb\n            helgrind\n            valgrind\n    \n    -v <venv>\n        venv is:\n        0 - do not use a venv.\n        1 - Use venv. If it already exists, we assume the existing directory\n            was created by us earlier and is a valid venv containing all\n            necessary packages; this saves a little time.\n        2 - Use venv.\n        3 - Use venv but delete it first if it already exists.\n        The default is 2.\n    \nCommands:\n    \n    build\n        Builds and installs PyMuPDF into venv, using `pip install .../PyMuPDF`.\n    \n    buildtest\n        Same as 'build test'.\n    \n    cibw\n        Build and test PyMuPDF wheel(s) using cibuildwheel. Wheels are placed\n        in directory `wheelhouse`.\n        * We do not attempt to install wheels.\n        * So it is generally not useful to do `cibw test`.\n        \n        If CIBW_BUILD is unset, we set it as follows:\n        * On Github we build and test all supported Python versions.\n        * Otherwise we build and test the current Python version only.\n        \n        If CIBW_ARCHS is unset we set $CIBW_ARCHS_WINDOWS, $CIBW_ARCHS_MACOS\n        and $CIBW_ARCHS_LINUX to auto64 if they are unset.\n    \n    install <pymupdf>\n        Install with `pip install --force-reinstall <pymupdf>`.\n    \n    pyodide\n        Build Pyodide wheel. We clone `emsdk.git`, set it up, and run\n        `pyodide build`. This runs our setup.py with CC etc set up\n        to create Pyodide binaries in a wheel called, for example,\n        `PyMuPDF-1.23.2-cp311-none-emscripten_3_1_32_wasm32.whl`.\n        \n        It seems that sys.version must match the Python version inside emsdk;\n        as of 2025-02-14 this is 3.12. Otherwise we get build errors such as:\n            [wasm-validator error in function 723] unexpected false: all used features should be allowed, on ...\n    \n    test\n        Runs PyMuPDF's pytest tests. Default is to test rebased and unoptimised\n        rebased; use `-i` to change this.\n    \n    wheel\n        Build and install wheel.\n            \n\nEnvironment:\n    PYMUDF_SCRIPTS_TEST_options\n        Is prepended to command line args.\n'''\n\nimport glob\nimport os\nimport platform\nimport re\nimport shlex\nimport shutil\nimport subprocess\nimport sys\nimport textwrap\n\n\npymupdf_dir_abs = os.path.abspath( f'{__file__}/../..')\n\ntry:\n    sys.path.insert(0, f'{pymupdf_dir_abs}/src')\n    import pipcl\nfinally:\n    del sys.path[0]\n\ntry:\n    sys.path.insert(0, f'{pymupdf_dir_abs}/scripts')\n    import gh_release\nfinally:\n    del sys.path[0]\n\n\npymupdf_dir = pipcl.relpath(pymupdf_dir_abs)\n\nlog = pipcl.log0\nrun = pipcl.run\n\n\n# We build and test Python 3.x for x in this range.\npython_versions_minor = range(9, 14+1)\n\ndef cibw_cp(*version_minors):\n    '''\n    Returns <version_tuples> in 'cp39*' format, e.g. suitable for CIBW_BUILD.\n    '''\n    ret = list()\n    for version_minor in version_minors:\n        ret.append(f'cp3{version_minor}*')\n    return ' '.join(ret)\n\n\ndef main(argv):\n\n    if github_workflow_unimportant():\n        return\n    \n    build_isolation = None\n    cibw_name = None\n    cibw_pyodide = None\n    cibw_pyodide_version = None\n    cibw_skip_add_defaults = True\n    cibw_test_project = None\n    cibw_test_project_setjmp = False\n    commands = list()\n    env_extra = dict()\n    graal = False\n    implementations = 'r'\n    install_version = None\n    mupdf_sync = None\n    os_names = list()\n    system_packages = True if os.environ.get('GITHUB_ACTIONS') == 'true' else False\n    pybind = False\n    pyodide_build_version = None\n    pytest_options = ''\n    pytest_prefix = None\n    cibw_sdist = None\n    show_args = False\n    show_help = False\n    sync_paths = False\n    system_site_packages = False\n    swig = None\n    swig_quick = None\n    test_fitz = False\n    test_names = list()\n    test_timeout = None\n    valgrind = False\n    warnings = list()\n    venv = 2\n    \n    options = os.environ.get('PYMUDF_SCRIPTS_TEST_options', '')\n    options = shlex.split(options)\n    \n    # Parse args and update the above state. We do this before moving into a\n    # venv, partly so we can return errors immediately.\n    #\n    args = iter(options + argv[1:])\n    i = 0\n    while 1:\n        try:\n            arg = next(args)\n        except StopIteration:\n            arg = None\n            break\n        \n        if 0:\n            pass\n        \n        elif arg == '-a':\n            _name = next(args)\n            _value = os.environ.get(_name, '')\n            _args = shlex.split(_value) + list(args)\n            args = iter(_args)\n        \n        elif arg == '-b':\n            env_extra['PYMUPDF_SETUP_MUPDF_BUILD_TYPE'] = next(args)\n        \n        elif arg == '--build-flavour':\n            env_extra['PYMUPDF_SETUP_FLAVOUR'] = next(args)\n        \n        elif arg == '--build-isolation':\n            build_isolation = int(next(args))\n        \n        elif arg == '--cibw-pyodide-version':\n            cibw_pyodide_version = next(args)\n        \n        elif arg == '--cibw-release-1':\n            cibw_sdist = True\n            env_extra['CIBW_ARCHS_LINUX'] = 'auto64'\n            env_extra['CIBW_ARCHS_MACOS'] = 'auto64'\n            env_extra['CIBW_ARCHS_WINDOWS'] = 'auto'    # win32 and win64.\n            env_extra['CIBW_SKIP'] = '*i686 *musllinux*aarch64* cp3??t-*'\n            cibw_skip_add_defaults = 0\n        \n        elif arg == '--cibw-release-2':\n            # Testing only first and last python versions because otherwise\n            # Github times out after 6h.\n            env_extra['CIBW_BUILD'] = cibw_cp(python_versions_minor[0], python_versions_minor[-1])\n            env_extra['CIBW_ARCHS_LINUX'] = 'aarch64'\n            env_extra['CIBW_SKIP'] = '*i686 *musllinux*aarch64* cp3??t-*'\n            cibw_skip_add_defaults = 0\n            os_names = ['linux']\n        \n        elif arg == '--cibw-archs-linux':\n            env_extra['CIBW_ARCHS_LINUX'] = next(args)\n            \n        elif arg == '--cibw-name':\n            cibw_name = next(args)\n        \n        elif arg == '--cibw-pyodide':\n            cibw_pyodide = int(next(args))\n        \n        elif arg == '--cibw-skip-add-defaults':\n            cibw_skip_add_defaults = int(next(args))\n        \n        elif arg == '--cibw-test-project':\n            cibw_test_project = int(next(args))\n        \n        elif arg == '--cibw-test-project-setjmp':\n            cibw_test_project_setjmp = int(next(args))\n        \n        elif arg == '-d':\n            env_extra['PYMUPDF_SETUP_MUPDF_BUILD_TYPE'] = 'debug'\n        \n        elif arg == '--dummy':\n            env_extra['PYMUPDF_SETUP_DUMMY'] = '1'\n            env_extra['CIBW_TEST_COMMAND'] = ''\n        \n        elif arg == '-e':\n            _nv = next(args)\n            assert '=' in _nv, f'-e <name>=<value> does not contain \"=\": {_nv!r}'\n            _name, _value = _nv.split('=', 1)\n            env_extra[_name] = _value\n        \n        elif arg == '-f':\n            test_fitz = int(next(args))\n        \n        elif arg == '--graal':\n            graal = True\n        \n        elif arg in ('-h', '--help'):\n            show_help = True\n        \n        elif arg == '-i':\n            install_version = next(args)\n        \n        elif arg == '-I':\n            implementations = next(args)\n        \n        elif arg == '-k':\n            pytest_options += f' -k {shlex.quote(next(args))}'\n        \n        elif arg in ('-m', '--mupdf'):\n            _mupdf = next(args)\n            if _mupdf == '-':\n                _mupdf = None\n            elif _mupdf.startswith(':'):\n                _branch = _mupdf[1:]\n                _mupdf = f'git:--branch {_branch} https://github.com/ArtifexSoftware/mupdf.git'\n                env_extra['PYMUPDF_SETUP_MUPDF_BUILD'] = _mupdf\n            elif _mupdf.startswith('git:') or '://' in _mupdf:\n                env_extra['PYMUPDF_SETUP_MUPDF_BUILD'] = _mupdf\n            else:\n                assert os.path.isdir(_mupdf), f'Not a directory: {_mupdf=}'\n                env_extra['PYMUPDF_SETUP_MUPDF_BUILD'] = os.path.abspath(_mupdf)\n                mupdf_sync = _mupdf\n        \n        elif arg == '--mupdf-clean':\n                env_extra['PYMUPDF_SETUP_MUPDF_CLEAN']=next(args)\n        \n        elif arg in ('-M', '--build-mupdf'):\n            env_extra['PYMUPDF_SETUP_MUPDF_REBUILD'] = next(args)\n        \n        elif arg == '-o':\n            os_names += next(args).split(',')\n        \n        elif arg == '-p':\n            pytest_options += f' {next(args)}'\n        \n        elif arg == '-P':\n            system_packages = int(next(args))\n        \n        elif arg == '--pybind':\n            pybind = int(next(args))\n        \n        elif arg == '--pyodide-build-version':\n            pyodide_build_version = next(args)\n        \n        elif arg == '-s':\n            _value = next(args)\n            assert _value in ('0', '1'), f'`-s` must be followed by `0` or `1`, not {_value=}.'\n            env_extra['PYMUPDF_SETUP_PY_LIMITED_API'] = _value\n        \n        elif arg == '--show-args':\n            show_args = 1\n        elif arg == '--sync-paths':\n            sync_paths = next(args)\n        \n        elif arg == '--system-site-packages':\n            system_site_packages = int(next(args))\n        \n        elif arg == '--swig':\n            swig = next(args)\n        \n        elif arg == '--swig-quick':\n            swig_quick = int(next(args))\n        \n        elif arg == '-t':\n            test_names += next(args).split(',')\n        \n        elif arg == '--timeout':\n            test_timeout = float(next(args))\n        \n        elif arg == '-T':\n            pytest_prefix = next(args)\n            assert pytest_prefix in ('gdb', 'helgrind', 'valgrind'), \\\n                    f'Unrecognised {pytest_prefix=}, should be one of: gdb valgrind helgrind.'\n        \n        elif arg == '-v':\n            venv = int(next(args))\n            assert venv in (0, 1, 2, 3), f'Invalid {venv=} should be 0, 1, 2 or 3.'\n        \n        elif arg in ('build', 'cibw', 'install', 'pyodide', 'test', 'wheel'):\n            commands.append(arg)\n        \n        elif arg == 'buildtest':\n            commands += ['build', 'test']\n        \n        else:\n            assert 0, f'Unrecognised option/command: {arg=}.'\n    \n    # Handle special args --sync-paths, -h, -v, -o first.\n    #\n    if sync_paths:\n        # Print required files, directories and checkouts.\n        with open(sync_paths, 'w') as f:\n            print(pymupdf_dir, file=f)\n            if mupdf_sync:\n                print(mupdf_sync, file=f)\n        return\n\n    if show_help:\n        print(__doc__)\n        return\n    \n    if show_args:\n        print(f'sys.argv ({len(sys.argv)}):')\n        for arg in sys.argv:\n            print(f'    {arg!r}')\n        return\n    \n    if os_names:\n        if platform.system().lower() not in os_names:\n            log(f'Not running because {platform.system().lower()=} not in {os_names=}')\n            return\n    \n    if commands:\n        if venv:\n            # Rerun ourselves inside a venv if not already in a venv.\n            if not venv_in():\n                if graal:\n                    if 'cibw' in commands:\n                        # We don't create graal/pyenv so wheel/build commands\n                        # will not work.\n                        assert 'wheel' not in commands\n                        assert 'build' not in commands\n                if graal and 'cibw' not in commands:\n                    # 2025-07-24: We need the latest pyenv.\n                    graalpy = 'graalpy-24.2.1'\n                    venv_name = f'venv-pymupdf-{graalpy}'\n                    pyenv_dir = f'{pymupdf_dir_abs}/pyenv-git'\n                    os.environ['PYENV_ROOT'] = pyenv_dir\n                    os.environ['PATH'] = f'{pyenv_dir}/bin:{os.environ[\"PATH\"]}'\n                    os.environ['PIPCL_GRAAL_PYTHON'] = sys.executable\n                    \n                    if venv >= 3:\n                        shutil.rmtree(venv_name, ignore_errors=1)\n                    if venv == 1 and os.path.exists(pyenv_dir) and os.path.exists(venv_name):\n                        log(f'{venv=} and {venv_name=} already exists so not building pyenv or creating venv.')\n                    else:\n                        pipcl.git_get(pyenv_dir, remote='https://github.com/pyenv/pyenv.git', branch='master')\n                        run(f'cd {pyenv_dir} && src/configure && make -C src')\n                        run(f'which pyenv')\n                        run(f'pyenv install -v -s {graalpy}')\n                        run(f'{pyenv_dir}/versions/{graalpy}/bin/graalpy -m venv {venv_name}')\n                    e = run(f'. {venv_name}/bin/activate && python {shlex.join(sys.argv)}',\n                            check=False,\n                            )\n                else:\n                    venv_name = f'venv-pymupdf-{platform.python_version()}-{int.bit_length(sys.maxsize+1)}'\n                    e = venv_run(\n                            sys.argv,\n                            venv_name,\n                            recreate=(venv>=2),\n                            clean=(venv>=3),\n                            )\n                sys.exit(e)\n    else:\n        log(f'Warning, no commands specified so nothing to do.')\n    \n    # Clone/update/build swig if specified.\n    swig_binary = pipcl.swig_get(swig, swig_quick)\n    if swig_binary:\n        os.environ['PYMUPDF_SETUP_SWIG'] = swig_binary\n    \n    # Handle commands.\n    #\n    have_installed = False\n    for command in commands:\n        log(f'### {command=}.')\n        if 0:\n            pass\n        \n        elif command in ('build', 'wheel'):\n            build(\n                    env_extra,\n                    build_isolation=build_isolation,\n                    venv=venv,\n                    wheel=(command=='wheel'),\n                    )\n            have_installed = True\n        \n        elif command == 'cibw':\n            # Build wheel(s) with cibuildwheel.\n            \n            if platform.system() == 'Linux':\n                PYMUPDF_SETUP_MUPDF_BUILD = env_extra.get('PYMUPDF_SETUP_MUPDF_BUILD')\n                if PYMUPDF_SETUP_MUPDF_BUILD and not PYMUPDF_SETUP_MUPDF_BUILD.startswith('git:'):\n                    assert PYMUPDF_SETUP_MUPDF_BUILD.startswith('/')\n                    env_extra['PYMUPDF_SETUP_MUPDF_BUILD'] = f'/host/{PYMUPDF_SETUP_MUPDF_BUILD}'\n            \n            cibuildwheel(\n                    env_extra,\n                    cibw_name or 'cibuildwheel',\n                    cibw_pyodide,\n                    cibw_pyodide_version,\n                    cibw_sdist,\n                    cibw_test_project,\n                    cibw_test_project_setjmp,\n                    cibw_skip_add_defaults,\n                    graal,\n                    )\n        \n        elif command == 'install':\n            p = 'pymupdf'\n            if install_version:\n                if install_version.endswith('.whl'):\n                    p = install_version\n                elif install_version.startswith(('==', '>=', '>')):\n                    p = f'{p}{install_version}'\n                else:\n                    p = f'{p}=={install_version}'\n            run(f'pip install --force-reinstall {p}')\n            have_installed = True\n        \n        elif command == 'test':\n            if not have_installed:\n                log(f'## Warning: have not built/installed PyMuPDF; testing whatever is already installed.')\n            test(\n                    env_extra=env_extra,\n                    implementations=implementations,\n                    test_names=test_names,\n                    pytest_options=pytest_options,\n                    test_timeout=test_timeout,\n                    pytest_prefix=pytest_prefix,\n                    test_fitz=test_fitz,\n                    pybind=pybind,\n                    system_packages=system_packages,\n                    venv=venv,\n                    )\n        \n        elif command == 'pyodide':\n            build_pyodide_wheel(pyodide_build_version=pyodide_build_version)\n        \n        else:\n            assert 0, f'{command=}'\n\n\ndef get_env_bool(name, default=0):\n    v = os.environ.get(name)\n    if v in ('1', 'true'):\n        return 1\n    elif v in ('0', 'false'):\n        return 0\n    elif v is None:\n        return default\n    else:\n        assert 0, f'Bad environ {name=} {v=}'\n\ndef show_help():\n    print(__doc__)\n    print(venv_info())\n\n\ndef github_workflow_unimportant():\n    '''\n    Returns true if we are running a Github scheduled workflow but in a\n    repository not called 'PyMuPDF'. This can be used to avoid consuming\n    unnecessary Github minutes running workflows on non-main repositories such\n    as ArtifexSoftware/PyMuPDF-julian.\n    '''\n    GITHUB_EVENT_NAME = os.environ.get('GITHUB_EVENT_NAME')\n    GITHUB_REPOSITORY = os.environ.get('GITHUB_REPOSITORY')\n    if GITHUB_EVENT_NAME == 'schedule' and GITHUB_REPOSITORY != 'pymupdf/PyMuPDF':\n            log(f'## This is an unimportant Github workflow: a scheduled event, not in the main repository `pymupdf/PyMuPDF`.')\n            log(f'## {GITHUB_EVENT_NAME=}.')\n            log(f'## {GITHUB_REPOSITORY=}.')\n            return True\n\ndef venv_info(pytest_args=None):\n    '''\n    Returns string containing information about the venv we use and how to\n    run tests manually. If specified, `pytest_args` contains the pytest args,\n    otherwise we use an example.\n    '''\n    pymupdf_dir_rel = gh_release.relpath(pymupdf_dir)\n    ret = f'Name of venv: {gh_release.venv_name}\\n'\n    if pytest_args is None:\n        pytest_args = f'{pymupdf_dir_rel}/tests/test_general.py::test_subset_fonts'\n    if platform.system() == 'Windows':\n        ret += textwrap.dedent(f'''\n                Rerun tests manually with rebased implementation:\n                    Enter venv:\n                        {gh_release.venv_name}\\\\Scripts\\\\activate\n                    Run specific test in venv:\n                        {gh_release.venv_name}\\\\Scripts\\\\python -m pytest {pytest_args}\n                ''')\n    else:\n        ret += textwrap.dedent(f'''\n                Rerun tests manually with rebased implementation:\n                    Enter venv and run specific test, also under gdb:\n                        . {gh_release.venv_name}/bin/activate\n                        python -m pytest {pytest_args}\n                        gdb --args python -m pytest {pytest_args}\n                    Run without explicitly entering venv, also under gdb:\n                        ./{gh_release.venv_name}/bin/python -m pytest {pytest_args}\n                        gdb --args ./{gh_release.venv_name}/bin/python -m pytest {pytest_args}\n                ''')\n    return ret\n\n\ndef build(\n        env_extra,\n        *,\n        build_isolation,\n        venv,\n        wheel,\n        ):\n    log(f'{build_isolation=}')\n    \n    if build_isolation is None:\n        # On OpenBSD libclang is not available on pypi.org, so we need to force\n        # use of system package py3-llvm with --no-build-isolation, manually\n        # installing other required packages.\n        build_isolation = False if platform.system() == 'OpenBSD' else True\n    \n    if build_isolation:\n        # This is the default on non-OpenBSD.\n        build_isolation_text = ''\n    else:\n        # Not using build isolation - i.e. pip will not be using its own clean\n        # venv, so we need to explicitly install required packages.  Manually\n        # install required packages from pyproject.toml.\n        sys.path.insert(0, os.path.abspath(f'{__file__}/../..'))\n        import setup\n        names = setup.get_requires_for_build_wheel()\n        del sys.path[0]\n        if names:\n            names = ' '.join(names)\n            if venv == 2:\n                run( f'python -m pip install --upgrade {names}')\n            else:\n                log(f'{venv=}: Not installing packages with pip: {names}')\n        build_isolation_text = ' --no-build-isolation'\n    \n    if wheel:\n        new_files = pipcl.NewFiles(f'wheelhouse/*.whl')\n        run(f'pip wheel{build_isolation_text} -w wheelhouse -v {pymupdf_dir_abs}', env_extra=env_extra)\n        wheel = new_files.get_one()\n        run(f'pip install --force-reinstall {wheel}')\n    else:\n        run(f'pip install{build_isolation_text} -v --force-reinstall {pymupdf_dir_abs}', env_extra=env_extra)\n\n\ndef cibuildwheel(\n        env_extra,\n        cibw_name,\n        cibw_pyodide,\n        cibw_pyodide_version,\n        cibw_sdist,\n        cibw_test_project,\n        cibw_test_project_setjmp,\n        cibw_skip_add_defaults,\n        graal,\n        ):\n    \n    if cibw_sdist and platform.system() == 'Linux':\n        log(f'Building sdist.')\n        run(f'cd {pymupdf_dir_abs} && {sys.executable} setup.py -d wheelhouse sdist', env_extra=env_extra)\n        sdists = glob.glob(f'{pymupdf_dir_abs}/wheelhouse/pymupdf-*.tar.gz')\n        log(f'{sdists=}')\n        assert sdists\n    \n    run(f'pip install --upgrade --force-reinstall {cibw_name}')\n\n    # Some general flags.\n    if 'CIBW_BUILD_VERBOSITY' not in env_extra:\n        env_extra['CIBW_BUILD_VERBOSITY'] = '1'\n    \n    # Add default flags to CIBW_SKIP.\n    # 2025-10-07: `cp3??t-*` excludes free-threading, which currently breaks\n    # some tests.\n    \n    if cibw_skip_add_defaults:\n        CIBW_SKIP = env_extra.get('CIBW_SKIP', '')\n        CIBW_SKIP += ' *i686 *musllinux* *-win32 *-aarch64 cp3??t-*'\n        CIBW_SKIP = CIBW_SKIP.split()\n        CIBW_SKIP = sorted(list(set(CIBW_SKIP)))\n        CIBW_SKIP = ' '.join(CIBW_SKIP)\n        env_extra['CIBW_SKIP'] = CIBW_SKIP\n    \n    # Set what wheels to build, if not already specified.\n    if 'CIBW_ARCHS' not in env_extra:\n        if 'CIBW_ARCHS_WINDOWS' not in env_extra:\n            env_extra['CIBW_ARCHS_WINDOWS'] = 'auto64'\n\n        if 'CIBW_ARCHS_MACOS' not in env_extra:\n            env_extra['CIBW_ARCHS_MACOS'] = 'auto64'\n\n        if 'CIBW_ARCHS_LINUX' not in env_extra:\n            env_extra['CIBW_ARCHS_LINUX'] = 'auto64'\n\n    # Tell cibuildwheel not to use `auditwheel` on Linux and MacOS,\n    # because it cannot cope with us deliberately having required\n    # libraries in different wheel - specifically in the PyMuPDF wheel.\n    #\n    # We cannot use a subset of auditwheel's functionality\n    # with `auditwheel addtag` because it says `No tags\n    # to be added` and terminates with non-zero. See:\n    # https://github.com/pypa/auditwheel/issues/439.\n    #\n    env_extra['CIBW_REPAIR_WHEEL_COMMAND_LINUX'] = ''\n    env_extra['CIBW_REPAIR_WHEEL_COMMAND_MACOS'] = ''\n\n    # Tell cibuildwheel how to test PyMuPDF.\n    if 'CIBW_TEST_COMMAND' not in env_extra:\n        env_extra['CIBW_TEST_COMMAND'] = f'python {{project}}/scripts/test.py test'\n\n    # Specify python versions.\n    CIBW_BUILD = env_extra.get('CIBW_BUILD')\n    log(f'{CIBW_BUILD=}')\n    if CIBW_BUILD is None:\n        if graal:\n            CIBW_BUILD = 'gp*'\n            env_extra['CIBW_ENABLE'] = 'graalpy'\n        elif cibw_pyodide:\n            # Using python-3.13 fixes problems with MuPDF's setjmp/longjmp.\n            CIBW_BUILD = 'cp313*'\n        elif os.environ.get('GITHUB_ACTIONS') == 'true':\n            # Build/test all supported Python versions.\n            CIBW_BUILD = cibw_cp(*python_versions_minor)\n        else:\n            # Build/test current Python only.\n            v = platform.python_version_tuple()[:2]\n            log(f'{v=}')\n            CIBW_BUILD = f'cp{\"\".join(v)}*'\n        log(f'Defaulting to {CIBW_BUILD=}.')\n    \n    cibw_pyodide_args = ''\n    if cibw_pyodide:\n        cibw_pyodide_args = ' --platform pyodide'\n        env_extra['HAVE_LIBCRYPTO'] = 'no'\n        env_extra['PYMUPDF_SETUP_MUPDF_TESSERACT'] = '0'\n    if cibw_pyodide_version:\n        # 2025-07-21: there is no --pyodide-version option so we set\n        # CIBW_PYODIDE_VERSION.\n        env_extra['CIBW_PYODIDE_VERSION'] = cibw_pyodide_version\n        env_extra['CIBW_ENABLE'] = 'pyodide-prerelease'\n\n    # Pass all the environment variables we have set, to Linux docker. Note\n    # that this will miss any settings in the original environment. We have to\n    # add CIBW_BUILD explicitly because we haven't set it yet.\n    CIBW_ENVIRONMENT_PASS_LINUX = set(env_extra.keys())\n    CIBW_ENVIRONMENT_PASS_LINUX.add('CIBW_BUILD')\n    CIBW_ENVIRONMENT_PASS_LINUX = sorted(list(CIBW_ENVIRONMENT_PASS_LINUX))\n    CIBW_ENVIRONMENT_PASS_LINUX = ' '.join(CIBW_ENVIRONMENT_PASS_LINUX)\n    env_extra['CIBW_ENVIRONMENT_PASS_LINUX'] = CIBW_ENVIRONMENT_PASS_LINUX\n    \n    if cibw_test_project:\n        cibw_do_test_project(\n                env_extra,\n                CIBW_BUILD,\n                cibw_pyodide,\n                cibw_pyodide_args,\n                cibw_test_project_setjmp,\n                )\n        return\n    \n    env_extra['CIBW_BUILD'] = CIBW_BUILD\n    run(f'cd {pymupdf_dir} && cibuildwheel{cibw_pyodide_args}', env_extra=env_extra, prefix='cibw: ')\n    run(f'ls -ld {pymupdf_dir}/wheelhouse/*')\n\n\ndef cibw_do_test_project(\n        env_extra,\n        CIBW_BUILD,\n        cibw_pyodide,\n        cibw_pyodide_args,\n        cibw_test_project_setjmp,\n        ):\n    testdir = f'{pymupdf_dir_abs}/cibw_test'\n    shutil.rmtree(testdir, ignore_errors=1)\n    os.mkdir(testdir)\n    with open(f'{testdir}/setup.py', 'w') as f:\n        f.write(textwrap.dedent(f'''\n                import shutil\n                import sys\n                import os\n                import pipcl\n\n                def build():\n                    so_leaf = pipcl.build_extension(\n                            name = 'foo',\n                            path_i = 'foo.i',\n                            outdir = 'build',\n                            source_extra = 'qwerty.cpp',\n                            py_limited_api = True,\n                            )\n                    \n                    return [\n                            ('build/foo.py', 'foo/__init__.py'),\n                            (f'build/{{so_leaf}}', f'foo/'),\n                            ]\n\n                p = pipcl.Package(\n                        name = 'pymupdf-test',\n                        version = '1.2.3',\n                        fn_build = build,\n                        py_limited_api=True,\n                        )\n\n                def get_requires_for_build_wheel(config_settings=None):\n                    return ['swig']\n                \n                build_wheel = p.build_wheel\n                build_sdist = p.build_sdist\n                \n                # Handle old-style setup.py command-line usage:\n                if __name__ == '__main__':\n                    p.handle_argv(sys.argv)\n                '''))\n    with open(f'{testdir}/foo.i', 'w') as f:\n        if cibw_test_project_setjmp:\n            f.write(textwrap.dedent('''\n                    %{\n                    #include <stdexcept>\n\n                    #include <assert.h>\n                    #include <setjmp.h>\n                    #include <stdio.h>\n                    #include <string.h>\n\n                    int qwerty(void);\n\n                    static sigjmp_buf jmpbuf;\n                    static int bar0(const char* text)\n                    {\n                        printf(\"bar0(): text: %s\\\\n\", text);\n\n                        int q = qwerty();\n                        printf(\"bar0(): q=%i\\\\n\", q);\n\n                        int len = (int) strlen(text);\n                        printf(\"bar0(): len=%i\\\\n\", len);\n                        printf(\"bar0(): calling longjmp().\\\\n\");\n                        fflush(stdout);\n                        longjmp(jmpbuf, 1);\n                        assert(0);\n                    }\n                    int bar1(const char* text)\n                    {\n                        int ret = 0;\n                        if (setjmp(jmpbuf) == 0)\n                        {\n                            ret = bar0(text);\n                        }\n                        else\n                        {\n                            printf(\"bar1(): setjmp() returned non-zero.\\\\n\");\n                            throw std::runtime_error(\"deliberate exception\");\n                        }\n                        assert(0);\n                    }\n                    int bar(const char* text)\n                    {\n                        int ret = 0;\n                        try\n                        {\n                            ret = bar1(text);\n                        }\n                        catch(std::exception& e)\n                        {\n                            printf(\"bar1(): received exception: %s\\\\n\", e.what());\n                        }\n                        return ret;\n                    }\n                    %}\n                    int bar(const char* text);\n                    '''))\n        else:\n            f.write(textwrap.dedent('''\n                    %{\n                    #include <stdexcept>\n\n                    #include <assert.h>\n                    #include <stdio.h>\n                    #include <string.h>\n\n                    int qwerty(void);\n\n                    int bar(const char* text)\n                    {\n                        qwerty();\n                        return strlen(text);\n                    }\n                    %}\n                    int bar(const char* text);\n                    '''))\n    \n    with open(f'{testdir}/qwerty.cpp', 'w') as f:\n        f.write(textwrap.dedent('''\n                #include <stdio.h>\n                int qwerty(void)\n                {\n                    printf(\"qwerty()\\\\n\");\n                    return 3;\n                }\n                '''))\n\n    with open(f'{testdir}/pyproject.toml', 'w') as f:\n        f.write(textwrap.dedent('''\n                [build-system]\n                    requires = ['pipcl']\n                    build-backend = 'setup'\n                    backend-path = ['.']\n                '''))\n        \n    shutil.copy2(f'{pymupdf_dir_abs}/pipcl.py', f'{testdir}/pipcl.py')\n    shutil.copy2(f'{pymupdf_dir_abs}/wdev.py', f'{testdir}/wdev.py')\n\n    env_extra['CIBW_BUILD'] = CIBW_BUILD\n    CIBW_TEST_COMMAND = ''\n    if cibw_pyodide:\n        CIBW_TEST_COMMAND += 'pyodide xbuildenv search --all; '\n    CIBW_TEST_COMMAND += 'python -c \"import foo; foo.bar(\\\\\"some text\\\\\")\"'\n    env_extra['CIBW_TEST_COMMAND'] = CIBW_TEST_COMMAND\n    #env_extra['CIBW_TEST_COMMAND'] = ''\n    \n    run(f'cd {testdir} && cibuildwheel --output-dir ../wheelhouse{cibw_pyodide_args}',\n            env_extra=env_extra,\n            prefix='cibw: ',\n            )\n    run(f'ls -ldt {pymupdf_dir_abs}/wheelhouse/*')\n        \n\ndef build_pyodide_wheel(pyodide_build_version=None):\n    '''\n    Build Pyodide wheel.\n\n    This runs `pyodide build` inside the PyMuPDF directory, which in turn runs\n    setup.py in a Pyodide build environment.\n    '''\n    log(f'## Building Pyodide wheel.')\n\n    # Our setup.py does not know anything about Pyodide; we set a few\n    # required environmental variables here.\n    #\n    env_extra = dict()\n\n    # Disable libcrypto because not available in Pyodide.\n    env_extra['HAVE_LIBCRYPTO'] = 'no'\n\n    # Tell MuPDF to build for Pyodide.\n    env_extra['OS'] = 'pyodide'\n\n    # Build a single wheel without a separate PyMuPDFb wheel.\n    env_extra['PYMUPDF_SETUP_FLAVOUR'] = 'pb'\n    \n    # 2023-08-30: We set PYMUPDF_SETUP_MUPDF_BUILD_TESSERACT=0 because\n    # otherwise mupdf thirdparty/tesseract/src/ccstruct/dppoint.cpp fails to\n    # build because `#include \"errcode.h\"` finds a header inside emsdk. This is\n    # pyodide bug https://github.com/pyodide/pyodide/issues/3839. It's fixed in\n    # https://github.com/pyodide/pyodide/pull/3866 but the fix has not reached\n    # pypi.org's pyodide-build package. E.g. currently in tag 0.23.4, but\n    # current devuan pyodide-build is pyodide_build-0.23.4.\n    #\n    env_extra['PYMUPDF_SETUP_MUPDF_TESSERACT'] = '0'\n    setup = pyodide_setup(pymupdf_dir, pyodide_build_version=pyodide_build_version)\n    command = f'{setup} && echo \"### Running pyodide build\" && pyodide build --exports whole_archive'\n    \n    command = command.replace(' && ', '\\n && ')\n    \n    run(command, env_extra=env_extra)\n    \n    # Copy wheel into `wheelhouse/` so it is picked up as a workflow\n    # artifact.\n    #\n    run(f'ls -l {pymupdf_dir}/dist/')\n    run(f'mkdir -p {pymupdf_dir}/wheelhouse && cp -p {pymupdf_dir}/dist/* {pymupdf_dir}/wheelhouse/')\n    run(f'ls -l {pymupdf_dir}/wheelhouse/')    \n\n\ndef pyodide_setup(\n        directory,\n        clean=False,\n        pyodide_build_version=None,\n        ):\n    '''\n    Returns a command that will set things up for a pyodide build.\n    \n    Args:\n        directory:\n            Our command cd's into this directory.\n        clean:\n            If true we create an entirely new environment. Otherwise\n            we reuse any existing emsdk repository and venv.\n        pyodide_build_version:\n            Version of Python package pyodide-build; if None we use latest\n            available version.\n            2025-02-13: pyodide_build_version='0.29.3' works.\n    \n    The returned command does the following:\n    \n    * Checkout latest emsdk from https://github.com/emscripten-core/emsdk.git:\n      * Clone emsdk repository to `emsdk` if not already present.\n      * Run `git pull -r` inside emsdk checkout.\n    * Create venv `venv_pyodide_<python_version>` if not already present.\n    * Activate venv `venv_pyodide_<python_version>`.\n    * Install/upgrade package `pyodide-build`.\n    * Run emsdk install scripts and enter emsdk environment.\n    \n    Example usage in a build function:\n    \n        command = pyodide_setup()\n        command += ' && pyodide build --exports pyinit'\n        subprocess.run(command, shell=1, check=1)\n    '''\n    \n    pv = platform.python_version_tuple()[:2]\n    assert pv == ('3', '12'), f'Pyodide builds need to be run with Python-3.12 but current Python is {platform.python_version()}.'\n    command = f'cd {directory}'\n    \n    # Clone/update emsdk. We always use the latest emsdk with `git pull`.\n    #\n    # 2025-02-13: this works: 2514ec738de72cebbba7f4fdba0cf2fabcb779a5\n    #\n    dir_emsdk = 'emsdk'\n    if clean:\n        shutil.rmtree(dir_emsdk, ignore_errors=1)\n        # 2024-06-25: old `.pyodide-xbuildenv` directory was breaking build, so\n        # important to remove it here.\n        shutil.rmtree('.pyodide-xbuildenv', ignore_errors=1)\n    if not os.path.exists(f'{directory}/{dir_emsdk}'):\n        command += f' && echo \"### Cloning emsdk.git\"'\n        command += f' && git clone https://github.com/emscripten-core/emsdk.git {dir_emsdk}'\n    command += f' && echo \"### Updating checkout {dir_emsdk}\"'\n    command += f' && (cd {dir_emsdk} && git pull -r)'\n    command += f' && echo \"### Checkout {dir_emsdk} is:\"'\n    command += f' && (cd {dir_emsdk} && git show -s --oneline)'\n    \n    # Create and enter Python venv.\n    #\n    python = sys.executable\n    venv_pyodide = f'venv_pyodide_{sys.version_info[0]}.{sys.version_info[1]}'\n    \n    if not os.path.exists( f'{directory}/{venv_pyodide}'):\n        command += f' && echo \"### Creating venv {venv_pyodide}\"'\n        command += f' && {python} -m venv {venv_pyodide}'\n    command += f' && . {venv_pyodide}/bin/activate'\n    command += f' && echo \"### Installing Python packages.\"'\n    command += f' && python -m pip install --upgrade pip wheel pyodide-build'\n    if pyodide_build_version:\n        command += f'=={pyodide_build_version}'\n    \n    # Run emsdk install scripts and enter emsdk environment.\n    #\n    command += f' && cd {dir_emsdk}'\n    command += ' && PYODIDE_EMSCRIPTEN_VERSION=$(pyodide config get emscripten_version)'\n    command += ' && echo \"### PYODIDE_EMSCRIPTEN_VERSION is: $PYODIDE_EMSCRIPTEN_VERSION\"'\n    command += ' && echo \"### Running ./emsdk install\"'\n    command += ' && ./emsdk install ${PYODIDE_EMSCRIPTEN_VERSION}'\n    command += ' && echo \"### Running ./emsdk activate\"'\n    command += ' && ./emsdk activate ${PYODIDE_EMSCRIPTEN_VERSION}'\n    command += ' && echo \"### Running ./emsdk_env.sh\"'\n    command += ' && . ./emsdk_env.sh'   # Need leading `./` otherwise weird 'Not found' error.\n    \n    command += ' && cd ..'\n    return command\n\n\ndef test(\n        *,\n        env_extra,\n        implementations,\n        venv=False,\n        test_names=None,\n        pytest_options=None,\n        test_timeout=None,\n        pytest_prefix=None,\n        test_fitz=True,\n        pytest_k=None,\n        pybind=False,\n        system_packages=False,\n        ):\n    if pybind:\n        cpp_path = 'pymupdf_test_pybind.cpp'\n        cpp_exe = 'pymupdf_test_pybind.exe'\n        cpp = textwrap.dedent('''\n                #include <pybind11/embed.h>\n                \n                int main()\n                {\n                    pybind11::scoped_interpreter guard{};\n                    pybind11::exec(R\"(\n                            print('Hello world', flush=1)\n                            import pymupdf\n                            pymupdf.JM_mupdf_show_warnings = 1\n                            print(f'{pymupdf.version=}', flush=1)\n                            doc = pymupdf.Document()\n                            pymupdf.mupdf.fz_warn('Dummy warning.')\n                            pymupdf.mupdf.fz_warn('Dummy warning.')\n                            pymupdf.mupdf.fz_warn('Dummy warning.')\n                            print(f'{doc=}', flush=1)\n                            )\");\n                }\n                ''')\n        def fs_read(path):\n            try:\n                with open(path) as f:\n                    return f.read()\n            except Exception:\n                return\n        def fs_remove(path):\n            try:\n                os.remove(path)\n            except Exception:\n                pass\n        cpp_existing = fs_read(cpp_path)\n        if cpp == cpp_existing:\n            log(f'Not creating {cpp_exe} because unchanged: {cpp_path}')\n        else:\n            with open(cpp_path, 'w') as f:\n                f.write(cpp)\n        def getmtime(path):\n            try:\n                return os.path.getmtime(path)\n            except Exception:\n                return 0\n        python_config = f'{os.path.realpath(sys.executable)}-config'\n        # `--embed` adds `-lpython3.11` to the link command, which appears to\n        # be necessary when building an executable.\n        flags = run(f'{python_config} --cflags --ldflags --embed', capture=1)\n        build_command = f'c++ {cpp_path} -o {cpp_exe} -g -W -Wall {flags}'\n        build_path = f'{cpp_exe}.cmd'\n        build_command_prev = fs_read(build_path)\n        if build_command != build_command_prev or getmtime(cpp_path) >= getmtime(cpp_exe):\n            fs_remove(build_path)\n            run(build_command)\n            with open(build_path, 'w') as f:\n                f.write(build_command)\n        run(f'./{cpp_exe}')\n        return\n    \n    pymupdf_dir_rel = gh_release.relpath(pymupdf_dir)\n    if not pytest_options and pytest_prefix == 'valgrind':\n        pytest_options = '-sv'\n    if pytest_k:\n        pytest_options += f' -k {shlex.quote(pytest_k)}'\n    pytest_arg = ''\n    if test_names:\n        for test_name in test_names:\n            pytest_arg += f' {pymupdf_dir_rel}/{test_name}'\n    else:\n        pytest_arg += f' {pymupdf_dir_rel}/tests'\n    python = gh_release.relpath(sys.executable)\n    log('Running tests with tests/run_compound.py and pytest.')\n    \n    PYODIDE_ROOT = os.environ.get('PYODIDE_ROOT')\n    if PYODIDE_ROOT is not None:\n        # We can't install packages with `pip install`; setup.py will have\n        # specified pytest in the wheels's <requires_dist>, so it will be\n        # already installed.\n        #\n        log(f'Not installing test packages because {PYODIDE_ROOT=}.')\n        command = f'{pytest_options} {pytest_arg}'\n        args = shlex.split(command)\n        log(f'{PYODIDE_ROOT=} so calling pytest.main(args).')\n        log(f'{command=}')\n        log(f'args are ({len(args)}):')\n        for arg in args:\n            log(f'    {arg!r}')\n        import pytest\n        e = pytest.main(args)\n        assert e == 0, f'pytest.main() failed: {e=}'\n        return\n    \n    if venv >= 2:\n        run(f'pip install --upgrade {gh_release.test_packages}')\n    else:\n        log(f'{venv=}: Not installing test packages: {gh_release.test_packages}')\n    run_compound_args = ''\n    \n    if implementations:\n        run_compound_args += f' -i {implementations}'\n    \n    if test_timeout:\n        run_compound_args += f' -t {test_timeout}'\n\n    if pytest_prefix in ('valgrind', 'helgrind'):\n        if system_packages:\n            log('Installing valgrind.')\n            run(f'sudo apt update')\n            run(f'sudo apt install --upgrade valgrind')\n        run(f'valgrind --version')\n\n    command = f'{python} {pymupdf_dir_rel}/tests/run_compound.py{run_compound_args}'\n    \n    if pytest_prefix is None:\n        pass\n    elif pytest_prefix == 'gdb':\n        command += ' gdb --args'\n    elif pytest_prefix == 'valgrind':\n        env_extra['PYMUPDF_RUNNING_ON_VALGRIND'] = '1'\n        env_extra['PYTHONMALLOC'] = 'malloc'\n        command += (\n                    f' valgrind'\n                    f' --suppressions={pymupdf_dir_abs}/valgrind.supp'\n                    f' --trace-children=no'\n                    f' --num-callers=20'\n                    f' --error-exitcode=100'\n                    f' --errors-for-leak-kinds=none'\n                    f' --fullpath-after='\n                    )\n    elif pytest_prefix == 'helgrind':\n        env_extra['PYMUPDF_RUNNING_ON_VALGRIND'] = '1'\n        env_extra['PYTHONMALLOC'] = 'malloc'\n        command = (\n                f' valgrind'\n                f' --tool=helgrind'\n                f' --trace-children=no'\n                f' --num-callers=20'\n                f' --error-exitcode=100'\n                f' --fullpath-after='\n                )\n    else:\n        assert 0, f'Unrecognised {pytest_prefix=}'\n\n    if platform.system() == 'Windows':\n        # `python -m pytest` doesn't seem to work.\n        command += ' pytest'\n    else:\n        # On OpenBSD `pip install pytest` doesn't seem to install the pytest\n        # command, so we use `python -m pytest ...`.\n        command += f' {python} -m pytest'\n\n    command += f' {pytest_options} {pytest_arg}'\n\n    # Always start by removing any test_*_fitz.py files.\n    for p in glob.glob(f'{pymupdf_dir_rel}/tests/test_*_fitz.py'):\n        log(f'Removing {p=}')\n        os.remove(p)\n    if test_fitz:\n        # Create copies of each test file, modified to use `pymupdf`\n        # instead of `fitz`.\n        for p in glob.glob(f'{pymupdf_dir_rel}/tests/test_*.py'):\n            if os.path.basename(p).startswith('test_fitz_'):\n                # Don't recursively generate test_fitz_fitz_foo.py,\n                # test_fitz_fitz_fitz_foo.py, ... etc.\n                continue\n            branch, leaf = os.path.split(p)\n            p2 = f'{branch}/{leaf[:5]}fitz_{leaf[5:]}'\n            log(f'Converting {p=} to {p2=}.')\n            with open(p, encoding='utf8') as f:\n                text = f.read()\n            text2 = re.sub(\"([^\\'])\\\\bpymupdf\\\\b\", '\\\\1fitz', text)\n            if p.replace(os.sep, '/') == f'{pymupdf_dir_rel}/tests/test_docs_samples.py'.replace(os.sep, '/'):\n                assert text2 == text\n            else:\n                assert text2 != text, f'Unexpectedly unchanged when creating {p!r} => {p2!r}'\n            with open(p2, 'w', encoding='utf8') as f:\n                f.write(text2)\n    try:\n        log(f'Running tests with tests/run_compound.py and pytest.')\n        run(command, env_extra=env_extra, timeout=test_timeout)\n        \n    except subprocess.TimeoutExpired as e:\n         log(f'Timeout when running tests.')\n         raise\n    finally:\n        log(f'\\n'\n                f'[As of 2024-10-10 we get warnings from pytest/Python such as:\\n'\n                f'    DeprecationWarning: builtin type SwigPyPacked has no __module__ attribute\\n'\n                f'This seems to be due to Swig\\'s handling of Py_LIMITED_API.\\n'\n                f'For details see https://github.com/swig/swig/issues/2881.\\n'\n                f']'\n                )\n        log('\\n' + venv_info(pytest_args=f'{pytest_options} {pytest_arg}'))\n\n\ndef get_pyproject_required(ppt=None):\n    '''\n    Returns list of names of required packages in pyproject.toml.  We\n    do not do a proper parse and rely on the packages being in a single line.\n    '''\n    if ppt is None:\n        ppt = os.path.abspath(f'{__file__}/../../pyproject.toml')\n    with open(ppt) as f:\n        for line in f:\n            m = re.match('^ *requires = \\\\[(.*)\\\\]$', line)\n            if m:\n                names = m.group(1).replace(',', ' ').replace('\"', '').replace(\"'\", '')\n                names = names.split()\n                return names\n        else:\n            assert 0, f'Failed to find \"requires\" line in {ppt}'\n\ndef wrap_get_requires_for_build_wheel(dir_):\n    '''\n    Returns space-separated list of required\n    packages. Looks at `dir_`/pyproject.toml and calls\n    `dir_`/setup.py:get_requires_for_build_wheel().\n    '''\n    dir_abs = os.path.abspath(dir_)\n    ret = list()\n    ppt = os.path.join(dir_abs, 'pyproject.toml')\n    if os.path.exists(ppt):\n        ret += get_pyproject_required(ppt)\n    log(f'{ret=}')\n    if os.path.exists(os.path.join(dir_abs, 'setup.py')):\n        sys.path.insert(0, dir_abs)\n        try:\n            from setup import get_requires_for_build_wheel as foo\n            for i in foo():\n                ret.append(i)\n        finally:\n            del sys.path[0]\n    return ' '.join(ret)\n\n\ndef venv_in(path=None):\n    '''\n    If path is None, returns true if we are in a venv. Otherwise returns true\n    only if we are in venv <path>.\n    '''\n    if path:\n        return os.path.abspath(sys.prefix) == os.path.abspath(path)\n    else:\n        return sys.prefix != sys.base_prefix\n\n\ndef venv_run(args, path, recreate=True, clean=False):\n    '''\n    Runs command inside venv and returns termination code.\n    \n    Args:\n        args:\n            List of args.\n        path:\n            Name of venv.\n        recreate:\n            If false we do not run `<sys.executable> -m venv <path>` if <path>\n            already exists. This avoids a delay in the common case where <path>\n            is already set up, but fails if <path> exists but does not contain\n            a valid venv.\n        clean:\n            If true we first delete <path>.\n    '''\n    if clean:\n        log(f'Removing any existing venv {path}.')\n        assert path.startswith('venv-')\n        shutil.rmtree(path, ignore_errors=1)\n    if recreate or not os.path.isdir(path):\n        run(f'{sys.executable} -m venv {path}')\n    if platform.system() == 'Windows':\n        command = f'{path}\\\\Scripts\\\\activate && python'\n        # shlex not reliable on Windows.\n        # Use crude quoting with \"...\". Seems to work.\n        for arg in args:\n            assert '\"' not in arg\n            command += f' \"{arg}\"'\n    else:\n        command = f'. {path}/bin/activate && python {shlex.join(args)}'\n    e = run(command, check=0)\n    return e\n\n\nif __name__ == '__main__':\n    try:\n        sys.exit(main(sys.argv))\n    except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:\n        # Terminate relatively quietly, failed commands will usually have\n        # generated diagnostics.\n        log(f'{e}')\n        sys.exit(1)\n    # Other exceptions should not happen, and will generate a full Python\n    # backtrace etc here.\n"
  },
  {
    "path": "setup.py",
    "content": "#! /usr/bin/env python3\n\n'''\nOverview:\n\n    Build script for PyMuPDF, supporting PEP-517 and simple command-line usage.\n\n    We hard-code the URL of the MuPDF .tar.gz file that we require. This\n    generally points to a particular source release on mupdf.com.\n\n    Default behaviour:\n\n        Building an sdist:\n            As of 2024-002-28 we no longer download the MuPDF .tar.gz file and\n            embed it within the sdist. Instead it will be downloaded at build\n            time.\n\n        Building PyMuPDF:\n            We first download the hard-coded mupdf .tar.gz file.\n\n            Then we extract and build MuPDF locally, before building PyMuPDF\n            itself. So PyMuPDF will always be built with the exact MuPDF\n            release that we require.\n\n\nEnvironmental variables:\n\n    If building with system MuPDF (PYMUPDF_SETUP_MUPDF_BUILD is empty string):\n    \n        CFLAGS\n        CXXFLAGS\n        LDFLAGS\n            Added to c, c++, and link commands.\n        \n        PYMUPDF_INCLUDES\n            Colon-separated extra include paths.\n        \n        PYMUPDF_MUPDF_LIB\n            Directory containing MuPDF libraries, (libmupdf.so,\n            libmupdfcpp.so).\n    \n    PIPCL_SHOW_ENV\n        If '0', we do not show environment variables on startup.\n    \n    PYMUPDF_SETUP_DEVENV\n        Location of devenv.com on Windows. If unset we search for it - see\n        wdev.py. if that fails we use just 'devenv.com'.\n\n    PYMUPDF_SETUP_DUMMY\n        If 1, we build dummy sdist and wheel with no files.\n    \n    PYMUPDF_SETUP_FLAVOUR\n        Control building of separate wheels for PyMuPDF.\n        \n        Must be unset or a combination of 'p', 'b' and 'd'.\n        \n        Default is 'pbd'.\n        \n        'p':\n            Generated wheel contains PyMuPDF code.\n        'b':\n            Generated wheel contains MuPDF libraries; these are independent of\n            the Python version.\n        'd':\n            Generated wheel contains includes and libraries for MuPDF.\n        \n        If 'p' is included, the generated wheel is called PyMuPDF.\n        Otherwise if 'b' is included the generated wheel is called PyMuPDFb.\n        Otherwise if 'd' is included the generated wheel is called PyMuPDFd.\n        \n        For example:\n        \n            'pb': a `PyMuPDF` wheel with PyMuPDF runtime files and MuPDF\n            runtime shared libraries.\n            \n            'b': a `PyMuPDFb` wheel containing MuPDF runtime shared libraries.\n            \n            'pbd' a `PyMuPDF` wheel with PyMuPDF runtime files and MuPDF\n            runtime shared libraries, plus MuPDF build-time files (includes,\n            *.lib files on Windows).\n            \n            'd': a `PyMuPDFd` wheel containing MuPDF build-time files\n            (includes, *.lib files on Windows).\n    \n    PYMUPDF_SETUP_LIBCLANG\n        For internal testing.\n        \n    PYMUPDF_SETUP_MUPDF_BUILD\n        If unset or '-', use internal hard-coded default MuPDF location.\n        Otherwise overrides location of MuPDF when building PyMuPDF:\n            Empty string:\n                Build PyMuPDF with the system MuPDF.\n            A string starting with 'git:':\n                We use `git` commands to clone/update a local MuPDF checkout.\n                Should match `git:[--branch <branch>][--tag <tag>][<remote>]`.\n                If <remote> is omitted we use a default.\n                For example:\n                    PYMUPDF_SETUP_MUPDF_BUILD=\"git:--branch master\"\n                Passed as <text> arg to pipcl.git_get().\n            Otherwise:\n                Location of mupdf directory.\n    \n    PYMUPDF_SETUP_MUPDF_BSYMBOLIC\n        If '0' we do not link libmupdf.so with -Bsymbolic.\n    \n    PYMUPDF_SETUP_MUPDF_TESSERACT\n        If '0' we build MuPDF without Tesseract.\n    \n    PYMUPDF_SETUP_MUPDF_BUILD_TYPE\n        Unix only. Controls build type of MuPDF. Supported values are:\n            debug\n            memento\n            release (default)\n    \n    PYMUPDF_SETUP_FAKE_NOGIL\n        If '1' we (incorrectly) claim we are thread-safe.\n\n    PYMUPDF_SETUP_MUPDF_CLEAN\n        Unix only. If '1', we do a clean MuPDF build.\n\n    PYMUPDF_SETUP_MUPDF_REFCHECK_IF\n        Should be preprocessor statement to enable MuPDF reference count\n        checking.\n        \n        As of 2024-09-27, MuPDF default is `#ifndef NDEBUG`.\n\n    PYMUPDF_SETUP_MUPDF_TRACE_IF\n        Should be preprocessor statement to enable MuPDF runtime diagnostics in\n        response to environment variables such as MUPDF_trace.\n        \n        As of 2024-09-27, MuPDF default is `#ifndef NDEBUG`.\n\n    PYMUPDF_SETUP_MUPDF_THIRD\n        If '0' and we are building on Linux with the system MuPDF\n        (i.e. PYMUPDF_SETUP_MUPDF_BUILD=''), then don't link with\n        `-lmupdf-third`.\n    \n    PYMUPDF_SETUP_MUPDF_VS_UPGRADE\n        If '1' we run mupdf `scripts/mupdfwrap.py` with `--vs-upgrade 1` to\n        help Windows builds work with Visual Studio versions newer than 2019.\n\n    PYMUPDF_SETUP_MUPDF_TGZ\n        If set, overrides location of MuPDF .tar.gz file:\n            Empty string:\n                Do not download MuPDF .tar.gz file. Sdist's will not contain\n                MuPDF.\n\n            A string containing '://':\n                The URL from which to download the MuPDF .tar.gz file. Leaf\n                must match mupdf-*.tar.gz.\n\n            Otherwise:\n                The path of local mupdf git checkout. We put all files in this\n                checkout known to git into a local tar archive.\n\n    PYMUPDF_SETUP_MUPDF_OVERWRITE_CONFIG\n        If '0' we do not overwrite MuPDF's include/mupdf/fitz/config.h with\n        PyMuPDF's own configuration file, before building MuPDF.\n    \n    PYMUPDF_SETUP_MUPDF_REBUILD\n        If 0 we do not (re)build mupdf.\n    \n    PYMUPDF_SETUP_PY_LIMITED_API\n        If not '0', we build for current Python's stable ABI.\n    \n    PYMUPDF_SETUP_URL_WHEEL\n        If set, we use an existing wheel instead of building a new wheel.\n        \n        If starts with `http://` or `https://`:\n            If ends with '/', we append our wheel name and download. Otherwise\n            we download directly.\n        \n        If starts with `file://`:\n            If ends with '/' we look for a matching wheel name, `using\n            pipcl.wheel_name_match()` to cope with differing platform tags,\n            for example our `manylinux2014_x86_64` will match with an existing\n            wheel with `manylinux2014_x86_64.manylinux_2_17_x86_64`.\n        \n        Any other prefix is an error.\n\n    PYMUPDF_SETUP_SWIG\n        If set, we use this instead of `swig`.\n    \n    WDEV_VS_YEAR\n        If set, we use as Visual Studio year, for example '2019' or '2022'.\n\n    WDEV_VS_GRADE\n        If set, we use as Visual Studio grade, for example 'Community' or\n        'Professional' or 'Enterprise'.\n'''\n\nimport glob\nimport io\nimport os\nimport textwrap\nimport time\nimport platform\nimport re\nimport shlex\nimport shutil\nimport stat\nimport subprocess\nimport sys\nimport tarfile\nimport traceback\nimport urllib.request\nimport zipfile\n\nimport pipcl\n\n\nlog = pipcl.log0\n\nrun = pipcl.run\n\n\nif 1:\n    # For debugging.\n    log(f'### Starting.')\n    pipcl.show_system()\n\n\nPYMUPDF_SETUP_FLAVOUR = os.environ.get( 'PYMUPDF_SETUP_FLAVOUR', 'pbd')\nfor i in PYMUPDF_SETUP_FLAVOUR:\n    assert i in 'pbd', f'Unrecognised flag \"{i} in {PYMUPDF_SETUP_FLAVOUR=}. Should be one of \"p\", \"b\", \"d\"'\n\ng_root = os.path.abspath( f'{__file__}/..')\n\n# Name of file that identifies that we are in a PyMuPDF sdist.\ng_pymupdfb_sdist_marker = 'pymupdfb_sdist'\n\npython_version_tuple = tuple(int(x) for x in platform.python_version_tuple()[:2])\n\nPYMUPDF_SETUP_PY_LIMITED_API = os.environ.get('PYMUPDF_SETUP_PY_LIMITED_API')\nassert PYMUPDF_SETUP_PY_LIMITED_API in (None, '', '0', '1'), \\\n        f'Should be \"\", \"0\", \"1\" or undefined: {PYMUPDF_SETUP_PY_LIMITED_API=}.'\ng_py_limited_api = (PYMUPDF_SETUP_PY_LIMITED_API != '0')\n\nPYMUPDF_SETUP_URL_WHEEL =  os.environ.get('PYMUPDF_SETUP_URL_WHEEL')\nlog(f'{PYMUPDF_SETUP_URL_WHEEL=}')\n\nPYMUPDF_SETUP_DUMMY = os.environ.get('PYMUPDF_SETUP_DUMMY')\nlog(f'{PYMUPDF_SETUP_DUMMY=}')\n\nPYMUPDF_SETUP_SWIG = os.environ.get('PYMUPDF_SETUP_SWIG')\nPYMUPDF_SETUP_FAKE_NOGIL = os.environ.get('PYMUPDF_SETUP_FAKE_NOGIL')\n\ndef _fs_remove(path):\n    '''\n    Removes file or directory, without raising exception if it doesn't exist.\n\n    We assert-fail if the path still exists when we return, in case of\n    permission problems etc.\n    '''\n    # First try deleting `path` as a file.\n    try:\n        os.remove( path)\n    except Exception as e:\n        pass\n    \n    if os.path.exists(path):\n        # Try deleting `path` as a directory. Need to use\n        # shutil.rmtree() callback to handle permission problems; see:\n        # https://docs.python.org/3/library/shutil.html#rmtree-example\n        #\n        def error_fn(fn, path, excinfo):\n            # Clear the readonly bit and reattempt the removal.\n            os.chmod(path, stat.S_IWRITE)\n            fn(path)\n        shutil.rmtree( path, onerror=error_fn)\n    \n    assert not os.path.exists( path)\n\n\ndef _git_get_branch( directory):\n    command = f'cd {directory} && git branch --show-current'\n    log( f'Running: {command}')\n    p = subprocess.run(\n            command,\n            shell=True,\n            check=False,\n            text=True,\n            stdout=subprocess.PIPE,\n            )\n    ret = None\n    if p.returncode == 0:\n        ret = p.stdout.strip()\n        log( f'Have found MuPDF git branch: ret={ret!r}')\n    return ret\n\n\ndef tar_check(path, mode='r:gz', prefix=None, remove=False):\n    '''\n    Checks items in tar file have same <top-directory>, or <prefix> if not None.\n\n    We fail if items in tar file have different top-level directory names.\n\n    path:\n        The tar file.\n    mode:\n        As tarfile.open().\n    prefix:\n        If not None, we fail if tar file's <top-directory> is not <prefix>.\n    \n    Returns the directory name (which will be <prefix> if not None).\n    '''\n    with tarfile.open( path, mode) as t:\n        items = t.getnames()\n        assert items\n        item = items[0]\n        assert not item.startswith('./') and not item.startswith('../')\n        s = item.find('/')\n        if s == -1:\n            prefix_actual = item + '/'\n        else:\n            prefix_actual = item[:s+1]\n        if prefix:\n            assert prefix == prefix_actual, f'{path=} {prefix=} {prefix_actual=}'\n        for item in items[1:]:\n            assert item.startswith( prefix_actual), f'prefix_actual={prefix_actual!r} != item={item!r}'\n    return prefix_actual\n\n\ndef tar_extract(path, mode='r:gz', prefix=None, exists='raise'):\n    '''\n    Extracts tar file into single local directory.\n    \n    We fail if items in tar file have different <top-directory>.\n\n    path:\n        The tar file.\n    mode:\n        As tarfile.open().\n    prefix:\n        If not None, we fail if tar file's <top-directory> is not <prefix>.\n    exists:\n        What to do if <top-directory> already exists:\n            'raise': raise exception.\n            'remove': remove existing file/directory before extracting.\n            'return': return without extracting.\n    \n    Returns the directory name (which will be <prefix> if not None, with '/'\n    appended if not already present).\n    '''\n    prefix_actual = tar_check( path, mode, prefix)\n    if os.path.exists( prefix_actual):\n        if exists == 'raise':\n            raise Exception( f'Path already exists: {prefix_actual!r}')\n        elif exists == 'remove':\n            remove( prefix_actual)\n        elif exists == 'return':\n            log( f'Not extracting {path} because already exists: {prefix_actual}')\n            return prefix_actual\n        else:\n            assert 0, f'Unrecognised exists={exists!r}'\n    assert not os.path.exists( prefix_actual), f'Path already exists: {prefix_actual}'\n    log( f'Extracting {path}')\n    with tarfile.open( path, mode) as t:\n        t.extractall()\n    return prefix_actual\n\n\ndef git_info( directory):\n    '''\n    Returns `(sha, comment, diff, branch)`, all items are str or None if not\n    available.\n\n    directory:\n        Root of git checkout.\n    '''\n    sha, comment, diff, branch = '', '', '', ''\n    cp = subprocess.run(\n            f'cd {directory} && (PAGER= git show --pretty=oneline|head -n 1 && git diff)',\n            capture_output=1,\n            shell=1,\n            text=1,\n            )\n    if cp.returncode == 0:\n        sha, _ = cp.stdout.split(' ', 1)\n        comment, diff = _.split('\\n', 1)\n    cp = subprocess.run(\n            f'cd {directory} && git rev-parse --abbrev-ref HEAD',\n            capture_output=1,\n            shell=1,\n            text=1,\n            )\n    if cp.returncode == 0:\n        branch = cp.stdout.strip()\n    log(f'git_info(): directory={directory!r} returning branch={branch!r} sha={sha!r} comment={comment!r}')\n    return sha, comment, diff, branch\n\n\ndef git_patch(directory, patch, hard=False):\n    '''\n    Applies string <patch> with `git patch` in <directory>.\n    \n    If <hard> is true we clean the tree with `git checkout .` and then apply\n    the patch.\n\n    Otherwise we apply patch only if it is not already applied; this might fail\n    if there are conflicting changes in the tree.\n    '''\n    log(f'Applying patch in {directory}:\\n{textwrap.indent(patch, \"    \")}')\n    if not patch:\n        return\n    # Carriage returns break `git apply` so we use `newline='\\n'` in open().\n    path = os.path.abspath(f'{directory}/pymupdf_patch.txt')\n    with open(path, 'w', newline='\\n') as f:\n        f.write(patch)\n    log(f'Using patch file: {path}')\n    if hard:\n        run(f'cd {directory} && git checkout .')\n        run(f'cd {directory} && git apply {path}')\n        log(f'Have applied patch in {directory}.')\n    else:\n        e = run( f'cd {directory} && git apply --check --reverse {path}', check=0)\n        if e == 0:\n            log(f'Not patching {directory} because already patched.')\n        else:\n            run(f'cd {directory} && git apply {path}')\n            log(f'Have applied patch in {directory}.')\n    run(f'cd {directory} && git diff')\n\n\nmupdf_tgz = os.path.abspath( f'{__file__}/../mupdf.tgz')\n\ndef get_mupdf_internal(out, location=None, local_tgz=None):\n    '''\n    Gets MuPDF as either a .tgz or a local directory.\n    \n    Args:\n        out:\n            Either 'dir' (we return name of local directory containing mupdf) or 'tgz' (we return\n            name of local .tgz file containing mupdf).\n        location:\n            First, if None we set to hard-coded default URL or git location.\n            If starts with 'git:', should be remote git location.\n            Otherwise if containing '://' should be URL for .tgz.\n            Otherwise should path of local mupdf checkout.\n        local_tgz:\n            If not None, must be local .tgz file.\n    Returns:\n        (path, location):\n            `path` is absolute path of local directory or .tgz containing\n            MuPDF, or None if we are to use system MuPDF.\n\n            `location_out` is `location` if not None, else the hard-coded\n            default location.\n                \n    '''\n    log(f'get_mupdf_internal(): {out=} {location=}')\n    assert out in ('dir', 'tgz')\n    if location is None:\n        location = f'https://mupdf.com/downloads/archive/mupdf-{version_mupdf}-source.tar.gz'\n        #location = 'git:--branch master https://github.com/ArtifexSoftware/mupdf.git'\n    \n    if location == '':\n        # Use system mupdf.\n        return None, location\n    \n    local_dir = None\n    if local_tgz:\n        assert os.path.isfile(local_tgz)\n    elif location.startswith( 'git:'):\n        local_dir = 'mupdf-git'\n        pipcl.git_get(local_dir, text=location, remote='https://github.com/ArtifexSoftware/mupdf.git')\n        \n        # Show sha of checkout.\n        run(\n                f'cd {local_dir} && git show --pretty=oneline|head -n 1',\n                check = False,\n                prefix = 'mupdf git id: ',\n                )\n    elif '://' in location:\n        # Download .tgz.\n        local_tgz = os.path.basename( location)\n        suffix = '.tar.gz'\n        assert location.endswith(suffix), f'Unrecognised suffix in remote URL {location=}.'\n        name = local_tgz[:-len(suffix)]\n        log( f'Download {location=} {local_tgz=} {name=}')\n        if os.path.exists(local_tgz):\n            try:\n                tar_check(local_tgz, 'r:gz', prefix=f'{name}/')\n            except Exception as e:\n                log(f'Not using existing file {local_tgz} because invalid tar data: {e}')\n                _fs_remove( local_tgz)\n        if os.path.exists(local_tgz):\n            log(f'Not downloading from {location} because already present: {local_tgz!r}')\n        else:\n            log(f'Downloading from {location=} to {local_tgz=}.')\n            urllib.request.urlretrieve( location, local_tgz + '-')\n            os.rename(local_tgz + '-', local_tgz)\n            assert os.path.exists( local_tgz)\n            tar_check( local_tgz, 'r:gz', prefix=f'{name}/')\n    else:\n        assert os.path.isdir(location), f'Local MuPDF does not exist: {location=}'\n        local_dir = location\n    \n    assert bool(local_dir) != bool(local_tgz)\n    if out == 'dir':\n        if not local_dir:\n            assert local_tgz\n            local_dir = tar_extract( local_tgz, exists='return')\n        return os.path.abspath( local_dir), location\n    elif out == 'tgz':\n        if not local_tgz:\n            # Create .tgz containing git files in `local_dir`.\n            assert local_dir\n            if local_dir.endswith( '/'):\n                local_dir = local_dir[:-1]\n            top = os.path.basename(local_dir)\n            local_tgz = f'{local_dir}.tgz'\n            log( f'Creating .tgz from git files. {top=} {local_dir=} {local_tgz=}')\n            _fs_remove( local_tgz)\n            with tarfile.open( local_tgz, 'w:gz') as f:\n                for name in pipcl.git_items( local_dir, submodules=True):\n                    path = os.path.join( local_dir, name)\n                    if os.path.isfile( path):\n                        path2 = f'{top}/{name}'\n                        log(f'Adding {path=} {path2=}.')\n                        f.add( path, path2, recursive=False)\n        return os.path.abspath( local_tgz), location\n    else:\n        assert 0, f'Unrecognised {out=}'\n            \n        \n\ndef get_mupdf_tgz():\n    '''\n    Creates .tgz file called containing MuPDF source, for inclusion in an\n    sdist.\n    \n    What we do depends on environmental variable PYMUPDF_SETUP_MUPDF_TGZ; see\n    docs at start of this file for details.\n\n    Returns name of top-level directory within the .tgz file.\n    '''\n    name, location = get_mupdf_internal( 'tgz', os.environ.get('PYMUPDF_SETUP_MUPDF_TGZ'))\n    return name, location\n\n\ndef get_mupdf(path=None, sha=None):\n    '''\n    Downloads and/or extracts mupdf and returns (path, location) where `path`\n    is the local mupdf directory and `location` is where it came from.\n\n    Exact behaviour depends on environmental variable\n    PYMUPDF_SETUP_MUPDF_BUILD; see docs at start of this file for details.\n    '''\n    m = os.environ.get('PYMUPDF_SETUP_MUPDF_BUILD')\n    if m == '-':\n        # This allows easy specification in Github actions.\n        m = None\n    if m is None and os.path.isfile(mupdf_tgz):\n        # This makes us use tgz inside sdist.\n        log(f'Using local tgz: {mupdf_tgz=}')\n        return get_mupdf_internal('dir', local_tgz=mupdf_tgz)\n    return get_mupdf_internal('dir', m)\n\n\nlinux = sys.platform.startswith( 'linux') or 'gnu' in sys.platform\nopenbsd = sys.platform.startswith( 'openbsd')\nfreebsd = sys.platform.startswith( 'freebsd')\ndarwin = sys.platform.startswith( 'darwin')\nwindows = platform.system() == 'Windows' or platform.system().startswith('CYGWIN')\nmsys2 = platform.system().startswith('MSYS_NT-')\n\nif os.environ.get('PYODIDE') == '1':\n    if os.environ.get('OS') != 'pyodide':\n        log('PYODIDE=1, setting OS=pyodide.')\n        os.environ['OS'] = 'pyodide'\n\npyodide = os.environ.get('OS') == 'pyodide'\n\ndef build():\n    '''\n    pipcl.py `build_fn()` callback.\n    '''\n    #pipcl.show_sysconfig()\n    \n    if PYMUPDF_SETUP_DUMMY == '1':\n        log(f'{PYMUPDF_SETUP_DUMMY=} Building dummy wheel with no files.')\n        return list()\n    \n    # Download MuPDF.\n    #\n    mupdf_local, mupdf_location = get_mupdf()\n    if mupdf_local:\n        mupdf_version_tuple = get_mupdf_version(mupdf_local)\n    # else we cannot determine version this way and do not use it\n\n    build_type = os.environ.get( 'PYMUPDF_SETUP_MUPDF_BUILD_TYPE', 'release')\n    assert build_type in ('debug', 'memento', 'release'), \\\n            f'Unrecognised build_type={build_type!r}'\n    \n    overwrite_config = os.environ.get('PYMUPDF_SETUP_MUPDF_OVERWRITE_CONFIG', '1') == '1'\n    \n    PYMUPDF_SETUP_MUPDF_REFCHECK_IF = os.environ.get('PYMUPDF_SETUP_MUPDF_REFCHECK_IF')\n    PYMUPDF_SETUP_MUPDF_TRACE_IF = os.environ.get('PYMUPDF_SETUP_MUPDF_TRACE_IF')\n    \n    # Build MuPDF shared libraries.\n    #\n    if windows:\n        mupdf_build_dir = build_mupdf_windows(\n                mupdf_local,\n                build_type,\n                overwrite_config,\n                g_py_limited_api,\n                PYMUPDF_SETUP_MUPDF_REFCHECK_IF,\n                PYMUPDF_SETUP_MUPDF_TRACE_IF,\n                PYMUPDF_SETUP_FAKE_NOGIL,\n                )\n    else:\n        if 'p' not in PYMUPDF_SETUP_FLAVOUR and 'b' not in PYMUPDF_SETUP_FLAVOUR:\n            # We only need MuPDF headers, so no point building MuPDF.\n            log(f'Not building MuPDF because not Windows and {PYMUPDF_SETUP_FLAVOUR=}.')\n            mupdf_build_dir = None\n        else:\n            mupdf_build_dir = build_mupdf_unix(\n                    mupdf_local,\n                    build_type,\n                    overwrite_config,\n                    g_py_limited_api,\n                    PYMUPDF_SETUP_MUPDF_REFCHECK_IF,\n                    PYMUPDF_SETUP_MUPDF_TRACE_IF,\n                    PYMUPDF_SETUP_SWIG,\n                    PYMUPDF_SETUP_FAKE_NOGIL,\n                    )\n    log( f'build(): mupdf_build_dir={mupdf_build_dir!r}')\n    \n    # Build `extra` module.\n    #\n    if 'p' in PYMUPDF_SETUP_FLAVOUR:\n        path_so_leaf = _build_extension(\n                mupdf_local,\n                mupdf_build_dir,\n                build_type,\n                g_py_limited_api,\n                )\n    else:\n        log(f'Not building extension.')\n        path_so_leaf = None\n    \n    # Generate list of (from, to) items to return to pipcl. What we add depends\n    # on PYMUPDF_SETUP_FLAVOUR.\n    #\n    ret = list()    \n    def add(flavour, from_, to_):\n        assert flavour in 'pbd'\n        if flavour in PYMUPDF_SETUP_FLAVOUR:\n            ret.append((from_, to_))\n    \n    to_dir = 'pymupdf/'\n    to_dir_d = f'{to_dir}/mupdf-devel'\n    \n    # Add implementation files.\n    add('p', f'{g_root}/src/__init__.py', to_dir)\n    add('p', f'{g_root}/src/__main__.py', to_dir)\n    add('p', f'{g_root}/src/pymupdf.py', to_dir)\n    add('p', f'{g_root}/src/table.py', to_dir)\n    add('p', f'{g_root}/src/utils.py', to_dir)\n    add('p', f'{g_root}/src/_wxcolors.py', to_dir)\n    add('p', f'{g_root}/src/_apply_pages.py', to_dir)\n    add('p', f'{g_root}/src/build/extra.py', to_dir)\n    add('p', b'', f'{to_dir}/py.typed')\n    if path_so_leaf:\n        add('p', f'{g_root}/src/build/{path_so_leaf}', to_dir)\n\n    # Add support for `fitz` backwards compatibility.\n    add('p', f'{g_root}/src/fitz___init__.py', 'fitz/__init__.py')\n    add('p', f'{g_root}/src/fitz_table.py', 'fitz/table.py')\n    add('p', f'{g_root}/src/fitz_utils.py', 'fitz/utils.py')\n\n    if mupdf_local:\n        # Add MuPDF Python API.\n        add('p', f'{mupdf_build_dir}/mupdf.py', to_dir)\n\n        # Add MuPDF shared libraries.\n        if windows:\n            wp = pipcl.wdev.WindowsPython()\n            add('p', f'{mupdf_build_dir}/_mupdf.pyd', to_dir)\n            add('b', f'{mupdf_build_dir}/mupdfcpp{wp.cpu.windows_suffix}.dll', to_dir)\n\n            # Add Windows .lib files.\n            mupdf_build_dir2 = _windows_lib_directory(mupdf_local, build_type)\n            add('d', f'{mupdf_build_dir2}/mupdfcpp{wp.cpu.windows_suffix}.lib', f'{to_dir_d}/lib/')\n            # MuPDF-1.25+ language bindings build also builds libmuthreads.\n            add('d', f'{mupdf_build_dir2}/libmuthreads.lib', f'{to_dir_d}/lib/')\n        elif darwin:\n            add('p', f'{mupdf_build_dir}/_mupdf.so', to_dir)\n            add('b', f'{mupdf_build_dir}/libmupdfcpp.so', to_dir)\n            add('b', f'{mupdf_build_dir}/libmupdf.dylib', to_dir)\n            add('d', f'{mupdf_build_dir}/libmupdf-threads.a', f'{to_dir_d}/lib/')\n        elif pyodide:\n            add('p', f'{mupdf_build_dir}/_mupdf.so', to_dir)\n            add('b', f'{mupdf_build_dir}/libmupdfcpp.so', to_dir)\n            add('b', f'{mupdf_build_dir}/libmupdf.so', to_dir)\n        else:\n            add('p', f'{mupdf_build_dir}/_mupdf.so', to_dir)\n            add('b', pipcl.get_soname(f'{mupdf_build_dir}/libmupdfcpp.so'), to_dir)\n            add('b', pipcl.get_soname(f'{mupdf_build_dir}/libmupdf.so'), to_dir)\n            add('d', f'{mupdf_build_dir}/libmupdf-threads.a', f'{to_dir_d}/lib/')\n\n        if 'd' in PYMUPDF_SETUP_FLAVOUR:\n            # Add MuPDF C and C++ headers to `ret_d`. Would prefer to use\n            # pipcl.git_items() but hard-coded mupdf tree is not a git\n            # checkout.\n            #\n            for root in (\n                    f'{mupdf_local}/include',\n                    f'{mupdf_local}/platform/c++/include',\n                    ):\n                for dirpath, dirnames, filenames in os.walk(root):\n                    for filename in filenames:\n                        if not filename.endswith('.h'):\n                            continue\n                        header_abs = os.path.join(dirpath, filename)\n                        assert header_abs.startswith(root)\n                        header_rel = header_abs[len(root)+1:]\n                        add('d', f'{header_abs}', f'{to_dir_d}/include/{header_rel}')\n    \n    # Add a .py file containing location of MuPDF.\n    try:\n        sha, comment, diff, branch = git_info(g_root)\n    except Exception as e:\n        log(f'Failed to get git information: {e}')\n        sha, comment, diff, branch = (None, None, None, None)\n    swig = PYMUPDF_SETUP_SWIG or 'swig'\n    swig_version_text = run(f'{swig} -version', capture=1)\n    m = re.search('\\nSWIG Version ([^\\n]+)', swig_version_text)\n    log(f'{swig_version_text=}')\n    assert m, f'Unrecognised {swig_version_text=}'\n    swig_version = m.group(1)\n    def int_or_0(text):\n        try:\n            return int(text)\n        except Exception:\n            return 0\n    swig_version_tuple = tuple(int_or_0(i) for i in swig_version.split('.'))\n    version_p_tuple = tuple(int_or_0(i) for i in version_p.split('.'))\n    log(f'{swig_version=}')\n    text = ''\n    text += f'mupdf_location = {mupdf_location!r}\\n'\n    text += f'pymupdf_version = {version_p!r}\\n'\n    text += f'pymupdf_version_tuple = {version_p_tuple!r}\\n'\n    text += f'pymupdf_git_sha = {sha!r}\\n'\n    text += f'pymupdf_git_diff = {diff!r}\\n'\n    text += f'pymupdf_git_branch = {branch!r}\\n'\n    text += f'swig_version = {swig_version!r}\\n'\n    text += f'swig_version_tuple = {swig_version_tuple!r}\\n'\n    text += f'fake_no_gil = {PYMUPDF_SETUP_FAKE_NOGIL==\"1\"!r}\\n'\n    log(f'_build.py is:\\n{textwrap.indent(text, \"    \")}')\n    add('p', text.encode(), f'{to_dir}/_build.py')\n    \n    # Add single README file.\n    if 'p' in PYMUPDF_SETUP_FLAVOUR:\n        add('p', f'{g_root}/README.md', '$dist-info/README.md')\n    elif 'b' in PYMUPDF_SETUP_FLAVOUR:\n        add('b', f'{g_root}/READMEb.md', '$dist-info/README.md')\n    elif 'd' in PYMUPDF_SETUP_FLAVOUR:\n        add('d', f'{g_root}/READMEd.md', '$dist-info/README.md')\n    \n    return ret\n\n\ndef env_add(env, name, value, sep=' ', prepend=False, verbose=False):\n    '''\n    Appends/prepends `<value>` to `env[name]`.\n    \n    If `name` is not in `env`, we use os.environ[name] if it exists.\n    '''\n    v = env.get(name)\n    if verbose:\n        log(f'Initally: {name}={v!r}')\n    if v is None:\n        v = os.environ.get(name)\n    if v is None:\n        env[ name] = value\n    else:\n        if prepend:\n            env[ name] =  f'{value}{sep}{v}'\n        else:\n            env[ name] =  f'{v}{sep}{value}'\n    if verbose:\n        log(f'Returning with {name}={env[name]!r}')\n\n\ndef build_mupdf_windows(\n        mupdf_local,\n        build_type,\n        overwrite_config,\n        g_py_limited_api,\n        PYMUPDF_SETUP_MUPDF_REFCHECK_IF,\n        PYMUPDF_SETUP_MUPDF_TRACE_IF,\n        PYMUPDF_SETUP_FAKE_NOGIL,\n        ):\n    \n    assert mupdf_local\n    mupdf_version_tuple = get_mupdf_version(mupdf_local)\n    log(f'{overwrite_config=}')\n    log(f'{mupdf_version_tuple=}')\n    wp = pipcl.wdev.WindowsPython()\n    tesseract = '' if os.environ.get('PYMUPDF_SETUP_MUPDF_TESSERACT') == '0' else 'tesseract-'\n    windows_build_tail = f'build\\\\shared-{tesseract}{build_type}'\n    \n    if overwrite_config:\n        if mupdf_version_tuple >= (1, 28):\n            # Tell mupdf build to use, for example, `/Build \"ReleaseTofuCjkExt|x64\"`.\n            # This avoids the need for us to modify mupdf's config.h.\n            windows_build_tail += '-TOFU_CJK_EXT'\n            log(f'Appending, {windows_build_tail=}')\n        else:\n            log(f'modifying mupdf:include/mupdf/fitz/config.h')\n            mupdf_config_h = f'{mupdf_local}/include/mupdf/fitz/config.h'\n            prefix = '#define TOFU_CJK_EXT 1 /* PyMuPDF override. */\\n'\n            with open(mupdf_config_h) as f:\n                text = f.read()\n            if text.startswith(prefix):\n                log(f'Not modifying {mupdf_config_h} because already has prefix {prefix!r}.')\n            else:\n                log(f'Prefixing {mupdf_config_h} with {prefix!r}.')\n                text = prefix + text\n                st = os.stat(mupdf_config_h)\n                with open(mupdf_config_h, 'w') as f:\n                    f.write(text)\n                os.utime(mupdf_config_h, (st.st_atime, st.st_mtime))\n    \n    if g_py_limited_api:\n        windows_build_tail += f'-Py_LIMITED_API_{pipcl.current_py_limited_api()}'\n    if PYMUPDF_SETUP_FAKE_NOGIL == '1':\n        windows_build_tail += '-nogil'\n    windows_build_tail += f'-x{wp.cpu.bits}-py{wp.version}'\n    windows_build_dir = f'{mupdf_local}\\\\{windows_build_tail}'\n    #log( f'Building mupdf.')\n    devenv = os.environ.get('PYMUPDF_SETUP_DEVENV')\n    if not devenv:\n        try:\n            # Prefer VS-2022 as that is what Github provide in windows-2022.\n            log(f'Looking for Visual Studio 2022.')\n            vs = pipcl.wdev.WindowsVS(year=2022)\n        except Exception as e:\n            log(f'Failed to find VS-2022:\\n'\n                    f'{textwrap.indent(traceback.format_exc(), \"    \")}'\n                    )\n            log(f'Looking for any Visual Studio.')\n            vs = pipcl.wdev.WindowsVS()\n        log(f'vs:\\n{vs.description_ml(\"    \")}')\n        devenv = vs.devenv\n    if not devenv:\n        devenv = 'devenv.com'\n        log( f'Cannot find devenv.com in default locations, using: {devenv!r}')\n    command = f'cd \"{mupdf_local}\" && \"{sys.executable}\" ./scripts/mupdfwrap.py'\n    if os.environ.get('PYMUPDF_SETUP_MUPDF_VS_UPGRADE') == '1':\n        command += ' --vs-upgrade 1'\n        \n    # Would like to simply do f'... --devenv {shutil.quote(devenv)}', but\n    # it looks like if `devenv` has spaces then `shutil.quote()` puts it\n    # inside single quotes, which then appear to be ignored when run by\n    # subprocess.run().\n    #\n    # So instead we strip any enclosing quotes and the enclose with\n    # double-quotes.\n    #\n    if len(devenv) >= 2:\n        for q in '\"', \"'\":\n            if devenv.startswith( q) and devenv.endswith( q):\n                devenv = devenv[1:-1]\n    command += f' -d {windows_build_tail}'\n    command += f' -b'\n    if PYMUPDF_SETUP_MUPDF_REFCHECK_IF:\n        command += f' --refcheck-if \"{PYMUPDF_SETUP_MUPDF_REFCHECK_IF}\"'\n    if PYMUPDF_SETUP_MUPDF_TRACE_IF:\n        command += f' --trace-if \"{PYMUPDF_SETUP_MUPDF_TRACE_IF}\"'\n    command += f' --devenv \"{devenv}\"'\n    command += f' all'\n    if os.environ.get( 'PYMUPDF_SETUP_MUPDF_REBUILD') == '0':\n        log( f'PYMUPDF_SETUP_MUPDF_REBUILD is \"0\" so not building MuPDF; would have run: {command}')\n    else:\n        log( f'Building MuPDF by running: {command}')\n        subprocess.run( command, shell=True, check=True)\n        log( f'Finished building mupdf.')\n    \n    return windows_build_dir\n\n\ndef _windows_lib_directory(mupdf_local, build_type):\n    ret = f'{mupdf_local}/platform/win32/'\n    if _cpu_bits() == 64:\n        ret += 'x64/'\n    if build_type == 'release':\n        ret += 'Release/'\n    elif build_type == 'debug':\n        ret += 'Debug/'\n    else:\n        assert 0, f'Unrecognised {build_type=}.'\n    return ret\n\n\ndef _cpu_bits():\n    if sys.maxsize == 2**31 - 1:\n        return 32\n    return 64\n\n\ndef build_mupdf_unix(\n        mupdf_local,\n        build_type,\n        overwrite_config,\n        g_py_limited_api,\n        PYMUPDF_SETUP_MUPDF_REFCHECK_IF,\n        PYMUPDF_SETUP_MUPDF_TRACE_IF,\n        PYMUPDF_SETUP_SWIG,\n        PYMUPDF_SETUP_FAKE_NOGIL,\n        ):\n    '''\n    Builds MuPDF.\n\n    Args:\n        mupdf_local:\n            Path of MuPDF directory or None if we are using system MuPDF.\n    \n    Returns the absolute path of build directory within MuPDF, e.g.\n    `.../mupdf/build/pymupdf-shared-release`, or `None` if we are using the\n    system MuPDF.\n    '''    \n    if not mupdf_local:\n        log( f'Using system mupdf.')\n        return None\n\n    env = dict()\n    if overwrite_config:\n        # By predefining TOFU_CJK_EXT here, we don't need to modify\n        # MuPDF's include/mupdf/fitz/config.h.\n        log( f'Setting XCFLAGS and XCXXFLAGS to predefine TOFU_CJK_EXT.')\n        env_add(env, 'XCFLAGS', '-DTOFU_CJK_EXT')\n        env_add(env, 'XCXXFLAGS', '-DTOFU_CJK_EXT')\n\n    if openbsd or freebsd:\n        env_add(env, 'CXX', 'c++', ' ')\n    \n    if darwin and os.environ.get('GITHUB_ACTIONS') == 'true':\n        if os.environ.get('ImageOS') == 'macos13':\n            # On Github macos13 we need to use Clang/LLVM (Homebrew) 15.0.7,\n            # otherwise mupdf:thirdparty/tesseract/src/api/baseapi.cpp fails to\n            # compile with:\n            #\n            #   thirdparty/tesseract/src/api/baseapi.cpp:150:25: error: 'recursive_directory_iterator' is unavailable: introduced in macOS 10.15\n            #\n            # See:\n            #   https://github.com/actions/runner-images/blob/main/images/macos/macos-13-Readme.md\n            #\n            log(f'Using llvm@15 clang and clang++')\n            cl15 = pipcl.run(f'brew --prefix llvm@15', capture=1)\n            log(f'{cl15=}')\n            cl15 = cl15.strip()\n            pipcl.run(f'ls -lL {cl15}')\n            pipcl.run(f'ls -lL {cl15}/bin')\n            cc = f'{cl15}/bin/clang'\n            cxx = f'{cl15}/bin/clang++'\n            env['CC'] = cc\n            env['CXX'] = cxx\n    \n    # Show compiler versions.\n    cc = env.get('CC', 'cc')\n    cxx = env.get('CXX', 'c++')\n    pipcl.run(f'{cc} --version')\n    pipcl.run(f'{cxx} --version')\n\n    # Add extra flags for MacOS cross-compilation, where ARCHFLAGS can be\n    # '-arch arm64'.\n    #\n    archflags = os.environ.get( 'ARCHFLAGS')\n    if archflags:\n        env_add(env, 'XCFLAGS', archflags)\n        env_add(env, 'XLIBS', archflags)\n\n    mupdf_version_tuple = get_mupdf_version(mupdf_local)\n    \n    # We specify a build directory path containing 'pymupdf' so that we\n    # coexist with non-PyMuPDF builds (because PyMuPDF builds have a\n    # different config.h).\n    #\n    # We also append further text to try to allow different builds to\n    # work if they reuse the mupdf directory.\n    #\n    # Using platform.machine() (e.g. 'amd64') ensures that different\n    # builds of mupdf on a shared filesystem can coexist. Using\n    # $_PYTHON_HOST_PLATFORM allows cross-compiled cibuildwheel builds\n    # to coexist, e.g. on github.\n    #\n    # Have experimented with looking at getconf_ARG_MAX to decide whether to\n    # omit `PyMuPDF-` from the build directory, to avoid command-too-long\n    # errors with mupdf-1.26. But it seems that `getconf ARG_MAX` returns\n    # a system limit, not the actual limit of the current shell, and there\n    # doesn't seem to be a way to find the current shell's limit.\n    #\n    # Avoid link command length problems seen on musllinux.\n    build_prefix = ''\n    if pyodide:\n        build_prefix += 'pyodide-'\n    else:\n        build_prefix += f'{platform.machine()}-'\n    build_prefix_extra = os.environ.get( '_PYTHON_HOST_PLATFORM')\n    if build_prefix_extra:\n        build_prefix += f'{build_prefix_extra}-'\n    build_prefix += 'shared-'\n    if msys2:\n        # Error in mupdf/scripts/tesseract/endianness.h:\n        # #error \"I don't know what architecture this is!\"\n        log(f'msys2: building MuPDF without tesseract.')\n    elif os.environ.get('PYMUPDF_SETUP_MUPDF_TESSERACT') == '0':\n        log(f'PYMUPDF_SETUP_MUPDF_TESSERACT=0 so building mupdf without tesseract.')\n    else:\n        build_prefix += 'tesseract-'\n    if (\n            linux\n            and os.environ.get('PYMUPDF_SETUP_MUPDF_BSYMBOLIC', '1') == '1'\n            ):\n        log(f'Appending `bsymbolic-` to MuPDF build path.')\n        build_prefix += 'bsymbolic-'\n    log(f'{g_py_limited_api=}')\n    if g_py_limited_api:\n        build_prefix += f'Py_LIMITED_API_{pipcl.current_py_limited_api()}-'\n    if PYMUPDF_SETUP_FAKE_NOGIL == '1':\n        build_prefix += 'nogil-'\n    unix_build_dir = f'{mupdf_local}/build/{build_prefix}{build_type}'\n    PYMUPDF_SETUP_MUPDF_CLEAN = os.environ.get('PYMUPDF_SETUP_MUPDF_CLEAN')\n    if PYMUPDF_SETUP_MUPDF_CLEAN == '1':\n        log(f'{PYMUPDF_SETUP_MUPDF_CLEAN=}, deleting {unix_build_dir=}.')\n        shutil.rmtree(unix_build_dir, ignore_errors=1)\n    # We need MuPDF's Python bindings, so we build MuPDF with\n    # `mupdf/scripts/mupdfwrap.py` instead of running `make`.\n    #\n    command = f'cd {mupdf_local} &&'\n    for n, v in env.items():\n        command += f' {n}={shlex.quote(v)}'\n    command += f' {sys.executable} ./scripts/mupdfwrap.py'\n    if PYMUPDF_SETUP_SWIG:\n        command += f' --swig {shlex.quote(PYMUPDF_SETUP_SWIG)}'\n    command += f' -d build/{build_prefix}{build_type} -b'\n    if sys.implementation.name == 'graalpy':\n        # Force rerun of swig.\n        pipcl.run(f'ls -l {mupdf_local}/platform/python/')\n        for p in glob.glob(f'{mupdf_local}/platform/python/mupdfcpp*.i.cpp'):\n            pipcl.log(f'Graal, deleting: {p!r}')\n            pipcl.fs_remove(p)\n    if PYMUPDF_SETUP_MUPDF_REFCHECK_IF:\n        command += f' --refcheck-if \"{PYMUPDF_SETUP_MUPDF_REFCHECK_IF}\"'\n    if PYMUPDF_SETUP_MUPDF_TRACE_IF:\n        command += f' --trace-if \"{PYMUPDF_SETUP_MUPDF_TRACE_IF}\"'\n    if 'p' in PYMUPDF_SETUP_FLAVOUR:\n        command += ' all'\n    else:\n        command += ' m01'    # No need for C++/Python bindings.\n    command += f' && echo {unix_build_dir}:'\n    command += f' && ls -l {unix_build_dir}'\n\n    if os.environ.get( 'PYMUPDF_SETUP_MUPDF_REBUILD') == '0':\n        log( f'PYMUPDF_SETUP_MUPDF_REBUILD is \"0\" so not building MuPDF; would have run: {command}')\n    else:\n        log( f'Building MuPDF by running: {command}')\n        subprocess.run( command, shell=True, check=True)\n        log( f'Finished building mupdf.')\n    \n    return unix_build_dir\n\n\ndef get_mupdf_version(mupdf_dir):\n    path = f'{mupdf_dir}/include/mupdf/fitz/version.h'\n    with open(path) as f:\n        text = f.read()\n    v0 = re.search('#define FZ_VERSION_MAJOR ([0-9]+)', text)\n    v1 = re.search('#define FZ_VERSION_MINOR ([0-9]+)', text)\n    v2 = re.search('#define FZ_VERSION_PATCH ([0-9]+)', text)\n    assert v0 and v1 and v2, f'Cannot find MuPDF version numbers in {path=}.'\n    v0 = int(v0.group(1))\n    v1 = int(v1.group(1))\n    v2 = int(v2.group(1))\n    return v0, v1, v2\n\ndef _fs_update(text, path):\n    try:\n        with open( path) as f:\n            text0 = f.read()\n    except OSError:\n        text0 = None\n    print(f'path={path!r} text==text0={text==text0!r}')\n    if text != text0:\n        with open( path, 'w') as f:\n            f.write( text)\n    \n\ndef _build_extension( mupdf_local, mupdf_build_dir, build_type, g_py_limited_api):\n    '''\n    Builds Python extension module `_extra`.\n\n    Returns leafname of the generated shared libraries within mupdf_build_dir.\n    '''\n    (compiler_extra, linker_extra, includes, defines, optimise, debug, libpaths, libs, libraries) \\\n        = _extension_flags( mupdf_local, mupdf_build_dir, build_type)\n    log(f'_build_extension(): {g_py_limited_api=} {defines=}')\n    if mupdf_local:\n        includes = (\n                f'{mupdf_local}/platform/c++/include',\n                f'{mupdf_local}/include',\n                )\n    \n    log('Building PyMuPDF extension.')\n    compile_extra_cpp = ''\n    if darwin:\n        # Avoids `error: cannot pass object of non-POD type\n        # 'std::nullptr_t' through variadic function; call will abort at\n        # runtime` when compiling `mupdf::pdf_dict_getl(..., nullptr)`.\n        compile_extra_cpp += ' -Wno-non-pod-varargs'\n        # Avoid errors caused by mupdf's C++ bindings' exception classes\n        # not having `nothrow` to match the base exception class.\n        compile_extra_cpp += ' -std=c++14'\n    if windows:\n        wp = pipcl.wdev.WindowsPython()\n        libs = f'mupdfcpp{wp.cpu.windows_suffix}.lib'\n    else:\n        libs = ('mupdf', 'mupdfcpp')\n        libraries = [\n                f'{mupdf_build_dir}/libmupdf.so'\n                f'{mupdf_build_dir}/libmupdfcpp.so'\n                ]\n    \n    path_so_leaf = pipcl.build_extension(\n            name = 'extra',\n            path_i = f'{g_root}/src/extra.i',\n            outdir = f'{g_root}/src/build',\n            includes = includes,\n            defines = defines,\n            libpaths = libpaths,\n            libs = libs,\n            compiler_extra = compiler_extra + compile_extra_cpp,\n            linker_extra = linker_extra,\n            optimise = optimise,\n            debug = debug,\n            prerequisites_swig = None,\n            prerequisites_compile = f'{mupdf_local}/include',\n            prerequisites_link = libraries,\n            py_limited_api = g_py_limited_api,\n            swig = PYMUPDF_SETUP_SWIG,\n            nogil = (PYMUPDF_SETUP_FAKE_NOGIL=='1')\n            )\n    \n    return path_so_leaf\n\n\ndef _extension_flags( mupdf_local, mupdf_build_dir, build_type):\n    '''\n    Returns various flags to pass to pipcl.build_extension().\n    '''\n    compiler_extra = ''\n    linker_extra = ''\n    if build_type == 'memento':\n        compiler_extra += ' -DMEMENTO'\n    if mupdf_build_dir:\n        mupdf_build_dir_flags = os.path.basename( mupdf_build_dir).split( '-')\n    else:\n        mupdf_build_dir_flags = [build_type]\n    optimise = 'release' in mupdf_build_dir_flags\n    debug = 'debug' in mupdf_build_dir_flags\n    r_extra = ''\n    defines = list()\n    if windows:\n        defines.append('FZ_DLL_CLIENT')\n        wp = pipcl.wdev.WindowsPython()\n        if os.environ.get('PYMUPDF_SETUP_MUPDF_VS_UPGRADE') == '1':\n            # MuPDF C++ build uses a parallel build tree with updated VS files.\n            infix = 'win32-vs-upgrade'\n        else:\n            infix = 'win32'\n        build_type_infix = 'Debug' if debug else 'Release'\n        libpaths = (\n                f'{mupdf_local}\\\\platform\\\\{infix}\\\\{wp.cpu.windows_subdir}{build_type_infix}',\n                f'{mupdf_local}\\\\platform\\\\{infix}\\\\{wp.cpu.windows_subdir}{build_type_infix}Tesseract',\n                )\n        libs = f'mupdfcpp{wp.cpu.windows_suffix}.lib'\n        libraries = f'{mupdf_local}\\\\platform\\\\{infix}\\\\{wp.cpu.windows_subdir}{build_type_infix}\\\\{libs}'\n        compiler_extra = ''\n    else:\n        libs = ['mupdf']\n        compiler_extra += (\n                ' -Wall'\n                ' -Wno-deprecated-declarations'\n                ' -Wno-unused-const-variable'\n                )\n        if mupdf_local:\n            libpaths = (mupdf_build_dir,)\n            libraries = f'{mupdf_build_dir}/{libs[0]}'\n            if openbsd:\n                compiler_extra += ' -Wno-deprecated-declarations'\n        else:\n            libpaths = os.environ.get('PYMUPDF_MUPDF_LIB')\n            libraries = None\n            if libpaths:\n                libpaths = libpaths.split(':')\n    \n    if mupdf_local:\n        includes = (\n                f'{mupdf_local}/include',\n                f'{mupdf_local}/include/mupdf',\n                f'{mupdf_local}/thirdparty/freetype/include',\n                )\n    else:\n        # Use system MuPDF.\n        includes = list()\n        pi = os.environ.get('PYMUPDF_INCLUDES')\n        if pi:\n            includes += pi.split(':')\n        pmi = os.environ.get('PYMUPDF_MUPDF_INCLUDE')\n        if pmi:\n            includes.append(pmi)\n        ldflags = os.environ.get('LDFLAGS')\n        if ldflags:\n            linker_extra += f' {ldflags}'\n        cflags = os.environ.get('CFLAGS')\n        if cflags:\n            compiler_extra += f' {cflags}'\n        cxxflags = os.environ.get('CXXFLAGS')\n        if cxxflags:\n            compiler_extra += f' {cxxflags}'\n\n    return compiler_extra, linker_extra, includes, defines, optimise, debug, libpaths, libs, libraries, \n\n\ndef clean(all_):\n    pipcl.log(f'{all_=}')\n    ret = list()\n    ret.append(f'{g_root}/src/build')\n    \n    path_mupdf, _ = get_mupdf()\n    \n    # We remove mupdf directories directly with shutil.rmtree() instead of\n    # returning them to pipcl, because pipcl will deliberately fail if asked to\n    # remove things that are outside our checkout.\n    shutil.rmtree(f'{path_mupdf}/platform/c++', ignore_errors=True)\n    shutil.rmtree(f'{path_mupdf}/platform/python', ignore_errors=True)\n    \n    if all_:\n        # Clean mupdf C library.\n        shutil.rmtree(f'{path_mupdf}/build', ignore_errors=True)\n        shutil.rmtree(f'{path_mupdf}/platform/win32', ignore_errors=True)\n        shutil.rmtree(f'{path_mupdf}/platform/win32/Release', ignore_errors=True)\n        shutil.rmtree(f'{path_mupdf}/platform/win32/x64', ignore_errors=True)\n    \n    pipcl.log(f'Returning: {ret=}')\n    return ret\n\n\ndef sdist():\n    ret = list()\n    if PYMUPDF_SETUP_DUMMY == '1':\n        return ret\n    \n    if PYMUPDF_SETUP_FLAVOUR == 'b':\n        # Create a minimal sdist that will build/install a dummy PyMuPDFb.\n        for p in (\n                'setup.py',\n                'pipcl.py',\n                'wdev.py',\n                'pyproject.toml',\n                ):\n            ret.append(p)\n        ret.append(\n                (\n                    b'This file indicates that we are a PyMuPDFb sdist and should build/install a dummy PyMuPDFb package.\\n',\n                    g_pymupdfb_sdist_marker,\n                    )\n                )\n        return ret\n        \n    for p in pipcl.git_items( g_root):\n        if p.startswith(\n                (\n                    'docs/',\n                    'signatures/',\n                    '.',\n                )\n                ):\n            pass\n        else:\n            ret.append(p)\n    if 0:\n        tgz, mupdf_location = get_mupdf_tgz()\n        if tgz:\n            ret.append((tgz, mupdf_tgz))\n    else:\n        log(f'Not including MuPDF .tgz in sdist.')\n    return ret\n\n\nclassifier = [\n        'Development Status :: 5 - Production/Stable',\n        'Intended Audience :: Developers',\n        'Intended Audience :: Information Technology',\n        'Operating System :: MacOS',\n        'Operating System :: Microsoft :: Windows',\n        'Operating System :: POSIX :: Linux',\n        'Programming Language :: C',\n        'Programming Language :: C++',\n        'Programming Language :: Python :: 3 :: Only',\n        'Programming Language :: Python :: Implementation :: CPython',\n        'Topic :: Utilities',\n        'Topic :: Multimedia :: Graphics',\n        'Topic :: Software Development :: Libraries',\n        ]\n\n# We generate different wheels depending on PYMUPDF_SETUP_FLAVOUR.\n#\n\n# PyMuPDF version.\nversion_p = '1.27.2.3'\n\nversion_mupdf = '1.27.2'\n\n# PyMuPDFb version. This is the PyMuPDF version whose PyMuPDFb wheels we will\n# (re)use if generating separate PyMuPDFb wheels. Though as of PyMuPDF-1.24.11\n# (2024-10-03) we no longer use PyMuPDFb wheels so this is actually unused.\n#\nversion_b = '1.26.3'\n\nif os.path.exists(f'{g_root}/{g_pymupdfb_sdist_marker}'):\n    \n    # We are in a PyMuPDFb sdist. We specify a dummy package so that pip builds\n    # from sdists work - pip's build using PyMuPDF's sdist will already create\n    # the required binaries, but pip will still see `requires_dist` set to\n    # 'PyMuPDFb', so will also download and build PyMuPDFb's sdist.\n    #\n    log(f'Specifying dummy PyMuPDFb wheel.')\n    \n    def get_requires_for_build_wheel(config_settings=None):\n        return list()\n    \n    p = pipcl.Package(\n            'PyMuPDFb',\n            version_b,\n            summary = 'Dummy PyMuPDFb wheel',\n            description = '',\n            author = 'Artifex',\n            author_email = 'support@artifex.com',\n            license = 'GNU AFFERO GPL 3.0',\n            tag_python = 'py3',\n            )\n\nelse:\n    # A normal PyMuPDF package.\n    \n    with open( f'{g_root}/README.md', encoding='utf-8') as f:\n        readme_p = f.read()\n\n    with open( f'{g_root}/READMEb.md', encoding='utf-8') as f:\n        readme_b = f.read()\n\n    with open( f'{g_root}/READMEd.md', encoding='utf-8') as f:\n        readme_d = f.read()\n\n    tag_python = None\n    requires_dist = list()\n    entry_points = None\n    \n    if 'p' in PYMUPDF_SETUP_FLAVOUR:\n        version = version_p\n        name = 'PyMuPDF'\n        readme = readme_p\n        summary = 'A high performance Python library for data extraction, analysis, conversion & manipulation of PDF (and other) documents.'\n        if 'b' not in PYMUPDF_SETUP_FLAVOUR:\n            requires_dist.append(f'PyMuPDFb =={version_b}')\n        # Create a `pymupdf` command.\n        entry_points = textwrap.dedent('''\n                [console_scripts]\n                pymupdf = pymupdf.__main__:main\n                ''')\n    elif 'b' in PYMUPDF_SETUP_FLAVOUR:\n        version = version_b\n        name = 'PyMuPDFb'\n        readme = readme_b\n        summary = 'MuPDF shared libraries for PyMuPDF.'\n        tag_python = 'py3'\n    elif 'd' in PYMUPDF_SETUP_FLAVOUR:\n        version = version_b\n        name = 'PyMuPDFd'\n        readme = readme_d\n        summary = 'MuPDF build-time files for PyMuPDF.'\n        tag_python = 'py3'\n    else:\n        assert 0, f'Unrecognised {PYMUPDF_SETUP_FLAVOUR=}.'\n    \n    if os.environ.get('PYODIDE_ROOT'):\n        # We can't pip install pytest on pyodide, so specify it here.\n        requires_dist.append('pytest')\n\n    p = pipcl.Package(\n            name,\n            version,\n            summary = summary,\n            description = readme,\n            description_content_type = 'text/markdown',\n            classifier = classifier,\n            author = 'Artifex',\n            author_email = 'support@artifex.com',\n            requires_dist = requires_dist,\n            requires_python = '>=3.10',\n            license = 'Dual Licensed - GNU AFFERO GPL 3.0 or Artifex Commercial License',\n            project_url = [\n                ('Documentation, https://pymupdf.readthedocs.io/'),\n                ('Source, https://github.com/pymupdf/pymupdf'),\n                ('Tracker, https://github.com/pymupdf/PyMuPDF/issues'),\n                ('Changelog, https://pymupdf.readthedocs.io/en/latest/changes.html'),\n                ],\n        \n            entry_points = entry_points,\n        \n            fn_build=build,\n            fn_clean=clean,\n            fn_sdist=sdist,\n        \n            tag_python=tag_python,\n            py_limited_api=g_py_limited_api,\n\n            # 30MB: 9 ZIP_DEFLATED\n            # 28MB: 9 ZIP_BZIP2\n            # 23MB: 9 ZIP_LZMA\n            #wheel_compression = zipfile.ZIP_DEFLATED if (darwin or pyodide) else zipfile.ZIP_LZMA,\n            wheel_compresslevel = 9,\n            )\n\n    def get_requires_for_build_wheel(config_settings=None):\n        '''\n        Adds to pyproject.toml:[build-system]:requires, allowing programmatic\n        control over what packages we require.\n        '''\n        def platform_release_tuple():\n            r = platform.release()\n            r = r.split('.')\n            r = tuple(int(i) for i in r)\n            log(f'platform_release_tuple() returning {r=}.')\n            return r\n            \n        ret = list()\n        libclang = os.environ.get('PYMUPDF_SETUP_LIBCLANG')\n        if libclang:\n            print(f'Overriding to use {libclang=}.')\n            ret.append(libclang)\n        elif openbsd:\n            print(f'OpenBSD: libclang not available via pip; assuming `pkg_add py3-llvm`.')\n        elif darwin and platform_release_tuple() < (18,):\n            # There are still of problems when building on old macos.\n            ret.append('libclang==14.0.6')\n        else:\n            ret.append('libclang')\n        if msys2:\n            print(f'msys2: pip install of swig does not build; assuming `pacman -S swig`.')\n        elif openbsd:\n            print(f'OpenBSD: pip install of swig does not build; assuming `pkg_add swig`.')\n        elif PYMUPDF_SETUP_SWIG:\n            pass\n        elif darwin and python_version_tuple < (3, 13):\n            # Latest swig-4.4.1 gives director errors on macos with python<3.13.\n            ret.append('swig==4.3.1')\n        else:\n            ret.append('swig')\n        return ret\n\n\nif PYMUPDF_SETUP_URL_WHEEL:\n    def build_wheel(\n            wheel_directory,\n            config_settings=None,\n            metadata_directory=None,\n            p=p,\n            ):\n        '''\n        Instead of building wheel, we look for and copy a wheel from location\n        specified by PYMUPDF_SETUP_URL_WHEEL.\n        '''\n        log(f'{PYMUPDF_SETUP_URL_WHEEL=}')\n        log(f'{p.wheel_name()=}')\n        url = PYMUPDF_SETUP_URL_WHEEL\n        if url.startswith(('http://', 'https://')):\n            leaf = p.wheel_name()\n            out_path = f'{wheel_directory}{leaf}'\n            out_path_temp = out_path + '-'\n            if url.endswith('/'):\n                url += leaf\n            log(f'Downloading from {url=} to {out_path_temp=}.')\n            urllib.request.urlretrieve(url, out_path_temp)\n        elif url.startswith(f'file://'):\n            in_path = url[len('file://'):]\n            log(f'{in_path=}')\n            if in_path.endswith('/'):\n                # Look for matching wheel within this directory.\n                wheels = glob.glob(f'{in_path}*.whl')\n                log(f'{len(wheels)=}')\n                for in_path in wheels:\n                    log(f'{in_path=}')\n                    leaf = os.path.basename(in_path)\n                    if p.wheel_name_match(leaf):\n                        log(f'Match: {in_path=}')\n                        break\n                else:\n                    message = f'Cannot find matching for {p.wheel_name()=} in ({len(wheels)=}):\\n'\n                    wheels_text = ''\n                    for wheel in wheels:\n                        wheels_text += f'    {wheel}\\n'\n                    assert 0, f'Cannot find matching for {p.wheel_name()=} in:\\n{wheels_text}'\n            else:\n                leaf = os.path.basename(in_path)\n            out_path = os.path.join(wheel_directory, leaf)\n            out_path_temp = out_path + '-'\n            log(f'Copying from {in_path=} to {out_path_temp=}.')\n            shutil.copy2(in_path, out_path_temp)\n        else:\n            assert 0, f'Unrecognised prefix in {PYMUPDF_SETUP_URL_WHEEL=}.'\n        \n        log(f'Renaming from:\\n    {out_path_temp}\\nto:\\n    {out_path}.')\n        os.rename(out_path_temp, out_path)\n        return os.path.basename(out_path)\nelse:\n    build_wheel = p.build_wheel\n\nbuild_sdist = p.build_sdist\n\n\nif __name__ == '__main__':\n    p.handle_argv(sys.argv)\n"
  },
  {
    "path": "src/__init__.py",
    "content": "'''\nPyMuPDF implemented on top of MuPDF Python bindings.\n\nLicense:\n\n    SPDX-License-Identifier: GPL-3.0-only\n'''\n\nfrom __future__ import annotations\n\n# To reduce startup times, we don't import everything we require here.\n#\nimport atexit\nimport binascii\nimport collections\nimport glob\nimport importlib.util\nimport inspect\nimport io\nimport math\nimport os\nimport pathlib\nimport re\nimport string\nimport sys\nimport tarfile\nimport time\nimport typing\nimport warnings\nimport weakref\nimport zipfile\n\nfrom . import extra\n\n# Set up g_out_log and g_out_message from environment variables.\n#\n# PYMUPDF_MESSAGE controls the destination of user messages (from function\n# `pymupdf.message()`).\n#\n# PYMUPDF_LOG controls the destination of internal development logging (from\n# function `pymupdf.log()`).\n#\n# For syntax, see _make_output()'s `text` arg.\n#\n\ndef _make_output(\n        *,\n        text=None,\n        fd=None,\n        stream=None,\n        path=None,\n        path_append=None,\n        pylogging=None,\n        pylogging_logger=None,\n        pylogging_level=None,\n        pylogging_name=None,\n        default=None,\n        ):\n    '''\n    Returns a stream that writes to a specified destination, which can be a\n    file descriptor, a file, an existing stream or Python's `logging' system.\n    \n    Args:\n        text: text specification of destination.\n            fd:<int> - write to file descriptor.\n            path:<str> - write to file.\n            path+:<str> - append to file.\n            logging:<items> - write to Python `logging` module.\n                items: comma-separated <name=value> pairs.\n                    level=<int>\n                    name=<str>.\n                Other names are ignored.\n        \n        fd: an int file descriptor.\n        stream: something with methods .write(text) and .flush().\n            If specified we simply return <stream>.\n        path: a file path.\n            If specified we return a stream that writes to this file.\n        path_append: a file path.\n            If specified we return a stream that appends to this file.\n        pylogging*:\n            if any of these args is not None, we return a stream that writes to\n            Python's `logging` module.\n            \n            pylogging:\n                Unused other than to activate use of logging module.\n            pylogging_logger:\n                A logging.Logger; If None, set from <pylogging_name>.\n            pylogging_level:\n                An int log level, if None we use\n                pylogging_logger.getEffectiveLevel().\n            pylogging_name:\n                Only used if <pylogging_logger> is None:\n                    If <pylogging_name> is None, we set it to 'pymupdf'.\n                    Then we do: pylogging_logger = logging.getLogger(pylogging_name)\n    '''\n    if text is not None:\n        # Textual specification, for example from from environment variable.\n        if text.startswith('fd:'):\n            fd = int(text[3:])\n        elif text.startswith('path:'):\n            path = text[5:]\n        elif text.startswith('path+'):\n            path_append = text[5:]\n        elif text.startswith('logging:'):\n            pylogging = True\n            items_d = dict()\n            items = text[8:].split(',')\n            #items_d = {n: v for (n, v) in [item.split('=', 1) for item in items]}\n            for item in items:\n                if not item:\n                    continue\n                nv = item.split('=', 1)\n                assert len(nv) == 2, f'Need `=` in {item=}.'\n                n, v = nv\n                items_d[n] = v\n            pylogging_level = items_d.get('level')\n            if pylogging_level is not None:\n                pylogging_level = int(pylogging_level)\n            pylogging_name = items_d.get('name', 'pymupdf')\n        else:\n            assert 0, f'Expected prefix `fd:`, `path:`. `path+:` or `logging:` in {text=}.'\n    \n    if fd is not None:\n        ret = io.open(fd, mode='w', closefd=False)\n    elif stream is not None:\n        assert hasattr(stream, 'write')\n        assert hasattr(stream, 'flush')\n        ret = stream\n    elif path is not None:\n        ret = io.open(path, 'w')\n    elif path_append is not None:\n        ret = io.open(path_append, 'a')\n    elif (0\n            or pylogging is not None\n            or pylogging_logger is not None\n            or pylogging_level is not None\n            or pylogging_name is not None\n            ):\n        import logging\n        if pylogging_logger is None:\n            if pylogging_name is None:\n                pylogging_name = 'pymupdf'\n            pylogging_logger = logging.getLogger(pylogging_name)\n        assert isinstance(pylogging_logger, logging.Logger)\n        if pylogging_level is None:\n            pylogging_level = pylogging_logger.getEffectiveLevel()\n        class Out:\n            def write(self, text):\n                # `logging` module appends newlines, but so does the `print()`\n                # functions in our caller message() and log() fns, so we need to\n                # remove them here.\n                text = text.rstrip('\\n')\n                if text:\n                    pylogging_logger.log(pylogging_level, text)\n            def flush(self):\n                pass\n        ret = Out()\n    else:\n        ret = default\n    return ret\n\n# Set steam used by PyMuPDF messaging.\n_g_out_message = _make_output(text=os.environ.get('PYMUPDF_MESSAGE'), default=sys.stdout)\n\n# Set steam used by PyMuPDF development/debugging logging.\n_g_out_log = _make_output(text=os.environ.get('PYMUPDF_LOG'), default=sys.stdout)\n\n# Things for testing logging.\n_g_log_items = list()\n_g_log_items_active = False\n\ndef _log_items():\n    return _g_log_items\n\ndef _log_items_active(active):\n    global _g_log_items_active\n    _g_log_items_active = active\n        \ndef _log_items_clear():\n    del _g_log_items[:]\n\n\ndef set_messages(\n        *,\n        text=None,\n        fd=None,\n        stream=None,\n        path=None,\n        path_append=None,\n        pylogging=None,\n        pylogging_logger=None,\n        pylogging_level=None,\n        pylogging_name=None,\n        ):\n    '''\n    Sets destination of PyMuPDF messages. See _make_output() for details.\n    '''\n    global _g_out_message\n    _g_out_message = _make_output(\n            text=text,\n            fd=fd,\n            stream=stream,\n            path=path,\n            path_append=path_append,\n            pylogging=pylogging,\n            pylogging_logger=pylogging_logger,\n            pylogging_level=pylogging_level,\n            pylogging_name=pylogging_name,\n            default=_g_out_message,\n            )\n\ndef set_log(\n        *,\n        text=None,\n        fd=None,\n        stream=None,\n        path=None,\n        path_append=None,\n        pylogging=None,\n        pylogging_logger=None,\n        pylogging_level=None,\n        pylogging_name=None,\n        ):\n    '''\n    Sets destination of PyMuPDF development/debugging logging. See\n    _make_output() for details.\n    '''\n    global _g_out_log\n    _g_out_log = _make_output(\n            text=text,\n            fd=fd,\n            stream=stream,\n            path=path,\n            path_append=path_append,\n            pylogging=pylogging,\n            pylogging_logger=pylogging_logger,\n            pylogging_level=pylogging_level,\n            pylogging_name=pylogging_name,\n            default=_g_out_log,\n            )\n\ndef log( text='', caller=1):\n    '''\n    For development/debugging diagnostics.\n    '''\n    try:\n        stack = inspect.stack(context=0)\n    except StopIteration:\n        pass\n    else:\n        frame_record = stack[caller]\n        try:\n            filename = os.path.relpath(frame_record.filename)\n        except Exception:   # Can fail on windows.\n            filename = frame_record.filename\n        line = frame_record.lineno\n        function = frame_record.function\n        text = f'{filename}:{line}:{function}(): {text}'\n        del stack\n        # Leaving <stack> to be garbage collected, appears to change behaviour.\n    if _g_log_items_active:\n        _g_log_items.append(text)\n    if _g_out_log:\n        print(text, file=_g_out_log, flush=1)\n\n\ndef message(text=''):\n    '''\n    For user messages.\n    '''\n    # It looks like `print()` does nothing if sys.stdout is None (without\n    # raising an exception), but we don't rely on this.\n    if _g_out_message:\n        print(text, file=_g_out_message, flush=1)\n\n\ndef exception_info():\n    import traceback\n    log(f'exception_info:')\n    log(traceback.format_exc())\n\n\n# PDF names must not contain these characters:\nINVALID_NAME_CHARS = set(string.whitespace + \"()<>[]{}/%\" + chr(0))\n\ndef get_env_bool( name, default):\n    '''\n    Returns `True`, `False` or `default` depending on whether $<name> is '1',\n    '0' or unset. Otherwise assert-fails.\n    '''\n    v = os.environ.get( name)\n    if v is None:\n        ret = default\n    elif v == '1':\n        ret = True\n    elif v == '0':\n        ret = False\n    else:\n        assert 0, f'Unrecognised value for {name}: {v!r}'\n    if ret != default:\n        log(f'Using non-default setting from {name}: {v!r}')\n    return ret\n\ndef get_env_int( name, default):\n    '''\n    Returns `True`, `False` or `default` depending on whether $<name> is '1',\n    '0' or unset. Otherwise assert-fails.\n    '''\n    v = os.environ.get( name)\n    if v is None:\n        ret = default\n    else:\n        ret = int(v)\n    if ret != default:\n        log(f'Using non-default setting from {name}: {v}')\n    return ret\n\n# All our `except ...` blocks output diagnostics if `g_exceptions_verbose` is\n# true.\ng_exceptions_verbose = get_env_int( 'PYMUPDF_EXCEPTIONS_VERBOSE', 1)\n\n# $PYMUPDF_USE_EXTRA overrides whether to use optimised C fns in `extra`.\n#\ng_use_extra = get_env_bool( 'PYMUPDF_USE_EXTRA', True)\n\n\n# Global switches\n#\n\nclass _Globals:\n    def __init__(self):\n        self.no_device_caching = 0\n        self.small_glyph_heights = 0\n        self.subset_fontnames = 0\n        self.skip_quad_corrections = 0\n\n_globals = _Globals()\n\n_get_layout: typing.Optional[typing.Callable] = None\n\n# global switch ensuring that the recommendation message is shown at most once\n_recommend_layout = True  # must be referred to as \"global\" everywhere\n\n\ndef no_recommend_layout():\n    \"\"\"For users who never want to see the layout recommendation.\"\"\"\n    global _recommend_layout\n    _recommend_layout = False\n\n\ndef _warn_layout_once():\n    \"\"\"Check if we should recommend installing the layout package.\"\"\"\n    msg=\"\"\"Consider using the pymupdf_layout package for a greatly improved page layout analysis.\"\"\"\n\n    global _recommend_layout\n    if (\n        1\n        and _recommend_layout  # still True?\n        and _get_layout is None  # no layout function stored here\n\n        # client did not globally disable the recommendation\n        and os.getenv(\"PYMUPDF_SUGGEST_LAYOUT_ANALYZER\") != \"0\"\n\n        # layout is not available in this Python\n        and not importlib.util.find_spec(\"pymupdf.layout\")\n    ):\n        print(msg)\n        _recommend_layout = False  # never show the message again\n\n\n# Optionally use MuPDF via cppyy bindings; experimental and not tested recently\n# as of 2023-01-20 11:51:40\n#\nmupdf_cppyy = os.environ.get( 'MUPDF_CPPYY')\nif mupdf_cppyy is not None:\n    # pylint: disable=all\n    log( f'{__file__}: $MUPDF_CPPYY={mupdf_cppyy!r} so attempting to import mupdf_cppyy.')\n    log( f'{__file__}: $PYTHONPATH={os.environ[\"PYTHONPATH\"]}')\n    if mupdf_cppyy == '':\n        import mupdf_cppyy\n    else:\n        import importlib\n        mupdf_cppyy = importlib.machinery.SourceFileLoader(\n                'mupdf_cppyy',\n                mupdf_cppyy\n                ).load_module()\n    mupdf = mupdf_cppyy.cppyy.gbl.mupdf\nelse:\n    # Use MuPDF Python SWIG bindings. We allow import from either our own\n    # directory for conventional wheel installs, or from separate place in case\n    # we are using a separately-installed system installation of mupdf.\n    #\n    try:\n        from . import mupdf\n    except Exception:\n        import mupdf\n    if hasattr(mupdf, 'internal_check_ndebug'):\n        mupdf.internal_check_ndebug()\n    mupdf.reinit_singlethreaded()\n\ndef _int_rc(text):\n    '''\n    Converts string to int, ignoring trailing 'rc...'.\n    '''\n    rc = text.find('rc')\n    if rc >= 0:\n        text = text[:rc]\n    return int(text)\n\n# Basic version information.\n#\n# (We use `noqa F401` to avoid flake8 errors such as `F401\n# '._build.mupdf_location' imported but unused`.\n#\nfrom ._build import mupdf_location      # noqa F401\nfrom ._build import pymupdf_git_branch  # noqa F401\nfrom ._build import pymupdf_git_diff    # noqa F401\nfrom ._build import pymupdf_git_sha     # noqa F401\nfrom ._build import pymupdf_version     # noqa F401\nfrom ._build import pymupdf_version_tuple   # noqa F401\nfrom ._build import swig_version        # noqa F401\nfrom ._build import swig_version_tuple  # noqa F401\n\nmupdf_version = mupdf.FZ_VERSION\n\n# Removed in PyMuPDF-1.26.1.\npymupdf_date = None\n\n# Versions as tuples; useful when comparing versions.\n#\nmupdf_version_tuple = tuple( [_int_rc(i) for i in mupdf_version.split('.')])\n\nassert mupdf_version_tuple == (mupdf.FZ_VERSION_MAJOR, mupdf.FZ_VERSION_MINOR, mupdf.FZ_VERSION_PATCH), \\\n        f'Inconsistent MuPDF version numbers: {mupdf_version_tuple=} != {(mupdf.FZ_VERSION_MAJOR, mupdf.FZ_VERSION_MINOR, mupdf.FZ_VERSION_PATCH)=}'\n\n# Legacy version information.\n#\nversion = (pymupdf_version, mupdf_version, None)\nVersionFitz = mupdf_version\nVersionBind = pymupdf_version\nVersionDate = None\n\n\n# String formatting.\n\ndef _format_g(value, *, fmt='%g'):\n    '''\n    Returns `value` formatted with mupdf.fz_format_double() if available,\n    otherwise with Python's `%`.\n\n    If `value` is a list or tuple, we return a space-separated string of\n    formatted values.\n    '''\n    if isinstance(value, (list, tuple)):\n        ret = ''\n        for v in value:\n            if ret:\n                ret += ' '\n            ret += _format_g(v, fmt=fmt)\n        return ret\n    else:\n        return mupdf.fz_format_double(fmt, value)\n        \nformat_g = _format_g\n\n# ByteString is gone from typing in 3.14.\n# collections.abc.Buffer available from 3.12 only\ntry:\n    ByteString = typing.ByteString\nexcept AttributeError:\n    ByteString = bytes | bytearray | memoryview\n\n# Names required by class method typing annotations.\nOptBytes = typing.Optional[ByteString]\nOptDict = typing.Optional[dict]\nOptFloat = typing.Optional[float]\nOptInt = typing.Union[int, None]\nOptSeq = typing.Optional[typing.Sequence]\nOptStr = typing.Optional[str]\n\nmatrix_like = 'matrix_like'\npoint_like = 'point_like'\nquad_like = 'quad_like'\nrect_like = 'rect_like'\n\n\ndef _as_fz_document(document):\n    '''\n    Returns document as a mupdf.FzDocument, upcasting as required. Raises\n    'document closed' exception if closed.\n    '''\n    if isinstance(document, Document):\n        if document.is_closed:\n            raise ValueError('document closed')\n        document = document.this\n    if isinstance(document, mupdf.FzDocument):\n        return document\n    elif isinstance(document, mupdf.PdfDocument):\n        return document.super()\n    elif document is None:\n        assert 0, f'document is None'\n    else:\n        assert 0, f'Unrecognised {type(document)=}'\n\ndef _as_pdf_document(document, required=True):\n    '''\n    Returns `document` downcast to a mupdf.PdfDocument. If downcast fails (i.e.\n    `document` is not actually a `PdfDocument`) then we assert-fail if `required`\n    is true (the default) else return a `mupdf.PdfDocument` with `.m_internal`\n    false.\n    '''\n    if isinstance(document, Document):\n        if document.is_closed:\n            raise ValueError('document closed')\n        document = document.this\n    if isinstance(document, mupdf.PdfDocument):\n        return document\n    elif isinstance(document, mupdf.FzDocument):\n        ret = mupdf.PdfDocument(document)\n        if required:\n            assert ret.m_internal\n        return ret\n    elif document is None:\n        assert 0, f'document is None'\n    else:\n        assert 0, f'Unrecognised {type(document)=}'\n\ndef _as_fz_page(page):\n    '''\n    Returns page as a mupdf.FzPage, upcasting as required.\n    '''\n    if isinstance(page, Page):\n        page = page.this\n    if isinstance(page, mupdf.PdfPage):\n        return page.super()\n    elif isinstance(page, mupdf.FzPage):\n        return page\n    elif page is None:\n        assert 0, f'page is None'\n    else:\n        assert 0, f'Unrecognised {type(page)=}'\n\ndef _as_pdf_page(page, required=True):\n    '''\n    Returns `page` downcast to a mupdf.PdfPage. If downcast fails (i.e. `page`\n    is not actually a `PdfPage`) then we assert-fail if `required` is true (the\n    default) else return a `mupdf.PdfPage` with `.m_internal` false.\n    '''\n    if isinstance(page, Page):\n        page = page.this\n    if isinstance(page, mupdf.PdfPage):\n        return page\n    elif isinstance(page, mupdf.FzPage):\n        ret = mupdf.pdf_page_from_fz_page(page)\n        if required:\n            assert ret.m_internal\n        return ret\n    elif page is None:\n        assert 0, f'page is None'\n    else:\n        assert 0, f'Unrecognised {type(page)=}'\n\n\ndef _pdf_annot_page(annot):\n    '''\n    Wrapper for mupdf.pdf_annot_page() which raises an exception if <annot>\n    is not bound to a page instead of returning a mupdf.PdfPage with\n    `.m_internal=None`.\n\n    [Some other MuPDF functions such as pdf_update_annot()` already raise a\n    similar exception if a pdf_annot's .page field is null.]\n    '''\n    page = mupdf.pdf_annot_page(annot)\n    if not page.m_internal:\n        raise RuntimeError('Annot is not bound to a page')\n    return page\n\n\n# Fixme: we don't support JM_MEMORY=1.\nJM_MEMORY = 0\n\n# Classes\n#\n\nclass Annot:\n\n    def __init__(self, annot):\n        assert isinstance( annot, mupdf.PdfAnnot)\n        self.this = annot\n    \n    def __bool__(self):\n        return bool(self.this)\n\n    def __repr__(self):\n        parent = getattr(self, 'parent', '<>')\n        return f\"'{self.type[1]}' annotation on {parent}\"\n\n    def __str__(self):\n        return self.__repr__()\n\n    def _erase(self):\n        if getattr(self, \"thisown\", False):\n            self.thisown = False\n\n    def _get_redact_values(self):\n        annot = self.this\n        if mupdf.pdf_annot_type(annot) != mupdf.PDF_ANNOT_REDACT:\n            return\n\n        values = dict()\n        try:\n            obj = mupdf.pdf_dict_gets(mupdf.pdf_annot_obj(annot), \"RO\")\n            if obj.m_internal:\n                message_warning(\"Ignoring redaction key '/RO'.\")\n                xref = mupdf.pdf_to_num(obj)\n                values[dictkey_xref] = xref\n            obj = mupdf.pdf_dict_gets(mupdf.pdf_annot_obj(annot), \"OverlayText\")\n            if obj.m_internal:\n                text = mupdf.pdf_to_text_string(obj)\n                values[dictkey_text] = JM_UnicodeFromStr(text)\n            else:\n                values[dictkey_text] = ''\n            obj = mupdf.pdf_dict_get(mupdf.pdf_annot_obj(annot), PDF_NAME('Q'))\n            align = 0\n            if obj.m_internal:\n                align = mupdf.pdf_to_int(obj)\n            values[dictkey_align] = align\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            return\n        val = values\n\n        if not val:\n            return val\n        val[\"rect\"] = self.rect\n        text_color, fontname, fontsize = TOOLS._parse_da(self)\n        val[\"text_color\"] = text_color\n        val[\"fontname\"] = fontname\n        val[\"fontsize\"] = fontsize\n        fill = self.colors[\"fill\"]\n        val[\"fill\"] = fill\n        return val\n\n    def _getAP(self):\n        if g_use_extra:\n            assert isinstance( self.this, mupdf.PdfAnnot)\n            ret = extra.Annot_getAP(self.this)\n            assert isinstance( ret, bytes)\n            return ret\n        else:\n            r = None\n            res = None\n            annot = self.this\n            assert isinstance( annot, mupdf.PdfAnnot)\n            annot_obj = mupdf.pdf_annot_obj( annot)\n            ap = mupdf.pdf_dict_getl( annot_obj, PDF_NAME('AP'), PDF_NAME('N'))\n            if mupdf.pdf_is_stream( ap):\n                res = mupdf.pdf_load_stream( ap)\n            if res and res.m_internal:\n                r = JM_BinFromBuffer(res)\n            return r\n\n    def _setAP(self, buffer_, rect=0):\n        try:\n            annot = self.this\n            annot_obj = mupdf.pdf_annot_obj( annot)\n            page = _pdf_annot_page(annot)\n            apobj = mupdf.pdf_dict_getl( annot_obj, PDF_NAME('AP'), PDF_NAME('N'))\n            if not apobj.m_internal:\n                raise RuntimeError( MSG_BAD_APN)\n            if not mupdf.pdf_is_stream( apobj):\n                raise RuntimeError( MSG_BAD_APN)\n            res = JM_BufferFromBytes( buffer_)\n            if not res.m_internal:\n                raise ValueError( MSG_BAD_BUFFER)\n            JM_update_stream( page.doc(), apobj, res, 1)\n            if rect:\n                bbox = mupdf.pdf_dict_get_rect( annot_obj, PDF_NAME('Rect'))\n                mupdf.pdf_dict_put_rect( apobj, PDF_NAME('BBox'), bbox)\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n\n    def _update_appearance(self, opacity=-1, blend_mode=None, fill_color=None, rotate=-1):\n        annot = self.this\n        assert annot.m_internal\n        annot_obj = mupdf.pdf_annot_obj( annot)\n        page = _pdf_annot_page(annot)\n        pdf = page.doc()\n        type_ = mupdf.pdf_annot_type( annot)\n        nfcol, fcol = JM_color_FromSequence(fill_color)\n\n        try:\n            # remove fill color from unsupported annots\n            # or if so requested\n            if nfcol == 0 or type_ not in (\n                    mupdf.PDF_ANNOT_SQUARE,\n                    mupdf.PDF_ANNOT_CIRCLE,\n                    mupdf.PDF_ANNOT_LINE,\n                    mupdf.PDF_ANNOT_POLY_LINE,\n                    mupdf.PDF_ANNOT_POLYGON\n                    ):\n                mupdf.pdf_dict_del( annot_obj, PDF_NAME('IC'))\n            elif nfcol > 0:\n                mupdf.pdf_set_annot_interior_color( annot, fcol[:nfcol])\n\n            insert_rot = 1 if rotate >= 0 else 0\n            if type_ not in (\n                    mupdf.PDF_ANNOT_CARET,\n                    mupdf.PDF_ANNOT_CIRCLE,\n                    mupdf.PDF_ANNOT_FREE_TEXT,\n                    mupdf.PDF_ANNOT_FILE_ATTACHMENT,\n                    mupdf.PDF_ANNOT_INK,\n                    mupdf.PDF_ANNOT_LINE,\n                    mupdf.PDF_ANNOT_POLY_LINE,\n                    mupdf.PDF_ANNOT_POLYGON,\n                    mupdf.PDF_ANNOT_SQUARE,\n                    mupdf.PDF_ANNOT_STAMP,\n                    mupdf.PDF_ANNOT_TEXT,\n                    ):\n                insert_rot = 0\n\n            if insert_rot:\n                mupdf.pdf_dict_put_int(annot_obj, PDF_NAME('Rotate'), rotate)\n\n            # insert fill color\n            if type_ == mupdf.PDF_ANNOT_FREE_TEXT:\n                if nfcol > 0:\n                    mupdf.pdf_set_annot_color(annot, fcol[:nfcol])\n            elif nfcol > 0:\n                col = mupdf.pdf_new_array(page.doc(), nfcol)\n                for i in range( nfcol):\n                    mupdf.pdf_array_push_real(col, fcol[i])\n                mupdf.pdf_dict_put(annot_obj, PDF_NAME('IC'), col)\n            mupdf.pdf_dirty_annot(annot)\n            mupdf.pdf_update_annot(annot) # let MuPDF update\n            pdf.resynth_required = 0\n        except Exception as e:\n            if g_exceptions_verbose:\n                exception_info()\n            message( f'cannot update annot: {e}')\n            raise\n        \n        if (opacity < 0 or opacity >= 1) and not blend_mode:    # no opacity, no blend_mode\n            return True\n\n        try:    # create or update /ExtGState\n            ap = mupdf.pdf_dict_getl(\n                    mupdf.pdf_annot_obj(annot),\n                    PDF_NAME('AP'),\n                    PDF_NAME('N')\n                    )\n            if not ap.m_internal:   # should never happen\n                raise RuntimeError( MSG_BAD_APN)\n\n            resources = mupdf.pdf_dict_get( ap, PDF_NAME('Resources'))\n            if not resources.m_internal:    # no Resources yet: make one\n                resources = mupdf.pdf_dict_put_dict( ap, PDF_NAME('Resources'), 2)\n            \n            alp0 = mupdf.pdf_new_dict( page.doc(), 3)\n            if opacity >= 0 and opacity < 1:\n                mupdf.pdf_dict_put_real( alp0, PDF_NAME('CA'), opacity)\n                mupdf.pdf_dict_put_real( alp0, PDF_NAME('ca'), opacity)\n                mupdf.pdf_dict_put_real( annot_obj, PDF_NAME('CA'), opacity)\n\n            if blend_mode:\n                mupdf.pdf_dict_put_name( alp0, PDF_NAME('BM'), blend_mode)\n                mupdf.pdf_dict_put_name( annot_obj, PDF_NAME('BM'), blend_mode)\n\n            extg = mupdf.pdf_dict_get( resources, PDF_NAME('ExtGState'))\n            if not extg.m_internal: # no ExtGState yet: make one\n                extg = mupdf.pdf_dict_put_dict( resources, PDF_NAME('ExtGState'), 2)\n\n            mupdf.pdf_dict_put( extg, PDF_NAME('H'), alp0)\n\n        except Exception as e:\n            if g_exceptions_verbose:    exception_info()\n            message( f'cannot set opacity or blend mode\\n: {e}')\n            raise\n\n        return True\n\n    @property\n    def apn_bbox(self):\n        \"\"\"annotation appearance bbox\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        ap = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AP'), PDF_NAME('N'))\n        if not ap.m_internal:\n            val = JM_py_from_rect(mupdf.FzRect(mupdf.FzRect.Fixed_INFINITE))\n        else:\n            rect = mupdf.pdf_dict_get_rect(ap, PDF_NAME('BBox'))\n            val = JM_py_from_rect(rect)\n\n        val = Rect(val) * self.get_parent().transformation_matrix\n        val *= self.get_parent().derotation_matrix\n        return val\n\n    @property\n    def apn_matrix(self):\n        \"\"\"annotation appearance matrix\"\"\"\n        try:\n            CheckParent(self)\n            annot = self.this\n            assert isinstance(annot, mupdf.PdfAnnot)\n            ap = mupdf.pdf_dict_getl(\n                    mupdf.pdf_annot_obj(annot),\n                    mupdf.PDF_ENUM_NAME_AP,\n                    mupdf.PDF_ENUM_NAME_N\n                    )\n            if not ap.m_internal:\n                return JM_py_from_matrix(mupdf.FzMatrix())\n            mat = mupdf.pdf_dict_get_matrix(ap, mupdf.PDF_ENUM_NAME_Matrix)\n            val = JM_py_from_matrix(mat)\n\n            val = Matrix(val)\n\n            return val\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            raise\n\n    @property\n    def blendmode(self):\n        \"\"\"annotation BlendMode\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        obj = mupdf.pdf_dict_get(annot_obj, PDF_NAME('BM'))\n        blend_mode = None\n        if obj.m_internal:\n            blend_mode = JM_UnicodeFromStr(mupdf.pdf_to_name(obj))\n            return blend_mode\n        # loop through the /AP/N/Resources/ExtGState objects\n        obj = mupdf.pdf_dict_getl(\n                annot_obj,\n                PDF_NAME('AP'),\n                PDF_NAME('N'),\n                PDF_NAME('Resources'),\n                PDF_NAME('ExtGState'),\n                )\n        if mupdf.pdf_is_dict(obj):\n            n = mupdf.pdf_dict_len(obj)\n            for i in range(n):\n                obj1 = mupdf.pdf_dict_get_val(obj, i)\n                if mupdf.pdf_is_dict(obj1):\n                    m = mupdf.pdf_dict_len(obj1)\n                    for j in range(m):\n                        obj2 = mupdf.pdf_dict_get_key(obj1, j)\n                        if mupdf.pdf_objcmp(obj2, PDF_NAME('BM')) == 0:\n                            blend_mode = JM_UnicodeFromStr(mupdf.pdf_to_name(mupdf.pdf_dict_get_val(obj1, j)))\n                            return blend_mode\n        return blend_mode\n\n    @property\n    def border(self):\n        \"\"\"Border information.\"\"\"\n        CheckParent(self)\n        atype = self.type[0]\n        if atype not in (\n                mupdf.PDF_ANNOT_CIRCLE,\n                mupdf.PDF_ANNOT_FREE_TEXT,\n                mupdf.PDF_ANNOT_INK,\n                mupdf.PDF_ANNOT_LINE,\n                mupdf.PDF_ANNOT_POLY_LINE,\n                mupdf.PDF_ANNOT_POLYGON,\n                mupdf.PDF_ANNOT_SQUARE,\n                ):\n            return dict()\n        ao = mupdf.pdf_annot_obj(self.this)\n        ret = JM_annot_border(ao)\n        return ret\n\n    def clean_contents(self, sanitize=1):\n        \"\"\"Clean appearance contents stream.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        pdf = mupdf.pdf_get_bound_document(mupdf.pdf_annot_obj(annot))\n        filter_ = _make_PdfFilterOptions(recurse=1, instance_forms=0, ascii=0, sanitize=sanitize)\n        mupdf.pdf_filter_annot_contents(pdf, annot, filter_)\n\n    @property\n    def colors(self):\n        \"\"\"Color definitions.\"\"\"\n        try:\n            CheckParent(self)\n            annot = self.this\n            assert isinstance(annot, mupdf.PdfAnnot)\n            return JM_annot_colors(mupdf.pdf_annot_obj(annot))\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            raise\n\n    def delete_responses(self):\n        \"\"\"Delete 'Popup' and responding annotations.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        page = _pdf_annot_page(annot)\n        while 1:\n            irt_annot = JM_find_annot_irt(annot)\n            if not irt_annot:\n                break\n            mupdf.pdf_delete_annot(page, irt_annot)\n        mupdf.pdf_dict_del(annot_obj, PDF_NAME('Popup'))\n\n        annots = mupdf.pdf_dict_get(page.obj(), PDF_NAME('Annots'))\n        n = mupdf.pdf_array_len(annots)\n        found = 0\n        for i in range(n-1, -1, -1):\n            o = mupdf.pdf_array_get(annots, i)\n            p = mupdf.pdf_dict_get(o, PDF_NAME('Parent'))\n            if not o.m_internal:\n                continue\n            if not mupdf.pdf_objcmp(p, annot_obj):\n                mupdf.pdf_array_delete(annots, i)\n                found = 1\n        if found:\n            mupdf.pdf_dict_put(page.obj(), PDF_NAME('Annots'), annots)\n\n    @property\n    def file_info(self):\n        \"\"\"Attached file information.\"\"\"\n        CheckParent(self)\n        res = dict()\n        length = -1\n        size = -1\n        desc = None\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        type_ = mupdf.pdf_annot_type(annot)\n        if type_ != mupdf.PDF_ANNOT_FILE_ATTACHMENT:\n            raise TypeError( MSG_BAD_ANNOT_TYPE)\n        stream = mupdf.pdf_dict_getl(\n                annot_obj,\n                PDF_NAME('FS'),\n                PDF_NAME('EF'),\n                PDF_NAME('F'),\n                )\n        if not stream.m_internal:\n            RAISEPY( \"bad PDF: file entry not found\", JM_Exc_FileDataError)\n\n        fs = mupdf.pdf_dict_get(annot_obj, PDF_NAME('FS'))\n\n        o = mupdf.pdf_dict_get(fs, PDF_NAME('UF'))\n        if o.m_internal:\n            filename = mupdf.pdf_to_text_string(o)\n        else:\n            o = mupdf.pdf_dict_get(fs, PDF_NAME('F'))\n            if o.m_internal:\n                filename = mupdf.pdf_to_text_string(o)\n\n        o = mupdf.pdf_dict_get(fs, PDF_NAME('Desc'))\n        if o.m_internal:\n            desc = mupdf.pdf_to_text_string(o)\n\n        o = mupdf.pdf_dict_get(stream, PDF_NAME('Length'))\n        if o.m_internal:\n            length = mupdf.pdf_to_int(o)\n\n        o = mupdf.pdf_dict_getl(stream, PDF_NAME('Params'), PDF_NAME('Size'))\n        if o.m_internal:\n            size = mupdf.pdf_to_int(o)\n\n        res[ dictkey_filename] = JM_EscapeStrFromStr(filename)\n        res[ dictkey_descr] = JM_UnicodeFromStr(desc)\n        res[ dictkey_length] = length\n        res[ dictkey_size] = size\n        return res\n\n    @property\n    def flags(self):\n        \"\"\"Flags field.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        return mupdf.pdf_annot_flags(annot)\n\n    def get_file(self):\n        \"\"\"Retrieve attached file content.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        type = mupdf.pdf_annot_type(annot)\n        if type != mupdf.PDF_ANNOT_FILE_ATTACHMENT:\n            raise TypeError( MSG_BAD_ANNOT_TYPE)\n        stream = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('FS'), PDF_NAME('EF'), PDF_NAME('F'))\n        if not stream.m_internal:\n            RAISEPY( \"bad PDF: file entry not found\", JM_Exc_FileDataError)\n        buf = mupdf.pdf_load_stream(stream)\n        res = JM_BinFromBuffer(buf)\n        return res\n\n    def get_oc(self):\n        \"\"\"Get annotation optional content reference.\"\"\"\n        CheckParent(self)\n        oc = 0\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        obj = mupdf.pdf_dict_get(annot_obj, PDF_NAME('OC'))\n        if obj.m_internal:\n            oc = mupdf.pdf_to_num(obj)\n        return oc\n\n    # PyMuPDF doesn't seem to have this .parent member, but removing it breaks\n    # 11 tests...?\n    #@property\n    def get_parent(self):\n        try:\n            ret = getattr( self, 'parent')\n        except AttributeError:\n            page = _pdf_annot_page(self.this)\n            assert isinstance( page, mupdf.PdfPage)\n            document = Document( page.doc()) if page.m_internal else None\n            ret = Page(page, document)\n            #self.parent = weakref.proxy( ret)\n            self.parent = ret\n            #log(f'No attribute .parent: {type(self)=} {id(self)=}: have set {id(self.parent)=}.')\n            #log( f'Have set self.parent')\n        return ret\n\n    def get_pixmap(self, matrix=None, dpi=None, colorspace=None, alpha=0):\n        \"\"\"annotation Pixmap\"\"\"\n\n        CheckParent(self)\n        cspaces = {\"gray\": csGRAY, \"rgb\": csRGB, \"cmyk\": csCMYK}\n        if type(colorspace) is str:\n            colorspace = cspaces.get(colorspace.lower(), None)\n        if dpi:\n            matrix = Matrix(dpi / 72, dpi / 72)\n        ctm = JM_matrix_from_py(matrix)\n        cs = colorspace\n        if not cs:\n            cs = mupdf.fz_device_rgb()\n\n        pix = mupdf.pdf_new_pixmap_from_annot(self.this, ctm, cs, mupdf.FzSeparations(0), alpha)\n        ret = Pixmap(pix)\n        if dpi:\n            ret.set_dpi(dpi, dpi)\n        return ret\n\n    def get_sound(self):\n        \"\"\"Retrieve sound stream.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        type = mupdf.pdf_annot_type(annot)\n        sound = mupdf.pdf_dict_get(annot_obj, PDF_NAME('Sound'))\n        if type != mupdf.PDF_ANNOT_SOUND or not sound.m_internal:\n            raise TypeError( MSG_BAD_ANNOT_TYPE)\n        if mupdf.pdf_dict_get(sound, PDF_NAME('F')).m_internal:\n            RAISEPY( \"unsupported sound stream\", JM_Exc_FileDataError)\n        res = dict()\n        obj = mupdf.pdf_dict_get(sound, PDF_NAME('R'))\n        if obj.m_internal:\n            res['rate'] = mupdf.pdf_to_real(obj)\n        obj = mupdf.pdf_dict_get(sound, PDF_NAME('C'))\n        if obj.m_internal:\n            res['channels'] = mupdf.pdf_to_int(obj)\n        obj = mupdf.pdf_dict_get(sound, PDF_NAME('B'))\n        if obj.m_internal:\n            res['bps'] = mupdf.pdf_to_int(obj)\n        obj = mupdf.pdf_dict_get(sound, PDF_NAME('E'))\n        if obj.m_internal:\n            res['encoding'] = mupdf.pdf_to_name(obj)\n        obj = mupdf.pdf_dict_gets(sound, \"CO\")\n        if obj.m_internal:\n            res['compression'] = mupdf.pdf_to_name(obj)\n        buf = mupdf.pdf_load_stream(sound)\n        stream = JM_BinFromBuffer(buf)\n        res['stream'] = stream\n        return res\n    \n    def get_text(self, *args, **kwargs):\n        return utils.get_text(self, *args, **kwargs)\n\n    def get_textbox(self, *args, **kwargs):\n        return utils.get_textbox(self, *args, **kwargs)\n\n    def get_textpage(self, clip=None, flags=0):\n        \"\"\"Make annotation TextPage.\"\"\"\n        CheckParent(self)\n        options = mupdf.FzStextOptions(flags)\n        if clip:\n            assert hasattr(mupdf, 'FZ_STEXT_CLIP_RECT'), f'MuPDF-{mupdf_version} does not support FZ_STEXT_CLIP_RECT.'\n            clip2 = JM_rect_from_py(clip)\n            options.clip = clip2.internal()\n            options.flags |= mupdf.FZ_STEXT_CLIP_RECT\n        annot = self.this\n        stextpage = mupdf.FzStextPage(annot, options)\n        ret = TextPage(stextpage)\n        p = self.get_parent()\n        if isinstance(p, weakref.ProxyType):\n            ret.parent = p\n        else:\n            ret.parent = weakref.proxy(p)\n        return ret\n\n    @property\n    def has_popup(self):\n        \"\"\"Check if annotation has a Popup.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        obj = mupdf.pdf_dict_get(mupdf.pdf_annot_obj(annot), PDF_NAME('Popup'))\n        return True if obj.m_internal else False\n\n    @property\n    def info(self):\n        \"\"\"Various information details.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        res = dict()\n\n        res[dictkey_content] = JM_UnicodeFromStr(mupdf.pdf_annot_contents(annot))\n\n        o = mupdf.pdf_dict_get(mupdf.pdf_annot_obj(annot), PDF_NAME('Name'))\n        res[dictkey_name] = JM_UnicodeFromStr(mupdf.pdf_to_name(o))\n\n        # Title (= author)\n        o = mupdf.pdf_dict_get(mupdf.pdf_annot_obj(annot), PDF_NAME('T'))\n        res[dictkey_title] = JM_UnicodeFromStr(mupdf.pdf_to_text_string(o))\n\n        # CreationDate\n        o = mupdf.pdf_dict_gets(mupdf.pdf_annot_obj(annot), \"CreationDate\")\n        res[dictkey_creationDate] = JM_UnicodeFromStr(mupdf.pdf_to_text_string(o))\n\n        # ModDate\n        o = mupdf.pdf_dict_get(mupdf.pdf_annot_obj(annot), PDF_NAME('M'))\n        res[dictkey_modDate] = JM_UnicodeFromStr(mupdf.pdf_to_text_string(o))\n\n        # Subj\n        o = mupdf.pdf_dict_gets(mupdf.pdf_annot_obj(annot), \"Subj\")\n        res[dictkey_subject] = mupdf.pdf_to_text_string(o)\n\n        # Identification (PDF key /NM)\n        o = mupdf.pdf_dict_gets(mupdf.pdf_annot_obj(annot), \"NM\")\n        res[dictkey_id] = JM_UnicodeFromStr(mupdf.pdf_to_text_string(o))\n\n        return res\n\n    @property\n    def irt_xref(self):\n        '''\n        annotation IRT xref\n        '''\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj( annot)\n        irt = mupdf.pdf_dict_get( annot_obj, PDF_NAME('IRT'))\n        if not irt.m_internal:\n            return 0\n        return mupdf.pdf_to_num( irt)\n\n    @property\n    def is_open(self):\n        \"\"\"Get 'open' status of annotation or its Popup.\"\"\"\n        CheckParent(self)\n        return mupdf.pdf_annot_is_open(self.this)\n\n    @property\n    def language(self):\n        \"\"\"annotation language\"\"\"\n        this_annot = self.this\n        lang = mupdf.pdf_annot_language(this_annot)\n        if lang == mupdf.FZ_LANG_UNSET:\n            return\n        assert hasattr(mupdf, 'fz_string_from_text_language2')\n        return mupdf.fz_string_from_text_language2(lang)\n\n    @property\n    def line_ends(self):\n        \"\"\"Line end codes.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        # return nothing for invalid annot types\n        if not mupdf.pdf_annot_has_line_ending_styles(annot):\n            return\n        lstart = mupdf.pdf_annot_line_start_style(annot)\n        lend = mupdf.pdf_annot_line_end_style(annot)\n        return lstart, lend\n\n    @property\n    def next(self):\n        \"\"\"Next annotation.\"\"\"\n        CheckParent(self)\n        this_annot = self.this\n        assert isinstance(this_annot, mupdf.PdfAnnot)\n        assert this_annot.m_internal\n        type_ = mupdf.pdf_annot_type(this_annot)\n        if type_ != mupdf.PDF_ANNOT_WIDGET:\n            annot = mupdf.pdf_next_annot(this_annot)\n        else:\n            annot = mupdf.pdf_next_widget(this_annot)\n\n        val = Annot(annot) if annot.m_internal else None\n        if not val:\n            return None\n        val.thisown = True\n        assert val.get_parent().this.m_internal_value() == self.get_parent().this.m_internal_value()\n        val.parent._annot_refs[id(val)] = val\n\n        if val.type[0] == mupdf.PDF_ANNOT_WIDGET:\n            widget = Widget()\n            TOOLS._fill_widget(val, widget)\n            val = widget\n        return val\n\n    @property\n    def opacity(self):\n        \"\"\"Opacity.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        opy = -1\n        ca = mupdf.pdf_dict_get( mupdf.pdf_annot_obj(annot), mupdf.PDF_ENUM_NAME_CA)\n        if mupdf.pdf_is_number(ca):\n            opy = mupdf.pdf_to_real(ca)\n        return opy\n\n    @property\n    def popup_rect(self):\n        \"\"\"annotation 'Popup' rectangle\"\"\"\n        CheckParent(self)\n        rect = mupdf.FzRect(mupdf.FzRect.Fixed_INFINITE)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj( annot)\n        obj = mupdf.pdf_dict_get( annot_obj, PDF_NAME('Popup'))\n        if obj.m_internal:\n            rect = mupdf.pdf_dict_get_rect(obj, PDF_NAME('Rect'))\n            #log(f'{rect=}')\n        val = JM_py_from_rect(rect)\n        #log(f'{val=}')\n        \n        val = Rect(val) * self.get_parent().transformation_matrix\n        val *= self.get_parent().derotation_matrix\n        \n        return val\n\n    @property\n    def popup_xref(self):\n        \"\"\"annotation 'Popup' xref\"\"\"\n        CheckParent(self)\n        xref = 0\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        obj = mupdf.pdf_dict_get(annot_obj, PDF_NAME('Popup'))\n        if obj.m_internal:\n            xref = mupdf.pdf_to_num(obj)\n        return xref\n\n    @property\n    def rect(self):\n        \"\"\"annotation rectangle\"\"\"\n        if g_use_extra:\n            val = extra.Annot_rect3( self.this)\n        else:\n            val = mupdf.pdf_bound_annot(self.this)\n        val = Rect(val)\n        \n        # Caching self.parent_() reduces 1000x from 0.07 to 0.04.\n        #\n        p = self.get_parent()\n        #p = getattr( self, 'parent', None)\n        #if p is None:\n        #    p = self.parent\n        #    self.parent = p\n        #p = self.parent_()\n        val *= p.derotation_matrix\n        return val\n\n    @property\n    def rect_delta(self):\n        '''\n        annotation delta values to rectangle\n        '''\n        annot_obj = mupdf.pdf_annot_obj(self.this)\n        arr = mupdf.pdf_dict_get( annot_obj, PDF_NAME('RD'))\n        if mupdf.pdf_array_len( arr) == 4:\n            return (\n                    mupdf.pdf_to_real( mupdf.pdf_array_get( arr, 0)),\n                    mupdf.pdf_to_real( mupdf.pdf_array_get( arr, 1)),\n                    -mupdf.pdf_to_real( mupdf.pdf_array_get( arr, 2)),\n                    -mupdf.pdf_to_real( mupdf.pdf_array_get( arr, 3)),\n                    )\n\n    @property\n    def rotation(self):\n        \"\"\"annotation rotation\"\"\"\n        CheckParent(self)\n        annot = self.this\n        rotation = mupdf.pdf_dict_get( mupdf.pdf_annot_obj(annot), mupdf.PDF_ENUM_NAME_Rotate)\n        if not rotation.m_internal:\n            return -1\n        return mupdf.pdf_to_int( rotation)\n\n    def set_apn_bbox(self, bbox):\n        \"\"\"\n        Set annotation appearance bbox.\n        \"\"\"\n        CheckParent(self)\n        page = self.get_parent()\n        rot = page.rotation_matrix\n        mat = page.transformation_matrix\n        bbox *= rot * ~mat\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        ap = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AP'), PDF_NAME('N'))\n        if not ap.m_internal:\n            raise RuntimeError( MSG_BAD_APN)\n        rect = JM_rect_from_py(bbox)\n        mupdf.pdf_dict_put_rect(ap, PDF_NAME('BBox'), rect)\n\n    def set_apn_matrix(self, matrix):\n        \"\"\"Set annotation appearance matrix.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        ap = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AP'), PDF_NAME('N'))\n        if not ap.m_internal:\n            raise RuntimeError( MSG_BAD_APN)\n        mat = JM_matrix_from_py(matrix)\n        mupdf.pdf_dict_put_matrix(ap, PDF_NAME('Matrix'), mat)\n\n    def set_blendmode(self, blend_mode):\n        \"\"\"Set annotation BlendMode.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('BM'), blend_mode)\n\n    def set_border(self, border=None, width=-1, style=None, dashes=None, clouds=-1):\n        \"\"\"Set border properties.\n\n        Either a dict, or direct arguments width, style, dashes or clouds.\"\"\"\n        CheckParent(self)\n        atype, atname = self.type[:2]  # annotation type\n        if atype not in (\n                mupdf.PDF_ANNOT_CIRCLE,\n                mupdf.PDF_ANNOT_FREE_TEXT,\n                mupdf.PDF_ANNOT_INK,\n                mupdf.PDF_ANNOT_LINE,\n                mupdf.PDF_ANNOT_POLY_LINE,\n                mupdf.PDF_ANNOT_POLYGON,\n                mupdf.PDF_ANNOT_SQUARE,\n                ):\n            message(f\"Cannot set border for '{atname}'.\")\n            return None\n        if atype not in (\n                mupdf.PDF_ANNOT_CIRCLE,\n                mupdf.PDF_ANNOT_FREE_TEXT,\n                mupdf.PDF_ANNOT_POLYGON,\n                mupdf.PDF_ANNOT_SQUARE,\n                ):\n            if clouds > 0:\n                message(f\"Cannot set cloudy border for '{atname}'.\")\n                clouds = -1  # do not set border effect\n        if type(border) is not dict:\n            border = {\"width\": width, \"style\": style, \"dashes\": dashes, \"clouds\": clouds}\n        border.setdefault(\"width\", -1)\n        border.setdefault(\"style\", None)\n        border.setdefault(\"dashes\", None)\n        border.setdefault(\"clouds\", -1)\n        if border[\"width\"] is None:\n            border[\"width\"] = -1\n        if border[\"clouds\"] is None:\n            border[\"clouds\"] = -1\n        if hasattr(border[\"dashes\"], \"__getitem__\"):  # ensure sequence items are integers\n            border[\"dashes\"] = tuple(border[\"dashes\"])\n            for item in border[\"dashes\"]:\n                if not isinstance(item, int):\n                    border[\"dashes\"] = None\n                    break\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj( annot)\n        pdf = mupdf.pdf_get_bound_document( annot_obj)\n        return JM_annot_set_border( border, pdf, annot_obj)\n\n    def set_colors(self, colors=None, stroke=None, fill=None):\n        \"\"\"Set 'stroke' and 'fill' colors.\n\n        Use either a dict or the direct arguments.\n        \"\"\"\n        if self.type[0] == mupdf.PDF_ANNOT_FREE_TEXT:\n            raise ValueError(\"cannot be used for FreeText annotations\")\n\n        CheckParent(self)\n        doc = self.get_parent().parent\n        if type(colors) is not dict:\n            colors = {\"fill\": fill, \"stroke\": stroke}\n        fill = colors.get(\"fill\")\n        stroke = colors.get(\"stroke\")\n\n        fill_annots = (mupdf.PDF_ANNOT_CIRCLE, mupdf.PDF_ANNOT_SQUARE, mupdf.PDF_ANNOT_LINE, mupdf.PDF_ANNOT_POLY_LINE, mupdf.PDF_ANNOT_POLYGON,\n                       mupdf.PDF_ANNOT_REDACT,)\n\n        if stroke in ([], ()):\n            doc.xref_set_key(self.xref, \"C\", \"[]\")\n        elif stroke is not None:\n            if hasattr(stroke, \"__float__\"):\n                stroke = [float(stroke)]\n            CheckColor(stroke)\n            assert len(stroke) in (1, 3, 4)\n            s = f\"[{_format_g(stroke)}]\"\n            doc.xref_set_key(self.xref, \"C\", s)\n\n        if fill and self.type[0] not in fill_annots:\n            message(f\"Warning: fill color ignored for annot type '{self.type[1]}'.\")\n            return\n        if fill in ([], ()):\n            doc.xref_set_key(self.xref, \"IC\", \"[]\")\n        elif fill is not None:\n            if hasattr(fill, \"__float__\"):\n                fill = [float(fill)]\n            CheckColor(fill)\n            assert len(fill) in (1, 3, 4)\n            s = f\"[{_format_g(fill)}]\"\n            doc.xref_set_key(self.xref, \"IC\", s)\n\n    def set_flags(self, flags):\n        \"\"\"Set annotation flags.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        mupdf.pdf_set_annot_flags(annot, flags)\n\n    def set_info(self, info=None, content=None, title=None, creationDate=None, modDate=None, subject=None):\n        \"\"\"Set various properties.\"\"\"\n        CheckParent(self)\n        if type(info) is dict:  # build the args from the dictionary\n            content = info.get(\"content\", None)\n            title = info.get(\"title\", None)\n            creationDate = info.get(\"creationDate\", None)\n            modDate = info.get(\"modDate\", None)\n            subject = info.get(\"subject\", None)\n            info = None\n        annot = self.this\n        # use this to indicate a 'markup' annot type\n        is_markup = mupdf.pdf_annot_has_author(annot)\n        # contents\n        if content:\n            mupdf.pdf_set_annot_contents(annot, content)\n        if is_markup:\n            # title (= author)\n            if title:\n                mupdf.pdf_set_annot_author(annot, title)\n            # creation date\n            if creationDate:\n                mupdf.pdf_dict_put_text_string(mupdf.pdf_annot_obj(annot), PDF_NAME('CreationDate'), creationDate)\n            # mod date\n            if modDate:\n                mupdf.pdf_dict_put_text_string(mupdf.pdf_annot_obj(annot), PDF_NAME('M'), modDate)\n            # subject\n            if subject:\n                mupdf.pdf_dict_puts(mupdf.pdf_annot_obj(annot), \"Subj\", mupdf.pdf_new_text_string(subject))\n\n    def set_irt_xref(self, xref):\n        '''\n        Set annotation IRT xref\n        '''\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj( annot)\n        page = _pdf_annot_page(annot)\n        if xref < 1 or xref >= mupdf.pdf_xref_len( page.doc()):\n            raise ValueError( MSG_BAD_XREF)\n        irt = mupdf.pdf_new_indirect( page.doc(), xref, 0)\n        subt = mupdf.pdf_dict_get( irt, PDF_NAME('Subtype'))\n        irt_subt = mupdf.pdf_annot_type_from_string( mupdf.pdf_to_name( subt))\n        if irt_subt < 0:\n            raise ValueError( MSG_IS_NO_ANNOT)\n        mupdf.pdf_dict_put( annot_obj, PDF_NAME('IRT'), irt)\n\n    def set_language(self, language=None):\n        \"\"\"Set annotation language.\"\"\"\n        CheckParent(self)\n        this_annot = self.this\n        if not language:\n            lang = mupdf.FZ_LANG_UNSET\n        else:\n            lang = mupdf.fz_text_language_from_string(language)\n        mupdf.pdf_set_annot_language(this_annot, lang)\n\n    def set_line_ends(self, start, end):\n        \"\"\"Set line end codes.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        if mupdf.pdf_annot_has_line_ending_styles(annot):\n            mupdf.pdf_set_annot_line_ending_styles(annot, start, end)\n        else:\n            message_warning(\"bad annot type for line ends\")\n\n    def set_name(self, name):\n        \"\"\"Set /Name (icon) of annotation.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('Name'), name)\n\n    def set_oc(self, oc=0):\n        \"\"\"Set / remove annotation OC xref.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        if not oc:\n            mupdf.pdf_dict_del(annot_obj, PDF_NAME('OC'))\n        else:\n            JM_add_oc_object(mupdf.pdf_get_bound_document(annot_obj), annot_obj, oc)\n\n    def set_opacity(self, opacity):\n        \"\"\"Set opacity.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        if not _INRANGE(opacity, 0.0, 1.0):\n            mupdf.pdf_set_annot_opacity(annot, 1)\n            return\n        mupdf.pdf_set_annot_opacity(annot, opacity)\n        if opacity < 1.0:\n            page = _pdf_annot_page(annot)\n            page.transparency = 1\n\n    def set_open(self, is_open):\n        \"\"\"Set 'open' status of annotation or its Popup.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        mupdf.pdf_set_annot_is_open(annot, is_open)\n\n    def set_popup(self, rect):\n        '''\n        Create annotation 'Popup' or update rectangle.\n        '''\n        CheckParent(self)\n        annot = self.this\n        pdfpage = _pdf_annot_page(annot)\n        rot = JM_rotate_page_matrix(pdfpage)\n        r = mupdf.fz_transform_rect(JM_rect_from_py(rect), rot)\n        mupdf.pdf_set_annot_popup(annot, r)\n\n    def set_rect(self, rect):\n        \"\"\"Set annotation rectangle.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        \n        pdfpage = _pdf_annot_page(annot)\n        rot = JM_rotate_page_matrix(pdfpage)\n        r = mupdf.fz_transform_rect(JM_rect_from_py(rect), rot)\n        if mupdf.fz_is_empty_rect(r) or mupdf.fz_is_infinite_rect(r):\n            raise ValueError( MSG_BAD_RECT)\n        try:\n            mupdf.pdf_set_annot_rect(annot, r)\n        except Exception as e:\n            message(f'cannot set rect: {e}')\n            return False\n\n    def set_rotation(self, rotate=0):\n        \"\"\"Set annotation rotation.\"\"\"\n        CheckParent(self)\n        \n        annot = self.this\n        type = mupdf.pdf_annot_type(annot)\n        if type not in (\n                mupdf.PDF_ANNOT_CARET,\n                mupdf.PDF_ANNOT_CIRCLE,\n                mupdf.PDF_ANNOT_FREE_TEXT,\n                mupdf.PDF_ANNOT_FILE_ATTACHMENT,\n                mupdf.PDF_ANNOT_INK,\n                mupdf.PDF_ANNOT_LINE,\n                mupdf.PDF_ANNOT_POLY_LINE,\n                mupdf.PDF_ANNOT_POLYGON,\n                mupdf.PDF_ANNOT_SQUARE,\n                mupdf.PDF_ANNOT_STAMP,\n                mupdf.PDF_ANNOT_TEXT,\n                ):\n            return\n        rot = rotate\n        while rot < 0:\n            rot += 360\n        while rot >= 360:\n            rot -= 360\n        if type == mupdf.PDF_ANNOT_FREE_TEXT and rot % 90 != 0:\n            rot = 0\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        mupdf.pdf_dict_put_int(annot_obj, PDF_NAME('Rotate'), rot)\n\n    @property\n    def type(self):\n        \"\"\"annotation type\"\"\"\n        CheckParent(self)\n        if not self.this.m_internal:\n            return 'null'\n        type_ = mupdf.pdf_annot_type(self.this)\n        c = mupdf.pdf_string_from_annot_type(type_)\n        o = mupdf.pdf_dict_gets( mupdf.pdf_annot_obj(self.this), 'IT')\n        if not o.m_internal or mupdf.pdf_is_name(o):\n            return (type_, c)\n        it = mupdf.pdf_to_name(o)\n        return (type_, c, it)\n\n    def update(self,\n            blend_mode: OptStr =None,\n            opacity: OptFloat =None,\n            fontsize: float =0,\n            fontname: OptStr =None,\n            text_color: OptSeq =None,\n            border_color: OptSeq =None,\n            fill_color: OptSeq =None,\n            cross_out: bool =True,\n            rotate: int =-1,\n            ):\n        \"\"\"Update annot appearance.\n\n        Notes:\n            Depending on the annot type, some parameters make no sense,\n            while others are only available in this method to achieve the\n            desired result. This is especially true for 'FreeText' annots.\n        Args:\n            blend_mode: set the blend mode, all annotations.\n            opacity: set the opacity, all annotations.\n            fontsize: set fontsize, 'FreeText' only.\n            fontname: set the font, 'FreeText' only.\n            border_color: set border color, 'FreeText' only.\n            text_color: set text color, 'FreeText' only.\n            fill_color: set fill color, all annotations.\n            cross_out: draw diagonal lines, 'Redact' only.\n            rotate: set rotation, 'FreeText' and some others.\n        \"\"\"\n        annot_obj = mupdf.pdf_annot_obj(self.this)\n        \n        if border_color:\n            is_rich_text = mupdf.pdf_dict_get(annot_obj, PDF_NAME(\"RC\"))\n            if not is_rich_text:\n                raise ValueError(\"cannot set border_color if rich_text is False\")\n        Annot.update_timing_test()\n        CheckParent(self)\n        def color_string(cs, code):\n            \"\"\"Return valid PDF color operator for a given color sequence.\n            \"\"\"\n            cc = ColorCode(cs, code)\n            if not cc:\n                return b\"\"\n            return (cc + \"\\n\").encode()\n\n        annot_type = self.type[0]  # get the annot type\n\n        dt = self.border.get(\"dashes\", None)  # get the dashes spec\n        bwidth = self.border.get(\"width\", -1)  # get border line width\n        stroke = self.colors[\"stroke\"]  # get the stroke color\n        if fill_color is not None:\n            fill = fill_color\n        else:\n            fill = self.colors[\"fill\"]\n        rect = None  # self.rect  # prevent MuPDF fiddling with it\n        apnmat = self.apn_matrix  # prevent MuPDF fiddling with it\n        if rotate != -1:  # sanitize rotation value\n            while rotate < 0:\n                rotate += 360\n            while rotate >= 360:\n                rotate -= 360\n            if annot_type == mupdf.PDF_ANNOT_FREE_TEXT and rotate % 90 != 0:\n                rotate = 0\n\n        #------------------------------------------------------------------\n        # handle opacity and blend mode\n        #------------------------------------------------------------------\n        if blend_mode is None:\n            blend_mode = self.blendmode\n        if not hasattr(opacity, \"__float__\"):\n            opacity = self.opacity\n\n        if 0 <= opacity < 1 or blend_mode:\n            opa_code = \"/H gs\\n\"  # then we must reference this 'gs'\n        else:\n            opa_code = \"\"\n\n        if annot_type == mupdf.PDF_ANNOT_FREE_TEXT:\n            CheckColor(text_color)\n            CheckColor(fill_color)\n            tcol, fname, fsize = TOOLS._parse_da(self)\n\n            # read and update default appearance as necessary\n            if fsize <= 0:\n                fsize = 12\n            if text_color:\n                tcol = text_color\n            if fontname:\n                fname = fontname\n            if fontsize > 0:\n                fsize = fontsize\n            JM_make_annot_DA(self, len(tcol), tcol, fname, fsize)\n            blend_mode = None  # not supported for free text annotations!\n\n        #------------------------------------------------------------------\n        # now invoke MuPDF to update the annot appearance\n        #------------------------------------------------------------------\n        val = self._update_appearance(\n            opacity=opacity,\n            blend_mode=blend_mode,\n            fill_color=fill,\n            rotate=rotate,\n        )\n        if val is False:\n            raise RuntimeError(\"Error updating annotation.\")\n\n        if annot_type == mupdf.PDF_ANNOT_FREE_TEXT:\n            # in absence of previous opacity, we may need to modify the AP\n            ap = self._getAP()\n            if 0 <= opacity < 1 and not ap.startswith(b\"/H gs\"):\n                self._setAP(b\"/H gs\\n\" + ap)\n            return\n\n        bfill = color_string(fill, \"f\")\n        bstroke = color_string(stroke, \"c\")\n\n        p_ctm = self.get_parent().transformation_matrix\n        imat = ~p_ctm  # inverse page transf. matrix\n\n        if dt:\n            dashes = \"[\" + \" \".join(map(str, dt)) + \"] 0 d\\n\"\n            dashes = dashes.encode(\"utf-8\")\n        else:\n            dashes = None\n\n        if self.line_ends:\n            line_end_le, line_end_ri = self.line_ends\n        else:\n            line_end_le, line_end_ri = 0, 0  # init line end codes\n\n        # read contents as created by MuPDF\n        ap = self._getAP()\n        ap_tab = ap.splitlines()  # split in single lines\n        ap_updated = False  # assume we did nothing\n\n        if annot_type == mupdf.PDF_ANNOT_REDACT:\n            if cross_out:  # create crossed-out rect\n                ap_updated = True\n                ap_tab = ap_tab[:-1]\n                _, LL, LR, UR, UL = ap_tab\n                ap_tab.append(LR)\n                ap_tab.append(LL)\n                ap_tab.append(UR)\n                ap_tab.append(LL)\n                ap_tab.append(UL)\n                ap_tab.append(b\"S\")\n\n            if bwidth > 0 or bstroke != b\"\":\n                ap_updated = True\n                ntab = [_format_g(bwidth).encode() + b\" w\"] if bwidth > 0 else []\n                for line in ap_tab:\n                    if line.endswith(b\"w\"):\n                        continue\n                    if line.endswith(b\"RG\") and bstroke != b\"\":\n                        line = bstroke[:-1]\n                    ntab.append(line)\n                ap_tab = ntab\n\n            ap = b\"\\n\".join(ap_tab)\n\n        if annot_type in (mupdf.PDF_ANNOT_POLYGON, mupdf.PDF_ANNOT_POLY_LINE):\n            ap = b\"\\n\".join(ap_tab[:-1]) + b\"\\n\"\n            ap_updated = True\n            if bfill != b\"\":\n                if annot_type == mupdf.PDF_ANNOT_POLYGON:\n                    ap = ap + bfill + b\"b\"  # close, fill, and stroke\n                elif annot_type == mupdf.PDF_ANNOT_POLY_LINE:\n                    ap = ap + b\"S\"  # stroke\n            else:\n                if annot_type == mupdf.PDF_ANNOT_POLYGON:\n                    ap = ap + b\"s\"  # close and stroke\n                elif annot_type == mupdf.PDF_ANNOT_POLY_LINE:\n                    ap = ap + b\"S\"  # stroke\n\n        if dashes is not None:  # handle dashes\n            ap = dashes + ap\n            # reset dashing - only applies for LINE annots with line ends given\n            ap = ap.replace(b\"\\nS\\n\", b\"\\nS\\n[] 0 d\\n\", 1)\n            ap_updated = True\n\n        if opa_code:\n            ap = opa_code.encode(\"utf-8\") + ap\n            ap_updated = True\n\n        ap = b\"q\\n\" + ap + b\"\\nQ\\n\"\n        #----------------------------------------------------------------------\n        # the following handles line end symbols for 'Polygon' and 'Polyline'\n        #----------------------------------------------------------------------\n        if line_end_le + line_end_ri > 0 and annot_type in (mupdf.PDF_ANNOT_POLYGON, mupdf.PDF_ANNOT_POLY_LINE):\n\n            le_funcs = (None, TOOLS._le_square, TOOLS._le_circle,\n                        TOOLS._le_diamond, TOOLS._le_openarrow,\n                        TOOLS._le_closedarrow, TOOLS._le_butt,\n                        TOOLS._le_ropenarrow, TOOLS._le_rclosedarrow,\n                        TOOLS._le_slash)\n            le_funcs_range = range(1, len(le_funcs))\n            d = 2 * max(1, self.border[\"width\"])\n            rect = self.rect + (-d, -d, d, d)\n            ap_updated = True\n            points = self.vertices\n            if line_end_le in le_funcs_range:\n                p1 = Point(points[0]) * imat\n                p2 = Point(points[1]) * imat\n                left = le_funcs[line_end_le](self, p1, p2, False, fill_color)\n                ap += left.encode()\n            if line_end_ri in le_funcs_range:\n                p1 = Point(points[-2]) * imat\n                p2 = Point(points[-1]) * imat\n                left = le_funcs[line_end_ri](self, p1, p2, True, fill_color)\n                ap += left.encode()\n\n        if ap_updated:\n            if rect:                        # rect modified here?\n                self.set_rect(rect)\n                self._setAP(ap, rect=1)\n            else:\n                self._setAP(ap, rect=0)\n\n        #-------------------------------\n        # handle annotation rotations\n        #-------------------------------\n        if annot_type not in (  # only these types are supported\n                mupdf.PDF_ANNOT_CARET,\n                mupdf.PDF_ANNOT_CIRCLE,\n                mupdf.PDF_ANNOT_FILE_ATTACHMENT,\n                mupdf.PDF_ANNOT_INK,\n                mupdf.PDF_ANNOT_LINE,\n                mupdf.PDF_ANNOT_POLY_LINE,\n                mupdf.PDF_ANNOT_POLYGON,\n                mupdf.PDF_ANNOT_SQUARE,\n                mupdf.PDF_ANNOT_STAMP,\n                mupdf.PDF_ANNOT_TEXT,\n                ):\n            return\n\n        rot = self.rotation  # get value from annot object\n        if rot == -1:  # nothing to change\n            return\n\n        M = (self.rect.tl + self.rect.br) / 2  # center of annot rect\n\n        if rot == 0:  # undo rotations\n            if abs(apnmat - Matrix(1, 1)) < 1e-5:\n                return  # matrix already is a no-op\n            quad = self.rect.morph(M, ~apnmat)  # derotate rect\n            self.setRect(quad.rect)\n            self.set_apn_matrix(Matrix(1, 1))  # appearance matrix = no-op\n            return\n\n        mat = Matrix(rot)\n        quad = self.rect.morph(M, mat)\n        self.set_rect(quad.rect)\n        self.set_apn_matrix(apnmat * mat)\n\n    def update_file(self, buffer_=None, filename=None, ufilename=None, desc=None):\n        \"\"\"Update attached file.\"\"\"\n        CheckParent(self)\n        annot = self.this\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        pdf = mupdf.pdf_get_bound_document(annot_obj)  # the owning PDF\n        type = mupdf.pdf_annot_type(annot)\n        if type != mupdf.PDF_ANNOT_FILE_ATTACHMENT:\n            raise TypeError( MSG_BAD_ANNOT_TYPE)\n        stream = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('FS'), PDF_NAME('EF'), PDF_NAME('F'))\n        # the object for file content\n        if not stream.m_internal:\n            RAISEPY( \"bad PDF: no /EF object\", JM_Exc_FileDataError)\n\n        fs = mupdf.pdf_dict_get(annot_obj, PDF_NAME('FS'))\n\n        # file content given\n        res = JM_BufferFromBytes(buffer_)\n        if buffer_ and not res.m_internal:\n            raise ValueError( MSG_BAD_BUFFER)\n        if res:\n            JM_update_stream(pdf, stream, res, 1)\n            # adjust /DL and /Size parameters\n            len, _ = mupdf.fz_buffer_storage(res)\n            l = mupdf.pdf_new_int(len)\n            mupdf.pdf_dict_put(stream, PDF_NAME('DL'), l)\n            mupdf.pdf_dict_putl(stream, l, PDF_NAME('Params'), PDF_NAME('Size'))\n\n        if filename:\n            mupdf.pdf_dict_put_text_string(stream, PDF_NAME('F'), filename)\n            mupdf.pdf_dict_put_text_string(fs, PDF_NAME('F'), filename)\n            mupdf.pdf_dict_put_text_string(stream, PDF_NAME('UF'), filename)\n            mupdf.pdf_dict_put_text_string(fs, PDF_NAME('UF'), filename)\n            mupdf.pdf_dict_put_text_string(annot_obj, PDF_NAME('Contents'), filename)\n\n        if ufilename:\n            mupdf.pdf_dict_put_text_string(stream, PDF_NAME('UF'), ufilename)\n            mupdf.pdf_dict_put_text_string(fs, PDF_NAME('UF'), ufilename)\n\n        if desc:\n            mupdf.pdf_dict_put_text_string(stream, PDF_NAME('Desc'), desc)\n            mupdf.pdf_dict_put_text_string(fs, PDF_NAME('Desc'), desc)\n\n    @staticmethod\n    def update_timing_test():\n        total = 0\n        for i in range( 30*1000):\n            total += i\n        return total\n    \n    @property\n    def vertices(self):\n        \"\"\"annotation vertex points\"\"\"\n        CheckParent(self)\n        annot = self.this\n        assert isinstance(annot, mupdf.PdfAnnot)\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        page = _pdf_annot_page(annot)\n        page_ctm = mupdf.FzMatrix()   # page transformation matrix\n        dummy = mupdf.FzRect()  # Out-param for mupdf.pdf_page_transform().\n        mupdf.pdf_page_transform(page, dummy, page_ctm)\n        derot = JM_derotate_page_matrix(page)\n        page_ctm = mupdf.fz_concat(page_ctm, derot)\n\n        #----------------------------------------------------------------\n        # The following objects occur in different annotation types.\n        # So we are sure that (!o) occurs at most once.\n        # Every pair of floats is one point, that needs to be separately\n        # transformed with the page transformation matrix.\n        #----------------------------------------------------------------\n        o = mupdf.pdf_dict_get(annot_obj, PDF_NAME('Vertices'))\n        if not o.m_internal:    o = mupdf.pdf_dict_get(annot_obj, PDF_NAME('L'))\n        if not o.m_internal:    o = mupdf.pdf_dict_get(annot_obj, PDF_NAME('QuadPoints'))\n        if not o.m_internal:    o = mupdf.pdf_dict_gets(annot_obj, 'CL')\n        \n        if o.m_internal:\n            # handle lists with 1-level depth\n            # weiter\n            res = []\n            for i in range(0, mupdf.pdf_array_len(o), 2):\n                x = mupdf.pdf_to_real(mupdf.pdf_array_get(o, i))\n                y = mupdf.pdf_to_real(mupdf.pdf_array_get(o, i+1))\n                point = mupdf.FzPoint(x, y)\n                point = mupdf.fz_transform_point(point, page_ctm)\n                res.append( (point.x, point.y))\n            return res\n            \n        o = mupdf.pdf_dict_gets(annot_obj, 'InkList')\n        if o.m_internal:\n            # InkList has 2-level lists\n            #inklist:\n            res = []\n            for i in range(mupdf.pdf_array_len(o)):\n                res1 = []\n                o1 = mupdf.pdf_array_get(o, i)\n                for j in range(0, mupdf.pdf_array_len(o1), 2):\n                    x = mupdf.pdf_to_real(mupdf.pdf_array_get(o1, j))\n                    y = mupdf.pdf_to_real(mupdf.pdf_array_get(o1, j+1))\n                    point = mupdf.FzPoint(x, y)\n                    point = mupdf.fz_transform_point(point, page_ctm)\n                    res1.append( (point.x, point.y))\n                res.append(res1)\n            return res\n\n    @property\n    def xref(self):\n        \"\"\"annotation xref number\"\"\"\n        CheckParent(self)\n        annot = self.this\n        return mupdf.pdf_to_num(mupdf.pdf_annot_obj(annot))\n\n\nclass Archive:\n    def __init__( self, *args):\n        '''\n        Archive(dirname [, path]) - from folder\n        Archive(file [, path]) - from file name or object\n        Archive(data, name) - from memory item\n        Archive() - empty archive\n        Archive(archive [, path]) - from archive\n        '''\n        self._subarchives = list()\n        self.this = mupdf.fz_new_multi_archive()\n        if args:\n            self.add( *args)\n    \n    def __repr__( self):\n        return f'Archive, sub-archives: {len(self._subarchives)}'\n\n    def _add_arch( self, subarch, path=None):\n        mupdf.fz_mount_multi_archive( self.this, subarch, path)\n    \n    def _add_dir( self, folder, path=None):\n        sub = mupdf.fz_open_directory( folder)\n        mupdf.fz_mount_multi_archive( self.this, sub, path)\n    \n    def _add_treeitem( self, memory, name, path=None):\n        buff = JM_BufferFromBytes( memory)\n        sub = mupdf.fz_new_tree_archive( mupdf.FzTree())\n        mupdf.fz_tree_archive_add_buffer( sub, name, buff)\n        mupdf.fz_mount_multi_archive( self.this, sub, path)\n    \n    def _add_ziptarfile( self, filepath, type_, path=None):\n        if type_ == 1:\n            sub = mupdf.fz_open_zip_archive( filepath)\n        else:\n            sub = mupdf.fz_open_tar_archive( filepath)\n        mupdf.fz_mount_multi_archive( self.this, sub, path)\n    \n    def _add_ziptarmemory( self, memory, type_, path=None):\n        buff = JM_BufferFromBytes( memory)\n        stream = mupdf.fz_open_buffer( buff)\n        if type_==1:\n            sub = mupdf.fz_open_zip_archive_with_stream( stream)\n        else:\n            sub = mupdf.fz_open_tar_archive_with_stream( stream)\n        mupdf.fz_mount_multi_archive( self.this, sub, path)\n    \n    def add( self, content, path=None):\n        '''\n        Add a sub-archive.\n\n        Args:\n            content:\n                The content to be added. May be one of:\n                    `str` - must be path of directory or file.\n                    `bytes`, `bytearray`, `io.BytesIO` - raw data.\n                    `zipfile.Zipfile`.\n                    `tarfile.TarFile`.\n                    `pymupdf.Archive`.\n                    A two-item tuple `(data, name)`.\n                    List or tuple (but not tuple with length 2) of the above.\n            path: (str) a \"virtual\" path name, under which the elements\n                of content can be retrieved. Use it to e.g. cope with\n                duplicate element names.\n        '''\n        def is_binary_data(x):\n            return isinstance(x, (bytes, bytearray, io.BytesIO))\n\n        def make_subarch(entries, mount, fmt):\n            subarch = dict(fmt=fmt, entries=entries, path=mount)\n            if fmt != \"tree\" or self._subarchives == []:\n                self._subarchives.append(subarch)\n            else:\n                ltree = self._subarchives[-1]\n                if ltree[\"fmt\"] != \"tree\" or ltree[\"path\"] != subarch[\"path\"]:\n                    self._subarchives.append(subarch)\n                else:\n                    ltree[\"entries\"].extend(subarch[\"entries\"])\n                    self._subarchives[-1] = ltree\n\n        if isinstance(content, pathlib.Path):\n            content = str(content)\n        \n        if isinstance(content, str):\n            if os.path.isdir(content):\n                self._add_dir(content, path)\n                return make_subarch(os.listdir(content), path, 'dir')\n            elif os.path.isfile(content):\n                assert isinstance(path, str) and path != '', \\\n                        f'Need name for binary content, but {path=}.'\n                with io.open(content, 'rb') as f:\n                    ff = f.read()\n                self._add_treeitem(ff, path)\n                return make_subarch([path], None, 'tree')\n            else:\n                raise ValueError(f'Not a file or directory: {content!r}')\n\n        elif is_binary_data(content):\n            assert isinstance(path, str) and path != '' \\\n                    f'Need name for binary content, but {path=}.'\n            self._add_treeitem(content, path)\n            return make_subarch([path], None, 'tree')\n\n        elif isinstance(content, zipfile.ZipFile):\n            filename = getattr(content, \"filename\", None)\n            if filename is None:\n                fp = content.fp.getvalue()\n                self._add_ziptarmemory(fp, 1, path)\n            else:\n                self._add_ziptarfile(filename, 1, path)\n            return make_subarch(content.namelist(), path, 'zip')\n\n        elif isinstance(content, tarfile.TarFile):\n            filename = getattr(content.fileobj, \"name\", None)\n            if filename is None:\n                fp = content.fileobj\n                if not isinstance(fp, io.BytesIO):\n                    fp = fp.fileobj\n                self._add_ziptarmemory(fp.getvalue(), 0, path)\n            else:\n                self._add_ziptarfile(filename, 0, path)\n            return make_subarch(content.getnames(), path, 'tar')\n\n        elif isinstance(content, Archive):\n            self._add_arch(content, path)\n            return make_subarch([], path, 'multi')\n        \n        if isinstance(content, tuple) and len(content) == 2:\n            # covers the tree item plus path\n            data, name = content\n            assert isinstance(name, str), f'Unexpected {type(name)=}'\n            if is_binary_data(data):\n                self._add_treeitem(data, name, path=path)\n            elif isinstance(data, str):\n                if os.path.isfile(data):\n                    with io.open(data, 'rb') as f:\n                        ff = f.read()\n                    self._add_treeitem(ff, name, path=path)\n            else:\n                assert 0, f'Unexpected {type(data)=}.'\n            return make_subarch([name], path, 'tree')\n        \n        elif hasattr(content, '__getitem__'):\n            # Deal with sequence of disparate items.\n            for item in content:\n                self.add(item, path)\n            return\n        \n        else:\n            raise TypeError(f'Unrecognised type {type(content)}.')\n        assert 0\n\n    @property\n    def entry_list( self):\n        '''\n        List of sub archives.\n        '''\n        return self._subarchives\n    \n    def has_entry( self, name):\n        return mupdf.fz_has_archive_entry( self.this, name)\n    \n    def read_entry( self, name):\n        buff = mupdf.fz_read_archive_entry( self.this, name)\n        return JM_BinFromBuffer( buff)\n\n\nclass Xml:\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, *args):\n        pass\n\n    def __init__(self, rhs):\n        if isinstance(rhs, mupdf.FzXml):\n            self.this = rhs\n        elif isinstance(rhs, str):\n            buff = mupdf.fz_new_buffer_from_copied_data(rhs)\n            self.this = mupdf.fz_parse_xml_from_html5(buff)\n        else:\n            assert 0, f'Unsupported type for rhs: {type(rhs)}'\n    \n    def _get_node_tree( self):\n        def show_node(node, items, shift):\n            while node is not None:\n                if node.is_text:\n                    items.append((shift, f'\"{node.text}\"'))\n                    node = node.next\n                    continue\n                items.append((shift, f\"({node.tagname}\"))\n                for k, v in node.get_attributes().items():\n                    items.append((shift, f\"={k} '{v}'\"))\n                child = node.first_child\n                if child:\n                    items = show_node(child, items, shift + 1)\n                items.append((shift, f\"){node.tagname}\"))\n                node = node.next\n            return items\n\n        shift = 0\n        items = []\n        items = show_node(self, items, shift)\n        return items\n    \n    def add_bullet_list(self):\n        \"\"\"Add bulleted list (\"ul\" tag)\"\"\"\n        child = self.create_element(\"ul\")\n        self.append_child(child)\n        return child\n\n    def add_class(self, text):\n        \"\"\"Set some class via CSS. Replaces complete class spec.\"\"\"\n        cls = self.get_attribute_value(\"class\")\n        if cls is not None and text in cls:\n            return self\n        self.remove_attribute(\"class\")\n        if cls is None:\n            cls = text\n        else:\n            cls += \" \" + text\n        self.set_attribute(\"class\", cls)\n        return self\n\n    def add_code(self, text=None):\n        \"\"\"Add a \"code\" tag\"\"\"\n        child = self.create_element(\"code\")\n        if type(text) is str:\n            child.append_child(self.create_text_node(text))\n        prev = self.span_bottom()\n        if prev is None:\n            prev = self\n        prev.append_child(child)\n        return self\n\n    def add_codeblock(self):\n        \"\"\"Add monospaced lines (\"pre\" node)\"\"\"\n        child = self.create_element(\"pre\")\n        self.append_child(child)\n        return child\n\n    def add_description_list(self):\n        \"\"\"Add description list (\"dl\" tag)\"\"\"\n        child = self.create_element(\"dl\")\n        self.append_child(child)\n        return child\n\n    def add_division(self):\n        \"\"\"Add \"div\" tag\"\"\"\n        child = self.create_element(\"div\")\n        self.append_child(child)\n        return child\n\n    def add_header(self, level=1):\n        \"\"\"Add header tag\"\"\"\n        if level not in range(1, 7):\n            raise ValueError(\"Header level must be in [1, 6]\")\n        this_tag = self.tagname\n        new_tag = f\"h{level}\"\n        child = self.create_element(new_tag)\n        if this_tag not in (\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"p\"):\n            self.append_child(child)\n            return child\n        self.parent.append_child(child)\n        return child\n\n    def add_horizontal_line(self):\n        \"\"\"Add horizontal line (\"hr\" tag)\"\"\"\n        child = self.create_element(\"hr\")\n        self.append_child(child)\n        return child\n\n    def add_image(self, name, width=None, height=None, imgfloat=None, align=None):\n        \"\"\"Add image node (tag \"img\").\"\"\"\n        child = self.create_element(\"img\")\n        if width is not None:\n            child.set_attribute(\"width\", f\"{width}\")\n        if height is not None:\n            child.set_attribute(\"height\", f\"{height}\")\n        if imgfloat is not None:\n            child.set_attribute(\"style\", f\"float: {imgfloat}\")\n        if align is not None:\n            child.set_attribute(\"align\", f\"{align}\")\n        child.set_attribute(\"src\", f\"{name}\")\n        self.append_child(child)\n        return child\n\n    def add_link(self, href, text=None):\n        \"\"\"Add a hyperlink (\"a\" tag)\"\"\"\n        child = self.create_element(\"a\")\n        if not isinstance(text, str):\n            text = href\n        child.set_attribute(\"href\", href)\n        child.append_child(self.create_text_node(text))\n        prev = self.span_bottom()\n        if prev is None:\n            prev = self\n        prev.append_child(child)\n        return self\n\n    def add_list_item(self):\n        \"\"\"Add item (\"li\" tag) under a (numbered or bulleted) list.\"\"\"\n        if self.tagname not in (\"ol\", \"ul\"):\n            raise ValueError(\"cannot add list item to\", self.tagname)\n        child = self.create_element(\"li\")\n        self.append_child(child)\n        return child\n\n    def add_number_list(self, start=1, numtype=None):\n        \"\"\"Add numbered list (\"ol\" tag)\"\"\"\n        child = self.create_element(\"ol\")\n        if start > 1:\n            child.set_attribute(\"start\", str(start))\n        if numtype is not None:\n            child.set_attribute(\"type\", numtype)\n        self.append_child(child)\n        return child\n\n    def add_paragraph(self):\n        \"\"\"Add \"p\" tag\"\"\"\n        child = self.create_element(\"p\")\n        if self.tagname != \"p\":\n            self.append_child(child)\n        else:\n            self.parent.append_child(child)\n        return child\n\n    def add_span(self):\n        child = self.create_element(\"span\")\n        self.append_child(child)\n        return child\n\n    def add_style(self, text):\n        \"\"\"Set some style via CSS style. Replaces complete style spec.\"\"\"\n        style = self.get_attribute_value(\"style\")\n        if style is not None and text in style:\n            return self\n        self.remove_attribute(\"style\")\n        if style is None:\n            style = text\n        else:\n            style += \";\" + text\n        self.set_attribute(\"style\", style)\n        return self\n\n    def add_subscript(self, text=None):\n        \"\"\"Add a subscript (\"sub\" tag)\"\"\"\n        child = self.create_element(\"sub\")\n        if type(text) is str:\n            child.append_child(self.create_text_node(text))\n        prev = self.span_bottom()\n        if prev is None:\n            prev = self\n        prev.append_child(child)\n        return self\n\n    def add_superscript(self, text=None):\n        \"\"\"Add a superscript (\"sup\" tag)\"\"\"\n        child = self.create_element(\"sup\")\n        if type(text) is str:\n            child.append_child(self.create_text_node(text))\n        prev = self.span_bottom()\n        if prev is None:\n            prev = self\n        prev.append_child(child)\n        return self\n\n    def add_text(self, text):\n        \"\"\"Add text. Line breaks are honored.\"\"\"\n        lines = text.splitlines()\n        line_count = len(lines)\n        prev = self.span_bottom()\n        if prev is None:\n            prev = self\n\n        for i, line in enumerate(lines):\n            prev.append_child(self.create_text_node(line))\n            if i < line_count - 1:\n                prev.append_child(self.create_element(\"br\"))\n        return self\n\n    def append_child( self, child):\n        mupdf.fz_dom_append_child( self.this, child.this)\n    \n    def append_styled_span(self, style):\n        span = self.create_element(\"span\")\n        span.add_style(style)\n        prev = self.span_bottom()\n        if prev is None:\n            prev = self\n        prev.append_child(span)\n        return prev\n\n    def bodytag( self):\n        return Xml( mupdf.fz_dom_body( self.this))\n    \n    def clone( self):\n        ret = mupdf.fz_dom_clone( self.this)\n        return Xml( ret)\n    \n    @staticmethod\n    def color_text(color):\n        if type(color) is str:\n            return color\n        if type(color) is int:\n            return f\"rgb({sRGB_to_rgb(color)})\"\n        if type(color) in (tuple, list):\n            return f\"rgb{tuple(color)}\"\n        return color\n\n    def create_element( self, tag):\n        return Xml( mupdf.fz_dom_create_element( self.this, tag))\n    \n    def create_text_node( self, text):\n        return Xml( mupdf.fz_dom_create_text_node( self.this, text))\n    \n    def debug(self):\n        \"\"\"Print a list of the node tree below self.\"\"\"\n        items = self._get_node_tree()\n        for item in items:\n            message(\"  \" * item[0] + item[1].replace(\"\\n\", \"\\\\n\"))\n\n    def find( self, tag, att, match):\n        ret = mupdf.fz_dom_find( self.this, tag, att, match)\n        if ret.m_internal:\n            return Xml( ret)\n    \n    def find_next( self, tag, att, match):\n        ret = mupdf.fz_dom_find_next( self.this, tag, att, match)\n        if ret.m_internal:\n            return Xml( ret)\n    \n    @property\n    def first_child( self):\n        if mupdf.fz_xml_text( self.this):\n            # text node, has no child.\n            return\n        ret = mupdf.fz_dom_first_child( self)\n        if ret.m_internal:\n            return Xml( ret)\n    \n    def get_attribute_value( self, key):\n        assert key\n        return mupdf.fz_dom_attribute( self.this, key)\n    \n    def get_attributes( self):\n        if mupdf.fz_xml_text( self.this):\n            # text node, has no attributes.\n            return\n        result = dict()\n        i = 0\n        while 1:\n            val, key = mupdf.fz_dom_get_attribute( self.this, i)\n            if not val or not key:\n                break\n            result[ key] = val\n            i += 1\n        return result\n    \n    def insert_after( self, node):\n        mupdf.fz_dom_insert_after( self.this, node.this)\n    \n    def insert_before( self, node):\n        mupdf.fz_dom_insert_before( self.this, node.this)\n    \n    def insert_text(self, text):\n        lines = text.splitlines()\n        line_count = len(lines)\n        for i, line in enumerate(lines):\n            self.append_child(self.create_text_node(line))\n            if i < line_count - 1:\n                self.append_child(self.create_element(\"br\"))\n        return self\n\n    @property\n    def is_text(self):\n        \"\"\"Check if this is a text node.\"\"\"\n        return self.text is not None\n\n    @property\n    def last_child(self):\n        \"\"\"Return last child node.\"\"\"\n        child = self.first_child\n        if child is None:\n            return None\n        while True:\n            next = child.next\n            if not next:\n                return child\n            child = next\n\n    @property\n    def next( self):\n        ret = mupdf.fz_dom_next( self.this)\n        if ret.m_internal:\n            return Xml( ret)\n            \n    @property\n    def parent( self):\n        ret = mupdf.fz_dom_parent( self.this)\n        if ret.m_internal:\n            return Xml( ret)\n    \n    @property\n    def previous( self):\n        ret = mupdf.fz_dom_previous( self.this)\n        if ret.m_internal:\n            return Xml( ret)\n    \n    def remove( self):\n        mupdf.fz_dom_remove( self.this)\n    \n    def remove_attribute( self, key):\n        assert key\n        mupdf.fz_dom_remove_attribute( self.this, key)\n    \n    @property\n    def root( self):\n        return Xml( mupdf.fz_xml_root( self.this))\n    \n    def set_align(self, align):\n        \"\"\"Set text alignment via CSS style\"\"\"\n        if isinstance( align, str):\n            t = align\n        elif align == TEXT_ALIGN_LEFT:\n            t = \"left\"\n        elif align == TEXT_ALIGN_CENTER:\n            t = \"center\"\n        elif align == TEXT_ALIGN_RIGHT:\n            t = \"right\"\n        elif align == TEXT_ALIGN_JUSTIFY:\n            t = \"justify\"\n        else:\n            raise ValueError(f\"Unrecognised {align=}\")\n        self.add_style(f\"text-align: {t}\")\n        return self\n\n    def set_attribute( self, key, value):\n        assert key\n        mupdf.fz_dom_add_attribute( self.this, key, value)\n    \n    def set_bgcolor(self, color):\n        \"\"\"Set background color via CSS style\"\"\"\n        self.add_style(f'background-color: {self.color_text(color)}')  # does not work on span level\n        return self\n\n    def set_bold(self, val=True):\n        \"\"\"Set bold on / off via CSS style\"\"\"\n        if val:\n            val=\"bold\"\n        else:\n            val=\"normal\"\n        self.append_styled_span(f\"font-weight: {val}\")\n        return self\n\n    def set_color(self, color):\n        \"\"\"Set text color via CSS style\"\"\"\n        self.append_styled_span(f\"color: {self.color_text(color)}\")\n        return self\n\n    def set_columns(self, cols):\n        \"\"\"Set number of text columns via CSS style\"\"\"\n        self.append_styled_span(f\"columns: {cols}\")\n        return self\n\n    def set_font(self, font):\n        \"\"\"Set font-family name via CSS style\"\"\"\n        self.append_styled_span(f\"font-family: {font}\")\n        return self\n\n    def set_fontsize(self, fontsize):\n        \"\"\"Set font size name via CSS style\"\"\"\n        if type(fontsize) is str:\n            px=\"\"\n        else:\n            px=\"px\"\n        text = f\"font-size: {fontsize}{px}\"\n        self.append_styled_span(text)\n        return self\n\n    def set_id(self, unique):\n        \"\"\"Set a unique id.\"\"\"\n        # check uniqueness\n        root = self.root\n        if root.find(None, \"id\", unique):\n            raise ValueError(f\"id '{unique}' already exists\")\n        self.set_attribute(\"id\", unique)\n        return self\n\n    def set_italic(self, val=True):\n        \"\"\"Set italic on / off via CSS style\"\"\"\n        if val:\n            val=\"italic\"\n        else:\n            val=\"normal\"\n        self.append_styled_span(f\"font-style: {val}\")\n        return self\n\n    def set_leading(self, leading):\n        \"\"\"Set inter-line spacing value via CSS style - block-level only.\"\"\"\n        self.add_style(f\"-mupdf-leading: {leading}\")\n        return self\n\n    def set_letter_spacing(self, spacing):\n        \"\"\"Set inter-letter spacing value via CSS style\"\"\"\n        self.append_styled_span(f\"letter-spacing: {spacing}\")\n        return self\n\n    def set_lineheight(self, lineheight):\n        \"\"\"Set line height name via CSS style - block-level only.\"\"\"\n        self.add_style(f\"line-height: {lineheight}\")\n        return self\n\n    def set_margins(self, val):\n        \"\"\"Set margin values via CSS style\"\"\"\n        self.append_styled_span(f\"margins: {val}\")\n        return self\n\n    def set_opacity(self, opacity):\n        \"\"\"Set opacity via CSS style\"\"\"\n        self.append_styled_span(f\"opacity: {opacity}\")\n        return self\n\n    def set_pagebreak_after(self):\n        \"\"\"Insert a page break after this node.\"\"\"\n        self.add_style(\"page-break-after: always\")\n        return self\n\n    def set_pagebreak_before(self):\n        \"\"\"Insert a page break before this node.\"\"\"\n        self.add_style(\"page-break-before: always\")\n        return self\n\n    def set_properties(\n            self,\n            align=None,\n            bgcolor=None,\n            bold=None,\n            color=None,\n            columns=None,\n            font=None,\n            fontsize=None,\n            indent=None,\n            italic=None,\n            leading=None,\n            letter_spacing=None,\n            lineheight=None,\n            margins=None,\n            pagebreak_after=None,\n            pagebreak_before=None,\n            word_spacing=None,\n            unqid=None,\n            cls=None,\n            ):\n        \"\"\"Set any or all properties of a node.\n\n        To be used for existing nodes preferably.\n        \"\"\"\n        root = self.root\n        temp = root.add_division()\n        if align is not None:\n            temp.set_align(align)\n        if bgcolor is not None:\n            temp.set_bgcolor(bgcolor)\n        if bold is not None:\n            temp.set_bold(bold)\n        if color is not None:\n            temp.set_color(color)\n        if columns is not None:\n            temp.set_columns(columns)\n        if font is not None:\n            temp.set_font(font)\n        if fontsize is not None:\n            temp.set_fontsize(fontsize)\n        if indent is not None:\n            temp.set_text_indent(indent)\n        if italic is not None:\n            temp.set_italic(italic)\n        if leading is not None:\n            temp.set_leading(leading)\n        if letter_spacing is not None:\n            temp.set_letter_spacing(letter_spacing)\n        if lineheight is not None:\n            temp.set_lineheight(lineheight)\n        if margins is not None:\n            temp.set_margins(margins)\n        if pagebreak_after is not None:\n            temp.set_pagebreak_after()\n        if pagebreak_before is not None:\n            temp.set_pagebreak_before()\n        if word_spacing is not None:\n            temp.set_word_spacing(word_spacing)\n        if unqid is not None:\n            self.set_id(unqid)\n        if cls is not None:\n            self.add_class(cls)\n\n        styles = []\n        top_style = temp.get_attribute_value(\"style\")\n        if top_style is not None:\n            styles.append(top_style)\n        child = temp.first_child\n        while child:\n            styles.append(child.get_attribute_value(\"style\"))\n            child = child.first_child\n        self.set_attribute(\"style\", \";\".join(styles))\n        temp.remove()\n        return self\n\n    def set_text_indent(self, indent):\n        \"\"\"Set text indentation name via CSS style - block-level only.\"\"\"\n        self.add_style(f\"text-indent: {indent}\")\n        return self\n\n    def set_underline(self, val=\"underline\"):\n        self.append_styled_span(f\"text-decoration: {val}\")\n        return self\n\n    def set_word_spacing(self, spacing):\n        \"\"\"Set inter-word spacing value via CSS style\"\"\"\n        self.append_styled_span(f\"word-spacing: {spacing}\")\n        return self\n\n    def span_bottom(self):\n        \"\"\"Find deepest level in stacked spans.\"\"\"\n        parent = self\n        child = self.last_child\n        if child is None:\n            return None\n        while child.is_text:\n            child = child.previous\n            if child is None:\n                break\n        if child is None or child.tagname != \"span\":\n            return None\n\n        while True:\n            if child is None:\n                return parent\n            if child.tagname in (\"a\", \"sub\",\"sup\",\"body\") or child.is_text:\n                child = child.next\n                continue\n            if child.tagname == \"span\":\n                parent = child\n                child = child.first_child\n            else:\n                return parent\n\n    @property\n    def tagname( self):\n        return mupdf.fz_xml_tag( self.this)\n    \n    @property\n    def text( self):\n        return mupdf.fz_xml_text( self.this)\n    \n    add_var = add_code\n    add_samp = add_code\n    add_kbd = add_code\n\n\nclass Colorspace:\n\n    def __init__(self, type_):\n        \"\"\"Supported are GRAY, RGB and CMYK.\"\"\"\n        if isinstance( type_, mupdf.FzColorspace):\n            self.this = type_\n        elif type_ == CS_GRAY:\n            self.this = mupdf.FzColorspace(mupdf.FzColorspace.Fixed_GRAY)\n        elif type_ == CS_CMYK:\n            self.this = mupdf.FzColorspace(mupdf.FzColorspace.Fixed_CMYK)\n        elif type_ == CS_RGB:\n            self.this = mupdf.FzColorspace(mupdf.FzColorspace.Fixed_RGB)\n        else:\n            self.this = mupdf.FzColorspace(mupdf.FzColorspace.Fixed_RGB)\n\n    def __repr__(self):\n        x = (\"\", \"GRAY\", \"\", \"RGB\", \"CMYK\")[self.n]\n        return f\"Colorspace(CS_{x}) - {self.name}\"\n\n    def _name(self):\n        return mupdf.fz_colorspace_name(self.this)\n\n    @property\n    def n(self):\n        \"\"\"Size of one pixel.\"\"\"\n        return mupdf.fz_colorspace_n(self.this)\n\n    @property\n    def name(self):\n        \"\"\"Name of the Colorspace.\"\"\"\n        return self._name()\n\n\nclass DeviceWrapper:\n    def __init__(self, *args):\n        if args_match( args, mupdf.FzDevice):\n            device, = args\n            self.this = device\n        elif args_match( args, Pixmap, None):\n            pm, clip = args\n            bbox = JM_irect_from_py( clip)\n            if mupdf.fz_is_infinite_irect( bbox):\n                self.this = mupdf.fz_new_draw_device( mupdf.FzMatrix(), pm)\n            else:\n                self.this = mupdf.fz_new_draw_device_with_bbox( mupdf.FzMatrix(), pm, bbox)\n        elif args_match( args, mupdf.FzDisplayList):\n            dl, = args\n            self.this = mupdf.fz_new_list_device( dl)\n        elif args_match( args, mupdf.FzStextPage, None):\n            tp, flags = args\n            opts = mupdf.FzStextOptions( flags)\n            self.this = mupdf.fz_new_stext_device( tp, opts)\n        else:\n            raise Exception( f'Unrecognised args for DeviceWrapper: {args!r}')\n\n\nclass DisplayList:\n    def __del__(self):\n        if not type(self) is DisplayList: return\n        self.thisown = False\n\n    def __init__(self, *args):\n        if len(args) == 1 and isinstance(args[0], mupdf.FzRect):\n            self.this = mupdf.FzDisplayList(args[0])\n        elif len(args) == 1 and isinstance(args[0], mupdf.FzDisplayList):\n            self.this = args[0]\n        else:\n            assert 0, f'Unrecognised {args=}'\n\n    def get_pixmap(self, matrix=None, colorspace=None, alpha=0, clip=None):\n        if isinstance(colorspace, Colorspace):\n            colorspace = colorspace.this\n        else:\n            colorspace = mupdf.FzColorspace(mupdf.FzColorspace.Fixed_RGB)\n        val = JM_pixmap_from_display_list(self.this, matrix, colorspace, alpha, clip, None)\n        val.thisown = True\n        return val\n\n    def get_textpage(self, flags=3):\n        \"\"\"Make a TextPage from a DisplayList.\"\"\"\n        stext_options = mupdf.FzStextOptions()\n        stext_options.flags = flags\n        val = mupdf.FzStextPage(self.this, stext_options)\n        val.thisown = True\n        return val\n\n    @property\n    def rect(self):\n        val = JM_py_from_rect(mupdf.fz_bound_display_list(self.this))\n        val = Rect(val)\n        return val\n\n    def run(self, dw, m, area):\n        mupdf.fz_run_display_list(\n                self.this,\n                dw.device,\n                JM_matrix_from_py(m),\n                JM_rect_from_py(area),\n                mupdf.FzCookie(),\n                )\n\nif g_use_extra:\n    extra_FzDocument_insert_pdf = extra.FzDocument_insert_pdf\n\n\nclass Document:\n\n    def __contains__(self, loc) -> bool:\n        if type(loc) is int:\n            if loc < self.page_count:\n                return True\n            return False\n        if type(loc) not in (tuple, list) or len(loc) != 2:\n            return False\n        chapter, pno = loc\n        if (0\n                or not isinstance(chapter, int)\n                or chapter < 0\n                or chapter >= self.chapter_count\n                ):\n            return False\n        if (0\n                or not isinstance(pno, int)\n                or pno < 0\n                or pno >= self.chapter_page_count(chapter)\n                ):\n            return False\n        return True\n\n    def __delitem__(self, i)->None:\n        if not self.is_pdf:\n            raise ValueError(\"is no PDF\")\n        if type(i) is int:\n            return self.delete_page(i)\n        if type(i) in (list, tuple, range):\n            return self.delete_pages(i)\n        if type(i) is not slice:\n            raise ValueError(\"bad argument type\")\n        pc = self.page_count\n        start = i.start if i.start else 0\n        stop = i.stop if i.stop else pc\n        step = i.step if i.step else 1\n        while start < 0:\n            start += pc\n        if start >= pc:\n            raise ValueError(\"bad page number(s)\")\n        while stop < 0:\n            stop += pc\n        if stop > pc:\n            raise ValueError(\"bad page number(s)\")\n        return self.delete_pages(range(start, stop, step))\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, *args):\n        self.close()\n\n    @typing.overload\n    def __getitem__(self, i: int = 0) -> Page:\n        ...\n    \n    if sys.version_info >= (3, 9):\n        @typing.overload\n        def __getitem__(self, i: slice) -> list[Page]:\n            ...\n        \n        @typing.overload\n        def __getitem__(self, i: tuple[int, int]) -> Page:\n            ...\n    \n    def __getitem__(self, i=0):\n        if isinstance(i, slice):\n            return [self[j] for j in range(*i.indices(len(self)))]\n        assert isinstance(i, int) or (isinstance(i, tuple) and len(i) == 2 and all(isinstance(x, int) for x in i)), \\\n                f'Invalid item number: {i=}.'\n        if i not in self:\n            raise IndexError(f\"page {i} not in document\")\n        return self.load_page(i)\n\n    def __init__(self, filename=None, stream=None, filetype=None, rect=None, width=0, height=0, fontsize=11):\n        \"\"\"Creates a document. Use 'open' as a synonym.\n\n        Notes:\n            Basic usages:\n            open() - new PDF document\n            open(filename) - string or pathlib.Path, must have supported\n                    file extension.\n            open(type, buffer) - type: valid extension, buffer: bytes object.\n            open(stream=buffer, filetype=type) - keyword version of previous.\n            open(filename, fileype=type) - filename with unrecognized extension.\n            rect, width, height, fontsize: layout reflowable document\n            on open (e.g. EPUB). Ignored if n/a.\n        \"\"\"\n        # We temporarily set JM_mupdf_show_errors=0 while we are constructing,\n        # then restore its original value in a `finally:` block.\n        #\n        global JM_mupdf_show_errors\n        JM_mupdf_show_errors_old = JM_mupdf_show_errors\n        JM_mupdf_show_errors = 0\n        \n        try:\n            self.is_closed    = False\n            self.is_encrypted = False\n            self.is_encrypted = False\n            self.metadata    = None\n            self.FontInfos   = []\n            self.Graftmaps   = {}\n            self.ShownPages  = {}\n            self.InsertedImages  = {}\n            self._page_refs  = weakref.WeakValueDictionary()\n            if isinstance(filename, mupdf.PdfDocument):\n                pdf_document = filename\n                self.this = pdf_document\n                self.this_is_pdf = True\n                return\n        \n            w = width\n            h = height\n            r = JM_rect_from_py(rect)\n            if not mupdf.fz_is_infinite_rect(r):\n                w = r.x1 - r.x0\n                h = r.y1 - r.y0\n\n            self._name = filename\n            self.stream = stream\n            \n            if stream is not None:\n                if filename is not None and filetype is None:\n                    # 2025-05-06: Use <filename> as the filetype. This is\n                    # reversing precedence - we used to use <filename> if both\n                    # were set.\n                    filetype = filename\n                if isinstance(stream, (bytes, memoryview)):\n                    pass\n                elif isinstance(stream, bytearray):\n                    stream = bytes(stream)\n                elif isinstance(stream, io.BytesIO):\n                    stream = stream.getvalue()\n                else:\n                    raise TypeError(f\"bad stream: {type(stream)=}.\")\n                self.stream = stream\n                \n                assert isinstance(stream, (bytes, memoryview))\n                if len(stream) == 0:\n                    # MuPDF raise an exception for this but also generates\n                    # warnings, which is not very helpful for us. So instead we\n                    # raise a specific exception.\n                    raise EmptyFileError('Cannot open empty stream.')\n                    \n                stream2 = mupdf.fz_open_memory(mupdf.python_buffer_data(stream), len(stream))\n                try:\n                    doc = mupdf.fz_open_document_with_stream(filetype if filetype else '', stream2)\n                except Exception as e:\n                    if g_exceptions_verbose > 1:    exception_info()\n                    raise FileDataError('Failed to open stream') from e\n            \n            elif filename:\n                assert not stream\n                if isinstance(filename, str):\n                    pass\n                elif hasattr(filename, \"absolute\"):\n                    filename = str(filename)\n                elif hasattr(filename, \"name\"):\n                    filename = filename.name\n                else:\n                    raise TypeError(f\"bad filename: {type(filename)=} {filename=}.\")\n                self._name = filename\n                \n                # Generate our own specific exceptions. This avoids MuPDF\n                # generating warnings etc.\n                if not os.path.exists(filename):\n                    raise FileNotFoundError(f\"no such file: '{filename}'\")\n                elif not os.path.isfile(filename):\n                    raise FileDataError(f\"'{filename}' is no file\")\n                elif os.path.getsize(filename) == 0:\n                    raise EmptyFileError(f'Cannot open empty file: {filename=}.')\n                \n                if filetype:\n                    # Override the type implied by <filename>. MuPDF does not\n                    # have a way to do this directly so we open via a stream.\n                    try:\n                        fz_stream = mupdf.fz_open_file(filename)\n                        doc = mupdf.fz_open_document_with_stream(filetype, fz_stream)\n                    except Exception as e:\n                        if g_exceptions_verbose > 1:    exception_info()\n                        raise FileDataError(f'Failed to open file {filename!r} as type {filetype!r}.') from e\n                else:\n                    try:\n                        doc = mupdf.fz_open_document(filename)\n                    except Exception as e:\n                        if g_exceptions_verbose > 1:    exception_info()\n                        raise FileDataError(f'Failed to open file {filename!r}.') from e\n\n            else:\n                pdf = mupdf.PdfDocument()\n                doc = mupdf.FzDocument(pdf)\n            \n            if w > 0 and h > 0:\n                mupdf.fz_layout_document(doc, w, h, fontsize)\n            elif mupdf.fz_is_document_reflowable(doc):\n                mupdf.fz_layout_document(doc, 400, 600, 11)\n\n            self.this = doc\n\n            # fixme: not sure where self.thisown gets initialised in PyMuPDF.\n            #\n            self.thisown = True\n\n            if self.thisown:\n                self._graft_id = TOOLS.gen_id()\n                if self.needs_pass:\n                    self.is_encrypted = True\n                else: # we won't init until doc is decrypted\n                    self.init_doc()\n                # the following hack detects invalid/empty SVG files, which else may lead\n                # to interpreter crashes\n                if filename and filename.lower().endswith(\"svg\") or filetype and \"svg\" in filetype.lower():\n                    try:\n                        _ = self.convert_to_pdf()  # this seems to always work\n                    except Exception as e:\n                        if g_exceptions_verbose > 1:    exception_info()\n                        raise FileDataError(\"cannot open broken document\") from e\n\n            if g_use_extra:\n                self.this_is_pdf = isinstance( self.this, mupdf.PdfDocument)\n                if self.this_is_pdf:\n                    self.page_count2 = extra.page_count_pdf\n                else:\n                    self.page_count2 = extra.page_count_fz\n        finally:\n            JM_mupdf_show_errors = JM_mupdf_show_errors_old\n    \n    def __len__(self) -> int:\n        return self.page_count\n\n    def __repr__(self) -> str:\n        is_closed = \"closed \" if self.is_closed else \"\"\n        if self.stream is None:\n            if self.name == \"\":\n                return f\"{is_closed}Document(<new PDF, doc# {self._graft_id:d}>)\"\n            return f\"{is_closed}Document('{self.name}')\"\n        return f\"{is_closed}Document('{self.name}', <memory, doc# {self._graft_id:d}>)\"\n\n    def _addFormFont(self, name, font):\n        \"\"\"Add new form font.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return\n        fonts = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer( pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('AcroForm'),\n                PDF_NAME('DR'),\n                PDF_NAME('Font'),\n                )\n        if not fonts.m_internal or not mupdf.pdf_is_dict( fonts):\n            raise RuntimeError( \"PDF has no form fonts yet\")\n        k = mupdf.pdf_new_name( name)\n        v = JM_pdf_obj_from_str( pdf, font)\n        mupdf.pdf_dict_put( fonts, k, v)\n\n    def del_toc_item(\n            self,\n            idx: int,\n            ) -> None:\n        \"\"\"Delete TOC / bookmark item by index.\"\"\"\n        xref = self.get_outline_xrefs()[idx]\n        self._remove_toc_item(xref)\n\n    def _delToC(self):\n        \"\"\"Delete the TOC.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        xrefs = []  # create Python list\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return xrefs    # not a pdf\n        # get the main root\n        root = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root'))\n        # get the outline root\n        olroot = mupdf.pdf_dict_get(root, PDF_NAME('Outlines'))\n        if not olroot.m_internal:\n            return xrefs    # no outlines or some problem\n\n        first = mupdf.pdf_dict_get(olroot, PDF_NAME('First'))  # first outline\n\n        xrefs = JM_outline_xrefs(first, xrefs)\n        xref_count = len(xrefs)\n\n        olroot_xref = mupdf.pdf_to_num(olroot) # delete OL root\n        mupdf.pdf_delete_object(pdf, olroot_xref)  # delete OL root\n        mupdf.pdf_dict_del(root, PDF_NAME('Outlines')) # delete OL root\n\n        for i in range(xref_count):\n            _, xref = JM_INT_ITEM(xrefs, i)\n            mupdf.pdf_delete_object(pdf, xref) # delete outline item\n        xrefs.append(olroot_xref)\n        val = xrefs\n        self.init_doc()\n        return val\n\n    def _delete_page(self, pno):\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_delete_page( pdf, pno)\n        if pdf.m_internal.rev_page_map:\n            mupdf.ll_pdf_drop_page_tree( pdf.m_internal)\n\n    def _deleteObject(self, xref):\n        \"\"\"Delete object.\"\"\"\n        pdf = _as_pdf_document(self)\n        if not _INRANGE(xref, 1, mupdf.pdf_xref_len(pdf)-1):\n            raise ValueError( MSG_BAD_XREF)\n        mupdf.pdf_delete_object(pdf, xref)\n\n    def _do_links(\n            doc1: 'Document',\n            doc2: 'Document',\n            from_page: int = -1,\n            to_page: int = -1,\n            start_at: int = -1,\n            ) -> None:\n        \"\"\"Insert links contained in copied page range into destination PDF.\n\n        Parameter values **must** equal those of method insert_pdf(), which must\n        have been previously executed.\n        \"\"\"\n        #pymupdf.log( 'utils.do_links()')\n        # --------------------------------------------------------------------------\n        # internal function to create the actual \"/Annots\" object string\n        # --------------------------------------------------------------------------\n        def cre_annot(lnk, xref_dst, pno_src, ctm):\n            \"\"\"Create annotation object string for a passed-in link.\"\"\"\n\n            r = lnk[\"from\"] * ctm  # rect in PDF coordinates\n            rect = _format_g(tuple(r))\n            if lnk[\"kind\"] == LINK_GOTO:\n                txt = annot_skel[\"goto1\"]  # annot_goto\n                idx = pno_src.index(lnk[\"page\"])\n                p = lnk[\"to\"] * ctm  # target point in PDF coordinates\n                annot = txt(xref_dst[idx], p.x, p.y, lnk[\"zoom\"], rect)\n\n            elif lnk[\"kind\"] == LINK_GOTOR:\n                if lnk[\"page\"] >= 0:\n                    txt = annot_skel[\"gotor1\"]  # annot_gotor\n                    pnt = lnk.get(\"to\", Point(0, 0))  # destination point\n                    if type(pnt) is not Point:\n                        pnt = Point(0, 0)\n                    annot = txt(\n                        lnk[\"page\"],\n                        pnt.x,\n                        pnt.y,\n                        lnk[\"zoom\"],\n                        lnk[\"file\"],\n                        lnk[\"file\"],\n                        rect,\n                    )\n                else:\n                    txt = annot_skel[\"gotor2\"]  # annot_gotor_n\n                    to = get_pdf_str(lnk[\"to\"])\n                    to = to[1:-1]\n                    f = lnk[\"file\"]\n                    annot = txt(to, f, rect)\n\n            elif lnk[\"kind\"] == LINK_LAUNCH:\n                txt = annot_skel[\"launch\"]  # annot_launch\n                annot = txt(lnk[\"file\"], lnk[\"file\"], rect)\n\n            elif lnk[\"kind\"] == LINK_URI:\n                txt = annot_skel[\"uri\"]  # annot_uri\n                annot = txt(lnk[\"uri\"], rect)\n\n            else:\n                annot = \"\"\n\n            return annot\n\n        # --------------------------------------------------------------------------\n\n        # validate & normalize parameters\n        if from_page < 0:\n            fp = 0\n        elif from_page >= doc2.page_count:\n            fp = doc2.page_count - 1\n        else:\n            fp = from_page\n\n        if to_page < 0 or to_page >= doc2.page_count:\n            tp = doc2.page_count - 1\n        else:\n            tp = to_page\n\n        if start_at < 0:\n            raise ValueError(\"'start_at' must be >= 0\")\n        sa = start_at\n\n        incr = 1 if fp <= tp else -1  # page range could be reversed\n\n        # lists of source / destination page numbers\n        pno_src = list(range(fp, tp + incr, incr))\n        pno_dst = [sa + i for i in range(len(pno_src))]\n\n        # lists of source / destination page xrefs\n        xref_src = []\n        xref_dst = []\n        for i in range(len(pno_src)):\n            p_src = pno_src[i]\n            p_dst = pno_dst[i]\n            old_xref = doc2.page_xref(p_src)\n            new_xref = doc1.page_xref(p_dst)\n            xref_src.append(old_xref)\n            xref_dst.append(new_xref)\n\n        # create the links for each copied page in destination PDF\n        for i in range(len(xref_src)):\n            page_src = doc2[pno_src[i]]  # load source page\n            links = page_src.get_links()  # get all its links\n            #log(f'{pno_src=}')\n            #log(f'{type(page_src)=}')\n            #log(f'{page_src=}')\n            #log(f'{=i len(links)}')\n            if len(links) == 0:  # no links there\n                page_src = None\n                continue\n            page_dst = doc1[pno_dst[i]]  # load destination page\n            \n            # In our call above to page_src.get_links(), we end up in\n            # fz_load_links(). This extracts the raw rects (encoded as strings\n            # such as `/Rect[10 782 40 822]`) and multiplies them by page_ctm\n            # from pdf_page_transform().\n            #\n            # We want to recreate the original raw rects, so we need to\n            # multiply by inverse of page_ctm. This fixes #4958.\n            ctm = mupdf.FzMatrix()\n            page_src_pdf_document = _as_pdf_page(page_src)\n            mupdf.pdf_page_transform(page_src_pdf_document, mupdf.FzRect(0), ctm)\n            ictm = Matrix(mupdf.fz_invert_matrix(ctm))\n\n            link_tab = []  # store all link definitions here\n            for l in links:\n                if l[\"kind\"] == LINK_GOTO and (l[\"page\"] not in pno_src):\n                    continue  # GOTO link target not in copied pages\n                annot_text = cre_annot(l, xref_dst, pno_src, ictm)\n                if annot_text:\n                    link_tab.append(annot_text)\n            if link_tab != []:\n                page_dst._addAnnot_FromString( tuple(link_tab))\n        #log( 'utils.do_links() returning.')\n\n    def _do_widgets(\n            tar: 'Document',\n            src: 'Document',\n            graftmap,\n            from_page: int = -1,\n            to_page: int = -1,\n            start_at: int = -1,\n            join_duplicates=0,\n            ) -> None:\n        \"\"\"Insert widgets of copied page range into target PDF.\n\n        Parameter values **must** equal those of method insert_pdf() which\n        must have been previously executed.\n        \"\"\"\n        if not src.is_form_pdf:  # nothing to do: source PDF has no fields\n            return\n\n        def clean_kid_parents(acro_fields):\n            \"\"\" Make sure all kids have correct \"Parent\" pointers.\"\"\"\n            for i in range(acro_fields.pdf_array_len()):\n                parent = acro_fields.pdf_array_get(i)\n                kids = parent.pdf_dict_get(PDF_NAME(\"Kids\"))\n                for j in range(kids.pdf_array_len()):\n                    kid = kids.pdf_array_get(j)\n                    kid.pdf_dict_put(PDF_NAME(\"Parent\"), parent)\n\n        def join_widgets(pdf, acro_fields, xref1, xref2, name):\n            \"\"\"Called for each pair of widgets having the same name.\n\n            Args:\n                pdf: target MuPDF document\n                acro_fields: object Root/AcroForm/Fields\n                xref1, xref2: widget xrefs having same names\n                name: (str) the name\n\n            Result:\n                Defined or updated widget parent that points to both widgets.\n            \"\"\"\n\n            def re_target(pdf, acro_fields, xref1, kids1, xref2, kids2):\n                \"\"\"Merge widget in xref2 into \"Kids\" list of widget xref1.\n\n                Args:\n                    xref1, kids1: target widget and its \"Kids\" array.\n                    xref2, kids2: source wwidget and its \"Kids\" array (may be empty).\n                \"\"\"\n                # make indirect objects from widgets\n                w1_ind = mupdf.pdf_new_indirect(pdf, xref1, 0)\n                w2_ind = mupdf.pdf_new_indirect(pdf, xref2, 0)\n                # find source widget in \"Fields\" array\n                idx = acro_fields.pdf_array_find(w2_ind)\n                acro_fields.pdf_array_delete(idx)\n\n                if not kids2.pdf_is_array():  # source widget has no kids\n                    widget = mupdf.pdf_load_object(pdf, xref2)\n\n                    # delete name from widget and insert target as parent\n                    widget.pdf_dict_del(PDF_NAME(\"T\"))\n                    widget.pdf_dict_put(PDF_NAME(\"Parent\"), w1_ind)\n\n                    # put in target Kids\n                    kids1.pdf_array_push(w2_ind)\n                else:  # copy source kids to target kids\n                    for i in range(kids2.pdf_array_len()):\n                        kid = kids2.pdf_array_get(i)\n                        kid.pdf_dict_put(PDF_NAME(\"Parent\"), w1_ind)\n                        kid_ind = mupdf.pdf_new_indirect(pdf, kid.pdf_to_num(), 0)\n                        kids1.pdf_array_push(kid_ind)\n\n            def new_target(pdf, acro_fields, xref1, w1, xref2, w2, name):\n                \"\"\"Make new \"Parent\" for two widgets with same name.\n\n                Args:\n                    xref1, w1: first widget\n                    xref2, w2: second widget\n                    name: field name\n\n                Result:\n                    Both widgets have no \"Kids\". We create a new object with the\n                    name and a \"Kids\" array containing the widgets.\n                    Original widgets must be removed from AcroForm/Fields.\n                \"\"\"\n                # make new \"Parent\" object\n                new = mupdf.pdf_new_dict(pdf, 5)\n                new.pdf_dict_put_text_string(PDF_NAME(\"T\"), name)\n                kids = new.pdf_dict_put_array(PDF_NAME(\"Kids\"), 2)\n                new_obj = mupdf.pdf_add_object(pdf, new)\n                new_obj_xref = new_obj.pdf_to_num()\n                new_ind = mupdf.pdf_new_indirect(pdf, new_obj_xref, 0)\n\n                # copy over some required source widget properties\n                ft = w1.pdf_dict_get(PDF_NAME(\"FT\"))\n                w1.pdf_dict_del(PDF_NAME(\"FT\"))\n                new_obj.pdf_dict_put(PDF_NAME(\"FT\"), ft)\n\n                aa = w1.pdf_dict_get(PDF_NAME(\"AA\"))\n                w1.pdf_dict_del(PDF_NAME(\"AA\"))\n                new_obj.pdf_dict_put(PDF_NAME(\"AA\"), aa)\n\n                # remove name field, insert \"Parent\" field in source widgets\n                w1.pdf_dict_del(PDF_NAME(\"T\"))\n                w1.pdf_dict_put(PDF_NAME(\"Parent\"), new_ind)\n                w2.pdf_dict_del(PDF_NAME(\"T\"))\n                w2.pdf_dict_put(PDF_NAME(\"Parent\"), new_ind)\n\n                # put source widgets in \"kids\" array\n                ind1 = mupdf.pdf_new_indirect(pdf, xref1, 0)\n                ind2 = mupdf.pdf_new_indirect(pdf, xref2, 0)\n                kids.pdf_array_push(ind1)\n                kids.pdf_array_push(ind2)\n\n                # remove source widgets from \"AcroForm/Fields\"\n                idx = acro_fields.pdf_array_find(ind1)\n                acro_fields.pdf_array_delete(idx)\n                idx = acro_fields.pdf_array_find(ind2)\n                acro_fields.pdf_array_delete(idx)\n\n                acro_fields.pdf_array_push(new_ind)\n\n            w1 = mupdf.pdf_load_object(pdf, xref1)\n            w2 = mupdf.pdf_load_object(pdf, xref2)\n            kids1 = w1.pdf_dict_get(PDF_NAME(\"Kids\"))\n            kids2 = w2.pdf_dict_get(PDF_NAME(\"Kids\"))\n\n            # check which widget has a suitable \"Kids\" array\n            if kids1.pdf_is_array():\n                re_target(pdf, acro_fields, xref1, kids1, xref2, kids2)  # pylint: disable=arguments-out-of-order\n            elif kids2.pdf_is_array():\n                re_target(pdf, acro_fields, xref2, kids2, xref1, kids1)  # pylint: disable=arguments-out-of-order\n            else:\n                new_target(pdf, acro_fields, xref1, w1, xref2, w2, name)  # pylint: disable=arguments-out-of-order\n\n        def get_kids(parent, kids_list):\n            \"\"\"Return xref list of leaf kids for a parent.\n\n            Call with an empty list.\n            \"\"\"\n            kids = mupdf.pdf_dict_get(parent, PDF_NAME(\"Kids\"))\n            if not kids.pdf_is_array():\n                return kids_list\n            for i in range(kids.pdf_array_len()):\n                kid = kids.pdf_array_get(i)\n                if mupdf.pdf_is_dict(mupdf.pdf_dict_get(kid, PDF_NAME(\"Kids\"))):\n                    kids_list = get_kids(kid, kids_list)\n                else:\n                    kids_list.append(kid.pdf_to_num())\n            return kids_list\n\n        def kids_xrefs(widget):\n            \"\"\"Get the xref of top \"Parent\" and the list of leaf widgets.\"\"\"\n            kids_list = []\n            parent = mupdf.pdf_dict_get(widget, PDF_NAME(\"Parent\"))\n            parent_xref = parent.pdf_to_num()\n            if parent_xref == 0:\n                return parent_xref, kids_list\n            kids_list = get_kids(parent, kids_list)\n            return parent_xref, kids_list\n\n        def deduplicate_names(pdf, acro_fields, join_duplicates=False):\n            \"\"\"Handle any widget name duplicates caused by the merge.\"\"\"\n            names = {}  # key is a widget name, value a list of widgets having it.\n\n            # extract all names and widgets in \"AcroForm/Fields\"\n            for i in range(mupdf.pdf_array_len(acro_fields)):\n                wobject = mupdf.pdf_array_get(acro_fields, i)\n                xref = wobject.pdf_to_num()\n\n                # extract widget name and collect widget(s) using it\n                T = mupdf.pdf_dict_get_text_string(wobject, PDF_NAME(\"T\"))\n                xrefs = names.get(T, [])\n                xrefs.append(xref)\n                names[T] = xrefs\n\n            for name, xrefs in names.items():\n                if len(xrefs) < 2:\n                    continue\n                xref0, xref1 = xrefs[:2]  # only exactly 2 should occur!\n                if join_duplicates:  # combine fields with equal names\n                    join_widgets(pdf, acro_fields, xref0, xref1, name)\n                else:  # make field names unique\n                    newname = name + f\" [{xref1}]\"  # append this to the name\n                    wobject = mupdf.pdf_load_object(pdf, xref1)\n                    wobject.pdf_dict_put_text_string(PDF_NAME(\"T\"), newname)\n\n            clean_kid_parents(acro_fields)\n\n        def get_acroform(doc):\n            \"\"\"Retrieve the AcroForm dictionary form a PDF.\"\"\"\n            pdf = mupdf.pdf_document_from_fz_document(doc)\n            # AcroForm (= central form field info)\n            return mupdf.pdf_dict_getp(mupdf.pdf_trailer(pdf), \"Root/AcroForm\")\n\n        tarpdf = mupdf.pdf_document_from_fz_document(tar)\n        srcpdf = mupdf.pdf_document_from_fz_document(src)\n\n        if tar.is_form_pdf:\n            # target is a Form PDF, so use it to include source fields\n            acro = get_acroform(tar)\n            # Important arrays in AcroForm\n            acro_fields = acro.pdf_dict_get(PDF_NAME(\"Fields\"))\n            tar_co = acro.pdf_dict_get(PDF_NAME(\"CO\"))\n            if not tar_co.pdf_is_array():\n                tar_co = acro.pdf_dict_put_array(PDF_NAME(\"CO\"), 5)\n        else:\n            # target is no Form PDF, so copy over source AcroForm\n            acro = mupdf.pdf_deep_copy_obj(get_acroform(src))  # make a copy\n\n            # Clear \"Fields\" and \"CO\" arrays: will be populated by page fields.\n            # This is required to avoid copying unneeded objects.\n            acro.pdf_dict_del(PDF_NAME(\"Fields\"))\n            acro.pdf_dict_put_array(PDF_NAME(\"Fields\"), 5)\n            acro.pdf_dict_del(PDF_NAME(\"CO\"))\n            acro.pdf_dict_put_array(PDF_NAME(\"CO\"), 5)\n\n            # Enrich AcroForm for copying to target\n            acro_graft = mupdf.pdf_graft_mapped_object(graftmap, acro)\n\n            # Insert AcroForm into target PDF\n            acro_tar = mupdf.pdf_add_object(tarpdf, acro_graft)\n            acro_fields = acro_tar.pdf_dict_get(PDF_NAME(\"Fields\"))\n            tar_co = acro_tar.pdf_dict_get(PDF_NAME(\"CO\"))\n\n            # get its xref and insert it into target catalog\n            tar_xref = acro_tar.pdf_to_num()\n            acro_tar_ind = mupdf.pdf_new_indirect(tarpdf, tar_xref, 0)\n            root = mupdf.pdf_dict_get(mupdf.pdf_trailer(tarpdf), PDF_NAME(\"Root\"))\n            root.pdf_dict_put(PDF_NAME(\"AcroForm\"), acro_tar_ind)\n\n        if from_page <= to_page:\n            src_range = range(from_page, to_page + 1)\n        else:\n            src_range = range(from_page, to_page - 1, -1)\n\n        parents = {}  # information about widget parents\n\n        # remove \"P\" owning page reference from all widgets of all source pages\n        for i in src_range:\n            src_page = src[i]\n            for xref in [\n                xref\n                for xref, wtype, _ in src_page.annot_xrefs()\n                if wtype == mupdf.PDF_ANNOT_WIDGET  # pylint: disable=no-member\n            ]:\n                w_obj = mupdf.pdf_load_object(srcpdf, xref)\n                w_obj.pdf_dict_del(PDF_NAME(\"P\"))\n\n                # get the widget's parent structure\n                parent_xref, old_kids = kids_xrefs(w_obj)\n                if parent_xref:\n                    parents[parent_xref] = {\n                        \"new_xref\": 0,\n                        \"old_kids\": old_kids,\n                        \"new_kids\": [],\n                    }\n        # Copy over Parent widgets first - they are not page-dependent\n        for xref in parents.keys():  # pylint: disable=consider-using-dict-items\n            parent = mupdf.pdf_load_object(srcpdf, xref)\n            parent_graft = mupdf.pdf_graft_mapped_object(graftmap, parent)\n            parent_tar = mupdf.pdf_add_object(tarpdf, parent_graft)\n            kids_xrefs_new = get_kids(parent_tar, [])\n            parent_xref_new = parent_tar.pdf_to_num()\n            parent_ind = mupdf.pdf_new_indirect(tarpdf, parent_xref_new, 0)\n            acro_fields.pdf_array_push(parent_ind)\n            parents[xref][\"new_xref\"] = parent_xref_new\n            parents[xref][\"new_kids\"] = kids_xrefs_new\n\n        for i in range(len(src_range)):\n            # read first copied over page in target\n            tar_page = tar[start_at + i]\n\n            # read the original page in the source PDF\n            src_page = src[src_range[i]]\n\n            # now walk through source page widgets and copy over\n            w_xrefs = [  # widget xrefs of the source page\n                xref\n                for xref, wtype, _ in src_page.annot_xrefs()\n                if wtype == mupdf.PDF_ANNOT_WIDGET  # pylint: disable=no-member\n            ]\n            if not w_xrefs:  # no widgets on this source page\n                continue\n\n            # convert to formal PDF page\n            tar_page_pdf = mupdf.pdf_page_from_fz_page(tar_page)\n\n            # extract annotations array\n            tar_annots = mupdf.pdf_dict_get(tar_page_pdf.obj(), PDF_NAME(\"Annots\"))\n            if not mupdf.pdf_is_array(tar_annots):\n                tar_annots = mupdf.pdf_dict_put_array(\n                    tar_page_pdf.obj(), PDF_NAME(\"Annots\"), 5\n                )\n\n            for xref in w_xrefs:\n                w_obj = mupdf.pdf_load_object(srcpdf, xref)\n\n                # check if field takes part in inter-field validations\n                is_aac = mupdf.pdf_is_dict(mupdf.pdf_dict_getp(w_obj, \"AA/C\"))\n\n                # check if parent of widget already in target\n                parent_xref = mupdf.pdf_to_num(\n                    w_obj.pdf_dict_get(PDF_NAME(\"Parent\"))\n                )\n                if parent_xref == 0:  # parent not in target yet\n                    try:\n                        w_obj_graft = mupdf.pdf_graft_mapped_object(graftmap, w_obj)\n                    except Exception as e:\n                        message_warning(f\"cannot copy widget at {xref=}: {e}\")\n                        continue\n                    w_obj_tar = mupdf.pdf_add_object(tarpdf, w_obj_graft)\n                    tar_xref = w_obj_tar.pdf_to_num()\n                    w_obj_tar_ind = mupdf.pdf_new_indirect(tarpdf, tar_xref, 0)\n                    mupdf.pdf_array_push(tar_annots, w_obj_tar_ind)\n                    mupdf.pdf_array_push(acro_fields, w_obj_tar_ind)\n                else:\n                    parent = parents[parent_xref]\n                    idx = parent[\"old_kids\"].index(xref)  # search for xref in parent\n                    tar_xref = parent[\"new_kids\"][idx]\n                    w_obj_tar_ind = mupdf.pdf_new_indirect(tarpdf, tar_xref, 0)\n                    mupdf.pdf_array_push(tar_annots, w_obj_tar_ind)\n\n                # Into \"AcroForm/CO\" if a computation field.\n                if is_aac:\n                    mupdf.pdf_array_push(tar_co, w_obj_tar_ind)\n\n        deduplicate_names(tarpdf, acro_fields, join_duplicates=join_duplicates)\n\n    def _embeddedFileGet(self, idx):\n        pdf = _as_pdf_document(self)\n        names = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer(pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('Names'),\n                PDF_NAME('EmbeddedFiles'),\n                PDF_NAME('Names'),\n                )\n        entry = mupdf.pdf_array_get(names, 2*idx+1)\n        filespec = mupdf.pdf_dict_getl(entry, PDF_NAME('EF'), PDF_NAME('F'))\n        buf = mupdf.pdf_load_stream(filespec)\n        cont = JM_BinFromBuffer(buf)\n        return cont\n\n    def _embeddedFileIndex(self, item: typing.Union[int, str]) -> int:\n        filenames = self.embfile_names()\n        if item in filenames:\n            idx = filenames.index(item)\n        elif item in range(len(filenames)):\n            idx = item\n        else:\n            raise ValueError(f\"'{item}' not in EmbeddedFiles array.\")\n        return idx\n\n    def _embfile_add(self, name, buffer_, filename=None, ufilename=None, desc=None):\n        pdf = _as_pdf_document(self)\n        data = JM_BufferFromBytes(buffer_)\n        if not data.m_internal:\n            raise TypeError( MSG_BAD_BUFFER)\n\n        names = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer(pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('Names'),\n                PDF_NAME('EmbeddedFiles'),\n                PDF_NAME('Names'),\n                )\n        if not mupdf.pdf_is_array(names):\n            root = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root'))\n            names = mupdf.pdf_new_array(pdf, 6)    # an even number!\n            mupdf.pdf_dict_putl(\n                    root,\n                    names,\n                    PDF_NAME('Names'),\n                    PDF_NAME('EmbeddedFiles'),\n                    PDF_NAME('Names'),\n                    )\n        fileentry = JM_embed_file(pdf, data, filename, ufilename, desc, 1)\n        xref = mupdf.pdf_to_num(\n                mupdf.pdf_dict_getl(fileentry, PDF_NAME('EF'), PDF_NAME('F'))\n                )\n        mupdf.pdf_array_push(names, mupdf.pdf_new_text_string(name))\n        mupdf.pdf_array_push(names, fileentry)\n        return xref\n\n    def _embfile_del(self, idx):\n        pdf = _as_pdf_document(self)\n        names = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer(pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('Names'),\n                PDF_NAME('EmbeddedFiles'),\n                PDF_NAME('Names'),\n                )\n        mupdf.pdf_array_delete(names, idx + 1)\n        mupdf.pdf_array_delete(names, idx)\n\n    def _embfile_info(self, idx, infodict):\n        pdf = _as_pdf_document(self)\n        xref = 0\n        ci_xref=0\n\n        trailer = mupdf.pdf_trailer(pdf)\n\n        names = mupdf.pdf_dict_getl(\n                trailer,\n                PDF_NAME('Root'),\n                PDF_NAME('Names'),\n                PDF_NAME('EmbeddedFiles'),\n                PDF_NAME('Names'),\n                )\n        o = mupdf.pdf_array_get(names, 2*idx+1)\n        ci = mupdf.pdf_dict_get(o, PDF_NAME('CI'))\n        if ci.m_internal:\n            ci_xref = mupdf.pdf_to_num(ci)\n        infodict[\"collection\"] = ci_xref\n        name = mupdf.pdf_to_text_string(mupdf.pdf_dict_get(o, PDF_NAME('F')))\n        infodict[dictkey_filename] = JM_EscapeStrFromStr(name)\n\n        name = mupdf.pdf_to_text_string(mupdf.pdf_dict_get(o, PDF_NAME('UF')))\n        infodict[dictkey_ufilename] = JM_EscapeStrFromStr(name)\n\n        name = mupdf.pdf_to_text_string(mupdf.pdf_dict_get(o, PDF_NAME('Desc')))\n        infodict[dictkey_descr] = JM_UnicodeFromStr(name)\n\n        len_ = -1\n        DL = -1\n        fileentry = mupdf.pdf_dict_getl(o, PDF_NAME('EF'), PDF_NAME('F'))\n        xref = mupdf.pdf_to_num(fileentry)\n        o = mupdf.pdf_dict_get(fileentry, PDF_NAME('Length'))\n        if o.m_internal:\n            len_ = mupdf.pdf_to_int(o)\n\n        o = mupdf.pdf_dict_get(fileentry, PDF_NAME('DL'))\n        if o.m_internal:\n            DL = mupdf.pdf_to_int(o)\n        else:\n            o = mupdf.pdf_dict_getl(fileentry, PDF_NAME('Params'), PDF_NAME('Size'))\n            if o.m_internal:\n                DL = mupdf.pdf_to_int(o)\n        infodict[dictkey_size] = DL\n        infodict[dictkey_length] = len_\n        return xref\n\n    def _embfile_names(self, namelist):\n        \"\"\"Get list of embedded file names.\"\"\"\n        pdf = _as_pdf_document(self)\n        names = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer(pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('Names'),\n                PDF_NAME('EmbeddedFiles'),\n                PDF_NAME('Names'),\n                )\n        if mupdf.pdf_is_array(names):\n            n = mupdf.pdf_array_len(names)\n            for i in range(0, n, 2):\n                val = JM_EscapeStrFromStr(\n                        mupdf.pdf_to_text_string(\n                            mupdf.pdf_array_get(names, i)\n                            )\n                        )\n                namelist.append(val)\n\n    def _embfile_upd(self, idx, buffer_=None, filename=None, ufilename=None, desc=None):\n        pdf = _as_pdf_document(self)\n        xref = 0\n        names = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer(pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('Names'),\n                PDF_NAME('EmbeddedFiles'),\n                PDF_NAME('Names'),\n                )\n        entry = mupdf.pdf_array_get(names, 2*idx+1)\n\n        filespec = mupdf.pdf_dict_getl(entry, PDF_NAME('EF'), PDF_NAME('F'))\n        if not filespec.m_internal:\n            RAISEPY( \"bad PDF: no /EF object\", JM_Exc_FileDataError)\n        res = JM_BufferFromBytes(buffer_)\n        if buffer_ and buffer_.m_internal and not res.m_internal:\n            raise TypeError( MSG_BAD_BUFFER)\n        if res.m_internal and buffer_ and buffer_.m_internal:\n            JM_update_stream(pdf, filespec, res, 1)\n            # adjust /DL and /Size parameters\n            len, _ = mupdf.fz_buffer_storage(res)\n            l = mupdf.pdf_new_int(len)\n            mupdf.pdf_dict_put(filespec, PDF_NAME('DL'), l)\n            mupdf.pdf_dict_putl(filespec, l, PDF_NAME('Params'), PDF_NAME('Size'))\n        xref = mupdf.pdf_to_num(filespec)\n        if filename:\n            mupdf.pdf_dict_put_text_string(entry, PDF_NAME('F'), filename)\n\n        if ufilename:\n            mupdf.pdf_dict_put_text_string(entry, PDF_NAME('UF'), ufilename)\n\n        if desc:\n            mupdf.pdf_dict_put_text_string(entry, PDF_NAME('Desc'), desc)\n        return xref\n\n    def _extend_toc_items(self, items):\n        \"\"\"Add color info to all items of an extended TOC list.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        if g_use_extra:\n            return extra.Document_extend_toc_items( self.this, items)\n        pdf = _as_pdf_document(self)\n        zoom = \"zoom\"\n        bold = \"bold\"\n        italic = \"italic\"\n        collapse = \"collapse\"\n\n        root = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root'))\n        if not root.m_internal:\n            return\n        olroot = mupdf.pdf_dict_get(root, PDF_NAME('Outlines'))\n        if not olroot.m_internal:\n            return\n        first = mupdf.pdf_dict_get(olroot, PDF_NAME('First'))\n        if not first.m_internal:\n            return\n        xrefs = []\n        xrefs = JM_outline_xrefs(first, xrefs)\n        n = len(xrefs)\n        m = len(items)\n        if not n:\n            return\n        if n != m:\n            raise IndexError( \"internal error finding outline xrefs\")\n\n        # update all TOC item dictionaries\n        for i in range(n):\n            xref = int(xrefs[i])\n            item = items[i]\n            itemdict = item[3]\n            if not isinstance(itemdict, dict):\n                raise ValueError( \"need non-simple TOC format\")\n            itemdict[dictkey_xref] = xrefs[i]\n            bm = mupdf.pdf_load_object(pdf, xref)\n            flags = mupdf.pdf_to_int( mupdf.pdf_dict_get(bm, PDF_NAME('F')))\n            if flags == 1:\n                itemdict[italic] = True\n            elif flags == 2:\n                itemdict[bold] = True\n            elif flags == 3:\n                itemdict[italic] = True\n                itemdict[bold] = True\n            count = mupdf.pdf_to_int( mupdf.pdf_dict_get(bm, PDF_NAME('Count')))\n            if count < 0:\n                itemdict[collapse] = True\n            elif count > 0:\n                itemdict[collapse] = False\n            col = mupdf.pdf_dict_get(bm, PDF_NAME('C'))\n            if mupdf.pdf_is_array(col) and mupdf.pdf_array_len(col) == 3:\n                color = (\n                        mupdf.pdf_to_real(mupdf.pdf_array_get(col, 0)),\n                        mupdf.pdf_to_real(mupdf.pdf_array_get(col, 1)),\n                        mupdf.pdf_to_real(mupdf.pdf_array_get(col, 2)),\n                        )\n                itemdict[dictkey_color] = color\n            z=0\n            obj = mupdf.pdf_dict_get(bm, PDF_NAME('Dest'))\n            if not obj.m_internal or not mupdf.pdf_is_array(obj):\n                obj = mupdf.pdf_dict_getl(bm, PDF_NAME('A'), PDF_NAME('D'))\n            if mupdf.pdf_is_array(obj) and mupdf.pdf_array_len(obj) == 5:\n                z = mupdf.pdf_to_real(mupdf.pdf_array_get(obj, 4))\n            itemdict[zoom] = float(z)\n            item[3] = itemdict\n            items[i] = item\n\n    def _forget_page(self, page: Page):\n        \"\"\"Remove a page from document page dict.\"\"\"\n        pid = id(page)\n        if pid in self._page_refs:\n            #self._page_refs[pid] = None\n            del self._page_refs[pid]\n\n    def _get_char_widths(self, xref: int, bfname: str, ext: str, ordering: int, limit: int, idx: int = 0):\n        pdf = _as_pdf_document(self)\n        mylimit = limit\n        if mylimit < 256:\n            mylimit = 256\n        if ordering >= 0:\n            data, size, index = mupdf.fz_lookup_cjk_font(ordering)\n            font = mupdf.fz_new_font_from_memory(None, data, size, index, 0)\n        else:\n            data, size = mupdf.fz_lookup_base14_font(bfname)\n            if data:\n                font = mupdf.fz_new_font_from_memory(bfname, data, size, 0, 0)\n            else:\n                buf = JM_get_fontbuffer(pdf, xref)\n                if not buf.m_internal:\n                    raise Exception(f\"font at xref {xref:d} is not supported\")\n\n                font = mupdf.fz_new_font_from_buffer(None, buf, idx, 0)\n        wlist = []\n        for i in range(mylimit):\n            glyph = mupdf.fz_encode_character(font, i)\n            adv = mupdf.fz_advance_glyph(font, glyph, 0)\n            if ordering >= 0:\n                glyph = i\n            if glyph > 0:\n                wlist.append( (glyph, adv))\n            else:\n                wlist.append( (glyph, 0.0))\n        return wlist\n\n    def _get_page_labels(self):\n        pdf = _as_pdf_document(self)\n        rc = []\n        pagelabels = mupdf.pdf_new_name(\"PageLabels\")\n        obj = mupdf.pdf_dict_getl( mupdf.pdf_trailer(pdf), PDF_NAME('Root'), pagelabels)\n        if not obj.m_internal:\n            return rc\n        # simple case: direct /Nums object\n        nums = mupdf.pdf_resolve_indirect( mupdf.pdf_dict_get( obj, PDF_NAME('Nums')))\n        if nums.m_internal:\n            JM_get_page_labels(rc, nums)\n            return rc\n        # case: /Kids/Nums\n        nums = mupdf.pdf_resolve_indirect( mupdf.pdf_dict_getl(obj, PDF_NAME('Kids'), PDF_NAME('Nums')))\n        if nums.m_internal:\n            JM_get_page_labels(rc, nums)\n            return rc\n        # case: /Kids is an array of multiple /Nums\n        kids = mupdf.pdf_resolve_indirect( mupdf.pdf_dict_get( obj, PDF_NAME('Kids')))\n        if not kids.m_internal or not mupdf.pdf_is_array(kids):\n            return rc\n        n = mupdf.pdf_array_len(kids)\n        for i in range(n):\n            nums = mupdf.pdf_resolve_indirect(\n                    mupdf.pdf_dict_get(\n                        mupdf.pdf_array_get(kids, i),\n                        PDF_NAME('Nums'),\n                        )\n                    )\n            JM_get_page_labels(rc, nums)\n        return rc\n\n    def _getMetadata(self, key):\n        \"\"\"Get metadata.\"\"\"\n        try:\n            return mupdf.fz_lookup_metadata2( self.this, key)\n        except Exception:\n            if g_exceptions_verbose > 2:    exception_info()\n            return ''\n\n    def _getOLRootNumber(self):\n        \"\"\"Get xref of Outline Root, create it if missing.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        # get main root\n        root = mupdf.pdf_dict_get( mupdf.pdf_trailer( pdf), PDF_NAME('Root'))\n        # get outline root\n        olroot = mupdf.pdf_dict_get( root, PDF_NAME('Outlines'))\n        if not olroot.m_internal:\n            olroot = mupdf.pdf_new_dict( pdf, 4)\n            mupdf.pdf_dict_put( olroot, PDF_NAME('Type'), PDF_NAME('Outlines'))\n            ind_obj = mupdf.pdf_add_object( pdf, olroot)\n            mupdf.pdf_dict_put( root, PDF_NAME('Outlines'), ind_obj)\n            olroot = mupdf.pdf_dict_get( root, PDF_NAME('Outlines'))\n        return mupdf.pdf_to_num( olroot)\n\n    def _getPDFfileid(self):\n        \"\"\"Get PDF file id.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return\n        idlist = []\n        identity = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('ID'))\n        if identity.m_internal:\n            n = mupdf.pdf_array_len(identity)\n            for i in range(n):\n                o = mupdf.pdf_array_get(identity, i)\n                text = mupdf.pdf_to_text_string(o)\n                hex_ = binascii.hexlify(text)\n                idlist.append(hex_)\n        return idlist\n\n    def _getPageInfo(self, pno, what):\n        \"\"\"List fonts, images, XObjects used on a page.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        doc = self.this\n        pageCount = mupdf.pdf_count_pages(doc) if isinstance(doc, mupdf.PdfDocument) else mupdf.fz_count_pages(doc)\n        n = pno  # pno < 0 is allowed\n        while n < 0:\n            n += pageCount  # make it non-negative\n        if n >= pageCount:\n            raise ValueError( MSG_BAD_PAGENO)\n        pdf = _as_pdf_document(self)\n        pageref = mupdf.pdf_lookup_page_obj(pdf, n)\n        rsrc = mupdf.pdf_dict_get_inheritable(pageref, mupdf.PDF_ENUM_NAME_Resources)\n        liste = []\n        tracer = []\n        if rsrc.m_internal:\n            JM_scan_resources(pdf, rsrc, liste, what, 0, tracer)\n        return liste\n\n    def _insert_font(self, fontfile=None, fontbuffer=None):\n        '''\n        Utility: insert font from file or binary.\n        '''\n        pdf = _as_pdf_document(self)\n        if not fontfile and not fontbuffer:\n            raise ValueError( MSG_FILE_OR_BUFFER)\n        value = JM_insert_font(pdf, None, fontfile, fontbuffer, 0, 0, 0, 0, 0, -1)\n        return value\n\n    def _loadOutline(self):\n        \"\"\"Load first outline.\"\"\"\n        doc = self.this\n        assert isinstance( doc, mupdf.FzDocument)\n        try:\n            ol = mupdf.fz_load_outline( doc)\n        except Exception:\n            if g_exceptions_verbose > 1:    exception_info()\n            return\n        return Outline( ol)\n\n    def _make_page_map(self):\n        \"\"\"Make an array page number -> page object.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        assert 0, f'_make_page_map() is no-op'\n\n    def _move_copy_page(self, pno, nb, before, copy):\n        \"\"\"Move or copy a PDF page reference.\"\"\"\n        pdf = _as_pdf_document(self)\n        same = 0\n        # get the two page objects -----------------------------------\n        # locate the /Kids arrays and indices in each\n\n        page1, parent1, i1 = pdf_lookup_page_loc( pdf, pno)\n\n        kids1 = mupdf.pdf_dict_get( parent1, PDF_NAME('Kids'))\n\n        page2, parent2, i2 = pdf_lookup_page_loc( pdf, nb)\n        kids2 = mupdf.pdf_dict_get( parent2, PDF_NAME('Kids'))\n        if before:  # calc index of source page in target /Kids\n            pos = i2\n        else:\n            pos = i2 + 1\n\n        # same /Kids array? ------------------------------------------\n        same = mupdf.pdf_objcmp( kids1, kids2)\n\n        # put source page in target /Kids array ----------------------\n        if not copy and same != 0:  # update parent in page object\n            mupdf.pdf_dict_put( page1, PDF_NAME('Parent'), parent2)\n        mupdf.pdf_array_insert( kids2, page1, pos)\n\n        if same != 0:   # different /Kids arrays ----------------------\n            parent = parent2\n            while parent.m_internal:    # increase /Count objects in parents\n                count = mupdf.pdf_dict_get_int( parent, PDF_NAME('Count'))\n                mupdf.pdf_dict_put_int( parent, PDF_NAME('Count'), count + 1)\n                parent = mupdf.pdf_dict_get( parent, PDF_NAME('Parent'))\n            if not copy:    # delete original item\n                mupdf.pdf_array_delete( kids1, i1)\n                parent = parent1\n                while parent.m_internal:    # decrease /Count objects in parents\n                    count = mupdf.pdf_dict_get_int( parent, PDF_NAME('Count'))\n                    mupdf.pdf_dict_put_int( parent, PDF_NAME('Count'), count - 1)\n                    parent = mupdf.pdf_dict_get( parent, PDF_NAME('Parent'))\n        else:   # same /Kids array\n            if copy:    # source page is copied\n                parent = parent2\n                while parent.m_internal:    # increase /Count object in parents\n                    count = mupdf.pdf_dict_get_int( parent, PDF_NAME('Count'))\n                    mupdf.pdf_dict_put_int( parent, PDF_NAME('Count'), count + 1)\n                    parent = mupdf.pdf_dict_get( parent, PDF_NAME('Parent'))\n            else:\n                if i1 < pos:\n                    mupdf.pdf_array_delete( kids1, i1)\n                else:\n                    mupdf.pdf_array_delete( kids1, i1 + 1)\n        if pdf.m_internal.rev_page_map: # page map no longer valid: drop it\n            mupdf.ll_pdf_drop_page_tree( pdf.m_internal)\n\n        self._reset_page_refs()\n\n    def _newPage(self, pno=-1, width=595, height=842):\n        \"\"\"Make a new PDF page.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if g_use_extra:\n            extra._newPage( self.this, pno, width, height)\n        else:\n            pdf = _as_pdf_document(self)\n            mediabox = mupdf.FzRect(mupdf.FzRect.Fixed_UNIT)\n            mediabox.x1 = width\n            mediabox.y1 = height\n            contents = mupdf.FzBuffer()\n            if pno < -1:\n                raise ValueError( MSG_BAD_PAGENO)\n            # create /Resources and /Contents objects\n            #resources = pdf.add_object(pdf.new_dict(1))\n            resources = mupdf.pdf_add_new_dict(pdf, 1)\n            page_obj = mupdf.pdf_add_page( pdf, mediabox, 0, resources, contents)\n            mupdf.pdf_insert_page( pdf, pno, page_obj)\n        # fixme: pdf->dirty = 1;\n\n        self._reset_page_refs()\n        return self[pno]\n\n    def _remove_links_to(self, numbers):\n        pdf = _as_pdf_document(self)\n        _remove_dest_range(pdf, numbers)\n\n    def _remove_toc_item(self, xref):\n        # \"remove\" bookmark by letting it point to nowhere\n        pdf = _as_pdf_document(self)\n        item = mupdf.pdf_new_indirect(pdf, xref, 0)\n        mupdf.pdf_dict_del( item, PDF_NAME('Dest'))\n        mupdf.pdf_dict_del( item, PDF_NAME('A'))\n        color = mupdf.pdf_new_array( pdf, 3)\n        for i in range(3):\n            mupdf.pdf_array_push_real( color, 0.8)\n        mupdf.pdf_dict_put( item, PDF_NAME('C'), color)\n\n    def _reset_page_refs(self):\n        \"\"\"Invalidate all pages in document dictionary.\"\"\"\n        if getattr(self, \"is_closed\", True):\n            return\n        pages = [p for p in self._page_refs.values()]\n        for page in pages:\n            if page:\n                page._erase()\n                page = None\n        self._page_refs.clear()\n\n    def _set_page_labels(self, labels):\n        pdf = _as_pdf_document(self)\n        pagelabels = mupdf.pdf_new_name(\"PageLabels\")\n        root = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root'))\n        mupdf.pdf_dict_del(root, pagelabels)\n        mupdf.pdf_dict_putl(root, mupdf.pdf_new_array(pdf, 0), pagelabels, PDF_NAME('Nums'))\n\n        xref = self.pdf_catalog()\n        text = self.xref_object(xref, compressed=True)\n        text = text.replace(\"/Nums[]\", f\"/Nums[{labels}]\")\n        self.update_object(xref, text)\n\n    def _update_toc_item(self, xref, action=None, title=None, flags=0, collapse=None, color=None):\n        '''\n        \"update\" bookmark by letting it point to nowhere\n        '''\n        pdf = _as_pdf_document(self)\n        item = mupdf.pdf_new_indirect( pdf, xref, 0)\n        if title:\n            mupdf.pdf_dict_put_text_string( item, PDF_NAME('Title'), title)\n        if action:\n            mupdf.pdf_dict_del( item, PDF_NAME('Dest'))\n            obj = JM_pdf_obj_from_str( pdf, action)\n            mupdf.pdf_dict_put( item, PDF_NAME('A'), obj)\n        mupdf.pdf_dict_put_int( item, PDF_NAME('F'), flags)\n        if color:\n            c = mupdf.pdf_new_array( pdf, 3)\n            for i in range(3):\n                f = color[i]\n                mupdf.pdf_array_push_real( c, f)\n            mupdf.pdf_dict_put( item, PDF_NAME('C'), c)\n        elif color is not None:\n            mupdf.pdf_dict_del( item, PDF_NAME('C'))\n        if collapse is not None:\n            if mupdf.pdf_dict_get( item, PDF_NAME('Count')).m_internal:\n                i = mupdf.pdf_dict_get_int( item, PDF_NAME('Count'))\n                if (i < 0 and collapse is False) or (i > 0 and collapse is True):\n                    i = i * (-1)\n                    mupdf.pdf_dict_put_int( item, PDF_NAME('Count'), i)\n\n    @property\n    def FormFonts(self):\n        \"\"\"Get list of field font resource names.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return\n        fonts = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer(pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('AcroForm'),\n                PDF_NAME('DR'),\n                PDF_NAME('Font'),\n                )\n        liste = list()\n        if fonts.m_internal and mupdf.pdf_is_dict(fonts):   # fonts exist\n            n = mupdf.pdf_dict_len(fonts)\n            for i in range(n):\n                f = mupdf.pdf_dict_get_key(fonts, i)\n                liste.append(JM_UnicodeFromStr(mupdf.pdf_to_name(f)))\n        return liste\n\n    def add_layer(self, name, creator=None, on=None):\n        \"\"\"Add a new OC layer.\"\"\"\n        pdf = _as_pdf_document(self)\n        JM_add_layer_config( pdf, name, creator, on)\n        mupdf.ll_pdf_read_ocg( pdf.m_internal)\n\n    def add_ocg(self, name, config=-1, on=1, intent=None, usage=None):\n        \"\"\"Add new optional content group.\"\"\"\n        xref = 0\n        pdf = _as_pdf_document(self)\n\n        # make the OCG\n        ocg = mupdf.pdf_add_new_dict(pdf, 3)\n        mupdf.pdf_dict_put(ocg, PDF_NAME('Type'), PDF_NAME('OCG'))\n        mupdf.pdf_dict_put_text_string(ocg, PDF_NAME('Name'), name)\n        intents = mupdf.pdf_dict_put_array(ocg, PDF_NAME('Intent'), 2)\n        if not intent:\n            mupdf.pdf_array_push(intents, PDF_NAME('View'))\n        elif not isinstance(intent, str):\n            assert 0, f'fixme: intent is not a str. {type(intent)=} {type=}'\n            #n = len(intent)\n            #for i in range(n):\n            #    item = intent[i]\n            #    c = JM_StrAsChar(item);\n            #    if (c) {\n            #        pdf_array_push(gctx, intents, pdf_new_name(gctx, c));\n            #    }\n            #    Py_DECREF(item);\n            #}\n        else:\n            mupdf.pdf_array_push(intents, mupdf.pdf_new_name(intent))\n        use_for = mupdf.pdf_dict_put_dict(ocg, PDF_NAME('Usage'), 3)\n        ci_name = mupdf.pdf_new_name(\"CreatorInfo\")\n        cre_info = mupdf.pdf_dict_put_dict(use_for, ci_name, 2)\n        mupdf.pdf_dict_put_text_string(cre_info, PDF_NAME('Creator'), \"PyMuPDF\")\n        if usage:\n            mupdf.pdf_dict_put_name(cre_info, PDF_NAME('Subtype'), usage)\n        else:\n            mupdf.pdf_dict_put_name(cre_info, PDF_NAME('Subtype'), \"Artwork\")\n        indocg = mupdf.pdf_add_object(pdf, ocg)\n\n        # Insert OCG in the right config\n        ocp = JM_ensure_ocproperties(pdf)\n        obj = mupdf.pdf_dict_get(ocp, PDF_NAME('OCGs'))\n        mupdf.pdf_array_push(obj, indocg)\n\n        if config > -1:\n            obj = mupdf.pdf_dict_get(ocp, PDF_NAME('Configs'))\n            if not mupdf.pdf_is_array(obj):\n                raise ValueError( MSG_BAD_OC_CONFIG)\n            cfg = mupdf.pdf_array_get(obj, config)\n            if not cfg.m_internal:\n                raise ValueError( MSG_BAD_OC_CONFIG)\n        else:\n            cfg = mupdf.pdf_dict_get(ocp, PDF_NAME('D'))\n\n        obj = mupdf.pdf_dict_get(cfg, PDF_NAME('Order'))\n        if not obj.m_internal:\n            obj = mupdf.pdf_dict_put_array(cfg, PDF_NAME('Order'), 1)\n        mupdf.pdf_array_push(obj, indocg)\n        if on:\n            obj = mupdf.pdf_dict_get(cfg, PDF_NAME('ON'))\n            if not obj.m_internal:\n                obj = mupdf.pdf_dict_put_array(cfg, PDF_NAME('ON'), 1)\n        else:\n            obj =mupdf.pdf_dict_get(cfg, PDF_NAME('OFF'))\n            if not obj.m_internal:\n                obj =mupdf.pdf_dict_put_array(cfg, PDF_NAME('OFF'), 1)\n        mupdf.pdf_array_push(obj, indocg)\n\n        # let MuPDF take note: re-read OCProperties\n        mupdf.ll_pdf_read_ocg(pdf.m_internal)\n\n        xref = mupdf.pdf_to_num(indocg)\n        return xref\n\n    def authenticate(self, password):\n        \"\"\"Decrypt document.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        val = mupdf.fz_authenticate_password(self.this, password)\n        if val:  # the doc is decrypted successfully and we init the outline\n            self.is_encrypted = False\n            self.is_encrypted = False\n            self.init_doc()\n            self.thisown = True\n        return val\n\n    def can_save_incrementally(self):\n        \"\"\"Check whether incremental saves are possible.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return False\n        return mupdf.pdf_can_be_saved_incrementally(pdf)\n\n    def bake(self, *, annots: bool = True, widgets: bool = True) -> None:\n        \"\"\"Convert annotations or fields to permanent content.\n\n        Notes:\n            Converts annotations or widgets to permanent page content, like\n            text and vector graphics, as appropriate.\n            After execution, pages will still look the same, but no longer\n            have annotations, respectively no fields.\n            If widgets are selected the PDF will no longer be a Form PDF.\n\n        Args:\n            annots: convert annotations\n            widgets: convert form fields\n\n        \"\"\"\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_bake_document(pdf, int(annots), int(widgets))\n\n    @property\n    def chapter_count(self):\n        \"\"\"Number of chapters.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        return mupdf.fz_count_chapters( self.this)\n\n    def chapter_page_count(self, chapter):\n        \"\"\"Page count of chapter.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        chapters = mupdf.fz_count_chapters( self.this)\n        if chapter < 0 or chapter >= chapters:\n            raise ValueError( \"bad chapter number\")\n        pages = mupdf.fz_count_chapter_pages( self.this, chapter)\n        return pages\n\n    def close(self):\n        \"\"\"Close document.\"\"\"\n        if getattr(self, \"is_closed\", True):\n            raise ValueError(\"document closed\")\n        # self._cleanup()\n        if hasattr(self, \"_outline\") and self._outline:\n            self._outline = None\n        self._reset_page_refs()\n        #self.metadata    = None\n        #self.stream      = None\n        self.is_closed    = True\n        #self.FontInfos   = []\n        self.Graftmaps = {} # Fixes test_3140().\n        #self.ShownPages = {}\n        #self.InsertedImages  = {}\n        #self.this = None\n        self.this = None\n\n    def convert_to_pdf(self, from_page=0, to_page=-1, rotate=0):\n        \"\"\"Convert document to a PDF, selecting page range and optional rotation. Output bytes object.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        fz_doc = self.this\n        fp = from_page\n        tp = to_page\n        srcCount = mupdf.fz_count_pages(fz_doc)\n        if fp < 0:\n            fp = 0\n        if fp > srcCount - 1:\n            fp = srcCount - 1\n        if tp < 0:\n            tp = srcCount - 1\n        if tp > srcCount - 1:\n            tp = srcCount - 1\n        len0 = len(JM_mupdf_warnings_store)\n        doc = JM_convert_to_pdf(fz_doc, fp, tp, rotate)\n        len1 = len(JM_mupdf_warnings_store)\n        for i in range(len0, len1):\n            message(f'{JM_mupdf_warnings_store[i]}')\n        return doc\n\n    def copy_page(self, pno: int, to: int =-1):\n        \"\"\"Copy a page within a PDF document.\n\n        This will only create another reference of the same page object.\n        Args:\n            pno: source page number\n            to: put before this page, '-1' means after last page.\n        \"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n\n        page_count = len(self)\n        if (\n                pno not in range(page_count)\n                or to not in range(-1, page_count)\n                ):\n            raise ValueError(\"bad page number(s)\")\n        before = 1\n        copy = 1\n        if to == -1:\n            to = page_count - 1\n            before = 0\n\n        return self._move_copy_page(pno, to, before, copy)\n\n    def del_xml_metadata(self):\n        \"\"\"Delete XML metadata.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        root = mupdf.pdf_dict_get( mupdf.pdf_trailer( pdf), PDF_NAME('Root'))\n        if root.m_internal:\n            mupdf.pdf_dict_del( root, PDF_NAME('Metadata'))\n\n    def delete_page(self, pno: int =-1):\n        \"\"\" Delete one page from a PDF.\n        \"\"\"\n        return self.delete_pages(pno)\n\n    def delete_pages(self, *args, **kw):\n        \"\"\"Delete pages from a PDF.\n\n        Args:\n            Either keywords 'from_page'/'to_page', or two integers to\n            specify the first/last page to delete.\n            Or a list/tuple/range object, which can contain arbitrary\n            page numbers.\n            Or a single integer page number.\n        \"\"\"\n        if not self.is_pdf:\n            raise ValueError(\"is no PDF\")\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n\n        page_count = self.page_count  # page count of document\n        f = t = -1\n        if kw:  # check if keywords were used\n            if args:  # then no positional args are allowed\n                raise ValueError(\"cannot mix keyword and positional argument\")\n            f = kw.get(\"from_page\", -1)  # first page to delete\n            t = kw.get(\"to_page\", -1)  # last page to delete\n            while f < 0:\n                f += page_count\n            while t < 0:\n                t += page_count\n            if not f <= t < page_count:\n                raise ValueError(\"bad page number(s)\")\n            numbers = tuple(range(f, t + 1))\n        else:\n            if len(args) > 2 or args == []:\n                raise ValueError(\"need 1 or 2 positional arguments\")\n            if len(args) == 2:\n                f, t = args\n                if not (type(f) is int and type(t) is int):\n                    raise ValueError(\"both arguments must be int\")\n                if f > t:\n                    f, t = t, f\n                if not f <= t < page_count:\n                    raise ValueError(\"bad page number(s)\")\n                numbers = tuple(range(f, t + 1))\n            elif isinstance(args[0], int):\n                pno = args[0]\n                while pno < 0:\n                    pno += page_count\n                numbers = (pno,)\n            else:\n                numbers = tuple(args[0])\n\n        numbers = list(map(int, set(numbers)))  # ensure unique integers\n        if numbers == []:\n            message(\"nothing to delete\")\n            return\n        numbers.sort()\n        if numbers[0] < 0 or numbers[-1] >= page_count:\n            raise ValueError(\"bad page number(s)\")\n        frozen_numbers = frozenset(numbers)\n        toc = self.get_toc()\n        for i, xref in enumerate(self.get_outline_xrefs()):\n            if toc[i][2] - 1 in frozen_numbers:\n                self._remove_toc_item(xref)  # remove target in PDF object\n\n        self._remove_links_to(frozen_numbers)\n\n        for i in reversed(numbers):  # delete pages, last to first\n            self._delete_page(i)\n\n        self._reset_page_refs()\n\n    def embfile_add(self,\n            name: str,\n            buffer_: ByteString,\n            filename: OptStr =None,\n            ufilename: OptStr =None,\n            desc: OptStr =None,\n            ) -> None:\n        \"\"\"Add an item to the EmbeddedFiles array.\n\n        Args:\n            name: name of the new item, must not already exist.\n            buffer_: (binary data) the file content.\n            filename: (str) the file name, default: the name\n            ufilename: (unicode) the file name, default: filename\n            desc: (str) the description.\n        \"\"\"\n        filenames = self.embfile_names()\n        if name in filenames:\n            raise ValueError(f\"Name '{name}' already exists.\")\n        if filename is None:\n            filename = name\n        if ufilename is None:\n            ufilename = filename\n        if desc is None:\n            desc = name\n        xref = self._embfile_add(\n                name,\n                buffer_=buffer_,\n                filename=filename,\n                ufilename=ufilename,\n                desc=desc,\n                )\n        date = get_pdf_now()\n        self.xref_set_key(xref, \"Type\", \"/EmbeddedFile\")\n        self.xref_set_key(xref, \"Params/CreationDate\", get_pdf_str(date))\n        self.xref_set_key(xref, \"Params/ModDate\", get_pdf_str(date))\n        return xref\n\n    def embfile_count(self) -> int:\n        \"\"\"Get number of EmbeddedFiles.\"\"\"\n        return len(self.embfile_names())\n\n    def embfile_del(self, item: typing.Union[int, str]):\n        \"\"\"Delete an entry from EmbeddedFiles.\n\n        Notes:\n            The argument must be name or index of an EmbeddedFiles item.\n            Physical deletion of data will happen on save to a new\n            file with appropriate garbage option.\n        Args:\n            item: name or number of item.\n        Returns:\n            None\n        \"\"\"\n        idx = self._embeddedFileIndex(item)\n        return self._embfile_del(idx)\n\n    def embfile_get(self, item: typing.Union[int, str]) -> bytes:\n        \"\"\"Get the content of an item in the EmbeddedFiles array.\n\n        Args:\n            item: number or name of item.\n        Returns:\n            (bytes) The file content.\n        \"\"\"\n        idx = self._embeddedFileIndex(item)\n        return self._embeddedFileGet(idx)\n\n    def embfile_info(self, item: typing.Union[int, str]) -> dict:\n        \"\"\"Get information of an item in the EmbeddedFiles array.\n\n        Args:\n            item: number or name of item.\n        Returns:\n            Information dictionary.\n        \"\"\"\n        idx = self._embeddedFileIndex(item)\n        infodict = {\"name\": self.embfile_names()[idx]}\n        xref = self._embfile_info(idx, infodict)\n        t, date = self.xref_get_key(xref, \"Params/CreationDate\")\n        if t != \"null\":\n            infodict[\"creationDate\"] = date\n        t, date = self.xref_get_key(xref, \"Params/ModDate\")\n        if t != \"null\":\n            infodict[\"modDate\"] = date\n        t, md5 = self.xref_get_key(xref, \"Params/CheckSum\")\n        if t != \"null\":\n            infodict[\"checksum\"] = binascii.hexlify(md5.encode()).decode()\n        return infodict\n\n    def embfile_names(self) -> list:\n        \"\"\"Get list of names of EmbeddedFiles.\"\"\"\n        filenames = []\n        self._embfile_names(filenames)\n        return filenames\n\n    def embfile_upd(self,\n            item: typing.Union[int, str],\n            buffer_: OptBytes =None,\n            filename: OptStr =None,\n            ufilename: OptStr =None,\n            desc: OptStr =None,\n            ) -> None:\n        \"\"\"Change an item of the EmbeddedFiles array.\n\n        Notes:\n            Only provided parameters are changed. If all are omitted,\n            the method is a no-op.\n        Args:\n            item: number or name of item.\n            buffer_: (binary data) the new file content.\n            filename: (str) the new file name.\n            ufilename: (unicode) the new filen ame.\n            desc: (str) the new description.\n        \"\"\"\n        idx = self._embeddedFileIndex(item)\n        xref = self._embfile_upd(\n                idx,\n                buffer_=buffer_,\n                filename=filename,\n                ufilename=ufilename,\n                desc=desc,\n                )\n        date = get_pdf_now()\n        self.xref_set_key(xref, \"Params/ModDate\", get_pdf_str(date))\n        return xref\n\n    def extract_font(self, xref=0, info_only=0, named=None):\n        '''\n        Get a font by xref. Returns a tuple or dictionary.\n        '''\n        #log(f'{=xref info_only}')\n        pdf = _as_pdf_document(self)\n        obj = mupdf.pdf_load_object(pdf, xref)\n        type_ = mupdf.pdf_dict_get(obj, PDF_NAME('Type'))\n        subtype = mupdf.pdf_dict_get(obj, PDF_NAME('Subtype'))\n        if (mupdf.pdf_name_eq(type_, PDF_NAME('Font'))\n                and not mupdf.pdf_to_name( subtype).startswith('CIDFontType')\n                ):\n            basefont = mupdf.pdf_dict_get(obj, PDF_NAME('BaseFont'))\n            if not basefont.m_internal or mupdf.pdf_is_null(basefont):\n                bname = mupdf.pdf_dict_get(obj, PDF_NAME('Name'))\n            else:\n                bname = basefont\n            ext = JM_get_fontextension(pdf, xref)\n            if ext != 'n/a' and not info_only:\n                buffer_ = JM_get_fontbuffer(pdf, xref)\n                bytes_ = JM_BinFromBuffer(buffer_)\n            else:\n                bytes_ = b''\n            if not named:\n                rc = (\n                        JM_EscapeStrFromStr(mupdf.pdf_to_name(bname)),\n                        JM_UnicodeFromStr(ext),\n                        JM_UnicodeFromStr(mupdf.pdf_to_name(subtype)),\n                        bytes_,\n                        )\n            else:\n                rc = {\n                        dictkey_name: JM_EscapeStrFromStr(mupdf.pdf_to_name(bname)),\n                        dictkey_ext: JM_UnicodeFromStr(ext),\n                        dictkey_type: JM_UnicodeFromStr(mupdf.pdf_to_name(subtype)),\n                        dictkey_content: bytes_,\n                        }\n        else:\n            if not named:\n                rc = '', '', '', b''\n            else:\n                rc = {\n                        dictkey_name: '',\n                        dictkey_ext: '',\n                        dictkey_type: '',\n                        dictkey_content: b'',\n                        }\n        return rc\n\n    def extract_image(self, xref):\n        \"\"\"Get image by xref. Returns a dictionary.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n\n        pdf = _as_pdf_document(self)\n\n        if not _INRANGE(xref, 1, mupdf.pdf_xref_len(pdf)-1):\n            raise ValueError( MSG_BAD_XREF)\n\n        obj = mupdf.pdf_new_indirect(pdf, xref, 0)\n        subtype = mupdf.pdf_dict_get(obj, PDF_NAME('Subtype'))\n\n        if not mupdf.pdf_name_eq(subtype, PDF_NAME('Image')):\n            raise ValueError( \"not an image\")\n\n        o = mupdf.pdf_dict_geta(obj, PDF_NAME('SMask'), PDF_NAME('Mask'))\n        if o.m_internal:\n            smask = mupdf.pdf_to_num(o)\n        else:\n            smask = 0\n\n        # load the image\n        img = mupdf.pdf_load_image(pdf, obj)\n        rc = dict()\n        _make_image_dict(img, rc)\n        rc[dictkey_smask] = smask\n        rc[dictkey_cs_name] = mupdf.fz_colorspace_name(img.colorspace())\n        return rc\n\n    def ez_save(\n            self,\n            filename,\n            garbage=3,\n            clean=False,\n            deflate=True,\n            deflate_images=True,\n            deflate_fonts=True,\n            incremental=False,\n            ascii=False,\n            expand=False,\n            linear=False,\n            pretty=False,\n            encryption=1,\n            permissions=4095,\n            owner_pw=None,\n            user_pw=None,\n            no_new_id=True,\n            preserve_metadata=1,\n            use_objstms=1,\n            compression_effort=0,\n            raise_on_repair=False,\n            ):\n        '''\n        Save PDF using some different defaults\n        '''\n        return self.save(\n                filename,\n                garbage=garbage,\n                clean=clean,\n                deflate=deflate,\n                deflate_images=deflate_images,\n                deflate_fonts=deflate_fonts,\n                incremental=incremental,\n                ascii=ascii,\n                expand=expand,\n                linear=linear,\n                pretty=pretty,\n                encryption=encryption,\n                permissions=permissions,\n                owner_pw=owner_pw,\n                user_pw=user_pw,\n                no_new_id=no_new_id,\n                preserve_metadata=preserve_metadata,\n                use_objstms=use_objstms,\n                compression_effort=compression_effort,\n                raise_on_repair=raise_on_repair,\n                )\n\n    def find_bookmark(self, bm):\n        \"\"\"Find new location after layouting a document.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        location = mupdf.fz_lookup_bookmark2( self.this, bm)\n        return location.chapter, location.page\n\n    def fullcopy_page(self, pno, to=-1):\n        \"\"\"Make a full page duplicate.\"\"\"\n        pdf = _as_pdf_document(self)\n        page_count = mupdf.pdf_count_pages( pdf)\n        try:\n            if (not _INRANGE(pno, 0, page_count - 1)\n                    or not _INRANGE(to, -1, page_count - 1)\n                    ):\n                raise ValueError( MSG_BAD_PAGENO)\n\n            page1 = mupdf.pdf_resolve_indirect( mupdf.pdf_lookup_page_obj( pdf, pno))\n\n            page2 = mupdf.pdf_deep_copy_obj( page1)\n            old_annots = mupdf.pdf_dict_get( page2, PDF_NAME('Annots'))\n\n            # copy annotations, but remove Popup and IRT types\n            if old_annots.m_internal:\n                n = mupdf.pdf_array_len( old_annots)\n                new_annots = mupdf.pdf_new_array( pdf, n)\n                for i in range(n):\n                    o = mupdf.pdf_array_get( old_annots, i)\n                    subtype = mupdf.pdf_dict_get( o, PDF_NAME('Subtype'))\n                    if mupdf.pdf_name_eq( subtype, PDF_NAME('Popup')):\n                        continue\n                    if mupdf.pdf_dict_gets( o, \"IRT\").m_internal:\n                        continue\n                    copy_o = mupdf.pdf_deep_copy_obj( mupdf.pdf_resolve_indirect( o))\n                    xref = mupdf.pdf_create_object( pdf)\n                    mupdf.pdf_update_object( pdf, xref, copy_o)\n                    copy_o = mupdf.pdf_new_indirect( pdf, xref, 0)\n                    mupdf.pdf_dict_del( copy_o, PDF_NAME('Popup'))\n                    mupdf.pdf_dict_del( copy_o, PDF_NAME('P'))\n                    mupdf.pdf_array_push( new_annots, copy_o)\n                mupdf.pdf_dict_put( page2, PDF_NAME('Annots'), new_annots)\n\n            # copy the old contents stream(s)\n            res = JM_read_contents( page1)\n\n            # create new /Contents object for page2\n            if res and res.m_internal:\n                #contents = mupdf.pdf_add_stream( pdf, mupdf.fz_new_buffer_from_copied_data( b\"  \", 1), NULL, 0)\n                contents = mupdf.pdf_add_stream( pdf, mupdf.fz_new_buffer_from_copied_data( b\" \"), mupdf.PdfObj(), 0)\n                JM_update_stream( pdf, contents, res, 1)\n                mupdf.pdf_dict_put( page2, PDF_NAME('Contents'), contents)\n\n            # now insert target page, making sure it is an indirect object\n            xref = mupdf.pdf_create_object( pdf)   # get new xref\n            mupdf.pdf_update_object( pdf, xref, page2) # store new page\n\n            page2 = mupdf.pdf_new_indirect( pdf, xref, 0)  # reread object\n            mupdf.pdf_insert_page( pdf, to, page2) # and store the page\n        finally:\n            mupdf.ll_pdf_drop_page_tree( pdf.m_internal)\n\n        self._reset_page_refs()\n\n    def get_char_widths(\n            doc: 'Document',\n            xref: int,\n            limit: int = 256,\n            idx: int = 0,\n            fontdict: OptDict = None,\n            ) -> list:\n        \"\"\"Get list of glyph information of a font.\n\n        Notes:\n            Must be provided by its XREF number. If we already dealt with the\n            font, it will be recorded in doc.FontInfos. Otherwise we insert an\n            entry there.\n            Finally we return the glyphs for the font. This is a list of\n            (glyph, width) where glyph is an integer controlling the char\n            appearance, and width is a float controlling the char's spacing:\n            width * fontsize is the actual space.\n            For 'simple' fonts, glyph == ord(char) will usually be true.\n            Exceptions are 'Symbol' and 'ZapfDingbats'. We are providing data for these directly here.\n        \"\"\"\n        fontinfo = CheckFontInfo(doc, xref)\n        if fontinfo is None:  # not recorded yet: create it\n            if fontdict is None:\n                name, ext, stype, asc, dsc = utils._get_font_properties(doc, xref)\n                fontdict = {\n                    \"name\": name,\n                    \"type\": stype,\n                    \"ext\": ext,\n                    \"ascender\": asc,\n                    \"descender\": dsc,\n                }\n            else:\n                name = fontdict[\"name\"]\n                ext = fontdict[\"ext\"]\n                stype = fontdict[\"type\"]\n                ordering = fontdict[\"ordering\"]\n                simple = fontdict[\"simple\"]\n\n            if ext == \"\":\n                raise ValueError(\"xref is not a font\")\n\n            # check for 'simple' fonts\n            if stype in (\"Type1\", \"MMType1\", \"TrueType\"):\n                simple = True\n            else:\n                simple = False\n\n            # check for CJK fonts\n            if name in (\"Fangti\", \"Ming\"):\n                ordering = 0\n            elif name in (\"Heiti\", \"Song\"):\n                ordering = 1\n            elif name in (\"Gothic\", \"Mincho\"):\n                ordering = 2\n            elif name in (\"Dotum\", \"Batang\"):\n                ordering = 3\n            else:\n                ordering = -1\n\n            fontdict[\"simple\"] = simple\n\n            if name == \"ZapfDingbats\":\n                glyphs = zapf_glyphs\n            elif name == \"Symbol\":\n                glyphs = symbol_glyphs\n            else:\n                glyphs = None\n\n            fontdict[\"glyphs\"] = glyphs\n            fontdict[\"ordering\"] = ordering\n            fontinfo = [xref, fontdict]\n            doc.FontInfos.append(fontinfo)\n        else:\n            fontdict = fontinfo[1]\n            glyphs = fontdict[\"glyphs\"]\n            simple = fontdict[\"simple\"]\n            ordering = fontdict[\"ordering\"]\n\n        if glyphs is None:\n            oldlimit = 0\n        else:\n            oldlimit = len(glyphs)\n\n        mylimit = max(256, limit)\n\n        if mylimit <= oldlimit:\n            return glyphs\n\n        if ordering < 0:  # not a CJK font\n            glyphs = doc._get_char_widths(\n                xref, fontdict[\"name\"], fontdict[\"ext\"], fontdict[\"ordering\"], mylimit, idx\n            )\n        else:  # CJK fonts use char codes and width = 1\n            glyphs = None\n\n        fontdict[\"glyphs\"] = glyphs\n        fontinfo[1] = fontdict\n        UpdateFontInfo(doc, fontinfo)\n\n        return glyphs\n\n    def get_layer(self, config=-1):\n        \"\"\"Content of ON, OFF, RBGroups of an OC layer.\"\"\"\n        pdf = _as_pdf_document(self)\n        ocp = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer( pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('OCProperties'),\n                )\n        if not ocp.m_internal:\n            return\n        if config == -1:\n            obj = mupdf.pdf_dict_get( ocp, PDF_NAME('D'))\n        else:\n            obj = mupdf.pdf_array_get(\n                    mupdf.pdf_dict_get( ocp, PDF_NAME('Configs')),\n                    config,\n                    )\n        if not obj.m_internal:\n            raise ValueError( MSG_BAD_OC_CONFIG)\n        rc = JM_get_ocg_arrays( obj)\n        return rc\n\n    def get_layers(self):\n        \"\"\"Show optional OC layers.\"\"\"\n        pdf = _as_pdf_document(self)\n        n = mupdf.pdf_count_layer_configs( pdf)\n        if n == 1:\n            obj = mupdf.pdf_dict_getl(\n                    mupdf.pdf_trailer( pdf),\n                    PDF_NAME('Root'),\n                    PDF_NAME('OCProperties'),\n                    PDF_NAME('Configs'),\n                    )\n            if not mupdf.pdf_is_array( obj):\n                n = 0\n        rc = []\n        info = mupdf.PdfLayerConfig()\n        for i in range(n):\n            mupdf.pdf_layer_config_info( pdf, i, info)\n            item = {\n                    \"number\": i,\n                    \"name\": info.name,\n                    \"creator\": info.creator,\n                    }\n            rc.append( item)\n        return rc\n\n    def get_new_xref(self):\n        \"\"\"Make new xref.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        xref = 0\n        ENSURE_OPERATION(pdf)\n        xref = mupdf.pdf_create_object(pdf)\n        return xref\n\n    def get_oc(doc: 'Document', xref: int) -> int:\n        \"\"\"Return optional content object xref for an image or form xobject.\n\n        Args:\n            xref: (int) xref number of an image or form xobject.\n        \"\"\"\n        if doc.is_closed or doc.is_encrypted:\n            raise ValueError(\"document close or encrypted\")\n        t, name = doc.xref_get_key(xref, \"Subtype\")\n        if t != \"name\" or name not in (\"/Image\", \"/Form\"):\n            raise ValueError(f\"bad object type at xref {xref}\")\n        t, oc = doc.xref_get_key(xref, \"OC\")\n        if t != \"xref\":\n            return 0\n        rc = int(oc.replace(\"0 R\", \"\"))\n        return rc\n    \n    def get_ocgs(self):\n        \"\"\"Show existing optional content groups.\"\"\"\n        ci = mupdf.pdf_new_name( \"CreatorInfo\")\n        pdf = _as_pdf_document(self)\n        ocgs = mupdf.pdf_dict_getl(\n                mupdf.pdf_dict_get( mupdf.pdf_trailer( pdf), PDF_NAME('Root')),\n                PDF_NAME('OCProperties'),\n                PDF_NAME('OCGs'),\n                )\n        rc = dict()\n        if not mupdf.pdf_is_array( ocgs):\n            return rc\n        n = mupdf.pdf_array_len( ocgs)\n        for i in range(n):\n            ocg = mupdf.pdf_array_get( ocgs, i)\n            xref = mupdf.pdf_to_num( ocg)\n            name = mupdf.pdf_to_text_string( mupdf.pdf_dict_get( ocg, PDF_NAME('Name')))\n            obj = mupdf.pdf_dict_getl( ocg, PDF_NAME('Usage'), ci, PDF_NAME('Subtype'))\n            usage = None\n            if obj.m_internal:\n                usage = mupdf.pdf_to_name( obj)\n            intents = list()\n            intent = mupdf.pdf_dict_get( ocg, PDF_NAME('Intent'))\n            if intent.m_internal:\n                if mupdf.pdf_is_name( intent):\n                    intents.append( mupdf.pdf_to_name( intent))\n                elif mupdf.pdf_is_array( intent):\n                    m = mupdf.pdf_array_len( intent)\n                    for j in range(m):\n                        o = mupdf.pdf_array_get( intent, j)\n                        if mupdf.pdf_is_name( o):\n                            intents.append( mupdf.pdf_to_name( o))\n            if mupdf_version_tuple >= (1, 26, 11):\n                resource_stack = mupdf.PdfResourceStack()\n                hidden = mupdf.pdf_is_ocg_hidden( pdf, resource_stack, usage, ocg)\n            else:\n                hidden = mupdf.pdf_is_ocg_hidden( pdf, mupdf.PdfObj(), usage, ocg)\n            item = {\n                    \"name\": name,\n                    \"intent\": intents,\n                    \"on\": not hidden,\n                    \"usage\": usage,\n                    }\n            temp = xref\n            rc[ temp] = item\n        return rc\n\n    def get_ocmd(doc: 'Document', xref: int) -> dict:\n        \"\"\"Return the definition of an OCMD (optional content membership dictionary).\n\n        Recognizes PDF dict keys /OCGs (PDF array of OCGs), /P (policy string) and\n        /VE (visibility expression, PDF array). Via string manipulation, this\n        info is converted to a Python dictionary with keys \"xref\", \"ocgs\", \"policy\"\n        and \"ve\" - ready to recycle as input for 'set_ocmd()'.\n        \"\"\"\n\n        if xref not in range(doc.xref_length()):\n            raise ValueError(\"bad xref\")\n        text = doc.xref_object(xref, compressed=True)\n        if \"/Type/OCMD\" not in text:\n            raise ValueError(\"bad object type\")\n        textlen = len(text)\n\n        p0 = text.find(\"/OCGs[\")  # look for /OCGs key\n        p1 = text.find(\"]\", p0)\n        if p0 < 0 or p1 < 0:  # no OCGs found\n            ocgs = None\n        else:\n            ocgs = text[p0 + 6 : p1].replace(\"0 R\", \" \").split()\n            ocgs = list(map(int, ocgs))\n\n        p0 = text.find(\"/P/\")  # look for /P policy key\n        if p0 < 0:\n            policy = None\n        else:\n            p1 = text.find(\"ff\", p0)\n            if p1 < 0:\n                p1 = text.find(\"on\", p0)\n            if p1 < 0:  # some irregular syntax\n                raise ValueError(\"bad object at xref\")\n            else:\n                policy = text[p0 + 3 : p1 + 2]\n\n        p0 = text.find(\"/VE[\")  # look for /VE visibility expression key\n        if p0 < 0:  # no visibility expression found\n            ve = None\n        else:\n            lp = rp = 0  # find end of /VE by finding last ']'.\n            p1 = p0\n            while lp < 1 or lp != rp:\n                p1 += 1\n                if not p1 < textlen:  # some irregular syntax\n                    raise ValueError(\"bad object at xref\")\n                if text[p1] == \"[\":\n                    lp += 1\n                if text[p1] == \"]\":\n                    rp += 1\n            # p1 now positioned at the last \"]\"\n            ve = text[p0 + 3 : p1 + 1]  # the PDF /VE array\n            ve = (\n                ve.replace(\"/And\", '\"and\",')\n                .replace(\"/Not\", '\"not\",')\n                .replace(\"/Or\", '\"or\",')\n            )\n            ve = ve.replace(\" 0 R]\", \"]\").replace(\" 0 R\", \",\").replace(\"][\", \"],[\")\n            import json\n            try:\n                ve = json.loads(ve)\n            except Exception:\n                exception_info()\n                message(f\"bad /VE key: {ve!r}\")\n                raise\n        return {\"xref\": xref, \"ocgs\": ocgs, \"policy\": policy, \"ve\": ve}\n\n    def get_outline_xrefs(self):\n        \"\"\"Get list of outline xref numbers.\"\"\"\n        xrefs = []\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return xrefs\n        root = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root'))\n        if not root.m_internal:\n            return xrefs\n        olroot = mupdf.pdf_dict_get(root, PDF_NAME('Outlines'))\n        if not olroot.m_internal:\n            return xrefs\n        first = mupdf.pdf_dict_get(olroot, PDF_NAME('First'))\n        if not first.m_internal:\n            return xrefs\n        xrefs = JM_outline_xrefs(first, xrefs)\n        return xrefs\n\n    def get_page_fonts(self, pno: int, full: bool =False) -> list:\n        \"\"\"Retrieve a list of fonts used on a page.\n        \"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if not self.is_pdf:\n            return ()\n        if type(pno) is not int:\n            try:\n                pno = pno.number\n            except Exception:\n                exception_info()\n                raise ValueError(\"need a Page or page number\")\n        val = self._getPageInfo(pno, 1)\n        if not full:\n            return [v[:-1] for v in val]\n        return val\n\n    def get_page_images(self, pno: int, full: bool =False) -> list:\n        \"\"\"Retrieve a list of images used on a page.\n        \"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if not self.is_pdf:\n            return ()\n        val = self._getPageInfo(pno, 2)\n        if not full:\n            return [v[:-1] for v in val]\n        return val\n\n    def get_page_labels(self):\n        \"\"\"Return page label definitions in PDF document.\n\n        Returns:\n            A list of dictionaries with the following format:\n            {'startpage': int, 'prefix': str, 'style': str, 'firstpagenum': int}.\n        \"\"\"\n        # Jorj McKie, 2021-01-10\n        return [utils.rule_dict(item) for item in self._get_page_labels()]\n\n    def get_page_numbers(doc, label, only_one=False):\n        \"\"\"Return a list of page numbers with the given label.\n\n        Args:\n            doc: PDF document object (resp. 'self').\n            label: (str) label.\n            only_one: (bool) stop searching after first hit.\n        Returns:\n            List of page numbers having this label.\n        \"\"\"\n        # Jorj McKie, 2021-01-06\n\n        numbers = []\n        if not label:\n            return numbers\n        labels = doc._get_page_labels()\n        if labels == []:\n            return numbers\n        for i in range(doc.page_count):\n            plabel = utils.get_label_pno(i, labels)\n            if plabel == label:\n                numbers.append(i)\n                if only_one:\n                    break\n        return numbers\n    \n    def get_page_pixmap(\n            doc: 'Document',\n            pno: int,\n            *,\n            matrix: matrix_like = None,\n            dpi=None,\n            colorspace: Colorspace = None,\n            clip: rect_like = None,\n            alpha: bool = False,\n            annots: bool = True,\n            ) -> 'Pixmap':\n        \"\"\"Create pixmap of document page by page number.\n\n        Notes:\n            Convenience function calling page.get_pixmap.\n        Args:\n            pno: (int) page number\n            matrix: pymupdf.Matrix for transformation (default: pymupdf.Identity).\n            colorspace: (str,pymupdf.Colorspace) rgb, rgb, gray - case ignored, default csRGB.\n            clip: (irect-like) restrict rendering to this area.\n            alpha: (bool) include alpha channel\n            annots: (bool) also render annotations\n        \"\"\"\n        if matrix is None:\n            matrix = Identity\n        if colorspace is None:\n            colorspace = csRGB\n        return doc[pno].get_pixmap(\n                matrix=matrix,\n                dpi=dpi, colorspace=colorspace,\n                clip=clip,\n                alpha=alpha,\n                annots=annots\n                )\n    \n    def get_page_text(\n            doc: 'Document',\n            pno: int,\n            option: str = \"text\",\n            clip: rect_like = None,\n            flags: OptInt = None,\n            textpage: 'TextPage' = None,\n            sort: bool = False,\n            ) -> typing.Any:\n        \"\"\"Extract a document page's text by page number.\n\n        Notes:\n            Convenience function calling page.get_text().\n        Args:\n            pno: page number\n            option: (str) text, words, blocks, html, dict, json, rawdict, xhtml or xml.\n        Returns:\n            output from page.TextPage().\n        \"\"\"\n        return doc[pno].get_text(option, clip=clip, flags=flags, sort=sort)\n    \n    def get_page_xobjects(self, pno: int) -> list:\n        \"\"\"Retrieve a list of XObjects used on a page.\n        \"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if not self.is_pdf:\n            return ()\n        val = self._getPageInfo(pno, 3)\n        return val\n\n    def get_sigflags(self):\n        \"\"\"Get the /SigFlags value.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return -1   # not a PDF\n        sigflags = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer(pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('AcroForm'),\n                PDF_NAME('SigFlags'),\n                )\n        sigflag = -1\n        if sigflags.m_internal:\n            sigflag = mupdf.pdf_to_int(sigflags)\n        return sigflag\n\n    def get_toc(\n            doc: 'Document',\n            simple: bool = True,\n            ) -> list:\n        \"\"\"Create a table of contents.\n\n        Args:\n            simple: a bool to control output. Returns a list, where each entry consists of outline level, title, page number and link destination (if simple = False). For details see PyMuPDF's documentation.\n        \"\"\"\n        def recurse(olItem, liste, lvl):\n            \"\"\"Recursively follow the outline item chain and record item information in a list.\"\"\"\n            while olItem and olItem.this.m_internal:\n                if olItem.title:\n                    title = olItem.title\n                else:\n                    title = \" \"\n\n                if not olItem.is_external:\n                    if olItem.uri:\n                        if olItem.page == -1:\n                            resolve = doc.resolve_link(olItem.uri)\n                            page = resolve[0] + 1\n                        else:\n                            page = olItem.page + 1\n                    else:\n                        page = -1\n                else:\n                    page = -1\n\n                if not simple:\n                    link = utils.getLinkDict(olItem, doc)\n                    liste.append([lvl, title, page, link])\n                else:\n                    liste.append([lvl, title, page])\n\n                if olItem.down:\n                    liste = recurse(olItem.down, liste, lvl + 1)\n                olItem = olItem.next\n            return liste\n\n        # ensure document is open\n        if doc.is_closed:\n            raise ValueError(\"document closed\")\n        doc.init_doc()\n        olItem = doc.outline\n        if not olItem:\n            return []\n        lvl = 1\n        liste = []\n        toc = recurse(olItem, liste, lvl)\n        if doc.is_pdf and not simple:\n            doc._extend_toc_items(toc)\n        return toc\n    \n    def get_xml_metadata(self):\n        \"\"\"Get document XML metadata.\"\"\"\n        xml = None\n        pdf = _as_pdf_document(self, required=0)\n        if pdf.m_internal:\n            xml = mupdf.pdf_dict_getl(\n                    mupdf.pdf_trailer(pdf),\n                    PDF_NAME('Root'),\n                    PDF_NAME('Metadata'),\n                    )\n        if xml is not None and xml.m_internal:\n            buff = mupdf.pdf_load_stream(xml)\n            rc = JM_UnicodeFromBuffer(buff)\n        else:\n            rc = ''\n        return rc\n\n    def has_annots(doc: 'Document') -> bool:\n        \"\"\"Check whether there are annotations on any page.\"\"\"\n        if doc.is_closed:\n            raise ValueError(\"document closed\")\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        for i in range(doc.page_count):\n            for item in doc.page_annot_xrefs(i):\n                # pylint: disable=no-member\n                if not (item[1] == mupdf.PDF_ANNOT_LINK or item[1] == mupdf.PDF_ANNOT_WIDGET):  # pylint: disable=no-member\n                    return True\n        return False\n    \n    def has_links(doc: 'Document') -> bool:\n        \"\"\"Check whether there are links on any page.\"\"\"\n        if doc.is_closed:\n            raise ValueError(\"document closed\")\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        for i in range(doc.page_count):\n            for item in doc.page_annot_xrefs(i):\n                if item[1] == mupdf.PDF_ANNOT_LINK:  # pylint: disable=no-member\n                    return True\n        return False\n    \n    def init_doc(self):\n        if self.is_encrypted:\n            raise ValueError(\"cannot initialize - document still encrypted\")\n        self._outline = self._loadOutline()\n        self.metadata = dict(\n                    [\n                        (k,self._getMetadata(v)) for k,v in {\n                            'format':'format',\n                            'title':'info:Title',\n                            'author':'info:Author',\n                            'subject':'info:Subject',\n                            'keywords':'info:Keywords',\n                            'creator':'info:Creator',\n                            'producer':'info:Producer',\n                            'creationDate':'info:CreationDate',\n                            'modDate':'info:ModDate',\n                            'trapped':'info:Trapped'\n                            }.items()\n                    ]\n                )\n        self.metadata['encryption'] = None if self._getMetadata('encryption')=='None' else self._getMetadata('encryption')\n\n    def insert_file(self,\n            infile,\n            from_page=-1,\n            to_page=-1,\n            start_at=-1,\n            rotate=-1,\n            links=True,\n            annots=True,\n            show_progress=0,\n            final=1,\n            ):\n        '''\n        Insert an arbitrary supported document to an existing PDF.\n\n        The infile may be given as a filename, a Document or a Pixmap. Other\n        parameters - where applicable - equal those of insert_pdf().\n        '''\n        src = None\n        if isinstance(infile, Pixmap):\n            if infile.colorspace.n > 3:\n                infile = Pixmap(csRGB, infile)\n            src = Document(\"png\", infile.tobytes())\n        elif isinstance(infile, Document):\n            src = infile\n        else:\n            src = Document(infile)\n        if not src:\n            raise ValueError(\"bad infile parameter\")\n        if not src.is_pdf:\n            pdfbytes = src.convert_to_pdf()\n            src = Document(\"pdf\", pdfbytes)\n        return self.insert_pdf(\n                src,\n                from_page=from_page,\n                to_page=to_page,\n                start_at=start_at,\n                rotate=rotate,\n                links=links,\n                annots=annots,\n                show_progress=show_progress,\n                final=final,\n                )\n\n    def insert_page(\n            doc: 'Document',\n            pno: int,\n            text: typing.Union[str, list, None] = None,\n            fontsize: float = 11,\n            width: float = 595,\n            height: float = 842,\n            fontname: str = \"helv\",\n            fontfile: OptStr = None,\n            color: OptSeq = (0,),\n            ) -> int:\n        \"\"\"Create a new PDF page and insert some text.\n\n        Notes:\n            Function combining pymupdf.Document.new_page() and pymupdf.Page.insert_text().\n            For parameter details see these methods.\n        \"\"\"\n        page = doc.new_page(pno=pno, width=width, height=height)\n        if not bool(text):\n            return 0\n        rc = page.insert_text(\n            (50, 72),\n            text,\n            fontsize=fontsize,\n            fontname=fontname,\n            fontfile=fontfile,\n            color=color,\n        )\n        return rc\n    \n    def insert_pdf(\n            self,\n            docsrc,\n            *,\n            from_page=-1,\n            to_page=-1,\n            start_at=-1,\n            rotate=-1,\n            links=1,\n            annots=1,\n            widgets=1,\n            join_duplicates=0,\n            show_progress=0,\n            final=1,\n            _gmap=None,\n            ):\n        \"\"\"Insert a page range from another PDF.\n\n        Args:\n            docsrc: PDF to copy from. Must be different object, but may be same file.\n            from_page: (int) first source page to copy, 0-based, default 0.\n            to_page: (int) last source page to copy, 0-based, default last page.\n            start_at: (int) from_page will become this page number in target.\n            rotate: (int) rotate copied pages, default -1 is no change.\n            links: (int/bool) whether to also copy links.\n            annots: (int/bool) whether to also copy annotations.\n            widgets: (int/bool) whether to also copy form fields.\n            join_duplicates: (int/bool) join or rename duplicate widget names.\n            show_progress: (int) progress message interval, 0 is no messages.\n            final: (bool) indicates last insertion from this source PDF.\n            _gmap: internal use only\n\n        Copy sequence reversed if from_page > to_page.\"\"\"\n\n        # Insert pages from a source PDF into this PDF.\n        # For reconstructing the links (_do_links method), we must save the\n        # insertion point (start_at) if it was specified as -1.\n        #log( 'insert_pdf(): start')\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if self._graft_id == docsrc._graft_id:\n            raise ValueError(\"source and target cannot be same object\")\n        sa = start_at\n        if sa < 0:\n            sa = self.page_count\n        outCount = self.page_count\n        srcCount = docsrc.page_count\n\n        # local copies of page numbers\n        fp = from_page\n        tp = to_page\n        sa = start_at\n\n        # normalize page numbers\n        fp = max(fp, 0) # -1 = first page\n        fp = min(fp, srcCount - 1)  # but do not exceed last page\n\n        if tp < 0:\n            tp = srcCount - 1   # -1 = last page\n        tp = min(tp, srcCount - 1)  # but do not exceed last page\n\n        if sa < 0:\n            sa = outCount   # -1 = behind last page\n        sa = min(sa, outCount)  # but that is also the limit\n\n        if len(docsrc) > show_progress > 0:\n            inname = os.path.basename(docsrc.name)\n            if not inname:\n                inname = \"memory PDF\"\n            outname = os.path.basename(self.name)\n            if not outname:\n                outname = \"memory PDF\"\n            message(f\"Inserting '{inname}' at '{outname}'\")\n\n        # retrieve / make a Graftmap to avoid duplicate objects\n        #log( 'insert_pdf(): Graftmaps')\n        isrt = docsrc._graft_id\n        _gmap = self.Graftmaps.get(isrt, None)\n        if _gmap is None:\n            #log( 'insert_pdf(): Graftmaps2')\n            _gmap = Graftmap(self)\n            self.Graftmaps[isrt] = _gmap\n\n        if g_use_extra:\n            #log( 'insert_pdf(): calling extra_FzDocument_insert_pdf()')\n            extra_FzDocument_insert_pdf(\n                    self.this,\n                    docsrc.this,\n                    from_page,\n                    to_page,\n                    start_at,\n                    rotate,\n                    links,\n                    annots,\n                    show_progress,\n                    final,\n                    _gmap,\n                    )\n            #log( 'insert_pdf(): extra_FzDocument_insert_pdf() returned.')\n        else:\n            pdfout = _as_pdf_document(self)\n            pdfsrc = _as_pdf_document(docsrc)\n\n            if not pdfout.m_internal or not pdfsrc.m_internal:\n                raise TypeError( \"source or target not a PDF\")\n            ENSURE_OPERATION(pdfout)\n            JM_merge_range(pdfout, pdfsrc, fp, tp, sa, rotate, links, annots, show_progress, _gmap)\n        \n        #log( 'insert_pdf(): calling self._reset_page_refs()')\n        self._reset_page_refs()\n        if links:\n            #log( 'insert_pdf(): calling self._do_links()')\n            self._do_links(docsrc, from_page=fp, to_page=tp, start_at=sa)\n        if widgets:\n            self._do_widgets(docsrc, _gmap, from_page=fp, to_page=tp, start_at=sa, join_duplicates=join_duplicates)\n        if final == 1:\n            self.Graftmaps[isrt] = None\n        #log( 'insert_pdf(): returning')\n\n    @property\n    def is_dirty(self):\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return False\n        r = mupdf.pdf_has_unsaved_changes(pdf)\n        return True if r else False\n\n    @property\n    def is_fast_webaccess(self):\n        '''\n        Check whether we have a linearized PDF.\n        '''\n        pdf = _as_pdf_document(self, required=0)\n        if pdf.m_internal:\n            return mupdf.pdf_doc_was_linearized(pdf)\n        return False    # gracefully handle non-PDF\n\n    @property\n    def is_form_pdf(self):\n        \"\"\"Either False or PDF field count.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return False\n        count = -1\n        try:\n            fields = mupdf.pdf_dict_getl(\n                    mupdf.pdf_trailer(pdf),\n                    mupdf.PDF_ENUM_NAME_Root,\n                    mupdf.PDF_ENUM_NAME_AcroForm,\n                    mupdf.PDF_ENUM_NAME_Fields,\n                    )\n            if mupdf.pdf_is_array(fields):\n                count = mupdf.pdf_array_len(fields)\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            return False\n        if count >= 0:\n            return count\n        return False\n\n    @property\n    def is_pdf(self):\n        \"\"\"Check for PDF.\"\"\"\n        if isinstance(self.this, mupdf.PdfDocument):\n            return True\n        # Avoid calling smupdf.pdf_specifics because it will end up creating\n        # a new PdfDocument which will call pdf_create_document(), which is ok\n        # but a little unnecessary.\n        #\n        if mupdf.ll_pdf_specifics(self.this.m_internal):\n            ret = True\n        else:\n            ret = False\n        return ret\n\n    @property\n    def is_reflowable(self):\n        \"\"\"Check if document is layoutable.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        return bool(mupdf.fz_is_document_reflowable(self))\n\n    @property\n    def is_repaired(self):\n        \"\"\"Check whether PDF was repaired.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return False\n        r = mupdf.pdf_was_repaired(pdf)\n        if r:\n            return True\n        return False\n\n    def journal_can_do(self):\n        \"\"\"Show if undo and / or redo are possible.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        undo=0\n        redo=0\n        pdf = _as_pdf_document(self)\n        undo = mupdf.pdf_can_undo(pdf)\n        redo = mupdf.pdf_can_redo(pdf)\n        return {'undo': bool(undo), 'redo': bool(redo)}\n\n    def journal_enable(self):\n        \"\"\"Activate document journalling.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_enable_journal(pdf)\n\n    def journal_is_enabled(self):\n        \"\"\"Check if journalling is enabled.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        enabled = pdf.m_internal and pdf.m_internal.journal\n        return enabled\n\n    def journal_load(self, filename):\n        \"\"\"Load a journal from a file.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        if isinstance(filename, str):\n            mupdf.pdf_load_journal(pdf, filename)\n        else:\n            res = JM_BufferFromBytes(filename)\n            stm = mupdf.fz_open_buffer(res)\n            mupdf.pdf_deserialise_journal(pdf, stm)\n        if not pdf.m_internal.journal:\n            RAISEPY( \"Journal and document do not match\", JM_Exc_FileDataError)\n\n    def journal_op_name(self, step):\n        \"\"\"Show operation name for given step.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        name = mupdf.pdf_undoredo_step(pdf, step)\n        return name\n\n    def journal_position(self):\n        \"\"\"Show journalling state.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        steps=0\n        pdf = _as_pdf_document(self)\n        rc, steps = mupdf.pdf_undoredo_state(pdf)\n        return rc, steps\n\n    def journal_redo(self):\n        \"\"\"Move forward in the journal.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_redo(pdf)\n        return True\n\n    def journal_save(self, filename):\n        \"\"\"Save journal to a file.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        if isinstance(filename, str):\n            mupdf.pdf_save_journal(pdf, filename)\n        else:\n            out = JM_new_output_fileptr(filename)\n            mupdf.pdf_write_journal(pdf, out)\n            out.fz_close_output()\n\n    def journal_start_op(self, name=None):\n        \"\"\"Begin a journalling operation.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        if not pdf.m_internal.journal:\n            raise RuntimeError( \"Journalling not enabled\")\n        if name:\n            mupdf.pdf_begin_operation(pdf, name)\n        else:\n            mupdf.pdf_begin_implicit_operation(pdf)\n\n    def journal_stop_op(self):\n        \"\"\"End a journalling operation.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_end_operation(pdf)\n\n    def journal_undo(self):\n        \"\"\"Move backwards in the journal.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_undo(pdf)\n        return True\n\n    @property\n    def language(self):\n        \"\"\"Document language.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return\n        lang = mupdf.pdf_document_language(pdf)\n        if lang == mupdf.FZ_LANG_UNSET:\n            return\n        return mupdf.fz_string_from_text_language2(lang)\n\n    @property\n    def last_location(self):\n        \"\"\"Id (chapter, page) of last page.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        last_loc = mupdf.fz_last_page(self.this)\n        return last_loc.chapter, last_loc.page\n\n    def layer_ui_configs(self):\n        \"\"\"Show OC visibility status modifiable by user.\"\"\"\n        pdf = _as_pdf_document(self)\n        info = mupdf.PdfLayerConfigUi()\n        n = mupdf.pdf_count_layer_config_ui( pdf)\n        rc = []\n        for i in range(n):\n            mupdf.pdf_layer_config_ui_info( pdf, i, info)\n            if info.type == 1:\n                type_ = \"checkbox\"\n            elif info.type == 2:\n                type_ = \"radiobox\"\n            else:\n                type_ = \"label\"\n            item = {\n                    \"number\": i,\n                    \"text\": info.text,\n                    \"depth\": info.depth,\n                    \"type\": type_,\n                    \"on\": info.selected,\n                    \"locked\": info.locked,\n                    }\n            rc.append(item)\n        return rc\n\n    def layout(self, rect=None, width=0, height=0, fontsize=11):\n        \"\"\"Re-layout a reflowable document.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        doc = self.this\n        if not mupdf.fz_is_document_reflowable( doc):\n            return\n        w = width\n        h = height\n        r = JM_rect_from_py(rect)\n        if not mupdf.fz_is_infinite_rect(r):\n            w = r.x1 - r.x0\n            h = r.y1 - r.y0\n        if w <= 0.0 or h <= 0.0:\n            raise ValueError( \"bad page size\")\n        mupdf.fz_layout_document( doc, w, h, fontsize)\n\n        self._reset_page_refs()\n        self.init_doc()\n\n    def load_page(self, page_id):\n        \"\"\"Load a page.\n\n        'page_id' is either a 0-based page number or a tuple (chapter, pno),\n        with chapter number and page number within that chapter.\n        \"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if page_id is None:\n            page_id = 0\n        if page_id not in self:\n            raise ValueError(\"page not in document\")\n        if type(page_id) is int and page_id < 0:\n            np = self.page_count\n            while page_id < 0:\n                page_id += np\n        if isinstance(page_id, int):\n            page = mupdf.fz_load_page(self.this, page_id)\n        else:\n            chapter, pagenum = page_id\n            page = mupdf.fz_load_chapter_page(self.this, chapter, pagenum)\n        val = Page(page, self)\n\n        val.thisown = True\n        val.parent = self\n        self._page_refs[id(val)] = val\n        val._annot_refs = weakref.WeakValueDictionary()\n        val.number = page_id\n        return val\n\n    def location_from_page_number(self, pno):\n        \"\"\"Convert pno to (chapter, page).\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        this_doc = self.this\n        loc = mupdf.fz_make_location(-1, -1)\n        page_count = mupdf.fz_count_pages(this_doc)\n        while pno < 0:\n            pno += page_count\n        if pno >= page_count:\n            raise ValueError( MSG_BAD_PAGENO)\n        loc = mupdf.fz_location_from_page_number(this_doc, pno)\n        return loc.chapter, loc.page\n\n    def make_bookmark(self, loc):\n        \"\"\"Make a page pointer before layouting document.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        loc = mupdf.FzLocation(*loc)\n        mark = mupdf.ll_fz_make_bookmark2( self.this.m_internal, loc.internal())\n        return mark\n\n    @property\n    def markinfo(self) -> dict:\n        \"\"\"Return the PDF MarkInfo value.\"\"\"\n        xref = self.pdf_catalog()\n        if xref == 0:\n            return None\n        rc = self.xref_get_key(xref, \"MarkInfo\")\n        if rc[0] == \"null\":\n            return {}\n        if rc[0] == \"xref\":\n            xref = int(rc[1].split()[0])\n            val = self.xref_object(xref, compressed=True)\n        elif rc[0] == \"dict\":\n            val = rc[1]\n        else:\n            val = None\n        if val is None or not (val[:2] == \"<<\" and val[-2:] == \">>\"):\n            return {}\n        valid = {\"Marked\": False, \"UserProperties\": False, \"Suspects\": False}\n        val = val[2:-2].split(\"/\")\n        for v in val[1:]:\n            try:\n                key, value = v.split()\n            except Exception:\n                if g_exceptions_verbose > 1:    exception_info()\n                return valid\n            if value == \"true\":\n                valid[key] = True\n        return valid\n\n    def move_page(self, pno: int, to: int =-1):\n        \"\"\"Move a page within a PDF document.\n\n        Args:\n            pno: source page number.\n            to: put before this page, '-1' means after last page.\n        \"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        page_count = len(self)\n        if (pno not in range(page_count) or to not in range(-1, page_count)):\n            raise ValueError(\"bad page number(s)\")\n        before = 1\n        copy = 0\n        if to == -1:\n            to = page_count - 1\n            before = 0\n\n        return self._move_copy_page(pno, to, before, copy)\n\n    @property\n    def name(self):\n        return self._name\n    \n    def need_appearances(self, value=None):\n        \"\"\"Get/set the NeedAppearances value.\"\"\"\n        if not self.is_form_pdf:\n            return None\n        \n        pdf = _as_pdf_document(self)\n        oldval = -1\n        appkey = \"NeedAppearances\"\n        \n        form = mupdf.pdf_dict_getp(\n                mupdf.pdf_trailer(pdf),\n                \"Root/AcroForm\",\n                )\n        app = mupdf.pdf_dict_gets(form, appkey)\n        if mupdf.pdf_is_bool(app):\n            oldval = mupdf.pdf_to_bool(app)\n        if value:\n            mupdf.pdf_dict_puts(form, appkey, mupdf.PDF_TRUE)\n        else:\n            mupdf.pdf_dict_puts(form, appkey, mupdf.PDF_FALSE)\n        if value is None:\n            return oldval >= 0\n        return value\n\n    @property\n    def needs_pass(self):\n        \"\"\"Indicate password required.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        document = self.this if isinstance(self.this, mupdf.FzDocument) else self.this.super()\n        ret = mupdf.fz_needs_password( document)\n        return ret\n\n    def new_page(\n            doc: 'Document',\n            pno: int = -1,\n            width: float = 595,\n            height: float = 842,\n            ) -> Page:\n        \"\"\"Create and return a new page object.\n\n        Args:\n            pno: (int) insert before this page. Default: after last page.\n            width: (float) page width in points. Default: 595 (ISO A4 width).\n            height: (float) page height in points. Default 842 (ISO A4 height).\n        Returns:\n            A pymupdf.Page object.\n        \"\"\"\n        doc._newPage(pno, width=width, height=height)\n        return doc[pno]\n    \n    def next_location(self, page_id):\n        \"\"\"Get (chapter, page) of next page.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if type(page_id) is int:\n            page_id = (0, page_id)\n        if page_id not in self:\n            raise ValueError(\"page id not in document\")\n        if tuple(page_id) == self.last_location:\n            return ()\n        this_doc = _as_fz_document(self)\n        val = page_id[ 0]\n        if not isinstance(val, int):\n            RAISEPY(MSG_BAD_PAGEID, PyExc_ValueError)\n        chapter = val\n        val = page_id[ 1]\n        pno = val\n        loc = mupdf.fz_make_location(chapter, pno)\n        next_loc = mupdf.fz_next_page( this_doc, loc)\n        return next_loc.chapter, next_loc.page\n\n    def page_annot_xrefs(self, n):\n        if g_use_extra:\n            return extra.page_annot_xrefs( self.this, n)\n        \n        if isinstance(self.this, mupdf.PdfDocument):\n            page_count = mupdf.pdf_count_pages(self.this)\n            pdf_document = self.this\n        else:\n            page_count = mupdf.fz_count_pages(self.this)\n            pdf_document = _as_pdf_document(self)\n        while n < 0:\n            n += page_count\n        if n > page_count:\n            raise ValueError( MSG_BAD_PAGENO)\n        page_obj = mupdf.pdf_lookup_page_obj(pdf_document, n)\n        annots = JM_get_annot_xref_list(page_obj)\n        return annots\n\n    @property\n    def page_count(self):\n        \"\"\"Number of pages.\"\"\"\n        if self.is_closed:\n            raise ValueError('document closed')\n        if g_use_extra:\n            return self.page_count2(self)\n        if isinstance( self.this, mupdf.FzDocument):\n            return mupdf.fz_count_pages( self.this)\n        else:\n            return mupdf.pdf_count_pages( self.this)\n\n    def page_cropbox(self, pno):\n        \"\"\"Get CropBox of page number (without loading page).\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        this_doc = self.this\n        page_count = mupdf.fz_count_pages( this_doc)\n        n = pno\n        while n < 0:\n            n += page_count\n        pdf = _as_pdf_document(self)\n        if n >= page_count:\n            raise ValueError( MSG_BAD_PAGENO)\n        pageref = mupdf.pdf_lookup_page_obj( pdf, n)\n        cropbox = JM_cropbox(pageref)\n        val = JM_py_from_rect(cropbox)\n\n        val = Rect(val)\n\n        return val\n\n    def page_number_from_location(self, page_id):\n        \"\"\"Convert (chapter, pno) to page number.\"\"\"\n        if type(page_id) is int:\n            np = self.page_count\n            while page_id < 0:\n                page_id += np\n            page_id = (0, page_id)\n        if page_id not in self:\n            raise ValueError(\"page id not in document\")\n        chapter, pno = page_id\n        loc = mupdf.fz_make_location( chapter, pno)\n        page_n = mupdf.fz_page_number_from_location( self.this, loc)\n        return page_n\n\n    def page_xref(self, pno):\n        \"\"\"Get xref of page number.\"\"\"\n        if g_use_extra:\n            return extra.page_xref( self.this, pno)\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        page_count = mupdf.fz_count_pages(self.this)\n        n = pno\n        while n < 0:\n            n += page_count\n        pdf = _as_pdf_document(self)\n        xref = 0\n        if n >= page_count:\n            raise ValueError( MSG_BAD_PAGENO)\n        xref = mupdf.pdf_to_num(mupdf.pdf_lookup_page_obj(pdf, n))\n        return xref\n\n    @property\n    def pagelayout(self) -> str:\n        \"\"\"Return the PDF PageLayout value.\n        \"\"\"\n        xref = self.pdf_catalog()\n        if xref == 0:\n            return None\n        rc = self.xref_get_key(xref, \"PageLayout\")\n        if rc[0] == \"null\":\n            return \"SinglePage\"\n        if rc[0] == \"name\":\n            return rc[1][1:]\n        return \"SinglePage\"\n\n    @property\n    def pagemode(self) -> str:\n        \"\"\"Return the PDF PageMode value.\n        \"\"\"\n        xref = self.pdf_catalog()\n        if xref == 0:\n            return None\n        rc = self.xref_get_key(xref, \"PageMode\")\n        if rc[0] == \"null\":\n            return \"UseNone\"\n        if rc[0] == \"name\":\n            return rc[1][1:]\n        return \"UseNone\"\n\n    def pages(self, start: OptInt =None, stop: OptInt =None, step: OptInt =None) -> collections.abc.Iterable[Page]:\n        \"\"\"Return a generator iterator over a page range.\n\n        Arguments have the same meaning as for the range() built-in.\n        \"\"\"\n        if not self.page_count:\n            return\n        # set the start value\n        start = start or 0\n        while start < 0:\n            start += self.page_count\n        if start not in range(self.page_count):\n            raise ValueError(\"bad start page number\")\n\n        # set the stop value\n        stop = stop if stop is not None and stop <= self.page_count else self.page_count\n\n        # set the step value\n        if step == 0:\n            raise ValueError(\"arg 3 must not be zero\")\n        if step is None:\n            if start > stop:\n                step = -1\n            else:\n                step = 1\n\n        for pno in range(start, stop, step):\n            yield (self.load_page(pno))\n\n    def pdf_catalog(self):\n        \"\"\"Get xref of PDF catalog.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        xref = 0\n        if not pdf.m_internal:\n            return xref\n        root = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root'))\n        xref = mupdf.pdf_to_num(root)\n        return xref\n\n    def pdf_trailer(self, compressed=0, ascii=0):\n        \"\"\"Get PDF trailer as a string.\"\"\"\n        return self.xref_object(-1, compressed=compressed, ascii=ascii)\n\n    @property\n    def permissions(self):\n        \"\"\"Document permissions.\"\"\"\n        if self.is_encrypted:\n            return 0\n        doc =self.this\n        pdf = mupdf.pdf_document_from_fz_document(doc)\n\n        # for PDF return result of standard function\n        if pdf.m_internal:\n            return mupdf.pdf_document_permissions(pdf)\n\n        # otherwise simulate the PDF return value\n        perm = 0xFFFFFFFC   # all permissions granted\n        # now switch off where needed\n        if not mupdf.fz_has_permission(doc, mupdf.FZ_PERMISSION_PRINT):\n            perm = perm ^ mupdf.PDF_PERM_PRINT\n        if not mupdf.fz_has_permission(doc, mupdf.FZ_PERMISSION_EDIT):\n            perm = perm ^ mupdf.PDF_PERM_MODIFY\n        if not mupdf.fz_has_permission(doc, mupdf.FZ_PERMISSION_COPY):\n            perm = perm ^ mupdf.PDF_PERM_COPY\n        if not mupdf.fz_has_permission(doc, mupdf.FZ_PERMISSION_ANNOTATE):\n            perm = perm ^ mupdf.PDF_PERM_ANNOTATE\n        return perm\n\n    def prev_location(self, page_id):\n\n        \"\"\"Get (chapter, page) of previous page.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if type(page_id) is int:\n            page_id = (0, page_id)\n        if page_id not in self:\n            raise ValueError(\"page id not in document\")\n        if page_id  == (0, 0):\n            return ()\n        chapter, pno = page_id\n        loc = mupdf.fz_make_location(chapter, pno)\n        prev_loc = mupdf.fz_previous_page(self.this, loc)\n        return prev_loc.chapter, prev_loc.page\n\n    def reload_page(self, page: Page) -> Page:\n        \"\"\"Make a fresh copy of a page.\"\"\"\n        old_annots = {}  # copy annot references to here\n        pno = page.number  # save the page number\n        for k, v in page._annot_refs.items():  # save the annot dictionary\n            old_annots[k] = v\n        \n        # When we call `self.load_page()` below, it will end up in\n        # fz_load_chapter_page(), which will return any matching page in the\n        # document's list of non-ref-counted loaded pages, instead of actually\n        # reloading the page.\n        #\n        # We want to assert that we have actually reloaded the fz_page, and not\n        # simply returned the same `fz_page*` pointer from the document's list\n        # of non-ref-counted loaded pages.\n        #\n        # So we first remove our reference to the `fz_page*`. This will\n        # decrement .refs, and if .refs was 1, this is guaranteed to free the\n        # `fz_page*` and remove it from the document's list if it was there. So\n        # we are guaranteed that our returned `fz_page*` is from a genuine\n        # reload, even if it happens to reuse the original block of memory.\n        #\n        # However if the original .refs is greater than one, there must be\n        # other references to the `fz_page` somewhere, and we require that\n        # these other references are not keeping the page in the document's\n        # list.  We check that we are returning a newly loaded page by\n        # asserting that our returned `fz_page*` is different from the original\n        # `fz_page*` - the original was not freed, so a new `fz_page` cannot\n        # reuse the same block of memory.\n        #\n        \n        refs_old = page.this.m_internal.refs\n        m_internal_old = page.this.m_internal_value()\n        \n        page.this = None\n        page._erase()  # remove the page\n        page = None\n        TOOLS.store_shrink(100)\n        page = self.load_page(pno)  # reload the page\n\n        # copy annot refs over to the new dictionary\n        #page_proxy = weakref.proxy(page)\n        for k, v in old_annots.items():\n            annot = old_annots[k]\n            #annot.parent = page_proxy  # refresh parent to new page\n            page._annot_refs[k] = annot\n        if refs_old == 1:\n            # We know that `page.this = None` will have decremented the ref\n            # count to zero so we are guaranteed that the new `fz_page` is a\n            # new page even if it happens to have reused the same block of\n            # memory.\n            pass\n        else:\n            # Check that the new `fz_page*` is different from the original.\n            m_internal_new = page.this.m_internal_value()\n            assert m_internal_new != m_internal_old, \\\n                    f'{refs_old=} {m_internal_old=:#x} {m_internal_new=:#x}'\n        return page\n\n    def repair(self):\n        '''\n        If we are a PDF document, does repair.\n        '''\n        pdf = _as_pdf_document(self, required=False)\n        if pdf.m_internal:\n            mupdf.pdf_check_document(pdf)\n    \n    def resolve_link(self, uri=None, chapters=0):\n        \"\"\"Calculate internal link destination.\n\n        Args:\n            uri: (str) some Link.uri\n            chapters: (bool) whether to use (chapter, page) format\n        Returns:\n            (page_id, x, y) where x, y are point coordinates on the page.\n            page_id is either page number (if chapters=0), or (chapter, pno).\n        \"\"\"\n        if not uri:\n            if chapters:\n                return (-1, -1), 0, 0\n            return -1, 0, 0\n        try:\n            loc, xp, yp = mupdf.fz_resolve_link(self.this, uri)\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            if chapters:\n                return (-1, -1), 0, 0\n            return -1, 0, 0\n        if chapters:\n            return (loc.chapter, loc.page), xp, yp\n        pno = mupdf.fz_page_number_from_location(self.this, loc)\n        return pno, xp, yp\n\n    def rewrite_images(\n        self,\n        dpi_threshold=None,\n        dpi_target=0,\n        quality=0,\n        lossy=True,\n        lossless=True,\n        bitonal=True,\n        color=True,\n        gray=True,\n        set_to_gray=False,\n        options=None,\n    ):\n        \"\"\"Rewrite images in a PDF document.\n\n        The typical use case is to reduce the size of the PDF by recompressing\n        images. Default parameters will convert all images to JPEG where\n        possible, using the specified resolutions and quality. Exclude\n        undesired images by setting parameters to False.\n        Args:\n            dpi_threshold: look at images with a larger DPI only.\n            dpi_target: change eligible images to this DPI.\n            quality: Quality of the recompressed images (0-100).\n            lossy: process lossy image types (e.g. JPEG).\n            lossless: process lossless image types (e.g. PNG).\n            bitonal: process black-and-white images (e.g. FAX)\n            color: process colored images.\n            gray: process gray images.\n            set_to_gray: whether to change the PDF to gray at process start.\n            options: (PdfImageRewriterOptions) Custom options for image\n                    rewriting (optional). Expert use only. If provided, other\n                    parameters are ignored, except set_to_gray.\n        \"\"\"\n        quality_str = str(quality)\n        if not dpi_threshold:\n            dpi_threshold = dpi_target = 0\n        if dpi_target > 0 and dpi_target >= dpi_threshold:\n            raise ValueError(\"{dpi_target=} must be less than {dpi_threshold=}\")\n        template_opts = mupdf.PdfImageRewriterOptions()\n        dir1 = set(dir(template_opts))  # for checking that only existing options are set\n        if not options:\n            opts = mupdf.PdfImageRewriterOptions()\n            if bitonal:\n                opts.bitonal_image_recompress_method = mupdf.FZ_RECOMPRESS_FAX\n                opts.bitonal_image_subsample_method = mupdf.FZ_SUBSAMPLE_AVERAGE\n                opts.bitonal_image_subsample_to = dpi_target\n                opts.bitonal_image_recompress_quality = quality_str\n                opts.bitonal_image_subsample_threshold = dpi_threshold\n            if color:\n                if lossless:\n                    opts.color_lossless_image_recompress_method = mupdf.FZ_RECOMPRESS_JPEG\n                    opts.color_lossless_image_subsample_method = mupdf.FZ_SUBSAMPLE_AVERAGE\n                    opts.color_lossless_image_subsample_to = dpi_target\n                    opts.color_lossless_image_subsample_threshold = dpi_threshold\n                    opts.color_lossless_image_recompress_quality = quality_str\n                if lossy:\n                    opts.color_lossy_image_recompress_method = mupdf.FZ_RECOMPRESS_JPEG\n                    opts.color_lossy_image_subsample_method = mupdf.FZ_SUBSAMPLE_AVERAGE\n                    opts.color_lossy_image_subsample_threshold = dpi_threshold\n                    opts.color_lossy_image_subsample_to = dpi_target\n                    opts.color_lossy_image_recompress_quality = quality_str\n            if gray:\n                if lossless:\n                    opts.gray_lossless_image_recompress_method = mupdf.FZ_RECOMPRESS_JPEG\n                    opts.gray_lossless_image_subsample_method = mupdf.FZ_SUBSAMPLE_AVERAGE\n                    opts.gray_lossless_image_subsample_to = dpi_target\n                    opts.gray_lossless_image_subsample_threshold = dpi_threshold\n                    opts.gray_lossless_image_recompress_quality = quality_str\n                if lossy:\n                    opts.gray_lossy_image_recompress_method = mupdf.FZ_RECOMPRESS_JPEG\n                    opts.gray_lossy_image_subsample_method = mupdf.FZ_SUBSAMPLE_AVERAGE\n                    opts.gray_lossy_image_subsample_threshold = dpi_threshold\n                    opts.gray_lossy_image_subsample_to = dpi_target\n                    opts.gray_lossy_image_recompress_quality = quality_str\n        else:\n            opts = options\n\n        dir2 = set(dir(opts))  # checking that only possible options were used\n        invalid_options = dir2 - dir1\n        if invalid_options:\n            raise ValueError(f\"Invalid options: {invalid_options}\")\n\n        if set_to_gray:\n            self.recolor(1)\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_rewrite_images(pdf, opts)\n\n    def recolor(self, components=1):\n        \"\"\"Change the color component count on all pages.\n\n        Args:\n            components: (int) desired color component count, one of 1, 3, 4.\n\n        Invokes the same-named method for all pages.\n        \"\"\"\n        if not self.is_pdf:\n            raise ValueError(\"is no PDF\")\n        for i in range(self.page_count):\n            self.load_page(i).recolor(components)\n\n    def resolve_names(self):\n        \"\"\"Convert the PDF's destination names into a Python dict.\n\n        The only parameter is the pymupdf.Document.\n        All names found in the catalog under keys \"/Dests\" and \"/Names/Dests\" are\n        being included.\n\n        Returns:\n            A dcitionary with the following layout:\n            - key: (str) the name\n            - value: (dict) with the following layout:\n                * \"page\":  target page number (0-based). If no page number found -1.\n                * \"to\": (x, y) target point on page - currently in PDF coordinates,\n                        i.e. point (0,0) is the bottom-left of the page.\n                * \"zoom\": (float) the zoom factor\n                * \"dest\": (str) only occurs if the target location on the page has\n                        not been provided as \"/XYZ\" or if no page number was found.\n            Examples:\n            {'__bookmark_1': {'page': 0, 'to': (0.0, 541.0), 'zoom': 0.0},\n            '__bookmark_2': {'page': 0, 'to': (0.0, 481.45), 'zoom': 0.0}}\n\n            or\n\n            '21154a7c20684ceb91f9c9adc3b677c40': {'page': -1, 'dest': '/XYZ 15.75 1486 0'}, ...\n        \"\"\"\n        if hasattr(self, \"_resolved_names\"):  # do not execute multiple times!\n            return self._resolved_names\n        # this is a backward listing of page xref to page number\n        page_xrefs = {self.page_xref(i): i for i in range(self.page_count)}\n\n        def obj_string(obj):\n            \"\"\"Return string version of a PDF object definition.\"\"\"\n            buffer = mupdf.fz_new_buffer(512)\n            output = mupdf.FzOutput(buffer)\n            mupdf.pdf_print_obj(output, obj, 1, 0)\n            output.fz_close_output()\n            return JM_UnicodeFromBuffer(buffer)\n\n        def get_array(val):\n            \"\"\"Generate value of one item of the names dictionary.\"\"\"\n            templ_dict = {\"page\": -1, \"dest\": \"\"}  # value template\n            if val.pdf_is_indirect():\n                val = mupdf.pdf_resolve_indirect(val)\n            if val.pdf_is_array():\n                array = obj_string(val)\n            elif val.pdf_is_dict():\n                array = obj_string(mupdf.pdf_dict_gets(val, \"D\"))\n            else:  # if all fails return the empty template\n                return templ_dict\n\n            # replace PDF \"null\" by zero, omit the square brackets\n            array = array.replace(\"null\", \"0\")[1:-1]\n\n            # find stuff before first \"/\"\n            idx = array.find(\"/\")\n            if idx < 1:  # this has no target page spec\n                templ_dict[\"dest\"] = array  # return the orig. string\n                return templ_dict\n\n            subval = array[:idx].strip()  # stuff before \"/\"\n            array = array[idx:]  # stuff from \"/\" onwards\n            templ_dict[\"dest\"] = array\n            # if we start with /XYZ: extract x, y, zoom\n            # 1, 2 or 3 of these values may actually be supplied\n            if array.startswith(\"/XYZ\"):\n                del templ_dict[\"dest\"]  # don't return orig string in this case\n\n                # make a list of the 3 tokens following \"/XYZ\"\n                array_list = array.split()[1:4]  # omit \"/XYZ\"\n\n                # fill up missing tokens with \"0\" strings\n                while len(array_list) < 3:  # fill up if too short\n                    array_list.append(\"0\")  # add missing values\n\n                # make list of 3 floats: x, y and zoom\n                t = list(map(float, array_list))  # the resulting x, y, z values\n                templ_dict[\"to\"] = (t[0], t[1])\n                templ_dict[\"zoom\"] = t[2]\n\n            # extract page number\n            if subval.endswith(\"0 R\"):  # page xref given?\n                templ_dict[\"page\"] = page_xrefs.get(int(subval.split()[0]),-1)\n            else:  # naked page number given\n                templ_dict[\"page\"] = int(subval)\n            return templ_dict\n\n        def fill_dict(dest_dict, pdf_dict):\n            \"\"\"Generate name resolution items for pdf_dict.\n\n            This may be either \"/Names/Dests\" or just \"/Dests\"\n            \"\"\"\n            # length of the PDF dictionary\n            name_count = mupdf.pdf_dict_len(pdf_dict)\n\n            # extract key-val of each dict item\n            for i in range(name_count):\n                key = mupdf.pdf_dict_get_key(pdf_dict, i)\n                val = mupdf.pdf_dict_get_val(pdf_dict, i)\n                if key.pdf_is_name():  # this should always be true!\n                    dict_key = key.pdf_to_name()\n                else:\n                    message(f\"key {i} is no /Name\")\n                    dict_key = None\n\n                if dict_key:\n                    dest_dict[dict_key] = get_array(val)  # store key/value in dict\n\n        # access underlying PDF document of fz Document\n        pdf = mupdf.pdf_document_from_fz_document(self)\n\n        # access PDF catalog\n        catalog = mupdf.pdf_dict_gets(mupdf.pdf_trailer(pdf), \"Root\")\n\n        dest_dict = {}\n\n        # make PDF_NAME(Dests)\n        dests = mupdf.pdf_new_name(\"Dests\")\n\n        # extract destinations old style (PDF 1.1)\n        old_dests = mupdf.pdf_dict_get(catalog, dests)\n        if old_dests.pdf_is_dict():\n            fill_dict(dest_dict, old_dests)\n\n        # extract destinations new style (PDF 1.2+)\n        tree = mupdf.pdf_load_name_tree(pdf, dests)\n        if tree.pdf_is_dict():\n            fill_dict(dest_dict, tree)\n\n        self._resolved_names = dest_dict  # store result or reuse\n        return dest_dict\n\n    def save(\n            self,\n            filename,\n            garbage=0,\n            clean=0,\n            deflate=0,\n            deflate_images=0,\n            deflate_fonts=0,\n            incremental=0,\n            ascii=0,\n            expand=0,\n            linear=0,\n            no_new_id=0,\n            appearance=0,\n            pretty=0,\n            encryption=1,\n            permissions=4095,\n            owner_pw=None,\n            user_pw=None,\n            preserve_metadata=1,\n            use_objstms=0,\n            compression_effort=0,\n            raise_on_repair=False,\n            ):\n        # From %pythonprepend save\n        #\n        is_repaired_pre = self.is_repaired\n        \"\"\"Save PDF to file, pathlib.Path or file pointer.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if type(filename) is str:\n            pass\n        elif hasattr(filename, \"open\"):  # assume: pathlib.Path\n            filename = str(filename)\n        elif hasattr(filename, \"name\"):  # assume: file object\n            filename = filename.name\n        elif not hasattr(filename, \"seek\"):  # assume file object\n            raise ValueError(\"filename must be str, Path or file object\")\n        if filename == self.name and not incremental:\n            raise ValueError(\"save to original must be incremental\")\n        if linear and use_objstms:\n            raise ValueError(\"'linear' and 'use_objstms' cannot both be requested\")\n        if self.page_count < 1:\n            raise ValueError(\"cannot save with zero pages\")\n        if incremental:\n            if self.name != filename or self.stream:\n                raise ValueError(\"incremental needs original file\")\n        if user_pw and len(user_pw) > 40 or owner_pw and len(owner_pw) > 40:\n            raise ValueError(\"password length must not exceed 40\")\n        \n        pdf = _as_pdf_document(self)\n        opts = mupdf.PdfWriteOptions()\n        opts.do_incremental = incremental\n        opts.do_ascii = ascii\n        opts.do_compress = deflate\n        opts.do_compress_images = deflate_images\n        opts.do_compress_fonts = deflate_fonts\n        opts.do_decompress = expand\n        opts.do_garbage = garbage\n        opts.do_pretty = pretty\n        opts.do_linear = linear\n        opts.do_clean = clean\n        opts.do_sanitize = clean\n        opts.dont_regenerate_id = no_new_id\n        opts.do_appearance = appearance\n        opts.do_encrypt = encryption\n        opts.permissions = permissions\n        if owner_pw is not None:\n            opts.opwd_utf8_set_value(owner_pw)\n        elif user_pw is not None:\n            opts.opwd_utf8_set_value(user_pw)\n        if user_pw is not None:\n            opts.upwd_utf8_set_value(user_pw)\n        opts.do_preserve_metadata = preserve_metadata\n        opts.do_use_objstms = use_objstms\n        opts.compression_effort = compression_effort\n\n        out = None\n        pdf.m_internal.resynth_required = 0\n        JM_embedded_clean(pdf)\n        if no_new_id == 0:\n            JM_ensure_identity(pdf)\n        if isinstance(filename, str):\n            #log( 'calling mupdf.pdf_save_document()')\n            mupdf.pdf_save_document(pdf, filename, opts)\n        else:\n            out = JM_new_output_fileptr(filename)\n            #log( f'{type(out)=} {type(out.this)=}')\n            mupdf.pdf_write_document(pdf, out, opts)\n            out.fz_close_output()\n        if raise_on_repair:\n            if self.is_repaired and not is_repaired_pre:\n                raise Exception(f'Document save did a repair')\n\n    def save_snapshot(self, filename):\n        \"\"\"Save a file snapshot suitable for journalling.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"doc is closed\")\n        if type(filename) is str:\n            pass\n        elif hasattr(filename, \"open\"):  # assume: pathlib.Path\n            filename = str(filename)\n        elif hasattr(filename, \"name\"):  # assume: file object\n            filename = filename.name\n        else:\n            raise ValueError(\"filename must be str, Path or file object\")\n        if filename == self.name:\n            raise ValueError(\"cannot snapshot to original\")\n        pdf = _as_pdf_document(self)\n        mupdf.pdf_save_snapshot(pdf, filename)\n\n    def saveIncr(self):\n        \"\"\" Save PDF incrementally\"\"\"\n        return self.save(self.name, incremental=True, encryption=mupdf.PDF_ENCRYPT_KEEP)\n\n    # ------------------------------------------------------------------------------\n    # Remove potentially sensitive data from a PDF. Similar to the Adobe\n    # Acrobat 'sanitize' function\n    # ------------------------------------------------------------------------------\n    def scrub(\n            doc: 'Document',\n            attached_files: bool = True,\n            clean_pages: bool = True,\n            embedded_files: bool = True,\n            hidden_text: bool = True,\n            javascript: bool = True,\n            metadata: bool = True,\n            redactions: bool = True,\n            redact_images: int = 0,\n            remove_links: bool = True,\n            reset_fields: bool = True,\n            reset_responses: bool = True,\n            thumbnails: bool = True,\n            xml_metadata: bool = True,\n            ) -> None:\n        \n        def remove_hidden(cont_lines):\n            \"\"\"Remove hidden text from a PDF page.\n\n            Args:\n                cont_lines: list of lines with /Contents content. Should have status\n                    from after page.cleanContents().\n\n            Returns:\n                List of /Contents lines from which hidden text has been removed.\n\n            Notes:\n                The input must have been created after the page's /Contents object(s)\n                have been cleaned with page.cleanContents(). This ensures a standard\n                formatting: one command per line, single spaces between operators.\n                This allows for drastic simplification of this code.\n            \"\"\"\n            out_lines = []  # will return this\n            in_text = False  # indicate if within BT/ET object\n            suppress = False  # indicate text suppression active\n            make_return = False\n            for line in cont_lines:\n                if line == b\"BT\":  # start of text object\n                    in_text = True  # switch on\n                    out_lines.append(line)  # output it\n                    continue\n                if line == b\"ET\":  # end of text object\n                    in_text = False  # switch off\n                    out_lines.append(line)  # output it\n                    continue\n                if line == b\"3 Tr\":  # text suppression operator\n                    suppress = True  # switch on\n                    make_return = True\n                    continue\n                if line[-2:] == b\"Tr\" and line[0] != b\"3\":\n                    suppress = False  # text rendering changed\n                    out_lines.append(line)\n                    continue\n                if line == b\"Q\":  # unstack command also switches off\n                    suppress = False\n                    out_lines.append(line)\n                    continue\n                if suppress and in_text:  # suppress hidden lines\n                    continue\n                out_lines.append(line)\n            if make_return:\n                return out_lines\n            else:\n                return None\n\n        if not doc.is_pdf:  # only works for PDF\n            raise ValueError(\"is no PDF\")\n        if doc.is_encrypted or doc.is_closed:\n            raise ValueError(\"closed or encrypted doc\")\n\n        if not clean_pages:\n            hidden_text = False\n            redactions = False\n\n        if metadata:\n            doc.set_metadata({})  # remove standard metadata\n\n        for page in doc:\n            if reset_fields:\n                # reset form fields (widgets)\n                for widget in page.widgets():\n                    widget.reset()\n\n            if remove_links:\n                links = page.get_links()  # list of all links on page\n                for link in links:  # remove all links\n                    page.delete_link(link)\n\n            found_redacts = False\n            for annot in page.annots():\n                if annot.type[0] == mupdf.PDF_ANNOT_FILE_ATTACHMENT and attached_files:\n                    annot.update_file(buffer_=b\" \")  # set file content to empty\n                if reset_responses:\n                    annot.delete_responses()\n                if annot.type[0] == mupdf.PDF_ANNOT_REDACT:  # pylint: disable=no-member\n                    found_redacts = True\n\n            if redactions and found_redacts:\n                page.apply_redactions(images=redact_images)\n\n            if not (clean_pages or hidden_text):\n                continue  # done with the page\n\n            page.clean_contents()\n            if not page.get_contents():\n                continue\n            if hidden_text:\n                xrefs = page.get_contents()\n                assert len(xrefs) == 1  # only one because of cleaning.\n                xref = xrefs[0]\n                cont = doc.xref_stream(xref)\n                cont_lines = remove_hidden(cont.splitlines())  # remove hidden text\n                if cont_lines:  # something was actually removed\n                    cont = b\"\\n\".join(cont_lines)\n                    doc.update_stream(xref, cont)  # rewrite the page /Contents\n\n            if thumbnails:  # remove page thumbnails?\n                if doc.xref_get_key(page.xref, \"Thumb\")[0] != \"null\":\n                    doc.xref_set_key(page.xref, \"Thumb\", \"null\")\n\n        # pages are scrubbed, now perform document-wide scrubbing\n        # remove embedded files\n        if embedded_files:\n            for name in doc.embfile_names():\n                doc.embfile_del(name)\n\n        if xml_metadata:\n            doc.del_xml_metadata()\n        if not (xml_metadata or javascript):\n            xref_limit = 0\n        else:\n            xref_limit = doc.xref_length()\n        for xref in range(1, xref_limit):\n            if not doc.xref_object(xref):\n                msg = f\"bad xref {xref} - clean PDF before scrubbing\"\n                raise ValueError(msg)\n            if javascript and doc.xref_get_key(xref, \"S\")[1] == \"/JavaScript\":\n                # a /JavaScript action object\n                obj = \"<</S/JavaScript/JS()>>\"  # replace with a null JavaScript\n                doc.update_object(xref, obj)  # update this object\n                continue  # no further handling\n\n            if not xml_metadata:\n                continue\n\n            if doc.xref_get_key(xref, \"Type\")[1] == \"/Metadata\":\n                # delete any metadata object directly\n                doc.update_object(xref, \"<<>>\")\n                doc.update_stream(xref, b\"deleted\", new=True)\n                continue\n\n            if doc.xref_get_key(xref, \"Metadata\")[0] != \"null\":\n                doc.xref_set_key(xref, \"Metadata\", \"null\")\n    \n    def search_page_for(\n            doc: 'Document',\n            pno: int,\n            text: str,\n            quads: bool = False,\n            clip: rect_like = None,\n            flags: int = None,\n            textpage: 'TextPage' = None,\n            ) -> list:\n        \"\"\"Search for a string on a page.\n\n        Args:\n            pno: page number\n            text: string to be searched for\n            clip: restrict search to this rectangle\n            quads: (bool) return quads instead of rectangles\n            flags: bit switches, default: join hyphened words\n            textpage: reuse a prepared textpage\n        Returns:\n            a list of rectangles or quads, each containing an occurrence.\n        \"\"\"\n        if flags is None:\n            flags = (0\n                    | TEXT_DEHYPHENATE\n                    | TEXT_PRESERVE_LIGATURES\n                    | TEXT_PRESERVE_WHITESPACE\n                    | TEXT_MEDIABOX_CLIP\n                    )\n        return doc[pno].search_for(\n            text,\n            quads=quads,\n            clip=clip,\n            flags=flags,\n            textpage=textpage,\n        )\n    \n    def select(self, pyliste):\n        \"\"\"Build sub-pdf with page numbers in the list.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if not self.is_pdf:\n            raise ValueError(\"is no PDF\")\n        if not hasattr(pyliste, \"__getitem__\"):\n            raise ValueError(\"sequence required\")\n\n        valid_range = range(len(self))\n        if (len(pyliste) == 0\n            or min(pyliste) not in valid_range\n            or max(pyliste) not in valid_range\n        ):\n            raise ValueError(\"bad page number(s)\")\n\n        # get underlying pdf document,\n        pdf = _as_pdf_document(self)\n        # create page sub-pdf via pdf_rearrange_pages2().\n        #\n        # We use PDF_CLEAN_STRUCTURE_KEEP otherwise we lose structure tree\n        # which, for example, breaks test_3705.\n        mupdf.pdf_rearrange_pages2(pdf, pyliste, mupdf.PDF_CLEAN_STRUCTURE_KEEP)\n\n        # remove any existing pages with their kids\n        self._reset_page_refs()\n\n    def set_language(self, language=None):\n        pdf = _as_pdf_document(self)\n        if not language:\n            lang = mupdf.FZ_LANG_UNSET\n        else:\n            lang = mupdf.fz_text_language_from_string(language)\n        mupdf.pdf_set_document_language(pdf, lang)\n        return True\n\n    def set_layer(self, config, basestate=None, on=None, off=None, rbgroups=None, locked=None):\n        \"\"\"Set the PDF keys /ON, /OFF, /RBGroups of an OC layer.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        ocgs = set(self.get_ocgs().keys())\n        if ocgs == set():\n            raise ValueError(\"document has no optional content\")\n\n        if on:\n            if type(on) not in (list, tuple):\n                raise ValueError(\"bad type: 'on'\")\n            s = set(on).difference(ocgs)\n            if s != set():\n                raise ValueError(f\"bad OCGs in 'on': {s}\")\n\n        if off:\n            if type(off) not in (list, tuple):\n                raise ValueError(\"bad type: 'off'\")\n            s = set(off).difference(ocgs)\n            if s != set():\n                raise ValueError(f\"bad OCGs in 'off': {s}\")\n\n        if locked:\n            if type(locked) not in (list, tuple):\n                raise ValueError(\"bad type: 'locked'\")\n            s = set(locked).difference(ocgs)\n            if s != set():\n                raise ValueError(f\"bad OCGs in 'locked': {s}\")\n\n        if rbgroups:\n            if type(rbgroups) not in (list, tuple):\n                raise ValueError(\"bad type: 'rbgroups'\")\n            for x in rbgroups:\n                if not type(x) in (list, tuple):\n                    raise ValueError(f\"bad RBGroup '{x}'\")\n                s = set(x).difference(ocgs)\n                if s != set():\n                    raise ValueError(f\"bad OCGs in RBGroup: {s}\")\n\n        if basestate:\n            basestate = str(basestate).upper()\n            if basestate == \"UNCHANGED\":\n                basestate = \"Unchanged\"\n            if basestate not in (\"ON\", \"OFF\", \"Unchanged\"):\n                raise ValueError(\"bad 'basestate'\")\n        pdf = _as_pdf_document(self)\n        ocp = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer( pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('OCProperties'),\n                )\n        if not ocp.m_internal:\n            return\n        if config == -1:\n            obj = mupdf.pdf_dict_get( ocp, PDF_NAME('D'))\n        else:\n            obj = mupdf.pdf_array_get(\n                    mupdf.pdf_dict_get( ocp, PDF_NAME('Configs')),\n                    config,\n                    )\n        if not obj.m_internal:\n            raise ValueError( MSG_BAD_OC_CONFIG)\n        JM_set_ocg_arrays( obj, basestate, on, off, rbgroups, locked)\n        mupdf.ll_pdf_read_ocg( pdf.m_internal)\n\n    def set_layer_ui_config(self, number, action=0):\n        \"\"\"Set / unset OC intent configuration.\"\"\"\n        # The user might have given the name instead of sequence number,\n        # so select by that name and continue with corresp. number\n        if isinstance(number, str):\n            select = [ui[\"number\"] for ui in self.layer_ui_configs() if ui[\"text\"] == number]\n            if select == []:\n                raise ValueError(f\"bad OCG '{number}'.\")\n            number = select[0]  # this is the number for the name\n        pdf = _as_pdf_document(self)\n        if action == 1:\n            mupdf.pdf_toggle_layer_config_ui(pdf, number)\n        elif action == 2:\n            mupdf.pdf_deselect_layer_config_ui(pdf, number)\n        else:\n            mupdf.pdf_select_layer_config_ui(pdf, number)\n\n    def set_markinfo(self, markinfo: dict) -> bool:\n        \"\"\"Set the PDF MarkInfo values.\"\"\"\n        xref = self.pdf_catalog()\n        if xref == 0:\n            raise ValueError(\"not a PDF\")\n        if not markinfo or not isinstance(markinfo, dict):\n            return False\n        valid = {\"Marked\": False, \"UserProperties\": False, \"Suspects\": False}\n\n        if not set(valid.keys()).issuperset(markinfo.keys()):\n            badkeys = f\"bad MarkInfo key(s): {set(markinfo.keys()).difference(valid.keys())}\"\n            raise ValueError(badkeys)\n        pdfdict = \"<<\"\n        valid.update(markinfo)\n        for key, value in valid.items():\n            value=str(value).lower()\n            if value not in (\"true\", \"false\"):\n                raise ValueError(f\"bad key value '{key}': '{value}'\")\n            pdfdict += f\"/{key} {value}\"\n        pdfdict += \">>\"\n        self.xref_set_key(xref, \"MarkInfo\", pdfdict)\n        return True\n\n    def set_metadata(doc: 'Document', m: dict = None) -> None:\n        \"\"\"Update the PDF /Info object.\n\n        Args:\n            m: a dictionary like doc.metadata.\n        \"\"\"\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        if doc.is_closed or doc.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if m is None:\n            m = {}\n        elif type(m) is not dict:\n            raise ValueError(\"bad metadata\")\n        keymap = {\n            \"author\": \"Author\",\n            \"producer\": \"Producer\",\n            \"creator\": \"Creator\",\n            \"title\": \"Title\",\n            \"format\": None,\n            \"encryption\": None,\n            \"creationDate\": \"CreationDate\",\n            \"modDate\": \"ModDate\",\n            \"subject\": \"Subject\",\n            \"keywords\": \"Keywords\",\n            \"trapped\": \"Trapped\",\n        }\n        valid_keys = set(keymap.keys())\n        diff_set = set(m.keys()).difference(valid_keys)\n        if diff_set != set():\n            msg = f\"bad dict key(s): {diff_set}\"\n            raise ValueError(msg)\n\n        t, temp = doc.xref_get_key(-1, \"Info\")\n        if t != \"xref\":\n            info_xref = 0\n        else:\n            info_xref = int(temp.replace(\"0 R\", \"\"))\n\n        if m == {} and info_xref == 0:  # nothing to do\n            return\n\n        if info_xref == 0:  # no prev metadata: get new xref\n            info_xref = doc.get_new_xref()\n            doc.update_object(info_xref, \"<<>>\")  # fill it with empty object\n            doc.xref_set_key(-1, \"Info\", f\"{info_xref} 0 R\")\n        elif m == {}:  # remove existing metadata\n            doc.xref_set_key(-1, \"Info\", \"null\")\n            doc.init_doc()\n            return\n\n        for key, val in [(k, v) for k, v in m.items() if keymap[k] is not None]:\n            pdf_key = keymap[key]\n            if not bool(val) or val in (\"none\", \"null\"):\n                val = \"null\"\n            else:\n                val = get_pdf_str(val)\n            doc.xref_set_key(info_xref, pdf_key, val)\n        doc.init_doc()\n        return\n\n    def set_oc(doc: 'Document', xref: int, oc: int) -> None:\n        \"\"\"Attach optional content object to image or form xobject.\n\n        Args:\n            xref: (int) xref number of an image or form xobject\n            oc: (int) xref number of an OCG or OCMD\n        \"\"\"\n        if doc.is_closed or doc.is_encrypted:\n            raise ValueError(\"document close or encrypted\")\n        t, name = doc.xref_get_key(xref, \"Subtype\")\n        if t != \"name\" or name not in (\"/Image\", \"/Form\"):\n            raise ValueError(f\"bad object type at xref {xref}\")\n        if oc > 0:\n            t, name = doc.xref_get_key(oc, \"Type\")\n            if t != \"name\" or name not in (\"/OCG\", \"/OCMD\"):\n                raise ValueError(f\"bad object type at xref {oc}\")\n        if oc == 0 and \"OC\" in doc.xref_get_keys(xref):\n            doc.xref_set_key(xref, \"OC\", \"null\")\n            return None\n        doc.xref_set_key(xref, \"OC\", f\"{oc} 0 R\")\n        return None\n\n    def set_ocmd(\n            doc: 'Document',\n            xref: int = 0,\n            ocgs: typing.Union[list, None] = None,\n            policy: OptStr = None,\n            ve: typing.Union[list, None] = None,\n            ) -> int:\n        \"\"\"Create or update an OCMD object in a PDF document.\n\n        Args:\n            xref: (int) 0 for creating a new object, otherwise update existing one.\n            ocgs: (list) OCG xref numbers, which shall be subject to 'policy'.\n            policy: one of 'AllOn', 'AllOff', 'AnyOn', 'AnyOff' (any casing).\n            ve: (list) visibility expression. Use instead of 'ocgs' with 'policy'.\n\n        Returns:\n            Xref of the created or updated OCMD.\n        \"\"\"\n\n        all_ocgs = set(doc.get_ocgs().keys())\n\n        def ve_maker(ve):\n            if type(ve) not in (list, tuple) or len(ve) < 2:\n                raise ValueError(f\"bad 've' format: {ve}\")\n            if ve[0].lower() not in (\"and\", \"or\", \"not\"):\n                raise ValueError(f\"bad operand: {ve[0]}\")\n            if ve[0].lower() == \"not\" and len(ve) != 2:\n                raise ValueError(f\"bad 've' format: {ve}\")\n            item = f\"[/{ve[0].title()}\"\n            for x in ve[1:]:\n                if type(x) is int:\n                    if x not in all_ocgs:\n                        raise ValueError(f\"bad OCG {x}\")\n                    item += f\" {x} 0 R\"\n                else:\n                    item += f\" {ve_maker(x)}\"\n            item += \"]\"\n            return item\n\n        text = \"<</Type/OCMD\"\n\n        if ocgs and type(ocgs) in (list, tuple):  # some OCGs are provided\n            s = set(ocgs).difference(all_ocgs)  # contains illegal xrefs\n            if s != set():\n                msg = f\"bad OCGs: {s}\"\n                raise ValueError(msg)\n            text += \"/OCGs[\" + \" \".join(map(lambda x: f\"{x} 0 R\", ocgs)) + \"]\"\n\n        if policy:\n            policy = str(policy).lower()\n            pols = {\n                \"anyon\": \"AnyOn\",\n                \"allon\": \"AllOn\",\n                \"anyoff\": \"AnyOff\",\n                \"alloff\": \"AllOff\",\n            }\n            if policy not in (\"anyon\", \"allon\", \"anyoff\", \"alloff\"):\n                raise ValueError(f\"bad policy: {policy}\")\n            text += f\"/P/{pols[policy]}\"\n\n        if ve:\n            text += f\"/VE{ve_maker(ve)}\"\n\n        text += \">>\"\n\n        # make new object or replace old OCMD (check type first)\n        if xref == 0:\n            xref = doc.get_new_xref()\n        elif \"/Type/OCMD\" not in doc.xref_object(xref, compressed=True):\n            raise ValueError(\"bad xref or not an OCMD\")\n        doc.update_object(xref, text)\n        return xref\n\n    def set_pagelayout(self, pagelayout: str):\n        \"\"\"Set the PDF PageLayout value.\"\"\"\n        valid = (\"SinglePage\", \"OneColumn\", \"TwoColumnLeft\", \"TwoColumnRight\", \"TwoPageLeft\", \"TwoPageRight\")\n        xref = self.pdf_catalog()\n        if xref == 0:\n            raise ValueError(\"not a PDF\")\n        if not pagelayout:\n            raise ValueError(\"bad PageLayout value\")\n        if pagelayout[0] == \"/\":\n            pagelayout = pagelayout[1:]\n        for v in valid:\n            if pagelayout.lower() == v.lower():\n                self.xref_set_key(xref, \"PageLayout\", f\"/{v}\")\n                return True\n        raise ValueError(\"bad PageLayout value\")\n\n    def set_pagemode(self, pagemode: str):\n        \"\"\"Set the PDF PageMode value.\"\"\"\n        valid = (\"UseNone\", \"UseOutlines\", \"UseThumbs\", \"FullScreen\", \"UseOC\", \"UseAttachments\")\n        xref = self.pdf_catalog()\n        if xref == 0:\n            raise ValueError(\"not a PDF\")\n        if not pagemode:\n            raise ValueError(\"bad PageMode value\")\n        if pagemode[0] == \"/\":\n            pagemode = pagemode[1:]\n        for v in valid:\n            if pagemode.lower() == v.lower():\n                self.xref_set_key(xref, \"PageMode\", f\"/{v}\")\n                return True\n        raise ValueError(\"bad PageMode value\")\n\n    def set_page_labels(doc, labels):\n        \"\"\"Add / replace page label definitions in PDF document.\n\n        Args:\n            doc: PDF document (resp. 'self').\n            labels: list of label dictionaries like:\n            {'startpage': int, 'prefix': str, 'style': str, 'firstpagenum': int},\n            as returned by get_page_labels().\n        \"\"\"\n        # William Chapman, 2021-01-06\n\n        def create_label_str(label):\n            \"\"\"Convert Python label dict to corresponding PDF rule string.\n\n            Args:\n                label: (dict) build rule for the label.\n            Returns:\n                PDF label rule string wrapped in \"<<\", \">>\".\n            \"\"\"\n            s = f\"{label['startpage']}<<\"\n            if label.get(\"prefix\", \"\") != \"\":\n                s += f\"/P({label['prefix']})\"\n            if label.get(\"style\", \"\") != \"\":\n                s += f\"/S/{label['style']}\"\n            if label.get(\"firstpagenum\", 1) > 1:\n                s += f\"/St {label['firstpagenum']}\"\n            s += \">>\"\n            return s\n\n        def create_nums(labels):\n            \"\"\"Return concatenated string of all labels rules.\n\n            Args:\n                labels: (list) dictionaries as created by function 'rule_dict'.\n            Returns:\n                PDF compatible string for page label definitions, ready to be\n                enclosed in PDF array 'Nums[...]'.\n            \"\"\"\n            labels.sort(key=lambda x: x[\"startpage\"])\n            s = \"\".join([create_label_str(label) for label in labels])\n            return s\n\n        doc._set_page_labels(create_nums(labels))\n\n    def set_toc(\n            doc: 'Document',\n            toc: list,\n            collapse: int = 1,\n            ) -> int:\n        \"\"\"Create new outline tree (table of contents, TOC).\n\n        Args:\n            toc: (list, tuple) each entry must contain level, title, page and\n                optionally top margin on the page. None or '()' remove the TOC.\n            collapse: (int) collapses entries beyond this level. Zero or None\n                shows all entries unfolded.\n        Returns:\n            the number of inserted items, or the number of removed items respectively.\n        \"\"\"\n        if doc.is_closed or doc.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        if not toc:  # remove all entries\n            return len(doc._delToC())\n\n        # validity checks --------------------------------------------------------\n        if type(toc) not in (list, tuple):\n            raise ValueError(\"'toc' must be list or tuple\")\n        toclen = len(toc)\n        page_count = doc.page_count\n        t0 = toc[0]\n        if type(t0) not in (list, tuple):\n            raise ValueError(\"items must be sequences of 3 or 4 items\")\n        if t0[0] != 1:\n            raise ValueError(\"hierarchy level of item 0 must be 1\")\n        for i in list(range(toclen - 1)):\n            t1 = toc[i]\n            t2 = toc[i + 1]\n            if not -1 <= t1[2] <= page_count:\n                raise ValueError(f\"row {i}: page number out of range\")\n            if (type(t2) not in (list, tuple)) or len(t2) not in (3, 4):\n                raise ValueError(f\"bad row {(i + 1)}\")\n            if (type(t2[0]) is not int) or t2[0] < 1:\n                raise ValueError(f\"bad hierarchy level in row {(i + 1)}\")\n            if t2[0] > t1[0] + 1:\n                raise ValueError(f\"bad hierarchy level in row {(i + 1)}\")\n        # no formal errors in toc --------------------------------------------------\n\n        # --------------------------------------------------------------------------\n        # make a list of xref numbers, which we can use for our TOC entries\n        # --------------------------------------------------------------------------\n        old_xrefs = doc._delToC()  # del old outlines, get their xref numbers\n\n        # prepare table of xrefs for new bookmarks\n        old_xrefs = []\n        xref = [0] + old_xrefs\n        xref[0] = doc._getOLRootNumber()  # entry zero is outline root xref number\n        if toclen > len(old_xrefs):  # too few old xrefs?\n            for i in range((toclen - len(old_xrefs))):\n                xref.append(doc.get_new_xref())  # acquire new ones\n\n        lvltab = {0: 0}  # to store last entry per hierarchy level\n\n        # ------------------------------------------------------------------------------\n        # contains new outline objects as strings - first one is the outline root\n        # ------------------------------------------------------------------------------\n        olitems = [{\"count\": 0, \"first\": -1, \"last\": -1, \"xref\": xref[0]}]\n        # ------------------------------------------------------------------------------\n        # build olitems as a list of PDF-like connected dictionaries\n        # ------------------------------------------------------------------------------\n        for i in range(toclen):\n            o = toc[i]\n            lvl = o[0]  # level\n            title = get_pdf_str(o[1])  # title\n            pno = min(doc.page_count - 1, max(0, o[2] - 1))  # page number\n            page_xref = doc.page_xref(pno)\n            page_height = doc.page_cropbox(pno).height\n            top = Point(72, page_height - 36)\n            dest_dict = {\"to\": top, \"kind\": LINK_GOTO}  # fall back target\n            if o[2] < 0:\n                dest_dict[\"kind\"] = LINK_NONE\n            if len(o) > 3:  # some target is specified\n                if type(o[3]) in (int, float):  # convert a number to a point\n                    dest_dict[\"to\"] = Point(72, page_height - o[3])\n                else:  # if something else, make sure we have a dict\n                    # We make a copy of o[3] to avoid modifying our caller's data.\n                    dest_dict = o[3].copy() if type(o[3]) is dict else dest_dict\n                    if \"to\" not in dest_dict:  # target point not in dict?\n                        dest_dict[\"to\"] = top  # put default in\n                    else:  # transform target to PDF coordinates\n                        page = doc[pno]\n                        point = Point(dest_dict[\"to\"])\n                        point.y = page.cropbox.height - point.y\n                        point = point * page.rotation_matrix\n                        dest_dict[\"to\"] = (point.x, point.y)\n            d = {}\n            d[\"first\"] = -1\n            d[\"count\"] = 0\n            d[\"last\"] = -1\n            d[\"prev\"] = -1\n            d[\"next\"] = -1\n            d[\"dest\"] = utils.getDestStr(page_xref, dest_dict)\n            d[\"top\"] = dest_dict[\"to\"]\n            d[\"title\"] = title\n            d[\"parent\"] = lvltab[lvl - 1]\n            d[\"xref\"] = xref[i + 1]\n            d[\"color\"] = dest_dict.get(\"color\")\n            d[\"flags\"] = dest_dict.get(\"italic\", 0) + 2 * dest_dict.get(\"bold\", 0)\n            lvltab[lvl] = i + 1\n            parent = olitems[lvltab[lvl - 1]]  # the parent entry\n\n            if (\n                dest_dict.get(\"collapse\") or collapse and lvl > collapse\n            ):  # suppress expansion\n                parent[\"count\"] -= 1  # make /Count negative\n            else:\n                parent[\"count\"] += 1  # positive /Count\n\n            if parent[\"first\"] == -1:\n                parent[\"first\"] = i + 1\n                parent[\"last\"] = i + 1\n            else:\n                d[\"prev\"] = parent[\"last\"]\n                prev = olitems[parent[\"last\"]]\n                prev[\"next\"] = i + 1\n                parent[\"last\"] = i + 1\n            olitems.append(d)\n\n        # ------------------------------------------------------------------------------\n        # now create each outline item as a string and insert it in the PDF\n        # ------------------------------------------------------------------------------\n        for i, ol in enumerate(olitems):\n            txt = \"<<\"\n            if ol[\"count\"] != 0:\n                txt += f\"/Count {ol['count']}\"\n            try:\n                txt += ol[\"dest\"]\n            except Exception:\n                # Verbose in PyMuPDF/tests.\n                if g_exceptions_verbose >= 2:   exception_info()\n                pass\n            try:\n                if ol[\"first\"] > -1:\n                    txt += f\"/First {xref[ol['first']]} 0 R\"\n            except Exception:\n                if g_exceptions_verbose >= 2:   exception_info()\n                pass\n            try:\n                if ol[\"last\"] > -1:\n                    txt += f\"/Last {xref[ol['last']]} 0 R\"\n            except Exception:\n                if g_exceptions_verbose >= 2:   exception_info()\n                pass\n            try:\n                if ol[\"next\"] > -1:\n                    txt += f\"/Next {xref[ol['next']]} 0 R\"\n            except Exception:\n                # Verbose in PyMuPDF/tests.\n                if g_exceptions_verbose >= 2:   exception_info()\n                pass\n            try:\n                if ol[\"parent\"] > -1:\n                    txt += f\"/Parent {xref[ol['parent']]} 0 R\"\n            except Exception:\n                # Verbose in PyMuPDF/tests.\n                if g_exceptions_verbose >= 2:   exception_info()\n                pass\n            try:\n                if ol[\"prev\"] > -1:\n                    txt += f\"/Prev {xref[ol['prev']]} 0 R\"\n            except Exception:\n                # Verbose in PyMuPDF/tests.\n                if g_exceptions_verbose >= 2:   exception_info()\n                pass\n            try:\n                txt += \"/Title\" + ol[\"title\"]\n            except Exception:\n                # Verbose in PyMuPDF/tests.\n                if g_exceptions_verbose >= 2:   exception_info()\n                pass\n\n            if ol.get(\"color\") and len(ol[\"color\"]) == 3:\n                txt += f\"/C[ {_format_g(tuple(ol['color']))}]\"\n            if ol.get(\"flags\", 0) > 0:\n                txt += f\"/F {ol['flags']}\"\n\n            if i == 0:  # special: this is the outline root\n                txt += \"/Type/Outlines\"  # so add the /Type entry\n            txt += \">>\"\n            doc.update_object(xref[i], txt)  # insert the PDF object\n\n        doc.init_doc()\n        return toclen\n\n    def set_toc_item(\n            doc: 'Document',\n            idx: int,\n            dest_dict: OptDict = None,\n            kind: OptInt = None,\n            pno: OptInt = None,\n            uri: OptStr = None,\n            title: OptStr = None,\n            to: point_like = None,\n            filename: OptStr = None,\n            zoom: float = 0,\n            ) -> None:\n        \"\"\"Update TOC item by index.\n\n        It allows changing the item's title and link destination.\n\n        Args:\n            idx:\n                (int) desired index of the TOC list, as created by get_toc.\n            dest_dict:\n                (dict) destination dictionary as created by get_toc(False).\n                Outrules all other parameters. If None, the remaining parameters\n                are used to make a dest dictionary.\n            kind:\n                (int) kind of link (pymupdf.LINK_GOTO, etc.). If None, then only\n                the title will be updated. If pymupdf.LINK_NONE, the TOC item will\n                be deleted.\n            pno:\n                (int) page number (1-based like in get_toc). Required if\n                pymupdf.LINK_GOTO.\n            uri:\n                (str) the URL, required if pymupdf.LINK_URI.\n            title:\n                (str) the new title. No change if None.\n            to:\n                (point-like) destination on the target page. If omitted, (72, 36)\n                will be used as target coordinates.\n            filename:\n                (str) destination filename, required for pymupdf.LINK_GOTOR and\n                pymupdf.LINK_LAUNCH.\n            name:\n                (str) a destination name for pymupdf.LINK_NAMED.\n            zoom:\n                (float) a zoom factor for the target location (pymupdf.LINK_GOTO).\n        \"\"\"\n        xref = doc.get_outline_xrefs()[idx]\n        page_xref = 0\n        if type(dest_dict) is dict:\n            if dest_dict[\"kind\"] == LINK_GOTO:\n                pno = dest_dict[\"page\"]\n                page_xref = doc.page_xref(pno)\n                page_height = doc.page_cropbox(pno).height\n                to = dest_dict.get('to', Point(72, 36))\n                to.y = page_height - to.y\n                dest_dict[\"to\"] = to\n            action = utils.getDestStr(page_xref, dest_dict)\n            if not action.startswith(\"/A\"):\n                raise ValueError(\"bad bookmark dest\")\n            color = dest_dict.get(\"color\")\n            if color:\n                color = list(map(float, color))\n                if len(color) != 3 or min(color) < 0 or max(color) > 1:\n                    raise ValueError(\"bad color value\")\n            bold = dest_dict.get(\"bold\", False)\n            italic = dest_dict.get(\"italic\", False)\n            flags = italic + 2 * bold\n            collapse = dest_dict.get(\"collapse\")\n            return doc._update_toc_item(\n                xref,\n                action=action[2:],\n                title=title,\n                color=color,\n                flags=flags,\n                collapse=collapse,\n            )\n\n        if kind == LINK_NONE:  # delete bookmark item\n            return doc.del_toc_item(idx)\n        if kind is None and title is None:  # treat as no-op\n            return None\n        if kind is None:  # only update title text\n            return doc._update_toc_item(xref, action=None, title=title)\n\n        if kind == LINK_GOTO:\n            if pno is None or pno not in range(1, doc.page_count + 1):\n                raise ValueError(\"bad page number\")\n            page_xref = doc.page_xref(pno - 1)\n            page_height = doc.page_cropbox(pno - 1).height\n            if to is None:\n                to = Point(72, page_height - 36)\n            else:\n                to = Point(to)\n                to.y = page_height - to.y\n\n        ddict = {\n            \"kind\": kind,\n            \"to\": to,\n            \"uri\": uri,\n            \"page\": pno,\n            \"file\": filename,\n            \"zoom\": zoom,\n        }\n        action = utils.getDestStr(page_xref, ddict)\n        if action == \"\" or not action.startswith(\"/A\"):\n            raise ValueError(\"bad bookmark dest\")\n\n        return doc._update_toc_item(xref, action=action[2:], title=title)\n\n    def set_xml_metadata(self, metadata):\n        \"\"\"Store XML document level metadata.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        root = mupdf.pdf_dict_get( mupdf.pdf_trailer( pdf), PDF_NAME('Root'))\n        if not root.m_internal:\n            RAISEPY( MSG_BAD_PDFROOT, JM_Exc_FileDataError)\n        res = mupdf.fz_new_buffer_from_copied_data( metadata.encode('utf-8'))\n        xml = mupdf.pdf_dict_get( root, PDF_NAME('Metadata'))\n        if xml.m_internal:\n            JM_update_stream( pdf, xml, res, 0)\n        else:\n            xml = mupdf.pdf_add_stream( pdf, res, mupdf.PdfObj(), 0)\n            mupdf.pdf_dict_put( xml, PDF_NAME('Type'), PDF_NAME('Metadata'))\n            mupdf.pdf_dict_put( xml, PDF_NAME('Subtype'), PDF_NAME('XML'))\n            mupdf.pdf_dict_put( root, PDF_NAME('Metadata'), xml)\n\n    def subset_fonts(doc: 'Document', verbose: bool = False, fallback: bool = False) -> OptInt:\n        \"\"\"Build font subsets in a PDF.\n\n        Eligible fonts are potentially replaced by smaller versions. Page text is\n        NOT rewritten and thus should retain properties like being hidden or\n        controlled by optional content.\n\n        This method by default uses MuPDF's own internal feature to create subset\n        fonts. As this is a new function, errors may still occur. In this case,\n        please fall back to using the previous version by using \"fallback=True\".\n        Fallback mode requires the external package 'fontTools'.\n\n        Args:\n            fallback: use the older deprecated implementation.\n            verbose: only used by fallback mode.\n\n        Returns:\n            The new MuPDF-based code returns None.  The deprecated fallback\n            mode returns 0 if there are no fonts to subset.  Otherwise, it\n            returns the decrease in fontsize (the difference in fontsize),\n            measured in bytes.\n        \"\"\"\n        # Font binaries: -  \"buffer\" -> (names, xrefs, (unicodes, glyphs))\n        # An embedded font is uniquely defined by its fontbuffer only. It may have\n        # multiple names and xrefs.\n        # Once the sets of used unicodes and glyphs are known, we compute a\n        # smaller version of the buffer user package fontTools.\n\n        if not fallback:  # by default use MuPDF function\n            pdf = mupdf.pdf_document_from_fz_document(doc)\n            mupdf.pdf_subset_fonts2(pdf, list(range(doc.page_count)))\n            return\n\n        font_buffers = {}\n\n        def get_old_widths(xref):\n            \"\"\"Retrieve old font '/W' and '/DW' values.\"\"\"\n            df = doc.xref_get_key(xref, \"DescendantFonts\")\n            if df[0] != \"array\":  # only handle xref specifications\n                return None, None\n            df_xref = int(df[1][1:-1].replace(\"0 R\", \"\"))\n            widths = doc.xref_get_key(df_xref, \"W\")\n            if widths[0] != \"array\":  # no widths key found\n                widths = None\n            else:\n                widths = widths[1]\n            dwidths = doc.xref_get_key(df_xref, \"DW\")\n            if dwidths[0] != \"int\":\n                dwidths = None\n            else:\n                dwidths = dwidths[1]\n            return widths, dwidths\n\n        def set_old_widths(xref, widths, dwidths):\n            \"\"\"Restore the old '/W' and '/DW' in subsetted font.\n\n            If either parameter is None or evaluates to False, the corresponding\n            dictionary key will be set to null.\n            \"\"\"\n            df = doc.xref_get_key(xref, \"DescendantFonts\")\n            if df[0] != \"array\":  # only handle xref specs\n                return None\n            df_xref = int(df[1][1:-1].replace(\"0 R\", \"\"))\n            if (type(widths) is not str or not widths) and doc.xref_get_key(df_xref, \"W\")[\n                0\n            ] != \"null\":\n                doc.xref_set_key(df_xref, \"W\", \"null\")\n            else:\n                doc.xref_set_key(df_xref, \"W\", widths)\n            if (type(dwidths) is not str or not dwidths) and doc.xref_get_key(\n                df_xref, \"DW\"\n            )[0] != \"null\":\n                doc.xref_set_key(df_xref, \"DW\", \"null\")\n            else:\n                doc.xref_set_key(df_xref, \"DW\", dwidths)\n            return None\n\n        def set_subset_fontname(new_xref):\n            \"\"\"Generate a name prefix to tag a font as subset.\n\n            We use a random generator to select 6 upper case ASCII characters.\n            The prefixed name must be put in the font xref as the \"/BaseFont\" value\n            and in the FontDescriptor object as the '/FontName' value.\n            \"\"\"\n            # The following generates a prefix like 'ABCDEF+'\n            import random\n            import string\n            prefix = \"\".join(random.choices(tuple(string.ascii_uppercase), k=6)) + \"+\"\n            font_str = doc.xref_object(new_xref, compressed=True)\n            font_str = font_str.replace(\"/BaseFont/\", \"/BaseFont/\" + prefix)\n            df = doc.xref_get_key(new_xref, \"DescendantFonts\")\n            if df[0] == \"array\":\n                df_xref = int(df[1][1:-1].replace(\"0 R\", \"\"))\n                fd = doc.xref_get_key(df_xref, \"FontDescriptor\")\n                if fd[0] == \"xref\":\n                    fd_xref = int(fd[1].replace(\"0 R\", \"\"))\n                    fd_str = doc.xref_object(fd_xref, compressed=True)\n                    fd_str = fd_str.replace(\"/FontName/\", \"/FontName/\" + prefix)\n                    doc.update_object(fd_xref, fd_str)\n            doc.update_object(new_xref, font_str)\n\n        def build_subset(buffer, unc_set, gid_set):\n            \"\"\"Build font subset using fontTools.\n\n            Args:\n                buffer: (bytes) the font given as a binary buffer.\n                unc_set: (set) required glyph ids.\n            Returns:\n                Either None if subsetting is unsuccessful or the subset font buffer.\n            \"\"\"\n            try:\n                import fontTools.subset as fts\n            except ImportError:\n                if g_exceptions_verbose:    exception_info()\n                message(\"This method requires fontTools to be installed.\")\n                raise\n            import tempfile\n            with tempfile.TemporaryDirectory() as tmp_dir:\n                oldfont_path = f\"{tmp_dir}/oldfont.ttf\"\n                newfont_path = f\"{tmp_dir}/newfont.ttf\"\n                uncfile_path = f\"{tmp_dir}/uncfile.txt\"\n                args = [\n                    oldfont_path,\n                    \"--retain-gids\",\n                    f\"--output-file={newfont_path}\",\n                    \"--layout-features=*\",\n                    \"--passthrough-tables\",\n                    \"--ignore-missing-glyphs\",\n                    \"--ignore-missing-unicodes\",\n                    \"--symbol-cmap\",\n                ]\n\n                # store glyph ids or unicodes as file\n                with io.open(f\"{tmp_dir}/uncfile.txt\", \"w\", encoding='utf8') as unc_file:\n                    if 0xFFFD in unc_set:  # error unicode exists -> use glyphs\n                        args.append(f\"--gids-file={uncfile_path}\")\n                        gid_set.add(189)\n                        unc_list = list(gid_set)\n                        for unc in unc_list:\n                            unc_file.write(f\"{unc}\\n\")\n                    else:\n                        args.append(f\"--unicodes-file={uncfile_path}\")\n                        unc_set.add(255)\n                        unc_list = list(unc_set)\n                        for unc in unc_list:\n                            unc_file.write(f\"{unc:04x}\\n\")\n\n                # store fontbuffer as a file\n                with io.open(oldfont_path, \"wb\") as fontfile:\n                    fontfile.write(buffer)\n                try:\n                    os.remove(newfont_path)  # remove old file\n                except Exception:\n                    pass\n                try:  # invoke fontTools subsetter\n                    fts.main(args)\n                    font = Font(fontfile=newfont_path)\n                    new_buffer = font.buffer  # subset font binary\n                    if font.glyph_count == 0:  # intercept empty font\n                        new_buffer = None\n                except Exception:\n                    exception_info()\n                    new_buffer = None\n            return new_buffer\n\n        def repl_fontnames(doc):\n            \"\"\"Populate 'font_buffers'.\n\n            For each font candidate, store its xref and the list of names\n            by which PDF text may refer to it (there may be multiple).\n            \"\"\"\n\n            def norm_name(name):\n                \"\"\"Recreate font name that contains PDF hex codes.\n\n                E.g. #20 -> space, chr(32)\n                \"\"\"\n                while \"#\" in name:\n                    p = name.find(\"#\")\n                    c = int(name[p + 1 : p + 3], 16)\n                    name = name.replace(name[p : p + 3], chr(c))\n                return name\n\n            def get_fontnames(doc, item):\n                \"\"\"Return a list of fontnames for an item of page.get_fonts().\n\n                There may be multiple names e.g. for Type0 fonts.\n                \"\"\"\n                fontname = item[3]\n                names = [fontname]\n                fontname = doc.xref_get_key(item[0], \"BaseFont\")[1][1:]\n                fontname = norm_name(fontname)\n                if fontname not in names:\n                    names.append(fontname)\n                descendents = doc.xref_get_key(item[0], \"DescendantFonts\")\n                if descendents[0] != \"array\":\n                    return names\n                descendents = descendents[1][1:-1]\n                if descendents.endswith(\" 0 R\"):\n                    xref = int(descendents[:-4])\n                    descendents = doc.xref_object(xref, compressed=True)\n                p1 = descendents.find(\"/BaseFont\")\n                if p1 >= 0:\n                    p2 = descendents.find(\"/\", p1 + 1)\n                    p1 = min(descendents.find(\"/\", p2 + 1), descendents.find(\">>\", p2 + 1))\n                    fontname = descendents[p2 + 1 : p1]\n                    fontname = norm_name(fontname)\n                    if fontname not in names:\n                        names.append(fontname)\n                return names\n\n            for i in range(doc.page_count):\n                for f in doc.get_page_fonts(i, full=True):\n                    font_xref = f[0]  # font xref\n                    font_ext = f[1]  # font file extension\n                    basename = f[3]  # font basename\n\n                    if font_ext not in (  # skip if not supported by fontTools\n                        \"otf\",\n                        \"ttf\",\n                        \"woff\",\n                        \"woff2\",\n                    ):\n                        continue\n                    # skip fonts which already are subsets\n                    if len(basename) > 6 and basename[6] == \"+\":\n                        continue\n\n                    extr = doc.extract_font(font_xref)\n                    fontbuffer = extr[-1]\n                    names = get_fontnames(doc, f)\n                    name_set, xref_set, subsets = font_buffers.get(\n                        fontbuffer, (set(), set(), (set(), set()))\n                    )\n                    xref_set.add(font_xref)\n                    for name in names:\n                        name_set.add(name)\n                    font = Font(fontbuffer=fontbuffer)\n                    name_set.add(font.name)\n                    del font\n                    font_buffers[fontbuffer] = (name_set, xref_set, subsets)\n\n        def find_buffer_by_name(name):\n            for buffer, (name_set, _, _) in font_buffers.items():\n                if name in name_set:\n                    return buffer\n            return None\n\n        # -----------------\n        # main function\n        # -----------------\n        repl_fontnames(doc)  # populate font information\n        if not font_buffers:  # nothing found to do\n            if verbose:\n                message(f'No fonts to subset.')\n            return 0\n\n        old_fontsize = 0\n        new_fontsize = 0\n        for fontbuffer in font_buffers.keys():\n            old_fontsize += len(fontbuffer)\n\n        # Scan page text for usage of subsettable fonts\n        for page in doc:\n            # go through the text and extend set of used glyphs by font\n            # we use a modified MuPDF trace device, which delivers us glyph ids.\n            for span in page.get_texttrace():\n                if type(span) is not dict:  # skip useless information\n                    continue\n                fontname = span[\"font\"][:33]  # fontname for the span\n                buffer = find_buffer_by_name(fontname)\n                if buffer is None:\n                    continue\n                name_set, xref_set, (set_ucs, set_gid) = font_buffers[buffer]\n                for c in span[\"chars\"]:\n                    set_ucs.add(c[0])  # unicode\n                    set_gid.add(c[1])  # glyph id\n                font_buffers[buffer] = (name_set, xref_set, (set_ucs, set_gid))\n\n        # build the font subsets\n        for old_buffer, (name_set, xref_set, subsets) in font_buffers.items():\n            new_buffer = build_subset(old_buffer, subsets[0], subsets[1])\n            fontname = list(name_set)[0]\n            if new_buffer is None or len(new_buffer) >= len(old_buffer):\n                # subset was not created or did not get smaller\n                if verbose:\n                    message(f'Cannot subset {fontname!r}.')\n                continue\n            if verbose:\n                message(f\"Built subset of font {fontname!r}.\")\n            val = doc._insert_font(fontbuffer=new_buffer)  # store subset font in PDF\n            new_xref = val[0]  # get its xref\n            set_subset_fontname(new_xref)  # tag fontname as subset font\n            font_str = doc.xref_object(  # get its object definition\n                new_xref,\n                compressed=True,\n            )\n            # walk through the original font xrefs and replace each by the subset def\n            for font_xref in xref_set:\n                # we need the original '/W' and '/DW' width values\n                width_table, def_width = get_old_widths(font_xref)\n                # ... and replace original font definition at xref with it\n                doc.update_object(font_xref, font_str)\n                # now copy over old '/W' and '/DW' values\n                if width_table or def_width:\n                    set_old_widths(font_xref, width_table, def_width)\n            # 'new_xref' remains unused in the PDF and must be removed\n            # by garbage collection.\n            new_fontsize += len(new_buffer)\n\n        return old_fontsize - new_fontsize\n\n    def switch_layer(self, config, as_default=0):\n        \"\"\"Activate an OC layer.\"\"\"\n        pdf = _as_pdf_document(self)\n        cfgs = mupdf.pdf_dict_getl(\n                mupdf.pdf_trailer( pdf),\n                PDF_NAME('Root'),\n                PDF_NAME('OCProperties'),\n                PDF_NAME('Configs')\n                )\n        if not mupdf.pdf_is_array( cfgs) or not mupdf.pdf_array_len( cfgs):\n            if config < 1:\n                return\n            raise ValueError( MSG_BAD_OC_LAYER)\n        if config < 0:\n            return\n        mupdf.pdf_select_layer_config( pdf, config)\n        if as_default:\n            mupdf.pdf_set_layer_config_as_default( pdf)\n            mupdf.ll_pdf_read_ocg( pdf.m_internal)\n\n    def update_object(self, xref, text, page=None):\n        \"\"\"Replace object definition source.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len(pdf)\n        if not _INRANGE(xref, 1, xreflen-1):\n            RAISEPY(\"bad xref\", MSG_BAD_XREF)\n        ENSURE_OPERATION(pdf)\n        # create new object with passed-in string\n        new_obj = JM_pdf_obj_from_str(pdf, text)\n        mupdf.pdf_update_object(pdf, xref, new_obj)\n        if page:\n            JM_refresh_links( _as_pdf_page(page))\n\n    def update_stream(self, xref=0, stream=None, new=1, compress=1):\n        \"\"\"Replace xref stream part.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len(pdf)\n        if xref < 1 or xref > xreflen:\n            raise ValueError( MSG_BAD_XREF)\n        # get the object\n        obj = mupdf.pdf_new_indirect(pdf, xref, 0)\n        if not mupdf.pdf_is_dict(obj):\n            raise ValueError( MSG_IS_NO_DICT)\n        res = JM_BufferFromBytes(stream)\n        if not res.m_internal:\n            raise TypeError( MSG_BAD_BUFFER)\n        JM_update_stream(pdf, obj, res, compress)\n        pdf.dirty = 1\n\n    @property\n    def version_count(self):\n        '''\n        Count versions of PDF document.\n        '''\n        pdf = _as_pdf_document(self, required=0)\n        if pdf.m_internal:\n            return mupdf.pdf_count_versions(pdf)\n        return 0\n\n    def write(\n            self,\n            garbage=False,\n            clean=False,\n            deflate=False,\n            deflate_images=False,\n            deflate_fonts=False,\n            incremental=False,\n            ascii=False,\n            expand=False,\n            linear=False,\n            no_new_id=False,\n            appearance=False,\n            pretty=False,\n            encryption=1,\n            permissions=4095,\n            owner_pw=None,\n            user_pw=None,\n            preserve_metadata=1,\n            use_objstms=0,\n            compression_effort=0,\n            raise_on_repair=False,\n    ):\n        from io import BytesIO\n        bio = BytesIO()\n        self.save(\n                bio,\n                garbage=garbage,\n                clean=clean,\n                no_new_id=no_new_id,\n                appearance=appearance,\n                deflate=deflate,\n                deflate_images=deflate_images,\n                deflate_fonts=deflate_fonts,\n                incremental=incremental,\n                ascii=ascii,\n                expand=expand,\n                linear=linear,\n                pretty=pretty,\n                encryption=encryption,\n                permissions=permissions,\n                owner_pw=owner_pw,\n                user_pw=user_pw,\n                preserve_metadata=preserve_metadata,\n                use_objstms=use_objstms,\n                compression_effort=compression_effort,\n                raise_on_repair=raise_on_repair,\n        )\n        return bio.getvalue()\n    \n    def tobytes(self, *args, **kwargs):\n        return self.write(*args, **kwargs)\n\n    @property\n    def xref(self):\n        \"\"\"PDF xref number of page.\"\"\"\n        CheckParent(self)\n        return self.parent.page_xref(self.number)\n\n    def xref_copy(doc: 'Document', source: int, target: int, *, keep: list = None) -> None:\n        \"\"\"Copy a PDF dictionary object to another one given their xref numbers.\n\n        Args:\n            doc: PDF document object\n            source: source xref number\n            target: target xref number, the xref must already exist\n            keep: an optional list of 1st level keys in target that should not be\n                  removed before copying.\n        Notes:\n            This works similar to the copy() method of dictionaries in Python. The\n            source may be a stream object.\n        \"\"\"\n        if doc.xref_is_stream(source):\n            # read new xref stream, maintaining compression\n            stream = doc.xref_stream_raw(source)\n            doc.update_stream(\n                target,\n                stream,\n                compress=False,  # keeps source compression\n                new=True,  # in case target is no stream\n            )\n\n        # empty the target completely, observe exceptions\n        if keep is None:\n            keep = []\n        for key in doc.xref_get_keys(target):\n            if key in keep:\n                continue\n            doc.xref_set_key(target, key, \"null\")\n        # copy over all source dict items\n        for key in doc.xref_get_keys(source):\n            item = doc.xref_get_key(source, key)\n            doc.xref_set_key(target, key, item[1])\n    \n    def xref_get_key(self, xref, key):\n        \"\"\"Get PDF dict key value of object at 'xref'.\"\"\"\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len(pdf)\n        if not _INRANGE(xref, 1, xreflen-1) and xref != -1:\n            raise ValueError( MSG_BAD_XREF)\n        if xref > 0:\n            obj = mupdf.pdf_load_object(pdf, xref)\n        else:\n            obj = mupdf.pdf_trailer(pdf)\n        if not obj.m_internal:\n            return (\"null\", \"null\")\n        subobj = mupdf.pdf_dict_getp(obj, key)\n        if not subobj.m_internal:\n            return (\"null\", \"null\")\n        text = None\n        if mupdf.pdf_is_indirect(subobj):\n            type = \"xref\"\n            text = f\"{mupdf.pdf_to_num(subobj):d} 0 R\"\n        elif mupdf.pdf_is_array(subobj):\n            type = \"array\"\n        elif mupdf.pdf_is_dict(subobj):\n            type = \"dict\"\n        elif mupdf.pdf_is_int(subobj):\n            type = \"int\"\n            text = f\"{mupdf.pdf_to_int(subobj):d}\"\n        elif mupdf.pdf_is_real(subobj):\n            type = \"float\"\n        elif mupdf.pdf_is_null(subobj):\n            type = \"null\"\n            text = \"null\"\n        elif mupdf.pdf_is_bool(subobj):\n            type = \"bool\"\n            if mupdf.pdf_to_bool(subobj):\n                text = \"true\"\n            else:\n                text = \"false\"\n        elif mupdf.pdf_is_name(subobj):\n            type = \"name\"\n            text = f\"/{mupdf.pdf_to_name(subobj)}\"\n        elif mupdf.pdf_is_string(subobj):\n            type = \"string\"\n            text = JM_UnicodeFromStr(mupdf.pdf_to_text_string(subobj))\n        else:\n            type = \"unknown\"\n        if text is None:\n            res = JM_object_to_buffer(subobj, 1, 0)\n            text = JM_UnicodeFromBuffer(res)\n        return (type, text)\n\n    def xref_get_keys(self, xref):\n        \"\"\"Get the keys of PDF dict object at 'xref'. Use -1 for the PDF trailer.\"\"\"\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len( pdf)\n        if not _INRANGE(xref, 1, xreflen-1) and xref != -1:\n            raise ValueError( MSG_BAD_XREF)\n        if xref > 0:\n            obj = mupdf.pdf_load_object( pdf, xref)\n        else:\n            obj = mupdf.pdf_trailer( pdf)\n        n = mupdf.pdf_dict_len( obj)\n        rc = []\n        if n == 0:\n            return rc\n        for i in range(n):\n            key = mupdf.pdf_to_name( mupdf.pdf_dict_get_key( obj, i))\n            rc.append(key)\n        return rc\n\n    def xref_is_font(self, xref):\n        \"\"\"Check if xref is a font object.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if self.xref_get_key(xref, \"Type\")[1] == \"/Font\":\n            return True\n        return False\n\n    def xref_is_image(self, xref):\n        \"\"\"Check if xref is an image object.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if self.xref_get_key(xref, \"Subtype\")[1] == \"/Image\":\n            return True\n        return False\n\n    def xref_is_stream(self, xref=0):\n        \"\"\"Check if xref is a stream object.\"\"\"\n        pdf = _as_pdf_document(self, required=0)\n        if not pdf.m_internal:\n            return False    # not a PDF\n        return bool(mupdf.pdf_obj_num_is_stream(pdf, xref))\n\n    def xref_is_xobject(self, xref):\n        \"\"\"Check if xref is a form xobject.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if self.xref_get_key(xref, \"Subtype\")[1] == \"/Form\":\n            return True\n        return False\n\n    def xref_length(self):\n        \"\"\"Get length of xref table.\"\"\"\n        xreflen = 0\n        pdf = _as_pdf_document(self, required=0)\n        if pdf.m_internal:\n            xreflen = mupdf.pdf_xref_len(pdf)\n        return xreflen\n\n    def xref_object(self, xref, compressed=0, ascii=0):\n        \"\"\"Get xref object source as a string.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n        if g_use_extra:\n            ret = extra.xref_object( self.this, xref, compressed, ascii)\n            return ret\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len(pdf)\n        if not _INRANGE(xref, 1, xreflen-1) and xref != -1:\n            raise ValueError( MSG_BAD_XREF)\n        if xref > 0:\n            obj = mupdf.pdf_load_object(pdf, xref)\n        else:\n            obj = mupdf.pdf_trailer(pdf)\n        res = JM_object_to_buffer(mupdf.pdf_resolve_indirect(obj), compressed, ascii)\n        text = JM_EscapeStrFromBuffer(res)\n        return text\n\n    def xref_set_key(self, xref, key, value):\n        \"\"\"Set the value of a PDF dictionary key.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"document closed\")\n\n        if not key or not isinstance(key, str) or INVALID_NAME_CHARS.intersection(key) not in (set(), {\"/\"}):\n            raise ValueError(\"bad 'key'\")\n        if not isinstance(value, str) or not value or value[0] == \"/\" and INVALID_NAME_CHARS.intersection(value[1:]) != set():\n            raise ValueError(\"bad 'value'\")\n\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len(pdf)\n        #if not _INRANGE(xref, 1, xreflen-1) and xref != -1:\n        #    THROWMSG(\"bad xref\")\n        #if len(value) == 0:\n        #    THROWMSG(\"bad 'value'\")\n        #if len(key) == 0:\n        #    THROWMSG(\"bad 'key'\")\n        if not _INRANGE(xref, 1, xreflen-1) and xref != -1:\n            raise ValueError( MSG_BAD_XREF)\n        if xref != -1:\n            obj = mupdf.pdf_load_object(pdf, xref)\n        else:\n            obj = mupdf.pdf_trailer(pdf)\n        new_obj = JM_set_object_value(obj, key, value)\n        if not new_obj.m_internal:\n            return  # did not work: skip update\n        if xref != -1:\n            mupdf.pdf_update_object(pdf, xref, new_obj)\n        else:\n            n = mupdf.pdf_dict_len(new_obj)\n            for i in range(n):\n                mupdf.pdf_dict_put(\n                        obj,\n                        mupdf.pdf_dict_get_key(new_obj, i),\n                        mupdf.pdf_dict_get_val(new_obj, i),\n                        )\n\n    def xref_stream(self, xref):\n        \"\"\"Get decompressed xref stream.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len( pdf)\n        if not _INRANGE(xref, 1, xreflen-1) and xref != -1:\n            raise ValueError( MSG_BAD_XREF)\n        if xref >= 0:\n            obj = mupdf.pdf_new_indirect( pdf, xref, 0)\n        else:\n            obj = mupdf.pdf_trailer( pdf)\n        r = None\n        if mupdf.pdf_is_stream( obj):\n            res = mupdf.pdf_load_stream_number( pdf, xref)\n            r = JM_BinFromBuffer( res)\n        return r\n\n    def xref_stream_raw(self, xref):\n        \"\"\"Get xref stream without decompression.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        pdf = _as_pdf_document(self)\n        xreflen = mupdf.pdf_xref_len( pdf)\n        if not _INRANGE(xref, 1, xreflen-1) and xref != -1:\n            raise ValueError( MSG_BAD_XREF)\n        if xref >= 0:\n            obj = mupdf.pdf_new_indirect( pdf, xref, 0)\n        else:\n            obj = mupdf.pdf_trailer( pdf)\n        r = None\n        if mupdf.pdf_is_stream( obj):\n            res = mupdf.pdf_load_raw_stream_number( pdf, xref)\n            r = JM_BinFromBuffer( res)\n        return r\n\n    def xref_xml_metadata(self):\n        \"\"\"Get xref of document XML metadata.\"\"\"\n        pdf = _as_pdf_document(self)\n        root = mupdf.pdf_dict_get( mupdf.pdf_trailer( pdf), PDF_NAME('Root'))\n        if not root.m_internal:\n            RAISEPY( MSG_BAD_PDFROOT, JM_Exc_FileDataError)\n        xml = mupdf.pdf_dict_get( root, PDF_NAME('Metadata'))\n        xref = 0\n        if xml.m_internal:\n            xref = mupdf.pdf_to_num( xml)\n        return xref\n    \n    __slots__ = ('this', 'page_count2', 'this_is_pdf', '__dict__')\n    \n    outline = property(lambda self: self._outline)\n    is_stream = xref_is_stream\n\nopen = Document\n\n\nclass DocumentWriter:\n\n    def __enter__(self):\n        return self\n\n    def __exit__(self, *args):\n        self.close()\n\n    def __init__(self, path, options=''):\n        if isinstance( path, str):\n            pass\n        elif hasattr( path, 'absolute'):\n            path = str( path)\n        elif hasattr( path, 'name'):\n            path = path.name\n        if isinstance( path, str):\n            self.this = mupdf.FzDocumentWriter( path, options, mupdf.FzDocumentWriter.PathType_PDF)\n        else:\n            # Need to keep the Python JM_new_output_fileptr_Output instance\n            # alive for the lifetime of this DocumentWriter, otherwise calls\n            # to virtual methods implemented in Python fail. So we make it a\n            # member of this DocumentWriter.\n            #\n            # Unrelated to this, mupdf.FzDocumentWriter will set\n            # self._out.m_internal to null because ownership is passed in.\n            #\n            out = JM_new_output_fileptr( path)\n            self.this = mupdf.FzDocumentWriter( out, options, mupdf.FzDocumentWriter.OutputType_PDF)\n            assert out.m_internal_value() == 0\n            assert hasattr( self.this, '_out')\n    \n    def begin_page( self, mediabox):\n        mediabox2 = JM_rect_from_py(mediabox)\n        device = mupdf.fz_begin_page( self.this, mediabox2)\n        device_wrapper = DeviceWrapper( device)\n        return device_wrapper\n    \n    def close( self):\n        mupdf.fz_close_document_writer( self.this)\n        \n    def end_page( self):\n        mupdf.fz_end_page( self.this)\n\n\nclass Font:\n\n    def __del__(self):\n        if type(self) is not Font:\n            return None\n\n    def __init__(\n            self,\n            fontname=None,\n            fontfile=None,\n            fontbuffer=None,\n            script=0,\n            language=None,\n            ordering=-1,\n            is_bold=0,\n            is_italic=0,\n            is_serif=0,\n            embed=1,\n            ):\n        \n        if fontbuffer:\n            if hasattr(fontbuffer, \"getvalue\"):\n                fontbuffer = fontbuffer.getvalue()\n            elif isinstance(fontbuffer, bytearray):\n                fontbuffer = bytes(fontbuffer)\n            if not isinstance(fontbuffer, bytes):\n                raise ValueError(\"bad type: 'fontbuffer'\")\n        \n        if isinstance(fontname, str):\n            fname_lower = fontname.lower()\n            if \"/\" in fname_lower or \"\\\\\" in fname_lower or \".\" in fname_lower:\n                message(\"Warning: did you mean a fontfile?\")\n\n            if fname_lower in (\"cjk\", \"china-t\", \"china-ts\"):\n                ordering = 0\n\n            elif fname_lower.startswith(\"china-s\"):\n                ordering = 1\n            elif fname_lower.startswith(\"korea\"):\n                ordering = 3\n            elif fname_lower.startswith(\"japan\"):\n                ordering = 2\n            elif fname_lower in fitz_fontdescriptors.keys():\n                import pymupdf_fonts  # optional fonts\n                fontbuffer = pymupdf_fonts.myfont(fname_lower)  # make a copy\n                fontname = None  # ensure using fontbuffer only\n                del pymupdf_fonts  # remove package again\n\n            elif ordering < 0:\n                fontname = Base14_fontdict.get(fontname, fontname)\n\n        lang = mupdf.fz_text_language_from_string(language)\n        font = JM_get_font(fontname, fontfile,\n                   fontbuffer, script, lang, ordering,\n                   is_bold, is_italic, is_serif, embed)\n        self.this = font\n\n    def __repr__(self):\n        return f\"Font('{self.name}')\"\n\n    @property\n    def ascender(self):\n        \"\"\"Return the glyph ascender value.\"\"\"\n        return mupdf.fz_font_ascender(self.this)\n\n    @property\n    def bbox(self):\n        return self.this.fz_font_bbox()\n    \n    @property\n    def buffer(self):\n        buffer_ = mupdf.FzBuffer( mupdf.ll_fz_keep_buffer( self.this.m_internal.buffer))\n        return mupdf.fz_buffer_extract_copy( buffer_)\n\n    def char_lengths(self, text, fontsize=11, language=None, script=0, wmode=0, small_caps=0):\n        \"\"\"Return tuple of char lengths of unicode 'text' under a fontsize.\"\"\"\n        lang = mupdf.fz_text_language_from_string(language)\n        rc = []\n        for ch in text:\n            c = ord(ch)\n            if small_caps:\n                gid = mupdf.fz_encode_character_sc(self.this, c)\n                if gid >= 0:\n                    font = self.this\n            else:\n                gid, font = mupdf.fz_encode_character_with_fallback(self.this, c, script, lang)\n            rc.append(fontsize * mupdf.fz_advance_glyph(font, gid, wmode))\n        return rc\n\n    @property\n    def descender(self):\n        \"\"\"Return the glyph descender value.\"\"\"\n        return mupdf.fz_font_descender(self.this)\n\n    @property\n    def flags(self):\n        f = mupdf.ll_fz_font_flags(self.this.m_internal)\n        if not f:\n            return\n        assert isinstance( f, mupdf.fz_font_flags_t)\n        #log(f'{f=}')\n        if mupdf_cppyy:\n            # cppyy includes remaining higher bits.\n            v = [f.is_mono]\n            def b(bits):\n                ret = v[0] & ((1 << bits)-1)\n                v[0] = v[0] >> bits\n                return ret\n            is_mono = b(1)\n            is_serif = b(1)\n            is_bold = b(1)\n            is_italic = b(1)\n            ft_substitute = b(1)\n            ft_stretch = b(1)\n            fake_bold = b(1)\n            fake_italic = b(1)\n            has_opentype = b(1)\n            invalid_bbox = b(1)\n            cjk_lang = b(1)\n            embed = b(1)\n            never_embed = b(1)\n        return {\n                \"mono\":         is_mono if mupdf_cppyy else f.is_mono,\n                \"serif\":        is_serif if mupdf_cppyy else f.is_serif,\n                \"bold\":         is_bold if mupdf_cppyy else f.is_bold,\n                \"italic\":       is_italic if mupdf_cppyy else f.is_italic,\n                \"substitute\":   ft_substitute if mupdf_cppyy else f.ft_substitute,\n                \"stretch\":      ft_stretch if mupdf_cppyy else f.ft_stretch,\n                \"fake-bold\":    fake_bold if mupdf_cppyy else f.fake_bold,\n                \"fake-italic\":  fake_italic if mupdf_cppyy else f.fake_italic,\n                \"opentype\":     has_opentype if mupdf_cppyy else f.has_opentype,\n                \"invalid-bbox\": invalid_bbox if mupdf_cppyy else f.invalid_bbox,\n                'cjk':          cjk_lang if mupdf_cppyy else f.cjk,\n                'cjk-lang':     cjk_lang if mupdf_cppyy else f.cjk_lang,\n                'embed':        embed if mupdf_cppyy else f.embed,\n                'never-embed':  never_embed if mupdf_cppyy else f.never_embed,\n                }\n\n    def glyph_advance(self, chr_, language=None, script=0, wmode=0, small_caps=0):\n        \"\"\"Return the glyph width of a unicode (font size 1).\"\"\"\n        lang = mupdf.fz_text_language_from_string(language)\n        if small_caps:\n            gid = mupdf.fz_encode_character_sc(self.this, chr_)\n            if gid >= 0:\n                font = self.this\n        else:\n            gid, font = mupdf.fz_encode_character_with_fallback(self.this, chr_, script, lang)\n        return mupdf.fz_advance_glyph(font, gid, wmode)\n\n    def glyph_bbox(self, char, language=None, script=0, small_caps=0):\n        \"\"\"Return the glyph bbox of a unicode (font size 1).\"\"\"\n        lang = mupdf.fz_text_language_from_string(language)\n        if small_caps:\n            gid = mupdf.fz_encode_character_sc( self.this, char)\n            if gid >= 0:\n                font = self.this\n        else:\n            gid, font = mupdf.fz_encode_character_with_fallback( self.this, char, script, lang)\n        return Rect(mupdf.fz_bound_glyph( font, gid, mupdf.FzMatrix()))\n\n    @property\n    def glyph_count(self):\n        return self.this.m_internal.glyph_count\n\n    def glyph_name_to_unicode(self, name):\n        \"\"\"Return the unicode for a glyph name.\"\"\"\n        return glyph_name_to_unicode(name)\n\n    def has_glyph(self, chr, language=None, script=0, fallback=0, small_caps=0):\n        \"\"\"Check whether font has a glyph for this unicode.\"\"\"\n        if fallback:\n            lang = mupdf.fz_text_language_from_string(language)\n            gid, font = mupdf.fz_encode_character_with_fallback(self.this, chr, script, lang)\n        else:\n            if small_caps:\n                gid = mupdf.fz_encode_character_sc(self.this, chr)\n            else:\n                gid = mupdf.fz_encode_character(self.this, chr)\n        return gid\n\n    @property\n    def is_bold(self):\n        return mupdf.fz_font_is_bold( self.this)\n\n    @property\n    def is_italic(self):\n        return mupdf.fz_font_is_italic( self.this)\n\n    @property\n    def is_monospaced(self):\n        return mupdf.fz_font_is_monospaced( self.this)\n\n    @property\n    def is_serif(self):\n        return mupdf.fz_font_is_serif( self.this)\n\n    @property\n    def is_writable(self):\n        return True # see pymupdf commit ef4056ee4da2\n        font = self.this\n        flags = mupdf.ll_fz_font_flags(font.m_internal)\n        if mupdf_cppyy:\n            # cppyy doesn't handle bitfields correctly.\n            import cppyy\n            ft_substitute = cppyy.gbl.mupdf_mfz_font_flags_ft_substitute( flags)\n        else:\n            ft_substitute = flags.ft_substitute\n        \n        if ( mupdf.ll_fz_font_t3_procs(font.m_internal)\n                or ft_substitute\n                or not mupdf.pdf_font_writing_supported(font)\n                ):\n            return False\n        return True\n\n    @property\n    def name(self):\n        ret = mupdf.fz_font_name(self.this)\n        #log(f'{ret=}')\n        return ret\n\n    def text_length(self, text, fontsize=11, language=None, script=0, wmode=0, small_caps=0):\n        \"\"\"Return length of unicode 'text' under a fontsize.\"\"\"\n        thisfont = self.this\n        lang = mupdf.fz_text_language_from_string(language)\n        rc = 0\n        if not isinstance(text, str):\n            raise TypeError( MSG_BAD_TEXT)\n        for ch in text:\n            c = ord(ch)\n            if small_caps:\n                gid = mupdf.fz_encode_character_sc(thisfont, c)\n                if gid >= 0:\n                    font = thisfont\n            else:\n                gid, font = mupdf.fz_encode_character_with_fallback(thisfont, c, script, lang)\n            rc += mupdf.fz_advance_glyph(font, gid, wmode)\n        rc *= fontsize\n        return rc\n\n    def unicode_to_glyph_name(self, ch):\n        \"\"\"Return the glyph name for a unicode.\"\"\"\n        return unicode_to_glyph_name(ch)\n\n    def valid_codepoints(self):\n        '''\n        Returns sorted list of valid unicodes of a fz_font.\n        '''\n        ucs_gids = mupdf.fz_enumerate_font_cmap2(self.this)\n        ucss = [i.ucs for i in ucs_gids]\n        ucss_unique = set(ucss)\n        ucss_unique_sorted = sorted(ucss_unique)\n        return ucss_unique_sorted\n\n\nclass Graftmap:\n\n    def __del__(self):\n        if not type(self) is Graftmap:\n            return\n        self.thisown = False\n\n    def __init__(self, doc):\n        dst = _as_pdf_document(doc)\n        map_ = mupdf.pdf_new_graft_map(dst)\n        self.this = map_\n        self.thisown = True\n\n\nclass Link:\n    def __del__(self):\n        self._erase()\n\n    def __init__( self, this):\n        assert isinstance( this, mupdf.FzLink)\n        self.this = this\n\n    def __repr__(self):\n        CheckParent(self)\n        return \"link on \" + str(self.parent)\n\n    def __str__(self):\n        CheckParent(self)\n        return \"link on \" + str(self.parent)\n\n    def _border(self, doc, xref):\n        pdf = _as_pdf_document(doc, required=0)\n        if not pdf.m_internal:\n            return\n        link_obj = mupdf.pdf_new_indirect(pdf, xref, 0)\n        if not link_obj.m_internal:\n            return\n        b = JM_annot_border(link_obj)\n        return b\n\n    def _colors(self, doc, xref):\n        pdf = _as_pdf_document(doc, required=0)\n        if not pdf.m_internal:\n            return\n        link_obj = mupdf.pdf_new_indirect( pdf, xref, 0)\n        if not link_obj.m_internal:\n            raise ValueError( MSG_BAD_XREF)\n        b = JM_annot_colors( link_obj)\n        return b\n\n    def _erase(self):\n        self.parent = None\n        self.thisown = False\n\n    def _setBorder(self, border, doc, xref):\n        pdf = _as_pdf_document(doc, required=0)\n        if not pdf.m_internal:\n            return\n        link_obj = mupdf.pdf_new_indirect(pdf, xref, 0)\n        if not link_obj.m_internal:\n            return\n        b = JM_annot_set_border(border, pdf, link_obj)\n        return b\n        \n    @property\n    def border(self):\n        return self._border(self.parent.parent.this, self.xref)\n\n    @property\n    def colors(self):\n        return self._colors(self.parent.parent.this, self.xref)\n\n    @property\n    def dest(self):\n        \"\"\"Create link destination details.\"\"\"\n        if hasattr(self, \"parent\") and self.parent is None:\n            raise ValueError(\"orphaned object: parent is None\")\n        if self.parent.parent.is_closed or self.parent.parent.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        doc = self.parent.parent\n\n        if self.is_external or self.uri.startswith(\"#\"):\n            uri = None\n        else:\n            uri = doc.resolve_link(self.uri)\n\n        return linkDest(self, uri, doc)\n\n    @property\n    def flags(self)->int:\n        CheckParent(self)\n        doc = self.parent.parent\n        if not doc.is_pdf:\n            return 0\n        f = doc.xref_get_key(self.xref, \"F\")\n        if f[1] != \"null\":\n            return int(f[1])\n        return 0\n\n    @property\n    def is_external(self):\n        \"\"\"Flag the link as external.\"\"\"\n        CheckParent(self)\n        if g_use_extra:\n            return extra.Link_is_external( self.this)\n        this_link = self.this\n        if not this_link.m_internal or not this_link.m_internal.uri:\n            return False\n        return bool( mupdf.fz_is_external_link( this_link.m_internal.uri))\n\n    @property\n    def next(self):\n        \"\"\"Next link.\"\"\"\n        if not self.this.m_internal:\n            return None\n        CheckParent(self)\n        if 0 and g_use_extra:\n            val = extra.Link_next( self.this)\n        else:\n            val = self.this.next()\n        if not val.m_internal:\n            return None\n        val = Link( val)\n        if val:\n            val.thisown = True\n            val.parent = self.parent  # copy owning page from prev link\n            val.parent._annot_refs[id(val)] = val\n            if self.xref > 0:  # prev link has an xref\n                link_xrefs = [x[0] for x in self.parent.annot_xrefs() if x[1] == mupdf.PDF_ANNOT_LINK]\n                link_ids = [x[2] for x in self.parent.annot_xrefs() if x[1] == mupdf.PDF_ANNOT_LINK]\n                idx = link_xrefs.index(self.xref)\n                val.xref = link_xrefs[idx + 1]\n                val.id = link_ids[idx + 1]\n            else:\n                val.xref = 0\n                val.id = \"\"\n        return val\n\n    @property\n    def rect(self):\n        \"\"\"Rectangle ('hot area').\"\"\"\n        CheckParent(self)\n        # utils.py:getLinkDict() appears to expect exceptions from us, so we\n        # ensure that we raise on error.\n        if self.this is None or not self.this.m_internal:\n            raise Exception( 'self.this.m_internal not available')\n        val = JM_py_from_rect( self.this.rect())\n        val = Rect(val)\n        return val\n\n    def set_border(self, border=None, width=0, dashes=None, style=None):\n        if type(border) is not dict:\n            border = {\"width\": width, \"style\": style, \"dashes\": dashes}\n        return self._setBorder(border, self.parent.parent.this, self.xref)\n\n    def set_colors(self, colors=None, stroke=None, fill=None):\n        \"\"\"Set border colors.\"\"\"\n        CheckParent(self)\n        doc = self.parent.parent\n        if type(colors) is not dict:\n            colors = {\"fill\": fill, \"stroke\": stroke}\n        fill = colors.get(\"fill\")\n        stroke = colors.get(\"stroke\")\n        if fill is not None:\n            message(\"warning: links have no fill color\")\n        if stroke in ([], ()):\n            doc.xref_set_key(self.xref, \"C\", \"[]\")\n            return\n        if hasattr(stroke, \"__float__\"):\n            stroke = [float(stroke)]\n        CheckColor(stroke)\n        assert len(stroke) in (1, 3, 4)\n        s = f\"[{_format_g(stroke)}]\"\n        doc.xref_set_key(self.xref, \"C\", s)\n\n    def set_flags(self, flags):\n        CheckParent(self)\n        doc = self.parent.parent\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        if not type(flags) is int:\n            raise ValueError(\"bad 'flags' value\")\n        doc.xref_set_key(self.xref, \"F\", str(flags))\n        return None\n\n    @property\n    def uri(self):\n        \"\"\"Uri string.\"\"\"\n        #CheckParent(self)\n        if g_use_extra:\n            return extra.link_uri(self.this)\n        this_link = self.this\n        return this_link.m_internal.uri if this_link.m_internal else ''\n\n    page = -1\n\n\nclass Matrix:\n\n    def __abs__(self):\n        return math.sqrt(sum([c*c for c in self]))\n\n    def __add__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a + m, self.b + m, self.c + m,\n                          self.d + m, self.e + m, self.f + m)\n        if len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        return Matrix(self.a + m[0], self.b + m[1], self.c + m[2],\n                          self.d + m[3], self.e + m[4], self.f + m[5])\n\n    def __bool__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __eq__(self, mat):\n        if not hasattr(mat, \"__len__\"):\n            return False\n        return len(mat) == 6 and not (self - mat)\n\n    def __getitem__(self, i):\n        return (self.a, self.b, self.c, self.d, self.e, self.f)[i]\n\n    def __init__(self, *args, a=None, b=None, c=None, d=None, e=None, f=None):\n        \"\"\"\n        Matrix() - all zeros\n        Matrix(a, b, c, d, e, f)\n        Matrix(zoom-x, zoom-y) - zoom\n        Matrix(shear-x, shear-y, 1) - shear\n        Matrix(degree) - rotate\n        Matrix(Matrix) - new copy\n        Matrix(sequence) - from 'sequence'\n        Matrix(mupdf.FzMatrix) - from MuPDF class wrapper for fz_matrix.\n        \n        Explicit keyword args a, b, c, d, e, f override any earlier settings if\n        not None.\n        \"\"\"\n        if not args:\n            self.a = self.b = self.c = self.d = self.e = self.f = 0.0\n        elif len(args) > 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        elif len(args) == 6:  # 6 numbers\n            self.a, self.b, self.c, self.d, self.e, self.f = map(float, args)\n        elif len(args) == 1:  # either an angle or a sequ\n            if isinstance(args[0], mupdf.FzMatrix):\n                self.a = args[0].a\n                self.b = args[0].b\n                self.c = args[0].c\n                self.d = args[0].d\n                self.e = args[0].e\n                self.f = args[0].f\n            elif hasattr(args[0], \"__float__\"):\n                theta = math.radians(args[0])\n                c_ = round(math.cos(theta), 8)\n                s_ = round(math.sin(theta), 8)\n                self.a = self.d = c_\n                self.b = s_\n                self.c = -s_\n                self.e = self.f = 0.0\n            else:\n                self.a, self.b, self.c, self.d, self.e, self.f = map(float, args[0])\n        elif len(args) == 2 or len(args) == 3 and args[2] == 0:\n            self.a, self.b, self.c, self.d, self.e, self.f = float(args[0]), \\\n                0.0, 0.0, float(args[1]), 0.0, 0.0\n        elif len(args) == 3 and args[2] == 1:\n            self.a, self.b, self.c, self.d, self.e, self.f = 1.0, \\\n                float(args[1]), float(args[0]), 1.0, 0.0, 0.0\n        else:\n            raise ValueError(\"Matrix: bad args\")\n        \n        # Override with explicit args if specified.\n        if a is not None:   self.a = a\n        if b is not None:   self.b = b\n        if c is not None:   self.c = c\n        if d is not None:   self.d = d\n        if e is not None:   self.e = e\n        if f is not None:   self.f = f\n\n    def __invert__(self):\n        \"\"\"Calculate inverted matrix.\"\"\"\n        m1 = Matrix()\n        m1.invert(self)\n        return m1\n\n    def __len__(self):\n        return 6\n\n    def __mul__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a * m, self.b * m, self.c * m,\n                          self.d * m, self.e * m, self.f * m)\n        m1 = Matrix(1,1)\n        return m1.concat(self, m)\n\n    def __neg__(self):\n        return Matrix(-self.a, -self.b, -self.c, -self.d, -self.e, -self.f)\n\n    def __nonzero__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __pos__(self):\n        return Matrix(self)\n\n    def __repr__(self):\n        return \"Matrix\" + str(tuple(self))\n\n    def __setitem__(self, i, v):\n        v = float(v)\n        if   i == 0: self.a = v\n        elif i == 1: self.b = v\n        elif i == 2: self.c = v\n        elif i == 3: self.d = v\n        elif i == 4: self.e = v\n        elif i == 5: self.f = v\n        else:\n            raise IndexError(\"index out of range\")\n        return\n\n    def __sub__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a - m, self.b - m, self.c - m,\n                          self.d - m, self.e - m, self.f - m)\n        if len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        return Matrix(self.a - m[0], self.b - m[1], self.c - m[2],\n                          self.d - m[3], self.e - m[4], self.f - m[5])\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a * 1./m, self.b * 1./m, self.c * 1./m,\n                          self.d * 1./m, self.e * 1./m, self.f * 1./m)\n        m1 = util_invert_matrix(m)[1]\n        if not m1:\n            raise ZeroDivisionError(\"matrix not invertible\")\n        m2 = Matrix(1,1)\n        return m2.concat(self, m1)\n\n    def concat(self, one, two):\n        \"\"\"Multiply two matrices and replace current one.\"\"\"\n        if not len(one) == len(two) == 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.a, self.b, self.c, self.d, self.e, self.f = util_concat_matrix(one, two)\n        return self\n\n    def invert(self, src=None):\n        \"\"\"Calculate the inverted matrix. Return 0 if successful and replace\n        current one. Else return 1 and do nothing.\n        \"\"\"\n        if src is None:\n            dst = util_invert_matrix(self)\n        else:\n            dst = util_invert_matrix(src)\n        if dst[0] == 1:\n            return 1\n        self.a, self.b, self.c, self.d, self.e, self.f = dst[1]\n        return 0\n\n    @property\n    def is_rectilinear(self):\n        \"\"\"True if rectangles are mapped to rectangles.\"\"\"\n        return (abs(self.b) < EPSILON and abs(self.c) < EPSILON) or \\\n            (abs(self.a) < EPSILON and abs(self.d) < EPSILON)\n\n    def prerotate(self, theta):\n        \"\"\"Calculate pre rotation and replace current matrix.\"\"\"\n        theta = float(theta)\n        while theta < 0: theta += 360\n        while theta >= 360: theta -= 360\n        if abs(0 - theta) < EPSILON:\n            pass\n\n        elif abs(90.0 - theta) < EPSILON:\n            a = self.a\n            b = self.b\n            self.a = self.c\n            self.b = self.d\n            self.c = -a\n            self.d = -b\n\n        elif abs(180.0 - theta) < EPSILON:\n            self.a = -self.a\n            self.b = -self.b\n            self.c = -self.c\n            self.d = -self.d\n\n        elif abs(270.0 - theta) < EPSILON:\n            a = self.a\n            b = self.b\n            self.a = -self.c\n            self.b = -self.d\n            self.c = a\n            self.d = b\n\n        else:\n            rad = math.radians(theta)\n            s = math.sin(rad)\n            c = math.cos(rad)\n            a = self.a\n            b = self.b\n            self.a = c * a + s * self.c\n            self.b = c * b + s * self.d\n            self.c =-s * a + c * self.c\n            self.d =-s * b + c * self.d\n\n        return self\n\n    def prescale(self, sx, sy):\n        \"\"\"Calculate pre scaling and replace current matrix.\"\"\"\n        sx = float(sx)\n        sy = float(sy)\n        self.a *= sx\n        self.b *= sx\n        self.c *= sy\n        self.d *= sy\n        return self\n\n    def preshear(self, h, v):\n        \"\"\"Calculate pre shearing and replace current matrix.\"\"\"\n        h = float(h)\n        v = float(v)\n        a, b = self.a, self.b\n        self.a += v * self.c\n        self.b += v * self.d\n        self.c += h * a\n        self.d += h * b\n        return self\n\n    def pretranslate(self, tx, ty):\n        \"\"\"Calculate pre translation and replace current matrix.\"\"\"\n        tx = float(tx)\n        ty = float(ty)\n        self.e += tx * self.a + ty * self.c\n        self.f += tx * self.b + ty * self.d\n        return self\n\n    __inv__ = __invert__\n    __div__ = __truediv__\n    norm = __abs__\n\n\nclass IdentityMatrix(Matrix):\n    \"\"\"Identity matrix [1, 0, 0, 1, 0, 0]\"\"\"\n\n    def __hash__(self):\n        return hash((1,0,0,1,0,0))\n\n    def __init__(self):\n        Matrix.__init__(self, 1.0, 1.0)\n\n    def __repr__(self):\n        return \"IdentityMatrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)\"\n\n    def __setattr__(self, name, value):\n        if name in \"ad\":\n            self.__dict__[name] = 1.0\n        elif name in \"bcef\":\n            self.__dict__[name] = 0.0\n        else:\n            self.__dict__[name] = value\n\n    def checkargs(*args):\n        raise NotImplementedError(\"Identity is readonly\")\n\nIdentity = IdentityMatrix()\n\n\nclass linkDest:\n    \"\"\"link or outline destination details\"\"\"\n\n    def __init__(self, obj, rlink, document=None):\n        isExt = obj.is_external\n        isInt = not isExt\n        self.dest = \"\"\n        self.file_spec = \"\"\n        self.flags = 0\n        self.is_map = False\n        self.is_uri = False\n        self.kind = LINK_NONE\n        self.lt = Point(0, 0)\n        self.named = dict()\n        self.new_window = \"\"\n        self.page = obj.page\n        self.rb = Point(0, 0)\n        self.uri = obj.uri\n        \n        def uri_to_dict(uri):\n            items = self.uri[1:].split('&')\n            ret = dict()\n            for item in items:\n                eq = item.find('=')\n                if eq >= 0:\n                    ret[item[:eq]] = item[eq+1:]\n                else:\n                    ret[item] = None\n            return ret\n\n        def unescape(name):\n            \"\"\"Unescape '%AB' substrings to chr(0xAB).\"\"\"\n            split = name.replace(\"%%\", \"%25\")  # take care of escaped '%'\n            split = split.split(\"%\")\n            newname = split[0]\n            for item in split[1:]:\n                piece = item[:2]\n                newname += chr(int(piece, base=16))\n                newname += item[2:]\n            return newname\n        \n        if rlink and not self.uri.startswith(\"#\"):\n            self.uri = f\"#page={rlink[0] + 1}&zoom=0,{_format_g(rlink[1])},{_format_g(rlink[2])}\"\n        if obj.is_external:\n            self.page = -1\n            self.kind = LINK_URI\n        if not self.uri:\n            self.page = -1\n            self.kind = LINK_NONE\n        if isInt and self.uri:\n            self.uri = self.uri.replace(\"&zoom=nan\", \"&zoom=0\")\n            if self.uri.startswith(\"#\"):\n                self.kind = LINK_GOTO\n                m = re.match('^#page=([0-9]+)&zoom=([0-9.]+),(-?[0-9.]+),(-?[0-9.]+)$', self.uri)\n                if m:\n                    self.page = int(m.group(1)) - 1\n                    self.lt = Point(float((m.group(3))), float(m.group(4)))\n                    self.flags = self.flags | LINK_FLAG_L_VALID | LINK_FLAG_T_VALID\n                else:\n                    m = re.match('^#page=([0-9]+)$', self.uri)\n                    if m:\n                        self.page = int(m.group(1)) - 1\n                    else:\n                        self.kind = LINK_NAMED\n                        m = re.match('^#nameddest=(.*)', self.uri)\n                        assert document\n                        if document and m:\n                            named = unescape(m.group(1))\n                            self.named = document.resolve_names().get(named)\n                            if self.named is None:\n                                # document.resolve_names() does not contain an\n                                # entry for `named` so use an empty dict.\n                                self.named = dict()\n                            self.named['nameddest'] = named\n                        else:\n                            self.named = uri_to_dict(self.uri[1:])\n            else:\n                self.kind = LINK_NAMED\n                self.named = uri_to_dict(self.uri)\n        if obj.is_external:\n            if not self.uri:\n                pass\n            elif self.uri.startswith(\"file:\"):\n                self.file_spec = self.uri[5:]\n                if self.file_spec.startswith(\"//\"):\n                    self.file_spec = self.file_spec[2:]\n                self.is_uri = False\n                self.uri = \"\"\n                self.kind = LINK_LAUNCH\n                ftab = self.file_spec.split(\"#\")\n                if len(ftab) == 2:\n                    if ftab[1].startswith(\"page=\"):\n                        self.kind = LINK_GOTOR\n                        self.file_spec = ftab[0]\n                        self.page = int(ftab[1].split(\"&\")[0][5:]) - 1\n            elif \":\" in self.uri:\n                self.is_uri = True\n                self.kind = LINK_URI\n            else:\n                self.is_uri = True\n                self.kind = LINK_LAUNCH\n        assert isinstance(self.named, dict)\n\nclass Widget:\n    '''\n    Class describing a PDF form field (\"widget\")\n    '''\n\n    def __init__(self):\n        self.border_color = None\n        self.border_style = \"S\"\n        self.border_width = 0\n        self.border_dashes = None\n        self.choice_values = None  # choice fields only\n        self.rb_parent = None   # radio buttons only: xref of owning parent\n\n        self.field_name = None  # field name\n        self.field_label = None # field label\n        self.field_value = None\n        self.field_flags = 0\n        self.field_display = 0\n        self.field_type = 0  # valid range 1 through 7\n        self.field_type_string = None  # field type as string\n\n        self.fill_color = None\n        self.button_caption = None  # button caption\n        self.is_signed = None  # True / False if signature\n        self.text_color = (0, 0, 0)\n        self.text_font = \"Helv\"\n        self.text_fontsize = 0\n        self.text_maxlen = 0  # text fields only\n        self.text_format = 0  # text fields only\n        self._text_da = \"\"  # /DA = default appearance\n\n        self.script = None  # JavaScript (/A)\n        self.script_stroke = None  # JavaScript (/AA/K)\n        self.script_format = None  # JavaScript (/AA/F)\n        self.script_change = None  # JavaScript (/AA/V)\n        self.script_calc = None  # JavaScript (/AA/C)\n        self.script_blur = None  # JavaScript (/AA/Bl)\n        self.script_focus = None  # JavaScript (/AA/Fo) codespell:ignore\n\n        self.rect = None  # annot value\n        self.xref = 0  # annot value\n\n    def __repr__(self):\n        return f'Widget:(field_type={self.field_type_string} script={self.script})'\n\n    def _adjust_font(self):\n        \"\"\"Ensure text_font is from our list and correctly spelled.\n        \"\"\"\n        if not self.text_font:\n            self.text_font = \"Helv\"\n            return\n        valid_fonts = (\"Cour\", \"TiRo\", \"Helv\", \"ZaDb\")\n        for f in valid_fonts:\n            if self.text_font.lower() == f.lower():\n                self.text_font = f\n                return\n        self.text_font = \"Helv\"\n        return\n\n    def _checker(self):\n        \"\"\"Any widget type checks.\n        \"\"\"\n        if self.field_type not in range(1, 8):\n            raise ValueError(\"bad field type\")\n\n        # if setting a radio button to ON, first set Off all buttons\n        # in the group - this is not done by MuPDF:\n        if self.field_type == mupdf.PDF_WIDGET_TYPE_RADIOBUTTON and self.field_value not in (False, \"Off\") and hasattr(self, \"parent\"):\n            # so we are about setting this button to ON/True\n            # check other buttons in same group and set them to 'Off'\n            doc = self.parent.parent\n            kids_type, kids_value = doc.xref_get_key(self.xref, \"Parent/Kids\")\n            if kids_type == \"array\":\n                xrefs = tuple(map(int, kids_value[1:-1].replace(\"0 R\",\"\").split()))\n                for xref in xrefs:\n                    if xref != self.xref:\n                        doc.xref_set_key(xref, \"AS\", \"/Off\")\n        # the calling method will now set the intended button to on and\n        # will find everything prepared for correct functioning.\n\n    def _parse_da(self):\n        \"\"\"Extract font name, size and color from default appearance string (/DA object).\n\n        Equivalent to 'pdf_parse_default_appearance' function in MuPDF's 'pdf-annot.c'.\n        \"\"\"\n        if not self._text_da:\n            return\n        font = \"Helv\"\n        fsize = 0\n        col = (0, 0, 0)\n        dat = self._text_da.split()  # split on any whitespace\n        for i, item in enumerate(dat):\n            if item == \"Tf\":\n                font = dat[i - 2][1:]\n                fsize = float(dat[i - 1])\n                dat[i] = dat[i-1] = dat[i-2] = \"\"\n                continue\n            if item == \"g\":  # unicolor text\n                col = [(float(dat[i - 1]))]\n                dat[i] = dat[i-1] = \"\"\n                continue\n            if item == \"rg\":  # RGB colored text\n                col = [float(f) for f in dat[i - 3:i]]\n                dat[i] = dat[i-1] = dat[i-2] = dat[i-3] = \"\"\n                continue\n        self.text_font = font\n        self.text_fontsize = fsize\n        self.text_color = col\n        self._text_da = \"\"\n        return\n\n    def _validate(self):\n        \"\"\"Validate the class entries.\n        \"\"\"\n        if (self.rect.is_infinite\n            or self.rect.is_empty\n           ):\n            raise ValueError(\"bad rect\")\n\n        if not self.field_name:\n            raise ValueError(\"field name missing\")\n\n        if self.field_label == \"Unnamed\":\n            self.field_label = None\n        CheckColor(self.border_color)\n        CheckColor(self.fill_color)\n        if not self.text_color:\n            self.text_color = (0, 0, 0)\n        CheckColor(self.text_color)\n\n        if not self.border_width:\n            self.border_width = 0\n\n        if not self.text_fontsize:\n            self.text_fontsize = 0\n\n        self.border_style = self.border_style.upper()[0:1]\n\n        # standardize content of JavaScript entries\n        btn_type = self.field_type in (\n                mupdf.PDF_WIDGET_TYPE_BUTTON,\n                mupdf.PDF_WIDGET_TYPE_CHECKBOX,\n                mupdf.PDF_WIDGET_TYPE_RADIOBUTTON,\n                )\n        if not self.script:\n            self.script = None\n        elif type(self.script) is not str:\n            raise ValueError(\"script content must be a string\")\n\n        # buttons cannot have the following script actions\n        if btn_type or not self.script_calc:\n            self.script_calc = None\n        elif type(self.script_calc) is not str:\n            raise ValueError(\"script_calc content must be a string\")\n\n        if btn_type or not self.script_change:\n            self.script_change = None\n        elif type(self.script_change) is not str:\n            raise ValueError(\"script_change content must be a string\")\n\n        if btn_type or not self.script_format:\n            self.script_format = None\n        elif type(self.script_format) is not str:\n            raise ValueError(\"script_format content must be a string\")\n\n        if btn_type or not self.script_stroke:\n            self.script_stroke = None\n        elif type(self.script_stroke) is not str:\n            raise ValueError(\"script_stroke content must be a string\")\n\n        if btn_type or not self.script_blur:\n            self.script_blur = None\n        elif type(self.script_blur) is not str:\n            raise ValueError(\"script_blur content must be a string\")\n\n        if btn_type or not self.script_focus:\n            self.script_focus = None\n        elif type(self.script_focus) is not str:\n            raise ValueError(\"script_focus content must be a string\")\n\n        self._checker()  # any field_type specific checks\n\n    def _sync_flags(self):\n        \"\"\"Propagate the field flags.\n\n        If this widget has a \"/Parent\", set its field flags and that of all\n        its /Kids widgets to the value of the current widget.\n        Only possible for widgets existing in the PDF.\n\n        Returns True or False.\n        \"\"\"\n        if not self.xref:\n            return False  # no xref: widget not in the PDF\n        doc = self.parent.parent  # the owning document\n        assert doc\n        pdf = _as_pdf_document(doc)\n        # load underlying PDF object\n        pdf_widget = mupdf.pdf_load_object(pdf, self.xref)\n        Parent = mupdf.pdf_dict_get(pdf_widget, PDF_NAME(\"Parent\"))\n        if not Parent.pdf_is_dict():\n            return False  # no /Parent: nothing to do\n\n        # put the field flags value into the parent field flags:\n        Parent.pdf_dict_put_int(PDF_NAME(\"Ff\"), self.field_flags)\n\n        # also put that value into all kids of the Parent\n        kids = Parent.pdf_dict_get(PDF_NAME(\"Kids\"))\n        if not kids.pdf_is_array():\n            message(\"warning: malformed PDF, Parent has no Kids array\")\n            return False  # no /Kids: should never happen!\n\n        for i in range(kids.pdf_array_len()):  # walk through all kids\n            # access kid widget, and do some precautionary checks\n            kid = kids.pdf_array_get(i)\n            if not kid.pdf_is_dict():\n                continue\n            xref = kid.pdf_to_num()  # get xref of the kid\n            if xref == self.xref:  # skip self widget\n                continue\n            subtype = kid.pdf_dict_get(PDF_NAME(\"Subtype\"))\n            if not subtype.pdf_to_name() == \"Widget\":\n                continue\n            # put the field flags value into the kid field flags:\n            kid.pdf_dict_put_int(PDF_NAME(\"Ff\"), self.field_flags)\n\n        return True  # all done\n\n    def button_states(self):\n        \"\"\"Return the on/off state names for button widgets.\n\n        A button may have 'normal' or 'pressed down' appearances. While the 'Off'\n        state is usually called like this, the 'On' state is often given a name\n        relating to the functional context.\n        \"\"\"\n        if self.field_type not in (2, 5):\n            return None  # no button type\n        if hasattr(self, \"parent\"):  # field already exists on page\n            doc = self.parent.parent\n        else:\n            return\n        xref = self.xref\n        states = {\"normal\": None, \"down\": None}\n        APN = doc.xref_get_key(xref, \"AP/N\")\n        if APN[0] == \"dict\":\n            nstates = []\n            APN = APN[1][2:-2]\n            apnt = APN.split(\"/\")[1:]\n            for x in apnt:\n                nstates.append(x.split()[0])\n            states[\"normal\"] = nstates\n        if APN[0] == \"xref\":\n            nstates = []\n            nxref = int(APN[1].split(\" \")[0])\n            APN = doc.xref_object(nxref)\n            apnt = APN.split(\"/\")[1:]\n            for x in apnt:\n                nstates.append(x.split()[0])\n            states[\"normal\"] = nstates\n        APD = doc.xref_get_key(xref, \"AP/D\")\n        if APD[0] == \"dict\":\n            dstates = []\n            APD = APD[1][2:-2]\n            apdt = APD.split(\"/\")[1:]\n            for x in apdt:\n                dstates.append(x.split()[0])\n            states[\"down\"] = dstates\n        if APD[0] == \"xref\":\n            dstates = []\n            dxref = int(APD[1].split(\" \")[0])\n            APD = doc.xref_object(dxref)\n            apdt = APD.split(\"/\")[1:]\n            for x in apdt:\n                dstates.append(x.split()[0])\n            states[\"down\"] = dstates\n        return states\n\n    @property\n    def next(self):\n        return self._annot.next\n\n    def on_state(self):\n        \"\"\"Return the \"On\" value for button widgets.\n        \n        This is useful for radio buttons mainly. Checkboxes will always return\n        \"Yes\". Radio buttons will return the string that is unequal to \"Off\"\n        as returned by method button_states().\n        If the radio button is new / being created, it does not yet have an\n        \"On\" value. In this case, a warning is shown and True is returned.\n        \"\"\"\n        if self.field_type not in (2, 5):\n            return None  # no checkbox or radio button\n        bstate = self.button_states()\n        if bstate is None:\n            bstate = dict()\n        for k in bstate.keys():\n            for v in bstate[k]:\n                if v != \"Off\":\n                    return v\n        message(\"warning: radio button has no 'On' value.\")\n        return True\n\n    def reset(self):\n        \"\"\"Reset the field value to its default.\n        \"\"\"\n        TOOLS._reset_widget(self._annot)\n\n    def update(self, sync_flags=False):\n        \"\"\"Reflect Python object in the PDF.\"\"\"\n        self._validate()\n\n        self._adjust_font()  # ensure valid text_font name\n\n        # now create the /DA string\n        self._text_da = \"\"\n        if   len(self.text_color) == 3:\n            fmt = \"{:g} {:g} {:g} rg /{f:s} {s:g} Tf\" + self._text_da\n        elif len(self.text_color) == 1:\n            fmt = \"{:g} g /{f:s} {s:g} Tf\" + self._text_da\n        elif len(self.text_color) == 4:\n            fmt = \"{:g} {:g} {:g} {:g} k /{f:s} {s:g} Tf\" + self._text_da\n        self._text_da = fmt.format(*self.text_color, f=self.text_font,\n                                    s=self.text_fontsize)\n        # finally update the widget\n\n        # if widget has a '/AA/C' script, make sure it is in the '/CO'\n        # array of the '/AcroForm' dictionary.\n        if self.script_calc:  # there is a \"calculation\" script:\n            # make sure we are in the /CO array\n            util_ensure_widget_calc(self._annot)\n\n        # finally update the widget\n        TOOLS._save_widget(self._annot, self)\n        self._text_da = \"\"\n        if sync_flags:\n            self._sync_flags()  # propagate field flags to parent and kids\n\n\nfrom . import _extra\n\n\nclass Outline:\n\n    def __init__(self, ol):\n        self.this = ol\n\n    @property\n    def dest(self):\n        '''outline destination details'''\n        return linkDest(self, None, None)\n\n    def destination(self, document):\n        '''\n        Like `dest` property but uses `document` to resolve destinations for\n        kind=LINK_NAMED.\n        '''\n        return linkDest(self, None, document)\n        \n    @property\n    def down(self):\n        ol = self.this\n        down_ol = ol.down()\n        if not down_ol.m_internal:\n            return\n        return Outline(down_ol)\n\n    @property\n    def is_external(self):\n        if g_use_extra:\n            # calling _extra.* here appears to save significant time in\n            # test_toc.py:test_full_toc, 1.2s=>0.94s.\n            #\n            return _extra.Outline_is_external( self.this)\n        ol = self.this\n        if not ol.m_internal:\n            return False\n        uri = ol.m_internal.uri if 1 else ol.uri()\n        if uri is None:\n            return False\n        return mupdf.fz_is_external_link(uri)\n\n    @property\n    def is_open(self):\n        if 1:\n            return self.this.m_internal.is_open\n        return self.this.is_open()\n\n    @property\n    def next(self):\n        ol = self.this\n        next_ol = ol.next()\n        if not next_ol.m_internal:\n            return\n        return Outline(next_ol)\n\n    @property\n    def page(self):\n        if 1:\n            return self.this.m_internal.page.page\n        return self.this.page().page\n\n    @property\n    def title(self):\n        return self.this.m_internal.title\n\n    @property\n    def uri(self):\n        ol = self.this\n        if not ol.m_internal:\n            return None\n        return ol.m_internal.uri\n\n    @property\n    def x(self):\n        return self.this.m_internal.x\n\n    @property\n    def y(self):\n        return self.this.m_internal.y\n\n    __slots__ = [ 'this']\n\n\ndef _make_PdfFilterOptions(\n        recurse=0,\n        instance_forms=0,\n        ascii=0,\n        no_update=0,\n        sanitize=0,\n        sopts=None,\n        ):\n    '''\n    Returns a mupdf.PdfFilterOptions instance.\n    '''\n\n    filter_ = mupdf.PdfFilterOptions()\n    filter_.recurse = recurse\n    filter_.instance_forms = instance_forms\n    filter_.ascii = ascii\n    \n    filter_.no_update = no_update\n    if sanitize:\n        # We want to use a PdfFilterFactory whose `.filter` fn pointer is\n        # set to MuPDF's `pdf_new_sanitize_filter()`. But not sure how to\n        # get access to this raw fn in Python; and on Windows raw MuPDF\n        # functions are not even available to C++.\n        #\n        # So we use SWIG Director to implement our own\n        # PdfFilterFactory whose `filter()` method calls\n        # `mupdf.ll_pdf_new_sanitize_filter()`.\n        if sopts:\n            assert isinstance(sopts, mupdf.PdfSanitizeFilterOptions)\n        else:\n            sopts = mupdf.PdfSanitizeFilterOptions()\n        class Factory(mupdf.PdfFilterFactory2):\n            def __init__(self):\n                super().__init__()\n                self.use_virtual_filter()\n                self.sopts = sopts\n            def filter(self, ctx, doc, chain, struct_parents, transform, options):\n                if 0:\n                    log(f'sanitize filter.filter():')\n                    log(f'    {self=}')\n                    log(f'    {ctx=}')\n                    log(f'    {doc=}')\n                    log(f'    {chain=}')\n                    log(f'    {struct_parents=}')\n                    log(f'    {transform=}')\n                    log(f'    {options=}')\n                    log(f'    {self.sopts.internal()=}')\n                return mupdf.ll_pdf_new_sanitize_filter(\n                        doc,\n                        chain,\n                        struct_parents,\n                        transform,\n                        options,\n                        self.sopts.internal(),\n                        )\n\n        factory = Factory()\n        filter_.add_factory(factory.internal())\n        filter_._factory = factory\n    return filter_\n\n\nclass Page:\n\n    def __init__(self, page, document):\n        assert isinstance(page, (mupdf.FzPage, mupdf.PdfPage)), f'page is: {page}'\n        self.this = page\n        self.thisown = True\n        self.last_point = None\n        self.draw_cont = ''\n        self._annot_refs = dict()\n        self.parent = document\n        if page.m_internal:\n            if isinstance( page, mupdf.PdfPage):\n                self.number = page.m_internal.super.number\n            else:\n                self.number = page.m_internal.number\n        else:\n            self.number = None\n\n    def __repr__(self):\n        return self.__str__()\n\n    def __str__(self):\n        #CheckParent(self)\n        parent = getattr(self, 'parent', None)\n        if isinstance(self.this.m_internal, mupdf.pdf_page):\n            number = self.this.m_internal.super.number\n        else:\n            number = self.this.m_internal.number\n\n        if parent:\n            x = self.parent.name\n            if self.parent.stream is not None:\n                x = \"memory\"\n            if x == \"\":\n                x = \"new PDF\"\n            ret = f'page {number} of <{x}, doc# {self.parent._graft_id:d}>'\n        else:\n            ret = f'page {number}'\n        return ret\n\n    def _add_caret_annot(self, point):\n        if g_use_extra:\n            annot = extra._add_caret_annot( self.this, JM_point_from_py(point))\n        else:\n            page = self._pdf_page()\n            annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_CARET)\n            if point:\n                p = JM_point_from_py(point)\n                r = mupdf.pdf_annot_rect(annot)\n                r = mupdf.FzRect(p.x, p.y, p.x + r.x1 - r.x0, p.y + r.y1 - r.y0)\n                mupdf.pdf_set_annot_rect(annot, r)\n            mupdf.pdf_update_annot(annot)\n            JM_add_annot_id(annot, \"A\")\n        return annot\n\n    def _add_file_annot(self, point, buffer_, filename, ufilename=None, desc=None, icon=None):\n        page = self._pdf_page()\n        uf = ufilename if ufilename else filename\n        d = desc if desc else filename\n        p = JM_point_from_py(point)\n        filebuf = JM_BufferFromBytes(buffer_)\n        if not filebuf.m_internal:\n            raise TypeError( MSG_BAD_BUFFER)\n        annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_FILE_ATTACHMENT)\n        r = mupdf.pdf_annot_rect(annot)\n        r = mupdf.fz_make_rect(p.x, p.y, p.x + r.x1 - r.x0, p.y + r.y1 - r.y0)\n        mupdf.pdf_set_annot_rect(annot, r)\n        flags = mupdf.PDF_ANNOT_IS_PRINT\n        mupdf.pdf_set_annot_flags(annot, flags)\n\n        if icon:\n            mupdf.pdf_set_annot_icon_name(annot, icon)\n\n        val = JM_embed_file(page.doc(), filebuf, filename, uf, d, 1)\n        mupdf.pdf_dict_put(mupdf.pdf_annot_obj(annot), PDF_NAME('FS'), val)\n        mupdf.pdf_dict_put_text_string(mupdf.pdf_annot_obj(annot), PDF_NAME('Contents'), filename)\n        mupdf.pdf_update_annot(annot)\n        mupdf.pdf_set_annot_rect(annot, r)\n        mupdf.pdf_set_annot_flags(annot, flags)\n        JM_add_annot_id(annot, \"A\")\n        return Annot(annot)\n\n    def _add_freetext_annot(\n            self, rect,\n            text,\n            fontsize=11,\n            fontname=None,\n            text_color=None,\n            fill_color=None,\n            border_color=None,\n            border_width=0,\n            dashes=None,\n            callout=None,\n            line_end=mupdf.PDF_ANNOT_LE_OPEN_ARROW,\n            opacity=1,\n            align=0,\n            rotate=0,\n            richtext=False,\n            style=None,\n            ):\n        rc = f\"\"\"<?xml version=\"1.0\"?>\n            <body xmlns=\"http://www.w3.org/1999/xtml\"\n            xmlns:xfa=\"http://www.xfa.org/schema/xfa-data/1.0/\"\n            xfa:contentType=\"text/html\" xfa:APIVersion=\"Acrobat:8.0.0\" xfa:spec=\"2.4\">\n            {text}\"\"\"\n        page = self._pdf_page()\n        if border_color and not richtext:\n            raise ValueError(\"cannot set border_color if rich_text is False\")\n        if border_color and not text_color:\n            text_color = border_color\n        nfcol, fcol = JM_color_FromSequence(fill_color)\n        ntcol, tcol = JM_color_FromSequence(text_color)\n        r = JM_rect_from_py(rect)\n        if mupdf.fz_is_infinite_rect(r) or mupdf.fz_is_empty_rect(r):\n            raise ValueError( MSG_BAD_RECT)\n        annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_FREE_TEXT)\n        annot_obj = mupdf.pdf_annot_obj(annot)\n\n        #insert text as 'contents' or 'RC' depending on 'richtext'\n        if not richtext:\n            mupdf.pdf_set_annot_contents(annot, text)\n        else:\n            mupdf.pdf_dict_put_text_string(annot_obj,PDF_NAME(\"RC\"), rc)\n            if style:\n                mupdf.pdf_dict_put_text_string(annot_obj,PDF_NAME(\"DS\"), style)\n\n        mupdf.pdf_set_annot_rect(annot, r)\n\n        while rotate < 0:\n            rotate += 360\n        while rotate >= 360:\n            rotate -= 360\n        if rotate != 0:\n            mupdf.pdf_dict_put_int(annot_obj, PDF_NAME('Rotate'), rotate)\n\n        mupdf.pdf_set_annot_quadding(annot, align)\n\n        if nfcol > 0:\n            mupdf.pdf_set_annot_color(annot, fcol[:nfcol])\n\n        mupdf.pdf_set_annot_border_width(annot, border_width)\n        mupdf.pdf_set_annot_opacity(annot, opacity)\n        if dashes:\n            for d in dashes:\n                mupdf.pdf_add_annot_border_dash_item(annot, float(d))\n\n        # Insert callout information\n        if callout:\n            mupdf.pdf_dict_put(annot_obj, PDF_NAME(\"IT\"), PDF_NAME(\"FreeTextCallout\"))\n            mupdf.pdf_set_annot_callout_style(annot, line_end)\n            point_count = len(callout)\n            extra.JM_set_annot_callout_line(annot, tuple(callout), point_count)\n\n        # insert the default appearance string\n        if not richtext:\n            JM_make_annot_DA(annot, ntcol, tcol, fontname, fontsize)\n\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        val = Annot(annot)\n        return val\n\n    def _add_ink_annot(self, list):\n        page = _as_pdf_page(self.this)\n        if not PySequence_Check(list):\n            raise ValueError( MSG_BAD_ARG_INK_ANNOT)\n        ctm = mupdf.FzMatrix()\n        mupdf.pdf_page_transform(page, mupdf.FzRect(0), ctm)\n        inv_ctm = mupdf.fz_invert_matrix(ctm)\n        annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_INK)\n        annot_obj = mupdf.pdf_annot_obj(annot)\n        n0 = len(list)\n        inklist = mupdf.pdf_new_array(page.doc(), n0)\n\n        for j in range(n0):\n            sublist = list[j]\n            n1 = len(sublist)\n            stroke = mupdf.pdf_new_array(page.doc(), 2 * n1)\n\n            for i in range(n1):\n                p = sublist[i]\n                if not PySequence_Check(p) or PySequence_Size(p) != 2:\n                    raise ValueError( MSG_BAD_ARG_INK_ANNOT)\n                point = mupdf.fz_transform_point(JM_point_from_py(p), inv_ctm)\n                mupdf.pdf_array_push_real(stroke, point.x)\n                mupdf.pdf_array_push_real(stroke, point.y)\n\n            mupdf.pdf_array_push(inklist, stroke)\n\n        mupdf.pdf_dict_put(annot_obj, PDF_NAME('InkList'), inklist)\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        return Annot(annot)\n\n    def _add_line_annot(self, p1, p2):\n        page = self._pdf_page()\n        annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_LINE)\n        a = JM_point_from_py(p1)\n        b = JM_point_from_py(p2)\n        mupdf.pdf_set_annot_line(annot, a, b)\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        assert annot.m_internal\n        return Annot(annot)\n\n    def _add_multiline(self, points, annot_type):\n        page = self._pdf_page()\n        if len(points) < 2:\n            raise ValueError( MSG_BAD_ARG_POINTS)\n        annot = mupdf.pdf_create_annot(page, annot_type)\n        for p in points:\n            if (PySequence_Size(p) != 2):\n                raise ValueError( MSG_BAD_ARG_POINTS)\n            point = JM_point_from_py(p)\n            mupdf.pdf_add_annot_vertex(annot, point)\n\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        return Annot(annot)\n\n    def _add_redact_annot(self, quad, text=None, da_str=None, align=0, fill=None, text_color=None):\n        page = self._pdf_page()\n        fcol = [ 1, 1, 1, 0]\n        nfcol = 0\n        annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_REDACT)\n        q = JM_quad_from_py(quad)\n        r = mupdf.fz_rect_from_quad(q)\n        # TODO calculate de-rotated rect\n        mupdf.pdf_set_annot_rect(annot, r)\n        if fill:\n            nfcol, fcol = JM_color_FromSequence(fill)\n            arr = mupdf.pdf_new_array(page.doc(), nfcol)\n            for i in range(nfcol):\n                mupdf.pdf_array_push_real(arr, fcol[i])\n            mupdf.pdf_dict_put(mupdf.pdf_annot_obj(annot), PDF_NAME('IC'), arr)\n        if text:\n            assert da_str\n            mupdf.pdf_dict_puts(\n                    mupdf.pdf_annot_obj(annot),\n                    \"OverlayText\",\n                    mupdf.pdf_new_text_string(text),\n                    )\n            mupdf.pdf_dict_put_text_string(mupdf.pdf_annot_obj(annot), PDF_NAME('DA'), da_str)\n            mupdf.pdf_dict_put_int(mupdf.pdf_annot_obj(annot), PDF_NAME('Q'), align)\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        annot = mupdf.ll_pdf_keep_annot(annot.m_internal)\n        annot = mupdf.PdfAnnot( annot)\n        return Annot(annot)\n\n    def _add_square_or_circle(self, rect, annot_type):\n        page = self._pdf_page()\n        r = JM_rect_from_py(rect)\n        if mupdf.fz_is_infinite_rect(r) or mupdf.fz_is_empty_rect(r):\n            raise ValueError( MSG_BAD_RECT)\n        annot = mupdf.pdf_create_annot(page, annot_type)\n        mupdf.pdf_set_annot_rect(annot, r)\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        assert annot.m_internal\n        return Annot(annot)\n\n    def _add_stamp_annot(self, rect, stamp=0):\n        rect = Rect(rect)\n        r = JM_rect_from_py(rect)\n        if mupdf.fz_is_infinite_rect(r) or mupdf.fz_is_empty_rect(r):\n            raise ValueError(MSG_BAD_RECT)\n        page = self._pdf_page()\n        stamp_id = [\n                \"Approved\",\n                \"AsIs\",\n                \"Confidential\",\n                \"Departmental\",\n                \"Experimental\",\n                \"Expired\",\n                \"Final\",\n                \"ForComment\",\n                \"ForPublicRelease\",\n                \"NotApproved\",\n                \"NotForPublicRelease\",\n                \"Sold\",\n                \"TopSecret\",\n                \"Draft\",\n                ]\n        n = len(stamp_id)\n        buf = None\n        name = None\n        if stamp in range(n):\n            name = stamp_id[stamp]\n        elif isinstance(stamp, Pixmap):\n            buf = stamp.tobytes()\n        elif isinstance(stamp, str):\n            buf = pathlib.Path(stamp).read_bytes()\n        elif isinstance(stamp, (bytes, bytearray)):\n            buf = stamp\n        elif isinstance(stamp, io.BytesIO):\n            buf = stamp.getvalue()\n        else:\n            name = stamp_id[0]\n\n        annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_STAMP)\n        if buf:  # image stamp\n            fzbuff = mupdf.fz_new_buffer_from_copied_data(buf)\n            img = mupdf.fz_new_image_from_buffer(fzbuff)\n\n            # compute image boundary box on page\n            w, h = img.w(), img.h()\n            scale = min(rect.width / w, rect.height / h)\n            width = w * scale  # bbox width\n            height = h * scale  # bbox height\n\n            # center of \"rect\"\n            center = (rect.tl + rect.br) / 2\n            x0 = center.x - width / 2\n            y0 = center.y - height / 2\n            x1 = x0 + width\n            y1 = y0 + height\n            r = mupdf.fz_make_rect(x0, y0, x1, y1)\n            mupdf.pdf_set_annot_rect(annot, r)\n            mupdf.pdf_set_annot_stamp_image(annot, img)\n            mupdf.pdf_dict_put(mupdf.pdf_annot_obj(annot), PDF_NAME(\"Name\"), mupdf.pdf_new_name(\"ImageStamp\"))\n            mupdf.pdf_set_annot_contents(annot, \"Image Stamp\")\n        else:  # text stamp\n            mupdf.pdf_set_annot_rect(annot, r)\n            mupdf.pdf_dict_put(mupdf.pdf_annot_obj(annot), PDF_NAME(\"Name\"), PDF_NAME(name))\n            mupdf.pdf_set_annot_contents(annot, name)\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        return Annot(annot)\n\n    def _add_text_annot(self, point, text, icon=None):\n        page = self._pdf_page()\n        p = JM_point_from_py( point)\n        annot = mupdf.pdf_create_annot(page, mupdf.PDF_ANNOT_TEXT)\n        r = mupdf.pdf_annot_rect(annot)\n        r = mupdf.fz_make_rect(p.x, p.y, p.x + r.x1 - r.x0, p.y + r.y1 - r.y0)\n        mupdf.pdf_set_annot_rect(annot, r)\n        mupdf.pdf_set_annot_contents(annot, text)\n        if icon:\n            mupdf.pdf_set_annot_icon_name(annot, icon)\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        return Annot(annot)\n\n    def _add_text_marker(self, quads, annot_type):\n\n        CheckParent(self)\n        if not self.parent.is_pdf:\n            raise ValueError(\"is no PDF\")\n\n        val = Page__add_text_marker(self, quads, annot_type)\n        if not val:\n            return None\n        val.parent = weakref.proxy(self)\n        self._annot_refs[id(val)] = val\n\n        return val\n\n    def _addAnnot_FromString(self, linklist):\n        \"\"\"Add links from list of object sources.\"\"\"\n        CheckParent(self)\n        if g_use_extra:\n            self.__class__._addAnnot_FromString = extra.Page_addAnnot_FromString\n            #log('Page._addAnnot_FromString() deferring to extra.Page_addAnnot_FromString().')\n            return extra.Page_addAnnot_FromString( self.this, linklist)\n        page = _as_pdf_page(self.this)\n        lcount = len(linklist)  # link count\n        if lcount < 1:\n            return\n        i = -1\n\n        # insert links from the provided sources\n        if not isinstance(linklist, tuple):\n            raise ValueError( \"bad 'linklist' argument\")\n        if not mupdf.pdf_dict_get( page.obj(), PDF_NAME('Annots')).m_internal:\n            mupdf.pdf_dict_put_array( page.obj(), PDF_NAME('Annots'), lcount)\n        annots = mupdf.pdf_dict_get( page.obj(), PDF_NAME('Annots'))\n        assert annots.m_internal, f'{lcount=} {annots.m_internal=}'\n        for i in range(lcount):\n            txtpy = linklist[i]\n            text = JM_StrAsChar(txtpy)\n            if not text:\n                message(f\"skipping bad link / annot item {i:d}.\")\n                continue\n            try:\n                annot = mupdf.pdf_add_object( page.doc(), JM_pdf_obj_from_str( page.doc(), text))\n                ind_obj = mupdf.pdf_new_indirect( page.doc(), mupdf.pdf_to_num( annot), 0)\n                mupdf.pdf_array_push( annots, ind_obj)\n            except Exception:\n                if g_exceptions_verbose:    exception_info()\n                message(f\"skipping bad link / annot item {i:d}.\\n\")\n\n    def _addWidget(self, field_type, field_name):\n        page = self._pdf_page()\n        pdf = page.doc()\n        annot = JM_create_widget(pdf, page, field_type, field_name)\n        if not annot.m_internal:\n            raise RuntimeError( \"cannot create widget\")\n        JM_add_annot_id(annot, \"W\")\n        return Annot(annot)\n\n    def _apply_redactions(self, text, images, graphics):\n        page = self._pdf_page()\n        opts = mupdf.PdfRedactOptions()\n        opts.black_boxes = 0  # no black boxes\n        opts.text = text  # how to treat text\n        opts.image_method = images  # how to treat images\n        opts.line_art = graphics  # how to treat vector graphics\n        success = mupdf.pdf_redact_page(page.doc(), page, opts)\n        return success\n\n    def _erase(self):\n        self._reset_annot_refs()\n        try:\n            self.parent._forget_page(self)\n        except Exception:\n            exception_info()\n            pass\n        self.parent = None\n        self.thisown = False\n        self.number = None\n        self.this = None\n\n    def _count_q_balance(self):\n        \"\"\"Count missing graphic state pushs and pops.\n\n        Returns:\n            A pair of integers (push, pop). Push is the number of missing\n            PDF \"q\" commands, pop is the number of \"Q\" commands.\n            A balanced graphics state for the page will be reached if its\n            /Contents is prepended with 'push' copies of string \"q\\n\"\n            and appended with 'pop' copies of \"\\nQ\".\n        \"\"\"\n        page = _as_pdf_page(self)  # need the underlying PDF page\n        res = mupdf.pdf_dict_get(  # access /Resources\n            page.obj(),\n            mupdf.PDF_ENUM_NAME_Resources,\n        )\n        cont = mupdf.pdf_dict_get(  # access /Contents\n            page.obj(),\n            mupdf.PDF_ENUM_NAME_Contents,\n        )\n        pdf = _as_pdf_document(self.parent)  # need underlying PDF document\n\n        # return value of MuPDF function\n        return mupdf.pdf_count_q_balance_outparams_fn(pdf, res, cont)\n\n    def _get_optional_content(self, oc: OptInt) -> OptStr:\n        if oc is None or oc == 0:\n            return None\n        doc = self.parent\n        check = doc.xref_object(oc, compressed=True)\n        if not (\"/Type/OCG\" in check or \"/Type/OCMD\" in check):\n            #log( 'raising \"bad optional content\"')\n            raise ValueError(\"bad optional content: 'oc'\")\n        #log( 'Looking at self._get_resource_properties()')\n        props = {}\n        for p, x in self._get_resource_properties():\n            props[x] = p\n        if oc in props.keys():\n            return props[oc]\n        i = 0\n        mc = f\"MC{i:d}\"\n        while mc in props.values():\n            i += 1\n            mc = f\"MC{i:d}\"\n        self._set_resource_property(mc, oc)\n        #log(f'returning {mc=}')\n        return mc\n\n    def _get_resource_properties(self):\n        '''\n        page list Resource/Properties\n        '''\n        page = self._pdf_page()\n        rc = JM_get_resource_properties(page.obj())\n        return rc\n\n    def _get_textpage(self, clip=None, flags=0, matrix=None):\n        if 1 or g_use_extra:\n            ll_tpage = extra.page_get_textpage(self.this, clip, flags, matrix)\n            tpage = mupdf.FzStextPage(ll_tpage)\n            return tpage\n        page = self.this\n        options = mupdf.FzStextOptions(flags)\n        rect = JM_rect_from_py(clip)\n        # Default to page's rect if `clip` not specified, for #2048.\n        rect = mupdf.fz_bound_page(page) if clip is None else JM_rect_from_py(clip)\n        ctm = JM_matrix_from_py(matrix)\n        tpage = mupdf.FzStextPage(rect)\n        dev = mupdf.fz_new_stext_device(tpage, options)\n        if _globals.no_device_caching:\n            mupdf.fz_enable_device_hints( dev, mupdf.FZ_NO_CACHE)\n        if isinstance(page, mupdf.FzPage):\n            pass\n        elif isinstance(page, mupdf.PdfPage):\n            page = page.super()\n        else:\n            assert 0, f'Unrecognised {type(page)=}'\n        mupdf.fz_run_page(page, dev, ctm, mupdf.FzCookie())\n        mupdf.fz_close_device(dev)\n        return tpage\n\n    def _insert_image(self,\n            filename=None, pixmap=None, stream=None, imask=None, clip=None,\n            overlay=1, rotate=0, keep_proportion=1, oc=0, width=0, height=0,\n            xref=0, alpha=-1, _imgname=None, digests=None\n            ):\n        maskbuf = mupdf.FzBuffer()\n        page = self._pdf_page()\n        # This will create an empty PdfDocument with a call to\n        # pdf_new_document() then assign page.doc()'s return value to it (which\n        # drop the original empty pdf_document).\n        pdf = page.doc()\n        w = width\n        h = height\n        img_xref = xref\n        rc_digest = 0\n\n        do_process_pixmap = 1\n        do_process_stream = 1\n        do_have_imask = 1\n        do_have_image = 1\n        do_have_xref = 1\n\n        if xref > 0:\n            ref = mupdf.pdf_new_indirect(pdf, xref, 0)\n            w = mupdf.pdf_to_int( mupdf.pdf_dict_geta( ref, PDF_NAME('Width'), PDF_NAME('W')))\n            h = mupdf.pdf_to_int( mupdf.pdf_dict_geta( ref, PDF_NAME('Height'), PDF_NAME('H')))\n            if w + h == 0:\n                raise ValueError( MSG_IS_NO_IMAGE)\n            #goto have_xref()\n            do_process_pixmap = 0\n            do_process_stream = 0\n            do_have_imask = 0\n            do_have_image = 0\n\n        else:\n            if stream:\n                imgbuf = JM_BufferFromBytes(stream)\n                do_process_pixmap = 0\n            else:\n                if filename:\n                    imgbuf = mupdf.fz_read_file(filename)\n                    #goto have_stream()\n                    do_process_pixmap = 0\n\n        if do_process_pixmap:\n            #log( 'do_process_pixmap')\n            # process pixmap ---------------------------------\n            arg_pix = pixmap.this\n            w = arg_pix.w()\n            h = arg_pix.h()\n            digest = mupdf.fz_md5_pixmap2(arg_pix)\n            md5_py = digest\n            temp = digests.get(md5_py, None)\n            if temp is not None:\n                img_xref = temp\n                ref = mupdf.pdf_new_indirect(page.doc(), img_xref, 0)\n                #goto have_xref()\n                do_process_stream = 0\n                do_have_imask = 0\n                do_have_image = 0\n            else:\n                if arg_pix.alpha() == 0:\n                    image = mupdf.fz_new_image_from_pixmap(arg_pix, mupdf.FzImage())\n                else:\n                    pm = mupdf.fz_convert_pixmap(\n                            arg_pix,\n                            mupdf.FzColorspace(),\n                            mupdf.FzColorspace(),\n                            mupdf.FzDefaultColorspaces(None),\n                            mupdf.FzColorParams(),\n                            1,\n                            )\n                    pm.alpha = 0\n                    pm.colorspace = None\n                    mask = mupdf.fz_new_image_from_pixmap(pm, mupdf.FzImage())\n                    image = mupdf.fz_new_image_from_pixmap(arg_pix, mask)\n                #goto have_image()\n                do_process_stream = 0\n                do_have_imask = 0\n\n        if do_process_stream:\n            #log( 'do_process_stream')\n            # process stream ---------------------------------\n            state = mupdf.FzMd5()\n            if mupdf_cppyy:\n                mupdf.fz_md5_update_buffer( state, imgbuf)\n            else:\n                mupdf.fz_md5_update(state, imgbuf.m_internal.data, imgbuf.m_internal.len)\n            if imask:\n                maskbuf = JM_BufferFromBytes(imask)\n                if mupdf_cppyy:\n                    mupdf.fz_md5_update_buffer( state, maskbuf)\n                else:\n                    mupdf.fz_md5_update(state, maskbuf.m_internal.data, maskbuf.m_internal.len)\n            digest = mupdf.fz_md5_final2(state)\n            md5_py = bytes(digest)\n            temp = digests.get(md5_py, None)\n            if temp is not None:\n                img_xref = temp\n                ref = mupdf.pdf_new_indirect(page.doc(), img_xref, 0)\n                w = mupdf.pdf_to_int( mupdf.pdf_dict_geta( ref, PDF_NAME('Width'), PDF_NAME('W')))\n                h = mupdf.pdf_to_int( mupdf.pdf_dict_geta( ref, PDF_NAME('Height'), PDF_NAME('H')))\n                #goto have_xref()\n                do_have_imask = 0\n                do_have_image = 0\n            else:\n                image = mupdf.fz_new_image_from_buffer(imgbuf)\n                w = image.w()\n                h = image.h()\n                if not imask:\n                    #goto have_image()\n                    do_have_imask = 0\n\n        if do_have_imask:\n            # `fz_compressed_buffer` is reference counted and\n            # `mupdf.fz_new_image_from_compressed_buffer2()`\n            # is povided as a Swig-friendly wrapper for\n            # `fz_new_image_from_compressed_buffer()`, so we can do things\n            # straightfowardly.\n            #\n            cbuf1 = mupdf.fz_compressed_image_buffer( image)\n            if not cbuf1.m_internal:\n                raise ValueError( \"uncompressed image cannot have mask\")\n            bpc = image.bpc()\n            colorspace = image.colorspace()\n            xres, yres = mupdf.fz_image_resolution(image)\n            mask = mupdf.fz_new_image_from_buffer(maskbuf)\n            image = mupdf.fz_new_image_from_compressed_buffer2(\n                    w,\n                    h,\n                    bpc,\n                    colorspace,\n                    xres,\n                    yres,\n                    1,  # interpolate\n                    0,  # imagemask,\n                    list(), # decode\n                    list(), # colorkey\n                    cbuf1,\n                    mask,\n                    )\n            \n        if do_have_image:\n            #log( 'do_have_image')\n            ref = mupdf.pdf_add_image(pdf, image)\n            if oc:\n                JM_add_oc_object(pdf, ref, oc)\n            img_xref = mupdf.pdf_to_num(ref)\n            digests[md5_py] = img_xref\n            rc_digest = 1\n\n        if do_have_xref:\n            #log( 'do_have_xref')\n            resources = mupdf.pdf_dict_get_inheritable(page.obj(), PDF_NAME('Resources'))\n            if not resources.m_internal:\n                resources = mupdf.pdf_dict_put_dict(page.obj(), PDF_NAME('Resources'), 2)\n            xobject = mupdf.pdf_dict_get(resources, PDF_NAME('XObject'))\n            if not xobject.m_internal:\n                xobject = mupdf.pdf_dict_put_dict(resources, PDF_NAME('XObject'), 2)\n            mat = calc_image_matrix(w, h, clip, rotate, keep_proportion)\n            mupdf.pdf_dict_puts(xobject, _imgname, ref)\n            nres = mupdf.fz_new_buffer(50)\n            s = f\"\\nq\\n{_format_g((mat.a, mat.b, mat.c, mat.d, mat.e, mat.f))} cm\\n/{_imgname} Do\\nQ\\n\"\n            #s = s.replace('\\n', '\\r\\n')\n            mupdf.fz_append_string(nres, s)\n            JM_insert_contents(pdf, page.obj(), nres, overlay)\n\n        if rc_digest:\n            return img_xref, digests\n        else:\n            return img_xref, None\n\n    def _insertFont(self, fontname, bfname, fontfile, fontbuffer, set_simple, idx, wmode, serif, encoding, ordering):\n        page = self._pdf_page()\n        pdf = page.doc()\n\n        value = JM_insert_font(pdf, bfname, fontfile,fontbuffer, set_simple, idx, wmode, serif, encoding, ordering)\n        # get the objects /Resources, /Resources/Font\n        resources = mupdf.pdf_dict_get_inheritable(page.obj(), PDF_NAME('Resources'))\n        if not resources.pdf_is_dict():\n            resources = mupdf.pdf_dict_put_dict(page.obj(), PDF_NAME(\"Resources\"), 5)\n        fonts = mupdf.pdf_dict_get(resources, PDF_NAME('Font'))\n        if not fonts.m_internal:    # page has no fonts yet\n            fonts = mupdf.pdf_new_dict(pdf, 5)\n            mupdf.pdf_dict_putl(page.obj(), fonts, PDF_NAME('Resources'), PDF_NAME('Font'))\n        # store font in resources and fonts objects will contain named reference to font\n        _, xref = JM_INT_ITEM(value, 0)\n        if not xref:\n            raise RuntimeError( \"cannot insert font\")\n        font_obj = mupdf.pdf_new_indirect(pdf, xref, 0)\n        mupdf.pdf_dict_puts(fonts, fontname, font_obj)\n        return value\n\n    def _load_annot(self, name, xref):\n        page = self._pdf_page()\n        if xref == 0:\n            annot = JM_get_annot_by_name(page, name)\n        else:\n            annot = JM_get_annot_by_xref(page, xref)\n        if annot:\n            return Annot(annot)\n\n    def _makePixmap(self, doc, ctm, cs, alpha=0, annots=1, clip=None):\n        pix = JM_pixmap_from_page(doc, self.this, ctm, cs, alpha, annots, clip)\n        return Pixmap(pix)\n\n    def _other_box(self, boxtype):\n        rect = mupdf.FzRect( mupdf.FzRect.Fixed_INFINITE)\n        page = _as_pdf_page(self.this, required=False)\n        if page.m_internal:\n            obj = mupdf.pdf_dict_gets( page.obj(), boxtype)\n            if mupdf.pdf_is_array(obj):\n                rect = mupdf.pdf_to_rect(obj)\n        if mupdf.fz_is_infinite_rect( rect):\n            return\n        return JM_py_from_rect(rect)\n\n    def _pdf_page(self, required=True):\n        return _as_pdf_page(self.this, required=required)\n\n    def _reset_annot_refs(self):\n        \"\"\"Invalidate / delete all annots of this page.\"\"\"\n        self._annot_refs.clear()\n\n    def _set_opacity(self, gstate=None, CA=1, ca=1, blendmode=None):\n\n        if CA >= 1 and ca >= 1 and blendmode is None:\n            return\n        tCA = int(round(max(CA , 0) * 100))\n        if tCA >= 100:\n            tCA = 99\n        tca = int(round(max(ca, 0) * 100))\n        if tca >= 100:\n            tca = 99\n        gstate = f\"fitzca{tCA:02d}{tca:02d}\"\n\n        if not gstate:\n            return\n        page = _as_pdf_page(self.this)\n        resources = mupdf.pdf_dict_get(page.obj(), PDF_NAME('Resources'))\n        if not resources.m_internal:\n            resources = mupdf.pdf_dict_put_dict(page.obj(), PDF_NAME('Resources'), 2)\n        extg = mupdf.pdf_dict_get(resources, PDF_NAME('ExtGState'))\n        if not extg.m_internal:\n            extg = mupdf.pdf_dict_put_dict(resources, PDF_NAME('ExtGState'), 2)\n        n = mupdf.pdf_dict_len(extg)\n        for i in range(n):\n            o1 = mupdf.pdf_dict_get_key(extg, i)\n            name = mupdf.pdf_to_name(o1)\n            if name == gstate:\n                return gstate\n        opa = mupdf.pdf_new_dict(page.doc(), 3)\n        mupdf.pdf_dict_put_real(opa, PDF_NAME('CA'), CA)\n        mupdf.pdf_dict_put_real(opa, PDF_NAME('ca'), ca)\n        mupdf.pdf_dict_puts(extg, gstate, opa)\n        return gstate\n\n    def _set_pagebox(self, boxtype, rect):\n        doc = self.parent\n        if doc is None:\n            raise ValueError(\"orphaned object: parent is None\")\n\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n\n        valid_boxes = (\"CropBox\", \"BleedBox\", \"TrimBox\", \"ArtBox\")\n\n        if boxtype not in valid_boxes:\n            raise ValueError(\"bad boxtype\")\n\n        rect = Rect(rect)\n        mb = self.mediabox\n        rect = Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n        if not (mb.x0 <= rect.x0 < rect.x1 <= mb.x1 and mb.y0 <= rect.y0 < rect.y1 <= mb.y1):\n            raise ValueError(f\"{boxtype} not in MediaBox\")\n\n        doc.xref_set_key(self.xref, boxtype, f\"[{_format_g(tuple(rect))}]\")\n\n    def _set_resource_property(self, name, xref):\n        page = self._pdf_page()\n        JM_set_resource_property(page.obj(), name, xref)\n\n    def _show_pdf_page(self, fz_srcpage, overlay=1, matrix=None, xref=0, oc=0, clip=None, graftmap=None, _imgname=None):\n        cropbox = JM_rect_from_py(clip)\n        mat = JM_matrix_from_py(matrix)\n        rc_xref = xref\n        tpage = _as_pdf_page(self.this)\n        tpageref = tpage.obj()\n        pdfout = tpage.doc()    # target PDF\n        ENSURE_OPERATION(pdfout)\n        #-------------------------------------------------------------\n        # convert the source page to a Form XObject\n        #-------------------------------------------------------------\n        xobj1 = JM_xobject_from_page(pdfout, fz_srcpage, xref, graftmap.this)\n        if not rc_xref:\n            rc_xref = mupdf.pdf_to_num(xobj1)\n\n        #-------------------------------------------------------------\n        # create referencing XObject (controls display on target page)\n        #-------------------------------------------------------------\n        # fill reference to xobj1 into the /Resources\n        #-------------------------------------------------------------\n        subres1 = mupdf.pdf_new_dict(pdfout, 5)\n        mupdf.pdf_dict_puts(subres1, \"fullpage\", xobj1)\n        subres = mupdf.pdf_new_dict(pdfout, 5)\n        mupdf.pdf_dict_put(subres, PDF_NAME('XObject'), subres1)\n\n        res = mupdf.fz_new_buffer(20)\n        mupdf.fz_append_string(res, \"/fullpage Do\")\n\n        xobj2 = mupdf.pdf_new_xobject(pdfout, cropbox, mat, subres, res)\n        if oc > 0:\n            JM_add_oc_object(pdfout, mupdf.pdf_resolve_indirect(xobj2), oc)\n\n        #-------------------------------------------------------------\n        # update target page with xobj2:\n        #-------------------------------------------------------------\n        # 1. insert Xobject in Resources\n        #-------------------------------------------------------------\n        resources = mupdf.pdf_dict_get_inheritable(tpageref, PDF_NAME('Resources'))\n        if not resources.m_internal:\n            resources = mupdf.pdf_dict_put_dict(tpageref,PDF_NAME('Resources'), 5)\n        subres = mupdf.pdf_dict_get(resources, PDF_NAME('XObject'))\n        if not subres.m_internal:\n            subres = mupdf.pdf_dict_put_dict(resources, PDF_NAME('XObject'), 5)\n\n        mupdf.pdf_dict_puts(subres, _imgname, xobj2)\n\n        #-------------------------------------------------------------\n        # 2. make and insert new Contents object\n        #-------------------------------------------------------------\n        nres = mupdf.fz_new_buffer(50) # buffer for Do-command\n        mupdf.fz_append_string(nres, \" q /\")   # Do-command\n        mupdf.fz_append_string(nres, _imgname)\n        mupdf.fz_append_string(nres, \" Do Q \")\n\n        JM_insert_contents(pdfout, tpageref, nres, overlay)\n        return rc_xref\n\n    def add_caret_annot(self, point: point_like) -> Annot:\n        \"\"\"Add a 'Caret' annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_caret_annot(point)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot = Annot( annot)\n        annot_postprocess(self, annot)\n        assert hasattr( annot, 'parent')\n        return annot\n\n    def add_circle_annot(self, rect: rect_like) -> Annot:\n        \"\"\"Add a 'Circle' (ellipse, oval) annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_square_or_circle(rect, mupdf.PDF_ANNOT_CIRCLE)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_file_annot(\n            self,\n            point: point_like,\n            buffer_: ByteString,\n            filename: str,\n            ufilename: OptStr =None,\n            desc: OptStr =None,\n            icon: OptStr =None\n            ) -> Annot:\n        \"\"\"Add a 'FileAttachment' annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_file_annot(point,\n                    buffer_,\n                    filename,\n                    ufilename=ufilename,\n                    desc=desc,\n                    icon=icon,\n                    )\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_freetext_annot(\n            self,\n            rect: rect_like,\n            text: str,\n            *,\n            fontsize: float =11,\n            fontname: OptStr =None,\n            text_color: OptSeq =None,\n            fill_color: OptSeq =None,\n            border_color: OptSeq =None,\n            border_width: float =0,\n            dashes: OptSeq =None,\n            callout: OptSeq =None,\n            line_end: int=mupdf.PDF_ANNOT_LE_OPEN_ARROW,\n            opacity: float =1,\n            align: int =0,\n            rotate: int =0,\n            richtext=False,\n            style=None,\n            ) -> Annot:\n        \"\"\"Add a 'FreeText' annotation.\"\"\"\n\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_freetext_annot(\n                    rect,\n                    text,\n                    fontsize=fontsize,\n                    fontname=fontname,\n                    text_color=text_color,\n                    fill_color=fill_color,\n                    border_color=border_color,\n                    border_width=border_width,\n                    dashes=dashes,\n                    callout=callout,\n                    line_end=line_end,\n                    opacity=opacity,\n                    align=align,\n                    rotate=rotate,\n                    richtext=richtext,\n                    style=style,\n                    )\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_highlight_annot(self, quads=None, start=None,\n                          stop=None, clip=None) -> Annot:\n        \"\"\"Add a 'Highlight' annotation.\"\"\"\n        if quads is None:\n            q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n        else:\n            q = CheckMarkerArg(quads)\n        ret = self._add_text_marker(q, mupdf.PDF_ANNOT_HIGHLIGHT)\n        return ret\n\n    def add_ink_annot(self, handwriting: list) -> Annot:\n        \"\"\"Add a 'Ink' ('handwriting') annotation.\n\n        The argument must be a list of lists of point_likes.\n        \"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_ink_annot(handwriting)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_line_annot(self, p1: point_like, p2: point_like) -> Annot:\n        \"\"\"Add a 'Line' annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_line_annot(p1, p2)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_polygon_annot(self, points: list) -> Annot:\n        \"\"\"Add a 'Polygon' annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_multiline(points, mupdf.PDF_ANNOT_POLYGON)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_polyline_annot(self, points: list) -> Annot:\n        \"\"\"Add a 'PolyLine' annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_multiline(points, mupdf.PDF_ANNOT_POLY_LINE)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_rect_annot(self, rect: rect_like) -> Annot:\n        \"\"\"Add a 'Square' (rectangle) annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_square_or_circle(rect, mupdf.PDF_ANNOT_SQUARE)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_redact_annot(\n            self,\n            quad,\n            text: OptStr =None,\n            fontname: OptStr =None,\n            fontsize: float =11,\n            align: int =0,\n            fill: OptSeq =None,\n            text_color: OptSeq =None,\n            cross_out: bool =True,\n            ) -> Annot:\n        \"\"\"Add a 'Redact' annotation.\"\"\"\n        da_str = None\n        if text and not set(string.whitespace).issuperset(text):\n            CheckColor(fill)\n            CheckColor(text_color)\n            if not fontname:\n                fontname = \"Helv\"\n            if not fontsize:\n                fontsize = 11\n            if not text_color:\n                text_color = (0, 0, 0)\n            if hasattr(text_color, \"__float__\"):\n                text_color = (text_color, text_color, text_color)\n            if len(text_color) > 3:\n                text_color = text_color[:3]\n            fmt = \"{:g} {:g} {:g} rg /{f:s} {s:g} Tf\"\n            da_str = fmt.format(*text_color, f=fontname, s=fontsize)\n            if fill is None:\n                fill = (1, 1, 1)\n            if fill:\n                if hasattr(fill, \"__float__\"):\n                    fill = (fill, fill, fill)\n                if len(fill) > 3:\n                    fill = fill[:3]\n        else:\n            text = None\n\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_redact_annot(quad, text=text, da_str=da_str,\n                       align=align, fill=fill)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        #-------------------------------------------------------------\n        # change appearance to show a crossed-out rectangle\n        #-------------------------------------------------------------\n        if cross_out:\n            ap_tab = annot._getAP().splitlines()[:-1]  # get the 4 commands only\n            _, LL, LR, UR, UL = ap_tab\n            ap_tab.append(LR)\n            ap_tab.append(LL)\n            ap_tab.append(UR)\n            ap_tab.append(LL)\n            ap_tab.append(UL)\n            ap_tab.append(b\"S\")\n            ap = b\"\\n\".join(ap_tab)\n            annot._setAP(ap, 0)\n        return annot\n\n    def add_squiggly_annot(\n            self,\n            quads=None,\n            start=None,\n            stop=None,\n            clip=None,\n            ) -> Annot:\n        \"\"\"Add a 'Squiggly' annotation.\"\"\"\n        if quads is None:\n            q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n        else:\n            q = CheckMarkerArg(quads)\n        return self._add_text_marker(q, mupdf.PDF_ANNOT_SQUIGGLY)\n\n    def add_stamp_annot(self, rect: rect_like, stamp=0) -> Annot:\n        \"\"\"Add a ('rubber') 'Stamp' annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_stamp_annot(rect, stamp)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_strikeout_annot(self, quads=None, start=None, stop=None, clip=None) -> Annot:\n        \"\"\"Add a 'StrikeOut' annotation.\"\"\"\n        if quads is None:\n            q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n        else:\n            q = CheckMarkerArg(quads)\n        return self._add_text_marker(q, mupdf.PDF_ANNOT_STRIKE_OUT)\n\n    def add_text_annot(self, point: point_like, text: str, icon: str =\"Note\") -> Annot:\n        \"\"\"Add a 'Text' (sticky note) annotation.\"\"\"\n        old_rotation = annot_preprocess(self)\n        try:\n            annot = self._add_text_annot(point, text, icon=icon)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        annot_postprocess(self, annot)\n        return annot\n\n    def add_underline_annot(self, quads=None, start=None, stop=None, clip=None) -> Annot:\n        \"\"\"Add a 'Underline' annotation.\"\"\"\n        if quads is None:\n            q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n        else:\n            q = CheckMarkerArg(quads)\n        return self._add_text_marker(q, mupdf.PDF_ANNOT_UNDERLINE)\n\n    def add_widget(self, widget: Widget) -> Annot:\n        \"\"\"Add a 'Widget' (form field).\"\"\"\n        CheckParent(self)\n        doc = self.parent\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        widget._validate()\n        annot = self._addWidget(widget.field_type, widget.field_name)\n        if not annot:\n            return None\n        annot.thisown = True\n        annot.parent = weakref.proxy(self) # owning page object\n        self._annot_refs[id(annot)] = annot\n        widget.parent = annot.parent\n        widget._annot = annot\n        widget.update()\n        return annot\n\n    def annot_names(self):\n        '''\n        page get list of annot names\n        '''\n        \"\"\"List of names of annotations, fields and links.\"\"\"\n        CheckParent(self)\n        page = self._pdf_page(required=False)\n        if not page.m_internal:\n            return []\n        return JM_get_annot_id_list(page)\n\n    def annot_xrefs(self):\n        '''\n        List of xref numbers of annotations, fields and links.\n        '''\n        return JM_get_annot_xref_list2(self)\n    \n    def annots(self, types=None):\n        \"\"\" Generator over the annotations of a page.\n\n        Args:\n            types: (list) annotation types to subselect from. If none,\n                   all annotations are returned. E.g. types=[PDF_ANNOT_LINE]\n                   will only yield line annotations.\n        \"\"\"\n        skip_types = (mupdf.PDF_ANNOT_LINK, mupdf.PDF_ANNOT_POPUP, mupdf.PDF_ANNOT_WIDGET)\n        if not hasattr(types, \"__getitem__\"):\n            annot_xrefs = [a[0] for a in self.annot_xrefs() if a[1] not in skip_types]\n        else:\n            annot_xrefs = [a[0] for a in self.annot_xrefs() if a[1] in types and a[1] not in skip_types]\n        for xref in annot_xrefs:\n            annot = self.load_annot(xref)\n            # In #4928, annot can be None, which we need to ignore.\n            if annot:\n                annot._yielded=True\n                yield annot\n\n    def apply_redactions(\n            page: 'Page',\n            images: int = 2,\n            graphics: int = 1,\n            text: int = 0,\n            ) -> bool:\n        \"\"\"Apply the redaction annotations of the page.\n\n        Args:\n            page: the PDF page.\n            images:\n                  0 - ignore images\n                  1 - remove all overlapping images\n                  2 - blank out overlapping image parts\n                  3 - remove image unless invisible\n            graphics:\n                  0 - ignore graphics\n                  1 - remove graphics if contained in rectangle\n                  2 - remove all overlapping graphics\n            text:\n                  0 - remove text\n                  1 - ignore text\n        \"\"\"\n\n        def center_rect(annot_rect, new_text, font, fsize):\n            \"\"\"Calculate minimal sub-rectangle for the overlay text.\n\n            Notes:\n                Because 'insert_textbox' supports no vertical text centering,\n                we calculate an approximate number of lines here and return a\n                sub-rect with smaller height, which should still be sufficient.\n            Args:\n                annot_rect: the annotation rectangle\n                new_text: the text to insert.\n                font: the fontname. Must be one of the CJK or Base-14 set, else\n                    the rectangle is returned unchanged.\n                fsize: the fontsize\n            Returns:\n                A rectangle to use instead of the annot rectangle.\n            \"\"\"\n            if not new_text or annot_rect.width <= EPSILON:\n                return annot_rect\n            try:\n                text_width = get_text_length(new_text, font, fsize)\n            except (ValueError, mupdf.FzErrorBase):  # unsupported font\n                if g_exceptions_verbose:\n                    exception_info()\n                return annot_rect\n            line_height = fsize * 1.2\n            limit = annot_rect.width\n            h = math.ceil(text_width / limit) * line_height  # estimate rect height\n            if h >= annot_rect.height:\n                return annot_rect\n            r = annot_rect\n            y = (annot_rect.tl.y + annot_rect.bl.y - h) * 0.5\n            r.y0 = y\n            return r\n\n        CheckParent(page)\n        doc = page.parent\n        if doc.is_encrypted or doc.is_closed:\n            raise ValueError(\"document closed or encrypted\")\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n\n        redact_annots = []  # storage of annot values\n        for annot in page.annots(\n            types=(mupdf.PDF_ANNOT_REDACT,)  # pylint: disable=no-member\n        ):\n            # loop redactions\n            redact_annots.append(annot._get_redact_values())  # save annot values\n\n        if redact_annots == []:  # any redactions on this page?\n            return False  # no redactions\n\n        rc = page._apply_redactions(text, images, graphics)  # call MuPDF\n        if not rc:  # should not happen really\n            raise ValueError(\"Error applying redactions.\")\n\n        # now write replacement text in old redact rectangles\n        shape = page.new_shape()\n        for redact in redact_annots:\n            annot_rect = redact[\"rect\"]\n            fill = redact[\"fill\"]\n            if fill:\n                shape.draw_rect(annot_rect)  # colorize the rect background\n                shape.finish(fill=fill, color=fill)\n            if \"text\" in redact.keys():  # if we also have text\n                new_text = redact[\"text\"]\n                align = redact.get(\"align\", 0)\n                fname = redact[\"fontname\"]\n                fsize = redact[\"fontsize\"]\n                color = redact[\"text_color\"]\n                # try finding vertical centered sub-rect\n                trect = center_rect(annot_rect, new_text, fname, fsize)\n\n                rc = -1\n                while rc < 0 and fsize >= 4:  # while not enough room\n                    # (re-) try insertion\n                    rc = shape.insert_textbox(\n                        trect,\n                        new_text,\n                        fontname=fname,\n                        fontsize=fsize,\n                        color=color,\n                        align=align,\n                    )\n                    fsize -= 0.5  # reduce font if unsuccessful\n        shape.commit()  # append new contents object\n        return True\n\n    def recolor(self, components=1):\n        \"\"\"Convert colorspaces of objects on the page.\n        \n        Valid values are 1, 3 and 4.\n        \"\"\"\n        if components not in (1, 3, 4):\n            raise ValueError(\"components must be one of 1, 3, 4\")\n        pdfdoc = _as_pdf_document(self.parent)\n        ropt = mupdf.pdf_recolor_options()\n        ropt.num_comp = components\n        ropts = mupdf.PdfRecolorOptions(ropt)\n        mupdf.pdf_recolor_page(pdfdoc, self.number, ropts)\n\n    def clip_to_rect(self, rect):\n        \"\"\"Clip away page content outside the rectangle.\"\"\"\n        clip = Rect(rect)\n        if clip.is_infinite or (clip & self.rect).is_empty:\n            raise ValueError(\"rect must not be infinite or empty\")\n        clip *= self.transformation_matrix\n        pdfpage = _as_pdf_page(self)\n        pclip = JM_rect_from_py(clip)\n        mupdf.pdf_clip_page(pdfpage, pclip)\n        JM_refresh_links(pdfpage)\n\n    def get_layout(self):\n        \"\"\"Try to access layout information.\"\"\"\n\n        if self.layout_information is not None:\n            # layout information already present\n            return\n\n        if not _get_layout:\n            # no layout information available\n            return\n\n        layout_info = _get_layout(self)\n        self.layout_information = layout_info\n\n    @property\n    def artbox(self):\n        \"\"\"The ArtBox\"\"\"\n        rect = self._other_box(\"ArtBox\")\n        if rect is None:\n            return self.cropbox\n        mb = self.mediabox\n        return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n\n    @property\n    def bleedbox(self):\n        \"\"\"The BleedBox\"\"\"\n        rect = self._other_box(\"BleedBox\")\n        if rect is None:\n            return self.cropbox\n        mb = self.mediabox\n        return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n\n    def bound(self):\n        \"\"\"Get page rectangle.\"\"\"\n        CheckParent(self)\n        page = _as_fz_page(self.this)\n        val = mupdf.fz_bound_page(page)\n        val = Rect(val)\n        \n        if val.is_infinite and self.parent.is_pdf:\n            cb = self.cropbox\n            w, h = cb.width, cb.height\n            if self.rotation not in (0, 180):\n                w, h = h, w\n            val = Rect(0, 0, w, h)\n            msg = TOOLS.mupdf_warnings(reset=False).splitlines()[-1]\n            message(msg)\n        \n        return val\n\n    def clean_contents(self, sanitize=1):\n        if not sanitize and not self.is_wrapped:\n            self.wrap_contents()\n        page = _as_pdf_page( self.this, required=False)\n        if not page.m_internal:\n            return\n        filter_ = _make_PdfFilterOptions(recurse=1, sanitize=sanitize)\n        mupdf.pdf_filter_page_contents( page.doc(), page, filter_)\n    \n    @property\n    def cropbox(self):\n        \"\"\"The CropBox.\"\"\"\n        CheckParent(self)\n        page = self._pdf_page(required=False)\n        if not page.m_internal:\n            val = mupdf.fz_bound_page(self.this)\n        else:\n            val = JM_cropbox(page.obj())\n        val = Rect(val)\n\n        return val\n\n    @property\n    def cropbox_position(self):\n        return self.cropbox.tl\n\n    def delete_annot(self, annot):\n        \"\"\"Delete annot and return next one.\"\"\"\n        CheckParent(self)\n        CheckParent(annot)\n\n        page = self._pdf_page()\n        while 1:\n            # first loop through all /IRT annots and remove them\n            irt_annot = JM_find_annot_irt(annot.this)\n            if not irt_annot:    # no more there\n                break\n            mupdf.pdf_delete_annot(page, irt_annot.this)\n        nextannot = mupdf.pdf_next_annot(annot.this)   # store next\n        mupdf.pdf_delete_annot(page, annot.this)\n        val = Annot(nextannot)\n\n        if val:\n            val.thisown = True\n            val.parent = weakref.proxy(self) # owning page object\n            val.parent._annot_refs[id(val)] = val\n        annot._erase()\n        return val\n\n    def delete_image(page: 'Page', xref: int):\n        \"\"\"Delete the image referred to by xef.\n\n        Actually replaces by a small transparent Pixmap using method Page.replace_image.\n\n        Args:\n            xref: xref of the image to delete.\n        \"\"\"\n        # make a small 100% transparent pixmap (of just any dimension)\n        pix = Pixmap(csGRAY, (0, 0, 1, 1), 1)\n        pix.clear_with()  # clear all samples bytes to 0x00\n        page.replace_image(xref, pixmap=pix)\n\n    def delete_link(self, linkdict):\n        \"\"\"Delete a Link.\"\"\"\n        CheckParent(self)\n        if not isinstance( linkdict, dict):\n            return  # have no dictionary\n\n        def finished():\n            if linkdict[\"xref\"] == 0: return\n            try:\n                linkid = linkdict[\"id\"]\n                linkobj = self._annot_refs[linkid]\n                linkobj._erase()\n            except Exception:\n                # Don't print this exception, to match classic. Issue #2841.\n                if g_exceptions_verbose > 1:    exception_info()\n                pass\n\n        page = _as_pdf_page(self.this, required=False)\n        if not page.m_internal:\n            return finished()   # have no PDF\n        xref = linkdict[dictkey_xref]\n        if xref < 1:\n            return finished()   # invalid xref\n        annots = mupdf.pdf_dict_get( page.obj(), PDF_NAME('Annots'))\n        if not annots.m_internal:\n            return finished()   # have no annotations\n        len_ = mupdf.pdf_array_len( annots)\n        if len_ == 0:\n            return finished()\n        oxref = 0\n        for i in range( len_):\n            oxref = mupdf.pdf_to_num( mupdf.pdf_array_get( annots, i))\n            if xref == oxref:\n                break   # found xref in annotations\n\n        if xref != oxref:\n            return finished()   # xref not in annotations\n        mupdf.pdf_array_delete( annots, i) # delete entry in annotations\n        mupdf.pdf_delete_object( page.doc(), xref) # delete link object\n        mupdf.pdf_dict_put( page.obj(), PDF_NAME('Annots'), annots)\n        JM_refresh_links( page)\n\n        return finished()\n\n    def delete_widget(page: 'Page', widget: Widget) -> Widget:\n        \"\"\"Delete widget from page and return the next one.\"\"\"\n        CheckParent(page)\n        annot = getattr(widget, \"_annot\", None)\n        if annot is None:\n            raise ValueError(\"bad type: widget\")\n        nextwidget = widget.next\n        page.delete_annot(annot)\n        widget._annot.parent = None\n        keylist = list(widget.__dict__.keys())\n        for key in keylist:\n            del widget.__dict__[key]\n        return nextwidget\n\n    @property\n    def derotation_matrix(self) -> Matrix:\n        \"\"\"Reflects page de-rotation.\"\"\"\n        if g_use_extra:\n            return Matrix(extra.Page_derotate_matrix( self.this))\n        pdfpage = self._pdf_page(required=False)\n        if not pdfpage.m_internal:\n            return Matrix(mupdf.FzRect(mupdf.FzRect.UNIT))\n        return Matrix(JM_derotate_page_matrix(pdfpage))\n\n    def draw_bezier(\n            page: 'Page',\n            p1: point_like,\n            p2: point_like,\n            p3: point_like,\n            p4: point_like,\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            dashes: OptStr = None,\n            width: float = 1,\n            morph: OptStr = None,\n            closePath: bool = False,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw a general cubic Bezier curve from p1 to p4 using control points p2 and p3.\"\"\"\n        img = page.new_shape()\n        Q = img.draw_bezier(Point(p1), Point(p2), Point(p3), Point(p4))\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                closePath=closePath,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return Q\n\n    def draw_circle(\n            page: 'Page',\n            center: point_like,\n            radius: float,\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            morph: OptSeq = None,\n            dashes: OptStr = None,\n            width: float = 1,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw a circle given its center and radius.\"\"\"\n        img = page.new_shape()\n        Q = img.draw_circle(Point(center), radius)\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n        return Q\n\n    def draw_curve(\n            page: 'Page',\n            p1: point_like,\n            p2: point_like,\n            p3: point_like,\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            dashes: OptStr = None,\n            width: float = 1,\n            morph: OptSeq = None,\n            closePath: bool = False,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw a special Bezier curve from p1 to p3, generating control points on lines p1 to p2 and p2 to p3.\"\"\"\n        img = page.new_shape()\n        Q = img.draw_curve(Point(p1), Point(p2), Point(p3))\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                closePath=closePath,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return Q\n\n    def draw_line(\n            page: 'Page',\n            p1: point_like,\n            p2: point_like,\n            color: OptSeq = (0,),\n            dashes: OptStr = None,\n            width: float = 1,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            morph: OptSeq = None,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc=0,\n            ) -> Point:\n        \"\"\"Draw a line from point p1 to point p2.\"\"\"\n        img = page.new_shape()\n        p = img.draw_line(Point(p1), Point(p2))\n        img.finish(\n                color=color,\n                dashes=dashes,\n                width=width,\n                closePath=False,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return p\n\n    def draw_oval(\n            page: 'Page',\n            rect: typing.Union[rect_like, quad_like],\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            dashes: OptStr = None,\n            morph: OptSeq = None,\n            width: float = 1,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw an oval given its containing rectangle or quad.\"\"\"\n        img = page.new_shape()\n        Q = img.draw_oval(rect)\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return Q\n\n    def draw_polyline(\n            page: 'Page',\n            points: list,\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            dashes: OptStr = None,\n            width: float = 1,\n            morph: OptSeq = None,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            closePath: bool = False,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw multiple connected line segments.\"\"\"\n        img = page.new_shape()\n        Q = img.draw_polyline(points)\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                closePath=closePath,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return Q\n\n    def draw_quad(\n            page: 'Page',\n            quad: quad_like,\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            dashes: OptStr = None,\n            width: float = 1,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            morph: OptSeq = None,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw a quadrilateral.\"\"\"\n        img = page.new_shape()\n        Q = img.draw_quad(Quad(quad))\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return Q\n\n    def draw_rect(\n            page: 'Page',\n            rect: rect_like,\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            dashes: OptStr = None,\n            width: float = 1,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            morph: OptSeq = None,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            radius=None,\n            ) -> Point:\n        '''\n        Draw a rectangle. See Shape class method for details.\n        '''\n        img = page.new_shape()\n        Q = img.draw_rect(Rect(rect), radius=radius)\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return Q\n\n    def draw_sector(\n            page: 'Page',\n            center: point_like,\n            point: point_like,\n            beta: float,\n            color: OptSeq = (0,),\n            fill: OptSeq = None,\n            dashes: OptStr = None,\n            fullSector: bool = True,\n            morph: OptSeq = None,\n            width: float = 1,\n            closePath: bool = False,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw a circle sector given circle center, one arc end point and the angle of the arc.\n\n        Parameters:\n            center -- center of circle\n            point -- arc end point\n            beta -- angle of arc (degrees)\n            fullSector -- connect arc ends with center\n        \"\"\"\n        img = page.new_shape()\n        Q = img.draw_sector(Point(center), Point(point), beta, fullSector=fullSector)\n        img.finish(\n                color=color,\n                fill=fill,\n                dashes=dashes,\n                width=width,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                closePath=closePath,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return Q\n\n    def draw_squiggle(\n            page: 'Page',\n            p1: point_like,\n            p2: point_like,\n            breadth: float = 2,\n            color: OptSeq = (0,),\n            dashes: OptStr = None,\n            width: float = 1,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            morph: OptSeq = None,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw a squiggly line from point p1 to point p2.\"\"\"\n        img = page.new_shape()\n        p = img.draw_squiggle(Point(p1), Point(p2), breadth=breadth)\n        img.finish(\n                color=color,\n                dashes=dashes,\n                width=width,\n                closePath=False,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return p\n\n    def draw_zigzag(\n            page: 'Page',\n            p1: point_like,\n            p2: point_like,\n            breadth: float = 2,\n            color: OptSeq = (0,),\n            dashes: OptStr = None,\n            width: float = 1,\n            lineCap: int = 0,\n            lineJoin: int = 0,\n            overlay: bool = True,\n            morph: OptSeq = None,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ) -> Point:\n        \"\"\"Draw a zigzag line from point p1 to point p2.\"\"\"\n        img = page.new_shape()\n        p = img.draw_zigzag(Point(p1), Point(p2), breadth=breadth)\n        img.finish(\n                color=color,\n                dashes=dashes,\n                width=width,\n                closePath=False,\n                lineCap=lineCap,\n                lineJoin=lineJoin,\n                morph=morph,\n                stroke_opacity=stroke_opacity,\n                fill_opacity=fill_opacity,\n                oc=oc,\n                )\n        img.commit(overlay)\n\n        return p\n\n    def extend_textpage(self, tpage, flags=0, matrix=None):\n        page = self.this\n        tp = tpage.this\n        assert isinstance( tp, mupdf.FzStextPage)\n        options = mupdf.FzStextOptions()\n        options.flags = flags\n        ctm = JM_matrix_from_py(matrix)\n        dev = mupdf.FzDevice(tp, options)\n        mupdf.fz_run_page( page, dev, ctm, mupdf.FzCookie())\n        mupdf.fz_close_device( dev)\n\n    def find_tables(self, **kwargs):\n        return table.find_tables(self, **kwargs)\n    \n    @property\n    def first_annot(self):\n        \"\"\"First annotation.\"\"\"\n        CheckParent(self)\n        page = self._pdf_page(required=False)\n        if not page.m_internal:\n            return\n        annot = mupdf.pdf_first_annot(page)\n        if not annot.m_internal:\n            return\n        val = Annot(annot)\n        val.thisown = True\n        val.parent = weakref.proxy(self) # owning page object\n        self._annot_refs[id(val)] = val\n        return val\n\n    @property\n    def first_link(self):\n        '''\n        First link on page\n        '''\n        return self.load_links()\n\n    @property\n    def first_widget(self):\n        \"\"\"First widget/field.\"\"\"\n        CheckParent(self)\n        annot = 0\n        page = self._pdf_page(required=False)\n        if not page.m_internal:\n            return\n        annot = mupdf.pdf_first_widget(page)\n        if not annot.m_internal:\n            return\n        val = Annot(annot)\n        val.thisown = True\n        val.parent = weakref.proxy(self) # owning page object\n        self._annot_refs[id(val)] = val\n        widget = Widget()\n        TOOLS._fill_widget(val, widget)\n        val = widget\n        return val\n\n    def get_bboxlog(self, layers=None):\n        CheckParent(self)\n        old_rotation = self.rotation\n        if old_rotation != 0:\n            self.set_rotation(0)\n        page = self.this\n        rc = []\n        inc_layers = True if layers else False\n        dev = JM_new_bbox_device( rc, inc_layers)\n        mupdf.fz_run_page( page, dev, mupdf.FzMatrix(), mupdf.FzCookie())\n        mupdf.fz_close_device( dev)\n\n        if old_rotation != 0:\n            self.set_rotation(old_rotation)\n        return rc\n\n    def get_cdrawings(self, extended=None, callback=None, method=None):\n        \"\"\"Extract vector graphics (\"line art\") from the page.\"\"\"\n        CheckParent(self)\n        old_rotation = self.rotation\n        if old_rotation != 0:\n            self.set_rotation(0)\n        page = self.this\n        if isinstance(page, mupdf.PdfPage):\n            # Downcast pdf_page to fz_page.\n            page = mupdf.FzPage(page)\n        assert isinstance(page, mupdf.FzPage), f'{self.this=}'\n        clips = True if extended else False\n        prect = mupdf.fz_bound_page(page)\n        if 1 or g_use_extra:\n            rc = extra.get_cdrawings(page, extended, callback, method)\n        else:\n            rc = list()\n            if callable(callback) or method is not None:\n                dev = JM_new_lineart_device_Device(callback, clips, method)\n            else:\n                dev = JM_new_lineart_device_Device(rc, clips, method)\n            dev.ptm = mupdf.FzMatrix(1, 0, 0, -1, 0, prect.y1)\n            mupdf.fz_run_page(page, dev, mupdf.FzMatrix(), mupdf.FzCookie())\n            mupdf.fz_close_device(dev)\n\n        if old_rotation != 0:\n            self.set_rotation(old_rotation)\n        if callable(callback) or method is not None:\n            return\n        return rc\n\n    def get_contents(self):\n        \"\"\"Get xrefs of /Contents objects.\"\"\"\n        CheckParent(self)\n        ret = []\n        page = _as_pdf_page(self.this)\n        obj = page.obj()\n        contents = mupdf.pdf_dict_get(obj, mupdf.PDF_ENUM_NAME_Contents)\n        if mupdf.pdf_is_array(contents):\n            n = mupdf.pdf_array_len(contents)\n            for i in range(n):\n                icont = mupdf.pdf_array_get(contents, i)\n                xref = mupdf.pdf_to_num(icont)\n                ret.append(xref)\n        elif contents.m_internal:\n            xref = mupdf.pdf_to_num(contents)\n            ret.append( xref)\n        return ret\n\n    def get_displaylist(self, annots=1):\n        '''\n        Make a DisplayList from the page for Pixmap generation.\n\n        Include (default) or exclude annotations.\n        '''\n        CheckParent(self)\n        if annots:\n            dl = mupdf.fz_new_display_list_from_page(self.this)\n        else:\n            dl = mupdf.fz_new_display_list_from_page_contents(self.this)\n        return DisplayList(dl)\n\n    def get_drawings(self, extended: bool=False) -> list:\n        \"\"\"Retrieve vector graphics. The extended version includes clips.\n\n        Note:\n        For greater comfort, this method converts point-likes, rect-likes, quad-likes\n        of the C version to respective Point / Rect / Quad objects.\n        It also adds default items that are missing in original path types.\n        \"\"\"\n        allkeys = (\n                'closePath',\n                'fill',\n                'color',\n                'width',\n                'lineCap',\n                'lineJoin',\n                'dashes',\n                'stroke_opacity',\n                'fill_opacity',\n                'even_odd',\n                )\n        val = self.get_cdrawings(extended=extended)\n        for i in range(len(val)):\n            npath = val[i]\n            if not npath[\"type\"].startswith(\"clip\"):\n                npath[\"rect\"] = Rect(npath[\"rect\"])\n            else:\n                npath[\"scissor\"] = Rect(npath[\"scissor\"])\n            if npath[\"type\"]!=\"group\":\n                items = npath[\"items\"]\n                newitems = []\n                for item in items:\n                    cmd = item[0]\n                    rest = item[1:]\n                    if  cmd == \"re\":\n                        item = (\"re\", Rect(rest[0]).normalize(), rest[1])\n                    elif cmd == \"qu\":\n                        item = (\"qu\", Quad(rest[0]))\n                    else:\n                        item = tuple([cmd] + [Point(i) for i in rest])\n                    newitems.append(item)\n                npath[\"items\"] = newitems\n            if npath['type'] in ('f', 's'):\n                for k in allkeys:\n                    npath[k] = npath.get(k)\n\n            val[i] = npath\n        return val\n\n        class Drawpath(object):\n            \"\"\"Reflects a path dictionary from get_cdrawings().\"\"\"\n            def __init__(self, **args):\n                self.__dict__.update(args)\n        \n        class Drawpathlist(object):\n            \"\"\"List of Path objects representing get_cdrawings() output.\"\"\"\n            def __getitem__(self, item):\n                return self.paths.__getitem__(item)\n\n            def __init__(self):\n                self.paths = []\n                self.path_count = 0\n                self.group_count = 0\n                self.clip_count = 0\n                self.fill_count = 0\n                self.stroke_count = 0\n                self.fillstroke_count = 0\n\n            def __len__(self):\n                return self.paths.__len__()\n\n            def append(self, path):\n                self.paths.append(path)\n                self.path_count += 1\n                if path.type == \"clip\":\n                    self.clip_count += 1\n                elif path.type == \"group\":\n                    self.group_count += 1\n                elif path.type == \"f\":\n                    self.fill_count += 1\n                elif path.type == \"s\":\n                    self.stroke_count += 1\n                elif path.type == \"fs\":\n                    self.fillstroke_count += 1\n\n            def clip_parents(self, i):\n                \"\"\"Return list of parent clip paths.\n\n                Args:\n                    i: (int) return parents of this path.\n                Returns:\n                    List of the clip parents.\"\"\"\n                if i >= self.path_count:\n                    raise IndexError(\"bad path index\")\n                while i < 0:\n                    i += self.path_count\n                lvl = self.paths[i].level\n                clips = list(  # clip paths before identified one\n                    reversed(\n                        [\n                            p\n                            for p in self.paths[:i]\n                            if p.type == \"clip\" and p.level < lvl\n                        ]\n                    )\n                )\n                if clips == []:  # none found: empty list\n                    return []\n                nclips = [clips[0]]  # init return list\n                for p in clips[1:]:\n                    if p.level >= nclips[-1].level:\n                        continue  # only accept smaller clip levels\n                    nclips.append(p)\n                return nclips\n\n            def group_parents(self, i):\n                \"\"\"Return list of parent group paths.\n\n                Args:\n                    i: (int) return parents of this path.\n                Returns:\n                    List of the group parents.\"\"\"\n                if i >= self.path_count:\n                    raise IndexError(\"bad path index\")\n                while i < 0:\n                    i += self.path_count\n                lvl = self.paths[i].level\n                groups = list(  # group paths before identified one\n                    reversed(\n                        [\n                            p\n                            for p in self.paths[:i]\n                            if p.type == \"group\" and p.level < lvl\n                        ]\n                    )\n                )\n                if groups == []:  # none found: empty list\n                    return []\n                ngroups = [groups[0]]  # init return list\n                for p in groups[1:]:\n                    if p.level >= ngroups[-1].level:\n                        continue  # only accept smaller group levels\n                    ngroups.append(p)\n                return ngroups\n\n        def get_lineart(self) -> object:\n            \"\"\"Get page drawings paths.\n\n            Note:\n            For greater comfort, this method converts point-like, rect-like, quad-like\n            tuples of the C version to respective Point / Rect / Quad objects.\n            Also adds default items that are missing in original path types.\n            In contrast to get_drawings(), this output is an object.\n            \"\"\"\n\n            val = self.get_cdrawings(extended=True)\n            paths = self.Drawpathlist()\n            for path in val:\n                npath = self.Drawpath(**path)\n                if npath.type != \"clip\":\n                    npath.rect = Rect(path[\"rect\"])\n                else:\n                    npath.scissor = Rect(path[\"scissor\"])\n                if npath.type != \"group\":\n                    items = path[\"items\"]\n                    newitems = []\n                    for item in items:\n                        cmd = item[0]\n                        rest = item[1:]\n                        if  cmd == \"re\":\n                            item = (\"re\", Rect(rest[0]).normalize(), rest[1])\n                        elif cmd == \"qu\":\n                            item = (\"qu\", Quad(rest[0]))\n                        else:\n                            item = tuple([cmd] + [Point(i) for i in rest])\n                        newitems.append(item)\n                    npath.items = newitems\n                \n                if npath.type == \"f\":\n                    npath.stroke_opacity = None\n                    npath.dashes = None\n                    npath.line_join = None\n                    npath.line_cap = None\n                    npath.color = None\n                    npath.width = None\n\n                paths.append(npath)\n\n            val = None\n            return paths\n\n    def get_image_info(\n            page: 'Page',\n            hashes: bool = False,\n            xrefs: bool = False\n            ) -> list:\n        \"\"\"Extract image information only from a pymupdf.TextPage.\n\n        Args:\n            hashes: (bool) include MD5 hash for each image.\n            xrefs: (bool) try to find the xref for each image. Sets hashes to true.\n        \"\"\"\n        doc = page.parent\n        if xrefs and doc.is_pdf:\n            hashes = True\n        if not doc.is_pdf:\n            xrefs = False\n        imginfo = getattr(page, \"_image_info\", None)\n        if imginfo and not xrefs:\n            return imginfo\n        if not imginfo:\n            tp = page.get_textpage(flags=TEXT_PRESERVE_IMAGES)\n            imginfo = tp.extractIMGINFO(hashes=hashes)\n            del tp\n            if hashes:\n                page._image_info = imginfo\n        if not xrefs or not doc.is_pdf:\n            return imginfo\n        imglist = page.get_images()\n        digests = {}\n        for item in imglist:\n            xref = item[0]\n            pix = Pixmap(doc, xref)\n            digests[pix.digest] = xref\n            del pix\n        for i in range(len(imginfo)):\n            item = imginfo[i]\n            xref = digests.get(item[\"digest\"], 0)\n            item[\"xref\"] = xref\n            imginfo[i] = item\n        return imginfo\n\n    def get_image_rects(page: 'Page', name, transform=False) -> list:\n        \"\"\"Return list of image positions on a page.\n\n        Args:\n            name: (str, list, int) image identification. May be reference name, an\n                  item of the page's image list or an xref.\n            transform: (bool) whether to also return the transformation matrix.\n        Returns:\n            A list of pymupdf.Rect objects or tuples of (pymupdf.Rect, pymupdf.Matrix)\n            for all image locations on the page.\n        \"\"\"\n        if type(name) in (list, tuple):\n            xref = name[0]\n        elif type(name) is int:\n            xref = name\n        else:\n            imglist = [i for i in page.get_images() if i[7] == name]\n            if imglist == []:\n                raise ValueError(\"bad image name\")\n            elif len(imglist) != 1:\n                raise ValueError(\"multiple image names found\")\n            xref = imglist[0][0]\n        pix = Pixmap(page.parent, xref)  # make pixmap of the image to compute MD5\n        digest = pix.digest\n        del pix\n        infos = page.get_image_info(hashes=True)\n        if not transform:\n            bboxes = [Rect(im[\"bbox\"]) for im in infos if im[\"digest\"] == digest]\n        else:\n            bboxes = [\n                (Rect(im[\"bbox\"]), Matrix(im[\"transform\"]))\n                for im in infos\n                if im[\"digest\"] == digest\n            ]\n        return bboxes\n\n    def get_label(page):\n        \"\"\"Return the label for this PDF page.\n\n        Args:\n            page: page object.\n        Returns:\n            The label (str) of the page. Errors return an empty string.\n        \"\"\"\n        # Jorj McKie, 2021-01-06\n\n        labels = page.parent._get_page_labels()\n        if not labels:\n            return \"\"\n        labels.sort()\n        return utils.get_label_pno(page.number, labels)\n\n    def get_links(page: 'Page') -> list:\n        \"\"\"Create a list of all links contained in a PDF page.\n\n        Notes:\n            see PyMuPDF ducmentation for details.\n        \"\"\"\n\n        CheckParent(page)\n        ln = page.first_link\n        links = []\n        while ln:\n            nl = utils.getLinkDict(ln, page.parent)\n            links.append(nl)\n            ln = ln.next\n        if links != [] and page.parent.is_pdf:\n            linkxrefs = [x for x in\n                    #page.annot_xrefs()\n                    JM_get_annot_xref_list2(page)\n                    if x[1] == mupdf.PDF_ANNOT_LINK  # pylint: disable=no-member\n                    ]\n            if len(linkxrefs) == len(links):\n                for i in range(len(linkxrefs)):\n                    links[i][\"xref\"] = linkxrefs[i][0]\n                    links[i][\"id\"] = linkxrefs[i][2]\n        return links\n\n    def get_pixmap(\n                page: 'Page',\n                *,\n                matrix: matrix_like=Identity,\n                dpi=None,\n                colorspace: Colorspace=None,\n                clip: rect_like=None,\n                alpha: bool=False,\n                annots: bool=True,\n                ) -> 'Pixmap':\n        \"\"\"Create pixmap of page.\n\n        Keyword args:\n            matrix: Matrix for transformation (default: Identity).\n            dpi: desired dots per inch. If given, matrix is ignored.\n            colorspace: (str/Colorspace) cmyk, rgb, gray - case ignored, default csRGB.\n            clip: (irect-like) restrict rendering to this area.\n            alpha: (bool) whether to include alpha channel\n            annots: (bool) whether to also render annotations\n        \"\"\"\n        if colorspace is None:\n            colorspace = csRGB\n        if dpi:\n            zoom = dpi / 72\n            matrix = Matrix(zoom, zoom)\n\n        if type(colorspace) is str:\n            if colorspace.upper() == \"GRAY\":\n                colorspace = csGRAY\n            elif colorspace.upper() == \"CMYK\":\n                colorspace = csCMYK\n            else:\n                colorspace = csRGB\n        if colorspace.n not in (1, 3, 4):\n            raise ValueError(\"unsupported colorspace\")\n\n        dl = page.get_displaylist(annots=annots)\n        pix = dl.get_pixmap(matrix=matrix, colorspace=colorspace, alpha=alpha, clip=clip)\n        dl = None\n        if dpi:\n            pix.set_dpi(dpi, dpi)\n        return pix\n\n    def remove_rotation(self):\n        \"\"\"Set page rotation to 0 while maintaining visual appearance.\"\"\"\n        rot = self.rotation  # normalized rotation value\n        if rot == 0:\n            return  Identity # nothing to do\n\n        # need to derotate the page's content\n        mb = self.mediabox  # current mediabox\n\n        if rot == 90:\n            # before derotation, shift content horizontally\n            mat0 = Matrix(1, 0, 0, 1, mb.y1 - mb.x1 - mb.x0 - mb.y0, 0)\n        elif rot == 270:\n            # before derotation, shift content vertically\n            mat0 = Matrix(1, 0, 0, 1, 0, mb.x1 - mb.y1 - mb.y0 - mb.x0)\n        else:  # rot = 180\n            mat0 = Matrix(1, 0, 0, 1, -2 * mb.x0, -2 * mb.y0)\n\n        # prefix with derotation matrix\n        mat = mat0 * self.derotation_matrix\n        cmd = _format_g(tuple(mat)) + ' cm '\n        cmd = cmd.encode('utf8')\n        _ = TOOLS._insert_contents(self, cmd, False)  # prepend to page contents\n\n        # swap x- and y-coordinates\n        if rot in (90, 270):\n            x0, y0, x1, y1 = mb\n            mb.x0 = y0\n            mb.y0 = x0\n            mb.x1 = y1\n            mb.y1 = x1\n            self.set_mediabox(mb)\n\n        self.set_rotation(0)\n        rot = ~mat  # inverse of the derotation matrix\n\n        for annot in self.annots():  # modify rectangles of annotations\n            r = annot.rect * rot\n            # TODO: only try to set rectangle for applicable annot types\n            annot.set_rect(r)\n        for link in self.get_links():  # modify 'from' rectangles of links\n            r = link[\"from\"] * rot\n            self.delete_link(link)\n            link[\"from\"] = r\n            try:  # invalid links remain deleted\n                self.insert_link(link)\n            except Exception:\n                pass\n        for widget in self.widgets():  # modify field rectangles\n            r = widget.rect * rot\n            widget.rect = r\n            widget.update()\n        return rot  # the inverse of the generated derotation matrix\n\n    def cluster_drawings(\n        self, clip=None, drawings=None, x_tolerance: float = 3, y_tolerance: float = 3,\n        final_filter: bool = True,\n    ) -> list:\n        \"\"\"Join rectangles of neighboring vector graphic items.\n\n        Args:\n            clip: optional rect-like to restrict the page area to consider.\n            drawings: (optional) output of a previous \"get_drawings()\".\n            x_tolerance: horizontal neighborhood threshold.\n            y_tolerance: vertical neighborhood threshold.\n\n        Notes:\n            Vector graphics (also called line-art or drawings) usually consist\n            of independent items like rectangles, lines or curves to jointly\n            form table grid lines or bar, line, pie charts and similar.\n            This method identifies rectangles wrapping these disparate items.\n\n        Returns:\n            A list of Rect items, each wrapping line-art items that are close\n            enough to be considered forming a common vector graphic.\n            Only \"significant\" rectangles will be returned, i.e. having both,\n            width and height larger than the tolerance values.\n        \"\"\"\n        CheckParent(self)\n        parea = self.rect  # the default clipping area\n        if clip is not None:\n            parea = Rect(clip)\n        delta_x = x_tolerance  # shorter local name\n        delta_y = y_tolerance  # shorter local name\n        if drawings is None:  # if we cannot re-use a previous output\n            drawings = self.get_drawings()\n\n        def are_neighbors(r1, r2):\n            \"\"\"Detect whether r1, r2 are \"neighbors\".\n\n            Items r1, r2 are called neighbors if the minimum distance between\n            their points is less-equal delta.\n\n            Both parameters must be (potentially invalid) rectangles.\n            \"\"\"\n            # normalize rectangles as needed\n            rr1_x0, rr1_x1 = (r1.x0, r1.x1) if r1.x1 > r1.x0 else (r1.x1, r1.x0)\n            rr1_y0, rr1_y1 = (r1.y0, r1.y1) if r1.y1 > r1.y0 else (r1.y1, r1.y0)\n            rr2_x0, rr2_x1 = (r2.x0, r2.x1) if r2.x1 > r2.x0 else (r2.x1, r2.x0)\n            rr2_y0, rr2_y1 = (r2.y0, r2.y1) if r2.y1 > r2.y0 else (r2.y1, r2.y0)\n            if (\n                0\n                or rr1_x1 < rr2_x0 - delta_x\n                or rr1_x0 > rr2_x1 + delta_x\n                or rr1_y1 < rr2_y0 - delta_y\n                or rr1_y0 > rr2_y1 + delta_y\n            ):\n                # Rects do not overlap.\n                return False\n            else:\n                # Rects overlap.\n                return True\n\n        # exclude graphics not contained in the clip\n        paths = [\n            p\n            for p in drawings\n            if 1\n            and p[\"rect\"].x0 >= parea.x0\n            and p[\"rect\"].x1 <= parea.x1\n            and p[\"rect\"].y0 >= parea.y0\n            and p[\"rect\"].y1 <= parea.y1\n        ]\n\n        # list of all vector graphic rectangles\n        prects = sorted([p[\"rect\"] for p in paths], key=lambda r: (r.y1, r.x0))\n\n        new_rects = []  # the final list of the joined rectangles\n\n        # -------------------------------------------------------------------------\n        # The strategy is to identify and join all rects that are neighbors\n        # -------------------------------------------------------------------------\n        while prects:  # the algorithm will empty this list\n            r = +prects[0]  # copy of first rectangle\n            repeat = True\n            while repeat:\n                repeat = False\n                for i in range(len(prects) - 1, 0, -1):  # from back to front\n                    if are_neighbors(prects[i], r):\n                        r |= prects[i].tl  # include in first rect\n                        r |= prects[i].br  # include in first rect\n                        del prects[i]  # delete this rect\n                        repeat = True\n\n            new_rects.append(r)\n            del prects[0]\n            prects = sorted(set(prects), key=lambda r: (r.y1, r.x0))\n\n        new_rects = sorted(set(new_rects), key=lambda r: (r.y1, r.x0))\n        if not final_filter:\n            return new_rects\n        return [r for r in new_rects if r.width > delta_x and r.height > delta_y]\n\n    def get_fonts(self, full=False):\n        \"\"\"List of fonts defined in the page object.\"\"\"\n        CheckParent(self)\n        return self.parent.get_page_fonts(self.number, full=full)\n\n    def get_image_bbox(self, name, transform=0):\n        \"\"\"Get rectangle occupied by image 'name'.\n\n        'name' is either an item of the image list, or the referencing\n        name string - elem[7] of the resp. item.\n        Option 'transform' also returns the image transformation matrix.\n        \"\"\"\n        CheckParent(self)\n        doc = self.parent\n        if doc.is_closed or doc.is_encrypted:\n            raise ValueError('document closed or encrypted')\n\n        inf_rect = Rect(1, 1, -1, -1)\n        null_mat = Matrix()\n        if transform:\n            rc = (inf_rect, null_mat)\n        else:\n            rc = inf_rect\n\n        if type(name) in (list, tuple):\n            if not type(name[-1]) is int:\n                raise ValueError('need item of full page image list')\n            item = name\n        else:\n            imglist = [i for i in doc.get_page_images(self.number, True) if name == i[7]]\n            if len(imglist) == 1:\n                item = imglist[0]\n            elif imglist == []:\n                raise ValueError('bad image name')\n            else:\n                raise ValueError(f\"found multiple images named '{name}'.\")\n        xref = item[-1]\n        if xref != 0 or transform:\n            try:\n                return self.get_image_rects(item, transform=transform)[0]\n            except Exception:\n                exception_info()\n                return inf_rect\n        pdf_page = self._pdf_page()\n        val = JM_image_reporter(pdf_page)\n\n        if not bool(val):\n            return rc\n\n        for v in val:\n            if v[0] != item[-3]:\n                continue\n            q = Quad(v[1])\n            bbox = q.rect\n            if transform == 0:\n                rc = bbox\n                break\n\n            hm = Matrix(util_hor_matrix(q.ll, q.lr))\n            h = abs(q.ll - q.ul)\n            w = abs(q.ur - q.ul)\n            m0 = Matrix(1 / w, 0, 0, 1 / h, 0, 0)\n            m = ~(hm * m0)\n            rc = (bbox, m)\n            break\n        val = rc\n\n        return val\n\n    def get_images(self, full=False):\n        \"\"\"List of images defined in the page object.\"\"\"\n        CheckParent(self)\n        return self.parent.get_page_images(self.number, full=full)\n\n    def get_oc_items(self) -> list:\n        \"\"\"Get OCGs and OCMDs used in the page's contents.\n\n        Returns:\n            List of items (name, xref, type), where type is one of \"ocg\" / \"ocmd\",\n            and name is the property name.\n        \"\"\"\n        rc = []\n        for pname, xref in self._get_resource_properties():\n            text = self.parent.xref_object(xref, compressed=True)\n            if \"/Type/OCG\" in text:\n                octype = \"ocg\"\n            elif \"/Type/OCMD\" in text:\n                octype = \"ocmd\"\n            else:\n                continue\n            rc.append((pname, xref, octype))\n        return rc\n\n    def get_svg_image(self, matrix=None, text_as_path=1):\n        \"\"\"Make SVG image from page.\"\"\"\n        CheckParent(self)\n        mediabox = mupdf.fz_bound_page(self.this)\n        ctm = JM_matrix_from_py(matrix)\n        tbounds = mediabox\n        text_option = mupdf.FZ_SVG_TEXT_AS_PATH if text_as_path == 1 else mupdf.FZ_SVG_TEXT_AS_TEXT\n        tbounds = mupdf.fz_transform_rect(tbounds, ctm)\n\n        res = mupdf.fz_new_buffer(1024)\n        out = mupdf.FzOutput(res)\n        dev = mupdf.fz_new_svg_device(\n                out,\n                tbounds.x1-tbounds.x0,  # width\n                tbounds.y1-tbounds.y0,  # height\n                text_option,\n                1,\n                )\n        mupdf.fz_run_page(self.this, dev, ctm, mupdf.FzCookie())\n        mupdf.fz_close_device(dev)\n        out.fz_close_output()\n        text = JM_EscapeStrFromBuffer(res)\n        return text\n\n    def get_textbox(\n            page: Page,\n            rect: rect_like,\n            textpage=None,  #: TextPage = None,\n            ) -> str:\n        tp = textpage\n        if tp is None:\n            tp = page.get_textpage()\n        elif getattr(tp, \"parent\") != page:\n            raise ValueError(\"not a textpage of this page\")\n        rc = tp.extractTextbox(rect)\n        if textpage is None:\n            del tp\n        return rc\n\n    def get_text(self, *args, **kwargs):\n        return utils.get_text(self, *args, **kwargs)\n\n    def get_text_blocks(self, *args, **kwargs):\n        return utils.get_text_blocks(self, *args, **kwargs)\n    \n    def get_text_selection(self, *args, **kwargs):\n        return utils.get_text_selection(self, *args, **kwargs)\n    \n    def get_text_words(self, *args, **kwargs):\n        return utils.get_text_words(self, *args, **kwargs)\n    \n    def get_textpage_ocr(self, *args, **kwargs):\n        return utils.get_textpage_ocr(self, *args, **kwargs)\n    \n    def get_textpage(self, clip: rect_like = None, flags: int = 0, matrix=None) -> \"TextPage\":\n        CheckParent(self)\n        if matrix is None:\n            matrix = Matrix(1, 1)\n        old_rotation = self.rotation\n        if old_rotation != 0:\n            self.set_rotation(0)\n        try:\n            textpage = self._get_textpage(clip, flags=flags, matrix=matrix)\n        finally:\n            if old_rotation != 0:\n                self.set_rotation(old_rotation)\n        textpage = TextPage(textpage)\n        textpage.parent = weakref.proxy(self)\n        return textpage\n\n    def get_texttrace(self):\n\n        CheckParent(self)\n        old_rotation = self.rotation\n        if old_rotation != 0:\n            self.set_rotation(0)\n        page = self.this\n        rc = []\n        if 1 or g_use_extra:\n            dev = extra.JM_new_texttrace_device(rc)\n        else:\n            dev = JM_new_texttrace_device(rc)\n        prect = mupdf.fz_bound_page(page)\n        dev.ptm = mupdf.FzMatrix(1, 0, 0, -1, 0, prect.y1)\n        mupdf.fz_run_page(page, dev, mupdf.FzMatrix(), mupdf.FzCookie())\n        mupdf.fz_close_device(dev)\n\n        if old_rotation != 0:\n            self.set_rotation(old_rotation)\n        return rc\n\n    def get_xobjects(self):\n        \"\"\"List of xobjects defined in the page object.\"\"\"\n        CheckParent(self)\n        return self.parent.get_page_xobjects(self.number)\n\n    def insert_font(self, fontname=\"helv\", fontfile=None, fontbuffer=None,\n                   set_simple=False, wmode=0, encoding=0):\n        doc = self.parent\n        if doc is None:\n            raise ValueError(\"orphaned object: parent is None\")\n        idx = 0\n\n        if fontname.startswith(\"/\"):\n            fontname = fontname[1:]\n        inv_chars = INVALID_NAME_CHARS.intersection(fontname)\n        if inv_chars != set():\n            raise ValueError(f\"bad fontname chars {inv_chars}\")\n\n        font = CheckFont(self, fontname)\n        if font is not None:                    # font already in font list of page\n            xref = font[0]                      # this is the xref\n            if CheckFontInfo(doc, xref):        # also in our document font list?\n                return xref                     # yes: we are done\n            # need to build the doc FontInfo entry - done via get_char_widths\n            doc.get_char_widths(xref)\n            return xref\n\n        #--------------------------------------------------------------------------\n        # the font is not present for this page\n        #--------------------------------------------------------------------------\n\n        bfname = Base14_fontdict.get(fontname.lower(), None) # BaseFont if Base-14 font\n\n        serif = 0\n        CJK_number = -1\n        CJK_list_n = [\"china-t\", \"china-s\", \"japan\", \"korea\"]\n        CJK_list_s = [\"china-ts\", \"china-ss\", \"japan-s\", \"korea-s\"]\n\n        try:\n            CJK_number = CJK_list_n.index(fontname)\n            serif = 0\n        except Exception:\n            # Verbose in PyMuPDF/tests.\n            if g_exceptions_verbose > 1:    exception_info()\n            pass\n\n        if CJK_number < 0:\n            try:\n                CJK_number = CJK_list_s.index(fontname)\n                serif = 1\n            except Exception:\n                # Verbose in PyMuPDF/tests.\n                if g_exceptions_verbose > 1:    exception_info()\n                pass\n\n        if fontname.lower() in fitz_fontdescriptors.keys():\n            import pymupdf_fonts\n            fontbuffer = pymupdf_fonts.myfont(fontname)  # make a copy\n            del pymupdf_fonts\n\n        # install the font for the page\n        if fontfile is not None:\n            if type(fontfile) is str:\n                fontfile_str = fontfile\n            elif hasattr(fontfile, \"absolute\"):\n                fontfile_str = str(fontfile)\n            elif hasattr(fontfile, \"name\"):\n                fontfile_str = fontfile.name\n            else:\n                raise ValueError(\"bad fontfile\")\n        else:\n            fontfile_str = None\n        val = self._insertFont(fontname, bfname, fontfile_str, fontbuffer, set_simple, idx,\n                               wmode, serif, encoding, CJK_number)\n\n        if not val:                   # did not work, error return\n            return val\n\n        xref = val[0]                 # xref of installed font\n        fontdict = val[1]\n\n        if CheckFontInfo(doc, xref):  # check again: document already has this font\n            return xref               # we are done\n\n        # need to create document font info\n        doc.get_char_widths(xref, fontdict=fontdict)\n        return xref\n\n    def insert_htmlbox(\n        page,\n        rect,\n        text,\n        *,\n        css=None,\n        scale_low=0,\n        archive=None,\n        rotate=0,\n        oc=0,\n        opacity=1,\n        overlay=True,\n        _scale_word_width=True,\n        _verbose=False,\n    ) -> tuple:\n        \"\"\"Insert text with optional HTML tags and stylings into a rectangle.\n\n        Args:\n            rect: (rect-like) rectangle into which the text should be placed.\n            text: (str) text with optional HTML tags and stylings.\n            css: (str) CSS styling commands.\n            scale_low: (float) force-fit content by scaling it down. Must be in\n                range [0, 1]. If 1, no scaling will take place. If 0, arbitrary\n                down-scaling is acceptable. A value of 0.1 would mean that content\n                may be scaled down by at most 90%.\n            archive: Archive object pointing to locations of used fonts or images\n            rotate: (int) rotate the text in the box by a multiple of 90 degrees.\n            oc: (int) the xref of an OCG / OCMD (Optional Content).\n            opacity: (float) set opacity of inserted content.\n            overlay: (bool) put text on top of page content.\n            _scale_word_width: internal, for testing only.\n            _verbose: internal, for testing only.\n        Returns:\n            A tuple of floats (spare_height, scale).\n            spare_height:\n                The height of the remaining space in <rect> below the\n                text, or -1 if we failed to fit.\n            scale:\n                The scaling required; `0 < scale <= 1`.\n                Will be less than `scale_low` if we failed to fit.\n        \"\"\"\n        # normalize rotation angle\n        if not rotate % 90 == 0:\n            raise ValueError(\"bad rotation angle\")\n        while rotate < 0:\n            rotate += 360\n        while rotate >= 360:\n            rotate -= 360\n\n        if not 0 <= scale_low <= 1:\n            raise ValueError(\"'scale_low' must be in [0, 1]\")\n\n        if css is None:\n            css = \"\"\n\n        rect = Rect(rect)\n        if rotate in (90, 270):\n            temp_rect = Rect(0, 0, rect.height, rect.width)\n        else:\n            temp_rect = Rect(0, 0, rect.width, rect.height)\n\n        # use a small border by default\n        mycss = \"body {margin:1px;}\" + css  # append user CSS\n\n        # either make a story, or accept a given one\n        if isinstance(text, str):  # if a string, convert to a Story\n            story = Story(html=text, user_css=mycss, archive=archive)\n        elif isinstance(text, Story):\n            story = text\n        else:\n            raise ValueError(\"'text' must be a string or a Story\")\n        \n        # ----------------------------------------------------------------\n        # Find a scaling factor that lets our story fit in. Instead of scaling\n        # the text smaller, we instead look at how much bigger the rect needs\n        # to be to fit the text, then reverse the scaling to get how much we\n        # need to scale down the text.\n        # ----------------------------------------------------------------\n        rect_scale_max = None if scale_low == 0 else 1 / scale_low\n\n        fit = story.fit_scale(\n                temp_rect,\n                scale_min=1,\n                scale_max=rect_scale_max,\n                flags=mupdf.FZ_PLACE_STORY_FLAG_NO_OVERFLOW if _scale_word_width else 0,\n                verbose=_verbose,\n                )\n        \n        if not fit.big_enough:  # there was no fit\n            scale = 1 / fit.parameter\n            return (-1, scale)\n\n        # fit.filled is a tuple; we convert it in place to a Rect for\n        # convenience. (fit.rect is already a Rect.)\n        fit.filled = Rect(fit.filled)\n        assert (fit.rect.x0, fit.rect.y0) == (0, 0)\n        assert (fit.filled.x0, fit.filled.y0) == (0, 0)\n        \n        scale = 1 / fit.parameter\n        assert scale >= scale_low, f'{scale_low=} {scale=}'\n        \n        spare_height = max((fit.rect.y1 - fit.filled.y1) * scale, 0)\n\n        def rect_function(*args):\n            return fit.rect, fit.rect, None\n\n        # draw story on temp PDF page\n        doc = story.write_with_links(rect_function)\n\n        # Insert opacity if requested.\n        # For this, we prepend a command to the /Contents.\n        if 0 <= opacity < 1:\n            tpage = doc[0]  # load page\n            # generate /ExtGstate for the page\n            alp0 = tpage._set_opacity(CA=opacity, ca=opacity)\n            s = f\"/{alp0} gs\\n\"  # generate graphic state command\n            TOOLS._insert_contents(tpage, s.encode(), 0)\n\n        # put result in target page\n        page.show_pdf_page(rect, doc, 0, rotate=rotate, oc=oc, overlay=overlay)\n\n        # -------------------------------------------------------------------------\n        # re-insert links in target rect (show_pdf_page cannot copy annotations)\n        # -------------------------------------------------------------------------\n        # scaled center point of fit.rect\n        mp1 = (fit.rect.tl + fit.rect.br) / 2 * scale\n\n        # center point of target rect\n        mp2 = (rect.tl + rect.br) / 2\n\n        # compute link positioning matrix:\n        # - move center of scaled-down fit.rect to (0,0)\n        # - rotate\n        # - move (0,0) to center of target rect\n        mat = (\n            Matrix(scale, 0, 0, scale, -mp1.x, -mp1.y)\n            * Matrix(-rotate)\n            * Matrix(1, 0, 0, 1, mp2.x, mp2.y)\n        )\n\n        # copy over links\n        for link in doc[0].get_links():\n            link[\"from\"] *= mat\n            page.insert_link(link)\n\n        return spare_height, scale\n\n    def insert_image(\n            page,\n            rect,\n            *,\n            alpha=-1,\n            filename=None,\n            height=0,\n            keep_proportion=True,\n            mask=None,\n            oc=0,\n            overlay=True,\n            pixmap=None,\n            rotate=0,\n            stream=None,\n            width=0,\n            xref=0,\n            ):\n        \"\"\"Insert an image for display in a rectangle.\n\n        Args:\n            rect: (rect_like) position of image on the page.\n            alpha: (int, optional) set to 0 if image has no transparency.\n            filename: (str, Path, file object) image filename.\n            height: (int)\n            keep_proportion: (bool) keep width / height ratio (default).\n            mask: (bytes, optional) image consisting of alpha values to use.\n            oc: (int) xref of OCG or OCMD to declare as Optional Content.\n            overlay: (bool) put in foreground (default) or background.\n            pixmap: (pymupdf.Pixmap) use this as image.\n            rotate: (int) rotate by 0, 90, 180 or 270 degrees.\n            stream: (bytes) use this as image.\n            width: (int)\n            xref: (int) use this as image.\n\n        'page' and 'rect' are positional, all other parameters are keywords.\n\n        If 'xref' is given, that image is used. Other input options are ignored.\n        Else, exactly one of pixmap, stream or filename must be given.\n\n        'alpha=0' for non-transparent images improves performance significantly.\n        Affects stream and filename only.\n\n        Optimum transparent insertions are possible by using filename / stream in\n        conjunction with a 'mask' image of alpha values.\n\n        Returns:\n            xref (int) of inserted image. Re-use as argument for multiple insertions.\n        \"\"\"\n        CheckParent(page)\n        doc = page.parent\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n\n        if xref == 0 and (bool(filename) + bool(stream) + bool(pixmap) != 1):\n            raise ValueError(\"xref=0 needs exactly one of filename, pixmap, stream\")\n\n        if filename:\n            if type(filename) is str:\n                pass\n            elif hasattr(filename, \"absolute\"):\n                filename = str(filename)\n            elif hasattr(filename, \"name\"):\n                filename = filename.name\n            else:\n                raise ValueError(\"bad filename\")\n\n        if filename and not os.path.exists(filename):\n            raise FileNotFoundError(f\"No such file: '{filename}'\")\n        elif stream and type(stream) not in (bytes, bytearray, io.BytesIO):\n            raise ValueError(\"stream must be bytes-like / BytesIO\")\n        elif pixmap and type(pixmap) is not Pixmap:\n            raise ValueError(\"pixmap must be a Pixmap\")\n        if mask and not (stream or filename):\n            raise ValueError(\"mask requires stream or filename\")\n        if mask and type(mask) not in (bytes, bytearray, io.BytesIO):\n            raise ValueError(\"mask must be bytes-like / BytesIO\")\n        while rotate < 0:\n            rotate += 360\n        while rotate >= 360:\n            rotate -= 360\n        if rotate not in (0, 90, 180, 270):\n            raise ValueError(\"bad rotate value\")\n\n        r = Rect(rect)\n        if r.is_empty or r.is_infinite:\n            raise ValueError(\"rect must be finite and not empty\")\n        clip = r * ~page.transformation_matrix\n\n        # Create a unique image reference name.\n        ilst = [i[7] for i in doc.get_page_images(page.number)]\n        ilst += [i[1] for i in doc.get_page_xobjects(page.number)]\n        ilst += [i[4] for i in doc.get_page_fonts(page.number)]\n        n = \"fzImg\"  # 'pymupdf image'\n        i = 0\n        _imgname = n + \"0\"  # first name candidate\n        while _imgname in ilst:\n            i += 1\n            _imgname = n + str(i)  # try new name\n\n        if overlay:\n            page.wrap_contents()  # ensure a balanced graphics state\n        digests = doc.InsertedImages\n        xref, digests = page._insert_image(\n            filename=filename,\n            pixmap=pixmap,\n            stream=stream,\n            imask=mask,\n            clip=clip,\n            overlay=overlay,\n            oc=oc,\n            xref=xref,\n            rotate=rotate,\n            keep_proportion=keep_proportion,\n            width=width,\n            height=height,\n            alpha=alpha,\n            _imgname=_imgname,\n            digests=digests,\n        )\n        if digests is not None:\n            doc.InsertedImages = digests\n\n        return xref\n\n    def insert_link(page: 'Page', lnk: dict, mark: bool = True) -> None:\n        \"\"\"Insert a new link for the current page.\"\"\"\n        CheckParent(page)\n        annot = utils.getLinkText(page, lnk)\n        if annot == \"\":\n            raise ValueError(\"link kind not supported\")\n        page._addAnnot_FromString((annot,))\n\n    def insert_text(\n            page: 'Page',\n            point: point_like,\n            text: typing.Union[str, list],\n            *,\n            fontsize: float = 11,\n            lineheight: OptFloat = None,\n            fontname: str = \"helv\",\n            fontfile: OptStr = None,\n            set_simple: int = 0,\n            encoding: int = 0,\n            color: OptSeq = None,\n            fill: OptSeq = None,\n            border_width: float = 0.05,\n            miter_limit: float = 1,\n            render_mode: int = 0,\n            rotate: int = 0,\n            morph: OptSeq = None,\n            overlay: bool = True,\n            stroke_opacity: float = 1,\n            fill_opacity: float = 1,\n            oc: int = 0,\n            ):\n\n        img = page.new_shape()\n        rc = img.insert_text(\n            point,\n            text,\n            fontsize=fontsize,\n            lineheight=lineheight,\n            fontname=fontname,\n            fontfile=fontfile,\n            set_simple=set_simple,\n            encoding=encoding,\n            color=color,\n            fill=fill,\n            border_width=border_width,\n            render_mode=render_mode,\n            miter_limit=miter_limit,\n            rotate=rotate,\n            morph=morph,\n            stroke_opacity=stroke_opacity,\n            fill_opacity=fill_opacity,\n            oc=oc,\n        )\n        if rc >= 0:\n            img.commit(overlay)\n        return rc\n\n    def insert_textbox(\n            page: 'Page',\n            rect: rect_like,\n            buffer: typing.Union[str, list],\n            *,\n            align: int = 0,\n            border_width: float = 0.05,\n            color: OptSeq = None,\n            encoding: int = 0,\n            expandtabs: int = 1,\n            fill_opacity: float = 1,\n            fill: OptSeq = None,\n            fontfile: OptStr = None,\n            fontname: str = \"helv\",\n            fontsize: float = 11,\n            lineheight: OptFloat = None,\n            miter_limit: float = 1,\n            morph: OptSeq = None,\n            oc: int = 0,\n            overlay: bool = True,\n            render_mode: int = 0,\n            rotate: int = 0,\n            set_simple: int = 0,\n            stroke_opacity: float = 1,\n            ) -> float:\n        \"\"\"Insert text into a given rectangle.\n\n        Notes:\n            Creates a Shape object, uses its same-named method and commits it.\n        Parameters:\n            rect: (rect-like) area to use for text.\n            buffer: text to be inserted\n            fontname: a Base-14 font, font name or '/name'\n            fontfile: name of a font file\n            fontsize: font size\n            lineheight: overwrite the font property\n            color: RGB color triple\n            expandtabs: handles tabulators with string function\n            align: left, center, right, justified\n            rotate: 0, 90, 180, or 270 degrees\n            morph: morph box with a matrix and a fixpoint\n            overlay: put text in foreground or background\n        Returns:\n            unused or deficit rectangle area (float)\n        \"\"\"\n        img = page.new_shape()\n        rc = img.insert_textbox(\n            rect,\n            buffer,\n            fontsize=fontsize,\n            lineheight=lineheight,\n            fontname=fontname,\n            fontfile=fontfile,\n            set_simple=set_simple,\n            encoding=encoding,\n            color=color,\n            fill=fill,\n            expandtabs=expandtabs,\n            render_mode=render_mode,\n            miter_limit=miter_limit,\n            border_width=border_width,\n            align=align,\n            rotate=rotate,\n            morph=morph,\n            stroke_opacity=stroke_opacity,\n            fill_opacity=fill_opacity,\n            oc=oc,\n        )\n        if rc >= 0:\n            img.commit(overlay)\n        return rc\n\n    @property\n    def is_wrapped(self):\n        \"\"\"Check if /Contents is in a balanced graphics state.\"\"\"\n        return self._count_q_balance() == (0, 0)\n\n    @property\n    def language(self):\n        \"\"\"Page language.\"\"\"\n        pdfpage = _as_pdf_page(self.this, required=False)\n        if not pdfpage.m_internal:\n            return\n        lang = mupdf.pdf_dict_get_inheritable(pdfpage.obj(), PDF_NAME('Lang'))\n        if not lang.m_internal:\n            return\n        return mupdf.pdf_to_str_buf(lang)\n\n    def links(self, kinds=None):\n        \"\"\" Generator over the links of a page.\n\n        Args:\n            kinds: (list) link kinds to subselect from. If none,\n                   all links are returned. E.g. kinds=[LINK_URI]\n                   will only yield URI links.\n        \"\"\"\n        all_links = self.get_links()\n        for link in all_links:\n            if kinds is None or link[\"kind\"] in kinds:\n                yield (link)\n\n    def load_annot(self, ident: typing.Union[str, int]) -> Annot:\n        \"\"\"Load an annot by name (/NM key) or xref.\n\n        Args:\n            ident: identifier, either name (str) or xref (int).\n        \"\"\"\n        CheckParent(self)\n        if type(ident) is str:\n            xref = 0\n            name = ident\n        elif type(ident) is int:\n            xref = ident\n            name = None\n        else:\n            raise ValueError(\"identifier must be a string or integer\")\n        val = self._load_annot(name, xref)\n        if not val:\n            return val\n        val.thisown = True\n        val.parent = weakref.proxy(self)\n        self._annot_refs[id(val)] = val\n        return val\n\n    def load_links(self):\n        \"\"\"Get first Link.\"\"\"\n        CheckParent(self)\n        val = mupdf.fz_load_links( self.this)\n        if not val.m_internal:\n            return\n        val = Link( val)\n        val.thisown = True\n        val.parent = weakref.proxy(self) # owning page object\n        self._annot_refs[id(val)] = val\n        val.xref = 0\n        val.id = \"\"\n        if self.parent.is_pdf:\n            xrefs = self.annot_xrefs()\n            xrefs = [x for x in xrefs if x[1] == mupdf.PDF_ANNOT_LINK]\n            if xrefs:\n                link_id = xrefs[0]\n                val.xref = link_id[0]\n                val.id = link_id[2]\n        else:\n            val.xref = 0\n            val.id = \"\"\n        return val\n\n    #----------------------------------------------------------------\n    # page load widget by xref\n    #----------------------------------------------------------------\n    def load_widget( self, xref):\n        \"\"\"Load a widget by its xref.\"\"\"\n        CheckParent(self)\n\n        page = _as_pdf_page(self.this)\n        annot = JM_get_widget_by_xref( page, xref)\n        #log(f'{type(annot)=}')\n        val = annot\n        if not val:\n            return val\n        val.thisown = True\n        val.parent = weakref.proxy(self)\n        self._annot_refs[id(val)] = val\n        widget = Widget()\n        TOOLS._fill_widget(val, widget)\n        val = widget\n        return val\n\n    @property\n    def mediabox(self):\n        \"\"\"The MediaBox.\"\"\"\n        CheckParent(self)\n        page = self._pdf_page(required=False)\n        if not page.m_internal:\n            rect = mupdf.fz_bound_page( self.this)\n        else:\n            rect = JM_mediabox( page.obj())\n        return Rect(rect)\n\n    @property\n    def mediabox_size(self):\n        return Point(self.mediabox.x1, self.mediabox.y1)\n\n    def new_shape(self):\n        return Shape(self)\n\n    #@property\n    #def parent( self):\n    #    assert self._parent\n    #    if self._parent:\n    #        return self._parent\n    #    return Document( self.this.document())\n\n    def read_contents(self):\n        \"\"\"All /Contents streams concatenated to one bytes object.\"\"\"\n        return TOOLS._get_all_contents(self)\n\n    def refresh(self):\n        \"\"\"Refresh page after link/annot/widget updates.\"\"\"\n        CheckParent(self)\n        doc = self.parent\n        page = doc.reload_page(self)\n        # fixme this looks wrong.\n        self.this = page\n\n    def replace_image(\n            page: 'Page',\n            xref: int,\n            *,\n            filename=None,\n            pixmap=None,\n            stream=None,\n            ):\n        \"\"\"Replace the image referred to by xref.\n\n        Replace the image by changing the object definition stored under xref. This\n        will leave the pages appearance instructions intact, so the new image is\n        being displayed with the same bbox, rotation etc.\n        By providing a small fully transparent image, an effect as if the image had\n        been deleted can be achieved.\n        A typical use may include replacing large images by a smaller version,\n        e.g. with a lower resolution or graylevel instead of colored.\n\n        Args:\n            xref: the xref of the image to replace.\n            filename, pixmap, stream: exactly one of these must be provided. The\n                meaning being the same as in Page.insert_image.\n        \"\"\"\n        doc = page.parent  # the owning document\n        if not doc.xref_is_image(xref):\n            raise ValueError(\"xref not an image\")  # insert new image anywhere in page\n        if bool(filename) + bool(stream) + bool(pixmap) != 1:\n            raise ValueError(\"Exactly one of filename/stream/pixmap must be given\")\n        new_xref = page.insert_image(\n            page.rect, filename=filename, stream=stream, pixmap=pixmap\n        )\n        doc.xref_copy(new_xref, xref)  # copy over new to old\n        last_contents_xref = page.get_contents()[-1]\n        # new image insertion has created a new /Contents source,\n        # which we will set to spaces now\n        doc.update_stream(last_contents_xref, b\" \")\n        page._image_info = None  # clear cache of extracted image information\n\n    @property\n    def rotation(self):\n        \"\"\"Page rotation.\"\"\"\n        CheckParent(self)\n        page = _as_pdf_page(self.this, required=0)\n        if not page.m_internal:\n            return 0\n        return JM_page_rotation(page)\n\n    @property\n    def rotation_matrix(self) -> Matrix:\n        \"\"\"Reflects page rotation.\"\"\"\n        return Matrix(TOOLS._rotate_matrix(self))\n\n    def run(self, dw, m):\n        \"\"\"Run page through a device.\n        dw: DeviceWrapper\n        \"\"\"\n        CheckParent(self)\n        mupdf.fz_run_page(self.this, dw.device, JM_matrix_from_py(m), mupdf.FzCookie())\n\n    def search_for(\n            page,\n            text,\n            *,\n            clip=None,\n            quads=False,\n            flags=None,\n            textpage=None,\n            ) -> list:\n        \"\"\"Search for a string on a page.\n\n        Args:\n            text: string to be searched for\n            clip: restrict search to this rectangle\n            quads: (bool) return quads instead of rectangles\n            flags: bit switches, default: join hyphened words\n            textpage: a pre-created pymupdf.TextPage\n        Returns:\n            a list of rectangles or quads, each containing one occurrence.\n        \"\"\"\n        if flags is None:\n            flags=(0\n                | TEXT_DEHYPHENATE\n                | TEXT_PRESERVE_WHITESPACE\n                | TEXT_PRESERVE_LIGATURES\n                | TEXT_MEDIABOX_CLIP\n                )\n        if clip is not None:\n            clip = Rect(clip)\n\n        CheckParent(page)\n        tp = textpage\n        if tp is None:\n            tp = page.get_textpage(clip=clip, flags=flags)  # create pymupdf.TextPage\n        elif getattr(tp, \"parent\") != page:\n            raise ValueError(\"not a textpage of this page\")\n        rlist = tp.search(text, quads=quads)\n        if textpage is None:\n            del tp\n        return rlist\n\n    def set_artbox(self, rect):\n        \"\"\"Set the ArtBox.\"\"\"\n        return self._set_pagebox(\"ArtBox\", rect)\n\n    def set_bleedbox(self, rect):\n        \"\"\"Set the BleedBox.\"\"\"\n        return self._set_pagebox(\"BleedBox\", rect)\n\n    def set_contents(self, xref):\n        \"\"\"Set object at 'xref' as the page's /Contents.\"\"\"\n        CheckParent(self)\n        doc = self.parent\n        if doc.is_closed:\n            raise ValueError(\"document closed\")\n        if not doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        if xref not in range(1, doc.xref_length()):\n            raise ValueError(\"bad xref\")\n        if not doc.xref_is_stream(xref):\n            raise ValueError(\"xref is no stream\")\n        doc.xref_set_key(self.xref, \"Contents\", f\"{xref:d} 0 R\")\n\n    def set_cropbox(self, rect):\n        \"\"\"Set the CropBox. Will also change Page.rect.\"\"\"\n        return self._set_pagebox(\"CropBox\", rect)\n\n    def set_language(self, language=None):\n        \"\"\"Set PDF page default language.\"\"\"\n        CheckParent(self)\n        pdfpage = _as_pdf_page(self.this)\n        if not language:\n            mupdf.pdf_dict_del(pdfpage.obj(), PDF_NAME('Lang'))\n        else:\n            lang = mupdf.fz_text_language_from_string(language)\n            assert hasattr(mupdf, 'fz_string_from_text_language2')\n            mupdf.pdf_dict_put_text_string(\n                    pdfpage.obj,\n                    PDF_NAME('Lang'),\n                    mupdf.fz_string_from_text_language2(lang)\n                    )\n\n    def set_mediabox(self, rect):\n        \"\"\"Set the MediaBox.\"\"\"\n        CheckParent(self)\n        page = self._pdf_page()\n        mediabox = JM_rect_from_py(rect)\n        if (mupdf.fz_is_empty_rect(mediabox)\n                or mupdf.fz_is_infinite_rect(mediabox)\n                ):\n            raise ValueError( MSG_BAD_RECT)\n        mupdf.pdf_dict_put_rect( page.obj(), PDF_NAME('MediaBox'), mediabox)\n        mupdf.pdf_dict_del( page.obj(), PDF_NAME('CropBox'))\n        mupdf.pdf_dict_del( page.obj(), PDF_NAME('ArtBox'))\n        mupdf.pdf_dict_del( page.obj(), PDF_NAME('BleedBox'))\n        mupdf.pdf_dict_del( page.obj(), PDF_NAME('TrimBox'))\n\n    def set_rotation(self, rotation):\n        \"\"\"Set page rotation.\"\"\"\n        CheckParent(self)\n        page = _as_pdf_page(self.this)\n        rot = JM_norm_rotation(rotation)\n        mupdf.pdf_dict_put_int( page.obj(), PDF_NAME('Rotate'), rot)\n\n    def set_trimbox(self, rect):\n        \"\"\"Set the TrimBox.\"\"\"\n        return self._set_pagebox(\"TrimBox\", rect)\n\n    def show_pdf_page(\n            page,\n            rect,\n            docsrc,\n            pno=0,\n            keep_proportion=True,\n            overlay=True,\n            oc=0,\n            rotate=0,\n            clip=None,\n            ) -> int:\n        \"\"\"Show page number 'pno' of PDF 'docsrc' in rectangle 'rect'.\n\n        Args:\n            rect: (rect-like) where to place the source image\n            docsrc: (document) source PDF\n            pno: (int) source page number\n            keep_proportion: (bool) do not change width-height-ratio\n            overlay: (bool) put in foreground\n            oc: (xref) make visibility dependent on this OCG / OCMD (which must be defined in the target PDF)\n            rotate: (int) degrees (multiple of 90)\n            clip: (rect-like) part of source page rectangle\n        Returns:\n            xref of inserted object (for reuse)\n        \"\"\"\n        def calc_matrix(sr, tr, keep=True, rotate=0):\n            \"\"\"Calculate transformation matrix from source to target rect.\n\n            Notes:\n                The product of four matrices in this sequence: (1) translate correct\n                source corner to origin, (2) rotate, (3) scale, (4) translate to\n                target's top-left corner.\n            Args:\n                sr: source rect in PDF (!) coordinate system\n                tr: target rect in PDF coordinate system\n                keep: whether to keep source ratio of width to height\n                rotate: rotation angle in degrees\n            Returns:\n                Transformation matrix.\n            \"\"\"\n            # calc center point of source rect\n            smp = (sr.tl + sr.br) / 2.0\n            # calc center point of target rect\n            tmp = (tr.tl + tr.br) / 2.0\n\n            # m moves to (0, 0), then rotates\n            m = Matrix(1, 0, 0, 1, -smp.x, -smp.y) * Matrix(rotate)\n\n            sr1 = sr * m  # resulting source rect to calculate scale factors\n\n            fw = tr.width / sr1.width  # scale the width\n            fh = tr.height / sr1.height  # scale the height\n            if keep:\n                fw = fh = min(fw, fh)  # take min if keeping aspect ratio\n\n            m *= Matrix(fw, fh)  # concat scale matrix\n            m *= Matrix(1, 0, 0, 1, tmp.x, tmp.y)  # concat move to target center\n            return JM_TUPLE(m)\n\n        CheckParent(page)\n        doc = page.parent\n\n        if not doc.is_pdf or not docsrc.is_pdf:\n            raise ValueError(\"is no PDF\")\n\n        if rect.is_empty or rect.is_infinite:\n            raise ValueError(\"rect must be finite and not empty\")\n\n        while pno < 0:  # support negative page numbers\n            pno += docsrc.page_count\n        src_page = docsrc[pno]  # load source page\n\n        tar_rect = rect * ~page.transformation_matrix  # target rect in PDF coordinates\n\n        src_rect = src_page.rect if not clip else src_page.rect & clip  # source rect\n        if src_rect.is_empty or src_rect.is_infinite:\n            raise ValueError(\"clip must be finite and not empty\")\n        src_rect = src_rect * ~src_page.transformation_matrix  # ... in PDF coord\n\n        matrix = calc_matrix(src_rect, tar_rect, keep=keep_proportion, rotate=rotate)\n\n        # list of existing /Form /XObjects\n        ilst = [i[1] for i in doc.get_page_xobjects(page.number)]\n        ilst += [i[7] for i in doc.get_page_images(page.number)]\n        ilst += [i[4] for i in doc.get_page_fonts(page.number)]\n\n        # create a name not in that list\n        n = \"fzFrm\"\n        i = 0\n        _imgname = n + \"0\"\n        while _imgname in ilst:\n            i += 1\n            _imgname = n + str(i)\n\n        isrc = docsrc._graft_id  # used as key for graftmaps\n        if doc._graft_id == isrc:\n            raise ValueError(\"source document must not equal target\")\n\n        # retrieve / make Graftmap for source PDF\n        gmap = doc.Graftmaps.get(isrc, None)\n        if gmap is None:\n            gmap = Graftmap(doc)\n            doc.Graftmaps[isrc] = gmap\n\n        # take note of generated xref for automatic reuse\n        pno_id = (isrc, pno)  # id of docsrc[pno]\n        xref = doc.ShownPages.get(pno_id, 0)\n\n        if overlay:\n            page.wrap_contents()  # ensure a balanced graphics state\n        xref = page._show_pdf_page(\n            src_page,\n            overlay=overlay,\n            matrix=matrix,\n            xref=xref,\n            oc=oc,\n            clip=src_rect,\n            graftmap=gmap,\n            _imgname=_imgname,\n        )\n        doc.ShownPages[pno_id] = xref\n\n        return xref\n\n    @property\n    def transformation_matrix(self):\n        \"\"\"Page transformation matrix.\"\"\"\n        CheckParent(self)\n\n        ctm = mupdf.FzMatrix()\n        page = self._pdf_page(required=False)\n        if not page.m_internal:\n            return JM_py_from_matrix(ctm)\n        mediabox = mupdf.FzRect(mupdf.FzRect.Fixed_UNIT)    # fixme: original code passed mediabox=NULL.\n        mupdf.pdf_page_transform(page, mediabox, ctm)\n        val = JM_py_from_matrix(ctm)\n\n        if self.rotation % 360 == 0:\n            val = Matrix(val)\n        else:\n            val = Matrix(1, 0, 0, -1, 0, self.cropbox.height)\n        return val\n\n    @property\n    def trimbox(self):\n        \"\"\"The TrimBox\"\"\"\n        rect = self._other_box(\"TrimBox\")\n        if rect is None:\n            return self.cropbox\n        mb = self.mediabox\n        return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n\n    def update_link(page: 'Page', lnk: dict) -> None:\n        \"\"\"Update a link on the current page.\"\"\"\n        CheckParent(page)\n        annot = utils.getLinkText(page, lnk)\n        if annot == \"\":\n            raise ValueError(\"link kind not supported\")\n\n        page.parent.update_object(lnk[\"xref\"], annot, page=page)\n\n    def widgets(self, types=None):\n        \"\"\" Generator over the widgets of a page.\n\n        Args:\n            types: (list) field types to subselect from. If none,\n                    all fields are returned. E.g. types=[PDF_WIDGET_TYPE_TEXT]\n                    will only yield text fields.\n        \"\"\"\n        #for a in self.annot_xrefs():\n        #    log(f'{a=}')\n        widget_xrefs = [a[0] for a in self.annot_xrefs() if a[1] == mupdf.PDF_ANNOT_WIDGET]\n        #log(f'widgets(): {widget_xrefs=}')\n        for xref in widget_xrefs:\n            widget = self.load_widget(xref)\n            if types is None or widget.field_type in types:\n                yield (widget)\n\n    def wrap_contents(self):\n        \"\"\"Ensure page is in a balanced graphics state.\"\"\"\n        push, pop = self._count_q_balance()  # count missing \"q\"/\"Q\" commands\n        if push > 0:  # prepend required push commands\n            prepend = b\"q\\n\" * push\n            TOOLS._insert_contents(self, prepend, False)\n        if pop > 0:  # append required pop commands\n            append = b\"\\nQ\" * pop + b\"\\n\"\n            TOOLS._insert_contents(self, append, True)\n\n    def write_text(\n            page: 'Page',\n            rect=None,\n            writers=None,\n            overlay=True,\n            color=None,\n            opacity=None,\n            keep_proportion=True,\n            rotate=0,\n            oc=0,\n            ) -> None:\n        \"\"\"Write the text of one or more pymupdf.TextWriter objects.\n\n        Args:\n            rect: target rectangle. If None, the union of the text writers is used.\n            writers: one or more pymupdf.TextWriter objects.\n            overlay: put in foreground or background.\n            keep_proportion: maintain aspect ratio of rectangle sides.\n            rotate: arbitrary rotation angle.\n            oc: the xref of an optional content object\n        \"\"\"\n        assert isinstance(page, Page)\n        if not writers:\n            raise ValueError(\"need at least one pymupdf.TextWriter\")\n        if type(writers) is TextWriter:\n            if rotate == 0 and rect is None:\n                writers.write_text(page, opacity=opacity, color=color, overlay=overlay)\n                return None\n            else:\n                writers = (writers,)\n        clip = writers[0].text_rect\n        textdoc = Document()\n        tpage = textdoc.new_page(width=page.rect.width, height=page.rect.height)\n        for writer in writers:\n            clip |= writer.text_rect\n            writer.write_text(tpage, opacity=opacity, color=color)\n        if rect is None:\n            rect = clip\n        page.show_pdf_page(\n            rect,\n            textdoc,\n            0,\n            overlay=overlay,\n            keep_proportion=keep_proportion,\n            rotate=rotate,\n            clip=clip,\n            oc=oc,\n        )\n        textdoc = None\n        tpage = None\n\n    @property\n    def xref(self):\n        \"\"\"PDF xref number of page.\"\"\"\n        CheckParent(self)\n        return self.parent.page_xref(self.number)\n\n    rect = property(bound, doc=\"page rectangle\")\n\n    # any result of layout analysis is stored here\n    layout_information = None\n\n\nclass Pixmap:\n\n    def __init__(self, *args):\n        \"\"\"\n        Pixmap(colorspace, irect, alpha) - empty pixmap.\n        Pixmap(colorspace, src) - copy changing colorspace.\n        Pixmap(src, width, height,[clip]) - scaled copy, float dimensions.\n        Pixmap(src, alpha=1) - copy and add or drop alpha channel.\n        Pixmap(filename) - from an image in a file.\n        Pixmap(image) - from an image in memory (bytes).\n        Pixmap(colorspace, width, height, samples, alpha) - from samples data.\n        Pixmap(PDFdoc, xref) - from an image at xref in a PDF document.\n        \"\"\"\n        # Cache for property `self.samples_mv`. Set here so __del_() sees it if\n        # we raise.\n        #\n        self._samples_mv = None\n\n        # 2024-01-16: Experimental support for a memory-view of the underlying\n        # data.  Doesn't seem to make much difference to Pixmap.set_pixel() so\n        # not currently used.\n        self._memory_view = None\n        \n        if 0:\n            pass\n\n        elif args_match(args,\n                (Colorspace, mupdf.FzColorspace),\n                (mupdf.FzRect, mupdf.FzIrect, IRect, Rect, tuple)\n                ):\n            # create empty pixmap with colorspace and IRect\n            cs, rect = args\n            alpha = 0\n            pm = mupdf.fz_new_pixmap_with_bbox(cs, JM_irect_from_py(rect), mupdf.FzSeparations(0), alpha)\n            self.this = pm\n\n        elif args_match(args,\n                (Colorspace, mupdf.FzColorspace),\n                (mupdf.FzRect, mupdf.FzIrect, IRect, Rect, tuple),\n                (int, bool)\n                ):\n            # create empty pixmap with colorspace and IRect\n            cs, rect, alpha = args\n            pm = mupdf.fz_new_pixmap_with_bbox(cs, JM_irect_from_py(rect), mupdf.FzSeparations(0), alpha)\n            self.this = pm\n\n        elif args_match(args, (Colorspace, mupdf.FzColorspace, type(None)), (Pixmap, mupdf.FzPixmap)):\n            # copy pixmap, converting colorspace\n            cs, spix = args\n            if isinstance(cs, Colorspace):\n                cs = cs.this\n            elif cs is None:\n                cs = mupdf.FzColorspace(None)\n            if isinstance(spix, Pixmap):\n                spix = spix.this\n            if not mupdf.fz_pixmap_colorspace(spix).m_internal:\n                raise ValueError( \"source colorspace must not be None\")\n            \n            if cs.m_internal:\n                self.this = mupdf.fz_convert_pixmap(\n                        spix,\n                        cs,\n                        mupdf.FzColorspace(),\n                        mupdf.FzDefaultColorspaces(None),\n                        mupdf.FzColorParams(),\n                        1\n                        )\n            else:\n                self.this = mupdf.fz_new_pixmap_from_alpha_channel( spix)\n                if not self.this.m_internal:\n                    raise RuntimeError( MSG_PIX_NOALPHA)\n\n        elif args_match(args, (Pixmap, mupdf.FzPixmap), (Pixmap, mupdf.FzPixmap)):\n            # add mask to a pixmap w/o alpha channel\n            spix, mpix = args\n            if isinstance(spix, Pixmap):\n                spix = spix.this\n            if isinstance(mpix, Pixmap):\n                mpix = mpix.this\n            spm = spix\n            mpm = mpix\n            if not spix.m_internal: # intercept NULL for spix: make alpha only pix\n                dst = mupdf.fz_new_pixmap_from_alpha_channel(mpm)\n                if not dst.m_internal:\n                    raise RuntimeError( MSG_PIX_NOALPHA)\n            else:\n                dst = mupdf.fz_new_pixmap_from_color_and_mask(spm, mpm)\n            self.this = dst\n\n        elif (args_match(args, (Pixmap, mupdf.FzPixmap), (float, int), (float, int), None) or\n             args_match(args, (Pixmap, mupdf.FzPixmap), (float, int), (float, int))):\n            # create pixmap as scaled copy of another one\n            if len(args) == 3:\n                spix, w, h = args\n                bbox = mupdf.FzIrect(mupdf.fz_infinite_irect)\n            else:\n                spix, w, h, clip = args\n                bbox = JM_irect_from_py(clip)\n        \n            src_pix = spix.this if isinstance(spix, Pixmap) else spix\n            if not mupdf.fz_is_infinite_irect(bbox):\n                pm = mupdf.fz_scale_pixmap(src_pix, src_pix.x(), src_pix.y(), w, h, bbox)\n            else:\n                pm = mupdf.fz_scale_pixmap(src_pix, src_pix.x(), src_pix.y(), w, h, mupdf.FzIrect(mupdf.fz_infinite_irect))\n            self.this = pm\n\n        elif args_match(args, str, (Pixmap, mupdf.FzPixmap)) and args[0] == 'raw':\n            # Special raw construction where we set .this directly.\n            _, pm = args\n            if isinstance(pm, Pixmap):\n                pm = pm.this\n            self.this = pm\n\n        elif args_match(args, (Pixmap, mupdf.FzPixmap), (int, None)):\n            # Pixmap(struct Pixmap *spix, int alpha=1)\n            # copy pixmap & add / drop the alpha channel\n            spix = args[0]\n            alpha = args[1] if len(args) == 2 else 1\n            src_pix = spix.this if isinstance(spix, Pixmap) else spix\n            if not _INRANGE(alpha, 0, 1):\n                raise ValueError( \"bad alpha value\")\n            cs = mupdf.fz_pixmap_colorspace(src_pix)\n            if not cs.m_internal and not alpha:\n                raise ValueError( \"cannot drop alpha for 'NULL' colorspace\")\n            seps = mupdf.FzSeparations()\n            n = mupdf.fz_pixmap_colorants(src_pix)\n            w = mupdf.fz_pixmap_width(src_pix)\n            h = mupdf.fz_pixmap_height(src_pix)\n            pm = mupdf.fz_new_pixmap(cs, w, h, seps, alpha)\n            pm.m_internal.x = src_pix.m_internal.x\n            pm.m_internal.y = src_pix.m_internal.y\n            pm.m_internal.xres = src_pix.m_internal.xres\n            pm.m_internal.yres = src_pix.m_internal.yres\n\n            # copy samples data ------------------------------------------\n            if 1:\n                # We use our pixmap_copy() to get best performance.\n                # test_pixmap.py:test_setalpha(): 3.9s t=0.0062\n                extra.pixmap_copy( pm.m_internal, src_pix.m_internal, n)\n            elif 1:\n                # Use memoryview.\n                # test_pixmap.py:test_setalpha(): 4.6 t=0.51\n                src_view = mupdf.fz_pixmap_samples_memoryview( src_pix)\n                pm_view = mupdf.fz_pixmap_samples_memoryview( pm)\n                if src_pix.alpha() == pm.alpha():   # identical samples\n                    #memcpy(tptr, sptr, w * h * (n + alpha));\n                    size = w * h * (n + alpha)\n                    pm_view[ 0 : size] = src_view[ 0 : size]\n                else:\n                    tptr = 0\n                    sptr = 0\n                    # This is a little faster than calling\n                    # pm.fz_samples_set(), but still quite slow. E.g. reduces\n                    # test_pixmap.py:test_setalpha() from 6.7s to 4.5s.\n                    #\n                    # t=0.53\n                    pm_stride = pm.stride()\n                    pm_n = pm.n()\n                    pm_alpha = pm.alpha()\n                    src_stride = src_pix.stride()\n                    src_n = src_pix.n()\n                    #log(f'{pm_stride pm_n src_stride src_n=}')\n                    for y in range( h):\n                        for x in range( w):\n                            pm_i = pm_stride * y + pm_n * x\n                            src_i = src_stride * y + src_n * x\n                            pm_view[ pm_i : pm_i + n] = src_view[ src_i : src_i + n]\n                            if pm_alpha:\n                                pm_view[ pm_i + n] = 255\n            else:\n                # Copy individual bytes from Python. Very slow.\n                # test_pixmap.py:test_setalpha(): 6.89 t=2.601\n                if src_pix.alpha() == pm.alpha():   # identical samples\n                    #memcpy(tptr, sptr, w * h * (n + alpha));\n                    for i in range(w * h * (n + alpha)):\n                        mupdf.fz_samples_set(pm, i, mupdf.fz_samples_get(src_pix, i))\n                else:\n                    # t=2.56\n                    tptr = 0\n                    sptr = 0\n                    src_pix_alpha = src_pix.alpha()\n                    for i in range(w * h):\n                        #memcpy(tptr, sptr, n);\n                        for j in range(n):\n                            mupdf.fz_samples_set(pm, tptr + j, mupdf.fz_samples_get(src_pix, sptr + j))\n                        tptr += n\n                        if pm.alpha():\n                            mupdf.fz_samples_set(pm, tptr, 255)\n                            tptr += 1\n                        sptr += n + src_pix_alpha\n            self.this = pm\n\n        elif args_match(args, (mupdf.FzColorspace, Colorspace), int, int, None, (int, bool)):\n            # create pixmap from samples data\n            cs, w, h, samples, alpha = args\n            if isinstance(cs, Colorspace):\n                cs = cs.this\n                assert isinstance(cs, mupdf.FzColorspace)\n            n = mupdf.fz_colorspace_n(cs)\n            stride = (n + alpha) * w\n            seps = mupdf.FzSeparations()\n            pm = mupdf.fz_new_pixmap(cs, w, h, seps, alpha)\n\n            if isinstance( samples, (bytes, bytearray)):\n                #log('using mupdf.python_buffer_data()')\n                samples2 = mupdf.python_buffer_data(samples)\n                size = len(samples)\n            else:\n                res = JM_BufferFromBytes(samples)\n                if not res.m_internal:\n                    raise ValueError( \"bad samples data\")\n                size, c = mupdf.fz_buffer_storage(res)\n                samples2 = mupdf.python_buffer_data(samples) # raw swig proxy for `const unsigned char*`.\n            if stride * h != size:\n                raise ValueError( f\"bad samples length {w=} {h=} {alpha=} {n=} {stride=} {size=}\")\n            mupdf.ll_fz_pixmap_copy_raw( pm.m_internal, samples2)\n            self.this = pm\n\n        elif args_match(args, None):\n            # create pixmap from filename, file object, pathlib.Path or memory\n            imagedata, = args\n            name = 'name'\n            if hasattr(imagedata, \"resolve\"):\n                fname = imagedata.__str__()\n                if fname:\n                    img = mupdf.fz_new_image_from_file(fname)\n            elif hasattr(imagedata, name):\n                fname = imagedata.name\n                if fname:\n                    img = mupdf.fz_new_image_from_file(fname)\n            elif isinstance(imagedata, str):\n                img = mupdf.fz_new_image_from_file(imagedata)\n            else:\n                res = JM_BufferFromBytes(imagedata)\n                if not res.m_internal or not res.m_internal.len:\n                    raise ValueError( \"bad image data\")\n                img = mupdf.fz_new_image_from_buffer(res)\n\n            # Original code passed null for subarea and ctm, but that's not\n            # possible with MuPDF's python bindings. The equivalent is an\n            # infinite rect and identify matrix scaled by img.w() and img.h().\n            pm, w, h = mupdf.fz_get_pixmap_from_image(\n                    img,\n                    mupdf.FzIrect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT),\n                    mupdf.FzMatrix( img.w(), 0, 0, img.h(), 0, 0),\n                    )\n            xres, yres = mupdf.fz_image_resolution(img)\n            pm.m_internal.xres = xres\n            pm.m_internal.yres = yres\n            self.this = pm\n\n        elif args_match(args, (Document, mupdf.FzDocument), int):\n            # Create pixmap from PDF image identified by XREF number\n            doc, xref = args\n            pdf = _as_pdf_document(doc)\n            xreflen = mupdf.pdf_xref_len(pdf)\n            if not _INRANGE(xref, 1, xreflen-1):\n                raise ValueError( MSG_BAD_XREF)\n            ref = mupdf.pdf_new_indirect(pdf, xref, 0)\n            type_ = mupdf.pdf_dict_get(ref, PDF_NAME('Subtype'))\n            if (not mupdf.pdf_name_eq(type_, PDF_NAME('Image'))\n                    and not mupdf.pdf_name_eq(type_, PDF_NAME('Alpha'))\n                    and not mupdf.pdf_name_eq(type_, PDF_NAME('Luminosity'))\n                    ):\n                raise ValueError( MSG_IS_NO_IMAGE)\n            img = mupdf.pdf_load_image(pdf, ref)\n            # Original code passed null for subarea and ctm, but that's not\n            # possible with MuPDF's python bindings. The equivalent is an\n            # infinite rect and identify matrix scaled by img.w() and img.h().\n            pix, w, h = mupdf.fz_get_pixmap_from_image(\n                    img,\n                    mupdf.FzIrect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT),\n                    mupdf.FzMatrix(img.w(), 0, 0, img.h(), 0, 0),\n                    )\n            self.this = pix\n\n        else:\n            text = 'Unrecognised args for constructing Pixmap:\\n'\n            for arg in args:\n                text += f'    {type(arg)}: {arg}\\n'\n            raise Exception( text)\n\n    def __len__(self):\n        return self.size\n\n    def __repr__(self):\n        if not type(self) is Pixmap:\n            return\n        colorspace = \"none\"\n        if self.colorspace:\n            colorspace = self.colorspace.this.m_internal.name\n\n        return f\"Pixmap({colorspace}, {self.irect}, {self.alpha})\"\n\n    def _tobytes(self, format_, jpg_quality):\n        '''\n        Pixmap._tobytes\n        '''\n        pm = self.this\n        size = mupdf.fz_pixmap_stride(pm) * pm.h()\n        res = mupdf.fz_new_buffer(size)\n        out = mupdf.FzOutput(res)\n        if   format_ == 1:  mupdf.fz_write_pixmap_as_png(out, pm)\n        elif format_ == 2:  mupdf.fz_write_pixmap_as_pnm(out, pm)\n        elif format_ == 3:  mupdf.fz_write_pixmap_as_pam(out, pm)\n        elif format_ == 5:  mupdf.fz_write_pixmap_as_psd(out, pm)\n        elif format_ == 6:  mupdf.fz_write_pixmap_as_ps(out, pm)\n        elif format_ == 7:\n            mupdf.fz_write_pixmap_as_jpeg(out, pm, jpg_quality, 0)\n        else:\n            mupdf.fz_write_pixmap_as_png(out, pm)\n        out.fz_close_output()\n        barray = JM_BinFromBuffer(res)\n        return barray\n\n    def _writeIMG(self, filename, format_, jpg_quality):\n        pm = self.this\n        if   format_ == 1:  mupdf.fz_save_pixmap_as_png(pm, filename)\n        elif format_ == 2:  mupdf.fz_save_pixmap_as_pnm(pm, filename)\n        elif format_ == 3:  mupdf.fz_save_pixmap_as_pam(pm, filename)\n        elif format_ == 5:  mupdf.fz_save_pixmap_as_psd(pm, filename)\n        elif format_ == 6:  mupdf.fz_save_pixmap_as_ps(pm, filename)\n        elif format_ == 7:  mupdf.fz_save_pixmap_as_jpeg(pm, filename, jpg_quality)\n        else:               mupdf.fz_save_pixmap_as_png(pm, filename)\n\n    @property\n    def alpha(self):\n        \"\"\"Indicates presence of alpha channel.\"\"\"\n        return mupdf.fz_pixmap_alpha(self.this)\n\n    def clear_with(self, value=None, bbox=None):\n        \"\"\"Fill all color components with same value.\"\"\"\n        if value is None:\n            mupdf.fz_clear_pixmap(self.this)\n        elif bbox is None:\n            mupdf.fz_clear_pixmap_with_value(self.this, value)\n        else:\n            JM_clear_pixmap_rect_with_value(self.this, value, JM_irect_from_py(bbox))\n\n    def color_count(self, colors=0, clip=None):\n        '''\n        Return count of each color.\n        '''\n        pm = self.this\n        rc = JM_color_count( pm, clip)\n        if not colors:\n            return len( rc)\n        return rc\n\n    def color_topusage(self, clip=None):\n        \"\"\"Return most frequent color and its usage ratio.\"\"\"\n        allpixels = 0\n        cnt = 0\n        if clip is not None and self.irect in Rect(clip):\n            clip = self.irect\n        for pixel, count in self.color_count(colors=True,clip=clip).items():\n            allpixels += count\n            if count > cnt:\n                cnt = count\n                maxpixel = pixel\n        if not allpixels:\n            return (1, bytes([255] * self.n))\n        return (cnt / allpixels, maxpixel)\n\n    @property\n    def colorspace(self):\n        \"\"\"Pixmap Colorspace.\"\"\"\n        cs = Colorspace(mupdf.fz_pixmap_colorspace(self.this))\n        if cs.name == \"None\":\n            return None\n        return cs\n\n    def copy(self, src, bbox):\n        \"\"\"Copy bbox from another Pixmap.\"\"\"\n        pm = self.this\n        src_pix = src.this\n        if not mupdf.fz_pixmap_colorspace(src_pix):\n            raise ValueError( \"cannot copy pixmap with NULL colorspace\")\n        if pm.alpha() != src_pix.alpha():\n            raise ValueError( \"source and target alpha must be equal\")\n        mupdf.fz_copy_pixmap_rect(pm, src_pix, JM_irect_from_py(bbox), mupdf.FzDefaultColorspaces(None))\n\n    @property\n    def digest(self):\n        \"\"\"MD5 digest of pixmap (bytes).\"\"\"\n        ret = mupdf.fz_md5_pixmap2(self.this)\n        return bytes(ret)\n\n    def gamma_with(self, gamma):\n        \"\"\"Apply correction with some float.\n        gamma=1 is a no-op.\"\"\"\n        if not mupdf.fz_pixmap_colorspace( self.this):\n            message_warning(\"colorspace invalid for function\")\n            return\n        mupdf.fz_gamma_pixmap( self.this, gamma)\n\n    @property\n    def h(self):\n        \"\"\"The height.\"\"\"\n        return mupdf.fz_pixmap_height(self.this)\n\n    def invert_irect(self, bbox=None):\n        \"\"\"Invert the colors inside a bbox.\"\"\"\n        pm = self.this\n        if not mupdf.fz_pixmap_colorspace(pm).m_internal:\n            message_warning(\"ignored for stencil pixmap\")\n            return False\n        r = JM_irect_from_py(bbox)\n        if mupdf.fz_is_infinite_irect(r):\n            mupdf.fz_invert_pixmap(pm)\n            return True\n        mupdf.fz_invert_pixmap_rect(pm, r)\n        return True\n\n    @property\n    def irect(self):\n        \"\"\"Pixmap bbox - an IRect object.\"\"\"\n        val = mupdf.fz_pixmap_bbox(self.this)\n        return JM_py_from_irect( val)\n\n    @property\n    def is_monochrome(self):\n        \"\"\"Check if pixmap is monochrome.\"\"\"\n        return mupdf.fz_is_pixmap_monochrome( self.this)\n\n    @property\n    def is_unicolor(self):\n        '''\n        Check if pixmap has only one color.\n        '''\n        pm = self.this\n        n = pm.n()\n        count = pm.w() * pm.h() * n\n        def _pixmap_read_samples(pm, offset, n):\n            ret = list()\n            for i in range(n):\n                ret.append(mupdf.fz_samples_get(pm, offset+i))\n            return ret\n        for offset in range( 0, count, n):\n            if offset == 0:\n                sample0 = _pixmap_read_samples( pm, 0, n)\n            else:\n                sample = _pixmap_read_samples( pm, offset, n)\n                if sample != sample0:\n                    return False\n        return True\n\n    @property\n    def n(self):\n        \"\"\"The size of one pixel.\"\"\"\n        if g_use_extra:\n            # Setting self.__class__.n gives a small reduction in overhead of\n            # test_general.py:test_2093, e.g. 1.4x -> 1.3x.\n            #return extra.pixmap_n(self.this)\n            def n2(self):\n                return extra.pixmap_n(self.this)\n            self.__class__.n = property(n2)\n            return self.n\n        return mupdf.fz_pixmap_components(self.this)\n\n    def pdfocr_save(self, filename, compress=1, language=None, tessdata=None):\n        '''\n        Save pixmap as an OCR-ed PDF page.\n        '''\n        tessdata = get_tessdata(tessdata)\n        opts = mupdf.FzPdfocrOptions()\n        opts.compress = compress\n        if language:\n            opts.language_set2( language)\n        if tessdata:\n            opts.datadir_set2( tessdata)\n        pix = self.this\n        if isinstance(filename, str):\n            mupdf.fz_save_pixmap_as_pdfocr( pix, filename, 0, opts)\n        else:\n            out = JM_new_output_fileptr( filename)\n            try:\n                mupdf.fz_write_pixmap_as_pdfocr( out, pix, opts)\n            finally:\n                out.fz_close_output()   # Avoid MuPDF warning.\n\n    def pdfocr_tobytes(self, compress=True, language=\"eng\", tessdata=None):\n        \"\"\"Save pixmap as an OCR-ed PDF page.\n\n        Args:\n            compress: (bool) compress, default 1 (True).\n            language: (str) language(s) occurring on page, default \"eng\" (English),\n                    multiples like \"eng+ger\" for English and German.\n            tessdata: (str) folder name of Tesseract's language support. If None\n                    we use environment variable TESSDATA_PREFIX or search for\n                    Tesseract installation.\n        Notes:\n            On failure, make sure Tesseract is installed and you have set\n            <tessdata> or environment variable \"TESSDATA_PREFIX\" to the folder\n            containing your Tesseract's language support data.\n        \"\"\"\n        tessdata = get_tessdata(tessdata)\n        from io import BytesIO\n        bio = BytesIO()\n        self.pdfocr_save(bio, compress=compress, language=language, tessdata=tessdata)\n        return bio.getvalue()\n\n    def pil_image(self):\n        \"\"\"Create a Pillow Image from the Pixmap.\"\"\"\n        try:\n            from PIL import Image\n        except ImportError:\n            message(\"PIL/Pillow not installed\")\n            raise\n\n        cspace = self.colorspace\n        if not cspace:\n            mode = \"L\"\n        elif cspace.n == 1:\n            mode = \"L\" if not self.alpha else \"LA\"\n        elif cspace.n == 3:\n            mode = \"RGB\" if not self.alpha else \"RGBA\"\n        else:\n            mode = \"CMYK\"\n\n        img = Image.frombytes(mode, (self.width, self.height), self.samples)\n        return img\n\n    def pil_save(self, *args, **kwargs):\n        \"\"\"Write to image file using Pillow.\n\n        An intermediate PIL Image is created, and its \"save\" method is used\n        to store the image. See Pillow documentation to learn about the\n        meaning of possible positional and keyword parameters.\n        Use this when other output formats are desired.\n        \"\"\"\n        img = self.pil_image()\n\n        if \"dpi\" not in kwargs.keys():\n            kwargs[\"dpi\"] = (self.xres, self.yres)\n\n        img.save(*args, **kwargs)\n\n    def pil_tobytes(self, *args, **kwargs):\n        \"\"\"Convert to an image in memory using Pillow.\n\n        An intermediate PIL Image is created, and its \"save\" method is used\n        to store the image. See Pillow documentation to learn about the\n        meaning of possible positional or keyword parameters.\n        Use this when other output formats are desired.\n        \"\"\"\n        bytes_out = io.BytesIO()\n        img = self.pil_image()\n\n        if \"dpi\" not in kwargs.keys():\n            kwargs[\"dpi\"] = (self.xres, self.yres)\n\n        img.save(bytes_out, *args, **kwargs)\n        return bytes_out.getvalue()\n\n    def pixel(self, x, y):\n        \"\"\"Get color tuple of pixel (x, y).\n        Last item is the alpha if Pixmap.alpha is true.\"\"\"\n        if g_use_extra:\n            return extra.pixmap_pixel(self.this.m_internal, x, y)\n        if (0\n                or x < 0\n                or x >= self.this.m_internal.w\n                or y < 0\n                or y >= self.this.m_internal.h\n                ):\n            RAISEPY(MSG_PIXEL_OUTSIDE, PyExc_ValueError)\n        n = self.this.m_internal.n\n        stride = self.this.m_internal.stride\n        i = stride * y + n * x\n        ret = tuple( self.samples_mv[ i: i+n])\n        return ret\n\n    @property\n    def samples(self)->bytes:\n        mv = self.samples_mv\n        return bytes( mv)\n\n    @property\n    def samples_mv(self):\n        '''\n        Pixmap samples memoryview.\n        '''\n        # We remember the returned memoryview so that our `__del__()` can\n        # release it; otherwise accessing it after we have been destructed will\n        # fail, possibly crashing Python; this is #4155.\n        #\n        if self._samples_mv is None:\n            self._samples_mv = mupdf.fz_pixmap_samples_memoryview(self.this)\n        return self._samples_mv\n    \n    def _samples_mv_release(self):\n        if self._samples_mv:\n            self._samples_mv.release()\n\n    @property\n    def samples_ptr(self):\n        return mupdf.fz_pixmap_samples_int(self.this)\n\n    def save(self, filename, output=None, jpg_quality=95):\n        \"\"\"Output as image in format determined by filename extension.\n\n        Args:\n            output: (str) only use to overrule filename extension. Default is PNG.\n                    Others are JPEG, JPG, PNM, PGM, PPM, PBM, PAM, PSD, PS.\n        \"\"\"\n        valid_formats = {\n                \"png\": 1,\n                \"pnm\": 2,\n                \"pgm\": 2,\n                \"ppm\": 2,\n                \"pbm\": 2,\n                \"pam\": 3,\n                \"psd\": 5,\n                \"ps\": 6,\n                \"jpg\": 7,\n                \"jpeg\": 7,\n                }\n        \n        if type(filename) is str:\n            pass\n        elif hasattr(filename, \"absolute\"):\n            filename = str(filename)\n        elif hasattr(filename, \"name\"):\n            filename = filename.name\n        if output is None:\n            _, ext = os.path.splitext(filename)\n            output = ext[1:]\n\n        idx = valid_formats.get(output.lower(), None)\n        if idx is None:\n            raise ValueError(f\"Image format {output} not in {tuple(valid_formats.keys())}\")\n        if self.alpha and idx in (2, 6, 7):\n            raise ValueError(f\"'{output}' cannot have alpha\")\n        if self.colorspace and self.colorspace.n > 3 and idx in (1, 2, 4):\n            raise ValueError(f\"unsupported colorspace for '{output}'\")\n        if idx == 7:\n            self.set_dpi(self.xres, self.yres)\n        return self._writeIMG(filename, idx, jpg_quality)\n\n    def set_alpha(self, alphavalues=None, premultiply=1, opaque=None, matte=None):\n        \"\"\"Set alpha channel to values contained in a byte array.\n        If omitted, set alphas to 255.\n\n        Args:\n            alphavalues: (bytes) with length (width * height) or 'None'.\n            premultiply: (bool, True) premultiply colors with alpha values.\n            opaque: (tuple, length colorspace.n) this color receives opacity 0.\n            matte: (tuple, length colorspace.n)) preblending background color.\n        \"\"\"\n        pix = self.this\n        alpha = 0\n        m = 0\n        if pix.alpha() == 0:\n            raise ValueError( MSG_PIX_NOALPHA)\n        n = mupdf.fz_pixmap_colorants(pix)\n        w = mupdf.fz_pixmap_width(pix)\n        h = mupdf.fz_pixmap_height(pix)\n        balen = w * h * (n+1)\n        colors = [0, 0, 0, 0]   # make this color opaque\n        bgcolor = [0, 0, 0, 0]  # preblending background color\n        zero_out = 0\n        bground = 0\n        if opaque and isinstance(opaque, (list, tuple)) and len(opaque) == n:\n            for i in range(n):\n                colors[i] = opaque[i]\n            zero_out = 1\n        if matte and isinstance( matte, (tuple, list)) and len(matte) == n:\n            for i in range(n):\n                bgcolor[i] = matte[i]\n            bground = 1\n        data = bytes()\n        data_len = 0\n        if alphavalues:\n            #res = JM_BufferFromBytes(alphavalues)\n            #data_len, data = mupdf.fz_buffer_storage(res)\n            #if data_len < w * h:\n            #    THROWMSG(\"bad alpha values\")\n            # fixme: don't seem to need to create an fz_buffer - can\n            # use <alphavalues> directly?\n            if isinstance(alphavalues, (bytes, bytearray)):\n                data = alphavalues\n                data_len = len(alphavalues)\n            else:\n                assert 0, f'unexpected type for alphavalues: {type(alphavalues)}'\n            if data_len < w * h:\n                raise ValueError( \"bad alpha values\")\n        if 1:\n            # Use C implementation for speed.\n            mupdf.Pixmap_set_alpha_helper(\n                    balen,\n                    n,\n                    data_len,\n                    zero_out,\n                    mupdf.python_buffer_data( data),\n                    pix.m_internal,\n                    premultiply,\n                    bground,\n                    colors,\n                    bgcolor,\n                    )\n        else:\n            i = k = j = 0\n            data_fix = 255\n            while i < balen:\n                alpha = data[k]\n                if zero_out:\n                    for j in range(i, i+n):\n                        if mupdf.fz_samples_get(pix, j) != colors[j - i]:\n                            data_fix = 255\n                            break\n                        else:\n                            data_fix = 0\n                if data_len:\n                    def fz_mul255( a, b):\n                        x = a * b + 128\n                        x += x // 256\n                        return x // 256\n\n                    if data_fix == 0:\n                        mupdf.fz_samples_set(pix, i+n, 0)\n                    else:\n                        mupdf.fz_samples_set(pix, i+n, alpha)\n                    if premultiply and not bground:\n                        for j in range(i, i+n):\n                            mupdf.fz_samples_set(pix, j, fz_mul255( mupdf.fz_samples_get(pix, j), alpha))\n                    elif bground:\n                        for j in range( i, i+n):\n                            m = bgcolor[j - i]\n                            mupdf.fz_samples_set(pix, j, fz_mul255( mupdf.fz_samples_get(pix, j) - m, alpha))\n                else:\n                    mupdf.fz_samples_set(pix, i+n, data_fix)\n                i += n+1\n                k += 1\n\n    def tobytes(self, output=\"png\", jpg_quality=95):\n        '''\n        Convert to binary image stream of desired type.\n        '''\n        valid_formats = {\n                \"png\": 1,\n                \"pnm\": 2,\n                \"pgm\": 2,\n                \"ppm\": 2,\n                \"pbm\": 2,\n                \"pam\": 3,\n                \"tga\": 4,\n                \"tpic\": 4,\n                \"psd\": 5,\n                \"ps\": 6,\n                'jpg': 7,\n                'jpeg': 7,\n                }\n        idx = valid_formats.get(output.lower(), None)\n        if idx is None:\n            raise ValueError(f\"Image format {output} not in {tuple(valid_formats.keys())}\")\n        if self.alpha and idx in (2, 6, 7):\n            raise ValueError(\"'{output}' cannot have alpha\")\n        if self.colorspace and self.colorspace.n > 3 and idx in (1, 2, 4):\n            raise ValueError(f\"unsupported colorspace for '{output}'\")\n        if idx == 7:\n            self.set_dpi(self.xres, self.yres)\n        barray = self._tobytes(idx, jpg_quality)\n        return barray\n\n    def set_dpi(self, xres, yres):\n        \"\"\"Set resolution in both dimensions.\"\"\"\n        pm = self.this\n        pm.m_internal.xres = xres\n        pm.m_internal.yres = yres\n\n    def set_origin(self, x, y):\n        \"\"\"Set top-left coordinates.\"\"\"\n        pm = self.this\n        pm.m_internal.x = x\n        pm.m_internal.y = y\n\n    def set_pixel(self, x, y, color):\n        \"\"\"Set color of pixel (x, y).\"\"\"\n        if g_use_extra:\n            return extra.set_pixel(self.this.m_internal, x, y, color)\n        pm = self.this\n        if not _INRANGE(x, 0, pm.w() - 1) or not _INRANGE(y, 0, pm.h() - 1):\n            raise ValueError( MSG_PIXEL_OUTSIDE)\n        n = pm.n()\n        for j in range(n):\n            i = color[j]\n            if not _INRANGE(i, 0, 255):\n                raise ValueError( MSG_BAD_COLOR_SEQ)\n        stride = mupdf.fz_pixmap_stride( pm)\n        i = stride * y + n * x\n        if 0:\n            # Using a cached self._memory_view doesn't actually make much\n            # difference to speed.\n            if not self._memory_view:\n                self._memory_view = self.samples_mv\n            for j in range(n):\n                self._memory_view[i + j] = color[j]\n        else:\n            for j in range(n):\n                pm.fz_samples_set(i + j, color[j])\n\n    def set_rect(self, bbox, color):\n        \"\"\"Set color of all pixels in bbox.\"\"\"\n        pm = self.this\n        n = pm.n()\n        c = []\n        for j in range(n):\n            i = color[j]\n            if not _INRANGE(i, 0, 255):\n                raise ValueError( MSG_BAD_COLOR_SEQ)\n            c.append(i)\n        bbox = JM_irect_from_py(bbox)\n        i = JM_fill_pixmap_rect_with_color(pm, c, bbox)\n        rc = bool(i)\n        return rc\n\n    def shrink(self, factor):\n        \"\"\"Divide width and height by 2**factor.\n        E.g. factor=1 shrinks to 25% of original size (in place).\"\"\"\n        if factor < 1:\n            message_warning(\"ignoring shrink factor < 1\")\n            return\n        mupdf.fz_subsample_pixmap( self.this, factor)\n        # Pixmap has changed so clear our memory view.\n        self._memory_view = None\n        self._samples_mv_release()\n\n    @property\n    def size(self):\n        \"\"\"Pixmap size.\"\"\"\n        return  mupdf.fz_pixmap_size( self.this)\n\n    @property\n    def stride(self):\n        \"\"\"Length of one image line (width * n).\"\"\"\n        return self.this.stride()\n\n    def tint_with(self, black, white):\n        \"\"\"Tint colors with modifiers for black and white.\"\"\"\n        if not self.colorspace or self.colorspace.n > 3:\n            message(\"warning: colorspace invalid for function\")\n            return\n        return mupdf.fz_tint_pixmap( self.this, black, white)\n\n    @property\n    def w(self):\n        \"\"\"The width.\"\"\"\n        return mupdf.fz_pixmap_width(self.this)\n    \n    def warp(self, quad, width, height):\n        \"\"\"Return pixmap from a warped quad.\"\"\"\n        if not quad.is_convex: raise ValueError(\"quad must be convex\")\n        q = JM_quad_from_py(quad)\n        points = [ q.ul, q.ur, q.lr, q.ll]\n        dst = mupdf.fz_warp_pixmap( self.this, points, width, height)\n        return Pixmap( dst)\n\n    @property\n    def x(self):\n        \"\"\"x component of Pixmap origin.\"\"\"\n        return mupdf.fz_pixmap_x(self.this)\n\n    @property\n    def xres(self):\n        \"\"\"Resolution in x direction.\"\"\"\n        return self.this.xres()\n\n    @property\n    def y(self):\n        \"\"\"y component of Pixmap origin.\"\"\"\n        return mupdf.fz_pixmap_y(self.this)\n\n    @property\n    def yres(self):\n        \"\"\"Resolution in y direction.\"\"\"\n        return self.this.yres()\n\n    width  = w\n    height = h\n    \n    def __del__(self):\n        if self._samples_mv:\n            self._samples_mv.release()\n\n\nclass Point:\n\n    def __abs__(self):\n        return math.sqrt(self.x * self.x + self.y * self.y)\n\n    def __add__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Point(self.x + p, self.y + p)\n        if len(p) != 2:\n            raise ValueError(\"Point: bad seq len\")\n        return Point(self.x + p[0], self.y + p[1])\n\n    def __bool__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __eq__(self, p):\n        if not hasattr(p, \"__len__\"):\n            return False\n        return len(p) == 2 and not (self - p)\n\n    def __getitem__(self, i):\n        return (self.x, self.y)[i]\n\n    def __hash__(self):\n        return hash(tuple(self))\n\n    def __init__(self, *args, x=None, y=None):\n        '''\n        Point() - all zeros\n        Point(x, y)\n        Point(Point) - new copy\n        Point(sequence) - from 'sequence'\n\n        Explicit keyword args x, y override earlier settings if not None.\n        '''\n        if not args:\n            self.x = 0.0\n            self.y = 0.0\n        elif len(args) > 2:\n            raise ValueError(\"Point: bad seq len\")\n        elif len(args) == 2:\n            self.x = float(args[0])\n            self.y = float(args[1])\n        elif len(args) == 1:\n            l = args[0]\n            if isinstance(l, (mupdf.FzPoint, mupdf.fz_point)):\n                self.x = l.x\n                self.y = l.y\n            else:\n                if not hasattr(l, \"__getitem__\"):\n                    raise ValueError(\"Point: bad args\")\n                if len(l) != 2:\n                    raise ValueError(\"Point: bad seq len\")\n                self.x = float(l[0])\n                self.y = float(l[1])\n        else:\n            raise ValueError(\"Point: bad seq len\")\n        if x is not None:   self.x = x\n        if y is not None:   self.y = y\n\n    def __len__(self):\n        return 2\n\n    def __mul__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Point(self.x * m, self.y * m)\n        if hasattr(m, \"__getitem__\") and len(m) == 2:\n            # dot product\n            return self.x * m[0] + self.y * m[1]\n        p = Point(self)\n        return p.transform(m)\n\n    def __neg__(self):\n        return Point(-self.x, -self.y)\n\n    def __nonzero__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __pos__(self):\n        return Point(self)\n\n    def __repr__(self):\n        return \"Point\" + str(tuple(self))\n\n    def __setitem__(self, i, v):\n        v = float(v)\n        if   i == 0: self.x = v\n        elif i == 1: self.y = v\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __sub__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Point(self.x - p, self.y - p)\n        if len(p) != 2:\n            raise ValueError(\"Point: bad seq len\")\n        return Point(self.x - p[0], self.y - p[1])\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Point(self.x * 1./m, self.y * 1./m)\n        m1 = util_invert_matrix(m)[1]\n        if not m1:\n            raise ZeroDivisionError(\"matrix not invertible\")\n        p = Point(self)\n        return p.transform(m1)\n\n    @property\n    def abs_unit(self):\n        \"\"\"Unit vector with positive coordinates.\"\"\"\n        s = self.x * self.x + self.y * self.y\n        if s < EPSILON:\n            return Point(0,0)\n        s = math.sqrt(s)\n        return Point(abs(self.x) / s, abs(self.y) / s)\n\n    def distance_to(self, *args):\n        \"\"\"Return distance to rectangle or another point.\"\"\"\n        if not len(args) > 0:\n            raise ValueError(\"at least one parameter must be given\")\n\n        x = args[0]\n        if len(x) == 2:\n            x = Point(x)\n        elif len(x) == 4:\n            x = Rect(x)\n        else:\n            raise ValueError(\"arg1 must be point-like or rect-like\")\n\n        if len(args) > 1:\n            unit = args[1]\n        else:\n            unit = \"px\"\n        u = {\"px\": (1.,1.), \"in\": (1.,72.), \"cm\": (2.54, 72.),\n             \"mm\": (25.4, 72.)}\n        f = u[unit][0] / u[unit][1]\n\n        if type(x) is Point:\n            return abs(self - x) * f\n\n        # from here on, x is a rectangle\n        # as a safeguard, make a finite copy of it\n        r = Rect(x.top_left, x.top_left)\n        r = r | x.bottom_right\n        if self in r:\n            return 0.0\n        if self.x > r.x1:\n            if self.y >= r.y1:\n                return self.distance_to(r.bottom_right, unit)\n            elif self.y <= r.y0:\n                return self.distance_to(r.top_right, unit)\n            else:\n                return (self.x - r.x1) * f\n        elif r.x0 <= self.x <= r.x1:\n            if self.y >= r.y1:\n                return (self.y - r.y1) * f\n            else:\n                return (r.y0 - self.y) * f\n        else:\n            if self.y >= r.y1:\n                return self.distance_to(r.bottom_left, unit)\n            elif self.y <= r.y0:\n                return self.distance_to(r.top_left, unit)\n            else:\n                return (r.x0 - self.x) * f\n\n    def transform(self, m):\n        \"\"\"Replace point by its transformation with matrix-like m.\"\"\"\n        if len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.x, self.y = util_transform_point(self, m)\n        return self\n\n    @property\n    def unit(self):\n        \"\"\"Unit vector of the point.\"\"\"\n        s = self.x * self.x + self.y * self.y\n        if s < EPSILON:\n            return Point(0,0)\n        s = math.sqrt(s)\n        return Point(self.x / s, self.y / s)\n\n    __div__ = __truediv__\n    norm = __abs__\n\n\nclass Quad:\n\n    def __abs__(self):\n        if self.is_empty:\n            return 0.0\n        return abs(self.ul - self.ur) * abs(self.ul - self.ll)\n\n    def __add__(self, q):\n        if hasattr(q, \"__float__\"):\n            return Quad(self.ul + q, self.ur + q, self.ll + q, self.lr + q)\n        if len(q) != 4:\n            raise ValueError(\"Quad: bad seq len\")\n        return Quad(self.ul + q[0], self.ur + q[1], self.ll + q[2], self.lr + q[3])\n\n    def __bool__(self):\n        return not self.is_empty\n\n    def __contains__(self, x):\n        try:\n            l = x.__len__()\n        except Exception:\n            if g_exceptions_verbose > 1:    exception_info()\n            return False\n        if l == 2:\n            return util_point_in_quad(x, self)\n        if l != 4:\n            return False\n        if CheckRect(x):\n            if Rect(x).is_empty:\n                return True\n            return util_point_in_quad(x[:2], self) and util_point_in_quad(x[2:], self)\n        if CheckQuad(x):\n            for i in range(4):\n                if not util_point_in_quad(x[i], self):\n                    return False\n            return True\n        return False\n\n    def __eq__(self, quad):\n        if not hasattr(quad, \"__len__\"):\n            return False\n        return len(quad) == 4 and (\n            self.ul == quad[0] and\n            self.ur == quad[1] and\n            self.ll == quad[2] and\n            self.lr == quad[3]\n        )\n\n    def __getitem__(self, i):\n        return (self.ul, self.ur, self.ll, self.lr)[i]\n\n    def __hash__(self):\n        return hash(tuple(self))\n\n    def __init__(self, *args, ul=None, ur=None, ll=None, lr=None):\n        '''\n        Quad() - all zero points\n        Quad(ul, ur, ll, lr)\n        Quad(quad) - new copy\n        Quad(sequence) - from 'sequence'\n\n        Explicit keyword args ul, ur, ll, lr override earlier settings if not\n        None.\n    \n        '''\n        if not args:\n            self.ul = self.ur = self.ll = self.lr = Point()\n        elif len(args) > 4:\n            raise ValueError(\"Quad: bad seq len\")\n        elif len(args) == 4:\n            self.ul, self.ur, self.ll, self.lr = map(Point, args)\n        elif len(args) == 1:\n            l = args[0]\n            if isinstance(l, mupdf.FzQuad):\n                self.this = l\n                self.ul, self.ur, self.ll, self.lr = Point(l.ul), Point(l.ur), Point(l.ll), Point(l.lr)\n            elif not hasattr(l, \"__getitem__\"):\n                raise ValueError(\"Quad: bad args\")\n            elif len(l) != 4:\n                raise ValueError(\"Quad: bad seq len\")\n            else:\n                self.ul, self.ur, self.ll, self.lr = map(Point, l)\n        else:\n            raise ValueError(\"Quad: bad args\")\n        if ul is not None:  self.ul = Point(ul)\n        if ur is not None:  self.ur = Point(ur)\n        if ll is not None:  self.ll = Point(ll)\n        if lr is not None:  self.lr = Point(lr)\n\n    def __len__(self):\n        return 4\n\n    def __mul__(self, m):\n        q = Quad(self)\n        q = q.transform(m)\n        return q\n\n    def __neg__(self):\n        return Quad(-self.ul, -self.ur, -self.ll, -self.lr)\n\n    def __nonzero__(self):\n        return not self.is_empty\n\n    def __pos__(self):\n        return Quad(self)\n\n    def __repr__(self):\n        return \"Quad\" + str(tuple(self))\n\n    def __setitem__(self, i, v):\n        if   i == 0: self.ul = Point(v)\n        elif i == 1: self.ur = Point(v)\n        elif i == 2: self.ll = Point(v)\n        elif i == 3: self.lr = Point(v)\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __sub__(self, q):\n        if hasattr(q, \"__float__\"):\n            return Quad(self.ul - q, self.ur - q, self.ll - q, self.lr - q)\n        if len(q) != 4:\n            raise ValueError(\"Quad: bad seq len\")\n        return Quad(self.ul - q[0], self.ur - q[1], self.ll - q[2], self.lr - q[3])\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            im = 1. / m\n        else:\n            im = util_invert_matrix(m)[1]\n            if not im:\n                raise ZeroDivisionError(\"Matrix not invertible\")\n        q = Quad(self)\n        q = q.transform(im)\n        return q\n\n    @property\n    def is_convex(self):\n        \"\"\"Check if quad is convex and not degenerate.\n\n        Notes:\n            Check that for the two diagonals, the other two corners are not\n            on the same side of the diagonal.\n        Returns:\n            True or False.\n        \"\"\"\n        m = planish_line(self.ul, self.lr)  # puts this diagonal on x-axis\n        p1 = self.ll * m  # transform the\n        p2 = self.ur * m  # other two points\n        if p1.y * p2.y > 0:\n            return False\n        m = planish_line(self.ll, self.ur)  # puts other diagonal on x-axis\n        p1 = self.lr * m  # transform the\n        p2 = self.ul * m  # remaining points\n        if p1.y * p2.y > 0:\n            return False\n        return True\n\n    @property\n    def is_empty(self):\n        \"\"\"Check whether all quad corners are on the same line.\n\n        This is the case if width or height is zero.\n        \"\"\"\n        return self.width < EPSILON or self.height < EPSILON\n\n    @property\n    def is_infinite(self):\n        \"\"\"Check whether this is the infinite quad.\"\"\"\n        return self.rect.is_infinite\n\n    @property\n    def is_rectangular(self):\n        \"\"\"Check if quad is rectangular.\n\n        Notes:\n            Some rotation matrix can thus transform it into a rectangle.\n            This is equivalent to three corners enclose 90 degrees.\n        Returns:\n            True or False.\n        \"\"\"\n\n        sine = util_sine_between(self.ul, self.ur, self.lr)\n        if abs(sine - 1) > EPSILON:  # the sine of the angle\n            return False\n\n        sine = util_sine_between(self.ur, self.lr, self.ll)\n        if abs(sine - 1) > EPSILON:\n            return False\n\n        sine = util_sine_between(self.lr, self.ll, self.ul)\n        if abs(sine - 1) > EPSILON:\n            return False\n\n        return True\n\n    def morph(self, p, m):\n        \"\"\"Morph the quad with matrix-like 'm' and point-like 'p'.\n\n        Return a new quad.\"\"\"\n        if self.is_infinite:\n            return INFINITE_QUAD()\n        delta = Matrix(1, 1).pretranslate(p.x, p.y)\n        q = self * ~delta * m * delta\n        return q\n\n    @property\n    def rect(self):\n        r = Rect()\n        r.x0 = min(self.ul.x, self.ur.x, self.lr.x, self.ll.x)\n        r.y0 = min(self.ul.y, self.ur.y, self.lr.y, self.ll.y)\n        r.x1 = max(self.ul.x, self.ur.x, self.lr.x, self.ll.x)\n        r.y1 = max(self.ul.y, self.ur.y, self.lr.y, self.ll.y)\n        return r\n\n    def transform(self, m):\n        \"\"\"Replace quad by its transformation with matrix m.\"\"\"\n        if hasattr(m, \"__float__\"):\n            pass\n        elif len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.ul *= m\n        self.ur *= m\n        self.ll *= m\n        self.lr *= m\n        return self\n\n    __div__ = __truediv__\n    width  = property(lambda self: max(abs(self.ul - self.ur), abs(self.ll - self.lr)))\n    height = property(lambda self: max(abs(self.ul - self.ll), abs(self.ur - self.lr)))\n\n\nclass Rect:\n    \n    def __abs__(self):\n        if self.is_empty or self.is_infinite:\n            return 0.0\n        return (self.x1 - self.x0) * (self.y1 - self.y0)\n\n    def __add__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Rect(self.x0 + p, self.y0 + p, self.x1 + p, self.y1 + p)\n        if len(p) != 4:\n            raise ValueError(\"Rect: bad seq len\")\n        return Rect(self.x0 + p[0], self.y0 + p[1], self.x1 + p[2], self.y1 + p[3])\n\n    def __and__(self, x):\n        if not hasattr(x, \"__len__\"):\n            raise ValueError(\"bad operand 2\")\n\n        r1 = Rect(x)\n        r = Rect(self)\n        return r.intersect(r1)\n\n    def __bool__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __contains__(self, x):\n        if hasattr(x, \"__float__\"):\n            return x in tuple(self)\n        l = len(x)\n        if l == 2:\n            return util_is_point_in_rect(x, self)\n        if l == 4:\n            r = INFINITE_RECT()\n            try:\n                r = Rect(x)\n            except Exception:\n                if g_exceptions_verbose > 1:    exception_info()\n                r = Quad(x).rect\n            return (self.x0 <= r.x0 <= r.x1 <= self.x1 and\n                    self.y0 <= r.y0 <= r.y1 <= self.y1)\n        return False\n\n    def __eq__(self, rect):\n        if not hasattr(rect, \"__len__\"):\n            return False\n        return len(rect) == 4 and not (self - rect)\n\n    def __getitem__(self, i):\n        return (self.x0, self.y0, self.x1, self.y1)[i]\n\n    def __hash__(self):\n        return hash(tuple(self))\n\n    def __init__(self, *args, p0=None, p1=None, x0=None, y0=None, x1=None, y1=None):\n        \"\"\"\n        Rect() - all zeros\n        Rect(x0, y0, x1, y1)\n        Rect(top-left, x1, y1)\n        Rect(x0, y0, bottom-right)\n        Rect(top-left, bottom-right)\n        Rect(Rect or IRect) - new copy\n        Rect(sequence) - from 'sequence'\n    \n        Explicit keyword args p0, p1, x0, y0, x1, y1 override earlier settings\n        if not None.\n        \"\"\"\n        x0, y0, x1, y1 = util_make_rect( *args, p0=p0, p1=p1, x0=x0, y0=y0, x1=x1, y1=y1)\n        self.x0 = float( x0)\n        self.y0 = float( y0)\n        self.x1 = float( x1)\n        self.y1 = float( y1)\n\n    def __len__(self):\n        return 4\n\n    def __mul__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Rect(self.x0 * m, self.y0 * m, self.x1 * m, self.y1 * m)\n        r = Rect(self)\n        r = r.transform(m)\n        return r\n\n    def __neg__(self):\n        return Rect(-self.x0, -self.y0, -self.x1, -self.y1)\n\n    def __nonzero__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __or__(self, x):\n        if not hasattr(x, \"__len__\"):\n            raise ValueError(\"bad operand 2\")\n        r = Rect(self)\n        if len(x) == 2:\n            return r.include_point(x)\n        if len(x) == 4:\n            return r.include_rect(x)\n        raise ValueError(\"bad operand 2\")\n\n    def __pos__(self):\n        return Rect(self)\n\n    def __repr__(self):\n        return \"Rect\" + str(tuple(self))\n\n    def __setitem__(self, i, v):\n        v = float(v)\n        if   i == 0: self.x0 = v\n        elif i == 1: self.y0 = v\n        elif i == 2: self.x1 = v\n        elif i == 3: self.y1 = v\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __sub__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Rect(self.x0 - p, self.y0 - p, self.x1 - p, self.y1 - p)\n        if len(p) != 4:\n            raise ValueError(\"Rect: bad seq len\")\n        return Rect(self.x0 - p[0], self.y0 - p[1], self.x1 - p[2], self.y1 - p[3])\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Rect(self.x0 * 1./m, self.y0 * 1./m, self.x1 * 1./m, self.y1 * 1./m)\n        im = util_invert_matrix(m)[1]\n        if not im:\n            raise ZeroDivisionError(f\"Matrix not invertible: {m}\")\n        r = Rect(self)\n        r = r.transform(im)\n        return r\n\n    @property\n    def bottom_left(self):\n        \"\"\"Bottom-left corner.\"\"\"\n        return Point(self.x0, self.y1)\n\n    @property\n    def bottom_right(self):\n        \"\"\"Bottom-right corner.\"\"\"\n        return Point(self.x1, self.y1)\n\n    def contains(self, x):\n        \"\"\"Check if containing point-like or rect-like x.\"\"\"\n        return self.__contains__(x)\n\n    @property\n    def height(self):\n        return max(0, self.y1 - self.y0)\n\n    def get_area(self, *args) -> float:\n        \"\"\"Calculate area of rectangle.\\nparameter is one of 'px' (default), 'in', 'cm', or 'mm'.\"\"\"\n        return _rect_area(self.width, self.height, args)\n\n    def include_point(self, p):\n        \"\"\"Extend to include point-like p.\"\"\"\n        if len(p) != 2:\n            raise ValueError(\"Point: bad seq len\")\n        self.x0, self.y0, self.x1, self.y1 = util_include_point_in_rect(self, p)\n        return self\n\n    def include_rect(self, r):\n        \"\"\"Extend to include rect-like r.\"\"\"\n        if len(r) != 4:\n            raise ValueError(\"Rect: bad seq len\")\n        r = Rect(r)\n        if r.is_infinite or self.is_infinite:\n            self.x0, self.y0, self.x1, self.y1 = FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT\n        elif r.is_empty:\n            return self\n        elif self.is_empty:\n            self.x0, self.y0, self.x1, self.y1 = r.x0, r.y0, r.x1, r.y1\n        else:\n            self.x0, self.y0, self.x1, self.y1 = util_union_rect(self, r)\n        return self\n\n    def intersect(self, r):\n        \"\"\"Restrict to common rect with rect-like r.\"\"\"\n        if not len(r) == 4:\n            raise ValueError(\"Rect: bad seq len\")\n        r = Rect(r)\n        if r.is_infinite:\n            return self\n        elif self.is_infinite:\n            self.x0, self.y0, self.x1, self.y1 = r.x0, r.y0, r.x1, r.y1\n        elif r.is_empty:\n            self.x0, self.y0, self.x1, self.y1 = r.x0, r.y0, r.x1, r.y1\n        elif self.is_empty:\n            return self\n        else:\n            self.x0, self.y0, self.x1, self.y1 = util_intersect_rect(self, r)\n        return self\n\n    def intersects(self, x):\n        \"\"\"Check if intersection with rectangle x is not empty.\"\"\"\n        rect2 = Rect(x)\n        return (1\n                and not self.is_empty\n                and not self.is_infinite\n                and not rect2.is_empty\n                and not rect2.is_infinite\n                and self.x0 < rect2.x1\n                and rect2.x0 < self.x1\n                and self.y0 < rect2.y1\n                and rect2.y0 < self.y1\n               )\n\n    @property\n    def is_empty(self):\n        \"\"\"True if rectangle area is empty.\"\"\"\n        return self.x0 >= self.x1 or self.y0 >= self.y1\n\n    @property\n    def is_infinite(self):\n        \"\"\"True if this is the infinite rectangle.\"\"\"\n        return self.x0 == self.y0 == FZ_MIN_INF_RECT and self.x1 == self.y1 == FZ_MAX_INF_RECT\n\n    @property\n    def is_valid(self):\n        \"\"\"True if rectangle is valid.\"\"\"\n        return self.x0 <= self.x1 and self.y0 <= self.y1\n\n    def morph(self, p, m):\n        \"\"\"Morph with matrix-like m and point-like p.\n\n        Returns a new quad.\"\"\"\n        if self.is_infinite:\n            return INFINITE_QUAD()\n        return self.quad.morph(p, m)\n\n    def norm(self):\n        return math.sqrt(sum([c*c for c in self]))\n\n    def normalize(self):\n        \"\"\"Replace rectangle with its finite version.\"\"\"\n        if self.x1 < self.x0:\n            self.x0, self.x1 = self.x1, self.x0\n        if self.y1 < self.y0:\n            self.y0, self.y1 = self.y1, self.y0\n        return self\n\n    @property\n    def quad(self):\n        \"\"\"Return Quad version of rectangle.\"\"\"\n        return Quad(self.tl, self.tr, self.bl, self.br)\n\n    def round(self):\n        \"\"\"Return the IRect.\"\"\"\n        return IRect(util_round_rect(self))\n\n    @property\n    def top_left(self):\n        \"\"\"Top-left corner.\"\"\"\n        return Point(self.x0, self.y0)\n\n    @property\n    def top_right(self):\n        \"\"\"Top-right corner.\"\"\"\n        return Point(self.x1, self.y0)\n    \n    def torect(self, r):\n        \"\"\"Return matrix that converts to target rect.\"\"\"\n\n        r = Rect(r)\n        if self.is_infinite or self.is_empty or r.is_infinite or r.is_empty:\n            raise ValueError(\"rectangles must be finite and not empty\")\n        return (\n            Matrix(1, 0, 0, 1, -self.x0, -self.y0)\n            * Matrix(r.width / self.width, r.height / self.height)\n            * Matrix(1, 0, 0, 1, r.x0, r.y0)\n        )\n\n    def transform(self, m):\n        \"\"\"Replace with the transformation by matrix-like m.\"\"\"\n        if not len(m) == 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.x0, self.y0, self.x1, self.y1 = util_transform_rect(self, m)\n        return self\n\n    @property\n    def width(self):\n        return max(0, self.x1 - self.x0)\n\n    __div__ = __truediv__\n\n    bl = bottom_left\n    br = bottom_right\n    irect = property(round)\n    tl = top_left\n    tr = top_right\n\n\nclass Shape:\n    \"\"\"Create a new shape.\"\"\"\n\n    @staticmethod\n    def horizontal_angle(C, P):\n        \"\"\"Return the angle to the horizontal for the connection from C to P.\n        This uses the arcus sine function and resolves its inherent ambiguity by\n        looking up in which quadrant vector S = P - C is located.\n        \"\"\"\n        S = Point(P - C).unit  # unit vector 'C' -> 'P'\n        alfa = math.asin(abs(S.y))  # absolute angle from horizontal\n        if S.x < 0:  # make arcsin result unique\n            if S.y <= 0:  # bottom-left\n                alfa = -(math.pi - alfa)\n            else:  # top-left\n                alfa = math.pi - alfa\n        else:\n            if S.y >= 0:  # top-right\n                pass\n            else:  # bottom-right\n                alfa = -alfa\n        return alfa\n\n    def __init__(self, page: Page):\n        CheckParent(page)\n        self.page = page\n        self.doc = page.parent\n        if not self.doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        self.height = page.mediabox_size.y\n        self.width = page.mediabox_size.x\n        self.x = page.cropbox_position.x\n        self.y = page.cropbox_position.y\n\n        self.pctm = page.transformation_matrix  # page transf. matrix\n        self.ipctm = ~self.pctm  # inverted transf. matrix\n\n        self.draw_cont = \"\"\n        self.text_cont = \"\"\n        self.totalcont = \"\"\n        self.last_point = None\n        self.rect = None\n\n    def updateRect(self, x):\n        if self.rect is None:\n            if len(x) == 2:\n                self.rect = Rect(x, x)\n            else:\n                self.rect = Rect(x)\n\n        else:\n            if len(x) == 2:\n                x = Point(x)\n                self.rect.x0 = min(self.rect.x0, x.x)\n                self.rect.y0 = min(self.rect.y0, x.y)\n                self.rect.x1 = max(self.rect.x1, x.x)\n                self.rect.y1 = max(self.rect.y1, x.y)\n            else:\n                x = Rect(x)\n                self.rect.x0 = min(self.rect.x0, x.x0)\n                self.rect.y0 = min(self.rect.y0, x.y0)\n                self.rect.x1 = max(self.rect.x1, x.x1)\n                self.rect.y1 = max(self.rect.y1, x.y1)\n\n    def draw_line(self, p1: point_like, p2: point_like) -> Point:\n        \"\"\"Draw a line between two points.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        if not (self.last_point == p1):\n            self.draw_cont += _format_g(JM_TUPLE(p1 * self.ipctm)) + \" m\\n\"\n            self.last_point = p1\n            self.updateRect(p1)\n\n        self.draw_cont += _format_g(JM_TUPLE(p2 * self.ipctm)) + \" l\\n\"\n        self.updateRect(p2)\n        self.last_point = p2\n        return self.last_point\n\n    def draw_polyline(self, points: list) -> Point:\n        \"\"\"Draw several connected line segments.\"\"\"\n        for i, p in enumerate(points):\n            if i == 0:\n                if not (self.last_point == Point(p)):\n                    self.draw_cont += _format_g(JM_TUPLE(Point(p) * self.ipctm)) + \" m\\n\"\n                    self.last_point = Point(p)\n            else:\n                self.draw_cont += _format_g(JM_TUPLE(Point(p) * self.ipctm)) + \" l\\n\"\n            self.updateRect(p)\n\n        self.last_point = Point(points[-1])\n        return self.last_point\n\n    def draw_bezier(\n        self,\n        p1: point_like,\n        p2: point_like,\n        p3: point_like,\n        p4: point_like,\n    ) -> Point:\n        \"\"\"Draw a standard cubic Bezier curve.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        p3 = Point(p3)\n        p4 = Point(p4)\n        if not (self.last_point == p1):\n            self.draw_cont += _format_g(JM_TUPLE(p1 * self.ipctm)) + \" m\\n\"\n        args = JM_TUPLE(list(p2 * self.ipctm) + list(p3 * self.ipctm) + list(p4 * self.ipctm))\n        self.draw_cont += _format_g(args) + \" c\\n\"\n        self.updateRect(p1)\n        self.updateRect(p2)\n        self.updateRect(p3)\n        self.updateRect(p4)\n        self.last_point = p4\n        return self.last_point\n\n    def draw_oval(self, tetra: typing.Union[quad_like, rect_like]) -> Point:\n        \"\"\"Draw an ellipse inside a tetrapod.\"\"\"\n        if len(tetra) != 4:\n            raise ValueError(\"invalid arg length\")\n        if hasattr(tetra[0], \"__float__\"):\n            q = Rect(tetra).quad\n        else:\n            q = Quad(tetra)\n\n        mt = q.ul + (q.ur - q.ul) * 0.5\n        mr = q.ur + (q.lr - q.ur) * 0.5\n        mb = q.ll + (q.lr - q.ll) * 0.5\n        ml = q.ul + (q.ll - q.ul) * 0.5\n        if not (self.last_point == ml):\n            self.draw_cont += _format_g(JM_TUPLE(ml * self.ipctm)) + \" m\\n\"\n            self.last_point = ml\n        self.draw_curve(ml, q.ll, mb)\n        self.draw_curve(mb, q.lr, mr)\n        self.draw_curve(mr, q.ur, mt)\n        self.draw_curve(mt, q.ul, ml)\n        self.updateRect(q.rect)\n        self.last_point = ml\n        return self.last_point\n\n    def draw_circle(self, center: point_like, radius: float) -> Point:\n        \"\"\"Draw a circle given its center and radius.\"\"\"\n        if not radius > EPSILON:\n            raise ValueError(\"radius must be positive\")\n        center = Point(center)\n        p1 = center - (radius, 0)\n        return self.draw_sector(center, p1, 360, fullSector=False)\n\n    def draw_curve(\n        self,\n        p1: point_like,\n        p2: point_like,\n        p3: point_like,\n    ) -> Point:\n        \"\"\"Draw a curve between points using one control point.\"\"\"\n        kappa = 0.55228474983\n        p1 = Point(p1)\n        p2 = Point(p2)\n        p3 = Point(p3)\n        k1 = p1 + (p2 - p1) * kappa\n        k2 = p3 + (p2 - p3) * kappa\n        return self.draw_bezier(p1, k1, k2, p3)\n\n    def draw_sector(\n        self,\n        center: point_like,\n        point: point_like,\n        beta: float,\n        fullSector: bool = True,\n    ) -> Point:\n        \"\"\"Draw a circle sector.\"\"\"\n        center = Point(center)\n        point = Point(point)\n        l3 = lambda a, b: _format_g((a, b)) + \" m\\n\"\n        l4 = lambda a, b, c, d, e, f: _format_g((a, b, c, d, e, f)) + \" c\\n\"\n        l5 = lambda a, b: _format_g((a, b)) + \" l\\n\"\n        betar = math.radians(-beta)\n        w360 = math.radians(math.copysign(360, betar)) * (-1)\n        w90 = math.radians(math.copysign(90, betar))\n        w45 = w90 / 2\n        while abs(betar) > 2 * math.pi:\n            betar += w360  # bring angle below 360 degrees\n        if not (self.last_point == point):\n            self.draw_cont += l3(*JM_TUPLE(point * self.ipctm))\n            self.last_point = point\n        Q = Point(0, 0)  # just make sure it exists\n        C = center\n        P = point\n        S = P - C  # vector 'center' -> 'point'\n        rad = abs(S)  # circle radius\n\n        if not rad > EPSILON:\n            raise ValueError(\"radius must be positive\")\n\n        alfa = self.horizontal_angle(center, point)\n        while abs(betar) > abs(w90):  # draw 90 degree arcs\n            q1 = C.x + math.cos(alfa + w90) * rad\n            q2 = C.y + math.sin(alfa + w90) * rad\n            Q = Point(q1, q2)  # the arc's end point\n            r1 = C.x + math.cos(alfa + w45) * rad / math.cos(w45)\n            r2 = C.y + math.sin(alfa + w45) * rad / math.cos(w45)\n            R = Point(r1, r2)  # crossing point of tangents\n            kappah = (1 - math.cos(w45)) * 4 / 3 / abs(R - Q)\n            kappa = kappah * abs(P - Q)\n            cp1 = P + (R - P) * kappa  # control point 1\n            cp2 = Q + (R - Q) * kappa  # control point 2\n            self.draw_cont += l4(*JM_TUPLE(\n                list(cp1 * self.ipctm) + list(cp2 * self.ipctm) + list(Q * self.ipctm)\n            ))\n\n            betar -= w90  # reduce param angle by 90 deg\n            alfa += w90  # advance start angle by 90 deg\n            P = Q  # advance to arc end point\n        # draw (remaining) arc\n        if abs(betar) > 1e-3:  # significant degrees left?\n            beta2 = betar / 2\n            q1 = C.x + math.cos(alfa + betar) * rad\n            q2 = C.y + math.sin(alfa + betar) * rad\n            Q = Point(q1, q2)  # the arc's end point\n            r1 = C.x + math.cos(alfa + beta2) * rad / math.cos(beta2)\n            r2 = C.y + math.sin(alfa + beta2) * rad / math.cos(beta2)\n            R = Point(r1, r2)  # crossing point of tangents\n            # kappa height is 4/3 of segment height\n            kappah = (1 - math.cos(beta2)) * 4 / 3 / abs(R - Q)  # kappa height\n            kappa = kappah * abs(P - Q) / (1 - math.cos(betar))\n            cp1 = P + (R - P) * kappa  # control point 1\n            cp2 = Q + (R - Q) * kappa  # control point 2\n            self.draw_cont += l4(*JM_TUPLE(\n                list(cp1 * self.ipctm) + list(cp2 * self.ipctm) + list(Q * self.ipctm)\n            ))\n        if fullSector:\n            self.draw_cont += l3(*JM_TUPLE(point * self.ipctm))\n            self.draw_cont += l5(*JM_TUPLE(center * self.ipctm))\n            self.draw_cont += l5(*JM_TUPLE(Q * self.ipctm))\n        self.last_point = Q\n        return self.last_point\n\n    def draw_rect(self, rect: rect_like, *, radius=None) -> Point:\n        \"\"\"Draw a rectangle.\n\n        Args:\n            radius: if not None, the rectangle will have rounded corners.\n                This is the radius of the curvature, given as percentage of\n                the rectangle width or height. Valid are values 0 < v <= 0.5.\n                For a sequence of two values, the corners will have different\n                radii. Otherwise, the percentage will be computed from the\n                shorter side. A value of (0.5, 0.5) will draw an ellipse.\n        \"\"\"\n        r = Rect(rect)\n        if radius is None:  # standard rectangle\n            self.draw_cont += _format_g(JM_TUPLE(\n                list(r.bl * self.ipctm) + [r.width, r.height]\n            )) + \" re\\n\"\n            self.updateRect(r)\n            self.last_point = r.tl\n            return self.last_point\n        # rounded corners requested. This requires 1 or 2 values, each\n        # with 0 < value <= 0.5\n        if hasattr(radius, \"__float__\"):\n            if radius <= 0 or radius > 0.5:\n                raise ValueError(f\"bad radius value {radius}.\")\n            d = min(r.width, r.height) * radius\n            px = (d, 0)\n            py = (0, d)\n        elif hasattr(radius, \"__len__\") and len(radius) == 2:\n            rx, ry = radius\n            px = (rx * r.width, 0)\n            py = (0, ry * r.height)\n            if min(rx, ry) <= 0 or max(rx, ry) > 0.5:\n                raise ValueError(f\"bad radius value {radius}.\")\n        else:\n            raise ValueError(f\"bad radius value {radius}.\")\n\n        lp = self.draw_line(r.tl + py, r.bl - py)\n        lp = self.draw_curve(lp, r.bl, r.bl + px)\n\n        lp = self.draw_line(lp, r.br - px)\n        lp = self.draw_curve(lp, r.br, r.br - py)\n\n        lp = self.draw_line(lp, r.tr + py)\n        lp = self.draw_curve(lp, r.tr, r.tr - px)\n\n        lp = self.draw_line(lp, r.tl + px)\n        self.last_point = self.draw_curve(lp, r.tl, r.tl + py)\n\n        self.updateRect(r)\n        return self.last_point\n\n    def draw_quad(self, quad: quad_like) -> Point:\n        \"\"\"Draw a Quad.\"\"\"\n        q = Quad(quad)\n        return self.draw_polyline([q.ul, q.ll, q.lr, q.ur, q.ul])\n\n    def draw_zigzag(\n        self,\n        p1: point_like,\n        p2: point_like,\n        breadth: float = 2,\n    ) -> Point:\n        \"\"\"Draw a zig-zagged line from p1 to p2.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        S = p2 - p1  # vector start - end\n        rad = abs(S)  # distance of points\n        cnt = 4 * int(round(rad / (4 * breadth), 0))  # always take full phases\n        if cnt < 4:\n            raise ValueError(\"points too close\")\n        mb = rad / cnt  # revised breadth\n        matrix = Matrix(util_hor_matrix(p1, p2))  # normalize line to x-axis\n        i_mat = ~matrix  # get original position\n        points = []  # stores edges\n        for i in range(1, cnt):\n            if i % 4 == 1:  # point \"above\" connection\n                p = Point(i, -1) * mb\n            elif i % 4 == 3:  # point \"below\" connection\n                p = Point(i, 1) * mb\n            else:  # ignore others\n                continue\n            points.append(p * i_mat)\n        self.draw_polyline([p1] + points + [p2])  # add start and end points\n        return p2\n\n    def draw_squiggle(\n        self,\n        p1: point_like,\n        p2: point_like,\n        breadth=2,\n    ) -> Point:\n        \"\"\"Draw a squiggly line from p1 to p2.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        S = p2 - p1  # vector start - end\n        rad = abs(S)  # distance of points\n        cnt = 4 * int(round(rad / (4 * breadth), 0))  # always take full phases\n        if cnt < 4:\n            raise ValueError(\"points too close\")\n        mb = rad / cnt  # revised breadth\n        matrix = Matrix(util_hor_matrix(p1, p2))  # normalize line to x-axis\n        i_mat = ~matrix  # get original position\n        k = 2.4142135623765633  # y of draw_curve helper point\n\n        points = []  # stores edges\n        for i in range(1, cnt):\n            if i % 4 == 1:  # point \"above\" connection\n                p = Point(i, -k) * mb\n            elif i % 4 == 3:  # point \"below\" connection\n                p = Point(i, k) * mb\n            else:  # else on connection line\n                p = Point(i, 0) * mb\n            points.append(p * i_mat)\n\n        points = [p1] + points + [p2]\n        cnt = len(points)\n        i = 0\n        while i + 2 < cnt:\n            self.draw_curve(points[i], points[i + 1], points[i + 2])\n            i += 2\n        return p2\n\n    # ==============================================================================\n    # Shape.insert_text\n    # ==============================================================================\n    def insert_text(\n        self,\n        point: point_like,\n        buffer: typing.Union[str, list],\n        *,\n        fontsize: float = 11,\n        lineheight: OptFloat = None,\n        fontname: str = \"helv\",\n        fontfile: OptStr = None,\n        set_simple: bool = 0,\n        encoding: int = 0,\n        color: OptSeq = None,\n        fill: OptSeq = None,\n        render_mode: int = 0,\n        border_width: float = 0.05,\n        miter_limit: float = 1,\n        rotate: int = 0,\n        morph: OptSeq = None,\n        stroke_opacity: float = 1,\n        fill_opacity: float = 1,\n        oc: int = 0,\n    ) -> int:\n\n        # ensure 'text' is a list of strings, worth dealing with\n        if not bool(buffer):\n            return 0\n\n        if type(buffer) not in (list, tuple):\n            text = buffer.splitlines()\n        else:\n            text = buffer\n\n        if not len(text) > 0:\n            return 0\n\n        point = Point(point)\n        try:\n            maxcode = max([ord(c) for c in \" \".join(text)])\n        except Exception:\n            exception_info()\n            return 0\n\n        # ensure valid 'fontname'\n        fname = fontname\n        if fname.startswith(\"/\"):\n            fname = fname[1:]\n\n        xref = self.page.insert_font(\n            fontname=fname, fontfile=fontfile, encoding=encoding, set_simple=set_simple\n        )\n        fontinfo = CheckFontInfo(self.doc, xref)\n\n        fontdict = fontinfo[1]\n        ordering = fontdict[\"ordering\"]\n        simple = fontdict[\"simple\"]\n        bfname = fontdict[\"name\"]\n        ascender = fontdict[\"ascender\"]\n        descender = fontdict[\"descender\"]\n        if lineheight:\n            lheight = fontsize * lineheight\n        elif ascender - descender <= 1:\n            lheight = fontsize * 1.2\n        else:\n            lheight = fontsize * (ascender - descender)\n\n        if maxcode > 255:\n            glyphs = self.doc.get_char_widths(xref, maxcode + 1)\n        else:\n            glyphs = fontdict[\"glyphs\"]\n\n        tab = []\n        for t in text:\n            if simple and bfname not in (\"Symbol\", \"ZapfDingbats\"):\n                g = None\n            else:\n                g = glyphs\n            tab.append(getTJstr(t, g, simple, ordering))\n        text = tab\n\n        color_str = ColorCode(color, \"c\")\n        fill_str = ColorCode(fill, \"f\")\n        if not fill and render_mode == 0:  # ensure fill color when 0 Tr\n            fill = color\n            fill_str = ColorCode(color, \"f\")\n\n        morphing = CheckMorph(morph)\n        rot = rotate\n        if rot % 90 != 0:\n            raise ValueError(\"bad rotate value\")\n\n        while rot < 0:\n            rot += 360\n        rot = rot % 360  # text rotate = 0, 90, 270, 180\n\n        templ1 = lambda a, b, c, d, e, f, g: f\"\\nq\\n{a}{b}BT\\n{c}1 0 0 1 {_format_g((d, e))} Tm\\n/{f} {_format_g(g)} Tf \"\n        templ2 = lambda a: f\"TJ\\n0 -{_format_g(a)} TD\\n\"\n        cmp90 = \"0 1 -1 0 0 0 cm\\n\"  # rotates 90 deg counter-clockwise\n        cmm90 = \"0 -1 1 0 0 0 cm\\n\"  # rotates 90 deg clockwise\n        cm180 = \"-1 0 0 -1 0 0 cm\\n\"  # rotates by 180 deg.\n        height = self.height\n        width = self.width\n\n        # setting up for standard rotation directions\n        # case rotate = 0\n        if morphing:\n            m1 = Matrix(1, 0, 0, 1, morph[0].x + self.x, height - morph[0].y - self.y)\n            mat = ~m1 * morph[1] * m1\n            cm = _format_g(JM_TUPLE(mat)) + \" cm\\n\"\n        else:\n            cm = \"\"\n        top = height - point.y - self.y  # start of 1st char\n        left = point.x + self.x  # start of 1. char\n        space = top  # space available\n        #headroom = point.y + self.y  # distance to page border\n        if rot == 90:\n            left = height - point.y - self.y\n            top = -point.x - self.x\n            cm += cmp90\n            space = width - abs(top)\n            #headroom = point.x + self.x\n\n        elif rot == 270:\n            left = -height + point.y + self.y\n            top = point.x + self.x\n            cm += cmm90\n            space = abs(top)\n            #headroom = width - point.x - self.x\n\n        elif rot == 180:\n            left = -point.x - self.x\n            top = -height + point.y + self.y\n            cm += cm180\n            space = abs(point.y + self.y)\n            #headroom = height - point.y - self.y\n\n        optcont = self.page._get_optional_content(oc)\n        if optcont is not None:\n            bdc = f\"/OC /{optcont} BDC\\n\"\n            emc = \"EMC\\n\"\n        else:\n            bdc = emc = \"\"\n\n        alpha = self.page._set_opacity(CA=stroke_opacity, ca=fill_opacity)\n        if alpha is None:\n            alpha = \"\"\n        else:\n            alpha = f\"/{alpha} gs\\n\"\n        nres = templ1(bdc, alpha, cm, left, top, fname, fontsize)\n\n        if render_mode > 0:\n            nres += f\"{render_mode} Tr \"\n            nres += _format_g(border_width * fontsize) + \" w \"\n            if miter_limit is not None:\n                nres += _format_g(miter_limit) + \" M \"\n        if color is not None:\n            nres += color_str\n        if fill is not None:\n            nres += fill_str\n\n        # =========================================================================\n        #   start text insertion\n        # =========================================================================\n        nres += text[0]\n        nlines = 1  # set output line counter\n        if len(text) > 1:\n            nres += templ2(lheight)  # line 1\n        else:\n            nres += 'TJ'\n        for i in range(1, len(text)):\n            if space < lheight:\n                break  # no space left on page\n            if i > 1:\n                nres += \"\\nT* \"\n            nres += text[i] + 'TJ'\n            space -= lheight\n            nlines += 1\n\n        nres += f\"\\nET\\n{emc}Q\\n\"\n\n        # =========================================================================\n        #   end of text insertion\n        # =========================================================================\n        # update the /Contents object\n        self.text_cont += nres\n        return nlines\n\n    # ==============================================================================\n    # Shape.insert_textbox\n    # ==============================================================================\n    def insert_textbox(\n        self,\n        rect: rect_like,\n        buffer: typing.Union[str, list],\n        *,\n        align: int = 0,\n        border_width: float = 0.05,\n        color: OptSeq = None,\n        encoding: int = 0,\n        expandtabs: int = 1,\n        fill_opacity: float = 1,\n        fill: OptSeq = None,\n        fontfile: OptStr = None,\n        fontname: OptStr = \"helv\",\n        fontsize: float = 11,\n        lineheight: OptFloat = None,\n        miter_limit: float = 1,\n        morph: OptSeq = None,\n        oc: int = 0,\n        render_mode: int = 0,\n        rotate: int = 0,\n        set_simple: bool = 0,\n        stroke_opacity: float = 1,\n    ) -> float:\n        \"\"\"Insert text into a given rectangle.\n\n        Args:\n            rect -- the textbox to fill\n            buffer -- text to be inserted\n            fontname -- a Base-14 font, font name or '/name'\n            fontfile -- name of a font file\n            fontsize -- font size\n            lineheight -- overwrite the font property\n            color -- RGB stroke color triple\n            fill -- RGB fill color triple\n            render_mode -- text rendering control\n            border_width -- thickness of glyph borders as percentage of fontsize\n            expandtabs -- handles tabulators with string function\n            align -- left, center, right, justified\n            rotate -- 0, 90, 180, or 270 degrees\n            morph -- morph box with a matrix and a fixpoint\n        Returns:\n            unused or deficit rectangle area (float)\n        \"\"\"\n        rect = Rect(rect)\n        if rect.is_empty or rect.is_infinite:\n            raise ValueError(\"text box must be finite and not empty\")\n\n        color_str = ColorCode(color, \"c\")\n        fill_str = ColorCode(fill, \"f\")\n        if fill is None and render_mode == 0:  # ensure fill color for 0 Tr\n            fill = color\n            fill_str = ColorCode(color, \"f\")\n\n        optcont = self.page._get_optional_content(oc)\n        if optcont is not None:\n            bdc = f\"/OC /{optcont} BDC\\n\"\n            emc = \"EMC\\n\"\n        else:\n            bdc = emc = \"\"\n\n        # determine opacity / transparency\n        alpha = self.page._set_opacity(CA=stroke_opacity, ca=fill_opacity)\n        if alpha is None:\n            alpha = \"\"\n        else:\n            alpha = f\"/{alpha} gs\\n\"\n\n        if rotate % 90 != 0:\n            raise ValueError(\"rotate must be multiple of 90\")\n\n        rot = rotate\n        while rot < 0:\n            rot += 360\n        rot = rot % 360\n\n        # is buffer worth of dealing with?\n        if not bool(buffer):\n            return rect.height if rot in (0, 180) else rect.width\n\n        cmp90 = \"0 1 -1 0 0 0 cm\\n\"  # rotates counter-clockwise\n        cmm90 = \"0 -1 1 0 0 0 cm\\n\"  # rotates clockwise\n        cm180 = \"-1 0 0 -1 0 0 cm\\n\"  # rotates by 180 deg.\n        height = self.height\n\n        fname = fontname\n        if fname.startswith(\"/\"):\n            fname = fname[1:]\n\n        xref = self.page.insert_font(\n            fontname=fname, fontfile=fontfile, encoding=encoding, set_simple=set_simple\n        )\n        fontinfo = CheckFontInfo(self.doc, xref)\n\n        fontdict = fontinfo[1]\n        ordering = fontdict[\"ordering\"]\n        simple = fontdict[\"simple\"]\n        glyphs = fontdict[\"glyphs\"]\n        bfname = fontdict[\"name\"]\n        ascender = fontdict[\"ascender\"]\n        descender = fontdict[\"descender\"]\n\n        if lineheight:\n            lheight_factor = lineheight\n        elif ascender - descender <= 1:\n            lheight_factor = 1.2\n        else:\n            lheight_factor = ascender - descender\n        lheight = fontsize * lheight_factor\n\n        # create a list from buffer, split into its lines\n        if type(buffer) in (list, tuple):\n            t0 = \"\\n\".join(buffer)\n        else:\n            t0 = buffer\n\n        maxcode = max([ord(c) for c in t0])\n        # replace invalid char codes for simple fonts\n        if simple and maxcode > 255:\n            t0 = \"\".join([c if ord(c) < 256 else \"?\" for c in t0])\n\n        t0 = t0.splitlines()\n\n        glyphs = self.doc.get_char_widths(xref, maxcode + 1)\n        if simple and bfname not in (\"Symbol\", \"ZapfDingbats\"):\n            tj_glyphs = None\n        else:\n            tj_glyphs = glyphs\n\n        # ----------------------------------------------------------------------\n        # calculate pixel length of a string\n        # ----------------------------------------------------------------------\n        def pixlen(x):\n            \"\"\"Calculate pixel length of x.\"\"\"\n            if ordering < 0:\n                return sum([glyphs[ord(c)][1] for c in x]) * fontsize\n            else:\n                return len(x) * fontsize\n\n        # ---------------------------------------------------------------------\n\n        if ordering < 0:\n            blen = glyphs[32][1] * fontsize  # pixel size of space character\n        else:\n            blen = fontsize\n\n        text = \"\"  # output buffer\n\n        if CheckMorph(morph):\n            m1 = Matrix(\n                1, 0, 0, 1, morph[0].x + self.x, self.height - morph[0].y - self.y\n            )\n            mat = ~m1 * morph[1] * m1\n            cm = _format_g(JM_TUPLE(mat)) + \" cm\\n\"\n        else:\n            cm = \"\"\n\n        # ---------------------------------------------------------------------\n        # adjust for text orientation / rotation\n        # ---------------------------------------------------------------------\n        progr = 1  # direction of line progress\n        c_pnt = Point(0, fontsize * ascender)  # used for line progress\n        if rot == 0:  # normal orientation\n            point = rect.tl + c_pnt  # line 1 is 'lheight' below top\n            maxwidth = rect.width  # pixels available in one line\n            maxheight = rect.height  # available text height\n\n        elif rot == 90:  # rotate counter clockwise\n            c_pnt = Point(fontsize * ascender, 0)  # progress in x-direction\n            point = rect.bl + c_pnt  # line 1 'lheight' away from left\n            maxwidth = rect.height  # pixels available in one line\n            maxheight = rect.width  # available text height\n            cm += cmp90\n\n        elif rot == 180:  # text upside down\n            # progress upwards in y direction\n            c_pnt = -Point(0, fontsize * ascender)\n            point = rect.br + c_pnt  # line 1 'lheight' above bottom\n            maxwidth = rect.width  # pixels available in one line\n            progr = -1  # subtract lheight for next line\n            maxheight =rect.height  # available text height\n            cm += cm180\n\n        else:  # rotate clockwise (270 or -90)\n            # progress from right to left\n            c_pnt = -Point(fontsize * ascender, 0)\n            point = rect.tr + c_pnt  # line 1 'lheight' left of right\n            maxwidth = rect.height  # pixels available in one line\n            progr = -1  # subtract lheight for next line\n            maxheight = rect.width  # available text height\n            cm += cmm90\n\n        # =====================================================================\n        # line loop\n        # =====================================================================\n        just_tab = []  # 'justify' indicators per line\n\n        for i, line in enumerate(t0):\n            line_t = line.expandtabs(expandtabs).split(\" \")  # split into words\n            num_words = len(line_t)\n            lbuff = \"\"  # init line buffer\n            rest = maxwidth  # available line pixels\n            # =================================================================\n            # word loop\n            # =================================================================\n            for j in range(num_words):\n                word = line_t[j]\n                pl_w = pixlen(word)  # pixel len of word\n                if rest >= pl_w:  # does it fit on the line?\n                    lbuff += word + \" \"  # yes, append word\n                    rest -= pl_w + blen  # update available line space\n                    continue  # next word\n\n                # word doesn't fit - output line (if not empty)\n                if lbuff:\n                    lbuff = lbuff.rstrip() + \"\\n\"  # line full, append line break\n                    text += lbuff  # append to total text\n                    just_tab.append(True)  # can align-justify\n\n                lbuff = \"\"  # re-init line buffer\n                rest = maxwidth  # re-init avail. space\n\n                if pl_w <= maxwidth:  # word shorter than 1 line?\n                    lbuff = word + \" \"  # start the line with it\n                    rest = maxwidth - pl_w - blen  # update free space\n                    continue\n\n                # long word: split across multiple lines - char by char ...\n                if len(just_tab) > 0:\n                    just_tab[-1] = False  # cannot align-justify\n                for c in word:\n                    if pixlen(lbuff) <= maxwidth - pixlen(c):\n                        lbuff += c\n                    else:  # line full\n                        lbuff += \"\\n\"  # close line\n                        text += lbuff  # append to text\n                        just_tab.append(False)  # cannot align-justify\n                        lbuff = c  # start new line with this char\n\n                lbuff += \" \"  # finish long word\n                rest = maxwidth - pixlen(lbuff)  # long word stored\n\n            if lbuff:  # unprocessed line content?\n                text += lbuff.rstrip()  # append to text\n                just_tab.append(False)  # cannot align-justify\n\n            if i < len(t0) - 1:  # not the last line?\n                text += \"\\n\"  # insert line break\n\n        # compute used part of the textbox\n        if text.endswith(\"\\n\"):\n            text = text[:-1]\n        lb_count = text.count(\"\\n\") + 1  # number of lines written\n\n        # text height = line count * line height plus one descender value\n        text_height = lheight * lb_count - descender * fontsize\n\n        more = text_height - maxheight  # difference to height limit\n        if more > EPSILON:  # landed too much outside rect\n            return (-1) * more  # return deficit, don't output\n\n        more = abs(more)\n        if more < EPSILON:\n            more = 0  # don't bother with epsilons\n        nres = f\"\\nq\\n{bdc}{alpha}BT\\n\" + cm  # initialize output buffer\n        templ = lambda a, b, c, d: f\"1 0 0 1 {_format_g((a, b))} Tm /{c} {_format_g(d)} Tf \"\n        # center, right, justify: output each line with its own specifics\n        text_t = text.splitlines()  # split text in lines again\n        just_tab[-1] = False  # never justify last line\n        for i, t in enumerate(text_t):\n            spacing = 0\n            pl = maxwidth - pixlen(t)  # length of empty line part\n            pnt = point + c_pnt * (i * lheight_factor)  # text start of line\n            if align == 1:  # center: right shift by half width\n                if rot in (0, 180):\n                    pnt = pnt + Point(pl / 2, 0) * progr\n                else:\n                    pnt = pnt - Point(0, pl / 2) * progr\n            elif align == 2:  # right: right shift by full width\n                if rot in (0, 180):\n                    pnt = pnt + Point(pl, 0) * progr\n                else:\n                    pnt = pnt - Point(0, pl) * progr\n            elif align == 3:  # justify\n                spaces = t.count(\" \")  # number of spaces in line\n                if spaces > 0 and just_tab[i]:  # if any, and we may justify\n                    spacing = pl / spaces  # make every space this much larger\n                else:\n                    spacing = 0  # keep normal space length\n            top = height - pnt.y - self.y\n            left = pnt.x + self.x\n            if rot == 90:\n                left = height - pnt.y - self.y\n                top = -pnt.x - self.x\n            elif rot == 270:\n                left = -height + pnt.y + self.y\n                top = pnt.x + self.x\n            elif rot == 180:\n                left = -pnt.x - self.x\n                top = -height + pnt.y + self.y\n\n            nres += templ(left, top, fname, fontsize)\n\n            if render_mode > 0:\n                nres += f\"{render_mode} Tr \"\n                nres += _format_g(border_width * fontsize) + \" w \"\n                if miter_limit is not None:\n                    nres += _format_g(miter_limit) + \" M \"\n\n            if align == 3:\n                nres += _format_g(spacing) + \" Tw \"\n\n            if color is not None:\n                nres += color_str\n            if fill is not None:\n                nres += fill_str\n            nres += f\"{getTJstr(t, tj_glyphs, simple, ordering)}TJ\\n\"\n\n        nres += f\"ET\\n{emc}Q\\n\"\n\n        self.text_cont += nres\n        self.updateRect(rect)\n        return more\n\n    def finish(\n        self,\n        width: float = 1,\n        color: OptSeq = (0,),\n        fill: OptSeq = None,\n        lineCap: int = 0,\n        lineJoin: int = 0,\n        dashes: OptStr = None,\n        even_odd: bool = False,\n        morph: OptSeq = None,\n        closePath: bool = True,\n        fill_opacity: float = 1,\n        stroke_opacity: float = 1,\n        oc: int = 0,\n    ) -> None:\n        \"\"\"Finish the current drawing segment.\n\n        Notes:\n            Apply colors, opacity, dashes, line style and width, or\n            morphing. Also whether to close the path\n            by connecting last to first point.\n        \"\"\"\n        if self.draw_cont == \"\":  # treat empty contents as no-op\n            return\n\n        if width == 0:  # border color makes no sense then\n            color = None\n        elif color is None:  # vice versa\n            width = 0\n        # if color == None and fill == None:\n        #     raise ValueError(\"at least one of 'color' or 'fill' must be given\")\n        color_str = ColorCode(color, \"c\")  # ensure proper color string\n        fill_str = ColorCode(fill, \"f\")  # ensure proper fill string\n\n        optcont = self.page._get_optional_content(oc)\n        if optcont is not None:\n            self.draw_cont = f\"/OC /{optcont} BDC\\n\" + self.draw_cont\n            emc = \"EMC\\n\"\n        else:\n            emc = \"\"\n\n        alpha = self.page._set_opacity(CA=stroke_opacity, ca=fill_opacity)\n        if alpha is not None:\n            self.draw_cont = f\"/{alpha} gs\\n\" + self.draw_cont\n\n        if width != 1 and width != 0:\n            self.draw_cont += _format_g(width) + \" w\\n\"\n\n        if lineCap != 0:\n            self.draw_cont = f\"{lineCap} J\\n\" + self.draw_cont\n        if lineJoin != 0:\n            self.draw_cont = f\"{lineJoin} j\\n\" + self.draw_cont\n\n        if dashes not in (None, \"\", \"[] 0\"):\n            self.draw_cont = f\"{dashes} d\\n\" + self.draw_cont\n\n        if closePath:\n            self.draw_cont += \"h\\n\"\n            self.last_point = None\n\n        if color is not None:\n            self.draw_cont += color_str\n\n        if fill is not None:\n            self.draw_cont += fill_str\n            if color is not None:\n                if not even_odd:\n                    self.draw_cont += \"B\\n\"\n                else:\n                    self.draw_cont += \"B*\\n\"\n            else:\n                if not even_odd:\n                    self.draw_cont += \"f\\n\"\n                else:\n                    self.draw_cont += \"f*\\n\"\n        else:\n            self.draw_cont += \"S\\n\"\n\n        self.draw_cont += emc\n        if CheckMorph(morph):\n            m1 = Matrix(\n                1, 0, 0, 1, morph[0].x + self.x, self.height - morph[0].y - self.y\n            )\n            mat = ~m1 * morph[1] * m1\n            self.draw_cont = _format_g(JM_TUPLE(mat)) + \" cm\\n\" + self.draw_cont\n\n        self.totalcont += \"\\nq\\n\" + self.draw_cont + \"Q\\n\"\n        self.draw_cont = \"\"\n        self.last_point = None\n        return\n\n    def commit(self, overlay: bool = True) -> None:\n        \"\"\"Update the page's /Contents object with Shape data.\n\n        The argument controls whether data appear in foreground (default)\n        or background.\n        \"\"\"\n        CheckParent(self.page)  # doc may have died meanwhile\n        self.totalcont += self.text_cont\n        self.totalcont = self.totalcont.encode()\n\n        if self.totalcont:\n            if overlay:\n                self.page.wrap_contents()  # ensure a balanced graphics state\n            # make /Contents object with dummy stream\n            xref = TOOLS._insert_contents(self.page, b\" \", overlay)\n            # update it with potential compression\n            self.doc.update_stream(xref, self.totalcont)\n\n        self.last_point = None  # clean up ...\n        self.rect = None  #\n        self.draw_cont = \"\"  # for potential ...\n        self.text_cont = \"\"  # ...\n        self.totalcont = \"\"  # re-use\n\n\nclass Story:\n\n    def __init__( self, html='', user_css=None, em=12, archive=None):\n        buffer_ = mupdf.fz_new_buffer_from_copied_data( html.encode('utf-8'))\n        if archive and not isinstance(archive, Archive):\n            archive = Archive(archive)\n        arch = archive.this if archive else mupdf.FzArchive( None)\n        if hasattr(mupdf, 'FzStoryS'):\n            self.this = mupdf.FzStoryS( buffer_, user_css, em, arch)\n        else:\n            self.this = mupdf.FzStory( buffer_, user_css, em, arch)\n    \n    def add_header_ids(self):\n        '''\n        Look for `<h1..6>` items in `self` and adds unique `id`\n        attributes if not already present.\n        '''\n        dom = self.body\n        i = 0\n        x = dom.find(None, None, None)\n        while x:\n            name = x.tagname\n            if len(name) == 2 and name[0]==\"h\" and name[1] in \"123456\":\n                attr = x.get_attribute_value(\"id\")\n                if not attr:\n                    id_ = f\"h_id_{i}\"\n                    #log(f\"{name=}: setting {id_=}\")\n                    x.set_attribute(\"id\", id_)\n                    i += 1\n            x = x.find_next(None, None, None)\n\n    @staticmethod\n    def add_pdf_links(document_or_stream, positions):\n        \"\"\"\n        Adds links to PDF document.\n        Args:\n            document_or_stream:\n                A PDF `Document` or raw PDF content, for example an\n                `io.BytesIO` instance.\n            positions:\n                List of `ElementPosition`'s for `document_or_stream`,\n                typically from Story.element_positions(). We raise an\n                exception if two or more positions have same id.\n        Returns:\n            `document_or_stream` if a `Document` instance, otherwise a\n            new `Document` instance.\n        We raise an exception if an `href` in `positions` refers to an\n        internal position `#<name>` but no item in `positions` has `id =\n        name`.\n        \"\"\"\n        if isinstance(document_or_stream, Document):\n            document = document_or_stream\n        else:\n            document = Document(\"pdf\", document_or_stream)\n\n        # Create dict from id to position, which we will use to find\n        # link destinations.\n        #\n        id_to_position = dict()\n        #log(f\"positions: {positions}\")\n        for position in positions:\n            #log(f\"add_pdf_links(): position: {position}\")\n            if (position.open_close & 1) and position.id:\n                #log(f\"add_pdf_links(): position with id: {position}\")\n                if position.id in id_to_position:\n                    #log(f\"Ignoring duplicate positions with id={position.id!r}\")\n                    pass\n                else:\n                    id_to_position[ position.id] = position\n\n        # Insert links for all positions that have an `href`.\n        #\n        for position_from in positions:\n        \n            if (position_from.open_close & 1) and position_from.href:\n            \n                #log(f\"add_pdf_links(): position with href: {position}\")\n                link = dict()\n                link['from'] = Rect(position_from.rect)\n                \n                if position_from.href.startswith(\"#\"):\n                    #`<a href=\"#...\">...</a>` internal link.\n                    target_id = position_from.href[1:]\n                    try:\n                        position_to = id_to_position[ target_id]\n                    except Exception as e:\n                        if g_exceptions_verbose > 1:    exception_info()\n                        raise RuntimeError(f\"No destination with id={target_id}, required by position_from: {position_from}\") from e\n                    # Make link from `position_from`'s rect to top-left of\n                    # `position_to`'s rect.\n                    if 0:\n                        log(f\"add_pdf_links(): making link from:\")\n                        log(f\"add_pdf_links():    {position_from}\")\n                        log(f\"add_pdf_links(): to:\")\n                        log(f\"add_pdf_links():    {position_to}\")\n                    link[\"kind\"] = LINK_GOTO\n                    x0, y0, x1, y1 = position_to.rect\n                    # This appears to work well with viewers which scroll\n                    # to make destination point top-left of window.\n                    link[\"to\"] = Point(x0, y0)\n                    link[\"page\"] = position_to.page_num - 1\n                    \n                else:\n                    # `<a href=\"...\">...</a>` external link.\n                    if position_from.href.startswith('name:'):\n                        link['kind'] = LINK_NAMED\n                        link['name'] = position_from.href[5:]\n                    else:\n                        link['kind'] = LINK_URI\n                        link['uri'] = position_from.href\n                \n                #log(f'Adding link: {position_from.page_num=} {link=}.')\n                document[position_from.page_num - 1].insert_link(link)\n        \n        return document\n\n    @property\n    def body(self):\n        dom = self.document()\n        return dom.bodytag()\n        \n    def document( self):\n        dom = mupdf.fz_story_document( self.this)\n        return Xml( dom)\n\n    def draw( self, device, matrix=None):\n        ctm2 = JM_matrix_from_py( matrix)\n        dev = device.this if device else mupdf.FzDevice( None)\n        mupdf.fz_draw_story( self.this, dev, ctm2)\n\n    def element_positions( self, function, args=None):\n        '''\n        Trigger a callback function to record where items have been placed.\n        '''\n        if type(args) is dict:\n            for k in args.keys():\n                if not (type(k) is str and k.isidentifier()):\n                    raise ValueError(f\"invalid key '{k}'\")\n        else:\n            args = {}\n        if not callable(function) or function.__code__.co_argcount != 1:\n            raise ValueError(\"callback 'function' must be a callable with exactly one argument\")\n        \n        def function2( position):\n            class Position2:\n                pass\n            position2 = Position2()\n            position2.depth = position.depth\n            position2.heading = position.heading\n            position2.id = position.id\n            position2.rect = JM_py_from_rect(position.rect)\n            position2.text = position.text\n            position2.open_close = position.open_close\n            position2.rect_num = position.rectangle_num\n            position2.href = position.href\n            if args:\n                for k, v in args.items():\n                    setattr( position2, k, v)\n            function( position2)\n        mupdf.fz_story_positions( self.this, function2)\n\n    def place( self, where, flags=0):\n        '''\n        Wrapper for fz_place_story_flags().\n        '''\n        where = JM_rect_from_py( where)\n        filled = mupdf.FzRect()\n        more = mupdf.fz_place_story_flags( self.this, where, filled, flags)\n        return more, JM_py_from_rect( filled)\n\n    def reset( self):\n        mupdf.fz_reset_story( self.this)\n    \n    def write(self, writer, rectfn, positionfn=None, pagefn=None):\n        dev = None\n        page_num = 0\n        rect_num = 0\n        filled = Rect(0, 0, 0, 0)\n        while 1:\n            mediabox, rect, ctm = rectfn(rect_num, filled)\n            rect_num += 1\n            if mediabox:\n                # new page.\n                page_num += 1\n            more, filled = self.place( rect)\n            if positionfn:\n                def positionfn2(position):\n                    # We add a `.page_num` member to the\n                    # `ElementPosition` instance.\n                    position.page_num = page_num\n                    positionfn(position)\n                self.element_positions(positionfn2)\n            if writer:\n                if mediabox:\n                    # new page.\n                    if dev:\n                        if pagefn:\n                            pagefn(page_num, mediabox, dev, 1)\n                        writer.end_page()\n                    dev = writer.begin_page( mediabox)\n                    if pagefn:\n                        pagefn(page_num, mediabox, dev, 0)\n                self.draw( dev, ctm)\n                if not more:\n                    if pagefn:\n                        pagefn( page_num, mediabox, dev, 1)\n                    writer.end_page()\n            else:\n                self.draw(None, ctm)\n            if not more:\n                break\n\n    @staticmethod\n    def write_stabilized(writer, contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True):\n        positions = list()\n        content = None\n        # Iterate until stable.\n        while 1:\n            content_prev = content\n            content = contentfn( positions)\n            stable = False\n            if content == content_prev:\n                stable = True\n            content2 = content\n            story = Story(content2, user_css, em, archive)\n\n            if add_header_ids:\n                story.add_header_ids()\n\n            positions = list()\n            def positionfn2(position):\n                #log(f\"write_stabilized(): {stable=} {positionfn=} {position=}\")\n                positions.append(position)\n                if stable and positionfn:\n                    positionfn(position)\n            story.write(\n                    writer if stable else None,\n                    rectfn,\n                    positionfn2,\n                    pagefn,\n                    )\n            if stable:\n                break\n\n    @staticmethod\n    def write_stabilized_with_links(contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True):\n        #log(\"write_stabilized_with_links()\")\n        stream = io.BytesIO()\n        writer = DocumentWriter(stream)\n        positions = []\n        def positionfn2(position):\n            #log(f\"write_stabilized_with_links(): {position=}\")\n            positions.append(position)\n            if positionfn:\n                positionfn(position)\n        Story.write_stabilized(writer, contentfn, rectfn, user_css, em, positionfn2, pagefn, archive, add_header_ids)\n        writer.close()\n        stream.seek(0)\n        return Story.add_pdf_links(stream, positions)\n\n    def write_with_links(self, rectfn, positionfn=None, pagefn=None):\n        #log(\"write_with_links()\")\n        stream = io.BytesIO()\n        writer = DocumentWriter(stream)\n        positions = []\n        def positionfn2(position):\n            #log(f\"write_with_links(): {position=}\")\n            positions.append(position)\n            if positionfn:\n                positionfn(position)\n        self.write(writer, rectfn, positionfn=positionfn2, pagefn=pagefn)\n        writer.close()\n        stream.seek(0)\n        return Story.add_pdf_links(stream, positions)\n\n    class FitResult:\n        '''\n        The result from a `Story.fit*()` method.\n        \n        Members:\n        \n        `big_enough`:\n            `True` if the fit succeeded.\n        `filled`:\n            Tuple (x0, y0, x1, y1) from the last call to `Story.place()`. This\n            will be wider than .rect if any single word (which we never split)\n            was too wide for .rect.\n        `more`:\n            `False` if the fit succeeded.\n        `numcalls`:\n            Number of calls made to `self.place()`.\n        `parameter`:\n            The successful parameter value, or the largest failing value.\n        `rect`:\n            The pumupdf.Rect created from `parameter`.\n        '''\n        def __init__(self, big_enough=None, filled=None, more=None, numcalls=None, parameter=None, rect=None):\n            self.big_enough = big_enough\n            self.filled = filled\n            self.more = more\n            self.numcalls = numcalls\n            self.parameter = parameter\n            self.rect = rect\n        \n        def __repr__(self):\n            return (\n                    f' big_enough={self.big_enough}'\n                    f' filled={self.filled}'\n                    f' more={self.more}'\n                    f' numcalls={self.numcalls}'\n                    f' parameter={self.parameter}'\n                    f' rect={self.rect}'\n                    )\n\n    def fit(self, fn, pmin=None, pmax=None, delta=0.001, verbose=False, flags=0):\n        '''\n        Finds optimal rect that contains the story `self`.\n        \n        Returns a `Story.FitResult` instance.\n            \n        On success, the last call to `self.place()` will have been with the\n        returned rectangle, so `self.draw()` can be used directly.\n        \n        Args:\n        :arg fn:\n            A callable taking a floating point `parameter` and returning a\n            `pymupdf.Rect()`. If the rect is empty, we assume the story will\n            not fit and do not call `self.place()`.\n\n            Must guarantee that `self.place()` behaves monotonically when\n            given rect `fn(parameter`) as `parameter` increases. This\n            usually means that both width and height increase or stay\n            unchanged as `parameter` increases.\n        :arg pmin:\n            Minimum parameter to consider; `None` for -infinity.\n        :arg pmax:\n            Maximum parameter to consider; `None` for +infinity.\n        :arg delta:\n            Maximum error in returned `parameter`.\n        :arg verbose:\n            If true we output diagnostics.\n        :arg flags:\n            Passed to mupdf.fz_place_story_flags(). e.g.\n            zero or `mupdf.FZ_PLACE_STORY_FLAG_NO_OVERFLOW`.\n        '''\n        def log(text):\n            assert verbose\n            message(f'fit(): {text}')\n        \n        assert isinstance(pmin, (int, float)) or pmin is None\n        assert isinstance(pmax, (int, float)) or pmax is None\n        \n        class State:\n            def __init__(self):\n                self.pmin = pmin\n                self.pmax = pmax\n                self.pmin_result = None\n                self.pmax_result = None\n                self.result = None\n                self.numcalls = 0\n                if verbose:\n                    self.pmin0 = pmin\n                    self.pmax0 = pmax\n        state = State()\n        \n        if verbose:\n            log(f'starting. {state.pmin=} {state.pmax=}.')\n        \n        self.reset()\n\n        def ret():\n            if state.pmax is not None:\n                if state.last_p != state.pmax:\n                    if verbose:\n                        log(f'Calling update() with pmax, because was overwritten by later calls.')\n                    big_enough = update(state.pmax)\n                    assert big_enough\n                result = state.pmax_result\n            else:\n                result = state.pmin_result if state.pmin_result else Story.FitResult(numcalls=state.numcalls)\n            if verbose:\n                log(f'finished. {state.pmin0=} {state.pmax0=} {state.pmax=}: returning {result=}')\n            return result\n        \n        def update(parameter):\n            '''\n            Evaluates `more, _ = self.place(fn(parameter))`. If `more` is\n            false, then `rect` is big enough to contain `self` and we\n            set `state.pmax=parameter` and return True. Otherwise we set\n            `state.pmin=parameter` and return False.\n            '''\n            rect = fn(parameter)\n            assert isinstance(rect, Rect), f'{type(rect)=} {rect=}'\n            if rect.is_empty:\n                big_enough = False\n                result = Story.FitResult(parameter=parameter, numcalls=state.numcalls)\n                if verbose:\n                    log(f'update(): not calling self.place() because rect is empty.')\n            else:\n                more, filled = self.place(rect, flags)\n                state.numcalls += 1\n                big_enough = not more\n                result = Story.FitResult(\n                        filled=filled,\n                        more=more,\n                        numcalls=state.numcalls,\n                        parameter=parameter,\n                        rect=rect,\n                        big_enough=big_enough,\n                        )\n                if verbose:\n                    log(f'update(): called self.place(): {state.numcalls:>2d}: {more=} {parameter=} {rect=}.')\n            if big_enough:\n                state.pmax = parameter\n                state.pmax_result = result\n            else:\n                state.pmin = parameter\n                state.pmin_result = result\n            state.last_p = parameter\n            return big_enough\n\n        def opposite(p, direction):\n            '''\n            Returns same sign as `direction`, larger or smaller than `p` if\n            direction is positive or negative respectively.\n            '''\n            if p is None or p==0:\n                return direction\n            if direction * p > 0:\n                return 2 * p\n            return -p\n            \n        if state.pmin is None:\n            # Find an initial finite pmin value.\n            if verbose: log(f'finding pmin.')\n            parameter = opposite(state.pmax, -1)\n            while 1:\n                if not update(parameter):\n                    break\n                parameter *= 2\n        else:\n            if update(state.pmin):\n                if verbose: log(f'{state.pmin=} is big enough.')\n                return ret()\n        \n        if state.pmax is None:\n            # Find an initial finite pmax value.\n            if verbose: log(f'finding pmax.')\n            parameter = opposite(state.pmin, +1)\n            while 1:\n                if update(parameter):\n                    break\n                parameter *= 2\n        else:\n            if not update(state.pmax):\n                # No solution possible.\n                state.pmax = None\n                if verbose: log(f'No solution possible {state.pmax=}.')\n                return ret()\n        \n        # Do binary search in pmin..pmax.\n        if verbose: log(f'doing binary search with {state.pmin=} {state.pmax=}.')\n        while 1:\n            if state.pmax - state.pmin < delta:\n                return ret()\n            parameter = (state.pmin + state.pmax) / 2\n            update(parameter)\n\n    def fit_scale(self, rect, scale_min=0, scale_max=None, delta=0.001, verbose=False, flags=0):\n        '''\n        Finds smallest value `scale` in range `scale_min..scale_max` where\n        `scale * rect` is large enough to contain the story `self`.\n\n        Returns a `Story.FitResult` instance with `.parameter` set to `scale`.\n\n        :arg width:\n            width of rect.\n        :arg height:\n            height of rect.\n        :arg scale_min:\n            Minimum scale to consider; must be >= 0.\n        :arg scale_max:\n            Maximum scale to consider, must be >= scale_min or `None` for\n            infinite.\n        :arg delta:\n            Maximum error in returned scale.\n        :arg verbose:\n            If true we output diagnostics.\n        :arg flags:\n            Passed to Story.place().\n        '''\n        x0, y0, x1, y1 = rect\n        width = x1 - x0\n        height = y1 - y0\n        def fn(scale):\n            return Rect(x0, y0, x0 + scale*width, y0 + scale*height)\n        return self.fit(fn, scale_min, scale_max, delta, verbose, flags)\n\n    def fit_height(self, width, height_min=0, height_max=None, origin=(0, 0), delta=0.001, verbose=False):\n        '''\n        Finds smallest height in range `height_min..height_max` where a rect\n        with size `(width, height)` is large enough to contain the story\n        `self`.\n\n        Returns a `Story.FitResult` instance.\n\n        :arg width:\n            width of rect.\n        :arg height_min:\n            Minimum height to consider; must be >= 0.\n        :arg height_max:\n            Maximum height to consider, must be >= height_min or `None` for\n            infinite.\n        :arg origin:\n            `(x0, y0)` of rect.\n        :arg delta:\n            Maximum error in returned height.\n        :arg verbose:\n            If true we output diagnostics.\n        '''\n        x0, y0 = origin\n        x1 = x0 + width\n        def fn(height):\n            return Rect(x0, y0, x1, y0+height)\n        return self.fit(fn, height_min, height_max, delta, verbose)\n\n    def fit_width(self, height, width_min=0, width_max=None, origin=(0, 0), delta=0.001, verbose=False):\n        '''\n        Finds smallest width in range `width_min..width_max` where a rect with size\n        `(width, height)` is large enough to contain the story `self`.\n\n        Returns a `Story.FitResult` instance.\n        Returns a `FitResult` instance.\n\n        :arg height:\n            height of rect.\n        :arg width_min:\n            Minimum width to consider; must be >= 0.\n        :arg width_max:\n            Maximum width to consider, must be >= width_min or `None` for\n            infinite.\n        :arg origin:\n            `(x0, y0)` of rect.\n        :arg delta:\n            Maximum error in returned width.\n        :arg verbose:\n            If true we output diagnostics.\n        '''\n        x0, y0 = origin\n        y1 = y0 + height\n        def fn(width):\n            return Rect(x0, y0, x0+width, y1)\n        return self.fit(fn, width_min, width_max, delta, verbose)\n\n\nclass TextPage:\n\n    def __init__(self, *args):\n        if args_match(args, mupdf.FzRect):\n            mediabox = args[0]\n            self.this = mupdf.FzStextPage( mediabox)\n        elif args_match(args, mupdf.FzStextPage):\n            self.this = args[0]\n        else:\n            raise Exception(f'Unrecognised args: {args}')\n        self.thisown = True\n        self.parent = None\n\n    def _extractText(self, format_):\n        this_tpage = self.this\n        res = mupdf.fz_new_buffer(1024)\n        out = mupdf.FzOutput( res)\n        # fixme: mupdfwrap.py thinks fz_output is not copyable, possibly\n        # because there is no .refs member visible and no fz_keep_output() fn,\n        # although there is an fz_drop_output(). So mupdf.fz_new_output_with_buffer()\n        # doesn't convert the returned fz_output* into a mupdf.FzOutput.\n        #out = mupdf.FzOutput(out)\n        if format_ == 1:\n            mupdf.fz_print_stext_page_as_html(out, this_tpage, 0)\n        elif format_ == 3:\n            mupdf.fz_print_stext_page_as_xml(out, this_tpage, 0)\n        elif format_ == 4:\n            mupdf.fz_print_stext_page_as_xhtml(out, this_tpage, 0)\n        else:\n            JM_print_stext_page_as_text(res, this_tpage)\n        out.fz_close_output()\n        text = JM_EscapeStrFromBuffer(res)\n        return text\n\n    def _getNewBlockList(self, page_dict, raw):\n        JM_make_textpage_dict(self.this, page_dict, raw)\n\n    def _textpage_dict(self, raw=False):\n        page_dict = {\"width\": self.rect.width, \"height\": self.rect.height}\n        self._getNewBlockList(page_dict, raw)\n        return page_dict\n\n    def extractBLOCKS(self):\n        \"\"\"Return a list with text block information.\"\"\"\n        if 1 or g_use_extra:\n            return extra.extractBLOCKS(self.this)\n        block_n = -1\n        this_tpage = self.this\n        tp_rect = mupdf.FzRect(this_tpage.m_internal.mediabox)\n        res = mupdf.fz_new_buffer(1024)\n        lines = []\n        for block in this_tpage:\n            block_n += 1\n            blockrect = mupdf.FzRect(mupdf.FzRect.Fixed_EMPTY)\n            if block.m_internal.type == mupdf.FZ_STEXT_BLOCK_TEXT:\n                mupdf.fz_clear_buffer(res) # set text buffer to empty\n                line_n = -1\n                last_char = 0\n                for line in block:\n                    line_n += 1\n                    linerect = mupdf.FzRect(mupdf.FzRect.Fixed_EMPTY)\n                    for ch in line:\n                        cbbox = JM_char_bbox(line, ch)\n                        if (not JM_rects_overlap(tp_rect, cbbox)\n                                and not mupdf.fz_is_infinite_rect(tp_rect)\n                                ):\n                            continue\n                        JM_append_rune(res, ch.m_internal.c)\n                        last_char = ch.m_internal.c\n                        linerect = mupdf.fz_union_rect(linerect, cbbox)\n                    if last_char != 10 and not mupdf.fz_is_empty_rect(linerect):\n                        mupdf.fz_append_byte(res, 10)\n                    blockrect = mupdf.fz_union_rect(blockrect, linerect)\n                text = JM_EscapeStrFromBuffer(res)\n            elif (JM_rects_overlap(tp_rect, block.m_internal.bbox)\n                    or mupdf.fz_is_infinite_rect(tp_rect)\n                    ):\n                img = block.i_image()\n                cs = img.colorspace()\n                text = f\"<image: {mupdf.fz_colorspace_name(cs)}, width: {img.w()}, height: {img.h()}, bpc: {img.bpc()}>\"\n                blockrect = mupdf.fz_union_rect(blockrect, mupdf.FzRect(block.m_internal.bbox))\n            if not mupdf.fz_is_empty_rect(blockrect):\n                litem = (\n                        blockrect.x0,\n                        blockrect.y0,\n                        blockrect.x1,\n                        blockrect.y1,\n                        text,\n                        block_n,\n                        block.m_internal.type,\n                        )\n                lines.append(litem)\n        return lines\n\n    def extractDICT(self, cb=None, sort=False) -> dict:\n        \"\"\"Return page content as a Python dict of images and text spans.\"\"\"\n        val = self._textpage_dict(raw=False)\n        if cb is not None:\n            val[\"width\"] = cb.width\n            val[\"height\"] = cb.height\n        if sort:\n            blocks = val[\"blocks\"]\n            blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n            val[\"blocks\"] = blocks\n        return val\n\n    def extractHTML(self) -> str:\n        \"\"\"Return page content as a HTML string.\"\"\"\n        return self._extractText(1)\n\n    def extractIMGINFO(self, hashes=0):\n        \"\"\"Return a list with image meta information.\"\"\"\n        block_n = -1\n        this_tpage = self.this\n        rc = []\n        for block in this_tpage:\n            block_n += 1\n            if block.m_internal.type == mupdf.FZ_STEXT_BLOCK_TEXT:\n                continue\n            img = block.i_image()\n            img_size = 0\n            mask = img.mask()\n            if mask.m_internal:\n                has_mask = True\n            else:\n                has_mask = False\n            compr_buff = mupdf.fz_compressed_image_buffer(img)\n            if compr_buff.m_internal:\n                img_size = compr_buff.fz_compressed_buffer_size()\n                compr_buff = None\n            if hashes:\n                r = mupdf.FzIrect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT)\n                assert mupdf.fz_is_infinite_irect(r)\n                m = mupdf.FzMatrix(img.w(), 0, 0, img.h(), 0, 0)\n                pix, w, h = mupdf.fz_get_pixmap_from_image(img, r, m)\n                digest = mupdf.fz_md5_pixmap2(pix)\n                digest = bytes(digest)\n                if img_size == 0:\n                    img_size = img.w() * img.h() * img.n()\n            cs = mupdf.FzColorspace(mupdf.ll_fz_keep_colorspace(img.m_internal.colorspace))\n            block_dict = dict()\n            block_dict[dictkey_number] = block_n\n            block_dict[dictkey_bbox] = JM_py_from_rect(block.m_internal.bbox)\n            block_dict[dictkey_matrix] = JM_py_from_matrix(block.i_transform())\n            block_dict[dictkey_width] = img.w()\n            block_dict[dictkey_height] = img.h()\n            block_dict[dictkey_colorspace] = mupdf.fz_colorspace_n(cs)\n            block_dict[dictkey_cs_name] = mupdf.fz_colorspace_name(cs)\n            block_dict[dictkey_xres] = img.xres()\n            block_dict[dictkey_yres] = img.yres()\n            block_dict[dictkey_bpc] = img.bpc()\n            block_dict[dictkey_size] = img_size\n            if hashes:\n                block_dict[\"digest\"] = digest\n            block_dict[\"has-mask\"] = has_mask\n            rc.append(block_dict)\n        return rc\n\n    def extractJSON(self, cb=None, sort=False) -> str:\n        \"\"\"Return 'extractDICT' converted to JSON format.\"\"\"\n        import base64\n        import json\n        val = self._textpage_dict(raw=False)\n\n        class b64encode(json.JSONEncoder):\n            def default(self, s):\n                if type(s) in (bytes, bytearray):\n                    return base64.b64encode(s).decode()\n\n        if cb is not None:\n            val[\"width\"] = cb.width\n            val[\"height\"] = cb.height\n        if sort:\n            blocks = val[\"blocks\"]\n            blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n            val[\"blocks\"] = blocks\n        \n        val = json.dumps(val, separators=(\",\", \":\"), cls=b64encode, indent=1)\n        return val\n\n    def extractRAWDICT(self, cb=None, sort=False) -> dict:\n        \"\"\"Return page content as a Python dict of images and text characters.\"\"\"\n        val = self._textpage_dict(raw=True)\n        if cb is not None:\n            val[\"width\"] = cb.width\n            val[\"height\"] = cb.height\n        if sort:\n            blocks = val[\"blocks\"]\n            blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n            val[\"blocks\"] = blocks\n        return val\n\n    def extractRAWJSON(self, cb=None, sort=False) -> str:\n        \"\"\"Return 'extractRAWDICT' converted to JSON format.\"\"\"\n        import base64\n        import json\n        val = self._textpage_dict(raw=True)\n\n        class b64encode(json.JSONEncoder):\n            def default(self,s):\n                if type(s) in (bytes, bytearray):\n                    return base64.b64encode(s).decode()\n\n        if cb is not None:\n            val[\"width\"] = cb.width\n            val[\"height\"] = cb.height\n        if sort:\n            blocks = val[\"blocks\"]\n            blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n            val[\"blocks\"] = blocks\n        val = json.dumps(val, separators=(\",\", \":\"), cls=b64encode, indent=1)\n        return val\n\n    def extractSelection(self, pointa, pointb):\n        a = JM_point_from_py(pointa)\n        b = JM_point_from_py(pointb)\n        found = mupdf.fz_copy_selection(self.this, a, b, 0)\n        return found\n\n    def extractText(self, sort=False) -> str:\n        \"\"\"Return simple, bare text on the page.\"\"\"\n        if not sort:\n            return self._extractText(0)\n        blocks = self.extractBLOCKS()[:]\n        blocks.sort(key=lambda b: (b[3], b[0]))\n        return \"\".join([b[4] for b in blocks])\n\n    def extractTextbox(self, rect):\n        this_tpage = self.this\n        assert isinstance(this_tpage, mupdf.FzStextPage)\n        area = JM_rect_from_py(rect)\n        found = JM_copy_rectangle(this_tpage, area)\n        rc = PyUnicode_DecodeRawUnicodeEscape(found)\n        return rc\n\n    def extractWORDS(self, delimiters=None):\n        \"\"\"Return a list with text word information.\"\"\"\n        if 1 or g_use_extra:\n            return extra.extractWORDS(self.this, delimiters)\n        buflen = 0\n        last_char_rtl = 0\n        block_n = -1\n        wbbox = mupdf.FzRect(mupdf.FzRect.Fixed_EMPTY)  # word bbox\n        this_tpage = self.this\n        tp_rect = mupdf.FzRect(this_tpage.m_internal.mediabox)\n\n        lines = None\n        buff = mupdf.fz_new_buffer(64)\n        lines = []\n        for block in this_tpage:\n            block_n += 1\n            if block.m_internal.type != mupdf.FZ_STEXT_BLOCK_TEXT:\n                continue\n            line_n = -1\n            for line in block:\n                line_n += 1\n                word_n = 0                  # word counter per line\n                mupdf.fz_clear_buffer(buff) # reset word buffer\n                buflen = 0                  # reset char counter\n                for ch in line:\n                    cbbox = JM_char_bbox(line, ch)\n                    if (not JM_rects_overlap(tp_rect, cbbox)\n                            and not mupdf.fz_is_infinite_rect(tp_rect)\n                            ):\n                        continue\n\n                    if buflen == 0 and ch.m_internal.c == 0x200d:\n                        # ZERO WIDTH JOINER cannot start a word\n                        continue\n                    word_delimiter = JM_is_word_delimiter(ch.m_internal.c, delimiters)\n                    this_char_rtl = JM_is_rtl_char(ch.m_internal.c)\n                    if word_delimiter or this_char_rtl != last_char_rtl:\n                        if buflen == 0 and word_delimiter:\n                            continue    # skip delimiters at line start\n                        if not mupdf.fz_is_empty_rect(wbbox):\n                            word_n, wbbox = JM_append_word(lines, buff, wbbox, block_n, line_n, word_n)\n                        mupdf.fz_clear_buffer(buff)\n                        buflen = 0  # reset char counter\n                        if word_delimiter:\n                            continue\n                    # append one unicode character to the word\n                    JM_append_rune(buff, ch.m_internal.c)\n                    last_char_rtl = this_char_rtl\n                    buflen += 1\n                    # enlarge word bbox\n                    wbbox = mupdf.fz_union_rect(wbbox, JM_char_bbox(line, ch))\n                if buflen and not mupdf.fz_is_empty_rect(wbbox):\n                    word_n, wbbox = JM_append_word(lines, buff, wbbox, block_n, line_n, word_n)\n                buflen = 0\n        return lines\n\n    def extractXHTML(self) -> str:\n        \"\"\"Return page content as a XHTML string.\"\"\"\n        return self._extractText(4)\n\n    def extractXML(self) -> str:\n        \"\"\"Return page content as a XML string.\"\"\"\n        return self._extractText(3)\n\n    def poolsize(self):\n        \"\"\"TextPage current poolsize.\"\"\"\n        tpage = self.this\n        pool = mupdf.Pool(tpage.m_internal.pool)\n        size = mupdf.fz_pool_size( pool)\n        pool.m_internal = None  # Ensure that pool's destructor does not free the pool.\n        return size\n\n    @property\n    def rect(self):\n        \"\"\"Page rectangle.\"\"\"\n        this_tpage = self.this\n        mediabox = this_tpage.m_internal.mediabox\n        val = JM_py_from_rect(mediabox)\n        val = Rect(val)\n\n        return val\n\n    def search(self, needle, hit_max=0, quads=1):\n        \"\"\"Locate 'needle' returning rects or quads.\"\"\"\n        val = JM_search_stext_page(self.this, needle)\n        if not val:\n            return val\n        items = len(val)\n        for i in range(items):  # change entries to quads or rects\n            q = Quad(val[i])\n            if quads:\n                val[i] = q\n            else:\n                val[i] = q.rect\n        if quads:\n            return val\n        i = 0  # join overlapping rects on the same line\n        while i < items - 1:\n            v1 = val[i]\n            v2 = val[i + 1]\n            if v1.y1 != v2.y1 or (v1 & v2).is_empty:\n                i += 1\n                continue  # no overlap on same line\n            val[i] = v1 | v2  # join rectangles\n            del val[i + 1]  # remove v2\n            items -= 1  # reduce item count\n        return val\n\n    extractTEXT = extractText\n\n\nclass TextWriter:\n\n    def __init__(self, page_rect, opacity=1, color=None):\n        \"\"\"Stores text spans for later output on compatible PDF pages.\"\"\"\n        self.this = mupdf.fz_new_text()\n\n        self.opacity = opacity\n        self.color = color\n        self.rect = Rect(page_rect)\n        self.ctm = Matrix(1, 0, 0, -1, 0, self.rect.height)\n        self.ictm = ~self.ctm\n        self.last_point = Point()\n        self.last_point.__doc__ = \"Position following last text insertion.\"\n        self.text_rect = Rect()\n        \n        self.text_rect.__doc__ = \"Accumulated area of text spans.\"\n        self.used_fonts = set()\n        self.thisown = True\n\n    @property\n    def _bbox(self):\n        val = JM_py_from_rect( mupdf.fz_bound_text( self.this, mupdf.FzStrokeState(None), mupdf.FzMatrix()))\n        val = Rect(val)\n        return val\n\n    def append(self, pos, text, font=None, fontsize=11, language=None, right_to_left=0, small_caps=0):\n        \"\"\"Store 'text' at point 'pos' using 'font' and 'fontsize'.\"\"\"\n        pos = Point(pos) * self.ictm\n        #log(f'{font=}')\n        if font is None:\n            font = Font(\"helv\")\n        if not font.is_writable:\n            if 0:\n                log(f'{font.this.m_internal.name=}')\n                log(f'{font.this.m_internal.t3matrix=}')\n                log(f'{font.this.m_internal.bbox=}')\n                log(f'{font.this.m_internal.glyph_count=}')\n                log(f'{font.this.m_internal.use_glyph_bbox=}')\n                log(f'{font.this.m_internal.width_count=}')\n                log(f'{font.this.m_internal.width_default=}')\n                log(f'{font.this.m_internal.has_digest=}')\n                log(f'Unsupported font {font.name=}')\n                if mupdf_cppyy:\n                    import cppyy\n                    log( f'Unsupported font {cppyy.gbl.mupdf_font_name(font.this.m_internal)=}')\n            raise ValueError(f\"Unsupported font '{font.name}'.\")\n        if right_to_left:\n            text = self.clean_rtl(text)\n            text = \"\".join(reversed(text))\n            right_to_left = 0\n\n        lang = mupdf.fz_text_language_from_string(language)\n        p = JM_point_from_py(pos)\n        trm = mupdf.fz_make_matrix(fontsize, 0, 0, fontsize, p.x, p.y)\n        markup_dir = 0\n        wmode = 0\n        if small_caps == 0:\n            trm = mupdf.fz_show_string( self.this, font.this, trm, text, wmode, right_to_left, markup_dir, lang)\n        else:\n            trm = JM_show_string_cs( self.this, font.this, trm, text, wmode, right_to_left, markup_dir, lang)\n        val = JM_py_from_matrix(trm)\n\n        self.last_point = Point(val[-2:]) * self.ctm\n        self.text_rect = self._bbox * self.ctm\n        val = self.text_rect, self.last_point\n        if font.flags[\"mono\"] == 1:\n            self.used_fonts.add(font)\n        return val\n\n    def appendv(self, pos, text, font=None, fontsize=11, language=None, small_caps=False):\n        lheight = fontsize * 1.2\n        for c in text:\n            self.append(pos, c, font=font, fontsize=fontsize,\n                language=language, small_caps=small_caps)\n            pos.y += lheight\n        return self.text_rect, self.last_point\n\n    def clean_rtl(self, text):\n        \"\"\"Revert the sequence of Latin text parts.\n\n        Text with right-to-left writing direction (Arabic, Hebrew) often\n        contains Latin parts, which are written in left-to-right: numbers, names,\n        etc. For output as PDF text we need *everything* in right-to-left.\n        E.g. an input like \"<arabic> ABCDE FG HIJ <arabic> KL <arabic>\" will be\n        converted to \"<arabic> JIH GF EDCBA <arabic> LK <arabic>\". The Arabic\n        parts remain untouched.\n\n        Args:\n            text: str\n        Returns:\n            Massaged string.\n        \"\"\"\n        if not text:\n            return text\n        # split into words at space boundaries\n        words = text.split(\" \")\n        idx = []\n        for i in range(len(words)):\n            w = words[i]\n        # revert character sequence for Latin only words\n            if not (len(w) < 2 or max([ord(c) for c in w]) > 255):\n                words[i] = \"\".join(reversed(w))\n                idx.append(i)  # stored index of Latin word\n\n        # adjacent Latin words must revert their sequence, too\n        idx2 = []  # store indices of adjacent Latin words\n        for i in range(len(idx)):\n            if idx2 == []:  # empty yet?\n                idx2.append(idx[i]) # store Latin word number\n\n            elif idx[i] > idx2[-1] + 1:  # large gap to last?\n                if len(idx2) > 1:  # at least two consecutives?\n                    words[idx2[0] : idx2[-1] + 1] = reversed(\n                        words[idx2[0] : idx2[-1] + 1]\n                    )  # revert their sequence\n                idx2 = [idx[i]]  # re-initialize\n\n            elif idx[i] == idx2[-1] + 1:  # new adjacent Latin word\n                idx2.append(idx[i])\n\n        text = \" \".join(words)\n        return text\n\n    def fill_textbox(\n            writer: 'TextWriter',\n            rect: rect_like,\n            text: typing.Union[str, list],\n            pos: point_like = None,\n            font: typing.Optional[Font] = None,\n            fontsize: float = 11,\n            lineheight: OptFloat = None,\n            align: int = 0,\n            warn: bool = None,\n            right_to_left: bool = False,\n            small_caps: bool = False,\n            ) -> tuple:\n        \"\"\"Fill a rectangle with text.\n\n        Args:\n            writer: pymupdf.TextWriter object (= \"self\")\n            rect: rect-like to receive the text.\n            text: string or list/tuple of strings.\n            pos: point-like start position of first word.\n            font: pymupdf.Font object (default pymupdf.Font('helv')).\n            fontsize: the fontsize.\n            lineheight: overwrite the font property\n            align: (int) 0 = left, 1 = center, 2 = right, 3 = justify\n            warn: (bool) text overflow action: none, warn, or exception\n            right_to_left: (bool) indicate right-to-left language.\n        \"\"\"\n        rect = Rect(rect)\n        if rect.is_empty:\n            raise ValueError(\"fill rect must not empty.\")\n        if type(font) is not Font:\n            font = Font(\"helv\")\n\n        def textlen(x):\n            \"\"\"Return length of a string.\"\"\"\n            return font.text_length(\n                x, fontsize=fontsize, small_caps=small_caps\n            )  # abbreviation\n\n        def char_lengths(x):\n            \"\"\"Return list of single character lengths for a string.\"\"\"\n            return font.char_lengths(x, fontsize=fontsize, small_caps=small_caps)\n\n        def append_this(pos, text):\n            ret = writer.append(\n                    pos, text, font=font, fontsize=fontsize, small_caps=small_caps\n                    )\n            return ret\n\n        tolerance = fontsize * 0.2  # extra distance to left border\n        space_len = textlen(\" \")\n        std_width = rect.width - tolerance\n        std_start = rect.x0 + tolerance\n\n        def norm_words(width, words):\n            \"\"\"Cut any word in pieces no longer than 'width'.\"\"\"\n            nwords = []\n            word_lengths = []\n            for w in words:\n                wl_lst = char_lengths(w)\n                wl = sum(wl_lst)\n                if wl <= width:  # nothing to do - copy over\n                    nwords.append(w)\n                    word_lengths.append(wl)\n                    continue\n\n                # word longer than rect width - split it in parts\n                n = len(wl_lst)\n                while n > 0:\n                    wl = sum(wl_lst[:n])\n                    if wl <= width:\n                        nwords.append(w[:n])\n                        word_lengths.append(wl)\n                        w = w[n:]\n                        wl_lst = wl_lst[n:]\n                        n = len(wl_lst)\n                    else:\n                        n -= 1\n            return nwords, word_lengths\n\n        def output_justify(start, line):\n            \"\"\"Justified output of a line.\"\"\"\n            # ignore leading / trailing / multiple spaces\n            words = [w for w in line.split(\" \") if w != \"\"]\n            nwords = len(words)\n            if nwords == 0:\n                return\n            if nwords == 1:  # single word cannot be justified\n                append_this(start, words[0])\n                return\n            tl = sum([textlen(w) for w in words])  # total word lengths\n            gaps = nwords - 1  # number of word gaps\n            gapl = (std_width - tl) / gaps  # width of each gap\n            for w in words:\n                _, lp = append_this(start, w)  # output one word\n                start.x = lp.x + gapl  # next start at word end plus gap\n            return\n\n        asc = font.ascender\n        dsc = font.descender\n        if not lineheight:\n            if asc - dsc <= 1:\n                lheight = 1.2\n            else:\n                lheight = asc - dsc\n        else:\n            lheight = lineheight\n\n        LINEHEIGHT = fontsize * lheight  # effective line height\n        width = std_width  # available horizontal space\n\n        # starting point of text\n        if pos is not None:\n            pos = Point(pos)\n        else:  # default is just below rect top-left\n            pos = rect.tl + (tolerance, fontsize * asc)\n        if pos not in rect:\n            raise ValueError(\"Text must start in rectangle.\")\n\n        # calculate displacement factor for alignment\n        if align == TEXT_ALIGN_CENTER:\n            factor = 0.5\n        elif align == TEXT_ALIGN_RIGHT:\n            factor = 1.0\n        else:\n            factor = 0\n\n        # split in lines if just a string was given\n        if type(text) is str:\n            textlines = text.splitlines()\n        else:\n            textlines = []\n            for line in text:\n                textlines.extend(line.splitlines())\n\n        max_lines = int((rect.y1 - pos.y) / LINEHEIGHT) + 1\n\n        new_lines = []  # the final list of textbox lines\n        no_justify = []  # no justify for these line numbers\n        for i, line in enumerate(textlines):\n            if line in (\"\", \" \"):\n                new_lines.append((line, space_len))\n                width = rect.width - tolerance\n                no_justify.append((len(new_lines) - 1))\n                continue\n            if i == 0:\n                width = rect.x1 - pos.x\n            else:\n                width = rect.width - tolerance\n\n            if right_to_left:  # reverses Arabic / Hebrew text front to back\n                line = writer.clean_rtl(line)\n            tl = textlen(line)\n            if tl <= width:  # line short enough\n                new_lines.append((line, tl))\n                no_justify.append((len(new_lines) - 1))\n                continue\n\n            # we need to split the line in fitting parts\n            words = line.split(\" \")  # the words in the line\n\n            # cut in parts any words that are longer than rect width\n            words, word_lengths = norm_words(width, words)\n\n            n = len(words)\n            while True:\n                line0 = \" \".join(words[:n])\n                wl = sum(word_lengths[:n]) + space_len * (n - 1)\n                if wl <= width:\n                    new_lines.append((line0, wl))\n                    words = words[n:]\n                    word_lengths = word_lengths[n:]\n                    n = len(words)\n                    line0 = None\n                else:\n                    n -= 1\n\n                if len(words) == 0:\n                    break\n                assert n\n\n        # -------------------------------------------------------------------------\n        # List of lines created. Each item is (text, tl), where 'tl' is the PDF\n        # output length (float) and 'text' is the text. Except for justified text,\n        # this is output-ready.\n        # -------------------------------------------------------------------------\n        nlines = len(new_lines)\n        if nlines > max_lines:\n            msg = f\"Only fitting {max_lines} of {nlines} lines.\"\n            if warn is None:\n                pass\n            elif warn:\n                message(\"Warning: \" + msg)\n            else:\n                raise ValueError(msg)\n\n        start = Point()\n        no_justify += [len(new_lines) - 1]  # no justifying of last line\n        for i in range(max_lines):\n            try:\n                line, tl = new_lines.pop(0)\n            except IndexError:\n                if g_exceptions_verbose >= 2:   exception_info()\n                break\n\n            if right_to_left:  # Arabic, Hebrew\n                line = \"\".join(reversed(line))\n\n            if i == 0:  # may have different start for first line\n                start = pos\n\n            if align == TEXT_ALIGN_JUSTIFY and i not in no_justify and tl < std_width:\n                output_justify(start, line)\n                start.x = std_start\n                start.y += LINEHEIGHT\n                continue\n\n            if i > 0 or pos.x == std_start:  # left, center, right alignments\n                start.x += (width - tl) * factor\n\n            append_this(start, line)\n            start.x = std_start\n            start.y += LINEHEIGHT\n\n        return new_lines  # return non-written lines\n\n    def write_text(self, page, color=None, opacity=-1, overlay=1, morph=None, matrix=None, render_mode=0, oc=0):\n        \"\"\"Write the text to a PDF page having the TextWriter's page size.\n\n        Args:\n            page: a PDF page having same size.\n            color: override text color.\n            opacity: override transparency.\n            overlay: put in foreground or background.\n            morph: tuple(Point, Matrix), apply a matrix with a fixpoint.\n            matrix: Matrix to be used instead of 'morph' argument.\n            render_mode: (int) PDF render mode operator 'Tr'.\n        \"\"\"\n        CheckParent(page)\n        if abs(self.rect - page.rect) > 1e-3:\n            raise ValueError(\"incompatible page rect\")\n        if morph is not None:\n            if (type(morph) not in (tuple, list)\n                    or type(morph[0]) is not Point\n                    or type(morph[1]) is not Matrix\n                    ):\n                raise ValueError(\"morph must be (Point, Matrix) or None\")\n        if matrix is not None and morph is not None:\n            raise ValueError(\"only one of matrix, morph is allowed\")\n        if getattr(opacity, \"__float__\", None) is None or opacity == -1:\n            opacity = self.opacity\n        if color is None:\n            color = self.color\n\n        if 1:\n            pdfpage = page._pdf_page()\n            alpha = 1\n            if opacity >= 0 and opacity < 1:\n                alpha = opacity\n            ncol = 1\n            dev_color = [0, 0, 0, 0]\n            if color:\n                ncol, dev_color = JM_color_FromSequence(color)\n            if ncol == 3:\n                colorspace = mupdf.fz_device_rgb()\n            elif ncol == 4:\n                colorspace = mupdf.fz_device_cmyk()\n            else:\n                colorspace = mupdf.fz_device_gray()\n\n            resources = mupdf.pdf_new_dict(pdfpage.doc(), 5)\n            contents = mupdf.fz_new_buffer(1024)\n            dev = mupdf.pdf_new_pdf_device( pdfpage.doc(), mupdf.FzMatrix(), resources, contents)\n            #log(f'=== {dev_color!r=}')\n            mupdf.fz_fill_text(\n                    dev,\n                    self.this,\n                    mupdf.FzMatrix(),\n                    colorspace,\n                    dev_color,\n                    alpha,\n                    mupdf.FzColorParams(mupdf.fz_default_color_params),\n                    )\n            mupdf.fz_close_device( dev)\n\n            # copy generated resources into the one of the page\n            max_nums = JM_merge_resources( pdfpage, resources)\n            cont_string = JM_EscapeStrFromBuffer( contents)\n            result = (max_nums, cont_string)\n            val = result\n\n        max_nums = val[0]\n        content = val[1]\n        max_alp, max_font = max_nums\n        old_cont_lines = content.splitlines()\n\n        optcont = page._get_optional_content(oc)\n        if optcont is not None:\n            bdc = f\"/OC /{optcont} BDC\"\n            emc = \"EMC\"\n        else:\n            bdc = emc = \"\"\n\n        new_cont_lines = [\"q\"]\n        if bdc:\n            new_cont_lines.append(bdc)\n\n        cb = page.cropbox_position\n        if page.rotation in (90, 270):\n            delta = page.rect.height - page.rect.width\n        else:\n            delta = 0\n        mb = page.mediabox\n        if bool(cb) or mb.y0 != 0 or delta != 0:\n            new_cont_lines.append(f\"1 0 0 1 {_format_g((cb.x, cb.y + mb.y0 - delta))} cm\")\n\n        if morph:\n            p = morph[0] * self.ictm\n            delta = Matrix(1, 1).pretranslate(p.x, p.y)\n            matrix = ~delta * morph[1] * delta\n        if morph or matrix:\n            new_cont_lines.append(_format_g(JM_TUPLE(matrix)) + \" cm\")\n\n        for line in old_cont_lines:\n            if line.endswith(\" cm\"):\n                continue\n            if line == \"BT\":\n                new_cont_lines.append(line)\n                new_cont_lines.append(f\"{render_mode:d} Tr\")\n                continue\n            if line.endswith(\" gs\"):\n                alp = int(line.split()[0][4:]) + max_alp\n                line = f\"/Alp{alp:d} gs\"\n            elif line.endswith(\" Tf\"):\n                temp = line.split()\n                fsize = float(temp[1])\n                if render_mode != 0:\n                    w = fsize * 0.05\n                else:\n                    w = 1\n                new_cont_lines.append(_format_g(w) + \" w\")\n                font = int(temp[0][2:]) + max_font\n                line = \" \".join([f\"/F{font:d}\"] + temp[1:])\n            elif line.endswith(\" rg\"):\n                new_cont_lines.append(line.replace(\"rg\", \"RG\"))\n            elif line.endswith(\" g\"):\n                new_cont_lines.append(line.replace(\" g\", \" G\"))\n            elif line.endswith(\" k\"):\n                new_cont_lines.append(line.replace(\" k\", \" K\"))\n            new_cont_lines.append(line)\n        if emc:\n            new_cont_lines.append(emc)\n        new_cont_lines.append(\"Q\\n\")\n        content = \"\\n\".join(new_cont_lines).encode(\"utf-8\")\n        TOOLS._insert_contents(page, content, overlay=overlay)\n        val = None\n        for font in self.used_fonts:\n            repair_mono_font(page, font)\n        return val\n\n\nclass IRect:\n    \"\"\"\n    IRect() - all zeros\n    IRect(x0, y0, x1, y1) - 4 coordinates\n    IRect(top-left, x1, y1) - point and 2 coordinates\n    IRect(x0, y0, bottom-right) - 2 coordinates and point\n    IRect(top-left, bottom-right) - 2 points\n    IRect(sequ) - new from sequence or rect-like\n    \"\"\"\n\n    def __add__(self, p):\n        return Rect.__add__(self, p).round()\n\n    def __and__(self, x):\n        return Rect.__and__(self, x).round()\n\n    def __contains__(self, x):\n        return Rect.__contains__(self, x)\n\n    def __eq__(self, r):\n        if not hasattr(r, \"__len__\"):\n            return False\n        return len(r) == 4 and self.x0 == r[0] and self.y0 == r[1] and self.x1 == r[2] and self.y1 == r[3]\n\n    def __getitem__(self, i):\n        return (self.x0, self.y0, self.x1, self.y1)[i]\n\n    def __hash__(self):\n        return hash(tuple(self))\n\n    def __init__(self, *args, p0=None, p1=None, x0=None, y0=None, x1=None, y1=None):\n        self.x0, self.y0, self.x1, self.y1 = util_make_irect( *args, p0=p0, p1=p1, x0=x0, y0=y0, x1=x1, y1=y1)\n\n    def __len__(self):\n        return 4\n\n    def __mul__(self, m):\n        return Rect.__mul__(self, m).round()\n\n    def __neg__(self):\n        return IRect(-self.x0, -self.y0, -self.x1, -self.y1)\n\n    def __or__(self, x):\n        return Rect.__or__(self, x).round()\n\n    def __pos__(self):\n        return IRect(self)\n\n    def __repr__(self):\n        return \"IRect\" + str(tuple(self))\n\n    def __setitem__(self, i, v):\n        v = int(v)\n        if   i == 0: self.x0 = v\n        elif i == 1: self.y0 = v\n        elif i == 2: self.x1 = v\n        elif i == 3: self.y1 = v\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __sub__(self, p):\n        return Rect.__sub__(self, p).round()\n\n    def __truediv__(self, m):\n        return Rect.__truediv__(self, m).round()\n\n    @property\n    def bottom_left(self):\n        \"\"\"Bottom-left corner.\"\"\"\n        return Point(self.x0, self.y1)\n\n    @property\n    def bottom_right(self):\n        \"\"\"Bottom-right corner.\"\"\"\n        return Point(self.x1, self.y1)\n\n    @property\n    def height(self):\n        return max(0, self.y1 - self.y0)\n\n    def contains(self, x):\n        \"\"\"Check if x is in the rectangle.\"\"\"\n        return self.__contains__(x)\n\n    def get_area(self, *args) -> float:\n        \"\"\"Calculate area of rectangle.\\nparameter is one of 'px' (default), 'in', 'cm', or 'mm'.\"\"\"\n        return _rect_area(self.width, self.height, args)\n\n    def include_point(self, p):\n        \"\"\"Extend rectangle to include point p.\"\"\"\n        rect = self.rect.include_point(p)\n        return rect.irect\n\n    def include_rect(self, r):\n        \"\"\"Extend rectangle to include rectangle r.\"\"\"\n        rect = self.rect.include_rect(r)\n        return rect.irect\n\n    def intersect(self, r):\n        \"\"\"Restrict rectangle to intersection with rectangle r.\"\"\"\n        return Rect.intersect(self, r).round()\n\n    def intersects(self, x):\n        return Rect.intersects(self, x)\n\n    @property\n    def is_empty(self):\n        \"\"\"True if rectangle area is empty.\"\"\"\n        return self.x0 >= self.x1 or self.y0 >= self.y1\n\n    @property\n    def is_infinite(self):\n        \"\"\"True if rectangle is infinite.\"\"\"\n        return self.x0 == self.y0 == FZ_MIN_INF_RECT and self.x1 == self.y1 == FZ_MAX_INF_RECT\n\n    @property\n    def is_valid(self):\n        \"\"\"True if rectangle is valid.\"\"\"\n        return self.x0 <= self.x1 and self.y0 <= self.y1\n\n    def morph(self, p, m):\n        \"\"\"Morph with matrix-like m and point-like p.\n\n        Returns a new quad.\"\"\"\n        if self.is_infinite:\n            return INFINITE_QUAD()\n        return self.quad.morph(p, m)\n\n    def norm(self):\n        return math.sqrt(sum([c*c for c in self]))\n\n    def normalize(self):\n        \"\"\"Replace rectangle with its valid version.\"\"\"\n        if self.x1 < self.x0:\n            self.x0, self.x1 = self.x1, self.x0\n        if self.y1 < self.y0:\n            self.y0, self.y1 = self.y1, self.y0\n        return self\n\n    @property\n    def quad(self):\n        \"\"\"Return Quad version of rectangle.\"\"\"\n        return Quad(self.tl, self.tr, self.bl, self.br)\n\n    @property\n    def rect(self):\n        return Rect(self)\n\n    @property\n    def top_left(self):\n        \"\"\"Top-left corner.\"\"\"\n        return Point(self.x0, self.y0)\n\n    @property\n    def top_right(self):\n        \"\"\"Top-right corner.\"\"\"\n        return Point(self.x1, self.y0)\n\n    def torect(self, r):\n        \"\"\"Return matrix that converts to target rect.\"\"\"\n        r = Rect(r)\n        if self.is_infinite or self.is_empty or r.is_infinite or r.is_empty:\n            raise ValueError(\"rectangles must be finite and not empty\")\n        return (\n                Matrix(1, 0, 0, 1, -self.x0, -self.y0)\n                * Matrix(r.width / self.width, r.height / self.height)\n                * Matrix(1, 0, 0, 1, r.x0, r.y0)\n                )\n\n    def transform(self, m):\n        return Rect.transform(self, m).round()\n\n    @property\n    def width(self):\n        return max(0, self.x1 - self.x0)\n\n    br = bottom_right\n    bl = bottom_left\n    tl = top_left\n    tr = top_right\n\n\n# Data\n#\n\nif 1:\n    _self = sys.modules[__name__]\n    if 1:\n        for _name, _value in mupdf.__dict__.items():\n            if _name.startswith(('PDF_', 'UCDN_SCRIPT_')):\n                if _name.startswith('PDF_ENUM_NAME_'):\n                    # Not a simple enum.\n                    pass\n                else:\n                    #assert not inspect.isroutine(value)\n                    #log(f'importing {_name=} {_value=}.')\n                    setattr(_self, _name, _value)\n                    #log(f'{getattr( self, name, None)=}')\n    else:\n        # This is slow due to importing inspect, e.g. 0.019 instead of 0.004.\n        for _name, _value in inspect.getmembers(mupdf):\n            if _name.startswith(('PDF_', 'UCDN_SCRIPT_')):\n                if _name.startswith('PDF_ENUM_NAME_'):\n                    # Not a simple enum.\n                    pass\n                else:\n                    #assert not inspect.isroutine(value)\n                    #log(f'importing {name}')\n                    setattr(_self, _name, _value)\n                    #log(f'{getattr( self, name, None)=}')\n    \n    # This is a macro so not preserved in mupdf C++/Python bindings.\n    #\n    PDF_SIGNATURE_DEFAULT_APPEARANCE = (0\n            | mupdf.PDF_SIGNATURE_SHOW_LABELS\n            | mupdf.PDF_SIGNATURE_SHOW_DN\n            | mupdf.PDF_SIGNATURE_SHOW_DATE\n            | mupdf.PDF_SIGNATURE_SHOW_TEXT_NAME\n            | mupdf.PDF_SIGNATURE_SHOW_GRAPHIC_NAME\n            | mupdf.PDF_SIGNATURE_SHOW_LOGO\n            )\n\n    #UCDN_SCRIPT_ADLAM = mupdf.UCDN_SCRIPT_ADLAM\n    #setattr(self, 'UCDN_SCRIPT_ADLAM', mupdf.UCDN_SCRIPT_ADLAM)\n    \n    assert mupdf.UCDN_EAST_ASIAN_H == 1\n    \n    # Flake8 incorrectly fails next two lines because we've dynamically added\n    # items to self.\n    assert PDF_TX_FIELD_IS_MULTILINE == mupdf.PDF_TX_FIELD_IS_MULTILINE # noqa: F821\n    assert UCDN_SCRIPT_ADLAM == mupdf.UCDN_SCRIPT_ADLAM # noqa: F821\n    del _self, _name, _value\n\nAnyType = typing.Any\n\nBase14_fontnames = (\n    \"Courier\",\n    \"Courier-Oblique\",\n    \"Courier-Bold\",\n    \"Courier-BoldOblique\",\n    \"Helvetica\",\n    \"Helvetica-Oblique\",\n    \"Helvetica-Bold\",\n    \"Helvetica-BoldOblique\",\n    \"Times-Roman\",\n    \"Times-Italic\",\n    \"Times-Bold\",\n    \"Times-BoldItalic\",\n    \"Symbol\",\n    \"ZapfDingbats\",\n    )\n\nBase14_fontdict = {}\nfor f in Base14_fontnames:\n    Base14_fontdict[f.lower()] = f\nBase14_fontdict[\"helv\"] = \"Helvetica\"\nBase14_fontdict[\"heit\"] = \"Helvetica-Oblique\"\nBase14_fontdict[\"hebo\"] = \"Helvetica-Bold\"\nBase14_fontdict[\"hebi\"] = \"Helvetica-BoldOblique\"\nBase14_fontdict[\"cour\"] = \"Courier\"\nBase14_fontdict[\"coit\"] = \"Courier-Oblique\"\nBase14_fontdict[\"cobo\"] = \"Courier-Bold\"\nBase14_fontdict[\"cobi\"] = \"Courier-BoldOblique\"\nBase14_fontdict[\"tiro\"] = \"Times-Roman\"\nBase14_fontdict[\"tibo\"] = \"Times-Bold\"\nBase14_fontdict[\"tiit\"] = \"Times-Italic\"\nBase14_fontdict[\"tibi\"] = \"Times-BoldItalic\"\nBase14_fontdict[\"symb\"] = \"Symbol\"\nBase14_fontdict[\"zadb\"] = \"ZapfDingbats\"\n\nEPSILON = 1e-5\nFLT_EPSILON = 1e-5\n\n# largest 32bit integers surviving C float conversion roundtrips\n# used by MuPDF to define infinite rectangles\nFZ_MIN_INF_RECT = -0x80000000\nFZ_MAX_INF_RECT = 0x7fffff80\n\nJM_annot_id_stem = \"fitz\"\nJM_mupdf_warnings_store = []\nJM_mupdf_show_errors = 1\nJM_mupdf_show_warnings = 0\n\n\n# ------------------------------------------------------------------------------\n# Image recompression constants\n# ------------------------------------------------------------------------------\nFZ_RECOMPRESS_NEVER = mupdf.FZ_RECOMPRESS_NEVER\nFZ_RECOMPRESS_SAME = mupdf.FZ_RECOMPRESS_SAME\nFZ_RECOMPRESS_LOSSLESS = mupdf.FZ_RECOMPRESS_LOSSLESS\nFZ_RECOMPRESS_JPEG = mupdf.FZ_RECOMPRESS_JPEG\nFZ_RECOMPRESS_J2K = mupdf.FZ_RECOMPRESS_J2K\nFZ_RECOMPRESS_FAX = mupdf.FZ_RECOMPRESS_FAX\nFZ_SUBSAMPLE_AVERAGE = mupdf.FZ_SUBSAMPLE_AVERAGE\nFZ_SUBSAMPLE_BICUBIC = mupdf.FZ_SUBSAMPLE_BICUBIC\n\n# ------------------------------------------------------------------------------\n# Various PDF Optional Content Flags\n# ------------------------------------------------------------------------------\nPDF_OC_ON = 0\nPDF_OC_TOGGLE = 1\nPDF_OC_OFF = 2\n\n# ------------------------------------------------------------------------------\n# link kinds and link flags\n# ------------------------------------------------------------------------------\nLINK_NONE = 0\nLINK_GOTO = 1\nLINK_URI = 2\nLINK_LAUNCH = 3\nLINK_NAMED = 4\nLINK_GOTOR = 5\nLINK_FLAG_L_VALID = 1\nLINK_FLAG_T_VALID = 2\nLINK_FLAG_R_VALID = 4\nLINK_FLAG_B_VALID = 8\nLINK_FLAG_FIT_H = 16\nLINK_FLAG_FIT_V = 32\nLINK_FLAG_R_IS_ZOOM = 64\n\nSigFlag_SignaturesExist = 1\nSigFlag_AppendOnly = 2\n\nSTAMP_Approved = 0\nSTAMP_AsIs = 1\nSTAMP_Confidential = 2\nSTAMP_Departmental = 3\nSTAMP_Experimental = 4\nSTAMP_Expired = 5\nSTAMP_Final = 6\nSTAMP_ForComment = 7\nSTAMP_ForPublicRelease = 8\nSTAMP_NotApproved = 9\nSTAMP_NotForPublicRelease = 10\nSTAMP_Sold = 11\nSTAMP_TopSecret = 12\nSTAMP_Draft = 13\n\nTEXT_ALIGN_LEFT = 0\nTEXT_ALIGN_CENTER = 1\nTEXT_ALIGN_RIGHT = 2\nTEXT_ALIGN_JUSTIFY = 3\n\nTEXT_FONT_SUPERSCRIPT = 1\nTEXT_FONT_ITALIC = 2\nTEXT_FONT_SERIFED = 4\nTEXT_FONT_MONOSPACED = 8\nTEXT_FONT_BOLD = 16\n\nTEXT_OUTPUT_TEXT = 0\nTEXT_OUTPUT_HTML = 1\nTEXT_OUTPUT_JSON = 2\nTEXT_OUTPUT_XML = 3\nTEXT_OUTPUT_XHTML = 4\n\nTEXT_PRESERVE_LIGATURES = mupdf.FZ_STEXT_PRESERVE_LIGATURES\nTEXT_PRESERVE_WHITESPACE = mupdf.FZ_STEXT_PRESERVE_WHITESPACE\nTEXT_PRESERVE_IMAGES = mupdf.FZ_STEXT_PRESERVE_IMAGES\nTEXT_INHIBIT_SPACES = mupdf.FZ_STEXT_INHIBIT_SPACES\nTEXT_DEHYPHENATE = mupdf.FZ_STEXT_DEHYPHENATE\nTEXT_PRESERVE_SPANS = mupdf.FZ_STEXT_PRESERVE_SPANS\nTEXT_MEDIABOX_CLIP = mupdf.FZ_STEXT_MEDIABOX_CLIP\nTEXT_USE_CID_FOR_UNKNOWN_UNICODE = mupdf.FZ_STEXT_USE_CID_FOR_UNKNOWN_UNICODE\nTEXT_COLLECT_STRUCTURE = mupdf.FZ_STEXT_COLLECT_STRUCTURE\nTEXT_ACCURATE_BBOXES = mupdf.FZ_STEXT_ACCURATE_BBOXES\nTEXT_COLLECT_VECTORS = mupdf.FZ_STEXT_COLLECT_VECTORS\nTEXT_IGNORE_ACTUALTEXT = mupdf.FZ_STEXT_IGNORE_ACTUALTEXT\nTEXT_SEGMENT = mupdf.FZ_STEXT_SEGMENT\nTEXT_CLIP = mupdf.FZ_STEXT_CLIP\nif mupdf_version_tuple >= (1, 27, 1):\n    TEXT_LAZY_VECTORS = mupdf.FZ_STEXT_LAZY_VECTORS\nif mupdf_version_tuple >= (1, 27, 2):\n    TEXT_FUZZY_VECTORS = mupdf.FZ_STEXT_FUZZY_VECTORS\n\nTEXT_PARAGRAPH_BREAK = mupdf.FZ_STEXT_PARAGRAPH_BREAK\nTEXT_TABLE_HUNT = mupdf.FZ_STEXT_TABLE_HUNT\nTEXT_COLLECT_STYLES = mupdf.FZ_STEXT_COLLECT_STYLES\nTEXT_USE_GID_FOR_UNKNOWN_UNICODE = mupdf.FZ_STEXT_USE_GID_FOR_UNKNOWN_UNICODE\nTEXT_CLIP_RECT = mupdf.FZ_STEXT_CLIP_RECT\nTEXT_ACCURATE_ASCENDERS = mupdf.FZ_STEXT_ACCURATE_ASCENDERS\nTEXT_ACCURATE_SIDE_BEARINGS = mupdf.FZ_STEXT_ACCURATE_SIDE_BEARINGS\n\n# 2025-05-07: Non-standard names preserved for backwards compatibility.\nTEXT_STEXT_SEGMENT = TEXT_SEGMENT\nTEXT_CID_FOR_UNKNOWN_UNICODE = TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n\nTEXTFLAGS_WORDS = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_BLOCKS = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_DICT = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_PRESERVE_IMAGES\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_RAWDICT = TEXTFLAGS_DICT\n\nTEXTFLAGS_SEARCH = (0\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_DEHYPHENATE\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_HTML = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_PRESERVE_IMAGES\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_XHTML = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_PRESERVE_IMAGES\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_XML = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_TEXT = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n        )\n\n# Simple text encoding options\nTEXT_ENCODING_LATIN = 0\nTEXT_ENCODING_GREEK = 1\nTEXT_ENCODING_CYRILLIC = 2\n\nTOOLS_JM_UNIQUE_ID = 0\n\n# colorspace identifiers\nCS_RGB = 1\nCS_GRAY = 2\nCS_CMYK = 3\n\n# PDF Blend Modes\nPDF_BM_Color = \"Color\"\nPDF_BM_ColorBurn = \"ColorBurn\"\nPDF_BM_ColorDodge = \"ColorDodge\"\nPDF_BM_Darken = \"Darken\"\nPDF_BM_Difference = \"Difference\"\nPDF_BM_Exclusion = \"Exclusion\"\nPDF_BM_HardLight = \"HardLight\"\nPDF_BM_Hue = \"Hue\"\nPDF_BM_Lighten = \"Lighten\"\nPDF_BM_Luminosity = \"Luminosity\"\nPDF_BM_Multiply = \"Multiply\"\nPDF_BM_Normal = \"Normal\"\nPDF_BM_Overlay = \"Overlay\"\nPDF_BM_Saturation = \"Saturation\"\nPDF_BM_Screen = \"Screen\"\nPDF_BM_SoftLight = \"Softlight\"\n\n\nannot_skel = {\n        \"goto1\": lambda a, b, c, d, e: f\"<</A<</S/GoTo/D[{a} 0 R/XYZ {_format_g((b, c, d))}]>>/Rect[{e}]/BS<</W 0>>/Subtype/Link>>\",\n        \"goto2\": lambda a, b: f\"<</A<</S/GoTo/D{a}>>/Rect[{b}]/BS<</W 0>>/Subtype/Link>>\",\n        \"gotor1\": lambda a, b, c, d, e, f, g: f\"<</A<</S/GoToR/D[{a} /XYZ {_format_g((b, c, d))}]/F<</F({e})/UF({f})/Type/Filespec>>>>/Rect[{g}]/BS<</W 0>>/Subtype/Link>>\",\n        \"gotor2\": lambda a, b, c: f\"<</A<</S/GoToR/D{a}/F({b})>>/Rect[{c}]/BS<</W 0>>/Subtype/Link>>\",\n        \"launch\": lambda a, b, c: f\"<</A<</S/Launch/F<</F({a})/UF({b})/Type/Filespec>>>>/Rect[{c}]/BS<</W 0>>/Subtype/Link>>\",\n        \"uri\": lambda a, b: f\"<</A<</S/URI/URI({a})>>/Rect[{b}]/BS<</W 0>>/Subtype/Link>>\",\n        \"named\": lambda a, b: f\"<</A<</S/GoTo/D({a})/Type/Action>>/Rect[{b}]/BS<</W 0>>/Subtype/Link>>\",\n        }\n\nclass FileDataError(RuntimeError):\n    \"\"\"Raised for documents with file structure issues.\"\"\"\n    pass\n\nclass FileNotFoundError(RuntimeError):\n    \"\"\"Raised if file does not exist.\"\"\"\n    pass\n\nclass EmptyFileError(FileDataError):\n    \"\"\"Raised when creating documents from zero-length data.\"\"\"\n    pass\n\n# propagate exception class to C-level code\n#_set_FileDataError(FileDataError)\n \ncsRGB = Colorspace(CS_RGB)\ncsGRAY = Colorspace(CS_GRAY)\ncsCMYK = Colorspace(CS_CMYK)\n\n# These don't appear to be visible in classic, but are used\n# internally.\n#\ndictkey_align = \"align\"\ndictkey_asc = \"ascender\"\ndictkey_bidi = \"bidi\"\ndictkey_bbox = \"bbox\"\ndictkey_blocks = \"blocks\"\ndictkey_bpc = \"bpc\"\ndictkey_c = \"c\"\ndictkey_chars = \"chars\"\ndictkey_color = \"color\"\ndictkey_colorspace = \"colorspace\"\ndictkey_content = \"content\"\ndictkey_creationDate = \"creationDate\"\ndictkey_cs_name = \"cs-name\"\ndictkey_da = \"da\"\ndictkey_dashes = \"dashes\"\ndictkey_descr = \"description\"\ndictkey_desc = \"descender\"\ndictkey_dir = \"dir\"\ndictkey_effect = \"effect\"\ndictkey_ext = \"ext\"\ndictkey_filename = \"filename\"\ndictkey_fill = \"fill\"\ndictkey_flags = \"flags\"\ndictkey_char_flags = \"char_flags\"\ndictkey_font = \"font\"\ndictkey_glyph = \"glyph\"\ndictkey_height = \"height\"\ndictkey_id = \"id\"\ndictkey_image = \"image\"\ndictkey_items = \"items\"\ndictkey_length = \"length\"\ndictkey_lines = \"lines\"\ndictkey_matrix = \"transform\"\ndictkey_modDate = \"modDate\"\ndictkey_name = \"name\"\ndictkey_number = \"number\"\ndictkey_origin = \"origin\"\ndictkey_rect = \"rect\"\ndictkey_size = \"size\"\ndictkey_smask = \"smask\"\ndictkey_spans = \"spans\"\ndictkey_stroke = \"stroke\"\ndictkey_style = \"style\"\ndictkey_subject = \"subject\"\ndictkey_text = \"text\"\ndictkey_title = \"title\"\ndictkey_type = \"type\"\ndictkey_ufilename = \"ufilename\"\ndictkey_width = \"width\"\ndictkey_wmode = \"wmode\"\ndictkey_xref = \"xref\"\ndictkey_xres = \"xres\"\ndictkey_yres = \"yres\"\n\n\ntry:\n    from pymupdf_fonts import fontdescriptors, fontbuffers\n\n    fitz_fontdescriptors = fontdescriptors.copy()\n    for k in fitz_fontdescriptors.keys():\n        fitz_fontdescriptors[k][\"loader\"] = fontbuffers[k]\n    del fontdescriptors, fontbuffers\nexcept ImportError:\n    fitz_fontdescriptors = {}\n\nsymbol_glyphs = (   # Glyph list for the built-in font 'Symbol'\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (32, 0.25),\n        (33, 0.333),\n        (34, 0.713),\n        (35, 0.5),\n        (36, 0.549),\n        (37, 0.833),\n        (38, 0.778),\n        (39, 0.439),\n        (40, 0.333),\n        (41, 0.333),\n        (42, 0.5),\n        (43, 0.549),\n        (44, 0.25),\n        (45, 0.549),\n        (46, 0.25),\n        (47, 0.278),\n        (48, 0.5),\n        (49, 0.5),\n        (50, 0.5),\n        (51, 0.5),\n        (52, 0.5),\n        (53, 0.5),\n        (54, 0.5),\n        (55, 0.5),\n        (56, 0.5),\n        (57, 0.5),\n        (58, 0.278),\n        (59, 0.278),\n        (60, 0.549),\n        (61, 0.549),\n        (62, 0.549),\n        (63, 0.444),\n        (64, 0.549),\n        (65, 0.722),\n        (66, 0.667),\n        (67, 0.722),\n        (68, 0.612),\n        (69, 0.611),\n        (70, 0.763),\n        (71, 0.603),\n        (72, 0.722),\n        (73, 0.333),\n        (74, 0.631),\n        (75, 0.722),\n        (76, 0.686),\n        (77, 0.889),\n        (78, 0.722),\n        (79, 0.722),\n        (80, 0.768),\n        (81, 0.741),\n        (82, 0.556),\n        (83, 0.592),\n        (84, 0.611),\n        (85, 0.69),\n        (86, 0.439),\n        (87, 0.768),\n        (88, 0.645),\n        (89, 0.795),\n        (90, 0.611),\n        (91, 0.333),\n        (92, 0.863),\n        (93, 0.333),\n        (94, 0.658),\n        (95, 0.5),\n        (96, 0.5),\n        (97, 0.631),\n        (98, 0.549),\n        (99, 0.549),\n        (100, 0.494),\n        (101, 0.439),\n        (102, 0.521),\n        (103, 0.411),\n        (104, 0.603),\n        (105, 0.329),\n        (106, 0.603),\n        (107, 0.549),\n        (108, 0.549),\n        (109, 0.576),\n        (110, 0.521),\n        (111, 0.549),\n        (112, 0.549),\n        (113, 0.521),\n        (114, 0.549),\n        (115, 0.603),\n        (116, 0.439),\n        (117, 0.576),\n        (118, 0.713),\n        (119, 0.686),\n        (120, 0.493),\n        (121, 0.686),\n        (122, 0.494),\n        (123, 0.48),\n        (124, 0.2),\n        (125, 0.48),\n        (126, 0.549),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (183, 0.46),\n        (160, 0.25),\n        (161, 0.62),\n        (162, 0.247),\n        (163, 0.549),\n        (164, 0.167),\n        (165, 0.713),\n        (166, 0.5),\n        (167, 0.753),\n        (168, 0.753),\n        (169, 0.753),\n        (170, 0.753),\n        (171, 1.042),\n        (172, 0.713),\n        (173, 0.603),\n        (174, 0.987),\n        (175, 0.603),\n        (176, 0.4),\n        (177, 0.549),\n        (178, 0.411),\n        (179, 0.549),\n        (180, 0.549),\n        (181, 0.576),\n        (182, 0.494),\n        (183, 0.46),\n        (184, 0.549),\n        (185, 0.549),\n        (186, 0.549),\n        (187, 0.549),\n        (188, 1),\n        (189, 0.603),\n        (190, 1),\n        (191, 0.658),\n        (192, 0.823),\n        (193, 0.686),\n        (194, 0.795),\n        (195, 0.987),\n        (196, 0.768),\n        (197, 0.768),\n        (198, 0.823),\n        (199, 0.768),\n        (200, 0.768),\n        (201, 0.713),\n        (202, 0.713),\n        (203, 0.713),\n        (204, 0.713),\n        (205, 0.713),\n        (206, 0.713),\n        (207, 0.713),\n        (208, 0.768),\n        (209, 0.713),\n        (210, 0.79),\n        (211, 0.79),\n        (212, 0.89),\n        (213, 0.823),\n        (214, 0.549),\n        (215, 0.549),\n        (216, 0.713),\n        (217, 0.603),\n        (218, 0.603),\n        (219, 1.042),\n        (220, 0.987),\n        (221, 0.603),\n        (222, 0.987),\n        (223, 0.603),\n        (224, 0.494),\n        (225, 0.329),\n        (226, 0.79),\n        (227, 0.79),\n        (228, 0.786),\n        (229, 0.713),\n        (230, 0.384),\n        (231, 0.384),\n        (232, 0.384),\n        (233, 0.384),\n        (234, 0.384),\n        (235, 0.384),\n        (236, 0.494),\n        (237, 0.494),\n        (238, 0.494),\n        (239, 0.494),\n        (183, 0.46),\n        (241, 0.329),\n        (242, 0.274),\n        (243, 0.686),\n        (244, 0.686),\n        (245, 0.686),\n        (246, 0.384),\n        (247, 0.549),\n        (248, 0.384),\n        (249, 0.384),\n        (250, 0.384),\n        (251, 0.384),\n        (252, 0.494),\n        (253, 0.494),\n        (254, 0.494),\n        (183, 0.46),\n        )\n\n\nzapf_glyphs = ( # Glyph list for the built-in font 'ZapfDingbats'\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (32, 0.278),\n        (33, 0.974),\n        (34, 0.961),\n        (35, 0.974),\n        (36, 0.98),\n        (37, 0.719),\n        (38, 0.789),\n        (39, 0.79),\n        (40, 0.791),\n        (41, 0.69),\n        (42, 0.96),\n        (43, 0.939),\n        (44, 0.549),\n        (45, 0.855),\n        (46, 0.911),\n        (47, 0.933),\n        (48, 0.911),\n        (49, 0.945),\n        (50, 0.974),\n        (51, 0.755),\n        (52, 0.846),\n        (53, 0.762),\n        (54, 0.761),\n        (55, 0.571),\n        (56, 0.677),\n        (57, 0.763),\n        (58, 0.76),\n        (59, 0.759),\n        (60, 0.754),\n        (61, 0.494),\n        (62, 0.552),\n        (63, 0.537),\n        (64, 0.577),\n        (65, 0.692),\n        (66, 0.786),\n        (67, 0.788),\n        (68, 0.788),\n        (69, 0.79),\n        (70, 0.793),\n        (71, 0.794),\n        (72, 0.816),\n        (73, 0.823),\n        (74, 0.789),\n        (75, 0.841),\n        (76, 0.823),\n        (77, 0.833),\n        (78, 0.816),\n        (79, 0.831),\n        (80, 0.923),\n        (81, 0.744),\n        (82, 0.723),\n        (83, 0.749),\n        (84, 0.79),\n        (85, 0.792),\n        (86, 0.695),\n        (87, 0.776),\n        (88, 0.768),\n        (89, 0.792),\n        (90, 0.759),\n        (91, 0.707),\n        (92, 0.708),\n        (93, 0.682),\n        (94, 0.701),\n        (95, 0.826),\n        (96, 0.815),\n        (97, 0.789),\n        (98, 0.789),\n        (99, 0.707),\n        (100, 0.687),\n        (101, 0.696),\n        (102, 0.689),\n        (103, 0.786),\n        (104, 0.787),\n        (105, 0.713),\n        (106, 0.791),\n        (107, 0.785),\n        (108, 0.791),\n        (109, 0.873),\n        (110, 0.761),\n        (111, 0.762),\n        (112, 0.762),\n        (113, 0.759),\n        (114, 0.759),\n        (115, 0.892),\n        (116, 0.892),\n        (117, 0.788),\n        (118, 0.784),\n        (119, 0.438),\n        (120, 0.138),\n        (121, 0.277),\n        (122, 0.415),\n        (123, 0.392),\n        (124, 0.392),\n        (125, 0.668),\n        (126, 0.668),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (183, 0.788),\n        (161, 0.732),\n        (162, 0.544),\n        (163, 0.544),\n        (164, 0.91),\n        (165, 0.667),\n        (166, 0.76),\n        (167, 0.76),\n        (168, 0.776),\n        (169, 0.595),\n        (170, 0.694),\n        (171, 0.626),\n        (172, 0.788),\n        (173, 0.788),\n        (174, 0.788),\n        (175, 0.788),\n        (176, 0.788),\n        (177, 0.788),\n        (178, 0.788),\n        (179, 0.788),\n        (180, 0.788),\n        (181, 0.788),\n        (182, 0.788),\n        (183, 0.788),\n        (184, 0.788),\n        (185, 0.788),\n        (186, 0.788),\n        (187, 0.788),\n        (188, 0.788),\n        (189, 0.788),\n        (190, 0.788),\n        (191, 0.788),\n        (192, 0.788),\n        (193, 0.788),\n        (194, 0.788),\n        (195, 0.788),\n        (196, 0.788),\n        (197, 0.788),\n        (198, 0.788),\n        (199, 0.788),\n        (200, 0.788),\n        (201, 0.788),\n        (202, 0.788),\n        (203, 0.788),\n        (204, 0.788),\n        (205, 0.788),\n        (206, 0.788),\n        (207, 0.788),\n        (208, 0.788),\n        (209, 0.788),\n        (210, 0.788),\n        (211, 0.788),\n        (212, 0.894),\n        (213, 0.838),\n        (214, 1.016),\n        (215, 0.458),\n        (216, 0.748),\n        (217, 0.924),\n        (218, 0.748),\n        (219, 0.918),\n        (220, 0.927),\n        (221, 0.928),\n        (222, 0.928),\n        (223, 0.834),\n        (224, 0.873),\n        (225, 0.828),\n        (226, 0.924),\n        (227, 0.924),\n        (228, 0.917),\n        (229, 0.93),\n        (230, 0.931),\n        (231, 0.463),\n        (232, 0.883),\n        (233, 0.836),\n        (234, 0.836),\n        (235, 0.867),\n        (236, 0.867),\n        (237, 0.696),\n        (238, 0.696),\n        (239, 0.874),\n        (183, 0.788),\n        (241, 0.874),\n        (242, 0.76),\n        (243, 0.946),\n        (244, 0.771),\n        (245, 0.865),\n        (246, 0.771),\n        (247, 0.888),\n        (248, 0.967),\n        (249, 0.888),\n        (250, 0.831),\n        (251, 0.873),\n        (252, 0.927),\n        (253, 0.97),\n        (183, 0.788),\n        (183, 0.788),\n        )\n\n\n# Functions\n#\n\ndef _rect_area(width, height, args):\n    # Used by IRect.get_area() and Rect.get_area().\n    unit = args[0] if args else 'px'\n    u = {\"px\": (1, 1), \"in\": (1.0, 72.0), \"cm\": (2.54, 72.0), \"mm\": (25.4, 72.0)}\n    f = (u[unit][0] / u[unit][1]) ** 2\n    return f * width * height\n\ndef _read_samples( pixmap, offset, n):\n    # fixme: need to be able to get a sample in one call, as a Python\n    # bytes or similar.\n    ret = []\n    if not pixmap.samples():\n        # mupdf.fz_samples_get() gives a segv if pixmap->samples is null.\n        return ret\n    for i in range( n):\n        ret.append( mupdf.fz_samples_get( pixmap, offset + i))\n    return bytes( ret)\n\n\ndef _INRANGE(v, low, high):\n    return low <= v and v <= high\n\n\ndef _remove_dest_range(pdf, numbers):\n    pagecount = mupdf.pdf_count_pages(pdf)\n    for i in range(pagecount):\n        n1 = i\n        if n1 in numbers:\n            continue\n\n        pageref = mupdf.pdf_lookup_page_obj( pdf, i)\n        annots = mupdf.pdf_dict_get( pageref, PDF_NAME('Annots'))\n        if not annots.m_internal:\n            continue\n        len_ = mupdf.pdf_array_len(annots)\n        for j in range(len_ - 1, -1, -1):\n            o = mupdf.pdf_array_get( annots, j)\n            if not mupdf.pdf_name_eq( mupdf.pdf_dict_get( o, PDF_NAME('Subtype')), PDF_NAME('Link')):\n                continue\n            action = mupdf.pdf_dict_get( o, PDF_NAME('A'))\n            dest = mupdf.pdf_dict_get( o, PDF_NAME('Dest'))\n            if action.m_internal:\n                if not mupdf.pdf_name_eq( mupdf.pdf_dict_get( action, PDF_NAME('S')), PDF_NAME('GoTo')):\n                    continue\n                dest = mupdf.pdf_dict_get( action, PDF_NAME('D'))\n            pno = -1\n            if mupdf.pdf_is_array( dest):\n                target = mupdf.pdf_array_get( dest, 0)\n                pno = mupdf.pdf_lookup_page_number( pdf, target)\n            elif mupdf.pdf_is_string( dest):\n                location, _, _ = mupdf.fz_resolve_link( pdf.super(), mupdf.pdf_to_text_string( dest))\n                pno = location.page\n            if pno < 0: # page number lookup did not work\n                continue\n            n1 = pno\n            if n1 in numbers:\n                mupdf.pdf_array_delete( annots, j)\n\n\ndef ASSERT_PDF(cond):\n    assert isinstance(cond, (mupdf.PdfPage, mupdf.PdfDocument)), f'{type(cond)=} {cond=}'\n    if not cond.m_internal:\n        raise Exception(MSG_IS_NO_PDF)\n\n\ndef EMPTY_IRECT():\n    return IRect(FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT)\n\n\ndef EMPTY_QUAD():\n    return EMPTY_RECT().quad\n\n\ndef EMPTY_RECT():\n    return Rect(FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT)\n\n\ndef ENSURE_OPERATION(pdf):\n    if not JM_have_operation(pdf):\n        raise Exception(\"No journalling operation started\")\n\n\ndef INFINITE_IRECT():\n    return IRect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT)\n\n\ndef INFINITE_QUAD():\n    return INFINITE_RECT().quad\n\n\ndef INFINITE_RECT():\n    return Rect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT)\n\n\ndef JM_BinFromBuffer(buffer_):\n    '''\n    Turn fz_buffer into a Python bytes object\n    '''\n    assert isinstance(buffer_, mupdf.FzBuffer)\n    ret = mupdf.fz_buffer_extract_copy(buffer_)\n    return ret\n\n\ndef JM_EscapeStrFromStr(c):\n    # `c` is typically from SWIG which will have converted a `const char*` from\n    # C into a Python `str` using `PyUnicode_DecodeUTF8(carray, static_cast<\n    # Py_ssize_t >(size), \"surrogateescape\")`.  This gives us a Python `str`\n    # with some characters encoded as a \\0xdcXY sequence, where `XY` are hex\n    # digits for an invalid byte in the original `const char*`.\n    #\n    # This is actually a reasonable way of representing arbitrary\n    # strings from C, but we want to mimic what PyMuPDF does. It uses\n    # `PyUnicode_DecodeRawUnicodeEscape(c, (Py_ssize_t) strlen(c), \"replace\")`\n    # which gives a string containing actual unicode characters for any invalid\n    # bytes.\n    #\n    # We mimic this by converting the `str` to a `bytes` with 'surrogateescape'\n    # to recognise \\0xdcXY sequences, then convert the individual bytes into a\n    # `str` using `chr()`.\n    #\n    # Would be good to have a more efficient way to do this.\n    #\n    if c is None:\n        return ''\n    assert isinstance(c, str), f'{type(c)=}'\n    b = c.encode('utf8', 'surrogateescape')\n    ret = ''\n    for bb in b:\n        ret += chr(bb)\n    return ret\n\n\ndef JM_BufferFromBytes(stream):\n    '''\n    Make fz_buffer from a PyBytes, PyByteArray or io.BytesIO object. If a text\n    io.BytesIO, we convert to binary by encoding as utf8.\n    '''\n    if isinstance(stream, (bytes, bytearray)):\n        data = stream\n    elif hasattr(stream, 'getvalue'):\n        data = stream.getvalue()\n        if isinstance(data, str):\n            data = data.encode('utf-8')\n        if not isinstance(data, (bytes, bytearray)):\n            raise Exception(f'.getvalue() returned unexpected type: {type(data)}')\n    else:\n        return mupdf.FzBuffer()\n    return mupdf.fz_new_buffer_from_copied_data(data)\n\n\ndef JM_FLOAT_ITEM(obj, idx):\n    if not PySequence_Check(obj):\n        return None\n    return float(obj[idx])\n\ndef JM_INT_ITEM(obj, idx):\n    if idx < len(obj):\n        temp = obj[idx]\n        if isinstance(temp, (int, float)):\n            return 0, temp\n    return 1, None\n\n\ndef JM_pixmap_from_page(doc, page, ctm, cs, alpha, annots, clip):\n    '''\n    Pixmap creation directly using a short-lived displaylist, so we can support\n    separations.\n    '''\n    SPOTS_NONE = 0\n    SPOTS_OVERPRINT_SIM = 1\n    SPOTS_FULL = 2\n    \n    FZ_ENABLE_SPOT_RENDERING = True # fixme: this is a build-time setting in MuPDF's config.h.\n    if FZ_ENABLE_SPOT_RENDERING:\n        spots = SPOTS_OVERPRINT_SIM\n    else:\n        spots = SPOTS_NONE\n\n    seps = None\n    colorspace = cs\n    \n    matrix = JM_matrix_from_py(ctm)\n    rect = mupdf.fz_bound_page(page)\n    rclip = JM_rect_from_py(clip)\n    rect = mupdf.fz_intersect_rect(rect, rclip) # no-op if clip is not given\n    rect = mupdf.fz_transform_rect(rect, matrix)\n    bbox = mupdf.fz_round_rect(rect)\n\n    # Pixmap of the document's /OutputIntents (\"output intents\")\n    oi = mupdf.fz_document_output_intent(doc)\n    # if present and compatible, use it instead of the parameter\n    if oi.m_internal:\n        if mupdf.fz_colorspace_n(oi) == mupdf.fz_colorspace_n(cs):\n            colorspace = mupdf.fz_keep_colorspace(oi)\n\n    # check if spots rendering is available and if so use separations\n    if spots != SPOTS_NONE:\n        seps = mupdf.fz_page_separations(page)\n        if seps.m_internal:\n            n = mupdf.fz_count_separations(seps)\n            if spots == SPOTS_FULL:\n                for i in range(n):\n                    mupdf.fz_set_separation_behavior(seps, i, mupdf.FZ_SEPARATION_SPOT)\n            else:\n                for i in range(n):\n                    mupdf.fz_set_separation_behavior(seps, i, mupdf.FZ_SEPARATION_COMPOSITE)\n        elif mupdf.fz_page_uses_overprint(page):\n            # This page uses overprint, so we need an empty\n            # sep object to force the overprint simulation on.\n            seps = mupdf.fz_new_separations(0)\n        elif oi.m_internal and mupdf.fz_colorspace_n(oi) != mupdf.fz_colorspace_n(colorspace):\n            # We have an output intent, and it's incompatible\n            # with the colorspace our device needs. Force the\n            # overprint simulation on, because this ensures that\n            # we 'simulate' the output intent too.\n            seps = mupdf.fz_new_separations(0)\n\n    pix = mupdf.fz_new_pixmap_with_bbox(colorspace, bbox, seps, alpha)\n\n    if alpha:\n        mupdf.fz_clear_pixmap(pix)\n    else:\n        mupdf.fz_clear_pixmap_with_value(pix, 0xFF)\n\n    dev = mupdf.fz_new_draw_device(matrix, pix)\n    if annots:\n        mupdf.fz_run_page(page, dev, mupdf.FzMatrix(), mupdf.FzCookie())\n    else:\n        mupdf.fz_run_page_contents(page, dev, mupdf.FzMatrix(), mupdf.FzCookie())\n    mupdf.fz_close_device(dev)\n    return pix\n\n\ndef JM_StrAsChar(x):\n    # fixme: should encode, but swig doesn't pass bytes to C as const char*.\n    return x\n    #return x.encode('utf8')\n\n\ndef JM_TUPLE(o: typing.Sequence) -> tuple:\n    return tuple(map(lambda x: round(x, 5) if abs(x) >= 1e-4 else 0, o))\n\n\ndef JM_TUPLE3(o: typing.Sequence) -> tuple:\n    return tuple(map(lambda x: round(x, 3) if abs(x) >= 1e-3 else 0, o))\n\n\ndef JM_UnicodeFromStr(s):\n    if s is None:\n        return ''\n    if isinstance(s, bytes):\n        s = s.decode('utf8')\n    assert isinstance(s, str), f'{type(s)=} {s=}'\n    return s\n\n\ndef JM_add_annot_id(annot, stem):\n    '''\n    Add a unique /NM key to an annotation or widget.\n    Append a number to 'stem' such that the result is a unique name.\n    '''\n    assert isinstance(annot, mupdf.PdfAnnot)\n    page = _pdf_annot_page(annot)\n    annot_obj = mupdf.pdf_annot_obj( annot)\n    names = JM_get_annot_id_list(page)\n    i = 0\n    while 1:\n        stem_id = f'{JM_annot_id_stem}-{stem}{i}'\n        if stem_id not in names:\n            break\n        i += 1\n    response = JM_StrAsChar(stem_id)\n    name = mupdf.pdf_new_string( response, len(response))\n    mupdf.pdf_dict_puts(annot_obj, \"NM\", name)\n    page.doc().m_internal.resynth_required = 0\n\n\ndef JM_add_oc_object(pdf, ref, xref):\n    '''\n    Add OC object reference to a dictionary\n    '''\n    indobj = mupdf.pdf_new_indirect(pdf, xref, 0)\n    if not mupdf.pdf_is_dict(indobj):\n        RAISEPY(MSG_BAD_OC_REF, PyExc_ValueError)\n    type_ = mupdf.pdf_dict_get(indobj, PDF_NAME('Type'))\n    if (mupdf.pdf_objcmp(type_, PDF_NAME('OCG')) == 0\n            or mupdf.pdf_objcmp(type_, PDF_NAME('OCMD')) == 0\n            ):\n        mupdf.pdf_dict_put(ref, PDF_NAME('OC'), indobj)\n    else:\n        RAISEPY(MSG_BAD_OC_REF, PyExc_ValueError)\n\n\ndef JM_annot_border(annot_obj):\n    dash_py = list()\n    style = None\n    width = -1\n    clouds = -1\n    obj = None\n\n    obj = mupdf.pdf_dict_get( annot_obj, PDF_NAME('Border'))\n    if mupdf.pdf_is_array( obj):\n        width = mupdf.pdf_to_real( mupdf.pdf_array_get( obj, 2))\n        if mupdf.pdf_array_len( obj) == 4:\n            dash = mupdf.pdf_array_get( obj, 3)\n            for i in range( mupdf.pdf_array_len( dash)):\n                val = mupdf.pdf_to_int( mupdf.pdf_array_get( dash, i))\n                dash_py.append( val)\n\n    bs_o = mupdf.pdf_dict_get( annot_obj, PDF_NAME('BS'))\n    if bs_o.m_internal:\n        width = mupdf.pdf_to_real( mupdf.pdf_dict_get( bs_o, PDF_NAME('W')))\n        style = mupdf.pdf_to_name( mupdf.pdf_dict_get( bs_o, PDF_NAME('S')))\n        if style == '':\n            style = None\n        obj = mupdf.pdf_dict_get( bs_o, PDF_NAME('D'))\n        if obj.m_internal:\n            for i in range( mupdf.pdf_array_len( obj)):\n                val = mupdf.pdf_to_int( mupdf.pdf_array_get( obj, i))\n                dash_py.append( val)\n\n    obj = mupdf.pdf_dict_get( annot_obj, PDF_NAME('BE'))\n    if obj.m_internal:\n        clouds = mupdf.pdf_to_int( mupdf.pdf_dict_get( obj, PDF_NAME('I')))\n\n    res = dict()\n    res[ dictkey_width] = width\n    res[ dictkey_dashes] = tuple( dash_py)\n    res[ dictkey_style] = style\n    res[ 'clouds'] = clouds\n    return res\n\n\ndef JM_annot_colors(annot_obj):\n    res = dict()\n    bc = list() # stroke colors\n    fc =list()  # fill colors\n    o = mupdf.pdf_dict_get(annot_obj, mupdf.PDF_ENUM_NAME_C)\n    if mupdf.pdf_is_array(o):\n        n = mupdf.pdf_array_len(o)\n        for i in range(n):\n            col = mupdf.pdf_to_real( mupdf.pdf_array_get(o, i))\n            bc.append(col)\n    res[dictkey_stroke] = bc\n\n    o = mupdf.pdf_dict_gets(annot_obj, \"IC\")\n    if mupdf.pdf_is_array(o):\n        n = mupdf.pdf_array_len(o)\n        for i in range(n):\n            col = mupdf.pdf_to_real( mupdf.pdf_array_get(o, i))\n            fc.append(col)\n\n    res[dictkey_fill] = fc\n    return res\n\n\ndef JM_annot_set_border( border, doc, annot_obj):\n    assert isinstance(border, dict)\n    obj = None\n    dashlen = 0\n    nwidth = border.get( dictkey_width)     # new width\n    ndashes = border.get( dictkey_dashes)   # new dashes\n    nstyle = border.get( dictkey_style)     # new style\n    nclouds  = border.get( 'clouds', -1)    # new clouds value\n\n    # get old border properties\n    oborder = JM_annot_border( annot_obj)\n\n    # delete border-related entries\n    mupdf.pdf_dict_del( annot_obj, PDF_NAME('BS'))\n    mupdf.pdf_dict_del( annot_obj, PDF_NAME('BE'))\n    mupdf.pdf_dict_del( annot_obj, PDF_NAME('Border'))\n\n    # populate border items: keep old values for any omitted new ones\n    if nwidth < 0:\n        nwidth = oborder.get( dictkey_width)    # no new width: keep current\n    if ndashes is None:\n        ndashes = oborder.get( dictkey_dashes)  # no new dashes: keep old\n    if nstyle is None:\n        nstyle  = oborder.get( dictkey_style)   # no new style: keep old\n    if nclouds < 0:\n        nclouds  = oborder.get( \"clouds\", -1)   # no new clouds: keep old\n\n    if isinstance( ndashes, tuple) and len( ndashes) > 0:\n        dashlen = len( ndashes)\n        darr = mupdf.pdf_new_array( doc, dashlen)\n        for d in ndashes:\n            mupdf.pdf_array_push_int( darr, d)\n        mupdf.pdf_dict_putl( annot_obj, darr, PDF_NAME('BS'), PDF_NAME('D'))\n\n    mupdf.pdf_dict_putl(\n            annot_obj,\n            mupdf.pdf_new_real( nwidth),\n            PDF_NAME('BS'),\n            PDF_NAME('W'),\n            )\n\n    if dashlen == 0:\n        obj = JM_get_border_style( nstyle)\n    else:\n        obj = PDF_NAME('D')\n    mupdf.pdf_dict_putl( annot_obj, obj, PDF_NAME('BS'), PDF_NAME('S'))\n\n    if nclouds > 0:\n        mupdf.pdf_dict_put_dict( annot_obj, PDF_NAME('BE'), 2)\n        obj = mupdf.pdf_dict_get( annot_obj, PDF_NAME('BE'))\n        mupdf.pdf_dict_put( obj, PDF_NAME('S'), PDF_NAME('C'))\n        mupdf.pdf_dict_put_int( obj, PDF_NAME('I'), nclouds)\n\n\ndef make_escape(ch):\n    if ch == 92:\n        return \"\\\\u005c\"\n    elif 32 <= ch <= 127 or ch == 10:\n        return chr(ch)\n    elif 0xd800 <= ch <= 0xdfff:  # orphaned surrogate\n        return \"\\\\ufffd\"\n    elif ch <= 0xffff:\n        return f\"\\\\u{ch:04x}\"\n    else:\n        return f\"\\\\U{ch:08x}\"\n\n\ndef JM_append_rune(buff, ch):\n    \"\"\"\n    APPEND non-ascii runes in unicode escape format to fz_buffer.\n    \"\"\"\n    mupdf.fz_append_string(buff, make_escape(ch))\n\n\ndef JM_append_word(lines, buff, wbbox, block_n, line_n, word_n):\n    '''\n    Functions for wordlist output\n    '''\n    s = JM_EscapeStrFromBuffer(buff)\n    litem = (\n            wbbox.x0,\n            wbbox.y0,\n            wbbox.x1,\n            wbbox.y1,\n            s,\n            block_n,\n            line_n,\n            word_n,\n            )\n    lines.append(litem)\n    return word_n + 1, mupdf.FzRect(mupdf.FzRect.Fixed_EMPTY)   # word counter\n\n\ndef JM_add_layer_config( pdf, name, creator, ON):\n    '''\n    Add OC configuration to the PDF catalog\n    '''\n    ocp = JM_ensure_ocproperties( pdf)\n    configs = mupdf.pdf_dict_get( ocp, PDF_NAME('Configs'))\n    if not mupdf.pdf_is_array( configs):\n        configs = mupdf.pdf_dict_put_array( ocp, PDF_NAME('Configs'), 1)\n    D = mupdf.pdf_new_dict( pdf, 5)\n    mupdf.pdf_dict_put_text_string( D, PDF_NAME('Name'), name)\n    if creator is not None:\n        mupdf.pdf_dict_put_text_string( D, PDF_NAME('Creator'), creator)\n    mupdf.pdf_dict_put( D, PDF_NAME('BaseState'), PDF_NAME('OFF'))\n    onarray = mupdf.pdf_dict_put_array( D, PDF_NAME('ON'), 5)\n    if not ON:\n        pass\n    else:\n        ocgs = mupdf.pdf_dict_get( ocp, PDF_NAME('OCGs'))\n        n = len(ON)\n        for i in range(n):\n            xref = 0\n            e, xref = JM_INT_ITEM(ON, i)\n            if e == 1:\n                continue\n            ind = mupdf.pdf_new_indirect( pdf, xref, 0)\n            if mupdf.pdf_array_contains( ocgs, ind):\n                mupdf.pdf_array_push( onarray, ind)\n    mupdf.pdf_array_push( configs, D)\n\n\ndef JM_char_bbox(line, ch):\n    '''\n    return rect of char quad\n    '''\n    q = JM_char_quad(line, ch)\n    r = mupdf.fz_rect_from_quad(q)\n    if not line.m_internal.wmode:\n        return r\n    if r.y1 < r.y0 + ch.m_internal.size:\n        r.y0 = r.y1 - ch.m_internal.size\n    return r\n\n\ndef JM_char_font_flags(font, line, ch):\n    flags = 0\n    if line and ch:\n        flags += detect_super_script(line, ch)\n    flags += mupdf.fz_font_is_italic(font) * TEXT_FONT_ITALIC\n    flags += mupdf.fz_font_is_serif(font) * TEXT_FONT_SERIFED\n    flags += mupdf.fz_font_is_monospaced(font) * TEXT_FONT_MONOSPACED\n    flags += mupdf.fz_font_is_bold(font) * TEXT_FONT_BOLD\n    return flags\n\n\ndef JM_char_quad(line, ch):\n    '''\n    re-compute char quad if ascender/descender values make no sense\n    '''\n    if 1 and g_use_extra:\n        # This reduces time taken to extract text from PyMuPDF.pdf from 20s to\n        # 15s.\n        return mupdf.FzQuad(extra.JM_char_quad( line.m_internal, ch.m_internal))\n        \n    assert isinstance(line, mupdf.FzStextLine)\n    assert isinstance(ch, mupdf.FzStextChar)\n    if _globals.skip_quad_corrections:   # no special handling\n        return ch.quad\n    if line.m_internal.wmode:  # never touch vertical write mode\n        return ch.quad\n    font = mupdf.FzFont(mupdf.ll_fz_keep_font(ch.m_internal.font))\n    asc = JM_font_ascender(font)\n    dsc = JM_font_descender(font)\n    fsize = ch.m_internal.size\n    asc_dsc = asc - dsc + FLT_EPSILON\n    if asc_dsc >= 1 and _globals.small_glyph_heights == 0:   # no problem\n        return mupdf.FzQuad(ch.m_internal.quad)\n\n    # Re-compute quad with adjusted ascender / descender values:\n    # Move ch->origin to (0,0) and de-rotate quad, then adjust the corners,\n    # re-rotate and move back to ch->origin location.\n    fsize = ch.m_internal.size\n    bbox = mupdf.fz_font_bbox(font)\n    fwidth = bbox.x1 - bbox.x0\n    if asc < 1e-3:  # probably Tesseract glyphless font\n        dsc = -0.1\n        asc = 0.9\n        asc_dsc = 1.0\n    \n    if _globals.small_glyph_heights or asc_dsc < 1:\n        dsc = dsc / asc_dsc\n        asc = asc / asc_dsc\n    asc_dsc = asc - dsc\n    asc = asc * fsize / asc_dsc\n    dsc = dsc * fsize / asc_dsc\n    \n    # Re-compute quad with the adjusted ascender / descender values:\n    # Move ch->origin to (0,0) and de-rotate quad, then adjust the corners,\n    # re-rotate and move back to ch->origin location.\n    c = line.m_internal.dir.x  # cosine\n    s = line.m_internal.dir.y  # sine\n    trm1 = mupdf.fz_make_matrix(c, -s, s, c, 0, 0) # derotate\n    trm2 = mupdf.fz_make_matrix(c, s, -s, c, 0, 0) # rotate\n    if (c == -1):   # left-right flip\n        trm1.d = 1\n        trm2.d = 1\n    xlate1 = mupdf.fz_make_matrix(1, 0, 0, 1, -ch.m_internal.origin.x, -ch.m_internal.origin.y)\n    xlate2 = mupdf.fz_make_matrix(1, 0, 0, 1, ch.m_internal.origin.x, ch.m_internal.origin.y)\n\n    quad = mupdf.fz_transform_quad(mupdf.FzQuad(ch.m_internal.quad), xlate1)    # move origin to (0,0)\n    quad = mupdf.fz_transform_quad(quad, trm1) # de-rotate corners\n    \n    # adjust vertical coordinates\n    if c == 1 and quad.ul.y > 0:    # up-down flip\n        quad.ul.y = asc\n        quad.ur.y = asc\n        quad.ll.y = dsc\n        quad.lr.y = dsc\n    else:\n        quad.ul.y = -asc\n        quad.ur.y = -asc\n        quad.ll.y = -dsc\n        quad.lr.y = -dsc\n\n    # adjust horizontal coordinates that are too crazy:\n    # (1) left x must be >= 0\n    # (2) if bbox width is 0, lookup char advance in font.\n    if quad.ll.x < 0:\n        quad.ll.x = 0\n        quad.ul.x = 0\n    \n    cwidth = quad.lr.x - quad.ll.x\n    if cwidth < FLT_EPSILON:\n        glyph = mupdf.fz_encode_character( font, ch.m_internal.c)\n        if glyph:\n            fwidth = mupdf.fz_advance_glyph( font, glyph, line.m_internal.wmode)\n            quad.lr.x = quad.ll.x + fwidth * fsize\n            quad.ur.x = quad.lr.x\n\n    quad = mupdf.fz_transform_quad(quad, trm2) # rotate back\n    quad = mupdf.fz_transform_quad(quad, xlate2)   # translate back\n    return quad\n\n\ndef JM_choice_options(annot):\n    '''\n    return list of choices for list or combo boxes\n    '''\n    annot_obj = mupdf.pdf_annot_obj( annot.this)\n    \n    opts = mupdf.pdf_choice_widget_options2( annot, 0)\n    n = len( opts)\n    if n == 0:\n        return  # wrong widget type\n\n    optarr = mupdf.pdf_dict_get( annot_obj, PDF_NAME('Opt'))\n    liste = []\n\n    for i in range( n):\n        m = mupdf.pdf_array_len( mupdf.pdf_array_get( optarr, i))\n        if m == 2:\n            val = (\n                    mupdf.pdf_to_text_string( mupdf.pdf_array_get( mupdf.pdf_array_get( optarr, i), 0)),\n                    mupdf.pdf_to_text_string( mupdf.pdf_array_get( mupdf.pdf_array_get( optarr, i), 1)),\n                    )\n            liste.append( val)\n        else:\n            val = mupdf.pdf_to_text_string( mupdf.pdf_array_get( optarr, i))\n            liste.append( val)\n    return liste\n\n\ndef JM_clear_pixmap_rect_with_value(dest, value, b):\n    '''\n    Clear a pixmap rectangle - my version also supports non-alpha pixmaps\n    '''\n    b = mupdf.fz_intersect_irect(b, mupdf.fz_pixmap_bbox(dest))\n    w = b.x1 - b.x0\n    y = b.y1 - b.y0\n    if w <= 0 or y <= 0:\n        return 0\n\n    destspan = dest.stride()\n    destp = destspan * (b.y0 - dest.y()) + dest.n() * (b.x0 - dest.x())\n\n    # CMYK needs special handling (and potentially any other subtractive colorspaces)\n    if mupdf.fz_colorspace_n(dest.colorspace()) == 4:\n        value = 255 - value\n        while 1:\n            s = destp\n            for x in range(0, w):\n                mupdf.fz_samples_set(dest, s, 0)\n                s += 1\n                mupdf.fz_samples_set(dest, s, 0)\n                s += 1\n                mupdf.fz_samples_set(dest, s, 0)\n                s += 1\n                mupdf.fz_samples_set(dest, s, value)\n                s += 1\n                if dest.alpha():\n                    mupdf.fz_samples_set(dest, s, 255)\n                    s += 1\n            destp += destspan\n            if y == 0:\n                break\n            y -= 1\n        return 1\n\n    while 1:\n        s = destp\n        for x in range(w):\n            for k in range(dest.n()-1):\n                mupdf.fz_samples_set(dest, s, value)\n                s += 1\n            if dest.alpha():\n                mupdf.fz_samples_set(dest, s, 255)\n                s += 1\n            else:\n                mupdf.fz_samples_set(dest, s, value)\n                s += 1\n        destp += destspan\n        if y == 0:\n            break\n        y -= 1\n    return 1\n\n\ndef JM_color_FromSequence(color):\n    \n    if isinstance(color, (int, float)):    # maybe just a single float\n        color = [color]\n    \n    if not isinstance( color, (list, tuple)):\n        return -1, []\n    \n    if len(color) not in (0, 1, 3, 4):\n        return -1, []\n    \n    ret = color[:]\n    for i in range(len(ret)):\n        if ret[i] < 0 or ret[i] > 1:\n            ret[i] = 1\n    return len(ret), ret\n\n\ndef JM_color_count( pm, clip):\n    if 1 or g_use_extra:\n        return extra.ll_JM_color_count(pm.m_internal, clip)\n    \n    rc = dict()\n    cnt = 0\n    irect = mupdf.fz_pixmap_bbox( pm)\n    irect = mupdf.fz_intersect_irect(irect, mupdf.fz_round_rect(JM_rect_from_py(clip)))\n    stride = pm.stride()\n    width = irect.x1 - irect.x0\n    height = irect.y1 - irect.y0\n    n = pm.n()\n    substride = width * n\n    s = stride * (irect.y0 - pm.y()) + (irect.x0 - pm.x()) * n\n    oldpix = _read_samples( pm, s, n)\n    cnt = 0\n    if mupdf.fz_is_empty_irect(irect):\n        return rc\n    for i in range( height):\n        for j in range( 0, substride, n):\n            newpix = _read_samples( pm, s + j, n)\n            if newpix != oldpix:\n                pixel = oldpix\n                c = rc.get( pixel, None)\n                if c is not None:\n                    cnt += c\n                rc[ pixel] = cnt\n                cnt = 1\n                oldpix = newpix\n            else:\n                cnt += 1\n        s += stride\n    pixel = oldpix\n    c = rc.get( pixel)\n    if c is not None:\n        cnt += c\n    rc[ pixel] = cnt\n    return rc\n\n\ndef JM_compress_buffer(inbuffer):\n    '''\n    compress char* into a new buffer\n    '''\n    data, compressed_length = mupdf.fz_new_deflated_data_from_buffer(\n            inbuffer,\n            mupdf.FZ_DEFLATE_BEST,\n            )\n    #log(f'{data compressed_length=}')\n    if not data or compressed_length == 0:\n        return None\n    buf = mupdf.FzBuffer(mupdf.fz_new_buffer_from_data(data, compressed_length))\n    mupdf.fz_resize_buffer(buf, compressed_length)\n    return buf\n\n\ndef JM_copy_rectangle(page, area):\n    need_new_line = 0\n    buffer = io.StringIO()\n    for block in page:\n        if block.m_internal.type != mupdf.FZ_STEXT_BLOCK_TEXT:\n            continue\n        for line in block:\n            line_had_text = 0\n            for ch in line:\n                r = JM_char_bbox(line, ch)\n                if JM_rects_overlap(area, r):\n                    line_had_text = 1\n                    if need_new_line:\n                        buffer.write(\"\\n\")\n                        need_new_line = 0\n                    buffer.write(make_escape(ch.m_internal.c))\n            if line_had_text:\n                need_new_line = 1\n\n    s = buffer.getvalue()   # take over the data\n    return s\n\n\ndef JM_convert_to_pdf(doc, fp, tp, rotate):\n    '''\n    Convert any MuPDF document to a PDF\n    Returns bytes object containing the PDF, created via 'write' function.\n    '''\n    pdfout = mupdf.PdfDocument()\n    incr = 1\n    s = fp\n    e = tp\n    if fp > tp:\n        incr = -1   # count backwards\n        s = tp      # adjust ...\n        e = fp      # ... range\n    rot = JM_norm_rotation(rotate)\n    i = fp\n    while 1:    # interpret & write document pages as PDF pages\n        if not _INRANGE(i, s, e):\n            break\n        page = mupdf.fz_load_page(doc, i)\n        mediabox = mupdf.fz_bound_page(page)\n        dev, resources, contents = mupdf.pdf_page_write(pdfout, mediabox)\n        mupdf.fz_run_page(page, dev, mupdf.FzMatrix(), mupdf.FzCookie())\n        mupdf.fz_close_device(dev)\n        dev = None\n        page_obj = mupdf.pdf_add_page(pdfout, mediabox, rot, resources, contents)\n        mupdf.pdf_insert_page(pdfout, -1, page_obj)\n        i += incr\n    # PDF created - now write it to Python bytearray\n    # prepare write options structure\n    opts = mupdf.PdfWriteOptions()\n    opts.do_garbage         = 4\n    opts.do_compress        = 1\n    opts.do_compress_images = 1\n    opts.do_compress_fonts  = 1\n    opts.do_sanitize        = 1\n    opts.do_incremental     = 0\n    opts.do_ascii           = 0\n    opts.do_decompress      = 0\n    opts.do_linear          = 0\n    opts.do_clean           = 1\n    opts.do_pretty          = 0\n\n    res = mupdf.fz_new_buffer(8192)\n    out = mupdf.FzOutput(res)\n    mupdf.pdf_write_document(pdfout, out, opts)\n    out.fz_close_output()\n    c = mupdf.fz_buffer_extract_copy(res)\n    assert isinstance(c, bytes)\n    return c\n\n\n# Copied from MuPDF v1.14\n# Create widget\ndef JM_create_widget(doc, page, type, fieldname):\n    old_sigflags = mupdf.pdf_to_int(mupdf.pdf_dict_getp(mupdf.pdf_trailer(doc), \"Root/AcroForm/SigFlags\"))\n    #log( '*** JM_create_widget()')\n    #log( f'{mupdf.pdf_create_annot_raw=}')\n    #log( f'{page=}')\n    #log( f'{mupdf.PDF_ANNOT_WIDGET=}')\n    annot = mupdf.pdf_create_annot_raw(page, mupdf.PDF_ANNOT_WIDGET)\n    annot_obj = mupdf.pdf_annot_obj(annot)\n    try:\n        JM_set_field_type(doc, annot_obj, type)\n        mupdf.pdf_dict_put_text_string(annot_obj, PDF_NAME('T'), fieldname)\n\n        if type == mupdf.PDF_WIDGET_TYPE_SIGNATURE:\n            sigflags = old_sigflags | (SigFlag_SignaturesExist | SigFlag_AppendOnly)\n            mupdf.pdf_dict_putl(\n                    mupdf.pdf_trailer(doc),\n                    mupdf.pdf_new_int(sigflags),\n                    PDF_NAME('Root'),\n                    PDF_NAME('AcroForm'),\n                    PDF_NAME('SigFlags'),\n                    )\n        # pdf_create_annot will have linked the new widget into the page's\n        # annot array. We also need it linked into the document's form\n        form = mupdf.pdf_dict_getp(mupdf.pdf_trailer(doc), \"Root/AcroForm/Fields\")\n        if not form.m_internal:\n            form = mupdf.pdf_new_array(doc, 1)\n            mupdf.pdf_dict_putl(\n                    mupdf.pdf_trailer(doc),\n                    form,\n                    PDF_NAME('Root'),\n                    PDF_NAME('AcroForm'),\n                    PDF_NAME('Fields'),\n                    )\n        mupdf.pdf_array_push(form, annot_obj)  # Cleanup relies on this statement being last\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        mupdf.pdf_delete_annot(page, annot)\n\n        if type == mupdf.PDF_WIDGET_TYPE_SIGNATURE:\n            mupdf.pdf_dict_putl(\n                    mupdf.pdf_trailer(doc),\n                    mupdf.pdf_new_int(old_sigflags),\n                    PDF_NAME('Root'),\n                    PDF_NAME('AcroForm'),\n                    PDF_NAME('SigFlags'),\n                    )\n        raise\n    return annot\n\n\ndef JM_cropbox(page_obj):\n    '''\n    return a PDF page's CropBox\n    '''\n    if g_use_extra:\n        return extra.JM_cropbox(page_obj)\n    \n    mediabox = JM_mediabox(page_obj)\n    cropbox = mupdf.pdf_to_rect(\n                mupdf.pdf_dict_get_inheritable(page_obj, PDF_NAME('CropBox'))\n                )\n    if mupdf.fz_is_infinite_rect(cropbox) or mupdf.fz_is_empty_rect(cropbox):\n        cropbox = mediabox\n    y0 = mediabox.y1 - cropbox.y1\n    y1 = mediabox.y1 - cropbox.y0\n    cropbox.y0 = y0\n    cropbox.y1 = y1\n    return cropbox\n\n\ndef JM_cropbox_size(page_obj):\n    rect = JM_cropbox(page_obj)\n    w = abs(rect.x1 - rect.x0)\n    h = abs(rect.y1 - rect.y0)\n    size = mupdf.fz_make_point(w, h)\n    return size\n\n\ndef JM_derotate_page_matrix(page):\n    '''\n    just the inverse of rotation\n    '''\n    mp = JM_rotate_page_matrix(page)\n    return mupdf.fz_invert_matrix(mp)\n\n\ndef JM_embed_file(\n        pdf,\n        buf,\n        filename,\n        ufilename,\n        desc,\n        compress,\n        ):\n    '''\n    embed a new file in a PDF (not only /EmbeddedFiles entries)\n    '''\n    len_ = 0\n    val = mupdf.pdf_new_dict(pdf, 6)\n    mupdf.pdf_dict_put_dict(val, PDF_NAME('CI'), 4)\n    ef = mupdf.pdf_dict_put_dict(val, PDF_NAME('EF'), 4)\n    mupdf.pdf_dict_put_text_string(val, PDF_NAME('F'), filename)\n    mupdf.pdf_dict_put_text_string(val, PDF_NAME('UF'), ufilename)\n    mupdf.pdf_dict_put_text_string(val, PDF_NAME('Desc'), desc)\n    mupdf.pdf_dict_put(val, PDF_NAME('Type'), PDF_NAME('Filespec'))\n    bs = b'  '\n    f = mupdf.pdf_add_stream(\n            pdf,\n            #mupdf.fz_fz_new_buffer_from_copied_data(bs),\n            mupdf.fz_new_buffer_from_copied_data(bs),\n            mupdf.PdfObj(),\n            0,\n            )\n    mupdf.pdf_dict_put(ef, PDF_NAME('F'), f)\n    JM_update_stream(pdf, f, buf, compress)\n    len_, _ = mupdf.fz_buffer_storage(buf)\n    mupdf.pdf_dict_put_int(f, PDF_NAME('DL'), len_)\n    mupdf.pdf_dict_put_int(f, PDF_NAME('Length'), len_)\n    params = mupdf.pdf_dict_put_dict(f, PDF_NAME('Params'), 4)\n    mupdf.pdf_dict_put_int(params, PDF_NAME('Size'), len_)\n    return val\n\n\ndef JM_embedded_clean(pdf):\n    '''\n    perform some cleaning if we have /EmbeddedFiles:\n    (1) remove any /Limits if /Names exists\n    (2) remove any empty /Collection\n    (3) set /PageMode/UseAttachments\n    '''\n    root = mupdf.pdf_dict_get( mupdf.pdf_trailer( pdf), PDF_NAME('Root'))\n\n    # remove any empty /Collection entry\n    coll = mupdf.pdf_dict_get(root, PDF_NAME('Collection'))\n    if coll.m_internal and mupdf.pdf_dict_len(coll) == 0:\n        mupdf.pdf_dict_del(root, PDF_NAME('Collection'))\n\n    efiles = mupdf.pdf_dict_getl(\n            root,\n            PDF_NAME('Names'),\n            PDF_NAME('EmbeddedFiles'),\n            PDF_NAME('Names'),\n            )\n    if efiles.m_internal:\n        mupdf.pdf_dict_put_name(root, PDF_NAME('PageMode'), \"UseAttachments\")\n\n\ndef JM_EscapeStrFromBuffer(buff):\n    if not buff.m_internal:\n        return ''\n    s = mupdf.fz_buffer_extract_copy(buff)\n    val = PyUnicode_DecodeRawUnicodeEscape(s, errors='replace')\n    return val\n\n\ndef JM_ensure_identity(pdf):\n    '''\n    Store ID in PDF trailer\n    '''\n    id_ = mupdf.pdf_dict_get( mupdf.pdf_trailer(pdf), PDF_NAME('ID'))\n    if not id_.m_internal:\n        rnd0 = mupdf.fz_memrnd2(16)\n        # Need to convert raw bytes into a str to send to\n        # mupdf.pdf_new_string(). chr() seems to work for this.\n        rnd = ''\n        for i in rnd0:\n            rnd += chr(i)\n        id_ = mupdf.pdf_dict_put_array( mupdf.pdf_trailer( pdf), PDF_NAME('ID'), 2)\n        mupdf.pdf_array_push( id_, mupdf.pdf_new_string( rnd, len(rnd)))\n        mupdf.pdf_array_push( id_, mupdf.pdf_new_string( rnd, len(rnd)))\n\ndef JM_ensure_ocproperties(pdf):\n    '''\n    Ensure OCProperties, return /OCProperties key\n    '''\n    ocp = mupdf.pdf_dict_get(mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root')), PDF_NAME('OCProperties'))\n    if ocp.m_internal:\n        return ocp\n    root = mupdf.pdf_dict_get(mupdf.pdf_trailer(pdf), PDF_NAME('Root'))\n    ocp = mupdf.pdf_dict_put_dict(root, PDF_NAME('OCProperties'), 2)\n    mupdf.pdf_dict_put_array(ocp, PDF_NAME('OCGs'), 0)\n    D = mupdf.pdf_dict_put_dict(ocp, PDF_NAME('D'), 5)\n    mupdf.pdf_dict_put_array(D, PDF_NAME('ON'), 0)\n    mupdf.pdf_dict_put_array(D, PDF_NAME('OFF'), 0)\n    mupdf.pdf_dict_put_array(D, PDF_NAME('Order'), 0)\n    mupdf.pdf_dict_put_array(D, PDF_NAME('RBGroups'), 0)\n    return ocp\n\n\ndef JM_expand_fname(name):\n    '''\n    Make /DA string of annotation\n    '''\n    if not name:    return \"Helv\"\n    if name.startswith(\"Co\"):   return \"Cour\"\n    if name.startswith(\"co\"):   return \"Cour\"\n    if name.startswith(\"Ti\"):   return \"TiRo\"\n    if name.startswith(\"ti\"):   return \"TiRo\"\n    if name.startswith(\"Sy\"):   return \"Symb\"\n    if name.startswith(\"sy\"):   return \"Symb\"\n    if name.startswith(\"Za\"):   return \"ZaDb\"\n    if name.startswith(\"za\"):   return \"ZaDb\"\n    return \"Helv\"\n\n\ndef JM_field_type_text(wtype):\n    '''\n    String from widget type\n    '''\n    if wtype == mupdf.PDF_WIDGET_TYPE_BUTTON:\n        return \"Button\"\n    if wtype == mupdf.PDF_WIDGET_TYPE_CHECKBOX:\n        return \"CheckBox\"\n    if wtype == mupdf.PDF_WIDGET_TYPE_RADIOBUTTON:\n        return \"RadioButton\"\n    if wtype == mupdf.PDF_WIDGET_TYPE_TEXT:\n        return \"Text\"\n    if wtype == mupdf.PDF_WIDGET_TYPE_LISTBOX:\n        return \"ListBox\"\n    if wtype == mupdf.PDF_WIDGET_TYPE_COMBOBOX:\n        return \"ComboBox\"\n    if wtype == mupdf.PDF_WIDGET_TYPE_SIGNATURE:\n        return \"Signature\"\n    return \"unknown\"\n\n\ndef JM_fill_pixmap_rect_with_color(dest, col, b):\n    assert isinstance(dest, mupdf.FzPixmap)\n    # fill a rect with a color tuple\n    b = mupdf.fz_intersect_irect(b, mupdf.fz_pixmap_bbox( dest))\n    w = b.x1 - b.x0\n    y = b.y1 - b.y0\n    if w <= 0 or y <= 0:\n        return 0\n    destspan = dest.stride()\n    destp = destspan * (b.y0 - dest.y()) + dest.n() * (b.x0 - dest.x())\n    while 1:\n        s = destp\n        for x in range(w):\n            for i in range( dest.n()):\n                mupdf.fz_samples_set(dest, s, col[i])\n                s += 1\n        destp += destspan\n        y -= 1\n        if y == 0:\n            break\n    return 1\n\n\ndef JM_find_annot_irt(annot):\n    '''\n    Return the first annotation whose /IRT key (\"In Response To\") points to\n    annot. Used to remove the response chain of a given annotation.\n    '''\n    assert isinstance(annot, mupdf.PdfAnnot)\n    irt_annot = None    # returning this\n    annot_obj = mupdf.pdf_annot_obj(annot)\n    found = 0\n    # loop thru MuPDF's internal annots array\n    page = _pdf_annot_page(annot)\n    irt_annot = mupdf.pdf_first_annot(page)\n    while 1:\n        assert isinstance(irt_annot, mupdf.PdfAnnot)\n        if not irt_annot.m_internal:\n            break\n        irt_annot_obj = mupdf.pdf_annot_obj(irt_annot)\n        o = mupdf.pdf_dict_gets(irt_annot_obj, 'IRT')\n        if o.m_internal:\n            if not mupdf.pdf_objcmp(o, annot_obj):\n                found = 1\n                break\n        irt_annot = mupdf.pdf_next_annot(irt_annot)\n    if found:\n        return irt_annot\n\n\ndef JM_font_ascender(font):\n    '''\n    need own versions of ascender / descender\n    '''\n    assert isinstance(font, mupdf.FzFont)\n    if _globals.skip_quad_corrections:\n        return 0.8\n    return mupdf.fz_font_ascender(font)\n\n\ndef JM_font_descender(font):\n    '''\n    need own versions of ascender / descender\n    '''\n    assert isinstance(font, mupdf.FzFont)\n    if _globals.skip_quad_corrections:\n        return -0.2\n    ret = mupdf.fz_font_descender(font)\n    return ret\n\n\ndef JM_is_word_delimiter(ch, delimiters):\n    \"\"\"Check if ch is an extra word delimiting character.\n    \"\"\"\n    if (0\n        or ch <= 32\n        or ch == 160\n        or 0x202a <= ch <= 0x202e\n    ):\n        # covers any whitespace plus unicodes that switch between\n        # right-to-left and left-to-right languages\n        return True\n    if not delimiters:  # no extra delimiters provided\n        return False\n    char = chr(ch)\n    for d in delimiters:\n        if d == char:\n            return True\n    return False\n    \n\ndef JM_is_rtl_char(ch):\n    if ch < 0x590 or ch > 0x900:\n        return False\n    return True\n\n\ndef JM_font_name(font):\n    assert isinstance(font, mupdf.FzFont)\n    name = mupdf.fz_font_name(font)\n    s = name.find('+')\n    if _globals.subset_fontnames or s == -1 or s != 6:\n        return name\n    return name[s + 1:]\n\n\ndef JM_gather_fonts(pdf, dict_, fontlist, stream_xref):\n    rc = 1\n    n = mupdf.pdf_dict_len(dict_)\n    for i in range(n):\n\n        refname = mupdf.pdf_dict_get_key(dict_, i)\n        fontdict = mupdf.pdf_dict_get_val(dict_, i)\n        if not mupdf.pdf_is_dict(fontdict):\n            mupdf.fz_warn( f\"'{mupdf.pdf_to_name(refname)}' is no font dict ({mupdf.pdf_to_num(fontdict)} 0 R)\")\n            continue\n\n        subtype = mupdf.pdf_dict_get(fontdict, mupdf.PDF_ENUM_NAME_Subtype)\n        basefont = mupdf.pdf_dict_get(fontdict, mupdf.PDF_ENUM_NAME_BaseFont)\n        if not basefont.m_internal or mupdf.pdf_is_null(basefont):\n            name = mupdf.pdf_dict_get(fontdict, mupdf.PDF_ENUM_NAME_Name)\n        else:\n            name = basefont\n        encoding = mupdf.pdf_dict_get(fontdict, mupdf.PDF_ENUM_NAME_Encoding)\n        if mupdf.pdf_is_dict(encoding):\n            encoding = mupdf.pdf_dict_get(encoding, mupdf.PDF_ENUM_NAME_BaseEncoding)\n        xref = mupdf.pdf_to_num(fontdict)\n        ext = \"n/a\"\n        if xref:\n            ext = JM_get_fontextension(pdf, xref)\n        entry = (\n                xref,\n                ext,\n                mupdf.pdf_to_name(subtype),\n                JM_EscapeStrFromStr(mupdf.pdf_to_name(name)),\n                mupdf.pdf_to_name(refname),\n                mupdf.pdf_to_name(encoding),\n                stream_xref,\n                )\n        fontlist.append(entry)\n    return rc\n\n\ndef JM_gather_forms(doc, dict_: mupdf.PdfObj, imagelist, stream_xref: int):\n    '''\n    Store info of a /Form xobject in Python list\n    '''\n    assert isinstance(doc, mupdf.PdfDocument)\n    rc = 1\n    n = mupdf.pdf_dict_len(dict_)\n    for i in range(n):\n        refname = mupdf.pdf_dict_get_key( dict_, i)\n        imagedict = mupdf.pdf_dict_get_val(dict_, i)\n        if not mupdf.pdf_is_dict(imagedict):\n            mupdf.fz_warn( f\"'{mupdf.pdf_to_name(refname)}' is no form dict ({mupdf.pdf_to_num(imagedict)} 0 R)\")\n            continue\n\n        type_ = mupdf.pdf_dict_get(imagedict, PDF_NAME('Subtype'))\n        if not mupdf.pdf_name_eq(type_, PDF_NAME('Form')):\n            continue\n\n        o = mupdf.pdf_dict_get(imagedict, PDF_NAME('BBox'))\n        m = mupdf.pdf_dict_get(imagedict, PDF_NAME('Matrix'))\n        if m.m_internal:\n            mat = mupdf.pdf_to_matrix(m)\n        else:\n            mat = mupdf.FzMatrix()\n        if o.m_internal:\n            bbox = mupdf.fz_transform_rect( mupdf.pdf_to_rect(o), mat)\n        else:\n            bbox = mupdf.FzRect(mupdf.FzRect.Fixed_INFINITE)\n        xref = mupdf.pdf_to_num(imagedict)\n\n        entry = (\n                xref,\n                mupdf.pdf_to_name( refname),\n                stream_xref,\n                JM_py_from_rect(bbox),\n                )\n        imagelist.append(entry)\n    return rc\n\n\ndef JM_gather_images(doc: mupdf.PdfDocument, dict_: mupdf.PdfObj, imagelist, stream_xref: int):\n    '''\n    Store info of an image in Python list\n    '''\n    rc = 1\n    n = mupdf.pdf_dict_len( dict_)\n    for i in range(n):\n        refname = mupdf.pdf_dict_get_key(dict_, i)\n        imagedict = mupdf.pdf_dict_get_val(dict_, i)\n        if not mupdf.pdf_is_dict(imagedict):\n            mupdf.fz_warn(f\"'{mupdf.pdf_to_name(refname)}' is no image dict ({mupdf.pdf_to_num(imagedict)} 0 R)\")\n            continue\n\n        type_ = mupdf.pdf_dict_get(imagedict, PDF_NAME('Subtype'))\n        if not mupdf.pdf_name_eq(type_, PDF_NAME('Image')):\n            continue\n\n        xref = mupdf.pdf_to_num(imagedict)\n        gen = 0\n        smask = mupdf.pdf_dict_geta(imagedict, PDF_NAME('SMask'), PDF_NAME('Mask'))\n        if smask.m_internal:\n            gen = mupdf.pdf_to_num(smask)\n\n        filter_ = mupdf.pdf_dict_geta(imagedict, PDF_NAME('Filter'), PDF_NAME('F'))\n        if mupdf.pdf_is_array(filter_):\n            filter_ = mupdf.pdf_array_get(filter_, 0)\n\n        altcs = mupdf.PdfObj(0)\n        cs = mupdf.pdf_dict_geta(imagedict, PDF_NAME('ColorSpace'), PDF_NAME('CS'))\n        if mupdf.pdf_is_array(cs):\n            cses = cs\n            cs = mupdf.pdf_array_get(cses, 0)\n            if (mupdf.pdf_name_eq(cs, PDF_NAME('DeviceN'))\n                    or mupdf.pdf_name_eq(cs, PDF_NAME('Separation'))\n                    ):\n                altcs = mupdf.pdf_array_get(cses, 2)\n                if mupdf.pdf_is_array(altcs):\n                    altcs = mupdf.pdf_array_get(altcs, 0)\n        width = mupdf.pdf_dict_geta(imagedict, PDF_NAME('Width'), PDF_NAME('W'))\n        height = mupdf.pdf_dict_geta(imagedict, PDF_NAME('Height'), PDF_NAME('H'))\n        bpc = mupdf.pdf_dict_geta(imagedict, PDF_NAME('BitsPerComponent'), PDF_NAME('BPC'))\n\n        entry = (\n                xref,\n                gen,\n                mupdf.pdf_to_int(width),\n                mupdf.pdf_to_int(height),\n                mupdf.pdf_to_int(bpc),\n                JM_EscapeStrFromStr(mupdf.pdf_to_name(cs)),\n                JM_EscapeStrFromStr(mupdf.pdf_to_name(altcs)),\n                JM_EscapeStrFromStr(mupdf.pdf_to_name(refname)),\n                JM_EscapeStrFromStr(mupdf.pdf_to_name(filter_)),\n                stream_xref,\n                )\n        imagelist.append(entry)\n    return rc\n\n\ndef JM_get_annot_by_xref(page, xref):\n    '''\n    retrieve annot by its xref\n    '''\n    assert isinstance(page, mupdf.PdfPage)\n    found = 0\n    # loop thru MuPDF's internal annots array\n    annot = mupdf.pdf_first_annot(page)\n    while 1:\n        if not annot.m_internal:\n            break\n        if xref == mupdf.pdf_to_num(mupdf.pdf_annot_obj(annot)):\n            found = 1\n            break\n        annot = mupdf.pdf_next_annot( annot)\n    if not found:\n        raise Exception(f\"xref {xref:d} is not an annot of this page\")\n    return annot\n\n\ndef JM_get_annot_by_name(page, name):\n    '''\n    retrieve annot by name (/NM key)\n    '''\n    assert isinstance(page, mupdf.PdfPage)\n    if not name:\n        return\n    found = 0\n    # loop thru MuPDF's internal annots and widget arrays\n    annot = mupdf.pdf_first_annot(page)\n    while 1:\n        if not annot.m_internal:\n            break\n\n        response, len_ = mupdf.pdf_to_string(mupdf.pdf_dict_gets(mupdf.pdf_annot_obj(annot), \"NM\"))\n        if name == response:\n            found = 1\n            break\n        annot = mupdf.pdf_next_annot(annot)\n    if not found:\n        raise Exception(f\"'{name}' is not an annot of this page\")\n    return annot\n\n\ndef JM_get_annot_id_list(page):\n    names = []\n    annots = mupdf.pdf_dict_get( page.obj(), mupdf.PDF_ENUM_NAME_Annots)\n    if not annots.m_internal:\n        return names\n    for i in range( mupdf.pdf_array_len(annots)):\n        annot_obj = mupdf.pdf_array_get(annots, i)\n        name = mupdf.pdf_dict_gets(annot_obj, \"NM\")\n        if name.m_internal:\n            names.append(\n                mupdf.pdf_to_text_string(name)\n                )\n    return names\n\ndef JM_get_annot_xref_list( page_obj):\n    '''\n    return the xrefs and /NM ids of a page's annots, links and fields\n    '''\n    if g_use_extra:\n        names = extra.JM_get_annot_xref_list( page_obj)\n        return names\n    \n    names = []\n    annots = mupdf.pdf_dict_get( page_obj, PDF_NAME('Annots'))\n    n = mupdf.pdf_array_len( annots)\n    for i in range( n):\n        annot_obj = mupdf.pdf_array_get( annots, i)\n        xref = mupdf.pdf_to_num( annot_obj)\n        subtype = mupdf.pdf_dict_get( annot_obj, PDF_NAME('Subtype'))\n        if not subtype.m_internal:\n            continue    # subtype is required\n        type_ = mupdf.pdf_annot_type_from_string( mupdf.pdf_to_name( subtype))\n        if type_ == mupdf.PDF_ANNOT_UNKNOWN:\n            continue    # only accept valid annot types\n        id_ = mupdf.pdf_dict_gets( annot_obj, \"NM\")\n        names.append( (xref, type_, mupdf.pdf_to_text_string( id_)))\n    return names\n\n\ndef JM_get_annot_xref_list2(page):\n    page = page._pdf_page(required=False)\n    if not page.m_internal:\n        return list()\n    return JM_get_annot_xref_list( page.obj())\n\n\ndef JM_get_border_style(style):\n    '''\n    return pdf_obj \"border style\" from Python str\n    '''\n    val = mupdf.PDF_ENUM_NAME_S\n    if style is None:\n        return val\n    s = style\n    if   s.startswith(\"b\") or s.startswith(\"B\"):    val = mupdf.PDF_ENUM_NAME_B\n    elif s.startswith(\"d\") or s.startswith(\"D\"):    val = mupdf.PDF_ENUM_NAME_D\n    elif s.startswith(\"i\") or s.startswith(\"I\"):    val = mupdf.PDF_ENUM_NAME_I\n    elif s.startswith(\"u\") or s.startswith(\"U\"):    val = mupdf.PDF_ENUM_NAME_U\n    elif s.startswith(\"s\") or s.startswith(\"S\"):    val = mupdf.PDF_ENUM_NAME_S\n    return val\n\n\ndef JM_get_font(\n        fontname,\n        fontfile,\n        fontbuffer,\n        script,\n        lang,\n        ordering,\n        is_bold,\n        is_italic,\n        is_serif,\n        embed,\n        ):\n    '''\n    return a fz_font from a number of parameters\n    '''\n    def fertig(font):\n        if not font.m_internal:\n            raise RuntimeError(MSG_FONT_FAILED)\n        # if font allows this, set embedding\n        if not font.m_internal.flags.never_embed:\n            mupdf.fz_set_font_embedding(font, embed)\n        return font\n    \n    index = 0\n    font = None\n    if fontfile:\n        #goto have_file;\n        font = mupdf.fz_new_font_from_file( None, fontfile, index, 0)\n        return fertig(font)\n\n    if fontbuffer:\n        #goto have_buffer;\n        res = JM_BufferFromBytes(fontbuffer)\n        font = mupdf.fz_new_font_from_buffer( None, res, index, 0)\n        return fertig(font)\n\n    if ordering > -1:\n        # goto have_cjk;\n        font = mupdf.fz_new_cjk_font(ordering)\n        return fertig(font)\n\n    if fontname:\n        # goto have_base14;\n        # Base-14 or a MuPDF builtin font\n        font = mupdf.fz_new_base14_font(fontname)\n        if font.m_internal:\n            return fertig(font)\n        font = mupdf.fz_new_builtin_font(fontname, is_bold, is_italic)\n        return fertig(font)\n    \n    # Check for NOTO font\n    #have_noto:;\n    data, size, index = mupdf.fz_lookup_noto_font( script, lang)\n    font = None\n    if data:\n        font = mupdf.fz_new_font_from_memory( None, data, size, index, 0)\n    if font.m_internal:\n        return fertig(font)\n    font = mupdf.fz_load_fallback_font( script, lang, is_serif, is_bold, is_italic)\n    return fertig(font)\n    \n\ndef JM_get_fontbuffer(doc, xref):\n    '''\n    Return the contents of a font file, identified by xref\n    '''\n    if xref < 1:\n        return\n    o = mupdf.pdf_load_object(doc, xref)\n    desft = mupdf.pdf_dict_get(o, PDF_NAME('DescendantFonts'))\n    if desft.m_internal:\n        obj = mupdf.pdf_resolve_indirect(mupdf.pdf_array_get(desft, 0))\n        obj = mupdf.pdf_dict_get(obj, PDF_NAME('FontDescriptor'))\n    else:\n        obj = mupdf.pdf_dict_get(o, PDF_NAME('FontDescriptor'))\n\n    if not obj.m_internal:\n        message(f\"invalid font - FontDescriptor missing\")\n        return\n\n    o = obj\n\n    stream = None\n\n    obj = mupdf.pdf_dict_get(o, PDF_NAME('FontFile'))\n    if obj.m_internal:\n        stream = obj    # ext = \"pfa\"\n\n    obj = mupdf.pdf_dict_get(o, PDF_NAME('FontFile2'))\n    if obj.m_internal:\n        stream = obj    # ext = \"ttf\"\n\n    obj = mupdf.pdf_dict_get(o, PDF_NAME('FontFile3'))\n    if obj.m_internal:\n        stream = obj\n\n        obj = mupdf.pdf_dict_get(obj, PDF_NAME('Subtype'))\n        if obj.m_internal and not mupdf.pdf_is_name(obj):\n            message(\"invalid font descriptor subtype\")\n            return\n\n        if mupdf.pdf_name_eq(obj, PDF_NAME('Type1C')):\n            pass    # Prev code did: ext = \"cff\", but this has no effect.\n        elif mupdf.pdf_name_eq(obj, PDF_NAME('CIDFontType0C')):\n            pass    # Prev code did: ext = \"cid\", but this has no effect.\n        elif mupdf.pdf_name_eq(obj, PDF_NAME('OpenType')):\n            pass    # Prev code did: ext = \"otf\", but this has no effect. */\n        else:\n            message(f'warning: unhandled font type {mupdf.pdf_to_name(obj)!r}')\n\n    if not stream:\n        message('warning: unhandled font type')\n        return\n\n    return mupdf.pdf_load_stream(stream)\n\n\ndef JM_get_resource_properties(ref):\n    '''\n    Return the items of Resources/Properties (used for Marked Content)\n    Argument may be e.g. a page object or a Form XObject\n    '''\n    properties = mupdf.pdf_dict_getl(ref, PDF_NAME('Resources'), PDF_NAME('Properties'))\n    if not properties.m_internal:\n        return ()\n    else:\n        n = mupdf.pdf_dict_len(properties)\n        if n < 1:\n            return ()\n        rc = []\n        for i in range(n):\n            key = mupdf.pdf_dict_get_key(properties, i)\n            val = mupdf.pdf_dict_get_val(properties, i)\n            c = mupdf.pdf_to_name(key)\n            xref = mupdf.pdf_to_num(val)\n            rc.append((c, xref))\n    return rc\n\n\ndef JM_get_widget_by_xref( page, xref):\n    '''\n    retrieve widget by its xref\n    '''\n    found = False\n    annot = mupdf.pdf_first_widget( page)\n    while annot.m_internal:\n        annot_obj = mupdf.pdf_annot_obj( annot)\n        if xref == mupdf.pdf_to_num( annot_obj):\n            found = True\n            break\n        annot = mupdf.pdf_next_widget( annot)\n    if not found:\n        raise Exception( f\"xref {xref} is not a widget of this page\")\n    return Annot( annot)\n\n\ndef JM_get_widget_properties(annot, Widget):\n    '''\n    Populate a Python Widget object with the values from a PDF form field.\n    Called by \"Page.first_widget\" and \"Widget.next\".\n    '''\n    #log(f'{type(annot)=}')\n    annot_obj = mupdf.pdf_annot_obj(annot.this)\n    #log( 'Have called mupdf.pdf_annot_obj()')\n    page = _pdf_annot_page(annot.this)\n    pdf = page.doc()\n    tw = annot\n\n    def SETATTR(key, value):\n        setattr(Widget, key, value)\n\n    def SETATTR_DROP(mod, key, value):\n        # Original C code for this function deletes if PyObject* is NULL. We\n        # don't have a representation for that in Python - e.g. None is not\n        # represented by NULL.\n        setattr(mod, key, value)\n\n    #log( '=== + mupdf.pdf_widget_type(tw)')\n    field_type = mupdf.pdf_widget_type(tw.this)\n    #log( '=== - mupdf.pdf_widget_type(tw)')\n    Widget.field_type = field_type\n    if field_type == mupdf.PDF_WIDGET_TYPE_SIGNATURE:\n        if mupdf.pdf_signature_is_signed(pdf, annot_obj):\n            SETATTR(\"is_signed\", True)\n        else:\n            SETATTR(\"is_signed\",False)\n    else:\n        SETATTR(\"is_signed\", None)\n    SETATTR_DROP(Widget, \"border_style\", JM_UnicodeFromStr(mupdf.pdf_field_border_style(annot_obj)))\n    SETATTR_DROP(Widget, \"field_type_string\", JM_UnicodeFromStr(JM_field_type_text(field_type)))\n\n    field_name = mupdf.pdf_load_field_name(annot_obj)\n    SETATTR_DROP(Widget, \"field_name\", field_name)\n\n    def pdf_dict_get_inheritable_nonempty_label(node, key):\n        '''\n        This is a modified version of MuPDF's pdf_dict_get_inheritable(), with\n        some changes:\n        * Returns string from pdf_to_text_string() or None if not found.\n        * Recurses to parent if current node exists but with empty string\n          value.\n        '''\n        slow = node\n        halfbeat = 11   # Don't start moving slow pointer for a while.\n        while 1:\n            if not node.m_internal:\n                return\n            val = mupdf.pdf_dict_get(node, key)\n            if val.m_internal:\n                label = mupdf.pdf_to_text_string(val)\n                if label:\n                    return label\n            node = mupdf.pdf_dict_get(node, PDF_NAME('Parent'))\n            if node.m_internal == slow.m_internal:\n                raise Exception(\"cycle in resources\")\n            halfbeat -= 1\n            if halfbeat == 0:\n                slow = mupdf.pdf_dict_get(slow, PDF_NAME('Parent'))\n                halfbeat = 2\n    \n    # In order to address #3950, we use our modified pdf_dict_get_inheritable()\n    # to ignore empty-string child values.\n    label = pdf_dict_get_inheritable_nonempty_label(annot_obj, PDF_NAME('TU'))\n    if label is not None:\n        SETATTR_DROP(Widget, \"field_label\", label)\n\n    fvalue = None\n    if field_type == mupdf.PDF_WIDGET_TYPE_RADIOBUTTON:\n        obj = mupdf.pdf_dict_get( annot_obj, PDF_NAME('Parent'))    # owning RB group\n        if obj.m_internal:\n            SETATTR_DROP(Widget, \"rb_parent\", mupdf.pdf_to_num( obj))\n        obj = mupdf.pdf_dict_get(annot_obj, PDF_NAME('AS'))\n        if obj.m_internal:\n            fvalue = mupdf.pdf_to_name(obj)\n    if not fvalue:\n        fvalue = mupdf.pdf_field_value(annot_obj)\n    SETATTR_DROP(Widget, \"field_value\", JM_UnicodeFromStr(fvalue))\n\n    SETATTR_DROP(Widget, \"field_display\", mupdf.pdf_field_display(annot_obj))\n\n    border_width = mupdf.pdf_to_real(mupdf.pdf_dict_getl(annot_obj, PDF_NAME('BS'), PDF_NAME('W')))\n    if border_width == 0:\n        border_width = 1\n    SETATTR_DROP(Widget, \"border_width\", border_width)\n\n    obj = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('BS'), PDF_NAME('D'))\n    if mupdf.pdf_is_array(obj):\n        n = mupdf.pdf_array_len(obj)\n        d = [0] * n\n        for i in range(n):\n            d[i] = mupdf.pdf_to_int(mupdf.pdf_array_get(obj, i))\n        SETATTR_DROP(Widget, \"border_dashes\", d)\n\n    SETATTR_DROP(Widget, \"text_maxlen\", mupdf.pdf_text_widget_max_len(tw.this))\n\n    SETATTR_DROP(Widget, \"text_format\", mupdf.pdf_text_widget_format(tw.this))\n\n    obj = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('MK'), PDF_NAME('BG'))\n    if mupdf.pdf_is_array(obj):\n        n = mupdf.pdf_array_len(obj)\n        col = [0] * n\n        for i in range(n):\n            col[i] = mupdf.pdf_to_real(mupdf.pdf_array_get(obj, i))\n        SETATTR_DROP(Widget, \"fill_color\", col)\n\n    obj = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('MK'), PDF_NAME('BC'))\n    if mupdf.pdf_is_array(obj):\n        n = mupdf.pdf_array_len(obj)\n        col = [0] * n\n        for i in range(n):\n            col[i] = mupdf.pdf_to_real(mupdf.pdf_array_get(obj, i))\n        SETATTR_DROP(Widget, \"border_color\", col)\n\n    SETATTR_DROP(Widget, \"choice_values\", JM_choice_options(annot))\n\n    da = mupdf.pdf_to_text_string(mupdf.pdf_dict_get_inheritable(annot_obj, PDF_NAME('DA')))\n    SETATTR_DROP(Widget, \"_text_da\", JM_UnicodeFromStr(da))\n\n    obj = mupdf.pdf_dict_getl(annot_obj, PDF_NAME('MK'), PDF_NAME('CA'))\n    if obj.m_internal:\n        SETATTR_DROP(Widget, \"button_caption\", JM_UnicodeFromStr(mupdf.pdf_to_text_string(obj)))\n\n    SETATTR_DROP(Widget, \"field_flags\", mupdf.pdf_field_flags(annot_obj))\n\n    # call Py method to reconstruct text color, font name, size\n    Widget._parse_da()\n\n    # extract JavaScript action texts\n    s = mupdf.pdf_dict_get(annot_obj, PDF_NAME('A'))\n    ss = JM_get_script(s)\n    SETATTR_DROP(Widget, \"script\", ss)\n\n    SETATTR_DROP(Widget, \"script_stroke\",\n            JM_get_script(mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AA'), PDF_NAME('K')))\n            )\n\n    SETATTR_DROP(Widget, \"script_format\",\n            JM_get_script(mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AA'), PDF_NAME('F')))\n            )\n\n    SETATTR_DROP(Widget, \"script_change\",\n            JM_get_script(mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AA'), PDF_NAME('V')))\n            )\n\n    SETATTR_DROP(Widget, \"script_calc\",\n            JM_get_script(mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AA'), PDF_NAME('C')))\n            )\n\n    SETATTR_DROP(Widget, \"script_blur\",\n            JM_get_script(mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AA'), mupdf.pdf_new_name('Bl')))\n            )\n\n    SETATTR_DROP(Widget, \"script_focus\",\n            JM_get_script(mupdf.pdf_dict_getl(annot_obj, PDF_NAME('AA'), mupdf.pdf_new_name('Fo')))\n            )\n\n\ndef JM_get_fontextension(doc, xref):\n    '''\n    Return the file extension of a font file, identified by xref\n    '''\n    if xref < 1:\n        return \"n/a\"\n    o = mupdf.pdf_load_object(doc, xref)\n    desft = mupdf.pdf_dict_get(o, PDF_NAME('DescendantFonts'))\n    if desft.m_internal:\n        obj = mupdf.pdf_resolve_indirect(mupdf.pdf_array_get(desft, 0))\n        obj = mupdf.pdf_dict_get(obj, PDF_NAME('FontDescriptor'))\n    else:\n        obj = mupdf.pdf_dict_get(o, PDF_NAME('FontDescriptor'))\n    if not obj.m_internal:\n        return \"n/a\"    # this is a base-14 font\n\n    o = obj # we have the FontDescriptor\n\n    obj = mupdf.pdf_dict_get(o, PDF_NAME('FontFile'))\n    if obj.m_internal:\n        return \"pfa\"\n\n    obj = mupdf.pdf_dict_get(o, PDF_NAME('FontFile2'))\n    if obj.m_internal:\n        return \"ttf\"\n\n    obj = mupdf.pdf_dict_get(o, PDF_NAME('FontFile3'))\n    if obj.m_internal:\n        obj = mupdf.pdf_dict_get(obj, PDF_NAME('Subtype'))\n        if obj.m_internal and not mupdf.pdf_is_name(obj):\n            message(\"invalid font descriptor subtype\")\n            return \"n/a\"\n        if mupdf.pdf_name_eq(obj, PDF_NAME('Type1C')):\n            return \"cff\"\n        elif mupdf.pdf_name_eq(obj, PDF_NAME('CIDFontType0C')):\n            return \"cid\"\n        elif mupdf.pdf_name_eq(obj, PDF_NAME('OpenType')):\n            return \"otf\"\n        else:\n            message(f\"unhandled font type '{mupdf.pdf_to_name(obj)}'\")\n\n    return \"n/a\"\n\n\ndef JM_get_ocg_arrays_imp(arr):\n    '''\n    Get OCG arrays from OC configuration\n    Returns dict {\"basestate\":name, \"on\":list, \"off\":list, \"rbg\":list, \"locked\":list}\n    '''\n    list_ = list()\n    if mupdf.pdf_is_array( arr):\n        n = mupdf.pdf_array_len( arr)\n        for i in range(n):\n            obj = mupdf.pdf_array_get( arr, i)\n            item = mupdf.pdf_to_num( obj)\n            if item not in list_:\n                list_.append(item)\n    return list_\n\n\ndef JM_get_ocg_arrays(conf):\n\n    rc = dict()\n    arr = mupdf.pdf_dict_get( conf, PDF_NAME('ON'))\n    list_ = JM_get_ocg_arrays_imp( arr)\n    if list_:\n        rc[\"on\"] = list_\n    arr = mupdf.pdf_dict_get( conf, PDF_NAME('OFF'))\n    list_ = JM_get_ocg_arrays_imp( arr)\n    if list_:\n        rc[\"off\"] = list_\n    arr = mupdf.pdf_dict_get( conf, PDF_NAME('Locked'))\n    list_ = JM_get_ocg_arrays_imp( arr)\n    if list_:\n        rc['locked'] = list_\n    list_ = list()\n    arr = mupdf.pdf_dict_get( conf, PDF_NAME('RBGroups'))\n    if mupdf.pdf_is_array( arr):\n        n = mupdf.pdf_array_len( arr)\n        for i in range(n):\n            obj = mupdf.pdf_array_get( arr, i)\n            list1 = JM_get_ocg_arrays_imp( obj)\n            list_.append(list1)\n    if list_:\n        rc[\"rbgroups\"] = list_\n    obj = mupdf.pdf_dict_get( conf, PDF_NAME('BaseState'))\n\n    if obj.m_internal:\n        state = mupdf.pdf_to_name( obj)\n        rc[\"basestate\"] = state\n    return rc\n\n\ndef JM_get_page_labels(liste, nums):\n    n = mupdf.pdf_array_len(nums)\n    for i in range(0, n, 2):\n        key = mupdf.pdf_resolve_indirect( mupdf.pdf_array_get(nums, i))\n        pno = mupdf.pdf_to_int(key)\n        val = mupdf.pdf_resolve_indirect( mupdf.pdf_array_get(nums, i + 1))\n        res = JM_object_to_buffer(val, 1, 0)\n        c = mupdf.fz_buffer_extract(res)\n        assert isinstance(c, bytes)\n        c = c.decode('utf-8')\n        liste.append( (pno, c))\n\n\ndef JM_get_script(key):\n    '''\n    JavaScript extractor\n    Returns either the script source or None. Parameter is a PDF action\n    dictionary, which must have keys /S and /JS. The value of /S must be\n    '/JavaScript'. The value of /JS is returned.\n    '''\n    if not key.m_internal:\n        return\n\n    j = mupdf.pdf_dict_get(key, PDF_NAME('S'))\n    jj = mupdf.pdf_to_name(j)\n    if jj == \"JavaScript\":\n        js = mupdf.pdf_dict_get(key, PDF_NAME('JS'))\n        if not js.m_internal:\n            return\n    else:\n        return\n\n    if mupdf.pdf_is_string(js):\n        script = JM_UnicodeFromStr(mupdf.pdf_to_text_string(js))\n    elif mupdf.pdf_is_stream(js):\n        res = mupdf.pdf_load_stream(js)\n        script = JM_EscapeStrFromBuffer(res)\n    else:\n        return\n    if script:  # do not return an empty script\n        return script\n    return\n\n\ndef JM_have_operation(pdf):\n    '''\n    Ensure valid journalling state\n    '''\n    if pdf.m_internal.journal and not mupdf.pdf_undoredo_step(pdf, 0):\n        return 0\n    return 1\n\n\ndef JM_image_extension(type_):\n    '''\n    return extension for MuPDF image type\n    '''\n    if type_ == mupdf.FZ_IMAGE_FAX:     return \"fax\"\n    if type_ == mupdf.FZ_IMAGE_RAW:     return \"raw\"\n    if type_ == mupdf.FZ_IMAGE_FLATE:   return \"flate\"\n    if type_ == mupdf.FZ_IMAGE_LZW:     return \"lzw\"\n    if type_ == mupdf.FZ_IMAGE_RLD:     return \"rld\"\n    if type_ == mupdf.FZ_IMAGE_BMP:     return \"bmp\"\n    if type_ == mupdf.FZ_IMAGE_GIF:     return \"gif\"\n    if type_ == mupdf.FZ_IMAGE_JBIG2:   return \"jb2\"\n    if type_ == mupdf.FZ_IMAGE_JPEG:    return \"jpeg\"\n    if type_ == mupdf.FZ_IMAGE_JPX:     return \"jpx\"\n    if type_ == mupdf.FZ_IMAGE_JXR:     return \"jxr\"\n    if type_ == mupdf.FZ_IMAGE_PNG:     return \"png\"\n    if type_ == mupdf.FZ_IMAGE_PNM:     return \"pnm\"\n    if type_ == mupdf.FZ_IMAGE_TIFF:    return \"tiff\"\n    #if type_ == mupdf.FZ_IMAGE_PSD:     return \"psd\"\n    return \"n/a\"\n\n\n# fixme: need to avoid using a global for this.\ng_img_info = None\n\n\ndef JM_image_filter(opaque, ctm, name, image):\n    assert isinstance(ctm, mupdf.FzMatrix)\n    r = mupdf.FzRect(mupdf.FzRect.Fixed_UNIT)\n    q = mupdf.fz_transform_quad( mupdf.fz_quad_from_rect(r), ctm)\n    q = mupdf.fz_transform_quad( q, g_img_info_matrix)\n    temp = name, JM_py_from_quad(q)\n    g_img_info.append(temp)\n\n\ndef JM_image_profile( imagedata, keep_image):\n    '''\n    Return basic properties of an image provided as bytes or bytearray\n    The function creates an fz_image and optionally returns it.\n    '''\n    if not imagedata:\n        return None # nothing given\n    \n    len_ = len( imagedata)\n    if len_ < 8:\n        message( \"bad image data\")\n        return None\n    c = imagedata\n    #log(f'calling mfz_recognize_image_format with {c!r=}')\n    type_ = mupdf.fz_recognize_image_format( c)\n    if type_ == mupdf.FZ_IMAGE_UNKNOWN:\n        return None\n\n    if keep_image:\n        res = mupdf.fz_new_buffer_from_copied_data( c, len_)\n    else:\n        res = mupdf.fz_new_buffer_from_shared_data( c, len_)\n    image = mupdf.fz_new_image_from_buffer( res)\n    ctm = mupdf.fz_image_orientation_matrix( image)\n    xres, yres = mupdf.fz_image_resolution(image)\n    orientation = mupdf.fz_image_orientation( image)\n    cs_name = mupdf.fz_colorspace_name( image.colorspace())\n    result = dict()\n    result[ dictkey_width] = image.w()\n    result[ dictkey_height] = image.h()\n    result[ \"orientation\"] = orientation\n    result[ dictkey_matrix] = JM_py_from_matrix(ctm)\n    result[ dictkey_xres] = xres\n    result[ dictkey_yres] = yres\n    result[ dictkey_colorspace] = image.n()\n    result[ dictkey_bpc] = image.bpc()\n    result[ dictkey_ext] = JM_image_extension(type_)\n    result[ dictkey_cs_name] = cs_name\n\n    if keep_image:\n        result[ dictkey_image] = image\n    return result\n\n\ndef JM_image_reporter(page):\n    doc = page.doc()\n    global g_img_info_matrix\n    g_img_info_matrix = mupdf.FzMatrix()\n    mediabox = mupdf.FzRect()\n    mupdf.pdf_page_transform(page, mediabox, g_img_info_matrix)\n\n    class SanitizeFilterOptions(mupdf.PdfSanitizeFilterOptions2):\n        def __init__(self):\n            super().__init__()\n            self.use_virtual_image_filter()\n        def image_filter(self, ctx, ctm, name, image, scissor):\n            JM_image_filter(None, mupdf.FzMatrix(ctm), name, image)\n\n    sanitize_filter_options = SanitizeFilterOptions()\n\n    filter_options = _make_PdfFilterOptions(\n            instance_forms=1,\n            ascii=1,\n            no_update=1,\n            sanitize=1,\n            sopts=sanitize_filter_options,\n            )\n\n    global g_img_info\n    g_img_info = []\n\n    mupdf.pdf_filter_page_contents( doc, page, filter_options)\n\n    rc = tuple(g_img_info)\n    g_img_info = []\n    return rc\n\n\ndef JM_fitz_config():\n    have_TOFU           = not hasattr(mupdf, 'TOFU')\n    have_TOFU_BASE14    = not hasattr(mupdf, 'TOFU_BASE14')\n    have_TOFU_CJK       = not hasattr(mupdf, 'TOFU_CJK')\n    have_TOFU_CJK_EXT   = not hasattr(mupdf, 'TOFU_CJK_EXT')\n    have_TOFU_CJK_LANG  = not hasattr(mupdf, 'TOFU_CJK_LANG')\n    have_TOFU_EMOJI     = not hasattr(mupdf, 'TOFU_EMOJI')\n    have_TOFU_HISTORIC  = not hasattr(mupdf, 'TOFU_HISTORIC')\n    have_TOFU_SIL       = not hasattr(mupdf, 'TOFU_SIL')\n    have_TOFU_SYMBOL    = not hasattr(mupdf, 'TOFU_SYMBOL')\n    \n    ret = dict()\n    ret[\"base14\"]           = have_TOFU_BASE14\n    ret[\"cbz\"]              = bool(mupdf.FZ_ENABLE_CBZ)\n    ret[\"epub\"]             = bool(mupdf.FZ_ENABLE_EPUB)\n    ret[\"html\"]             = bool(mupdf.FZ_ENABLE_HTML)\n    ret[\"icc\"]              = bool(mupdf.FZ_ENABLE_ICC)\n    ret[\"img\"]              = bool(mupdf.FZ_ENABLE_IMG)\n    ret[\"jpx\"]              = bool(mupdf.FZ_ENABLE_JPX)\n    ret[\"js\"]               = bool(mupdf.FZ_ENABLE_JS)\n    ret[\"pdf\"]              = bool(mupdf.FZ_ENABLE_PDF)\n    ret[\"plotter-cmyk\"]     = bool(mupdf.FZ_PLOTTERS_CMYK)\n    ret[\"plotter-g\"]        = bool(mupdf.FZ_PLOTTERS_G)\n    ret[\"plotter-n\"]        = bool(mupdf.FZ_PLOTTERS_N)\n    ret[\"plotter-rgb\"]      = bool(mupdf.FZ_PLOTTERS_RGB)\n    ret[\"py-memory\"]        = bool(JM_MEMORY)\n    ret[\"svg\"]              = bool(mupdf.FZ_ENABLE_SVG)\n    ret[\"tofu\"]             = have_TOFU\n    ret[\"tofu-cjk\"]         = have_TOFU_CJK\n    ret[\"tofu-cjk-ext\"]     = have_TOFU_CJK_EXT\n    ret[\"tofu-cjk-lang\"]    = have_TOFU_CJK_LANG\n    ret[\"tofu-emoji\"]       = have_TOFU_EMOJI\n    ret[\"tofu-historic\"]    = have_TOFU_HISTORIC\n    ret[\"tofu-sil\"]         = have_TOFU_SIL\n    ret[\"tofu-symbol\"]      = have_TOFU_SYMBOL\n    ret[\"xps\"]              = bool(mupdf.FZ_ENABLE_XPS)\n    return ret\n\n\ndef JM_insert_contents(pdf, pageref, newcont, overlay):\n    '''\n    Insert a buffer as a new separate /Contents object of a page.\n    1. Create a new stream object from buffer 'newcont'\n    2. If /Contents already is an array, then just prepend or append this object\n    3. Else, create new array and put old content obj and this object into it.\n       If the page had no /Contents before, just create a 1-item array.\n    '''\n    contents = mupdf.pdf_dict_get(pageref, PDF_NAME('Contents'))\n    newconts = mupdf.pdf_add_stream(pdf, newcont, mupdf.PdfObj(), 0)\n    xref = mupdf.pdf_to_num(newconts)\n    if mupdf.pdf_is_array(contents):\n        if overlay:  # append new object\n            mupdf.pdf_array_push(contents, newconts)\n        else:   # prepend new object\n            mupdf.pdf_array_insert(contents, newconts, 0)\n    else:\n        carr = mupdf.pdf_new_array(pdf, 5)\n        if overlay:\n            if contents.m_internal:\n                mupdf.pdf_array_push(carr, contents)\n            mupdf.pdf_array_push(carr, newconts)\n        else:\n            mupdf.pdf_array_push(carr, newconts)\n            if contents.m_internal:\n                mupdf.pdf_array_push(carr, contents)\n        mupdf.pdf_dict_put(pageref, PDF_NAME('Contents'), carr)\n    return xref\n\n\ndef JM_insert_font(pdf, bfname, fontfile, fontbuffer, set_simple, idx, wmode, serif, encoding, ordering):\n    '''\n    Insert a font in a PDF\n    '''\n    font = None\n    res = None\n    data = None\n    ixref = 0\n    index = 0\n    simple = 0\n    value=None\n    name=None\n    subt=None\n    exto = None\n\n    ENSURE_OPERATION(pdf)\n    # check for CJK font\n    if ordering > -1:\n        data, size, index = mupdf.fz_lookup_cjk_font(ordering)\n    if data:\n        font = mupdf.fz_new_font_from_memory(None, data, size, index, 0)\n        font_obj = mupdf.pdf_add_cjk_font(pdf, font, ordering, wmode, serif)\n        exto = \"n/a\"\n        simple = 0\n        #goto weiter;\n    else:\n\n        # check for PDF Base-14 font\n        if bfname:\n            data, size = mupdf.fz_lookup_base14_font(bfname)\n        if data:\n            font = mupdf.fz_new_font_from_memory(bfname, data, size, 0, 0)\n            font_obj = mupdf.pdf_add_simple_font(pdf, font, encoding)\n            exto = \"n/a\"\n            simple = 1\n            #goto weiter;\n\n        else:\n            if fontfile:\n                font = mupdf.fz_new_font_from_file(None, fontfile, idx, 0)\n            else:\n                res = JM_BufferFromBytes(fontbuffer)\n                if not res.m_internal:\n                    RAISEPY(MSG_FILE_OR_BUFFER, PyExc_ValueError)\n                font = mupdf.fz_new_font_from_buffer(None, res, idx, 0)\n\n            if not set_simple:\n                font_obj = mupdf.pdf_add_cid_font(pdf, font)\n                simple = 0\n            else:\n                font_obj = mupdf.pdf_add_simple_font(pdf, font, encoding)\n                simple = 2\n    #weiter: ;\n    ixref = mupdf.pdf_to_num(font_obj)\n    name = JM_EscapeStrFromStr( mupdf.pdf_to_name( mupdf.pdf_dict_get(font_obj, PDF_NAME('BaseFont'))))\n\n    subt = JM_UnicodeFromStr( mupdf.pdf_to_name( mupdf.pdf_dict_get( font_obj, PDF_NAME('Subtype'))))\n\n    if not exto:\n        exto = JM_UnicodeFromStr(JM_get_fontextension(pdf, ixref))\n\n    asc = mupdf.fz_font_ascender(font)\n    dsc = mupdf.fz_font_descender(font)\n    value = [\n            ixref,\n            {\n                \"name\": name,        # base font name\n                \"type\": subt,        # subtype\n                \"ext\": exto,         # file extension\n                \"simple\": bool(simple), # simple font?\n                \"ordering\": ordering, # CJK font?\n                \"ascender\": asc,\n                \"descender\": dsc,\n            },\n            ]\n    return value\n\ndef JM_irect_from_py(r):\n    '''\n    PySequence to mupdf.FzIrect. Default: infinite irect\n    '''\n    if isinstance(r, mupdf.FzIrect):\n        return r\n    if isinstance(r, IRect):\n        r = mupdf.FzIrect( r.x0, r.y0, r.x1, r.y1)\n        return r\n    if isinstance(r, Rect):\n        ret = mupdf.FzRect(r.x0, r.y0, r.x1, r.y1)\n        ret = mupdf.FzIrect(ret)  # Uses fz_irect_from_rect().\n        return ret\n    if isinstance(r, mupdf.FzRect):\n        ret = mupdf.FzIrect(r)  # Uses fz_irect_from_rect().\n        return ret\n    if not r or not PySequence_Check(r) or PySequence_Size(r) != 4:\n        return mupdf.FzIrect(mupdf.fz_infinite_irect)\n    f = [0, 0, 0, 0]\n    for i in range(4):\n        f[i] = r[i]\n        if f[i] is None:\n            return mupdf.FzIrect(mupdf.fz_infinite_irect)\n        if f[i] < FZ_MIN_INF_RECT:\n            f[i] = FZ_MIN_INF_RECT\n        if f[i] > FZ_MAX_INF_RECT:\n            f[i] = FZ_MAX_INF_RECT\n    return mupdf.fz_make_irect(f[0], f[1], f[2], f[3])\n\ndef JM_listbox_value( annot):\n    '''\n    ListBox retrieve value\n    '''\n    # may be single value or array\n    annot_obj = mupdf.pdf_annot_obj( annot)\n    optarr = mupdf.pdf_dict_get( annot_obj, PDF_NAME('V'))\n    if mupdf.pdf_is_string( optarr):   # a single string\n        return mupdf.pdf_to_text_string( optarr)\n\n    # value is an array (may have len 0)\n    n = mupdf.pdf_array_len( optarr)\n    liste = []\n\n    # extract a list of strings\n    # each entry may again be an array: take second entry then\n    for i in range( n):\n        elem = mupdf.pdf_array_get( optarr, i)\n        if mupdf.pdf_is_array( elem):\n            elem = mupdf.pdf_array_get( elem, 1)\n        liste.append( JM_UnicodeFromStr( mupdf.pdf_to_text_string( elem)))\n    return liste\n\n\ndef JM_make_annot_DA(annot, ncol, col, fontname, fontsize):\n    # PyMuPDF uses a fz_buffer to build up the string, but it's non-trivial to\n    # convert the fz_buffer's `unsigned char*` into a `const char*` suitable\n    # for passing to pdf_dict_put_text_string(). So instead we build up the\n    # string directly in Python.\n    buf = ''\n    if ncol < 1:\n        buf += f'0 g '\n    elif ncol == 1:\n        buf += f'{col[0]:g} g '\n    elif ncol == 2:\n        assert 0\n    elif ncol == 3:\n        buf += f'{col[0]:g} {col[1]:g} {col[2]:g} rg '\n    else:\n        buf += f'{col[0]:g} {col[1]:g} {col[2]:g} {col[3]:g} k '\n    buf += f'/{JM_expand_fname(fontname)} {fontsize} Tf'\n    mupdf.pdf_dict_put_text_string(mupdf.pdf_annot_obj(annot), mupdf.PDF_ENUM_NAME_DA, buf)\n\n\ndef JM_make_spanlist(line_dict, line, raw, buff, tp_rect):\n    if 1 or g_use_extra:\n        return extra.JM_make_spanlist(line_dict, line, raw, buff, tp_rect)\n    char_list = None\n    span_list = []\n    mupdf.fz_clear_buffer(buff)\n    span_rect = mupdf.FzRect(mupdf.FzRect.Fixed_EMPTY)\n    line_rect = mupdf.FzRect(mupdf.FzRect.Fixed_EMPTY)\n\n    class char_style:\n        def __init__(self, rhs=None):\n            if rhs:\n                self.size = rhs.size\n                self.flags = rhs.flags\n                self.char_flags = rhs.char_flags\n                self.font = rhs.font\n                self.argb = rhs.argb\n                self.asc = rhs.asc\n                self.desc = rhs.desc\n                self.bidi = rhs.bidi\n            else:\n                self.size = -1\n                self.flags = -1\n                self.char_flags = -1\n                self.font = ''\n                self.argb = -1\n                self.asc = 0\n                self.desc = 0\n                self.bidi = 0\n        def __str__(self):\n            ret = f'{self.size} {self.flags}'\n            ret += f' {self.char_flags}'\n            ret += f' {self.font} {self.color} {self.asc} {self.desc}'\n            return ret\n\n    old_style = char_style()\n    style = char_style()\n    span = None\n    span_origin = None\n\n    for ch in line:\n        # start-trace\n        r = JM_char_bbox(line, ch)\n        if (not JM_rects_overlap(tp_rect, r)\n                and not mupdf.fz_is_infinite_rect(tp_rect)\n                ):\n            continue\n\n        # Info from:\n        # detect_super_script()\n        # fz_font_is_italic()\n        # fz_font_is_serif()\n        # fz_font_is_monospaced()\n        # fz_font_is_bold()\n        \n        flags = JM_char_font_flags(mupdf.FzFont(mupdf.ll_fz_keep_font(ch.m_internal.font)), line, ch)\n        origin = mupdf.FzPoint(ch.m_internal.origin)\n        style.size = ch.m_internal.size\n        style.flags = flags\n        # FZ_STEXT_SYNTHETIC is per-char, not per-span.\n        style.char_flags = ch.m_internal.flags & ~mupdf.FZ_STEXT_SYNTHETIC\n        style.font = JM_font_name(mupdf.FzFont(mupdf.ll_fz_keep_font(ch.m_internal.font)))\n        style.argb = ch.m_internal.argb\n        style.asc = JM_font_ascender(mupdf.FzFont(mupdf.ll_fz_keep_font(ch.m_internal.font)))\n        style.desc = JM_font_descender(mupdf.FzFont(mupdf.ll_fz_keep_font(ch.m_internal.font)))\n        style.bidi = ch.m_internal.bidi\n\n        if (style.size != old_style.size\n                or style.flags != old_style.flags\n                or (style.char_flags != old_style.char_flags)\n                or style.argb != old_style.argb\n                or style.font != old_style.font\n                or style.bidi != old_style.bidi\n                ):\n            if old_style.size >= 0:\n                # not first one, output previous\n                if raw:\n                    # put character list in the span\n                    span[dictkey_chars] = char_list\n                    char_list = None\n                else:\n                    # put text string in the span\n                    span[dictkey_text] = JM_EscapeStrFromBuffer( buff)\n                    mupdf.fz_clear_buffer(buff)\n\n                span[dictkey_origin] = JM_py_from_point(span_origin)\n                span[dictkey_bbox] = JM_py_from_rect(span_rect)\n                line_rect = mupdf.fz_union_rect(line_rect, span_rect)\n                span_list.append( span)\n                span = None\n\n            span = dict()\n            asc = style.asc\n            desc = style.desc\n            if style.asc < 1e-3:\n                asc = 0.9\n                desc = -0.1\n\n            span[dictkey_size] = style.size\n            span[dictkey_flags] = style.flags\n            span[dictkey_bidi] = style.bidi\n            span[dictkey_char_flags] = style.char_flags\n            span[dictkey_font] = JM_EscapeStrFromStr(style.font)\n            span[dictkey_color] = style.argb & 0xffffff\n            span['alpha'] = style.argb >> 24\n            span[\"ascender\"] = asc\n            span[\"descender\"] = desc\n\n            # Need to be careful here - doing 'old_style=style' does a shallow\n            # copy, but we need to keep old_style as a distinct instance.\n            old_style = char_style(style)\n            span_rect = r\n            span_origin = origin\n\n        span_rect = mupdf.fz_union_rect(span_rect, r)\n\n        if raw: # make and append a char dict\n            char_dict = dict()\n            char_dict[dictkey_origin] = JM_py_from_point( ch.m_internal.origin)\n            char_dict[dictkey_bbox] = JM_py_from_rect(r)\n            char_dict[dictkey_c] = chr(ch.m_internal.c)\n            char_dict['synthetic'] = bool(ch.m_internal.flags & mupdf.FZ_STEXT_SYNTHETIC)\n\n            if char_list is None:\n                char_list = []\n            char_list.append(char_dict)\n        else:   # add character byte to buffer\n            JM_append_rune(buff, ch.m_internal.c)\n\n    # all characters processed, now flush remaining span\n    if span:\n        if raw:\n            span[dictkey_chars] = char_list\n            char_list = None\n        else:\n            span[dictkey_text] = JM_EscapeStrFromBuffer(buff)\n            mupdf.fz_clear_buffer(buff)\n        span[dictkey_origin] = JM_py_from_point(span_origin)\n        span[dictkey_bbox] = JM_py_from_rect(span_rect)\n\n        if not mupdf.fz_is_empty_rect(span_rect):\n            span_list.append(span)\n            line_rect = mupdf.fz_union_rect(line_rect, span_rect)\n        span = None\n    if not mupdf.fz_is_empty_rect(line_rect):\n        line_dict[dictkey_spans] = span_list\n    else:\n        line_dict[dictkey_spans] = span_list\n    return line_rect\n\ndef _make_image_dict(img, img_dict):\n    \"\"\"Populate a dictionary with information extracted from a given image.\n\n    Used by 'Document.extract_image' and by 'JM_make_image_block'.\n    Both of these functions will add some more specific information.\n    \"\"\"\n    img_type = img.fz_compressed_image_type()\n    ext = JM_image_extension(img_type)\n\n    # compressed image buffer if present, else None\n    ll_cbuf = mupdf.ll_fz_compressed_image_buffer(img.m_internal)\n\n    if (0\n        or not ll_cbuf\n        or img_type in (mupdf.FZ_IMAGE_JBIG2, mupdf.FZ_IMAGE_UNKNOWN)\n        or img_type < mupdf.FZ_IMAGE_BMP\n    ):\n        # not an image with a compressed buffer: convert to PNG\n        res = mupdf.fz_new_buffer_from_image_as_png(\n                    img,\n                    mupdf.FzColorParams(mupdf.fz_default_color_params),\n              )\n        ext = \"png\"\n    elif ext == \"jpeg\" and img.n() == 4:\n        # JPEG with CMYK: invert colors\n        res = mupdf.fz_new_buffer_from_image_as_jpeg(\n                    img, mupdf.FzColorParams(mupdf.fz_default_color_params), 95, 1)\n    else:\n        # copy the compressed buffer\n        res = mupdf.FzBuffer(mupdf.ll_fz_keep_buffer(ll_cbuf.buffer))\n\n    bytes_ = JM_BinFromBuffer(res)\n    img_dict[dictkey_width] = img.w()\n    img_dict[dictkey_height] = img.h()\n    img_dict[dictkey_ext] = ext\n    img_dict[dictkey_colorspace] = img.n()\n    img_dict[dictkey_xres] = img.xres()\n    img_dict[dictkey_yres] = img.yres()\n    img_dict[dictkey_bpc] = img.bpc()\n    img_dict[dictkey_size] = len(bytes_)\n    img_dict[dictkey_image] = bytes_\n\ndef JM_make_image_block(block, block_dict):\n    img = block.i_image()\n    _make_image_dict(img, block_dict)\n    # if the image has a mask, store it as a PNG buffer\n    mask = img.mask()\n    if mask.m_internal:\n        buff = mask.fz_new_buffer_from_image_as_png(mupdf.FzColorParams(mupdf.fz_default_color_params))\n        block_dict[\"mask\"] = buff.fz_buffer_extract()\n    else:\n        block_dict[\"mask\"] = None\n    block_dict[dictkey_matrix] = JM_py_from_matrix(block.i_transform())\n\n\ndef JM_make_text_block(block, block_dict, raw, buff, tp_rect):\n    if 1 or g_use_extra:\n        return extra.JM_make_text_block(block.m_internal, block_dict, raw, buff.m_internal, tp_rect.m_internal)\n    line_list = []\n    block_rect = mupdf.FzRect(mupdf.FzRect.Fixed_EMPTY)\n    #log(f'{block=}')\n    for line in block:\n        #log(f'{line=}')\n        if (mupdf.fz_is_empty_rect(mupdf.fz_intersect_rect(tp_rect, mupdf.FzRect(line.m_internal.bbox)))\n                and not mupdf.fz_is_infinite_rect(tp_rect)\n                ):\n            continue\n        line_dict = dict()\n        line_rect = JM_make_spanlist(line_dict, line, raw, buff, tp_rect)\n        block_rect = mupdf.fz_union_rect(block_rect, line_rect)\n        line_dict[dictkey_wmode] = line.m_internal.wmode\n        line_dict[dictkey_dir] = JM_py_from_point(line.m_internal.dir)\n        line_dict[dictkey_bbox] = JM_py_from_rect(line_rect)\n        line_list.append(line_dict)\n    block_dict[dictkey_bbox] = JM_py_from_rect(block_rect)\n    block_dict[dictkey_lines] = line_list\n\n\ndef JM_make_textpage_dict(tp, page_dict, raw):\n    if 1 or g_use_extra:\n        return extra.JM_make_textpage_dict(tp.m_internal, page_dict, raw)\n    text_buffer = mupdf.fz_new_buffer(128)\n    block_list = []\n    tp_rect = mupdf.FzRect(tp.m_internal.mediabox)\n    block_n = -1\n    #log(f'JM_make_textpage_dict {=tp}')\n    for block in tp:\n        block_n += 1\n        if (not mupdf.fz_contains_rect(tp_rect, mupdf.FzRect(block.m_internal.bbox))\n                and not mupdf.fz_is_infinite_rect(tp_rect)\n                and block.m_internal.type == mupdf.FZ_STEXT_BLOCK_IMAGE\n                ):\n            continue\n        if (not mupdf.fz_is_infinite_rect(tp_rect)\n                and mupdf.fz_is_empty_rect(mupdf.fz_intersect_rect(tp_rect, mupdf.FzRect(block.m_internal.bbox)))\n                ):\n            continue\n\n        block_dict = dict()\n        block_dict[dictkey_number] = block_n\n        block_dict[dictkey_type] = block.m_internal.type\n        if block.m_internal.type == mupdf.FZ_STEXT_BLOCK_IMAGE:\n            block_dict[dictkey_bbox] = JM_py_from_rect(block.m_internal.bbox)\n            JM_make_image_block(block, block_dict)\n        else:\n            JM_make_text_block(block, block_dict, raw, text_buffer, tp_rect)\n\n        block_list.append(block_dict)\n    page_dict[dictkey_blocks] = block_list\n\n\ndef JM_matrix_from_py(m):\n    a = [0, 0, 0, 0, 0, 0]\n    if isinstance(m, mupdf.FzMatrix):\n        return m\n    if isinstance(m, Matrix):\n        return mupdf.FzMatrix(m.a, m.b, m.c, m.d, m.e, m.f)\n    if not m or not PySequence_Check(m) or PySequence_Size(m) != 6:\n        return mupdf.FzMatrix()\n    for i in range(6):\n        a[i] = JM_FLOAT_ITEM(m, i)\n        if a[i] is None:\n            return mupdf.FzRect()\n    return mupdf.FzMatrix(a[0], a[1], a[2], a[3], a[4], a[5])\n\n\ndef JM_mediabox(page_obj):\n    '''\n    return a PDF page's MediaBox\n    '''\n    page_mediabox = mupdf.FzRect(mupdf.FzRect.Fixed_UNIT)\n    mediabox = mupdf.pdf_to_rect(\n            mupdf.pdf_dict_get_inheritable(page_obj, PDF_NAME('MediaBox'))\n            )\n    if mupdf.fz_is_empty_rect(mediabox) or mupdf.fz_is_infinite_rect(mediabox):\n        mediabox.x0 = 0\n        mediabox.y0 = 0\n        mediabox.x1 = 612\n        mediabox.y1 = 792\n\n    page_mediabox = mupdf.FzRect(\n            mupdf.fz_min(mediabox.x0, mediabox.x1),\n            mupdf.fz_min(mediabox.y0, mediabox.y1),\n            mupdf.fz_max(mediabox.x0, mediabox.x1),\n            mupdf.fz_max(mediabox.y0, mediabox.y1),\n            )\n\n    if (page_mediabox.x1 - page_mediabox.x0 < 1\n            or page_mediabox.y1 - page_mediabox.y0 < 1\n            ):\n        page_mediabox = mupdf.FzRect(mupdf.FzRect.Fixed_UNIT)\n\n    return page_mediabox\n\n\ndef JM_merge_range(\n        doc_des,\n        doc_src,\n        spage,\n        epage,\n        apage,\n        rotate,\n        links,\n        annots,\n        show_progress,\n        graft_map,\n        ):\n    '''\n    Copy a range of pages (spage, epage) from a source PDF to a specified\n    location (apage) of the target PDF.\n    If spage > epage, the sequence of source pages is reversed.\n    '''\n    if g_use_extra:\n        return extra.JM_merge_range(\n                doc_des,\n                doc_src,\n                spage,\n                epage,\n                apage,\n                rotate,\n                links,\n                annots,\n                show_progress,\n                graft_map,\n                )\n    afterpage = apage\n    counter = 0  # copied pages counter\n    total = mupdf.fz_absi(epage - spage) + 1   # total pages to copy\n\n    if spage < epage:\n        page = spage\n        while page <= epage:\n            page_merge(doc_des, doc_src, page, afterpage, rotate, links, annots, graft_map)\n            counter += 1\n            if show_progress > 0 and counter % show_progress == 0:\n                message(f\"Inserted {counter} of {total} pages.\")\n            page += 1\n            afterpage += 1\n    else:\n        page = spage\n        while page >= epage:\n            page_merge(doc_des, doc_src, page, afterpage, rotate, links, annots, graft_map)\n            counter += 1\n            if show_progress > 0 and counter % show_progress == 0:\n                message(f\"Inserted {counter} of {total} pages.\")\n            page -= 1\n            afterpage += 1\n\n\ndef JM_merge_resources( page, temp_res):\n    '''\n    Merge the /Resources object created by a text pdf device into the page.\n    The device may have created multiple /ExtGState/Alp? and /Font/F? objects.\n    These need to be renamed (renumbered) to not overwrite existing page\n    objects from previous executions.\n    Returns the next available numbers n, m for objects /Alp<n>, /F<m>.\n    '''\n    # page objects /Resources, /Resources/ExtGState, /Resources/Font\n    resources = mupdf.pdf_dict_get(page.obj(), PDF_NAME('Resources'))\n    if not resources.m_internal:\n        resources = mupdf.pdf_dict_put_dict(page.obj(), PDF_NAME('Resources'), 5)\n    main_extg = mupdf.pdf_dict_get(resources, PDF_NAME('ExtGState'))\n    main_fonts = mupdf.pdf_dict_get(resources, PDF_NAME('Font'))\n\n    # text pdf device objects /ExtGState, /Font\n    temp_extg = mupdf.pdf_dict_get(temp_res, PDF_NAME('ExtGState'))\n    temp_fonts = mupdf.pdf_dict_get(temp_res, PDF_NAME('Font'))\n\n    max_alp = -1\n    max_fonts = -1\n\n    # Handle /Alp objects\n    if mupdf.pdf_is_dict(temp_extg):   # any created at all?\n        n = mupdf.pdf_dict_len(temp_extg)\n        if mupdf.pdf_is_dict(main_extg):   # does page have /ExtGState yet?\n            for i in range(mupdf.pdf_dict_len(main_extg)):\n                # get highest number of objects named /Alpxxx\n                alp = mupdf.pdf_to_name( mupdf.pdf_dict_get_key(main_extg, i))\n                if not alp.startswith('Alp'):\n                    continue\n                j = mupdf.fz_atoi(alp[3:])\n                if j > max_alp:\n                    max_alp = j\n        else:   # create a /ExtGState for the page\n            main_extg = mupdf.pdf_dict_put_dict(resources, PDF_NAME('ExtGState'), n)\n\n        max_alp += 1\n        for i in range(n):  # copy over renumbered /Alp objects\n            alp = mupdf.pdf_to_name( mupdf.pdf_dict_get_key( temp_extg, i))\n            j = mupdf.fz_atoi(alp[3:]) + max_alp\n            text = f'Alp{j}'\n            val = mupdf.pdf_dict_get_val( temp_extg, i)\n            mupdf.pdf_dict_puts(main_extg, text, val)\n\n    if mupdf.pdf_is_dict(main_fonts):  # has page any fonts yet?\n        for i in range(mupdf.pdf_dict_len(main_fonts)):    # get max font number\n            font = mupdf.pdf_to_name( mupdf.pdf_dict_get_key( main_fonts, i))\n            if not font.startswith(\"F\"):\n                continue\n            j = mupdf.fz_atoi(font[1:])\n            if j > max_fonts:\n                max_fonts = j\n    else:   # create a Resources/Font for the page\n        main_fonts = mupdf.pdf_dict_put_dict(resources, PDF_NAME('Font'), 2)\n\n    max_fonts += 1\n    for i in range(mupdf.pdf_dict_len(temp_fonts)):    # copy renumbered fonts\n        font = mupdf.pdf_to_name( mupdf.pdf_dict_get_key( temp_fonts, i))\n        j = mupdf.fz_atoi(font[1:]) + max_fonts\n        text = f'F{j}'\n        val = mupdf.pdf_dict_get_val(temp_fonts, i)\n        mupdf.pdf_dict_puts(main_fonts, text, val)\n    return (max_alp, max_fonts) # next available numbers\n\n\ndef JM_mupdf_warning( text):\n    '''\n    redirect MuPDF warnings\n    '''\n    JM_mupdf_warnings_store.append(text)\n    if JM_mupdf_show_warnings:\n        message(f'MuPDF warning: {text}')\n\n\ndef JM_mupdf_error( text):\n    JM_mupdf_warnings_store.append(text)\n    if JM_mupdf_show_errors:\n        message(f'MuPDF error: {text}\\n')\n\n\ndef JM_new_bbox_device(rc, inc_layers):\n    assert isinstance(rc, list)\n    return JM_new_bbox_device_Device( rc, inc_layers)\n\n\ndef JM_new_buffer_from_stext_page(page):\n    '''\n    make a buffer from an stext_page's text\n    '''\n    assert isinstance(page, mupdf.FzStextPage)\n    rect = mupdf.FzRect(page.m_internal.mediabox)\n    buf = mupdf.fz_new_buffer(256)\n    for block in page:\n        if block.m_internal.type == mupdf.FZ_STEXT_BLOCK_TEXT:\n            for line in block:\n                for ch in line:\n                    if (not JM_rects_overlap(rect, JM_char_bbox(line, ch))\n                            and not mupdf.fz_is_infinite_rect(rect)\n                            ):\n                        continue\n                    mupdf.fz_append_rune(buf, ch.m_internal.c)\n                mupdf.fz_append_byte(buf, ord('\\n'))\n            mupdf.fz_append_byte(buf, ord('\\n'))\n    return buf\n\n\ndef JM_new_javascript(pdf, value):\n    '''\n    make new PDF action object from JavaScript source\n    Parameters are a PDF document and a Python string.\n    Returns a PDF action object.\n    '''\n    if value is None:\n        # no argument given\n        return\n    data = JM_StrAsChar(value)\n    if data is None:\n        # not convertible to char*\n        return\n\n    res = mupdf.fz_new_buffer_from_copied_data(data.encode('utf8'))\n    source = mupdf.pdf_add_stream(pdf, res, mupdf.PdfObj(), 0)\n    newaction = mupdf.pdf_add_new_dict(pdf, 4)\n    mupdf.pdf_dict_put(newaction, PDF_NAME('S'), mupdf.pdf_new_name('JavaScript'))\n    mupdf.pdf_dict_put(newaction, PDF_NAME('JS'), source)\n    return newaction\n\n\ndef JM_new_output_fileptr(bio):\n    return JM_new_output_fileptr_Output( bio)\n\n\ndef JM_norm_rotation(rotate):\n    '''\n    # return normalized /Rotate value:one of 0, 90, 180, 270\n    '''\n    while rotate < 0:\n        rotate += 360\n    while rotate >= 360:\n        rotate -= 360\n    if rotate % 90 != 0:\n        return 0\n    return rotate\n\n\ndef JM_object_to_buffer(what, compress, ascii):\n    res = mupdf.fz_new_buffer(512)\n    out = mupdf.FzOutput(res)\n    mupdf.pdf_print_obj(out, what, compress, ascii)\n    out.fz_close_output()\n    mupdf.fz_terminate_buffer(res)\n    return res\n\n\ndef JM_outline_xrefs(obj, xrefs):\n    '''\n    Return list of outline xref numbers. Recursive function. Arguments:\n    'obj' first OL item\n    'xrefs' empty Python list\n    '''\n    if not obj.m_internal:\n        return xrefs\n    thisobj = obj\n    while thisobj.m_internal:\n        newxref = mupdf.pdf_to_num( thisobj)\n        if newxref in xrefs or mupdf.pdf_dict_get( thisobj, PDF_NAME('Type')).m_internal:\n            # circular ref or top of chain: terminate\n            break\n        xrefs.append( newxref)\n        first = mupdf.pdf_dict_get( thisobj, PDF_NAME('First'))    # try go down\n        if mupdf.pdf_is_dict( first):\n            xrefs = JM_outline_xrefs( first, xrefs)\n        thisobj = mupdf.pdf_dict_get( thisobj, PDF_NAME('Next'))   # try go next\n        parent = mupdf.pdf_dict_get( thisobj, PDF_NAME('Parent'))  # get parent\n        if not mupdf.pdf_is_dict( thisobj):\n            thisobj = parent\n    return xrefs\n\n\ndef JM_page_rotation(page):\n    '''\n    return a PDF page's /Rotate value: one of (0, 90, 180, 270)\n    '''\n    rotate = 0\n\n    obj = mupdf.pdf_dict_get_inheritable( page.obj(), mupdf.PDF_ENUM_NAME_Rotate)\n    rotate = mupdf.pdf_to_int(obj)\n    rotate = JM_norm_rotation(rotate)\n    return rotate\n\n\ndef JM_pdf_obj_from_str(doc, src):\n    '''\n    create PDF object from given string (new in v1.14.0: MuPDF dropped it)\n    '''\n    # fixme: seems inefficient to convert to bytes instance then make another\n    # copy inside fz_new_buffer_from_copied_data(), but no other way?\n    #\n    buffer_ = mupdf.fz_new_buffer_from_copied_data(bytes(src, 'utf8'))\n    stream = mupdf.fz_open_buffer(buffer_)\n    lexbuf = mupdf.PdfLexbuf(mupdf.PDF_LEXBUF_SMALL)\n    result = mupdf.pdf_parse_stm_obj(doc, stream, lexbuf)\n    return result\n\n\ndef JM_pixmap_from_display_list(\n        list_,\n        ctm,\n        cs,\n        alpha,\n        clip,\n        seps,\n        ):\n    '''\n    Version of fz_new_pixmap_from_display_list (util.c) to also support\n    rendering of only the 'clip' part of the displaylist rectangle\n    '''\n    assert isinstance(list_, mupdf.FzDisplayList)\n    if seps is None:\n        seps = mupdf.FzSeparations()\n    assert seps is None or isinstance(seps, mupdf.FzSeparations), f'{type(seps)=}: {seps}'\n\n    rect = mupdf.fz_bound_display_list(list_)\n    matrix = JM_matrix_from_py(ctm)\n    rclip = JM_rect_from_py(clip)\n    rect = mupdf.fz_intersect_rect(rect, rclip)    # no-op if clip is not given\n\n    rect = mupdf.fz_transform_rect(rect, matrix)\n    irect = mupdf.fz_round_rect(rect)\n\n    assert isinstance( cs, mupdf.FzColorspace)\n\n    pix = mupdf.fz_new_pixmap_with_bbox(cs, irect, seps, alpha)\n    if alpha:\n        mupdf.fz_clear_pixmap(pix)\n    else:\n        mupdf.fz_clear_pixmap_with_value(pix, 0xFF)\n\n    if not mupdf.fz_is_infinite_rect(rclip):\n        dev = mupdf.fz_new_draw_device_with_bbox(matrix, pix, irect)\n        mupdf.fz_run_display_list(list_, dev, mupdf.FzMatrix(), rclip, mupdf.FzCookie())\n    else:\n        dev = mupdf.fz_new_draw_device(matrix, pix)\n        mupdf.fz_run_display_list(list_, dev, mupdf.FzMatrix(), mupdf.FzRect(mupdf.FzRect.Fixed_INFINITE), mupdf.FzCookie())\n\n    mupdf.fz_close_device(dev)\n    # Use special raw Pixmap constructor so we don't set alpha to true.\n    return Pixmap( 'raw', pix)\n\n\ndef JM_point_from_py(p):\n    '''\n    PySequence to fz_point. Default: (FZ_MIN_INF_RECT, FZ_MIN_INF_RECT)\n    '''\n    if isinstance(p, mupdf.FzPoint):\n        return p\n    if isinstance(p, Point):\n        return mupdf.FzPoint(p.x, p.y)\n    if g_use_extra:\n        return extra.JM_point_from_py( p)\n    \n    p0 = mupdf.FzPoint(0, 0)\n    x = JM_FLOAT_ITEM(p, 0)\n    y = JM_FLOAT_ITEM(p, 1)\n    if x is None or y is None:\n        return p0\n    x = max( x, FZ_MIN_INF_RECT)\n    y = max( y, FZ_MIN_INF_RECT)\n    x = min( x, FZ_MAX_INF_RECT)\n    y = min( y, FZ_MAX_INF_RECT)\n    return mupdf.FzPoint(x, y)\n\n\ndef JM_print_stext_page_as_text(res, page):\n    '''\n    Plain text output. An identical copy of fz_print_stext_page_as_text,\n    but lines within a block are concatenated by space instead a new-line\n    character (which else leads to 2 new-lines).\n    '''\n    if 1 and g_use_extra:\n        return extra.JM_print_stext_page_as_text(res, page)\n    \n    assert isinstance(res, mupdf.FzBuffer)\n    assert isinstance(page, mupdf.FzStextPage)\n    rect = mupdf.FzRect(page.m_internal.mediabox)\n    last_char = 0\n\n    n_blocks = 0\n    n_lines = 0\n    n_chars = 0\n    for n_blocks2, block in enumerate( page):\n        if block.m_internal.type == mupdf.FZ_STEXT_BLOCK_TEXT:\n            for n_lines2, line in enumerate( block):\n                for n_chars2, ch in enumerate( line):\n                    pass\n                n_chars += n_chars2\n            n_lines += n_lines2\n        n_blocks += n_blocks2\n    \n    for block in page:\n        if block.m_internal.type == mupdf.FZ_STEXT_BLOCK_TEXT:\n            for line in block:\n                last_char = 0\n                for ch in line:\n                    chbbox = JM_char_bbox(line, ch)\n                    if (mupdf.fz_is_infinite_rect(rect)\n                            or JM_rects_overlap(rect, chbbox)\n                            ):\n                        #raw += chr(ch.m_internal.c)\n                        last_char = ch.m_internal.c\n                        #log(f'{=last_char!r utf!r}')\n                        JM_append_rune(res, last_char)\n                if last_char != 10 and last_char > 0:\n                    mupdf.fz_append_string(res, \"\\n\")\n\n\ndef JM_put_script(annot_obj, key1, key2, value):\n    '''\n    Create a JavaScript PDF action.\n    Usable for all object types which support PDF actions, even if the\n    argument name suggests annotations. Up to 2 key values can be specified, so\n    JavaScript actions can be stored for '/A' and '/AA/?' keys.\n    '''\n    key1_obj = mupdf.pdf_dict_get(annot_obj, key1)\n    pdf = mupdf.pdf_get_bound_document(annot_obj)  # owning PDF\n\n    # if no new script given, just delete corresponding key\n    if not value:\n        if key2 is None or not key2.m_internal:\n            mupdf.pdf_dict_del(annot_obj, key1)\n        elif key1_obj.m_internal:\n            mupdf.pdf_dict_del(key1_obj, key2)\n        return\n\n    # read any existing script as a PyUnicode string\n    if not key2.m_internal or not key1_obj.m_internal:\n        script = JM_get_script(key1_obj)\n    else:\n        script = JM_get_script(mupdf.pdf_dict_get(key1_obj, key2))\n\n    # replace old script, if different from new one\n    if value != script:\n        newaction = JM_new_javascript(pdf, value)\n        if not key2.m_internal:\n            mupdf.pdf_dict_put(annot_obj, key1, newaction)\n        else:\n            mupdf.pdf_dict_putl(annot_obj, newaction, key1, key2)\n\n\ndef JM_py_from_irect(r):\n    return r.x0, r.y0, r.x1, r.y1\n\n\ndef JM_py_from_matrix(m):\n    return m.a, m.b, m.c, m.d, m.e, m.f\n\n\ndef JM_py_from_point(p):\n    return p.x, p.y\n\n\ndef JM_py_from_quad(q):\n    '''\n    PySequence from fz_quad.\n    '''\n    return (\n            (q.ul.x, q.ul.y),\n            (q.ur.x, q.ur.y),\n            (q.ll.x, q.ll.y),\n            (q.lr.x, q.lr.y),\n            )\n\n\ndef JM_py_from_rect(r):\n    return r.x0, r.y0, r.x1, r.y1\n\n\ndef JM_quad_from_py(r):\n    if isinstance(r, mupdf.FzQuad):\n        return r\n    # cover all cases of 4-float-sequences\n    if hasattr(r, \"__getitem__\") and len(r) == 4 and hasattr(r[0], \"__float__\"):\n        r = mupdf.FzRect(*tuple(r))\n    if isinstance( r, mupdf.FzRect):\n        return mupdf.fz_quad_from_rect( r)\n    if isinstance( r, Quad):\n        return mupdf.fz_make_quad(\n                r.ul.x, r.ul.y,\n                r.ur.x, r.ur.y,\n                r.ll.x, r.ll.y,\n                r.lr.x, r.lr.y,\n                )\n    q = mupdf.fz_make_quad(0, 0, 0, 0, 0, 0, 0, 0)\n    p = [0,0,0,0]\n    if not r or not isinstance(r, (tuple, list)) or len(r) != 4:\n        return q\n\n    if JM_FLOAT_ITEM(r, 0) is None:\n        return mupdf.fz_quad_from_rect(JM_rect_from_py(r))\n\n    for i in range(4):\n        if i >= len(r):\n            return q    # invalid: cancel the rest\n        obj = r[i]  # next point item\n        if not PySequence_Check(obj) or PySequence_Size(obj) != 2:\n            return q    # invalid: cancel the rest\n\n        p[i].x = JM_FLOAT_ITEM(obj, 0)\n        p[i].y = JM_FLOAT_ITEM(obj, 1)\n        if p[i].x is None or p[i].y is None:\n            return q\n        p[i].x = max( p[i].x, FZ_MIN_INF_RECT)\n        p[i].y = max( p[i].y, FZ_MIN_INF_RECT)\n        p[i].x = min( p[i].x, FZ_MAX_INF_RECT)\n        p[i].y = min( p[i].y, FZ_MAX_INF_RECT)\n    q.ul = p[0]\n    q.ur = p[1]\n    q.ll = p[2]\n    q.lr = p[3]\n    return q\n\n\ndef JM_read_contents(pageref):\n    '''\n    Read and concatenate a PDF page's /Contents object(s) in a buffer\n    '''\n    assert isinstance(pageref, mupdf.PdfObj), f'{type(pageref)}'\n    contents = mupdf.pdf_dict_get(pageref, mupdf.PDF_ENUM_NAME_Contents)\n    if mupdf.pdf_is_array(contents):\n        res = mupdf.FzBuffer(1024)\n        for i in range(mupdf.pdf_array_len(contents)):\n            if i > 0:\n                mupdf.fz_append_byte(res, 32)\n            obj = mupdf.pdf_array_get(contents, i)\n            if mupdf.pdf_is_stream(obj):\n                nres = mupdf.pdf_load_stream(obj)\n                mupdf.fz_append_buffer(res, nres)\n    elif contents.m_internal:\n        res = mupdf.pdf_load_stream(contents)\n    else:\n        res = mupdf.FzBuffer(0)\n    return res\n\n\ndef JM_rect_from_py(r):\n    if isinstance(r, mupdf.FzRect):\n        return r\n    if isinstance(r, mupdf.FzIrect):\n        return mupdf.FzRect(r)\n    if isinstance(r, Rect):\n        return mupdf.fz_make_rect(r.x0, r.y0, r.x1, r.y1)\n    if isinstance(r, IRect):\n        return mupdf.fz_make_rect(r.x0, r.y0, r.x1, r.y1)\n    if not r or not PySequence_Check(r) or PySequence_Size(r) != 4:\n        return mupdf.FzRect(mupdf.FzRect.Fixed_INFINITE)\n    f = [0, 0, 0, 0]\n    for i in range(4):\n        f[i] = JM_FLOAT_ITEM(r, i)\n        if f[i] is None:\n            return mupdf.FzRect(mupdf.FzRect.Fixed_INFINITE)\n        if f[i] < FZ_MIN_INF_RECT:\n            f[i] = FZ_MIN_INF_RECT\n        if f[i] > FZ_MAX_INF_RECT:\n            f[i] = FZ_MAX_INF_RECT\n    return mupdf.fz_make_rect(f[0], f[1], f[2], f[3])\n\n\ndef JM_rects_overlap(a, b):\n    if (0\n            or a.x0 >= b.x1\n            or a.y0 >= b.y1\n            or a.x1 <= b.x0\n            or a.y1 <= b.y0\n            ):\n        return 0\n    return 1\n\n\ndef JM_refresh_links( page):\n    '''\n    refreshes the link and annotation tables of a page\n    '''\n    if page is None or not page.m_internal:\n        return\n    obj = mupdf.pdf_dict_get( page.obj(), PDF_NAME('Annots'))\n    if obj.m_internal:\n        pdf = page.doc()\n        number = mupdf.pdf_lookup_page_number( pdf, page.obj())\n        page_mediabox = mupdf.FzRect()\n        page_ctm = mupdf.FzMatrix()\n        mupdf.pdf_page_transform( page, page_mediabox, page_ctm)\n        link = mupdf.pdf_load_link_annots( pdf, page, obj, number, page_ctm)\n        page.m_internal.links = mupdf.ll_fz_keep_link( link.m_internal)\n\n\ndef JM_rotate_page_matrix(page):\n    '''\n    calculate page rotation matrices\n    '''\n    if not page.m_internal:\n        return mupdf.FzMatrix()  # no valid pdf page given\n    rotation = JM_page_rotation(page)\n    #log(f'{rotation=}')\n    if rotation == 0:\n        return mupdf.FzMatrix()  # no rotation\n    cb_size = JM_cropbox_size(page.obj())\n    w = cb_size.x\n    h = cb_size.y\n    #log(f'{=h w}')\n    if rotation == 90:\n        m = mupdf.fz_make_matrix(0, 1, -1, 0, h, 0)\n    elif rotation == 180:\n        m = mupdf.fz_make_matrix(-1, 0, 0, -1, w, h)\n    else:\n        m = mupdf.fz_make_matrix(0, -1, 1, 0, 0, w)\n    #log(f'returning {m=}')\n    return m\n\n\ndef JM_search_stext_page(page, needle):\n    if 1 or g_use_extra:\n        return extra.JM_search_stext_page(page.m_internal, needle)\n    \n    rect = mupdf.FzRect(page.m_internal.mediabox)\n    if not needle:\n        return\n    quads = []\n    class Hits:\n        def __str__(self):\n            return f'Hits(len={self.len} quads={self.quads} hfuzz={self.hfuzz} vfuzz={self.vfuzz}'\n    hits = Hits()\n    hits.len = 0\n    hits.quads = quads\n    hits.hfuzz = 0.2    # merge kerns but not large gaps\n    hits.vfuzz = 0.1\n\n    buffer_ = JM_new_buffer_from_stext_page(page)\n    haystack_string = mupdf.fz_string_from_buffer(buffer_)\n    haystack = 0\n    begin, end = find_string(haystack_string[haystack:], needle)\n    if begin is None:\n        #goto no_more_matches;\n        return quads\n\n    begin += haystack\n    end += haystack\n    inside = 0\n    i = 0\n    for block in page:\n        if block.m_internal.type != mupdf.FZ_STEXT_BLOCK_TEXT:\n            continue\n        for line in block:\n            for ch in line:\n                i += 1\n                if not mupdf.fz_is_infinite_rect(rect):\n                    r = JM_char_bbox(line, ch)\n                    if not JM_rects_overlap(rect, r):\n                        #goto next_char;\n                        continue\n                while 1:\n                    #try_new_match:\n                    if not inside:\n                        if haystack >= begin:\n                            inside = 1\n                    if inside:\n                        if haystack < end:\n                            on_highlight_char(hits, line, ch)\n                            break\n                        else:\n                            inside = 0\n                            begin, end = find_string(haystack_string[haystack:], needle)\n                            if begin is None:\n                                #goto no_more_matches;\n                                return quads\n                            else:\n                                #goto try_new_match;\n                                begin += haystack\n                                end += haystack\n                                continue\n                    break\n                haystack += 1\n                #next_char:;\n            assert haystack_string[haystack] == '\\n', \\\n                    f'{haystack=} {haystack_string[haystack]=}'\n            haystack += 1\n        assert haystack_string[haystack] == '\\n', \\\n                f'{haystack=} {haystack_string[haystack]=}'\n        haystack += 1\n    #no_more_matches:;\n    return quads\n\n\ndef JM_scan_resources(pdf, rsrc, liste, what, stream_xref, tracer):\n    '''\n    Step through /Resources, looking up image, xobject or font information\n    '''\n    if mupdf.pdf_mark_obj(rsrc):\n        mupdf.fz_warn('Circular dependencies! Consider page cleaning.')\n        return  # Circular dependencies!\n    try:\n        xobj = mupdf.pdf_dict_get(rsrc, mupdf.PDF_ENUM_NAME_XObject)\n\n        if what == 1:   # lookup fonts\n            font = mupdf.pdf_dict_get(rsrc, mupdf.PDF_ENUM_NAME_Font)\n            JM_gather_fonts(pdf, font, liste, stream_xref)\n        elif what == 2: # look up images\n            JM_gather_images(pdf, xobj, liste, stream_xref)\n        elif what == 3: # look up form xobjects\n            JM_gather_forms(pdf, xobj, liste, stream_xref)\n        else:   # should never happen\n            return\n\n        # check if we need to recurse into Form XObjects\n        n = mupdf.pdf_dict_len(xobj)\n        for i in range(n):\n            obj = mupdf.pdf_dict_get_val(xobj, i)\n            if mupdf.pdf_is_stream(obj):\n                sxref = mupdf.pdf_to_num(obj)\n            else:\n                sxref = 0\n            subrsrc = mupdf.pdf_dict_get(obj, mupdf.PDF_ENUM_NAME_Resources)\n            if subrsrc.m_internal:\n                sxref_t = sxref\n                if sxref_t not in tracer:\n                    tracer.append(sxref_t)\n                    JM_scan_resources( pdf, subrsrc, liste, what, sxref, tracer)\n                else:\n                    mupdf.fz_warn('Circular dependencies! Consider page cleaning.')\n                    return\n    finally:\n        mupdf.pdf_unmark_obj(rsrc)\n\n\ndef JM_set_choice_options(annot, liste):\n    '''\n    set ListBox / ComboBox values\n    '''\n    if not liste:\n        return\n    assert isinstance( liste, (tuple, list))\n    n = len( liste)\n    if n == 0:\n        return\n    annot_obj = mupdf.pdf_annot_obj( annot)\n    pdf = mupdf.pdf_get_bound_document( annot_obj)\n    optarr = mupdf.pdf_new_array( pdf, n)\n    for i in range(n):\n        val = liste[i]\n        opt = val\n        if isinstance(opt, str):\n            mupdf.pdf_array_push_text_string( optarr, opt)\n        else:\n            assert isinstance( val, (tuple, list)) and len( val) == 2, 'bad choice field list'\n            opt1, opt2 = val\n            assert opt1 and opt2, 'bad choice field list'\n            optarrsub = mupdf.pdf_array_push_array( optarr, 2)\n            mupdf.pdf_array_push_text_string( optarrsub, opt1)\n            mupdf.pdf_array_push_text_string( optarrsub, opt2)\n    mupdf.pdf_dict_put( annot_obj, PDF_NAME('Opt'), optarr)\n\n\ndef JM_set_field_type(doc, obj, type):\n    '''\n    Set the field type\n    '''\n    setbits = 0\n    clearbits = 0\n    typename = None\n    if type == mupdf.PDF_WIDGET_TYPE_BUTTON:\n        typename = PDF_NAME('Btn')\n        setbits = mupdf.PDF_BTN_FIELD_IS_PUSHBUTTON\n    elif type == mupdf.PDF_WIDGET_TYPE_RADIOBUTTON:\n        typename = PDF_NAME('Btn')\n        clearbits = mupdf.PDF_BTN_FIELD_IS_PUSHBUTTON\n        setbits = mupdf.PDF_BTN_FIELD_IS_RADIO\n    elif type == mupdf.PDF_WIDGET_TYPE_CHECKBOX:\n        typename = PDF_NAME('Btn')\n        clearbits = (mupdf.PDF_BTN_FIELD_IS_PUSHBUTTON | mupdf.PDF_BTN_FIELD_IS_RADIO)\n    elif type == mupdf.PDF_WIDGET_TYPE_TEXT:\n        typename = PDF_NAME('Tx')\n    elif type == mupdf.PDF_WIDGET_TYPE_LISTBOX:\n        typename = PDF_NAME('Ch')\n        clearbits = mupdf.PDF_CH_FIELD_IS_COMBO\n    elif type == mupdf.PDF_WIDGET_TYPE_COMBOBOX:\n        typename = PDF_NAME('Ch')\n        setbits = mupdf.PDF_CH_FIELD_IS_COMBO\n    elif type == mupdf.PDF_WIDGET_TYPE_SIGNATURE:\n        typename = PDF_NAME('Sig')\n\n    if typename is not None and typename.m_internal:\n        mupdf.pdf_dict_put(obj, PDF_NAME('FT'), typename)\n\n    if setbits != 0 or clearbits != 0:\n        bits = mupdf.pdf_dict_get_int(obj, PDF_NAME('Ff'))\n        bits &= ~clearbits\n        bits |= setbits\n        mupdf.pdf_dict_put_int(obj, PDF_NAME('Ff'), bits)\n\n\ndef JM_set_object_value(obj, key, value):\n    '''\n    Set a PDF dict key to some value\n    '''\n    eyecatcher = \"fitz: replace me!\"\n    pdf = mupdf.pdf_get_bound_document(obj)\n    # split PDF key at path seps and take last key part\n    list_ = key.split('/')\n    len_ = len(list_)\n    i = len_ - 1\n    skey = list_[i]\n\n    del list_[i]    # del the last sub-key\n    len_ = len(list_)   # remaining length\n    testkey = mupdf.pdf_dict_getp(obj, key)    # check if key already exists\n    if not testkey.m_internal:\n        #No, it will be created here. But we cannot allow this happening if\n        #indirect objects are referenced. So we check all higher level\n        #sub-paths for indirect references.\n        while len_ > 0:\n            t = '/'.join(list_) # next high level\n            if mupdf.pdf_is_indirect(mupdf.pdf_dict_getp(obj, JM_StrAsChar(t))):\n                raise Exception(f\"path to '{JM_StrAsChar(skey)}' has indirects\")\n            del list_[len_ - 1]   # del last sub-key\n            len_ = len(list_)   # remaining length\n    # Insert our eyecatcher. Will create all sub-paths in the chain, or\n    # respectively remove old value of key-path.\n    mupdf.pdf_dict_putp(obj, key, mupdf.pdf_new_text_string(eyecatcher))\n    testkey = mupdf.pdf_dict_getp(obj, key)\n    if not mupdf.pdf_is_string(testkey):\n        raise Exception(f\"cannot insert value for '{key}'\")\n    temp = mupdf.pdf_to_text_string(testkey)\n    if temp != eyecatcher:\n        raise Exception(f\"cannot insert value for '{key}'\")\n    # read the result as a string\n    res = JM_object_to_buffer(obj, 1, 0)\n    objstr = JM_EscapeStrFromBuffer(res)\n\n    # replace 'eyecatcher' by desired 'value'\n    nullval = f\"/{skey}({eyecatcher})\"\n    newval = f\"/{skey} {value}\"\n    newstr = objstr.replace(nullval, newval, 1)\n\n    # make PDF object from resulting string\n    new_obj = JM_pdf_obj_from_str(pdf, newstr)\n    return new_obj\n\n\ndef JM_set_ocg_arrays(conf, basestate, on, off, rbgroups, locked):\n    if basestate:\n        mupdf.pdf_dict_put_name( conf, PDF_NAME('BaseState'), basestate)\n\n    if on is not None:\n        mupdf.pdf_dict_del( conf, PDF_NAME('ON'))\n        if on:\n            arr = mupdf.pdf_dict_put_array( conf, PDF_NAME('ON'), 1)\n            JM_set_ocg_arrays_imp( arr, on)\n    if off is not None:\n        mupdf.pdf_dict_del( conf, PDF_NAME('OFF'))\n        if off:\n            arr = mupdf.pdf_dict_put_array( conf, PDF_NAME('OFF'), 1)\n            JM_set_ocg_arrays_imp( arr, off)\n    if locked is not None:\n        mupdf.pdf_dict_del( conf, PDF_NAME('Locked'))\n        if locked:\n            arr = mupdf.pdf_dict_put_array( conf, PDF_NAME('Locked'), 1)\n            JM_set_ocg_arrays_imp( arr, locked)\n    if rbgroups is not None:\n        mupdf.pdf_dict_del( conf, PDF_NAME('RBGroups'))\n        if rbgroups:\n            arr = mupdf.pdf_dict_put_array( conf, PDF_NAME('RBGroups'), 1)\n            n =len(rbgroups)\n            for i in range(n):\n                item0 = rbgroups[i]\n                obj = mupdf.pdf_array_push_array( arr, 1)\n                JM_set_ocg_arrays_imp( obj, item0)\n\n\ndef JM_set_ocg_arrays_imp(arr, list_):\n    '''\n    Set OCG arrays from dict of Python lists\n    Works with dict like {\"basestate\":name, \"on\":list, \"off\":list, \"rbg\":list}\n    '''\n    pdf = mupdf.pdf_get_bound_document(arr)\n    for xref in list_:\n        obj = mupdf.pdf_new_indirect(pdf, xref, 0)\n        mupdf.pdf_array_push(arr, obj)\n\n\ndef JM_set_resource_property(ref, name, xref):\n    '''\n    Insert an item into Resources/Properties (used for Marked Content)\n    Arguments:\n    (1) e.g. page object, Form XObject\n    (2) marked content name\n    (3) xref of the referenced object (insert as indirect reference)\n    '''\n    pdf = mupdf.pdf_get_bound_document(ref)\n    ind = mupdf.pdf_new_indirect(pdf, xref, 0)\n    if not ind.m_internal:\n        RAISEPY(MSG_BAD_XREF, PyExc_ValueError)\n    resources = mupdf.pdf_dict_get(ref, PDF_NAME('Resources'))\n    if not resources.m_internal:\n        resources = mupdf.pdf_dict_put_dict(ref, PDF_NAME('Resources'), 1)\n    properties = mupdf.pdf_dict_get(resources, PDF_NAME('Properties'))\n    if not properties.m_internal:\n        properties = mupdf.pdf_dict_put_dict(resources, PDF_NAME('Properties'), 1)\n    mupdf.pdf_dict_put(properties, mupdf.pdf_new_name(name), ind)\n\n\ndef JM_set_widget_properties(annot, Widget):\n    '''\n    Update the PDF form field with the properties from a Python Widget object.\n    Called by \"Page.add_widget\" and \"Annot.update_widget\".\n    '''\n    if isinstance( annot, Annot):\n        annot = annot.this\n    assert isinstance( annot, mupdf.PdfAnnot), f'{type(annot)=} {type=}'\n    page = _pdf_annot_page(annot)\n    assert page.m_internal, 'Annot is not bound to a page'\n    annot_obj = mupdf.pdf_annot_obj(annot)\n    pdf = page.doc()\n    def GETATTR(name):\n        return getattr(Widget, name, None)\n\n    value = GETATTR(\"field_type\")\n    field_type = value\n\n    # rectangle --------------------------------------------------------------\n    value = GETATTR(\"rect\")\n    rect = JM_rect_from_py(value)\n    rot_mat = JM_rotate_page_matrix(page)\n    rect = mupdf.fz_transform_rect(rect, rot_mat)\n    mupdf.pdf_set_annot_rect(annot, rect)\n\n    # fill color -------------------------------------------------------------\n    value = GETATTR(\"fill_color\")\n    if value and PySequence_Check(value):\n        n = len(value)\n        fill_col = mupdf.pdf_new_array(pdf, n)\n        col = 0\n        for i in range(n):\n            col = value[i]\n            mupdf.pdf_array_push_real(fill_col, col)\n        mupdf.pdf_field_set_fill_color(annot_obj, fill_col)\n\n    # dashes -----------------------------------------------------------------\n    value = GETATTR(\"border_dashes\")\n    if value and PySequence_Check(value):\n        n = len(value)\n        dashes = mupdf.pdf_new_array(pdf, n)\n        for i in range(n):\n            mupdf.pdf_array_push_int(dashes, value[i])\n        mupdf.pdf_dict_putl(annot_obj, dashes, PDF_NAME('BS'), PDF_NAME('D'))\n\n    # border color -----------------------------------------------------------\n    value = GETATTR(\"border_color\")\n    if value and PySequence_Check(value):\n        n = len(value)\n        border_col = mupdf.pdf_new_array(pdf, n)\n        col = 0\n        for i in range(n):\n            col = value[i]\n            mupdf.pdf_array_push_real(border_col, col)\n        mupdf.pdf_dict_putl(annot_obj, border_col, PDF_NAME('MK'), PDF_NAME('BC'))\n\n    # entry ignored - may be used later\n    #\n    #int text_format = (int) PyInt_AsLong(GETATTR(\"text_format\"));\n    #\n\n    # field label -----------------------------------------------------------\n    value = GETATTR(\"field_label\")\n    if value is not None:\n        label = JM_StrAsChar(value)\n        mupdf.pdf_dict_put_text_string(annot_obj, PDF_NAME('TU'), label)\n\n    # field name -------------------------------------------------------------\n    value = GETATTR(\"field_name\")\n    if value is not None:\n        name = JM_StrAsChar(value)\n        old_name = mupdf.pdf_load_field_name(annot_obj)\n        if name != old_name:\n            mupdf.pdf_dict_put_text_string(annot_obj, PDF_NAME('T'), name)\n\n    # max text len -----------------------------------------------------------\n    if field_type == mupdf.PDF_WIDGET_TYPE_TEXT:\n        value = GETATTR(\"text_maxlen\")\n        text_maxlen = value\n        if text_maxlen:\n            mupdf.pdf_dict_put_int(annot_obj, PDF_NAME('MaxLen'), text_maxlen)\n    value = GETATTR(\"field_display\")\n    d = value\n    mupdf.pdf_field_set_display(annot_obj, d)\n\n    # choice values ----------------------------------------------------------\n    if field_type in (mupdf.PDF_WIDGET_TYPE_LISTBOX, mupdf.PDF_WIDGET_TYPE_COMBOBOX):\n        value = GETATTR(\"choice_values\")\n        JM_set_choice_options(annot, value)\n\n    # border style -----------------------------------------------------------\n    value = GETATTR(\"border_style\")\n    val = JM_get_border_style(value)\n    mupdf.pdf_dict_putl(annot_obj, val, PDF_NAME('BS'), PDF_NAME('S'))\n\n    # border width -----------------------------------------------------------\n    value = GETATTR(\"border_width\")\n    border_width = value\n    mupdf.pdf_dict_putl(\n            annot_obj,\n            mupdf.pdf_new_real(border_width),\n            PDF_NAME('BS'),\n            PDF_NAME('W'),\n            )\n\n    # /DA string -------------------------------------------------------------\n    value = GETATTR(\"_text_da\")\n    da = JM_StrAsChar(value)\n    mupdf.pdf_dict_put_text_string(annot_obj, PDF_NAME('DA'), da)\n    mupdf.pdf_dict_del(annot_obj, PDF_NAME('DS'))  # not supported by MuPDF\n    mupdf.pdf_dict_del(annot_obj, PDF_NAME('RC'))  # not supported by MuPDF\n\n    # field flags ------------------------------------------------------------\n    field_flags = GETATTR(\"field_flags\")\n    if field_flags is not None:\n        if field_type == mupdf.PDF_WIDGET_TYPE_COMBOBOX:\n            field_flags |= mupdf.PDF_CH_FIELD_IS_COMBO\n        elif field_type == mupdf.PDF_WIDGET_TYPE_RADIOBUTTON:\n            field_flags |= mupdf.PDF_BTN_FIELD_IS_RADIO\n        elif field_type == mupdf.PDF_WIDGET_TYPE_BUTTON:\n            field_flags |= mupdf.PDF_BTN_FIELD_IS_PUSHBUTTON\n        mupdf.pdf_dict_put_int( annot_obj, PDF_NAME('Ff'), field_flags)\n\n    # button caption ---------------------------------------------------------\n    value = GETATTR(\"button_caption\")\n    ca = JM_StrAsChar(value)\n    if ca:\n        mupdf.pdf_field_set_button_caption(annot_obj, ca)\n\n    # script (/A) -------------------------------------------------------\n    value = GETATTR(\"script\")\n    JM_put_script(annot_obj, PDF_NAME('A'), mupdf.PdfObj(), value)\n\n    # script (/AA/K) -------------------------------------------------------\n    value = GETATTR(\"script_stroke\")\n    JM_put_script(annot_obj, PDF_NAME('AA'), PDF_NAME('K'), value)\n\n    # script (/AA/F) -------------------------------------------------------\n    value = GETATTR(\"script_format\")\n    JM_put_script(annot_obj, PDF_NAME('AA'), PDF_NAME('F'), value)\n\n    # script (/AA/V) -------------------------------------------------------\n    value = GETATTR(\"script_change\")\n    JM_put_script(annot_obj, PDF_NAME('AA'), PDF_NAME('V'), value)\n\n    # script (/AA/C) -------------------------------------------------------\n    value = GETATTR(\"script_calc\")\n    JM_put_script(annot_obj, PDF_NAME('AA'), PDF_NAME('C'), value)\n\n    # script (/AA/Bl) -------------------------------------------------------\n    value = GETATTR(\"script_blur\")\n    JM_put_script(annot_obj, PDF_NAME('AA'), mupdf.pdf_new_name('Bl'), value)\n\n    # script (/AA/Fo) codespell:ignore --------------------------------------\n    value = GETATTR(\"script_focus\")\n    JM_put_script(annot_obj, PDF_NAME('AA'), mupdf.pdf_new_name('Fo'), value)\n\n    # field value ------------------------------------------------------------\n    value = GETATTR(\"field_value\")  # field value\n    text = JM_StrAsChar(value)  # convert to text (may fail!)\n    if field_type == mupdf.PDF_WIDGET_TYPE_RADIOBUTTON:\n        if not value:\n            mupdf.pdf_set_field_value(pdf, annot_obj, \"Off\", 1)\n            mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), \"Off\")\n        else:\n            # TODO check if another button in the group is ON and if so set it Off\n            onstate = mupdf.pdf_button_field_on_state(annot_obj)\n            if onstate.m_internal:\n                on = mupdf.pdf_to_name(onstate)\n                mupdf.pdf_set_field_value(pdf, annot_obj, on, 1)\n                mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), on)\n            elif text:\n                mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), text)\n    elif field_type == mupdf.PDF_WIDGET_TYPE_CHECKBOX:\n        onstate = mupdf.pdf_button_field_on_state(annot_obj)\n        on = onstate.pdf_to_name()\n        if value in (True, on) or text == 'Yes':\n            mupdf.pdf_set_field_value(pdf, annot_obj, on, 1)\n            mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('AS'), on)\n            mupdf.pdf_dict_put_name(annot_obj, PDF_NAME('V'), on)\n        else:\n            mupdf.pdf_dict_put_name( annot_obj, PDF_NAME('AS'), 'Off')\n            mupdf.pdf_dict_put_name( annot_obj, PDF_NAME('V'), 'Off')\n    else:\n        if text:\n            mupdf.pdf_set_field_value(pdf, annot_obj, text, 1)\n            if field_type in (mupdf.PDF_WIDGET_TYPE_COMBOBOX, mupdf.PDF_WIDGET_TYPE_LISTBOX):\n                mupdf.pdf_dict_del(annot_obj, PDF_NAME('I'))\n    mupdf.pdf_dirty_annot(annot)\n    mupdf.pdf_set_annot_hot(annot, 1)\n    mupdf.pdf_set_annot_active(annot, 1)\n    mupdf.pdf_update_annot(annot)\n\n\ndef JM_show_string_cs(\n        text,\n        user_font,\n        trm,\n        s,\n        wmode,\n        bidi_level,\n        markup_dir,\n        language,\n        ):\n    i = 0\n    while i < len(s):\n        l, ucs = mupdf.fz_chartorune(s[i:])\n        i += l\n        gid = mupdf.fz_encode_character_sc(user_font, ucs)\n        if gid == 0:\n            gid, font = mupdf.fz_encode_character_with_fallback(user_font, ucs, 0, language)\n        else:\n            font = user_font\n        mupdf.fz_show_glyph(text, font, trm, gid, ucs, wmode, bidi_level, markup_dir, language)\n        adv = mupdf.fz_advance_glyph(font, gid, wmode)\n        if wmode == 0:\n            trm = mupdf.fz_pre_translate(trm, adv, 0)\n        else:\n            trm = mupdf.fz_pre_translate(trm, 0, -adv)\n    return trm\n\n\ndef JM_UnicodeFromBuffer(buff):\n    buff_bytes = mupdf.fz_buffer_extract_copy(buff)\n    val = buff_bytes.decode(errors='replace')\n    z = val.find(chr(0))\n    if z >= 0:\n        val = val[:z]\n    return val\n\n\ndef message_warning(text):\n    '''\n    Generate a warning.\n    '''\n    message(f'warning: {text}')\n\n\ndef JM_update_stream(doc, obj, buffer_, compress):\n    '''\n    update a stream object\n    compress stream when beneficial\n    '''\n    if compress:\n        length, _ = mupdf.fz_buffer_storage(buffer_)\n        if length > 30:   # ignore small stuff\n            buffer_compressed = JM_compress_buffer(buffer_)\n            assert isinstance(buffer_compressed, mupdf.FzBuffer)\n            if buffer_compressed.m_internal:\n                length_compressed, _ = mupdf.fz_buffer_storage(buffer_compressed)\n                if length_compressed < length:  # was it worth the effort?\n                    mupdf.pdf_dict_put(\n                            obj,\n                            mupdf.PDF_ENUM_NAME_Filter,\n                            mupdf.PDF_ENUM_NAME_FlateDecode,\n                            )\n                    mupdf.pdf_update_stream(doc, obj, buffer_compressed, 1)\n                    return\n    \n    mupdf.pdf_update_stream(doc, obj, buffer_, 0)\n\n\ndef JM_xobject_from_page(pdfout, fsrcpage, xref, gmap):\n    '''\n    Make an XObject from a PDF page\n    For a positive xref assume that its object can be used instead\n    '''\n    assert isinstance(gmap, mupdf.PdfGraftMap), f'{type(gmap)=}'\n    if xref > 0:\n        xobj1 = mupdf.pdf_new_indirect(pdfout, xref, 0)\n    else:\n        srcpage = _as_pdf_page(fsrcpage.this)\n        spageref = srcpage.obj()\n        mediabox = mupdf.pdf_to_rect(mupdf.pdf_dict_get_inheritable(spageref, PDF_NAME('MediaBox')))\n        # Deep-copy resources object of source page\n        o = mupdf.pdf_dict_get_inheritable(spageref, PDF_NAME('Resources'))\n        if gmap.m_internal:\n            # use graftmap when possible\n            resources = mupdf.pdf_graft_mapped_object(gmap, o)\n        else:\n            resources = mupdf.pdf_graft_object(pdfout, o)\n\n        # get spgage contents source\n        res = JM_read_contents(spageref)\n\n        #-------------------------------------------------------------\n        # create XObject representing the source page\n        #-------------------------------------------------------------\n        xobj1 = mupdf.pdf_new_xobject(pdfout, mediabox, mupdf.FzMatrix(), mupdf.PdfObj(0), res)\n        # store spage contents\n        JM_update_stream(pdfout, xobj1, res, 1)\n\n        # store spage resources\n        mupdf.pdf_dict_put(xobj1, PDF_NAME('Resources'), resources)\n    return xobj1\n\n\ndef PySequence_Check(s):\n    return isinstance(s, (tuple, list))\n\n\ndef PySequence_Size(s):\n    return len(s)\n\n\n# constants: error messages. These are also in extra.i.\n#\nMSG_BAD_ANNOT_TYPE = \"bad annot type\"\nMSG_BAD_APN = \"bad or missing annot AP/N\"\nMSG_BAD_ARG_INK_ANNOT = \"arg must be seq of seq of float pairs\"\nMSG_BAD_ARG_POINTS = \"bad seq of points\"\nMSG_BAD_BUFFER = \"bad type: 'buffer'\"\nMSG_BAD_COLOR_SEQ = \"bad color sequence\"\nMSG_BAD_DOCUMENT = \"cannot open broken document\"\nMSG_BAD_FILETYPE = \"bad filetype\"\nMSG_BAD_LOCATION = \"bad location\"\nMSG_BAD_OC_CONFIG = \"bad config number\"\nMSG_BAD_OC_LAYER = \"bad layer number\"\nMSG_BAD_OC_REF = \"bad 'oc' reference\"\nMSG_BAD_PAGEID = \"bad page id\"\nMSG_BAD_PAGENO = \"bad page number(s)\"\nMSG_BAD_PDFROOT = \"PDF has no root\"\nMSG_BAD_RECT = \"rect is infinite or empty\"\nMSG_BAD_TEXT = \"bad type: 'text'\"\nMSG_BAD_XREF = \"bad xref\"\nMSG_COLOR_COUNT_FAILED = \"color count failed\"\nMSG_FILE_OR_BUFFER = \"need font file or buffer\"\nMSG_FONT_FAILED = \"cannot create font\"\nMSG_IS_NO_ANNOT = \"is no annotation\"\nMSG_IS_NO_IMAGE = \"is no image\"\nMSG_IS_NO_PDF = \"is no PDF\"\nMSG_IS_NO_DICT = \"object is no PDF dict\"\nMSG_PIX_NOALPHA = \"source pixmap has no alpha\"\nMSG_PIXEL_OUTSIDE = \"pixel(s) outside image\"\n\n\nJM_Exc_FileDataError = 'FileDataError'\nPyExc_ValueError = 'ValueError'\n\ndef RAISEPY( msg, exc):\n    #JM_Exc_CurrentException=exc\n    #fz_throw(context, FZ_ERROR_GENERIC, msg)\n    raise Exception( msg)\n\n\ndef PyUnicode_DecodeRawUnicodeEscape(s, errors='strict'):\n    # FIXED: handle raw unicode escape sequences\n    if not s:\n        return \"\"\n    if isinstance(s, str):\n        rc = s.encode(\"utf8\", errors=errors)\n    elif isinstance(s, bytes):\n        rc = s[:]\n    ret = rc.decode('raw_unicode_escape', errors=errors)\n    return ret\n\n\ndef CheckColor(c: OptSeq):\n    if c:\n        if (\n            type(c) not in (list, tuple)\n            or len(c) not in (1, 3, 4)\n            or min(c) < 0\n            or max(c) > 1\n        ):\n            raise ValueError(\"need 1, 3 or 4 color components in range 0 to 1\")\n\n\ndef CheckFont(page: Page, fontname: str) -> tuple:\n    \"\"\"Return an entry in the page's font list if reference name matches.\n    \"\"\"\n    for f in page.get_fonts():\n        if f[4] == fontname:\n            return f\n\n\ndef CheckFontInfo(doc: Document, xref: int) -> list:\n    \"\"\"Return a font info if present in the document.\n    \"\"\"\n    for f in doc.FontInfos:\n        if xref == f[0]:\n            return f\n\n\ndef CheckMarkerArg(quads: typing.Any) -> tuple:\n    if CheckRect(quads):\n        r = Rect(quads)\n        return (r.quad,)\n    if CheckQuad(quads):\n        return (quads,)\n    for q in quads:\n        if not (CheckRect(q) or CheckQuad(q)):\n            raise ValueError(\"bad quads entry\")\n    return quads\n\n\ndef CheckMorph(o: typing.Any) -> bool:\n    if not bool(o):\n        return False\n    if not (type(o) in (list, tuple) and len(o) == 2):\n        raise ValueError(\"morph must be a sequence of length 2\")\n    if not (len(o[0]) == 2 and len(o[1]) == 6):\n        raise ValueError(\"invalid morph param 0\")\n    if not o[1][4] == o[1][5] == 0:\n        raise ValueError(\"invalid morph param 1\")\n    return True\n\n\ndef CheckParent(o: typing.Any):\n    return\n    if not hasattr(o, \"parent\") or o.parent is None:\n        raise ValueError(f\"orphaned object {type(o)=}: parent is None\")\n\n\ndef CheckQuad(q: typing.Any) -> bool:\n    \"\"\"Check whether an object is convex, not empty  quad-like.\n\n    It must be a sequence of 4 number pairs.\n    \"\"\"\n    try:\n        q0 = Quad(q)\n    except Exception:\n        if g_exceptions_verbose > 1:    exception_info()\n        return False\n    return q0.is_convex\n\n\ndef CheckRect(r: typing.Any) -> bool:\n    \"\"\"Check whether an object is non-degenerate rect-like.\n\n    It must be a sequence of 4 numbers.\n    \"\"\"\n    try:\n        r = Rect(r)\n    except Exception:\n        if g_exceptions_verbose > 1:    exception_info()\n        return False\n    return not (r.is_empty or r.is_infinite)\n\n\ndef ColorCode(c: typing.Union[list, tuple, float, None], f: str) -> str:\n    if not c:\n        return \"\"\n    if hasattr(c, \"__float__\"):\n        c = (c,)\n    CheckColor(c)\n    if len(c) == 1:\n        s = _format_g(c[0]) + \" \"\n        return s + \"G \" if f == \"c\" else s + \"g \"\n\n    if len(c) == 3:\n        s = _format_g(tuple(c)) + \" \"\n        return s + \"RG \" if f == \"c\" else s + \"rg \"\n\n    s = _format_g(tuple(c)) + \" \"\n    return s + \"K \" if f == \"c\" else s + \"k \"\n\n\ndef Page__add_text_marker(self, quads, annot_type):\n    pdfpage = self._pdf_page()\n    rotation = JM_page_rotation(pdfpage)\n    def final():\n        if rotation != 0:\n            mupdf.pdf_dict_put_int(pdfpage.obj(), PDF_NAME('Rotate'), rotation)\n    try:\n        if rotation != 0:\n            mupdf.pdf_dict_put_int(pdfpage.obj(), PDF_NAME('Rotate'), 0)\n        annot = mupdf.pdf_create_annot(pdfpage, annot_type)\n        for item in quads:\n            q = JM_quad_from_py(item)\n            mupdf.pdf_add_annot_quad_point(annot, q)\n        mupdf.pdf_update_annot(annot)\n        JM_add_annot_id(annot, \"A\")\n        final()\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        final()\n        return\n    return Annot(annot)\n\n\ndef PDF_NAME(x):\n    assert isinstance(x, str)\n    ret = getattr(mupdf, f'PDF_ENUM_NAME_{x}')\n    # Note that we return a (swig proxy for) pdf_obj*, not a mupdf.PdfObj. In\n    # the C++ API, the constructor PdfObj::PdfObj(pdf_obj*) is marked as\n    # explicit, but this seems to be ignored by SWIG. If SWIG started to\n    # generate code that respected `explicit`, we would need to do `return\n    # mupdf.PdfObj(ret)`.\n    #\n    # [Compare with extra.i, where we define our own PDF_NAME2() macro that\n    # returns a mupdf::PdfObj.]\n    return ret\n\n\ndef UpdateFontInfo(doc: Document, info: typing.Sequence):\n    xref = info[0]\n    found = False\n    for i, fi in enumerate(doc.FontInfos):\n        if fi[0] == xref:\n            found = True\n            break\n    if found:\n        doc.FontInfos[i] = info\n    else:\n        doc.FontInfos.append(info)\n\n\ndef args_match(args, *types):\n    '''\n    Returns true if <args> matches <types>.\n\n    Each item in <types> is a type or tuple of types. Any of these types will\n    match an item in <args>. `None` will match anything in <args>. `type(None)`\n    will match an arg whose value is `None`.\n    '''\n    j = 0\n    for i in range(len(types)):\n        type_ = types[i]\n        if j >= len(args):\n            if isinstance(type_, tuple) and None in type_:\n                # arg is missing but has default value.\n                continue\n            else:\n                return False\n        if type_ is not None and not isinstance(args[j], type_):\n            return False\n        j += 1\n    if j != len(args):\n        return False\n    return True\n\n\ndef calc_image_matrix(width, height, tr, rotate, keep):\n    '''\n    # compute image insertion matrix\n    '''\n    trect = JM_rect_from_py(tr)\n    rot = mupdf.fz_rotate(rotate)\n    trw = trect.x1 - trect.x0\n    trh = trect.y1 - trect.y0\n    w = trw\n    h = trh\n    if keep:\n        large = max(width, height)\n        fw = width / large\n        fh = height / large\n    else:\n        fw = fh = 1\n    small = min(fw, fh)\n    if rotate != 0 and rotate != 180:\n        f = fw\n        fw = fh\n        fh = f\n    if fw < 1:\n        if trw / fw > trh / fh:\n            w = trh * small\n            h = trh\n        else:\n            w = trw\n            h = trw / small\n    elif fw != fh:\n        if trw / fw > trh / fh:\n            w = trh / small\n            h = trh\n        else:\n            w = trw\n            h = trw * small\n    else:\n        w = trw\n        h = trh\n    tmp = mupdf.fz_make_point(\n            (trect.x0 + trect.x1) / 2,\n            (trect.y0 + trect.y1) / 2,\n            )\n    mat = mupdf.fz_make_matrix(1, 0, 0, 1, -0.5, -0.5)\n    mat = mupdf.fz_concat(mat, rot)\n    mat = mupdf.fz_concat(mat, mupdf.fz_scale(w, h))\n    mat = mupdf.fz_concat(mat, mupdf.fz_translate(tmp.x, tmp.y))\n    return mat\n\n\ndef detect_super_script(line, ch):\n    if line.m_internal.wmode == 0 and line.m_internal.dir.x == 1 and line.m_internal.dir.y == 0:\n        return ch.m_internal.origin.y < line.m_internal.first_char.origin.y - ch.m_internal.size * 0.1\n    return 0\n\n\ndef dir_str(x):\n    ret = f'{x} {type(x)} ({len(dir(x))}):\\n'\n    for i in dir(x):\n        ret += f'    {i}\\n'\n    return ret\n\n\ndef getTJstr(text: str, glyphs: typing.Union[list, tuple, None], simple: bool, ordering: int) -> str:\n    \"\"\" Return a PDF string enclosed in [] brackets, suitable for the PDF TJ\n    operator.\n\n    Notes:\n        The input string is converted to either 2 or 4 hex digits per character.\n    Args:\n        simple: no glyphs: 2-chars, use char codes as the glyph\n                glyphs: 2-chars, use glyphs instead of char codes (Symbol,\n                ZapfDingbats)\n        not simple: ordering < 0: 4-chars, use glyphs not char codes\n                    ordering >=0: a CJK font! 4 chars, use char codes as glyphs\n    \"\"\"\n    if text.startswith(\"[<\") and text.endswith(\">]\"):  # already done\n        return text\n\n    if not bool(text):\n        return \"[<>]\"\n\n    if simple:  # each char or its glyph is coded as a 2-byte hex\n        if glyphs is None:  # not Symbol, not ZapfDingbats: use char code\n            otxt = \"\".join([f\"{ord(c):02x}\" if ord(c) < 256 else \"b7\" for c in text])\n        else:  # Symbol or ZapfDingbats: use glyphs\n            otxt = \"\".join(\n                [f\"{glyphs[ord(c)][0]:02x}\" if ord(c) < 256 else \"b7\" for c in text]\n            )\n        return \"[<\" + otxt + \">]\"\n\n    # non-simple fonts: each char or its glyph is coded as 4-byte hex\n    if ordering < 0:  # not a CJK font: use the glyphs\n        otxt = \"\".join([f\"{glyphs[ord(c)][0]:04x}\" for c in text])\n    else:  # CJK: use the char codes\n        otxt = \"\".join([f\"{ord(c):04x}\" for c in text])\n\n    return \"[<\" + otxt + \">]\"\n\n\ndef get_pdf_str(s: str) -> str:\n    \"\"\" Return a PDF string depending on its coding.\n\n    Notes:\n        Returns a string bracketed with either \"()\" or \"<>\" for hex values.\n        If only ascii then \"(original)\" is returned, else if only 8 bit chars\n        then \"(original)\" with interspersed octal strings \\nnn is returned,\n        else a string \"<FEFF[hexstring]>\" is returned, where [hexstring] is the\n        UTF-16BE encoding of the original.\n    \"\"\"\n    if not bool(s):\n        return \"()\"\n\n    def make_utf16be(s):\n        r = bytearray([254, 255]) + bytearray(s, \"UTF-16BE\")\n        return \"<\" + r.hex() + \">\"  # brackets indicate hex\n\n    # The following either returns the original string with mixed-in\n    # octal numbers \\nnn for chars outside the ASCII range, or returns\n    # the UTF-16BE BOM version of the string.\n    r = \"\"\n    for c in s:\n        oc = ord(c)\n        if oc > 255:  # shortcut if beyond 8-bit code range\n            return make_utf16be(s)\n\n        if oc > 31 and oc < 127:  # in ASCII range\n            if c in (\"(\", \")\", \"\\\\\"):  # these need to be escaped\n                r += \"\\\\\"\n            r += c\n            continue\n\n        if oc > 127:  # beyond ASCII\n            r += f\"\\\\{oc:03o}\"\n            continue\n\n        # now the white spaces\n        if oc == 8:  # backspace\n            r += \"\\\\b\"\n        elif oc == 9:  # tab\n            r += \"\\\\t\"\n        elif oc == 10:  # line feed\n            r += \"\\\\n\"\n        elif oc == 12:  # form feed\n            r += \"\\\\f\"\n        elif oc == 13:  # carriage return\n            r += \"\\\\r\"\n        else:\n            r += \"\\\\267\"  # unsupported: replace by 0xB7\n\n    return \"(\" + r + \")\"\n\n\ndef get_tessdata(tessdata=None):\n    \"\"\"Detect Tesseract language support folder.\n\n    This function is used to enable OCR via Tesseract even if the language\n    support folder is not specified directly or in environment variable\n    TESSDATA_PREFIX.\n\n    * If <tessdata> is set we return it directly.\n    \n    * Otherwise we return `os.environ['TESSDATA_PREFIX']` if set.\n    \n    * Otherwise we search for a Tesseract installation and return its language\n      support folder.\n\n    * Otherwise we raise an exception.\n    \"\"\"\n    if tessdata:\n        return tessdata\n    tessdata = os.getenv(\"TESSDATA_PREFIX\")\n    if tessdata:  # use environment variable if set\n        return tessdata\n\n    # Try to locate the tesseract-ocr installation.\n    \n    import subprocess\n    \n    cp = subprocess.run('tesseract --list-langs', shell=1, capture_output=1, check=0, text=True)\n    if cp.returncode == 0:\n        m = re.search('List of available languages in \"(.+)\"', cp.stdout)\n        if m:\n            tessdata = m.group(1)\n            return tessdata\n    \n    # Windows systems:\n    if sys.platform == \"win32\":\n        cp = subprocess.run(\"where tesseract\", shell=1, capture_output=1, check=0, text=True)\n        response = cp.stdout.strip()\n        if cp.returncode or not response:\n            raise RuntimeError(\"No tessdata specified and Tesseract is not installed\")\n        dirname = os.path.dirname(response)  # path of tesseract.exe\n        tessdata = os.path.join(dirname, \"tessdata\")  # language support\n        if os.path.exists(tessdata):  # all ok?\n            return tessdata\n        else:  # should not happen!\n            raise RuntimeError(f\"No tessdata specified and Tesseract installation has no {tessdata} folder\")\n\n    # Unix-like systems:\n    attempts = list()\n    for path in 'tesseract-ocr', 'tesseract':\n        cp = subprocess.run(f'whereis {path}', shell=1, capture_output=1, check=0, text=True)\n        if cp.returncode == 0:\n            response = cp.stdout.strip().split()\n            if len(response) == 2:\n                # search tessdata in folder structure\n                dirname = response[1]  # contains tesseract-ocr installation folder\n                pattern = f\"{dirname}/*/tessdata\"\n                attempts.append(pattern)\n                tessdatas = glob.glob(pattern)\n                tessdatas.sort()\n                if tessdatas:\n                    return tessdatas[-1]\n    if attempts:\n        text = 'No tessdata specified and no match for:\\n'\n        for attempt in attempts:\n            text += f'    {attempt}'\n        raise RuntimeError(text)\n    else:\n        raise RuntimeError('No tessdata specified and Tesseract is not installed')\n\n\ndef css_for_pymupdf_font(\n    fontcode: str, *, CSS: OptStr = None, archive: AnyType = None, name: OptStr = None\n) -> str:\n    \"\"\"Create @font-face items for the given fontcode of pymupdf-fonts.\n\n    Adds @font-face support for fonts contained in package pymupdf-fonts.\n\n    Creates a CSS font-family for all fonts starting with string 'fontcode'.\n\n    Note:\n        The font naming convention in package pymupdf-fonts is \"fontcode<sf>\",\n        where the suffix \"sf\" is either empty or one of \"it\", \"bo\" or \"bi\".\n        These suffixes thus represent the regular, italic, bold or bold-italic\n        variants of a font. For example, font code \"notos\" refers to fonts\n        \"notos\" - \"Noto Sans Regular\"\n        \"notosit\" - \"Noto Sans Italic\"\n        \"notosbo\" - \"Noto Sans Bold\"\n        \"notosbi\" - \"Noto Sans Bold Italic\"\n\n        This function creates four CSS @font-face definitions and collectively\n        assigns the font-family name \"notos\" to them (or the \"name\" value).\n\n    All fitting font buffers of the pymupdf-fonts package are placed / added\n    to the archive provided as parameter.\n    To use the font in pymupdf.Story, execute 'set_font(fontcode)'. The correct\n    font weight (bold) or style (italic) will automatically be selected.\n    Expects and returns the CSS source, with the new CSS definitions appended.\n\n    Args:\n        fontcode: (str) font code for naming the font variants to include.\n                  E.g. \"fig\" adds notos, notosi, notosb, notosbi fonts.\n                  A maximum of 4 font variants is accepted.\n        CSS: (str) CSS string to add @font-face definitions to.\n        archive: (Archive, mandatory) where to place the font buffers.\n        name: (str) use this as family-name instead of 'fontcode'.\n    Returns:\n        Modified CSS, with appended @font-face statements for each font variant\n        of fontcode.\n        Fontbuffers associated with \"fontcode\" will be added to 'archive'.\n    \"\"\"\n    # @font-face template string\n    CSSFONT = \"\\n@font-face {font-family: %s; src: url(%s);%s%s}\\n\"\n\n    if not type(archive) is Archive:\n        raise ValueError(\"'archive' must be an Archive\")\n    if CSS is None:\n        CSS = \"\"\n\n    # select font codes starting with the pass-in string\n    font_keys = [k for k in fitz_fontdescriptors.keys() if k.startswith(fontcode)]\n    if font_keys == []:\n        raise ValueError(f\"No font code '{fontcode}' found in pymupdf-fonts.\")\n    if len(font_keys) > 4:\n        raise ValueError(\"fontcode too short\")\n    if name is None:  # use this name for font-family\n        name = fontcode\n\n    for fkey in font_keys:\n        font = fitz_fontdescriptors[fkey]\n        bold = font[\"bold\"]  # determine font property\n        italic = font[\"italic\"]  # determine font property\n        fbuff = font[\"loader\"]()  # load the fontbuffer\n        archive.add(fbuff, fkey)  # update the archive\n        bold_text = \"font-weight: bold;\" if bold else \"\"\n        italic_text = \"font-style: italic;\" if italic else \"\"\n        CSS += CSSFONT % (name, fkey, bold_text, italic_text)\n    return CSS\n\n\ndef get_text_length(text: str, fontname: str =\"helv\", fontsize: float =11, encoding: int =0) -> float:\n    \"\"\"Calculate length of a string for a built-in font.\n\n    Args:\n        fontname: name of the font.\n        fontsize: font size points.\n        encoding: encoding to use, 0=Latin (default), 1=Greek, 2=Cyrillic.\n    Returns:\n        (float) length of text.\n    \"\"\"\n    fontname = fontname.lower()\n    basename = Base14_fontdict.get(fontname, None)\n\n    glyphs = None\n    if basename == \"Symbol\":\n        glyphs = symbol_glyphs\n    if basename == \"ZapfDingbats\":\n        glyphs = zapf_glyphs\n    if glyphs is not None:\n        w = sum([glyphs[ord(c)][1] if ord(c) < 256 else glyphs[183][1] for c in text])\n        return w * fontsize\n\n    if fontname in Base14_fontdict.keys():\n        return util_measure_string(\n            text, Base14_fontdict[fontname], fontsize, encoding\n        )\n\n    if fontname in (\n        \"china-t\",\n        \"china-s\",\n        \"china-ts\",\n        \"china-ss\",\n        \"japan\",\n        \"japan-s\",\n        \"korea\",\n        \"korea-s\",\n    ):\n        return len(text) * fontsize\n\n    raise ValueError(f\"Font '{fontname}' is unsupported\")\n\n\ndef image_profile(img: ByteString) -> dict:\n    \"\"\" Return basic properties of an image.\n\n    Args:\n        img: bytes, bytearray, io.BytesIO object or an opened image file.\n    Returns:\n        A dictionary with keys width, height, colorspace.n, bpc, type, ext and size,\n        where 'type' is the MuPDF image type (0 to 14) and 'ext' the suitable\n        file extension.\n    \"\"\"\n    if type(img) is io.BytesIO:\n        stream = img.getvalue()\n    elif hasattr(img, \"read\"):\n        stream = img.read()\n    elif type(img) in (bytes, bytearray):\n        stream = img\n    else:\n        raise ValueError(\"bad argument 'img'\")\n\n    return TOOLS.image_profile(stream)\n\n\ndef jm_append_merge(dev):\n    '''\n    Append current path to list or merge into last path of the list.\n    (1) Append if first path, different item lists or not a 'stroke' version\n        of previous path\n    (2) If new path has the same items, merge its content into previous path\n        and change path[\"type\"] to \"fs\".\n    (3) If \"out\" is callable, skip the previous and pass dictionary to it.\n    '''\n    #log(f'{getattr(dev, \"pathdict\", None)=}')\n    assert isinstance(dev.out, list)\n    #log( f'{dev.out=}')\n    \n    if callable(dev.method) or dev.method:  # function or method\n        # callback.\n        if dev.method is None:\n            # fixme, this surely cannot happen?\n            assert 0\n            #resp = PyObject_CallFunctionObjArgs(out, dev.pathdict, NULL)\n        else:\n            #log(f'calling {dev.out=} {dev.method=} {dev.pathdict=}')\n            resp = getattr(dev.out, dev.method)(dev.pathdict)\n        if not resp:\n            message(\"calling cdrawings callback function/method failed!\")\n        dev.pathdict = None\n        return\n    \n    def append():\n        #log(f'jm_append_merge(): clearing dev.pathdict')\n        dev.out.append(dev.pathdict.copy())\n        dev.pathdict.clear()\n    assert isinstance(dev.out, list)\n    len_ = len(dev.out) # len of output list so far\n    #log(f'{len_=}')\n    if len_ == 0:   # always append first path\n        return append()\n    #log(f'{getattr(dev, \"pathdict\", None)=}')\n    thistype = dev.pathdict[ dictkey_type]\n    #log(f'{thistype=}')\n    if thistype != 's': # if not stroke, then append\n        return append()\n    prev = dev.out[ len_-1] # get prev path\n    #log( f'{prev=}')\n    prevtype = prev[ dictkey_type]\n    #log( f'{prevtype=}')\n    if prevtype != 'f': # if previous not fill, append\n        return append()\n    # last check: there must be the same list of items for \"f\" and \"s\".\n    previtems = prev[ dictkey_items]\n    thisitems = dev.pathdict[ dictkey_items]\n    if previtems != thisitems:\n        return append()\n    \n    #rc = PyDict_Merge(prev, dev.pathdict, 0);  // merge with no override\n    try:\n        for k, v in dev.pathdict.items():\n            if k not in prev:\n                prev[k] = v\n        rc = 0\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        #raise\n        rc = -1\n    if rc == 0:\n        prev[ dictkey_type] = 'fs'\n        dev.pathdict.clear()\n    else:\n        message(\"could not merge stroke and fill path\")\n        append()\n\n\ndef jm_bbox_add_rect( dev, ctx, rect, code):\n    if not dev.layers:\n        dev.result.append( (code, JM_py_from_rect(rect)))\n    else:\n        dev.result.append( (code, JM_py_from_rect(rect), dev.layer_name))\n\n\ndef jm_bbox_fill_image( dev, ctx, image, ctm, alpha, color_params):\n    r = mupdf.FzRect(mupdf.FzRect.Fixed_UNIT)\n    r = mupdf.ll_fz_transform_rect( r.internal(), ctm)\n    jm_bbox_add_rect( dev, ctx, r, \"fill-image\")\n\n\ndef jm_bbox_fill_image_mask( dev, ctx, image, ctm, colorspace, color, alpha, color_params):\n    try:\n        jm_bbox_add_rect( dev, ctx, mupdf.ll_fz_transform_rect(mupdf.fz_unit_rect, ctm), \"fill-imgmask\")\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_bbox_fill_path( dev, ctx, path, even_odd, ctm, colorspace, color, alpha, color_params):\n    even_odd = True if even_odd else False\n    try:\n        jm_bbox_add_rect( dev, ctx, mupdf.ll_fz_bound_path(path, None, ctm), \"fill-path\")\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_bbox_fill_shade( dev, ctx, shade, ctm, alpha, color_params):\n    try:\n        jm_bbox_add_rect( dev, ctx, mupdf.ll_fz_bound_shade( shade, ctm), \"fill-shade\")\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_bbox_stroke_text( dev, ctx, text, stroke, ctm, *args):\n    try:\n        jm_bbox_add_rect( dev, ctx, mupdf.ll_fz_bound_text( text, stroke, ctm), \"stroke-text\")\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_bbox_fill_text( dev, ctx, text, ctm, *args):\n    try:\n        jm_bbox_add_rect( dev, ctx, mupdf.ll_fz_bound_text( text, None, ctm), \"fill-text\")\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_bbox_ignore_text( dev, ctx, text, ctm):\n    jm_bbox_add_rect( dev, ctx, mupdf.ll_fz_bound_text(text, None, ctm), \"ignore-text\")\n\n\ndef jm_bbox_stroke_path( dev, ctx, path, stroke, ctm, colorspace, color, alpha, color_params):\n    try:\n        jm_bbox_add_rect( dev, ctx, mupdf.ll_fz_bound_path( path, stroke, ctm), \"stroke-path\")\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_checkquad(dev):\n    '''\n    Check whether the last 4 lines represent a quad.\n    Because of how we count, the lines are a polyline already, i.e. last point\n    of a line equals 1st point of next line.\n    So we check for a polygon (last line's end point equals start point).\n    If not true we return 0.\n    '''\n    #log(f'{getattr(dev, \"pathdict\", None)=}')\n    items = dev.pathdict[ dictkey_items]\n    len_ = len(items)\n    f = [0] * 8 # coordinates of the 4 corners\n    # fill the 8 floats in f, start from items[-4:]\n    for i in range( 4): # store line start points\n        line = items[ len_ - 4 + i]\n        temp = JM_point_from_py( line[1])\n        f[i * 2] = temp.x\n        f[i * 2 + 1] = temp.y\n        lp = JM_point_from_py( line[ 2])\n    if lp.x != f[0] or lp.y != f[1]:\n        # not a polygon!\n        #dev.linecount -= 1\n        return 0\n    \n    # we have detected a quad\n    dev.linecount = 0   # reset this\n    # a quad item is (\"qu\", (ul, ur, ll, lr)), where the tuple items\n    # are pairs of floats representing a quad corner each.\n    \n    # relationship of float array to quad points:\n    # (0, 1) = ul, (2, 3) = ll, (6, 7) = ur, (4, 5) = lr\n    q = mupdf.fz_make_quad(f[0], f[1], f[6], f[7], f[2], f[3], f[4], f[5])\n    rect = ('qu', JM_py_from_quad(q))\n    \n    items[ len_ - 4] = rect  # replace item -4 by rect\n    del items[ len_ - 3 : len_]  # delete remaining 3 items\n    return 1\n\n\ndef jm_checkrect(dev):\n    '''\n    Check whether the last 3 path items represent a rectangle.\n    Returns 1 if we have modified the path, otherwise 0.\n    '''\n    #log(f'{getattr(dev, \"pathdict\", None)=}')\n    dev.linecount = 0   # reset line count\n    orientation = 0 # area orientation of rectangle\n    items = dev.pathdict[ dictkey_items]\n    len_ = len(items)\n\n    line0 = items[ len_ - 3]\n    ll = JM_point_from_py( line0[ 1])\n    lr = JM_point_from_py( line0[ 2])\n\n    # no need to extract \"line1\"!\n    line2 = items[ len_ - 1]\n    ur = JM_point_from_py( line2[ 1])\n    ul = JM_point_from_py( line2[ 2])\n\n    # Assumption:\n    # When decomposing rects, MuPDF always starts with a horizontal line,\n    # followed by a vertical line, followed by a horizontal line.\n    # First line: (ll, lr), third line: (ul, ur).\n    # If 1st line is below 3rd line, we record anti-clockwise (+1), else\n    # clockwise (-1) orientation.\n    \n    if (0\n            or ll.y != lr.y\n            or ll.x != ul.x\n            or ur.y != ul.y\n            or ur.x != lr.x\n            ):\n        return 0 # not a rectangle\n    \n    # we have a rect, replace last 3 \"l\" items by one \"re\" item.\n    if ul.y < lr.y:\n        r = mupdf.fz_make_rect(ul.x, ul.y, lr.x, lr.y)\n        orientation = 1\n    else:\n        r = mupdf.fz_make_rect(ll.x, ll.y, ur.x, ur.y)\n        orientation = -1\n    \n    rect = ( 're', JM_py_from_rect(r), orientation)\n    items[ len_ - 3] = rect # replace item -3 by rect\n    del items[ len_ - 2 : len_] # delete remaining 2 items\n    return 1\n\n\ndef jm_trace_text( dev, text, type_, ctm, colorspace, color, alpha, seqno):\n    span = text.head\n    while 1:\n        if not span:\n            break\n        jm_trace_text_span( dev, span, type_, ctm, colorspace, color, alpha, seqno)\n        span = span.next\n\n\ndef jm_trace_text_span(dev, span, type_, ctm, colorspace, color, alpha, seqno):\n    '''\n    jm_trace_text_span(fz_context *ctx, PyObject *out, fz_text_span *span, int type, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, size_t seqno)\n    '''\n    out_font = None\n    assert isinstance( span, mupdf.fz_text_span)\n    span = mupdf.FzTextSpan( span)\n    assert isinstance( ctm, mupdf.fz_matrix)\n    ctm = mupdf.FzMatrix( ctm)\n    fontname = JM_font_name( span.font())\n    #float rgb[3];\n    #PyObject *chars = PyTuple_New(span->len);\n    \n    mat = mupdf.fz_concat(span.trm(), ctm)  # text transformation matrix\n    dir = mupdf.fz_transform_vector(mupdf.fz_make_point(1, 0), mat) # writing direction\n    fsize = math.sqrt(dir.x * dir.x + dir.y * dir.y)  # font size\n\n    dir = mupdf.fz_normalize_vector(dir)\n\n    space_adv = 0\n    asc = JM_font_ascender( span.font())\n    dsc = JM_font_descender( span.font())\n    if asc < 1e-3:  # probably Tesseract font\n        dsc = -0.1\n        asc = 0.9\n\n    # compute effective ascender / descender\n    ascsize = asc * fsize / (asc - dsc)\n    dscsize = dsc * fsize / (asc - dsc)\n    fflags = 0  # font flags\n    mono = mupdf.fz_font_is_monospaced( span.font())\n    fflags += mono * TEXT_FONT_MONOSPACED\n    fflags += mupdf.fz_font_is_italic( span.font()) * TEXT_FONT_ITALIC\n    fflags += mupdf.fz_font_is_serif( span.font()) * TEXT_FONT_SERIFED\n    fflags += mupdf.fz_font_is_bold( span.font()) * TEXT_FONT_BOLD\n\n    last_adv = 0\n\n    # walk through characters of span\n    span_bbox = mupdf.FzRect()\n    rot = mupdf.fz_make_matrix(dir.x, dir.y, -dir.y, dir.x, 0, 0)\n    if dir.x == -1: # left-right flip\n        rot.d = 1\n\n    chars = []\n    for i in range( span.m_internal.len):\n        adv = 0\n        if span.items(i).gid >= 0:\n            adv = mupdf.fz_advance_glyph( span.font(), span.items(i).gid, span.m_internal.wmode)\n        adv *= fsize\n        last_adv = adv\n        if span.items(i).ucs == 32:\n            space_adv = adv\n        char_orig = mupdf.fz_make_point(span.items(i).x, span.items(i).y)\n        char_orig = mupdf.fz_transform_point(char_orig, ctm)\n        m1 = mupdf.fz_make_matrix(1, 0, 0, 1, -char_orig.x, -char_orig.y)\n        m1 = mupdf.fz_concat(m1, rot)\n        m1 = mupdf.fz_concat(m1, mupdf.FzMatrix(1, 0, 0, 1, char_orig.x, char_orig.y))\n        x0 = char_orig.x\n        x1 = x0 + adv\n        if (\n                (mat.d > 0 and (dir.x == 1 or dir.x == -1))\n                or\n                (mat.b != 0 and mat.b == -mat.c)\n                ):  # up-down flip\n            y0 = char_orig.y + dscsize\n            y1 = char_orig.y + ascsize\n        else:\n            y0 = char_orig.y - ascsize\n            y1 = char_orig.y - dscsize\n        char_bbox = mupdf.fz_make_rect(x0, y0, x1, y1)\n        char_bbox = mupdf.fz_transform_rect(char_bbox, m1)\n        chars.append(\n                (\n                    span.items(i).ucs,\n                    span.items(i).gid,\n                    (\n                        char_orig.x,\n                        char_orig.y,\n                    ),\n                    (\n                        char_bbox.x0,\n                        char_bbox.y0,\n                        char_bbox.x1,\n                        char_bbox.y1,\n                    ),\n                )\n                )\n        if i > 0:\n            span_bbox = mupdf.fz_union_rect(span_bbox, char_bbox)\n        else:\n            span_bbox = char_bbox\n    chars = tuple(chars)\n    \n    if not space_adv:\n        if not (fflags & TEXT_FONT_MONOSPACED):\n            c, out_font = mupdf.fz_encode_character_with_fallback( span.font(), 32, 0, 0)\n            space_adv = mupdf.fz_advance_glyph(\n                    span.font(),\n                    c,\n                    span.m_internal.wmode,\n                    )\n            space_adv *= fsize\n            if not space_adv:\n                space_adv = last_adv\n        else:\n            space_adv = last_adv    # for mono, any char width suffices\n\n    # make the span dictionary\n    span_dict = dict()\n    span_dict[ 'dir'] = JM_py_from_point(dir)\n    span_dict[ 'font'] = JM_EscapeStrFromStr(fontname)\n    span_dict[ 'wmode'] = span.m_internal.wmode\n    span_dict[ 'flags'] =fflags\n    span_dict[ \"bidi_lvl\"] =span.m_internal.bidi_level\n    span_dict[ \"bidi_dir\"] = span.m_internal.markup_dir\n    span_dict[ 'ascender'] = asc\n    span_dict[ 'descender'] = dsc\n    span_dict[ 'colorspace'] = 3\n    \n    if colorspace:\n        rgb = mupdf.fz_convert_color(\n                mupdf.FzColorspace( mupdf.ll_fz_keep_colorspace( colorspace)),\n                color,\n                mupdf.fz_device_rgb(),\n                mupdf.FzColorspace(),\n                mupdf.FzColorParams(),\n                )\n        rgb = rgb[:3]   # mupdf.fz_convert_color() always returns 4 items.\n    else:\n        rgb = (0, 0, 0)\n    \n    if dev.linewidth > 0:   # width of character border\n        linewidth = dev.linewidth\n    else:\n        linewidth = fsize * 0.05    # default: 5% of font size\n    #log(f'{dev.linewidth=:.4f} {fsize=:.4f} {linewidth=:.4f}')\n    \n    span_dict[ 'color'] = rgb\n    span_dict[ 'size'] = fsize\n    span_dict[ \"opacity\"] = alpha\n    span_dict[ \"linewidth\"] = linewidth\n    span_dict[ \"spacewidth\"] = space_adv\n    span_dict[ 'type'] = type_\n    span_dict[ 'bbox'] = JM_py_from_rect(span_bbox)\n    span_dict[ 'layer'] = dev.layer_name\n    span_dict[ \"seqno\"] = seqno\n    span_dict[ 'chars'] = chars\n    #log(f'{span_dict=}')\n    dev.out.append( span_dict)\n\n\ndef jm_lineart_color(colorspace, color):\n    #log(f' ')\n    if colorspace:\n        try:\n            # Need to be careful to use a named Python object to ensure\n            # that the `params` we pass to mupdf.ll_fz_convert_color() is\n            # valid. E.g. doing:\n            #\n            #   rgb = mupdf.ll_fz_convert_color(..., mupdf.FzColorParams().internal())\n            #\n            # - seems to end up with a corrupted `params`.\n            #\n            cs = mupdf.FzColorspace( mupdf.FzColorspace.Fixed_RGB)\n            cp = mupdf.FzColorParams()\n            rgb = mupdf.ll_fz_convert_color(\n                    colorspace,\n                    color,\n                    cs.m_internal,\n                    None,\n                    cp.internal(),\n                    )\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            raise\n        return rgb[:3]\n    return ()\n\n\ndef jm_lineart_drop_device(dev, ctx):\n    if isinstance(dev.out, list):\n        dev.out = []\n    dev.scissors = []\n \n \ndef jm_lineart_fill_path( dev, ctx, path, even_odd, ctm, colorspace, color, alpha, color_params):\n    #log(f'{getattr(dev, \"pathdict\", None)=}')\n    #log(f'jm_lineart_fill_path(): {dev.seqno=}')\n    even_odd = True if even_odd else False\n    try:\n        assert isinstance( ctm, mupdf.fz_matrix)\n        dev.ctm = mupdf.FzMatrix( ctm)  # fz_concat(ctm, dev_ptm);\n        dev.path_type = trace_device_FILL_PATH\n        jm_lineart_path( dev, ctx, path)\n        if dev.pathdict is None:\n            return\n        #item_count = len(dev.pathdict[ dictkey_items])\n        #if item_count == 0:\n        #    return\n        dev.pathdict[ dictkey_type] =\"f\"\n        dev.pathdict[ \"even_odd\"] = even_odd\n        dev.pathdict[ \"fill_opacity\"] = alpha\n        #log(f'setting dev.pathdict[ \"closePath\"] to false')\n        #dev.pathdict[ \"closePath\"] = False\n        dev.pathdict[ \"fill\"] = jm_lineart_color( colorspace, color)\n        dev.pathdict[ dictkey_rect] = JM_py_from_rect(dev.pathrect)\n        dev.pathdict[ \"seqno\"] = dev.seqno\n        #jm_append_merge(dev)\n        dev.pathdict[ 'layer'] = dev.layer_name\n        if dev.clips:\n            dev.pathdict[ 'level'] = dev.depth\n        jm_append_merge(dev)\n        dev.seqno += 1\n        #log(f'jm_lineart_fill_path() end: {getattr(dev, \"pathdict\", None)=}')\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\n# There are 3 text trace types:\n# 0 - fill text (PDF Tr 0)\n# 1 - stroke text (PDF Tr 1)\n# 3 - ignore text (PDF Tr 3)\n\ndef jm_lineart_fill_text( dev, ctx, text, ctm, colorspace, color, alpha, color_params):\n    if 0:\n        log(f'{type(ctx)=} {ctx=}')\n        log(f'{type(dev)=} {dev=}')\n        log(f'{type(text)=} {text=}')\n        log(f'{type(ctm)=} {ctm=}')\n        log(f'{type(colorspace)=} {colorspace=}')\n        log(f'{type(color)=} {color=}')\n        log(f'{type(alpha)=} {alpha=}')\n        log(f'{type(color_params)=} {color_params=}')\n    jm_trace_text(dev, text, 0, ctm, colorspace, color, alpha, dev.seqno)\n    dev.seqno += 1\n\n\ndef jm_lineart_ignore_text(dev, text, ctm):\n    #log(f'{getattr(dev, \"pathdict\", None)=}')\n    jm_trace_text(dev, text, 3, ctm, None, None, 1, dev.seqno)\n    dev.seqno += 1\n\n\nclass Walker(mupdf.FzPathWalker2):\n\n    def __init__(self, dev):\n        super().__init__()\n        self.use_virtual_moveto()\n        self.use_virtual_lineto()\n        self.use_virtual_curveto()\n        self.use_virtual_closepath()\n        self.dev = dev\n\n    def closepath(self, ctx):    # trace_close().\n        #log(f'Walker(): {self.dev.pathdict=}')\n        try:\n            if self.dev.linecount == 3:\n                if jm_checkrect(self.dev):\n                    #log(f'end1: {self.dev.pathdict=}')\n                    return\n            self.dev.linecount = 0   # reset # of consec. lines\n\n            if self.dev.havemove:\n                if self.dev.lastpoint != self.dev.firstpoint:\n                    item = (\"l\", JM_py_from_point(self.dev.lastpoint),\n                                 JM_py_from_point(self.dev.firstpoint))\n                    self.dev.pathdict[dictkey_items].append(item)\n                    self.dev.lastpoint = self.dev.firstpoint\n                self.dev.pathdict[\"closePath\"] = False\n\n            else:\n                #log('setting self.dev.pathdict[ \"closePath\"] to true')\n                self.dev.pathdict[ \"closePath\"] = True\n                #log(f'end2: {self.dev.pathdict=}')\n\n            self.dev.havemove = 0\n\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            raise\n\n    def curveto(self, ctx, x1, y1, x2, y2, x3, y3):   # trace_curveto().\n        #log(f'Walker(): {self.dev.pathdict=}')\n        try:\n            self.dev.linecount = 0  # reset # of consec. lines\n            p1 = mupdf.fz_make_point(x1, y1)\n            p2 = mupdf.fz_make_point(x2, y2)\n            p3 = mupdf.fz_make_point(x3, y3)\n            p1 = mupdf.fz_transform_point(p1, self.dev.ctm)\n            p2 = mupdf.fz_transform_point(p2, self.dev.ctm)\n            p3 = mupdf.fz_transform_point(p3, self.dev.ctm)\n            self.dev.pathrect = mupdf.fz_include_point_in_rect(self.dev.pathrect, p1)\n            self.dev.pathrect = mupdf.fz_include_point_in_rect(self.dev.pathrect, p2)\n            self.dev.pathrect = mupdf.fz_include_point_in_rect(self.dev.pathrect, p3)\n\n            list_ = (\n                    \"c\",\n                    JM_py_from_point(self.dev.lastpoint),\n                    JM_py_from_point(p1),\n                    JM_py_from_point(p2),\n                    JM_py_from_point(p3),\n                    )\n            self.dev.lastpoint = p3\n            self.dev.pathdict[ dictkey_items].append( list_)\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            raise\n\n    def lineto(self, ctx, x, y):   # trace_lineto().\n        #log(f'Walker(): {self.dev.pathdict=}')\n        try:\n            p1 = mupdf.fz_transform_point( mupdf.fz_make_point(x, y), self.dev.ctm)\n            self.dev.pathrect = mupdf.fz_include_point_in_rect( self.dev.pathrect, p1)\n            list_ = (\n                    'l',\n                    JM_py_from_point( self.dev.lastpoint),\n                    JM_py_from_point(p1),\n                    )\n            self.dev.lastpoint = p1\n            items = self.dev.pathdict[ dictkey_items]\n            items.append( list_)\n            self.dev.linecount += 1 # counts consecutive lines\n            if self.dev.linecount == 4 and self.dev.path_type != trace_device_FILL_PATH:\n                # shrink to \"re\" or \"qu\" item\n                jm_checkquad(self.dev)\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            raise\n\n    def moveto(self, ctx, x, y):   # trace_moveto().\n        if 0 and isinstance(self.dev.pathdict, dict):\n            log(f'self.dev.pathdict:')\n            for n, v in self.dev.pathdict.items():\n                log(f'    {type(n)=} {len(n)=} {n!r} {n}: {v!r}: {v}')\n\n        #log(f'Walker(): {type(self.dev.pathdict)=} {self.dev.pathdict=}')\n\n        try:\n            #log(f'{dev.ctm type(dev.ctm)=}')\n            self.dev.lastpoint = mupdf.fz_transform_point(\n                    mupdf.fz_make_point(x, y),\n                    self.dev.ctm,\n                    )\n            if mupdf.fz_is_infinite_rect( self.dev.pathrect):\n                self.dev.pathrect = mupdf.fz_make_rect(\n                        self.dev.lastpoint.x,\n                        self.dev.lastpoint.y,\n                        self.dev.lastpoint.x,\n                        self.dev.lastpoint.y,\n                        )\n            self.dev.firstpoint = self.dev.lastpoint\n            self.dev.havemove = 1\n            self.dev.linecount = 0  # reset # of consec. lines\n        except Exception:\n            if g_exceptions_verbose:    exception_info()\n            raise\n\n\ndef jm_lineart_path(dev, ctx, path):\n    '''\n    Create the \"items\" list of the path dictionary\n    * either create or empty the path dictionary\n    * reset the end point of the path\n    * reset count of consecutive lines\n    * invoke fz_walk_path(), which create the single items\n    * if no items detected, empty path dict again\n    '''\n    #log(f'{getattr(dev, \"pathdict\", None)=}')\n    try:\n        dev.pathrect = mupdf.FzRect( mupdf.FzRect.Fixed_INFINITE)\n        dev.linecount = 0\n        dev.lastpoint = mupdf.FzPoint( 0, 0)\n        dev.pathdict = dict()\n        dev.pathdict[ dictkey_items] = []\n        \n        # First time we create a Walker instance is slow, e.g. 0.3s, then later\n        # times run in around 0.01ms. If Walker is defined locally instead of\n        # globally, each time takes 0.3s.\n        #\n        walker = Walker(dev)\n        # Unlike fz_run_page(), fz_path_walker callbacks are not passed\n        # a pointer to the struct, instead they get an arbitrary\n        # void*. The underlying C++ Director callbacks use this void* to\n        # identify the fz_path_walker instance so in turn we need to pass\n        # arg=walker.m_internal.\n        mupdf.fz_walk_path( mupdf.FzPath(mupdf.ll_fz_keep_path(path)), walker, walker.m_internal)\n        # Check if any items were added ...\n        if not dev.pathdict[ dictkey_items]:\n            dev.pathdict = None\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_lineart_stroke_path( dev, ctx, path, stroke, ctm, colorspace, color, alpha, color_params):\n    #log(f'{dev.pathdict=} {dev.clips=}')\n    try:\n        assert isinstance( ctm, mupdf.fz_matrix)\n        dev.pathfactor = math.sqrt(abs(ctm.a * ctm.d - ctm.b * ctm.c))\n        dev.ctm = mupdf.FzMatrix( ctm)  # fz_concat(ctm, dev_ptm);\n        dev.path_type = trace_device_STROKE_PATH\n\n        jm_lineart_path( dev, ctx, path)\n        if dev.pathdict is None:\n            return\n        dev.pathdict[ dictkey_type] = 's'\n        dev.pathdict[ 'stroke_opacity'] = alpha\n        dev.pathdict[ 'color'] = jm_lineart_color( colorspace, color)\n        dev.pathdict[ dictkey_width] = dev.pathfactor * stroke.linewidth\n        dev.pathdict[ 'lineCap'] = (\n                stroke.start_cap,\n                stroke.dash_cap,\n                stroke.end_cap,\n                )\n        dev.pathdict[ 'lineJoin'] = float(stroke.linejoin)\n        if 'closePath' not in dev.pathdict:\n            #log('setting dev.pathdict[\"closePath\"] to false')\n            dev.pathdict['closePath'] = False\n\n        # output the \"dashes\" string\n        if stroke.dash_len:\n            buff = mupdf.fz_new_buffer( 256)\n            mupdf.fz_append_string( buff, \"[ \") # left bracket\n            for i in range( stroke.dash_len):\n                # We use mupdf python's SWIG-generated floats_getitem() fn to\n                # access float *stroke.dash_list[].\n                value = mupdf.floats_getitem( stroke.dash_list, i)  # stroke.dash_list[i].\n                mupdf.fz_append_string( buff, f'{_format_g(dev.pathfactor * value)} ')\n            mupdf.fz_append_string( buff, f'] {_format_g(dev.pathfactor * stroke.dash_phase)}')\n            dev.pathdict[ 'dashes'] = buff\n        else:\n            dev.pathdict[ 'dashes'] = '[] 0'\n        dev.pathdict[ dictkey_rect] = JM_py_from_rect(dev.pathrect)\n        dev.pathdict['layer'] = dev.layer_name\n        dev.pathdict[ 'seqno'] = dev.seqno\n        if dev.clips:\n            dev.pathdict[ 'level'] = dev.depth\n        jm_append_merge(dev)\n        dev.seqno += 1\n    \n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef jm_lineart_clip_path(dev, ctx, path, even_odd, ctm, scissor):\n    if not dev.clips:\n        return\n    dev.ctm = mupdf.FzMatrix(ctm)    # fz_concat(ctm, trace_device_ptm);\n    dev.path_type = trace_device_CLIP_PATH\n    jm_lineart_path(dev, ctx, path)\n    if dev.pathdict is None:\n        return\n    dev.pathdict[ dictkey_type] = 'clip'\n    dev.pathdict[ 'even_odd'] = bool(even_odd)\n    if 'closePath' not in dev.pathdict:\n        #log(f'setting dev.pathdict[\"closePath\"] to False')\n        dev.pathdict['closePath'] = False\n   \n    dev.pathdict['scissor'] = JM_py_from_rect(compute_scissor(dev))\n    dev.pathdict['level'] = dev.depth\n    dev.pathdict['layer'] = dev.layer_name\n    jm_append_merge(dev)\n    dev.depth += 1\n\n\ndef jm_lineart_clip_stroke_path(dev, ctx, path, stroke, ctm, scissor):\n    if not dev.clips:\n        return\n    dev.ctm = mupdf.FzMatrix(ctm)    # fz_concat(ctm, trace_device_ptm);\n    dev.path_type = trace_device_CLIP_STROKE_PATH\n    jm_lineart_path(dev, ctx, path)\n    if dev.pathdict is None:\n        return\n    dev.pathdict['dictkey_type'] = 'clip'\n    dev.pathdict['even_odd'] = None\n    if 'closePath' not in dev.pathdict:\n        #log(f'setting dev.pathdict[\"closePath\"] to False')\n        dev.pathdict['closePath'] = False\n    dev.pathdict['scissor'] = JM_py_from_rect(compute_scissor(dev))\n    dev.pathdict['level'] = dev.depth\n    dev.pathdict['layer'] = dev.layer_name\n    jm_append_merge(dev)\n    dev.depth += 1\n\n\ndef jm_lineart_clip_stroke_text(dev, ctx, text, stroke, ctm, scissor):\n    if not dev.clips:\n        return\n    compute_scissor(dev)\n    dev.depth += 1\n\n\ndef jm_lineart_clip_text(dev, ctx, text, ctm, scissor):\n    if not dev.clips:\n        return\n    compute_scissor(dev)\n    dev.depth += 1\n\n\ndef jm_lineart_clip_image_mask( dev, ctx, image, ctm, scissor):\n    if not dev.clips:\n        return\n    compute_scissor(dev)\n    dev.depth += 1\n \n\ndef jm_lineart_pop_clip(dev, ctx):\n    if not dev.clips or not dev.scissors:\n        return\n    len_ = len(dev.scissors)\n    if len_ < 1:\n        return\n    del dev.scissors[-1]\n    dev.depth -= 1\n\n\ndef jm_lineart_begin_layer(dev, ctx, name):\n    if name:\n        dev.layer_name = name\n    else:\n        dev.layer_name = \"\"\n\n\ndef jm_lineart_end_layer(dev, ctx):\n    dev.layer_name = \"\"\n\n\ndef jm_lineart_begin_group(dev, ctx, bbox, cs, isolated, knockout, blendmode, alpha):\n    #log(f'{dev.pathdict=} {dev.clips=}')\n    if not dev.clips:\n        return\n    dev.pathdict = { # Py_BuildValue(\"{s:s,s:N,s:N,s:N,s:s,s:f,s:i,s:N}\",\n            \"type\": \"group\",\n            \"rect\": JM_py_from_rect(bbox),\n            \"isolated\": bool(isolated),\n            \"knockout\": bool(knockout),\n            \"blendmode\": mupdf.fz_blendmode_name(blendmode),\n            \"opacity\": alpha,\n            \"level\": dev.depth,\n            \"layer\": dev.layer_name\n            }\n    jm_append_merge(dev)\n    dev.depth += 1\n\n\ndef jm_lineart_end_group(dev, ctx):\n    #log(f'{dev.pathdict=} {dev.clips=}')\n    if not dev.clips:\n        return\n    dev.depth -= 1\n\n\ndef jm_lineart_stroke_text(dev, ctx, text, stroke, ctm, colorspace, color, alpha, color_params):\n    jm_trace_text(dev, text, 1, ctm, colorspace, color, alpha, dev.seqno)\n    dev.seqno += 1\n\n\ndef jm_dev_linewidth( dev, ctx, path, stroke, matrix, colorspace, color, alpha, color_params):\n    dev.linewidth = stroke.linewidth\n    jm_increase_seqno( dev, ctx)\n\n\ndef jm_increase_seqno( dev, ctx, *vargs):\n    try:\n        dev.seqno += 1\n    except Exception:\n        if g_exceptions_verbose:    exception_info()\n        raise\n\n\ndef planish_line(p1: point_like, p2: point_like) -> Matrix:\n    \"\"\"Compute matrix which maps line from p1 to p2 to the x-axis, such that it\n    maintains its length and p1 * matrix = Point(0, 0).\n\n    Args:\n        p1, p2: point_like\n    Returns:\n        Matrix which maps p1 to Point(0, 0) and p2 to a point on the x axis at\n        the same distance to Point(0,0). Will always combine a rotation and a\n        transformation.\n    \"\"\"\n    p1 = Point(p1)\n    p2 = Point(p2)\n    return Matrix(util_hor_matrix(p1, p2))\n\n\nclass JM_image_reporter_Filter(mupdf.PdfFilterOptions2):\n    def __init__(self):\n        super().__init__()\n        self.use_virtual_image_filter()\n\n    def image_filter( self, ctx, ctm, name, image):\n        assert isinstance(ctm, mupdf.fz_matrix)\n        JM_image_filter(self, mupdf.FzMatrix(ctm), name, image)\n        if mupdf_cppyy:\n            # cppyy doesn't appear to treat returned None as nullptr,\n            # resulting in obscure 'python exception' exception.\n            return 0\n\n\nclass JM_new_bbox_device_Device(mupdf.FzDevice2):\n    def __init__(self, result, layers):\n        super().__init__()\n        self.result = result\n        self.layers = layers\n        self.layer_name = \"\"\n        self.use_virtual_fill_path()\n        self.use_virtual_stroke_path()\n        self.use_virtual_fill_text()\n        self.use_virtual_stroke_text()\n        self.use_virtual_ignore_text()\n        self.use_virtual_fill_shade()\n        self.use_virtual_fill_image()\n        self.use_virtual_fill_image_mask()\n        \n        self.use_virtual_begin_layer()\n        self.use_virtual_end_layer()\n\n    begin_layer = jm_lineart_begin_layer\n    end_layer = jm_lineart_end_layer\n    \n    fill_path = jm_bbox_fill_path\n    stroke_path = jm_bbox_stroke_path\n    fill_text = jm_bbox_fill_text\n    stroke_text = jm_bbox_stroke_text\n    ignore_text = jm_bbox_ignore_text\n    fill_shade = jm_bbox_fill_shade\n    fill_image = jm_bbox_fill_image\n    fill_image_mask = jm_bbox_fill_image_mask\n    \n\nclass JM_new_output_fileptr_Output(mupdf.FzOutput2):\n    def __init__(self, bio):\n        super().__init__()\n        self.bio = bio\n        self.use_virtual_write()\n        self.use_virtual_seek()\n        self.use_virtual_tell()\n        self.use_virtual_truncate()\n    \n    def seek( self, ctx, offset, whence):\n        return self.bio.seek( offset, whence)\n    \n    def tell( self, ctx):\n        ret = self.bio.tell()\n        return ret\n    \n    def truncate( self, ctx):\n        return self.bio.truncate()\n    \n    def write(self, ctx, data_raw, data_length):\n        data = mupdf.raw_to_python_bytes(data_raw, data_length)\n        return self.bio.write(data)\n\n\ndef compute_scissor(dev):\n    '''\n    Every scissor of a clip is a sub rectangle of the preceding clip scissor\n    if the clip level is larger.\n    '''\n    if dev.scissors is None:\n        dev.scissors = list()\n    num_scissors = len(dev.scissors)\n    if num_scissors > 0:\n        last_scissor = dev.scissors[num_scissors-1]\n        scissor = JM_rect_from_py(last_scissor)\n        scissor = mupdf.fz_intersect_rect(scissor, dev.pathrect)\n    else:\n        scissor = dev.pathrect\n    dev.scissors.append(JM_py_from_rect(scissor))\n    return scissor\n\n\nclass JM_new_lineart_device_Device(mupdf.FzDevice2):\n    '''\n    LINEART device for Python method Page.get_cdrawings()\n    '''\n    #log(f'JM_new_lineart_device_Device()')\n    def __init__(self, out, clips, method):\n        #log(f'JM_new_lineart_device_Device.__init__()')\n        super().__init__()\n        # fixme: this results in \"Unexpected call of unimplemented virtual_fnptrs fn FzDevice2::drop_device().\".\n        #self.use_virtual_drop_device()\n        self.use_virtual_fill_path()\n        self.use_virtual_stroke_path()\n        self.use_virtual_clip_path()\n        self.use_virtual_clip_image_mask()\n        self.use_virtual_clip_stroke_path()\n        self.use_virtual_clip_stroke_text()\n        self.use_virtual_clip_text()\n        \n        self.use_virtual_fill_text\n        self.use_virtual_stroke_text\n        self.use_virtual_ignore_text\n        \n        self.use_virtual_fill_shade()\n        self.use_virtual_fill_image()\n        self.use_virtual_fill_image_mask()\n        \n        self.use_virtual_pop_clip()\n        \n        self.use_virtual_begin_group()\n        self.use_virtual_end_group()\n        \n        self.use_virtual_begin_layer()\n        self.use_virtual_end_layer()\n        \n        self.out = out\n        self.seqno = 0\n        self.depth = 0\n        self.clips = clips\n        self.method = method\n        \n        self.scissors = None\n        self.layer_name = \"\"  # optional content name\n        self.pathrect = None\n        \n        self.linewidth = 0\n        self.ptm = mupdf.FzMatrix()\n        self.ctm = mupdf.FzMatrix()\n        self.rot = mupdf.FzMatrix()\n        self.lastpoint = mupdf.FzPoint()\n        self.firstpoint = mupdf.FzPoint()\n        self.havemove = 0\n        self.pathrect = mupdf.FzRect()\n        self.pathfactor = 0\n        self.linecount = 0\n        self.path_type = 0\n    \n    #drop_device = jm_lineart_drop_device\n    \n    fill_path           = jm_lineart_fill_path\n    stroke_path         = jm_lineart_stroke_path\n    clip_image_mask     = jm_lineart_clip_image_mask\n    clip_path           = jm_lineart_clip_path\n    clip_stroke_path    = jm_lineart_clip_stroke_path\n    clip_text           = jm_lineart_clip_text\n    clip_stroke_text    = jm_lineart_clip_stroke_text\n    \n    fill_text           = jm_increase_seqno\n    stroke_text         = jm_increase_seqno\n    ignore_text         = jm_increase_seqno\n    \n    fill_shade          = jm_increase_seqno\n    fill_image          = jm_increase_seqno\n    fill_image_mask     = jm_increase_seqno\n    \n    pop_clip            = jm_lineart_pop_clip\n    \n    begin_group         = jm_lineart_begin_group\n    end_group           = jm_lineart_end_group\n    \n    begin_layer         = jm_lineart_begin_layer\n    end_layer           = jm_lineart_end_layer\n    \n\nclass JM_new_texttrace_device(mupdf.FzDevice2):\n    '''\n    Trace TEXT device for Python method Page.get_texttrace()\n    '''\n\n    def __init__(self, out):\n        super().__init__()\n        self.use_virtual_fill_path()\n        self.use_virtual_stroke_path()\n        self.use_virtual_fill_text()\n        self.use_virtual_stroke_text()\n        self.use_virtual_ignore_text()\n        self.use_virtual_fill_shade()\n        self.use_virtual_fill_image()\n        self.use_virtual_fill_image_mask()\n        \n        self.use_virtual_begin_layer()\n        self.use_virtual_end_layer()\n        \n        self.out = out\n        \n        self.seqno = 0\n        self.depth = 0\n        self.clips = 0\n        self.method = None\n        \n        self.seqno = 0\n\n        self.pathdict = dict()\n        self.scissors = list()\n        self.linewidth = 0\n        self.ptm = mupdf.FzMatrix()\n        self.ctm = mupdf.FzMatrix()\n        self.rot = mupdf.FzMatrix()\n        self.lastpoint = mupdf.FzPoint()\n        self.pathrect = mupdf.FzRect()\n        self.pathfactor = 0\n        self.linecount = 0\n        self.path_type = 0\n        self.layer_name = \"\"\n    \n    fill_path = jm_increase_seqno\n    stroke_path = jm_dev_linewidth\n    fill_text = jm_lineart_fill_text\n    stroke_text = jm_lineart_stroke_text\n    ignore_text = jm_lineart_ignore_text\n    fill_shade = jm_increase_seqno\n    fill_image = jm_increase_seqno\n    fill_image_mask = jm_increase_seqno\n    \n    begin_layer = jm_lineart_begin_layer\n    end_layer = jm_lineart_end_layer\n\n\ndef ConversionHeader(i: str, filename: OptStr =\"unknown\"):\n    t = i.lower()\n    import textwrap\n    html = textwrap.dedent(\"\"\"\n            <!DOCTYPE html>\n            <html>\n            <head>\n            <style>\n            body{background-color:gray}\n            div{position:relative;background-color:white;margin:1em auto}\n            p{position:absolute;margin:0}\n            img{position:absolute}\n            </style>\n            </head>\n            <body>\n            \"\"\")\n\n    xml = textwrap.dedent(f\"\"\"\n            <?xml version=\"1.0\"?>\n            <document name=\"{filename}\">\n            \"\"\")\n\n    xhtml = textwrap.dedent(\"\"\"\n            <?xml version=\"1.0\"?>\n            <!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n            <html xmlns=\"http://www.w3.org/1999/xhtml\">\n            <head>\n            <style>\n            body{background-color:gray}\n            div{background-color:white;margin:1em;padding:1em}\n            p{white-space:pre-wrap}\n            </style>\n            </head>\n            <body>\n            \"\"\")\n\n    text = \"\"\n    json = f'{{\"document\": \"{filename}\", \"pages\": [\\n'\n    if t == \"html\":\n        r = html\n    elif t == \"json\":\n        r = json\n    elif t == \"xml\":\n        r = xml\n    elif t == \"xhtml\":\n        r = xhtml\n    else:\n        r = text\n\n    return r\n\n\ndef ConversionTrailer(i: str):\n    t = i.lower()\n    text = \"\"\n    json = \"]\\n}\"\n    html = \"</body>\\n</html>\\n\"\n    xml = \"</document>\\n\"\n    xhtml = html\n    if t == \"html\":\n        r = html\n    elif t == \"json\":\n        r = json\n    elif t == \"xml\":\n        r = xml\n    elif t == \"xhtml\":\n        r = xhtml\n    else:\n        r = text\n\n    return r\n\n\ndef annot_preprocess(page: \"Page\") -> int:\n    \"\"\"Prepare for annotation insertion on the page.\n\n    Returns:\n        Old page rotation value. Temporarily sets rotation to 0 when required.\n    \"\"\"\n    CheckParent(page)\n    if not page.parent.is_pdf:\n        raise ValueError(\"is no PDF\")\n    old_rotation = page.rotation\n    if old_rotation != 0:\n        page.set_rotation(0)\n    return old_rotation\n\n\ndef annot_postprocess(page: \"Page\", annot: \"Annot\") -> None:\n    \"\"\"Clean up after annotation insertion.\n\n    Set ownership flag and store annotation in page annotation dictionary.\n    \"\"\"\n    #annot.parent = weakref.proxy(page)\n    assert isinstance( page, Page)\n    assert isinstance( annot, Annot)\n    annot.parent = page\n    page._annot_refs[id(annot)] = annot\n    annot.thisown = True\n\n\ndef canon(c):\n    assert isinstance(c, int)\n    # TODO: proper unicode case folding\n    # TODO: character equivalence (a matches ä, etc)\n    if c == 0xA0 or c == 0x2028 or c == 0x2029:\n        return ord(' ')\n    if c == ord('\\r') or c == ord('\\n') or c == ord('\\t'):\n        return ord(' ')\n    if c >= ord('A') and c <= ord('Z'):\n        return c - ord('A') + ord('a')\n    return c\n\n\ndef chartocanon(s):\n    assert isinstance(s, str)\n    n, c = mupdf.fz_chartorune(s)\n    c = canon(c)\n    return n, c\n\n\ndef dest_is_valid(o, page_count, page_object_nums, names_list):\n    p = mupdf.pdf_dict_get( o, PDF_NAME('A'))\n    if (\n            mupdf.pdf_name_eq(\n                mupdf.pdf_dict_get( p, PDF_NAME('S')),\n                PDF_NAME('GoTo')\n                )\n            and not string_in_names_list(\n                mupdf.pdf_dict_get( p, PDF_NAME('D')),\n                names_list\n                )\n            ):\n        return 0\n\n    p = mupdf.pdf_dict_get( o, PDF_NAME('Dest'))\n    if not p.m_internal:\n        pass\n    elif mupdf.pdf_is_string( p):\n        return string_in_names_list( p, names_list)\n    elif not dest_is_valid_page(\n            mupdf.pdf_array_get( p, 0),\n            page_object_nums,\n            page_count,\n            ):\n        return 0\n    return 1\n\n\ndef dest_is_valid_page(obj, page_object_nums, pagecount):\n    num = mupdf.pdf_to_num(obj)\n\n    if num == 0:\n        return 0\n    for i in range(pagecount):\n        if page_object_nums[i] == num:\n            return 1\n    return 0\n\n\ndef find_string(s, needle):\n    assert isinstance(s, str)\n    for i in range(len(s)):\n        end = match_string(s[i:], needle)\n        if end is not None:\n            end += i\n            return i, end\n    return None, None\n\n\ndef get_pdf_now() -> str:\n    '''\n    \"Now\" timestamp in PDF Format\n    '''\n    import time\n    a = str(abs(time.altzone // 3600)).rjust(2, \"0\")\n    b = str((abs(time.altzone // 60) % 60)).rjust(2, \"0\")\n    tz = f\"{a}'{b}'\"\n    tstamp = time.strftime(\"D:%Y%m%d%H%M%S\", time.localtime())\n    if time.altzone > 0:\n        tstamp += \"-\" + tz\n    elif time.altzone < 0:\n        tstamp += \"+\" + tz\n    else:\n        pass\n    return tstamp\n\n\nclass ElementPosition(object):\n    \"\"\"Convert a dictionary with element position information to an object.\"\"\"\n\n    def __init__(self):\n        pass\n\n\ndef make_story_elpos():\n    return ElementPosition()\n\n \ndef get_highlight_selection(page, start: point_like =None, stop: point_like =None, clip: rect_like =None) -> list:\n    \"\"\"Return rectangles of text lines between two points.\n\n    Notes:\n        The default of 'start' is top-left of 'clip'. The default of 'stop'\n        is bottom-reight of 'clip'.\n\n    Args:\n        start: start point_like\n        stop: end point_like, must be 'below' start\n        clip: consider this rect_like only, default is page rectangle\n    Returns:\n        List of line bbox intersections with the area established by the\n        parameters.\n    \"\"\"\n    # validate and normalize arguments\n    if clip is None:\n        clip = page.rect\n    clip = Rect(clip)\n    if start is None:\n        start = clip.tl\n    if stop is None:\n        stop = clip.br\n    clip.y0 = start.y\n    clip.y1 = stop.y\n    if clip.is_empty or clip.is_infinite:\n        return []\n\n    # extract text of page, clip only, no images, expand ligatures\n    blocks = page.get_text(\n        \"dict\", flags=0, clip=clip,\n    )[\"blocks\"]\n\n    lines = []  # will return this list of rectangles\n    for b in blocks:\n        bbox = Rect(b[\"bbox\"])\n        if bbox.is_infinite or bbox.is_empty:\n            continue\n        for line in b[\"lines\"]:\n            bbox = Rect(line[\"bbox\"])\n            if bbox.is_infinite or bbox.is_empty:\n                continue\n            lines.append(bbox)\n\n    if lines == []:  # did not select anything\n        return lines\n\n    lines.sort(key=lambda bbox: bbox.y1)  # sort by vertical positions\n\n    # cut off prefix from first line if start point is close to its top\n    bboxf = lines.pop(0)\n    if bboxf.y0 - start.y <= 0.1 * bboxf.height:  # close enough?\n        r = Rect(start.x, bboxf.y0, bboxf.br)  # intersection rectangle\n        if not (r.is_empty or r.is_infinite):\n            lines.insert(0, r)  # insert again if not empty\n    else:\n        lines.insert(0, bboxf)  # insert again\n\n    if lines == []:  # the list might have been emptied\n        return lines\n\n    # cut off suffix from last line if stop point is close to its bottom\n    bboxl = lines.pop()\n    if stop.y - bboxl.y1 <= 0.1 * bboxl.height:  # close enough?\n        r = Rect(bboxl.tl, stop.x, bboxl.y1)  # intersection rectangle\n        if not (r.is_empty or r.is_infinite):\n            lines.append(r)  # append if not empty\n    else:\n        lines.append(bboxl)  # append again\n\n    return lines\n\n\ndef glyph_name_to_unicode(name: str) -> int:\n    \"\"\"Convenience function accessing unicodedata.\"\"\"\n    import unicodedata\n    try:\n        unc = ord(unicodedata.lookup(name))\n    except Exception:\n        unc = 65533\n    return unc\n\n\ndef hdist(dir, a, b):\n    dx = b.x - a.x\n    dy = b.y - a.y\n    return mupdf.fz_abs(dx * dir.x + dy * dir.y)\n\n\ndef make_table(rect: rect_like =(0, 0, 1, 1), cols: int =1, rows: int =1) -> list:\n    \"\"\"Return a list of (rows x cols) equal sized rectangles.\n\n    Notes:\n        A utility to fill a given area with table cells of equal size.\n    Args:\n        rect: rect_like to use as the table area\n        rows: number of rows\n        cols: number of columns\n    Returns:\n        A list with <rows> items, where each item is a list of <cols>\n        PyMuPDF Rect objects of equal sizes.\n    \"\"\"\n    rect = Rect(rect)  # ensure this is a Rect\n    if rect.is_empty or rect.is_infinite:\n        raise ValueError(\"rect must be finite and not empty\")\n    tl = rect.tl\n\n    height = rect.height / rows  # height of one table cell\n    width = rect.width / cols  # width of one table cell\n    delta_h = (width, 0, width, 0)  # diff to next right rect\n    delta_v = (0, height, 0, height)  # diff to next lower rect\n\n    r = Rect(tl, tl.x + width, tl.y + height)  # first rectangle\n\n    # make the first row\n    row = [r]\n    for i in range(1, cols):\n        r += delta_h  # build next rect to the right\n        row.append(r)\n\n    # make result, starts with first row\n    rects = [row]\n    for i in range(1, rows):\n        row = rects[i - 1]  # take previously appended row\n        nrow = []  # the new row to append\n        for r in row:  # for each previous cell add its downward copy\n            nrow.append(r + delta_v)\n        rects.append(nrow)  # append new row to result\n\n    return rects\n\n\ndef util_ensure_widget_calc(annot):\n    '''\n    Ensure that widgets with /AA/C JavaScript are in array AcroForm/CO\n    '''\n    annot_obj = mupdf.pdf_annot_obj(annot.this)\n    pdf = mupdf.pdf_get_bound_document(annot_obj)\n    PDFNAME_CO = mupdf.pdf_new_name(\"CO\")    # = PDF_NAME(CO)\n    acro = mupdf.pdf_dict_getl(  # get AcroForm dict\n            mupdf.pdf_trailer(pdf),\n            PDF_NAME('Root'),\n            PDF_NAME('AcroForm'),\n            )\n\n    CO = mupdf.pdf_dict_get(acro, PDFNAME_CO)  # = AcroForm/CO\n    if not mupdf.pdf_is_array(CO):\n        CO = mupdf.pdf_dict_put_array(acro, PDFNAME_CO, 2)\n    n = mupdf.pdf_array_len(CO)\n    found = 0\n    xref = mupdf.pdf_to_num(annot_obj)\n    for i in range(n):\n        nxref = mupdf.pdf_to_num(mupdf.pdf_array_get(CO, i))\n        if xref == nxref:\n            found = 1\n            break\n    if not found:\n        mupdf.pdf_array_push(CO, mupdf.pdf_new_indirect(pdf, xref, 0))\n\n\ndef util_make_rect( *args, p0=None, p1=None, x0=None, y0=None, x1=None, y1=None):\n    '''\n    Helper for initialising rectangle classes.\n    \n    2022-09-02: This is quite different from PyMuPDF's util_make_rect(), which\n    uses `goto` in ways that don't easily translate to Python.\n\n    Returns (x0, y0, x1, y1) derived from <args>, then override with p0, p1,\n    x0, y0, x1, y1 if they are not None.\n\n    Accepts following forms for <args>:\n        () returns all zeros.\n        (top-left, bottom-right)\n        (top-left, x1, y1)\n        (x0, y0, bottom-right)\n        (x0, y0, x1, y1)\n        (rect)\n\n    Where top-left and bottom-right are (x, y) or something with .x, .y\n    members; rect is something with .x0, .y0, .x1, and .y1 members.\n\n    2023-11-18: we now override with p0, p1, x0, y0, x1, y1 if not None.\n    '''\n    def get_xy( arg):\n        if isinstance( arg, (list, tuple)) and len( arg) == 2:\n            return arg[0], arg[1]\n        if isinstance( arg, (Point, mupdf.FzPoint, mupdf.fz_point)):\n            return arg.x, arg.y\n        return None, None\n    def make_tuple( a):\n        if isinstance( a, tuple):\n            return a\n        if isinstance( a, Point):\n            return a.x, a.y\n        elif isinstance( a, (Rect, IRect, mupdf.FzRect, mupdf.fz_rect)):\n            return a.x0, a.y0, a.x1, a.y1\n        if not isinstance( a, (list, tuple)):\n            a = a,\n        return a\n    def handle_args():\n        if len(args) == 0:\n            return 0, 0, 0, 0\n        elif len(args) == 1:\n            arg = args[0]\n            if isinstance( arg, (list, tuple)) and len( arg) == 2:\n                p1, p2 = arg\n                ret = *p1, *p2\n                assert len(ret) == 4\n                return ret\n            if isinstance( arg, (list, tuple)) and len( arg) == 3:\n                a, b, c = arg\n                a = make_tuple(a)\n                b = make_tuple(b)\n                c = make_tuple(c)\n                ret = *a, *b, *c\n                assert len(ret) == 4\n                return ret\n            ret = make_tuple( arg)\n            assert len(ret) == 4, f'{arg=} {ret=}'\n            return ret\n        elif len(args) == 2:\n            ret = get_xy( args[0]) + get_xy( args[1])\n            assert len(ret) == 4\n            return ret\n        elif len(args) == 3:\n            x0, y0 = get_xy( args[0])\n            if (x0, y0) != (None, None):\n                return x0, y0, args[1], args[2]\n            x1, y1 = get_xy( args[2])\n            if (x1, y1) != (None, None):\n                return args[0], args[1], x1, y1\n        elif len(args) == 4:\n            return args[0], args[1], args[2], args[3]\n        raise Exception( f'Unrecognised args: {args}')\n    ret_x0, ret_y0, ret_x1, ret_y1 = handle_args()\n    if p0 is not None:  ret_x0, ret_y0 = get_xy(p0)\n    if p1 is not None:  ret_x1, ret_y1 = get_xy(p1)\n    if x0 is not None:  ret_x0 = x0\n    if y0 is not None:  ret_y0 = y0\n    if x1 is not None:  ret_x1 = x1\n    if y1 is not None:  ret_y1 = y1\n    return ret_x0, ret_y0, ret_x1, ret_y1\n\n\ndef util_make_irect( *args, p0=None, p1=None, x0=None, y0=None, x1=None, y1=None):\n    a, b, c, d = util_make_rect( *args, p0=p0, p1=p1, x0=x0, y0=y0, x1=x1, y1=y1)\n    def convert(x, ceil):\n        if ceil:\n            return int(math.ceil(x))\n        else:\n            return int(math.floor(x))\n    a = convert(a, False)\n    b = convert(b, False)\n    c = convert(c, True)\n    d = convert(d, True)\n    return a, b, c, d\n\n\ndef util_round_rect( rect):\n    return JM_py_from_irect(mupdf.fz_round_rect(JM_rect_from_py(rect)))\n\n\ndef util_transform_rect( rect, matrix):\n    if g_use_extra:\n        return extra.util_transform_rect( rect, matrix)\n    return JM_py_from_rect(mupdf.fz_transform_rect(JM_rect_from_py(rect), JM_matrix_from_py(matrix)))\n\n\ndef util_intersect_rect( r1, r2):\n    return JM_py_from_rect(\n            mupdf.fz_intersect_rect(\n                JM_rect_from_py(r1),\n                JM_rect_from_py(r2),\n                )\n            )\n\n\ndef util_is_point_in_rect( p, r):\n    return mupdf.fz_is_point_inside_rect(\n                JM_point_from_py(p),\n                JM_rect_from_py(r),\n                )\n\ndef util_include_point_in_rect( r, p):\n    return JM_py_from_rect(\n            mupdf.fz_include_point_in_rect(\n                JM_rect_from_py(r),\n                JM_point_from_py(p),\n                )\n            )\n\n\ndef util_point_in_quad( P, Q):\n    p = JM_point_from_py(P)\n    q = JM_quad_from_py(Q)\n    return mupdf.fz_is_point_inside_quad(p, q)\n\n\ndef util_transform_point( point, matrix):\n    return JM_py_from_point(\n            mupdf.fz_transform_point(\n                JM_point_from_py(point),\n                JM_matrix_from_py(matrix),\n                )\n            )\n\n\ndef util_union_rect( r1, r2):\n    return JM_py_from_rect(\n            mupdf.fz_union_rect(\n                JM_rect_from_py(r1),\n                JM_rect_from_py(r2),\n                )\n            )\n\n\ndef util_concat_matrix( m1, m2):\n    return JM_py_from_matrix(\n            mupdf.fz_concat(\n                JM_matrix_from_py(m1),\n                JM_matrix_from_py(m2),\n                )\n            )\n\n\ndef util_invert_matrix(matrix):\n    if 0:\n        # Use MuPDF's fz_invert_matrix().\n        if isinstance( matrix, (tuple, list)):\n            matrix = mupdf.FzMatrix( *matrix)\n        elif isinstance( matrix, mupdf.fz_matrix):\n            matrix = mupdf.FzMatrix( matrix)\n        elif isinstance( matrix, Matrix):\n            matrix = mupdf.FzMatrix( matrix.a, matrix.b, matrix.c, matrix.d, matrix.e, matrix.f)\n        assert isinstance( matrix, mupdf.FzMatrix), f'{type(matrix)=}: {matrix}'\n        ret = mupdf.fz_invert_matrix( matrix)\n        if ret == matrix and (0\n                or abs( matrix.a - 1) >= sys.float_info.epsilon\n                or abs( matrix.b - 0) >= sys.float_info.epsilon\n                or abs( matrix.c - 0) >= sys.float_info.epsilon\n                or abs( matrix.d - 1) >= sys.float_info.epsilon\n                ):\n            # Inversion not possible.\n            return 1, ()\n        return 0, (ret.a, ret.b, ret.c, ret.d, ret.e, ret.f)\n    # Do inversion in python.\n    src = JM_matrix_from_py(matrix)\n    a = src.a\n    det = a * src.d - src.b * src.c\n    if det < -sys.float_info.epsilon or det > sys.float_info.epsilon:\n        dst = mupdf.FzMatrix()\n        rdet = 1 / det\n        dst.a = src.d * rdet\n        dst.b = -src.b * rdet\n        dst.c = -src.c * rdet\n        dst.d = a * rdet\n        a = -src.e * dst.a - src.f * dst.c\n        dst.f = -src.e * dst.b - src.f * dst.d\n        dst.e = a\n        return 0, (dst.a, dst.b, dst.c, dst.d, dst.e, dst.f)\n\n    return 1, ()\n\n\ndef util_measure_string( text, fontname, fontsize, encoding):\n    font = mupdf.fz_new_base14_font(fontname)\n    w = 0\n    pos = 0\n    while pos < len(text):\n        t, c = mupdf.fz_chartorune(text[pos:])\n        pos += t\n        if encoding == mupdf.PDF_SIMPLE_ENCODING_GREEK:\n            c = mupdf.fz_iso8859_7_from_unicode(c)\n        elif encoding == mupdf.PDF_SIMPLE_ENCODING_CYRILLIC:\n            c = mupdf.fz_windows_1251_from_unicode(c)\n        else:\n            c = mupdf.fz_windows_1252_from_unicode(c)\n        if c < 0:\n            c = 0xB7\n        g = mupdf.fz_encode_character(font, c)\n        dw = mupdf.fz_advance_glyph(font, g, 0)\n        w += dw\n    ret = w * fontsize\n    return ret\n\n\ndef util_sine_between(C, P, Q):\n    # for points C, P, Q compute the sine between lines CP and QP\n    c = JM_point_from_py(C)\n    p = JM_point_from_py(P)\n    q = JM_point_from_py(Q)\n    s = mupdf.fz_normalize_vector(mupdf.fz_make_point(q.x - p.x, q.y - p.y))\n    m1 = mupdf.fz_make_matrix(1, 0, 0, 1, -p.x, -p.y)\n    m2 = mupdf.fz_make_matrix(s.x, -s.y, s.y, s.x, 0, 0)\n    m1 = mupdf.fz_concat(m1, m2)\n    c = mupdf.fz_transform_point(c, m1)\n    c = mupdf.fz_normalize_vector(c)\n    return c.y\n\n\ndef util_hor_matrix(C, P):\n    '''\n    Return the matrix that maps two points C, P to the x-axis such that\n    C -> (0,0) and the image of P have the same distance.\n    '''\n    c = JM_point_from_py(C)\n    p = JM_point_from_py(P)\n    \n    # compute (cosine, sine) of vector P-C with double precision:\n    s = mupdf.fz_normalize_vector(mupdf.fz_make_point(p.x - c.x, p.y - c.y))\n    \n    m1 = mupdf.fz_make_matrix(1, 0, 0, 1, -c.x, -c.y)\n    m2 = mupdf.fz_make_matrix(s.x, -s.y, s.y, s.x, 0, 0)\n    return JM_py_from_matrix(mupdf.fz_concat(m1, m2))\n\n\ndef match_string(h0, n0):\n    h = 0\n    n = 0\n    e = h\n    delta_h, hc = chartocanon(h0[h:])\n    h += delta_h\n    delta_n, nc = chartocanon(n0[n:])\n    n += delta_n\n    while hc == nc:\n        e = h\n        if hc == ord(' '):\n            while 1:\n                delta_h, hc = chartocanon(h0[h:])\n                h += delta_h\n                if hc != ord(' '):\n                    break\n        else:\n            delta_h, hc = chartocanon(h0[h:])\n            h += delta_h\n        if nc == ord(' '):\n            while 1:\n                delta_n, nc = chartocanon(n0[n:])\n                n += delta_n\n                if nc != ord(' '):\n                    break\n        else:\n            delta_n, nc = chartocanon(n0[n:])\n            n += delta_n\n    return None if nc != 0 else e\n\n\ndef on_highlight_char(hits, line, ch):\n    assert hits\n    assert isinstance(line, mupdf.FzStextLine)\n    assert isinstance(ch, mupdf.FzStextChar)\n    vfuzz = ch.m_internal.size * hits.vfuzz\n    hfuzz = ch.m_internal.size * hits.hfuzz\n    ch_quad = JM_char_quad(line, ch)\n    if hits.len > 0:\n        # fixme: end = hits.quads[-1]\n        quad = hits.quads[hits.len - 1]\n        end = JM_quad_from_py(quad)\n        if ( 1\n                and hdist(line.m_internal.dir, end.lr, ch_quad.ll) < hfuzz\n                and vdist(line.m_internal.dir, end.lr, ch_quad.ll) < vfuzz\n                and hdist(line.m_internal.dir, end.ur, ch_quad.ul) < hfuzz\n                and vdist(line.m_internal.dir, end.ur, ch_quad.ul) < vfuzz\n                ):\n            end.ur = ch_quad.ur\n            end.lr = ch_quad.lr\n            assert hits.quads[-1] == end\n            return\n    hits.quads.append(ch_quad)\n    hits.len += 1\n\n\ndef page_merge(doc_des, doc_src, page_from, page_to, rotate, links, copy_annots, graft_map):\n    '''\n    Deep-copies a source page to the target.\n    Modified version of function of pdfmerge.c: we also copy annotations, but\n    we skip some subtypes. In addition we rotate output.\n    '''\n    if g_use_extra:\n        #log( 'Calling C++ extra.page_merge()')\n        return extra.page_merge( doc_des, doc_src, page_from, page_to, rotate, links, copy_annots, graft_map)\n    \n    # list of object types (per page) we want to copy\n    known_page_objs = [\n        PDF_NAME('Contents'),\n        PDF_NAME('Resources'),\n        PDF_NAME('MediaBox'),\n        PDF_NAME('CropBox'),\n        PDF_NAME('BleedBox'),\n        PDF_NAME('TrimBox'),\n        PDF_NAME('ArtBox'),\n        PDF_NAME('Rotate'),\n        PDF_NAME('UserUnit'),\n        ]\n    page_ref = mupdf.pdf_lookup_page_obj(doc_src, page_from)\n\n    # make new page dict in dest doc\n    page_dict = mupdf.pdf_new_dict(doc_des, 4)\n    mupdf.pdf_dict_put(page_dict, PDF_NAME('Type'), PDF_NAME('Page'))\n\n    # copy objects of source page into it\n    for i in range( len(known_page_objs)):\n        obj = mupdf.pdf_dict_get_inheritable( page_ref, known_page_objs[i])\n        if obj.m_internal:\n            #log(f'{type(graft_map) type(graft_map.this)=}')\n            mupdf.pdf_dict_put( page_dict, known_page_objs[i], mupdf.pdf_graft_mapped_object(graft_map.this, obj))\n\n    # Copy annotations, but skip Link, Popup, IRT, Widget types\n    # If selected, remove dict keys P (parent) and Popup\n    if copy_annots:\n        old_annots = mupdf.pdf_dict_get( page_ref, PDF_NAME('Annots'))\n        n = mupdf.pdf_array_len( old_annots)\n        if n > 0:\n            new_annots = mupdf.pdf_dict_put_array( page_dict, PDF_NAME('Annots'), n)\n            for i in range(n):\n                o = mupdf.pdf_array_get( old_annots, i)\n                if not o.m_internal or not mupdf.pdf_is_dict(o):\n                    continue    # skip non-dict items\n                if mupdf.pdf_dict_gets( o, \"IRT\").m_internal:\n                    continue\n                subtype = mupdf.pdf_dict_get( o, PDF_NAME('Subtype'))\n                if mupdf.pdf_name_eq( subtype, PDF_NAME('Link')):\n                    continue\n                if mupdf.pdf_name_eq( subtype, PDF_NAME('Popup')):\n                    continue\n                if mupdf.pdf_name_eq(subtype, PDF_NAME('Widget')):\n                    continue\n                mupdf.pdf_dict_del( o, PDF_NAME('Popup'))\n                mupdf.pdf_dict_del( o, PDF_NAME('P'))\n                copy_o = mupdf.pdf_graft_mapped_object( graft_map.this, o)\n                annot = mupdf.pdf_new_indirect( doc_des, mupdf.pdf_to_num( copy_o), 0)\n                mupdf.pdf_array_push( new_annots, annot)\n\n    # rotate the page\n    if rotate != -1:\n        mupdf.pdf_dict_put_int( page_dict, PDF_NAME('Rotate'), rotate)\n    # Now add the page dictionary to dest PDF\n    ref = mupdf.pdf_add_object( doc_des, page_dict)\n\n    # Insert new page at specified location\n    mupdf.pdf_insert_page( doc_des, page_to, ref)\n\n\ndef paper_rect(s: str) -> Rect:\n    \"\"\"Return a Rect for the paper size indicated in string 's'. Must conform to the argument of method 'PaperSize', which will be invoked.\n    \"\"\"\n    width, height = paper_size(s)\n    return Rect(0.0, 0.0, width, height)\n\n\ndef paper_size(s: str) -> tuple:\n    \"\"\"Return a tuple (width, height) for a given paper format string.\n\n    Notes:\n        'A4-L' will return (842, 595), the values for A4 landscape.\n        Suffix '-P' and no suffix return the portrait tuple.\n    \"\"\"\n    size = s.lower()\n    f = \"p\"\n    if size.endswith(\"-l\"):\n        f = \"l\"\n        size = size[:-2]\n    if size.endswith(\"-p\"):\n        size = size[:-2]\n    rc = paper_sizes().get(size, (-1, -1))\n    if f == \"p\":\n        return rc\n    return (rc[1], rc[0])\n\n\ndef paper_sizes():\n    \"\"\"Known paper formats @ 72 dpi as a dictionary. Key is the format string\n    like \"a4\" for ISO-A4. Value is the tuple (width, height).\n\n    Information taken from the following web sites:\n    www.din-formate.de\n    www.din-formate.info/amerikanische-formate.html\n    www.directtools.de/wissen/normen/iso.htm\n    \"\"\"\n    return {\n        \"a0\": (2384, 3370),\n        \"a1\": (1684, 2384),\n        \"a10\": (74, 105),\n        \"a2\": (1191, 1684),\n        \"a3\": (842, 1191),\n        \"a4\": (595, 842),\n        \"a5\": (420, 595),\n        \"a6\": (298, 420),\n        \"a7\": (210, 298),\n        \"a8\": (147, 210),\n        \"a9\": (105, 147),\n        \"b0\": (2835, 4008),\n        \"b1\": (2004, 2835),\n        \"b10\": (88, 125),\n        \"b2\": (1417, 2004),\n        \"b3\": (1001, 1417),\n        \"b4\": (709, 1001),\n        \"b5\": (499, 709),\n        \"b6\": (354, 499),\n        \"b7\": (249, 354),\n        \"b8\": (176, 249),\n        \"b9\": (125, 176),\n        \"c0\": (2599, 3677),\n        \"c1\": (1837, 2599),\n        \"c10\": (79, 113),\n        \"c2\": (1298, 1837),\n        \"c3\": (918, 1298),\n        \"c4\": (649, 918),\n        \"c5\": (459, 649),\n        \"c6\": (323, 459),\n        \"c7\": (230, 323),\n        \"c8\": (162, 230),\n        \"c9\": (113, 162),\n        \"card-4x6\": (288, 432),\n        \"card-5x7\": (360, 504),\n        \"commercial\": (297, 684),\n        \"executive\": (522, 756),\n        \"invoice\": (396, 612),\n        \"ledger\": (792, 1224),\n        \"legal\": (612, 1008),\n        \"legal-13\": (612, 936),\n        \"letter\": (612, 792),\n        \"monarch\": (279, 540),\n        \"tabloid-extra\": (864, 1296),\n        }\n\ndef pdf_lookup_page_loc(doc, needle):\n    return mupdf.pdf_lookup_page_loc(doc, needle)\n\n\ndef pdfobj_string(o, prefix=''):\n    '''\n    Returns description of mupdf.PdfObj (wrapper for pdf_obj) <o>.\n    '''\n    assert 0, 'use mupdf.pdf_debug_obj() ?'\n    ret = ''\n    if mupdf.pdf_is_array(o):\n        l = mupdf.pdf_array_len(o)\n        ret += f'array {l}\\n'\n        for i in range(l):\n            oo = mupdf.pdf_array_get(o, i)\n            ret += pdfobj_string(oo, prefix + '    ')\n            ret += '\\n'\n    elif mupdf.pdf_is_bool(o):\n        ret += f'bool: {o.array_get_bool()}\\n'\n    elif mupdf.pdf_is_dict(o):\n        l = mupdf.pdf_dict_len(o)\n        ret += f'dict {l}\\n'\n        for i in range(l):\n            key = mupdf.pdf_dict_get_key(o, i)\n            value = mupdf.pdf_dict_get( o, key)\n            ret += f'{prefix} {key}: '\n            ret += pdfobj_string( value, prefix + '    ')\n            ret += '\\n'\n    elif mupdf.pdf_is_embedded_file(o):\n        ret += f'embedded_file: {o.embedded_file_name()}\\n'\n    elif mupdf.pdf_is_indirect(o):\n        ret += f'indirect: ...\\n'\n    elif mupdf.pdf_is_int(o):\n        ret += f'int: {mupdf.pdf_to_int(o)}\\n'\n    elif mupdf.pdf_is_jpx_image(o):\n        ret += f'jpx_image:\\n'\n    elif mupdf.pdf_is_name(o):\n        ret += f'name: {mupdf.pdf_to_name(o)}\\n'\n    elif o.pdf_is_null:\n        ret += f'null\\n'\n    #elif o.pdf_is_number:\n    #    ret += f'number\\n'\n    elif o.pdf_is_real:\n        ret += f'real: {o.pdf_to_real()}\\n'\n    elif mupdf.pdf_is_stream(o):\n        ret += f'stream\\n'\n    elif mupdf.pdf_is_string(o):\n        ret += f'string: {mupdf.pdf_to_string(o)}\\n'\n    else:\n        ret += '<>\\n'\n\n    return ret\n\n\ndef repair_mono_font(page: \"Page\", font: \"Font\") -> None:\n    \"\"\"Repair character spacing for mono fonts.\n\n    Notes:\n        Some mono-spaced fonts are displayed with a too large character\n        distance, e.g. \"a b c\" instead of \"abc\". This utility adds an entry\n        \"/W[0 65535 w]\" to the descendent font(s) of font. The float w is\n        taken to be the width of 0x20 (space).\n        This should enforce viewers to use 'w' as the character width.\n\n    Args:\n        page: pymupdf.Page object.\n        font: pymupdf.Font object.\n    \"\"\"\n    if not font.flags[\"mono\"]:  # font not flagged as monospaced\n        return None\n    doc = page.parent  # the document\n    fontlist = page.get_fonts()  # list of fonts on page\n    xrefs = [  # list of objects referring to font\n        f[0]\n        for f in fontlist\n        if (f[3] == font.name and f[4].startswith(\"F\") and f[5].startswith(\"Identity\"))\n    ]\n    if xrefs == []:  # our font does not occur\n        return\n    xrefs = set(xrefs)  # drop any double counts\n    width = int(round((font.glyph_advance(32) * 1000)))\n    for xref in xrefs:\n        if not TOOLS.set_font_width(doc, xref, width):\n            log(f\"Cannot set width for '{font.name}' in xref {xref:d}\")\n\n\ndef sRGB_to_pdf(srgb: int) -> tuple:\n    \"\"\"Convert sRGB color code to a PDF color triple.\n\n    There is **no error checking** for performance reasons!\n\n    Args:\n        srgb: (int) RRGGBB (red, green, blue), each color in range(255).\n    Returns:\n        Tuple (red, green, blue) each item in interval 0 <= item <= 1.\n    \"\"\"\n    t = sRGB_to_rgb(srgb)\n    return t[0] / 255.0, t[1] / 255.0, t[2] / 255.0\n\n\ndef sRGB_to_rgb(srgb: int) -> tuple:\n    \"\"\"Convert sRGB color code to an RGB color triple.\n\n    There is **no error checking** for performance reasons!\n\n    Args:\n        srgb: (int) SSRRGGBB (red, green, blue), each color in range(255).\n        With MuPDF < 1.26, `s` is always 0.\n    Returns:\n        Tuple (red, green, blue) each item in interval 0 <= item <= 255.\n    \"\"\"\n    srgb &= 0xffffff\n    r = srgb >> 16\n    g = (srgb - (r << 16)) >> 8\n    b = srgb - (r << 16) - (g << 8)\n    return (r, g, b)\n\n\ndef string_in_names_list(p, names_list):\n    n = mupdf.pdf_array_len( names_list) if names_list else 0\n    str_ = mupdf.pdf_to_text_string( p)\n    for i in range(0, n, 2):\n        if mupdf.pdf_to_text_string( mupdf.pdf_array_get( names_list, i)) == str_:\n            return 1\n    return 0\n\n\ndef strip_outline(doc, outlines, page_count, page_object_nums, names_list):\n    '''\n    Returns (count, first, prev).\n    '''\n    first = None\n    count = 0\n    current = outlines\n    prev = None\n    while current.m_internal:\n        # Strip any children to start with. This takes care of\n        # First / Last / Count for us.\n        nc = strip_outlines(doc, current, page_count, page_object_nums, names_list)\n\n        if not dest_is_valid(current, page_count, page_object_nums, names_list):\n            if nc == 0:\n                # Outline with invalid dest and no children. Drop it by\n                # pulling the next one in here.\n                next = mupdf.pdf_dict_get(current, PDF_NAME('Next'))\n                if not next.m_internal:\n                    # There is no next one to pull in\n                    if prev.m_internal:\n                        mupdf.pdf_dict_del(prev, PDF_NAME('Next'))\n                elif prev.m_internal:\n                    mupdf.pdf_dict_put(prev, PDF_NAME('Next'), next)\n                    mupdf.pdf_dict_put(next, PDF_NAME('Prev'), prev)\n                else:\n                    mupdf.pdf_dict_del(next, PDF_NAME('Prev'))\n                current = next\n            else:\n                # Outline with invalid dest, but children. Just drop the dest.\n                mupdf.pdf_dict_del(current, PDF_NAME('Dest'))\n                mupdf.pdf_dict_del(current, PDF_NAME('A'))\n                current = mupdf.pdf_dict_get(current, PDF_NAME('Next'))\n        else:\n            # Keep this one\n            if not first or not first.m_internal:\n                first = current\n            prev = current\n            current = mupdf.pdf_dict_get(current, PDF_NAME('Next'))\n            count += 1\n\n    return count, first, prev\n\n\ndef strip_outlines(doc, outlines, page_count, page_object_nums, names_list):\n    if not outlines.m_internal:\n        return 0\n\n    first = mupdf.pdf_dict_get(outlines, PDF_NAME('First'))\n    if not first.m_internal:\n        nc = 0\n    else:\n        nc, first, last = strip_outline(doc, first, page_count, page_object_nums, names_list)\n\n    if nc == 0:\n        mupdf.pdf_dict_del(outlines, PDF_NAME('First'))\n        mupdf.pdf_dict_del(outlines, PDF_NAME('Last'))\n        mupdf.pdf_dict_del(outlines, PDF_NAME('Count'))\n    else:\n        old_count = mupdf.pdf_to_int(mupdf.pdf_dict_get(outlines, PDF_NAME('Count')))\n        mupdf.pdf_dict_put(outlines, PDF_NAME('First'), first)\n        mupdf.pdf_dict_put(outlines, PDF_NAME('Last'), last)\n        mupdf.pdf_dict_put(outlines, PDF_NAME('Count'), mupdf.pdf_new_int(nc if old_count > 0 else -nc))\n    return nc\n\n\ntrace_device_FILL_PATH = 1\ntrace_device_STROKE_PATH = 2\ntrace_device_CLIP_PATH = 3\ntrace_device_CLIP_STROKE_PATH = 4\n\n\ndef unicode_to_glyph_name(ch: int) -> str:\n    \"\"\"\n    Convenience function accessing unicodedata.\n    \"\"\"\n    import unicodedata\n    try:\n        name = unicodedata.name(chr(ch))\n    except ValueError:\n        name = \".notdef\"\n    return name\n\n\ndef vdist(dir, a, b):\n    dx = b.x - a.x\n    dy = b.y - a.y\n    return mupdf.fz_abs(dx * dir.y + dy * dir.x)\n\n\ndef apply_pages(\n        path,\n        pagefn,\n        *,\n        pagefn_args=(),\n        pagefn_kwargs=dict(),\n        initfn=None,\n        initfn_args=(),\n        initfn_kwargs=dict(),\n        pages=None,\n        method='single',\n        concurrency=None,\n        _stats=False,\n        ):\n    '''\n    Returns list of results from `pagefn()`, optionally using concurrency for\n    speed.\n    \n    Args:\n        path:\n            Path of document.\n        pagefn:\n            Function to call for each page; is passed (page, *pagefn_args,\n            **pagefn_kwargs). Return value is added to list that we return. If\n            `method` is not 'single', must be a top-level function - nested\n            functions don't work with concurrency.\n        pagefn_args\n        pagefn_kwargs:\n            Additional args to pass to `pagefn`. Must be picklable.\n        initfn:\n            If true, called once in each worker process; is passed\n            (*initfn_args, **initfn_kwargs).\n        initfn_args\n        initfn_kwargs:\n            Args to pass to initfn. Must be picklable.\n        pages:\n            List of page numbers to process, or None to include all pages.\n        method:\n            'single'\n                Do not use concurrency.\n            'mp'\n                Operate concurrently using Python's `multiprocessing` module.\n            'fork'\n                 Operate concurrently using custom implementation with\n                 `os.fork()`. Does not work on Windows.\n        concurrency:\n            Number of worker processes to use when operating concurrently. If\n            None, we use the number of available CPUs.\n        _stats:\n            Internal, may change or be removed. If true, we output simple\n            timing diagnostics.\n    \n    Note: We require a file path rather than a Document, because Document\n    instances do not work properly after a fork - internal file descriptor\n    offsets are shared between the parent and child processes.\n    '''\n    if _stats:\n        t0 = time.time()\n    \n    if method == 'single':\n        if initfn:\n            initfn(*initfn_args, **initfn_kwargs)\n        ret = list()\n        document = Document(path)\n        if pages is None:\n            pages = range(len(document))\n        for pno in pages:\n            page = document[pno]\n            r = pagefn(page, *pagefn_args, **initfn_kwargs)\n            ret.append(r)\n    \n    else:\n        # Use concurrency.\n        #\n        from . import _apply_pages\n    \n        if pages is None:\n            if _stats:\n                t = time.time()\n            with Document(path) as document:\n                num_pages = len(document)\n                pages = list(range(num_pages))\n            if _stats:\n                t = time.time() - t\n                log(f'{t:.2f}s: count pages.')\n    \n        if _stats:\n            t = time.time()\n        \n        if method == 'mp':\n            ret = _apply_pages._multiprocessing(\n                    path,\n                    pages,\n                    pagefn,\n                    pagefn_args,\n                    pagefn_kwargs,\n                    initfn,\n                    initfn_args,\n                    initfn_kwargs,\n                    concurrency,\n                    _stats,\n                    )\n    \n        elif method == 'fork':\n            ret = _apply_pages._fork(\n                    path,\n                    pages,\n                    pagefn,\n                    pagefn_args,\n                    pagefn_kwargs,\n                    initfn,\n                    initfn_args,\n                    initfn_kwargs,\n                    concurrency,\n                    _stats,\n                    )\n        \n        else:\n            assert 0, f'Unrecognised {method=}.'\n        \n        if _stats:\n            t = time.time() - t\n            log(f'{t:.2f}s: work.')\n\n    if _stats:\n        t = time.time() - t0\n        log(f'{t:.2f}s: total.')\n    return ret\n\n\ndef get_text(\n        path,\n        *,\n        pages=None,\n        method='single',\n        concurrency=None,\n        \n        option='text',\n        clip=None,\n        flags=None,\n        textpage=None,\n        sort=False,\n        delimiters=None,\n        \n        _stats=False,\n        ):\n    '''\n    Returns list of results from `Page.get_text()`, optionally using\n    concurrency for speed.\n    \n    Args:\n        path:\n            Path of document.\n        pages:\n            List of page numbers to process, or None to include all pages.\n        method:\n            'single'\n                Do not use concurrency.\n            'mp'\n                Operate concurrently using Python's `multiprocessing` module.\n            'fork'\n                 Operate concurrently using custom implementation with\n                 `os.fork`. Does not work on Windows.\n        concurrency:\n            Number of worker processes to use when operating concurrently. If\n            None, we use the number of available CPUs.\n        option\n        clip\n        flags\n        textpage\n        sort\n        delimiters:\n            Passed to internal calls to `Page.get_text()`.\n    '''\n    args_dict = dict(\n            option=option,\n            clip=clip,\n            flags=flags,\n            textpage=textpage,\n            sort=sort,\n            delimiters=delimiters,\n            )\n    \n    return apply_pages(\n            path,\n            Page.get_text,\n            pagefn_kwargs=args_dict,\n            pages=pages,\n            method=method,\n            concurrency=concurrency,\n            _stats=_stats,\n            )\n\n\nclass TOOLS:\n    '''\n    We use @staticmethod to avoid the need to create an instance of this class.\n    '''\n\n    def _derotate_matrix(page):\n        if isinstance(page, mupdf.PdfPage):\n            return JM_py_from_matrix(JM_derotate_page_matrix(page))\n        else:\n            return JM_py_from_matrix(mupdf.FzMatrix())\n\n    @staticmethod\n    def _fill_widget(annot, widget):\n        val = JM_get_widget_properties(annot, widget)\n\n        widget.rect = Rect(annot.rect)\n        widget.xref = annot.xref\n        widget.parent = annot.parent\n        widget._annot = annot  # backpointer to annot object\n        if not widget.script:\n            widget.script = None\n        if not widget.script_stroke:\n            widget.script_stroke = None\n        if not widget.script_format:\n            widget.script_format = None\n        if not widget.script_change:\n            widget.script_change = None\n        if not widget.script_calc:\n            widget.script_calc = None\n        if not widget.script_blur:\n            widget.script_blur = None\n        if not widget.script_focus:\n            widget.script_focus = None\n        return val\n\n    @staticmethod\n    def _get_all_contents(page):\n        page = _as_pdf_page(page.this)\n        res = JM_read_contents(page.obj())\n        result = JM_BinFromBuffer( res)\n        return result\n\n    @staticmethod\n    def _insert_contents(page, newcont, overlay=1):\n        \"\"\"Add bytes as a new /Contents object for a page, and return its xref.\"\"\"\n        pdfpage = _as_pdf_page(page, required=1)\n        contbuf = JM_BufferFromBytes(newcont)\n        xref = JM_insert_contents(pdfpage.doc(), pdfpage.obj(), contbuf, overlay)\n        #fixme: pdfpage->doc->dirty = 1;\n        return xref\n\n    @staticmethod\n    def _le_annot_parms(annot, p1, p2, fill_color):\n        \"\"\"Get common parameters for making annot line end symbols.\n\n        Returns:\n            m: matrix that maps p1, p2 to points L, P on the x-axis\n            im: its inverse\n            L, P: transformed p1, p2\n            w: line width\n            scol: stroke color string\n            fcol: fill color store_shrink\n            opacity: opacity string (gs command)\n        \"\"\"\n        w = annot.border[\"width\"]  # line width\n        sc = annot.colors[\"stroke\"]  # stroke color\n        if not sc:  # black if missing\n            sc = (0,0,0)\n        scol = \" \".join(map(str, sc)) + \" RG\\n\"\n        if fill_color:\n            fc = fill_color\n        else:\n            fc = annot.colors[\"fill\"]  # fill color\n        if not fc:\n            fc = (1,1,1)  # white if missing\n        fcol = \" \".join(map(str, fc)) + \" rg\\n\"\n        # nr = annot.rect\n        np1 = p1                   # point coord relative to annot rect\n        np2 = p2                   # point coord relative to annot rect\n        m = Matrix(util_hor_matrix(np1, np2))  # matrix makes the line horizontal\n        im = ~m                            # inverted matrix\n        L = np1 * m                        # converted start (left) point\n        R = np2 * m                        # converted end (right) point\n        if 0 <= annot.opacity < 1:\n            opacity = \"/H gs\\n\"\n        else:\n            opacity = \"\"\n        return m, im, L, R, w, scol, fcol, opacity\n\n    @staticmethod\n    def _le_butt(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for butt line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 3\n        d = shift * max(1, w)\n        M = R if lr else L\n        top = (M + (0, -d/2.)) * im\n        bot = (M + (0, d/2.)) * im\n        ap = f\"\\nq\\n{opacity}{top.x:f} {top.y:f} m\\n\"\n        ap += f\"{bot.x:f} {bot.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + \"s\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_circle(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for circle line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 2.5             # 2*shift*width = length of square edge\n        d = shift * max(1, w)\n        M = R - (d/2., 0) if lr else L + (d/2., 0)\n        r = Rect(M, M) + (-d, -d, d, d)         # the square\n        ap = \"q\\n\" + opacity + TOOLS._oval_string(r.tl * im, r.tr * im, r.br * im, r.bl * im)\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + fcol + \"b\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_closedarrow(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for closed arrow line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 2.5\n        d = shift * max(1, w)\n        p2 = R + (d/2., 0) if lr else L - (d/2., 0)\n        p1 = p2 + (-2*d, -d) if lr else p2 + (2*d, -d)\n        p3 = p2 + (-2*d, d) if lr else p2 + (2*d, d)\n        p1 *= im\n        p2 *= im\n        p3 *= im\n        ap = f\"\\nq\\n{opacity}{p1.x:f} {p1.y:f} m\\n\"\n        ap += f\"{p2.x:f} {p2.y:f} l\\n\"\n        ap += f\"{p3.x:f} {p3.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + fcol + \"b\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_diamond(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for diamond line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 2.5             # 2*shift*width = length of square edge\n        d = shift * max(1, w)\n        M = R - (d/2., 0) if lr else L + (d/2., 0)\n        r = Rect(M, M) + (-d, -d, d, d)         # the square\n        # the square makes line longer by (2*shift - 1)*width\n        p = (r.tl + (r.bl - r.tl) * 0.5) * im\n        ap = f\"q\\n{opacity}{p.x:f} {p.y:f} m\\n\"\n        p = (r.tl + (r.tr - r.tl) * 0.5) * im\n        ap += f\"{p.x:f} {p.y:f} l\\n\"\n        p = (r.tr + (r.br - r.tr) * 0.5) * im\n        ap += f\"{p.x:f} {p.y:f} l\\n\"\n        p = (r.br + (r.bl - r.br) * 0.5) * im\n        ap += f\"{p.x:f} {p.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + fcol + \"b\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_openarrow(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for open arrow line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 2.5\n        d = shift * max(1, w)\n        p2 = R + (d/2., 0) if lr else L - (d/2., 0)\n        p1 = p2 + (-2*d, -d) if lr else p2 + (2*d, -d)\n        p3 = p2 + (-2*d, d) if lr else p2 + (2*d, d)\n        p1 *= im\n        p2 *= im\n        p3 *= im\n        ap = f\"\\nq\\n{opacity}{p1.x:f} {p1.y:f} m\\n\"\n        ap += f\"{p2.x:f} {p2.y:f} l\\n\"\n        ap += f\"{p3.x:f} {p3.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + \"S\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_rclosedarrow(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for right closed arrow line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 2.5\n        d = shift * max(1, w)\n        p2 = R - (2*d, 0) if lr else L + (2*d, 0)\n        p1 = p2 + (2*d, -d) if lr else p2 + (-2*d, -d)\n        p3 = p2 + (2*d, d) if lr else p2 + (-2*d, d)\n        p1 *= im\n        p2 *= im\n        p3 *= im\n        ap = f\"\\nq\\n{opacity}{p1.x:f} {p1.y:f} m\\n\"\n        ap += f\"{p2.x:f} {p2.y:f} l\\n\"\n        ap += f\"{p3.x:f} {p3.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + fcol + \"b\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_ropenarrow(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for right open arrow line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 2.5\n        d = shift * max(1, w)\n        p2 = R - (d/3., 0) if lr else L + (d/3., 0)\n        p1 = p2 + (2*d, -d) if lr else p2 + (-2*d, -d)\n        p3 = p2 + (2*d, d) if lr else p2 + (-2*d, d)\n        p1 *= im\n        p2 *= im\n        p3 *= im\n        ap = f\"\\nq\\n{opacity}{p1.x:f} {p1.y:f} m\\n\"\n        ap += f\"{p2.x:f} {p2.y:f} l\\n\"\n        ap += f\"{p3.x:f} {p3.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + fcol + \"S\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_slash(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for slash line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        rw = 1.1547 * max(1, w) * 1.0         # makes rect diagonal a 30 deg inclination\n        M = R if lr else L\n        r = Rect(M.x - rw, M.y - 2 * w, M.x + rw, M.y + 2 * w)\n        top = r.tl * im\n        bot = r.br * im\n        ap = f\"\\nq\\n{opacity}{top.x:f} {top.y:f} m\\n\"\n        ap += f\"{bot.x:f} {bot.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + \"s\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _le_square(annot, p1, p2, lr, fill_color):\n        \"\"\"Make stream commands for square line end symbol. \"lr\" denotes left (False) or right point.\n        \"\"\"\n        m, im, L, R, w, scol, fcol, opacity = TOOLS._le_annot_parms(annot, p1, p2, fill_color)\n        shift = 2.5             # 2*shift*width = length of square edge\n        d = shift * max(1, w)\n        M = R - (d/2., 0) if lr else L + (d/2., 0)\n        r = Rect(M, M) + (-d, -d, d, d)         # the square\n        # the square makes line longer by (2*shift - 1)*width\n        p = r.tl * im\n        ap = f\"q\\n{opacity}{p.x:f} {p.y:f} m\\n\"\n        p = r.tr * im\n        ap += f\"{p.x:f} {p.y:f} l\\n\"\n        p = r.br * im\n        ap += f\"{p.x:f} {p.y:f} l\\n\"\n        p = r.bl * im\n        ap += f\"{p.x:f} {p.y:f} l\\n\"\n        ap += _format_g(w) + \" w\\n\"\n        ap += scol + fcol + \"b\\nQ\\n\"\n        return ap\n\n    @staticmethod\n    def _oval_string(p1, p2, p3, p4):\n        \"\"\"Return /AP string defining an oval within a 4-polygon provided as points\n        \"\"\"\n        def bezier(p, q, r):\n            return f\"{p.x:f} {p.y:f} {q.x:f} {q.y:f} {r.x:f} {r.y:f} c\\n\"\n\n        kappa = 0.55228474983              # magic number\n        ml = p1 + (p4 - p1) * 0.5          # middle points ...\n        mo = p1 + (p2 - p1) * 0.5          # for each ...\n        mr = p2 + (p3 - p2) * 0.5          # polygon ...\n        mu = p4 + (p3 - p4) * 0.5          # side\n        ol1 = ml + (p1 - ml) * kappa       # the 8 bezier\n        ol2 = mo + (p1 - mo) * kappa       # helper points\n        or1 = mo + (p2 - mo) * kappa\n        or2 = mr + (p2 - mr) * kappa\n        ur1 = mr + (p3 - mr) * kappa\n        ur2 = mu + (p3 - mu) * kappa\n        ul1 = mu + (p4 - mu) * kappa\n        ul2 = ml + (p4 - ml) * kappa\n        # now draw, starting from middle point of left side\n        ap = f\"{ml.x:f} {ml.y:f} m\\n\"\n        ap += bezier(ol1, ol2, mo)\n        ap += bezier(or1, or2, mr)\n        ap += bezier(ur1, ur2, mu)\n        ap += bezier(ul1, ul2, ml)\n        return ap\n\n    @staticmethod\n    def _parse_da(annot):\n\n        if g_use_extra:\n            val = extra.Tools_parse_da( annot.this)\n        else:\n            def Tools__parse_da(annot):\n                this_annot = annot.this\n                assert isinstance(this_annot, mupdf.PdfAnnot)\n                this_annot_obj = mupdf.pdf_annot_obj( this_annot)\n                pdf = mupdf.pdf_get_bound_document( this_annot_obj)\n                try:\n                    da = mupdf.pdf_dict_get_inheritable( this_annot_obj, PDF_NAME('DA'))\n                    if not da.m_internal:\n                        trailer = mupdf.pdf_trailer(pdf)\n                        da = mupdf.pdf_dict_getl(trailer,\n                                PDF_NAME('Root'),\n                                PDF_NAME('AcroForm'),\n                                PDF_NAME('DA'),\n                                )\n                    da_str = mupdf.pdf_to_text_string(da)\n                except Exception:\n                    if g_exceptions_verbose:    exception_info()\n                    return\n                return da_str\n            val = Tools__parse_da(annot)\n\n        if not val:\n            return ((0,), \"\", 0)\n        font = \"Helv\"\n        fsize = 12\n        col = (0, 0, 0)\n        dat = val.split()  # split on any whitespace\n        for i, item in enumerate(dat):\n            if item == \"Tf\":\n                font = dat[i - 2][1:]\n                fsize = float(dat[i - 1])\n                dat[i] = dat[i-1] = dat[i-2] = \"\"\n                continue\n            if item == \"g\":            # unicolor text\n                col = [(float(dat[i - 1]))]\n                dat[i] = dat[i-1] = \"\"\n                continue\n            if item == \"rg\":           # RGB colored text\n                col = [float(f) for f in dat[i - 3:i]]\n                dat[i] = dat[i-1] = dat[i-2] = dat[i-3] = \"\"\n                continue\n            if item == \"k\":           # CMYK colored text\n                col = [float(f) for f in dat[i - 4:i]]\n                dat[i] = dat[i-1] = dat[i-2] = dat[i-3] = dat[i-4] = \"\"\n                continue\n\n        val = (col, font, fsize)\n        return val\n\n    @staticmethod\n    def _reset_widget(annot):\n        this_annot = annot\n        this_annot_obj = mupdf.pdf_annot_obj(this_annot)\n        pdf = mupdf.pdf_get_bound_document(this_annot_obj)\n        mupdf.pdf_field_reset(pdf, this_annot_obj)\n\n    @staticmethod\n    def _rotate_matrix(page):\n        pdfpage = page._pdf_page(required=False)\n        if not pdfpage.m_internal:\n            return JM_py_from_matrix(mupdf.FzMatrix())\n        return JM_py_from_matrix(JM_rotate_page_matrix(pdfpage))\n\n    @staticmethod\n    def _save_widget(annot, widget):\n        JM_set_widget_properties(annot, widget)\n\n    def _update_da(annot, da_str):\n        if g_use_extra:\n            extra.Tools_update_da( annot.this, da_str)\n        else:\n            try:\n                this_annot = annot.this\n                assert isinstance(this_annot, mupdf.PdfAnnot)\n                mupdf.pdf_dict_put_text_string(mupdf.pdf_annot_obj(this_annot), PDF_NAME('DA'), da_str)\n                mupdf.pdf_dict_del(mupdf.pdf_annot_obj(this_annot), PDF_NAME('DS'))    # /* not supported */\n                mupdf.pdf_dict_del(mupdf.pdf_annot_obj(this_annot), PDF_NAME('RC'))    # /* not supported */\n            except Exception:\n                if g_exceptions_verbose:    exception_info()\n                return\n            return\n    \n    @staticmethod\n    def gen_id():\n        global TOOLS_JM_UNIQUE_ID\n        TOOLS_JM_UNIQUE_ID += 1\n        return TOOLS_JM_UNIQUE_ID\n\n    @staticmethod\n    def glyph_cache_empty():\n        '''\n        Empty the glyph cache.\n        '''\n        mupdf.fz_purge_glyph_cache()\n\n    @staticmethod\n    def image_profile(stream, keep_image=0):\n        '''\n        Metadata of an image binary stream.\n        '''\n        return JM_image_profile(stream, keep_image)\n    \n    @staticmethod\n    def mupdf_display_errors(on=None):\n        '''\n        Set MuPDF error display to True or False.\n        '''\n        global JM_mupdf_show_errors\n        if on is not None:\n            JM_mupdf_show_errors = bool(on)\n        return JM_mupdf_show_errors\n\n    @staticmethod\n    def mupdf_display_warnings(on=None):\n        '''\n        Set MuPDF warnings display to True or False.\n        '''\n        global JM_mupdf_show_warnings\n        if on is not None:\n            JM_mupdf_show_warnings = bool(on)\n        return JM_mupdf_show_warnings\n\n    @staticmethod\n    def mupdf_version():\n        '''Get version of MuPDF binary build.'''\n        return mupdf.FZ_VERSION\n\n    @staticmethod\n    def mupdf_warnings(reset=1):\n        '''\n        Get the MuPDF warnings/errors with optional reset (default).\n        '''\n        # Get any trailing `... repeated <N> times...` message.\n        mupdf.fz_flush_warnings()\n        ret = '\\n'.join( JM_mupdf_warnings_store)\n        if reset:\n            TOOLS.reset_mupdf_warnings()\n        return ret\n\n    @staticmethod\n    def reset_mupdf_warnings():\n        global JM_mupdf_warnings_store\n        JM_mupdf_warnings_store = list()\n        \n    @staticmethod\n    def set_aa_level(level):\n        '''\n        Set anti-aliasing level.\n        '''\n        mupdf.fz_set_aa_level(level)\n    \n    @staticmethod\n    def set_annot_stem( stem=None):\n        global JM_annot_id_stem\n        if stem is None:\n            return JM_annot_id_stem\n        len_ = len(stem) + 1\n        if len_ > 50:\n            len_ = 50\n        JM_annot_id_stem = stem[:50]\n        return JM_annot_id_stem\n\n    @staticmethod\n    def set_font_width(doc, xref, width):\n        pdf = _as_pdf_document(doc, required=0)\n        if not pdf.m_internal:\n            return False\n        font = mupdf.pdf_load_object(pdf, xref)\n        dfonts = mupdf.pdf_dict_get(font, PDF_NAME('DescendantFonts'))\n        if mupdf.pdf_is_array(dfonts):\n            n = mupdf.pdf_array_len(dfonts)\n            for i in range(n):\n                dfont = mupdf.pdf_array_get(dfonts, i)\n                warray = mupdf.pdf_new_array(pdf, 3)\n                mupdf.pdf_array_push(warray, mupdf.pdf_new_int(0))\n                mupdf.pdf_array_push(warray, mupdf.pdf_new_int(65535))\n                mupdf.pdf_array_push(warray, mupdf.pdf_new_int(width))\n                mupdf.pdf_dict_put(dfont, PDF_NAME('W'), warray)\n        return True\n\n    @staticmethod\n    def set_graphics_min_line_width(min_line_width):\n        '''\n        Set the graphics minimum line width.\n        '''\n        mupdf.fz_set_graphics_min_line_width(min_line_width)\n\n    @staticmethod\n    def set_icc( on=0):\n        \"\"\"Set ICC color handling on or off.\"\"\"\n        if on:\n            if mupdf.FZ_ENABLE_ICC:\n                mupdf.fz_enable_icc()\n            else:\n                RAISEPY( \"MuPDF built w/o ICC support\",PyExc_ValueError)\n        elif mupdf.FZ_ENABLE_ICC:\n            mupdf.fz_disable_icc()\n \n    @staticmethod\n    def set_low_memory( on=None):\n        \"\"\"Set / unset MuPDF device caching.\"\"\"\n        if on is not None:\n            _globals.no_device_caching = bool(on)\n        return _globals.no_device_caching\n\n    @staticmethod\n    def set_small_glyph_heights(on=None):\n        \"\"\"Set / unset small glyph heights.\"\"\"\n        if on is not None:\n            _globals.small_glyph_heights = bool(on)\n            if g_use_extra:\n                extra.set_small_glyph_heights(_globals.small_glyph_heights)\n        return _globals.small_glyph_heights\n    \n    @staticmethod\n    def set_subset_fontnames(on=None):\n        '''\n        Set / unset returning fontnames with their subset prefix.\n        '''\n        if on is not None:\n            _globals.subset_fontnames = bool(on)\n            if g_use_extra:\n                extra.set_subset_fontnames(_globals.subset_fontnames)\n        return _globals.subset_fontnames\n    \n    @staticmethod\n    def show_aa_level():\n        '''\n        Show anti-aliasing values.\n        '''\n        return dict(\n                graphics = mupdf.fz_graphics_aa_level(),\n                text = mupdf.fz_text_aa_level(),\n                graphics_min_line_width = mupdf.fz_graphics_min_line_width(),\n                )\n\n    @staticmethod\n    def store_maxsize():\n        '''\n        MuPDF store size limit.\n        '''\n        # fixme: return gctx->store->max.\n        return None\n\n    @staticmethod\n    def store_shrink(percent):\n        '''\n        Free 'percent' of current store size.\n        '''\n        if percent >= 100:\n            mupdf.fz_empty_store()\n            return 0\n        if percent > 0:\n            mupdf.fz_shrink_store( 100 - percent)\n        # fixme: return gctx->store->size.\n    \n    @staticmethod\n    def store_size():\n        '''\n        MuPDF current store size.\n        '''\n        # fixme: return gctx->store->size.\n        return None\n    \n    @staticmethod\n    def unset_quad_corrections(on=None):\n        '''\n        Set ascender / descender corrections on or off.\n        '''\n        if on is not None:\n            _globals.skip_quad_corrections = bool(on)\n            if g_use_extra:\n                extra.set_skip_quad_corrections(_globals.skip_quad_corrections)\n        return _globals.skip_quad_corrections\n\n    # fixme: also defined at top-level.\n    JM_annot_id_stem = 'fitz'\n\n    fitz_config = JM_fitz_config()\n\n\n# Callbacks not yet supported with cppyy.\nif not mupdf_cppyy:\n    mupdf.fz_set_warning_callback(JM_mupdf_warning)\n    mupdf.fz_set_error_callback(JM_mupdf_error)\n\n\n# If there are pending warnings when we exit, we end up in this sequence:\n#\n#   atexit()\n#   -> mupdf::internal_thread_state::~internal_thread_state()\n#   -> fz_drop_context()\n#   -> fz_flush_warnings()\n#   -> SWIG Director code\n#   -> Python calling JM_mupdf_warning().\n#\n# Unfortunately this causes a SEGV, seemingly because the SWIG Director code has\n# already been torn down.\n#\n# So we use a Python atexit handler to explicitly call fz_flush_warnings();\n# this appears to happen early enough for the Director machinery to still\n# work. So in the sequence above, fz_flush_warnings() will find that there are\n# no pending warnings and will not attempt to call JM_mupdf_warning().\n#\ndef _atexit():\n    #log( 'PyMuPDF/src/__init__.py:_atexit() called')\n    mupdf.fz_flush_warnings()\n    mupdf.fz_set_warning_callback(None)\n    mupdf.fz_set_error_callback(None)\n    #log( '_atexit() returning')\natexit.register( _atexit)\n\n\n# List of (name, red, green, blue) where:\n#   name: upper-case name.\n#   red, green, blue: integer in range 0..255.\n#\nfrom . import _wxcolors\n_wxcolors = _wxcolors._wxcolors\n\n\n# Dict mapping from name to (red, green, blue).\n#   name: lower-case name.\n#   red, green, blue: float in range 0..1.\n#\npdfcolor = dict()\nfor name, r, g, b in _wxcolors:\n    pdfcolor[name.lower()] = (r/255, g/255, b/255)\n\n\ndef colors_pdf_dict():\n    '''\n    Returns dict mapping from name to (red, green, blue).\n        name: lower-case name.\n        red, green, blue: float in range 0..1.\n    '''\n    return pdfcolor\n\n\ndef colors_wx_list():\n    '''\n    Returns list of (name, red, green, blue) tuples:\n        name: upper-case name.\n        red, green, blue: integers in range 0..255.\n    '''\n    return _wxcolors\n\n\ndef _mupdf_devel(make_links=True):\n    '''\n    Allows PyMuPDF installation to be used to compile and link programmes that\n    use the MuPDF C/C++ API.\n    \n    Args:\n        make_links:\n            If true, then on non-windows we also create softlinks to any shared\n            libraries that are supplied with a version suffix; this allows them\n            to be used in a link command.\n\n            For example we create links such as:\n\n            site-packages/pymupdf/\n                libmupdf.so -> libmupdf.so.26.7\n                libmupdfcpp.so -> libmupdfcpp.so.26.7\n    \n    Returns: (mupdf_include, mupdf_lib).\n        mupdf_include:\n            Path of MuPDF include directory within PyMuPDF install.\n        mupdf_lib\n            Path of MuPDF library directory within PyMuPDF install.\n    '''\n    import platform\n    \n    log(f'{mupdf_version=}')\n    \n    p = os.path.normpath(f'{__file__}/..')\n\n    mupdf_include = f'{p}/mupdf-devel/include'\n    \n    if platform.system() == 'Windows':\n        # Separate .lib files are used at build time.\n        mupdf_lib = f'{p}/mupdf-devel/lib'\n    else:\n        # .so files are used for both buildtime and runtime linking.\n        mupdf_lib = p\n    log(f'Within installed PyMuPDF:')\n    log(f'    {mupdf_include=}')\n    log(f'    {mupdf_lib=}')\n\n    assert os.path.isdir(mupdf_include), f'Not a directory: {mupdf_include=}.'\n    assert os.path.isdir(mupdf_lib), f'Not a directory: {mupdf_lib=}.'\n\n    if platform.system() != 'Windows' and make_links:\n        # Make symbolic links within the installed pymupdf module so\n        # that ld can find libmupdf.so etc. This is a bit of a hack, but\n        # necessary because wheels cannot contain symbolic links.\n        #\n        # For example we create `libmupdf.so -> libmupdf.so.24.8`.\n        #\n        # We are careful to only create symlinks for the expected MuPDF\n        # version, in case old .so files from a previous install are still\n        # in place.\n        #\n        log(f'Creating symlinks in {mupdf_lib=} for MuPDF-{mupdf_version} .so files.')\n        regex_suffix = mupdf_version.split('.')[1:3]\n        regex_suffix = '[.]'.join(regex_suffix)\n        mupdf_lib_regex = f'^(lib[^.]+[.]so)[.]{regex_suffix}$'\n        log(f'{mupdf_lib_regex=}.')\n        for leaf in os.listdir(mupdf_lib):\n            m = re.match(mupdf_lib_regex, leaf)\n            if m:\n                pfrom = f'{mupdf_lib}/{m.group(1)}'\n                # os.path.exists() can return false if softlink exists\n                # but points to non-existent file, so we also use\n                # `os.path.islink()`.\n                if os.path.islink(pfrom) or os.path.exists(pfrom):\n                    log(f'Removing existing link {pfrom=}.')\n                    os.remove(pfrom)\n                log(f'Creating symlink: {pfrom} -> {leaf}')\n                os.symlink(leaf, pfrom)\n    \n    return mupdf_include, mupdf_lib\n\n\n# We cannot import utils earlier because it imports this .py file itself and\n# uses some pymupdf.* types in function typing.\n#\nfrom . import utils\n\n\n# Use utils.*() fns for some class methods.\n#\nrecover_bbox_quad           = utils.recover_bbox_quad\nrecover_char_quad           = utils.recover_char_quad\nrecover_line_quad           = utils.recover_line_quad\nrecover_quad                = utils.recover_quad\nrecover_span_quad           = utils.recover_span_quad\n\nfrom . import table\n\n\nclass FitzDeprecation(DeprecationWarning):\n    pass\n\ndef restore_aliases():\n    warnings.filterwarnings( \"once\", category=FitzDeprecation)\n\n    def showthis(msg, cat, filename, lineno, file=None, line=None):\n        text = warnings.formatwarning(msg, cat, filename, lineno, line=line)\n        s = text.find(\"FitzDeprecation\")\n        if s < 0:\n            log(text)\n            return\n        text = text[s:].splitlines()[0][4:]\n        log(text)\n\n    warnings.showwarning = showthis\n\n    def _alias(class_, new_name, legacy_name=None):\n        '''\n        Adds an alias for a class_ or module item clled <class_>.<new>.\n\n        class_:\n            Class/module to modify; use None for the current module.\n        new_name:\n            String name of existing item, e.g. name of method.\n        legacy_name:\n            Name of legacy object to create in <class_>. If None, we generate\n            from <item> by removing underscores and capitalising the next\n            letter.\n        '''\n        if class_ is None:\n            class_ = sys.modules[__name__]\n        if not legacy_name:\n            legacy_name = ''\n            capitalise_next = False\n            for c in new_name:\n                if c == '_':\n                    capitalise_next = True\n                elif capitalise_next:\n                    legacy_name += c.upper()\n                    capitalise_next = False\n                else:\n                    legacy_name += c\n        new_object = getattr( class_, new_name)\n        assert not getattr( class_, legacy_name, None), f'class {class_} already has {legacy_name}'\n        if callable( new_object):\n            def deprecated_function( *args, **kwargs):\n                warnings.warn(\n                        f'\"{legacy_name=}\" removed from {class_} after v1.19.0 - use \"{new_name}\".',\n                        category=FitzDeprecation,\n                        )\n                return new_object( *args, **kwargs)\n            setattr( class_, legacy_name, deprecated_function)\n            deprecated_function.__doc__ = (\n                    f'*** Deprecated and removed in version after v1.19.0 - use \"{new_name}\". ***\\n'\n                    f'{new_object.__doc__}'\n                    )\n        else:\n            setattr( class_, legacy_name, new_object)\n\n    _alias( Annot, 'get_file',              'fileGet')\n    _alias( Annot, 'get_pixmap')\n    _alias( Annot, 'get_sound',             'soundGet')\n    _alias( Annot, 'get_text')\n    _alias( Annot, 'get_textbox')\n    _alias( Annot, 'get_textpage',          'getTextPage')\n    _alias( Annot, 'line_ends')\n    _alias( Annot, 'set_blendmode',         'setBlendMode')\n    _alias( Annot, 'set_border')\n    _alias( Annot, 'set_colors')\n    _alias( Annot, 'set_flags')\n    _alias( Annot, 'set_info')\n    _alias( Annot, 'set_line_ends')\n    _alias( Annot, 'set_name')\n    _alias( Annot, 'set_oc', 'setOC')\n    _alias( Annot, 'set_opacity')\n    _alias( Annot, 'set_rect')\n    _alias( Annot, 'update_file',           'fileUpd')\n    _alias( DisplayList, 'get_pixmap')\n    _alias( DisplayList, 'get_textpage',    'getTextPage')\n    _alias( Document, 'chapter_count')\n    _alias( Document, 'chapter_page_count')\n    _alias( Document, 'convert_to_pdf',     'convertToPDF')\n    _alias( Document, 'copy_page')\n    _alias( Document, 'delete_page')\n    _alias( Document, 'delete_pages',       'deletePageRange')\n    _alias( Document, 'embfile_add',        'embeddedFileAdd')\n    _alias( Document, 'embfile_count',      'embeddedFileCount')\n    _alias( Document, 'embfile_del',        'embeddedFileDel')\n    _alias( Document, 'embfile_get',        'embeddedFileGet')\n    _alias( Document, 'embfile_info',       'embeddedFileInfo')\n    _alias( Document, 'embfile_names',      'embeddedFileNames')\n    _alias( Document, 'embfile_upd',        'embeddedFileUpd')\n    _alias( Document, 'extract_font')\n    _alias( Document, 'extract_image')\n    _alias( Document, 'find_bookmark')\n    _alias( Document, 'fullcopy_page')\n    _alias( Document, 'get_char_widths')\n    _alias( Document, 'get_ocgs',           'getOCGs')\n    _alias( Document, 'get_page_fonts',     'getPageFontList')\n    _alias( Document, 'get_page_images',    'getPageImageList')\n    _alias( Document, 'get_page_pixmap')\n    _alias( Document, 'get_page_text')\n    _alias( Document, 'get_page_xobjects',  'getPageXObjectList')\n    _alias( Document, 'get_sigflags',       'getSigFlags')\n    _alias( Document, 'get_toc', 'getToC')\n    _alias( Document, 'get_xml_metadata')\n    _alias( Document, 'insert_page')\n    _alias( Document, 'insert_pdf',         'insertPDF')\n    _alias( Document, 'is_dirty')\n    _alias( Document, 'is_form_pdf',        'isFormPDF')\n    _alias( Document, 'is_pdf', 'isPDF')\n    _alias( Document, 'is_reflowable')\n    _alias( Document, 'is_repaired')\n    _alias( Document, 'last_location')\n    _alias( Document, 'load_page')\n    _alias( Document, 'make_bookmark')\n    _alias( Document, 'move_page')\n    _alias( Document, 'needs_pass')\n    _alias( Document, 'new_page')\n    _alias( Document, 'next_location')\n    _alias( Document, 'page_count')\n    _alias( Document, 'page_cropbox',       'pageCropBox')\n    _alias( Document, 'page_xref')\n    _alias( Document, 'pdf_catalog',        'PDFCatalog')\n    _alias( Document, 'pdf_trailer',        'PDFTrailer')\n    _alias( Document, 'prev_location',      'previousLocation')\n    _alias( Document, 'resolve_link')\n    _alias( Document, 'search_page_for')\n    _alias( Document, 'set_language')\n    _alias( Document, 'set_metadata')\n    _alias( Document, 'set_toc', 'setToC')\n    _alias( Document, 'set_xml_metadata')\n    _alias( Document, 'update_object')\n    _alias( Document, 'update_stream')\n    _alias( Document, 'xref_is_stream',     'isStream')\n    _alias( Document, 'xref_length')\n    _alias( Document, 'xref_object')\n    _alias( Document, 'xref_stream')\n    _alias( Document, 'xref_stream_raw')\n    _alias( Document, 'xref_xml_metadata',  'metadataXML')\n    _alias( IRect, 'get_area')\n    _alias( IRect, 'get_area',              'getRectArea')\n    _alias( IRect, 'include_point')\n    _alias( IRect, 'include_rect')\n    _alias( IRect, 'is_empty')\n    _alias( IRect, 'is_infinite')\n    _alias( Link, 'is_external')\n    _alias( Link, 'set_border')\n    _alias( Link, 'set_colors')\n    _alias( Matrix, 'is_rectilinear')\n    _alias( Matrix, 'prerotate',            'preRotate')\n    _alias( Matrix, 'prescale',             'preScale')\n    _alias( Matrix, 'preshear',             'preShear')\n    _alias( Matrix, 'pretranslate',         'preTranslate')\n    _alias( None, 'get_pdf_now',            'getPDFnow')\n    _alias( None, 'get_pdf_str',            'getPDFstr')\n    _alias( None, 'get_text_length')\n    _alias( None, 'get_text_length',        'getTextlength')\n    _alias( None, 'image_profile',          'ImageProperties')\n    _alias( None, 'paper_rect',             'PaperRect')\n    _alias( None, 'paper_size',             'PaperSize')\n    _alias( None, 'paper_sizes')\n    _alias( None, 'planish_line')\n    _alias( Outline, 'is_external')\n    _alias( Outline, 'is_open')\n    _alias( Page, 'add_caret_annot')\n    _alias( Page, 'add_circle_annot')\n    _alias( Page, 'add_file_annot')\n    _alias( Page, 'add_freetext_annot')\n    _alias( Page, 'add_highlight_annot')\n    _alias( Page, 'add_ink_annot')\n    _alias( Page, 'add_line_annot')\n    _alias( Page, 'add_polygon_annot')\n    _alias( Page, 'add_polyline_annot')\n    _alias( Page, 'add_rect_annot')\n    _alias( Page, 'add_redact_annot')\n    _alias( Page, 'add_squiggly_annot')\n    _alias( Page, 'add_stamp_annot')\n    _alias( Page, 'add_strikeout_annot')\n    _alias( Page, 'add_text_annot')\n    _alias( Page, 'add_underline_annot')\n    _alias( Page, 'add_widget')\n    _alias( Page, 'clean_contents')\n    _alias( Page, 'cropbox',                'CropBox')\n    _alias( Page, 'cropbox_position',       'CropBoxPosition')\n    _alias( Page, 'delete_annot')\n    _alias( Page, 'delete_link')\n    _alias( Page, 'delete_widget')\n    _alias( Page, 'derotation_matrix')\n    _alias( Page, 'draw_bezier')\n    _alias( Page, 'draw_circle')\n    _alias( Page, 'draw_curve')\n    _alias( Page, 'draw_line')\n    _alias( Page, 'draw_oval')\n    _alias( Page, 'draw_polyline')\n    _alias( Page, 'draw_quad')\n    _alias( Page, 'draw_rect')\n    _alias( Page, 'draw_sector')\n    _alias( Page, 'draw_squiggle')\n    _alias( Page, 'draw_zigzag')\n    _alias( Page, 'first_annot')\n    _alias( Page, 'first_link')\n    _alias( Page, 'first_widget')\n    _alias( Page, 'get_contents')\n    _alias( Page, 'get_displaylist',        'getDisplayList')\n    _alias( Page, 'get_drawings')\n    _alias( Page, 'get_fonts',              'getFontList')\n    _alias( Page, 'get_image_bbox')\n    _alias( Page, 'get_images',             'getImageList')\n    _alias( Page, 'get_links')\n    _alias( Page, 'get_pixmap')\n    _alias( Page, 'get_svg_image',          'getSVGimage')\n    _alias( Page, 'get_text')\n    _alias( Page, 'get_text_blocks')\n    _alias( Page, 'get_text_words')\n    _alias( Page, 'get_textbox')\n    _alias( Page, 'get_textpage',           'getTextPage')\n    _alias( Page, 'insert_font')\n    _alias( Page, 'insert_image')\n    _alias( Page, 'insert_link')\n    _alias( Page, 'insert_text')\n    _alias( Page, 'insert_textbox')\n    _alias( Page, 'is_wrapped',             '_isWrapped')\n    _alias( Page, 'load_annot')\n    _alias( Page, 'load_links')\n    _alias( Page, 'mediabox',               'MediaBox')\n    _alias( Page, 'mediabox_size',          'MediaBoxSize')\n    _alias( Page, 'new_shape')\n    _alias( Page, 'read_contents')\n    _alias( Page, 'rotation_matrix')\n    _alias( Page, 'search_for')\n    _alias( Page, 'set_cropbox',            'setCropBox')\n    _alias( Page, 'set_mediabox',           'setMediaBox')\n    _alias( Page, 'set_rotation')\n    _alias( Page, 'show_pdf_page',          'showPDFpage')\n    _alias( Page, 'transformation_matrix')\n    _alias( Page, 'update_link')\n    _alias( Page, 'wrap_contents')\n    _alias( Page, 'write_text')\n    _alias( Pixmap, 'clear_with')\n    _alias( Pixmap, 'copy',                 'copyPixmap')\n    _alias( Pixmap, 'gamma_with')\n    _alias( Pixmap, 'invert_irect',         'invertIRect')\n    _alias( Pixmap, 'pil_save',             'pillowWrite')\n    _alias( Pixmap, 'pil_tobytes',          'pillowData')\n    _alias( Pixmap, 'save',                 'writeImage')\n    _alias( Pixmap, 'save',                 'writePNG')\n    _alias( Pixmap, 'set_alpha')\n    _alias( Pixmap, 'set_dpi',              'setResolution')\n    _alias( Pixmap, 'set_origin')\n    _alias( Pixmap, 'set_pixel')\n    _alias( Pixmap, 'set_rect')\n    _alias( Pixmap, 'tint_with')\n    _alias( Pixmap, 'tobytes',              'getImageData')\n    _alias( Pixmap, 'tobytes',              'getPNGData')\n    _alias( Pixmap, 'tobytes',              'getPNGdata')\n    _alias( Quad, 'is_convex')\n    _alias( Quad, 'is_empty')\n    _alias( Quad, 'is_rectangular')\n    _alias( Rect, 'get_area')\n    _alias( Rect, 'get_area',               'getRectArea')\n    _alias( Rect, 'include_point')\n    _alias( Rect, 'include_rect')\n    _alias( Rect, 'is_empty')\n    _alias( Rect, 'is_infinite')\n    _alias( TextWriter, 'fill_textbox')\n    _alias( TextWriter, 'write_text')\n    _alias( Shape, 'draw_bezier')\n    _alias( Shape, 'draw_circle')\n    _alias( Shape, 'draw_curve')\n    _alias( Shape, 'draw_line')\n    _alias( Shape, 'draw_oval')\n    _alias( Shape, 'draw_polyline')\n    _alias( Shape, 'draw_quad')\n    _alias( Shape, 'draw_rect')\n    _alias( Shape, 'draw_sector')\n    _alias( Shape, 'draw_squiggle')\n    _alias( Shape, 'draw_zigzag')\n    _alias( Shape, 'insert_text')\n    _alias( Shape, 'insert_textbox')\n\nif 0:\n    restore_aliases()\n\n__version__ = VersionBind\n__doc__ = (\n        f'PyMuPDF {VersionBind}: Python bindings for the MuPDF {VersionFitz} library.\\n'\n        f'Python {sys.version_info[0]}.{sys.version_info[1]} running on {sys.platform} ({64 if sys.maxsize > 2**32 else 32}-bit).\\n'\n        )\n"
  },
  {
    "path": "src/__main__.py",
    "content": "# -----------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n# Part of \"PyMuPDF\", Python bindings for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# -----------------------------------------------------------------------------\nimport argparse\nimport bisect\nimport os\nimport sys\nimport statistics\nfrom typing import Dict, List, Set\n\nfrom . import pymupdf\n\ndef mycenter(x):\n    return (f\" {x} \").center(75, \"-\")\n\n\ndef recoverpix(doc, item):\n    \"\"\"Return image for a given XREF.\"\"\"\n    x = item[0]  # xref of PDF image\n    s = item[1]  # xref of its /SMask\n    if s == 0:  # no smask: use direct image output\n        return doc.extract_image(x)\n\n    def getimage(pix):\n        if pix.colorspace.n != 4:\n            return pix\n        tpix = pymupdf.Pixmap(pymupdf.csRGB, pix)\n        return tpix\n\n    # we need to reconstruct the alpha channel with the smask\n    pix1 = pymupdf.Pixmap(doc, x)\n    pix2 = pymupdf.Pixmap(doc, s)  # create pixmap of the /SMask entry\n\n    \"\"\"Sanity check:\n    - both pixmaps must have the same rectangle\n    - both pixmaps must have alpha=0\n    - pix2 must consist of 1 byte per pixel\n    \"\"\"\n    if not (pix1.irect == pix2.irect and pix1.alpha == pix2.alpha == 0 and pix2.n == 1):\n        pymupdf.message(f\"Warning: unsupported /SMask {s} for {x}:\")\n        pymupdf.message(pix2)\n        pix2 = None\n        return getimage(pix1)  # return the pixmap as is\n\n    pix = pymupdf.Pixmap(pix1)  # copy of pix1, with an alpha channel added\n    pix.set_alpha(pix2.samples)  # treat pix2.samples as the alpha values\n    pix1 = pix2 = None  # free temp pixmaps\n\n    # we may need to adjust something for CMYK pixmaps here:\n    return getimage(pix)\n\n\ndef open_file(filename, password, show=False, pdf=True):\n    \"\"\"Open and authenticate a document.\"\"\"\n    doc = pymupdf.open(filename)\n    if not doc.is_pdf and pdf is True:\n        sys.exit(\"this command supports PDF files only\")\n    rc = -1\n    if not doc.needs_pass:\n        return doc\n    if password:\n        rc = doc.authenticate(password)\n        if not rc:\n            sys.exit(\"authentication unsuccessful\")\n        if show is True:\n            auth_level = \"user\"\n            if rc > 2:\n                auth_level = \"owner\"\n            pymupdf.message(f\"authenticated as {auth_level}\")\n    else:\n        sys.exit(f\"'{doc.name}' requires a password\")\n    return doc\n\n\ndef print_dict(item):\n    \"\"\"Print a Python dictionary.\"\"\"\n    l = max([len(k) for k in item.keys()]) + 1\n    for k, v in item.items():\n        msg = f\"{k.rjust(l)}: {v}\"\n        pymupdf.message(msg)\n\n\ndef print_xref(doc, xref):\n    \"\"\"Print an object given by XREF number.\n\n    Simulate the PDF source in \"pretty\" format.\n    For a stream also print its size.\n    \"\"\"\n    pymupdf.message(f\"{xref:d} 0 obj\")\n    xref_str = doc.xref_object(xref)\n    pymupdf.message(xref_str)\n    if doc.xref_is_stream(xref):\n        temp = xref_str.split()\n        try:\n            idx = temp.index(\"/Length\") + 1\n            size = temp[idx]\n            if size.endswith(\"0 R\"):\n                size = \"unknown\"\n        except Exception:\n            size = \"unknown\"\n        pymupdf.message(f\"stream\\n...{size} bytes\")\n        pymupdf.message(\"endstream\")\n    pymupdf.message(\"endobj\")\n\n\ndef get_list(rlist, limit, what=\"page\"):\n    \"\"\"Transform a page / xref specification into a list of integers.\n\n    Args\n    ----\n        rlist: (str) the specification\n        limit: maximum number, i.e. number of pages, number of objects\n        what: a string to be used in error messages\n    Returns\n    -------\n        A list of integers representing the specification.\n    \"\"\"\n    N = str(limit - 1)\n    rlist = rlist.replace(\"N\", N).replace(\" \", \"\")\n    rlist_arr = rlist.split(\",\")\n    out_list = []\n    for seq, item in enumerate(rlist_arr):\n        n = seq + 1\n        if item.isdecimal():  # a single integer\n            i = int(item)\n            if 1 <= i < limit:\n                out_list.append(int(item))\n            else:\n                sys.exit(f\"bad {what} specification at item {n:d}\")\n            continue\n        try:  # this must be a range now, and all of the following must work:\n            i1, i2 = item.split(\"-\")  # will fail if not 2 items produced\n            i1 = int(i1)  # will fail on non-integers\n            i2 = int(i2)\n        except Exception:\n            sys.exit(f\"bad {what} range specification at item {n:d}\")\n\n        if not (1 <= i1 < limit and 1 <= i2 < limit):\n            sys.exit(f\"bad {what} range specification at item {n:d}\")\n\n        if i1 == i2:  # just in case: a range of equal numbers\n            out_list.append(i1)\n            continue\n\n        if i1 < i2:  # first less than second\n            out_list += list(range(i1, i2 + 1))\n        else:  # first larger than second\n            out_list += list(range(i1, i2 - 1, -1))\n\n    return out_list\n\n\ndef show(args):\n    doc = open_file(args.input, args.password, True)\n    size = os.path.getsize(args.input) / 1024\n    flag = \"KB\"\n    if size > 1000:\n        size /= 1024\n        flag = \"MB\"\n    size = round(size, 1)\n    meta = doc.metadata # pylint: disable=no-member\n    pymupdf.message(\n        \"'%s', pages: %i, objects: %i, %g %s, %s, encryption: %s\"\n        % (\n            args.input,\n            doc.page_count,\n            doc.xref_length() - 1,\n            size,\n            flag,\n            meta[\"format\"],\n            meta[\"encryption\"],\n        )\n    )\n    n = doc.is_form_pdf\n    if n > 0:\n        s = doc.get_sigflags()\n        sign_str = \"\"\n        if s != 3:\n            sign_str = \"not \"\n        pymupdf.message(f\"document contains {n} root form fields and is {sign_str}signed\")\n    n = doc.embfile_count()\n    if n > 0:\n        pymupdf.message(f\"document contains {n:d} embedded files\")\n    pymupdf.message()\n    if args.catalog:\n        pymupdf.message(mycenter(\"PDF catalog\"))\n        xref = doc.pdf_catalog()\n        print_xref(doc, xref)\n        pymupdf.message()\n    if args.metadata:\n        pymupdf.message(mycenter(\"PDF metadata\"))\n        print_dict(doc.metadata)    # pylint: disable=no-member\n        pymupdf.message()\n    if args.xrefs:\n        pymupdf.message(mycenter(\"object information\"))\n        xrefl = get_list(args.xrefs, doc.xref_length(), what=\"xref\")\n        for xref in xrefl:\n            print_xref(doc, xref)\n            pymupdf.message()\n    if args.pages:\n        pymupdf.message(mycenter(\"page information\"))\n        pagel = get_list(args.pages, doc.page_count + 1)\n        for pno in pagel:\n            n = pno - 1\n            xref = doc.page_xref(n)\n            pymupdf.message(f\"Page {pno:d}:\")\n            print_xref(doc, xref)\n            pymupdf.message()\n    if args.trailer:\n        pymupdf.message(mycenter(\"PDF trailer\"))\n        pymupdf.message(doc.pdf_trailer())\n        pymupdf.message()\n    doc.close()\n\n\ndef clean(args):\n    doc = open_file(args.input, args.password, pdf=True)\n    encryption = args.encryption\n    encrypt = (\"keep\", \"none\", \"rc4-40\", \"rc4-128\", \"aes-128\", \"aes-256\").index(\n        encryption\n    )\n\n    if not args.pages:  # simple cleaning\n        doc.save(\n            args.output,\n            garbage=args.garbage,\n            deflate=args.compress,\n            pretty=args.pretty,\n            clean=args.sanitize,\n            ascii=args.ascii,\n            linear=args.linear,\n            encryption=encrypt,\n            owner_pw=args.owner,\n            user_pw=args.user,\n            permissions=args.permission,\n        )\n        return\n\n    # create sub document from page numbers\n    pages = get_list(args.pages, doc.page_count + 1)\n    outdoc = pymupdf.open()\n    for pno in pages:\n        n = pno - 1\n        outdoc.insert_pdf(doc, from_page=n, to_page=n)\n    outdoc.save(\n        args.output,\n        garbage=args.garbage,\n        deflate=args.compress,\n        pretty=args.pretty,\n        clean=args.sanitize,\n        ascii=args.ascii,\n        linear=args.linear,\n        encryption=encrypt,\n        owner_pw=args.owner,\n        user_pw=args.user,\n        permissions=args.permission,\n    )\n    doc.close()\n    outdoc.close()\n    return\n\n\ndef doc_join(args):\n    \"\"\"Join pages from several PDF documents.\"\"\"\n    doc_list = args.input  # a list of input PDFs\n    doc = pymupdf.open()  # output PDF\n    for src_item in doc_list:  # process one input PDF\n        src_list = src_item.split(\",\")\n        password = src_list[1] if len(src_list) > 1 else None\n        src = open_file(src_list[0], password, pdf=True)\n        pages = \",\".join(src_list[2:])  # get 'pages' specifications\n        if pages:  # if anything there, retrieve a list of desired pages\n            page_list = get_list(\",\".join(src_list[2:]), src.page_count + 1)\n        else:  # take all pages\n            page_list = range(1, src.page_count + 1)\n        for i in page_list:\n            doc.insert_pdf(src, from_page=i - 1, to_page=i - 1)  # copy each source page\n        src.close()\n\n    doc.save(args.output, garbage=4, deflate=True)\n    doc.close()\n\n\ndef embedded_copy(args):\n    \"\"\"Copy embedded files between PDFs.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        not args.output or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n    src = open_file(args.source, args.pwdsource)\n    names = set(args.name) if args.name else set()\n    src_names = set(src.embfile_names())\n    if names:\n        if not names <= src_names:\n            sys.exit(\"not all names are contained in source\")\n    else:\n        names = src_names\n    if not names:\n        sys.exit(\"nothing to copy\")\n    intersect = names & set(doc.embfile_names())  # any equal name already in target?\n    if intersect:\n        sys.exit(f\"following names already exist in receiving PDF: {str(intersect)}\")\n\n    for item in names:\n        info = src.embfile_info(item)\n        buff = src.embfile_get(item)\n        doc.embfile_add(\n            item,\n            buff,\n            filename=info[\"filename\"],\n            ufilename=info[\"ufilename\"],\n            desc=info[\"desc\"],\n        )\n        pymupdf.message(f\"copied entry '{item}' from '{src.name}'\")\n    src.close()\n    if args.output and args.output != args.input:\n        doc.save(args.output, garbage=3)\n    else:\n        doc.saveIncr()\n    doc.close()\n\n\ndef embedded_del(args):\n    \"\"\"Delete an embedded file entry.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        not args.output or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n\n    try:\n        doc.embfile_del(args.name)\n    except (ValueError, pymupdf.mupdf.FzErrorBase) as e:\n        sys.exit(f'no such embedded file {args.name!r}: {e}')\n    if not args.output or args.output == args.input:\n        doc.saveIncr()\n    else:\n        doc.save(args.output, garbage=1)\n    doc.close()\n\n\ndef embedded_get(args):\n    \"\"\"Retrieve contents of an embedded file.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    try:\n        stream = doc.embfile_get(args.name)\n        d = doc.embfile_info(args.name)\n    except (ValueError, pymupdf.mupdf.FzErrorBase) as e:\n        sys.exit(f'no such embedded file {args.name!r}: {e}')\n    filename = args.output if args.output else d[\"filename\"]\n    if not args.unsafe and not args.output:\n        if os.path.exists(filename):\n            sys.exit(f'refusing to overwrite existing file with stored name: {filename}')\n        filename_abs = os.path.abspath(filename)\n        if not filename_abs.startswith(os.getcwd() + os.sep):\n            sys.exit(f'refusing to write stored name outside current directory: {filename}')\n    with open(filename, \"wb\") as output:\n        output.write(stream)\n    pymupdf.message(f\"saved entry '{args.name}' as '{filename}'\")\n    doc.close()\n\n\ndef embedded_add(args):\n    \"\"\"Insert a new embedded file.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        args.output is None or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n\n    try:\n        doc.embfile_del(args.name)\n        sys.exit(f\"entry '{args.name}' already exists\")\n    except Exception:\n        pass\n\n    if not os.path.exists(args.path) or not os.path.isfile(args.path):\n        sys.exit(f\"no such file '{args.path}'\")\n    with open(args.path, \"rb\") as f:\n        stream = f.read()\n    filename = args.path\n    ufilename = filename\n    if not args.desc:\n        desc = filename\n    else:\n        desc = args.desc\n    doc.embfile_add(\n        args.name, stream, filename=filename, ufilename=ufilename, desc=desc\n    )\n    if not args.output or args.output == args.input:\n        doc.saveIncr()\n    else:\n        doc.save(args.output, garbage=3)\n    doc.close()\n\n\ndef embedded_upd(args):\n    \"\"\"Update contents or metadata of an embedded file.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        args.output is None or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n\n    try:\n        doc.embfile_info(args.name)\n    except Exception:\n        sys.exit(f\"no such embedded file '{args.name}'\")\n\n    if (\n        args.path is not None\n        and os.path.exists(args.path)\n        and os.path.isfile(args.path)\n    ):\n        with open(args.path, \"rb\") as f:\n            stream = f.read()\n    else:\n        stream = None\n\n    if args.filename:\n        filename = args.filename\n    else:\n        filename = None\n\n    if args.ufilename:\n        ufilename = args.ufilename\n    elif args.filename:\n        ufilename = args.filename\n    else:\n        ufilename = None\n\n    if args.desc:\n        desc = args.desc\n    else:\n        desc = None\n\n    doc.embfile_upd(\n        args.name, stream, filename=filename, ufilename=ufilename, desc=desc\n    )\n    if args.output is None or args.output == args.input:\n        doc.saveIncr()\n    else:\n        doc.save(args.output, garbage=3)\n    doc.close()\n\n\ndef embedded_list(args):\n    \"\"\"List embedded files.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    names = doc.embfile_names()\n    if args.name is not None:\n        if args.name not in names:\n            sys.exit(f\"no such embedded file '{args.name}'\")\n        else:\n            pymupdf.message()\n            plural = \"\"\n            if len(names) > 1:\n                plural = \"s\"\n            pymupdf.message(f\"printing 1 of {len(names):d} embedded file{plural}:\")\n            pymupdf.message()\n            print_dict(doc.embfile_info(args.name))\n            pymupdf.message()\n            return\n    if not names:\n        pymupdf.message(f\"'{doc.name}' contains no embedded files\")\n        return\n\n    if len(names) > 1:\n        msg = f\"'{doc.name}' contains the following {len(names):d} embedded files\"\n    else:\n        msg = f\"'{doc.name}' contains the following embedded file\"\n    pymupdf.message(msg)\n    pymupdf.message()\n    for name in names:\n        if not args.detail:\n            pymupdf.message(name)\n            continue\n        _ = doc.embfile_info(name)\n        print_dict(doc.embfile_info(name))\n        pymupdf.message()\n    doc.close()\n\n\ndef extract_objects(args):\n    \"\"\"Extract images and / or fonts from a PDF.\"\"\"\n    if not args.fonts and not args.images:\n        sys.exit(\"neither fonts nor images requested\")\n    doc = open_file(args.input, args.password, pdf=True)\n\n    if args.pages:\n        pages = get_list(args.pages, doc.page_count + 1)\n    else:\n        pages = range(1, doc.page_count + 1)\n\n    if not args.output:\n        out_dir = os.path.abspath(os.curdir)\n    else:\n        out_dir = args.output\n        if not (os.path.exists(out_dir) and os.path.isdir(out_dir)):\n            sys.exit(f\"output directory {out_dir} does not exist\")\n\n    font_xrefs = set()  # already saved fonts\n    image_xrefs = set()  # already saved images\n\n    for pno in pages:\n        if args.fonts:\n            itemlist = doc.get_page_fonts(pno - 1)\n            for item in itemlist:\n                xref = item[0]\n                if xref not in font_xrefs:\n                    font_xrefs.add(xref)\n                    fontname, ext, _, buffer = doc.extract_font(xref)\n                    if ext == \"n/a\" or not buffer:\n                        continue\n                    outname = os.path.join(\n                        out_dir, f\"{fontname.replace(' ', '-')}-{xref}.{ext}\"\n                    )\n                    with open(outname, \"wb\") as outfile:\n                        outfile.write(buffer)\n                    buffer = None\n        if args.images:\n            itemlist = doc.get_page_images(pno - 1)\n            for item in itemlist:\n                xref = item[0]\n                if xref not in image_xrefs:\n                    image_xrefs.add(xref)\n                    pix = recoverpix(doc, item)\n                    if type(pix) is dict:\n                        ext = pix[\"ext\"]\n                        imgdata = pix[\"image\"]\n                        outname = os.path.join(out_dir, f\"img-{xref:d}.{ext}\")\n                        with open(outname, \"wb\") as outfile:\n                            outfile.write(imgdata)\n                    else:\n                        outname = os.path.join(out_dir, f\"img-{xref:d}.png\")\n                        pix2 = (\n                            pix\n                            if pix.colorspace.n < 4\n                            else pymupdf.Pixmap(pymupdf.csRGB, pix)\n                        )\n                        pix2.save(outname)\n\n    if args.fonts:\n        pymupdf.message(f\"saved {len(font_xrefs):d} fonts to '{out_dir}'\")\n    if args.images:\n        pymupdf.message(f\"saved {len(image_xrefs):d} images to '{out_dir}'\")\n    doc.close()\n\n\ndef page_simple(page, textout, GRID, fontsize, noformfeed, skip_empty, flags):\n    eop = b\"\\n\" if noformfeed else bytes([12])\n    text = page.get_text(\"text\", flags=flags)\n    if not text:\n        if not skip_empty:\n            textout.write(eop)  # write formfeed\n        return\n    textout.write(text.encode(\"utf8\", errors=\"surrogatepass\"))\n    textout.write(eop)\n    return\n\n\ndef page_blocksort(page, textout, GRID, fontsize, noformfeed, skip_empty, flags):\n    eop = b\"\\n\" if noformfeed else bytes([12])\n    blocks = page.get_text(\"blocks\", flags=flags)\n    if blocks == []:\n        if not skip_empty:\n            textout.write(eop)  # write formfeed\n        return\n    blocks.sort(key=lambda b: (b[3], b[0]))\n    for b in blocks:\n        textout.write(b[4].encode(\"utf8\", errors=\"surrogatepass\"))\n    textout.write(eop)\n    return\n\n\ndef page_layout(page, textout, GRID, fontsize, noformfeed, skip_empty, flags):\n    eop = b\"\\n\" if noformfeed else bytes([12])\n\n    # --------------------------------------------------------------------\n    def find_line_index(values: List[int], value: int) -> int:\n        \"\"\"Find the right row coordinate.\n\n        Args:\n            values: (list) y-coordinates of rows.\n            value: (int) lookup for this value (y-origin of char).\n        Returns:\n            y-ccordinate of appropriate line for value.\n        \"\"\"\n        i = bisect.bisect_right(values, value)\n        if i:\n            return values[i - 1]\n        raise RuntimeError(f\"Line for {value:g} not found in {values}\")\n\n    # --------------------------------------------------------------------\n    def curate_rows(rows: Set[int], GRID) -> List:\n        rows = list(rows)\n        rows.sort()  # sort ascending\n        nrows = [rows[0]]\n        for h in rows[1:]:\n            if h >= nrows[-1] + GRID:  # only keep significant differences\n                nrows.append(h)\n        return nrows  # curated list of line bottom coordinates\n\n    def process_blocks(blocks: List[Dict], page: pymupdf.Page):\n        rows = set()\n        page_width = page.rect.width\n        page_height = page.rect.height\n        rowheight = page_height\n        left = page_width\n        right = 0\n        chars = []\n        for block in blocks:\n            for line in block[\"lines\"]:\n                if line[\"dir\"] != (1, 0):  # ignore non-horizontal text\n                    continue\n                x0, y0, x1, y1 = line[\"bbox\"]\n                if y1 < 0 or y0 > page.rect.height:  # ignore if outside CropBox\n                    continue\n                # upd row height\n                height = y1 - y0\n\n                if rowheight > height:\n                    rowheight = height\n                for span in line[\"spans\"]:\n                    if span[\"size\"] <= fontsize:\n                        continue\n                    for c in span[\"chars\"]:\n                        x0, _, x1, _ = c[\"bbox\"]\n                        cwidth = x1 - x0\n                        ox, oy = c[\"origin\"]\n                        oy = int(round(oy))\n                        rows.add(oy)\n                        ch = c[\"c\"]\n                        if left > ox and ch != \" \":\n                            left = ox  # update left coordinate\n                        if right < x1:\n                            right = x1  # update right coordinate\n                        # handle ligatures:\n                        if cwidth == 0 and chars != []:  # potential ligature\n                            old_ch, old_ox, old_oy, old_cwidth = chars[-1]\n                            if old_oy == oy:  # ligature\n                                if old_ch != chr(0xFB00):  # previous \"ff\" char lig?\n                                    lig = joinligature(old_ch + ch)  # no\n                                # convert to one of the 3-char ligatures:\n                                elif ch == \"i\":\n                                    lig = chr(0xFB03)  # \"ffi\"\n                                elif ch == \"l\":\n                                    lig = chr(0xFB04)  # \"ffl\"\n                                else:  # something wrong, leave old char in place\n                                    lig = old_ch\n                                chars[-1] = (lig, old_ox, old_oy, old_cwidth)\n                                continue\n                        chars.append((ch, ox, oy, cwidth))  # all chars on page\n        return chars, rows, left, right, rowheight\n\n    def joinligature(lig: str) -> str:\n        \"\"\"Return ligature character for a given pair / triple of characters.\n\n        Args:\n            lig: (str) 2/3 characters, e.g. \"ff\"\n        Returns:\n            Ligature, e.g. \"ff\" -> chr(0xFB00)\n        \"\"\"\n\n        if lig == \"ff\":\n            return chr(0xFB00)\n        elif lig == \"fi\":\n            return chr(0xFB01)\n        elif lig == \"fl\":\n            return chr(0xFB02)\n        elif lig == \"ffi\":\n            return chr(0xFB03)\n        elif lig == \"ffl\":\n            return chr(0xFB04)\n        elif lig == \"ft\":\n            return chr(0xFB05)\n        elif lig == \"st\":\n            return chr(0xFB06)\n        return lig\n\n    # --------------------------------------------------------------------\n    def make_textline(left, slot, minslot, lchars):\n        \"\"\"Produce the text of one output line.\n\n        Args:\n            left: (float) left most coordinate used on page\n            slot: (float) avg width of one character in any font in use.\n            minslot: (float) min width for the characters in this line.\n            chars: (list[tuple]) characters of this line.\n        Returns:\n            text: (str) text string for this line\n        \"\"\"\n        text = \"\"  # we output this\n        old_char = \"\"\n        old_x1 = 0  # end coordinate of last char\n        old_ox = 0  # x-origin of last char\n        if minslot <= pymupdf.EPSILON:\n            raise RuntimeError(f\"program error: minslot too small = {minslot:g}\")\n\n        for c in lchars:  # loop over characters\n            char, ox, _, cwidth = c\n            ox = ox - left  # its (relative) start coordinate\n            x1 = ox + cwidth  # ending coordinate\n\n            # eliminate overprint effect\n            if old_char == char and ox - old_ox <= cwidth * 0.2:\n                continue\n\n            # omit spaces overlapping previous char\n            if char == \" \" and (old_x1 - ox) / cwidth > 0.8:\n                continue\n\n            old_char = char\n            # close enough to previous?\n            if ox < old_x1 + minslot:  # assume char adjacent to previous\n                text += char  # append to output\n                old_x1 = x1  # new end coord\n                old_ox = ox  # new origin.x\n                continue\n\n            # else next char starts after some gap:\n            # fill in right number of spaces, so char is positioned\n            # in the right slot of the line\n            if char == \" \":  # rest relevant for non-space only\n                continue\n            delta = int(ox / slot) - len(text)\n            if ox > old_x1 and delta > 1:\n                text += \" \" * delta\n            # now append char\n            text += char\n            old_x1 = x1  # new end coordinate\n            old_ox = ox  # new origin\n        return text.rstrip()\n\n    # extract page text by single characters (\"rawdict\")\n    blocks = page.get_text(\"rawdict\", flags=flags)[\"blocks\"]\n    chars, rows, left, right, rowheight = process_blocks(blocks, page)\n\n    if chars == []:\n        if not skip_empty:\n            textout.write(eop)  # write formfeed\n        return\n    # compute list of line coordinates - ignoring small (GRID) differences\n    rows = curate_rows(rows, GRID)\n\n    # sort all chars by x-coordinates, so every line will receive char info,\n    # sorted from left to right.\n    chars.sort(key=lambda c: c[1])\n\n    # populate the lines with their char info\n    lines = {}  # key: y1-ccordinate, value: char list\n    for c in chars:\n        _, _, oy, _ = c\n        y = find_line_index(rows, oy)  # y-coord of the right line\n        lchars = lines.get(y, [])  # read line chars so far\n        lchars.append(c)  # append this char\n        lines[y] = lchars  # write back to line\n\n    # ensure line coordinates are ascending\n    keys = list(lines.keys())\n    keys.sort()\n\n    # -------------------------------------------------------------------------\n    # Compute \"char resolution\" for the page: the char width corresponding to\n    # 1 text char position on output - call it 'slot'.\n    # For each line, compute median of its char widths. The minimum across all\n    # lines is 'slot'.\n    # The minimum char width of each line is used to determine if spaces must\n    # be inserted in between two characters.\n    # -------------------------------------------------------------------------\n    slot = right - left\n    minslots = {}\n    for k in keys:\n        lchars = lines[k]\n        ccount = len(lchars)\n        if ccount < 2:\n            minslots[k] = 1\n            continue\n        widths = [c[3] for c in lchars]\n        widths.sort()\n        this_slot = statistics.median(widths)  # take median value\n        if this_slot < slot:\n            slot = this_slot\n        minslots[k] = widths[0]\n\n    # compute line advance in text output\n    rowheight = rowheight * (rows[-1] - rows[0]) / (rowheight * len(rows)) * 1.2\n    rowpos = rows[0]  # first line positioned here\n    textout.write(b\"\\n\")\n    for k in keys:  # walk through the lines\n        while rowpos < k:  # honor distance between lines\n            textout.write(b\"\\n\")\n            rowpos += rowheight\n        text = make_textline(left, slot, minslots[k], lines[k])\n        textout.write((text + \"\\n\").encode(\"utf8\", errors=\"surrogatepass\"))\n        rowpos = k + rowheight\n\n    textout.write(eop)  # write formfeed\n\n\ndef gettext(args):\n    doc = open_file(args.input, args.password, pdf=False)\n    pagel = get_list(args.pages, doc.page_count + 1)\n    output = args.output\n    if output is None:\n        filename, _ = os.path.splitext(doc.name)\n        output = filename + \".txt\"\n    with open(output, \"wb\") as textout:\n        flags = pymupdf.TEXT_PRESERVE_LIGATURES | pymupdf.TEXT_PRESERVE_WHITESPACE\n        if args.convert_white:\n            flags ^= pymupdf.TEXT_PRESERVE_WHITESPACE\n        if args.noligatures:\n            flags ^= pymupdf.TEXT_PRESERVE_LIGATURES\n        if args.extra_spaces:\n            flags ^= pymupdf.TEXT_INHIBIT_SPACES\n        func = {\n            \"simple\": page_simple,\n            \"blocks\": page_blocksort,\n            \"layout\": page_layout,\n        }\n        for pno in pagel:\n            page = doc[pno - 1]\n            func[args.mode](\n                page,\n                textout,\n                args.grid,\n                args.fontsize,\n                args.noformfeed,\n                args.skip_empty,\n                flags=flags,\n            )\n\n\ndef _internal(args):\n    pymupdf.message('This is from PyMuPDF message().')\n    pymupdf.log('This is from PyMuPDF log().')\n\ndef main():\n    \"\"\"Define command configurations.\"\"\"\n    parser = argparse.ArgumentParser(\n        prog=\"pymupdf\",\n        description=mycenter(\"Basic PyMuPDF Functions\"),\n    )\n    subps = parser.add_subparsers(\n        title=\"Subcommands\", help=\"Enter 'command -h' for subcommand specific help\"\n    )\n\n    # -------------------------------------------------------------------------\n    # 'show' command\n    # -------------------------------------------------------------------------\n    ps_show = subps.add_parser(\"show\", description=mycenter(\"display PDF information\"))\n    ps_show.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_show.add_argument(\"-password\", help=\"password\")\n    ps_show.add_argument(\"-catalog\", action=\"store_true\", help=\"show PDF catalog\")\n    ps_show.add_argument(\"-trailer\", action=\"store_true\", help=\"show PDF trailer\")\n    ps_show.add_argument(\"-metadata\", action=\"store_true\", help=\"show PDF metadata\")\n    ps_show.add_argument(\n        \"-xrefs\", type=str, help=\"show selected objects, format: 1,5-7,N\"\n    )\n    ps_show.add_argument(\n        \"-pages\", type=str, help=\"show selected pages, format: 1,5-7,50-N\"\n    )\n    ps_show.set_defaults(func=show)\n\n    # -------------------------------------------------------------------------\n    # 'clean' command\n    # -------------------------------------------------------------------------\n    ps_clean = subps.add_parser(\n        \"clean\", description=mycenter(\"optimize PDF, or create sub-PDF if pages given\")\n    )\n    ps_clean.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_clean.add_argument(\"output\", type=str, help=\"output PDF filename\")\n    ps_clean.add_argument(\"-password\", help=\"password\")\n\n    ps_clean.add_argument(\n        \"-encryption\",\n        help=\"encryption method\",\n        choices=(\"keep\", \"none\", \"rc4-40\", \"rc4-128\", \"aes-128\", \"aes-256\"),\n        default=\"none\",\n    )\n\n    ps_clean.add_argument(\"-owner\", type=str, help=\"owner password\")\n    ps_clean.add_argument(\"-user\", type=str, help=\"user password\")\n\n    ps_clean.add_argument(\n        \"-garbage\",\n        type=int,\n        help=\"garbage collection level\",\n        choices=range(5),\n        default=0,\n    )\n\n    ps_clean.add_argument(\n        \"-compress\",\n        action=\"store_true\",\n        default=False,\n        help=\"compress (deflate) output\",\n    )\n\n    ps_clean.add_argument(\n        \"-ascii\", action=\"store_true\", default=False, help=\"ASCII encode binary data\"\n    )\n\n    ps_clean.add_argument(\n        \"-linear\",\n        action=\"store_true\",\n        default=False,\n        help=\"format for fast web display\",\n    )\n\n    ps_clean.add_argument(\n        \"-permission\", type=int, default=-1, help=\"integer with permission levels\"\n    )\n\n    ps_clean.add_argument(\n        \"-sanitize\",\n        action=\"store_true\",\n        default=False,\n        help=\"sanitize / clean contents\",\n    )\n    ps_clean.add_argument(\n        \"-pretty\", action=\"store_true\", default=False, help=\"prettify PDF structure\"\n    )\n    ps_clean.add_argument(\n        \"-pages\", help=\"output selected pages pages, format: 1,5-7,50-N\"\n    )\n    ps_clean.set_defaults(func=clean)\n\n    # -------------------------------------------------------------------------\n    # 'join' command\n    # -------------------------------------------------------------------------\n    ps_join = subps.add_parser(\n        \"join\",\n        description=mycenter(\"join PDF documents\"),\n        epilog=\"specify each input as 'filename[,password[,pages]]'\",\n    )\n    ps_join.add_argument(\"input\", nargs=\"*\", help=\"input filenames\")\n    ps_join.add_argument(\"-output\", required=True, help=\"output filename\")\n    ps_join.set_defaults(func=doc_join)\n\n    # -------------------------------------------------------------------------\n    # 'extract' command\n    # -------------------------------------------------------------------------\n    ps_extract = subps.add_parser(\n        \"extract\", description=mycenter(\"extract images and fonts to disk\")\n    )\n    ps_extract.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_extract.add_argument(\"-images\", action=\"store_true\", help=\"extract images\")\n    ps_extract.add_argument(\"-fonts\", action=\"store_true\", help=\"extract fonts\")\n    ps_extract.add_argument(\n        \"-output\", help=\"folder to receive output, defaults to current\"\n    )\n    ps_extract.add_argument(\"-password\", help=\"password\")\n    ps_extract.add_argument(\n        \"-pages\", type=str, help=\"consider these pages only, format: 1,5-7,50-N\"\n    )\n    ps_extract.set_defaults(func=extract_objects)\n\n    # -------------------------------------------------------------------------\n    # 'embed-info'\n    # -------------------------------------------------------------------------\n    ps_show = subps.add_parser(\n        \"embed-info\", description=mycenter(\"list embedded files\")\n    )\n    ps_show.add_argument(\"input\", help=\"PDF filename\")\n    ps_show.add_argument(\"-name\", help=\"if given, report only this one\")\n    ps_show.add_argument(\"-detail\", action=\"store_true\", help=\"detail information\")\n    ps_show.add_argument(\"-password\", help=\"password\")\n    ps_show.set_defaults(func=embedded_list)\n\n    # -------------------------------------------------------------------------\n    # 'embed-add' command\n    # -------------------------------------------------------------------------\n    ps_embed_add = subps.add_parser(\n        \"embed-add\", description=mycenter(\"add embedded file\")\n    )\n    ps_embed_add.add_argument(\"input\", help=\"PDF filename\")\n    ps_embed_add.add_argument(\"-password\", help=\"password\")\n    ps_embed_add.add_argument(\n        \"-output\", help=\"output PDF filename, incremental save if none\"\n    )\n    ps_embed_add.add_argument(\"-name\", required=True, help=\"name of new entry\")\n    ps_embed_add.add_argument(\"-path\", required=True, help=\"path to data for new entry\")\n    ps_embed_add.add_argument(\"-desc\", help=\"description of new entry\")\n    ps_embed_add.set_defaults(func=embedded_add)\n\n    # -------------------------------------------------------------------------\n    # 'embed-del' command\n    # -------------------------------------------------------------------------\n    ps_embed_del = subps.add_parser(\n        \"embed-del\", description=mycenter(\"delete embedded file\")\n    )\n    ps_embed_del.add_argument(\"input\", help=\"PDF filename\")\n    ps_embed_del.add_argument(\"-password\", help=\"password\")\n    ps_embed_del.add_argument(\n        \"-output\", help=\"output PDF filename, incremental save if none\"\n    )\n    ps_embed_del.add_argument(\"-name\", required=True, help=\"name of entry to delete\")\n    ps_embed_del.set_defaults(func=embedded_del)\n\n    # -------------------------------------------------------------------------\n    # 'embed-upd' command\n    # -------------------------------------------------------------------------\n    ps_embed_upd = subps.add_parser(\n        \"embed-upd\",\n        description=mycenter(\"update embedded file\"),\n        epilog=\"except '-name' all parameters are optional\",\n    )\n    ps_embed_upd.add_argument(\"input\", help=\"PDF filename\")\n    ps_embed_upd.add_argument(\"-name\", required=True, help=\"name of entry\")\n    ps_embed_upd.add_argument(\"-password\", help=\"password\")\n    ps_embed_upd.add_argument(\n        \"-output\", help=\"Output PDF filename, incremental save if none\"\n    )\n    ps_embed_upd.add_argument(\"-path\", help=\"path to new data for entry\")\n    ps_embed_upd.add_argument(\"-filename\", help=\"new filename to store in entry\")\n    ps_embed_upd.add_argument(\n        \"-ufilename\", help=\"new unicode filename to store in entry\"\n    )\n    ps_embed_upd.add_argument(\"-desc\", help=\"new description to store in entry\")\n    ps_embed_upd.set_defaults(func=embedded_upd)\n\n    # -------------------------------------------------------------------------\n    # 'embed-extract' command\n    # -------------------------------------------------------------------------\n    ps_embed_extract = subps.add_parser(\n        \"embed-extract\", description=mycenter(\"extract embedded file to disk\")\n    )\n    ps_embed_extract.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_embed_extract.add_argument(\"-name\", required=True, help=\"name of entry\")\n    ps_embed_extract.add_argument(\"-password\", help=\"password\")\n    ps_embed_extract.add_argument(\"-unsafe\", default=False, action=\"store_true\",\n        help=\"allow write to stored name even if an existing file or outside current directory\"\n    )\n    ps_embed_extract.add_argument(\n        \"-output\", help=\"output filename, default is stored name\"\n    )\n    ps_embed_extract.set_defaults(func=embedded_get)\n\n    # -------------------------------------------------------------------------\n    # 'embed-copy' command\n    # -------------------------------------------------------------------------\n    ps_embed_copy = subps.add_parser(\n        \"embed-copy\", description=mycenter(\"copy embedded files between PDFs\")\n    )\n    ps_embed_copy.add_argument(\"input\", type=str, help=\"PDF to receive embedded files\")\n    ps_embed_copy.add_argument(\"-password\", help=\"password of input\")\n    ps_embed_copy.add_argument(\n        \"-output\", help=\"output PDF, incremental save to 'input' if omitted\"\n    )\n    ps_embed_copy.add_argument(\n        \"-source\", required=True, help=\"copy embedded files from here\"\n    )\n    ps_embed_copy.add_argument(\"-pwdsource\", help=\"password of 'source' PDF\")\n    ps_embed_copy.add_argument(\n        \"-name\", nargs=\"*\", help=\"restrict copy to these entries\"\n    )\n    ps_embed_copy.set_defaults(func=embedded_copy)\n\n    # -------------------------------------------------------------------------\n    # 'textlayout' command\n    # -------------------------------------------------------------------------\n    ps_gettext = subps.add_parser(\n        \"gettext\", description=mycenter(\"extract text in various formatting modes\")\n    )\n    ps_gettext.add_argument(\"input\", type=str, help=\"input document filename\")\n    ps_gettext.add_argument(\"-password\", help=\"password for input document\")\n    ps_gettext.add_argument(\n        \"-mode\",\n        type=str,\n        help=\"mode: simple, block sort, or layout (default)\",\n        choices=(\"simple\", \"blocks\", \"layout\"),\n        default=\"layout\",\n    )\n    ps_gettext.add_argument(\n        \"-pages\",\n        type=str,\n        help=\"select pages, format: 1,5-7,50-N\",\n        default=\"1-N\",\n    )\n    ps_gettext.add_argument(\n        \"-noligatures\",\n        action=\"store_true\",\n        help=\"expand ligature characters (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-convert-white\",\n        action=\"store_true\",\n        help=\"convert whitespace characters to white (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-extra-spaces\",\n        action=\"store_true\",\n        help=\"fill gaps with spaces (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-noformfeed\",\n        action=\"store_true\",\n        help=\"write linefeeds, no formfeeds (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-skip-empty\",\n        action=\"store_true\",\n        help=\"suppress pages with no text (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-output\",\n        help=\"store text in this file (default inputfilename.txt)\",\n    )\n    ps_gettext.add_argument(\n        \"-grid\",\n        type=float,\n        help=\"merge lines if closer than this (default 2)\",\n        default=2,\n    )\n    ps_gettext.add_argument(\n        \"-fontsize\",\n        type=float,\n        help=\"only include text with a larger fontsize (default 3)\",\n        default=3,\n    )\n    ps_gettext.set_defaults(func=gettext)\n\n    # -------------------------------------------------------------------------\n    # '_internal' command\n    # -------------------------------------------------------------------------\n    ps_internal = subps.add_parser(\n        \"internal\", description=mycenter(\"internal testing\")\n    )\n    ps_internal.set_defaults(func=_internal)\n\n    # -------------------------------------------------------------------------\n    # start program\n    # -------------------------------------------------------------------------\n    args = parser.parse_args()  # create parameter arguments class\n    if not hasattr(args, \"func\"):  # no function selected\n        parser.print_help()  # so print top level help\n    else:\n        args.func(args)  # execute requested command\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "src/_apply_pages.py",
    "content": "import multiprocessing\nimport os\nimport time\n\nimport pymupdf\n\n\n# Support for concurrent processing of document pages.\n#\n\nclass _worker_State:\n    pass\n_worker_state = _worker_State()\n\n\ndef _worker_init(\n        path,\n        initfn,\n        initfn_args,\n        initfn_kwargs,\n        pagefn,\n        pagefn_args,\n        pagefn_kwargs,\n        stats,\n        ):\n    # pylint: disable=attribute-defined-outside-init\n    _worker_state.path = path\n    _worker_state.pagefn = pagefn\n    _worker_state.pagefn_args = pagefn_args\n    _worker_state.pagefn_kwargs = pagefn_kwargs\n    _worker_state.stats = stats\n    _worker_state.document = None\n    if initfn:\n        initfn(*initfn_args, **initfn_kwargs)\n\n\ndef _stats_write(t, label):\n    t = time.time() - t\n    if t >= 10:\n        pymupdf.log(f'{os.getpid()=}: {t:2f}s: {label}.')   # pylint: disable=c-extension-no-member\n\n\ndef _worker_fn(page_number):\n    # Create Document from filename if we haven't already done so.\n    if not _worker_state.document:\n        if _worker_state.stats:\n            t = time.time()\n        _worker_state.document = pymupdf.Document(_worker_state.path)   # pylint: disable=c-extension-no-member,attribute-defined-outside-init\n        if _worker_state.stats:\n            _stats_write(t, 'pymupdf.Document()')\n    \n    if _worker_state.stats:\n        t = time.time()\n    page = _worker_state.document[page_number]\n    if _worker_state.stats:\n        _stats_write(t, '_worker_state.document[page_number]')\n    \n    if _worker_state.stats:\n        t = time.time()\n    ret = _worker_state.pagefn(\n            page,\n            *_worker_state.pagefn_args,\n            **_worker_state.pagefn_kwargs,\n            )\n    if _worker_state.stats:\n        _stats_write(t, '_worker_state.pagefn()')\n    \n    return ret\n    \n\ndef _multiprocessing(\n        path,\n        pages,\n        pagefn,\n        pagefn_args,\n        pagefn_kwargs,\n        initfn,\n        initfn_args,\n        initfn_kwargs,\n        concurrency,\n        stats,\n        ):\n    #print(f'_worker_mp(): {concurrency=}', flush=1)\n    with multiprocessing.Pool(\n            concurrency,\n            _worker_init,\n            (\n                path,\n                initfn, initfn_args, initfn_kwargs,\n                pagefn, pagefn_args, pagefn_kwargs,\n                stats,\n            ),\n            ) as pool:\n        result = pool.map_async(_worker_fn, pages)\n        return result.get()\n    \n\ndef _fork(\n        path,\n        pages,\n        pagefn,\n        pagefn_args,\n        pagefn_kwargs,\n        initfn,\n        initfn_args,\n        initfn_kwargs,\n        concurrency,\n        stats,\n        ):\n    verbose = 0\n    if concurrency is None:\n        concurrency = multiprocessing.cpu_count()\n    # We write page numbers to `queue_down` and read `(page_num, text)` from\n    # `queue_up`. Workers each repeatedly read the next available page number\n    # from `queue_down`, extract the text and write it onto `queue_up`.\n    #\n    # This is better than pre-allocating a subset of pages to each worker\n    # because it ensures there will never be idle workers until we are near the\n    # end with fewer pages left than workers.\n    #\n    queue_down = multiprocessing.Queue()\n    queue_up = multiprocessing.Queue()\n    def childfn():\n        document = None\n        if verbose:\n            pymupdf.log(f'{os.getpid()=}: {initfn=} {initfn_args=}')\n        _worker_init(\n                path,\n                initfn,\n                initfn_args,\n                initfn_kwargs,\n                pagefn,\n                pagefn_args,\n                pagefn_kwargs,\n                stats,\n                )\n        while 1:\n            if verbose:\n                pymupdf.log(f'{os.getpid()=}: calling get().')\n            page_num = queue_down.get()\n            if verbose:\n                pymupdf.log(f'{os.getpid()=}: {page_num=}.')\n            if page_num is None:\n                break\n            try:\n                if not document:\n                    if stats:\n                        t = time.time()\n                    document = pymupdf.Document(path)   # pylint: disable=c-extension-no-member\n                    if stats:\n                        _stats_write(t, 'pymupdf.Document(path)')\n                \n                if stats:\n                    t = time.time()\n                page = document[page_num]\n                if stats:\n                    _stats_write(t, 'document[page_num]')\n                \n                if verbose:\n                    pymupdf.log(f'{os.getpid()=}: {_worker_state=}')\n                \n                if stats:\n                    t = time.time()\n                ret = pagefn(\n                        page,\n                        *_worker_state.pagefn_args,\n                        **_worker_state.pagefn_kwargs,\n                        )\n                if stats:\n                    _stats_write(t, f'{page_num=} pagefn()')\n            except Exception as e:\n                if verbose: pymupdf.log(f'{os.getpid()=}: exception {e=}')\n                ret = e\n            if verbose:\n                pymupdf.log(f'{os.getpid()=}: sending {page_num=} {ret=}')\n                \n            queue_up.put( (page_num, ret) )\n\n    error = None\n\n    pids = list()\n    try:\n        # Start child processes.\n        if stats:\n            t = time.time()\n        for i in range(concurrency):\n            p = os.fork()   # pylint: disable=no-member\n            if p == 0:\n                # Child process.\n                try:\n                    try:\n                        childfn()\n                    except Exception as e:\n                        pymupdf.log(f'{os.getpid()=}: childfn() => {e=}')   # pylint: disable=c-extension-no-member\n                        raise\n                finally:\n                    if verbose:\n                        pymupdf.log(f'{os.getpid()=}: calling os._exit(0)')\n                    os._exit(0)\n            pids.append(p)\n        if stats:\n            _stats_write(t, 'create child processes')\n\n        # Send page numbers.\n        if stats:\n            t = time.time()\n        if verbose:\n            pymupdf.log(f'Sending page numbers.')\n        for page_num in range(len(pages)):\n            queue_down.put(page_num)\n        if stats:\n            _stats_write(t, 'Send page numbers')\n\n        # Collect results. We give up if any worker sends an exception instead\n        # of text, but this hasn't been tested.\n        ret = [None] * len(pages)\n        for i in range(len(pages)):\n            page_num, text = queue_up.get()\n            if verbose:\n                pymupdf.log(f'{page_num=} {len(text)=}')\n            assert ret[page_num] is None\n            if isinstance(text, Exception):\n                if not error:\n                    error = text\n                break\n            ret[page_num] = text\n\n        # Close queue. This should cause exception in workers and terminate\n        # them, but on macos-arm64 this does not seem to happen, so we also\n        # send None, which makes workers terminate.\n        for i in range(concurrency):\n            queue_down.put(None)\n        if verbose: pymupdf.log(f'Closing queues.')\n        queue_down.close()\n\n        if error:\n            raise error\n        if verbose:\n            pymupdf.log(f'After concurrent, returning {len(ret)=}')\n        return ret\n        \n    finally:\n        # Join all child processes.\n        if stats:\n            t = time.time()\n        for pid in pids:\n            if verbose:\n                pymupdf.log(f'waiting for {pid=}.')\n            e = os.waitpid(pid, 0)\n            if verbose:\n                pymupdf.log(f'{pid=} => {e=}')\n        if stats:\n            _stats_write(t, 'Join all child proceses')\n"
  },
  {
    "path": "src/_wxcolors.py",
    "content": "_wxcolors = [\n        (\"ALICEBLUE\", 240, 248, 255),\n        (\"ANTIQUEWHITE\", 250, 235, 215),\n        (\"ANTIQUEWHITE1\", 255, 239, 219),\n        (\"ANTIQUEWHITE2\", 238, 223, 204),\n        (\"ANTIQUEWHITE3\", 205, 192, 176),\n        (\"ANTIQUEWHITE4\", 139, 131, 120),\n        (\"AQUA\", 0, 255, 255),\n        (\"AQUAMARINE\", 127, 255, 212),\n        (\"AQUAMARINE1\", 127, 255, 212),\n        (\"AQUAMARINE2\", 118, 238, 198),\n        (\"AQUAMARINE3\", 102, 205, 170),\n        (\"AQUAMARINE4\", 69, 139, 116),\n        (\"AZURE\", 240, 255, 255),\n        (\"AZURE1\", 240, 255, 255),\n        (\"AZURE2\", 224, 238, 238),\n        (\"AZURE3\", 193, 205, 205),\n        (\"AZURE4\", 131, 139, 139),\n        (\"BEIGE\", 245, 245, 220),\n        (\"BISQUE\", 255, 228, 196),\n        (\"BISQUE1\", 255, 228, 196),\n        (\"BISQUE2\", 238, 213, 183),\n        (\"BISQUE3\", 205, 183, 158),\n        (\"BISQUE4\", 139, 125, 107),\n        (\"BLACK\", 0, 0, 0),\n        (\"BLANCHEDALMOND\", 255, 235, 205),\n        (\"BLUE\", 0, 0, 255),\n        (\"BLUE1\", 0, 0, 255),\n        (\"BLUE2\", 0, 0, 238),\n        (\"BLUE3\", 0, 0, 205),\n        (\"BLUE4\", 0, 0, 139),\n        (\"BLUEVIOLET\", 138, 43, 226),\n        (\"BROWN\", 165, 42, 42),\n        (\"BROWN1\", 255, 64, 64),\n        (\"BROWN2\", 238, 59, 59),\n        (\"BROWN3\", 205, 51, 51),\n        (\"BROWN4\", 139, 35, 35),\n        (\"BURLYWOOD\", 222, 184, 135),\n        (\"BURLYWOOD1\", 255, 211, 155),\n        (\"BURLYWOOD2\", 238, 197, 145),\n        (\"BURLYWOOD3\", 205, 170, 125),\n        (\"BURLYWOOD4\", 139, 115, 85),\n        (\"CADETBLUE\", 95, 158, 160),\n        (\"CADETBLUE1\", 152, 245, 255),\n        (\"CADETBLUE2\", 142, 229, 238),\n        (\"CADETBLUE3\", 122, 197, 205),\n        (\"CADETBLUE4\", 83, 134, 139),\n        (\"CHARTREUSE\", 127, 255, 0),\n        (\"CHARTREUSE1\", 127, 255, 0),\n        (\"CHARTREUSE2\", 118, 238, 0),\n        (\"CHARTREUSE3\", 102, 205, 0),\n        (\"CHARTREUSE4\", 69, 139, 0),\n        (\"CHOCOLATE\", 210, 105, 30),\n        (\"CHOCOLATE1\", 255, 127, 36),\n        (\"CHOCOLATE2\", 238, 118, 33),\n        (\"CHOCOLATE3\", 205, 102, 29),\n        (\"CHOCOLATE4\", 139, 69, 19),\n        (\"COFFEE\", 156, 79, 0),\n        (\"CORAL\", 255, 127, 80),\n        (\"CORAL1\", 255, 114, 86),\n        (\"CORAL2\", 238, 106, 80),\n        (\"CORAL3\", 205, 91, 69),\n        (\"CORAL4\", 139, 62, 47),\n        (\"CORNFLOWERBLUE\", 100, 149, 237),\n        (\"CORNSILK\", 255, 248, 220),\n        (\"CORNSILK1\", 255, 248, 220),\n        (\"CORNSILK2\", 238, 232, 205),\n        (\"CORNSILK3\", 205, 200, 177),\n        (\"CORNSILK4\", 139, 136, 120),\n        (\"CRIMSON\", 220, 20, 60),\n        (\"CYAN\", 0, 255, 255),\n        (\"CYAN1\", 0, 255, 255),\n        (\"CYAN2\", 0, 238, 238),\n        (\"CYAN3\", 0, 205, 205),\n        (\"CYAN4\", 0, 139, 139),\n        (\"DARKBLUE\", 0, 0, 139),\n        (\"DARKCYAN\", 0, 139, 139),\n        (\"DARKGOLDENROD\", 184, 134, 11),\n        (\"DARKGOLDENROD1\", 255, 185, 15),\n        (\"DARKGOLDENROD2\", 238, 173, 14),\n        (\"DARKGOLDENROD3\", 205, 149, 12),\n        (\"DARKGOLDENROD4\", 139, 101, 8),\n        (\"DARKGRAY\", 169, 169, 169),\n        (\"DARKGREEN\", 0, 100, 0),\n        (\"DARKGREY\", 169, 169, 169),\n        (\"DARKKHAKI\", 189, 183, 107),\n        (\"DARKMAGENTA\", 139, 0, 139),\n        (\"DARKOLIVEGREEN\", 85, 107, 47),\n        (\"DARKOLIVEGREEN1\", 202, 255, 112),\n        (\"DARKOLIVEGREEN2\", 188, 238, 104),\n        (\"DARKOLIVEGREEN3\", 162, 205, 90),\n        (\"DARKOLIVEGREEN4\", 110, 139, 61),\n        (\"DARKORANGE\", 255, 140, 0),\n        (\"DARKORANGE1\", 255, 127, 0),\n        (\"DARKORANGE2\", 238, 118, 0),\n        (\"DARKORANGE3\", 205, 102, 0),\n        (\"DARKORANGE4\", 139, 69, 0),\n        (\"DARKORCHID\", 153, 50, 204),\n        (\"DARKORCHID1\", 191, 62, 255),\n        (\"DARKORCHID2\", 178, 58, 238),\n        (\"DARKORCHID3\", 154, 50, 205),\n        (\"DARKORCHID4\", 104, 34, 139),\n        (\"DARKRED\", 139, 0, 0),\n        (\"DARKSALMON\", 233, 150, 122),\n        (\"DARKSEAGREEN\", 143, 188, 143),\n        (\"DARKSEAGREEN1\", 193, 255, 193),\n        (\"DARKSEAGREEN2\", 180, 238, 180),\n        (\"DARKSEAGREEN3\", 155, 205, 155),\n        (\"DARKSEAGREEN4\", 105, 139, 105),\n        (\"DARKSLATEBLUE\", 72, 61, 139),\n        (\"DARKSLATEGRAY\", 47, 79, 79),\n        (\"DARKSLATEGREY\", 47, 79, 79),\n        (\"DARKTURQUOISE\", 0, 206, 209),\n        (\"DARKVIOLET\", 148, 0, 211),\n        (\"DEEPPINK\", 255, 20, 147),\n        (\"DEEPPINK1\", 255, 20, 147),\n        (\"DEEPPINK2\", 238, 18, 137),\n        (\"DEEPPINK3\", 205, 16, 118),\n        (\"DEEPPINK4\", 139, 10, 80),\n        (\"DEEPSKYBLUE\", 0, 191, 255),\n        (\"DEEPSKYBLUE1\", 0, 191, 255),\n        (\"DEEPSKYBLUE2\", 0, 178, 238),\n        (\"DEEPSKYBLUE3\", 0, 154, 205),\n        (\"DEEPSKYBLUE4\", 0, 104, 139),\n        (\"DIMGRAY\", 105, 105, 105),\n        (\"DIMGREY\", 105, 105, 105),\n        (\"DODGERBLUE\", 30, 144, 255),\n        (\"DODGERBLUE1\", 30, 144, 255),\n        (\"DODGERBLUE2\", 28, 134, 238),\n        (\"DODGERBLUE3\", 24, 116, 205),\n        (\"DODGERBLUE4\", 16, 78, 139),\n        (\"FIREBRICK\", 178, 34, 34),\n        (\"FIREBRICK1\", 255, 48, 48),\n        (\"FIREBRICK2\", 238, 44, 44),\n        (\"FIREBRICK3\", 205, 38, 38),\n        (\"FIREBRICK4\", 139, 26, 26),\n        (\"FLORALWHITE\", 255, 250, 240),\n        (\"FORESTGREEN\", 34, 139, 34),\n        (\"FUCHSIA\", 255, 0, 255),\n        (\"GAINSBORO\", 220, 220, 220),\n        (\"GHOSTWHITE\", 248, 248, 255),\n        (\"GOLD\", 255, 215, 0),\n        (\"GOLD1\", 255, 215, 0),\n        (\"GOLD2\", 238, 201, 0),\n        (\"GOLD3\", 205, 173, 0),\n        (\"GOLD4\", 139, 117, 0),\n        (\"GOLDENROD\", 218, 165, 32),\n        (\"GOLDENROD1\", 255, 193, 37),\n        (\"GOLDENROD2\", 238, 180, 34),\n        (\"GOLDENROD3\", 205, 155, 29),\n        (\"GOLDENROD4\", 139, 105, 20),\n        (\"GRAY\", 190, 190, 190),\n        (\"GRAY0\", 0, 0, 0),\n        (\"GRAY1\", 3, 3, 3),\n        (\"GRAY10\", 26, 26, 26),\n        (\"GRAY100\", 255, 255, 255),\n        (\"GRAY11\", 28, 28, 28),\n        (\"GRAY12\", 31, 31, 31),\n        (\"GRAY13\", 33, 33, 33),\n        (\"GRAY14\", 36, 36, 36),\n        (\"GRAY15\", 38, 38, 38),\n        (\"GRAY16\", 41, 41, 41),\n        (\"GRAY17\", 43, 43, 43),\n        (\"GRAY18\", 46, 46, 46),\n        (\"GRAY19\", 48, 48, 48),\n        (\"GRAY2\", 5, 5, 5),\n        (\"GRAY20\", 51, 51, 51),\n        (\"GRAY21\", 54, 54, 54),\n        (\"GRAY22\", 56, 56, 56),\n        (\"GRAY23\", 59, 59, 59),\n        (\"GRAY24\", 61, 61, 61),\n        (\"GRAY25\", 64, 64, 64),\n        (\"GRAY26\", 66, 66, 66),\n        (\"GRAY27\", 69, 69, 69),\n        (\"GRAY28\", 71, 71, 71),\n        (\"GRAY29\", 74, 74, 74),\n        (\"GRAY3\", 8, 8, 8),\n        (\"GRAY30\", 77, 77, 77),\n        (\"GRAY31\", 79, 79, 79),\n        (\"GRAY32\", 82, 82, 82),\n        (\"GRAY33\", 84, 84, 84),\n        (\"GRAY34\", 87, 87, 87),\n        (\"GRAY35\", 89, 89, 89),\n        (\"GRAY36\", 92, 92, 92),\n        (\"GRAY37\", 94, 94, 94),\n        (\"GRAY38\", 97, 97, 97),\n        (\"GRAY39\", 99, 99, 99),\n        (\"GRAY4\", 10, 10, 10),\n        (\"GRAY40\", 102, 102, 102),\n        (\"GRAY41\", 105, 105, 105),\n        (\"GRAY42\", 107, 107, 107),\n        (\"GRAY43\", 110, 110, 110),\n        (\"GRAY44\", 112, 112, 112),\n        (\"GRAY45\", 115, 115, 115),\n        (\"GRAY46\", 117, 117, 117),\n        (\"GRAY47\", 120, 120, 120),\n        (\"GRAY48\", 122, 122, 122),\n        (\"GRAY49\", 125, 125, 125),\n        (\"GRAY5\", 13, 13, 13),\n        (\"GRAY50\", 127, 127, 127),\n        (\"GRAY51\", 130, 130, 130),\n        (\"GRAY52\", 133, 133, 133),\n        (\"GRAY53\", 135, 135, 135),\n        (\"GRAY54\", 138, 138, 138),\n        (\"GRAY55\", 140, 140, 140),\n        (\"GRAY56\", 143, 143, 143),\n        (\"GRAY57\", 145, 145, 145),\n        (\"GRAY58\", 148, 148, 148),\n        (\"GRAY59\", 150, 150, 150),\n        (\"GRAY6\", 15, 15, 15),\n        (\"GRAY60\", 153, 153, 153),\n        (\"GRAY61\", 156, 156, 156),\n        (\"GRAY62\", 158, 158, 158),\n        (\"GRAY63\", 161, 161, 161),\n        (\"GRAY64\", 163, 163, 163),\n        (\"GRAY65\", 166, 166, 166),\n        (\"GRAY66\", 168, 168, 168),\n        (\"GRAY67\", 171, 171, 171),\n        (\"GRAY68\", 173, 173, 173),\n        (\"GRAY69\", 176, 176, 176),\n        (\"GRAY7\", 18, 18, 18),\n        (\"GRAY70\", 179, 179, 179),\n        (\"GRAY71\", 181, 181, 181),\n        (\"GRAY72\", 184, 184, 184),\n        (\"GRAY73\", 186, 186, 186),\n        (\"GRAY74\", 189, 189, 189),\n        (\"GRAY75\", 191, 191, 191),\n        (\"GRAY76\", 194, 194, 194),\n        (\"GRAY77\", 196, 196, 196),\n        (\"GRAY78\", 199, 199, 199),\n        (\"GRAY79\", 201, 201, 201),\n        (\"GRAY8\", 20, 20, 20),\n        (\"GRAY80\", 204, 204, 204),\n        (\"GRAY81\", 207, 207, 207),\n        (\"GRAY82\", 209, 209, 209),\n        (\"GRAY83\", 212, 212, 212),\n        (\"GRAY84\", 214, 214, 214),\n        (\"GRAY85\", 217, 217, 217),\n        (\"GRAY86\", 219, 219, 219),\n        (\"GRAY87\", 222, 222, 222),\n        (\"GRAY88\", 224, 224, 224),\n        (\"GRAY89\", 227, 227, 227),\n        (\"GRAY9\", 23, 23, 23),\n        (\"GRAY90\", 229, 229, 229),\n        (\"GRAY91\", 232, 232, 232),\n        (\"GRAY92\", 235, 235, 235),\n        (\"GRAY93\", 237, 237, 237),\n        (\"GRAY94\", 240, 240, 240),\n        (\"GRAY95\", 242, 242, 242),\n        (\"GRAY96\", 245, 245, 245),\n        (\"GRAY97\", 247, 247, 247),\n        (\"GRAY98\", 250, 250, 250),\n        (\"GRAY99\", 252, 252, 252),\n        (\"GREEN YELLOW\", 173, 255, 47),\n        (\"GREEN\", 0, 255, 0),\n        (\"GREEN1\", 0, 255, 0),\n        (\"GREEN2\", 0, 238, 0),\n        (\"GREEN3\", 0, 205, 0),\n        (\"GREEN4\", 0, 139, 0),\n        (\"GREENYELLOW\", 173, 255, 47),\n        (\"GREY\", 128, 128, 128),\n        (\"HONEYDEW\", 240, 255, 240),\n        (\"HONEYDEW1\", 240, 255, 240),\n        (\"HONEYDEW2\", 224, 238, 224),\n        (\"HONEYDEW3\", 193, 205, 193),\n        (\"HONEYDEW4\", 131, 139, 131),\n        (\"HOTPINK\", 255, 105, 180),\n        (\"HOTPINK1\", 255, 110, 180),\n        (\"HOTPINK2\", 238, 106, 167),\n        (\"HOTPINK3\", 205, 96, 144),\n        (\"HOTPINK4\", 139, 58, 98),\n        (\"INDIANRED\", 205, 92, 92),\n        (\"INDIANRED1\", 255, 106, 106),\n        (\"INDIANRED2\", 238, 99, 99),\n        (\"INDIANRED3\", 205, 85, 85),\n        (\"INDIANRED4\", 139, 58, 58),\n        (\"INDIGO\", 75, 0, 130),\n        (\"IVORY\", 255, 255, 240),\n        (\"IVORY1\", 255, 255, 240),\n        (\"IVORY2\", 238, 238, 224),\n        (\"IVORY3\", 205, 205, 193),\n        (\"IVORY4\", 139, 139, 131),\n        (\"KHAKI\", 240, 230, 140),\n        (\"KHAKI1\", 255, 246, 143),\n        (\"KHAKI2\", 238, 230, 133),\n        (\"KHAKI3\", 205, 198, 115),\n        (\"KHAKI4\", 139, 134, 78),\n        (\"LAVENDER\", 230, 230, 250),\n        (\"LAVENDERBLUSH\", 255, 240, 245),\n        (\"LAVENDERBLUSH1\", 255, 240, 245),\n        (\"LAVENDERBLUSH2\", 238, 224, 229),\n        (\"LAVENDERBLUSH3\", 205, 193, 197),\n        (\"LAVENDERBLUSH4\", 139, 131, 134),\n        (\"LAWNGREEN\", 124, 252, 0),\n        (\"LEMONCHIFFON\", 255, 250, 205),\n        (\"LEMONCHIFFON1\", 255, 250, 205),\n        (\"LEMONCHIFFON2\", 238, 233, 191),\n        (\"LEMONCHIFFON3\", 205, 201, 165),\n        (\"LEMONCHIFFON4\", 139, 137, 112),\n        (\"LIGHTBLUE\", 173, 216, 230),\n        (\"LIGHTBLUE1\", 191, 239, 255),\n        (\"LIGHTBLUE2\", 178, 223, 238),\n        (\"LIGHTBLUE3\", 154, 192, 205),\n        (\"LIGHTBLUE4\", 104, 131, 139),\n        (\"LIGHTCORAL\", 240, 128, 128),\n        (\"LIGHTCYAN\", 224, 255, 255),\n        (\"LIGHTCYAN1\", 224, 255, 255),\n        (\"LIGHTCYAN2\", 209, 238, 238),\n        (\"LIGHTCYAN3\", 180, 205, 205),\n        (\"LIGHTCYAN4\", 122, 139, 139),\n        (\"LIGHTGOLDENROD\", 238, 221, 130),\n        (\"LIGHTGOLDENROD1\", 255, 236, 139),\n        (\"LIGHTGOLDENROD2\", 238, 220, 130),\n        (\"LIGHTGOLDENROD3\", 205, 190, 112),\n        (\"LIGHTGOLDENROD4\", 139, 129, 76),\n        (\"LIGHTGOLDENRODYELLOW\", 250, 250, 210),\n        (\"LIGHTGRAY\", 211, 211, 211),\n        (\"LIGHTGREEN\", 144, 238, 144),\n        (\"LIGHTGREY\", 211, 211, 211),\n        (\"LIGHTPINK\", 255, 182, 193),\n        (\"LIGHTPINK1\", 255, 174, 185),\n        (\"LIGHTPINK2\", 238, 162, 173),\n        (\"LIGHTPINK3\", 205, 140, 149),\n        (\"LIGHTPINK4\", 139, 95, 101),\n        (\"LIGHTSALMON\", 255, 160, 122),\n        (\"LIGHTSALMON1\", 255, 160, 122),\n        (\"LIGHTSALMON2\", 238, 149, 114),\n        (\"LIGHTSALMON3\", 205, 129, 98),\n        (\"LIGHTSALMON4\", 139, 87, 66),\n        (\"LIGHTSEAGREEN\", 32, 178, 170),\n        (\"LIGHTSKYBLUE\", 135, 206, 250),\n        (\"LIGHTSKYBLUE1\", 176, 226, 255),\n        (\"LIGHTSKYBLUE2\", 164, 211, 238),\n        (\"LIGHTSKYBLUE3\", 141, 182, 205),\n        (\"LIGHTSKYBLUE4\", 96, 123, 139),\n        (\"LIGHTSLATEBLUE\", 132, 112, 255),\n        (\"LIGHTSLATEGRAY\", 119, 136, 153),\n        (\"LIGHTSLATEGREY\", 119, 136, 153),\n        (\"LIGHTSTEELBLUE\", 176, 196, 222),\n        (\"LIGHTSTEELBLUE1\", 202, 225, 255),\n        (\"LIGHTSTEELBLUE2\", 188, 210, 238),\n        (\"LIGHTSTEELBLUE3\", 162, 181, 205),\n        (\"LIGHTSTEELBLUE4\", 110, 123, 139),\n        (\"LIGHTYELLOW\", 255, 255, 224),\n        (\"LIGHTYELLOW1\", 255, 255, 224),\n        (\"LIGHTYELLOW2\", 238, 238, 209),\n        (\"LIGHTYELLOW3\", 205, 205, 180),\n        (\"LIGHTYELLOW4\", 139, 139, 122),\n        (\"LIME\", 0, 255, 0),\n        (\"LIMEGREEN\", 50, 205, 50),\n        (\"LINEN\", 250, 240, 230),\n        (\"MAGENTA\", 255, 0, 255),\n        (\"MAGENTA1\", 255, 0, 255),\n        (\"MAGENTA2\", 238, 0, 238),\n        (\"MAGENTA3\", 205, 0, 205),\n        (\"MAGENTA4\", 139, 0, 139),\n        (\"MAROON\", 176, 48, 96),\n        (\"MAROON1\", 255, 52, 179),\n        (\"MAROON2\", 238, 48, 167),\n        (\"MAROON3\", 205, 41, 144),\n        (\"MAROON4\", 139, 28, 98),\n        (\"MEDIUMAQUAMARINE\", 102, 205, 170),\n        (\"MEDIUMBLUE\", 0, 0, 205),\n        (\"MEDIUMORCHID\", 186, 85, 211),\n        (\"MEDIUMORCHID1\", 224, 102, 255),\n        (\"MEDIUMORCHID2\", 209, 95, 238),\n        (\"MEDIUMORCHID3\", 180, 82, 205),\n        (\"MEDIUMORCHID4\", 122, 55, 139),\n        (\"MEDIUMPURPLE\", 147, 112, 219),\n        (\"MEDIUMPURPLE1\", 171, 130, 255),\n        (\"MEDIUMPURPLE2\", 159, 121, 238),\n        (\"MEDIUMPURPLE3\", 137, 104, 205),\n        (\"MEDIUMPURPLE4\", 93, 71, 139),\n        (\"MEDIUMSEAGREEN\", 60, 179, 113),\n        (\"MEDIUMSLATEBLUE\", 123, 104, 238),\n        (\"MEDIUMSPRINGGREEN\", 0, 250, 154),\n        (\"MEDIUMTURQUOISE\", 72, 209, 204),\n        (\"MEDIUMVIOLETRED\", 199, 21, 133),\n        (\"MIDNIGHTBLUE\", 25, 25, 112),\n        (\"MINTCREAM\", 245, 255, 250),\n        (\"MISTYROSE\", 255, 228, 225),\n        (\"MISTYROSE1\", 255, 228, 225),\n        (\"MISTYROSE2\", 238, 213, 210),\n        (\"MISTYROSE3\", 205, 183, 181),\n        (\"MISTYROSE4\", 139, 125, 123),\n        (\"MOCCASIN\", 255, 228, 181),\n        (\"MUPDFBLUE\", 37, 114, 172),\n        (\"NAVAJOWHITE\", 255, 222, 173),\n        (\"NAVAJOWHITE1\", 255, 222, 173),\n        (\"NAVAJOWHITE2\", 238, 207, 161),\n        (\"NAVAJOWHITE3\", 205, 179, 139),\n        (\"NAVAJOWHITE4\", 139, 121, 94),\n        (\"NAVY\", 0, 0, 128),\n        (\"NAVYBLUE\", 0, 0, 128),\n        (\"OLDLACE\", 253, 245, 230),\n        (\"OLIVE\", 128, 128, 0),\n        (\"OLIVEDRAB\", 107, 142, 35),\n        (\"OLIVEDRAB1\", 192, 255, 62),\n        (\"OLIVEDRAB2\", 179, 238, 58),\n        (\"OLIVEDRAB3\", 154, 205, 50),\n        (\"OLIVEDRAB4\", 105, 139, 34),\n        (\"ORANGE\", 255, 165, 0),\n        (\"ORANGE1\", 255, 165, 0),\n        (\"ORANGE2\", 238, 154, 0),\n        (\"ORANGE3\", 205, 133, 0),\n        (\"ORANGE4\", 139, 90, 0),\n        (\"ORANGERED\", 255, 69, 0),\n        (\"ORANGERED1\", 255, 69, 0),\n        (\"ORANGERED2\", 238, 64, 0),\n        (\"ORANGERED3\", 205, 55, 0),\n        (\"ORANGERED4\", 139, 37, 0),\n        (\"ORCHID\", 218, 112, 214),\n        (\"ORCHID1\", 255, 131, 250),\n        (\"ORCHID2\", 238, 122, 233),\n        (\"ORCHID3\", 205, 105, 201),\n        (\"ORCHID4\", 139, 71, 137),\n        (\"PALEGOLDENROD\", 238, 232, 170),\n        (\"PALEGREEN\", 152, 251, 152),\n        (\"PALEGREEN1\", 154, 255, 154),\n        (\"PALEGREEN2\", 144, 238, 144),\n        (\"PALEGREEN3\", 124, 205, 124),\n        (\"PALEGREEN4\", 84, 139, 84),\n        (\"PALETURQUOISE\", 175, 238, 238),\n        (\"PALETURQUOISE1\", 187, 255, 255),\n        (\"PALETURQUOISE2\", 174, 238, 238),\n        (\"PALETURQUOISE3\", 150, 205, 205),\n        (\"PALETURQUOISE4\", 102, 139, 139),\n        (\"PALEVIOLETRED\", 219, 112, 147),\n        (\"PALEVIOLETRED1\", 255, 130, 171),\n        (\"PALEVIOLETRED2\", 238, 121, 159),\n        (\"PALEVIOLETRED3\", 205, 104, 137),\n        (\"PALEVIOLETRED4\", 139, 71, 93),\n        (\"PAPAYAWHIP\", 255, 239, 213),\n        (\"PEACHPUFF\", 255, 218, 185),\n        (\"PEACHPUFF1\", 255, 218, 185),\n        (\"PEACHPUFF2\", 238, 203, 173),\n        (\"PEACHPUFF3\", 205, 175, 149),\n        (\"PEACHPUFF4\", 139, 119, 101),\n        (\"PERU\", 205, 133, 63),\n        (\"PINK\", 255, 192, 203),\n        (\"PINK1\", 255, 181, 197),\n        (\"PINK2\", 238, 169, 184),\n        (\"PINK3\", 205, 145, 158),\n        (\"PINK4\", 139, 99, 108),\n        (\"PLUM\", 221, 160, 221),\n        (\"PLUM1\", 255, 187, 255),\n        (\"PLUM2\", 238, 174, 238),\n        (\"PLUM3\", 205, 150, 205),\n        (\"PLUM4\", 139, 102, 139),\n        (\"POWDERBLUE\", 176, 224, 230),\n        (\"PURPLE\", 160, 32, 240),\n        (\"PURPLE1\", 155, 48, 255),\n        (\"PURPLE2\", 145, 44, 238),\n        (\"PURPLE3\", 125, 38, 205),\n        (\"PURPLE4\", 85, 26, 139),\n        (\"PY_COLOR\", 240, 255, 210),\n        (\"RED\", 255, 0, 0),\n        (\"RED1\", 255, 0, 0),\n        (\"RED2\", 238, 0, 0),\n        (\"RED3\", 205, 0, 0),\n        (\"RED4\", 139, 0, 0),\n        (\"ROSYBROWN\", 188, 143, 143),\n        (\"ROSYBROWN1\", 255, 193, 193),\n        (\"ROSYBROWN2\", 238, 180, 180),\n        (\"ROSYBROWN3\", 205, 155, 155),\n        (\"ROSYBROWN4\", 139, 105, 105),\n        (\"ROYALBLUE\", 65, 105, 225),\n        (\"ROYALBLUE1\", 72, 118, 255),\n        (\"ROYALBLUE2\", 67, 110, 238),\n        (\"ROYALBLUE3\", 58, 95, 205),\n        (\"ROYALBLUE4\", 39, 64, 139),\n        (\"SADDLEBROWN\", 139, 69, 19),\n        (\"SALMON\", 250, 128, 114),\n        (\"SALMON1\", 255, 140, 105),\n        (\"SALMON2\", 238, 130, 98),\n        (\"SALMON3\", 205, 112, 84),\n        (\"SALMON4\", 139, 76, 57),\n        (\"SANDYBROWN\", 244, 164, 96),\n        (\"SEAGREEN\", 46, 139, 87),\n        (\"SEAGREEN1\", 84, 255, 159),\n        (\"SEAGREEN2\", 78, 238, 148),\n        (\"SEAGREEN3\", 67, 205, 128),\n        (\"SEAGREEN4\", 46, 139, 87),\n        (\"SEASHELL\", 255, 245, 238),\n        (\"SEASHELL1\", 255, 245, 238),\n        (\"SEASHELL2\", 238, 229, 222),\n        (\"SEASHELL3\", 205, 197, 191),\n        (\"SEASHELL4\", 139, 134, 130),\n        (\"SIENNA\", 160, 82, 45),\n        (\"SIENNA1\", 255, 130, 71),\n        (\"SIENNA2\", 238, 121, 66),\n        (\"SIENNA3\", 205, 104, 57),\n        (\"SIENNA4\", 139, 71, 38),\n        (\"SILVER\", 192, 192, 192),\n        (\"SKYBLUE\", 135, 206, 235),\n        (\"SKYBLUE1\", 135, 206, 255),\n        (\"SKYBLUE2\", 126, 192, 238),\n        (\"SKYBLUE3\", 108, 166, 205),\n        (\"SKYBLUE4\", 74, 112, 139),\n        (\"SLATEBLUE\", 106, 90, 205),\n        (\"SLATEBLUE1\", 131, 111, 255),\n        (\"SLATEBLUE2\", 122, 103, 238),\n        (\"SLATEBLUE3\", 105, 89, 205),\n        (\"SLATEBLUE4\", 71, 60, 139),\n        (\"SLATEGRAY\", 112, 128, 144),\n        (\"SLATEGREY\", 112, 128, 144),\n        (\"SNOW\", 255, 250, 250),\n        (\"SNOW1\", 255, 250, 250),\n        (\"SNOW2\", 238, 233, 233),\n        (\"SNOW3\", 205, 201, 201),\n        (\"SNOW4\", 139, 137, 137),\n        (\"SPRINGGREEN\", 0, 255, 127),\n        (\"SPRINGGREEN1\", 0, 255, 127),\n        (\"SPRINGGREEN2\", 0, 238, 118),\n        (\"SPRINGGREEN3\", 0, 205, 102),\n        (\"SPRINGGREEN4\", 0, 139, 69),\n        (\"STEELBLUE\", 70, 130, 180),\n        (\"STEELBLUE1\", 99, 184, 255),\n        (\"STEELBLUE2\", 92, 172, 238),\n        (\"STEELBLUE3\", 79, 148, 205),\n        (\"STEELBLUE4\", 54, 100, 139),\n        (\"TAN\", 210, 180, 140),\n        (\"TAN1\", 255, 165, 79),\n        (\"TAN2\", 238, 154, 73),\n        (\"TAN3\", 205, 133, 63),\n        (\"TAN4\", 139, 90, 43),\n        (\"TEAL\", 0, 128, 128),\n        (\"THISTLE\", 216, 191, 216),\n        (\"THISTLE1\", 255, 225, 255),\n        (\"THISTLE2\", 238, 210, 238),\n        (\"THISTLE3\", 205, 181, 205),\n        (\"THISTLE4\", 139, 123, 139),\n        (\"TOMATO\", 255, 99, 71),\n        (\"TOMATO1\", 255, 99, 71),\n        (\"TOMATO2\", 238, 92, 66),\n        (\"TOMATO3\", 205, 79, 57),\n        (\"TOMATO4\", 139, 54, 38),\n        (\"TURQUOISE\", 64, 224, 208),\n        (\"TURQUOISE1\", 0, 245, 255),\n        (\"TURQUOISE2\", 0, 229, 238),\n        (\"TURQUOISE3\", 0, 197, 205),\n        (\"TURQUOISE4\", 0, 134, 139),\n        (\"VIOLET\", 238, 130, 238),\n        (\"VIOLETRED\", 208, 32, 144),\n        (\"VIOLETRED1\", 255, 62, 150),\n        (\"VIOLETRED2\", 238, 58, 140),\n        (\"VIOLETRED3\", 205, 50, 120),\n        (\"VIOLETRED4\", 139, 34, 82),\n        (\"WHEAT\", 245, 222, 179),\n        (\"WHEAT1\", 255, 231, 186),\n        (\"WHEAT2\", 238, 216, 174),\n        (\"WHEAT3\", 205, 186, 150),\n        (\"WHEAT4\", 139, 126, 102),\n        (\"WHITE\", 255, 255, 255),\n        (\"WHITESMOKE\", 245, 245, 245),\n        (\"YELLOW\", 255, 255, 0),\n        (\"YELLOW1\", 255, 255, 0),\n        (\"YELLOW2\", 238, 238, 0),\n        (\"YELLOW3\", 205, 205, 0),\n        (\"YELLOW4\", 139, 139, 0),\n        (\"YELLOWGREEN\", 154, 205, 50),\n        ]\n"
  },
  {
    "path": "src/extra.i",
    "content": "%pythoncode %{\n# pylint: disable=all\n%}\n\n%begin\n%{\n#define SWIG_PYTHON_INTERPRETER_NO_DEBUG\n\n/* This seems to be necessary on some Windows machines with Py_LIMITED_API,\notherwise compilation can fail because free() and malloc() are not declared. */\n#include <stdlib.h>\n%}\n\n%init\n%{\n    /* Initialise some globals that require Python functions.\n    \n    [Prior to 2023-08-18 we initialised these global variables inline,\n    but this causes a SEGV on Windows with Python-3.10 for `dictkey_c`\n    (actually any string of length 1 failed).] */\n    \n    dictkey_align = PyUnicode_InternFromString(\"align\");\n    dictkey_ascender = PyUnicode_InternFromString(\"ascender\");\n    dictkey_bidi = PyUnicode_InternFromString(\"bidi\");\n    dictkey_bbox = PyUnicode_InternFromString(\"bbox\");\n    dictkey_blocks = PyUnicode_InternFromString(\"blocks\");\n    dictkey_bpc = PyUnicode_InternFromString(\"bpc\");\n    dictkey_c = PyUnicode_InternFromString(\"c\");\n    dictkey_chars = PyUnicode_InternFromString(\"chars\");\n    dictkey_color = PyUnicode_InternFromString(\"color\");\n    dictkey_colorspace = PyUnicode_InternFromString(\"colorspace\");\n    dictkey_content = PyUnicode_InternFromString(\"content\");\n    dictkey_creationDate = PyUnicode_InternFromString(\"creationDate\");\n    dictkey_cs_name = PyUnicode_InternFromString(\"cs-name\");\n    dictkey_da = PyUnicode_InternFromString(\"da\");\n    dictkey_dashes = PyUnicode_InternFromString(\"dashes\");\n    dictkey_desc = PyUnicode_InternFromString(\"descender\");\n    dictkey_descender = PyUnicode_InternFromString(\"descender\");\n    dictkey_dir = PyUnicode_InternFromString(\"dir\");\n    dictkey_effect = PyUnicode_InternFromString(\"effect\");\n    dictkey_ext = PyUnicode_InternFromString(\"ext\");\n    dictkey_filename = PyUnicode_InternFromString(\"filename\");\n    dictkey_fill = PyUnicode_InternFromString(\"fill\");\n    dictkey_flags = PyUnicode_InternFromString(\"flags\");\n    dictkey_char_flags = PyUnicode_InternFromString(\"char_flags\");  /* Only used with mupdf >= 1.25.2. */\n    dictkey_font = PyUnicode_InternFromString(\"font\");\n    dictkey_glyph = PyUnicode_InternFromString(\"glyph\");\n    dictkey_height = PyUnicode_InternFromString(\"height\");\n    dictkey_id = PyUnicode_InternFromString(\"id\");\n    dictkey_image = PyUnicode_InternFromString(\"image\");\n    dictkey_items = PyUnicode_InternFromString(\"items\");\n    dictkey_length = PyUnicode_InternFromString(\"length\");\n    dictkey_lines = PyUnicode_InternFromString(\"lines\");\n    dictkey_matrix = PyUnicode_InternFromString(\"transform\");\n    dictkey_modDate = PyUnicode_InternFromString(\"modDate\");\n    dictkey_name = PyUnicode_InternFromString(\"name\");\n    dictkey_number = PyUnicode_InternFromString(\"number\");\n    dictkey_origin = PyUnicode_InternFromString(\"origin\");\n    dictkey_rect = PyUnicode_InternFromString(\"rect\");\n    dictkey_size = PyUnicode_InternFromString(\"size\");\n    dictkey_smask = PyUnicode_InternFromString(\"smask\");\n    dictkey_spans = PyUnicode_InternFromString(\"spans\");\n    dictkey_stroke = PyUnicode_InternFromString(\"stroke\");\n    dictkey_style = PyUnicode_InternFromString(\"style\");\n    dictkey_subject = PyUnicode_InternFromString(\"subject\");\n    dictkey_text = PyUnicode_InternFromString(\"text\");\n    dictkey_title = PyUnicode_InternFromString(\"title\");\n    dictkey_type = PyUnicode_InternFromString(\"type\");\n    dictkey_ufilename = PyUnicode_InternFromString(\"ufilename\");\n    dictkey_width = PyUnicode_InternFromString(\"width\");\n    dictkey_wmode = PyUnicode_InternFromString(\"wmode\");\n    dictkey_xref = PyUnicode_InternFromString(\"xref\");\n    dictkey_xres = PyUnicode_InternFromString(\"xres\");\n    dictkey_yres = PyUnicode_InternFromString(\"yres\");\n%}\n\n%include std_string.i\n\n%include exception.i\n%exception {\n    try {\n        $action\n    }\n\n/* this might not be ok on windows.\ncatch (Swig::DirectorException &e) {\n    SWIG_fail;\n}*/\ncatch(std::exception& e) {\n    SWIG_exception(SWIG_RuntimeError, e.what());\n}\ncatch(...) {\n        SWIG_exception(SWIG_RuntimeError, \"Unknown exception\");\n    }\n}\n\n%{\n#include \"mupdf/classes2.h\"\n#include \"mupdf/exceptions.h\"\n#include \"mupdf/internal.h\"\n\n#include <algorithm>\n#include <float.h>\n\n\n#define MAKE_MUPDF_VERSION_INT(major, minor, patch) ((major << 16) + (minor << 8) + (patch << 0))\n\n#define MUPDF_VERSION_INT MAKE_MUPDF_VERSION_INT(FZ_VERSION_MAJOR, FZ_VERSION_MINOR, FZ_VERSION_PATCH)\n\n#define MUPDF_VERSION_GE(major, minor, patch) \\\n        MUPDF_VERSION_INT >= MAKE_MUPDF_VERSION_INT(major, minor, patch)\n\n/* Define a wrapper for PDF_NAME that returns a mupdf::PdfObj instead of a\npdf_obj*. This avoids implicit construction of a mupdf::PdfObj, which is\ndeliberately prohibited (with `explicit` on constructors) by recent MuPDF. */\n#define PDF_NAME2(X) mupdf::PdfObj(PDF_NAME(X))\n\n/* Returns equivalent of `repr(x)`. */\nstatic std::string repr(PyObject* x)\n{\n    PyObject* repr = PyObject_Repr(x);\n    PyObject* repr_str = PyUnicode_AsEncodedString(repr, \"utf-8\", \"~E~\");\n    #ifdef Py_LIMITED_API\n        const char* repr_str_s = PyBytes_AsString(repr_str);\n    #else\n        const char* repr_str_s = PyBytes_AS_STRING(repr_str);\n    #endif\n    std::string ret = repr_str_s;\n    Py_DECREF(repr_str);\n    Py_DECREF(repr);\n    return ret;\n}\n\n#ifdef Py_LIMITED_API\n    static PyObject* PySequence_ITEM(PyObject* o, Py_ssize_t i)\n    {\n        return PySequence_GetItem(o, i);\n    }\n\n    static const char* PyUnicode_AsUTF8(PyObject* o)\n    {\n        static PyObject* string = nullptr;\n        Py_XDECREF(string);\n        string = PyUnicode_AsUTF8String(o);\n        return PyBytes_AsString(string);\n    }\n#endif\n\n\n/* These are also in pymupdf/__init__.py. */\nconst char MSG_BAD_ANNOT_TYPE[] = \"bad annot type\";\nconst char MSG_BAD_APN[] = \"bad or missing annot AP/N\";\nconst char MSG_BAD_ARG_INK_ANNOT[] = \"arg must be seq of seq of float pairs\";\nconst char MSG_BAD_ARG_POINTS[] = \"bad seq of points\";\nconst char MSG_BAD_BUFFER[] = \"bad type: 'buffer'\";\nconst char MSG_BAD_COLOR_SEQ[] = \"bad color sequence\";\nconst char MSG_BAD_DOCUMENT[] = \"cannot open broken document\";\nconst char MSG_BAD_FILETYPE[] = \"bad filetype\";\nconst char MSG_BAD_LOCATION[] = \"bad location\";\nconst char MSG_BAD_OC_CONFIG[] = \"bad config number\";\nconst char MSG_BAD_OC_LAYER[] = \"bad layer number\";\nconst char MSG_BAD_OC_REF[] = \"bad 'oc' reference\";\nconst char MSG_BAD_PAGEID[] = \"bad page id\";\nconst char MSG_BAD_PAGENO[] = \"bad page number(s)\";\nconst char MSG_BAD_PDFROOT[] = \"PDF has no root\";\nconst char MSG_BAD_RECT[] = \"rect is infinite or empty\";\nconst char MSG_BAD_TEXT[] = \"bad type: 'text'\";\nconst char MSG_BAD_XREF[] = \"bad xref\";\nconst char MSG_COLOR_COUNT_FAILED[] = \"color count failed\";\nconst char MSG_FILE_OR_BUFFER[] = \"need font file or buffer\";\nconst char MSG_FONT_FAILED[] = \"cannot create font\";\nconst char MSG_IS_NO_ANNOT[] = \"is no annotation\";\nconst char MSG_IS_NO_IMAGE[] = \"is no image\";\nconst char MSG_IS_NO_PDF[] = \"is no PDF\";\nconst char MSG_IS_NO_DICT[] = \"object is no PDF dict\";\nconst char MSG_PIX_NOALPHA[] = \"source pixmap has no alpha\";\nconst char MSG_PIXEL_OUTSIDE[] = \"pixel(s) outside image\";\n\n#define JM_BOOL(x) PyBool_FromLong((long) (x))\n\nstatic PyObject *JM_UnicodeFromStr(const char *c);\n\n\n#ifdef _WIN32\n\n/* These functions are not provided on Windows. */\n\nint vasprintf(char** str, const char* fmt, va_list ap)\n{\n    va_list ap2;\n\n    va_copy(ap2, ap);\n    int len = vsnprintf(nullptr, 0, fmt, ap2);\n    va_end(ap2);\n    \n    char* buffer = (char*) malloc(len + 1);\n    if (!buffer)\n    {\n        *str = nullptr;\n        return -1;\n    }\n    va_copy(ap2, ap);\n    int len2 = vsnprintf(buffer, len + 1, fmt, ap2);\n    va_end(ap2);\n    assert(len2 == len);\n    *str = buffer;\n    return len;\n}\n\nint asprintf(char** str, const char* fmt, ...)\n{\n    va_list ap;\n    va_start(ap, fmt);\n    int ret = vasprintf(str, fmt, ap);\n    va_end(ap);\n\n    return ret;\n}\n#endif\n\n\nstatic void messagev(const char* format, va_list va)\n{\n    static PyObject* pymupdf_module = PyImport_ImportModule(\"pymupdf\");\n    static PyObject* message_fn = PyObject_GetAttrString(pymupdf_module, \"message\");\n    char* text;\n    vasprintf(&text, format, va);\n    PyObject* text_py = PyString_FromString(text);\n    PyObject* args = PyTuple_Pack(1, text_py);\n    PyObject* ret = PyObject_CallObject(message_fn, args);\n    Py_XDECREF(ret);\n    Py_XDECREF(args);\n    Py_XDECREF(text_py);\n    free(text);\n}\n\nstatic void messagef(const char* format, ...)\n{\n    va_list args;\n    va_start(args, format);\n    messagev(format, args);\n    va_end(args);\n}\n\nPyObject* JM_EscapeStrFromStr(const char* c)\n{\n    if (!c) return PyUnicode_FromString(\"\");\n    PyObject* val = PyUnicode_DecodeRawUnicodeEscape(c, (Py_ssize_t) strlen(c), \"replace\");\n    if (!val)\n    {\n        val = PyUnicode_FromString(\"\");\n        PyErr_Clear();\n    }\n    return val;\n}\n\nPyObject* JM_EscapeStrFromBuffer(fz_buffer* buff)\n{\n    if (!buff) return PyUnicode_FromString(\"\");\n    unsigned char* s = nullptr;\n    size_t len = mupdf::ll_fz_buffer_storage(buff, &s);\n    PyObject* val = PyUnicode_DecodeRawUnicodeEscape((const char*) s, (Py_ssize_t) len, \"replace\");\n    if (!val)\n    {\n        val = PyUnicode_FromString(\"\");\n        PyErr_Clear();\n    }\n    return val;\n}\n\n//----------------------------------------------------------------------------\n// Deep-copies a source page to the target.\n// Modified version of function of pdfmerge.c: we also copy annotations, but\n// we skip some subtypes. In addition we rotate output.\n//----------------------------------------------------------------------------\nstatic void page_merge(\n        mupdf::PdfDocument& doc_des,\n        mupdf::PdfDocument& doc_src,\n        int page_from,\n        int page_to,\n        int rotate,\n        int links,\n        int copy_annots,\n        mupdf::PdfGraftMap& graft_map\n        )\n{\n    // list of object types (per page) we want to copy\n\n    /* Fixme: on linux these get destructed /after/\n    mupdf/platform/c++/implementation/internal.cpp:s_thread_state, which causes\n    problems - s_thread_state::m_ctx will have been freed. We have a hack\n    that sets s_thread_state::m_ctx when destructed, so it mostly works when\n    s_thread_state.get_context() is called after destruction, but this causes\n    memento leaks and is clearly incorrect.\n    \n    Perhaps we could use pdf_obj* known_page_objs[] = {...} and create PdfObj\n    wrappers as used - this would avoid any cleanup at exit. And it's a general\n    solution to problem of ordering of cleanup of globals.\n    */\n    static pdf_obj* known_page_objs[] = {\n            PDF_NAME(Contents),\n            PDF_NAME(Resources),\n            PDF_NAME(MediaBox),\n            PDF_NAME(CropBox),\n            PDF_NAME(BleedBox),\n            PDF_NAME(TrimBox),\n            PDF_NAME(ArtBox),\n            PDF_NAME(Rotate),\n            PDF_NAME(UserUnit)\n            };\n    int known_page_objs_num = sizeof(known_page_objs) / sizeof(known_page_objs[0]);\n    mupdf::PdfObj   page_ref = mupdf::pdf_lookup_page_obj(doc_src, page_from);\n\n    // make new page dict in dest doc\n    mupdf::PdfObj   page_dict = mupdf::pdf_new_dict(doc_des, 4);\n    mupdf::pdf_dict_put(page_dict, PDF_NAME2(Type), PDF_NAME2(Page));\n\n    for (int i = 0; i < known_page_objs_num; ++i)\n    {\n        mupdf::PdfObj   known_page_obj(known_page_objs[i]);\n        mupdf::PdfObj   obj = mupdf::pdf_dict_get_inheritable(page_ref, known_page_obj);\n        if (obj.m_internal)\n        {\n            mupdf::pdf_dict_put(\n                    page_dict,\n                    known_page_obj,\n                    mupdf::pdf_graft_mapped_object(graft_map, obj)\n                    );\n        }\n    }\n\n    // Copy annotations, but skip Link, Popup, IRT, Widget types\n    // If selected, remove dict keys P (parent) and Popup\n    if (copy_annots)\n    {\n        mupdf::PdfObj old_annots = mupdf::pdf_dict_get(page_ref, PDF_NAME2(Annots));\n        int n = mupdf::pdf_array_len(old_annots);\n        if (n > 0)\n        {\n            mupdf::PdfObj new_annots = mupdf::pdf_dict_put_array(page_dict, PDF_NAME2(Annots), n);\n            for (int i = 0; i < n; i++)\n            {\n                mupdf::PdfObj o = mupdf::pdf_array_get(old_annots, i);\n                if (!o.m_internal || !mupdf::pdf_is_dict(o)) // skip non-dict items\n                {\n                    continue;   // skip invalid/null/non-dict items\n                }\n                if (mupdf::pdf_dict_get(o, PDF_NAME2(IRT)).m_internal) continue;\n                mupdf::PdfObj subtype = mupdf::pdf_dict_get(o, PDF_NAME2(Subtype));\n                if (mupdf::pdf_name_eq(subtype, PDF_NAME2(Link))) continue;\n                if (mupdf::pdf_name_eq(subtype, PDF_NAME2(Popup))) continue;\n                if (mupdf::pdf_name_eq(subtype, PDF_NAME2(Widget))) continue;\n                mupdf::pdf_dict_del(o, PDF_NAME2(Popup));\n                mupdf::pdf_dict_del(o, PDF_NAME2(P));\n                mupdf::PdfObj copy_o = mupdf::pdf_graft_mapped_object(graft_map, o);\n                mupdf::PdfObj annot = mupdf::pdf_new_indirect(\n                        doc_des,\n                        mupdf::pdf_to_num(copy_o),\n                        0\n                        );\n                mupdf::pdf_array_push(new_annots, annot);\n            }\n        }\n    }\n    // rotate the page\n    if (rotate != -1)\n    {\n        mupdf::pdf_dict_put_int(page_dict, PDF_NAME2(Rotate), rotate);\n    }\n    // Now add the page dictionary to dest PDF\n    mupdf::PdfObj ref = mupdf::pdf_add_object(doc_des, page_dict);\n\n    // Insert new page at specified location\n    mupdf::pdf_insert_page(doc_des, page_to, ref);\n}\n\n//-----------------------------------------------------------------------------\n// Copy a range of pages (spage, epage) from a source PDF to a specified\n// location (apage) of the target PDF.\n// If spage > epage, the sequence of source pages is reversed.\n//-----------------------------------------------------------------------------\nstatic void JM_merge_range(\n        mupdf::PdfDocument& doc_des,\n        mupdf::PdfDocument& doc_src,\n        int spage,\n        int epage,\n        int apage,\n        int rotate,\n        int links,\n        int annots,\n        int show_progress,\n        mupdf::PdfGraftMap& graft_map\n        )\n{\n    int afterpage = apage;\n    int counter = 0;  // copied pages counter\n    int total = mupdf::ll_fz_absi(epage - spage) + 1;  // total pages to copy\n\n    if (spage < epage)\n    {\n        for (int page = spage; page <= epage; page++, afterpage++)\n        {\n            page_merge(doc_des, doc_src, page, afterpage, rotate, links, annots, graft_map);\n            counter++;\n            if (show_progress > 0 && counter % show_progress == 0)\n            {\n                messagef(\"Inserted %i of %i pages.\", counter, total);\n            }\n        }\n    }\n    else\n    {\n        for (int page = spage; page >= epage; page--, afterpage++)\n        {\n            page_merge(doc_des, doc_src, page, afterpage, rotate, links, annots, graft_map);\n            counter++;\n            if (show_progress > 0 && counter % show_progress == 0)\n            {\n                messagef(\"Inserted %i of %i pages.\", counter, total);\n            }\n        }\n    }\n}\n\nstatic bool JM_have_operation(mupdf::PdfDocument& pdf)\n{\n    // Ensure valid journalling state\n    if (pdf.m_internal->journal and !mupdf::pdf_undoredo_step(pdf, 0))\n    {\n        return 0;\n    }\n    return 1;\n}\n\nstatic void JM_ensure_operation(mupdf::PdfDocument& pdf)\n{\n    if (!JM_have_operation(pdf))\n    {\n        throw std::runtime_error(\"No journalling operation started\");\n    }\n}\n\n\nstatic void FzDocument_insert_pdf(\n        mupdf::FzDocument& doc,\n        mupdf::FzDocument& src,\n        int from_page,\n        int to_page,\n        int start_at,\n        int rotate,\n        int links,\n        int annots,\n        int show_progress,\n        int final,\n        mupdf::PdfGraftMap& graft_map\n        )\n{\n    //std::cerr << __FILE__ << \":\" << __LINE__ << \":\" << __FUNCTION__ << \"\\n\";\n    mupdf::PdfDocument pdfout = mupdf::pdf_specifics(doc);\n    mupdf::PdfDocument pdfsrc = mupdf::pdf_specifics(src);\n    int outCount = mupdf::fz_count_pages(doc);\n    int srcCount = mupdf::fz_count_pages(src);\n\n    // local copies of page numbers\n    int fp = from_page;\n    int tp = to_page;\n    int sa = start_at;\n\n    // normalize page numbers\n    fp = std::max(fp, 0);               // -1 = first page\n    fp = std::min(fp, srcCount - 1);    // but do not exceed last page\n\n    if (tp < 0) tp = srcCount - 1;      // -1 = last page\n    tp = std::min(tp, srcCount - 1);    // but do not exceed last page\n\n    if (sa < 0) sa = outCount;          // -1 = behind last page\n    sa = std::min(sa, outCount);        // but that is also the limit\n\n    if (!pdfout.m_internal || !pdfsrc.m_internal)\n    {\n        throw std::runtime_error(\"source or target not a PDF\");\n    }\n    JM_ensure_operation(pdfout);\n    JM_merge_range(pdfout, pdfsrc, fp, tp, sa, rotate, links, annots, show_progress, graft_map);\n}\n\nstatic int page_xref(mupdf::FzDocument& this_doc, int pno)\n{\n    int page_count = mupdf::fz_count_pages(this_doc);\n    int n = pno;\n    while (n < 0)\n    {\n        n += page_count;\n    }\n    mupdf::PdfDocument pdf = mupdf::pdf_specifics(this_doc);\n    assert(pdf.m_internal);\n    int xref = 0;\n    if (n >= page_count)\n    {\n        throw std::runtime_error(MSG_BAD_PAGENO);//, PyExc_ValueError);\n    }\n    xref = mupdf::pdf_to_num(mupdf::pdf_lookup_page_obj(pdf, n));\n    return xref;\n}\n\nstatic void _newPage(mupdf::PdfDocument& pdf, int pno=-1, float width=595, float height=842)\n{\n    if (!pdf.m_internal)\n    {\n        throw std::runtime_error(\"is no PDF\");\n    }\n    mupdf::FzRect mediabox(0, 0, width, height);\n    if (pno < -1)\n    {\n        throw std::runtime_error(\"bad page number(s)\");  // Should somehow be Python ValueError\n    }\n    JM_ensure_operation(pdf);\n    // create /Resources and /Contents objects\n    mupdf::PdfObj resources = mupdf::pdf_add_new_dict(pdf, 1);\n    mupdf::FzBuffer contents;\n    mupdf::PdfObj page_obj = mupdf::pdf_add_page(pdf, mediabox, 0, resources, contents);\n    mupdf::pdf_insert_page(pdf, pno, page_obj);\n}\n\nstatic void _newPage(mupdf::FzDocument& self, int pno=-1, float width=595, float height=842)\n{\n    mupdf::PdfDocument pdf = mupdf::pdf_specifics(self);\n    _newPage(pdf, pno, width, height);\n}\n\n\n//------------------------------------------------------------------------\n// return the annotation names (list of /NM entries)\n//------------------------------------------------------------------------\nstatic std::vector< std::string> JM_get_annot_id_list(mupdf::PdfPage& page)\n{\n    std::vector< std::string> names;\n    mupdf::PdfObj annots = mupdf::pdf_dict_get(page.obj(), PDF_NAME2(Annots));\n    if (!annots.m_internal) return names;\n    int n = mupdf::pdf_array_len(annots);\n    for (int i = 0; i < n; i++)\n    {\n        mupdf::PdfObj annot_obj = mupdf::pdf_array_get(annots, i);\n        mupdf::PdfObj name = mupdf::pdf_dict_gets(annot_obj, \"NM\");\n        if (name.m_internal)\n        {\n            names.push_back(mupdf::pdf_to_text_string(name));\n        }\n    }\n    return names;\n}\n\n\n//------------------------------------------------------------------------\n// Add a unique /NM key to an annotation or widget.\n// Append a number to 'stem' such that the result is a unique name.\n//------------------------------------------------------------------------\nstatic void JM_add_annot_id(mupdf::PdfAnnot& annot, const char* stem)\n{\n    mupdf::PdfPage page = mupdf::pdf_annot_page(annot);\n    mupdf::PdfObj annot_obj = mupdf::pdf_annot_obj(annot);\n    std::vector< std::string> names = JM_get_annot_id_list(page);\n    char* stem_id = nullptr;\n    for (int i=0; ; ++i)\n    {\n        free(stem_id);\n        asprintf(&stem_id,  \"fitz-%s%d\", stem, i);\n        if (std::find(names.begin(), names.end(), stem_id) == names.end())\n        {\n            break;\n        }\n    }\n    mupdf::PdfObj name = mupdf::pdf_new_string(stem_id, strlen(stem_id));\n    free(stem_id);\n    mupdf::pdf_dict_puts(annot_obj, \"NM\", name);\n    page.m_internal->doc->resynth_required = 0;\n}\n\n//----------------------------------------------------------------\n// page add_caret_annot\n//----------------------------------------------------------------\nstatic mupdf::PdfAnnot _add_caret_annot(mupdf::PdfPage& page, mupdf::FzPoint& point)\n{\n    mupdf::PdfAnnot annot = mupdf::pdf_create_annot(page, ::PDF_ANNOT_CARET);\n    mupdf::FzPoint  p = point;\n    mupdf::FzRect   r = mupdf::pdf_annot_rect(annot);\n    r = mupdf::fz_make_rect(p.x, p.y, p.x + r.x1 - r.x0, p.y + r.y1 - r.y0);\n    mupdf::pdf_set_annot_rect(annot, r);\n    mupdf::pdf_update_annot(annot);\n    JM_add_annot_id(annot, \"A\");\n    return annot;\n}\n\nstatic mupdf::PdfAnnot _add_caret_annot(mupdf::FzPage& page, mupdf::FzPoint& point)\n{\n    mupdf::PdfPage  pdf_page = mupdf::pdf_page_from_fz_page(page);\n    return _add_caret_annot(pdf_page, point);\n}\n\nstatic const char* Tools_parse_da(mupdf::PdfAnnot& this_annot)\n{\n    const char* da_str = nullptr;\n    mupdf::PdfObj this_annot_obj = mupdf::pdf_annot_obj(this_annot);\n    mupdf::PdfDocument pdf = mupdf::pdf_get_bound_document(this_annot_obj);\n    try\n    {\n        mupdf::PdfObj da = mupdf::pdf_dict_get_inheritable(this_annot_obj, PDF_NAME2(DA));\n        if (!da.m_internal)\n        {\n            mupdf::PdfObj trailer = mupdf::pdf_trailer(pdf);\n            da = mupdf::pdf_dict_getl(\n                    &trailer,\n                    PDF_NAME(Root),\n                    PDF_NAME(AcroForm),\n                    PDF_NAME(DA),\n                    nullptr\n                    );\n        }\n        da_str = mupdf::pdf_to_text_string(da);\n    }\n    catch (std::exception&)\n    {\n        return nullptr;\n    }\n    return da_str;\n}\n\n//----------------------------------------------------------------------------\n// Turn fz_buffer into a Python bytes object\n//----------------------------------------------------------------------------\nstatic PyObject* JM_BinFromBuffer(fz_buffer* buffer)\n{\n    if (!buffer)\n    {\n        return PyBytes_FromStringAndSize(\"\", 0);\n    }\n    unsigned char* c = nullptr;\n    size_t len = mupdf::ll_fz_buffer_storage(buffer, &c);\n    return PyBytes_FromStringAndSize((const char*) c, len);\n}\nstatic PyObject* JM_BinFromBuffer(mupdf::FzBuffer& buffer)\n{\n    return JM_BinFromBuffer( buffer.m_internal);\n}\n\nstatic PyObject* Annot_getAP(mupdf::PdfAnnot& annot)\n{\n    mupdf::PdfObj annot_obj = mupdf::pdf_annot_obj(annot);\n    mupdf::PdfObj ap = mupdf::pdf_dict_getl(\n            &annot_obj,\n            PDF_NAME(AP),\n            PDF_NAME(N),\n            nullptr\n            );\n    if (mupdf::pdf_is_stream(ap))\n    {\n        mupdf::FzBuffer res = mupdf::pdf_load_stream(ap);\n        return JM_BinFromBuffer(res);\n    }\n    return PyBytes_FromStringAndSize(\"\", 0);\n}\n\nvoid Tools_update_da(mupdf::PdfAnnot& this_annot, const char* da_str)\n{\n    mupdf::PdfObj this_annot_obj = mupdf::pdf_annot_obj(this_annot);\n    mupdf::pdf_dict_put_text_string(this_annot_obj, PDF_NAME2(DA), da_str);\n    mupdf::pdf_dict_del(this_annot_obj, PDF_NAME2(DS)); /* not supported */\n    mupdf::pdf_dict_del(this_annot_obj, PDF_NAME2(RC)); /* not supported */\n}\n\nstatic int\njm_float_item(PyObject* obj, Py_ssize_t idx, double* result)\n{\n    PyObject* temp = PySequence_ITEM(obj, idx);\n    if (!temp) return 1;\n    *result = PyFloat_AsDouble(temp);\n    Py_DECREF(temp);\n    if (PyErr_Occurred())\n    {\n        PyErr_Clear();\n        return 1;\n    }\n    return 0;\n}\n\n\nstatic mupdf::FzPoint JM_point_from_py(PyObject* p)\n{\n    fz_point p0 = fz_make_point(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT);\n    if (!p || !PySequence_Check(p) || PySequence_Size(p) != 2)\n    {\n        return p0;\n    }\n    double x;\n    double y;\n    if (jm_float_item(p, 0, &x) == 1) return p0;\n    if (jm_float_item(p, 1, &y) == 1) return p0;\n    if (x < FZ_MIN_INF_RECT) x = FZ_MIN_INF_RECT;\n    if (y < FZ_MIN_INF_RECT) y = FZ_MIN_INF_RECT;\n    if (x > FZ_MAX_INF_RECT) x = FZ_MAX_INF_RECT;\n    if (y > FZ_MAX_INF_RECT) y = FZ_MAX_INF_RECT;\n\n    return fz_make_point(x, y);\n}\n\nstatic int s_list_append_drop(PyObject* list, PyObject* item)\n{\n    if (!list || !PyList_Check(list) || !item)\n    {\n        return -2;\n    }\n    int rc = PyList_Append(list, item);\n    Py_DECREF(item);\n    return rc;\n}\n\nstatic int LIST_APPEND_DROP(PyObject *list, PyObject *item)\n{\n    if (!list || !PyList_Check(list) || !item) return -2;\n    int rc = PyList_Append(list, item);\n    Py_DECREF(item);\n    return rc;\n}\n\nstatic int LIST_APPEND(PyObject *list, PyObject *item)\n{\n    if (!list || !PyList_Check(list) || !item) return -2;\n    int rc = PyList_Append(list, item);\n    return rc;\n}\n\nstatic int DICT_SETITEM_DROP(PyObject *dict, PyObject *key, PyObject *value)\n{\n    if (!dict || !PyDict_Check(dict) || !key || !value) return -2;\n    int rc = PyDict_SetItem(dict, key, value);\n    Py_DECREF(value);\n    return rc;\n}\n\nstatic int DICT_SETITEMSTR_DROP(PyObject *dict, const char *key, PyObject *value)\n{\n    if (!dict || !PyDict_Check(dict) || !key || !value) return -2;\n    int rc = PyDict_SetItemString(dict, key, value);\n    Py_DECREF(value);\n    return rc;\n}\n\n\n//-----------------------------------------------------------------------------\n// Functions converting between PySequences and pymupdf geometry objects\n//-----------------------------------------------------------------------------\nstatic int\njm_init_item(PyObject* obj, Py_ssize_t idx, int* result)\n{\n    PyObject* temp = PySequence_ITEM(obj, idx);\n    if (!temp)\n    {\n        return 1;\n    }\n    if (PyLong_Check(temp))\n    {\n        *result = (int) PyLong_AsLong(temp);\n        Py_DECREF(temp);\n    }\n    else if (PyFloat_Check(temp))\n    {\n        *result = (int) PyFloat_AsDouble(temp);\n        Py_DECREF(temp);\n    }\n    else\n    {\n        Py_DECREF(temp);\n        return 1;\n    }\n    if (PyErr_Occurred())\n    {\n        PyErr_Clear();\n        return 1;\n    }\n    return 0;\n}\n\n// TODO: ------------------------------------------------------------------\n// This is a temporary solution and should be replaced by a C++ extension:\n// There is no way in Python specify an array of fz_point - as is required\n// for function pdf_set_annot_callout_line().\nstatic void JM_set_annot_callout_line(mupdf::PdfAnnot& annot, PyObject *callout, int count)\n{\n    fz_point points[3];\n    mupdf::FzPoint p;\n    for (int i = 0; i < count; i++)\n    {\n        p = JM_point_from_py(PyTuple_GetItem(callout, (Py_ssize_t) i));\n        points[i] = fz_make_point(p.x, p.y);\n    }\n    mupdf::pdf_set_annot_callout_line(annot, points, count);\n}\n\n\n//----------------------------------------------------------------------------\n// Return list of outline xref numbers. Recursive function. Arguments:\n// 'obj' first OL item\n// 'xrefs' empty Python list\n//----------------------------------------------------------------------------\nstatic PyObject* JM_outline_xrefs(mupdf::PdfObj obj, PyObject* xrefs)\n{\n    if (!obj.m_internal)\n    {\n        return xrefs;\n    }\n    PyObject* newxref = nullptr;\n    mupdf::PdfObj thisobj = obj;\n    while (thisobj.m_internal)\n    {\n        int nxr = mupdf::pdf_to_num(thisobj);\n        newxref = PyLong_FromLong((long) nxr);\n        if (PySequence_Contains(xrefs, newxref)\n                or mupdf::pdf_dict_get(thisobj, PDF_NAME2(Type)).m_internal\n                )\n        {\n            // circular ref or top of chain: terminate\n            Py_DECREF(newxref);\n            break;\n        }\n        s_list_append_drop(xrefs, newxref);\n        mupdf::PdfObj first = mupdf::pdf_dict_get(thisobj, PDF_NAME2(First));  // try go down\n        if (mupdf::pdf_is_dict(first))\n        {\n            xrefs = JM_outline_xrefs(first, xrefs);\n        }\n        thisobj = mupdf::pdf_dict_get(thisobj, PDF_NAME2(Next));  // try go next\n        mupdf::PdfObj parent = mupdf::pdf_dict_get(thisobj, PDF_NAME2(Parent));  // get parent\n        if (!mupdf::pdf_is_dict(thisobj))\n        {\n            thisobj = parent;\n        }\n    }\n    return xrefs;\n}\n\n\nPyObject* dictkey_align = NULL;\nPyObject* dictkey_ascender = NULL;\nPyObject* dictkey_bidi = NULL;\nPyObject* dictkey_bbox = NULL;\nPyObject* dictkey_blocks = NULL;\nPyObject* dictkey_bpc = NULL;\nPyObject* dictkey_c = NULL;\nPyObject* dictkey_chars = NULL;\nPyObject* dictkey_color = NULL;\nPyObject* dictkey_colorspace = NULL;\nPyObject* dictkey_content = NULL;\nPyObject* dictkey_creationDate = NULL;\nPyObject* dictkey_cs_name = NULL;\nPyObject* dictkey_da = NULL;\nPyObject* dictkey_dashes = NULL;\nPyObject* dictkey_desc = NULL;\nPyObject* dictkey_descender = NULL;\nPyObject* dictkey_dir = NULL;\nPyObject* dictkey_effect = NULL;\nPyObject* dictkey_ext = NULL;\nPyObject* dictkey_filename = NULL;\nPyObject* dictkey_fill = NULL;\nPyObject* dictkey_flags = NULL;\nPyObject* dictkey_char_bidi = NULL;\nPyObject* dictkey_char_flags = NULL;\nPyObject* dictkey_font = NULL;\nPyObject* dictkey_glyph = NULL;\nPyObject* dictkey_height = NULL;\nPyObject* dictkey_id = NULL;\nPyObject* dictkey_image = NULL;\nPyObject* dictkey_items = NULL;\nPyObject* dictkey_length = NULL;\nPyObject* dictkey_lines = NULL;\nPyObject* dictkey_matrix = NULL;\nPyObject* dictkey_modDate = NULL;\nPyObject* dictkey_name = NULL;\nPyObject* dictkey_number = NULL;\nPyObject* dictkey_origin = NULL;\nPyObject* dictkey_rect = NULL;\nPyObject* dictkey_size = NULL;\nPyObject* dictkey_smask = NULL;\nPyObject* dictkey_spans = NULL;\nPyObject* dictkey_stroke = NULL;\nPyObject* dictkey_style = NULL;\nPyObject* dictkey_subject = NULL;\nPyObject* dictkey_text = NULL;\nPyObject* dictkey_title = NULL;\nPyObject* dictkey_type = NULL;\nPyObject* dictkey_ufilename = NULL;\nPyObject* dictkey_width = NULL;\nPyObject* dictkey_wmode = NULL;\nPyObject* dictkey_xref = NULL;\nPyObject* dictkey_xres = NULL;\nPyObject* dictkey_yres = NULL;\n\nstatic int dict_setitem_drop(PyObject* dict, PyObject* key, PyObject* value)\n{\n    if (!dict || !PyDict_Check(dict) || !key || !value)\n    {\n        return -2;\n    }\n    int rc = PyDict_SetItem(dict, key, value);\n    Py_DECREF(value);\n    return rc;\n}\n\nstatic int dict_setitemstr_drop(PyObject* dict, const char* key, PyObject* value)\n{\n    if (!dict || !PyDict_Check(dict) || !key || !value)\n    {\n        return -2;\n    }\n    int rc = PyDict_SetItemString(dict, key, value);\n    Py_DECREF(value);\n    return rc;\n}\n\n\nstatic void Document_extend_toc_items(mupdf::PdfDocument& pdf, PyObject* items)\n{\n    PyObject* item=nullptr;\n    PyObject* itemdict=nullptr;\n    PyObject* xrefs=nullptr;\n    \n    PyObject* bold = PyUnicode_FromString(\"bold\");\n    PyObject* italic = PyUnicode_FromString(\"italic\");\n    PyObject* collapse = PyUnicode_FromString(\"collapse\");\n    PyObject* zoom = PyUnicode_FromString(\"zoom\");\n    \n    try\n    {\n        /* Need to define these things early because later code uses\n        `goto`; otherwise we get compiler warnings 'jump bypasses variable\n        initialization' */\n        int xref = 0;\n        mupdf::PdfObj   root;\n        mupdf::PdfObj   olroot;\n        mupdf::PdfObj   first;\n        Py_ssize_t  n;\n        Py_ssize_t  m;\n        \n        root = mupdf::pdf_dict_get(mupdf::pdf_trailer(pdf), PDF_NAME2(Root));\n        if (!root.m_internal) goto end;\n        \n        olroot = mupdf::pdf_dict_get(root, PDF_NAME2(Outlines));\n        if (!olroot.m_internal) goto end;\n        \n        first = mupdf::pdf_dict_get(olroot, PDF_NAME2(First));\n        if (!first.m_internal) goto end;\n        \n        xrefs = PyList_New(0);  // pre-allocate an empty list\n        xrefs = JM_outline_xrefs(first, xrefs);\n        n = PySequence_Size(xrefs);\n        m = PySequence_Size(items);\n        if (!n) goto end;\n        \n        if (n != m)\n        {\n            throw std::runtime_error(\"internal error finding outline xrefs\");\n        }\n\n        // update all TOC item dictionaries\n        for (int i = 0; i < n; i++)\n        {\n            jm_init_item(xrefs, i, &xref);\n            item = PySequence_ITEM(items, i);\n            itemdict = PySequence_ITEM(item, 3);\n            if (!itemdict || !PyDict_Check(itemdict))\n            {\n                throw std::runtime_error(\"need non-simple TOC format\");\n            }\n            PyDict_SetItem(itemdict, dictkey_xref, PySequence_ITEM(xrefs, i));\n            mupdf::PdfObj bm = mupdf::pdf_load_object(pdf, xref);\n            int flags = mupdf::pdf_to_int(mupdf::pdf_dict_get(bm, PDF_NAME2(F)));\n            if (flags == 1)\n            {\n                PyDict_SetItem(itemdict, italic, Py_True);\n            }\n            else if (flags == 2)\n            {\n                PyDict_SetItem(itemdict, bold, Py_True);\n            }\n            else if (flags == 3)\n            {\n                PyDict_SetItem(itemdict, italic, Py_True);\n                PyDict_SetItem(itemdict, bold, Py_True);\n            }\n            int count = mupdf::pdf_to_int(mupdf::pdf_dict_get(bm, PDF_NAME2(Count)));\n            if (count < 0)\n            {\n                PyDict_SetItem(itemdict, collapse, Py_True);\n            }\n            else if (count > 0)\n            {\n                PyDict_SetItem(itemdict, collapse, Py_False);\n            }\n            mupdf::PdfObj col = mupdf::pdf_dict_get(bm, PDF_NAME2(C));\n            if (mupdf::pdf_is_array(col) && mupdf::pdf_array_len(col) == 3)\n            {\n                PyObject* color = PyTuple_New(3);\n                PyTuple_SET_ITEM(color, 0, Py_BuildValue(\"f\", mupdf::pdf_to_real(mupdf::pdf_array_get(col, 0))));\n                PyTuple_SET_ITEM(color, 1, Py_BuildValue(\"f\", mupdf::pdf_to_real(mupdf::pdf_array_get(col, 1))));\n                PyTuple_SET_ITEM(color, 2, Py_BuildValue(\"f\", mupdf::pdf_to_real(mupdf::pdf_array_get(col, 2))));\n                dict_setitem_drop(itemdict, dictkey_color, color);\n            }\n            float z=0;\n            mupdf::PdfObj obj = mupdf::pdf_dict_get(bm, PDF_NAME2(Dest));\n            if (!obj.m_internal || !mupdf::pdf_is_array(obj))\n            {\n                obj = mupdf::pdf_dict_getl(&bm, PDF_NAME(A), PDF_NAME(D), nullptr);\n            }\n            if (mupdf::pdf_is_array(obj) && mupdf::pdf_array_len(obj) == 5)\n            {\n                z = mupdf::pdf_to_real(mupdf::pdf_array_get(obj, 4));\n            }\n            dict_setitem_drop(itemdict, zoom, Py_BuildValue(\"f\", z));\n            PyList_SetItem(item, 3, itemdict);\n            PyList_SetItem(items, i, item);\n        }\n        end:;\n    }\n    catch (std::exception&)\n    {\n    }\n    Py_CLEAR(xrefs);\n    Py_CLEAR(bold);\n    Py_CLEAR(italic);\n    Py_CLEAR(collapse);\n    Py_CLEAR(zoom);\n}\n\nstatic void Document_extend_toc_items(mupdf::FzDocument& document, PyObject* items)\n{\n    mupdf::PdfDocument  pdf = mupdf::pdf_document_from_fz_document(document);\n    return Document_extend_toc_items(pdf, items);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_rect\n//-----------------------------------------------------------------------------\nstatic PyObject* JM_py_from_rect(fz_rect r)\n{\n    return Py_BuildValue(\"ffff\", r.x0, r.y0, r.x1, r.y1);\n}\nstatic PyObject* JM_py_from_rect(mupdf::FzRect r)\n{\n    return JM_py_from_rect(*r.internal());\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_point\n//-----------------------------------------------------------------------------\nstatic PyObject* JM_py_from_point(fz_point p)\n{\n    return Py_BuildValue(\"ff\", p.x, p.y);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_quad.\n//-----------------------------------------------------------------------------\nstatic PyObject *\nJM_py_from_quad(fz_quad q)\n{\n    return Py_BuildValue(\"((f,f),(f,f),(f,f),(f,f))\",\n                          q.ul.x, q.ul.y, q.ur.x, q.ur.y,\n                          q.ll.x, q.ll.y, q.lr.x, q.lr.y);\n}\n\n//----------------------------------------------------------------\n// annotation rectangle\n//----------------------------------------------------------------\nstatic mupdf::FzRect Annot_rect(mupdf::PdfAnnot& annot)\n{\n    mupdf::FzRect rect = mupdf::pdf_bound_annot(annot);\n    return rect;\n}\n\nstatic PyObject* Annot_rect3(mupdf::PdfAnnot& annot)\n{\n    fz_rect rect = mupdf::ll_pdf_bound_annot(annot.m_internal);\n    return JM_py_from_rect(rect);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence to fz_rect. Default: infinite rect\n//-----------------------------------------------------------------------------\nstatic fz_rect JM_rect_from_py(PyObject* r)\n{\n    if (!r || !PySequence_Check(r) || PySequence_Size(r) != 4)\n    {\n        return *mupdf::FzRect(mupdf::FzRect::Fixed_INFINITE).internal();// fz_infinite_rect;\n    }\n    double f[4];\n    for (int i = 0; i < 4; i++)\n    {\n        if (jm_float_item(r, i, &f[i]) == 1)\n        {\n            return *mupdf::FzRect(mupdf::FzRect::Fixed_INFINITE).internal();\n        }\n        if (f[i] < FZ_MIN_INF_RECT) f[i] = FZ_MIN_INF_RECT;\n        if (f[i] > FZ_MAX_INF_RECT) f[i] = FZ_MAX_INF_RECT;\n    }\n    return mupdf::ll_fz_make_rect(\n            (float) f[0],\n            (float) f[1],\n            (float) f[2],\n            (float) f[3]\n            );\n}\n\n//-----------------------------------------------------------------------------\n// PySequence to fz_matrix. Default: fz_identity\n//-----------------------------------------------------------------------------\nstatic fz_matrix JM_matrix_from_py(PyObject* m)\n{\n    double a[6];\n\n    if (!m || !PySequence_Check(m) || PySequence_Size(m) != 6)\n    {\n        return fz_identity;\n    }\n    for (int i = 0; i < 6; i++)\n    {\n        if (jm_float_item(m, i, &a[i]) == 1)\n        {\n            return *mupdf::FzMatrix().internal();\n        }\n    }\n    return mupdf::ll_fz_make_matrix(\n            (float) a[0],\n            (float) a[1],\n            (float) a[2],\n            (float) a[3],\n            (float) a[4],\n            (float) a[5]\n            );\n}\n\nPyObject* util_transform_rect(PyObject* rect, PyObject* matrix)\n{\n    return JM_py_from_rect(\n            mupdf::ll_fz_transform_rect(\n                JM_rect_from_py(rect),\n                JM_matrix_from_py(matrix)\n                )\n            );\n}\n\n//----------------------------------------------------------------------------\n// return normalized /Rotate value:one of 0, 90, 180, 270\n//----------------------------------------------------------------------------\nstatic int JM_norm_rotation(int rotate)\n{\n    while (rotate < 0) rotate += 360;\n    while (rotate >= 360) rotate -= 360;\n    if (rotate % 90 != 0) return 0;\n    return rotate;\n}\n\n\n//----------------------------------------------------------------------------\n// return a PDF page's /Rotate value: one of (0, 90, 180, 270)\n//----------------------------------------------------------------------------\nstatic int JM_page_rotation(mupdf::PdfPage& page)\n{\n    int rotate = 0;\n    rotate = mupdf::pdf_to_int(\n            mupdf::pdf_dict_get_inheritable(page.obj(), PDF_NAME2(Rotate))\n            );\n    rotate = JM_norm_rotation(rotate);\n    return rotate;\n}\n\n\n//----------------------------------------------------------------------------\n// return a PDF page's MediaBox\n//----------------------------------------------------------------------------\nstatic mupdf::FzRect JM_mediabox(mupdf::PdfObj& page_obj)\n{\n    mupdf::FzRect mediabox = mupdf::pdf_to_rect(\n            mupdf::pdf_dict_get_inheritable(page_obj, PDF_NAME2(MediaBox))\n            );\n    if (mupdf::fz_is_empty_rect(mediabox) || mupdf::fz_is_infinite_rect(mediabox))\n    {\n        mediabox.x0 = 0;\n        mediabox.y0 = 0;\n        mediabox.x1 = 612;\n        mediabox.y1 = 792;\n    }\n    mupdf::FzRect   page_mediabox;\n    page_mediabox.x0 = mupdf::fz_min(mediabox.x0, mediabox.x1);\n    page_mediabox.y0 = mupdf::fz_min(mediabox.y0, mediabox.y1);\n    page_mediabox.x1 = mupdf::fz_max(mediabox.x0, mediabox.x1);\n    page_mediabox.y1 = mupdf::fz_max(mediabox.y0, mediabox.y1);\n    if (0\n            || page_mediabox.x1 - page_mediabox.x0 < 1\n            || page_mediabox.y1 - page_mediabox.y0 < 1\n            )\n    {\n        page_mediabox = *mupdf::FzRect(mupdf::FzRect::Fixed_UNIT).internal(); //fz_unit_rect;\n    }\n    return page_mediabox;\n}\n\n\n//----------------------------------------------------------------------------\n// return a PDF page's CropBox\n//----------------------------------------------------------------------------\nmupdf::FzRect JM_cropbox(mupdf::PdfObj& page_obj)\n{\n    mupdf::FzRect mediabox = JM_mediabox(page_obj);\n    mupdf::FzRect cropbox = mupdf::pdf_to_rect(\n                mupdf::pdf_dict_get_inheritable(page_obj, PDF_NAME2(CropBox))\n                );\n    if (mupdf::fz_is_infinite_rect(cropbox) || mupdf::fz_is_empty_rect(cropbox))\n    {\n        cropbox = mediabox;\n    }\n    float y0 = mediabox.y1 - cropbox.y1;\n    float y1 = mediabox.y1 - cropbox.y0;\n    cropbox.y0 = y0;\n    cropbox.y1 = y1;\n    return cropbox;\n}\n\n\n//----------------------------------------------------------------------------\n// calculate width and height of the UNROTATED page\n//----------------------------------------------------------------------------\nstatic mupdf::FzPoint JM_cropbox_size(mupdf::PdfObj& page_obj)\n{\n    mupdf::FzPoint size;\n    mupdf::FzRect rect = JM_cropbox(page_obj);\n    float w = (rect.x0 < rect.x1) ? rect.x1 - rect.x0 : rect.x0 - rect.x1;\n    float h = (rect.y0 < rect.y1) ? rect.y1 - rect.y0 : rect.y0 - rect.y1;\n    size = fz_make_point(w, h);\n    return size;\n}\n\n\n//----------------------------------------------------------------------------\n// calculate page rotation matrices\n//----------------------------------------------------------------------------\nstatic mupdf::FzMatrix JM_rotate_page_matrix(mupdf::PdfPage& page)\n{\n    if (!page.m_internal)\n    {\n        return *mupdf::FzMatrix().internal();  // no valid pdf page given\n    }\n    int rotation = JM_page_rotation(page);\n    if (rotation == 0)\n    {\n        return *mupdf::FzMatrix().internal();  // no rotation\n    }\n    auto po = page.obj();\n    mupdf::FzPoint cb_size = JM_cropbox_size(po);\n    float w = cb_size.x;\n    float h = cb_size.y;\n    mupdf::FzMatrix m;\n    if (rotation == 90)\n    {\n        m = mupdf::fz_make_matrix(0, 1, -1, 0, h, 0);\n    }\n    else if (rotation == 180)\n    {\n        m = mupdf::fz_make_matrix(-1, 0, 0, -1, w, h);\n    }\n    else\n    {\n        m = mupdf::fz_make_matrix(0, -1, 1, 0, 0, w);\n    }\n    return m;\n}\n\n\nstatic mupdf::FzMatrix JM_derotate_page_matrix(mupdf::PdfPage& page)\n{  // just the inverse of rotation\n    return mupdf::fz_invert_matrix(JM_rotate_page_matrix(page));\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_matrix\n//-----------------------------------------------------------------------------\nstatic PyObject* JM_py_from_matrix(mupdf::FzMatrix m)\n{\n    return Py_BuildValue(\"ffffff\", m.a, m.b, m.c, m.d, m.e, m.f);\n}\n\nstatic mupdf::FzMatrix Page_derotate_matrix(mupdf::PdfPage& pdfpage)\n{\n    if (!pdfpage.m_internal)\n    {\n        return mupdf::FzMatrix();\n    }\n    return JM_derotate_page_matrix(pdfpage);\n}\n\nstatic mupdf::FzMatrix Page_derotate_matrix(mupdf::FzPage& page)\n{\n    mupdf::PdfPage pdf_page = mupdf::pdf_page_from_fz_page(page);\n    return Page_derotate_matrix(pdf_page);\n}\n\n\nstatic PyObject *lll_JM_get_annot_xref_list(pdf_obj *page_obj)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    PyObject *names = PyList_New(0);\n    pdf_obj *id, *subtype, *annots, *annot_obj;\n    int xref, type, i, n;\n    fz_try(ctx) {\n        annots = pdf_dict_get(ctx, page_obj, PDF_NAME(Annots));\n        n = pdf_array_len(ctx, annots);\n        for (i = 0; i < n; i++) {\n            annot_obj = pdf_array_get(ctx, annots, i);\n            xref = pdf_to_num(ctx, annot_obj);\n            subtype = pdf_dict_get(ctx, annot_obj, PDF_NAME(Subtype));\n            if (!subtype) {\n                continue;  // subtype is required\n            }\n            type = pdf_annot_type_from_string(ctx, pdf_to_name(ctx, subtype));\n            if (type == PDF_ANNOT_UNKNOWN) {\n                continue;  // only accept valid annot types\n            }\n            id = pdf_dict_gets(ctx, annot_obj, \"NM\");\n            LIST_APPEND_DROP(names, Py_BuildValue(\"iis\", xref, type, pdf_to_text_string(ctx, id)));\n        }\n    }\n    fz_catch(ctx) {\n        return names;\n    }\n    return names;\n}\n//------------------------------------------------------------------------\n// return the xrefs and /NM ids of a page's annots, links and fields\n//------------------------------------------------------------------------\nstatic PyObject* JM_get_annot_xref_list(const mupdf::PdfObj& page_obj)\n{\n    if (!page_obj.m_internal)\n    {\n        PyObject* names = PyList_New(0);\n        return names;\n    }\n    return lll_JM_get_annot_xref_list( page_obj.m_internal);\n}\n\nstatic mupdf::FzBuffer JM_object_to_buffer(const mupdf::PdfObj& what, int compress, int ascii)\n{\n    mupdf::FzBuffer res = mupdf::fz_new_buffer(512);\n    mupdf::FzOutput out(res);\n    mupdf::pdf_print_obj(out, what, compress, ascii);\n    out.fz_close_output();\n    mupdf::fz_terminate_buffer(res);\n    return res;\n}\n\nstatic PyObject* JM_EscapeStrFromBuffer(mupdf::FzBuffer& buff)\n{\n    if (!buff.m_internal)\n    {\n        return PyUnicode_FromString(\"\");\n    }\n    unsigned char* s = nullptr;\n    size_t len = mupdf::fz_buffer_storage(buff, &s);\n    PyObject* val = PyUnicode_DecodeRawUnicodeEscape((const char*) s, (Py_ssize_t) len, \"replace\");\n    if (!val)\n    {\n        val = PyUnicode_FromString(\"\");\n        PyErr_Clear();\n    }\n    return val;\n}\n\nstatic PyObject* xref_object(mupdf::PdfDocument& pdf, int xref, int compressed=0, int ascii=0)\n{\n    if (!pdf.m_internal)\n    {\n        throw std::runtime_error(MSG_IS_NO_PDF);\n    }\n    int xreflen = mupdf::pdf_xref_len(pdf);\n    if ((xref < 1 || xref >= xreflen) and xref != -1) \n    {\n        throw std::runtime_error(MSG_BAD_XREF);\n    }\n    mupdf::PdfObj obj = (xref > 0) ? mupdf::pdf_load_object(pdf, xref) : mupdf::pdf_trailer(pdf);\n    mupdf::FzBuffer res = JM_object_to_buffer(mupdf::pdf_resolve_indirect(obj), compressed, ascii);\n    PyObject* text = JM_EscapeStrFromBuffer(res);\n    return text;\n}\n\nstatic PyObject* xref_object(mupdf::FzDocument& document, int xref, int compressed=0, int ascii=0)\n{\n    mupdf::PdfDocument pdf = mupdf::pdf_document_from_fz_document(document);\n    return xref_object(pdf, xref, compressed, ascii);\n}\n\n\n//-------------------------------------\n// fz_output for Python file objects\n//-------------------------------------\n\nstatic PyObject* Link_is_external(mupdf::FzLink& this_link)\n{\n    const char* uri = this_link.m_internal->uri;\n    if (!uri)\n    {\n        return PyBool_FromLong(0);\n    }\n    bool ret = mupdf::fz_is_external_link(uri);\n    return PyBool_FromLong((long) ret);\n}\n\nstatic mupdf::FzLink Link_next(mupdf::FzLink& this_link)\n{\n    return this_link.next();\n}\n\n\n//-----------------------------------------------------------------------------\n// create PDF object from given string\n//-----------------------------------------------------------------------------\nstatic pdf_obj *lll_JM_pdf_obj_from_str(fz_context *ctx, pdf_document *doc, const char *src)\n{\n    pdf_obj *result = NULL;\n    pdf_lexbuf lexbuf;\n    fz_stream *stream = fz_open_memory(ctx, (unsigned char *)src, strlen(src));\n\n    pdf_lexbuf_init(ctx, &lexbuf, PDF_LEXBUF_SMALL);\n\n    fz_try(ctx) {\n        result = pdf_parse_stm_obj(ctx, doc, stream, &lexbuf);\n    }\n\n    fz_always(ctx) {\n        pdf_lexbuf_fin(ctx, &lexbuf);\n        fz_drop_stream(ctx, stream);\n    }\n\n    fz_catch(ctx) {\n        mupdf::internal_throw_exception(ctx);\n    }\n\n    return result;\n\n}\n\n/*********************************************************************/\n// Page._addAnnot_FromString\n// Add new links provided as an array of string object definitions.\n/*********************************************************************/\nPyObject* Page_addAnnot_FromString(mupdf::PdfPage& page, PyObject* linklist)\n{\n    PyObject* txtpy = nullptr;\n    int lcount = (int) PySequence_Size(linklist); // link count\n    //printf(\"Page_addAnnot_FromString(): lcount=%i\\n\", lcount);\n    if (lcount < 1)\n    {\n        Py_RETURN_NONE;\n    }\n    try\n    {\n        // insert links from the provided sources\n        if (!page.m_internal)\n        {\n            throw std::runtime_error(MSG_IS_NO_PDF);\n        }\n        if (!mupdf::pdf_dict_get(page.obj(), PDF_NAME2(Annots)).m_internal)\n        {\n            mupdf::pdf_dict_put_array(page.obj(), PDF_NAME2(Annots), lcount);\n        }\n        mupdf::PdfObj annots = mupdf::pdf_dict_get(page.obj(), PDF_NAME2(Annots));\n        mupdf::PdfDocument doc = page.doc();\n        //printf(\"lcount=%i\\n\", lcount);\n        fz_context* ctx = mupdf::internal_context_get();\n        for (int i = 0; i < lcount; i++)\n        {\n            const char* text = nullptr;\n            txtpy = PySequence_ITEM(linklist, (Py_ssize_t) i);\n            text = PyUnicode_AsUTF8(txtpy);\n            Py_CLEAR(txtpy);\n            if (!text)\n            {\n                messagef(\"skipping bad link / annot item %i.\", i);\n                continue;\n            }\n            try\n            {\n                pdf_obj* obj = lll_JM_pdf_obj_from_str(ctx, doc.m_internal, text);\n                pdf_obj* annot = pdf_add_object_drop(\n                        ctx,\n                        doc.m_internal,\n                        obj\n                        );\n                pdf_obj* ind_obj = pdf_new_indirect(ctx, doc.m_internal, pdf_to_num(ctx, annot), 0);\n                pdf_array_push_drop(ctx, annots.m_internal, ind_obj);\n                pdf_drop_obj(ctx, annot);\n             }\n            catch (std::exception&)\n            {\n                messagef(\"skipping bad link / annot item %i.\", i);\n            }\n        }\n    }\n    catch (std::exception&)\n    {\n        PyErr_Clear();\n        return nullptr;\n    }\n    Py_RETURN_NONE;\n}\n\nPyObject* Page_addAnnot_FromString(mupdf::FzPage& page, PyObject* linklist)\n{\n    mupdf::PdfPage pdf_page = mupdf::pdf_page_from_fz_page(page);\n    return Page_addAnnot_FromString(pdf_page, linklist);\n}\n\nstatic int page_count_fz2(void* document)\n{\n    mupdf::FzDocument* document2 = (mupdf::FzDocument*) document;\n    return mupdf::fz_count_pages(*document2);\n}\n\nstatic int page_count_fz(mupdf::FzDocument& document)\n{\n    return mupdf::fz_count_pages(document);\n}\n\nstatic int page_count_pdf(mupdf::PdfDocument& pdf)\n{\n    mupdf::FzDocument document = pdf.super();\n    return page_count_fz(document);\n}\n\nstatic int page_count(mupdf::FzDocument& document)\n{\n    return mupdf::fz_count_pages(document);\n}\n\nstatic int page_count(mupdf::PdfDocument& pdf)\n{\n    mupdf::FzDocument document = pdf.super();\n    return page_count(document);\n}\n\nstatic PyObject* page_annot_xrefs(mupdf::FzDocument& document, mupdf::PdfDocument& pdf, int pno)\n{\n    int page_count = mupdf::fz_count_pages(document);\n    int n = pno;\n    while (n < 0)\n    {\n        n += page_count;\n    }\n    PyObject* annots = nullptr;\n    if (n >= page_count)\n    {\n        throw std::runtime_error(MSG_BAD_PAGENO);\n    }\n    if (!pdf.m_internal)\n    {\n        throw std::runtime_error(MSG_IS_NO_PDF);\n    }\n    annots = JM_get_annot_xref_list(mupdf::pdf_lookup_page_obj(pdf, n));\n    return annots;\n}\n\nstatic PyObject* page_annot_xrefs(mupdf::FzDocument& document, int pno)\n{\n    mupdf::PdfDocument pdf = mupdf::pdf_specifics(document);\n    return page_annot_xrefs(document, pdf, pno);\n}\n\nstatic PyObject* page_annot_xrefs(mupdf::PdfDocument& pdf, int pno)\n{\n    mupdf::FzDocument document = pdf.super();\n    return page_annot_xrefs(document, pdf, pno);\n}\n\nstatic bool Outline_is_external(mupdf::FzOutline* outline)\n{\n    if (!outline->m_internal->uri)\n    {\n        return false;\n    }\n    return mupdf::ll_fz_is_external_link(outline->m_internal->uri);\n}\n\nint ll_fz_absi(int i)\n{\n    return mupdf::ll_fz_absi(i);\n}\n\nenum\n{\n    TEXT_FONT_SUPERSCRIPT = 1,\n    TEXT_FONT_ITALIC = 2,\n    TEXT_FONT_SERIFED = 4,\n    TEXT_FONT_MONOSPACED = 8,\n    TEXT_FONT_BOLD = 16,\n};\n\nint g_skip_quad_corrections = 0;\nint g_subset_fontnames = 0;\nint g_small_glyph_heights = 0;\n\nvoid set_skip_quad_corrections(int on)\n{\n    g_skip_quad_corrections = on;\n}\n\nvoid set_subset_fontnames(int on)\n{\n    g_subset_fontnames = on;\n}\n\nvoid set_small_glyph_heights(int on)\n{\n    g_small_glyph_heights = on;\n}\n\nstruct jm_lineart_device\n{\n    fz_device super;\n    \n    PyObject* out = {};\n    PyObject* method = {};\n    PyObject* pathdict = {};\n    PyObject* scissors = {};\n    float pathfactor = {};\n    fz_matrix ctm = {};\n    fz_matrix ptm = {};\n    fz_matrix rot = {};\n    fz_point lastpoint = {};\n    fz_point firstpoint = {};\n    int havemove = 0;\n    fz_rect pathrect = {};\n    int clips = {};\n    int linecount = {};\n    int path_type = {};\n    long depth = {};\n    size_t seqno = {};\n    char* layer_name;\n};\n\n\nstatic void jm_lineart_drop_device(fz_context *ctx, fz_device *dev_)\n{\n    jm_lineart_device *dev = (jm_lineart_device *)dev_;\n    if (PyList_Check(dev->out)) {\n        Py_CLEAR(dev->out);\n    }\n    Py_CLEAR(dev->method);\n    Py_CLEAR(dev->scissors);\n    mupdf::ll_fz_free(dev->layer_name);\n    dev->layer_name = nullptr;\n}\n\ntypedef jm_lineart_device jm_tracedraw_device;\n\n// need own versions of ascender / descender\nstatic float JM_font_ascender(fz_font* font)\n{\n    if (g_skip_quad_corrections)\n    {\n        return 0.8f;\n    }\n    return mupdf::ll_fz_font_ascender(font);\n}\n\nstatic float JM_font_descender(fz_font* font)\n{\n    if (g_skip_quad_corrections)\n    {\n        return -0.2f;\n    }\n    return mupdf::ll_fz_font_descender(font);\n}\n\n\n//----------------------------------------------------------------\n// Return true if character is considered to be a word delimiter\n//----------------------------------------------------------------\nstatic int \nJM_is_word_delimiter(int c, PyObject *delimiters)\n{\n    if (c <= 32 || c == 160) return 1;  // a standard delimiter\n    if (0x202a <= c && c <= 0x202e)\n    {\n        return 1; // change between writing directions\n    }\n\n    // extra delimiters must be a non-empty sequence\n    if (!delimiters || PyObject_Not(delimiters) || !PySequence_Check(delimiters)) {  \n        return 0;\n    }\n\n    // convert to tuple for easier looping\n    PyObject *delims = PySequence_Tuple(delimiters);\n    if (!delims) {\n        PyErr_Clear();\n        return 0;\n    }\n\n    // Make 1-char PyObject from character given as integer\n    PyObject *cchar = Py_BuildValue(\"C\", c);  // single character PyObject\n    Py_ssize_t i, len = PyTuple_Size(delims);\n    for (i = 0; i < len; i++) {\n        int rc = PyUnicode_Compare(cchar, PyTuple_GET_ITEM(delims, i));\n        if (rc == 0) {  // equal to a delimiter character\n            Py_DECREF(cchar);\n            Py_DECREF(delims);\n            PyErr_Clear();\n            return 1;\n        }\n    }\n\n    Py_DECREF(delims);\n    PyErr_Clear();\n    return 0;\n}\n\nstatic int \nJM_is_rtl_char(int c)\n{\n    if (c < 0x590 || c > 0x900) return 0;\n    return 1;\n}\n\nstatic const char* JM_font_name(fz_font* font)\n{\n    const char* name = mupdf::ll_fz_font_name(font);\n    const char* s = strchr(name, '+');\n    if (g_subset_fontnames || !s || s-name != 6)\n    {\n        return name;\n    }\n    return s + 1;\n}\n\nstatic void jm_trace_text_span(\n        jm_tracedraw_device* dev,\n        fz_text_span* span,\n        int type,\n        fz_matrix ctm,\n        fz_colorspace* colorspace,\n        const float* color,\n        float alpha,\n        size_t seqno,\n        const fz_stroke_state* stroke\n        )\n{\n    //printf(\"extra.jm_trace_text_span(): seqno=%zi\\n\", seqno);\n    //fz_matrix join = mupdf::ll_fz_concat(span->trm, ctm);\n    //double fsize = sqrt(fabs((double) span->trm.a * (double) span->trm.d));\n    fz_matrix mat = mupdf::ll_fz_concat(span->trm, ctm); // text transformation matrix\n    fz_point dir = mupdf::ll_fz_transform_vector(mupdf::ll_fz_make_point(1, 0), mat); // writing direction\n    double fsize = sqrt(dir.x * dir.x + dir.y * dir.y); // font size\n\n    dir = mupdf::ll_fz_normalize_vector(dir);\n\n    // compute effective ascender / descender\n    double asc = (double) JM_font_ascender(span->font);\n    double dsc = (double) JM_font_descender(span->font);\n    if (asc < 1e-3) {  // probably Tesseract font\n        dsc = -0.1;\n        asc = 0.9;\n    }\n\n    double ascsize = asc * fsize / (asc - dsc);\n    double dscsize = dsc * fsize / (asc - dsc);\n    int fflags = 0; // font flags\n    int mono = mupdf::ll_fz_font_is_monospaced(span->font);\n    fflags += mono * TEXT_FONT_MONOSPACED;\n    fflags += mupdf::ll_fz_font_is_italic(span->font) * TEXT_FONT_ITALIC;\n    fflags += mupdf::ll_fz_font_is_serif(span->font) * TEXT_FONT_SERIFED;\n    fflags += mupdf::ll_fz_font_is_bold(span->font) * TEXT_FONT_BOLD;\n\n    // walk through characters of span\n    fz_matrix rot = mupdf::ll_fz_make_matrix(dir.x, dir.y, -dir.y, dir.x, 0, 0);\n    if (dir.x == -1)\n    {\n        // left-right flip\n        rot.d = 1;\n    }\n    PyObject* chars = PyTuple_New(span->len);\n    double space_adv = 0;\n    double last_adv = 0;\n    fz_rect span_bbox;\n    \n    for (int i = 0; i < span->len; i++)\n    {\n        double adv = 0;\n        if (span->items[i].gid >= 0)\n        {\n            adv = (double) mupdf::ll_fz_advance_glyph(span->font, span->items[i].gid, span->wmode);\n        }\n        adv *= fsize;\n        last_adv = adv;\n        if (span->items[i].ucs == 32)\n        {\n            space_adv = adv;\n        }\n        fz_point char_orig;\n        char_orig = fz_make_point(span->items[i].x, span->items[i].y);\n        char_orig = fz_transform_point(char_orig, ctm);\n        fz_matrix m1 = mupdf::ll_fz_make_matrix(1, 0, 0, 1, -char_orig.x, -char_orig.y);\n        m1 = mupdf::ll_fz_concat(m1, rot);\n        m1 = mupdf::ll_fz_concat(m1, mupdf::ll_fz_make_matrix(1, 0, 0, 1, char_orig.x, char_orig.y));\n        float x0 = char_orig.x;\n        float x1 = x0 + adv;\n        float y0;\n        float y1;\n        if (\n                (mat.d > 0 && (dir.x == 1 || dir.x == -1))\n                ||\n                (mat.b !=0 && mat.b == -mat.c)\n                )   // up-down flip\n        {\n            // up-down flip\n            y0 = char_orig.y + dscsize;\n            y1 = char_orig.y + ascsize;\n        }\n        else\n        {\n            y0 = char_orig.y - ascsize;\n            y1 = char_orig.y - dscsize;\n        }\n        fz_rect char_bbox = mupdf::ll_fz_make_rect(x0, y0, x1, y1);\n        char_bbox = mupdf::ll_fz_transform_rect(char_bbox, m1);\n        PyTuple_SET_ITEM(\n                chars,\n                (Py_ssize_t) i,\n                Py_BuildValue(\n                    \"ii(ff)(ffff)\",\n                    span->items[i].ucs,\n                    span->items[i].gid,\n                    char_orig.x,\n                    char_orig.y,\n                    char_bbox.x0,\n                    char_bbox.y0,\n                    char_bbox.x1,\n                    char_bbox.y1\n                    )\n                );\n        if (i > 0)\n        {\n            span_bbox = mupdf::ll_fz_union_rect(span_bbox, char_bbox);\n        }\n        else\n        {\n            span_bbox = char_bbox;\n        }\n    }\n    if (!space_adv)\n    {\n        if (!(fflags & TEXT_FONT_MONOSPACED))\n        {\n            fz_font* out_font = nullptr;\n            space_adv = mupdf::ll_fz_advance_glyph(\n                    span->font,\n                    mupdf::ll_fz_encode_character_with_fallback(span->font, 32, 0, 0, &out_font),\n                    span->wmode\n                    );\n            space_adv *= fsize;\n            if (!space_adv)\n            {\n                space_adv = last_adv;\n            }\n        }\n        else\n        {\n            space_adv = last_adv; // for mono any char width suffices\n        }\n    }\n    // make the span dictionary\n    PyObject* span_dict = PyDict_New();\n    dict_setitemstr_drop(span_dict, \"dir\", JM_py_from_point(dir));\n    dict_setitem_drop(span_dict, dictkey_font, JM_EscapeStrFromStr(JM_font_name(span->font)));\n    dict_setitem_drop(span_dict, dictkey_wmode, PyLong_FromLong((long) span->wmode));\n    dict_setitem_drop(span_dict, dictkey_flags, PyLong_FromLong((long) fflags));\n    dict_setitemstr_drop(span_dict, \"bidi_lvl\", PyLong_FromLong((long) span->bidi_level));\n    dict_setitemstr_drop(span_dict, \"bidi_dir\", PyLong_FromLong((long) span->markup_dir));\n    dict_setitem_drop(span_dict, dictkey_ascender, PyFloat_FromDouble(asc));\n    dict_setitem_drop(span_dict, dictkey_descender, PyFloat_FromDouble(dsc));\n    dict_setitem_drop(span_dict, dictkey_colorspace, PyLong_FromLong(3));\n    float rgb[3];\n    if (colorspace)\n    {\n        mupdf::ll_fz_convert_color(\n                colorspace,\n                color,\n                mupdf::ll_fz_device_rgb(),\n                rgb,\n                nullptr,\n                fz_default_color_params\n                );\n    }\n    else\n    {\n        rgb[0] = rgb[1] = rgb[2] = 0;\n    }\n    if (0)\n    {\n        std::cout << \" fsize=\" << fsize;\n        if (stroke)\n        {\n            std::cout  << \" linewidth=\" << stroke->linewidth;\n        }\n        std::cout << \"\\n\";\n    }\n    dict_setitem_drop(span_dict, dictkey_color, Py_BuildValue(\"fff\", rgb[0], rgb[1], rgb[2]));\n    dict_setitem_drop(span_dict, dictkey_size, PyFloat_FromDouble(fsize));\n    dict_setitemstr_drop(span_dict, \"opacity\", PyFloat_FromDouble((double) alpha));\n    if (stroke)\n        dict_setitemstr_drop(span_dict, \"linewidth\", PyFloat_FromDouble((double) stroke->linewidth));\n    else\n        dict_setitemstr_drop(span_dict, \"linewidth\", Py_None);\n    dict_setitemstr_drop(span_dict, \"spacewidth\", PyFloat_FromDouble(space_adv));\n    dict_setitem_drop(span_dict, dictkey_type, PyLong_FromLong((long) type));\n    dict_setitem_drop(span_dict, dictkey_bbox, JM_py_from_rect(span_bbox));\n    dict_setitemstr_drop(span_dict, \"layer\", JM_UnicodeFromStr(dev->layer_name));\n    dict_setitemstr_drop(span_dict, \"seqno\", PyLong_FromSize_t(seqno));\n    dict_setitem_drop(span_dict, dictkey_chars, chars);\n    //std::cout << \"span_dict=\" << repr(span_dict) << \"\\n\";\n    s_list_append_drop(dev->out, span_dict);\n}\n\nstatic inline void jm_increase_seqno(fz_context* ctx, fz_device* dev_)\n{\n    jm_tracedraw_device* dev = (jm_tracedraw_device*) dev_;\n    dev->seqno += 1;\n}\n\nstatic void jm_fill_path(\n        fz_context* ctx,\n        fz_device* dev,\n        const fz_path*,\n        int even_odd,\n        fz_matrix,\n        fz_colorspace*,\n        const float* color,\n        float alpha,\n        fz_color_params\n        )\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_fill_shade(\n        fz_context* ctx,\n        fz_device* dev,\n        fz_shade* shd,\n        fz_matrix ctm,\n        float alpha,\n        fz_color_params color_params\n        )\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_fill_image(\n        fz_context* ctx,\n        fz_device* dev,\n        fz_image* img,\n        fz_matrix ctm,\n        float alpha,\n        fz_color_params color_params\n        )\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_fill_image_mask(\n        fz_context* ctx,\n        fz_device* dev,\n        fz_image* img,\n        fz_matrix ctm,\n        fz_colorspace* cs,\n        const float* color,\n        float alpha,\n        fz_color_params color_params\n        )\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_stroke_path(\n        fz_context* ctx,\n        fz_device* dev_,\n        const fz_path* path,\n        const fz_stroke_state* stroke,\n        fz_matrix ctm,\n        fz_colorspace* colorspace,\n        const float* color,\n        float alpha,\n        fz_color_params color_params\n        )\n{\n    jm_increase_seqno(ctx, dev_);\n}\n\nstatic void jm_trace_text(\n        jm_tracedraw_device* dev,\n        const fz_text* text,\n        int type,\n        fz_matrix ctm,\n        fz_colorspace* colorspace,\n        const float* color,\n        float alpha,\n        size_t seqno,\n        const fz_stroke_state* stroke\n        )\n{\n    fz_text_span* span;\n    for (span = text->head; span; span = span->next)\n    {\n        jm_trace_text_span(dev, span, type, ctm, colorspace, color, alpha, seqno, stroke);\n    }\n}\n\n/*---------------------------------------------------------\nThere are 3 text trace types:\n0 - fill text (PDF Tr 0)\n1 - stroke text (PDF Tr 1)\n3 - ignore text (PDF Tr 3)\n---------------------------------------------------------*/\nstatic void\njm_tracedraw_fill_text(\n        fz_context* ctx,\n        fz_device* dev_,\n        const fz_text* text,\n        fz_matrix ctm,\n        fz_colorspace* colorspace,\n        const float* color,\n        float alpha,\n        fz_color_params color_params\n        )\n{\n    jm_tracedraw_device* dev = (jm_tracedraw_device*) dev_;\n    jm_trace_text(dev, text, 0, ctm, colorspace, color, alpha, dev->seqno, NULL);\n    dev->seqno += 1;\n}\n\nstatic void\njm_tracedraw_stroke_text(\n        fz_context* ctx,\n        fz_device* dev_,\n        const fz_text* text,\n        const fz_stroke_state* stroke,\n        fz_matrix ctm,\n        fz_colorspace* colorspace,\n        const float* color,\n        float alpha,\n        fz_color_params color_params\n        )\n{\n    jm_tracedraw_device* dev = (jm_tracedraw_device*) dev_;\n    jm_trace_text(dev, text, 1, ctm, colorspace, color, alpha, dev->seqno, stroke);\n    dev->seqno += 1;\n}\n\n\nstatic void\njm_tracedraw_ignore_text(\n        fz_context* ctx,\n        fz_device* dev_,\n        const fz_text* text,\n        fz_matrix ctm\n        )\n{\n    jm_tracedraw_device* dev = (jm_tracedraw_device*) dev_;\n    jm_trace_text(dev, text, 3, ctm, nullptr, nullptr, 1, dev->seqno, NULL);\n    dev->seqno += 1;\n}\n\nstatic void\njm_lineart_begin_layer(fz_context *ctx, fz_device *dev_, const char *name)\n{\n    jm_tracedraw_device* dev = (jm_tracedraw_device*) dev_;\n    mupdf::ll_fz_free(dev->layer_name);\n    dev->layer_name = mupdf::ll_fz_strdup(name);\n}\n\nstatic void\njm_lineart_end_layer(fz_context *ctx, fz_device *dev_)\n{\n    jm_tracedraw_device* dev = (jm_tracedraw_device*) dev_;\n    mupdf::ll_fz_free(dev->layer_name);\n    dev->layer_name = nullptr;\n}\n\n\nmupdf::FzDevice JM_new_texttrace_device(PyObject* out)\n{\n    mupdf::FzDevice device(sizeof(jm_tracedraw_device));\n    jm_tracedraw_device* dev = (jm_tracedraw_device*) device.m_internal;\n    \n    dev->super.close_device = nullptr;    \n    dev->super.drop_device = jm_lineart_drop_device;    \n    dev->super.fill_path = jm_fill_path;\n    dev->super.stroke_path = jm_stroke_path;\n    dev->super.clip_path = nullptr;\n    dev->super.clip_stroke_path = nullptr;\n\n    dev->super.fill_text = jm_tracedraw_fill_text;\n    dev->super.stroke_text = jm_tracedraw_stroke_text;\n    dev->super.clip_text = nullptr;\n    dev->super.clip_stroke_text = nullptr;\n    dev->super.ignore_text = jm_tracedraw_ignore_text;\n\n    dev->super.fill_shade = jm_fill_shade;\n    dev->super.fill_image = jm_fill_image;\n    dev->super.fill_image_mask = jm_fill_image_mask;\n    dev->super.clip_image_mask = nullptr;\n\n    dev->super.pop_clip = nullptr;\n\n    dev->super.begin_mask = nullptr;\n    dev->super.end_mask = nullptr;\n    dev->super.begin_group = nullptr;\n    dev->super.end_group = nullptr;\n\n    dev->super.begin_tile = nullptr;\n    dev->super.end_tile = nullptr;\n\n    dev->super.begin_layer = jm_lineart_begin_layer;\n    dev->super.end_layer = jm_lineart_end_layer;\n\n    dev->super.begin_structure = nullptr;\n    dev->super.end_structure = nullptr;\n\n    dev->super.begin_metatext = nullptr;\n    dev->super.end_metatext = nullptr;\n\n    dev->super.render_flags = nullptr;\n    dev->super.set_default_colorspaces = nullptr;\n\n    Py_XINCREF(out);\n    dev->out = out;\n    dev->seqno = 0;\n    return device;\n}\n\n\nstatic fz_quad\nJM_char_quad(fz_stext_line *line, fz_stext_char *ch)\n{\n    if (g_skip_quad_corrections) {  // no special handling\n        return ch->quad;\n    }\n    if (line->wmode) {  // never touch vertical write mode\n        return ch->quad;\n    }\n    fz_font *font = ch->font;\n    float asc = JM_font_ascender(font);\n    float dsc = JM_font_descender(font);\n    float c, s, fsize = ch->size;\n    float asc_dsc = asc - dsc + FLT_EPSILON;\n    if (asc_dsc >= 1 && g_small_glyph_heights == 0) {  // no problem\n       return ch->quad;\n    }\n    if (asc < 1e-3) {  // probably Tesseract glyphless font\n        dsc = -0.1f;\n        asc = 0.9f;\n        asc_dsc = 1.0f;\n    }\n\n    if (g_small_glyph_heights || asc_dsc < 1) {\n        dsc = dsc / asc_dsc;\n        asc = asc / asc_dsc;\n    }\n    asc_dsc = asc - dsc;\n    asc = asc * fsize / asc_dsc;\n    dsc = dsc * fsize / asc_dsc;\n\n    /* ------------------------------\n    Re-compute quad with the adjusted ascender / descender values:\n    Move ch->origin to (0,0) and de-rotate quad, then adjust the corners,\n    re-rotate and move back to ch->origin location.\n    ------------------------------ */\n    fz_matrix trm1, trm2, xlate1, xlate2;\n    fz_quad quad;\n    c = line->dir.x;  // cosine\n    s = line->dir.y;  // sine\n    trm1 = mupdf::ll_fz_make_matrix(c, -s, s, c, 0, 0);  // derotate\n    trm2 = mupdf::ll_fz_make_matrix(c, s, -s, c, 0, 0);  // rotate\n    if (c == -1) {  // left-right flip\n        trm1.d = 1;\n        trm2.d = 1;\n    }\n    xlate1 = mupdf::ll_fz_make_matrix(1, 0, 0, 1, -ch->origin.x, -ch->origin.y);\n    xlate2 = mupdf::ll_fz_make_matrix(1, 0, 0, 1, ch->origin.x, ch->origin.y);\n\n    quad = mupdf::ll_fz_transform_quad(ch->quad, xlate1);  // move origin to (0,0)\n    quad = mupdf::ll_fz_transform_quad(quad, trm1);  // de-rotate corners\n\n    // adjust vertical coordinates\n    if (c == 1 && quad.ul.y > 0) {  // up-down flip\n        quad.ul.y = asc;\n        quad.ur.y = asc;\n        quad.ll.y = dsc;\n        quad.lr.y = dsc;\n    } else {\n        quad.ul.y = -asc;\n        quad.ur.y = -asc;\n        quad.ll.y = -dsc;\n        quad.lr.y = -dsc;\n    }\n\n    // adjust horizontal coordinates that are too crazy:\n    // (1) left x must be >= 0\n    // (2) if bbox width is 0, lookup char advance in font.\n    if (quad.ll.x < 0) {\n        quad.ll.x = 0;\n        quad.ul.x = 0;\n    }\n    float cwidth = quad.lr.x - quad.ll.x;\n    if (cwidth < FLT_EPSILON) {\n        int glyph = mupdf::ll_fz_encode_character( font, ch->c);\n        if (glyph) {\n            float fwidth = mupdf::ll_fz_advance_glyph( font, glyph, line->wmode);\n            quad.lr.x = quad.ll.x + fwidth * fsize;\n            quad.ur.x = quad.lr.x;\n        }\n    }\n\n    quad = mupdf::ll_fz_transform_quad(quad, trm2);  // rotate back\n    quad = mupdf::ll_fz_transform_quad(quad, xlate2);  // translate back\n    return quad;\n}\n\n\nstatic fz_rect JM_char_bbox(fz_stext_line* line, fz_stext_char* ch)\n{\n    fz_rect r = mupdf::ll_fz_rect_from_quad(JM_char_quad( line, ch));\n    if (!line->wmode) {\n        return r;\n    }\n    if (r.y1 < r.y0 + ch->size) {\n        r.y0 = r.y1 - ch->size;\n    }\n    return r;\n}\n\nfz_rect JM_char_bbox(const mupdf::FzStextLine& line, const mupdf::FzStextChar& ch)\n{\n    return JM_char_bbox( line.m_internal, ch.m_internal);\n}\n\nstatic int JM_rects_overlap(const fz_rect a, const fz_rect b)\n{\n    if (0\n            || a.x0 >= b.x1\n            || a.y0 >= b.y1\n            || a.x1 <= b.x0\n            || a.y1 <= b.y0\n            )\n        return 0;\n    return 1;\n}\n\n//\nvoid JM_append_rune(fz_buffer *buff, int ch);\n\n//-----------------------------------------------------------------------------\n// Plain text output. An identical copy of fz_print_stext_page_as_text,\n// but lines within a block are concatenated by space instead a new-line\n// character (which else leads to 2 new-lines).\n//-----------------------------------------------------------------------------\nvoid _as_text(fz_stext_block *block, mupdf::FzBuffer& res, mupdf::FzStextPage& page)\n{\n    /*\n    Recursive function for output by blocks as identified by the\n    MuPDF SEGMENT logic.\n    The recursion happens when we encounter a structure block.\n    */\n    fz_rect rect = page.m_internal->mediabox;\n    int last_char;\n    fz_stext_line *line;\n    fz_stext_char *ch;\n    while (block)\n    {\n        switch (block->type)\n        {\n            case FZ_STEXT_BLOCK_STRUCT:\n                if (block->u.s.down)\n                {\n                    _as_text(block->u.s.down->first_block, res, page);\n                }\n                break;\n\n            case FZ_STEXT_BLOCK_TEXT:\n                last_char = 0;\n                for (line = block->u.t.first_line; line; line = line->next)\n                {\n                    for (ch = line->first_char; ch; ch = ch->next)\n                    {\n                        fz_rect chbbox = JM_char_bbox( line, ch);\n                        if (mupdf::ll_fz_is_infinite_rect(rect) || JM_rects_overlap(rect, chbbox))\n                        {\n                            last_char = ch->c;\n                            JM_append_rune(res.m_internal, last_char);\n                        }\n                    }\n                    if (last_char != 10 && last_char > 0)\n                    {\n                        mupdf::ll_fz_append_string(res.m_internal, \"\\n\");\n                        last_char = 10;\n                    }\n                }\n                if (last_char != 10 && last_char > 0)\n                {\n                    mupdf::ll_fz_append_string(res.m_internal, \"\\n\");\n                    last_char = 10;\n                }\n                break;\n        }\n        block = block->next;\n    }\n}\n\nvoid JM_print_stext_page_as_text(mupdf::FzBuffer& res, mupdf::FzStextPage& page)\n{\n    fz_stext_block *block = page.m_internal->first_block;\n    _as_text(block, res, page);\n}\n\n\n\n// path_type is one of:\n#define FILL_PATH 1\n#define STROKE_PATH 2\n#define CLIP_PATH 3\n#define CLIP_STROKE_PATH 4\n\n// Every scissor of a clip is a sub rectangle of the preceding clip scissor if\n// the clip level is larger.\nstatic fz_rect compute_scissor(jm_lineart_device *dev)\n{\n    PyObject *last_scissor = NULL;\n    fz_rect scissor;\n    if (!dev->scissors) {\n        dev->scissors = PyList_New(0);\n    }\n    Py_ssize_t num_scissors = PyList_Size(dev->scissors);\n    if (num_scissors > 0) {\n        last_scissor = PyList_GET_ITEM(dev->scissors, num_scissors-1);\n        scissor = JM_rect_from_py(last_scissor);\n        scissor = fz_intersect_rect(scissor, dev->pathrect);\n    } else {\n        scissor = dev->pathrect;\n    }\n    LIST_APPEND_DROP(dev->scissors, JM_py_from_rect(scissor));\n    return scissor;\n}\n\n\n/*\n--------------------------------------------------------------------------\nCheck whether the last 4 lines represent a quad.\nBecause of how we count, the lines are a polyline already, i.e. last point\nof a line equals 1st point of next line.\nSo we check for a polygon (last line's end point equals start point).\nIf not true we return 0.\n--------------------------------------------------------------------------\n*/\nstatic int\njm_checkquad(jm_lineart_device* dev)\n{\n    PyObject *items = PyDict_GetItem(dev->pathdict, dictkey_items);\n    Py_ssize_t i, len = PyList_Size(items);\n    float f[8]; // coordinates of the 4 corners\n    mupdf::FzPoint temp, lp; // line = (temp, lp)\n    PyObject *rect;\n    PyObject *line;\n    // fill the 8 floats in f, start from items[-4:]\n    for (i = 0; i < 4; i++) {  // store line start points\n        line = PyList_GET_ITEM(items, len - 4 + i);\n        temp = JM_point_from_py(PyTuple_GET_ITEM(line, 1));\n        f[i * 2] = temp.x;\n        f[i * 2 + 1] = temp.y;\n        lp = JM_point_from_py(PyTuple_GET_ITEM(line, 2));\n    }\n    if (lp.x != f[0] || lp.y != f[1]) {\n        // not a polygon!\n        //dev_linecount -= 1;\n        return 0;\n    }\n\n    // we have detected a quad\n    dev->linecount = 0;  // reset this\n    // a quad item is (\"qu\", (ul, ur, ll, lr)), where the tuple items\n    // are pairs of floats representing a quad corner each.\n    rect = PyTuple_New(2);\n    PyTuple_SET_ITEM(rect, 0, PyUnicode_FromString(\"qu\"));\n    /* ----------------------------------------------------\n    * relationship of float array to quad points:\n    * (0, 1) = ul, (2, 3) = ll, (6, 7) = ur, (4, 5) = lr\n    ---------------------------------------------------- */\n    fz_quad q = fz_make_quad(f[0], f[1], f[6], f[7], f[2], f[3], f[4], f[5]);\n    PyTuple_SET_ITEM(rect, 1, JM_py_from_quad(q));\n    PyList_SetItem(items, len - 4, rect); // replace item -4 by rect\n    PyList_SetSlice(items, len - 3, len, NULL); // delete remaining 3 items\n    return 1;\n}\n\n\n/*\n--------------------------------------------------------------------------\nCheck whether the last 3 path items represent a rectangle.\nLine 1 and 3 must be horizontal, line 2 must be vertical.\nReturns 1 if we have modified the path, otherwise 0.\n--------------------------------------------------------------------------\n*/\nstatic int\njm_checkrect(jm_lineart_device* dev)\n{\n    dev->linecount = 0; // reset line count\n    long orientation = 0; // area orientation of rectangle\n    mupdf::FzPoint ll, lr, ur, ul;\n    mupdf::FzRect r;\n    PyObject *rect;\n    PyObject *line0, *line2;\n    PyObject *items = PyDict_GetItem(dev->pathdict, dictkey_items);\n    Py_ssize_t len = PyList_Size(items);\n\n    line0 = PyList_GET_ITEM(items, len - 3);\n    ll = JM_point_from_py(PyTuple_GET_ITEM(line0, 1));\n    lr = JM_point_from_py(PyTuple_GET_ITEM(line0, 2));\n    // no need to extract \"line1\"!\n    line2 = PyList_GET_ITEM(items, len - 1);\n    ur = JM_point_from_py(PyTuple_GET_ITEM(line2, 1));\n    ul = JM_point_from_py(PyTuple_GET_ITEM(line2, 2));\n\n    /*\n    ---------------------------------------------------------------------\n    Assumption:\n    When decomposing rects, MuPDF always starts with a horizontal line,\n    followed by a vertical line, followed by a horizontal line.\n    First line: (ll, lr), third line: (ul, ur).\n    If 1st line is below 3rd line, we record anti-clockwise (+1), else\n    clockwise (-1) orientation.\n    ---------------------------------------------------------------------\n    */\n    if (ll.y != lr.y ||\n        ll.x != ul.x ||\n        ur.y != ul.y ||\n        ur.x != lr.x) {\n        goto drop_out;  // not a rectangle\n    }\n\n    // we have a rect, replace last 3 \"l\" items by one \"re\" item.\n    if (ul.y < lr.y) {\n        r = fz_make_rect(ul.x, ul.y, lr.x, lr.y);\n        orientation = 1;\n    } else {\n        r = fz_make_rect(ll.x, ll.y, ur.x, ur.y);\n        orientation = -1;\n    }\n    rect = PyTuple_New(3);\n    PyTuple_SET_ITEM(rect, 0, PyUnicode_FromString(\"re\"));\n    PyTuple_SET_ITEM(rect, 1, JM_py_from_rect(r));\n    PyTuple_SET_ITEM(rect, 2, PyLong_FromLong(orientation));\n    PyList_SetItem(items, len - 3, rect); // replace item -3 by rect\n    PyList_SetSlice(items, len - 2, len, NULL); // delete remaining 2 items\n    return 1;\n    drop_out:;\n    return 0;\n}\n\nstatic PyObject *\njm_lineart_color(fz_colorspace *colorspace, const float *color)\n{\n    float rgb[3];\n    if (colorspace) {\n        mupdf::ll_fz_convert_color(colorspace, color, mupdf::ll_fz_device_rgb(),\n                         rgb, NULL, fz_default_color_params);\n        return Py_BuildValue(\"fff\", rgb[0], rgb[1], rgb[2]);\n    }\n    return PyTuple_New(0);\n}\n\nstatic void\ntrace_moveto(fz_context *ctx, void *dev_, float x, float y)\n{\n    jm_lineart_device* dev = (jm_lineart_device*) dev_;\n    dev->lastpoint = mupdf::ll_fz_transform_point(fz_make_point(x, y), dev->ctm);\n    if (mupdf::ll_fz_is_infinite_rect(dev->pathrect))\n    {\n        dev->pathrect = mupdf::ll_fz_make_rect(\n                dev->lastpoint.x,\n                dev->lastpoint.y,\n                dev->lastpoint.x,\n                dev->lastpoint.y\n                );\n    }\n    dev->firstpoint = dev->lastpoint;\n    dev->havemove = 1;\n    dev->linecount = 0;  // reset # of consec. lines\n}\n\nstatic void\ntrace_lineto(fz_context *ctx, void *dev_, float x, float y)\n{\n    jm_lineart_device* dev = (jm_lineart_device*) dev_;\n    fz_point p1 = fz_transform_point(fz_make_point(x, y), dev->ctm);\n    dev->pathrect = fz_include_point_in_rect(dev->pathrect, p1);\n    PyObject *list = PyTuple_New(3);\n    PyTuple_SET_ITEM(list, 0, PyUnicode_FromString(\"l\"));\n    PyTuple_SET_ITEM(list, 1, JM_py_from_point(dev->lastpoint));\n    PyTuple_SET_ITEM(list, 2, JM_py_from_point(p1));\n    dev->lastpoint = p1;\n    PyObject *items = PyDict_GetItem(dev->pathdict, dictkey_items);\n    LIST_APPEND_DROP(items, list);\n    dev->linecount += 1;  // counts consecutive lines\n    if (dev->linecount == 4 && dev->path_type != FILL_PATH) {  // shrink to \"re\" or \"qu\" item\n        jm_checkquad(dev);\n    }\n}\n\nstatic void\ntrace_curveto(fz_context *ctx, void *dev_, float x1, float y1, float x2, float y2, float x3, float y3)\n{\n    jm_lineart_device* dev = (jm_lineart_device*) dev_;\n    dev->linecount = 0;  // reset # of consec. lines\n    fz_point p1 = fz_make_point(x1, y1);\n    fz_point p2 = fz_make_point(x2, y2);\n    fz_point p3 = fz_make_point(x3, y3);\n    p1 = fz_transform_point(p1, dev->ctm);\n    p2 = fz_transform_point(p2, dev->ctm);\n    p3 = fz_transform_point(p3, dev->ctm);\n    dev->pathrect = fz_include_point_in_rect(dev->pathrect, p1);\n    dev->pathrect = fz_include_point_in_rect(dev->pathrect, p2);\n    dev->pathrect = fz_include_point_in_rect(dev->pathrect, p3);\n\n    PyObject *list = PyTuple_New(5);\n    PyTuple_SET_ITEM(list, 0, PyUnicode_FromString(\"c\"));\n    PyTuple_SET_ITEM(list, 1, JM_py_from_point(dev->lastpoint));\n    PyTuple_SET_ITEM(list, 2, JM_py_from_point(p1));\n    PyTuple_SET_ITEM(list, 3, JM_py_from_point(p2));\n    PyTuple_SET_ITEM(list, 4, JM_py_from_point(p3));\n    dev->lastpoint = p3;\n    PyObject *items = PyDict_GetItem(dev->pathdict, dictkey_items);\n    LIST_APPEND_DROP(items, list);\n}\n\nstatic void\ntrace_close(fz_context *ctx, void *dev_)\n{\n    jm_lineart_device* dev = (jm_lineart_device*) dev_;\n    if (dev->linecount == 3) {\n        if (jm_checkrect(dev)) {\n            return;\n        }\n    }\n    dev->linecount = 0;  // reset # of consec. lines\n\tif (dev->havemove) {\n\t\tif (dev->firstpoint.x != dev->lastpoint.x || dev->firstpoint.y != dev->lastpoint.y) {\n\t\t\tPyObject *list = PyTuple_New(3);\n\t\t\tPyTuple_SET_ITEM(list, 0, PyUnicode_FromString(\"l\"));\n\t\t\tPyTuple_SET_ITEM(list, 1, JM_py_from_point(dev->lastpoint));\n\t\t\tPyTuple_SET_ITEM(list, 2, JM_py_from_point(dev->firstpoint));\n\t\t\tdev->lastpoint = dev->firstpoint;\n\t\t\tPyObject *items = PyDict_GetItem(dev->pathdict, dictkey_items);\n\t\t\tLIST_APPEND_DROP(items, list);\n\t\t}\n\t\tdev->havemove = 0;\n\t\tDICT_SETITEMSTR_DROP(dev->pathdict, \"closePath\", JM_BOOL(0));\n\t} else {\n\t\tDICT_SETITEMSTR_DROP(dev->pathdict, \"closePath\", JM_BOOL(1));\n\t}\n}\n\nstatic const fz_path_walker trace_path_walker =\n    {\n        trace_moveto,\n        trace_lineto,\n        trace_curveto,\n        trace_close\n    };\n\n/*\n---------------------------------------------------------------------\nCreate the \"items\" list of the path dictionary\n* either create or empty the path dictionary\n* reset the end point of the path\n* reset count of consecutive lines\n* invoke fz_walk_path(), which create the single items\n* if no items detected, empty path dict again\n---------------------------------------------------------------------\n*/\nstatic void\njm_lineart_path(jm_lineart_device *dev, const fz_path *path)\n{\n    dev->pathrect = fz_infinite_rect;\n    dev->linecount = 0;\n    dev->lastpoint = fz_make_point(0, 0);\n    dev->firstpoint = fz_make_point(0, 0);\n    if (dev->pathdict) {\n        Py_CLEAR(dev->pathdict);\n    }\n    dev->pathdict = PyDict_New();\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_items, PyList_New(0));\n    mupdf::ll_fz_walk_path(path, &trace_path_walker, dev);\n    // Check if any items were added ...\n    if (!PyDict_GetItem(dev->pathdict, dictkey_items) || !PyList_Size(PyDict_GetItem(dev->pathdict, dictkey_items)))\n    {\n        Py_CLEAR(dev->pathdict);\n    }\n}\n\n//---------------------------------------------------------------------------\n// Append current path to list or merge into last path of the list.\n// (1) Append if first path, different item lists or not a 'stroke' version\n//     of previous path\n// (2) If new path has the same items, merge its content into previous path\n//     and change path[\"type\"] to \"fs\".\n// (3) If \"out\" is callable, skip the previous and pass dictionary to it.\n//---------------------------------------------------------------------------\nstatic void\n// todo: remove `method` arg - it is dev->method.\njm_append_merge(jm_lineart_device *dev)\n{\n    Py_ssize_t len;\n    int rc;\n    PyObject *prev;\n    PyObject *previtems;\n    PyObject *thisitems;\n    const char *thistype;\n    const char *prevtype;\n    if (PyCallable_Check(dev->out) || dev->method != Py_None) {  // function or method\n        goto callback;\n    }\n    len = PyList_Size(dev->out);  // len of output list so far\n    if (len == 0) {  // always append first path \n        goto append;\n    }\n    thistype = PyUnicode_AsUTF8(PyDict_GetItem(dev->pathdict, dictkey_type));\n    if (strcmp(thistype, \"s\") != 0) {  // if not stroke, then append\n        goto append;\n    }\n    prev = PyList_GET_ITEM(dev->out, len - 1);  // get prev path\n    prevtype = PyUnicode_AsUTF8(PyDict_GetItem(prev, dictkey_type));\n    if (strcmp(prevtype, \"f\") != 0) {  // if previous not fill, append\n        goto append;\n    }\n    // last check: there must be the same list of items for \"f\" and \"s\".\n    previtems = PyDict_GetItem(prev, dictkey_items);\n    thisitems = PyDict_GetItem(dev->pathdict, dictkey_items);\n    if (PyObject_RichCompareBool(previtems, thisitems, Py_NE)) {\n        goto append;\n    }\n    rc = PyDict_Merge(prev, dev->pathdict, 0);  // merge, do not override\n    if (rc == 0) {\n        DICT_SETITEM_DROP(prev, dictkey_type, PyUnicode_FromString(\"fs\"));\n        goto postappend;\n    } else {\n        messagef(\"could not merge stroke and fill path\");\n        goto append;\n    }\n    append:;\n    //printf(\"Appending to dev->out. len(dev->out)=%zi\\n\", PyList_Size(dev->out));\n    PyList_Append(dev->out, dev->pathdict);\n    postappend:;\n    Py_CLEAR(dev->pathdict);\n    return;\n\n    callback:;  // callback function or method\n    PyObject *resp = NULL;\n    if (dev->method == Py_None) {\n        resp = PyObject_CallFunctionObjArgs(dev->out, dev->pathdict, NULL);\n    } else {\n        resp = PyObject_CallMethodObjArgs(dev->out, dev->method, dev->pathdict, NULL);\n    }\n    if (resp) {\n        Py_DECREF(resp);\n    } else {\n        messagef(\"calling cdrawings callback function/method failed!\");\n        PyErr_Clear();\n    }\n    Py_CLEAR(dev->pathdict);\n    return;\n}\n\nstatic void\njm_lineart_fill_path(fz_context *ctx, fz_device *dev_, const fz_path *path,\n                int even_odd, fz_matrix ctm, fz_colorspace *colorspace,\n                const float *color, float alpha, fz_color_params color_params)\n{\n    jm_lineart_device *dev = (jm_lineart_device *) dev_;\n    //printf(\"extra.jm_lineart_fill_path(): dev->seqno=%zi\\n\", dev->seqno);\n    dev->ctm = ctm; //fz_concat(ctm, trace_device_ptm);\n    dev->path_type = FILL_PATH;\n    jm_lineart_path(dev, path);\n    if (!dev->pathdict) {\n        return;\n    }\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_type, PyUnicode_FromString(\"f\"));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"even_odd\", JM_BOOL(even_odd));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"fill_opacity\", Py_BuildValue(\"f\", alpha));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"fill\", jm_lineart_color(colorspace, color));\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_rect, JM_py_from_rect(dev->pathrect));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"seqno\", PyLong_FromSize_t(dev->seqno));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"layer\", JM_UnicodeFromStr(dev->layer_name));\n    if (dev->clips)    {\n        DICT_SETITEMSTR_DROP(dev->pathdict, \"level\", PyLong_FromLong(dev->depth));\n    }\n    jm_append_merge(dev);\n    dev->seqno += 1;\n}\n\nstatic void\njm_lineart_stroke_path(fz_context *ctx, fz_device *dev_, const fz_path *path,\n                const fz_stroke_state *stroke, fz_matrix ctm,\n                fz_colorspace *colorspace, const float *color, float alpha,\n                fz_color_params color_params)\n{\n    jm_lineart_device *dev = (jm_lineart_device *)dev_;\n    //printf(\"extra.jm_lineart_stroke_path(): dev->seqno=%zi\\n\", dev->seqno);\n    int i;\n    dev->pathfactor = sqrtf(fabsf(ctm.a * ctm.d - ctm.b * ctm.c));\n    dev->ctm = ctm; // fz_concat(ctm, trace_device_ptm);\n    dev->path_type = STROKE_PATH;\n\n    jm_lineart_path(dev, path);\n    if (!dev->pathdict) {\n        return;\n    }\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_type, PyUnicode_FromString(\"s\"));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"stroke_opacity\", Py_BuildValue(\"f\", alpha));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"color\", jm_lineart_color(colorspace, color));\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_width, Py_BuildValue(\"f\", dev->pathfactor * stroke->linewidth));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"lineCap\", Py_BuildValue(\"iii\", stroke->start_cap, stroke->dash_cap, stroke->end_cap));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"lineJoin\", Py_BuildValue(\"f\", (float)stroke->linejoin));\n    if (!PyDict_GetItemString(dev->pathdict, \"closePath\")) {\n        DICT_SETITEMSTR_DROP(dev->pathdict, \"closePath\", JM_BOOL(0));\n    }\n\n    // output the \"dashes\" string\n    if (stroke->dash_len) {\n        mupdf::FzBuffer buff(256);\n        mupdf::fz_append_string(buff, \"[ \");  // left bracket\n        for (i = 0; i < stroke->dash_len; i++) {\n            fz_append_printf(ctx, buff.m_internal, \"%g \", dev->pathfactor * stroke->dash_list[i]);\n        }\n        fz_append_printf(ctx, buff.m_internal, \"] %g\", dev->pathfactor * stroke->dash_phase);\n        DICT_SETITEMSTR_DROP(dev->pathdict, \"dashes\", JM_EscapeStrFromBuffer(buff));\n    } else {\n        DICT_SETITEMSTR_DROP(dev->pathdict, \"dashes\", PyUnicode_FromString(\"[] 0\"));\n    }\n\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_rect, JM_py_from_rect(dev->pathrect));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"layer\", JM_UnicodeFromStr(dev->layer_name));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"seqno\", PyLong_FromSize_t(dev->seqno));\n    if (dev->clips) {\n        DICT_SETITEMSTR_DROP(dev->pathdict, \"level\", PyLong_FromLong(dev->depth));\n    }\n    // output the dict - potentially merging it with a previous fill_path twin\n    jm_append_merge(dev);\n    dev->seqno += 1;\n}\n\nstatic void\njm_lineart_clip_path(fz_context *ctx, fz_device *dev_, const fz_path *path, int even_odd, fz_matrix ctm, fz_rect scissor)\n{\n    jm_lineart_device *dev = (jm_lineart_device *)dev_;\n    if (!dev->clips) return;\n    dev->ctm = ctm; //fz_concat(ctm, trace_device_ptm);\n    dev->path_type = CLIP_PATH;\n    jm_lineart_path(dev, path);\n\tif (!dev->pathdict) {\n\t\treturn;\n\t}\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_type, PyUnicode_FromString(\"clip\"));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"even_odd\", JM_BOOL(even_odd));\n    if (!PyDict_GetItemString(dev->pathdict, \"closePath\")) {\n        DICT_SETITEMSTR_DROP(dev->pathdict, \"closePath\", JM_BOOL(0));\n    }\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"scissor\", JM_py_from_rect(compute_scissor(dev)));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"level\", PyLong_FromLong(dev->depth));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"layer\", JM_UnicodeFromStr(dev->layer_name));\n    jm_append_merge(dev);\n    dev->depth++;\n}\n\nstatic void\njm_lineart_clip_stroke_path(fz_context *ctx, fz_device *dev_, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor)\n{\n    jm_lineart_device *dev = (jm_lineart_device *)dev_;\n    if (!dev->clips) return;\n    dev->ctm = ctm; //fz_concat(ctm, trace_device_ptm);\n    dev->path_type = CLIP_STROKE_PATH;\n    jm_lineart_path(dev, path);\n\tif (!dev->pathdict) {\n\t\treturn;\n\t}\n    DICT_SETITEM_DROP(dev->pathdict, dictkey_type, PyUnicode_FromString(\"clip\"));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"even_odd\", Py_BuildValue(\"s\", NULL));\n    if (!PyDict_GetItemString(dev->pathdict, \"closePath\")) {\n        DICT_SETITEMSTR_DROP(dev->pathdict, \"closePath\", JM_BOOL(0));\n    }\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"scissor\", JM_py_from_rect(compute_scissor(dev)));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"level\", PyLong_FromLong(dev->depth));\n    DICT_SETITEMSTR_DROP(dev->pathdict, \"layer\", JM_UnicodeFromStr(dev->layer_name));\n    jm_append_merge(dev);\n    dev->depth++;\n}\n\n\nstatic void\njm_lineart_clip_stroke_text(fz_context *ctx, fz_device *dev_, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor)\n{\n   jm_lineart_device *dev = (jm_lineart_device *)dev_;\n   if (!dev->clips) return;\n   compute_scissor(dev);\n   dev->depth++;\n}\n\nstatic void\njm_lineart_clip_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm, fz_rect scissor)\n{\n   jm_lineart_device *dev = (jm_lineart_device *)dev_;\n   if (!dev->clips) return;\n   compute_scissor(dev);\n   dev->depth++;\n}\n\nstatic void\njm_lineart_clip_image_mask(fz_context *ctx, fz_device *dev_, fz_image *image, fz_matrix ctm, fz_rect scissor)\n{\n   jm_lineart_device *dev = (jm_lineart_device *)dev_;\n   if (!dev->clips) return;\n   compute_scissor(dev);\n   dev->depth++;\n}\n \nstatic void\njm_lineart_pop_clip(fz_context *ctx, fz_device *dev_)\n{\n    jm_lineart_device *dev = (jm_lineart_device *)dev_;\n    if (!dev->clips) return;\n    if (!dev->scissors) return;\n    Py_ssize_t len = PyList_Size(dev->scissors);\n    if (len < 1) return;\n    PyList_SetSlice(dev->scissors, len - 1, len, NULL);\n    dev->depth--;\n}\n\n\nstatic void\njm_lineart_begin_group(fz_context *ctx, fz_device *dev_, fz_rect bbox, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)\n{\n    jm_lineart_device *dev = (jm_lineart_device *)dev_;\n    if (!dev->clips) return;\n    dev->pathdict = Py_BuildValue(\"{s:s,s:N,s:N,s:N,s:s,s:f,s:i,s:N}\",\n                        \"type\", \"group\",\n                        \"rect\", JM_py_from_rect(bbox),\n                        \"isolated\", JM_BOOL(isolated),\n                        \"knockout\", JM_BOOL(knockout),\n                        \"blendmode\", fz_blendmode_name(blendmode),\n                        \"opacity\", alpha,\n                        \"level\", dev->depth,\n                        \"layer\", JM_UnicodeFromStr(dev->layer_name)\n                    );\n    jm_append_merge(dev);\n    dev->depth++;\n}\n\nstatic void\njm_lineart_end_group(fz_context *ctx, fz_device *dev_)\n{\n    jm_lineart_device *dev = (jm_lineart_device *)dev_;\n    if (!dev->clips) return;\n    dev->depth--;\n}\n\nstatic void jm_lineart_fill_text(fz_context *ctx, fz_device *dev, const fz_text *, fz_matrix, fz_colorspace *, const float *color, float alpha, fz_color_params)\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_lineart_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *, const fz_stroke_state *, fz_matrix, fz_colorspace *, const float *color, float alpha, fz_color_params)\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_lineart_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shd, fz_matrix ctm, float alpha, fz_color_params color_params)\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_lineart_fill_image(fz_context *ctx, fz_device *dev, fz_image *img, fz_matrix ctm, float alpha, fz_color_params color_params)\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_lineart_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *img, fz_matrix ctm, fz_colorspace *, const float *color, float alpha, fz_color_params color_params)\n{\n    jm_increase_seqno(ctx, dev);\n}\n\nstatic void jm_lineart_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *, fz_matrix)\n{\n    jm_increase_seqno(ctx, dev);\n}\n\n\n//-------------------------------------------------------------------\n// LINEART device for Python method Page.get_cdrawings()\n//-------------------------------------------------------------------\nmupdf::FzDevice JM_new_lineart_device(PyObject *out, int clips, PyObject *method)\n{\n    //printf(\"extra.JM_new_lineart_device()\\n\");\n    jm_lineart_device* dev = (jm_lineart_device*) mupdf::ll_fz_new_device_of_size(sizeof(jm_lineart_device));\n\n    dev->super.close_device = NULL;\n    dev->super.drop_device = jm_lineart_drop_device;\n    dev->super.fill_path = jm_lineart_fill_path;\n    dev->super.stroke_path = jm_lineart_stroke_path;\n    dev->super.clip_path = jm_lineart_clip_path;\n    dev->super.clip_stroke_path = jm_lineart_clip_stroke_path;\n\n    dev->super.fill_text = jm_lineart_fill_text;\n    dev->super.stroke_text = jm_lineart_stroke_text;\n    dev->super.clip_text = jm_lineart_clip_text;\n    dev->super.clip_stroke_text = jm_lineart_clip_stroke_text;\n    dev->super.ignore_text = jm_lineart_ignore_text;\n\n    dev->super.fill_shade = jm_lineart_fill_shade;\n    dev->super.fill_image = jm_lineart_fill_image;\n    dev->super.fill_image_mask = jm_lineart_fill_image_mask;\n    dev->super.clip_image_mask = jm_lineart_clip_image_mask;\n\n    dev->super.pop_clip = jm_lineart_pop_clip;\n\n    dev->super.begin_mask = NULL;\n    dev->super.end_mask = NULL;\n    dev->super.begin_group = jm_lineart_begin_group;\n    dev->super.end_group = jm_lineart_end_group;\n\n    dev->super.begin_tile = NULL;\n    dev->super.end_tile = NULL;\n\n    dev->super.begin_layer = jm_lineart_begin_layer;\n    dev->super.end_layer = jm_lineart_end_layer;\n\n    dev->super.begin_structure = NULL;\n    dev->super.end_structure = NULL;\n\n    dev->super.begin_metatext = NULL;\n    dev->super.end_metatext = NULL;\n\n    dev->super.render_flags = NULL;\n    dev->super.set_default_colorspaces = NULL;\n\n    if (PyList_Check(out)) {\n        Py_INCREF(out);\n    }\n    Py_INCREF(method);\n    dev->out = out;\n    dev->seqno = 0;\n    dev->depth = 0;\n    dev->clips = clips;\n    dev->method = method;\n    dev->pathdict = nullptr;\n\n    return mupdf::FzDevice(&dev->super);\n}\n\nPyObject* get_cdrawings(mupdf::FzPage& page, PyObject *extended=NULL, PyObject *callback=NULL, PyObject *method=NULL)\n{\n    //fz_page *page = (fz_page *) $self;\n    //fz_device *dev = NULL;\n    PyObject *rc = NULL;\n    int clips = PyObject_IsTrue(extended);\n\n    mupdf::FzDevice dev;\n    if (PyCallable_Check(callback) || method != Py_None) {\n        dev = JM_new_lineart_device(callback, clips, method);\n    } else {\n        rc = PyList_New(0);\n        dev = JM_new_lineart_device(rc, clips, method);\n    }\n    mupdf::FzRect prect = mupdf::fz_bound_page(page);\n    ((jm_lineart_device*) dev.m_internal)->ptm = mupdf::ll_fz_make_matrix(1, 0, 0, -1, 0, prect.y1);\n    \n    mupdf::FzCookie cookie;\n    mupdf::FzMatrix identity;\n    mupdf::fz_run_page( page, dev, *identity.internal(), cookie);\n    mupdf::fz_close_device( dev);\n    if (PyCallable_Check(callback) || method != Py_None)\n    {\n        Py_RETURN_NONE;\n    }\n    return rc;\n}\n\n\nstatic int detect_super_script(fz_stext_line *line, fz_stext_char *ch)\n{\n    if (line->wmode == 0 && line->dir.x == 1 && line->dir.y == 0)\n    {\n        return ch->origin.y < line->first_char->origin.y - ch->size * 0.1f;\n    }\n    return 0;\n}\n\nstatic int JM_char_font_flags(fz_font *font, fz_stext_line *line, fz_stext_char *ch)\n{\n    int flags = detect_super_script(line, ch);\n    flags += mupdf::ll_fz_font_is_italic(font) * TEXT_FONT_ITALIC;\n    flags += mupdf::ll_fz_font_is_serif(font) * TEXT_FONT_SERIFED;\n    flags += mupdf::ll_fz_font_is_monospaced(font) * TEXT_FONT_MONOSPACED;\n    flags += mupdf::ll_fz_font_is_bold(font) * TEXT_FONT_BOLD;\n    return flags;\n}\n\n//---------------------------------------------------------------------------\n// APPEND non-ascii runes in unicode escape format to fz_buffer\n//---------------------------------------------------------------------------\nvoid JM_append_rune(fz_buffer *buff, int ch)\n{\n    char text[32];\n    if (ch == 92)  // prevent accidental \"\\u\", \"\\U\" sequences\n    {\n        mupdf::ll_fz_append_string(buff, \"\\\\u005c\");\n    }\n    else if ((ch >= 32 && ch <= 127) || ch == 10)\n    {\n        mupdf::ll_fz_append_byte(buff, ch);\n    }\n    else if (ch >= 0xd800 && ch <= 0xdfff)  // orphaned surrogate Unicodes\n    {\n        mupdf::ll_fz_append_string(buff, \"\\\\ufffd\");\n    }\n    else if (ch <= 0xffff)\n    {\n        // 4 hex digits\n        snprintf(text, sizeof(text), \"\\\\u%04x\", ch);\n        mupdf::ll_fz_append_string(buff, text);\n    }\n    else\n    {\n        // 8 hex digits\n        snprintf(text, sizeof(text), \"\\\\U%08x\", ch);\n        mupdf::ll_fz_append_string(buff, text);\n    }\n}\n\n\nmupdf::FzRect JM_make_spanlist(\n        PyObject *line_dict,\n        mupdf::FzStextLine& line,\n        int raw,\n        mupdf::FzBuffer& buff,\n        mupdf::FzRect& tp_rect\n        )\n{\n    PyObject *span = NULL, *char_list = NULL, *char_dict;\n    PyObject *span_list = PyList_New(0);\n    mupdf::fz_clear_buffer(buff);\n    fz_rect span_rect = fz_empty_rect;\n    fz_rect line_rect = fz_empty_rect;\n    fz_point span_origin = {0, 0};\n    struct char_style\n    {\n        float size = -1;\n        unsigned flags = 0;\n        \n        /* From mupdf:include/mupdf/fitz/structured-text.h:fz_stext_char::flags, which\n        uses anonymous enum values:\n        FZ_STEXT_STRIKEOUT = 1,\n        FZ_STEXT_UNDERLINE = 2,\n        FZ_STEXT_SYNTHETIC = 4,\n        FZ_STEXT_FILLED = 16,\n        FZ_STEXT_STROKED = 32,\n        FZ_STEXT_CLIPPED = 64\n        */\n        unsigned char_flags = 0;\n        \n        const char *font = \"\";\n        unsigned argb = 0;\n        float asc = 0;\n        float desc = 0;\n        uint16_t bidi = 0;\n    };\n    char_style old_style;\n    char_style style;\n\n    for (mupdf::FzStextChar ch: line)\n    {\n        fz_rect r = JM_char_bbox(line, ch);\n        if (!JM_rects_overlap(*tp_rect.internal(), r) && !fz_is_infinite_rect(tp_rect))\n        {\n            continue;\n        }\n        /* Info from:\n        detect_super_script()\n        fz_font_is_italic()\n        fz_font_is_serif()\n        fz_font_is_monospaced()\n        fz_font_is_bold()\n        */\n        int flags = JM_char_font_flags( ch.m_internal->font, line.m_internal, ch.m_internal);\n        fz_point origin = ch.m_internal->origin;\n        style.size = ch.m_internal->size;\n        style.flags = flags;\n        /* FZ_STEXT_SYNTHETIC is per-char, not per-span. */\n        style.char_flags = ch.m_internal->flags & ~FZ_STEXT_SYNTHETIC;\n        style.font = JM_font_name(ch.m_internal->font);\n        style.argb = ch.m_internal->argb;\n        style.asc = JM_font_ascender(ch.m_internal->font);\n        style.desc = JM_font_descender(ch.m_internal->font);\n\n        if (0\n                || style.size != old_style.size\n                || style.flags != old_style.flags\n                || style.char_flags != old_style.char_flags\n                || style.argb != old_style.argb\n                || strcmp(style.font, old_style.font) != 0\n                || style.bidi != old_style.bidi\n                )\n        {\n            if (old_style.size >= 0)\n            {\n                // not first one, output previous\n                if (raw)\n                {\n                    // put character list in the span\n                    DICT_SETITEM_DROP(span, dictkey_chars, char_list);\n                    char_list = NULL;\n                }\n                else\n                {\n                    // put text string in the span\n                    DICT_SETITEM_DROP(span, dictkey_text, JM_EscapeStrFromBuffer(buff));\n                    mupdf::fz_clear_buffer(buff);\n                }\n\n                DICT_SETITEM_DROP(span, dictkey_origin, JM_py_from_point(span_origin));\n                DICT_SETITEM_DROP(span, dictkey_bbox, JM_py_from_rect(span_rect));\n                line_rect = mupdf::ll_fz_union_rect(line_rect, span_rect);\n                LIST_APPEND_DROP(span_list, span);\n                span = NULL;\n            }\n\n            span = PyDict_New();\n            float asc = style.asc, desc = style.desc;\n            if (style.asc < 1e-3)\n            {\n                asc = 0.9f;\n                desc = -0.1f;\n            }\n\n            DICT_SETITEM_DROP(span, dictkey_size, Py_BuildValue(\"f\", style.size));\n            DICT_SETITEM_DROP(span, dictkey_flags, Py_BuildValue(\"I\", style.flags));\n            DICT_SETITEM_DROP(span, dictkey_bidi, Py_BuildValue(\"I\", style.bidi));\n            DICT_SETITEM_DROP(span, dictkey_char_flags, Py_BuildValue(\"I\", style.char_flags));\n            DICT_SETITEM_DROP(span, dictkey_font, JM_EscapeStrFromStr(style.font));\n            DICT_SETITEM_DROP(span, dictkey_color, Py_BuildValue(\"I\", style.argb & 0xffffff));\n            DICT_SETITEMSTR_DROP(span, \"alpha\", Py_BuildValue(\"I\", style.argb >> 24));\n            DICT_SETITEMSTR_DROP(span, \"ascender\", Py_BuildValue(\"f\", asc));\n            DICT_SETITEMSTR_DROP(span, \"descender\", Py_BuildValue(\"f\", desc));\n\n            old_style = style;\n            span_rect = r;\n            span_origin = origin;\n\n        }\n        span_rect = mupdf::ll_fz_union_rect(span_rect, r);\n\n        if (raw)\n        {\n            // make and append a char dict\n            char_dict = PyDict_New();\n            DICT_SETITEM_DROP(char_dict, dictkey_origin, JM_py_from_point(ch.m_internal->origin));\n\n            DICT_SETITEM_DROP(char_dict, dictkey_bbox, JM_py_from_rect(r));\n\n            DICT_SETITEM_DROP(char_dict, dictkey_c, Py_BuildValue(\"C\", ch.m_internal->c));\n            DICT_SETITEMSTR_DROP(char_dict, \"synthetic\", Py_BuildValue(\"O\", (ch.m_internal->flags & FZ_STEXT_SYNTHETIC) ? Py_True : Py_False));\n            if (!char_list)\n            {\n                char_list = PyList_New(0);\n            }\n            LIST_APPEND_DROP(char_list, char_dict);\n        }\n        else\n        {\n            // add character byte to buffer\n            JM_append_rune(buff.m_internal, ch.m_internal->c);\n        }\n    }\n    // all characters processed, now flush remaining span\n    if (span)\n    {\n        if (raw)\n        {\n            DICT_SETITEM_DROP(span, dictkey_chars, char_list);\n            char_list = NULL;\n        }\n        else\n        {\n            DICT_SETITEM_DROP(span, dictkey_text, JM_EscapeStrFromBuffer(buff));\n            mupdf::fz_clear_buffer(buff);\n        }\n        DICT_SETITEM_DROP(span, dictkey_origin, JM_py_from_point(span_origin));\n        DICT_SETITEM_DROP(span, dictkey_bbox, JM_py_from_rect(span_rect));\n\n        if (!fz_is_empty_rect(span_rect))\n        {\n            LIST_APPEND_DROP(span_list, span);\n            line_rect = fz_union_rect(line_rect, span_rect);\n        }\n        else\n        {\n            Py_DECREF(span);\n        }\n        span = NULL;\n    }\n    if (!mupdf::fz_is_empty_rect(line_rect))\n    {\n        DICT_SETITEM_DROP(line_dict, dictkey_spans, span_list);\n    }\n    else\n    {\n        DICT_SETITEM_DROP(line_dict, dictkey_spans, span_list);\n    }\n    return line_rect;\n}\n\n//-----------------------------------------------------------------------------\n// Functions for wordlist output\n//-----------------------------------------------------------------------------\nint JM_append_word(\n        PyObject* lines,\n        fz_buffer* buff,\n        fz_rect* wbbox,\n        int block_n,\n        int line_n,\n        int word_n\n        )\n{\n    PyObject* s = JM_EscapeStrFromBuffer(buff);\n    PyObject* litem = Py_BuildValue(\n            \"ffffOiii\",\n            wbbox->x0,\n            wbbox->y0,\n            wbbox->x1,\n            wbbox->y1,\n            s,\n            block_n,\n            line_n,\n            word_n\n            );\n    LIST_APPEND_DROP(lines, litem);\n    Py_DECREF(s);\n    *wbbox = fz_empty_rect;\n    return word_n + 1;  // word counter\n}\n\nint _as_words(fz_stext_block *block, mupdf::FzBuffer& buff, fz_rect tp_rect, PyObject *lines, int block_n, PyObject *delimiters)\n{\n    /* 'buff' is intermediate storage for composing a word. Used as parameter only for\n    avoiding repeated allocation of an FzBuffer.*/\n    int line_n;\n    fz_stext_line *line;\n    fz_stext_char *ch;\n    fz_rect wbbox, blockrect;\n    while (block)\n    {\n        switch (block->type)\n        {\n            case FZ_STEXT_BLOCK_STRUCT:\n                if (block->u.s.down)\n                {\n                    block_n = _as_words(block->u.s.down->first_block, buff, tp_rect, lines, block_n, delimiters);\n                }\n                break;\n\n            case FZ_STEXT_BLOCK_TEXT:\n                block_n++;\n                blockrect = block->bbox;\n                wbbox = fz_empty_rect;\n                line_n = -1;\n                for (line = block->u.t.first_line; line; line = line->next)\n                {\n                    line_n++;\n                    int word_n = 0;                 // word counter per line\n                    mupdf::fz_clear_buffer(buff);   // reset word buffer\n                    int last_char_rtl = 0;          // was last character RTL?\n                            for (ch = line->first_char; ch; ch = ch->next)\n                    {\n                        mupdf::FzRect cbbox = JM_char_bbox(line, ch);\n                        if (!JM_rects_overlap(tp_rect, *cbbox.internal()) && !fz_is_infinite_rect(tp_rect))\n                        {\n                            continue;\n                        }\n                        // prevent Unicode ZWJ 0x200d to start a word\n                        if (mupdf::fz_buffer_storage(buff, NULL) == 0 && ch->c == 0x200d)\n                        {\n                            continue;\n                        }\n                        int word_delimiter = JM_is_word_delimiter(ch->c, delimiters);\n                        int this_char_rtl = JM_is_rtl_char(ch->c);\n                        if (word_delimiter || this_char_rtl != last_char_rtl)\n                        {\n                            if (mupdf::fz_buffer_storage(buff, NULL) == 0 && word_delimiter)\n                            {\n                                continue;  // skip delimiters at line start\n                            }\n                            if (!fz_is_empty_rect(wbbox))\n                            {\n                                word_n = JM_append_word(\n                                        lines,\n                                        buff.m_internal,\n                                        &wbbox,\n                                        block_n,\n                                        line_n,\n                                        word_n\n                                        );\n                            }\n                            mupdf::fz_clear_buffer(buff);\n                            if (word_delimiter) continue;\n                        }\n                        // append one unicode character to the word\n                        JM_append_rune(buff.m_internal, ch->c);\n                        last_char_rtl = this_char_rtl;\n                        // enlarge word bbox\n                        wbbox = fz_union_rect(wbbox, JM_char_bbox(line, ch));\n                    }\n                    if (mupdf::fz_buffer_storage(buff, NULL) && !fz_is_empty_rect(wbbox))\n                    {\n                        word_n = JM_append_word(\n                                lines,\n                                buff.m_internal,\n                                &wbbox,\n                                block_n,\n                                line_n,\n                                word_n\n                                );\n                    }\n                    mupdf::fz_clear_buffer(buff);\n                }\n                break;\n        }\n        block = block->next;     \n    }\n    return block_n;\n}\n\n\nPyObject* extractWORDS(mupdf::FzStextPage& this_tpage, PyObject *delimiters)\n{\n    int block_n = -1;\n    fz_rect tp_rect = this_tpage.m_internal->mediabox;\n    PyObject *lines = NULL;\n    mupdf::FzBuffer buff = mupdf::fz_new_buffer(64);\n    lines = PyList_New(0);\n    mupdf::FzStextBlock block = this_tpage.m_internal->first_block;\n    block_n = _as_words(block.m_internal, buff, tp_rect, lines, block_n, delimiters);\n    return lines;\n}\n\n\nstruct ScopedPyObject\n/* PyObject* wrapper, destructor calls Py_CLEAR() unless `release()` has been\ncalled. */\n{\n    ScopedPyObject(PyObject* rhs=nullptr)\n    :\n    m_pyobject(rhs)\n    {}\n    \n    PyObject*& get()\n    {\n        return m_pyobject;\n    }\n    \n    ScopedPyObject& operator= (PyObject* rhs)\n    {\n        Py_CLEAR(m_pyobject);\n        m_pyobject = rhs;\n        return *this;\n    }\n    \n    PyObject* release()\n    {\n        PyObject* ret = m_pyobject;\n        m_pyobject = nullptr;\n        return ret;\n    }\n    ~ScopedPyObject()\n    {\n        Py_CLEAR(m_pyobject);\n    }\n    \n    PyObject*   m_pyobject = nullptr;\n};\n\nint _as_blocks(fz_stext_block *block, fz_rect tp_rect, PyObject *lines, int block_n)\n{\n    /*\n    Recursive function for output by blocks as identified by the\n    MuPDF SEGMENT logic.\n    Recursion happens on encountering a structure block.\n    In addition to the previous support of text and image, we now also support\n    vector blocks.\n    */\n    PyObject *text = NULL;\n    fz_rect blockrect;\n    mupdf::FzBuffer res;\n    int last_char;\n    while (block)\n    {\n        switch (block->type)\n        {\n            case FZ_STEXT_BLOCK_STRUCT:\n                if (block->u.s.down)\n                {\n                    block_n = _as_blocks(block->u.s.down->first_block, tp_rect, lines, block_n);\n                }\n                break;\n\n            case FZ_STEXT_BLOCK_TEXT:\n                blockrect = fz_empty_rect;\n                res = mupdf::fz_new_buffer(1024);\n                last_char = 10;\n                for (fz_stext_line* line = block->u.t.first_line; line; line = line->next)\n                {\n                    fz_rect linerect = fz_empty_rect;\n                    for (fz_stext_char* ch = line->first_char; ch; ch = ch->next)\n                    {\n                        fz_rect cbbox = JM_char_bbox(line, ch);\n                        if (!JM_rects_overlap(tp_rect, cbbox) && !fz_is_infinite_rect(tp_rect))\n                        {\n                            continue;\n                        }\n                        JM_append_rune(res.m_internal, ch->c);\n                        last_char = ch->c;\n                        linerect = fz_union_rect(linerect, cbbox);\n                    }\n                    if (last_char != 10 && !fz_is_empty_rect(linerect))\n                    {\n                            JM_append_rune(res.m_internal, 10);\n                    }\n                    blockrect = fz_union_rect(blockrect, linerect);\n                }\n                text = JM_EscapeStrFromBuffer(res);\n                break;\n\n            case FZ_STEXT_BLOCK_IMAGE:\n                if (fz_contains_rect(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect))\n                {\n                    blockrect = block->bbox;\n                    fz_image *img = block->u.i.image;\n                    fz_colorspace *cs = img->colorspace;\n                    text = PyUnicode_FromFormat(\n                                    \"<image: %s, width: %d, height: %d, bpc: %d>\\n\",\n                            mupdf::ll_fz_colorspace_name(cs),\n                            img->w,\n                            img->h,\n                            img->bpc\n                            );\n                }\n                break;\n\n            case FZ_STEXT_BLOCK_VECTOR:\n                if (JM_rects_overlap(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect))\n                {\n                    blockrect = block->bbox;\n                    int alpha = (int) (block->u.v.argb >> 24);\n                    int color = (int) (block->u.v.argb & 0xffffff);\n                    text = PyUnicode_FromFormat(\n                            \"\\n<vector %s, color: #%06x, alpha: %i, is-rect: %s, continues: %s>\\n\",\n                            (block->u.v.flags & FZ_STEXT_VECTOR_IS_STROKED) ? \"stroked\" : \"filled\",\n                            color,\n                            alpha,\n                            (block->u.v.flags & FZ_STEXT_VECTOR_IS_RECTANGLE) ? \"true\":\"false\",\n                            (block->u.v.flags & FZ_STEXT_VECTOR_CONTINUES) ? \"true\":\"false\");\n                }\n                break;\n        }\n\n        if (text)\n        {\n            block_n += 1;\n            PyObject *litem = PyTuple_New(7);\n            PyTuple_SET_ITEM(litem, 0, Py_BuildValue(\"f\", blockrect.x0));\n            PyTuple_SET_ITEM(litem, 1, Py_BuildValue(\"f\", blockrect.y0));\n            PyTuple_SET_ITEM(litem, 2, Py_BuildValue(\"f\", blockrect.x1));\n            PyTuple_SET_ITEM(litem, 3, Py_BuildValue(\"f\", blockrect.y1));\n            PyTuple_SET_ITEM(litem, 4, Py_BuildValue(\"O\", text));\n            PyTuple_SET_ITEM(litem, 5, Py_BuildValue(\"i\", block_n));\n            PyTuple_SET_ITEM(litem, 6, Py_BuildValue(\"i\", block->type));\n            LIST_APPEND(lines, litem);\n        }\n        text = NULL;\n        block = block->next;\n        }\n    return block_n;\n    }\n\nPyObject* extractBLOCKS(mupdf::FzStextPage& self)\n{\n    fz_stext_page *this_tpage = self.m_internal;\n    fz_rect tp_rect = this_tpage->mediabox;\n    ScopedPyObject lines(PyList_New(0));\n    int block_n = -1;\n    fz_stext_block *block = this_tpage->first_block;\n    block_n = _as_blocks(block, tp_rect, lines.get(), block_n);\n    return lines.release();\n}\n\n#define EMPTY_STRING PyUnicode_FromString(\"\")\n\nstatic PyObject *JM_UnicodeFromStr(const char *c)\n{\n    if (!c) return EMPTY_STRING;\n    PyObject *val = Py_BuildValue(\"s\", c);\n    if (!val) {\n        val = EMPTY_STRING;\n        PyErr_Clear();\n    }\n    return val;\n}\n\nPyObject* link_uri(mupdf::FzLink& link)\n{\n    return JM_UnicodeFromStr( link.m_internal->uri);\n}\n\nfz_stext_page* page_get_textpage(\n        mupdf::FzPage& self,\n        PyObject* clip,\n        int flags,\n        PyObject* matrix\n        )\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    fz_stext_page *tpage=NULL;\n    fz_page *page = self.m_internal;\n    fz_device *dev = NULL;\n    fz_stext_options options;\n    memset(&options, 0, sizeof options);\n    options.flags = flags;\n    fz_try(ctx) {\n        // Default to page's rect if `clip` not specified, for #2048.\n        fz_rect rect = (clip==Py_None) ? fz_bound_page(ctx, page) : JM_rect_from_py(clip);\n        fz_matrix ctm = JM_matrix_from_py(matrix);\n        tpage = fz_new_stext_page(ctx, rect);\n        dev = fz_new_stext_device(ctx, tpage, &options);\n        fz_run_page(ctx, page, dev, ctm, NULL);\n        fz_close_device(ctx, dev);\n    }\n    fz_always(ctx) {\n        fz_drop_device(ctx, dev);\n    }\n    fz_catch(ctx) {\n        mupdf::internal_throw_exception(ctx);\n    }\n    return tpage;\n}\n\n// return extension for pymupdf image type\nconst char *JM_image_extension(int type)\n{\n    switch (type) {\n        case(FZ_IMAGE_RAW): return \"raw\";\n        case(FZ_IMAGE_FLATE): return \"flate\";\n        case(FZ_IMAGE_LZW): return \"lzw\";\n        case(FZ_IMAGE_RLD): return \"rld\";\n        case(FZ_IMAGE_BMP): return \"bmp\";\n        case(FZ_IMAGE_GIF): return \"gif\";\n        case(FZ_IMAGE_JBIG2): return \"jb2\";\n        case(FZ_IMAGE_JPEG): return \"jpeg\";\n        case(FZ_IMAGE_JPX): return \"jpx\";\n        case(FZ_IMAGE_JXR): return \"jxr\";\n        case(FZ_IMAGE_PNG): return \"png\";\n        case(FZ_IMAGE_PNM): return \"pnm\";\n        case(FZ_IMAGE_TIFF): return \"tiff\";\n        default: return \"n/a\";\n    }\n}\n\nvoid JM_make_image_block(fz_stext_block *block, PyObject *block_dict)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    fz_image *image = block->u.i.image;\n    fz_buffer *buf = NULL, *freebuf = NULL, *mask_buf = NULL;\n    fz_compressed_buffer *buffer = fz_compressed_image_buffer(ctx, image);\n    fz_var(buf);\n    fz_var(freebuf);\n    fz_var(mask_buf);\n    int n = fz_colorspace_n(ctx, image->colorspace);\n    int w = image->w;\n    int h = image->h;\n    const char *ext = \"\";\n    int type = FZ_IMAGE_UNKNOWN;\n    if (buffer) {\n        type = buffer->params.type;\n        ext = JM_image_extension(type);\n    }\n    if (type < FZ_IMAGE_BMP || type == FZ_IMAGE_JBIG2)\n        type = FZ_IMAGE_UNKNOWN;\n    PyObject *bytes = NULL;\n    fz_var(bytes);\n    PyObject *mask_bytes = NULL;\n    fz_var(mask_bytes);\n    fz_try(ctx) {\n        if (!buffer || type == FZ_IMAGE_UNKNOWN)\n        {\n            buf = freebuf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);\n            ext = \"png\";\n        }\n        else if (n == 4 && strcmp(ext, \"jpeg\") == 0) // JPEG CMYK needs another step\n        {\n            buf = freebuf = fz_new_buffer_from_image_as_jpeg(ctx, image, fz_default_color_params, 95, 1);        \n        }\n        else\n        {\n            buf = buffer->buffer;\n        } \n        bytes = JM_BinFromBuffer(buf);\n        if (image->mask) {\n            mask_buf = fz_new_buffer_from_image_as_png(ctx, image->mask, fz_default_color_params);\n            mask_bytes = JM_BinFromBuffer(mask_buf);\n        } else {\n            mask_bytes = Py_BuildValue(\"s\", NULL);\n        }\n    }\n    fz_always(ctx) {\n        if (!bytes)\n            bytes = PyBytes_FromString(\"\");\n        DICT_SETITEM_DROP(block_dict, dictkey_width,\n                        Py_BuildValue(\"i\", w));\n        DICT_SETITEM_DROP(block_dict, dictkey_height,\n                        Py_BuildValue(\"i\", h));\n        DICT_SETITEM_DROP(block_dict, dictkey_ext,\n                        Py_BuildValue(\"s\", ext));\n        DICT_SETITEM_DROP(block_dict, dictkey_colorspace,\n                        Py_BuildValue(\"i\", n));\n        DICT_SETITEM_DROP(block_dict, dictkey_xres,\n                        Py_BuildValue(\"i\", image->xres));\n        DICT_SETITEM_DROP(block_dict, dictkey_yres,\n                        Py_BuildValue(\"i\", image->xres));\n        DICT_SETITEM_DROP(block_dict, dictkey_bpc,\n                        Py_BuildValue(\"i\", (int) image->bpc));\n        DICT_SETITEM_DROP(block_dict, dictkey_matrix,\n                        JM_py_from_matrix(block->u.i.transform));\n        DICT_SETITEM_DROP(block_dict, dictkey_size,\n                        Py_BuildValue(\"n\", PyBytes_Size(bytes)));\n        DICT_SETITEM_DROP(block_dict, dictkey_image, bytes);\n        DICT_SETITEMSTR_DROP(block_dict, \"mask\", mask_bytes);\n        fz_drop_buffer(ctx, mask_buf);\n        fz_drop_buffer(ctx, freebuf);\n    }\n    fz_catch(ctx)\n    {\n        fz_ignore_error(ctx);\n    }\n    return;\n}\n\n\nvoid JM_make_vector_block(fz_stext_block *block, PyObject *block_dict)\n{\n    DICT_SETITEM_DROP(block_dict, dictkey_bbox, JM_py_from_rect(block->bbox));\n    DICT_SETITEMSTR_DROP(block_dict, \"stroked\", JM_BOOL(block->u.v.flags & FZ_STEXT_VECTOR_IS_STROKED));\n    DICT_SETITEMSTR_DROP(block_dict, \"isrect\", JM_BOOL(block->u.v.flags & FZ_STEXT_VECTOR_IS_RECTANGLE));\n    DICT_SETITEMSTR_DROP(block_dict, \"continues\", JM_BOOL(block->u.v.flags & FZ_STEXT_VECTOR_CONTINUES));\n    int color = (int) block->u.v.argb & 0xffffff;  // extract color components\n    int alpha = block->u.v.argb >> 24;  // extract alpha value\n    DICT_SETITEM_DROP(block_dict, dictkey_color, Py_BuildValue(\"i\", color));\n    DICT_SETITEMSTR_DROP(block_dict, \"alpha\", Py_BuildValue(\"i\", alpha));\n    return;\n}\n\nvoid JM_make_grid_block(fz_stext_block *block, PyObject *block_dict)\n{\n    Py_ssize_t i;\n    PyObject *pos;\n\n    DICT_SETITEM_DROP(block_dict, dictkey_bbox, JM_py_from_rect(block->bbox));\n\n    DICT_SETITEM_DROP(block_dict, dictkey_type, Py_BuildValue(\"i\", block->type));\n\n    DICT_SETITEMSTR_DROP(block_dict, \"max_uncertain\", Py_BuildValue(\"ii\",\n        block->u.b.xs->max_uncertainty,\n        block->u.b.ys->max_uncertainty));\n\n    // x coordinates with uncertainties\n    pos = PyList_New((size_t) block->u.b.xs->len);\n    for (i = 0; i <  block->u.b.xs->len; i++)\n    {\n        PyList_SetItem(pos, i, Py_BuildValue(\"fi\",\n            block->u.b.xs->list[i].pos,\n            block->u.b.xs->list[i].uncertainty));\n    }\n    DICT_SETITEMSTR_DROP(block_dict, \"xpos\", pos);\n\n    // y coordinates with uncertainties\n    pos = PyList_New((size_t) block->u.b.ys->len);\n    for (i = 0; i <  block->u.b.ys->len; i++)\n    {\n        PyList_SetItem(pos, i, Py_BuildValue(\"fi\",\n            block->u.b.ys->list[i].pos,\n            block->u.b.ys->list[i].uncertainty));\n    }\n    DICT_SETITEMSTR_DROP(block_dict, \"ypos\", pos);\n    \n    return;\n}\n\n\nvoid make_table_dict(fz_stext_page *tp, PyObject *table_dict, PyObject *bbox)\n{\n    fz_rect bounds = JM_rect_from_py(bbox);\n    fz_stext_block *block;\n\n    try\n    {\n        block = mupdf::ll_fz_find_table_within_bounds(tp, bounds);\n    }\n    catch (std::exception&)\n    {\n        /* Ignore failure to find a table structure. */\n        return;\n    }\n\n    // Check if a table structure was found\n    if (block && block->type == FZ_STEXT_BLOCK_GRID)\n    {\n        JM_make_grid_block(block, table_dict);\n    }\n\n}\n\n\nstatic void JM_make_text_block(fz_stext_block *block, PyObject *block_dict, int raw, fz_buffer *buff, fz_rect tp_rect)\n{\n    fz_stext_line *line;\n    PyObject *line_list = PyList_New(0), *line_dict;\n    fz_rect block_rect = fz_empty_rect;\n    for (line = block->u.t.first_line; line; line = line->next) {\n        if (fz_is_empty_rect(fz_intersect_rect(tp_rect, line->bbox)) &&\n            !fz_is_infinite_rect(tp_rect)) {\n            continue;\n        }\n        line_dict = PyDict_New();\n        mupdf::FzStextLine line2(line);\n        mupdf::FzBuffer buff2( mupdf::ll_fz_keep_buffer( buff));\n        mupdf::FzRect tp_rect2( tp_rect);\n        mupdf::FzRect line_rect2 = JM_make_spanlist(\n                line_dict,\n                line2,\n                raw,\n                buff2,\n                tp_rect2\n                );\n        fz_rect& line_rect = *line_rect2.internal();\n        block_rect = fz_union_rect(block_rect, line_rect);\n        DICT_SETITEM_DROP(line_dict, dictkey_wmode,\n                    Py_BuildValue(\"i\", line->wmode));\n        DICT_SETITEM_DROP(line_dict, dictkey_dir, JM_py_from_point(line->dir));\n        DICT_SETITEM_DROP(line_dict, dictkey_bbox,\n                    JM_py_from_rect(line_rect));\n        LIST_APPEND_DROP(line_list, line_dict);\n    }\n    DICT_SETITEM_DROP(block_dict, dictkey_bbox, JM_py_from_rect(block_rect));\n    DICT_SETITEM_DROP(block_dict, dictkey_lines, line_list);\n    return;\n}\n\n\nvoid JM_make_struct_block(fz_stext_block *block, PyObject *block_dict)\n{\n    DICT_SETITEMSTR_DROP(block_dict, \"index\", Py_BuildValue(\"i\",block->u.s.index));\n    if (block->u.s.down)\n    {\n        DICT_SETITEMSTR_DROP(block_dict, \"raw\", Py_BuildValue(\"s\",block->u.s.down->raw));\n        DICT_SETITEMSTR_DROP(block_dict, \"std\", Py_BuildValue(\"s\",fz_structure_to_string(block->u.s.down->standard)));\n    }\n    \n}\n\n\nint _as_dict(PyObject *block_list, fz_stext_block *block, fz_buffer *text_buffer, int raw, fz_rect tp_rect, int block_n)\n{\n    /*\n    Recursive function for output by blocks as identified by the\n    MuPDF SEGMENT logic.\n    */\n    PyObject *block_dict;\n    while (block)\n    {\n        switch (block->type)\n        {\n            case FZ_STEXT_BLOCK_STRUCT:\n                if (block->u.s.down && block->u.s.down->first_block)\n                {\n                    block_n++;\n                    block_dict = PyDict_New();\n                    DICT_SETITEM_DROP(block_dict, dictkey_type, Py_BuildValue(\"i\", block->type));\n                    DICT_SETITEM_DROP(block_dict, dictkey_number, Py_BuildValue(\"i\", block_n));\n                    DICT_SETITEM_DROP(block_dict, dictkey_bbox, JM_py_from_rect(block->bbox));\n                    JM_make_struct_block(block, block_dict);\n                    PyObject *subblocks = PyList_New(0);\n                    block_n = _as_dict(subblocks, block->u.s.down->first_block, text_buffer, raw, tp_rect, block_n);\n                    DICT_SETITEM_DROP(block_dict, dictkey_blocks, subblocks);\n                    LIST_APPEND_DROP(block_list, block_dict);\n                }\n            break;\n\n            case FZ_STEXT_BLOCK_TEXT:\n                if (JM_rects_overlap(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect))\n                {\n                    block_dict = PyDict_New();\n                    block_n++;\n                    DICT_SETITEM_DROP(block_dict, dictkey_type, Py_BuildValue(\"i\", block->type));\n                    DICT_SETITEM_DROP(block_dict, dictkey_number, Py_BuildValue(\"i\", block_n));\n                    DICT_SETITEMSTR_DROP(block_dict, \"flags\", Py_BuildValue(\"i\", block->u.t.flags));\n                    JM_make_text_block(block, block_dict, raw, text_buffer, tp_rect);\n                    LIST_APPEND_DROP(block_list, block_dict);\n                }\n            break;\n\n            case FZ_STEXT_BLOCK_IMAGE:\n                if (fz_contains_rect(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect))\n                {\n                    block_dict = PyDict_New();\n                    block_n++;\n                    DICT_SETITEM_DROP(block_dict, dictkey_type, Py_BuildValue(\"i\", block->type));\n                    DICT_SETITEM_DROP(block_dict, dictkey_number, Py_BuildValue(\"i\", block_n));\n                    DICT_SETITEM_DROP(block_dict, dictkey_bbox, JM_py_from_rect(block->bbox));\n                    JM_make_image_block(block, block_dict);\n                    LIST_APPEND_DROP(block_list, block_dict);\n                }\n            break;\n\n            case FZ_STEXT_BLOCK_VECTOR:\n                if (JM_rects_overlap(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect))\n                {\n                    block_dict = PyDict_New();\n                    block_n++;\n                    DICT_SETITEM_DROP(block_dict, dictkey_type, Py_BuildValue(\"i\", block->type));\n                    DICT_SETITEM_DROP(block_dict, dictkey_number, Py_BuildValue(\"i\", block_n));\n                    JM_make_vector_block(block, block_dict);\n                    LIST_APPEND_DROP(block_list, block_dict);\n                }\n            break;\n\n            case FZ_STEXT_BLOCK_GRID:\n                if (JM_rects_overlap(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect))\n                {\n                    block_dict = PyDict_New();\n                    block_n++;\n                    DICT_SETITEM_DROP(block_dict, dictkey_type, Py_BuildValue(\"i\", block->type));\n                    DICT_SETITEM_DROP(block_dict, dictkey_number, Py_BuildValue(\"i\", block_n));\n                    JM_make_grid_block(block, block_dict);\n                    LIST_APPEND_DROP(block_list, block_dict);\n                }\n            break;\n        }\n        block = block->next;\n    }\n    return block_n;\n}\n\nvoid JM_make_textpage_dict(fz_stext_page *tp, PyObject *page_dict, int raw)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    fz_stext_block *block;\n    fz_buffer *text_buffer = fz_new_buffer(ctx, 128);\n    PyObject *block_list = PyList_New(0);\n    fz_rect tp_rect = tp->mediabox;\n    block = tp->first_block;\n    int block_n = -1;\n    block_n = _as_dict(block_list, block, text_buffer, raw, tp_rect, block_n);\n    DICT_SETITEM_DROP(page_dict, dictkey_blocks, block_list);\n    fz_drop_buffer(ctx, text_buffer);\n}\n\n//-----------------------------------------------------------------\n// get one pixel as a list\n//-----------------------------------------------------------------\nPyObject *pixmap_pixel(fz_pixmap* pm, int x, int y)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    PyObject *p = NULL;\n    if (0\n            || x < 0\n            || x >= pm->w\n            || y < 0\n            || y >= pm->h\n            )\n    {\n        throw std::range_error( MSG_PIXEL_OUTSIDE);\n    }\n    int n = pm->n;\n    int stride = fz_pixmap_stride(ctx, pm);\n    int i = stride * y + n * x;\n    p = PyTuple_New(n);\n    for (int j = 0; j < n; j++)\n    {\n        PyTuple_SET_ITEM(p, j, Py_BuildValue(\"i\", pm->samples[i + j]));\n    }\n    return p;\n}\n\nint pixmap_n(mupdf::FzPixmap& pixmap)\n{\n    return mupdf::fz_pixmap_components( pixmap);\n}\n\nstatic int\nJM_INT_ITEM(PyObject *obj, Py_ssize_t idx, int *result)\n{\n    PyObject *temp = PySequence_ITEM(obj, idx);\n    if (!temp) return 1;\n    if (PyLong_Check(temp)) {\n        *result = (int) PyLong_AsLong(temp);\n        Py_DECREF(temp);\n    } else if (PyFloat_Check(temp)) {\n        *result = (int) PyFloat_AsDouble(temp);\n        Py_DECREF(temp);\n    } else {\n        Py_DECREF(temp);\n        return 1;\n    }\n    if (PyErr_Occurred()) {\n        PyErr_Clear();\n        return 1;\n    }\n    return 0;\n}\n\nPyObject *set_pixel(fz_pixmap* pm, int x, int y, PyObject *color)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    if (0\n            || x < 0\n            || x >= pm->w\n            || y < 0\n            || y >= pm->h\n            )\n    {\n        throw std::range_error( MSG_PIXEL_OUTSIDE);\n    }\n    int n = pm->n;\n    if (!PySequence_Check(color) || PySequence_Size(color) != n) {\n        throw std::range_error(MSG_BAD_COLOR_SEQ);\n    }\n    int i, j;\n    unsigned char c[5];\n    for (j = 0; j < n; j++) {\n        if (JM_INT_ITEM(color, j, &i) == 1) {\n            throw std::range_error(MSG_BAD_COLOR_SEQ);\n        }\n        if (i < 0 or i >= 256) {\n            throw std::range_error(MSG_BAD_COLOR_SEQ);\n        }\n        c[j] = (unsigned char) i;\n    }\n    int stride = fz_pixmap_stride(ctx, pm);\n    i = stride * y + n * x;\n    for (j = 0; j < n; j++) {\n        pm->samples[i + j] = c[j];\n    }\n    Py_RETURN_NONE;\n}\n//-------------------------------------------\n// make a buffer from an stext_page's text\n//-------------------------------------------\nfz_buffer *\nJM_new_buffer_from_stext_page(fz_stext_page *page)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    fz_stext_block *block;\n    fz_stext_line *line;\n    fz_stext_char *ch;\n    fz_rect rect = page->mediabox;\n    fz_buffer *buf = NULL;\n\n    fz_try(ctx)\n    {\n        buf = fz_new_buffer(ctx, 256);\n        for (block = page->first_block; block; block = block->next) {\n            if (block->type == FZ_STEXT_BLOCK_TEXT) {\n                for (line = block->u.t.first_line; line; line = line->next) {\n                    for (ch = line->first_char; ch; ch = ch->next) {\n                        if (!JM_rects_overlap(rect, JM_char_bbox(line, ch)) &&\n                            !fz_is_infinite_rect(rect)) {\n                            continue;\n                        }\n                        fz_append_rune(ctx, buf, ch->c);\n                    }\n                    fz_append_byte(ctx, buf, '\\n');\n                }\n                fz_append_byte(ctx, buf, '\\n');\n            }\n        }\n    }\n    fz_catch(ctx) {\n        fz_drop_buffer(ctx, buf);\n        mupdf::internal_throw_exception(ctx);\n    }\n    return buf;\n}\n\nstatic inline int canon(int c)\n{\n    /* TODO: proper unicode case folding */\n    /* TODO: character equivalence (a matches ä, etc) */\n    if (c == 0xA0 || c == 0x2028 || c == 0x2029)\n        return ' ';\n    if (c == '\\r' || c == '\\n' || c == '\\t')\n        return ' ';\n    if (c >= 'A' && c <= 'Z')\n        return c - 'A' + 'a';\n    return c;\n}\n\nstatic inline int chartocanon(int *c, const char *s)\n{\n    int n = fz_chartorune(c, s);\n    *c = canon(*c);\n    return n;\n}\n\nstatic const char *match_string(const char *h, const char *n)\n{\n    int hc, nc;\n    const char *e = h;\n    h += chartocanon(&hc, h);\n    n += chartocanon(&nc, n);\n    while (hc == nc)\n    {\n        e = h;\n        if (hc == ' ')\n            do\n                h += chartocanon(&hc, h);\n            while (hc == ' ');\n        else\n            h += chartocanon(&hc, h);\n        if (nc == ' ')\n            do\n                n += chartocanon(&nc, n);\n            while (nc == ' ');\n        else\n            n += chartocanon(&nc, n);\n    }\n    return nc == 0 ? e : NULL;\n}\n\n\nstatic const char *find_string(const char *s, const char *needle, const char **endp)\n{\n    const char *end;\n    while (*s)\n    {\n        end = match_string(s, needle);\n        if (end)\n        {\n            *endp = end;\n            return s;\n        }\n        ++s;\n    }\n    *endp = NULL;\n    return NULL;\n}\n\nstruct highlight\n{\n    Py_ssize_t len;\n    PyObject *quads;\n    float hfuzz, vfuzz;\n};\n\n\nstatic int\nJM_FLOAT_ITEM(PyObject *obj, Py_ssize_t idx, double *result)\n{\n    PyObject *temp = PySequence_ITEM(obj, idx);\n    if (!temp) return 1;\n    *result = PyFloat_AsDouble(temp);\n    Py_DECREF(temp);\n    if (PyErr_Occurred()) {\n        PyErr_Clear();\n        return 1;\n    }\n    return 0;\n}\n\n\n//-----------------------------------------------------------------------------\n// fz_quad from PySequence. Four floats are treated as rect.\n// Else must be four pairs of floats.\n//-----------------------------------------------------------------------------\nstatic fz_quad\nJM_quad_from_py(PyObject *r)\n{\n    fz_quad q = fz_make_quad(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT,\n                             FZ_MAX_INF_RECT, FZ_MIN_INF_RECT,\n                             FZ_MIN_INF_RECT, FZ_MAX_INF_RECT,\n                             FZ_MAX_INF_RECT, FZ_MAX_INF_RECT);\n    fz_point p[4];\n    double test, x, y;\n    Py_ssize_t i;\n    PyObject *obj = NULL;\n\n    if (!r || !PySequence_Check(r) || PySequence_Size(r) != 4)\n        return q;\n\n    if (JM_FLOAT_ITEM(r, 0, &test) == 0)\n        return fz_quad_from_rect(JM_rect_from_py(r));\n\n    for (i = 0; i < 4; i++) {\n        obj = PySequence_ITEM(r, i);  // next point item\n        if (!obj || !PySequence_Check(obj) || PySequence_Size(obj) != 2)\n            goto exit_result;  // invalid: cancel the rest\n\n        if (JM_FLOAT_ITEM(obj, 0, &x) == 1) goto exit_result;\n        if (JM_FLOAT_ITEM(obj, 1, &y) == 1) goto exit_result;\n        if (x < FZ_MIN_INF_RECT) x = FZ_MIN_INF_RECT;\n        if (y < FZ_MIN_INF_RECT) y = FZ_MIN_INF_RECT;\n        if (x > FZ_MAX_INF_RECT) x = FZ_MAX_INF_RECT;\n        if (y > FZ_MAX_INF_RECT) y = FZ_MAX_INF_RECT;\n        p[i] = fz_make_point((float) x, (float) y);\n\n        Py_CLEAR(obj);\n    }\n    q.ul = p[0];\n    q.ur = p[1];\n    q.ll = p[2];\n    q.lr = p[3];\n    return q;\n\n    exit_result:;\n    Py_CLEAR(obj);\n    return q;\n}\n\nstatic float hdist(fz_point *dir, fz_point *a, fz_point *b)\n{\n    float dx = b->x - a->x;\n    float dy = b->y - a->y;\n    return fz_abs(dx * dir->x + dy * dir->y);\n}\n\nstatic float vdist(fz_point *dir, fz_point *a, fz_point *b)\n{\n    float dx = b->x - a->x;\n    float dy = b->y - a->y;\n    return fz_abs(dx * dir->y + dy * dir->x);\n}\n\nstatic void on_highlight_char(fz_context *ctx, void *arg, fz_stext_line *line, fz_stext_char *ch)\n{\n    struct highlight* hits = (struct highlight*) arg;\n    float vfuzz = ch->size * hits->vfuzz;\n    float hfuzz = ch->size * hits->hfuzz;\n    fz_quad ch_quad = JM_char_quad(line, ch);\n    if (hits->len > 0) {\n        PyObject *quad = PySequence_ITEM(hits->quads, hits->len - 1);\n        fz_quad end = JM_quad_from_py(quad);\n        Py_DECREF(quad);\n        if (hdist(&line->dir, &end.lr, &ch_quad.ll) < hfuzz\n            && vdist(&line->dir, &end.lr, &ch_quad.ll) < vfuzz\n            && hdist(&line->dir, &end.ur, &ch_quad.ul) < hfuzz\n            && vdist(&line->dir, &end.ur, &ch_quad.ul) < vfuzz)\n        {\n            end.ur = ch_quad.ur;\n            end.lr = ch_quad.lr;\n            quad = JM_py_from_quad(end);\n            PyList_SetItem(hits->quads, hits->len - 1, quad);\n            return;\n        }\n    }\n    LIST_APPEND_DROP(hits->quads, JM_py_from_quad(ch_quad));\n    hits->len++;\n}\n\n\nPyObject* JM_search_stext_page(fz_stext_page *page, const char *needle)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    struct highlight hits;\n    fz_stext_block *block;\n    fz_stext_line *line;\n    fz_stext_char *ch;\n    fz_buffer *buffer = NULL;\n    const char *haystack, *begin, *end;\n    fz_rect rect = page->mediabox;\n    int c, inside;\n\n    if (strlen(needle) == 0) Py_RETURN_NONE;\n    PyObject *quads = PyList_New(0);\n    hits.len = 0;\n    hits.quads = quads;\n    hits.hfuzz = 0.2f; /* merge kerns but not large gaps */\n    hits.vfuzz = 0.1f;\n\n    fz_try(ctx) {\n        buffer = JM_new_buffer_from_stext_page( page);\n        haystack = fz_string_from_buffer(ctx, buffer);\n        begin = find_string(haystack, needle, &end);\n        if (!begin) goto no_more_matches;\n\n        inside = 0;\n        for (block = page->first_block; block; block = block->next) {\n            if (block->type != FZ_STEXT_BLOCK_TEXT) {\n                continue;\n            }\n            for (line = block->u.t.first_line; line; line = line->next) {\n                for (ch = line->first_char; ch; ch = ch->next) {\n                    if (!fz_is_infinite_rect(rect) &&\n                        !JM_rects_overlap(rect, JM_char_bbox(line, ch))) {\n                            goto next_char;\n                        }\ntry_new_match:\n                    if (!inside) {\n                        if (haystack >= begin) inside = 1;\n                    }\n                    if (inside) {\n                        if (haystack < end) {\n                            on_highlight_char(ctx, &hits, line, ch);\n                        } else {\n                            inside = 0;\n                            begin = find_string(haystack, needle, &end);\n                            if (!begin) goto no_more_matches;\n                            else goto try_new_match;\n                        }\n                    }\n                    haystack += fz_chartorune(&c, haystack);\nnext_char:;\n                }\n                assert(*haystack == '\\n');\n                ++haystack;\n            }\n            assert(*haystack == '\\n');\n            ++haystack;\n        }\nno_more_matches:;\n    }\n    fz_always(ctx)\n        fz_drop_buffer(ctx, buffer);\n    fz_catch(ctx)\n        mupdf::internal_throw_exception(ctx);\n\n    return quads;\n}\n\nvoid pixmap_copy( fz_pixmap* pm, const fz_pixmap* src, int n)\n{\n    assert(pm->w == src->w);\n    assert(pm->h == src->h);\n    assert(n <= pm->n);\n    assert(n <= src->n);\n\n    if (pm->n == src->n)\n    {\n        // identical samples\n        assert(pm->stride == src->stride);\n        memcpy(pm->samples, src->samples, pm->w * pm->h * pm->n);\n    }\n    else\n    {\n        int nn;\n        int do_alpha;\n        if (pm->n > src->n)\n        {\n            assert(pm->n == src->n + 1);\n            nn = src->n;\n            assert(!src->alpha);\n            assert(pm->alpha);\n            do_alpha = 1;\n        }\n        else\n        {\n            assert(src->n == pm->n + 1);\n            nn = pm->n;\n            assert(src->alpha);\n            assert(!pm->alpha);\n            do_alpha = 0;\n        }\n        for (int y=0; y<pm->h; ++y)\n        {\n            for (int x=0; x<pm->w; ++x)\n            {\n                memcpy(\n                        pm->samples + pm->stride * y + pm->n * x,\n                        src->samples + src->stride * y + src->n * x,\n                        nn\n                        );\n                if (do_alpha)\n                {\n                    pm->samples[pm->stride * y + pm->n * x + pm->n-1] = 255;\n                }\n            }\n        }\n    }\n}\n\n\nPyObject* ll_JM_color_count(fz_pixmap *pm, PyObject *clip)\n{\n    fz_context* ctx = mupdf::internal_context_get();\n    PyObject* rc = PyDict_New();\n    fz_irect irect = fz_pixmap_bbox(ctx, pm);\n    irect = fz_intersect_irect(irect, fz_round_rect(JM_rect_from_py(clip)));\n    if (fz_is_empty_irect(irect))\n    {\n        return rc;\n    }\n    size_t stride = pm->stride;\n    size_t width = irect.x1 - irect.x0;\n    size_t height = irect.y1 - irect.y0;\n    size_t n = (size_t) pm->n;\n    size_t substride = width * n;\n    unsigned char* s = pm->samples + stride * (irect.y0 - pm->y) + n * (irect.x0 - pm->x);\n    // Cache previous pixel.\n    char oldpix[10];\n    assert(n <= sizeof(oldpix));\n    memcpy(oldpix, s, n);\n    long cnt = 0;\n    for (size_t i = 0; i < height; i++)\n    {\n        for (size_t j = 0; j < substride; j += n)\n        {\n            const char* newpix = (const char*) s + j;\n            if (memcmp(oldpix, newpix, n))\n            {\n                /* Pixel differs from previous pixel, so update results with\n                last run of pixels. We get a PyObject representation of pixel\n                so we can look up in Python dict <rc>. */\n                PyObject* pixel = PyBytes_FromStringAndSize(&oldpix[0], n);\n                PyObject* c = PyDict_GetItem(rc, pixel);\n                if (c) cnt += PyLong_AsLong(c);\n                DICT_SETITEM_DROP(rc, pixel, PyLong_FromLong(cnt));\n                Py_DECREF(pixel);\n                /* Start next run of identical pixels. */\n                cnt = 1;\n                memcpy(oldpix, newpix, n);\n            }\n            else\n            {\n                cnt += 1;\n            }\n        }\n        s += stride;\n    }\n    /* Update results with last pixel. */\n    PyObject* pixel = PyBytes_FromStringAndSize(&oldpix[0], n);\n    PyObject* c = PyDict_GetItem(rc, pixel);\n    if (c) cnt += PyLong_AsLong(c);\n    DICT_SETITEM_DROP(rc, pixel, PyLong_FromLong(cnt));\n    Py_DECREF(pixel);\n    PyErr_Clear();\n    return rc;\n}\n\n%}\n\n/* Declarations for functions defined above. */\n\nvoid page_merge(\n        mupdf::PdfDocument& doc_des,\n        mupdf::PdfDocument& doc_src,\n        int page_from,\n        int page_to,\n        int rotate,\n        int links,\n        int copy_annots,\n        mupdf::PdfGraftMap& graft_map\n        );\n\nvoid JM_merge_range(\n        mupdf::PdfDocument& doc_des,\n        mupdf::PdfDocument& doc_src,\n        int spage,\n        int epage,\n        int apage,\n        int rotate,\n        int links,\n        int annots,\n        int show_progress,\n        mupdf::PdfGraftMap& graft_map\n        );\n\nvoid FzDocument_insert_pdf(\n        mupdf::FzDocument& doc,\n        mupdf::FzDocument& src,\n        int from_page,\n        int to_page,\n        int start_at,\n        int rotate,\n        int links,\n        int annots,\n        int show_progress,\n        int final,\n        mupdf::PdfGraftMap& graft_map\n        );\n\nint page_xref(mupdf::FzDocument& this_doc, int pno);\nvoid _newPage(mupdf::FzDocument& self, int pno=-1, float width=595, float height=842);\nvoid _newPage(mupdf::PdfDocument& self, int pno=-1, float width=595, float height=842);\nvoid JM_add_annot_id(mupdf::PdfAnnot& annot, const char* stem);\nvoid JM_set_annot_callout_line(mupdf::PdfAnnot& annot, PyObject *callout, int count);\nstd::vector< std::string> JM_get_annot_id_list(mupdf::PdfPage& page);\nmupdf::PdfAnnot _add_caret_annot(mupdf::PdfPage& self, mupdf::FzPoint& point);\nmupdf::PdfAnnot _add_caret_annot(mupdf::FzPage& self, mupdf::FzPoint& point);\nconst char* Tools_parse_da(mupdf::PdfAnnot& this_annot);\nPyObject* Annot_getAP(mupdf::PdfAnnot& annot);\nvoid Tools_update_da(mupdf::PdfAnnot& this_annot, const char* da_str);\nmupdf::FzPoint JM_point_from_py(PyObject* p);\nmupdf::FzRect Annot_rect(mupdf::PdfAnnot& annot);\nPyObject* util_transform_rect(PyObject* rect, PyObject* matrix);\nPyObject* Annot_rect3(mupdf::PdfAnnot& annot);\nmupdf::FzMatrix Page_derotate_matrix(mupdf::PdfPage& pdfpage);\nmupdf::FzMatrix Page_derotate_matrix(mupdf::FzPage& pdfpage);\nPyObject* JM_get_annot_xref_list(const mupdf::PdfObj& page_obj);\nPyObject* xref_object(mupdf::PdfDocument& pdf, int xref, int compressed=0, int ascii=0);\nPyObject* xref_object(mupdf::FzDocument& document, int xref, int compressed=0, int ascii=0);\n\nPyObject* Link_is_external(mupdf::FzLink& this_link);\nPyObject* Page_addAnnot_FromString(mupdf::PdfPage& page, PyObject* linklist);\nPyObject* Page_addAnnot_FromString(mupdf::FzPage& page, PyObject* linklist);\nmupdf::FzLink Link_next(mupdf::FzLink& this_link);\n\nstatic int page_count_fz2(void* document);\nint page_count_fz(mupdf::FzDocument& document);\nint page_count_pdf(mupdf::PdfDocument& pdf);\nint page_count(mupdf::FzDocument& document);\nint page_count(mupdf::PdfDocument& pdf);\n\nPyObject* page_annot_xrefs(mupdf::PdfDocument& pdf, int pno);\nPyObject* page_annot_xrefs(mupdf::FzDocument& document, int pno);\nbool Outline_is_external(mupdf::FzOutline* outline);\nvoid Document_extend_toc_items(mupdf::PdfDocument& pdf, PyObject* items);\nvoid Document_extend_toc_items(mupdf::FzDocument& document, PyObject* items);\n\nint ll_fz_absi(int i);\n\nmupdf::FzDevice JM_new_texttrace_device(PyObject* out);\n\nfz_rect JM_char_bbox(const mupdf::FzStextLine& line, const mupdf::FzStextChar& ch);\n\nstatic fz_quad JM_char_quad( fz_stext_line *line, fz_stext_char *ch);\nvoid JM_print_stext_page_as_text(mupdf::FzBuffer& res, mupdf::FzStextPage& page);\n\nvoid set_skip_quad_corrections(int on);\nvoid set_subset_fontnames(int on);\nvoid set_small_glyph_heights(int on);\n\nmupdf::FzRect JM_cropbox(mupdf::PdfObj& page_obj);\nPyObject* get_cdrawings(mupdf::FzPage& page, PyObject *extended=NULL, PyObject *callback=NULL, PyObject *method=NULL);\n\nmupdf::FzRect JM_make_spanlist(\n        PyObject *line_dict,\n        mupdf::FzStextLine& line,\n        int raw,\n        mupdf::FzBuffer& buff,\n        mupdf::FzRect& tp_rect\n        );\n\nPyObject* extractWORDS(mupdf::FzStextPage& this_tpage, PyObject *delimiters);\nPyObject* extractBLOCKS(mupdf::FzStextPage& self);\n\nPyObject* link_uri(mupdf::FzLink& link);\n\nfz_stext_page* page_get_textpage(\n        mupdf::FzPage& self,\n        PyObject* clip,\n        int flags,\n        PyObject* matrix\n        );\n\nvoid make_table_dict(fz_stext_page *tp, PyObject *table_dict, PyObject *bbox);\nvoid JM_make_textpage_dict(fz_stext_page *tp, PyObject *page_dict, int raw);\nPyObject *pixmap_pixel(fz_pixmap* pm, int x, int y);\nint pixmap_n(mupdf::FzPixmap& pixmap);\n\nPyObject* JM_search_stext_page(fz_stext_page *page, const char *needle);\n\nPyObject *set_pixel(fz_pixmap* pm, int x, int y, PyObject *color);\n\n/* Copies from <src> to <pm>, which must have same width and height. pm->n -\nsrc->n must be -1, 0 or +1. If -1, <src> must have alpha and <pm> must not have\nalpha, and we copy the non-alpha bytes. If +1 <src> must not have alpha and\n<pm> must have alpha and we set <pm>'s alpha bytes all to 255.*/\nvoid pixmap_copy(fz_pixmap* pm, const fz_pixmap* src, int n);\n\nPyObject* ll_JM_color_count(fz_pixmap *pm, PyObject *clip);\n"
  },
  {
    "path": "src/fitz___init__.py",
    "content": "# pylint: disable=wildcard-import,unused-import,unused-wildcard-import,no-name-in-module\nfrom pymupdf import *\nfrom pymupdf import _as_fz_document\nfrom pymupdf import _as_fz_page\nfrom pymupdf import _as_pdf_document\nfrom pymupdf import _as_pdf_page\nfrom pymupdf import _log_items\nfrom pymupdf import _log_items_active\nfrom pymupdf import _log_items_clear\nfrom pymupdf import __version__\nfrom pymupdf import __doc__\nfrom pymupdf import _globals\nfrom pymupdf import _g_out_message\n"
  },
  {
    "path": "src/fitz_table.py",
    "content": "# pylint: disable=wildcard-import,unused-wildcard-import\nfrom pymupdf.table import *\n"
  },
  {
    "path": "src/fitz_utils.py",
    "content": "# pylint: disable=wildcard-import,unused-wildcard-import\nfrom pymupdf.utils import *\n"
  },
  {
    "path": "src/pipcl.py",
    "content": "'''\nPython packaging operations, including PEP-517 support, for use by a `setup.py`\nscript.\n\nOverview:\n\n    The intention is to take care of as many packaging details as possible so\n    that setup.py contains only project-specific information, while also giving\n    as much flexibility as possible.\n\n    For example we provide a function `build_extension()` that can be used\n    to build a SWIG extension, but we also give access to the located\n    compiler/linker so that a `setup.py` script can take over the details\n    itself.\n\nDoctests:\n    Doctest strings are provided in some comments.\n\n    Test in the usual way with:\n        python -m doctest pipcl.py\n\n    Test specific functions/classes with:\n        python pipcl.py --doctest run_if ...\n\n        If no functions or classes are specified, this tests everything.\n\nGraal:\n    For Graal we require that PIPCL_GRAAL_PYTHON is set to non-graal Python (we\n    build for non-graal except with Graal Python's include paths and library\n    directory).\n'''\n\nimport base64\nimport codecs\nimport difflib\nimport glob\nimport hashlib\nimport inspect\nimport io\nimport os\nimport pickle\nimport platform\nimport re\nimport shlex\nimport shutil\nimport site\nimport subprocess\nimport sys\nimport sysconfig\nimport tarfile\nimport textwrap\nimport time\nimport zipfile\n\nimport wdev\n\n\nclass Package:\n    '''\n    Our constructor takes a definition of a Python package similar to that\n    passed to `distutils.core.setup()` or `setuptools.setup()` (name, version,\n    summary etc) plus callbacks for building, getting a list of sdist\n    filenames, and cleaning.\n\n    We provide methods that can be used to implement a Python package's\n    `setup.py` supporting PEP-517.\n\n    We also support basic command line handling for use\n    with a legacy (pre-PEP-517) pip, as implemented\n    by legacy distutils/setuptools and described in:\n    https://pip.pypa.io/en/stable/reference/build-system/setup-py/\n\n    The file pyproject.toml must exist; this is checked if/when fn_build() is\n    called.\n\n    Here is a `doctest` example of using pipcl to create a SWIG extension\n    module. Requires `swig`.\n\n    Create an empty test directory:\n\n        >>> import os\n        >>> import shutil\n        >>> shutil.rmtree('pipcl_test', ignore_errors=1)\n        >>> os.mkdir('pipcl_test')\n\n    Create a `setup.py` which uses `pipcl` to define an extension module.\n\n        >>> import textwrap\n        >>> with open('pipcl_test/setup.py', 'w') as f:\n        ...     _ = f.write(textwrap.dedent(\"\"\"\n        ...             import sys\n        ...             import pipcl\n        ...\n        ...             def build():\n        ...                 so_leaf = pipcl.build_extension(\n        ...                         name = 'foo',\n        ...                         path_i = 'foo.i',\n        ...                         outdir = 'build',\n        ...                         source_extra = 'wibble.c',\n        ...                         )\n        ...                 return [\n        ...                         ('build/foo.py', 'foo/__init__.py'),\n        ...                         ('cli.py', 'foo/__main__.py'),\n        ...                         (f'build/{so_leaf}', f'foo/'),\n        ...                         ('README', '$dist-info/'),\n        ...                         (b'Hello world', 'foo/hw.txt'),\n        ...                         ]\n        ...\n        ...             def sdist():\n        ...                 return [\n        ...                         'pyproject.toml',\n        ...                         'foo.i',\n        ...                         'bar.i',\n        ...                         'wibble.c',\n        ...                         'setup.py',\n        ...                         'pipcl.py',\n        ...                         'wdev.py',\n        ...                         'README',\n        ...                         (b'Hello word2', 'hw2.txt'),\n        ...                         ]\n        ...\n        ...             p = pipcl.Package(\n        ...                     name = 'foo',\n        ...                     version = '1.2.3',\n        ...                     fn_build = build,\n        ...                     fn_sdist = sdist,\n        ...                     entry_points = (\n        ...                         { 'console_scripts': [\n        ...                             'foo_cli = foo.__main__:main',\n        ...                             ],\n        ...                         }),\n        ...                     )\n        ...\n        ...             build_wheel = p.build_wheel\n        ...             build_sdist = p.build_sdist\n        ...\n        ...             # Handle old-style setup.py command-line usage:\n        ...             if __name__ == '__main__':\n        ...                 p.handle_argv(sys.argv)\n        ...             \"\"\"))\n\n    Create the files required by the above `setup.py` - the SWIG `.i` input\n    file, the README file, and copies of `pipcl.py` and `wdev.py`.\n\n        >>> with open('pipcl_test/foo.i', 'w') as f:\n        ...     _ = f.write(textwrap.dedent(\"\"\"\n        ...             %include bar.i\n        ...             %{\n        ...             #include <stdio.h>\n        ...             #include <string.h>\n        ...             int bar(const char* text)\n        ...             {\n        ...                 printf(\"bar(): text: %s\\\\\\\\n\", text);\n        ...                 int len = (int) strlen(text);\n        ...                 printf(\"bar(): len=%i\\\\\\\\n\", len);\n        ...                 fflush(stdout);\n        ...                 return len;\n        ...             }\n        ...             %}\n        ...             int bar(const char* text);\n        ...             \"\"\"))\n\n        >>> with open('pipcl_test/bar.i', 'w') as f:\n        ...     _ = f.write( '\\\\n')\n\n        >>> with open('pipcl_test/wibble.c', 'w') as f:\n        ...     _ = f.write( '\\\\n')\n\n        >>> with open('pipcl_test/pyproject.toml', 'w') as f:\n        ...     pass\n\n        >>> with open('pipcl_test/README', 'w') as f:\n        ...     _ = f.write(textwrap.dedent(\"\"\"\n        ...             This is Foo.\n        ...             \"\"\"))\n\n        >>> with open('pipcl_test/cli.py', 'w') as f:\n        ...     _ = f.write(textwrap.dedent(\"\"\"\n        ...             def main():\n        ...                 print('pipcl_test:main().')\n        ...             if __name__ == '__main__':\n        ...                 main()\n        ...             \"\"\"))\n\n        >>> root = os.path.dirname(__file__)\n        >>> _ = shutil.copy2(f'{root}/pipcl.py', 'pipcl_test/pipcl.py')\n        >>> _ = shutil.copy2(f'{root}/wdev.py', 'pipcl_test/wdev.py')\n\n    Use `setup.py`'s command-line interface to build and install the extension\n    module into root `pipcl_test/install`.\n\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} setup.py --root install install',\n        ...         shell=1, check=1)\n\n    The actual install directory depends on `sysconfig.get_path('platlib')`:\n\n        >>> if windows():\n        ...     install_dir = 'pipcl_test/install'\n        ... else:\n        ...     install_dir = f'pipcl_test/install/{sysconfig.get_path(\"platlib\").lstrip(os.sep)}'\n        >>> assert os.path.isfile( f'{install_dir}/foo/__init__.py')\n\n    Create a test script which asserts that Python function call `foo.bar(s)`\n    returns the length of `s`, and run it with `PYTHONPATH` set to the install\n    directory:\n\n        >>> with open('pipcl_test/test.py', 'w') as f:\n        ...     _ = f.write(textwrap.dedent(\"\"\"\n        ...             import sys\n        ...             import foo\n        ...             text = 'hello'\n        ...             print(f'test.py: calling foo.bar() with text={text!r}')\n        ...             sys.stdout.flush()\n        ...             l = foo.bar(text)\n        ...             print(f'test.py: foo.bar() returned: {l}')\n        ...             assert l == len(text)\n        ...             \"\"\"))\n        >>> r = subprocess.run(\n        ...         f'{sys.executable} pipcl_test/test.py',\n        ...         shell=1, check=1, text=1,\n        ...         stdout=subprocess.PIPE, stderr=subprocess.STDOUT,\n        ...         env=os.environ | dict(PYTHONPATH=install_dir),\n        ...         )\n        >>> print(r.stdout)\n        test.py: calling foo.bar() with text='hello'\n        bar(): text: hello\n        bar(): len=5\n        test.py: foo.bar() returned: 5\n        <BLANKLINE>\n\n    Check that building sdist and wheel succeeds. For now we don't attempt to\n    check that the sdist and wheel actually work.\n\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} setup.py sdist',\n        ...         shell=1, check=1)\n\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',\n        ...         shell=1, check=1)\n\n    Check that rebuild does nothing.\n\n        >>> t0 = os.path.getmtime('pipcl_test/build/foo.py')\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',\n        ...         shell=1, check=1)\n        >>> t = os.path.getmtime('pipcl_test/build/foo.py')\n        >>> assert t == t0\n\n    Check that touching bar.i forces rebuild.\n\n        >>> os.utime('pipcl_test/bar.i')\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',\n        ...         shell=1, check=1)\n        >>> t = os.path.getmtime('pipcl_test/build/foo.py')\n        >>> assert t > t0\n\n    Check that touching foo.i.cpp does not run swig, but does recompile/link.\n\n        >>> t0 = time.time()\n        >>> os.utime('pipcl_test/build/foo.i.cpp')\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',\n        ...         shell=1, check=1)\n        >>> assert os.path.getmtime('pipcl_test/build/foo.py') <= t0\n        >>> so = glob.glob('pipcl_test/build/*.so')\n        >>> assert len(so) == 1\n        >>> so = so[0]\n        >>> assert os.path.getmtime(so) > t0\n\n    Check that touching wibble.c does not run swig, but does recompile/link.\n\n        >>> t0 = time.time()\n        >>> os.utime('pipcl_test/wibble.c')\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} setup.py bdist_wheel',\n        ...         shell=1, check=1)\n        >>> assert os.path.getmtime('pipcl_test/build/foo.py') <= t0\n        >>> so = glob.glob('pipcl_test/build/*.so')\n        >>> assert len(so) == 1\n        >>> so = so[0]\n        >>> assert os.path.getmtime(so) > t0\n\n    Check `entry_points` causes creation of command `foo_cli` when we install\n    from our wheel using pip. [As of 2024-02-24 using pipcl's CLI interface\n    directly with `setup.py install` does not support entry points.]\n\n        >>> print('Creating venv.', file=sys.stderr)\n        >>> _ = subprocess.run(\n        ...         f'cd pipcl_test && {sys.executable} -m venv pylocal',\n        ...         shell=1, check=1)\n\n        >>> print('Installing from wheel into venv using pip.', file=sys.stderr)\n        >>> _ = subprocess.run(\n        ...         f'. pipcl_test/pylocal/bin/activate && pip install pipcl_test/dist/*.whl',\n        ...         shell=1, check=1)\n\n        >>> print('Running foo_cli.', file=sys.stderr)\n        >>> _ = subprocess.run(\n        ...         f'. pipcl_test/pylocal/bin/activate && foo_cli',\n        ...         shell=1, check=1)\n\n    Wheels and sdists\n\n        Wheels:\n            We generate wheels according to:\n            https://packaging.python.org/specifications/binary-distribution-format/\n\n            * `{name}-{version}.dist-info/RECORD` uses sha256 hashes.\n            * We do not generate other `RECORD*` files such as\n              `RECORD.jws` or `RECORD.p7s`.\n            * `{name}-{version}.dist-info/WHEEL` has:\n\n              * `Wheel-Version: 1.0`\n              * `Root-Is-Purelib: false`\n            * No support for signed wheels.\n\n        Sdists:\n            We generate sdist's according to:\n            https://packaging.python.org/specifications/source-distribution-format/\n    '''\n    def __init__(self,\n            name,\n            version,\n            *,\n            platform = None,\n            supported_platform = None,\n            summary = None,\n            description = None,\n            description_content_type = None,\n            keywords = None,\n            home_page = None,\n            download_url = None,\n            author = None,\n            author_email = None,\n            maintainer = None,\n            maintainer_email = None,\n            license = None,\n            classifier = None,\n            requires_dist = None,\n            requires_python = None,\n            requires_external = None,\n            project_url = None,\n            provides_extra = None,\n\n            entry_points = None,\n\n            root = None,\n            fn_build = None,\n            fn_clean = None,\n            fn_sdist = None,\n            tag_python = None,\n            tag_abi = None,\n            tag_platform = None,\n            py_limited_api = None,\n\n            wheel_compression = zipfile.ZIP_DEFLATED,\n            wheel_compresslevel = None,\n            ):\n        '''\n        The initial args before `entry_points` define the\n        package metadata and closely follow the definitions in:\n        https://packaging.python.org/specifications/core-metadata/\n\n        Args:\n\n            name:\n                Used for metadata `Name`.\n                A string, the name of the Python package.\n            version:\n                Used for metadata `Version`.\n                A string, the version of the Python package. Also see PEP-440\n                `Version Identification and Dependency Specification`.\n            platform:\n                Used for metadata `Platform`.\n                A string or list of strings.\n            supported_platform:\n                Used for metadata `Supported-Platform`.\n                A string or list of strings.\n            summary:\n                Used for metadata `Summary`.\n                A string, short description of the package.\n            description:\n                Used for metadata `Description`.\n                A string. If contains newlines, a detailed description of the\n                package. Otherwise the path of a file containing the detailed\n                description of the package.\n            description_content_type:\n                Used for metadata `Description-Content-Type`.\n                A string describing markup of `description` arg. For example\n                `text/markdown; variant=GFM`.\n            keywords:\n                Used for metadata `Keywords`.\n                A string containing comma-separated keywords.\n            home_page:\n                Used for metadata `Home-page`.\n                URL of home page.\n            download_url:\n                Used for metadata `Download-URL`.\n                Where this version can be downloaded from.\n            author:\n                Used for metadata `Author`.\n                Author.\n            author_email:\n                Used for metadata `Author-email`.\n                Author email.\n            maintainer:\n                Used for metadata `Maintainer`.\n                Maintainer.\n            maintainer_email:\n                Used for metadata `Maintainer-email`.\n                Maintainer email.\n            license:\n                Used for metadata `License`.\n                A string containing the license text. Written into metadata\n                file `COPYING`. Is also written into metadata itself if not\n                multi-line.\n            classifier:\n                Used for metadata `Classifier`.\n                A string or list of strings. Also see:\n\n                * https://pypi.org/pypi?%3Aaction=list_classifiers\n                * https://pypi.org/classifiers/\n\n            requires_dist:\n                Used for metadata `Requires-Dist`.\n                A string or list of strings, Python packages required\n                at runtime. None items are ignored.\n            requires_python:\n                Used for metadata `Requires-Python`.\n                A string or list of strings.\n            requires_external:\n                Used for metadata `Requires-External`.\n                A string or list of strings.\n            project_url:\n                Used for metadata `Project-URL`.\n                A string or list of strings, each of the form: `{name},\n                {url}`.\n            provides_extra:\n                Used for metadata `Provides-Extra`.\n                A string or list of strings.\n\n            entry_points:\n                String or dict specifying *.dist-info/entry_points.txt, for\n                example:\n\n                    ```\n                    [console_scripts]\n                    foo_cli = foo.__main__:main\n                    ```\n\n                or:\n\n                    { 'console_scripts': [\n                        'foo_cli = foo.__main__:main',\n                        ],\n                    }\n\n                See: https://packaging.python.org/en/latest/specifications/entry-points/\n\n            root:\n                Root of package, defaults to current directory.\n\n            fn_build:\n                A function taking no args, or a single `config_settings` dict\n                arg (as described in PEP-517), that builds the package.\n\n                Should return a list of items; each item should be a tuple\n                `(from_, to_)`, or a single string `path` which is treated as\n                the tuple `(path, path)`.\n\n                `from_` can be a string or a `bytes`. If a string it should\n                be the path to a file; a relative path is treated as relative\n                to `root`. If a `bytes` it is the contents of the file to be\n                added.\n\n                `to_` identifies what the file should be called within a wheel\n                or when installing. If `to_` is empty or `/` we set it to the\n                leaf of `from_` (`from_` must not be a `bytes`) - i.e. we place\n                the file in the root directory of the wheel; otherwise if\n                `to_` ends with `/` the leaf of `from_` is appended to it (and\n                `from_` must not be a `bytes`).\n\n                Initial `$dist-info/` in `_to` is replaced by\n                `{name}-{version}.dist-info/`; this is useful for license files\n                etc.\n\n                Initial `$data/` in `_to` is replaced by\n                `{name}-{version}.data/`. We do not enforce particular\n                subdirectories, instead it is up to `fn_build()` to specify\n                specific subdirectories such as `purelib`, `headers`,\n                `scripts`, `data` etc.\n\n                If we are building a wheel (e.g. `python setup.py bdist_wheel`,\n                or PEP-517 pip calls `self.build_wheel()`), we add file `from_`\n                to the wheel archive with name `to_`.\n\n                If we are installing (e.g. `install` command in\n                the argv passed to `self.handle_argv()`), then\n                we copy `from_` to `{sitepackages}/{to_}`, where\n                `sitepackages` is the installation directory, the\n                default being `sysconfig.get_path('platlib')` e.g.\n                `myvenv/lib/python3.9/site-packages/`.\n\n                When calling this function, we assert that the file\n                pyproject.toml exists in the current directory. (We do this\n                here rather than in pipcl.Package's constructor, as otherwise\n                importing setup.py from non-package-related code could fail.)\n\n            fn_clean:\n                A function taking a single arg `all_` that cleans generated\n                files. `all_` is true iff `--all` is in argv.\n\n                For safety and convenience, can also returns a list of\n                files/directory paths to be deleted. Relative paths are\n                interpreted as relative to `root`. All paths are asserted to be\n                within `root`.\n\n            fn_sdist:\n                A function taking no args, or a single `config_settings` dict\n                arg (as described in PEP517), that returns a list of items to\n                be copied into the sdist. The list should be in the same format\n                as returned by `fn_build`.\n\n                It can be convenient to use `pipcl.git_items()`.\n\n                The specification for sdists requires that the list contains\n                `pyproject.toml`; we enforce this with a Python assert.\n\n            tag_python:\n                First element of wheel tag defined in PEP-425. If None we use\n                `cp{version}`.\n\n                For example if code works with any Python version, one can use\n                'py3'.\n\n            tag_abi:\n                Second element of wheel tag defined in PEP-425. If None we use\n                `none`.\n\n            tag_platform:\n                Third element of wheel tag defined in PEP-425. Default\n                is `os.environ('AUDITWHEEL_PLAT')` if set, otherwise\n                derived from `sysconfig.get_platform()` (was\n                `setuptools.distutils.util.get_platform(), before that\n                `distutils.util.get_platform()` as specified in the PEP), e.g.\n                `openbsd_7_0_amd64`.\n\n                For pure python packages use: `tag_platform=any`\n\n            py_limited_api:\n                If true we build wheels that use the Python Limited API. We use\n                the version of `sys.executable` to define `Py_LIMITED_API` when\n                compiling extensions, and use ABI tag `abi3` in the wheel name\n                if argument `tag_abi` is None.\n\n            wheel_compression:\n                Used as `zipfile.ZipFile()`'s `compression` parameter when\n                creating wheels.\n\n            wheel_compresslevel:\n                Used as `zipfile.ZipFile()`'s `compresslevel` parameter when\n                creating wheels.\n\n        Occurrences of `None` in lists are ignored.\n        '''\n        assert name\n        assert version\n\n        def assert_str( v):\n            if v is not None:\n                assert isinstance( v, str), f'Not a string: {v!r}'\n        def assert_str_or_multi( v):\n            if v is not None:\n                assert isinstance( v, (str, tuple, list)), f'Not a string, tuple or list: {v!r}'\n\n        assert_str( name)\n        assert_str( version)\n        assert_str_or_multi( platform)\n        assert_str_or_multi( supported_platform)\n        assert_str( summary)\n        assert_str( description)\n        assert_str( description_content_type)\n        assert_str( keywords)\n        assert_str( home_page)\n        assert_str( download_url)\n        assert_str( author)\n        assert_str( author_email)\n        assert_str( maintainer)\n        assert_str( maintainer_email)\n        assert_str( license)\n        assert_str_or_multi( classifier)\n        assert_str_or_multi( requires_dist)\n        assert_str( requires_python)\n        assert_str_or_multi( requires_external)\n        assert_str_or_multi( project_url)\n        assert_str_or_multi( provides_extra)\n        \n        assert re.match('^([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])\\\\Z', name, re.IGNORECASE), (\n                f'Invalid package name'\n                f' (https://packaging.python.org/en/latest/specifications/name-normalization/)'\n                f': {name!r}'\n                )\n\n        # https://packaging.python.org/en/latest/specifications/core-metadata/.\n        assert re.match('([A-Z0-9]|[A-Z0-9][A-Z0-9._-]*[A-Z0-9])$', name, re.IGNORECASE), \\\n                f'Bad name: {name!r}'\n\n        _assert_version_pep_440(version)\n\n        # https://packaging.python.org/en/latest/specifications/binary-distribution-format/\n        if tag_python:\n            assert '-' not in tag_python\n        if tag_abi:\n            assert '-' not in tag_abi\n        if tag_platform:\n            assert '-' not in tag_platform\n\n        self.name = name\n        self.version = version\n        self.platform = platform\n        self.supported_platform = supported_platform\n        self.summary = summary\n        self.description = description\n        self.description_content_type = description_content_type\n        self.keywords = keywords\n        self.home_page = home_page\n        self.download_url = download_url\n        self.author = author\n        self.author_email  = author_email\n        self.maintainer = maintainer\n        self.maintainer_email = maintainer_email\n        self.license = license\n        self.classifier = classifier\n        self.requires_dist = requires_dist\n        self.requires_python = requires_python\n        self.requires_external = requires_external\n        self.project_url = project_url\n        self.provides_extra = provides_extra\n        self.entry_points = entry_points\n\n        self.root = os.path.abspath(root if root else os.getcwd())\n        self.fn_build = fn_build\n        self.fn_clean = fn_clean\n        self.fn_sdist = fn_sdist\n        self.tag_python_ = tag_python\n        self.tag_abi_ = tag_abi\n        self.tag_platform_ = tag_platform\n        self.py_limited_api = py_limited_api\n\n        self.wheel_compression = wheel_compression\n        self.wheel_compresslevel = wheel_compresslevel\n        \n        # If true and we are building for graal, we set PIPCL_PYTHON_CONFIG to\n        # a command that will print includes/libs from graal_py's sysconfig.\n        #\n        self.graal_legacy_python_config = True\n\n\n    def build_wheel(self,\n            wheel_directory,\n            config_settings=None,\n            metadata_directory=None,\n            ):\n        '''\n        A PEP-517 `build_wheel()` function.\n\n        Also called by `handle_argv()` to handle the `bdist_wheel` command.\n\n        Returns leafname of generated wheel within `wheel_directory`.\n        '''\n        log2(\n                f' wheel_directory={wheel_directory!r}'\n                f' config_settings={config_settings!r}'\n                f' metadata_directory={metadata_directory!r}'\n                )\n\n        if os.environ.get('CIBUILDWHEEL') == '1':\n            # Don't special-case graal builds when running under cibuildwheel.\n            pass\n        elif sys.implementation.name == 'graalpy':\n            # We build for Graal by building a native Python wheel with Graal\n            # Python's include paths and library directory. We then rename the\n            # wheel to contain graal's tag etc.\n            #\n            log0(f'### Graal build: deferring to cpython.')\n            python_native = os.environ.get('PIPCL_GRAAL_PYTHON')\n            assert python_native, f'Graal build requires that PIPCL_GRAAL_PYTHON is set.'\n            env_extra = dict(\n                    PIPCL_SYSCONFIG_PATH_include = sysconfig.get_path('include'),\n                    PIPCL_SYSCONFIG_PATH_platinclude = sysconfig.get_path('platinclude'),\n                    PIPCL_SYSCONFIG_CONFIG_VAR_LIBDIR = sysconfig.get_config_var('LIBDIR'),\n                    )\n            # Tell native build to run pipcl.py itself to get python-config\n            # information about include paths etc.\n            if self.graal_legacy_python_config:\n                env_extra['PIPCL_PYTHON_CONFIG'] = f'{python_native} {os.path.abspath(__file__)} --graal-legacy-python-config'\n            \n            # Create venv.\n            venv_name = os.environ.get('PIPCL_GRAAL_NATIVE_VENV')\n            if venv_name:\n                log1(f'Graal using pre-existing {venv_name=}')\n            else:\n                venv_name = 'venv-pipcl-graal-native'\n                run(f'{shlex.quote(python_native)} -m venv {venv_name}')\n                log1(f'Graal using {venv_name=}')\n            \n            newfiles = NewFiles(f'{wheel_directory}/*.whl')\n            run(\n                    f'. {venv_name}/bin/activate && python setup.py --dist-dir {shlex.quote(wheel_directory)} bdist_wheel',\n                    env_extra = env_extra,\n                    prefix = f'pipcl.py graal {python_native}: ',\n                    )\n            wheel = newfiles.get_one()\n            wheel_leaf = os.path.basename(wheel)\n            python_major_minor = run(f'{shlex.quote(python_native)} -c \"import platform; import sys; sys.stdout.write(str().join(platform.python_version_tuple()[:2]))\"', capture=1)\n            cpabi = f'cp{python_major_minor}-abi3'\n            assert cpabi in wheel_leaf, f'Expected wheel to be for {cpabi=}, but {wheel=}.'\n            graalpy_ext_suffix = sysconfig.get_config_var('EXT_SUFFIX')\n            log1(f'{graalpy_ext_suffix=}')\n            m = re.match(r'\\.graalpy(\\d+[^\\-]*)-(\\d+)', graalpy_ext_suffix)\n            gpver = m[1]\n            cpver = m[2]\n            graalpy_wheel_tag = f'graalpy{cpver}-graalpy{gpver}_{cpver}_native'\n            name = wheel_leaf.replace(cpabi, graalpy_wheel_tag)\n            destination = f'{wheel_directory}/{name}'\n            log0(f'### Graal build: copying {wheel=} to {destination=}')\n            # Copying results in two wheels which appears to confuse pip, showing:\n            #   Found multiple .whl files; unspecified behaviour. Will call build_wheel.\n            os.rename(wheel, destination)\n            log1(f'Returning {name=}.')\n            return name\n\n        wheel_name = self.wheel_name()\n        path = f'{wheel_directory}/{wheel_name}'\n\n        # Do a build and get list of files to copy into the wheel.\n        #\n        items = list()\n        if self.fn_build:\n            items = self._call_fn_build(config_settings)\n\n        log2(f'Creating wheel: {path}')\n        os.makedirs(wheel_directory, exist_ok=True)\n        record = _Record()\n        with zipfile.ZipFile(path, 'w', self.wheel_compression, self.wheel_compresslevel) as z:\n\n            def add(from_, to_):\n                if isinstance(from_, str):\n                    z.write(from_, to_)\n                    record.add_file(from_, to_)\n                elif isinstance(from_, bytes):\n                    z.writestr(to_, from_)\n                    record.add_content(from_, to_)\n                else:\n                    assert 0\n\n            def add_str(content, to_):\n                add(content.encode('utf8'), to_)\n\n            dist_info_dir = self._dist_info_dir()\n\n            # Add the files returned by fn_build().\n            #\n            for item in items:\n                from_, (to_abs, to_rel) = self._fromto(item)\n                add(from_, to_rel)\n\n            # Add <name>-<version>.dist-info/WHEEL.\n            #\n            add_str(\n                    f'Wheel-Version: 1.0\\n'\n                    f'Generator: pipcl\\n'\n                    f'Root-Is-Purelib: false\\n'\n                    f'Tag: {self.wheel_tag_string()}\\n'\n                    ,\n                    f'{dist_info_dir}/WHEEL',\n                    )\n            # Add <name>-<version>.dist-info/METADATA.\n            #\n            add_str(self._metainfo(), f'{dist_info_dir}/METADATA')\n\n            # Add <name>-<version>.dist-info/COPYING.\n            if self.license:\n                add_str(self.license, f'{dist_info_dir}/COPYING')\n\n            # Add <name>-<version>.dist-info/entry_points.txt.\n            entry_points_text = self._entry_points_text()\n            if entry_points_text:\n                add_str(entry_points_text, f'{dist_info_dir}/entry_points.txt')\n\n            # Update <name>-<version>.dist-info/RECORD. This must be last.\n            #\n            z.writestr(f'{dist_info_dir}/RECORD', record.get(f'{dist_info_dir}/RECORD'))\n\n        st = os.stat(path)\n        log1( f'Have created wheel size={st.st_size:,}: {path}')\n        if g_verbose >= 2:\n            with zipfile.ZipFile(path, compression=self.wheel_compression) as z:\n                log2(f'Contents are:')\n                for zi in sorted(z.infolist(), key=lambda z: z.filename):\n                    log2(f'    {zi.file_size: 10,d} {zi.filename}')\n\n        return os.path.basename(path)\n\n\n    def build_sdist(self,\n            sdist_directory,\n            formats,\n            config_settings=None,\n            ):\n        '''\n        A PEP-517 `build_sdist()` function.\n\n        Also called by `handle_argv()` to handle the `sdist` command.\n\n        Returns leafname of generated archive within `sdist_directory`.\n        '''\n        assert self.fn_sdist, f'fn_sdist() not provided.'\n        log2(\n                f' sdist_directory={sdist_directory!r}'\n                f' formats={formats!r}'\n                f' config_settings={config_settings!r}'\n                )\n        if formats and formats != 'gztar':\n            raise Exception( f'Unsupported: formats={formats}')\n        items = list()\n        if inspect.signature(self.fn_sdist).parameters:\n            items = self.fn_sdist(config_settings)\n        else:\n            items = self.fn_sdist()\n\n        prefix = f'{_normalise2(self.name)}-{self.version}'\n        os.makedirs(sdist_directory, exist_ok=True)\n        tarpath = f'{sdist_directory}/{prefix}.tar.gz'\n        log2(f'Creating sdist: {tarpath}')\n\n        with tarfile.open(tarpath, 'w:gz') as tar:\n\n            names_in_tar = list()\n            def check_name(name):\n                if name in names_in_tar:\n                    raise Exception(f'Name specified twice: {name}')\n                names_in_tar.append(name)\n\n            def add(from_, name):\n                check_name(name)\n                if isinstance(from_, str):\n                    log2( f'Adding file: {os.path.relpath(from_)} => {name}')\n                    tar.add( from_, f'{prefix}/{name}', recursive=False)\n                elif isinstance(from_, bytes):\n                    log2( f'Adding: {name}')\n                    ti = tarfile.TarInfo(f'{prefix}/{name}')\n                    ti.size = len(from_)\n                    ti.mtime = time.time()\n                    tar.addfile(ti, io.BytesIO(from_))\n                else:\n                    assert 0\n\n            def add_string(text, name):\n                textb = text.encode('utf8')\n                return add(textb, name)\n\n            found_pyproject_toml = False\n            for item in items:\n                from_, (to_abs, to_rel) = self._fromto(item)\n                if isinstance(from_, bytes):\n                    add(from_, to_rel)\n                else:\n                    if from_.startswith(f'{os.path.abspath(sdist_directory)}/'):\n                        # Source files should not be inside <sdist_directory>.\n                        assert 0, f'Path is inside sdist_directory={sdist_directory}: {from_!r}'\n                    assert os.path.exists(from_), f'Path does not exist: {from_!r}'\n                    assert os.path.isfile(from_), f'Path is not a file: {from_!r}'\n                    add(from_, to_rel)\n                if to_rel == 'pyproject.toml':\n                    found_pyproject_toml = True\n\n            assert found_pyproject_toml, f'Cannot create sdist because file not specified: pyproject.toml'\n\n            # Always add a PKG-INFO file.\n            add_string(self._metainfo(), 'PKG-INFO')\n\n            if self.license:\n                if 'COPYING' in names_in_tar:\n                    log2(f'Not writing .license because file already in sdist: COPYING')\n                else:\n                    add_string(self.license, 'COPYING')\n\n        log1( f'Have created sdist: {tarpath}')\n        return os.path.basename(tarpath)\n\n    def wheel_tag_string(self):\n        '''\n        Returns <tag_python>-<tag_abi>-<tag_platform>.\n        '''\n        return f'{self.tag_python()}-{self.tag_abi()}-{self.tag_platform()}'\n\n    def tag_python(self):\n        '''\n        Get two-digit python version, e.g. 'cp3.8' for python-3.8.6.\n        '''\n        if self.tag_python_:\n            ret = self.tag_python_\n        else:\n            ret = 'cp' + ''.join(platform.python_version().split('.')[:2])\n        assert '-' not in ret\n        return ret\n\n    def tag_abi(self):\n        '''\n        ABI tag.\n        '''\n        Py_GIL_DISABLED = sysconfig.get_config_var('Py_GIL_DISABLED')\n        if self.tag_abi_:\n            return self.tag_abi_\n        elif self.py_limited_api:\n            assert Py_GIL_DISABLED != 1, \\\n                    f'py_limited_api and Py_GIL_DISABLED are not supported together as of 2026-02-20, e.g. see PEP 803 and PEP 809.'\n            return 'abi3'\n        elif Py_GIL_DISABLED == 1:\n            ret = ''\n            ret += 'cp'\n            ret += ''.join(platform.python_version().split('.')[:2])\n            ret += 't'\n            return ret\n        else:\n            return 'none'\n\n    def tag_platform(self):\n        '''\n        Find platform tag used in wheel filename.\n        '''\n        ret = self.tag_platform_\n        log0(f'From self.tag_platform_: {ret=}.')\n        \n        if not ret:\n            # Prefer this to PEP-425. Appears to be undocumented,\n            # but set in manylinux docker images and appears\n            # to be used by cibuildwheel and auditwheel, e.g.\n            # https://github.com/rapidsai/shared-action-workflows/issues/80\n            ret = os.environ.get( 'AUDITWHEEL_PLAT')\n            log0(f'From AUDITWHEEL_PLAT: {ret=}.')\n\n        if not ret:\n            # Notes:\n            #\n            # PEP-425. On Linux gives `linux_x86_64` which is rejected by\n            # pypi.org.\n            #\n            # On local MacOS/arm64 mac-mini have seen sysconfig.get_platform()\n            # unhelpfully return `macosx-10.9-universal2` if `python3` is the\n            # system Python /usr/bin/python3; this happens if we source `.\n            # /etc/profile`.\n            #\n            ret = sysconfig.get_platform()\n            ret = ret.replace('-', '_').replace('.', '_').lower()\n            log0(f'From sysconfig.get_platform(): {ret=}.')\n\n            ret = _macos_fixup_platform_tag(ret)\n\n        log0( f'tag_platform(): returning {ret=}.')\n        assert '-' not in ret\n        return ret\n\n    def wheel_name(self):\n        ret = f'{_normalise2(self.name)}-{self.version}-{self.tag_python()}-{self.tag_abi()}-{self.tag_platform()}.whl'\n        assert ret.count('-') == 4, f'Expected 4 dash characters in {ret=}.'\n        return ret\n\n    def wheel_name_match(self, wheel):\n        '''\n        Returns true if `wheel` matches our wheel. We basically require the\n        name to be the same, except that we accept platform tags that contain\n        extra items (see pep-0600/), for example we return true with:\n\n            self:   foo-cp38-none-manylinux2014_x86_64.whl\n            wheel:  foo-cp38-none-manylinux2014_x86_64.manylinux_2_17_x86_64.whl\n        '''\n        log2(f'{wheel=}')\n        assert wheel.endswith('.whl')\n        wheel2 = wheel[:-len('.whl')]\n        name, version, tag_python, tag_abi, tag_platform = wheel2.split('-')\n        \n        py_limited_api_compatible = False\n        if self.py_limited_api and tag_abi == 'abi3':\n            # Allow lower tag_python number.\n            m = re.match('cp([0-9]+)', tag_python)\n            tag_python_int = int(m.group(1))\n            m = re.match('cp([0-9]+)', self.tag_python())\n            tag_python_int_self = int(m.group(1))\n            if tag_python_int <= tag_python_int_self:\n                # This wheel uses Python stable ABI same or older than ours, so\n                # we can use it.\n                log2(f'py_limited_api; {tag_python=} compatible with {self.tag_python()=}.')\n                py_limited_api_compatible = True\n            \n        log2(f'{_normalise2(self.name) == name=}')\n        log2(f'{self.version == version=}')\n        log2(f'{self.tag_python() == tag_python=} {self.tag_python()=} {tag_python=}')\n        log2(f'{py_limited_api_compatible=}')\n        log2(f'{self.tag_abi() == tag_abi=}')\n        log2(f'{self.tag_platform() in tag_platform.split(\".\")=}')\n        log2(f'{self.tag_platform()=}')\n        log2(f'{tag_platform.split(\".\")=}')\n        ret = (1\n                and _normalise2(self.name) == name\n                and self.version == version\n                and (self.tag_python() == tag_python or py_limited_api_compatible)\n                and self.tag_abi() == tag_abi\n                and self.tag_platform() in tag_platform.split('.')\n                )\n        log2(f'Returning {ret=}.')\n        return ret\n    \n    def _entry_points_text(self):\n        if self.entry_points:\n            if isinstance(self.entry_points, str):\n                return self.entry_points\n            ret = ''\n            for key, values in self.entry_points.items():\n                ret += f'[{key}]\\n'\n                for value in values:\n                    ret += f'{value}\\n'\n            return ret\n\n    def _call_fn_build( self, config_settings=None):\n        assert self.fn_build\n        assert os.path.isfile('pyproject.toml'), (\n                'Cannot create package because file does not exist: pyproject.toml'\n                )\n        log2(f'calling self.fn_build={self.fn_build}')\n        if inspect.signature(self.fn_build).parameters:\n            ret = self.fn_build(config_settings)\n        else:\n            ret = self.fn_build()\n        assert isinstance( ret, (list, tuple)), \\\n                f'Expected list/tuple from {self.fn_build} but got: {ret!r}'\n\n        # Check that any extensions that we have built, have same\n        # py_limited_api value. If package is marked with py_limited_api=True\n        # then non-py_limited_api extensions seem to fail at runtime on\n        # Windows.\n        #\n        # (We could possibly allow package py_limited_api=False and extensions\n        # py_limited_api=True, but haven't tested this, and it seems simpler to\n        # be strict.)\n        for item in ret:\n            from_, (to_abs, to_rel) = self._fromto(item)\n            from_abs = os.path.abspath(from_)\n            is_py_limited_api = _extensions_to_py_limited_api.get(from_abs)\n            if is_py_limited_api is not None:\n                assert bool(self.py_limited_api) == bool(is_py_limited_api), (\n                        f'Extension was built with'\n                        f' py_limited_api={is_py_limited_api} but pipcl.Package'\n                        f' name={self.name!r} has'\n                        f' py_limited_api={self.py_limited_api}:'\n                        f' {from_abs!r}'\n                        )\n        \n        return ret\n\n\n    def _argv_clean(self, all_):\n        '''\n        Called by `handle_argv()`.\n        '''\n        if not self.fn_clean:\n            return\n        paths = self.fn_clean(all_)\n        if paths:\n            if isinstance(paths, str):\n                paths = paths,\n            for path in paths:\n                if not os.path.isabs(path):\n                    path = ps.path.join(self.root, path)\n                path = os.path.abspath(path)\n                assert path.startswith(self.root+os.sep), \\\n                        f'path={path!r} does not start with root={self.root+os.sep!r}'\n                log(f'Removing: {path}')\n                shutil.rmtree(path, ignore_errors=True)\n\n\n    def install(self, record_path=None, root=None):\n        '''\n        Called by `handle_argv()` to handle `install` command..\n        '''\n        log2( f'{record_path=} {root=}')\n\n        # Do a build and get list of files to install.\n        #\n        items = list()\n        if self.fn_build:\n            items = self._call_fn_build( dict())\n\n        root2 = install_dir(root)\n        log2( f'{root2=}')\n\n        log1( f'Installing into: {root2!r}')\n        dist_info_dir = self._dist_info_dir()\n\n        if not record_path:\n            record_path = f'{root2}/{dist_info_dir}/RECORD'\n        record = _Record()\n\n        def add_file(from_, to_abs, to_rel):\n            os.makedirs( os.path.dirname( to_abs), exist_ok=True)\n            if isinstance(from_, bytes):\n                log2(f'Copying content into {to_abs}.')\n                with open(to_abs, 'wb') as f:\n                    f.write(from_)\n                record.add_content(from_, to_rel)\n            else:\n                log0(f'{from_=}')\n                log2(f'Copying from {os.path.relpath(from_, self.root)} to {to_abs}')\n                shutil.copy2( from_, to_abs)\n                record.add_file(from_, to_rel)\n\n        def add_str(content, to_abs, to_rel):\n            log2( f'Writing to: {to_abs}')\n            os.makedirs( os.path.dirname( to_abs), exist_ok=True)\n            with open( to_abs, 'w') as f:\n                f.write( content)\n            record.add_content(content, to_rel)\n\n        for item in items:\n            from_, (to_abs, to_rel) = self._fromto(item)\n            log0(f'{from_=} {to_abs=} {to_rel=}')\n            to_abs2 = f'{root2}/{to_rel}'\n            add_file( from_, to_abs2, to_rel)\n\n        add_str( self._metainfo(), f'{root2}/{dist_info_dir}/METADATA', f'{dist_info_dir}/METADATA')\n\n        if self.license:\n            add_str( self.license, f'{root2}/{dist_info_dir}/COPYING', f'{dist_info_dir}/COPYING')\n\n        entry_points_text = self._entry_points_text()\n        if entry_points_text:\n            add_str(\n                    entry_points_text,\n                    f'{root2}/{dist_info_dir}/entry_points.txt',\n                    f'{dist_info_dir}/entry_points.txt',\n                    )\n\n        log2( f'Writing to: {record_path}')\n        with open(record_path, 'w') as f:\n            f.write(record.get())\n\n        log2(f'Finished.')\n\n\n    def _argv_dist_info(self, root):\n        '''\n        Called by `handle_argv()`. There doesn't seem to be any documentation\n        for `setup.py dist_info`, but it appears to be like `egg_info` except\n        it writes to a slightly different directory.\n        '''\n        if root is None:\n            root = f'{normalise2(self.name)}-{self.version}.dist-info'\n        self._write_info(f'{root}/METADATA')\n        if self.license:\n            with open( f'{root}/COPYING', 'w') as f:\n                f.write( self.license)\n\n\n    def _argv_egg_info(self, egg_base):\n        '''\n        Called by `handle_argv()`.\n        '''\n        if egg_base is None:\n            egg_base = '.'\n        self._write_info(f'{egg_base}/.egg-info')\n\n\n    def _write_info(self, dirpath=None):\n        '''\n        Writes egg/dist info to files in directory `dirpath` or `self.root` if\n        `None`.\n        '''\n        if dirpath is None:\n            dirpath = self.root\n        log2(f'Creating files in directory {dirpath}')\n        os.makedirs(dirpath, exist_ok=True)\n        with open(os.path.join(dirpath, 'PKG-INFO'), 'w') as f:\n            f.write(self._metainfo())\n\n        # These don't seem to be required?\n        #\n        #with open(os.path.join(dirpath, 'SOURCES.txt', 'w') as f:\n        #    pass\n        #with open(os.path.join(dirpath, 'dependency_links.txt', 'w') as f:\n        #    pass\n        #with open(os.path.join(dirpath, 'top_level.txt', 'w') as f:\n        #    f.write(f'{self.name}\\n')\n        #with open(os.path.join(dirpath, 'METADATA', 'w') as f:\n        #    f.write(self._metainfo())\n\n\n    def handle_argv(self, argv):\n        '''\n        Attempt to handles old-style (pre PEP-517) command line passed by\n        old releases of pip to a `setup.py` script, and manual running of\n        `setup.py`.\n\n        This is partial support at best.\n        '''\n        global g_verbose\n        #log2(f'argv: {argv}')\n\n        class ArgsRaise:\n            pass\n\n        class Args:\n            '''\n            Iterates over argv items.\n            '''\n            def __init__( self, argv):\n                self.items = iter( argv)\n            def next( self, eof=ArgsRaise):\n                '''\n                Returns next arg. If no more args, we return <eof> or raise an\n                exception if <eof> is ArgsRaise.\n                '''\n                try:\n                    return next( self.items)\n                except StopIteration:\n                    if eof is ArgsRaise:\n                        raise Exception('Not enough args')\n                    return eof\n\n        command = None\n        opt_all = None\n        opt_dist_dir = 'dist'\n        opt_egg_base = None\n        opt_formats = None\n        opt_install_headers = None\n        opt_record = None\n        opt_root = None\n\n        args = Args(argv[1:])\n\n        while 1:\n            arg = args.next(None)\n            if arg is None:\n                break\n\n            elif arg in ('-h', '--help', '--help-commands'):\n                log0(textwrap.dedent('''\n                        Usage:\n                            [<options>...] <command> [<options>...]\n                        Commands:\n                            bdist_wheel\n                                Creates a wheel called\n                                <dist-dir>/<name>-<version>-<details>.whl, where\n                                <dist-dir> is \"dist\" or as specified by --dist-dir,\n                                and <details> encodes ABI and platform etc.\n                            clean\n                                Cleans build files.\n                            dist_info\n                                Creates files in <name>-<version>.dist-info/ or\n                                directory specified by --egg-base.\n                            egg_info\n                                Creates files in .egg-info/ or directory\n                                directory specified by --egg-base.\n                            install\n                                Builds and installs. Writes installation\n                                information to <record> if --record was\n                                specified.\n                            sdist\n                                Make a source distribution:\n                                    <dist-dir>/<name>-<version>.tar.gz\n                        Options:\n                            --all\n                                Used by \"clean\".\n                            --compile\n                                Ignored.\n                            --dist-dir | -d <dist-dir>\n                                Default is \"dist\".\n                            --egg-base <egg-base>\n                                Used by \"egg_info\".\n                            --formats <formats>\n                                Used by \"sdist\".\n                            --install-headers <directory>\n                                Ignored.\n                            --python-tag <python-tag>\n                                Ignored.\n                            --record <record>\n                                Used by \"install\".\n                            --root <path>\n                                Used by \"install\".\n                            --single-version-externally-managed\n                                Ignored.\n                            --verbose -v\n                                Extra diagnostics.\n                        Other:\n                            windows-vs [-y <year>] [-v <version>] [-g <grade] [--verbose]\n                                Windows only; looks for matching Visual Studio.\n                            windows-python [-v <version>] [--verbose]\n                                Windows only; looks for matching Python.\n                        '''))\n                return\n\n            elif arg in ('bdist_wheel', 'clean', 'dist_info', 'egg_info', 'install', 'sdist'):\n                assert command is None, 'Two commands specified: {command} and {arg}.'\n                command = arg\n\n            elif arg in ('windows-vs', 'windows-python', 'show-sysconfig'):\n                assert command is None, 'Two commands specified: {command} and {arg}.'\n                command = arg\n\n            elif arg == '--all':                                opt_all = True\n            elif arg == '--compile':                            pass\n            elif arg == '--dist-dir' or arg == '-d':            opt_dist_dir = args.next()\n            elif arg == '--egg-base':                           opt_egg_base = args.next()\n            elif arg == '--formats':                            opt_formats = args.next()\n            elif arg == '--install-headers':                    opt_install_headers = args.next()\n            elif arg == '--python-tag':                         pass\n            elif arg == '--record':                             opt_record = args.next()\n            elif arg == '--root':                               opt_root = args.next()\n            elif arg == '--single-version-externally-managed':  pass\n            elif arg == '--verbose' or arg == '-v':             g_verbose += 1\n\n            else:\n               raise Exception(f'Unrecognised arg: {arg}')\n\n        assert command, 'No command specified'\n\n        log1(f'Handling command={command}')\n        if 0:   pass\n        elif command == 'bdist_wheel':  self.build_wheel(opt_dist_dir)\n        elif command == 'clean':        self._argv_clean(opt_all)\n        elif command == 'dist_info':    self._argv_dist_info(opt_egg_base)\n        elif command == 'egg_info':     self._argv_egg_info(opt_egg_base)\n        elif command == 'install':      self.install(opt_record, opt_root)\n        elif command == 'sdist':        self.build_sdist(opt_dist_dir, opt_formats)\n\n        elif command == 'windows-python':\n            version = None\n            while 1:\n                arg = args.next(None)\n                if arg is None:\n                    break\n                elif arg == '-v':\n                    version = args.next()\n                elif arg == '--verbose':\n                    g_verbose += 1\n                else:\n                    assert 0, f'Unrecognised {arg=}'\n            python = wdev.WindowsPython(version=version)\n            print(f'Python is:\\n{python.description_ml(\"    \")}')\n\n        elif command == 'windows-vs':\n            grade = None\n            version = None\n            year = None\n            while 1:\n                arg = args.next(None)\n                if arg is None:\n                    break\n                elif arg == '-g':\n                    grade = args.next()\n                elif arg == '-v':\n                    version = args.next()\n                elif arg == '-y':\n                    year = args.next()\n                elif arg == '--verbose':\n                    g_verbose += 1\n                else:\n                    assert 0, f'Unrecognised {arg=}'\n            vs = wdev.WindowsVS(year=year, grade=grade, version=version)\n            print(f'Visual Studio is:\\n{vs.description_ml(\"    \")}')\n\n        elif command == 'show-sysconfig':\n            show_sysconfig()\n            for mod in platform, sys:\n                log0(f'{mod.__name__}:')\n                for n in dir(mod):\n                    if n.startswith('_'):\n                        continue\n                    log0(f'{mod.__name__}.{n}')\n                    if mod is platform and n == 'uname':\n                        continue\n                    if mod is platform and n == 'pdb':\n                        continue\n                    if mod is sys and n in ('breakpointhook', 'exit'):\n                        # We don't want to call these.\n                        continue\n                    v = getattr(mod, n)\n                    if callable(v):\n                        try:\n                            v = v()\n                        except Exception:\n                            pass\n                        else:\n                            #print(f'{n=}', flush=1)\n                            try:\n                                print(f'    {mod.__name__}.{n}()={v!r}')\n                            except Exception:\n                                print(f'    Failed to print value of {mod.__name__}.{n}().')\n                    else:\n                        try:\n                            print(f'    {mod.__name__}.{n}={v!r}')\n                        except Exception:\n                            print(f'    Failed to print value of {mod.__name__}.{n}.')\n        \n        else:\n            assert 0, f'Unrecognised command: {command}'\n\n        log2(f'Finished handling command: {command}')\n\n\n    def __str__(self):\n        return ('{'\n            f'name={self.name!r}'\n            f' version={self.version!r}'\n            f' platform={self.platform!r}'\n            f' supported_platform={self.supported_platform!r}'\n            f' summary={self.summary!r}'\n            f' description={self.description!r}'\n            f' description_content_type={self.description_content_type!r}'\n            f' keywords={self.keywords!r}'\n            f' home_page={self.home_page!r}'\n            f' download_url={self.download_url!r}'\n            f' author={self.author!r}'\n            f' author_email={self.author_email!r}'\n            f' maintainer={self.maintainer!r}'\n            f' maintainer_email={self.maintainer_email!r}'\n            f' license={self.license!r}'\n            f' classifier={self.classifier!r}'\n            f' requires_dist={self.requires_dist!r}'\n            f' requires_python={self.requires_python!r}'\n            f' requires_external={self.requires_external!r}'\n            f' project_url={self.project_url!r}'\n            f' provides_extra={self.provides_extra!r}'\n\n            f' root={self.root!r}'\n            f' fn_build={self.fn_build!r}'\n            f' fn_sdist={self.fn_sdist!r}'\n            f' fn_clean={self.fn_clean!r}'\n            f' tag_python={self.tag_python_!r}'\n            f' tag_abi={self.tag_abi_!r}'\n            f' tag_platform={self.tag_platform_!r}'\n            '}'\n            )\n\n    def _dist_info_dir( self):\n        return f'{_normalise2(self.name)}-{self.version}.dist-info'\n\n    def _metainfo(self):\n        '''\n        Returns text for `.egg-info/PKG-INFO` file, or `PKG-INFO` in an sdist\n        `.tar.gz` file, or `...dist-info/METADATA` in a wheel.\n        '''\n        # 2021-04-30: Have been unable to get multiline content working on\n        # test.pypi.org so we currently put the description as the body after\n        # all the other headers.\n        #\n        ret = ['']\n        def add(key, value):\n            if value is None:\n                return\n            if isinstance( value, (tuple, list)):\n                for v in value:\n                    if v is not None:\n                        add( key, v)\n                return\n            if key == 'License' and '\\n' in value:\n                # This is ok because we write `self.license` into\n                # *.dist-info/COPYING.\n                #\n                log1( f'Omitting license because contains newline(s).')\n                return\n            assert '\\n' not in value, f'key={key} value contains newline: {value!r}'\n            if key == 'Project-URL':\n                assert value.count(',') == 1, f'For {key=}, should have one comma in {value!r}.'\n            ret[0] += f'{key}: {value}\\n'\n        #add('Description', self.description)\n        add('Metadata-Version', '2.1')\n\n        # These names are from:\n        # https://packaging.python.org/specifications/core-metadata/\n        #\n        for name in (\n                'Name',\n                'Version',\n                'Platform',\n                'Supported-Platform',\n                'Summary',\n                'Description-Content-Type',\n                'Keywords',\n                'Home-page',\n                'Download-URL',\n                'Author',\n                'Author-email',\n                'Maintainer',\n                'Maintainer-email',\n                'License',\n                'Classifier',\n                'Requires-Dist',\n                'Requires-Python',\n                'Requires-External',\n                'Project-URL',\n                'Provides-Extra',\n                ):\n            identifier = name.lower().replace( '-', '_')\n            add( name, getattr( self, identifier))\n\n        ret = ret[0]\n\n        # Append description as the body\n        if self.description:\n            if '\\n' in self.description:\n                description_text = self.description.strip()\n            else:\n                with open(self.description) as f:\n                    description_text = f.read()\n            ret += '\\n' # Empty line separates headers from body.\n            ret += description_text\n            ret += '\\n'\n        return ret\n\n    def _path_relative_to_root(self, path, assert_within_root=True):\n        '''\n        Returns `(path_abs, path_rel)`, where `path_abs` is absolute path and\n        `path_rel` is relative to `self.root`.\n\n        Interprets `path` as relative to `self.root` if not absolute.\n\n        We use `os.path.realpath()` to resolve any links.\n\n        if `assert_within_root` is true, assert-fails if `path` is not within\n        `self.root`.\n        '''\n        if os.path.isabs(path):\n            p = path\n        else:\n            p = os.path.join(self.root, path)\n        p = os.path.realpath(os.path.abspath(p))\n        if assert_within_root:\n            assert p.startswith(self.root+os.sep) or p == self.root, \\\n                    f'Path not within root={self.root+os.sep!r}: {path=} {p=}'\n        p_rel = os.path.relpath(p, self.root)\n        return p, p_rel\n\n    def _fromto(self, p):\n        '''\n        Returns `(from_, (to_abs, to_rel))`.\n\n        If `p` is a string we convert to `(p, p)`. Otherwise we assert that\n        `p` is a tuple `(from_, to_)` where `from_` is str/bytes and `to_` is\n        str. If `from_` is a bytes it is contents of file to add, otherwise the\n        path of an existing file; non-absolute paths are assumed to be relative\n        to `self.root`.\n\n        If `to_` is empty or `/` we set it to the leaf of `from_` (which must\n        be a str) - i.e. we place the file in the root directory of the wheel;\n        otherwise if `to_` ends with `/` we append the leaf of `from_` (which\n        must be a str).\n\n        If `to_` starts with `$dist-info/`, we replace this with\n        `self._dist_info_dir()`.\n\n        If `to_` starts with `$data/`, we replace this with\n        `{self.name}-{self.version}.data/`.\n\n        We assert that `to_abs` is `within self.root`.\n\n        `to_rel` is derived from the `to_abs` and is relative to self.root`.\n        '''\n        ret = None\n        if isinstance(p, str):\n            p = p, p\n        assert isinstance(p, tuple) and len(p) == 2\n\n        from_, to_ = p\n        assert isinstance(from_, (str, bytes))\n        assert isinstance(to_, str)\n        if to_ == '/' or to_ == '':\n            to_ = os.path.basename(from_)\n        elif to_.endswith('/'):\n            to_ += os.path.basename(from_)\n        prefix = '$dist-info/'\n        if to_.startswith( prefix):\n            to_ = f'{self._dist_info_dir()}/{to_[ len(prefix):]}'\n        prefix = '$data/'\n        if to_.startswith( prefix):\n            to_ = f'{_normalise2(self.name)}-{self.version}.data/{to_[ len(prefix):]}'\n        if isinstance(from_, str):\n            from_, _ = self._path_relative_to_root( from_, assert_within_root=False)\n        to_ = self._path_relative_to_root(to_)\n        assert isinstance(from_, (str, bytes))\n        log2(f'returning {from_=} {to_=}')\n        return from_, to_\n\n_extensions_to_py_limited_api = dict()\n\ndef build_extension(\n        name,\n        path_i,\n        outdir,\n        *,\n        builddir=None,\n        includes=None,\n        defines=None,\n        libpaths=None,\n        libs=None,\n        optimise=True,\n        debug=False,\n        compiler_extra='',\n        linker_extra='',\n        swig=None,\n        cpp=True,\n        source_extra=None,\n        prerequisites_swig=None,\n        prerequisites_compile=None,\n        prerequisites_link=None,\n        infer_swig_includes=True,\n        py_limited_api=False,\n        ):\n    '''\n    Builds a Python extension module using SWIG. Works on Windows, Linux, MacOS\n    and OpenBSD.\n\n    On Unix, sets rpath when linking shared libraries.\n\n    Args:\n        name:\n            Name of generated extension module.\n        path_i:\n            Path of input SWIG `.i` file. Internally we use swig to generate a\n            corresponding `.c` or `.cpp` file.\n        outdir:\n            Output directory for generated files:\n\n                * `{outdir}/{name}.py`\n                * `{outdir}/_{name}.so`     # Unix\n                * `{outdir}/_{name}.*.pyd`  # Windows\n            We return the leafname of the `.so` or `.pyd` file.\n        builddir:\n            Where to put intermediate files, for example the .cpp file\n            generated by swig and `.d` dependency files. Default is `outdir`.\n        includes:\n            A string, or a sequence of extra include directories to be prefixed\n            with `-I`.\n        defines:\n            A string, or a sequence of extra preprocessor defines to be\n            prefixed with `-D`.\n        libpaths\n            A string, or a sequence of library paths to be prefixed with\n            `/LIBPATH:` on Windows or `-L` on Unix.\n        libs\n            A string, or a sequence of library names. Each item is prefixed\n            with `-l` on non-Windows.\n        optimise:\n            Whether to use compiler optimisations and define NDEBUG.\n        debug:\n            Whether to build with debug symbols.\n        compiler_extra:\n            Extra compiler flags. Can be None.\n        linker_extra:\n            Extra linker flags. Can be None.\n        swig:\n            Swig command; if false we use 'swig'.\n        cpp:\n            If true we tell SWIG to generate C++ code instead of C.\n        source_extra:\n            Extra source files to build into the shared library,\n        prerequisites_swig:\n        prerequisites_compile:\n        prerequisites_link:\n\n            [These are mainly for use on Windows. On other systems we\n            automatically generate dynamic dependencies using swig/compile/link\n            commands' `-MD` and `-MF` args.]\n\n            Sequences of extra input files/directories that should force\n            running of swig, compile or link commands if they are newer than\n            any existing generated SWIG `.i` file, compiled object file or\n            shared library file.\n\n            If present, the first occurrence of `True` or `False` forces re-run\n            or no re-run. Any occurrence of None is ignored. If an item is a\n            directory path we look for newest file within the directory tree.\n\n            If not a sequence, we convert into a single-item list.\n\n            prerequisites_swig\n\n                We use swig's -MD and -MF args to generate dynamic dependencies\n                automatically, so this is not usually required.\n\n            prerequisites_compile\n            prerequisites_link\n\n                On non-Windows we use cc's -MF and -MF args to generate dynamic\n                dependencies so this is not usually required.\n        infer_swig_includes:\n            If true, we extract `-I<path>` and `-I <path>` args from\n            `compile_extra` (also `/I` on windows) and use them with swig so\n            that it can see the same header files as C/C++. This is useful\n            when using enviromment variables such as `CC` and `CXX` to set\n            `compile_extra`.\n        py_limited_api:\n            If true we build for current Python's limited API / stable ABI.\n\n            Note that we will assert false if this extension is added to a\n            pipcl.Package that has a different <py_limited_api>, because\n            on Windows importing a non-py_limited_api extension inside a\n            py_limited=True package fails.\n\n    Returns the leafname of the generated library file within `outdir`, e.g.\n    `_{name}.so` on Unix or `_{name}.cp311-win_amd64.pyd` on Windows.\n    '''\n    if compiler_extra is None:\n        compiler_extra = ''\n    if linker_extra is None:\n        linker_extra = ''\n    if builddir is None:\n        builddir = outdir\n    if not swig:\n        swig = 'swig'\n        \n    if source_extra is None:\n        source_extra = list()\n    if isinstance(source_extra, str):\n        source_extra = [source_extra]\n    \n    includes_text = _flags( includes, '-I')\n    defines_text = _flags( defines, '-D')\n    libpaths_text = _flags( libpaths, '/LIBPATH:', '\"') if windows() else _flags( libpaths, '-L')\n    libs_text = _flags( libs, '' if windows() else '-l')\n    path_cpp = f'{builddir}/{os.path.basename(path_i)}'\n    path_cpp += '.cpp' if cpp else '.c'\n    os.makedirs( outdir, exist_ok=True)\n\n    # Run SWIG.\n    #\n    if infer_swig_includes:\n        # Extract include flags from `compiler_extra`.\n        swig_includes_extra = ''\n        compiler_extra_items = shlex.split(compiler_extra)\n        i = 0\n        while i < len(compiler_extra_items):\n            item = compiler_extra_items[i]\n            # Swig doesn't seem to like a space after `I`.\n            if item == '-I' or (windows() and item == '/I'):\n                swig_includes_extra += f' -I{compiler_extra_items[i+1]}'\n                i += 1\n            elif item.startswith('-I') or (windows() and item.startswith('/I')):\n                swig_includes_extra += f' -I{compiler_extra_items[i][2:]}'\n            i += 1\n        swig_includes_extra = swig_includes_extra.strip()\n    deps_path = f'{path_cpp}.d'\n    prerequisites_swig2 = _get_prerequisites( deps_path)\n    run_if(\n            f'''\n            {swig}\n                -Wall\n                {\"-c++\" if cpp else \"\"}\n                -python\n                -module {name}\n                -outdir {outdir}\n                -o {path_cpp}\n                -MD -MF {deps_path}\n                {includes_text}\n                {swig_includes_extra}\n                {path_i}\n            '''\n            ,\n            path_cpp,\n            path_i,\n            prerequisites_swig,\n            prerequisites_swig2,\n            )\n\n    if pyodide():\n        so_suffix = '.so'\n        log0(f'pyodide: PEP-3149 suffix untested, so omitting. {_so_suffix()=}.')\n    else:\n        so_suffix = _so_suffix(use_so_versioning = not py_limited_api)\n    path_so_leaf = f'_{name}{so_suffix}'\n    path_so = f'{outdir}/{path_so_leaf}'\n\n    py_limited_api2 = current_py_limited_api() if py_limited_api else None\n\n    compiler_command, pythonflags = base_compiler(cpp=cpp)\n    linker_command, _ = base_linker(cpp=cpp)\n    # setuptools on Linux seems to use slightly different compile flags:\n    #\n    # -fwrapv -O3 -Wall -O2 -g0 -DPY_CALL_TRAMPOLINE\n    #\n\n    general_flags = ''\n    if windows():\n        permissive = '/permissive-'\n        EHsc = '/EHsc'\n        T = '/Tp' if cpp else '/Tc'\n        optimise2 = '/DNDEBUG /O2' if optimise else '/D_DEBUG'\n        debug2 = '/Zi' if debug else ''\n        py_limited_api3 = f'/DPy_LIMITED_API={py_limited_api2}' if py_limited_api2 else ''\n\n    else:\n        if debug:\n            general_flags += '/Zi' if windows() else ' -g'\n        if optimise:\n            general_flags += ' /DNDEBUG /O2' if windows() else ' -O2 -DNDEBUG'\n\n        py_limited_api3 = f'-DPy_LIMITED_API={py_limited_api2}' if py_limited_api2 else ''\n\n    if windows():\n        pass\n    elif darwin():\n        # MacOS's linker does not like `-z origin`.\n        rpath_flag = \"-Wl,-rpath,@loader_path/\"\n        # Avoid `Undefined symbols for ... \"_PyArg_UnpackTuple\" ...'.\n        general_flags += ' -undefined dynamic_lookup'\n    elif pyodide():\n        # Setting `-Wl,-rpath,'$ORIGIN',-z,origin` gives:\n        #   emcc: warning: ignoring unsupported linker flag: `-rpath` [-Wlinkflags]\n        #   wasm-ld: error: unknown -z value: origin\n        #\n        rpath_flag = \"-Wl,-rpath,'$ORIGIN'\"\n    else:\n        rpath_flag = \"-Wl,-rpath,'$ORIGIN',-z,origin\"\n    \n    # Fun fact - on Linux, if the -L and -l options are before '{path_cpp}'\n    # they seem to be ignored...\n    #\n    path_os = list()\n\n    for path_source in [path_cpp] + source_extra:\n        path_o = f'{path_source}.obj' if windows() else f'{path_source}.o'\n        path_os.append(path_o)\n\n        prerequisites_path = f'{path_o}.d'\n\n        if windows():\n            compiler_command2 = f'''\n                    {compiler_command}\n                        # General:\n                        /c                          # Compiles without linking.\n                        {EHsc}                      # Enable \"Standard C++ exception handling\".\n\n                        #/MD                         # Creates a multithreaded DLL using MSVCRT.lib.\n                        {'/MDd' if debug else '/MD'}\n\n                        # Input/output files:\n                        {T}{path_source}            # /Tp specifies C++ source file.\n                        /Fo{path_o}                 # Output file. codespell:ignore\n\n                        # Include paths:\n                        {includes_text}\n                        {pythonflags.includes}      # Include path for Python headers.\n\n                        # Code generation:\n                        {optimise2}\n                        {debug2}\n                        {permissive}                # Set standard-conformance mode.\n\n                        # Diagnostics:\n                        #/FC                         # Display full path of source code files passed to cl.exe in diagnostic text.\n                        /W3                         # Sets which warning level to output. /W3 is IDE default.\n                        /diagnostics:caret          # Controls the format of diagnostic messages.\n                        /nologo                     #\n\n                        {defines_text}\n                        {compiler_extra}\n\n                        {py_limited_api3}\n                    '''\n\n        else:\n            compiler_command2 = f'''\n                    {compiler_command}\n                        -fPIC\n                        {general_flags.strip()}\n                        {pythonflags.includes}\n                        {includes_text}\n                        {defines_text}\n                        -MD -MF {prerequisites_path}\n                        -c {path_source}\n                        -o {path_o}\n                        {compiler_extra}\n                        {py_limited_api3}\n                    '''\n        run_if(\n                compiler_command2,\n                path_o,\n                path_source,\n                [path_source] + _get_prerequisites(prerequisites_path),\n                )\n\n    # Link\n    prerequisites_path = f'{path_so}.d'\n    if windows():\n        debug2 = '/DEBUG' if debug else ''\n        base, _ = os.path.splitext(path_so_leaf)\n        command2 = f'''\n                {linker_command}\n                    /DLL                    # Builds a DLL.\n                    /EXPORT:PyInit__{name}  # Exports a function.\n                    /IMPLIB:{base}.lib      # Overrides the default import library name.\n                    {libpaths_text}\n                    {pythonflags.ldflags}\n                    /OUT:{path_so}          # Specifies the output file name.\n                    {debug2}\n                    /nologo\n                    {libs_text}\n                    {' '.join(path_os)}\n                    {linker_extra}\n                '''\n    elif pyodide():\n        command2 = f'''\n                {linker_command}\n                    -MD -MF {prerequisites_path}\n                    -o {path_so}\n                    {' '.join(path_os)}\n                    {libpaths_text}\n                    {libs_text}\n                    {linker_extra}\n                    {pythonflags.ldflags}\n                    {rpath_flag}\n                '''\n    else:\n        command2 = f'''\n                {linker_command}\n                    -shared\n                    {general_flags.strip()}\n                    -MD -MF {prerequisites_path}\n                    -o {path_so}\n                    {' '.join(path_os)}\n                    {libpaths_text}\n                    {libs_text}\n                    {linker_extra}\n                    {pythonflags.ldflags}\n                    {rpath_flag}\n                    {py_limited_api3}\n                '''\n    link_was_run = run_if(\n            command2,\n            path_so,\n            path_cpp,\n            *path_os,\n            *_get_prerequisites(f'{path_so}.d'),\n            )\n\n    if link_was_run and darwin():\n        # We need to patch up references to shared libraries in `libs`.\n        sublibraries = list()\n        for lib in () if libs is None else libs:\n            for libpath in libpaths:\n                found = list()\n                for suffix in '.so', '.dylib':\n                    path = f'{libpath}/lib{os.path.basename(lib)}{suffix}'\n                    if os.path.exists( path):\n                        found.append( path)\n                if found:\n                    assert len(found) == 1, f'More than one file matches lib={lib!r}: {found}'\n                    sublibraries.append( found[0])\n                    break\n            else:\n                log2(f'Warning: can not find path of lib={lib!r} in libpaths={libpaths}')\n        macos_patch( path_so, *sublibraries)\n\n        #run(f'ls -l {path_so}', check=0)\n        #run(f'file {path_so}', check=0)\n\n    _extensions_to_py_limited_api[os.path.abspath(path_so)] = py_limited_api\n    \n    return path_so_leaf\n\n\n# Functions that might be useful.\n#\n\n\ndef base_compiler(vs=None, pythonflags=None, cpp=False, use_env=True):\n    '''\n    Returns basic compiler command and PythonFlags.\n\n    Args:\n        vs:\n            Windows only. A `wdev.WindowsVS` instance or None to use default\n            `wdev.WindowsVS` instance.\n        pythonflags:\n            A `pipcl.PythonFlags` instance or None to use default\n            `pipcl.PythonFlags` instance.\n        cpp:\n            If true we return C++ compiler command instead of C. On Windows\n            this has no effect - we always return `cl.exe`.\n        use_env:\n            If true we return '$CC' or '$CXX' if the corresponding\n            environmental variable is set (without evaluating with `getenv()`\n            or `os.environ`).\n\n    Returns `(cc, pythonflags)`:\n        cc:\n            C or C++ command. On Windows this is of the form\n            `{vs.vcvars}&&{vs.cl}`; otherwise it is typically `cc` or `c++`.\n        pythonflags:\n            The `pythonflags` arg or a new `pipcl.PythonFlags` instance.\n    '''\n    if not pythonflags:\n        pythonflags = PythonFlags()\n    cc = None\n    if use_env:\n        if cpp:\n            if os.environ.get( 'CXX'):\n                cc = '$CXX'\n        else:\n            if os.environ.get( 'CC'):\n                cc = '$CC'\n    if cc:\n        pass\n    elif windows():\n        if not vs:\n            vs = wdev.WindowsVS()\n        cc = f'\"{vs.vcvars}\"&&\"{vs.cl}\"'\n    elif wasm():\n        cc = 'em++' if cpp else 'emcc'\n    else:\n        cc = 'c++' if cpp else 'cc'\n    cc = macos_add_cross_flags( cc)\n    return cc, pythonflags\n\n\ndef base_linker(vs=None, pythonflags=None, cpp=False, use_env=True):\n    '''\n    Returns basic linker command.\n\n    Args:\n        vs:\n            Windows only. A `wdev.WindowsVS` instance or None to use default\n            `wdev.WindowsVS` instance.\n        pythonflags:\n            A `pipcl.PythonFlags` instance or None to use default\n            `pipcl.PythonFlags` instance.\n        cpp:\n            If true we return C++ linker command instead of C. On Windows this\n            has no effect - we always return `link.exe`.\n        use_env:\n            If true we use `os.environ['LD']` if set.\n\n    Returns `(linker, pythonflags)`:\n        linker:\n            Linker command. On Windows this is of the form\n            `{vs.vcvars}&&{vs.link}`; otherwise it is typically `cc` or `c++`.\n        pythonflags:\n            The `pythonflags` arg or a new `pipcl.PythonFlags` instance.\n    '''\n    if not pythonflags:\n        pythonflags = PythonFlags()\n    linker = None\n    if use_env:\n        if os.environ.get( 'LD'):\n            linker = '$LD'\n    if linker:\n        pass\n    elif windows():\n        if not vs:\n            vs = wdev.WindowsVS()\n        linker = f'\"{vs.vcvars}\"&&\"{vs.link}\"'\n    elif wasm():\n        linker = 'em++' if cpp else 'emcc'\n    else:\n        linker = 'c++' if cpp else 'cc'\n    linker = macos_add_cross_flags( linker)\n    return linker, pythonflags\n\n\ndef git_info( directory):\n    '''\n    Returns `(sha, comment, diff, branch)`, all items are str or None if not\n    available.\n\n    directory:\n        Root of git checkout.\n    '''\n    sha, comment, diff, branch = None, None, None, None\n    e, out = run(\n            f'cd {directory} && (PAGER= git show --pretty=oneline|head -n 1 && git diff)',\n            capture=1,\n            check=0\n            )\n    if not e:\n        sha, _ = out.split(' ', 1)\n        comment, diff = _.split('\\n', 1)\n    e, out = run(\n            f'cd {directory} && git rev-parse --abbrev-ref HEAD',\n            capture=1,\n            check=0\n            )\n    if not e:\n        branch = out.strip()\n    log1(f'git_info(): directory={directory!r} returning branch={branch!r} sha={sha!r} comment={comment!r}')\n    return sha, comment, diff, branch\n\n\ndef git_items( directory, submodules=False):\n    '''\n    Returns list of paths for all files known to git within a `directory`.\n\n    Args:\n        directory:\n            Must be somewhere within a git checkout.\n        submodules:\n            If true we also include git submodules.\n\n    Returns:\n        A list of paths for all files known to git within `directory`. Each\n        path is relative to `directory`. `directory` must be somewhere within a\n        git checkout.\n\n    We run a `git ls-files` command internally.\n\n    This function can be useful for the `fn_sdist()` callback.\n    '''\n    command = 'cd ' + directory + ' && git ls-files'\n    if submodules:\n        command += ' --recurse-submodules'\n    log1(f'Running {command=}')\n    text = subprocess.check_output( command, shell=True)\n    ret = []\n    for path in text.decode('utf8').strip().split( '\\n'):\n        path2 = os.path.join(directory, path)\n        # Sometimes git ls-files seems to list empty/non-existent directories\n        # within submodules.\n        #\n        if not os.path.exists(path2):\n            log2(f'Ignoring git ls-files item that does not exist: {path2}')\n        elif os.path.isdir(path2):\n            log2(f'Ignoring git ls-files item that is actually a directory: {path2}')\n        else:\n            ret.append(path)\n    return ret\n\n\ndef git_get(\n        local,\n        *,\n        remote=None,\n        branch=None,\n        tag=None,\n        text=None,\n        depth=1,\n        env_extra=None,\n        update=True,\n        submodules=True,\n        ):\n    '''\n    Creates/updates local checkout <local> of remote repository and returns\n    absolute path of <local>.\n\n    If <text> is set but does not start with 'git:', it is assumed to be an up\n    to date local checkout, and we return absolute path of <text> without doing\n    any git operations.\n    \n    Args:\n        local:\n            Local directory. Created and/or updated using `git clone` and `git\n            fetch` etc.\n        remote:\n            Remote git repostitory, for example\n            'https://github.com/ArtifexSoftware/mupdf.git'. Can be overridden\n            by <text>.\n        branch:\n            Branch to use; can be overridden by <text>.\n        tag:\n            Tag to use; can be overridden by <text>.\n        text:\n            If None or empty:\n                Ignored.\n            \n            If starts with 'git:':\n                The remaining text should be a command-line\n                style string containing some or all of these args:\n                    --branch <branch>\n                    --tag <tag>\n                    <remote>\n                These overrides <branch>, <tag> and <remote>.\n            Otherwise:\n                <text> is assumed to be a local directory, and we simply return\n                it as an absolute path without doing any git operations.\n            \n            For example these all clone/update/branch master of https://foo.bar/qwerty.git to local\n            checkout 'foo-local':\n            \n                git_get('foo-local', remote='https://foo.bar/qwerty.git', branch='master')\n                git_get('foo-local', text='git:--branch master https://foo.bar/qwerty.git')\n                git_get('foo-local', text='git:--branch master', remote='https://foo.bar/qwerty.git')\n                git_get('foo-local', text='git:', branch='master', remote='https://foo.bar/qwerty.git')\n        depth:\n            Depth of local checkout when cloning and fetching, or None.\n        env_extra:\n            Dict of extra name=value environment variables to use whenever we\n            run git.\n        update:\n            If false we do not update existing repository. Might be useful if\n            testing without network access.\n        submodules:\n            If true, we clone with `--recursive --shallow-submodules` and run\n            `git submodule update --init --recursive` before returning.\n    '''\n    log0(f'{remote=} {local=} {branch=} {tag=} {text=}')\n    \n    if text:\n        if text.startswith('git:'):\n            args = iter(shlex.split(text[len('git:'):]))\n            while 1:\n                try:\n                    arg = next(args)\n                except StopIteration:\n                    break\n                if arg == '--branch':\n                    branch = next(args)\n                    tag = None\n                elif arg == '--tag':\n                    tag = next(args)\n                    branch = None\n                else:\n                    remote = arg\n            assert remote, f'<remote> unset and no remote specified in {text=}.'\n            assert branch or tag, f'<branch> and <tag> unset and no branch/tag specified in {text=}.'\n        else:\n            log0(f'Using local directory {text!r}.')\n            return os.path.abspath(text)\n        \n    assert (branch and not tag) or (not branch and tag), f'Must specify exactly one of <branch> and <tag>; {branch=} {tag=}.'\n    \n    depth_arg = f' --depth {depth}' if depth else ''\n    \n    def do_update():\n        # This seems to pull in the entire repository.\n        log0(f'do_update(): attempting to update {local=}.')\n        # Remove any local changes.\n        run(f'cd {local} && git reset --hard', env_extra=env_extra)\n        if tag:\n            # `-u` avoids `fatal: Refusing to fetch into current branch`.\n            # Using '+' and `revs/tags/` prefix seems to avoid errors like:\n            #   error: cannot update ref 'refs/heads/v3.16.44':\n            #   trying to write non-commit object\n            #   06c4ae5fe39a03b37a25a8b95214d9f8f8a867b8 to branch\n            #   'refs/heads/v3.16.44'\n            #\n            run(f'cd {local} && git fetch -fuv{depth_arg} {remote} +refs/tags/{tag}:refs/tags/{tag}', env_extra=env_extra)\n            run(f'cd {local} && git checkout {tag}', env_extra=env_extra)\n        if branch:\n            # `-u` avoids `fatal: Refusing to fetch into current branch`.\n            run(f'cd {local} && git fetch -fuv{depth_arg} {remote} {branch}:{branch}', env_extra=env_extra)\n            run(f'cd {local} && git checkout {branch}', env_extra=env_extra)\n    \n    do_clone = True\n    if os.path.isdir(f'{local}/.git'):\n        if update:\n            # Try to update existing checkout.\n            try:\n                do_update()\n                do_clone = False\n            except Exception as e:\n                log0(f'Failed to update existing checkout {local}: {e}')\n        else:\n            do_clone = False\n    \n    if do_clone:\n        # No existing git checkout, so do a fresh clone.\n        #_fs_remove(local)\n        log0(f'Cloning to: {local}')\n        command = f'git clone --config core.longpaths=true{depth_arg}'\n        if submodules:\n            command += f' --recursive --shallow-submodules'\n        if branch:\n            command += f' -b {branch}'\n        if tag:\n            command += f' -b {tag}'\n        command += f' {remote} {local}'\n        run(command, env_extra=env_extra)\n        do_update()\n    \n    if submodules:\n        run(f'cd {local} && git submodule update --init --recursive', env_extra=env_extra)\n\n    # Show sha of checkout.\n    run( f'cd {local} && git show --pretty=oneline|head -n 1', check=False)\n    return os.path.abspath(local)\n    \n\ndef run(\n        command,\n        *,\n        capture=False,\n        check=1,\n        verbose=1,\n        env=None,\n        env_extra=None,\n        timeout=None,\n        caller=1,\n        prefix=None,\n        encoding=None,  # System default.\n        errors='backslashreplace',\n        ):\n    '''\n    Runs a command using `subprocess.run()`.\n\n    Args:\n        command:\n            A string, the command to run.\n\n            Multiple lines in `command` are treated as a single command.\n\n            * If a line starts with `#` it is discarded.\n            * If a line contains ` #`, the trailing text is discarded.\n\n            When running the command on Windows, newlines are replaced by\n            spaces; otherwise each line is terminated by a backslash character.\n        capture:\n            If true, we include the command's output in our return value.\n        check:\n            If true we raise an exception on error; otherwise we include the\n            command's returncode in our return value.\n        verbose:\n            If true we show the command.\n        env:\n            None or dict to use instead of <os.environ>.\n        env_extra:\n            None or dict to add to <os.environ> or <env>.\n        timeout:\n            If not None, timeout in seconds; passed directly to\n            subprocess.run(). Note that on MacOS subprocess.run() seems to\n            leave processes running if timeout expires.\n        prefix:\n            String prefix for each line of output.\n\n            If true:\n            * We run command with stdout=subprocess.PIPE and\n              stderr=subprocess.STDOUT, repetaedly reading the command's output\n              and writing it to stdout with <prefix>.\n            * We do not support <timeout>, which must be None.\n    Returns:\n        check capture   Return\n        --------------------------\n          false false   returncode\n          false  true   (returncode, output)\n          true  false   None or raise exception\n          true   true   output or raise exception\n    '''\n    if env is None:\n        env = os.environ\n        if env_extra:\n            env = env.copy()\n    if env_extra:\n        env.update(env_extra)\n    lines = _command_lines( command)\n    if verbose:\n        text = f'Running:'\n        nl = '\\n    '\n        text += f' {nl.join(lines)}'\n        if env_extra:\n            text += f'\\nwith:\\n'\n            for k in sorted(env_extra.keys()):\n                text += f'    {k}={shlex.quote(env_extra[k])}\\n'\n        log1(text, caller=caller+1)\n    sep = ' ' if windows() else ' \\\\\\n'\n    command2 = sep.join( lines)\n    \n    if prefix:\n        assert not timeout, f'Timeout not supported with prefix.'\n        child = subprocess.Popen(\n                command2,\n                shell=True,\n                stdout=subprocess.PIPE,\n                stderr=subprocess.STDOUT,\n                encoding=encoding,\n                errors=errors,\n                env=env,\n                )\n        if capture:\n            capture_text = ''\n        decoder = codecs.getincrementaldecoder(child.stdout.encoding)(errors)\n        line_start = True\n        \n        while 1:\n            raw = os.read( child.stdout.fileno(), 10000)\n            text = decoder.decode(raw, final=not raw)\n            if capture:\n                capture_text += text\n            lines = text.split('\\n')\n            for i, line in enumerate(lines):\n                if line_start:\n                    sys.stdout.write(prefix)\n                    line_start = False\n                sys.stdout.write(line)\n                if i < len(lines) - 1:\n                    sys.stdout.write('\\n')\n                    line_start = True\n            sys.stdout.flush()\n            if not raw:\n                break\n        if not line_start:\n            sys.stdout.write('\\n')\n        e = child.wait()\n        if check and e:\n            raise subprocess.CalledProcessError(e, command2, capture_text if capture else None)\n        if check:\n            return capture_text if capture else None\n        else:\n            return (e, capture_text) if capture else e\n    else:\n        cp = subprocess.run(\n                command2,\n                shell=True,\n                stdout=subprocess.PIPE if capture else None,\n                stderr=subprocess.STDOUT if capture else None,\n                check=check,\n                encoding=encoding,\n                errors=errors,\n                env=env,\n                timeout=timeout,\n                )\n    if check:\n        return cp.stdout if capture else None\n    else:\n        return (cp.returncode, cp.stdout) if capture else cp.returncode\n\n\ndef darwin():\n    return sys.platform.startswith( 'darwin')\n\ndef windows():\n    return platform.system() == 'Windows'\n\ndef wasm():\n    return os.environ.get( 'OS') in ('wasm', 'wasm-mt')\n\ndef pyodide():\n    return os.environ.get( 'PYODIDE') == '1'\n\ndef linux():\n    return platform.system() == 'Linux'\n\ndef openbsd():\n    return platform.system() == 'OpenBSD'\n\n\ndef show_system():\n    '''\n    Show useful information about the system plus argv and environ.\n    \n    Omits os.environ if $PIPCL_SHOW_ENV is '0'.\n    '''\n    def log(text):\n        log0(text, caller=3)\n    \n    #log(f'{__file__=}')\n    #log(f'{__name__=}')\n    log(f'{os.getcwd()=}')\n    log(f'{platform.machine()=}')\n    log(f'{platform.platform()=}')\n    log(f'{platform.python_implementation()=}')\n    log(f'{platform.python_version()=}')\n    log(f'{platform.system()=}')\n    if sys.implementation.name != 'graalpy':\n        log(f'{platform.uname()=}')\n    log(f'{sys.executable=}')\n    log(f'{sys.version=}')\n    log(f'{sys.version_info=}')\n    log(f'{list(sys.version_info)=}')\n    \n    log(f'{sysconfig.get_config_var(\"Py_GIL_DISABLED\")=}')\n    try:\n        log(f'{sys._is_gil_enabled()=}')\n    except AttributeError:\n        log(f'sys._is_gil_enabled() => AttributeError')\n    \n    log(f'CPU bits: {cpu_bits()}')\n    \n    log(f'sys.argv ({len(sys.argv)}):')\n    for i, arg in enumerate(sys.argv):\n        log(f'    {i}: {arg!r}')\n    \n    PIPCL_SHOW_ENV = os.environ.get('PIPCL_SHOW_ENV')\n    if PIPCL_SHOW_ENV == '0':\n        log(f'[Not showing os.environ because {PIPCL_SHOW_ENV=}.]')\n    else:\n        log(f'os.environ ({len(os.environ)}):')\n        for k in sorted( os.environ.keys()):\n            v = os.environ[ k]\n            if 'BEGIN OPENSSH PRIVATE KEY' in v:\n                # Don't show private keys.\n                log(f'    {k} ****')\n            else:\n                log( f'    {k}: {v!r}')\n\n\nclass PythonFlags:\n    '''\n    Compile/link flags for the current python, for example the include path\n    needed to get `Python.h`.\n\n    The 'PIPCL_PYTHON_CONFIG' environment variable allows to override\n    the location of the python-config executable.\n\n    Members:\n        .includes:\n            String containing compiler flags for include paths.\n        .ldflags:\n            String containing linker flags for library paths.\n    '''\n    def __init__(self):\n        \n        # Experimental detection of python flags from sysconfig.*() instead of\n        # python-config command.\n        includes_, ldflags_ = sysconfig_python_flags()\n      \n        if pyodide():\n            _include_dir = os.environ[ 'PYO3_CROSS_INCLUDE_DIR']\n            _lib_dir = os.environ[ 'PYO3_CROSS_LIB_DIR']\n            self.includes = f'-I {_include_dir}'\n            self.ldflags = f'-L {_lib_dir}'\n\n        elif 0:\n\n            self.includes = includes_\n            self.ldflags = ldflags_\n        \n        elif windows():\n            wp = wdev.WindowsPython()\n            self.includes = f'/I\"{wp.include}\"'\n            self.ldflags = f'/LIBPATH:\"{wp.libs}\"'\n\n        elif pyodide():\n            _include_dir = os.environ[ 'PYO3_CROSS_INCLUDE_DIR']\n            _lib_dir = os.environ[ 'PYO3_CROSS_LIB_DIR']\n            self.includes = f'-I {_include_dir}'\n            self.ldflags = f'-L {_lib_dir}'\n\n        else:\n            python_config = os.environ.get(\"PIPCL_PYTHON_CONFIG\")\n            if not python_config:\n                # We use python-config which appears to work better than pkg-config\n                # because it copes with multiple installed python's, e.g.\n                # manylinux_2014's /opt/python/cp*-cp*/bin/python*.\n                #\n                # But... on non-macos it seems that we should not attempt to specify\n                # libpython on the link command. The manylinux docker containers\n                # don't actually contain libpython.so, and it seems that this\n                # deliberate. And the link command runs ok.\n                #\n                python_exe = os.path.realpath( sys.executable)\n                if darwin():\n                    # Basic install of dev tools with `xcode-select --install` doesn't\n                    # seem to provide a `python3-config` or similar, but there is a\n                    # `python-config.py` accessible via sysconfig.\n                    #\n                    # We try different possibilities and use the last one that\n                    # works.\n                    #\n                    python_config = None\n                    for pc in (\n                            f'python3-config',\n                            f'{sys.executable} {sysconfig.get_config_var(\"srcdir\")}/python-config.py',\n                            f'{python_exe}-config',\n                            ):\n                        e = subprocess.run(\n                                f'{pc} --includes',\n                                shell=1,\n                                stdout=subprocess.DEVNULL,\n                                stderr=subprocess.DEVNULL,\n                                check=0,\n                                ).returncode\n                        log2(f'{e=} from {pc!r}.')\n                        if e == 0:\n                            python_config = pc\n                    assert python_config, f'Cannot find python-config'\n                else:\n                    python_config = f'{python_exe}-config'\n            log2(f'Using {python_config=}.')\n            try:\n                self.includes = run( f'{python_config} --includes', capture=1, verbose=0).strip()\n            except Exception as e:\n                raise Exception('We require python development tools to be installed.') from e\n            self.ldflags = run( f'{python_config} --ldflags', capture=1, verbose=0).strip()\n            if linux():\n                # It seems that with python-3.10 on Linux, we can get an\n                # incorrect -lcrypt flag that on some systems (e.g. WSL)\n                # causes:\n                #\n                #   ImportError: libcrypt.so.2: cannot open shared object file: No such file or directory\n                #\n                ldflags2 = self.ldflags.replace(' -lcrypt ', ' ')\n                if ldflags2 != self.ldflags:\n                    log2(f'### Have removed `-lcrypt` from ldflags: {self.ldflags!r} -> {ldflags2!r}')\n                    self.ldflags = ldflags2\n\n        if 0:\n            log1(f'{self.includes=}')\n            log1(f'    {includes_=}')\n            log1(f'{self.ldflags=}')\n            log1(f'    {ldflags_=}')\n\n\ndef macos_add_cross_flags(command):\n    '''\n    If running on MacOS and environment variables ARCHFLAGS is set\n    (indicating we are cross-building, e.g. for arm64), returns\n    `command` with extra flags appended. Otherwise returns unchanged\n    `command`.\n    '''\n    if darwin():\n        archflags = os.environ.get( 'ARCHFLAGS')\n        if archflags:\n            command = f'{command} {archflags}'\n            log2(f'Appending ARCHFLAGS to command: {command}')\n            return command\n    return command\n\n\ndef macos_patch( library, *sublibraries):\n    '''\n    If running on MacOS, patches `library` so that all references to items in\n    `sublibraries` are changed to `@rpath/{leafname}`. Does nothing on other\n    platforms.\n\n    library:\n        Path of shared library.\n    sublibraries:\n        List of paths of shared libraries; these have typically been\n        specified with `-l` when `library` was created.\n    '''\n    log2( f'macos_patch(): library={library}  sublibraries={sublibraries}')\n    if not darwin():\n        return\n    if not sublibraries:\n        return\n    subprocess.run( f'otool -L {library}', shell=1, check=1)\n    command = 'install_name_tool'\n    names = []\n    for sublibrary in sublibraries:\n        name = subprocess.run(\n                f'otool -D {sublibrary}',\n                shell=1,\n                check=1,\n                capture_output=1,\n                encoding='utf8',\n                ).stdout.strip()\n        name = name.split('\\n')\n        assert len(name) == 2 and name[0] == f'{sublibrary}:', f'{name=}'\n        name = name[1]\n        # strip trailing so_name.\n        leaf = os.path.basename(name)\n        m = re.match('^(.+[.]((so)|(dylib)))[0-9.]*$', leaf)\n        assert m\n        log2(f'Changing {leaf=} to {m.group(1)}')\n        leaf = m.group(1)\n        command += f' -change {name} @rpath/{leaf}'\n    command += f' {library}'\n    log2( f'Running: {command}')\n    subprocess.run( command, shell=1, check=1)\n    subprocess.run( f'otool -L {library}', shell=1, check=1)\n\n\ndef _macos_fixup_platform_tag(tag):\n    '''\n    Patch up platform tag on MacOS.\n\n    E.g. `foo-1.2.3-cp311-none-macosx_13_x86_64.whl` causes `pip` to fail with:\n    `not a supported wheel on this platform`. We seem to need to add `_0` to\n    the OS version. (This is documented at\n    https://packaging.python.org/en/latest/specifications/platform-compatibility-tags/#macos).\n\n    And with graal we need to replace trailing `universal2` with x86_64\n    or arm64. On non-graal this causes problems because non-universal\n    platform tags seem more restricted than platform tags from\n    sysconfig.get_platform(). For example:\n    \n        pip install ...-macosx_10_13_arm64.whl\n            ERROR: ...-macosx_10_13_arm64.whl is not a supported wheel on this platform.\n        pip install ...-macosx_10_13_universal2.whl\n            Ok.\n    '''\n    m = re.match( '^macosx_([0-9_]+)_([^0-9].+)$', tag)\n    if not m:\n        return tag\n    a = m.group(1)\n    if '_' not in a:\n        a += '_0'\n    b = m.group(2)\n    if sys.implementation.name == 'graalpy' and b == 'universal2':\n        # Replace 'universal2' with x86_64 or arm64.\n        b = platform.machine()\n    ret = f'macosx_{a}_{b}'\n    #log0(f'Changing from {tag=} to {ret=}.')\n    return ret\n    \n\n# Internal helpers.\n#\n\ndef _command_lines( command):\n    '''\n    Process multiline command by running through `textwrap.dedent()`, removes\n    comments (lines starting with `#` or ` #` until end of line), removes\n    entirely blank lines.\n\n    Returns list of lines.\n    '''\n    command = textwrap.dedent( command)\n    lines = []\n    for line in command.split( '\\n'):\n        if line.startswith( '#'):\n            h = 0\n        else:\n            h = line.find( ' #')\n        if h >= 0:\n            line = line[:h]\n        if line.strip():\n            lines.append(line.rstrip())\n    return lines\n\n\ndef cpu_bits():\n    return int.bit_length(sys.maxsize+1)\n\n\ndef _cpu_name():\n    '''\n    Returns `x32` or `x64` depending on Python build.\n    '''\n    #log(f'sys.maxsize={hex(sys.maxsize)}')\n    return f'x{32 if sys.maxsize == 2**31 - 1 else 64}'\n\n\ndef run_if( command, out, *prerequisites, caller=1):\n    '''\n    Runs a command only if the output file is not up to date.\n\n    Args:\n        command:\n            The command to run. We write this and a hash of argv[0] into a file\n            <out>.cmd so that we know to run a command if the command itself\n            has changed.\n        out:\n            Path of the output file.\n\n        prerequisites:\n            List of prerequisite paths or true/false/None items. If an item\n            is None it is ignored, otherwise if an item is not a string we\n            immediately return it cast to a bool. We recurse into directories,\n            effectively using the newest file in the directory.\n\n    Returns:\n        True if we ran the command, otherwise None.\n\n\n    If the output file does not exist, the command is run:\n\n        >>> verbose(1)\n        1\n        >>> log_line_numbers(0)\n        >>> out = 'run_if_test_out'\n        >>> if os.path.exists( out):\n        ...     os.remove( out)\n        >>> if os.path.exists( f'{out}.cmd'):\n        ...     os.remove( f'{out}.cmd')\n        >>> run_if( f'touch {out}', out, caller=0)\n        pipcl.py:run_if(): Running command because: File does not exist: 'run_if_test_out'\n        pipcl.py:run_if(): Running: touch run_if_test_out\n        True\n\n    If we repeat, the output file will be up to date so the command is not run:\n\n        >>> run_if( f'touch {out}', out, caller=0)\n        pipcl.py:run_if(): Not running command because up to date: 'run_if_test_out'\n\n    If we change the command, the command is run:\n\n        >>> run_if( f'touch {out};', out, caller=0)\n        pipcl.py:run_if(): Running command because: Command has changed:\n        pipcl.py:run_if():     @@ -1,2 +1,2 @@\n        pipcl.py:run_if():      touch\n        pipcl.py:run_if():     -run_if_test_out\n        pipcl.py:run_if():     +run_if_test_out;\n        pipcl.py:run_if(): \n        pipcl.py:run_if(): Running: touch run_if_test_out;\n        True\n\n    If we add a prerequisite that is newer than the output, the command is run:\n\n        >>> time.sleep(1)\n        >>> prerequisite = 'run_if_test_prerequisite'\n        >>> run( f'touch {prerequisite}', caller=0)\n        pipcl.py:run(): Running: touch run_if_test_prerequisite\n        >>> run_if( f'touch  {out}', out, prerequisite, caller=0)\n        pipcl.py:run_if(): Running command because: Command has changed:\n        pipcl.py:run_if():     @@ -1,2 +1,2 @@\n        pipcl.py:run_if():      touch\n        pipcl.py:run_if():     -run_if_test_out;\n        pipcl.py:run_if():     +run_if_test_out\n        pipcl.py:run_if(): \n        pipcl.py:run_if(): Running: touch  run_if_test_out\n        True\n\n    If we repeat, the output will be newer than the prerequisite, so the\n    command is not run:\n\n        >>> run_if( f'touch  {out}', out, prerequisite, caller=0)\n        pipcl.py:run_if(): Not running command because up to date: 'run_if_test_out'\n    \n    We detect changes to the contents of argv[0]:\n    \n    Create a shell script and run it:\n    \n    >>> _ = subprocess.run('rm run_if_test_argv0.* 1>/dev/null 2>/dev/null || true', shell=1)\n    >>> with open('run_if_test_argv0.sh', 'w') as f:\n    ...     print('#! /bin/sh', file=f)\n    ...     print('echo hello world > run_if_test_argv0.out', file=f)\n    >>> _ = subprocess.run(f'chmod u+x run_if_test_argv0.sh', shell=1)\n    >>> run_if( f'./run_if_test_argv0.sh', f'run_if_test_argv0.out', caller=0)\n    pipcl.py:run_if(): Running command because: File does not exist: 'run_if_test_argv0.out'\n    pipcl.py:run_if(): Running: ./run_if_test_argv0.sh\n    True\n    \n    Running it a second time does nothing:\n    \n    >>> run_if( f'./run_if_test_argv0.sh', f'run_if_test_argv0.out', caller=0)\n    pipcl.py:run_if(): Not running command because up to date: 'run_if_test_argv0.out'\n    \n    Modify the script.\n    \n    >>> with open('run_if_test_argv0.sh', 'a') as f:\n    ...     print('\\\\necho hello >> run_if_test_argv0.out', file=f)\n    \n    And now it is run because the hash of argv[0] has changed:\n    \n    >>> run_if( f'./run_if_test_argv0.sh', f'run_if_test_argv0.out', caller=0)\n    pipcl.py:run_if(): Running command because: arg0 hash has changed.\n    pipcl.py:run_if(): Running: ./run_if_test_argv0.sh\n    True\n    '''\n    doit = False\n    \n    # Path of file containing pickle data for command and hash of command's\n    # first arg.\n    cmd_path = f'{out}.cmd'\n    \n    def hash_get(path):\n        try:\n            with open(path, 'rb') as f:\n                return hashlib.md5(f.read()).hexdigest()\n        except Exception as e:\n            #log(f'Failed to get hash of {path=}: {e}')\n            return None\n    \n    command_args = shlex.split(command or '')\n    command_arg0_path = fs_find_in_paths(command_args[0])\n    command_arg0_hash = hash_get(command_arg0_path)\n    \n    cmd_args, cmd_arg0_hash = (None, None)\n    if os.path.isfile(cmd_path):\n        with open(cmd_path, 'rb') as f:\n            try:\n                cmd_args, cmd_arg0_hash = pickle.load(f)\n            except Exception as e:\n                #log(f'pickle.load() failed with {cmd_path=}: {e}')\n                pass\n\n    if not doit:\n        # Set doit if outfile does not exist.\n        out_mtime = _fs_mtime( out)\n        if out_mtime == 0:\n            doit = f'File does not exist: {out!r}'\n\n    if not doit:\n        # Set doit if command has changed.\n        if command_args != cmd_args:\n            if cmd_args is None:\n                doit = 'No previous command stored'\n            else:\n                doit = f'Command has changed'\n                if 0:\n                    doit += f':\\n    {cmd!r}\\n    {command!r}'\n                if 0:\n                    doit += f'\\nbefore:\\n'\n                    doit += textwrap.indent(cmd, '    ')\n                    doit += f'\\nafter:\\n'\n                    doit += textwrap.indent(command, '    ')\n                if 1:\n                    # Show diff based on commands split into pseudo lines by\n                    # shlex.split().\n                    doit += ':\\n'\n                    lines = difflib.unified_diff(\n                            cmd_args,\n                            command_args,\n                            lineterm='',\n                            )\n                    # Skip initial lines.\n                    assert next(lines) == '--- '\n                    assert next(lines) == '+++ '\n                    for line in lines:\n                        doit += f'    {line}\\n'\n\n    if not doit:\n        # Set doit if argv[0] hash has changed.\n        #print(f'{cmd_arg0_hash=} {command_arg0_hash=}', file=sys.stderr)\n        if command_arg0_hash != cmd_arg0_hash:\n            doit = f'arg0 hash has changed.'\n            #doit = f'arg0 hash has changed from {cmd_arg0_hash=} to {command_arg0_hash=}..'\n    \n    if not doit:\n        # See whether any prerequisites are newer than target.\n        def _make_prerequisites(p):\n            if isinstance( p, (list, tuple)):\n                return list(p)\n            else:\n                return [p]\n        prerequisites_all = list()\n        for p in prerequisites:\n            prerequisites_all += _make_prerequisites( p)\n        if 0:\n            log2( 'prerequisites_all:', caller=caller+1)\n            for i in  prerequisites_all:\n                log2( f'    {i!r}', caller=caller+1)\n        pre_mtime = 0\n        pre_path = None\n        for prerequisite in prerequisites_all:\n            if isinstance( prerequisite, str):\n                mtime = _fs_mtime_newest( prerequisite)\n                if mtime >= pre_mtime:\n                    pre_mtime = mtime\n                    pre_path = prerequisite\n            elif prerequisite is None:\n                pass\n            elif prerequisite:\n                doit = str(prerequisite)\n                break\n        if not doit:\n            if pre_mtime > out_mtime:\n                doit = f'Prerequisite is new: {os.path.abspath(pre_path)!r}'\n\n    if doit:\n        # Remove `cmd_path` before we run the command, so any failure\n        # will force rerun next time.\n        #\n        try:\n            os.remove( cmd_path)\n        except Exception:\n            pass\n        log1( f'Running command because: {doit}', caller=caller+1)\n\n        run( command, caller=caller+1)\n\n        # Write the command we ran, into `cmd_path`.\n        \n        with open(cmd_path, 'wb') as f:\n            pickle.dump((command_args, command_arg0_hash), f)\n        return True\n    else:\n        log1( f'Not running command because up to date: {out!r}', caller=caller+1)\n\n    if 0:\n        log2( f'out_mtime={time.ctime(out_mtime)} pre_mtime={time.ctime(pre_mtime)}.'\n                f' pre_path={pre_path!r}: returning {ret!r}.'\n                )\n\n\ndef fs_find_in_paths( name, paths=None, verbose=False):\n    '''\n    Looks for `name` in paths and returns complete path. `paths` is list/tuple\n    or `os.pathsep`-separated string; if `None` we use `$PATH`. If `name`\n    contains `/`, we return `name` itself if it is a file or None, regardless\n    of <paths>.\n    '''\n    if '/' in name:\n        return name if os.path.isfile( name) else None\n    if paths is None:\n        paths = os.environ.get( 'PATH', '')\n        if verbose:\n            log('From os.environ[\"PATH\"]: {paths=}')\n    if isinstance( paths, str):\n        paths = paths.split( os.pathsep)\n        if verbose:\n            log('After split: {paths=}')\n    for path in paths:\n        p = os.path.join( path, name)\n        if verbose:\n            log('Checking {p=}')\n        if os.path.isfile( p):\n            if verbose:\n                log('Returning because is file: {p!r}')\n            return p\n    if verbose:\n        log('Returning None because not found: {name!r}')\n\n\ndef _get_prerequisites(path):\n    '''\n    Returns list of prerequisites from Makefile-style dependency file, e.g.\n    created by `cc -MD -MF <path>`.\n    '''\n    ret = list()\n    if os.path.isfile(path):\n        with open(path) as f:\n            for line in f:\n                for item in line.split():\n                    if item.endswith( (':', '\\\\')):\n                        continue\n                    ret.append( item)\n    return ret\n\n\ndef _fs_mtime_newest( path):\n    '''\n    path:\n        If a file, returns mtime of the file. If a directory, returns mtime of\n        newest file anywhere within directory tree. Otherwise returns 0.\n    '''\n    ret = 0\n    if os.path.isdir( path):\n        for dirpath, dirnames, filenames in os.walk( path):\n            for filename in filenames:\n                path = os.path.join( dirpath, filename)\n                ret = max( ret, _fs_mtime( path))\n    else:\n        ret = _fs_mtime( path)\n    return ret\n\n\ndef _flags( items, prefix='', quote=''):\n    '''\n    Turns sequence into string, prefixing/quoting each item.\n    '''\n    if not items:\n        return ''\n    if isinstance( items, str):\n        items = items,\n    ret = ''\n    for item in items:\n        if ret:\n            ret += ' '\n        ret += f'{prefix}{quote}{item}{quote}'\n    return ret.strip()\n\n\ndef _fs_mtime( filename, default=0):\n    '''\n    Returns mtime of file, or `default` if error - e.g. doesn't exist.\n    '''\n    try:\n        return os.path.getmtime( filename)\n    except OSError:\n        return default\n\n\ndef _normalise(name):\n    # https://packaging.python.org/en/latest/specifications/name-normalization/#name-normalization\n    return re.sub(r\"[-_.]+\", \"-\", name).lower()\n\n\ndef _normalise2(name):\n    # https://packaging.python.org/en/latest/specifications/binary-distribution-format/\n    return _normalise(name).replace('-', '_')\n\n\ndef _assert_version_pep_440(version):\n    assert re.match(\n                r'^([1-9][0-9]*!)?(0|[1-9][0-9]*)(\\.(0|[1-9][0-9]*))*((a|b|rc)(0|[1-9][0-9]*))?(\\.post(0|[1-9][0-9]*))?(\\.dev(0|[1-9][0-9]*))?$',\n                version,\n            ), \\\n            f'Bad version: {version!r}.'\n\n\ng_verbose = int(os.environ.get('PIPCL_VERBOSE', '1'))\n\ndef verbose(level=None):\n    '''\n    Sets verbose level if `level` is not None.\n    Returns verbose level.\n    '''\n    global g_verbose\n    if level is not None:\n        g_verbose = level\n    return g_verbose\n\ng_log_line_numbers = True\n\ndef log_line_numbers(yes):\n    '''\n    Sets whether to include line numbers; helps with doctest.\n    '''\n    global g_log_line_numbers\n    g_log_line_numbers = bool(yes)\n\ndef log(text='', caller=1):\n    _log(text, 0, caller+1)\n\ndef log0(text='', caller=1):\n    _log(text, 0, caller+1)\n\ndef log1(text='', caller=1):\n    _log(text, 1, caller+1)\n\ndef log2(text='', caller=1):\n    _log(text, 2, caller+1)\n\ndef _log(text, level, caller):\n    '''\n    Logs lines with prefix, if <level> is lower or equal to <g_verbose>.\n    '''\n    if level <= g_verbose:\n        fr = inspect.stack(context=0)[caller]\n        filename = relpath(fr.filename)\n        for line in text.split('\\n'):\n            if g_log_line_numbers:\n                print(f'{filename}:{fr.lineno}:{fr.function}(): {line}', file=sys.stdout, flush=1)\n            else:\n                print(f'{filename}:{fr.function}(): {line}', file=sys.stdout, flush=1)\n\n\ndef relpath(path, start=None, allow_up=True):\n    '''\n    A safe alternative to os.path.relpath(), avoiding an exception on Windows\n    if the drive needs to change - in this case we use os.path.abspath().\n    \n    Args:\n        path:\n            Path to be processed.\n        start:\n            Start directory or current directory if None.\n        allow_up:\n            If false we return absolute path is <path> is not within <start>.\n    '''\n    if windows():\n        try:\n            ret = os.path.relpath(path, start)\n        except ValueError:\n            # os.path.relpath() fails if trying to change drives.\n            ret = os.path.abspath(path)\n    else:\n        ret = os.path.relpath(path, start)\n    if not allow_up and ret.startswith('../') or ret.startswith('..\\\\'):\n        ret = os.path.abspath(path)\n    return ret\n\n\ndef _so_suffix(use_so_versioning=True):\n    '''\n    Filename suffix for shared libraries is defined in pep-3149.  The\n    pep claims to only address posix systems, but the recommended\n    sysconfig.get_config_var('EXT_SUFFIX') also seems to give the\n    right string on Windows.\n    \n    If use_so_versioning is false, we return only the last component of\n    the suffix, which removes any version number, for example changing\n    `.cp312-win_amd64.pyd` to `.pyd`.\n    '''\n    # Example values:\n    #   linux:      .cpython-311-x86_64-linux-gnu.so\n    #   macos:      .cpython-311-darwin.so\n    #   openbsd:    .cpython-310.so\n    #   windows     .cp311-win_amd64.pyd\n    #\n    # Only Linux and Windows seem to identify the cpu. For example shared\n    # libraries in numpy-1.25.2-cp311-cp311-macosx_11_0_arm64.whl are called\n    # things like `numpy/core/_simd.cpython-311-darwin.so`.\n    #\n    ret = sysconfig.get_config_var('EXT_SUFFIX')\n    if not use_so_versioning:\n        # Use last component only.\n        ret = os.path.splitext(ret)[1]\n    return ret\n\n\ndef get_soname(path):\n    '''\n    If we are on Linux and `path` is softlink and points to a shared library\n    for which `objdump -p` contains 'SONAME', return the pointee. Otherwise\n    return `path`. Useful if Linux shared libraries have been created with\n    `-Wl,-soname,...`, where we need to embed the versioned library.\n    '''\n    if linux() and os.path.islink(path):\n        path2 = os.path.realpath(path)\n        if subprocess.run(f'objdump -p {path2}|grep SONAME', shell=1, check=0).returncode == 0:\n            return path2\n    elif openbsd():\n        # Return newest .so with version suffix.\n        sos = glob.glob(f'{path}.*')\n        log1(f'{sos=}')\n        sos2 = list()\n        for so in sos:\n            suffix = so[len(path):]\n            if not suffix or re.match('^[.][0-9.]*[0-9]$', suffix):\n                sos2.append(so)\n        sos2.sort(key=lambda p: os.path.getmtime(p))\n        log1(f'{sos2=}')\n        return sos2[-1]\n    return path\n\n\ndef current_py_limited_api():\n    '''\n    Returns value of PyLIMITED_API to build for current Python.\n    '''\n    a, b = map(int, platform.python_version().split('.')[:2])\n    return f'0x{a:02x}{b:02x}0000'\n    \n\ndef install_dir(root=None):\n    '''\n    Returns install directory used by `install()`.\n\n    This will be `sysconfig.get_path('platlib')`, modified by `root` if not\n    None.\n    '''\n    # todo: for pure-python we should use sysconfig.get_path('purelib') ?\n    root2 = sysconfig.get_path('platlib')\n    if root:\n        if windows():\n            # If we are in a venv, `sysconfig.get_path('platlib')`\n            # can be absolute, e.g.\n            # `C:\\\\...\\\\venv-pypackage-3.11.1-64\\\\Lib\\\\site-packages`, so it's\n            # not clear how to append it to `root`. So we just use `root`.\n            return root\n        else:\n            # E.g. if `root` is `install' and `sysconfig.get_path('platlib')`\n            # is `/usr/local/lib/python3.9/site-packages`, we set `root2` to\n            # `install/usr/local/lib/python3.9/site-packages`.\n            #\n            return os.path.join( root, root2.lstrip( os.sep))\n    else:\n        return root2\n\n\nclass _Record:\n    '''\n    Internal - builds up text suitable for writing to a RECORD item, e.g.\n    within a wheel.\n    '''\n    def __init__(self):\n        self.text = ''\n\n    def add_content(self, content, to_, verbose=True):\n        if isinstance(content, str):\n            content = content.encode('utf8')\n\n        # Specification for the line we write is supposed to be in\n        # https://packaging.python.org/en/latest/specifications/binary-distribution-format\n        # but it's not very clear.\n        #\n        h = hashlib.sha256(content)\n        digest = h.digest()\n        digest = base64.urlsafe_b64encode(digest)\n        digest = digest.rstrip(b'=')\n        digest = digest.decode('utf8')\n\n        self.text += f'{to_},sha256={digest},{len(content)}\\n'\n        if verbose:\n            log2(f'Adding {to_}')\n\n    def add_file(self, from_, to_):\n        log1(f'Adding file: {os.path.relpath(from_)} => {to_}')\n        with open(from_, 'rb') as f:\n            content = f.read()\n        self.add_content(content, to_, verbose=False)\n\n    def get(self, record_path=None):\n        '''\n        Returns contents of the RECORD file. If `record_path` is\n        specified we append a final line `<record_path>,,`; this can be\n        used to include the RECORD file itself in the contents, with\n        empty hash and size fields.\n        '''\n        ret = self.text\n        if record_path:\n            ret += f'{record_path},,\\n'\n        return ret\n\n\nclass NewFiles:\n    '''\n    Detects new/modified/updated files matching a glob pattern. Useful for\n    detecting wheels created by pip or cubuildwheel etc.\n    '''\n    def __init__(self, glob_pattern):\n        # Find current matches of <glob_pattern>.\n        self.glob_pattern = glob_pattern\n        self.items0 = self._items()\n    def get(self):\n        '''\n        Returns list of new matches of <glob_pattern> - paths of files that\n        were not present previously, or have different mtimes or have different\n        contents.\n        '''\n        ret = list()\n        items = self._items()\n        for path, id_ in items.items():\n            id0 = self.items0.get(path)\n            if id0 != id_:\n                ret.append(path)\n        return ret\n    def get_n(self, n):\n        '''\n        Returns new files matching <glob_pattern>, asserting that there are\n        exactly <n>.\n        '''\n        ret = self.get()\n        assert len(ret) == n, f'{len(ret)=}: {ret}'\n        return ret\n    def get_one(self):\n        '''\n        Returns new match of <glob_pattern>, asserting that there is exactly\n        one.\n        '''\n        return self.get_n(1)[0]\n    def _file_id(self, path):\n        mtime = os.stat(path).st_mtime\n        with open(path, 'rb') as f:\n            content = f.read()\n            hash_ = hashlib.md5(content).digest()\n            # With python >= 3.11 we can do:\n            #hash_ = hashlib.file_digest(f, hashlib.md5).digest()\n        return mtime, hash_\n    def _items(self):\n        ret = dict()\n        for path in glob.glob(self.glob_pattern):\n            if os.path.isfile(path):\n                ret[path] = self._file_id(path)\n        return ret\n\n\ndef swig_get(swig, quick, swig_local='pipcl-swig-git'):\n    '''\n    Returns <swig> or a new swig binary.\n    \n    If <swig> is true and starts with 'git:' (not Windows), the remaining text\n    is passed to git_get() and we clone/update/build swig, and return the built\n    binary. We default to the main swig repository, branch master, so for\n    example 'git:' will return the latest swig from branch master.\n    \n    Otherwise we simply return <swig>.\n    \n    Args:\n        swig:\n            If starts with 'git:', passed as <text> arg to git_get().\n        quick:\n            If true, we do not update/build local checkout if the binary is\n            already present.\n        swig_local:\n            path to use for checkout.\n    '''\n    if swig and swig.startswith('git:'):\n        assert platform.system() != 'Windows', f'Cannot build swig on Windows.'\n        # Note that {swig_local}/install/bin/swig doesn't work on MacOS because\n        # {swig_local}/INSTALL is a file and the fs is case-insensitive.\n        swig_binary = f'{swig_local}/install-dir/bin/swig'\n        if quick and os.path.isfile(swig_binary):\n            log1(f'{quick=} and {swig_binary=} already exists, so not downloading/building.')\n        else:\n            if darwin():\n                run(f'brew install automake')\n                run(f'brew install pcre2')\n                run(f'brew install bison')\n                # Default bison doesn't work, and Brew's bison is not added to $PATH.\n                #\n                # > bison is keg-only, which means it was not symlinked into /opt/homebrew,\n                # > because macOS already provides this software and installing another version in\n                # > parallel can cause all kinds of trouble.\n                # > \n                # > If you need to have bison first in your PATH, run:\n                # >   echo 'export PATH=\"/opt/homebrew/opt/bison/bin:$PATH\"' >> ~/.zshrc\n                #\n                swig_env_extra = dict()\n                macos_add_brew_path('bison', swig_env_extra)\n                run(f'which bison')\n                run(f'which bison', env_extra=swig_env_extra)\n            \n            # Building swig requires bison>=3.5.\n            bison_ok = 0\n            e, text = run(f'bison --version', capture=1, check=0, env_extra=swig_env_extra)\n            if not e:\n                log(textwrap.indent(text, '    '))\n                m = re.search('bison (GNU Bison) ([0-9]+)[.]([0-9]+)', text)\n                if m:\n                    assert m, f'Unexpected output from `bison --version`: {text!r}'\n                    version_tuple = int(m.group(1)), int(m.group2())\n                    if version_tuple >= (3, 5):\n                        bison_ok = 1\n            if not bison_ok:\n                if 0:\n                    # Use git checkout. Fails to find scan-code.c. Presumably\n                    # something wrong with ./bootstrap?\n                    log(f'Cloning/fetching/build/installing bison.')\n                    bison_git = git_get(\n                            'pipcl-bison-git',\n                            remote='https://git.savannah.gnu.org/git/bison.git',\n                            #branch='master',\n                            tag='v3.5.4',\n                            submodules=0, # recursive update fails.\n                            )\n                    run(f'cd {bison_git} && git submodule update --init', prefix='bison git submodule update --init: ')\n                    run(f'cd {bison_git} && ./bootstrap', prefix='bison bootstrap: ')\n                    run(f'cd {bison_git} && ./configure', prefix='bison configure: ')\n                    run(f'cd {bison_git} && make', prefix='bison make: ')\n                    run(f'cd {bison_git} && sudo make install', prefix='bison make install: ')\n                else:\n                    bison_version = 'bison-3.5.4'\n                    if not os.path.exists(f'{bison_version}.tar.gz'):\n                        run(\n                                f'wget -O {bison_version}.tar.gz-0 http://www.mirrorservice.org/sites/ftp.gnu.org/gnu/bison/{bison_version}.tar.gz',\n                                prefix='bison wget: ',\n                                )\n                        os.rename(f'{bison_version}.tar.gz-0', f'{bison_version}.tar.gz')\n                    if not os.path.exists(f'{bison_version}'):\n                        run(f'tar -xzf {bison_version}.tar.gz', prefix='bison extract: ')\n                    run(f'cd {bison_version} && ./configure', prefix='bison configure: ')\n                    run(f'cd {bison_version} && make', prefix='bison make: ')\n                    run(f'cd {bison_version} && sudo make install', prefix='bison make install: ')\n                \n            # Clone swig.\n            swig_env_extra = None\n            swig_local = git_get(\n                    swig_local,\n                    text=swig,\n                    remote='https://github.com/swig/swig.git',\n                    branch='master',\n                    )\n            # Build swig.\n            run(f'cd {swig_local} && ./autogen.sh', env_extra=swig_env_extra)\n            run(f'cd {swig_local} && ./configure --prefix={swig_local}/install-dir', env_extra=swig_env_extra)\n            run(f'cd {swig_local} && make', env_extra=swig_env_extra)\n            run(f'cd {swig_local} && make install', env_extra=swig_env_extra)\n        assert os.path.isfile(swig_binary)\n        return swig_binary\n    else:\n        return swig\n\n\ndef macos_add_brew_path(package, env=None, gnubin=True):\n    '''\n    Adds path(s) for Brew <package>'s binaries to env['PATH'].\n    \n    We assert-fail if the relevant directory does no exist.\n    \n    Args:\n        package:\n            Name of package. We get <package_root> of installed package by\n            running `brew --prefix <package>`.\n        env:\n            The environment dict to modify. If None we use os.environ. If PATH\n            is not in <env>, we first copy os.environ['PATH'] into <env>.\n        gnubin:\n            If true, we also add path to gnu binaries if it exists,\n            <package_root>/libexe/gnubin.\n    '''\n    if not darwin():\n        return\n    if env is None:\n        env = os.environ\n    if 'PATH' not in env:\n        env['PATH'] = os.environ['PATH']\n    package_root = run(f'brew --prefix {package}', capture=1).strip()\n    log(f'{package=} {package_root=}')\n    def add(path):\n        log(f'{path=}')\n        if os.path.isdir(path):\n            log(f'Prepending to $PATH: {path}')\n            PATH = env['PATH']\n            env['PATH'] = f'{path}:{PATH}'\n            return 1\n        else:\n            log(f'Not a directory: {path=}')\n            return 0\n    n = 0\n    n += add(f'{package_root}/bin')\n    if gnubin:\n        n += add(f'{package_root}/libexec/gnubin')\n    assert n, f'Failed to add to $PATH, {package=} {gnubin=}.'\n\n\ndef _show_dict(d):\n    ret = ''\n    for n in sorted(d.keys()):\n        v = d[n]\n        ret += f'    {n}: {v!r}\\n'\n    return ret\n\ndef show_sysconfig():\n    '''\n    Shows contents of sysconfig.get_paths() and sysconfig.get_config_vars() dicts.\n    '''\n    import sysconfig\n    paths = sysconfig.get_paths()\n    log0(f'show_sysconfig().')\n    log0(f'sysconfig.get_paths():\\n{_show_dict(sysconfig.get_paths())}')\n    log0(f'sysconfig.get_config_vars():\\n{_show_dict(sysconfig.get_config_vars())}')\n\n\ndef sysconfig_python_flags():\n    '''\n    Returns include paths and library directory for Python.\n    \n    Uses sysconfig.*(), overridden by environment variables\n    PIPCL_SYSCONFIG_PATH_include, PIPCL_SYSCONFIG_PATH_platinclude and\n    PIPCL_SYSCONFIG_CONFIG_VAR_LIBDIR if set.\n    '''\n    include1_ = os.environ.get('PIPCL_SYSCONFIG_PATH_include') or sysconfig.get_path('include')\n    include2_ = os.environ.get('PIPCL_SYSCONFIG_PATH_platinclude') or sysconfig.get_path('platinclude')\n    ldflags_ = os.environ.get('PIPCL_SYSCONFIG_CONFIG_VAR_LIBDIR') or sysconfig.get_config_var('LIBDIR')\n\n    includes_ = [include1_]\n    if include2_ != include1_:\n        includes_.append(include2_)\n    if windows():\n        includes_ = [f'/I\"{i}\"' for i in includes_]\n        ldflags_ = f'/LIBPATH:\"{ldflags_}\"'\n    else:\n        includes_ = [f'-I {i}' for i in includes_]\n        ldflags_ = f'-L {ldflags_}'\n    includes_ = ' '.join(includes_)\n    return includes_, ldflags_\n\n\ndef venv_in(path=None):\n    '''\n    If path is None, returns true if we are in a venv. Otherwise returns true\n    only if we are in venv <path>.\n    '''\n    if path:\n        return os.path.abspath(sys.prefix) == os.path.abspath(path)\n    else:\n        return sys.prefix != sys.base_prefix\n\n\ndef venv_run(args, path, recreate=True, clean=False):\n    '''\n    Runs Python command inside venv and returns termination code.\n    \n    Args:\n        args:\n            List of args or string command.\n        path:\n            Path of venv directory.\n        recreate:\n            If false we do not run `<sys.executable> -m venv <path>` if <path>\n            already exists. This avoids a delay in the common case where <path>\n            is already set up, but fails if <path> exists but does not contain\n            a valid venv.\n        clean:\n            If true we first delete <path>.\n    '''\n    if clean:\n        log(f'Removing any existing venv {path}.')\n        assert path.startswith('venv-')\n        shutil.rmtree(path, ignore_errors=1)\n    if recreate or not os.path.isdir(path):\n        run(f'{sys.executable} -m venv {path}')\n    \n    if isinstance(args, str):\n        args_string = args\n    elif platform.system() == 'Windows':\n        # shlex not reliable on Windows so we use Use crude quoting with \"...\".\n        args_string = ''\n        for i, arg in enumerate(args):\n            assert '\"' not in arg\n            if i:\n                args_string += ' '\n            args_string += f'\"{arg}\"'\n    else:\n        args_string = shlex.join(args)\n    \n    if platform.system() == 'Windows':\n        command = f'{path}\\\\Scripts\\\\activate && python {args_string}'\n    else:\n        command = f'. {path}/bin/activate && python {args_string}'\n    e = run(command, check=0)\n    return e\n\n\nif __name__ == '__main__':\n    # Internal-only limited command line support, used if\n    # graal_legacy_python_config is true.\n    #\n    includes, ldflags = sysconfig_python_flags()\n    if sys.argv[1] == '--doctest':\n        import doctest\n        if sys.argv[2:]:\n            for f in sys.argv[2:]:\n                ff = globals()[f]\n                doctest.run_docstring_examples(ff, globals())\n        else:\n            doctest.testmod(None)\n    elif sys.argv[1:] == ['--graal-legacy-python-config', '--includes']:\n        print(includes)\n    elif sys.argv[1:] == ['--graal-legacy-python-config', '--ldflags']:\n        print(ldflags)\n    else:\n        assert 0, f'Expected `--graal-legacy-python-config --includes|--ldflags` but {sys.argv=}'\n"
  },
  {
    "path": "src/pymupdf.py",
    "content": "# pylint: disable=wildcard-import,unused-import\nfrom . import *\n"
  },
  {
    "path": "src/table.py",
    "content": "\"\"\"\nCopyright (C) 2023 Artifex Software, Inc.\n\nThis file is part of PyMuPDF.\n\nPyMuPDF is free software: you can redistribute it and/or modify it under the\nterms of the GNU Affero General Public License as published by the Free\nSoftware Foundation, either version 3 of the License, or (at your option)\nany later version.\n\nPyMuPDF is distributed in the hope that it will be useful, but WITHOUT ANY\nWARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\nFOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\ndetails.\n\nYou should have received a copy of the GNU Affero General Public License\nalong with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>\n\nAlternative licensing terms are available from the licensor.\nFor commercial licensing, see <https://www.artifex.com/> or contact\nArtifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,\nCA 94129, USA, for further information.\n\n---------------------------------------------------------------------\nPortions of this code have been ported from pdfplumber, see\nhttps://pypi.org/project/pdfplumber/.\n\nThe ported code is under the following MIT license:\n\n---------------------------------------------------------------------\nThe MIT License (MIT)\n\nCopyright (c) 2015, Jeremy Singer-Vine\n\nPermission is hereby granted, free of charge, to any person obtaining a copy\nof this software and associated documentation files (the \"Software\"), to deal\nin the Software without restriction, including without limitation the rights\nto use, copy, modify, merge, publish, distribute, sublicense, and/or sell\ncopies of the Software, and to permit persons to whom the Software is\nfurnished to do so, subject to the following conditions:\n\nThe above copyright notice and this permission notice shall be included in all\ncopies or substantial portions of the Software.\n\nTHE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR\nIMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,\nFITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE\nAUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER\nLIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,\nOUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE\nSOFTWARE.\n---------------------------------------------------------------------\nAlso see here: https://github.com/jsvine/pdfplumber/blob/stable/LICENSE.txt\n---------------------------------------------------------------------\n\nThe porting mainly pertains to files \"table.py\" and relevant parts of\n\"utils/text.py\" within pdfplumber's repository on Github.\nWith respect to \"text.py\", we have removed functions or features that are not\nused by table processing. Examples are:\n\n* the text search function\n* simple text extraction\n* text extraction by lines\n\nOriginal pdfplumber code does neither detect, nor identify table headers.\nThis PyMuPDF port adds respective code to the 'Table' class as method '_get_header'.\nThis is implemented as new class TableHeader with the properties:\n* bbox: A tuple for the header's bbox\n* cells: A tuple for each bbox of a column header\n* names: A list of strings with column header text\n* external: A bool indicating whether the header is outside the table cells.\n\n\"\"\"\n\nimport inspect\nimport itertools\nimport string\nimport html\nfrom collections.abc import Sequence\nfrom dataclasses import dataclass\nfrom operator import itemgetter\nimport weakref\nimport pymupdf\nfrom pymupdf import mupdf\n\n# -------------------------------------------------------------------\n# Start of PyMuPDF interface code\n# -------------------------------------------------------------------\n\n# pylint: disable=no-name-in-module\n\nEDGES = []  # vector graphics from PyMuPDF\nCHARS = []  # text characters from PyMuPDF\nTEXTPAGE = None  # textpage for cell text extraction\nTEXT_BOLD = mupdf.FZ_STEXT_BOLD\nTEXT_STRIKEOUT = mupdf.FZ_STEXT_STRIKEOUT\nFLAGS = (\n    0\n    | pymupdf.TEXTFLAGS_TEXT\n    | pymupdf.TEXT_COLLECT_STYLES\n    | pymupdf.TEXT_ACCURATE_BBOXES\n    | pymupdf.TEXT_MEDIABOX_CLIP\n)\n# needed by mupdf function fz_find_table_within_bounds().\nTABLE_DETECTOR_FLAGS = (\n    0\n    | pymupdf.TEXT_ACCURATE_BBOXES\n    | pymupdf.TEXT_SEGMENT\n    | pymupdf.TEXT_COLLECT_VECTORS\n    | pymupdf.TEXT_MEDIABOX_CLIP\n)\nwhite_spaces = set(string.whitespace)  # for checking white space only cells\n\n\ndef rect_in_rect(inner, outer):\n    \"\"\"Check whether rectangle 'inner' is fully inside rectangle 'outer'.\"\"\"\n    return (\n        1\n        and inner[0] >= outer[0]\n        and inner[1] >= outer[1]\n        and inner[2] <= outer[2]\n        and inner[3] <= outer[3]\n    )\n\n\ndef chars_in_rect(CHARS, rect):\n    \"\"\"Check whether any of the chars in CHAR are inside rectangle 'rect'.\"\"\"\n    return any(\n        1\n        and rect[0] <= c[\"x0\"]\n        and c[\"x1\"] <= rect[2]\n        and rect[1] <= c[\"y0\"]\n        and rect[3] >= c[\"y1\"]\n        for c in CHARS\n    )\n\n\ndef _iou(r1, r2):\n    \"\"\"Compute intersection over union of two rectangles.\"\"\"\n    ix = max(0, min(r1[2], r2[2]) - max(r1[0], r2[0]))\n    iy = max(0, min(r1[3], r2[3]) - max(r1[1], r2[1]))\n    intersection = ix * iy  # intersection area\n    if not intersection:\n        return 0\n    area1 = (r1[2] - r1[0]) * (r1[3] - r1[1])\n    area2 = (r2[2] - r2[0]) * (r2[3] - r2[1])\n    return intersection / (area1 + area2 - intersection)\n\n\ndef intersects_words_h(bbox, y, word_rects) -> bool:\n    \"\"\"Check whether any of the words in bbox are cut through by\n    horizontal line y.\n    \"\"\"\n    return any(r.y0 < y < r.y1 for r in word_rects if rect_in_rect(r, bbox))\n\n\ndef get_table_dict_from_rect(textpage, rect):\n    \"\"\"Extract MuPDF table structure information from a given rectangle.\"\"\"\n    table_dict = {}\n    pymupdf.extra.make_table_dict(textpage.this.m_internal, table_dict, rect)\n    return table_dict\n\n\ndef make_table_from_bbox(textpage, word_rects, rect):\n    \"\"\"Detect table structure within a given rectangle.\"\"\"\n    cells = []  # table cells as (x0,y0,x1,y1) tuples\n\n    # calls fz_find_table_within_bounds\n    block = get_table_dict_from_rect(textpage, rect)\n    # No table structure found if not a grid block\n    if block.get(\"type\") != mupdf.FZ_STEXT_BLOCK_GRID:\n        return cells\n    bbox = pymupdf.Rect(block[\"bbox\"])  # resulting table bbox\n\n    # lists of (pos,uncertainty) tuples\n    xpos = sorted(block[\"xpos\"], key=lambda x: x[0])\n    ypos = sorted(block[\"ypos\"], key=lambda y: y[0])\n\n    # maximum uncertainties in x and y directions\n    xmaxu, ymaxu = block[\"max_uncertain\"]\n\n    # Modify ypos to remove uncertain positions, and y positions\n    # that cut through words.\n    nypos = []\n    for y, yunc in ypos:\n        if yunc > 0:  # allow no uncertain y values\n            continue\n        if intersects_words_h(bbox, y, word_rects):\n            continue  # allow no y that cuts through words\n        if nypos and (y - nypos[-1] < 3):\n            nypos[-1] = y  # snap close positions\n        else:\n            nypos.append(y)\n\n    # New max y uncertainty: 35% of remaining y positions.\n    # Omit x positions that intersect too many words, otherwise\n    # only remove x for the affected cells.\n    ymaxu = max(0, round((len(nypos) - 2) * 0.35))\n\n    # Exclude x positions with too high uncertainty\n    # (we allow more uncertainty in x direction)\n    nxpos = [x[0] for x in xpos if x[1] <= ymaxu]\n    if bbox.x1 > nxpos[-1] + 3:\n        nxpos.append(bbox.x1)  # ensure right table border\n\n    # Compose cells from the remaining x and y positions.\n    for i in range(len(nypos) - 1):\n        row_box = pymupdf.Rect(bbox.x0, nypos[i], bbox.x1, nypos[i + 1])\n        # Sub-select words in this row and sort them by left coordinate\n        row_words = sorted(\n            [r for r in word_rects if rect_in_rect(r, row_box)], key=lambda r: r.x0\n        )\n        # Sub-select x values that do not cut through words\n        this_xpos = [x for x in nxpos if not any(r.x0 < x < r.x1 for r in row_words)]\n        for j in range(len(this_xpos) - 1):\n            cell = pymupdf.Rect(this_xpos[j], nypos[i], this_xpos[j + 1], nypos[i + 1])\n            if not cell.is_empty:  # valid cell\n                cells.append(tuple(cell))\n    # Add new table to TableFinder tables\n    return cells\n\n\ndef extract_cells(textpage, cell, markdown=False):\n    \"\"\"Extract text from a rect-like 'cell' as plain or MD styled text.\n\n    This function should ultimately be used to extract text from a table cell.\n    Markdown output will only work correctly if extraction flag bit\n    TEXT_COLLECT_STYLES is set.\n\n    Args:\n        textpage: A PyMuPDF TextPage object. Must have been created with\n            TEXTFLAGS_TEXT | TEXT_COLLECT_STYLES.\n        cell: A tuple (x0, y0, x1, y1) defining the cell's bbox.\n        markdown: If True, return text formatted for Markdown.\n\n    Returns:\n        A string with the text extracted from the cell.\n    \"\"\"\n    text = \"\"\n    for block in textpage.extractRAWDICT()[\"blocks\"]:\n        if block[\"type\"] != 0:\n            continue\n        block_bbox = block[\"bbox\"]\n        if (\n            0\n            or block_bbox[0] > cell[2]\n            or block_bbox[2] < cell[0]\n            or block_bbox[1] > cell[3]\n            or block_bbox[3] < cell[1]\n        ):\n            continue  # skip block outside cell\n        for line in block[\"lines\"]:\n            lbbox = line[\"bbox\"]\n            if (\n                0\n                or lbbox[0] > cell[2]\n                or lbbox[2] < cell[0]\n                or lbbox[1] > cell[3]\n                or lbbox[3] < cell[1]\n            ):\n                continue  # skip line outside cell\n\n            if text:  # must be a new line in the cell\n                text += \"<br>\" if markdown else \"\\n\"\n\n            # strikeout detection only works with horizontal text\n            horizontal = line[\"dir\"] == (0, 1) or line[\"dir\"] == (1, 0)\n\n            for span in line[\"spans\"]:\n                sbbox = span[\"bbox\"]\n                if (\n                    0\n                    or sbbox[0] > cell[2]\n                    or sbbox[2] < cell[0]\n                    or sbbox[1] > cell[3]\n                    or sbbox[3] < cell[1]\n                ):\n                    continue  # skip spans outside cell\n\n                # only include chars with more than 50% bbox overlap\n                span_text = \"\"\n                for char in span[\"chars\"]:\n                    this_char = char[\"c\"]\n                    bbox = pymupdf.Rect(char[\"bbox\"])\n                    if abs(bbox & cell) > 0.5 * abs(bbox):\n                        span_text += this_char\n                    elif this_char in white_spaces:\n                        span_text += \" \"\n\n                if not span_text:\n                    continue  # skip empty span\n\n                if not markdown:  # no MD styling\n                    text += span_text\n                    continue\n\n                prefix = \"\"\n                suffix = \"\"\n                if horizontal and span[\"char_flags\"] & TEXT_STRIKEOUT:\n                    prefix += \"~~\"\n                    suffix = \"~~\" + suffix\n                if span[\"char_flags\"] & TEXT_BOLD:\n                    prefix += \"**\"\n                    suffix = \"**\" + suffix\n                if span[\"flags\"] & pymupdf.TEXT_FONT_ITALIC:\n                    prefix += \"_\"\n                    suffix = \"_\" + suffix\n                if span[\"flags\"] & pymupdf.TEXT_FONT_MONOSPACED:\n                    prefix += \"`\"\n                    suffix = \"`\" + suffix\n\n                if len(span[\"chars\"]) > 2:\n                    span_text = span_text.rstrip()\n\n                # if span continues previous styling: extend cell text\n                if (ls := len(suffix)) and text.endswith(suffix):\n                    text = text[:-ls] + span_text + suffix\n                else:  # append the span with new styling\n                    if not span_text.strip():\n                        text += \" \"\n                    else:\n                        text += prefix + span_text + suffix\n\n    return text.strip()\n\n\n# -------------------------------------------------------------------\n# End of PyMuPDF interface code\n# -------------------------------------------------------------------\n\n\nclass UnsetFloat(float):\n    pass\n\n\nNON_NEGATIVE_SETTINGS = [\n    \"snap_tolerance\",\n    \"snap_x_tolerance\",\n    \"snap_y_tolerance\",\n    \"join_tolerance\",\n    \"join_x_tolerance\",\n    \"join_y_tolerance\",\n    \"edge_min_length\",\n    \"min_words_vertical\",\n    \"min_words_horizontal\",\n    \"intersection_tolerance\",\n    \"intersection_x_tolerance\",\n    \"intersection_y_tolerance\",\n]\n\n\nTABLE_STRATEGIES = [\"lines\", \"lines_strict\", \"text\", \"explicit\"]\nUNSET = UnsetFloat(0)\nDEFAULT_SNAP_TOLERANCE = 3\nDEFAULT_JOIN_TOLERANCE = 3\nDEFAULT_MIN_WORDS_VERTICAL = 3\nDEFAULT_MIN_WORDS_HORIZONTAL = 1\nDEFAULT_X_TOLERANCE = 3\nDEFAULT_Y_TOLERANCE = 3\nDEFAULT_X_DENSITY = 7.25\nDEFAULT_Y_DENSITY = 13\nbbox_getter = itemgetter(\"x0\", \"top\", \"x1\", \"bottom\")\n\n\nLIGATURES = {\n    \"ﬀ\": \"ff\",\n    \"ﬃ\": \"ffi\",\n    \"ﬄ\": \"ffl\",\n    \"ﬁ\": \"fi\",\n    \"ﬂ\": \"fl\",\n    \"ﬆ\": \"st\",\n    \"ﬅ\": \"st\",\n}\n\n\ndef to_list(collection) -> list:\n    if isinstance(collection, list):\n        return collection\n    elif isinstance(collection, Sequence):\n        return list(collection)\n    elif hasattr(collection, \"to_dict\"):\n        res = collection.to_dict(\"records\")  # pragma: nocover\n        return res\n    else:\n        return list(collection)\n\n\nclass TextMap:\n    \"\"\"\n    A TextMap maps each unicode character in the text to an individual `char`\n    object (or, in the case of layout-implied whitespace, `None`).\n    \"\"\"\n\n    def __init__(self, tuples=None) -> None:\n        self.tuples = tuples\n        self.as_string = \"\".join(map(itemgetter(0), tuples))\n\n    def match_to_dict(\n        self,\n        m,\n        main_group: int = 0,\n        return_groups: bool = True,\n        return_chars: bool = True,\n    ) -> dict:\n        subset = self.tuples[m.start(main_group) : m.end(main_group)]\n        chars = [c for (text, c) in subset if c is not None]\n        x0, top, x1, bottom = objects_to_bbox(chars)\n\n        result = {\n            \"text\": m.group(main_group),\n            \"x0\": x0,\n            \"top\": top,\n            \"x1\": x1,\n            \"bottom\": bottom,\n        }\n\n        if return_groups:\n            result[\"groups\"] = m.groups()\n\n        if return_chars:\n            result[\"chars\"] = chars\n\n        return result\n\n\nclass WordMap:\n    \"\"\"\n    A WordMap maps words->chars.\n    \"\"\"\n\n    def __init__(self, tuples) -> None:\n        self.tuples = tuples\n\n    def to_textmap(\n        self,\n        layout: bool = False,\n        layout_width=0,\n        layout_height=0,\n        layout_width_chars: int = 0,\n        layout_height_chars: int = 0,\n        x_density=DEFAULT_X_DENSITY,\n        y_density=DEFAULT_Y_DENSITY,\n        x_shift=0,\n        y_shift=0,\n        y_tolerance=DEFAULT_Y_TOLERANCE,\n        use_text_flow: bool = False,\n        presorted: bool = False,\n        expand_ligatures: bool = True,\n    ) -> TextMap:\n        \"\"\"\n        Given a list of (word, chars) tuples (i.e., a WordMap), return a list of\n        (char-text, char) tuples (i.e., a TextMap) that can be used to mimic the\n        structural layout of the text on the page(s), using the following approach:\n\n        - Sort the words by (doctop, x0) if not already sorted.\n\n        - Calculate the initial doctop for the starting page.\n\n        - Cluster the words by doctop (taking `y_tolerance` into account), and\n          iterate through them.\n\n        - For each cluster, calculate the distance between that doctop and the\n          initial doctop, in points, minus `y_shift`. Divide that distance by\n          `y_density` to calculate the minimum number of newlines that should come\n          before this cluster. Append that number of newlines *minus* the number of\n          newlines already appended, with a minimum of one.\n\n        - Then for each cluster, iterate through each word in it. Divide each\n          word's x0, minus `x_shift`, by `x_density` to calculate the minimum\n          number of characters that should come before this cluster.  Append that\n          number of spaces *minus* the number of characters and spaces already\n          appended, with a minimum of one. Then append the word's text.\n\n        - At the termination of each line, add more spaces if necessary to\n          mimic `layout_width`.\n\n        - Finally, add newlines to the end if necessary to mimic to\n          `layout_height`.\n\n        Note: This approach currently works best for horizontal, left-to-right\n        text, but will display all words regardless of orientation. There is room\n        for improvement in better supporting right-to-left text, as well as\n        vertical text.\n        \"\"\"\n        _textmap = []\n\n        if not len(self.tuples):\n            return TextMap(_textmap)\n\n        expansions = LIGATURES if expand_ligatures else {}\n\n        if layout:\n            if layout_width_chars:\n                if layout_width:\n                    raise ValueError(\n                        \"`layout_width` and `layout_width_chars` cannot both be set.\"\n                    )\n            else:\n                layout_width_chars = int(round(layout_width / x_density))\n\n            if layout_height_chars:\n                if layout_height:\n                    raise ValueError(\n                        \"`layout_height` and `layout_height_chars` cannot both be set.\"\n                    )\n            else:\n                layout_height_chars = int(round(layout_height / y_density))\n\n            blank_line = [(\" \", None)] * layout_width_chars\n        else:\n            blank_line = []\n\n        num_newlines = 0\n\n        words_sorted_doctop = (\n            self.tuples\n            if presorted or use_text_flow\n            else sorted(self.tuples, key=lambda x: float(x[0][\"doctop\"]))\n        )\n\n        first_word = words_sorted_doctop[0][0]\n        doctop_start = first_word[\"doctop\"] - first_word[\"top\"]\n\n        for i, ws in enumerate(\n            cluster_objects(\n                words_sorted_doctop, lambda x: float(x[0][\"doctop\"]), y_tolerance\n            )\n        ):\n            y_dist = (\n                (ws[0][0][\"doctop\"] - (doctop_start + y_shift)) / y_density\n                if layout\n                else 0\n            )\n            num_newlines_prepend = max(\n                # At least one newline, unless this iis the first line\n                int(i > 0),\n                # ... or as many as needed to get the imputed \"distance\" from the top\n                round(y_dist) - num_newlines,\n            )\n\n            for i in range(num_newlines_prepend):\n                if not len(_textmap) or _textmap[-1][0] == \"\\n\":\n                    _textmap += blank_line\n                _textmap.append((\"\\n\", None))\n\n            num_newlines += num_newlines_prepend\n\n            line_len = 0\n\n            line_words_sorted_x0 = (\n                ws\n                if presorted or use_text_flow\n                else sorted(ws, key=lambda x: float(x[0][\"x0\"]))\n            )\n\n            for word, chars in line_words_sorted_x0:\n                x_dist = (word[\"x0\"] - x_shift) / x_density if layout else 0\n                num_spaces_prepend = max(min(1, line_len), round(x_dist) - line_len)\n                _textmap += [(\" \", None)] * num_spaces_prepend\n                line_len += num_spaces_prepend\n\n                for c in chars:\n                    letters = expansions.get(c[\"text\"], c[\"text\"])\n                    for letter in letters:\n                        _textmap.append((letter, c))\n                        line_len += 1\n\n            # Append spaces at end of line\n            if layout:\n                _textmap += [(\" \", None)] * (layout_width_chars - line_len)\n\n        # Append blank lines at end of text\n        if layout:\n            num_newlines_append = layout_height_chars - (num_newlines + 1)\n            for i in range(num_newlines_append):\n                if i > 0:\n                    _textmap += blank_line\n                _textmap.append((\"\\n\", None))\n\n            # Remove terminal newline\n            if _textmap[-1] == (\"\\n\", None):\n                _textmap = _textmap[:-1]\n\n        return TextMap(_textmap)\n\n\nclass WordExtractor:\n    def __init__(\n        self,\n        x_tolerance=DEFAULT_X_TOLERANCE,\n        y_tolerance=DEFAULT_Y_TOLERANCE,\n        keep_blank_chars: bool = False,\n        use_text_flow=False,\n        horizontal_ltr=True,  # Should words be read left-to-right?\n        vertical_ttb=False,  # Should vertical words be read top-to-bottom?\n        extra_attrs=None,\n        split_at_punctuation=False,\n        expand_ligatures=True,\n    ):\n        self.x_tolerance = x_tolerance\n        self.y_tolerance = y_tolerance\n        self.keep_blank_chars = keep_blank_chars\n        self.use_text_flow = use_text_flow\n        self.horizontal_ltr = horizontal_ltr\n        self.vertical_ttb = vertical_ttb\n        self.extra_attrs = [] if extra_attrs is None else extra_attrs\n\n        # Note: string.punctuation = '!\"#$%&\\'()*+,-./:;<=>?@[\\\\]^_`{|}~'\n        self.split_at_punctuation = (\n            string.punctuation\n            if split_at_punctuation is True\n            else (split_at_punctuation or \"\")\n        )\n\n        self.expansions = LIGATURES if expand_ligatures else {}\n\n    def merge_chars(self, ordered_chars: list):\n        x0, top, x1, bottom = objects_to_bbox(ordered_chars)\n        doctop_adj = ordered_chars[0][\"doctop\"] - ordered_chars[0][\"top\"]\n        upright = ordered_chars[0][\"upright\"]\n        direction = 1 if (self.horizontal_ltr if upright else self.vertical_ttb) else -1\n\n        matrix = ordered_chars[0][\"matrix\"]\n\n        rotation = 0\n        if not upright and matrix[1] < 0:\n            ordered_chars = reversed(ordered_chars)\n            rotation = 270\n\n        if matrix[0] < 0 and matrix[3] < 0:\n            rotation = 180\n        elif matrix[1] > 0:\n            rotation = 90\n\n        word = {\n            \"text\": \"\".join(\n                self.expansions.get(c[\"text\"], c[\"text\"]) for c in ordered_chars\n            ),\n            \"x0\": x0,\n            \"x1\": x1,\n            \"top\": top,\n            \"doctop\": top + doctop_adj,\n            \"bottom\": bottom,\n            \"upright\": upright,\n            \"direction\": direction,\n            \"rotation\": rotation,\n        }\n\n        for key in self.extra_attrs:\n            word[key] = ordered_chars[0][key]\n\n        return word\n\n    def char_begins_new_word(\n        self,\n        prev_char,\n        curr_char,\n    ) -> bool:\n        \"\"\"This method takes several factors into account to determine if\n        `curr_char` represents the beginning of a new word:\n\n        - Whether the text is \"upright\" (i.e., non-rotated)\n        - Whether the user has specified that horizontal text runs\n          left-to-right (default) or right-to-left, as represented by\n          self.horizontal_ltr\n        - Whether the user has specified that vertical text the text runs\n          top-to-bottom (default) or bottom-to-top, as represented by\n          self.vertical_ttb\n        - The x0, top, x1, and bottom attributes of prev_char and\n          curr_char\n        - The self.x_tolerance and self.y_tolerance settings. Note: In\n          this case, x/y refer to those directions for non-rotated text.\n          For vertical text, they are flipped. A more accurate terminology\n          might be \"*intra*line character distance tolerance\" and\n          \"*inter*line character distance tolerance\"\n\n        An important note: The *intra*line distance is measured from the\n        *end* of the previous character to the *beginning* of the current\n        character, while the *inter*line distance is measured from the\n        *top* of the previous character to the *top* of the next\n        character. The reasons for this are partly repository-historical,\n        and partly logical, as successive text lines' bounding boxes often\n        overlap slightly (and we don't want that overlap to be interpreted\n        as the two lines being the same line).\n\n        The upright-ness of the character determines the attributes to\n        compare, while horizontal_ltr/vertical_ttb determine the direction\n        of the comparison.\n        \"\"\"\n\n        # Note: Due to the grouping step earlier in the process,\n        # curr_char[\"upright\"] will always equal prev_char[\"upright\"].\n        if curr_char[\"upright\"]:\n            x = self.x_tolerance\n            y = self.y_tolerance\n            ay = prev_char[\"top\"]\n            cy = curr_char[\"top\"]\n            if self.horizontal_ltr:\n                ax = prev_char[\"x0\"]\n                bx = prev_char[\"x1\"]\n                cx = curr_char[\"x0\"]\n            else:\n                ax = -prev_char[\"x1\"]\n                bx = -prev_char[\"x0\"]\n                cx = -curr_char[\"x1\"]\n\n        else:\n            x = self.y_tolerance\n            y = self.x_tolerance\n            ay = prev_char[\"x0\"]\n            cy = curr_char[\"x0\"]\n            if self.vertical_ttb:\n                ax = prev_char[\"top\"]\n                bx = prev_char[\"bottom\"]\n                cx = curr_char[\"top\"]\n            else:\n                ax = -prev_char[\"bottom\"]\n                bx = -prev_char[\"top\"]\n                cx = -curr_char[\"bottom\"]\n\n        return bool(\n            # Intraline test\n            (cx < ax)\n            or (cx > bx + x)\n            # Interline test\n            or (cy > ay + y)\n        )\n\n    def iter_chars_to_words(self, ordered_chars):\n        current_word: list = []\n\n        def start_next_word(new_char=None):\n            nonlocal current_word\n\n            if current_word:\n                yield current_word\n\n            current_word = [] if new_char is None else [new_char]\n\n        for char in ordered_chars:\n            text = char[\"text\"]\n\n            if not self.keep_blank_chars and text.isspace():\n                yield from start_next_word(None)\n\n            elif text in self.split_at_punctuation:\n                yield from start_next_word(char)\n                yield from start_next_word(None)\n\n            elif current_word and self.char_begins_new_word(current_word[-1], char):\n                yield from start_next_word(char)\n\n            else:\n                current_word.append(char)\n\n        # Finally, after all chars processed\n        if current_word:\n            yield current_word\n\n    def iter_sort_chars(self, chars):\n        def upright_key(x) -> int:\n            return -int(x[\"upright\"])\n\n        for upright_cluster in cluster_objects(list(chars), upright_key, 0):\n            upright = upright_cluster[0][\"upright\"]\n            cluster_key = \"doctop\" if upright else \"x0\"\n\n            # Cluster by line\n            subclusters = cluster_objects(\n                upright_cluster, itemgetter(cluster_key), self.y_tolerance\n            )\n\n            for sc in subclusters:\n                # Sort within line\n                sort_key = \"x0\" if upright else \"doctop\"\n                to_yield = sorted(sc, key=itemgetter(sort_key))\n\n                # Reverse order if necessary\n                if not (self.horizontal_ltr if upright else self.vertical_ttb):\n                    yield from reversed(to_yield)\n                else:\n                    yield from to_yield\n\n    def iter_extract_tuples(self, chars):\n        ordered_chars = chars if self.use_text_flow else self.iter_sort_chars(chars)\n\n        grouping_key = itemgetter(\"upright\", *self.extra_attrs)\n        grouped_chars = itertools.groupby(ordered_chars, grouping_key)\n\n        for keyvals, char_group in grouped_chars:\n            for word_chars in self.iter_chars_to_words(char_group):\n                yield (self.merge_chars(word_chars), word_chars)\n\n    def extract_wordmap(self, chars) -> WordMap:\n        return WordMap(list(self.iter_extract_tuples(chars)))\n\n    def extract_words(self, chars: list) -> list:\n        words = list(word for word, word_chars in self.iter_extract_tuples(chars))\n        return words\n\n\ndef extract_words(chars: list, **kwargs) -> list:\n    return WordExtractor(**kwargs).extract_words(chars)\n\n\nTEXTMAP_KWARGS = inspect.signature(WordMap.to_textmap).parameters.keys()\nWORD_EXTRACTOR_KWARGS = inspect.signature(WordExtractor).parameters.keys()\n\n\ndef chars_to_textmap(chars: list, **kwargs) -> TextMap:\n    kwargs.update({\"presorted\": True})\n\n    extractor = WordExtractor(\n        **{k: kwargs[k] for k in WORD_EXTRACTOR_KWARGS if k in kwargs}\n    )\n    wordmap = extractor.extract_wordmap(chars)\n    textmap = wordmap.to_textmap(\n        **{k: kwargs[k] for k in TEXTMAP_KWARGS if k in kwargs}\n    )\n\n    return textmap\n\n\ndef extract_text(chars: list, **kwargs) -> str:\n    chars = to_list(chars)\n    if len(chars) == 0:\n        return \"\"\n\n    if kwargs.get(\"layout\"):\n        return chars_to_textmap(chars, **kwargs).as_string\n    else:\n        y_tolerance = kwargs.get(\"y_tolerance\", DEFAULT_Y_TOLERANCE)\n        extractor = WordExtractor(\n            **{k: kwargs[k] for k in WORD_EXTRACTOR_KWARGS if k in kwargs}\n        )\n        words = extractor.extract_words(chars)\n        if words:\n            rotation = words[0][\"rotation\"]  # rotation cannot change within a cell\n        else:\n            rotation = 0\n\n        if rotation == 90:\n            words.sort(key=lambda w: (w[\"x1\"], -w[\"top\"]))\n            lines = \" \".join([w[\"text\"] for w in words])\n        elif rotation == 270:\n            words.sort(key=lambda w: (-w[\"x1\"], w[\"top\"]))\n            lines = \" \".join([w[\"text\"] for w in words])\n        else:\n            lines = cluster_objects(words, itemgetter(\"doctop\"), y_tolerance)\n            lines = \"\\n\".join(\" \".join(word[\"text\"] for word in line) for line in lines)\n            if rotation == 180:  # needs extra treatment\n                lines = \"\".join([(c if c != \"\\n\" else \" \") for c in reversed(lines)])\n\n        return lines\n\n\ndef collate_line(\n    line_chars: list,\n    tolerance=DEFAULT_X_TOLERANCE,\n) -> str:\n    coll = \"\"\n    last_x1 = None\n    for char in sorted(line_chars, key=itemgetter(\"x0\")):\n        if (last_x1 is not None) and (char[\"x0\"] > (last_x1 + tolerance)):\n            coll += \" \"\n        last_x1 = char[\"x1\"]\n        coll += char[\"text\"]\n    return coll\n\n\ndef dedupe_chars(chars: list, tolerance=1) -> list:\n    \"\"\"\n    Removes duplicate chars — those sharing the same text, fontname, size,\n    and positioning (within `tolerance`) as other characters in the set.\n    \"\"\"\n    key = itemgetter(\"fontname\", \"size\", \"upright\", \"text\")\n    pos_key = itemgetter(\"doctop\", \"x0\")\n\n    def yield_unique_chars(chars: list):\n        sorted_chars = sorted(chars, key=key)\n        for grp, grp_chars in itertools.groupby(sorted_chars, key=key):\n            for y_cluster in cluster_objects(\n                list(grp_chars), itemgetter(\"doctop\"), tolerance\n            ):\n                for x_cluster in cluster_objects(\n                    y_cluster, itemgetter(\"x0\"), tolerance\n                ):\n                    yield sorted(x_cluster, key=pos_key)[0]\n\n    deduped = yield_unique_chars(chars)\n    return sorted(deduped, key=chars.index)\n\n\ndef line_to_edge(line):\n    edge = dict(line)\n    edge[\"orientation\"] = \"h\" if (line[\"top\"] == line[\"bottom\"]) else \"v\"\n    return edge\n\n\ndef rect_to_edges(rect) -> list:\n    top, bottom, left, right = [dict(rect) for x in range(4)]\n    top.update(\n        {\n            \"object_type\": \"rect_edge\",\n            \"height\": 0,\n            \"y0\": rect[\"y1\"],\n            \"bottom\": rect[\"top\"],\n            \"orientation\": \"h\",\n        }\n    )\n    bottom.update(\n        {\n            \"object_type\": \"rect_edge\",\n            \"height\": 0,\n            \"y1\": rect[\"y0\"],\n            \"top\": rect[\"top\"] + rect[\"height\"],\n            \"doctop\": rect[\"doctop\"] + rect[\"height\"],\n            \"orientation\": \"h\",\n        }\n    )\n    left.update(\n        {\n            \"object_type\": \"rect_edge\",\n            \"width\": 0,\n            \"x1\": rect[\"x0\"],\n            \"orientation\": \"v\",\n        }\n    )\n    right.update(\n        {\n            \"object_type\": \"rect_edge\",\n            \"width\": 0,\n            \"x0\": rect[\"x1\"],\n            \"orientation\": \"v\",\n        }\n    )\n    return [top, bottom, left, right]\n\n\ndef curve_to_edges(curve) -> list:\n    point_pairs = zip(curve[\"pts\"], curve[\"pts\"][1:])\n    return [\n        {\n            \"object_type\": \"curve_edge\",\n            \"x0\": min(p0[0], p1[0]),\n            \"x1\": max(p0[0], p1[0]),\n            \"top\": min(p0[1], p1[1]),\n            \"doctop\": min(p0[1], p1[1]) + (curve[\"doctop\"] - curve[\"top\"]),\n            \"bottom\": max(p0[1], p1[1]),\n            \"width\": abs(p0[0] - p1[0]),\n            \"height\": abs(p0[1] - p1[1]),\n            \"orientation\": \"v\" if p0[0] == p1[0] else (\"h\" if p0[1] == p1[1] else None),\n        }\n        for p0, p1 in point_pairs\n    ]\n\n\ndef obj_to_edges(obj) -> list:\n    t = obj[\"object_type\"]\n    if \"_edge\" in t:\n        return [obj]\n    elif t == \"line\":\n        return [line_to_edge(obj)]\n    else:\n        return {\"rect\": rect_to_edges, \"curve\": curve_to_edges}[t](obj)\n\n\ndef filter_edges(\n    edges,\n    orientation=None,\n    edge_type=None,\n    min_length=1,\n) -> list:\n    if orientation not in (\"v\", \"h\", None):\n        raise ValueError(\"Orientation must be 'v' or 'h'\")\n\n    def test(e) -> bool:\n        dim = \"height\" if e[\"orientation\"] == \"v\" else \"width\"\n        et_correct = e[\"object_type\"] == edge_type if edge_type is not None else True\n        orient_correct = orientation is None or e[\"orientation\"] == orientation\n        return bool(et_correct and orient_correct and (e[dim] >= min_length))\n\n    return list(filter(test, edges))\n\n\ndef cluster_list(xs, tolerance=0) -> list:\n    if tolerance == 0:\n        return [[x] for x in sorted(xs)]\n    if len(xs) < 2:\n        return [[x] for x in sorted(xs)]\n    groups = []\n    xs = list(sorted(xs))\n    current_group = [xs[0]]\n    last = xs[0]\n    for x in xs[1:]:\n        if x <= (last + tolerance):\n            current_group.append(x)\n        else:\n            groups.append(current_group)\n            current_group = [x]\n        last = x\n    groups.append(current_group)\n    return groups\n\n\ndef make_cluster_dict(values, tolerance) -> dict:\n    clusters = cluster_list(list(set(values)), tolerance)\n\n    nested_tuples = [\n        [(val, i) for val in value_cluster] for i, value_cluster in enumerate(clusters)\n    ]\n\n    return dict(itertools.chain(*nested_tuples))\n\n\ndef cluster_objects(xs, key_fn, tolerance) -> list:\n    if not callable(key_fn):\n        key_fn = itemgetter(key_fn)\n\n    values = map(key_fn, xs)\n    cluster_dict = make_cluster_dict(values, tolerance)\n\n    get_0, get_1 = itemgetter(0), itemgetter(1)\n\n    cluster_tuples = sorted(((x, cluster_dict.get(key_fn(x))) for x in xs), key=get_1)\n\n    grouped = itertools.groupby(cluster_tuples, key=get_1)\n\n    return [list(map(get_0, v)) for k, v in grouped]\n\n\ndef move_object(obj, axis: str, value):\n    assert axis in (\"h\", \"v\")\n    if axis == \"h\":\n        new_items = [\n            (\"x0\", obj[\"x0\"] + value),\n            (\"x1\", obj[\"x1\"] + value),\n        ]\n    if axis == \"v\":\n        new_items = [\n            (\"top\", obj[\"top\"] + value),\n            (\"bottom\", obj[\"bottom\"] + value),\n        ]\n        if \"doctop\" in obj:\n            new_items += [(\"doctop\", obj[\"doctop\"] + value)]\n        if \"y0\" in obj:\n            new_items += [\n                (\"y0\", obj[\"y0\"] - value),\n                (\"y1\", obj[\"y1\"] - value),\n            ]\n    return obj.__class__(tuple(obj.items()) + tuple(new_items))\n\n\ndef snap_objects(objs, attr: str, tolerance) -> list:\n    axis = {\"x0\": \"h\", \"x1\": \"h\", \"top\": \"v\", \"bottom\": \"v\"}[attr]\n    list_objs = list(objs)\n    clusters = cluster_objects(list_objs, itemgetter(attr), tolerance)\n    avgs = [sum(map(itemgetter(attr), cluster)) / len(cluster) for cluster in clusters]\n    snapped_clusters = [\n        [move_object(obj, axis, avg - obj[attr]) for obj in cluster]\n        for cluster, avg in zip(clusters, avgs)\n    ]\n    return list(itertools.chain(*snapped_clusters))\n\n\ndef snap_edges(\n    edges,\n    x_tolerance=DEFAULT_SNAP_TOLERANCE,\n    y_tolerance=DEFAULT_SNAP_TOLERANCE,\n):\n    \"\"\"\n    Given a list of edges, snap any within `tolerance` pixels of one another\n    to their positional average.\n    \"\"\"\n    by_orientation = {\"v\": [], \"h\": []}\n    for e in edges:\n        by_orientation[e[\"orientation\"]].append(e)\n\n    snapped_v = snap_objects(by_orientation[\"v\"], \"x0\", x_tolerance)\n    snapped_h = snap_objects(by_orientation[\"h\"], \"top\", y_tolerance)\n    return snapped_v + snapped_h\n\n\ndef resize_object(obj, key: str, value):\n    assert key in (\"x0\", \"x1\", \"top\", \"bottom\")\n    old_value = obj[key]\n    diff = value - old_value\n    new_items = [\n        (key, value),\n    ]\n    if key == \"x0\":\n        assert value <= obj[\"x1\"]\n        new_items.append((\"width\", obj[\"x1\"] - value))\n    elif key == \"x1\":\n        assert value >= obj[\"x0\"]\n        new_items.append((\"width\", value - obj[\"x0\"]))\n    elif key == \"top\":\n        assert value <= obj[\"bottom\"]\n        new_items.append((\"doctop\", obj[\"doctop\"] + diff))\n        new_items.append((\"height\", obj[\"height\"] - diff))\n        if \"y1\" in obj:\n            new_items.append((\"y1\", obj[\"y1\"] - diff))\n    elif key == \"bottom\":\n        assert value >= obj[\"top\"]\n        new_items.append((\"height\", obj[\"height\"] + diff))\n        if \"y0\" in obj:\n            new_items.append((\"y0\", obj[\"y0\"] - diff))\n    return obj.__class__(tuple(obj.items()) + tuple(new_items))\n\n\ndef join_edge_group(edges, orientation: str, tolerance=DEFAULT_JOIN_TOLERANCE):\n    \"\"\"\n    Given a list of edges along the same infinite line, join those that\n    are within `tolerance` pixels of one another.\n    \"\"\"\n    if orientation == \"h\":\n        min_prop, max_prop = \"x0\", \"x1\"\n    elif orientation == \"v\":\n        min_prop, max_prop = \"top\", \"bottom\"\n    else:\n        raise ValueError(\"Orientation must be 'v' or 'h'\")\n\n    sorted_edges = list(sorted(edges, key=itemgetter(min_prop)))\n    joined = [sorted_edges[0]]\n    for e in sorted_edges[1:]:\n        last = joined[-1]\n        if e[min_prop] <= (last[max_prop] + tolerance):\n            if e[max_prop] > last[max_prop]:\n                # Extend current edge to new extremity\n                joined[-1] = resize_object(last, max_prop, e[max_prop])\n        else:\n            # Edge is separate from previous edges\n            joined.append(e)\n\n    return joined\n\n\ndef merge_edges(\n    edges,\n    snap_x_tolerance,\n    snap_y_tolerance,\n    join_x_tolerance,\n    join_y_tolerance,\n):\n    \"\"\"\n    Using the `snap_edges` and `join_edge_group` methods above,\n    merge a list of edges into a more \"seamless\" list.\n    \"\"\"\n\n    def get_group(edge):\n        if edge[\"orientation\"] == \"h\":\n            return (\"h\", edge[\"top\"])\n        else:\n            return (\"v\", edge[\"x0\"])\n\n    if snap_x_tolerance > 0 or snap_y_tolerance > 0:\n        edges = snap_edges(edges, snap_x_tolerance, snap_y_tolerance)\n\n    _sorted = sorted(edges, key=get_group)\n    edge_groups = itertools.groupby(_sorted, key=get_group)\n    edge_gen = (\n        join_edge_group(\n            items, k[0], (join_x_tolerance if k[0] == \"h\" else join_y_tolerance)\n        )\n        for k, items in edge_groups\n    )\n    edges = list(itertools.chain(*edge_gen))\n    return edges\n\n\ndef bbox_to_rect(bbox) -> dict:\n    \"\"\"\n    Return the rectangle (i.e a dict with keys \"x0\", \"top\", \"x1\",\n    \"bottom\") for an object.\n    \"\"\"\n    return {\"x0\": bbox[0], \"top\": bbox[1], \"x1\": bbox[2], \"bottom\": bbox[3]}\n\n\ndef objects_to_rect(objects) -> dict:\n    \"\"\"\n    Given an iterable of objects, return the smallest rectangle (i.e. a\n    dict with \"x0\", \"top\", \"x1\", and \"bottom\" keys) that contains them\n    all.\n    \"\"\"\n    return bbox_to_rect(objects_to_bbox(objects))\n\n\ndef merge_bboxes(bboxes):\n    \"\"\"\n    Given an iterable of bounding boxes, return the smallest bounding box\n    that contains them all.\n    \"\"\"\n    x0, top, x1, bottom = zip(*bboxes)\n    return (min(x0), min(top), max(x1), max(bottom))\n\n\ndef objects_to_bbox(objects):\n    \"\"\"\n    Given an iterable of objects, return the smallest bounding box that\n    contains them all.\n    \"\"\"\n    return merge_bboxes(map(bbox_getter, objects))\n\n\ndef words_to_edges_h(words, word_threshold: int = DEFAULT_MIN_WORDS_HORIZONTAL):\n    \"\"\"\n    Find (imaginary) horizontal lines that connect the tops\n    of at least `word_threshold` words.\n    \"\"\"\n    by_top = cluster_objects(words, itemgetter(\"top\"), 1)\n    large_clusters = filter(lambda x: len(x) >= word_threshold, by_top)\n    rects = list(map(objects_to_rect, large_clusters))\n    if len(rects) == 0:\n        return []\n    min_x0 = min(map(itemgetter(\"x0\"), rects))\n    max_x1 = max(map(itemgetter(\"x1\"), rects))\n\n    edges = []\n    for r in rects:\n        edges += [\n            # Top of text\n            {\n                \"x0\": min_x0,\n                \"x1\": max_x1,\n                \"top\": r[\"top\"],\n                \"bottom\": r[\"top\"],\n                \"width\": max_x1 - min_x0,\n                \"orientation\": \"h\",\n            },\n            # For each detected row, we also add the 'bottom' line.  This will\n            # generate extra edges, (some will be redundant with the next row\n            # 'top' line), but this catches the last row of every table.\n            {\n                \"x0\": min_x0,\n                \"x1\": max_x1,\n                \"top\": r[\"bottom\"],\n                \"bottom\": r[\"bottom\"],\n                \"width\": max_x1 - min_x0,\n                \"orientation\": \"h\",\n            },\n        ]\n\n    return edges\n\n\ndef get_bbox_overlap(a, b):\n    a_left, a_top, a_right, a_bottom = a\n    b_left, b_top, b_right, b_bottom = b\n    o_left = max(a_left, b_left)\n    o_right = min(a_right, b_right)\n    o_bottom = min(a_bottom, b_bottom)\n    o_top = max(a_top, b_top)\n    o_width = o_right - o_left\n    o_height = o_bottom - o_top\n    if o_height >= 0 and o_width >= 0 and o_height + o_width > 0:\n        return (o_left, o_top, o_right, o_bottom)\n    else:\n        return None\n\n\ndef words_to_edges_v(words, word_threshold: int = DEFAULT_MIN_WORDS_VERTICAL):\n    \"\"\"\n    Find (imaginary) vertical lines that connect the left, right, or\n    center of at least `word_threshold` words.\n    \"\"\"\n    # Find words that share the same left, right, or centerpoints\n    by_x0 = cluster_objects(words, itemgetter(\"x0\"), 1)\n    by_x1 = cluster_objects(words, itemgetter(\"x1\"), 1)\n\n    def get_center(word):\n        return float(word[\"x0\"] + word[\"x1\"]) / 2\n\n    by_center = cluster_objects(words, get_center, 1)\n    clusters = by_x0 + by_x1 + by_center\n\n    # Find the points that align with the most words\n    sorted_clusters = sorted(clusters, key=lambda x: -len(x))\n    large_clusters = filter(lambda x: len(x) >= word_threshold, sorted_clusters)\n\n    # For each of those points, find the bboxes fitting all matching words\n    bboxes = list(map(objects_to_bbox, large_clusters))\n\n    # Iterate through those bboxes, condensing overlapping bboxes\n    condensed_bboxes = []\n    for bbox in bboxes:\n        overlap = any(get_bbox_overlap(bbox, c) for c in condensed_bboxes)\n        if not overlap:\n            condensed_bboxes.append(bbox)\n\n    if not condensed_bboxes:\n        return []\n\n    condensed_rects = map(bbox_to_rect, condensed_bboxes)\n    sorted_rects = list(sorted(condensed_rects, key=itemgetter(\"x0\")))\n\n    max_x1 = max(map(itemgetter(\"x1\"), sorted_rects))\n    min_top = min(map(itemgetter(\"top\"), sorted_rects))\n    max_bottom = max(map(itemgetter(\"bottom\"), sorted_rects))\n\n    return [\n        {\n            \"x0\": b[\"x0\"],\n            \"x1\": b[\"x0\"],\n            \"top\": min_top,\n            \"bottom\": max_bottom,\n            \"height\": max_bottom - min_top,\n            \"orientation\": \"v\",\n        }\n        for b in sorted_rects\n    ] + [\n        {\n            \"x0\": max_x1,\n            \"x1\": max_x1,\n            \"top\": min_top,\n            \"bottom\": max_bottom,\n            \"height\": max_bottom - min_top,\n            \"orientation\": \"v\",\n        }\n    ]\n\n\ndef edges_to_intersections(edges, x_tolerance=1, y_tolerance=1) -> dict:\n    \"\"\"\n    Given a list of edges, return the points at which they intersect\n    within `tolerance` pixels.\n    \"\"\"\n    intersections = {}\n    v_edges, h_edges = [\n        list(filter(lambda x: x[\"orientation\"] == o, edges)) for o in (\"v\", \"h\")\n    ]\n    for v in sorted(v_edges, key=itemgetter(\"x0\", \"top\")):\n        for h in sorted(h_edges, key=itemgetter(\"top\", \"x0\")):\n            if (\n                (v[\"top\"] <= (h[\"top\"] + y_tolerance))\n                and (v[\"bottom\"] >= (h[\"top\"] - y_tolerance))\n                and (v[\"x0\"] >= (h[\"x0\"] - x_tolerance))\n                and (v[\"x0\"] <= (h[\"x1\"] + x_tolerance))\n            ):\n                vertex = (v[\"x0\"], h[\"top\"])\n                if vertex not in intersections:\n                    intersections[vertex] = {\"v\": [], \"h\": []}\n                intersections[vertex][\"v\"].append(v)\n                intersections[vertex][\"h\"].append(h)\n    return intersections\n\n\ndef obj_to_bbox(obj):\n    \"\"\"\n    Return the bounding box for an object.\n    \"\"\"\n    return bbox_getter(obj)\n\n\ndef intersections_to_cells(intersections):\n    \"\"\"\n    Given a list of points (`intersections`), return all rectangular \"cells\"\n    that those points describe.\n\n    `intersections` should be a dictionary with (x0, top) tuples as keys,\n    and a list of edge objects as values. The edge objects should correspond\n    to the edges that touch the intersection.\n    \"\"\"\n\n    def edge_connects(p1, p2) -> bool:\n        def edges_to_set(edges):\n            return set(map(obj_to_bbox, edges))\n\n        if p1[0] == p2[0]:\n            common = edges_to_set(intersections[p1][\"v\"]).intersection(\n                edges_to_set(intersections[p2][\"v\"])\n            )\n            if len(common):\n                return True\n\n        if p1[1] == p2[1]:\n            common = edges_to_set(intersections[p1][\"h\"]).intersection(\n                edges_to_set(intersections[p2][\"h\"])\n            )\n            if len(common):\n                return True\n        return False\n\n    points = list(sorted(intersections.keys()))\n    n_points = len(points)\n\n    def find_smallest_cell(points, i: int):\n        if i == n_points - 1:\n            return None\n        pt = points[i]\n        rest = points[i + 1 :]\n        # Get all the points directly below and directly right\n        below = [x for x in rest if x[0] == pt[0]]\n        right = [x for x in rest if x[1] == pt[1]]\n        for below_pt in below:\n            if not edge_connects(pt, below_pt):\n                continue\n\n            for right_pt in right:\n                if not edge_connects(pt, right_pt):\n                    continue\n\n                bottom_right = (right_pt[0], below_pt[1])\n\n                if (\n                    (bottom_right in intersections)\n                    and edge_connects(bottom_right, right_pt)\n                    and edge_connects(bottom_right, below_pt)\n                ):\n                    return (pt[0], pt[1], bottom_right[0], bottom_right[1])\n        return None\n\n    cell_gen = (find_smallest_cell(points, i) for i in range(len(points)))\n    return list(filter(None, cell_gen))\n\n\ndef cells_to_tables(page, cells) -> list:\n    \"\"\"\n    Given a list of bounding boxes (`cells`), return a list of tables that\n    hold those cells most simply (and contiguously).\n    \"\"\"\n\n    def bbox_to_corners(bbox) -> tuple:\n        x0, top, x1, bottom = bbox\n        return ((x0, top), (x0, bottom), (x1, top), (x1, bottom))\n\n    remaining_cells = list(cells)\n\n    # Iterate through the cells found above, and assign them\n    # to contiguous tables\n\n    current_corners = set()\n    current_cells = []\n\n    tables = []\n    while len(remaining_cells):\n        initial_cell_count = len(current_cells)\n        for cell in list(remaining_cells):\n            cell_corners = bbox_to_corners(cell)\n            # If we're just starting a table ...\n            if len(current_cells) == 0:\n                # ... immediately assign it to the empty group\n                current_corners |= set(cell_corners)\n                current_cells.append(cell)\n                remaining_cells.remove(cell)\n            else:\n                # How many corners does this table share with the current group?\n                corner_count = sum(c in current_corners for c in cell_corners)\n\n                # If touching on at least one corner...\n                if corner_count > 0:\n                    # ... assign it to the current group\n                    current_corners |= set(cell_corners)\n                    current_cells.append(cell)\n                    remaining_cells.remove(cell)\n\n        # If this iteration did not find any more cells to append...\n        if len(current_cells) == initial_cell_count:\n            # ... start a new cell group\n            tables.append(list(current_cells))\n            current_corners.clear()\n            current_cells.clear()\n\n    # Once we have exhausting the list of cells ...\n\n    # ... and we have a cell group that has not been stored\n    if len(current_cells):\n        # ... store it.\n        tables.append(list(current_cells))\n\n    # PyMuPDF modification:\n    # Remove tables without text or having only 1 column\n    for i in range(len(tables) - 1, -1, -1):\n        r = pymupdf.EMPTY_RECT()\n        x1_vals = set()\n        x0_vals = set()\n        for c in tables[i]:\n            r |= c\n            x1_vals.add(c[2])\n            x0_vals.add(c[0])\n        if (\n            len(x1_vals) < 2\n            or len(x0_vals) < 2\n            or white_spaces.issuperset(\n                page.get_textbox(\n                    r,\n                    textpage=TEXTPAGE,\n                )\n            )\n        ):\n            del tables[i]\n\n    # Sort the tables top-to-bottom-left-to-right based on the value of the\n    # topmost-and-then-leftmost coordinate of a table.\n    _sorted = sorted(tables, key=lambda t: min((c[1], c[0]) for c in t))\n    return _sorted\n\n\nclass CellGroup:\n    def __init__(self, cells):\n        self.cells = cells\n        self.bbox = (\n            min(map(itemgetter(0), filter(None, cells))),\n            min(map(itemgetter(1), filter(None, cells))),\n            max(map(itemgetter(2), filter(None, cells))),\n            max(map(itemgetter(3), filter(None, cells))),\n        )\n\n\nclass TableRow(CellGroup):\n    pass\n\n\nclass TableHeader:\n    \"\"\"PyMuPDF extension containing the identified table header.\"\"\"\n\n    def __init__(self, bbox, cells, names, above):\n        self.bbox = bbox\n        self.cells = cells\n        self.names = names\n        self.external = above\n\n\nclass Table:\n    def __init__(self, page, cells):\n        self.page = page\n        self.textpage = None\n        self.cells = cells\n        self.header = self._get_header()  # PyMuPDF extension\n\n    @property\n    def bbox(self):\n        c = self.cells\n        return (\n            min(map(itemgetter(0), c)),\n            min(map(itemgetter(1), c)),\n            max(map(itemgetter(2), c)),\n            max(map(itemgetter(3), c)),\n        )\n\n    @property\n    def rows(self) -> list:\n        _sorted = sorted(self.cells, key=itemgetter(1, 0))\n        xs = list(sorted(set(map(itemgetter(0), self.cells))))\n        rows = []\n        for y, row_cells in itertools.groupby(_sorted, itemgetter(1)):\n            xdict = {cell[0]: cell for cell in row_cells}\n            row = TableRow([xdict.get(x) for x in xs])\n            rows.append(row)\n        return rows\n\n    @property\n    def row_count(self) -> int:  # PyMuPDF extension\n        return len(self.rows)\n\n    @property\n    def col_count(self) -> int:  # PyMuPDF extension\n        return max([len(r.cells) for r in self.rows])\n\n    def extract(self, **kwargs) -> list:\n        chars = CHARS\n        table_arr = []\n\n        def char_in_bbox(char, bbox) -> bool:\n            v_mid = (char[\"top\"] + char[\"bottom\"]) / 2\n            h_mid = (char[\"x0\"] + char[\"x1\"]) / 2\n            x0, top, x1, bottom = bbox\n            return bool(\n                (h_mid >= x0) and (h_mid < x1) and (v_mid >= top) and (v_mid < bottom)\n            )\n\n        for row in self.rows:\n            arr = []\n            row_chars = [char for char in chars if char_in_bbox(char, row.bbox)]\n\n            for cell in row.cells:\n                if cell is None:\n                    cell_text = None\n                else:\n                    cell_chars = [\n                        char for char in row_chars if char_in_bbox(char, cell)\n                    ]\n\n                    if len(cell_chars):\n                        kwargs[\"x_shift\"] = cell[0]\n                        kwargs[\"y_shift\"] = cell[1]\n                        if \"layout\" in kwargs:\n                            kwargs[\"layout_width\"] = cell[2] - cell[0]\n                            kwargs[\"layout_height\"] = cell[3] - cell[1]\n                        cell_text = extract_text(cell_chars, **kwargs)\n                    else:\n                        cell_text = \"\"\n                arr.append(cell_text)\n            table_arr.append(arr)\n\n        return table_arr\n\n    def to_markdown(self, clean=False, fill_empty=True):\n        \"\"\"Output table content as a string in Github-markdown format.\n\n        If \"clean\" then markdown syntax is removed from cell content.\n        If \"fill_empty\" then cell content None is replaced by the values\n        above (columns) or left (rows) in an effort to approximate row and\n        columns spans.\n\n        \"\"\"\n        output = \"|\"\n        rows = self.row_count\n        cols = self.col_count\n\n        # cell coordinates\n        cell_boxes = [[c for c in r.cells] for r in self.rows]\n\n        # cell text strings\n        cells = [[None for i in range(cols)] for j in range(rows)]\n        for i, row in enumerate(cell_boxes):\n            for j, cell in enumerate(row):\n                if cell is not None:\n                    cells[i][j] = extract_cells(\n                        self.textpage, cell_boxes[i][j], markdown=True\n                    )\n\n        if fill_empty:  # fill \"None\" cells where possible\n\n            # for rows, copy content from left to right\n            for j in range(rows):\n                for i in range(cols - 1):\n                    if cells[j][i + 1] is None:\n                        cells[j][i + 1] = cells[j][i]\n\n            # for columns, copy top to bottom\n            for i in range(cols):\n                for j in range(rows - 1):\n                    if cells[j + 1][i] is None:\n                        cells[j + 1][i] = cells[j][i]\n\n        # generate header string and MD separator\n        for i, name in enumerate(self.header.names):\n            if not name:  # generate a name if empty\n                name = f\"Col{i+1}\"\n            name = name.replace(\"\\n\", \"<br>\")  # use HTML line breaks\n            if clean:  # remove sensitive syntax\n                name = html.escape(name.replace(\"-\", \"&#45;\"))\n            output += name + \"|\"\n\n        output += \"\\n\"\n        # insert GitHub header line separator\n        output += \"|\" + \"|\".join(\"---\" for i in range(self.col_count)) + \"|\\n\"\n\n        # skip first row in details if header is part of the table\n        j = 0 if self.header.external else 1\n\n        # iterate over detail rows\n        for row in cells[j:]:\n            line = \"|\"\n            for i, cell in enumerate(row):\n                # replace None cells with empty string\n                # use HTML line break tag\n                if cell is None:\n                    cell = \"\"\n                if clean:  # remove sensitive syntax\n                    cell = html.escape(cell.replace(\"-\", \"&#45;\"))\n                line += cell + \"|\"\n            line += \"\\n\"\n            output += line\n        return output + \"\\n\"\n\n    def to_pandas(self, **kwargs):\n        \"\"\"Return a pandas DataFrame version of the table.\"\"\"\n        try:\n            import pandas as pd\n        except ModuleNotFoundError:\n            pymupdf.message(\"Package 'pandas' is not installed\")\n            raise\n\n        pd_dict = {}\n        extract = self.extract()\n        hdr = self.header\n        names = self.header.names\n        hdr_len = len(names)\n        # ensure uniqueness of column names\n        for i in range(hdr_len):\n            name = names[i]\n            if not name:\n                names[i] = f\"Col{i}\"\n        if hdr_len != len(set(names)):\n            for i in range(hdr_len):\n                name = names[i]\n                if name != f\"Col{i}\":\n                    names[i] = f\"{i}-{name}\"\n\n        if not hdr.external:  # header is part of 'extract'\n            extract = extract[1:]\n\n        for i in range(hdr_len):\n            key = names[i]\n            value = []\n            for j in range(len(extract)):\n                value.append(extract[j][i])\n            pd_dict[key] = value\n\n        return pd.DataFrame(pd_dict)\n\n    def _get_header(self, y_tolerance=3):\n        \"\"\"Identify the table header.\n\n        *** PyMuPDF extension. ***\n\n        Starting from the first line above the table upwards, check if it\n        qualifies to be part of the table header.\n\n        Criteria include:\n        * A one-line table never has an extra header.\n        * Column borders must not intersect any word. If this happens, all\n          text of this line and above of it is ignored.\n        * No excess inter-line distance: If a line further up has a distance\n          of more than 1.5 times of its font size, it will be ignored and\n          all lines above of it.\n        * Must have same text properties.\n        * Starting with the top table line, a bold text property cannot change\n          back to non-bold.\n\n        If not all criteria are met (or there is no text above the table),\n        the first table row is assumed to be the header.\n        \"\"\"\n        page = self.page\n        y_delta = y_tolerance\n\n        def top_row_bg_color(self):\n            \"\"\"\n            Compare top row background color with color of same-sized bbox\n            above. If different, return True indicating that the original\n            table top row is already the header.\n            \"\"\"\n            bbox0 = pymupdf.Rect(self.rows[0].bbox)\n            bboxt = bbox0 + (0, -bbox0.height, 0, -bbox0.height)  # area above\n            top_color0 = page.get_pixmap(clip=bbox0).color_topusage()[1]\n            top_colort = page.get_pixmap(clip=bboxt).color_topusage()[1]\n            if top_color0 != top_colort:\n                return True  # top row is header\n            return False\n\n        def row_has_bold(bbox):\n            \"\"\"Check if a row contains some bold text.\n\n            If e.g. true for the top row, then it will be used as (internal)\n            column header row if any of the following is true:\n            * the previous (above) text line has no bold span\n            * the second table row text has no bold span\n\n            Returns True if any spans are bold else False.\n            \"\"\"\n            return any(\n                c[\"bold\"]\n                for c in CHARS\n                if rect_in_rect((c[\"x0\"], c[\"y0\"], c[\"x1\"], c[\"y1\"]), bbox)\n            )\n\n        try:\n            row = self.rows[0]\n            cells = row.cells\n            bbox = pymupdf.Rect(row.bbox)\n        except IndexError:  # this table has no rows\n            return None\n\n        # return this if we determine that the top row is the header\n        header_top_row = TableHeader(bbox, cells, self.extract()[0], False)\n\n        # 1-line tables have no extra header\n        if len(self.rows) < 2:\n            return header_top_row\n\n        # 1-column tables have no extra header\n        if len(cells) < 2:\n            return header_top_row\n\n        # assume top row is the header if second row is empty\n        row2 = self.rows[1]  # second row\n        if all(c is None for c in row2.cells):  # no valid cell bboxes in row2\n            return header_top_row\n\n        # Special check: is top row bold?\n        top_row_bold = row_has_bold(bbox)\n\n        # assume top row is header if it is bold and any cell\n        # of 2nd row is non-bold\n        if top_row_bold and not row_has_bold(row2.bbox):\n            return header_top_row\n\n        if top_row_bg_color(self):\n            # if area above top row has a different background color,\n            # then top row is already the header\n            return header_top_row\n\n        # column coordinates (x1 values) in top row\n        col_x = [c[2] if c is not None else None for c in cells[:-1]]\n\n        # clip = page area above the table\n        # We will inspect this area for text qualifying as column header.\n        clip = +bbox  # take row 0 bbox\n        clip.y0 = 0  # start at top of page\n        clip.y1 = bbox.y0  # end at top of table\n\n        blocks = page.get_text(\"dict\", clip=clip, flags=pymupdf.TEXTFLAGS_TEXT)[\n            \"blocks\"\n        ]\n        # non-empty, non-superscript spans above table, sorted descending by y1\n        spans = sorted(\n            [\n                s\n                for b in blocks\n                for l in b[\"lines\"]\n                for s in l[\"spans\"]\n                if not (\n                    white_spaces.issuperset(s[\"text\"])\n                    or s[\"flags\"] & pymupdf.TEXT_FONT_SUPERSCRIPT\n                )\n            ],\n            key=lambda s: s[\"bbox\"][3],\n            reverse=True,\n        )\n\n        select = []  # y1 coordinates above, sorted descending\n        line_heights = []  # line heights above, sorted descending\n        line_bolds = []  # bold indicator per line above, same sorting\n\n        # walk through the spans and fill above 3 lists\n        for i in range(len(spans)):\n            s = spans[i]\n            y1 = s[\"bbox\"][3]  # span bottom\n            h = y1 - s[\"bbox\"][1]  # span bbox height\n            bold = s[\"flags\"] & pymupdf.TEXT_FONT_BOLD\n\n            # use first item to start the lists\n            if i == 0:\n                select.append(y1)\n                line_heights.append(h)\n                line_bolds.append(bold)\n                continue\n\n            # get previous items from the 3 lists\n            y0 = select[-1]\n            h0 = line_heights[-1]\n            bold0 = line_bolds[-1]\n\n            if bold0 and not bold:\n                break  # stop if switching from bold to non-bold\n\n            # if fitting in height of previous span, modify bbox\n            if y0 - y1 <= y_delta or abs((y0 - h0) - s[\"bbox\"][1]) <= y_delta:\n                s[\"bbox\"] = (s[\"bbox\"][0], y0 - h0, s[\"bbox\"][2], y0)\n                spans[i] = s\n                if bold:\n                    line_bolds[-1] = bold\n                continue\n            elif y0 - y1 > 1.5 * h0:\n                break  # stop if distance to previous line too large\n            select.append(y1)\n            line_heights.append(h)\n            line_bolds.append(bold)\n\n        if select == []:  # nothing above the table?\n            return header_top_row\n\n        select = select[:5]  # accept up to 5 lines for an external header\n\n        # assume top row as header if text above is too far away\n        if bbox.y0 - select[0] >= line_heights[0]:\n            return header_top_row\n\n        # accept top row as header if bold, but line above is not\n        if top_row_bold and not line_bolds[0]:\n            return header_top_row\n\n        if spans == []:  # nothing left above the table, return top row\n            return header_top_row\n\n        # re-compute clip above table\n        nclip = pymupdf.EMPTY_RECT()\n        for s in [s for s in spans if s[\"bbox\"][3] >= select[-1]]:\n            nclip |= s[\"bbox\"]\n        if not nclip.is_empty:\n            clip = nclip\n\n        clip.y1 = bbox.y0  # make sure we still include every word above\n\n        # Confirm that no word in clip is intersecting a column separator\n        word_rects = [pymupdf.Rect(w[:4]) for w in page.get_text(\"words\", clip=clip)]\n        word_tops = sorted(list(set([r[1] for r in word_rects])), reverse=True)\n\n        select = []\n\n        # exclude lines with words that intersect a column border\n        for top in word_tops:\n            intersecting = [\n                (x, r)\n                for x in col_x\n                if x is not None\n                for r in word_rects\n                if r[1] == top and r[0] < x and r[2] > x\n            ]\n            if intersecting == []:\n                select.append(top)\n            else:  # detected a word crossing a column border\n                break\n\n        if select == []:  # nothing left over: return first row\n            return header_top_row\n\n        hdr_bbox = +clip  # compute the header cells\n        hdr_bbox.y0 = select[-1]  # hdr_bbox top is smallest top coord of words\n        hdr_cells = [\n            (c[0], hdr_bbox.y0, c[2], hdr_bbox.y1) if c is not None else None\n            for c in cells\n        ]\n\n        # adjust left/right of header bbox\n        hdr_bbox.x0 = self.bbox[0]\n        hdr_bbox.x1 = self.bbox[2]\n\n        # column names: no line breaks, no excess spaces\n        hdr_names = [\n            (\n                page.get_textbox(c).replace(\"\\n\", \" \").replace(\"  \", \" \").strip()\n                if c is not None\n                else \"\"\n            )\n            for c in hdr_cells\n        ]\n        return TableHeader(tuple(hdr_bbox), hdr_cells, hdr_names, True)\n\n\n@dataclass\nclass TableSettings:\n    vertical_strategy: str = \"lines\"\n    horizontal_strategy: str = \"lines\"\n    explicit_vertical_lines: list = None\n    explicit_horizontal_lines: list = None\n    snap_tolerance: float = DEFAULT_SNAP_TOLERANCE\n    snap_x_tolerance: float = UNSET\n    snap_y_tolerance: float = UNSET\n    join_tolerance: float = DEFAULT_JOIN_TOLERANCE\n    join_x_tolerance: float = UNSET\n    join_y_tolerance: float = UNSET\n    edge_min_length: float = 3\n    min_words_vertical: float = DEFAULT_MIN_WORDS_VERTICAL\n    min_words_horizontal: float = DEFAULT_MIN_WORDS_HORIZONTAL\n    intersection_tolerance: float = 3\n    intersection_x_tolerance: float = UNSET\n    intersection_y_tolerance: float = UNSET\n    text_settings: dict = None\n\n    def __post_init__(self) -> \"TableSettings\":\n        \"\"\"Clean up user-provided table settings.\n\n        Validates that the table settings provided consists of acceptable values and\n        returns a cleaned up version. The cleaned up version fills out the missing\n        values with the default values in the provided settings.\n\n        TODO: Can be further used to validate that the values are of the correct\n            type. For example, raising a value error when a non-boolean input is\n            provided for the key ``keep_blank_chars``.\n\n        :param table_settings: User-provided table settings.\n        :returns: A cleaned up version of the user-provided table settings.\n        :raises ValueError: When an unrecognised key is provided.\n        \"\"\"\n\n        for setting in NON_NEGATIVE_SETTINGS:\n            if (getattr(self, setting) or 0) < 0:\n                raise ValueError(f\"Table setting '{setting}' cannot be negative\")\n\n        for orientation in [\"horizontal\", \"vertical\"]:\n            strategy = getattr(self, orientation + \"_strategy\")\n            if strategy not in TABLE_STRATEGIES:\n                raise ValueError(\n                    f\"{orientation}_strategy must be one of\"\n                    f'{{{\",\".join(TABLE_STRATEGIES)}}}'\n                )\n\n        if self.text_settings is None:\n            self.text_settings = {}\n\n        # This next section is for backwards compatibility\n        for attr in [\"x_tolerance\", \"y_tolerance\"]:\n            if attr not in self.text_settings:\n                self.text_settings[attr] = self.text_settings.get(\"tolerance\", 3)\n\n        if \"tolerance\" in self.text_settings:\n            del self.text_settings[\"tolerance\"]\n        # End of that section\n\n        for attr, fallback in [\n            (\"snap_x_tolerance\", \"snap_tolerance\"),\n            (\"snap_y_tolerance\", \"snap_tolerance\"),\n            (\"join_x_tolerance\", \"join_tolerance\"),\n            (\"join_y_tolerance\", \"join_tolerance\"),\n            (\"intersection_x_tolerance\", \"intersection_tolerance\"),\n            (\"intersection_y_tolerance\", \"intersection_tolerance\"),\n        ]:\n            if getattr(self, attr) is UNSET:\n                setattr(self, attr, getattr(self, fallback))\n\n        return self\n\n    @classmethod\n    def resolve(cls, settings=None):\n        if settings is None:\n            return cls()\n        elif isinstance(settings, cls):\n            return settings\n        elif isinstance(settings, dict):\n            core_settings = {}\n            text_settings = {}\n            for k, v in settings.items():\n                if k[:5] == \"text_\":\n                    text_settings[k[5:]] = v\n                else:\n                    core_settings[k] = v\n            core_settings[\"text_settings\"] = text_settings\n            return cls(**core_settings)\n        else:\n            raise ValueError(f\"Cannot resolve settings: {settings}\")\n\n\nclass TableFinder:\n    \"\"\"\n    Given a PDF page, find plausible table structures.\n\n    Largely borrowed from Anssi Nurminen's master's thesis:\n    http://dspace.cc.tut.fi/dpub/bitstream/handle/123456789/21520/Nurminen.pdf?sequence=3\n\n    ... and inspired by Tabula:\n    https://github.com/tabulapdf/tabula-extractor/issues/16\n    \"\"\"\n\n    def __init__(self, page, settings=None):\n        self.page = weakref.proxy(page)\n        self.textpage = None\n        self.settings = TableSettings.resolve(settings)\n        self.edges = self.get_edges()\n        self.intersections = edges_to_intersections(\n            self.edges,\n            self.settings.intersection_x_tolerance,\n            self.settings.intersection_y_tolerance,\n        )\n        self.cells = intersections_to_cells(self.intersections)\n        self.tables = [\n            Table(self.page, cell_group)\n            for cell_group in cells_to_tables(self.page, self.cells)\n        ]\n\n    def get_edges(self) -> list:\n        settings = self.settings\n\n        for orientation in [\"vertical\", \"horizontal\"]:\n            strategy = getattr(settings, orientation + \"_strategy\")\n            if strategy == \"explicit\":\n                lines = getattr(settings, \"explicit_\" + orientation + \"_lines\")\n                if len(lines) < 2:\n                    raise ValueError(\n                        f\"If {orientation}_strategy == 'explicit', \"\n                        f\"explicit_{orientation}_lines \"\n                        f\"must be specified as a list/tuple of two or more \"\n                        f\"floats/ints.\"\n                    )\n\n        v_strat = settings.vertical_strategy\n        h_strat = settings.horizontal_strategy\n\n        if v_strat == \"text\" or h_strat == \"text\":\n            words = extract_words(CHARS, **(settings.text_settings or {}))\n        else:\n            words = []\n\n        v_explicit = []\n        for desc in settings.explicit_vertical_lines or []:\n            if isinstance(desc, dict):\n                for e in obj_to_edges(desc):\n                    if e[\"orientation\"] == \"v\":\n                        v_explicit.append(e)\n            else:\n                v_explicit.append(\n                    {\n                        \"x0\": desc,\n                        \"x1\": desc,\n                        \"top\": self.page.rect[1],\n                        \"bottom\": self.page.rect[3],\n                        \"height\": self.page.rect[3] - self.page.rect[1],\n                        \"orientation\": \"v\",\n                    }\n                )\n\n        if v_strat == \"lines\":\n            v_base = filter_edges(EDGES, \"v\")\n        elif v_strat == \"lines_strict\":\n            v_base = filter_edges(EDGES, \"v\", edge_type=\"line\")\n        elif v_strat == \"text\":\n            v_base = words_to_edges_v(words, word_threshold=settings.min_words_vertical)\n        elif v_strat == \"explicit\":\n            v_base = []\n        else:\n            v_base = []\n\n        v = v_base + v_explicit\n\n        h_explicit = []\n        for desc in settings.explicit_horizontal_lines or []:\n            if isinstance(desc, dict):\n                for e in obj_to_edges(desc):\n                    if e[\"orientation\"] == \"h\":\n                        h_explicit.append(e)\n            else:\n                h_explicit.append(\n                    {\n                        \"x0\": self.page.rect[0],\n                        \"x1\": self.page.rect[2],\n                        \"width\": self.page.rect[2] - self.page.rect[0],\n                        \"top\": desc,\n                        \"bottom\": desc,\n                        \"orientation\": \"h\",\n                    }\n                )\n\n        if h_strat == \"lines\":\n            h_base = filter_edges(EDGES, \"h\")\n        elif h_strat == \"lines_strict\":\n            h_base = filter_edges(EDGES, \"h\", edge_type=\"line\")\n        elif h_strat == \"text\":\n            h_base = words_to_edges_h(\n                words, word_threshold=settings.min_words_horizontal\n            )\n        elif h_strat == \"explicit\":\n            h_base = []\n        else:\n            h_base = []\n\n        h = h_base + h_explicit\n\n        edges = list(v) + list(h)\n\n        edges = merge_edges(\n            edges,\n            snap_x_tolerance=settings.snap_x_tolerance,\n            snap_y_tolerance=settings.snap_y_tolerance,\n            join_x_tolerance=settings.join_x_tolerance,\n            join_y_tolerance=settings.join_y_tolerance,\n        )\n\n        return filter_edges(edges, min_length=settings.edge_min_length)\n\n    def __getitem__(self, i):\n        tcount = len(self.tables)\n        if i >= tcount:\n            raise IndexError(\"table not on page\")\n        while i < 0:\n            i += tcount\n        return self.tables[i]\n\n\n\"\"\"\nStart of PyMuPDF interface code.\nThe following functions are executed when \"page.find_tables()\" is called.\n\n* make_chars: Fills the CHARS list with text character information extracted\n              via \"rawdict\" text extraction. Items in CHARS are formatted\n              as expected by the table code.\n* make_edges: Fills the EDGES list with vector graphic information extracted\n              via \"get_drawings\". Items in EDGES are formatted as expected\n              by the table code.\n\nThe lists CHARS and EDGES are used to replace respective document access\nof pdfplumber or, respectively pdfminer.\nThe table code has been modified to use these lists instead of accessing\npage information themselves.\n\"\"\"\n\n\n# -----------------------------------------------------------------------------\n# Extract all page characters to fill the CHARS list\n# -----------------------------------------------------------------------------\ndef make_chars(page, clip=None):\n    \"\"\"Extract text as \"rawdict\" to fill CHARS.\"\"\"\n    page_number = page.number + 1\n    page_height = page.rect.height\n    ctm = page.transformation_matrix\n    TEXTPAGE = page.get_textpage(clip=clip, flags=FLAGS)\n    blocks = page.get_text(\"rawdict\", textpage=TEXTPAGE)[\"blocks\"]\n    doctop_base = page_height * page.number\n    for block in blocks:\n        for line in block[\"lines\"]:\n            ldir = line[\"dir\"]  # = (cosine, sine) of angle\n            ldir = (round(ldir[0], 4), round(ldir[1], 4))\n            matrix = pymupdf.Matrix(ldir[0], -ldir[1], ldir[1], ldir[0], 0, 0)\n            if ldir[1] == 0:\n                upright = True\n            else:\n                upright = False\n            for span in sorted(line[\"spans\"], key=lambda s: s[\"bbox\"][0]):\n                fontname = span[\"font\"]\n                fontsize = span[\"size\"]\n                span_bold = bool(\n                    span[\"flags\"] & pymupdf.TEXT_FONT_BOLD or span[\"char_flags\"] & 8\n                )\n                color = pymupdf.sRGB_to_pdf(span[\"color\"])\n                for char in sorted(span[\"chars\"], key=lambda c: c[\"bbox\"][0]):\n                    bbox = pymupdf.Rect(char[\"bbox\"])\n                    bbox_ctm = bbox * ctm\n                    origin = pymupdf.Point(char[\"origin\"]) * ctm\n                    matrix.e = origin.x\n                    matrix.f = origin.y\n                    text = char[\"c\"]\n                    char_dict = {\n                        \"adv\": bbox.x1 - bbox.x0 if upright else bbox.y1 - bbox.y0,\n                        \"bottom\": bbox.y1,\n                        \"doctop\": bbox.y0 + doctop_base,\n                        \"fontname\": fontname,\n                        \"height\": bbox.y1 - bbox.y0,\n                        \"matrix\": tuple(matrix),\n                        \"ncs\": \"DeviceRGB\",\n                        \"non_stroking_color\": color,\n                        \"non_stroking_pattern\": None,\n                        \"object_type\": \"char\",\n                        \"page_number\": page_number,\n                        \"size\": fontsize if upright else bbox.y1 - bbox.y0,\n                        \"stroking_color\": color,\n                        \"stroking_pattern\": None,\n                        \"bold\": span_bold,\n                        \"text\": text,\n                        \"top\": bbox.y0,\n                        \"upright\": upright,\n                        \"width\": bbox.x1 - bbox.x0,\n                        \"x0\": bbox.x0,\n                        \"x1\": bbox.x1,\n                        \"y0\": bbox_ctm.y0,\n                        \"y1\": bbox_ctm.y1,\n                    }\n                    CHARS.append(char_dict)\n    return TEXTPAGE\n\n\n# ------------------------------------------------------------------------\n# Extract all page vector graphics to fill the EDGES list.\n# We are ignoring Bézier curves completely and are converting everything\n# else to lines.\n# ------------------------------------------------------------------------\ndef make_edges(page, clip=None, tset=None, paths=None, add_lines=None, add_boxes=None):\n    snap_x = tset.snap_x_tolerance\n    snap_y = tset.snap_y_tolerance\n    min_length = tset.edge_min_length\n    lines_strict = (\n        tset.vertical_strategy == \"lines_strict\"\n        or tset.horizontal_strategy == \"lines_strict\"\n    )\n    page_height = page.rect.height\n    doctop_basis = page.number * page_height\n    page_number = page.number + 1\n    prect = page.rect\n    if page.rotation in (90, 270):\n        w, h = prect.br\n        prect = pymupdf.Rect(0, 0, h, w)\n    if clip is not None:\n        clip = pymupdf.Rect(clip)\n    else:\n        clip = prect\n\n    def are_neighbors(r1, r2):\n        \"\"\"Detect whether r1, r2 are neighbors.\n\n        Defined as:\n        The minimum distance between points of r1 and points of r2 is not\n        larger than some delta.\n\n        This check supports empty rect-likes and thus also lines.\n\n        Note:\n        This type of check is MUCH faster than native Rect containment checks.\n        \"\"\"\n        if (  # check if x-coordinates of r1 are within those of r2\n            r2.x0 - snap_x <= r1.x0 <= r2.x1 + snap_x\n            or r2.x0 - snap_x <= r1.x1 <= r2.x1 + snap_x\n        ) and (  # ... same for y-coordinates\n            r2.y0 - snap_y <= r1.y0 <= r2.y1 + snap_y\n            or r2.y0 - snap_y <= r1.y1 <= r2.y1 + snap_y\n        ):\n            return True\n\n        # same check with r1 / r2 exchanging their roles (this is necessary!)\n        if (\n            r1.x0 - snap_x <= r2.x0 <= r1.x1 + snap_x\n            or r1.x0 - snap_x <= r2.x1 <= r1.x1 + snap_x\n        ) and (\n            r1.y0 - snap_y <= r2.y0 <= r1.y1 + snap_y\n            or r1.y0 - snap_y <= r2.y1 <= r1.y1 + snap_y\n        ):\n            return True\n        return False\n\n    def clean_graphics(npaths=None):\n        \"\"\"Detect and join rectangles of \"connected\" vector graphics.\"\"\"\n        if npaths is None:\n            allpaths = page.get_drawings()\n        else:  # accept passed-in vector graphics\n            allpaths = npaths[:]  # paths relevant for table detection\n        paths = []\n        for p in allpaths:\n            # If only looking at lines, we ignore fill-only paths,\n            # except simulated lines (i.e. small width or height).\n            if (\n                lines_strict\n                and p[\"type\"] == \"f\"\n                and p[\"rect\"].width > snap_x\n                and p[\"rect\"].height > snap_y\n            ):\n                continue\n            paths.append(p)\n\n        # start with all vector graphics rectangles\n        prects = sorted(set([p[\"rect\"] for p in paths]), key=lambda r: (r.y1, r.x0))\n        new_rects = []  # the final list of joined rectangles\n        # ----------------------------------------------------------------\n        # Strategy: Join rectangles that \"almost touch\" each other.\n        # Extend first rectangle with any other that is a \"neighbor\".\n        # Then move it to the final list and continue with the rest.\n        # ----------------------------------------------------------------\n        while prects:  # the algorithm will empty this list\n            prect0 = prects[0]  # copy of first rectangle (performance reasons!)\n            repeat = True\n            while repeat:  # this loop extends first rect in list\n                repeat = False  # set to true again if some other rect touches\n                for i in range(len(prects) - 1, 0, -1):  # run backwards\n                    if are_neighbors(prect0, prects[i]):  # close enough to rect 0?\n                        prect0 |= prects[i].tl  # extend rect 0\n                        prect0 |= prects[i].br  # extend rect 0\n                        del prects[i]  # delete this rect\n                        repeat = True  # keep checking the rest\n\n            # move rect 0 over to result list if there is some text in it\n            if chars_in_rect(CHARS, prect0):\n                # contains text, so accept it as a table bbox candidate\n                new_rects.append(prect0)\n            del prects[0]  # remove from rect list\n\n        return new_rects, paths\n\n    bboxes, paths = clean_graphics(npaths=paths)\n\n    def is_parallel(p1, p2):\n        \"\"\"Check if line is roughly axis-parallel.\"\"\"\n        if abs(p1.x - p2.x) <= snap_x or abs(p1.y - p2.y) <= snap_y:\n            return True\n        return False\n\n    def make_line(p, p1, p2, clip):\n        \"\"\"Given 2 points, make a line dictionary for table detection.\"\"\"\n        if not is_parallel(p1, p2):  # only accepting axis-parallel lines\n            return {}\n        # compute the extremal values\n        x0 = min(p1.x, p2.x)\n        x1 = max(p1.x, p2.x)\n        y0 = min(p1.y, p2.y)\n        y1 = max(p1.y, p2.y)\n\n        # check for outside clip\n        if x0 > clip.x1 or x1 < clip.x0 or y0 > clip.y1 or y1 < clip.y0:\n            return {}\n\n        if x0 < clip.x0:\n            x0 = clip.x0  # adjust to clip boundary\n\n        if x1 > clip.x1:\n            x1 = clip.x1  # adjust to clip boundary\n\n        if y0 < clip.y0:\n            y0 = clip.y0  # adjust to clip boundary\n\n        if y1 > clip.y1:\n            y1 = clip.y1  # adjust to clip boundary\n\n        width = x1 - x0  # from adjusted values\n        height = y1 - y0  # from adjusted values\n        if width == height == 0:\n            return {}  # nothing left to deal with\n        line_dict = {\n            \"x0\": x0,\n            \"y0\": page_height - y0,\n            \"x1\": x1,\n            \"y1\": page_height - y1,\n            \"width\": width,\n            \"height\": height,\n            \"pts\": [(x0, y0), (x1, y1)],\n            \"linewidth\": p[\"width\"],\n            \"stroke\": True,\n            \"fill\": False,\n            \"evenodd\": False,\n            \"stroking_color\": p[\"color\"] if p[\"color\"] else p[\"fill\"],\n            \"non_stroking_color\": None,\n            \"object_type\": \"line\",\n            \"page_number\": page_number,\n            \"stroking_pattern\": None,\n            \"non_stroking_pattern\": None,\n            \"top\": y0,\n            \"bottom\": y1,\n            \"doctop\": y0 + doctop_basis,\n        }\n        return line_dict\n\n    for p in paths:\n        items = p[\"items\"]  # items in this path\n\n        # if 'closePath', add a line from last to first point\n        if p[\"closePath\"] and items[0][0] == \"l\" and items[-1][0] == \"l\":\n            items.append((\"l\", items[-1][2], items[0][1]))\n\n        for i in items:\n            if i[0] not in (\"l\", \"re\", \"qu\"):\n                continue  # ignore anything else\n\n            if i[0] == \"l\":  # a line\n                p1, p2 = i[1:]\n                line_dict = make_line(p, p1, p2, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n            elif i[0] == \"re\":\n                # A rectangle: decompose into 4 lines, but filter out\n                # the ones that simulate a line\n                rect = i[1].normalize()  # normalize the rectangle\n\n                if (\n                    rect.width <= min_length and rect.width < rect.height\n                ):  # simulates a vertical line\n                    x = abs(rect.x1 + rect.x0) / 2  # take middle value for x\n                    p1 = pymupdf.Point(x, rect.y0)\n                    p2 = pymupdf.Point(x, rect.y1)\n                    line_dict = make_line(p, p1, p2, clip)\n                    if line_dict:\n                        EDGES.append(line_to_edge(line_dict))\n                    continue\n\n                if (\n                    rect.height <= min_length and rect.height < rect.width\n                ):  # simulates a horizontal line\n                    y = abs(rect.y1 + rect.y0) / 2  # take middle value for y\n                    p1 = pymupdf.Point(rect.x0, y)\n                    p2 = pymupdf.Point(rect.x1, y)\n                    line_dict = make_line(p, p1, p2, clip)\n                    if line_dict:\n                        EDGES.append(line_to_edge(line_dict))\n                    continue\n\n                line_dict = make_line(p, rect.tl, rect.bl, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n                line_dict = make_line(p, rect.bl, rect.br, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n                line_dict = make_line(p, rect.br, rect.tr, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n                line_dict = make_line(p, rect.tr, rect.tl, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n            else:  # must be a quad\n                # we convert it into (up to) 4 lines\n                ul, ur, ll, lr = i[1]\n\n                line_dict = make_line(p, ul, ll, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n                line_dict = make_line(p, ll, lr, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n                line_dict = make_line(p, lr, ur, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n                line_dict = make_line(p, ur, ul, clip)\n                if line_dict:\n                    EDGES.append(line_to_edge(line_dict))\n\n    path = {\"color\": (0, 0, 0), \"fill\": None, \"width\": 1}\n    for bbox in bboxes:  # add the border lines for all enveloping bboxes\n        line_dict = make_line(path, bbox.tl, bbox.tr, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n\n        line_dict = make_line(path, bbox.bl, bbox.br, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n\n        line_dict = make_line(path, bbox.tl, bbox.bl, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n\n        line_dict = make_line(path, bbox.tr, bbox.br, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n\n    if add_lines is not None:  # add user-specified lines\n        assert isinstance(add_lines, (tuple, list))\n    else:\n        add_lines = []\n    for p1, p2 in add_lines:\n        p1 = pymupdf.Point(p1)\n        p2 = pymupdf.Point(p2)\n        line_dict = make_line(path, p1, p2, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n\n    if add_boxes is not None:  # add user-specified rectangles\n        assert isinstance(add_boxes, (tuple, list))\n    else:\n        add_boxes = []\n    for box in add_boxes:\n        r = pymupdf.Rect(box)\n        line_dict = make_line(path, r.tl, r.bl, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n        line_dict = make_line(path, r.bl, r.br, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n        line_dict = make_line(path, r.br, r.tr, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n        line_dict = make_line(path, r.tr, r.tl, clip)\n        if line_dict:\n            EDGES.append(line_to_edge(line_dict))\n\n\ndef page_rotation_set0(page):\n    \"\"\"Nullify page rotation.\n\n    To correctly detect tables, page rotation must be zero.\n    This function performs the necessary adjustments and returns information\n    for reverting this changes.\n    \"\"\"\n    mediabox = page.mediabox\n    rot = page.rotation  # contains normalized rotation value\n    # need to derotate the page's content\n    mb = page.mediabox  # current mediabox\n\n    if rot == 90:\n        # before derotation, shift content horizontally\n        mat0 = pymupdf.Matrix(1, 0, 0, 1, mb.y1 - mb.x1 - mb.x0 - mb.y0, 0)\n    elif rot == 270:\n        # before derotation, shift content vertically\n        mat0 = pymupdf.Matrix(1, 0, 0, 1, 0, mb.x1 - mb.y1 - mb.y0 - mb.x0)\n    else:\n        mat0 = pymupdf.Matrix(1, 0, 0, 1, -2 * mb.x0, -2 * mb.y0)\n\n    # prefix with derotation matrix\n    mat = mat0 * page.derotation_matrix\n    cmd = b\"%g %g %g %g %g %g cm \" % tuple(mat)\n    xref = pymupdf.TOOLS._insert_contents(page, cmd, 0)\n\n    # swap x- and y-coordinates\n    if rot in (90, 270):\n        x0, y0, x1, y1 = mb\n        mb.x0 = y0\n        mb.y0 = x0\n        mb.x1 = y1\n        mb.y1 = x1\n        page.set_mediabox(mb)\n\n    page.set_rotation(0)\n\n    # refresh the page to apply these changes\n    doc = page.parent\n    pno = page.number\n    page = doc[pno]\n    return page, xref, rot, mediabox\n\n\ndef page_rotation_reset(page, xref, rot, mediabox):\n    \"\"\"Reset page rotation to original values.\n\n    To be used before we return tables.\"\"\"\n    doc = page.parent  # document of the page\n    doc.update_stream(xref, b\" \")  # remove de-rotation matrix\n    page.set_mediabox(mediabox)  # set mediabox to old value\n    page.set_rotation(rot)  # set rotation to old value\n    pno = page.number\n    page = doc[pno]  # update page info\n    return page\n\n\ndef find_tables(\n    page,\n    clip=None,\n    vertical_strategy: str = \"lines\",\n    horizontal_strategy: str = \"lines\",\n    vertical_lines: list = None,\n    horizontal_lines: list = None,\n    snap_tolerance: float = DEFAULT_SNAP_TOLERANCE,\n    snap_x_tolerance: float = None,\n    snap_y_tolerance: float = None,\n    join_tolerance: float = DEFAULT_JOIN_TOLERANCE,\n    join_x_tolerance: float = None,\n    join_y_tolerance: float = None,\n    edge_min_length: float = 3,\n    min_words_vertical: float = DEFAULT_MIN_WORDS_VERTICAL,\n    min_words_horizontal: float = DEFAULT_MIN_WORDS_HORIZONTAL,\n    intersection_tolerance: float = 3,\n    intersection_x_tolerance: float = None,\n    intersection_y_tolerance: float = None,\n    text_tolerance=3,\n    text_x_tolerance=3,\n    text_y_tolerance=3,\n    strategy=None,  # offer abbreviation\n    add_lines=None,  # user-specified lines\n    add_boxes=None,  # user-specified rectangles\n    paths=None,  # accept vector graphics as parameter\n):\n    pymupdf._warn_layout_once()\n    CHARS.clear()\n    EDGES.clear()\n    TEXTPAGE = None\n    old_small = bool(pymupdf.TOOLS.set_small_glyph_heights())  # save old value\n    pymupdf.TOOLS.set_small_glyph_heights(True)  # we need minimum bboxes\n    if page.rotation != 0:\n        page, old_xref, old_rot, old_mediabox = page_rotation_set0(page)\n    else:\n        old_xref, old_rot, old_mediabox = None, None, None\n\n    if snap_x_tolerance is None:\n        snap_x_tolerance = UNSET\n    if snap_y_tolerance is None:\n        snap_y_tolerance = UNSET\n    if join_x_tolerance is None:\n        join_x_tolerance = UNSET\n    if join_y_tolerance is None:\n        join_y_tolerance = UNSET\n    if intersection_x_tolerance is None:\n        intersection_x_tolerance = UNSET\n    if intersection_y_tolerance is None:\n        intersection_y_tolerance = UNSET\n    if strategy is not None:\n        vertical_strategy = strategy\n        horizontal_strategy = strategy\n\n    settings = {\n        \"vertical_strategy\": vertical_strategy,\n        \"horizontal_strategy\": horizontal_strategy,\n        \"explicit_vertical_lines\": vertical_lines,\n        \"explicit_horizontal_lines\": horizontal_lines,\n        \"snap_tolerance\": snap_tolerance,\n        \"snap_x_tolerance\": snap_x_tolerance,\n        \"snap_y_tolerance\": snap_y_tolerance,\n        \"join_tolerance\": join_tolerance,\n        \"join_x_tolerance\": join_x_tolerance,\n        \"join_y_tolerance\": join_y_tolerance,\n        \"edge_min_length\": edge_min_length,\n        \"min_words_vertical\": min_words_vertical,\n        \"min_words_horizontal\": min_words_horizontal,\n        \"intersection_tolerance\": intersection_tolerance,\n        \"intersection_x_tolerance\": intersection_x_tolerance,\n        \"intersection_y_tolerance\": intersection_y_tolerance,\n        \"text_tolerance\": text_tolerance,\n        \"text_x_tolerance\": text_x_tolerance,\n        \"text_y_tolerance\": text_y_tolerance,\n    }\n\n    old_quad_corrections = pymupdf.TOOLS.unset_quad_corrections()\n    try:\n        page.get_layout()\n        if page.layout_information:\n            pymupdf.TOOLS.unset_quad_corrections(True)\n            boxes = [\n                pymupdf.Rect(b[:4]) for b in page.layout_information if b[-1] == \"table\"\n            ]\n        else:\n            boxes = []\n\n        if boxes:  # layout did find some tables\n            pass\n        elif page.layout_information is not None:\n            # layout was executed but found no tables\n            # make sure we exit quickly with an empty TableFinder\n            tbf = TableFinder(page)\n            return tbf\n\n        tset = TableSettings.resolve(settings=settings)\n        page.table_settings = tset\n\n        TEXTPAGE = make_chars(page, clip=clip)  # create character list of page\n        make_edges(\n            page,\n            clip=clip,\n            tset=tset,\n            paths=paths,\n            add_lines=add_lines,\n            add_boxes=add_boxes,\n        )  # create lines and curves\n\n        tbf = TableFinder(page, settings=tset)\n        tbf.textpage = TEXTPAGE  # store textpage for later use\n        if boxes:\n            # only keep Finder tables that match a layout box\n            tbf.tables = [\n                tab\n                for tab in tbf.tables\n                if any(_iou(tab.bbox, r) >= 0.6 for r in boxes)\n            ]\n        # build the complementary list of layout table boxes\n        my_boxes = [\n            r for r in boxes if all(_iou(r, tab.bbox) < 0.6 for tab in tbf.tables)\n        ]\n        if my_boxes:\n            word_rects = [pymupdf.Rect(w[:4]) for w in TEXTPAGE.extractWORDS()]\n            tp2 = page.get_textpage(flags=TABLE_DETECTOR_FLAGS)\n        for rect in my_boxes:\n            cells = make_table_from_bbox(tp2, word_rects, rect)  # pylint: disable=E0606\n            tbf.tables.append(Table(page, cells))\n    except Exception as e:\n        pymupdf.message(\"find_tables: exception occurred: %s\" % str(e))\n        return None\n    finally:\n        pymupdf.TOOLS.set_small_glyph_heights(old_small)\n        if old_xref is not None:\n            page = page_rotation_reset(page, old_xref, old_rot, old_mediabox)\n        pymupdf.TOOLS.unset_quad_corrections(old_quad_corrections)\n    for table in tbf.tables:\n        table.textpage = TEXTPAGE\n    return tbf\n"
  },
  {
    "path": "src/utils.py",
    "content": "# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\nimport math\nimport typing\nimport weakref\n\ntry:\n    from . import pymupdf\nexcept Exception:\n    import pymupdf\n\n_format_g = pymupdf.format_g\n\ng_exceptions_verbose = pymupdf.g_exceptions_verbose\n\npoint_like = \"point_like\"\nrect_like = \"rect_like\"\nmatrix_like = \"matrix_like\"\nquad_like = \"quad_like\"\n\n# ByteString is gone from typing in 3.14.\n# collections.abc.Buffer available from 3.12 only\ntry:\n    ByteString = typing.ByteString\nexcept AttributeError:\n    # pylint: disable=unsupported-binary-operation\n    ByteString = bytes | bytearray | memoryview\n\nAnyType = typing.Any\nOptInt = typing.Union[int, None]\nOptFloat = typing.Optional[float]\nOptStr = typing.Optional[str]\nOptDict = typing.Optional[dict]\nOptBytes = typing.Optional[ByteString]\nOptSeq = typing.Optional[typing.Sequence]\n\n\"\"\"\nThis is a collection of functions to extend PyMupdf.\n\"\"\"\n\n\ndef get_text_blocks(\n    page: pymupdf.Page,\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: pymupdf.TextPage = None,\n    sort: bool = False,\n) -> list:\n    \"\"\"Return the text blocks on a page.\n\n    Notes:\n        Lines in a block are concatenated with line breaks.\n    Args:\n        flags: (int) control the amount of data parsed into the textpage.\n    Returns:\n        A list of the blocks. Each item contains the containing rectangle\n        coordinates, text lines, running block number and block type.\n    \"\"\"\n    pymupdf.CheckParent(page)\n    if flags is None:\n        flags = pymupdf.TEXTFLAGS_BLOCKS\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=flags)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n\n    blocks = tp.extractBLOCKS()\n    if textpage is None:\n        del tp\n    if sort:\n        blocks.sort(key=lambda b: (b[3], b[0]))\n    return blocks\n\n\ndef get_text_words(\n    page: pymupdf.Page,\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: pymupdf.TextPage = None,\n    sort: bool = False,\n    delimiters=None,\n    tolerance=3,\n) -> list:\n    \"\"\"Return the text words as a list with the bbox for each word.\n\n    Args:\n        page: pymupdf.Page\n        clip: (rect-like) area on page to consider\n        flags: (int) control the amount of data parsed into the textpage.\n        textpage: (pymupdf.TextPage) either passed-in or None.\n        sort: (bool) sort the words in reading sequence.\n        delimiters: (str,list) characters to use as word delimiters.\n        tolerance: (float) consider words to be part of the same line if\n            top or bottom coordinate are not larger than this. Relevant\n            only if sort=True.\n\n    Returns:\n        Word tuples (x0, y0, x1, y1, \"word\", bno, lno, wno).\n    \"\"\"\n\n    def sort_words(words):\n        \"\"\"Sort words line-wise, forgiving small deviations.\"\"\"\n        words.sort(key=lambda w: (w[3], w[0]))\n        nwords = []  # final word list\n        line = [words[0]]  # collects words roughly in same line\n        lrect = pymupdf.Rect(words[0][:4])  # start the line rectangle\n        for w in words[1:]:\n            wrect = pymupdf.Rect(w[:4])\n            if (\n                abs(wrect.y0 - lrect.y0) <= tolerance\n                or abs(wrect.y1 - lrect.y1) <= tolerance\n            ):\n                line.append(w)\n                lrect |= wrect\n            else:\n                line.sort(key=lambda w: w[0])  # sort words in line l-t-r\n                nwords.extend(line)  # append to final words list\n                line = [w]  # start next line\n                lrect = wrect  # start next line rect\n\n        line.sort(key=lambda w: w[0])  # sort words in line l-t-r\n        nwords.extend(line)  # append to final words list\n\n        return nwords\n\n    pymupdf.CheckParent(page)\n    if flags is None:\n        flags = pymupdf.TEXTFLAGS_WORDS\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=flags)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n\n    words = tp.extractWORDS(delimiters)\n\n    # if textpage was given, we subselect the words in clip\n    if textpage is not None and clip is not None:\n        # sub-select words contained in clip\n        clip = pymupdf.Rect(clip)\n        words = [\n            w for w in words if abs(clip & w[:4]) >= 0.5 * abs(pymupdf.Rect(w[:4]))\n        ]\n\n    if textpage is None:\n        del tp\n    if words and sort:\n        # advanced sort if any words found\n        words = sort_words(words)\n\n    return words\n\n\ndef get_sorted_text(\n    page: pymupdf.Page,\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: pymupdf.TextPage = None,\n    tolerance=3,\n) -> str:\n    \"\"\"Extract plain text avoiding unacceptable line breaks.\n\n    Text contained in clip will be sorted in reading sequence. Some effort\n    is also spent to simulate layout vertically and horizontally.\n\n    Args:\n        page: pymupdf.Page\n        clip: (rect-like) only consider text inside\n        flags: (int) text extraction flags\n        textpage: pymupdf.TextPage\n        tolerance: (float) consider words to be on the same line if their top\n            or bottom coordinates do not differ more than this.\n\n    Notes:\n        If a TextPage is provided, all text is checked for being inside clip\n        with at least 50% of its bbox.\n        This allows to use some \"global\" TextPage in conjunction with sub-\n        selecting words in parts of the defined TextPage rectangle.\n\n    Returns:\n        A text string in reading sequence. Left indentation of each line,\n        inter-line and inter-word distances strive to reflect the layout.\n    \"\"\"\n\n    def line_text(clip, line):\n        \"\"\"Create the string of one text line.\n\n        We are trying to simulate some horizontal layout here, too.\n\n        Args:\n            clip: (pymupdf.Rect) the area from which all text is being read.\n            line: (list) word tuples (rect, text) contained in the line\n        Returns:\n            Text in this line. Generated from words in 'line'. Distance from\n            predecessor is translated to multiple spaces, thus simulating\n            text indentations and large horizontal distances.\n        \"\"\"\n        line.sort(key=lambda w: w[0].x0)\n        ltext = \"\"  # text in the line\n        x1 = clip.x0  # end coordinate of ltext\n        lrect = pymupdf.EMPTY_RECT()  # bbox of this line\n        for r, t in line:\n            lrect |= r  # update line bbox\n            # convert distance to previous word to multiple spaces\n            dist = max(\n                int(round((r.x0 - x1) / r.width * len(t))),\n                0 if (x1 == clip.x0 or r.x0 <= x1) else 1,\n            )  # number of space characters\n\n            ltext += \" \" * dist + t  # append word string\n            x1 = r.x1  # update new end position\n        return ltext\n\n    # Extract words in correct sequence first.\n    words = [\n        (pymupdf.Rect(w[:4]), w[4])\n        for w in get_text_words(\n            page,\n            clip=clip,\n            flags=flags,\n            textpage=textpage,\n            sort=True,\n            tolerance=tolerance,\n        )\n    ]\n\n    if not words:  # no text present\n        return \"\"\n    totalbox = pymupdf.EMPTY_RECT()  # area covering all text\n    for wr, text in words:\n        totalbox |= wr\n\n    lines = []  # list of reconstituted lines\n    line = [words[0]]  # current line\n    lrect = words[0][0]  # the line's rectangle\n\n    # walk through the words\n    for wr, text in words[1:]:  # start with second word\n        w0r, _ = line[-1]  # read previous word in current line\n\n        # if this word matches top or bottom of the line, append it\n        if abs(lrect.y0 - wr.y0) <= tolerance or abs(lrect.y1 - wr.y1) <= tolerance:\n            line.append((wr, text))\n            lrect |= wr\n        else:\n            # output current line and re-initialize\n            ltext = line_text(totalbox, line)\n            lines.append((lrect, ltext))\n            line = [(wr, text)]\n            lrect = wr\n\n    # also append unfinished last line\n    ltext = line_text(totalbox, line)\n    lines.append((lrect, ltext))\n\n    # sort all lines vertically\n    lines.sort(key=lambda l: (l[0].y1))\n\n    text = lines[0][1]  # text of first line\n    y1 = lines[0][0].y1  # its bottom coordinate\n    for lrect, ltext in lines[1:]:\n        distance = min(int(round((lrect.y0 - y1) / lrect.height)), 5)\n        breaks = \"\\n\" * (distance + 1)\n        text += breaks + ltext\n        y1 = lrect.y1\n\n    # return text in clip\n    return text\n\n\ndef get_textbox(\n    page: pymupdf.Page,\n    rect: rect_like,\n    textpage: pymupdf.TextPage = None,\n) -> str:\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage()\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n    rc = tp.extractTextbox(rect)\n    if textpage is None:\n        del tp\n    return rc\n\n\ndef get_text_selection(\n    page: pymupdf.Page,\n    p1: point_like,\n    p2: point_like,\n    clip: rect_like = None,\n    textpage: pymupdf.TextPage = None,\n):\n    pymupdf.CheckParent(page)\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=pymupdf.TEXT_DEHYPHENATE)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n    rc = tp.extractSelection(p1, p2)\n    if textpage is None:\n        del tp\n    return rc\n\n\ndef get_textpage_ocr(\n    page: pymupdf.Page,\n    flags: int = 0,\n    language: str = \"eng\",\n    dpi: int = 72,\n    full: bool = False,\n    tessdata: str = None,\n) -> pymupdf.TextPage:\n    \"\"\"Create a Textpage from the OCR version of the page.\n\n    OCR can be executed for the full page image, or (the default) only\n    for areas that are not covered by readable digital text.\n\n    Args:\n        flags: (int) control content becoming part of the result.\n        language: (str) specify expected language(s). Default is \"eng\" (English).\n        dpi: (int) resolution in dpi, default 72.\n        full: (bool) whether to OCR the full page, or to keep legible text\n        tessdata: (str) path to Tesseract language data files. If None, the\n                  built-in function is used to find the path.\n    \"\"\"\n    pymupdf.CheckParent(page)\n    tessdata = pymupdf.get_tessdata(tessdata)\n\n    # Ensure 0xFFFD is not suppressed\n    flags = (\n        flags\n        & ~pymupdf.TEXT_USE_CID_FOR_UNKNOWN_UNICODE  # pylint: disable=no-member\n        & ~pymupdf.TEXT_USE_GID_FOR_UNKNOWN_UNICODE  # pylint: disable=no-member\n    )\n\n    def full_ocr(page, dpi, language, flags):\n        \"\"\"Perform OCR for the full page image.\"\"\"\n        pix = page.get_pixmap(dpi=dpi)\n        # create a 1-page PDF with an OCR text layer.\n        ocr_pdf = pymupdf.Document(\n            stream=pix.pdfocr_tobytes(\n                compress=False,\n                language=language,\n                tessdata=tessdata,\n            ),\n        )\n        ocr_page = ocr_pdf.load_page(0)\n        unzoom = page.rect.width / ocr_page.rect.width\n        ctm = pymupdf.Matrix(unzoom, unzoom) * page.derotation_matrix\n        tpage = ocr_page.get_textpage(flags=flags, matrix=ctm)\n\n        # associate the textpage with the original page\n        tpage.parent = weakref.proxy(page)\n        return tpage\n\n    def partial_ocr(page, dpi, language, flags):\n        \"\"\"Perform OCR for parts of the page without legible text.\n\n        We create a temporary PDF for which we can freely redact text.\n        \"\"\"\n        doc = page.parent\n\n        # make temporary PDF with the passed-in page\n        temp_pdf = pymupdf.open()\n        temp_pdf.insert_pdf(doc, from_page=page.number, to_page=page.number)\n        temp_page = temp_pdf.load_page(0)\n        temp_page.remove_rotation()  # avoid OCR problems with rotated pages\n\n        # extract text bboxes from the page\n        tp = temp_page.get_textpage(flags=flags)\n        blocks = tp.extractDICT()[\"blocks\"]\n\n        \"\"\"\n        For partial OCR we need a TextPage that contains legible text only.\n        Illegible text must be passed to the OCR engine.\n        \"\"\"\n        # Select spans with illegible text. If present, remove them first.\n        fffd_spans = [\n            s[\"bbox\"]\n            for b in blocks\n            if b[\"type\"] == 0\n            for l in b[\"lines\"]\n            for s in l[\"spans\"]\n            if chr(0xFFFD) in s[\"text\"]\n        ]\n        if fffd_spans:\n            for bbox in fffd_spans:\n                temp_page.add_redact_annot(bbox)\n            temp_page.apply_redactions(\n                images=pymupdf.PDF_REDACT_IMAGE_NONE,  # pylint: disable=no-member\n                graphics=pymupdf.PDF_REDACT_LINE_ART_NONE,  # pylint: disable=no-member\n                text=pymupdf.PDF_REDACT_TEXT_REMOVE,  # pylint: disable=no-member\n            )\n            # Extract text again, now without the unreadable spans.\n            tp = temp_page.get_textpage(flags=flags)\n            blocks = tp.extractDICT()[\"blocks\"]\n            # We also need a fresh copy of the original page.\n            temp_pdf.insert_pdf(doc, from_page=page.number, to_page=page.number)\n            temp_page = temp_pdf.load_page(-1)\n            temp_page.remove_rotation()  # avoid OCR problems with rotated pages\n\n        span_bboxes = [\n            s[\"bbox\"]\n            for b in blocks\n            if b[\"type\"] == 0\n            for l in b[\"lines\"]\n            for s in l[\"spans\"]\n            if not chr(0xFFFD) in s[\"text\"]\n        ]\n\n        # Remove digital text by redacting the span bboxes.\n        # Then OCR the remainder of the page.\n        for bbox in span_bboxes:\n            temp_page.add_redact_annot(bbox)\n\n        # only remove text, no images, no vectors\n        temp_page.apply_redactions(\n            images=pymupdf.PDF_REDACT_IMAGE_NONE,  # pylint: disable=no-member\n            graphics=pymupdf.PDF_REDACT_LINE_ART_NONE,  # pylint: disable=no-member\n            text=pymupdf.PDF_REDACT_TEXT_REMOVE,  # pylint: disable=no-member\n        )\n        pix = temp_page.get_pixmap(dpi=dpi)\n        # matrix = pymupdf.Rect(pix.irect).torect(page.rect)\n\n        # OCR the redacted page\n        ocr_pdf = pymupdf.open(\n            stream=pix.pdfocr_tobytes(\n                compress=False,\n                language=language,\n                tessdata=tessdata,\n            ),\n        )\n        ocr_page = ocr_pdf[0]\n\n        # Extend the original textpage with OCR-ed text.\n        ocr_page.extend_textpage(tp, flags=pymupdf.TEXT_ACCURATE_BBOXES)\n\n        # associate the textpage with the original page\n        tp.parent = weakref.proxy(page)\n        return tp\n\n    # if OCR for the full page, OCR its pixmap @ desired dpi\n    if full:\n        return full_ocr(page, dpi, language, flags)\n\n    # For partial OCR, make a normal textpage, then extend it with text that\n    # is OCRed from the rest of page.\n    return partial_ocr(page, dpi, language, flags)\n\n\ndef get_text(\n    page: pymupdf.Page,\n    option: str = \"text\",\n    *,\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: pymupdf.TextPage = None,\n    sort: bool = False,\n    delimiters=None,\n    tolerance=3,\n):\n    \"\"\"Extract text from a page or an annotation.\n\n    This is a unifying wrapper for various methods of the pymupdf.TextPage class.\n\n    Args:\n        option: (str) text, words, blocks, html, dict, json, rawdict, xhtml or xml.\n        clip: (rect-like) restrict output to this area.\n        flags: bit switches to e.g. exclude images or decompose ligatures.\n        textpage: reuse this pymupdf.TextPage and make no new one. If specified,\n            'flags' and 'clip' are ignored.\n\n    Returns:\n        the output of methods get_text_words / get_text_blocks or pymupdf.TextPage\n        methods extractText, extractHTML, extractDICT, extractJSON, extractRAWDICT,\n        extractXHTML or etractXML respectively.\n        Default and misspelling choice is \"text\".\n    \"\"\"\n    formats = {\n        \"text\": pymupdf.TEXTFLAGS_TEXT,\n        \"html\": pymupdf.TEXTFLAGS_HTML,\n        \"json\": pymupdf.TEXTFLAGS_DICT,\n        \"rawjson\": pymupdf.TEXTFLAGS_RAWDICT,\n        \"xml\": pymupdf.TEXTFLAGS_XML,\n        \"xhtml\": pymupdf.TEXTFLAGS_XHTML,\n        \"dict\": pymupdf.TEXTFLAGS_DICT,\n        \"rawdict\": pymupdf.TEXTFLAGS_RAWDICT,\n        \"words\": pymupdf.TEXTFLAGS_WORDS,\n        \"blocks\": pymupdf.TEXTFLAGS_BLOCKS,\n    }\n    option = option.lower()\n    assert option in formats\n    if option not in formats:\n        option = \"text\"\n    if flags is None:\n        flags = formats[option]\n\n    if option == \"words\":\n        return get_text_words(\n            page,\n            clip=clip,\n            flags=flags,\n            textpage=textpage,\n            sort=sort,\n            delimiters=delimiters,\n        )\n    if option == \"blocks\":\n        return get_text_blocks(\n            page, clip=clip, flags=flags, textpage=textpage, sort=sort\n        )\n\n    if option == \"text\" and sort:\n        return get_sorted_text(\n            page,\n            clip=clip,\n            flags=flags,\n            textpage=textpage,\n            tolerance=tolerance,\n        )\n\n    pymupdf.CheckParent(page)\n    cb = None\n    if option in (\"html\", \"xml\", \"xhtml\"):  # no clipping for MuPDF functions\n        clip = page.cropbox\n    if clip is not None:\n        clip = pymupdf.Rect(clip)\n        cb = None\n    elif type(page) is pymupdf.Page:\n        cb = page.cropbox\n    # pymupdf.TextPage with or without images\n    tp = textpage\n    #pymupdf.exception_info()\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=flags)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n    #pymupdf.log( '{option=}')\n    if option == \"json\":\n        t = tp.extractJSON(cb=cb, sort=sort)\n    elif option == \"rawjson\":\n        t = tp.extractRAWJSON(cb=cb, sort=sort)\n    elif option == \"dict\":\n        t = tp.extractDICT(cb=cb, sort=sort)\n    elif option == \"rawdict\":\n        t = tp.extractRAWDICT(cb=cb, sort=sort)\n    elif option == \"html\":\n        t = tp.extractHTML()\n    elif option == \"xml\":\n        t = tp.extractXML()\n    elif option == \"xhtml\":\n        t = tp.extractXHTML()\n    else:\n        t = tp.extractText(sort=sort)\n\n    if textpage is None:\n        del tp\n    return t\n\n\ndef getLinkDict(ln, document=None) -> dict:\n    if isinstance(ln, pymupdf.Outline):\n        dest = ln.destination(document)\n    elif isinstance(ln, pymupdf.Link):\n        dest = ln.dest\n    else:\n        assert 0, f'Unexpected {type(ln)=}.'\n    nl = {\"kind\": dest.kind, \"xref\": 0}\n    try:\n        if hasattr(ln, 'rect'):\n            nl[\"from\"] = ln.rect\n    except Exception:\n        # This seems to happen quite often in PyMuPDF/tests.\n        if g_exceptions_verbose >= 2:   pymupdf.exception_info()\n        pass\n    pnt = pymupdf.Point(0, 0)\n    if dest.flags & pymupdf.LINK_FLAG_L_VALID:\n        pnt.x = dest.lt.x\n    if dest.flags & pymupdf.LINK_FLAG_T_VALID:\n        pnt.y = dest.lt.y\n\n    if dest.kind == pymupdf.LINK_URI:\n        nl[\"uri\"] = dest.uri\n\n    elif dest.kind == pymupdf.LINK_GOTO:\n        nl[\"page\"] = dest.page\n        nl[\"to\"] = pnt\n        if dest.flags & pymupdf.LINK_FLAG_R_IS_ZOOM:\n            nl[\"zoom\"] = dest.rb.x\n        else:\n            nl[\"zoom\"] = 0.0\n\n    elif dest.kind == pymupdf.LINK_GOTOR:\n        nl[\"file\"] = dest.file_spec.replace(\"\\\\\", \"/\")\n        nl[\"page\"] = dest.page\n        if dest.page < 0:\n            nl[\"to\"] = dest.dest\n        else:\n            nl[\"to\"] = pnt\n            if dest.flags & pymupdf.LINK_FLAG_R_IS_ZOOM:\n                nl[\"zoom\"] = dest.rb.x\n            else:\n                nl[\"zoom\"] = 0.0\n\n    elif dest.kind == pymupdf.LINK_LAUNCH:\n        nl[\"file\"] = dest.file_spec.replace(\"\\\\\", \"/\")\n\n    elif dest.kind == pymupdf.LINK_NAMED:\n        # The dicts should not have same key(s).\n        assert not (dest.named.keys() & nl.keys())\n        nl.update(dest.named)\n        if 'to' in nl:\n            nl['to'] = pymupdf.Point(nl['to'])\n\n    else:\n        nl[\"page\"] = dest.page\n    return nl\n\n\ndef getDestStr(xref: int, ddict: dict) -> str:\n    \"\"\"Calculate the PDF action string.\n\n    Notes:\n        Supports Link annotations and outline items (bookmarks).\n    \"\"\"\n    if not ddict:\n        return \"\"\n    str_goto = lambda a, b, c, d: f\"/A<</S/GoTo/D[{a} 0 R/XYZ {_format_g((b, c, d))}]>>\"\n    str_gotor1 = lambda a, b, c, d, e, f: f\"/A<</S/GoToR/D[{a} /XYZ {_format_g((b, c, d))}]/F<</F{e}/UF{f}/Type/Filespec>>>>\"\n    str_gotor2 = lambda a, b, c: f\"/A<</S/GoToR/D{a}/F<</F{b}/UF{c}/Type/Filespec>>>>\"\n    str_launch = lambda a, b: f\"/A<</S/Launch/F<</F{a}/UF{b}/Type/Filespec>>>>\"\n    str_uri = lambda a: f\"/A<</S/URI/URI{a}>>\"\n\n    if type(ddict) in (int, float):\n        dest = str_goto(xref, 0, ddict, 0)\n        return dest\n    d_kind = ddict.get(\"kind\", pymupdf.LINK_NONE)\n\n    if d_kind == pymupdf.LINK_NONE:\n        return \"\"\n\n    if ddict[\"kind\"] == pymupdf.LINK_GOTO:\n        d_zoom = ddict.get(\"zoom\", 0)\n        to = ddict.get(\"to\", pymupdf.Point(0, 0))\n        d_left, d_top = to\n        dest = str_goto(xref, d_left, d_top, d_zoom)\n        return dest\n\n    if ddict[\"kind\"] == pymupdf.LINK_URI:\n        dest = str_uri(pymupdf.get_pdf_str(ddict[\"uri\"]),)\n        return dest\n\n    if ddict[\"kind\"] == pymupdf.LINK_LAUNCH:\n        fspec = pymupdf.get_pdf_str(ddict[\"file\"])\n        dest = str_launch(fspec, fspec)\n        return dest\n\n    if ddict[\"kind\"] == pymupdf.LINK_GOTOR and ddict[\"page\"] < 0:\n        fspec = pymupdf.get_pdf_str(ddict[\"file\"])\n        dest = str_gotor2(pymupdf.get_pdf_str(ddict[\"to\"]), fspec, fspec)\n        return dest\n\n    if ddict[\"kind\"] == pymupdf.LINK_GOTOR and ddict[\"page\"] >= 0:\n        fspec = pymupdf.get_pdf_str(ddict[\"file\"])\n        dest = str_gotor1(\n            ddict[\"page\"],\n            ddict[\"to\"].x,\n            ddict[\"to\"].y,\n            ddict[\"zoom\"],\n            fspec,\n            fspec,\n        )\n        return dest\n\n    return \"\"\n\n\ndef getLinkText(page: pymupdf.Page, lnk: dict) -> str:\n    # --------------------------------------------------------------------------\n    # define skeletons for /Annots object texts\n    # --------------------------------------------------------------------------\n    ctm = page.transformation_matrix\n    ictm = ~ctm\n    r = lnk[\"from\"]\n    rect = _format_g(tuple(r * ictm))\n\n    annot = \"\"\n    if lnk[\"kind\"] == pymupdf.LINK_GOTO:\n        if lnk[\"page\"] >= 0:\n            txt = pymupdf.annot_skel[\"goto1\"]  # annot_goto\n            pno = lnk[\"page\"]\n            xref = page.parent.page_xref(pno)\n            pnt = lnk.get(\"to\", pymupdf.Point(0, 0))  # destination point\n            dest_page = page.parent[pno]\n            dest_ctm = dest_page.transformation_matrix\n            dest_ictm = ~dest_ctm\n            ipnt = pnt * dest_ictm\n            annot = txt(xref, ipnt.x, ipnt.y, lnk.get(\"zoom\", 0), rect)\n        else:\n            txt = pymupdf.annot_skel[\"goto2\"]  # annot_goto_n\n            annot = txt(pymupdf.get_pdf_str(lnk[\"to\"]), rect)\n\n    elif lnk[\"kind\"] == pymupdf.LINK_GOTOR:\n        if lnk[\"page\"] >= 0:\n            txt = pymupdf.annot_skel[\"gotor1\"]  # annot_gotor\n            pnt = lnk.get(\"to\", pymupdf.Point(0, 0))  # destination point\n            if type(pnt) is not pymupdf.Point:\n                pnt = pymupdf.Point(0, 0)\n            annot = txt(\n                lnk[\"page\"],\n                pnt.x,\n                pnt.y,\n                lnk.get(\"zoom\", 0),\n                lnk[\"file\"],\n                lnk[\"file\"],\n                rect,\n            )\n        else:\n            txt = pymupdf.annot_skel[\"gotor2\"]  # annot_gotor_n\n            annot = txt(pymupdf.get_pdf_str(lnk[\"to\"]), lnk[\"file\"], rect)\n\n    elif lnk[\"kind\"] == pymupdf.LINK_LAUNCH:\n        txt = pymupdf.annot_skel[\"launch\"]  # annot_launch\n        annot = txt(lnk[\"file\"], lnk[\"file\"], rect)\n\n    elif lnk[\"kind\"] == pymupdf.LINK_URI:\n        txt = pymupdf.annot_skel[\"uri\"]  # txt = annot_uri\n        annot = txt(lnk[\"uri\"], rect)\n\n    elif lnk[\"kind\"] == pymupdf.LINK_NAMED:\n        txt = pymupdf.annot_skel[\"named\"]  # annot_named\n        lname = lnk.get(\"name\")  # check presence of key\n        if lname is None:  # if missing, fall back to alternative\n            lname = lnk[\"nameddest\"]\n        annot = txt(lname, rect)\n    if not annot:\n        return annot\n\n    # add a /NM PDF key to the object definition\n    link_names = dict(  # existing ids and their xref\n        [(x[0], x[2]) for x in page.annot_xrefs() if x[1] == pymupdf.PDF_ANNOT_LINK]   # pylint: disable=no-member\n    )\n\n    old_name = lnk.get(\"id\", \"\")  # id value in the argument\n\n    if old_name and (lnk[\"xref\"], old_name) in link_names.items():\n        name = old_name  # no new name if this is an update only\n    else:\n        i = 0\n        stem = pymupdf.TOOLS.set_annot_stem() + \"-L%i\"\n        while True:\n            name = stem % i\n            if name not in link_names.values():\n                break\n            i += 1\n    # add /NM key to object definition\n    annot = annot.replace(f\"/Link\", f\"/Link/NM({name})\")\n    return annot\n\n\n# ----------------------------------------------------------------------\n# Name:        wx.lib.colourdb.py\n# Purpose:     Adds a bunch of colour names and RGB values to the\n#              colour database so they can be found by name\n#\n# Author:      Robin Dunn\n#\n# Created:     13-March-2001\n# Copyright:   (c) 2001-2017 by Total Control Software\n# Licence:     wxWindows license\n# Tags:        phoenix-port, unittest, documented\n# ----------------------------------------------------------------------\n\n\ndef getColorList() -> list:\n    \"\"\"\n    Returns a list of upper-case colour names.\n    :rtype: list of strings\n    \"\"\"\n    return [name for name, r, g, b in pymupdf.colors_wx_list()]\n\n\ndef getColorInfoList() -> list:\n    \"\"\"\n    Returns list of (name, red, gree, blue) tuples, where:\n        name: upper-case color name.\n        read, green, blue: integers in range 0..255.\n    :rtype: list of tuples\n    \"\"\"\n    return pymupdf.colors_wx_list()\n\n\ndef getColor(name: str) -> tuple:\n    \"\"\"Retrieve RGB color in PDF format by name.\n\n    Returns:\n        a triple of floats in range 0 to 1. In case of name-not-found, \"white\" is returned.\n    \"\"\"\n    return pymupdf.colors_pdf_dict().get(name.lower(), (1, 1, 1))\n\n\ndef getColorHSV(name: str) -> tuple:\n    \"\"\"Retrieve the hue, saturation, value triple of a color name.\n\n    Returns:\n        a triple (degree, percent, percent). If not found (-1, -1, -1) is returned.\n    \"\"\"\n    try:\n        x = getColorInfoList()[getColorList().index(name.upper())]\n    except Exception:\n        if g_exceptions_verbose:    pymupdf.exception_info()\n        return (-1, -1, -1)\n\n    r = x[1] / 255.0\n    g = x[2] / 255.0\n    b = x[3] / 255.0\n    cmax = max(r, g, b)\n    V = round(cmax * 100, 1)\n    cmin = min(r, g, b)\n    delta = cmax - cmin\n    if delta == 0:\n        hue = 0\n    elif cmax == r:\n        hue = 60.0 * (((g - b) / delta) % 6)\n    elif cmax == g:\n        hue = 60.0 * (((b - r) / delta) + 2)\n    else:\n        hue = 60.0 * (((r - g) / delta) + 4)\n\n    H = int(round(hue))\n\n    if cmax == 0:\n        sat = 0\n    else:\n        sat = delta / cmax\n    S = int(round(sat * 100))\n\n    return (H, S, V)\n\n\ndef _get_font_properties(doc: pymupdf.Document, xref: int) -> tuple:\n    fontname, ext, stype, buffer = doc.extract_font(xref)\n    asc = 0.8\n    dsc = -0.2\n    if ext == \"\":\n        return fontname, ext, stype, asc, dsc\n\n    if buffer:\n        try:\n            font = pymupdf.Font(fontbuffer=buffer)\n            asc = font.ascender\n            dsc = font.descender\n            bbox = font.bbox\n            if asc - dsc < 1:\n                if bbox.y0 < dsc:\n                    dsc = bbox.y0\n                asc = 1 - dsc\n        except Exception:\n            pymupdf.exception_info()\n            asc *= 1.2\n            dsc *= 1.2\n        return fontname, ext, stype, asc, dsc\n    if ext != \"n/a\":\n        try:\n            font = pymupdf.Font(fontname)\n            asc = font.ascender\n            dsc = font.descender\n        except Exception:\n            pymupdf.exception_info()\n            asc *= 1.2\n            dsc *= 1.2\n    else:\n        asc *= 1.2\n        dsc *= 1.2\n    return fontname, ext, stype, asc, dsc\n\n\ndef _show_fz_text( text):\n    #if mupdf_cppyy:\n    #    assert isinstance( text, cppyy.gbl.mupdf.Text)\n    #else:\n    #    assert isinstance( text, mupdf.Text)\n    num_spans = 0\n    num_chars = 0\n    span = text.m_internal.head\n    while 1:\n        if not span:\n            break\n        num_spans += 1\n        num_chars += span.len\n        span = span.next\n    return f'num_spans={num_spans} num_chars={num_chars}'\n\n\n\"\"\"\nHandle page labels for PDF documents.\n\nReading\n-------\n* compute the label of a page\n* find page number(s) having the given label.\n\nWriting\n-------\nSupports setting (defining) page labels for PDF documents.\n\nA big Thank You goes to WILLIAM CHAPMAN who contributed the idea and\nsignificant parts of the following code during late December 2020\nthrough early January 2021.\n\"\"\"\n\n\ndef rule_dict(item):\n    \"\"\"Make a Python dict from a PDF page label rule.\n\n    Args:\n        item -- a tuple (pno, rule) with the start page number and the rule\n                string like <</S/D...>>.\n    Returns:\n        A dict like\n        {'startpage': int, 'prefix': str, 'style': str, 'firstpagenum': int}.\n    \"\"\"\n    # Jorj McKie, 2021-01-06\n\n    pno, rule = item\n    rule = rule[2:-2].split(\"/\")[1:]  # strip \"<<\" and \">>\"\n    d = {\"startpage\": pno, \"prefix\": \"\", \"firstpagenum\": 1}\n    skip = False\n    for i, item in enumerate(rule): # pylint: disable=redefined-argument-from-local\n        if skip:  # this item has already been processed\n            skip = False  # deactivate skipping again\n            continue\n        if item == \"S\":  # style specification\n            d[\"style\"] = rule[i + 1]  # next item has the style\n            skip = True  # do not process next item again\n            continue\n        if item.startswith(\"P\"):  # prefix specification: extract the string\n            x = item[1:].replace(\"(\", \"\").replace(\")\", \"\")\n            d[\"prefix\"] = x\n            continue\n        if item.startswith(\"St\"):  # start page number specification\n            x = int(item[2:])\n            d[\"firstpagenum\"] = x\n    return d\n\n\ndef get_label_pno(pgNo, labels):\n    \"\"\"Return the label for this page number.\n\n    Args:\n        pgNo: page number, 0-based.\n        labels: result of doc._get_page_labels().\n    Returns:\n        The label (str) of the page number. Errors return an empty string.\n    \"\"\"\n    # Jorj McKie, 2021-01-06\n\n    item = [x for x in labels if x[0] <= pgNo][-1]\n    rule = rule_dict(item)\n    prefix = rule.get(\"prefix\", \"\")\n    style = rule.get(\"style\", \"\")\n    # make sure we start at 0 when enumerating the alphabet\n    delta = -1 if style in (\"a\", \"A\") else 0\n    pagenumber = pgNo - rule[\"startpage\"] + rule[\"firstpagenum\"] + delta\n    return construct_label(style, prefix, pagenumber)\n\n\ndef construct_label(style, prefix, pno) -> str:\n    \"\"\"Construct a label based on style, prefix and page number.\"\"\"\n    # William Chapman, 2021-01-06\n\n    n_str = \"\"\n    if style == \"D\":\n        n_str = str(pno)\n    elif style == \"r\":\n        n_str = integerToRoman(pno).lower()\n    elif style == \"R\":\n        n_str = integerToRoman(pno).upper()\n    elif style == \"a\":\n        n_str = integerToLetter(pno).lower()\n    elif style == \"A\":\n        n_str = integerToLetter(pno).upper()\n    result = prefix + n_str\n    return result\n\n\ndef integerToLetter(i) -> str:\n    \"\"\"Returns letter sequence string for integer i.\"\"\"\n    # William Chapman, Jorj McKie, 2021-01-06\n    import string\n    ls = string.ascii_uppercase\n    n, a = 1, i\n    while pow(26, n) <= a:\n        a -= int(math.pow(26, n))\n        n += 1\n\n    str_t = \"\"\n    for j in reversed(range(n)):\n        f, g = divmod(a, int(math.pow(26, j)))\n        str_t += ls[f]\n        a = g\n    return str_t\n\n\ndef integerToRoman(num: int) -> str:\n    \"\"\"Return roman numeral for an integer.\"\"\"\n    # William Chapman, Jorj McKie, 2021-01-06\n\n    roman = (\n        (1000, \"M\"),\n        (900, \"CM\"),\n        (500, \"D\"),\n        (400, \"CD\"),\n        (100, \"C\"),\n        (90, \"XC\"),\n        (50, \"L\"),\n        (40, \"XL\"),\n        (10, \"X\"),\n        (9, \"IX\"),\n        (5, \"V\"),\n        (4, \"IV\"),\n        (1, \"I\"),\n    )\n\n    def roman_num(num):\n        for r, ltr in roman:\n            x, _ = divmod(num, r)\n            yield ltr * x\n            num -= r * x\n            if num <= 0:\n                break\n\n    return \"\".join([a for a in roman_num(num)])\n\n\n# -------------------------------------------------------------------\n# Functions to recover the quad contained in a text extraction bbox\n# -------------------------------------------------------------------\ndef recover_bbox_quad(line_dir: tuple, span: dict, bbox: tuple) -> pymupdf.Quad:\n    \"\"\"Compute the quad located inside the bbox.\n\n    The bbox may be any of the resp. tuples occurring inside the given span.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the owning line or None.\n        span: (dict) the span. May be from get_texttrace() method.\n        bbox: (tuple) the bbox of the span or any of its characters.\n    Returns:\n        The quad which is wrapped by the bbox.\n    \"\"\"\n    if line_dir is None:\n        line_dir = span[\"dir\"]\n    cos, sin = line_dir\n    bbox = pymupdf.Rect(bbox)  # make it a rect\n    if pymupdf.TOOLS.set_small_glyph_heights():  # ==> just fontsize as height\n        d = 1\n    else:\n        d = span[\"ascender\"] - span[\"descender\"]\n\n    height = d * span[\"size\"]  # the quad's rectangle height\n    # The following are distances from the bbox corners, at which we find the\n    # respective quad points. The computation depends on in which quadrant the\n    # text writing angle is located.\n    hs = height * sin\n    hc = height * cos\n    if hc >= 0 and hs <= 0:  # quadrant 1\n        ul = bbox.bl - (0, hc)\n        ur = bbox.tr + (hs, 0)\n        ll = bbox.bl - (hs, 0)\n        lr = bbox.tr + (0, hc)\n    elif hc <= 0 and hs <= 0:  # quadrant 2\n        ul = bbox.br + (hs, 0)\n        ur = bbox.tl - (0, hc)\n        ll = bbox.br + (0, hc)\n        lr = bbox.tl - (hs, 0)\n    elif hc <= 0 and hs >= 0:  # quadrant 3\n        ul = bbox.tr - (0, hc)\n        ur = bbox.bl + (hs, 0)\n        ll = bbox.tr - (hs, 0)\n        lr = bbox.bl + (0, hc)\n    else:  # quadrant 4\n        ul = bbox.tl + (hs, 0)\n        ur = bbox.br - (0, hc)\n        ll = bbox.tl + (0, hc)\n        lr = bbox.br - (hs, 0)\n    return pymupdf.Quad(ul, ur, ll, lr)\n\n\ndef recover_quad(line_dir: tuple, span: dict) -> pymupdf.Quad:\n    \"\"\"Recover the quadrilateral of a text span.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the owning line.\n        span: the span.\n    Returns:\n        The quadrilateral enveloping the span's text.\n    \"\"\"\n    if type(line_dir) is not tuple or len(line_dir) != 2:\n        raise ValueError(\"bad line dir argument\")\n    if type(span) is not dict:\n        raise ValueError(\"bad span argument\")\n    return recover_bbox_quad(line_dir, span, span[\"bbox\"])\n\n\ndef recover_line_quad(line: dict, spans: list = None) -> pymupdf.Quad:\n    \"\"\"Calculate the line quad for 'dict' / 'rawdict' text extractions.\n\n    The lower quad points are those of the first, resp. last span quad.\n    The upper points are determined by the maximum span quad height.\n    From this, compute a rect with bottom-left in (0, 0), convert this to a\n    quad and rotate and shift back to cover the text of the spans.\n\n    Args:\n        spans: (list, optional) sub-list of spans to consider.\n    Returns:\n        pymupdf.Quad covering selected spans.\n    \"\"\"\n    if spans is None:  # no sub-selection\n        spans = line[\"spans\"]  # all spans\n    if len(spans) == 0:\n        raise ValueError(\"bad span list\")\n    line_dir = line[\"dir\"]  # text direction\n    cos, sin = line_dir\n    q0 = recover_quad(line_dir, spans[0])  # quad of first span\n    if len(spans) > 1:  # get quad of last span\n        q1 = recover_quad(line_dir, spans[-1])\n    else:\n        q1 = q0  # last = first\n\n    line_ll = q0.ll  # lower-left of line quad\n    line_lr = q1.lr  # lower-right of line quad\n\n    mat0 = pymupdf.planish_line(line_ll, line_lr)\n\n    # map base line to x-axis such that line_ll goes to (0, 0)\n    x_lr = line_lr * mat0\n\n    small = pymupdf.TOOLS.set_small_glyph_heights()  # small glyph heights?\n\n    h = max(\n        [s[\"size\"] * (1 if small else (s[\"ascender\"] - s[\"descender\"])) for s in spans]\n    )\n\n    line_rect = pymupdf.Rect(0, -h, x_lr.x, 0)  # line rectangle\n    line_quad = line_rect.quad  # make it a quad and:\n    line_quad *= ~mat0\n    return line_quad\n\n\ndef recover_span_quad(line_dir: tuple, span: dict, chars: list = None) -> pymupdf.Quad:\n    \"\"\"Calculate the span quad for 'dict' / 'rawdict' text extractions.\n\n    Notes:\n        There are two execution paths:\n        1. For the full span quad, the result of 'recover_quad' is returned.\n        2. For the quad of a sub-list of characters, the char quads are\n           computed and joined. This is only supported for the \"rawdict\"\n           extraction option.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the owning line.\n        span: (dict) the span.\n        chars: (list, optional) sub-list of characters to consider.\n    Returns:\n        pymupdf.Quad covering selected characters.\n    \"\"\"\n    if line_dir is None:  # must be a span from get_texttrace()\n        line_dir = span[\"dir\"]\n    if chars is None:  # no sub-selection\n        return recover_quad(line_dir, span)\n    if \"chars\" not in span.keys():\n        raise ValueError(\"need 'rawdict' option to sub-select chars\")\n\n    q0 = recover_char_quad(line_dir, span, chars[0])  # quad of first char\n    if len(chars) > 1:  # get quad of last char\n        q1 = recover_char_quad(line_dir, span, chars[-1])\n    else:\n        q1 = q0  # last = first\n\n    span_ll = q0.ll  # lower-left of span quad\n    span_lr = q1.lr  # lower-right of span quad\n    mat0 = pymupdf.planish_line(span_ll, span_lr)\n    # map base line to x-axis such that span_ll goes to (0, 0)\n    x_lr = span_lr * mat0\n\n    small = pymupdf.TOOLS.set_small_glyph_heights()  # small glyph heights?\n    h = span[\"size\"] * (1 if small else (span[\"ascender\"] - span[\"descender\"]))\n\n    span_rect = pymupdf.Rect(0, -h, x_lr.x, 0)  # line rectangle\n    span_quad = span_rect.quad  # make it a quad and:\n    span_quad *= ~mat0  # rotate back and shift back\n    return span_quad\n\n\ndef recover_char_quad(line_dir: tuple, span: dict, char: dict) -> pymupdf.Quad:\n    \"\"\"Recover the quadrilateral of a text character.\n\n    This requires the \"rawdict\" option of text extraction.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the span's line.\n        span: (dict) the span dict.\n        char: (dict) the character dict.\n    Returns:\n        The quadrilateral enveloping the character.\n    \"\"\"\n    if line_dir is None:\n        line_dir = span[\"dir\"]\n    if type(line_dir) is not tuple or len(line_dir) != 2:\n        raise ValueError(\"bad line dir argument\")\n    if type(span) is not dict:\n        raise ValueError(\"bad span argument\")\n    if type(char) is dict:\n        bbox = pymupdf.Rect(char[\"bbox\"])\n    elif type(char) is tuple:\n        bbox = pymupdf.Rect(char[3])\n    else:\n        raise ValueError(\"bad span argument\")\n\n    return recover_bbox_quad(line_dir, span, bbox)\n"
  },
  {
    "path": "src/wdev.py",
    "content": "'''\nFinds locations of Windows command-line development tools.\n'''\n\nimport os\nimport platform\nimport glob\nimport re\nimport subprocess\nimport sys\nimport sysconfig\nimport textwrap\n\nimport pipcl\n\n\nclass WindowsVS:\n    r'''\n    Windows only. Finds locations of Visual Studio command-line tools. Assumes\n    VS2019-style paths.\n\n    Members and example values::\n\n        .year:      2019\n        .grade:     Community\n        .version:   14.28.29910\n        .directory: C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\n        .vcvars:    C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Auxiliary\\Build\\vcvars64.bat\n        .cl:        C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\bin\\Hostx64\\x64\\cl.exe\n        .link:      C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\VC\\Tools\\MSVC\\14.28.29910\\bin\\Hostx64\\x64\\link.exe\n        .csc:       C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin\\Roslyn\\csc.exe\n        .msbuild:   C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\MSBuild\\Current\\Bin\\MSBuild.exe\n        .devenv:    C:\\Program Files (x86)\\Microsoft Visual Studio\\2019\\Community\\Common7\\IDE\\devenv.com\n\n    `.csc` is C# compiler; will be None if not found.\n    '''\n    def __init__(\n            self,\n            *,\n            year=None,\n            grade=None,\n            version=None,\n            cpu=None,\n            directory=None,\n            verbose=False,\n            ):\n        '''\n        Args:\n            year:\n                None or, for example, `2019`. If None we use environment\n                variable WDEV_VS_YEAR if set.\n            grade:\n                None or, for example, one of:\n\n                * `Community`\n                * `Professional`\n                * `Enterprise`\n\n                If None we use environment variable WDEV_VS_GRADE if set.\n            version:\n                None or, for example: `14.28.29910`. If None we use environment\n                variable WDEV_VS_VERSION if set.\n            cpu:\n                None or a `WindowsCpu` instance.\n            directory:\n                Ignore year, grade, version and cpu and use this directory\n                directly.\n            verbose:\n                .\n            \n        '''\n        if year is not None:\n            year = str(year)    # Allow specification as a number.\n        def default(value, name):\n            if value is None:\n                name2 = f'WDEV_VS_{name.upper()}'\n                value = os.environ.get(name2)\n                if value is not None:\n                    _log(f'Setting {name} from environment variable {name2}: {value!r}')\n            return value\n        try:\n            year = default(year, 'year')\n            grade = default(grade, 'grade')\n            version = default(version, 'version')\n\n            if not cpu:\n                cpu = WindowsCpu()\n\n            if not directory:\n                # Find `directory`.\n                #\n                pattern = _vs_pattern(year, grade)\n                directories = glob.glob( pattern)\n                if verbose:\n                    _log( f'Matches for: {pattern=}')\n                    _log( f'{directories=}')\n                assert directories, f'No match found for {pattern=}.'\n                directories.sort()\n                directory = directories[-1]\n\n            # Find `devenv`.\n            #\n            devenv = f'{directory}\\\\Common7\\\\IDE\\\\devenv.com'\n            assert os.path.isfile( devenv), f'Does not exist: {devenv}'\n\n            # Extract `year` and `grade` from `directory`.\n            #\n            # We use r'...' for regex strings because an extra level of escaping is\n            # required for backslashes.\n            #\n            regex = rf'^C:\\\\Program Files.*\\\\Microsoft Visual Studio\\\\([^\\\\]+)\\\\([^\\\\]+)'\n            m = re.match( regex, directory)\n            assert m, f'No match: {regex=} {directory=}'\n            year2 = m.group(1)\n            grade2 = m.group(2)\n            if year:\n                assert year2 == year\n            else:\n                year = year2\n            if grade:\n                assert grade2 == grade\n            else:\n                grade = grade2\n\n            # Find vcvars.bat.\n            #\n            vcvars = f'{directory}\\\\VC\\\\Auxiliary\\\\Build\\\\vcvars{cpu.bits}.bat'\n            assert os.path.isfile( vcvars), f'No match for: {vcvars}'\n\n            # Find cl.exe.\n            #\n            cl_pattern = f'{directory}\\\\VC\\\\Tools\\\\MSVC\\\\{version if version else \"*\"}\\\\bin\\\\Host{cpu.windows_name}\\\\{cpu.windows_name}\\\\cl.exe'\n            cl_s = glob.glob( cl_pattern)\n            assert cl_s, f'No match for: {cl_pattern}'\n            cl_s.sort()\n            cl = cl_s[ -1]\n\n            # Extract `version` from cl.exe's path.\n            #\n            m = re.search( rf'\\\\VC\\\\Tools\\\\MSVC\\\\([^\\\\]+)\\\\bin\\\\Host{cpu.windows_name}\\\\{cpu.windows_name}\\\\cl.exe$', cl)\n            assert m\n            version2 = m.group(1)\n            if version:\n                assert version2 == version\n            else:\n                version = version2\n            assert version\n\n            # Find link.exe.\n            #\n            link_pattern = f'{directory}\\\\VC\\\\Tools\\\\MSVC\\\\{version}\\\\bin\\\\Host{cpu.windows_name}\\\\{cpu.windows_name}\\\\link.exe'\n            link_s = glob.glob( link_pattern)\n            assert link_s, f'No match for: {link_pattern}'\n            link_s.sort()\n            link = link_s[ -1]\n\n            # Find csc.exe.\n            #\n            csc = None\n            for dirpath, dirnames, filenames in os.walk(directory):\n                for filename in filenames:\n                    if filename == 'csc.exe':\n                        csc = os.path.join(dirpath, filename)\n                        #_log(f'{csc=}')\n                        #break\n\n            # Find MSBuild.exe.\n            #\n            msbuild = None\n            for dirpath, dirnames, filenames in os.walk(directory):\n                for filename in filenames:\n                    if filename == 'MSBuild.exe':\n                        msbuild = os.path.join(dirpath, filename)\n                        #_log(f'{csc=}')\n                        #break\n\n            self.cl = cl\n            self.devenv = devenv\n            self.directory = directory\n            self.grade = grade\n            self.link = link\n            self.csc = csc\n            self.msbuild = msbuild\n            self.vcvars = vcvars\n            self.version = version\n            self.year = year\n            self.cpu = cpu\n        except Exception as e:\n            raise Exception( f'Unable to find Visual Studio {year=} {grade=} {version=} {cpu=} {directory=}') from e\n\n    def description_ml( self, indent=''):\n        '''\n        Return multiline description of `self`.\n        '''\n        ret = textwrap.dedent(f'''\n                year:         {self.year}\n                grade:        {self.grade}\n                version:      {self.version}\n                directory:    {self.directory}\n                vcvars:       {self.vcvars}\n                cl:           {self.cl}\n                link:         {self.link}\n                csc:          {self.csc}\n                msbuild:      {self.msbuild}\n                devenv:       {self.devenv}\n                cpu:          {self.cpu}\n                ''')\n        return textwrap.indent( ret, indent)\n\n    def __repr__( self):\n        items = list()\n        for name in (\n                'year',\n                'grade',\n                'version',\n                'directory',\n                'vcvars',\n                'cl',\n                'link',\n                'csc',\n                'msbuild',\n                'devenv',\n                'cpu',\n                ):\n            items.append(f'{name}={getattr(self, name)!r}')\n        return ' '.join(items)\n\n\ndef _vs_pattern(year=None, grade=None):\n    return f'C:\\\\Program Files*\\\\Microsoft Visual Studio\\\\{year if year else \"2*\"}\\\\{grade if grade else \"*\"}'\n\n\ndef windows_vs_multiple(year=None, grade=None, verbose=0):\n    '''\n    Returns list of WindowsVS instances.\n    '''\n    ret = list()\n    directories = glob.glob(_vs_pattern(year, grade))\n    for directory in directories:\n        vs = WindowsVS(directory=directory)\n        if verbose:\n            _log(vs.description_ml())\n        ret.append(vs)\n    return ret\n\n\nclass WindowsCpu:\n    '''\n    For Windows only. Paths and names that depend on cpu.\n\n    Members:\n        .bits\n            32 or 64.\n        .windows_subdir\n            Empty string or `x64/`.\n        .windows_name\n            `x86` or `x64`.\n        .windows_config\n            `x64` or `Win32`, e.g. for use in `/Build Release|x64`.\n        .windows_suffix\n            `64` or empty string.\n    '''\n    def __init__(self, name=None):\n        if not name:\n            name = _cpu_name()\n        self.name = name\n        if name == 'x32':\n            self.bits = 32\n            self.windows_subdir = ''\n            self.windows_name = 'x86'\n            self.windows_config = 'Win32'\n            self.windows_suffix = ''\n        elif name == 'x64':\n            self.bits = 64\n            self.windows_subdir = 'x64/'\n            self.windows_name = 'x64'\n            self.windows_config = 'x64'\n            self.windows_suffix = '64'\n        else:\n            assert 0, f'Unrecognised cpu name: {name}'\n\n    def __repr__(self):\n        return self.name\n\n\nclass WindowsPython:\n    '''\n    Windows only. Information about installed Python with specific word size\n    and version. Defaults to the currently-running Python.\n\n    Members:\n\n        .path:\n            Path of python binary.\n        .version:\n            `{major}.{minor}`, e.g. `3.9` or `3.11`. Same as `version` passed\n            to `__init__()` if not None, otherwise the inferred version.\n        .include:\n            Python include path.\n        .cpu:\n            A `WindowsCpu` instance, same as `cpu` passed to `__init__()` if\n            not None, otherwise the inferred cpu.\n\n    We parse the output from `py -0p` to find all available python\n    installations.\n    '''\n\n    def __init__( self, cpu=None, version=None, verbose=True):\n        '''\n        Args:\n\n            cpu:\n                A WindowsCpu instance. If None, we use whatever we are running\n                on.\n            version:\n                Two-digit Python version as a string such as `3.8`. If None we\n                use current Python's version.\n            verbose:\n                If true we show diagnostics.\n        '''\n        if cpu is None:\n            cpu = WindowsCpu(_cpu_name())\n        if version is None:\n            version = '.'.join(platform.python_version().split('.')[:2])\n        _log(f'Looking for Python {version=} {cpu.bits=}.')\n\n        if '.'.join(platform.python_version().split('.')[:2]) == version:\n            # Current python matches, so use it directly. This avoids problems\n            # on Github where experimental python-3.13 was not available via\n            # `py`, and is kept here in case a similar problems happens with\n            # future Python versions.\n            _log(f'{cpu=} {version=}: using {sys.executable=}.')\n            self.path = sys.executable\n            self.version = version\n            self.cpu = cpu\n            self.include = sysconfig.get_path('include')\n\n        else:\n            command = 'py -0p'\n            if verbose:\n                _log(f'{cpu=} {version=}: Running: {command}')\n            text = subprocess.check_output( command, shell=True, text=True)\n            for line in text.split('\\n'):\n                #_log( f'    {line}')\n                if m := re.match( '^ *-V:([0-9.]+)(-32)? ([*])? +(.+)$', line):\n                    version2 = m.group(1)\n                    bits = 32 if m.group(2) else 64\n                    current = m.group(3)\n                    path = m.group(4).strip()\n                elif m := re.match( '^ *-([0-9.]+)-((32)|(64)) +(.+)$', line):\n                    version2 = m.group(1)\n                    bits = int(m.group(2))\n                    path = m.group(5).strip()\n                else:\n                    if verbose:\n                        _log( f'No match for {line=}')\n                    continue\n                if verbose:\n                    _log( f'{version2=} {bits=} {path=} from {line=}.')\n                if bits != cpu.bits or version2 != version:\n                    continue\n                root = os.path.dirname(path)\n                if not os.path.exists(path):\n                    # Sometimes it seems that the specified .../python.exe does not exist,\n                    # and we have to change it to .../python<version>.exe.\n                    #\n                    assert path.endswith('.exe'), f'path={path!r}'\n                    path2 = f'{path[:-4]}{version}.exe'\n                    _log( f'Python {path!r} does not exist; changed to: {path2!r}')\n                    assert os.path.exists( path2)\n                    path = path2\n\n                self.path = path\n                self.version = version\n                self.cpu = cpu\n                command = f'{self.path} -c \"import sysconfig; print(sysconfig.get_path(\\'include\\'))\"'\n                _log(f'Finding Python include path by running {command=}.')\n                self.include = subprocess.check_output(command, shell=True, text=True).strip()\n                _log(f'Python include path is {self.include=}.')\n                #_log( f'pipcl.py:WindowsPython():\\n{self.description_ml(\"    \")}')\n                break\n            else:\n                _log(f'Failed to find python matching cpu={cpu}.')\n                _log(f'Output from {command!r} was:\\n{text}')\n                raise Exception( f'Failed to find python matching cpu={cpu} {version=}.')\n\n        # Oddly there doesn't seem to be a\n        # `sysconfig.get_path('libs')`, but it seems to be next\n        # to `includes`:\n        self.libs = os.path.abspath(f'{self.include}/../libs')\n\n        _log( f'WindowsPython:\\n{self.description_ml(\"    \")}')\n\n    def description_ml(self, indent=''):\n        ret = textwrap.dedent(f'''\n                path:       {self.path}\n                version:    {self.version}\n                cpu:        {self.cpu}\n                include:    {self.include}\n                libs:       {self.libs}\n                ''')\n        return textwrap.indent( ret, indent)\n\n    def __repr__(self):\n        return f'path={self.path!r} version={self.version!r} cpu={self.cpu!r} include={self.include!r} libs={self.libs!r}'\n\n\n# Internal helpers.\n#\n\ndef _cpu_name():\n    '''\n    Returns `x32` or `x64` depending on Python build.\n    '''\n    #log(f'sys.maxsize={hex(sys.maxsize)}')\n    return f'x{32 if sys.maxsize == 2**31 - 1 else 64}'\n\n\n\ndef _log(text='', caller=1):\n    '''\n    Logs lines with prefix.\n    '''\n    pipcl.log1(text, caller+1)\n"
  },
  {
    "path": "src_classic/__init__.py",
    "content": "# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\nimport sys\n\nimport glob\nimport os\nif os.path.exists( 'fitz/__init__.py'):\n    if not glob.glob( 'fitz/_fitz*'):\n        print( '#' * 40)\n        print( '# Warning: current directory appears to contain an incomplete')\n        print( '# fitz/ installation directory so \"import fitz\" may fail.')\n        print( '# This can happen if current directory is a PyMuPDF source tree.')\n        print( '# Suggest changing to a different current directory.')\n        print( '#' * 40)\n\ndef message(text=''):\n    print(text)\n\nfrom fitz_old.fitz_old import *\n\n# Allow this to work:\n#   import fitz_old as fitz\n#   fitz.fitz.TEXT_ALIGN_CENTER\n#\nfitz = fitz_old\n\n# define the supported colorspaces for convenience\nfitz_old.csRGB = fitz_old.Colorspace(fitz_old.CS_RGB)\nfitz_old.csGRAY = fitz_old.Colorspace(fitz_old.CS_GRAY)\nfitz_old.csCMYK = fitz_old.Colorspace(fitz_old.CS_CMYK)\ncsRGB = fitz_old.csRGB\ncsGRAY = fitz_old.csGRAY\ncsCMYK = fitz_old.csCMYK\n\n# create the TOOLS object.\n#\n# Unfortunately it seems that this is never be destructed even if we use an\n# atexit() handler, which makes MuPDF's Memento list it as a leak. In fitz_old.i\n# we use Memento_startLeaking()/Memento_stopLeaking() when allocating\n# the Tools instance so at least the leak is marked as known.\n#\nTOOLS = fitz_old.Tools()\nTOOLS.thisown = True\nfitz_old.TOOLS = TOOLS\n\n# This atexit handler runs, but doesn't cause ~Tools() to be run.\n#\nimport atexit\n\n\ndef cleanup_tools(TOOLS):\n    # print(f'cleanup_tools: TOOLS={TOOLS} id(TOOLS)={id(TOOLS)}')\n    # print(f'TOOLS.thisown={TOOLS.thisown}')\n    del TOOLS\n    del fitz_old.TOOLS\n\n\natexit.register(cleanup_tools, TOOLS)\n\n\n# Require that MuPDF matches fitz_old.TOOLS.mupdf_version(); also allow use with\n# next minor version (e.g. 1.21.2 => 1.22), so we can test with mupdf master.\n#\ndef v_str_to_tuple(s):\n    return tuple(map(int, s.split('.')))\n\ndef v_tuple_to_string(t):\n    return '.'.join(map(str, t))\n\nmupdf_version_tuple = v_str_to_tuple(fitz_old.TOOLS.mupdf_version())\nmupdf_version_tuple_required = v_str_to_tuple(fitz_old.VersionFitz)\nmupdf_version_tuple_required_prev = (mupdf_version_tuple_required[0], mupdf_version_tuple_required[1]-1)\nmupdf_version_tuple_required_next = (mupdf_version_tuple_required[0], mupdf_version_tuple_required[1]+1)\n\n# copy functions in 'utils' to their respective fitz classes\nimport fitz_old.utils\nfrom .table import find_tables\n\n# ------------------------------------------------------------------------------\n# General\n# ------------------------------------------------------------------------------\nfitz_old.recover_quad = fitz_old.utils.recover_quad\nfitz_old.recover_bbox_quad = fitz_old.utils.recover_bbox_quad\nfitz_old.recover_line_quad = fitz_old.utils.recover_line_quad\nfitz_old.recover_span_quad = fitz_old.utils.recover_span_quad\nfitz_old.recover_char_quad = fitz_old.utils.recover_char_quad\n\n# ------------------------------------------------------------------------------\n# Document\n# ------------------------------------------------------------------------------\nfitz_old.open = fitz_old.Document\nfitz_old.Document._do_links = fitz_old.utils.do_links\nfitz_old.Document.del_toc_item = fitz_old.utils.del_toc_item\nfitz_old.Document.get_char_widths = fitz_old.utils.get_char_widths\nfitz_old.Document.get_ocmd = fitz_old.utils.get_ocmd\nfitz_old.Document.get_page_labels = fitz_old.utils.get_page_labels\nfitz_old.Document.get_page_numbers = fitz_old.utils.get_page_numbers\nfitz_old.Document.get_page_pixmap = fitz_old.utils.get_page_pixmap\nfitz_old.Document.get_page_text = fitz_old.utils.get_page_text\nfitz_old.Document.get_toc = fitz_old.utils.get_toc\nfitz_old.Document.has_annots = fitz_old.utils.has_annots\nfitz_old.Document.has_links = fitz_old.utils.has_links\nfitz_old.Document.insert_page = fitz_old.utils.insert_page\nfitz_old.Document.new_page = fitz_old.utils.new_page\nfitz_old.Document.scrub = fitz_old.utils.scrub\nfitz_old.Document.search_page_for = fitz_old.utils.search_page_for\nfitz_old.Document.set_metadata = fitz_old.utils.set_metadata\nfitz_old.Document.set_ocmd = fitz_old.utils.set_ocmd\nfitz_old.Document.set_page_labels = fitz_old.utils.set_page_labels\nfitz_old.Document.set_toc = fitz_old.utils.set_toc\nfitz_old.Document.set_toc_item = fitz_old.utils.set_toc_item\nfitz_old.Document.tobytes = fitz_old.Document.write\nfitz_old.Document.subset_fonts = fitz_old.utils.subset_fonts\nfitz_old.Document.get_oc = fitz_old.utils.get_oc\nfitz_old.Document.set_oc = fitz_old.utils.set_oc\nfitz_old.Document.xref_copy = fitz_old.utils.xref_copy\n\n\n# ------------------------------------------------------------------------------\n# Page\n# ------------------------------------------------------------------------------\nfitz_old.Page.apply_redactions = fitz_old.utils.apply_redactions\nfitz_old.Page.delete_widget = fitz_old.utils.delete_widget\nfitz_old.Page.draw_bezier = fitz_old.utils.draw_bezier\nfitz_old.Page.draw_circle = fitz_old.utils.draw_circle\nfitz_old.Page.draw_curve = fitz_old.utils.draw_curve\nfitz_old.Page.draw_line = fitz_old.utils.draw_line\nfitz_old.Page.draw_oval = fitz_old.utils.draw_oval\nfitz_old.Page.draw_polyline = fitz_old.utils.draw_polyline\nfitz_old.Page.draw_quad = fitz_old.utils.draw_quad\nfitz_old.Page.draw_rect = fitz_old.utils.draw_rect\nfitz_old.Page.draw_sector = fitz_old.utils.draw_sector\nfitz_old.Page.draw_squiggle = fitz_old.utils.draw_squiggle\nfitz_old.Page.draw_zigzag = fitz_old.utils.draw_zigzag\nfitz_old.Page.get_links = fitz_old.utils.get_links\nfitz_old.Page.get_pixmap = fitz_old.utils.get_pixmap\nfitz_old.Page.get_text = fitz_old.utils.get_text\nfitz_old.Page.get_image_info = fitz_old.utils.get_image_info\nfitz_old.Page.get_text_blocks = fitz_old.utils.get_text_blocks\nfitz_old.Page.get_text_selection = fitz_old.utils.get_text_selection\nfitz_old.Page.get_text_words = fitz_old.utils.get_text_words\nfitz_old.Page.get_textbox = fitz_old.utils.get_textbox\nfitz_old.Page.insert_image = fitz_old.utils.insert_image\nfitz_old.Page.insert_link = fitz_old.utils.insert_link\nfitz_old.Page.insert_text = fitz_old.utils.insert_text\nfitz_old.Page.insert_textbox = fitz_old.utils.insert_textbox\nfitz_old.Page.new_shape = lambda x: fitz_old.utils.Shape(x)\nfitz_old.Page.search_for = fitz_old.utils.search_for\nfitz_old.Page.show_pdf_page = fitz_old.utils.show_pdf_page\nfitz_old.Page.update_link = fitz_old.utils.update_link\nfitz_old.Page.write_text = fitz_old.utils.write_text\nfitz_old.Page.get_label = fitz_old.utils.get_label\nfitz_old.Page.get_image_rects = fitz_old.utils.get_image_rects\nfitz_old.Page.get_textpage_ocr = fitz_old.utils.get_textpage_ocr\nfitz_old.Page.delete_image = fitz_old.utils.delete_image\nfitz_old.Page.replace_image = fitz_old.utils.replace_image\nfitz_old.Page.find_tables = find_tables\n# ------------------------------------------------------------------------\n# Annot\n# ------------------------------------------------------------------------\nfitz_old.Annot.get_text = fitz_old.utils.get_text\nfitz_old.Annot.get_textbox = fitz_old.utils.get_textbox\n\n# ------------------------------------------------------------------------\n# Rect and IRect\n# ------------------------------------------------------------------------\nfitz_old.Rect.get_area = fitz_old.utils.get_area\nfitz_old.IRect.get_area = fitz_old.utils.get_area\n\n# ------------------------------------------------------------------------\n# TextWriter\n# ------------------------------------------------------------------------\nfitz_old.TextWriter.fill_textbox = fitz_old.utils.fill_textbox\n\n\nclass FitzDeprecation(DeprecationWarning):\n    pass\n\n\ndef restore_aliases():\n    import warnings\n\n    warnings.filterwarnings(\n        \"once\",\n        category=FitzDeprecation,\n    )\n\n    def showthis(msg, cat, filename, lineno, file=None, line=None):\n        text = warnings.formatwarning(msg, cat, filename, lineno, line=line)\n        s = text.find(\"FitzDeprecation\")\n        if s < 0:\n            print(text, file=sys.stderr)\n            return\n        text = text[s:].splitlines()[0][4:]\n        print(text, file=sys.stderr)\n\n    warnings.showwarning = showthis\n\n    def _alias(fitz_class, old, new):\n        fname = getattr(fitz_class, new)\n        r = str(fitz_class)[1:-1]\n        objname = \" \".join(r.split()[:2])\n        objname = objname.replace(\"fitz_old.fitz_old.\", \"\")\n        objname = objname.replace(\"fitz_old.utils.\", \"\")\n        if callable(fname):\n\n            def deprecated_function(*args, **kw):\n                msg = \"'%s' removed from %s after v1.19 - use '%s'.\" % (\n                    old,\n                    objname,\n                    new,\n                )\n                if not VersionBind.startswith(\"1.18\"):\n                    warnings.warn(msg, category=FitzDeprecation)\n                return fname(*args, **kw)\n\n            setattr(fitz_class, old, deprecated_function)\n        else:\n            if type(fname) is property:\n                setattr(fitz_class, old, property(fname.fget))\n            else:\n                setattr(fitz_class, old, fname)\n\n        eigen = getattr(fitz_class, old)\n        x = fname.__doc__\n        if not x:\n            x = \"\"\n        try:\n            if callable(fname) or type(fname) is property:\n                eigen.__doc__ = (\n                    \"*** Deprecated and removed after v1.19 - use '%s'. ***\\n\" % new + x\n                )\n        except:\n            pass\n\n    # deprecated Document aliases\n    _alias(fitz_old.Document, \"chapterCount\", \"chapter_count\")\n    _alias(fitz_old.Document, \"chapterPageCount\", \"chapter_page_count\")\n    _alias(fitz_old.Document, \"convertToPDF\", \"convert_to_pdf\")\n    _alias(fitz_old.Document, \"copyPage\", \"copy_page\")\n    _alias(fitz_old.Document, \"deletePage\", \"delete_page\")\n    _alias(fitz_old.Document, \"deletePageRange\", \"delete_pages\")\n    _alias(fitz_old.Document, \"embeddedFileAdd\", \"embfile_add\")\n    _alias(fitz_old.Document, \"embeddedFileCount\", \"embfile_count\")\n    _alias(fitz_old.Document, \"embeddedFileDel\", \"embfile_del\")\n    _alias(fitz_old.Document, \"embeddedFileGet\", \"embfile_get\")\n    _alias(fitz_old.Document, \"embeddedFileInfo\", \"embfile_info\")\n    _alias(fitz_old.Document, \"embeddedFileNames\", \"embfile_names\")\n    _alias(fitz_old.Document, \"embeddedFileUpd\", \"embfile_upd\")\n    _alias(fitz_old.Document, \"extractFont\", \"extract_font\")\n    _alias(fitz_old.Document, \"extractImage\", \"extract_image\")\n    _alias(fitz_old.Document, \"findBookmark\", \"find_bookmark\")\n    _alias(fitz_old.Document, \"fullcopyPage\", \"fullcopy_page\")\n    _alias(fitz_old.Document, \"getCharWidths\", \"get_char_widths\")\n    _alias(fitz_old.Document, \"getOCGs\", \"get_ocgs\")\n    _alias(fitz_old.Document, \"getPageFontList\", \"get_page_fonts\")\n    _alias(fitz_old.Document, \"getPageImageList\", \"get_page_images\")\n    _alias(fitz_old.Document, \"getPagePixmap\", \"get_page_pixmap\")\n    _alias(fitz_old.Document, \"getPageText\", \"get_page_text\")\n    _alias(fitz_old.Document, \"getPageXObjectList\", \"get_page_xobjects\")\n    _alias(fitz_old.Document, \"getSigFlags\", \"get_sigflags\")\n    _alias(fitz_old.Document, \"getToC\", \"get_toc\")\n    _alias(fitz_old.Document, \"getXmlMetadata\", \"get_xml_metadata\")\n    _alias(fitz_old.Document, \"insertPage\", \"insert_page\")\n    _alias(fitz_old.Document, \"insertPDF\", \"insert_pdf\")\n    _alias(fitz_old.Document, \"isDirty\", \"is_dirty\")\n    _alias(fitz_old.Document, \"isFormPDF\", \"is_form_pdf\")\n    _alias(fitz_old.Document, \"isPDF\", \"is_pdf\")\n    _alias(fitz_old.Document, \"isReflowable\", \"is_reflowable\")\n    _alias(fitz_old.Document, \"isRepaired\", \"is_repaired\")\n    _alias(fitz_old.Document, \"isStream\", \"xref_is_stream\")\n    _alias(fitz_old.Document, \"is_stream\", \"xref_is_stream\")\n    _alias(fitz_old.Document, \"lastLocation\", \"last_location\")\n    _alias(fitz_old.Document, \"loadPage\", \"load_page\")\n    _alias(fitz_old.Document, \"makeBookmark\", \"make_bookmark\")\n    _alias(fitz_old.Document, \"metadataXML\", \"xref_xml_metadata\")\n    _alias(fitz_old.Document, \"movePage\", \"move_page\")\n    _alias(fitz_old.Document, \"needsPass\", \"needs_pass\")\n    _alias(fitz_old.Document, \"newPage\", \"new_page\")\n    _alias(fitz_old.Document, \"nextLocation\", \"next_location\")\n    _alias(fitz_old.Document, \"pageCount\", \"page_count\")\n    _alias(fitz_old.Document, \"pageCropBox\", \"page_cropbox\")\n    _alias(fitz_old.Document, \"pageXref\", \"page_xref\")\n    _alias(fitz_old.Document, \"PDFCatalog\", \"pdf_catalog\")\n    _alias(fitz_old.Document, \"PDFTrailer\", \"pdf_trailer\")\n    _alias(fitz_old.Document, \"previousLocation\", \"prev_location\")\n    _alias(fitz_old.Document, \"resolveLink\", \"resolve_link\")\n    _alias(fitz_old.Document, \"searchPageFor\", \"search_page_for\")\n    _alias(fitz_old.Document, \"setLanguage\", \"set_language\")\n    _alias(fitz_old.Document, \"setMetadata\", \"set_metadata\")\n    _alias(fitz_old.Document, \"setToC\", \"set_toc\")\n    _alias(fitz_old.Document, \"setXmlMetadata\", \"set_xml_metadata\")\n    _alias(fitz_old.Document, \"updateObject\", \"update_object\")\n    _alias(fitz_old.Document, \"updateStream\", \"update_stream\")\n    _alias(fitz_old.Document, \"xrefLength\", \"xref_length\")\n    _alias(fitz_old.Document, \"xrefObject\", \"xref_object\")\n    _alias(fitz_old.Document, \"xrefStream\", \"xref_stream\")\n    _alias(fitz_old.Document, \"xrefStreamRaw\", \"xref_stream_raw\")\n\n    # deprecated Page aliases\n    _alias(fitz_old.Page, \"_isWrapped\", \"is_wrapped\")\n    _alias(fitz_old.Page, \"addCaretAnnot\", \"add_caret_annot\")\n    _alias(fitz_old.Page, \"addCircleAnnot\", \"add_circle_annot\")\n    _alias(fitz_old.Page, \"addFileAnnot\", \"add_file_annot\")\n    _alias(fitz_old.Page, \"addFreetextAnnot\", \"add_freetext_annot\")\n    _alias(fitz_old.Page, \"addHighlightAnnot\", \"add_highlight_annot\")\n    _alias(fitz_old.Page, \"addInkAnnot\", \"add_ink_annot\")\n    _alias(fitz_old.Page, \"addLineAnnot\", \"add_line_annot\")\n    _alias(fitz_old.Page, \"addPolygonAnnot\", \"add_polygon_annot\")\n    _alias(fitz_old.Page, \"addPolylineAnnot\", \"add_polyline_annot\")\n    _alias(fitz_old.Page, \"addRectAnnot\", \"add_rect_annot\")\n    _alias(fitz_old.Page, \"addRedactAnnot\", \"add_redact_annot\")\n    _alias(fitz_old.Page, \"addSquigglyAnnot\", \"add_squiggly_annot\")\n    _alias(fitz_old.Page, \"addStampAnnot\", \"add_stamp_annot\")\n    _alias(fitz_old.Page, \"addStrikeoutAnnot\", \"add_strikeout_annot\")\n    _alias(fitz_old.Page, \"addTextAnnot\", \"add_text_annot\")\n    _alias(fitz_old.Page, \"addUnderlineAnnot\", \"add_underline_annot\")\n    _alias(fitz_old.Page, \"addWidget\", \"add_widget\")\n    _alias(fitz_old.Page, \"cleanContents\", \"clean_contents\")\n    _alias(fitz_old.Page, \"CropBox\", \"cropbox\")\n    _alias(fitz_old.Page, \"CropBoxPosition\", \"cropbox_position\")\n    _alias(fitz_old.Page, \"deleteAnnot\", \"delete_annot\")\n    _alias(fitz_old.Page, \"deleteLink\", \"delete_link\")\n    _alias(fitz_old.Page, \"deleteWidget\", \"delete_widget\")\n    _alias(fitz_old.Page, \"derotationMatrix\", \"derotation_matrix\")\n    _alias(fitz_old.Page, \"drawBezier\", \"draw_bezier\")\n    _alias(fitz_old.Page, \"drawCircle\", \"draw_circle\")\n    _alias(fitz_old.Page, \"drawCurve\", \"draw_curve\")\n    _alias(fitz_old.Page, \"drawLine\", \"draw_line\")\n    _alias(fitz_old.Page, \"drawOval\", \"draw_oval\")\n    _alias(fitz_old.Page, \"drawPolyline\", \"draw_polyline\")\n    _alias(fitz_old.Page, \"drawQuad\", \"draw_quad\")\n    _alias(fitz_old.Page, \"drawRect\", \"draw_rect\")\n    _alias(fitz_old.Page, \"drawSector\", \"draw_sector\")\n    _alias(fitz_old.Page, \"drawSquiggle\", \"draw_squiggle\")\n    _alias(fitz_old.Page, \"drawZigzag\", \"draw_zigzag\")\n    _alias(fitz_old.Page, \"firstAnnot\", \"first_annot\")\n    _alias(fitz_old.Page, \"firstLink\", \"first_link\")\n    _alias(fitz_old.Page, \"firstWidget\", \"first_widget\")\n    _alias(fitz_old.Page, \"getContents\", \"get_contents\")\n    _alias(fitz_old.Page, \"getDisplayList\", \"get_displaylist\")\n    _alias(fitz_old.Page, \"getDrawings\", \"get_drawings\")\n    _alias(fitz_old.Page, \"getFontList\", \"get_fonts\")\n    _alias(fitz_old.Page, \"getImageBbox\", \"get_image_bbox\")\n    _alias(fitz_old.Page, \"getImageList\", \"get_images\")\n    _alias(fitz_old.Page, \"getLinks\", \"get_links\")\n    _alias(fitz_old.Page, \"getPixmap\", \"get_pixmap\")\n    _alias(fitz_old.Page, \"getSVGimage\", \"get_svg_image\")\n    _alias(fitz_old.Page, \"getText\", \"get_text\")\n    _alias(fitz_old.Page, \"getTextBlocks\", \"get_text_blocks\")\n    _alias(fitz_old.Page, \"getTextbox\", \"get_textbox\")\n    _alias(fitz_old.Page, \"getTextPage\", \"get_textpage\")\n    _alias(fitz_old.Page, \"getTextWords\", \"get_text_words\")\n    _alias(fitz_old.Page, \"insertFont\", \"insert_font\")\n    _alias(fitz_old.Page, \"insertImage\", \"insert_image\")\n    _alias(fitz_old.Page, \"insertLink\", \"insert_link\")\n    _alias(fitz_old.Page, \"insertText\", \"insert_text\")\n    _alias(fitz_old.Page, \"insertTextbox\", \"insert_textbox\")\n    _alias(fitz_old.Page, \"loadAnnot\", \"load_annot\")\n    _alias(fitz_old.Page, \"loadLinks\", \"load_links\")\n    _alias(fitz_old.Page, \"MediaBox\", \"mediabox\")\n    _alias(fitz_old.Page, \"MediaBoxSize\", \"mediabox_size\")\n    _alias(fitz_old.Page, \"newShape\", \"new_shape\")\n    _alias(fitz_old.Page, \"readContents\", \"read_contents\")\n    _alias(fitz_old.Page, \"rotationMatrix\", \"rotation_matrix\")\n    _alias(fitz_old.Page, \"searchFor\", \"search_for\")\n    _alias(fitz_old.Page, \"setCropBox\", \"set_cropbox\")\n    _alias(fitz_old.Page, \"setMediaBox\", \"set_mediabox\")\n    _alias(fitz_old.Page, \"setRotation\", \"set_rotation\")\n    _alias(fitz_old.Page, \"showPDFpage\", \"show_pdf_page\")\n    _alias(fitz_old.Page, \"transformationMatrix\", \"transformation_matrix\")\n    _alias(fitz_old.Page, \"updateLink\", \"update_link\")\n    _alias(fitz_old.Page, \"wrapContents\", \"wrap_contents\")\n    _alias(fitz_old.Page, \"writeText\", \"write_text\")\n\n    # deprecated Shape aliases\n    _alias(fitz_old.utils.Shape, \"drawBezier\", \"draw_bezier\")\n    _alias(fitz_old.utils.Shape, \"drawCircle\", \"draw_circle\")\n    _alias(fitz_old.utils.Shape, \"drawCurve\", \"draw_curve\")\n    _alias(fitz_old.utils.Shape, \"drawLine\", \"draw_line\")\n    _alias(fitz_old.utils.Shape, \"drawOval\", \"draw_oval\")\n    _alias(fitz_old.utils.Shape, \"drawPolyline\", \"draw_polyline\")\n    _alias(fitz_old.utils.Shape, \"drawQuad\", \"draw_quad\")\n    _alias(fitz_old.utils.Shape, \"drawRect\", \"draw_rect\")\n    _alias(fitz_old.utils.Shape, \"drawSector\", \"draw_sector\")\n    _alias(fitz_old.utils.Shape, \"drawSquiggle\", \"draw_squiggle\")\n    _alias(fitz_old.utils.Shape, \"drawZigzag\", \"draw_zigzag\")\n    _alias(fitz_old.utils.Shape, \"insertText\", \"insert_text\")\n    _alias(fitz_old.utils.Shape, \"insertTextbox\", \"insert_textbox\")\n\n    # deprecated Annot aliases\n    _alias(fitz_old.Annot, \"getText\", \"get_text\")\n    _alias(fitz_old.Annot, \"getTextbox\", \"get_textbox\")\n    _alias(fitz_old.Annot, \"fileGet\", \"get_file\")\n    _alias(fitz_old.Annot, \"fileUpd\", \"update_file\")\n    _alias(fitz_old.Annot, \"getPixmap\", \"get_pixmap\")\n    _alias(fitz_old.Annot, \"getTextPage\", \"get_textpage\")\n    _alias(fitz_old.Annot, \"lineEnds\", \"line_ends\")\n    _alias(fitz_old.Annot, \"setBlendMode\", \"set_blendmode\")\n    _alias(fitz_old.Annot, \"setBorder\", \"set_border\")\n    _alias(fitz_old.Annot, \"setColors\", \"set_colors\")\n    _alias(fitz_old.Annot, \"setFlags\", \"set_flags\")\n    _alias(fitz_old.Annot, \"setInfo\", \"set_info\")\n    _alias(fitz_old.Annot, \"setLineEnds\", \"set_line_ends\")\n    _alias(fitz_old.Annot, \"setName\", \"set_name\")\n    _alias(fitz_old.Annot, \"setOpacity\", \"set_opacity\")\n    _alias(fitz_old.Annot, \"setRect\", \"set_rect\")\n    _alias(fitz_old.Annot, \"setOC\", \"set_oc\")\n    _alias(fitz_old.Annot, \"soundGet\", \"get_sound\")\n\n    # deprecated TextWriter aliases\n    _alias(fitz_old.TextWriter, \"writeText\", \"write_text\")\n    _alias(fitz_old.TextWriter, \"fillTextbox\", \"fill_textbox\")\n\n    # deprecated DisplayList aliases\n    _alias(fitz_old.DisplayList, \"getPixmap\", \"get_pixmap\")\n    _alias(fitz_old.DisplayList, \"getTextPage\", \"get_textpage\")\n\n    # deprecated Pixmap aliases\n    _alias(fitz_old.Pixmap, \"setAlpha\", \"set_alpha\")\n    _alias(fitz_old.Pixmap, \"gammaWith\", \"gamma_with\")\n    _alias(fitz_old.Pixmap, \"tintWith\", \"tint_with\")\n    _alias(fitz_old.Pixmap, \"clearWith\", \"clear_with\")\n    _alias(fitz_old.Pixmap, \"copyPixmap\", \"copy\")\n    _alias(fitz_old.Pixmap, \"getImageData\", \"tobytes\")\n    _alias(fitz_old.Pixmap, \"getPNGData\", \"tobytes\")\n    _alias(fitz_old.Pixmap, \"getPNGdata\", \"tobytes\")\n    _alias(fitz_old.Pixmap, \"writeImage\", \"save\")\n    _alias(fitz_old.Pixmap, \"writePNG\", \"save\")\n    _alias(fitz_old.Pixmap, \"pillowWrite\", \"pil_save\")\n    _alias(fitz_old.Pixmap, \"pillowData\", \"pil_tobytes\")\n    _alias(fitz_old.Pixmap, \"invertIRect\", \"invert_irect\")\n    _alias(fitz_old.Pixmap, \"setPixel\", \"set_pixel\")\n    _alias(fitz_old.Pixmap, \"setOrigin\", \"set_origin\")\n    _alias(fitz_old.Pixmap, \"setRect\", \"set_rect\")\n    _alias(fitz_old.Pixmap, \"setResolution\", \"set_dpi\")\n\n    # deprecated geometry aliases\n    _alias(fitz_old.Rect, \"getArea\", \"get_area\")\n    _alias(fitz_old.IRect, \"getArea\", \"get_area\")\n    _alias(fitz_old.Rect, \"getRectArea\", \"get_area\")\n    _alias(fitz_old.IRect, \"getRectArea\", \"get_area\")\n    _alias(fitz_old.Rect, \"includePoint\", \"include_point\")\n    _alias(fitz_old.IRect, \"includePoint\", \"include_point\")\n    _alias(fitz_old.Rect, \"includeRect\", \"include_rect\")\n    _alias(fitz_old.IRect, \"includeRect\", \"include_rect\")\n    _alias(fitz_old.Rect, \"isInfinite\", \"is_infinite\")\n    _alias(fitz_old.IRect, \"isInfinite\", \"is_infinite\")\n    _alias(fitz_old.Rect, \"isEmpty\", \"is_empty\")\n    _alias(fitz_old.IRect, \"isEmpty\", \"is_empty\")\n    _alias(fitz_old.Quad, \"isEmpty\", \"is_empty\")\n    _alias(fitz_old.Quad, \"isRectangular\", \"is_rectangular\")\n    _alias(fitz_old.Quad, \"isConvex\", \"is_convex\")\n    _alias(fitz_old.Matrix, \"isRectilinear\", \"is_rectilinear\")\n    _alias(fitz_old.Matrix, \"preRotate\", \"prerotate\")\n    _alias(fitz_old.Matrix, \"preScale\", \"prescale\")\n    _alias(fitz_old.Matrix, \"preShear\", \"preshear\")\n    _alias(fitz_old.Matrix, \"preTranslate\", \"pretranslate\")\n\n    # deprecated other aliases\n    _alias(fitz_old.Outline, \"isExternal\", \"is_external\")\n    _alias(fitz_old.Outline, \"isOpen\", \"is_open\")\n    _alias(fitz_old.Link, \"isExternal\", \"is_external\")\n    _alias(fitz_old.Link, \"setBorder\", \"set_border\")\n    _alias(fitz_old.Link, \"setColors\", \"set_colors\")\n    _alias(fitz, \"getPDFstr\", \"get_pdf_str\")\n    _alias(fitz, \"getPDFnow\", \"get_pdf_now\")\n    _alias(fitz, \"PaperSize\", \"paper_size\")\n    _alias(fitz, \"PaperRect\", \"paper_rect\")\n    _alias(fitz, \"paperSizes\", \"paper_sizes\")\n    _alias(fitz, \"ImageProperties\", \"image_profile\")\n    _alias(fitz, \"planishLine\", \"planish_line\")\n    _alias(fitz, \"getTextLength\", \"get_text_length\")\n    _alias(fitz, \"getTextlength\", \"get_text_length\")\n\n\nfitz_old.__doc__ = \"\"\"\nPyMuPDF %s: Python bindings for the MuPDF %s library.\nVersion date: %s.\nBuilt for Python %i.%i on %s (%i-bit).\n\"\"\" % (\n    fitz_old.VersionBind,\n    fitz_old.VersionFitz,\n    fitz_old.VersionDate,\n    sys.version_info[0],\n    sys.version_info[1],\n    sys.platform,\n    64 if sys.maxsize > 2**32 else 32,\n)\n\nif VersionBind.startswith(\"1.19\"):  # don't generate aliases after v1.19.*\n    restore_aliases()\n\npdfcolor = dict(\n    [\n        (k, (r / 255, g / 255, b / 255))\n        for k, (r, g, b) in fitz_old.utils.getColorInfoDict().items()\n    ]\n)\n__version__ = fitz_old.VersionBind\n"
  },
  {
    "path": "src_classic/__main__.py",
    "content": "# -----------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n# Part of \"PyMuPDF\", Python bindings for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# -----------------------------------------------------------------------------\nimport argparse\nimport bisect\nimport os\nimport sys\nimport statistics\nfrom typing import Dict, List, Set, Tuple\n\nimport fitz\nfrom fitz.fitz import (\n    TEXT_INHIBIT_SPACES,\n    TEXT_PRESERVE_LIGATURES,\n    TEXT_PRESERVE_WHITESPACE,\n)\n\nmycenter = lambda x: (\" %s \" % x).center(75, \"-\")\n\n\ndef recoverpix(doc, item):\n    \"\"\"Return image for a given XREF.\"\"\"\n    x = item[0]  # xref of PDF image\n    s = item[1]  # xref of its /SMask\n    if s == 0:  # no smask: use direct image output\n        return doc.extract_image(x)\n\n    def getimage(pix):\n        if pix.colorspace.n != 4:\n            return pix\n        tpix = fitz.Pixmap(fitz.csRGB, pix)\n        return tpix\n\n    # we need to reconstruct the alpha channel with the smask\n    pix1 = fitz.Pixmap(doc, x)\n    pix2 = fitz.Pixmap(doc, s)  # create pixmap of the /SMask entry\n\n    \"\"\"Sanity check:\n    - both pixmaps must have the same rectangle\n    - both pixmaps must have alpha=0\n    - pix2 must consist of 1 byte per pixel\n    \"\"\"\n    if not (pix1.irect == pix2.irect and pix1.alpha == pix2.alpha == 0 and pix2.n == 1):\n        print(\"Warning: unsupported /SMask %i for %i:\" % (s, x))\n        print(pix2)\n        pix2 = None\n        return getimage(pix1)  # return the pixmap as is\n\n    pix = fitz.Pixmap(pix1)  # copy of pix1, with an alpha channel added\n    pix.set_alpha(pix2.samples)  # treat pix2.samples as the alpha values\n    pix1 = pix2 = None  # free temp pixmaps\n\n    # we may need to adjust something for CMYK pixmaps here:\n    return getimage(pix)\n\n\ndef open_file(filename, password, show=False, pdf=True):\n    \"\"\"Open and authenticate a document.\"\"\"\n    doc = fitz.open(filename)\n    if not doc.is_pdf and pdf is True:\n        sys.exit(\"this command supports PDF files only\")\n    rc = -1\n    if not doc.needs_pass:\n        return doc\n    if password:\n        rc = doc.authenticate(password)\n        if not rc:\n            sys.exit(\"authentication unsuccessful\")\n        if show is True:\n            print(\"authenticated as %s\" % \"owner\" if rc > 2 else \"user\")\n    else:\n        sys.exit(\"'%s' requires a password\" % doc.name)\n    return doc\n\n\ndef print_dict(item):\n    \"\"\"Print a Python dictionary.\"\"\"\n    l = max([len(k) for k in item.keys()]) + 1\n    for k, v in item.items():\n        msg = \"%s: %s\" % (k.rjust(l), v)\n        print(msg)\n    return\n\n\ndef print_xref(doc, xref):\n    \"\"\"Print an object given by XREF number.\n\n    Simulate the PDF source in \"pretty\" format.\n    For a stream also print its size.\n    \"\"\"\n    print(\"%i 0 obj\" % xref)\n    xref_str = doc.xref_object(xref)\n    print(xref_str)\n    if doc.xref_is_stream(xref):\n        temp = xref_str.split()\n        try:\n            idx = temp.index(\"/Length\") + 1\n            size = temp[idx]\n            if size.endswith(\"0 R\"):\n                size = \"unknown\"\n        except:\n            size = \"unknown\"\n        print(\"stream\\n...%s bytes\" % size)\n        print(\"endstream\")\n    print(\"endobj\")\n\n\ndef get_list(rlist, limit, what=\"page\"):\n    \"\"\"Transform a page / xref specification into a list of integers.\n\n    Args\n    ----\n        rlist: (str) the specification\n        limit: maximum number, i.e. number of pages, number of objects\n        what: a string to be used in error messages\n    Returns\n    -------\n        A list of integers representing the specification.\n    \"\"\"\n    N = str(limit - 1)\n    rlist = rlist.replace(\"N\", N).replace(\" \", \"\")\n    rlist_arr = rlist.split(\",\")\n    out_list = []\n    for seq, item in enumerate(rlist_arr):\n        n = seq + 1\n        if item.isdecimal():  # a single integer\n            i = int(item)\n            if 1 <= i < limit:\n                out_list.append(int(item))\n            else:\n                sys.exit(\"bad %s specification at item %i\" % (what, n))\n            continue\n        try:  # this must be a range now, and all of the following must work:\n            i1, i2 = item.split(\"-\")  # will fail if not 2 items produced\n            i1 = int(i1)  # will fail on non-integers\n            i2 = int(i2)\n        except:\n            sys.exit(\"bad %s range specification at item %i\" % (what, n))\n\n        if not (1 <= i1 < limit and 1 <= i2 < limit):\n            sys.exit(\"bad %s range specification at item %i\" % (what, n))\n\n        if i1 == i2:  # just in case: a range of equal numbers\n            out_list.append(i1)\n            continue\n\n        if i1 < i2:  # first less than second\n            out_list += list(range(i1, i2 + 1))\n        else:  # first larger than second\n            out_list += list(range(i1, i2 - 1, -1))\n\n    return out_list\n\n\ndef show(args):\n    doc = open_file(args.input, args.password, True)\n    size = os.path.getsize(args.input) / 1024\n    flag = \"KB\"\n    if size > 1000:\n        size /= 1024\n        flag = \"MB\"\n    size = round(size, 1)\n    meta = doc.metadata\n    print(\n        \"'%s', pages: %i, objects: %i, %g %s, %s, encryption: %s\"\n        % (\n            args.input,\n            doc.page_count,\n            doc.xref_length() - 1,\n            size,\n            flag,\n            meta[\"format\"],\n            meta[\"encryption\"],\n        )\n    )\n    n = doc.is_form_pdf\n    if n > 0:\n        s = doc.get_sigflags()\n        print(\n            \"document contains %i root form fields and is %ssigned\"\n            % (n, \"not \" if s != 3 else \"\")\n        )\n    n = doc.embfile_count()\n    if n > 0:\n        print(\"document contains %i embedded files\" % n)\n    print()\n    if args.catalog:\n        print(mycenter(\"PDF catalog\"))\n        xref = doc.pdf_catalog()\n        print_xref(doc, xref)\n        print()\n    if args.metadata:\n        print(mycenter(\"PDF metadata\"))\n        print_dict(doc.metadata)\n        print()\n    if args.xrefs:\n        print(mycenter(\"object information\"))\n        xrefl = get_list(args.xrefs, doc.xref_length(), what=\"xref\")\n        for xref in xrefl:\n            print_xref(doc, xref)\n            print()\n    if args.pages:\n        print(mycenter(\"page information\"))\n        pagel = get_list(args.pages, doc.page_count + 1)\n        for pno in pagel:\n            n = pno - 1\n            xref = doc.page_xref(n)\n            print(\"Page %i:\" % pno)\n            print_xref(doc, xref)\n            print()\n    if args.trailer:\n        print(mycenter(\"PDF trailer\"))\n        print(doc.pdf_trailer())\n        print()\n    doc.close()\n\n\ndef clean(args):\n    doc = open_file(args.input, args.password, pdf=True)\n    encryption = args.encryption\n    encrypt = (\"keep\", \"none\", \"rc4-40\", \"rc4-128\", \"aes-128\", \"aes-256\").index(\n        encryption\n    )\n\n    if not args.pages:  # simple cleaning\n        doc.save(\n            args.output,\n            garbage=args.garbage,\n            deflate=args.compress,\n            pretty=args.pretty,\n            clean=args.sanitize,\n            ascii=args.ascii,\n            linear=args.linear,\n            encryption=encrypt,\n            owner_pw=args.owner,\n            user_pw=args.user,\n            permissions=args.permission,\n        )\n        return\n\n    # create sub document from page numbers\n    pages = get_list(args.pages, doc.page_count + 1)\n    outdoc = fitz.open()\n    for pno in pages:\n        n = pno - 1\n        outdoc.insert_pdf(doc, from_page=n, to_page=n)\n    outdoc.save(\n        args.output,\n        garbage=args.garbage,\n        deflate=args.compress,\n        pretty=args.pretty,\n        clean=args.sanitize,\n        ascii=args.ascii,\n        linear=args.linear,\n        encryption=encrypt,\n        owner_pw=args.owner,\n        user_pw=args.user,\n        permissions=args.permission,\n    )\n    doc.close()\n    outdoc.close()\n    return\n\n\ndef doc_join(args):\n    \"\"\"Join pages from several PDF documents.\"\"\"\n    doc_list = args.input  # a list of input PDFs\n    doc = fitz.open()  # output PDF\n    for src_item in doc_list:  # process one input PDF\n        src_list = src_item.split(\",\")\n        password = src_list[1] if len(src_list) > 1 else None\n        src = open_file(src_list[0], password, pdf=True)\n        pages = \",\".join(src_list[2:])  # get 'pages' specifications\n        if pages:  # if anything there, retrieve a list of desired pages\n            page_list = get_list(\",\".join(src_list[2:]), src.page_count + 1)\n        else:  # take all pages\n            page_list = range(1, src.page_count + 1)\n        for i in page_list:\n            doc.insert_pdf(src, from_page=i - 1, to_page=i - 1)  # copy each source page\n        src.close()\n\n    doc.save(args.output, garbage=4, deflate=True)\n    doc.close()\n\n\ndef embedded_copy(args):\n    \"\"\"Copy embedded files between PDFs.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        not args.output or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n    src = open_file(args.source, args.pwdsource)\n    names = set(args.name) if args.name else set()\n    src_names = set(src.embfile_names())\n    if names:\n        if not names <= src_names:\n            sys.exit(\"not all names are contained in source\")\n    else:\n        names = src_names\n    if not names:\n        sys.exit(\"nothing to copy\")\n    intersect = names & set(doc.embfile_names())  # any equal name already in target?\n    if intersect:\n        sys.exit(\"following names already exist in receiving PDF: %s\" % str(intersect))\n\n    for item in names:\n        info = src.embfile_info(item)\n        buff = src.embfile_get(item)\n        doc.embfile_add(\n            item,\n            buff,\n            filename=info[\"filename\"],\n            ufilename=info[\"ufilename\"],\n            desc=info[\"desc\"],\n        )\n        print(\"copied entry '%s' from '%s'\" % (item, src.name))\n    src.close()\n    if args.output and args.output != args.input:\n        doc.save(args.output, garbage=3)\n    else:\n        doc.saveIncr()\n    doc.close()\n\n\ndef embedded_del(args):\n    \"\"\"Delete an embedded file entry.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        not args.output or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n\n    try:\n        doc.embfile_del(args.name)\n    except ValueError:\n        sys.exit(\"no such embedded file '%s'\" % args.name)\n    if not args.output or args.output == args.input:\n        doc.save_incr()\n    else:\n        doc.save(args.output, garbage=1)\n    doc.close()\n\n\ndef embedded_get(args):\n    \"\"\"Retrieve contents of an embedded file.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    try:\n        stream = doc.embfile_get(args.name)\n        d = doc.embfile_info(args.name)\n    except ValueError:\n        sys.exit(\"no such embedded file '%s'\" % args.name)\n    filename = args.output if args.output else d[\"filename\"]\n    output = open(filename, \"wb\")\n    output.write(stream)\n    output.close()\n    print(\"saved entry '%s' as '%s'\" % (args.name, filename))\n    doc.close()\n\n\ndef embedded_add(args):\n    \"\"\"Insert a new embedded file.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        args.output is None or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n\n    try:\n        doc.embfile_del(args.name)\n        sys.exit(\"entry '%s' already exists\" % args.name)\n    except:\n        pass\n\n    if not os.path.exists(args.path) or not os.path.isfile(args.path):\n        sys.exit(\"no such file '%s'\" % args.path)\n    stream = open(args.path, \"rb\").read()\n    filename = args.path\n    ufilename = filename\n    if not args.desc:\n        desc = filename\n    else:\n        desc = args.desc\n    doc.embfile_add(\n        args.name, stream, filename=filename, ufilename=ufilename, desc=desc\n    )\n    if not args.output or args.output == args.input:\n        doc.saveIncr()\n    else:\n        doc.save(args.output, garbage=3)\n    doc.close()\n\n\ndef embedded_upd(args):\n    \"\"\"Update contents or metadata of an embedded file.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    if not doc.can_save_incrementally() and (\n        args.output is None or args.output == args.input\n    ):\n        sys.exit(\"cannot save PDF incrementally\")\n\n    try:\n        doc.embfile_info(args.name)\n    except:\n        sys.exit(\"no such embedded file '%s'\" % args.name)\n\n    if (\n        args.path is not None\n        and os.path.exists(args.path)\n        and os.path.isfile(args.path)\n    ):\n        stream = open(args.path, \"rb\").read()\n    else:\n        stream = None\n\n    if args.filename:\n        filename = args.filename\n    else:\n        filename = None\n\n    if args.ufilename:\n        ufilename = args.ufilename\n    elif args.filename:\n        ufilename = args.filename\n    else:\n        ufilename = None\n\n    if args.desc:\n        desc = args.desc\n    else:\n        desc = None\n\n    doc.embfile_upd(\n        args.name, stream, filename=filename, ufilename=ufilename, desc=desc\n    )\n    if args.output is None or args.output == args.input:\n        doc.saveIncr()\n    else:\n        doc.save(args.output, garbage=3)\n    doc.close()\n\n\ndef embedded_list(args):\n    \"\"\"List embedded files.\"\"\"\n    doc = open_file(args.input, args.password, pdf=True)\n    names = doc.embfile_names()\n    if args.name is not None:\n        if args.name not in names:\n            sys.exit(\"no such embedded file '%s'\" % args.name)\n        else:\n            print()\n            print(\n                \"printing 1 of %i embedded file%s:\"\n                % (len(names), \"s\" if len(names) > 1 else \"\")\n            )\n            print()\n            print_dict(doc.embfile_info(args.name))\n            print()\n            return\n    if not names:\n        print(\"'%s' contains no embedded files\" % doc.name)\n        return\n    if len(names) > 1:\n        msg = \"'%s' contains the following %i embedded files\" % (doc.name, len(names))\n    else:\n        msg = \"'%s' contains the following embedded file\" % doc.name\n    print(msg)\n    print()\n    for name in names:\n        if not args.detail:\n            print(name)\n            continue\n        _ = doc.embfile_info(name)\n        print_dict(doc.embfile_info(name))\n        print()\n    doc.close()\n\n\ndef extract_objects(args):\n    \"\"\"Extract images and / or fonts from a PDF.\"\"\"\n    if not args.fonts and not args.images:\n        sys.exit(\"neither fonts nor images requested\")\n    doc = open_file(args.input, args.password, pdf=True)\n\n    if args.pages:\n        pages = get_list(args.pages, doc.page_count + 1)\n    else:\n        pages = range(1, doc.page_count + 1)\n\n    if not args.output:\n        out_dir = os.path.abspath(os.curdir)\n    else:\n        out_dir = args.output\n        if not (os.path.exists(out_dir) and os.path.isdir(out_dir)):\n            sys.exit(\"output directory %s does not exist\" % out_dir)\n\n    font_xrefs = set()  # already saved fonts\n    image_xrefs = set()  # already saved images\n\n    for pno in pages:\n        if args.fonts:\n            itemlist = doc.get_page_fonts(pno - 1)\n            for item in itemlist:\n                xref = item[0]\n                if xref not in font_xrefs:\n                    font_xrefs.add(xref)\n                    fontname, ext, _, buffer = doc.extract_font(xref)\n                    if ext == \"n/a\" or not buffer:\n                        continue\n                    outname = os.path.join(\n                        out_dir, f\"{fontname.replace(' ', '-')}-{xref}.{ext}\"\n                    )\n                    outfile = open(outname, \"wb\")\n                    outfile.write(buffer)\n                    outfile.close()\n                    buffer = None\n        if args.images:\n            itemlist = doc.get_page_images(pno - 1)\n            for item in itemlist:\n                xref = item[0]\n                if xref not in image_xrefs:\n                    image_xrefs.add(xref)\n                    pix = recoverpix(doc, item)\n                    if type(pix) is dict:\n                        ext = pix[\"ext\"]\n                        imgdata = pix[\"image\"]\n                        outname = os.path.join(out_dir, \"img-%i.%s\" % (xref, ext))\n                        outfile = open(outname, \"wb\")\n                        outfile.write(imgdata)\n                        outfile.close()\n                    else:\n                        outname = os.path.join(out_dir, \"img-%i.png\" % xref)\n                        pix2 = (\n                            pix\n                            if pix.colorspace.n < 4\n                            else fitz.Pixmap(fitz.csRGB, pix)\n                        )\n                        pix2.save(outname)\n\n    if args.fonts:\n        print(\"saved %i fonts to '%s'\" % (len(font_xrefs), out_dir))\n    if args.images:\n        print(\"saved %i images to '%s'\" % (len(image_xrefs), out_dir))\n    doc.close()\n\n\ndef page_simple(page, textout, GRID, fontsize, noformfeed, skip_empty, flags):\n    eop = b\"\\n\" if noformfeed else bytes([12])\n    text = page.get_text(\"text\", flags=flags)\n    if not text:\n        if not skip_empty:\n            textout.write(eop)  # write formfeed\n        return\n    textout.write(text.encode(\"utf8\", errors=\"surrogatepass\"))\n    textout.write(eop)\n    return\n\n\ndef page_blocksort(page, textout, GRID, fontsize, noformfeed, skip_empty, flags):\n    eop = b\"\\n\" if noformfeed else bytes([12])\n    blocks = page.get_text(\"blocks\", flags=flags)\n    if blocks == []:\n        if not skip_empty:\n            textout.write(eop)  # write formfeed\n        return\n    blocks.sort(key=lambda b: (b[3], b[0]))\n    for b in blocks:\n        textout.write(b[4].encode(\"utf8\", errors=\"surrogatepass\"))\n    textout.write(eop)\n    return\n\n\ndef page_layout(page, textout, GRID, fontsize, noformfeed, skip_empty, flags):\n    eop = b\"\\n\" if noformfeed else bytes([12])\n\n    # --------------------------------------------------------------------\n    def find_line_index(values: List[int], value: int) -> int:\n        \"\"\"Find the right row coordinate.\n\n        Args:\n            values: (list) y-coordinates of rows.\n            value: (int) lookup for this value (y-origin of char).\n        Returns:\n            y-ccordinate of appropriate line for value.\n        \"\"\"\n        i = bisect.bisect_right(values, value)\n        if i:\n            return values[i - 1]\n        raise RuntimeError(\"Line for %g not found in %s\" % (value, values))\n\n    # --------------------------------------------------------------------\n    def curate_rows(rows: Set[int], GRID) -> List:\n        rows = list(rows)\n        rows.sort()  # sort ascending\n        nrows = [rows[0]]\n        for h in rows[1:]:\n            if h >= nrows[-1] + GRID:  # only keep significant differences\n                nrows.append(h)\n        return nrows  # curated list of line bottom coordinates\n\n    def process_blocks(blocks: List[Dict], page: fitz.Page):\n        rows = set()\n        page_width = page.rect.width\n        page_height = page.rect.height\n        rowheight = page_height\n        left = page_width\n        right = 0\n        chars = []\n        for block in blocks:\n            for line in block[\"lines\"]:\n                if line[\"dir\"] != (1, 0):  # ignore non-horizontal text\n                    continue\n                x0, y0, x1, y1 = line[\"bbox\"]\n                if y1 < 0 or y0 > page.rect.height:  # ignore if outside CropBox\n                    continue\n                # upd row height\n                height = y1 - y0\n\n                if rowheight > height:\n                    rowheight = height\n                for span in line[\"spans\"]:\n                    if span[\"size\"] <= fontsize:\n                        continue\n                    for c in span[\"chars\"]:\n                        x0, _, x1, _ = c[\"bbox\"]\n                        cwidth = x1 - x0\n                        ox, oy = c[\"origin\"]\n                        oy = int(round(oy))\n                        rows.add(oy)\n                        ch = c[\"c\"]\n                        if left > ox and ch != \" \":\n                            left = ox  # update left coordinate\n                        if right < x1:\n                            right = x1  # update right coordinate\n                        # handle ligatures:\n                        if cwidth == 0 and chars != []:  # potential ligature\n                            old_ch, old_ox, old_oy, old_cwidth = chars[-1]\n                            if old_oy == oy:  # ligature\n                                if old_ch != chr(0xFB00):  # previous \"ff\" char lig?\n                                    lig = joinligature(old_ch + ch)  # no\n                                # convert to one of the 3-char ligatures:\n                                elif ch == \"i\":\n                                    lig = chr(0xFB03)  # \"ffi\"\n                                elif ch == \"l\":\n                                    lig = chr(0xFB04)  # \"ffl\"\n                                else:  # something wrong, leave old char in place\n                                    lig = old_ch\n                                chars[-1] = (lig, old_ox, old_oy, old_cwidth)\n                                continue\n                        chars.append((ch, ox, oy, cwidth))  # all chars on page\n        return chars, rows, left, right, rowheight\n\n    def joinligature(lig: str) -> str:\n        \"\"\"Return ligature character for a given pair / triple of characters.\n\n        Args:\n            lig: (str) 2/3 characters, e.g. \"ff\"\n        Returns:\n            Ligature, e.g. \"ff\" -> chr(0xFB00)\n        \"\"\"\n\n        if lig == \"ff\":\n            return chr(0xFB00)\n        elif lig == \"fi\":\n            return chr(0xFB01)\n        elif lig == \"fl\":\n            return chr(0xFB02)\n        elif lig == \"ffi\":\n            return chr(0xFB03)\n        elif lig == \"ffl\":\n            return chr(0xFB04)\n        elif lig == \"ft\":\n            return chr(0xFB05)\n        elif lig == \"st\":\n            return chr(0xFB06)\n        return lig\n\n    # --------------------------------------------------------------------\n    def make_textline(left, slot, minslot, lchars):\n        \"\"\"Produce the text of one output line.\n\n        Args:\n            left: (float) left most coordinate used on page\n            slot: (float) avg width of one character in any font in use.\n            minslot: (float) min width for the characters in this line.\n            chars: (list[tuple]) characters of this line.\n        Returns:\n            text: (str) text string for this line\n        \"\"\"\n        text = \"\"  # we output this\n        old_char = \"\"\n        old_x1 = 0  # end coordinate of last char\n        old_ox = 0  # x-origin of last char\n        if minslot <= fitz.EPSILON:\n            raise RuntimeError(\"program error: minslot too small = %g\" % minslot)\n\n        for c in lchars:  # loop over characters\n            char, ox, _, cwidth = c\n            ox = ox - left  # its (relative) start coordinate\n            x1 = ox + cwidth  # ending coordinate\n\n            # eliminate overprint effect\n            if old_char == char and ox - old_ox <= cwidth * 0.2:\n                continue\n\n            # omit spaces overlapping previous char\n            if char == \" \" and (old_x1 - ox) / cwidth > 0.8:\n                continue\n\n            old_char = char\n            # close enough to previous?\n            if ox < old_x1 + minslot:  # assume char adjacent to previous\n                text += char  # append to output\n                old_x1 = x1  # new end coord\n                old_ox = ox  # new origin.x\n                continue\n\n            # else next char starts after some gap:\n            # fill in right number of spaces, so char is positioned\n            # in the right slot of the line\n            if char == \" \":  # rest relevant for non-space only\n                continue\n            delta = int(ox / slot) - len(text)\n            if ox > old_x1 and delta > 1:\n                text += \" \" * delta\n            # now append char\n            text += char\n            old_x1 = x1  # new end coordinate\n            old_ox = ox  # new origin\n        return text.rstrip()\n\n    # extract page text by single characters (\"rawdict\")\n    blocks = page.get_text(\"rawdict\", flags=flags)[\"blocks\"]\n    chars, rows, left, right, rowheight = process_blocks(blocks, page)\n\n    if chars == []:\n        if not skip_empty:\n            textout.write(eop)  # write formfeed\n        return\n    # compute list of line coordinates - ignoring small (GRID) differences\n    rows = curate_rows(rows, GRID)\n\n    # sort all chars by x-coordinates, so every line will receive char info,\n    # sorted from left to right.\n    chars.sort(key=lambda c: c[1])\n\n    # populate the lines with their char info\n    lines = {}  # key: y1-ccordinate, value: char list\n    for c in chars:\n        _, _, oy, _ = c\n        y = find_line_index(rows, oy)  # y-coord of the right line\n        lchars = lines.get(y, [])  # read line chars so far\n        lchars.append(c)  # append this char\n        lines[y] = lchars  # write back to line\n\n    # ensure line coordinates are ascending\n    keys = list(lines.keys())\n    keys.sort()\n\n    # -------------------------------------------------------------------------\n    # Compute \"char resolution\" for the page: the char width corresponding to\n    # 1 text char position on output - call it 'slot'.\n    # For each line, compute median of its char widths. The minimum across all\n    # lines is 'slot'.\n    # The minimum char width of each line is used to determine if spaces must\n    # be inserted in between two characters.\n    # -------------------------------------------------------------------------\n    slot = right - left\n    minslots = {}\n    for k in keys:\n        lchars = lines[k]\n        ccount = len(lchars)\n        if ccount < 2:\n            minslots[k] = 1\n            continue\n        widths = [c[3] for c in lchars]\n        widths.sort()\n        this_slot = statistics.median(widths)  # take median value\n        if this_slot < slot:\n            slot = this_slot\n        minslots[k] = widths[0]\n\n    # compute line advance in text output\n    rowheight = rowheight * (rows[-1] - rows[0]) / (rowheight * len(rows)) * 1.2\n    rowpos = rows[0]  # first line positioned here\n    textout.write(b\"\\n\")\n    for k in keys:  # walk through the lines\n        while rowpos < k:  # honor distance between lines\n            textout.write(b\"\\n\")\n            rowpos += rowheight\n        text = make_textline(left, slot, minslots[k], lines[k])\n        textout.write((text + \"\\n\").encode(\"utf8\", errors=\"surrogatepass\"))\n        rowpos = k + rowheight\n\n    textout.write(eop)  # write formfeed\n\n\ndef gettext(args):\n    doc = open_file(args.input, args.password, pdf=False)\n    pagel = get_list(args.pages, doc.page_count + 1)\n    output = args.output\n    if output == None:\n        filename, _ = os.path.splitext(doc.name)\n        output = filename + \".txt\"\n    textout = open(output, \"wb\")\n    flags = TEXT_PRESERVE_LIGATURES | TEXT_PRESERVE_WHITESPACE\n    if args.convert_white:\n        flags ^= TEXT_PRESERVE_WHITESPACE\n    if args.noligatures:\n        flags ^= TEXT_PRESERVE_LIGATURES\n    if args.extra_spaces:\n        flags ^= TEXT_INHIBIT_SPACES\n    func = {\n        \"simple\": page_simple,\n        \"blocks\": page_blocksort,\n        \"layout\": page_layout,\n    }\n    for pno in pagel:\n        page = doc[pno - 1]\n        func[args.mode](\n            page,\n            textout,\n            args.grid,\n            args.fontsize,\n            args.noformfeed,\n            args.skip_empty,\n            flags=flags,\n        )\n\n    textout.close()\n\n\ndef main():\n    \"\"\"Define command configurations.\"\"\"\n    parser = argparse.ArgumentParser(\n        prog=\"fitz\",\n        description=mycenter(\"Basic PyMuPDF Functions\"),\n    )\n    subps = parser.add_subparsers(\n        title=\"Subcommands\", help=\"Enter 'command -h' for subcommand specific help\"\n    )\n\n    # -------------------------------------------------------------------------\n    # 'show' command\n    # -------------------------------------------------------------------------\n    ps_show = subps.add_parser(\"show\", description=mycenter(\"display PDF information\"))\n    ps_show.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_show.add_argument(\"-password\", help=\"password\")\n    ps_show.add_argument(\"-catalog\", action=\"store_true\", help=\"show PDF catalog\")\n    ps_show.add_argument(\"-trailer\", action=\"store_true\", help=\"show PDF trailer\")\n    ps_show.add_argument(\"-metadata\", action=\"store_true\", help=\"show PDF metadata\")\n    ps_show.add_argument(\n        \"-xrefs\", type=str, help=\"show selected objects, format: 1,5-7,N\"\n    )\n    ps_show.add_argument(\n        \"-pages\", type=str, help=\"show selected pages, format: 1,5-7,50-N\"\n    )\n    ps_show.set_defaults(func=show)\n\n    # -------------------------------------------------------------------------\n    # 'clean' command\n    # -------------------------------------------------------------------------\n    ps_clean = subps.add_parser(\n        \"clean\", description=mycenter(\"optimize PDF, or create sub-PDF if pages given\")\n    )\n    ps_clean.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_clean.add_argument(\"output\", type=str, help=\"output PDF filename\")\n    ps_clean.add_argument(\"-password\", help=\"password\")\n\n    ps_clean.add_argument(\n        \"-encryption\",\n        help=\"encryption method\",\n        choices=(\"keep\", \"none\", \"rc4-40\", \"rc4-128\", \"aes-128\", \"aes-256\"),\n        default=\"none\",\n    )\n\n    ps_clean.add_argument(\"-owner\", type=str, help=\"owner password\")\n    ps_clean.add_argument(\"-user\", type=str, help=\"user password\")\n\n    ps_clean.add_argument(\n        \"-garbage\",\n        type=int,\n        help=\"garbage collection level\",\n        choices=range(5),\n        default=0,\n    )\n\n    ps_clean.add_argument(\n        \"-compress\",\n        action=\"store_true\",\n        default=False,\n        help=\"compress (deflate) output\",\n    )\n\n    ps_clean.add_argument(\n        \"-ascii\", action=\"store_true\", default=False, help=\"ASCII encode binary data\"\n    )\n\n    ps_clean.add_argument(\n        \"-linear\",\n        action=\"store_true\",\n        default=False,\n        help=\"format for fast web display\",\n    )\n\n    ps_clean.add_argument(\n        \"-permission\", type=int, default=-1, help=\"integer with permission levels\"\n    )\n\n    ps_clean.add_argument(\n        \"-sanitize\",\n        action=\"store_true\",\n        default=False,\n        help=\"sanitize / clean contents\",\n    )\n    ps_clean.add_argument(\n        \"-pretty\", action=\"store_true\", default=False, help=\"prettify PDF structure\"\n    )\n    ps_clean.add_argument(\n        \"-pages\", help=\"output selected pages pages, format: 1,5-7,50-N\"\n    )\n    ps_clean.set_defaults(func=clean)\n\n    # -------------------------------------------------------------------------\n    # 'join' command\n    # -------------------------------------------------------------------------\n    ps_join = subps.add_parser(\n        \"join\",\n        description=mycenter(\"join PDF documents\"),\n        epilog=\"specify each input as 'filename[,password[,pages]]'\",\n    )\n    ps_join.add_argument(\"input\", nargs=\"*\", help=\"input filenames\")\n    ps_join.add_argument(\"-output\", required=True, help=\"output filename\")\n    ps_join.set_defaults(func=doc_join)\n\n    # -------------------------------------------------------------------------\n    # 'extract' command\n    # -------------------------------------------------------------------------\n    ps_extract = subps.add_parser(\n        \"extract\", description=mycenter(\"extract images and fonts to disk\")\n    )\n    ps_extract.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_extract.add_argument(\"-images\", action=\"store_true\", help=\"extract images\")\n    ps_extract.add_argument(\"-fonts\", action=\"store_true\", help=\"extract fonts\")\n    ps_extract.add_argument(\n        \"-output\", help=\"folder to receive output, defaults to current\"\n    )\n    ps_extract.add_argument(\"-password\", help=\"password\")\n    ps_extract.add_argument(\n        \"-pages\", type=str, help=\"consider these pages only, format: 1,5-7,50-N\"\n    )\n    ps_extract.set_defaults(func=extract_objects)\n\n    # -------------------------------------------------------------------------\n    # 'embed-info'\n    # -------------------------------------------------------------------------\n    ps_show = subps.add_parser(\n        \"embed-info\", description=mycenter(\"list embedded files\")\n    )\n    ps_show.add_argument(\"input\", help=\"PDF filename\")\n    ps_show.add_argument(\"-name\", help=\"if given, report only this one\")\n    ps_show.add_argument(\"-detail\", action=\"store_true\", help=\"detail information\")\n    ps_show.add_argument(\"-password\", help=\"password\")\n    ps_show.set_defaults(func=embedded_list)\n\n    # -------------------------------------------------------------------------\n    # 'embed-add' command\n    # -------------------------------------------------------------------------\n    ps_embed_add = subps.add_parser(\n        \"embed-add\", description=mycenter(\"add embedded file\")\n    )\n    ps_embed_add.add_argument(\"input\", help=\"PDF filename\")\n    ps_embed_add.add_argument(\"-password\", help=\"password\")\n    ps_embed_add.add_argument(\n        \"-output\", help=\"output PDF filename, incremental save if none\"\n    )\n    ps_embed_add.add_argument(\"-name\", required=True, help=\"name of new entry\")\n    ps_embed_add.add_argument(\"-path\", required=True, help=\"path to data for new entry\")\n    ps_embed_add.add_argument(\"-desc\", help=\"description of new entry\")\n    ps_embed_add.set_defaults(func=embedded_add)\n\n    # -------------------------------------------------------------------------\n    # 'embed-del' command\n    # -------------------------------------------------------------------------\n    ps_embed_del = subps.add_parser(\n        \"embed-del\", description=mycenter(\"delete embedded file\")\n    )\n    ps_embed_del.add_argument(\"input\", help=\"PDF filename\")\n    ps_embed_del.add_argument(\"-password\", help=\"password\")\n    ps_embed_del.add_argument(\n        \"-output\", help=\"output PDF filename, incremental save if none\"\n    )\n    ps_embed_del.add_argument(\"-name\", required=True, help=\"name of entry to delete\")\n    ps_embed_del.set_defaults(func=embedded_del)\n\n    # -------------------------------------------------------------------------\n    # 'embed-upd' command\n    # -------------------------------------------------------------------------\n    ps_embed_upd = subps.add_parser(\n        \"embed-upd\",\n        description=mycenter(\"update embedded file\"),\n        epilog=\"except '-name' all parameters are optional\",\n    )\n    ps_embed_upd.add_argument(\"input\", help=\"PDF filename\")\n    ps_embed_upd.add_argument(\"-name\", required=True, help=\"name of entry\")\n    ps_embed_upd.add_argument(\"-password\", help=\"password\")\n    ps_embed_upd.add_argument(\n        \"-output\", help=\"Output PDF filename, incremental save if none\"\n    )\n    ps_embed_upd.add_argument(\"-path\", help=\"path to new data for entry\")\n    ps_embed_upd.add_argument(\"-filename\", help=\"new filename to store in entry\")\n    ps_embed_upd.add_argument(\n        \"-ufilename\", help=\"new unicode filename to store in entry\"\n    )\n    ps_embed_upd.add_argument(\"-desc\", help=\"new description to store in entry\")\n    ps_embed_upd.set_defaults(func=embedded_upd)\n\n    # -------------------------------------------------------------------------\n    # 'embed-extract' command\n    # -------------------------------------------------------------------------\n    ps_embed_extract = subps.add_parser(\n        \"embed-extract\", description=mycenter(\"extract embedded file to disk\")\n    )\n    ps_embed_extract.add_argument(\"input\", type=str, help=\"PDF filename\")\n    ps_embed_extract.add_argument(\"-name\", required=True, help=\"name of entry\")\n    ps_embed_extract.add_argument(\"-password\", help=\"password\")\n    ps_embed_extract.add_argument(\n        \"-output\", help=\"output filename, default is stored name\"\n    )\n    ps_embed_extract.set_defaults(func=embedded_get)\n\n    # -------------------------------------------------------------------------\n    # 'embed-copy' command\n    # -------------------------------------------------------------------------\n    ps_embed_copy = subps.add_parser(\n        \"embed-copy\", description=mycenter(\"copy embedded files between PDFs\")\n    )\n    ps_embed_copy.add_argument(\"input\", type=str, help=\"PDF to receive embedded files\")\n    ps_embed_copy.add_argument(\"-password\", help=\"password of input\")\n    ps_embed_copy.add_argument(\n        \"-output\", help=\"output PDF, incremental save to 'input' if omitted\"\n    )\n    ps_embed_copy.add_argument(\n        \"-source\", required=True, help=\"copy embedded files from here\"\n    )\n    ps_embed_copy.add_argument(\"-pwdsource\", help=\"password of 'source' PDF\")\n    ps_embed_copy.add_argument(\n        \"-name\", nargs=\"*\", help=\"restrict copy to these entries\"\n    )\n    ps_embed_copy.set_defaults(func=embedded_copy)\n\n    # -------------------------------------------------------------------------\n    # 'textlayout' command\n    # -------------------------------------------------------------------------\n    ps_gettext = subps.add_parser(\n        \"gettext\", description=mycenter(\"extract text in various formatting modes\")\n    )\n    ps_gettext.add_argument(\"input\", type=str, help=\"input document filename\")\n    ps_gettext.add_argument(\"-password\", help=\"password for input document\")\n    ps_gettext.add_argument(\n        \"-mode\",\n        type=str,\n        help=\"mode: simple, block sort, or layout (default)\",\n        choices=(\"simple\", \"blocks\", \"layout\"),\n        default=\"layout\",\n    )\n    ps_gettext.add_argument(\n        \"-pages\",\n        type=str,\n        help=\"select pages, format: 1,5-7,50-N\",\n        default=\"1-N\",\n    )\n    ps_gettext.add_argument(\n        \"-noligatures\",\n        action=\"store_true\",\n        help=\"expand ligature characters (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-convert-white\",\n        action=\"store_true\",\n        help=\"convert whitespace characters to white (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-extra-spaces\",\n        action=\"store_true\",\n        help=\"fill gaps with spaces (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-noformfeed\",\n        action=\"store_true\",\n        help=\"write linefeeds, no formfeeds (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-skip-empty\",\n        action=\"store_true\",\n        help=\"suppress pages with no text (default False)\",\n        default=False,\n    )\n    ps_gettext.add_argument(\n        \"-output\",\n        help=\"store text in this file (default inputfilename.txt)\",\n    )\n    ps_gettext.add_argument(\n        \"-grid\",\n        type=float,\n        help=\"merge lines if closer than this (default 2)\",\n        default=2,\n    )\n    ps_gettext.add_argument(\n        \"-fontsize\",\n        type=float,\n        help=\"only include text with a larger fontsize (default 3)\",\n        default=3,\n    )\n    ps_gettext.set_defaults(func=gettext)\n\n    # -------------------------------------------------------------------------\n    # start program\n    # -------------------------------------------------------------------------\n    args = parser.parse_args()  # create parameter arguments class\n    if not hasattr(args, \"func\"):  # no function selected\n        parser.print_help()  # so print top level help\n    else:\n        args.func(args)  # execute requested command\n\n\nif __name__ == \"__main__\":\n    main()\n"
  },
  {
    "path": "src_classic/_config.h",
    "content": "// Copyright (C) 2004-2021 Artifex Software, Inc.\n//\n// This file is part of MuPDF.\n//\n// MuPDF is free software: you can redistribute it and/or modify it under the\n// terms of the GNU Affero General Public License as published by the Free\n// Software Foundation, either version 3 of the License, or (at your option)\n// any later version.\n//\n// MuPDF is distributed in the hope that it will be useful, but WITHOUT ANY\n// WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS\n// FOR A PARTICULAR PURPOSE. See the GNU Affero General Public License for more\n// details.\n//\n// You should have received a copy of the GNU Affero General Public License\n// along with MuPDF. If not, see <https://www.gnu.org/licenses/agpl-3.0.en.html>\n//\n// Alternative licensing terms are available from the licensor.\n// For commercial licensing, see <https://www.artifex.com/> or contact\n// Artifex Software, Inc., 39 Mesa Street, Suite 108A, San Francisco,\n// CA 94129, USA, for further information.\n\n#ifndef FZ_CONFIG_H\n\n#define FZ_CONFIG_H\n\n/**\n\tEnable the following for spot (and hence overprint/overprint\n\tsimulation) capable rendering. This forces FZ_PLOTTERS_N on.\n*/\n/* #define FZ_ENABLE_SPOT_RENDERING 1 */\n\n/**\n\tChoose which plotters we need.\n\tBy default we build all the plotters in. To avoid building\n\tplotters in that aren't needed, define the unwanted\n\tFZ_PLOTTERS_... define to 0.\n*/\n/* #define FZ_PLOTTERS_G 1 */\n/* #define FZ_PLOTTERS_RGB 1 */\n/* #define FZ_PLOTTERS_CMYK 1 */\n/* #define FZ_PLOTTERS_N 1 */\n\n/**\n\tChoose which document agents to include.\n\tBy default all are enabled. To avoid building unwanted\n\tones, define FZ_ENABLE_... to 0.\n*/\n/* #define FZ_ENABLE_PDF 1 */\n/* #define FZ_ENABLE_XPS 1 */\n/* #define FZ_ENABLE_SVG 1 */\n/* #define FZ_ENABLE_CBZ 1 */\n/* #define FZ_ENABLE_IMG 1 */\n/* #define FZ_ENABLE_HTML 1 */\n/* #define FZ_ENABLE_EPUB 1 */\n\n/**\n\tChoose which document writers to include.\n\tBy default all are enabled. To avoid building unwanted\n\tones, define FZ_ENABLE_..._OUTPUT to 0.\n*/\n/* #define FZ_ENABLE_OCR_OUTPUT 1 */\n/* #define FZ_ENABLE_DOCX_OUTPUT 1 */\n/* #define FZ_ENABLE_ODT_OUTPUT 1 */\n\n/**\n\tChoose whether to enable ICC color profiles.\n*/\n/* #define FZ_ENABLE_ICC 1 */\n\n/**\n\tChoose whether to enable JPEG2000 decoding.\n\tBy default, it is enabled, but due to frequent security\n\tissues with the third party libraries we support disabling\n\tit with this flag.\n*/\n/* #define FZ_ENABLE_JPX 1 */\n\n/**\n\tChoose whether to enable JavaScript.\n\tBy default JavaScript is enabled both for mutool and PDF\n\tinteractivity.\n*/\n/* #define FZ_ENABLE_JS 1 */\n\n/**\n\tChoose which fonts to include.\n\tBy default we include the base 14 PDF fonts,\n\tDroidSansFallback from Android for CJK, and\n\tCharis SIL from SIL for epub/html.\n\tEnable the following defines to AVOID including\n\tunwanted fonts.\n*/\n/* To avoid all noto fonts except CJK, enable: */\n/* #define TOFU */\n\n/* To skip the CJK font, enable: (this implicitly enables TOFU_CJK_EXT\n * and TOFU_CJK_LANG) */\n/* #define TOFU_CJK */\n\n/* To skip CJK Extension A, enable: (this implicitly enables\n * TOFU_CJK_LANG) */\n#define TOFU_CJK_EXT 1\n\n/* To skip CJK language specific fonts, enable: */\n/* #define TOFU_CJK_LANG */\n\n/* To skip the Emoji font, enable: */\n/* #define TOFU_EMOJI */\n\n/* To skip the ancient/historic scripts, enable: */\n/* #define TOFU_HISTORIC */\n\n/* To skip the symbol font, enable: */\n/* #define TOFU_SYMBOL */\n\n/* To skip the SIL fonts, enable: */\n/* #define TOFU_SIL */\n\n/* To skip the Base14 fonts, enable: */\n/* #define TOFU_BASE14 */\n/* (You probably really don't want to do that except for measurement\n * purposes!) */\n\n/* ---------- DO NOT EDIT ANYTHING UNDER THIS LINE ---------- */\n\n#ifndef FZ_ENABLE_SPOT_RENDERING\n#define FZ_ENABLE_SPOT_RENDERING 1\n#endif\n\n#if FZ_ENABLE_SPOT_RENDERING\n#undef FZ_PLOTTERS_N\n#define FZ_PLOTTERS_N 1\n#endif /* FZ_ENABLE_SPOT_RENDERING */\n\n#ifndef FZ_PLOTTERS_G\n#define FZ_PLOTTERS_G 1\n#endif /* FZ_PLOTTERS_G */\n\n#ifndef FZ_PLOTTERS_RGB\n#define FZ_PLOTTERS_RGB 1\n#endif /* FZ_PLOTTERS_RGB */\n\n#ifndef FZ_PLOTTERS_CMYK\n#define FZ_PLOTTERS_CMYK 1\n#endif /* FZ_PLOTTERS_CMYK */\n\n#ifndef FZ_PLOTTERS_N\n#define FZ_PLOTTERS_N 1\n#endif /* FZ_PLOTTERS_N */\n\n/* We need at least 1 plotter defined */\n#if FZ_PLOTTERS_G == 0 && FZ_PLOTTERS_RGB == 0 && FZ_PLOTTERS_CMYK == 0\n#undef FZ_PLOTTERS_N\n#define FZ_PLOTTERS_N 1\n#endif\n\n#ifndef FZ_ENABLE_PDF\n#define FZ_ENABLE_PDF 1\n#endif /* FZ_ENABLE_PDF */\n\n#ifndef FZ_ENABLE_XPS\n#define FZ_ENABLE_XPS 1\n#endif /* FZ_ENABLE_XPS */\n\n#ifndef FZ_ENABLE_SVG\n#define FZ_ENABLE_SVG 1\n#endif /* FZ_ENABLE_SVG */\n\n#ifndef FZ_ENABLE_CBZ\n#define FZ_ENABLE_CBZ 1\n#endif /* FZ_ENABLE_CBZ */\n\n#ifndef FZ_ENABLE_IMG\n#define FZ_ENABLE_IMG 1\n#endif /* FZ_ENABLE_IMG */\n\n#ifndef FZ_ENABLE_HTML\n#define FZ_ENABLE_HTML 1\n#endif /* FZ_ENABLE_HTML */\n\n#ifndef FZ_ENABLE_EPUB\n#define FZ_ENABLE_EPUB 1\n#endif /* FZ_ENABLE_EPUB */\n\n#ifndef FZ_ENABLE_OCR_OUTPUT\n#define FZ_ENABLE_OCR_OUTPUT 1\n#endif /* FZ_ENABLE_OCR_OUTPUT */\n\n#ifndef FZ_ENABLE_ODT_OUTPUT\n#define FZ_ENABLE_ODT_OUTPUT 1\n#endif /* FZ_ENABLE_ODT_OUTPUT */\n\n#ifndef FZ_ENABLE_DOCX_OUTPUT\n#define FZ_ENABLE_DOCX_OUTPUT 1\n#endif /* FZ_ENABLE_DOCX_OUTPUT */\n\n#ifndef FZ_ENABLE_JPX\n#define FZ_ENABLE_JPX 1\n#endif /* FZ_ENABLE_JPX */\n\n#ifndef FZ_ENABLE_JS\n#define FZ_ENABLE_JS 1\n#endif /* FZ_ENABLE_JS */\n\n#ifndef FZ_ENABLE_ICC\n#define FZ_ENABLE_ICC 1\n#endif /* FZ_ENABLE_ICC */\n\n/* If Epub and HTML are both disabled, disable SIL fonts */\n#if FZ_ENABLE_HTML == 0 && FZ_ENABLE_EPUB == 0\n#undef TOFU_SIL\n#define TOFU_SIL\n#endif\n\n#if !defined(HAVE_LEPTONICA) || !defined(HAVE_TESSERACT)\n#ifndef OCR_DISABLED\n#define OCR_DISABLED\n#endif\n#endif\n\n#endif /* FZ_CONFIG_H */\n"
  },
  {
    "path": "src_classic/fitz_old.i",
    "content": "%module fitz\n%pythonbegin %{\n%}\n//------------------------------------------------------------------------\n// SWIG macros: handle fitz exceptions\n//------------------------------------------------------------------------\n%define FITZEXCEPTION(meth, cond)\n%exception meth\n{\n    $action\n    if (cond) {\n        return JM_ReturnException(gctx);\n    }\n}\n%enddef\n\n\n%define FITZEXCEPTION2(meth, cond)\n%exception meth\n{\n    $action\n    if (cond) {\n        const char *msg = fz_caught_message(gctx);\n        if (strcmp(msg, MSG_BAD_FILETYPE) == 0) {\n            PyErr_SetString(PyExc_ValueError, msg);\n        } else {\n            PyErr_SetString(JM_Exc_FileDataError, MSG_BAD_DOCUMENT);\n        }\n        return NULL;\n    }\n}\n%enddef\n\n//------------------------------------------------------------------------\n// SWIG macro: check that a document is not closed / encrypted\n//------------------------------------------------------------------------\n%define CLOSECHECK(meth, doc)\n%pythonprepend meth %{doc\nif self.is_closed or self.is_encrypted:\n    raise ValueError(\"document closed or encrypted\")%}\n%enddef\n\n%define CLOSECHECK0(meth, doc)\n%pythonprepend meth%{doc\nif self.is_closed:\n    raise ValueError(\"document closed\")%}\n%enddef\n\n//------------------------------------------------------------------------\n// SWIG macro: check if object has a valid parent\n//------------------------------------------------------------------------\n%define PARENTCHECK(meth, doc)\n%pythonprepend meth %{doc\nCheckParent(self)%}\n%enddef\n\n\n//------------------------------------------------------------------------\n// SWIG macro: ensure object still exists\n//------------------------------------------------------------------------\n%define ENSURE_OWNERSHIP(meth, doc)\n%pythonprepend meth %{doc\nEnsureOwnership(self)%}\n%enddef\n\n%include \"mupdf/fitz/version.h\"\n\n%{\n#define MEMDEBUG 0\n#if MEMDEBUG == 1\n    #define DEBUGMSG1(x) PySys_WriteStderr(\"[DEBUG] free %s \", x)\n    #define DEBUGMSG2 PySys_WriteStderr(\"... done!\\n\")\n#else\n    #define DEBUGMSG1(x)\n    #define DEBUGMSG2\n#endif\n\n#ifndef FLT_EPSILON\n  #define FLT_EPSILON 1e-5\n#endif\n\n#define SWIG_FILE_WITH_INIT\n\n// JM_MEMORY controls what allocators we tell MuPDF to use when we call\n// fz_new_context():\n//\n//  JM_MEMORY=0: MuPDF uses malloc()/free().\n//  JM_MEMORY=1: MuPDF uses PyMem_Malloc()/PyMem_Free().\n//\n// There are also a small number of places where we call malloc() or\n// PyMem_Malloc() ourselves, depending on JM_MEMORY.\n//\n#define JM_MEMORY 0\n\n#if JM_MEMORY == 1\n    #define JM_Alloc(type, len) PyMem_New(type, len)\n    #define JM_Free(x) PyMem_Del(x)\n#else\n    #define JM_Alloc(type, len) (type *) malloc(sizeof(type)*len)\n    #define JM_Free(x) free(x)\n#endif\n\n#define EMPTY_STRING PyUnicode_FromString(\"\")\n#define EXISTS(x) (x != NULL && PyObject_IsTrue(x)==1)\n#define RAISEPY(context, msg, exc) {JM_Exc_CurrentException=exc; fz_throw(context, FZ_ERROR_GENERIC, msg);}\n#define ASSERT_PDF(cond) if (cond == NULL) RAISEPY(gctx, MSG_IS_NO_PDF, PyExc_RuntimeError)\n#define ENSURE_OPERATION(ctx, pdf) if (!JM_have_operation(ctx, pdf)) RAISEPY(ctx, \"No journalling operation started\", PyExc_RuntimeError)\n#define INRANGE(v, low, high) ((low) <= v && v <= (high))\n#define JM_BOOL(x) PyBool_FromLong((long) (x))\n#define JM_PyErr_Clear if (PyErr_Occurred()) PyErr_Clear()\n\n#define JM_StrAsChar(x) (char *)PyUnicode_AsUTF8(x)\n#define JM_BinFromChar(x) PyBytes_FromString(x)\n#define JM_BinFromCharSize(x, y) PyBytes_FromStringAndSize(x, (Py_ssize_t) y)\n\n#include <mupdf/fitz.h>\n#include <mupdf/pdf.h>\n#include <time.h>\n// freetype includes >> --------------------------------------------------\n#include <ft2build.h>\n#include FT_FREETYPE_H\n#ifdef FT_FONT_FORMATS_H\n#include FT_FONT_FORMATS_H\n#else\n#include FT_XFREE86_H\n#endif\n#include FT_TRUETYPE_TABLES_H\n\n#ifndef FT_SFNT_HEAD\n#define FT_SFNT_HEAD ft_sfnt_head\n#endif\n// << freetype includes --------------------------------------------------\n\nvoid JM_delete_widget(fz_context *ctx, pdf_page *page, pdf_annot *annot);\nstatic void JM_get_page_labels(fz_context *ctx, PyObject *liste, pdf_obj *nums);\nstatic int DICT_SETITEMSTR_DROP(PyObject *dict, const char *key, PyObject *value);\nstatic int LIST_APPEND_DROP(PyObject *list, PyObject *item);\nstatic int LIST_APPEND_DROP(PyObject *list, PyObject *item);\nstatic fz_irect JM_irect_from_py(PyObject *r);\nstatic fz_matrix JM_matrix_from_py(PyObject *m);\nstatic fz_point JM_normalize_vector(float x, float y);\nstatic fz_point JM_point_from_py(PyObject *p);\nstatic fz_quad JM_quad_from_py(PyObject *r);\nstatic fz_rect JM_rect_from_py(PyObject *r);\nstatic int JM_FLOAT_ITEM(PyObject *obj, Py_ssize_t idx, double *result);\nstatic int JM_INT_ITEM(PyObject *obj, Py_ssize_t idx, int *result);\nstatic PyObject *JM_py_from_irect(fz_irect r);\nstatic PyObject *JM_py_from_matrix(fz_matrix m);\nstatic PyObject *JM_py_from_point(fz_point p);\nstatic PyObject *JM_py_from_quad(fz_quad q);\nstatic PyObject *JM_py_from_rect(fz_rect r);\nstatic void show(const char* prefix, PyObject* obj);\n\n\n// additional headers ----------------------------------------------\n#if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR == 23 && FZ_VERSION_PATCH < 8\npdf_obj *pdf_lookup_page_loc(fz_context *ctx, pdf_document *doc, int needle, pdf_obj **parentp, int *indexp);\nfz_pixmap *fz_scale_pixmap(fz_context *ctx, fz_pixmap *src, float x, float y, float w, float h, const fz_irect *clip);\nint fz_pixmap_size(fz_context *ctx, fz_pixmap *src);\nvoid fz_subsample_pixmap(fz_context *ctx, fz_pixmap *tile, int factor);\nvoid fz_copy_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_pixmap *src, fz_irect b, const fz_default_colorspaces *default_cs);\nvoid fz_write_pixmap_as_jpeg(fz_context *ctx, fz_output *out, fz_pixmap *pix, int jpg_quality);\n#endif\nstatic const float JM_font_ascender(fz_context *ctx, fz_font *font);\nstatic const float JM_font_descender(fz_context *ctx, fz_font *font);\n// end of additional headers --------------------------------------------\n\nstatic PyObject *JM_mupdf_warnings_store;\nstatic int JM_mupdf_show_errors;\nstatic int JM_mupdf_show_warnings;\nstatic PyObject *JM_Exc_FileDataError;\nstatic PyObject *JM_Exc_CurrentException;\n%}\n\n//------------------------------------------------------------------------\n// global context\n//------------------------------------------------------------------------\n%init %{\n    #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n    /* Stop Memento backtraces if we reach the Python interpreter.\n    `cfunction_call()` isn't the only way that Python calls C though, so we\n    might need extra calls to Memento_addBacktraceLimitFnname().\n    \n    We put this inside `#ifdef MEMENTO` because memento.h's disabling macro\n    causes \"warning: statement with no effect\" from cc. */\n    #ifdef MEMENTO\n        Memento_addBacktraceLimitFnname(\"cfunction_call\");\n    #endif\n    #endif\n\n    /*\n    We end up with Memento leaks from fz_new_context()'s allocs even when our\n    atexit handler calls fz_drop_context(), so remove these from Memento's\n    accounting.\n    */\n    Memento_startLeaking();\n#if JM_MEMORY == 1\n    gctx = fz_new_context(&JM_Alloc_Context, NULL, FZ_STORE_DEFAULT);\n#else\n    gctx = fz_new_context(NULL, NULL, FZ_STORE_DEFAULT);\n#endif\n    Memento_stopLeaking();\n    if(!gctx)\n    {\n        PyErr_SetString(PyExc_RuntimeError, \"Fatal error: cannot create global context.\");\n        return NULL;\n    }\n    fz_register_document_handlers(gctx);\n\n//------------------------------------------------------------------------\n// START redirect stdout/stderr\n//------------------------------------------------------------------------\nJM_mupdf_warnings_store = PyList_New(0);\nJM_mupdf_show_errors = 1;\nJM_mupdf_show_warnings = 0;\nchar user[] = \"PyMuPDF\";\nfz_set_warning_callback(gctx, JM_mupdf_warning, &user);\nfz_set_error_callback(gctx, JM_mupdf_error, &user);\nJM_Exc_FileDataError = NULL;\nJM_Exc_CurrentException = PyExc_RuntimeError;\n//------------------------------------------------------------------------\n// STOP redirect stdout/stderr\n//------------------------------------------------------------------------\n// init global constants\n//------------------------------------------------------------------------\ndictkey_align = PyUnicode_InternFromString(\"align\");\ndictkey_ascender = PyUnicode_InternFromString(\"ascender\");\ndictkey_bbox = PyUnicode_InternFromString(\"bbox\");\ndictkey_blocks = PyUnicode_InternFromString(\"blocks\");\ndictkey_bpc = PyUnicode_InternFromString(\"bpc\");\ndictkey_c = PyUnicode_InternFromString(\"c\");\ndictkey_chars = PyUnicode_InternFromString(\"chars\");\ndictkey_color = PyUnicode_InternFromString(\"color\");\ndictkey_colorspace = PyUnicode_InternFromString(\"colorspace\");\ndictkey_content = PyUnicode_InternFromString(\"content\");\ndictkey_creationDate = PyUnicode_InternFromString(\"creationDate\");\ndictkey_cs_name = PyUnicode_InternFromString(\"cs-name\");\ndictkey_da = PyUnicode_InternFromString(\"da\");\ndictkey_dashes = PyUnicode_InternFromString(\"dashes\");\ndictkey_desc = PyUnicode_InternFromString(\"desc\");\ndictkey_desc = PyUnicode_InternFromString(\"descender\");\ndictkey_descender = PyUnicode_InternFromString(\"descender\");\ndictkey_dir = PyUnicode_InternFromString(\"dir\");\ndictkey_effect = PyUnicode_InternFromString(\"effect\");\ndictkey_ext = PyUnicode_InternFromString(\"ext\");\ndictkey_filename = PyUnicode_InternFromString(\"filename\");\ndictkey_fill = PyUnicode_InternFromString(\"fill\");\ndictkey_flags = PyUnicode_InternFromString(\"flags\");\ndictkey_font = PyUnicode_InternFromString(\"font\");\ndictkey_glyph = PyUnicode_InternFromString(\"glyph\");\ndictkey_height = PyUnicode_InternFromString(\"height\");\ndictkey_id = PyUnicode_InternFromString(\"id\");\ndictkey_image = PyUnicode_InternFromString(\"image\");\ndictkey_items = PyUnicode_InternFromString(\"items\");\ndictkey_length = PyUnicode_InternFromString(\"length\");\ndictkey_lines = PyUnicode_InternFromString(\"lines\");\ndictkey_matrix = PyUnicode_InternFromString(\"transform\");\ndictkey_modDate = PyUnicode_InternFromString(\"modDate\");\ndictkey_name = PyUnicode_InternFromString(\"name\");\ndictkey_number = PyUnicode_InternFromString(\"number\");\ndictkey_origin = PyUnicode_InternFromString(\"origin\");\ndictkey_rect = PyUnicode_InternFromString(\"rect\");\ndictkey_size = PyUnicode_InternFromString(\"size\");\ndictkey_smask = PyUnicode_InternFromString(\"smask\");\ndictkey_spans = PyUnicode_InternFromString(\"spans\");\ndictkey_stroke = PyUnicode_InternFromString(\"stroke\");\ndictkey_style = PyUnicode_InternFromString(\"style\");\ndictkey_subject = PyUnicode_InternFromString(\"subject\");\ndictkey_text = PyUnicode_InternFromString(\"text\");\ndictkey_title = PyUnicode_InternFromString(\"title\");\ndictkey_type = PyUnicode_InternFromString(\"type\");\ndictkey_ufilename = PyUnicode_InternFromString(\"ufilename\");\ndictkey_width = PyUnicode_InternFromString(\"width\");\ndictkey_wmode = PyUnicode_InternFromString(\"wmode\");\ndictkey_xref = PyUnicode_InternFromString(\"xref\");\ndictkey_xres = PyUnicode_InternFromString(\"xres\");\ndictkey_yres = PyUnicode_InternFromString(\"yres\");\n\natexit( cleanup);\n%}\n\n%header %{\nfz_context *gctx;\n\nstatic void cleanup()\n{\n    fz_drop_context( gctx);\n}\n\nstatic int JM_UNIQUE_ID = 0;\n\nstruct DeviceWrapper {\n    fz_device *device;\n    fz_display_list *list;\n};\n%}\n\n//------------------------------------------------------------------------\n// include version information and several other helpers\n//------------------------------------------------------------------------\n%pythoncode %{\nimport sys\nimport io\nimport math\nimport os\nimport weakref\nimport hashlib\nimport typing\nimport binascii\nimport re\nimport tarfile\nimport zipfile\nimport pathlib\nimport string\n\n# PDF names must not contain these characters:\nINVALID_NAME_CHARS = set(string.whitespace + \"()<>[]{}/%\" + chr(0))\n\nTESSDATA_PREFIX = os.getenv(\"TESSDATA_PREFIX\")\npoint_like = \"point_like\"\nrect_like = \"rect_like\"\nmatrix_like = \"matrix_like\"\nquad_like = \"quad_like\"\n\n# ByteString is gone from typing in 3.14.\n# collections.abc.Buffer available from 3.12 only\ntry:\n    ByteString = typing.ByteString\nexcept AttributeError:\n    ByteString = bytes | bytearray | memoryview\n\nAnyType = typing.Any\nOptInt = typing.Union[int, None]\nOptFloat = typing.Optional[float]\nOptStr = typing.Optional[str]\nOptDict = typing.Optional[dict]\nOptBytes = typing.Optional[ByteString]\nOptSeq = typing.Optional[typing.Sequence]\n\ntry:\n    from pymupdf_fonts import fontdescriptors, fontbuffers\n\n    fitz_fontdescriptors = fontdescriptors.copy()\n    for k in fitz_fontdescriptors.keys():\n        fitz_fontdescriptors[k][\"loader\"] = fontbuffers[k]\n    del fontdescriptors, fontbuffers\nexcept ImportError:\n    fitz_fontdescriptors = {}\n%}\n%include version.i\n%include helper-git-versions.i\n%include helper-defines.i\n%include helper-globals.i\n%include helper-geo-c.i\n%include helper-other.i\n%include helper-pixmap.i\n%include helper-geo-py.i\n%include helper-annot.i\n%include helper-fields.i\n%include helper-python.i\n%include helper-portfolio.i\n%include helper-select.i\n%include helper-stext.i\n%include helper-xobject.i\n%include helper-pdfinfo.i\n%include helper-convert.i\n%include helper-fileobj.i\n%include helper-devices.i\n\n%{\n// Declaring these structs here prevents gcc from generating warnings like:\n//\n//      warning: 'struct Document' declared inside parameter list will not be visible outside of this definition or declaration\n//\nstruct Colorspace;\nstruct Document;\nstruct Font;\nstruct Graftmap;\nstruct TextPage;\nstruct TextWriter;\nstruct DocumentWriter;\nstruct Xml;\nstruct Archive;\nstruct Story;\n%}\n\n//------------------------------------------------------------------------\n// fz_document\n//------------------------------------------------------------------------\nstruct Document\n{\n    %extend\n    {\n        ~Document()\n        {\n            DEBUGMSG1(\"Document\");\n            fz_document *this_doc = (fz_document *) $self;\n            fz_drop_document(gctx, this_doc);\n            DEBUGMSG2;\n        }\n        FITZEXCEPTION2(Document, !result)\n\n        %pythonprepend Document %{\n        \"\"\"Creates a document. Use 'open' as a synonym.\n\n        Notes:\n            Basic usages:\n            open() - new PDF document\n            open(filename) - string, pathlib.Path, or file object.\n            open(filename, fileype=type) - overwrite filename extension.\n            open(type, buffer) - type: extension, buffer: bytes object.\n            open(stream=buffer, filetype=type) - keyword version of previous.\n            Parameters rect, width, height, fontsize: layout reflowable\n                 document on open (e.g. EPUB). Ignored if n/a.\n        \"\"\"\n        self.is_closed = False\n        self.is_encrypted = False\n        self.isEncrypted = False\n        self.metadata    = None\n        self.FontInfos   = []\n        self.Graftmaps   = {}\n        self.ShownPages  = {}\n        self.InsertedImages  = {}\n        self._page_refs  = weakref.WeakValueDictionary()\n\n        if not filename or type(filename) is str:\n            pass\n        elif hasattr(filename, \"absolute\"):\n            filename = str(filename)\n        elif hasattr(filename, \"name\"):\n            filename = filename.name\n        else:\n            msg = \"bad filename\"\n            raise TypeError(msg)\n\n        if stream != None:\n            if type(stream) is bytes:\n                self.stream = stream\n            elif type(stream) is bytearray:\n                self.stream = bytes(stream)\n            elif type(stream) is io.BytesIO:\n                self.stream = stream.getvalue()\n            else:\n                msg = \"bad type: 'stream'\"\n                raise TypeError(msg)\n            stream = self.stream\n            if not (filename or filetype):\n                filename = \"pdf\"\n        else:\n            self.stream = None\n\n        if filename and self.stream == None:\n            self.name = filename\n            from_file = True\n        else:\n            from_file = False\n            self.name = \"\"\n\n        if from_file:\n            if not os.path.exists(filename):\n                msg = f\"no such file: '{filename}'\"\n                raise FileNotFoundError(msg)\n            elif not os.path.isfile(filename):\n                msg = f\"'{filename}' is no file\"\n                raise FileDataError(msg)\n        if from_file and os.path.getsize(filename) == 0 or type(self.stream) is bytes and len(self.stream) == 0:\n            msg = \"cannot open empty document\"\n            raise EmptyFileError(msg)\n        %}\n        %pythonappend Document %{\n            if self.thisown:\n                self._graft_id = TOOLS.gen_id()\n                if self.needs_pass is True:\n                    self.is_encrypted = True\n                    self.isEncrypted = True\n                else: # we won't init until doc is decrypted\n                    self.init_doc()\n                # the following hack detects invalid/empty SVG files, which else may lead\n                # to interpreter crashes\n                if filename and filename.lower().endswith(\"svg\") or filetype and \"svg\" in filetype.lower():\n                    try:\n                        _ = self.convert_to_pdf()  # this seems to always work\n                    except:\n                        raise FileDataError(\"cannot open broken document\") from None\n        %}\n\n        Document(const char *filename=NULL, PyObject *stream=NULL,\n                      const char *filetype=NULL, PyObject *rect=NULL,\n                      float width=0, float height=0,\n                      float fontsize=11)\n        {\n            int old_msg_option = JM_mupdf_show_errors;\n            JM_mupdf_show_errors = 0;\n            fz_document *doc = NULL;\n            const fz_document_handler *handler;\n            char *c = NULL;\n            char *magic = NULL;\n            size_t len = 0;\n            fz_stream *data = NULL;\n            float w = width, h = height;\n            fz_rect r = JM_rect_from_py(rect);\n            if (!fz_is_infinite_rect(r)) {\n                w = r.x1 - r.x0;\n                h = r.y1 - r.y0;\n            }\n\n            fz_try(gctx) {\n                if (stream != Py_None) { // stream given, **MUST** be bytes!\n                    c = PyBytes_AS_STRING(stream); // just a pointer, no new obj\n                    len = (size_t) PyBytes_Size(stream);\n                    data = fz_open_memory(gctx, (const unsigned char *) c, len);\n                    magic = (char *)filename;\n                    if (!magic) magic = (char *)filetype;\n                    handler = fz_recognize_document(gctx, magic);\n                    if (!handler) {\n                        RAISEPY(gctx, MSG_BAD_FILETYPE, PyExc_ValueError);\n                    }\n                    doc = fz_open_document_with_stream(gctx, magic, data);\n                } else {\n                    if (filename && strlen(filename)) {\n                        if (!filetype || strlen(filetype) == 0) {\n                            doc = fz_open_document(gctx, filename);\n                        } else {\n                            handler = fz_recognize_document(gctx, filetype);\n                            if (!handler) {\n                                RAISEPY(gctx, MSG_BAD_FILETYPE, PyExc_ValueError);\n                            }\n                            #if FZ_VERSION_MINOR >= 24\n                            if (handler->open)\n                            {\n                                fz_stream* filename_stream = fz_open_file(gctx, filename);\n                                fz_try(gctx)\n                                {\n                                    doc = handler->open(gctx, filename_stream, NULL, NULL);\n                                }\n                                fz_always(gctx)\n                                {\n                                    fz_drop_stream(gctx, filename_stream);\n                                }\n                                fz_catch(gctx)\n                                {\n                                    fz_rethrow(gctx);\n                                }\n                            }\n                            #else\n                            if (handler->open) {\n                                doc = handler->open(gctx, filename);\n                            } else if (handler->open_with_stream) {\n                                data = fz_open_file(gctx, filename);\n                                doc = handler->open_with_stream(gctx, data);\n                            }\n                            #endif\n                        }\n                    } else {\n                        pdf_document *pdf = pdf_create_document(gctx);\n                        doc = (fz_document *) pdf;\n                    }\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_stream(gctx, data);\n            }\n            fz_catch(gctx) {\n                JM_mupdf_show_errors = old_msg_option;\n                return NULL;\n            }\n            if (w > 0 && h > 0) {\n                fz_layout_document(gctx, doc, w, h, fontsize);\n            } else if (fz_is_document_reflowable(gctx, doc)) {\n                fz_layout_document(gctx, doc, 400, 600, 11);\n            }\n            return (struct Document *) doc;\n        }\n\n\n        FITZEXCEPTION(load_page, !result)\n        %pythonprepend load_page %{\n        \"\"\"Load a page.\n\n        'page_id' is either a 0-based page number or a tuple (chapter, pno),\n        with chapter number and page number within that chapter.\n        \"\"\"\n\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if page_id is None:\n            page_id = 0\n        if page_id not in self:\n            raise ValueError(\"page not in document\")\n        if type(page_id) is int and page_id < 0:\n            np = self.page_count\n            while page_id < 0:\n                page_id += np\n        %}\n        %pythonappend load_page %{\n        val.thisown = True\n        val.parent = weakref.proxy(self)\n        self._page_refs[id(val)] = val\n        val._annot_refs = weakref.WeakValueDictionary()\n        val.number = page_id\n        %}\n        struct Page *\n        load_page(PyObject *page_id)\n        {\n            fz_page *page = NULL;\n            fz_document *doc = (fz_document *) $self;\n            int pno = 0, chapter = 0;\n            fz_try(gctx) {\n                if (PySequence_Check(page_id)) {\n                    if (JM_INT_ITEM(page_id, 0, &chapter) == 1) {\n                        RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                    }\n                    if (JM_INT_ITEM(page_id, 1, &pno) == 1) {\n                        RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                    }\n                    page = fz_load_chapter_page(gctx, doc, chapter, pno);\n                } else {\n                    pno = (int) PyLong_AsLong(page_id);\n                    if (PyErr_Occurred()) {\n                        RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                    }\n                    page = fz_load_page(gctx, doc, pno);\n                }\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            PyErr_Clear();\n            return (struct Page *) page;\n        }\n\n\n        FITZEXCEPTION(_remove_links_to, !result)\n        PyObject *_remove_links_to(PyObject *numbers)\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                remove_dest_range(gctx, pdf, numbers);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        CLOSECHECK0(_loadOutline, \"\"\"Load first outline.\"\"\")\n        struct Outline *_loadOutline()\n        {\n            fz_outline *ol = NULL;\n            fz_document *doc = (fz_document *) $self;\n            fz_try(gctx) {\n                ol = fz_load_outline(gctx, doc);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Outline *) ol;\n        }\n\n        void _dropOutline(struct Outline *ol) {\n            DEBUGMSG1(\"Outline\");\n            fz_outline *this_ol = (fz_outline *) ol;\n            fz_drop_outline(gctx, this_ol);\n            DEBUGMSG2;\n        }\n\n        FITZEXCEPTION(_insert_font, !result)\n        CLOSECHECK0(_insert_font, \"\"\"Utility: insert font from file or binary.\"\"\")\n        PyObject *\n        _insert_font(char *fontfile=NULL, PyObject *fontbuffer=NULL)\n        {\n            PyObject *value=NULL;\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *)$self);\n\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                if (!fontfile && !EXISTS(fontbuffer)) {\n                    RAISEPY(gctx, MSG_FILE_OR_BUFFER, PyExc_ValueError);\n                }\n                value = JM_insert_font(gctx, pdf, NULL, fontfile, fontbuffer,\n                            0, 0, 0, 0, 0, -1);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return value;\n        }\n\n\n        FITZEXCEPTION(get_outline_xrefs, !result)\n        CLOSECHECK0(get_outline_xrefs, \"\"\"Get list of outline xref numbers.\"\"\")\n        PyObject *\n        get_outline_xrefs()\n        {\n            PyObject *xrefs = PyList_New(0);\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *)$self);\n            if (!pdf) {\n                return xrefs;\n            }\n            fz_try(gctx) {\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n                if (!root) goto finished;\n                pdf_obj *olroot = pdf_dict_get(gctx, root, PDF_NAME(Outlines));\n                if (!olroot) goto finished;\n                pdf_obj *first = pdf_dict_get(gctx, olroot, PDF_NAME(First));\n                if (!first) goto finished;\n                xrefs = JM_outline_xrefs(gctx, first, xrefs);\n                finished:;\n            }\n            fz_catch(gctx) {\n                Py_DECREF(xrefs);\n                return NULL;\n            }\n            return xrefs;\n        }\n\n\n        FITZEXCEPTION(xref_get_keys, !result)\n        CLOSECHECK0(xref_get_keys, \"\"\"Get the keys of PDF dict object at 'xref'. Use -1 for the PDF trailer.\"\"\")\n        PyObject *\n        xref_get_keys(int xref)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *)$self);\n            pdf_obj *obj=NULL;\n            PyObject *rc = NULL;\n            int i, n;\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1) && xref != -1) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                if (xref > 0) {\n                    obj = pdf_load_object(gctx, pdf, xref);\n                } else {\n                    obj = pdf_trailer(gctx, pdf);\n                }\n                n = pdf_dict_len(gctx, obj);\n                rc = PyTuple_New(n);\n                if (!n) goto finished;\n                for (i = 0; i < n; i++) {\n                    const char *key = pdf_to_name(gctx, pdf_dict_get_key(gctx, obj, i));\n                    PyTuple_SET_ITEM(rc, i, Py_BuildValue(\"s\", key));\n                }\n                finished:;\n            }\n            fz_always(gctx) {\n                if (xref > 0) {\n                    pdf_drop_obj(gctx, obj);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(xref_get_key, !result)\n        CLOSECHECK0(xref_get_key, \"\"\"Get PDF dict key value of object at 'xref'.\"\"\")\n        PyObject *\n        xref_get_key(int xref, const char *key)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *)$self);\n            pdf_obj *obj=NULL, *subobj=NULL;\n            PyObject *rc = NULL;\n            fz_buffer *res = NULL;\n            PyObject *text = NULL;\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1) && xref != -1) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                if (xref > 0) {\n                    obj = pdf_load_object(gctx, pdf, xref);\n                } else {\n                    obj = pdf_trailer(gctx, pdf);\n                }\n                if (!obj) {\n                    goto not_found;\n                }\n                subobj = pdf_dict_getp(gctx, obj, key);\n                if (!subobj) {\n                    goto not_found;\n                }\n                char *type;\n                if (pdf_is_indirect(gctx, subobj)) {\n                    type = \"xref\";\n                    text = PyUnicode_FromFormat(\"%i 0 R\", pdf_to_num(gctx, subobj));\n                } else if (pdf_is_array(gctx, subobj)) {\n                    type = \"array\";\n                } else if (pdf_is_dict(gctx, subobj)) {\n                    type = \"dict\";\n                } else if (pdf_is_int(gctx, subobj)) {\n                    type = \"int\";\n                    text = PyUnicode_FromFormat(\"%i\", pdf_to_int(gctx, subobj));\n                } else if (pdf_is_real(gctx, subobj)) {\n                    type = \"float\";\n                } else if (pdf_is_null(gctx, subobj)) {\n                    type = \"null\";\n                    text = PyUnicode_FromString(\"null\");\n                } else if (pdf_is_bool(gctx, subobj)) {\n                    type = \"bool\";\n                    if (pdf_to_bool(gctx, subobj)) {\n                        text = PyUnicode_FromString(\"true\");\n                    } else {\n                        text = PyUnicode_FromString(\"false\");\n                    }\n                } else if (pdf_is_name(gctx, subobj)) {\n                    type = \"name\";\n                    text = PyUnicode_FromFormat(\"/%s\", pdf_to_name(gctx, subobj));\n                } else if (pdf_is_string(gctx, subobj)) {\n                    type = \"string\";\n                    text = JM_UnicodeFromStr(pdf_to_text_string(gctx, subobj));\n                } else {\n                    type = \"unknown\";\n                }\n                if (!text) {\n                    res = JM_object_to_buffer(gctx, subobj, 1, 0);\n                    text = JM_UnicodeFromBuffer(gctx, res);\n                }\n                rc = Py_BuildValue(\"sO\", type, text);\n                Py_DECREF(text);\n                goto finished;\n\n                not_found:;\n                rc = Py_BuildValue(\"ss\", \"null\", \"null\");\n                finished:;\n            }\n            fz_always(gctx) {\n                if (xref > 0) {\n                    pdf_drop_obj(gctx, obj);\n                }\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(xref_set_key, !result)\n        %pythonprepend xref_set_key %{\n        \"\"\"Set the value of a PDF dictionary key.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if not key or not isinstance(key, str) or INVALID_NAME_CHARS.intersection(key) not in (set(), {\"/\"}):\n            raise ValueError(\"bad 'key'\")\n        if not isinstance(value, str) or not value or value[0] == \"/\" and INVALID_NAME_CHARS.intersection(value[1:]) != set():\n            raise ValueError(\"bad 'value'\")\n        %}\n        PyObject *\n        xref_set_key(int xref, const char *key, char *value)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *)$self);\n            pdf_obj *obj = NULL, *new_obj = NULL;\n            int i, n;\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                if (!key || strlen(key) == 0) {\n                    RAISEPY(gctx, \"bad 'key'\", PyExc_ValueError);\n                }\n                if (!value || strlen(value) == 0) {\n                    RAISEPY(gctx, \"bad 'value'\", PyExc_ValueError);\n                }\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1) && xref != -1) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                if (xref != -1) {\n                    obj = pdf_load_object(gctx, pdf, xref);\n                } else {\n                    obj = pdf_trailer(gctx, pdf);\n                }\n                // if val==\"null\" and no path hierarchy, delete \"key\" from object\n                // chr(47) = \"/\"\n                if (strcmp(value, \"null\") == 0 && strchr(key, 47) == NULL) {\n                    pdf_dict_dels(gctx, obj, key);\n                    goto finished;\n                }\n                new_obj = JM_set_object_value(gctx, obj, key, value);\n                if (!new_obj) {\n                    goto finished;  // did not work: skip update\n                }\n                if (xref != -1) {\n                    pdf_drop_obj(gctx, obj);\n                    obj = NULL;\n                    pdf_update_object(gctx, pdf, xref, new_obj);\n                } else {\n                    n = pdf_dict_len(gctx, new_obj);\n                    for (i = 0; i < n; i++) {\n                        pdf_dict_put(gctx, obj, pdf_dict_get_key(gctx, new_obj, i), pdf_dict_get_val(gctx, new_obj, i));\n                    }\n                }\n                finished:;\n            }\n            fz_always(gctx) {\n                if (xref != -1) {\n                    pdf_drop_obj(gctx, obj);\n                }\n                pdf_drop_obj(gctx, new_obj);\n                PyErr_Clear();\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(_extend_toc_items, !result)\n        CLOSECHECK0(_extend_toc_items, \"\"\"Add color info to all items of an extended TOC list.\"\"\")\n        PyObject *\n        _extend_toc_items(PyObject *items)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *)$self);\n            pdf_obj *bm, *col, *obj;\n            int count, flags;\n            PyObject *item=NULL, *itemdict=NULL, *xrefs, *bold, *italic, *collapse, *zoom;\n            zoom = PyUnicode_FromString(\"zoom\");\n            bold = PyUnicode_FromString(\"bold\");\n            italic = PyUnicode_FromString(\"italic\");\n            collapse = PyUnicode_FromString(\"collapse\");\n            fz_try(gctx) {\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n                if (!root) goto finished;\n                pdf_obj *olroot = pdf_dict_get(gctx, root, PDF_NAME(Outlines));\n                if (!olroot) goto finished;\n                pdf_obj *first = pdf_dict_get(gctx, olroot, PDF_NAME(First));\n                if (!first) goto finished;\n                xrefs = PyList_New(0);  // pre-allocate an empty list\n                xrefs = JM_outline_xrefs(gctx, first, xrefs);\n                Py_ssize_t i, n = PySequence_Size(xrefs), m = PySequence_Size(items);\n                if (!n) goto finished;\n                if (n != m) {\n                    RAISEPY(gctx, \"internal error finding outline xrefs\", PyExc_IndexError);\n                }\n                int xref;\n\n                // update all TOC item dictionaries\n                for (i = 0; i < n; i++) {\n                    JM_INT_ITEM(xrefs, i, &xref);\n                    item = PySequence_ITEM(items, i);\n                    itemdict = PySequence_ITEM(item, 3);\n                    if (!itemdict || !PyDict_Check(itemdict)) {\n                        RAISEPY(gctx, \"need non-simple TOC format\", PyExc_ValueError);\n                    }\n                    PyDict_SetItem(itemdict, dictkey_xref, PySequence_ITEM(xrefs, i));\n                    bm = pdf_load_object(gctx, pdf, xref);\n                    flags = pdf_to_int(gctx, (pdf_dict_get(gctx, bm, PDF_NAME(F))));\n                    if (flags == 1) {\n                        PyDict_SetItem(itemdict, italic, Py_True);\n                    } else if (flags == 2) {\n                        PyDict_SetItem(itemdict, bold, Py_True);\n                    } else if (flags == 3) {\n                        PyDict_SetItem(itemdict, italic, Py_True);\n                        PyDict_SetItem(itemdict, bold, Py_True);\n                    }\n                    count = pdf_to_int(gctx, (pdf_dict_get(gctx, bm, PDF_NAME(Count))));\n                    if (count < 0) {\n                        PyDict_SetItem(itemdict, collapse, Py_True);\n                    } else if (count > 0) {\n                        PyDict_SetItem(itemdict, collapse, Py_False);\n                    }\n                    col = pdf_dict_get(gctx, bm, PDF_NAME(C));\n                    if (pdf_is_array(gctx, col) && pdf_array_len(gctx, col) == 3) {\n                        PyObject *color = PyTuple_New(3);\n                        PyTuple_SET_ITEM(color, 0, Py_BuildValue(\"f\", pdf_to_real(gctx, pdf_array_get(gctx, col, 0))));\n                        PyTuple_SET_ITEM(color, 1, Py_BuildValue(\"f\", pdf_to_real(gctx, pdf_array_get(gctx, col, 1))));\n                        PyTuple_SET_ITEM(color, 2, Py_BuildValue(\"f\", pdf_to_real(gctx, pdf_array_get(gctx, col, 2))));\n                        DICT_SETITEM_DROP(itemdict, dictkey_color, color);\n                    }\n                    float z=0;\n                    obj = pdf_dict_get(gctx, bm, PDF_NAME(Dest));\n                    if (!obj || !pdf_is_array(gctx, obj)) {\n                        obj = pdf_dict_getl(gctx, bm, PDF_NAME(A), PDF_NAME(D), NULL);\n                    }\n                    if (pdf_is_array(gctx, obj) && pdf_array_len(gctx, obj) == 5) {\n                        z = pdf_to_real(gctx, pdf_array_get(gctx, obj, 4));\n                    }\n                    DICT_SETITEM_DROP(itemdict, zoom, Py_BuildValue(\"f\", z));\n                    PyList_SetItem(item, 3, itemdict);\n                    PyList_SetItem(items, i, item);\n                    pdf_drop_obj(gctx, bm);\n                    bm = NULL;\n                }\n                finished:;\n            }\n            fz_always(gctx) {\n                Py_CLEAR(xrefs);\n                Py_CLEAR(bold);\n                Py_CLEAR(italic);\n                Py_CLEAR(collapse);\n                Py_CLEAR(zoom);\n                pdf_drop_obj(gctx, bm);\n                PyErr_Clear();\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // EmbeddedFiles utility functions\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_embfile_names, !result)\n        CLOSECHECK0(_embfile_names, \"\"\"Get list of embedded file names.\"\"\")\n        PyObject *_embfile_names(PyObject *namelist)\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_specifics(gctx, doc);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                PyObject *val;\n                pdf_obj *names = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                      PDF_NAME(Root),\n                                      PDF_NAME(Names),\n                                      PDF_NAME(EmbeddedFiles),\n                                      PDF_NAME(Names),\n                                      NULL);\n                if (pdf_is_array(gctx, names)) {\n                    int i, n = pdf_array_len(gctx, names);\n                    for (i=0; i < n; i+=2) {\n                        val = JM_EscapeStrFromStr(pdf_to_text_string(gctx,\n                                         pdf_array_get(gctx, names, i)));\n                        LIST_APPEND_DROP(namelist, val);\n                    }\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION(_embfile_del, !result)\n        PyObject *_embfile_del(int idx)\n        {\n            fz_try(gctx) {\n                fz_document *doc = (fz_document *) $self;\n                pdf_document *pdf = pdf_document_from_fz_document(gctx, doc);\n                pdf_obj *names = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                      PDF_NAME(Root),\n                                      PDF_NAME(Names),\n                                      PDF_NAME(EmbeddedFiles),\n                                      PDF_NAME(Names),\n                                      NULL);\n                pdf_array_delete(gctx, names, idx + 1);\n                pdf_array_delete(gctx, names, idx);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION(_embfile_info, !result)\n        PyObject *_embfile_info(int idx, PyObject *infodict)\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, doc);\n            char *name;\n            int xref = 0, ci_xref=0;\n            fz_try(gctx) {\n                pdf_obj *names = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                      PDF_NAME(Root),\n                                      PDF_NAME(Names),\n                                      PDF_NAME(EmbeddedFiles),\n                                      PDF_NAME(Names),\n                                      NULL);\n\n                pdf_obj *o = pdf_array_get(gctx, names, 2*idx+1);\n                pdf_obj *ci = pdf_dict_get(gctx, o, PDF_NAME(CI));\n                if (ci) {\n                    ci_xref = pdf_to_num(gctx, ci);\n                }\n                DICT_SETITEMSTR_DROP(infodict, \"collection\", Py_BuildValue(\"i\", ci_xref));\n                name = (char *) pdf_to_text_string(gctx,\n                                          pdf_dict_get(gctx, o, PDF_NAME(F)));\n                DICT_SETITEM_DROP(infodict, dictkey_filename, JM_EscapeStrFromStr(name));\n\n                name = (char *) pdf_to_text_string(gctx,\n                                    pdf_dict_get(gctx, o, PDF_NAME(UF)));\n                DICT_SETITEM_DROP(infodict, dictkey_ufilename, JM_EscapeStrFromStr(name));\n\n                name = (char *) pdf_to_text_string(gctx,\n                                    pdf_dict_get(gctx, o, PDF_NAME(Desc)));\n                DICT_SETITEM_DROP(infodict, dictkey_desc, JM_UnicodeFromStr(name));\n\n                int len = -1, DL = -1;\n                pdf_obj *fileentry = pdf_dict_getl(gctx, o, PDF_NAME(EF), PDF_NAME(F), NULL);\n                xref = pdf_to_num(gctx, fileentry);\n                o = pdf_dict_get(gctx, fileentry, PDF_NAME(Length));\n                if (o) len = pdf_to_int(gctx, o);\n\n                o = pdf_dict_get(gctx, fileentry, PDF_NAME(DL));\n                if (o) {\n                    DL = pdf_to_int(gctx, o);\n                } else {\n                    o = pdf_dict_getl(gctx, fileentry, PDF_NAME(Params),\n                                   PDF_NAME(Size), NULL);\n                    if (o) DL = pdf_to_int(gctx, o);\n                }\n                DICT_SETITEM_DROP(infodict, dictkey_size, Py_BuildValue(\"i\", DL));\n                DICT_SETITEM_DROP(infodict, dictkey_length, Py_BuildValue(\"i\", len));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xref);\n        }\n\n        FITZEXCEPTION(_embfile_upd, !result)\n        PyObject *_embfile_upd(int idx, PyObject *buffer = NULL, char *filename = NULL, char *ufilename = NULL, char *desc = NULL)\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, doc);\n            fz_buffer *res = NULL;\n            fz_var(res);\n            int xref = 0;\n            fz_try(gctx) {\n                pdf_obj *names = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                      PDF_NAME(Root),\n                                      PDF_NAME(Names),\n                                      PDF_NAME(EmbeddedFiles),\n                                      PDF_NAME(Names),\n                                      NULL);\n\n                pdf_obj *entry = pdf_array_get(gctx, names, 2*idx+1);\n\n                pdf_obj *filespec = pdf_dict_getl(gctx, entry, PDF_NAME(EF),\n                                                  PDF_NAME(F), NULL);\n                if (!filespec) {\n                    RAISEPY(gctx, \"bad PDF: no /EF object\", JM_Exc_FileDataError);\n                }\n                res = JM_BufferFromBytes(gctx, buffer);\n                if (EXISTS(buffer) && !res) {\n                    RAISEPY(gctx, MSG_BAD_BUFFER, PyExc_TypeError);\n                }\n                if (res && buffer != Py_None)\n                {\n                    JM_update_stream(gctx, pdf, filespec, res, 1);\n                    // adjust /DL and /Size parameters\n                    int64_t len = (int64_t) fz_buffer_storage(gctx, res, NULL);\n                    pdf_obj *l = pdf_new_int(gctx, len);\n                    pdf_dict_put(gctx, filespec, PDF_NAME(DL), l);\n                    pdf_dict_putl(gctx, filespec, l, PDF_NAME(Params), PDF_NAME(Size), NULL);\n                }\n                xref = pdf_to_num(gctx, filespec);\n                if (filename)\n                    pdf_dict_put_text_string(gctx, entry, PDF_NAME(F), filename);\n\n                if (ufilename)\n                    pdf_dict_put_text_string(gctx, entry, PDF_NAME(UF), ufilename);\n\n                if (desc)\n                    pdf_dict_put_text_string(gctx, entry, PDF_NAME(Desc), desc);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx)\n                return NULL;\n            \n            return Py_BuildValue(\"i\", xref);\n        }\n\n        FITZEXCEPTION(_embeddedFileGet, !result)\n        PyObject *_embeddedFileGet(int idx)\n        {\n            fz_document *doc = (fz_document *) $self;\n            PyObject *cont = NULL;\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, doc);\n            fz_buffer *buf = NULL;\n            fz_var(buf);\n            fz_try(gctx) {\n                pdf_obj *names = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                      PDF_NAME(Root),\n                                      PDF_NAME(Names),\n                                      PDF_NAME(EmbeddedFiles),\n                                      PDF_NAME(Names),\n                                      NULL);\n\n                pdf_obj *entry = pdf_array_get(gctx, names, 2*idx+1);\n                pdf_obj *filespec = pdf_dict_getl(gctx, entry, PDF_NAME(EF),\n                                                  PDF_NAME(F), NULL);\n                buf = pdf_load_stream(gctx, filespec);\n                cont = JM_BinFromBuffer(gctx, buf);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return cont;\n        }\n\n        FITZEXCEPTION(_embfile_add, !result)\n        PyObject *_embfile_add(const char *name, PyObject *buffer, char *filename=NULL, char *ufilename=NULL, char *desc=NULL)\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, doc);\n            fz_buffer *data = NULL;\n            fz_var(data);\n            pdf_obj *names = NULL;\n            int xref = 0; // xref of file entry\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                data = JM_BufferFromBytes(gctx, buffer);\n                if (!data) {\n                    RAISEPY(gctx, MSG_BAD_BUFFER, PyExc_TypeError);\n                }\n\n                names = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                      PDF_NAME(Root),\n                                      PDF_NAME(Names),\n                                      PDF_NAME(EmbeddedFiles),\n                                      PDF_NAME(Names),\n                                      NULL);\n                if (!pdf_is_array(gctx, names)) {\n                    pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf),\n                                                 PDF_NAME(Root));\n                    names = pdf_new_array(gctx, pdf, 6);  // an even number!\n                    pdf_dict_putl_drop(gctx, root, names,\n                                      PDF_NAME(Names),\n                                      PDF_NAME(EmbeddedFiles),\n                                      PDF_NAME(Names),\n                                      NULL);\n                }\n\n                pdf_obj *fileentry = JM_embed_file(gctx, pdf, data,\n                                                   filename,\n                                                   ufilename,\n                                                   desc, 1);\n                xref = pdf_to_num(gctx, pdf_dict_getl(gctx, fileentry,\n                                    PDF_NAME(EF), PDF_NAME(F), NULL));\n                pdf_array_push_drop(gctx, names, pdf_new_text_string(gctx, name));\n                pdf_array_push_drop(gctx, names, fileentry);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, data);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            return Py_BuildValue(\"i\", xref);\n        }\n\n\n        %pythoncode %{\n        def embfile_names(self) -> list:\n            \"\"\"Get list of names of EmbeddedFiles.\"\"\"\n            filenames = []\n            self._embfile_names(filenames)\n            return filenames\n\n        def _embeddedFileIndex(self, item: typing.Union[int, str]) -> int:\n            filenames = self.embfile_names()\n            msg = \"'%s' not in EmbeddedFiles array.\" % str(item)\n            if item in filenames:\n                idx = filenames.index(item)\n            elif item in range(len(filenames)):\n                idx = item\n            else:\n                raise ValueError(msg)\n            return idx\n\n        def embfile_count(self) -> int:\n            \"\"\"Get number of EmbeddedFiles.\"\"\"\n            return len(self.embfile_names())\n\n        def embfile_del(self, item: typing.Union[int, str]):\n            \"\"\"Delete an entry from EmbeddedFiles.\n\n            Notes:\n                The argument must be name or index of an EmbeddedFiles item.\n                Physical deletion of data will happen on save to a new\n                file with appropriate garbage option.\n            Args:\n                item: name or number of item.\n            Returns:\n                None\n            \"\"\"\n            idx = self._embeddedFileIndex(item)\n            return self._embfile_del(idx)\n\n        def embfile_info(self, item: typing.Union[int, str]) -> dict:\n            \"\"\"Get information of an item in the EmbeddedFiles array.\n\n            Args:\n                item: number or name of item.\n            Returns:\n                Information dictionary.\n            \"\"\"\n            idx = self._embeddedFileIndex(item)\n            infodict = {\"name\": self.embfile_names()[idx]}\n            xref = self._embfile_info(idx, infodict)\n            t, date = self.xref_get_key(xref, \"Params/CreationDate\")\n            if t != \"null\":\n                infodict[\"creationDate\"] = date\n            t, date = self.xref_get_key(xref, \"Params/ModDate\")\n            if t != \"null\":\n                infodict[\"modDate\"] = date\n            t, md5 = self.xref_get_key(xref, \"Params/CheckSum\")\n            if t != \"null\":\n                infodict[\"checksum\"] = binascii.hexlify(md5.encode()).decode()\n            return infodict\n\n        def embfile_get(self, item: typing.Union[int, str]) -> bytes:\n            \"\"\"Get the content of an item in the EmbeddedFiles array.\n\n            Args:\n                item: number or name of item.\n            Returns:\n                (bytes) The file content.\n            \"\"\"\n            idx = self._embeddedFileIndex(item)\n            return self._embeddedFileGet(idx)\n\n        def embfile_upd(self, item: typing.Union[int, str],\n                                 buffer: OptBytes =None,\n                                 filename: OptStr =None,\n                                 ufilename: OptStr =None,\n                                 desc: OptStr =None,) -> None:\n            \"\"\"Change an item of the EmbeddedFiles array.\n\n            Notes:\n                Only provided parameters are changed. If all are omitted,\n                the method is a no-op.\n            Args:\n                item: number or name of item.\n                buffer: (binary data) the new file content.\n                filename: (str) the new file name.\n                ufilename: (unicode) the new filen ame.\n                desc: (str) the new description.\n            \"\"\"\n            idx = self._embeddedFileIndex(item)\n            xref = self._embfile_upd(idx, buffer=buffer,\n                                         filename=filename,\n                                         ufilename=ufilename,\n                                         desc=desc)\n            date = get_pdf_now()\n            self.xref_set_key(xref, \"Params/ModDate\", get_pdf_str(date))\n            return xref\n\n        def embfile_add(self, name: str, buffer: ByteString,\n                                  filename: OptStr =None,\n                                  ufilename: OptStr =None,\n                                  desc: OptStr =None,) -> None:\n            \"\"\"Add an item to the EmbeddedFiles array.\n\n            Args:\n                name: name of the new item, must not already exist.\n                buffer: (binary data) the file content.\n                filename: (str) the file name, default: the name\n                ufilename: (unicode) the file name, default: filename\n                desc: (str) the description.\n            \"\"\"\n            filenames = self.embfile_names()\n            msg = \"Name '%s' already exists.\" % str(name)\n            if name in filenames:\n                raise ValueError(msg)\n\n            if filename is None:\n                filename = name\n            if ufilename is None:\n                ufilename = unicode(filename, \"utf8\") if str is bytes else filename\n            if desc is None:\n                desc = name\n            xref = self._embfile_add(name, buffer=buffer,\n                                         filename=filename,\n                                         ufilename=ufilename,\n                                         desc=desc)\n            date = get_pdf_now()\n            self.xref_set_key(xref, \"Type\", \"/EmbeddedFile\")\n            self.xref_set_key(xref, \"Params/CreationDate\", get_pdf_str(date))\n            self.xref_set_key(xref, \"Params/ModDate\", get_pdf_str(date))\n            return xref\n        %}\n\n        FITZEXCEPTION(convert_to_pdf, !result)\n        %pythonprepend convert_to_pdf %{\n        \"\"\"Convert document to a PDF, selecting page range and optional rotation. Output bytes object.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        %}\n        PyObject *convert_to_pdf(int from_page=0, int to_page=-1, int rotate=0)\n        {\n            PyObject *doc = NULL;\n            fz_document *fz_doc = (fz_document *) $self;\n            fz_try(gctx) {\n                int fp = from_page, tp = to_page, srcCount = fz_count_pages(gctx, fz_doc);\n                if (fp < 0) fp = 0;\n                if (fp > srcCount - 1) fp = srcCount - 1;\n                if (tp < 0) tp = srcCount - 1;\n                if (tp > srcCount - 1) tp = srcCount - 1;\n                Py_ssize_t len0 = PyList_Size(JM_mupdf_warnings_store);\n                doc = JM_convert_to_pdf(gctx, fz_doc, fp, tp, rotate);\n                Py_ssize_t len1 = PyList_Size(JM_mupdf_warnings_store);\n                Py_ssize_t i = len0;\n                while (i < len1) {\n                    PySys_WriteStderr(\"%s\\n\", JM_StrAsChar(PyList_GetItem(JM_mupdf_warnings_store, i)));\n                    i++;\n                } \n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            if (doc) {\n                return doc;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(page_count, !result)\n        CLOSECHECK0(page_count, \"\"\"Number of pages.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *page_count()\n        {\n            PyObject *ret;\n            fz_try(gctx) {\n                ret = PyLong_FromLong((long) fz_count_pages(gctx, (fz_document *) $self));\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            return ret;\n        }\n\n        FITZEXCEPTION(chapter_count, !result)\n        CLOSECHECK0(chapter_count, \"\"\"Number of chapters.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *chapter_count()\n        {\n            PyObject *ret;\n            fz_try(gctx) {\n                ret = PyLong_FromLong((long) fz_count_chapters(gctx, (fz_document *) $self));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return ret;\n        }\n\n        FITZEXCEPTION(last_location, !result)\n        CLOSECHECK0(last_location, \"\"\"Id (chapter, page) of last page.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *last_location()\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            fz_location last_loc;\n            fz_try(gctx) {\n                last_loc = fz_last_page(gctx, this_doc);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"ii\", last_loc.chapter, last_loc.page);\n        }\n\n\n        FITZEXCEPTION(chapter_page_count, !result)\n        CLOSECHECK0(chapter_page_count, \"\"\"Page count of chapter.\"\"\")\n        PyObject *chapter_page_count(int chapter)\n        {\n            long pages = 0;\n            fz_try(gctx) {\n                int chapters = fz_count_chapters(gctx, (fz_document *) $self);\n                if (chapter < 0 || chapter >= chapters) {\n                    RAISEPY(gctx, \"bad chapter number\", PyExc_ValueError);\n                }\n                pages = (long) fz_count_chapter_pages(gctx, (fz_document *) $self, chapter);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return PyLong_FromLong(pages);\n        }\n\n        FITZEXCEPTION(prev_location, !result)\n        %pythonprepend prev_location %{\n        \"\"\"Get (chapter, page) of previous page.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if type(page_id) is int:\n            page_id = (0, page_id)\n        if page_id not in self:\n            raise ValueError(\"page id not in document\")\n        if page_id  == (0, 0):\n            return ()\n        %}\n        PyObject *prev_location(PyObject *page_id)\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            fz_location prev_loc, loc;\n            PyObject *val;\n            int pno;\n            fz_try(gctx) {\n                val = PySequence_GetItem(page_id, 0);\n                if (!val) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                int chapter = (int) PyLong_AsLong(val);\n                Py_DECREF(val);\n                if (PyErr_Occurred()) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n\n                val = PySequence_GetItem(page_id, 1);\n                if (!val) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                pno = (int) PyLong_AsLong(val);\n                Py_DECREF(val);\n                if (PyErr_Occurred()) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                loc = fz_make_location(chapter, pno);\n                prev_loc = fz_previous_page(gctx, this_doc, loc);\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            return Py_BuildValue(\"ii\", prev_loc.chapter, prev_loc.page);\n        }\n\n\n        FITZEXCEPTION(next_location, !result)\n        %pythonprepend next_location %{\n        \"\"\"Get (chapter, page) of next page.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if type(page_id) is int:\n            page_id = (0, page_id)\n        if page_id not in self:\n            raise ValueError(\"page id not in document\")\n        if tuple(page_id)  == self.last_location:\n            return ()\n        %}\n        PyObject *next_location(PyObject *page_id)\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            fz_location next_loc, loc;\n            PyObject *val;\n            int pno;\n            fz_try(gctx) {\n                val = PySequence_GetItem(page_id, 0);\n                if (!val) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                int chapter = (int) PyLong_AsLong(val);\n                Py_DECREF(val);\n                if (PyErr_Occurred()) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n\n                val = PySequence_GetItem(page_id, 1);\n                if (!val) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                pno = (int) PyLong_AsLong(val);\n                Py_DECREF(val);\n                if (PyErr_Occurred()) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                loc = fz_make_location(chapter, pno);\n                next_loc = fz_next_page(gctx, this_doc, loc);\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            return Py_BuildValue(\"ii\", next_loc.chapter, next_loc.page);\n        }\n\n\n        FITZEXCEPTION(location_from_page_number, !result)\n        CLOSECHECK0(location_from_page_number, \"\"\"Convert pno to (chapter, page).\"\"\")\n        PyObject *location_from_page_number(int pno)\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            fz_location loc = fz_make_location(-1, -1);\n            int page_count = fz_count_pages(gctx, this_doc);\n            while (pno < 0) pno += page_count;\n            fz_try(gctx) {\n                if (pno >= page_count) {\n                    RAISEPY(gctx, MSG_BAD_PAGENO, PyExc_ValueError);\n                }\n                loc = fz_location_from_page_number(gctx, this_doc, pno);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"ii\", loc.chapter, loc.page);\n        }\n\n        FITZEXCEPTION(page_number_from_location, !result)\n        %pythonprepend page_number_from_location%{\n        \"\"\"Convert (chapter, pno) to page number.\"\"\"\n        if type(page_id) is int:\n            np = self.page_count\n            while page_id < 0:\n                page_id += np\n            page_id = (0, page_id)\n        if page_id not in self:\n            raise ValueError(\"page id not in document\")\n        %}\n        PyObject *page_number_from_location(PyObject *page_id)\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            fz_location loc;\n            long page_n = -1;\n            PyObject *val;\n            int pno;\n            fz_try(gctx) {\n                val = PySequence_GetItem(page_id, 0);\n                if (!val) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                int chapter = (int) PyLong_AsLong(val);\n                Py_DECREF(val);\n                if (PyErr_Occurred()) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n\n                val = PySequence_GetItem(page_id, 1);\n                if (!val) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n                pno = (int) PyLong_AsLong(val);\n                Py_DECREF(val);\n                if (PyErr_Occurred()) {\n                    RAISEPY(gctx, MSG_BAD_PAGEID, PyExc_ValueError);\n                }\n\n                loc = fz_make_location(chapter, pno);\n                page_n = (long) fz_page_number_from_location(gctx, this_doc, loc);\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            return PyLong_FromLong(page_n);\n        }\n\n        FITZEXCEPTION(_getMetadata, !result)\n        CLOSECHECK0(_getMetadata, \"\"\"Get metadata.\"\"\")\n        PyObject *\n        _getMetadata(const char *key)\n        {\n            PyObject *res = NULL;\n            fz_document *doc = (fz_document *) $self;\n            int vsize;\n            char *value;\n            fz_try(gctx) {\n                vsize = fz_lookup_metadata(gctx, doc, key, NULL, 0)+1;\n                if(vsize > 1) {\n                    value = JM_Alloc(char, vsize);\n                    fz_lookup_metadata(gctx, doc, key, value, vsize);\n                    res = JM_UnicodeFromStr(value);\n                    JM_Free(value);\n                } else {\n                    res = EMPTY_STRING;\n                }\n            }\n            fz_always(gctx) {\n                PyErr_Clear();\n            }\n            fz_catch(gctx) {\n                return EMPTY_STRING;\n            }\n            return res;\n        }\n\n        CLOSECHECK0(needs_pass, \"\"\"Indicate password required.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *needs_pass() {\n            return JM_BOOL(fz_needs_password(gctx, (fz_document *) $self));\n        }\n\n        %pythoncode%{@property%}\n        CLOSECHECK0(language, \"\"\"Document language.\"\"\")\n        PyObject *language()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_NONE;\n            fz_text_language lang = pdf_document_language(gctx, pdf);\n            char buf[8];\n            if (lang == FZ_LANG_UNSET) Py_RETURN_NONE;\n            return PyUnicode_FromString(fz_string_from_text_language(buf, lang));\n        }\n\n        FITZEXCEPTION(set_language, !result)\n        PyObject *set_language(char *language=NULL)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                fz_text_language lang;\n                if (!language)\n                    lang = FZ_LANG_UNSET;\n                else\n                    lang = fz_text_language_from_string(language);\n                pdf_set_document_language(gctx, pdf, lang);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_TRUE;\n        }\n\n\n        %pythonprepend resolve_link %{\n        \"\"\"Calculate internal link destination.\n\n        Args:\n            uri: (str) some Link.uri\n            chapters: (bool) whether to use (chapter, page) format\n        Returns:\n            (page_id, x, y) where x, y are point coordinates on the page.\n            page_id is either page number (if chapters=0), or (chapter, pno).\n        \"\"\"\n        %}\n        PyObject *resolve_link(char *uri=NULL, int chapters=0)\n        {\n            if (!uri) {\n                if (chapters) return Py_BuildValue(\"(ii)ff\", -1, -1, 0, 0);\n                return Py_BuildValue(\"iff\", -1, 0, 0);\n            }\n            fz_document *this_doc = (fz_document *) $self;\n            float xp = 0, yp = 0;\n            fz_location loc = {0, 0};\n            fz_try(gctx) {\n                loc = fz_resolve_link(gctx, (fz_document *) $self, uri, &xp, &yp);\n            }\n            fz_catch(gctx) {\n                if (chapters) return Py_BuildValue(\"(ii)ff\", -1, -1, 0, 0);\n                return Py_BuildValue(\"iff\", -1, 0, 0);\n            }\n            if (chapters)\n                return Py_BuildValue(\"(ii)ff\", loc.chapter, loc.page, xp, yp);\n            int pno = fz_page_number_from_location(gctx, this_doc, loc);\n            return Py_BuildValue(\"iff\", pno, xp, yp);\n        }\n\n        FITZEXCEPTION(layout, !result)\n        CLOSECHECK(layout, \"\"\"Re-layout a reflowable document.\"\"\")\n        %pythonappend layout %{\n            self._reset_page_refs()\n            self.init_doc()%}\n        PyObject *layout(PyObject *rect = NULL, float width = 0, float height = 0, float fontsize = 11)\n        {\n            fz_document *doc = (fz_document *) $self;\n            if (!fz_is_document_reflowable(gctx, doc)) Py_RETURN_NONE;\n            fz_try(gctx) {\n                float w = width, h = height;\n                fz_rect r = JM_rect_from_py(rect);\n                if (!fz_is_infinite_rect(r)) {\n                    w = r.x1 - r.x0;\n                    h = r.y1 - r.y0;\n                }\n                if (w <= 0.0f || h <= 0.0f) {\n                    RAISEPY(gctx, \"bad page size\", PyExc_ValueError);\n                }\n                fz_layout_document(gctx, doc, w, h, fontsize);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION(make_bookmark, !result)\n        CLOSECHECK(make_bookmark, \"\"\"Make a page pointer before layouting document.\"\"\")\n        PyObject *make_bookmark(PyObject *loc)\n        {\n            fz_document *doc = (fz_document *) $self;\n            fz_location location;\n            fz_bookmark mark;\n            fz_try(gctx) {\n                if (JM_INT_ITEM(loc, 0, &location.chapter) == 1) {\n                    RAISEPY(gctx, MSG_BAD_LOCATION, PyExc_ValueError);\n                }\n                if (JM_INT_ITEM(loc, 1, &location.page) == 1) {\n                    RAISEPY(gctx, MSG_BAD_LOCATION, PyExc_ValueError);\n                }\n                mark = fz_make_bookmark(gctx, doc, location);\n                if (!mark) {\n                    RAISEPY(gctx, MSG_BAD_LOCATION, PyExc_ValueError);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return PyLong_FromVoidPtr((void *) mark);\n        }\n\n\n        FITZEXCEPTION(find_bookmark, !result)\n        CLOSECHECK(find_bookmark, \"\"\"Find new location after layouting a document.\"\"\")\n        PyObject *find_bookmark(PyObject *bm)\n        {\n            fz_document *doc = (fz_document *) $self;\n            fz_location location;\n            fz_try(gctx) {\n                intptr_t mark = (intptr_t) PyLong_AsVoidPtr(bm);\n                location = fz_lookup_bookmark(gctx, doc, mark);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"ii\", location.chapter, location.page);\n        }\n\n\n        CLOSECHECK0(is_reflowable, \"\"\"Check if document is layoutable.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *is_reflowable()\n        {\n            return JM_BOOL(fz_is_document_reflowable(gctx, (fz_document *) $self));\n        }\n\n        FITZEXCEPTION(_deleteObject, !result)\n        CLOSECHECK0(_deleteObject, \"\"\"Delete object.\"\"\")\n        PyObject *_deleteObject(int xref)\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_specifics(gctx, doc);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                if (!INRANGE(xref, 1, pdf_xref_len(gctx, pdf)-1)) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                pdf_delete_object(gctx, pdf, xref);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION(pdf_catalog, !result)\n        CLOSECHECK0(pdf_catalog, \"\"\"Get xref of PDF catalog.\"\"\")\n        PyObject *pdf_catalog()\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_specifics(gctx, doc);\n            int xref = 0;\n            if (!pdf) return Py_BuildValue(\"i\", xref);\n            fz_try(gctx) {\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf),\n                                             PDF_NAME(Root));\n                xref = pdf_to_num(gctx, root);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xref);\n        }\n\n        FITZEXCEPTION(_getPDFfileid, !result)\n        CLOSECHECK0(_getPDFfileid, \"\"\"Get PDF file id.\"\"\")\n        PyObject *_getPDFfileid()\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_specifics(gctx, doc);\n            if (!pdf) Py_RETURN_NONE;\n            PyObject *idlist = PyList_New(0);\n            fz_buffer *buffer = NULL;\n            unsigned char *hex;\n            pdf_obj *o;\n            int n, i, len;\n            PyObject *bytes;\n\n            fz_try(gctx) {\n                pdf_obj *identity = pdf_dict_get(gctx, pdf_trailer(gctx, pdf),\n                                             PDF_NAME(ID));\n                if (identity) {\n                    n = pdf_array_len(gctx, identity);\n                    for (i = 0; i < n; i++) {\n                        o = pdf_array_get(gctx, identity, i);\n                        len = (int) pdf_to_str_len(gctx, o);\n                        buffer = fz_new_buffer(gctx, 2 * len);\n                        fz_buffer_storage(gctx, buffer, &hex);\n                        hexlify(len, (unsigned char *) pdf_to_text_string(gctx, o), hex);\n                        LIST_APPEND_DROP(idlist, JM_UnicodeFromStr(hex));\n                        Py_CLEAR(bytes);\n                        fz_drop_buffer(gctx, buffer);\n                        buffer = NULL;\n                    }\n                }\n            }\n            fz_catch(gctx) {\n                fz_drop_buffer(gctx, buffer);\n            }\n            return idlist;\n        }\n\n        CLOSECHECK0(version_count, \"\"\"Count versions of PDF document.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *version_count()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) return Py_BuildValue(\"i\", 0);\n            return Py_BuildValue(\"i\", pdf_count_versions(gctx, pdf));\n        }\n\n\n        CLOSECHECK0(is_pdf, \"\"\"Check for PDF.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *is_pdf()\n        {\n            if (pdf_specifics(gctx, (fz_document *) $self)) Py_RETURN_TRUE;\n            else Py_RETURN_FALSE;\n        }\n\n        #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR <= 21\n        /* The underlying struct members that these methods give access to, are\n        not available. */\n        CLOSECHECK0(has_xref_streams, \"\"\"Check if xref table is a stream.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *has_xref_streams()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE;\n            if (pdf->has_xref_streams) Py_RETURN_TRUE;\n            Py_RETURN_FALSE;\n        }\n\n        CLOSECHECK0(has_old_style_xrefs, \"\"\"Check if xref table is old style.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *has_old_style_xrefs()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE;\n            if (pdf->has_old_style_xrefs) Py_RETURN_TRUE;\n            Py_RETURN_FALSE;\n        }\n        #endif\n\n        CLOSECHECK0(is_dirty, \"\"\"True if PDF has unsaved changes.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *is_dirty()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE;\n            return JM_BOOL(pdf_has_unsaved_changes(gctx, pdf));\n        }\n\n        CLOSECHECK0(can_save_incrementally, \"\"\"Check whether incremental saves are possible.\"\"\")\n        PyObject *can_save_incrementally()\n        {\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE; // gracefully handle non-PDF\n            return JM_BOOL(pdf_can_be_saved_incrementally(gctx, pdf));\n        }\n\n        CLOSECHECK0(is_fast_webaccess, \"\"\"Check whether we have a linearized PDF.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *is_fast_webaccess()\n        {\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE; // gracefully handle non-PDF\n            return JM_BOOL(pdf_doc_was_linearized(gctx, pdf));\n        }\n\n        CLOSECHECK0(is_repaired, \"\"\"Check whether PDF was repaired.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *is_repaired()\n        {\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE; // gracefully handle non-PDF\n            return JM_BOOL(pdf_was_repaired(gctx, pdf));\n        }\n\n        FITZEXCEPTION(save_snapshot, !result)\n        %pythonprepend save_snapshot %{\n        \"\"\"Save a file snapshot suitable for journalling.\"\"\"\n        if self.is_closed:\n            raise ValueError(\"doc is closed\")\n        if type(filename) == str:\n            pass\n        elif hasattr(filename, \"open\"):  # assume: pathlib.Path\n            filename = str(filename)\n        elif hasattr(filename, \"name\"):  # assume: file object\n            filename = filename.name\n        else:\n            raise ValueError(\"filename must be str, Path or file object\")\n        if filename == self.name:\n            raise ValueError(\"cannot snapshot to original\")\n        %}\n        PyObject *save_snapshot(const char *filename)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                pdf_save_snapshot(gctx, pdf, filename);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        CLOSECHECK0(authenticate, \"\"\"Decrypt document.\"\"\")\n        %pythonappend authenticate %{\n        if val:  # the doc is decrypted successfully and we init the outline\n            self.is_encrypted = False\n            self.isEncrypted = False\n            self.init_doc()\n            self.thisown = True\n        %}\n        PyObject *authenticate(char *password)\n        {\n            return Py_BuildValue(\"i\", fz_authenticate_password(gctx, (fz_document *) $self, (const char *) password));\n        }\n\n        //------------------------------------------------------------------\n        // save a PDF\n        //------------------------------------------------------------------\n        FITZEXCEPTION(save, !result)\n        %pythonprepend save %{\n        \"\"\"Save PDF to file, pathlib.Path or file pointer.\"\"\"\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if type(filename) == str:\n            pass\n        elif hasattr(filename, \"open\"):  # assume: pathlib.Path\n            filename = str(filename)\n        elif hasattr(filename, \"name\"):  # assume: file object\n            filename = filename.name\n        elif not hasattr(filename, \"seek\"):  # assume file object\n            raise ValueError(\"filename must be str, Path or file object\")\n        if filename == self.name and not incremental:\n            raise ValueError(\"save to original must be incremental\")\n        if self.page_count < 1:\n            raise ValueError(\"cannot save with zero pages\")\n        if incremental:\n            if self.name != filename or self.stream:\n                raise ValueError(\"incremental needs original file\")\n        if user_pw and len(user_pw) > 40 or owner_pw and len(owner_pw) > 40:\n            raise ValueError(\"password length must not exceed 40\")\n        %}\n\n        PyObject *\n        save(PyObject *filename, int garbage=0, int clean=0,\n            int deflate=0, int deflate_images=0, int deflate_fonts=0,\n            int incremental=0, int ascii=0, int expand=0, int linear=0,\n            int no_new_id=0, int appearance=0,\n            int pretty=0, int encryption=1, int permissions=4095,\n            char *owner_pw=NULL, char *user_pw=NULL)\n        {\n            pdf_write_options opts = pdf_default_write_options;\n            opts.do_incremental     = incremental;\n            opts.do_ascii           = ascii;\n            opts.do_compress        = deflate;\n            opts.do_compress_images = deflate_images;\n            opts.do_compress_fonts  = deflate_fonts;\n            opts.do_decompress      = expand;\n            opts.do_garbage         = garbage;\n            opts.do_pretty          = pretty;\n            opts.do_linear          = linear;\n            opts.do_clean           = clean;\n            opts.do_sanitize        = clean;\n            opts.dont_regenerate_id = no_new_id;\n            opts.do_appearance      = appearance;\n            opts.do_encrypt         = encryption;\n            opts.permissions        = permissions;\n            if (owner_pw) {\n                memcpy(&opts.opwd_utf8, owner_pw, strlen(owner_pw)+1);\n            } else if (user_pw) {\n                memcpy(&opts.opwd_utf8, user_pw, strlen(user_pw)+1);\n            }\n            if (user_pw) {\n                memcpy(&opts.upwd_utf8, user_pw, strlen(user_pw)+1);\n            }\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_specifics(gctx, doc);\n            fz_output *out = NULL;\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                pdf->resynth_required = 0;\n                JM_embedded_clean(gctx, pdf);\n                if (no_new_id == 0) {\n                    JM_ensure_identity(gctx, pdf);\n                }\n                if (PyUnicode_Check(filename)) {\n                    pdf_save_document(gctx, pdf, JM_StrAsChar(filename), &opts);\n                } else {\n                    out = JM_new_output_fileptr(gctx, filename);\n                    pdf_write_document(gctx, pdf, out, &opts);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_output(gctx, out);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode %{\n        def write(self, garbage=False, clean=False,\n            deflate=False, deflate_images=False, deflate_fonts=False,\n            incremental=False, ascii=False, expand=False, linear=False,\n            no_new_id=False, appearance=False, pretty=False, encryption=1, permissions=4095,\n            owner_pw=None, user_pw=None):\n            from io import BytesIO\n            bio = BytesIO()\n            self.save(bio, garbage=garbage, clean=clean,\n            no_new_id=no_new_id, appearance=appearance,\n            deflate=deflate, deflate_images=deflate_images, deflate_fonts=deflate_fonts,\n            incremental=incremental, ascii=ascii, expand=expand, linear=linear,\n            pretty=pretty, encryption=encryption, permissions=permissions,\n            owner_pw=owner_pw, user_pw=user_pw)\n            return bio.getvalue()\n        %}\n\n        //----------------------------------------------------------------\n        // Insert pages from a source PDF into this PDF.\n        // For reconstructing the links (_do_links method), we must save the\n        // insertion point (start_at) if it was specified as -1.\n        //----------------------------------------------------------------\n        FITZEXCEPTION(insert_pdf, !result)\n        %pythonprepend insert_pdf %{\n        \"\"\"Insert a page range from another PDF.\n\n        Args:\n            docsrc: PDF to copy from. Must be different object, but may be same file.\n            from_page: (int) first source page to copy, 0-based, default 0.\n            to_page: (int) last source page to copy, 0-based, default last page.\n            start_at: (int) from_page will become this page number in target.\n            rotate: (int) rotate copied pages, default -1 is no change.\n            links: (int/bool) whether to also copy links.\n            annots: (int/bool) whether to also copy annotations.\n            show_progress: (int) progress message interval, 0 is no messages.\n            final: (bool) indicates last insertion from this source PDF.\n            _gmap: internal use only\n\n        Copy sequence reversed if from_page > to_page.\"\"\"\n\n        if self.is_closed or self.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n        if self._graft_id == docsrc._graft_id:\n            raise ValueError(\"source and target cannot be same object\")\n        sa = start_at\n        if sa < 0:\n            sa = self.page_count\n        if len(docsrc) > show_progress > 0:\n            inname = os.path.basename(docsrc.name)\n            if not inname:\n                inname = \"memory PDF\"\n            outname = os.path.basename(self.name)\n            if not outname:\n                outname = \"memory PDF\"\n            print(\"Inserting '%s' at '%s'\" % (inname, outname))\n\n        # retrieve / make a Graftmap to avoid duplicate objects\n        isrt = docsrc._graft_id\n        _gmap = self.Graftmaps.get(isrt, None)\n        if _gmap is None:\n            _gmap = Graftmap(self)\n            self.Graftmaps[isrt] = _gmap\n        %}\n\n        %pythonappend insert_pdf %{\n        self._reset_page_refs()\n        if links:\n            self._do_links(docsrc, from_page = from_page, to_page = to_page,\n                        start_at = sa)\n        if final == 1:\n            self.Graftmaps[isrt] = None%}\n\n        PyObject *\n        insert_pdf(struct Document *docsrc,\n            int from_page=-1,\n            int to_page=-1,\n            int start_at=-1,\n            int rotate=-1,\n            int links=1,\n            int annots=1,\n            int show_progress=0,\n            int final = 1,\n            struct Graftmap *_gmap=NULL)\n        {\n            fz_document *doc = (fz_document *) $self;\n            fz_document *src = (fz_document *) docsrc;\n            pdf_document *pdfout = pdf_specifics(gctx, doc);\n            pdf_document *pdfsrc = pdf_specifics(gctx, src);\n            int outCount = fz_count_pages(gctx, doc);\n            int srcCount = fz_count_pages(gctx, src);\n\n            // local copies of page numbers\n            int fp = from_page, tp = to_page, sa = start_at;\n\n            // normalize page numbers\n            fp = Py_MAX(fp, 0);                // -1 = first page\n            fp = Py_MIN(fp, srcCount - 1);     // but do not exceed last page\n\n            if (tp < 0) tp = srcCount - 1;  // -1 = last page\n            tp = Py_MIN(tp, srcCount - 1);     // but do not exceed last page\n\n            if (sa < 0) sa = outCount;      // -1 = behind last page\n            sa = Py_MIN(sa, outCount);         // but that is also the limit\n\n            fz_try(gctx) {\n                if (!pdfout || !pdfsrc) {\n                    RAISEPY(gctx, \"source or target not a PDF\", PyExc_TypeError);\n                }\n                ENSURE_OPERATION(gctx, pdfout);\n                JM_merge_range(gctx, pdfout, pdfsrc, fp, tp, sa, rotate, links, annots, show_progress, (pdf_graft_map *) _gmap);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode %{\n        def insert_file(self, infile, from_page=-1, to_page=-1, start_at=-1, rotate=-1, links=True, annots=True,show_progress=0, final=1):\n            \"\"\"Insert an arbitrary supported document to an existing PDF.\n            \n            The infile may be given as a filename, a Document or a Pixmap.\n            Other paramters - where applicable - equal those of insert_pdf().\n            \"\"\"\n            src = None\n            if isinstance(infile, Pixmap):\n                if infile.colorspace.n > 3:\n                    infile = Pixmap(csRGB, infile)\n                src = Document(\"png\", infile.tobytes())\n            elif isinstance(infile, Document):\n                src = infile\n            else:\n                src = Document(infile)\n            if not src:\n                raise ValueError(\"bad infile parameter\")\n            if not src.is_pdf:\n                pdfbytes = src.convert_to_pdf()\n                src = Document(\"pdf\", pdfbytes)\n            return self.insert_pdf(src, from_page=from_page, to_page=to_page, start_at=start_at, rotate=rotate,links=links, annots=annots, show_progress=show_progress, final=final)\n        %}\n\n        //------------------------------------------------------------------\n        // Create and insert a new page (PDF)\n        //------------------------------------------------------------------\n        FITZEXCEPTION(_newPage, !result)\n        CLOSECHECK(_newPage, \"\"\"Make a new PDF page.\"\"\")\n        %pythonappend _newPage %{self._reset_page_refs()%}\n        PyObject *_newPage(int pno=-1, float width=595, float height=842)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_rect mediabox = fz_unit_rect;\n            mediabox.x1 = width;\n            mediabox.y1 = height;\n            pdf_obj *resources = NULL, *page_obj = NULL;\n            fz_buffer *contents = NULL;\n            fz_var(contents);\n            fz_var(page_obj);\n            fz_var(resources);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                if (pno < -1) {\n                    RAISEPY(gctx, MSG_BAD_PAGENO, PyExc_ValueError);\n                }\n                ENSURE_OPERATION(gctx, pdf);\n                // create /Resources and /Contents objects\n                resources = pdf_add_new_dict(gctx, pdf, 1);\n                page_obj = pdf_add_page(gctx, pdf, mediabox, 0, resources, contents);\n                pdf_insert_page(gctx, pdf, pno, page_obj);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, contents);\n                pdf_drop_obj(gctx, page_obj);\n                pdf_drop_obj(gctx, resources);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // Create sub-document to keep only selected pages.\n        // Parameter is a Python sequence of the wanted page numbers.\n        //------------------------------------------------------------------\n        FITZEXCEPTION(select, !result)\n        %pythonprepend select %{\"\"\"Build sub-pdf with page numbers in the list.\"\"\"\nif self.is_closed or self.is_encrypted:\n    raise ValueError(\"document closed or encrypted\")\nif not self.is_pdf:\n    raise ValueError(\"is no PDF\")\nif not hasattr(pyliste, \"__getitem__\"):\n    raise ValueError(\"sequence required\")\nif len(pyliste) == 0 or min(pyliste) not in range(len(self)) or max(pyliste) not in range(len(self)):\n    raise ValueError(\"bad page number(s)\")\npyliste = tuple(pyliste)%}\n        %pythonappend select %{self._reset_page_refs()%}\n        PyObject *select(PyObject *pyliste)\n        {\n            // preparatory stuff:\n            // (1) get underlying pdf document,\n            // (2) transform Python list into integer array\n\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            int *pages = NULL;\n            fz_try(gctx) {\n                // call retainpages (code copy of fz_clean_file.c)\n                int i, len = (int) PyTuple_Size(pyliste);\n                pages = fz_realloc_array(gctx, pages, len, int);\n                for (i = 0; i < len; i++) {\n                    pages[i] = (int) PyLong_AsLong(PyTuple_GET_ITEM(pyliste, (Py_ssize_t) i));\n                }\n                pdf_rearrange_pages(gctx, pdf, len, pages);\n                if (pdf->rev_page_map)\n                {\n                    pdf_drop_page_tree(gctx, pdf);\n                }\n            }\n            fz_always(gctx) {\n                fz_free(gctx, pages);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // remove one page\n        //------------------------------------------------------------------\n        FITZEXCEPTION(_delete_page, !result)\n        PyObject *_delete_page(int pno)\n        {\n            fz_try(gctx) {\n                fz_document *doc = (fz_document *) $self;\n                pdf_document *pdf = pdf_specifics(gctx, doc);\n                pdf_delete_page(gctx, pdf, pno);\n                if (pdf->rev_page_map)\n                {\n                    pdf_drop_page_tree(gctx, pdf);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // get document permissions\n        //------------------------------------------------------------------\n        %pythoncode%{@property%}\n        %pythonprepend permissions %{\n        \"\"\"Document permissions.\"\"\"\n\n        if self.is_encrypted:\n            return 0\n        %}\n        PyObject *permissions()\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_document_from_fz_document(gctx, doc);\n\n            // for PDF return result of standard function\n            if (pdf)\n                return Py_BuildValue(\"i\", pdf_document_permissions(gctx, pdf));\n\n            // otherwise simulate the PDF return value\n            int perm = (int) 0xFFFFFFFC;  // all permissions granted\n            // now switch off where needed\n            if (!fz_has_permission(gctx, doc, FZ_PERMISSION_PRINT))\n                perm = perm ^ PDF_PERM_PRINT;\n            if (!fz_has_permission(gctx, doc, FZ_PERMISSION_EDIT))\n                perm = perm ^ PDF_PERM_MODIFY;\n            if (!fz_has_permission(gctx, doc, FZ_PERMISSION_COPY))\n                perm = perm ^ PDF_PERM_COPY;\n            if (!fz_has_permission(gctx, doc, FZ_PERMISSION_ANNOTATE))\n                perm = perm ^ PDF_PERM_ANNOTATE;\n            return Py_BuildValue(\"i\", perm);\n        }\n\n\n        FITZEXCEPTION(journal_enable, !result)\n        CLOSECHECK(journal_enable, \"\"\"Activate document journalling.\"\"\")\n        PyObject *journal_enable()\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                pdf_enable_journal(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(journal_start_op, !result)\n        CLOSECHECK(journal_start_op, \"\"\"Begin a journalling operation.\"\"\")\n        PyObject *journal_start_op(const char *name=NULL)\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                if (!pdf->journal) {\n                    RAISEPY(gctx, \"Journalling not enabled\", PyExc_RuntimeError);\n                }\n                if (name) {\n                    pdf_begin_operation(gctx, pdf, name);\n                } else {\n                    pdf_begin_implicit_operation(gctx, pdf);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(journal_stop_op, !result)\n        CLOSECHECK(journal_stop_op, \"\"\"End a journalling operation.\"\"\")\n        PyObject *journal_stop_op()\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                pdf_end_operation(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(journal_position, !result)\n        CLOSECHECK(journal_position, \"\"\"Show journalling state.\"\"\")\n        PyObject *journal_position()\n        {\n            int rc, steps=0;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                rc = pdf_undoredo_state(gctx, pdf, &steps);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"ii\", rc, steps);\n        }\n\n\n        FITZEXCEPTION(journal_op_name, !result)\n        CLOSECHECK(journal_op_name, \"\"\"Show operation name for given step.\"\"\")\n        PyObject *journal_op_name(int step)\n        {\n            const char *name=NULL;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                name = pdf_undoredo_step(gctx, pdf, step);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            if (name) {\n                return PyUnicode_FromString(name);\n            } else {\n                Py_RETURN_NONE;\n            }\n        }\n\n\n        FITZEXCEPTION(journal_can_do, !result)\n        CLOSECHECK(journal_can_do, \"\"\"Show if undo and / or redo are possible.\"\"\")\n        PyObject *journal_can_do()\n        {\n            int undo=0, redo=0;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                undo = pdf_can_undo(gctx, pdf);\n                redo = pdf_can_redo(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"{s:N,s:N}\", \"undo\", JM_BOOL(undo), \"redo\", JM_BOOL(redo));\n        }\n\n\n        FITZEXCEPTION(journal_undo, !result)\n        CLOSECHECK(journal_undo, \"\"\"Move backwards in the journal.\"\"\")\n        PyObject *journal_undo()\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                pdf_undo(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_TRUE;\n        }\n\n\n        FITZEXCEPTION(journal_redo, !result)\n        CLOSECHECK(journal_redo, \"\"\"Move forward in the journal.\"\"\")\n        PyObject *journal_redo()\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                pdf_redo(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_TRUE;\n        }\n\n\n        FITZEXCEPTION(journal_save, !result)\n        CLOSECHECK(journal_save, \"\"\"Save journal to a file.\"\"\")\n        PyObject *journal_save(PyObject *filename)\n        {\n            fz_output *out = NULL;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                if (PyUnicode_Check(filename)) {\n                    pdf_save_journal(gctx, pdf, (const char *) PyUnicode_AsUTF8(filename));\n                } else {\n                    out = JM_new_output_fileptr(gctx, filename);\n                    pdf_write_journal(gctx, pdf, out);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_output(gctx, out);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(journal_load, !result)\n        CLOSECHECK(journal_load, \"\"\"Load a journal from a file.\"\"\")\n        PyObject *journal_load(PyObject *filename)\n        {\n            fz_buffer *res = NULL;\n            fz_stream *stm = NULL;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                if (PyUnicode_Check(filename)) {\n                    pdf_load_journal(gctx, pdf, PyUnicode_AsUTF8(filename));\n                } else {\n                    res = JM_BufferFromBytes(gctx, filename);\n                    stm = fz_open_buffer(gctx, res);\n                    pdf_deserialise_journal(gctx, pdf, stm);\n                }\n                if (!pdf->journal) {\n                    RAISEPY(gctx, \"Journal and document do not match\", JM_Exc_FileDataError);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_stream(gctx, stm);\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(journal_is_enabled, !result)\n        CLOSECHECK(journal_is_enabled, \"\"\"Check if journalling is enabled.\"\"\")\n        PyObject *journal_is_enabled()\n        {\n            int enabled = 0;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                enabled = pdf && pdf->journal;\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_BOOL(enabled);\n        }\n\n\n        FITZEXCEPTION(_get_char_widths, !result)\n        CLOSECHECK(_get_char_widths, \"\"\"Return list of glyphs and glyph widths of a font.\"\"\")\n        PyObject *_get_char_widths(int xref, char *bfname, char *ext,\n                                 int ordering, int limit, int idx = 0)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            PyObject *wlist = NULL;\n            int i, glyph, mylimit;\n            mylimit = limit;\n            if (mylimit < 256) mylimit = 256;\n            const unsigned char *data;\n            int size, index;\n            fz_font *font = NULL;\n            fz_buffer *buf = NULL;\n\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                if (ordering >= 0) {\n                    data = fz_lookup_cjk_font(gctx, ordering, &size, &index);\n                    font = fz_new_font_from_memory(gctx, NULL, data, size, index, 0);\n                    goto weiter;\n                }\n                data = fz_lookup_base14_font(gctx, bfname, &size);\n                if (data) {\n                    font = fz_new_font_from_memory(gctx, bfname, data, size, 0, 0);\n                    goto weiter;\n                }\n                buf = JM_get_fontbuffer(gctx, pdf, xref);\n                if (!buf) {\n                    fz_throw(gctx, FZ_ERROR_GENERIC, \"font at xref %d is not supported\", xref);\n                }\n                font = fz_new_font_from_buffer(gctx, NULL, buf, idx, 0);\n\n                weiter:;\n                wlist = PyList_New(0);\n                float adv;\n                for (i = 0; i < mylimit; i++) {\n                    glyph = fz_encode_character(gctx, font, i);\n                    adv = fz_advance_glyph(gctx, font, glyph, 0);\n                    if (ordering >= 0) {\n                        glyph = i;\n                    }\n                    if (glyph > 0) {\n                        LIST_APPEND_DROP(wlist, Py_BuildValue(\"if\", glyph, adv));\n                    } else {\n                        LIST_APPEND_DROP(wlist, Py_BuildValue(\"if\", glyph, 0.0));\n                    }\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buf);\n                fz_drop_font(gctx, font);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return wlist;\n        }\n\n\n        FITZEXCEPTION(page_xref, !result)\n        CLOSECHECK0(page_xref, \"\"\"Get xref of page number.\"\"\")\n        PyObject *page_xref(int pno)\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            int page_count = fz_count_pages(gctx, this_doc);\n            int n = pno;\n            while (n < 0) n += page_count;\n            pdf_document *pdf = pdf_specifics(gctx, this_doc);\n            int xref = 0;\n            fz_try(gctx) {\n                if (n >= page_count) {\n                    RAISEPY(gctx, MSG_BAD_PAGENO, PyExc_ValueError);\n                }\n                ASSERT_PDF(pdf);\n                xref = pdf_to_num(gctx, pdf_lookup_page_obj(gctx, pdf, n));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xref);\n        }\n\n\n        FITZEXCEPTION(page_annot_xrefs, !result)\n        CLOSECHECK0(page_annot_xrefs, \"\"\"Get list annotations of page number.\"\"\")\n        PyObject *page_annot_xrefs(int pno)\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            int page_count = fz_count_pages(gctx, this_doc);\n            int n = pno;\n            while (n < 0) n += page_count;\n            pdf_document *pdf = pdf_specifics(gctx, this_doc);\n            PyObject *annots = NULL;\n            fz_try(gctx) {\n                if (n >= page_count) {\n                    RAISEPY(gctx, MSG_BAD_PAGENO, PyExc_ValueError);\n                }\n                ASSERT_PDF(pdf);\n                annots = JM_get_annot_xref_list(gctx, pdf_lookup_page_obj(gctx, pdf, n));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return annots;\n        }\n\n\n        FITZEXCEPTION(page_cropbox, !result)\n        CLOSECHECK0(page_cropbox, \"\"\"Get CropBox of page number (without loading page).\"\"\")\n        %pythonappend page_cropbox %{val = Rect(JM_TUPLE3(val))%}\n        PyObject *page_cropbox(int pno)\n        {\n            fz_document *this_doc = (fz_document *) $self;\n            int page_count = fz_count_pages(gctx, this_doc);\n            int n = pno;\n            while (n < 0) n += page_count;\n            pdf_obj *pageref = NULL;\n            fz_var(pageref);\n            pdf_document *pdf = pdf_specifics(gctx, this_doc);\n            fz_try(gctx) {\n                if (n >= page_count) {\n                    RAISEPY(gctx, MSG_BAD_PAGENO, PyExc_ValueError);\n                }\n                ASSERT_PDF(pdf);\n                pageref = pdf_lookup_page_obj(gctx, pdf, n);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_py_from_rect(JM_cropbox(gctx, pageref));\n        }\n\n\n        FITZEXCEPTION(_getPageInfo, !result)\n        CLOSECHECK(_getPageInfo, \"\"\"List fonts, images, XObjects used on a page.\"\"\")\n        PyObject *_getPageInfo(int pno, int what)\n        {\n            fz_document *doc = (fz_document *) $self;\n            pdf_document *pdf = pdf_specifics(gctx, doc);\n            pdf_obj *pageref, *rsrc;\n            PyObject *liste = NULL, *tracer = NULL;\n            fz_var(liste);\n            fz_var(tracer);\n            fz_try(gctx) {\n                int page_count = fz_count_pages(gctx, doc);\n                int n = pno;  // pno < 0 is allowed\n                while (n < 0) n += page_count;  // make it non-negative\n                if (n >= page_count) {\n                    RAISEPY(gctx, MSG_BAD_PAGENO, PyExc_ValueError);\n                }\n                ASSERT_PDF(pdf);\n                pageref = pdf_lookup_page_obj(gctx, pdf, n);\n                rsrc = pdf_dict_get_inheritable(gctx,\n                           pageref, PDF_NAME(Resources));\n                liste = PyList_New(0);\n                tracer = PyList_New(0);\n                if (rsrc) {\n                    JM_scan_resources(gctx, pdf, rsrc, liste, what, 0, tracer);\n                }\n            }\n            fz_always(gctx) {\n                Py_CLEAR(tracer);\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(liste);\n                return NULL;\n            }\n            return liste;\n        }\n\n        FITZEXCEPTION(extract_font, !result)\n        CLOSECHECK(extract_font, \"\"\"Get a font by xref. Returns a tuple or dictionary.\"\"\")\n        PyObject *extract_font(int xref=0, int info_only=0, PyObject *named=NULL)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n\n            fz_buffer *buffer = NULL;\n            pdf_obj *obj, *basefont, *bname;\n            PyObject *bytes = NULL;\n            char *ext = NULL;\n            PyObject *rc;\n            fz_try(gctx) {\n                obj = pdf_load_object(gctx, pdf, xref);\n                pdf_obj *type = pdf_dict_get(gctx, obj, PDF_NAME(Type));\n                pdf_obj *subtype = pdf_dict_get(gctx, obj, PDF_NAME(Subtype));\n                if(pdf_name_eq(gctx, type, PDF_NAME(Font)) &&\n                   strncmp(pdf_to_name(gctx, subtype), \"CIDFontType\", 11) != 0) {\n                    basefont = pdf_dict_get(gctx, obj, PDF_NAME(BaseFont));\n                    if (!basefont || pdf_is_null(gctx, basefont)) {\n                        bname = pdf_dict_get(gctx, obj, PDF_NAME(Name));\n                    } else {\n                        bname = basefont;\n                    }\n                    ext = JM_get_fontextension(gctx, pdf, xref);\n                    if (strcmp(ext, \"n/a\") != 0 && !info_only) {\n                        buffer = JM_get_fontbuffer(gctx, pdf, xref);\n                        bytes = JM_BinFromBuffer(gctx, buffer);\n                        fz_drop_buffer(gctx, buffer);\n                    } else {\n                        bytes = Py_BuildValue(\"y\", \"\");\n                    }\n                    if (PyObject_Not(named)) {\n                        rc = PyTuple_New(4);\n                        PyTuple_SET_ITEM(rc, 0, JM_EscapeStrFromStr(pdf_to_name(gctx, bname)));\n                        PyTuple_SET_ITEM(rc, 1, JM_UnicodeFromStr(ext));\n                        PyTuple_SET_ITEM(rc, 2, JM_UnicodeFromStr(pdf_to_name(gctx, subtype)));\n                        PyTuple_SET_ITEM(rc, 3, bytes);\n                    } else {\n                        rc = PyDict_New();\n                        DICT_SETITEM_DROP(rc, dictkey_name, JM_EscapeStrFromStr(pdf_to_name(gctx, bname)));\n                        DICT_SETITEM_DROP(rc, dictkey_ext, JM_UnicodeFromStr(ext));\n                        DICT_SETITEM_DROP(rc, dictkey_type, JM_UnicodeFromStr(pdf_to_name(gctx, subtype)));\n                        DICT_SETITEM_DROP(rc, dictkey_content, bytes);\n                    }\n                } else {\n                    if (PyObject_Not(named)) {\n                        rc = Py_BuildValue(\"sssy\", \"\", \"\", \"\", \"\");\n                    } else {\n                        rc = PyDict_New();\n                        DICT_SETITEM_DROP(rc, dictkey_name, Py_BuildValue(\"s\", \"\"));\n                        DICT_SETITEM_DROP(rc, dictkey_ext, Py_BuildValue(\"s\", \"\"));\n                        DICT_SETITEM_DROP(rc, dictkey_type, Py_BuildValue(\"s\", \"\"));\n                        DICT_SETITEM_DROP(rc, dictkey_content, Py_BuildValue(\"y\", \"\"));\n                    }\n                }\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, obj);\n                JM_PyErr_Clear;\n            }\n            fz_catch(gctx) {\n                if (PyObject_Not(named)) {\n                    rc = Py_BuildValue(\"sssy\", \"invalid-name\", \"\", \"\", \"\");\n                } else {\n                    rc = PyDict_New();\n                    DICT_SETITEM_DROP(rc, dictkey_name, Py_BuildValue(\"s\", \"invalid-name\"));\n                    DICT_SETITEM_DROP(rc, dictkey_ext, Py_BuildValue(\"s\", \"\"));\n                    DICT_SETITEM_DROP(rc, dictkey_type, Py_BuildValue(\"s\", \"\"));\n                    DICT_SETITEM_DROP(rc, dictkey_content, Py_BuildValue(\"y\", \"\"));\n                }\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(extract_image, !result)\n        CLOSECHECK(extract_image, \"\"\"Get image by xref. Returns a dictionary.\"\"\")\n        PyObject *extract_image(int xref)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            pdf_obj *obj = NULL;\n            fz_buffer *res = NULL;\n            fz_image *img = NULL;\n            PyObject *rc = NULL;\n            const char *ext = NULL;\n            const char *cs_name = NULL;\n            int img_type = 0, xres, yres, colorspace;\n            int smask = 0, width, height, bpc;\n            fz_compressed_buffer *cbuf = NULL;\n            fz_var(img);\n            fz_var(res);\n            fz_var(obj);\n\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                if (!INRANGE(xref, 1, pdf_xref_len(gctx, pdf)-1)) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                obj = pdf_new_indirect(gctx, pdf, xref, 0);\n                pdf_obj *subtype = pdf_dict_get(gctx, obj, PDF_NAME(Subtype));\n\n                if (!pdf_name_eq(gctx, subtype, PDF_NAME(Image))) {\n                    RAISEPY(gctx, \"not an image\", PyExc_ValueError);\n                }\n\n                pdf_obj *o = pdf_dict_geta(gctx, obj, PDF_NAME(SMask), PDF_NAME(Mask));\n                if (o) smask = pdf_to_num(gctx, o);\n\n                if (pdf_is_jpx_image(gctx, obj)) {\n                    img_type = FZ_IMAGE_JPX;\n                    res = pdf_load_stream(gctx, obj);\n                    ext = \"jpx\";\n                }\n                if (JM_is_jbig2_image(gctx, obj)) {\n                    img_type = FZ_IMAGE_JBIG2;\n                    res = pdf_load_stream(gctx, obj);\n                    ext = \"jb2\";\n                }\n                if (img_type == FZ_IMAGE_UNKNOWN) {\n                    res = pdf_load_raw_stream(gctx, obj);\n                    unsigned char *c = NULL;\n                    fz_buffer_storage(gctx, res, &c);\n                    img_type = fz_recognize_image_format(gctx, c);\n                    ext = JM_image_extension(img_type);\n                }\n                if (img_type == FZ_IMAGE_UNKNOWN) {\n                    fz_drop_buffer(gctx, res);\n                    res = NULL;\n                    img = pdf_load_image(gctx, pdf, obj);\n                    cbuf = fz_compressed_image_buffer(gctx, img);\n                    if (cbuf &&\n                        cbuf->params.type != FZ_IMAGE_RAW &&\n                        cbuf->params.type != FZ_IMAGE_FAX &&\n                        cbuf->params.type != FZ_IMAGE_FLATE && \n                        cbuf->params.type != FZ_IMAGE_LZW && \n                        cbuf->params.type != FZ_IMAGE_RLD) {\n                        img_type = cbuf->params.type;\n                        ext = JM_image_extension(img_type);\n                        res = cbuf->buffer;\n                    } else {\n                        res = fz_new_buffer_from_image_as_png(gctx, img,\n                                fz_default_color_params);\n                        ext = \"png\";\n                    }\n                } else {\n                    img = fz_new_image_from_buffer(gctx, res);\n                }\n\n                fz_image_resolution(img, &xres, &yres);\n                width = img->w;\n                height = img->h;\n                colorspace = img->n;\n                bpc = img->bpc;\n                cs_name = fz_colorspace_name(gctx, img->colorspace);\n\n                rc = PyDict_New();\n                DICT_SETITEM_DROP(rc, dictkey_ext,\n                                    JM_UnicodeFromStr(ext));\n                DICT_SETITEM_DROP(rc, dictkey_smask,\n                                    Py_BuildValue(\"i\", smask));\n                DICT_SETITEM_DROP(rc, dictkey_width,\n                                    Py_BuildValue(\"i\", width));\n                DICT_SETITEM_DROP(rc, dictkey_height,\n                                    Py_BuildValue(\"i\", height));\n                DICT_SETITEM_DROP(rc, dictkey_colorspace,\n                                    Py_BuildValue(\"i\", colorspace));\n                DICT_SETITEM_DROP(rc, dictkey_bpc,\n                                    Py_BuildValue(\"i\", bpc));\n                DICT_SETITEM_DROP(rc, dictkey_xres,\n                                    Py_BuildValue(\"i\", xres));\n                DICT_SETITEM_DROP(rc, dictkey_yres,\n                                    Py_BuildValue(\"i\", yres));\n                DICT_SETITEM_DROP(rc, dictkey_cs_name,\n                                    JM_UnicodeFromStr(cs_name));\n                DICT_SETITEM_DROP(rc, dictkey_image,\n                                    JM_BinFromBuffer(gctx, res));\n            }\n            fz_always(gctx) {\n                fz_drop_image(gctx, img);\n                if (!cbuf) fz_drop_buffer(gctx, res);\n                pdf_drop_obj(gctx, obj);\n            }\n\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                fz_warn(gctx, \"%s\", fz_caught_message(gctx));\n                Py_RETURN_FALSE;\n            }\n            if (!rc)\n                Py_RETURN_NONE;\n            return rc;\n        }\n\n\n        //------------------------------------------------------------------\n        // Delete all bookmarks (table of contents)\n        // returns list of deleted (now available) xref numbers\n        //------------------------------------------------------------------\n        CLOSECHECK(_delToC, \"\"\"Delete the TOC.\"\"\")\n        %pythonappend _delToC %{self.init_doc()%}\n        PyObject *_delToC()\n        {\n            PyObject *xrefs = PyList_New(0);          // create Python list\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) return xrefs;                   // not a pdf\n\n            pdf_obj *root, *olroot, *first;\n            int xref_count, olroot_xref, i, xref;\n\n            // get the main root\n            root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n            // get the outline root\n            olroot = pdf_dict_get(gctx, root, PDF_NAME(Outlines));\n            if (!olroot) return xrefs;                // no outlines or some problem\n\n            first = pdf_dict_get(gctx, olroot, PDF_NAME(First)); // first outline\n\n            xrefs = JM_outline_xrefs(gctx, first, xrefs);\n            xref_count = (int) PyList_Size(xrefs);\n\n            olroot_xref = pdf_to_num(gctx, olroot);        // delete OL root\n            pdf_delete_object(gctx, pdf, olroot_xref);     // delete OL root\n            pdf_dict_del(gctx, root, PDF_NAME(Outlines));  // delete OL root\n\n            for (i = 0; i < xref_count; i++)\n            {\n                JM_INT_ITEM(xrefs, i, &xref);\n                pdf_delete_object(gctx, pdf, xref);      // delete outline item\n            }\n            LIST_APPEND_DROP(xrefs, Py_BuildValue(\"i\", olroot_xref));\n            \n            return xrefs;\n        }\n\n\n        //------------------------------------------------------------------\n        // Check: is xref a stream object?\n        //------------------------------------------------------------------\n        CLOSECHECK0(xref_is_stream, \"\"\"Check if xref is a stream object.\"\"\")\n        PyObject *xref_is_stream(int xref=0)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE;  // not a PDF\n            return JM_BOOL(pdf_obj_num_is_stream(gctx, pdf, xref));\n        }\n\n        //------------------------------------------------------------------\n        // Return or set NeedAppearances\n        //------------------------------------------------------------------\n        %pythonprepend need_appearances\n%{\"\"\"Get/set the NeedAppearances value.\"\"\"\nif self.is_closed:\n    raise ValueError(\"document closed\")\nif not self.is_form_pdf:\n    return None\n%}\n        PyObject *need_appearances(PyObject *value=NULL)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            int oldval = -1;\n            pdf_obj *app = NULL;\n            char appkey[] = \"NeedAppearances\";\n            fz_try(gctx) {\n                pdf_obj *form = pdf_dict_getp(gctx, pdf_trailer(gctx, pdf),\n                                \"Root/AcroForm\");\n                app = pdf_dict_gets(gctx, form, appkey);\n                if (pdf_is_bool(gctx, app)) {\n                    oldval = pdf_to_bool(gctx, app);\n                }\n\n                if (EXISTS(value)) {\n                    pdf_dict_puts_drop(gctx, form, appkey, PDF_TRUE);\n                } else if (value == Py_False) {\n                    pdf_dict_puts_drop(gctx, form, appkey, PDF_FALSE);\n                }\n            }\n            fz_catch(gctx) {\n                Py_RETURN_NONE;\n            }\n            if (value != Py_None) {\n                return value;\n            }\n            if (oldval >= 0) {\n                return JM_BOOL(oldval);\n            }\n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // Return the /SigFlags value\n        //------------------------------------------------------------------\n        CLOSECHECK0(get_sigflags, \"\"\"Get the /SigFlags value.\"\"\")\n        int get_sigflags()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) return -1;  // not a PDF\n            int sigflag = -1;\n            fz_try(gctx) {\n                pdf_obj *sigflags = pdf_dict_getl(gctx,\n                                        pdf_trailer(gctx, pdf),\n                                        PDF_NAME(Root),\n                                        PDF_NAME(AcroForm),\n                                        PDF_NAME(SigFlags),\n                                        NULL);\n                if (sigflags) {\n                    sigflag = (int) pdf_to_int(gctx, sigflags);\n                }\n            }\n            fz_catch(gctx) {\n                return -1;  // any problem\n            }\n            return sigflag;\n        }\n\n        //------------------------------------------------------------------\n        // Check: is this an AcroForm with at least one field?\n        //------------------------------------------------------------------\n        CLOSECHECK0(is_form_pdf, \"\"\"Either False or PDF field count.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *is_form_pdf()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_FALSE;  // not a PDF\n            int count = -1;  // init count\n            fz_try(gctx) {\n                pdf_obj *fields = pdf_dict_getl(gctx,\n                                                pdf_trailer(gctx, pdf),\n                                                PDF_NAME(Root),\n                                                PDF_NAME(AcroForm),\n                                                PDF_NAME(Fields),\n                                                NULL);\n                if (pdf_is_array(gctx, fields)) {\n                    count = pdf_array_len(gctx, fields);\n                }\n            }\n            fz_catch(gctx) {\n                Py_RETURN_FALSE;\n            }\n            if (count >= 0) {\n                return Py_BuildValue(\"i\", count);\n            } else {\n                Py_RETURN_FALSE;\n            }\n        }\n\n        //------------------------------------------------------------------\n        // Return the list of field font resource names\n        //------------------------------------------------------------------\n        CLOSECHECK0(FormFonts, \"\"\"Get list of field font resource names.\"\"\")\n        %pythoncode%{@property%}\n        PyObject *FormFonts()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_NONE;           // not a PDF\n            pdf_obj *fonts = NULL;\n            PyObject *liste = PyList_New(0);\n            fz_var(liste);\n            fz_try(gctx) {\n                fonts = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(DR), PDF_NAME(Font), NULL);\n                if (fonts && pdf_is_dict(gctx, fonts))       // fonts exist\n                {\n                    int i, n = pdf_dict_len(gctx, fonts);\n                    for (i = 0; i < n; i++)\n                    {\n                        pdf_obj *f = pdf_dict_get_key(gctx, fonts, i);\n                        LIST_APPEND_DROP(liste, JM_UnicodeFromStr(pdf_to_name(gctx, f)));\n                    }\n                }\n            }\n            fz_catch(gctx) {\n                Py_DECREF(liste);\n                Py_RETURN_NONE;  // any problem yields None\n            }\n            return liste;\n        }\n\n        //------------------------------------------------------------------\n        // Add a field font\n        //------------------------------------------------------------------\n        FITZEXCEPTION(_addFormFont, !result)\n        CLOSECHECK(_addFormFont, \"\"\"Add new form font.\"\"\")\n        PyObject *_addFormFont(char *name, char *font)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_NONE;  // not a PDF\n            pdf_obj *fonts = NULL;\n            fz_try(gctx) {\n                fonts = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root),\n                             PDF_NAME(AcroForm), PDF_NAME(DR), PDF_NAME(Font), NULL);\n                if (!fonts || !pdf_is_dict(gctx, fonts)) {\n                    RAISEPY(gctx, \"PDF has no form fonts yet\", PyExc_RuntimeError);\n                }\n                pdf_obj *k = pdf_new_name(gctx, (const char *) name);\n                pdf_obj *v = JM_pdf_obj_from_str(gctx, pdf, font);\n                pdf_dict_put(gctx, fonts, k, v);\n            }\n            fz_catch(gctx) NULL;\n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // Get Xref Number of Outline Root, create it if missing\n        //------------------------------------------------------------------\n        FITZEXCEPTION(_getOLRootNumber, !result)\n        CLOSECHECK(_getOLRootNumber, \"\"\"Get xref of Outline Root, create it if missing.\"\"\")\n        PyObject *_getOLRootNumber()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            pdf_obj *ind_obj = NULL;\n            pdf_obj *olroot2 = NULL;\n            int ret;\n            fz_var(ind_obj);\n            fz_var(olroot2);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                // get main root\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n                // get outline root\n                pdf_obj *olroot = pdf_dict_get(gctx, root, PDF_NAME(Outlines));\n                if (!olroot)\n                {\n                    olroot2 = pdf_new_dict(gctx, pdf, 4);\n                    pdf_dict_put(gctx, olroot2, PDF_NAME(Type), PDF_NAME(Outlines));\n                    ind_obj = pdf_add_object(gctx, pdf, olroot2);\n                    pdf_dict_put(gctx, root, PDF_NAME(Outlines), ind_obj);\n                    olroot = pdf_dict_get(gctx, root, PDF_NAME(Outlines));\n                    \n                }\n                ret = pdf_to_num(gctx, olroot);\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, ind_obj);\n                pdf_drop_obj(gctx, olroot2);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", ret);\n        }\n\n        //------------------------------------------------------------------\n        // Get a new Xref number\n        //------------------------------------------------------------------\n        FITZEXCEPTION(get_new_xref, !result)\n        CLOSECHECK(get_new_xref, \"\"\"Make a new xref.\"\"\")\n        PyObject *get_new_xref()\n        {\n            int xref = 0;\n            fz_try(gctx) {\n                fz_document *doc = (fz_document *) $self;\n                pdf_document *pdf = pdf_specifics(gctx, doc);\n                ASSERT_PDF(pdf);\n                ENSURE_OPERATION(gctx, pdf);\n                xref = pdf_create_object(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xref);\n        }\n\n        //------------------------------------------------------------------\n        // Get Length of XREF table\n        //------------------------------------------------------------------\n        FITZEXCEPTION(xref_length, !result)\n        CLOSECHECK0(xref_length, \"\"\"Get length of xref table.\"\"\")\n        PyObject *xref_length()\n        {\n            int xreflen = 0;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                if (pdf) xreflen = pdf_xref_len(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xreflen);\n        }\n\n        //------------------------------------------------------------------\n        // Get XML Metadata\n        //------------------------------------------------------------------\n        CLOSECHECK0(get_xml_metadata, \"\"\"Get document XML metadata.\"\"\")\n        PyObject *get_xml_metadata()\n        {\n            PyObject *rc = NULL;\n            fz_buffer *buff = NULL;\n            pdf_obj *xml = NULL;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                if (pdf) {\n                    xml = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root), PDF_NAME(Metadata), NULL);\n                }\n                if (xml) {\n                    buff = pdf_load_stream(gctx, xml);\n                    rc = JM_UnicodeFromBuffer(gctx, buff);\n                } else {\n                    rc = EMPTY_STRING;\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buff);\n                PyErr_Clear();\n            }\n            fz_catch(gctx) {\n                return EMPTY_STRING;\n            }\n            return rc;\n        }\n\n        //------------------------------------------------------------------\n        // Get XML Metadata xref\n        //------------------------------------------------------------------\n        FITZEXCEPTION(xref_xml_metadata, !result)\n        CLOSECHECK0(xref_xml_metadata, \"\"\"Get xref of document XML metadata.\"\"\")\n        PyObject *xref_xml_metadata()\n        {\n            int xref = 0;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n                ASSERT_PDF(pdf);\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n                if (!root) {\n                    RAISEPY(gctx, MSG_BAD_PDFROOT, JM_Exc_FileDataError);\n                }\n                pdf_obj *xml = pdf_dict_get(gctx, root, PDF_NAME(Metadata));\n                if (xml) xref = pdf_to_num(gctx, xml);\n            }\n            fz_catch(gctx) {;}\n            return Py_BuildValue(\"i\", xref);\n        }\n\n        //------------------------------------------------------------------\n        // Delete XML Metadata\n        //------------------------------------------------------------------\n        FITZEXCEPTION(del_xml_metadata, !result)\n        CLOSECHECK(del_xml_metadata, \"\"\"Delete XML metadata.\"\"\")\n        PyObject *del_xml_metadata()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n                if (root) pdf_dict_del(gctx, root, PDF_NAME(Metadata));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // Set XML-based Metadata\n        //------------------------------------------------------------------\n        FITZEXCEPTION(set_xml_metadata, !result)\n        CLOSECHECK(set_xml_metadata, \"\"\"Store XML document level metadata.\"\"\")\n        PyObject *set_xml_metadata(char *metadata)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_buffer *res = NULL;\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n                if (!root) {\n                    RAISEPY(gctx, MSG_BAD_PDFROOT, JM_Exc_FileDataError);\n                }\n                res = fz_new_buffer_from_copied_data(gctx, (const unsigned char *) metadata, strlen(metadata));\n                pdf_obj *xml = pdf_dict_get(gctx, root, PDF_NAME(Metadata));\n                if (xml) {\n                    JM_update_stream(gctx, pdf, xml, res, 0);\n                } else {\n                    xml = pdf_add_stream(gctx, pdf, res, NULL, 0);\n                    pdf_dict_put(gctx, xml, PDF_NAME(Type), PDF_NAME(Metadata));\n                    pdf_dict_put(gctx, xml, PDF_NAME(Subtype), PDF_NAME(XML));\n                    pdf_dict_put_drop(gctx, root, PDF_NAME(Metadata), xml);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // Get Object String of xref\n        //------------------------------------------------------------------\n        FITZEXCEPTION(xref_object, !result)\n        CLOSECHECK0(xref_object, \"\"\"Get xref object source as a string.\"\"\")\n        PyObject *xref_object(int xref, int compressed=0, int ascii=0)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            pdf_obj *obj = NULL;\n            PyObject *text = NULL;\n            fz_buffer *res=NULL;\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1) && xref != -1) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                if (xref > 0) {\n                    obj = pdf_load_object(gctx, pdf, xref);\n                } else {\n                    obj = pdf_trailer(gctx, pdf);\n                }\n                res = JM_object_to_buffer(gctx, pdf_resolve_indirect(gctx, obj), compressed, ascii);\n                text = JM_EscapeStrFromBuffer(gctx, res);\n            }\n            fz_always(gctx) {\n                if (xref > 0) {\n                    pdf_drop_obj(gctx, obj);\n                }\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) return EMPTY_STRING;\n            return text;\n        }\n        %pythoncode %{\n        def pdf_trailer(self, compressed: bool=False, ascii:bool=False)->str:\n            \"\"\"Get PDF trailer as a string.\"\"\"\n            return self.xref_object(-1, compressed=compressed, ascii=ascii)%}\n\n\n        //------------------------------------------------------------------\n        // Get compressed stream of an object by xref\n        // Py_RETURN_NONE if not stream\n        //------------------------------------------------------------------\n        FITZEXCEPTION(xref_stream_raw, !result)\n        CLOSECHECK(xref_stream_raw, \"\"\"Get xref stream without decompression.\"\"\")\n        PyObject *xref_stream_raw(int xref)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            PyObject *r = NULL;\n            pdf_obj *obj = NULL;\n            fz_var(obj);\n            fz_buffer *res = NULL;\n            fz_var(res);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1) && xref != -1) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                if (xref >= 0) {\n                    obj = pdf_new_indirect(gctx, pdf, xref, 0);\n                } else {\n                    obj = pdf_trailer(gctx, pdf);\n                }\n                if (pdf_is_stream(gctx, obj))\n                {\n                    res = pdf_load_raw_stream_number(gctx, pdf, xref);\n                    r = JM_BinFromBuffer(gctx, res);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n                if (xref >= 0) {\n                    pdf_drop_obj(gctx, obj);\n                }\n            }\n            fz_catch(gctx)\n            {\n                Py_CLEAR(r);\n                return NULL;\n            }\n            if (!r) Py_RETURN_NONE;\n            return r;\n        }\n\n        //------------------------------------------------------------------\n        // Get decompressed stream of an object by xref\n        // Py_RETURN_NONE if not stream\n        //------------------------------------------------------------------\n        FITZEXCEPTION(xref_stream, !result)\n        CLOSECHECK(xref_stream, \"\"\"Get decompressed xref stream.\"\"\")\n        PyObject *xref_stream(int xref)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            PyObject *r = Py_None;\n            pdf_obj *obj = NULL;\n            fz_var(obj);\n            fz_buffer *res = NULL;\n            fz_var(res);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1) && xref != -1) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                if (xref >= 0) {\n                    obj = pdf_new_indirect(gctx, pdf, xref, 0);\n                } else {\n                    obj = pdf_trailer(gctx, pdf);\n                }\n                if (pdf_is_stream(gctx, obj))\n                {\n                    res = pdf_load_stream_number(gctx, pdf, xref);\n                    r = JM_BinFromBuffer(gctx, res);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n                if (xref >= 0) {\n                    pdf_drop_obj(gctx, obj);\n                }\n            }\n            fz_catch(gctx)\n            {\n                Py_CLEAR(r);\n                return NULL;\n            }\n            return r;\n        }\n\n        //------------------------------------------------------------------\n        // Update an Xref number with a new object given as a string\n        //------------------------------------------------------------------\n        FITZEXCEPTION(update_object, !result)\n        CLOSECHECK(update_object, \"\"\"Replace object definition source.\"\"\")\n        PyObject *update_object(int xref, char *text, struct Page *page = NULL)\n        {\n            pdf_obj *new_obj;\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1)) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                ENSURE_OPERATION(gctx, pdf);\n                // create new object with passed-in string\n                new_obj = JM_pdf_obj_from_str(gctx, pdf, text);\n                pdf_update_object(gctx, pdf, xref, new_obj);\n                pdf_drop_obj(gctx, new_obj);\n                if (page) {\n                    pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) page);\n                    JM_refresh_links(gctx, pdfpage);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // Update a stream identified by its xref\n        //------------------------------------------------------------------\n        FITZEXCEPTION(update_stream, !result)\n        CLOSECHECK(update_stream, \"\"\"Replace xref stream part.\"\"\")\n        PyObject *update_stream(int xref=0, PyObject *stream=NULL, int new=1, int compress=1)\n        {\n            pdf_obj *obj = NULL;\n            fz_var(obj);\n            fz_buffer *res = NULL;\n            fz_var(res);\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1)) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                ENSURE_OPERATION(gctx, pdf);\n                // get the object\n                obj = pdf_new_indirect(gctx, pdf, xref, 0);\n                if (!pdf_is_dict(gctx, obj)) {\n                    RAISEPY(gctx, MSG_IS_NO_DICT, PyExc_ValueError);\n                }\n                res = JM_BufferFromBytes(gctx, stream);\n                if (!res) {\n                    RAISEPY(gctx, MSG_BAD_BUFFER, PyExc_TypeError);\n                }\n                JM_update_stream(gctx, pdf, obj, res, compress);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n                pdf_drop_obj(gctx, obj);\n            }\n            fz_catch(gctx)\n                return NULL;\n            \n            Py_RETURN_NONE;\n        }\n\n\n        //------------------------------------------------------------------\n        // create / refresh the page map\n        //------------------------------------------------------------------\n        FITZEXCEPTION(_make_page_map, !result)\n        CLOSECHECK0(_make_page_map, \"\"\"Make an array page number -> page object.\"\"\")\n        PyObject *_make_page_map()\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            if (!pdf) Py_RETURN_NONE;\n            fz_try(gctx) {\n                pdf_drop_page_tree(gctx, pdf);\n                pdf_load_page_tree(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", pdf->map_page_count);\n        }\n\n\n        //------------------------------------------------------------------\n        // full (deep) copy of one page\n        //------------------------------------------------------------------\n        FITZEXCEPTION(fullcopy_page, !result)\n        CLOSECHECK0(fullcopy_page, \"\"\"Make a full page duplicate.\"\"\")\n        %pythonappend fullcopy_page %{self._reset_page_refs()%}\n        PyObject *fullcopy_page(int pno, int to = -1)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            int page_count = pdf_count_pages(gctx, pdf);\n            fz_buffer *res = NULL, *nres=NULL;\n            fz_buffer *contents_buffer = NULL;\n            fz_var(pdf);\n            fz_var(res);\n            fz_var(nres);\n            fz_var(contents_buffer);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                if (!INRANGE(pno, 0, page_count - 1) ||\n                    !INRANGE(to, -1, page_count - 1)) {\n                    RAISEPY(gctx, MSG_BAD_PAGENO, PyExc_ValueError);\n                }\n\n                pdf_obj *page1 = pdf_resolve_indirect(gctx,\n                                 pdf_lookup_page_obj(gctx, pdf, pno));\n\n                pdf_obj *page2 = pdf_deep_copy_obj(gctx, page1);\n                pdf_obj *old_annots = pdf_dict_get(gctx, page2, PDF_NAME(Annots));\n\n                // copy annotations, but remove Popup and IRT types\n                if (old_annots) {\n                    int i, n = pdf_array_len(gctx, old_annots);\n                    pdf_obj *new_annots = pdf_new_array(gctx, pdf, n);\n                    for (i = 0; i < n; i++) {\n                        pdf_obj *o = pdf_array_get(gctx, old_annots, i);\n                        pdf_obj *subtype = pdf_dict_get(gctx, o, PDF_NAME(Subtype));\n                        if (pdf_name_eq(gctx, subtype, PDF_NAME(Popup))) continue;\n                        if (pdf_dict_gets(gctx, o, \"IRT\")) continue;\n                        pdf_obj *copy_o = pdf_deep_copy_obj(gctx,\n                                            pdf_resolve_indirect(gctx, o));\n                        int xref = pdf_create_object(gctx, pdf);\n                        pdf_update_object(gctx, pdf, xref, copy_o);\n                        pdf_drop_obj(gctx, copy_o);\n                        copy_o = pdf_new_indirect(gctx, pdf, xref, 0);\n                        pdf_dict_del(gctx, copy_o, PDF_NAME(Popup));\n                        pdf_dict_del(gctx, copy_o, PDF_NAME(P));\n                        pdf_array_push_drop(gctx, new_annots, copy_o);\n                    }\n                pdf_dict_put_drop(gctx, page2, PDF_NAME(Annots), new_annots);\n                }\n\n                // copy the old contents stream(s)\n                res = JM_read_contents(gctx, page1);\n\n                // create new /Contents object for page2\n                if (res) {\n                    contents_buffer = fz_new_buffer_from_copied_data(gctx, \"  \", 1);\n                    pdf_obj *contents = pdf_add_stream(gctx, pdf, contents_buffer, NULL, 0);\n                    JM_update_stream(gctx, pdf, contents, res, 1);\n                    pdf_dict_put_drop(gctx, page2, PDF_NAME(Contents), contents);\n                }\n\n                // now insert target page, making sure it is an indirect object\n                int xref = pdf_create_object(gctx, pdf);  // get new xref\n                pdf_update_object(gctx, pdf, xref, page2);  // store new page\n                pdf_drop_obj(gctx, page2);  // give up this object for now\n\n                page2 = pdf_new_indirect(gctx, pdf, xref, 0);  // reread object\n                pdf_insert_page(gctx, pdf, to, page2);  // and store the page\n                pdf_drop_obj(gctx, page2);\n            }\n            fz_always(gctx) {\n                pdf_drop_page_tree(gctx, pdf);\n                fz_drop_buffer(gctx, res);\n                fz_drop_buffer(gctx, nres);\n                fz_drop_buffer(gctx, contents_buffer);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //------------------------------------------------------------------\n        // move or copy one page\n        //------------------------------------------------------------------\n        FITZEXCEPTION(_move_copy_page, !result)\n        CLOSECHECK0(_move_copy_page, \"\"\"Move or copy a PDF page reference.\"\"\")\n        %pythonappend _move_copy_page %{self._reset_page_refs()%}\n        PyObject *_move_copy_page(int pno, int nb, int before, int copy)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            int i1, i2, pos, count, same = 0;\n            pdf_obj *parent1 = NULL, *parent2 = NULL, *parent = NULL;\n            pdf_obj *kids1, *kids2;\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                // get the two page objects -----------------------------------\n                // locate the /Kids arrays and indices in each\n                pdf_obj *page1 = pdf_lookup_page_loc(gctx, pdf, pno, &parent1, &i1);\n                kids1 = pdf_dict_get(gctx, parent1, PDF_NAME(Kids));\n\n                pdf_obj *page2 = pdf_lookup_page_loc(gctx, pdf, nb, &parent2, &i2);\n                (void) page2;\n                kids2 = pdf_dict_get(gctx, parent2, PDF_NAME(Kids));\n\n                if (before)  // calc index of source page in target /Kids\n                    pos = i2;\n                else\n                    pos = i2 + 1;\n\n                // same /Kids array? ------------------------------------------\n                same = pdf_objcmp(gctx, kids1, kids2);\n\n                // put source page in target /Kids array ----------------------\n                if (!copy && same != 0)  // update parent in page object\n                {\n                    pdf_dict_put(gctx, page1, PDF_NAME(Parent), parent2);\n                }\n                pdf_array_insert(gctx, kids2, page1, pos);\n\n                if (same != 0) // different /Kids arrays ----------------------\n                {\n                    parent = parent2;\n                    while (parent)  // increase /Count objects in parents\n                    {\n                        count = pdf_dict_get_int(gctx, parent, PDF_NAME(Count));\n                        pdf_dict_put_int(gctx, parent, PDF_NAME(Count), count + 1);\n                        parent = pdf_dict_get(gctx, parent, PDF_NAME(Parent));\n                    }\n                    if (!copy)  // delete original item\n                    {\n                        pdf_array_delete(gctx, kids1, i1);\n                        parent = parent1;\n                        while (parent) // decrease /Count objects in parents\n                        {\n                            count = pdf_dict_get_int(gctx, parent, PDF_NAME(Count));\n                            pdf_dict_put_int(gctx, parent, PDF_NAME(Count), count - 1);\n                            parent = pdf_dict_get(gctx, parent, PDF_NAME(Parent));\n                        }\n                    }\n                }\n                else {  // same /Kids array\n                    if (copy) {  // source page is copied\n                        parent = parent2;\n                        while (parent) // increase /Count object in parents\n                        {\n                            count = pdf_dict_get_int(gctx, parent, PDF_NAME(Count));\n                            pdf_dict_put_int(gctx, parent, PDF_NAME(Count), count + 1);\n                            parent = pdf_dict_get(gctx, parent, PDF_NAME(Parent));\n                        }\n                    } else {\n                        if (i1 < pos)\n                            pdf_array_delete(gctx, kids1, i1);\n                        else\n                            pdf_array_delete(gctx, kids1, i1 + 1);\n                    }\n                }\n                if (pdf->rev_page_map) {  // page map no longer valid: drop it\n                    pdf_drop_page_tree(gctx, pdf);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION(_remove_toc_item, !result)\n        PyObject *_remove_toc_item(int xref)\n        {\n            // \"remove\" bookmark by letting it point to nowhere\n            pdf_obj *item = NULL, *color;\n            int i;\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_try(gctx) {\n                item = pdf_new_indirect(gctx, pdf, xref, 0);\n                pdf_dict_del(gctx, item, PDF_NAME(Dest));\n                pdf_dict_del(gctx, item, PDF_NAME(A));\n                color = pdf_new_array(gctx, pdf, 3);\n                for (i=0; i < 3; i++) {\n                    pdf_array_push_real(gctx, color, 0.8);\n                }\n                pdf_dict_put_drop(gctx, item, PDF_NAME(C), color);\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, item);\n            }\n            fz_catch(gctx){\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION(_update_toc_item, !result)\n        PyObject *_update_toc_item(int xref, char *action=NULL, char *title=NULL, int flags=0, PyObject *collapse=NULL, PyObject *color=NULL)\n        {\n            // \"update\" bookmark by letting it point to nowhere\n            pdf_obj *item = NULL;\n            pdf_obj *obj = NULL;\n            Py_ssize_t i;\n            double f;\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            fz_try(gctx) {\n                item = pdf_new_indirect(gctx, pdf, xref, 0);\n                if (title) {\n                    pdf_dict_put_text_string(gctx, item, PDF_NAME(Title), title);\n                }\n                if (action) {\n                    pdf_dict_del(gctx, item, PDF_NAME(Dest));\n                    obj = JM_pdf_obj_from_str(gctx, pdf, action);\n                    pdf_dict_put_drop(gctx, item, PDF_NAME(A), obj);\n                }\n                pdf_dict_put_int(gctx, item, PDF_NAME(F), flags);\n                if (EXISTS(color)) {\n                    pdf_obj *c = pdf_new_array(gctx, pdf, 3);\n                    for (i = 0; i < 3; i++) {\n                        JM_FLOAT_ITEM(color, i, &f);\n                        pdf_array_push_real(gctx, c, f);\n                    }\n                    pdf_dict_put_drop(gctx, item, PDF_NAME(C), c);\n                } else if (color != Py_None) {\n                    pdf_dict_del(gctx, item, PDF_NAME(C));\n                }\n                if (collapse != Py_None) {\n                    if (pdf_dict_get(gctx, item, PDF_NAME(Count))) {\n                        i = pdf_dict_get_int(gctx, item, PDF_NAME(Count));\n                        if ((i < 0 && collapse == Py_False) || (i > 0 && collapse == Py_True)) {\n                            i = i * (-1);\n                            pdf_dict_put_int(gctx, item, PDF_NAME(Count), i);\n                        }\n                    }\n                }\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, item);\n            }\n            fz_catch(gctx){\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //------------------------------------------------------------------\n        // PDF page label getting / setting\n        //------------------------------------------------------------------\n        FITZEXCEPTION(_get_page_labels, !result)\n        PyObject *\n        _get_page_labels()\n        {\n            pdf_obj *obj, *nums, *kids;\n            PyObject *rc = NULL;\n            int i, n;\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n\n            pdf_obj *pagelabels = NULL;\n            fz_var(pagelabels);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                rc = PyList_New(0);\n                pagelabels = pdf_new_name(gctx, \"PageLabels\");\n                obj = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                   PDF_NAME(Root), pagelabels, NULL);\n                if (!obj) {\n                    goto finished;\n                }\n                // simple case: direct /Nums object\n                nums = pdf_resolve_indirect(gctx,\n                       pdf_dict_get(gctx, obj, PDF_NAME(Nums)));\n                if (nums) {\n                    JM_get_page_labels(gctx, rc, nums);\n                    goto finished;\n                }\n                // case: /Kids/Nums\n                nums = pdf_resolve_indirect(gctx,\n                           pdf_dict_getl(gctx, obj, PDF_NAME(Kids), PDF_NAME(Nums), NULL)\n                );\n                if (nums) {\n                    JM_get_page_labels(gctx, rc, nums);\n                    goto finished;\n                }\n                // case: /Kids is an array of multiple /Nums\n                kids = pdf_resolve_indirect(gctx,\n                       pdf_dict_get(gctx, obj, PDF_NAME(Kids)));\n                if (!kids || !pdf_is_array(gctx, kids)) {\n                    goto finished;\n                }\n\n                n = pdf_array_len(gctx, kids);\n                for (i = 0; i < n; i++) {\n                    nums = pdf_resolve_indirect(gctx,\n                           pdf_dict_get(gctx,\n                           pdf_array_get(gctx, kids, i),\n                           PDF_NAME(Nums)));\n                    JM_get_page_labels(gctx, rc, nums);\n                }\n                finished:;\n            }\n            fz_always(gctx) {\n                PyErr_Clear();\n                pdf_drop_obj(gctx, pagelabels);\n            }\n            fz_catch(gctx){\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(_set_page_labels, !result)\n        %pythonappend _set_page_labels %{\n        xref = self.pdf_catalog()\n        text = self.xref_object(xref, compressed=True)\n        text = text.replace(\"/Nums[]\", \"/Nums[%s]\" % labels)\n        self.update_object(xref, text)%}\n        PyObject *\n        _set_page_labels(char *labels)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) $self);\n            pdf_obj *pagelabels = NULL;\n            fz_var(pagelabels);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                pagelabels = pdf_new_name(gctx, \"PageLabels\");\n                pdf_obj *root = pdf_dict_get(gctx, pdf_trailer(gctx, pdf), PDF_NAME(Root));\n                pdf_dict_del(gctx, root, pagelabels);\n                pdf_dict_putl_drop(gctx, root, pdf_new_array(gctx, pdf, 0), pagelabels, PDF_NAME(Nums), NULL);\n            }\n            fz_always(gctx) {\n                PyErr_Clear();\n                pdf_drop_obj(gctx, pagelabels);\n            }\n            fz_catch(gctx){\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //------------------------------------------------------------------\n        // PDF Optional Content functions\n        //------------------------------------------------------------------\n        FITZEXCEPTION(get_layers, !result)\n        CLOSECHECK0(get_layers, \"\"\"Show optional OC layers.\"\"\")\n        PyObject *\n        get_layers()\n        {\n            PyObject *rc = NULL;\n            pdf_layer_config info = {NULL, NULL};\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                int i, n = pdf_count_layer_configs(gctx, pdf);\n                if (n == 1) {\n                    pdf_obj *obj = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                   PDF_NAME(Root), PDF_NAME(OCProperties), PDF_NAME(Configs), NULL);\n                    if (!pdf_is_array(gctx, obj)) n = 0;\n                }\n                rc = PyTuple_New(n);\n                for (i = 0; i < n; i++) {\n                    pdf_layer_config_info(gctx, pdf, i, &info);\n                    PyObject *item = Py_BuildValue(\"{s:i,s:s,s:s}\",\n                        \"number\", i, \"name\", info.name, \"creator\", info.creator);\n                    PyTuple_SET_ITEM(rc, i, item);\n                    info.name = NULL;\n                    info.creator = NULL;\n                }\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(switch_layer, !result)\n        CLOSECHECK0(switch_layer, \"\"\"Activate an OC layer.\"\"\")\n        PyObject *\n        switch_layer(int config, int as_default=0)\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                pdf_obj *cfgs = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                   PDF_NAME(Root), PDF_NAME(OCProperties), PDF_NAME(Configs), NULL);\n                if (!pdf_is_array(gctx, cfgs) || !pdf_array_len(gctx, cfgs)) {\n                    if (config < 1) goto finished;\n                    RAISEPY(gctx, MSG_BAD_OC_LAYER, PyExc_ValueError);\n                }\n                if (config < 0) goto finished;\n                pdf_select_layer_config(gctx, pdf, config);\n                if (as_default) {\n                    pdf_set_layer_config_as_default(gctx, pdf);\n                    pdf_read_ocg(gctx, pdf);\n                }\n                finished:;\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(get_layer, !result)\n        CLOSECHECK0(get_layer, \"\"\"Content of ON, OFF, RBGroups of an OC layer.\"\"\")\n        PyObject *\n        get_layer(int config=-1)\n        {\n            PyObject *rc;\n            pdf_obj *obj = NULL;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                pdf_obj *ocp = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                   PDF_NAME(Root), PDF_NAME(OCProperties), NULL);\n                if (!ocp) {\n                    rc = Py_BuildValue(\"s\", NULL);\n                    goto finished;\n                }\n                if (config == -1) {\n                    obj = pdf_dict_get(gctx, ocp, PDF_NAME(D));\n                } else {\n                    obj = pdf_array_get(gctx, pdf_dict_get(gctx, ocp, PDF_NAME(Configs)), config);\n                }\n                if (!obj) {\n                    RAISEPY(gctx, MSG_BAD_OC_CONFIG, PyExc_ValueError);\n                }\n                rc = JM_get_ocg_arrays(gctx, obj);\n                finished:;\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                PyErr_Clear();\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(set_layer, !result)\n        %pythonprepend set_layer\n%{\"\"\"Set the PDF keys /ON, /OFF, /RBGroups of an OC layer.\"\"\"\nif self.is_closed:\n    raise ValueError(\"document closed\")\nocgs = set(self.get_ocgs().keys())\nif ocgs == set():\n    raise ValueError(\"document has no optional content\")\n\nif on:\n    if type(on) not in (list, tuple):\n        raise ValueError(\"bad type: 'on'\")\n    s = set(on).difference(ocgs)\n    if s != set():\n        raise ValueError(\"bad OCGs in 'on': %s\" % s)\n\nif off:\n    if type(off) not in (list, tuple):\n        raise ValueError(\"bad type: 'off'\")\n    s = set(off).difference(ocgs)\n    if s != set():\n        raise ValueError(\"bad OCGs in 'off': %s\" % s)\n\nif locked:\n    if type(locked) not in (list, tuple):\n        raise ValueError(\"bad type: 'locked'\")\n    s = set(locked).difference(ocgs)\n    if s != set():\n        raise ValueError(\"bad OCGs in 'locked': %s\" % s)\n\nif rbgroups:\n    if type(rbgroups) not in (list, tuple):\n        raise ValueError(\"bad type: 'rbgroups'\")\n    for x in rbgroups:\n        if not type(x) in (list, tuple):\n            raise ValueError(\"bad RBGroup '%s'\" % x)\n        s = set(x).difference(ocgs)\n        if s != set():\n            raise ValueError(\"bad OCGs in RBGroup: %s\" % s)\n\nif basestate:\n    basestate = str(basestate).upper()\n    if basestate == \"UNCHANGED\":\n        basestate = \"Unchanged\"\n    if basestate not in (\"ON\", \"OFF\", \"Unchanged\"):\n        raise ValueError(\"bad 'basestate'\")\n%}\n        PyObject *\n        set_layer(int config, const char *basestate=NULL, PyObject *on=NULL,\n                    PyObject *off=NULL, PyObject *rbgroups=NULL, PyObject *locked=NULL)\n        {\n            pdf_obj *obj = NULL;\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                pdf_obj *ocp = pdf_dict_getl(gctx, pdf_trailer(gctx, pdf),\n                                   PDF_NAME(Root), PDF_NAME(OCProperties), NULL);\n                if (!ocp) {\n                    goto finished;\n                }\n                if (config == -1) {\n                    obj = pdf_dict_get(gctx, ocp, PDF_NAME(D));\n                } else {\n                    obj = pdf_array_get(gctx, pdf_dict_get(gctx, ocp, PDF_NAME(Configs)), config);\n                }\n                if (!obj) {\n                    RAISEPY(gctx, MSG_BAD_OC_CONFIG, PyExc_ValueError);\n                }\n                JM_set_ocg_arrays(gctx, obj, basestate, on, off, rbgroups, locked);\n                pdf_read_ocg(gctx, pdf);\n                finished:;\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(add_layer, !result)\n        CLOSECHECK0(add_layer, \"\"\"Add a new OC layer.\"\"\")\n        PyObject *add_layer(char *name, char *creator=NULL, PyObject *on=NULL)\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                JM_add_layer_config(gctx, pdf, name, creator, on);\n                pdf_read_ocg(gctx, pdf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(layer_ui_configs, !result)\n        CLOSECHECK0(layer_ui_configs, \"\"\"Show OC visibility status modifiable by user.\"\"\")\n        PyObject *layer_ui_configs()\n        {\n            typedef struct\n            {\n                const char *text;\n                int depth;\n                pdf_layer_config_ui_type type;\n                int selected;\n                int locked;\n            } pdf_layer_config_ui;\n            PyObject *rc = NULL;\n\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                pdf_layer_config_ui info;\n                int i, n = pdf_count_layer_config_ui(gctx, pdf);\n                rc = PyTuple_New(n);\n                char *type = NULL;\n                for (i = 0; i < n; i++) {\n                    pdf_layer_config_ui_info(gctx, pdf, i, (void *) &info);\n                    switch (info.type)\n                    {\n                        case (1): type = \"checkbox\"; break;\n                        case (2): type = \"radiobox\"; break;\n                        default: type = \"label\"; break;\n                    }\n                    PyObject *item = Py_BuildValue(\"{s:i,s:N,s:i,s:s,s:N,s:N}\",\n                        \"number\", i,\n                        \"text\", JM_UnicodeFromStr(info.text),\n                        \"depth\", info.depth,\n                        \"type\", type,\n                        \"on\", JM_BOOL(info.selected),\n                        \"locked\", JM_BOOL(info.locked));\n                    PyTuple_SET_ITEM(rc, i, item);\n                }\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(set_layer_ui_config, !result)\n        CLOSECHECK0(set_layer_ui_config, )\n        %pythonprepend set_layer_ui_config %{\n        \"\"\"Set / unset OC intent configuration.\"\"\"\n        # The user might have given the name instead of sequence number, \n        # so select by that name and continue with corresp. number\n        if isinstance(number, str):\n            select = [ui[\"number\"] for ui in self.layer_ui_configs() if ui[\"text\"] == number]\n            if select == []:\n                raise ValueError(f\"bad OCG '{number}'.\")\n            number = select[0]  # this is the number for the name\n        %}\n        PyObject *set_layer_ui_config(int number, int action=0)\n        {\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                switch (action)\n                {\n                    case (1):\n                        pdf_toggle_layer_config_ui(gctx, pdf, number);\n                        break;\n                    case (2):\n                        pdf_deselect_layer_config_ui(gctx, pdf, number);\n                        break;\n                    default:\n                        pdf_select_layer_config_ui(gctx, pdf, number);\n                        break;\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(get_ocgs, !result)\n        CLOSECHECK0(get_ocgs, \"\"\"Show existing optional content groups.\"\"\")\n        PyObject *\n        get_ocgs()\n        {\n            PyObject *rc = NULL;\n            pdf_obj *ci = pdf_new_name(gctx, \"CreatorInfo\");\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n                pdf_obj *ocgs = pdf_dict_getl(gctx,\n                                pdf_dict_get(gctx,\n                                pdf_trailer(gctx, pdf), PDF_NAME(Root)),\n                                PDF_NAME(OCProperties), PDF_NAME(OCGs), NULL);\n                rc = PyDict_New();\n                if (!pdf_is_array(gctx, ocgs)) goto fertig;\n                int i, n = pdf_array_len(gctx, ocgs);\n                for (i = 0; i < n; i++) {\n                    pdf_obj *ocg = pdf_array_get(gctx, ocgs, i);\n                    int xref = pdf_to_num(gctx, ocg);\n                    const char *name = pdf_to_text_string(gctx, pdf_dict_get(gctx, ocg, PDF_NAME(Name)));\n                    pdf_obj *obj = pdf_dict_getl(gctx, ocg, PDF_NAME(Usage), ci, PDF_NAME(Subtype), NULL);\n                    const char *usage = NULL;\n                    if (obj) usage = pdf_to_name(gctx, obj);\n                    PyObject *intents = PyList_New(0);\n                    pdf_obj *intent = pdf_dict_get(gctx, ocg, PDF_NAME(Intent));\n                    if (intent) {\n                        if (pdf_is_name(gctx, intent)) {\n                            LIST_APPEND_DROP(intents, Py_BuildValue(\"s\", pdf_to_name(gctx, intent)));\n                        } else if (pdf_is_array(gctx, intent)) {\n                            int j, m = pdf_array_len(gctx, intent);\n                            for (j = 0; j < m; j++) {\n                                pdf_obj *o = pdf_array_get(gctx, intent, j);\n                                if (pdf_is_name(gctx, o))\n                                    LIST_APPEND_DROP(intents, Py_BuildValue(\"s\", pdf_to_name(gctx, o)));\n                            }\n                        }\n                    }\n                    int hidden = pdf_is_ocg_hidden(gctx, pdf, NULL, usage, ocg);\n                    PyObject *item = Py_BuildValue(\"{s:s,s:O,s:O,s:s}\",\n                            \"name\", name,\n                            \"intent\", intents,\n                            \"on\", JM_BOOL(!hidden),\n                            \"usage\", usage);\n                    Py_DECREF(intents);\n                    PyObject *temp = Py_BuildValue(\"i\", xref);\n                    DICT_SETITEM_DROP(rc, temp, item);\n                    Py_DECREF(temp);\n                }\n                fertig:;\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, ci);\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(add_ocg, !result)\n        CLOSECHECK0(add_ocg, \"\"\"Add new optional content group.\"\"\")\n        PyObject *\n        add_ocg(char *name, int config=-1, int on=1, PyObject *intent=NULL, const char *usage=NULL)\n        {\n            int xref = 0;\n            pdf_obj *obj = NULL, *cfg = NULL;\n            pdf_obj *indocg = NULL;\n            pdf_obj *ocg = NULL;\n            pdf_obj *ci_name = NULL;\n            fz_var(indocg);\n            fz_var(ocg);\n            fz_var(ci_name);\n            fz_try(gctx) {\n                pdf_document *pdf = pdf_specifics(gctx, (fz_document *) self);\n                ASSERT_PDF(pdf);\n\n                // ------------------------------\n                // make the OCG\n                // ------------------------------\n                ocg = pdf_add_new_dict(gctx, pdf, 3);\n                pdf_dict_put(gctx, ocg, PDF_NAME(Type), PDF_NAME(OCG));\n                pdf_dict_put_text_string(gctx, ocg, PDF_NAME(Name), name);\n                pdf_obj *intents = pdf_dict_put_array(gctx, ocg, PDF_NAME(Intent), 2);\n                if (!EXISTS(intent)) {\n                    pdf_array_push(gctx, intents, PDF_NAME(View));\n                } else if (!PyUnicode_Check(intent)) {\n                    int i, n = PySequence_Size(intent);\n                    for (i = 0; i < n; i++) {\n                        PyObject *item = PySequence_ITEM(intent, i);\n                        char *c = JM_StrAsChar(item);\n                        if (c) {\n                            pdf_array_push_drop(gctx, intents, pdf_new_name(gctx, c));\n                        }\n                        Py_DECREF(item);\n                    }\n                } else {\n                    char *c = JM_StrAsChar(intent);\n                    if (c) {\n                        pdf_array_push_drop(gctx, intents, pdf_new_name(gctx, c));\n                    }\n                }\n                pdf_obj *use_for = pdf_dict_put_dict(gctx, ocg, PDF_NAME(Usage), 3);\n                ci_name = pdf_new_name(gctx, \"CreatorInfo\");\n                pdf_obj *cre_info = pdf_dict_put_dict(gctx, use_for, ci_name, 2);\n                pdf_dict_put_text_string(gctx, cre_info, PDF_NAME(Creator), \"PyMuPDF\");\n                if (usage) {\n                    pdf_dict_put_name(gctx, cre_info, PDF_NAME(Subtype), usage);\n                } else {\n                    pdf_dict_put_name(gctx, cre_info, PDF_NAME(Subtype), \"Artwork\");\n                }\n                indocg = pdf_add_object(gctx, pdf, ocg);\n\n                // ------------------------------\n                // Insert OCG in the right config\n                // ------------------------------\n                pdf_obj *ocp = JM_ensure_ocproperties(gctx, pdf);\n                obj = pdf_dict_get(gctx, ocp, PDF_NAME(OCGs));\n                pdf_array_push(gctx, obj, indocg);\n\n                if (config > -1) {\n                    obj = pdf_dict_get(gctx, ocp, PDF_NAME(Configs));\n                    if (!pdf_is_array(gctx, obj)) {\n                        RAISEPY(gctx, MSG_BAD_OC_CONFIG, PyExc_ValueError);\n                    }\n                    cfg = pdf_array_get(gctx, obj, config);\n                    if (!cfg) {\n                        RAISEPY(gctx, MSG_BAD_OC_CONFIG, PyExc_ValueError);\n                    }\n                } else {\n                    cfg = pdf_dict_get(gctx, ocp, PDF_NAME(D));\n                }\n\n                obj = pdf_dict_get(gctx, cfg, PDF_NAME(Order));\n                if (!obj) {\n                    obj = pdf_dict_put_array(gctx, cfg, PDF_NAME(Order), 1);\n                }\n                pdf_array_push(gctx, obj, indocg);\n                if (on) {\n                    obj = pdf_dict_get(gctx, cfg, PDF_NAME(ON));\n                    if (!obj) {\n                        obj = pdf_dict_put_array(gctx, cfg, PDF_NAME(ON), 1);\n                    }\n                } else {\n                    obj = pdf_dict_get(gctx, cfg, PDF_NAME(OFF));\n                    if (!obj) {\n                        obj = pdf_dict_put_array(gctx, cfg, PDF_NAME(OFF), 1);\n                    }\n                }\n                pdf_array_push(gctx, obj, indocg);\n\n                // let MuPDF take note: re-read OCProperties\n                pdf_read_ocg(gctx, pdf);\n\n                xref = pdf_to_num(gctx, indocg);\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, indocg);\n                pdf_drop_obj(gctx, ocg);\n                pdf_drop_obj(gctx, ci_name);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xref);\n        }\n        \n        struct Annot;\n\n        void internal_keep_annot(struct Annot* annot)\n        {\n            pdf_keep_annot(gctx, (pdf_annot*) annot);\n        }\n\n        //------------------------------------------------------------------\n        // Initialize document: set outline and metadata properties\n        //------------------------------------------------------------------\n        %pythoncode %{\n            def init_doc(self):\n                if self.is_encrypted:\n                    raise ValueError(\"cannot initialize - document still encrypted\")\n                self._outline = self._loadOutline()\n                if self._outline:\n                    self._outline.thisown = True\n                self.metadata = dict([(k,self._getMetadata(v)) for k,v in {'format':'format', 'title':'info:Title', 'author':'info:Author','subject':'info:Subject', 'keywords':'info:Keywords','creator':'info:Creator', 'producer':'info:Producer', 'creationDate':'info:CreationDate', 'modDate':'info:ModDate', 'trapped':'info:Trapped'}.items()])\n                self.metadata['encryption'] = None if self._getMetadata('encryption')=='None' else self._getMetadata('encryption')\n\n            outline = property(lambda self: self._outline)\n\n\n            def get_page_fonts(self, pno: int, full: bool =False) -> list:\n                \"\"\"Retrieve a list of fonts used on a page.\n                \"\"\"\n                if self.is_closed or self.is_encrypted:\n                    raise ValueError(\"document closed or encrypted\")\n                if not self.is_pdf:\n                    return ()\n                if type(pno) is not int:\n                    try:\n                        pno = pno.number\n                    except:\n                        raise ValueError(\"need a Page or page number\")\n                val = self._getPageInfo(pno, 1)\n                if full is False:\n                    return [v[:-1] for v in val]\n                return val\n\n\n            def get_page_images(self, pno: int, full: bool =False) -> list:\n                \"\"\"Retrieve a list of images used on a page.\n                \"\"\"\n                if self.is_closed or self.is_encrypted:\n                    raise ValueError(\"document closed or encrypted\")\n                if not self.is_pdf:\n                    return ()\n                if type(pno) is not int:\n                    try:\n                        pno = pno.number\n                    except:\n                        raise ValueError(\"need a Page or page number\")\n                val = self._getPageInfo(pno, 2)\n                if full is False:\n                    return [v[:-1] for v in val]\n                return val\n\n\n            def get_page_xobjects(self, pno: int) -> list:\n                \"\"\"Retrieve a list of XObjects used on a page.\n                \"\"\"\n                if self.is_closed or self.is_encrypted:\n                    raise ValueError(\"document closed or encrypted\")\n                if not self.is_pdf:\n                    return ()\n                if type(pno) is not int:\n                    try:\n                        pno = pno.number\n                    except:\n                        raise ValueError(\"need a Page or page number\")\n                val = self._getPageInfo(pno, 3)\n                rc = [(v[0], v[1], v[2], Rect(v[3])) for v in val]\n                return rc\n\n\n            def xref_is_image(self, xref):\n                \"\"\"Check if xref is an image object.\"\"\"\n                if self.is_closed or self.is_encrypted:\n                    raise ValueError(\"document closed or encrypted\")\n                if self.xref_get_key(xref, \"Subtype\")[1] == \"/Image\":\n                    return True\n                return False\n\n            def xref_is_font(self, xref):\n                \"\"\"Check if xref is a font object.\"\"\"\n                if self.is_closed or self.is_encrypted:\n                    raise ValueError(\"document closed or encrypted\")\n                if self.xref_get_key(xref, \"Type\")[1] == \"/Font\":\n                    return True\n                return False\n\n            def xref_is_xobject(self, xref):\n                \"\"\"Check if xref is a form xobject.\"\"\"\n                if self.is_closed or self.is_encrypted:\n                    raise ValueError(\"document closed or encrypted\")\n                if self.xref_get_key(xref, \"Subtype\")[1] == \"/Form\":\n                    return True\n                return False\n\n            def copy_page(self, pno: int, to: int =-1):\n                \"\"\"Copy a page within a PDF document.\n\n                This will only create another reference of the same page object.\n                Args:\n                    pno: source page number\n                    to: put before this page, '-1' means after last page.\n                \"\"\"\n                if self.is_closed:\n                    raise ValueError(\"document closed\")\n\n                page_count = len(self)\n                if (\n                    pno not in range(page_count) or\n                    to not in range(-1, page_count)\n                   ):\n                    raise ValueError(\"bad page number(s)\")\n                before = 1\n                copy = 1\n                if to == -1:\n                    to = page_count - 1\n                    before = 0\n\n                return self._move_copy_page(pno, to, before, copy)\n\n            def move_page(self, pno: int, to: int =-1):\n                \"\"\"Move a page within a PDF document.\n\n                Args:\n                    pno: source page number.\n                    to: put before this page, '-1' means after last page.\n                \"\"\"\n                if self.is_closed:\n                    raise ValueError(\"document closed\")\n\n                page_count = len(self)\n                if (\n                    pno not in range(page_count) or\n                    to not in range(-1, page_count)\n                   ):\n                    raise ValueError(\"bad page number(s)\")\n                before = 1\n                copy = 0\n                if to == -1:\n                    to = page_count - 1\n                    before = 0\n\n                return self._move_copy_page(pno, to, before, copy)\n\n            def delete_page(self, pno: int =-1):\n                \"\"\" Delete one page from a PDF.\n                \"\"\"\n                if not self.is_pdf:\n                    raise ValueError(\"is no PDF\")\n                if self.is_closed:\n                    raise ValueError(\"document closed\")\n\n                page_count = self.page_count\n                while pno < 0:\n                    pno += page_count\n\n                if pno >= page_count:\n                    raise ValueError(\"bad page number(s)\")\n\n                # remove TOC bookmarks pointing to deleted page\n                toc = self.get_toc()\n                ol_xrefs = self.get_outline_xrefs()\n                for i, item in enumerate(toc):\n                    if item[2] == pno + 1:\n                        self._remove_toc_item(ol_xrefs[i])\n\n                self._remove_links_to(frozenset((pno,)))\n                self._delete_page(pno)\n                self._reset_page_refs()\n\n\n            def delete_pages(self, *args, **kw):\n                \"\"\"Delete pages from a PDF.\n\n                Args:\n                    Either keywords 'from_page'/'to_page', or two integers to\n                    specify the first/last page to delete.\n                    Or a list/tuple/range object, which can contain arbitrary\n                    page numbers.\n                \"\"\"\n                if not self.is_pdf:\n                    raise ValueError(\"is no PDF\")\n                if self.is_closed:\n                    raise ValueError(\"document closed\")\n\n                page_count = self.page_count  # page count of document\n                f = t = -1\n                if kw:  # check if keywords were used\n                    if args:  # then no positional args are allowed\n                        raise ValueError(\"cannot mix keyword and positional argument\")\n                    f = kw.get(\"from_page\", -1)  # first page to delete\n                    t = kw.get(\"to_page\", -1)  # last page to delete\n                    while f < 0:\n                        f += page_count\n                    while t < 0:\n                        t += page_count\n                    if not f <= t < page_count:\n                        raise ValueError(\"bad page number(s)\")\n                    numbers = tuple(range(f, t + 1))\n                else:\n                    if len(args) > 2 or args == []:\n                        raise ValueError(\"need 1 or 2 positional arguments\")\n                    if len(args) == 2:\n                        f, t = args\n                        if not (type(f) is int and type(t) is int):\n                            raise ValueError(\"both arguments must be int\")\n                        if f > t:\n                            f, t = t, f\n                        if not f <= t < page_count:\n                            raise ValueError(\"bad page number(s)\")\n                        numbers = tuple(range(f, t + 1))\n                    else:\n                        r = args[0]\n                        if type(r) not in (int, range, list, tuple):\n                            raise ValueError(\"need int or sequence if one argument\")\n                        numbers = tuple(r)\n\n                numbers = list(map(int, set(numbers)))  # ensure unique integers\n                if numbers == []:\n                    print(\"nothing to delete\")\n                    return\n                numbers.sort()\n                if numbers[0] < 0 or numbers[-1] >= page_count:\n                    raise ValueError(\"bad page number(s)\")\n                frozen_numbers = frozenset(numbers)\n                toc = self.get_toc()\n                for i, xref in enumerate(self.get_outline_xrefs()):\n                    if toc[i][2] - 1 in frozen_numbers:\n                        self._remove_toc_item(xref)  # remove target in PDF object\n\n                self._remove_links_to(frozen_numbers)\n\n                for i in reversed(numbers):  # delete pages, last to first\n                    self._delete_page(i)\n\n                self._reset_page_refs()\n\n\n            def saveIncr(self):\n                \"\"\" Save PDF incrementally\"\"\"\n                return self.save(self.name, incremental=True, encryption=PDF_ENCRYPT_KEEP)\n\n\n            def ez_save(self, filename, garbage=3, clean=False,\n            deflate=True, deflate_images=True, deflate_fonts=True,\n            incremental=False, ascii=False, expand=False, linear=False,\n            pretty=False, encryption=1, permissions=4095,\n            owner_pw=None, user_pw=None, no_new_id=True):\n                \"\"\" Save PDF using some different defaults\"\"\"\n                return self.save(filename, garbage=garbage,\n                clean=clean,\n                deflate=deflate,\n                deflate_images=deflate_images,\n                deflate_fonts=deflate_fonts,\n                incremental=incremental,\n                ascii=ascii,\n                expand=expand,\n                linear=linear,\n                pretty=pretty,\n                encryption=encryption,\n                permissions=permissions,\n                owner_pw=owner_pw,\n                user_pw=user_pw,\n                no_new_id=no_new_id,)\n\n\n            def reload_page(self, page: \"struct Page *\") -> \"struct Page *\":\n                \"\"\"Make a fresh copy of a page.\"\"\"\n                old_annots = {}  # copy annot references to here\n                pno = page.number  # save the page number\n                for k, v in page._annot_refs.items():  # save the annot dictionary\n                    # We need to call pdf_keep_annot() here, otherwise `v`'s\n                    # refcount can reach zero even if there is an external\n                    # reference.\n                    self.internal_keep_annot(v)\n                    old_annots[k] = v\n                page._erase()  # remove the page\n                page = None\n                TOOLS.store_shrink(100)\n                page = self.load_page(pno)  # reload the page\n\n                # copy annot refs over to the new dictionary\n                page_proxy = weakref.proxy(page)\n                for k, v in old_annots.items():\n                    annot = old_annots[k]\n                    annot.parent = page_proxy  # refresh parent to new page\n                    page._annot_refs[k] = annot\n                return page\n\n\n            @property\n            def pagemode(self) -> str:\n                \"\"\"Return the PDF PageMode value.\n                \"\"\"\n                xref = self.pdf_catalog()\n                if xref == 0:\n                    return None\n                rc = self.xref_get_key(xref, \"PageMode\")\n                if rc[0] == \"null\":\n                    return \"UseNone\"\n                if rc[0] == \"name\":\n                    return rc[1][1:]\n                return \"UseNone\"\n\n\n            def set_pagemode(self, pagemode: str):\n                \"\"\"Set the PDF PageMode value.\"\"\"\n                valid = (\"UseNone\", \"UseOutlines\", \"UseThumbs\", \"FullScreen\", \"UseOC\", \"UseAttachments\")\n                xref = self.pdf_catalog()\n                if xref == 0:\n                    raise ValueError(\"not a PDF\")\n                if not pagemode:\n                    raise ValueError(\"bad PageMode value\")\n                if pagemode[0] == \"/\":\n                    pagemode = pagemode[1:]\n                for v in valid:\n                    if pagemode.lower() == v.lower():\n                        self.xref_set_key(xref, \"PageMode\", f\"/{v}\")\n                        return True\n                raise ValueError(\"bad PageMode value\")\n\n\n            @property\n            def pagelayout(self) -> str:\n                \"\"\"Return the PDF PageLayout value.\n                \"\"\"\n                xref = self.pdf_catalog()\n                if xref == 0:\n                    return None\n                rc = self.xref_get_key(xref, \"PageLayout\")\n                if rc[0] == \"null\":\n                    return \"SinglePage\"\n                if rc[0] == \"name\":\n                    return rc[1][1:]\n                return \"SinglePage\"\n\n\n            def set_pagelayout(self, pagelayout: str):\n                \"\"\"Set the PDF PageLayout value.\"\"\"\n                valid = (\"SinglePage\", \"OneColumn\", \"TwoColumnLeft\", \"TwoColumnRight\", \"TwoPageLeft\", \"TwoPageRight\")\n                xref = self.pdf_catalog()\n                if xref == 0:\n                    raise ValueError(\"not a PDF\")\n                if not pagelayout:\n                    raise ValueError(\"bad PageLayout value\")\n                if pagelayout[0] == \"/\":\n                    pagelayout = pagelayout[1:]\n                for v in valid:\n                    if pagelayout.lower() == v.lower():\n                        self.xref_set_key(xref, \"PageLayout\", f\"/{v}\")\n                        return True\n                raise ValueError(\"bad PageLayout value\")\n\n\n            @property\n            def markinfo(self) -> dict:\n                \"\"\"Return the PDF MarkInfo value.\"\"\"\n                xref = self.pdf_catalog()\n                if xref == 0:\n                    return None\n                rc = self.xref_get_key(xref, \"MarkInfo\")\n                if rc[0] == \"null\":\n                    return {}\n                if rc[0] == \"xref\":\n                    xref = int(rc[1].split()[0])\n                    val = self.xref_object(xref, compressed=True)\n                elif rc[0] == \"dict\":\n                    val = rc[1]\n                else:\n                    val = None\n                if val == None or not (val[:2] == \"<<\" and val[-2:] == \">>\"):\n                    return {}\n                valid = {\"Marked\": False, \"UserProperties\": False, \"Suspects\": False}\n                val = val[2:-2].split(\"/\")\n                for v in val[1:]:\n                    try:\n                        key, value = v.split()\n                    except:\n                        return valid\n                    if value == \"true\":\n                        valid[key] = True\n                return valid\n\n\n            def set_markinfo(self, markinfo: dict) -> bool:\n                \"\"\"Set the PDF MarkInfo values.\"\"\"\n                xref = self.pdf_catalog()\n                if xref == 0:\n                    raise ValueError(\"not a PDF\")\n                if not markinfo or not isinstance(markinfo, dict):\n                    return False\n                valid = {\"Marked\": False, \"UserProperties\": False, \"Suspects\": False}\n                \n                if not set(valid.keys()).issuperset(markinfo.keys()):\n                    badkeys = f\"bad MarkInfo key(s): {set(markinfo.keys()).difference(valid.keys())}\"\n                    raise ValueError(badkeys)\n                pdfdict = \"<<\"\n                valid.update(markinfo)\n                for key, value in valid.items():\n                    value=str(value).lower()\n                    if not value in (\"true\", \"false\"):\n                        raise ValueError(f\"bad key value '{key}': '{value}'\")\n                    pdfdict += f\"/{key} {value}\"\n                pdfdict += \">>\"\n                self.xref_set_key(xref, \"MarkInfo\", pdfdict)\n                return True\n\n\n            def __repr__(self) -> str:\n                m = \"closed \" if self.is_closed else \"\"\n                if self.stream is None:\n                    if self.name == \"\":\n                        return m + \"Document(<new PDF, doc# %i>)\" % self._graft_id\n                    return m + \"Document('%s')\" % (self.name,)\n                return m + \"Document('%s', <memory, doc# %i>)\" % (self.name, self._graft_id)\n\n\n            def __contains__(self, loc) -> bool:\n                if type(loc) is int:\n                    if loc < self.page_count:\n                        return True\n                    return False\n                if type(loc) not in (tuple, list) or len(loc) != 2:\n                    return False\n\n                chapter, pno = loc\n                if (type(chapter) != int or\n                    chapter < 0 or\n                    chapter >= self.chapter_count\n                    ):\n                    return False\n                if (type(pno) != int or\n                    pno < 0 or\n                    pno >= self.chapter_page_count(chapter)\n                    ):\n                    return False\n\n                return True\n\n\n            def __getitem__(self, i: int =0)->\"Page\":\n                assert isinstance(i, int) or (isinstance(i, tuple) and len(i) == 2 and all(isinstance(x, int) for x in i))\n                if i not in self:\n                    raise IndexError(\"page not in document\")\n                return self.load_page(i)\n\n\n            def __delitem__(self, i: AnyType)->None:\n                if not self.is_pdf:\n                    raise ValueError(\"is no PDF\")\n                if type(i) is int:\n                    return self.delete_page(i)\n                if type(i) in (list, tuple, range):\n                    return self.delete_pages(i)\n                if type(i) is not slice:\n                    raise ValueError(\"bad argument type\")\n                pc = self.page_count\n                start = i.start if i.start else 0\n                stop = i.stop if i.stop else pc\n                step = i.step if i.step else 1\n                while start < 0:\n                    start += pc\n                if start >= pc:\n                    raise ValueError(\"bad page number(s)\")\n                while stop < 0:\n                    stop += pc\n                if stop > pc:\n                    raise ValueError(\"bad page number(s)\")\n                return self.delete_pages(range(start, stop, step))\n\n\n            def pages(self, start: OptInt =None, stop: OptInt =None, step: OptInt =None):\n                \"\"\"Return a generator iterator over a page range.\n\n                Arguments have the same meaning as for the range() built-in.\n                \"\"\"\n                # set the start value\n                start = start or 0\n                while start < 0:\n                    start += self.page_count\n                if start not in range(self.page_count):\n                    raise ValueError(\"bad start page number\")\n\n                # set the stop value\n                stop = stop if stop is not None and stop <= self.page_count else self.page_count\n\n                # set the step value\n                if step == 0:\n                    raise ValueError(\"arg 3 must not be zero\")\n                if step is None:\n                    if start > stop:\n                        step = -1\n                    else:\n                        step = 1\n\n                for pno in range(start, stop, step):\n                    yield (self.load_page(pno))\n\n\n            def __len__(self) -> int:\n                return self.page_count\n\n            def _forget_page(self, page: \"struct Page *\"):\n                \"\"\"Remove a page from document page dict.\"\"\"\n                pid = id(page)\n                if pid in self._page_refs:\n                    self._page_refs[pid] = None\n\n            def _reset_page_refs(self):\n                \"\"\"Invalidate all pages in document dictionary.\"\"\"\n                if getattr(self, \"is_closed\", True):\n                    return\n                for page in self._page_refs.values():\n                    if page:\n                        page._erase()\n                        page = None\n                self._page_refs.clear()\n\n\n\n            def _cleanup(self):\n                self._reset_page_refs()\n                for k in self.Graftmaps.keys():\n                    self.Graftmaps[k] = None\n                self.Graftmaps = {}\n                self.ShownPages = {}\n                self.InsertedImages  = {}\n                self.FontInfos   = []\n                self.metadata    = None\n                self.stream      = None\n                self.is_closed = True\n\n\n            def close(self):\n                \"\"\"Close the document.\"\"\"\n                if getattr(self, \"is_closed\", False):\n                    raise ValueError(\"document closed\")\n                self._cleanup()\n                if getattr(self, \"thisown\", False):\n                    self.__swig_destroy__(self)\n                    return\n                else:\n                    raise RuntimeError(\"document object unavailable\")\n\n            def __del__(self):\n                if not type(self) is Document:\n                    return\n                self._cleanup()\n                if getattr(self, \"thisown\", False):\n                    self.__swig_destroy__(self)\n\n            def __enter__(self):\n                return self\n\n            def __exit__(self, *args):\n                self.close()\n            %}\n    }\n};\n\n/*****************************************************************************/\n// fz_page\n/*****************************************************************************/\n%nodefaultctor;\nstruct Page {\n    %extend {\n        ~Page()\n        {\n            DEBUGMSG1(\"Page\");\n            fz_page *this_page = (fz_page *) $self;\n            fz_drop_page(gctx, this_page);\n            DEBUGMSG2;\n        }\n        //----------------------------------------------------------------\n        // bound()\n        //----------------------------------------------------------------\n        FITZEXCEPTION(bound, !result)\n        PARENTCHECK(bound, \"\"\"Get page rectangle.\"\"\")\n        %pythonappend bound %{\n        val = Rect(val)\n        if val.is_infinite and self.parent.is_pdf:\n            cb = self.cropbox\n            w, h = cb.width, cb.height\n            if self.rotation not in (0, 180):\n                w, h = h, w\n            val = Rect(0, 0, w, h)\n            msg = TOOLS.mupdf_warnings(reset=False).splitlines()[-1]\n            print(msg, file=sys.stderr)\n        %}\n        PyObject *bound() {\n            fz_rect rect = fz_infinite_rect;\n            fz_try(gctx) {\n                rect = fz_bound_page(gctx, (fz_page *) $self);\n            }\n            fz_catch(gctx) {\n                ;\n            }\n            return JM_py_from_rect(rect);\n        }\n        %pythoncode %{rect = property(bound, doc=\"page rectangle\")%}\n\n        //----------------------------------------------------------------\n        // Page.get_image_bbox\n        //----------------------------------------------------------------\n        %pythonprepend get_image_bbox %{\n        \"\"\"Get rectangle occupied by image 'name'.\n\n        'name' is either an item of the image list, or the referencing\n        name string - elem[7] of the resp. item.\n        Option 'transform' also returns the image transformation matrix.\n        \"\"\"\n        CheckParent(self)\n        doc = self.parent\n        if doc.is_closed or doc.is_encrypted:\n            raise ValueError(\"document closed or encrypted\")\n\n        inf_rect = Rect(1, 1, -1, -1)\n        null_mat = Matrix()\n        if transform:\n            rc = (inf_rect, null_mat)\n        else:\n            rc = inf_rect\n\n        if type(name) in (list, tuple):\n            if not type(name[-1]) is int:\n                raise ValueError(\"need item of full page image list\")\n            item = name\n        else:\n            imglist = [i for i in doc.get_page_images(self.number, True) if name == i[7]]\n            if len(imglist) == 1:\n                item = imglist[0]\n            elif imglist == []:\n                raise ValueError(\"bad image name\")\n            else:\n                raise ValueError(\"found multiple images named '%s'.\" % name)\n        xref = item[-1]\n        if xref != 0 or transform == True:\n            try:\n                return self.get_image_rects(item, transform=transform)[0]\n            except:\n                return inf_rect\n        %}\n        %pythonappend get_image_bbox %{\n        if not bool(val):\n            return rc\n\n        for v in val:\n            if v[0] != item[-3]:\n                continue\n            q = Quad(v[1])\n            bbox = q.rect\n            if transform == 0:\n                rc = bbox\n                break\n\n            hm = Matrix(util_hor_matrix(q.ll, q.lr))\n            h = abs(q.ll - q.ul)\n            w = abs(q.ur - q.ul)\n            m0 = Matrix(1 / w, 0, 0, 1 / h, 0, 0)\n            m = ~(hm * m0)\n            rc = (bbox, m)\n            break\n        val = rc%}\n        PyObject *\n        get_image_bbox(PyObject *name, int transform=0)\n        {\n            pdf_page *pdf_page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            PyObject *rc =NULL;\n            fz_try(gctx) {\n                rc = JM_image_reporter(gctx, pdf_page);\n            }\n            fz_catch(gctx) {\n                Py_RETURN_NONE;\n            }\n            return rc;\n        }\n\n        //----------------------------------------------------------------\n        // run()\n        //----------------------------------------------------------------\n        FITZEXCEPTION(run, !result)\n        PARENTCHECK(run, \"\"\"Run page through a device.\"\"\")\n        PyObject *run(struct DeviceWrapper *dw, PyObject *m)\n        {\n            fz_try(gctx) {\n                fz_run_page(gctx, (fz_page *) $self, dw->device, JM_matrix_from_py(m), NULL);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // Page.extend_textpage\n        //----------------------------------------------------------------\n        FITZEXCEPTION(extend_textpage, !result)\n        PyObject *\n        extend_textpage(struct TextPage *tpage, int flags=0, PyObject *matrix=NULL)\n        {\n            fz_page *page = (fz_page *) $self;\n            fz_stext_page *tp = (fz_stext_page *) tpage;\n            fz_device *dev = NULL;\n            fz_stext_options options;\n            memset(&options, 0, sizeof options);\n            options.flags = flags;\n            fz_try(gctx) {\n                fz_matrix ctm = JM_matrix_from_py(matrix);\n                dev = fz_new_stext_device(gctx, tp, &options);\n                fz_run_page(gctx, page, dev, ctm, NULL);\n                fz_close_device(gctx, dev);\n            }\n            fz_always(gctx) {\n                fz_drop_device(gctx, dev);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.get_textpage\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_get_textpage, !result)\n        %pythonappend _get_textpage %{val.thisown = True%}\n        struct TextPage *\n        _get_textpage(PyObject *clip=NULL, int flags=0, PyObject *matrix=NULL)\n        {\n            fz_stext_page *tpage=NULL;\n            fz_page *page = (fz_page *) $self;\n            fz_device *dev = NULL;\n            fz_stext_options options;\n            memset(&options, 0, sizeof options);\n            options.flags = flags;\n            fz_try(gctx) {\n                // Default to page's rect if `clip` not specified, for #2048.\n                fz_rect rect = (clip==Py_None) ? fz_bound_page(gctx, page) : JM_rect_from_py(clip);\n                fz_matrix ctm = JM_matrix_from_py(matrix);\n                tpage = fz_new_stext_page(gctx, rect);\n                dev = fz_new_stext_device(gctx, tpage, &options);\n                fz_run_page(gctx, page, dev, ctm, NULL);\n                fz_close_device(gctx, dev);\n            }\n            fz_always(gctx) {\n                fz_drop_device(gctx, dev);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct TextPage *) tpage;\n        }\n\n\n        %pythoncode %{\n        def get_textpage(self, clip: rect_like = None, flags: int = 0, matrix=None) -> \"TextPage\":\n            CheckParent(self)\n            if matrix is None:\n                matrix = Matrix(1, 1)\n            old_rotation = self.rotation\n            if old_rotation != 0:\n                self.set_rotation(0)\n            try:\n                textpage = self._get_textpage(clip, flags=flags, matrix=matrix)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            textpage.parent = weakref.proxy(self)\n            return textpage\n        %}\n\n        /*  ****************** currently inactive\n        //----------------------------------------------------------------\n        // Page._get_textpage_ocr\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_get_textpage_ocr, !result)\n        %pythonappend _get_textpage_ocr %{val.thisown = True%}\n        struct TextPage *\n        _get_textpage_ocr(PyObject *clip=NULL, int flags=0, const char *language=NULL, const char *tessdata=NULL)\n        {\n            fz_stext_page *textpage=NULL;\n            fz_try(gctx) {\n                fz_rect rect = JM_rect_from_py(clip);\n                textpage = JM_new_stext_page_ocr_from_page(gctx, (fz_page *) $self, rect, flags, language, tessdata);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct TextPage *) textpage;\n        }\n        ************************* */\n\n        //----------------------------------------------------------------\n        // Page.language\n        //----------------------------------------------------------------\n        %pythoncode%{@property%}\n        %pythonprepend language %{\"\"\"Page language.\"\"\"%}\n        PyObject *language()\n        {\n            pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            if (!pdfpage) Py_RETURN_NONE;\n            pdf_obj *lang = pdf_dict_get_inheritable(gctx, pdfpage->obj, PDF_NAME(Lang));\n            if (!lang) Py_RETURN_NONE;\n            return Py_BuildValue(\"s\", pdf_to_str_buf(gctx, lang));\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.set_language\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_language, !result)\n        PARENTCHECK(set_language, \"\"\"Set PDF page default language.\"\"\")\n        PyObject *set_language(char *language=NULL)\n        {\n            pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(pdfpage);\n                fz_text_language lang;\n                char buf[8];\n                if (!language) {\n                    pdf_dict_del(gctx, pdfpage->obj, PDF_NAME(Lang));\n                } else {\n                    lang = fz_text_language_from_string(language);\n                    pdf_dict_put_text_string(gctx, pdfpage->obj,\n                        PDF_NAME(Lang),\n                        fz_string_from_text_language(buf, lang));\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_TRUE;\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.get_svg_image\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_svg_image, !result)\n        PARENTCHECK(get_svg_image, \"\"\"Make SVG image from page.\"\"\")\n        PyObject *get_svg_image(PyObject *matrix = NULL, int text_as_path=1)\n        {\n            fz_rect mediabox = fz_bound_page(gctx, (fz_page *) $self);\n            fz_device *dev = NULL;\n            fz_buffer *res = NULL;\n            PyObject *text = NULL;\n            fz_matrix ctm = JM_matrix_from_py(matrix);\n            fz_output *out = NULL;\n            fz_var(out);\n            fz_var(dev);\n            fz_var(res);\n            fz_rect tbounds = mediabox;\n            int text_option = (text_as_path == 1) ? FZ_SVG_TEXT_AS_PATH : FZ_SVG_TEXT_AS_TEXT;\n            tbounds = fz_transform_rect(tbounds, ctm);\n\n            fz_try(gctx) {\n                res = fz_new_buffer(gctx, 1024);\n                out = fz_new_output_with_buffer(gctx, res);\n                dev = fz_new_svg_device(gctx, out,\n                            tbounds.x1-tbounds.x0,  // width\n                            tbounds.y1-tbounds.y0,  // height\n                            text_option, 1);\n                fz_run_page(gctx, (fz_page *) $self, dev, ctm, NULL);\n                fz_close_device(gctx, dev);\n                text = JM_EscapeStrFromBuffer(gctx, res);\n            }\n            fz_always(gctx) {\n                fz_drop_device(gctx, dev);\n                fz_drop_output(gctx, out);\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return text;\n        }\n\n\n        //----------------------------------------------------------------\n        // page set opacity\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_set_opacity, !result)\n        %pythonprepend _set_opacity %{\n        if CA >= 1 and ca >= 1 and blendmode == None:\n            return None\n        tCA = int(round(max(CA , 0) * 100))\n        if tCA >= 100:\n            tCA = 99\n        tca = int(round(max(ca, 0) * 100))\n        if tca >= 100:\n            tca = 99\n        gstate = \"fitzca%02i%02i\" % (tCA, tca)\n        %}\n        PyObject *\n        _set_opacity(char *gstate=NULL, float CA=1, float ca=1, char *blendmode=NULL)\n        {\n            if (!gstate) Py_RETURN_NONE;\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                pdf_obj *resources = pdf_dict_get(gctx, page->obj, PDF_NAME(Resources));\n                if (!resources) {\n                    resources = pdf_dict_put_dict(gctx, page->obj, PDF_NAME(Resources), 2);\n                }\n                pdf_obj *extg = pdf_dict_get(gctx, resources, PDF_NAME(ExtGState));\n                if (!extg) {\n                    extg = pdf_dict_put_dict(gctx, resources, PDF_NAME(ExtGState), 2);\n                }\n                int i, n = pdf_dict_len(gctx, extg);\n                for (i = 0; i < n; i++) {\n                    pdf_obj *o1 = pdf_dict_get_key(gctx, extg, i);\n                    char *name = (char *) pdf_to_name(gctx, o1);\n                    if (strcmp(name, gstate) == 0) goto finished;\n                }\n                pdf_obj *opa = pdf_new_dict(gctx, page->doc, 3);\n                pdf_dict_put_real(gctx, opa, PDF_NAME(CA), (double) CA);\n                pdf_dict_put_real(gctx, opa, PDF_NAME(ca), (double) ca);\n                pdf_dict_puts_drop(gctx, extg, gstate, opa);\n                finished:;\n            }\n            fz_always(gctx) {\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"s\", gstate);\n        }\n\n        //----------------------------------------------------------------\n        // page add_caret_annot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_caret_annot, !result)\n        struct Annot *\n        _add_caret_annot(PyObject *point)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            fz_try(gctx) {\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_CARET);\n                if (point)\n                {\n                    fz_point p = JM_point_from_py(point);\n                    fz_rect r = pdf_annot_rect(gctx, annot);\n                    r = fz_make_rect(p.x, p.y, p.x + r.x1 - r.x0, p.y + r.y1 - r.y0);\n                    pdf_set_annot_rect(gctx, annot, r);\n                }\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // page addRedactAnnot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_redact_annot, !result)\n        struct Annot *\n        _add_redact_annot(PyObject *quad,\n            PyObject *text=NULL,\n            PyObject *da_str=NULL,\n            int align=0,\n            PyObject *fill=NULL,\n            PyObject *text_color=NULL)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            float fcol[4] = { 1, 1, 1, 0};\n            int nfcol = 0, i;\n            fz_try(gctx) {\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_REDACT);\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                fz_quad q = JM_quad_from_py(quad);\n                fz_rect r = fz_rect_from_quad(q);\n\n                // TODO calculate de-rotated rect\n                pdf_set_annot_rect(gctx, annot, r);\n                if (EXISTS(fill)) {\n                    JM_color_FromSequence(fill, &nfcol, fcol);\n                    pdf_obj *arr = pdf_new_array(gctx, page->doc, nfcol);\n                    for (i = 0; i < nfcol; i++) {\n                        pdf_array_push_real(gctx, arr, fcol[i]);\n                    }\n                    pdf_dict_put_drop(gctx, annot_obj, PDF_NAME(IC), arr);\n                }\n                if (EXISTS(text)) {\n                    const char *otext = PyUnicode_AsUTF8(text);\n                    pdf_dict_puts_drop(gctx, annot_obj, \"OverlayText\",\n                                       pdf_new_text_string(gctx, otext));\n                    pdf_dict_put_text_string(gctx,annot_obj, PDF_NAME(DA), PyUnicode_AsUTF8(da_str));\n                    pdf_dict_put_int(gctx, annot_obj, PDF_NAME(Q), (int64_t) align);\n                }\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n        //----------------------------------------------------------------\n        // page addLineAnnot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_line_annot, !result)\n        struct Annot *\n        _add_line_annot(PyObject *p1, PyObject *p2)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_LINE);\n                fz_point a = JM_point_from_py(p1);\n                fz_point b = JM_point_from_py(p2);\n                pdf_set_annot_line(gctx, annot, a, b);\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n        //----------------------------------------------------------------\n        // page addTextAnnot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_text_annot, !result)\n        struct Annot *\n        _add_text_annot(PyObject *point,\n            char *text,\n            char *icon=NULL)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            fz_rect r;\n            fz_point p = JM_point_from_py(point);\n            fz_var(annot);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_TEXT);\n                r = pdf_annot_rect(gctx, annot);\n                r = fz_make_rect(p.x, p.y, p.x + r.x1 - r.x0, p.y + r.y1 - r.y0);\n                pdf_set_annot_rect(gctx, annot, r);\n                pdf_set_annot_contents(gctx, annot, text);\n                if (icon) {\n                    pdf_set_annot_icon_name(gctx, annot, icon);\n                }\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n        //----------------------------------------------------------------\n        // page addInkAnnot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_ink_annot, !result)\n        struct Annot *\n        _add_ink_annot(PyObject *list)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            PyObject *p = NULL, *sublist = NULL;\n            pdf_obj *inklist = NULL, *stroke = NULL;\n            fz_matrix ctm, inv_ctm;\n            fz_point point;\n            fz_var(annot);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                if (!PySequence_Check(list)) {\n                    RAISEPY(gctx, MSG_BAD_ARG_INK_ANNOT, PyExc_ValueError);\n                }\n                pdf_page_transform(gctx, page, NULL, &ctm);\n                inv_ctm = fz_invert_matrix(ctm);\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_INK);\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                Py_ssize_t i, j, n0 = PySequence_Size(list), n1;\n                inklist = pdf_new_array(gctx, page->doc, n0);\n\n                for (j = 0; j < n0; j++) {\n                    sublist = PySequence_ITEM(list, j);\n                    n1 = PySequence_Size(sublist);\n                    stroke = pdf_new_array(gctx, page->doc, 2 * n1);\n\n                    for (i = 0; i < n1; i++) {\n                        p = PySequence_ITEM(sublist, i);\n                        if (!PySequence_Check(p) || PySequence_Size(p) != 2) {\n                            RAISEPY(gctx, MSG_BAD_ARG_INK_ANNOT, PyExc_ValueError);\n                        }\n                        point = fz_transform_point(JM_point_from_py(p), inv_ctm);\n                        Py_CLEAR(p);\n                        pdf_array_push_real(gctx, stroke, point.x);\n                        pdf_array_push_real(gctx, stroke, point.y);\n                    }\n\n                    pdf_array_push_drop(gctx, inklist, stroke);\n                    stroke = NULL;\n                    Py_CLEAR(sublist);\n                }\n\n                pdf_dict_put_drop(gctx, annot_obj, PDF_NAME(InkList), inklist);\n                inklist = NULL;\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n\n            fz_catch(gctx) {\n                Py_CLEAR(p);\n                Py_CLEAR(sublist);\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n        //----------------------------------------------------------------\n        // page addStampAnnot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_stamp_annot, !result)\n        struct Annot *\n        _add_stamp_annot(PyObject *rect, int stamp=0)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            pdf_obj *stamp_id[] = {PDF_NAME(Approved), PDF_NAME(AsIs),\n                                   PDF_NAME(Confidential), PDF_NAME(Departmental),\n                                   PDF_NAME(Experimental), PDF_NAME(Expired),\n                                   PDF_NAME(Final), PDF_NAME(ForComment),\n                                   PDF_NAME(ForPublicRelease), PDF_NAME(NotApproved),\n                                   PDF_NAME(NotForPublicRelease), PDF_NAME(Sold),\n                                   PDF_NAME(TopSecret), PDF_NAME(Draft)};\n            int n = nelem(stamp_id);\n            pdf_obj *name = stamp_id[0];\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                fz_rect r = JM_rect_from_py(rect);\n                if (fz_is_infinite_rect(r) || fz_is_empty_rect(r)) {\n                    RAISEPY(gctx, MSG_BAD_RECT, PyExc_ValueError);\n                }\n                if (INRANGE(stamp, 0, n-1)) {\n                    name = stamp_id[stamp];\n                }\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_STAMP);\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_set_annot_rect(gctx, annot, r);\n                pdf_dict_put(gctx, annot_obj, PDF_NAME(Name), name);\n                pdf_set_annot_contents(gctx, annot,\n                        pdf_dict_get_name(gctx, annot_obj, PDF_NAME(Name)));\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n        //----------------------------------------------------------------\n        // page addFileAnnot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_file_annot, !result)\n        struct Annot *\n        _add_file_annot(PyObject *point,\n            PyObject *buffer,\n            char *filename,\n            char *ufilename=NULL,\n            char *desc=NULL,\n            char *icon=NULL)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            char *uf = ufilename, *d = desc;\n            if (!ufilename) uf = filename;\n            if (!desc) d = filename;\n            fz_buffer *filebuf = NULL;\n            fz_rect r;\n            fz_point p = JM_point_from_py(point);\n            fz_var(filebuf);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                filebuf = JM_BufferFromBytes(gctx, buffer);\n                if (!filebuf) {\n                    RAISEPY(gctx, MSG_BAD_BUFFER, PyExc_TypeError);\n                }\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_FILE_ATTACHMENT);\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                r = pdf_annot_rect(gctx, annot);\n                r = fz_make_rect(p.x, p.y, p.x + r.x1 - r.x0, p.y + r.y1 - r.y0);\n                pdf_set_annot_rect(gctx, annot, r);\n                int flags = PDF_ANNOT_IS_PRINT;\n                pdf_set_annot_flags(gctx, annot, flags);\n\n                if (icon)\n                    pdf_set_annot_icon_name(gctx, annot, icon);\n\n                pdf_obj *val = JM_embed_file(gctx, page->doc, filebuf,\n                                    filename, uf, d, 1);\n                pdf_dict_put_drop(gctx, annot_obj, PDF_NAME(FS), val);\n                pdf_dict_put_text_string(gctx, annot_obj, PDF_NAME(Contents), filename);\n                pdf_update_annot(gctx, annot);\n                pdf_set_annot_rect(gctx, annot, r);\n                pdf_set_annot_flags(gctx, annot, flags);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, filebuf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // page: add a text marker annotation\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_text_marker, !result)\n        %pythonprepend _add_text_marker %{\n        CheckParent(self)\n        if not self.parent.is_pdf:\n            raise ValueError(\"is no PDF\")%}\n\n        %pythonappend _add_text_marker %{\n        if not val:\n            return None\n        val.parent = weakref.proxy(self)\n        self._annot_refs[id(val)] = val%}\n\n        struct Annot *\n        _add_text_marker(PyObject *quads, int annot_type)\n        {\n            pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            PyObject *item = NULL;\n            int rotation = JM_page_rotation(gctx, pdfpage);\n            fz_quad q;\n            fz_var(annot);\n            fz_var(item);\n            fz_try(gctx) {\n                if (rotation != 0) {\n                    pdf_dict_put_int(gctx, pdfpage->obj, PDF_NAME(Rotate), 0);\n                }\n                annot = pdf_create_annot(gctx, pdfpage, annot_type);\n                Py_ssize_t i, len = PySequence_Size(quads);\n                for (i = 0; i < len; i++) {\n                    item = PySequence_ITEM(quads, i);\n                    q = JM_quad_from_py(item);\n                    Py_DECREF(item);\n                    pdf_add_annot_quad_point(gctx, annot, q);\n                }\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_always(gctx) {\n                if (rotation != 0) {\n                    pdf_dict_put_int(gctx, pdfpage->obj, PDF_NAME(Rotate), rotation);\n                }\n            }\n            fz_catch(gctx) {\n                pdf_drop_annot(gctx, annot);\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // page: add circle or rectangle annotation\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_square_or_circle, !result)\n        struct Annot *\n        _add_square_or_circle(PyObject *rect, int annot_type)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            fz_try(gctx) {\n                fz_rect r = JM_rect_from_py(rect);\n                if (fz_is_infinite_rect(r) || fz_is_empty_rect(r)) {\n                    RAISEPY(gctx, MSG_BAD_RECT, PyExc_ValueError);\n                }\n                annot = pdf_create_annot(gctx, page, annot_type);\n                pdf_set_annot_rect(gctx, annot, r);\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // page: add multiline annotation\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_multiline, !result)\n        struct Annot *\n        _add_multiline(PyObject *points, int annot_type)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *annot = NULL;\n            fz_try(gctx) {\n                Py_ssize_t i, n = PySequence_Size(points);\n                if (n < 2) {\n                    RAISEPY(gctx, MSG_BAD_ARG_POINTS, PyExc_ValueError);\n                }\n                annot = pdf_create_annot(gctx, page, annot_type);\n                for (i = 0; i < n; i++) {\n                    PyObject *p = PySequence_ITEM(points, i);\n                    if (PySequence_Size(p) != 2) {\n                        Py_DECREF(p);\n                        RAISEPY(gctx, MSG_BAD_ARG_POINTS, PyExc_ValueError);\n                    }\n                    fz_point point = JM_point_from_py(p);\n                    Py_DECREF(p);\n                    pdf_add_annot_vertex(gctx, annot, point);\n                }\n\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // page addFreetextAnnot\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_add_freetext_annot, !result)\n        %pythonappend _add_freetext_annot %{\n        ap = val._getAP()\n        BT = ap.find(b\"BT\")\n        ET = ap.find(b\"ET\") + 2\n        ap = ap[BT:ET]\n        w = rect[2]-rect[0]\n        h = rect[3]-rect[1]\n        if rotate in (90, -90, 270):\n            w, h = h, w\n        re = b\"0 0 %g %g re\" % (w, h)\n        ap = re + b\"\\nW\\nn\\n\" + ap\n        ope = None\n        bwidth = b\"\"\n        fill_string = ColorCode(fill_color, \"f\").encode()\n        if fill_string:\n            fill_string += b\"\\n\"\n            ope = b\"f\"\n        stroke_string = ColorCode(border_color, \"c\").encode()\n        if stroke_string:\n            stroke_string += b\"\\n\"\n            bwidth = b\"1 w\\n\"\n            ope = b\"S\"\n        if fill_string and stroke_string:\n            ope = b\"B\"\n        if ope != None:\n            ap = bwidth + fill_string + stroke_string + re + b\"\\n\" + ope + b\"\\n\" + ap\n        val._setAP(ap)\n        %}\n        struct Annot *\n        _add_freetext_annot(PyObject *rect, char *text,\n            float fontsize=11,\n            char *fontname=NULL,\n            PyObject *text_color=NULL,\n            PyObject *fill_color=NULL,\n            PyObject *border_color=NULL,\n            int align=0,\n            int rotate=0)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            float fcol[4] = {1, 1, 1, 1}; // fill color: white\n            int nfcol = 0;\n            JM_color_FromSequence(fill_color, &nfcol, fcol);\n            float tcol[4] = {0, 0, 0, 0}; // std. text color: black\n            int ntcol = 0;\n            JM_color_FromSequence(text_color, &ntcol, tcol);\n            fz_rect r = JM_rect_from_py(rect);\n            pdf_annot *annot = NULL;\n            fz_try(gctx) {\n                if (fz_is_infinite_rect(r) || fz_is_empty_rect(r)) {\n                    RAISEPY(gctx, MSG_BAD_RECT, PyExc_ValueError);\n                }\n                annot = pdf_create_annot(gctx, page, PDF_ANNOT_FREE_TEXT);\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_set_annot_contents(gctx, annot, text);\n                pdf_set_annot_rect(gctx, annot, r);\n                pdf_dict_put_int(gctx, annot_obj, PDF_NAME(Rotate), rotate);\n                pdf_dict_put_int(gctx, annot_obj, PDF_NAME(Q), align);\n\n                if (nfcol > 0) {\n                    pdf_set_annot_color(gctx, annot, nfcol, fcol);\n                }\n\n                // insert the default appearance string\n                JM_make_annot_DA(gctx, annot, ntcol, tcol, fontname, fontsize);\n                pdf_update_annot(gctx, annot);\n                JM_add_annot_id(gctx, annot, \"A\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n    %pythoncode %{\n        @property\n        def rotation_matrix(self) -> Matrix:\n            \"\"\"Reflects page rotation.\"\"\"\n            return Matrix(TOOLS._rotate_matrix(self))\n\n        @property\n        def derotation_matrix(self) -> Matrix:\n            \"\"\"Reflects page de-rotation.\"\"\"\n            return Matrix(TOOLS._derotate_matrix(self))\n\n        def add_caret_annot(self, point: point_like) -> \"struct Annot *\":\n            \"\"\"Add a 'Caret' annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_caret_annot(point)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_strikeout_annot(self, quads=None, start=None, stop=None, clip=None) -> \"struct Annot *\":\n            \"\"\"Add a 'StrikeOut' annotation.\"\"\"\n            if quads is None:\n                q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n            else:\n                q = CheckMarkerArg(quads)\n            return self._add_text_marker(q, PDF_ANNOT_STRIKE_OUT)\n\n\n        def add_underline_annot(self, quads=None, start=None, stop=None, clip=None) -> \"struct Annot *\":\n            \"\"\"Add a 'Underline' annotation.\"\"\"\n            if quads is None:\n                q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n            else:\n                q = CheckMarkerArg(quads)\n            return self._add_text_marker(q, PDF_ANNOT_UNDERLINE)\n\n\n        def add_squiggly_annot(self, quads=None, start=None,\n                             stop=None, clip=None) -> \"struct Annot *\":\n            \"\"\"Add a 'Squiggly' annotation.\"\"\"\n            if quads is None:\n                q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n            else:\n                q = CheckMarkerArg(quads)\n            return self._add_text_marker(q, PDF_ANNOT_SQUIGGLY)\n\n\n        def add_highlight_annot(self, quads=None, start=None,\n                              stop=None, clip=None) -> \"struct Annot *\":\n            \"\"\"Add a 'Highlight' annotation.\"\"\"\n            if quads is None:\n                q = get_highlight_selection(self, start=start, stop=stop, clip=clip)\n            else:\n                q = CheckMarkerArg(quads)\n            return self._add_text_marker(q, PDF_ANNOT_HIGHLIGHT)\n\n\n        def add_rect_annot(self, rect: rect_like) -> \"struct Annot *\":\n            \"\"\"Add a 'Square' (rectangle) annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_square_or_circle(rect, PDF_ANNOT_SQUARE)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_circle_annot(self, rect: rect_like) -> \"struct Annot *\":\n            \"\"\"Add a 'Circle' (ellipse, oval) annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_square_or_circle(rect, PDF_ANNOT_CIRCLE)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_text_annot(self, point: point_like, text: str, icon: str =\"Note\") -> \"struct Annot *\":\n            \"\"\"Add a 'Text' (sticky note) annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_text_annot(point, text, icon=icon)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_line_annot(self, p1: point_like, p2: point_like) -> \"struct Annot *\":\n            \"\"\"Add a 'Line' annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_line_annot(p1, p2)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_polyline_annot(self, points: list) -> \"struct Annot *\":\n            \"\"\"Add a 'PolyLine' annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_multiline(points, PDF_ANNOT_POLY_LINE)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_polygon_annot(self, points: list) -> \"struct Annot *\":\n            \"\"\"Add a 'Polygon' annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_multiline(points, PDF_ANNOT_POLYGON)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_stamp_annot(self, rect: rect_like, stamp: int =0) -> \"struct Annot *\":\n            \"\"\"Add a ('rubber') 'Stamp' annotation.\"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_stamp_annot(rect, stamp)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_ink_annot(self, handwriting: list) -> \"struct Annot *\":\n            \"\"\"Add a 'Ink' ('handwriting') annotation.\n\n            The argument must be a list of lists of point_likes.\n            \"\"\"\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_ink_annot(handwriting)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_file_annot(self, point: point_like,\n            buffer: ByteString,\n            filename: str,\n            ufilename: OptStr =None,\n            desc: OptStr =None,\n            icon: OptStr =None) -> \"struct Annot *\":\n            \"\"\"Add a 'FileAttachment' annotation.\"\"\"\n\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_file_annot(point,\n                            buffer,\n                            filename,\n                            ufilename=ufilename,\n                            desc=desc,\n                            icon=icon)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_freetext_annot(self, rect: rect_like, text: str, fontsize: float =11,\n                             fontname: OptStr =None, border_color: OptSeq =None,\n                             text_color: OptSeq =None,\n                             fill_color: OptSeq =None, align: int =0, rotate: int =0) -> \"struct Annot *\":\n            \"\"\"Add a 'FreeText' annotation.\"\"\"\n\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_freetext_annot(rect, text, fontsize=fontsize,\n                        fontname=fontname, border_color=border_color,text_color=text_color,\n                        fill_color=fill_color, align=align, rotate=rotate)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            return annot\n\n\n        def add_redact_annot(self, quad, text: OptStr =None, fontname: OptStr =None,\n                           fontsize: float =11, align: int =0, fill: OptSeq =None, text_color: OptSeq =None,\n                           cross_out: bool =True) -> \"struct Annot *\":\n            \"\"\"Add a 'Redact' annotation.\"\"\"\n            da_str = None\n            if text:\n                CheckColor(fill)\n                CheckColor(text_color)\n                if not fontname:\n                    fontname = \"Helv\"\n                if not fontsize:\n                    fontsize = 11\n                if not text_color:\n                    text_color = (0, 0, 0)\n                if hasattr(text_color, \"__float__\"):\n                    text_color = (text_color, text_color, text_color)\n                if len(text_color) > 3:\n                    text_color = text_color[:3]\n                fmt = \"{:g} {:g} {:g} rg /{f:s} {s:g} Tf\"\n                da_str = fmt.format(*text_color, f=fontname, s=fontsize)\n                if fill is None:\n                    fill = (1, 1, 1)\n                if fill:\n                    if hasattr(fill, \"__float__\"):\n                        fill = (fill, fill, fill)\n                    if len(fill) > 3:\n                        fill = fill[:3]\n\n            old_rotation = annot_preprocess(self)\n            try:\n                annot = self._add_redact_annot(quad, text=text, da_str=da_str,\n                           align=align, fill=fill)\n            finally:\n                if old_rotation != 0:\n                    self.set_rotation(old_rotation)\n            annot_postprocess(self, annot)\n            #-------------------------------------------------------------\n            # change appearance to show a crossed-out rectangle\n            #-------------------------------------------------------------\n            if cross_out:\n                ap_tab = annot._getAP().splitlines()[:-1]  # get the 4 commands only\n                _, LL, LR, UR, UL = ap_tab\n                ap_tab.append(LR)\n                ap_tab.append(LL)\n                ap_tab.append(UR)\n                ap_tab.append(LL)\n                ap_tab.append(UL)\n                ap_tab.append(b\"S\")\n                ap = b\"\\n\".join(ap_tab)\n                annot._setAP(ap, 0)\n            return annot\n        %}\n\n\n        //----------------------------------------------------------------\n        // page load annot by name or xref\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_load_annot, !result)\n        struct Annot *\n        _load_annot(char *name, int xref)\n        {\n            pdf_annot *annot = NULL;\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                if (xref == 0)\n                    annot = JM_get_annot_by_name(gctx, page, name);\n                else\n                    annot = JM_get_annot_by_xref(gctx, page, xref);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // page load widget by xref\n        //----------------------------------------------------------------\n        FITZEXCEPTION(load_widget, !result)\n        %pythonprepend load_widget %{\n        \"\"\"Load a widget by its xref.\"\"\"\n        CheckParent(self)\n        %}\n        %pythonappend load_widget %{\n        if not val:\n            return val\n        val.thisown = True\n        val.parent = weakref.proxy(self)\n        self._annot_refs[id(val)] = val\n        widget = Widget()\n        TOOLS._fill_widget(val, widget)\n        val = widget\n        %}\n        struct Annot *\n        load_widget(int xref)\n        {\n            pdf_annot *annot = NULL;\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                annot = JM_get_widget_by_xref(gctx, page, xref);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // page list Resource/Properties\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_get_resource_properties, !result)\n        PyObject *\n        _get_resource_properties()\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            PyObject *rc;\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                rc = JM_get_resource_properties(gctx, page->obj);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        //----------------------------------------------------------------\n        // page list Resource/Properties\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_set_resource_property, !result)\n        PyObject *\n        _set_resource_property(char *name, int xref)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                JM_set_resource_property(gctx, page->obj, name, xref);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode %{\ndef _get_optional_content(self, oc: OptInt) -> OptStr:\n    if oc == None or oc == 0:\n        return None\n    doc = self.parent\n    check = doc.xref_object(oc, compressed=True)\n    if not (\"/Type/OCG\" in check or \"/Type/OCMD\" in check):\n        raise ValueError(\"bad optional content: 'oc'\")\n    props = {}\n    for p, x in self._get_resource_properties():\n        props[x] = p\n    if oc in props.keys():\n        return props[oc]\n    i = 0\n    mc = \"MC%i\" % i\n    while mc in props.values():\n        i += 1\n        mc = \"MC%i\" % i\n    self._set_resource_property(mc, oc)\n    return mc\n\ndef get_oc_items(self) -> list:\n    \"\"\"Get OCGs and OCMDs used in the page's contents.\n\n    Returns:\n        List of items (name, xref, type), where type is one of \"ocg\" / \"ocmd\",\n        and name is the property name.\n    \"\"\"\n    rc = []\n    for pname, xref in self._get_resource_properties():\n        text = self.parent.xref_object(xref, compressed=True)\n        if \"/Type/OCG\" in text:\n            octype = \"ocg\"\n        elif \"/Type/OCMD\" in text:\n            octype = \"ocmd\"\n        else:\n            continue\n        rc.append((pname, xref, octype))\n    return rc\n%}\n\n        //----------------------------------------------------------------\n        // page get list of annot names\n        //----------------------------------------------------------------\n        PARENTCHECK(annot_names, \"\"\"List of names of annotations, fields and links.\"\"\")\n        PyObject *annot_names()\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n\n            if (!page) {\n                PyObject *rc = PyList_New(0);\n                return rc;\n            }\n            return JM_get_annot_id_list(gctx, page);\n        }\n\n\n        //----------------------------------------------------------------\n        // page retrieve list of annotation xrefs\n        //----------------------------------------------------------------\n        PARENTCHECK(annot_xrefs,\"\"\"List of xref numbers of annotations, fields and links.\"\"\")\n        PyObject *annot_xrefs()\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            if (!page) {\n                PyObject *rc = PyList_New(0);\n                return rc;\n            }\n            return JM_get_annot_xref_list(gctx, page->obj);\n        }\n\n\n        %pythoncode %{\n        def load_annot(self, ident: typing.Union[str, int]) -> \"struct Annot *\":\n            \"\"\"Load an annot by name (/NM key) or xref.\n\n            Args:\n                ident: identifier, either name (str) or xref (int).\n            \"\"\"\n\n            CheckParent(self)\n            if type(ident) is str:\n                xref = 0\n                name = ident\n            elif type(ident) is int:\n                xref = ident\n                name = None\n            else:\n                raise ValueError(\"identifier must be string or integer\")\n            val = self._load_annot(name, xref)\n            if not val:\n                return val\n            val.thisown = True\n            val.parent = weakref.proxy(self)\n            self._annot_refs[id(val)] = val\n            return val\n\n\n        #---------------------------------------------------------------------\n        # page addWidget\n        #---------------------------------------------------------------------\n        def add_widget(self, widget: Widget) -> \"struct Annot *\":\n            \"\"\"Add a 'Widget' (form field).\"\"\"\n            CheckParent(self)\n            doc = self.parent\n            if not doc.is_pdf:\n                raise ValueError(\"is no PDF\")\n            widget._validate()\n            annot = self._addWidget(widget.field_type, widget.field_name)\n            if not annot:\n                return None\n            annot.thisown = True\n            annot.parent = weakref.proxy(self) # owning page object\n            self._annot_refs[id(annot)] = annot\n            widget.parent = annot.parent\n            widget._annot = annot\n            widget.update()\n            return annot\n        %}\n\n        FITZEXCEPTION(_addWidget, !result)\n        struct Annot *_addWidget(int field_type, char *field_name)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_document *pdf = page->doc;\n            pdf_annot *annot = NULL;\n            fz_var(annot);\n            fz_try(gctx) {\n                annot = JM_create_widget(gctx, pdf, page, field_type, field_name);\n                if (!annot) {\n                    RAISEPY(gctx, \"cannot create widget\", PyExc_RuntimeError);\n                }\n                JM_add_annot_id(gctx, annot, \"W\");\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Annot *) annot;\n        }\n\n        //----------------------------------------------------------------\n        // Page.get_displaylist\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_displaylist, !result)\n        %pythonprepend get_displaylist %{\n        \"\"\"Make a DisplayList from the page for Pixmap generation.\n\n        Include (default) or exclude annotations.\"\"\"\n\n        CheckParent(self)\n        %}\n        %pythonappend get_displaylist %{val.thisown = True%}\n        struct DisplayList *get_displaylist(int annots=1)\n        {\n            fz_display_list *dl = NULL;\n            fz_try(gctx) {\n                if (annots) {\n                    dl = fz_new_display_list_from_page(gctx, (fz_page *) $self);\n                } else {\n                    dl = fz_new_display_list_from_page_contents(gctx, (fz_page *) $self);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct DisplayList *) dl;\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.get_drawings\n        //----------------------------------------------------------------\n        %pythoncode %{\n        def get_drawings(self, extended: bool = False) -> list:\n            \"\"\"Retrieve vector graphics. The extended version includes clips.\n\n            Note:\n            For greater comfort, this method converts point-like, rect-like, quad-like\n            tuples of the C version to respective Point / Rect / Quad objects.\n            It also adds default items that are missing in original path types.\n            \"\"\"\n            allkeys = (\n                    \"closePath\", \"fill\", \"color\", \"width\", \"lineCap\",\n                    \"lineJoin\", \"dashes\", \"stroke_opacity\", \"fill_opacity\", \"even_odd\",\n                )\n            val = self.get_cdrawings(extended=extended)\n            for i in range(len(val)):\n                npath = val[i]\n                if not npath[\"type\"].startswith(\"clip\"):\n                    npath[\"rect\"] = Rect(npath[\"rect\"])\n                else:\n                    npath[\"scissor\"] = Rect(npath[\"scissor\"])\n                if npath[\"type\"]!=\"group\":\n                    items = npath[\"items\"]\n                    newitems = []\n                    for item in items:\n                        cmd = item[0]\n                        rest = item[1:]\n                        if  cmd == \"re\":\n                            item = (\"re\", Rect(rest[0]).normalize(), rest[1])\n                        elif cmd == \"qu\":\n                            item = (\"qu\", Quad(rest[0]))\n                        else:\n                            item = tuple([cmd] + [Point(i) for i in rest])\n                        newitems.append(item)\n                    npath[\"items\"] = newitems\n                if npath[\"type\"] in (\"f\", \"s\"):\n                    for k in allkeys:\n                        npath[k] = npath.get(k)\n                val[i] = npath\n            return val\n\n        class Drawpath(object):\n            \"\"\"Reflects a path dictionary from get_cdrawings().\"\"\"\n            def __init__(self, **args):\n                self.__dict__.update(args)\n        \n        class Drawpathlist(object):\n            \"\"\"List of Path objects representing get_cdrawings() output.\"\"\"\n            def __init__(self):\n                self.paths = []\n                self.path_count = 0\n                self.group_count = 0\n                self.clip_count = 0\n                self.fill_count = 0\n                self.stroke_count = 0\n                self.fillstroke_count = 0\n\n            def append(self, path):\n                self.paths.append(path)\n                self.path_count += 1\n                if path.type == \"clip\":\n                    self.clip_count += 1\n                elif path.type == \"group\":\n                    self.group_count += 1\n                elif path.type == \"f\":\n                    self.fill_count += 1\n                elif path.type == \"s\":\n                    self.stroke_count += 1\n                elif path.type == \"fs\":\n                    self.fillstroke_count += 1\n\n            def clip_parents(self, i):\n                \"\"\"Return list of parent clip paths.\n\n                Args:\n                    i: (int) return parents of this path.\n                Returns:\n                    List of the clip parents.\"\"\"\n                if i >= self.path_count:\n                    raise IndexError(\"bad path index\")\n                while i < 0:\n                    i += self.path_count\n                lvl = self.paths[i].level\n                clips = list(  # clip paths before identified one\n                    reversed(\n                        [\n                            p\n                            for p in self.paths[:i]\n                            if p.type == \"clip\" and p.level < lvl\n                        ]\n                    )\n                )\n                if clips == []:  # none found: empty list\n                    return []\n                nclips = [clips[0]]  # init return list\n                for p in clips[1:]:\n                    if p.level >= nclips[-1].level:\n                        continue  # only accept smaller clip levels\n                    nclips.append(p)\n                return nclips\n\n            def group_parents(self, i):\n                \"\"\"Return list of parent group paths.\n\n                Args:\n                    i: (int) return parents of this path.\n                Returns:\n                    List of the group parents.\"\"\"\n                if i >= self.path_count:\n                    raise IndexError(\"bad path index\")\n                while i < 0:\n                    i += self.path_count\n                lvl = self.paths[i].level\n                groups = list(  # group paths before identified one\n                    reversed(\n                        [\n                            p\n                            for p in self.paths[:i]\n                            if p.type == \"group\" and p.level < lvl\n                        ]\n                    )\n                )\n                if groups == []:  # none found: empty list\n                    return []\n                ngroups = [groups[0]]  # init return list\n                for p in groups[1:]:\n                    if p.level >= ngroups[-1].level:\n                        continue  # only accept smaller group levels\n                    ngroups.append(p)\n                return ngroups\n\n            def __getitem__(self, item):\n                return self.paths.__getitem__(item)\n\n            def __len__(self):\n                return self.paths.__len__()\n\n\n        def get_lineart(self) -> object:\n            \"\"\"Get page drawings paths.\n\n            Note:\n            For greater comfort, this method converts point-like, rect-like, quad-like\n            tuples of the C version to respective Point / Rect / Quad objects.\n            Also adds default items that are missing in original path types.\n            In contrast to get_drawings(), this output is an object.\n            \"\"\"\n\n            val = self.get_cdrawings(extended=True)\n            paths = self.Drawpathlist()\n            for path in val:\n                npath = self.Drawpath(**path)\n                if npath.type != \"clip\":\n                    npath.rect = Rect(path[\"rect\"])\n                else:\n                    npath.scissor = Rect(path[\"scissor\"])\n                if npath.type != \"group\":\n                    items = path[\"items\"]\n                    newitems = []\n                    for item in items:\n                        cmd = item[0]\n                        rest = item[1:]\n                        if  cmd == \"re\":\n                            item = (\"re\", Rect(rest[0]).normalize(), rest[1])\n                        elif cmd == \"qu\":\n                            item = (\"qu\", Quad(rest[0]))\n                        else:\n                            item = tuple([cmd] + [Point(i) for i in rest])\n                        newitems.append(item)\n                    npath.items = newitems\n                \n                if npath.type == \"f\":\n                    npath.stroke_opacity = None\n                    npath.dashes = None\n                    npath.lineJoin = None\n                    npath.lineCap = None\n                    npath.color = None\n                    npath.width = None\n\n                paths.append(npath)\n\n            val = None\n            return paths\n        %}\n\n\n        FITZEXCEPTION(get_cdrawings, !result)\n        %pythonprepend get_cdrawings %{\n        \"\"\"Extract vector graphics (\"line art\") from the page.\"\"\"\n        CheckParent(self)\n        old_rotation = self.rotation\n        if old_rotation != 0:\n            self.set_rotation(0)\n        %}\n        %pythonappend get_cdrawings %{\n        if old_rotation != 0:\n            self.set_rotation(old_rotation)\n        %}\n        PyObject *\n        get_cdrawings(PyObject *extended=NULL, PyObject *callback=NULL, PyObject *method=NULL)\n        {\n            fz_page *page = (fz_page *) $self;\n            fz_device *dev = NULL;\n            PyObject *rc = NULL;\n            int clips = PyObject_IsTrue(extended);\n            fz_var(rc);\n            fz_try(gctx) {\n                fz_rect prect = fz_bound_page(gctx, page);\n                trace_device_ptm = fz_make_matrix(1, 0, 0, -1, 0, prect.y1);\n                if (PyCallable_Check(callback) || method != Py_None) {\n                    dev = JM_new_lineart_device(gctx, callback, clips, method);\n                } else {\n                    rc = PyList_New(0);\n                    dev = JM_new_lineart_device(gctx, rc, clips, method);\n                }\n                fz_run_page(gctx, page, dev, fz_identity, NULL);\n                fz_close_device(gctx, dev);\n            }\n            fz_always(gctx) {\n                fz_drop_device(gctx, dev);\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            if (PyCallable_Check(callback) || method != Py_None) {\n                Py_RETURN_NONE;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(get_bboxlog, !result)\n        %pythonprepend get_bboxlog %{\n        CheckParent(self)\n        old_rotation = self.rotation\n        if old_rotation != 0:\n            self.set_rotation(0)\n        %}\n        %pythonappend get_bboxlog %{\n        if old_rotation != 0:\n            self.set_rotation(old_rotation)\n        %}\n        PyObject *\n        get_bboxlog(PyObject *layers=NULL)\n        {\n            fz_page *page = (fz_page *) $self;\n            fz_device *dev = NULL;\n            PyObject *rc = PyList_New(0);\n            int inc_layers = PyObject_IsTrue(layers);\n            fz_try(gctx) {\n                dev = JM_new_bbox_device(gctx, rc, inc_layers);\n                fz_run_page(gctx, page, dev, fz_identity, NULL);\n                fz_close_device(gctx, dev);\n            }\n            fz_always(gctx) {\n                fz_drop_device(gctx, dev);\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        FITZEXCEPTION(get_texttrace, !result)\n        %pythonprepend get_texttrace %{\n        CheckParent(self)\n        old_rotation = self.rotation\n        if old_rotation != 0:\n            self.set_rotation(0)\n        %}\n        %pythonappend get_texttrace %{\n        if old_rotation != 0:\n            self.set_rotation(old_rotation)\n        %}\n        PyObject *\n        get_texttrace()\n        {\n            fz_page *page = (fz_page *) $self;\n            fz_device *dev = NULL;\n            PyObject *rc = PyList_New(0);\n            fz_try(gctx) {\n                dev = JM_new_texttrace_device(gctx, rc);\n                fz_rect prect = fz_bound_page(gctx, page);\n                trace_device_rot = fz_identity;\n                trace_device_ptm = fz_make_matrix(1, 0, 0, -1, 0, prect.y1);\n                fz_run_page(gctx, page, dev, fz_identity, NULL);\n                fz_close_device(gctx, dev);\n            }\n            fz_always(gctx) {\n                fz_drop_device(gctx, dev);\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        //----------------------------------------------------------------\n        // Page apply redactions\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_apply_redactions, !result)\n        PyObject *_apply_redactions(int images=PDF_REDACT_IMAGE_PIXELS)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            int success = 0;\n            pdf_redact_options opts = {0};\n            opts.black_boxes = 0;  // no black boxes\n            opts.image_method = images;  // how to treat images\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                success = pdf_redact_page(gctx, page->doc, page, &opts);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_BOOL(success);\n        }\n\n\n        //----------------------------------------------------------------\n        // Page._makePixmap\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_makePixmap, !result)\n        struct Pixmap *\n        _makePixmap(struct Document *doc,\n            PyObject *ctm,\n            struct Colorspace *cs,\n            int alpha=0,\n            int annots=1,\n            PyObject *clip=NULL)\n        {\n            fz_pixmap *pix = NULL;\n            fz_try(gctx) {\n                pix = JM_pixmap_from_page(gctx, (fz_document *) doc, (fz_page *) $self, ctm, (fz_colorspace *) cs, alpha, annots, clip);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pix;\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.set_mediabox\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_mediabox, !result)\n        PARENTCHECK(set_mediabox, \"\"\"Set the MediaBox.\"\"\")\n        PyObject *set_mediabox(PyObject *rect)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                fz_rect mediabox = JM_rect_from_py(rect);\n                if (fz_is_empty_rect(mediabox) ||\n                    fz_is_infinite_rect(mediabox)) {\n                    RAISEPY(gctx, MSG_BAD_RECT, PyExc_ValueError);\n                }\n                pdf_dict_put_rect(gctx, page->obj, PDF_NAME(MediaBox), mediabox);\n                pdf_dict_del(gctx, page->obj, PDF_NAME(CropBox));\n                pdf_dict_del(gctx, page->obj, PDF_NAME(ArtBox));\n                pdf_dict_del(gctx, page->obj, PDF_NAME(BleedBox));\n                pdf_dict_del(gctx, page->obj, PDF_NAME(TrimBox));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.load_links()\n        //----------------------------------------------------------------\n        PARENTCHECK(load_links, \"\"\"Get first Link.\"\"\")\n        %pythonappend load_links %{\n            if val:\n                val.thisown = True\n                val.parent = weakref.proxy(self) # owning page object\n                self._annot_refs[id(val)] = val\n                if self.parent.is_pdf:\n                    link_id = [x for x in self.annot_xrefs() if x[1] == PDF_ANNOT_LINK][0]\n                    val.xref = link_id[0]\n                    val.id = link_id[2]\n                else:\n                    val.xref = 0\n                    val.id = \"\"\n        %}\n        struct Link *load_links()\n        {\n            fz_link *l = NULL;\n            fz_try(gctx) {\n                l = fz_load_links(gctx, (fz_page *) $self);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Link *) l;\n        }\n        %pythoncode %{first_link = property(load_links, doc=\"First link on page\")%}\n\n        //----------------------------------------------------------------\n        // Page.first_annot\n        //----------------------------------------------------------------\n        PARENTCHECK(first_annot, \"\"\"First annotation.\"\"\")\n        %pythonappend first_annot %{\n        if val:\n            val.thisown = True\n            val.parent = weakref.proxy(self) # owning page object\n            self._annot_refs[id(val)] = val\n        %}\n        %pythoncode %{@property%}\n        struct Annot *first_annot()\n        {\n            pdf_annot *annot = NULL;\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            if (page)\n            {\n                annot = pdf_first_annot(gctx, page);\n                if (annot) pdf_keep_annot(gctx, annot);\n            }\n            return (struct Annot *) annot;\n        }\n\n        //----------------------------------------------------------------\n        // first_widget\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(first_widget, \"\"\"First widget/field.\"\"\")\n        %pythonappend first_widget %{\n        if val:\n            val.thisown = True\n            val.parent = weakref.proxy(self) # owning page object\n            self._annot_refs[id(val)] = val\n            widget = Widget()\n            TOOLS._fill_widget(val, widget)\n            val = widget\n        %}\n        struct Annot *first_widget()\n        {\n            pdf_annot *annot = NULL;\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            if (page) {\n                annot = pdf_first_widget(gctx, page);\n                if (annot) pdf_keep_annot(gctx, annot);\n            }\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.delete_link() - delete link\n        //----------------------------------------------------------------\n        PARENTCHECK(delete_link, \"\"\"Delete a Link.\"\"\")\n        %pythonappend delete_link %{\n        if linkdict[\"xref\"] == 0: return\n        try:\n            linkid = linkdict[\"id\"]\n            linkobj = self._annot_refs[linkid]\n            linkobj._erase()\n        except:\n            pass\n        %}\n        void delete_link(PyObject *linkdict)\n        {\n            if (!PyDict_Check(linkdict)) return; // have no dictionary\n            fz_try(gctx) {\n                pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n                if (!page) goto finished;  // have no PDF\n                int xref = (int) PyInt_AsLong(PyDict_GetItem(linkdict, dictkey_xref));\n                if (xref < 1) goto finished;  // invalid xref\n                pdf_obj *annots = pdf_dict_get(gctx, page->obj, PDF_NAME(Annots));\n                if (!annots) goto finished;  // have no annotations\n                int len = pdf_array_len(gctx, annots);\n                if (len == 0) goto finished;\n                int i, oxref = 0;\n\n                for (i = 0; i < len; i++) {\n                    oxref = pdf_to_num(gctx, pdf_array_get(gctx, annots, i));\n                    if (xref == oxref) break;        // found xref in annotations\n                }\n\n                if (xref != oxref) goto finished;  // xref not in annotations\n                pdf_array_delete(gctx, annots, i);   // delete entry in annotations\n                pdf_delete_object(gctx, page->doc, xref);  // delete link obj\n                pdf_dict_put(gctx, page->obj, PDF_NAME(Annots), annots);\n                JM_refresh_links(gctx, page);\n                finished:;\n\n            }\n            fz_catch(gctx) {;}\n        }\n\n        //----------------------------------------------------------------\n        // Page.delete_annot() - delete annotation and return the next one\n        //----------------------------------------------------------------\n        %pythonprepend delete_annot %{\n        \"\"\"Delete annot and return next one.\"\"\"\n        CheckParent(self)\n        CheckParent(annot)%}\n\n        %pythonappend delete_annot %{\n        if val:\n            val.thisown = True\n            val.parent = weakref.proxy(self) # owning page object\n            val.parent._annot_refs[id(val)] = val\n        %}\n\n        struct Annot *delete_annot(struct Annot *annot)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_annot *irt_annot = NULL;\n            while (1) {\n                // first loop through all /IRT annots and remove them\n                irt_annot = JM_find_annot_irt(gctx, (pdf_annot *) annot);\n                if (!irt_annot)  // no more there\n                    break;\n                pdf_delete_annot(gctx, page, irt_annot);\n            }\n            pdf_annot *nextannot = pdf_next_annot(gctx, (pdf_annot *) annot);  // store next\n            pdf_delete_annot(gctx, page, (pdf_annot *) annot);\n            if (nextannot) {\n                nextannot = pdf_keep_annot(gctx, nextannot);\n            }\n            return (struct Annot *) nextannot;\n        }\n\n\n        //----------------------------------------------------------------\n        // mediabox: get the /MediaBox (PDF only)\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(mediabox, \"\"\"The MediaBox.\"\"\")\n        %pythonappend mediabox %{val = Rect(JM_TUPLE3(val))%}\n        PyObject *mediabox()\n        {\n            fz_rect rect = fz_infinite_rect;\n            fz_try(gctx) {\n                pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n                if (!page) {\n                    rect = fz_bound_page(gctx, (fz_page *) $self);\n                } else {\n                    rect = JM_mediabox(gctx, page->obj);\n                }\n            }\n            fz_catch(gctx) {;}\n            return JM_py_from_rect(rect);\n        }\n\n\n        //----------------------------------------------------------------\n        // cropbox: get the /CropBox (PDF only)\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(cropbox, \"\"\"The CropBox.\"\"\")\n        %pythonappend cropbox %{val = Rect(JM_TUPLE3(val))%}\n        PyObject *cropbox()\n        {\n            fz_rect rect = fz_infinite_rect;\n            fz_try(gctx) {\n                pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n                if (!page) {\n                    rect = fz_bound_page(gctx, (fz_page *) $self);\n                } else {\n                    rect = JM_cropbox(gctx, page->obj);\n                }\n            }\n            fz_catch(gctx) {;}\n            return JM_py_from_rect(rect);\n        }\n\n\n        PyObject *_other_box(const char *boxtype)\n        {\n            fz_rect rect = fz_infinite_rect;\n            fz_try(gctx) {\n                pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n                if (page) {\n                    pdf_obj *obj = pdf_dict_gets(gctx, page->obj, boxtype);\n                    if (pdf_is_array(gctx, obj)) {\n                        rect = pdf_to_rect(gctx, obj);\n                    }\n                }\n            }\n            fz_catch(gctx) {;}\n            if (fz_is_infinite_rect(rect)) {\n                Py_RETURN_NONE;\n            }\n            return JM_py_from_rect(rect);\n        }\n\n\n        //----------------------------------------------------------------\n        // CropBox position: x0, y0 of /CropBox\n        //----------------------------------------------------------------\n        %pythoncode %{\n        @property\n        def cropbox_position(self):\n            return self.cropbox.tl\n\n        @property\n        def artbox(self):\n            \"\"\"The ArtBox\"\"\"\n            rect = self._other_box(\"ArtBox\")\n            if rect == None:\n                return self.cropbox\n            mb = self.mediabox\n            return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n\n        @property\n        def trimbox(self):\n            \"\"\"The TrimBox\"\"\"\n            rect = self._other_box(\"TrimBox\")\n            if rect == None:\n                return self.cropbox\n            mb = self.mediabox\n            return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n\n        @property\n        def bleedbox(self):\n            \"\"\"The BleedBox\"\"\"\n            rect = self._other_box(\"BleedBox\")\n            if rect == None:\n                return self.cropbox\n            mb = self.mediabox\n            return Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n\n        def _set_pagebox(self, boxtype, rect):\n            doc = self.parent\n            if doc == None:\n                raise ValueError(\"orphaned object: parent is None\")\n\n            if not doc.is_pdf:\n                raise ValueError(\"is no PDF\")\n\n            valid_boxes = (\"CropBox\", \"BleedBox\", \"TrimBox\", \"ArtBox\")\n\n            if boxtype not in valid_boxes:\n                raise ValueError(\"bad boxtype\")\n\n            rect = Rect(rect)\n            mb = self.mediabox\n            rect = Rect(rect[0], mb.y1 - rect[3], rect[2], mb.y1 - rect[1])\n            if not (mb.x0 <= rect.x0 < rect.x1 <= mb.x1 and mb.y0 <= rect.y0 < rect.y1 <= mb.y1):\n                raise ValueError(f\"{boxtype} not in MediaBox\")\n\n            doc.xref_set_key(self.xref, boxtype, \"[%g %g %g %g]\" % tuple(rect))\n\n\n        def set_cropbox(self, rect):\n            \"\"\"Set the CropBox. Will also change Page.rect.\"\"\"\n            return self._set_pagebox(\"CropBox\", rect)\n\n        def set_artbox(self, rect):\n            \"\"\"Set the ArtBox.\"\"\"\n            return self._set_pagebox(\"ArtBox\", rect)\n\n        def set_bleedbox(self, rect):\n            \"\"\"Set the BleedBox.\"\"\"\n            return self._set_pagebox(\"BleedBox\", rect)\n\n        def set_trimbox(self, rect):\n            \"\"\"Set the TrimBox.\"\"\"\n            return self._set_pagebox(\"TrimBox\", rect)\n        %}\n\n\n        //----------------------------------------------------------------\n        // rotation - return page rotation\n        //----------------------------------------------------------------\n        PARENTCHECK(rotation, \"\"\"Page rotation.\"\"\")\n        %pythoncode %{@property%}\n        int rotation()\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            if (!page) return 0;\n            return JM_page_rotation(gctx, page);\n        }\n\n        /*********************************************************************/\n        // set_rotation() - set page rotation\n        /*********************************************************************/\n        FITZEXCEPTION(set_rotation, !result)\n        PARENTCHECK(set_rotation, \"\"\"Set page rotation.\"\"\")\n        PyObject *set_rotation(int rotation)\n        {\n            fz_try(gctx) {\n                pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n                ASSERT_PDF(page);\n                int rot = JM_norm_rotation(rotation);\n                pdf_dict_put_int(gctx, page->obj, PDF_NAME(Rotate), (int64_t) rot);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        /*********************************************************************/\n        // Page._addAnnot_FromString\n        // Add new links provided as an array of string object definitions.\n        /*********************************************************************/\n        FITZEXCEPTION(_addAnnot_FromString, !result)\n        PARENTCHECK(_addAnnot_FromString, \"\"\"Add links from list of object sources.\"\"\")\n        PyObject *_addAnnot_FromString(PyObject *linklist)\n        {\n            pdf_obj *annots, *annot, *ind_obj;\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            PyObject *txtpy = NULL;\n            char *text = NULL;\n            Py_ssize_t lcount = PyTuple_Size(linklist); // link count\n            if (lcount < 1) Py_RETURN_NONE;\n            Py_ssize_t i = -1;\n            fz_var(text);\n\n            // insert links from the provided sources\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                if (!PyTuple_Check(linklist)) {\n                    RAISEPY(gctx, \"bad 'linklist' argument\", PyExc_ValueError);\n                }\n                if (!pdf_dict_get(gctx, page->obj, PDF_NAME(Annots))) {\n                    pdf_dict_put_array(gctx, page->obj, PDF_NAME(Annots), lcount);\n                }\n                annots = pdf_dict_get(gctx, page->obj, PDF_NAME(Annots));\n                for (i = 0; i < lcount; i++) {\n                    fz_try(gctx) {\n                        for (; i < lcount; i++) {\n                            text = JM_StrAsChar(PyTuple_GET_ITEM(linklist, i));\n                    if (!text) {\n                        PySys_WriteStderr(\"skipping bad link / annot item %zi.\\n\", i);\n                        continue;\n                    }\n                        annot = pdf_add_object_drop(gctx, page->doc,\n                                JM_pdf_obj_from_str(gctx, page->doc, text));\n                        ind_obj = pdf_new_indirect(gctx, page->doc, pdf_to_num(gctx, annot), 0);\n                        pdf_array_push_drop(gctx, annots, ind_obj);\n                        pdf_drop_obj(gctx, annot);\n                    }\n                    }\n                    fz_catch(gctx) {\n                        PySys_WriteStderr(\"skipping bad link / annot item %zi.\\n\", i);\n                    }\n                }\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // Page clean contents stream\n        //----------------------------------------------------------------\n        FITZEXCEPTION(clean_contents, !result)\n        %pythonprepend clean_contents\n%{\"\"\"Clean page /Contents into one object.\"\"\"\nCheckParent(self)\nif not sanitize and not self.is_wrapped:\n    self.wrap_contents()%}\n        PyObject *clean_contents(int sanitize=1)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            if (!page) {\n                Py_RETURN_NONE;\n            }\n            #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n            pdf_filter_factory list[2] = { 0 };\n            pdf_sanitize_filter_options sopts = { 0 };\n            pdf_filter_options filter = {\n                1,     // recurse: true\n                0,     // instance forms\n                0,     // do not ascii-escape binary data\n                0,     // no_update\n                NULL,  // end_page_opaque\n                NULL,  // end page\n                list,  // filters\n                };\n            if (sanitize) {\n              list[0].filter = pdf_new_sanitize_filter;\n              list[0].options = &sopts;\n            }\n            #else\n            pdf_filter_options filter = {\n                NULL,  // opaque\n                NULL,  // image filter\n                NULL,  // text filter\n                NULL,  // after text\n                NULL,  // end page\n                1,     // recurse: true\n                1,     // instance forms\n                1,     // sanitize plus filtering\n                0      // do not ascii-escape binary data\n                };\n            filter.sanitize = sanitize;\n            #endif\n            fz_try(gctx) {\n                pdf_filter_page_contents(gctx, page->doc, page, &filter);\n            }\n            fz_catch(gctx) {\n                Py_RETURN_NONE;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // Show a PDF page\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_show_pdf_page, !result)\n        PyObject *_show_pdf_page(struct Page *fz_srcpage, int overlay=1, PyObject *matrix=NULL, int xref=0, int oc=0, PyObject *clip = NULL, struct Graftmap *graftmap = NULL, char *_imgname = NULL)\n        {\n            pdf_obj *xobj1=NULL, *xobj2=NULL, *resources;\n            fz_buffer *res=NULL, *nres=NULL;\n            fz_rect cropbox = JM_rect_from_py(clip);\n            fz_matrix mat = JM_matrix_from_py(matrix);\n            int rc_xref = xref;\n            fz_var(xobj1);\n            fz_var(xobj2);\n            fz_try(gctx) {\n                pdf_page *tpage = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n                pdf_obj *tpageref = tpage->obj;\n                pdf_document *pdfout = tpage->doc;    // target PDF\n                ENSURE_OPERATION(gctx, pdfout);\n                //-------------------------------------------------------------\n                // convert the source page to a Form XObject\n                //-------------------------------------------------------------\n                xobj1 = JM_xobject_from_page(gctx, pdfout, (fz_page *) fz_srcpage,\n                                             xref, (pdf_graft_map *) graftmap);\n                if (!rc_xref) rc_xref = pdf_to_num(gctx, xobj1);\n\n                //-------------------------------------------------------------\n                // create referencing XObject (controls display on target page)\n                //-------------------------------------------------------------\n                // fill reference to xobj1 into the /Resources\n                //-------------------------------------------------------------\n                pdf_obj *subres1 = pdf_new_dict(gctx, pdfout, 5);\n                pdf_dict_puts(gctx, subres1, \"fullpage\", xobj1);\n                pdf_obj *subres  = pdf_new_dict(gctx, pdfout, 5);\n                pdf_dict_put_drop(gctx, subres, PDF_NAME(XObject), subres1);\n\n                res = fz_new_buffer(gctx, 20);\n                fz_append_string(gctx, res, \"/fullpage Do\");\n\n                xobj2 = pdf_new_xobject(gctx, pdfout, cropbox, mat, subres, res);\n                if (oc > 0) {\n                    JM_add_oc_object(gctx, pdfout, pdf_resolve_indirect(gctx, xobj2), oc);\n                }\n                pdf_drop_obj(gctx, subres);\n                fz_drop_buffer(gctx, res);\n\n                //-------------------------------------------------------------\n                // update target page with xobj2:\n                //-------------------------------------------------------------\n                // 1. insert Xobject in Resources\n                //-------------------------------------------------------------\n                resources = pdf_dict_get_inheritable(gctx, tpageref, PDF_NAME(Resources));\n                subres = pdf_dict_get(gctx, resources, PDF_NAME(XObject));\n                if (!subres) {\n                    subres = pdf_dict_put_dict(gctx, resources, PDF_NAME(XObject), 5);\n                }\n\n                pdf_dict_puts(gctx, subres, _imgname, xobj2);\n\n                //-------------------------------------------------------------\n                // 2. make and insert new Contents object\n                //-------------------------------------------------------------\n                nres = fz_new_buffer(gctx, 50);       // buffer for Do-command\n                fz_append_string(gctx, nres, \" q /\");    // Do-command\n                fz_append_string(gctx, nres, _imgname);\n                fz_append_string(gctx, nres, \" Do Q \");\n\n                JM_insert_contents(gctx, pdfout, tpageref, nres, overlay);\n                fz_drop_buffer(gctx, nres);\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, xobj1);\n                pdf_drop_obj(gctx, xobj2);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", rc_xref);\n        }\n\n        //----------------------------------------------------------------\n        // insert an image\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_insert_image, !result)\n        PyObject *\n        _insert_image(char *filename=NULL,\n                struct Pixmap *pixmap=NULL,\n                PyObject *stream=NULL,\n                PyObject *imask=NULL,\n                PyObject *clip=NULL,\n                int overlay=1,\n                int rotate=0,\n                int keep_proportion=1,\n                int oc=0,\n                int width=0,\n                int height=0,\n                int xref=0,\n                int alpha=-1,\n                const char *_imgname=NULL,\n                PyObject *digests=NULL)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_document *pdf = page->doc;\n            float w = width, h = height;\n            fz_pixmap *pm = NULL;\n            fz_pixmap *pix = NULL;\n            fz_image *mask = NULL, *zimg = NULL, *image = NULL, *freethis = NULL;\n            pdf_obj *resources, *xobject, *ref;\n            fz_buffer *nres = NULL,  *imgbuf = NULL, *maskbuf = NULL;\n            fz_compressed_buffer *cbuf1 = NULL;\n            int xres, yres, bpc, img_xref = xref, rc_digest = 0;\n            unsigned char digest[16];\n            PyObject *md5_py = NULL, *temp;\n            const char *template = \"\\nq\\n%g %g %g %g %g %g cm\\n/%s Do\\nQ\\n\";\n\n            fz_try(gctx) {\n                if (xref > 0) {\n                    ref = pdf_new_indirect(gctx, pdf, xref, 0);\n                    w = pdf_to_int(gctx,\n                        pdf_dict_geta(gctx, ref,\n                        PDF_NAME(Width), PDF_NAME(W)));\n                    h = pdf_to_int(gctx,\n                        pdf_dict_geta(gctx, ref,\n                        PDF_NAME(Height), PDF_NAME(H)));\n                    if ((w + h) == 0) {\n                        RAISEPY(gctx, MSG_IS_NO_IMAGE, PyExc_ValueError);\n                    }\n                    goto have_xref;\n                }\n                if (EXISTS(stream)) {\n                    imgbuf = JM_BufferFromBytes(gctx, stream);\n                    goto have_stream;\n                }\n                if (filename) {\n                    imgbuf = fz_read_file(gctx, filename);\n                    goto have_stream;\n                }\n            // process pixmap ---------------------------------\n                fz_pixmap *arg_pix = (fz_pixmap *) pixmap;\n                w = arg_pix->w;\n                h = arg_pix->h;\n                fz_md5_pixmap(gctx, arg_pix, digest);\n                md5_py = PyBytes_FromStringAndSize(digest, 16);\n                temp = PyDict_GetItem(digests, md5_py);\n                if (temp) {\n                    img_xref = (int) PyLong_AsLong(temp);\n                    ref = pdf_new_indirect(gctx, page->doc, img_xref, 0);\n                    goto have_xref;\n                }\n                if (arg_pix->alpha == 0) {\n                    image = fz_new_image_from_pixmap(gctx, arg_pix, NULL);\n                } else {\n                    pm = fz_convert_pixmap(gctx, arg_pix, NULL, NULL, NULL,\n                            fz_default_color_params, 1);\n                    pm->alpha = 0;\n                    pm->colorspace = NULL;\n                    mask = fz_new_image_from_pixmap(gctx, pm, NULL);\n                    image = fz_new_image_from_pixmap(gctx, arg_pix, mask);\n                }\n                goto have_image;\n\n            // process stream ---------------------------------\n            have_stream:;\n                fz_md5 state;\n                fz_md5_init(&state);\n                fz_md5_update(&state, imgbuf->data, imgbuf->len);\n                if (imask != Py_None) {\n                    maskbuf = JM_BufferFromBytes(gctx, imask);\n                    fz_md5_update(&state, maskbuf->data, maskbuf->len);\n                }\n                fz_md5_final(&state, digest);\n                md5_py = PyBytes_FromStringAndSize(digest, 16);\n                temp = PyDict_GetItem(digests, md5_py);\n                if (temp) {\n                    img_xref = (int) PyLong_AsLong(temp);\n                    ref = pdf_new_indirect(gctx, page->doc, img_xref, 0);\n                    w = pdf_to_int(gctx,\n                        pdf_dict_geta(gctx, ref,\n                        PDF_NAME(Width), PDF_NAME(W)));\n                    h = pdf_to_int(gctx,\n                        pdf_dict_geta(gctx, ref,\n                        PDF_NAME(Height), PDF_NAME(H)));\n                    goto have_xref;\n                }\n                image = fz_new_image_from_buffer(gctx, imgbuf);\n                w = image->w;\n                h = image->h;\n                if (imask == Py_None) {\n                    goto have_image;\n                }\n\n                cbuf1 = fz_compressed_image_buffer(gctx, image);\n                if (!cbuf1) {\n                    RAISEPY(gctx, \"uncompressed image cannot have mask\", PyExc_ValueError);\n                }\n                bpc = image->bpc;\n                fz_colorspace *colorspace = image->colorspace;\n                fz_image_resolution(image, &xres, &yres);\n                mask = fz_new_image_from_buffer(gctx, maskbuf);\n                zimg = fz_new_image_from_compressed_buffer(gctx, w, h,\n                            bpc, colorspace, xres, yres, 1, 0, NULL,\n                            NULL, cbuf1, mask);\n                freethis = image;\n                image = zimg;\n                zimg = NULL;\n                goto have_image;\n\n            have_image:;\n                ref =  pdf_add_image(gctx, pdf, image);\n                if (oc) {\n                    JM_add_oc_object(gctx, pdf, ref, oc);\n                }\n                img_xref = pdf_to_num(gctx, ref);\n                DICT_SETITEM_DROP(digests, md5_py, Py_BuildValue(\"i\", img_xref));\n                rc_digest = 1;\n            have_xref:;\n                resources = pdf_dict_get_inheritable(gctx, page->obj,\n                                PDF_NAME(Resources));\n                if (!resources) {\n                    resources = pdf_dict_put_dict(gctx, page->obj,\n                                    PDF_NAME(Resources), 2);\n                }\n                xobject = pdf_dict_get(gctx, resources, PDF_NAME(XObject));\n                if (!xobject) {\n                    xobject = pdf_dict_put_dict(gctx, resources,\n                                  PDF_NAME(XObject), 2);\n                }\n                fz_matrix mat = calc_image_matrix(w, h, clip, rotate, keep_proportion);\n                pdf_dict_puts_drop(gctx, xobject, _imgname, ref);\n                nres = fz_new_buffer(gctx, 50);\n                fz_append_printf(gctx, nres, template,\n                                 mat.a, mat.b, mat.c, mat.d, mat.e, mat.f, _imgname);\n                JM_insert_contents(gctx, pdf, page->obj, nres, overlay);\n            }\n            fz_always(gctx) {\n                if (freethis) {\n                    fz_drop_image(gctx, freethis);\n                } else {\n                    fz_drop_image(gctx, image);\n                }\n                fz_drop_image(gctx, mask);\n                fz_drop_image(gctx, zimg);\n                fz_drop_pixmap(gctx, pix);\n                fz_drop_pixmap(gctx, pm);\n                fz_drop_buffer(gctx, imgbuf);\n                fz_drop_buffer(gctx, maskbuf);\n                fz_drop_buffer(gctx, nres);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n\n            if (rc_digest) {\n                return Py_BuildValue(\"iO\", img_xref, digests);\n            } else {\n                return Py_BuildValue(\"iO\", img_xref, Py_None);\n            }\n        }\n\n\n        //----------------------------------------------------------------\n        // Page.refresh()\n        //----------------------------------------------------------------\n        %pythoncode %{\n        def refresh(self):\n            doc = self.parent\n            page = doc.reload_page(self)\n            self = page\n        %}\n\n\n        //----------------------------------------------------------------\n        // insert font\n        //----------------------------------------------------------------\n        %pythoncode\n%{\ndef insert_font(self, fontname=\"helv\", fontfile=None, fontbuffer=None,\n               set_simple=False, wmode=0, encoding=0):\n    doc = self.parent\n    if doc is None:\n        raise ValueError(\"orphaned object: parent is None\")\n    idx = 0\n\n    if fontname.startswith(\"/\"):\n        fontname = fontname[1:]\n    inv_chars = INVALID_NAME_CHARS.intersection(fontname)\n    if inv_chars != set():\n        raise ValueError(f\"bad fontname chars {inv_chars}\")\n\n    font = CheckFont(self, fontname)\n    if font is not None:                    # font already in font list of page\n        xref = font[0]                      # this is the xref\n        if CheckFontInfo(doc, xref):        # also in our document font list?\n            return xref                     # yes: we are done\n        # need to build the doc FontInfo entry - done via get_char_widths\n        doc.get_char_widths(xref)\n        return xref\n\n    #--------------------------------------------------------------------------\n    # the font is not present for this page\n    #--------------------------------------------------------------------------\n\n    bfname = Base14_fontdict.get(fontname.lower(), None) # BaseFont if Base-14 font\n\n    serif = 0\n    CJK_number = -1\n    CJK_list_n = [\"china-t\", \"china-s\", \"japan\", \"korea\"]\n    CJK_list_s = [\"china-ts\", \"china-ss\", \"japan-s\", \"korea-s\"]\n\n    try:\n        CJK_number = CJK_list_n.index(fontname)\n        serif = 0\n    except:\n        pass\n\n    if CJK_number < 0:\n        try:\n            CJK_number = CJK_list_s.index(fontname)\n            serif = 1\n        except:\n            pass\n\n    if fontname.lower() in fitz_fontdescriptors.keys():\n        import pymupdf_fonts\n        fontbuffer = pymupdf_fonts.myfont(fontname)  # make a copy\n        del pymupdf_fonts\n\n    # install the font for the page\n    if fontfile != None:\n        if type(fontfile) is str:\n            fontfile_str = fontfile\n        elif hasattr(fontfile, \"absolute\"):\n            fontfile_str = str(fontfile)\n        elif hasattr(fontfile, \"name\"):\n            fontfile_str = fontfile.name\n        else:\n            raise ValueError(\"bad fontfile\")\n    else:\n        fontfile_str = None\n    val = self._insertFont(fontname, bfname, fontfile_str, fontbuffer, set_simple, idx,\n                           wmode, serif, encoding, CJK_number)\n\n    if not val:                   # did not work, error return\n        return val\n\n    xref = val[0]                 # xref of installed font\n    fontdict = val[1]\n\n    if CheckFontInfo(doc, xref):  # check again: document already has this font\n        return xref               # we are done\n\n    # need to create document font info\n    doc.get_char_widths(xref, fontdict=fontdict)\n    return xref\n\n%}\n\n        FITZEXCEPTION(_insertFont, !result)\n        PyObject *_insertFont(char *fontname, char *bfname,\n                             char *fontfile,\n                             PyObject *fontbuffer,\n                             int set_simple, int idx,\n                             int wmode, int serif,\n                             int encoding, int ordering)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            pdf_document *pdf;\n            pdf_obj *resources, *fonts, *font_obj;\n            PyObject *value;\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                pdf = page->doc;\n\n                value = JM_insert_font(gctx, pdf, bfname, fontfile,fontbuffer,\n                            set_simple, idx, wmode, serif, encoding, ordering);\n\n                // get the objects /Resources, /Resources/Font\n                resources = pdf_dict_get_inheritable(gctx, page->obj, PDF_NAME(Resources));\n                fonts = pdf_dict_get(gctx, resources, PDF_NAME(Font));\n                if (!fonts) {  // page has no fonts yet\n                    fonts = pdf_new_dict(gctx, pdf, 5);\n                    pdf_dict_putl_drop(gctx, page->obj, fonts, PDF_NAME(Resources), PDF_NAME(Font), NULL);\n                }\n                // store font in resources and fonts objects will contain named reference to font\n                int xref = 0;\n                JM_INT_ITEM(value, 0, &xref);\n                if (!xref) {\n                    RAISEPY(gctx, \"cannot insert font\", PyExc_RuntimeError);\n                }\n                font_obj = pdf_new_indirect(gctx, pdf, xref, 0);\n                pdf_dict_puts_drop(gctx, fonts, fontname, font_obj);\n            }\n            fz_always(gctx) {\n                ;\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            return value;\n        }\n\n        //----------------------------------------------------------------\n        // Get page transformation matrix\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(transformation_matrix, \"\"\"Page transformation matrix.\"\"\")\n        %pythonappend transformation_matrix %{\n        if self.rotation % 360 == 0:\n            val = Matrix(val)\n        else:\n            val = Matrix(1, 0, 0, -1, 0, self.cropbox.height)\n        %}\n        PyObject *transformation_matrix()\n        {\n            fz_matrix ctm = fz_identity;\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            if (!page) return JM_py_from_matrix(ctm);\n            fz_try(gctx) {\n                pdf_page_transform(gctx, page, NULL, &ctm);\n            }\n            fz_catch(gctx) {;}\n            return JM_py_from_matrix(ctm);\n        }\n\n        //----------------------------------------------------------------\n        // Page Get list of contents objects\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_contents, !result)\n        PARENTCHECK(get_contents, \"\"\"Get xrefs of /Contents objects.\"\"\")\n        PyObject *get_contents()\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) $self);\n            PyObject *list = NULL;\n            pdf_obj *contents = NULL, *icont = NULL;\n            int i, xref;\n            size_t n = 0;\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                contents = pdf_dict_get(gctx, page->obj, PDF_NAME(Contents));\n                if (pdf_is_array(gctx, contents)) {\n                    n = pdf_array_len(gctx, contents);\n                    list = PyList_New(n);\n                    for (i = 0; i < n; i++) {\n                        icont = pdf_array_get(gctx, contents, i);\n                        xref = pdf_to_num(gctx, icont);\n                        PyList_SET_ITEM(list, i, Py_BuildValue(\"i\", xref));\n                    }\n                }\n                else if (contents) {\n                    list = PyList_New(1);\n                    xref = pdf_to_num(gctx, contents);\n                    PyList_SET_ITEM(list, 0, Py_BuildValue(\"i\", xref));\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            if (list) {\n                return list;\n            }\n            return PyList_New(0);\n        }\n\n        //----------------------------------------------------------------\n        //\n        //----------------------------------------------------------------\n        %pythoncode %{\n        def set_contents(self, xref: int)->None:\n            \"\"\"Set object at 'xref' as the page's /Contents.\"\"\"\n            CheckParent(self)\n            doc = self.parent\n            if doc.is_closed:\n                raise ValueError(\"document closed\")\n            if not doc.is_pdf:\n                raise ValueError(\"is no PDF\")\n            if not xref in range(1, doc.xref_length()):\n                raise ValueError(\"bad xref\")\n            if not doc.xref_is_stream(xref):\n                raise ValueError(\"xref is no stream\")\n            doc.xref_set_key(self.xref, \"Contents\", \"%i 0 R\" % xref)\n\n\n        @property\n        def is_wrapped(self):\n            \"\"\"Check if /Contents is wrapped with string pair \"q\" / \"Q\".\"\"\"\n            if getattr(self, \"was_wrapped\", False):  # costly checks only once\n                return True\n            cont = self.read_contents().split()\n            if cont == []:  # no contents treated as okay\n                self.was_wrapped = True\n                return True\n            if cont[0] != b\"q\" or cont[-1] != b\"Q\":\n                return False  # potential \"geometry\" issue\n            self.was_wrapped = True  # cheap check next time\n            return True\n\n\n        def wrap_contents(self):\n            if self.is_wrapped:  # avoid unnecessary wrapping\n                return\n            TOOLS._insert_contents(self, b\"q\\n\", False)\n            TOOLS._insert_contents(self, b\"\\nQ\", True)\n            self.was_wrapped = True  # indicate not needed again\n\n\n        def links(self, kinds=None):\n            \"\"\" Generator over the links of a page.\n\n            Args:\n                kinds: (list) link kinds to subselect from. If none,\n                       all links are returned. E.g. kinds=[LINK_URI]\n                       will only yield URI links.\n            \"\"\"\n            all_links = self.get_links()\n            for link in all_links:\n                if kinds is None or link[\"kind\"] in kinds:\n                    yield (link)\n\n\n        def annots(self, types=None):\n            \"\"\" Generator over the annotations of a page.\n\n            Args:\n                types: (list) annotation types to subselect from. If none,\n                       all annotations are returned. E.g. types=[PDF_ANNOT_LINE]\n                       will only yield line annotations.\n            \"\"\"\n            skip_types = (PDF_ANNOT_LINK, PDF_ANNOT_POPUP, PDF_ANNOT_WIDGET)\n            if not hasattr(types, \"__getitem__\"):\n                annot_xrefs = [a[0] for a in self.annot_xrefs() if a[1] not in skip_types]\n            else:\n                annot_xrefs = [a[0] for a in self.annot_xrefs() if a[1] in types and a[1] not in skip_types]\n            for xref in annot_xrefs:\n                annot = self.load_annot(xref)\n                annot._yielded=True\n                yield annot\n\n\n        def widgets(self, types=None):\n            \"\"\" Generator over the widgets of a page.\n\n            Args:\n                types: (list) field types to subselect from. If none,\n                        all fields are returned. E.g. types=[PDF_WIDGET_TYPE_TEXT]\n                        will only yield text fields.\n            \"\"\"\n            widget_xrefs = [a[0] for a in self.annot_xrefs() if a[1] == PDF_ANNOT_WIDGET]\n            for xref in widget_xrefs:\n                widget = self.load_widget(xref)\n                if types == None or widget.field_type in types:\n                    yield (widget)\n\n\n        def __str__(self):\n            CheckParent(self)\n            x = self.parent.name\n            if self.parent.stream is not None:\n                x = \"<memory, doc# %i>\" % (self.parent._graft_id,)\n            if x == \"\":\n                x = \"<new PDF, doc# %i>\" % self.parent._graft_id\n            return \"page %s of %s\" % (self.number, x)\n\n        def __repr__(self):\n            CheckParent(self)\n            x = self.parent.name\n            if self.parent.stream is not None:\n                x = \"<memory, doc# %i>\" % (self.parent._graft_id,)\n            if x == \"\":\n                x = \"<new PDF, doc# %i>\" % self.parent._graft_id\n            return \"page %s of %s\" % (self.number, x)\n\n        def _reset_annot_refs(self):\n            \"\"\"Invalidate / delete all annots of this page.\"\"\"\n            for annot in self._annot_refs.values():\n                if annot:\n                    annot._erase()\n            self._annot_refs.clear()\n\n        @property\n        def xref(self):\n            \"\"\"PDF xref number of page.\"\"\"\n            CheckParent(self)\n            return self.parent.page_xref(self.number)\n\n        def _erase(self):\n            self._reset_annot_refs()\n            self._image_infos = None\n            try:\n                self.parent._forget_page(self)\n            except:\n                pass\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n            self.parent = None\n            self.number = None\n\n\n        def __del__(self):\n            self._erase()\n\n\n        def get_fonts(self, full=False):\n            \"\"\"List of fonts defined in the page object.\"\"\"\n            CheckParent(self)\n            return self.parent.get_page_fonts(self.number, full=full)\n\n\n        def get_images(self, full=False):\n            \"\"\"List of images defined in the page object.\"\"\"\n            CheckParent(self)\n            ret = self.parent.get_page_images(self.number, full=full)\n            return ret\n\n\n        def get_xobjects(self):\n            \"\"\"List of xobjects defined in the page object.\"\"\"\n            CheckParent(self)\n            return self.parent.get_page_xobjects(self.number)\n\n\n        def read_contents(self):\n            \"\"\"All /Contents streams concatenated to one bytes object.\"\"\"\n            return TOOLS._get_all_contents(self)\n\n\n        @property\n        def mediabox_size(self):\n            return Point(self.mediabox.x1, self.mediabox.y1)\n        %}\n    }\n};\n%clearnodefaultctor;\n\n//------------------------------------------------------------------------\n// Pixmap\n//------------------------------------------------------------------------\nstruct Pixmap\n{\n    %extend {\n        ~Pixmap() {\n            DEBUGMSG1(\"Pixmap\");\n            fz_pixmap *this_pix = (fz_pixmap *) $self;\n            fz_drop_pixmap(gctx, this_pix);\n            DEBUGMSG2;\n        }\n        FITZEXCEPTION(Pixmap, !result)\n        %pythonprepend Pixmap\n%{\"\"\"Pixmap(colorspace, irect, alpha) - empty pixmap.\nPixmap(colorspace, src) - copy changing colorspace.\nPixmap(src, width, height,[clip]) - scaled copy, float dimensions.\nPixmap(src, alpha=True) - copy adding / dropping alpha.\nPixmap(source, mask) - from a non-alpha and a mask pixmap.\nPixmap(file) - from an image file.\nPixmap(memory) - from an image in memory (bytes).\nPixmap(colorspace, width, height, samples, alpha) - from samples data.\nPixmap(PDFdoc, xref) - from an image xref in a PDF document.\n\"\"\"%}\n        //----------------------------------------------------------------\n        // create empty pixmap with colorspace and IRect\n        //----------------------------------------------------------------\n        Pixmap(struct Colorspace *cs, PyObject *bbox, int alpha = 0)\n        {\n            fz_pixmap *pm = NULL;\n            fz_try(gctx) {\n                pm = fz_new_pixmap_with_bbox(gctx, (fz_colorspace *) cs, JM_irect_from_py(bbox), NULL, alpha);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pm;\n        }\n\n        //----------------------------------------------------------------\n        // copy pixmap, converting colorspace\n        //----------------------------------------------------------------\n        Pixmap(struct Colorspace *cs, struct Pixmap *spix)\n        {\n            fz_pixmap *pm = NULL;\n            fz_try(gctx) {\n                if (!fz_pixmap_colorspace(gctx, (fz_pixmap *) spix)) {\n                    RAISEPY(gctx, \"source colorspace must not be None\", PyExc_ValueError);\n                }\n                fz_colorspace *cspace = NULL;\n                if (cs) {\n                    cspace = (fz_colorspace *) cs;\n                }\n                if (cspace) {\n                    pm = fz_convert_pixmap(gctx, (fz_pixmap *) spix, cspace, NULL, NULL, fz_default_color_params, 1);\n                } else {\n                    pm = fz_new_pixmap_from_alpha_channel(gctx, (fz_pixmap *) spix);\n                    if (!pm) {\n                        RAISEPY(gctx, MSG_PIX_NOALPHA, PyExc_RuntimeError);\n                    }\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pm;\n        }\n\n\n        //----------------------------------------------------------------\n        // add mask to a pixmap w/o alpha channel\n        //----------------------------------------------------------------\n        Pixmap(struct Pixmap *spix, struct Pixmap *mpix)\n        {\n            fz_pixmap *dst = NULL;\n            fz_pixmap *spm = (fz_pixmap *) spix;\n            fz_pixmap *mpm = (fz_pixmap *) mpix;\n            fz_try(gctx) {\n                if (!spix) {  // intercept NULL for spix: make alpha only pix\n                    dst = fz_new_pixmap_from_alpha_channel(gctx, mpm);\n                    if (!dst) {\n                        RAISEPY(gctx, MSG_PIX_NOALPHA, PyExc_RuntimeError);\n                    }\n                } else {\n                    dst = fz_new_pixmap_from_color_and_mask(gctx, spm, mpm);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) dst;\n        }\n\n\n        //----------------------------------------------------------------\n        // create pixmap as scaled copy of another one\n        //----------------------------------------------------------------\n        Pixmap(struct Pixmap *spix, float w, float h, PyObject *clip=NULL)\n        {\n            fz_pixmap *pm = NULL;\n            fz_pixmap *src_pix = (fz_pixmap *) spix;\n            fz_try(gctx) {\n                fz_irect bbox = JM_irect_from_py(clip);\n                if (clip != Py_None && (fz_is_infinite_irect(bbox) || fz_is_empty_irect(bbox))) {\n                    RAISEPY(gctx, \"bad clip parameter\", PyExc_ValueError);\n                }\n                if (!fz_is_infinite_irect(bbox)) {\n                    pm = fz_scale_pixmap(gctx, src_pix, src_pix->x, src_pix->y, w, h, &bbox);\n                } else {\n                    pm = fz_scale_pixmap(gctx, src_pix, src_pix->x, src_pix->y, w, h, NULL);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pm;\n        }\n\n\n        //----------------------------------------------------------------\n        // copy pixmap & add / drop the alpha channel\n        //----------------------------------------------------------------\n        Pixmap(struct Pixmap *spix, int alpha=1)\n        {\n            fz_pixmap *pm = NULL, *src_pix = (fz_pixmap *) spix;\n            int n, w, h, i;\n            fz_separations *seps = NULL;\n            fz_try(gctx) {\n                if (!INRANGE(alpha, 0, 1)) {\n                    RAISEPY(gctx, \"bad alpha value\", PyExc_ValueError);\n                }\n                fz_colorspace *cs = fz_pixmap_colorspace(gctx, src_pix);\n                if (!cs && !alpha) {\n                    RAISEPY(gctx, \"cannot drop alpha for 'NULL' colorspace\", PyExc_ValueError);\n                }\n                n = fz_pixmap_colorants(gctx, src_pix);\n                w = fz_pixmap_width(gctx, src_pix);\n                h = fz_pixmap_height(gctx, src_pix);\n                pm = fz_new_pixmap(gctx, cs, w, h, seps, alpha);\n                pm->x = src_pix->x;\n                pm->y = src_pix->y;\n                pm->xres = src_pix->xres;\n                pm->yres = src_pix->yres;\n\n                // copy samples data ------------------------------------------\n                unsigned char *sptr = src_pix->samples;\n                unsigned char *tptr = pm->samples;\n                if (src_pix->alpha == pm->alpha) {  // identical samples\n                    memcpy(tptr, sptr, w * h * (n + alpha));\n                } else {\n                    for (i = 0; i < w * h; i++) {\n                        memcpy(tptr, sptr, n);\n                        tptr += n;\n                        if (pm->alpha) {\n                            tptr[0] = 255;\n                            tptr++;\n                        }\n                        sptr += n + src_pix->alpha;\n                    }\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pm;\n        }\n\n        //----------------------------------------------------------------\n        // create pixmap from samples data\n        //----------------------------------------------------------------\n        Pixmap(struct Colorspace *cs, int w, int h, PyObject *samples, int alpha=0)\n        {\n            int n = fz_colorspace_n(gctx, (fz_colorspace *) cs);\n            int stride = (n + alpha) * w;\n            fz_separations *seps = NULL;\n            fz_buffer *res = NULL;\n            fz_pixmap *pm = NULL;\n            fz_try(gctx) {\n                size_t size = 0;\n                unsigned char *c = NULL;\n                res = JM_BufferFromBytes(gctx, samples);\n                if (!res) {\n                    RAISEPY(gctx, \"bad samples data\", PyExc_ValueError);\n                }\n                size = fz_buffer_storage(gctx, res, &c);\n                if (stride * h != size) {\n                    RAISEPY(gctx, \"bad samples length\", PyExc_ValueError);\n                }\n                pm = fz_new_pixmap(gctx, (fz_colorspace *) cs, w, h, seps, alpha);\n                memcpy(pm->samples, c, size);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pm;\n        }\n\n\n        //----------------------------------------------------------------\n        // create pixmap from filename, file object, pathlib.Path or memory\n        //----------------------------------------------------------------\n        Pixmap(PyObject *imagedata)\n        {\n            fz_buffer *res = NULL;\n            fz_image *img = NULL;\n            fz_pixmap *pm = NULL;\n            PyObject *fname = NULL;\n            PyObject *name = PyUnicode_FromString(\"name\");\n            fz_try(gctx) {\n                if (PyObject_HasAttrString(imagedata, \"resolve\")) {\n                    fname = PyObject_CallMethod(imagedata, \"__str__\", NULL);\n                    if (fname) {\n                        img = fz_new_image_from_file(gctx, JM_StrAsChar(fname));\n                    }\n                } else if (PyObject_HasAttr(imagedata, name)) {\n                    fname = PyObject_GetAttr(imagedata, name);\n                    if (fname) {\n                        img = fz_new_image_from_file(gctx, JM_StrAsChar(fname));\n                    }\n                } else if (PyUnicode_Check(imagedata)) {\n                    img = fz_new_image_from_file(gctx, JM_StrAsChar(imagedata));\n                } else {\n                    res = JM_BufferFromBytes(gctx, imagedata);\n                    if (!res || !fz_buffer_storage(gctx, res, NULL)) {\n                        RAISEPY(gctx, \"bad image data\", PyExc_ValueError);\n                    }\n                    img = fz_new_image_from_buffer(gctx, res);\n                }\n                pm = fz_get_pixmap_from_image(gctx, img, NULL, NULL, NULL, NULL);\n                int xres, yres;\n                fz_image_resolution(img, &xres, &yres);\n                pm->xres = xres;\n                pm->yres = yres;\n            }\n            fz_always(gctx) {\n                Py_CLEAR(fname);\n                Py_CLEAR(name);\n                fz_drop_image(gctx, img);\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pm;\n        }\n\n\n        //----------------------------------------------------------------\n        // Create pixmap from PDF image identified by XREF number\n        //----------------------------------------------------------------\n        Pixmap(struct Document *doc, int xref)\n        {\n            fz_image *img = NULL;\n            fz_pixmap *pix = NULL;\n            pdf_obj *ref = NULL;\n            pdf_obj *type;\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) doc);\n            fz_try(gctx) {\n                ASSERT_PDF(pdf);\n                int xreflen = pdf_xref_len(gctx, pdf);\n                if (!INRANGE(xref, 1, xreflen-1)) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                ref = pdf_new_indirect(gctx, pdf, xref, 0);\n                type = pdf_dict_get(gctx, ref, PDF_NAME(Subtype));\n                if (!pdf_name_eq(gctx, type, PDF_NAME(Image)) &&\n                    !pdf_name_eq(gctx, type, PDF_NAME(Alpha)) &&\n                    !pdf_name_eq(gctx, type, PDF_NAME(Luminosity))) {\n                    RAISEPY(gctx, MSG_IS_NO_IMAGE, PyExc_ValueError);\n                }\n                img = pdf_load_image(gctx, pdf, ref);\n                pix = fz_get_pixmap_from_image(gctx, img, NULL, NULL, NULL, NULL);\n            }\n            fz_always(gctx) {\n                fz_drop_image(gctx, img);\n                pdf_drop_obj(gctx, ref);\n            }\n            fz_catch(gctx) {\n                fz_drop_pixmap(gctx, pix);\n                return NULL;\n            }\n            return (struct Pixmap *) pix;\n        }\n\n\n        //----------------------------------------------------------------\n        // warp\n        //----------------------------------------------------------------\n        FITZEXCEPTION(warp, !result)\n        %pythonprepend warp %{\n        \"\"\"Return pixmap from a warped quad.\"\"\"\n        EnsureOwnership(self)\n        if not quad.is_convex: raise ValueError(\"quad must be convex\")%}\n        struct Pixmap *warp(PyObject *quad, int width, int height)\n        {\n            fz_point points[4];\n            fz_quad q = JM_quad_from_py(quad);\n            fz_pixmap *dst = NULL;\n            points[0] = q.ul;\n            points[1] = q.ur;\n            points[2] = q.lr;\n            points[3] = q.ll;\n\n            fz_try(gctx) {\n                dst = fz_warp_pixmap(gctx, (fz_pixmap *) $self, points, width, height);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) dst;\n        }\n\n\n        //----------------------------------------------------------------\n        // shrink\n        //----------------------------------------------------------------\n        ENSURE_OWNERSHIP(shrink, \"\"\"Divide width and height by 2**factor.\n        E.g. factor=1 shrinks to 25% of original size (in place).\"\"\")\n        void shrink(int factor)\n        {\n            if (factor < 1)\n            {\n                JM_Warning(\"ignoring shrink factor < 1\");\n                return;\n            }\n            fz_subsample_pixmap(gctx, (fz_pixmap *) $self, factor);\n        }\n\n        //----------------------------------------------------------------\n        // apply gamma correction\n        //----------------------------------------------------------------\n        ENSURE_OWNERSHIP(gamma_with, \"\"\"Apply correction with some float.\ngamma=1 is a no-op.\"\"\")\n        void gamma_with(float gamma)\n        {\n            if (!fz_pixmap_colorspace(gctx, (fz_pixmap *) $self))\n            {\n                JM_Warning(\"colorspace invalid for function\");\n                return;\n            }\n            fz_gamma_pixmap(gctx, (fz_pixmap *) $self, gamma);\n        }\n\n        //----------------------------------------------------------------\n        // tint pixmap with color\n        //----------------------------------------------------------------\n        %pythonprepend tint_with\n%{\"\"\"Tint colors with modifiers for black and white.\"\"\"\nEnsureOwnership(self)\nif not self.colorspace or self.colorspace.n > 3:\n    print(\"warning: colorspace invalid for function\")\n    return%}\n        void tint_with(int black, int white)\n        {\n            fz_tint_pixmap(gctx, (fz_pixmap *) $self, black, white);\n        }\n\n        //-----------------------------------------------------------------\n        // clear all of pixmap samples to 0x00 */\n        //-----------------------------------------------------------------\n        ENSURE_OWNERSHIP(clear_with, \"\"\"Fill all color components with same value.\"\"\")\n        void clear_with()\n        {\n            fz_clear_pixmap(gctx, (fz_pixmap *) $self);\n        }\n\n        //-----------------------------------------------------------------\n        // clear total pixmap with value */\n        //-----------------------------------------------------------------\n        void clear_with(int value)\n        {\n            fz_clear_pixmap_with_value(gctx, (fz_pixmap *) $self, value);\n        }\n\n        //-----------------------------------------------------------------\n        // clear pixmap rectangle with value\n        //-----------------------------------------------------------------\n        void clear_with(int value, PyObject *bbox)\n        {\n            JM_clear_pixmap_rect_with_value(gctx, (fz_pixmap *) $self, value, JM_irect_from_py(bbox));\n        }\n\n        //-----------------------------------------------------------------\n        // copy pixmaps\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(copy, !result)\n        ENSURE_OWNERSHIP(copy, \"\"\"Copy bbox from another Pixmap.\"\"\")\n        PyObject *copy(struct Pixmap *src, PyObject *bbox)\n        {\n            fz_try(gctx) {\n                fz_pixmap *pm = (fz_pixmap *) $self, *src_pix = (fz_pixmap *) src;\n                if (!fz_pixmap_colorspace(gctx, src_pix)) {\n                    RAISEPY(gctx, \"cannot copy pixmap with NULL colorspace\", PyExc_ValueError);\n                }\n                if (pm->alpha != src_pix->alpha) {\n                    RAISEPY(gctx, \"source and target alpha must be equal\", PyExc_ValueError);\n                }\n                fz_copy_pixmap_rect(gctx, pm, src_pix, JM_irect_from_py(bbox), NULL);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //-----------------------------------------------------------------\n        // set alpha values\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(set_alpha, !result)\n        ENSURE_OWNERSHIP(set_alpha, \"\"\"Set alpha channel to values contained in a byte array.\nIf None, all alphas are 255.\n\nArgs:\n    alphavalues: (bytes) with length (width * height) or 'None'.\n    premultiply: (bool, True) premultiply colors with alpha values.\n    opaque: (tuple, length colorspace.n) this color receives opacity 0.\n    matte: (tuple, length colorspace.n) preblending background color.\n\"\"\")\n        PyObject *set_alpha(PyObject *alphavalues=NULL, int premultiply=1, PyObject *opaque=NULL, PyObject *matte=NULL)\n        {\n            fz_buffer *res = NULL;\n            fz_pixmap *pix = (fz_pixmap *) $self;\n            unsigned char alpha = 0, m = 0;\n            fz_try(gctx) {\n                if (pix->alpha == 0) {\n                    RAISEPY(gctx, MSG_PIX_NOALPHA, PyExc_ValueError);\n                }\n                size_t i, k, j;\n                size_t n = fz_pixmap_colorants(gctx, pix);\n                size_t w = (size_t) fz_pixmap_width(gctx, pix);\n                size_t h = (size_t) fz_pixmap_height(gctx, pix);\n                size_t balen = w * h * (n+1);\n                int colors[4];  // make this color opaque\n                int bgcolor[4];  // preblending background color\n                int zero_out = 0, bground = 0;\n                if (opaque && PySequence_Check(opaque) && PySequence_Size(opaque) == n) {\n                    for (i = 0; i < n; i++) {\n                        if (JM_INT_ITEM(opaque, i, &colors[i]) == 1) {\n                            RAISEPY(gctx, \"bad opaque components\", PyExc_ValueError);\n                        }\n                    }\n                    zero_out = 1;\n                }\n                if (matte && PySequence_Check(matte) && PySequence_Size(matte) == n) {\n                    for (i = 0; i < n; i++) {\n                        if (JM_INT_ITEM(matte, i, &bgcolor[i]) == 1) {\n                            RAISEPY(gctx, \"bad matte components\", PyExc_ValueError);\n                        }\n                    }\n                    bground = 1;\n                }\n                unsigned char *data = NULL;\n                size_t data_len = 0;\n                if (alphavalues && PyObject_IsTrue(alphavalues)) {\n                    res = JM_BufferFromBytes(gctx, alphavalues);\n                    data_len = fz_buffer_storage(gctx, res, &data);\n                    if (data_len < w * h) {\n                        RAISEPY(gctx, \"bad alpha values\", PyExc_ValueError);\n                    }\n                }\n                i = k = j = 0;\n                int data_fix = 255;\n                while (i < balen) {\n                    alpha = data[k];\n                    if (zero_out) {\n                        for (j = i; j < i+n; j++) {\n                            if (pix->samples[j] != (unsigned char) colors[j - i]) {\n                                data_fix = 255;\n                                break;\n                            } else {\n                                data_fix = 0;\n                            }\n                        }\n                    }\n                    if (data_len) {\n                        if (data_fix == 0) {\n                            pix->samples[i+n] = 0;\n                        } else {\n                            pix->samples[i+n] = alpha;\n                        }\n                        if (premultiply && !bground) {\n                            for (j = i; j < i+n; j++) {\n                                pix->samples[j] = fz_mul255(pix->samples[j], alpha);\n                            }\n                        } else if (bground) {\n                            for (j = i; j < i+n; j++) {\n                                m = (unsigned char) bgcolor[j - i];\n                                pix->samples[j] = m + fz_mul255((pix->samples[j] - m), alpha);\n                            }\n                        }\n                    } else {\n                        pix->samples[i+n] = data_fix;\n                    }\n                    i += n+1;\n                    k += 1;\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //-----------------------------------------------------------------\n        // Pixmap._tobytes\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(_tobytes, !result)\n        PyObject *_tobytes(int format, int jpg_quality)\n        {\n            fz_output *out = NULL;\n            fz_buffer *res = NULL;\n            PyObject *barray = NULL;\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            fz_try(gctx) {\n                size_t size = fz_pixmap_stride(gctx, pm) * pm->h;\n                res = fz_new_buffer(gctx, size);\n                out = fz_new_output_with_buffer(gctx, res);\n\n                switch(format) {\n                    case(1):\n                        fz_write_pixmap_as_png(gctx, out, pm);\n                        break;\n                    case(2):\n                        fz_write_pixmap_as_pnm(gctx, out, pm);\n                        break;\n                    case(3):\n                        fz_write_pixmap_as_pam(gctx, out, pm);\n                        break;\n                    case(5):           // Adobe Photoshop Document\n                        fz_write_pixmap_as_psd(gctx, out, pm);\n                        break;\n                    case(6):           // Postscript format\n                        fz_write_pixmap_as_ps(gctx, out, pm);\n                        break;\n                    #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n                    case(7):           // JPEG format\n                        #if FZ_VERSION_MINOR < 24\n                        fz_write_pixmap_as_jpeg(gctx, out, pm, jpg_quality);\n                        #else\n                        fz_write_pixmap_as_jpeg(gctx, out, pm, jpg_quality, 0 /*invert_cmyk*/);\n                        #endif\n                        break;\n                    #endif\n                    default:\n                        fz_write_pixmap_as_png(gctx, out, pm);\n                        break;\n                }\n                barray = JM_BinFromBuffer(gctx, res);\n            }\n            fz_always(gctx) {\n                fz_drop_output(gctx, out);\n                fz_drop_buffer(gctx, res);\n            }\n\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return barray;\n        }\n\n        %pythoncode %{\ndef tobytes(self, output=\"png\", jpg_quality=95):\n    \"\"\"Convert to binary image stream of desired type.\n\n    Can be used as input to GUI packages like tkinter.\n\n    Args:\n        output: (str) image type, default is PNG. Others are JPG, JPEG, PNM, PGM, PPM,\n                PBM, PAM, PSD, PS.\n    Returns:\n        Bytes object.\n    \"\"\"\n    EnsureOwnership(self)\n    valid_formats = {\"png\": 1, \"pnm\": 2, \"pgm\": 2, \"ppm\": 2, \"pbm\": 2,\n                     \"pam\": 3, \"psd\": 5, \"ps\": 6, \"jpg\": 7, \"jpeg\": 7}\n                     \n    idx = valid_formats.get(output.lower(), None)\n    if idx==None:\n        raise ValueError(f\"Image format {output} not in {tuple(valid_formats.keys())}\")\n    if self.alpha and idx in (2, 6, 7):\n        raise ValueError(\"'%s' cannot have alpha\" % output)\n    if self.colorspace and self.colorspace.n > 3 and idx in (1, 2, 4):\n        raise ValueError(\"unsupported colorspace for '%s'\" % output)\n    if idx == 7:\n        self.set_dpi(self.xres, self.yres)\n    barray = self._tobytes(idx, jpg_quality)\n    return barray\n    %}\n\n\n        //-----------------------------------------------------------------\n        // output as PDF-OCR\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(pdfocr_save, !result)\n        %pythonprepend pdfocr_save %{\n        \"\"\"Save pixmap as an OCR-ed PDF page.\"\"\"\n        EnsureOwnership(self)\n        if not os.getenv(\"TESSDATA_PREFIX\") and not tessdata:\n            raise RuntimeError(\"No OCR support: TESSDATA_PREFIX not set\")\n        %}\n        ENSURE_OWNERSHIP(pdfocr_save, )\n        PyObject *pdfocr_save(PyObject *filename, int compress=1, char *language=NULL, char *tessdata=NULL)\n        {\n            fz_pdfocr_options opts;\n            memset(&opts, 0, sizeof opts);\n            opts.compress = compress;\n            if (language) {\n                fz_strlcpy(opts.language, language, sizeof(opts.language));\n            }\n            if (tessdata) {\n                fz_strlcpy(opts.datadir, tessdata, sizeof(opts.language));\n            }\n            fz_output *out = NULL;\n            fz_pixmap *pix = (fz_pixmap *) $self;\n            fz_try(gctx) {\n                if (PyUnicode_Check(filename)) {\n                    fz_save_pixmap_as_pdfocr(gctx, pix, (char *) PyUnicode_AsUTF8(filename), 0, &opts);\n                } else {\n                    out = JM_new_output_fileptr(gctx, filename);\n                    fz_write_pixmap_as_pdfocr(gctx, out, pix, &opts);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_output(gctx, out);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode %{\n        def pdfocr_tobytes(self, compress=True, language=\"eng\", tessdata=None):\n            \"\"\"Save pixmap as an OCR-ed PDF page.\n\n            Args:\n                compress: (bool) compress, default 1 (True).\n                language: (str) language(s) occurring on page, default \"eng\" (English),\n                        multiples like \"eng+ger\" for English and German.\n                tessdata: (str) folder name of Tesseract's language support. Must be\n                        given if environment variable TESSDATA_PREFIX is not set.\n            Notes:\n                On failure, make sure Tesseract is installed and you have set the\n                environment variable \"TESSDATA_PREFIX\" to the folder containing your\n                Tesseract's language support data.\n            \"\"\"\n            if not os.getenv(\"TESSDATA_PREFIX\") and not tessdata:\n                raise RuntimeError(\"No OCR support: TESSDATA_PREFIX not set\")\n            EnsureOwnership(self)\n            from io import BytesIO\n            bio = BytesIO()\n            self.pdfocr_save(bio, compress=compress, language=language, tessdata=tessdata)\n            return bio.getvalue()\n        %}\n\n\n        //-----------------------------------------------------------------\n        // _writeIMG\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(_writeIMG, !result)\n        PyObject *_writeIMG(char *filename, int format, int jpg_quality)\n        {\n            fz_try(gctx) {\n                fz_pixmap *pm = (fz_pixmap *) $self;\n                switch(format) {\n                    case(1):\n                        fz_save_pixmap_as_png(gctx, pm, filename);\n                        break;\n                    case(2):\n                        fz_save_pixmap_as_pnm(gctx, pm, filename);\n                        break;\n                    case(3):\n                        fz_save_pixmap_as_pam(gctx, pm, filename);\n                        break;\n                    case(5): // Adobe Photoshop Document\n                        fz_save_pixmap_as_psd(gctx, pm, filename);\n                        break;\n                    case(6): // Postscript\n                        fz_save_pixmap_as_ps(gctx, pm, filename, 0);\n                        break;\n                    #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n                    case(7): // JPEG\n                        fz_save_pixmap_as_jpeg(gctx, pm, filename, jpg_quality);\n                        break;\n                    #endif\n                    default:\n                        fz_save_pixmap_as_png(gctx, pm, filename);\n                        break;\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n        %pythoncode %{\ndef save(self, filename, output=None, jpg_quality=95):\n    \"\"\"Output as image in format determined by filename extension.\n\n    Args:\n        output: (str) only use to overrule filename extension. Default is PNG.\n                Others are JPEG, JPG, PNM, PGM, PPM, PBM, PAM, PSD, PS.\n    \"\"\"\n    EnsureOwnership(self)\n    valid_formats = {\"png\": 1, \"pnm\": 2, \"pgm\": 2, \"ppm\": 2, \"pbm\": 2,\n                     \"pam\": 3, \"psd\": 5, \"ps\": 6, \"jpg\": 7, \"jpeg\": 7}\n                     \n    if type(filename) is str:\n        pass\n    elif hasattr(filename, \"absolute\"):\n        filename = str(filename)\n    elif hasattr(filename, \"name\"):\n        filename = filename.name\n    if output is None:\n        _, ext = os.path.splitext(filename)\n        output = ext[1:]\n\n    idx = valid_formats.get(output.lower(), None)\n    if idx == None:\n        raise ValueError(f\"Image format {output} not in {tuple(valid_formats.keys())}\")\n    if self.alpha and idx in (2, 6, 7):\n        raise ValueError(\"'%s' cannot have alpha\" % output)\n    if self.colorspace and self.colorspace.n > 3 and idx in (1, 2, 4):\n        raise ValueError(\"unsupported colorspace for '%s'\" % output)\n    if idx == 7:\n        self.set_dpi(self.xres, self.yres)\n    return self._writeIMG(filename, idx, jpg_quality)\n\ndef pil_save(self, *args, unmultiply=False, **kwargs):\n    \"\"\"Write to image file using Pillow.\n\n    Args are passed to Pillow's Image.save method, see their documentation.\n    Use instead of save when other output formats are desired.\n\n    :arg bool unmultiply: generates Pillow mode \"RGBa\" instead of \"RGBA\".\n        Relevant for colorspace RGB with alpha only.\n    \"\"\"\n    EnsureOwnership(self)\n    try:\n        from PIL import Image\n    except ImportError:\n        print(\"Pillow not installed\")\n        raise\n\n    cspace = self.colorspace\n    if cspace is None:\n        mode = \"L\"\n    elif cspace.n == 1:\n        mode = \"L\" if self.alpha == 0 else \"LA\"\n    elif cspace.n == 3:\n        mode = \"RGB\" if self.alpha == 0 else \"RGBA\"\n        if mode == \"RGBA\" and unmultiply:\n            mode = \"RGBa\"\n    else:\n        mode = \"CMYK\"\n\n    img = Image.frombytes(mode, (self.width, self.height), self.samples)\n\n    if \"dpi\" not in kwargs.keys():\n        kwargs[\"dpi\"] = (self.xres, self.yres)\n\n    img.save(*args, **kwargs)\n\ndef pil_tobytes(self, *args, unmultiply=False, **kwargs):\n    \"\"\"Convert to binary image stream using pillow.\n\n    Args are passed to Pillow's Image.save method, see their documentation.\n    Use instead of 'tobytes' when other output formats are needed.\n    \"\"\"\n    EnsureOwnership(self)\n    from io import BytesIO\n    bytes_out = BytesIO()\n    self.pil_save(bytes_out, *args, unmultiply=unmultiply, **kwargs)\n    return bytes_out.getvalue()\n\n        %}\n        //-----------------------------------------------------------------\n        // invert_irect\n        //-----------------------------------------------------------------\n        %pythonprepend invert_irect\n        %{\"\"\"Invert the colors inside a bbox.\"\"\"%}\n        PyObject *invert_irect(PyObject *bbox = NULL)\n        {\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            if (!fz_pixmap_colorspace(gctx, pm))\n                {\n                    JM_Warning(\"ignored for stencil pixmap\");\n                    return JM_BOOL(0);\n                }\n\n            fz_irect r = JM_irect_from_py(bbox);\n            if (fz_is_infinite_irect(r))\n                r = fz_pixmap_bbox(gctx, pm);\n\n            return JM_BOOL(JM_invert_pixmap_rect(gctx, pm, r));\n        }\n\n        //-----------------------------------------------------------------\n        // get one pixel as a list\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(pixel, !result)\n        ENSURE_OWNERSHIP(pixel, \"\"\"Get color tuple of pixel (x, y).\nIncludes alpha byte if applicable.\"\"\")\n        PyObject *pixel(int x, int y)\n        {\n            PyObject *p = NULL;\n            fz_try(gctx) {\n                fz_pixmap *pm = (fz_pixmap *) $self;\n                if (!INRANGE(x, 0, pm->w - 1) || !INRANGE(y, 0, pm->h - 1)) {\n                    RAISEPY(gctx, MSG_PIXEL_OUTSIDE, PyExc_ValueError);\n                }\n                int n = pm->n;\n                int stride = fz_pixmap_stride(gctx, pm);\n                int j, i = stride * y + n * x;\n                p = PyTuple_New(n);\n                for (j = 0; j < n; j++) {\n                    PyTuple_SET_ITEM(p, j, Py_BuildValue(\"i\", pm->samples[i + j]));\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return p;\n        }\n\n        //-----------------------------------------------------------------\n        // Set one pixel to a given color tuple\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(set_pixel, !result)\n        ENSURE_OWNERSHIP(set_pixel, \"\"\"Set color of pixel (x, y).\"\"\")\n        PyObject *set_pixel(int x, int y, PyObject *color)\n        {\n            fz_try(gctx) {\n                fz_pixmap *pm = (fz_pixmap *) $self;\n                if (!INRANGE(x, 0, pm->w - 1) || !INRANGE(y, 0, pm->h - 1)) {\n                    RAISEPY(gctx, MSG_PIXEL_OUTSIDE, PyExc_ValueError);\n                }\n                int n = pm->n;\n                if (!PySequence_Check(color) || PySequence_Size(color) != n) {\n                    RAISEPY(gctx, MSG_BAD_COLOR_SEQ, PyExc_ValueError);\n                }\n                int i, j;\n                unsigned char c[5];\n                for (j = 0; j < n; j++) {\n                    if (JM_INT_ITEM(color, j, &i) == 1) {\n                        RAISEPY(gctx, MSG_BAD_COLOR_SEQ, PyExc_ValueError);\n                    }\n                    if (!INRANGE(i, 0, 255)) {\n                        RAISEPY(gctx, MSG_BAD_COLOR_SEQ, PyExc_ValueError);\n                    }\n                    c[j] = (unsigned char) i;\n                }\n                int stride = fz_pixmap_stride(gctx, pm);\n                i = stride * y + n * x;\n                for (j = 0; j < n; j++) {\n                    pm->samples[i + j] = c[j];\n                }\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //-----------------------------------------------------------------\n        // Set Pixmap origin\n        //-----------------------------------------------------------------\n        ENSURE_OWNERSHIP(set_origin, \"\"\"Set top-left coordinates.\"\"\")\n        PyObject *set_origin(int x, int y)\n        {\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            pm->x = x;\n            pm->y = y;\n            Py_RETURN_NONE;\n        }\n\n        ENSURE_OWNERSHIP(set_dpi, \"\"\"Set resolution in both dimensions.\"\"\")\n        PyObject *set_dpi(int xres, int yres)\n        {\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            pm->xres = xres;\n            pm->yres = yres;\n            Py_RETURN_NONE;\n        }\n\n        //-----------------------------------------------------------------\n        // Set a rect to a given color tuple\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(set_rect, !result)\n        ENSURE_OWNERSHIP(set_rect, \"\"\"Set color of all pixels in bbox.\"\"\")\n        PyObject *set_rect(PyObject *bbox, PyObject *color)\n        {\n            PyObject *rc = NULL;\n            fz_try(gctx) {\n                fz_pixmap *pm = (fz_pixmap *) $self;\n                Py_ssize_t j, n = (Py_ssize_t) pm->n;\n                if (!PySequence_Check(color) || PySequence_Size(color) != n) {\n                    RAISEPY(gctx, MSG_BAD_COLOR_SEQ, PyExc_ValueError);\n                }\n                unsigned char c[5];\n                int i;\n                for (j = 0; j < n; j++) {\n                    if (JM_INT_ITEM(color, j, &i) == 1) {\n                        RAISEPY(gctx, MSG_BAD_COLOR_SEQ, PyExc_ValueError);\n                    }\n                    if (!INRANGE(i, 0, 255)) {\n                        RAISEPY(gctx, MSG_BAD_COLOR_SEQ, PyExc_ValueError);\n                    }\n                    c[j] = (unsigned char) i;\n                }\n                i = JM_fill_pixmap_rect_with_color(gctx, pm, c, JM_irect_from_py(bbox));\n                rc = JM_BOOL(i);\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            return rc;\n        }\n\n        //-----------------------------------------------------------------\n        // check if monochrome\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(is_monochrome, \"\"\"Check if pixmap is monochrome.\"\"\")\n        PyObject *is_monochrome()\n        {\n            return JM_BOOL(fz_is_pixmap_monochrome(gctx, (fz_pixmap *) $self));\n        }\n\n        //-----------------------------------------------------------------\n        // check if unicolor (only one color there)\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(is_unicolor, \"\"\"Check if pixmap has only one color.\"\"\")\n        PyObject *is_unicolor()\n        {\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            size_t i, n = pm->n, count = pm->w * pm->h * n;\n            unsigned char *s = pm->samples;\n            for (i = n; i < count; i += n) {\n                if (memcmp(s, s + i, n) != 0) {\n                    Py_RETURN_FALSE;\n                }\n            }\n            Py_RETURN_TRUE;\n        }\n\n\n        //-----------------------------------------------------------------\n        // count each pixmap color\n        //-----------------------------------------------------------------\n        FITZEXCEPTION(color_count, !result)\n        ENSURE_OWNERSHIP(color_count, \"\"\"Return count of each color.\"\"\")\n        PyObject *color_count(int colors=0, PyObject *clip=NULL)\n        {\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            PyObject *rc = NULL;\n            fz_try(gctx) {\n                rc = JM_color_count(gctx, pm, clip);\n                if (!rc) {\n                    RAISEPY(gctx, MSG_COLOR_COUNT_FAILED, PyExc_RuntimeError);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            if (!colors) {\n                Py_ssize_t len = PyDict_Size(rc);\n                Py_DECREF(rc);\n                return PyLong_FromSsize_t(len);\n            }\n            return rc;\n        }\n\n        %pythoncode %{\n        def color_topusage(self, clip=None):\n            \"\"\"Return most frequent color and its usage ratio.\"\"\"\n            EnsureOwnership(self)\n            allpixels = 0\n            cnt = 0\n            if clip != None and self.irect in Rect(clip):\n                clip = self.irect\n            for pixel, count in self.color_count(colors=True,clip=clip).items():\n                allpixels += count\n                if count > cnt:\n                    cnt = count\n                    maxpixel = pixel\n            if not allpixels:\n                return (1, bytes([255] * self.n))\n            return (cnt / allpixels, maxpixel)\n\n        %}\n\n        //-----------------------------------------------------------------\n        // MD5 digest of pixmap\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(digest, \"\"\"MD5 digest of pixmap (bytes).\"\"\")\n        PyObject *digest()\n        {\n            unsigned char digest[16];\n            fz_md5_pixmap(gctx, (fz_pixmap *) $self, digest);\n            return PyBytes_FromStringAndSize(digest, 16);\n        }\n\n        //-----------------------------------------------------------------\n        // get length of one image row\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(stride, \"\"\"Length of one image line (width * n).\"\"\")\n        PyObject *stride()\n        {\n            return PyLong_FromSize_t((size_t) fz_pixmap_stride(gctx, (fz_pixmap *) $self));\n        }\n\n        //-----------------------------------------------------------------\n        // x, y, width, height, xres, yres, n\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(xres, \"\"\"Resolution in x direction.\"\"\")\n        int xres()\n        {\n            fz_pixmap *this_pix = (fz_pixmap *) $self;\n            return this_pix->xres;\n        }\n\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(yres, \"\"\"Resolution in y direction.\"\"\")\n        int yres()\n        {\n            fz_pixmap *this_pix = (fz_pixmap *) $self;\n            return this_pix->yres;\n        }\n\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(w, \"\"\"The width.\"\"\")\n        PyObject *w()\n        {\n            return PyLong_FromSize_t((size_t) fz_pixmap_width(gctx, (fz_pixmap *) $self));\n        }\n\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(h, \"\"\"The height.\"\"\")\n        PyObject *h()\n        {\n            return PyLong_FromSize_t((size_t) fz_pixmap_height(gctx, (fz_pixmap *) $self));\n        }\n\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(x, \"\"\"x component of Pixmap origin.\"\"\")\n        int x()\n        {\n            return fz_pixmap_x(gctx, (fz_pixmap *) $self);\n        }\n\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(y, \"\"\"y component of Pixmap origin.\"\"\")\n        int y()\n        {\n            return fz_pixmap_y(gctx, (fz_pixmap *) $self);\n        }\n\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(n, \"\"\"The size of one pixel.\"\"\")\n        int n()\n        {\n            return fz_pixmap_components(gctx, (fz_pixmap *) $self);\n        }\n\n        //-----------------------------------------------------------------\n        // check alpha channel\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(alpha, \"\"\"Indicates presence of alpha channel.\"\"\")\n        int alpha()\n        {\n            return fz_pixmap_alpha(gctx, (fz_pixmap *) $self);\n        }\n\n        //-----------------------------------------------------------------\n        // get colorspace of pixmap\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(colorspace, \"\"\"Pixmap Colorspace.\"\"\")\n        struct Colorspace *colorspace()\n        {\n            return (struct Colorspace *) fz_pixmap_colorspace(gctx, (fz_pixmap *) $self);\n        }\n\n        //-----------------------------------------------------------------\n        // return irect of pixmap\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(irect, \"\"\"Pixmap bbox - an IRect object.\"\"\")\n        %pythonappend irect %{val = IRect(val)%}\n        PyObject *irect()\n        {\n            return JM_py_from_irect(fz_pixmap_bbox(gctx, (fz_pixmap *) $self));\n        }\n\n        //-----------------------------------------------------------------\n        // return size of pixmap\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(size, \"\"\"Pixmap size.\"\"\")\n        PyObject *size()\n        {\n            return PyLong_FromSize_t(fz_pixmap_size(gctx, (fz_pixmap *) $self));\n        }\n\n        //-----------------------------------------------------------------\n        // samples\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(samples_mv, \"\"\"Pixmap samples memoryview.\"\"\")\n        PyObject *samples_mv()\n        {\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            Py_ssize_t s = (Py_ssize_t) pm->w;\n            s *= pm->h;\n            s *= pm->n;\n            return PyMemoryView_FromMemory((char *) pm->samples, s, PyBUF_READ);\n        }\n\n\n        %pythoncode %{@property%}\n        ENSURE_OWNERSHIP(samples_ptr, \"\"\"Pixmap samples pointer.\"\"\")\n        PyObject *samples_ptr()\n        {\n            fz_pixmap *pm = (fz_pixmap *) $self;\n            return PyLong_FromVoidPtr((void *) pm->samples);\n        }\n\n        %pythoncode %{\n        @property\n        def samples(self)->bytes:\n            return bytes(self.samples_mv)\n\n        width  = w\n        height = h\n\n        def __len__(self):\n            return self.size\n\n        def __repr__(self):\n            EnsureOwnership(self)\n            if not type(self) is Pixmap: return\n            if self.colorspace:\n                return \"Pixmap(%s, %s, %s)\" % (self.colorspace.name, self.irect, self.alpha)\n            else:\n                return \"Pixmap(%s, %s, %s)\" % ('None', self.irect, self.alpha)\n\n        def __enter__(self):\n            return self\n\n        def __exit__(self, *args):\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n\n        def __del__(self):\n            if not type(self) is Pixmap:\n                return\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n\n        %}\n    }\n};\n\n/* fz_colorspace */\nstruct Colorspace\n{\n    %extend {\n        ~Colorspace()\n        {\n            DEBUGMSG1(\"Colorspace\");\n            fz_colorspace *this_cs = (fz_colorspace *) $self;\n            fz_drop_colorspace(gctx, this_cs);\n            DEBUGMSG2;\n        }\n\n        %pythonprepend Colorspace\n        %{\"\"\"Supported are GRAY, RGB and CMYK.\"\"\"%}\n        Colorspace(int type)\n        {\n            fz_colorspace *cs = NULL;\n            switch(type) {\n                case CS_GRAY:\n                    cs = fz_device_gray(gctx);\n                    break;\n                case CS_CMYK:\n                    cs = fz_device_cmyk(gctx);\n                    break;\n                case CS_RGB:\n                default:\n                    cs = fz_device_rgb(gctx);\n                    break;\n            }\n            fz_keep_colorspace(gctx, cs);\n            return (struct Colorspace *) cs;\n        }\n        //-----------------------------------------------------------------\n        // number of bytes to define color of one pixel\n        //-----------------------------------------------------------------\n        %pythoncode %{@property%}\n        %pythonprepend n %{\"\"\"Size of one pixel.\"\"\"%}\n        PyObject *n()\n        {\n            return Py_BuildValue(\"i\", fz_colorspace_n(gctx, (fz_colorspace *) $self));\n        }\n\n        //-----------------------------------------------------------------\n        // name of colorspace\n        //-----------------------------------------------------------------\n        PyObject *_name()\n        {\n            return JM_UnicodeFromStr(fz_colorspace_name(gctx, (fz_colorspace *) $self));\n        }\n\n        %pythoncode %{\n        @property\n        def name(self):\n            \"\"\"Name of the Colorspace.\"\"\"\n\n            if self.n == 1:\n                return csGRAY._name()\n            elif self.n == 3:\n                return csRGB._name()\n            elif self.n == 4:\n                return csCMYK._name()\n            return self._name()\n\n        def __repr__(self):\n            x = (\"\", \"GRAY\", \"\", \"RGB\", \"CMYK\")[self.n]\n            return \"Colorspace(CS_%s) - %s\" % (x, self.name)\n        %}\n    }\n};\n\n\n/* fz_device wrapper */\n%rename(Device) DeviceWrapper;\nstruct DeviceWrapper\n{\n    %extend {\n        FITZEXCEPTION(DeviceWrapper, !result)\n        DeviceWrapper(struct Pixmap *pm, PyObject *clip) {\n            struct DeviceWrapper *dw = NULL;\n            fz_try(gctx) {\n                dw = (struct DeviceWrapper *)calloc(1, sizeof(struct DeviceWrapper));\n                fz_irect bbox = JM_irect_from_py(clip);\n                if (fz_is_infinite_irect(bbox))\n                    dw->device = fz_new_draw_device(gctx, fz_identity, (fz_pixmap *) pm);\n                else\n                    dw->device = fz_new_draw_device_with_bbox(gctx, fz_identity, (fz_pixmap *) pm, &bbox);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return dw;\n        }\n        DeviceWrapper(struct DisplayList *dl) {\n            struct DeviceWrapper *dw = NULL;\n            fz_try(gctx) {\n                dw = (struct DeviceWrapper *)calloc(1, sizeof(struct DeviceWrapper));\n                dw->device = fz_new_list_device(gctx, (fz_display_list *) dl);\n                dw->list = (fz_display_list *) dl;\n                fz_keep_display_list(gctx, (fz_display_list *) dl);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return dw;\n        }\n        DeviceWrapper(struct TextPage *tp, int flags = 0) {\n            struct DeviceWrapper *dw = NULL;\n            fz_try(gctx) {\n                dw = (struct DeviceWrapper *)calloc(1, sizeof(struct DeviceWrapper));\n                fz_stext_options opts = { 0 };\n                opts.flags = flags;\n                dw->device = fz_new_stext_device(gctx, (fz_stext_page *) tp, &opts);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return dw;\n        }\n        ~DeviceWrapper() {\n            fz_display_list *list = $self->list;\n            DEBUGMSG1(\"Device\");\n            fz_close_device(gctx, $self->device);\n            fz_drop_device(gctx, $self->device);\n            DEBUGMSG2;\n            if(list)\n            {\n                DEBUGMSG1(\"DisplayList after Device\");\n                fz_drop_display_list(gctx, list);\n                DEBUGMSG2;\n            }\n        }\n    }\n};\n\n//------------------------------------------------------------------------\n// fz_outline\n//------------------------------------------------------------------------\n%nodefaultctor;\nstruct Outline {\n    %immutable;\n    %extend {\n        ~Outline()\n        {\n            DEBUGMSG1(\"Outline\");\n            fz_outline *this_ol = (fz_outline *) $self;\n            fz_drop_outline(gctx, this_ol);\n            DEBUGMSG2;\n        }\n\n        %pythoncode %{@property%}\n        PyObject *uri()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            return JM_UnicodeFromStr(ol->uri);\n        }\n\n        /* `%newobject foo;` is equivalent to wrapping C fn in python like:\n            ret = _foo()\n            ret.thisown=true\n            return ret.\n        */\n        %newobject next;\n        %pythoncode %{@property%}\n        struct Outline *next()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            fz_outline *next_ol = ol->next;\n            if (!next_ol) return NULL;\n            next_ol = fz_keep_outline(gctx, next_ol);\n            return (struct Outline *) next_ol;\n        }\n\n        %newobject down;\n        %pythoncode %{@property%}\n        struct Outline *down()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            fz_outline *down_ol = ol->down;\n            if (!down_ol) return NULL;\n            down_ol = fz_keep_outline(gctx, down_ol);\n            return (struct Outline *) down_ol;\n        }\n\n        %pythoncode %{@property%}\n        PyObject *is_external()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            if (!ol->uri) Py_RETURN_FALSE;\n            return JM_BOOL(fz_is_external_link(gctx, ol->uri));\n        }\n\n        %pythoncode %{@property%}\n        int page()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            return ol->page.page;\n        }\n\n        %pythoncode %{@property%}\n        float x()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            return ol->x;\n        }\n\n        %pythoncode %{@property%}\n        float y()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            return ol->y;\n        }\n\n        %pythoncode %{@property%}\n        PyObject *title()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            return JM_UnicodeFromStr(ol->title);\n        }\n\n        %pythoncode %{@property%}\n        PyObject *is_open()\n        {\n            fz_outline *ol = (fz_outline *) $self;\n            return JM_BOOL(ol->is_open);\n        }\n\n        %pythoncode %{\n        @property\n        def dest(self):\n            '''outline destination details'''\n            return linkDest(self, None)\n\n        def __del__(self):\n            if not isinstance(self, Outline):\n                return\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n        %}\n    }\n};\n%clearnodefaultctor;\n\n\n//------------------------------------------------------------------------\n// Annotation\n//------------------------------------------------------------------------\n%nodefaultctor;\nstruct Annot\n{\n    %extend\n    {\n        ~Annot()\n        {\n            DEBUGMSG1(\"Annot\");\n            pdf_annot *this_annot = (pdf_annot *) $self;\n            pdf_drop_annot(gctx, this_annot);\n            DEBUGMSG2;\n        }\n        //----------------------------------------------------------------\n        // annotation rectangle\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(rect, \"\"\"annotation rectangle\"\"\")\n        %pythonappend rect %{\n        val = Rect(val)\n        val *= self.parent.derotation_matrix\n        %}\n        PyObject *\n        rect()\n        {\n            fz_rect r = pdf_bound_annot(gctx, (pdf_annot *) $self);\n            return JM_py_from_rect(r);\n        }\n\n        %pythoncode %{@property%}\n        PARENTCHECK(rect_delta, \"\"\"annotation delta values to rectangle\"\"\")\n        PyObject *\n        rect_delta()\n        {\n            PyObject *rc=NULL;\n            float d;\n            fz_try(gctx) {\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, (pdf_annot *) $self);\n                pdf_obj *arr = pdf_dict_get(gctx, annot_obj, PDF_NAME(RD));\n                int i, n = pdf_array_len(gctx, arr);\n                if (n != 4) {\n                    rc = Py_BuildValue(\"s\", NULL);\n                } else {\n                    rc = PyTuple_New(4);\n                    for (i = 0; i < n; i++) {\n                        d = pdf_to_real(gctx, pdf_array_get(gctx, arr, i));\n                        if (i == 2 || i == 3) d *= -1;\n                        PyTuple_SET_ITEM(rc, i, Py_BuildValue(\"f\", d));\n                    }\n                }\n            }\n            fz_catch(gctx) {\n                Py_RETURN_NONE;\n            }\n            return rc;\n        }\n\n        //----------------------------------------------------------------\n        // annotation xref number\n        //----------------------------------------------------------------\n        PARENTCHECK(xref, \"\"\"annotation xref\"\"\")\n        %pythoncode %{@property%}\n        PyObject *xref()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            return Py_BuildValue(\"i\", pdf_to_num(gctx, annot_obj));\n        }\n\n        //----------------------------------------------------------------\n        // annotation get IRT xref number\n        //----------------------------------------------------------------\n        PARENTCHECK(irt_xref, \"\"\"annotation IRT xref\"\"\")\n        %pythoncode %{@property%}\n        PyObject *irt_xref()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_obj *irt = pdf_dict_get(gctx, annot_obj, PDF_NAME(IRT));\n            if (!irt) return PyLong_FromLong(0);\n            return PyLong_FromLong((long) pdf_to_num(gctx, irt));\n        }\n\n        //----------------------------------------------------------------\n        // annotation set IRT xref number\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_irt_xref, !result)\n        PARENTCHECK(set_irt_xref, \"\"\"Set annotation IRT xref\"\"\")\n        PyObject *set_irt_xref(int xref)\n        {\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_page *page = pdf_annot_page(gctx, annot);\n                if (!INRANGE(xref, 1, pdf_xref_len(gctx, page->doc) - 1)) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                pdf_obj *irt = pdf_new_indirect(gctx, page->doc, xref, 0);\n                pdf_obj *subt = pdf_dict_get(gctx, irt, PDF_NAME(Subtype));\n                int irt_subt = pdf_annot_type_from_string(gctx, pdf_to_name(gctx, subt));\n                if (irt_subt < 0) {\n                    pdf_drop_obj(gctx, irt);\n                    RAISEPY(gctx, MSG_IS_NO_ANNOT, PyExc_ValueError);\n                }\n                pdf_dict_put_drop(gctx, annot_obj, PDF_NAME(IRT), irt);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // annotation get AP/N Matrix\n        //----------------------------------------------------------------\n        PARENTCHECK(apn_matrix, \"\"\"annotation appearance matrix\"\"\")\n        %pythonappend apn_matrix %{val = Matrix(val)%}\n        %pythoncode %{@property%}\n        PyObject *\n        apn_matrix()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_obj *ap = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                            PDF_NAME(N), NULL);\n            if (!ap)\n                return JM_py_from_matrix(fz_identity);\n            fz_matrix mat = pdf_dict_get_matrix(gctx, ap, PDF_NAME(Matrix));\n            return JM_py_from_matrix(mat);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation get AP/N BBox\n        //----------------------------------------------------------------\n        PARENTCHECK(apn_bbox, \"\"\"annotation appearance bbox\"\"\")\n        %pythonappend apn_bbox %{\n        val = Rect(val) * self.parent.transformation_matrix\n        val *= self.parent.derotation_matrix%}\n        %pythoncode %{@property%}\n        PyObject *\n        apn_bbox()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_obj *ap = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                            PDF_NAME(N), NULL);\n            if (!ap)\n                return JM_py_from_rect(fz_infinite_rect);\n            fz_rect rect = pdf_dict_get_rect(gctx, ap, PDF_NAME(BBox));\n            return JM_py_from_rect(rect);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set AP/N Matrix\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_apn_matrix, !result)\n        PARENTCHECK(set_apn_matrix, \"\"\"Set annotation appearance matrix.\"\"\")\n        PyObject *\n        set_apn_matrix(PyObject *matrix)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            fz_try(gctx) {\n                pdf_obj *ap = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                                                PDF_NAME(N), NULL);\n                if (!ap) {\n                    RAISEPY(gctx, MSG_BAD_APN, PyExc_RuntimeError);\n                }\n                fz_matrix mat = JM_matrix_from_py(matrix);\n                pdf_dict_put_matrix(gctx, ap, PDF_NAME(Matrix), mat);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set AP/N BBox\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_apn_bbox, !result)\n        %pythonprepend set_apn_bbox %{\n        \"\"\"Set annotation appearance bbox.\"\"\"\n\n        CheckParent(self)\n        page = self.parent\n        rot = page.rotation_matrix\n        mat = page.transformation_matrix\n        bbox *= rot * ~mat\n        %}\n        PyObject *\n        set_apn_bbox(PyObject *bbox)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            fz_try(gctx) {\n                pdf_obj *ap = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                                                PDF_NAME(N), NULL);\n                if (!ap) {\n                    RAISEPY(gctx, MSG_BAD_APN, PyExc_RuntimeError);\n                }\n                fz_rect rect = JM_rect_from_py(bbox);\n                pdf_dict_put_rect(gctx, ap, PDF_NAME(BBox), rect);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation show blend mode (/BM)\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(blendmode, \"\"\"annotation BlendMode\"\"\")\n        PyObject *blendmode()\n        {\n            PyObject *blend_mode = NULL;\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_obj *obj, *obj1, *obj2;\n                obj = pdf_dict_get(gctx, annot_obj, PDF_NAME(BM));\n                if (obj) {\n                    blend_mode = JM_UnicodeFromStr(pdf_to_name(gctx, obj));\n                    goto finished;\n                }\n                // loop through the /AP/N/Resources/ExtGState objects\n                obj = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                    PDF_NAME(N),\n                    PDF_NAME(Resources),\n                    PDF_NAME(ExtGState),\n                    NULL);\n\n                if (pdf_is_dict(gctx, obj)) {\n                    int i, j, m, n = pdf_dict_len(gctx, obj);\n                    for (i = 0; i < n; i++) {\n                        obj1 = pdf_dict_get_val(gctx, obj, i);\n                        if (pdf_is_dict(gctx, obj1)) {\n                            m = pdf_dict_len(gctx, obj1);\n                            for (j = 0; j < m; j++) {\n                                obj2 = pdf_dict_get_key(gctx, obj1, j);\n                                if (pdf_objcmp(gctx, obj2, PDF_NAME(BM)) == 0) {\n                                    blend_mode = JM_UnicodeFromStr(pdf_to_name(gctx, pdf_dict_get_val(gctx, obj1, j)));\n                                    goto finished;\n                                }\n                            }\n                        }\n                    }\n                }\n                finished:;\n            }\n            fz_catch(gctx) {\n                Py_RETURN_NONE;\n            }\n            if (blend_mode) return blend_mode;\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set blend mode (/BM)\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_blendmode, !result)\n        PARENTCHECK(set_blendmode, \"\"\"Set annotation BlendMode.\"\"\")\n        PyObject *\n        set_blendmode(char *blend_mode)\n        {\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_dict_put_name(gctx, annot_obj, PDF_NAME(BM), blend_mode);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation get optional content\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_oc, !result)\n        PARENTCHECK(get_oc, \"\"\"Get annotation optional content reference.\"\"\")\n        PyObject *get_oc()\n        {\n            int oc = 0;\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_obj *obj = pdf_dict_get(gctx, annot_obj, PDF_NAME(OC));\n                if (obj) {\n                    oc = pdf_to_num(gctx, obj);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", oc);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set open\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_open, !result)\n        PARENTCHECK(set_open, \"\"\"Set 'open' status of annotation or its Popup.\"\"\")\n        PyObject *set_open(int is_open)\n        {\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_set_annot_is_open(gctx, annot, is_open);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation inquiry: is open\n        //----------------------------------------------------------------\n        FITZEXCEPTION(is_open, !result)\n        PARENTCHECK(is_open, \"\"\"Get 'open' status of annotation or its Popup.\"\"\")\n        %pythoncode %{@property%}\n        PyObject *\n        is_open()\n        {\n            int is_open;\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                is_open = pdf_annot_is_open(gctx, annot);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_BOOL(is_open);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation inquiry: has Popup\n        //----------------------------------------------------------------\n        FITZEXCEPTION(has_popup, !result)\n        PARENTCHECK(has_popup, \"\"\"Check if annotation has a Popup.\"\"\")\n        %pythoncode %{@property%}\n        PyObject *\n        has_popup()\n        {\n            int has_popup = 0;\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_obj *obj = pdf_dict_get(gctx, annot_obj, PDF_NAME(Popup));\n                if (obj) has_popup = 1;\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_BOOL(has_popup);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set Popup\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_popup, !result)\n        PARENTCHECK(set_popup, \"\"\"Create annotation 'Popup' or update rectangle.\"\"\")\n        PyObject *\n        set_popup(PyObject *rect)\n        {\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_page *pdfpage = pdf_annot_page(gctx, annot);\n                fz_matrix rot = JM_rotate_page_matrix(gctx, pdfpage);\n                fz_rect r = fz_transform_rect(JM_rect_from_py(rect), rot);\n                pdf_set_annot_popup(gctx, annot, r);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // annotation Popup rectangle\n        //----------------------------------------------------------------\n        FITZEXCEPTION(popup_rect, !result)\n        PARENTCHECK(popup_rect, \"\"\"annotation 'Popup' rectangle\"\"\")\n        %pythoncode %{@property%}\n        %pythonappend popup_rect %{\n        val = Rect(val) * self.parent.transformation_matrix\n        val *= self.parent.derotation_matrix%}\n        PyObject *\n        popup_rect()\n        {\n            fz_rect rect = fz_infinite_rect;\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_obj *obj = pdf_dict_get(gctx, annot_obj, PDF_NAME(Popup));\n                if (obj) {\n                    rect = pdf_dict_get_rect(gctx, obj, PDF_NAME(Rect));\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_py_from_rect(rect);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation Popup xref\n        //----------------------------------------------------------------\n        FITZEXCEPTION(popup_xref, !result)\n        PARENTCHECK(popup_xref, \"\"\"annotation 'Popup' xref\"\"\")\n        %pythoncode %{@property%}\n        PyObject *\n        popup_xref()\n        {\n            int xref = 0;\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_obj *obj = pdf_dict_get(gctx, annot_obj, PDF_NAME(Popup));\n                if (obj) {\n                    xref = pdf_to_num(gctx, obj);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xref);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set optional content\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_oc, !result)\n        PARENTCHECK(set_oc, \"\"\"Set / remove annotation OC xref.\"\"\")\n        PyObject *\n        set_oc(int oc=0)\n        {\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                if (!oc) {\n                    pdf_dict_del(gctx, annot_obj, PDF_NAME(OC));\n                } else {\n                    JM_add_oc_object(gctx, pdf_get_bound_document(gctx, annot_obj), annot_obj, oc);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        %pythoncode%{@property%}\n        %pythonprepend language %{\"\"\"annotation language\"\"\"%}\n        PyObject *language()\n        {\n            pdf_annot *this_annot = (pdf_annot *) $self;\n            fz_text_language lang = pdf_annot_language(gctx, this_annot);\n            char buf[8];\n            if (lang == FZ_LANG_UNSET) Py_RETURN_NONE;\n            return Py_BuildValue(\"s\", fz_string_from_text_language(buf, lang));\n        }\n\n        //----------------------------------------------------------------\n        // annotation set language (/Lang)\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_language, !result)\n        PARENTCHECK(set_language, \"\"\"Set annotation language.\"\"\")\n        PyObject *set_language(char *language=NULL)\n        {\n            pdf_annot *this_annot = (pdf_annot *) $self;\n            fz_try(gctx) {\n                fz_text_language lang;\n                if (!language)\n                    lang = FZ_LANG_UNSET;\n                else\n                    lang = fz_text_language_from_string(language);\n                pdf_set_annot_language(gctx, this_annot, lang);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation get decompressed appearance stream source\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_getAP, !result)\n        PyObject *\n        _getAP()\n        {\n            PyObject *r = NULL;\n            fz_buffer *res = NULL;\n            fz_var(res);\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_obj *ap = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                                              PDF_NAME(N), NULL);\n\n                if (pdf_is_stream(gctx, ap))  res = pdf_load_stream(gctx, ap);\n                if (res) {\n                    r = JM_BinFromBuffer(gctx, res);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                Py_RETURN_NONE;\n            }\n            if (!r) Py_RETURN_NONE;\n            return r;\n        }\n\n        //----------------------------------------------------------------\n        // annotation update /AP stream\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_setAP, !result)\n        PyObject *\n        _setAP(PyObject *buffer, int rect=0)\n        {\n            fz_buffer *res = NULL;\n            fz_var(res);\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_page *page = pdf_annot_page(gctx, annot);\n                pdf_obj *apobj = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                                              PDF_NAME(N), NULL);\n                if (!apobj) {\n                    RAISEPY(gctx, MSG_BAD_APN, PyExc_RuntimeError);\n                }\n                if (!pdf_is_stream(gctx, apobj)) {\n                    RAISEPY(gctx, MSG_BAD_APN, PyExc_RuntimeError);\n                }\n                res = JM_BufferFromBytes(gctx, buffer);\n                if (!res) {\n                    RAISEPY(gctx, MSG_BAD_BUFFER, PyExc_ValueError);\n                }\n                JM_update_stream(gctx, page->doc, apobj, res, 1);\n                if (rect) {\n                    fz_rect bbox = pdf_dict_get_rect(gctx, annot_obj, PDF_NAME(Rect));\n                    pdf_dict_put_rect(gctx, apobj, PDF_NAME(BBox), bbox);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // redaction annotation get values\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_get_redact_values, !result)\n        %pythonappend _get_redact_values %{\n        if not val:\n            return val\n        val[\"rect\"] = self.rect\n        text_color, fontname, fontsize = TOOLS._parse_da(self)\n        val[\"text_color\"] = text_color\n        val[\"fontname\"] = fontname\n        val[\"fontsize\"] = fontsize\n        fill = self.colors[\"fill\"]\n        val[\"fill\"] = fill\n\n        %}\n        PyObject *\n        _get_redact_values()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            if (pdf_annot_type(gctx, annot) != PDF_ANNOT_REDACT)\n                Py_RETURN_NONE;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            PyObject *values = PyDict_New();\n            pdf_obj *obj = NULL;\n            const char *text = NULL;\n            fz_try(gctx) {\n                obj = pdf_dict_gets(gctx, annot_obj, \"RO\");\n                if (obj) {\n                    JM_Warning(\"Ignoring redaction key '/RO'.\");\n                    int xref = pdf_to_num(gctx, obj);\n                    DICT_SETITEM_DROP(values, dictkey_xref, Py_BuildValue(\"i\", xref));\n                }\n                obj = pdf_dict_gets(gctx, annot_obj, \"OverlayText\");\n                if (obj) {\n                    text = pdf_to_text_string(gctx, obj);\n                    DICT_SETITEM_DROP(values, dictkey_text, JM_UnicodeFromStr(text));\n                } else {\n                    DICT_SETITEM_DROP(values, dictkey_text, Py_BuildValue(\"s\", \"\"));\n                }\n                obj = pdf_dict_get(gctx, annot_obj, PDF_NAME(Q));\n                int align = 0;\n                if (obj) {\n                    align = pdf_to_int(gctx, obj);\n                }\n                DICT_SETITEM_DROP(values, dictkey_align, Py_BuildValue(\"i\", align));\n            }\n            fz_catch(gctx) {\n                Py_DECREF(values);\n                return NULL;\n            }\n            return values;\n        }\n\n        //----------------------------------------------------------------\n        // annotation get TextPage\n        //----------------------------------------------------------------\n        %pythonappend get_textpage %{\n            if val:\n                val.thisown = True\n        %}\n        FITZEXCEPTION(get_textpage, !result)\n        PARENTCHECK(get_textpage, \"\"\"Make annotation TextPage.\"\"\")\n        struct TextPage *\n        get_textpage(PyObject *clip=NULL, int flags = 0)\n        {\n            fz_stext_page *textpage=NULL;\n            fz_stext_options options = { 0 };\n            options.flags = flags;\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                textpage = pdf_new_stext_page_from_annot(gctx, annot, &options);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct TextPage *) textpage;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set name\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_name, !result)\n        PARENTCHECK(set_name, \"\"\"Set /Name (icon) of annotation.\"\"\")\n        PyObject *\n        set_name(char *name)\n        {\n            fz_try(gctx) {\n                pdf_annot *annot = (pdf_annot *) $self;\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n                pdf_dict_put_name(gctx, annot_obj, PDF_NAME(Name), name);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set rectangle\n        //----------------------------------------------------------------\n        PARENTCHECK(set_rect, \"\"\"Set annotation rectangle.\"\"\")\n        FITZEXCEPTION(set_rect, !result)\n        PyObject *\n        set_rect(PyObject *rect)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            int type = pdf_annot_type(gctx, annot);\n            int err_source = 0;  // what raised the error\n            fz_var(err_source);\n            fz_try(gctx) {\n                pdf_page *pdfpage = pdf_annot_page(gctx, annot);\n                fz_matrix rot = JM_rotate_page_matrix(gctx, pdfpage);\n                fz_rect r = fz_transform_rect(JM_rect_from_py(rect), rot);\n                if (fz_is_empty_rect(r) || fz_is_infinite_rect(r)) {\n                    RAISEPY(gctx, MSG_BAD_RECT, PyExc_ValueError);\n                }\n                err_source = 1;  // indicate that error was from MuPDF\n                pdf_set_annot_rect(gctx, annot, r);\n            }\n            fz_catch(gctx) {\n                if (err_source == 0) {\n                    return NULL;\n                }\n                PySys_WriteStderr(\"cannot set rect: '%s'\\n\", fz_caught_message(gctx));\n                Py_RETURN_FALSE;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set rotation\n        //----------------------------------------------------------------\n        PARENTCHECK(set_rotation, \"\"\"Set annotation rotation.\"\"\")\n        PyObject *\n        set_rotation(int rotate=0)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            int type = pdf_annot_type(gctx, annot);\n            switch (type)\n            {\n                case PDF_ANNOT_CARET: break;\n                case PDF_ANNOT_CIRCLE: break;\n                case PDF_ANNOT_FREE_TEXT: break;\n                case PDF_ANNOT_FILE_ATTACHMENT: break;\n                case PDF_ANNOT_INK: break;\n                case PDF_ANNOT_LINE: break;\n                case PDF_ANNOT_POLY_LINE: break;\n                case PDF_ANNOT_POLYGON: break;\n                case PDF_ANNOT_SQUARE: break;\n                case PDF_ANNOT_STAMP: break;\n                case PDF_ANNOT_TEXT: break;\n                default: Py_RETURN_NONE;\n            }\n            int rot = rotate;\n            while (rot < 0) rot += 360;\n            while (rot >= 360) rot -= 360;\n            if (type == PDF_ANNOT_FREE_TEXT && rot % 90 != 0)\n                rot = 0;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_dict_put_int(gctx, annot_obj, PDF_NAME(Rotate), rot);\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation get rotation\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(rotation, \"\"\"annotation rotation\"\"\")\n        int rotation()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_obj *rotation = pdf_dict_get(gctx, annot_obj, PDF_NAME(Rotate));\n            if (!rotation) return -1;\n            return pdf_to_int(gctx, rotation);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation vertices (for \"Line\", \"Polgon\", \"Ink\", etc.\n        //----------------------------------------------------------------\n        PARENTCHECK(vertices, \"\"\"annotation vertex points\"\"\")\n        %pythoncode %{@property%}\n        PyObject *vertices()\n        {\n            PyObject *res = NULL, *res1 = NULL;\n            pdf_obj *o, *o1;\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_page *page = pdf_annot_page(gctx, annot);\n            int i, j;\n            fz_point point;  // point object to work with\n            fz_matrix page_ctm;  // page transformation matrix\n            pdf_page_transform(gctx, page, NULL, &page_ctm);\n            fz_matrix derot = JM_derotate_page_matrix(gctx, page);\n            page_ctm = fz_concat(page_ctm, derot);\n\n            //----------------------------------------------------------------\n            // The following objects occur in different annotation types.\n            // So we are sure that (!o) occurs at most once.\n            // Every pair of floats is one point, that needs to be separately\n            // transformed with the page transformation matrix.\n            //----------------------------------------------------------------\n            o = pdf_dict_get(gctx, annot_obj, PDF_NAME(Vertices));\n            if (o) goto weiter;\n            o = pdf_dict_get(gctx, annot_obj, PDF_NAME(L));\n            if (o) goto weiter;\n            o = pdf_dict_get(gctx, annot_obj, PDF_NAME(QuadPoints));\n            if (o) goto weiter;\n            o = pdf_dict_gets(gctx, annot_obj, \"CL\");\n            if (o) goto weiter;\n            o = pdf_dict_get(gctx, annot_obj, PDF_NAME(InkList));\n            if (o) goto inklist;\n            Py_RETURN_NONE;\n\n            // handle lists with 1-level depth --------------------------------\n            weiter:;\n            res = PyList_New(0);  // create Python list\n            for (i = 0; i < pdf_array_len(gctx, o); i += 2)\n            {\n                point.x = pdf_to_real(gctx, pdf_array_get(gctx, o, i));\n                point.y = pdf_to_real(gctx, pdf_array_get(gctx, o, i+1));\n                point = fz_transform_point(point, page_ctm);\n                LIST_APPEND_DROP(res, Py_BuildValue(\"ff\", point.x, point.y));\n            }\n            return res;\n\n            // InkList has 2-level lists --------------------------------------\n            inklist:;\n            res = PyList_New(0);\n            for (i = 0; i < pdf_array_len(gctx, o); i++)\n            {\n                res1 = PyList_New(0);\n                o1 = pdf_array_get(gctx, o, i);\n                for (j = 0; j < pdf_array_len(gctx, o1); j += 2)\n                {\n                    point.x = pdf_to_real(gctx, pdf_array_get(gctx, o1, j));\n                    point.y = pdf_to_real(gctx, pdf_array_get(gctx, o1, j+1));\n                    point = fz_transform_point(point, page_ctm);\n                    LIST_APPEND_DROP(res1, Py_BuildValue(\"ff\", point.x, point.y));\n                }\n                LIST_APPEND_DROP(res, res1);\n            }\n            return res;\n        }\n\n        //----------------------------------------------------------------\n        // annotation colors\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(colors, \"\"\"Color definitions.\"\"\")\n        PyObject *colors()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            return JM_annot_colors(gctx, annot_obj);\n        }\n\n        //----------------------------------------------------------------\n        // annotation update appearance\n        //----------------------------------------------------------------\n        PyObject *_update_appearance(float opacity=-1,\n                    char *blend_mode=NULL,\n                    PyObject *fill_color=NULL,\n                    int rotate = -1)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_page *page = pdf_annot_page(gctx, annot);\n            pdf_document *pdf = page->doc;\n            int type = pdf_annot_type(gctx, annot);\n            float fcol[4] = {1,1,1,1};  // std fill color: white\n            int i, nfcol = 0;  // number of color components\n            JM_color_FromSequence(fill_color, &nfcol, fcol);\n            fz_try(gctx) {\n                // remove fill color from unsupported annots\n                // or if so requested\n                if ((type != PDF_ANNOT_SQUARE\n                    && type != PDF_ANNOT_CIRCLE\n                    && type != PDF_ANNOT_LINE\n                    && type != PDF_ANNOT_POLY_LINE\n                    && type != PDF_ANNOT_POLYGON\n                    )\n                    || nfcol == 0\n                    ) {\n                    pdf_dict_del(gctx, annot_obj, PDF_NAME(IC));\n                } else if (nfcol > 0) {\n                    pdf_set_annot_interior_color(gctx, annot, nfcol, fcol);\n                }\n\n                int insert_rot = (rotate >= 0) ? 1 : 0;\n                switch (type) {\n                    case PDF_ANNOT_CARET:\n                    case PDF_ANNOT_CIRCLE:\n                    case PDF_ANNOT_FREE_TEXT:\n                    case PDF_ANNOT_FILE_ATTACHMENT:\n                    case PDF_ANNOT_INK:\n                    case PDF_ANNOT_LINE:\n                    case PDF_ANNOT_POLY_LINE:\n                    case PDF_ANNOT_POLYGON:\n                    case PDF_ANNOT_SQUARE:\n                    case PDF_ANNOT_STAMP:\n                    case PDF_ANNOT_TEXT: break;\n                    default: insert_rot = 0;\n                }\n\n                if (insert_rot) {\n                    pdf_dict_put_int(gctx, annot_obj, PDF_NAME(Rotate), rotate);\n                }\n\n                pdf_dirty_annot(gctx, annot);\n                pdf_update_annot(gctx, annot);  // let MuPDF update\n                pdf->resynth_required = 0;\n                // insert fill color\n                if (type == PDF_ANNOT_FREE_TEXT) {\n                    if (nfcol > 0) {\n                        pdf_set_annot_color(gctx, annot, nfcol, fcol);\n                    }\n                } else if (nfcol > 0) {\n                    pdf_obj *col = pdf_new_array(gctx, page->doc, nfcol);\n                    for (i = 0; i < nfcol; i++) {\n                        pdf_array_push_real(gctx, col, fcol[i]);\n                    }\n                    pdf_dict_put_drop(gctx,annot_obj, PDF_NAME(IC), col);\n                }\n            }\n            fz_catch(gctx) {\n                PySys_WriteStderr(\"cannot update annot: '%s'\\n\", fz_caught_message(gctx));\n                Py_RETURN_FALSE;\n            }\n\n            if ((opacity < 0 || opacity >= 1) && !blend_mode)  // no opacity, no blend_mode\n                goto normal_exit;\n\n            fz_try(gctx) {  // create or update /ExtGState\n                pdf_obj *ap = pdf_dict_getl(gctx, annot_obj, PDF_NAME(AP),\n                                        PDF_NAME(N), NULL);\n                if (!ap)  { // should never happen\n                    RAISEPY(gctx, MSG_BAD_APN, PyExc_RuntimeError);\n                }\n\n                pdf_obj *resources = pdf_dict_get(gctx, ap, PDF_NAME(Resources));\n                if (!resources) {  // no Resources yet: make one\n                    resources = pdf_dict_put_dict(gctx, ap, PDF_NAME(Resources), 2);\n                }\n                pdf_obj *alp0 = pdf_new_dict(gctx, page->doc, 3);\n                if (opacity >= 0 && opacity < 1) {\n                    pdf_dict_put_real(gctx, alp0, PDF_NAME(CA), (double) opacity);\n                    pdf_dict_put_real(gctx, alp0, PDF_NAME(ca), (double) opacity);\n                    pdf_dict_put_real(gctx, annot_obj, PDF_NAME(CA), (double) opacity);\n                }\n                if (blend_mode) {\n                    pdf_dict_put_name(gctx, alp0, PDF_NAME(BM), blend_mode);\n                    pdf_dict_put_name(gctx, annot_obj, PDF_NAME(BM), blend_mode);\n                }\n                pdf_obj *extg = pdf_dict_get(gctx, resources, PDF_NAME(ExtGState));\n                if (!extg) {  // no ExtGState yet: make one\n                    extg = pdf_dict_put_dict(gctx, resources, PDF_NAME(ExtGState), 2);\n                }\n                pdf_dict_put_drop(gctx, extg, PDF_NAME(H), alp0);\n            }\n\n            fz_catch(gctx) {\n                PySys_WriteStderr(\"cannot set opacity or blend mode\\n\");\n                Py_RETURN_FALSE;\n            }\n            normal_exit:;\n            Py_RETURN_TRUE;\n        }\n\n\n        %pythoncode %{\n        def update(self,\n                   blend_mode: OptStr =None,\n                   opacity: OptFloat =None,\n                   fontsize: float =0,\n                   fontname: OptStr =None,\n                   text_color: OptSeq =None,\n                   border_color: OptSeq =None,\n                   fill_color: OptSeq =None,\n                   cross_out: bool =True,\n                   rotate: int =-1,\n                   ):\n\n            \"\"\"Update annot appearance.\n\n            Notes:\n                Depending on the annot type, some parameters make no sense,\n                while others are only available in this method to achieve the\n                desired result. This is especially true for 'FreeText' annots.\n            Args:\n                blend_mode: set the blend mode, all annotations.\n                opacity: set the opacity, all annotations.\n                fontsize: set fontsize, 'FreeText' only.\n                fontname: set the font, 'FreeText' only.\n                border_color: set border color, 'FreeText' only.\n                text_color: set text color, 'FreeText' only.\n                fill_color: set fill color, all annotations.\n                cross_out: draw diagonal lines, 'Redact' only.\n                rotate: set rotation, 'FreeText' and some others.\n            \"\"\"\n            CheckParent(self)\n            def color_string(cs, code):\n                \"\"\"Return valid PDF color operator for a given color sequence.\n                \"\"\"\n                cc = ColorCode(cs, code)\n                if not cc:\n                    return b\"\"\n                return (cc + \"\\n\").encode()\n\n            annot_type = self.type[0]  # get the annot type\n            dt = self.border.get(\"dashes\", None)  # get the dashes spec\n            bwidth = self.border.get(\"width\", -1)  # get border line width\n            stroke = self.colors[\"stroke\"]  # get the stroke color\n            if fill_color != None:  # change of fill color requested\n                fill = fill_color\n            else:  # put in current annot value\n                fill = self.colors[\"fill\"]\n\n            rect = None  # self.rect  # prevent MuPDF fiddling with it\n            apnmat = self.apn_matrix  # prevent MuPDF fiddling with it\n            if rotate != -1:  # sanitize rotation value\n                while rotate < 0:\n                    rotate += 360\n                while rotate >= 360:\n                    rotate -= 360\n                if annot_type == PDF_ANNOT_FREE_TEXT and rotate % 90 != 0:\n                    rotate = 0\n\n            #------------------------------------------------------------------\n            # handle opacity and blend mode\n            #------------------------------------------------------------------\n            if blend_mode is None:\n                blend_mode = self.blendmode\n            if not hasattr(opacity, \"__float__\"):\n                opacity = self.opacity\n\n            if 0 <= opacity < 1 or blend_mode is not None:\n                opa_code = \"/H gs\\n\"  # then we must reference this 'gs'\n            else:\n                opa_code = \"\"\n\n            if annot_type == PDF_ANNOT_FREE_TEXT:\n                CheckColor(border_color)\n                CheckColor(text_color)\n                CheckColor(fill_color)\n                tcol, fname, fsize = TOOLS._parse_da(self)\n\n                # read and update default appearance as necessary\n                update_default_appearance = False\n                if fsize <= 0:\n                    fsize = 12\n                    update_default_appearance = True\n                if text_color is not None:\n                    tcol = text_color\n                    update_default_appearance = True\n                if fontname is not None:\n                    fname = fontname\n                    update_default_appearance = True\n                if fontsize > 0:\n                    fsize = fontsize\n                    update_default_appearance = True\n\n                if update_default_appearance:\n                    da_str = \"\"\n                    if len(tcol) == 3:\n                        fmt = \"{:g} {:g} {:g} rg /{f:s} {s:g} Tf\"\n                    elif len(tcol) == 1:\n                        fmt = \"{:g} g /{f:s} {s:g} Tf\"\n                    elif len(tcol) == 4:\n                        fmt = \"{:g} {:g} {:g} {:g} k /{f:s} {s:g} Tf\"\n                    da_str = fmt.format(*tcol, f=fname, s=fsize)\n                    TOOLS._update_da(self, da_str)\n\n            #------------------------------------------------------------------\n            # now invoke MuPDF to update the annot appearance\n            #------------------------------------------------------------------\n            val = self._update_appearance(\n                opacity=opacity,\n                blend_mode=blend_mode,\n                fill_color=fill,\n                rotate=rotate,\n            )\n            if val == False:\n                raise RuntimeError(\"Error updating annotation.\")\n\n            bfill = color_string(fill, \"f\")\n            bstroke = color_string(stroke, \"c\")\n\n            p_ctm = self.parent.transformation_matrix\n            imat = ~p_ctm  # inverse page transf. matrix\n\n            if dt:\n                dashes = \"[\" + \" \".join(map(str, dt)) + \"] 0 d\\n\"\n                dashes = dashes.encode(\"utf-8\")\n            else:\n                dashes = None\n\n            if self.line_ends:\n                line_end_le, line_end_ri = self.line_ends\n            else:\n                line_end_le, line_end_ri = 0, 0  # init line end codes\n\n            # read contents as created by MuPDF\n            ap = self._getAP()\n            ap_tab = ap.splitlines()  # split in single lines\n            ap_updated = False  # assume we did nothing\n\n            if annot_type == PDF_ANNOT_REDACT:\n                if cross_out:  # create crossed-out rect\n                    ap_updated = True\n                    ap_tab = ap_tab[:-1]\n                    _, LL, LR, UR, UL = ap_tab\n                    ap_tab.append(LR)\n                    ap_tab.append(LL)\n                    ap_tab.append(UR)\n                    ap_tab.append(LL)\n                    ap_tab.append(UL)\n                    ap_tab.append(b\"S\")\n\n                if bwidth > 0 or bstroke != b\"\":\n                    ap_updated = True\n                    ntab = [b\"%g w\" % bwidth] if bwidth > 0 else []\n                    for line in ap_tab:\n                        if line.endswith(b\"w\"):\n                            continue\n                        if line.endswith(b\"RG\") and bstroke != b\"\":\n                            line = bstroke[:-1]\n                        ntab.append(line)\n                    ap_tab = ntab\n\n                ap = b\"\\n\".join(ap_tab)\n\n            if annot_type == PDF_ANNOT_FREE_TEXT:\n                BT = ap.find(b\"BT\")\n                ET = ap.find(b\"ET\") + 2\n                ap = ap[BT:ET]\n                w, h = self.rect.width, self.rect.height\n                if rotate in (90, 270) or not (apnmat.b == apnmat.c == 0):\n                    w, h = h, w\n                re = b\"0 0 %g %g re\" % (w, h)\n                ap = re + b\"\\nW\\nn\\n\" + ap\n                ope = None\n                fill_string = color_string(fill, \"f\")\n                if fill_string:\n                    ope = b\"f\"\n                stroke_string = color_string(border_color, \"c\")\n                if stroke_string and bwidth > 0:\n                    ope = b\"S\"\n                    bwidth = b\"%g w\\n\" % bwidth\n                else:\n                    bwidth = stroke_string = b\"\"\n                if fill_string and stroke_string:\n                    ope = b\"B\"\n                if ope != None:\n                    ap = bwidth + fill_string + stroke_string + re + b\"\\n\" + ope + b\"\\n\" + ap\n\n                if dashes != None:  # handle dashes\n                    ap = dashes + b\"\\n\" + ap\n                    dashes = None\n\n                ap_updated = True\n\n            if annot_type in (PDF_ANNOT_POLYGON, PDF_ANNOT_POLY_LINE):\n                ap = b\"\\n\".join(ap_tab[:-1]) + b\"\\n\"\n                ap_updated = True\n                if bfill != b\"\":\n                    if annot_type == PDF_ANNOT_POLYGON:\n                        ap = ap + bfill + b\"b\"  # close, fill, and stroke\n                    elif annot_type == PDF_ANNOT_POLY_LINE:\n                        ap = ap + b\"S\"  # stroke\n                else:\n                    if annot_type == PDF_ANNOT_POLYGON:\n                        ap = ap + b\"s\"  # close and stroke\n                    elif annot_type == PDF_ANNOT_POLY_LINE:\n                        ap = ap + b\"S\"  # stroke\n\n            if dashes is not None:  # handle dashes\n                ap = dashes + ap\n                # reset dashing - only applies for LINE annots with line ends given\n                ap = ap.replace(b\"\\nS\\n\", b\"\\nS\\n[] 0 d\\n\", 1)\n                ap_updated = True\n\n            if opa_code:\n                ap = opa_code.encode(\"utf-8\") + ap\n                ap_updated = True\n\n            ap = b\"q\\n\" + ap + b\"\\nQ\\n\"\n            #----------------------------------------------------------------------\n            # the following handles line end symbols for 'Polygon' and 'Polyline'\n            #----------------------------------------------------------------------\n            if line_end_le + line_end_ri > 0 and annot_type in (PDF_ANNOT_POLYGON, PDF_ANNOT_POLY_LINE):\n\n                le_funcs = (None, TOOLS._le_square, TOOLS._le_circle,\n                            TOOLS._le_diamond, TOOLS._le_openarrow,\n                            TOOLS._le_closedarrow, TOOLS._le_butt,\n                            TOOLS._le_ropenarrow, TOOLS._le_rclosedarrow,\n                            TOOLS._le_slash)\n                le_funcs_range = range(1, len(le_funcs))\n                d = 2 * max(1, self.border[\"width\"])\n                rect = self.rect + (-d, -d, d, d)\n                ap_updated = True\n                points = self.vertices\n                if line_end_le in le_funcs_range:\n                    p1 = Point(points[0]) * imat\n                    p2 = Point(points[1]) * imat\n                    left = le_funcs[line_end_le](self, p1, p2, False, fill_color)\n                    ap += left.encode()\n                if line_end_ri in le_funcs_range:\n                    p1 = Point(points[-2]) * imat\n                    p2 = Point(points[-1]) * imat\n                    left = le_funcs[line_end_ri](self, p1, p2, True, fill_color)\n                    ap += left.encode()\n\n            if ap_updated:\n                if rect:                        # rect modified here?\n                    self.set_rect(rect)\n                    self._setAP(ap, rect=1)\n                else:\n                    self._setAP(ap, rect=0)\n\n            #-------------------------------\n            # handle annotation rotations\n            #-------------------------------\n            if annot_type not in (  # only these types are supported\n                PDF_ANNOT_CARET,\n                PDF_ANNOT_CIRCLE,\n                PDF_ANNOT_FILE_ATTACHMENT,\n                PDF_ANNOT_INK,\n                PDF_ANNOT_LINE,\n                PDF_ANNOT_POLY_LINE,\n                PDF_ANNOT_POLYGON,\n                PDF_ANNOT_SQUARE,\n                PDF_ANNOT_STAMP,\n                PDF_ANNOT_TEXT,\n                ):\n                return\n\n            rot = self.rotation  # get value from annot object\n            if rot == -1:  # nothing to change\n                return\n\n            M = (self.rect.tl + self.rect.br) / 2  # center of annot rect\n\n            if rot == 0:  # undo rotations\n                if abs(apnmat - Matrix(1, 1)) < 1e-5:\n                    return  # matrix already is a no-op\n                quad = self.rect.morph(M, ~apnmat)  # derotate rect\n                self.set_rect(quad.rect)\n                self.set_apn_matrix(Matrix(1, 1))  # appearance matrix = no-op\n                return\n\n            mat = Matrix(rot)\n            quad = self.rect.morph(M, mat)\n            self.set_rect(quad.rect)\n            self.set_apn_matrix(apnmat * mat)\n        %}\n\n        //----------------------------------------------------------------\n        // annotation set colors\n        //----------------------------------------------------------------\n        %pythoncode %{\n        def set_colors(self, colors=None, stroke=None, fill=None):\n            \"\"\"Set 'stroke' and 'fill' colors.\n\n            Use either a dict or the direct arguments.\n            \"\"\"\n            CheckParent(self)\n            doc = self.parent.parent\n            if type(colors) is not dict:\n                colors = {\"fill\": fill, \"stroke\": stroke}\n            fill = colors.get(\"fill\")\n            stroke = colors.get(\"stroke\")\n            fill_annots = (PDF_ANNOT_CIRCLE, PDF_ANNOT_SQUARE, PDF_ANNOT_LINE, PDF_ANNOT_POLY_LINE, PDF_ANNOT_POLYGON,\n                           PDF_ANNOT_REDACT,)\n            if stroke in ([], ()):\n                doc.xref_set_key(self.xref, \"C\", \"[]\")\n            elif stroke is not None:\n                if hasattr(stroke, \"__float__\"):\n                    stroke = [float(stroke)]\n                CheckColor(stroke)\n                if len(stroke) == 1:\n                    s = \"[%g]\" % stroke[0]\n                elif len(stroke) == 3:\n                    s = \"[%g %g %g]\" % tuple(stroke)\n                else:\n                    s = \"[%g %g %g %g]\" % tuple(stroke)\n                doc.xref_set_key(self.xref, \"C\", s)\n\n            if fill and self.type[0] not in fill_annots:\n                print(\"Warning: fill color ignored for annot type '%s'.\" % self.type[1])\n                return\n            if fill in ([], ()):\n                doc.xref_set_key(self.xref, \"IC\", \"[]\")\n            elif fill is not None:\n                if hasattr(fill, \"__float__\"):\n                    fill = [float(fill)]\n                CheckColor(fill)\n                if len(fill) == 1:\n                    s = \"[%g]\" % fill[0]\n                elif len(fill) == 3:\n                    s = \"[%g %g %g]\" % tuple(fill)\n                else:\n                    s = \"[%g %g %g %g]\" % tuple(fill)\n                doc.xref_set_key(self.xref, \"IC\", s)\n        %}\n\n\n        //----------------------------------------------------------------\n        // annotation line_ends\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(line_ends, \"\"\"Line end codes.\"\"\")\n        PyObject *\n        line_ends()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n\n            // return nothing for invalid annot types\n            if (!pdf_annot_has_line_ending_styles(gctx, annot))\n                Py_RETURN_NONE;\n\n            int lstart = (int) pdf_annot_line_start_style(gctx, annot);\n            int lend = (int) pdf_annot_line_end_style(gctx, annot);\n            return Py_BuildValue(\"ii\", lstart, lend);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation set line ends\n        //----------------------------------------------------------------\n        PARENTCHECK(set_line_ends, \"\"\"Set line end codes.\"\"\")\n        void set_line_ends(int start, int end)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            if (pdf_annot_has_line_ending_styles(gctx, annot))\n                pdf_set_annot_line_ending_styles(gctx, annot, start, end);\n            else\n                JM_Warning(\"bad annot type for line ends\");\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation type\n        //----------------------------------------------------------------\n        PARENTCHECK(type, \"\"\"annotation type\"\"\")\n        %pythoncode %{@property%}\n        PyObject *type()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            int type = pdf_annot_type(gctx, annot);\n            const char *c = pdf_string_from_annot_type(gctx, type);\n            pdf_obj *o = pdf_dict_gets(gctx, annot_obj, \"IT\");\n            if (!o || !pdf_is_name(gctx, o))\n                return Py_BuildValue(\"is\", type, c);         // no IT entry\n            const char *it = pdf_to_name(gctx, o);\n            return Py_BuildValue(\"iss\", type, c, it);\n        }\n\n        //----------------------------------------------------------------\n        // annotation opacity\n        //----------------------------------------------------------------\n        PARENTCHECK(opacity, \"\"\"Opacity.\"\"\")\n        %pythoncode %{@property%}\n        PyObject *opacity()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            double opy = -1;\n            pdf_obj *ca = pdf_dict_get(gctx, annot_obj, PDF_NAME(CA));\n            if (pdf_is_number(gctx, ca))\n                opy = pdf_to_real(gctx, ca);\n            return Py_BuildValue(\"f\", opy);\n        }\n\n        //----------------------------------------------------------------\n        // annotation set opacity\n        //----------------------------------------------------------------\n        PARENTCHECK(set_opacity, \"\"\"Set opacity.\"\"\")\n        void set_opacity(float opacity)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            if (!INRANGE(opacity, 0.0f, 1.0f))\n            {\n                pdf_set_annot_opacity(gctx, annot, 1);\n                return;\n            }\n            pdf_set_annot_opacity(gctx, annot, opacity);\n            if (opacity < 1.0f)\n            {\n                pdf_page *page = pdf_annot_page(gctx, annot);\n                page->transparency = 1;\n            }\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation get attached file info\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        FITZEXCEPTION(file_info, !result)\n        PARENTCHECK(file_info, \"\"\"Attached file information.\"\"\")\n        PyObject *file_info()\n        {\n            PyObject *res = PyDict_New();  // create Python dict\n            char *filename = NULL;\n            char *desc = NULL;\n            int length = -1, size = -1;\n            pdf_obj *stream = NULL, *o = NULL, *fs = NULL;\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            fz_try(gctx) {\n                int type = (int) pdf_annot_type(gctx, annot);\n                if (type != PDF_ANNOT_FILE_ATTACHMENT) {\n                    RAISEPY(gctx, MSG_BAD_ANNOT_TYPE, PyExc_TypeError);\n                }\n                stream = pdf_dict_getl(gctx, annot_obj, PDF_NAME(FS),\n                                   PDF_NAME(EF), PDF_NAME(F), NULL);\n                if (!stream) {\n                    RAISEPY(gctx, \"bad PDF: file entry not found\", JM_Exc_FileDataError);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n\n            fs = pdf_dict_get(gctx, annot_obj, PDF_NAME(FS));\n\n            o = pdf_dict_get(gctx, fs, PDF_NAME(UF));\n            if (o) {\n                filename = (char *) pdf_to_text_string(gctx, o);\n            } else {\n                o = pdf_dict_get(gctx, fs, PDF_NAME(F));\n                if (o) filename = (char *) pdf_to_text_string(gctx, o);\n            }\n\n            o = pdf_dict_get(gctx, fs, PDF_NAME(Desc));\n            if (o) desc = (char *) pdf_to_text_string(gctx, o);\n\n            o = pdf_dict_get(gctx, stream, PDF_NAME(Length));\n            if (o) length = pdf_to_int(gctx, o);\n\n            o = pdf_dict_getl(gctx, stream, PDF_NAME(Params),\n                                PDF_NAME(Size), NULL);\n            if (o) size = pdf_to_int(gctx, o);\n\n            DICT_SETITEM_DROP(res, dictkey_filename, JM_EscapeStrFromStr(filename));\n            DICT_SETITEM_DROP(res, dictkey_desc, JM_UnicodeFromStr(desc));\n            DICT_SETITEM_DROP(res, dictkey_length, Py_BuildValue(\"i\", length));\n            DICT_SETITEM_DROP(res, dictkey_size, Py_BuildValue(\"i\", size));\n            return res;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation get attached file content\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_file, !result)\n        PARENTCHECK(get_file, \"\"\"Retrieve attached file content.\"\"\")\n        PyObject *\n        get_file()\n        {\n            PyObject *res = NULL;\n            pdf_obj *stream = NULL;\n            fz_buffer *buf = NULL;\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            fz_var(buf);\n            fz_try(gctx) {\n                int type = (int) pdf_annot_type(gctx, annot);\n                if (type != PDF_ANNOT_FILE_ATTACHMENT) {\n                    RAISEPY(gctx, MSG_BAD_ANNOT_TYPE, PyExc_TypeError);\n                }\n                stream = pdf_dict_getl(gctx, annot_obj, PDF_NAME(FS),\n                                   PDF_NAME(EF), PDF_NAME(F), NULL);\n                if (!stream) {\n                    RAISEPY(gctx, \"bad PDF: file entry not found\", JM_Exc_FileDataError);\n                }\n                buf = pdf_load_stream(gctx, stream);\n                res = JM_BinFromBuffer(gctx, buf);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return res;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation get attached sound stream\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_sound, !result)\n        PARENTCHECK(get_sound, \"\"\"Retrieve sound stream.\"\"\")\n        PyObject *\n        get_sound()\n        {\n            PyObject *res = NULL;\n            PyObject *stream = NULL;\n            fz_buffer *buf = NULL;\n            pdf_obj *obj = NULL;\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            fz_var(buf);\n            fz_try(gctx) {\n                int type = (int) pdf_annot_type(gctx, annot);\n                pdf_obj *sound = pdf_dict_get(gctx, annot_obj, PDF_NAME(Sound));\n                if (type != PDF_ANNOT_SOUND || !sound) {\n                    RAISEPY(gctx, MSG_BAD_ANNOT_TYPE, PyExc_TypeError);\n                }\n                if (pdf_dict_get(gctx, sound, PDF_NAME(F))) {\n                    RAISEPY(gctx, \"unsupported sound stream\", JM_Exc_FileDataError);\n                }\n                res = PyDict_New();\n                obj = pdf_dict_get(gctx, sound, PDF_NAME(R));\n                if (obj) {\n                    DICT_SETITEMSTR_DROP(res, \"rate\",\n                            Py_BuildValue(\"f\", pdf_to_real(gctx, obj)));\n                }\n                obj = pdf_dict_get(gctx, sound, PDF_NAME(C));\n                if (obj) {\n                    DICT_SETITEMSTR_DROP(res, \"channels\",\n                            Py_BuildValue(\"i\", pdf_to_int(gctx, obj)));\n                }\n                obj = pdf_dict_get(gctx, sound, PDF_NAME(B));\n                if (obj) {\n                    DICT_SETITEMSTR_DROP(res, \"bps\",\n                            Py_BuildValue(\"i\", pdf_to_int(gctx, obj)));\n                }\n                obj = pdf_dict_get(gctx, sound, PDF_NAME(E));\n                if (obj) {\n                    DICT_SETITEMSTR_DROP(res, \"encoding\",\n                            Py_BuildValue(\"s\", pdf_to_name(gctx, obj)));\n                }\n                obj = pdf_dict_gets(gctx, sound, \"CO\");\n                if (obj) {\n                    DICT_SETITEMSTR_DROP(res, \"compression\",\n                            Py_BuildValue(\"s\", pdf_to_name(gctx, obj)));\n                }\n                buf = pdf_load_stream(gctx, sound);\n                stream = JM_BinFromBuffer(gctx, buf);\n                DICT_SETITEMSTR_DROP(res, \"stream\", stream);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buf);\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(res);\n                return NULL;\n            }\n            return res;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation update attached file\n        //----------------------------------------------------------------\n        FITZEXCEPTION(update_file, !result)\n        %pythonprepend update_file\n%{\"\"\"Update attached file.\"\"\"\nCheckParent(self)%}\n\n        PyObject *\n        update_file(PyObject *buffer=NULL, char *filename=NULL, char *ufilename=NULL, char *desc=NULL)\n        {\n            pdf_document *pdf = NULL;       // to be filled in\n            fz_buffer *res = NULL;          // for compressed content\n            pdf_obj *stream = NULL, *fs = NULL;\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            fz_try(gctx) {\n                pdf = pdf_get_bound_document(gctx, annot_obj);  // the owning PDF\n                int type = (int) pdf_annot_type(gctx, annot);\n                if (type != PDF_ANNOT_FILE_ATTACHMENT) {\n                    RAISEPY(gctx, MSG_BAD_ANNOT_TYPE, PyExc_TypeError);\n                }\n                stream = pdf_dict_getl(gctx, annot_obj, PDF_NAME(FS),\n                                   PDF_NAME(EF), PDF_NAME(F), NULL);\n                // the object for file content\n                if (!stream) {\n                    RAISEPY(gctx, \"bad PDF: no /EF object\", JM_Exc_FileDataError);\n                }\n\n                fs = pdf_dict_get(gctx, annot_obj, PDF_NAME(FS));\n\n                // file content given\n                res = JM_BufferFromBytes(gctx, buffer);\n                if (buffer && !res) {\n                    RAISEPY(gctx, MSG_BAD_BUFFER, PyExc_ValueError);\n                }\n                if (res) {\n                    JM_update_stream(gctx, pdf, stream, res, 1);\n                    // adjust /DL and /Size parameters\n                    int64_t len = (int64_t) fz_buffer_storage(gctx, res, NULL);\n                    pdf_obj *l = pdf_new_int(gctx, len);\n                    pdf_dict_put(gctx, stream, PDF_NAME(DL), l);\n                    pdf_dict_putl(gctx, stream, l, PDF_NAME(Params), PDF_NAME(Size), NULL);\n                }\n\n                if (filename) {\n                    pdf_dict_put_text_string(gctx, stream, PDF_NAME(F), filename);\n                    pdf_dict_put_text_string(gctx, fs, PDF_NAME(F), filename);\n                    pdf_dict_put_text_string(gctx, stream, PDF_NAME(UF), filename);\n                    pdf_dict_put_text_string(gctx, fs, PDF_NAME(UF), filename);\n                    pdf_dict_put_text_string(gctx, annot_obj, PDF_NAME(Contents), filename);\n                }\n\n                if (ufilename) {\n                    pdf_dict_put_text_string(gctx, stream, PDF_NAME(UF), ufilename);\n                    pdf_dict_put_text_string(gctx, fs, PDF_NAME(UF), ufilename);\n                }\n\n                if (desc) {\n                    pdf_dict_put_text_string(gctx, stream, PDF_NAME(Desc), desc);\n                    pdf_dict_put_text_string(gctx, fs, PDF_NAME(Desc), desc);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            \n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation info\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(info, \"\"\"Various information details.\"\"\")\n        PyObject *info()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            PyObject *res = PyDict_New();\n            pdf_obj *o;\n\n            DICT_SETITEM_DROP(res, dictkey_content,\n                          JM_UnicodeFromStr(pdf_annot_contents(gctx, annot)));\n\n            o = pdf_dict_get(gctx, annot_obj, PDF_NAME(Name));\n            DICT_SETITEM_DROP(res, dictkey_name, JM_UnicodeFromStr(pdf_to_name(gctx, o)));\n\n            // Title (= author)\n            o = pdf_dict_get(gctx, annot_obj, PDF_NAME(T));\n            DICT_SETITEM_DROP(res, dictkey_title, JM_UnicodeFromStr(pdf_to_text_string(gctx, o)));\n\n            // CreationDate\n            o = pdf_dict_gets(gctx, annot_obj, \"CreationDate\");\n            DICT_SETITEM_DROP(res, dictkey_creationDate,\n                          JM_UnicodeFromStr(pdf_to_text_string(gctx, o)));\n\n            // ModDate\n            o = pdf_dict_get(gctx, annot_obj, PDF_NAME(M));\n            DICT_SETITEM_DROP(res, dictkey_modDate, JM_UnicodeFromStr(pdf_to_text_string(gctx, o)));\n\n            // Subj\n            o = pdf_dict_gets(gctx, annot_obj, \"Subj\");\n            DICT_SETITEM_DROP(res, dictkey_subject,\n                          Py_BuildValue(\"s\",pdf_to_text_string(gctx, o)));\n\n            // Identification (PDF key /NM)\n            o = pdf_dict_gets(gctx, annot_obj, \"NM\");\n            DICT_SETITEM_DROP(res, dictkey_id,\n                          JM_UnicodeFromStr(pdf_to_text_string(gctx, o)));\n\n            return res;\n        }\n\n        //----------------------------------------------------------------\n        // annotation set information\n        //----------------------------------------------------------------\n        FITZEXCEPTION(set_info, !result)\n        %pythonprepend set_info %{\n        \"\"\"Set various properties.\"\"\"\n        CheckParent(self)\n        if type(info) is dict:  # build the args from the dictionary\n            content = info.get(\"content\", None)\n            title = info.get(\"title\", None)\n            creationDate = info.get(\"creationDate\", None)\n            modDate = info.get(\"modDate\", None)\n            subject = info.get(\"subject\", None)\n            info = None\n        %}\n        PyObject *\n        set_info(PyObject *info=NULL, char *content=NULL, char *title=NULL,\n                          char *creationDate=NULL, char *modDate=NULL, char *subject=NULL)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            // use this to indicate a 'markup' annot type\n            int is_markup = pdf_annot_has_author(gctx, annot);\n            fz_try(gctx) {\n                // contents\n                if (content)\n                    pdf_set_annot_contents(gctx, annot, content);\n\n                if (is_markup) {\n                    // title (= author)\n                    if (title)\n                        pdf_set_annot_author(gctx, annot, title);\n\n                    // creation date\n                    if (creationDate)\n                        pdf_dict_put_text_string(gctx, annot_obj,\n                                                 PDF_NAME(CreationDate), creationDate);\n\n                    // mod date\n                    if (modDate)\n                        pdf_dict_put_text_string(gctx, annot_obj,\n                                                 PDF_NAME(M), modDate);\n\n                    // subject\n                    if (subject)\n                        pdf_dict_puts_drop(gctx, annot_obj, \"Subj\",\n                                           pdf_new_text_string(gctx, subject));\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation border\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        %pythonprepend border %{\n        \"\"\"Border information.\"\"\"\n        CheckParent(self)\n        atype = self.type[0]\n        if atype not in (PDF_ANNOT_CIRCLE, PDF_ANNOT_FREE_TEXT, PDF_ANNOT_INK, PDF_ANNOT_LINE, PDF_ANNOT_POLY_LINE,PDF_ANNOT_POLYGON, PDF_ANNOT_SQUARE):\n            return {}\n        %}\n        PyObject *border()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            return JM_annot_border(gctx, annot_obj);\n        }\n\n        //----------------------------------------------------------------\n        // set annotation border\n        //----------------------------------------------------------------\n        %pythonprepend set_border %{\n        \"\"\"Set border properties.\n\n        Either a dict, or direct arguments width, style, dashes or clouds.\"\"\"\n\n        CheckParent(self)\n        atype, atname = self.type[:2]  # annotation type\n        if atype not in (PDF_ANNOT_CIRCLE, PDF_ANNOT_FREE_TEXT, PDF_ANNOT_INK, PDF_ANNOT_LINE, PDF_ANNOT_POLY_LINE,PDF_ANNOT_POLYGON, PDF_ANNOT_SQUARE):\n            print(f\"Cannot set border for '{atname}'.\")\n            return None\n        if not atype in (PDF_ANNOT_CIRCLE, PDF_ANNOT_FREE_TEXT,PDF_ANNOT_POLYGON, PDF_ANNOT_SQUARE):\n            if clouds > 0:\n                print(f\"Cannot set cloudy border for '{atname}'.\")\n                clouds = -1  # do not set border effect\n        if type(border) is not dict:\n            border = {\"width\": width, \"style\": style, \"dashes\": dashes, \"clouds\": clouds}\n        border.setdefault(\"width\", -1)\n        border.setdefault(\"style\", None)\n        border.setdefault(\"dashes\", None)\n        border.setdefault(\"clouds\", -1)\n        if border[\"width\"] == None:\n            border[\"width\"] = -1\n        if border[\"clouds\"] == None:\n            border[\"clouds\"] = -1\n        if hasattr(border[\"dashes\"], \"__getitem__\"):  # ensure sequence items are integers\n            border[\"dashes\"] = tuple(border[\"dashes\"])\n            for item in border[\"dashes\"]:\n                if not isinstance(item, int):\n                    border[\"dashes\"] = None\n                    break\n        %}\n        PyObject *\n        set_border(PyObject *border=NULL, float width=-1, char *style=NULL, PyObject *dashes=NULL, int clouds=-1)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_document *pdf = pdf_get_bound_document(gctx, annot_obj);\n            return JM_annot_set_border(gctx, border, pdf, annot_obj);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation flags\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        PARENTCHECK(flags, \"\"\"Flags field.\"\"\")\n        int flags()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            return pdf_annot_flags(gctx, annot);\n        }\n\n        //----------------------------------------------------------------\n        // annotation clean contents\n        //----------------------------------------------------------------\n        FITZEXCEPTION(clean_contents, !result)\n        PARENTCHECK(clean_contents, \"\"\"Clean appearance contents stream.\"\"\")\n        PyObject *clean_contents(int sanitize=1)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_document *pdf = pdf_get_bound_document(gctx, pdf_annot_obj(gctx, annot));\n            #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n            pdf_filter_factory list[2] = { 0 };\n            pdf_sanitize_filter_options sopts = { 0 };\n            pdf_filter_options filter = {\n                1,     // recurse: true\n                0,     // instance forms\n                0,     // do not ascii-escape binary data\n                0,     // no_update\n                NULL,  // end_page_opaque\n                NULL,  // end page\n                list,  // filters\n                };\n            if (sanitize) {\n              list[0].filter = pdf_new_sanitize_filter;\n              list[0].options = &sopts;\n            }\n            #else\n            pdf_filter_options filter = {\n                NULL,  // opaque\n                NULL,  // image filter\n                NULL,  // text filter\n                NULL,  // after text\n                NULL,  // end page\n                1,     // recurse: true\n                1,     // instance forms\n                1,     // sanitize,\n                0      // do not ascii-escape binary data\n                };\n            filter.sanitize = sanitize;\n            #endif\n            fz_try(gctx) {\n                pdf_filter_annot_contents(gctx, pdf, annot, &filter);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        //----------------------------------------------------------------\n        // set annotation flags\n        //----------------------------------------------------------------\n        PARENTCHECK(set_flags, \"\"\"Set annotation flags.\"\"\")\n        void\n        set_flags(int flags)\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_set_annot_flags(gctx, annot, flags);\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation delete responses\n        //----------------------------------------------------------------\n        FITZEXCEPTION(delete_responses, !result)\n        PARENTCHECK(delete_responses, \"\"\"Delete 'Popup' and responding annotations.\"\"\")\n        PyObject *\n        delete_responses()\n        {\n            pdf_annot *annot = (pdf_annot *) $self;\n            pdf_obj *annot_obj = pdf_annot_obj(gctx, annot);\n            pdf_page *page = pdf_annot_page(gctx, annot);\n            pdf_annot *irt_annot = NULL;\n            fz_try(gctx) {\n                while (1) {\n                    irt_annot = JM_find_annot_irt(gctx, annot);\n                    if (!irt_annot)\n                        break;\n                    pdf_delete_annot(gctx, page, irt_annot);\n                }\n                pdf_dict_del(gctx, annot_obj, PDF_NAME(Popup));\n                \n                pdf_obj *annots = pdf_dict_get(gctx, page->obj, PDF_NAME(Annots));\n                int i, n = pdf_array_len(gctx, annots), found = 0;\n                for (i = n - 1; i >= 0; i--) {\n                    pdf_obj *o = pdf_array_get(gctx, annots, i);\n                    pdf_obj *p = pdf_dict_get(gctx, o, PDF_NAME(Parent));\n                    if (!p)\n                        continue;\n                    if (!pdf_objcmp(gctx, p, annot_obj)) {\n                        pdf_array_delete(gctx, annots, i);\n                        found = 1;\n                    }\n                }\n                if (found > 0) {\n                    pdf_dict_put(gctx, page->obj, PDF_NAME(Annots), annots);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // next annotation\n        //----------------------------------------------------------------\n        PARENTCHECK(next, \"\"\"Next annotation.\"\"\")\n        %pythonappend next %{\n        if not val:\n            return None\n        val.thisown = True\n        val.parent = self.parent  # copy owning page object from previous annot\n        val.parent._annot_refs[id(val)] = val\n\n        if val.type[0] == PDF_ANNOT_WIDGET:\n            widget = Widget()\n            TOOLS._fill_widget(val, widget)\n            val = widget\n        %}\n        %pythoncode %{@property%}\n        struct Annot *next()\n        {\n            pdf_annot *this_annot = (pdf_annot *) $self;\n            int type = pdf_annot_type(gctx, this_annot);\n            pdf_annot *annot;\n\n            if (type != PDF_ANNOT_WIDGET) {\n                annot = pdf_next_annot(gctx, this_annot);\n            } else {\n                annot = pdf_next_widget(gctx, this_annot);\n            }\n\n            if (annot)\n                pdf_keep_annot(gctx, annot);\n            return (struct Annot *) annot;\n        }\n\n\n        //----------------------------------------------------------------\n        // annotation pixmap\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_pixmap, !result)\n        %pythonprepend get_pixmap\n%{\"\"\"annotation Pixmap\"\"\"\n\nCheckParent(self)\ncspaces = {\"gray\": csGRAY, \"rgb\": csRGB, \"cmyk\": csCMYK}\nif type(colorspace) is str:\n    colorspace = cspaces.get(colorspace.lower(), None)\nif dpi:\n    matrix = Matrix(dpi / 72, dpi / 72)\n%}\n        %pythonappend get_pixmap\n%{\n        val.thisown = True\n        if dpi:\n            val.set_dpi(dpi, dpi)\n%}\n        struct Pixmap *\n        get_pixmap(PyObject *matrix = NULL, PyObject *dpi=NULL, struct Colorspace *colorspace = NULL, int alpha = 0)\n        {\n            fz_matrix ctm = JM_matrix_from_py(matrix);\n            fz_colorspace *cs = (fz_colorspace *) colorspace;\n            fz_pixmap *pix = NULL;\n            if (!cs) {\n                cs = fz_device_rgb(gctx);\n            }\n\n            fz_try(gctx) {\n                pix = pdf_new_pixmap_from_annot(gctx, (pdf_annot *) $self, ctm, cs, NULL, alpha);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pix;\n        }\n        %pythoncode %{\n        def _erase(self):\n            self.__swig_destroy__(self)\n            self.parent = None\n\n        def __str__(self):\n            CheckParent(self)\n            return \"'%s' annotation on %s\" % (self.type[1], str(self.parent))\n\n        def __repr__(self):\n            CheckParent(self)\n            return \"'%s' annotation on %s\" % (self.type[1], str(self.parent))\n\n        def __del__(self):\n            if self.parent is None:\n                return\n            self._erase()%}\n    }\n};\n%clearnodefaultctor;\n\n//------------------------------------------------------------------------\n// fz_link\n//------------------------------------------------------------------------\n%nodefaultctor;\nstruct Link\n{\n    %immutable;\n    %extend {\n        ~Link() {\n            DEBUGMSG1(\"Link\");\n            fz_link *this_link = (fz_link *) $self;\n            fz_drop_link(gctx, this_link);\n            DEBUGMSG2;\n        }\n\n        PyObject *_border(struct Document *doc, int xref)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) doc);\n            if (!pdf) Py_RETURN_NONE;\n            pdf_obj *link_obj = pdf_new_indirect(gctx, pdf, xref, 0);\n            if (!link_obj) Py_RETURN_NONE;\n            PyObject *b = JM_annot_border(gctx, link_obj);\n            pdf_drop_obj(gctx, link_obj);\n            return b;\n        }\n\n        PyObject *_setBorder(PyObject *border, struct Document *doc, int xref)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) doc);\n            if (!pdf) Py_RETURN_NONE;\n            pdf_obj *link_obj = pdf_new_indirect(gctx, pdf, xref, 0);\n            if (!link_obj) Py_RETURN_NONE;\n            PyObject *b = JM_annot_set_border(gctx, border, pdf, link_obj);\n            pdf_drop_obj(gctx, link_obj);\n            return b;\n        }\n\n        FITZEXCEPTION(_colors, !result)\n        PyObject *_colors(struct Document *doc, int xref)\n        {\n            pdf_document *pdf = pdf_specifics(gctx, (fz_document *) doc);\n            if (!pdf) Py_RETURN_NONE;\n            PyObject *b = NULL;\n            pdf_obj *link_obj;\n            fz_try(gctx) {\n                link_obj = pdf_new_indirect(gctx, pdf, xref, 0);\n                if (!link_obj) {\n                    RAISEPY(gctx, MSG_BAD_XREF, PyExc_ValueError);\n                }\n                b = JM_annot_colors(gctx, link_obj);\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, link_obj);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return b;\n        }\n\n\n        %pythoncode %{\n        @property\n        def border(self):\n            return self._border(self.parent.parent.this, self.xref)\n\n        @property\n        def flags(self)->int:\n            CheckParent(self)\n            doc = self.parent.parent\n            if not doc.is_pdf:\n                return 0\n            f = doc.xref_get_key(self.xref, \"F\")\n            if f[1] != \"null\":\n                return int(f[1])\n            return 0\n\n        def set_flags(self, flags):\n            CheckParent(self)\n            doc = self.parent.parent\n            if not doc.is_pdf:\n                raise ValueError(\"is no PDF\")\n            if not type(flags) is int:\n                raise ValueError(\"bad 'flags' value\")\n            doc.xref_set_key(self.xref, \"F\", str(flags))\n            return None\n\n        def set_border(self, border=None, width=0, dashes=None, style=None):\n            if type(border) is not dict:\n                border = {\"width\": width, \"style\": style, \"dashes\": dashes}\n            return self._setBorder(border, self.parent.parent.this, self.xref)\n\n        @property\n        def colors(self):\n            return self._colors(self.parent.parent.this, self.xref)\n\n        def set_colors(self, colors=None, stroke=None, fill=None):\n            \"\"\"Set border colors.\"\"\"\n            CheckParent(self)\n            doc = self.parent.parent\n            if type(colors) is not dict:\n                colors = {\"fill\": fill, \"stroke\": stroke}\n            fill = colors.get(\"fill\")\n            stroke = colors.get(\"stroke\")\n            if fill is not None:\n                print(\"warning: links have no fill color\")\n            if stroke in ([], ()):\n                doc.xref_set_key(self.xref, \"C\", \"[]\")\n                return\n            if hasattr(stroke, \"__float__\"):\n                stroke = [float(stroke)]\n            CheckColor(stroke)\n            if len(stroke) == 1:\n                s = \"[%g]\" % stroke[0]\n            elif len(stroke) == 3:\n                s = \"[%g %g %g]\" % tuple(stroke)\n            else:\n                s = \"[%g %g %g %g]\" % tuple(stroke)\n            doc.xref_set_key(self.xref, \"C\", s)\n        %}\n        %pythoncode %{@property%}\n        PARENTCHECK(uri, \"\"\"Uri string.\"\"\")\n        PyObject *uri()\n        {\n            fz_link *this_link = (fz_link *) $self;\n            return JM_UnicodeFromStr(this_link->uri);\n        }\n\n        %pythoncode %{@property%}\n        PARENTCHECK(is_external, \"\"\"Flag the link as external.\"\"\")\n        PyObject *is_external()\n        {\n            fz_link *this_link = (fz_link *) $self;\n            if (!this_link->uri) Py_RETURN_FALSE;\n            return JM_BOOL(fz_is_external_link(gctx, this_link->uri));\n        }\n\n        %pythoncode\n        %{\n        page = -1\n        @property\n        def dest(self):\n            \"\"\"Create link destination details.\"\"\"\n            if hasattr(self, \"parent\") and self.parent is None:\n                raise ValueError(\"orphaned object: parent is None\")\n            if self.parent.parent.is_closed or self.parent.parent.is_encrypted:\n                raise ValueError(\"document closed or encrypted\")\n            doc = self.parent.parent\n\n            if self.is_external or self.uri.startswith(\"#\"):\n                uri = None\n            else:\n                uri = doc.resolve_link(self.uri)\n\n            return linkDest(self, uri)\n        %}\n\n        PARENTCHECK(rect, \"\"\"Rectangle ('hot area').\"\"\")\n        %pythoncode %{@property%}\n        %pythonappend rect %{val = Rect(val)%}\n        PyObject *rect()\n        {\n            fz_link *this_link = (fz_link *) $self;\n            return JM_py_from_rect(this_link->rect);\n        }\n\n        //----------------------------------------------------------------\n        // next link\n        //----------------------------------------------------------------\n        // we need to increase the link refs number\n        // so that it will not be freed when the head is dropped\n        PARENTCHECK(next, \"\"\"Next link.\"\"\")\n        %pythonappend next %{\n            if val:\n                val.thisown = True\n                val.parent = self.parent  # copy owning page from prev link\n                val.parent._annot_refs[id(val)] = val\n                if self.xref > 0:  # prev link has an xref\n                    link_xrefs = [x[0] for x in self.parent.annot_xrefs() if x[1] == PDF_ANNOT_LINK]\n                    link_ids = [x[2] for x in self.parent.annot_xrefs() if x[1] == PDF_ANNOT_LINK]\n                    idx = link_xrefs.index(self.xref)\n                    val.xref = link_xrefs[idx + 1]\n                    val.id = link_ids[idx + 1]\n                else:\n                    val.xref = 0\n                    val.id = \"\"\n        %}\n        %pythoncode %{@property%}\n        struct Link *next()\n        {\n            fz_link *this_link = (fz_link *) $self;\n            fz_link *next_link = this_link->next;\n            if (!next_link) return NULL;\n            next_link = fz_keep_link(gctx, next_link);\n            return (struct Link *) next_link;\n        }\n\n        %pythoncode %{\n        def _erase(self):\n            self.__swig_destroy__(self)\n            self.parent = None\n\n        def __str__(self):\n            CheckParent(self)\n            return \"link on \" + str(self.parent)\n\n        def __repr__(self):\n            CheckParent(self)\n            return \"link on \" + str(self.parent)\n\n        def __del__(self):\n            self._erase()%}\n    }\n};\n%clearnodefaultctor;\n\n//------------------------------------------------------------------------\n// fz_display_list\n//------------------------------------------------------------------------\nstruct DisplayList {\n    %extend\n    {\n        ~DisplayList() {\n            DEBUGMSG1(\"DisplayList\");\n            fz_display_list *this_dl = (fz_display_list *) $self;\n            fz_drop_display_list(gctx, this_dl);\n            DEBUGMSG2;\n        }\n        FITZEXCEPTION(DisplayList, !result)\n        DisplayList(PyObject *mediabox)\n        {\n            fz_display_list *dl = NULL;\n            fz_try(gctx) {\n                dl = fz_new_display_list(gctx, JM_rect_from_py(mediabox));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct DisplayList *) dl;\n        }\n\n        FITZEXCEPTION(run, !result)\n        PyObject *run(struct DeviceWrapper *dw, PyObject *m, PyObject *area) {\n            fz_try(gctx) {\n                fz_run_display_list(gctx, (fz_display_list *) $self, dw->device,\n                    JM_matrix_from_py(m), JM_rect_from_py(area), NULL);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------------------------------------\n        // DisplayList.rect\n        //----------------------------------------------------------------\n        %pythoncode%{@property%}\n        %pythonappend rect %{val = Rect(val)%}\n        PyObject *rect()\n        {\n            return JM_py_from_rect(fz_bound_display_list(gctx, (fz_display_list *) $self));\n        }\n\n        //----------------------------------------------------------------\n        // DisplayList.get_pixmap\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_pixmap, !result)\n        %pythonappend get_pixmap %{val.thisown = True%}\n        struct Pixmap *get_pixmap(PyObject *matrix=NULL,\n                                      struct Colorspace *colorspace=NULL,\n                                      int alpha=0,\n                                      PyObject *clip=NULL)\n        {\n            fz_colorspace *cs = NULL;\n            fz_pixmap *pix = NULL;\n\n            if (colorspace) cs = (fz_colorspace *) colorspace;\n            else cs = fz_device_rgb(gctx);\n\n            fz_try(gctx) {\n                pix = JM_pixmap_from_display_list(gctx,\n                          (fz_display_list *) $self, matrix, cs,\n                           alpha, clip, NULL);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Pixmap *) pix;\n        }\n\n        //----------------------------------------------------------------\n        // DisplayList.get_textpage\n        //----------------------------------------------------------------\n        FITZEXCEPTION(get_textpage, !result)\n        %pythonappend get_textpage %{val.thisown = True%}\n        struct TextPage *get_textpage(int flags = 3)\n        {\n            fz_display_list *this_dl = (fz_display_list *) $self;\n            fz_stext_page *tp = NULL;\n            fz_try(gctx) {\n                fz_stext_options stext_options = { 0 };\n                stext_options.flags = flags;\n                tp = fz_new_stext_page_from_display_list(gctx, this_dl, &stext_options);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct TextPage *) tp;\n        }\n        %pythoncode %{\n        def __del__(self):\n            if not type(self) is DisplayList:\n                return\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n        %}\n    }\n};\n\n//------------------------------------------------------------------------\n// fz_stext_page\n//------------------------------------------------------------------------\nstruct TextPage {\n    %extend {\n        ~TextPage()\n        {\n            DEBUGMSG1(\"TextPage\");\n            fz_stext_page *this_tp = (fz_stext_page *) $self;\n            fz_drop_stext_page(gctx, this_tp);\n            DEBUGMSG2;\n        }\n\n        FITZEXCEPTION(TextPage, !result)\n        %pythonappend TextPage %{self.thisown=True%}\n        TextPage(PyObject *mediabox)\n        {\n            fz_stext_page *tp = NULL;\n            fz_try(gctx) {\n                tp = fz_new_stext_page(gctx, JM_rect_from_py(mediabox));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct TextPage *) tp;\n        }\n\n        //----------------------------------------------------------------\n        // method search()\n        //----------------------------------------------------------------\n        FITZEXCEPTION(search, !result)\n        %pythonprepend search\n        %{\"\"\"Locate 'needle' returning rects or quads.\"\"\"%}\n        %pythonappend search %{\n        if not val:\n            return val\n        items = len(val)\n        for i in range(items):  # change entries to quads or rects\n            q = Quad(val[i])\n            if quads:\n                val[i] = q\n            else:\n                val[i] = q.rect\n        if quads:\n            return val\n        i = 0  # join overlapping rects on the same line\n        while i < items - 1:\n            v1 = val[i]\n            v2 = val[i + 1]\n            if v1.y1 != v2.y1 or (v1 & v2).is_empty:\n                i += 1\n                continue  # no overlap on same line\n            val[i] = v1 | v2  # join rectangles\n            del val[i + 1]  # remove v2\n            items -= 1  # reduce item count\n        %}\n        PyObject *search(const char *needle, int hit_max=0, int quads=1)\n        {\n            PyObject *liste = NULL;\n            fz_try(gctx) {\n                liste = JM_search_stext_page(gctx, (fz_stext_page *) $self, needle);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return liste;\n        }\n\n\n        //----------------------------------------------------------------\n        // Get list of all blocks with block type and bbox as a Python list\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_getNewBlockList, !result)\n        PyObject *\n        _getNewBlockList(PyObject *page_dict, int raw)\n        {\n            fz_try(gctx) {\n                JM_make_textpage_dict(gctx, (fz_stext_page *) $self, page_dict, raw);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode %{\n        def _textpage_dict(self, raw=False):\n            page_dict = {\"width\": self.rect.width, \"height\": self.rect.height}\n            self._getNewBlockList(page_dict, raw)\n            return page_dict\n        %}\n\n\n        //----------------------------------------------------------------\n        // Get image meta information as a Python dictionary\n        //----------------------------------------------------------------\n        FITZEXCEPTION(extractIMGINFO, !result)\n        %pythonprepend extractIMGINFO\n        %{\"\"\"Return a list with image meta information.\"\"\"%}\n        PyObject *\n        extractIMGINFO(int hashes=0)\n        {\n            fz_stext_block *block;\n            int block_n = -1;\n            fz_stext_page *this_tpage = (fz_stext_page *) $self;\n            PyObject *rc = NULL, *block_dict = NULL;\n            fz_pixmap *pix = NULL;\n            fz_try(gctx) {\n                rc = PyList_New(0);\n                for (block = this_tpage->first_block; block; block = block->next) {\n                    block_n++;\n                    if (block->type == FZ_STEXT_BLOCK_TEXT) {\n                        continue;\n                    }\n                    unsigned char digest[16];\n                    fz_image *img = block->u.i.image;\n                    Py_ssize_t img_size = 0;\n                    fz_compressed_buffer *cbuff = fz_compressed_image_buffer(gctx, img);\n                    if (cbuff) {\n                        img_size = (Py_ssize_t) cbuff->buffer->len;\n                    }\n                    if (hashes) {\n                        pix = fz_get_pixmap_from_image(gctx, img, NULL, NULL, NULL, NULL);\n                        if (img_size == 0) {\n                            img_size = (Py_ssize_t) pix->w * pix->h * pix->n;\n                        }\n                        fz_md5_pixmap(gctx, pix, digest);\n                        fz_drop_pixmap(gctx, pix);\n                        pix = NULL;\n                    }\n                    fz_colorspace *cs = img->colorspace;\n                    block_dict = PyDict_New();\n                    DICT_SETITEM_DROP(block_dict, dictkey_number, Py_BuildValue(\"i\", block_n));\n                    DICT_SETITEM_DROP(block_dict, dictkey_bbox,\n                                    JM_py_from_rect(block->bbox));\n                    DICT_SETITEM_DROP(block_dict, dictkey_matrix,\n                                    JM_py_from_matrix(block->u.i.transform));\n                    DICT_SETITEM_DROP(block_dict, dictkey_width,\n                                    Py_BuildValue(\"i\", img->w));\n                    DICT_SETITEM_DROP(block_dict, dictkey_height,\n                                    Py_BuildValue(\"i\", img->h));\n                    DICT_SETITEM_DROP(block_dict, dictkey_colorspace,\n                                    Py_BuildValue(\"i\",\n                                    fz_colorspace_n(gctx, cs)));\n                    DICT_SETITEM_DROP(block_dict, dictkey_cs_name,\n                                    Py_BuildValue(\"s\",\n                                    fz_colorspace_name(gctx, cs)));\n                    DICT_SETITEM_DROP(block_dict, dictkey_xres,\n                                    Py_BuildValue(\"i\", img->xres));\n                    DICT_SETITEM_DROP(block_dict, dictkey_yres,\n                                    Py_BuildValue(\"i\", img->xres));\n                    DICT_SETITEM_DROP(block_dict, dictkey_bpc,\n                                    Py_BuildValue(\"i\", (int) img->bpc));\n                    DICT_SETITEM_DROP(block_dict, dictkey_size,\n                                    Py_BuildValue(\"n\", img_size));\n                    if (hashes) {\n                        DICT_SETITEMSTR_DROP(block_dict, \"digest\",\n                                    PyBytes_FromStringAndSize(digest, 16));\n                    }\n                    LIST_APPEND_DROP(rc, block_dict);\n                }\n            }\n            fz_always(gctx) {\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(rc);\n                Py_CLEAR(block_dict);\n                fz_drop_pixmap(gctx, pix);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        //----------------------------------------------------------------\n        // Get text blocks with their bbox and concatenated lines\n        // as a Python list\n        //----------------------------------------------------------------\n        FITZEXCEPTION(extractBLOCKS, !result)\n        %pythonprepend extractBLOCKS\n        %{\"\"\"Return a list with text block information.\"\"\"%}\n        PyObject *\n        extractBLOCKS()\n        {\n            fz_stext_block *block;\n            fz_stext_line *line;\n            fz_stext_char *ch;\n            int block_n = -1;\n            PyObject *text = NULL, *litem;\n            fz_buffer *res = NULL;\n            fz_var(res);\n            fz_stext_page *this_tpage = (fz_stext_page *) $self;\n            fz_rect tp_rect = this_tpage->mediabox;\n            PyObject *lines = NULL;\n            fz_try(gctx) {\n                res = fz_new_buffer(gctx, 1024);\n                lines = PyList_New(0);\n                for (block = this_tpage->first_block; block; block = block->next) {\n                    block_n++;\n                    fz_rect blockrect = fz_empty_rect;\n                    if (block->type == FZ_STEXT_BLOCK_TEXT) {\n                        fz_clear_buffer(gctx, res);  // set text buffer to empty\n                        int line_n = -1;\n                        int last_char = 0;\n                        for (line = block->u.t.first_line; line; line = line->next) {\n                            line_n++;\n                            fz_rect linerect = fz_empty_rect;\n                            for (ch = line->first_char; ch; ch = ch->next) {\n                                fz_rect cbbox = JM_char_bbox(gctx, line, ch);\n                                if (!JM_rects_overlap(tp_rect, cbbox) &&\n                                    !fz_is_infinite_rect(tp_rect)) {\n                                    continue;\n                                }\n                                JM_append_rune(gctx, res, ch->c);\n                                last_char = ch->c;\n                                linerect = fz_union_rect(linerect, cbbox);\n                            }\n                            if (last_char != 10 && !fz_is_empty_rect(linerect)) {\n                                fz_append_byte(gctx, res, 10);\n                            }\n                            blockrect = fz_union_rect(blockrect, linerect);\n                        }\n                        text = JM_EscapeStrFromBuffer(gctx, res);\n                    } else if (JM_rects_overlap(tp_rect, block->bbox) || fz_is_infinite_rect(tp_rect)) {\n                        fz_image *img = block->u.i.image;\n                        fz_colorspace *cs = img->colorspace;\n                        text = PyUnicode_FromFormat(\"<image: %s, width: %d, height: %d, bpc: %d>\", fz_colorspace_name(gctx, cs), img->w, img->h, img->bpc);\n                        blockrect = fz_union_rect(blockrect, block->bbox);\n                    }\n                    if (!fz_is_empty_rect(blockrect)) {\n                        litem = PyTuple_New(7);\n                        PyTuple_SET_ITEM(litem, 0, Py_BuildValue(\"f\", blockrect.x0));\n                        PyTuple_SET_ITEM(litem, 1, Py_BuildValue(\"f\", blockrect.y0));\n                        PyTuple_SET_ITEM(litem, 2, Py_BuildValue(\"f\", blockrect.x1));\n                        PyTuple_SET_ITEM(litem, 3, Py_BuildValue(\"f\", blockrect.y1));\n                        PyTuple_SET_ITEM(litem, 4, Py_BuildValue(\"O\", text));\n                        PyTuple_SET_ITEM(litem, 5, Py_BuildValue(\"i\", block_n));\n                        PyTuple_SET_ITEM(litem, 6, Py_BuildValue(\"i\", block->type));\n                        LIST_APPEND_DROP(lines, litem);\n                    }\n                    Py_CLEAR(text);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n                PyErr_Clear();\n            }\n            fz_catch(gctx) {\n                Py_CLEAR(lines);\n                return NULL;\n            }\n            return lines;\n        }\n\n        //----------------------------------------------------------------\n        // Get text words with their bbox\n        //----------------------------------------------------------------\n        FITZEXCEPTION(extractWORDS, !result)\n        %pythonprepend extractWORDS\n        %{\"\"\"Return a list with text word information.\"\"\"%}\n        PyObject *\n        extractWORDS(PyObject *delimiters=NULL)\n        {\n            fz_stext_block *block;\n            fz_stext_line *line;\n            fz_stext_char *ch;\n            fz_buffer *buff = NULL;\n            fz_var(buff);\n            size_t buflen = 0;\n            int block_n = -1, line_n, word_n;\n            fz_rect wbbox = fz_empty_rect;  // word bbox\n            fz_stext_page *this_tpage = (fz_stext_page *) $self;\n            fz_rect tp_rect = this_tpage->mediabox;\n            int word_delimiter = 0;\n            PyObject *lines = NULL;\n            fz_try(gctx) {\n                buff = fz_new_buffer(gctx, 64);\n                lines = PyList_New(0);\n                for (block = this_tpage->first_block; block; block = block->next) {\n                    block_n++;\n                    if (block->type != FZ_STEXT_BLOCK_TEXT) {\n                        continue;\n                    }\n                    line_n = -1;\n                    for (line = block->u.t.first_line; line; line = line->next) {\n                        line_n++;\n                        word_n = 0;                       // word counter per line\n                        fz_clear_buffer(gctx, buff);      // reset word buffer\n                        buflen = 0;                       // reset char counter\n                        for (ch = line->first_char; ch; ch = ch->next) {\n                            fz_rect cbbox = JM_char_bbox(gctx, line, ch);\n                            if (!JM_rects_overlap(tp_rect, cbbox) &&\n                                !fz_is_infinite_rect(tp_rect)) {\n                                continue;\n                            }\n                            word_delimiter = JM_is_word_delimiter(ch->c, delimiters);\n                            if (word_delimiter) {\n                                if (buflen == 0) continue;  // skip spaces at line start\n                                if (!fz_is_empty_rect(wbbox)) {  // output word\n                                    word_n = JM_append_word(gctx, lines, buff, &wbbox,\n                                                        block_n, line_n, word_n);\n                                }\n                                fz_clear_buffer(gctx, buff);\n                                buflen = 0;  // reset char counter\n                                continue;\n                            }\n                            // append one unicode character to the word\n                            JM_append_rune(gctx, buff, ch->c);\n                            buflen++;\n                            // enlarge word bbox\n                            wbbox = fz_union_rect(wbbox, JM_char_bbox(gctx, line, ch));\n                        }\n                        if (buflen && !fz_is_empty_rect(wbbox)) {\n                            word_n = JM_append_word(gctx, lines, buff, &wbbox,\n                                                    block_n, line_n, word_n);\n                        }\n                        fz_clear_buffer(gctx, buff);\n                        buflen = 0;\n                    }\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buff);\n                PyErr_Clear();\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return lines;\n        }\n\n        //----------------------------------------------------------------\n        // TextPage poolsize\n        //----------------------------------------------------------------\n        %pythonprepend poolsize\n        %{\"\"\"TextPage current poolsize.\"\"\"%}\n        PyObject *poolsize()\n        {\n            fz_stext_page *tpage = (fz_stext_page *) $self;\n            size_t size = fz_pool_size(gctx, tpage->pool);\n            return PyLong_FromSize_t(size);\n        }\n\n        //----------------------------------------------------------------\n        // TextPage rectangle\n        //----------------------------------------------------------------\n        %pythoncode %{@property%}\n        %pythonprepend rect\n        %{\"\"\"TextPage rectangle.\"\"\"%}\n        %pythonappend rect %{val = Rect(val)%}\n        PyObject *rect()\n        {\n            fz_stext_page *this_tpage = (fz_stext_page *) $self;\n            fz_rect mediabox = this_tpage->mediabox;\n            return JM_py_from_rect(mediabox);\n        }\n\n        //----------------------------------------------------------------\n        // method _extractText()\n        //----------------------------------------------------------------\n        FITZEXCEPTION(_extractText, !result)\n        %newobject _extractText;\n        PyObject *_extractText(int format)\n        {\n            fz_buffer *res = NULL;\n            fz_output *out = NULL;\n            PyObject *text = NULL;\n            fz_var(res);\n            fz_var(out);\n            fz_stext_page *this_tpage = (fz_stext_page *) $self;\n            fz_try(gctx) {\n                res = fz_new_buffer(gctx, 1024);\n                out = fz_new_output_with_buffer(gctx, res);\n                switch(format) {\n                    case(1):\n                        fz_print_stext_page_as_html(gctx, out, this_tpage, 0);\n                        break;\n                    case(3):\n                        fz_print_stext_page_as_xml(gctx, out, this_tpage, 0);\n                        break;\n                    case(4):\n                        fz_print_stext_page_as_xhtml(gctx, out, this_tpage, 0);\n                        break;\n                    default:\n                        JM_print_stext_page_as_text(gctx, res, this_tpage);\n                        break;\n                }\n                text = JM_EscapeStrFromBuffer(gctx, res);\n\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n                fz_drop_output(gctx, out);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return text;\n        }\n\n\n        //----------------------------------------------------------------\n        // method extractTextbox()\n        //----------------------------------------------------------------\n        FITZEXCEPTION(extractTextbox, !result)\n        PyObject *extractTextbox(PyObject *rect)\n        {\n            fz_stext_page *this_tpage = (fz_stext_page *) $self;\n            fz_rect area = JM_rect_from_py(rect);\n            PyObject *rc = NULL;\n            fz_try(gctx) {\n                rc = JM_copy_rectangle(gctx, this_tpage, area);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return rc;\n        }\n\n        //----------------------------------------------------------------\n        // method extractSelection()\n        //----------------------------------------------------------------\n        PyObject *extractSelection(PyObject *pointa, PyObject *pointb)\n        {\n            fz_stext_page *this_tpage = (fz_stext_page *) $self;\n            fz_point a = JM_point_from_py(pointa);\n            fz_point b = JM_point_from_py(pointb);\n            char *found = fz_copy_selection(gctx, this_tpage, a, b, 0);\n            PyObject *rc = NULL;\n            if (found) {\n                rc = PyUnicode_FromString(found);\n                JM_Free(found);\n            } else {\n                rc = EMPTY_STRING;\n            }\n            return rc;\n        }\n\n        %pythoncode %{\n            def extractText(self, sort=False) -> str:\n                \"\"\"Return simple, bare text on the page.\"\"\"\n                if sort is False:\n                    return self._extractText(0)\n                blocks = self.extractBLOCKS()[:]\n                blocks.sort(key=lambda b: (b[3], b[0]))\n                return \"\".join([b[4] for b in blocks])\n\n            def extractHTML(self) -> str:\n                \"\"\"Return page content as a HTML string.\"\"\"\n                return self._extractText(1)\n\n            def extractJSON(self, cb=None, sort=False) -> str:\n                \"\"\"Return 'extractDICT' converted to JSON format.\"\"\"\n                import base64, json\n                val = self._textpage_dict(raw=False)\n\n                class b64encode(json.JSONEncoder):\n                    def default(self, s):\n                        if type(s) in (bytes, bytearray):\n                            return base64.b64encode(s).decode()\n\n                if cb is not None:\n                    val[\"width\"] = cb.width\n                    val[\"height\"] = cb.height\n                if sort is True:\n                    blocks = val[\"blocks\"]\n                    blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n                    val[\"blocks\"] = blocks\n                val = json.dumps(val, separators=(\",\", \":\"), cls=b64encode, indent=1)\n                return val\n\n            def extractRAWJSON(self, cb=None, sort=False) -> str:\n                \"\"\"Return 'extractRAWDICT' converted to JSON format.\"\"\"\n                import base64, json\n                val = self._textpage_dict(raw=True)\n\n                class b64encode(json.JSONEncoder):\n                    def default(self,s):\n                        if type(s) in (bytes, bytearray):\n                            return base64.b64encode(s).decode()\n\n                if cb is not None:\n                    val[\"width\"] = cb.width\n                    val[\"height\"] = cb.height\n                if sort is True:\n                    blocks = val[\"blocks\"]\n                    blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n                    val[\"blocks\"] = blocks\n                val = json.dumps(val, separators=(\",\", \":\"), cls=b64encode, indent=1)\n                return val\n\n            def extractXML(self) -> str:\n                \"\"\"Return page content as a XML string.\"\"\"\n                return self._extractText(3)\n\n            def extractXHTML(self) -> str:\n                \"\"\"Return page content as a XHTML string.\"\"\"\n                return self._extractText(4)\n\n            def extractDICT(self, cb=None, sort=False) -> dict:\n                \"\"\"Return page content as a Python dict of images and text spans.\"\"\"\n                val = self._textpage_dict(raw=False)\n                if cb is not None:\n                    val[\"width\"] = cb.width\n                    val[\"height\"] = cb.height\n                if sort is True:\n                    blocks = val[\"blocks\"]\n                    blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n                    val[\"blocks\"] = blocks\n                return val\n\n            def extractRAWDICT(self, cb=None, sort=False) -> dict:\n                \"\"\"Return page content as a Python dict of images and text characters.\"\"\"\n                val =  self._textpage_dict(raw=True)\n                if cb is not None:\n                    val[\"width\"] = cb.width\n                    val[\"height\"] = cb.height\n                if sort is True:\n                    blocks = val[\"blocks\"]\n                    blocks.sort(key=lambda b: (b[\"bbox\"][3], b[\"bbox\"][0]))\n                    val[\"blocks\"] = blocks\n                return val\n\n            def __del__(self):\n                if not type(self) is TextPage:\n                    return\n                if getattr(self, \"thisown\", False):\n                    self.__swig_destroy__(self)\n        %}\n    }\n};\n\n//------------------------------------------------------------------------\n// Graftmap - only used internally for inter-PDF object copy operations\n//------------------------------------------------------------------------\nstruct Graftmap\n{\n    %extend\n    {\n        ~Graftmap()\n        {\n            DEBUGMSG1(\"Graftmap\");\n            pdf_graft_map *this_gm = (pdf_graft_map *) $self;\n            pdf_drop_graft_map(gctx, this_gm);\n            DEBUGMSG2;\n        }\n\n        FITZEXCEPTION(Graftmap, !result)\n        Graftmap(struct Document *doc)\n        {\n            pdf_graft_map *map = NULL;\n            fz_try(gctx) {\n                pdf_document *dst = pdf_specifics(gctx, (fz_document *) doc);\n                ASSERT_PDF(dst);\n                map = pdf_new_graft_map(gctx, dst);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Graftmap *) map;\n        }\n\n        %pythoncode %{\n        def __del__(self):\n            if not type(self) is Graftmap:\n                return\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n        %}\n    }\n};\n\n\n//------------------------------------------------------------------------\n// TextWriter\n//------------------------------------------------------------------------\nstruct TextWriter\n{\n    %extend {\n        ~TextWriter()\n        {\n            DEBUGMSG1(\"TextWriter\");\n            fz_text *this_tw = (fz_text *) $self;\n            fz_drop_text(gctx, this_tw);\n            DEBUGMSG2;\n        }\n\n        FITZEXCEPTION(TextWriter, !result)\n        %pythonprepend TextWriter\n        %{\"\"\"Stores text spans for later output on compatible PDF pages.\"\"\"%}\n        %pythonappend TextWriter %{\n        self.opacity = opacity\n        self.color = color\n        self.rect = Rect(page_rect)\n        self.ctm = Matrix(1, 0, 0, -1, 0, self.rect.height)\n        self.ictm = ~self.ctm\n        self.last_point = Point()\n        self.last_point.__doc__ = \"Position following last text insertion.\"\n        self.text_rect = Rect()\n\n        self.text_rect.__doc__ = \"Accumulated area of text spans.\"\n        self.used_fonts = set()\n        self.thisown = True\n        %}\n        TextWriter(PyObject *page_rect, float opacity=1, PyObject *color=NULL )\n        {\n            fz_text *text = NULL;\n            fz_try(gctx) {\n                text = fz_new_text(gctx);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct TextWriter *) text;\n        }\n\n        FITZEXCEPTION(append, !result)\n        %pythonprepend append %{\n        \"\"\"Store 'text' at point 'pos' using 'font' and 'fontsize'.\"\"\"\n\n        pos = Point(pos) * self.ictm\n        if font is None:\n            font = Font(\"helv\")\n        if not font.is_writable:\n            raise ValueError(\"Unsupported font '%s'.\" % font.name)\n        if right_to_left:\n            text = self.clean_rtl(text)\n            text = \"\".join(reversed(text))\n            right_to_left = 0\n        %}\n        %pythonappend append %{\n        self.last_point = Point(val[-2:]) * self.ctm\n        self.text_rect = self._bbox * self.ctm\n        val = self.text_rect, self.last_point\n        if font.flags[\"mono\"] == 1:\n            self.used_fonts.add(font)\n        %}\n        PyObject *\n        append(PyObject *pos, char *text, struct Font *font=NULL, float fontsize=11, char *language=NULL, int right_to_left=0, int small_caps=0)\n        {\n            fz_text_language lang = fz_text_language_from_string(language);\n            fz_point p = JM_point_from_py(pos);\n            fz_matrix trm = fz_make_matrix(fontsize, 0, 0, fontsize, p.x, p.y);\n            int markup_dir = 0, wmode = 0;\n            fz_try(gctx) {\n                if (small_caps == 0) {\n                    trm = fz_show_string(gctx, (fz_text *) $self, (fz_font *) font,\n                                trm, text, wmode, right_to_left, markup_dir, lang);\n                } else {\n                    trm = JM_show_string_cs(gctx, (fz_text *) $self, (fz_font *) font,\n                                trm, text, wmode, right_to_left, markup_dir, lang);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_py_from_matrix(trm);\n        }\n\n        %pythoncode %{\n        def appendv(self, pos, text, font=None, fontsize=11,\n            language=None, small_caps=False):\n            \"\"\"Append text in vertical write mode.\"\"\"\n            lheight = fontsize * 1.2\n            for c in text:\n                self.append(pos, c, font=font, fontsize=fontsize,\n                    language=language, small_caps=small_caps)\n                pos.y += lheight\n            return self.text_rect, self.last_point\n\n\n        def clean_rtl(self, text):\n            \"\"\"Revert the sequence of Latin text parts.\n\n            Text with right-to-left writing direction (Arabic, Hebrew) often\n            contains Latin parts, which are written in left-to-right: numbers, names,\n            etc. For output as PDF text we need *everything* in right-to-left.\n            E.g. an input like \"<arabic> ABCDE FG HIJ <arabic> KL <arabic>\" will be\n            converted to \"<arabic> JIH GF EDCBA <arabic> LK <arabic>\". The Arabic\n            parts remain untouched.\n\n            Args:\n                text: str\n            Returns:\n                Massaged string.\n            \"\"\"\n            if not text:\n                return text\n            # split into words at space boundaries\n            words = text.split(\" \")\n            idx = []\n            for i in range(len(words)):\n                w = words[i]\n                # revert character sequence for Latin only words\n                if not (len(w) < 2 or max([ord(c) for c in w]) > 255):\n                    words[i] = \"\".join(reversed(w))\n                    idx.append(i)  # stored index of Latin word\n\n            # adjacent Latin words must revert their sequence, too\n            idx2 = []  # store indices of adjacent Latin words\n            for i in range(len(idx)):\n                if idx2 == []:  # empty yet?\n                    idx2.append(idx[i]) # store Latin word number\n\n                elif idx[i] > idx2[-1] + 1:  # large gap to last?\n                    if len(idx2) > 1:  # at least two consecutives?\n                        words[idx2[0] : idx2[-1] + 1] = reversed(\n                            words[idx2[0] : idx2[-1] + 1]\n                        )  # revert their sequence\n                    idx2 = [idx[i]]  # re-initialize\n\n                elif idx[i] == idx2[-1] + 1:  # new adjacent Latin word\n                    idx2.append(idx[i])\n\n            text = \" \".join(words)\n            return text\n        %}\n\n\n        %pythoncode %{@property%}\n        %pythonappend _bbox%{val = Rect(val)%}\n        PyObject *_bbox()\n        {\n            return JM_py_from_rect(fz_bound_text(gctx, (fz_text *) $self, NULL, fz_identity));\n        }\n\n        FITZEXCEPTION(write_text, !result)\n        %pythonprepend write_text%{\n        \"\"\"Write the text to a PDF page having the TextWriter's page size.\n\n        Args:\n            page: a PDF page having same size.\n            color: override text color.\n            opacity: override transparency.\n            overlay: put in foreground or background.\n            morph: tuple(Point, Matrix), apply a matrix with a fixpoint.\n            matrix: Matrix to be used instead of 'morph' argument.\n            render_mode: (int) PDF render mode operator 'Tr'.\n        \"\"\"\n\n        CheckParent(page)\n        if abs(self.rect - page.rect) > 1e-3:\n            raise ValueError(\"incompatible page rect\")\n        if morph != None:\n            if (type(morph) not in (tuple, list)\n                or type(morph[0]) is not Point\n                or type(morph[1]) is not Matrix\n                ):\n                raise ValueError(\"morph must be (Point, Matrix) or None\")\n        if matrix != None and morph != None:\n            raise ValueError(\"only one of matrix, morph is allowed\")\n        if getattr(opacity, \"__float__\", None) is None or opacity == -1:\n            opacity = self.opacity\n        if color is None:\n            color = self.color\n        %}\n\n        %pythonappend write_text%{\n        max_nums = val[0]\n        content = val[1]\n        max_alp, max_font = max_nums\n        old_cont_lines = content.splitlines()\n\n        optcont = page._get_optional_content(oc)\n        if optcont != None:\n            bdc = \"/OC /%s BDC\" % optcont\n            emc = \"EMC\"\n        else:\n            bdc = emc = \"\"\n\n        new_cont_lines = [\"q\"]\n        if bdc:\n            new_cont_lines.append(bdc)\n\n        cb = page.cropbox_position\n        if page.rotation in (90, 270):\n            delta = page.rect.height - page.rect.width\n        else:\n            delta = 0\n        mb = page.mediabox\n        if bool(cb) or mb.y0 != 0 or delta != 0:\n            new_cont_lines.append(\"1 0 0 1 %g %g cm\" % (cb.x, cb.y + mb.y0 - delta))\n\n        if morph:\n            p = morph[0] * self.ictm\n            delta = Matrix(1, 1).pretranslate(p.x, p.y)\n            matrix = ~delta * morph[1] * delta\n        if morph or matrix:\n            new_cont_lines.append(\"%g %g %g %g %g %g cm\" % JM_TUPLE(matrix))\n\n        for line in old_cont_lines:\n            if line.endswith(\" cm\"):\n                continue\n            if line == \"BT\":\n                new_cont_lines.append(line)\n                new_cont_lines.append(\"%i Tr\" % render_mode)\n                continue\n            if line.endswith(\" gs\"):\n                alp = int(line.split()[0][4:]) + max_alp\n                line = \"/Alp%i gs\" % alp\n            elif line.endswith(\" Tf\"):\n                temp = line.split()\n                fsize = float(temp[1])\n                if render_mode != 0:\n                    w = fsize * 0.05\n                else:\n                    w = 1\n                new_cont_lines.append(\"%g w\" % w)\n                font = int(temp[0][2:]) + max_font\n                line = \" \".join([\"/F%i\" % font] + temp[1:])\n            elif line.endswith(\" rg\"):\n                new_cont_lines.append(line.replace(\"rg\", \"RG\"))\n            elif line.endswith(\" g\"):\n                new_cont_lines.append(line.replace(\" g\", \" G\"))\n            elif line.endswith(\" k\"):\n                new_cont_lines.append(line.replace(\" k\", \" K\"))\n            new_cont_lines.append(line)\n        if emc:\n            new_cont_lines.append(emc)\n        new_cont_lines.append(\"Q\\n\")\n        content = \"\\n\".join(new_cont_lines).encode(\"utf-8\")\n        TOOLS._insert_contents(page, content, overlay=overlay)\n        val = None\n        for font in self.used_fonts:\n            repair_mono_font(page, font)\n        %}\n        PyObject *write_text(struct Page *page, PyObject *color=NULL, float opacity=-1, int overlay=1,\n                    PyObject *morph=NULL, PyObject *matrix=NULL, int render_mode=0, int oc=0)\n        {\n            pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) page);\n            pdf_obj *resources = NULL;\n            fz_buffer *contents = NULL;\n            fz_device *dev = NULL;\n            PyObject *result = NULL, *max_nums, *cont_string;\n            float alpha = 1;\n            if (opacity >= 0 && opacity < 1)\n                alpha = opacity;\n            fz_colorspace *colorspace;\n            int ncol = 1;\n            float dev_color[4] = {0, 0, 0, 0};\n            if (EXISTS(color)) {\n                JM_color_FromSequence(color, &ncol, dev_color);\n            }\n            switch(ncol) {\n                case 3: colorspace = fz_device_rgb(gctx); break;\n                case 4: colorspace = fz_device_cmyk(gctx); break;\n                default: colorspace = fz_device_gray(gctx); break;\n            }\n\n            fz_var(contents);\n            fz_var(resources);\n            fz_var(dev);\n            fz_try(gctx) {\n                ASSERT_PDF(pdfpage);\n                resources = pdf_new_dict(gctx, pdfpage->doc, 5);\n                contents = fz_new_buffer(gctx, 1024);\n                dev = pdf_new_pdf_device(gctx, pdfpage->doc, fz_identity,\n                                         resources, contents);\n                fz_fill_text(gctx, dev, (fz_text *) $self, fz_identity,\n                    colorspace, dev_color, alpha, fz_default_color_params);\n                fz_close_device(gctx, dev);\n\n                // copy generated resources into the one of the page\n                max_nums = JM_merge_resources(gctx, pdfpage, resources);\n                cont_string = JM_EscapeStrFromBuffer(gctx, contents);\n                result = Py_BuildValue(\"OO\", max_nums, cont_string);\n                Py_DECREF(cont_string);\n                Py_DECREF(max_nums);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, contents);\n                pdf_drop_obj(gctx, resources);\n                fz_drop_device(gctx, dev);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return result;\n        }\n        %pythoncode %{\n        def __del__(self):\n            if not type(self) is TextWriter:\n                return\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n        %}\n    }\n};\n\n\n//------------------------------------------------------------------------\n// Font\n//------------------------------------------------------------------------\nstruct Font\n{\n    %extend\n    {\n        ~Font()\n        {\n            DEBUGMSG1(\"Font\");\n            fz_font *this_font = (fz_font *) $self;\n            fz_drop_font(gctx, this_font);\n            DEBUGMSG2;\n        }\n\n        FITZEXCEPTION(Font, !result)\n        %pythonprepend Font %{\n        if fontbuffer:\n            if hasattr(fontbuffer, \"getvalue\"):\n                fontbuffer = fontbuffer.getvalue()\n            elif isinstance(fontbuffer, bytearray):\n                fontbuffer = bytes(fontbuffer)\n            if not isinstance(fontbuffer, bytes):\n                raise ValueError(\"bad type: 'fontbuffer'\")\n\n        if isinstance(fontname, str):\n            fname_lower = fontname.lower()\n            if \"/\" in fname_lower or \"\\\\\" in fname_lower or \".\" in fname_lower:\n                print(\"Warning: did you mean a fontfile?\")\n\n            if fname_lower in (\"cjk\", \"china-t\", \"china-ts\"):\n                ordering = 0\n            elif fname_lower.startswith(\"china-s\"):\n                ordering = 1\n            elif fname_lower.startswith(\"korea\"):\n                ordering = 3\n            elif fname_lower.startswith(\"japan\"):\n                ordering = 2\n            elif fname_lower in fitz_fontdescriptors.keys():\n                import pymupdf_fonts  # optional fonts\n                fontbuffer = pymupdf_fonts.myfont(fname_lower)  # make a copy\n                fontname = None  # ensure using fontbuffer only\n                del pymupdf_fonts  # remove package again\n\n            elif ordering < 0:\n                fontname = Base14_fontdict.get(fontname, fontname)\n        %}\n        %pythonappend Font %{self.thisown = True%}\n        Font(char *fontname=NULL, char *fontfile=NULL,\n             PyObject *fontbuffer=NULL, int script=0,\n             char *language=NULL, int ordering=-1, int is_bold=0,\n             int is_italic=0, int is_serif=0, int embed=1)\n        {\n            fz_font *font = NULL;\n            fz_try(gctx) {\n                fz_text_language lang = fz_text_language_from_string(language);\n                font = JM_get_font(gctx, fontname, fontfile,\n                           fontbuffer, script, lang, ordering,\n                           is_bold, is_italic, is_serif, embed);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Font *) font;\n        }\n\n\n        %pythonprepend glyph_advance\n        %{\"\"\"Return the glyph width of a unicode (font size 1).\"\"\"%}\n        PyObject *glyph_advance(int chr, char *language=NULL, int script=0, int wmode=0, int small_caps=0)\n        {\n            fz_font *font, *thisfont = (fz_font *) $self;\n            int gid;\n            fz_text_language lang = fz_text_language_from_string(language);\n            if (small_caps) {\n                gid = fz_encode_character_sc(gctx, thisfont, chr);\n                if (gid >= 0) font = thisfont;\n            } else {\n                gid = fz_encode_character_with_fallback(gctx, thisfont, chr, script, lang, &font);\n            }\n            return PyFloat_FromDouble((double) fz_advance_glyph(gctx, font, gid, wmode));\n        }\n        \n\n        FITZEXCEPTION(text_length, !result)\n        %pythonprepend text_length\n        %{\"\"\"Return length of unicode 'text' under a fontsize.\"\"\"%}\n        PyObject *text_length(PyObject *text, double fontsize=11, char *language=NULL, int script=0, int wmode=0, int small_caps=0)\n        {\n            fz_font *font=NULL, *thisfont = (fz_font *) $self;\n            fz_text_language lang = fz_text_language_from_string(language);\n            double rc = 0;\n            int gid;\n            fz_try(gctx) {\n                if (!PyUnicode_Check(text) || PyUnicode_READY(text) != 0) {\n                    RAISEPY(gctx, MSG_BAD_TEXT, PyExc_TypeError);\n                }\n                Py_ssize_t i, len = PyUnicode_GET_LENGTH(text);\n                int kind = PyUnicode_KIND(text);\n                void *data = PyUnicode_DATA(text);\n                for (i = 0; i < len; i++) {\n                    int c = PyUnicode_READ(kind, data, i);\n                    if (small_caps) {\n                        gid = fz_encode_character_sc(gctx, thisfont, c);\n                        if (gid >= 0) font = thisfont;\n                    } else {\n                        gid = fz_encode_character_with_fallback(gctx,thisfont, c, script, lang, &font);\n                    }\n                    rc += (double) fz_advance_glyph(gctx, font, gid, wmode);\n                }\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                return NULL;\n            }\n            rc *= fontsize;\n            return PyFloat_FromDouble(rc);\n        }\n\n\n        FITZEXCEPTION(char_lengths, !result)\n        %pythonprepend char_lengths\n        %{\"\"\"Return tuple of char lengths of unicode 'text' under a fontsize.\"\"\"%}\n        PyObject *char_lengths(PyObject *text, double fontsize=11, char *language=NULL, int script=0, int wmode=0, int small_caps=0)\n        {\n            fz_font *font, *thisfont = (fz_font *) $self;\n            fz_text_language lang = fz_text_language_from_string(language);\n            PyObject *rc = NULL;\n            int gid;\n            fz_try(gctx) {\n                if (!PyUnicode_Check(text) || PyUnicode_READY(text) != 0) {\n                    RAISEPY(gctx, MSG_BAD_TEXT, PyExc_TypeError);\n                }\n                Py_ssize_t i, len = PyUnicode_GET_LENGTH(text);\n                int kind = PyUnicode_KIND(text);\n                void *data = PyUnicode_DATA(text);\n                rc = PyTuple_New(len);\n                for (i = 0; i < len; i++) {\n                    int c = PyUnicode_READ(kind, data, i);\n                    if (small_caps) {\n                        gid = fz_encode_character_sc(gctx, thisfont, c);\n                        if (gid >= 0) font = thisfont;\n                    } else {\n                        gid = fz_encode_character_with_fallback(gctx,thisfont, c, script, lang, &font);\n                    }\n                    PyTuple_SET_ITEM(rc, i,\n                        PyFloat_FromDouble(fontsize * (double) fz_advance_glyph(gctx, font, gid, wmode)));\n                }\n            }\n            fz_catch(gctx) {\n                PyErr_Clear();\n                Py_CLEAR(rc);\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        %pythonprepend glyph_bbox\n        %{\"\"\"Return the glyph bbox of a unicode (font size 1).\"\"\"%}\n        %pythonappend glyph_bbox %{val = Rect(val)%}\n        PyObject *glyph_bbox(int chr, char *language=NULL, int script=0, int small_caps=0)\n        {\n            fz_font *font, *thisfont = (fz_font *) $self;\n            int gid;\n            fz_text_language lang = fz_text_language_from_string(language);\n            if (small_caps) {\n                gid = fz_encode_character_sc(gctx, thisfont, chr);\n                if (gid >= 0) font = thisfont;\n            } else {\n                gid = fz_encode_character_with_fallback(gctx, thisfont, chr, script, lang, &font);\n            }\n            return JM_py_from_rect(fz_bound_glyph(gctx, font, gid, fz_identity));\n        }\n\n        %pythonprepend has_glyph\n        %{\"\"\"Check whether font has a glyph for this unicode.\"\"\"%}\n        PyObject *has_glyph(int chr, char *language=NULL, int script=0, int fallback=0, int small_caps=0)\n        {\n            fz_font *font, *thisfont = (fz_font *) $self;\n            fz_text_language lang;\n            int gid = 0;\n            if (fallback) {\n                lang = fz_text_language_from_string(language);\n                gid = fz_encode_character_with_fallback(gctx, (fz_font *) $self, chr, script, lang, &font);\n            } else {\n                if (!small_caps) {\n                    gid = fz_encode_character(gctx, thisfont, chr);\n                } else {\n                    gid = fz_encode_character_sc(gctx, thisfont, chr);\n                }\n            }\n            return Py_BuildValue(\"i\", gid);\n        }\n\n\n        %pythoncode %{\n        def valid_codepoints(self):\n            from array import array\n            gc = self.glyph_count\n            cp = array(\"l\", (0,) * gc)\n            arr = cp.buffer_info()\n            self._valid_unicodes(arr)\n            return array(\"l\", sorted(set(cp))[1:])\n        %}\n        void _valid_unicodes(PyObject *arr)\n        {\n            fz_font *font = (fz_font *) $self;\n            PyObject *temp = PySequence_ITEM(arr, 0);\n            void *ptr = PyLong_AsVoidPtr(temp);\n            JM_valid_chars(gctx, font, ptr);\n            Py_DECREF(temp);\n        }\n\n\n        %pythoncode %{@property%}\n        PyObject *flags()\n        {\n            fz_font_flags_t *f = fz_font_flags((fz_font *) $self);\n            if (!f) Py_RETURN_NONE;\n            return Py_BuildValue(\n                \"{s:N,s:N,s:N,s:N,s:N,s:N,s:N,s:N,s:N,s:N,s:N,s:N\"\n                #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n                    \",s:N,s:N\"\n                #endif\n                \"}\",\n                \"mono\", JM_BOOL(f->is_mono),\n                \"serif\", JM_BOOL(f->is_serif),\n                \"bold\", JM_BOOL(f->is_bold),\n                \"italic\", JM_BOOL(f->is_italic),\n                \"substitute\", JM_BOOL(f->ft_substitute),\n                \"stretch\", JM_BOOL(f->ft_stretch),\n                \"fake-bold\", JM_BOOL(f->fake_bold),\n                \"fake-italic\", JM_BOOL(f->fake_italic),\n                \"opentype\", JM_BOOL(f->has_opentype),\n                \"invalid-bbox\", JM_BOOL(f->invalid_bbox),\n                \"cjk\", JM_BOOL(f->cjk),\n                \"cjk-lang\", (f->cjk ? PyLong_FromUnsignedLong((unsigned long) f->cjk_lang) : Py_BuildValue(\"s\",NULL))\n                #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n                ,\n                \"embed\", JM_BOOL(f->embed),\n                \"never-embed\", JM_BOOL(f->never_embed)\n                #endif\n            );\n\n        }\n\n\n        %pythoncode %{@property%}\n        PyObject *is_bold()\n        {\n            fz_font *font = (fz_font *) $self;\n            if (fz_font_is_bold(gctx,font)) {\n                Py_RETURN_TRUE;\n            }\n            Py_RETURN_FALSE;\n        }\n\n\n        %pythoncode %{@property%}\n        PyObject *is_serif()\n        {\n            fz_font *font = (fz_font *) $self;\n            if (fz_font_is_serif(gctx,font)) {\n                Py_RETURN_TRUE;\n            }\n            Py_RETURN_FALSE;\n        }\n\n\n        %pythoncode %{@property%}\n        PyObject *is_italic()\n        {\n            fz_font *font = (fz_font *) $self;\n            if (fz_font_is_italic(gctx,font)) {\n                Py_RETURN_TRUE;\n            }\n            Py_RETURN_FALSE;\n        }\n\n\n        %pythoncode %{@property%}\n        PyObject *is_monospaced()\n        {\n            fz_font *font = (fz_font *) $self;\n            if (fz_font_is_monospaced(gctx,font)) {\n                Py_RETURN_TRUE;\n            }\n            Py_RETURN_FALSE;\n        }\n\n\n        /* temporarily disabled\n        * PyObject *is_writable()\n        * {\n        *     fz_font *font = (fz_font *) $self;\n        *     if (fz_font_t3_procs(gctx, font) ||\n        *         fz_font_flags(font)->ft_substitute ||\n        *         !pdf_font_writing_supported(font)) {\n        *         Py_RETURN_FALSE;\n        *     }\n        *     Py_RETURN_TRUE;\n        * }\n        */\n\n        %pythoncode %{@property%}\n        PyObject *name()\n        {\n            return JM_UnicodeFromStr(fz_font_name(gctx, (fz_font *) $self));\n        }\n\n        %pythoncode %{@property%}\n        int glyph_count()\n        {\n            fz_font *this_font = (fz_font *) $self;\n            return this_font->glyph_count;\n        }\n\n        %pythoncode %{@property%}\n        PyObject *buffer()\n        {\n            fz_font *this_font = (fz_font *) $self;\n            unsigned char *data = NULL;\n            size_t len = fz_buffer_storage(gctx, this_font->buffer, &data);\n            return JM_BinFromCharSize(data, len);\n        }\n\n        %pythoncode %{@property%}\n        %pythonappend bbox%{val = Rect(val)%}\n        PyObject *bbox()\n        {\n            fz_font *this_font = (fz_font *) $self;\n            return JM_py_from_rect(fz_font_bbox(gctx, this_font));\n        }\n\n        %pythoncode %{@property%}\n        %pythonprepend ascender\n        %{\"\"\"Return the glyph ascender value.\"\"\"%}\n        float ascender()\n        {\n            return fz_font_ascender(gctx, (fz_font *) $self);\n        }\n\n\n        %pythoncode %{@property%}\n        %pythonprepend descender\n        %{\"\"\"Return the glyph descender value.\"\"\"%}\n        float descender()\n        {\n            return fz_font_descender(gctx, (fz_font *) $self);\n        }\n\n\n        %pythoncode %{\n\n            @property\n            def is_writable(self):\n                return True\n\n            def glyph_name_to_unicode(self, name):\n                \"\"\"Return the unicode for a glyph name.\"\"\"\n                return glyph_name_to_unicode(name)\n\n            def unicode_to_glyph_name(self, ch):\n                \"\"\"Return the glyph name for a unicode.\"\"\"\n                return unicode_to_glyph_name(ch)\n\n            def __repr__(self):\n                return \"Font('%s')\" % self.name\n\n            def __del__(self):\n                if not type(self) is Font:\n                    return\n                if getattr(self, \"thisown\", False):\n                    self.__swig_destroy__(self)\n        %}\n    }\n};\n\n\n//------------------------------------------------------------------------\n// DocumentWriter\n//------------------------------------------------------------------------\n\nstruct DocumentWriter\n{\n    %extend\n    {\n        ~DocumentWriter()\n        {\n            // need this structure to free any fz_output the writer may have\n            typedef struct { // copied from pdf_write.c\n                fz_document_writer super;\n                pdf_document *pdf;\n                pdf_write_options opts;\n                fz_output *out;\n                fz_rect mediabox;\n                pdf_obj *resources;\n                fz_buffer *contents;\n            } pdf_writer;\n\n            fz_document_writer *writer_fz = (fz_document_writer *) $self;\n            fz_output *out = NULL;\n            pdf_writer *writer_pdf = (pdf_writer *) writer_fz;\n            if (writer_pdf) {\n                out = writer_pdf->out;\n                if (out) {\n                    DEBUGMSG1(\"Output of DocumentWriter\");\n                    fz_drop_output(gctx, out);\n                    writer_pdf->out = NULL;\n                    DEBUGMSG2;\n                }\n            }\n            DEBUGMSG1(\"DocumentWriter\");\n            fz_drop_document_writer( gctx, writer_fz);\n            DEBUGMSG2;\n        }\n        \n        FITZEXCEPTION(DocumentWriter, !result)\n        %pythonprepend DocumentWriter\n        %{\n            if type(path) is str:\n                pass\n            elif hasattr(path, \"absolute\"):\n                path = str(path)\n            elif hasattr(path, \"name\"):\n                path = path.name\n            if options==None:\n                options=\"\"\n        %}\n        %pythonappend DocumentWriter\n        %{\n        %}\n        DocumentWriter( PyObject* path, const char* options=NULL)\n        {\n            fz_output *out = NULL;\n            fz_document_writer* ret=NULL;\n            fz_try(gctx) {\n            if (PyUnicode_Check(path)) {\n                ret = fz_new_pdf_writer( gctx, PyUnicode_AsUTF8(path), options);\n            } else {\n                out = JM_new_output_fileptr(gctx, path);\n                ret = fz_new_pdf_writer_with_output(gctx, out, options);\n            }\n            }\n\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct DocumentWriter*) ret;\n        }\n        \n        struct DeviceWrapper* begin_page( PyObject* mediabox)\n        {\n            fz_rect mediabox2 = JM_rect_from_py(mediabox);\n            fz_device* device = fz_begin_page( gctx, (fz_document_writer*) $self, mediabox2);\n            struct DeviceWrapper* device_wrapper\n                = (struct DeviceWrapper*) calloc(1, sizeof(struct DeviceWrapper))\n                ;\n            device_wrapper->device = device;\n            device_wrapper->list = NULL;\n            return device_wrapper;\n        }\n        \n        void end_page()\n        {\n            fz_end_page( gctx, (fz_document_writer*) $self);\n        }\n        \n        void close()\n        {\n            fz_document_writer *writer = (fz_document_writer*) $self;\n            fz_close_document_writer( gctx, writer);\n        }\n        %pythoncode\n        %{\n            def __del__(self):\n                if not type(self) is DocumentWriter:\n                    return\n                if getattr(self, \"thisown\", False):\n                    self.__swig_destroy__(self)\n\n            def __enter__(self):\n                return self\n\n            def __exit__(self, *args):\n                self.close()\n        %}\n    }\n};\n\n//------------------------------------------------------------------------\n// Archive\n//------------------------------------------------------------------------\nstruct Archive\n{\n    %extend\n    {\n        ~Archive()\n        {\n            DEBUGMSG1(\"Archive\");\n            fz_drop_archive( gctx, (fz_archive *) $self);\n            DEBUGMSG2;\n        }\n        FITZEXCEPTION(Archive, !result)\n        %pythonprepend Archive %{\n        self._subarchives = []\n        %}\n        %pythonappend Archive %{\n        self.thisown = True\n        if args != ():\n            self.add(*args)\n        %}\n\n        //---------------------------------------\n        // new empty archive\n        //---------------------------------------\n        Archive(struct Archive *a0=NULL, const char *path=NULL)\n        {\n            fz_archive *arch=NULL;\n            fz_try(gctx) {\n                arch = fz_new_multi_archive(gctx);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Archive *) arch;\n        }\n\n        Archive(PyObject *a0=NULL, const char *path=NULL)\n        {\n            fz_archive *arch=NULL;\n            fz_try(gctx) {\n                arch = fz_new_multi_archive(gctx);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Archive *) arch;\n        }\n\n        FITZEXCEPTION(has_entry, !result)\n        PyObject *has_entry(const char *name)\n        {\n            fz_archive *arch = (fz_archive *) $self;\n            int ret = 0;\n            fz_try(gctx) {\n                ret = fz_has_archive_entry(gctx, arch, name);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_BOOL(ret);\n        }\n\n        FITZEXCEPTION(read_entry, !result)\n        PyObject *read_entry(const char *name)\n        {\n            fz_archive *arch = (fz_archive *) $self;\n            PyObject *ret = NULL;\n            fz_buffer *buff = NULL;\n            fz_try(gctx) {\n                buff = fz_read_archive_entry(gctx, arch, name);\n                ret = JM_BinFromBuffer(gctx, buff);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buff);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return ret;\n        }\n\n        //--------------------------------------\n        // add dir\n        //--------------------------------------\n        FITZEXCEPTION(_add_dir, !result)\n        PyObject *_add_dir(const char *folder, const char *path=NULL)\n        {\n            fz_archive *arch = (fz_archive *) $self;\n            fz_archive *sub = NULL;\n            fz_try(gctx) {\n                sub = fz_open_directory(gctx, folder);\n                fz_mount_multi_archive(gctx, arch, sub, path);\n            }\n            fz_always(gctx) {\n                fz_drop_archive(gctx, sub);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------\n        // add archive\n        //----------------------------------\n        FITZEXCEPTION(_add_arch, !result)\n        PyObject *_add_arch(struct Archive *subarch, const char *path=NULL)\n        {\n            fz_archive *arch = (fz_archive *) $self;\n            fz_archive *sub = (fz_archive *) subarch;\n            fz_try(gctx) {\n                fz_mount_multi_archive(gctx, arch, sub, path);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------\n        // add ZIP/TAR from file\n        //----------------------------------\n        FITZEXCEPTION(_add_ziptarfile, !result)\n        PyObject *_add_ziptarfile(const char *filepath, int type, const char *path=NULL)\n        {\n            fz_archive *arch = (fz_archive *) $self;\n            fz_archive *sub = NULL;\n            fz_try(gctx) {\n                if (type==1) {\n                    sub = fz_open_zip_archive(gctx, filepath);\n                } else {\n                    sub = fz_open_tar_archive(gctx, filepath);\n                }\n                fz_mount_multi_archive(gctx, arch, sub, path);\n            }\n            fz_always(gctx) {\n                fz_drop_archive(gctx, sub);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------\n        // add ZIP/TAR from memory\n        //----------------------------------\n        FITZEXCEPTION(_add_ziptarmemory, !result)\n        PyObject *_add_ziptarmemory(PyObject *memory, int type, const char *path=NULL)\n        {\n            fz_archive *arch = (fz_archive *) $self;\n            fz_archive *sub = NULL;\n            fz_stream *stream = NULL;\n            fz_buffer *buff = NULL;\n            fz_try(gctx) {\n                buff = JM_BufferFromBytes(gctx, memory);\n                stream = fz_open_buffer(gctx, buff);\n                if (type==1) {\n                    sub = fz_open_zip_archive_with_stream(gctx, stream);\n                } else {\n                    sub = fz_open_tar_archive_with_stream(gctx, stream);\n                }\n                fz_mount_multi_archive(gctx, arch, sub, path);\n            }\n            fz_always(gctx) {\n                fz_drop_stream(gctx, stream);\n                fz_drop_buffer(gctx, buff);\n                fz_drop_archive(gctx, sub);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        //----------------------------------\n        // add \"tree\" item\n        //----------------------------------\n        FITZEXCEPTION(_add_treeitem, !result)\n        PyObject *_add_treeitem(PyObject *memory, const char *name, const char *path=NULL)\n        {\n            fz_archive *arch = (fz_archive *) $self;\n            fz_archive *sub = NULL;\n            fz_buffer *buff = NULL;\n            int drop_sub = 0;\n            fz_try(gctx) {\n                buff = JM_BufferFromBytes(gctx, memory);\n                sub = JM_last_tree(gctx, arch, path);\n                if (!sub) {\n                    sub = fz_new_tree_archive(gctx, NULL);\n                    drop_sub = 1;\n                }\n                fz_tree_archive_add_buffer(gctx, sub, name, buff);\n                if (drop_sub) {\n                    fz_mount_multi_archive(gctx, arch, sub, path);\n                }\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buff);\n                if (drop_sub) {\n                    fz_drop_archive(gctx, sub);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode %{\n        def add(self, content, path=None):\n            \"\"\"Add a sub-archive.\n\n            Args:\n                content: content to be added. May be one of Archive, folder\n                     name, file name, raw bytes (bytes, bytearray), zipfile,\n                     tarfile, or a sequence of any of these types.\n                path: (str) a \"virtual\" path name, under which the elements\n                    of content can be retrieved. Use it to e.g. cope with\n                    duplicate element names.\n            \"\"\"\n            bin_ok = lambda x: isinstance(x, (bytes, bytearray, io.BytesIO))\n\n            entries = []\n            mount = None\n            fmt = None\n\n            def make_subarch():\n                subarch = {\"fmt\": fmt, \"entries\": entries, \"path\": mount}\n                if fmt != \"tree\" or self._subarchives == []:\n                    self._subarchives.append(subarch)\n                else:\n                    ltree = self._subarchives[-1]\n                    if ltree[\"fmt\"] != \"tree\" or ltree[\"path\"] != subarch[\"path\"]:\n                        self._subarchives.append(subarch)\n                    else:\n                        ltree[\"entries\"].extend(subarch[\"entries\"])\n                        self._subarchives[-1] = ltree\n                return\n\n            if isinstance(content, zipfile.ZipFile):\n                fmt = \"zip\"\n                entries = content.namelist()\n                mount = path\n                filename = getattr(content, \"filename\", None)\n                fp = getattr(content, \"fp\", None)\n                if filename:\n                    self._add_ziptarfile(filename, 1, path)\n                else:\n                    self._add_ziptarmemory(fp.getvalue(), 1, path)\n                return make_subarch()\n            \n            if isinstance(content, tarfile.TarFile):\n                fmt = \"tar\"\n                entries = content.getnames()\n                mount = path\n                filename = getattr(content.fileobj, \"name\", None)\n                fp = content.fileobj\n                if not isinstance(fp, io.BytesIO) and not filename:\n                    fp = fp.fileobj\n                if filename:\n                    self._add_ziptarfile(filename, 0, path)\n                else:\n                    self._add_ziptarmemory(fp.getvalue(), 0, path)\n                return make_subarch()\n\n            if isinstance(content, Archive):\n                fmt = \"multi\"\n                mount = path\n                self._add_arch(content, path)\n                return make_subarch()\n\n            if bin_ok(content):\n                if not (path and type(path) is str):\n                    raise ValueError(\"need name for binary content\")\n                fmt = \"tree\"\n                mount = None\n                entries = [path]\n                self._add_treeitem(content, path)\n                return make_subarch()\n\n            if hasattr(content, \"name\"):\n                content = content.name\n            elif isinstance(content, pathlib.Path):\n                content = str(content)\n            \n            if os.path.isdir(str(content)):\n                a0 = str(content)\n                fmt = \"dir\"\n                mount = path\n                entries = os.listdir(a0)\n                self._add_dir(a0, path)\n                return make_subarch()\n            \n            if os.path.isfile(str(content)):\n                if not (path and type(path) is str):\n                    raise ValueError(\"need name for binary content\")\n                a0 = str(content)\n                _ = open(a0, \"rb\")\n                ff = _.read()\n                _.close()\n                fmt = \"tree\"\n                mount = None\n                entries = [path]\n                self._add_treeitem(ff, path)\n                return make_subarch()\n            \n            if type(content) is str or not getattr(content, \"__getitem__\", None):\n                raise ValueError(\"bad archive content\")\n\n            #----------------------------------------\n            # handling sequence types here\n            #----------------------------------------\n\n            if len(content) == 2: # covers the tree item plus path\n                data, name = content\n                if bin_ok(data) or os.path.isfile(str(data)):\n                    if not type(name) is str:\n                        raise ValueError(f\"bad item name {name}\")\n                    mount = path\n                    fmt = \"tree\"\n                    if bin_ok(data):\n                        self._add_treeitem(data, name, path=mount)\n                    else:\n                        _ = open(str(data), \"rb\")\n                        ff = _.read()\n                        _.close()\n                        seld._add_treeitem(ff, name, path=mount)\n                    entries = [name]\n                    return make_subarch()\n\n            # deal with sequence of disparate items\n            for item in content:\n                self.add(item, path)\n\n        __doc__ = \"\"\"Archive(dirname [, path]) - from folder\n        Archive(file [, path]) - from file name or object\n        Archive(data, name) - from memory item\n        Archive() - empty archive\n        Archive(archive [, path]) - from archive\n        \"\"\"\n\n        @property\n        def entry_list(self):\n            \"\"\"List of sub archives.\"\"\"\n            return self._subarchives\n\n        def __repr__(self):\n            return f\"Archive, sub-archives: {len(self._subarchives)}\"\n\n        def __del__(self):\n            if not type(self) is Archive:\n                return\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n        %}\n    }\n};\n//------------------------------------------------------------------------\n// Xml\n//------------------------------------------------------------------------\nstruct Xml\n{\n    %extend\n    {\n        ~Xml()\n        {\n            DEBUGMSG1(\"Xml\");\n            fz_drop_xml( gctx, (fz_xml*) $self);\n            DEBUGMSG2;\n        }\n        \n        FITZEXCEPTION(Xml, !result)\n        Xml(fz_xml* xml)\n        {\n            fz_keep_xml( gctx, xml);\n            return (struct Xml*) xml;\n        }\n\n        Xml(const char *html)\n        {\n            fz_buffer *buff = NULL;\n            fz_xml *ret = NULL;\n            fz_try(gctx) {\n                buff = fz_new_buffer_from_copied_data(gctx, html, strlen(html)+1);\n                ret = fz_parse_xml_from_html5(gctx, buff);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, buff);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            fz_keep_xml(gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        %pythoncode %{@property%}\n        FITZEXCEPTION (root, !result)\n        struct Xml* root()\n        {\n            fz_xml* ret = NULL;\n            fz_try(gctx) {\n                ret = fz_xml_root((fz_xml_doc *) $self);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Xml*) ret;\n        }\n\n        FITZEXCEPTION (bodytag, !result)\n        struct Xml* bodytag()\n        {\n            fz_xml* ret = NULL;\n            fz_try(gctx) {\n                ret = fz_keep_xml( gctx, fz_dom_body( gctx, (fz_xml *) $self));\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return (struct Xml*) ret;\n        }\n\n        FITZEXCEPTION (append_child, !result)\n        PyObject *append_child( struct Xml* child)\n        {\n            fz_try(gctx) {\n                fz_dom_append_child( gctx, (fz_xml *) $self, (fz_xml *) child);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION (create_text_node, !result)\n        struct Xml* create_text_node( const char *text)\n        {\n            fz_xml* ret = NULL;\n            fz_try(gctx) {\n                ret = fz_dom_create_text_node( gctx,(fz_xml *) $self, text);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        FITZEXCEPTION (create_element, !result)\n        struct Xml* create_element( const char *tag)\n        {\n            fz_xml* ret = NULL;\n            fz_try(gctx) {\n                ret = fz_dom_create_element( gctx, (fz_xml *)$self, tag);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        struct Xml *find(const char *tag, const char *att, const char *match)\n        {\n            fz_xml* ret=NULL;\n            ret = fz_dom_find( gctx, (fz_xml *)$self, tag, att, match);\n            if (!ret) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        struct Xml *find_next( const char *tag, const char *att, const char *match)\n        {\n            fz_xml* ret=NULL;\n            ret = fz_dom_find_next( gctx, (fz_xml *)$self, tag, att, match);\n            if (!ret) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        %pythoncode %{@property%}\n        struct Xml *next()\n        {\n            fz_xml* ret=NULL;\n            ret = fz_dom_next( gctx, (fz_xml *)$self);\n            if (!ret) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        %pythoncode %{@property%}\n        struct Xml *previous()\n        {\n            fz_xml* ret=NULL;\n            ret = fz_dom_previous( gctx, (fz_xml *)$self);\n            if (!ret) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        FITZEXCEPTION (set_attribute, !result)\n        PyObject *set_attribute(const char *key, const char *value)\n        {\n            fz_try(gctx) {\n                if (strlen(key)==0) {\n                    RAISEPY(gctx, \"key must not be empty\", PyExc_ValueError);\n                }\n                fz_dom_add_attribute(gctx, (fz_xml *)$self, key, value);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION (remove_attribute, !result)\n        PyObject *remove_attribute(const char *key)\n        {\n            fz_try(gctx) {\n                if (strlen(key)==0) {\n                    RAISEPY(gctx, \"key must not be empty\", PyExc_ValueError);\n                }\n                fz_xml *elt = (fz_xml *)$self;\n                fz_dom_remove_attribute(gctx, elt, key);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION (get_attribute_value, !result)\n        PyObject *get_attribute_value(const char *key)\n        {\n            const char *ret=NULL;\n            fz_try(gctx) {\n                if (strlen(key)==0) {\n                    RAISEPY(gctx, \"key must not be empty\", PyExc_ValueError);\n                }\n                fz_xml *elt = (fz_xml *)$self;\n                ret=fz_dom_attribute(gctx, elt, key);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"s\", ret);\n        }\n\n\n        FITZEXCEPTION (get_attributes, !result)\n        PyObject *get_attributes()\n        {\n            fz_xml *this = (fz_xml *) $self;\n            if (fz_xml_text(this)) { // text node has none\n                Py_RETURN_NONE;\n            }\n            PyObject *result=PyDict_New();\n            fz_try(gctx) {\n                int i=0;\n                const char *key=NULL;\n                const char *val=NULL;\n                while (1) {\n                    val = fz_dom_get_attribute(gctx, this, i, &key);\n                    if (!val || !key) {\n                        break;\n                    }\n                    PyObject *temp = Py_BuildValue(\"s\",val);\n                    PyDict_SetItemString(result, key, temp);\n                    Py_DECREF(temp);\n                    i += 1;\n                }\n            }\n            fz_catch(gctx) {\n                Py_DECREF(result);\n                return NULL;\n            }\n            return result;\n        }\n\n\n        FITZEXCEPTION (insert_before, !result)\n        PyObject *insert_before(struct Xml *node)\n        {\n            fz_xml *existing = (fz_xml *) $self;\n            fz_xml *what = (fz_xml *) node;\n            fz_try(gctx)\n            {\n                fz_dom_insert_before(gctx, existing, what);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION (insert_after, !result)\n        PyObject *insert_after(struct Xml *node)\n        {\n            fz_xml *existing = (fz_xml *) $self;\n            fz_xml *what = (fz_xml *) node;\n            fz_try(gctx)\n            {\n                fz_dom_insert_after(gctx, existing, what);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION (clone, !result)\n        struct Xml* clone()\n        {\n            fz_xml* ret = NULL;\n            fz_try(gctx) {\n                ret = fz_dom_clone( gctx, (fz_xml *)$self);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        %pythoncode %{@property%}\n        struct Xml *parent()\n        {\n            fz_xml* ret = NULL;\n            ret = fz_dom_parent( gctx, (fz_xml *)$self);\n            if (!ret) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n        %pythoncode %{@property%}\n        struct Xml *first_child()\n        {\n            fz_xml* ret = NULL;\n            fz_xml *this = (fz_xml *)$self;\n            if (fz_xml_text(this)) { // a text node has no child\n                return NULL;\n            }\n            ret = fz_dom_first_child( gctx, (fz_xml *)$self);\n            if (!ret) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, ret);\n            return (struct Xml*) ret;\n        }\n\n\n        FITZEXCEPTION (remove, !result)\n        PyObject *remove()\n        {\n            fz_try(gctx) {\n                fz_dom_remove( gctx, (fz_xml *)$self);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode %{@property%}\n        PyObject *text()\n        {\n            return Py_BuildValue(\"s\", fz_xml_text((fz_xml *)$self));\n        }\n\n        %pythoncode %{@property%}\n        PyObject *tagname()\n        {\n            return Py_BuildValue(\"s\", fz_xml_tag((fz_xml *)$self));\n        }\n\n\n        %pythoncode %{\n        def _get_node_tree(self):\n            def show_node(node, items, shift):\n                while node != None:\n                    if node.is_text:\n                        items.append((shift, f'\"{node.text}\"'))\n                        node = node.next\n                        continue\n                    items.append((shift, f\"({node.tagname}\"))\n                    for k, v in node.get_attributes().items():\n                        items.append((shift, f\"={k} '{v}'\"))\n                    child = node.first_child\n                    if child:\n                        items = show_node(child, items, shift + 1)\n                    items.append((shift, f\"){node.tagname}\"))\n                    node = node.next\n                return items\n\n            shift = 0\n            items = []\n            items = show_node(self, items, shift)\n            return items\n\n        def debug(self):\n            \"\"\"Print a list of the node tree below self.\"\"\"\n            items = self._get_node_tree()\n            for item in items:\n                print(\"  \" * item[0] + item[1].replace(\"\\n\", \"\\\\n\"))\n\n        @property\n        def is_text(self):\n            \"\"\"Check if this is a text node.\"\"\"\n            return self.text != None\n\n        @property\n        def last_child(self):\n            \"\"\"Return last child node.\"\"\"\n            child = self.first_child\n            if child==None:\n                return None\n            while True:\n                if child.next == None:\n                    return child\n                child = child.next\n\n        @staticmethod\n        def color_text(color):\n            if type(color) is str:\n                return color\n            if type(color) is int:\n                return f\"rgb({sRGB_to_rgb(color)})\"\n            if type(color) in (tuple, list):\n                return f\"rgb{tuple(color)}\"\n            return color\n\n        def add_number_list(self, start=1, numtype=None):\n            \"\"\"Add numbered list (\"ol\" tag)\"\"\"\n            child = self.create_element(\"ol\")\n            if start > 1:\n                child.set_attribute(\"start\", str(start))\n            if numtype != None:\n                child.set_attribute(\"type\", numtype)\n            self.append_child(child)\n            return child\n\n        def add_description_list(self):\n            \"\"\"Add description list (\"dl\" tag)\"\"\"\n            child = self.create_element(\"dl\")\n            self.append_child(child)\n            return child\n\n        def add_image(self, name, width=None, height=None, imgfloat=None, align=None):\n            \"\"\"Add image node (tag \"img\").\"\"\"\n            child = self.create_element(\"img\")\n            if width != None:\n                child.set_attribute(\"width\", f\"{width}\")\n            if height != None:\n                child.set_attribute(\"height\", f\"{height}\")\n            if imgfloat != None:\n                child.set_attribute(\"style\", f\"float: {imgfloat}\")\n            if align != None:\n                child.set_attribute(\"align\", f\"{align}\")\n            child.set_attribute(\"src\", f\"{name}\")\n            self.append_child(child)\n            return child\n\n        def add_bullet_list(self):\n            \"\"\"Add bulleted list (\"ul\" tag)\"\"\"\n            child = self.create_element(\"ul\")\n            self.append_child(child)\n            return child\n\n        def add_list_item(self):\n            \"\"\"Add item (\"li\" tag) under a (numbered or bulleted) list.\"\"\"\n            if self.tagname not in (\"ol\", \"ul\"):\n                raise ValueError(\"cannot add list item to\", self.tagname)\n            child = self.create_element(\"li\")\n            self.append_child(child)\n            return child\n\n        def add_span(self):\n            child = self.create_element(\"span\")\n            self.append_child(child)\n            return child\n\n        def add_paragraph(self):\n            \"\"\"Add \"p\" tag\"\"\"\n            child = self.create_element(\"p\")\n            if self.tagname != \"p\":\n                self.append_child(child)\n            else:\n                self.parent.append_child(child)\n            return child\n\n        def add_header(self, level=1):\n            \"\"\"Add header tag\"\"\"\n            if level not in range(1, 7):\n                raise ValueError(\"Header level must be in [1, 6]\")\n            this_tag = self.tagname\n            new_tag = f\"h{level}\"\n            child = self.create_element(new_tag)\n            prev = self\n            if this_tag not in (\"h1\", \"h2\", \"h3\", \"h4\", \"h5\", \"h6\", \"p\"):\n                self.append_child(child)\n                return child\n            self.parent.append_child(child)\n            return child\n\n        def add_division(self):\n            \"\"\"Add \"div\" tag\"\"\"\n            child = self.create_element(\"div\")\n            self.append_child(child)\n            return child\n\n        def add_horizontal_line(self):\n            \"\"\"Add horizontal line (\"hr\" tag)\"\"\"\n            child = self.create_element(\"hr\")\n            self.append_child(child)\n            return child\n\n        def add_link(self, href, text=None):\n            \"\"\"Add a hyperlink (\"a\" tag)\"\"\"\n            child = self.create_element(\"a\")\n            if not isinstance(text, str):\n                text = href\n            child.set_attribute(\"href\", href)\n            child.append_child(self.create_text_node(text)) \n            prev = self.span_bottom()\n            if prev == None:\n                prev = self\n            prev.append_child(child)\n            return self\n\n        def add_code(self, text=None):\n            \"\"\"Add a \"code\" tag\"\"\"\n            child = self.create_element(\"code\")\n            if type(text) is str:\n               child.append_child(self.create_text_node(text)) \n            prev = self.span_bottom()\n            if prev == None:\n                prev = self\n            prev.append_child(child)\n            return self\n\n        add_var = add_code\n        add_samp = add_code\n        add_kbd = add_code\n\n        def add_superscript(self, text=None):\n            \"\"\"Add a superscript (\"sup\" tag)\"\"\"\n            child = self.create_element(\"sup\")\n            if type(text) is str:\n               child.append_child(self.create_text_node(text)) \n            prev = self.span_bottom()\n            if prev == None:\n                prev = self\n            prev.append_child(child)\n            return self\n\n        def add_subscript(self, text=None):\n            \"\"\"Add a subscript (\"sub\" tag)\"\"\"\n            child = self.create_element(\"sub\")\n            if type(text) is str:\n               child.append_child(self.create_text_node(text)) \n            prev = self.span_bottom()\n            if prev == None:\n                prev = self\n            prev.append_child(child)\n            return self\n\n        def add_codeblock(self):\n            \"\"\"Add monospaced lines (\"pre\" node)\"\"\"\n            child = self.create_element(\"pre\")\n            self.append_child(child)\n            return child\n\n        def span_bottom(self):\n            \"\"\"Find deepest level in stacked spans.\"\"\"\n            parent = self\n            child = self.last_child\n            if child == None:\n                return None\n            while child.is_text:\n                child = child.previous\n                if child == None:\n                    break\n            if child == None or child.tagname != \"span\":\n                return None\n\n            while True:\n                if child == None:\n                    return parent\n                if child.tagname in (\"a\", \"sub\",\"sup\",\"body\") or child.is_text:\n                    child = child.next\n                    continue\n                if child.tagname == \"span\":\n                    parent = child\n                    child = child.first_child\n                else:\n                    return parent\n\n        def append_styled_span(self, style):\n            span = self.create_element(\"span\")\n            span.add_style(style)\n            prev = self.span_bottom()\n            if prev == None:\n                prev = self\n            prev.append_child(span)\n            return prev\n\n        def set_margins(self, val):\n            \"\"\"Set margin values via CSS style\"\"\"\n            text = \"margins: %s\" % val\n            self.append_styled_span(text)\n            return self\n\n        def set_font(self, font):\n            \"\"\"Set font-family name via CSS style\"\"\"\n            text = \"font-family: %s\" % font\n            self.append_styled_span(text)\n            return self\n\n        def set_color(self, color):\n            \"\"\"Set text color via CSS style\"\"\"\n            text = f\"color: %s\" % self.color_text(color)\n            self.append_styled_span(text)\n            return self\n\n        def set_columns(self, cols):\n            \"\"\"Set number of text columns via CSS style\"\"\"\n            text = f\"columns: {cols}\"\n            self.append_styled_span(text)\n            return self\n\n        def set_bgcolor(self, color):\n            \"\"\"Set background color via CSS style\"\"\"\n            text = f\"background-color: %s\" % self.color_text(color)\n            self.add_style(text)  # does not work on span level\n            return self\n\n        def set_opacity(self, opacity):\n            \"\"\"Set opacity via CSS style\"\"\"\n            text = f\"opacity: {opacity}\"\n            self.append_styled_span(text)\n            return self\n\n        def set_align(self, align):\n            \"\"\"Set text alignment via CSS style\"\"\"\n            text = \"text-align: %s\"\n            if isinstance( align, str):\n                t = align\n            elif align == TEXT_ALIGN_LEFT:\n                t = \"left\"\n            elif align == TEXT_ALIGN_CENTER:\n                t = \"center\"\n            elif align == TEXT_ALIGN_RIGHT:\n                t = \"right\"\n            elif align == TEXT_ALIGN_JUSTIFY:\n                t = \"justify\"\n            else:\n                raise ValueError(f\"Unrecognised align={align}\")\n            text = text % t\n            self.add_style(text)\n            return self\n\n        def set_underline(self, val=\"underline\"):\n            text = \"text-decoration: %s\" % val\n            self.append_styled_span(text)\n            return self\n\n        def set_pagebreak_before(self):\n            \"\"\"Insert a page break before this node.\"\"\"\n            text = \"page-break-before: always\"\n            self.add_style(text)\n            return self\n\n        def set_pagebreak_after(self):\n            \"\"\"Insert a page break after this node.\"\"\"\n            text = \"page-break-after: always\"\n            self.add_style(text)\n            return self\n\n        def set_fontsize(self, fontsize):\n            \"\"\"Set font size name via CSS style\"\"\"\n            if type(fontsize) is str:\n                px=\"\"\n            else:\n                px=\"px\"\n            text = f\"font-size: {fontsize}{px}\"\n            self.append_styled_span(text)\n            return self\n\n        def set_lineheight(self, lineheight):\n            \"\"\"Set line height name via CSS style - block-level only.\"\"\"\n            text = f\"line-height: {lineheight}\"\n            self.add_style(text)\n            return self\n\n        def set_leading(self, leading):\n            \"\"\"Set inter-line spacing value via CSS style - block-level only.\"\"\"\n            text = f\"-mupdf-leading: {leading}\"\n            self.add_style(text)\n            return self\n\n        def set_word_spacing(self, spacing):\n            \"\"\"Set inter-word spacing value via CSS style\"\"\"\n            text = f\"word-spacing: {spacing}\"\n            self.append_styled_span(text)\n            return self\n\n        def set_letter_spacing(self, spacing):\n            \"\"\"Set inter-letter spacing value via CSS style\"\"\"\n            text = f\"letter-spacing: {spacing}\"\n            self.append_styled_span(text)\n            return self\n\n        def set_text_indent(self, indent):\n            \"\"\"Set text indentation name via CSS style - block-level only.\"\"\"\n            text = f\"text-indent: {indent}\"\n            self.add_style(text)\n            return self\n\n        def set_bold(self, val=True):\n            \"\"\"Set bold on / off via CSS style\"\"\"\n            if val:\n                val=\"bold\"\n            else:\n                val=\"normal\"\n            text = \"font-weight: %s\" % val\n            self.append_styled_span(text)\n            return self\n\n        def set_italic(self, val=True):\n            \"\"\"Set italic on / off via CSS style\"\"\"\n            if val:\n                val=\"italic\"\n            else:\n                val=\"normal\"\n            text = \"font-style: %s\" % val\n            self.append_styled_span(text)\n            return self\n\n        def set_properties(\n            self,\n            align=None,\n            bgcolor=None,\n            bold=None,\n            color=None,\n            columns=None,\n            font=None,\n            fontsize=None,\n            indent=None,\n            italic=None,\n            leading=None,\n            letter_spacing=None,\n            lineheight=None,\n            margins=None,\n            pagebreak_after=None,\n            pagebreak_before=None,\n            word_spacing=None,\n            unqid=None,\n            cls=None,\n        ):\n            \"\"\"Set any or all properties of a node.\n            \n            To be used for existing nodes preferrably.\n            \"\"\"\n            root = self.root\n            temp = root.add_division()\n            if align is not None:\n                temp.set_align(align)\n            if bgcolor is not None:\n                temp.set_bgcolor(bgcolor)\n            if bold is not None:\n                temp.set_bold(bold)\n            if color is not None:\n                temp.set_color(color)\n            if columns is not None:\n                temp.set_columns(columns)\n            if font is not None:\n                temp.set_font(font)\n            if fontsize is not None:\n                temp.set_fontsize(fontsize)\n            if indent is not None:\n                temp.set_text_indent(indent)\n            if italic is not None:\n                temp.set_italic(italic)\n            if leading is not None:\n                temp.set_leading(leading)\n            if letter_spacing is not None:\n                temp.set_letter_spacing(letter_spacing)\n            if lineheight is not None:\n                temp.set_lineheight(lineheight)\n            if margins is not None:\n                temp.set_margins(margins)\n            if pagebreak_after is not None:\n                temp.set_pagebreak_after()\n            if pagebreak_before is not None:\n                temp.set_pagebreak_before()\n            if word_spacing is not None:\n                temp.set_word_spacing(word_spacing)\n            if unqid is not None:\n                self.set_id(unqid)\n            if cls is not None:\n                self.add_class(cls)\n\n            styles = []\n            top_style = temp.get_attribute_value(\"style\")\n            if top_style is not None:\n                styles.append(top_style)\n            child = temp.first_child\n            while child:\n                styles.append(child.get_attribute_value(\"style\"))\n                child = child.first_child\n            self.set_attribute(\"style\", \";\".join(styles))\n            temp.remove()\n            return self\n\n        def set_id(self, unique):\n            \"\"\"Set a unique id.\"\"\"\n            # check uniqueness\n            tagname = self.tagname\n            root = self.root\n            if root.find(None, \"id\", unique):\n                raise ValueError(f\"id '{unique}' already exists\")\n            self.set_attribute(\"id\", unique)\n            return self\n\n        def add_text(self, text):\n            \"\"\"Add text. Line breaks are honored.\"\"\"\n            lines = text.splitlines()\n            line_count = len(lines)\n            prev = self.span_bottom()\n            if prev == None:\n                prev = self\n\n            for i, line in enumerate(lines):\n                prev.append_child(self.create_text_node(line))\n                if i < line_count - 1:\n                    prev.append_child(self.create_element(\"br\"))\n            return self\n\n        def add_style(self, text):\n            \"\"\"Set some style via CSS style. Replaces complete style spec.\"\"\"\n            style = self.get_attribute_value(\"style\")\n            if style != None and text in style:\n                return self\n            self.remove_attribute(\"style\")\n            if style == None:\n                style = text\n            else:\n                style += \";\" + text\n            self.set_attribute(\"style\", style)\n            return self\n\n        def add_class(self, text):\n            \"\"\"Set some class via CSS. Replaces complete class spec.\"\"\"\n            cls = self.get_attribute_value(\"class\")\n            if cls != None and text in cls:\n                return self\n            self.remove_attribute(\"class\")\n            if cls == None:\n                cls = text\n            else:\n                cls += \" \" + text\n            self.set_attribute(\"class\", cls)\n            return self\n\n        def insert_text(self, text):\n            lines = text.splitlines()\n            line_count = len(lines)\n            for i, line in enumerate(lines):\n                self.append_child(self.create_text_node(line))\n                if i < line_count - 1:\n                    self.append_child(self.create_element(\"br\"))\n            return self\n\n        def __enter__(self):\n            return self\n\n        def __exit__(self, *args):\n            pass\n\n        def __del__(self):\n            if not type(self) is Xml:\n                return\n            if getattr(self, \"thisown\", False):\n                self.__swig_destroy__(self)\n        %}\n    }\n};\n\n//------------------------------------------------------------------------\n// Story\n//------------------------------------------------------------------------\nstruct Story\n{\n    %extend\n    {\n        ~Story()\n        {\n            DEBUGMSG1(\"Story\");\n            fz_story *this_story = (fz_story *) $self;\n            fz_drop_story(gctx, this_story);\n            DEBUGMSG2;\n        }\n\n        FITZEXCEPTION(Story, !result)\n        %pythonprepend Story %{\n        if archive != None and isinstance(archive, Archive) == False:\n            archive = Archive(archive)\n        %}\n        Story(const char* html=NULL, const char *user_css=NULL, double em=12, struct Archive *archive=NULL)\n        {\n            fz_story* story = NULL;\n            fz_buffer *buffer = NULL;\n            fz_archive* arch = NULL;\n            fz_var(story);\n            fz_var(buffer);\n            const char *html2=\"\";\n            if (html) {\n                html2=html;\n            }\n\n            fz_try(gctx)\n            {\n                buffer = fz_new_buffer_from_copied_data(gctx, html2, strlen(html2)+1);\n                if (archive) {\n                    arch = (fz_archive *) archive;\n                }\n                story = fz_new_story(gctx, buffer, user_css, em, arch);\n            }\n            fz_always(gctx)\n            {\n                fz_drop_buffer(gctx, buffer);\n            }\n            fz_catch(gctx)\n            {\n                return NULL;\n            }\n            struct Story* ret = (struct Story *) story;\n            return ret;\n        }\n        \n        FITZEXCEPTION(reset, !result)\n        PyObject* reset()\n        {\n            fz_try(gctx)\n            {\n                fz_reset_story(gctx, (fz_story *)$self);\n            }\n            fz_catch(gctx)\n            {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n        \n        FITZEXCEPTION(place, !result)\n        PyObject* place( PyObject* where)\n        {\n            PyObject* ret = NULL;\n            fz_try(gctx)\n            {\n                fz_rect where2 = JM_rect_from_py(where);\n                fz_rect filled;\n                int more = fz_place_story( gctx, (fz_story*) $self, where2, &filled);\n                ret = PyTuple_New(2);\n                PyTuple_SET_ITEM( ret, 0, Py_BuildValue( \"i\", more));\n                PyTuple_SET_ITEM( ret, 1, JM_py_from_rect( filled));\n            }\n            fz_catch(gctx)\n            {\n                return NULL;\n            }\n            return ret;\n        }\n\n        FITZEXCEPTION(draw, !result)\n        PyObject* draw( struct DeviceWrapper* device, PyObject* matrix=NULL)\n        {\n            fz_try(gctx)\n            {\n                fz_matrix ctm2 = JM_matrix_from_py( matrix);\n                fz_device *dev = (device) ? device->device : NULL;\n                fz_draw_story( gctx, (fz_story*) $self, dev, ctm2);\n            }\n            fz_catch(gctx)\n            {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        FITZEXCEPTION(document, !result)\n        struct Xml* document()\n        {\n            fz_xml* dom=NULL;\n            fz_try(gctx) {\n                dom = fz_story_document( gctx, (fz_story*) $self);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            fz_keep_xml( gctx, dom);\n            return (struct Xml*) dom;\n        }\n\n        FITZEXCEPTION(element_positions, !result)\n        %pythonprepend element_positions %{\n        \"\"\"Trigger a callback function to record where items have been placed.\n        \n        Args:\n            function: a function accepting exactly one argument.\n            args: an optional dictionary for passing additional data.\n        \"\"\"\n        if type(args) is dict:\n            for k in args.keys():\n                if not (type(k) is str and k.isidentifier()):\n                    raise ValueError(f\"invalid key '{k}'\")\n        else:\n            args = {}\n        if not callable(function) or function.__code__.co_argcount != 1:\n            raise ValueError(\"callback 'function' must be a callable with exactly one argument\")\n        %}\n        PyObject* element_positions(PyObject *function, PyObject *args)\n        {\n            PyObject *callarg=NULL;\n            fz_try(gctx) {\n                callarg = Py_BuildValue(\"OO\", function, args);\n                fz_story_positions(gctx, (fz_story *) $self, Story_Callback, callarg);\n            }\n            fz_always(gctx) {\n                Py_CLEAR(callarg);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        %pythoncode\n        %{\n            def write(self, writer, rectfn, positionfn=None, pagefn=None):\n                dev = None\n                page_num = 0\n                rect_num = 0\n                filled = Rect(0, 0, 0, 0)\n                while 1:\n                    mediabox, rect, ctm = rectfn(rect_num, filled)\n                    rect_num += 1\n                    if mediabox:\n                        # new page.\n                        page_num += 1\n                    more, filled = self.place( rect)\n                    #print(f\"write(): positionfn={positionfn}\")\n                    if positionfn:\n                        def positionfn2(position):\n                            # We add a `.page_num` member to the\n                            # `ElementPosition` instance.\n                            position.page_num = page_num\n                            #print(f\"write(): position={position}\")\n                            positionfn(position)\n                        self.element_positions(positionfn2, {})\n                    if writer:\n                        if mediabox:\n                            # new page.\n                            if dev:\n                                if pagefn:\n                                    pagefn(page_num, medibox, dev, 1)\n                                writer.end_page()\n                            dev = writer.begin_page( mediabox)\n                            if pagefn:\n                                pagefn(page_num, mediabox, dev, 0)\n                        self.draw( dev, ctm)\n                        if not more:\n                            if pagefn:\n                                pagefn( page_num, mediabox, dev, 1)\n                            writer.end_page()\n                    else:\n                        self.draw(None, ctm)\n                    if not more:\n                        break\n\n            @staticmethod\n            def write_stabilized(writer, contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True):\n                positions = list()\n                content = None\n                # Iterate until stable.\n                while 1:\n                    content_prev = content\n                    content = contentfn( positions)\n                    stable = False\n                    if content == content_prev:\n                        stable = True\n                    content2 = content\n                    story = Story(content2, user_css, em, archive)\n\n                    if add_header_ids:\n                        story.add_header_ids()\n\n                    positions = list()\n                    def positionfn2(position):\n                        #print(f\"write_stabilized(): stable={stable} positionfn={positionfn} position={position}\")\n                        positions.append(position)\n                        if stable and positionfn:\n                            positionfn(position)\n                    story.write(\n                            writer if stable else None,\n                            rectfn,\n                            positionfn2,\n                            pagefn,\n                            )\n                    if stable:\n                        break\n\n            def add_header_ids(self):\n                '''\n                Look for `<h1..6>` items in `self` and adds unique `id`\n                attributes if not already present.\n                '''\n                dom = self.body\n                i = 0\n                x = dom.find(None, None, None)\n                while x:\n                    name = x.tagname\n                    if len(name) == 2 and name[0]==\"h\" and name[1] in \"123456\":\n                        attr = x.get_attribute_value(\"id\")\n                        if not attr:\n                            id_ = f\"h_id_{i}\"\n                            #print(f\"name={name}: setting id={id_}\")\n                            x.set_attribute(\"id\", id_)\n                            i += 1\n                    x = x.find_next(None, None, None)\n\n            def write_with_links(self, rectfn, positionfn=None, pagefn=None):\n                #print(\"write_with_links()\")\n                stream = io.BytesIO()\n                writer = DocumentWriter(stream)\n                positions = []\n                def positionfn2(position):\n                    #print(f\"write_with_links(): position={position}\")\n                    positions.append(position)\n                    if positionfn:\n                        positionfn(position)\n                self.write(writer, rectfn, positionfn=positionfn2, pagefn=pagefn)\n                writer.close()\n                stream.seek(0)\n                return Story.add_pdf_links(stream, positions)\n\n            @staticmethod\n            def write_stabilized_with_links(contentfn, rectfn, user_css=None, em=12, positionfn=None, pagefn=None, archive=None, add_header_ids=True):\n                #print(\"write_stabilized_with_links()\")\n                stream = io.BytesIO()\n                writer = DocumentWriter(stream)\n                positions = []\n                def positionfn2(position):\n                    #print(f\"write_stabilized_with_links(): position={position}\")\n                    positions.append(position)\n                    if positionfn:\n                        positionfn(position)\n                Story.write_stabilized(writer, contentfn, rectfn, user_css, em, positionfn2, pagefn, archive, add_header_ids)\n                writer.close()\n                stream.seek(0)\n                return Story.add_pdf_links(stream, positions)\n\n            @staticmethod\n            def add_pdf_links(document_or_stream, positions):\n                \"\"\"\n                Adds links to PDF document.\n                Args:\n                    document_or_stream:\n                        A PDF `Document` or raw PDF content, for example an\n                        `io.BytesIO` instance.\n                    positions:\n                        List of `ElementPosition`'s for `document_or_stream`,\n                        typically from Story.element_positions(). We raise an\n                        exception if two or more positions have same id.\n                Returns:\n                    `document_or_stream` if a `Document` instance, otherwise a\n                    new `Document` instance.\n                We raise an exception if an `href` in `positions` refers to an\n                internal position `#<name>` but no item in `postions` has `id =\n                name`.\n                \"\"\"\n                if isinstance(document_or_stream, Document):\n                    document = document_or_stream\n                else:\n                    document = Document(\"pdf\", document_or_stream)\n\n                # Create dict from id to position, which we will use to find\n                # link destinations.\n                #\n                id_to_position = dict()\n                #print(f\"positions: {positions}\")\n                for position in positions:\n                    #print(f\"add_pdf_links(): position: {position}\")\n                    if (position.open_close & 1) and position.id:\n                        #print(f\"add_pdf_links(): position with id: {position}\")\n                        if position.id in id_to_position:\n                            #print(f\"Ignoring duplicate positions with id={position.id!r}\")\n                            pass\n                        else:\n                            id_to_position[ position.id] = position\n\n                # Insert links for all positions that have an `href` starting\n                # with '#'.\n                #\n                for position_from in positions:\n                    if ((position_from.open_close & 1)\n                            and position_from.href\n                            and position_from.href.startswith(\"#\")\n                            ):\n                        # This is a `<a href=\"#...\">...</a>` internal link.\n                        #print(f\"add_pdf_links(): position with href: {position}\")\n                        target_id = position_from.href[1:]\n                        try:\n                            position_to = id_to_position[ target_id]\n                        except Exception as e:\n                            raise RuntimeError(f\"No destination with id={target_id}, required by position_from: {position_from}\")\n                        # Make link from `position_from`'s rect to top-left of\n                        # `position_to`'s rect.\n                        if 0:\n                            print(f\"add_pdf_links(): making link from:\")\n                            print(f\"add_pdf_links():    {position_from}\")\n                            print(f\"add_pdf_links(): to:\")\n                            print(f\"add_pdf_links():    {position_to}\")\n                        link = dict()\n                        link[\"kind\"] = LINK_GOTO\n                        link[\"from\"] = Rect(position_from.rect)\n                        x0, y0, x1, y1 = position_to.rect\n                        # This appears to work well with viewers which scroll\n                        # to make destination point top-left of window.\n                        link[\"to\"] = Point(x0, y0)\n                        link[\"page\"] = position_to.page_num - 1\n                        document[position_from.page_num - 1].insert_link(link)\n                return document\n\n            @property\n            def body(self):\n                dom = self.document()\n                return dom.bodytag()\n\n            def __del__(self):\n                if not type(self) is Story:\n                    return\n                if getattr(self, \"thisown\", False):\n                    self.__swig_destroy__(self)\n        %}\n    }\n};\n\n\n//------------------------------------------------------------------------\n// Tools - a collection of tools and utilities\n//------------------------------------------------------------------------\nstruct Tools\n{\n    %extend\n    {\n        Tools()\n        {\n            /* It looks like global objects are never destructed when running\n            with SWIG, so we use Memento_startLeaking()/Memento_stopLeaking().\n            */\n            Memento_startLeaking();\n            void* p = malloc( sizeof(struct Tools));\n            Memento_stopLeaking();\n            //fprintf(stderr, \"Tools constructor p=%p\\n\", p);\n            return (struct Tools*) p;\n        }\n\n        ~Tools()\n        {\n            /* This is not called. */\n            struct Tools* p = (struct Tools*) $self;\n            //fprintf(stderr, \"~Tools() p=%p\\n\", p);\n            free(p);\n        }\n\n        %pythonprepend gen_id\n        %{\"\"\"Return a unique positive integer.\"\"\"%}\n        PyObject *gen_id()\n        {\n            JM_UNIQUE_ID += 1;\n            if (JM_UNIQUE_ID < 0) JM_UNIQUE_ID = 1;\n            return Py_BuildValue(\"i\", JM_UNIQUE_ID);\n        }\n\n\n        FITZEXCEPTION(set_icc, !result)\n        %pythonprepend set_icc\n        %{\"\"\"Set ICC color handling on or off.\"\"\"%}\n        PyObject *set_icc(int on=0)\n        {\n            fz_try(gctx) {\n                if (on) {\n                    if (FZ_ENABLE_ICC)\n                        fz_enable_icc(gctx);\n                    else {\n                        RAISEPY(gctx, \"MuPDF built w/o ICC support\",PyExc_ValueError);\n                    }\n                } else if (FZ_ENABLE_ICC) {\n                    fz_disable_icc(gctx);\n                }\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        %pythonprepend set_annot_stem\n        %{\"\"\"Get / set id prefix for annotations.\"\"\"%}\n        char *set_annot_stem(char *stem=NULL)\n        {\n            if (!stem) {\n                return JM_annot_id_stem;\n            }\n            size_t len = strlen(stem) + 1;\n            if (len > 50) len = 50;\n            memcpy(&JM_annot_id_stem, stem, len);\n            return JM_annot_id_stem;\n        }\n\n\n        %pythonprepend set_small_glyph_heights\n        %{\"\"\"Set / unset small glyph heights.\"\"\"%}\n        PyObject *set_small_glyph_heights(PyObject *on=NULL)\n        {\n            if (!on || on == Py_None) {\n                return JM_BOOL(small_glyph_heights);\n            }\n            if (PyObject_IsTrue(on)) {\n                small_glyph_heights = 1;\n            } else {\n                small_glyph_heights = 0;\n            }\n            return JM_BOOL(small_glyph_heights);\n        }\n\n\n        %pythonprepend set_subset_fontnames\n        %{\"\"\"Set / unset returning fontnames with their subset prefix.\"\"\"%}\n        PyObject *set_subset_fontnames(PyObject *on=NULL)\n        {\n            if (!on || on == Py_None) {\n                return JM_BOOL(subset_fontnames);\n            }\n            if (PyObject_IsTrue(on)) {\n                subset_fontnames = 1;\n            } else {\n                subset_fontnames = 0;\n            }\n            return JM_BOOL(subset_fontnames);\n        }\n\n\n        %pythonprepend set_low_memory\n        %{\"\"\"Set / unset MuPDF device caching.\"\"\"%}\n        PyObject *set_low_memory(PyObject *on=NULL)\n        {\n            if (!on || on == Py_None) {\n                return JM_BOOL(no_device_caching);\n            }\n            if (PyObject_IsTrue(on)) {\n                no_device_caching = 1;\n            } else {\n                no_device_caching = 0;\n            }\n            return JM_BOOL(no_device_caching);\n        }\n\n\n        %pythonprepend unset_quad_corrections\n        %{\"\"\"Set ascender / descender corrections on or off.\"\"\"%}\n        PyObject *unset_quad_corrections(PyObject *on=NULL)\n        {\n            if (!on || on == Py_None) {\n                return JM_BOOL(skip_quad_corrections);\n            }\n            if (PyObject_IsTrue(on)) {\n                skip_quad_corrections = 1;\n            } else {\n                skip_quad_corrections = 0;\n            }\n            return JM_BOOL(skip_quad_corrections);\n        }\n\n\n        %pythonprepend store_shrink\n        %{\"\"\"Free 'percent' of current store size.\"\"\"%}\n        PyObject *store_shrink(int percent)\n        {\n            if (percent >= 100) {\n                fz_empty_store(gctx);\n                return Py_BuildValue(\"i\", 0);\n            }\n            if (percent > 0) fz_shrink_store(gctx, 100 - percent);\n            return Py_BuildValue(\"i\", (int) gctx->store->size);\n        }\n\n\n        %pythoncode%{@property%}\n        %pythonprepend store_size\n        %{\"\"\"MuPDF current store size.\"\"\"%}\n        PyObject *store_size()\n        {\n            return Py_BuildValue(\"i\", (int) gctx->store->size);\n        }\n\n\n        %pythoncode%{@property%}\n        %pythonprepend store_maxsize\n        %{\"\"\"MuPDF store size limit.\"\"\"%}\n        PyObject *store_maxsize()\n        {\n            return Py_BuildValue(\"i\", (int) gctx->store->max);\n        }\n\n\n        %pythonprepend show_aa_level\n        %{\"\"\"Show anti-aliasing values.\"\"\"%}\n        %pythonappend show_aa_level %{\n        temp = {\"graphics\": val[0], \"text\": val[1], \"graphics_min_line_width\": val[2]}\n        val = temp%}\n        PyObject *show_aa_level()\n        {\n            return Py_BuildValue(\"iif\",\n                fz_graphics_aa_level(gctx),\n                fz_text_aa_level(gctx),\n                fz_graphics_min_line_width(gctx));\n        }\n\n\n        %pythonprepend set_aa_level\n        %{\"\"\"Set anti-aliasing level.\"\"\"%}\n        void set_aa_level(int level)\n        {\n            fz_set_aa_level(gctx, level);\n        }\n\n\n        %pythonprepend set_graphics_min_line_width\n        %{\"\"\"Set the graphics minimum line width.\"\"\"%}\n        void set_graphics_min_line_width(float min_line_width)\n        {\n            fz_set_graphics_min_line_width(gctx, min_line_width);\n        }\n\n\n        FITZEXCEPTION(image_profile, !result)\n        %pythonprepend image_profile\n        %{\"\"\"Metadata of an image binary stream.\"\"\"%}\n        PyObject *image_profile(PyObject *stream, int keep_image=0)\n        {\n            PyObject *rc = NULL;\n            fz_try(gctx) {\n                rc = JM_image_profile(gctx, stream, keep_image);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return rc;\n        }\n\n\n        PyObject *_rotate_matrix(struct Page *page)\n        {\n            pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) page);\n            if (!pdfpage) return JM_py_from_matrix(fz_identity);\n            return JM_py_from_matrix(JM_rotate_page_matrix(gctx, pdfpage));\n        }\n\n\n        PyObject *_derotate_matrix(struct Page *page)\n        {\n            pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) page);\n            if (!pdfpage) return JM_py_from_matrix(fz_identity);\n            return JM_py_from_matrix(JM_derotate_page_matrix(gctx, pdfpage));\n        }\n\n\n        %pythoncode%{@property%}\n        %pythonprepend fitz_config\n        %{\"\"\"PyMuPDF configuration parameters.\"\"\"%}\n        PyObject *fitz_config()\n        {\n            return JM_fitz_config();\n        }\n\n\n        %pythonprepend glyph_cache_empty\n        %{\"\"\"Empty the glyph cache.\"\"\"%}\n        void glyph_cache_empty()\n        {\n            fz_purge_glyph_cache(gctx);\n        }\n\n\n        FITZEXCEPTION(_fill_widget, !result)\n        %pythonappend _fill_widget %{\n            widget.rect = Rect(annot.rect)\n            widget.xref = annot.xref\n            widget.parent = annot.parent\n            widget._annot = annot  # backpointer to annot object\n            if not widget.script:\n                widget.script = None\n            if not widget.script_stroke:\n                widget.script_stroke = None\n            if not widget.script_format:\n                widget.script_format = None\n            if not widget.script_change:\n                widget.script_change = None\n            if not widget.script_calc:\n                widget.script_calc = None\n            if not widget.script_blur:\n                widget.script_blur = None\n            if not widget.script_focus:\n                widget.script_focus = None\n        %}\n        PyObject *_fill_widget(struct Annot *annot, PyObject *widget)\n        {\n            fz_try(gctx) {\n                JM_get_widget_properties(gctx, (pdf_annot *) annot, widget);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(_save_widget, !result)\n        PyObject *_save_widget(struct Annot *annot, PyObject *widget)\n        {\n            fz_try(gctx) {\n                JM_set_widget_properties(gctx, (pdf_annot *) annot, widget);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(_reset_widget, !result)\n        PyObject *_reset_widget(struct Annot *annot)\n        {\n            fz_try(gctx) {\n                pdf_annot *this_annot = (pdf_annot *) annot;\n                pdf_obj *this_annot_obj = pdf_annot_obj(gctx, this_annot);\n                pdf_document *pdf = pdf_get_bound_document(gctx, this_annot_obj);\n                pdf_field_reset(gctx, pdf, this_annot_obj);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n        // Ensure that widgets with a /AA/C JavaScript are in AcroForm/CO\n        FITZEXCEPTION(_ensure_widget_calc, !result)\n        PyObject *_ensure_widget_calc(struct Annot *annot)\n        {\n            pdf_obj *PDFNAME_CO=NULL;\n            fz_try(gctx) {\n                pdf_obj *annot_obj = pdf_annot_obj(gctx, (pdf_annot *) annot);\n                pdf_document *pdf = pdf_get_bound_document(gctx, annot_obj);\n                PDFNAME_CO = pdf_new_name(gctx, \"CO\");  // = PDF_NAME(CO)\n                pdf_obj *acro = pdf_dict_getl(gctx,  // get AcroForm dict\n                                pdf_trailer(gctx, pdf),\n                                PDF_NAME(Root),\n                                PDF_NAME(AcroForm),\n                                NULL);\n\n                pdf_obj *CO = pdf_dict_get(gctx, acro, PDFNAME_CO);  // = AcroForm/CO\n                if (!CO) {\n                    CO = pdf_dict_put_array(gctx, acro, PDFNAME_CO, 2);\n                }\n                int i, n = pdf_array_len(gctx, CO);\n                int xref, nxref, found = 0;\n                xref = pdf_to_num(gctx, annot_obj);\n                for (i = 0; i < n; i++) {\n                    nxref = pdf_to_num(gctx, pdf_array_get(gctx, CO, i));\n                    if (xref == nxref) {\n                        found = 1;\n                        break;\n                    }\n                }\n                if (!found) {\n                    pdf_array_push_drop(gctx, CO, pdf_new_indirect(gctx, pdf, xref, 0));\n                }\n            }\n            fz_always(gctx) {\n                pdf_drop_obj(gctx, PDFNAME_CO);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(_parse_da, !result)\n        %pythonappend _parse_da %{\n        if not val:\n            return ((0,), \"\", 0)\n        font = \"Helv\"\n        fsize = 12\n        col = (0, 0, 0)\n        dat = val.split()  # split on any whitespace\n        for i, item in enumerate(dat):\n            if item == \"Tf\":\n                font = dat[i - 2][1:]\n                fsize = float(dat[i - 1])\n                dat[i] = dat[i-1] = dat[i-2] = \"\"\n                continue\n            if item == \"g\":            # unicolor text\n                col = [(float(dat[i - 1]))]\n                dat[i] = dat[i-1] = \"\"\n                continue\n            if item == \"rg\":           # RGB colored text\n                col = [float(f) for f in dat[i - 3:i]]\n                dat[i] = dat[i-1] = dat[i-2] = dat[i-3] = \"\"\n                continue\n            if item == \"k\":           # CMYK colored text\n                col = [float(f) for f in dat[i - 4:i]]\n                dat[i] = dat[i-1] = dat[i-2] = dat[i-3] = dat[i-4] = \"\"\n                continue\n\n        val = (col, font, fsize)\n        %}\n        PyObject *_parse_da(struct Annot *annot)\n        {\n            char *da_str = NULL;\n            pdf_annot *this_annot = (pdf_annot *) annot;\n            pdf_obj *this_annot_obj = pdf_annot_obj(gctx, this_annot);\n            pdf_document *pdf = pdf_get_bound_document(gctx, this_annot_obj);\n            fz_try(gctx) {\n                pdf_obj *da = pdf_dict_get_inheritable(gctx, this_annot_obj,\n                                                       PDF_NAME(DA));\n                if (!da) {\n                    pdf_obj *trailer = pdf_trailer(gctx, pdf);\n                    da = pdf_dict_getl(gctx, trailer, PDF_NAME(Root),\n                                       PDF_NAME(AcroForm),\n                                       PDF_NAME(DA),\n                                       NULL);\n                }\n                da_str = (char *) pdf_to_text_string(gctx, da);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return JM_UnicodeFromStr(da_str);\n        }\n\n\n        FITZEXCEPTION(_update_da, !result)\n        PyObject *_update_da(struct Annot *annot, char *da_str)\n        {\n            fz_try(gctx) {\n                pdf_annot *this_annot = (pdf_annot *) annot;\n                pdf_obj *this_annot_obj = pdf_annot_obj(gctx, this_annot);\n                pdf_dict_put_text_string(gctx, this_annot_obj, PDF_NAME(DA), da_str);\n                pdf_dict_del(gctx, this_annot_obj, PDF_NAME(DS)); /* not supported */\n                pdf_dict_del(gctx, this_annot_obj, PDF_NAME(RC)); /* not supported */\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            Py_RETURN_NONE;\n        }\n\n\n        FITZEXCEPTION(_get_all_contents, !result)\n        %pythonprepend _get_all_contents\n        %{\"\"\"Concatenate all /Contents objects of a page into a bytes object.\"\"\"%}\n        PyObject *_get_all_contents(struct Page *fzpage)\n        {\n            pdf_page *page = pdf_page_from_fz_page(gctx, (fz_page *) fzpage);\n            fz_buffer *res = NULL;\n            PyObject *result = NULL;\n            fz_try(gctx) {\n                ASSERT_PDF(page);\n                res = JM_read_contents(gctx, page->obj);\n                result = JM_BinFromBuffer(gctx, res);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, res);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return result;\n        }\n\n\n        FITZEXCEPTION(_insert_contents, !result)\n        %pythonprepend _insert_contents\n        %{\"\"\"Add bytes as a new /Contents object for a page, and return its xref.\"\"\"%}\n        PyObject *_insert_contents(struct Page *page, PyObject *newcont, int overlay=1)\n        {\n            fz_buffer *contbuf = NULL;\n            int xref = 0;\n            pdf_page *pdfpage = pdf_page_from_fz_page(gctx, (fz_page *) page);\n            fz_try(gctx) {\n                ASSERT_PDF(pdfpage);\n                ENSURE_OPERATION(gctx, pdfpage->doc);\n                contbuf = JM_BufferFromBytes(gctx, newcont);\n                xref = JM_insert_contents(gctx, pdfpage->doc, pdfpage->obj, contbuf, overlay);\n            }\n            fz_always(gctx) {\n                fz_drop_buffer(gctx, contbuf);\n            }\n            fz_catch(gctx) {\n                return NULL;\n            }\n            return Py_BuildValue(\"i\", xref);\n        }\n\n        %pythonprepend mupdf_version\n        %{\"\"\"Get version of MuPDF binary build.\"\"\"%}\n        PyObject *mupdf_version()\n        {\n            return Py_BuildValue(\"s\", FZ_VERSION);\n        }\n\n        %pythonprepend mupdf_warnings\n        %{\"\"\"Get the MuPDF warnings/errors with optional reset (default).\"\"\"%}\n        %pythonappend mupdf_warnings %{\n        val = \"\\n\".join(val)\n        if reset:\n            self.reset_mupdf_warnings()%}\n        PyObject *mupdf_warnings(int reset=1)\n        {\n            Py_INCREF(JM_mupdf_warnings_store);\n            return JM_mupdf_warnings_store;\n        }\n\n        int _int_from_language(char *language)\n        {\n            return fz_text_language_from_string(language);\n        }\n\n        %pythonprepend reset_mupdf_warnings\n        %{\"\"\"Empty the MuPDF warnings/errors store.\"\"\"%}\n        void reset_mupdf_warnings()\n        {\n            Py_CLEAR(JM_mupdf_warnings_store);\n            JM_mupdf_warnings_store = PyList_New(0);\n        }\n\n        %pythonprepend mupdf_display_errors\n        %{\"\"\"Set MuPDF error display to True or False.\"\"\"%}\n        PyObject *mupdf_display_errors(PyObject *on=NULL)\n        {\n            if (!on || on == Py_None) {\n                return JM_BOOL(JM_mupdf_show_errors);\n            }\n            if (PyObject_IsTrue(on)) {\n                JM_mupdf_show_errors = 1;\n            } else {\n                JM_mupdf_show_errors = 0;\n            }\n            return JM_BOOL(JM_mupdf_show_errors);\n        }\n\n        %pythonprepend mupdf_display_warnings\n        %{\"\"\"Set MuPDF warnings display to True or False.\"\"\"%}\n        PyObject *mupdf_display_warnings(PyObject *on=NULL)\n        {\n            if (!on || on == Py_None) {\n                return JM_BOOL(JM_mupdf_show_warnings);\n            }\n            if (PyObject_IsTrue(on)) {\n                JM_mupdf_show_warnings = 1;\n            } else {\n                JM_mupdf_show_warnings = 0;\n            }\n            return JM_BOOL(JM_mupdf_show_warnings);\n        }\n\n        %pythoncode %{\ndef _le_annot_parms(self, annot, p1, p2, fill_color):\n    \"\"\"Get common parameters for making annot line end symbols.\n\n    Returns:\n        m: matrix that maps p1, p2 to points L, P on the x-axis\n        im: its inverse\n        L, P: transformed p1, p2\n        w: line width\n        scol: stroke color string\n        fcol: fill color store_shrink\n        opacity: opacity string (gs command)\n    \"\"\"\n    w = annot.border[\"width\"]  # line width\n    sc = annot.colors[\"stroke\"]  # stroke color\n    if not sc:  # black if missing\n        sc = (0,0,0)\n    scol = \" \".join(map(str, sc)) + \" RG\\n\"\n    if fill_color:\n        fc = fill_color\n    else:\n        fc = annot.colors[\"fill\"]  # fill color\n    if not fc:\n        fc = (1,1,1)  # white if missing\n    fcol = \" \".join(map(str, fc)) + \" rg\\n\"\n    # nr = annot.rect\n    np1 = p1                   # point coord relative to annot rect\n    np2 = p2                   # point coord relative to annot rect\n    m = Matrix(util_hor_matrix(np1, np2))  # matrix makes the line horizontal\n    im = ~m                            # inverted matrix\n    L = np1 * m                        # converted start (left) point\n    R = np2 * m                        # converted end (right) point\n    if 0 <= annot.opacity < 1:\n        opacity = \"/H gs\\n\"\n    else:\n        opacity = \"\"\n    return m, im, L, R, w, scol, fcol, opacity\n\ndef _oval_string(self, p1, p2, p3, p4):\n    \"\"\"Return /AP string defining an oval within a 4-polygon provided as points\n    \"\"\"\n    def bezier(p, q, r):\n        f = \"%f %f %f %f %f %f c\\n\"\n        return f % (p.x, p.y, q.x, q.y, r.x, r.y)\n\n    kappa = 0.55228474983              # magic number\n    ml = p1 + (p4 - p1) * 0.5          # middle points ...\n    mo = p1 + (p2 - p1) * 0.5          # for each ...\n    mr = p2 + (p3 - p2) * 0.5          # polygon ...\n    mu = p4 + (p3 - p4) * 0.5          # side\n    ol1 = ml + (p1 - ml) * kappa       # the 8 bezier\n    ol2 = mo + (p1 - mo) * kappa       # helper points\n    or1 = mo + (p2 - mo) * kappa\n    or2 = mr + (p2 - mr) * kappa\n    ur1 = mr + (p3 - mr) * kappa\n    ur2 = mu + (p3 - mu) * kappa\n    ul1 = mu + (p4 - mu) * kappa\n    ul2 = ml + (p4 - ml) * kappa\n    # now draw, starting from middle point of left side\n    ap = \"%f %f m\\n\" % (ml.x, ml.y)\n    ap += bezier(ol1, ol2, mo)\n    ap += bezier(or1, or2, mr)\n    ap += bezier(ur1, ur2, mu)\n    ap += bezier(ul1, ul2, ml)\n    return ap\n\ndef _le_diamond(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for diamond line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 2.5             # 2*shift*width = length of square edge\n    d = shift * max(1, w)\n    M = R - (d/2., 0) if lr else L + (d/2., 0)\n    r = Rect(M, M) + (-d, -d, d, d)         # the square\n    # the square makes line longer by (2*shift - 1)*width\n    p = (r.tl + (r.bl - r.tl) * 0.5) * im\n    ap = \"q\\n%s%f %f m\\n\" % (opacity, p.x, p.y)\n    p = (r.tl + (r.tr - r.tl) * 0.5) * im\n    ap += \"%f %f l\\n\"   % (p.x, p.y)\n    p = (r.tr + (r.br - r.tr) * 0.5) * im\n    ap += \"%f %f l\\n\"   % (p.x, p.y)\n    p = (r.br + (r.bl - r.br) * 0.5) * im\n    ap += \"%f %f l\\n\"   % (p.x, p.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + fcol + \"b\\nQ\\n\"\n    return ap\n\ndef _le_square(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for square line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 2.5             # 2*shift*width = length of square edge\n    d = shift * max(1, w)\n    M = R - (d/2., 0) if lr else L + (d/2., 0)\n    r = Rect(M, M) + (-d, -d, d, d)         # the square\n    # the square makes line longer by (2*shift - 1)*width\n    p = r.tl * im\n    ap = \"q\\n%s%f %f m\\n\" % (opacity, p.x, p.y)\n    p = r.tr * im\n    ap += \"%f %f l\\n\"   % (p.x, p.y)\n    p = r.br * im\n    ap += \"%f %f l\\n\"   % (p.x, p.y)\n    p = r.bl * im\n    ap += \"%f %f l\\n\"   % (p.x, p.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + fcol + \"b\\nQ\\n\"\n    return ap\n\ndef _le_circle(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for circle line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 2.5             # 2*shift*width = length of square edge\n    d = shift * max(1, w)\n    M = R - (d/2., 0) if lr else L + (d/2., 0)\n    r = Rect(M, M) + (-d, -d, d, d)         # the square\n    ap = \"q\\n\" + opacity + self._oval_string(r.tl * im, r.tr * im, r.br * im, r.bl * im)\n    ap += \"%g w\\n\" % w\n    ap += scol + fcol + \"b\\nQ\\n\"\n    return ap\n\ndef _le_butt(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for butt line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 3\n    d = shift * max(1, w)\n    M = R if lr else L\n    top = (M + (0, -d/2.)) * im\n    bot = (M + (0, d/2.)) * im\n    ap = \"\\nq\\n%s%f %f m\\n\" % (opacity, top.x, top.y)\n    ap += \"%f %f l\\n\" % (bot.x, bot.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + \"s\\nQ\\n\"\n    return ap\n\ndef _le_slash(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for slash line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    rw = 1.1547 * max(1, w) * 1.0         # makes rect diagonal a 30 deg inclination\n    M = R if lr else L\n    r = Rect(M.x - rw, M.y - 2 * w, M.x + rw, M.y + 2 * w)\n    top = r.tl * im\n    bot = r.br * im\n    ap = \"\\nq\\n%s%f %f m\\n\" % (opacity, top.x, top.y)\n    ap += \"%f %f l\\n\" % (bot.x, bot.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + \"s\\nQ\\n\"\n    return ap\n\ndef _le_openarrow(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for open arrow line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 2.5\n    d = shift * max(1, w)\n    p2 = R + (d/2., 0) if lr else L - (d/2., 0)\n    p1 = p2 + (-2*d, -d) if lr else p2 + (2*d, -d)\n    p3 = p2 + (-2*d, d) if lr else p2 + (2*d, d)\n    p1 *= im\n    p2 *= im\n    p3 *= im\n    ap = \"\\nq\\n%s%f %f m\\n\" % (opacity, p1.x, p1.y)\n    ap += \"%f %f l\\n\" % (p2.x, p2.y)\n    ap += \"%f %f l\\n\" % (p3.x, p3.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + \"S\\nQ\\n\"\n    return ap\n\ndef _le_closedarrow(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for closed arrow line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 2.5\n    d = shift * max(1, w)\n    p2 = R + (d/2., 0) if lr else L - (d/2., 0)\n    p1 = p2 + (-2*d, -d) if lr else p2 + (2*d, -d)\n    p3 = p2 + (-2*d, d) if lr else p2 + (2*d, d)\n    p1 *= im\n    p2 *= im\n    p3 *= im\n    ap = \"\\nq\\n%s%f %f m\\n\" % (opacity, p1.x, p1.y)\n    ap += \"%f %f l\\n\" % (p2.x, p2.y)\n    ap += \"%f %f l\\n\" % (p3.x, p3.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + fcol + \"b\\nQ\\n\"\n    return ap\n\ndef _le_ropenarrow(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for right open arrow line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 2.5\n    d = shift * max(1, w)\n    p2 = R - (d/3., 0) if lr else L + (d/3., 0)\n    p1 = p2 + (2*d, -d) if lr else p2 + (-2*d, -d)\n    p3 = p2 + (2*d, d) if lr else p2 + (-2*d, d)\n    p1 *= im\n    p2 *= im\n    p3 *= im\n    ap = \"\\nq\\n%s%f %f m\\n\" % (opacity, p1.x, p1.y)\n    ap += \"%f %f l\\n\" % (p2.x, p2.y)\n    ap += \"%f %f l\\n\" % (p3.x, p3.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + fcol + \"S\\nQ\\n\"\n    return ap\n\ndef _le_rclosedarrow(self, annot, p1, p2, lr, fill_color):\n    \"\"\"Make stream commands for right closed arrow line end symbol. \"lr\" denotes left (False) or right point.\n    \"\"\"\n    m, im, L, R, w, scol, fcol, opacity = self._le_annot_parms(annot, p1, p2, fill_color)\n    shift = 2.5\n    d = shift * max(1, w)\n    p2 = R - (2*d, 0) if lr else L + (2*d, 0)\n    p1 = p2 + (2*d, -d) if lr else p2 + (-2*d, -d)\n    p3 = p2 + (2*d, d) if lr else p2 + (-2*d, d)\n    p1 *= im\n    p2 *= im\n    p3 *= im\n    ap = \"\\nq\\n%s%f %f m\\n\" % (opacity, p1.x, p1.y)\n    ap += \"%f %f l\\n\" % (p2.x, p2.y)\n    ap += \"%f %f l\\n\" % (p3.x, p3.y)\n    ap += \"%g w\\n\" % w\n    ap += scol + fcol + \"b\\nQ\\n\"\n    return ap\n\ndef __del__(self):\n    if not type(self) is Tools:\n        return\n    if getattr(self, \"thisown\", False):\n        self.__swig_destroy__(self)\n        %}\n    }\n};\n"
  },
  {
    "path": "src_classic/helper-annot.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//------------------------------------------------------------------------\n// return pdf_obj \"border style\" from Python str\n//------------------------------------------------------------------------\npdf_obj *JM_get_border_style(fz_context *ctx, PyObject *style)\n{\n    pdf_obj *val = PDF_NAME(S);\n    if (!style) return val;\n    char *s = JM_StrAsChar(style);\n    JM_PyErr_Clear;\n    if (!s) return val;\n    if      (!strncmp(s, \"b\", 1) || !strncmp(s, \"B\", 1)) val = PDF_NAME(B);\n    else if (!strncmp(s, \"d\", 1) || !strncmp(s, \"D\", 1)) val = PDF_NAME(D);\n    else if (!strncmp(s, \"i\", 1) || !strncmp(s, \"I\", 1)) val = PDF_NAME(I);\n    else if (!strncmp(s, \"u\", 1) || !strncmp(s, \"U\", 1)) val = PDF_NAME(U);\n    else if (!strncmp(s, \"s\", 1) || !strncmp(s, \"S\", 1)) val = PDF_NAME(S);\n    return val;\n}\n\n//------------------------------------------------------------------------\n// Make /DA string of annotation\n//------------------------------------------------------------------------\nconst char *JM_expand_fname(const char **name)\n{\n    if (!*name) return \"Helv\";\n    if (!strncmp(*name, \"Co\", 2)) return \"Cour\";\n    if (!strncmp(*name, \"co\", 2)) return \"Cour\";\n    if (!strncmp(*name, \"Ti\", 2)) return \"TiRo\";\n    if (!strncmp(*name, \"ti\", 2)) return \"TiRo\";\n    if (!strncmp(*name, \"Sy\", 2)) return \"Symb\";\n    if (!strncmp(*name, \"sy\", 2)) return \"Symb\";\n    if (!strncmp(*name, \"Za\", 2)) return \"ZaDb\";\n    if (!strncmp(*name, \"za\", 2)) return \"ZaDb\";\n    return \"Helv\";\n}\n\nvoid JM_make_annot_DA(fz_context *ctx, pdf_annot *annot, int ncol, float col[4], const char *fontname, float fontsize)\n{\n    fz_buffer *buf = NULL;\n    fz_try(ctx)\n    {\n        buf = fz_new_buffer(ctx, 50);\n       if (ncol <= 1)\n            fz_append_printf(ctx, buf, \"%g g \", col[0]);\n        else if (ncol < 4)\n            fz_append_printf(ctx, buf, \"%g %g %g rg \", col[0], col[1], col[2]);\n        else\n            fz_append_printf(ctx, buf, \"%g %g %g %g k \", col[0], col[1], col[2], col[3]);\n        fz_append_printf(ctx, buf, \"/%s %g Tf\", JM_expand_fname(&fontname), fontsize);\n        unsigned char *da = NULL;\n        size_t len = fz_buffer_storage(ctx, buf, &da);\n        pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n        pdf_dict_put_string(ctx, annot_obj, PDF_NAME(DA), (const char *) da, len);\n    }\n    fz_always(ctx) fz_drop_buffer(ctx, buf);\n    fz_catch(ctx) fz_rethrow(ctx);\n    return;\n}\n\n//------------------------------------------------------------------------\n// refreshes the link and annotation tables of a page\n//------------------------------------------------------------------------\nvoid JM_refresh_links(fz_context *ctx, pdf_page *page)\n{\n    if (!page) return;\n    fz_try(ctx) {\n\t\tpdf_obj *obj = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));\n\t\tif (obj)\n\t\t{\n\t\t\tpdf_document *pdf = page->doc;\n            int number = pdf_lookup_page_number(ctx, pdf, page->obj);\n            fz_rect page_mediabox;\n\t\t\tfz_matrix page_ctm;\n\t\t\tpdf_page_transform(ctx, page, &page_mediabox, &page_ctm);\n\t\t\tpage->links = pdf_load_link_annots(ctx, pdf, page, obj, number, page_ctm);\n\t\t}\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return;\n}\n\n\nPyObject *JM_annot_border(fz_context *ctx, pdf_obj *annot_obj)\n{\n    PyObject *res = PyDict_New();\n    PyObject *dash_py   = PyList_New(0);\n    PyObject *val;\n    int i;\n    const char *style = NULL;\n    float width = -1.0f;\n    int clouds = -1;\n    pdf_obj *obj = NULL;\n\n    obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(Border));\n    if (pdf_is_array(ctx, obj)) {\n        width = pdf_to_real(ctx, pdf_array_get(ctx, obj, 2));\n        if (pdf_array_len(ctx, obj) == 4) {\n            pdf_obj *dash = pdf_array_get(ctx, obj, 3);\n            for (i = 0; i < pdf_array_len(ctx, dash); i++) {\n                val = Py_BuildValue(\"i\", pdf_to_int(ctx, pdf_array_get(ctx, dash, i)));\n                LIST_APPEND_DROP(dash_py, val);\n            }\n        }\n    }\n\n    pdf_obj *bs_o = pdf_dict_get(ctx, annot_obj, PDF_NAME(BS));\n    if (bs_o) {\n        width = pdf_to_real(ctx, pdf_dict_get(ctx, bs_o, PDF_NAME(W)));\n        style = pdf_to_name(ctx, pdf_dict_get(ctx, bs_o, PDF_NAME(S)));\n        if (style && strcmp(style, \"\") == 0) {\n            style = NULL;\n        }\n        obj = pdf_dict_get(ctx, bs_o, PDF_NAME(D));\n        if (obj) {\n            for (i = 0; i < pdf_array_len(ctx, obj); i++) {\n                val = Py_BuildValue(\"i\", pdf_to_int(ctx, pdf_array_get(ctx, obj, i)));\n                LIST_APPEND_DROP(dash_py, val);\n            }\n        }\n    }\n\n    obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(BE));\n    if (obj) {\n        clouds = pdf_to_int(ctx, pdf_dict_get(ctx, obj, PDF_NAME(I)));\n    }\n    val = PySequence_Tuple(dash_py);\n    Py_CLEAR(dash_py);\n    DICT_SETITEM_DROP(res, dictkey_width, Py_BuildValue(\"f\", width));\n    DICT_SETITEM_DROP(res, dictkey_dashes, val);\n    DICT_SETITEM_DROP(res, dictkey_style, Py_BuildValue(\"s\", style));\n    DICT_SETITEMSTR_DROP(res, \"clouds\", Py_BuildValue(\"i\", clouds));\n    return res;\n}\n\nPyObject *JM_annot_set_border(fz_context *ctx, PyObject *border, pdf_document *doc, pdf_obj *annot_obj)\n{\n    if (!PyDict_Check(border)) {\n        JM_Warning(\"arg must be a dict\");\n        Py_RETURN_NONE;     // not a dict\n    }\n    pdf_obj *obj = NULL;\n    Py_ssize_t i = 0, dashlen = 0;\n    int d;\n    double nwidth = PyFloat_AsDouble(PyDict_GetItem(border, dictkey_width));  // new width\n    PyObject *ndashes = PyDict_GetItem(border, dictkey_dashes);  // new dashes\n    PyObject *nstyle  = PyDict_GetItem(border, dictkey_style);  // new style\n    int nclouds  = (int) PyLong_AsLong(PyDict_GetItemString(border, \"clouds\"));  // new clouds value\n\n    // get old border properties\n    PyObject *oborder = JM_annot_border(ctx, annot_obj);\n\n    // delete border-related entries\n    pdf_dict_del(ctx, annot_obj, PDF_NAME(BS));\n    pdf_dict_del(ctx, annot_obj, PDF_NAME(BE));\n    pdf_dict_del(ctx, annot_obj, PDF_NAME(Border));\n\n    // populate border items: keep old values for any omitted new ones\n    if (nwidth < 0) nwidth = PyFloat_AsDouble(PyDict_GetItem(oborder, dictkey_width));  // no new width: keep current\n    if (ndashes == Py_None) ndashes = PyDict_GetItem(oborder, dictkey_dashes);  // no new dashes: keep old\n    if (nstyle == Py_None) nstyle  = PyDict_GetItem(oborder, dictkey_style);  // no new style: keep old\n    if (nclouds < 0) nclouds  = (int) PyLong_AsLong(PyDict_GetItemString(oborder, \"clouds\"));  // no new clouds: keep old\n\n    if (ndashes && PyTuple_Check(ndashes) && PyTuple_Size(ndashes) > 0) {\n        dashlen = PyTuple_Size(ndashes);\n        pdf_obj *darr = pdf_new_array(ctx, doc, dashlen);\n        for (i = 0; i < dashlen; i++) {\n            d = (int) PyLong_AsLong(PyTuple_GetItem(ndashes, i));\n            pdf_array_push_int(ctx, darr, (int64_t) d);\n        }\n        pdf_dict_putl_drop(ctx, annot_obj, darr, PDF_NAME(BS), PDF_NAME(D), NULL);\n    }\n\n    pdf_dict_putl_drop(ctx, annot_obj, pdf_new_real(ctx, (float) nwidth),\n                               PDF_NAME(BS), PDF_NAME(W), NULL);\n\n    if (dashlen == 0) {\n        obj = JM_get_border_style(ctx, nstyle);\n    } else {\n        obj = PDF_NAME(D);\n    }\n    pdf_dict_putl_drop(ctx, annot_obj, obj, PDF_NAME(BS), PDF_NAME(S), NULL);\n\n    if (nclouds > 0) {\n        pdf_dict_put_dict(ctx, annot_obj, PDF_NAME(BE), 2);\n        pdf_obj *obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(BE));\n        pdf_dict_put(ctx, obj, PDF_NAME(S), PDF_NAME(C));\n        pdf_dict_put_int(ctx, obj, PDF_NAME(I), (int64_t) nclouds);\n    }\n\n    PyErr_Clear();\n    Py_RETURN_NONE;\n}\n\nPyObject *JM_annot_colors(fz_context *ctx, pdf_obj *annot_obj)\n{\n    PyObject *res = PyDict_New();\n    PyObject *color = NULL;\n    int i, n;\n    float col;\n    pdf_obj *o = NULL;\n    \n    o = pdf_dict_get(ctx, annot_obj, PDF_NAME(C));\n    if (pdf_is_array(ctx, o)) {\n        n = pdf_array_len(ctx, o);\n        color = PyTuple_New((Py_ssize_t) n);\n        for (i = 0; i < n; i++) {\n            col = pdf_to_real(ctx, pdf_array_get(ctx, o, i));\n            PyTuple_SET_ITEM(color, i, Py_BuildValue(\"f\", col));\n        }\n        DICT_SETITEM_DROP(res, dictkey_stroke, color);\n    } else {\n        DICT_SETITEM_DROP(res, dictkey_stroke, Py_BuildValue(\"s\", NULL));\n    }\n\n    o = pdf_dict_get(ctx, annot_obj, PDF_NAME(IC));\n    if (pdf_is_array(ctx, o)) {\n        n = pdf_array_len(ctx, o);\n        color = PyTuple_New((Py_ssize_t) n);\n        for (i = 0; i < n; i++) {\n            col = pdf_to_real(ctx, pdf_array_get(ctx, o, i));\n            PyTuple_SET_ITEM(color, i, Py_BuildValue(\"f\", col));\n        }\n        DICT_SETITEM_DROP(res, dictkey_fill, color);\n    } else {\n        DICT_SETITEM_DROP(res, dictkey_fill, Py_BuildValue(\"s\", NULL));\n    }\n\n    return res;\n}\n\n\n//------------------------------------------------------------------------\n// Return the first annotation whose /IRT key (\"In Response To\") points to\n// annot. Used to remove the response chain of a given annotation.\n//------------------------------------------------------------------------\npdf_annot *JM_find_annot_irt(fz_context *ctx, pdf_annot *annot)\n{\n    pdf_annot *irt_annot = NULL;  // returning this\n    pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n    pdf_obj *o = NULL;\n    int found = 0;\n    fz_try(ctx) {   // loop thru MuPDF's internal annots array\n        pdf_page *page = pdf_annot_page(ctx, annot);\n        irt_annot = pdf_first_annot(ctx, page);\n        while (irt_annot) {\n            pdf_obj *irt_annot_obj = pdf_annot_obj(ctx, irt_annot);\n            o = pdf_dict_gets(ctx, irt_annot_obj, \"IRT\");\n            if (o) {\n                if (!pdf_objcmp(ctx, o, annot_obj)) {\n                    found = 1;\n                    break;\n                }\n            }\n            irt_annot = pdf_next_annot(ctx, irt_annot);\n        }\n    }\n    fz_catch(ctx) {;}\n    if (found) return pdf_keep_annot(ctx, irt_annot);\n    return NULL;\n}\n\n//------------------------------------------------------------------------\n// return the annotation names (list of /NM entries)\n//------------------------------------------------------------------------\nPyObject *JM_get_annot_id_list(fz_context *ctx, pdf_page *page)\n{\n    PyObject *names = PyList_New(0);\n    pdf_obj *annot_obj = NULL;\n    pdf_obj *annots = pdf_dict_get(ctx, page->obj, PDF_NAME(Annots));\n    pdf_obj *name = NULL;\n    if (!annots) return names;\n    fz_try(ctx) {\n        int i, n = pdf_array_len(ctx, annots);\n        for (i = 0; i < n; i++) {\n            annot_obj = pdf_array_get(ctx, annots, i);\n            name = pdf_dict_gets(ctx, annot_obj, \"NM\");\n            if (name) {\n                LIST_APPEND_DROP(names, Py_BuildValue(\"s\", pdf_to_text_string(ctx, name)));\n            }\n        }\n    }\n    fz_catch(ctx) {\n        return names;\n    }\n    return names;\n}\n\n\n//------------------------------------------------------------------------\n// return the xrefs and /NM ids of a page's annots, links and fields\n//------------------------------------------------------------------------\nPyObject *JM_get_annot_xref_list(fz_context *ctx, pdf_obj *page_obj)\n{\n    PyObject *names = PyList_New(0);\n    pdf_obj *id, *subtype, *annots, *annot_obj;\n    int xref, type, i, n;\n    fz_try(ctx) {\n        annots = pdf_dict_get(ctx, page_obj, PDF_NAME(Annots));\n        n = pdf_array_len(ctx, annots);\n        for (i = 0; i < n; i++) {\n            annot_obj = pdf_array_get(ctx, annots, i);\n            xref = pdf_to_num(ctx, annot_obj);\n            subtype = pdf_dict_get(ctx, annot_obj, PDF_NAME(Subtype));\n            if (!subtype) {\n                continue;  // subtype is required\n            }\n            type = pdf_annot_type_from_string(ctx, pdf_to_name(ctx, subtype));\n            if (type == PDF_ANNOT_UNKNOWN) {\n                continue;  // only accept valid annot types\n            }\n            id = pdf_dict_gets(ctx, annot_obj, \"NM\");\n            LIST_APPEND_DROP(names, Py_BuildValue(\"iis\", xref, type, pdf_to_text_string(ctx, id)));\n        }\n    }\n    fz_catch(ctx) {\n        return names;\n    }\n    return names;\n}\n\n\n//------------------------------------------------------------------------\n// Add a unique /NM key to an annotation or widget.\n// Append a number to 'stem' such that the result is a unique name.\n//------------------------------------------------------------------------\nstatic char JM_annot_id_stem[50] = \"fitz\";\nvoid JM_add_annot_id(fz_context *ctx, pdf_annot *annot, char *stem)\n{\n    fz_try(ctx) {\n        PyObject *names = NULL;\n        pdf_page *page = pdf_annot_page(ctx, annot);\n        pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n        names = JM_get_annot_id_list(ctx, page);\n        int i = 0;\n        PyObject *stem_id = NULL;\n        while (1) {\n            stem_id = PyUnicode_FromFormat(\"%s-%s%d\", JM_annot_id_stem, stem, i);\n            if (!PySequence_Contains(names, stem_id)) break;\n            i += 1;\n            Py_DECREF(stem_id);\n        }\n        char *response = JM_StrAsChar(stem_id);\n        pdf_obj *name = pdf_new_string(ctx, (const char *) response, strlen(response));\n        pdf_dict_puts_drop(ctx, annot_obj, \"NM\", name);\n        Py_CLEAR(stem_id);\n        Py_CLEAR(names);\n        page->doc->resynth_required = 0;\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\n//------------------------------------------------------------------------\n// retrieve annot by name (/NM key)\n//------------------------------------------------------------------------\npdf_annot *JM_get_annot_by_name(fz_context *ctx, pdf_page *page, char *name)\n{\n    if (!name || strlen(name) == 0) {\n        return NULL;\n    }\n    pdf_annot *annot = NULL;\n    int found = 0;\n    size_t len = 0;\n\n    fz_try(ctx) {   // loop thru MuPDF's internal annots and widget arrays\n        annot = pdf_first_annot(ctx, page);\n        while (annot) {\n            pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n            const char *response = pdf_to_string(ctx, pdf_dict_gets(ctx, annot_obj, \"NM\"), &len);\n            if (strcmp(name, response) == 0) {\n                found = 1;\n                break;\n            }\n            annot = pdf_next_annot(ctx, annot);\n        }\n        if (!found) {\n            fz_throw(ctx, FZ_ERROR_GENERIC, \"'%s' is not an annot of this page\", name);\n        }\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return pdf_keep_annot(ctx, annot);\n}\n\n//------------------------------------------------------------------------\n// retrieve annot by its xref\n//------------------------------------------------------------------------\npdf_annot *JM_get_annot_by_xref(fz_context *ctx, pdf_page *page, int xref)\n{\n    pdf_annot *annot = NULL;\n    int found = 0;\n\n    fz_try(ctx) {   // loop thru MuPDF's internal annots array\n        annot = pdf_first_annot(ctx, page);\n        while (annot) {\n            pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n            if (xref == pdf_to_num(ctx, annot_obj)) {\n                found = 1;\n                break;\n            }\n            annot = pdf_next_annot(ctx, annot);\n        }\n        if (!found) {\n            fz_throw(ctx, FZ_ERROR_GENERIC, \"xref %d is not an annot of this page\", xref);\n        }\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return pdf_keep_annot(ctx, annot);\n}\n\n//------------------------------------------------------------------------\n// retrieve widget by its xref\n//------------------------------------------------------------------------\npdf_annot *JM_get_widget_by_xref(fz_context *ctx, pdf_page *page, int xref)\n{\n    pdf_annot *annot = NULL;\n    int found = 0;\n\n    fz_try(ctx) {   // loop thru MuPDF's internal annots array\n        annot = pdf_first_widget(ctx, page);\n        while (annot) {\n            pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n            if (xref == pdf_to_num(ctx, annot_obj)) {\n                found = 1;\n                break;\n            }\n            annot = pdf_next_widget(ctx, annot);\n        }\n        if (!found) {\n            fz_throw(ctx, FZ_ERROR_GENERIC, \"xref %d is not a widget of this page\", xref);\n        }\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return pdf_keep_annot(ctx, annot);\n}\n\n%}\n"
  },
  {
    "path": "src_classic/helper-convert.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//-----------------------------------------------------------------------------\n// Convert any MuPDF document to a PDF\n// Returns bytes object containing the PDF, created via 'write' function.\n//-----------------------------------------------------------------------------\nPyObject *JM_convert_to_pdf(fz_context *ctx, fz_document *doc, int fp, int tp, int rotate)\n{\n    pdf_document *pdfout = pdf_create_document(ctx);  // new PDF document\n    int i, incr = 1, s = fp, e = tp;\n    if (fp > tp) {\n        incr = -1;           // count backwards\n        s = tp;              // adjust ...\n        e = fp;              // ... range\n    }\n    fz_rect mediabox;\n    int rot = JM_norm_rotation(rotate);\n    fz_device *dev = NULL;\n    fz_buffer *contents = NULL;\n    pdf_obj *resources = NULL;\n    fz_page *page=NULL;\n    fz_var(dev);\n    fz_var(contents);\n    fz_var(resources);\n    fz_var(page);\n    for (i = fp; INRANGE(i, s, e); i += incr) {  // interpret & write document pages as PDF pages\n        fz_try(ctx) {\n            page = fz_load_page(ctx, doc, i);\n            mediabox = fz_bound_page(ctx, page);\n            dev = pdf_page_write(ctx, pdfout, mediabox, &resources, &contents);\n            fz_run_page(ctx, page, dev, fz_identity, NULL);\n            fz_close_device(ctx, dev);\n            fz_drop_device(ctx, dev);\n            dev = NULL;\n            pdf_obj *page_obj = pdf_add_page(ctx, pdfout, mediabox, rot, resources, contents);\n            pdf_insert_page(ctx, pdfout, -1, page_obj);\n            pdf_drop_obj(ctx, page_obj);\n        }\n        fz_always(ctx) {\n            pdf_drop_obj(ctx, resources);\n            fz_drop_buffer(ctx, contents);\n            fz_drop_device(ctx, dev);\n            fz_drop_page(ctx, page);\n            page = NULL;\n            dev = NULL;\n            contents = NULL;\n            resources = NULL;\n        }\n        fz_catch(ctx) {\n            fz_rethrow(ctx);\n        }\n    }\n    // PDF created - now write it to Python bytearray\n    PyObject *r = NULL;\n    fz_output *out = NULL;\n    fz_buffer *res = NULL;\n    // prepare write options structure\n    pdf_write_options opts = { 0 };\n    opts.do_garbage         = 4;\n    opts.do_compress        = 1;\n    opts.do_compress_images = 1;\n    opts.do_compress_fonts  = 1;\n    opts.do_sanitize        = 1;\n    opts.do_incremental     = 0;\n    opts.do_ascii           = 0;\n    opts.do_decompress      = 0;\n    opts.do_linear          = 0;\n    opts.do_clean           = 1;\n    opts.do_pretty          = 0;\n\n    fz_try(ctx) {\n        res = fz_new_buffer(ctx, 8192);\n        out = fz_new_output_with_buffer(ctx, res);\n        pdf_write_document(ctx, pdfout, out, &opts);\n        unsigned char *c = NULL;\n        size_t len = fz_buffer_storage(ctx, res, &c);\n        r = PyBytes_FromStringAndSize((const char *) c, (Py_ssize_t) len);\n    }\n    fz_always(ctx) {\n        pdf_drop_document(ctx, pdfout);\n        fz_drop_output(ctx, out);\n        fz_drop_buffer(ctx, res);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return r;\n}\n%}\n"
  },
  {
    "path": "src_classic/helper-defines.i",
    "content": "%inline %{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//----------------------------------------------------------------------------\n// general\n//----------------------------------------------------------------------------\n#define EPSILON 1e-5\n\n//----------------------------------------------------------------------------\n// annotation types\n//----------------------------------------------------------------------------\n#define PDF_ANNOT_TEXT 0\n#define PDF_ANNOT_LINK 1\n#define PDF_ANNOT_FREE_TEXT 2\n#define PDF_ANNOT_LINE 3\n#define PDF_ANNOT_SQUARE 4\n#define PDF_ANNOT_CIRCLE 5\n#define PDF_ANNOT_POLYGON 6\n#define PDF_ANNOT_POLY_LINE 7\n#define PDF_ANNOT_HIGHLIGHT 8\n#define PDF_ANNOT_UNDERLINE 9\n#define PDF_ANNOT_SQUIGGLY 10\n#define PDF_ANNOT_STRIKE_OUT 11\n#define PDF_ANNOT_REDACT 12\n#define PDF_ANNOT_STAMP 13\n#define PDF_ANNOT_CARET 14\n#define PDF_ANNOT_INK 15\n#define PDF_ANNOT_POPUP 16\n#define PDF_ANNOT_FILE_ATTACHMENT 17\n#define PDF_ANNOT_SOUND 18\n#define PDF_ANNOT_MOVIE 19\n#define PDF_ANNOT_RICH_MEDIA 20\n#define PDF_ANNOT_WIDGET 21\n#define PDF_ANNOT_SCREEN 22\n#define PDF_ANNOT_PRINTER_MARK 23\n#define PDF_ANNOT_TRAP_NET 24\n#define PDF_ANNOT_WATERMARK 25\n#define PDF_ANNOT_3D 26\n#define PDF_ANNOT_PROJECTION 27\n#define PDF_ANNOT_UNKNOWN -1\n\n//------------------------\n// redaction annot options\n//------------------------\n#define PDF_REDACT_IMAGE_NONE 0\n#define PDF_REDACT_IMAGE_REMOVE 1\n#define PDF_REDACT_IMAGE_PIXELS 2\n\n//----------------------------------------------------------------------------\n// annotation flag bits\n//----------------------------------------------------------------------------\n#define PDF_ANNOT_IS_INVISIBLE 1 << (1-1)\n#define PDF_ANNOT_IS_HIDDEN 1 << (2-1)\n#define PDF_ANNOT_IS_PRINT 1 << (3-1)\n#define PDF_ANNOT_IS_NO_ZOOM 1 << (4-1)\n#define PDF_ANNOT_IS_NO_ROTATE 1 << (5-1)\n#define PDF_ANNOT_IS_NO_VIEW 1 << (6-1)\n#define PDF_ANNOT_IS_READ_ONLY 1 << (7-1)\n#define PDF_ANNOT_IS_LOCKED 1 << (8-1)\n#define PDF_ANNOT_IS_TOGGLE_NO_VIEW 1 << (9-1)\n#define PDF_ANNOT_IS_LOCKED_CONTENTS 1 << (10-1)\n\n\n//----------------------------------------------------------------------------\n// annotation line ending styles\n//----------------------------------------------------------------------------\n#define PDF_ANNOT_LE_NONE 0\n#define PDF_ANNOT_LE_SQUARE 1\n#define PDF_ANNOT_LE_CIRCLE 2\n#define PDF_ANNOT_LE_DIAMOND 3\n#define PDF_ANNOT_LE_OPEN_ARROW 4\n#define PDF_ANNOT_LE_CLOSED_ARROW 5\n#define PDF_ANNOT_LE_BUTT 6\n#define PDF_ANNOT_LE_R_OPEN_ARROW 7\n#define PDF_ANNOT_LE_R_CLOSED_ARROW 8\n#define PDF_ANNOT_LE_SLASH 9\n\n\n//----------------------------------------------------------------------------\n// annotation field (widget) types\n//----------------------------------------------------------------------------\n#define PDF_WIDGET_TYPE_UNKNOWN 0\n#define PDF_WIDGET_TYPE_BUTTON 1\n#define PDF_WIDGET_TYPE_CHECKBOX 2\n#define PDF_WIDGET_TYPE_COMBOBOX 3\n#define PDF_WIDGET_TYPE_LISTBOX 4\n#define PDF_WIDGET_TYPE_RADIOBUTTON 5\n#define PDF_WIDGET_TYPE_SIGNATURE 6\n#define PDF_WIDGET_TYPE_TEXT 7\n\n\n//----------------------------------------------------------------------------\n// annotation text widget subtypes\n//----------------------------------------------------------------------------\n#define PDF_WIDGET_TX_FORMAT_NONE 0\n#define PDF_WIDGET_TX_FORMAT_NUMBER 1\n#define PDF_WIDGET_TX_FORMAT_SPECIAL 2\n#define PDF_WIDGET_TX_FORMAT_DATE 3\n#define PDF_WIDGET_TX_FORMAT_TIME 4\n\n\n//----------------------------------------------------------------------------\n// annotation widget flags\n//----------------------------------------------------------------------------\n// Common to all field types\n#define PDF_FIELD_IS_READ_ONLY 1\n#define PDF_FIELD_IS_REQUIRED 1 << 1\n#define PDF_FIELD_IS_NO_EXPORT 1 << 2\n\n\n// Text fields\n#define PDF_TX_FIELD_IS_MULTILINE  1 << 12\n#define PDF_TX_FIELD_IS_PASSWORD  1 << 13\n#define PDF_TX_FIELD_IS_FILE_SELECT  1 << 20\n#define PDF_TX_FIELD_IS_DO_NOT_SPELL_CHECK  1 << 22\n#define PDF_TX_FIELD_IS_DO_NOT_SCROLL  1 << 23\n#define PDF_TX_FIELD_IS_COMB  1 << 24\n#define PDF_TX_FIELD_IS_RICH_TEXT  1 << 25\n\n\n// Button fields\n#define PDF_BTN_FIELD_IS_NO_TOGGLE_TO_OFF  1 << 14\n#define PDF_BTN_FIELD_IS_RADIO  1 << 15\n#define PDF_BTN_FIELD_IS_PUSHBUTTON  1 << 16\n#define PDF_BTN_FIELD_IS_RADIOS_IN_UNISON  1 << 25\n\n\n// Choice fields\n#define PDF_CH_FIELD_IS_COMBO  1 << 17\n#define PDF_CH_FIELD_IS_EDIT  1 << 18\n#define PDF_CH_FIELD_IS_SORT  1 << 19\n#define PDF_CH_FIELD_IS_MULTI_SELECT  1 << 21\n#define PDF_CH_FIELD_IS_DO_NOT_SPELL_CHECK  1 << 22\n#define PDF_CH_FIELD_IS_COMMIT_ON_SEL_CHANGE  1 << 25\n\n\n// Signature fields errors\n#define PDF_SIGNATURE_ERROR_OKAY 0\n#define PDF_SIGNATURE_ERROR_NO_SIGNATURES 1\n#define PDF_SIGNATURE_ERROR_NO_CERTIFICATE 2\n#define PDF_SIGNATURE_ERROR_DIGEST_FAILURE 3\n#define PDF_SIGNATURE_ERROR_SELF_SIGNED 4\n#define PDF_SIGNATURE_ERROR_SELF_SIGNED_IN_CHAIN 5\n#define PDF_SIGNATURE_ERROR_NOT_TRUSTED 6\n#define PDF_SIGNATURE_ERROR_UNKNOWN 7\n\n// Signature appearances\n\n#define PDF_SIGNATURE_SHOW_LABELS 1\n#define PDF_SIGNATURE_SHOW_DN 2\n#define PDF_SIGNATURE_SHOW_DATE 4\n#define PDF_SIGNATURE_SHOW_TEXT_NAME 8\n#define PDF_SIGNATURE_SHOW_GRAPHIC_NAME 16\n#define PDF_SIGNATURE_SHOW_LOGO 32\n#define PDF_SIGNATURE_DEFAULT_APPEARANCE ( \\\n\tPDF_SIGNATURE_SHOW_LABELS | \\\n\tPDF_SIGNATURE_SHOW_DN | \\\n\tPDF_SIGNATURE_SHOW_DATE | \\\n\tPDF_SIGNATURE_SHOW_TEXT_NAME | \\\n\tPDF_SIGNATURE_SHOW_GRAPHIC_NAME | \\\n\tPDF_SIGNATURE_SHOW_LOGO )\n\n//----------------------------------------------------------------------------\n// colorspace identifiers\n//----------------------------------------------------------------------------\n#define CS_RGB  1\n#define CS_GRAY 2\n#define CS_CMYK 3\n\n//----------------------------------------------------------------------------\n// PDF encryption algorithms\n//----------------------------------------------------------------------------\n#define PDF_ENCRYPT_KEEP 0\n#define PDF_ENCRYPT_NONE 1\n#define PDF_ENCRYPT_RC4_40 2\n#define PDF_ENCRYPT_RC4_128 3\n#define PDF_ENCRYPT_AES_128 4\n#define PDF_ENCRYPT_AES_256 5\n#define PDF_ENCRYPT_UNKNOWN 6\n\n//----------------------------------------------------------------------------\n// PDF permission codes\n//----------------------------------------------------------------------------\n#define PDF_PERM_PRINT 1 << 2\n#define PDF_PERM_MODIFY 1 << 3\n#define PDF_PERM_COPY 1 << 4\n#define PDF_PERM_ANNOTATE 1 << 5\n#define PDF_PERM_FORM 1 << 8\n#define PDF_PERM_ACCESSIBILITY 1 << 9\n#define PDF_PERM_ASSEMBLE 1 << 10\n#define PDF_PERM_PRINT_HQ 1 << 11\n\n//----------------------------------------------------------------------------\n// PDF Blend Modes\n//----------------------------------------------------------------------------\n#define PDF_BM_Color \"Color\"\n#define PDF_BM_ColorBurn \"ColorBurn\"\n#define PDF_BM_ColorDodge \"ColorDodge\"\n#define PDF_BM_Darken \"Darken\"\n#define PDF_BM_Difference \"Difference\"\n#define PDF_BM_Exclusion \"Exclusion\"\n#define PDF_BM_HardLight \"HardLight\"\n#define PDF_BM_Hue \"Hue\"\n#define PDF_BM_Lighten \"Lighten\"\n#define PDF_BM_Luminosity \"Luminosity\"\n#define PDF_BM_Multiply \"Multiply\"\n#define PDF_BM_Normal \"Normal\"\n#define PDF_BM_Overlay \"Overlay\"\n#define PDF_BM_Saturation \"Saturation\"\n#define PDF_BM_Screen \"Screen\"\n#define PDF_BM_SoftLight \"Softlight\"\n\n\n// General text flags\n#define TEXT_FONT_SUPERSCRIPT 1\n#define TEXT_FONT_ITALIC 2\n#define TEXT_FONT_SERIFED 4\n#define TEXT_FONT_MONOSPACED 8\n#define TEXT_FONT_BOLD 16\n\n// UCDN Script codes\n#define UCDN_SCRIPT_COMMON 0\n#define UCDN_SCRIPT_LATIN 1\n#define UCDN_SCRIPT_GREEK 2\n#define UCDN_SCRIPT_CYRILLIC 3\n#define UCDN_SCRIPT_ARMENIAN 4\n#define UCDN_SCRIPT_HEBREW 5\n#define UCDN_SCRIPT_ARABIC 6\n#define UCDN_SCRIPT_SYRIAC 7\n#define UCDN_SCRIPT_THAANA 8\n#define UCDN_SCRIPT_DEVANAGARI 9\n#define UCDN_SCRIPT_BENGALI 10\n#define UCDN_SCRIPT_GURMUKHI 11\n#define UCDN_SCRIPT_GUJARATI 12\n#define UCDN_SCRIPT_ORIYA 13\n#define UCDN_SCRIPT_TAMIL 14\n#define UCDN_SCRIPT_TELUGU 15\n#define UCDN_SCRIPT_KANNADA 16\n#define UCDN_SCRIPT_MALAYALAM 17\n#define UCDN_SCRIPT_SINHALA 18\n#define UCDN_SCRIPT_THAI 19\n#define UCDN_SCRIPT_LAO 20\n#define UCDN_SCRIPT_TIBETAN 21\n#define UCDN_SCRIPT_MYANMAR 22\n#define UCDN_SCRIPT_GEORGIAN 23\n#define UCDN_SCRIPT_HANGUL 24\n#define UCDN_SCRIPT_ETHIOPIC 25\n#define UCDN_SCRIPT_CHEROKEE 26\n#define UCDN_SCRIPT_CANADIAN_ABORIGINAL 27\n#define UCDN_SCRIPT_OGHAM 28\n#define UCDN_SCRIPT_RUNIC 29\n#define UCDN_SCRIPT_KHMER 30\n#define UCDN_SCRIPT_MONGOLIAN 31\n#define UCDN_SCRIPT_HIRAGANA 32\n#define UCDN_SCRIPT_KATAKANA 33\n#define UCDN_SCRIPT_BOPOMOFO 34\n#define UCDN_SCRIPT_HAN 35\n#define UCDN_SCRIPT_YI 36\n#define UCDN_SCRIPT_OLD_ITALIC 37\n#define UCDN_SCRIPT_GOTHIC 38\n#define UCDN_SCRIPT_DESERET 39\n#define UCDN_SCRIPT_INHERITED 40\n#define UCDN_SCRIPT_TAGALOG 41\n#define UCDN_SCRIPT_HANUNOO 42\n#define UCDN_SCRIPT_BUHID 43\n#define UCDN_SCRIPT_TAGBANWA 44\n#define UCDN_SCRIPT_LIMBU 45\n#define UCDN_SCRIPT_TAI_LE 46\n#define UCDN_SCRIPT_LINEAR_B 47\n#define UCDN_SCRIPT_UGARITIC 48\n#define UCDN_SCRIPT_SHAVIAN 49\n#define UCDN_SCRIPT_OSMANYA 50\n#define UCDN_SCRIPT_CYPRIOT 51\n#define UCDN_SCRIPT_BRAILLE 52\n#define UCDN_SCRIPT_BUGINESE 53\n#define UCDN_SCRIPT_COPTIC 54\n#define UCDN_SCRIPT_NEW_TAI_LUE 55\n#define UCDN_SCRIPT_GLAGOLITIC 56\n#define UCDN_SCRIPT_TIFINAGH 57\n#define UCDN_SCRIPT_SYLOTI_NAGRI 58\n#define UCDN_SCRIPT_OLD_PERSIAN 59\n#define UCDN_SCRIPT_KHAROSHTHI 60\n#define UCDN_SCRIPT_BALINESE 61\n#define UCDN_SCRIPT_CUNEIFORM 62\n#define UCDN_SCRIPT_PHOENICIAN 63\n#define UCDN_SCRIPT_PHAGS_PA 64\n#define UCDN_SCRIPT_NKO 65\n#define UCDN_SCRIPT_SUNDANESE 66\n#define UCDN_SCRIPT_LEPCHA 67\n#define UCDN_SCRIPT_OL_CHIKI 68\n#define UCDN_SCRIPT_VAI 69\n#define UCDN_SCRIPT_SAURASHTRA 70\n#define UCDN_SCRIPT_KAYAH_LI 71\n#define UCDN_SCRIPT_REJANG 72\n#define UCDN_SCRIPT_LYCIAN 73\n#define UCDN_SCRIPT_CARIAN 74\n#define UCDN_SCRIPT_LYDIAN 75\n#define UCDN_SCRIPT_CHAM 76\n#define UCDN_SCRIPT_TAI_THAM 77\n#define UCDN_SCRIPT_TAI_VIET 78\n#define UCDN_SCRIPT_AVESTAN 79\n#define UCDN_SCRIPT_EGYPTIAN_HIEROGLYPHS 80\n#define UCDN_SCRIPT_SAMARITAN 81\n#define UCDN_SCRIPT_LISU 82\n#define UCDN_SCRIPT_BAMUM 83\n#define UCDN_SCRIPT_JAVANESE 84\n#define UCDN_SCRIPT_MEETEI_MAYEK 85\n#define UCDN_SCRIPT_IMPERIAL_ARAMAIC 86\n#define UCDN_SCRIPT_OLD_SOUTH_ARABIAN 87\n#define UCDN_SCRIPT_INSCRIPTIONAL_PARTHIAN 88\n#define UCDN_SCRIPT_INSCRIPTIONAL_PAHLAVI 89\n#define UCDN_SCRIPT_OLD_TURKIC 90\n#define UCDN_SCRIPT_KAITHI 91\n#define UCDN_SCRIPT_BATAK 92\n#define UCDN_SCRIPT_BRAHMI 93\n#define UCDN_SCRIPT_MANDAIC 94\n#define UCDN_SCRIPT_CHAKMA 95\n#define UCDN_SCRIPT_MEROITIC_CURSIVE 96\n#define UCDN_SCRIPT_MEROITIC_HIEROGLYPHS 97\n#define UCDN_SCRIPT_MIAO 98\n#define UCDN_SCRIPT_SHARADA 99\n#define UCDN_SCRIPT_SORA_SOMPENG 100\n#define UCDN_SCRIPT_TAKRI 101\n#define UCDN_SCRIPT_UNKNOWN 102\n#define UCDN_SCRIPT_BASSA_VAH 103\n#define UCDN_SCRIPT_CAUCASIAN_ALBANIAN 104\n#define UCDN_SCRIPT_DUPLOYAN 105\n#define UCDN_SCRIPT_ELBASAN 106\n#define UCDN_SCRIPT_GRANTHA 107\n#define UCDN_SCRIPT_KHOJKI 108\n#define UCDN_SCRIPT_KHUDAWADI 109\n#define UCDN_SCRIPT_LINEAR_A 110\n#define UCDN_SCRIPT_MAHAJANI 111\n#define UCDN_SCRIPT_MANICHAEAN 112\n#define UCDN_SCRIPT_MENDE_KIKAKUI 113\n#define UCDN_SCRIPT_MODI 114\n#define UCDN_SCRIPT_MRO 115\n#define UCDN_SCRIPT_NABATAEAN 116\n#define UCDN_SCRIPT_OLD_NORTH_ARABIAN 117\n#define UCDN_SCRIPT_OLD_PERMIC 118\n#define UCDN_SCRIPT_PAHAWH_HMONG 119\n#define UCDN_SCRIPT_PALMYRENE 120\n#define UCDN_SCRIPT_PAU_CIN_HAU 121\n#define UCDN_SCRIPT_PSALTER_PAHLAVI 122\n#define UCDN_SCRIPT_SIDDHAM 123\n#define UCDN_SCRIPT_TIRHUTA 124\n#define UCDN_SCRIPT_WARANG_CITI 125\n#define UCDN_SCRIPT_AHOM 126\n#define UCDN_SCRIPT_ANATOLIAN_HIEROGLYPHS 127\n#define UCDN_SCRIPT_HATRAN 128\n#define UCDN_SCRIPT_MULTANI 129\n#define UCDN_SCRIPT_OLD_HUNGARIAN 130\n#define UCDN_SCRIPT_SIGNWRITING 131\n#define UCDN_SCRIPT_ADLAM 132\n#define UCDN_SCRIPT_BHAIKSUKI 133\n#define UCDN_SCRIPT_MARCHEN 134\n#define UCDN_SCRIPT_NEWA 135\n#define UCDN_SCRIPT_OSAGE 136\n#define UCDN_SCRIPT_TANGUT 137\n#define UCDN_SCRIPT_MASARAM_GONDI 138\n#define UCDN_SCRIPT_NUSHU 139\n#define UCDN_SCRIPT_SOYOMBO 140\n#define UCDN_SCRIPT_ZANABAZAR_SQUARE 141\n#define UCDN_SCRIPT_DOGRA 142\n#define UCDN_SCRIPT_GUNJALA_GONDI 143\n#define UCDN_SCRIPT_HANIFI_ROHINGYA 144\n#define UCDN_SCRIPT_MAKASAR 145\n#define UCDN_SCRIPT_MEDEFAIDRIN 146\n#define UCDN_SCRIPT_OLD_SOGDIAN 147\n#define UCDN_SCRIPT_SOGDIAN 148\n#define UCDN_SCRIPT_ELYMAIC 149\n#define UCDN_SCRIPT_NANDINAGARI 150\n#define UCDN_SCRIPT_NYIAKENG_PUACHUE_HMONG 151\n#define UCDN_SCRIPT_WANCHO 152\n\n\n// exceptions\nPyObject *_set_FileDataError(PyObject *value)\n{\n\tif (!value) {\n\t\tPy_RETURN_FALSE;\n\t}\n\tJM_Exc_FileDataError = value;\n\tPy_RETURN_TRUE;\n}\n\n//-------------------------------------------------------------------\n// minor tools\n//-------------------------------------------------------------------\nPyObject *util_sine_between(PyObject *C, PyObject *P, PyObject *Q)\n{\n\t// for points C, P, Q compute the sine between lines CP and QP\n\tfz_point c = JM_point_from_py(C);\n\tfz_point p = JM_point_from_py(P);\n\tfz_point q = JM_point_from_py(Q);\n\tfz_point s = JM_normalize_vector(q.x - p.x, q.y - p.y);\n\tfz_matrix m1 = fz_make_matrix(1, 0, 0, 1, -p.x, -p.y);\n\tfz_matrix m2 = fz_make_matrix(s.x, -s.y, s.y, s.x, 0, 0);\n\tm1 = fz_concat(m1, m2);\n\tc = fz_transform_point(c, m1);\n\tc = JM_normalize_vector(c.x, c.y);\n\treturn Py_BuildValue(\"f\", c.y);\n}\n\n\n// Return the matrix that maps two points C, P to the x-axis such that\n// C -> (0,0) and the image of P have the same distance.\nPyObject *util_hor_matrix(PyObject *C, PyObject *P)\n{\n\tfz_point c = JM_point_from_py(C);\n\tfz_point p = JM_point_from_py(P);\n\n\t// compute (cosine, sine) of vector P-C with double precision:\n\tfz_point s = JM_normalize_vector(p.x - c.x, p.y - c.y);\n\n\tfz_matrix m1 = fz_make_matrix(1, 0, 0, 1, -c.x, -c.y);\n\tfz_matrix m2 = fz_make_matrix(s.x, -s.y, s.y, s.x, 0, 0);\n\treturn JM_py_from_matrix(fz_concat(m1, m2));\n}\n\nstruct Annot;\n\n// Ensure that widgets with /AA/C JavaScript are in array AcroForm/CO\nstruct Annot;\nPyObject *util_ensure_widget_calc(struct Annot *annot)\n{\n\tpdf_obj *PDFNAME_CO=NULL;\n\tfz_try(gctx) {\n\t\tpdf_obj *annot_obj = pdf_annot_obj(gctx, (pdf_annot *) annot);\n\t\tpdf_document *pdf = pdf_get_bound_document(gctx, annot_obj);\n\t\tPDFNAME_CO = pdf_new_name(gctx, \"CO\");  // = PDF_NAME(CO)\n\t\tpdf_obj *acro = pdf_dict_getl(gctx,  // get AcroForm dict\n\t\t\t\t\t\tpdf_trailer(gctx, pdf),\n\t\t\t\t\t\tPDF_NAME(Root),\n\t\t\t\t\t\tPDF_NAME(AcroForm),\n\t\t\t\t\t\tNULL);\n\n\t\tpdf_obj *CO = pdf_dict_get(gctx, acro, PDFNAME_CO);  // = AcroForm/CO\n\t\tif (!CO) {\n\t\t\tCO = pdf_dict_put_array(gctx, acro, PDFNAME_CO, 2);\n\t\t}\n\t\tint i, n = pdf_array_len(gctx, CO);\n\t\tint xref, nxref, found = 0;\n\t\txref = pdf_to_num(gctx, annot_obj);\n\t\tfor (i = 0; i < n; i++) {\n\t\t\tnxref = pdf_to_num(gctx, pdf_array_get(gctx, CO, i));\n\t\t\tif (xref == nxref) {\n\t\t\t\tfound = 1;\n\t\t\t\tbreak;\n\t\t\t}\n\t\t}\n\t\tif (!found) {\n\t\t\tpdf_array_push_drop(gctx, CO, pdf_new_indirect(gctx, pdf, xref, 0));\n\t\t}\n\t}\n\tfz_always(gctx) {\n\t\tpdf_drop_obj(gctx, PDFNAME_CO);\n\t}\n\tfz_catch(gctx) {\n\t\tPyErr_SetString(PyExc_RuntimeError, fz_caught_message(gctx));\n\t\treturn NULL;\n\t}\n\tPy_RETURN_NONE;\n}\n\n\n//-----------------------------------------------------------\n// Compute Rect coordinates using different alternatives\n//-----------------------------------------------------------\nPyObject *util_make_rect(PyObject *a)\n{\n\tPy_ssize_t i, n = PyTuple_GET_SIZE(a);\n\tPyObject *p1, *p2, *l = a;\n\tchar *msg = \"Rect: bad args\";\n\tdouble c[4] = { 0, 0, 0, 0 };\n\tswitch (n) {\n\t\tcase 0: goto exit_normal;\n\t\tcase 1: goto size1;\n\t\tcase 2: goto size2;\n\t\tcase 3: goto size31;\n\t\tcase 4: goto size4;\n\t\tdefault:\n\t\t\tmsg = \"Rect: bad seq len\";\n\t\t\tgoto exit_error;\n\t}\n\n\tsize4:;\n\t\tfor (i = 0; i < 4; i++) {\n\t\t\tif (JM_FLOAT_ITEM(l, i, &c[i]) == 1) {\n\t\t\t\tgoto exit_error;\n\t\t\t}\n\t\t}\n\t\tgoto exit_normal;\n\n\tsize1:;\n\t\tl = PyTuple_GET_ITEM(a, 0);\n\t\tif (!PySequence_Check(l) || PySequence_Size(l) != 4) {\n\t\t\tmsg = \"Rect: bad seq len\";\n\t\t\tgoto exit_error;\n\t\t}\n\t\tgoto size4;\n\n\tsize2:;\n\t\tmsg = \"Rect: bad args\";\n\t\tp1 = PyTuple_GET_ITEM(a, 0);\n\t\tp2 = PyTuple_GET_ITEM(a, 1);\n\t\tif (!PySequence_Check(p1) || PySequence_Size(p1) != 2) {\n\t\t\tgoto exit_error;\n\t\t}\n\t\tif (!PySequence_Check(p2) || PySequence_Size(p2) != 2) {\n\t\t\tgoto exit_error;\n\t\t}\n\t\tif (JM_FLOAT_ITEM(p1, 0, &c[0]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(p1, 1, &c[1]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(p2, 0, &c[2]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(p2, 1, &c[3]) == 1) goto exit_error;\n\t\tgoto exit_normal;\n\n\tsize31:;\n\t\tp1 = PyTuple_GET_ITEM(a, 0);\n\t\tif (PySequence_Check(p1)) goto size32;\n\t\tif (JM_FLOAT_ITEM(a, 0, &c[0]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(a, 1, &c[1]) == 1) goto exit_error;\n\t\tp2 = PyTuple_GET_ITEM(a, 2);\n\t\tif (!PySequence_Check(p2) || PySequence_Size(p2) != 2) {\n\t\t\tgoto exit_error;\n\t\t}\n\t\tif (JM_FLOAT_ITEM(p2, 0, &c[2]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(p2, 1, &c[3]) == 1) goto exit_error;\n\t\tgoto exit_normal;\n\n\tsize32:;\n\t\tif (PySequence_Size(p1) != 2) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(p1, 0, &c[0]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(p1, 1, &c[1]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(a, 1, &c[2]) == 1) goto exit_error;\n\t\tif (JM_FLOAT_ITEM(a, 2, &c[3]) == 1) goto exit_error;\n\t\tgoto exit_normal;\n\n\texit_normal:;\n\t\tfor (i = 0; i < 4; i++) {\n\t\t\tif (c[i] < FZ_MIN_INF_RECT) c[i] = FZ_MIN_INF_RECT;\n\t\t\tif (c[i] > FZ_MAX_INF_RECT) c[i] = FZ_MAX_INF_RECT;\n\t\t}\n\t\treturn Py_BuildValue(\"dddd\", c[0], c[1], c[2], c[3]);\n\n\texit_error:;\n\t\tPyErr_SetString(PyExc_ValueError, msg);\n\t\treturn NULL;\n}\n\n\n//-----------------------------------------------------------\n// Compute IRect coordinates using different alternatives\n//-----------------------------------------------------------\nPyObject *util_make_irect(PyObject *a)\n{\n\tPy_ssize_t i, n = PyTuple_GET_SIZE(a);\n\tPyObject *p1, *p2, *l = a;\n\tchar *msg = \"IRect: bad args\";\n\tint c[4] = { 0, 0, 0, 0 };\n\tswitch (n) {\n\t\tcase 0: goto exit_normal;\n\t\tcase 1: goto size1;\n\t\tcase 2: goto size2;\n\t\tcase 3: goto size31;\n\t\tcase 4: goto size4;\n\t\tdefault:\n\t\t\tmsg = \"IRect: bad seq len\";\n\t\t\tgoto exit_error;\n\t}\n\n\tsize4:;\n\t\tfor (i = 0; i < 4; i++) {\n\t\t\tif (JM_INT_ITEM(l, i, &c[i]) == 1) {\n\t\t\t\tgoto exit_error;\n\t\t\t}\n\t\t}\n\t\tgoto exit_normal;\n\n\tsize1:;\n\t\tl = PyTuple_GET_ITEM(a, 0);\n\t\tif (!PySequence_Check(l) || PySequence_Size(l) != 4) {\n\t\t\tmsg = \"IRect: bad seq len\";\n\t\t\tgoto exit_error;\n\t\t}\n\t\tgoto size4;\n\n\tsize2:;\n\t\tp1 = PyTuple_GET_ITEM(a, 0);\n\t\tp2 = PyTuple_GET_ITEM(a, 1);\n\t\tif (!PySequence_Check(p1) || PySequence_Size(p1) != 2) {\n\t\t\tgoto exit_error;\n\t\t}\n\t\tif (!PySequence_Check(p2) || PySequence_Size(p2) != 2) {\n\t\t\tgoto exit_error;\n\t\t}\n\t\tmsg = \"IRect: bad int values\";\n\t\tif (JM_INT_ITEM(p1, 0, &c[0]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(p1, 1, &c[1]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(p2, 0, &c[2]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(p2, 1, &c[3]) == 1) goto exit_error;\n\t\tgoto exit_normal;\n\n\tsize31:;\n\t\tp1 = PyTuple_GET_ITEM(a, 0);\n\t\tif (PySequence_Check(p1)) goto size32;\n\t\tif (JM_INT_ITEM(a, 0, &c[0]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(a, 1, &c[1]) == 1) goto exit_error;\n\t\tp2 = PyTuple_GET_ITEM(a, 2);\n\t\tif (!PySequence_Check(p2) || PySequence_Size(p2) != 2) {\n\t\t\tgoto exit_error;\n\t\t}\n\t\tif (JM_INT_ITEM(p2, 0, &c[2]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(p2, 1, &c[3]) == 1) goto exit_error;\n\t\tgoto exit_normal;\n\n\tsize32:;\n\t\tif (PySequence_Size(p1) != 2) goto exit_error;\n\t\tif (JM_INT_ITEM(p1, 0, &c[0]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(p1, 1, &c[1]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(a, 1, &c[2]) == 1) goto exit_error;\n\t\tif (JM_INT_ITEM(a, 2, &c[3]) == 1) goto exit_error;\n\t\tgoto exit_normal;\n\n\texit_normal:;\n\t\tfor (i = 0; i < 4; i++) {\n\t\t\tif (c[i] < FZ_MIN_INF_RECT) c[i] = FZ_MIN_INF_RECT;\n\t\t\tif (c[i] > FZ_MAX_INF_RECT) c[i] = FZ_MAX_INF_RECT;\n\t\t}\n\t\treturn Py_BuildValue(\"iiii\", c[0], c[1], c[2], c[3]);\n\n\texit_error:;\n\t\tPyErr_SetString(PyExc_ValueError, msg);\n\t\treturn NULL;\n}\n\n\nPyObject *util_round_rect(PyObject *rect)\n{\n\treturn JM_py_from_irect(fz_round_rect(JM_rect_from_py(rect)));\n}\n\n\nPyObject *util_transform_rect(PyObject *rect, PyObject *matrix)\n{\n\treturn JM_py_from_rect(fz_transform_rect(JM_rect_from_py(rect), JM_matrix_from_py(matrix)));\n}\n\n\nPyObject *util_intersect_rect(PyObject *r1, PyObject *r2)\n{\n\treturn JM_py_from_rect(fz_intersect_rect(JM_rect_from_py(r1),\n\t\t\t\t\t\t\t\t\t\t\t\tJM_rect_from_py(r2)));\n}\n\n\nPyObject *util_is_point_in_rect(PyObject *p, PyObject *r)\n{\n\treturn JM_BOOL(fz_is_point_inside_rect(JM_point_from_py(p), JM_rect_from_py(r)));\n}\n\n\nPyObject *util_include_point_in_rect(PyObject *r, PyObject *p)\n{\n\treturn JM_py_from_rect(fz_include_point_in_rect(JM_rect_from_py(r),\n\t\t\t\t\t\t\t\t\t\t\t\tJM_point_from_py(p)));\n}\n\n\nPyObject *util_point_in_quad(PyObject *P, PyObject *Q)\n{\n\tfz_point p = JM_point_from_py(P);\n\tfz_quad q = JM_quad_from_py(Q);\n\treturn JM_BOOL(fz_is_point_inside_quad(p, q));\n}\n\n\nPyObject *util_transform_point(PyObject *point, PyObject *matrix)\n{\n\treturn JM_py_from_point(fz_transform_point(JM_point_from_py(point), JM_matrix_from_py(matrix)));\n}\n\n\nPyObject *util_union_rect(PyObject *r1, PyObject *r2)\n{\n\treturn JM_py_from_rect(fz_union_rect(JM_rect_from_py(r1),\n\t\t\t\t\t\t\t\t\t\t\tJM_rect_from_py(r2)));\n}\n\n\nPyObject *util_concat_matrix(PyObject *m1, PyObject *m2)\n{\n\treturn JM_py_from_matrix(fz_concat(JM_matrix_from_py(m1),\n\t\t\t\t\t\t\t\t\t\tJM_matrix_from_py(m2)));\n}\n\n\nPyObject *util_invert_matrix(PyObject *matrix)\n{\n\tfz_matrix src = JM_matrix_from_py(matrix);\n\tfloat a = src.a;\n\tfloat det = a * src.d - src.b * src.c;\n\tif (det < -FLT_EPSILON || det > FLT_EPSILON)\n\t{\n\t\tfz_matrix dst;\n\t\tfloat rdet = 1 / det;\n\t\tdst.a = src.d * rdet;\n\t\tdst.b = -src.b * rdet;\n\t\tdst.c = -src.c * rdet;\n\t\tdst.d = a * rdet;\n\t\ta = -src.e * dst.a - src.f * dst.c;\n\t\tdst.f = -src.e * dst.b - src.f * dst.d;\n\t\tdst.e = a;\n\t\treturn Py_BuildValue(\"iN\", 0, JM_py_from_matrix(dst));\n\t}\n\treturn Py_BuildValue(\"(i, ())\", 1);\n}\n\n\nPyObject *util_measure_string(const char *text, const char *fontname, double fontsize, int encoding)\n{\n\tdouble w = 0;\n\tfz_font *font = NULL;\n\tfz_try(gctx) {\n\t\tfont = fz_new_base14_font(gctx, fontname);\n\t\twhile (*text)\n\t\t{\n\t\t\tint c, g;\n\t\t\ttext += fz_chartorune(&c, text);\n\t\t\tswitch (encoding)\n\t\t\t{\n\t\t\t\tcase PDF_SIMPLE_ENCODING_GREEK:\n\t\t\t\t\tc = fz_iso8859_7_from_unicode(c); break;\n\t\t\t\tcase PDF_SIMPLE_ENCODING_CYRILLIC:\n\t\t\t\t\tc = fz_windows_1251_from_unicode(c); break;\n\t\t\t\tdefault:\n\t\t\t\t\tc = fz_windows_1252_from_unicode(c); break;\n\t\t\t}\n\t\t\tif (c < 0) c = 0xB7;\n\t\t\tg = fz_encode_character(gctx, font, c);\n\t\t\tw += (double) fz_advance_glyph(gctx, font, g, 0);\n\t\t}\n\t}\n\tfz_always(gctx) {\n\t\tfz_drop_font(gctx, font);\n\t}\n\tfz_catch(gctx) {\n\t\treturn PyFloat_FromDouble(0);\n\t}\n\treturn PyFloat_FromDouble(w * fontsize);\n}\n\n%}\n\n%{\n// Global Constants - Python dictionary keys\nPyObject *dictkey_align;\nPyObject *dictkey_ascender;\nPyObject *dictkey_bbox;\nPyObject *dictkey_blocks;\nPyObject *dictkey_bpc;\nPyObject *dictkey_c;\nPyObject *dictkey_chars;\nPyObject *dictkey_color;\nPyObject *dictkey_colorspace;\nPyObject *dictkey_content;\nPyObject *dictkey_creationDate;\nPyObject *dictkey_cs_name;\nPyObject *dictkey_da;\nPyObject *dictkey_dashes;\nPyObject *dictkey_desc;\nPyObject *dictkey_descender;\nPyObject *dictkey_dir;\nPyObject *dictkey_effect;\nPyObject *dictkey_ext;\nPyObject *dictkey_filename;\nPyObject *dictkey_fill;\nPyObject *dictkey_flags;\nPyObject *dictkey_font;\nPyObject *dictkey_glyph;\nPyObject *dictkey_height;\nPyObject *dictkey_id;\nPyObject *dictkey_image;\nPyObject *dictkey_items;\nPyObject *dictkey_length;\nPyObject *dictkey_lines;\nPyObject *dictkey_matrix;\nPyObject *dictkey_modDate;\nPyObject *dictkey_name;\nPyObject *dictkey_number;\nPyObject *dictkey_origin;\nPyObject *dictkey_rect;\nPyObject *dictkey_size;\nPyObject *dictkey_smask;\nPyObject *dictkey_spans;\nPyObject *dictkey_stroke;\nPyObject *dictkey_style;\nPyObject *dictkey_subject;\nPyObject *dictkey_text;\nPyObject *dictkey_title;\nPyObject *dictkey_type;\nPyObject *dictkey_ufilename;\nPyObject *dictkey_width;\nPyObject *dictkey_wmode;\nPyObject *dictkey_xref;\nPyObject *dictkey_xres;\nPyObject *dictkey_yres;\n%}\n"
  },
  {
    "path": "src_classic/helper-devices.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\ntypedef struct\n{\n\tfz_device super;\n\tPyObject *out;\n\tsize_t seqno;\n\tlong depth;\n\tint clips;\n\tPyObject *method;\n} jm_lineart_device;\n\nstatic PyObject *dev_pathdict = NULL;\nstatic PyObject *scissors = NULL;\nstatic float dev_linewidth = 0;  // border width if present\nstatic fz_matrix trace_device_ptm;  // page transformation matrix\nstatic fz_matrix trace_device_ctm;  // trace device matrix\nstatic fz_matrix trace_device_rot;\nstatic fz_point dev_lastpoint = {0, 0};\nstatic fz_point dev_firstpoint = {0, 0};\nstatic int dev_havemove = 0;\nstatic fz_rect dev_pathrect;\nstatic float dev_pathfactor = 0;\nstatic int dev_linecount = 0;\nstatic char *layer_name=NULL; // optional content name\nstatic int path_type = 0;  // one of the following values:\n#define FILL_PATH 1\n#define STROKE_PATH 2\n#define CLIP_PATH 3\n#define CLIP_STROKE_PATH 4\n\nstatic void trace_device_reset()\n{\n    Py_CLEAR(dev_pathdict);\n    Py_CLEAR(scissors);\n\tlayer_name = NULL;\n    dev_linewidth = 0;\n    trace_device_ptm = fz_identity;\n    trace_device_ctm = fz_identity;\n    trace_device_rot = fz_identity;\n    dev_lastpoint.x = 0;\n    dev_lastpoint.y = 0;\n    dev_firstpoint.x = 0;\n    dev_firstpoint.y = 0;\n    dev_pathrect.x0 = 0;\n    dev_pathrect.y0 = 0;\n    dev_pathrect.x1 = 0;\n    dev_pathrect.y1 = 0;\n    dev_pathfactor = 0;\n    dev_linecount = 0;\n    path_type = 0;\n}\n\n// Every scissor of a clip is a sub rectangle of the preceeding clip\n// scissor if the clip level is larger.\nstatic fz_rect compute_scissor()\n{\n\tPyObject *last_scissor = NULL;\n\tfz_rect scissor;\n\tif (!scissors) {\n\t\tscissors = PyList_New(0);\n\t}\n\tPy_ssize_t num_scissors = PyList_Size(scissors);\n\tif (num_scissors > 0) {\n\t\tlast_scissor = PyList_GET_ITEM(scissors, num_scissors-1);\n\t\tscissor = JM_rect_from_py(last_scissor);\n\t\tscissor = fz_intersect_rect(scissor, dev_pathrect);\n\t} else {\n\t\tscissor = dev_pathrect;\n\t}\n\tLIST_APPEND_DROP(scissors, JM_py_from_rect(scissor));\n\treturn scissor;\n}\n\n\nstatic void\njm_increase_seqno(fz_context *ctx, fz_device *dev_, ...)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *) dev_;\n\tdev->seqno += 1;\n}\n\n/*\n--------------------------------------------------------------------------\nCheck whether the last 4 lines represent a quad.\nBecause of how we count, the lines are a polyline already, i.e. last point\nof a line equals 1st point of next line.\nSo we check for a polygon (last line's end point equals start point).\nIf not true we return 0.\n--------------------------------------------------------------------------\n*/\nstatic int\njm_checkquad()\n{\n\tPyObject *items = PyDict_GetItem(dev_pathdict, dictkey_items);\n\tPy_ssize_t i, len = PyList_Size(items);\n\tfloat f[8]; // coordinates of the 4 corners\n\tfz_point temp, lp; // line = (temp, lp)\n\tPyObject *rect;\n\tPyObject *line;\n\t// fill the 8 floats in f, start from items[-4:]\n\tfor (i = 0; i < 4; i++) {  // store line start points\n\t\tline = PyList_GET_ITEM(items, len - 4 + i);\n\t\ttemp = JM_point_from_py(PyTuple_GET_ITEM(line, 1));\n\t\tf[i * 2] = temp.x;\n\t\tf[i * 2 + 1] = temp.y;\n\t\tlp = JM_point_from_py(PyTuple_GET_ITEM(line, 2));\n\t}\n\tif (lp.x != f[0] || lp.y != f[1]) {\n\t\t// not a polygon!\n\t\t//dev_linecount -= 1;\n\t\treturn 0;\n\t}\n\n\t// we have detected a quad\n\tdev_linecount = 0;  // reset this\n\t// a quad item is (\"qu\", (ul, ur, ll, lr)), where the tuple items\n\t// are pairs of floats representing a quad corner each.\n\trect = PyTuple_New(2);\n\tPyTuple_SET_ITEM(rect, 0, PyUnicode_FromString(\"qu\"));\n\t/* ----------------------------------------------------\n\t* relationship of float array to quad points:\n\t* (0, 1) = ul, (2, 3) = ll, (6, 7) = ur, (4, 5) = lr\n\t---------------------------------------------------- */\n\tfz_quad q = fz_make_quad(f[0], f[1], f[6], f[7], f[2], f[3], f[4], f[5]);\n\tPyTuple_SET_ITEM(rect, 1, JM_py_from_quad(q));\n\tPyList_SetItem(items, len - 4, rect); // replace item -4 by rect\n\tPyList_SetSlice(items, len - 3, len, NULL); // delete remaining 3 items\n\treturn 1;\n}\n\n\n/*\n--------------------------------------------------------------------------\nCheck whether the last 3 path items represent a rectangle.\nLine 1 and 3 must be horizontal, line 2 must be vertical.\nReturns 1 if we have modified the path, otherwise 0.\n--------------------------------------------------------------------------\n*/\nstatic int\njm_checkrect()\n{\n\tdev_linecount = 0; // reset line count\n\tlong orientation = 0; // area orientation of rectangle\n\tfz_point ll, lr, ur, ul;\n\tfz_rect r;\n\tPyObject *rect;\n\tPyObject *line0, *line2;\n\tPyObject *items = PyDict_GetItem(dev_pathdict, dictkey_items);\n\tPy_ssize_t len = PyList_Size(items);\n\n\tline0 = PyList_GET_ITEM(items, len - 3);\n\tll = JM_point_from_py(PyTuple_GET_ITEM(line0, 1));\n\tlr = JM_point_from_py(PyTuple_GET_ITEM(line0, 2));\n\t// no need to extract \"line1\"!\n\tline2 = PyList_GET_ITEM(items, len - 1);\n\tur = JM_point_from_py(PyTuple_GET_ITEM(line2, 1));\n\tul = JM_point_from_py(PyTuple_GET_ITEM(line2, 2));\n\n\t/*\n\t---------------------------------------------------------------------\n\tAssumption:\n\tWhen decomposing rects, MuPDF always starts with a horizontal line,\n\tfollowed by a vertical line, followed by a horizontal line.\n\tFirst line: (ll, lr), third line: (ul, ur).\n\tIf 1st line is below 3rd line, we record anti-clockwise (+1), else\n\tclockwise (-1) orientation.\n\t---------------------------------------------------------------------\n\t*/\n\tif (ll.y != lr.y ||\n\t\tll.x != ul.x ||\n\t\tur.y != ul.y ||\n\t\tur.x != lr.x) {\n\t\tgoto drop_out;  // not a rectangle\n\t}\n\n\t// we have a rect, replace last 3 \"l\" items by one \"re\" item.\n\tif (ul.y < lr.y) {\n\t\tr = fz_make_rect(ul.x, ul.y, lr.x, lr.y);\n\t\torientation = 1;\n\t} else {\n\t\tr = fz_make_rect(ll.x, ll.y, ur.x, ur.y);\n\t\torientation = -1;\n\t}\n\trect = PyTuple_New(3);\n\tPyTuple_SET_ITEM(rect, 0, PyUnicode_FromString(\"re\"));\n\tPyTuple_SET_ITEM(rect, 1, JM_py_from_rect(r));\n\tPyTuple_SET_ITEM(rect, 2, PyLong_FromLong(orientation));\n\tPyList_SetItem(items, len - 3, rect); // replace item -3 by rect\n\tPyList_SetSlice(items, len - 2, len, NULL); // delete remaining 2 items\n\treturn 1;\n\tdrop_out:;\n\treturn 0;\n}\n\nstatic PyObject *\njm_lineart_color(fz_context *ctx, fz_colorspace *colorspace, const float *color)\n{\n\tfloat rgb[3];\n\tif (colorspace) {\n\t\tfz_convert_color(ctx, colorspace, color, fz_device_rgb(ctx),\n\t\t                 rgb, NULL, fz_default_color_params);\n\t\treturn Py_BuildValue(\"fff\", rgb[0], rgb[1], rgb[2]);\n\t}\n\treturn PyTuple_New(0);\n}\n\nstatic void\ntrace_moveto(fz_context *ctx, void *dev_, float x, float y)\n{\n\tdev_lastpoint = fz_transform_point(fz_make_point(x, y), trace_device_ctm);\n\tif (fz_is_infinite_rect(dev_pathrect)) {\n\t\tdev_pathrect = fz_make_rect(dev_lastpoint.x, dev_lastpoint.y,\n\t\t                            dev_lastpoint.x, dev_lastpoint.y);\n\t}\n\tdev_firstpoint = dev_lastpoint;\n\tdev_havemove = 1;\n\tdev_linecount = 0;  // reset # of consec. lines\n}\n\nstatic void\ntrace_lineto(fz_context *ctx, void *dev_, float x, float y)\n{\n\tfz_point p1 = fz_transform_point(fz_make_point(x, y), trace_device_ctm);\n\tdev_pathrect = fz_include_point_in_rect(dev_pathrect, p1);\n    PyObject *list = PyTuple_New(3);\n\tPyTuple_SET_ITEM(list, 0, PyUnicode_FromString(\"l\"));\n\tPyTuple_SET_ITEM(list, 1, JM_py_from_point(dev_lastpoint));\n\tPyTuple_SET_ITEM(list, 2, JM_py_from_point(p1));\n\tdev_lastpoint = p1;\n\tPyObject *items = PyDict_GetItem(dev_pathdict, dictkey_items);\n\tLIST_APPEND_DROP(items, list);\n\tdev_linecount += 1;  // counts consecutive lines\n\tif (dev_linecount == 4 && path_type != FILL_PATH) {  // shrink to \"re\" or \"qu\" item\n\t\tjm_checkquad();\n\t}\n}\n\nstatic void\ntrace_curveto(fz_context *ctx, void *dev_, float x1, float y1, float x2, float y2, float x3, float y3)\n{\n\tdev_linecount = 0;  // reset # of consec. lines\n\tfz_point p1 = fz_make_point(x1, y1);\n\tfz_point p2 = fz_make_point(x2, y2);\n\tfz_point p3 = fz_make_point(x3, y3);\n\tp1 = fz_transform_point(p1, trace_device_ctm);\n\tp2 = fz_transform_point(p2, trace_device_ctm);\n\tp3 = fz_transform_point(p3, trace_device_ctm);\n\tdev_pathrect = fz_include_point_in_rect(dev_pathrect, p1);\n\tdev_pathrect = fz_include_point_in_rect(dev_pathrect, p2);\n\tdev_pathrect = fz_include_point_in_rect(dev_pathrect, p3);\n\n\tPyObject *list = PyTuple_New(5);\n\tPyTuple_SET_ITEM(list, 0, PyUnicode_FromString(\"c\"));\n\tPyTuple_SET_ITEM(list, 1, JM_py_from_point(dev_lastpoint));\n\tPyTuple_SET_ITEM(list, 2, JM_py_from_point(p1));\n\tPyTuple_SET_ITEM(list, 3, JM_py_from_point(p2));\n\tPyTuple_SET_ITEM(list, 4, JM_py_from_point(p3));\n\tdev_lastpoint = p3;\n\tPyObject *items = PyDict_GetItem(dev_pathdict, dictkey_items);\n\tLIST_APPEND_DROP(items, list);\n}\n\nstatic void\ntrace_close(fz_context *ctx, void *dev_)\n{\n\tif (dev_linecount == 3) {\n\t\tif (jm_checkrect()) {\n\t\t\treturn;\n\t\t}\n\t}\n\tdev_linecount = 0;  // reset # of consec. lines\n\tif (dev_havemove) {\n\t\tif (dev_firstpoint.x != dev_lastpoint.x || dev_firstpoint.y != dev_lastpoint.y) {\n\t\t\tPyObject *list = PyTuple_New(3);\n\t\t\tPyTuple_SET_ITEM(list, 0, PyUnicode_FromString(\"l\"));\n\t\t\tPyTuple_SET_ITEM(list, 1, JM_py_from_point(dev_lastpoint));\n\t\t\tPyTuple_SET_ITEM(list, 2, JM_py_from_point(dev_firstpoint));\n\t\t\tdev_lastpoint = dev_firstpoint;\n\t\t\tPyObject *items = PyDict_GetItem(dev_pathdict, dictkey_items);\n\t\t\tLIST_APPEND_DROP(items, list);\n\t\t}\n\t\tdev_havemove = 0;\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"closePath\", JM_BOOL(0));\n\t} else {\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"closePath\", JM_BOOL(1));\n\t}\n}\n\nstatic const fz_path_walker trace_path_walker =\n\t{\n\t\ttrace_moveto,\n\t\ttrace_lineto,\n\t\ttrace_curveto,\n\t\ttrace_close\n\t};\n\n/*\n---------------------------------------------------------------------\nCreate the \"items\" list of the path dictionary\n* either create or empty the path dictionary\n* reset the end point of the path\n* reset count of consecutive lines\n* invoke fz_walk_path(), which create the single items\n* if no items detected, empty path dict again\n---------------------------------------------------------------------\n*/\nstatic void\njm_lineart_path(fz_context *ctx, jm_lineart_device *dev, const fz_path *path)\n{\n\tdev_pathrect = fz_infinite_rect;\n\tdev_linecount = 0;\n\tdev_lastpoint = fz_make_point(0, 0);\n\tif (dev_pathdict) {\n\t\tPy_CLEAR(dev_pathdict);\n\t}\n\tdev_pathdict = PyDict_New();\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_items, PyList_New(0));\n\tfz_walk_path(ctx, path, &trace_path_walker, dev);\n\t// Check if any items were added ...\n\tif (!PyDict_GetItem(dev_pathdict, dictkey_items) || !PyList_Size(PyDict_GetItem(dev_pathdict, dictkey_items))) {\n\t\tPy_CLEAR(dev_pathdict);\n\t}\n}\n\n//---------------------------------------------------------------------------\n// Append current path to list or merge into last path of the list.\n// (1) Append if first path, different item lists or not a 'stroke' version\n//     of previous path\n// (2) If new path has the same items, merge its content into previous path\n//     and change path[\"type\"] to \"fs\".\n// (3) If \"out\" is callable, skip the previous and pass dictionary to it.\n//---------------------------------------------------------------------------\nstatic void\njm_append_merge(PyObject *out, PyObject *method)\n{\n\tif (PyCallable_Check(out) || method != Py_None) {  // function or method\n\t\tgoto callback;\n\t}\n\tPy_ssize_t len = PyList_Size(out);  // len of output list so far\n\tif (len == 0) {  // always append first path \n\t\tgoto append;\n\t}\n\tconst char *thistype = PyUnicode_AsUTF8(PyDict_GetItem(dev_pathdict, dictkey_type));\n\tif (strcmp(thistype, \"s\") != 0) {  // if not stroke, then append\n\t\tgoto append;\n\t}\n\tPyObject *prev = PyList_GET_ITEM(out, len - 1);  // get prev path\n\tconst char *prevtype = PyUnicode_AsUTF8(PyDict_GetItem(prev, dictkey_type));\n\tif (strcmp(prevtype, \"f\") != 0) {  // if previous not fill, append\n\t\tgoto append;\n\t}\n\t// last check: there must be the same list of items for \"f\" and \"s\".\n\tPyObject *previtems = PyDict_GetItem(prev, dictkey_items);\n\tPyObject *thisitems = PyDict_GetItem(dev_pathdict, dictkey_items);\n\tif (PyObject_RichCompareBool(previtems, thisitems, Py_NE)) {\n\t\tgoto append;\n\t}\n\tint rc = PyDict_Merge(prev, dev_pathdict, 0);  // merge with no override\n\tif (rc == 0) {\n\t\tDICT_SETITEM_DROP(prev, dictkey_type, PyUnicode_FromString(\"fs\"));\n\t\tgoto postappend;\n\t} else {\n\t\tPySys_WriteStderr(\"could not merge stroke and fill path\");\n\t\tgoto append;\n\t}\n\tappend:;\n\tPyList_Append(out, dev_pathdict);\n\tpostappend:;\n\tPy_CLEAR(dev_pathdict);\n\treturn;\n\n\tcallback:;  // callback function or method\n\tPyObject *resp = NULL;\n\tif (method == Py_None) {\n\t\tresp = PyObject_CallFunctionObjArgs(out, dev_pathdict, NULL);\n\t} else {\n\t\tresp = PyObject_CallMethodObjArgs(out, method, dev_pathdict, NULL);\n\t}\n\tif (resp) {\n\t\tPy_DECREF(resp);\n\t} else {\n\t\tPySys_WriteStderr(\"calling cdrawings callback function/method failed!\");\n\t\tPyErr_Clear();\n\t}\n\tPy_CLEAR(dev_pathdict);\n\treturn;\n}\n\n\nstatic void\njm_lineart_fill_path(fz_context *ctx, fz_device *dev_, const fz_path *path,\n\t\t\t\tint even_odd, fz_matrix ctm, fz_colorspace *colorspace,\n\t\t\t\tconst float *color, float alpha, fz_color_params color_params)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *) dev_;\n\tPyObject *out = dev->out;\n\ttrace_device_ctm = ctm; //fz_concat(ctm, trace_device_ptm);\n\tpath_type = FILL_PATH;\n\tjm_lineart_path(ctx, dev, path);\n\tif (!dev_pathdict) {\n\t\treturn;\n\t}\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_type, PyUnicode_FromString(\"f\"));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"even_odd\", JM_BOOL(even_odd));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"fill_opacity\", Py_BuildValue(\"f\", alpha));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"fill\", jm_lineart_color(ctx, colorspace, color));\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_rect, JM_py_from_rect(dev_pathrect));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"seqno\", PyLong_FromSize_t(dev->seqno));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"layer\", JM_UnicodeFromStr(layer_name));\n\tif (dev->clips)\t{\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"level\", PyLong_FromLong(dev->depth));\n\t}\n\tjm_append_merge(out, dev->method);\n\tdev->seqno += 1;\n}\n\nstatic void\njm_lineart_stroke_path(fz_context *ctx, fz_device *dev_, const fz_path *path,\n\t\t\t\tconst fz_stroke_state *stroke, fz_matrix ctm,\n\t\t\t\tfz_colorspace *colorspace, const float *color, float alpha,\n\t\t\t\tfz_color_params color_params)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tPyObject *out = dev->out;\n\tint i;\n\tdev_pathfactor = 1;\n\tif (fz_abs(ctm.a) == fz_abs(ctm.d)) {\n\t\tdev_pathfactor = fz_abs(ctm.a);\n\t}\n\ttrace_device_ctm = ctm; // fz_concat(ctm, trace_device_ptm);\n\tpath_type = STROKE_PATH;\n\n\tjm_lineart_path(ctx, dev, path);\n\tif (!dev_pathdict) {\n\t\treturn;\n\t}\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_type, PyUnicode_FromString(\"s\"));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"stroke_opacity\", Py_BuildValue(\"f\", alpha));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"color\", jm_lineart_color(ctx, colorspace, color));\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_width, Py_BuildValue(\"f\", dev_pathfactor * stroke->linewidth));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"lineCap\", Py_BuildValue(\"iii\", stroke->start_cap, stroke->dash_cap, stroke->end_cap));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"lineJoin\", Py_BuildValue(\"f\", dev_pathfactor * stroke->linejoin));\n\tif (!PyDict_GetItemString(dev_pathdict, \"closePath\")) {\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"closePath\", JM_BOOL(0));\n\t}\n\n\t// output the \"dashes\" string\n\tif (stroke->dash_len) {\n\t\tfz_buffer *buff = fz_new_buffer(ctx, 256);\n\t\tfz_append_string(ctx, buff, \"[ \");  // left bracket\n\t\tfor (i = 0; i < stroke->dash_len; i++) {\n\t\t\tfz_append_printf(ctx, buff, \"%g \", dev_pathfactor * stroke->dash_list[i]);\n\t\t}\n\t\tfz_append_printf(ctx, buff, \"] %g\", dev_pathfactor * stroke->dash_phase);\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"dashes\", JM_EscapeStrFromBuffer(ctx, buff));\n\t\tfz_drop_buffer(ctx, buff);\n\t} else {\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"dashes\", PyUnicode_FromString(\"[] 0\"));\n\t}\n\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_rect, JM_py_from_rect(dev_pathrect));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"layer\", JM_UnicodeFromStr(layer_name));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"seqno\", PyLong_FromSize_t(dev->seqno));\n\tif (dev->clips) {\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"level\", PyLong_FromLong(dev->depth));\n\t}\n\t// output the dict - potentially merging it with a previous fill_path twin\n\tjm_append_merge(out, dev->method);\n\tdev->seqno += 1;\n}\n\nstatic void\njm_lineart_clip_path(fz_context *ctx, fz_device *dev_, const fz_path *path, int even_odd, fz_matrix ctm, fz_rect scissor)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tPyObject *out = dev->out;\n\ttrace_device_ctm = ctm; //fz_concat(ctm, trace_device_ptm);\n\tpath_type = CLIP_PATH;\n\tjm_lineart_path(ctx, dev, path);\n\tif (!dev_pathdict) {\n\t\treturn;\n\t}\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_type, PyUnicode_FromString(\"clip\"));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"even_odd\", JM_BOOL(even_odd));\n\tif (!PyDict_GetItemString(dev_pathdict, \"closePath\")) {\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"closePath\", JM_BOOL(0));\n\t}\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"scissor\", JM_py_from_rect(compute_scissor()));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"level\", PyLong_FromLong(dev->depth));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"layer\", JM_UnicodeFromStr(layer_name));\n\tjm_append_merge(out, dev->method);\n\tdev->depth++;\n}\n\nstatic void\njm_lineart_clip_stroke_path(fz_context *ctx, fz_device *dev_, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tPyObject *out = dev->out;\n\ttrace_device_ctm = ctm; //fz_concat(ctm, trace_device_ptm);\n\tpath_type = CLIP_STROKE_PATH;\n\tjm_lineart_path(ctx, dev, path);\n\tif (!dev_pathdict) {\n\t\treturn;\n\t}\n\tDICT_SETITEM_DROP(dev_pathdict, dictkey_type, PyUnicode_FromString(\"clip\"));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"even_odd\", Py_BuildValue(\"s\", NULL));\n\tif (!PyDict_GetItemString(dev_pathdict, \"closePath\")) {\n\t\tDICT_SETITEMSTR_DROP(dev_pathdict, \"closePath\", JM_BOOL(0));\n\t}\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"scissor\", JM_py_from_rect(compute_scissor()));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"level\", PyLong_FromLong(dev->depth));\n\tDICT_SETITEMSTR_DROP(dev_pathdict, \"layer\", JM_UnicodeFromStr(layer_name));\n\tjm_append_merge(out, dev->method);\n\tdev->depth++;\n}\n\nstatic void\njm_lineart_clip_stroke_text(fz_context *ctx, fz_device *dev_, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_rect scissor)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tPyObject *out = dev->out;\n\tcompute_scissor();\n\tdev->depth++;\n}\n\nstatic void\njm_lineart_clip_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm, fz_rect scissor)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tPyObject *out = dev->out;\n\tcompute_scissor();\n\tdev->depth++;\n}\n\nstatic void\njm_lineart_clip_image_mask(fz_context *ctx, fz_device *dev_, fz_image *image, fz_matrix ctm, fz_rect scissor)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tPyObject *out = dev->out;\n\tcompute_scissor();\n\tdev->depth++;\n}\n\nstatic void\njm_lineart_pop_clip(fz_context *ctx, fz_device *dev_)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tif (!scissors) return;\n\tPy_ssize_t len = PyList_Size(scissors);\n\tif (len < 1) return;\n\tPyList_SetSlice(scissors, len - 1, len, NULL);\n\tdev->depth--;\n}\n\n\nstatic void\njm_lineart_begin_layer(fz_context *ctx, fz_device *dev_, const char *name)\n{\n\tlayer_name = fz_strdup(ctx, name);\n}\n\nstatic void\njm_lineart_end_layer(fz_context *ctx, fz_device *dev_)\n{\n\tfz_free(ctx, layer_name);\n\tlayer_name = NULL;\n}\n\nstatic void\njm_lineart_begin_group(fz_context *ctx, fz_device *dev_, fz_rect bbox, fz_colorspace *cs, int isolated, int knockout, int blendmode, float alpha)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tPyObject *out = dev->out;\n\tdev_pathdict = Py_BuildValue(\"{s:s,s:N,s:N,s:N,s:s,s:f,s:i,s:N}\",\n\t\t\t\t\t\t\"type\", \"group\",\n\t\t\t\t\t\t\"rect\", JM_py_from_rect(bbox),\n\t\t\t\t\t\t\"isolated\", JM_BOOL(isolated),\n\t\t\t\t\t\t\"knockout\", JM_BOOL(knockout),\n\t\t\t\t\t\t\"blendmode\", fz_blendmode_name(blendmode),\n\t\t\t\t\t\t\"opacity\", alpha,\n\t\t\t\t\t\t\"level\", dev->depth,\n\t\t\t\t\t\t\"layer\", JM_UnicodeFromStr(layer_name)\n\t\t\t\t\t);\n\tjm_append_merge(out, dev->method);\n\tdev->depth++;\n}\n\nstatic void\njm_lineart_end_group(fz_context *ctx, fz_device *dev_)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (!dev->clips) return;\n\tdev->depth--;\n}\n\n\nstatic void\njm_dev_linewidth(fz_context *ctx, fz_device *dev_, const fz_path *path, const fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)\n{\n\tdev_linewidth = stroke->linewidth;\n\tjm_increase_seqno(ctx, dev_);\n}\n\n\nstatic void\njm_trace_text_span(fz_context *ctx, PyObject *out, fz_text_span *span, int type, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, size_t seqno)\n{\n\tfz_font *out_font = NULL;\n\tint i;\n\tconst char *fontname = JM_font_name(ctx, span->font);\n\tfloat rgb[3];\n\tPyObject *chars = PyTuple_New(span->len);\n\tfz_matrix mat = fz_concat(span->trm, ctm); // text transformation matrix\n\tfz_point dir = fz_transform_vector(fz_make_point(1, 0), mat); // writing direction\n\tdouble fsize = sqrt(dir.x * dir.x + dir.y * dir.y);\n\n\tdir = fz_normalize_vector(dir);\n\tdouble linewidth, adv, asc, dsc;\n\tdouble space_adv = 0;\n\tfloat x0, y0, x1, y1;\n\tasc = (double) JM_font_ascender(ctx, span->font);\n\tdsc = (double) JM_font_descender(ctx, span->font);\n\tif (asc < 1e-3) {  // probably Tesseract font\n\t\tdsc = -0.1;\n\t\tasc = 0.9;\n\t}\n\t// compute effective ascender / descender\n\tdouble ascsize = asc * fsize / (asc - dsc);\n\tdouble dscsize = dsc * fsize / (asc - dsc);\n\n\tint fflags = 0; // font flags\n\tint mono = fz_font_is_monospaced(ctx, span->font);\n\tfflags += mono * TEXT_FONT_MONOSPACED;\n\tfflags += fz_font_is_italic(ctx, span->font) * TEXT_FONT_ITALIC;\n\tfflags += fz_font_is_serif(ctx, span->font) * TEXT_FONT_SERIFED;\n\tfflags += fz_font_is_bold(ctx, span->font) * TEXT_FONT_BOLD;\n\n\tif (dev_linewidth > 0) {  // width of character border\n\t\tlinewidth = (double) dev_linewidth;\n\t} else {\n\t\tlinewidth = fsize * 0.05;  // default: 5% of font size\n\t}\n\tfz_point char_orig;\n\tdouble last_adv = 0;\n\n\t// walk through characters of span\n\tfz_rect span_bbox;\n\tfz_matrix rot = fz_make_matrix(dir.x, dir.y, -dir.y, dir.x, 0, 0);\n\tif (dir.x == -1) {  // left-right flip\n\t\trot.d = 1;\n\t}\n\n\t//PySys_WriteStdout(\"mat: (%g, %g, %g, %g)\\n\", mat.a, mat.b, mat.c, mat.d);\n\t//PySys_WriteStdout(\"rot: (%g, %g, %g, %g)\\n\", rot.a, rot.b, rot.c, rot.d);\n\n\tfor (i = 0; i < span->len; i++) {\n\t\tadv = 0;\n\t\tif (span->items[i].gid >= 0) {\n\t\t\tadv = (double) fz_advance_glyph(ctx, span->font, span->items[i].gid, span->wmode);\n\t\t}\n\t\tadv *= fsize;\n\t\tlast_adv = adv;\n\t\tif (span->items[i].ucs == 32) {\n\t\t\tspace_adv = adv;\n\t\t}\n\t\tchar_orig = fz_make_point(span->items[i].x, span->items[i].y);\n\t\tchar_orig = fz_transform_point(char_orig, ctm);\n\t\tfz_matrix m1 = fz_make_matrix(1, 0, 0, 1, -char_orig.x, -char_orig.y);\n\t\tm1 = fz_concat(m1, rot);\n\t\tm1 = fz_concat(m1, fz_make_matrix(1, 0, 0, 1, char_orig.x, char_orig.y));\n\t\tx0 = char_orig.x;\n\t\tx1 = x0 + adv;\n\t\tif (mat.d > 0 && (dir.x == 1 || dir.x == -1) ||\n\t\t    mat.b !=0 && mat.b == -mat.c) {  // up-down flip\n\t\t\ty0 = char_orig.y + dscsize;\n\t\t\ty1 = char_orig.y + ascsize;\n\t\t} else {\n\t\t\ty0 = char_orig.y - ascsize;\n\t\t\ty1 = char_orig.y - dscsize;\n\t\t}\n\t\tfz_rect char_bbox = fz_make_rect(x0, y0, x1, y1);\n\t\tchar_bbox = fz_transform_rect(char_bbox, m1);\n\t\tPyTuple_SET_ITEM(chars, (Py_ssize_t) i, Py_BuildValue(\"ii(ff)(ffff)\",\n\t\t\tspan->items[i].ucs, span->items[i].gid,\n\t\t\tchar_orig.x, char_orig.y, char_bbox.x0, char_bbox.y0, char_bbox.x1, char_bbox.y1));\n\t\tif (i > 0) {\n\t\t\tspan_bbox = fz_union_rect(span_bbox, char_bbox);\n\t\t} else {\n\t\t\tspan_bbox = char_bbox;\n\t\t}\n\t}\n\tif (!space_adv) {\n\t\tif (!mono) {\n\t\t\tspace_adv = fz_advance_glyph(ctx, span->font,\n\t\t\tfz_encode_character_with_fallback(ctx, span->font, 32, 0, 0, &out_font),\n\t\t\tspan->wmode);\n\t\t\tspace_adv *= fsize;\n\t\t\tif (!space_adv) {\n\t\t\t\tspace_adv = last_adv;\n\t\t\t}\n\t\t} else {\n\t\t\tspace_adv = last_adv; // for mono, any char width suffices\n\t\t}\n\t}\n\t// make the span dictionary\n\tPyObject *span_dict = PyDict_New();\n\tDICT_SETITEMSTR_DROP(span_dict, \"dir\", JM_py_from_point(dir));\n\tDICT_SETITEM_DROP(span_dict, dictkey_font, JM_EscapeStrFromStr(fontname));\n\tDICT_SETITEM_DROP(span_dict, dictkey_wmode, PyLong_FromLong((long) span->wmode));\n\tDICT_SETITEM_DROP(span_dict, dictkey_flags, PyLong_FromLong((long) fflags));\n\tDICT_SETITEMSTR_DROP(span_dict, \"bidi_lvl\", PyLong_FromLong((long) span->bidi_level));\n\tDICT_SETITEMSTR_DROP(span_dict, \"bidi_dir\", PyLong_FromLong((long) span->markup_dir));\n\tDICT_SETITEM_DROP(span_dict, dictkey_ascender, PyFloat_FromDouble(asc));\n\tDICT_SETITEM_DROP(span_dict, dictkey_descender, PyFloat_FromDouble(dsc));\n\tDICT_SETITEM_DROP(span_dict, dictkey_colorspace, PyLong_FromLong(3));\n\n\tif (colorspace) {\n\t\tfz_convert_color(ctx, colorspace, color, fz_device_rgb(ctx),\n\t\t\t\t\t\t rgb, NULL, fz_default_color_params);\n\t} else {\n\t\trgb[0] = rgb[1] = rgb[2] = 0;\n\t}\n\n\tDICT_SETITEM_DROP(span_dict, dictkey_color, Py_BuildValue(\"fff\", rgb[0], rgb[1], rgb[2]));\n\tDICT_SETITEM_DROP(span_dict, dictkey_size, PyFloat_FromDouble(fsize));\n\tDICT_SETITEMSTR_DROP(span_dict, \"opacity\", PyFloat_FromDouble((double) alpha));\n\tDICT_SETITEMSTR_DROP(span_dict, \"linewidth\", PyFloat_FromDouble((double) linewidth));\n\tDICT_SETITEMSTR_DROP(span_dict, \"spacewidth\", PyFloat_FromDouble(space_adv));\n\tDICT_SETITEM_DROP(span_dict, dictkey_type, PyLong_FromLong((long) type));\n\tDICT_SETITEM_DROP(span_dict, dictkey_bbox, JM_py_from_rect(span_bbox));\n\tDICT_SETITEMSTR_DROP(span_dict, \"layer\", JM_UnicodeFromStr(layer_name));\n\tDICT_SETITEMSTR_DROP(span_dict, \"seqno\", PyLong_FromSize_t(seqno));\n\tDICT_SETITEM_DROP(span_dict, dictkey_chars, chars);\n\tLIST_APPEND_DROP(out, span_dict);\n}\n\nstatic void\njm_trace_text(fz_context *ctx, PyObject *out, const fz_text *text, int type, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, size_t seqno)\n{\n\tfz_text_span *span;\n\tfor (span = text->head; span; span = span->next)\n\t\tjm_trace_text_span(ctx, out, span, type, ctm, colorspace, color, alpha, seqno);\n}\n\n/*---------------------------------------------------------\nThere are 3 text trace types:\n0 - fill text (PDF Tr 0)\n1 - stroke text (PDF Tr 1)\n3 - ignore text (PDF Tr 3)\n---------------------------------------------------------*/\nstatic void\njm_lineart_fill_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tPyObject *out = dev->out;\n\tjm_trace_text(ctx, out, text, 0, ctm, colorspace, color, alpha, dev->seqno);\n\tdev->seqno += 1;\n}\n\nstatic void\njm_lineart_stroke_text(fz_context *ctx, fz_device *dev_, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tPyObject *out = dev->out;\n\tjm_trace_text(ctx, out, text, 1, ctm, colorspace, color, alpha, dev->seqno);\n\tdev->seqno += 1;\n}\n\n\nstatic void\njm_lineart_ignore_text(fz_context *ctx, fz_device *dev_, const fz_text *text, fz_matrix ctm)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tPyObject *out = dev->out;\n\tjm_trace_text(ctx, out, text, 3, ctm, NULL, NULL, 1, dev->seqno);\n\tdev->seqno += 1;\n}\n\nstatic void jm_lineart_drop_device(fz_context *ctx, fz_device *dev_)\n{\n\tjm_lineart_device *dev = (jm_lineart_device *)dev_;\n\tif (PyList_Check(dev->out)) {\n\t\tPy_CLEAR(dev->out);\n\t}\n\tPy_CLEAR(dev->method);\n\tPy_CLEAR(scissors);\n}\n\n//-------------------------------------------------------------------\n// LINEART device for Python method Page.get_cdrawings()\n//-------------------------------------------------------------------\nfz_device *JM_new_lineart_device(fz_context *ctx, PyObject *out, int clips, PyObject *method)\n{\n\tjm_lineart_device *dev = fz_new_derived_device(ctx, jm_lineart_device);\n\n\tdev->super.close_device = NULL;\n\tdev->super.drop_device = jm_lineart_drop_device;\n\tdev->super.fill_path = jm_lineart_fill_path;\n\tdev->super.stroke_path = jm_lineart_stroke_path;\n\tdev->super.clip_path = jm_lineart_clip_path;\n\tdev->super.clip_stroke_path = jm_lineart_clip_stroke_path;\n\n\tdev->super.fill_text = jm_increase_seqno;\n\tdev->super.stroke_text = jm_increase_seqno;\n\tdev->super.clip_text = jm_lineart_clip_text;\n\tdev->super.clip_stroke_text = jm_lineart_clip_stroke_text;\n\tdev->super.ignore_text = jm_increase_seqno;\n\n\tdev->super.fill_shade = jm_increase_seqno;\n\tdev->super.fill_image = jm_increase_seqno;\n\tdev->super.fill_image_mask = jm_increase_seqno;\n\tdev->super.clip_image_mask = jm_lineart_clip_image_mask;\n\n\tdev->super.pop_clip = jm_lineart_pop_clip;\n\n\tdev->super.begin_mask = NULL;\n\tdev->super.end_mask = NULL;\n\tdev->super.begin_group = jm_lineart_begin_group;\n\tdev->super.end_group = jm_lineart_end_group;\n\n\tdev->super.begin_tile = NULL;\n\tdev->super.end_tile = NULL;\n\n\tdev->super.begin_layer = jm_lineart_begin_layer;\n\tdev->super.end_layer = jm_lineart_end_layer;\n\n\tdev->super.begin_structure = NULL;\n\tdev->super.end_structure = NULL;\n\n\tdev->super.begin_metatext = NULL;\n\tdev->super.end_metatext = NULL;\n\n\tdev->super.render_flags = NULL;\n\tdev->super.set_default_colorspaces = NULL;\n\n\tif (PyList_Check(out)) {\n\t\tPy_INCREF(out);\n\t}\n\tPy_INCREF(method);\n\tdev->out = out;\n\tdev->seqno = 0;\n\tdev->depth = 0;\n\tdev->clips = clips;\n\tdev->method = method;\n\ttrace_device_reset();\n\treturn (fz_device *)dev;\n}\n\n//-------------------------------------------------------------------\n// Trace TEXT device for Python method Page.get_texttrace()\n//-------------------------------------------------------------------\nfz_device *JM_new_texttrace_device(fz_context *ctx, PyObject *out)\n{\n\tjm_lineart_device *dev = fz_new_derived_device(ctx, jm_lineart_device);\n\n\tdev->super.close_device = NULL;\n\tdev->super.drop_device = jm_lineart_drop_device;\n\tdev->super.fill_path = jm_increase_seqno;\n\tdev->super.stroke_path = jm_dev_linewidth;\n\tdev->super.clip_path = NULL;\n\tdev->super.clip_stroke_path = NULL;\n\n\tdev->super.fill_text = jm_lineart_fill_text;\n\tdev->super.stroke_text = jm_lineart_stroke_text;\n\tdev->super.clip_text = NULL;\n\tdev->super.clip_stroke_text = NULL;\n\tdev->super.ignore_text = jm_lineart_ignore_text;\n\n\tdev->super.fill_shade = jm_increase_seqno;\n\tdev->super.fill_image = jm_increase_seqno;\n\tdev->super.fill_image_mask = jm_increase_seqno;\n\tdev->super.clip_image_mask = NULL;\n\n\tdev->super.pop_clip = NULL;\n\n\tdev->super.begin_mask = NULL;\n\tdev->super.end_mask = NULL;\n\tdev->super.begin_group = NULL;\n\tdev->super.end_group = NULL;\n\n\tdev->super.begin_tile = NULL;\n\tdev->super.end_tile = NULL;\n\n\tdev->super.begin_layer = jm_lineart_begin_layer;\n\tdev->super.end_layer = jm_lineart_end_layer;\n\n\tdev->super.begin_structure = NULL;\n\tdev->super.end_structure = NULL;\n\n\tdev->super.begin_metatext = NULL;\n\tdev->super.end_metatext = NULL;\n\n\tdev->super.render_flags = NULL;\n\tdev->super.set_default_colorspaces = NULL;\n\n\tif (PyList_Check(out)) {\n\t\tPy_XINCREF(out);\n\t}\n\tdev->out = out;\n\tdev->seqno = 0;\n\tdev->depth = 0;\n\tdev->clips = 0;\n\tdev->method = NULL;\n\ttrace_device_reset();\n    \n\treturn (fz_device *)dev;\n}\n\n//-------------------------------------------------------------------\n// BBOX device\n//-------------------------------------------------------------------\ntypedef struct jm_bbox_device_s\n{\n\tfz_device super;\n\tPyObject *result;\n\tint layers;\n} jm_bbox_device;\n\nstatic void\njm_bbox_add_rect(fz_context *ctx, fz_device *dev, fz_rect rect, char *code)\n{\n\tjm_bbox_device *bdev = (jm_bbox_device *)dev;\n\tif (!bdev->layers) {\n\t\tLIST_APPEND_DROP(bdev->result, Py_BuildValue(\"sN\", code, JM_py_from_rect(rect)));\n\t} else {\n\t\tLIST_APPEND_DROP(bdev->result, Py_BuildValue(\"sNN\", code, JM_py_from_rect(rect), JM_UnicodeFromStr(layer_name)));\n\t}\n}\n\nstatic void\njm_bbox_fill_path(fz_context *ctx, fz_device *dev, const fz_path *path, int even_odd, fz_matrix ctm,\n\t\t\t\t  fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, NULL, ctm), \"fill-path\");\n}\n\nstatic void\njm_bbox_stroke_path(fz_context *ctx, fz_device *dev, const fz_path *path, const fz_stroke_state *stroke,\n\t\t\t\t\tfz_matrix ctm, fz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_bound_path(ctx, path, stroke, ctm), \"stroke-path\");\n}\n\nstatic void\njm_bbox_fill_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm, ...)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, NULL, ctm), \"fill-text\");\n}\n\nstatic void\njm_bbox_ignore_text(fz_context *ctx, fz_device *dev, const fz_text *text, fz_matrix ctm)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, NULL, ctm), \"ignore-text\");\n}\n\nstatic void\njm_bbox_stroke_text(fz_context *ctx, fz_device *dev, const fz_text *text, const fz_stroke_state *stroke, fz_matrix ctm, ...)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_bound_text(ctx, text, stroke, ctm), \"stroke-text\");\n}\n\nstatic void\njm_bbox_fill_shade(fz_context *ctx, fz_device *dev, fz_shade *shade, fz_matrix ctm, float alpha, fz_color_params color_params)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_bound_shade(ctx, shade, ctm), \"fill-shade\");\n}\n\nstatic void\njm_bbox_fill_image(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm, float alpha, fz_color_params color_params)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_transform_rect(fz_unit_rect, ctm), \"fill-image\");\n}\n\nstatic void\njm_bbox_fill_image_mask(fz_context *ctx, fz_device *dev, fz_image *image, fz_matrix ctm,\n\t\t\t\t\t\tfz_colorspace *colorspace, const float *color, float alpha, fz_color_params color_params)\n{\n\tjm_bbox_add_rect(ctx, dev, fz_transform_rect(fz_unit_rect, ctm), \"fill-imgmask\");\n}\n\nfz_device *\nJM_new_bbox_device(fz_context *ctx, PyObject *result, int layers)\n{\n\tjm_bbox_device *dev = fz_new_derived_device(ctx, jm_bbox_device);\n\n\tdev->super.fill_path = jm_bbox_fill_path;\n\tdev->super.stroke_path = jm_bbox_stroke_path;\n\tdev->super.clip_path = NULL;\n\tdev->super.clip_stroke_path = NULL;\n\n\tdev->super.fill_text = jm_bbox_fill_text;\n\tdev->super.stroke_text = jm_bbox_stroke_text;\n\tdev->super.clip_text = NULL;\n\tdev->super.clip_stroke_text = NULL;\n\tdev->super.ignore_text = jm_bbox_ignore_text;\n\n\tdev->super.fill_shade = jm_bbox_fill_shade;\n\tdev->super.fill_image = jm_bbox_fill_image;\n\tdev->super.fill_image_mask = jm_bbox_fill_image_mask;\n\tdev->super.clip_image_mask = NULL;\n\n\tdev->super.pop_clip = NULL;\n\n\tdev->super.begin_mask = NULL;\n\tdev->super.end_mask = NULL;\n\tdev->super.begin_group = NULL;\n\tdev->super.end_group = NULL;\n\n\tdev->super.begin_tile = NULL;\n\tdev->super.end_tile = NULL;\n\n\tdev->super.begin_layer = jm_lineart_begin_layer;\n\tdev->super.end_layer = jm_lineart_end_layer;\n\n\tdev->super.begin_structure = NULL;\n\tdev->super.end_structure = NULL;\n\n\tdev->super.begin_metatext = NULL;\n\tdev->super.end_metatext = NULL;\n\n\tdev->super.render_flags = NULL;\n\tdev->super.set_default_colorspaces = NULL;\n\n\tdev->result = result;\n\tdev->layers = layers;\n\ttrace_device_reset();\n\n\treturn (fz_device *)dev;\n}\n\n%}\n"
  },
  {
    "path": "src_classic/helper-fields.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n#define SETATTR(a, v) PyObject_SetAttrString(Widget, a, v)\n#define GETATTR(a) PyObject_GetAttrString(Widget, a)\n#define CALLATTR(m, p) PyObject_CallMethod(Widget, m, p)\n\nstatic void\nSETATTR_DROP(PyObject *mod, const char *attr, PyObject *value)\n{\n    if (!value)\n        PyObject_DelAttrString(mod, attr);\n    else\n    {\n        PyObject_SetAttrString(mod, attr, value);\n        Py_DECREF(value);\n    }\n}\n\n//-----------------------------------------------------------------------------\n// Functions dealing with PDF form fields (widgets)\n//-----------------------------------------------------------------------------\nenum\n{\n\tSigFlag_SignaturesExist = 1,\n\tSigFlag_AppendOnly = 2\n};\n\n\n// make new PDF action object from JavaScript source\n// Parameters are a PDF document and a Python string.\n// Returns a PDF action object.\n//-----------------------------------------------------------------------------\npdf_obj *\nJM_new_javascript(fz_context *ctx, pdf_document *pdf, PyObject *value)\n{\n    fz_buffer *res = NULL;\n    if (!PyObject_IsTrue(value))  // no argument given\n        return NULL;\n\n    char *data = JM_StrAsChar(value);\n    if (!data)  // not convertible to char*\n        return NULL;\n\n    res = fz_new_buffer_from_copied_data(ctx, data, strlen(data));\n    pdf_obj *source = pdf_add_stream(ctx, pdf, res, NULL, 0);\n    pdf_obj *newaction = pdf_add_new_dict(ctx, pdf, 4);\n    pdf_dict_put(ctx, newaction, PDF_NAME(S), pdf_new_name(ctx, \"JavaScript\"));\n    pdf_dict_put(ctx, newaction, PDF_NAME(JS), source);\n    fz_drop_buffer(ctx, res);\n    return pdf_keep_obj(ctx, newaction);\n}\n\n\n// JavaScript extractor\n// Returns either the script source or None. Parameter is a PDF action\n// dictionary, which must have keys /S and /JS. The value of /S must be\n// '/JavaScript'. The value of /JS is returned.\n//-----------------------------------------------------------------------------\nPyObject *\nJM_get_script(fz_context *ctx, pdf_obj *key)\n{\n    pdf_obj *js = NULL;\n    fz_buffer *res = NULL;\n    PyObject *script = NULL;\n    if (!key) Py_RETURN_NONE;\n\n    if (!strcmp(pdf_to_name(ctx,\n                pdf_dict_get(ctx, key, PDF_NAME(S))), \"JavaScript\")) {\n        js = pdf_dict_get(ctx, key, PDF_NAME(JS));\n    }\n    if (!js) Py_RETURN_NONE;\n\n    if (pdf_is_string(ctx, js)) {\n        script = JM_UnicodeFromStr(pdf_to_text_string(ctx, js));\n    } else if (pdf_is_stream(ctx, js)) {\n        res = pdf_load_stream(ctx, js);\n        script = JM_EscapeStrFromBuffer(ctx, res);\n        fz_drop_buffer(ctx, res);\n    } else {\n        Py_RETURN_NONE;\n    }\n    if (PyObject_IsTrue(script)) { // do not return an empty script\n        return script;\n    }\n    Py_CLEAR(script);\n    Py_RETURN_NONE;\n}\n\n\n// Create a JavaScript PDF action.\n// Usable for all object types which support PDF actions, even if the\n// argument name suggests annotations. Up to 2 key values can be specified, so\n// JavaScript actions can be stored for '/A' and '/AA/?' keys.\n//-----------------------------------------------------------------------------\nvoid JM_put_script(fz_context *ctx, pdf_obj *annot_obj, pdf_obj *key1, pdf_obj *key2, PyObject *value)\n{\n    PyObject *script = NULL;\n    pdf_obj *key1_obj = pdf_dict_get(ctx, annot_obj, key1);\n    pdf_document *pdf = pdf_get_bound_document(ctx, annot_obj);  // owning PDF\n\n    // if no new script given, just delete corresponding key\n    if (!value || !PyObject_IsTrue(value)) {\n        if (!key2) {\n            pdf_dict_del(ctx, annot_obj, key1);\n        } else if (key1_obj) {\n            pdf_dict_del(ctx, key1_obj, key2);\n        }\n        return;\n    }\n\n    // read any existing script as a PyUnicode string\n    if (!key2 || !key1_obj) {\n        script = JM_get_script(ctx, key1_obj);\n    } else {\n        script = JM_get_script(ctx, pdf_dict_get(ctx, key1_obj, key2));\n    }\n\n    // replace old script, if different from new one\n    if (!PyObject_RichCompareBool(value, script, Py_EQ)) {\n        pdf_obj *newaction = JM_new_javascript(ctx, pdf, value);\n        if (!key2) {\n            pdf_dict_put_drop(ctx, annot_obj, key1, newaction);\n        } else {\n            pdf_dict_putl_drop(ctx, annot_obj, newaction, key1, key2, NULL);\n        }\n    }\n    Py_XDECREF(script);\n    return;\n}\n\n/*\n// Execute a JavaScript action for annot or field.\n//-----------------------------------------------------------------------------\nPyObject *\nJM_exec_script(fz_context *ctx, pdf_obj *annot_obj, pdf_obj *key1, pdf_obj *key2)\n{\n    PyObject *script = NULL;\n    char *code = NULL;\n    fz_try(ctx) {\n        pdf_document *pdf = pdf_get_bound_document(ctx, annot_obj);\n        char buf[100];\n        if (!key2) {\n            script = JM_get_script(ctx, key1_obj);\n        } else {\n            script = JM_get_script(ctx, pdf_dict_get(ctx, key1_obj, key2));\n        }\n        code = JM_StrAsChar(script);\n        fz_snprintf(buf, sizeof buf, \"%d/A\", pdf_to_num(ctx, annot_obj));\n        pdf_js_execute(pdf->js, buf, code);\n    }\n    fz_always(ctx) {\n        Py_XDECREF(string);\n    }\n    fz_catch(ctx) {\n        Py_RETURN_FALSE;\n    }\n    Py_RETURN_TRUE;\n}\n*/\n\n// String from widget type\n//-----------------------------------------------------------------------------\nchar *JM_field_type_text(int wtype)\n{\n    switch(wtype) {\n        case(PDF_WIDGET_TYPE_BUTTON):\n            return \"Button\";\n        case(PDF_WIDGET_TYPE_CHECKBOX):\n            return \"CheckBox\";\n        case(PDF_WIDGET_TYPE_RADIOBUTTON):\n            return \"RadioButton\";\n        case(PDF_WIDGET_TYPE_TEXT):\n            return \"Text\";\n        case(PDF_WIDGET_TYPE_LISTBOX):\n            return \"ListBox\";\n        case(PDF_WIDGET_TYPE_COMBOBOX):\n            return \"ComboBox\";\n        case(PDF_WIDGET_TYPE_SIGNATURE):\n            return \"Signature\";\n        default:\n            return \"unknown\";\n    }\n}\n\n// Set the field type\n//-----------------------------------------------------------------------------\nvoid JM_set_field_type(fz_context *ctx, pdf_document *doc, pdf_obj *obj, int type)\n{\n\tint setbits = 0;\n\tint clearbits = 0;\n\tpdf_obj *typename = NULL;\n\n\tswitch(type) {\n\tcase PDF_WIDGET_TYPE_BUTTON:\n\t\ttypename = PDF_NAME(Btn);\n\t\tsetbits = PDF_BTN_FIELD_IS_PUSHBUTTON;\n\t\tbreak;\n\tcase PDF_WIDGET_TYPE_RADIOBUTTON:\n\t\ttypename = PDF_NAME(Btn);\n\t\tclearbits = PDF_BTN_FIELD_IS_PUSHBUTTON;\n\t\tsetbits = PDF_BTN_FIELD_IS_RADIO;\n\t\tbreak;\n\tcase PDF_WIDGET_TYPE_CHECKBOX:\n\t\ttypename = PDF_NAME(Btn);\n\t\tclearbits = (PDF_BTN_FIELD_IS_PUSHBUTTON|PDF_BTN_FIELD_IS_RADIO);\n\t\tbreak;\n\tcase PDF_WIDGET_TYPE_TEXT:\n\t\ttypename = PDF_NAME(Tx);\n\t\tbreak;\n\tcase PDF_WIDGET_TYPE_LISTBOX:\n\t\ttypename = PDF_NAME(Ch);\n\t\tclearbits = PDF_CH_FIELD_IS_COMBO;\n\t\tbreak;\n\tcase PDF_WIDGET_TYPE_COMBOBOX:\n\t\ttypename = PDF_NAME(Ch);\n\t\tsetbits = PDF_CH_FIELD_IS_COMBO;\n\t\tbreak;\n\tcase PDF_WIDGET_TYPE_SIGNATURE:\n\t\ttypename = PDF_NAME(Sig);\n\t\tbreak;\n\t}\n\n\tif (typename)\n\t\tpdf_dict_put_drop(ctx, obj, PDF_NAME(FT), typename);\n\n\tif (setbits != 0 || clearbits != 0) {\n\t\tint bits = pdf_dict_get_int(ctx, obj, PDF_NAME(Ff));\n\t\tbits &= ~clearbits;\n\t\tbits |= setbits;\n\t\tpdf_dict_put_int(ctx, obj, PDF_NAME(Ff), bits);\n\t}\n}\n\n// Copied from MuPDF v1.14\n// Create widget.\n// Returns a kept reference to a pdf_annot - caller must drop it.\n//-----------------------------------------------------------------------------\npdf_annot *JM_create_widget(fz_context *ctx, pdf_document *doc, pdf_page *page, int type, char *fieldname)\n{\n\tpdf_obj *form = NULL;\n\tint old_sigflags = pdf_to_int(ctx, pdf_dict_getp(ctx, pdf_trailer(ctx, doc), \"Root/AcroForm/SigFlags\"));\n\tpdf_annot *annot = pdf_create_annot_raw(ctx, page, PDF_ANNOT_WIDGET);   // returns a kept reference.\n    pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n\tfz_try(ctx) {\n\t\tJM_set_field_type(ctx, doc, annot_obj, type);\n\t\tpdf_dict_put_text_string(ctx, annot_obj, PDF_NAME(T), fieldname);\n\n\t\tif (type == PDF_WIDGET_TYPE_SIGNATURE) {\n\t\t\tint sigflags = (old_sigflags | (SigFlag_SignaturesExist|SigFlag_AppendOnly));\n\t\t\tpdf_dict_putl_drop(ctx, pdf_trailer(ctx, doc), pdf_new_int(ctx, sigflags), PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(SigFlags), NULL);\n\t\t}\n\n\t\t/*\n\t\tpdf_create_annot will have linked the new widget into the page's\n\t\tannot array. We also need it linked into the document's form\n\t\t*/\n\t\tform = pdf_dict_getp(ctx, pdf_trailer(ctx, doc), \"Root/AcroForm/Fields\");\n\t\tif (!form) {\n\t\t\tform = pdf_new_array(ctx, doc, 1);\n\t\t\tpdf_dict_putl_drop(ctx, pdf_trailer(ctx, doc),\n                               form,\n                               PDF_NAME(Root),\n                               PDF_NAME(AcroForm),\n                               PDF_NAME(Fields),\n                               NULL);\n\t\t}\n\n\t\tpdf_array_push(ctx, form, annot_obj); // Cleanup relies on this statement being last\n\t}\n\tfz_catch(ctx) {\n\t\tpdf_delete_annot(ctx, page, annot);\n\n\t\tif (type == PDF_WIDGET_TYPE_SIGNATURE) {\n\t\t\tpdf_dict_putl_drop(ctx, pdf_trailer(ctx, doc), pdf_new_int(ctx, old_sigflags), PDF_NAME(Root), PDF_NAME(AcroForm), PDF_NAME(SigFlags), NULL);\n        }\n\n\t\tfz_rethrow(ctx);\n\t}\n\n\treturn annot;\n}\n\n\n\n// PushButton get state\n//-----------------------------------------------------------------------------\nPyObject *JM_pushbtn_state(fz_context *ctx, pdf_annot *annot)\n{   // pushed buttons do not reflect status changes in the PDF\n    // always reflect them as untouched\n    Py_RETURN_FALSE;\n}\n\n\n// Text field retrieve value\n//-----------------------------------------------------------------------------\nPyObject *JM_text_value(fz_context *ctx, pdf_annot *annot)\n{\n    const char *text = NULL;\n    fz_var(text);\n    fz_try(ctx) {\n        pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n        text = pdf_field_value(ctx, annot_obj);\n    }\n    fz_catch(ctx) Py_RETURN_NONE;\n    return JM_UnicodeFromStr(text);\n}\n\n// ListBox retrieve value\n//-----------------------------------------------------------------------------\nPyObject *JM_listbox_value(fz_context *ctx, pdf_annot *annot)\n{\n    int i = 0, n = 0;\n    // may be single value or array\n    pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n    pdf_obj *optarr = pdf_dict_get(ctx, annot_obj, PDF_NAME(V));\n    if (pdf_is_string(ctx, optarr))         // a single string\n        return PyString_FromString(pdf_to_text_string(ctx, optarr));\n\n    // value is an array (may have len 0)\n    n = pdf_array_len(ctx, optarr);\n    PyObject *liste = PyList_New(0);\n\n    // extract a list of strings\n    // each entry may again be an array: take second entry then\n    for (i = 0; i < n; i++) {\n        pdf_obj *elem = pdf_array_get(ctx, optarr, i);\n        if (pdf_is_array(ctx, elem))\n            elem = pdf_array_get(ctx, elem, 1);\n        LIST_APPEND_DROP(liste, JM_UnicodeFromStr(pdf_to_text_string(ctx, elem)));\n    }\n    return liste;\n}\n\n// ComboBox retrieve value\n//-----------------------------------------------------------------------------\nPyObject *JM_combobox_value(fz_context *ctx, pdf_annot *annot)\n{   // combobox treated like listbox\n    return JM_listbox_value(ctx, annot);\n}\n\n// Signature field retrieve value\nPyObject *JM_signature_value(fz_context *ctx, pdf_annot *annot)\n{   // signatures are currently not supported\n    Py_RETURN_NONE;\n}\n\n// retrieve ListBox / ComboBox choice values\n//-----------------------------------------------------------------------------\nPyObject *JM_choice_options(fz_context *ctx, pdf_annot *annot)\n{   // return list of choices for list or combo boxes\n    pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n    PyObject *val;\n    int n = pdf_choice_widget_options(ctx, annot, 0, NULL);\n    if (n == 0) Py_RETURN_NONE;                     // wrong widget type\n\n    pdf_obj *optarr = pdf_dict_get(ctx, annot_obj, PDF_NAME(Opt));\n    int i, m;\n    PyObject *liste = PyList_New(0);\n\n    for (i = 0; i < n; i++) {\n        m = pdf_array_len(ctx, pdf_array_get(ctx, optarr, i));\n        if (m == 2) {\n            val = Py_BuildValue(\"ss\",\n            pdf_to_text_string(ctx, pdf_array_get(ctx, pdf_array_get(ctx, optarr, i), 0)),\n            pdf_to_text_string(ctx, pdf_array_get(ctx, pdf_array_get(ctx, optarr, i), 1)));\n            LIST_APPEND_DROP(liste, val);\n        } else {\n            val = JM_UnicodeFromStr(pdf_to_text_string(ctx, pdf_array_get(ctx, optarr, i)));\n            LIST_APPEND_DROP(liste, val);\n        }\n    }\n    return liste;\n}\n\n\n// set ListBox / ComboBox values\n//-----------------------------------------------------------------------------\nvoid JM_set_choice_options(fz_context *ctx, pdf_annot *annot, PyObject *liste)\n{\n    if (!liste) return;\n    if (!PySequence_Check(liste)) return;\n    Py_ssize_t i, n = PySequence_Size(liste);\n    if (n < 1) return;\n    PyObject *tuple = PySequence_Tuple(liste);\n    PyObject *val = NULL, *val1 = NULL, *val2 = NULL;\n    pdf_obj *optarrsub = NULL, *optarr = NULL, *annot_obj = NULL;\n    pdf_document *pdf = NULL;\n    const char *opt = NULL, *opt1 = NULL, *opt2 = NULL;\n    fz_try(ctx) {\n        annot_obj = pdf_annot_obj(ctx, annot);\n        pdf = pdf_get_bound_document(ctx, annot_obj);\n        optarr = pdf_new_array(ctx, pdf, (int) n);\n    for (i = 0; i < n; i++) {\n        val = PyTuple_GET_ITEM(tuple, i);\n        opt = PyUnicode_AsUTF8(val);\n        if (opt) {\n            pdf_array_push_text_string(ctx, optarr, opt);\n        } else {\n                if (!PySequence_Check(val) || PySequence_Size(val) != 2) {\n                    RAISEPY(ctx, \"bad choice field list\", PyExc_ValueError);\n                }\n                val1 = PySequence_GetItem(val, 0);\n                opt1 = PyUnicode_AsUTF8(val1);\n                if (!opt1) {\n                    RAISEPY(ctx, \"bad choice field list\", PyExc_ValueError);\n                }\n                val2 = PySequence_GetItem(val, 1);\n                opt2 = PyUnicode_AsUTF8(val2);\n                if (!opt2) {\n                    RAISEPY(ctx, \"bad choice field list\", PyExc_ValueError);\n                };\n                Py_CLEAR(val1);\n                Py_CLEAR(val2);\n            optarrsub = pdf_array_push_array(ctx, optarr, 2);\n            pdf_array_push_text_string(ctx, optarrsub, opt1);\n            pdf_array_push_text_string(ctx, optarrsub, opt2);\n        }\n    }\n    pdf_dict_put_drop(ctx, annot_obj, PDF_NAME(Opt), optarr);\n    }\n    fz_always(ctx) {\n        Py_CLEAR(tuple);\n        Py_CLEAR(val1);\n        Py_CLEAR(val2);\n        PyErr_Clear();\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return;\n}\n\n\n//-----------------------------------------------------------------------------\n// Populate a Python Widget object with the values from a PDF form field.\n// Called by \"Page.firstWidget\" and \"Widget.next\".\n//-----------------------------------------------------------------------------\nvoid JM_get_widget_properties(fz_context *ctx, pdf_annot *annot, PyObject *Widget)\n{\n    pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n    pdf_page *page = pdf_annot_page(ctx, annot);\n    pdf_document *pdf = page->doc;\n    pdf_annot *tw = annot;\n    pdf_obj *obj = NULL;\n    Py_ssize_t i = 0, n = 0;\n    fz_try(ctx) {\n        int field_type = pdf_widget_type(ctx, tw);\n        SETATTR_DROP(Widget, \"field_type\", Py_BuildValue(\"i\", field_type));\n        if (field_type == PDF_WIDGET_TYPE_SIGNATURE) {\n            if (pdf_signature_is_signed(ctx, pdf, annot_obj)) {\n                SETATTR(\"is_signed\", Py_True);\n            } else {\n                SETATTR(\"is_signed\", Py_False);\n            }\n        } else {\n            SETATTR(\"is_signed\", Py_None);\n        }\n        SETATTR_DROP(Widget, \"border_style\",\n                JM_UnicodeFromStr(pdf_field_border_style(ctx, annot_obj)));\n        SETATTR_DROP(Widget, \"field_type_string\",\n                JM_UnicodeFromStr(JM_field_type_text(field_type)));\n\n        #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR <= 22\n            char *field_name = pdf_field_name(ctx, annot_obj);\n        #else\n            char *field_name = pdf_load_field_name(ctx, annot_obj);\n        #endif\n        SETATTR_DROP(Widget, \"field_name\", JM_UnicodeFromStr(field_name));\n        JM_Free(field_name);\n\n        const char *label = NULL;\n        obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(TU));\n        if (obj) label = pdf_to_text_string(ctx, obj);\n        SETATTR_DROP(Widget, \"field_label\", JM_UnicodeFromStr(label));\n\n        const char *fvalue = NULL;\n        if (field_type == PDF_WIDGET_TYPE_RADIOBUTTON) {\n            obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(Parent));  // owning RB group\n            if (obj) {\n                SETATTR_DROP(Widget, \"rb_parent\", Py_BuildValue(\"i\", pdf_to_num(ctx, obj)));\n            }\n            obj = pdf_dict_get(ctx, annot_obj, PDF_NAME(AS));\n            if (obj) {\n                fvalue = pdf_to_name(ctx, obj);\n            }\n        }\n        if (!fvalue) {\n            fvalue = pdf_field_value(ctx, annot_obj);\n        }\n        SETATTR_DROP(Widget, \"field_value\", JM_UnicodeFromStr(fvalue));\n\n        SETATTR_DROP(Widget, \"field_display\",\n                Py_BuildValue(\"i\", pdf_field_display(ctx, annot_obj)));\n\n        float border_width = pdf_to_real(ctx, pdf_dict_getl(ctx, annot_obj,\n                                PDF_NAME(BS), PDF_NAME(W), NULL));\n        if (border_width == 0) border_width = 1;\n        SETATTR_DROP(Widget, \"border_width\",\n                Py_BuildValue(\"f\", border_width));\n\n        obj = pdf_dict_getl(ctx, annot_obj,\n                                PDF_NAME(BS), PDF_NAME(D), NULL);\n        if (pdf_is_array(ctx, obj)) {\n            n = (Py_ssize_t) pdf_array_len(ctx, obj);\n            PyObject *d = PyList_New(n);\n            for (i = 0; i < n; i++) {\n                PyList_SET_ITEM(d, i, Py_BuildValue(\"i\", pdf_to_int(ctx,\n                                pdf_array_get(ctx, obj, (int) i))));\n            }\n            SETATTR_DROP(Widget, \"border_dashes\", d);\n        }\n\n        SETATTR_DROP(Widget, \"text_maxlen\",\n                Py_BuildValue(\"i\", pdf_text_widget_max_len(ctx, tw)));\n\n        SETATTR_DROP(Widget, \"text_format\",\n                Py_BuildValue(\"i\", pdf_text_widget_format(ctx, tw)));\n\n        obj = pdf_dict_getl(ctx, annot_obj, PDF_NAME(MK), PDF_NAME(BG), NULL);\n        if (pdf_is_array(ctx, obj)) {\n            n = (Py_ssize_t) pdf_array_len(ctx, obj);\n            PyObject *col = PyList_New(n);\n            for (i = 0; i < n; i++) {\n                PyList_SET_ITEM(col, i, Py_BuildValue(\"f\",\n                pdf_to_real(ctx, pdf_array_get(ctx, obj, (int) i))));\n            }\n            SETATTR_DROP(Widget, \"fill_color\", col);\n        }\n\n        obj = pdf_dict_getl(ctx, annot_obj, PDF_NAME(MK), PDF_NAME(BC), NULL);\n        if (pdf_is_array(ctx, obj)) {\n            n = (Py_ssize_t) pdf_array_len(ctx, obj);\n            PyObject *col = PyList_New(n);\n            for (i = 0; i < n; i++) {\n                PyList_SET_ITEM(col, i, Py_BuildValue(\"f\",\n                pdf_to_real(ctx, pdf_array_get(ctx, obj, (int) i))));\n            }\n            SETATTR_DROP(Widget, \"border_color\", col);\n        }\n\n        SETATTR_DROP(Widget, \"choice_values\", JM_choice_options(ctx, annot));\n\n        const char *da = pdf_to_text_string(ctx, pdf_dict_get_inheritable(ctx,\n                                        annot_obj, PDF_NAME(DA)));\n        SETATTR_DROP(Widget, \"_text_da\", JM_UnicodeFromStr(da));\n\n        obj = pdf_dict_getl(ctx, annot_obj, PDF_NAME(MK), PDF_NAME(CA), NULL);\n        if (obj) {\n            SETATTR_DROP(Widget, \"button_caption\",\n                    JM_UnicodeFromStr((char *)pdf_to_text_string(ctx, obj)));\n        }\n\n        SETATTR_DROP(Widget, \"field_flags\",\n                Py_BuildValue(\"i\", pdf_field_flags(ctx, annot_obj)));\n\n        // call Py method to reconstruct text color, font name, size\n        PyObject *call = CALLATTR(\"_parse_da\", NULL);\n        Py_XDECREF(call);\n\n        // extract JavaScript action texts\n        SETATTR_DROP(Widget, \"script\",\n            JM_get_script(ctx, pdf_dict_get(ctx, annot_obj, PDF_NAME(A))));\n\n        SETATTR_DROP(Widget, \"script_stroke\",\n            JM_get_script(ctx, pdf_dict_getl(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(K), NULL)));\n\n        SETATTR_DROP(Widget, \"script_format\",\n            JM_get_script(ctx, pdf_dict_getl(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(F), NULL)));\n\n        SETATTR_DROP(Widget, \"script_change\",\n            JM_get_script(ctx, pdf_dict_getl(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(V), NULL)));\n\n        SETATTR_DROP(Widget, \"script_calc\",\n            JM_get_script(ctx, pdf_dict_getl(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(C), NULL)));\n\n        SETATTR_DROP(Widget, \"script_blur\",\n            JM_get_script(ctx, pdf_dict_getl(ctx, annot_obj, PDF_NAME(AA), pdf_new_name(ctx, \"Bl\"), NULL)));\n\n        SETATTR_DROP(Widget, \"script_focus\",\n            JM_get_script(ctx, pdf_dict_getl(ctx, annot_obj, PDF_NAME(AA), pdf_new_name(ctx, \"Fo\"), NULL)));\n    }\n    fz_always(ctx) PyErr_Clear();\n    fz_catch(ctx) fz_rethrow(ctx);\n    return;\n}\n\n\n//-----------------------------------------------------------------------------\n// Update the PDF form field with the properties from a Python Widget object.\n// Called by \"Page.addWidget\" and \"Annot.updateWidget\".\n//-----------------------------------------------------------------------------\nvoid JM_set_widget_properties(fz_context *ctx, pdf_annot *annot, PyObject *Widget)\n{\n    pdf_page *page = pdf_annot_page(ctx, annot);\n    pdf_obj *annot_obj = pdf_annot_obj(ctx, annot);\n    pdf_document *pdf = page->doc;\n    fz_rect rect;\n    pdf_obj *fill_col = NULL, *border_col = NULL;\n    pdf_obj *dashes = NULL;\n    Py_ssize_t i, n = 0;\n    int d;\n    PyObject *value = GETATTR(\"field_type\");\n    int field_type = (int) PyInt_AsLong(value);\n    Py_DECREF(value);\n\n    // rectangle --------------------------------------------------------------\n    value = GETATTR(\"rect\");\n    rect = JM_rect_from_py(value);\n    Py_XDECREF(value);\n    fz_matrix rot_mat = JM_rotate_page_matrix(ctx, page);\n    rect = fz_transform_rect(rect, rot_mat);\n    pdf_set_annot_rect(ctx, annot, rect);\n\n    // fill color -------------------------------------------------------------\n    value = GETATTR(\"fill_color\");\n    if (value && PySequence_Check(value)) {\n        n = PySequence_Size(value);\n        fill_col = pdf_new_array(ctx, pdf, n);\n        double col = 0;\n        for (i = 0; i < n; i++) {\n            JM_FLOAT_ITEM(value, i, &col);\n            pdf_array_push_real(ctx, fill_col, col);\n        }\n        pdf_field_set_fill_color(ctx, annot_obj, fill_col);\n        pdf_drop_obj(ctx, fill_col);\n    }\n    Py_XDECREF(value);\n\n    // dashes -----------------------------------------------------------------\n    value = GETATTR(\"border_dashes\");\n    if (value && PySequence_Check(value)) {\n        n = PySequence_Size(value);\n        dashes = pdf_new_array(ctx, pdf, n);\n        for (i = 0; i < n; i++) {\n            pdf_array_push_int(ctx, dashes,\n                               (int64_t) PyInt_AsLong(PySequence_ITEM(value, i)));\n        }\n        pdf_dict_putl_drop(ctx, annot_obj, dashes,\n                                PDF_NAME(BS),\n                                PDF_NAME(D),\n                                NULL);\n    }\n    Py_XDECREF(value);\n\n    // border color -----------------------------------------------------------\n    value = GETATTR(\"border_color\");\n    if (value && PySequence_Check(value)) {\n        n = PySequence_Size(value);\n        border_col = pdf_new_array(ctx, pdf, n);\n        double col = 0;\n        for (i = 0; i < n; i++) {\n            JM_FLOAT_ITEM(value, i, &col);\n            pdf_array_push_real(ctx, border_col, col);\n        }\n        pdf_dict_putl_drop(ctx, annot_obj, border_col,\n                                PDF_NAME(MK),\n                                PDF_NAME(BC),\n                                NULL);\n    }\n    Py_XDECREF(value);\n\n    // entry ignored - may be used later\n    /*\n    int text_format = (int) PyInt_AsLong(GETATTR(\"text_format\"));\n    */\n\n    // field label -----------------------------------------------------------\n    value = GETATTR(\"field_label\");\n    if (value != Py_None) {\n        char *label = JM_StrAsChar(value);\n        pdf_dict_put_text_string(ctx, annot_obj, PDF_NAME(TU), label);\n    }\n    Py_XDECREF(value);\n\n    // field name -------------------------------------------------------------\n    value = GETATTR(\"field_name\");\n    if (value != Py_None) {\n        char *name = JM_StrAsChar(value);\n        #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR <= 22\n            char *old_name = pdf_field_name(ctx, annot_obj);\n        #else\n            char *old_name = pdf_load_field_name(ctx, annot_obj);\n        #endif\n        if (strcmp(name, old_name) != 0) {\n            pdf_dict_put_text_string(ctx, annot_obj, PDF_NAME(T), name);\n        }\n        JM_Free(old_name);\n    }\n    Py_XDECREF(value);\n\n    // max text len -----------------------------------------------------------\n    if (field_type == PDF_WIDGET_TYPE_TEXT)\n    {\n        value = GETATTR(\"text_maxlen\");\n        int text_maxlen = (int) PyInt_AsLong(value);\n        if (text_maxlen) {\n            pdf_dict_put_int(ctx, annot_obj, PDF_NAME(MaxLen), text_maxlen);\n        }\n        Py_XDECREF(value);\n    }\n    value = GETATTR(\"field_display\");\n    d = (int) PyInt_AsLong(value);\n    Py_XDECREF(value);\n    pdf_field_set_display(ctx, annot_obj, d);\n\n    // choice values ----------------------------------------------------------\n    if (field_type == PDF_WIDGET_TYPE_LISTBOX ||\n        field_type == PDF_WIDGET_TYPE_COMBOBOX) {\n        value = GETATTR(\"choice_values\");\n        JM_set_choice_options(ctx, annot, value);\n        Py_XDECREF(value);\n    }\n\n    // border style -----------------------------------------------------------\n    value = GETATTR(\"border_style\");\n    pdf_obj *val = JM_get_border_style(ctx, value);\n    Py_XDECREF(value);\n    pdf_dict_putl_drop(ctx, annot_obj, val,\n                            PDF_NAME(BS),\n                            PDF_NAME(S),\n                            NULL);\n\n    // border width -----------------------------------------------------------\n    value = GETATTR(\"border_width\");\n    float border_width = (float) PyFloat_AsDouble(value);\n    Py_XDECREF(value);\n    pdf_dict_putl_drop(ctx, annot_obj, pdf_new_real(ctx, border_width),\n                            PDF_NAME(BS),\n                            PDF_NAME(W),\n                            NULL);\n\n    // /DA string -------------------------------------------------------------\n    value = GETATTR(\"_text_da\");\n    char *da = JM_StrAsChar(value);\n    Py_XDECREF(value);\n    pdf_dict_put_text_string(ctx, annot_obj, PDF_NAME(DA), da);\n    pdf_dict_del(ctx, annot_obj, PDF_NAME(DS)); /* not supported by MuPDF */\n    pdf_dict_del(ctx, annot_obj, PDF_NAME(RC)); /* not supported by MuPDF */\n\n    // field flags ------------------------------------------------------------\n    value = GETATTR(\"field_flags\");\n    int field_flags = (int) PyInt_AsLong(value);\n    Py_XDECREF(value);\n    if (!PyErr_Occurred()) {\n        if (field_type == PDF_WIDGET_TYPE_COMBOBOX) {\n            field_flags |= PDF_CH_FIELD_IS_COMBO;\n        } else if (field_type == PDF_WIDGET_TYPE_RADIOBUTTON) {\n            field_flags |= PDF_BTN_FIELD_IS_RADIO;\n        } else if (field_type == PDF_WIDGET_TYPE_BUTTON) {\n            field_flags |= PDF_BTN_FIELD_IS_PUSHBUTTON;\n        }\n        pdf_dict_put_int(ctx, annot_obj, PDF_NAME(Ff), field_flags);\n    }\n\n    // button caption ---------------------------------------------------------\n    value = GETATTR(\"button_caption\");\n    char *ca = JM_StrAsChar(value);\n    if (ca) {\n        pdf_field_set_button_caption(ctx, annot_obj, ca);\n    }\n    Py_XDECREF(value);\n\n    // script (/A) -------------------------------------------------------\n    value = GETATTR(\"script\");\n    JM_put_script(ctx, annot_obj, PDF_NAME(A), NULL, value);\n    Py_CLEAR(value);\n\n    // script (/AA/K) -------------------------------------------------------\n    value = GETATTR(\"script_stroke\");\n    JM_put_script(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(K), value);\n    Py_CLEAR(value);\n\n    // script (/AA/F) -------------------------------------------------------\n    value = GETATTR(\"script_format\");\n    JM_put_script(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(F), value);\n    Py_CLEAR(value);\n\n    // script (/AA/V) -------------------------------------------------------\n    value = GETATTR(\"script_change\");\n    JM_put_script(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(V), value);\n    Py_CLEAR(value);\n\n    // script (/AA/C) -------------------------------------------------------\n    value = GETATTR(\"script_calc\");\n    JM_put_script(ctx, annot_obj, PDF_NAME(AA), PDF_NAME(C), value);\n    Py_CLEAR(value);\n\n    // script (/AA/Bl) ------------------------------------------------------\n    value = GETATTR(\"script_blur\");\n    JM_put_script(ctx, annot_obj, PDF_NAME(AA), pdf_new_name(ctx, \"Bl\"), value);\n    Py_CLEAR(value);\n\n    // script (/AA/Fo) ------------------------------------------------------\n    value = GETATTR(\"script_focus\");\n    JM_put_script(ctx, annot_obj, PDF_NAME(AA), pdf_new_name(ctx, \"Fo\"), value);\n    Py_CLEAR(value);\n\n    // field value ------------------------------------------------------------\n    value = GETATTR(\"field_value\");  // field value\n    char *text = JM_StrAsChar(value);  // convert to text (may fail!)\n\n    switch(field_type)\n    {\n    case PDF_WIDGET_TYPE_RADIOBUTTON:\n        if (PyObject_RichCompareBool(value, Py_False, Py_EQ)) {\n            pdf_set_field_value(ctx, pdf, annot_obj, \"Off\", 1);\n            pdf_dict_put_name(gctx, annot_obj, PDF_NAME(AS), \"Off\");\n        } else {\n            pdf_obj *onstate = pdf_button_field_on_state(ctx, annot_obj);\n            if (onstate) {\n                const char *on = pdf_to_name(ctx, onstate);\n                pdf_set_field_value(ctx, pdf, annot_obj, on, 1);\n                pdf_dict_put_name(gctx, annot_obj, PDF_NAME(AS), on);\n            } else  if (text) {\n                pdf_dict_put_name(gctx, annot_obj, PDF_NAME(AS), text);\n            }\n        }\n        break;\n\n    case PDF_WIDGET_TYPE_CHECKBOX:  // will always be \"Yes\" or \"Off\"\n        if (PyObject_RichCompareBool(value, Py_True, Py_EQ) || text && strcmp(text, \"Yes\")==0) {\n            pdf_dict_put_name(gctx, annot_obj, PDF_NAME(AS), \"Yes\");\n            pdf_dict_put_name(gctx, annot_obj, PDF_NAME(V), \"Yes\");\n        } else {\n            pdf_dict_put_name(gctx, annot_obj, PDF_NAME(AS), \"Off\");\n            pdf_dict_put_name(gctx, annot_obj, PDF_NAME(V), \"Off\");\n        }\n        break;\n\n    default:\n        if (text) {\n            pdf_set_field_value(ctx, pdf, annot_obj, (const char *)text, 1);\n            if (field_type == PDF_WIDGET_TYPE_COMBOBOX || field_type == PDF_WIDGET_TYPE_LISTBOX) {\n                pdf_dict_del(ctx, annot_obj, PDF_NAME(I));\n            }\n        }\n    }\n    Py_CLEAR(value);\n    PyErr_Clear();\n    pdf_dirty_annot(ctx, annot);\n    pdf_set_annot_hot(ctx, annot, 1);\n    pdf_set_annot_active(ctx, annot, 1);\n    pdf_update_annot(ctx, annot);\n}\n#undef SETATTR\n#undef GETATTR\n#undef CALLATTR\n%}\n\n%pythoncode %{\n#------------------------------------------------------------------------------\n# Class describing a PDF form field (\"widget\")\n#------------------------------------------------------------------------------\nclass Widget(object):\n    def __init__(self):\n        self.thisown = True\n        self.border_color = None\n        self.border_style = \"S\"\n        self.border_width = 0\n        self.border_dashes = None\n        self.choice_values = None  # choice fields only\n        self.rb_parent = None  # radio buttons only: xref of owning parent\n\n        self.field_name = None  # field name\n        self.field_label = None  # field label\n        self.field_value = None\n        self.field_flags = 0\n        self.field_display = 0\n        self.field_type = 0  # valid range 1 through 7\n        self.field_type_string = None  # field type as string\n\n        self.fill_color = None\n        self.button_caption = None  # button caption\n        self.is_signed = None  # True / False if signature\n        self.text_color = (0, 0, 0)\n        self.text_font = \"Helv\"\n        self.text_fontsize = 0\n        self.text_maxlen = 0  # text fields only\n        self.text_format = 0  # text fields only\n        self._text_da = \"\"  # /DA = default apparance\n\n        self.script = None  # JavaScript (/A)\n        self.script_stroke = None  # JavaScript (/AA/K)\n        self.script_format = None  # JavaScript (/AA/F)\n        self.script_change = None  # JavaScript (/AA/V)\n        self.script_calc = None  # JavaScript (/AA/C)\n        self.script_blur = None  # JavaScript (/AA/Bl)\n        self.script_focus = None  # JavaScript (/AA/Fo)\n\n        self.rect = None  # annot value\n        self.xref = 0  # annot value\n\n\n    def _validate(self):\n        \"\"\"Validate the class entries.\n        \"\"\"\n        if (self.rect.is_infinite\n            or self.rect.is_empty\n           ):\n            raise ValueError(\"bad rect\")\n\n        if not self.field_name:\n            raise ValueError(\"field name missing\")\n\n        if self.field_label == \"Unnamed\":\n            self.field_label = None\n        CheckColor(self.border_color)\n        CheckColor(self.fill_color)\n        if not self.text_color:\n            self.text_color = (0, 0, 0)\n        CheckColor(self.text_color)\n\n        if not self.border_width:\n            self.border_width = 0\n\n        if not self.text_fontsize:\n            self.text_fontsize = 0\n\n        self.border_style = self.border_style.upper()[0:1]\n\n        # standardize content of JavaScript entries\n        btn_type = self.field_type in (\n            PDF_WIDGET_TYPE_BUTTON,\n            PDF_WIDGET_TYPE_CHECKBOX,\n            PDF_WIDGET_TYPE_RADIOBUTTON\n        )\n        if not self.script:\n            self.script = None\n        elif type(self.script) is not str:\n            raise ValueError(\"script content must be a string\")\n\n        # buttons cannot have the following script actions\n        if btn_type or not self.script_calc:\n            self.script_calc = None\n        elif type(self.script_calc) is not str:\n            raise ValueError(\"script_calc content must be a string\")\n\n        if btn_type or not self.script_change:\n            self.script_change = None\n        elif type(self.script_change) is not str:\n            raise ValueError(\"script_change content must be a string\")\n\n        if btn_type or not self.script_format:\n            self.script_format = None\n        elif type(self.script_format) is not str:\n            raise ValueError(\"script_format content must be a string\")\n\n        if btn_type or not self.script_stroke:\n            self.script_stroke = None\n        elif type(self.script_stroke) is not str:\n            raise ValueError(\"script_stroke content must be a string\")\n\n        if btn_type or not self.script_blur:\n            self.script_blur = None\n        elif type(self.script_blur) is not str:\n            raise ValueError(\"script_blur content must be a string\")\n\n        if btn_type or not self.script_focus:\n            self.script_focus = None\n        elif type(self.script_focus) is not str:\n            raise ValueError(\"script_focus content must be a string\")\n\n        self._checker()  # any field_type specific checks\n\n\n    def _adjust_font(self):\n        \"\"\"Ensure text_font is correctly spelled if empty or from our list.\n\n        Otherwise assume the font is in an existing field.\n        \"\"\"\n        if not self.text_font:\n            self.text_font = \"Helv\"\n            return\n        doc = self.parent.parent\n        for f in doc.FormFonts + [\"Cour\", \"TiRo\", \"Helv\", \"ZaDb\"]:\n            if self.text_font.lower() == f.lower():\n                self.text_font = f\n                return\n        self.text_font = \"Helv\"\n        return\n\n\n    def _parse_da(self):\n        \"\"\"Extract font name, size and color from default appearance string (/DA object).\n\n        Equivalent to 'pdf_parse_default_appearance' function in MuPDF's 'pdf-annot.c'.\n        \"\"\"\n        if not self._text_da:\n            return\n        font = \"Helv\"\n        fsize = 0\n        col = (0, 0, 0)\n        dat = self._text_da.split()  # split on any whitespace\n        for i, item in enumerate(dat):\n            if item == \"Tf\":\n                font = dat[i - 2][1:]\n                fsize = float(dat[i - 1])\n                dat[i] = dat[i-1] = dat[i-2] = \"\"\n                continue\n            if item == \"g\":  # unicolor text\n                col = [(float(dat[i - 1]))]\n                dat[i] = dat[i-1] = \"\"\n                continue\n            if item == \"rg\":  # RGB colored text\n                col = [float(f) for f in dat[i - 3:i]]\n                dat[i] = dat[i-1] = dat[i-2] = dat[i-3] = \"\"\n                continue\n        self.text_font = font\n        self.text_fontsize = fsize\n        self.text_color = col\n        self._text_da = \"\"\n        return\n\n\n    def _checker(self):\n        \"\"\"Any widget type checks.\n        \"\"\"\n        if self.field_type not in range(1, 8):\n            raise ValueError(\"bad field type\")\n\n\n        # if setting a radio button to ON, first set Off all buttons\n        # in the group - this is not done by MuPDF:\n        if self.field_type == PDF_WIDGET_TYPE_RADIOBUTTON and self.field_value not in (False, \"Off\") and hasattr(self, \"parent\"):\n            # so we are about setting this button to ON/True\n            # check other buttons in same group and set them to 'Off'\n            doc = self.parent.parent\n            kids_type, kids_value = doc.xref_get_key(self.xref, \"Parent/Kids\")\n            if kids_type == \"array\":\n                xrefs = tuple(map(int, kids_value[1:-1].replace(\"0 R\",\"\").split()))\n                for xref in xrefs:\n                    if xref != self.xref:\n                        doc.xref_set_key(xref, \"AS\", \"/Off\")\n        # the calling method will now set the intended button to on and\n        # will find everything prepared for correct functioning.\n\n\n    def update(self):\n        \"\"\"Reflect Python object in the PDF.\n        \"\"\"\n        doc = self.parent.parent\n        self._validate()\n\n        self._adjust_font()  # ensure valid text_font name\n\n        # now create the /DA string\n        self._text_da = \"\"\n        if   len(self.text_color) == 3:\n            fmt = \"{:g} {:g} {:g} rg /{f:s} {s:g} Tf\" + self._text_da\n        elif len(self.text_color) == 1:\n            fmt = \"{:g} g /{f:s} {s:g} Tf\" + self._text_da\n        elif len(self.text_color) == 4:\n            fmt = \"{:g} {:g} {:g} {:g} k /{f:s} {s:g} Tf\" + self._text_da\n        self._text_da = fmt.format(*self.text_color, f=self.text_font,\n                                    s=self.text_fontsize)\n\n        # if widget has a '/AA/C' script, make sure it is in the '/CO'\n        # array of the '/AcroForm' dictionary.\n        if self.script_calc:  # there is a \"calculation\" script:\n            # make sure we are in the /CO array\n            util_ensure_widget_calc(self._annot)\n\n        # finally update the widget\n        TOOLS._save_widget(self._annot, self)\n        self._text_da = \"\"\n\n\n    def button_states(self):\n        \"\"\"Return the on/off state names for button widgets.\n\n        A button may have 'normal' or 'pressed down' appearances. While the 'Off'\n        state is usually called like this, the 'On' state is often given a name\n        relating to the functional context.\n        \"\"\"\n        if self.field_type not in (2, 5):\n            return None  # no button type\n        if hasattr(self, \"parent\"):  # field already exists on page\n            doc = self.parent.parent\n        else:\n            return None\n        xref = self.xref\n        states = {\"normal\": None, \"down\": None}\n        APN = doc.xref_get_key(xref, \"AP/N\")\n        if APN[0] == \"dict\":\n            nstates = []\n            APN = APN[1][2:-2]\n            apnt = APN.split(\"/\")[1:]\n            for x in apnt:\n                nstates.append(x.split()[0])\n            states[\"normal\"] = nstates\n        if APN[0] == \"xref\":\n            nstates = []\n            nxref = int(APN[1].split(\" \")[0])\n            APN = doc.xref_object(nxref)\n            apnt = APN.split(\"/\")[1:]\n            for x in apnt:\n                nstates.append(x.split()[0])\n            states[\"normal\"] = nstates\n        APD = doc.xref_get_key(xref, \"AP/D\")\n        if APD[0] == \"dict\":\n            dstates = []\n            APD = APD[1][2:-2]\n            apdt = APD.split(\"/\")[1:]\n            for x in apdt:\n                dstates.append(x.split()[0])\n            states[\"down\"] = dstates\n        if APD[0] == \"xref\":\n            dstates = []\n            dxref = int(APD[1].split(\" \")[0])\n            APD = doc.xref_object(dxref)\n            apdt = APD.split(\"/\")[1:]\n            for x in apdt:\n                dstates.append(x.split()[0])\n            states[\"down\"] = dstates\n        return states\n\n    def on_state(self):\n        \"\"\"Return the \"On\" value for button widgets.\n\n        This is useful for radio buttons mainly. Checkboxes will always return\n        \"Yes\". Radio buttons will return the string that is unequal to \"Off\"\n        as returned by method button_states().\n        If the radio button is new / being created, it does not yet have an\n        \"On\" value. In this case, a warning is shown and True is returned.\n        \"\"\"\n        if self.field_type not in (2, 5):\n            return None  # no checkbox or radio button\n        if self.field_type == 2:\n            return \"Yes\"\n        bstate = self.button_states()\n        if bstate==None:\n            bstate = {}\n        for k in bstate.keys():\n            for v in bstate[k]:\n                if v != \"Off\":\n                    return v\n        print(\"warning: radio button has no 'On' value.\")\n        return True\n\n    def reset(self):\n        \"\"\"Reset the field value to its default.\n        \"\"\"\n        TOOLS._reset_widget(self._annot)\n\n    def __repr__(self):\n        return \"'%s' widget on %s\" % (self.field_type_string, str(self.parent))\n\n    def __del__(self):\n        if hasattr(self, \"_annot\"):\n            del self._annot\n\n    @property\n    def next(self):\n        return self._annot.next\n%}\n"
  },
  {
    "path": "src_classic/helper-fileobj.i",
    "content": "%{\n//-------------------------------------\n// fz_output for Python file objects\n//-------------------------------------\nstatic void\nJM_bytesio_write(fz_context *ctx, void *opaque, const void *data, size_t len)\n{  // bio.write(bytes object)\n    PyObject *bio = opaque, *b, *name, *rc;\n    fz_try(ctx){\n        b = PyBytes_FromStringAndSize((const char *) data, (Py_ssize_t) len);\n        name = PyUnicode_FromString(\"write\");\n        PyObject_CallMethodObjArgs(bio, name, b, NULL);\n        rc = PyErr_Occurred();\n        if (rc) {\n            RAISEPY(ctx, \"could not write to Py file obj\", rc);\n        }\n    }\n    fz_always(ctx) {\n        Py_XDECREF(b);\n        Py_XDECREF(name);\n        Py_XDECREF(rc);\n        PyErr_Clear();\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\nstatic void\nJM_bytesio_truncate(fz_context *ctx, void *opaque)\n{  // bio.truncate(bio.tell()) !!!\n    PyObject *bio = opaque, *trunc = NULL, *tell = NULL, *rctell= NULL, *rc = NULL;\n    fz_try(ctx) {\n        trunc = PyUnicode_FromString(\"truncate\");\n        tell = PyUnicode_FromString(\"tell\");\n        rctell = PyObject_CallMethodObjArgs(bio, tell, NULL);\n        PyObject_CallMethodObjArgs(bio, trunc, rctell, NULL);\n        rc = PyErr_Occurred();\n        if (rc) {\n            RAISEPY(ctx, \"could not truncate Py file obj\", rc);\n        }\n    }\n    fz_always(ctx) {\n        Py_XDECREF(tell);\n        Py_XDECREF(trunc);\n        Py_XDECREF(rc);\n        Py_XDECREF(rctell);\n        PyErr_Clear();\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\nstatic int64_t\nJM_bytesio_tell(fz_context *ctx, void *opaque)\n{  // returns bio.tell() -> int\n    PyObject *bio = opaque, *rc = NULL, *name = NULL;\n    int64_t pos = 0;\n    fz_try(ctx) {\n        name = PyUnicode_FromString(\"tell\");\n        rc = PyObject_CallMethodObjArgs(bio, name, NULL);\n        if (!rc) {\n            RAISEPY(ctx, \"could not tell Py file obj\", PyErr_Occurred());\n        }\n        pos = (int64_t) PyLong_AsUnsignedLongLong(rc);\n    }\n    fz_always(ctx) {\n        Py_XDECREF(name);\n        Py_XDECREF(rc);\n        PyErr_Clear();\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return pos;\n}\n\n\nstatic void\nJM_bytesio_seek(fz_context *ctx, void *opaque, int64_t off, int whence)\n{  // bio.seek(off, whence=0)\n    PyObject *bio = opaque, *rc = NULL, *name = NULL, *pos = NULL;\n    fz_try(ctx) {\n        name = PyUnicode_FromString(\"seek\");\n        pos = PyLong_FromUnsignedLongLong((unsigned long long) off);\n        PyObject_CallMethodObjArgs(bio, name, pos, whence, NULL);\n        rc = PyErr_Occurred();\n        if (rc) {\n            RAISEPY(ctx, \"could not seek Py file obj\", rc);\n        }\n    }\n    fz_always(ctx) {\n        Py_XDECREF(rc);\n        Py_XDECREF(name);\n        Py_XDECREF(pos);\n        PyErr_Clear();\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\nfz_output *\nJM_new_output_fileptr(fz_context *ctx, PyObject *bio)\n{\n    fz_output *out = fz_new_output(ctx, 0, bio, JM_bytesio_write, NULL, NULL);\n    out->seek = JM_bytesio_seek;\n    out->tell = JM_bytesio_tell;\n    out->truncate = JM_bytesio_truncate;\n    return out;\n}\n%}\n"
  },
  {
    "path": "src_classic/helper-geo-c.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//-----------------------------------------------------------------------------\n// Functions converting betwenn PySequences and fitz geometry objects\n//-----------------------------------------------------------------------------\nstatic int\nJM_INT_ITEM(PyObject *obj, Py_ssize_t idx, int *result)\n{\n    PyObject *temp = PySequence_ITEM(obj, idx);\n    if (!temp) return 1;\n    if (PyLong_Check(temp)) {\n        *result = (int) PyLong_AsLong(temp);\n        Py_DECREF(temp);\n    } else if (PyFloat_Check(temp)) {\n        *result = (int) PyFloat_AsDouble(temp);\n        Py_DECREF(temp);\n    } else {\n        Py_DECREF(temp);\n        return 1;\n    }\n    if (PyErr_Occurred()) {\n        PyErr_Clear();\n        return 1;\n    }\n    return 0;\n}\n\nstatic int\nJM_FLOAT_ITEM(PyObject *obj, Py_ssize_t idx, double *result)\n{\n    PyObject *temp = PySequence_ITEM(obj, idx);\n    if (!temp) return 1;\n    *result = PyFloat_AsDouble(temp);\n    Py_DECREF(temp);\n    if (PyErr_Occurred()) {\n        PyErr_Clear();\n        return 1;\n    }\n    return 0;\n}\n\n\nstatic fz_point\nJM_normalize_vector(float x, float y)\n{\n    double px = x, py = y, len = (double) (x * x + y * y);\n\n    if (len != 0) {\n        len = sqrt(len);\n        px /= len;\n        py /= len;\n    }\n    return fz_make_point((float) px, (float) py);\n}\n\n\n//-----------------------------------------------------------------------------\n// PySequence to fz_rect. Default: infinite rect\n//-----------------------------------------------------------------------------\nstatic fz_rect\nJM_rect_from_py(PyObject *r)\n{\n    if (!r || !PySequence_Check(r) || PySequence_Size(r) != 4)\n        return fz_infinite_rect;\n    Py_ssize_t i;\n    double f[4];\n\n    for (i = 0; i < 4; i++) {\n        if (JM_FLOAT_ITEM(r, i, &f[i]) == 1) return fz_infinite_rect;\n        if (f[i] < FZ_MIN_INF_RECT) f[i] = FZ_MIN_INF_RECT;\n        if (f[i] > FZ_MAX_INF_RECT) f[i] = FZ_MAX_INF_RECT;\n    }\n\n    return fz_make_rect((float) f[0], (float) f[1], (float) f[2], (float) f[3]);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_rect\n//-----------------------------------------------------------------------------\nstatic PyObject *\nJM_py_from_rect(fz_rect r)\n{\n    return Py_BuildValue(\"ffff\", r.x0, r.y0, r.x1, r.y1);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence to fz_irect. Default: infinite irect\n//-----------------------------------------------------------------------------\nstatic fz_irect\nJM_irect_from_py(PyObject *r)\n{\n    if (!r || !PySequence_Check(r) || PySequence_Size(r) != 4)\n        return fz_infinite_irect;\n    int x[4];\n    Py_ssize_t i;\n\n    for (i = 0; i < 4; i++) {\n        if (JM_INT_ITEM(r, i, &x[i]) == 1) return fz_infinite_irect;\n        if (x[i] < FZ_MIN_INF_RECT) x[i] = FZ_MIN_INF_RECT;\n        if (x[i] > FZ_MAX_INF_RECT) x[i] = FZ_MAX_INF_RECT;\n    }\n\n    return fz_make_irect(x[0], x[1], x[2], x[3]);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_irect\n//-----------------------------------------------------------------------------\nstatic PyObject *\nJM_py_from_irect(fz_irect r)\n{\n    return Py_BuildValue(\"iiii\", r.x0, r.y0, r.x1, r.y1);\n}\n\n\n//-----------------------------------------------------------------------------\n// PySequence to fz_point. Default: (FZ_MIN_INF_RECT, FZ_MIN_INF_RECT)\n//-----------------------------------------------------------------------------\nstatic fz_point\nJM_point_from_py(PyObject *p)\n{\n    fz_point p0 = fz_make_point(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT);\n    double x, y;\n\n    if (!p || !PySequence_Check(p) || PySequence_Size(p) != 2)\n        return p0;\n\n    if (JM_FLOAT_ITEM(p, 0, &x) == 1) return p0;\n    if (JM_FLOAT_ITEM(p, 1, &y) == 1) return p0;\n    if (x < FZ_MIN_INF_RECT) x = FZ_MIN_INF_RECT;\n    if (y < FZ_MIN_INF_RECT) y = FZ_MIN_INF_RECT;\n    if (x > FZ_MAX_INF_RECT) x = FZ_MAX_INF_RECT;\n    if (y > FZ_MAX_INF_RECT) y = FZ_MAX_INF_RECT;\n\n    return fz_make_point((float) x, (float) y);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_point\n//-----------------------------------------------------------------------------\nstatic PyObject *\nJM_py_from_point(fz_point p)\n{\n    return Py_BuildValue(\"ff\", p.x, p.y);\n}\n\n\n//-----------------------------------------------------------------------------\n// PySequence to fz_matrix. Default: fz_identity\n//-----------------------------------------------------------------------------\nstatic fz_matrix\nJM_matrix_from_py(PyObject *m)\n{\n    Py_ssize_t i;\n    double a[6];\n\n    if (!m || !PySequence_Check(m) || PySequence_Size(m) != 6)\n        return fz_identity;\n\n    for (i = 0; i < 6; i++)\n        if (JM_FLOAT_ITEM(m, i, &a[i]) == 1) return fz_identity;\n\n    return fz_make_matrix((float) a[0], (float) a[1], (float) a[2], (float) a[3], (float) a[4], (float) a[5]);\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_matrix\n//-----------------------------------------------------------------------------\nstatic PyObject *\nJM_py_from_matrix(fz_matrix m)\n{\n    return Py_BuildValue(\"ffffff\", m.a, m.b, m.c, m.d, m.e, m.f);\n}\n\n//-----------------------------------------------------------------------------\n// fz_quad from PySequence. Four floats are treated as rect.\n// Else must be four pairs of floats.\n//-----------------------------------------------------------------------------\nstatic fz_quad\nJM_quad_from_py(PyObject *r)\n{\n    fz_quad q = fz_make_quad(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT,\n                             FZ_MAX_INF_RECT, FZ_MIN_INF_RECT,\n                             FZ_MIN_INF_RECT, FZ_MAX_INF_RECT,\n                             FZ_MAX_INF_RECT, FZ_MAX_INF_RECT);\n    fz_point p[4];\n    double test, x, y;\n    Py_ssize_t i;\n    PyObject *obj = NULL;\n\n    if (!r || !PySequence_Check(r) || PySequence_Size(r) != 4)\n        return q;\n\n    if (JM_FLOAT_ITEM(r, 0, &test) == 0)\n        return fz_quad_from_rect(JM_rect_from_py(r));\n\n    for (i = 0; i < 4; i++) {\n        obj = PySequence_ITEM(r, i);  // next point item\n        if (!obj || !PySequence_Check(obj) || PySequence_Size(obj) != 2)\n            goto exit_result;  // invalid: cancel the rest\n\n        if (JM_FLOAT_ITEM(obj, 0, &x) == 1) goto exit_result;\n        if (JM_FLOAT_ITEM(obj, 1, &y) == 1) goto exit_result;\n        if (x < FZ_MIN_INF_RECT) x = FZ_MIN_INF_RECT;\n        if (y < FZ_MIN_INF_RECT) y = FZ_MIN_INF_RECT;\n        if (x > FZ_MAX_INF_RECT) x = FZ_MAX_INF_RECT;\n        if (y > FZ_MAX_INF_RECT) y = FZ_MAX_INF_RECT;\n        p[i] = fz_make_point((float) x, (float) y);\n\n        Py_CLEAR(obj);\n    }\n    q.ul = p[0];\n    q.ur = p[1];\n    q.ll = p[2];\n    q.lr = p[3];\n    return q;\n\n    exit_result:;\n    Py_CLEAR(obj);\n    return q;\n}\n\n//-----------------------------------------------------------------------------\n// PySequence from fz_quad.\n//-----------------------------------------------------------------------------\nstatic PyObject *\nJM_py_from_quad(fz_quad q)\n{\n    return Py_BuildValue(\"((f,f),(f,f),(f,f),(f,f))\",\n                          q.ul.x, q.ul.y, q.ur.x, q.ur.y,\n                          q.ll.x, q.ll.y, q.lr.x, q.lr.y);\n}\n\n%}\n"
  },
  {
    "path": "src_classic/helper-geo-py.i",
    "content": "%pythoncode %{\n\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n\n# largest 32bit integers surviving C float conversion roundtrips\n# used by MuPDF to define infinite rectangles\nFZ_MIN_INF_RECT = -0x80000000\nFZ_MAX_INF_RECT = 0x7fffff80\n\n\nclass Matrix(object):\n    \"\"\"Matrix() - all zeros\n    Matrix(a, b, c, d, e, f)\n    Matrix(zoom-x, zoom-y) - zoom\n    Matrix(shear-x, shear-y, 1) - shear\n    Matrix(degree) - rotate\n    Matrix(Matrix) - new copy\n    Matrix(sequence) - from 'sequence'\"\"\"\n    def __init__(self, *args):\n        if not args:\n            self.a = self.b = self.c = self.d = self.e = self.f = 0.0\n            return None\n        if len(args) > 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        if len(args) == 6:  # 6 numbers\n            self.a, self.b, self.c, self.d, self.e, self.f = map(float, args)\n            return None\n        if len(args) == 1:  # either an angle or a sequ\n            if hasattr(args[0], \"__float__\"):\n                theta = math.radians(args[0])\n                c = round(math.cos(theta), 12)\n                s = round(math.sin(theta), 12)\n                self.a = self.d = c\n                self.b = s\n                self.c = -s\n                self.e = self.f = 0.0\n                return None\n            else:\n                self.a, self.b, self.c, self.d, self.e, self.f = map(float, args[0])\n                return None\n        if len(args) == 2 or len(args) == 3 and args[2] == 0:\n            self.a, self.b, self.c, self.d, self.e, self.f = float(args[0]), \\\n                0.0, 0.0, float(args[1]), 0.0, 0.0\n            return None\n        if len(args) == 3 and args[2] == 1:\n            self.a, self.b, self.c, self.d, self.e, self.f = 1.0, \\\n                float(args[1]), float(args[0]), 1.0, 0.0, 0.0\n            return None\n        raise ValueError(\"Matrix: bad args\")\n\n    def invert(self, src=None):\n        \"\"\"Calculate the inverted matrix. Return 0 if successful and replace\n        current one. Else return 1 and do nothing.\n        \"\"\"\n        if src is None:\n            dst = util_invert_matrix(self)\n        else:\n            dst = util_invert_matrix(src)\n        if dst[0] == 1:\n            return 1\n        self.a, self.b, self.c, self.d, self.e, self.f = dst[1]\n        return 0\n\n    def pretranslate(self, tx, ty):\n        \"\"\"Calculate pre translation and replace current matrix.\"\"\"\n        tx = float(tx)\n        ty = float(ty)\n        self.e += tx * self.a + ty * self.c\n        self.f += tx * self.b + ty * self.d\n        return self\n\n    def prescale(self, sx, sy):\n        \"\"\"Calculate pre scaling and replace current matrix.\"\"\"\n        sx = float(sx)\n        sy = float(sy)\n        self.a *= sx\n        self.b *= sx\n        self.c *= sy\n        self.d *= sy\n        return self\n\n    def preshear(self, h, v):\n        \"\"\"Calculate pre shearing and replace current matrix.\"\"\"\n        h = float(h)\n        v = float(v)\n        a, b = self.a, self.b\n        self.a += v * self.c\n        self.b += v * self.d\n        self.c += h * a\n        self.d += h * b\n        return self\n\n    def prerotate(self, theta):\n        \"\"\"Calculate pre rotation and replace current matrix.\"\"\"\n        theta = float(theta)\n        while theta < 0: theta += 360\n        while theta >= 360: theta -= 360\n        if abs(0 - theta) < EPSILON:\n            pass\n\n        elif abs(90.0 - theta) < EPSILON:\n            a = self.a\n            b = self.b\n            self.a = self.c\n            self.b = self.d\n            self.c = -a\n            self.d = -b\n\n        elif abs(180.0 - theta) < EPSILON:\n            self.a = -self.a\n            self.b = -self.b\n            self.c = -self.c\n            self.d = -self.d\n\n        elif abs(270.0 - theta) < EPSILON:\n            a = self.a\n            b = self.b\n            self.a = -self.c\n            self.b = -self.d\n            self.c = a\n            self.d = b\n\n        else:\n            rad = math.radians(theta)\n            s = math.sin(rad)\n            c = math.cos(rad)\n            a = self.a\n            b = self.b\n            self.a = c * a + s * self.c\n            self.b = c * b + s * self.d\n            self.c =-s * a + c * self.c\n            self.d =-s * b + c * self.d\n\n        return self\n\n    def concat(self, one, two):\n        \"\"\"Multiply two matrices and replace current one.\"\"\"\n        if not len(one) == len(two) == 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.a, self.b, self.c, self.d, self.e, self.f = util_concat_matrix(one, two)\n        return self\n\n    def __getitem__(self, i):\n        return (self.a, self.b, self.c, self.d, self.e, self.f)[i]\n\n    def __setitem__(self, i, v):\n        v = float(v)\n        if   i == 0: self.a = v\n        elif i == 1: self.b = v\n        elif i == 2: self.c = v\n        elif i == 3: self.d = v\n        elif i == 4: self.e = v\n        elif i == 5: self.f = v\n        else:\n            raise IndexError(\"index out of range\")\n        return\n\n    def __len__(self):\n        return 6\n\n    def __repr__(self):\n        return \"Matrix\" + str(tuple(self))\n\n    def __invert__(self):\n        \"\"\"Calculate inverted matrix.\"\"\"\n        m1 = Matrix()\n        m1.invert(self)\n        return m1\n    __inv__ = __invert__\n\n    def __mul__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a * m, self.b * m, self.c * m,\n                          self.d * m, self.e * m, self.f * m)\n        m1 = Matrix(1,1)\n        return m1.concat(self, m)\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a * 1./m, self.b * 1./m, self.c * 1./m,\n                          self.d * 1./m, self.e * 1./m, self.f * 1./m)\n        m1 = util_invert_matrix(m)[1]\n        if not m1:\n            raise ZeroDivisionError(\"matrix not invertible\")\n        m2 = Matrix(1,1)\n        return m2.concat(self, m1)\n    __div__ = __truediv__\n\n    def __add__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a + m, self.b + m, self.c + m,\n                          self.d + m, self.e + m, self.f + m)\n        if len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        return Matrix(self.a + m[0], self.b + m[1], self.c + m[2],\n                          self.d + m[3], self.e + m[4], self.f + m[5])\n\n    def __sub__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Matrix(self.a - m, self.b - m, self.c - m,\n                          self.d - m, self.e - m, self.f - m)\n        if len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        return Matrix(self.a - m[0], self.b - m[1], self.c - m[2],\n                          self.d - m[3], self.e - m[4], self.f - m[5])\n\n    def __pos__(self):\n        return Matrix(self)\n\n    def __neg__(self):\n        return Matrix(-self.a, -self.b, -self.c, -self.d, -self.e, -self.f)\n\n    def __bool__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __nonzero__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __eq__(self, mat):\n        if not hasattr(mat, \"__len__\"):\n            return False\n        return len(mat) == 6 and bool(self - mat) is False\n\n    def __abs__(self):\n        return math.sqrt(sum([c*c for c in self]))\n\n    norm = __abs__\n\n    @property\n    def is_rectilinear(self):\n        \"\"\"True if rectangles are mapped to rectangles.\"\"\"\n        return (abs(self.b) < EPSILON and abs(self.c) < EPSILON) or \\\n            (abs(self.a) < EPSILON and abs(self.d) < EPSILON);\n\n\nclass IdentityMatrix(Matrix):\n    \"\"\"Identity matrix [1, 0, 0, 1, 0, 0]\"\"\"\n    def __init__(self):\n        Matrix.__init__(self, 1.0, 1.0)\n    def __setattr__(self, name, value):\n        if name in \"ad\":\n            self.__dict__[name] = 1.0\n        elif name in \"bcef\":\n            self.__dict__[name] = 0.0\n        else:\n            self.__dict__[name] = value\n\n    def checkargs(*args):\n        raise NotImplementedError(\"Identity is readonly\")\n\n    prerotate    = checkargs\n    preshear     = checkargs\n    prescale     = checkargs\n    pretranslate = checkargs\n    concat       = checkargs\n    invert       = checkargs\n\n    def __repr__(self):\n        return \"IdentityMatrix(1.0, 0.0, 0.0, 1.0, 0.0, 0.0)\"\n\n    def __hash__(self):\n        return hash((1,0,0,1,0,0))\n\n\nIdentity = IdentityMatrix()\n\nclass Point(object):\n    \"\"\"Point() - all zeros\\nPoint(x, y)\\nPoint(Point) - new copy\\nPoint(sequence) - from 'sequence'\"\"\"\n    def __init__(self, *args):\n        if not args:\n            self.x = 0.0\n            self.y = 0.0\n            return None\n\n        if len(args) > 2:\n            raise ValueError(\"Point: bad seq len\")\n        if len(args) == 2:\n            self.x = float(args[0])\n            self.y = float(args[1])\n            return None\n        if len(args) == 1:\n            l = args[0]\n            if hasattr(l, \"__getitem__\") is False:\n                raise ValueError(\"Point: bad args\")\n            if len(l) != 2:\n                raise ValueError(\"Point: bad seq len\")\n            self.x = float(l[0])\n            self.y = float(l[1])\n            return None\n        raise ValueError(\"Point: bad args\")\n\n    def transform(self, m):\n        \"\"\"Replace point by its transformation with matrix-like m.\"\"\"\n        if len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.x, self.y = util_transform_point(self, m)\n        return self\n\n    @property\n    def unit(self):\n        \"\"\"Unit vector of the point.\"\"\"\n        s = self.x * self.x + self.y * self.y\n        if s < EPSILON:\n            return Point(0,0)\n        s = math.sqrt(s)\n        return Point(self.x / s, self.y / s)\n\n    @property\n    def abs_unit(self):\n        \"\"\"Unit vector with positive coordinates.\"\"\"\n        s = self.x * self.x + self.y * self.y\n        if s < EPSILON:\n            return Point(0,0)\n        s = math.sqrt(s)\n        return Point(abs(self.x) / s, abs(self.y) / s)\n\n    def distance_to(self, *args):\n        \"\"\"Return distance to rectangle or another point.\"\"\"\n        if not len(args) > 0:\n            raise ValueError(\"at least one parameter must be given\")\n\n        x = args[0]\n        if len(x) == 2:\n            x = Point(x)\n        elif len(x) == 4:\n            x = Rect(x)\n        else:\n            raise ValueError(\"arg1 must be point-like or rect-like\")\n\n        if len(args) > 1:\n            unit = args[1]\n        else:\n            unit = \"px\"\n        u = {\"px\": (1.,1.), \"in\": (1.,72.), \"cm\": (2.54, 72.),\n             \"mm\": (25.4, 72.)}\n        f = u[unit][0] / u[unit][1]\n\n        if type(x) is Point:\n            return abs(self - x) * f\n\n        # from here on, x is a rectangle\n        # as a safeguard, make a finite copy of it\n        r = Rect(x.top_left, x.top_left)\n        r = r | x.bottom_right\n        if self in r:\n            return 0.0\n        if self.x > r.x1:\n            if self.y >= r.y1:\n                return self.distance_to(r.bottom_right, unit)\n            elif self.y <= r.y0:\n                return self.distance_to(r.top_right, unit)\n            else:\n                return (self.x - r.x1) * f\n        elif r.x0 <= self.x <= r.x1:\n            if self.y >= r.y1:\n                return (self.y - r.y1) * f\n            else:\n                return (r.y0 - self.y) * f\n        else:\n            if self.y >= r.y1:\n                return self.distance_to(r.bottom_left, unit)\n            elif self.y <= r.y0:\n                return self.distance_to(r.top_left, unit)\n            else:\n                return (r.x0 - self.x) * f\n\n    def __getitem__(self, i):\n        return (self.x, self.y)[i]\n\n    def __len__(self):\n        return 2\n\n    def __setitem__(self, i, v):\n        v = float(v)\n        if   i == 0: self.x = v\n        elif i == 1: self.y = v\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __repr__(self):\n        return \"Point\" + str(tuple(self))\n\n    def __pos__(self):\n        return Point(self)\n\n    def __neg__(self):\n        return Point(-self.x, -self.y)\n\n    def __bool__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __nonzero__(self):\n        return not (max(self) == min(self) == 0)\n\n    def __eq__(self, p):\n        if not hasattr(p, \"__len__\"):\n            return False\n        return len(p) == 2 and bool(self - p) is False\n\n    def __abs__(self):\n        return math.sqrt(self.x * self.x + self.y * self.y)\n\n    norm = __abs__\n\n    def __add__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Point(self.x + p, self.y + p)\n        if len(p) != 2:\n            raise ValueError(\"Point: bad seq len\")\n        return Point(self.x + p[0], self.y + p[1])\n\n    def __sub__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Point(self.x - p, self.y - p)\n        if len(p) != 2:\n            raise ValueError(\"Point: bad seq len\")\n        return Point(self.x - p[0], self.y - p[1])\n\n    def __mul__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Point(self.x * m, self.y * m)\n        p = Point(self)\n        return p.transform(m)\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Point(self.x * 1./m, self.y * 1./m)\n        m1 = util_invert_matrix(m)[1]\n        if not m1:\n            raise ZeroDivisionError(\"matrix not invertible\")\n        p = Point(self)\n        return p.transform(m1)\n\n    __div__ = __truediv__\n\n    def __hash__(self):\n        return hash(tuple(self))\n\nclass Rect(object):\n    \"\"\"Rect() - all zeros\n    Rect(x0, y0, x1, y1) - 4 coordinates\n    Rect(top-left, x1, y1) - point and 2 coordinates\n    Rect(x0, y0, bottom-right) - 2 coordinates and point\n    Rect(top-left, bottom-right) - 2 points\n    Rect(sequ) - new from sequence or rect-like\n    \"\"\"\n    def __init__(self, *args):\n        self.x0, self.y0, self.x1, self.y1 = util_make_rect(args)\n        return None\n\n    def normalize(self):\n        \"\"\"Replace rectangle with its valid version.\"\"\"\n        if self.x1 < self.x0:\n            self.x0, self.x1 = self.x1, self.x0\n        if self.y1 < self.y0:\n            self.y0, self.y1 = self.y1, self.y0\n        return self\n\n    @property\n    def is_empty(self):\n        \"\"\"True if rectangle area is empty.\"\"\"\n        return self.x0 >= self.x1 or self.y0 >= self.y1\n\n    @property\n    def is_valid(self):\n        \"\"\"True if rectangle is valid.\"\"\"\n        return self.x0 <= self.x1 and self.y0 <= self.y1\n\n    @property\n    def is_infinite(self):\n        \"\"\"True if this is the infinite rectangle.\"\"\"\n        return self.x0 == self.y0 == FZ_MIN_INF_RECT and self.x1 == self.y1 == FZ_MAX_INF_RECT\n\n    @property\n    def top_left(self):\n        \"\"\"Top-left corner.\"\"\"\n        return Point(self.x0, self.y0)\n\n    @property\n    def top_right(self):\n        \"\"\"Top-right corner.\"\"\"\n        return Point(self.x1, self.y0)\n\n    @property\n    def bottom_left(self):\n        \"\"\"Bottom-left corner.\"\"\"\n        return Point(self.x0, self.y1)\n\n    @property\n    def bottom_right(self):\n        \"\"\"Bottom-right corner.\"\"\"\n        return Point(self.x1, self.y1)\n\n    tl = top_left\n    tr = top_right\n    bl = bottom_left\n    br = bottom_right\n\n    @property\n    def quad(self):\n        \"\"\"Return Quad version of rectangle.\"\"\"\n        return Quad(self.tl, self.tr, self.bl, self.br)\n\n    def torect(self, r):\n        \"\"\"Return matrix that converts to target rect.\"\"\"\n\n        r = Rect(r)\n        if self.is_infinite or self.is_empty or r.is_infinite or r.is_empty:\n            raise ValueError(\"rectangles must be finite and not empty\")\n        return (\n            Matrix(1, 0, 0, 1, -self.x0, -self.y0)\n            * Matrix(r.width / self.width, r.height / self.height)\n            * Matrix(1, 0, 0, 1, r.x0, r.y0)\n        )\n\n    def morph(self, p, m):\n        \"\"\"Morph with matrix-like m and point-like p.\n\n        Returns a new quad.\"\"\"\n        if self.is_infinite:\n            return INFINITE_QUAD()\n        return self.quad.morph(p, m)\n\n    def round(self):\n        \"\"\"Return the IRect.\"\"\"\n        return IRect(util_round_rect(self))\n\n    irect = property(round)\n\n    width  = property(lambda self: self.x1 - self.x0 if self.x1 > self.x0 else 0)\n    height = property(lambda self: self.y1 - self.y0 if self.y1 > self.y0 else 0)\n\n    def include_point(self, p):\n        \"\"\"Extend to include point-like p.\"\"\"\n        if len(p) != 2:\n            raise ValueError(\"Point: bad seq len\")\n        self.x0, self.y0, self.x1, self.y1 = util_include_point_in_rect(self, p)\n        return self\n\n    def include_rect(self, r):\n        \"\"\"Extend to include rect-like r.\"\"\"\n        if len(r) != 4:\n            raise ValueError(\"Rect: bad seq len\")\n        r = Rect(r)\n        if r.is_infinite or self.is_infinite:\n            self.x0, self.y0, self.x1, self.y1 = FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT\n        elif r.is_empty:\n            return self\n        elif self.is_empty:\n            self.x0, self.y0, self.x1, self.y1 = r.x0, r.y0, r.x1, r.y1\n        else:\n            self.x0, self.y0, self.x1, self.y1 = util_union_rect(self, r)\n        return self\n\n    def intersect(self, r):\n        \"\"\"Restrict to common rect with rect-like r.\"\"\"\n        if not len(r) == 4:\n            raise ValueError(\"Rect: bad seq len\")\n        r = Rect(r)\n        if r.is_infinite:\n            return self\n        elif self.is_infinite:\n            self.x0, self.y0, self.x1, self.y1 = r.x0, r.y0, r.x1, r.y1\n        elif r.is_empty:\n            self.x0, self.y0, self.x1, self.y1 = r.x0, r.y0, r.x1, r.y1\n        elif self.is_empty:\n            return self\n        else:\n            self.x0, self.y0, self.x1, self.y1 = util_intersect_rect(self, r)\n        return self\n\n    def contains(self, x):\n        \"\"\"Check if containing point-like or rect-like x.\"\"\"\n        return self.__contains__(x)\n\n    def transform(self, m):\n        \"\"\"Replace with the transformation by matrix-like m.\"\"\"\n        if not len(m) == 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.x0, self.y0, self.x1, self.y1 = util_transform_rect(self, m)\n        return self\n\n    def __getitem__(self, i):\n        return (self.x0, self.y0, self.x1, self.y1)[i]\n\n    def __len__(self):\n        return 4\n\n    def __setitem__(self, i, v):\n        v = float(v)\n        if   i == 0: self.x0 = v\n        elif i == 1: self.y0 = v\n        elif i == 2: self.x1 = v\n        elif i == 3: self.y1 = v\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __repr__(self):\n        return \"Rect\" + str(tuple(self))\n\n    def __pos__(self):\n        return Rect(self)\n\n    def __neg__(self):\n        return Rect(-self.x0, -self.y0, -self.x1, -self.y1)\n\n    def __bool__(self):\n        return not self.x0 == self.y0 == self.x1 == self.y1 == 0\n\n    def __nonzero__(self):\n        return not self.x0 == self.y0 == self.x1 == self.y1 == 0\n\n    def __eq__(self, r):\n        if not hasattr(r, \"__len__\"):\n            return False\n        return len(r) == 4 and self.x0 == r[0] and self.y0 == r[1] and self.x1 == r[2] and self.y1 == r[3]\n\n    def __abs__(self):\n        if self.is_infinite or not self.is_valid:\n            return 0.0\n        return self.width * self.height\n\n    def norm(self):\n        return math.sqrt(sum([c*c for c in self]))\n\n    def __add__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Rect(self.x0 + p, self.y0 + p, self.x1 + p, self.y1 + p)\n        if len(p) != 4:\n            raise ValueError(\"Rect: bad seq len\")\n        return Rect(self.x0 + p[0], self.y0 + p[1], self.x1 + p[2], self.y1 + p[3])\n\n\n    def __sub__(self, p):\n        if hasattr(p, \"__float__\"):\n            return Rect(self.x0 - p, self.y0 - p, self.x1 - p, self.y1 - p)\n        if len(p) != 4:\n            raise ValueError(\"Rect: bad seq len\")\n        return Rect(self.x0 - p[0], self.y0 - p[1], self.x1 - p[2], self.y1 - p[3])\n\n\n    def __mul__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Rect(self.x0 * m, self.y0 * m, self.x1 * m, self.y1 * m)\n        r = Rect(self)\n        r = r.transform(m)\n        return r\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            return Rect(self.x0 * 1./m, self.y0 * 1./m, self.x1 * 1./m, self.y1 * 1./m)\n        im = util_invert_matrix(m)[1]\n        if not im:\n            raise ZeroDivisionError(\"Matrix not invertible\")\n        r = Rect(self)\n        r = r.transform(im)\n        return r\n\n    __div__ = __truediv__\n\n    def __contains__(self, x):\n        if hasattr(x, \"__float__\"):\n            return x in tuple(self)\n        l = len(x)\n        if l == 2:\n            return util_is_point_in_rect(x, self)\n        if l == 4:\n            r = INFINITE_RECT()\n            try:\n                r = Rect(x)\n            except:\n                r = Quad(x).rect\n            return (self.x0 <= r.x0 <= r.x1 <= self.x1 and\n                    self.y0 <= r.y0 <= r.y1 <= self.y1)\n        return False\n    \n\n    def __or__(self, x):\n        if not hasattr(x, \"__len__\"):\n            raise ValueError(\"bad type op 2\")\n\n        r = Rect(self)\n        if len(x) == 2:\n            return r.include_point(x)\n        if len(x) == 4:\n            return r.include_rect(x)\n        raise ValueError(\"bad type op 2\")\n\n    def __and__(self, x):\n        if not hasattr(x, \"__len__\") or len(x) != 4:\n            raise ValueError(\"bad type op 2\")\n        r = Rect(self)\n        return r.intersect(x)\n\n    def intersects(self, x):\n        \"\"\"Check if intersection with rectangle x is not empty.\"\"\"\n        r1 = Rect(x)\n        if self.is_empty or self.is_infinite or r1.is_empty or r1.is_infinite:\n            return False\n        r = Rect(self)\n        if r.intersect(r1).is_empty:\n            return False\n        return True\n\n    def __hash__(self):\n        return hash(tuple(self))\n\nclass IRect(object):\n    \"\"\"IRect() - all zeros\n    IRect(x0, y0, x1, y1) - 4 coordinates\n    IRect(top-left, x1, y1) - point and 2 coordinates\n    IRect(x0, y0, bottom-right) - 2 coordinates and point\n    IRect(top-left, bottom-right) - 2 points\n    IRect(sequ) - new from sequence or rect-like\n    \"\"\"\n    def __init__(self, *args):\n        self.x0, self.y0, self.x1, self.y1 = util_make_irect(args)\n        return None\n\n    def normalize(self):\n        \"\"\"Replace rectangle with its valid version.\"\"\"\n        if self.x1 < self.x0:\n            self.x0, self.x1 = self.x1, self.x0\n        if self.y1 < self.y0:\n            self.y0, self.y1 = self.y1, self.y0\n        return self\n\n    @property\n    def is_empty(self):\n        \"\"\"True if rectangle area is empty.\"\"\"\n        return self.x0 >= self.x1 or self.y0 >= self.y1\n\n    @property\n    def is_valid(self):\n        \"\"\"True if rectangle is valid.\"\"\"\n        return self.x0 <= self.x1 and self.y0 <= self.y1\n\n    @property\n    def is_infinite(self):\n        \"\"\"True if rectangle is infinite.\"\"\"\n        return self.x0 == self.y0 == FZ_MIN_INF_RECT and self.x1 == self.y1 == FZ_MAX_INF_RECT\n\n    @property\n    def top_left(self):\n        \"\"\"Top-left corner.\"\"\"\n        return Point(self.x0, self.y0)\n\n    @property\n    def top_right(self):\n        \"\"\"Top-right corner.\"\"\"\n        return Point(self.x1, self.y0)\n\n    @property\n    def bottom_left(self):\n        \"\"\"Bottom-left corner.\"\"\"\n        return Point(self.x0, self.y1)\n\n    @property\n    def bottom_right(self):\n        \"\"\"Bottom-right corner.\"\"\"\n        return Point(self.x1, self.y1)\n\n    tl = top_left\n    tr = top_right\n    bl = bottom_left\n    br = bottom_right\n\n    @property\n    def quad(self):\n        \"\"\"Return Quad version of rectangle.\"\"\"\n        return Quad(self.tl, self.tr, self.bl, self.br)\n\n\n    def torect(self, r):\n        \"\"\"Return matrix that converts to target rect.\"\"\"\n\n        r = Rect(r)\n        if self.is_infinite or self.is_empty or r.is_infinite or r.is_empty:\n            raise ValueError(\"rectangles must be finite and not empty\")\n        return (\n            Matrix(1, 0, 0, 1, -self.x0, -self.y0)\n            * Matrix(r.width / self.width, r.height / self.height)\n            * Matrix(1, 0, 0, 1, r.x0, r.y0)\n        )\n\n    def morph(self, p, m):\n        \"\"\"Morph with matrix-like m and point-like p.\n\n        Returns a new quad.\"\"\"\n        if self.is_infinite:\n            return INFINITE_QUAD()\n        return self.quad.morph(p, m)\n\n    @property\n    def rect(self):\n        return Rect(self)\n\n    width  = property(lambda self: self.x1 - self.x0 if self.x1 > self.x0 else 0)\n    height = property(lambda self: self.y1 - self.y0 if self.y1 > self.y0 else 0)\n\n    def include_point(self, p):\n        \"\"\"Extend rectangle to include point p.\"\"\"\n        rect = self.rect.include_point(p)\n        return rect.irect\n\n    def include_rect(self, r):\n        \"\"\"Extend rectangle to include rectangle r.\"\"\"\n        rect = self.rect.include_rect(r)\n        return rect.irect\n\n    def intersect(self, r):\n        \"\"\"Restrict rectangle to intersection with rectangle r.\"\"\"\n        rect = self.rect.intersect(r)\n        return rect.irect\n\n    def __getitem__(self, i):\n        return (self.x0, self.y0, self.x1, self.y1)[i]\n\n    def __len__(self):\n        return 4\n\n    def __setitem__(self, i, v):\n        v = int(v)\n        if   i == 0: self.x0 = v\n        elif i == 1: self.y0 = v\n        elif i == 2: self.x1 = v\n        elif i == 3: self.y1 = v\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __repr__(self):\n        return \"IRect\" + str(tuple(self))\n\n    def __pos__(self):\n        return IRect(self)\n\n    def __neg__(self):\n        return IRect(-self.x0, -self.y0, -self.x1, -self.y1)\n\n    def __bool__(self):\n        return not self.x0 == self.y0 == self.x1 == self.y1 == 0\n\n    def __nonzero__(self):\n        return not self.x0 == self.y0 == self.x1 == self.y1 == 0\n\n    def __eq__(self, r):\n        if not hasattr(r, \"__len__\"):\n            return False\n        return len(r) == 4 and self.x0 == r[0] and self.y0 == r[1] and self.x1 == r[2] and self.y1 == r[3]\n\n    def __abs__(self):\n        if self.is_infinite or not self.is_valid:\n            return 0\n        return self.width * self.height\n\n    def norm(self):\n        return math.sqrt(sum([c*c for c in self]))\n\n    def __add__(self, p):\n        return Rect.__add__(self, p).round()\n\n    def __sub__(self, p):\n        return Rect.__sub__(self, p).round()\n\n    def transform(self, m):\n        return Rect.transform(self, m).round()\n\n    def __mul__(self, m):\n        return Rect.__mul__(self, m).round()\n\n    def __truediv__(self, m):\n        return Rect.__truediv__(self, m).round()\n\n    __div__ = __truediv__\n\n\n    def __contains__(self, x):\n        return Rect.__contains__(self, x)\n\n\n    def __or__(self, x):\n        return Rect.__or__(self, x).round()\n\n    def __and__(self, x):\n        return Rect.__and__(self, x).round()\n\n    def intersects(self, x):\n        return Rect.intersects(self, x)\n\n    def __hash__(self):\n        return hash(tuple(self))\n\n\nclass Quad(object):\n    \"\"\"Quad() - all zero points\\nQuad(ul, ur, ll, lr)\\nQuad(quad) - new copy\\nQuad(sequence) - from 'sequence'\"\"\"\n    def __init__(self, *args):\n        if not args:\n            self.ul = self.ur = self.ll = self.lr = Point()\n            return None\n\n        if len(args) > 4:\n            raise ValueError(\"Quad: bad seq len\")\n        if len(args) == 4:\n            self.ul, self.ur, self.ll, self.lr = map(Point, args)\n            return None\n        if len(args) == 1:\n            l = args[0]\n            if hasattr(l, \"__getitem__\") is False:\n                raise ValueError(\"Quad: bad args\")\n            if len(l) != 4:\n                raise ValueError(\"Quad: bad seq len\")\n            self.ul, self.ur, self.ll, self.lr = map(Point, l)\n            return None\n        raise ValueError(\"Quad: bad args\")\n\n    @property\n    def is_rectangular(self)->bool:\n        \"\"\"Check if quad is rectangular.\n\n        Notes:\n            Some rotation matrix can thus transform it into a rectangle.\n            This is equivalent to three corners enclose 90 degrees.\n        Returns:\n            True or False.\n        \"\"\"\n\n        sine = util_sine_between(self.ul, self.ur, self.lr)\n        if abs(sine - 1) > EPSILON:  # the sine of the angle\n            return False\n\n        sine = util_sine_between(self.ur, self.lr, self.ll)\n        if abs(sine - 1) > EPSILON:\n            return False\n\n        sine = util_sine_between(self.lr, self.ll, self.ul)\n        if abs(sine - 1) > EPSILON:\n            return False\n\n        return True\n\n\n    @property\n    def is_convex(self)->bool:\n        \"\"\"Check if quad is convex and not degenerate.\n\n        Notes:\n            Check that for the two diagonals, the other two corners are not\n            on the same side of the diagonal.\n        Returns:\n            True or False.\n        \"\"\"\n        m = planish_line(self.ul, self.lr)  # puts this diagonal on x-axis\n        p1 = self.ll * m  # transform the\n        p2 = self.ur * m  # other two points\n        if p1.y * p2.y > 0:\n            return False\n        m = planish_line(self.ll, self.ur)  # puts other diagonal on x-axis\n        p1 = self.lr * m  # tranform the\n        p2 = self.ul * m  # remaining points\n        if p1.y * p2.y > 0:\n            return False\n        return True\n\n\n    width  = property(lambda self: max(abs(self.ul - self.ur), abs(self.ll - self.lr)))\n    height = property(lambda self: max(abs(self.ul - self.ll), abs(self.ur - self.lr)))\n\n    @property\n    def is_empty(self):\n        \"\"\"Check whether all quad corners are on the same line.\n\n        This is the case if width or height is zero.\n        \"\"\"\n        return self.width < EPSILON or self.height < EPSILON\n\n    @property\n    def is_infinite(self):\n        \"\"\"Check whether this is the infinite quad.\"\"\"\n        return self.rect.is_infinite\n\n    @property\n    def rect(self):\n        r = Rect()\n        r.x0 = min(self.ul.x, self.ur.x, self.lr.x, self.ll.x)\n        r.y0 = min(self.ul.y, self.ur.y, self.lr.y, self.ll.y)\n        r.x1 = max(self.ul.x, self.ur.x, self.lr.x, self.ll.x)\n        r.y1 = max(self.ul.y, self.ur.y, self.lr.y, self.ll.y)\n        return r\n\n\n    def __contains__(self, x):\n        try:\n            l = x.__len__()\n        except:\n            return False\n        if l == 2:\n            return util_point_in_quad(x, self)\n        if l != 4:\n            return False\n        if CheckRect(x):\n            if Rect(x).is_empty:\n                return True\n            return util_point_in_quad(x[:2], self) and util_point_in_quad(x[2:], self)\n        if CheckQuad(x):\n            for i in range(4):\n                if not util_point_in_quad(x[i], self):\n                    return False\n            return True\n        return False\n\n\n    def __getitem__(self, i):\n        return (self.ul, self.ur, self.ll, self.lr)[i]\n\n    def __len__(self):\n        return 4\n\n    def __setitem__(self, i, v):\n        if   i == 0: self.ul = Point(v)\n        elif i == 1: self.ur = Point(v)\n        elif i == 2: self.ll = Point(v)\n        elif i == 3: self.lr = Point(v)\n        else:\n            raise IndexError(\"index out of range\")\n        return None\n\n    def __repr__(self):\n        return \"Quad\" + str(tuple(self))\n\n    def __pos__(self):\n        return Quad(self)\n\n    def __neg__(self):\n        return Quad(-self.ul, -self.ur, -self.ll, -self.lr)\n\n    def __bool__(self):\n        return not self.is_empty\n\n    def __nonzero__(self):\n        return not self.is_empty\n\n    def __eq__(self, quad):\n        if not hasattr(quad, \"__len__\"):\n            return False\n        return len(quad) == 4 and (\n            self.ul == quad[0] and\n            self.ur == quad[1] and\n            self.ll == quad[2] and\n            self.lr == quad[3]\n        )\n\n    def __abs__(self):\n        if self.is_empty:\n            return 0.0\n        return abs(self.ul - self.ur) * abs(self.ul - self.ll)\n\n\n    def morph(self, p, m):\n        \"\"\"Morph the quad with matrix-like 'm' and point-like 'p'.\n\n        Return a new quad.\"\"\"\n        if self.is_infinite:\n            return INFINITE_QUAD()\n        delta = Matrix(1, 1).pretranslate(p.x, p.y)\n        q = self * ~delta * m * delta\n        return q\n\n\n    def transform(self, m):\n        \"\"\"Replace quad by its transformation with matrix m.\"\"\"\n        if hasattr(m, \"__float__\"):\n            pass\n        elif len(m) != 6:\n            raise ValueError(\"Matrix: bad seq len\")\n        self.ul *= m\n        self.ur *= m\n        self.ll *= m\n        self.lr *= m\n        return self\n\n    def __mul__(self, m):\n        q = Quad(self)\n        q = q.transform(m)\n        return q\n\n    def __add__(self, q):\n        if hasattr(q, \"__float__\"):\n            return Quad(self.ul + q, self.ur + q, self.ll + q, self.lr + q)\n        if len(p) != 4:\n            raise ValueError(\"Quad: bad seq len\")\n        return Quad(self.ul + q[0], self.ur + q[1], self.ll + q[2], self.lr + q[3])\n\n\n    def __sub__(self, q):\n        if hasattr(q, \"__float__\"):\n            return Quad(self.ul - q, self.ur - q, self.ll - q, self.lr - q)\n        if len(p) != 4:\n            raise ValueError(\"Quad: bad seq len\")\n        return Quad(self.ul - q[0], self.ur - q[1], self.ll - q[2], self.lr - q[3])\n\n\n    def __truediv__(self, m):\n        if hasattr(m, \"__float__\"):\n            im = 1. / m\n        else:\n            im = util_invert_matrix(m)[1]\n            if not im:\n                raise ZeroDivisionError(\"Matrix not invertible\")\n        q = Quad(self)\n        q = q.transform(im)\n        return q\n\n    __div__ = __truediv__\n\n\n    def __hash__(self):\n        return hash(tuple(self))\n\n\n# some special geometry objects\ndef EMPTY_RECT():\n    return Rect(FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT)\n\n\ndef INFINITE_RECT():\n    return Rect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT)\n\n\ndef EMPTY_IRECT():\n    return IRect(FZ_MAX_INF_RECT, FZ_MAX_INF_RECT, FZ_MIN_INF_RECT, FZ_MIN_INF_RECT)\n\n\ndef INFINITE_IRECT():\n    return IRect(FZ_MIN_INF_RECT, FZ_MIN_INF_RECT, FZ_MAX_INF_RECT, FZ_MAX_INF_RECT)\n\n\ndef INFINITE_QUAD():\n    return INFINITE_RECT().quad\n\n\ndef EMPTY_QUAD():\n    return EMPTY_RECT().quad\n\n\n%}\n"
  },
  {
    "path": "src_classic/helper-globals.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n// Global switches\n// Switch for device hints = no cache\nstatic int no_device_caching = 0;\n\n// Switch for computing glyph of fontsize height\nstatic int small_glyph_heights = 0;\n\n// Switch for returning fontnames including subset prefix\nstatic int subset_fontnames = 0;\n\n// Unset ascender / descender corrections\nstatic int skip_quad_corrections = 0;\n\n// constants: error messages\nstatic const char MSG_BAD_ANNOT_TYPE[] = \"bad annot type\";\nstatic const char MSG_BAD_APN[] = \"bad or missing annot AP/N\";\nstatic const char MSG_BAD_ARG_INK_ANNOT[] = \"arg must be seq of seq of float pairs\";\nstatic const char MSG_BAD_ARG_POINTS[] = \"bad seq of points\";\nstatic const char MSG_BAD_BUFFER[] = \"bad type: 'buffer'\";\nstatic const char MSG_BAD_COLOR_SEQ[] = \"bad color sequence\";\nstatic const char MSG_BAD_DOCUMENT[] = \"cannot open broken document\";\nstatic const char MSG_BAD_FILETYPE[] = \"bad filetype\";\nstatic const char MSG_BAD_LOCATION[] = \"bad location\";\nstatic const char MSG_BAD_OC_CONFIG[] = \"bad config number\";\nstatic const char MSG_BAD_OC_LAYER[] = \"bad layer number\";\nstatic const char MSG_BAD_OC_REF[] = \"bad 'oc' reference\";\nstatic const char MSG_BAD_PAGEID[] = \"bad page id\";\nstatic const char MSG_BAD_PAGENO[] = \"bad page number(s)\";\nstatic const char MSG_BAD_PDFROOT[] = \"PDF has no root\";\nstatic const char MSG_BAD_RECT[] = \"rect is infinite or empty\";\nstatic const char MSG_BAD_TEXT[] = \"bad type: 'text'\";\nstatic const char MSG_BAD_XREF[] = \"bad xref\";\nstatic const char MSG_COLOR_COUNT_FAILED[] = \"color count failed\";\nstatic const char MSG_FILE_OR_BUFFER[] = \"need font file or buffer\";\nstatic const char MSG_FONT_FAILED[] = \"cannot create font\";\nstatic const char MSG_IS_NO_ANNOT[] = \"is no annotation\";\nstatic const char MSG_IS_NO_IMAGE[] = \"is no image\";\nstatic const char MSG_IS_NO_PDF[] = \"is no PDF\";\nstatic const char MSG_IS_NO_DICT[] = \"object is no PDF dict\";\nstatic const char MSG_PIX_NOALPHA[] = \"source pixmap has no alpha\";\nstatic const char MSG_PIXEL_OUTSIDE[] = \"pixel(s) outside image\";\n%}\n"
  },
  {
    "path": "src_classic/helper-other.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\nfz_buffer *JM_object_to_buffer(fz_context *ctx, pdf_obj *val, int a, int b);\nPyObject *JM_EscapeStrFromBuffer(fz_context *ctx, fz_buffer *buff);\npdf_obj *JM_pdf_obj_from_str(fz_context *ctx, pdf_document *doc, char *src);\n\n// exception handling\nvoid *JM_ReturnException(fz_context *ctx)\n{\n    PyErr_SetString(JM_Exc_CurrentException, fz_caught_message(ctx));\n    JM_Exc_CurrentException = PyExc_RuntimeError;\n    return NULL;\n}\n\n\nstatic int LIST_APPEND_DROP(PyObject *list, PyObject *item)\n{\n    if (!list || !PyList_Check(list) || !item) return -2;\n    int rc = PyList_Append(list, item);\n    Py_DECREF(item);\n    return rc;\n}\n\nstatic int DICT_SETITEM_DROP(PyObject *dict, PyObject *key, PyObject *value)\n{\n    if (!dict || !PyDict_Check(dict) || !key || !value) return -2;\n    int rc = PyDict_SetItem(dict, key, value);\n    Py_DECREF(value);\n    return rc;\n}\n\nstatic int DICT_SETITEMSTR_DROP(PyObject *dict, const char *key, PyObject *value)\n{\n    if (!dict || !PyDict_Check(dict) || !key || !value) return -2;\n    int rc = PyDict_SetItemString(dict, key, value);\n    Py_DECREF(value);\n    return rc;\n}\n\n\n//--------------------------------------\n// Ensure valid journalling state\n//--------------------------------------\nint JM_have_operation(fz_context *ctx, pdf_document *pdf)\n{\n    if (pdf->journal && !pdf_undoredo_step(ctx, pdf, 0)) {\n        return 0;\n    }\n    return 1;\n}\n\n//----------------------------------\n// Set a PDF dict key to some value\n//----------------------------------\nstatic pdf_obj\n*JM_set_object_value(fz_context *ctx, pdf_obj *obj, const char *key, char *value)\n{\n    fz_buffer *res = NULL;\n    pdf_obj *new_obj = NULL, *testkey = NULL;\n    PyObject *skey = PyUnicode_FromString(key);  // Python version of dict key\n    PyObject *slash = PyUnicode_FromString(\"/\");  // PDF path separator\n    PyObject *list = NULL, *newval=NULL, *newstr=NULL, *nullval=NULL;\n    const char eyecatcher[] = \"fitz: replace me!\";\n    pdf_document *pdf = NULL;\n    fz_try(ctx)\n    {\n        pdf = pdf_get_bound_document(ctx, obj);\n        // split PDF key at path seps and take last key part\n        list = PyUnicode_Split(skey, slash, -1);\n        Py_ssize_t len = PySequence_Size(list);\n        Py_ssize_t i = len - 1;\n        Py_DECREF(skey);\n        skey = PySequence_GetItem(list, i);\n\n        PySequence_DelItem(list, i);  // del the last sub-key\n        len =  PySequence_Size(list);  // remaining length\n        testkey = pdf_dict_getp(ctx, obj, key);  // check if key already exists\n        if (!testkey) {\n            /*-----------------------------------------------------------------\n            No, it will be created here. But we cannot allow this happening if\n            indirect objects are referenced. So we check all higher level\n            sub-paths for indirect references.\n            -----------------------------------------------------------------*/\n            while (len > 0) {\n                PyObject *t = PyUnicode_Join(slash, list);  // next high level\n                if (pdf_is_indirect(ctx, pdf_dict_getp(ctx, obj, JM_StrAsChar(t)))) {\n                    Py_DECREF(t);\n                    fz_throw(ctx, FZ_ERROR_GENERIC, \"path to '%s' has indirects\", JM_StrAsChar(skey));\n                }\n                PySequence_DelItem(list, len - 1);  // del last sub-key\n                len = PySequence_Size(list);  // remaining length\n                Py_DECREF(t);\n            }\n        }\n        // Insert our eyecatcher. Will create all sub-paths in the chain, or\n        // respectively remove old value of key-path.\n        pdf_dict_putp_drop(ctx, obj, key, pdf_new_text_string(ctx, eyecatcher));\n        testkey = pdf_dict_getp(ctx, obj, key);\n        if (!pdf_is_string(ctx, testkey)) {\n            fz_throw(ctx, FZ_ERROR_GENERIC, \"cannot insert value for '%s'\", key);\n        }\n        const char *temp = pdf_to_text_string(ctx, testkey);\n        if (strcmp(temp, eyecatcher) != 0) {\n            fz_throw(ctx, FZ_ERROR_GENERIC, \"cannot insert value for '%s'\", key);\n        }\n        // read the result as a string\n        res = JM_object_to_buffer(ctx, obj, 1, 0);\n        PyObject *objstr = JM_EscapeStrFromBuffer(ctx, res);\n\n        // replace 'eyecatcher' by desired 'value'\n        nullval = PyUnicode_FromFormat(\"/%s(%s)\", JM_StrAsChar(skey), eyecatcher);\n        newval = PyUnicode_FromFormat(\"/%s %s\", JM_StrAsChar(skey), value);\n        newstr = PyUnicode_Replace(objstr, nullval, newval, 1);\n\n        // make PDF object from resulting string\n        new_obj = JM_pdf_obj_from_str(ctx, pdf, JM_StrAsChar(newstr));\n    }\n    fz_always(ctx) {\n        fz_drop_buffer(ctx, res);\n        Py_CLEAR(skey);\n        Py_CLEAR(slash);\n        Py_CLEAR(list);\n        Py_CLEAR(newval);\n        Py_CLEAR(newstr);\n        Py_CLEAR(nullval);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return new_obj;\n}\n\n\nstatic void\nJM_get_page_labels(fz_context *ctx, PyObject *liste, pdf_obj *nums)\n{\n    int pno, i, n = pdf_array_len(ctx, nums);\n    char *c = NULL;\n    pdf_obj *val;\n    fz_buffer *res = NULL;\n    for (i = 0; i < n; i += 2) {\n        pdf_obj *key = pdf_resolve_indirect(ctx, pdf_array_get(ctx, nums, i));\n        pno = pdf_to_int(ctx, key);\n        val = pdf_resolve_indirect(ctx, pdf_array_get(ctx, nums, i + 1));\n        res = JM_object_to_buffer(ctx, val, 1, 0);\n        fz_buffer_storage(ctx, res, &c);\n        LIST_APPEND_DROP(liste, Py_BuildValue(\"is\", pno, c));\n        fz_drop_buffer(ctx, res);\n    }\n}\n\n\nPyObject *JM_EscapeStrFromBuffer(fz_context *ctx, fz_buffer *buff)\n{\n    if (!buff) return EMPTY_STRING;\n    unsigned char *s = NULL;\n    size_t len = fz_buffer_storage(ctx, buff, &s);\n    PyObject *val = PyUnicode_DecodeRawUnicodeEscape((const char *) s, (Py_ssize_t) len, \"replace\");\n    if (!val) {\n        val = EMPTY_STRING;\n        PyErr_Clear();\n    }\n    return val;\n}\n\nPyObject *JM_UnicodeFromBuffer(fz_context *ctx, fz_buffer *buff)\n{\n    unsigned char *s = NULL;\n    Py_ssize_t len = (Py_ssize_t) fz_buffer_storage(ctx, buff, &s);\n    PyObject *val = PyUnicode_DecodeUTF8((const char *) s, len, \"replace\");\n    if (!val) {\n        val = EMPTY_STRING;\n        PyErr_Clear();\n    }\n    return val;\n}\n\nPyObject *JM_UnicodeFromStr(const char *c)\n{\n    if (!c) return EMPTY_STRING;\n    PyObject *val = Py_BuildValue(\"s\", c);\n    if (!val) {\n        val = EMPTY_STRING;\n        PyErr_Clear();\n    }\n    return val;\n}\n\nPyObject *JM_EscapeStrFromStr(const char *c)\n{\n    if (!c) return EMPTY_STRING;\n    PyObject *val = PyUnicode_DecodeRawUnicodeEscape(c, (Py_ssize_t) strlen(c), \"replace\");\n    if (!val) {\n        val = EMPTY_STRING;\n        PyErr_Clear();\n    }\n    return val;\n}\n\n\n// list of valid unicodes of a fz_font\nvoid JM_valid_chars(fz_context *ctx, fz_font *font, void *arr)\n{\n\tFT_Face face = font->ft_face;\n\tFT_ULong ucs;\n\tFT_UInt gid;\n\tlong *table = (long *)arr;\n\tfz_lock(ctx, FZ_LOCK_FREETYPE);\n\tucs = FT_Get_First_Char(face, &gid);\n\twhile (gid > 0)\n\t{\n\t\tif (gid < (FT_ULong)face->num_glyphs && face->num_glyphs > 0)\n\t\t\ttable[gid] = (long)ucs;\n\t\tucs = FT_Get_Next_Char(face, ucs, &gid);\n\t}\n\tfz_unlock(ctx, FZ_LOCK_FREETYPE);\n\treturn;\n}\n\n\n// redirect MuPDF warnings\nvoid JM_mupdf_warning(void *user, const char *message)\n{\n    LIST_APPEND_DROP(JM_mupdf_warnings_store, JM_EscapeStrFromStr(message));\n    if (JM_mupdf_show_warnings) {\n        PySys_WriteStderr(\"mupdf: %s\\n\", message);\n    }\n}\n\n// redirect MuPDF errors\nvoid JM_mupdf_error(void *user, const char *message)\n{\n    LIST_APPEND_DROP(JM_mupdf_warnings_store, JM_EscapeStrFromStr(message));\n    if (JM_mupdf_show_errors) {\n        PySys_WriteStderr(\"mupdf: %s\\n\", message);\n    }\n}\n\n// a simple tracer\nvoid JM_TRACE(const char *id)\n{\n    PySys_WriteStdout(\"%s\\n\", id);\n}\n\n\n// put a warning on Python-stdout\nvoid JM_Warning(const char *id)\n{\n    PySys_WriteStdout(\"warning: %s\\n\", id);\n}\n\n#if JM_MEMORY == 1\n//-----------------------------------------------------------------------------\n// The following 3 functions replace MuPDF standard memory allocation.\n// This will ensure, that MuPDF memory handling becomes part of Python's\n// memory management.\n//-----------------------------------------------------------------------------\nstatic void *JM_Py_Malloc(void *opaque, size_t size)\n{\n    void *mem = PyMem_Malloc((Py_ssize_t) size);\n    if (mem) return mem;\n    fz_throw(gctx, FZ_ERROR_MEMORY, \"malloc of %zu bytes failed\", size);\n}\n\nstatic void *JM_Py_Realloc(void *opaque, void *old, size_t size)\n{\n    void *mem = PyMem_Realloc(old, (Py_ssize_t) size);\n    if (mem) return mem;\n    fz_throw(gctx, FZ_ERROR_MEMORY, \"realloc of %zu bytes failed\", size);\n}\n\nstatic void JM_PY_Free(void *opaque, void *ptr)\n{\n    PyMem_Free(ptr);\n}\n\nconst fz_alloc_context JM_Alloc_Context =\n{\n\tNULL,\n\tJM_Py_Malloc,\n\tJM_Py_Realloc,\n\tJM_PY_Free\n};\n#endif\n\nPyObject *JM_fitz_config()\n{\n#if defined(TOFU)\n#define have_TOFU JM_BOOL(0)\n#else\n#define have_TOFU JM_BOOL(1)\n#endif\n#if defined(TOFU_CJK)\n#define have_TOFU_CJK JM_BOOL(0)\n#else\n#define have_TOFU_CJK JM_BOOL(1)\n#endif\n#if defined(TOFU_CJK_EXT)\n#define have_TOFU_CJK_EXT JM_BOOL(0)\n#else\n#define have_TOFU_CJK_EXT JM_BOOL(1)\n#endif\n#if defined(TOFU_CJK_LANG)\n#define have_TOFU_CJK_LANG JM_BOOL(0)\n#else\n#define have_TOFU_CJK_LANG JM_BOOL(1)\n#endif\n#if defined(TOFU_EMOJI)\n#define have_TOFU_EMOJI JM_BOOL(0)\n#else\n#define have_TOFU_EMOJI JM_BOOL(1)\n#endif\n#if defined(TOFU_HISTORIC)\n#define have_TOFU_HISTORIC JM_BOOL(0)\n#else\n#define have_TOFU_HISTORIC JM_BOOL(1)\n#endif\n#if defined(TOFU_SYMBOL)\n#define have_TOFU_SYMBOL JM_BOOL(0)\n#else\n#define have_TOFU_SYMBOL JM_BOOL(1)\n#endif\n#if defined(TOFU_SIL)\n#define have_TOFU_SIL JM_BOOL(0)\n#else\n#define have_TOFU_SIL JM_BOOL(1)\n#endif\n#if defined(TOFU_BASE14)\n#define have_TOFU_BASE14 JM_BOOL(0)\n#else\n#define have_TOFU_BASE14 JM_BOOL(1)\n#endif\n    PyObject *dict = PyDict_New();\n    DICT_SETITEMSTR_DROP(dict, \"plotter-g\", JM_BOOL(FZ_PLOTTERS_G));\n    DICT_SETITEMSTR_DROP(dict, \"plotter-rgb\", JM_BOOL(FZ_PLOTTERS_RGB));\n    DICT_SETITEMSTR_DROP(dict, \"plotter-cmyk\", JM_BOOL(FZ_PLOTTERS_CMYK));\n    DICT_SETITEMSTR_DROP(dict, \"plotter-n\", JM_BOOL(FZ_PLOTTERS_N));\n    DICT_SETITEMSTR_DROP(dict, \"pdf\", JM_BOOL(FZ_ENABLE_PDF));\n    DICT_SETITEMSTR_DROP(dict, \"xps\", JM_BOOL(FZ_ENABLE_XPS));\n    DICT_SETITEMSTR_DROP(dict, \"svg\", JM_BOOL(FZ_ENABLE_SVG));\n    DICT_SETITEMSTR_DROP(dict, \"cbz\", JM_BOOL(FZ_ENABLE_CBZ));\n    DICT_SETITEMSTR_DROP(dict, \"img\", JM_BOOL(FZ_ENABLE_IMG));\n    DICT_SETITEMSTR_DROP(dict, \"html\", JM_BOOL(FZ_ENABLE_HTML));\n    DICT_SETITEMSTR_DROP(dict, \"epub\", JM_BOOL(FZ_ENABLE_EPUB));\n    DICT_SETITEMSTR_DROP(dict, \"jpx\", JM_BOOL(FZ_ENABLE_JPX));\n    DICT_SETITEMSTR_DROP(dict, \"js\", JM_BOOL(FZ_ENABLE_JS));\n    DICT_SETITEMSTR_DROP(dict, \"tofu\", have_TOFU);\n    DICT_SETITEMSTR_DROP(dict, \"tofu-cjk\", have_TOFU_CJK);\n    DICT_SETITEMSTR_DROP(dict, \"tofu-cjk-ext\", have_TOFU_CJK_EXT);\n    DICT_SETITEMSTR_DROP(dict, \"tofu-cjk-lang\", have_TOFU_CJK_LANG);\n    DICT_SETITEMSTR_DROP(dict, \"tofu-emoji\", have_TOFU_EMOJI);\n    DICT_SETITEMSTR_DROP(dict, \"tofu-historic\", have_TOFU_HISTORIC);\n    DICT_SETITEMSTR_DROP(dict, \"tofu-symbol\", have_TOFU_SYMBOL);\n    DICT_SETITEMSTR_DROP(dict, \"tofu-sil\", have_TOFU_SIL);\n    DICT_SETITEMSTR_DROP(dict, \"icc\", JM_BOOL(FZ_ENABLE_ICC));\n    DICT_SETITEMSTR_DROP(dict, \"base14\", have_TOFU_BASE14);\n    DICT_SETITEMSTR_DROP(dict, \"py-memory\", JM_BOOL(JM_MEMORY));\n    return dict;\n}\n\n//----------------------------------------------------------------------------\n// Update a color float array with values from a Python sequence.\n// Any error condition is treated as a no-op.\n//----------------------------------------------------------------------------\nvoid JM_color_FromSequence(PyObject *color, int *n, float col[4])\n{\n    if (!color || color == Py_None) {\n        *n = -1;\n        return;\n    }\n    if (PyFloat_Check(color)) { // maybe just a single float\n        *n = 1;\n        float c = (float) PyFloat_AsDouble(color);\n        if (!INRANGE(c, 0, 1)) {\n            c = 1;\n        }\n        col[0] = c;\n        return;\n    }\n\n    if (!PySequence_Check(color)) {\n        *n = -1;\n        return;\n    }\n    int len = (int) PySequence_Size(color), rc;\n    if (len == 0) {\n        *n = 0;\n        return;\n    }\n    if (!INRANGE(len, 1, 4) || len == 2) {\n        *n = -1;\n        return;\n    }\n\n    double mcol[4] = {0,0,0,0}; // local color storage\n    Py_ssize_t i;\n    for (i = 0; i < len; i++) {\n        rc = JM_FLOAT_ITEM(color, i, &mcol[i]);\n        if (!INRANGE(mcol[i], 0, 1) || rc == 1) mcol[i] = 1;\n    }\n\n    *n = len;\n    for (i = 0; i < len; i++)\n        col[i] = (float) mcol[i];\n    return;\n}\n\n// return extension for fitz image type\nconst char *JM_image_extension(int type)\n{\n    switch (type) {\n        case(FZ_IMAGE_FAX): return \"fax\";\n        case(FZ_IMAGE_RAW): return \"raw\";\n        case(FZ_IMAGE_FLATE): return \"flate\";\n        case(FZ_IMAGE_LZW): return \"lzw\";\n        case(FZ_IMAGE_RLD): return \"rld\";\n        case(FZ_IMAGE_BMP): return \"bmp\";\n        case(FZ_IMAGE_GIF): return \"gif\";\n        case(FZ_IMAGE_JBIG2): return \"jb2\";\n        case(FZ_IMAGE_JPEG): return \"jpeg\";\n        case(FZ_IMAGE_JPX): return \"jpx\";\n        case(FZ_IMAGE_JXR): return \"jxr\";\n        case(FZ_IMAGE_PNG): return \"png\";\n        case(FZ_IMAGE_PNM): return \"pnm\";\n        case(FZ_IMAGE_TIFF): return \"tiff\";\n        // case(FZ_IMAGE_PSD): return \"psd\";\n        case(FZ_IMAGE_UNKNOWN): return \"n/a\";\n        default: return \"n/a\";\n    }\n}\n\n//----------------------------------------------------------------------------\n// Turn fz_buffer into a Python bytes object\n//----------------------------------------------------------------------------\nPyObject *JM_BinFromBuffer(fz_context *ctx, fz_buffer *buffer)\n{\n    if (!buffer) {\n        return PyBytes_FromString(\"\");\n    }\n    unsigned char *c = NULL;\n    size_t len = fz_buffer_storage(ctx, buffer, &c);\n    return PyBytes_FromStringAndSize((const char *) c, (Py_ssize_t) len);\n}\n\n//----------------------------------------------------------------------------\n// Turn fz_buffer into a Python bytearray object\n//----------------------------------------------------------------------------\nPyObject *JM_BArrayFromBuffer(fz_context *ctx, fz_buffer *buffer)\n{\n    if (!buffer) {\n        return PyByteArray_FromStringAndSize(\"\", 0);\n    }\n    unsigned char *c = NULL;\n    size_t len = fz_buffer_storage(ctx, buffer, &c);\n    return PyByteArray_FromStringAndSize((const char *) c, (Py_ssize_t) len);\n}\n\n\n//----------------------------------------------------------------------------\n// compress char* into a new buffer\n//----------------------------------------------------------------------------\nfz_buffer *JM_compress_buffer(fz_context *ctx, fz_buffer *inbuffer)\n{\n    fz_buffer *buf = NULL;\n    fz_try(ctx) {\n        size_t compressed_length = 0;\n        unsigned char *data = fz_new_deflated_data_from_buffer(ctx,\n                              &compressed_length, inbuffer, FZ_DEFLATE_BEST);\n        if (data == NULL || compressed_length == 0)\n            return NULL;\n        buf = fz_new_buffer_from_data(ctx, data, compressed_length);\n        fz_resize_buffer(ctx, buf, compressed_length);\n    }\n    fz_catch(ctx) {\n        fz_drop_buffer(ctx, buf);\n        fz_rethrow(ctx);\n    }\n    return buf;\n}\n\n//----------------------------------------------------------------------------\n// update a stream object\n// compress stream when beneficial\n//----------------------------------------------------------------------------\nvoid JM_update_stream(fz_context *ctx, pdf_document *doc, pdf_obj *obj, fz_buffer *buffer, int compress)\n{\n\n    fz_buffer *nres = NULL;\n    size_t len = fz_buffer_storage(ctx, buffer, NULL);\n    size_t nlen = len;\n\n    if (compress == 1 && len > 30) {  // ignore small stuff\n        nres = JM_compress_buffer(ctx, buffer);\n        nlen = fz_buffer_storage(ctx, nres, NULL);\n    }\n\n    if (nlen < len && nres && compress==1) {  // was it worth the effort?\n        pdf_dict_put(ctx, obj, PDF_NAME(Filter), PDF_NAME(FlateDecode));\n        pdf_update_stream(ctx, doc, obj, nres, 1);\n    } else {\n        pdf_update_stream(ctx, doc, obj, buffer, 0);\n    }\n    fz_drop_buffer(ctx, nres);\n}\n\n//-----------------------------------------------------------------------------\n// return hex characters for n characters in input 'in'\n//-----------------------------------------------------------------------------\nvoid hexlify(int n, unsigned char *in, unsigned char *out)\n{\n    const unsigned char hdigit[17] = \"0123456789abcedf\";\n    int i, i1, i2;\n    for (i = 0; i < n; i++) {\n        i1 = in[i]>>4;\n        i2 = in[i] - i1*16;\n        out[2*i] = hdigit[i1];\n        out[2*i + 1] = hdigit[i2];\n    }\n    out[2*n] = 0;\n}\n\n//----------------------------------------------------------------------------\n// Make fz_buffer from a PyBytes, PyByteArray, or io.BytesIO object\n//----------------------------------------------------------------------------\nfz_buffer *JM_BufferFromBytes(fz_context *ctx, PyObject *stream)\n{\n    char *c = NULL;\n    PyObject *mybytes = NULL;\n    size_t len = 0;\n    fz_buffer *res = NULL;\n    fz_var(res);\n    fz_try(ctx) {\n        if (PyBytes_Check(stream)) {\n            c = PyBytes_AS_STRING(stream);\n            len = (size_t) PyBytes_GET_SIZE(stream);\n        } else if (PyByteArray_Check(stream)) {\n            c = PyByteArray_AS_STRING(stream);\n            len = (size_t) PyByteArray_GET_SIZE(stream);\n        } else if (PyObject_HasAttrString(stream, \"getvalue\")) {\n            // we assume here that this delivers what we expect\n            mybytes = PyObject_CallMethod(stream, \"getvalue\", NULL);\n            c = PyBytes_AS_STRING(mybytes);\n            len = (size_t) PyBytes_GET_SIZE(mybytes);\n        }\n        // if none of the above, c is NULL and we return an empty buffer\n        if (c) {\n            res = fz_new_buffer_from_copied_data(ctx, (const unsigned char *) c, len);\n        } else {\n            res = fz_new_buffer(ctx, 1);\n            fz_append_byte(ctx, res, 10);\n        }\n        fz_terminate_buffer(ctx, res);\n    }\n    fz_always(ctx) {\n        Py_CLEAR(mybytes);\n        PyErr_Clear();\n    }\n    fz_catch(ctx) {\n        fz_drop_buffer(ctx, res);\n        fz_rethrow(ctx);\n    }\n    return res;\n}\n\n\n//----------------------------------------------------------------------------\n// Deep-copies a source page to the target.\n// Modified version of function of pdfmerge.c: we also copy annotations, but\n// we skip some subtypes. In addition we rotate output.\n//----------------------------------------------------------------------------\nstatic void\npage_merge(fz_context *ctx, pdf_document *doc_des, pdf_document *doc_src, int page_from, int page_to, int rotate, int links, int copy_annots, pdf_graft_map *graft_map)\n{\n    pdf_obj *page_ref = NULL;\n    pdf_obj *page_dict = NULL;\n    pdf_obj *obj = NULL, *ref = NULL;\n\n    // list of object types (per page) we want to copy\n    static pdf_obj * const known_page_objs[] = {\n        PDF_NAME(Contents),\n        PDF_NAME(Resources),\n        PDF_NAME(MediaBox),\n        PDF_NAME(CropBox),\n        PDF_NAME(BleedBox),\n        PDF_NAME(TrimBox),\n        PDF_NAME(ArtBox),\n        PDF_NAME(Rotate),\n        PDF_NAME(UserUnit)\n    };\n\n    int i, n;\n\n    fz_var(ref);\n    fz_var(page_dict);\n\n    fz_try(ctx) {\n        page_ref = pdf_lookup_page_obj(ctx, doc_src, page_from);\n\n        // make new page dict in dest doc\n        page_dict = pdf_new_dict(ctx, doc_des, 4);\n        pdf_dict_put(ctx, page_dict, PDF_NAME(Type), PDF_NAME(Page));\n\n        for (i = 0; i < (int) nelem(known_page_objs); i++) {\n            obj = pdf_dict_get_inheritable(ctx, page_ref, known_page_objs[i]);\n            if (obj != NULL) {\n                pdf_dict_put_drop(ctx, page_dict, known_page_objs[i], pdf_graft_mapped_object(ctx, graft_map, obj));\n            }\n        }\n\n        // Copy annotations, but skip Link, Popup, IRT, Widget types\n        // If selected, remove dict keys P (parent) and Popup\n        if (copy_annots) {\n            pdf_obj *old_annots = pdf_dict_get(ctx, page_ref, PDF_NAME(Annots));\n            n = pdf_array_len(ctx, old_annots);\n            if (n > 0) {\n                pdf_obj *new_annots = pdf_dict_put_array(ctx, page_dict, PDF_NAME(Annots), n);\n                for (i = 0; i < n; i++) {\n                    pdf_obj *o = pdf_array_get(ctx, old_annots, i);\n                    if (!pdf_is_dict(ctx, o)) continue;  // skip non-dict items\n                    if (pdf_dict_get(ctx, o, PDF_NAME(IRT))) continue;\n                    pdf_obj *subtype = pdf_dict_get(ctx, o, PDF_NAME(Subtype));\n                    if (pdf_name_eq(ctx, subtype, PDF_NAME(Link))) continue;\n                    if (pdf_name_eq(ctx, subtype, PDF_NAME(Popup))) continue;\n                    if (pdf_name_eq(ctx, subtype, PDF_NAME(Widget))) continue;\n                    pdf_dict_del(ctx, o, PDF_NAME(Popup));\n                    pdf_dict_del(ctx, o, PDF_NAME(P));\n                    pdf_obj *copy_o = pdf_graft_mapped_object(ctx, graft_map, o);\n                    pdf_obj *annot = pdf_new_indirect(ctx, doc_des,\n                                     pdf_to_num(ctx, copy_o), 0);\n                    pdf_array_push_drop(ctx, new_annots, annot);\n                    pdf_drop_obj(ctx, copy_o);\n                }\n            }\n        }\n        // rotate the page\n        if (rotate != -1) {\n            pdf_dict_put_int(ctx, page_dict, PDF_NAME(Rotate), (int64_t) rotate);\n        }\n        // Now add the page dictionary to dest PDF\n        ref = pdf_add_object(ctx, doc_des, page_dict);\n\n        // Insert new page at specified location\n        pdf_insert_page(ctx, doc_des, page_to, ref);\n\n    }\n    fz_always(ctx) {\n        pdf_drop_obj(ctx, page_dict);\n        pdf_drop_obj(ctx, ref);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\n//-----------------------------------------------------------------------------\n// Copy a range of pages (spage, epage) from a source PDF to a specified\n// location (apage) of the target PDF.\n// If spage > epage, the sequence of source pages is reversed.\n//-----------------------------------------------------------------------------\nvoid JM_merge_range(fz_context *ctx, pdf_document *doc_des, pdf_document *doc_src, int spage, int epage, int apage, int rotate, int links, int annots, int show_progress, pdf_graft_map *graft_map)\n{\n    int page, afterpage;\n    afterpage = apage;\n    int counter = 0;  // copied pages counter\n    int total = fz_absi(epage - spage) + 1;  // total pages to copy\n\n    fz_try(ctx) {\n        if (spage < epage) {\n            for (page = spage; page <= epage; page++, afterpage++) {\n                page_merge(ctx, doc_des, doc_src, page, afterpage, rotate, links, annots, graft_map);\n                counter++;\n                if (show_progress > 0 && counter % show_progress == 0) {\n                    PySys_WriteStdout(\"Inserted %i of %i pages.\\n\", counter, total);\n                }\n            }\n        } else {\n            for (page = spage; page >= epage; page--, afterpage++) {\n                page_merge(ctx, doc_des, doc_src, page, afterpage, rotate, links, annots, graft_map);\n                counter++;\n                if (show_progress > 0 && counter % show_progress == 0) {\n                    PySys_WriteStdout(\"Inserted %i of %i pages.\\n\", counter, total);\n                }\n            }\n        }\n    }\n\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\n//----------------------------------------------------------------------------\n// Return list of outline xref numbers. Recursive function. Arguments:\n// 'obj' first OL item\n// 'xrefs' empty Python list\n//----------------------------------------------------------------------------\nPyObject *JM_outline_xrefs(fz_context *ctx, pdf_obj *obj, PyObject *xrefs)\n{\n    pdf_obj *first, *parent, *thisobj;\n    if (!obj) return xrefs;\n    PyObject *newxref = NULL;\n    thisobj = obj;\n    while (thisobj) {\n        newxref = PyLong_FromLong((long) pdf_to_num(ctx, thisobj));\n        if (PySequence_Contains(xrefs, newxref) ||\n            pdf_dict_get(ctx, thisobj, PDF_NAME(Type))) {\n            // circular ref or top of chain: terminate\n            Py_DECREF(newxref);\n            break;\n        }\n        LIST_APPEND_DROP(xrefs, newxref);\n        first = pdf_dict_get(ctx, thisobj, PDF_NAME(First));  // try go down\n        if (pdf_is_dict(ctx, first)) xrefs = JM_outline_xrefs(ctx, first, xrefs);\n        thisobj = pdf_dict_get(ctx, thisobj, PDF_NAME(Next));  // try go next\n        parent = pdf_dict_get(ctx, thisobj, PDF_NAME(Parent));  // get parent\n        if (!pdf_is_dict(ctx, thisobj)) {\n            thisobj = parent;\n        }\n    }\n    return xrefs;\n}\n\n\n//-------------------------------------------------------------------\n// Return the contents of a font file, identified by xref\n//-------------------------------------------------------------------\nfz_buffer *JM_get_fontbuffer(fz_context *ctx, pdf_document *doc, int xref)\n{\n    if (xref < 1) return NULL;\n    pdf_obj *o, *obj = NULL, *desft, *stream = NULL;\n    o = pdf_load_object(ctx, doc, xref);\n    desft = pdf_dict_get(ctx, o, PDF_NAME(DescendantFonts));\n    if (desft) {\n        obj = pdf_resolve_indirect(ctx, pdf_array_get(ctx, desft, 0));\n        obj = pdf_dict_get(ctx, obj, PDF_NAME(FontDescriptor));\n    } else {\n        obj = pdf_dict_get(ctx, o, PDF_NAME(FontDescriptor));\n    }\n\n    if (!obj) {\n        pdf_drop_obj(ctx, o);\n        PySys_WriteStdout(\"invalid font - FontDescriptor missing\");\n        return NULL;\n    }\n    pdf_drop_obj(ctx, o);\n    o = obj;\n\n    obj = pdf_dict_get(ctx, o, PDF_NAME(FontFile));\n    if (obj) stream = obj;             // ext = \"pfa\"\n\n    obj = pdf_dict_get(ctx, o, PDF_NAME(FontFile2));\n    if (obj) stream = obj;             // ext = \"ttf\"\n\n    obj = pdf_dict_get(ctx, o, PDF_NAME(FontFile3));\n    if (obj) {\n        stream = obj;\n\n        obj = pdf_dict_get(ctx, obj, PDF_NAME(Subtype));\n        if (obj && !pdf_is_name(ctx, obj)) {\n            PySys_WriteStdout(\"invalid font descriptor subtype\");\n            return NULL;\n        }\n\n        if (pdf_name_eq(ctx, obj, PDF_NAME(Type1C)))\n            ; /*Prev code did: ext = \"cff\", but this has no effect. */\n        else if (pdf_name_eq(ctx, obj, PDF_NAME(CIDFontType0C)))\n            ; /*Prev code did: ext = \"cid\", but this has no effect. */\n        else if (pdf_name_eq(ctx, obj, PDF_NAME(OpenType)))\n            ; /*Prev code did: ext = \"otf\", but this has no effect. */\n        else\n            PySys_WriteStdout(\"warning: unhandled font type '%s'\", pdf_to_name(ctx, obj));\n    }\n\n    if (!stream) {\n        PySys_WriteStdout(\"warning: unhandled font type\");\n        return NULL;\n    }\n\n    return pdf_load_stream(ctx, stream);\n}\n\n//-----------------------------------------------------------------------------\n// Return the file extension of a font file, identified by xref\n//-----------------------------------------------------------------------------\nchar *JM_get_fontextension(fz_context *ctx, pdf_document *doc, int xref)\n{\n    if (xref < 1) return \"n/a\";\n    pdf_obj *o, *obj = NULL, *desft;\n    o = pdf_load_object(ctx, doc, xref);\n    desft = pdf_dict_get(ctx, o, PDF_NAME(DescendantFonts));\n    if (desft) {\n        obj = pdf_resolve_indirect(ctx, pdf_array_get(ctx, desft, 0));\n        obj = pdf_dict_get(ctx, obj, PDF_NAME(FontDescriptor));\n    } else {\n        obj = pdf_dict_get(ctx, o, PDF_NAME(FontDescriptor));\n    }\n\n    pdf_drop_obj(ctx, o);\n    if (!obj) return \"n/a\";  // this is a base-14 font\n\n    o = obj;  // we have the FontDescriptor\n\n    obj = pdf_dict_get(ctx, o, PDF_NAME(FontFile));\n    if (obj) return \"pfa\";\n\n    obj = pdf_dict_get(ctx, o, PDF_NAME(FontFile2));\n    if (obj) return \"ttf\";\n\n    obj = pdf_dict_get(ctx, o, PDF_NAME(FontFile3));\n    if (obj) {\n        obj = pdf_dict_get(ctx, obj, PDF_NAME(Subtype));\n        if (obj && !pdf_is_name(ctx, obj)) {\n            PySys_WriteStdout(\"invalid font descriptor subtype\");\n            return \"n/a\";\n        }\n        if (pdf_name_eq(ctx, obj, PDF_NAME(Type1C)))\n            return \"cff\";\n        else if (pdf_name_eq(ctx, obj, PDF_NAME(CIDFontType0C)))\n            return \"cid\";\n        else if (pdf_name_eq(ctx, obj, PDF_NAME(OpenType)))\n            return \"otf\";\n        else\n            PySys_WriteStdout(\"unhandled font type '%s'\", pdf_to_name(ctx, obj));\n    }\n\n    return \"n/a\";\n}\n\n\n//-----------------------------------------------------------------------------\n// create PDF object from given string (new in v1.14.0: MuPDF dropped it)\n//-----------------------------------------------------------------------------\npdf_obj *JM_pdf_obj_from_str(fz_context *ctx, pdf_document *doc, char *src)\n{\n    pdf_obj *result = NULL;\n    pdf_lexbuf lexbuf;\n    fz_stream *stream = fz_open_memory(ctx, (unsigned char *)src, strlen(src));\n\n    pdf_lexbuf_init(ctx, &lexbuf, PDF_LEXBUF_SMALL);\n\n    fz_try(ctx) {\n        result = pdf_parse_stm_obj(ctx, doc, stream, &lexbuf);\n    }\n\n    fz_always(ctx) {\n        pdf_lexbuf_fin(ctx, &lexbuf);\n        fz_drop_stream(ctx, stream);\n    }\n\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n\n    return result;\n\n}\n\n//----------------------------------------------------------------------------\n// return normalized /Rotate value:one of 0, 90, 180, 270\n//----------------------------------------------------------------------------\nint JM_norm_rotation(int rotate)\n{\n    while (rotate < 0) rotate += 360;\n    while (rotate >= 360) rotate -= 360;\n    if (rotate % 90 != 0) return 0;\n    return rotate;\n}\n\n\n//----------------------------------------------------------------------------\n// return a PDF page's /Rotate value: one of (0, 90, 180, 270)\n//----------------------------------------------------------------------------\nint JM_page_rotation(fz_context *ctx, pdf_page *page)\n{\n    int rotate = 0;\n    fz_try(ctx)\n    {\n        rotate = pdf_to_int(ctx,\n                pdf_dict_get_inheritable(ctx, page->obj, PDF_NAME(Rotate)));\n        rotate = JM_norm_rotation(rotate);\n    }\n    fz_catch(ctx) return 0;\n    return rotate;\n}\n\n\n//----------------------------------------------------------------------------\n// return a PDF page's MediaBox\n//----------------------------------------------------------------------------\nfz_rect JM_mediabox(fz_context *ctx, pdf_obj *page_obj)\n{\n    fz_rect mediabox, page_mediabox;\n\n    mediabox = pdf_to_rect(ctx, pdf_dict_get_inheritable(ctx, page_obj,\n        PDF_NAME(MediaBox)));\n    if (fz_is_empty_rect(mediabox) || fz_is_infinite_rect(mediabox))\n    {\n        mediabox.x0 = 0;\n        mediabox.y0 = 0;\n        mediabox.x1 = 612;\n        mediabox.y1 = 792;\n    }\n\n    page_mediabox.x0 = fz_min(mediabox.x0, mediabox.x1);\n    page_mediabox.y0 = fz_min(mediabox.y0, mediabox.y1);\n    page_mediabox.x1 = fz_max(mediabox.x0, mediabox.x1);\n    page_mediabox.y1 = fz_max(mediabox.y0, mediabox.y1);\n\n    if (page_mediabox.x1 - page_mediabox.x0 < 1 ||\n        page_mediabox.y1 - page_mediabox.y0 < 1)\n        page_mediabox = fz_unit_rect;\n\n    return page_mediabox;\n}\n\n\n//----------------------------------------------------------------------------\n// return a PDF page's CropBox\n//----------------------------------------------------------------------------\nfz_rect JM_cropbox(fz_context *ctx, pdf_obj *page_obj)\n{\n    fz_rect mediabox = JM_mediabox(ctx, page_obj);\n    fz_rect cropbox = pdf_to_rect(ctx,\n                pdf_dict_get_inheritable(ctx, page_obj, PDF_NAME(CropBox)));\n    if (fz_is_infinite_rect(cropbox) || fz_is_empty_rect(cropbox))\n        cropbox = mediabox;\n    float y0 = mediabox.y1 - cropbox.y1;\n    float y1 = mediabox.y1 - cropbox.y0;\n    cropbox.y0 = y0;\n    cropbox.y1 = y1;\n    return cropbox;\n}\n\n\n//----------------------------------------------------------------------------\n// calculate width and height of the UNROTATED page\n//----------------------------------------------------------------------------\nfz_point JM_cropbox_size(fz_context *ctx, pdf_obj *page_obj)\n{\n    fz_point size;\n    fz_try(ctx)\n    {\n        fz_rect rect = JM_cropbox(ctx, page_obj);\n        float w = (rect.x0 < rect.x1 ? rect.x1 - rect.x0 : rect.x0 - rect.x1);\n        float h = (rect.y0 < rect.y1 ? rect.y1 - rect.y0 : rect.y0 - rect.y1);\n        size = fz_make_point(w, h);\n    }\n    fz_catch(ctx) fz_rethrow(ctx);\n    return size;\n}\n\n\n//----------------------------------------------------------------------------\n// calculate page rotation matrices\n//----------------------------------------------------------------------------\nfz_matrix JM_rotate_page_matrix(fz_context *ctx, pdf_page *page)\n{\n    if (!page) return fz_identity;  // no valid pdf page given\n    int rotation = JM_page_rotation(ctx, page);\n    if (rotation == 0) return fz_identity;  // no rotation\n    fz_matrix m;\n    fz_point cb_size = JM_cropbox_size(ctx, page->obj);\n    float w = cb_size.x;\n    float h = cb_size.y;\n    if (rotation == 90)\n        m = fz_make_matrix(0, 1, -1, 0, h, 0);\n    else if (rotation == 180)\n        m = fz_make_matrix(-1, 0, 0, -1, w, h);\n    else\n        m = fz_make_matrix(0, -1, 1, 0, 0, w);\n    return m;\n}\n\n\nfz_matrix JM_derotate_page_matrix(fz_context *ctx, pdf_page *page)\n{  // just the inverse of rotation\n    return fz_invert_matrix(JM_rotate_page_matrix(ctx, page));\n}\n\n\n//-----------------------------------------------------------------------------\n// Insert a font in a PDF\n//-----------------------------------------------------------------------------\nPyObject *\nJM_insert_font(fz_context *ctx, pdf_document *pdf, char *bfname, char *fontfile,\n    PyObject *fontbuffer, int set_simple, int idx, int wmode, int serif,\n    int encoding, int ordering)\n{\n    pdf_obj *font_obj = NULL;\n    fz_font *font = NULL;\n    fz_buffer *res = NULL;\n    const unsigned char *data = NULL;\n    int size, ixref = 0, index = 0, simple = 0;\n    PyObject *value=NULL, *name=NULL, *subt=NULL, *exto = NULL;\n\n    fz_var(exto);\n    fz_var(name);\n    fz_var(subt);\n    fz_var(res);\n    fz_var(font);\n    fz_var(font_obj);\n    fz_try(ctx) {\n        ENSURE_OPERATION(ctx, pdf);\n        //-------------------------------------------------------------\n        // check for CJK font\n        //-------------------------------------------------------------\n        if (ordering > -1) {\n            data = fz_lookup_cjk_font(ctx, ordering, &size, &index);\n        }\n        if (data) {\n            font = fz_new_font_from_memory(ctx, NULL, data, size, index, 0);\n            font_obj = pdf_add_cjk_font(ctx, pdf, font, ordering, wmode, serif);\n            exto = JM_UnicodeFromStr(\"n/a\");\n            simple = 0;\n            goto weiter;\n        }\n\n        //-------------------------------------------------------------\n        // check for PDF Base-14 font\n        //-------------------------------------------------------------\n        if (bfname) {\n            data = fz_lookup_base14_font(ctx, bfname, &size);\n        }\n        if (data) {\n            font = fz_new_font_from_memory(ctx, bfname, data, size, 0, 0);\n            font_obj = pdf_add_simple_font(ctx, pdf, font, encoding);\n            exto = JM_UnicodeFromStr(\"n/a\");\n            simple = 1;\n            goto weiter;\n        }\n\n        if (fontfile) {\n            font = fz_new_font_from_file(ctx, NULL, fontfile, idx, 0);\n        } else {\n            res = JM_BufferFromBytes(ctx, fontbuffer);\n            if (!res) {\n                RAISEPY(ctx, MSG_FILE_OR_BUFFER, PyExc_ValueError);\n            }\n            font = fz_new_font_from_buffer(ctx, NULL, res, idx, 0);\n        }\n\n        if (!set_simple) {\n            font_obj = pdf_add_cid_font(ctx, pdf, font);\n            simple = 0;\n        } else {\n            font_obj = pdf_add_simple_font(ctx, pdf, font, encoding);\n            simple = 2;\n        }\n\n        weiter: ;\n        ixref = pdf_to_num(ctx, font_obj);\n        name = JM_EscapeStrFromStr(pdf_to_name(ctx,\n                    pdf_dict_get(ctx, font_obj, PDF_NAME(BaseFont))));\n\n        subt = JM_UnicodeFromStr(pdf_to_name(ctx,\n                    pdf_dict_get(ctx, font_obj, PDF_NAME(Subtype))));\n\n        if (!exto)\n            exto = JM_UnicodeFromStr(JM_get_fontextension(ctx, pdf, ixref));\n\n        float asc = fz_font_ascender(ctx, font);\n        float dsc = fz_font_descender(ctx, font);\n        value = Py_BuildValue(\"[i,{s:O,s:O,s:O,s:O,s:i,s:f,s:f}]\",\n                                ixref,\n                                \"name\", name,        // base font name\n                                \"type\", subt,        // subtype\n                                \"ext\", exto,         // file extension\n                                \"simple\", JM_BOOL(simple), // simple font?\n                                \"ordering\", ordering, // CJK font?\n                                \"ascender\", asc,\n                                \"descender\", dsc\n                                );\n    }\n    fz_always(ctx) {\n        Py_CLEAR(exto);\n        Py_CLEAR(name);\n        Py_CLEAR(subt);\n        fz_drop_buffer(ctx, res);\n        fz_drop_font(ctx, font);\n        pdf_drop_obj(ctx, font_obj);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return value;\n}\n\n\n//-----------------------------------------------------------------------------\n// compute image insertion matrix\n//-----------------------------------------------------------------------------\nfz_matrix\ncalc_image_matrix(int width, int height, PyObject *tr, int rotate, int keep)\n{\n    float large, small, fw, fh, trw, trh, f, w, h;\n    fz_rect trect = JM_rect_from_py(tr);\n    fz_matrix rot = fz_rotate((float) rotate);\n    trw = trect.x1 - trect.x0;\n    trh = trect.y1 - trect.y0;\n    w = trw;\n    h = trh;\n    if (keep) {\n        large = (float) Py_MAX(width, height);\n        fw = (float) width / large;\n        fh = (float) height / large;\n    } else {\n        fw = fh = 1;\n    }\n    small = Py_MIN(fw, fh);\n    if (rotate != 0 && rotate != 180) {\n        f = fw;\n        fw = fh;\n        fh = f;\n    }\n    if (fw < 1) {\n        if ((trw / fw) > (trh / fh)) {\n            w = trh * small;\n            h = trh;\n        } else {\n            w = trw;\n            h = trw / small;\n        }\n    } else if (fw != fh) {\n        if ((trw / fw) > (trh / fh)) {\n            w = trh / small;\n            h = trh;\n        } else {\n            w = trw;\n            h = trw * small;\n        }\n    } else {\n        w = trw;\n        h = trh;\n    }\n    fz_point tmp = fz_make_point((trect.x0 + trect.x1) / 2,\n                                 (trect.y0 + trect.y1) / 2);\n    fz_matrix mat = fz_make_matrix(1, 0, 0, 1, -0.5, -0.5);\n    mat = fz_concat(mat, rot);\n    mat = fz_concat(mat, fz_scale(w, h));\n    mat = fz_concat(mat, fz_translate(tmp.x, tmp.y));\n    return mat;\n}\n\n// --------------------------------------------------------\n// Callback function for the Story class\n// --------------------------------------------------------\nstatic PyObject *make_story_elpos = NULL; // Py function returning object\nvoid Story_Callback(fz_context *ctx, void *opaque, fz_story_element_position *pos)\n{\n#define SETATTR(a, v) PyObject_SetAttrString(arg, a, v);Py_DECREF(v)\n    // ------------------------------------------------------------------------\n    // 'opaque' is a tuple (userfunc, userdict), where 'userfunc' is a function\n    // in the user's script and 'userdict' is a dictionary containing any\n    // additional parameters of the user\n    // userfunc will be called with the joined info of userdict and pos.\n    // ------------------------------------------------------------------------\n    PyObject *callarg = (PyObject *) opaque;\n    PyObject *userfunc = PyTuple_GET_ITEM(callarg, 0);\n    PyObject *userdict = PyTuple_GET_ITEM(callarg, 1);\n\n    PyObject *this_module = PyImport_AddModule(\"fitz\");  // get our module\n    if (!make_story_elpos) {  // locate ElementPosition maker once\n        make_story_elpos = Py_BuildValue(\"s\", \"make_story_elpos\");\n    }\n    // get access to ElementPosition() object\n    PyObject *arg = PyObject_CallMethodObjArgs(this_module, make_story_elpos, NULL);\n    Py_INCREF(arg);\n    SETATTR(\"depth\", Py_BuildValue(\"i\", pos->depth));\n    SETATTR(\"heading\", Py_BuildValue(\"i\", pos->heading));\n    SETATTR(\"id\", Py_BuildValue(\"s\", pos->id));\n    SETATTR(\"rect\", JM_py_from_rect(pos->rect));\n    SETATTR(\"text\", Py_BuildValue(\"s\", pos->text));\n    SETATTR(\"open_close\", Py_BuildValue(\"i\", pos->open_close));\n    SETATTR(\"rect_num\", Py_BuildValue(\"i\", pos->rectangle_num));\n    SETATTR(\"href\", Py_BuildValue(\"s\", pos->href));\n\n    // iterate over userdict items and set their attributes\n    PyObject *pkey = NULL;\n    PyObject *pval = NULL;\n    Py_ssize_t ppos = 0;\n    while (PyDict_Next(userdict, &ppos, &pkey, &pval)) {\n            PyObject_SetAttr(arg, pkey, pval);\n    }\n    PyObject_CallFunctionObjArgs(userfunc, arg, NULL);\n#undef SETATTR\n}\n\n// -----------------------------------------------------------\n// Return last archive if it is a tree and mount points match\n// -----------------------------------------------------------\nfz_archive *JM_last_tree(fz_context *ctx, fz_archive *arch, const char *mount)\n{\n    typedef struct\n    {\n        fz_archive *arch;\n        char *dir;\n    } multi_archive_entry;\n\n    typedef struct\n    {\n        fz_archive super;\n        int len;\n        int max;\n        multi_archive_entry *sub;\n    } fz_multi_archive;\n\n    if (!arch) {\n        return NULL;\n    }\n\n    fz_multi_archive *multi = (fz_multi_archive *) arch;\n    if (multi->len == 0) {  // archive is empty\n        return NULL;\n    }\n    int i = multi->len - 1;  // read last sub archive\n    multi_archive_entry *e = &multi->sub[i];\n    fz_archive *arch_ = e->arch;\n    const char *mount_ = e->dir;\n    const char *fmt = fz_archive_format(ctx, arch_);\n    if (strcmp(fmt, \"tree\") != 0) {  // not a tree archive\n        return NULL;\n    }\n    if ((mount_ && mount && strcmp(mount, mount_) == 0) || (!mount && !mount_)) {  // last sub archive is eligible!\n        return arch_;\n    }\n    return NULL;\n}\n\nfz_archive *JM_archive_from_py(fz_context *ctx, fz_archive *arch, PyObject *path, const char *mount, int *drop_sub)\n{\n    fz_stream *stream = NULL;\n    fz_buffer *buff = NULL;\n    *drop_sub = 1;\n    fz_archive *sub = NULL;\n    const char *my_mount = mount;\n    fz_try(ctx) {\n        // tree archive: tuple of memory items\n        // check if we can add to last sub-archive\n        sub = JM_last_tree(ctx, arch, my_mount);\n        if (!sub) {\n            sub = fz_new_tree_archive(ctx, NULL);\n        } else {\n            *drop_sub = 0;  // never drop last sub-archive\n        }\n\n        // a single tree item\n        if (PyBytes_Check(path) || PyByteArray_Check(path) || PyObject_HasAttrString(path, \"getvalue\")) {\n            buff = JM_BufferFromBytes(ctx, path);\n            fz_tree_archive_add_buffer(ctx, sub, mount, buff);\n            goto finished;\n        }\n\n        // a tuple of tree items\n        Py_ssize_t i, n = PyTuple_Size(path);\n        for (i = 0; i < n; i++) {\n            PyObject *item = PyTuple_GET_ITEM(path, i);\n            PyObject *i0 = PySequence_GetItem(item, 0);  // data\n            PyObject *i1 = PySequence_GetItem(item, 1);  // name\n            buff = JM_BufferFromBytes(ctx, i0);\n            fz_tree_archive_add_buffer(ctx, sub, PyUnicode_AsUTF8(i1), buff);\n            fz_drop_buffer(ctx, buff);\n            Py_DECREF(i0);\n            Py_DECREF(i1);\n        }\n        buff = NULL;\n        goto finished;\n\n        finished:;\n    }\n\n    fz_always(ctx) {\n        fz_drop_buffer(ctx, buff);\n        fz_drop_stream(ctx, stream);\n    }\n\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n\n    return sub;\n}\n\n\nint JM_rects_overlap(const fz_rect a, const fz_rect b)\n{\n    if (0\n            || a.x0 >= b.x1\n            || a.y0 >= b.y1\n            || a.x1 <= b.x0\n            || a.y1 <= b.y0\n            )\n        return 0;\n    return 1;\n}\n\n//-----------------------------------------------------------------------------\n// dummy structure for various tools and utilities\n//-----------------------------------------------------------------------------\nstruct Tools {int index;};\n\ntypedef struct fz_item fz_item;\n\nstruct fz_item\n{\n\tvoid *key;\n\tfz_storable *val;\n\tsize_t size;\n\tfz_item *next;\n\tfz_item *prev;\n\tfz_store *store;\n\tconst fz_store_type *type;\n};\n\nstruct fz_store\n{\n\tint refs;\n\n\t/* Every item in the store is kept in a doubly linked list, ordered\n\t * by usage (so LRU entries are at the end). */\n\tfz_item *head;\n\tfz_item *tail;\n\n\t/* We have a hash table that allows to quickly find a subset of the\n\t * entries (those whose keys are indirect objects). */\n\tfz_hash_table *hash;\n\n\t/* We keep track of the size of the store, and keep it below max. */\n\tsize_t max;\n\tsize_t size;\n\n\tint defer_reap_count;\n\tint needs_reaping;\n};\n\n%}\n"
  },
  {
    "path": "src_classic/helper-pdfinfo.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//------------------------------------------------------------------------\n// Store ID in PDF trailer\n//------------------------------------------------------------------------\nvoid JM_ensure_identity(fz_context *ctx, pdf_document *pdf)\n{\n    unsigned char rnd[16];\n    pdf_obj *id;\n    id = pdf_dict_get(ctx, pdf_trailer(ctx, pdf), PDF_NAME(ID));\n    if (!id) {\n        fz_memrnd(ctx, rnd, nelem(rnd));\n        id = pdf_dict_put_array(ctx, pdf_trailer(ctx, pdf), PDF_NAME(ID), 2);\n        pdf_array_push_drop(ctx, id, pdf_new_string(ctx, (char *) rnd + 0, nelem(rnd)));\n        pdf_array_push_drop(ctx, id, pdf_new_string(ctx, (char *) rnd + 0, nelem(rnd)));\n    }\n}\n\n\n//------------------------------------------------------------------------\n// Ensure OCProperties, return /OCProperties key\n//------------------------------------------------------------------------\npdf_obj *\nJM_ensure_ocproperties(fz_context *ctx, pdf_document *pdf)\n{\n    pdf_obj *D, *ocp;\n    fz_try(ctx) {\n        ocp = pdf_dict_get(ctx, pdf_dict_get(ctx, pdf_trailer(ctx, pdf), PDF_NAME(Root)), PDF_NAME(OCProperties));\n        if (ocp) goto finished;\n        pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, pdf), PDF_NAME(Root));\n        ocp = pdf_dict_put_dict(ctx, root, PDF_NAME(OCProperties), 2);\n        pdf_dict_put_array(ctx, ocp, PDF_NAME(OCGs), 0);\n        D = pdf_dict_put_dict(ctx, ocp, PDF_NAME(D), 5);\n        pdf_dict_put_array(ctx, D, PDF_NAME(ON), 0);\n        pdf_dict_put_array(ctx, D, PDF_NAME(OFF), 0);\n        pdf_dict_put_array(ctx, D, PDF_NAME(Order), 0);\n        pdf_dict_put_array(ctx, D, PDF_NAME(RBGroups), 0);\n    finished:;\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return ocp;\n}\n\n\n//------------------------------------------------------------------------\n// Add OC configuration to the PDF catalog\n//------------------------------------------------------------------------\nvoid\nJM_add_layer_config(fz_context *ctx, pdf_document *pdf, char *name, char *creator, PyObject *ON)\n{\n    pdf_obj *D, *ocp, *configs;\n    fz_try(ctx) {\n        ocp = JM_ensure_ocproperties(ctx, pdf);\n        configs = pdf_dict_get(ctx, ocp, PDF_NAME(Configs));\n        if (!pdf_is_array(ctx, configs)) {\n            configs = pdf_dict_put_array(ctx,ocp, PDF_NAME(Configs), 1);\n        }\n        D = pdf_new_dict(ctx, pdf, 5);\n        pdf_dict_put_text_string(ctx, D, PDF_NAME(Name), name);\n        if (creator) {\n            pdf_dict_put_text_string(ctx, D, PDF_NAME(Creator), creator);\n        }\n        pdf_dict_put(ctx, D, PDF_NAME(BaseState), PDF_NAME(OFF));\n        pdf_obj *onarray = pdf_dict_put_array(ctx, D, PDF_NAME(ON), 5);\n        if (!EXISTS(ON) || !PySequence_Check(ON) || !PySequence_Size(ON)) {\n            ;\n        } else {\n            pdf_obj *ocgs = pdf_dict_get(ctx, ocp, PDF_NAME(OCGs));\n            int i, n = PySequence_Size(ON);\n            for (i = 0; i < n; i++) {\n                int xref = 0;\n                if (JM_INT_ITEM(ON, (Py_ssize_t) i, &xref) == 1) continue;\n                pdf_obj *ind = pdf_new_indirect(ctx, pdf, xref, 0);\n                if (pdf_array_contains(ctx, ocgs, ind)) {\n                    pdf_array_push_drop(ctx, onarray, ind);\n                } else {\n                    pdf_drop_obj(ctx, ind);\n                }\n            }\n        }\n        pdf_array_push_drop(ctx, configs, D);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\n\n//------------------------------------------------------------------------\n// Get OCG arrays from OC configuration\n// Returns dict\n// {\"basestate\":name, \"on\":list, \"off\":list, \"rbg\":list, \"locked\":list}\n//------------------------------------------------------------------------\nstatic PyObject *\nJM_get_ocg_arrays_imp(fz_context *ctx, pdf_obj *arr)\n{\n    int i, n;\n    PyObject *list = PyList_New(0), *item = NULL;\n    pdf_obj *obj = NULL;\n    if (pdf_is_array(ctx, arr)) {\n        n = pdf_array_len(ctx, arr);\n        for (i = 0; i < n; i++) {\n            obj = pdf_array_get(ctx, arr, i);\n            item = Py_BuildValue(\"i\", pdf_to_num(ctx, obj));\n            if (!PySequence_Contains(list, item)) {\n                LIST_APPEND_DROP(list, item);\n            } else {\n                Py_DECREF(item);\n            }\n        }\n    }\n    return list;\n}\n\nPyObject *\nJM_get_ocg_arrays(fz_context *ctx, pdf_obj *conf)\n{\n    PyObject *rc = PyDict_New(), *list = NULL, *list1 = NULL;\n    int i, n;\n    pdf_obj *arr = NULL, *obj = NULL;\n    fz_try(ctx) {\n        arr = pdf_dict_get(ctx, conf, PDF_NAME(ON));\n        list = JM_get_ocg_arrays_imp(ctx, arr);\n        if (PySequence_Size(list)) {\n            PyDict_SetItemString(rc, \"on\", list);\n        }\n        Py_DECREF(list);\n        arr = pdf_dict_get(ctx, conf, PDF_NAME(OFF));\n        list = JM_get_ocg_arrays_imp(ctx, arr);\n        if (PySequence_Size(list)) {\n            PyDict_SetItemString(rc, \"off\", list);\n        }\n        Py_DECREF(list);\n        arr = pdf_dict_get(ctx, conf, PDF_NAME(Locked));\n        list = JM_get_ocg_arrays_imp(ctx, arr);\n        if (PySequence_Size(list)) {\n            PyDict_SetItemString(rc, \"locked\", list);\n        }\n        Py_DECREF(list);\n        list = PyList_New(0);\n        arr = pdf_dict_get(ctx, conf, PDF_NAME(RBGroups));\n        if (pdf_is_array(ctx, arr)) {\n            n = pdf_array_len(ctx, arr);\n            for (i = 0; i < n; i++) {\n                obj = pdf_array_get(ctx, arr, i);\n                list1 = JM_get_ocg_arrays_imp(ctx, obj);\n                LIST_APPEND_DROP(list, list1);\n            }\n        }\n        if (PySequence_Size(list)) {\n            PyDict_SetItemString(rc, \"rbgroups\", list);\n        }\n        Py_DECREF(list);\n        obj = pdf_dict_get(ctx, conf, PDF_NAME(BaseState));\n\n        if (obj) {\n            PyObject *state = NULL;\n            state = Py_BuildValue(\"s\", pdf_to_name(ctx, obj));\n            PyDict_SetItemString(rc, \"basestate\", state);\n            Py_DECREF(state);\n        }\n    }\n    fz_always(ctx) {\n    }\n    fz_catch(ctx) {\n        Py_CLEAR(rc);\n        PyErr_Clear();\n        fz_rethrow(ctx);\n    }\n    return rc;\n}\n\n\n//------------------------------------------------------------------------\n// Set OCG arrays from dict of Python lists\n// Works with dict like {\"basestate\":name, \"on\":list, \"off\":list, \"rbg\":list}\n//------------------------------------------------------------------------\nstatic void\nJM_set_ocg_arrays_imp(fz_context *ctx, pdf_obj *arr, PyObject *list)\n{\n    int i, n = PySequence_Size(list);\n    pdf_obj *obj = NULL;\n    pdf_document *pdf = pdf_get_bound_document(ctx, arr);\n    for (i = 0; i < n; i++) {\n        int xref = 0;\n        if (JM_INT_ITEM(list, i, &xref) == 1) continue;\n        obj = pdf_new_indirect(ctx, pdf, xref, 0);\n        pdf_array_push_drop(ctx, arr, obj);\n    }\n    return;\n}\n\nstatic void\nJM_set_ocg_arrays(fz_context *ctx, pdf_obj *conf, const char *basestate,\n                  PyObject *on, PyObject *off, PyObject *rbgroups, PyObject *locked)\n{\n    int i, n;\n    pdf_obj *arr = NULL, *obj = NULL;\n    fz_try(ctx) {\n        if (basestate) {\n            pdf_dict_put_name(ctx, conf, PDF_NAME(BaseState), basestate);\n        }\n\n        if (on != Py_None) {\n            pdf_dict_del(ctx, conf, PDF_NAME(ON));\n            if (PySequence_Size(on)) {\n                arr = pdf_dict_put_array(ctx, conf, PDF_NAME(ON), 1);\n                JM_set_ocg_arrays_imp(ctx, arr, on);\n            }\n        }\n\n        if (off != Py_None) {\n            pdf_dict_del(ctx, conf, PDF_NAME(OFF));\n            if (PySequence_Size(off)) {\n                arr = pdf_dict_put_array(ctx, conf, PDF_NAME(OFF), 1);\n                JM_set_ocg_arrays_imp(ctx, arr, off);\n            }\n        }\n\n        if (locked != Py_None) {\n            pdf_dict_del(ctx, conf, PDF_NAME(Locked));\n            if (PySequence_Size(locked)) {\n                arr = pdf_dict_put_array(ctx, conf, PDF_NAME(Locked), 1);\n                JM_set_ocg_arrays_imp(ctx, arr, locked);\n            }\n        }\n\n        if (rbgroups != Py_None) {\n            pdf_dict_del(ctx, conf, PDF_NAME(RBGroups));\n            if (PySequence_Size(rbgroups)) {\n                arr = pdf_dict_put_array(ctx, conf, PDF_NAME(RBGroups), 1);\n                n = PySequence_Size(rbgroups);\n                for (i = 0; i < n; i++) {\n                    PyObject *item0 = PySequence_ITEM(rbgroups, i);\n                    obj = pdf_array_push_array(ctx, arr, 1);\n                    JM_set_ocg_arrays_imp(ctx, obj, item0);\n                    Py_DECREF(item0);\n                }\n            }\n        }\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return;\n}\n\n\n//------------------------------------------------------------------------\n// Return the items of Resources/Properties (used for Marked Content)\n// Argument may be e.g. a page object or a Form XObject\n//------------------------------------------------------------------------\nPyObject *\nJM_get_resource_properties(fz_context *ctx, pdf_obj *ref)\n{\n    PyObject *rc = NULL;\n    fz_try(ctx) {\n        pdf_obj *properties = pdf_dict_getl(ctx, ref,\n                         PDF_NAME(Resources),\n                         PDF_NAME(Properties), NULL);\n        if (!properties) {\n            rc = PyTuple_New(0);\n        } else {\n            int i, n = pdf_dict_len(ctx, properties);\n            if (n < 1) {\n                rc = PyTuple_New(0);\n                goto finished;\n            }\n            rc = PyTuple_New(n);\n            for (i = 0; i < n; i++) {\n                pdf_obj *key = pdf_dict_get_key(ctx, properties, i);\n                pdf_obj *val = pdf_dict_get_val(ctx, properties, i);\n                const char *c = pdf_to_name(ctx, key);\n                int xref = pdf_to_num(ctx, val);\n                PyTuple_SET_ITEM(rc, i, Py_BuildValue(\"si\", c, xref));\n            }\n        }\n        finished:;\n    }\n    fz_catch(ctx) {\n        Py_CLEAR(rc);\n        fz_rethrow(ctx);\n    }\n    return rc;\n}\n\n\n//------------------------------------------------------------------------\n// Insert an item into Resources/Properties (used for Marked Content)\n// Arguments:\n// (1) e.g. page object, Form XObject\n// (2) marked content name\n// (3) xref of the referenced object (insert as indirect reference)\n//------------------------------------------------------------------------\nvoid\nJM_set_resource_property(fz_context *ctx, pdf_obj *ref, const char *name, int xref)\n{\n    pdf_obj *ind = NULL;\n    pdf_obj *properties = NULL;\n    pdf_document *pdf = pdf_get_bound_document(ctx, ref);\n    pdf_obj *name2 = NULL;\n    fz_var(ind);\n    fz_var(name2);\n    fz_try(ctx) {\n        ind = pdf_new_indirect(ctx, pdf, xref, 0);\n        if (!ind) {\n            RAISEPY(ctx, MSG_BAD_XREF, PyExc_ValueError);\n        }\n        pdf_obj *resources = pdf_dict_get(ctx, ref, PDF_NAME(Resources));\n        if (!resources) {\n            resources = pdf_dict_put_dict(ctx, ref, PDF_NAME(Resources), 1);\n        }\n        properties = pdf_dict_get(ctx, resources, PDF_NAME(Properties));\n        if (!properties) {\n            properties = pdf_dict_put_dict(ctx, resources, PDF_NAME(Properties), 1);\n        }\n        name2 = pdf_new_name(ctx, name);\n        pdf_dict_put(ctx, properties, name2, ind);\n    }\n    fz_always(ctx) {\n        pdf_drop_obj(ctx, ind);\n        pdf_drop_obj(ctx, name2);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return;\n}\n\n\n//------------------------------------------------------------------------\n// Add OC object reference to a dictionary\n//------------------------------------------------------------------------\nvoid\nJM_add_oc_object(fz_context *ctx, pdf_document *pdf, pdf_obj *ref, int xref)\n{\n    pdf_obj *indobj = NULL;\n    fz_try(ctx) {\n        indobj = pdf_new_indirect(ctx, pdf, xref, 0);\n        if (!pdf_is_dict(ctx, indobj)) {\n            RAISEPY(ctx, MSG_BAD_OC_REF, PyExc_ValueError);\n        }\n        pdf_obj *type = pdf_dict_get(ctx, indobj, PDF_NAME(Type));\n        if (pdf_objcmp(ctx, type, PDF_NAME(OCG)) == 0 ||\n            pdf_objcmp(ctx, type, PDF_NAME(OCMD)) == 0) {\n            pdf_dict_put(ctx, ref, PDF_NAME(OC), indobj);\n        } else {\n            RAISEPY(ctx, MSG_BAD_OC_REF, PyExc_ValueError);\n        }\n    }\n    fz_always(ctx) {\n        pdf_drop_obj(ctx, indobj);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n\n\n//-------------------------------------------------------------------------\n// Store info of a font in Python list\n//-------------------------------------------------------------------------\nint JM_gather_fonts(fz_context *ctx, pdf_document *pdf, pdf_obj *dict,\n                    PyObject *fontlist, int stream_xref)\n{\n    int i, n, rc = 1;\n    n = pdf_dict_len(ctx, dict);\n    for (i = 0; i < n; i++) {\n        pdf_obj *fontdict = NULL;\n        pdf_obj *subtype = NULL;\n        pdf_obj *basefont = NULL;\n        pdf_obj *name = NULL;\n        pdf_obj *refname = NULL;\n        pdf_obj *encoding = NULL;\n\n        refname = pdf_dict_get_key(ctx, dict, i);\n        fontdict = pdf_dict_get_val(ctx, dict, i);\n        if (!pdf_is_dict(ctx, fontdict)) {\n            fz_warn(ctx, \"'%s' is no font dict (%d 0 R)\",\n                    pdf_to_name(ctx, refname), pdf_to_num(ctx, fontdict));\n            continue;\n        }\n\n        subtype = pdf_dict_get(ctx, fontdict, PDF_NAME(Subtype));\n        basefont = pdf_dict_get(ctx, fontdict, PDF_NAME(BaseFont));\n        if (!basefont || pdf_is_null(ctx, basefont)) {\n            name = pdf_dict_get(ctx, fontdict, PDF_NAME(Name));\n        } else {\n            name = basefont;\n        }\n        encoding = pdf_dict_get(ctx, fontdict, PDF_NAME(Encoding));\n        if (pdf_is_dict(ctx, encoding)) {\n            encoding = pdf_dict_get(ctx, encoding, PDF_NAME(BaseEncoding));\n        }\n        int xref = pdf_to_num(ctx, fontdict);\n        char *ext = \"n/a\";\n        if (xref) {\n            ext = JM_get_fontextension(ctx, pdf, xref);\n        }\n        PyObject *entry = PyTuple_New(7);\n        PyTuple_SET_ITEM(entry, 0, Py_BuildValue(\"i\", xref));\n        PyTuple_SET_ITEM(entry, 1, Py_BuildValue(\"s\", ext));\n        PyTuple_SET_ITEM(entry, 2, Py_BuildValue(\"s\", pdf_to_name(ctx, subtype)));\n        PyTuple_SET_ITEM(entry, 3, JM_EscapeStrFromStr(pdf_to_name(ctx, name)));\n        PyTuple_SET_ITEM(entry, 4, Py_BuildValue(\"s\", pdf_to_name(ctx, refname)));\n        PyTuple_SET_ITEM(entry, 5, Py_BuildValue(\"s\", pdf_to_name(ctx, encoding)));\n        PyTuple_SET_ITEM(entry, 6, Py_BuildValue(\"i\", stream_xref));\n        LIST_APPEND_DROP(fontlist, entry);\n    }\n    return rc;\n}\n\n//-------------------------------------------------------------------------\n// Store info of an image in Python list\n//-------------------------------------------------------------------------\nint JM_gather_images(fz_context *ctx, pdf_document *doc, pdf_obj *dict,\n                     PyObject *imagelist, int stream_xref)\n{\n    int i, n, rc = 1;\n    n = pdf_dict_len(ctx, dict);\n    for (i = 0; i < n; i++) {\n        pdf_obj *imagedict, *smask;\n        pdf_obj *refname = NULL;\n        pdf_obj *type;\n        pdf_obj *width;\n        pdf_obj *height;\n        pdf_obj *bpc = NULL;\n        pdf_obj *filter = NULL;\n        pdf_obj *cs = NULL;\n        pdf_obj *altcs;\n\n        refname = pdf_dict_get_key(ctx, dict, i);\n        imagedict = pdf_dict_get_val(ctx, dict, i);\n        if (!pdf_is_dict(ctx, imagedict)) {\n            fz_warn(ctx, \"'%s' is no image dict (%d 0 R)\",\n                    pdf_to_name(ctx, refname), pdf_to_num(ctx, imagedict));\n            continue;\n        }\n\n        type = pdf_dict_get(ctx, imagedict, PDF_NAME(Subtype));\n        if (!pdf_name_eq(ctx, type, PDF_NAME(Image)))\n            continue;\n\n        int xref = pdf_to_num(ctx, imagedict);\n        int gen = 0;\n        smask = pdf_dict_geta(ctx, imagedict, PDF_NAME(SMask), PDF_NAME(Mask));\n        if (smask)\n            gen = pdf_to_num(ctx, smask);\n\n        filter = pdf_dict_geta(ctx, imagedict, PDF_NAME(Filter), PDF_NAME(F));\n        if (pdf_is_array(ctx, filter)) {\n            filter = pdf_array_get(ctx, filter, 0);\n        }\n\n        altcs = NULL;\n        cs = pdf_dict_geta(ctx, imagedict, PDF_NAME(ColorSpace), PDF_NAME(CS));\n        if (pdf_is_array(ctx, cs)) {\n            pdf_obj *cses = cs;\n            cs = pdf_array_get(ctx, cses, 0);\n            if (pdf_name_eq(ctx, cs, PDF_NAME(DeviceN)) ||\n                pdf_name_eq(ctx, cs, PDF_NAME(Separation))) {\n                altcs = pdf_array_get(ctx, cses, 2);\n                if (pdf_is_array(ctx, altcs)) {\n                    altcs = pdf_array_get(ctx, altcs, 0);\n                }\n            }\n        }\n\n        width = pdf_dict_geta(ctx, imagedict, PDF_NAME(Width), PDF_NAME(W));\n        height = pdf_dict_geta(ctx, imagedict, PDF_NAME(Height), PDF_NAME(H));\n        bpc = pdf_dict_geta(ctx, imagedict, PDF_NAME(BitsPerComponent), PDF_NAME(BPC));\n\n        PyObject *entry = PyTuple_New(10);\n        PyTuple_SET_ITEM(entry, 0, Py_BuildValue(\"i\", xref));\n        PyTuple_SET_ITEM(entry, 1, Py_BuildValue(\"i\", gen));\n        PyTuple_SET_ITEM(entry, 2, Py_BuildValue(\"i\", pdf_to_int(ctx, width)));\n        PyTuple_SET_ITEM(entry, 3, Py_BuildValue(\"i\", pdf_to_int(ctx, height)));\n        PyTuple_SET_ITEM(entry, 4, Py_BuildValue(\"i\", pdf_to_int(ctx, bpc)));\n        PyTuple_SET_ITEM(entry, 5, JM_EscapeStrFromStr(pdf_to_name(ctx, cs)));\n        PyTuple_SET_ITEM(entry, 6, JM_EscapeStrFromStr(pdf_to_name(ctx, altcs)));\n        PyTuple_SET_ITEM(entry, 7, JM_EscapeStrFromStr(pdf_to_name(ctx, refname)));\n        PyTuple_SET_ITEM(entry, 8, JM_EscapeStrFromStr(pdf_to_name(ctx, filter)));\n        PyTuple_SET_ITEM(entry, 9, Py_BuildValue(\"i\", stream_xref));\n        LIST_APPEND_DROP(imagelist, entry);\n    }\n    return rc;\n}\n\n//-------------------------------------------------------------------------\n// Store info of a /Form xobject in Python list\n//-------------------------------------------------------------------------\nint JM_gather_forms(fz_context *ctx, pdf_document *doc, pdf_obj *dict,\n                     PyObject *imagelist, int stream_xref)\n{\n    int i, rc = 1, n = pdf_dict_len(ctx, dict);\n    fz_rect bbox;\n    fz_matrix mat;\n    pdf_obj *o = NULL, *m = NULL;\n    for (i = 0; i < n; i++) {\n        pdf_obj *imagedict;\n        pdf_obj *refname = NULL;\n        pdf_obj *type;\n\n        refname = pdf_dict_get_key(ctx, dict, i);\n        imagedict = pdf_dict_get_val(ctx, dict, i);\n        if (!pdf_is_dict(ctx, imagedict)) {\n            fz_warn(ctx, \"'%s' is no form dict (%d 0 R)\",\n                    pdf_to_name(ctx, refname), pdf_to_num(ctx, imagedict));\n            continue;\n        }\n\n        type = pdf_dict_get(ctx, imagedict, PDF_NAME(Subtype));\n        if (!pdf_name_eq(ctx, type, PDF_NAME(Form)))\n            continue;\n\n        o = pdf_dict_get(ctx, imagedict, PDF_NAME(BBox));\n        m = pdf_dict_get(ctx, imagedict, PDF_NAME(Matrix));\n        if (m) {\n            mat = pdf_to_matrix(ctx, m);\n        } else {\n            mat = fz_identity;\n        }\n        if (o) {\n            bbox = fz_transform_rect(pdf_to_rect(ctx, o), mat);\n        } else {\n            bbox = fz_infinite_rect;\n        }\n        int xref = pdf_to_num(ctx, imagedict);\n\n        PyObject *entry = PyTuple_New(4);\n        PyTuple_SET_ITEM(entry, 0, Py_BuildValue(\"i\", xref));\n        PyTuple_SET_ITEM(entry, 1, Py_BuildValue(\"s\", pdf_to_name(ctx, refname)));\n        PyTuple_SET_ITEM(entry, 2, Py_BuildValue(\"i\", stream_xref));\n        PyTuple_SET_ITEM(entry, 3, JM_py_from_rect(bbox));\n        LIST_APPEND_DROP(imagelist, entry);\n    }\n    return rc;\n}\n\n//-------------------------------------------------------------------------\n// Step through /Resources, looking up image, xobject or font information\n//-------------------------------------------------------------------------\nvoid JM_scan_resources(fz_context *ctx, pdf_document *pdf, pdf_obj *rsrc,\n                 PyObject *liste, int what, int stream_xref,\n                 PyObject *tracer)\n{\n    pdf_obj *font, *xobj, *subrsrc;\n    int i, n, sxref;\n    if (pdf_mark_obj(ctx, rsrc)) {\n        fz_warn(ctx, \"Circular dependencies! Consider page cleaning.\");\n        return;  // Circular dependencies!\n    }\n\n    fz_try(ctx) {\n\n        xobj = pdf_dict_get(ctx, rsrc, PDF_NAME(XObject));\n\n        if (what == 1) {  // lookup fonts\n            font = pdf_dict_get(ctx, rsrc, PDF_NAME(Font));\n            JM_gather_fonts(ctx, pdf, font, liste, stream_xref);\n        } else if (what == 2) {  // look up images\n            JM_gather_images(ctx, pdf, xobj, liste, stream_xref);\n        } else if (what == 3) {  // look up form xobjects\n            JM_gather_forms(ctx, pdf, xobj, liste, stream_xref);\n        } else {  // should never happen\n            goto finished;\n        }\n\n        // check if we need to recurse into Form XObjects\n        n = pdf_dict_len(ctx, xobj);\n        for (i = 0; i < n; i++) {\n            pdf_obj *obj = pdf_dict_get_val(ctx, xobj, i);\n            if (pdf_is_stream(ctx, obj)) {\n                sxref = pdf_to_num(ctx, obj);\n            } else {\n                sxref = 0;\n            }\n            subrsrc = pdf_dict_get(ctx, obj, PDF_NAME(Resources));\n            if (subrsrc) {\n                PyObject *sxref_t = Py_BuildValue(\"i\", sxref);\n                if (PySequence_Contains(tracer, sxref_t) == 0) {\n                    LIST_APPEND_DROP(tracer, sxref_t);\n                    JM_scan_resources(ctx, pdf, subrsrc, liste, what, sxref, tracer);\n                } else {\n                    Py_DECREF(sxref_t);\n                    PyErr_Clear();\n                    fz_warn(ctx, \"Circular dependencies! Consider page cleaning.\");\n                    goto finished;\n                }\n            }\n        }\n        finished:;\n    }\n    fz_always(ctx) {\n        pdf_unmark_obj(ctx, rsrc);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n}\n%}\n"
  },
  {
    "path": "src_classic/helper-pixmap.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//-----------------------------------------------------------------------------\n// pixmap helper functions\n//-----------------------------------------------------------------------------\n\n//-----------------------------------------------------------------------------\n// Clear a pixmap rectangle - my version also supports non-alpha pixmaps\n//-----------------------------------------------------------------------------\nint\nJM_clear_pixmap_rect_with_value(fz_context *ctx, fz_pixmap *dest, int value, fz_irect b)\n{\n    unsigned char *destp;\n    int x, y, w, k, destspan;\n\n    b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));\n    w = b.x1 - b.x0;\n    y = b.y1 - b.y0;\n    if (w <= 0 || y <= 0)\n        return 0;\n\n    destspan = dest->stride;\n    destp = dest->samples + (unsigned int)(destspan * (b.y0 - dest->y) + dest->n * (b.x0 - dest->x));\n\n    /* CMYK needs special handling (and potentially any other subtractive colorspaces) */\n    if (fz_colorspace_n(ctx, dest->colorspace) == 4) {\n        value = 255 - value;\n        do {\n            unsigned char *s = destp;\n            for (x = 0; x < w; x++) {\n                *s++ = 0;\n                *s++ = 0;\n                *s++ = 0;\n                *s++ = value;\n                if (dest->alpha) *s++ = 255;\n            }\n            destp += destspan;\n        } while (--y);\n        return 1;\n    }\n\n    do {\n        unsigned char *s = destp;\n        for (x = 0; x < w; x++) {\n            for (k = 0; k < dest->n - 1; k++)\n                *s++ = value;\n            if (dest->alpha) *s++ = 255;\n            else *s++ = value;\n        }\n        destp += destspan;\n    } while (--y);\n    return 1;\n}\n\n//-----------------------------------------------------------------------------\n// fill a rect with a color tuple\n//-----------------------------------------------------------------------------\nint\nJM_fill_pixmap_rect_with_color(fz_context *ctx, fz_pixmap *dest, unsigned char col[5], fz_irect b)\n{\n    unsigned char *destp;\n    int x, y, w, i, destspan;\n\n    b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));\n    w = b.x1 - b.x0;\n    y = b.y1 - b.y0;\n    if (w <= 0 || y <= 0)\n        return 0;\n\n    destspan = dest->stride;\n    destp = dest->samples + (unsigned int)(destspan * (b.y0 - dest->y) + dest->n * (b.x0 - dest->x));\n\n    do {\n        unsigned char *s = destp;\n        for (x = 0; x < w; x++) {\n            for (i = 0; i < dest->n; i++)\n                *s++ = col[i];\n        }\n        destp += destspan;\n    } while (--y);\n    return 1;\n}\n\n//-----------------------------------------------------------------------------\n// invert a rectangle - also supports non-alpha pixmaps\n//-----------------------------------------------------------------------------\nint\nJM_invert_pixmap_rect(fz_context *ctx, fz_pixmap *dest, fz_irect b)\n{\n    unsigned char *destp;\n    int x, y, w, i, destspan;\n\n    b = fz_intersect_irect(b, fz_pixmap_bbox(ctx, dest));\n    w = b.x1 - b.x0;\n    y = b.y1 - b.y0;\n    if (w <= 0 || y <= 0)\n        return 0;\n\n    destspan = dest->stride;\n    destp = dest->samples + (unsigned int)(destspan * (b.y0 - dest->y) + dest->n * (b.x0 - dest->x));\n    int n0 = dest->n - dest->alpha;\n    do {\n        unsigned char *s = destp;\n        for (x = 0; x < w; x++) {\n            for (i = 0; i < n0; i++) {\n                *s = 255 - *s;\n                s++;\n            }\n            if (dest->alpha) s++;\n        }\n        destp += destspan;\n    } while (--y);\n    return 1;\n}\n\nint\nJM_is_jbig2_image(fz_context *ctx, pdf_obj *dict)\n{\n    // fixme: should we remove this function?\n\treturn 0;\n    /*\n    pdf_obj *filter;\n\tint i, n;\n\n\tfilter = pdf_dict_get(ctx, dict, PDF_NAME(Filter));\n\tif (pdf_name_eq(ctx, filter, PDF_NAME(JBIG2Decode)))\n\t\treturn 1;\n\tn = pdf_array_len(ctx, filter);\n\tfor (i = 0; i < n; i++)\n\t\tif (pdf_name_eq(ctx, pdf_array_get(ctx, filter, i), PDF_NAME(JBIG2Decode)))\n\t\t\treturn 1;\n\treturn 0;\n    */\n}\n\n//-----------------------------------------------------------------------------\n// Return basic properties of an image provided as bytes or bytearray\n// The function creates an fz_image and optionally returns it.\n//-----------------------------------------------------------------------------\nPyObject *JM_image_profile(fz_context *ctx, PyObject *imagedata, int keep_image)\n{\n    if (!EXISTS(imagedata)) {\n        Py_RETURN_NONE;  // nothing given\n    }\n    fz_image *image = NULL;\n    fz_buffer *res = NULL;\n    PyObject *result = NULL;\n    unsigned char *c = NULL;\n    Py_ssize_t len = 0;\n    if (PyBytes_Check(imagedata)) {\n        c = PyBytes_AS_STRING(imagedata);\n        len = PyBytes_GET_SIZE(imagedata);\n    } else if (PyByteArray_Check(imagedata)) {\n        c = PyByteArray_AS_STRING(imagedata);\n        len = PyByteArray_GET_SIZE(imagedata);\n    } else {\n        PySys_WriteStderr(\"bad image data\\n\");\n        Py_RETURN_NONE;\n    }\n\n    if (len < 8) {\n        PySys_WriteStderr(\"bad image data\\n\");\n        Py_RETURN_NONE;\n    }\n    int type = fz_recognize_image_format(ctx, c);\n    if (type == FZ_IMAGE_UNKNOWN) {\n        Py_RETURN_NONE;\n    }\n\n    fz_try(ctx) {\n        if (keep_image) {\n            res = fz_new_buffer_from_copied_data(ctx, c, (size_t) len);\n        } else {\n            res = fz_new_buffer_from_shared_data(ctx, c, (size_t) len);\n        }\n        image = fz_new_image_from_buffer(ctx, res);\n        int xres, yres, orientation;\n        fz_matrix ctm = fz_image_orientation_matrix(ctx, image);\n        fz_image_resolution(image, &xres, &yres);\n        orientation = (int) fz_image_orientation(ctx, image);\n        const char *cs_name = fz_colorspace_name(ctx, image->colorspace);\n        result = PyDict_New();\n        DICT_SETITEM_DROP(result, dictkey_width,\n                Py_BuildValue(\"i\", image->w));\n        DICT_SETITEM_DROP(result, dictkey_height,\n                Py_BuildValue(\"i\", image->h));\n        DICT_SETITEMSTR_DROP(result, \"orientation\",\n                Py_BuildValue(\"i\", orientation));\n        DICT_SETITEM_DROP(result, dictkey_matrix,\n                JM_py_from_matrix(ctm));\n        DICT_SETITEM_DROP(result, dictkey_xres,\n                Py_BuildValue(\"i\", xres));\n        DICT_SETITEM_DROP(result, dictkey_yres,\n                Py_BuildValue(\"i\", yres));\n        DICT_SETITEM_DROP(result, dictkey_colorspace,\n                Py_BuildValue(\"i\", image->n));\n        DICT_SETITEM_DROP(result, dictkey_bpc,\n                Py_BuildValue(\"i\", image->bpc));\n        DICT_SETITEM_DROP(result, dictkey_ext,\n                Py_BuildValue(\"s\", JM_image_extension(type)));\n        DICT_SETITEM_DROP(result, dictkey_cs_name,\n                Py_BuildValue(\"s\", cs_name));\n\n        if (keep_image) {\n            DICT_SETITEM_DROP(result, dictkey_image,\n                    PyLong_FromVoidPtr((void *) fz_keep_image(ctx, image)));\n        }\n    }\n    fz_always(ctx) {\n        if (!keep_image) {\n            fz_drop_image(ctx, image);\n        } else {\n            fz_drop_buffer(ctx, res);  // drop the buffer copy\n        }\n    }\n    fz_catch(ctx) {\n        Py_CLEAR(result);\n        fz_rethrow(ctx);\n    }\n    PyErr_Clear();\n    return result;\n}\n\n//----------------------------------------------------------------------------\n// Version of fz_new_pixmap_from_display_list (util.c) to also support\n// rendering of only the 'clip' part of the displaylist rectangle\n//----------------------------------------------------------------------------\nfz_pixmap *\nJM_pixmap_from_display_list(fz_context *ctx,\n                            fz_display_list *list,\n                            PyObject *ctm,\n                            fz_colorspace *cs,\n                            int alpha,\n                            PyObject *clip,\n                            fz_separations *seps\n                           )\n{\n    fz_rect rect = fz_bound_display_list(ctx, list);\n    fz_matrix matrix = JM_matrix_from_py(ctm);\n    fz_pixmap *pix = NULL;\n    fz_var(pix);\n    fz_device *dev = NULL;\n    fz_var(dev);\n    fz_rect rclip = JM_rect_from_py(clip);\n    rect = fz_intersect_rect(rect, rclip);  // no-op if clip is not given\n\n    rect = fz_transform_rect(rect, matrix);\n    fz_irect irect = fz_round_rect(rect);\n\n    pix = fz_new_pixmap_with_bbox(ctx, cs, irect, seps, alpha);\n    if (alpha)\n        fz_clear_pixmap(ctx, pix);\n    else\n        fz_clear_pixmap_with_value(ctx, pix, 0xFF);\n\n    fz_try(ctx) {\n        if (!fz_is_infinite_rect(rclip)) {\n            dev = fz_new_draw_device_with_bbox(ctx, matrix, pix, &irect);\n            fz_run_display_list(ctx, list, dev, fz_identity, rclip, NULL);\n        } else {\n            dev = fz_new_draw_device(ctx, matrix, pix);\n            fz_run_display_list(ctx, list, dev, fz_identity, fz_infinite_rect, NULL);\n        }\n\n        fz_close_device(ctx, dev);\n    }\n    fz_always(ctx) {\n        fz_drop_device(ctx, dev);\n    }\n    fz_catch(ctx) {\n        fz_drop_pixmap(ctx, pix);\n        fz_rethrow(ctx);\n    }\n    return pix;\n}\n\n//----------------------------------------------------------------------------\n// Pixmap creation directly using a short-lived displaylist, so we can support\n// separations.\n//----------------------------------------------------------------------------\nfz_pixmap *\nJM_pixmap_from_page(fz_context *ctx,\n                    fz_document *doc,\n                    fz_page *page,\n                    PyObject *ctm,\n                    fz_colorspace *cs,\n                    int alpha,\n                    int annots,\n                    PyObject *clip\n                   )\n{\n    enum { SPOTS_NONE, SPOTS_OVERPRINT_SIM, SPOTS_FULL };\n    int spots;\n    if (FZ_ENABLE_SPOT_RENDERING)\n        spots = SPOTS_OVERPRINT_SIM;\n    else\n        spots = SPOTS_NONE;\n\n    fz_separations *seps = NULL;\n    fz_pixmap *pix = NULL;\n    fz_colorspace *oi = NULL;\n    fz_var(oi);\n    fz_colorspace *colorspace = cs;\n    fz_rect rect;\n    fz_irect bbox;\n    fz_device *dev = NULL;\n    fz_var(dev);\n    fz_matrix matrix = JM_matrix_from_py(ctm);\n    rect = fz_bound_page(ctx, page);\n    fz_rect rclip = JM_rect_from_py(clip);\n    rect = fz_intersect_rect(rect, rclip);  // no-op if clip is not given\n    rect = fz_transform_rect(rect, matrix);\n    bbox = fz_round_rect(rect);\n\n    fz_try(ctx) {\n        // Pixmap of the document's /OutputIntents (\"output intents\")\n        oi = fz_document_output_intent(ctx, doc);\n        // if present and compatible, use it instead of the parameter\n        if (oi) {\n            if (fz_colorspace_n(ctx, oi) == fz_colorspace_n(ctx, cs)) {\n                colorspace = fz_keep_colorspace(ctx, oi);\n            }\n        }\n\n        // check if spots rendering is available and if so use separations\n        if (spots != SPOTS_NONE) {\n            seps = fz_page_separations(ctx, page);\n            if (seps) {\n                int i, n = fz_count_separations(ctx, seps);\n                if (spots == SPOTS_FULL)\n                    for (i = 0; i < n; i++)\n                        fz_set_separation_behavior(ctx, seps, i, FZ_SEPARATION_SPOT);\n                else\n                    for (i = 0; i < n; i++)\n                        fz_set_separation_behavior(ctx, seps, i, FZ_SEPARATION_COMPOSITE);\n            } else if (fz_page_uses_overprint(ctx, page)) {\n                /* This page uses overprint, so we need an empty\n                 * sep object to force the overprint simulation on. */\n                seps = fz_new_separations(ctx, 0);\n            } else if (oi && fz_colorspace_n(ctx, oi) != fz_colorspace_n(ctx, colorspace)) {\n                /* We have an output intent, and it's incompatible\n                 * with the colorspace our device needs. Force the\n                 * overprint simulation on, because this ensures that\n                 * we 'simulate' the output intent too. */\n                seps = fz_new_separations(ctx, 0);\n            }\n        }\n\n        pix = fz_new_pixmap_with_bbox(ctx, colorspace, bbox, seps, alpha);\n\n        if (alpha) {\n            fz_clear_pixmap(ctx, pix);\n        } else {\n            fz_clear_pixmap_with_value(ctx, pix, 0xFF);\n        }\n\n        dev = fz_new_draw_device(ctx, matrix, pix);\n        if (annots) {\n            fz_run_page(ctx, page, dev, fz_identity, NULL);\n        } else {\n            fz_run_page_contents(ctx, page, dev, fz_identity, NULL);\n        }\n        fz_close_device(ctx, dev);\n    }\n    fz_always(ctx) {\n        fz_drop_device(ctx, dev);\n        fz_drop_separations(ctx, seps);\n        fz_drop_colorspace(ctx, oi);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return pix;\n}\n\nPyObject *JM_color_count(fz_context *ctx, fz_pixmap *pm, PyObject *clip)\n{\n    PyObject *rc = PyDict_New(), *pixel=NULL, *c=NULL;\n    long cnt=0;\n    fz_irect irect = fz_pixmap_bbox(ctx, pm);\n    irect = fz_intersect_irect(irect, fz_round_rect(JM_rect_from_py(clip)));\n    size_t stride = pm->stride;\n    size_t width = irect.x1 - irect.x0, height = irect.y1 - irect.y0;\n    size_t i, j, n = (size_t) pm->n, substride = width * n;\n    unsigned char *s = pm->samples + stride * (irect.y0 - pm->y) + (irect.x0 - pm->x) * n;\n    unsigned char oldpix[10], newpix[10];\n    memcpy(oldpix, s, n);\n    cnt = 0;\n    fz_try(ctx) {\n        if (fz_is_empty_irect(irect)) goto finished;\n        for (i = 0; i < height; i++) {\n            for (j = 0; j < substride; j += n) {\n                memcpy(newpix, s + j, n);\n                if (memcmp(oldpix, newpix,n) != 0) {\n                    pixel = PyBytes_FromStringAndSize(oldpix, n);\n                    c = PyDict_GetItem(rc, pixel);\n                    if (c) cnt += PyLong_AsLong(c);\n                    DICT_SETITEM_DROP(rc, pixel, PyLong_FromLong(cnt));\n                    Py_DECREF(pixel);\n                    cnt = 1;\n                    memcpy(oldpix, newpix, n);\n                } else {\n                    cnt += 1;\n                }\n            }\n            s += stride;\n        }\n        pixel = PyBytes_FromStringAndSize(oldpix, n);\n        c = PyDict_GetItem(rc, pixel);\n        if (c) cnt += PyLong_AsLong(c);\n        DICT_SETITEM_DROP(rc, pixel, PyLong_FromLong(cnt));\n        Py_DECREF(pixel);\n        finished:;\n    }\n    fz_catch(ctx) {\n        Py_CLEAR(rc);\n        fz_rethrow(ctx);\n    }\n    PyErr_Clear();\n    return rc;\n}\n%}\n"
  },
  {
    "path": "src_classic/helper-portfolio.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//-----------------------------------------------------------------------------\n// perform some cleaning if we have /EmbeddedFiles:\n// (1) remove any /Limits if /Names exists\n// (2) remove any empty /Collection\n// (3) set /PageMode/UseAttachments\n//-----------------------------------------------------------------------------\nvoid JM_embedded_clean(fz_context *ctx, pdf_document *pdf)\n{\n    pdf_obj *root = pdf_dict_get(ctx, pdf_trailer(ctx, pdf), PDF_NAME(Root));\n\n    // remove any empty /Collection entry\n    pdf_obj *coll = pdf_dict_get(ctx, root, PDF_NAME(Collection));\n    if (coll && pdf_dict_len(ctx, coll) == 0)\n        pdf_dict_del(ctx, root, PDF_NAME(Collection));\n\n    pdf_obj *efiles = pdf_dict_getl(ctx, root,\n                                    PDF_NAME(Names),\n                                    PDF_NAME(EmbeddedFiles),\n                                    PDF_NAME(Names),\n                                    NULL);\n    if (efiles) {\n        pdf_dict_put_name(ctx, root, PDF_NAME(PageMode), \"UseAttachments\");\n    }\n    return;\n}\n\n//-----------------------------------------------------------------------------\n// embed a new file in a PDF (not only /EmbeddedFiles entries)\n//-----------------------------------------------------------------------------\npdf_obj *JM_embed_file(fz_context *ctx,\n                       pdf_document *pdf,\n                       fz_buffer *buf,\n                       char *filename,\n                       char *ufilename,\n                       char *desc,\n                       int compress)\n{\n    size_t len = 0;\n    pdf_obj *ef, *f, *params, *val = NULL;\n    fz_buffer *buff2 = NULL;\n    fz_var(buff2);\n    fz_try(ctx) {\n        val = pdf_new_dict(ctx, pdf, 6);\n        pdf_dict_put_dict(ctx, val, PDF_NAME(CI), 4);\n        ef = pdf_dict_put_dict(ctx, val, PDF_NAME(EF), 4);\n        pdf_dict_put_text_string(ctx, val, PDF_NAME(F), filename);\n        pdf_dict_put_text_string(ctx, val, PDF_NAME(UF), ufilename);\n        pdf_dict_put_text_string(ctx, val, PDF_NAME(Desc), desc);\n        pdf_dict_put(ctx, val, PDF_NAME(Type), PDF_NAME(Filespec));\n        buff2 = fz_new_buffer_from_copied_data(ctx, \"  \", 1);\n        f = pdf_add_stream(ctx, pdf, buff2, NULL, 0);\n        pdf_dict_put_drop(ctx, ef, PDF_NAME(F), f);\n        JM_update_stream(ctx, pdf, f, buf, compress);\n        len = fz_buffer_storage(ctx, buf, NULL);\n        pdf_dict_put_int(ctx, f, PDF_NAME(DL), len);\n        pdf_dict_put_int(ctx, f, PDF_NAME(Length), len);\n        params = pdf_dict_put_dict(ctx, f, PDF_NAME(Params), 4);\n        pdf_dict_put_int(ctx, params, PDF_NAME(Size), len);\n    }\n    fz_always(ctx) {\n        fz_drop_buffer(ctx, buff2);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return val;\n}\n%}\n"
  },
  {
    "path": "src_classic/helper-python.i",
    "content": "%pythoncode %{\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n\n# ------------------------------------------------------------------------------\n# Various PDF Optional Content Flags\n# ------------------------------------------------------------------------------\nPDF_OC_ON = 0\nPDF_OC_TOGGLE = 1\nPDF_OC_OFF = 2\n\n# ------------------------------------------------------------------------------\n# link kinds and link flags\n# ------------------------------------------------------------------------------\nLINK_NONE = 0\nLINK_GOTO = 1\nLINK_URI = 2\nLINK_LAUNCH = 3\nLINK_NAMED = 4\nLINK_GOTOR = 5\nLINK_FLAG_L_VALID = 1\nLINK_FLAG_T_VALID = 2\nLINK_FLAG_R_VALID = 4\nLINK_FLAG_B_VALID = 8\nLINK_FLAG_FIT_H = 16\nLINK_FLAG_FIT_V = 32\nLINK_FLAG_R_IS_ZOOM = 64\n\n# ------------------------------------------------------------------------------\n# Text handling flags\n# ------------------------------------------------------------------------------\nTEXT_ALIGN_LEFT = 0\nTEXT_ALIGN_CENTER = 1\nTEXT_ALIGN_RIGHT = 2\nTEXT_ALIGN_JUSTIFY = 3\n\nTEXT_OUTPUT_TEXT = 0\nTEXT_OUTPUT_HTML = 1\nTEXT_OUTPUT_JSON = 2\nTEXT_OUTPUT_XML = 3\nTEXT_OUTPUT_XHTML = 4\n\nTEXT_PRESERVE_LIGATURES = 1\nTEXT_PRESERVE_WHITESPACE = 2\nTEXT_PRESERVE_IMAGES = 4\nTEXT_INHIBIT_SPACES = 8\nTEXT_DEHYPHENATE = 16\nTEXT_PRESERVE_SPANS = 32\nTEXT_MEDIABOX_CLIP = 64\nTEXT_CID_FOR_UNKNOWN_UNICODE = 128\n\nTEXTFLAGS_WORDS = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_BLOCKS = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_DICT = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_PRESERVE_IMAGES\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_RAWDICT = TEXTFLAGS_DICT\n\nTEXTFLAGS_SEARCH = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_DEHYPHENATE\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_HTML = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_PRESERVE_IMAGES\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_XHTML = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_PRESERVE_IMAGES\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_XML = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\nTEXTFLAGS_TEXT = (0\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_MEDIABOX_CLIP\n        | TEXT_CID_FOR_UNKNOWN_UNICODE\n        )\n\n# ------------------------------------------------------------------------------\n# Simple text encoding options\n# ------------------------------------------------------------------------------\nTEXT_ENCODING_LATIN = 0\nTEXT_ENCODING_GREEK = 1\nTEXT_ENCODING_CYRILLIC = 2\n# ------------------------------------------------------------------------------\n# Stamp annotation icon numbers\n# ------------------------------------------------------------------------------\nSTAMP_Approved = 0\nSTAMP_AsIs = 1\nSTAMP_Confidential = 2\nSTAMP_Departmental = 3\nSTAMP_Experimental = 4\nSTAMP_Expired = 5\nSTAMP_Final = 6\nSTAMP_ForComment = 7\nSTAMP_ForPublicRelease = 8\nSTAMP_NotApproved = 9\nSTAMP_NotForPublicRelease = 10\nSTAMP_Sold = 11\nSTAMP_TopSecret = 12\nSTAMP_Draft = 13\n\n# ------------------------------------------------------------------------------\n# Base 14 font names and dictionary\n# ------------------------------------------------------------------------------\nBase14_fontnames = (\n    \"Courier\",\n    \"Courier-Oblique\",\n    \"Courier-Bold\",\n    \"Courier-BoldOblique\",\n    \"Helvetica\",\n    \"Helvetica-Oblique\",\n    \"Helvetica-Bold\",\n    \"Helvetica-BoldOblique\",\n    \"Times-Roman\",\n    \"Times-Italic\",\n    \"Times-Bold\",\n    \"Times-BoldItalic\",\n    \"Symbol\",\n    \"ZapfDingbats\",\n)\n\nBase14_fontdict = {}\nfor f in Base14_fontnames:\n    Base14_fontdict[f.lower()] = f\n    del f\nBase14_fontdict[\"helv\"] = \"Helvetica\"\nBase14_fontdict[\"heit\"] = \"Helvetica-Oblique\"\nBase14_fontdict[\"hebo\"] = \"Helvetica-Bold\"\nBase14_fontdict[\"hebi\"] = \"Helvetica-BoldOblique\"\nBase14_fontdict[\"cour\"] = \"Courier\"\nBase14_fontdict[\"coit\"] = \"Courier-Oblique\"\nBase14_fontdict[\"cobo\"] = \"Courier-Bold\"\nBase14_fontdict[\"cobi\"] = \"Courier-BoldOblique\"\nBase14_fontdict[\"tiro\"] = \"Times-Roman\"\nBase14_fontdict[\"tibo\"] = \"Times-Bold\"\nBase14_fontdict[\"tiit\"] = \"Times-Italic\"\nBase14_fontdict[\"tibi\"] = \"Times-BoldItalic\"\nBase14_fontdict[\"symb\"] = \"Symbol\"\nBase14_fontdict[\"zadb\"] = \"ZapfDingbats\"\n\nannot_skel = {\n    \"goto1\": \"<</A<</S/GoTo/D[%i 0 R/XYZ %g %g %g]>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>\",\n    \"goto2\": \"<</A<</S/GoTo/D%s>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>\",\n    \"gotor1\": \"<</A<</S/GoToR/D[%i /XYZ %g %g %g]/F<</F(%s)/UF(%s)/Type/Filespec>>>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>\",\n    \"gotor2\": \"<</A<</S/GoToR/D%s/F(%s)>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>\",\n    \"launch\": \"<</A<</S/Launch/F<</F(%s)/UF(%s)/Type/Filespec>>>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>\",\n    \"uri\": \"<</A<</S/URI/URI(%s)>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>\",\n    \"named\": \"<</A<</S/Named/N/%s/Type/Action>>/Rect[%s]/BS<</W 0>>/Subtype/Link>>\",\n}\n\nclass FileDataError(RuntimeError):\n    \"\"\"Raised for documents with file structure issues.\"\"\"\n    pass\n\nclass FileNotFoundError(RuntimeError):\n    \"\"\"Raised if file does not exist.\"\"\"\n    pass\n\nclass EmptyFileError(FileDataError):\n    \"\"\"Raised when creating documents from zero-length data.\"\"\"\n    pass\n\n# propagate exception class to C-level code\n_set_FileDataError(FileDataError)\n\ndef css_for_pymupdf_font(\n    fontcode: str, *, CSS: OptStr = None, archive: AnyType = None, name: OptStr = None\n) -> str:\n    \"\"\"Create @font-face items for the given fontcode of pymupdf-fonts.\n\n    Adds @font-face support for fonts contained in package pymupdf-fonts.\n\n    Creates a CSS font-family for all fonts starting with string 'fontcode'.\n\n    Note:\n        The font naming convention in package pymupdf-fonts is \"fontcode<sf>\",\n        where the suffix \"sf\" is either empty or one of \"it\", \"bo\" or \"bi\".\n        These suffixes thus represent the regular, italic, bold or bold-italic\n        variants of a font. For example, font code \"notos\" refers to fonts\n        \"notos\" - \"Noto Sans Regular\"\n        \"notosit\" - \"Noto Sans Italic\"\n        \"notosbo\" - \"Noto Sans Bold\"\n        \"notosbi\" - \"Noto Sans Bold Italic\"\n\n        This function creates four CSS @font-face definitions and collectively\n        assigns the font-family name \"notos\" to them (or the \"name\" value).\n\n    All fitting font buffers of the pymupdf-fonts package are placed / added\n    to the archive provided as parameter.\n    To use the font in fitz.Story, execute 'set_font(fontcode)'. The correct\n    font weight (bold) or style (italic) will automatically be selected.\n    Expects and returns the CSS source, with the new CSS definitions appended.\n\n    Args:\n        fontcode: (str) font code for naming the font variants to include.\n                  E.g. \"fig\" adds notos, notosi, notosb, notosbi fonts.\n                  A maximum of 4 font variants is accepted.\n        CSS: (str) CSS string to add @font-face definitions to.\n        archive: (Archive, mandatory) where to place the font buffers.\n        name: (str) use this as family-name instead of 'fontcode'.\n    Returns:\n        Modified CSS, with appended @font-face statements for each font variant\n        of fontcode.\n        Fontbuffers associated with \"fontcode\" will be added to 'archive'.\n    \"\"\"\n    # @font-face template string\n    CSSFONT = \"\\n@font-face {font-family: %s; src: url(%s);%s%s}\\n\"\n\n    if not type(archive) is Archive:\n        raise ValueError(\"'archive' must be an Archive\")\n    if CSS == None:\n        CSS = \"\"\n\n    # select font codes starting with the pass-in string\n    font_keys = [k for k in fitz_fontdescriptors.keys() if k.startswith(fontcode)]\n    if font_keys == []:\n        raise ValueError(f\"No font code '{fontcode}' found in pymupdf-fonts.\")\n    if len(font_keys) > 4:\n        raise ValueError(\"fontcode too short\")\n    if name == None:  # use this name for font-family\n        name = fontcode\n\n    for fkey in font_keys:\n        font = fitz_fontdescriptors[fkey]\n        bold = font[\"bold\"]  # determine font property\n        italic = font[\"italic\"]  # determine font property\n        fbuff = font[\"loader\"]()  # load the fontbuffer\n        archive.add(fbuff, fkey)  # update the archive\n        bold_text = \"font-weight: bold;\" if bold else \"\"\n        italic_text = \"font-style: italic;\" if italic else \"\"\n        CSS += CSSFONT % (name, fkey, bold_text, italic_text)\n    return CSS\n\n\ndef get_text_length(text: str, fontname: str =\"helv\", fontsize: float =11, encoding: int =0) -> float:\n    \"\"\"Calculate length of a string for a built-in font.\n\n    Args:\n        fontname: name of the font.\n        fontsize: font size points.\n        encoding: encoding to use, 0=Latin (default), 1=Greek, 2=Cyrillic.\n    Returns:\n        (float) length of text.\n    \"\"\"\n    fontname = fontname.lower()\n    basename = Base14_fontdict.get(fontname, None)\n\n    glyphs = None\n    if basename == \"Symbol\":\n        glyphs = symbol_glyphs\n    if basename == \"ZapfDingbats\":\n        glyphs = zapf_glyphs\n    if glyphs is not None:\n        w = sum([glyphs[ord(c)][1] if ord(c) < 256 else glyphs[183][1] for c in text])\n        return w * fontsize\n\n    if fontname in Base14_fontdict.keys():\n        return util_measure_string(\n            text, Base14_fontdict[fontname], fontsize, encoding\n        )\n\n    if fontname in (\n        \"china-t\",\n        \"china-s\",\n        \"china-ts\",\n        \"china-ss\",\n        \"japan\",\n        \"japan-s\",\n        \"korea\",\n        \"korea-s\",\n    ):\n        return len(text) * fontsize\n\n    raise ValueError(\"Font '%s' is unsupported\" % fontname)\n\n\n# ------------------------------------------------------------------------------\n# Glyph list for the built-in font 'ZapfDingbats'\n# ------------------------------------------------------------------------------\nzapf_glyphs = (\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (32, 0.278),\n    (33, 0.974),\n    (34, 0.961),\n    (35, 0.974),\n    (36, 0.98),\n    (37, 0.719),\n    (38, 0.789),\n    (39, 0.79),\n    (40, 0.791),\n    (41, 0.69),\n    (42, 0.96),\n    (43, 0.939),\n    (44, 0.549),\n    (45, 0.855),\n    (46, 0.911),\n    (47, 0.933),\n    (48, 0.911),\n    (49, 0.945),\n    (50, 0.974),\n    (51, 0.755),\n    (52, 0.846),\n    (53, 0.762),\n    (54, 0.761),\n    (55, 0.571),\n    (56, 0.677),\n    (57, 0.763),\n    (58, 0.76),\n    (59, 0.759),\n    (60, 0.754),\n    (61, 0.494),\n    (62, 0.552),\n    (63, 0.537),\n    (64, 0.577),\n    (65, 0.692),\n    (66, 0.786),\n    (67, 0.788),\n    (68, 0.788),\n    (69, 0.79),\n    (70, 0.793),\n    (71, 0.794),\n    (72, 0.816),\n    (73, 0.823),\n    (74, 0.789),\n    (75, 0.841),\n    (76, 0.823),\n    (77, 0.833),\n    (78, 0.816),\n    (79, 0.831),\n    (80, 0.923),\n    (81, 0.744),\n    (82, 0.723),\n    (83, 0.749),\n    (84, 0.79),\n    (85, 0.792),\n    (86, 0.695),\n    (87, 0.776),\n    (88, 0.768),\n    (89, 0.792),\n    (90, 0.759),\n    (91, 0.707),\n    (92, 0.708),\n    (93, 0.682),\n    (94, 0.701),\n    (95, 0.826),\n    (96, 0.815),\n    (97, 0.789),\n    (98, 0.789),\n    (99, 0.707),\n    (100, 0.687),\n    (101, 0.696),\n    (102, 0.689),\n    (103, 0.786),\n    (104, 0.787),\n    (105, 0.713),\n    (106, 0.791),\n    (107, 0.785),\n    (108, 0.791),\n    (109, 0.873),\n    (110, 0.761),\n    (111, 0.762),\n    (112, 0.762),\n    (113, 0.759),\n    (114, 0.759),\n    (115, 0.892),\n    (116, 0.892),\n    (117, 0.788),\n    (118, 0.784),\n    (119, 0.438),\n    (120, 0.138),\n    (121, 0.277),\n    (122, 0.415),\n    (123, 0.392),\n    (124, 0.392),\n    (125, 0.668),\n    (126, 0.668),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (183, 0.788),\n    (161, 0.732),\n    (162, 0.544),\n    (163, 0.544),\n    (164, 0.91),\n    (165, 0.667),\n    (166, 0.76),\n    (167, 0.76),\n    (168, 0.776),\n    (169, 0.595),\n    (170, 0.694),\n    (171, 0.626),\n    (172, 0.788),\n    (173, 0.788),\n    (174, 0.788),\n    (175, 0.788),\n    (176, 0.788),\n    (177, 0.788),\n    (178, 0.788),\n    (179, 0.788),\n    (180, 0.788),\n    (181, 0.788),\n    (182, 0.788),\n    (183, 0.788),\n    (184, 0.788),\n    (185, 0.788),\n    (186, 0.788),\n    (187, 0.788),\n    (188, 0.788),\n    (189, 0.788),\n    (190, 0.788),\n    (191, 0.788),\n    (192, 0.788),\n    (193, 0.788),\n    (194, 0.788),\n    (195, 0.788),\n    (196, 0.788),\n    (197, 0.788),\n    (198, 0.788),\n    (199, 0.788),\n    (200, 0.788),\n    (201, 0.788),\n    (202, 0.788),\n    (203, 0.788),\n    (204, 0.788),\n    (205, 0.788),\n    (206, 0.788),\n    (207, 0.788),\n    (208, 0.788),\n    (209, 0.788),\n    (210, 0.788),\n    (211, 0.788),\n    (212, 0.894),\n    (213, 0.838),\n    (214, 1.016),\n    (215, 0.458),\n    (216, 0.748),\n    (217, 0.924),\n    (218, 0.748),\n    (219, 0.918),\n    (220, 0.927),\n    (221, 0.928),\n    (222, 0.928),\n    (223, 0.834),\n    (224, 0.873),\n    (225, 0.828),\n    (226, 0.924),\n    (227, 0.924),\n    (228, 0.917),\n    (229, 0.93),\n    (230, 0.931),\n    (231, 0.463),\n    (232, 0.883),\n    (233, 0.836),\n    (234, 0.836),\n    (235, 0.867),\n    (236, 0.867),\n    (237, 0.696),\n    (238, 0.696),\n    (239, 0.874),\n    (183, 0.788),\n    (241, 0.874),\n    (242, 0.76),\n    (243, 0.946),\n    (244, 0.771),\n    (245, 0.865),\n    (246, 0.771),\n    (247, 0.888),\n    (248, 0.967),\n    (249, 0.888),\n    (250, 0.831),\n    (251, 0.873),\n    (252, 0.927),\n    (253, 0.97),\n    (183, 0.788),\n    (183, 0.788),\n)\n\n# ------------------------------------------------------------------------------\n# Glyph list for the built-in font 'Symbol'\n# ------------------------------------------------------------------------------\nsymbol_glyphs = (\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (32, 0.25),\n    (33, 0.333),\n    (34, 0.713),\n    (35, 0.5),\n    (36, 0.549),\n    (37, 0.833),\n    (38, 0.778),\n    (39, 0.439),\n    (40, 0.333),\n    (41, 0.333),\n    (42, 0.5),\n    (43, 0.549),\n    (44, 0.25),\n    (45, 0.549),\n    (46, 0.25),\n    (47, 0.278),\n    (48, 0.5),\n    (49, 0.5),\n    (50, 0.5),\n    (51, 0.5),\n    (52, 0.5),\n    (53, 0.5),\n    (54, 0.5),\n    (55, 0.5),\n    (56, 0.5),\n    (57, 0.5),\n    (58, 0.278),\n    (59, 0.278),\n    (60, 0.549),\n    (61, 0.549),\n    (62, 0.549),\n    (63, 0.444),\n    (64, 0.549),\n    (65, 0.722),\n    (66, 0.667),\n    (67, 0.722),\n    (68, 0.612),\n    (69, 0.611),\n    (70, 0.763),\n    (71, 0.603),\n    (72, 0.722),\n    (73, 0.333),\n    (74, 0.631),\n    (75, 0.722),\n    (76, 0.686),\n    (77, 0.889),\n    (78, 0.722),\n    (79, 0.722),\n    (80, 0.768),\n    (81, 0.741),\n    (82, 0.556),\n    (83, 0.592),\n    (84, 0.611),\n    (85, 0.69),\n    (86, 0.439),\n    (87, 0.768),\n    (88, 0.645),\n    (89, 0.795),\n    (90, 0.611),\n    (91, 0.333),\n    (92, 0.863),\n    (93, 0.333),\n    (94, 0.658),\n    (95, 0.5),\n    (96, 0.5),\n    (97, 0.631),\n    (98, 0.549),\n    (99, 0.549),\n    (100, 0.494),\n    (101, 0.439),\n    (102, 0.521),\n    (103, 0.411),\n    (104, 0.603),\n    (105, 0.329),\n    (106, 0.603),\n    (107, 0.549),\n    (108, 0.549),\n    (109, 0.576),\n    (110, 0.521),\n    (111, 0.549),\n    (112, 0.549),\n    (113, 0.521),\n    (114, 0.549),\n    (115, 0.603),\n    (116, 0.439),\n    (117, 0.576),\n    (118, 0.713),\n    (119, 0.686),\n    (120, 0.493),\n    (121, 0.686),\n    (122, 0.494),\n    (123, 0.48),\n    (124, 0.2),\n    (125, 0.48),\n    (126, 0.549),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (183, 0.46),\n    (160, 0.25),\n    (161, 0.62),\n    (162, 0.247),\n    (163, 0.549),\n    (164, 0.167),\n    (165, 0.713),\n    (166, 0.5),\n    (167, 0.753),\n    (168, 0.753),\n    (169, 0.753),\n    (170, 0.753),\n    (171, 1.042),\n    (172, 0.713),\n    (173, 0.603),\n    (174, 0.987),\n    (175, 0.603),\n    (176, 0.4),\n    (177, 0.549),\n    (178, 0.411),\n    (179, 0.549),\n    (180, 0.549),\n    (181, 0.576),\n    (182, 0.494),\n    (183, 0.46),\n    (184, 0.549),\n    (185, 0.549),\n    (186, 0.549),\n    (187, 0.549),\n    (188, 1),\n    (189, 0.603),\n    (190, 1),\n    (191, 0.658),\n    (192, 0.823),\n    (193, 0.686),\n    (194, 0.795),\n    (195, 0.987),\n    (196, 0.768),\n    (197, 0.768),\n    (198, 0.823),\n    (199, 0.768),\n    (200, 0.768),\n    (201, 0.713),\n    (202, 0.713),\n    (203, 0.713),\n    (204, 0.713),\n    (205, 0.713),\n    (206, 0.713),\n    (207, 0.713),\n    (208, 0.768),\n    (209, 0.713),\n    (210, 0.79),\n    (211, 0.79),\n    (212, 0.89),\n    (213, 0.823),\n    (214, 0.549),\n    (215, 0.549),\n    (216, 0.713),\n    (217, 0.603),\n    (218, 0.603),\n    (219, 1.042),\n    (220, 0.987),\n    (221, 0.603),\n    (222, 0.987),\n    (223, 0.603),\n    (224, 0.494),\n    (225, 0.329),\n    (226, 0.79),\n    (227, 0.79),\n    (228, 0.786),\n    (229, 0.713),\n    (230, 0.384),\n    (231, 0.384),\n    (232, 0.384),\n    (233, 0.384),\n    (234, 0.384),\n    (235, 0.384),\n    (236, 0.494),\n    (237, 0.494),\n    (238, 0.494),\n    (239, 0.494),\n    (183, 0.46),\n    (241, 0.329),\n    (242, 0.274),\n    (243, 0.686),\n    (244, 0.686),\n    (245, 0.686),\n    (246, 0.384),\n    (247, 0.549),\n    (248, 0.384),\n    (249, 0.384),\n    (250, 0.384),\n    (251, 0.384),\n    (252, 0.494),\n    (253, 0.494),\n    (254, 0.494),\n    (183, 0.46),\n)\n\n\nclass linkDest(object):\n    \"\"\"link or outline destination details\"\"\"\n\n    def __init__(self, obj, rlink):\n        isExt = obj.is_external\n        isInt = not isExt\n        self.dest = \"\"\n        self.fileSpec = \"\"\n        self.flags = 0\n        self.isMap = False\n        self.isUri = False\n        self.kind = LINK_NONE\n        self.lt = Point(0, 0)\n        self.named = \"\"\n        self.newWindow = \"\"\n        self.page = obj.page\n        self.rb = Point(0, 0)\n        self.uri = obj.uri\n        if rlink and not self.uri.startswith(\"#\"):\n            self.uri = \"#page=%i&zoom=0,%g,%g\" % (rlink[0] + 1, rlink[1], rlink[2])\n        if obj.is_external:\n            self.page = -1\n            self.kind = LINK_URI\n        if not self.uri:\n            self.page = -1\n            self.kind = LINK_NONE\n        if isInt and self.uri:\n            self.uri = self.uri.replace(\"&zoom=nan\", \"&zoom=0\")\n            if self.uri.startswith(\"#\"):\n                self.named = \"\"\n                self.kind = LINK_GOTO\n                m = re.match('^#page=([0-9]+)&zoom=([0-9.]+),(-?[0-9.]+),(-?[0-9.]+)$', self.uri)\n                if m:\n                    self.page = int(m.group(1)) - 1\n                    self.lt = Point(float((m.group(3))), float(m.group(4)))\n                    self.flags = self.flags | LINK_FLAG_L_VALID | LINK_FLAG_T_VALID\n                else:\n                    m = re.match('^#page=([0-9]+)$', self.uri)\n                    if m:\n                        self.page = int(m.group(1)) - 1\n                    else:\n                        self.kind = LINK_NAMED\n                        self.named = self.uri[1:]\n            else:\n                self.kind = LINK_NAMED\n                self.named = self.uri\n        if obj.is_external:\n            if self.uri.startswith((\"http://\", \"https://\", \"mailto:\", \"ftp://\")):\n                self.isUri = True\n                self.kind = LINK_URI\n            elif self.uri.startswith(\"file://\"):\n                self.fileSpec = self.uri[7:]\n                self.isUri = False\n                self.uri = \"\"\n                self.kind = LINK_LAUNCH\n                ftab = self.fileSpec.split(\"#\")\n                if len(ftab) == 2:\n                    if ftab[1].startswith(\"page=\"):\n                        self.kind = LINK_GOTOR\n                        self.fileSpec = ftab[0]\n                        self.page = int(ftab[1][5:]) - 1\n            else:\n                self.isUri = True\n                self.kind = LINK_LAUNCH\n\n\n# -------------------------------------------------------------------------------\n# \"Now\" timestamp in PDF Format\n# -------------------------------------------------------------------------------\ndef get_pdf_now() -> str:\n    import time\n\n    tz = \"%s'%s'\" % (\n        str(abs(time.altzone // 3600)).rjust(2, \"0\"),\n        str((abs(time.altzone // 60) % 60)).rjust(2, \"0\"),\n    )\n    tstamp = time.strftime(\"D:%Y%m%d%H%M%S\", time.localtime())\n    if time.altzone > 0:\n        tstamp += \"-\" + tz\n    elif time.altzone < 0:\n        tstamp += \"+\" + tz\n    else:\n        pass\n    return tstamp\n\n\ndef get_pdf_str(s: str) -> str:\n    \"\"\" Return a PDF string depending on its coding.\n\n    Notes:\n        Returns a string bracketed with either \"()\" or \"<>\" for hex values.\n        If only ascii then \"(original)\" is returned, else if only 8 bit chars\n        then \"(original)\" with interspersed octal strings \\nnn is returned,\n        else a string \"<FEFF[hexstring]>\" is returned, where [hexstring] is the\n        UTF-16BE encoding of the original.\n    \"\"\"\n    if not bool(s):\n        return \"()\"\n\n    def make_utf16be(s):\n        r = bytearray([254, 255]) + bytearray(s, \"UTF-16BE\")\n        return \"<\" + r.hex() + \">\"  # brackets indicate hex\n\n    # The following either returns the original string with mixed-in\n    # octal numbers \\nnn for chars outside the ASCII range, or returns\n    # the UTF-16BE BOM version of the string.\n    r = \"\"\n    for c in s:\n        oc = ord(c)\n        if oc > 255:  # shortcut if beyond 8-bit code range\n            return make_utf16be(s)\n\n        if oc > 31 and oc < 127:  # in ASCII range\n            if c in (\"(\", \")\", \"\\\\\"):  # these need to be escaped\n                r += \"\\\\\"\n            r += c\n            continue\n\n        if oc > 127:  # beyond ASCII\n            r += \"\\\\%03o\" % oc\n            continue\n\n        # now the white spaces\n        if oc == 8:  # backspace\n            r += \"\\\\b\"\n        elif oc == 9:  # tab\n            r += \"\\\\t\"\n        elif oc == 10:  # line feed\n            r += \"\\\\n\"\n        elif oc == 12:  # form feed\n            r += \"\\\\f\"\n        elif oc == 13:  # carriage return\n            r += \"\\\\r\"\n        else:\n            r += \"\\\\267\"  # unsupported: replace by 0xB7\n\n    return \"(\" + r + \")\"\n\n\ndef getTJstr(text: str, glyphs: typing.Union[list, tuple, None], simple: bool, ordering: int) -> str:\n    \"\"\" Return a PDF string enclosed in [] brackets, suitable for the PDF TJ\n    operator.\n\n    Notes:\n        The input string is converted to either 2 or 4 hex digits per character.\n    Args:\n        simple: no glyphs: 2-chars, use char codes as the glyph\n                glyphs: 2-chars, use glyphs instead of char codes (Symbol,\n                ZapfDingbats)\n        not simple: ordering < 0: 4-chars, use glyphs not char codes\n                    ordering >=0: a CJK font! 4 chars, use char codes as glyphs\n    \"\"\"\n    if text.startswith(\"[<\") and text.endswith(\">]\"):  # already done\n        return text\n\n    if not bool(text):\n        return \"[<>]\"\n\n    if simple:  # each char or its glyph is coded as a 2-byte hex\n        if glyphs is None:  # not Symbol, not ZapfDingbats: use char code\n            otxt = \"\".join([\"%02x\" % ord(c) if ord(c) < 256 else \"b7\" for c in text])\n        else:  # Symbol or ZapfDingbats: use glyphs\n            otxt = \"\".join(\n                [\"%02x\" % glyphs[ord(c)][0] if ord(c) < 256 else \"b7\" for c in text]\n            )\n        return \"[<\" + otxt + \">]\"\n\n    # non-simple fonts: each char or its glyph is coded as 4-byte hex\n    if ordering < 0:  # not a CJK font: use the glyphs\n        otxt = \"\".join([\"%04x\" % glyphs[ord(c)][0] for c in text])\n    else:  # CJK: use the char codes\n        otxt = \"\".join([\"%04x\" % ord(c) for c in text])\n\n    return \"[<\" + otxt + \">]\"\n\n\ndef paper_sizes():\n    \"\"\"Known paper formats @ 72 dpi as a dictionary. Key is the format string\n    like \"a4\" for ISO-A4. Value is the tuple (width, height).\n\n    Information taken from the following web sites:\n    www.din-formate.de\n    www.din-formate.info/amerikanische-formate.html\n    www.directtools.de/wissen/normen/iso.htm\n    \"\"\"\n    return {\n        \"a0\": (2384, 3370),\n        \"a1\": (1684, 2384),\n        \"a10\": (74, 105),\n        \"a2\": (1191, 1684),\n        \"a3\": (842, 1191),\n        \"a4\": (595, 842),\n        \"a5\": (420, 595),\n        \"a6\": (298, 420),\n        \"a7\": (210, 298),\n        \"a8\": (147, 210),\n        \"a9\": (105, 147),\n        \"b0\": (2835, 4008),\n        \"b1\": (2004, 2835),\n        \"b10\": (88, 125),\n        \"b2\": (1417, 2004),\n        \"b3\": (1001, 1417),\n        \"b4\": (709, 1001),\n        \"b5\": (499, 709),\n        \"b6\": (354, 499),\n        \"b7\": (249, 354),\n        \"b8\": (176, 249),\n        \"b9\": (125, 176),\n        \"c0\": (2599, 3677),\n        \"c1\": (1837, 2599),\n        \"c10\": (79, 113),\n        \"c2\": (1298, 1837),\n        \"c3\": (918, 1298),\n        \"c4\": (649, 918),\n        \"c5\": (459, 649),\n        \"c6\": (323, 459),\n        \"c7\": (230, 323),\n        \"c8\": (162, 230),\n        \"c9\": (113, 162),\n        \"card-4x6\": (288, 432),\n        \"card-5x7\": (360, 504),\n        \"commercial\": (297, 684),\n        \"executive\": (522, 756),\n        \"invoice\": (396, 612),\n        \"ledger\": (792, 1224),\n        \"legal\": (612, 1008),\n        \"legal-13\": (612, 936),\n        \"letter\": (612, 792),\n        \"monarch\": (279, 540),\n        \"tabloid-extra\": (864, 1296),\n    }\n\n\ndef paper_size(s: str) -> tuple:\n    \"\"\"Return a tuple (width, height) for a given paper format string.\n\n    Notes:\n        'A4-L' will return (842, 595), the values for A4 landscape.\n        Suffix '-P' and no suffix return the portrait tuple.\n    \"\"\"\n    size = s.lower()\n    f = \"p\"\n    if size.endswith(\"-l\"):\n        f = \"l\"\n        size = size[:-2]\n    if size.endswith(\"-p\"):\n        size = size[:-2]\n    rc = paper_sizes().get(size, (-1, -1))\n    if f == \"p\":\n        return rc\n    return (rc[1], rc[0])\n\n\ndef paper_rect(s: str) -> Rect:\n    \"\"\"Return a Rect for the paper size indicated in string 's'. Must conform to the argument of method 'PaperSize', which will be invoked.\n    \"\"\"\n    width, height = paper_size(s)\n    return Rect(0.0, 0.0, width, height)\n\n\ndef CheckParent(o: typing.Any):\n    if getattr(o, \"parent\", None) == None:\n        raise ValueError(\"orphaned object: parent is None\")\n\n\ndef EnsureOwnership(o: typing.Any):\n    if not getattr(o, \"thisown\", False):\n        raise RuntimeError(\"object destroyed\")\n\n\ndef CheckColor(c: OptSeq):\n    if c:\n        if (\n            type(c) not in (list, tuple)\n            or len(c) not in (1, 3, 4)\n            or min(c) < 0\n            or max(c) > 1\n        ):\n            raise ValueError(\"need 1, 3 or 4 color components in range 0 to 1\")\n\n\ndef ColorCode(c: typing.Union[list, tuple, float, None], f: str) -> str:\n    if not c:\n        return \"\"\n    if hasattr(c, \"__float__\"):\n        c = (c,)\n    CheckColor(c)\n    if len(c) == 1:\n        s = \"%g \" % c[0]\n        return s + \"G \" if f == \"c\" else s + \"g \"\n\n    if len(c) == 3:\n        s = \"%g %g %g \" % tuple(c)\n        return s + \"RG \" if f == \"c\" else s + \"rg \"\n\n    s = \"%g %g %g %g \" % tuple(c)\n    return s + \"K \" if f == \"c\" else s + \"k \"\n\n\ndef JM_TUPLE(o: typing.Sequence) -> tuple:\n    return tuple(map(lambda x: round(x, 5) if abs(x) >= 1e-4 else 0, o))\n\n\ndef JM_TUPLE3(o: typing.Sequence) -> tuple:\n    return tuple(map(lambda x: round(x, 3) if abs(x) >= 1e-3 else 0, o))\n\n\ndef CheckRect(r: typing.Any) -> bool:\n    \"\"\"Check whether an object is non-degenerate rect-like.\n\n    It must be a sequence of 4 numbers.\n    \"\"\"\n    try:\n        r = Rect(r)\n    except:\n        return False\n    return not (r.is_empty or r.is_infinite)\n\n\ndef CheckQuad(q: typing.Any) -> bool:\n    \"\"\"Check whether an object is convex, not empty quad-like.\n\n    It must be a sequence of 4 number pairs.\n    \"\"\"\n    try:\n        q0 = Quad(q)\n    except:\n        return False\n    return q0.is_convex\n\n\ndef CheckMarkerArg(quads: typing.Any) -> tuple:\n    if CheckRect(quads):\n        r = Rect(quads)\n        return (r.quad,)\n    if CheckQuad(quads):\n        return (quads,)\n    for q in quads:\n        if not (CheckRect(q) or CheckQuad(q)):\n            raise ValueError(\"bad quads entry\")\n    return quads\n\n\ndef CheckMorph(o: typing.Any) -> bool:\n    if not bool(o):\n        return False\n    if not (type(o) in (list, tuple) and len(o) == 2):\n        raise ValueError(\"morph must be a sequence of length 2\")\n    if not (len(o[0]) == 2 and len(o[1]) == 6):\n        raise ValueError(\"invalid morph parm 0\")\n    if not o[1][4] == o[1][5] == 0:\n        raise ValueError(\"invalid morph parm 1\")\n    return True\n\n\ndef CheckFont(page: \"struct Page *\", fontname: str) -> tuple:\n    \"\"\"Return an entry in the page's font list if reference name matches.\n    \"\"\"\n    for f in page.get_fonts():\n        if f[4] == fontname:\n            return f\n\n\ndef CheckFontInfo(doc: \"struct Document *\", xref: int) -> list:\n    \"\"\"Return a font info if present in the document.\n    \"\"\"\n    for f in doc.FontInfos:\n        if xref == f[0]:\n            return f\n\n\ndef UpdateFontInfo(doc: \"struct Document *\", info: typing.Sequence):\n    xref = info[0]\n    found = False\n    for i, fi in enumerate(doc.FontInfos):\n        if fi[0] == xref:\n            found = True\n            break\n    if found:\n        doc.FontInfos[i] = info\n    else:\n        doc.FontInfos.append(info)\n\n\ndef DUMMY(*args, **kw):\n    return\n\n\ndef planish_line(p1: point_like, p2: point_like) -> Matrix:\n    \"\"\"Compute matrix which maps line from p1 to p2 to the x-axis, such that it\n    maintains its length and p1 * matrix = Point(0, 0).\n\n    Args:\n        p1, p2: point_like\n    Returns:\n        Matrix which maps p1 to Point(0, 0) and p2 to a point on the x axis at\n        the same distance to Point(0,0). Will always combine a rotation and a\n        transformation.\n    \"\"\"\n    p1 = Point(p1)\n    p2 = Point(p2)\n    return Matrix(util_hor_matrix(p1, p2))\n\n\ndef image_profile(img: ByteString) -> dict:\n    \"\"\" Return basic properties of an image.\n\n    Args:\n        img: bytes, bytearray, io.BytesIO object or an opened image file.\n    Returns:\n        A dictionary with keys width, height, colorspace.n, bpc, type, ext and size,\n        where 'type' is the MuPDF image type (0 to 14) and 'ext' the suitable\n        file extension.\n    \"\"\"\n    if type(img) is io.BytesIO:\n        stream = img.getvalue()\n    elif hasattr(img, \"read\"):\n        stream = img.read()\n    elif type(img) in (bytes, bytearray):\n        stream = img\n    else:\n        raise ValueError(\"bad argument 'img'\")\n\n    return TOOLS.image_profile(stream)\n\n\ndef ConversionHeader(i: str, filename: OptStr =\"unknown\"):\n    t = i.lower()\n    html = \"\"\"<!DOCTYPE html>\n<html>\n<head>\n<style>\nbody{background-color:gray}\ndiv{position:relative;background-color:white;margin:1em auto}\np{position:absolute;margin:0}\nimg{position:absolute}\n</style>\n</head>\n<body>\\n\"\"\"\n\n    xml = (\n        \"\"\"<?xml version=\"1.0\"?>\n<document name=\"%s\">\\n\"\"\"\n        % filename\n    )\n\n    xhtml = \"\"\"<?xml version=\"1.0\"?>\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\n<head>\n<style>\nbody{background-color:gray}\ndiv{background-color:white;margin:1em;padding:1em}\np{white-space:pre-wrap}\n</style>\n</head>\n<body>\\n\"\"\"\n\n    text = \"\"\n    json = '{\"document\": \"%s\", \"pages\": [\\n' % filename\n    if t == \"html\":\n        r = html\n    elif t == \"json\":\n        r = json\n    elif t == \"xml\":\n        r = xml\n    elif t == \"xhtml\":\n        r = xhtml\n    else:\n        r = text\n\n    return r\n\n\ndef ConversionTrailer(i: str):\n    t = i.lower()\n    text = \"\"\n    json = \"]\\n}\"\n    html = \"</body>\\n</html>\\n\"\n    xml = \"</document>\\n\"\n    xhtml = html\n    if t == \"html\":\n        r = html\n    elif t == \"json\":\n        r = json\n    elif t == \"xml\":\n        r = xml\n    elif t == \"xhtml\":\n        r = xhtml\n    else:\n        r = text\n\n    return r\n\nclass ElementPosition(object):\n    \"\"\"Convert a dictionary with element position information to an object.\"\"\"\n    def __init__(self):\n        pass\n    def __str__(self):\n        ret = \"\"\n        for n, v in self.__dict__.items():\n            ret += f\" {n}={v!r}\"\n        return ret\n\ndef make_story_elpos():\n    return ElementPosition()\n\n\ndef get_highlight_selection(page, start: point_like =None, stop: point_like =None, clip: rect_like =None) -> list:\n    \"\"\"Return rectangles of text lines between two points.\n\n    Notes:\n        The default of 'start' is top-left of 'clip'. The default of 'stop'\n        is bottom-reight of 'clip'.\n\n    Args:\n        start: start point_like\n        stop: end point_like, must be 'below' start\n        clip: consider this rect_like only, default is page rectangle\n    Returns:\n        List of line bbox intersections with the area established by the\n        parameters.\n    \"\"\"\n    # validate and normalize arguments\n    if clip is None:\n        clip = page.rect\n    clip = Rect(clip)\n    if start is None:\n        start = clip.tl\n    if stop is None:\n        stop = clip.br\n    clip.y0 = start.y\n    clip.y1 = stop.y\n    if clip.is_empty or clip.is_infinite:\n        return []\n\n    # extract text of page, clip only, no images, expand ligatures\n    blocks = page.get_text(\n        \"dict\", flags=0, clip=clip,\n    )[\"blocks\"]\n\n    lines = []  # will return this list of rectangles\n    for b in blocks:\n        bbox = Rect(b[\"bbox\"])\n        if bbox.is_infinite or bbox.is_empty:\n            continue\n        for line in b[\"lines\"]:\n            bbox = Rect(line[\"bbox\"])\n            if bbox.is_infinite or bbox.is_empty:\n                continue\n            lines.append(bbox)\n\n    if lines == []:  # did not select anything\n        return lines\n\n    lines.sort(key=lambda bbox: bbox.y1)  # sort by vertical positions\n\n    # cut off prefix from first line if start point is close to its top\n    bboxf = lines.pop(0)\n    if bboxf.y0 - start.y <= 0.1 * bboxf.height:  # close enough?\n        r = Rect(start.x, bboxf.y0, bboxf.br)  # intersection rectangle\n        if not (r.is_empty or r.is_infinite):\n            lines.insert(0, r)  # insert again if not empty\n    else:\n        lines.insert(0, bboxf)  # insert again\n\n    if lines == []:  # the list might have been emptied\n        return lines\n\n    # cut off suffix from last line if stop point is close to its bottom\n    bboxl = lines.pop()\n    if stop.y - bboxl.y1 <= 0.1 * bboxl.height:  # close enough?\n        r = Rect(bboxl.tl, stop.x, bboxl.y1)  # intersection rectangle\n        if not (r.is_empty or r.is_infinite):\n            lines.append(r)  # append if not empty\n    else:\n        lines.append(bboxl)  # append again\n\n    return lines\n\n\ndef annot_preprocess(page: \"Page\") -> int:\n    \"\"\"Prepare for annotation insertion on the page.\n\n    Returns:\n        Old page rotation value. Temporarily sets rotation to 0 when required.\n    \"\"\"\n    CheckParent(page)\n    if not page.parent.is_pdf:\n        raise ValueError(\"is no PDF\")\n    old_rotation = page.rotation\n    if old_rotation != 0:\n        page.set_rotation(0)\n    return old_rotation\n\n\ndef annot_postprocess(page: \"Page\", annot: \"Annot\") -> None:\n    \"\"\"Clean up after annotation inertion.\n\n    Set ownership flag and store annotation in page annotation dictionary.\n    \"\"\"\n    annot.parent = weakref.proxy(page)\n    page._annot_refs[id(annot)] = annot\n    annot.thisown = True\n\n\ndef sRGB_to_rgb(srgb: int) -> tuple:\n    \"\"\"Convert sRGB color code to an RGB color triple.\n\n    There is **no error checking** for performance reasons!\n\n    Args:\n        srgb: (int) RRGGBB (red, green, blue), each color in range(255).\n    Returns:\n        Tuple (red, green, blue) each item in intervall 0 <= item <= 255.\n    \"\"\"\n    r = srgb >> 16\n    g = (srgb - (r << 16)) >> 8\n    b = srgb - (r << 16) - (g << 8)\n    return (r, g, b)\n\n\ndef sRGB_to_pdf(srgb: int) -> tuple:\n    \"\"\"Convert sRGB color code to a PDF color triple.\n\n    There is **no error checking** for performance reasons!\n\n    Args:\n        srgb: (int) RRGGBB (red, green, blue), each color in range(255).\n    Returns:\n        Tuple (red, green, blue) each item in intervall 0 <= item <= 1.\n    \"\"\"\n    t = sRGB_to_rgb(srgb)\n    return t[0] / 255.0, t[1] / 255.0, t[2] / 255.0\n\n\ndef make_table(rect: rect_like =(0, 0, 1, 1), cols: int =1, rows: int =1) -> list:\n    \"\"\"Return a list of (rows x cols) equal sized rectangles.\n\n    Notes:\n        A utility to fill a given area with table cells of equal size.\n    Args:\n        rect: rect_like to use as the table area\n        rows: number of rows\n        cols: number of columns\n    Returns:\n        A list with <rows> items, where each item is a list of <cols>\n        PyMuPDF Rect objects of equal sizes.\n    \"\"\"\n    rect = Rect(rect)  # ensure this is a Rect\n    if rect.is_empty or rect.is_infinite:\n        raise ValueError(\"rect must be finite and not empty\")\n    tl = rect.tl\n\n    height = rect.height / rows  # height of one table cell\n    width = rect.width / cols  # width of one table cell\n    delta_h = (width, 0, width, 0)  # diff to next right rect\n    delta_v = (0, height, 0, height)  # diff to next lower rect\n\n    r = Rect(tl, tl.x + width, tl.y + height)  # first rectangle\n\n    # make the first row\n    row = [r]\n    for i in range(1, cols):\n        r += delta_h  # build next rect to the right\n        row.append(r)\n\n    # make result, starts with first row\n    rects = [row]\n    for i in range(1, rows):\n        row = rects[i - 1]  # take previously appended row\n        nrow = []  # the new row to append\n        for r in row:  # for each previous cell add its downward copy\n            nrow.append(r + delta_v)\n        rects.append(nrow)  # append new row to result\n\n    return rects\n\n\ndef repair_mono_font(page: \"Page\", font: \"Font\") -> None:\n    \"\"\"Repair character spacing for mono fonts.\n\n    Notes:\n        Some mono-spaced fonts are displayed with a too large character\n        width, e.g. \"a b c\" instead of \"abc\". This utility adds an entry\n        \"/DW w\" to the descendent font of font. The int w is\n        taken to be the first width > 0 of the font's unicodes.\n        This should enforce viewers to use 'w' as the character width.\n\n    Args:\n        page: fitz.Page object.\n        font: fitz.Font object.\n    \"\"\"\n    def set_font_width(doc, xref, width):\n        df = doc.xref_get_key(xref, \"DescendantFonts\")\n        if df[0] != \"array\":\n            return False\n        df_xref = int(df[1][1:-1].replace(\"0 R\",\"\"))\n        W = doc.xref_get_key(df_xref, \"W\")\n        if W[1] != \"null\":\n            doc.xref_set_key(df_xref, \"W\", \"null\")\n        doc.xref_set_key(df_xref, \"DW\", str(width))\n        return True\n\n    if not font.flags[\"mono\"]:  # font not flagged as monospaced\n        return None\n    doc = page.parent  # the document\n    fontlist = page.get_fonts()  # list of fonts on page\n    xrefs = [  # list of objects referring to font\n        f[0]\n        for f in fontlist\n        if (f[3] == font.name and f[4].startswith(\"F\") and f[5].startswith(\"Identity\"))\n    ]\n    if xrefs == []:  # our font does not occur\n        return\n    xrefs = set(xrefs)  # drop any double counts\n    maxadv = max([font.glyph_advance(cp) for cp in font.valid_codepoints()[:3]])\n    width = int(round((maxadv * 1000)))\n    for xref in xrefs:\n        if not set_font_width(doc, xref, width):\n            print(\"Cannot set width for '%s' in xref %i\" % (font.name, xref))\n\n\n# Adobe Glyph List functions\nimport base64, gzip\n\n_adobe_glyphs = {}\n_adobe_unicodes = {}\ndef unicode_to_glyph_name(ch: int) -> str:\n    if _adobe_glyphs == {}:\n        for line in _get_glyph_text():\n            if line.startswith(\"#\"):\n                continue\n            name, unc = line.split(\";\")\n            uncl = unc.split()\n            for unc in uncl:\n                c = int(unc[:4], base=16)\n                _adobe_glyphs[c] = name\n    return _adobe_glyphs.get(ch, \".notdef\")\n\n\ndef glyph_name_to_unicode(name: str) -> int:\n    if _adobe_unicodes == {}:\n        for line in _get_glyph_text():\n            if line.startswith(\"#\"):\n                continue\n            gname, unc = line.split(\";\")\n            c = int(unc[:4], base=16)\n            _adobe_unicodes[gname] = c\n    return _adobe_unicodes.get(name, 65533)\n\ndef adobe_glyph_names() -> tuple:\n    if _adobe_unicodes == {}:\n        for line in _get_glyph_text():\n            if line.startswith(\"#\"):\n                continue\n            gname, unc = line.split(\";\")\n            c = int(\"0x\" + unc[:4], base=16)\n            _adobe_unicodes[gname] = c\n    return tuple(_adobe_unicodes.keys())\n\ndef adobe_glyph_unicodes() -> tuple:\n    if _adobe_unicodes == {}:\n        for line in _get_glyph_text():\n            if line.startswith(\"#\"):\n                continue\n            gname, unc = line.split(\";\")\n            c = int(\"0x\" + unc[:4], base=16)\n            _adobe_unicodes[gname] = c\n    return tuple(_adobe_unicodes.values())\n\ndef _get_glyph_text() -> bytes:\n    return gzip.decompress(base64.b64decode(\n    b'H4sIABmRaF8C/7W9SZfjRpI1useviPP15utzqroJgBjYWhEkKGWVlKnOoapVO0YQEYSCJE'\n    b'IcMhT569+9Ppibg8xevHdeSpmEXfPBfDZ3N3f/t7u//r//k/zb3WJ4eTv2T9vzXTaZZH/N'\n    b'Junsbr4Z7ru7/7s9n1/+6z//8/X19T/WRP7jYdj/57//R/Jv8Pax2/Sn87G/v5z74XC3Pm'\n    b'zuLqfurj/cnYbL8aEzyH1/WB/f7h6H4/70l7vX/ry9G47wzK/hcr7bD5v+sX9YM4i/3K2P'\n    b'3d1Ld9z353O3uXs5Dl/7DT7O2/UZ/3Tw9zjsdsNrf3i6exgOm57eTsbbvjv/1w2xTnfDo5'\n    b'fnYdjA3eV0vjt25zXkRJB36/vhKwN+kEw4DOf+ofsLuP3pboewGISO7bAxPkUU+EaUD7t1'\n    b'v++O/3FTCESmcsILgQRuLhDs/w857lz6NsPDZd8dzmtfSP85HO8GcI53+/W5O/br3QkeJa'\n    b'9NERmPKgE2Ue+73vgj97Ded5TH1pPDEFCT4/35RFFtAMORMezXb3dwiioCsYe77rABjjCO'\n    b'jHs/nLs7mx3wuYFYX+HsEQyTfHg/DY/nVxa0rzmnl+6BVQfeegTyemSlOdjqczqJ0J9/ev'\n    b'fp7tOH1ed/zj+2d/j+9eOHf7xbtsu75jcw27vFh19/+/jux58+3/304edl+/HT3fz9kq3i'\n    b'w/vPH981Xz5/APR/5p/g9/+Qhb+/3bX/8+vH9tOnuw8f79798uvP7xAcwv84f//5XfvpL/'\n    b'D97v3i5y/Ld+9//Msdgrh7/+Hz3c/vfnn3GQ4/f/iLifja492HFbz+0n5c/ARg3rz7+d3n'\n    b'30ycq3ef3zO+FSKc3/06//j53eLLz/OPd79++fjrh0/tHRIHr8t3nxY/z9/90i7/AxIg1r'\n    b'v2H+37z3effpr//PPN1CIF47Q2LUSdNz+3NjakdvnuY7v4/BcEGb4WyEPI+DMT++nXdvEO'\n    b'n8iWFomaf/ztL8wZhPqp/e8vcAbm3XL+y/xHpPH/xlnDejXKHJTQ4svH9hdK/mF19+lL8+'\n    b'nzu89fPrd3P374sDSZ/qn9+I93i/bTD/D+8wcWxOruy6f2L4jl89xEjkCQaZ9+4Hfz5dM7'\n    b'k33v3n9uP3788uvndx/e/zu8/vThn8ggSDqH56XJ6Q/vTZKRVx8+/sZgmRemIP5y98+fWu'\n    b'Ao8vc+z+bMjE/Iu8Vn7RBxIis/q7TevW9//Pndj+37RWuz/AND+ue7T+2/o+zefaKTdzbq'\n    b'f84R7xeTdJYYJLOf7z4xq11N/osp2bt3q7v58h/vKLxzjtrw6Z2rOSbzFj+5rEd7+P84UL'\n    b'xH8/6vO/lj2/6Pu7eX7d3P6C3Y2tb3u+7ua3dkA/yvu+w/JqyV6GeUt0/dy7nb36MjySZ/'\n    b'MUMO3Hz5+LNycsdx54SB5wmN/XJvRh0z/vz1/PaCf4Zhd/rP9dPur/j7eDDtfIV+dX3+r7'\n    b'vz63B36vb9w7AbDn/ddLseown7kr7bbU4YIhD6/03//e7JiM0O669/vbyg1/hPdKLd8WGN'\n    b'PmnXoSs52h5200OGk/WW/fvdl0NvhpHTw3q3Pt59Xe8uCOARA8ydCcX433Z/rjfonfbrnf'\n    b'hP5j9MJtM0mbf4XZT4XT9czt0Pk3S1ALFfPxyHA6g2A3WCz90Pq6qFO+dsskjdtzAB3B+7'\n    b'rwwDeWi/reu0nbcOeMBostv1Dz9MpsuJwzbD+b5DcuGuKR32dFx/pcfGO9oOw7MZlAj64M'\n    b'/9bmOAaTJ/WFuJF0t898eHXfdDNmV4JC77x133J8XONCDiTTWq5JkvNMMLNY9C1ZLNa82R'\n    b'rIki9ULP50AZ/6pczOyn92DSE3IqRSZs7nc2+gmqKMi+O3an/sQkTQOpszcLsBTnsg2gSE'\n    b'f/KskTQ4YaANrFPFn4b/ELIEo/Iu2jQkbg/QEtEJXe1Y6MtWP3sl3/MMlnqf08D4cBaclr'\n    b'5KzEzHTuyXhZPyCXVhkcD0/DoXsmEwEfoWVQqsJ+Sg2eW9qniOGQFqHh3n+XCNMWCMLJ3b'\n    b'c4BPB2vz5CYenXkKjI06Rhu8mSJlSxKmmQX+uHB6g1jC0ztEQ+TRqdISmC6A46TLiH/sfM'\n    b'wBczE0mo4WrXHzoJpUyaKCvglLnpJC1XiEWSBN55eIHcDChLFpQ4TxZrHWkL2mUXwl6Yto'\n    b'N6OLefEmyRLHy7mizwDT1yt1szryqhfCOa1AJJBtKVZFRtCd8WU3pATvFrbr5cHlo6Dome'\n    b'tzoF0xmAbn3/vF2fgKgcbhbkKCCrCKBYETp0uZt+2siJ5pSGc92+kOVgbLVIOREE/rw+jc'\n    b'JfNGSxGWBysYMmOzxrCU3qelSBOUV1VQCf456kXEGaqB4gykGJUKTJQupBnixZ9NNk+S+2'\n    b'ihS/0kkCjOoD6ccjhCO3niVLKfYW367Y0xY90TIU6MwSVkRfVdMM6HFYsxzpPGobc0NLrV'\n    b'4ky6htQIoOA9rLmWTeIupuh6aRZaij5vPp2LH15zO49PmEMH1niBrcCCWd60KgH00/Bmgp'\n    b'kM8t9NzL/mm930scS/j7XYuHlr2MGiXkiwoDQvnESoFVyfKEarx1uSGFA7ehkULobywiRP'\n    b'BNiqgAcbOCo9MFRwtGp1GVn6wSDuzTImllwJ65b2mcAPyAjZxvfcTpHN+2xC0bZboApKt6'\n    b'joBDPZhbIgyyEeD7B7Sx9kZ1qTWqKgeUkvZ66MUI1N4eejGytzeG3kgUP/QumFyVWyD1+E'\n    b'pSja9NICVYYqbrSkvzJV2Xo0WhQfIedV+EsGU0rd23hAogyuUKtNZ7kBjOxTEPBT9LS/Cv'\n    b'BlfE32OqDgVzo+JFfWt3uqkhATv4OEhYCFtGXrRhR/jCY7Is4kuCVWavQ0QdiVoDqoiute'\n    b'kS9K0eFjpDy3E8nc75EdVjKGbtgVmg+1KkWtQAVp/hpaPQM1SNl1O/YwryWeEJUS3gUkeb'\n    b'wTnzDLP+DdtgG0jtClLrXh86SHu6mQoIb1r5HM1KWjmksEN7xQ9VsjVpEQ1ezvA7gUqMD+'\n    b'97RcpruAv3Le0G8V2Oww/ZBDpq+40xQxPBh2/G6D1BqRSiKq7YJ5TJKjTdJlnpDjptk1U0'\n    b'phVwrbvkabJy/S5Ut1UPnyELqgwIovM1Cm6jCoGgMDERdp6sJJ/K5EeKViU/Nqc/Lutj90'\n    b'OeYwD8UVS6Kb7RNzMrc/sZhqsZmYenfh3EnCc/StfWJj9KniAe0WFSKFE/hpxYWEK0k5TA'\n    b'wIh806Z72+hRd37UjZ50NJBBxu16o3UD+N1iHrjZ7LpRfab42+5KJ5gZH5eX8+WomxFq+Y'\n    b'++BBALJnWqVgGIRywArlFjJgefUXkgf/142NpPKQ84le/KfdtYs1kD2gjLDJ0mP7Hg6uSn'\n    b'tEb8P2TFYmW+p/xGo+B3kfK7SX7CQF4ZPE1++lUKGh3sT+tbAx3G5J/WN5WyDIzj5tQ/ae'\n    b'cZYrMDKqraT6b8fWshK2gxGcINBb+0hBQ8uuifpPuHY4SlmwhqwU+qg6frKFcRttbIphPQ'\n    b'R9WCwJesxfcF85bjZb9bX84siFWEiBYBh98kv1AF3jHTZ8k7PUvMVsm7v0F+TCjefdF4m7'\n    b'wTJWDpvmXIAeBbSrZI3on2gcBCFrWWCAN8BEhYRFXlK5N3elStQapRdRVIP8hQ0huaNirZ'\n    b'u6sBmN5NW8wn5kvaoqNFjZgn77qrpQeIFrXXInn3eFw/o62hZ8IU7Z2M0Qv3LREDiNQOJK'\n    b'vXQZEej8mQoT9th+NZO0TxyYCL+ukInW4UZFS14AO1SrX3Jnk36ByH4DIyMjMHO/jMzJfq'\n    b'MEsDhNLI0VCJyIAEUiopfEt7xzj2zk2XU9T0d9GQxPrzbdufT9GgMPWgrwuaWSZ/Y02eJ3'\n    b'+L5nZp8rdQ+VaWkPaJucrfok6uTv42mog1yd+ijEP4kpx58ndG2SR/V0NNkfz976E/WiZ/'\n    b'X99DZ3/uoxF+AtjV1Nx8q8JEqDd7qhkZYwUmB/byYoqG7OuuvwX63cnibJH8XQa0Gt8yoO'\n    b'UlKJ9v0JT/Ho9fZKuWgX7i7/FYPwUQLU2skr9vdTKh0/19q9UBhOgHI0gSjz0QU8+WUGx/'\n    b'jwoFJTAgF5SXemIhmYEhH066cZUEfEE2yc8syEXyM3s9aIU//4yuEtXlZ6815DN87+83Jq'\n    b'fh3OdavsR3yDVyJNdSS8STlByRjPISnlz/szJfgWNp8VoGUoZiqH8/969RViOG35kMcOJs'\n    b'RBqibJwnP0fZCI9+gol2Y79l3IBnya9F8gvza5n8oip+mfxihVqVUD7tt0yJVwRchW+TX0'\n    b'ImZckvekjEGPeLSjJ0nV+iejSdJr9EMkMGEQvfVHGMioqq/cuFhbVI3lPWNnlvynaevPdl'\n    b'Os2T974coS++D+WIye77IGJuibgc0dG8j8uRnqKkTA0tHsrkPSv4rnuk69kyeY+yEBW2Tt'\n    b'6bQmvwGxUa4tGFBv3ofZQBSNjwqnMI8UiOgOmXJJep+5Y5AQCTQ8vkA3NolXzARD8tMvxK'\n    b'qc+TD37AX+buWwIAACXpGM1y0I048Nbwi+C8ioAS+eBzH7J9YK7Bw8aPCTPIE8pgaglRG5'\n    b'YR4KsW6t2HmysAy1oz/LxzmWlUD8Vx8JLgCPXzKWgAH3T/jXRhfPKVrJgYUlSXBcigutDv'\n    b'rXxSsEROTCkjCMiMz1JUDQCnajBhkaqxAhD1zwXoPeodVNIPkQ7Skj6yUDBImU/J3LmllR'\n    b'BtZiHJ0IWlo6x0IfrsahmsVlVtHvWMEcFdKTzwLroNeugP8WICa2u8mMDA9t3T2iWOn7rb'\n    b'd1w/LmCKbejjcDnoalzNLX7uzzutF1ULh3v1BrV031vx8pkQwqZz3VrhQjV6CCNKFtuGJc'\n    b'J+CXy7FQn0rh9c3zxhZTbfMqVtHSDFTRe+D0CUduDXzrX6WJH2vUThvn0GM8sNoOYxU+9B'\n    b'4iuSX+EZWf+rFMw0+TU0X/B111iUya+R0rwCHaldcwA3p7hzeLXr2/ywCsMccRkI8fevR1'\n    b'3P8+RXnf9Qtn49Gac1P3QmkOOSg+//ZnLS5L9DEsrkv6OQwBT3afKR7rPkY6R7LkD7bmCa'\n    b'fPS9XVHjW8Ya5MXHEEsFIhpVyFb9RzoBqXOyNrRvkMU8kKIiFJAj1s4QiJqjgL0dmCdIRt'\n    b'jbKlcLknFrTJFEPRoVbfIxyhXwJVf8tw8E/ut0hJ0uLx2tXMBryuQTczFPPq24YzeZYHqP'\n    b'/hJU5qh0Sir31ITU1FM1qcJRufFXOiozVOV5JpTa+zO8mXdJnoncxM4YUpElI+VdlimozL'\n    b'ssycu8SxQaKC81OltQXuqS6cu81IUJxUtdVKS81MWSlJe6oJyZl7poQOXisiUlLlekxOWc'\n    b'lJe6YPqmIvWMlJe6pNRTL3XJtE+91IWhvNQlZZl6qUtKPfWylCyHqZelNPF5WUrmxFRkYe'\n    b'yFl6Wgv0JykPlZSA4yzwrJQaa9EFmQPmll/ls3EYqw3r/0vsvHAPTJN8XSf0ceSgdKS0BB'\n    b'qAaLzH7YvvITvb/51OsBtYVubaNDutDSa0vIXJTlGzX9jDU6kmtiaN/2WOU8GTmDt7gzhf'\n    b'jR+jzSF2+AVgT05AxBbB9iCIUVzdcQ+zZy0SB5236vlk6Rov7JrLTOUYD9nyIAqkHUa4A7'\n    b'PJ7Ha3DwLn0JXJwZlszn5slndhbT5POaSiyGgM92wQ6p+yzFCzQUHDLsc8j/mSVirR49/+'\n    b'e4/6WnKHfnhpZCWCSfow1iOL+5+Tunw1AEiL07n6KNW8i6dbv3NT7d0LbgJ/WxCRQp8ymD'\n    b'Lmlkh4SJqNWgXJIfzwyh4n/WvTemB5+jcoAIesERk97PUEgee6OwNwtDnXrW1npqiPPrQC'\n    b'Gr5POxg47h1WhiCDtKH5Sxz6d4Z7EB4gsY4b12O7XkD+brIFSafGFxF8kXmY7M3bfkBwA/'\n    b'uUCxfJHJRY5vKfa5JcJEotGA1INSoxID3aoUIWCl6aPufNEj9RSk0vQXgfQ+llXAJOYsYJ'\n    b'KCmcKU2cAkwC7WlMm5NtUpAihpoTxKk4e0MnuYuW9xC0Cr9JiefPGThJX99Gofpn9fRpME'\n    b'iqknCVB0v4wnCegqvkSThBZ0PElg9mpIZwTy7EpTgYxab6wgmGQIGvGX6zXS1oNK1a3oUj'\n    b'cRZKWo7Cwr2SacF55I2T8Jy+QM03p6298PO+nAcnEgi6lN6jG9ntqMwRuBTb2bwIuEkPkI'\n    b'0mhNnVI0/i/jheQJMd8ikR7MG9bcJdb9WBvga+MTlJGfv2MY+hLNJCoPSFWfJv9goy6Tf4'\n    b'T22ST/UHUHU5N/RBOFDHS02gEHrsdpwIuKCuFG2yd18g9JHHi+rmFK90+KUSX/9KLWWfLP'\n    b'INLCEjJSQ+5/qipSk1QjBKZq/1RJqOvkn77q15Pkn5GIiFNEqpL/oRh18j8h6mXyPzqmBU'\n    b'gd0zz5n2ikz+Ges5tZm/xPFA8ClXjq5DfGM0t+k6506b6lwRPQpY6x5bcgVWuJkCFl8luo'\n    b'sSljuOpuVsC06K2hpY+YJr9hHqA714bI5Va3h+B9hqLl/+aLP7efvktZQSi9wzEtQOu6Xo'\n    b'GOhkfonL9FuYYsklzDt68wFOByuu+fdAbNHXbLYGJB3q4/n3e6LkNREfiWrzr5F8tpnvwr'\n    b'Mq8qQfsRZ5aIGVa1dN8y/K8ASJE5whVZ2s4myb/sonPVmC9ReBztS2aWJf+KWmAF+ub2RE'\n    b'3GDa23BW7VGoi+7XRa5gTGO2qLlKiO0vi7Gafl3Ih0kfxLazqzafKvqGgRsxQtv/2uVFMk'\n    b'tEmEvrFe33cYbXZoTzM06bVvLC1Zm+4rnM0mxJ8uv6+P6zPczWtLH/eXZ65RzA1/v0Z3qc'\n    b'C8BXi8yML5JAf9dYD2QwU4RNq0Gncx5hGooqbre2Zlb87D7NfHZ121VxFXBYhhVScUyb8f'\n    b'Xob98Dj8kNN+ay2G2Ln7FkvnlQN0vqcO03ZLlcPEENs7igySfPBipgJRZAsZiZO6vJxYQl'\n    b'Q4TEXWNwyxC41qq+SlZoghdqXRyBB5pjlict0kvkZAczefJoKH/T2qelpZyFKT1FFDRLoS'\n    b'KJx3LtkMXCRBYzUABm0XwJQ+Qi7nyAG9pgzuZrN+VnWsIuTqKPJB6aFQ9G7OTfMAB70Rgu'\n    b'iMSw0ZlidBmxaBWh4WF5G73fNw7FDvcq7srrvgAZE89v2EO/g/QOzCkvVsmtL4aGrIdII+'\n    b'yFqqe7K2xs6enFlFwJHZxFrJeDK11p+ezOyevCdzu7ftyantXjxZ2A7Ok6XdhPdkZbfaPV'\n    b'nbzVpPzqwpnCPzibVj82RqzdY8mdmNAk/mdg3Uk1NrU+bJwhqLebK000xPVnYm4snaWgZ6'\n    b'cma3Wh05ndiJmCdTa9LsycxO/T2Z22m/J6fWLsaThR2kPVnaGbsnK2vw5snaGo94cmZtTB'\n    b'xZTKwxkidTayDrycxaH3kyt1aWnpxao1VPFtZaxJOlHeg9Wdk9fk/WdlPUkzO73ebIcmKn'\n    b'qJ5M7Ua0JzOrLnsyp8WNSFVOSYpUZeEarSMpVS4FWlKqXNJbUqpc0ltSqlxCrihVLiFXlK'\n    b'qQoCpKlUvyK+ZVLsmvmFe5JL8yUknyKyOVJL8yUknyKyOVJL8yUkn51kYqyY2aUuVSvjWl'\n    b'mkrya0o1FZlrSjWV5NeUairJrynVVJJfU6qpJL+mVFNJb02pppLeGaWaSnpnlGoq6Z0ZqS'\n    b'S9MyOVpHdmpJL0zoxUkt6ZkUrSOzNSSXpnlGomCZxRqsInEADJXEhTglMhKVVRCEmpilJI'\n    b'SlVUQlKqohaSUhUzISlVMReSUhWNkEYqn8A0NVL5FKWmdU9WQpZ2DuDJyppoerK2xjmORM'\n    b'ai8ovMJmMLCcpkbCnJNxlbBZIRVT75NbpNBFUJaUL26a2NVEub3gy5nE1cg8y5MDxx4mO4'\n    b'JWHLrqhyVs6ynAsJ4UvXrkGyVpTlRMicZCrklGQmZEEyF7IkORWyIlkIyYjKUsgZycqRU9'\n    b'aKsqyFNELOhKQYbnAhyZDdeEGSQWVeyCmLsswyIRlUlgvJBGZTIRlyVgjJBGalkExgJkKm'\n    b'TGAmQnKYLjMRksN0mc2FNFKJzJmRaiGkkWoppJGqFdJIJQnkMF3mEyEpVS7p5TBd5pJeDt'\n    b'NlLunlMF3mkl4O02Uu6eUwXeaSXg7TZS7p5TBd5pJeDtNlLunNjVSSXo6t5VSE5NhaTkVI'\n    b'jq3lVITk2FpORUiOreVUhGTrK6ciJOt5ORUh2dzKqUjFwbScilSFEUOkKowYUgqFEUNKoT'\n    b'BiSCkURgwphcKIIaXAwbQsJIEcTMtCEsjBtCwkgZURw+dkwZ6qnE+FZFBVKySDqkshGdSs'\n    b'FpIJnHsxClOfq5mQTFEtjk19nqVCMkXNXEgGtfRCFqYElz6fUQ+ohXrHJUuhaLyQJRNYLH'\n    b'yRoZ2DXE6EpONlKmRJMhOyIhn8MqjlVMgZSRGDWVcsSyFTkpWQGclayJzkTEgjlSShMlI1'\n    b'QhqpFkIaqZZCGqkkvZWRymd7ySG+aCW97EWLVtLLIb5oJb0c4otW0sshvmglvRzii1bSyy'\n    b'G+aCW9HOKLVtLL/rloJb0c4otW0jszUkl60T+vmiyQBUmf/Ap97KqZBpJc6UUrdm7FaiIk'\n    b'xVilQlKMlU9ghQ5q1Ug3UnGYKJqpkExvE7imIpVCMqJGxOAwUTS1kIyoqYRkehsvVc1hom'\n    b'gyIVkKTSokS6HJhaRUi+CYUi2CYyPGTEgjhq8bdW7i9XWjnpqIVkIyooWXasZONXN+yzRD'\n    b'B5WlTicHiSLLUjdBK9McXVCWujlXmRY04p9kCyGnJJdCFiRbR7LRYSh3jvO0NCOsczydcS'\n    b'qUUWa/kcHqqldniiRanAG57Y/rp/Vh/UPOk7jraNoPifuwMsL5Sa+XRiBU76bYnKrGR5UR'\n    b'dK9iNp5V1MbDeF2IXTpvUlnfMwwz0PSHRyA7h61ogQ4M/517jTZE990mAhcER7ZUTNKNlS'\n    b'aqVP14pWkagSoxdP28PuOvybd5Fsjtevf42m/O2x9WKy5ByDoAR5Fd9+i6THxJMqldgN6s'\n    b'n7rT1iwGvrJpWVdx6uvWgNv1/tvalFIIJB9xRh6ngW0WM4LHYsQZeawt24olwu/WyGyR1a'\n    b'VtzzWYkVjZiDMK3bOfT5fjWnxxLA9w7GU10bxxRVjlmjuqECubCS8oqpDPmc3SP7hIeQqo'\n    b'SdHLFg2Vfdxu1/1xWe9+yDJqDu64PXsdfdx+DlY4bg+mXm6lHrR/6Y6n9WHzAxdWAqmdTR'\n    b'TuV2eN22BPjyw7qFbIHD48aWBK4Hm7PjxvL+ftGhWWRlHAuHaYcVWFn/fH9cNzdza2uJgt'\n    b'1FeoN5lHxnEiq7jmCiN6ml3DytfUxWSiyPLMuba+QRuZuOxsrDDRgg/DGY575m2NNnG4bN'\n    b'bns1/Eo2J1uJy+sjTDYm0A/VpfQHS/BzRcdoACfVmj2ML684TIsTv8kPFAwPploFgv0Uo9'\n    b's1Bwu0rJ/v7lBbm6qlcrfh6H9cO2OyGXqSSS/lPqTa2B4Yi+74nFwWQZnJ1ht3sT9xDyuO'\n    b'7UQiLbPpEAoJ8/PiAnuRJocpWdj9nbTNvZnJi50YF6RnSjQ2NpOXmNqnk8Dq/3w5n1fTa1'\n    b'5GZ92m6GV9oeUI/xkC1NXmQhkCtRXm8i2OWFgAt5c79zgS+ngriwl7kgLujlRBAf8jITyA'\n    b'S89AHbMGZ5IF0gs1mAfChUqD32uu2RGRDRuUNZb4i79ecioAzQoVlATZgOzgN8eXGYS+cW'\n    b'Jf2t+xM1hPocES/fJJBIlUq2Q9x+TMYrWARHB3r0qeH6gsclNQ6TFGeKjgJdKQYE//r2Q1'\n    b'bNWgUyKierT4zBJSqXmWfeCmSrxFQQqREuH02hzVJPbEyhFYG8PzHIeS0ISuJ+PQJ9zpUa'\n    b'GB5dHVhIcJL4yiMis0OMTmAKBWGdHvrebm5wr7HVQLRf5jjeTLjStHZogzj2LzRg4+zQEv'\n    b'5Yhmnx9gio0rxSh2mtYoxp1YLLJife8HZ65mgyF2q9456JjKRUDT3nBoY+B60yS0No0WAU'\n    b'gnVjUcuFIAuh0zYKo5ivrkq2pdPb/uU8mCFAdWZoIWcesEAV9/nHPuUcGYaTKfGgjwo5Bs'\n    b'5F6aFTkmrAI9vroeRptdPSQe0kvUNQ5y33B0OgnF5ervRRdPCXW9pihHttMQK1tgjGV2rk'\n    b'Wz9Icdk4ugqH2frWH9wM8o0KD4sxqCMTg4oWBlf33KPFjxoNoYDcYyT2RvKFIqOaTNxJkv'\n    b'FbyTq3tOSA4auKWk1In51aAb3gXivCS3KPbBz0doxaBRBVZhiD78N2ZprcRxeb5IaW8Qlu'\n    b'O+pyp/7PcwcnWyoKGGXLEoF2D+sLO4ospzO9RYhQaRriNdGaZKxLohMGNtYhZ8ajSvOM9E'\n    b'iXRM9qwG4/8r6YrYRzGnYY1DfCmhgZDsMQT2oWaJH3nc5HxqjtMljQ3dmur9xbU4LGQOuR'\n    b'FRQTdLYzCc4h0kCGiYUBg0JvSGjZobahJt9vdb1akvY1xhC6yjgg1BkC9nh7gZLsdVaS1g'\n    b'klvUMurHcPKDVzIh551B82eq4Ine6+V+YCTMEONdtXIJ6SNwBKCHVuQ6R0CAaHl6E/nKHv'\n    b'QEF1SjBn+YbNEcSzzW93pOfpNVd5xqzfscF5uKAYY106/d/4WqtuvuPO69dp+r850CH55P'\n    b'CWO8aipEU/G3jGo2ZmlnnsHs4em7vAjNvrzGnmN9g6a13Om57cFZm5u8Ch/Q7uH9kpZKXP'\n    b'geDMZd3pjG4kK9nySZrb98bpmireVbqCRyehEUeLOR270EyTLYdn9E0Zs09fU1SBHlBTsw'\n    b'JT4/toigdfwz1XNXrXP6ZI9aCrP7J20NUftMw70Gr+CLM8RIuy7oyWgnmrIey5yUnVBPL+'\n    b'TH4egH2/IZIpRPfCyqsfajV2fqHnNAC6klUWtrUTYiwVbeVoFeIE0Y4iSTRDRFko0MqiES'\n    b'1MnehGh8Gu0YAVZ6Ihq++tNBQNipF/E3fbJlGDRCTLCLGxNBFmC2weYVE8cRA2keju3frU'\n    b'sk7CVRvW8iVrLeQMaUpLycKWcriKWc4OJ43RzXCBwm55JXn95imKbu6wGzHk5GECcbCj/B'\n    b'yyiNlYjdzWuiCchiu5UEEvuh3A40W3A9KY/p251Jm5bxM/R3au9VtoQPCYtx+pss4Mdure'\n    b'TJfcJg/Uh/LkQVsKloDVOIY58YPc01fh2yuNxLXSaOmgNJLehWPeNcjDhoP3YaP00jrVuM'\n    b'v9icb8GkXkUC9TkPFysv0Lj0M+IMbh0a4lO0uwbFHZT11mCwu5KmIo9GZP3bGjEg3/Dfzr'\n    b'pVskQe6kW+JbriLEFOlhfBXhDJDoapklwr2D5F6OO472iMRdQdiYr3AFIenQucGdRNjUnn'\n    b'BpgQDGE5dV+dU/cXGHeZBb+vDoK9lyZRDdvtqJgYbd5nR+49JM5YLRdRNuotM/0PAetMIz'\n    b'a0j72mEIXT0cEOoHAZ27U9C3b1NckvPwzLkHJtxpbsjAn1YE/vfLFVeRE82xnm+YCxdkaC'\n    b'vpykR8+3LFBVnfv1yRWUUDa1bDbd9deEbKVA6/LpVVgWMGN2Gkwhj5KGeeEZbL5x6Kw2B1'\n    b'2w4ImlM4M8hO5h7xQG2BPjhxnobOA0yku/EQrhnPVSpKh4/S4OBxClwoQX4HjKR36GUUKM'\n    b'QRXbZx3/vL7ty/7N7Q2c0qh6FxgZo56mV34VrjrPD0AL1pZ+pWjs7dobxTnWMalw+MysMe'\n    b'daKYsnQo3DTRTTxblMnofJBrqkuFu74HjW3XUXkzDZk6/Xr3tcM8iOPAIrPQhnfW7whMLM'\n    b'Bp0tEiqUXkMBUx1Nbd5Z4TPvt1uvRnJ6yG3DIPbUoe9g/omUOXM0eTjHQ1+HJr6soRpNHH'\n    b'JdgdD+ZoywQjn/nc88TX+vjGbfJUIAk2dc64AqCciH5TWNqqmlTome12xXCZjnkOp1Dmsj'\n    b'buEdqTedxIceNLriBTkA4vEn2Ib1UuvEM/H574wNQS99JCqodtUwtFy0LOp78NT4szjVlu'\n    b'ndyFK9ngkqS75MxCds1HhxgxXHgNsRd0XZxDUJrD0/HCdJp1c75NMFyOnLA8Hc36E1Qo82'\n    b'DBAILG5o6YL3h5ETQqRzct78ChZuBoHsZmk7XkYs5rVNJA88Q7R09LLhcp2WmgM9JZoHPS'\n    b'eaCnpKdCm9irldA/89JRKhCWbnnhDNQeT77nAf1JIfQHngadSHDtJ15VzKHJ0Z952XJaBZ'\n    b'pnbUJmrHidoSlaSzLtqZA/GlLS+pOJS2T52fide/L9nPmaimgfjWcpg0+8b20i6fzEq1cm'\n    b'gWvTIdn2ycop2frpi0mHRPbpN1MqUohfTGQS+j9MaMwF9/QGFYtZIE/rw4m6voZQKR+pXR'\n    b'BDrRtN700ejeBoaTa75utdsTRmy2ba8gYehZvfcKADNvG+DEd7vsF3aqZCBdWL5Q9Pz08B'\n    b'QtbJJBTFcLx863p7FyZChALQnalWcGkGnqHpvXELM6ONvqGMOk4F/HJEIA9vzGDUwrejuV'\n    b'Ob+ZiSWrEvX9H0CMS9ZxmHj45VJNwaLafJJlLiSavFqBLkJtgIGNItTZnveImvaYmNl/ig'\n    b'RAEd2wtMErdyZsxAomUzjzxxDWSSTdy32bmZZClJtSJWGjosiJFW05+S3tX0x0S8CyuVFG'\n    b'5nl/ty+xlW9CIgrOk5eItA7f628XxnLGVGnLDyd8U/dU88Nek46Zgz8un5AXVAf+z/EFdT'\n    b'BY4C8CxoB3sBZwocuXesOH2VAkfuHctu7Qtaa3Tkw/Mu9xflo9HoyIfjxTlXKnDk3rO2ps'\n    b'o6cKLAkXvHYqfUCVgocOTesOImMJ8D00P/dGUBbQbisfP6MNpCmi4CJ8IOvApuZprn8SnI'\n    b'Pa8sYPrFCMRM4+XQcZdFjvKYQX5aQ+r7nb8/lfWIy2/XRgrzWwy9KrQcO5DetbnJ0X5b4+'\n    b'LIecP10or1rvZv0XN5RG1Sc1vb54tJ05NPUymUU5RXBLSOsiCAGLnayKNBlaLd8ovJGLMx'\n    b'GzATzsux33ujBJNJPmFcf8k4OiqMnpWGNWHC1c4MWtl9GBzQImShAFGpy+vR/MOqQG6J0W'\n    b'3kRP3l9XAedeOG9h23IXQP6oDQhRog9JGYtW3GFb2pIfpmIxP3Ajm6ifYxskSxM0vpWD0S'\n    b'oiWid6YaQ8tiMOqbfQrm1L2szdJU2GVtrni06zFjmmOqvSrUpo6bOFwQQZPvtn1oOktDh9'\n    b'EDFUPfQoJS0XtHC7LROYjZTeNosbspCdg9pKn9lCsDa8Z1GPbIVsiLn8sJXcHhsrfrbiEr'\n    b'V8j/jvdkZxjr40yuEpXHhtBZ7ICQwwTcZhE+MR6/nblD5E/rFyPMnQacJrLXwxMFjogmgS'\n    b'i6cOZvXifx1RNoklUS3TzhWvpUUNc8gk9pzAGK5NSFxNh1qZA+nwc3OYfaven5JhtEW1Xu'\n    b'm3P5zDL4wpLdxs0y6NGb6D7EAmE9n7ZmUayYwUO0P4HqEJYqobFtwj30aEPRHBhJPchmBg'\n    b'guomzWfokE3cKAmuW3MsjXCURb01sZC9I7M82fMA/Nt55I5g6LZpLeoVquE89iCuBD1tNF'\n    b'Ojo8UUdF9R7U3iBrd1h4zJazQLryrBLfgl2J5wEYFKISt2IkGGxOvDgtzVNP/c4rUluh7G'\n    b'KZq80mQ8/OwGJRkOCavCzzoHMyK/Fvw8YqNMYSO8ZEvzOc1wMS8qyP2LaCurUCRCOqPLzo'\n    b'HEMSzuveLNMii8LSPOTQS/MctvTSPCU3r2kgT75ZzYCNnpQcTS5J2CXgOZ3ffmcjJUdXYz'\n    b'qNVj+LVcIGARE6OWo+w/eReciTJJ1abIdbveS6SDq5ox7+7fq6X29fekCvtQt4ZchRXHG0'\n    b'NYfhuhbV4Hv0uAeD1UutTM3D9i2+Z6GuAMrgObVEOM0914C8+LHSqIyxM43q2zErzZAXP1'\n    b'KNRtde5pojb3tQelVCEFUfuwbX5zGk02eskTPuSY8q6aInPSwtR+Mhf6f3+hFOd2WHAz/6'\n    b'3Q/0XJ1YuNf4VsUK/1H2w2u0No/y0YZX8B2dwYfckY07gnOrBnltP8MI74BQKdvWIlK0jD'\n    b'0AbkeLSw52jSGrZql14HKxdAF0mEj7MKpUMN+2MdoIxAa+YXufWUzlhRdH5aSPYIs+4yoh'\n    b'XFT/th0uyJfMQzS1sdY3HFMbi2KwGpD/L9verRzkWeZSKl1+NqldGNECqcNUh+/z1Seucp'\n    b'FIyuqVAE59Wjkv/m6sykUu/V02qZwTbwBNcnwWgL5u3DqCzNVmeHUgI+N+1MHn4YBc1JcO'\n    b'GNCf/AehX4nJkbBdt7frlFArOvNkTKgrc4dIRrQekDLOHCIJp59d/8JGl9Go3FMyscky1o'\n    b'KgA+SekLdoKo/IWzTIAP0WTY6+db8xygiXK+23njmhgkZ6Bf2/cAA4je/gaMg5v506kwVw'\n    b'F1myQzY9YmA21x18vLn71vFmxG5dNEfH5g2chh86CkY5ehSH0PhOeRTOwSbHPGHZhRdy0M'\n    b'qGUMKIyN5OmzFp/HzYDSe7WDa3QHgzBoN+DInboo0ZXiFGBvjKMJ/g21+0hVl+F99qhUmC'\n    b'NbZEP+U+o2bnMNGpSkerBrMg1H/FvP3AdGclivWo8w5+dC5PIZFOXB1I7Qox671IjuK3n/'\n    b'xBBnLpLatzfjh9oi5JDEffQUIrtfTVoG0cegF2w/DCq9nmBKkbnpWk7D2vDHArh+mWP8ai'\n    b'1VgGfTZG+xseX6BcSttCZtoZVsUPNRzVpKXU4Ms8VbRCXsqtL0v3LUM8cuaM2M/rxwH9jE'\n    b'wMOXYoPFpvCbwb0LVLP/9bIu6LVG/WAHkVqbtlB1sp2BeExrTeBPzPB7PSxwVT+637hoXD'\n    b'7JpqLiTNuyfcSgu03KnvwWhS4UE5P0MAUzXaDpgeEbMvO3dlf6reeFoZyla8mXGjH3yaEb'\n    b'AqdNrMk0dqqmXyKKsNLb7VUGBoBHDYdj1XhyYz0OetWoVrLRCtwjksWmtrkke9PlMnj0F1'\n    b'LJLH6MWpVfKobF7R2B4jbQjN6XFsBLvMiI1XyJc50dEKOTTVR730gNgxdlASHvt+fMRMZc'\n    b'Lfnh8I4HHHD3gyAITpHyPVBtqIg0SzyQSRQQ8y0xq080MBnex2GMeHP63JoCVpw2jNF036'\n    b'nteP9iCwp8Ia+hgLy+iBE5ZVAxYWkud2sThmKC8xWxZ753ZFN8JHvhx33+3tyWRPBWcOO1'\n    b'wO9nSyp4ILh7109giyI4LxuIP4ikxvzyEHOrgiejydzRVMqB7diToTpvmPPeS2Vlck4kfL'\n    b'GLRRy/PCfAUd09JKV24MEOrCVNE3NOW6NXyvKFvfVkeF7pMWSwNo7bdxSFB+LRLrvoXDgu'\n    b'prkVs6rhVRq7jWbTTUWkgruBYRta62pKi3C0977da6Fx3PxqqHauvAq7agTDtDu+DBMvMm'\n    b'Eb4jlQxtKBwhxFThcXgUexl2GsOjX/eBqvAIXXAv7CnZR3alvM474XPYLN+p+Qr5aGlVvn'\n    b'MDhPLNFX2rfJeG78vX+tbF6ZFQnBaJi3PqsFCcFrlVnFYiXZzWbVScFrq1BFoZji5o61YK'\n    b'2joIBd142he0dS8FbeXRBW0dxH3mUjDpNNMASa9ZWMzVERfQdtSaIZEomAjkuH7g3jFP9k'\n    b'xJHR449ucJTxFiKvukTeRI+gOFBb69tRzxcLZ5viIZL9NjaH3iod5owGlmU6LxgNPMGLI2'\n    b'vasMHSzvSGs1bgFaq3Ck7UuHTW4/dwjJKRCYMDlQ3cHfTgDF7x82iZ5DTJYg/VITkifqA2'\n    b'RRzyEi5DBMl5YIzyEijNFziHDvnkNMzVfggI72CuBSL2EUGWiV5ob0sOcOV3QIq2A4x45v'\n    b'ZjDkoAAuHC7IKnfI/vLHRu3CzpbEUVl5kpCXpq5II8A33nkeB9oGVggXRQzt162BY0r3FB'\n    b'ld1qT1M49VZhBXsQxb1wUHhMpgAH1/wNwCoxsEWote3SGwsvhY50F9+N5bkwVZ10+KMWE3'\n    b'3ppE/m/D5tTcUFphJGInfiXjVE8UIkC9uQAt8UlvLsxJa12a1brfdzt7A4v5DNpPBATVx8'\n    b'FBiwAQbzsg0N1wxvRBXq6QK0NbzzqdOfHK2JgDoF6/gDKnGO6s7ERjaqLG/L1mOE/pLZ5u'\n    b'x5EIXtRsnl7DKso5Uh3e+ITbaBRFC9d7IOhVn/QeSANautOM38G0EI3syOsl7eJPlfjlSx'\n    b'Y1P/WyfpnojWLnwN+c6UhfjXJLhpszWwtEcjs/6jZNIh2NLjmUt57wXQWUIo0MR25vAF82'\n    b'Ho+GSPE/HGUJgcms8sBwIVSVQF9VfILKAgUkkEO0mIc+hUdSwdEbFgWScuEEYD/4syDzJk'\n    b'De5qux2Kk/PLlz5pN8FiC3OUo7zye9/dEw9ON6HzaY2Mu8hf3xWcL5O6b129uPrs7IiA0q'\n    b'UHV1v9fQyU177jwJJ0bpSN91a+lwoy5pddhxSXJkBpIRG/d689ygYf9nRXrUB86nAPuz2m'\n    b'WbJ9vIgmmlaL1MUtPhDrqkXs2ncLymRKRNLRBbqWTpnTFLCSw9K7bcheXGE2vLahXr2mNj'\n    b'udFFKKlgz+vTcRQeqlnEvQ7Spep0eb6MWAVznja9ZqJ65MoKM/Tqyd0pM+v4MgzmEoP79f'\n    b'HenJtvFh62p448vqBIoSbSs7L+ajJFm5udIiTLr5DHMRJs3zR6cJcd3OJRGLTi20zUie6K'\n    b'I3NqU9sFSO+voKy+gvLpFRQiiOCx0BHzSuqIG4vtWN7eq0kVbS7MipBsOkbyyRgJYWt0LL'\n    b'DmXcmrmbG44LhHnKtEb4NN0K7iN53RItSbzuhOgvZaWSK86VwkW/2mM/jRm865oSVkuO7s'\n    b'bW+8UOXMfaTCfkZ2/AoTGw6I3wXNZSpUUFuIbW90sHoVrCIpeo3xYbtG7W3VzCvNOb8O0v'\n    b'9h7rkdL5tZ7Dv3LTXzIuaOj4I3cyOG741HgtSaJxE2Bg2H6Iwr11OPApgplvhHNwI5OhRc'\n    b'6DUqBqpP4tWKjjryJRmXc3Rve14CPIjWyvw7XtQwwVHJ2rGSpSxFQXpPpf3Ur6Ch+Prucn'\n    b'2uqHH46PCMg8cncpYWDidyWguMTuTQmc5V9EvRCXVNRxnCaK2hK/Q+85lOFZGlmtgoIrRO'\n    b'B4zbuoOvmrnD4xYOMLrmH/kZ6X4oUH2mpcKgAR32xS0MsNlHJ5RJ6+RrOko+ctPZ7VIX4W'\n    b'c6U0RWKiLPFBFEd8A4+Q6+Sr7D4+QTPAzP24s3VMoomNvQ9zrzzEAPmnjhQgAUsG+xnWdq'\n    b'mHL4SLMysoJd/ZS0fop+ZuhvA482ObPLgpA7lclqOpxPL7x5ydxdwYIxN1fw0NRW5g3oPH'\n    b'VbQHHJPSjsIqNjtKT7Xl1klcN3dLC2UHRUfOgMoseFsuUyQlxmQeivXE9EOG8vW+508mpC'\n    b'+62tuzw/2ojxDkWpzz2gdspKh/EdrYzHXXrq07OkFxOgJb+VlrRK1KWEdZVoe42MpFucga'\n    b'C9vB+FcMOAVid9bHDTJvpdlKJMem3lAmH86qExRnIB5Vm9CpzH/tgFRpOoBUea3GJW0PmF'\n    b'x3yluWQLZx5xkCsqUIwpmsnNY5oSlhFqjorlPC8zRs2sZ7WC6hlxuO1/vuzMoRERo4rdHL'\n    b'm3EuTINdfkiCypRikzzxmjwp9CypcR/8+Hbse5ogQ9i/iP3GHFbNL7xqxVczHgHh54c4j4'\n    b'Lm/yJfIR+yhiZVFxbddfg8BZxIH+HbIhysieBxj9syMsgKiwduiOjkHO+oon8cUsFFmILy'\n    b'oU9kvCiRLGYf+B9uHCnsXsc8gSdJaaNYQqkEU18bDehyyJ0u0WnHOaSWiYx+9CgqNoMPI+'\n    b'SI2Z5jHrBVolaoRENovZJ24hBFHicJXpFVId5eSpe+A5JhFoFjN3jyJPlIzT8NB35zeJLx'\n    b'LW9nN8kjNGu6jSRfXgdB4enoWVxqzLJkQUVcjTJbTMOC72o191+1po9itXVKRAY9YwbIQT'\n    b'Nbpv3XFgolRtM1Um9G0q01ljAkNVGVaYkNuqxiAtAVeJMbKGoJSwFDUwjKzWFIQSKovDVS'\n    b'C9bVOmMG2KyjJRlpLI7KsnmKCiRvfZshw7jo9jpdTjI6XUwWOltLJwUEodMFJKgYp9I7JC'\n    b'2zeSpcwlQeqVYeR0ZNSJeq4HS7QJPdCxt5Hs5LeOyNIhJtJXhpkowSuzOmRnP35Wj+345r'\n    b'27E417E5II1DYkYPxOC2y0Q73+PU1uqujQ5ftgzAI/5ua5bIkc3V3ewgEL0GIgx6Hg+l3E'\n    b'PDH3dQ7Hm3d1FoY9euIKVS/Sw5EBB/RB3vwPXfbB7IHxfH+KJnXQL7WVkEIdDQrU/cBDBD'\n    b'zFkQbsHNP2CppCaC7Jw8EkAIo+ome0e35ZRhHPfbgVlUF89Rez8BYWkGLAvqTrr7zPqQu3'\n    b'OfX6ofgCIonhHJviYE2iZuZLve+4mEeIt45i9wDYbNhR+7X+xHYKAYrSjApw1JWVJX9l4p'\n    b'U7TNecMRaZeCHBp9N2rfd8IalsJRi+0mTRNXklQEU7U7A+UkDYvRPJjI8svtgjRzccwsFF'\n    b'q8CoL7eeS1slV20p15heQAb+bdufT5H5RuFBOaymmFXyO1XzefJ7dHdKClrt4i1A+i07fu'\n    b'sdO0uHDTvQ2tZ6kvzu9fUVv0Vfn1lCFqDQGf+OJno6df5MA3L5d3cMQ8qnWCXxBlYNutuH'\n    b'tdmFoUdXArYGvLoTcGXg8bo4pFQLTTNGsB2dSWuS36NdziVpn0GG0DnkgJBFBOKrWxAgWk'\n    b'3Oo/6/Rz0MCkYaBDJIzyKzhNeEolfByLA+bZ/7yPIyJRwkLEC6ATQnS3fjc9A3nyFsDMOm'\n    b'igE82mcXnpUtABpgZIbVJDcssAw4MlBjpMogyzi5slcz6HjvdkEwvttwCUjneGHokOGkda'\n    b'/BcMfmwVNguhdpFB0NQCUYLy+m15vbz/i+RlRzoG/dcDnsoQfsZbSqUmG8cNXqJaxj1dPA'\n    b'Iif4qYVxOq2hU8TcGbjH4dirDp55cdr2mzUm/EMop4mGUcF69kz2CunYzag3XTHvwjVZlF'\n    b'PvoxST5GrrxBTH9Q76KmGwLAYMtztjjnR8jnKWYX33kiI0o2e92N0mz9EFXjPSzmqD32K1'\n    b'gYnvc+h2UGSxkQbZSnGEGvIcm1dOCai9SZRiZJqh6Sg5kCK+8BM5cGWQvEJ1Ys057NaHDR'\n    b'OaQoF7jnqXkrQeKQoCvmEarq78Dgi13wBqH7E19Ggj0Tq62kmsDDzuIimhthmlq2AFMTOU'\n    b'toIggor7fL38WwtnpGsLY6xtzz0j6NuNh0YaN50Oz1u5uhHTWQMMcqtUYYHL2p8pmeQWeQ'\n    b'2epkT2Fzl1wtjsNVMzpgv647O+uYoZqcw8UDsiZR61OFJzNR3VHuRpfxzGG9WFQfddd9YH'\n    b'JFnEgAMNmXt0Gs/j/C5bzxhllcfH7icOl8zm6GGQUQDe4akfTsExcjMertF565VtDPrP6m'\n    b'QrCn18xxNSFg2IyP3rO55QrpENR05aPa8A4ZBkKdHUkKEF54qOygAVaECXE/IV2TSgw1cp'\n    b'qhkYk3s685KA48Y9U466vSJnOPhDxxwqZSwv+R0SgIhOehLHruIc5CflF4yhzDzrBeMpmH'\n    b'p5eK7pKDXI3a8SZgPqNVBtwmMm5SLZaSuGDKSzB4SWsBPDBeJa77R0mCeRfjat4m09eJPT'\n    b'IuHhgKvnT1YLj3/vnZNVfe1ivPfWrqrI0Y1XT1bzaxfXwcy8o2tW41nfe/kEffmVi+tgbD'\n    b'7IYDkleb8x+kTjvsUwZmYQljsfuDKfQdeKgKBtOTjoVh7wV7Is7L0rAZQbchzrztyMM+ar'\n    b'AG+6GvPJGil9LbHrYWaxMEVzpf6tiN7Q3BcLE/jzrZBMhhlptuOsX65YL8f6fjuxYHdDsG'\n    b'Vde+ZVRAvPuTW1WK7uEPL0zkwnnLtb46tyx5iOT2I7X7RIvd3mnyF3UFuN1RRi1UoQSK/0'\n    b'5MhcpfSQI0pPY4n4lHG+BBqrQvBk7VWhCu60vaqjxWsVSLGsy1Eo3aO9clpf9jY38PiYO5'\n    b'JL67EJDwXxS8zGpoEcjt6gLcuWc4NHNmrW59hALXNo8AuV3UDaOs1CsovFWM3xIYyQvDTR'\n    b'XaCAGKK9QzpAtqH3tS877+Ij4CwermWxfsbjHgC+Xo+RaBe60ZyE7kcJ6NER5aacI7rd1w'\n    b'FKb/+gTPLTgHo7ewXdWFFo8xts7xU8axbr1jEyzC+jU4dTJDGMrEukZ3jYcqvJ7dSCPTxR'\n    b'gbcXimWVpw+DMeNbKFpsNDPeqetwc/VYhuox7MJlnxk6zYF7rJMUw6q/QMfsRZmrdVbttE'\n    b'3ie3UyT/OIEeKAE5Tc8A35YM65oD7JaAwh3QML6RT+/NXlPFm706tBiOMsl3Qgl/1TTBlq'\n    b'01XJsPLEBTMJyK1yyZLvFgtYf4ZMzxMeuENF3Os7WtrEL3hSB7Df+p7n1GFuF3jqyGBlun'\n    b'RIdPVuTtAtHDBUfwkMY9N3wFg6XAFDmkq9Ots4nwoW3yNlcLUFTr/cskOn8UrjPNN/MKdX'\n    b'Nab2Me8oB8LBnGqm1zsaDYZb550Xpq/vnuNYUHQe1eHXjYV9yLUlx2HWc+LQfrh+oPGpwv'\n    b'1rGyyV/rzuMQnRTmcB9rFVBsJQG4u6CnAka+tw733m6Ctpl4aBrirO6CzAUR6nDvfhzh19'\n    b'lbMTMt7W+0HyqwSiDRlaRUeGDEyTPYFIKQ6nN22jwXz4Q60dNQzmePKu0fO7WU+oYAwvrB'\n    b'SgyPUYivDC3VhLlFEYN1ENRtMRVD9tFjdNDe07bKj4e70aCZ13f7UaiXZ+Q6FoW+t3rJ1M'\n    b'HXqtgSzTwBo/SsKqOZojovfb63WMmt77b7HlGLJSr220qaJ1CbF22NOM9LEPOqkig0ZqwK'\n    b'AektSjZsU0cikoFFjhkOfuEWNLwMsIj3sRz4tRhOSs0iokRs/MkQQz0qlrgaKdgsLwzajV'\n    b'oI5wKe9q+SJz+GjxwsHjyfQ0iRcEWXsIvKCK62lzNfF4NMV23uMlQOgrBo0CwPRxHxnAkd'\n    b'YtT9NRuTLmg7mB2iQCn9pcynF9A6FxhgHcTUWVpdwV1hg8SdLoE17xfezvI0tDdh0AA40u'\n    b'iqP8rnuS2S6zQi0QIL5xi0QskX6Can61QDBDevUCQZ2RVgsEKAi9IsAmenNFgMPFEORZQp'\n    b'5hL7oPQ6FGE4SrIkRJjfYp2of5DiwMMiEEqIR7rYEgIcF0DMSFtRM19ZL6D9XRIRWXh23Q'\n    b'g6HLEXDHNkpk/+UxuEZnd/Fr2I0hAg+ZqtccapSKXnNoNR3lF7LkosqPArob0CcT1peLOs'\n    b'FK6Q7KQp1FSyBu0ARPToE09sRzDZiLBkqTUGCP6BXttd18IM1A3Pt78RgzUOU180utkKBw'\n    b'L2qJBFnydd89hfzFFHevnCM1rzEfwSv/y4SqGdrrQWttNUlM2cwBooNfbZlO8e1VLTrRqp'\n    b'alg6pFWp/2mCeH6ByHpqNhtgBDnr9krDMAodDTRN/kMmlA2lYGBXOSHPzEE2PNIUw8MciH'\n    b'c63LpSXiiSc0skM88aSnaFgtDC0ekDPRbYkINroeUdNRCiFa9wr1/w+rTtuH0A+q0kOU6A'\n    b'TsjLRfWjeEXlp3QFhaJ4Aey+toLEK9TZwn5hYae4SJo8VhPJus4ITGIlcLtSuHj8YAB8fv'\n    b'EuSFR+MwUgvHJtN5adEATC0wHoXK2uORBC7Q2GllwXP/3F3OAWZUutyQ29EFipqOyo0ezX'\n    b'qJ1p+Z/Q71GiUKntO/Cc998SucGbe0ml2tDBCOXNeKvnWJV2b4fgJmfeuj6x4JR9ctEh9d'\n    b'nzksHF23yK2j61YifXTduo3WPCykD6hbRA6oLywpZ8YnnvYH1K17OaBuY9UH1K2D+L6yTD'\n    b'A5oF4GSCKbW8ztlCAgsxoCkeLVEDjTW2B5IKPBA6ULXcDMPqgXcCkMvadeIWGPFY3+4KsR'\n    b'BfFEnW1O2nerhtD9qgNCx0oguEdU0WWZiCq6LFPTUWWmxwOGr/UzzcRVD8prWP0NDTlJ34'\n    b'+wlIdB7aiWydUDg21rwaftBUKK02au0NEZ/ZVh3TqGUt2ZsyRkX/MMfGsZdpkF1tUMpDG8'\n    b'8XSmduiNwIrAugqsNbzrRxahmGDU57MA6/5ApWbCRJzVlWwzRfPVJY/4dUAWw1mpSCtFHw'\n    b'ZZL8TkIcL90VcTWL8xj/nZAJknZ69itZ7QQZkoeX3wbtcZU7DSAEdeO2kujK2Ni9Pl3t6p'\n    b'Vk8tidERKiSB1AJs1NYF8+5VT6kQpOiXkFEpOfCrGzvS619vXYF1ofKHTI2uD0WeRteHaj'\n    b'qq6RUZZ72DtLCIX8J0pF7zFChsHxHa37PHejKHE3JFR4cRNEMeIlkl9mIPax3lFFrMMRVq'\n    b'3k0UVmFZAxf8kG/mDh5otPiQee1UkcHsxIDhch2QSh1EqEr5Q2t403pGS9rrGYbQeoYDgp'\n    b'7RJgN1x1Uy+BMU6DSHsOucLZPhfn082jlT4Qlt7jjz4C3j2QbMIByC1iZcZLrjF1NIEF3D'\n    b'mqYe0PILeGUFOrviaFNQw3WHOzJ8ix7ZWkIOd6ymGvALlMtUo0qBXM40w9+JuMw1qk1s0R'\n    b'cN1/emYr6iTSFzCMXr4p3KXqSGlAMmKBGfR4hHGTWvykDqMkDo2oAZ/k2w8Kyun5wn3vqS'\n    b'B/ftt5uc18ng7YtXyDxdHggjMmlB8vQOMgKNDIxXpI8shXlqPyWHG0srQdvcQpKrS0tH+e'\n    b'lC9DnZMtjoqJLJPl7EjFF4uLI+hne9wz1Pbm/XI1khp5CdegkQgos9MNTGIb4wk7kcX5hJ'\n    b'efbeomWCb8zsaNY6s58pH+Yt7bfet08tZOxb5SrIqrLocUAfoq0vG4ufoebqmlUtHe7MYq'\n    b'FaDHtVnkvK09vEcJbpCHG+AKKVIriwSnKaRO+IG1KpyBXpoCFPAnnrbqc52V4/Nl5RKzpo'\n    b'bOgbzIMqU2L2Ni9e5tWQfOx5YzbvW1+Q1Ap1ZYGgTxsgVqdTC+14UR+GqSFWrQ33lmZtUq'\n    b'IVa+My0qsNcutGKJMKrW8bl6JuG3a4Dqp2pFe2jWN36pEym1SL7m3kCjadk2ZGwKvPqSX6'\n    b'Iy+jZA0Vw2v215aQOt0uCakhg+6vTPvpz91tCsFFQ0BRAhWrcGiWNO2iAXmeoVEdN49GXz'\n    b'OViI6Pm/369HDZWaQhct5SIKPgpKhv+n7PNHP01WgAj/5h81XtvuUCKoYyNveeOUz3BmMs'\n    b'WsRFgq0xRRRsWFBboQj0mQboQ4PoQ4X79r0E+w0DqIPybFyRWTdKzT3mwXXPVqh4t3KexE'\n    b'9+TAoBwn7lLGD3u9f11zeCCwE90hjk9DAcO7v3N9w6lNEo2Oe/xvQ43CQvfLZskrys1/uX'\n    b'oDzWBuFZrmATlcGxnmPNQfpetcC3nz4Rf+rMzZ9ZigGBlLnyAoP7SzQPMy7VNIy0XsxOQf'\n    b'dva0wH/CZUxuD0+jaduLPAxkh/9DTNlOzhYRvZQS+YuNFCPMNFxOxOWNHLRKvtTN2xO7gL'\n    b'ajD+Chkf3V/mbWCZ94XRWAWwbxgvAqD7KeUuUnxVXKL3zhSmFHwVhH0BuQmAvnjZpcbfrZ'\n    b'PNFD1Oz0rx7IPJtULsWZVKITpJrcKjNOkIJVFzDapU6VDse8ulQnS6DM6Z5qZ/NPO/DMCp'\n    b'Cyf2Tbmfolt1KUpYkCfl7l+p7GeaamKjiGytiLBF6YDxqXgHX52Kd3h8Kp7gN+UKutmLXp'\n    b'9FQoPCjBLSC6rQhuzNoaj50Qk4uAuXcUynQoVJDrHuW9ilyVF/rN3b2GUORjAzZhHFhxzm'\n    b'ib6wlOGOzlUYKceLE01RGzS0fxPO6FJB1v7ozgs6unnB25yRxMcHKOnRPVDMVm2JoHXMPR'\n    b'TVV3EoRkTGHRUBBNO6b612zxxmhwKqhtxZtFg0aqUO1KfxvcNIBh+LtJfMA2rPqDbYCTUF'\n    b'kphZrzNINY4x8G/6B75NisYxN4milcDJ2O9gYAJw4r3XGe/OflFL50ht9EZQQ9r39obQnb'\n    b'oDQq9OwLw5XPLD6NNF4s5FXO2zzoUz2mkVxnjte5GMz1hg9HbQaEXbOPUn0qqa1OEsdhe5'\n    b'iSI+4mEktTbgc/P5El4qxlzdABeZnKeMYDiteX++N8eASvpiUs9fyHSV4tzho/Q6OF7/r0'\n    b'qPxnlQWHhkwV1lSbyFPHXAKFucbzMgjkKYKpaEosDRPkDlgjoz+8+hRDAvsvjIOROpGzxD'\n    b'1m2b9KhAmAOvR93YEAj3odEUG/OljQ9XBgnb2IWh7c73hCc6DGk3tUtHqFZnA5Rmn1lSjU'\n    b'6oMtoD5o8vymYONSy6ngX1cuAhzcNTD83sT6pI/rIkSqp5HLSFt4h5ZuQTZhszLy/CYXQ6'\n    b'N0m/iAFfisTpJ6ehvAf60R6OZ+WVuQPch5VLphyasbnkz8wfUgqiHrKbWSpY/vFS6ZfjsL'\n    b'k8mOXaFYnfeXz1q7lFxTC5+N9t/G7BgtBLtzOWgjQkNeQxLJdmgoQF0txgmIPYY7F5pWg7'\n    b'aUE2nEyLrPmhpwQpgV3/nWcOUT/U6ipyJrrNBfFEd7eAVmuEqMhqjXCe/EGtO03+kKM0Nb'\n    b'/3ygCGgDp9l5EcGVmXxK4MjSui46N0DM1f1ea/00lErSPqQVNZFVEzTeW5pjidClRQaTwy'\n    b'1os8/gfPlX0H/l/9XGlUETfWq4T1PT/Xzo+Hjtc6KI1xlfyhl0xRhqKLtZPkD2eCNMdn1D'\n    b'HA3cBTlRjd8REUMUUGNcWA0X2AbWVfe43woGKNuP5+O4unMT7yZbkBM6S7Gsu6mAo08moZ'\n    b'7rCBhWYCjdwaRpyaSqCRW8OQ+mqxOmAj15bj33y1WBOwkWvDifOnFGjk1jLc9f8Wmgg0cm'\n    b'sY/p1XCxUCjdyCIZ3qInG10Ru5IKN8Wiis+U5rTWWFpvJUU6H2emTcejx+1Qg8I24ERHmR'\n    b'j7E2xiTCU9IzpRoL74G0gronQJpVhPjnPRQs2zTBb7RwF1x6z0YeZwuE4T8T6n59Mq+wto'\n    b'K4W2PThSDRQB+8mlGLw2EbQzKQ5XxJ3bP8zbMe8tHUgVQjYNpY+BbkA5op+mBNdQxgLrr1'\n    b'6ZorjEtBWaWBKGVVwvVGqILH6Nz/ArTavZuA9NsbRSKbPjnxjdvwRKyOsCsZxt3IDK4dYc'\n    b'oQbkVWIJcJp2asYqtETdIcrfcNJ0l8NwdpbaI2A61N1DQdWRkgK9ZmQxBjo1nCVIu/KXjO'\n    b'SvSayRj3J7tTQuNOcx8ElYsy0W8spSD9rhamqcdgK4X5bnhLoUVcsVUU2WpHCYPKMZrTzw'\n    b'zt92GKJpByJqdAfnaYQ/L5J6PQQd9qCKGwgsJUChIUJsTdPfGBHTtPZRE6mpsALOg6IGZL'\n    b'YFVi0n1UKwB5asmgk08IjA4eM2BdbgvSb52x49UH5fL0btWucvxTt3fm3NwxMlVeKDoqXw'\n    b'plTrcZiU/b8bBq0Xhcre3IGTNCfz1my8hR27EzZoz8OXYALe0H19qOoYKNfDuOH15rO4oK'\n    b'NnJtOXGyqoCNXFtOGGJrO5AGcOTesWSQre1QGsCRe8uKM6sM2Mi14/iBtrbjqWAj15YjQ2'\n    b'1tR1TBRq7JsZ2tXezPeIsdoF6pdJUFaBS7VuVlcXWoyRxeOvIFHW9o3gZSXUNfoQfTCyaY'\n    b'eB3DoXkSA6cfKT9sOEv7GYyhGw3ou0AKMkbXUJiAzv0Dfbi5LATDfHt3tdiQOny02ODg8b'\n    b'JCbuHRTawTi46Pi881HBsNzhxL3DogNpJnf0X0yjxx4fFo1cIJN178gU5g8WjlI18oNA7d'\n    b'xRofZ19acLyOkbt8HZs/urQj5cd+ZIVZMiiurJuh2uyZ2bXs0THJmYOPvXfJgVCvjtSMRX'\n    b'eEmo46QjTXnlZ0PEvJL23ZXxjE7UVZNv06y1UTZ0C0RjeLOFr0RcQJa57ZMheO223ImjaG'\n    b'9Lm1WczSAWVkxbYCKQM/RydfMMs6aqPBAqlx5wzYqBZChYaGHIjmaYgoOj+A0ovOC2g6yn'\n    b'NUI4giJwQgnOj48KOVreWCtNewUhL6Cg1y9bVEqaFH9xIxyOsTopOA+u16BekteAXf2kKc'\n    b'3mD7rcRbPL2lCL7edoX4Z3/KdoZoQ9bPPKH7N/iOzh8gW6PzB5qO8h+hIRij+yjNLbNonL'\n    b'xVTrTnq90l+2Y53InIrw93NskoTycB0TfuBfRWjubJdzP0BkvnZ55wqbLCj1bY6+QkCnvj'\n    b'vrXOWBYAN0GnMqSrcvS7iZWzZk5svJbUMOTNaC2pWQDU+nlt6KCfk9Z3dDBqfQmHpiOrHs'\n    b'YGfRn/b4cLYnzbdq9rA+3DyX4Kuu+ejZaTuu+wnBIjQfXzeNAOiGBK5Btsnlna22RMHb/f'\n    b'8/+dXCmC6h/wS3hmLbfw3gfnaE9ODCmBW7Lv9enM0mHeS2Fp7cRB3oUVRc592hRcuk57qT'\n    b'3oPVUO0I485t1YUWRfxIUh9Cw56VkPSD/rKVP3HVVFBK+mQitQ29c1LVNm9lNf3OmgG2Zz'\n    b'y8ay/PO6qAhhSpVZQu6Yg5Z1iuZYGcWMpEoN7YcK6DpCRs7grUP13u30SIUm0D0Mdt8sd9'\n    b'+jx9nmib+bccL9tFPXqaetckOPmmBmwKs2aN2OGyHK3j9iUdrPNNfEoyKyB0WEebYDxgtE'\n    b'Dr5aH3K43j3PkhuPVtBdtBu8JKD6A5RjdK2WpqP+oAVj3z8MO7v41AQyrD4pMFosUrhsmU'\n    b'4N9nXoURs5TjgBZosbeDS2oMp2+m7NLEtGpjEspK/mgnU2MH6GTWUHqHF6aZFggFdq4NYZ'\n    b'lYl14Ed1F4B6QLO1iB7jlx4KhnYOik3tKg8G+zoH3bKwc6JqQw/nOsp/h2lzOgeJQd3c0W'\n    b'JS1wrgjeqcFzGjc5HrHTjnJD7EMgmgnGKZKkyOsdQOdIZ4COzxLHflQ3E7baNVs4qAGoVL'\n    b'0vrCtpoAbwSSa/NSh+jnkVaLMoLDnXqrBUvScPSzSPAw0bC+hK9wTyJZtr60D74yDUfRrB'\n    b'K538I64ikMo6TlltzZFUlef2Fo9kCXvXJvlQmTBVodcEDQBwyww1R+px4RMbHoUQRj2/Yh'\n    b'zkx0vduo25xaYNRvlha96jgri497ThaRvtKOgvDYoD0yaL+dmB4x6xLNxH5CVE1pIss00S'\n    b'kidI8OGPe6Dr7qdR0ed7EEo6xiH7rlzceSKlbd3pxvmJmvoCJpOihIGjVfwxlwtriGxU/M'\n    b'FC/LKzT4cLwh1INFaqCgl1lBlAhzDYSgHCzOGkUHV0StvlCj1vZP5jFRqtT8pCnKwsGmTi'\n    b'l6dzmsz91ooYU8PZKhhukJeaPpaCRDTvW7i3o7ZmmB6MCzAfe9tc+hijHKKcY+nK6WdKYW'\n    b'Hq3oWHRkPdI6MF7lKZNblh/zJDb6KAwdHyilxt6zz48WZmx4o/tLl8ktcxEmkqc82Ef0f4'\n    b'YhyZBqwDTuwnBZBPKWvfqKbD9UGq96WHRAGBQNEA+JpYXCgGiAW8OhEUUPhsZlNBQaRA+E'\n    b'BpBhcGYoGQSXjvRDoHEsA6CJTg9/hh0/MbwS6HLkfsDbBuPwHvU7NnefeWcyQuaCyPhYGc'\n    b'iNjojL2XBnK/sZ7TQRs4c3K/epFekZ6oq+bhz1K1p4QeTcDT6pVrIwWDwec0d19O4eyi+6'\n    b'E5KudKvUdNQqIeWw6zcXI6uxtV6/OQW/9ixjzh7zkCdcdBKTZGQk2l+4GIt+T35WNmlIhX'\n    b'UhJNudC80m9lPXPAduzE6w+4yeWVOYPLM2TU6y1IQWbnRSPVlpHPbwwAswpp7a89zs0lF+'\n    b'08vcyw394mHL1w4x2M9nzkV4HslzfEjPTzQSXHnKhNsK9bB+6eGJUXtwd6BxVOqpgf6XmS'\n    b'P3JjTvFDWGzMKTJvCFp5zs3E70oYXzCddJKZ2bcIHRYLYDzWqjd1RpR3ZJ1rqiB++odo68'\n    b'+bHHvZymbF5RQ8zcw5Ueb7Q4HYN1GMolWtKpSHu1yhBarTIAn6TQPTqHbaLxkjPXCYjGj1'\n    b'XUE4uO1+0zC8c9e+mCGNkP5haNR4bSgqO+nU1IrwMiGnsqgs+RMyccFd1BhlI0ZziuG2Tp'\n    b'ODfaI0RVFmH2Wx38recOCwdz2UmHQ7YcxS4PW6rVNEwjpbsTZHH0pqymo+5kmcSvhxYUht'\n    b'q9tURLkbgLLyPh0B4ZrHlKC90IqsRGHQg2ZUsE8zZcXtfRvU6LhLbNUAr04dw5yYdneyQj'\n    b'c5Q1VeB7UHJqNyNH2/JaOpjyklbbvhXJ0fvcGbGr17nz5BytCa5IjzTzBUPvmaYoRcvkHC'\n    b'0frhQdnUmegHF+7bqdvuf8vOZBZxP0V6qXc34Y5ZRab6C2IzJoxgYM+ilIe1kn5s1nbZUP'\n    b'hiyDFfjG6Mu3DdBXnMPqV4mMeNDPW6IqGiBe30eVNOjYQp7F+3D1OGTDPLLw1Wl7eDEXjy'\n    b'bnsFiWWyK+q6VKgUZWCZRVnX+CLnCOVsYaQ8sCGmTQBw6mqAjdrccG5nSoLimfkxw941AS'\n    b'u3Hp6zzzjPHFAZMFOVcPP1QGDQfcTcC3bjjAAOI5V0E3ZO35cO9ZvSs8U+hI/KlhxbV7Vl'\n    b'vwRtRT4VxF3ZJ1fRtChaKJ7sUpFR01CjrcdS9bngvNeGZNSK9TmDh2PSft3WbQd7BNPOOP'\n    b'jksHgcGkK4XTkLeUY8MQRXdpKFEtKUpY2aFTqpZ8KO1sXx1lhp3DhXOKDBfOGTBcOGfIk6'\n    b'6GDZpi97UPM+pZY4Fo6kUwOuJQkPa9oiF0t+iA0C8aIPQ7+cTQI/uXBUEuNT1jpBndwViP'\n    b'eNFFjJVm+tX+KLSrKxlRH3QvkzWGHlXTuQGv2ox1O66+jA99Qfdnfzqb+zdyCzzyMGLGd+'\n    b'VA2ieCavtpTnqk9ntkxE/U7KxfzWZnwhlNaIUxnr42yXiX3uSNgUYzU+P0GM+WFoLJPGgS'\n    b'IKmtTB60SqOvhLs2UybEHQ9Z8vPFnCYRdkaMVmOTVZtYb+r8SOUgASYWGMKBktoi6ogJS9'\n    b'Ye2tF302eCnsx7cpzrhens4gY3TDENGyXDeXhuP4NXB6i5+MwiIQczDdyaj7vw/YzcBaAW'\n    b'r50DPUufeSjM0x0Uz9RzD4a5uoNudUhOVD1fd66jGbvDbh0SLy1LT+eda+nnnJMwpZ8L4C'\n    b'f1zotb7TNHUdoY4t2aJ7NB7RjSU7o06MPkLjg/Tyeprr9E1Y3u5kKdje7m0nQ0dhgGmtFV'\n    b'I514xqiNenzcRLNkPDmoHDJqoHQoz7yFR7Wcoj+xkLNdyR01RORmuNzvnJPSeeARERajXV'\n    b'azUDSDmFrQz+Yciozv9506PEShedIxDBulQ+LBxKAv0YtmlERd/eBOlFDm6FrxCsqtNmAp'\n    b'QUerJJBUvwfNNhFdVYX+IrqqStNR2TIgxIPs//NMc9qnrbUca4uIIXdGs0FaXLktPRac1R'\n    b'7a9xsHVQZ67M29Ms3SUGbZjxNVEnw8GB2o8WrutbDShd01hkAzRn+/8ATZwmlgj45m22GC'\n    b'fUSf0Jkb5GiePf0uV7YCl991ok8Uz266sqZMOR+I/i5bImq/70bHhC4CqrWMGwjZHWv3o0'\n    b'uTnGWRB6mn/ZA1803ZqXnSW+zOFeRNdhGC3Efo18SR5cd+/bRBsHziwRC7R16aPrXEkTtA'\n    b'zdwSPMRPa1jagPLZWr4013NO5D7DRCoCwlTKwWEyRSCaNBjAGHZSceNnmmlCc7J7RYRVdA'\n    b'eMN1gcfLXB4vB4g4XgNrrIDrmnVzPQcvUEe7Yi7W/BMIS+lccB4coOAvoE9czQ8RyQ88vr'\n    b'KU3DJn41u2jYEcQa7MQAXoW1lNZhPRKUWCLeOKtG5NHNYKgP0c1gmo46FlSPy/g2D47Sl/'\n    b'F1HosrMDoZjSx67XZflZ7ROEQGWu8kaGm5Q2SwNH4O57ewNZw7RDSGIp9OHSYaYOUBCZkB'\n    b'8WauPONH0D8MqbSjmnSQOQ3kLc3IhOr1IuN1dLNO4bDvIboPmZCjdajaAkGDMkCsP2UWCt'\n    b'qTAW7pTiYpWnMyLiO9ySC3tCYjtNaZjEspSMMO+tLMkV5bMo6lSI0c8m5OY7JQK0PGtVeF'\n    b'HNEfN0bRnCa8RhnxXeR2tXlyMes5GaK9KLM/UuqylxqkuxqtXCYXubwMIYaFFUeEy8saDc'\n    b'hKS5VEz4HmyWWzDt1HkYIOt41VlpSzIZDd2yFCRH3b2CKQ3jMmxIJJ9HnAJBlzhQXRVmmA'\n    b'nQDpUkUjdxItS4DqpjAIKTeUQUptJmnI8C4xSH3tD8LR14lBd7i4C8qaif30V860M0uraC'\n    b'muvqCsbSwdhbi0mFxQtgIdX1DGHNeQzhDk3ZUdMmTUtxSVye3lYXjVt1Ogz7+EO8yQqZKZ'\n    b'6Ogu148YrzyoluQq43J08xOkj1RGlAVX4PytQcVK0eYS7QlTIJD2m2u3uqvJFe4vJ6Jb9x'\n    b'TxnJ/s7cyy9QQlJxdaMRt8u2eRvsgLPCTQiqMtbzQonsg2158tCk/ox4ebMeh1SBO44fgL'\n    b'HzAPc4jcn4bK8DI2xPeYO0kBEaL8ZQKsdT0v37+Mn8qGwnc1/E2L5Gr0m4+xaPBD3UAPtz'\n    b'ZW8GrldBXgq1czG5S7f5KY/qP7rCoPSCeA6HVvh6yRboXfusVaOjRZ0le1LgN4y+45wr3F'\n    b'cwRqW2cwbgWSJtdhaEwHkSZf2cWXyVfZSyvwrbfSLB0MlEjrW4or0NwsWJIRtgdyRZbFCA'\n    b'hLkgYMS5KWNKe4oAE3QgWt2GDaz2pC5G0IL7uhZ/sahhkEqXo9qEHRS88YW78q3XI+JTlS'\n    b'LRtiV5rlguhYsVwC1JkzA23ejeDuiu8TzAg6qRYCcBKrngabLCOOPo8yizjhjaI4LAfWAK'\n    b'Pbb9vkq5/LIE16WWMFt2iC+uEkNHcL+TrkaV1/iJ3WR31XPObpDvNNRADdTgBGHS+qoJ6r'\n    b'VxDImJjefGe8HTN1UjxTG602yf9isEoPOoB58lU6XVQlP/hVSGxQ+ZHjeiyeoeLogW01TV'\n    b'5ZyFXy6rsVJPl1re4snYHUhzdWoPXhDU1H8i7IkGBqUOM+tG49qAMkeFZ2uAWF+2ou1uME'\n    b'ncF+fbs9hCE169ewU8g4R89ImtBfw0uUYTV9GjNib3WZvKpnhpbJa2i5pSXETB3d8Ksaz2'\n    b'uSaosN85BX1dKhO73q3axZChq+OSbwFuo0RSqixkoHIV+Rnk7dmwrJvKZUwyFNFvTFkAaQ'\n    b'Rwox0CrAzWWAL2cOh07VHeOFmEn7HZ4qB2i/1278Cstk9T2mDmFqHaHb2huT/GJRRYi7NJ'\n    b'zn4LjlZSqRclw7x8PrwV+kY5yEk3g8kn7lRrOXls2kfS+IRX7tRrNTz+b94ryja7SmVX6H'\n    b'L4tRLs2G/m46Zjccab4LxPjzb+PxRl2H9jTYCAZcFhVnLgmnMw0Yy4mTWG0/lr48/7fFu/'\n    b'r7TiStLhnQF7+X0GLsQjNRFHpBfDYBrVuNoaWZQOaoW0ce6SXXWQZa+9Z0pNQhQwbzMMmM'\n    b'H5HdC1noSf1GUIY4pL9GeEbfTLmF/KrPysFV6L1RB98OZqK0Sjj3xHDzpxqB82Xypza3zp'\n    b'JgT4lZ1p+6F4LTqBdqkj+jEx3QCf7kBUpNm0SWjui4xawRmfynkrXNEz4EBD30bb3ehA57'\n    b'2ib6tnRouG8yM18mcnF6Rlz1ZFkSXaNuvOmlLNJ68JiC1uOGpqOByDAkmhTUfs3h1e+6Ut'\n    b'yroSn3oI7iCozqwgJcrdqXcB7Ko7ZEGCaq5E3P9JG8qIAsLdPgInlTCuB0TtLcCB+GsGUW'\n    b'wFg3ZF6Od4pXxvWtkbCMGaORcB5zxzvNqFgRf7TlDIXk7Xp7GlPwt6vdaegmb7eNKzD+vn'\n    b'3HuALV9e2WccXMBGa3LIezXTcJGYc6oSoi029MU5nncZsmokZbQ16dDq8ZwHG9RRN4Q9sM'\n    b'JhbzCI8fxjI8fXHZlBl5vLmCgwYHKDYETAUbH7VnVXasGGcFOPdhijKDDF55YIm4bYpmaj'\n    b'/9agumUm+91oGRC1rwgvxgdIhY+sMb+mmMFWzD8eYYhYi6G6RtMA9mm48wT1NkmJYZMEzL'\n    b'DBlNsTKH6PsyVk0KMaID4ag0QxC5Zji62deKjnqWkgypDSiwqzuvoe29XV163V6BUT+C/s'\n    b'g8VmLPJ6AgBt1PGmFVh2ZieJNttIxJfgtv72KWJkvgLMmX4alDIe9ZAryXaR5D+oJRlCtt'\n    b'4uZIpR+skDN6sIIoftrBShkGLiQhOvGNIC4qg9EJRAfAS0VHGVyQIVVpAup03z/pPrZxWD'\n    b'+c+8c+ejQDQxp4u/4MPUTDVYBv+ZqRPS7GwoNa7CswKkbGrroVdowX3XuwJ9Xj5HJF2i8Y'\n    b'r5JvHFvnyTd9WA36xjdZRCbPO2/wrS8cIK2MOmuSI6NOBnVt1FkZNBh1Gldjo04G16szXJ'\n    b'mhR0e4JgC1jSdD+qN7xIRbHVhFCRs0visQvfW39fEPtSnPGN/M2adlaT9D1xABoXNwcOge'\n    b'AGhtCSn1S+VVi28ZqWeWcCM1an0KwBp+8tO+sV4tzJcYVjraj9ezPPkWLeAgtpuWk2hS37'\n    b'pbJ6NRAaITtgg/OmFL+mh2rybmK2z/WFrtX5UG8FtSltJ7Sh4Jm0oWiXeVbLB6s8gi0W6R'\n    b'hfSukEXUzo8F9HkXi/jtHUuZZvT7wLfOqAusAngYDg7PJpNFwK0MwFD3ndEakhGdR0ShbD'\n    b'vdnOYEzKK/vko+I6oLj+HcLr3KcG4U3zL5Fh0rQwWOjpWRPgzqPnBUQW0lwoYRDYwQNToR'\n    b'A/fRiRjQ0s/D79gsABOib2GDDQmK7OEReGQPP0/+7a59v0z+H+SUGTTsMAEA'\n    )).decode().splitlines()\n\n\ndef get_tessdata() -> str:\n    \"\"\"Detect Tesseract-OCR and return its language support folder.\n\n    This function can be used to enable OCR via Tesseract even if the\n    environment variable TESSDATA_PREFIX has not been set.\n    If the value of TESSDATA_PREFIX is None, the function tries to locate\n    Tesseract-OCR and fills the required variable.\n\n    Returns:\n        Folder name of tessdata if Tesseract-OCR is available, otherwise False.\n    \"\"\"\n    TESSDATA_PREFIX = os.getenv(\"TESSDATA_PREFIX\")\n    if TESSDATA_PREFIX != None:\n        return TESSDATA_PREFIX\n\n    if sys.platform == \"win32\":\n        tessdata = \"C:\\\\Program Files\\\\Tesseract-OCR\\\\tessdata\"\n    else:\n        tessdata = \"/usr/share/tesseract-ocr/4.00/tessdata\"\n\n    if os.path.exists(tessdata):\n        return tessdata\n\n    \"\"\"\n    Try to locate the tesseract-ocr installation.\n    \"\"\"\n    # Windows systems:\n    if sys.platform == \"win32\":\n        try:\n            response = os.popen(\"where tesseract\").read().strip()\n        except:\n            response = \"\"\n        if not response:\n            print(\"Tesseract-OCR is not installed\")\n            return False\n        dirname = os.path.dirname(response)  # path of tesseract.exe\n        tessdata = os.path.join(dirname, \"tessdata\")  # language support\n        if os.path.exists(tessdata):  # all ok?\n            return tessdata\n        else:  # should not happen!\n            print(\"unexpected: Tesseract-OCR has no 'tessdata' folder\", file=sys.stderr)\n            return False\n\n    # Unix-like systems:\n    try:\n        response = os.popen(\"whereis tesseract-ocr\").read().strip().split()\n    except:\n        response = \"\"\n    if len(response) != 2:  # if not 2 tokens: no tesseract-ocr\n        print(\"Tesseract-OCR is not installed\")\n        return False\n\n    # determine tessdata via iteration over subfolders\n    tessdata = None\n    for sub_response in response.iterdir():\n        for sub_sub in sub_response.iterdir():\n            if str(sub_sub).endswith(\"tessdata\"):\n                tessdata = sub_sub\n                break\n    if tessdata != None:\n        return tessdata\n    else:\n        print(\n            \"unexpected: tesseract-ocr has no 'tessdata' folder\",\n            file=sys.stderr,\n        )\n        return False\n    return False\n\n%}\n"
  },
  {
    "path": "src_classic/helper-select.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\nvoid remove_dest_range(fz_context *ctx, pdf_document *pdf, PyObject *numbers)\n{\n    fz_try(ctx) {\n        int i, j, pno, len, pagecount = pdf_count_pages(ctx, pdf);\n        PyObject *n1 = NULL;\n        pdf_obj *target, *annots, *pageref, *o, *action, *dest;\n        for (i = 0; i < pagecount; i++) {\n            n1 = PyLong_FromLong((long) i);\n            if (PySet_Contains(numbers, n1)) {\n                Py_DECREF(n1);\n                continue;\n            }\n            Py_DECREF(n1);\n\n            pageref = pdf_lookup_page_obj(ctx, pdf, i);\n            annots = pdf_dict_get(ctx, pageref, PDF_NAME(Annots));\n            if (!annots) continue;\n            len = pdf_array_len(ctx, annots);\n            for (j = len - 1; j >= 0; j -= 1) {\n                o = pdf_array_get(ctx, annots, j);\n                if (!pdf_name_eq(ctx, pdf_dict_get(ctx, o, PDF_NAME(Subtype)), PDF_NAME(Link))) {\n                    continue;\n                }\n                action = pdf_dict_get(ctx, o, PDF_NAME(A));\n                dest =  pdf_dict_get(ctx, o, PDF_NAME(Dest));\n                if (action) {\n                    if (!pdf_name_eq(ctx, pdf_dict_get(ctx, action,\n                        PDF_NAME(S)), PDF_NAME(GoTo)))\n                        continue;\n                    dest = pdf_dict_get(ctx, action, PDF_NAME(D));\n                }\n                pno = -1;\n                if (pdf_is_array(ctx, dest)) {\n                    target = pdf_array_get(ctx, dest, 0);\n                    pno = pdf_lookup_page_number(ctx, pdf, target);\n                }\n                else if (pdf_is_string(ctx, dest)) {\n                    fz_location location = fz_resolve_link(ctx, &pdf->super,\n                                            pdf_to_text_string(ctx, dest),\n                                            NULL, NULL);\n                    pno = location.page;\n                }\n                if (pno < 0) { // page number lookup did not work\n                    continue;\n                }\n                n1 = PyLong_FromLong((long) pno);\n                if (PySet_Contains(numbers, n1)) {\n                    pdf_array_delete(ctx, annots, j);\n                }\n                Py_DECREF(n1);\n            }\n        }\n    }\n\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return;\n}\n%}\n"
  },
  {
    "path": "src_classic/helper-stext.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n// need own versions of ascender / descender\nstatic const float\nJM_font_ascender(fz_context *ctx, fz_font *font)\n{\n    if (skip_quad_corrections) {\n        return 0.8f;\n    }\n    return fz_font_ascender(ctx, font);\n}\n\nstatic const float\nJM_font_descender(fz_context *ctx, fz_font *font)\n{\n    if (skip_quad_corrections) {\n        return -0.2f;\n    }\n    return fz_font_descender(ctx, font);\n}\n\n\n//----------------------------------------------------------------\n// Return true if character is considered to be a word delimiter\n//----------------------------------------------------------------\nstatic const int \nJM_is_word_delimiter(int c, PyObject *delimiters)\n{\n    if (c <= 32 || c == 160) return 1;  // a standard delimiter\n\n    // extra delimiters must be a non-empty sequence\n    if (!delimiters || PyObject_Not(delimiters) || !PySequence_Check(delimiters)) {  \n        return 0;\n    }\n\n    // convert to tuple for easier looping\n    PyObject *delims = PySequence_Tuple(delimiters);\n    if (!delims) {\n        PyErr_Clear();\n        return 0;\n    }\n\n    // Make 1-char PyObject from character given as integer\n    PyObject *cchar = Py_BuildValue(\"C\", c);  // single character PyObject\n    Py_ssize_t i, len = PyTuple_Size(delims);\n    for (i = 0; i < len; i++) {\n        int rc = PyUnicode_Compare(cchar, PyTuple_GET_ITEM(delims, i));\n        if (rc == 0) {  // equal to a delimiter character\n            Py_DECREF(cchar);\n            Py_DECREF(delims);\n            PyErr_Clear();\n            return 1;\n        }\n    }\n\n    Py_DECREF(delims);\n    PyErr_Clear();\n    return 0;\n}\n\n/*  inactive\n//-----------------------------------------------------------------------------\n// Make OCR text page directly from an fz_page\n//-----------------------------------------------------------------------------\nfz_stext_page *\nJM_new_stext_page_ocr_from_page(fz_context *ctx, fz_page *page, fz_rect rect, int flags,\n        const char *lang, const char *tessdata)\n{\n    if (!page) return NULL;\n    int with_list = 1;\n    fz_stext_page *tp = NULL;\n    fz_device *dev = NULL, *ocr_dev = NULL;\n    fz_var(dev);\n    fz_var(ocr_dev);\n    fz_var(tp);\n    fz_stext_options options;\n    memset(&options, 0, sizeof options);\n    options.flags = flags;\n    //fz_matrix ctm = fz_identity;\n    fz_matrix ctm1 = fz_make_matrix(100/72, 0, 0, 100/72, 0, 0);\n    fz_matrix ctm2 = fz_make_matrix(400/72, 0, 0, 400/72, 0, 0);\n\n    fz_try(ctx) {\n        tp = fz_new_stext_page(ctx, rect);\n        dev = fz_new_stext_device(ctx, tp, &options);\n        ocr_dev = fz_new_ocr_device(ctx, dev, fz_identity, rect, with_list, lang, tessdata, NULL);\n        fz_run_page(ctx, page, ocr_dev, fz_identity, NULL);\n        fz_close_device(ctx, ocr_dev);\n        fz_close_device(ctx, dev);\n    }\n    fz_always(ctx) {\n        fz_drop_device(ctx, dev);\n        fz_drop_device(ctx, ocr_dev);\n    }\n    fz_catch(ctx) {\n        fz_drop_stext_page(ctx, tp);\n        fz_rethrow(ctx);\n    }\n    return tp;\n}\n*/\n\n//---------------------------------------------------------------------------\n// APPEND non-ascii runes in unicode escape format to fz_buffer\n//---------------------------------------------------------------------------\nvoid JM_append_rune(fz_context *ctx, fz_buffer *buff, int ch)\n{\n    if (ch == 92) {  // prevent accidental \"\\u\" etc.\n        fz_append_string(ctx, buff, \"\\\\u005c\");\n    } else if ((ch >= 32 && ch <= 255) || ch == 10) {\n        fz_append_byte(ctx, buff, ch);\n    } else if (ch >= 0xd800 && ch <= 0xdfff) {  // surrogate Unicode range\n        fz_append_string(ctx, buff, \"\\\\ufffd\");\n    } else if (ch <= 0xffff) {  // 4 hex digits\n        fz_append_printf(ctx, buff, \"\\\\u%04x\", ch);\n    } else {  // 8 hex digits\n        fz_append_printf(ctx, buff, \"\\\\U%08x\", ch);\n    }\n}\n\n\n// re-compute char quad if ascender/descender values make no sense\nstatic fz_quad\nJM_char_quad(fz_context *ctx, fz_stext_line *line, fz_stext_char *ch)\n{\n    if (skip_quad_corrections) {  // no special handling\n        return ch->quad;\n    }\n    if (line->wmode) {  // never touch vertical write mode\n        return ch->quad;\n    }\n    fz_font *font = ch->font;\n    float asc = JM_font_ascender(ctx, font);\n    float dsc = JM_font_descender(ctx, font);\n    float c, s, fsize = ch->size;\n    float asc_dsc = asc - dsc + FLT_EPSILON;\n    if (asc_dsc >= 1 && small_glyph_heights == 0) {  // no problem\n       return ch->quad;\n    }\n    if (asc < 1e-3) {  // probably Tesseract glyphless font\n        dsc = -0.1f;\n        asc = 0.9f;\n        asc_dsc = 1.0f;\n    }\n\n    if (small_glyph_heights || asc_dsc < 1) {\n        dsc = dsc / asc_dsc;\n        asc = asc / asc_dsc;\n    }\n    asc_dsc = asc - dsc;\n    asc = asc * fsize / asc_dsc;\n    dsc = dsc * fsize / asc_dsc;\n\n    /* ------------------------------\n    Re-compute quad with the adjusted ascender / descender values:\n    Move ch->origin to (0,0) and de-rotate quad, then adjust the corners,\n    re-rotate and move back to ch->origin location.\n    ------------------------------ */\n    fz_matrix trm1, trm2, xlate1, xlate2;\n    fz_quad quad;\n    c = line->dir.x;  // cosine\n    s = line->dir.y;  // sine\n    trm1 = fz_make_matrix(c, -s, s, c, 0, 0);  // derotate\n    trm2 = fz_make_matrix(c, s, -s, c, 0, 0);  // rotate\n    if (c == -1) {  // left-right flip\n        trm1.d = 1;\n        trm2.d = 1;\n    }\n    xlate1 = fz_make_matrix(1, 0, 0, 1, -ch->origin.x, -ch->origin.y);\n    xlate2 = fz_make_matrix(1, 0, 0, 1, ch->origin.x, ch->origin.y);\n\n    quad = fz_transform_quad(ch->quad, xlate1);  // move origin to (0,0)\n    quad = fz_transform_quad(quad, trm1);  // de-rotate corners\n\n    // adjust vertical coordinates\n    if (c == 1 && quad.ul.y > 0) {  // up-down flip\n        quad.ul.y = asc;\n        quad.ur.y = asc;\n        quad.ll.y = dsc;\n        quad.lr.y = dsc;\n    } else {\n        quad.ul.y = -asc;\n        quad.ur.y = -asc;\n        quad.ll.y = -dsc;\n        quad.lr.y = -dsc;\n    }\n\n    // adjust horizontal coordinates that are too crazy:\n    // (1) left x must be >= 0\n    // (2) if bbox width is 0, lookup char advance in font.\n    if (quad.ll.x < 0) {\n        quad.ll.x = 0;\n        quad.ul.x = 0;\n    }\n    float cwidth = quad.lr.x - quad.ll.x;\n    if (cwidth < FLT_EPSILON) {\n        int glyph = fz_encode_character(ctx, font, ch->c);\n        if (glyph) {\n            float fwidth = fz_advance_glyph(ctx, font, glyph, line->wmode);\n            quad.lr.x = quad.ll.x + fwidth * fsize;\n            quad.ur.x = quad.lr.x;\n        }\n    }\n\n    quad = fz_transform_quad(quad, trm2);  // rotate back\n    quad = fz_transform_quad(quad, xlate2);  // translate back\n    return quad;\n}\n\n\n// return rect of char quad\nstatic fz_rect\nJM_char_bbox(fz_context *ctx, fz_stext_line *line, fz_stext_char *ch)\n{\n    fz_rect r = fz_rect_from_quad(JM_char_quad(ctx, line, ch));\n    if (!line->wmode) {\n        return r;\n    }\n    if (r.y1 < r.y0 + ch->size) {\n        r.y0 = r.y1 - ch->size;\n    }\n    return r;\n}\n\n\n//-------------------------------------------\n// make a buffer from an stext_page's text\n//-------------------------------------------\nfz_buffer *\nJM_new_buffer_from_stext_page(fz_context *ctx, fz_stext_page *page)\n{\n    fz_stext_block *block;\n    fz_stext_line *line;\n    fz_stext_char *ch;\n    fz_rect rect = page->mediabox;\n    fz_buffer *buf = NULL;\n\n    fz_try(ctx)\n    {\n        buf = fz_new_buffer(ctx, 256);\n        for (block = page->first_block; block; block = block->next) {\n            if (block->type == FZ_STEXT_BLOCK_TEXT) {\n                for (line = block->u.t.first_line; line; line = line->next) {\n                    for (ch = line->first_char; ch; ch = ch->next) {\n                        if (!JM_rects_overlap(rect, JM_char_bbox(ctx, line, ch)) &&\n                            !fz_is_infinite_rect(rect)) {\n                            continue;\n                        }\n                        fz_append_rune(ctx, buf, ch->c);\n                    }\n                    fz_append_byte(ctx, buf, '\\n');\n                }\n                fz_append_byte(ctx, buf, '\\n');\n            }\n        }\n    }\n    fz_catch(ctx) {\n        fz_drop_buffer(ctx, buf);\n        fz_rethrow(ctx);\n    }\n    return buf;\n}\n\n\nstatic float hdist(fz_point *dir, fz_point *a, fz_point *b)\n{\n    float dx = b->x - a->x;\n    float dy = b->y - a->y;\n    return fz_abs(dx * dir->x + dy * dir->y);\n}\n\n\nstatic float vdist(fz_point *dir, fz_point *a, fz_point *b)\n{\n    float dx = b->x - a->x;\n    float dy = b->y - a->y;\n    return fz_abs(dx * dir->y + dy * dir->x);\n}\n\n\nstruct highlight\n{\n    Py_ssize_t len;\n    PyObject *quads;\n    float hfuzz, vfuzz;\n};\n\n\nstatic void on_highlight_char(fz_context *ctx, void *arg, fz_stext_line *line, fz_stext_char *ch)\n{\n    struct highlight *hits = arg;\n    float vfuzz = ch->size * hits->vfuzz;\n    float hfuzz = ch->size * hits->hfuzz;\n    fz_quad ch_quad = JM_char_quad(ctx, line, ch);\n    if (hits->len > 0) {\n        PyObject *quad = PySequence_ITEM(hits->quads, hits->len - 1);\n        fz_quad end = JM_quad_from_py(quad);\n        Py_DECREF(quad);\n        if (hdist(&line->dir, &end.lr, &ch_quad.ll) < hfuzz\n            && vdist(&line->dir, &end.lr, &ch_quad.ll) < vfuzz\n            && hdist(&line->dir, &end.ur, &ch_quad.ul) < hfuzz\n            && vdist(&line->dir, &end.ur, &ch_quad.ul) < vfuzz)\n        {\n            end.ur = ch_quad.ur;\n            end.lr = ch_quad.lr;\n            quad = JM_py_from_quad(end);\n            PyList_SetItem(hits->quads, hits->len - 1, quad);\n            return;\n        }\n    }\n    LIST_APPEND_DROP(hits->quads, JM_py_from_quad(ch_quad));\n    hits->len++;\n}\n\n\nstatic inline int canon(int c)\n{\n\t/* TODO: proper unicode case folding */\n\t/* TODO: character equivalence (a matches ä, etc) */\n\tif (c == 0xA0 || c == 0x2028 || c == 0x2029)\n\t\treturn ' ';\n\tif (c == '\\r' || c == '\\n' || c == '\\t')\n\t\treturn ' ';\n\tif (c >= 'A' && c <= 'Z')\n\t\treturn c - 'A' + 'a';\n\treturn c;\n}\n\n\nstatic inline int chartocanon(int *c, const char *s)\n{\n\tint n = fz_chartorune(c, s);\n\t*c = canon(*c);\n\treturn n;\n}\n\n\nstatic const char *match_string(const char *h, const char *n)\n{\n\tint hc, nc;\n\tconst char *e = h;\n\th += chartocanon(&hc, h);\n\tn += chartocanon(&nc, n);\n\twhile (hc == nc)\n\t{\n\t\te = h;\n\t\tif (hc == ' ')\n\t\t\tdo\n\t\t\t\th += chartocanon(&hc, h);\n\t\t\twhile (hc == ' ');\n\t\telse\n\t\t\th += chartocanon(&hc, h);\n\t\tif (nc == ' ')\n\t\t\tdo\n\t\t\t\tn += chartocanon(&nc, n);\n\t\t\twhile (nc == ' ');\n\t\telse\n\t\t\tn += chartocanon(&nc, n);\n\t}\n\treturn nc == 0 ? e : NULL;\n}\n\n\nstatic const char *find_string(const char *s, const char *needle, const char **endp)\n{\n    const char *end;\n    while (*s)\n    {\n        end = match_string(s, needle);\n        if (end)\n            return *endp = end, s;\n        ++s;\n    }\n    return *endp = NULL, NULL;\n}\n\n\nPyObject *\nJM_search_stext_page(fz_context *ctx, fz_stext_page *page, const char *needle)\n{\n    struct highlight hits;\n    fz_stext_block *block;\n    fz_stext_line *line;\n    fz_stext_char *ch;\n    fz_buffer *buffer = NULL;\n    const char *haystack, *begin, *end;\n    fz_rect rect = page->mediabox;\n    int c, inside;\n\n    if (strlen(needle) == 0) Py_RETURN_NONE;\n    PyObject *quads = PyList_New(0);\n    hits.len = 0;\n    hits.quads = quads;\n    hits.hfuzz = 0.2f; /* merge kerns but not large gaps */\n    hits.vfuzz = 0.1f;\n\n    fz_try(ctx) {\n        buffer = JM_new_buffer_from_stext_page(ctx, page);\n        haystack = fz_string_from_buffer(ctx, buffer);\n        begin = find_string(haystack, needle, &end);\n        if (!begin) goto no_more_matches;\n\n        inside = 0;\n        for (block = page->first_block; block; block = block->next) {\n            if (block->type != FZ_STEXT_BLOCK_TEXT) {\n                continue;\n            }\n            for (line = block->u.t.first_line; line; line = line->next) {\n                for (ch = line->first_char; ch; ch = ch->next) {\n                    if (!fz_is_infinite_rect(rect) &&\n                        !JM_rects_overlap(rect, JM_char_bbox(ctx, line, ch))) {\n                            goto next_char;\n                        }\ntry_new_match:\n                    if (!inside) {\n                        if (haystack >= begin) inside = 1;\n                    }\n                    if (inside) {\n                        if (haystack < end) {\n                            on_highlight_char(ctx, &hits, line, ch);\n                        } else {\n                            inside = 0;\n                            begin = find_string(haystack, needle, &end);\n                            if (!begin) goto no_more_matches;\n                            else goto try_new_match;\n                        }\n                    }\n                    haystack += fz_chartorune(&c, haystack);\nnext_char:;\n                }\n                assert(*haystack == '\\n');\n                ++haystack;\n            }\n            assert(*haystack == '\\n');\n            ++haystack;\n        }\nno_more_matches:;\n    }\n    fz_always(ctx)\n        fz_drop_buffer(ctx, buffer);\n    fz_catch(ctx)\n        fz_rethrow(ctx);\n\n    return quads;\n}\n\n\n//-----------------------------------------------------------------------------\n// Plain text output. An identical copy of fz_print_stext_page_as_text,\n// but lines within a block are concatenated by space instead a new-line\n// character (which else leads to 2 new-lines).\n//-----------------------------------------------------------------------------\nvoid\nJM_print_stext_page_as_text(fz_context *ctx, fz_buffer *buff, fz_stext_page *page)\n{\n    fz_stext_block *block;\n    fz_stext_line *line;\n    fz_stext_char *ch;\n    fz_rect rect = page->mediabox;\n    fz_rect chbbox;\n    int last_char = 0;\n    char utf[10];\n    int i, n;\n\n    for (block = page->first_block; block; block = block->next) {\n        if (block->type == FZ_STEXT_BLOCK_TEXT) {\n            for (line = block->u.t.first_line; line; line = line->next) {\n                last_char = 0;\n                for (ch = line->first_char; ch; ch = ch->next) {\n                    chbbox = JM_char_bbox(ctx, line, ch);\n                    if (fz_is_infinite_rect(rect) ||\n                        JM_rects_overlap(rect, chbbox)) {\n                        last_char = ch->c;\n                        JM_append_rune(ctx, buff, ch->c);\n                    }\n                }\n                if (last_char != 10 && last_char > 0) {\n                    fz_append_string(ctx, buff, \"\\n\");\n                }\n            }\n        }\n    }\n}\n\n//-----------------------------------------------------------------------------\n// Functions for wordlist output\n//-----------------------------------------------------------------------------\nint JM_append_word(fz_context *ctx, PyObject *lines, fz_buffer *buff, fz_rect *wbbox,\n                   int block_n, int line_n, int word_n)\n{\n    PyObject *s = JM_EscapeStrFromBuffer(ctx, buff);\n    PyObject *litem = Py_BuildValue(\"ffffOiii\",\n                                    wbbox->x0,\n                                    wbbox->y0,\n                                    wbbox->x1,\n                                    wbbox->y1,\n                                    s,\n                                    block_n, line_n, word_n);\n    LIST_APPEND_DROP(lines, litem);\n    Py_DECREF(s);\n    *wbbox = fz_empty_rect;\n    return word_n + 1;                 // word counter\n}\n\n//-----------------------------------------------------------------------------\n// Functions for dictionary output\n//-----------------------------------------------------------------------------\n\nstatic int detect_super_script(fz_stext_line *line, fz_stext_char *ch)\n{\n    if (line->wmode == 0 && line->dir.x == 1 && line->dir.y == 0)\n        return ch->origin.y < line->first_char->origin.y - ch->size * 0.1f;\n    return 0;\n}\n\nstatic int JM_char_font_flags(fz_context *ctx, fz_font *font, fz_stext_line *line, fz_stext_char *ch)\n{\n    int flags = detect_super_script(line, ch);\n    flags += fz_font_is_italic(ctx, font) * TEXT_FONT_ITALIC;\n    flags += fz_font_is_serif(ctx, font) * TEXT_FONT_SERIFED;\n    flags += fz_font_is_monospaced(ctx, font) * TEXT_FONT_MONOSPACED;\n    flags += fz_font_is_bold(ctx, font) * TEXT_FONT_BOLD;\n    return flags;\n}\n\nstatic const char *\nJM_font_name(fz_context *ctx, fz_font *font)\n{\n    const char *name = fz_font_name(ctx, font);\n    const char *s = strchr(name, '+');\n    if (subset_fontnames || s == NULL || s-name != 6) {\n        return name;\n    }\n    return s + 1;\n}\n\n\nstatic fz_rect\nJM_make_spanlist(fz_context *ctx, PyObject *line_dict,\n                 fz_stext_line *line, int raw, fz_buffer *buff,\n                 fz_rect tp_rect)\n{\n    PyObject *span = NULL, *char_list = NULL, *char_dict;\n    PyObject *span_list = PyList_New(0);\n    fz_clear_buffer(ctx, buff);\n    fz_stext_char *ch;\n    fz_rect span_rect = fz_empty_rect;\n    fz_rect line_rect = fz_empty_rect;\n    fz_point span_origin = {0, 0};\n    typedef struct style_s {\n        float size; int flags; const char *font; int color;\n        float asc; float desc;\n    } char_style;\n    char_style old_style = { -1, -1, \"\", -1, 0, 0 }, style;\n\n    for (ch = line->first_char; ch; ch = ch->next) {\n        fz_rect r = JM_char_bbox(ctx, line, ch);\n        if (!JM_rects_overlap(tp_rect, r) &&\n            !fz_is_infinite_rect(tp_rect)) {\n            continue;\n        }\n        int flags = JM_char_font_flags(ctx, ch->font, line, ch);\n        fz_point origin = ch->origin;\n        style.size = ch->size;\n        style.flags = flags;\n        style.font = JM_font_name(ctx, ch->font);\n        style.color = ch->color;\n        style.asc = JM_font_ascender(ctx, ch->font);\n        style.desc = JM_font_descender(ctx, ch->font);\n\n        if (style.size != old_style.size ||\n            style.flags != old_style.flags ||\n            style.color != old_style.color ||\n            strcmp(style.font, old_style.font) != 0) {\n\n            if (old_style.size >= 0) {\n                // not first one, output previous\n                if (raw) {\n                    // put character list in the span\n                    DICT_SETITEM_DROP(span, dictkey_chars, char_list);\n                    char_list = NULL;\n                } else {\n                    // put text string in the span\n                    DICT_SETITEM_DROP(span, dictkey_text, JM_EscapeStrFromBuffer(ctx, buff));\n                    fz_clear_buffer(ctx, buff);\n                }\n\n                DICT_SETITEM_DROP(span, dictkey_origin,\n                    JM_py_from_point(span_origin));\n                DICT_SETITEM_DROP(span, dictkey_bbox,\n                    JM_py_from_rect(span_rect));\n                line_rect = fz_union_rect(line_rect, span_rect);\n                LIST_APPEND_DROP(span_list, span);\n                span = NULL;\n            }\n\n            span = PyDict_New();\n            float asc = style.asc, desc = style.desc;\n            if (style.asc < 1e-3) {\n                asc = 0.9f;\n                desc = -0.1f;\n            }\n\n            DICT_SETITEM_DROP(span, dictkey_size, Py_BuildValue(\"f\", style.size));\n            DICT_SETITEM_DROP(span, dictkey_flags, Py_BuildValue(\"i\", style.flags));\n            DICT_SETITEM_DROP(span, dictkey_font, JM_EscapeStrFromStr(style.font));\n            DICT_SETITEM_DROP(span, dictkey_color, Py_BuildValue(\"i\", style.color));\n            DICT_SETITEMSTR_DROP(span, \"ascender\", Py_BuildValue(\"f\", asc));\n            DICT_SETITEMSTR_DROP(span, \"descender\", Py_BuildValue(\"f\", desc));\n\n            old_style = style;\n            span_rect = r;\n            span_origin = origin;\n\n        }\n        span_rect = fz_union_rect(span_rect, r);\n\n        if (raw) {  // make and append a char dict\n            char_dict = PyDict_New();\n            DICT_SETITEM_DROP(char_dict, dictkey_origin,\n                          JM_py_from_point(ch->origin));\n\n            DICT_SETITEM_DROP(char_dict, dictkey_bbox,\n                          JM_py_from_rect(r));\n\n            DICT_SETITEM_DROP(char_dict, dictkey_c,\n                          Py_BuildValue(\"C\", ch->c));\n\n            if (!char_list) {\n                char_list = PyList_New(0);\n            }\n            LIST_APPEND_DROP(char_list, char_dict);\n        } else {  // add character byte to buffer\n            JM_append_rune(ctx, buff, ch->c);\n        }\n    }\n    // all characters processed, now flush remaining span\n    if (span) {\n        if (raw) {\n            DICT_SETITEM_DROP(span, dictkey_chars, char_list);\n            char_list = NULL;\n        } else {\n            DICT_SETITEM_DROP(span, dictkey_text, JM_EscapeStrFromBuffer(ctx, buff));\n            fz_clear_buffer(ctx, buff);\n        }\n        DICT_SETITEM_DROP(span, dictkey_origin, JM_py_from_point(span_origin));\n        DICT_SETITEM_DROP(span, dictkey_bbox, JM_py_from_rect(span_rect));\n\n        if (!fz_is_empty_rect(span_rect)) {\n            LIST_APPEND_DROP(span_list, span);\n            line_rect = fz_union_rect(line_rect, span_rect);\n        } else {\n            Py_DECREF(span);\n        }\n        span = NULL;\n    }\n    if (!fz_is_empty_rect(line_rect)) {\n        DICT_SETITEM_DROP(line_dict, dictkey_spans, span_list);\n    } else {\n        DICT_SETITEM_DROP(line_dict, dictkey_spans, span_list);\n    }\n    return line_rect;\n}\n\nstatic void JM_make_image_block(fz_context *ctx, fz_stext_block *block, PyObject *block_dict)\n{\n    fz_image *image = block->u.i.image;\n    fz_buffer *buf = NULL, *freebuf = NULL;\n    fz_compressed_buffer *buffer = fz_compressed_image_buffer(ctx, image);\n    fz_var(buf);\n    fz_var(freebuf);\n    int n = fz_colorspace_n(ctx, image->colorspace);\n    int w = image->w;\n    int h = image->h;\n    const char *ext = NULL;\n    int type = FZ_IMAGE_UNKNOWN;\n    if (buffer)\n        type = buffer->params.type;\n    if (type < FZ_IMAGE_BMP || type == FZ_IMAGE_JBIG2)\n        type = FZ_IMAGE_UNKNOWN;\n    PyObject *bytes = NULL;\n    fz_var(bytes);\n    fz_try(ctx) {\n        if (buffer && type != FZ_IMAGE_UNKNOWN) {\n            buf = buffer->buffer;\n            ext = JM_image_extension(type);\n        } else {\n            buf = freebuf = fz_new_buffer_from_image_as_png(ctx, image, fz_default_color_params);\n            ext = \"png\";\n        }\n        bytes = JM_BinFromBuffer(ctx, buf);\n    }\n    fz_always(ctx) {\n        if (!bytes)\n            bytes = JM_BinFromChar(\"\");\n\n        DICT_SETITEM_DROP(block_dict, dictkey_width,\n                        Py_BuildValue(\"i\", w));\n        DICT_SETITEM_DROP(block_dict, dictkey_height,\n                        Py_BuildValue(\"i\", h));\n        DICT_SETITEM_DROP(block_dict, dictkey_ext,\n                        Py_BuildValue(\"s\", ext));\n        DICT_SETITEM_DROP(block_dict, dictkey_colorspace,\n                        Py_BuildValue(\"i\", n));\n        DICT_SETITEM_DROP(block_dict, dictkey_xres,\n                        Py_BuildValue(\"i\", image->xres));\n        DICT_SETITEM_DROP(block_dict, dictkey_yres,\n                        Py_BuildValue(\"i\", image->xres));\n        DICT_SETITEM_DROP(block_dict, dictkey_bpc,\n                        Py_BuildValue(\"i\", (int) image->bpc));\n        DICT_SETITEM_DROP(block_dict, dictkey_matrix,\n                        JM_py_from_matrix(block->u.i.transform));\n        DICT_SETITEM_DROP(block_dict, dictkey_size,\n                        Py_BuildValue(\"n\", PyBytes_Size(bytes)));\n        DICT_SETITEM_DROP(block_dict, dictkey_image, bytes);\n\n        fz_drop_buffer(ctx, freebuf);\n    }\n    fz_catch(ctx) {;}\n    return;\n}\n\nstatic void JM_make_text_block(fz_context *ctx, fz_stext_block *block, PyObject *block_dict, int raw, fz_buffer *buff, fz_rect tp_rect)\n{\n    fz_stext_line *line;\n    PyObject *line_list = PyList_New(0), *line_dict;\n    fz_rect block_rect = fz_empty_rect;\n    for (line = block->u.t.first_line; line; line = line->next) {\n        if (fz_is_empty_rect(fz_intersect_rect(tp_rect, line->bbox)) &&\n            !fz_is_infinite_rect(tp_rect)) {\n            continue;\n        }\n        line_dict = PyDict_New();\n        fz_rect line_rect = JM_make_spanlist(ctx, line_dict, line, raw, buff, tp_rect);\n        block_rect = fz_union_rect(block_rect, line_rect);\n        DICT_SETITEM_DROP(line_dict, dictkey_wmode,\n                    Py_BuildValue(\"i\", line->wmode));\n        DICT_SETITEM_DROP(line_dict, dictkey_dir, JM_py_from_point(line->dir));\n        DICT_SETITEM_DROP(line_dict, dictkey_bbox,\n                    JM_py_from_rect(line_rect));\n        LIST_APPEND_DROP(line_list, line_dict);\n    }\n    DICT_SETITEM_DROP(block_dict, dictkey_bbox, JM_py_from_rect(block_rect));\n    DICT_SETITEM_DROP(block_dict, dictkey_lines, line_list);\n    return;\n}\n\nvoid JM_make_textpage_dict(fz_context *ctx, fz_stext_page *tp, PyObject *page_dict, int raw)\n{\n    fz_stext_block *block;\n    fz_buffer *text_buffer = fz_new_buffer(ctx, 128);\n    PyObject *block_dict, *block_list = PyList_New(0);\n    fz_rect tp_rect = tp->mediabox;\n    int block_n = -1;\n    for (block = tp->first_block; block; block = block->next) {\n        block_n++;\n        if (!fz_contains_rect(tp_rect, block->bbox) &&\n            !fz_is_infinite_rect(tp_rect) &&\n            block->type == FZ_STEXT_BLOCK_IMAGE) {\n            continue;\n        }\n        if (!fz_is_infinite_rect(tp_rect) &&\n            fz_is_empty_rect(fz_intersect_rect(tp_rect, block->bbox))) {\n            continue;\n        }\n\n        block_dict = PyDict_New();\n        DICT_SETITEM_DROP(block_dict, dictkey_number, Py_BuildValue(\"i\", block_n));\n        DICT_SETITEM_DROP(block_dict, dictkey_type, Py_BuildValue(\"i\", block->type));\n        if (block->type == FZ_STEXT_BLOCK_IMAGE) {\n            DICT_SETITEM_DROP(block_dict, dictkey_bbox, JM_py_from_rect(block->bbox));\n            JM_make_image_block(ctx, block, block_dict);\n        } else {\n            JM_make_text_block(ctx, block, block_dict, raw, text_buffer, tp_rect);\n        }\n\n        LIST_APPEND_DROP(block_list, block_dict);\n    }\n    DICT_SETITEM_DROP(page_dict, dictkey_blocks, block_list);\n    fz_drop_buffer(ctx, text_buffer);\n}\n\n\n\n//---------------------------------------------------------------------\nPyObject *\nJM_copy_rectangle(fz_context *ctx, fz_stext_page *page, fz_rect area)\n{\n\tfz_stext_block *block;\n\tfz_stext_line *line;\n\tfz_stext_char *ch;\n\tfz_buffer *buffer;\n\tint need_new_line = 0;\n\tPyObject *rc = NULL;\n\tfz_try(ctx) {\n        buffer = fz_new_buffer(ctx, 1024);\n\t\tfor (block = page->first_block; block; block = block->next) {\n\t\t\tif (block->type != FZ_STEXT_BLOCK_TEXT)\n\t\t\t\tcontinue;\n\t\t\tfor (line = block->u.t.first_line; line; line = line->next) {\n\t\t\t\tint line_had_text = 0;\n\t\t\t\tfor (ch = line->first_char; ch; ch = ch->next) {\n\t\t\t\t\tfz_rect r = JM_char_bbox(ctx, line, ch);\n\t\t\t\t\tif (JM_rects_overlap(area, r)) {\n\t\t\t\t\t\tline_had_text = 1;\n\t\t\t\t\t\tif (need_new_line) {\n\t\t\t\t\t\t\tfz_append_string(ctx, buffer, \"\\n\");\n\t\t\t\t\t\t\tneed_new_line = 0;\n\t\t\t\t\t\t}\n\t\t\t\t\t\tJM_append_rune(ctx, buffer, ch->c);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tif (line_had_text)\n\t\t\t\t\tneed_new_line = 1;\n\t\t\t}\n\t\t}\n\t\tfz_terminate_buffer(ctx, buffer);\n        rc = JM_EscapeStrFromBuffer(ctx, buffer);\n        if (!rc) {\n            rc = EMPTY_STRING;\n            PyErr_Clear();\n        }\n\t}\n    fz_always(ctx) {\n        fz_drop_buffer(ctx, buffer);\n        }\n\tfz_catch(ctx) {\n\t\tfz_rethrow(ctx);\n\t}\n\treturn rc;\n}\n//---------------------------------------------------------------------\n\n\n\n\nfz_buffer *JM_object_to_buffer(fz_context *ctx, pdf_obj *what, int compress, int ascii)\n{\n    fz_buffer *res=NULL;\n    fz_output *out=NULL;\n    fz_try(ctx) {\n        res = fz_new_buffer(ctx, 512);\n        out = fz_new_output_with_buffer(ctx, res);\n        pdf_print_obj(ctx, out, what, compress, ascii);\n    }\n    fz_always(ctx) {\n        fz_drop_output(ctx, out);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    fz_terminate_buffer(ctx, res);\n    return res;\n}\n\n//-----------------------------------------------------------------------------\n// Merge the /Resources object created by a text pdf device into the page.\n// The device may have created multiple /ExtGState/Alp? and /Font/F? objects.\n// These need to be renamed (renumbered) to not overwrite existing page\n// objects from previous executions.\n// Returns the next available numbers n, m for objects /Alp<n>, /F<m>.\n//-----------------------------------------------------------------------------\nPyObject *JM_merge_resources(fz_context *ctx, pdf_page *page, pdf_obj *temp_res)\n{\n    // page objects /Resources, /Resources/ExtGState, /Resources/Font\n    pdf_obj *resources = pdf_dict_get(ctx, page->obj, PDF_NAME(Resources));\n    pdf_obj *main_extg = pdf_dict_get(ctx, resources, PDF_NAME(ExtGState));\n    pdf_obj *main_fonts = pdf_dict_get(ctx, resources, PDF_NAME(Font));\n\n    // text pdf device objects /ExtGState, /Font\n    pdf_obj *temp_extg = pdf_dict_get(ctx, temp_res, PDF_NAME(ExtGState));\n    pdf_obj *temp_fonts = pdf_dict_get(ctx, temp_res, PDF_NAME(Font));\n\n\n    int max_alp = -1, max_fonts = -1, i, n;\n    char text[20];\n\n    // Handle /Alp objects\n    if (pdf_is_dict(ctx, temp_extg))  // any created at all?\n    {\n        n = pdf_dict_len(ctx, temp_extg);\n        if (pdf_is_dict(ctx, main_extg)) {  // does page have /ExtGState yet?\n            for (i = 0; i < pdf_dict_len(ctx, main_extg); i++) {\n                // get highest number of objects named /Alpxxx\n                char *alp = (char *) pdf_to_name(ctx, pdf_dict_get_key(ctx, main_extg, i));\n                if (strncmp(alp, \"Alp\", 3) != 0) continue;\n                int j = fz_atoi(alp + 3);\n                if (j > max_alp) max_alp = j;\n            }\n        }\n        else  // create a /ExtGState for the page\n            main_extg = pdf_dict_put_dict(ctx, resources, PDF_NAME(ExtGState), n);\n\n        max_alp += 1;\n        for (i = 0; i < n; i++)  // copy over renumbered /Alp objects\n        {\n            char *alp = (char *) pdf_to_name(ctx, pdf_dict_get_key(ctx, temp_extg, i));\n            int j = fz_atoi(alp + 3) + max_alp;\n            fz_snprintf(text, sizeof(text), \"Alp%d\", j);  // new name\n            pdf_obj *val = pdf_dict_get_val(ctx, temp_extg, i);\n            pdf_dict_puts(ctx, main_extg, text, val);\n        }\n    }\n\n\n    if (pdf_is_dict(ctx, main_fonts)) { // has page any fonts yet?\n        for (i = 0; i < pdf_dict_len(ctx, main_fonts); i++) { // get max font number\n            char *font = (char *) pdf_to_name(ctx, pdf_dict_get_key(ctx, main_fonts, i));\n            if (strncmp(font, \"F\", 1) != 0) continue;\n            int j = fz_atoi(font + 1);\n            if (j > max_fonts) max_fonts = j;\n        }\n    }\n    else  // create a Resources/Font for the page\n        main_fonts = pdf_dict_put_dict(ctx, resources, PDF_NAME(Font), 2);\n\n    max_fonts += 1;\n    for (i = 0; i < pdf_dict_len(ctx, temp_fonts); i++) { // copy renumbered fonts\n        char *font = (char *) pdf_to_name(ctx, pdf_dict_get_key(ctx, temp_fonts, i));\n        int j = fz_atoi(font + 1) + max_fonts;\n        fz_snprintf(text, sizeof(text), \"F%d\", j);\n        pdf_obj *val = pdf_dict_get_val(ctx, temp_fonts, i);\n        pdf_dict_puts(ctx, main_fonts, text, val);\n    }\n    return Py_BuildValue(\"ii\", max_alp, max_fonts); // next available numbers\n}\n\n\n//-----------------------------------------------------------------------------\n// version of fz_show_string, which covers SMALL CAPS\n//-----------------------------------------------------------------------------\nfz_matrix\nJM_show_string_cs(fz_context *ctx, fz_text *text, fz_font *user_font, fz_matrix trm, const char *s,\n\tint wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language)\n{\n\tfz_font *font=NULL;\n\tint gid, ucs;\n\tfloat adv;\n\n\twhile (*s)\n\t{\n\t\ts += fz_chartorune(&ucs, s);\n        gid = fz_encode_character_sc(ctx, user_font, ucs);\n        if (gid == 0) {\n\t\t    gid = fz_encode_character_with_fallback(ctx, user_font, ucs, 0, language, &font);\n        } else {\n            font = user_font;\n        }\n\t\tfz_show_glyph(ctx, text, font, trm, gid, ucs, wmode, bidi_level, markup_dir, language);\n\t\tadv = fz_advance_glyph(ctx, font, gid, wmode);\n\t\tif (wmode == 0)\n\t\t\ttrm = fz_pre_translate(trm, adv, 0);\n\t\telse\n\t\t\ttrm = fz_pre_translate(trm, 0, -adv);\n\t}\n\n\treturn trm;\n}\n\n\n//-----------------------------------------------------------------------------\n// version of fz_show_string, which also covers UCDN script\n//-----------------------------------------------------------------------------\nfz_matrix JM_show_string(fz_context *ctx, fz_text *text, fz_font *user_font, fz_matrix trm, const char *s, int wmode, int bidi_level, fz_bidi_direction markup_dir, fz_text_language language, int script)\n{\n    fz_font *font;\n    int gid, ucs;\n    float adv;\n\n    while (*s) {\n        s += fz_chartorune(&ucs, s);\n        gid = fz_encode_character_with_fallback(ctx, user_font, ucs, script, language, &font);\n        fz_show_glyph(ctx, text, font, trm, gid, ucs, wmode, bidi_level, markup_dir, language);\n        adv = fz_advance_glyph(ctx, font, gid, wmode);\n        if (wmode == 0)\n            trm = fz_pre_translate(trm, adv, 0);\n        else\n            trm = fz_pre_translate(trm, 0, -adv);\n    }\n    return trm;\n}\n\n\n//-----------------------------------------------------------------------------\n// return a fz_font from a number of parameters\n//-----------------------------------------------------------------------------\nfz_font *JM_get_font(fz_context *ctx,\n    char *fontname,\n    char *fontfile,\n    PyObject *fontbuffer,\n    int script,\n    int lang,\n    int ordering,\n    int is_bold,\n    int is_italic,\n    int is_serif,\n    int embed)\n{\n    const unsigned char *data = NULL;\n    int size, index=0;\n    fz_buffer *res = NULL;\n    fz_font *font = NULL;\n    fz_try(ctx) {\n        if (fontfile) goto have_file;\n        if (EXISTS(fontbuffer)) goto have_buffer;\n        if (ordering > -1) goto have_cjk;\n        if (fontname) goto have_base14;\n        goto have_noto;\n\n        // Base-14 or a MuPDF builtin font\n        have_base14:;\n        font = fz_new_base14_font(ctx, fontname);\n        if (font) {\n            goto fertig;\n        }\n        font = fz_new_builtin_font(ctx, fontname, is_bold, is_italic);\n        goto fertig;\n\n        // CJK font\n        have_cjk:;\n        font = fz_new_cjk_font(ctx, ordering);\n        goto fertig;\n\n        // fontfile\n        have_file:;\n        font = fz_new_font_from_file(ctx, NULL, fontfile, index, 0);\n        goto fertig;\n\n        // fontbuffer\n        have_buffer:;\n        res = JM_BufferFromBytes(ctx, fontbuffer);\n        font = fz_new_font_from_buffer(ctx, NULL, res, index, 0);\n        goto fertig;\n\n        // Check for NOTO font\n        have_noto:;\n        data = fz_lookup_noto_font(ctx, script, lang, &size, &index);\n        if (data) font = fz_new_font_from_memory(ctx, NULL, data, size, index, 0);\n        if (font) goto fertig;\n        font = fz_load_fallback_font(ctx, script, lang, is_serif, is_bold, is_italic);\n        goto fertig;\n\n        fertig:;\n        if (!font) {\n            RAISEPY(ctx, MSG_FONT_FAILED, PyExc_RuntimeError);\n        }\n        #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n        // if font allows this, set embedding\n        if (!font->flags.never_embed) {\n            fz_set_font_embedding(ctx, font, embed);\n        }\n        #endif\n    }\n    fz_always(ctx) {\n        fz_drop_buffer(ctx, res);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return font;\n}\n\n%}\n"
  },
  {
    "path": "src_classic/helper-xobject.i",
    "content": "%{\n/*\n# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\n*/\n//-----------------------------------------------------------------------------\n// Read and concatenate a PDF page's /Conents object(s) in a buffer\n//-----------------------------------------------------------------------------\nfz_buffer *JM_read_contents(fz_context * ctx, pdf_obj * pageref)\n{\n    fz_buffer *res = NULL, *nres = NULL;\n    int i;\n    fz_try(ctx) {\n        pdf_obj *contents = pdf_dict_get(ctx, pageref, PDF_NAME(Contents));\n        if (pdf_is_array(ctx, contents)) {\n            res = fz_new_buffer(ctx, 1024);\n            for (i = 0; i < pdf_array_len(ctx, contents); i++) {\n                nres = pdf_load_stream(ctx, pdf_array_get(ctx, contents, i));\n                fz_append_buffer(ctx, res, nres);\n                fz_drop_buffer(ctx, nres);\n            }\n        }\n        else if (contents) {\n            res = pdf_load_stream(ctx, contents);\n        }\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return res;\n}\n\n//-----------------------------------------------------------------------------\n// Make an XObject from a PDF page\n// For a positive xref assume that its object can be used instead\n//-----------------------------------------------------------------------------\npdf_obj *JM_xobject_from_page(fz_context * ctx, pdf_document * pdfout, fz_page * fsrcpage, int xref, pdf_graft_map *gmap)\n{\n    pdf_obj *xobj1, *resources = NULL, *o, *spageref;\n    fz_try(ctx) {\n        if (xref > 0) {\n            xobj1 = pdf_new_indirect(ctx, pdfout, xref, 0);\n        } else {\n            fz_buffer *res = NULL;\n            fz_rect mediabox;\n            pdf_page *srcpage = pdf_page_from_fz_page(ctx, fsrcpage);\n            spageref = srcpage->obj;\n            mediabox = pdf_to_rect(ctx, pdf_dict_get_inheritable(ctx, spageref, PDF_NAME(MediaBox)));\n            // Deep-copy resources object of source page\n            o = pdf_dict_get_inheritable(ctx, spageref, PDF_NAME(Resources));\n            if (gmap) // use graftmap when possible\n                resources = pdf_graft_mapped_object(ctx, gmap, o);\n            else\n                resources = pdf_graft_object(ctx, pdfout, o);\n\n            // get spgage contents source\n            res = JM_read_contents(ctx, spageref);\n\n            //-------------------------------------------------------------\n            // create XObject representing the source page\n            //-------------------------------------------------------------\n            xobj1 = pdf_new_xobject(ctx, pdfout, mediabox, fz_identity, NULL, res);\n            // store spage contents\n            JM_update_stream(ctx, pdfout, xobj1, res, 1);\n            fz_drop_buffer(ctx, res);\n\n            // store spage resources\n            pdf_dict_put_drop(ctx, xobj1, PDF_NAME(Resources), resources);\n        }\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return xobj1;\n}\n\n//-----------------------------------------------------------------------------\n// Insert a buffer as a new separate /Contents object of a page.\n// 1. Create a new stream object from buffer 'newcont'\n// 2. If /Contents already is an array, then just prepend or append this object\n// 3. Else, create new array and put old content obj and this object into it.\n//    If the page had no /Contents before, just create a 1-item array.\n//-----------------------------------------------------------------------------\nint JM_insert_contents(fz_context * ctx, pdf_document * pdf,\n                        pdf_obj * pageref, fz_buffer * newcont, int overlay)\n{\n    int xref = 0;\n    pdf_obj *newconts = NULL;\n    pdf_obj *carr = NULL;\n    fz_var(newconts);\n    fz_var(carr);\n    fz_try(ctx) {\n        pdf_obj *contents = pdf_dict_get(ctx, pageref, PDF_NAME(Contents));\n        newconts = pdf_add_stream(ctx, pdf, newcont, NULL, 0);\n        xref = pdf_to_num(ctx, newconts);\n        if (pdf_is_array(ctx, contents)) {\n            if (overlay) // append new object\n                pdf_array_push(ctx, contents, newconts);\n            else // prepend new object\n                pdf_array_insert(ctx, contents, newconts, 0);\n        } else {\n            carr = pdf_new_array(ctx, pdf, 5);\n            if (overlay) {\n                if (contents)\n                    pdf_array_push(ctx, carr, contents);\n                pdf_array_push(ctx, carr, newconts);\n            } else {\n                pdf_array_push(ctx, carr, newconts);\n                if (contents)\n                    pdf_array_push(ctx, carr, contents);\n            }\n            pdf_dict_put(ctx, pageref, PDF_NAME(Contents), carr);\n        }\n    }\n    fz_always(ctx) {\n        pdf_drop_obj(ctx, newconts);\n        pdf_drop_obj(ctx, carr);\n    }\n    fz_catch(ctx) {\n        fz_rethrow(ctx);\n    }\n    return xref;\n}\n\nstatic void show(const char* prefix, PyObject* obj)\n{\n    if (!obj)\n    {\n        printf( \"%s <null>\\n\", prefix);\n        return;\n    }\n    PyObject* obj_repr = PyObject_Repr( obj);\n    PyObject* obj_repr_u = PyUnicode_AsEncodedString( obj_repr, \"utf-8\", \"~E~\");\n    const char* obj_repr_s = PyString_AsString( obj_repr_u);\n    printf( \"%s%s\\n\", prefix, obj_repr_s);\n    fflush(stdout);\n}\n\nstatic PyObject *g_img_info = NULL;\nstatic fz_matrix g_img_info_matrix = {0};\n\nstatic fz_image *\nJM_image_filter(fz_context *ctx, void *opaque, fz_matrix ctm, const char *name, fz_image *image)\n{\n    fz_quad q = fz_transform_quad(fz_quad_from_rect(fz_unit_rect), ctm);\n    #if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n    q = fz_transform_quad( q, g_img_info_matrix);\n    #endif\n    PyObject *temp = Py_BuildValue(\"sN\", name, JM_py_from_quad(q));\n    \n    LIST_APPEND_DROP(g_img_info, temp);\n    return image;\n}\n\n#if FZ_VERSION_MAJOR == 1 && FZ_VERSION_MINOR >= 22\n\nstatic PyObject *\nJM_image_reporter(fz_context *ctx, pdf_page *page)\n{\n    pdf_document *doc = page->doc;\n    \n    pdf_page_transform(ctx, page, NULL, &g_img_info_matrix);\n    pdf_filter_options filter_options = {0};\n    filter_options.recurse = 0;\n    filter_options.instance_forms = 1;\n    filter_options.ascii = 1;\n    filter_options.no_update = 1;\n    \n    pdf_sanitize_filter_options sanitize_filter_options = {0};\n    sanitize_filter_options.opaque = page;\n    sanitize_filter_options.image_filter = JM_image_filter;\n    \n    pdf_filter_factory filter_factory[2] = {0};\n    filter_factory[0].filter = pdf_new_sanitize_filter;\n    filter_factory[0].options = &sanitize_filter_options;\n    \n    filter_options.filters = filter_factory; // was &\n    \n    g_img_info = PyList_New(0);\n    \n    pdf_filter_page_contents(ctx, doc, page, &filter_options);\n    \n    PyObject *rc = PySequence_Tuple(g_img_info);\n    Py_CLEAR(g_img_info);\n    \n    return rc;\n}\n\n#else\n\nvoid\nJM_filter_content_stream(\n    fz_context * ctx,\n    pdf_document * doc,\n    pdf_obj * in_stm,\n    pdf_obj * in_res,\n    fz_matrix transform,\n    pdf_filter_options * filter,\n    int struct_parents,\n    fz_buffer **out_buf,\n    pdf_obj **out_res)\n{\n    pdf_processor *proc_buffer = NULL;\n    pdf_processor *proc_filter = NULL;\n\n    fz_var(proc_buffer);\n    fz_var(proc_filter);\n\n    *out_buf = NULL;\n    *out_res = NULL;\n\n    fz_try(ctx) {\n\t\t*out_buf = fz_new_buffer(ctx, 1024);\n\t\tproc_buffer = pdf_new_buffer_processor(ctx, *out_buf, filter->ascii);\n\t\tif (filter->sanitize) {\n\t\t\t*out_res = pdf_new_dict(ctx, doc, 1);\n\t\t\tproc_filter = pdf_new_filter_processor(ctx, doc, proc_buffer, in_res, *out_res, struct_parents, transform, filter);\n\t\t\tpdf_process_contents(ctx, proc_filter, doc, in_res, in_stm, NULL);\n\t\t\tpdf_close_processor(ctx, proc_filter);\n\t\t} else {\n\t\t\t*out_res = pdf_keep_obj(ctx, in_res);\n\t\t\tpdf_process_contents(ctx, proc_buffer, doc, in_res, in_stm, NULL);\n\t\t}\n\t\tpdf_close_processor(ctx, proc_buffer);\n    }\n    fz_always(ctx) {\n        pdf_drop_processor(ctx, proc_filter);\n        pdf_drop_processor(ctx, proc_buffer);\n    }\n    fz_catch(ctx) {\n        fz_drop_buffer(ctx, *out_buf);\n        *out_buf = NULL;\n        pdf_drop_obj(ctx, *out_res);\n        *out_res = NULL;\n        fz_rethrow(ctx);\n    }\n}\n\nPyObject *\nJM_image_reporter(fz_context *ctx, pdf_page *page)\n{\n    pdf_document *doc = page->doc;\n    pdf_filter_options filter;\n    memset(&filter, 0, sizeof filter);\n    filter.opaque = page;\n    filter.text_filter = NULL;\n    filter.image_filter = JM_image_filter;\n    filter.end_page = NULL;\n    filter.recurse = 0;\n    filter.instance_forms = 1;\n    filter.sanitize = 1;\n    filter.ascii = 1;\n\n    pdf_obj *contents, *old_res;\n    pdf_obj *struct_parents_obj;\n    pdf_obj *new_res;\n    fz_buffer *buffer;\n    int struct_parents;\n    fz_matrix ctm = fz_identity;\n    pdf_page_transform(ctx, page, NULL, &ctm);\n    struct_parents_obj = pdf_dict_get(ctx, page->obj, PDF_NAME(StructParents));\n    struct_parents = -1;\n    if (pdf_is_number(ctx, struct_parents_obj))\n        struct_parents = pdf_to_int(ctx, struct_parents_obj);\n\n    contents = pdf_page_contents(ctx, page);\n    old_res = pdf_page_resources(ctx, page);\n    g_img_info = PyList_New(0);\n    JM_filter_content_stream(ctx, doc, contents, old_res, ctm, &filter, struct_parents, &buffer, &new_res);\n    fz_drop_buffer(ctx, buffer);\n    pdf_drop_obj(ctx, new_res);\n    PyObject *rc = PySequence_Tuple(g_img_info);\n    Py_CLEAR(g_img_info);\n    return rc;\n}\n\n#endif\n\n%}\n"
  },
  {
    "path": "src_classic/utils.py",
    "content": "# ------------------------------------------------------------------------\n# Copyright 2020-2022, Harald Lieder, mailto:harald.lieder@outlook.com\n# License: GNU AFFERO GPL 3.0, https://www.gnu.org/licenses/agpl-3.0.html\n#\n# Part of \"PyMuPDF\", a Python binding for \"MuPDF\" (http://mupdf.com), a\n# lightweight PDF, XPS, and E-book viewer, renderer and toolkit which is\n# maintained and developed by Artifex Software, Inc. https://artifex.com.\n# ------------------------------------------------------------------------\nimport io\nimport json\nimport math\nimport os\nimport random\nimport string\nimport tempfile\nimport typing\nimport warnings\n\nfrom fitz_old import *\n\nTESSDATA_PREFIX = os.getenv(\"TESSDATA_PREFIX\")\npoint_like = \"point_like\"\nrect_like = \"rect_like\"\nmatrix_like = \"matrix_like\"\nquad_like = \"quad_like\"\n\n# ByteString is gone from typing in 3.14.\n# collections.abc.Buffer available from 3.12 only\ntry:\n    ByteString = typing.ByteString\nexcept AttributeError:\n    ByteString = bytes | bytearray | memoryview\n\nAnyType = typing.Any\nOptInt = typing.Union[int, None]\nOptFloat = typing.Optional[float]\nOptStr = typing.Optional[str]\nOptDict = typing.Optional[dict]\nOptBytes = typing.Optional[ByteString]\nOptSeq = typing.Optional[typing.Sequence]\n\n\"\"\"\nThis is a collection of functions to extend PyMupdf.\n\"\"\"\n\n\ndef write_text(page: Page, **kwargs) -> None:\n    \"\"\"Write the text of one or more TextWriter objects.\n\n    Args:\n        rect: target rectangle. If None, the union of the text writers is used.\n        writers: one or more TextWriter objects.\n        overlay: put in foreground or background.\n        keep_proportion: maintain aspect ratio of rectangle sides.\n        rotate: arbitrary rotation angle.\n        oc: the xref of an optional content object\n    \"\"\"\n    if type(page) is not Page:\n        raise ValueError(\"bad page parameter\")\n    s = {\n        k\n        for k in kwargs.keys()\n        if k\n        not in {\n            \"rect\",\n            \"writers\",\n            \"opacity\",\n            \"color\",\n            \"overlay\",\n            \"keep_proportion\",\n            \"rotate\",\n            \"oc\",\n        }\n    }\n    if s != set():\n        raise ValueError(\"bad keywords: \" + str(s))\n\n    rect = kwargs.get(\"rect\")\n    writers = kwargs.get(\"writers\")\n    opacity = kwargs.get(\"opacity\")\n    color = kwargs.get(\"color\")\n    overlay = bool(kwargs.get(\"overlay\", True))\n    keep_proportion = bool(kwargs.get(\"keep_proportion\", True))\n    rotate = int(kwargs.get(\"rotate\", 0))\n    oc = int(kwargs.get(\"oc\", 0))\n\n    if not writers:\n        raise ValueError(\"need at least one TextWriter\")\n    if type(writers) is TextWriter:\n        if rotate == 0 and rect is None:\n            writers.write_text(page, opacity=opacity, color=color, overlay=overlay)\n            return None\n        else:\n            writers = (writers,)\n    clip = writers[0].text_rect\n    textdoc = Document()\n    tpage = textdoc.new_page(width=page.rect.width, height=page.rect.height)\n    for writer in writers:\n        clip |= writer.text_rect\n        writer.write_text(tpage, opacity=opacity, color=color)\n    if rect is None:\n        rect = clip\n    page.show_pdf_page(\n        rect,\n        textdoc,\n        0,\n        overlay=overlay,\n        keep_proportion=keep_proportion,\n        rotate=rotate,\n        clip=clip,\n        oc=oc,\n    )\n    textdoc = None\n    tpage = None\n\n\ndef show_pdf_page(*args, **kwargs) -> int:\n    \"\"\"Show page number 'pno' of PDF 'src' in rectangle 'rect'.\n\n    Args:\n        rect: (rect-like) where to place the source image\n        src: (document) source PDF\n        pno: (int) source page number\n        overlay: (bool) put in foreground\n        keep_proportion: (bool) do not change width-height-ratio\n        rotate: (int) degrees (multiple of 90)\n        clip: (rect-like) part of source page rectangle\n    Returns:\n        xref of inserted object (for reuse)\n    \"\"\"\n    if len(args) not in (3, 4):\n        raise ValueError(\"bad number of positional parameters\")\n    pno = None\n    if len(args) == 3:\n        page, rect, src = args\n    else:\n        page, rect, src, pno = args\n    if pno == None:\n        pno = int(kwargs.get(\"pno\", 0))\n    overlay = bool(kwargs.get(\"overlay\", True))\n    keep_proportion = bool(kwargs.get(\"keep_proportion\", True))\n    rotate = float(kwargs.get(\"rotate\", 0))\n    oc = int(kwargs.get(\"oc\", 0))\n    clip = kwargs.get(\"clip\")\n\n    def calc_matrix(sr, tr, keep=True, rotate=0):\n        \"\"\"Calculate transformation matrix from source to target rect.\n\n        Notes:\n            The product of four matrices in this sequence: (1) translate correct\n            source corner to origin, (2) rotate, (3) scale, (4) translate to\n            target's top-left corner.\n        Args:\n            sr: source rect in PDF (!) coordinate system\n            tr: target rect in PDF coordinate system\n            keep: whether to keep source ratio of width to height\n            rotate: rotation angle in degrees\n        Returns:\n            Transformation matrix.\n        \"\"\"\n        # calc center point of source rect\n        smp = (sr.tl + sr.br) / 2.0\n        # calc center point of target rect\n        tmp = (tr.tl + tr.br) / 2.0\n\n        # m moves to (0, 0), then rotates\n        m = Matrix(1, 0, 0, 1, -smp.x, -smp.y) * Matrix(rotate)\n\n        sr1 = sr * m  # resulting source rect to calculate scale factors\n\n        fw = tr.width / sr1.width  # scale the width\n        fh = tr.height / sr1.height  # scale the height\n        if keep:\n            fw = fh = min(fw, fh)  # take min if keeping aspect ratio\n\n        m *= Matrix(fw, fh)  # concat scale matrix\n        m *= Matrix(1, 0, 0, 1, tmp.x, tmp.y)  # concat move to target center\n        return JM_TUPLE(m)\n\n    CheckParent(page)\n    doc = page.parent\n\n    if not doc.is_pdf or not src.is_pdf:\n        raise ValueError(\"is no PDF\")\n\n    if rect.is_empty or rect.is_infinite:\n        raise ValueError(\"rect must be finite and not empty\")\n\n    while pno < 0:  # support negative page numbers\n        pno += src.page_count\n    src_page = src[pno]  # load source page\n    if src_page.get_contents() == []:\n        raise ValueError(\"nothing to show - source page empty\")\n\n    tar_rect = rect * ~page.transformation_matrix  # target rect in PDF coordinates\n\n    src_rect = src_page.rect if not clip else src_page.rect & clip  # source rect\n    if src_rect.is_empty or src_rect.is_infinite:\n        raise ValueError(\"clip must be finite and not empty\")\n    src_rect = src_rect * ~src_page.transformation_matrix  # ... in PDF coord\n\n    matrix = calc_matrix(src_rect, tar_rect, keep=keep_proportion, rotate=rotate)\n\n    # list of existing /Form /XObjects\n    ilst = [i[1] for i in doc.get_page_xobjects(page.number)]\n    ilst += [i[7] for i in doc.get_page_images(page.number)]\n    ilst += [i[4] for i in doc.get_page_fonts(page.number)]\n\n    # create a name not in that list\n    n = \"fzFrm\"\n    i = 0\n    _imgname = n + \"0\"\n    while _imgname in ilst:\n        i += 1\n        _imgname = n + str(i)\n\n    isrc = src._graft_id  # used as key for graftmaps\n    if doc._graft_id == isrc:\n        raise ValueError(\"source document must not equal target\")\n\n    # retrieve / make Graftmap for source PDF\n    gmap = doc.Graftmaps.get(isrc, None)\n    if gmap is None:\n        gmap = Graftmap(doc)\n        doc.Graftmaps[isrc] = gmap\n\n    # take note of generated xref for automatic reuse\n    pno_id = (isrc, pno)  # id of src[pno]\n    xref = doc.ShownPages.get(pno_id, 0)\n\n    xref = page._show_pdf_page(\n        src_page,\n        overlay=overlay,\n        matrix=matrix,\n        xref=xref,\n        oc=oc,\n        clip=src_rect,\n        graftmap=gmap,\n        _imgname=_imgname,\n    )\n    doc.ShownPages[pno_id] = xref\n\n    return xref\n\n\ndef replace_image(page: Page, xref: int, *, filename=None, pixmap=None, stream=None):\n    \"\"\"Replace the image referred to by xref.\n\n    Replace the image by changing the object definition stored under xref. This\n    will leave the pages appearance instructions intact, so the new image is\n    being displayed with the same bbox, rotation etc.\n    By providing a small fully transparent image, an effect as if the image had\n    been deleted can be achieved.\n    A typical use may include replacing large images by a smaller version,\n    e.g. with a lower resolution or graylevel instead of colored.\n\n    Args:\n        xref: the xref of the image to replace.\n        filename, pixmap, stream: exactly one of these must be provided. The\n            meaning being the same as in Page.insert_image.\n    \"\"\"\n    doc = page.parent  # the owning document\n    if not doc.xref_is_image(xref):\n        raise ValueError(\"xref not an image\")  # insert new image anywhere in page\n    if bool(filename) + bool(stream) + bool(pixmap) != 1:\n        raise ValueError(\"Exactly one of filename/stream/pixmap must be given\")\n    new_xref = page.insert_image(\n        page.rect, filename=filename, stream=stream, pixmap=pixmap\n    )\n    doc.xref_copy(new_xref, xref)  # copy over new to old\n    last_contents_xref = page.get_contents()[-1]\n    # new image insertion has created a new /Contents source,\n    # which we will set to spaces now\n    doc.update_stream(last_contents_xref, b\" \")\n\n\ndef delete_image(page: Page, xref: int):\n    \"\"\"Delete the image referred to by xef.\n\n    Actually replaces by a small transparent Pixmap using method Page.replace_image.\n\n    Args:\n        xref: xref of the image to delete.\n    \"\"\"\n    # make a small 100% transparent pixmap (of just any dimension)\n    pix = fitz_old.Pixmap(fitz_old.csGRAY, (0, 0, 1, 1), 1)\n    pix.clear_with()  # clear all samples bytes to 0x00\n    page.replace_image(xref, pixmap=pix)\n\n\ndef insert_image(page, rect, **kwargs):\n    \"\"\"Insert an image for display in a rectangle.\n\n    Args:\n        rect: (rect_like) position of image on the page.\n        alpha: (int, optional) set to 0 if image has no transparency.\n        filename: (str, Path, file object) image filename.\n        keep_proportion: (bool) keep width / height ratio (default).\n        mask: (bytes, optional) image consisting of alpha values to use.\n        oc: (int) xref of OCG or OCMD to declare as Optional Content.\n        overlay: (bool) put in foreground (default) or background.\n        pixmap: (Pixmap) use this as image.\n        rotate: (int) rotate by 0, 90, 180 or 270 degrees.\n        stream: (bytes) use this as image.\n        xref: (int) use this as image.\n\n    'page' and 'rect' are positional, all other parameters are keywords.\n\n    If 'xref' is given, that image is used. Other input options are ignored.\n    Else, exactly one of pixmap, stream or filename must be given.\n\n    'alpha=0' for non-transparent images improves performance significantly.\n    Affects stream and filename only.\n\n    Optimum transparent insertions are possible by using filename / stream in\n    conjunction with a 'mask' image of alpha values.\n\n    Returns:\n        xref (int) of inserted image. Re-use as argument for multiple insertions.\n    \"\"\"\n    CheckParent(page)\n    doc = page.parent\n    if not doc.is_pdf:\n        raise ValueError(\"is no PDF\")\n\n    valid_keys = {\n        \"alpha\",\n        \"filename\",\n        \"height\",\n        \"keep_proportion\",\n        \"mask\",\n        \"oc\",\n        \"overlay\",\n        \"pixmap\",\n        \"rotate\",\n        \"stream\",\n        \"width\",\n        \"xref\",\n    }\n    s = set(kwargs.keys()).difference(valid_keys)\n    if s != set():\n        raise ValueError(f\"bad key argument(s): {s}.\")\n    filename = kwargs.get(\"filename\")\n    pixmap = kwargs.get(\"pixmap\")\n    stream = kwargs.get(\"stream\")\n    mask = kwargs.get(\"mask\")\n    rotate = int(kwargs.get(\"rotate\", 0))\n    width = int(kwargs.get(\"width\", 0))\n    height = int(kwargs.get(\"height\", 0))\n    alpha = int(kwargs.get(\"alpha\", -1))\n    oc = int(kwargs.get(\"oc\", 0))\n    xref = int(kwargs.get(\"xref\", 0))\n    keep_proportion = bool(kwargs.get(\"keep_proportion\", True))\n    overlay = bool(kwargs.get(\"overlay\", True))\n\n    if xref == 0 and (bool(filename) + bool(stream) + bool(pixmap) != 1):\n        raise ValueError(\"xref=0 needs exactly one of filename, pixmap, stream\")\n\n    if filename:\n        if type(filename) is str:\n            pass\n        elif hasattr(filename, \"absolute\"):\n            filename = str(filename)\n        elif hasattr(filename, \"name\"):\n            filename = filename.name\n        else:\n            raise ValueError(\"bad filename\")\n\n    if filename and not os.path.exists(filename):\n        raise FileNotFoundError(\"No such file: '%s'\" % filename)\n    elif stream and type(stream) not in (bytes, bytearray, io.BytesIO):\n        raise ValueError(\"stream must be bytes-like / BytesIO\")\n    elif pixmap and type(pixmap) is not Pixmap:\n        raise ValueError(\"pixmap must be a Pixmap\")\n    if mask and not (stream or filename):\n        raise ValueError(\"mask requires stream or filename\")\n    if mask and type(mask) not in (bytes, bytearray, io.BytesIO):\n        raise ValueError(\"mask must be bytes-like / BytesIO\")\n    while rotate < 0:\n        rotate += 360\n    while rotate >= 360:\n        rotate -= 360\n    if rotate not in (0, 90, 180, 270):\n        raise ValueError(\"bad rotate value\")\n\n    r = Rect(rect)\n    if r.is_empty or r.is_infinite:\n        raise ValueError(\"rect must be finite and not empty\")\n    clip = r * ~page.transformation_matrix\n\n    # Create a unique image reference name.\n    ilst = [i[7] for i in doc.get_page_images(page.number)]\n    ilst += [i[1] for i in doc.get_page_xobjects(page.number)]\n    ilst += [i[4] for i in doc.get_page_fonts(page.number)]\n    n = \"fzImg\"  # 'fitz image'\n    i = 0\n    _imgname = n + \"0\"  # first name candidate\n    while _imgname in ilst:\n        i += 1\n        _imgname = n + str(i)  # try new name\n\n    digests = doc.InsertedImages\n    xref, digests = page._insert_image(\n        filename=filename,\n        pixmap=pixmap,\n        stream=stream,\n        imask=mask,\n        clip=clip,\n        overlay=overlay,\n        oc=oc,\n        xref=xref,\n        rotate=rotate,\n        keep_proportion=keep_proportion,\n        width=width,\n        height=height,\n        alpha=alpha,\n        _imgname=_imgname,\n        digests=digests,\n    )\n    if digests != None:\n        doc.InsertedImages = digests\n\n    return xref\n\n\ndef search_for(*args, **kwargs) -> list:\n    \"\"\"Search for a string on a page.\n\n    Args:\n        text: string to be searched for\n        clip: restrict search to this rectangle\n        quads: (bool) return quads instead of rectangles\n        flags: bit switches, default: join hyphened words\n        textpage: a pre-created TextPage\n    Returns:\n        a list of rectangles or quads, each containing one occurrence.\n    \"\"\"\n    if len(args) != 2:\n        raise ValueError(\"bad number of positional parameters\")\n    page, text = args\n    quads = kwargs.get(\"quads\", 0)\n    clip = kwargs.get(\"clip\")\n    textpage = kwargs.get(\"textpage\")\n    if clip != None:\n        clip = Rect(clip)\n    flags = kwargs.get(\n        \"flags\",\n        TEXT_DEHYPHENATE\n        | TEXT_PRESERVE_WHITESPACE\n        | TEXT_PRESERVE_LIGATURES\n        | TEXT_MEDIABOX_CLIP,\n    )\n\n    CheckParent(page)\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=flags)  # create TextPage\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n    rlist = tp.search(text, quads=quads)\n    if textpage is None:\n        del tp\n    return rlist\n\n\ndef search_page_for(\n    doc: Document,\n    pno: int,\n    text: str,\n    quads: bool = False,\n    clip: rect_like = None,\n    flags: int = TEXT_DEHYPHENATE\n    | TEXT_PRESERVE_LIGATURES\n    | TEXT_PRESERVE_WHITESPACE\n    | TEXT_MEDIABOX_CLIP,\n    textpage: TextPage = None,\n) -> list:\n    \"\"\"Search for a string on a page.\n\n    Args:\n        pno: page number\n        text: string to be searched for\n        clip: restrict search to this rectangle\n        quads: (bool) return quads instead of rectangles\n        flags: bit switches, default: join hyphened words\n        textpage: reuse a prepared textpage\n    Returns:\n        a list of rectangles or quads, each containing an occurrence.\n    \"\"\"\n\n    return doc[pno].search_for(\n        text,\n        quads=quads,\n        clip=clip,\n        flags=flags,\n        textpage=textpage,\n    )\n\n\ndef get_text_blocks(\n    page: Page,\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: TextPage = None,\n    sort: bool = False,\n) -> list:\n    \"\"\"Return the text blocks on a page.\n\n    Notes:\n        Lines in a block are concatenated with line breaks.\n    Args:\n        flags: (int) control the amount of data parsed into the textpage.\n    Returns:\n        A list of the blocks. Each item contains the containing rectangle\n        coordinates, text lines, block type and running block number.\n    \"\"\"\n    CheckParent(page)\n    if flags is None:\n        flags = (\n            TEXT_PRESERVE_WHITESPACE\n            | TEXT_PRESERVE_IMAGES\n            | TEXT_PRESERVE_LIGATURES\n            | TEXT_MEDIABOX_CLIP\n        )\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=flags)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n\n    blocks = tp.extractBLOCKS()\n    if textpage is None:\n        del tp\n    if sort is True:\n        blocks.sort(key=lambda b: (b[3], b[0]))\n    return blocks\n\n\ndef get_text_words(\n    page: Page,\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: TextPage = None,\n    sort: bool = False,\n    delimiters=None,\n) -> list:\n    \"\"\"Return the text words as a list with the bbox for each word.\n\n    Args:\n        flags: (int) control the amount of data parsed into the textpage.\n        delimiters: (str,list) characters to use as word delimiters\n\n    Returns:\n        Word tuples (x0, y0, x1, y1, \"word\", bno, lno, wno).\n    \"\"\"\n    CheckParent(page)\n    if flags is None:\n        flags = TEXT_PRESERVE_WHITESPACE | TEXT_PRESERVE_LIGATURES | TEXT_MEDIABOX_CLIP\n\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=flags)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n\n    words = tp.extractWORDS(delimiters)\n    if textpage is None:\n        del tp\n    if sort is True:\n        words.sort(key=lambda w: (w[3], w[0]))\n\n    return words\n\n\ndef get_textbox(\n    page: Page,\n    rect: rect_like,\n    textpage: TextPage = None,\n) -> str:\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage()\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n    rc = tp.extractTextbox(rect)\n    if textpage is None:\n        del tp\n    return rc\n\n\ndef get_text_selection(\n    page: Page,\n    p1: point_like,\n    p2: point_like,\n    clip: rect_like = None,\n    textpage: TextPage = None,\n):\n    CheckParent(page)\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=TEXT_DEHYPHENATE)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n    rc = tp.extractSelection(p1, p2)\n    if textpage is None:\n        del tp\n    return rc\n\n\ndef get_textpage_ocr(\n    page: Page,\n    flags: int = 0,\n    language: str = \"eng\",\n    dpi: int = 72,\n    full: bool = False,\n    tessdata: str = None,\n) -> TextPage:\n    \"\"\"Create a Textpage from combined results of normal and OCR text parsing.\n\n    Args:\n        flags: (int) control content becoming part of the result.\n        language: (str) specify expected language(s). Deafault is \"eng\" (English).\n        dpi: (int) resolution in dpi, default 72.\n        full: (bool) whether to OCR the full page image, or only its images (default)\n    \"\"\"\n    CheckParent(page)\n    if not os.getenv(\"TESSDATA_PREFIX\") and not tessdata:\n        raise RuntimeError(\"No OCR support: TESSDATA_PREFIX not set\")\n\n    def full_ocr(page, dpi, language, flags):\n        zoom = dpi / 72\n        mat = Matrix(zoom, zoom)\n        pix = page.get_pixmap(matrix=mat)\n        ocr_pdf = Document(\n            \"pdf\",\n            pix.pdfocr_tobytes(compress=False, language=language, tessdata=tessdata),\n        )\n        ocr_page = ocr_pdf.load_page(0)\n        unzoom = page.rect.width / ocr_page.rect.width\n        ctm = Matrix(unzoom, unzoom) * page.derotation_matrix\n        tpage = ocr_page.get_textpage(flags=flags, matrix=ctm)\n        ocr_pdf.close()\n        pix = None\n        tpage.parent = weakref.proxy(page)\n        return tpage\n\n    # if OCR for the full page, OCR its pixmap @ desired dpi\n    if full is True:\n        return full_ocr(page, dpi, language, flags)\n\n    # For partial OCR, make a normal textpage, then extend it with text that\n    # is OCRed from each image.\n    # Because of this, we need the images flag bit set ON.\n    tpage = page.get_textpage(flags=flags)\n    for block in page.get_text(\"dict\", flags=TEXT_PRESERVE_IMAGES)[\"blocks\"]:\n        if block[\"type\"] != 1:  # only look at images\n            continue\n        bbox = Rect(block[\"bbox\"])\n        if bbox.width <= 3 or bbox.height <= 3:  # ignore tiny stuff\n            continue\n        try:\n            pix = Pixmap(block[\"image\"])  # get image pixmap\n            if pix.n - pix.alpha != 3:  # we need to convert this to RGB!\n                pix = Pixmap(csRGB, pix)\n            if pix.alpha:  # must remove alpha channel\n                pix = Pixmap(pix, 0)\n            imgdoc = Document(\n                \"pdf\", pix.pdfocr_tobytes(language=language, tessdata=tessdata)\n            )  # pdf with OCRed page\n            imgpage = imgdoc.load_page(0)  # read image as a page\n            pix = None\n            # compute matrix to transform coordinates back to that of 'page'\n            imgrect = imgpage.rect  # page size of image PDF\n            shrink = Matrix(1 / imgrect.width, 1 / imgrect.height)\n            mat = shrink * block[\"transform\"]\n            imgpage.extend_textpage(tpage, flags=0, matrix=mat)\n            imgdoc.close()\n        except RuntimeError:\n            tpage = None\n            print(\"Falling back to full page OCR\")\n            return full_ocr(page, dpi, language, flags)\n\n    return tpage\n\n\ndef get_image_info(page: Page, hashes: bool = False, xrefs: bool = False) -> list:\n    \"\"\"Extract image information only from a TextPage.\n\n    Args:\n        hashes: (bool) include MD5 hash for each image.\n        xrefs: (bool) try to find the xref for each image. Sets hashes to true.\n    \"\"\"\n    doc = page.parent\n    if xrefs and doc.is_pdf:\n        hashes = True\n    if not doc.is_pdf:\n        xrefs = False\n    imginfo = getattr(page, \"_image_info\", None)\n    if imginfo and not xrefs:\n        return imginfo\n    if not imginfo:\n        tp = page.get_textpage(flags=TEXT_PRESERVE_IMAGES)\n        imginfo = tp.extractIMGINFO(hashes=hashes)\n        del tp\n        if hashes:\n            page._image_info = imginfo\n    if not xrefs or not doc.is_pdf:\n        return imginfo\n    imglist = page.get_images()\n    digests = {}\n    for item in imglist:\n        xref = item[0]\n        pix = Pixmap(doc, xref)\n        digests[pix.digest] = xref\n        del pix\n    for i in range(len(imginfo)):\n        item = imginfo[i]\n        xref = digests.get(item[\"digest\"], 0)\n        item[\"xref\"] = xref\n        imginfo[i] = item\n    return imginfo\n\n\ndef get_image_rects(page: Page, name, transform=False) -> list:\n    \"\"\"Return list of image positions on a page.\n\n    Args:\n        name: (str, list, int) image identification. May be reference name, an\n              item of the page's image list or an xref.\n        transform: (bool) whether to also return the transformation matrix.\n    Returns:\n        A list of Rect objects or tuples of (Rect, Matrix) for all image\n        locations on the page.\n    \"\"\"\n    if type(name) in (list, tuple):\n        xref = name[0]\n    elif type(name) is int:\n        xref = name\n    else:\n        imglist = [i for i in page.get_images() if i[7] == name]\n        if imglist == []:\n            raise ValueError(\"bad image name\")\n        elif len(imglist) != 1:\n            raise ValueError(\"multiple image names found\")\n        xref = imglist[0][0]\n    pix = Pixmap(page.parent, xref)  # make pixmap of the image to compute MD5\n    digest = pix.digest\n    del pix\n    infos = page.get_image_info(hashes=True)\n    if not transform:\n        bboxes = [Rect(im[\"bbox\"]) for im in infos if im[\"digest\"] == digest]\n    else:\n        bboxes = [\n            (Rect(im[\"bbox\"]), Matrix(im[\"transform\"]))\n            for im in infos\n            if im[\"digest\"] == digest\n        ]\n    return bboxes\n\n\ndef get_text(\n    page: Page,\n    option: str = \"text\",\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: TextPage = None,\n    sort: bool = False,\n    delimiters=None,\n):\n    \"\"\"Extract text from a page or an annotation.\n\n    This is a unifying wrapper for various methods of the TextPage class.\n\n    Args:\n        option: (str) text, words, blocks, html, dict, json, rawdict, xhtml or xml.\n        clip: (rect-like) restrict output to this area.\n        flags: bit switches to e.g. exclude images or decompose ligatures.\n        textpage: reuse this TextPage and make no new one. If specified,\n            'flags' and 'clip' are ignored.\n\n    Returns:\n        the output of methods get_text_words / get_text_blocks or TextPage\n        methods extractText, extractHTML, extractDICT, extractJSON, extractRAWDICT,\n        extractXHTML or etractXML respectively.\n        Default and misspelling choice is \"text\".\n    \"\"\"\n    formats = {\n        \"text\": fitz.TEXTFLAGS_TEXT,\n        \"html\": fitz.TEXTFLAGS_HTML,\n        \"json\": fitz.TEXTFLAGS_DICT,\n        \"rawjson\": fitz.TEXTFLAGS_RAWDICT,\n        \"xml\": fitz.TEXTFLAGS_XML,\n        \"xhtml\": fitz.TEXTFLAGS_XHTML,\n        \"dict\": fitz.TEXTFLAGS_DICT,\n        \"rawdict\": fitz.TEXTFLAGS_RAWDICT,\n        \"words\": fitz.TEXTFLAGS_WORDS,\n        \"blocks\": fitz.TEXTFLAGS_BLOCKS,\n    }\n    option = option.lower()\n    if option not in formats:\n        option = \"text\"\n    if flags is None:\n        flags = formats[option]\n\n    if option == \"words\":\n        return get_text_words(\n            page,\n            clip=clip,\n            flags=flags,\n            textpage=textpage,\n            sort=sort,\n            delimiters=delimiters,\n        )\n    if option == \"blocks\":\n        return get_text_blocks(\n            page, clip=clip, flags=flags, textpage=textpage, sort=sort\n        )\n    CheckParent(page)\n    cb = None\n    if option in (\"html\", \"xml\", \"xhtml\"):  # no clipping for MuPDF functions\n        clip = page.cropbox\n    if clip != None:\n        clip = Rect(clip)\n        cb = None\n    elif type(page) is Page:\n        cb = page.cropbox\n\n    # TextPage with or without images\n    tp = textpage\n    if tp is None:\n        tp = page.get_textpage(clip=clip, flags=flags)\n    elif getattr(tp, \"parent\") != page:\n        raise ValueError(\"not a textpage of this page\")\n\n    if option == \"json\":\n        t = tp.extractJSON(cb=cb, sort=sort)\n    elif option == \"rawjson\":\n        t = tp.extractRAWJSON(cb=cb, sort=sort)\n    elif option == \"dict\":\n        t = tp.extractDICT(cb=cb, sort=sort)\n    elif option == \"rawdict\":\n        t = tp.extractRAWDICT(cb=cb, sort=sort)\n    elif option == \"html\":\n        t = tp.extractHTML()\n    elif option == \"xml\":\n        t = tp.extractXML()\n    elif option == \"xhtml\":\n        t = tp.extractXHTML()\n    else:\n        t = tp.extractText(sort=sort)\n\n    if textpage is None:\n        del tp\n    return t\n\n\ndef get_page_text(\n    doc: Document,\n    pno: int,\n    option: str = \"text\",\n    clip: rect_like = None,\n    flags: OptInt = None,\n    textpage: TextPage = None,\n    sort: bool = False,\n) -> typing.Any:\n    \"\"\"Extract a document page's text by page number.\n\n    Notes:\n        Convenience function calling page.get_text().\n    Args:\n        pno: page number\n        option: (str) text, words, blocks, html, dict, json, rawdict, xhtml or xml.\n    Returns:\n        output from page.TextPage().\n    \"\"\"\n    return doc[pno].get_text(option, clip=clip, flags=flags, sort=sort)\n\n\ndef get_pixmap(\n    page: Page,\n    *,\n    matrix: matrix_like = Identity,\n    dpi=None,\n    colorspace: Colorspace = csRGB,\n    clip: rect_like = None,\n    alpha: bool = False,\n    annots: bool = True,\n) -> Pixmap:\n    \"\"\"Create pixmap of page.\n\n    Keyword args:\n        matrix: Matrix for transformation (default: Identity).\n        dpi: desired dots per inch. If given, matrix is ignored.\n        colorspace: (str/Colorspace) cmyk, rgb, gray - case ignored, default csRGB.\n        clip: (irect-like) restrict rendering to this area.\n        alpha: (bool) whether to include alpha channel\n        annots: (bool) whether to also render annotations\n    \"\"\"\n    CheckParent(page)\n    if dpi:\n        zoom = dpi / 72\n        matrix = Matrix(zoom, zoom)\n\n    if type(colorspace) is str:\n        if colorspace.upper() == \"GRAY\":\n            colorspace = csGRAY\n        elif colorspace.upper() == \"CMYK\":\n            colorspace = csCMYK\n        else:\n            colorspace = csRGB\n    if colorspace.n not in (1, 3, 4):\n        raise ValueError(\"unsupported colorspace\")\n\n    dl = page.get_displaylist(annots=annots)\n    pix = dl.get_pixmap(matrix=matrix, colorspace=colorspace, alpha=alpha, clip=clip)\n    dl = None\n    if dpi:\n        pix.set_dpi(dpi, dpi)\n    return pix\n\n\ndef get_page_pixmap(\n    doc: Document,\n    pno: int,\n    *,\n    matrix: matrix_like = Identity,\n    dpi=None,\n    colorspace: Colorspace = csRGB,\n    clip: rect_like = None,\n    alpha: bool = False,\n    annots: bool = True,\n) -> Pixmap:\n    \"\"\"Create pixmap of document page by page number.\n\n    Notes:\n        Convenience function calling page.get_pixmap.\n    Args:\n        pno: (int) page number\n        matrix: Matrix for transformation (default: Identity).\n        colorspace: (str,Colorspace) rgb, rgb, gray - case ignored, default csRGB.\n        clip: (irect-like) restrict rendering to this area.\n        alpha: (bool) include alpha channel\n        annots: (bool) also render annotations\n    \"\"\"\n    return doc[pno].get_pixmap(\n        matrix=matrix,\n        dpi=dpi,\n        colorspace=colorspace,\n        clip=clip,\n        alpha=alpha,\n        annots=annots,\n    )\n\n\ndef getLinkDict(ln) -> dict:\n    nl = {\"kind\": ln.dest.kind, \"xref\": 0}\n    try:\n        nl[\"from\"] = ln.rect\n    except:\n        pass\n    pnt = Point(0, 0)\n    if ln.dest.flags & LINK_FLAG_L_VALID:\n        pnt.x = ln.dest.lt.x\n    if ln.dest.flags & LINK_FLAG_T_VALID:\n        pnt.y = ln.dest.lt.y\n\n    if ln.dest.kind == LINK_URI:\n        nl[\"uri\"] = ln.dest.uri\n\n    elif ln.dest.kind == LINK_GOTO:\n        nl[\"page\"] = ln.dest.page\n        nl[\"to\"] = pnt\n        if ln.dest.flags & LINK_FLAG_R_IS_ZOOM:\n            nl[\"zoom\"] = ln.dest.rb.x\n        else:\n            nl[\"zoom\"] = 0.0\n\n    elif ln.dest.kind == LINK_GOTOR:\n        nl[\"file\"] = ln.dest.fileSpec.replace(\"\\\\\", \"/\")\n        nl[\"page\"] = ln.dest.page\n        if ln.dest.page < 0:\n            nl[\"to\"] = ln.dest.dest\n        else:\n            nl[\"to\"] = pnt\n            if ln.dest.flags & LINK_FLAG_R_IS_ZOOM:\n                nl[\"zoom\"] = ln.dest.rb.x\n            else:\n                nl[\"zoom\"] = 0.0\n\n    elif ln.dest.kind == LINK_LAUNCH:\n        nl[\"file\"] = ln.dest.fileSpec.replace(\"\\\\\", \"/\")\n\n    elif ln.dest.kind == LINK_NAMED:\n        nl[\"name\"] = ln.dest.named\n\n    else:\n        nl[\"page\"] = ln.dest.page\n\n    return nl\n\n\ndef get_links(page: Page) -> list:\n    \"\"\"Create a list of all links contained in a PDF page.\n\n    Notes:\n        see PyMuPDF ducmentation for details.\n    \"\"\"\n\n    CheckParent(page)\n    ln = page.first_link\n    links = []\n    while ln:\n        nl = getLinkDict(ln)\n        links.append(nl)\n        ln = ln.next\n    if links != [] and page.parent.is_pdf:\n        linkxrefs = [x for x in page.annot_xrefs() if x[1] == PDF_ANNOT_LINK]\n        if len(linkxrefs) == len(links):\n            for i in range(len(linkxrefs)):\n                links[i][\"xref\"] = linkxrefs[i][0]\n                links[i][\"id\"] = linkxrefs[i][2]\n    return links\n\n\ndef get_toc(\n    doc: Document,\n    simple: bool = True,\n) -> list:\n    \"\"\"Create a table of contents.\n\n    Args:\n        simple: a bool to control output. Returns a list, where each entry consists of outline level, title, page number and link destination (if simple = False). For details see PyMuPDF's documentation.\n    \"\"\"\n\n    def recurse(olItem, liste, lvl):\n        \"\"\"Recursively follow the outline item chain and record item information in a list.\"\"\"\n        while olItem:\n            if olItem.title:\n                title = olItem.title\n            else:\n                title = \" \"\n\n            if not olItem.is_external:\n                if olItem.uri:\n                    if olItem.page == -1:\n                        resolve = doc.resolve_link(olItem.uri)\n                        page = resolve[0] + 1\n                    else:\n                        page = olItem.page + 1\n                else:\n                    page = -1\n            else:\n                page = -1\n\n            if not simple:\n                link = getLinkDict(olItem)\n                liste.append([lvl, title, page, link])\n            else:\n                liste.append([lvl, title, page])\n\n            if olItem.down:\n                liste = recurse(olItem.down, liste, lvl + 1)\n            olItem = olItem.next\n        return liste\n\n    # ensure document is open\n    if doc.is_closed:\n        raise ValueError(\"document closed\")\n    doc.init_doc()\n    olItem = doc.outline\n    if not olItem:\n        return []\n    lvl = 1\n    liste = []\n    toc = recurse(olItem, liste, lvl)\n    if doc.is_pdf and simple is False:\n        doc._extend_toc_items(toc)\n    return toc\n\n\ndef del_toc_item(\n    doc: Document,\n    idx: int,\n) -> None:\n    \"\"\"Delete TOC / bookmark item by index.\"\"\"\n    xref = doc.get_outline_xrefs()[idx]\n    doc._remove_toc_item(xref)\n\n\ndef set_toc_item(\n    doc: Document,\n    idx: int,\n    dest_dict: OptDict = None,\n    kind: OptInt = None,\n    pno: OptInt = None,\n    uri: OptStr = None,\n    title: OptStr = None,\n    to: point_like = None,\n    filename: OptStr = None,\n    zoom: float = 0,\n) -> None:\n    \"\"\"Update TOC item by index.\n\n    It allows changing the item's title and link destination.\n\n    Args:\n        idx: (int) desired index of the TOC list, as created by get_toc.\n        dest_dict: (dict) destination dictionary as created by get_toc(False).\n            Outrules all other parameters. If None, the remaining parameters\n            are used to make a dest dictionary.\n        kind: (int) kind of link (LINK_GOTO, etc.). If None, then only the\n            title will be updated. If LINK_NONE, the TOC item will be deleted.\n        pno: (int) page number (1-based like in get_toc). Required if LINK_GOTO.\n        uri: (str) the URL, required if LINK_URI.\n        title: (str) the new title. No change if None.\n        to: (point-like) destination on the target page. If omitted, (72, 36)\n            will be used as taget coordinates.\n        filename: (str) destination filename, required for LINK_GOTOR and\n            LINK_LAUNCH.\n        name: (str) a destination name for LINK_NAMED.\n        zoom: (float) a zoom factor for the target location (LINK_GOTO).\n    \"\"\"\n    xref = doc.get_outline_xrefs()[idx]\n    page_xref = 0\n    if type(dest_dict) is dict:\n        if dest_dict[\"kind\"] == LINK_GOTO:\n            pno = dest_dict[\"page\"]\n            page_xref = doc.page_xref(pno)\n            page_height = doc.page_cropbox(pno).height\n            to = dest_dict.get(\"to\", Point(72, 36))\n            to.y = page_height - to.y\n            dest_dict[\"to\"] = to\n        action = getDestStr(page_xref, dest_dict)\n        if not action.startswith(\"/A\"):\n            raise ValueError(\"bad bookmark dest\")\n        color = dest_dict.get(\"color\")\n        if color:\n            color = list(map(float, color))\n            if len(color) != 3 or min(color) < 0 or max(color) > 1:\n                raise ValueError(\"bad color value\")\n        bold = dest_dict.get(\"bold\", False)\n        italic = dest_dict.get(\"italic\", False)\n        flags = italic + 2 * bold\n        collapse = dest_dict.get(\"collapse\")\n        return doc._update_toc_item(\n            xref,\n            action=action[2:],\n            title=title,\n            color=color,\n            flags=flags,\n            collapse=collapse,\n        )\n\n    if kind == LINK_NONE:  # delete bookmark item\n        return doc.del_toc_item(idx)\n    if kind is None and title is None:  # treat as no-op\n        return None\n    if kind is None:  # only update title text\n        return doc._update_toc_item(xref, action=None, title=title)\n\n    if kind == LINK_GOTO:\n        if pno is None or pno not in range(1, doc.page_count + 1):\n            raise ValueError(\"bad page number\")\n        page_xref = doc.page_xref(pno - 1)\n        page_height = doc.page_cropbox(pno - 1).height\n        if to is None:\n            to = Point(72, page_height - 36)\n        else:\n            to = Point(to)\n            to.y = page_height - to.y\n\n    ddict = {\n        \"kind\": kind,\n        \"to\": to,\n        \"uri\": uri,\n        \"page\": pno,\n        \"file\": filename,\n        \"zoom\": zoom,\n    }\n    action = getDestStr(page_xref, ddict)\n    if action == \"\" or not action.startswith(\"/A\"):\n        raise ValueError(\"bad bookmark dest\")\n\n    return doc._update_toc_item(xref, action=action[2:], title=title)\n\n\ndef get_area(*args) -> float:\n    \"\"\"Calculate area of rectangle.\\nparameter is one of 'px' (default), 'in', 'cm', or 'mm'.\"\"\"\n    rect = args[0]\n    if len(args) > 1:\n        unit = args[1]\n    else:\n        unit = \"px\"\n    u = {\"px\": (1, 1), \"in\": (1.0, 72.0), \"cm\": (2.54, 72.0), \"mm\": (25.4, 72.0)}\n    f = (u[unit][0] / u[unit][1]) ** 2\n    return f * rect.width * rect.height\n\n\ndef set_metadata(doc: Document, m: dict) -> None:\n    \"\"\"Update the PDF /Info object.\n\n    Args:\n        m: a dictionary like doc.metadata.\n    \"\"\"\n    if not doc.is_pdf:\n        raise ValueError(\"is no PDF\")\n    if doc.is_closed or doc.is_encrypted:\n        raise ValueError(\"document closed or encrypted\")\n    if type(m) is not dict:\n        raise ValueError(\"bad metadata\")\n    keymap = {\n        \"author\": \"Author\",\n        \"producer\": \"Producer\",\n        \"creator\": \"Creator\",\n        \"title\": \"Title\",\n        \"format\": None,\n        \"encryption\": None,\n        \"creationDate\": \"CreationDate\",\n        \"modDate\": \"ModDate\",\n        \"subject\": \"Subject\",\n        \"keywords\": \"Keywords\",\n        \"trapped\": \"Trapped\",\n    }\n    valid_keys = set(keymap.keys())\n    diff_set = set(m.keys()).difference(valid_keys)\n    if diff_set != set():\n        msg = \"bad dict key(s): %s\" % diff_set\n        raise ValueError(msg)\n\n    t, temp = doc.xref_get_key(-1, \"Info\")\n    if t != \"xref\":\n        info_xref = 0\n    else:\n        info_xref = int(temp.replace(\"0 R\", \"\"))\n\n    if m == {} and info_xref == 0:  # nothing to do\n        return\n\n    if info_xref == 0:  # no prev metadata: get new xref\n        info_xref = doc.get_new_xref()\n        doc.update_object(info_xref, \"<<>>\")  # fill it with empty object\n        doc.xref_set_key(-1, \"Info\", \"%i 0 R\" % info_xref)\n    elif m == {}:  # remove existing metadata\n        doc.xref_set_key(-1, \"Info\", \"null\")\n        return\n\n    for key, val in [(k, v) for k, v in m.items() if keymap[k] != None]:\n        pdf_key = keymap[key]\n        if not bool(val) or val in (\"none\", \"null\"):\n            val = \"null\"\n        else:\n            val = get_pdf_str(val)\n        doc.xref_set_key(info_xref, pdf_key, val)\n    doc.init_doc()\n    return\n\n\ndef getDestStr(xref: int, ddict: dict) -> str:\n    \"\"\"Calculate the PDF action string.\n\n    Notes:\n        Supports Link annotations and outline items (bookmarks).\n    \"\"\"\n    if not ddict:\n        return \"\"\n    str_goto = \"/A<</S/GoTo/D[%i 0 R/XYZ %g %g %g]>>\"\n    str_gotor1 = \"/A<</S/GoToR/D[%s /XYZ %g %g %g]/F<</F%s/UF%s/Type/Filespec>>>>\"\n    str_gotor2 = \"/A<</S/GoToR/D%s/F<</F%s/UF%s/Type/Filespec>>>>\"\n    str_launch = \"/A<</S/Launch/F<</F%s/UF%s/Type/Filespec>>>>\"\n    str_uri = \"/A<</S/URI/URI%s>>\"\n\n    if type(ddict) in (int, float):\n        dest = str_goto % (xref, 0, ddict, 0)\n        return dest\n    d_kind = ddict.get(\"kind\", LINK_NONE)\n\n    if d_kind == LINK_NONE:\n        return \"\"\n\n    if ddict[\"kind\"] == LINK_GOTO:\n        d_zoom = ddict.get(\"zoom\", 0)\n        to = ddict.get(\"to\", Point(0, 0))\n        d_left, d_top = to\n        dest = str_goto % (xref, d_left, d_top, d_zoom)\n        return dest\n\n    if ddict[\"kind\"] == LINK_URI:\n        dest = str_uri % (get_pdf_str(ddict[\"uri\"]),)\n        return dest\n\n    if ddict[\"kind\"] == LINK_LAUNCH:\n        fspec = get_pdf_str(ddict[\"file\"])\n        dest = str_launch % (fspec, fspec)\n        return dest\n\n    if ddict[\"kind\"] == LINK_GOTOR and ddict[\"page\"] < 0:\n        fspec = get_pdf_str(ddict[\"file\"])\n        dest = str_gotor2 % (get_pdf_str(ddict[\"to\"]), fspec, fspec)\n        return dest\n\n    if ddict[\"kind\"] == LINK_GOTOR and ddict[\"page\"] >= 0:\n        fspec = get_pdf_str(ddict[\"file\"])\n        dest = str_gotor1 % (\n            ddict[\"page\"],\n            ddict[\"to\"].x,\n            ddict[\"to\"].y,\n            ddict[\"zoom\"],\n            fspec,\n            fspec,\n        )\n        return dest\n\n    return \"\"\n\n\ndef set_toc(\n    doc: Document,\n    toc: list,\n    collapse: int = 1,\n) -> int:\n    \"\"\"Create new outline tree (table of contents, TOC).\n\n    Args:\n        toc: (list, tuple) each entry must contain level, title, page and\n            optionally top margin on the page. None or '()' remove the TOC.\n        collapse: (int) collapses entries beyond this level. Zero or None\n            shows all entries unfolded.\n    Returns:\n        the number of inserted items, or the number of removed items respectively.\n    \"\"\"\n    if doc.is_closed or doc.is_encrypted:\n        raise ValueError(\"document closed or encrypted\")\n    if not doc.is_pdf:\n        raise ValueError(\"is no PDF\")\n    if not toc:  # remove all entries\n        return len(doc._delToC())\n\n    # validity checks --------------------------------------------------------\n    if type(toc) not in (list, tuple):\n        raise ValueError(\"'toc' must be list or tuple\")\n    toclen = len(toc)\n    page_count = doc.page_count\n    t0 = toc[0]\n    if type(t0) not in (list, tuple):\n        raise ValueError(\"items must be sequences of 3 or 4 items\")\n    if t0[0] != 1:\n        raise ValueError(\"hierarchy level of item 0 must be 1\")\n    for i in list(range(toclen - 1)):\n        t1 = toc[i]\n        t2 = toc[i + 1]\n        if not -1 <= t1[2] <= page_count:\n            raise ValueError(\"row %i: page number out of range\" % i)\n        if (type(t2) not in (list, tuple)) or len(t2) not in (3, 4):\n            raise ValueError(\"bad row %i\" % (i + 1))\n        if (type(t2[0]) is not int) or t2[0] < 1:\n            raise ValueError(\"bad hierarchy level in row %i\" % (i + 1))\n        if t2[0] > t1[0] + 1:\n            raise ValueError(\"bad hierarchy level in row %i\" % (i + 1))\n    # no formal errors in toc --------------------------------------------------\n\n    # --------------------------------------------------------------------------\n    # make a list of xref numbers, which we can use for our TOC entries\n    # --------------------------------------------------------------------------\n    old_xrefs = doc._delToC()  # del old outlines, get their xref numbers\n\n    # prepare table of xrefs for new bookmarks\n    old_xrefs = []\n    xref = [0] + old_xrefs\n    xref[0] = doc._getOLRootNumber()  # entry zero is outline root xref number\n    if toclen > len(old_xrefs):  # too few old xrefs?\n        for i in range((toclen - len(old_xrefs))):\n            xref.append(doc.get_new_xref())  # acquire new ones\n\n    lvltab = {0: 0}  # to store last entry per hierarchy level\n\n    # ------------------------------------------------------------------------------\n    # contains new outline objects as strings - first one is the outline root\n    # ------------------------------------------------------------------------------\n    olitems = [{\"count\": 0, \"first\": -1, \"last\": -1, \"xref\": xref[0]}]\n    # ------------------------------------------------------------------------------\n    # build olitems as a list of PDF-like connnected dictionaries\n    # ------------------------------------------------------------------------------\n    for i in range(toclen):\n        o = toc[i]\n        lvl = o[0]  # level\n        title = get_pdf_str(o[1])  # title\n        pno = min(doc.page_count - 1, max(0, o[2] - 1))  # page number\n        page_xref = doc.page_xref(pno)\n        page_height = doc.page_cropbox(pno).height\n        top = Point(72, page_height - 36)\n        dest_dict = {\"to\": top, \"kind\": LINK_GOTO}  # fall back target\n        if o[2] < 0:\n            dest_dict[\"kind\"] = LINK_NONE\n        if len(o) > 3:  # some target is specified\n            if type(o[3]) in (int, float):  # convert a number to a point\n                dest_dict[\"to\"] = Point(72, page_height - o[3])\n            else:  # if something else, make sure we have a dict\n                dest_dict = o[3] if type(o[3]) is dict else dest_dict\n                if \"to\" not in dest_dict:  # target point not in dict?\n                    dest_dict[\"to\"] = top  # put default in\n                else:  # transform target to PDF coordinates\n                    point = +dest_dict[\"to\"]\n                    point.y = page_height - point.y\n                    dest_dict[\"to\"] = point\n        d = {}\n        d[\"first\"] = -1\n        d[\"count\"] = 0\n        d[\"last\"] = -1\n        d[\"prev\"] = -1\n        d[\"next\"] = -1\n        d[\"dest\"] = getDestStr(page_xref, dest_dict)\n        d[\"top\"] = dest_dict[\"to\"]\n        d[\"title\"] = title\n        d[\"parent\"] = lvltab[lvl - 1]\n        d[\"xref\"] = xref[i + 1]\n        d[\"color\"] = dest_dict.get(\"color\")\n        d[\"flags\"] = dest_dict.get(\"italic\", 0) + 2 * dest_dict.get(\"bold\", 0)\n        lvltab[lvl] = i + 1\n        parent = olitems[lvltab[lvl - 1]]  # the parent entry\n\n        if (\n            dest_dict.get(\"collapse\") or collapse and lvl > collapse\n        ):  # suppress expansion\n            parent[\"count\"] -= 1  # make /Count negative\n        else:\n            parent[\"count\"] += 1  # positive /Count\n\n        if parent[\"first\"] == -1:\n            parent[\"first\"] = i + 1\n            parent[\"last\"] = i + 1\n        else:\n            d[\"prev\"] = parent[\"last\"]\n            prev = olitems[parent[\"last\"]]\n            prev[\"next\"] = i + 1\n            parent[\"last\"] = i + 1\n        olitems.append(d)\n\n    # ------------------------------------------------------------------------------\n    # now create each outline item as a string and insert it in the PDF\n    # ------------------------------------------------------------------------------\n    for i, ol in enumerate(olitems):\n        txt = \"<<\"\n        if ol[\"count\"] != 0:\n            txt += \"/Count %i\" % ol[\"count\"]\n        try:\n            txt += ol[\"dest\"]\n        except:\n            pass\n        try:\n            if ol[\"first\"] > -1:\n                txt += \"/First %i 0 R\" % xref[ol[\"first\"]]\n        except:\n            pass\n        try:\n            if ol[\"last\"] > -1:\n                txt += \"/Last %i 0 R\" % xref[ol[\"last\"]]\n        except:\n            pass\n        try:\n            if ol[\"next\"] > -1:\n                txt += \"/Next %i 0 R\" % xref[ol[\"next\"]]\n        except:\n            pass\n        try:\n            if ol[\"parent\"] > -1:\n                txt += \"/Parent %i 0 R\" % xref[ol[\"parent\"]]\n        except:\n            pass\n        try:\n            if ol[\"prev\"] > -1:\n                txt += \"/Prev %i 0 R\" % xref[ol[\"prev\"]]\n        except:\n            pass\n        try:\n            txt += \"/Title\" + ol[\"title\"]\n        except:\n            pass\n\n        if ol.get(\"color\") and len(ol[\"color\"]) == 3:\n            txt += \"/C[ %g %g %g]\" % tuple(ol[\"color\"])\n        if ol.get(\"flags\", 0) > 0:\n            txt += \"/F %i\" % ol[\"flags\"]\n\n        if i == 0:  # special: this is the outline root\n            txt += \"/Type/Outlines\"  # so add the /Type entry\n        txt += \">>\"\n        doc.update_object(xref[i], txt)  # insert the PDF object\n\n    doc.init_doc()\n    return toclen\n\n\ndef do_links(\n    doc1: Document,\n    doc2: Document,\n    from_page: int = -1,\n    to_page: int = -1,\n    start_at: int = -1,\n) -> None:\n    \"\"\"Insert links contained in copied page range into destination PDF.\n\n    Parameter values **must** equal those of method insert_pdf(), which must\n    have been previously executed.\n    \"\"\"\n\n    # --------------------------------------------------------------------------\n    # internal function to create the actual \"/Annots\" object string\n    # --------------------------------------------------------------------------\n    def cre_annot(lnk, xref_dst, pno_src, ctm):\n        \"\"\"Create annotation object string for a passed-in link.\"\"\"\n\n        r = lnk[\"from\"] * ctm  # rect in PDF coordinates\n        rect = \"%g %g %g %g\" % tuple(r)\n        if lnk[\"kind\"] == LINK_GOTO:\n            txt = annot_skel[\"goto1\"]  # annot_goto\n            idx = pno_src.index(lnk[\"page\"])\n            p = lnk[\"to\"] * ctm  # target point in PDF coordinates\n            annot = txt % (xref_dst[idx], p.x, p.y, lnk[\"zoom\"], rect)\n\n        elif lnk[\"kind\"] == LINK_GOTOR:\n            if lnk[\"page\"] >= 0:\n                txt = annot_skel[\"gotor1\"]  # annot_gotor\n                pnt = lnk.get(\"to\", Point(0, 0))  # destination point\n                if type(pnt) is not Point:\n                    pnt = Point(0, 0)\n                annot = txt % (\n                    lnk[\"page\"],\n                    pnt.x,\n                    pnt.y,\n                    lnk[\"zoom\"],\n                    lnk[\"file\"],\n                    lnk[\"file\"],\n                    rect,\n                )\n            else:\n                txt = annot_skel[\"gotor2\"]  # annot_gotor_n\n                to = get_pdf_str(lnk[\"to\"])\n                to = to[1:-1]\n                f = lnk[\"file\"]\n                annot = txt % (to, f, rect)\n\n        elif lnk[\"kind\"] == LINK_LAUNCH:\n            txt = annot_skel[\"launch\"]  # annot_launch\n            annot = txt % (lnk[\"file\"], lnk[\"file\"], rect)\n\n        elif lnk[\"kind\"] == LINK_URI:\n            txt = annot_skel[\"uri\"]  # annot_uri\n            annot = txt % (lnk[\"uri\"], rect)\n\n        else:\n            annot = \"\"\n\n        return annot\n\n    # --------------------------------------------------------------------------\n\n    # validate & normalize parameters\n    if from_page < 0:\n        fp = 0\n    elif from_page >= doc2.page_count:\n        fp = doc2.page_count - 1\n    else:\n        fp = from_page\n\n    if to_page < 0 or to_page >= doc2.page_count:\n        tp = doc2.page_count - 1\n    else:\n        tp = to_page\n\n    if start_at < 0:\n        raise ValueError(\"'start_at' must be >= 0\")\n    sa = start_at\n\n    incr = 1 if fp <= tp else -1  # page range could be reversed\n\n    # lists of source / destination page numbers\n    pno_src = list(range(fp, tp + incr, incr))\n    pno_dst = [sa + i for i in range(len(pno_src))]\n\n    # lists of source / destination page xrefs\n    xref_src = []\n    xref_dst = []\n    for i in range(len(pno_src)):\n        p_src = pno_src[i]\n        p_dst = pno_dst[i]\n        old_xref = doc2.page_xref(p_src)\n        new_xref = doc1.page_xref(p_dst)\n        xref_src.append(old_xref)\n        xref_dst.append(new_xref)\n\n    # create the links for each copied page in destination PDF\n    for i in range(len(xref_src)):\n        page_src = doc2[pno_src[i]]  # load source page\n        links = page_src.get_links()  # get all its links\n        if len(links) == 0:  # no links there\n            page_src = None\n            continue\n        ctm = ~page_src.transformation_matrix  # calc page transformation matrix\n        page_dst = doc1[pno_dst[i]]  # load destination page\n        link_tab = []  # store all link definitions here\n        for l in links:\n            if l[\"kind\"] == LINK_GOTO and (l[\"page\"] not in pno_src):\n                continue  # GOTO link target not in copied pages\n            annot_text = cre_annot(l, xref_dst, pno_src, ctm)\n            if annot_text:\n                link_tab.append(annot_text)\n        if link_tab != []:\n            page_dst._addAnnot_FromString(tuple(link_tab))\n\n    return\n\n\ndef getLinkText(page: Page, lnk: dict) -> str:\n    # --------------------------------------------------------------------------\n    # define skeletons for /Annots object texts\n    # --------------------------------------------------------------------------\n    ctm = page.transformation_matrix\n    ictm = ~ctm\n    r = lnk[\"from\"]\n    rect = \"%g %g %g %g\" % tuple(r * ictm)\n\n    annot = \"\"\n    if lnk[\"kind\"] == LINK_GOTO:\n        if lnk[\"page\"] >= 0:\n            txt = annot_skel[\"goto1\"]  # annot_goto\n            pno = lnk[\"page\"]\n            xref = page.parent.page_xref(pno)\n            pnt = lnk.get(\"to\", Point(0, 0))  # destination point\n            ipnt = pnt * ictm\n            annot = txt % (xref, ipnt.x, ipnt.y, lnk.get(\"zoom\", 0), rect)\n        else:\n            txt = annot_skel[\"goto2\"]  # annot_goto_n\n            annot = txt % (get_pdf_str(lnk[\"to\"]), rect)\n\n    elif lnk[\"kind\"] == LINK_GOTOR:\n        if lnk[\"page\"] >= 0:\n            txt = annot_skel[\"gotor1\"]  # annot_gotor\n            pnt = lnk.get(\"to\", Point(0, 0))  # destination point\n            if type(pnt) is not Point:\n                pnt = Point(0, 0)\n            annot = txt % (\n                lnk[\"page\"],\n                pnt.x,\n                pnt.y,\n                lnk.get(\"zoom\", 0),\n                lnk[\"file\"],\n                lnk[\"file\"],\n                rect,\n            )\n        else:\n            txt = annot_skel[\"gotor2\"]  # annot_gotor_n\n            annot = txt % (get_pdf_str(lnk[\"to\"]), lnk[\"file\"], rect)\n\n    elif lnk[\"kind\"] == LINK_LAUNCH:\n        txt = annot_skel[\"launch\"]  # annot_launch\n        annot = txt % (lnk[\"file\"], lnk[\"file\"], rect)\n\n    elif lnk[\"kind\"] == LINK_URI:\n        txt = annot_skel[\"uri\"]  # txt = annot_uri\n        annot = txt % (lnk[\"uri\"], rect)\n\n    elif lnk[\"kind\"] == LINK_NAMED:\n        txt = annot_skel[\"named\"]  # annot_named\n        annot = txt % (lnk[\"name\"], rect)\n    if not annot:\n        return annot\n\n    # add a /NM PDF key to the object definition\n    link_names = dict(  # existing ids and their xref\n        [(x[0], x[2]) for x in page.annot_xrefs() if x[1] == PDF_ANNOT_LINK]\n    )\n\n    old_name = lnk.get(\"id\", \"\")  # id value in the argument\n\n    if old_name and (lnk[\"xref\"], old_name) in link_names.items():\n        name = old_name  # no new name if this is an update only\n    else:\n        i = 0\n        stem = TOOLS.set_annot_stem() + \"-L%i\"\n        while True:\n            name = stem % i\n            if name not in link_names.values():\n                break\n            i += 1\n    # add /NM key to object definition\n    annot = annot.replace(\"/Link\", \"/Link/NM(%s)\" % name)\n    return annot\n\n\ndef delete_widget(page: Page, widget: Widget) -> Widget:\n    \"\"\"Delete widget from page and return the next one.\"\"\"\n    CheckParent(page)\n    annot = getattr(widget, \"_annot\", None)\n    if annot is None:\n        raise ValueError(\"bad type: widget\")\n    nextwidget = widget.next\n    page.delete_annot(annot)\n    widget._annot.__del__()\n    widget._annot.parent = None\n    keylist = list(widget.__dict__.keys())\n    for key in keylist:\n        del widget.__dict__[key]\n    return nextwidget\n\n\ndef update_link(page: Page, lnk: dict) -> None:\n    \"\"\"Update a link on the current page.\"\"\"\n    CheckParent(page)\n    annot = getLinkText(page, lnk)\n    if annot == \"\":\n        raise ValueError(\"link kind not supported\")\n\n    page.parent.update_object(lnk[\"xref\"], annot, page=page)\n    return\n\n\ndef insert_link(page: Page, lnk: dict, mark: bool = True) -> None:\n    \"\"\"Insert a new link for the current page.\"\"\"\n    CheckParent(page)\n    annot = getLinkText(page, lnk)\n    if annot == \"\":\n        raise ValueError(\"link kind not supported\")\n    page._addAnnot_FromString((annot,))\n    return\n\n\ndef insert_textbox(\n    page: Page,\n    rect: rect_like,\n    buffer: typing.Union[str, list],\n    fontname: str = \"helv\",\n    fontfile: OptStr = None,\n    set_simple: int = 0,\n    encoding: int = 0,\n    fontsize: float = 11,\n    lineheight: OptFloat = None,\n    color: OptSeq = None,\n    fill: OptSeq = None,\n    expandtabs: int = 1,\n    align: int = 0,\n    rotate: int = 0,\n    render_mode: int = 0,\n    border_width: float = 0.05,\n    morph: OptSeq = None,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> float:\n    \"\"\"Insert text into a given rectangle.\n\n    Notes:\n        Creates a Shape object, uses its same-named method and commits it.\n    Parameters:\n        rect: (rect-like) area to use for text.\n        buffer: text to be inserted\n        fontname: a Base-14 font, font name or '/name'\n        fontfile: name of a font file\n        fontsize: font size\n        lineheight: overwrite the font property\n        color: RGB color triple\n        expandtabs: handles tabulators with string function\n        align: left, center, right, justified\n        rotate: 0, 90, 180, or 270 degrees\n        morph: morph box with a matrix and a fixpoint\n        overlay: put text in foreground or background\n    Returns:\n        unused or deficit rectangle area (float)\n    \"\"\"\n    img = page.new_shape()\n    rc = img.insert_textbox(\n        rect,\n        buffer,\n        fontsize=fontsize,\n        lineheight=lineheight,\n        fontname=fontname,\n        fontfile=fontfile,\n        set_simple=set_simple,\n        encoding=encoding,\n        color=color,\n        fill=fill,\n        expandtabs=expandtabs,\n        render_mode=render_mode,\n        border_width=border_width,\n        align=align,\n        rotate=rotate,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    if rc >= 0:\n        img.commit(overlay)\n    return rc\n\n\ndef insert_text(\n    page: Page,\n    point: point_like,\n    text: typing.Union[str, list],\n    fontsize: float = 11,\n    lineheight: OptFloat = None,\n    fontname: str = \"helv\",\n    fontfile: OptStr = None,\n    set_simple: int = 0,\n    encoding: int = 0,\n    color: OptSeq = None,\n    fill: OptSeq = None,\n    border_width: float = 0.05,\n    render_mode: int = 0,\n    rotate: int = 0,\n    morph: OptSeq = None,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n):\n    img = page.new_shape()\n    rc = img.insert_text(\n        point,\n        text,\n        fontsize=fontsize,\n        lineheight=lineheight,\n        fontname=fontname,\n        fontfile=fontfile,\n        set_simple=set_simple,\n        encoding=encoding,\n        color=color,\n        fill=fill,\n        border_width=border_width,\n        render_mode=render_mode,\n        rotate=rotate,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    if rc >= 0:\n        img.commit(overlay)\n    return rc\n\n\ndef new_page(\n    doc: Document,\n    pno: int = -1,\n    width: float = 595,\n    height: float = 842,\n) -> Page:\n    \"\"\"Create and return a new page object.\n\n    Args:\n        pno: (int) insert before this page. Default: after last page.\n        width: (float) page width in points. Default: 595 (ISO A4 width).\n        height: (float) page height in points. Default 842 (ISO A4 height).\n    Returns:\n        A Page object.\n    \"\"\"\n    doc._newPage(pno, width=width, height=height)\n    return doc[pno]\n\n\ndef insert_page(\n    doc: Document,\n    pno: int,\n    text: typing.Union[str, list, None] = None,\n    fontsize: float = 11,\n    width: float = 595,\n    height: float = 842,\n    fontname: str = \"helv\",\n    fontfile: OptStr = None,\n    color: OptSeq = (0,),\n) -> int:\n    \"\"\"Create a new PDF page and insert some text.\n\n    Notes:\n        Function combining Document.new_page() and Page.insert_text().\n        For parameter details see these methods.\n    \"\"\"\n    page = doc.new_page(pno=pno, width=width, height=height)\n    if not bool(text):\n        return 0\n    rc = page.insert_text(\n        (50, 72),\n        text,\n        fontsize=fontsize,\n        fontname=fontname,\n        fontfile=fontfile,\n        color=color,\n    )\n    return rc\n\n\ndef draw_line(\n    page: Page,\n    p1: point_like,\n    p2: point_like,\n    color: OptSeq = (0,),\n    dashes: OptStr = None,\n    width: float = 1,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    morph: OptSeq = None,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc=0,\n) -> Point:\n    \"\"\"Draw a line from point p1 to point p2.\"\"\"\n    img = page.new_shape()\n    p = img.draw_line(Point(p1), Point(p2))\n    img.finish(\n        color=color,\n        dashes=dashes,\n        width=width,\n        closePath=False,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return p\n\n\ndef draw_squiggle(\n    page: Page,\n    p1: point_like,\n    p2: point_like,\n    breadth: float = 2,\n    color: OptSeq = (0,),\n    dashes: OptStr = None,\n    width: float = 1,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    morph: OptSeq = None,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw a squiggly line from point p1 to point p2.\"\"\"\n    img = page.new_shape()\n    p = img.draw_squiggle(Point(p1), Point(p2), breadth=breadth)\n    img.finish(\n        color=color,\n        dashes=dashes,\n        width=width,\n        closePath=False,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return p\n\n\ndef draw_zigzag(\n    page: Page,\n    p1: point_like,\n    p2: point_like,\n    breadth: float = 2,\n    color: OptSeq = (0,),\n    dashes: OptStr = None,\n    width: float = 1,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    morph: OptSeq = None,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw a zigzag line from point p1 to point p2.\"\"\"\n    img = page.new_shape()\n    p = img.draw_zigzag(Point(p1), Point(p2), breadth=breadth)\n    img.finish(\n        color=color,\n        dashes=dashes,\n        width=width,\n        closePath=False,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return p\n\n\ndef draw_rect(\n    page: Page,\n    rect: rect_like,\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    dashes: OptStr = None,\n    width: float = 1,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    morph: OptSeq = None,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n    radius=None,\n) -> Point:\n    \"\"\"Draw a rectangle. See Shape class method for details.\"\"\"\n    img = page.new_shape()\n    Q = img.draw_rect(Rect(rect), radius=radius)\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return Q\n\n\ndef draw_quad(\n    page: Page,\n    quad: quad_like,\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    dashes: OptStr = None,\n    width: float = 1,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    morph: OptSeq = None,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw a quadrilateral.\"\"\"\n    img = page.new_shape()\n    Q = img.draw_quad(Quad(quad))\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return Q\n\n\ndef draw_polyline(\n    page: Page,\n    points: list,\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    dashes: OptStr = None,\n    width: float = 1,\n    morph: OptSeq = None,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    closePath: bool = False,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw multiple connected line segments.\"\"\"\n    img = page.new_shape()\n    Q = img.draw_polyline(points)\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        closePath=closePath,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return Q\n\n\ndef draw_circle(\n    page: Page,\n    center: point_like,\n    radius: float,\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    morph: OptSeq = None,\n    dashes: OptStr = None,\n    width: float = 1,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw a circle given its center and radius.\"\"\"\n    img = page.new_shape()\n    Q = img.draw_circle(Point(center), radius)\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n    return Q\n\n\ndef draw_oval(\n    page: Page,\n    rect: typing.Union[rect_like, quad_like],\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    dashes: OptStr = None,\n    morph: OptSeq = None,\n    width: float = 1,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw an oval given its containing rectangle or quad.\"\"\"\n    img = page.new_shape()\n    Q = img.draw_oval(rect)\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return Q\n\n\ndef draw_curve(\n    page: Page,\n    p1: point_like,\n    p2: point_like,\n    p3: point_like,\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    dashes: OptStr = None,\n    width: float = 1,\n    morph: OptSeq = None,\n    closePath: bool = False,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw a special Bezier curve from p1 to p3, generating control points on lines p1 to p2 and p2 to p3.\"\"\"\n    img = page.new_shape()\n    Q = img.draw_curve(Point(p1), Point(p2), Point(p3))\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        closePath=closePath,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return Q\n\n\ndef draw_bezier(\n    page: Page,\n    p1: point_like,\n    p2: point_like,\n    p3: point_like,\n    p4: point_like,\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    dashes: OptStr = None,\n    width: float = 1,\n    morph: OptStr = None,\n    closePath: bool = False,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw a general cubic Bezier curve from p1 to p4 using control points p2 and p3.\"\"\"\n    img = page.new_shape()\n    Q = img.draw_bezier(Point(p1), Point(p2), Point(p3), Point(p4))\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        closePath=closePath,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return Q\n\n\ndef draw_sector(\n    page: Page,\n    center: point_like,\n    point: point_like,\n    beta: float,\n    color: OptSeq = (0,),\n    fill: OptSeq = None,\n    dashes: OptStr = None,\n    fullSector: bool = True,\n    morph: OptSeq = None,\n    width: float = 1,\n    closePath: bool = False,\n    lineCap: int = 0,\n    lineJoin: int = 0,\n    overlay: bool = True,\n    stroke_opacity: float = 1,\n    fill_opacity: float = 1,\n    oc: int = 0,\n) -> Point:\n    \"\"\"Draw a circle sector given circle center, one arc end point and the angle of the arc.\n\n    Parameters:\n        center -- center of circle\n        point -- arc end point\n        beta -- angle of arc (degrees)\n        fullSector -- connect arc ends with center\n    \"\"\"\n    img = page.new_shape()\n    Q = img.draw_sector(Point(center), Point(point), beta, fullSector=fullSector)\n    img.finish(\n        color=color,\n        fill=fill,\n        dashes=dashes,\n        width=width,\n        lineCap=lineCap,\n        lineJoin=lineJoin,\n        morph=morph,\n        closePath=closePath,\n        stroke_opacity=stroke_opacity,\n        fill_opacity=fill_opacity,\n        oc=oc,\n    )\n    img.commit(overlay)\n\n    return Q\n\n\n# ----------------------------------------------------------------------\n# Name:        wx.lib.colourdb.py\n# Purpose:     Adds a bunch of colour names and RGB values to the\n#              colour database so they can be found by name\n#\n# Author:      Robin Dunn\n#\n# Created:     13-March-2001\n# Copyright:   (c) 2001-2017 by Total Control Software\n# Licence:     wxWindows license\n# Tags:        phoenix-port, unittest, documented\n# ----------------------------------------------------------------------\n\n\ndef getColorList() -> list:\n    \"\"\"\n    Returns a list of just the colour names used by this module.\n    :rtype: list of strings\n    \"\"\"\n\n    return [x[0] for x in getColorInfoList()]\n\n\ndef getColorInfoList() -> list:\n    \"\"\"\n    Returns the list of colour name/value tuples used by this module.\n    :rtype: list of tuples\n    \"\"\"\n\n    return [\n        (\"ALICEBLUE\", 240, 248, 255),\n        (\"ANTIQUEWHITE\", 250, 235, 215),\n        (\"ANTIQUEWHITE1\", 255, 239, 219),\n        (\"ANTIQUEWHITE2\", 238, 223, 204),\n        (\"ANTIQUEWHITE3\", 205, 192, 176),\n        (\"ANTIQUEWHITE4\", 139, 131, 120),\n        (\"AQUAMARINE\", 127, 255, 212),\n        (\"AQUAMARINE1\", 127, 255, 212),\n        (\"AQUAMARINE2\", 118, 238, 198),\n        (\"AQUAMARINE3\", 102, 205, 170),\n        (\"AQUAMARINE4\", 69, 139, 116),\n        (\"AZURE\", 240, 255, 255),\n        (\"AZURE1\", 240, 255, 255),\n        (\"AZURE2\", 224, 238, 238),\n        (\"AZURE3\", 193, 205, 205),\n        (\"AZURE4\", 131, 139, 139),\n        (\"BEIGE\", 245, 245, 220),\n        (\"BISQUE\", 255, 228, 196),\n        (\"BISQUE1\", 255, 228, 196),\n        (\"BISQUE2\", 238, 213, 183),\n        (\"BISQUE3\", 205, 183, 158),\n        (\"BISQUE4\", 139, 125, 107),\n        (\"BLACK\", 0, 0, 0),\n        (\"BLANCHEDALMOND\", 255, 235, 205),\n        (\"BLUE\", 0, 0, 255),\n        (\"BLUE1\", 0, 0, 255),\n        (\"BLUE2\", 0, 0, 238),\n        (\"BLUE3\", 0, 0, 205),\n        (\"BLUE4\", 0, 0, 139),\n        (\"BLUEVIOLET\", 138, 43, 226),\n        (\"BROWN\", 165, 42, 42),\n        (\"BROWN1\", 255, 64, 64),\n        (\"BROWN2\", 238, 59, 59),\n        (\"BROWN3\", 205, 51, 51),\n        (\"BROWN4\", 139, 35, 35),\n        (\"BURLYWOOD\", 222, 184, 135),\n        (\"BURLYWOOD1\", 255, 211, 155),\n        (\"BURLYWOOD2\", 238, 197, 145),\n        (\"BURLYWOOD3\", 205, 170, 125),\n        (\"BURLYWOOD4\", 139, 115, 85),\n        (\"CADETBLUE\", 95, 158, 160),\n        (\"CADETBLUE1\", 152, 245, 255),\n        (\"CADETBLUE2\", 142, 229, 238),\n        (\"CADETBLUE3\", 122, 197, 205),\n        (\"CADETBLUE4\", 83, 134, 139),\n        (\"CHARTREUSE\", 127, 255, 0),\n        (\"CHARTREUSE1\", 127, 255, 0),\n        (\"CHARTREUSE2\", 118, 238, 0),\n        (\"CHARTREUSE3\", 102, 205, 0),\n        (\"CHARTREUSE4\", 69, 139, 0),\n        (\"CHOCOLATE\", 210, 105, 30),\n        (\"CHOCOLATE1\", 255, 127, 36),\n        (\"CHOCOLATE2\", 238, 118, 33),\n        (\"CHOCOLATE3\", 205, 102, 29),\n        (\"CHOCOLATE4\", 139, 69, 19),\n        (\"COFFEE\", 156, 79, 0),\n        (\"CORAL\", 255, 127, 80),\n        (\"CORAL1\", 255, 114, 86),\n        (\"CORAL2\", 238, 106, 80),\n        (\"CORAL3\", 205, 91, 69),\n        (\"CORAL4\", 139, 62, 47),\n        (\"CORNFLOWERBLUE\", 100, 149, 237),\n        (\"CORNSILK\", 255, 248, 220),\n        (\"CORNSILK1\", 255, 248, 220),\n        (\"CORNSILK2\", 238, 232, 205),\n        (\"CORNSILK3\", 205, 200, 177),\n        (\"CORNSILK4\", 139, 136, 120),\n        (\"CYAN\", 0, 255, 255),\n        (\"CYAN1\", 0, 255, 255),\n        (\"CYAN2\", 0, 238, 238),\n        (\"CYAN3\", 0, 205, 205),\n        (\"CYAN4\", 0, 139, 139),\n        (\"DARKBLUE\", 0, 0, 139),\n        (\"DARKCYAN\", 0, 139, 139),\n        (\"DARKGOLDENROD\", 184, 134, 11),\n        (\"DARKGOLDENROD1\", 255, 185, 15),\n        (\"DARKGOLDENROD2\", 238, 173, 14),\n        (\"DARKGOLDENROD3\", 205, 149, 12),\n        (\"DARKGOLDENROD4\", 139, 101, 8),\n        (\"DARKGREEN\", 0, 100, 0),\n        (\"DARKGRAY\", 169, 169, 169),\n        (\"DARKKHAKI\", 189, 183, 107),\n        (\"DARKMAGENTA\", 139, 0, 139),\n        (\"DARKOLIVEGREEN\", 85, 107, 47),\n        (\"DARKOLIVEGREEN1\", 202, 255, 112),\n        (\"DARKOLIVEGREEN2\", 188, 238, 104),\n        (\"DARKOLIVEGREEN3\", 162, 205, 90),\n        (\"DARKOLIVEGREEN4\", 110, 139, 61),\n        (\"DARKORANGE\", 255, 140, 0),\n        (\"DARKORANGE1\", 255, 127, 0),\n        (\"DARKORANGE2\", 238, 118, 0),\n        (\"DARKORANGE3\", 205, 102, 0),\n        (\"DARKORANGE4\", 139, 69, 0),\n        (\"DARKORCHID\", 153, 50, 204),\n        (\"DARKORCHID1\", 191, 62, 255),\n        (\"DARKORCHID2\", 178, 58, 238),\n        (\"DARKORCHID3\", 154, 50, 205),\n        (\"DARKORCHID4\", 104, 34, 139),\n        (\"DARKRED\", 139, 0, 0),\n        (\"DARKSALMON\", 233, 150, 122),\n        (\"DARKSEAGREEN\", 143, 188, 143),\n        (\"DARKSEAGREEN1\", 193, 255, 193),\n        (\"DARKSEAGREEN2\", 180, 238, 180),\n        (\"DARKSEAGREEN3\", 155, 205, 155),\n        (\"DARKSEAGREEN4\", 105, 139, 105),\n        (\"DARKSLATEBLUE\", 72, 61, 139),\n        (\"DARKSLATEGRAY\", 47, 79, 79),\n        (\"DARKTURQUOISE\", 0, 206, 209),\n        (\"DARKVIOLET\", 148, 0, 211),\n        (\"DEEPPINK\", 255, 20, 147),\n        (\"DEEPPINK1\", 255, 20, 147),\n        (\"DEEPPINK2\", 238, 18, 137),\n        (\"DEEPPINK3\", 205, 16, 118),\n        (\"DEEPPINK4\", 139, 10, 80),\n        (\"DEEPSKYBLUE\", 0, 191, 255),\n        (\"DEEPSKYBLUE1\", 0, 191, 255),\n        (\"DEEPSKYBLUE2\", 0, 178, 238),\n        (\"DEEPSKYBLUE3\", 0, 154, 205),\n        (\"DEEPSKYBLUE4\", 0, 104, 139),\n        (\"DIMGRAY\", 105, 105, 105),\n        (\"DODGERBLUE\", 30, 144, 255),\n        (\"DODGERBLUE1\", 30, 144, 255),\n        (\"DODGERBLUE2\", 28, 134, 238),\n        (\"DODGERBLUE3\", 24, 116, 205),\n        (\"DODGERBLUE4\", 16, 78, 139),\n        (\"FIREBRICK\", 178, 34, 34),\n        (\"FIREBRICK1\", 255, 48, 48),\n        (\"FIREBRICK2\", 238, 44, 44),\n        (\"FIREBRICK3\", 205, 38, 38),\n        (\"FIREBRICK4\", 139, 26, 26),\n        (\"FLORALWHITE\", 255, 250, 240),\n        (\"FORESTGREEN\", 34, 139, 34),\n        (\"GAINSBORO\", 220, 220, 220),\n        (\"GHOSTWHITE\", 248, 248, 255),\n        (\"GOLD\", 255, 215, 0),\n        (\"GOLD1\", 255, 215, 0),\n        (\"GOLD2\", 238, 201, 0),\n        (\"GOLD3\", 205, 173, 0),\n        (\"GOLD4\", 139, 117, 0),\n        (\"GOLDENROD\", 218, 165, 32),\n        (\"GOLDENROD1\", 255, 193, 37),\n        (\"GOLDENROD2\", 238, 180, 34),\n        (\"GOLDENROD3\", 205, 155, 29),\n        (\"GOLDENROD4\", 139, 105, 20),\n        (\"GREEN YELLOW\", 173, 255, 47),\n        (\"GREEN\", 0, 255, 0),\n        (\"GREEN1\", 0, 255, 0),\n        (\"GREEN2\", 0, 238, 0),\n        (\"GREEN3\", 0, 205, 0),\n        (\"GREEN4\", 0, 139, 0),\n        (\"GREENYELLOW\", 173, 255, 47),\n        (\"GRAY\", 190, 190, 190),\n        (\"GRAY0\", 0, 0, 0),\n        (\"GRAY1\", 3, 3, 3),\n        (\"GRAY10\", 26, 26, 26),\n        (\"GRAY100\", 255, 255, 255),\n        (\"GRAY11\", 28, 28, 28),\n        (\"GRAY12\", 31, 31, 31),\n        (\"GRAY13\", 33, 33, 33),\n        (\"GRAY14\", 36, 36, 36),\n        (\"GRAY15\", 38, 38, 38),\n        (\"GRAY16\", 41, 41, 41),\n        (\"GRAY17\", 43, 43, 43),\n        (\"GRAY18\", 46, 46, 46),\n        (\"GRAY19\", 48, 48, 48),\n        (\"GRAY2\", 5, 5, 5),\n        (\"GRAY20\", 51, 51, 51),\n        (\"GRAY21\", 54, 54, 54),\n        (\"GRAY22\", 56, 56, 56),\n        (\"GRAY23\", 59, 59, 59),\n        (\"GRAY24\", 61, 61, 61),\n        (\"GRAY25\", 64, 64, 64),\n        (\"GRAY26\", 66, 66, 66),\n        (\"GRAY27\", 69, 69, 69),\n        (\"GRAY28\", 71, 71, 71),\n        (\"GRAY29\", 74, 74, 74),\n        (\"GRAY3\", 8, 8, 8),\n        (\"GRAY30\", 77, 77, 77),\n        (\"GRAY31\", 79, 79, 79),\n        (\"GRAY32\", 82, 82, 82),\n        (\"GRAY33\", 84, 84, 84),\n        (\"GRAY34\", 87, 87, 87),\n        (\"GRAY35\", 89, 89, 89),\n        (\"GRAY36\", 92, 92, 92),\n        (\"GRAY37\", 94, 94, 94),\n        (\"GRAY38\", 97, 97, 97),\n        (\"GRAY39\", 99, 99, 99),\n        (\"GRAY4\", 10, 10, 10),\n        (\"GRAY40\", 102, 102, 102),\n        (\"GRAY41\", 105, 105, 105),\n        (\"GRAY42\", 107, 107, 107),\n        (\"GRAY43\", 110, 110, 110),\n        (\"GRAY44\", 112, 112, 112),\n        (\"GRAY45\", 115, 115, 115),\n        (\"GRAY46\", 117, 117, 117),\n        (\"GRAY47\", 120, 120, 120),\n        (\"GRAY48\", 122, 122, 122),\n        (\"GRAY49\", 125, 125, 125),\n        (\"GRAY5\", 13, 13, 13),\n        (\"GRAY50\", 127, 127, 127),\n        (\"GRAY51\", 130, 130, 130),\n        (\"GRAY52\", 133, 133, 133),\n        (\"GRAY53\", 135, 135, 135),\n        (\"GRAY54\", 138, 138, 138),\n        (\"GRAY55\", 140, 140, 140),\n        (\"GRAY56\", 143, 143, 143),\n        (\"GRAY57\", 145, 145, 145),\n        (\"GRAY58\", 148, 148, 148),\n        (\"GRAY59\", 150, 150, 150),\n        (\"GRAY6\", 15, 15, 15),\n        (\"GRAY60\", 153, 153, 153),\n        (\"GRAY61\", 156, 156, 156),\n        (\"GRAY62\", 158, 158, 158),\n        (\"GRAY63\", 161, 161, 161),\n        (\"GRAY64\", 163, 163, 163),\n        (\"GRAY65\", 166, 166, 166),\n        (\"GRAY66\", 168, 168, 168),\n        (\"GRAY67\", 171, 171, 171),\n        (\"GRAY68\", 173, 173, 173),\n        (\"GRAY69\", 176, 176, 176),\n        (\"GRAY7\", 18, 18, 18),\n        (\"GRAY70\", 179, 179, 179),\n        (\"GRAY71\", 181, 181, 181),\n        (\"GRAY72\", 184, 184, 184),\n        (\"GRAY73\", 186, 186, 186),\n        (\"GRAY74\", 189, 189, 189),\n        (\"GRAY75\", 191, 191, 191),\n        (\"GRAY76\", 194, 194, 194),\n        (\"GRAY77\", 196, 196, 196),\n        (\"GRAY78\", 199, 199, 199),\n        (\"GRAY79\", 201, 201, 201),\n        (\"GRAY8\", 20, 20, 20),\n        (\"GRAY80\", 204, 204, 204),\n        (\"GRAY81\", 207, 207, 207),\n        (\"GRAY82\", 209, 209, 209),\n        (\"GRAY83\", 212, 212, 212),\n        (\"GRAY84\", 214, 214, 214),\n        (\"GRAY85\", 217, 217, 217),\n        (\"GRAY86\", 219, 219, 219),\n        (\"GRAY87\", 222, 222, 222),\n        (\"GRAY88\", 224, 224, 224),\n        (\"GRAY89\", 227, 227, 227),\n        (\"GRAY9\", 23, 23, 23),\n        (\"GRAY90\", 229, 229, 229),\n        (\"GRAY91\", 232, 232, 232),\n        (\"GRAY92\", 235, 235, 235),\n        (\"GRAY93\", 237, 237, 237),\n        (\"GRAY94\", 240, 240, 240),\n        (\"GRAY95\", 242, 242, 242),\n        (\"GRAY96\", 245, 245, 245),\n        (\"GRAY97\", 247, 247, 247),\n        (\"GRAY98\", 250, 250, 250),\n        (\"GRAY99\", 252, 252, 252),\n        (\"HONEYDEW\", 240, 255, 240),\n        (\"HONEYDEW1\", 240, 255, 240),\n        (\"HONEYDEW2\", 224, 238, 224),\n        (\"HONEYDEW3\", 193, 205, 193),\n        (\"HONEYDEW4\", 131, 139, 131),\n        (\"HOTPINK\", 255, 105, 180),\n        (\"HOTPINK1\", 255, 110, 180),\n        (\"HOTPINK2\", 238, 106, 167),\n        (\"HOTPINK3\", 205, 96, 144),\n        (\"HOTPINK4\", 139, 58, 98),\n        (\"INDIANRED\", 205, 92, 92),\n        (\"INDIANRED1\", 255, 106, 106),\n        (\"INDIANRED2\", 238, 99, 99),\n        (\"INDIANRED3\", 205, 85, 85),\n        (\"INDIANRED4\", 139, 58, 58),\n        (\"IVORY\", 255, 255, 240),\n        (\"IVORY1\", 255, 255, 240),\n        (\"IVORY2\", 238, 238, 224),\n        (\"IVORY3\", 205, 205, 193),\n        (\"IVORY4\", 139, 139, 131),\n        (\"KHAKI\", 240, 230, 140),\n        (\"KHAKI1\", 255, 246, 143),\n        (\"KHAKI2\", 238, 230, 133),\n        (\"KHAKI3\", 205, 198, 115),\n        (\"KHAKI4\", 139, 134, 78),\n        (\"LAVENDER\", 230, 230, 250),\n        (\"LAVENDERBLUSH\", 255, 240, 245),\n        (\"LAVENDERBLUSH1\", 255, 240, 245),\n        (\"LAVENDERBLUSH2\", 238, 224, 229),\n        (\"LAVENDERBLUSH3\", 205, 193, 197),\n        (\"LAVENDERBLUSH4\", 139, 131, 134),\n        (\"LAWNGREEN\", 124, 252, 0),\n        (\"LEMONCHIFFON\", 255, 250, 205),\n        (\"LEMONCHIFFON1\", 255, 250, 205),\n        (\"LEMONCHIFFON2\", 238, 233, 191),\n        (\"LEMONCHIFFON3\", 205, 201, 165),\n        (\"LEMONCHIFFON4\", 139, 137, 112),\n        (\"LIGHTBLUE\", 173, 216, 230),\n        (\"LIGHTBLUE1\", 191, 239, 255),\n        (\"LIGHTBLUE2\", 178, 223, 238),\n        (\"LIGHTBLUE3\", 154, 192, 205),\n        (\"LIGHTBLUE4\", 104, 131, 139),\n        (\"LIGHTCORAL\", 240, 128, 128),\n        (\"LIGHTCYAN\", 224, 255, 255),\n        (\"LIGHTCYAN1\", 224, 255, 255),\n        (\"LIGHTCYAN2\", 209, 238, 238),\n        (\"LIGHTCYAN3\", 180, 205, 205),\n        (\"LIGHTCYAN4\", 122, 139, 139),\n        (\"LIGHTGOLDENROD\", 238, 221, 130),\n        (\"LIGHTGOLDENROD1\", 255, 236, 139),\n        (\"LIGHTGOLDENROD2\", 238, 220, 130),\n        (\"LIGHTGOLDENROD3\", 205, 190, 112),\n        (\"LIGHTGOLDENROD4\", 139, 129, 76),\n        (\"LIGHTGOLDENRODYELLOW\", 250, 250, 210),\n        (\"LIGHTGREEN\", 144, 238, 144),\n        (\"LIGHTGRAY\", 211, 211, 211),\n        (\"LIGHTPINK\", 255, 182, 193),\n        (\"LIGHTPINK1\", 255, 174, 185),\n        (\"LIGHTPINK2\", 238, 162, 173),\n        (\"LIGHTPINK3\", 205, 140, 149),\n        (\"LIGHTPINK4\", 139, 95, 101),\n        (\"LIGHTSALMON\", 255, 160, 122),\n        (\"LIGHTSALMON1\", 255, 160, 122),\n        (\"LIGHTSALMON2\", 238, 149, 114),\n        (\"LIGHTSALMON3\", 205, 129, 98),\n        (\"LIGHTSALMON4\", 139, 87, 66),\n        (\"LIGHTSEAGREEN\", 32, 178, 170),\n        (\"LIGHTSKYBLUE\", 135, 206, 250),\n        (\"LIGHTSKYBLUE1\", 176, 226, 255),\n        (\"LIGHTSKYBLUE2\", 164, 211, 238),\n        (\"LIGHTSKYBLUE3\", 141, 182, 205),\n        (\"LIGHTSKYBLUE4\", 96, 123, 139),\n        (\"LIGHTSLATEBLUE\", 132, 112, 255),\n        (\"LIGHTSLATEGRAY\", 119, 136, 153),\n        (\"LIGHTSTEELBLUE\", 176, 196, 222),\n        (\"LIGHTSTEELBLUE1\", 202, 225, 255),\n        (\"LIGHTSTEELBLUE2\", 188, 210, 238),\n        (\"LIGHTSTEELBLUE3\", 162, 181, 205),\n        (\"LIGHTSTEELBLUE4\", 110, 123, 139),\n        (\"LIGHTYELLOW\", 255, 255, 224),\n        (\"LIGHTYELLOW1\", 255, 255, 224),\n        (\"LIGHTYELLOW2\", 238, 238, 209),\n        (\"LIGHTYELLOW3\", 205, 205, 180),\n        (\"LIGHTYELLOW4\", 139, 139, 122),\n        (\"LIMEGREEN\", 50, 205, 50),\n        (\"LINEN\", 250, 240, 230),\n        (\"MAGENTA\", 255, 0, 255),\n        (\"MAGENTA1\", 255, 0, 255),\n        (\"MAGENTA2\", 238, 0, 238),\n        (\"MAGENTA3\", 205, 0, 205),\n        (\"MAGENTA4\", 139, 0, 139),\n        (\"MAROON\", 176, 48, 96),\n        (\"MAROON1\", 255, 52, 179),\n        (\"MAROON2\", 238, 48, 167),\n        (\"MAROON3\", 205, 41, 144),\n        (\"MAROON4\", 139, 28, 98),\n        (\"MEDIUMAQUAMARINE\", 102, 205, 170),\n        (\"MEDIUMBLUE\", 0, 0, 205),\n        (\"MEDIUMORCHID\", 186, 85, 211),\n        (\"MEDIUMORCHID1\", 224, 102, 255),\n        (\"MEDIUMORCHID2\", 209, 95, 238),\n        (\"MEDIUMORCHID3\", 180, 82, 205),\n        (\"MEDIUMORCHID4\", 122, 55, 139),\n        (\"MEDIUMPURPLE\", 147, 112, 219),\n        (\"MEDIUMPURPLE1\", 171, 130, 255),\n        (\"MEDIUMPURPLE2\", 159, 121, 238),\n        (\"MEDIUMPURPLE3\", 137, 104, 205),\n        (\"MEDIUMPURPLE4\", 93, 71, 139),\n        (\"MEDIUMSEAGREEN\", 60, 179, 113),\n        (\"MEDIUMSLATEBLUE\", 123, 104, 238),\n        (\"MEDIUMSPRINGGREEN\", 0, 250, 154),\n        (\"MEDIUMTURQUOISE\", 72, 209, 204),\n        (\"MEDIUMVIOLETRED\", 199, 21, 133),\n        (\"MIDNIGHTBLUE\", 25, 25, 112),\n        (\"MINTCREAM\", 245, 255, 250),\n        (\"MISTYROSE\", 255, 228, 225),\n        (\"MISTYROSE1\", 255, 228, 225),\n        (\"MISTYROSE2\", 238, 213, 210),\n        (\"MISTYROSE3\", 205, 183, 181),\n        (\"MISTYROSE4\", 139, 125, 123),\n        (\"MOCCASIN\", 255, 228, 181),\n        (\"MUPDFBLUE\", 37, 114, 172),\n        (\"NAVAJOWHITE\", 255, 222, 173),\n        (\"NAVAJOWHITE1\", 255, 222, 173),\n        (\"NAVAJOWHITE2\", 238, 207, 161),\n        (\"NAVAJOWHITE3\", 205, 179, 139),\n        (\"NAVAJOWHITE4\", 139, 121, 94),\n        (\"NAVY\", 0, 0, 128),\n        (\"NAVYBLUE\", 0, 0, 128),\n        (\"OLDLACE\", 253, 245, 230),\n        (\"OLIVEDRAB\", 107, 142, 35),\n        (\"OLIVEDRAB1\", 192, 255, 62),\n        (\"OLIVEDRAB2\", 179, 238, 58),\n        (\"OLIVEDRAB3\", 154, 205, 50),\n        (\"OLIVEDRAB4\", 105, 139, 34),\n        (\"ORANGE\", 255, 165, 0),\n        (\"ORANGE1\", 255, 165, 0),\n        (\"ORANGE2\", 238, 154, 0),\n        (\"ORANGE3\", 205, 133, 0),\n        (\"ORANGE4\", 139, 90, 0),\n        (\"ORANGERED\", 255, 69, 0),\n        (\"ORANGERED1\", 255, 69, 0),\n        (\"ORANGERED2\", 238, 64, 0),\n        (\"ORANGERED3\", 205, 55, 0),\n        (\"ORANGERED4\", 139, 37, 0),\n        (\"ORCHID\", 218, 112, 214),\n        (\"ORCHID1\", 255, 131, 250),\n        (\"ORCHID2\", 238, 122, 233),\n        (\"ORCHID3\", 205, 105, 201),\n        (\"ORCHID4\", 139, 71, 137),\n        (\"PALEGOLDENROD\", 238, 232, 170),\n        (\"PALEGREEN\", 152, 251, 152),\n        (\"PALEGREEN1\", 154, 255, 154),\n        (\"PALEGREEN2\", 144, 238, 144),\n        (\"PALEGREEN3\", 124, 205, 124),\n        (\"PALEGREEN4\", 84, 139, 84),\n        (\"PALETURQUOISE\", 175, 238, 238),\n        (\"PALETURQUOISE1\", 187, 255, 255),\n        (\"PALETURQUOISE2\", 174, 238, 238),\n        (\"PALETURQUOISE3\", 150, 205, 205),\n        (\"PALETURQUOISE4\", 102, 139, 139),\n        (\"PALEVIOLETRED\", 219, 112, 147),\n        (\"PALEVIOLETRED1\", 255, 130, 171),\n        (\"PALEVIOLETRED2\", 238, 121, 159),\n        (\"PALEVIOLETRED3\", 205, 104, 137),\n        (\"PALEVIOLETRED4\", 139, 71, 93),\n        (\"PAPAYAWHIP\", 255, 239, 213),\n        (\"PEACHPUFF\", 255, 218, 185),\n        (\"PEACHPUFF1\", 255, 218, 185),\n        (\"PEACHPUFF2\", 238, 203, 173),\n        (\"PEACHPUFF3\", 205, 175, 149),\n        (\"PEACHPUFF4\", 139, 119, 101),\n        (\"PERU\", 205, 133, 63),\n        (\"PINK\", 255, 192, 203),\n        (\"PINK1\", 255, 181, 197),\n        (\"PINK2\", 238, 169, 184),\n        (\"PINK3\", 205, 145, 158),\n        (\"PINK4\", 139, 99, 108),\n        (\"PLUM\", 221, 160, 221),\n        (\"PLUM1\", 255, 187, 255),\n        (\"PLUM2\", 238, 174, 238),\n        (\"PLUM3\", 205, 150, 205),\n        (\"PLUM4\", 139, 102, 139),\n        (\"POWDERBLUE\", 176, 224, 230),\n        (\"PURPLE\", 160, 32, 240),\n        (\"PURPLE1\", 155, 48, 255),\n        (\"PURPLE2\", 145, 44, 238),\n        (\"PURPLE3\", 125, 38, 205),\n        (\"PURPLE4\", 85, 26, 139),\n        (\"PY_COLOR\", 240, 255, 210),\n        (\"RED\", 255, 0, 0),\n        (\"RED1\", 255, 0, 0),\n        (\"RED2\", 238, 0, 0),\n        (\"RED3\", 205, 0, 0),\n        (\"RED4\", 139, 0, 0),\n        (\"ROSYBROWN\", 188, 143, 143),\n        (\"ROSYBROWN1\", 255, 193, 193),\n        (\"ROSYBROWN2\", 238, 180, 180),\n        (\"ROSYBROWN3\", 205, 155, 155),\n        (\"ROSYBROWN4\", 139, 105, 105),\n        (\"ROYALBLUE\", 65, 105, 225),\n        (\"ROYALBLUE1\", 72, 118, 255),\n        (\"ROYALBLUE2\", 67, 110, 238),\n        (\"ROYALBLUE3\", 58, 95, 205),\n        (\"ROYALBLUE4\", 39, 64, 139),\n        (\"SADDLEBROWN\", 139, 69, 19),\n        (\"SALMON\", 250, 128, 114),\n        (\"SALMON1\", 255, 140, 105),\n        (\"SALMON2\", 238, 130, 98),\n        (\"SALMON3\", 205, 112, 84),\n        (\"SALMON4\", 139, 76, 57),\n        (\"SANDYBROWN\", 244, 164, 96),\n        (\"SEAGREEN\", 46, 139, 87),\n        (\"SEAGREEN1\", 84, 255, 159),\n        (\"SEAGREEN2\", 78, 238, 148),\n        (\"SEAGREEN3\", 67, 205, 128),\n        (\"SEAGREEN4\", 46, 139, 87),\n        (\"SEASHELL\", 255, 245, 238),\n        (\"SEASHELL1\", 255, 245, 238),\n        (\"SEASHELL2\", 238, 229, 222),\n        (\"SEASHELL3\", 205, 197, 191),\n        (\"SEASHELL4\", 139, 134, 130),\n        (\"SIENNA\", 160, 82, 45),\n        (\"SIENNA1\", 255, 130, 71),\n        (\"SIENNA2\", 238, 121, 66),\n        (\"SIENNA3\", 205, 104, 57),\n        (\"SIENNA4\", 139, 71, 38),\n        (\"SKYBLUE\", 135, 206, 235),\n        (\"SKYBLUE1\", 135, 206, 255),\n        (\"SKYBLUE2\", 126, 192, 238),\n        (\"SKYBLUE3\", 108, 166, 205),\n        (\"SKYBLUE4\", 74, 112, 139),\n        (\"SLATEBLUE\", 106, 90, 205),\n        (\"SLATEBLUE1\", 131, 111, 255),\n        (\"SLATEBLUE2\", 122, 103, 238),\n        (\"SLATEBLUE3\", 105, 89, 205),\n        (\"SLATEBLUE4\", 71, 60, 139),\n        (\"SLATEGRAY\", 112, 128, 144),\n        (\"SNOW\", 255, 250, 250),\n        (\"SNOW1\", 255, 250, 250),\n        (\"SNOW2\", 238, 233, 233),\n        (\"SNOW3\", 205, 201, 201),\n        (\"SNOW4\", 139, 137, 137),\n        (\"SPRINGGREEN\", 0, 255, 127),\n        (\"SPRINGGREEN1\", 0, 255, 127),\n        (\"SPRINGGREEN2\", 0, 238, 118),\n        (\"SPRINGGREEN3\", 0, 205, 102),\n        (\"SPRINGGREEN4\", 0, 139, 69),\n        (\"STEELBLUE\", 70, 130, 180),\n        (\"STEELBLUE1\", 99, 184, 255),\n        (\"STEELBLUE2\", 92, 172, 238),\n        (\"STEELBLUE3\", 79, 148, 205),\n        (\"STEELBLUE4\", 54, 100, 139),\n        (\"TAN\", 210, 180, 140),\n        (\"TAN1\", 255, 165, 79),\n        (\"TAN2\", 238, 154, 73),\n        (\"TAN3\", 205, 133, 63),\n        (\"TAN4\", 139, 90, 43),\n        (\"THISTLE\", 216, 191, 216),\n        (\"THISTLE1\", 255, 225, 255),\n        (\"THISTLE2\", 238, 210, 238),\n        (\"THISTLE3\", 205, 181, 205),\n        (\"THISTLE4\", 139, 123, 139),\n        (\"TOMATO\", 255, 99, 71),\n        (\"TOMATO1\", 255, 99, 71),\n        (\"TOMATO2\", 238, 92, 66),\n        (\"TOMATO3\", 205, 79, 57),\n        (\"TOMATO4\", 139, 54, 38),\n        (\"TURQUOISE\", 64, 224, 208),\n        (\"TURQUOISE1\", 0, 245, 255),\n        (\"TURQUOISE2\", 0, 229, 238),\n        (\"TURQUOISE3\", 0, 197, 205),\n        (\"TURQUOISE4\", 0, 134, 139),\n        (\"VIOLET\", 238, 130, 238),\n        (\"VIOLETRED\", 208, 32, 144),\n        (\"VIOLETRED1\", 255, 62, 150),\n        (\"VIOLETRED2\", 238, 58, 140),\n        (\"VIOLETRED3\", 205, 50, 120),\n        (\"VIOLETRED4\", 139, 34, 82),\n        (\"WHEAT\", 245, 222, 179),\n        (\"WHEAT1\", 255, 231, 186),\n        (\"WHEAT2\", 238, 216, 174),\n        (\"WHEAT3\", 205, 186, 150),\n        (\"WHEAT4\", 139, 126, 102),\n        (\"WHITE\", 255, 255, 255),\n        (\"WHITESMOKE\", 245, 245, 245),\n        (\"YELLOW\", 255, 255, 0),\n        (\"YELLOW1\", 255, 255, 0),\n        (\"YELLOW2\", 238, 238, 0),\n        (\"YELLOW3\", 205, 205, 0),\n        (\"YELLOW4\", 139, 139, 0),\n        (\"YELLOWGREEN\", 154, 205, 50),\n    ]\n\n\ndef getColorInfoDict() -> dict:\n    d = {}\n    for item in getColorInfoList():\n        d[item[0].lower()] = item[1:]\n    return d\n\n\ndef getColor(name: str) -> tuple:\n    \"\"\"Retrieve RGB color in PDF format by name.\n\n    Returns:\n        a triple of floats in range 0 to 1. In case of name-not-found, \"white\" is returned.\n    \"\"\"\n    try:\n        c = getColorInfoList()[getColorList().index(name.upper())]\n        return (c[1] / 255.0, c[2] / 255.0, c[3] / 255.0)\n    except:\n        return (1, 1, 1)\n\n\ndef getColorHSV(name: str) -> tuple:\n    \"\"\"Retrieve the hue, saturation, value triple of a color name.\n\n    Returns:\n        a triple (degree, percent, percent). If not found (-1, -1, -1) is returned.\n    \"\"\"\n    try:\n        x = getColorInfoList()[getColorList().index(name.upper())]\n    except:\n        return (-1, -1, -1)\n\n    r = x[1] / 255.0\n    g = x[2] / 255.0\n    b = x[3] / 255.0\n    cmax = max(r, g, b)\n    V = round(cmax * 100, 1)\n    cmin = min(r, g, b)\n    delta = cmax - cmin\n    if delta == 0:\n        hue = 0\n    elif cmax == r:\n        hue = 60.0 * (((g - b) / delta) % 6)\n    elif cmax == g:\n        hue = 60.0 * (((b - r) / delta) + 2)\n    else:\n        hue = 60.0 * (((r - g) / delta) + 4)\n\n    H = int(round(hue))\n\n    if cmax == 0:\n        sat = 0\n    else:\n        sat = delta / cmax\n    S = int(round(sat * 100))\n\n    return (H, S, V)\n\n\ndef _get_font_properties(doc: Document, xref: int) -> tuple:\n    fontname, ext, stype, buffer = doc.extract_font(xref)\n    asc = 0.8\n    dsc = -0.2\n    if ext == \"\":\n        return fontname, ext, stype, asc, dsc\n\n    if buffer:\n        try:\n            font = Font(fontbuffer=buffer)\n            asc = font.ascender\n            dsc = font.descender\n            bbox = font.bbox\n            if asc - dsc < 1:\n                if bbox.y0 < dsc:\n                    dsc = bbox.y0\n                asc = 1 - dsc\n        except:\n            asc *= 1.2\n            dsc *= 1.2\n        return fontname, ext, stype, asc, dsc\n    if ext != \"n/a\":\n        try:\n            font = Font(fontname)\n            asc = font.ascender\n            dsc = font.descender\n        except:\n            asc *= 1.2\n            dsc *= 1.2\n    else:\n        asc *= 1.2\n        dsc *= 1.2\n    return fontname, ext, stype, asc, dsc\n\n\ndef get_char_widths(\n    doc: Document, xref: int, limit: int = 256, idx: int = 0, fontdict: OptDict = None\n) -> list:\n    \"\"\"Get list of glyph information of a font.\n\n    Notes:\n        Must be provided by its XREF number. If we already dealt with the\n        font, it will be recorded in doc.FontInfos. Otherwise we insert an\n        entry there.\n        Finally we return the glyphs for the font. This is a list of\n        (glyph, width) where glyph is an integer controlling the char\n        appearance, and width is a float controlling the char's spacing:\n        width * fontsize is the actual space.\n        For 'simple' fonts, glyph == ord(char) will usually be true.\n        Exceptions are 'Symbol' and 'ZapfDingbats'. We are providing data for these directly here.\n    \"\"\"\n    fontinfo = CheckFontInfo(doc, xref)\n    if fontinfo is None:  # not recorded yet: create it\n        if fontdict is None:\n            name, ext, stype, asc, dsc = _get_font_properties(doc, xref)\n            fontdict = {\n                \"name\": name,\n                \"type\": stype,\n                \"ext\": ext,\n                \"ascender\": asc,\n                \"descender\": dsc,\n            }\n        else:\n            name = fontdict[\"name\"]\n            ext = fontdict[\"ext\"]\n            stype = fontdict[\"type\"]\n            ordering = fontdict[\"ordering\"]\n            simple = fontdict[\"simple\"]\n\n        if ext == \"\":\n            raise ValueError(\"xref is not a font\")\n\n        # check for 'simple' fonts\n        if stype in (\"Type1\", \"MMType1\", \"TrueType\"):\n            simple = True\n        else:\n            simple = False\n\n        # check for CJK fonts\n        if name in (\"Fangti\", \"Ming\"):\n            ordering = 0\n        elif name in (\"Heiti\", \"Song\"):\n            ordering = 1\n        elif name in (\"Gothic\", \"Mincho\"):\n            ordering = 2\n        elif name in (\"Dotum\", \"Batang\"):\n            ordering = 3\n        else:\n            ordering = -1\n\n        fontdict[\"simple\"] = simple\n\n        if name == \"ZapfDingbats\":\n            glyphs = zapf_glyphs\n        elif name == \"Symbol\":\n            glyphs = symbol_glyphs\n        else:\n            glyphs = None\n\n        fontdict[\"glyphs\"] = glyphs\n        fontdict[\"ordering\"] = ordering\n        fontinfo = [xref, fontdict]\n        doc.FontInfos.append(fontinfo)\n    else:\n        fontdict = fontinfo[1]\n        glyphs = fontdict[\"glyphs\"]\n        simple = fontdict[\"simple\"]\n        ordering = fontdict[\"ordering\"]\n\n    if glyphs is None:\n        oldlimit = 0\n    else:\n        oldlimit = len(glyphs)\n\n    mylimit = max(256, limit)\n\n    if mylimit <= oldlimit:\n        return glyphs\n\n    if ordering < 0:  # not a CJK font\n        glyphs = doc._get_char_widths(\n            xref, fontdict[\"name\"], fontdict[\"ext\"], fontdict[\"ordering\"], mylimit, idx\n        )\n    else:  # CJK fonts use char codes and width = 1\n        glyphs = None\n\n    fontdict[\"glyphs\"] = glyphs\n    fontinfo[1] = fontdict\n    UpdateFontInfo(doc, fontinfo)\n\n    return glyphs\n\n\nclass Shape(object):\n    \"\"\"Create a new shape.\"\"\"\n\n    @staticmethod\n    def horizontal_angle(C, P):\n        \"\"\"Return the angle to the horizontal for the connection from C to P.\n        This uses the arcus sine function and resolves its inherent ambiguity by\n        looking up in which quadrant vector S = P - C is located.\n        \"\"\"\n        S = Point(P - C).unit  # unit vector 'C' -> 'P'\n        alfa = math.asin(abs(S.y))  # absolute angle from horizontal\n        if S.x < 0:  # make arcsin result unique\n            if S.y <= 0:  # bottom-left\n                alfa = -(math.pi - alfa)\n            else:  # top-left\n                alfa = math.pi - alfa\n        else:\n            if S.y >= 0:  # top-right\n                pass\n            else:  # bottom-right\n                alfa = -alfa\n        return alfa\n\n    def __init__(self, page: Page):\n        CheckParent(page)\n        self.page = page\n        self.doc = page.parent\n        if not self.doc.is_pdf:\n            raise ValueError(\"is no PDF\")\n        self.height = page.mediabox_size.y\n        self.width = page.mediabox_size.x\n        self.x = page.cropbox_position.x\n        self.y = page.cropbox_position.y\n\n        self.pctm = page.transformation_matrix  # page transf. matrix\n        self.ipctm = ~self.pctm  # inverted transf. matrix\n\n        self.draw_cont = \"\"\n        self.text_cont = \"\"\n        self.totalcont = \"\"\n        self.lastPoint = None\n        self.rect = None\n\n    def updateRect(self, x):\n        if self.rect is None:\n            if len(x) == 2:\n                self.rect = Rect(x, x)\n            else:\n                self.rect = Rect(x)\n\n        else:\n            if len(x) == 2:\n                x = Point(x)\n                self.rect.x0 = min(self.rect.x0, x.x)\n                self.rect.y0 = min(self.rect.y0, x.y)\n                self.rect.x1 = max(self.rect.x1, x.x)\n                self.rect.y1 = max(self.rect.y1, x.y)\n            else:\n                x = Rect(x)\n                self.rect.x0 = min(self.rect.x0, x.x0)\n                self.rect.y0 = min(self.rect.y0, x.y0)\n                self.rect.x1 = max(self.rect.x1, x.x1)\n                self.rect.y1 = max(self.rect.y1, x.y1)\n\n    def draw_line(self, p1: point_like, p2: point_like) -> Point:\n        \"\"\"Draw a line between two points.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        if not (self.lastPoint == p1):\n            self.draw_cont += \"%g %g m\\n\" % JM_TUPLE(p1 * self.ipctm)\n            self.lastPoint = p1\n            self.updateRect(p1)\n\n        self.draw_cont += \"%g %g l\\n\" % JM_TUPLE(p2 * self.ipctm)\n        self.updateRect(p2)\n        self.lastPoint = p2\n        return self.lastPoint\n\n    def draw_polyline(self, points: list) -> Point:\n        \"\"\"Draw several connected line segments.\"\"\"\n        for i, p in enumerate(points):\n            if i == 0:\n                if not (self.lastPoint == Point(p)):\n                    self.draw_cont += \"%g %g m\\n\" % JM_TUPLE(Point(p) * self.ipctm)\n                    self.lastPoint = Point(p)\n            else:\n                self.draw_cont += \"%g %g l\\n\" % JM_TUPLE(Point(p) * self.ipctm)\n            self.updateRect(p)\n\n        self.lastPoint = Point(points[-1])\n        return self.lastPoint\n\n    def draw_bezier(\n        self,\n        p1: point_like,\n        p2: point_like,\n        p3: point_like,\n        p4: point_like,\n    ) -> Point:\n        \"\"\"Draw a standard cubic Bezier curve.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        p3 = Point(p3)\n        p4 = Point(p4)\n        if not (self.lastPoint == p1):\n            self.draw_cont += \"%g %g m\\n\" % JM_TUPLE(p1 * self.ipctm)\n        self.draw_cont += \"%g %g %g %g %g %g c\\n\" % JM_TUPLE(\n            list(p2 * self.ipctm) + list(p3 * self.ipctm) + list(p4 * self.ipctm)\n        )\n        self.updateRect(p1)\n        self.updateRect(p2)\n        self.updateRect(p3)\n        self.updateRect(p4)\n        self.lastPoint = p4\n        return self.lastPoint\n\n    def draw_oval(self, tetra: typing.Union[quad_like, rect_like]) -> Point:\n        \"\"\"Draw an ellipse inside a tetrapod.\"\"\"\n        if len(tetra) != 4:\n            raise ValueError(\"invalid arg length\")\n        if hasattr(tetra[0], \"__float__\"):\n            q = Rect(tetra).quad\n        else:\n            q = Quad(tetra)\n\n        mt = q.ul + (q.ur - q.ul) * 0.5\n        mr = q.ur + (q.lr - q.ur) * 0.5\n        mb = q.ll + (q.lr - q.ll) * 0.5\n        ml = q.ul + (q.ll - q.ul) * 0.5\n        if not (self.lastPoint == ml):\n            self.draw_cont += \"%g %g m\\n\" % JM_TUPLE(ml * self.ipctm)\n            self.lastPoint = ml\n        self.draw_curve(ml, q.ll, mb)\n        self.draw_curve(mb, q.lr, mr)\n        self.draw_curve(mr, q.ur, mt)\n        self.draw_curve(mt, q.ul, ml)\n        self.updateRect(q.rect)\n        self.lastPoint = ml\n        return self.lastPoint\n\n    def draw_circle(self, center: point_like, radius: float) -> Point:\n        \"\"\"Draw a circle given its center and radius.\"\"\"\n        if not radius > EPSILON:\n            raise ValueError(\"radius must be positive\")\n        center = Point(center)\n        p1 = center - (radius, 0)\n        return self.draw_sector(center, p1, 360, fullSector=False)\n\n    def draw_curve(\n        self,\n        p1: point_like,\n        p2: point_like,\n        p3: point_like,\n    ) -> Point:\n        \"\"\"Draw a curve between points using one control point.\"\"\"\n        kappa = 0.55228474983\n        p1 = Point(p1)\n        p2 = Point(p2)\n        p3 = Point(p3)\n        k1 = p1 + (p2 - p1) * kappa\n        k2 = p3 + (p2 - p3) * kappa\n        return self.draw_bezier(p1, k1, k2, p3)\n\n    def draw_sector(\n        self,\n        center: point_like,\n        point: point_like,\n        beta: float,\n        fullSector: bool = True,\n    ) -> Point:\n        \"\"\"Draw a circle sector.\"\"\"\n        center = Point(center)\n        point = Point(point)\n        l3 = \"%g %g m\\n\"\n        l4 = \"%g %g %g %g %g %g c\\n\"\n        l5 = \"%g %g l\\n\"\n        betar = math.radians(-beta)\n        w360 = math.radians(math.copysign(360, betar)) * (-1)\n        w90 = math.radians(math.copysign(90, betar))\n        w45 = w90 / 2\n        while abs(betar) > 2 * math.pi:\n            betar += w360  # bring angle below 360 degrees\n        if not (self.lastPoint == point):\n            self.draw_cont += l3 % JM_TUPLE(point * self.ipctm)\n            self.lastPoint = point\n        Q = Point(0, 0)  # just make sure it exists\n        C = center\n        P = point\n        S = P - C  # vector 'center' -> 'point'\n        rad = abs(S)  # circle radius\n\n        if not rad > EPSILON:\n            raise ValueError(\"radius must be positive\")\n\n        alfa = self.horizontal_angle(center, point)\n        while abs(betar) > abs(w90):  # draw 90 degree arcs\n            q1 = C.x + math.cos(alfa + w90) * rad\n            q2 = C.y + math.sin(alfa + w90) * rad\n            Q = Point(q1, q2)  # the arc's end point\n            r1 = C.x + math.cos(alfa + w45) * rad / math.cos(w45)\n            r2 = C.y + math.sin(alfa + w45) * rad / math.cos(w45)\n            R = Point(r1, r2)  # crossing point of tangents\n            kappah = (1 - math.cos(w45)) * 4 / 3 / abs(R - Q)\n            kappa = kappah * abs(P - Q)\n            cp1 = P + (R - P) * kappa  # control point 1\n            cp2 = Q + (R - Q) * kappa  # control point 2\n            self.draw_cont += l4 % JM_TUPLE(\n                list(cp1 * self.ipctm) + list(cp2 * self.ipctm) + list(Q * self.ipctm)\n            )\n\n            betar -= w90  # reduce parm angle by 90 deg\n            alfa += w90  # advance start angle by 90 deg\n            P = Q  # advance to arc end point\n        # draw (remaining) arc\n        if abs(betar) > 1e-3:  # significant degrees left?\n            beta2 = betar / 2\n            q1 = C.x + math.cos(alfa + betar) * rad\n            q2 = C.y + math.sin(alfa + betar) * rad\n            Q = Point(q1, q2)  # the arc's end point\n            r1 = C.x + math.cos(alfa + beta2) * rad / math.cos(beta2)\n            r2 = C.y + math.sin(alfa + beta2) * rad / math.cos(beta2)\n            R = Point(r1, r2)  # crossing point of tangents\n            # kappa height is 4/3 of segment height\n            kappah = (1 - math.cos(beta2)) * 4 / 3 / abs(R - Q)  # kappa height\n            kappa = kappah * abs(P - Q) / (1 - math.cos(betar))\n            cp1 = P + (R - P) * kappa  # control point 1\n            cp2 = Q + (R - Q) * kappa  # control point 2\n            self.draw_cont += l4 % JM_TUPLE(\n                list(cp1 * self.ipctm) + list(cp2 * self.ipctm) + list(Q * self.ipctm)\n            )\n        if fullSector:\n            self.draw_cont += l3 % JM_TUPLE(point * self.ipctm)\n            self.draw_cont += l5 % JM_TUPLE(center * self.ipctm)\n            self.draw_cont += l5 % JM_TUPLE(Q * self.ipctm)\n        self.lastPoint = Q\n        return self.lastPoint\n\n    def draw_rect(self, rect: rect_like, *, radius=None) -> Point:\n        \"\"\"Draw a rectangle.\n\n        Args:\n            radius: if not None, the rectangle will have rounded corners.\n                This is the radius of the curvature, given as percentage of\n                the rectangle width or height. Valid are values 0 < v <= 0.5.\n                For a sequence of two values, the corners will have different\n                radii. Otherwise, the percentage will be computed from the\n                shorter side. A value of (0.5, 0.5) will draw an ellipse.\n        \"\"\"\n        r = Rect(rect)\n        if radius == None:  # standard rectangle\n            self.draw_cont += \"%g %g %g %g re\\n\" % JM_TUPLE(\n                list(r.bl * self.ipctm) + [r.width, r.height]\n            )\n            self.updateRect(r)\n            self.lastPoint = r.tl\n            return self.lastPoint\n        # rounded corners requested. This requires 1 or 2 values, each\n        # with 0 < value <= 0.5\n        if hasattr(radius, \"__float__\"):\n            if radius <= 0 or radius > 0.5:\n                raise ValueError(f\"bad radius value {radius}.\")\n            d = min(r.width, r.height) * radius\n            px = (d, 0)\n            py = (0, d)\n        elif hasattr(radius, \"__len__\") and len(radius) == 2:\n            rx, ry = radius\n            px = (rx * r.width, 0)\n            py = (0, ry * r.height)\n            if min(rx, ry) <= 0 or max(rx, ry) > 0.5:\n                raise ValueError(f\"bad radius value {radius}.\")\n        else:\n            raise ValueError(f\"bad radius value {radius}.\")\n\n        lp = self.draw_line(r.tl + py, r.bl - py)\n        lp = self.draw_curve(lp, r.bl, r.bl + px)\n\n        lp = self.draw_line(lp, r.br - px)\n        lp = self.draw_curve(lp, r.br, r.br - py)\n\n        lp = self.draw_line(lp, r.tr + py)\n        lp = self.draw_curve(lp, r.tr, r.tr - px)\n\n        lp = self.draw_line(lp, r.tl + px)\n        self.lastPoint = self.draw_curve(lp, r.tl, r.tl + py)\n\n        self.updateRect(r)\n        return self.lastPoint\n\n    def draw_quad(self, quad: quad_like) -> Point:\n        \"\"\"Draw a Quad.\"\"\"\n        q = Quad(quad)\n        return self.draw_polyline([q.ul, q.ll, q.lr, q.ur, q.ul])\n\n    def draw_zigzag(\n        self,\n        p1: point_like,\n        p2: point_like,\n        breadth: float = 2,\n    ) -> Point:\n        \"\"\"Draw a zig-zagged line from p1 to p2.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        S = p2 - p1  # vector start - end\n        rad = abs(S)  # distance of points\n        cnt = 4 * int(round(rad / (4 * breadth), 0))  # always take full phases\n        if cnt < 4:\n            raise ValueError(\"points too close\")\n        mb = rad / cnt  # revised breadth\n        matrix = Matrix(util_hor_matrix(p1, p2))  # normalize line to x-axis\n        i_mat = ~matrix  # get original position\n        points = []  # stores edges\n        for i in range(1, cnt):\n            if i % 4 == 1:  # point \"above\" connection\n                p = Point(i, -1) * mb\n            elif i % 4 == 3:  # point \"below\" connection\n                p = Point(i, 1) * mb\n            else:  # ignore others\n                continue\n            points.append(p * i_mat)\n        self.draw_polyline([p1] + points + [p2])  # add start and end points\n        return p2\n\n    def draw_squiggle(\n        self,\n        p1: point_like,\n        p2: point_like,\n        breadth=2,\n    ) -> Point:\n        \"\"\"Draw a squiggly line from p1 to p2.\"\"\"\n        p1 = Point(p1)\n        p2 = Point(p2)\n        S = p2 - p1  # vector start - end\n        rad = abs(S)  # distance of points\n        cnt = 4 * int(round(rad / (4 * breadth), 0))  # always take full phases\n        if cnt < 4:\n            raise ValueError(\"points too close\")\n        mb = rad / cnt  # revised breadth\n        matrix = Matrix(util_hor_matrix(p1, p2))  # normalize line to x-axis\n        i_mat = ~matrix  # get original position\n        k = 2.4142135623765633  # y of draw_curve helper point\n\n        points = []  # stores edges\n        for i in range(1, cnt):\n            if i % 4 == 1:  # point \"above\" connection\n                p = Point(i, -k) * mb\n            elif i % 4 == 3:  # point \"below\" connection\n                p = Point(i, k) * mb\n            else:  # else on connection line\n                p = Point(i, 0) * mb\n            points.append(p * i_mat)\n\n        points = [p1] + points + [p2]\n        cnt = len(points)\n        i = 0\n        while i + 2 < cnt:\n            self.draw_curve(points[i], points[i + 1], points[i + 2])\n            i += 2\n        return p2\n\n    # ==============================================================================\n    # Shape.insert_text\n    # ==============================================================================\n    def insert_text(\n        self,\n        point: point_like,\n        buffer: typing.Union[str, list],\n        fontsize: float = 11,\n        lineheight: OptFloat = None,\n        fontname: str = \"helv\",\n        fontfile: OptStr = None,\n        set_simple: bool = 0,\n        encoding: int = 0,\n        color: OptSeq = None,\n        fill: OptSeq = None,\n        render_mode: int = 0,\n        border_width: float = 0.05,\n        rotate: int = 0,\n        morph: OptSeq = None,\n        stroke_opacity: float = 1,\n        fill_opacity: float = 1,\n        oc: int = 0,\n    ) -> int:\n        # ensure 'text' is a list of strings, worth dealing with\n        if not bool(buffer):\n            return 0\n\n        if type(buffer) not in (list, tuple):\n            text = buffer.splitlines()\n        else:\n            text = buffer\n\n        if not len(text) > 0:\n            return 0\n\n        point = Point(point)\n        try:\n            maxcode = max([ord(c) for c in \" \".join(text)])\n        except:\n            return 0\n\n        # ensure valid 'fontname'\n        fname = fontname\n        if fname.startswith(\"/\"):\n            fname = fname[1:]\n\n        xref = self.page.insert_font(\n            fontname=fname, fontfile=fontfile, encoding=encoding, set_simple=set_simple\n        )\n        fontinfo = CheckFontInfo(self.doc, xref)\n\n        fontdict = fontinfo[1]\n        ordering = fontdict[\"ordering\"]\n        simple = fontdict[\"simple\"]\n        bfname = fontdict[\"name\"]\n        ascender = fontdict[\"ascender\"]\n        descender = fontdict[\"descender\"]\n        if lineheight:\n            lheight = fontsize * lineheight\n        elif ascender - descender <= 1:\n            lheight = fontsize * 1.2\n        else:\n            lheight = fontsize * (ascender - descender)\n\n        if maxcode > 255:\n            glyphs = self.doc.get_char_widths(xref, maxcode + 1)\n        else:\n            glyphs = fontdict[\"glyphs\"]\n\n        tab = []\n        for t in text:\n            if simple and bfname not in (\"Symbol\", \"ZapfDingbats\"):\n                g = None\n            else:\n                g = glyphs\n            tab.append(getTJstr(t, g, simple, ordering))\n        text = tab\n\n        color_str = ColorCode(color, \"c\")\n        fill_str = ColorCode(fill, \"f\")\n        if not fill and render_mode == 0:  # ensure fill color when 0 Tr\n            fill = color\n            fill_str = ColorCode(color, \"f\")\n\n        morphing = CheckMorph(morph)\n        rot = rotate\n        if rot % 90 != 0:\n            raise ValueError(\"bad rotate value\")\n\n        while rot < 0:\n            rot += 360\n        rot = rot % 360  # text rotate = 0, 90, 270, 180\n\n        templ1 = \"\\nq\\n%s%sBT\\n%s1 0 0 1 %g %g Tm\\n/%s %g Tf \"\n        templ2 = \"TJ\\n0 -%g TD\\n\"\n        cmp90 = \"0 1 -1 0 0 0 cm\\n\"  # rotates 90 deg counter-clockwise\n        cmm90 = \"0 -1 1 0 0 0 cm\\n\"  # rotates 90 deg clockwise\n        cm180 = \"-1 0 0 -1 0 0 cm\\n\"  # rotates by 180 deg.\n        height = self.height\n        width = self.width\n\n        # setting up for standard rotation directions\n        # case rotate = 0\n        if morphing:\n            m1 = Matrix(1, 0, 0, 1, morph[0].x + self.x, height - morph[0].y - self.y)\n            mat = ~m1 * morph[1] * m1\n            cm = \"%g %g %g %g %g %g cm\\n\" % JM_TUPLE(mat)\n        else:\n            cm = \"\"\n        top = height - point.y - self.y  # start of 1st char\n        left = point.x + self.x  # start of 1. char\n        space = top  # space available\n        headroom = point.y + self.y  # distance to page border\n        if rot == 90:\n            left = height - point.y - self.y\n            top = -point.x - self.x\n            cm += cmp90\n            space = width - abs(top)\n            headroom = point.x + self.x\n\n        elif rot == 270:\n            left = -height + point.y + self.y\n            top = point.x + self.x\n            cm += cmm90\n            space = abs(top)\n            headroom = width - point.x - self.x\n\n        elif rot == 180:\n            left = -point.x - self.x\n            top = -height + point.y + self.y\n            cm += cm180\n            space = abs(point.y + self.y)\n            headroom = height - point.y - self.y\n\n        optcont = self.page._get_optional_content(oc)\n        if optcont != None:\n            bdc = \"/OC /%s BDC\\n\" % optcont\n            emc = \"EMC\\n\"\n        else:\n            bdc = emc = \"\"\n\n        alpha = self.page._set_opacity(CA=stroke_opacity, ca=fill_opacity)\n        if alpha == None:\n            alpha = \"\"\n        else:\n            alpha = \"/%s gs\\n\" % alpha\n        nres = templ1 % (bdc, alpha, cm, left, top, fname, fontsize)\n\n        if render_mode > 0:\n            nres += \"%i Tr \" % render_mode\n            nres += \"%g w \" % (border_width * fontsize)\n\n        if color is not None:\n            nres += color_str\n        if fill is not None:\n            nres += fill_str\n\n        # =========================================================================\n        #   start text insertion\n        # =========================================================================\n        nres += text[0]\n        nlines = 1  # set output line counter\n        if len(text) > 1:\n            nres += templ2 % lheight  # line 1\n        else:\n            nres += templ2[:2]\n        for i in range(1, len(text)):\n            if space < lheight:\n                break  # no space left on page\n            if i > 1:\n                nres += \"\\nT* \"\n            nres += text[i] + templ2[:2]\n            space -= lheight\n            nlines += 1\n\n        nres += \"\\nET\\n%sQ\\n\" % emc\n\n        # =====================================================================\n        #   end of text insertion\n        # =====================================================================\n        # update the /Contents object\n        self.text_cont += nres\n        return nlines\n\n    # =========================================================================\n    # Shape.insert_textbox\n    # =========================================================================\n    def insert_textbox(\n        self,\n        rect: rect_like,\n        buffer: typing.Union[str, list],\n        fontname: OptStr = \"helv\",\n        fontfile: OptStr = None,\n        fontsize: float = 11,\n        lineheight: OptFloat = None,\n        set_simple: bool = 0,\n        encoding: int = 0,\n        color: OptSeq = None,\n        fill: OptSeq = None,\n        expandtabs: int = 1,\n        border_width: float = 0.05,\n        align: int = 0,\n        render_mode: int = 0,\n        rotate: int = 0,\n        morph: OptSeq = None,\n        stroke_opacity: float = 1,\n        fill_opacity: float = 1,\n        oc: int = 0,\n    ) -> float:\n        \"\"\"Insert text into a given rectangle.\n\n        Args:\n            rect -- the textbox to fill\n            buffer -- text to be inserted\n            fontname -- a Base-14 font, font name or '/name'\n            fontfile -- name of a font file\n            fontsize -- font size\n            lineheight -- overwrite the font property\n            color -- RGB stroke color triple\n            fill -- RGB fill color triple\n            render_mode -- text rendering control\n            border_width -- thickness of glyph borders as percentage of fontsize\n            expandtabs -- handles tabulators with string function\n            align -- left, center, right, justified\n            rotate -- 0, 90, 180, or 270 degrees\n            morph -- morph box with a matrix and a fixpoint\n        Returns:\n            unused or deficit rectangle area (float)\n        \"\"\"\n        rect = Rect(rect)\n        if rect.is_empty or rect.is_infinite:\n            raise ValueError(\"text box must be finite and not empty\")\n\n        color_str = ColorCode(color, \"c\")\n        fill_str = ColorCode(fill, \"f\")\n        if fill is None and render_mode == 0:  # ensure fill color for 0 Tr\n            fill = color\n            fill_str = ColorCode(color, \"f\")\n\n        optcont = self.page._get_optional_content(oc)\n        if optcont != None:\n            bdc = \"/OC /%s BDC\\n\" % optcont\n            emc = \"EMC\\n\"\n        else:\n            bdc = emc = \"\"\n\n        # determine opacity / transparency\n        alpha = self.page._set_opacity(CA=stroke_opacity, ca=fill_opacity)\n        if alpha == None:\n            alpha = \"\"\n        else:\n            alpha = \"/%s gs\\n\" % alpha\n\n        if rotate % 90 != 0:\n            raise ValueError(\"rotate must be multiple of 90\")\n\n        rot = rotate\n        while rot < 0:\n            rot += 360\n        rot = rot % 360\n\n        # is buffer worth of dealing with?\n        if not bool(buffer):\n            return rect.height if rot in (0, 180) else rect.width\n\n        cmp90 = \"0 1 -1 0 0 0 cm\\n\"  # rotates counter-clockwise\n        cmm90 = \"0 -1 1 0 0 0 cm\\n\"  # rotates clockwise\n        cm180 = \"-1 0 0 -1 0 0 cm\\n\"  # rotates by 180 deg.\n        height = self.height\n\n        fname = fontname\n        if fname.startswith(\"/\"):\n            fname = fname[1:]\n\n        xref = self.page.insert_font(\n            fontname=fname, fontfile=fontfile, encoding=encoding, set_simple=set_simple\n        )\n        fontinfo = CheckFontInfo(self.doc, xref)\n\n        fontdict = fontinfo[1]\n        ordering = fontdict[\"ordering\"]\n        simple = fontdict[\"simple\"]\n        glyphs = fontdict[\"glyphs\"]\n        bfname = fontdict[\"name\"]\n        ascender = fontdict[\"ascender\"]\n        descender = fontdict[\"descender\"]\n\n        if lineheight:\n            lheight_factor = lineheight\n        elif ascender - descender <= 1:\n            lheight_factor = 1.2\n        else:\n            lheight_factor = ascender - descender\n        lheight = fontsize * lheight_factor\n\n        # create a list from buffer, split into its lines\n        if type(buffer) in (list, tuple):\n            t0 = \"\\n\".join(buffer)\n        else:\n            t0 = buffer\n\n        maxcode = max([ord(c) for c in t0])\n        # replace invalid char codes for simple fonts\n        if simple and maxcode > 255:\n            t0 = \"\".join([c if ord(c) < 256 else \"?\" for c in t0])\n\n        t0 = t0.splitlines()\n\n        glyphs = self.doc.get_char_widths(xref, maxcode + 1)\n        if simple and bfname not in (\"Symbol\", \"ZapfDingbats\"):\n            tj_glyphs = None\n        else:\n            tj_glyphs = glyphs\n\n        # ----------------------------------------------------------------------\n        # calculate pixel length of a string\n        # ----------------------------------------------------------------------\n        def pixlen(x):\n            \"\"\"Calculate pixel length of x.\"\"\"\n            if ordering < 0:\n                return sum([glyphs[ord(c)][1] for c in x]) * fontsize\n            else:\n                return len(x) * fontsize\n\n        # ---------------------------------------------------------------------\n\n        if ordering < 0:\n            blen = glyphs[32][1] * fontsize  # pixel size of space character\n        else:\n            blen = fontsize\n\n        text = \"\"  # output buffer\n\n        if CheckMorph(morph):\n            m1 = Matrix(\n                1, 0, 0, 1, morph[0].x + self.x, self.height - morph[0].y - self.y\n            )\n            mat = ~m1 * morph[1] * m1\n            cm = \"%g %g %g %g %g %g cm\\n\" % JM_TUPLE(mat)\n        else:\n            cm = \"\"\n\n        # ---------------------------------------------------------------------\n        # adjust for text orientation / rotation\n        # ---------------------------------------------------------------------\n        progr = 1  # direction of line progress\n        c_pnt = Point(0, fontsize * ascender)  # used for line progress\n        if rot == 0:  # normal orientation\n            point = rect.tl + c_pnt  # line 1 is 'lheight' below top\n            maxwidth = rect.width  # pixels available in one line\n            maxheight = rect.height  # available text height\n\n        elif rot == 90:  # rotate counter clockwise\n            c_pnt = Point(fontsize * ascender, 0)  # progress in x-direction\n            point = rect.bl + c_pnt  # line 1 'lheight' away from left\n            maxwidth = rect.height  # pixels available in one line\n            maxheight = rect.width  # available text height\n            cm += cmp90\n\n        elif rot == 180:  # text upside down\n            # progress upwards in y direction\n            c_pnt = -Point(0, fontsize * ascender)\n            point = rect.br + c_pnt  # line 1 'lheight' above bottom\n            maxwidth = rect.width  # pixels available in one line\n            progr = -1  # subtract lheight for next line\n            maxheight = rect.height  # available text height\n            cm += cm180\n\n        else:  # rotate clockwise (270 or -90)\n            # progress from right to left\n            c_pnt = -Point(fontsize * ascender, 0)\n            point = rect.tr + c_pnt  # line 1 'lheight' left of right\n            maxwidth = rect.height  # pixels available in one line\n            progr = -1  # subtract lheight for next line\n            maxheight = rect.width  # available text height\n            cm += cmm90\n\n        # =====================================================================\n        # line loop\n        # =====================================================================\n        just_tab = []  # 'justify' indicators per line\n\n        for i, line in enumerate(t0):\n            line_t = line.expandtabs(expandtabs).split(\" \")  # split into words\n            num_words = len(line_t)\n            lbuff = \"\"  # init line buffer\n            rest = maxwidth  # available line pixels\n            # =================================================================\n            # word loop\n            # =================================================================\n            for j in range(num_words):\n                word = line_t[j]\n                pl_w = pixlen(word)  # pixel len of word\n                if rest >= pl_w:  # does it fit on the line?\n                    lbuff += word + \" \"  # yes, append word\n                    rest -= pl_w + blen  # update available line space\n                    continue  # next word\n\n                # word doesn't fit - output line (if not empty)\n                if lbuff:\n                    lbuff = lbuff.rstrip() + \"\\n\"  # line full, append line break\n                    text += lbuff  # append to total text\n                    just_tab.append(True)  # can align-justify\n\n                lbuff = \"\"  # re-init line buffer\n                rest = maxwidth  # re-init avail. space\n\n                if pl_w <= maxwidth:  # word shorter than 1 line?\n                    lbuff = word + \" \"  # start the line with it\n                    rest = maxwidth - pl_w - blen  # update free space\n                    continue\n\n                # long word: split across multiple lines - char by char ...\n                if len(just_tab) > 0:\n                    just_tab[-1] = False  # cannot align-justify\n                for c in word:\n                    if pixlen(lbuff) <= maxwidth - pixlen(c):\n                        lbuff += c\n                    else:  # line full\n                        lbuff += \"\\n\"  # close line\n                        text += lbuff  # append to text\n                        just_tab.append(False)  # cannot align-justify\n                        lbuff = c  # start new line with this char\n\n                lbuff += \" \"  # finish long word\n                rest = maxwidth - pixlen(lbuff)  # long word stored\n\n            if lbuff:  # unprocessed line content?\n                text += lbuff.rstrip()  # append to text\n                just_tab.append(False)  # cannot align-justify\n\n            if i < len(t0) - 1:  # not the last line?\n                text += \"\\n\"  # insert line break\n\n        # compute used part of the textbox\n        if text.endswith(\"\\n\"):\n            text = text[:-1]\n        lb_count = text.count(\"\\n\") + 1  # number of lines written\n\n        # text height = line count * line height plus one descender value\n        text_height = lheight * lb_count - descender * fontsize\n\n        more = text_height - maxheight  # difference to height limit\n        if more > EPSILON:  # landed too much outside rect\n            return (-1) * more  # return deficit, don't output\n\n        more = abs(more)\n        if more < EPSILON:\n            more = 0  # don't bother with epsilons\n        nres = \"\\nq\\n%s%sBT\\n\" % (bdc, alpha) + cm  # initialize output buffer\n        templ = \"1 0 0 1 %g %g Tm /%s %g Tf \"\n        # center, right, justify: output each line with its own specifics\n        text_t = text.splitlines()  # split text in lines again\n        just_tab[-1] = False  # never justify last line\n        for i, t in enumerate(text_t):\n            pl = maxwidth - pixlen(t)  # length of empty line part\n            pnt = point + c_pnt * (i * lheight_factor)  # text start of line\n            if align == 1:  # center: right shift by half width\n                if rot in (0, 180):\n                    pnt = pnt + Point(pl / 2, 0) * progr\n                else:\n                    pnt = pnt - Point(0, pl / 2) * progr\n            elif align == 2:  # right: right shift by full width\n                if rot in (0, 180):\n                    pnt = pnt + Point(pl, 0) * progr\n                else:\n                    pnt = pnt - Point(0, pl) * progr\n            elif align == 3:  # justify\n                spaces = t.count(\" \")  # number of spaces in line\n                if spaces > 0 and just_tab[i]:  # if any, and we may justify\n                    spacing = pl / spaces  # make every space this much larger\n                else:\n                    spacing = 0  # keep normal space length\n            top = height - pnt.y - self.y\n            left = pnt.x + self.x\n            if rot == 90:\n                left = height - pnt.y - self.y\n                top = -pnt.x - self.x\n            elif rot == 270:\n                left = -height + pnt.y + self.y\n                top = pnt.x + self.x\n            elif rot == 180:\n                left = -pnt.x - self.x\n                top = -height + pnt.y + self.y\n\n            nres += templ % (left, top, fname, fontsize)\n\n            if render_mode > 0:\n                nres += \"%i Tr \" % render_mode\n                nres += \"%g w \" % (border_width * fontsize)\n\n            if align == 3:\n                nres += \"%g Tw \" % spacing\n\n            if color is not None:\n                nres += color_str\n            if fill is not None:\n                nres += fill_str\n            nres += \"%sTJ\\n\" % getTJstr(t, tj_glyphs, simple, ordering)\n\n        nres += \"ET\\n%sQ\\n\" % emc\n\n        self.text_cont += nres\n        self.updateRect(rect)\n        return more\n\n    def finish(\n        self,\n        width: float = 1,\n        color: OptSeq = (0,),\n        fill: OptSeq = None,\n        lineCap: int = 0,\n        lineJoin: int = 0,\n        dashes: OptStr = None,\n        even_odd: bool = False,\n        morph: OptSeq = None,\n        closePath: bool = True,\n        fill_opacity: float = 1,\n        stroke_opacity: float = 1,\n        oc: int = 0,\n    ) -> None:\n        \"\"\"Finish the current drawing segment.\n\n        Notes:\n            Apply colors, opacity, dashes, line style and width, or\n            morphing. Also whether to close the path\n            by connecting last to first point.\n        \"\"\"\n        if self.draw_cont == \"\":  # treat empty contents as no-op\n            return\n\n        if width == 0:  # border color makes no sense then\n            color = None\n        elif color == None:  # vice versa\n            width = 0\n        # if color == None and fill == None:\n        #     raise ValueError(\"at least one of 'color' or 'fill' must be given\")\n        color_str = ColorCode(color, \"c\")  # ensure proper color string\n        fill_str = ColorCode(fill, \"f\")  # ensure proper fill string\n\n        optcont = self.page._get_optional_content(oc)\n        if optcont is not None:\n            self.draw_cont = \"/OC /%s BDC\\n\" % optcont + self.draw_cont\n            emc = \"EMC\\n\"\n        else:\n            emc = \"\"\n\n        alpha = self.page._set_opacity(CA=stroke_opacity, ca=fill_opacity)\n        if alpha != None:\n            self.draw_cont = \"/%s gs\\n\" % alpha + self.draw_cont\n\n        if width != 1 and width != 0:\n            self.draw_cont += \"%g w\\n\" % width\n\n        if lineCap != 0:\n            self.draw_cont = \"%i J\\n\" % lineCap + self.draw_cont\n        if lineJoin != 0:\n            self.draw_cont = \"%i j\\n\" % lineJoin + self.draw_cont\n\n        if dashes not in (None, \"\", \"[] 0\"):\n            self.draw_cont = \"%s d\\n\" % dashes + self.draw_cont\n\n        if closePath:\n            self.draw_cont += \"h\\n\"\n            self.lastPoint = None\n\n        if color is not None:\n            self.draw_cont += color_str\n\n        if fill is not None:\n            self.draw_cont += fill_str\n            if color is not None:\n                if not even_odd:\n                    self.draw_cont += \"B\\n\"\n                else:\n                    self.draw_cont += \"B*\\n\"\n            else:\n                if not even_odd:\n                    self.draw_cont += \"f\\n\"\n                else:\n                    self.draw_cont += \"f*\\n\"\n        else:\n            self.draw_cont += \"S\\n\"\n\n        self.draw_cont += emc\n        if CheckMorph(morph):\n            m1 = Matrix(\n                1, 0, 0, 1, morph[0].x + self.x, self.height - morph[0].y - self.y\n            )\n            mat = ~m1 * morph[1] * m1\n            self.draw_cont = \"%g %g %g %g %g %g cm\\n\" % JM_TUPLE(mat) + self.draw_cont\n\n        self.totalcont += \"\\nq\\n\" + self.draw_cont + \"Q\\n\"\n        self.draw_cont = \"\"\n        self.lastPoint = None\n        return\n\n    def commit(self, overlay: bool = True) -> None:\n        \"\"\"Update the page's /Contents object with Shape data. The argument controls whether data appear in foreground (default) or background.\"\"\"\n        CheckParent(self.page)  # doc may have died meanwhile\n        self.totalcont += self.text_cont\n\n        self.totalcont = self.totalcont.encode()\n\n        if self.totalcont != b\"\":\n            # make /Contents object with dummy stream\n            xref = TOOLS._insert_contents(self.page, b\" \", overlay)\n            # update it with potential compression\n            self.doc.update_stream(xref, self.totalcont)\n\n        self.lastPoint = None  # clean up ...\n        self.rect = None  #\n        self.draw_cont = \"\"  # for potential ...\n        self.text_cont = \"\"  # ...\n        self.totalcont = \"\"  # re-use\n        return\n\n\ndef apply_redactions(page: Page, images: int = 2) -> bool:\n    \"\"\"Apply the redaction annotations of the page.\n\n    Args:\n        page: the PDF page.\n        images: 0 - ignore images, 1 - remove complete overlapping image,\n                2 - blank out overlapping image parts.\n    \"\"\"\n\n    def center_rect(annot_rect, text, font, fsize):\n        \"\"\"Calculate minimal sub-rectangle for the overlay text.\n\n        Notes:\n            Because 'insert_textbox' supports no vertical text centering,\n            we calculate an approximate number of lines here and return a\n            sub-rect with smaller height, which should still be sufficient.\n        Args:\n            annot_rect: the annotation rectangle\n            text: the text to insert.\n            font: the fontname. Must be one of the CJK or Base-14 set, else\n                the rectangle is returned unchanged.\n            fsize: the fontsize\n        Returns:\n            A rectangle to use instead of the annot rectangle.\n        \"\"\"\n        if not text:\n            return annot_rect\n        try:\n            text_width = get_text_length(text, font, fsize)\n        except ValueError:  # unsupported font\n            return annot_rect\n        line_height = fsize * 1.2\n        limit = annot_rect.width\n        h = math.ceil(text_width / limit) * line_height  # estimate rect height\n        if h >= annot_rect.height:\n            return annot_rect\n        r = annot_rect\n        y = (annot_rect.tl.y + annot_rect.bl.y - h) * 0.5\n        r.y0 = y\n        return r\n\n    CheckParent(page)\n    doc = page.parent\n    if doc.is_encrypted or doc.is_closed:\n        raise ValueError(\"document closed or encrypted\")\n    if not doc.is_pdf:\n        raise ValueError(\"is no PDF\")\n\n    redact_annots = []  # storage of annot values\n    for annot in page.annots(types=(PDF_ANNOT_REDACT,)):  # loop redactions\n        redact_annots.append(annot._get_redact_values())  # save annot values\n\n    if redact_annots == []:  # any redactions on this page?\n        return False  # no redactions\n\n    rc = page._apply_redactions(images)  # call MuPDF redaction process step\n    if not rc:  # should not happen really\n        raise ValueError(\"Error applying redactions.\")\n\n    # now write replacement text in old redact rectangles\n    shape = page.new_shape()\n    for redact in redact_annots:\n        annot_rect = redact[\"rect\"]\n        fill = redact[\"fill\"]\n        if fill:\n            shape.draw_rect(annot_rect)  # colorize the rect background\n            shape.finish(fill=fill, color=fill)\n        if \"text\" in redact.keys():  # if we also have text\n            text = redact[\"text\"]\n            align = redact.get(\"align\", 0)\n            fname = redact[\"fontname\"]\n            fsize = redact[\"fontsize\"]\n            color = redact[\"text_color\"]\n            # try finding vertical centered sub-rect\n            trect = center_rect(annot_rect, text, fname, fsize)\n\n            rc = -1\n            while rc < 0 and fsize >= 4:  # while not enough room\n                # (re-) try insertion\n                rc = shape.insert_textbox(\n                    trect,\n                    text,\n                    fontname=fname,\n                    fontsize=fsize,\n                    color=color,\n                    align=align,\n                )\n                fsize -= 0.5  # reduce font if unsuccessful\n    shape.commit()  # append new contents object\n    return True\n\n\n# ------------------------------------------------------------------------------\n# Remove potentially sensitive data from a PDF. Similar to the Adobe\n# Acrobat 'sanitize' function\n# ------------------------------------------------------------------------------\ndef scrub(\n    doc: Document,\n    attached_files: bool = True,\n    clean_pages: bool = True,\n    embedded_files: bool = True,\n    hidden_text: bool = True,\n    javascript: bool = True,\n    metadata: bool = True,\n    redactions: bool = True,\n    redact_images: int = 0,\n    remove_links: bool = True,\n    reset_fields: bool = True,\n    reset_responses: bool = True,\n    thumbnails: bool = True,\n    xml_metadata: bool = True,\n) -> None:\n    def remove_hidden(cont_lines):\n        \"\"\"Remove hidden text from a PDF page.\n\n        Args:\n            cont_lines: list of lines with /Contents content. Should have status\n                from after page.cleanContents().\n\n        Returns:\n            List of /Contents lines from which hidden text has been removed.\n\n        Notes:\n            The input must have been created after the page's /Contents object(s)\n            have been cleaned with page.cleanContents(). This ensures a standard\n            formatting: one command per line, single spaces between operators.\n            This allows for drastic simplification of this code.\n        \"\"\"\n        out_lines = []  # will return this\n        in_text = False  # indicate if within BT/ET object\n        suppress = False  # indicate text suppression active\n        make_return = False\n        for line in cont_lines:\n            if line == b\"BT\":  # start of text object\n                in_text = True  # switch on\n                out_lines.append(line)  # output it\n                continue\n            if line == b\"ET\":  # end of text object\n                in_text = False  # switch off\n                out_lines.append(line)  # output it\n                continue\n            if line == b\"3 Tr\":  # text suppression operator\n                suppress = True  # switch on\n                make_return = True\n                continue\n            if line[-2:] == b\"Tr\" and line[0] != b\"3\":\n                suppress = False  # text rendering changed\n                out_lines.append(line)\n                continue\n            if line == b\"Q\":  # unstack command also switches off\n                suppress = False\n                out_lines.append(line)\n                continue\n            if suppress and in_text:  # suppress hidden lines\n                continue\n            out_lines.append(line)\n        if make_return:\n            return out_lines\n        else:\n            return None\n\n    if not doc.is_pdf:  # only works for PDF\n        raise ValueError(\"is no PDF\")\n    if doc.is_encrypted or doc.is_closed:\n        raise ValueError(\"closed or encrypted doc\")\n\n    if clean_pages is False:\n        hidden_text = False\n        redactions = False\n\n    if metadata:\n        doc.set_metadata({})  # remove standard metadata\n\n    for page in doc:\n        if reset_fields:\n            # reset form fields (widgets)\n            for widget in page.widgets():\n                widget.reset()\n\n        if remove_links:\n            links = page.get_links()  # list of all links on page\n            for link in links:  # remove all links\n                page.delete_link(link)\n\n        found_redacts = False\n        for annot in page.annots():\n            if annot.type[0] == PDF_ANNOT_FILE_ATTACHMENT and attached_files:\n                annot.update_file(buffer=b\" \")  # set file content to empty\n            if reset_responses:\n                annot.delete_responses()\n            if annot.type[0] == PDF_ANNOT_REDACT:\n                found_redacts = True\n\n        if redactions and found_redacts:\n            page.apply_redactions(images=redact_images)\n\n        if not (clean_pages or hidden_text):\n            continue  # done with the page\n\n        page.clean_contents()\n        if not page.get_contents():\n            continue\n        if hidden_text:\n            xref = page.get_contents()[0]  # only one b/o cleaning!\n            cont = doc.xref_stream(xref)\n            cont_lines = remove_hidden(cont.splitlines())  # remove hidden text\n            if cont_lines:  # something was actually removed\n                cont = b\"\\n\".join(cont_lines)\n                doc.update_stream(xref, cont)  # rewrite the page /Contents\n\n        if thumbnails:  # remove page thumbnails?\n            if doc.xref_get_key(page.xref, \"Thumb\")[0] != \"null\":\n                doc.xref_set_key(page.xref, \"Thumb\", \"null\")\n\n    # pages are scrubbed, now perform document-wide scrubbing\n    # remove embedded files\n    if embedded_files:\n        for name in doc.embfile_names():\n            doc.embfile_del(name)\n\n    if xml_metadata:\n        doc.del_xml_metadata()\n    if not (xml_metadata or javascript):\n        xref_limit = 0\n    else:\n        xref_limit = doc.xref_length()\n    for xref in range(1, xref_limit):\n        if not doc.xref_object(xref):\n            msg = \"bad xref %i - clean PDF before scrubbing\" % xref\n            raise ValueError(msg)\n        if javascript and doc.xref_get_key(xref, \"S\")[1] == \"/JavaScript\":\n            # a /JavaScript action object\n            obj = \"<</S/JavaScript/JS()>>\"  # replace with a null JavaScript\n            doc.update_object(xref, obj)  # update this object\n            continue  # no further handling\n\n        if not xml_metadata:\n            continue\n\n        if doc.xref_get_key(xref, \"Type\")[1] == \"/Metadata\":\n            # delete any metadata object directly\n            doc.update_object(xref, \"<<>>\")\n            doc.update_stream(xref, b\"deleted\", new=True)\n            continue\n\n        if doc.xref_get_key(xref, \"Metadata\")[0] != \"null\":\n            doc.xref_set_key(xref, \"Metadata\", \"null\")\n\n\ndef fill_textbox(\n    writer: TextWriter,\n    rect: rect_like,\n    text: typing.Union[str, list],\n    pos: point_like = None,\n    font: typing.Optional[Font] = None,\n    fontsize: float = 11,\n    lineheight: OptFloat = None,\n    align: int = 0,\n    warn: bool = None,\n    right_to_left: bool = False,\n    small_caps: bool = False,\n) -> tuple:\n    \"\"\"Fill a rectangle with text.\n\n    Args:\n        writer: TextWriter object (= \"self\")\n        rect: rect-like to receive the text.\n        text: string or list/tuple of strings.\n        pos: point-like start position of first word.\n        font: Font object (default Font('helv')).\n        fontsize: the fontsize.\n        lineheight: overwrite the font property\n        align: (int) 0 = left, 1 = center, 2 = right, 3 = justify\n        warn: (bool) text overflow action: none, warn, or exception\n        right_to_left: (bool) indicate right-to-left language.\n    \"\"\"\n    rect = Rect(rect)\n    if rect.is_empty:\n        raise ValueError(\"fill rect must not empty.\")\n    if type(font) is not Font:\n        font = Font(\"helv\")\n\n    def textlen(x):\n        \"\"\"Return length of a string.\"\"\"\n        return font.text_length(\n            x, fontsize=fontsize, small_caps=small_caps\n        )  # abbreviation\n\n    def char_lengths(x):\n        \"\"\"Return list of single character lengths for a string.\"\"\"\n        return font.char_lengths(x, fontsize=fontsize, small_caps=small_caps)\n\n    def append_this(pos, text):\n        return writer.append(\n            pos, text, font=font, fontsize=fontsize, small_caps=small_caps\n        )\n\n    tolerance = fontsize * 0.2  # extra distance to left border\n    space_len = textlen(\" \")\n    std_width = rect.width - tolerance\n    std_start = rect.x0 + tolerance\n\n    def norm_words(width, words):\n        \"\"\"Cut any word in pieces no longer than 'width'.\"\"\"\n        nwords = []\n        word_lengths = []\n        for w in words:\n            wl_lst = char_lengths(w)\n            wl = sum(wl_lst)\n            if wl <= width:  # nothing to do - copy over\n                nwords.append(w)\n                word_lengths.append(wl)\n                continue\n\n            # word longer than rect width - split it in parts\n            n = len(wl_lst)\n            while n > 0:\n                wl = sum(wl_lst[:n])\n                if wl <= width:\n                    nwords.append(w[:n])\n                    word_lengths.append(wl)\n                    w = w[n:]\n                    wl_lst = wl_lst[n:]\n                    n = len(wl_lst)\n                else:\n                    n -= 1\n        return nwords, word_lengths\n\n    def output_justify(start, line):\n        \"\"\"Justified output of a line.\"\"\"\n        # ignore leading / trailing / multiple spaces\n        words = [w for w in line.split(\" \") if w != \"\"]\n        nwords = len(words)\n        if nwords == 0:\n            return\n        if nwords == 1:  # single word cannot be justified\n            append_this(start, words[0])\n            return\n        tl = sum([textlen(w) for w in words])  # total word lengths\n        gaps = nwords - 1  # number of word gaps\n        gapl = (std_width - tl) / gaps  # width of each gap\n        for w in words:\n            _, lp = append_this(start, w)  # output one word\n            start.x = lp.x + gapl  # next start at word end plus gap\n        return\n\n    asc = font.ascender\n    dsc = font.descender\n    if not lineheight:\n        if asc - dsc <= 1:\n            lheight = 1.2\n        else:\n            lheight = asc - dsc\n    else:\n        lheight = lineheight\n\n    LINEHEIGHT = fontsize * lheight  # effective line height\n    width = std_width  # available horizontal space\n\n    # starting point of text\n    if pos is not None:\n        pos = Point(pos)\n    else:  # default is just below rect top-left\n        pos = rect.tl + (tolerance, fontsize * asc)\n    if not pos in rect:\n        raise ValueError(\"Text must start in rectangle.\")\n\n    # calculate displacement factor for alignment\n    if align == TEXT_ALIGN_CENTER:\n        factor = 0.5\n    elif align == TEXT_ALIGN_RIGHT:\n        factor = 1.0\n    else:\n        factor = 0\n\n    # split in lines if just a string was given\n    if type(text) is str:\n        textlines = text.splitlines()\n    else:\n        textlines = []\n        for line in text:\n            textlines.extend(line.splitlines())\n\n    max_lines = int((rect.y1 - pos.y) / LINEHEIGHT) + 1\n\n    new_lines = []  # the final list of textbox lines\n    no_justify = []  # no justify for these line numbers\n    for i, line in enumerate(textlines):\n        if line in (\"\", \" \"):\n            new_lines.append((line, space_len))\n            width = rect.width - tolerance\n            no_justify.append((len(new_lines) - 1))\n            continue\n        if i == 0:\n            width = rect.x1 - pos.x\n        else:\n            width = rect.width - tolerance\n\n        if right_to_left:  # reverses Arabic / Hebrew text front to back\n            line = writer.clean_rtl(line)\n        tl = textlen(line)\n        if tl <= width:  # line short enough\n            new_lines.append((line, tl))\n            no_justify.append((len(new_lines) - 1))\n            continue\n\n        # we need to split the line in fitting parts\n        words = line.split(\" \")  # the words in the line\n\n        # cut in parts any words that are longer than rect width\n        words, word_lengths = norm_words(std_width, words)\n\n        n = len(words)\n        while True:\n            line0 = \" \".join(words[:n])\n            wl = sum(word_lengths[:n]) + space_len * (len(word_lengths[:n]) - 1)\n            if wl <= width:\n                new_lines.append((line0, wl))\n                words = words[n:]\n                word_lengths = word_lengths[n:]\n                n = len(words)\n                line0 = None\n            else:\n                n -= 1\n\n            if len(words) == 0:\n                break\n\n    # -------------------------------------------------------------------------\n    # List of lines created. Each item is (text, tl), where 'tl' is the PDF\n    # output length (float) and 'text' is the text. Except for justified text,\n    # this is output-ready.\n    # -------------------------------------------------------------------------\n    nlines = len(new_lines)\n    if nlines > max_lines:\n        msg = \"Only fitting %i of %i lines.\" % (max_lines, nlines)\n        if warn == True:\n            print(\"Warning: \" + msg)\n        elif warn == False:\n            raise ValueError(msg)\n\n    start = Point()\n    no_justify += [len(new_lines) - 1]  # no justifying of last line\n    for i in range(max_lines):\n        try:\n            line, tl = new_lines.pop(0)\n        except IndexError:\n            break\n\n        if right_to_left:  # Arabic, Hebrew\n            line = \"\".join(reversed(line))\n\n        if i == 0:  # may have different start for first line\n            start = pos\n\n        if align == TEXT_ALIGN_JUSTIFY and i not in no_justify and tl < std_width:\n            output_justify(start, line)\n            start.x = std_start\n            start.y += LINEHEIGHT\n            continue\n\n        if i > 0 or pos.x == std_start:  # left, center, right alignments\n            start.x += (width - tl) * factor\n\n        append_this(start, line)\n        start.x = std_start\n        start.y += LINEHEIGHT\n\n    return new_lines  # return non-written lines\n\n\n# ------------------------------------------------------------------------\n# Optional Content functions\n# ------------------------------------------------------------------------\ndef get_oc(doc: Document, xref: int) -> int:\n    \"\"\"Return optional content object xref for an image or form xobject.\n\n    Args:\n        xref: (int) xref number of an image or form xobject.\n    \"\"\"\n    if doc.is_closed or doc.is_encrypted:\n        raise ValueError(\"document close or encrypted\")\n    t, name = doc.xref_get_key(xref, \"Subtype\")\n    if t != \"name\" or name not in (\"/Image\", \"/Form\"):\n        raise ValueError(\"bad object type at xref %i\" % xref)\n    t, oc = doc.xref_get_key(xref, \"OC\")\n    if t != \"xref\":\n        return 0\n    rc = int(oc.replace(\"0 R\", \"\"))\n    return rc\n\n\ndef set_oc(doc: Document, xref: int, oc: int) -> None:\n    \"\"\"Attach optional content object to image or form xobject.\n\n    Args:\n        xref: (int) xref number of an image or form xobject\n        oc: (int) xref number of an OCG or OCMD\n    \"\"\"\n    if doc.is_closed or doc.is_encrypted:\n        raise ValueError(\"document close or encrypted\")\n    t, name = doc.xref_get_key(xref, \"Subtype\")\n    if t != \"name\" or name not in (\"/Image\", \"/Form\"):\n        raise ValueError(\"bad object type at xref %i\" % xref)\n    if oc > 0:\n        t, name = doc.xref_get_key(oc, \"Type\")\n        if t != \"name\" or name not in (\"/OCG\", \"/OCMD\"):\n            raise ValueError(\"bad object type at xref %i\" % oc)\n    if oc == 0 and \"OC\" in doc.xref_get_keys(xref):\n        doc.xref_set_key(xref, \"OC\", \"null\")\n        return None\n    doc.xref_set_key(xref, \"OC\", \"%i 0 R\" % oc)\n    return None\n\n\ndef set_ocmd(\n    doc: Document,\n    xref: int = 0,\n    ocgs: typing.Union[list, None] = None,\n    policy: OptStr = None,\n    ve: typing.Union[list, None] = None,\n) -> int:\n    \"\"\"Create or update an OCMD object in a PDF document.\n\n    Args:\n        xref: (int) 0 for creating a new object, otherwise update existing one.\n        ocgs: (list) OCG xref numbers, which shall be subject to 'policy'.\n        policy: one of 'AllOn', 'AllOff', 'AnyOn', 'AnyOff' (any casing).\n        ve: (list) visibility expression. Use instead of 'ocgs' with 'policy'.\n\n    Returns:\n        Xref of the created or updated OCMD.\n    \"\"\"\n\n    all_ocgs = set(doc.get_ocgs().keys())\n\n    def ve_maker(ve):\n        if type(ve) not in (list, tuple) or len(ve) < 2:\n            raise ValueError(\"bad 've' format: %s\" % ve)\n        if ve[0].lower() not in (\"and\", \"or\", \"not\"):\n            raise ValueError(\"bad operand: %s\" % ve[0])\n        if ve[0].lower() == \"not\" and len(ve) != 2:\n            raise ValueError(\"bad 've' format: %s\" % ve)\n        item = \"[/%s\" % ve[0].title()\n        for x in ve[1:]:\n            if type(x) is int:\n                if x not in all_ocgs:\n                    raise ValueError(\"bad OCG %i\" % x)\n                item += \" %i 0 R\" % x\n            else:\n                item += \" %s\" % ve_maker(x)\n        item += \"]\"\n        return item\n\n    text = \"<</Type/OCMD\"\n\n    if ocgs and type(ocgs) in (list, tuple):  # some OCGs are provided\n        s = set(ocgs).difference(all_ocgs)  # contains illegal xrefs\n        if s != set():\n            msg = \"bad OCGs: %s\" % s\n            raise ValueError(msg)\n        text += \"/OCGs[\" + \" \".join(map(lambda x: \"%i 0 R\" % x, ocgs)) + \"]\"\n\n    if policy:\n        policy = str(policy).lower()\n        pols = {\n            \"anyon\": \"AnyOn\",\n            \"allon\": \"AllOn\",\n            \"anyoff\": \"AnyOff\",\n            \"alloff\": \"AllOff\",\n        }\n        if policy not in (\"anyon\", \"allon\", \"anyoff\", \"alloff\"):\n            raise ValueError(\"bad policy: %s\" % policy)\n        text += \"/P/%s\" % pols[policy]\n\n    if ve:\n        text += \"/VE%s\" % ve_maker(ve)\n\n    text += \">>\"\n\n    # make new object or replace old OCMD (check type first)\n    if xref == 0:\n        xref = doc.get_new_xref()\n    elif \"/Type/OCMD\" not in doc.xref_object(xref, compressed=True):\n        raise ValueError(\"bad xref or not an OCMD\")\n    doc.update_object(xref, text)\n    return xref\n\n\ndef get_ocmd(doc: Document, xref: int) -> dict:\n    \"\"\"Return the definition of an OCMD (optional content membership dictionary).\n\n    Recognizes PDF dict keys /OCGs (PDF array of OCGs), /P (policy string) and\n    /VE (visibility expression, PDF array). Via string manipulation, this\n    info is converted to a Python dictionary with keys \"xref\", \"ocgs\", \"policy\"\n    and \"ve\" - ready to recycle as input for 'set_ocmd()'.\n    \"\"\"\n\n    if xref not in range(doc.xref_length()):\n        raise ValueError(\"bad xref\")\n    text = doc.xref_object(xref, compressed=True)\n    if \"/Type/OCMD\" not in text:\n        raise ValueError(\"bad object type\")\n    textlen = len(text)\n\n    p0 = text.find(\"/OCGs[\")  # look for /OCGs key\n    p1 = text.find(\"]\", p0)\n    if p0 < 0 or p1 < 0:  # no OCGs found\n        ocgs = None\n    else:\n        ocgs = text[p0 + 6 : p1].replace(\"0 R\", \" \").split()\n        ocgs = list(map(int, ocgs))\n\n    p0 = text.find(\"/P/\")  # look for /P policy key\n    if p0 < 0:\n        policy = None\n    else:\n        p1 = text.find(\"ff\", p0)\n        if p1 < 0:\n            p1 = text.find(\"on\", p0)\n        if p1 < 0:  # some irregular syntax\n            raise ValueError(\"bad object at xref\")\n        else:\n            policy = text[p0 + 3 : p1 + 2]\n\n    p0 = text.find(\"/VE[\")  # look for /VE visibility expression key\n    if p0 < 0:  # no visibility expression found\n        ve = None\n    else:\n        lp = rp = 0  # find end of /VE by finding last ']'.\n        p1 = p0\n        while lp < 1 or lp != rp:\n            p1 += 1\n            if not p1 < textlen:  # some irregular syntax\n                raise ValueError(\"bad object at xref\")\n            if text[p1] == \"[\":\n                lp += 1\n            if text[p1] == \"]\":\n                rp += 1\n        # p1 now positioned at the last \"]\"\n        ve = text[p0 + 3 : p1 + 1]  # the PDF /VE array\n        ve = (\n            ve.replace(\"/And\", '\"and\",')\n            .replace(\"/Not\", '\"not\",')\n            .replace(\"/Or\", '\"or\",')\n        )\n        ve = ve.replace(\" 0 R]\", \"]\").replace(\" 0 R\", \",\").replace(\"][\", \"],[\")\n        try:\n            ve = json.loads(ve)\n        except:\n            print(\"bad /VE key: \", ve)\n            raise\n    return {\"xref\": xref, \"ocgs\": ocgs, \"policy\": policy, \"ve\": ve}\n\n\n\"\"\"\nHandle page labels for PDF documents.\n\nReading\n-------\n* compute the label of a page\n* find page number(s) having the given label.\n\nWriting\n-------\nSupports setting (defining) page labels for PDF documents.\n\nA big Thank You goes to WILLIAM CHAPMAN who contributed the idea and\nsignificant parts of the following code during late December 2020\nthrough early January 2021.\n\"\"\"\n\n\ndef rule_dict(item):\n    \"\"\"Make a Python dict from a PDF page label rule.\n\n    Args:\n        item -- a tuple (pno, rule) with the start page number and the rule\n                string like <</S/D...>>.\n    Returns:\n        A dict like\n        {'startpage': int, 'prefix': str, 'style': str, 'firstpagenum': int}.\n    \"\"\"\n    # Jorj McKie, 2021-01-06\n\n    pno, rule = item\n    rule = rule[2:-2].split(\"/\")[1:]  # strip \"<<\" and \">>\"\n    d = {\"startpage\": pno, \"prefix\": \"\", \"firstpagenum\": 1}\n    skip = False\n    for i, item in enumerate(rule):\n        if skip:  # this item has already been processed\n            skip = False  # deactivate skipping again\n            continue\n        if item == \"S\":  # style specification\n            d[\"style\"] = rule[i + 1]  # next item has the style\n            skip = True  # do not process next item again\n            continue\n        if item.startswith(\"P\"):  # prefix specification: extract the string\n            x = item[1:].replace(\"(\", \"\").replace(\")\", \"\")\n            d[\"prefix\"] = x\n            continue\n        if item.startswith(\"St\"):  # start page number specification\n            x = int(item[2:])\n            d[\"firstpagenum\"] = x\n    return d\n\n\ndef get_label_pno(pgNo, labels):\n    \"\"\"Return the label for this page number.\n\n    Args:\n        pgNo: page number, 0-based.\n        labels: result of doc._get_page_labels().\n    Returns:\n        The label (str) of the page number. Errors return an empty string.\n    \"\"\"\n    # Jorj McKie, 2021-01-06\n\n    item = [x for x in labels if x[0] <= pgNo][-1]\n    rule = rule_dict(item)\n    prefix = rule.get(\"prefix\", \"\")\n    style = rule.get(\"style\", \"\")\n    pagenumber = pgNo - rule[\"startpage\"] + rule[\"firstpagenum\"]\n    return construct_label(style, prefix, pagenumber)\n\n\ndef get_label(page):\n    \"\"\"Return the label for this PDF page.\n\n    Args:\n        page: page object.\n    Returns:\n        The label (str) of the page. Errors return an empty string.\n    \"\"\"\n    # Jorj McKie, 2021-01-06\n\n    labels = page.parent._get_page_labels()\n    if not labels:\n        return \"\"\n    labels.sort()\n    return get_label_pno(page.number, labels)\n\n\ndef get_page_numbers(doc, label, only_one=False):\n    \"\"\"Return a list of page numbers with the given label.\n\n    Args:\n        doc: PDF document object (resp. 'self').\n        label: (str) label.\n        only_one: (bool) stop searching after first hit.\n    Returns:\n        List of page numbers having this label.\n    \"\"\"\n    # Jorj McKie, 2021-01-06\n\n    numbers = []\n    if not label:\n        return numbers\n    labels = doc._get_page_labels()\n    if labels == []:\n        return numbers\n    for i in range(doc.page_count):\n        plabel = get_label_pno(i, labels)\n        if plabel == label:\n            numbers.append(i)\n            if only_one:\n                break\n    return numbers\n\n\ndef construct_label(style, prefix, pno) -> str:\n    \"\"\"Construct a label based on style, prefix and page number.\"\"\"\n    # William Chapman, 2021-01-06\n\n    n_str = \"\"\n    if style == \"D\":\n        n_str = str(pno)\n    elif style == \"r\":\n        n_str = integerToRoman(pno).lower()\n    elif style == \"R\":\n        n_str = integerToRoman(pno).upper()\n    elif style == \"a\":\n        n_str = integerToLetter(pno).lower()\n    elif style == \"A\":\n        n_str = integerToLetter(pno).upper()\n    result = prefix + n_str\n    return result\n\n\ndef integerToLetter(i) -> str:\n    \"\"\"Returns letter sequence string for integer i.\"\"\"\n    # William Chapman, Jorj McKie, 2021-01-06\n\n    ls = string.ascii_uppercase\n    n, a = 1, i\n    while pow(26, n) <= a:\n        a -= int(math.pow(26, n))\n        n += 1\n\n    str_t = \"\"\n    for j in reversed(range(n)):\n        f, g = divmod(a, int(math.pow(26, j)))\n        str_t += ls[f]\n        a = g\n    return str_t\n\n\ndef integerToRoman(num: int) -> str:\n    \"\"\"Return roman numeral for an integer.\"\"\"\n    # William Chapman, Jorj McKie, 2021-01-06\n\n    roman = (\n        (1000, \"M\"),\n        (900, \"CM\"),\n        (500, \"D\"),\n        (400, \"CD\"),\n        (100, \"C\"),\n        (90, \"XC\"),\n        (50, \"L\"),\n        (40, \"XL\"),\n        (10, \"X\"),\n        (9, \"IX\"),\n        (5, \"V\"),\n        (4, \"IV\"),\n        (1, \"I\"),\n    )\n\n    def roman_num(num):\n        for r, ltr in roman:\n            x, _ = divmod(num, r)\n            yield ltr * x\n            num -= r * x\n            if num <= 0:\n                break\n\n    return \"\".join([a for a in roman_num(num)])\n\n\ndef get_page_labels(doc):\n    \"\"\"Return page label definitions in PDF document.\n\n    Args:\n        doc: PDF document (resp. 'self').\n    Returns:\n        A list of dictionaries with the following format:\n        {'startpage': int, 'prefix': str, 'style': str, 'firstpagenum': int}.\n    \"\"\"\n    # Jorj McKie, 2021-01-10\n    return [rule_dict(item) for item in doc._get_page_labels()]\n\n\ndef set_page_labels(doc, labels):\n    \"\"\"Add / replace page label definitions in PDF document.\n\n    Args:\n        doc: PDF document (resp. 'self').\n        labels: list of label dictionaries like:\n        {'startpage': int, 'prefix': str, 'style': str, 'firstpagenum': int},\n        as returned by get_page_labels().\n    \"\"\"\n    # William Chapman, 2021-01-06\n\n    def create_label_str(label):\n        \"\"\"Convert Python label dict to correspnding PDF rule string.\n\n        Args:\n            label: (dict) build rule for the label.\n        Returns:\n            PDF label rule string wrapped in \"<<\", \">>\".\n        \"\"\"\n        s = \"%i<<\" % label[\"startpage\"]\n        if label.get(\"prefix\", \"\") != \"\":\n            s += \"/P(%s)\" % label[\"prefix\"]\n        if label.get(\"style\", \"\") != \"\":\n            s += \"/S/%s\" % label[\"style\"]\n        if label.get(\"firstpagenum\", 1) > 1:\n            s += \"/St %i\" % label[\"firstpagenum\"]\n        s += \">>\"\n        return s\n\n    def create_nums(labels):\n        \"\"\"Return concatenated string of all labels rules.\n\n        Args:\n            labels: (list) dictionaries as created by function 'rule_dict'.\n        Returns:\n            PDF compatible string for page label definitions, ready to be\n            enclosed in PDF array 'Nums[...]'.\n        \"\"\"\n        labels.sort(key=lambda x: x[\"startpage\"])\n        s = \"\".join([create_label_str(label) for label in labels])\n        return s\n\n    doc._set_page_labels(create_nums(labels))\n\n\n# End of Page Label Code -------------------------------------------------\n\n\ndef has_links(doc: Document) -> bool:\n    \"\"\"Check whether there are links on any page.\"\"\"\n    if doc.is_closed:\n        raise ValueError(\"document closed\")\n    if not doc.is_pdf:\n        raise ValueError(\"is no PDF\")\n    for i in range(doc.page_count):\n        for item in doc.page_annot_xrefs(i):\n            if item[1] == PDF_ANNOT_LINK:\n                return True\n    return False\n\n\ndef has_annots(doc: Document) -> bool:\n    \"\"\"Check whether there are annotations on any page.\"\"\"\n    if doc.is_closed:\n        raise ValueError(\"document closed\")\n    if not doc.is_pdf:\n        raise ValueError(\"is no PDF\")\n    for i in range(doc.page_count):\n        for item in doc.page_annot_xrefs(i):\n            if not (item[1] == PDF_ANNOT_LINK or item[1] == PDF_ANNOT_WIDGET):\n                return True\n    return False\n\n\n# -------------------------------------------------------------------\n# Functions to recover the quad contained in a text extraction bbox\n# -------------------------------------------------------------------\ndef recover_bbox_quad(line_dir: tuple, span: dict, bbox: tuple) -> Quad:\n    \"\"\"Compute the quad located inside the bbox.\n\n    The bbox may be any of the resp. tuples occurring inside the given span.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the owning line or None.\n        span: (dict) the span. May be from get_texttrace() method.\n        bbox: (tuple) the bbox of the span or any of its characters.\n    Returns:\n        The quad which is wrapped by the bbox.\n    \"\"\"\n    if line_dir == None:\n        line_dir = span[\"dir\"]\n    cos, sin = line_dir\n    bbox = Rect(bbox)  # make it a rect\n    if TOOLS.set_small_glyph_heights():  # ==> just fontsize as height\n        d = 1\n    else:\n        d = span[\"ascender\"] - span[\"descender\"]\n\n    height = d * span[\"size\"]  # the quad's rectangle height\n    # The following are distances from the bbox corners, at wich we find the\n    # respective quad points. The computation depends on in which quadrant\n    # the text writing angle is located.\n    hs = height * sin\n    hc = height * cos\n    if hc >= 0 and hs <= 0:  # quadrant 1\n        ul = bbox.bl - (0, hc)\n        ur = bbox.tr + (hs, 0)\n        ll = bbox.bl - (hs, 0)\n        lr = bbox.tr + (0, hc)\n    elif hc <= 0 and hs <= 0:  # quadrant 2\n        ul = bbox.br + (hs, 0)\n        ur = bbox.tl - (0, hc)\n        ll = bbox.br + (0, hc)\n        lr = bbox.tl - (hs, 0)\n    elif hc <= 0 and hs >= 0:  # quadrant 3\n        ul = bbox.tr - (0, hc)\n        ur = bbox.bl + (hs, 0)\n        ll = bbox.tr - (hs, 0)\n        lr = bbox.bl + (0, hc)\n    else:  # quadrant 4\n        ul = bbox.tl + (hs, 0)\n        ur = bbox.br - (0, hc)\n        ll = bbox.tl + (0, hc)\n        lr = bbox.br - (hs, 0)\n    return Quad(ul, ur, ll, lr)\n\n\ndef recover_quad(line_dir: tuple, span: dict) -> Quad:\n    \"\"\"Recover the quadrilateral of a text span.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the owning line.\n        span: the span.\n    Returns:\n        The quadrilateral enveloping the span's text.\n    \"\"\"\n    if type(line_dir) is not tuple or len(line_dir) != 2:\n        raise ValueError(\"bad line dir argument\")\n    if type(span) is not dict:\n        raise ValueError(\"bad span argument\")\n    return recover_bbox_quad(line_dir, span, span[\"bbox\"])\n\n\ndef recover_line_quad(line: dict, spans: list = None) -> Quad:\n    \"\"\"Calculate the line quad for 'dict' / 'rawdict' text extractions.\n\n    The lower quad points are those of the first, resp. last span quad.\n    The upper points are determined by the maximum span quad height.\n    From this, compute a rect with bottom-left in (0, 0), convert this to a\n    quad and rotate and shift back to cover the text of the spans.\n\n    Args:\n        spans: (list, optional) sub-list of spans to consider.\n    Returns:\n        Quad covering selected spans.\n    \"\"\"\n    if spans == None:  # no sub-selection\n        spans = line[\"spans\"]  # all spans\n    if len(spans) == 0:\n        raise ValueError(\"bad span list\")\n    line_dir = line[\"dir\"]  # text direction\n    cos, sin = line_dir\n    q0 = recover_quad(line_dir, spans[0])  # quad of first span\n    if len(spans) > 1:  # get quad of last span\n        q1 = recover_quad(line_dir, spans[-1])\n    else:\n        q1 = q0  # last = first\n\n    line_ll = q0.ll  # lower-left of line quad\n    line_lr = q1.lr  # lower-right of line quad\n\n    mat0 = planish_line(line_ll, line_lr)\n\n    # map base line to x-axis such that line_ll goes to (0, 0)\n    x_lr = line_lr * mat0\n\n    small = TOOLS.set_small_glyph_heights()  # small glyph heights?\n\n    h = max(\n        [s[\"size\"] * (1 if small else (s[\"ascender\"] - s[\"descender\"])) for s in spans]\n    )\n\n    line_rect = Rect(0, -h, x_lr.x, 0)  # line rectangle\n    line_quad = line_rect.quad  # make it a quad and:\n    line_quad *= ~mat0\n    return line_quad\n\n\ndef recover_span_quad(line_dir: tuple, span: dict, chars: list = None) -> Quad:\n    \"\"\"Calculate the span quad for 'dict' / 'rawdict' text extractions.\n\n    Notes:\n        There are two execution paths:\n        1. For the full span quad, the result of 'recover_quad' is returned.\n        2. For the quad of a sub-list of characters, the char quads are\n           computed and joined. This is only supported for the \"rawdict\"\n           extraction option.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the owning line.\n        span: (dict) the span.\n        chars: (list, optional) sub-list of characters to consider.\n    Returns:\n        Quad covering selected characters.\n    \"\"\"\n    if line_dir == None:  # must be a span from get_texttrace()\n        line_dir = span[\"dir\"]\n    if chars == None:  # no sub-selection\n        return recover_quad(line_dir, span)\n    if not \"chars\" in span.keys():\n        raise ValueError(\"need 'rawdict' option to sub-select chars\")\n\n    q0 = recover_char_quad(line_dir, span, chars[0])  # quad of first char\n    if len(chars) > 1:  # get quad of last char\n        q1 = recover_char_quad(line_dir, span, chars[-1])\n    else:\n        q1 = q0  # last = first\n\n    span_ll = q0.ll  # lower-left of span quad\n    span_lr = q1.lr  # lower-right of span quad\n    mat0 = planish_line(span_ll, span_lr)\n    # map base line to x-axis such that span_ll goes to (0, 0)\n    x_lr = span_lr * mat0\n\n    small = TOOLS.set_small_glyph_heights()  # small glyph heights?\n    h = span[\"size\"] * (1 if small else (span[\"ascender\"] - span[\"descender\"]))\n\n    span_rect = Rect(0, -h, x_lr.x, 0)  # line rectangle\n    span_quad = span_rect.quad  # make it a quad and:\n    span_quad *= ~mat0  # rotate back and shift back\n    return span_quad\n\n\ndef recover_char_quad(line_dir: tuple, span: dict, char: dict) -> Quad:\n    \"\"\"Recover the quadrilateral of a text character.\n\n    This requires the \"rawdict\" option of text extraction.\n\n    Args:\n        line_dir: (tuple) 'line[\"dir\"]' of the span's line.\n        span: (dict) the span dict.\n        char: (dict) the character dict.\n    Returns:\n        The quadrilateral enveloping the character.\n    \"\"\"\n    if line_dir == None:\n        line_dir = span[\"dir\"]\n    if type(line_dir) is not tuple or len(line_dir) != 2:\n        raise ValueError(\"bad line dir argument\")\n    if type(span) is not dict:\n        raise ValueError(\"bad span argument\")\n    if type(char) is dict:\n        bbox = Rect(char[\"bbox\"])\n    elif type(char) is tuple:\n        bbox = Rect(char[3])\n    else:\n        raise ValueError(\"bad span argument\")\n\n    return recover_bbox_quad(line_dir, span, bbox)\n\n\n# -------------------------------------------------------------------\n# Building font subsets using fontTools\n# -------------------------------------------------------------------\ndef subset_fonts(doc: Document, verbose: bool = False) -> None:\n    \"\"\"Build font subsets of a PDF. Requires package 'fontTools'.\n\n    Eligible fonts are potentially replaced by smaller versions. Page text is\n    NOT rewritten and thus should retain properties like being hidden or\n    controlled by optional content.\n    \"\"\"\n    # Font binaries: -  \"buffer\" -> (names, xrefs, (unicodes, glyphs))\n    # An embedded font is uniquely defined by its fontbuffer only. It may have\n    # multiple names and xrefs.\n    # Once the sets of used unicodes and glyphs are known, we compute a\n    # smaller version of the buffer user package fontTools.\n    font_buffers = {}\n\n    def get_old_widths(xref):\n        \"\"\"Retrieve old font '/W' and '/DW' values.\"\"\"\n        df = doc.xref_get_key(xref, \"DescendantFonts\")\n        if df[0] != \"array\":  # only handle xref specifications\n            return None, None\n        df_xref = int(df[1][1:-1].replace(\"0 R\", \"\"))\n        widths = doc.xref_get_key(df_xref, \"W\")\n        if widths[0] != \"array\":  # no widths key found\n            widths = None\n        else:\n            widths = widths[1]\n        dwidths = doc.xref_get_key(df_xref, \"DW\")\n        if dwidths[0] != \"int\":\n            dwidths = None\n        else:\n            dwidths = dwidths[1]\n        return widths, dwidths\n\n    def set_old_widths(xref, widths, dwidths):\n        \"\"\"Restore the old '/W' and '/DW' in subsetted font.\n\n        If either parameter is None or evaluates to False, the corresponding\n        dictionary key will be set to null.\n        \"\"\"\n        df = doc.xref_get_key(xref, \"DescendantFonts\")\n        if df[0] != \"array\":  # only handle xref specs\n            return None\n        df_xref = int(df[1][1:-1].replace(\"0 R\", \"\"))\n        if (type(widths) is not str or not widths) and doc.xref_get_key(df_xref, \"W\")[\n            0\n        ] != \"null\":\n            doc.xref_set_key(df_xref, \"W\", \"null\")\n        else:\n            doc.xref_set_key(df_xref, \"W\", widths)\n        if (type(dwidths) is not str or not dwidths) and doc.xref_get_key(\n            df_xref, \"DW\"\n        )[0] != \"null\":\n            doc.xref_set_key(df_xref, \"DW\", \"null\")\n        else:\n            doc.xref_set_key(df_xref, \"DW\", dwidths)\n        return None\n\n    def set_subset_fontname(new_xref):\n        \"\"\"Generate a name prefix to tag a font as subset.\n\n        We use a random generator to select 6 upper case ASCII characters.\n        The prefixed name must be put in the font xref as the \"/BaseFont\" value\n        and in the FontDescriptor object as the '/FontName' value.\n        \"\"\"\n        # The following generates a prefix like 'ABCDEF+'\n        prefix = \"\".join(random.choices(tuple(string.ascii_uppercase), k=6)) + \"+\"\n        font_str = doc.xref_object(new_xref, compressed=True)\n        font_str = font_str.replace(\"/BaseFont/\", \"/BaseFont/\" + prefix)\n        df = doc.xref_get_key(new_xref, \"DescendantFonts\")\n        if df[0] == \"array\":\n            df_xref = int(df[1][1:-1].replace(\"0 R\", \"\"))\n            fd = doc.xref_get_key(df_xref, \"FontDescriptor\")\n            if fd[0] == \"xref\":\n                fd_xref = int(fd[1].replace(\"0 R\", \"\"))\n                fd_str = doc.xref_object(fd_xref, compressed=True)\n                fd_str = fd_str.replace(\"/FontName/\", \"/FontName/\" + prefix)\n                doc.update_object(fd_xref, fd_str)\n        doc.update_object(new_xref, font_str)\n        return None\n\n    def build_subset(buffer, unc_set, gid_set):\n        \"\"\"Build font subset using fontTools.\n\n        Args:\n            buffer: (bytes) the font given as a binary buffer.\n            unc_set: (set) required glyph ids.\n        Returns:\n            Either None if subsetting is unsuccessful or the subset font buffer.\n        \"\"\"\n        try:\n            import fontTools.subset as fts\n        except ImportError:\n            print(\"This method requires fontTools to be installed.\")\n            raise\n        tmp_dir = tempfile.gettempdir()\n        oldfont_path = f\"{tmp_dir}/oldfont.ttf\"\n        newfont_path = f\"{tmp_dir}/newfont.ttf\"\n        uncfile_path = f\"{tmp_dir}/uncfile.txt\"\n        args = [\n            oldfont_path,\n            \"--retain-gids\",\n            f\"--output-file={newfont_path}\",\n            \"--layout-features='*'\",\n            \"--passthrough-tables\",\n            \"--ignore-missing-glyphs\",\n            \"--ignore-missing-unicodes\",\n            \"--symbol-cmap\",\n        ]\n\n        unc_file = open(\n            f\"{tmp_dir}/uncfile.txt\", \"w\"\n        )  # store glyph ids or unicodes as file\n        if 0xFFFD in unc_set:  # error unicode exists -> use glyphs\n            args.append(f\"--gids-file={uncfile_path}\")\n            gid_set.add(189)\n            unc_list = list(gid_set)\n            for unc in unc_list:\n                unc_file.write(\"%i\\n\" % unc)\n        else:\n            args.append(f\"--unicodes-file={uncfile_path}\")\n            unc_set.add(255)\n            unc_list = list(unc_set)\n            for unc in unc_list:\n                unc_file.write(\"%04x\\n\" % unc)\n\n        unc_file.close()\n        fontfile = open(oldfont_path, \"wb\")  # store fontbuffer as a file\n        fontfile.write(buffer)\n        fontfile.close()\n        try:\n            os.remove(newfont_path)  # remove old file\n        except:\n            pass\n        try:  # invoke fontTools subsetter\n            fts.main(args)\n            font = Font(fontfile=newfont_path)\n            new_buffer = font.buffer\n            if len(font.valid_codepoints()) == 0:\n                new_buffer = None\n        except:\n            new_buffer = None\n        try:\n            os.remove(uncfile_path)\n        except:\n            pass\n        try:\n            os.remove(oldfont_path)\n        except:\n            pass\n        try:\n            os.remove(newfont_path)\n        except:\n            pass\n        return new_buffer\n\n    def repl_fontnames(doc):\n        \"\"\"Populate 'font_buffers'.\n\n        For each font candidate, store its xref and the list of names\n        by which PDF text may refer to it (there may be multiple).\n        \"\"\"\n\n        def norm_name(name):\n            \"\"\"Recreate font name that contains PDF hex codes.\n\n            E.g. #20 -> space, chr(32)\n            \"\"\"\n            while \"#\" in name:\n                p = name.find(\"#\")\n                c = int(name[p + 1 : p + 3], 16)\n                name = name.replace(name[p : p + 3], chr(c))\n            return name\n\n        def get_fontnames(doc, item):\n            \"\"\"Return a list of fontnames for an item of page.get_fonts().\n\n            There may be multiple names e.g. for Type0 fonts.\n            \"\"\"\n            fontname = item[3]\n            names = [fontname]\n            fontname = doc.xref_get_key(item[0], \"BaseFont\")[1][1:]\n            fontname = norm_name(fontname)\n            if fontname not in names:\n                names.append(fontname)\n            descendents = doc.xref_get_key(item[0], \"DescendantFonts\")\n            if descendents[0] != \"array\":\n                return names\n            descendents = descendents[1][1:-1]\n            if descendents.endswith(\" 0 R\"):\n                xref = int(descendents[:-4])\n                descendents = doc.xref_object(xref, compressed=True)\n            p1 = descendents.find(\"/BaseFont\")\n            if p1 >= 0:\n                p2 = descendents.find(\"/\", p1 + 1)\n                p1 = min(descendents.find(\"/\", p2 + 1), descendents.find(\">>\", p2 + 1))\n                fontname = descendents[p2 + 1 : p1]\n                fontname = norm_name(fontname)\n                if fontname not in names:\n                    names.append(fontname)\n            return names\n\n        for i in range(doc.page_count):\n            for f in doc.get_page_fonts(i, full=True):\n                font_xref = f[0]  # font xref\n                font_ext = f[1]  # font file extension\n                basename = f[3]  # font basename\n\n                if font_ext not in (  # skip if not supported by fontTools\n                    \"otf\",\n                    \"ttf\",\n                    \"woff\",\n                    \"woff2\",\n                ):\n                    continue\n                # skip fonts which already are subsets\n                if len(basename) > 6 and basename[6] == \"+\":\n                    continue\n\n                extr = doc.extract_font(font_xref)\n                fontbuffer = extr[-1]\n                names = get_fontnames(doc, f)\n                name_set, xref_set, subsets = font_buffers.get(\n                    fontbuffer, (set(), set(), (set(), set()))\n                )\n                xref_set.add(font_xref)\n                for name in names:\n                    name_set.add(name)\n                font = Font(fontbuffer=fontbuffer)\n                name_set.add(font.name)\n                del font\n                font_buffers[fontbuffer] = (name_set, xref_set, subsets)\n        return None\n\n    def find_buffer_by_name(name):\n        for buffer in font_buffers.keys():\n            name_set, _, _ = font_buffers[buffer]\n            if name in name_set:\n                return buffer\n        return None\n\n    # -----------------\n    # main function\n    # -----------------\n    repl_fontnames(doc)  # populate font information\n    if not font_buffers:  # nothing found to do\n        if verbose:\n            print(\"No fonts to subset.\")\n        return 0\n\n    old_fontsize = 0\n    new_fontsize = 0\n    for fontbuffer in font_buffers.keys():\n        old_fontsize += len(fontbuffer)\n\n    # Scan page text for usage of subsettable fonts\n    for page in doc:\n        # go through the text and extend set of used glyphs by font\n        # we use a modified MuPDF trace device, which delivers us glyph ids.\n        for span in page.get_texttrace():\n            if type(span) is not dict:  # skip useless information\n                continue\n            fontname = span[\"font\"][:33]  # fontname for the span\n            buffer = find_buffer_by_name(fontname)\n            if buffer is None:\n                continue\n            name_set, xref_set, (set_ucs, set_gid) = font_buffers[buffer]\n            for c in span[\"chars\"]:\n                set_ucs.add(c[0])  # unicode\n                set_gid.add(c[1])  # glyph id\n            font_buffers[buffer] = (name_set, xref_set, (set_ucs, set_gid))\n\n    # build the font subsets\n    for old_buffer in font_buffers.keys():\n        name_set, xref_set, subsets = font_buffers[old_buffer]\n        new_buffer = build_subset(old_buffer, subsets[0], subsets[1])\n        fontname = list(name_set)[0]\n        if new_buffer == None or len(new_buffer) >= len(old_buffer):\n            # subset was not created or did not get smaller\n            if verbose:\n                print(f\"Cannot subset '{fontname}'.\")\n            continue\n        if verbose:\n            print(f\"Built subset of font '{fontname}'.\")\n        val = doc._insert_font(fontbuffer=new_buffer)  # store subset font in PDF\n        new_xref = val[0]  # get its xref\n        set_subset_fontname(new_xref)  # tag fontname as subset font\n        font_str = doc.xref_object(  # get its object definition\n            new_xref,\n            compressed=True,\n        )\n        # walk through the original font xrefs and replace each by the subset def\n        for font_xref in xref_set:\n            # we need the original '/W' and '/DW' width values\n            width_table, def_width = get_old_widths(font_xref)\n            # ... and replace original font definition at xref with it\n            doc.update_object(font_xref, font_str)\n            # now copy over old '/W' and '/DW' values\n            if width_table or def_width:\n                set_old_widths(font_xref, width_table, def_width)\n        # 'new_xref' remains unused in the PDF and must be removed\n        # by garbage collection.\n        new_fontsize += len(new_buffer)\n\n    return old_fontsize - new_fontsize\n\n\n# -------------------------------------------------------------------\n# Copy XREF object to another XREF\n# -------------------------------------------------------------------\ndef xref_copy(doc: Document, source: int, target: int, *, keep: list = None) -> None:\n    \"\"\"Copy a PDF dictionary object to another one given their xref numbers.\n\n    Args:\n        doc: PDF document object\n        source: source xref number\n        target: target xref number, the xref must already exist\n        keep: an optional list of 1st level keys in target that should not be\n              removed before copying.\n    Notes:\n        This works similar to the copy() method of dictionaries in Python. The\n        source may be a stream object.\n    \"\"\"\n    if doc.xref_is_stream(source):\n        # read new xref stream, maintaining compression\n        stream = doc.xref_stream_raw(source)\n        doc.update_stream(\n            target,\n            stream,\n            compress=False,  # keeps source compression\n            new=True,  # in case target is no stream\n        )\n\n    # empty the target completely, observe exceptions\n    if keep is None:\n        keep = []\n    for key in doc.xref_get_keys(target):\n        if key in keep:\n            continue\n        doc.xref_set_key(target, key, \"null\")\n    # copy over all source dict items\n    for key in doc.xref_get_keys(source):\n        item = doc.xref_get_key(source, key)\n        doc.xref_set_key(target, key, item[1])\n    return None\n"
  },
  {
    "path": "src_classic/version.i",
    "content": "%pythoncode %{\nVersionFitz = \"1.24.1\" # MuPDF version.\nVersionBind = \"1.24.1\" # PyMuPDF version.\nVersionDate = \"2024-04-02 00:00:01\"\nversion = (VersionBind, VersionFitz, \"20240402000001\")\npymupdf_version_tuple = tuple( [int(i) for i in VersionFitz.split('.')])\n%}\n"
  },
  {
    "path": "tests/README.md",
    "content": "# PyMuPDF tests\n\nTo run these tests:\n\n* Create and enter a venv.\n* Install PyMuPDF.\n* Install the Python packages listed in\n  `PyMuPDF/scripts/gh_release.py:test_packages`.\n* Run pytest on the PyMuPDF directory.\n\nFor example, as of 2023-12-11:\n\n```\n> python -m pip install pytest fontTools psutil pymupdf-fonts pillow\n> pytest PyMuPDF\n============================= test session starts ==============================\nplatform linux -- Python 3.11.2, pytest-7.4.3, pluggy-1.3.0\nrootdir: /home/jules/artifex-remote/PyMuPDF\nconfigfile: pytest.ini\ncollected 171 items\n\nPyMuPDF/tests/test_2548.py .                                             [  0%]\nPyMuPDF/tests/test_2634.py .                                             [  1%]\nPyMuPDF/tests/test_2736.py .                                             [  1%]\nPyMuPDF/tests/test_2791.py .                                             [  2%]\nPyMuPDF/tests/test_2861.py .                                             [  2%]\nPyMuPDF/tests/test_annots.py ..................                          [ 13%]\nPyMuPDF/tests/test_badfonts.py .                                         [ 14%]\nPyMuPDF/tests/test_crypting.py .                                         [ 14%]\nPyMuPDF/tests/test_docs_samples.py .............                         [ 22%]\nPyMuPDF/tests/test_drawings.py ......                                    [ 25%]\nPyMuPDF/tests/test_embeddedfiles.py .                                    [ 26%]\nPyMuPDF/tests/test_extractimage.py ..                                    [ 27%]\nPyMuPDF/tests/test_flake8.py .                                           [ 28%]\nPyMuPDF/tests/test_font.py .....                                         [ 30%]\nPyMuPDF/tests/test_general.py .......................................... [ 55%]\n...                                                                      [ 57%]\nPyMuPDF/tests/test_geometry.py ........                                  [ 61%]\nPyMuPDF/tests/test_imagebbox.py ..                                       [ 63%]\nPyMuPDF/tests/test_insertimage.py ..                                     [ 64%]\nPyMuPDF/tests/test_insertpdf.py ..                                       [ 65%]\nPyMuPDF/tests/test_linequad.py .                                         [ 66%]\nPyMuPDF/tests/test_metadata.py ..                                        [ 67%]\nPyMuPDF/tests/test_nonpdf.py ...                                         [ 69%]\nPyMuPDF/tests/test_object_manipulation.py ....                           [ 71%]\nPyMuPDF/tests/test_optional_content.py ..                                [ 72%]\nPyMuPDF/tests/test_pagedelete.py .                                       [ 73%]\nPyMuPDF/tests/test_pagelabels.py .                                       [ 73%]\nPyMuPDF/tests/test_pixmap.py ..........                                  [ 79%]\nPyMuPDF/tests/test_showpdfpage.py .                                      [ 80%]\nPyMuPDF/tests/test_story.py ...                                          [ 81%]\nPyMuPDF/tests/test_tables.py ...                                         [ 83%]\nPyMuPDF/tests/test_tesseract.py .                                        [ 84%]\nPyMuPDF/tests/test_textbox.py ......                                     [ 87%]\nPyMuPDF/tests/test_textextract.py ..                                     [ 88%]\nPyMuPDF/tests/test_textsearch.py ..                                      [ 90%]\nPyMuPDF/tests/test_toc.py ........                                       [ 94%]\nPyMuPDF/tests/test_widgets.py ........                                   [ 99%]\nPyMuPDF/tests/test_word_delimiters.py .                                  [100%]\n\n======================== 171 passed in 78.65s (0:01:18) ========================\n> \n```\n\n## Known test failure with non-default build of MuPDF\n\nIf PyMuPDF has been built with a non-default build of MuPDF (using\nenvironmental variable ``PYMUPDF_SETUP_MUPDF_BUILD``), it is possible that\n``tests/test_textbox.py:test_textbox3()`` will fail, because it relies on MuPDF\nhaving been built with PyMuPDF's customized configuration, ``fitz/_config.h``.\n\nOne can skip this particular test by adding ``-k 'not test_textbox3'`` to the\npytest command line.\n\n\n## Resuming at a particular test.\n\nTo skip tests before a particular test, set PYMUPDF_PYTEST_RESUME to the name\nof the function.\n\nFor example PYMUPDF_PYTEST_RESUME=test_haslinks.\n\n\n## Checks on all tests\n\nAll tests are wrapped by tests/conftest.py:wrap(), which does additional checking.\n\n* Checks that pymupdf.TOOLS.mupdf_warnings() is empty.\n* Checks tests do not modify globals such as small_glyph_heights.\n"
  },
  {
    "path": "tests/conftest.py",
    "content": "import copy\nimport os\nimport platform\nimport subprocess\nimport sys\n\nimport pytest\n\n# Install required packages. There doesn't seem to be any official way for\n# us to programmatically specify required test packages in setup.py, or in\n# pytest. Doing it here seems to be the least ugly approach.\n#\n# However our diagnostics do not show up so this can cause an unfortunate pause\n# before tests start to run.\n#\ndef install_required_packages():\n    PYODIDE_ROOT = os.environ.get('PYODIDE_ROOT')\n    if PYODIDE_ROOT:\n        # We can't run child processes, so rely on required test packages\n        # already being installed, e.g. in our wheel's <requires_dist>.\n        return\n    packages = 'pytest fontTools pymupdf-fonts flake8 pylint codespell mypy'\n    packages += ' pipcl'\n    if platform.system() == 'Windows' and int.bit_length(sys.maxsize+1) == 32:\n        # No pillow wheel available, and doesn't build easily.\n        pass\n    elif platform.python_implementation() == 'GraalVM':\n        pass\n    else:\n        packages += ' pillow'\n    if platform.system().startswith('MSYS_NT-'):\n        # psutil not available on msys2.\n        pass\n    else:\n        packages += ' psutil'\n    command = f'pip install --upgrade {packages}'\n    print(f'{__file__}:install_required_packages)(): Running: {command}', flush=1)\n    subprocess.run(command, shell=1, check=1)\n\ninstall_required_packages()\n\n\n@pytest.fixture(scope=\"session\", autouse=True)\ndef log_global_env_facts(record_testsuite_property):\n    record_testsuite_property('platform.python_version()', platform.python_version())\n\n# Need to import pymupdf only after we've installed pymupdf-fonts above,\n# because pymupdf imports pymupdf_fonts, and copes with import failure.\nimport pymupdf\n\n\nPYMUPDF_PYTEST_RESUME = os.environ.get('PYMUPDF_PYTEST_RESUME')\n\n@pytest.fixture(autouse=True)\ndef wrap(request):\n    '''\n    Check that tests return with empty MuPDF warnings buffer. For example this\n    detects failure to call fz_close_output() before fz_drop_output(), which\n    (as of 2024-4-12) generates a warning from MuPDF.\n    \n    As of 2024-09-12 we also detect whether tests leave fds open; but for now\n    do not fail tests, because many tests need fixing.\n    '''\n    global PYMUPDF_PYTEST_RESUME\n    if PYMUPDF_PYTEST_RESUME:\n        # Skip all tests until we reach a matching name.\n        if PYMUPDF_PYTEST_RESUME == request.function.__name__:\n            print(f'### {PYMUPDF_PYTEST_RESUME=}: resuming at {request.function.__name__=}.')\n            PYMUPDF_PYTEST_RESUME = None\n        else:\n            print(f'### {PYMUPDF_PYTEST_RESUME=}: Skipping {request.function.__name__=}.')\n            return\n    \n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert not wt, f'{wt=}'\n    if platform.python_implementation() == 'GraalVM':\n        pymupdf.TOOLS.set_small_glyph_heights()\n    else:\n        assert not pymupdf.TOOLS.set_small_glyph_heights()\n    next_fd_before = os.open(__file__, os.O_RDONLY)\n    os.close(next_fd_before)\n    \n    if platform.system() == 'Linux' and platform.python_implementation() != 'GraalVM':\n        test_fds = True\n    else:\n        test_fds = False\n        \n    if test_fds:\n        # Gather detailed information about leaked fds.\n        def get_fds():\n            import subprocess\n            path = 'PyMuPDF-linx-fds'\n            path_l = 'PyMuPDF-linx-fds-l'\n            command = f'ls /proc/{os.getpid()}/fd > {path}'\n            command_l = f'ls -l /proc/{os.getpid()}/fd > {path_l}'\n            subprocess.run(command, shell=1)\n            subprocess.run(command_l, shell=1)\n            with open(path) as f:\n                ret = f.read()\n                ret = ret.replace('\\n', ' ')\n            with open(path_l) as f:\n                ret_l = f.read()\n            return ret, ret_l\n        open_fds_before, open_fds_before_l = get_fds()\n    \n    pymupdf._log_items_clear()\n    pymupdf._log_items_active(True)\n    \n    JM_annot_id_stem = pymupdf.JM_annot_id_stem\n    \n    def get_members(a):\n        ret = dict()\n        for n in dir(a):\n            if not n.startswith('_'):\n                v = getattr(a, n)\n                ret[n] = v\n        return ret\n        \n    # Allow post-test checking that pymupdf._globals has not changed.\n    _globals_pre = get_members(pymupdf._globals)\n    \n    testsfailed_before = request.session.testsfailed\n    \n    # Run the test.\n    rep = yield\n    \n    sys.stdout.flush()\n    \n    # This seems the only way for us to tell that a test has failed. In\n    # particular, <rep> is always None. We're implicitly relying on tests not\n    # being run in parallel.\n    #\n    failed = request.session.testsfailed - testsfailed_before\n    assert failed in (0, 1)\n    \n    if failed:\n        # Do not check post-test conditions if the test as failed. This avoids\n        # additional confusing `ERROR` status for failed tests.\n        return\n    \n    # Test has run; check it did not create any MuPDF warnings etc.\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if not hasattr(pymupdf, 'mupdf'):\n        print(f'Not checking mupdf_warnings on classic.')\n    else:\n        assert not wt, f'Warnings text not empty: {wt=}'\n    \n    assert not pymupdf.TOOLS.set_small_glyph_heights()\n    \n    _globals_post = get_members(pymupdf._globals)\n    if _globals_post != _globals_pre:\n        print(f'Test has changed pymupdf._globals from {_globals_pre=} to {_globals_post=}')\n        assert 0\n    \n    log_items = pymupdf._log_items()\n    assert not log_items, f'log() was called; {len(log_items)=}.'\n    \n    assert pymupdf.JM_annot_id_stem == JM_annot_id_stem, \\\n            f'pymupdf.JM_annot_id_stem has changed from {JM_annot_id_stem!r} to {pymupdf.JM_annot_id_stem!r}'\n    \n    if test_fds:\n        # Show detailed information about leaked fds.\n        open_fds_after, open_fds_after_l = get_fds()\n        if open_fds_after != open_fds_before:\n            import textwrap\n            print(f'Test has changed process fds:')\n            print(f'    {open_fds_before=}')\n            print(f'     {open_fds_after=}')\n            print(f'open_fds_before_l:')\n            print(textwrap.indent(open_fds_before_l, '    '))\n            print(f'open_fds_after_l:')\n            print(textwrap.indent(open_fds_after_l, '    '))\n            #assert 0\n    \n    next_fd_after = os.open(__file__, os.O_RDONLY)\n    os.close(next_fd_after)\n    \n    if test_fds and next_fd_after != next_fd_before:\n        print(f'Test has leaked fds, {next_fd_before=} {next_fd_after=}.')\n        #assert 0, f'Test has leaked fds, {next_fd_before=} {next_fd_after=}. {args=} {kwargs=}.'\n    \n    if 0:\n        # This code can be useful to track down test failures caused by other\n        # tests modifying global state.\n        #\n        # We run a particular test menually after each test returns.\n        sys.path.insert(0, os.path.dirname(__file__))\n        try:\n            import test_tables\n        finally:\n            del sys.path[0]\n        print(f'### Calling test_tables.test_md_styles().')\n        try:\n            test_tables.test_md_styles()\n        except Exception as e:\n            print(f'### test_tables.test_md_styles() failed: {e}')\n            raise\n        else:\n            print(f'### test_tables.test_md_styles() passed.')\n"
  },
  {
    "path": "tests/gentle_compare.py",
    "content": "import math\n\nimport pymupdf\n\n\ndef gentle_compare(w0, w1):\n    \"\"\"Check lists of \"words\" extractions for approximate equality.\n\n    * both lists must have same length\n    * word items must contain same word strings\n    * word rectangles must be approximately equal\n    \"\"\"\n    tolerance = 1e-3  # maximum (Euclidean) norm of difference rectangle\n    word_count = len(w0)  # number of words\n    if word_count != len(w1):\n        print(f\"different number of words: {word_count}/{len(w1)}\")\n        return False\n    for i in range(word_count):\n        if w0[i][4] != w1[i][4]:  # word strings must be the same\n            print(f\"word {i} mismatch\")\n            return False\n        r0 = pymupdf.Rect(w0[i][:4])  # rect of first word\n        r1 = pymupdf.Rect(w1[i][:4])  # rect of second word\n        delta = (r1 - r0).norm()  # norm of difference rectangle\n        if delta > tolerance:\n            print(f\"word {i}: rectangle mismatch {delta}\")\n            return False\n    return True\n\n\ndef rms(a, b, verbose=None, out_prefix=''):\n    '''\n    Returns RMS diff of raw bytes of two sequences.\n    '''\n    assert len(a) == len(b)\n    e = 0\n    for i, (aa, bb) in enumerate(zip(a, b)):\n        if verbose and (i % verbose == 0):\n            print(f'{out_prefix}rms(): {i=} {e=} {aa=} {aa=}.')\n        e += (aa - bb) ** 2\n    rms = math.sqrt(e / len(a))\n    return rms\n\n\ndef pixmaps_rms(a, b, out_prefix=''):\n    '''\n    Returns RMS diff of raw bytes of two pixmaps.\n\n    We assert that the pixmaps/sequences are the same size.\n\n    <a> and <b> can each be a pymupdf.Pixmap or path of a bitmap file.\n    '''\n    if isinstance(a, str):\n        print(f'{out_prefix}pixmaps_rms(): reading pixmap from {a=}.')\n        a = pymupdf.Pixmap(a)\n    if isinstance(b, str):\n        print(f'{out_prefix}pixmaps_rms(): reading pixmap from {b=}.')\n        b = pymupdf.Pixmap(b)\n    assert a.irect == b.irect, f'Differing rects: {a.irect=} {b.irect=}.'\n    a_mv = a.samples_mv\n    b_mv = b.samples_mv\n    assert len(a_mv) == len(b_mv)\n    ret = rms(a_mv, b_mv, out_prefix=out_prefix)\n    print(f'{out_prefix}pixmaps_rms(): {ret=}.')\n    return ret\n\n\ndef pixmaps_diff(a, b, out_prefix=''):\n    '''\n    Returns a pymupdf.Pixmap that represents the difference between pixmaps <a>\n    and <b>.\n    \n    Each byte in the returned pixmap is `128 + (b_byte - a_byte) // 2`.\n    '''\n    if isinstance(a, str):\n        print(f'{out_prefix}pixmaps_rms(): reading pixmap from {a=}.')\n        a = pymupdf.Pixmap(a)\n    if isinstance(b, str):\n        print(f'{out_prefix}pixmaps_rms(): reading pixmap from {b=}.')\n        b = pymupdf.Pixmap(b)\n    assert a.irect == b.irect, f'Differing rects: {a.irect=} {b.irect=}.'\n    a_mv = a.samples_mv\n    b_mv = b.samples_mv\n    c = pymupdf.Pixmap(a.tobytes())\n    c_mv = c.samples_mv\n    assert len(a_mv) == len(b_mv) == len(c_mv)\n    if 1:\n        print(f'{len(a_mv)=}')\n        for i, (a_byte, b_byte, c_byte) in enumerate(zip(a_mv, b_mv, c_mv)):\n            assert 0 <= a_byte < 256\n            assert 0 <= b_byte < 256\n            assert 0 <= c_byte < 256\n            # Set byte to 128 plus half the diff so we represent the full\n            # -255..+255 range.\n            c_mv[i] = 128 + (b_byte - a_byte) // 2\n    return c    \n"
  },
  {
    "path": "tests/resources/full_toc.txt",
    "content": "[1, 'HAUPTÜBERSICHT', -1, {'kind': 5, 'xref': 2, 'file': '../SDW2006.PDF', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[1, 'Januar 01/2006', -1, {'kind': 5, 'xref': 3, 'file': '01004INH.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0, 'collapse': False}]\n[2, 'SPEKTROGRAMM', -1, {'kind': 0, 'xref': 4, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Urzeit-Godzilla', -1, {'kind': 5, 'xref': 87, 'file': '01008SP.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Frühchristliche Mosaike im Knast', -1, {'kind': 5, 'xref': 102, 'file': '01008SP.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Evolution auf Eis', -1, {'kind': 5, 'xref': 100, 'file': '01008SP.pdf', 'page': 1, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Entwarnung bei Kondensstreifen', -1, {'kind': 5, 'xref': 98, 'file': '01008SP.pdf', 'page': 1, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Spermatausch beim Schnecken-Sex', -1, {'kind': 5, 'xref': 96, 'file': '01008SP.pdf', 'page': 1, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Mehr Monde für Pluto', -1, {'kind': 5, 'xref': 94, 'file': '01008SP.pdf', 'page': 2, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Endlich ein Malaria-Impfstoff', -1, {'kind': 5, 'xref': 92, 'file': '01008SP.pdf', 'page': 2, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Spuren der ersten Sterne', -1, {'kind': 5, 'xref': 90, 'file': '01008SP.pdf', 'page': 2, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Bild des Monats', -1, {'kind': 5, 'xref': 88, 'file': '01008SP.pdf', 'page': 3, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'FORSCHUNG AKTUELL', -1, {'kind': 0, 'xref': 23, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Der Super-Teilchenfänger in der Pampa', -1, {'kind': 5, 'xref': 24, 'file': '01012FA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Auf der Fährte der Lepra', -1, {'kind': 5, 'xref': 29, 'file': '01012FA.pdf', 'page': 2, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Vampire gegen Schlaganfall', -1, {'kind': 5, 'xref': 27, 'file': '01012FA.pdf', 'page': 4, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Der Flug des Kolibris', -1, {'kind': 5, 'xref': 25, 'file': '01012FA.pdf', 'page': 7, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'THEMEN', -1, {'kind': 0, 'xref': 20, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Entwicklung von Spiralgalaxien', -1, {'kind': 5, 'xref': 21, 'file': '01022HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Geschichtsträchtige Genspuren', -1, {'kind': 5, 'xref': 46, 'file': '01030HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Was Sedimente verraten', -1, {'kind': 5, 'xref': 44, 'file': '01042HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Von Baumringen und Regenmengen', -1, {'kind': 5, 'xref': 42, 'file': '01050HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Software-Agenten in Not', -1, {'kind': 5, 'xref': 40, 'file': '01056HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Künstlicher kalter Antiwasserstoff', -1, {'kind': 5, 'xref': 38, 'file': '01062HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Rüsten gegen eine Pandemie', -1, {'kind': 5, 'xref': 36, 'file': '01072HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Satelliten zeigen Lawinengefahr', -1, {'kind': 5, 'xref': 34, 'file': '01084HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Provokante Verheißung: Update für den Menschen', -1, {'kind': 5, 'xref': 22, 'file': '01100HA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'KOMMENTAR', -1, {'kind': 0, 'xref': 18, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Springers Einwüfe: Holland, die Hydrometropole', -1, {'kind': 5, 'xref': 19, 'file': '01012FA.pdf', 'page': 8, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'WISSENSCHAFT IM ...', -1, {'kind': 0, 'xref': 15, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Alltag: Eine Decke für die Straße', -1, {'kind': 5, 'xref': 16, 'file': '01040WA.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Rückblick: Mozarts Ohr • Per Auto zum Südpol u.a.', -1, {'kind': 5, 'xref': 17, 'file': '01081IR.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'JUNGE WISSENSCHAFT', -1, {'kind': 0, 'xref': 13, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Ein Putzroboter für die Mama', -1, {'kind': 5, 'xref': 14, 'file': '01082JW.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'REZENSIONEN', -1, {'kind': 0, 'xref': 10, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Vulkanismus verstehen und erleben', -1, {'kind': 5, 'xref': 11, 'file': '01090RE.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Warum der Mensch glaubt', -1, {'kind': 5, 'xref': 72, 'file': '01090RE.pdf', 'page': 1, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Biomedizin und Ethik', -1, {'kind': 5, 'xref': 70, 'file': '01090RE.pdf', 'page': 2, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Mythos Meer', -1, {'kind': 5, 'xref': 68, 'file': '01090RE.pdf', 'page': 3, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Warum Frauen nicht schwach ... sind', -1, {'kind': 5, 'xref': 66, 'file': '01090RE.pdf', 'page': 4, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'PISA, Bach, Pythagoras', -1, {'kind': 5, 'xref': 12, 'file': '01090RE.pdf', 'page': 5, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'MATHEMATISCHE UNTERHALTUNGEN', -1, {'kind': 0, 'xref': 8, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Himmliches Ballett', -1, {'kind': 5, 'xref': 9, 'file': '01098MU.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[2, 'WEITERE RUBRIKEN', -1, {'kind': 0, 'xref': 5, 'page': -1, 'collapse': False, 'zoom': 0.0}]\n[3, 'Editorial', -1, {'kind': 5, 'xref': 6, 'file': '01003ED.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Leserbriefe/Impressum', -1, {'kind': 5, 'xref': 81, 'file': '01006LB.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Preisrätsel', -1, {'kind': 5, 'xref': 79, 'file': '01090RE.pdf', 'page': 6, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n[3, 'Vorschau', -1, {'kind': 5, 'xref': 7, 'file': '01106VO.pdf', 'page': 0, 'to': Point(0.0, 0.0), 'zoom': 0.0}]\n"
  },
  {
    "path": "tests/resources/metadata.txt",
    "content": "{\"format\": \"PDF 1.6\", \"title\": \"RUBRIK_Editorial_01-06.indd\", \"author\": \"Natalie Schaefer\", \"subject\": \"\", \"keywords\": \"\", \"creator\": \"\", \"producer\": \"Acrobat Distiller 7.0.5 (Windows)\", \"creationDate\": \"D:20070113191400+01'00'\", \"modDate\": \"D:20070120104154+01'00'\", \"trapped\": \"\", \"encryption\": null}"
  },
  {
    "path": "tests/resources/simple_toc.txt",
    "content": "[1, 'HAUPTÜBERSICHT', -1][1, 'Januar 01/2006', -1][2, 'SPEKTROGRAMM', -1][3, 'Urzeit-Godzilla', -1][3, 'Frühchristliche Mosaike im Knast', -1][3, 'Evolution auf Eis', -1][3, 'Entwarnung bei Kondensstreifen', -1][3, 'Spermatausch beim Schnecken-Sex', -1][3, 'Mehr Monde für Pluto', -1][3, 'Endlich ein Malaria-Impfstoff', -1][3, 'Spuren der ersten Sterne', -1][3, 'Bild des Monats', -1][2, 'FORSCHUNG AKTUELL', -1][3, 'Der Super-Teilchenfänger in der Pampa', -1][3, 'Auf der Fährte der Lepra', -1][3, 'Vampire gegen Schlaganfall', -1][3, 'Der Flug des Kolibris', -1][2, 'THEMEN', -1][3, 'Entwicklung von Spiralgalaxien', -1][3, 'Geschichtsträchtige Genspuren', -1][3, 'Was Sedimente verraten', -1][3, 'Von Baumringen und Regenmengen', -1][3, 'Software-Agenten in Not', -1][3, 'Künstlicher kalter Antiwasserstoff', -1][3, 'Rüsten gegen eine Pandemie', -1][3, 'Satelliten zeigen Lawinengefahr', -1][3, 'Provokante Verheißung: Update für den Menschen', -1][2, 'KOMMENTAR', -1][3, 'Springers Einwüfe: Holland, die Hydrometropole', -1][2, 'WISSENSCHAFT IM ...', -1][3, 'Alltag: Eine Decke für die Straße', -1][3, 'Rückblick: Mozarts Ohr • Per Auto zum Südpol u.a.', -1][2, 'JUNGE WISSENSCHAFT', -1][3, 'Ein Putzroboter für die Mama', -1][2, 'REZENSIONEN', -1][3, 'Vulkanismus verstehen und erleben', -1][3, 'Warum der Mensch glaubt', -1][3, 'Biomedizin und Ethik', -1][3, 'Mythos Meer', -1][3, 'Warum Frauen nicht schwach ... sind', -1][3, 'PISA, Bach, Pythagoras', -1][2, 'MATHEMATISCHE UNTERHALTUNGEN', -1][3, 'Himmliches Ballett', -1][2, 'WEITERE RUBRIKEN', -1][3, 'Editorial', -1][3, 'Leserbriefe/Impressum', -1][3, 'Preisrätsel', -1][3, 'Vorschau', -1]"
  },
  {
    "path": "tests/resources/symbols.txt",
    "content": "[{'closePath': False,\n  'color': (1.0, 1.0, 1.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (1.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('l', (50.0, 50.0), (50.0, 100.0)),\n            ('l', (50.0, 100.0), (100.0, 75.0)),\n            ('l', (100.0, 75.0), (50.0, 50.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 50.0, 100.0, 100.0),\n  'seqno': 0,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 1.0},\n {'closePath': False,\n  'color': (1.0, 1.0, 1.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (1.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (50.0, 135.0),\n             (63.807098388671875, 135.0),\n             (75.0, 123.8070068359375),\n             (75.0, 110.0)),\n            ('c',\n             (75.0, 110.0),\n             (75.0, 123.8070068359375),\n             (86.19290161132812, 135.0),\n             (100.0, 135.0)),\n            ('c',\n             (100.0, 135.0),\n             (86.19290161132812, 135.0),\n             (75.0, 146.1929931640625),\n             (75.0, 160.0)),\n            ('c',\n             (75.0, 160.0),\n             (75.0, 146.1929931640625),\n             (63.807098388671875, 135.0),\n             (50.0, 135.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 110.0, 100.0, 160.0),\n  'seqno': 2,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 1.0},\n {'closePath': False,\n  'color': (0.0, 1.0, 0.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (0.0, 1.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c', (75.0, 195.0), (50.0, 170.0), (100.0, 170.0), (75.0, 195.0)),\n            ('c', (75.0, 195.0), (100.0, 170.0), (100.0, 220.0), (75.0, 195.0)),\n            ('c', (75.0, 195.0), (50.0, 220.0), (50.0, 170.0), (75.0, 195.0)),\n            ('c', (75.0, 195.0), (100.0, 220.0), (50.0, 220.0), (75.0, 195.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 170.0, 100.0, 220.0),\n  'seqno': 4,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 0.30000001192092896},\n {'closePath': False,\n  'color': (1.0, 1.0, 1.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (1.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('l', (75.0, 230.0), (100.0, 255.0)),\n            ('l', (100.0, 255.0), (75.0, 280.0)),\n            ('l', (75.0, 280.0), (50.0, 255.0)),\n            ('l', (50.0, 255.0), (75.0, 230.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 230.0, 100.0, 280.0),\n  'seqno': 6,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 1.0},\n {'closePath': False,\n  'color': (1.0, 1.0, 1.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (0.8039219975471497, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (50.0, 315.0),\n             (50.0, 328.8070068359375),\n             (61.192901611328125, 340.0),\n             (75.0, 340.0)),\n            ('c',\n             (75.0, 340.0),\n             (88.80709838867188, 340.0),\n             (100.0, 328.8070068359375),\n             (100.0, 315.0)),\n            ('c',\n             (100.0, 315.0),\n             (100.0, 301.1929931640625),\n             (88.80709838867188, 290.0),\n             (75.0, 290.0)),\n            ('c',\n             (75.0, 290.0),\n             (61.192901611328125, 290.0),\n             (50.0, 301.1929931640625),\n             (50.0, 315.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 290.0, 100.0, 340.0),\n  'seqno': 8,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 2.0},\n {'closePath': False,\n  'color': (0.0, 0.0, 0.0),\n  'dashes': '[] 0',\n  'items': [('c',\n             (50.0, 315.0),\n             (50.0, 328.8070068359375),\n             (61.192901611328125, 340.0),\n             (75.0, 340.0)),\n            ('c',\n             (75.0, 340.0),\n             (88.80709838867188, 340.0),\n             (100.0, 328.8070068359375),\n             (100.0, 315.0)),\n            ('c',\n             (100.0, 315.0),\n             (100.0, 301.1929931640625),\n             (88.80709838867188, 290.0),\n             (75.0, 290.0)),\n            ('c',\n             (75.0, 290.0),\n             (61.192901611328125, 290.0),\n             (50.0, 301.1929931640625),\n             (50.0, 315.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 290.0, 100.0, 340.0),\n  'seqno': 10,\n  'stroke_opacity': 1.0,\n  'type': 's',\n  'width': 1.0},\n {'closePath': False,\n  'color': (1.0, 1.0, 1.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (1.0, 1.0, 1.0),\n  'fill_opacity': 1.0,\n  'items': [('re', (56.5, 312.5, 93.5, 317.5), 1)],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (56.5, 312.5, 93.5, 317.5),\n  'seqno': 11,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 3.0},\n {'closePath': False,\n  'even_odd': False,\n  'fill': (1.0, 1.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (50.0, 375.0),\n             (50.0, 388.8070068359375),\n             (61.192901611328125, 400.0),\n             (75.0, 400.0)),\n            ('c',\n             (75.0, 400.0),\n             (88.80709838867188, 400.0),\n             (100.0, 388.8070068359375),\n             (100.0, 375.0)),\n            ('c',\n             (100.0, 375.0),\n             (100.0, 361.1929931640625),\n             (88.80709838867188, 350.0),\n             (75.0, 350.0)),\n            ('c',\n             (75.0, 350.0),\n             (61.192901611328125, 350.0),\n             (50.0, 361.1929931640625),\n             (50.0, 375.0))],\n  'layer': '',\n  'rect': (50.0, 350.0, 100.0, 400.0),\n  'seqno': 13,\n  'type': 'f'},\n {'closePath': False,\n  'even_odd': False,\n  'fill': (0.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (60.0, 368.75),\n             (60.0, 372.2019958496094),\n             (62.23860168457031, 375.0),\n             (65.0, 375.0)),\n            ('c',\n             (65.0, 375.0),\n             (67.76139831542969, 375.0),\n             (70.0, 372.2019958496094),\n             (70.0, 368.75)),\n            ('c',\n             (70.0, 368.75),\n             (70.0, 365.2980041503906),\n             (67.76139831542969, 362.5),\n             (65.0, 362.5)),\n            ('c',\n             (65.0, 362.5),\n             (62.23860168457031, 362.5),\n             (60.0, 365.2980041503906),\n             (60.0, 368.75)),\n            ('c',\n             (80.0, 368.75),\n             (80.0, 372.2019958496094),\n             (82.23860168457031, 375.0),\n             (85.0, 375.0)),\n            ('c',\n             (85.0, 375.0),\n             (87.76139831542969, 375.0),\n             (90.0, 372.2019958496094),\n             (90.0, 368.75)),\n            ('c',\n             (90.0, 368.75),\n             (90.0, 365.2980041503906),\n             (87.76139831542969, 362.5),\n             (85.0, 362.5)),\n            ('c',\n             (85.0, 362.5),\n             (82.23860168457031, 362.5),\n             (80.0, 365.2980041503906),\n             (80.0, 368.75))],\n  'layer': '',\n  'rect': (60.0, 362.5, 90.0, 375.0),\n  'seqno': 14,\n  'type': 'f'},\n {'closePath': False,\n  'color': (0.0, 0.0, 0.0),\n  'dashes': '[] 0',\n  'items': [('c',\n             (60.0, 387.5),\n             (68.2843017578125, 380.59600830078125),\n             (81.7156982421875, 380.59600830078125),\n             (90.0, 387.5))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (60.0, 380.59600830078125, 90.0, 387.5),\n  'seqno': 15,\n  'stroke_opacity': 1.0,\n  'type': 's',\n  'width': 1.0},\n {'closePath': False,\n  'color': (1.0, 0.6470590233802795, 0.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (1.0, 0.8274509906768799, 0.6078429818153381),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (50.0, 433.6669921875),\n             (60.30929946899414, 433.6669921875),\n             (68.66670227050781, 426.50299072265625),\n             (68.66670227050781, 417.6669921875)),\n            ('c',\n             (68.66670227050781, 417.6669921875),\n             (74.55770111083984, 416.1940002441406),\n             (74.55770111083984, 423.35699462890625),\n             (68.66670227050781, 433.6669921875)),\n            ('l',\n             (68.66670227050781, 433.6669921875),\n             (95.33329772949219, 433.6669921875)),\n            ('c',\n             (95.33329772949219, 433.6669921875),\n             (100.66699981689453, 433.6669921875),\n             (100.66699981689453, 439.0),\n             (95.33329772949219, 439.0)),\n            ('l', (95.33329772949219, 439.0), (79.33329772949219, 439.0)),\n            ('l', (79.33329772949219, 439.0), (87.33329772949219, 439.0)),\n            ('c',\n             (87.33329772949219, 439.0),\n             (92.66670227050781, 439.0),\n             (92.66670227050781, 444.3330078125),\n             (87.33329772949219, 444.3330078125)),\n            ('l',\n             (87.33329772949219, 444.3330078125),\n             (79.33329772949219, 444.3330078125)),\n            ('l',\n             (79.33329772949219, 444.3330078125),\n             (84.66670227050781, 444.3330078125)),\n            ('c',\n             (84.66670227050781, 444.3330078125),\n             (90.0, 444.3330078125),\n             (90.0, 449.6669921875),\n             (84.66670227050781, 449.6669921875)),\n            ('l',\n             (84.66670227050781, 449.6669921875),\n             (79.33329772949219, 449.6669921875)),\n            ('l',\n             (79.33329772949219, 449.6669921875),\n             (83.33329772949219, 449.6669921875)),\n            ('c',\n             (83.33329772949219, 449.6669921875),\n             (88.66670227050781, 449.6669921875),\n             (88.66670227050781, 455.0),\n             (83.33329772949219, 455.0)),\n            ('l', (83.33329772949219, 455.0), (50.0, 455.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 416.1940002441406, 100.66699981689453, 455.0),\n  'seqno': 16,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 1.0},\n {'closePath': False,\n  'color': (1.0, 0.0, 0.0),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (1.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c', (75.0, 485.0), (62.5, 470.0), (50.0, 490.0), (75.0, 510.0)),\n            ('c', (75.0, 485.0), (87.5, 470.0), (100.0, 490.0), (75.0, 510.0)),\n            ('l', (75.0, 510.0), (75.0, 485.0))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (50.0, 470.0, 100.0, 510.0),\n  'seqno': 18,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 1.0},\n {'closePath': False,\n  'color': (0.9333329796791077, 0.8470590114593506, 0.6823530197143555),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'fill_opacity': 1.0,\n  'items': [('re',\n             (56.52170181274414,\n              547.753173828125,\n              85.5072021484375,\n              562.2459716796875),\n             1)],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (56.52170181274414,\n           547.753173828125,\n           85.5072021484375,\n           562.2459716796875),\n  'seqno': 20,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 0.07246380299329758},\n {'closePath': False,\n  'color': (0.9333329796791077, 0.8470590114593506, 0.6823530197143555),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (0.9333329796791077, 0.8470590114593506, 0.6823530197143555),\n  'fill_opacity': 1.0,\n  'items': [('l',\n             (56.52170181274414, 547.7540283203125),\n             (59.4202995300293, 550.6519775390625)),\n            ('l',\n             (59.4202995300293, 550.6519775390625),\n             (59.4202995300293, 559.3480224609375)),\n            ('l',\n             (59.4202995300293, 559.3480224609375),\n             (56.52170181274414, 562.2459716796875)),\n            ('l',\n             (85.5072021484375, 547.7540283203125),\n             (82.60870361328125, 550.6519775390625)),\n            ('l',\n             (82.60870361328125, 550.6519775390625),\n             (82.60870361328125, 559.3480224609375)),\n            ('l',\n             (82.60870361328125, 559.3480224609375),\n             (85.5072021484375, 562.2459716796875))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (56.52170181274414,\n           547.7540283203125,\n           85.5072021484375,\n           562.2459716796875),\n  'seqno': 22,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 0.07246380299329758},\n {'closePath': False,\n  'color': (0.8039219975471497, 0.7294120192527771, 0.5882350206375122),\n  'dashes': '[] 0',\n  'items': [('l',\n             (59.4202995300293, 550.6519775390625),\n             (82.60870361328125, 550.6519775390625)),\n            ('l',\n             (59.4202995300293, 559.3480224609375),\n             (82.60870361328125, 559.3480224609375))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (59.4202995300293,\n           550.6519775390625,\n           82.60870361328125,\n           559.3480224609375),\n  'seqno': 24,\n  'stroke_opacity': 1.0,\n  'type': 's',\n  'width': 0.07246380299329758},\n {'even_odd': False,\n  'fill': (0.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('re',\n             (56.52170181274414,\n              547.753173828125,\n              63.76808166503906,\n              562.2459716796875),\n             1)],\n  'layer': '',\n  'rect': (56.52170181274414,\n           547.753173828125,\n           63.76808166503906,\n           562.2459716796875),\n  'seqno': 25,\n  'type': 'f'},\n {'even_odd': False,\n  'fill': (1.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (56.52170181274414, 547.7540283203125),\n             (47.82609939575195, 547.7540283203125),\n             (47.82609939575195, 562.2459716796875),\n             (56.52170181274414, 562.2459716796875))],\n  'layer': '',\n  'rect': (47.82609939575195,\n           547.7540283203125,\n           56.52170181274414,\n           562.2459716796875),\n  'seqno': 26,\n  'type': 'f'},\n {'even_odd': False,\n  'fill': (0.9333329796791077, 0.8470590114593506, 0.6823530197143555),\n  'fill_opacity': 1.0,\n  'items': [('l', (85.5072021484375, 547.7540283203125), (100.0, 555.0)),\n            ('l', (100.0, 555.0), (85.5072021484375, 562.2459716796875))],\n  'layer': '',\n  'rect': (85.5072021484375, 547.7540283203125, 100.0, 562.2459716796875),\n  'seqno': 27,\n  'type': 'f'},\n {'closePath': False,\n  'color': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (85.5072021484375, 547.7540283203125),\n             (86.30770111083984, 548.553955078125),\n             (85.00990295410156, 549.8519897460938),\n             (82.60870361328125, 550.6519775390625)),\n            ('l',\n             (82.60870361328125, 550.6519775390625),\n             (85.5072021484375, 547.7540283203125))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (82.60870361328125,\n           547.7540283203125,\n           86.30770111083984,\n           550.6519775390625),\n  'seqno': 28,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 0.07246380299329758},\n {'closePath': False,\n  'color': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (82.60870361328125, 550.6519775390625),\n             (87.2510986328125, 553.052978515625),\n             (87.2510986328125, 556.947021484375),\n             (82.60870361328125, 559.3480224609375)),\n            ('l',\n             (82.60870361328125, 559.3480224609375),\n             (82.60870361328125, 550.6519775390625))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (82.60870361328125,\n           550.6519775390625,\n           87.2510986328125,\n           559.3480224609375),\n  'seqno': 30,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 0.07246380299329758},\n {'closePath': False,\n  'color': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'dashes': '[] 0',\n  'even_odd': False,\n  'fill': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (82.60870361328125, 559.3480224609375),\n             (85.00990295410156, 560.1480102539062),\n             (86.30770111083984, 561.446044921875),\n             (85.5072021484375, 562.2459716796875)),\n            ('l',\n             (85.5072021484375, 562.2459716796875),\n             (82.60870361328125, 559.3480224609375))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (82.60870361328125,\n           559.3480224609375,\n           86.30770111083984,\n           562.2459716796875),\n  'seqno': 32,\n  'stroke_opacity': 1.0,\n  'type': 'fs',\n  'width': 0.07246380299329758},\n {'even_odd': False,\n  'fill': (0.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('l', (94.2029037475586, 552.1010131835938), (100.0, 555.0)),\n            ('l', (100.0, 555.0), (94.2029037475586, 557.8989868164062)),\n            ('c',\n             (94.2029037475586, 552.1010131835938),\n             (92.60209655761719, 553.7020263671875),\n             (92.60209655761719, 556.2979736328125),\n             (94.2029037475586, 557.8989868164062))],\n  'layer': '',\n  'rect': (92.60209655761719, 552.1010131835938, 100.0, 557.8989868164062),\n  'seqno': 34,\n  'type': 'f'},\n {'closePath': False,\n  'color': (0.7215690016746521, 0.5254899859428406, 0.04313730075955391),\n  'dashes': '[] 0',\n  'items': [('l',\n             (85.5072021484375, 547.7540283203125),\n             (82.60870361328125, 550.6519775390625)),\n            ('l',\n             (82.60870361328125, 550.6519775390625),\n             (82.60870361328125, 559.3480224609375)),\n            ('l',\n             (82.60870361328125, 559.3480224609375),\n             (85.5072021484375, 562.2459716796875))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (82.60870361328125,\n           547.7540283203125,\n           85.5072021484375,\n           562.2459716796875),\n  'seqno': 35,\n  'stroke_opacity': 1.0,\n  'type': 's',\n  'width': 0.07246380299329758},\n {'closePath': False,\n  'color': (0.0, 0.0, 0.0),\n  'dashes': '[] 0',\n  'items': [('l',\n             (63.76810073852539, 547.7540283203125),\n             (85.5072021484375, 547.7540283203125)),\n            ('l', (85.5072021484375, 547.7540283203125), (100.0, 555.0)),\n            ('l', (100.0, 555.0), (85.5072021484375, 562.2459716796875)),\n            ('l',\n             (85.5072021484375, 562.2459716796875),\n             (63.76810073852539, 562.2459716796875))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (63.76810073852539, 547.7540283203125, 100.0, 562.2459716796875),\n  'seqno': 36,\n  'stroke_opacity': 1.0,\n  'type': 's',\n  'width': 1.0},\n {'even_odd': False,\n  'fill': (0.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('re',\n             (65.94200134277344,\n              552.826171875,\n              73.18838500976562,\n              557.1740112304688),\n             1),\n            ('c',\n             (73.18840026855469, 552.8259887695312),\n             (75.18939971923828, 554.0269775390625),\n             (75.18939971923828, 555.9730224609375),\n             (73.18840026855469, 557.1740112304688)),\n            ('c',\n             (65.94200134277344, 552.8259887695312),\n             (63.941001892089844, 554.0269775390625),\n             (63.941001892089844, 555.9730224609375),\n             (65.94200134277344, 557.1740112304688))],\n  'layer': '',\n  'rect': (63.941001892089844,\n           552.826171875,\n           75.18939971923828,\n           557.1740112304688),\n  'seqno': 37,\n  'type': 'f'},\n {'closePath': False,\n  'color': (1.0, 1.0, 1.0),\n  'dashes': '[] 0',\n  'items': [('l',\n             (58.937198638916016, 548.47802734375),\n             (58.937198638916016, 561.52197265625)),\n            ('l',\n             (61.352699279785156, 548.47802734375),\n             (61.352699279785156, 561.52197265625)),\n            ('l',\n             (61.352699279785156, 561.52197265625),\n             (61.352699279785156, 548.47802734375))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (58.937198638916016,\n           548.47802734375,\n           61.352699279785156,\n           561.52197265625),\n  'seqno': 38,\n  'stroke_opacity': 1.0,\n  'type': 's',\n  'width': 1.1594200134277344},\n {'closePath': False,\n  'even_odd': False,\n  'fill': (1.0, 1.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (50.0, 615.0),\n             (50.0, 628.8070068359375),\n             (61.192901611328125, 640.0),\n             (75.0, 640.0)),\n            ('c',\n             (75.0, 640.0),\n             (88.80709838867188, 640.0),\n             (100.0, 628.8070068359375),\n             (100.0, 615.0)),\n            ('c',\n             (100.0, 615.0),\n             (100.0, 601.1929931640625),\n             (88.80709838867188, 590.0),\n             (75.0, 590.0)),\n            ('c',\n             (75.0, 590.0),\n             (61.192901611328125, 590.0),\n             (50.0, 601.1929931640625),\n             (50.0, 615.0))],\n  'layer': '',\n  'rect': (50.0, 590.0, 100.0, 640.0),\n  'seqno': 39,\n  'type': 'f'},\n {'closePath': False,\n  'even_odd': False,\n  'fill': (0.0, 0.0, 0.0),\n  'fill_opacity': 1.0,\n  'items': [('c',\n             (60.0, 608.75),\n             (60.0, 612.2020263671875),\n             (62.23860168457031, 615.0),\n             (65.0, 615.0)),\n            ('c',\n             (65.0, 615.0),\n             (67.76139831542969, 615.0),\n             (70.0, 612.2020263671875),\n             (70.0, 608.75)),\n            ('c',\n             (70.0, 608.75),\n             (70.0, 605.2979736328125),\n             (67.76139831542969, 602.5),\n             (65.0, 602.5)),\n            ('c',\n             (65.0, 602.5),\n             (62.23860168457031, 602.5),\n             (60.0, 605.2979736328125),\n             (60.0, 608.75)),\n            ('c',\n             (80.0, 608.75),\n             (80.0, 612.2020263671875),\n             (82.23860168457031, 615.0),\n             (85.0, 615.0)),\n            ('c',\n             (85.0, 615.0),\n             (87.76139831542969, 615.0),\n             (90.0, 612.2020263671875),\n             (90.0, 608.75)),\n            ('c',\n             (90.0, 608.75),\n             (90.0, 605.2979736328125),\n             (87.76139831542969, 602.5),\n             (85.0, 602.5)),\n            ('c',\n             (85.0, 602.5),\n             (82.23860168457031, 602.5),\n             (80.0, 605.2979736328125),\n             (80.0, 608.75))],\n  'layer': '',\n  'rect': (60.0, 602.5, 90.0, 615.0),\n  'seqno': 40,\n  'type': 'f'},\n {'closePath': False,\n  'color': (0.0, 0.0, 0.0),\n  'dashes': '[] 0',\n  'items': [('c',\n             (60.0, 624.375),\n             (68.2843017578125, 633.0040283203125),\n             (81.7156982421875, 633.0040283203125),\n             (90.0, 624.375))],\n  'layer': '',\n  'lineCap': (0, 0, 0),\n  'lineJoin': 0.0,\n  'rect': (60.0, 624.375, 90.0, 633.0040283203125),\n  'seqno': 41,\n  'stroke_opacity': 1.0,\n  'type': 's',\n  'width': 1.0}]\n"
  },
  {
    "path": "tests/resources/test_2608_expected",
    "content": "No significant gamma-ray excess above the expected background\nis detected from the direction of FRB 20171019A, with 52 gamma\ncandidate events from the source region and 524 background event.\nA second analysis using an independent event calibration and recon-\nstruction (Parsons & Hinton 2014) confirms this result. A search for\nvariable emission on timescales ranging from milliseconds to sev-\neral minutes with tools provided in (Brun et al. 2020) does not reveal\nany variability above 2.2 𝜎. For the total data set of 1.8 h, 95% confi-\ndence level (C. L.) upper limits on the photon flux are derived using\nthe method described by Rolke et al. (2005). The energy threshold\nof the data is highly dependent on the zenith angle of the observa-\ntions. For these observations, the zenith angles range from 15 to 25\ndeg, which leads to an energy threshold for the stacked data set of\n𝐸th = 120 GeV. The upper limit on the Very High Energy (VHE)\n"
  },
  {
    "path": "tests/resources/test_2608_expected_1.26",
    "content": "No significant gamma-ray excess above the expected background\nis detected from the direction of FRB 20171019A, with 52 gamma\ncandidate events from the source region and 524 background event.\nA second analysis using an independent event calibration and reconstruction (Parsons & Hinton 2014) confirms this result. A search for\nvariable emission on timescales ranging from milliseconds to several minutes with tools provided in (Brun et al. 2020) does not reveal\nany variability above 2.2 𝜎. For the total data set of 1.8 h, 95% confidence level (C. L.) upper limits on the photon flux are derived using\nthe method described by Rolke et al. (2005). The energy threshold\nof the data is highly dependent on the zenith angle of the observations. For these observations, the zenith angles range from 15 to 25\ndeg, which leads to an energy threshold for the stacked data set of\n𝐸th = 120 GeV. The upper limit on the Very High Energy (VHE)\n"
  },
  {
    "path": "tests/resources/test_2608_expected_1.28",
    "content": "The XRT summed image is shown in Figure 5. At the edge\nof the field-of-view, we detect a source spatially coincident with\nthe Wolf 1561 star. As we consider this source unrelated to the\nFRB, we use the online Swift-XRT data products generator (Evans\net al. 2007) (Evans et al. 2009) to derive upper limits in the 0.3-\n10 keV range on the count rate of 0.001885 counts.s−1. Using\nWebPIMMS9 (v4.11a) and assuming a weighted average 𝑁H = 5.12×\n1020 cm−2 from the direction of the source estimated from the\nNASA’s HEASARC 10 online tools (HI4PI Collaboration et al.\n2016) and a power law model with a photon index = 2, this upper\nlimit translates to an energy flux of 6.6 × 10−14 erg cm−2 s−1 (8.3 ×\n10−14 erg cm−2 s−1 unabsorbed).\n"
  },
  {
    "path": "tests/resources/test_3842_expected_1.28.txt",
    "content": "NIST SP 800-223  \n \nHigh-Performance Computing Security \nFebruary 2024 \n \n  \niii \nTable of Contents \n1. Introduction ...................................................................................................................................1 \n2. HPC System Reference Architecture and Main Components ............................................................2 \n2.1.1. Components of the High-Performance Computing Zone ............................................................. 3 \n2.1.2. Components of the Data Storage Zone ........................................................................................ 4 \n2.1.3. Parallel File System ....................................................................................................................... 4 \n2.1.4. Archival and Campaign Storage .................................................................................................... 5 \n2.1.5. Burst Buffer .................................................................................................................................. 5 \n2.1.6. Components of the Access Zone .................................................................................................. 6 \n2.1.7. Components of the Management Zone ....................................................................................... 6 \n2.1.8. General Architecture and Characteristics .................................................................................... 6 \n2.1.9. Basic Services ................................................................................................................................ 7 \n2.1.10. Configuration Management ....................................................................................................... 7 \n2.1.11. HPC Scheduler and Workflow Management .............................................................................. 7 \n2.1.12. HPC Software .............................................................................................................................. 8 \n2.1.13. User Software ............................................................................................................................. 8 \n2.1.14. Site-Provided Software and Vendor Software ........................................................................... 8 \n2.1.15. Containerized Software in HPC .................................................................................................. 9 \n3. HPC Threat Analysis...................................................................................................................... 10 \n3.2.1. Access Zone Threats ................................................................................................................... 11 \n3.2.2. Management Zone Threats ........................................................................................................ 11 \n3.2.3. High-Performance Computing Zone Threats .............................................................................. 12 \n3.2.4. Data Storage Zone Threats ......................................................................................................... 12 \n4. HPC Security Posture, Challenges, and Recommendations ............................................................. 14 \n5. Conclusions .................................................................................................................................. 19 \n2.1. Main COMPONENNS..........cccccssccccssssccccssssecccssssecccsessseccessseeecsesseeceesseecsesseeesesseeecesaseecsesseeesessaeeesessaeeesD\n3.1. Key HPC Security Characteristics and Use REquireMent............cccsscccessccessecesssecesseecsssecesseeestessstree LO\n3.2. Threats to HPC FUNCTION ZONES.........cesccesscesscesscssscesecessssssssssscesscesscessssseeseesseascessssssessesssesssssessssees LO\n3.3. Other Threats ........cccccsccssccsscssccssecssscssscssscsseesssesssssesscesscseesesseeecessccssssssssessssssssssesessssssssssssssssesesLO\n4.1. HPC Access Control via Network S@gMeNtatiOn ...........ccccscccsssccessecessseceseccsssecessecessecesstecsssecesseessses LA\n4.2. Compute Node Sanitization ............cccccssecsssecsessccsseccsseecsseecceseecssseesseecssssesssesessssessseesssssesssessssessses\nLD\n4.3. Data Integrity Protection ............cccccccccccccessssssssccecccessessssssseecccesssesssssseescesssesssssseeesessssssstsssesesssssssesLO\n4.4. SECUFING CONTAINELSS ........eccesscccesssccccessseccceesscccessssecccesseeccesseeccessseeccessseccessssescessssesesssssescsssseseessLO\n4.5. Achieving Security While Maintaining HPC Performance. ..........cc:cccsscccessscesssecessecesssecesstcessseeesreesss LZ\n4.6. Challenges to HPC Security TOols..........c:ccccssccsssecceseecssseccssecessseccsseecssseecsseecssseecsssesssscssssessssssssssessse LD\n"
  },
  {
    "path": "tests/resources/test_3842_partial.txt",
    "content": "NIST SP 800-223  \n \nHigh-Performance Computing Security \nFebruary 2024 \n \n  \niii \nTable of Contents \n1. Introduction ...................................................................................................................................1 \n2. HPC System Reference Architecture and Main Components ............................................................2 \n2.1.1. Components of the High-Performance Computing Zone ............................................................. 3 \n2.1.2. Components of the Data Storage Zone ........................................................................................ 4 \n2.1.3. Parallel File System ....................................................................................................................... 4 \n2.1.4. Archival and Campaign Storage .................................................................................................... 5 \n2.1.5. Burst Buffer .................................................................................................................................. 5 \n2.1.6. Components of the Access Zone .................................................................................................. 6 \n2.1.7. Components of the Management Zone ....................................................................................... 6 \n2.1.8. General Architecture and Characteristics .................................................................................... 6 \n2.1.9. Basic Services ................................................................................................................................ 7 \n2.1.10. Configuration Management ....................................................................................................... 7 \n2.1.11. HPC Scheduler and Workflow Management .............................................................................. 7 \n2.1.12. HPC Software .............................................................................................................................. 8 \n2.1.13. User Software ............................................................................................................................. 8 \n2.1.14. Site-Provided Software and Vendor Software ........................................................................... 8 \n2.1.15. Containerized Software in HPC .................................................................................................. 9 \n3. HPC Threat Analysis...................................................................................................................... 10 \n3.2.1. Access Zone Threats ................................................................................................................... 11 \n3.2.2. Management Zone Threats ........................................................................................................ 11 \n3.2.3. High-Performance Computing Zone Threats .............................................................................. 12 \n3.2.4. Data Storage Zone Threats ......................................................................................................... 12 \n4. HPC Security Posture, Challenges, and Recommendations ............................................................. 14 \n5. Conclusions .................................................................................................................................. 19 \n2.1. Main COMPONENNS..........cccccssccccssssccccssssccccssnsecccsssseeccessseeecsessseecssaseecsessseeceessseecseeaseecsessseeesessseeessstseeesD\n3.1. Key HPC Security Characteristics and Use REquireMent............cccsscccessscesseceessecesseeesssecesseeestteessteee LO\n3.2. Threats to HPC FUNCTION ZONES..........cesccesscesscesscesscesecsssesssecssscesscesscsseessessescesssesscessessssssssssssssssssees LO\n3.3. Other Threats ........cccccsccsscssscsssccssscssscssscssscsssesssesssscssscssessseesseeseessesscsssssssessessesssessssssssssssssssssssseesesLO\n4.1. HPC Access Control via Network SEgMeNtatiOn ..........:ccccscccsssccessecesssecesecesssecessecessecessteessecessteessee LO\n4.2. Compute Node Sanitization ...........cccccessccssssccessecessecesseecssseccseecsseecsseecesseesessscssssesssescssssessssesssessses\nLD\n4.3. Data Integrity Protection ............cccccccccccccsssssssscececccesssssssseceeccessscssssseeeccesesssssssseeesessssssstsssesesssssssesLOD\n4.4. SECUFING CONTAINELSS ........ccccssccccssssccccessseeccesseeccsssssecceesssecceessseccesssseecsessseeccsssssescsssssescssssssscssssesesesLO\n4.5. Achieving Security While Maintaining HPC Performance. ..........cc:cccssccsssseesssecessecesssecessecessseesseeesee LZ\n4.6. Challenges to HPC Security TOols...........c:ccccssccssseccsssecesseecesecessseccsseecssseecsseecseseecssesesstscssssesssessssessse LZ\n"
  },
  {
    "path": "tests/resources/test_open2.fb2",
    "content": "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n<FictionBook xmlns=\"http://www.gribuser.ru/xml/fictionbook/2.0\" xmlns:xlink=\"http://www.w3.org/1999/xlink\">\n<description>\n    <title-info>\n        <genre>computers</genre>\n        <author>\n            <first-name>Chris</first-name>\n            <last-name>Clark</last-name>\n        </author>\n        <book-title>Sample FB2 book</book-title>\n        <annotation>\n            <p>Short sample of a FictionBook2 book with simple metadata. Based on test_book.md from https://github.com/clach04/sample_reading_media</p>\n        </annotation>\n        <keywords>ebook,sample,markdown,fb2,FictionBook2</keywords>\n    </title-info>\n    <document-info>\n        <author>\n            <nickname>clach04</nickname>\n            <home-page>https://github.com/clach04/sample_reading_media</home-page>\n        </author>\n\n        <program-used>vim and scite</program-used>\n        <src-url>https://github.com/clach04/sample_reading_media</src-url>\n        <version>1.0</version>\n        <history>\n            <p>Initial version, written by hand.</p>\n        </history>\n    </document-info>\n</description>\n<body>\n    <title>\n        <p>This is a title</p>\n    </title>\n\n    <section id=\"test-header-h1\">\n        <title>\n            <p>Test Header h1</p>\n        </title>\n\n        <p>A test paragraph.</p>\n        <p>Another test paragraph.</p>\n    </section>\n\n    <section id=\"another-test-header-h1\">\n        <title>\n            <p>Another Test Header h1</p>\n        </title>\n\n        <section id=\"a-test-header-h2\">\n            <title>\n                <p>A Test Header h2</p>\n            </title>\n        \n            <section id=\"a-test-header-h3\">\n                <title>\n                    <p>A Test Header h3</p>\n                </title>\n\n                <p>Yet more copy</p>\n            </section>\n        </section>\n    </section>\n</body>\n</FictionBook>\n"
  },
  {
    "path": "tests/resources/test_open2.xhtml",
    "content": "\r\n<?xml version=\"1.0\"?>\r\n<!DOCTYPE html PUBLIC \"-//W3C//DTD XHTML 1.0 Strict//EN\" \"http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd\">\r\n<html xmlns=\"http://www.w3.org/1999/xhtml\">\r\n<head>\r\n<style>\r\nbody{background-color:gray}\r\ndiv{background-color:white;margin:1em;padding:1em}\r\np{white-space:pre-wrap}\r\n</style>\r\n</head>\r\n<body>\r\n<div id=\"page0\">\r\n<p>Some text</p>\r\n</div>\r\n</body>\r\n</html>\r\n"
  },
  {
    "path": "tests/resources/test_open2.xml",
    "content": "\r\n<?xml version=\"1.0\"?>\r\n<document name=\"xml-file.xml\">\r\n<page id=\"page0\" width=\"612\" height=\"792\">\r\n<block bbox=\"100 88.175 149.52199 103.289\" justify=\"unknown\">\r\n<line bbox=\"100 88.175 149.52199 103.289\" wmode=\"0\" dir=\"1 0\" text=\"Some text\">\r\n<font name=\"Helvetica\" size=\"11\">\r\n<char quad=\"100 88.175 107.337 88.175 100 103.289 107.337 103.289\" x=\"100\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"S\"/>\r\n<char quad=\"107.337 88.175 113.452999 88.175 107.337 103.289 113.452999 103.289\" x=\"107.337\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"o\"/>\r\n<char quad=\"113.452999 88.175 122.616 88.175 113.452999 103.289 122.616 103.289\" x=\"113.452999\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"m\"/>\r\n<char quad=\"122.616 88.175 128.732 88.175 122.616 103.289 128.732 103.289\" x=\"122.616\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"e\"/>\r\n<char quad=\"128.732 88.175 131.79 88.175 128.732 103.289 131.79 103.289\" x=\"128.732\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\" \"/>\r\n<char quad=\"131.79 88.175 134.84799 88.175 131.79 103.289 134.84799 103.289\" x=\"131.79\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"t\"/>\r\n<char quad=\"134.84799 88.175 140.96399 88.175 134.84799 103.289 140.96399 103.289\" x=\"134.84799\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"e\"/>\r\n<char quad=\"140.96399 88.175 146.46399 88.175 140.96399 103.289 146.46399 103.289\" x=\"140.96399\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"x\"/>\r\n<char quad=\"146.46399 88.175 149.52199 88.175 146.46399 103.289 149.52199 103.289\" x=\"146.46399\" y=\"100\" bidi=\"0\" color=\"#000000\" alpha=\"#ff\" flags=\"16\" c=\"t\"/>\r\n</font>\r\n</line>\r\n</block>\r\n</page>\r\n</document>\r\n"
  },
  {
    "path": "tests/resources/test_open2_expected.json",
    "content": "{\n    \"tests/resources/test_open2.cbz\": {\n        \"\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".cbz\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".doc\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".docx\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".epub\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".fb2\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".html\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".jpg\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".mobi\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".pdf\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".svg\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".txt\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".xhtml\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".xml\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".xps\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        }\n    },\n    \"tests/resources/test_open2.doc\": {\n        \"\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".cbz\": {\n            \"file\": \"cfb\",\n            \"stream\": \"cfb\"\n        },\n        \".doc\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".docx\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".epub\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".fb2\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".html\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".jpg\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".mobi\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".pdf\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".svg\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".txt\": {\n            \"file\": \"Text\",\n            \"stream\": \"Text\"\n        },\n        \".xhtml\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".xml\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".xps\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        }\n    },\n    \"tests/resources/test_open2.docx\": {\n        \"\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".cbz\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".doc\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".docx\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".epub\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".fb2\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".html\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".jpg\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".mobi\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".pdf\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".svg\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".txt\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".xhtml\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".xml\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        },\n        \".xps\": {\n            \"file\": \"Office document\",\n            \"stream\": \"Office document\"\n        }\n    },\n    \"tests/resources/test_open2.epub\": {\n        \"\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".cbz\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".doc\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".docx\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".epub\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".fb2\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".html\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".jpg\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".mobi\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".pdf\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".svg\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".txt\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".xhtml\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".xml\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        },\n        \".xps\": {\n            \"file\": \"EPUB\",\n            \"stream\": \"EPUB\"\n        }\n    },\n    \"tests/resources/test_open2.fb2\": {\n        \"\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".cbz\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".doc\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".docx\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".epub\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".fb2\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".html\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".jpg\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".mobi\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".pdf\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".svg\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".txt\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".xhtml\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".xml\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".xps\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        }\n    },\n    \"tests/resources/test_open2.html\": {\n        \"\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".cbz\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".doc\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".docx\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".epub\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".fb2\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".html\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".jpg\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".mobi\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".pdf\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".svg\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".txt\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".xhtml\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".xml\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".xps\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        }\n    },\n    \"tests/resources/test_open2.jpg\": {\n        \"\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".cbz\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".doc\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".docx\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".epub\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".fb2\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".html\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".jpg\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".mobi\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".pdf\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".svg\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".txt\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".xhtml\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".xml\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".xps\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        }\n    },\n    \"tests/resources/test_open2.mobi\": {\n        \"\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".cbz\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".doc\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".docx\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".epub\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".fb2\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".html\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".jpg\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".mobi\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".pdf\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".svg\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".txt\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".xhtml\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".xml\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        },\n        \".xps\": {\n            \"file\": \"MOBI\",\n            \"stream\": \"MOBI\"\n        }\n    },\n    \"tests/resources/test_open2.pdf\": {\n        \"\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".cbz\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".doc\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".docx\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".epub\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".fb2\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".html\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".jpg\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".mobi\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".pdf\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".svg\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".txt\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".xhtml\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".xml\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        },\n        \".xps\": {\n            \"file\": \"PDF 1.5\",\n            \"stream\": \"PDF 1.5\"\n        }\n    },\n    \"tests/resources/test_open2.svg\": {\n        \"\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".cbz\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".doc\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".docx\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".epub\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".fb2\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".html\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".jpg\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".mobi\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".pdf\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".svg\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".txt\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".xhtml\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".xml\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".xps\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        }\n    },\n    \"tests/resources/test_open2.xhtml\": {\n        \"\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".cbz\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".doc\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".docx\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".epub\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".fb2\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".html\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".jpg\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".mobi\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".pdf\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".svg\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".txt\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".xhtml\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".xml\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".xps\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        }\n    },\n    \"tests/resources/test_open2.xml\": {\n        \"\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".cbz\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".doc\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".docx\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".epub\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".fb2\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".html\": {\n            \"file\": \"HTML5\",\n            \"stream\": \"HTML5\"\n        },\n        \".jpg\": {\n            \"file\": \"Image\",\n            \"stream\": \"Image\"\n        },\n        \".mobi\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".pdf\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        },\n        \".svg\": {\n            \"file\": \"SVG\",\n            \"stream\": \"SVG\"\n        },\n        \".txt\": {\n            \"file\": \"Text\",\n            \"stream\": \"Text\"\n        },\n        \".xhtml\": {\n            \"file\": \"XHTML\",\n            \"stream\": \"XHTML\"\n        },\n        \".xml\": {\n            \"file\": \"FictionBook2\",\n            \"stream\": \"FictionBook2\"\n        },\n        \".xps\": {\n            \"file\": \"[error]\",\n            \"stream\": \"[error]\"\n        }\n    },\n    \"tests/resources/test_open2.xps\": {\n        \"\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".cbz\": {\n            \"file\": \"zip\",\n            \"stream\": \"zip\"\n        },\n        \".doc\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".docx\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".epub\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".fb2\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".html\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".jpg\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".mobi\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".pdf\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".svg\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".txt\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".xhtml\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".xml\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        },\n        \".xps\": {\n            \"file\": \"XPS\",\n            \"stream\": \"XPS\"\n        }\n    }\n}"
  },
  {
    "path": "tests/run_compound.py",
    "content": "#! /usr/bin/env python3\n\n'''\nRuns a command using different implementations of PyMuPDF:\n\n1.  Run with rebased implementation of PyMuPDF.\n\n2.  As 1 but also set PYMUPDF_USE_EXTRA=0 to disable use of C++ optimisations.\n\nExample usage:\n\n    ./PyMuPDF/tests/run_compound.py python -m pytest -s PyMuPDF\n\nUse `-i <implementations>` to select which implementations to use. In\n`<implementations>`, `r` means rebased, `R` means rebased without\noptimisations.\n\nFor example use the rebased and unoptimised rebased implementations with:\n\n    ./PyMuPDF/tests/run_compound.py python -m pytest -s PyMuPDF\n'''\n\nimport shlex\nimport os\nimport platform\nimport subprocess\nimport sys\nimport textwrap\nimport time\n\n\ndef log(text):\n    print(textwrap.indent(text, 'PyMuPDF:tests/run_compound.py: '))\n    sys.stdout.flush()\n\n\ndef log_star(text):\n    log('#' * 40)\n    log(text)\n    log('#' * 40)\n\n\ndef main():\n\n    implementations = 'rR'\n    timeout = None\n    i = 1\n    while i < len(sys.argv):\n        arg = sys.argv[i]\n        if arg == '-i':\n            i += 1\n            implementations = sys.argv[i]\n        elif arg == '-t':\n            i += 1\n            timeout = float(sys.argv[i])\n        elif arg.startswith('-'):\n            raise Exception(f'Unrecognised {arg=}.')\n        else:\n            break\n        i += 1\n    args = sys.argv[i:]\n    \n    e_rebased = None\n    e_rebased_unoptimised = None\n    \n    endtime = None\n    if timeout:\n        endtime = time.time() + timeout\n    \n    # Check `implementations`.\n    implementations_seen = set()\n    for i in implementations:\n        assert i not in implementations_seen, f'Duplicate implementation {i!r} in {implementations!r}.'\n        if i == 'r':\n            name = 'rebased'\n        elif i == 'R':\n            name = 'rebased (unoptimised)'\n        else:\n            assert 0, f'Unrecognised implementation {i!r} in {implementations!r}.'\n        log(f'    {i!r}: will run with PyMuPDF {name}.')\n        implementations_seen.add(i)\n    \n    for i in implementations:\n        log(f'run_compound.py: {i=}')\n        \n        cpu_bits = int.bit_length(sys.maxsize+1)\n        log(f'{os.getcwd()=}')\n        log(f'{platform.machine()=}')\n        log(f'{platform.platform()=}')\n        log(f'{platform.python_version()=}')\n        log(f'{platform.system()=}')\n        if sys.implementation.name != 'graalpy':\n            log(f'{platform.uname()=}')\n        log(f'{sys.executable=}')\n        log(f'{sys.version=}')\n        log(f'{sys.version_info=}')\n        log(f'{list(sys.version_info)=}')\n        log(f'{cpu_bits=}')\n        \n        timeout = None\n        if endtime:\n            timeout = max(0, endtime - time.time())\n        if i == 'r':\n    \n            # Run with default `pymupdf` (rebased).\n            #\n            log_star( f'Running using pymupdf (rebased): {shlex.join(args)}')\n            e_rebased = subprocess.run( args, shell=0, check=0, timeout=timeout).returncode\n    \n        elif i == 'R':\n    \n            # Run with `pymupdf` (rebased) again, this time with PYMUPDF_USE_EXTRA=0.\n            #\n            env = os.environ.copy()\n            env[ 'PYMUPDF_USE_EXTRA'] = '0'\n            log_star(f'Running using pymupdf (rebased) with PYMUPDF_USE_EXTRA=0: {shlex.join(args)}')\n            e_rebased_unoptimised = subprocess.run( args, shell=0, check=0, env=env, timeout=timeout).returncode\n        \n        else:\n            raise Exception(f'Unrecognised implementation {i!r}.')\n    \n    if e_rebased is not None:\n        log(f'{e_rebased=}')\n    if e_rebased_unoptimised is not None:\n        log(f'{e_rebased_unoptimised=}')\n    \n    if e_rebased or e_rebased_unoptimised:\n       log('Test(s) failed.')\n       return 1\n\n\nif __name__ == '__main__':\n    try:\n        sys.exit(main())\n    except (subprocess.CalledProcessError, subprocess.TimeoutExpired) as e:\n        # Terminate relatively quietly, failed commands will usually have\n        # generated diagnostics.\n        log(str(e))\n        sys.exit(1)\n"
  },
  {
    "path": "tests/test_2548.py",
    "content": "import os\n\nimport pymupdf\n\nroot = os.path.abspath(f'{__file__}/../..')\n\ndef test_2548():\n    \"\"\"Text extraction should fail because of PDF structure cycle.\n\n    Old MuPDF version did not detect the loop.\n    \"\"\"\n    print(f'test_2548(): {pymupdf.mupdf_version_tuple=}')\n    pymupdf.TOOLS.mupdf_warnings(reset=True)\n    doc = pymupdf.open(f'{root}/tests/resources/test_2548.pdf')\n    e = False\n    for page in doc:\n        try:\n            _ = page.get_text()\n        except Exception as ee:\n            print(f'test_2548: {ee=}')\n            expected = \"RuntimeError('code=2: cycle in structure tree')\"\n            assert repr(ee) == expected, f'Expected {expected=} but got {repr(ee)=}.'\n            e = True\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    print(f'test_2548(): {wt=}')\n\n    # This checks that PyMuPDF 1.23.7 fixes this bug, and also that earlier\n    # versions with updated MuPDF also fix the bug.\n    if pymupdf.mupdf_version_tuple >= (1, 27, 1):\n        expected = ''\n    elif pymupdf.mupdf_version_tuple >= (1, 27):\n        expected = 'format error: No common ancestor in structure tree\\nstructure tree broken, assume tree is missing'\n        expected = '\\n'.join([expected] * 5)\n    else:\n        expected = 'format error: cycle in structure tree\\nstructure tree broken, assume tree is missing'\n    assert wt == expected, f'expected:\\n    {expected!r}\\nwt:\\n    {wt!r}\\n'\n    assert not e\n"
  },
  {
    "path": "tests/test_2634.py",
    "content": "import pymupdf\n\nimport difflib\nimport json\nimport os\nimport pprint\n\n\ndef test_2634():\n    if not hasattr(pymupdf, 'mupdf'):\n        print('test_2634(): Not running on classic.')\n        return\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2634.pdf')\n    with pymupdf.open(path) as pdf, pymupdf.open() as new:\n        new.insert_pdf(pdf)\n        new.set_toc(pdf.get_toc(simple=False))\n        toc_pdf = pdf.get_toc(simple=False)\n        toc_new = new.get_toc(simple=False)\n\n        def clear_xref(toc):\n            '''\n            Clear toc items that naturally differ.\n            '''\n            for item in toc:\n                d = item[3]\n                if 'collapse' in d:\n                    d['collapse'] = 'dummy'\n                if 'xref' in d:\n                    d['xref'] = 'dummy'\n\n        clear_xref(toc_pdf)\n        clear_xref(toc_new)\n\n        print('toc_pdf')\n        for item in toc_pdf: print(item)\n        print()\n        print('toc_new')\n        for item in toc_new: print(item)\n\n        toc_text_pdf = pprint.pformat(toc_pdf, indent=4).split('\\n')\n        toc_text_new = pprint.pformat(toc_new, indent=4).split('\\n')\n\n        diff = difflib.unified_diff(\n                toc_text_pdf,\n                toc_text_new,\n                lineterm='',\n                )\n        print('\\n'.join(diff))\n\n        # Check 'to' points are identical apart from rounding errors.\n        #\n        assert len(toc_new) == len(toc_pdf)\n        for a, b in zip(toc_pdf, toc_new):\n            a_dict = a[3]\n            b_dict = b[3]\n            if 'to' in a_dict:\n                assert 'to' in b_dict\n                a_to = a_dict['to']\n                b_to = b_dict['to']\n                assert isinstance(a_to, pymupdf.Point)\n                assert isinstance(b_to, pymupdf.Point)\n                if a_to != b_to:\n                    print(f'Points not identical: {a_to=} {b_to=}.')\n                assert abs(a_to.x - b_to.x) < 0.01\n                assert abs(a_to.y - b_to.y) < 0.01\n"
  },
  {
    "path": "tests/test_2904.py",
    "content": "import pymupdf\n\nimport os\nimport sys\n\ndef test_2904():\n    print(f'test_2904(): {pymupdf.mupdf_version_tuple=}.')\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2904.pdf')\n    pdf_docs = pymupdf.open(path)\n    for page_id, page in enumerate(pdf_docs):\n        page_imgs = page.get_images()\n        for i, img in enumerate(page_imgs):\n            if page_id == 5:\n                #print(f'{page_id=} {i=} {type(img)=} {img=}')\n                sys.stdout.flush()\n            e = None\n            try:\n                recs = page.get_image_rects(img, transform=True)\n            except Exception as ee:\n                print(f'Exception: {page_id=} {i=} {img=}: {ee}')\n                if 0 and hasattr(pymupdf, 'mupdf'):\n                    print(f'pymupdf.exception_info:')\n                    pymupdf.exception_info()\n                    sys.stdout.flush()\n                e = ee\n            if page_id == 5:\n                print(f'{pymupdf.mupdf_version_tuple=}: {page_id=} {i=} {e=} {img=}:')\n            if page_id == 5 and i==3:\n                assert e\n                assert str(e) == 'code=8: Failed to read JPX header'\n            else:\n                assert not e\n    \n    # Clear warnings, as we will have generated many.\n    pymupdf.TOOLS.mupdf_warnings()     \n"
  },
  {
    "path": "tests/test_2907.py",
    "content": "import pymupdf\n\nimport os.path\nimport pathlib\n\ndef test_2907():\n    # This test is for a bug in classic 'segfault trying to call clean_contents\n    # on certain pdfs with python 3.12', which we are not going to fix.\n    if not hasattr(pymupdf, 'mupdf'):\n        print('test_2907(): not running on classic because known to fail.')\n        return\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2907.pdf')\n    pdf_file = pathlib.Path(path).read_bytes()\n    fitz_document = pymupdf.open(stream=pdf_file, filetype=\"application/pdf\")\n\n    pdf_pages = list(fitz_document.pages())\n    (page,) = pdf_pages\n    page.clean_contents()\n"
  },
  {
    "path": "tests/test_4141.py",
    "content": "import pymupdf\n\nimport os.path\n\n\ndef test_4141():\n    \"\"\"survive missing /Resources object in a number of cases.\"\"\"\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/test_4141.pdf\")\n    doc = pymupdf.open(path)\n    page = doc[0]\n    # make sure the right test file\n    assert doc.xref_get_key(page.xref, \"Resources\") == (\"null\", \"null\")\n    page.insert_htmlbox((100, 100, 200, 200), \"Hallo\")  # will fail without the fix\n    doc.close()\n    doc = pymupdf.open(doc.name)\n    page = doc[0]\n    tw = pymupdf.TextWriter(page.rect)\n    tw.append((100, 100), \"Hallo\")\n    tw.write_text(page)  # will fail without the fix\n"
  },
  {
    "path": "tests/test_4503.py",
    "content": "\"\"\"\nTest for issue #4503 in pymupdf:\nCorrect recognition of strikeout and underline styles in text spans.\n\"\"\"\n\nimport os\nimport pymupdf\nfrom pymupdf import mupdf\n\nSTRIKEOUT = mupdf.FZ_STEXT_STRIKEOUT\nUNDERLINE = mupdf.FZ_STEXT_UNDERLINE\n\n\ndef test_4503():\n    \"\"\"\n    Check that the text span with the specified text has the correct styling:\n    strikeout, but no underline.\n    Previously, the text was broken in multiple spans with span breaks at\n    every space. and some parts were not detected as strikeout at all.\n    \"\"\"\n    scriptdir = os.path.dirname(os.path.abspath(__file__))\n    text = \"the right to request the state to review and, if appropriate,\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-4503.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    flags = pymupdf.TEXT_ACCURATE_BBOXES | pymupdf.TEXT_COLLECT_STYLES\n    spans = [\n        s\n        for b in page.get_text(\"dict\", flags=flags)[\"blocks\"]\n        for l in b[\"lines\"]\n        for s in l[\"spans\"]\n        if s[\"text\"] == text\n    ]\n    assert spans, \"No spans found with the specified text\"\n    span = spans[0]\n\n    assert span[\"char_flags\"] & STRIKEOUT\n    assert not span[\"char_flags\"] & UNDERLINE\n"
  },
  {
    "path": "tests/test_4505.py",
    "content": "import pymupdf\nimport os.path\n\n\ndef test_4505():\n    \"\"\"Copy field flags to Parent widget and all of its kids.\"\"\"\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/test_4505.pdf\")\n    doc = pymupdf.open(path)\n    page = doc[0]\n    text1_flags_before = {}\n    text1_flags_after = {}\n    # extract all widgets having the same field name\n    for w in page.widgets():\n        if w.field_name != \"text_1\":\n            continue\n        text1_flags_before[w.xref] = w.field_flags\n    # expected exiting field flags\n    assert text1_flags_before == {8: 1, 10: 0, 33: 0}\n    w = page.load_widget(8)  # first of these widgets\n    # give all connected widgets that field flags value\n    w.update(sync_flags=True)\n    # confirm that all connected widgets have the same field flags\n    for w in page.widgets():\n        if w.field_name != \"text_1\":\n            continue\n        text1_flags_after[w.xref] = w.field_flags\n    assert text1_flags_after == {8: 1, 10: 1, 33: 1}\n"
  },
  {
    "path": "tests/test_4520.py",
    "content": "import pymupdf\n\n\ndef test_4520():\n    \"\"\"Accept source pages without /Contents object in show_pdf_page.\"\"\"\n    tar = pymupdf.open()\n    src = pymupdf.open()\n    src.new_page()\n    page = tar.new_page()\n    xref = page.show_pdf_page(page.rect, src, 0)\n    assert xref\n"
  },
  {
    "path": "tests/test_4614.py",
    "content": "import pymupdf\nimport os\n\n\ndef test_4614():\n    script_dir = os.path.dirname(__file__)\n    filename = os.path.join(script_dir, \"resources\", \"test_4614.pdf\")\n    src = pymupdf.open(filename)\n    doc = pymupdf.open()\n    doc.insert_pdf(src)\n"
  },
  {
    "path": "tests/test_4716.py",
    "content": "import pymupdf\nimport os\n\ndef test_4716():\n    \"\"\"Confirm that ZERO WIDTH JOINER will never start a word.\"\"\"\n    script_dir = os.path.dirname(__file__)\n    filename = os.path.join(script_dir, \"resources\", \"test_4716.pdf\")\n    doc = pymupdf.open(filename)\n    expected = set([\"+25.00\", \"Любимый\", \"-10.00\"])\n    word_text = set()\n    for page in doc:\n        words = page.get_text(\"words\")\n        for w in words:\n            word_text.add(w[4])\n    assert word_text == expected\n"
  },
  {
    "path": "tests/test_4767.py",
    "content": "import shutil\nimport os\nimport platform\nimport pymupdf\nimport subprocess\nimport sys\nimport sysconfig\n\n\ndef test_4767():\n    '''\n    Check handling of unsafe paths in `pymupdf embed-extract`.\n    '''\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4767(): not running on Pyodide - cannot run child processes.')\n        return\n    \n    if (1\n            and platform.system() == 'Windows'\n            and os.environ.get('GITHUB_ACTIONS') == 'true'\n            and os.environ.get('CIBUILDWHEEL') == '1'\n            ):\n        print(f'test_4767(): not running because known to fail on Github/Windows/Cibuildwheel.')\n        # Using -unsafe makes pymupdf return 0 but does not seem to create\n        # output file.\n        return\n        \n    with pymupdf.open() as document:\n        document.new_page() \n        document.embfile_add(\n                'evil_entry',\n                b'poc:traversal test\\n',\n                filename=\"../../test.txt\",\n                ufilename=\"../../test.txt\",\n                desc=\"poc\",\n                )\n        document.embfile_add(\n                'evil_entry2',\n                b'poc:traversal test\\n',\n                filename=\"test2.txt\",\n                ufilename=\"test2.txt\",\n                desc=\"poc\",\n                )\n        path = os.path.abspath(f'{__file__}/../../tests/test_4767.pdf')\n        document.save(path)\n    testdir = os.path.abspath(f'{__file__}/../../tests/test_4767_dir').replace('\\\\', '/')\n    shutil.rmtree(testdir, ignore_errors=1)\n    os.makedirs(f'{testdir}/one/two', exist_ok=1)\n    \n    def run(command, *, check=0, capture=1):\n        print(f'Running: {command}')\n        cp = subprocess.run(\n                command, shell=1,\n                text=1,\n                check=check,\n                stdout=subprocess.PIPE if capture else None,\n                stderr=subprocess.STDOUT if capture else None,\n                )\n        print(cp.stdout)\n        return cp\n    \n    def get_paths():\n        paths = list()\n        for dirpath, dirnames, filenames in os.walk(testdir):\n            for filename in filenames:\n                path = f'{dirpath}/{filename}'.replace('\\\\', '/')\n                paths.append(path)\n        return paths\n    \n    def get_stdout(cp):\n        '''\n        Strips free-threading warning.\n        '''\n        stdout = cp.stdout\n        if sysconfig.get_config_var('Py_GIL_DISABLED') == 1 and sys._is_gil_enabled():\n            line0, stdout = stdout.split('\\n', 1)\n            assert 'The global interpreter lock (GIL) has been enabled to load module \\'pymupdf._extra\\',' in line0\n        return stdout\n    \n    cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry')\n    assert cp.returncode\n    stdout = get_stdout(cp)\n    print(f'{stdout=}')\n    assert stdout == 'refusing to write stored name outside current directory: ../../test.txt\\n'\n    assert not get_paths()\n    \n    cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry -unsafe')\n    assert cp.returncode == 0\n    stdout = get_stdout(cp)\n    assert stdout == \"saved entry 'evil_entry' as '../../test.txt'\\n\"\n    paths = get_paths()\n    print(f'{paths=}')\n    assert paths == [f'{testdir}/test.txt']\n    \n    cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry2')\n    assert not cp.returncode\n    stdout = get_stdout(cp)\n    assert stdout == \"saved entry 'evil_entry2' as 'test2.txt'\\n\"\n    paths = get_paths()\n    print(f'{paths=}')\n    assert paths == [f'{testdir}/test.txt', f'{testdir}/one/two/test2.txt']\n    \n    cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry2')\n    assert cp.returncode\n    stdout = get_stdout(cp)\n    assert stdout == \"refusing to overwrite existing file with stored name: test2.txt\\n\"\n    paths = get_paths()\n    print(f'{paths=}')\n    assert paths == [f'{testdir}/test.txt', f'{testdir}/one/two/test2.txt']\n    \n    cp = run(f'cd {testdir}/one/two && {sys.executable} -m pymupdf embed-extract {path} -name evil_entry2 -unsafe')\n    assert not cp.returncode\n    stdout = get_stdout(cp)\n    assert stdout == \"saved entry 'evil_entry2' as 'test2.txt'\\n\"\n    paths = get_paths()\n    print(f'{paths=}')\n    assert paths == [f'{testdir}/test.txt', f'{testdir}/one/two/test2.txt']\n"
  },
  {
    "path": "tests/test_4942.py",
    "content": "import pymupdf, os\n\n\ndef test_4942():\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/test_4942.pdf\")\n    document = pymupdf.Document(path)\n    page = document[0]\n    page.clip_to_rect(page.rect)\n    page.get_links()\n"
  },
  {
    "path": "tests/test_annots.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"\nTest PDF annotation insertions.\n\"\"\"\n\nimport copy\nimport os\nimport platform\n\nimport pymupdf\nimport gentle_compare\n\n\nred = (1, 0, 0)\nblue = (0, 0, 1)\ngold = (1, 1, 0)\ngreen = (0, 1, 0)\nscriptdir = os.path.dirname(__file__)\n\ndispl = pymupdf.Rect(0, 50, 0, 50)\nr = pymupdf.Rect(72, 72, 220, 100)\nt1 = \"têxt üsès Lätiñ charß,\\nEUR: €, mu: µ, super scripts: ²³!\"\nrect = pymupdf.Rect(100, 100, 200, 200)\n\n\ndef test_caret():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_caret_annot(rect.tl)\n    assert annot.type == (14, \"Caret\")\n    annot.update(rotate=20)\n    page.annot_names()\n    page.annot_xrefs()\n\n\ndef test_freetext():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_freetext_annot(\n        rect,\n        t1,\n        fontsize=10,\n        rotate=90,\n        text_color=blue,\n        fill_color=gold,\n        align=pymupdf.TEXT_ALIGN_CENTER,\n    )\n    annot.set_border(width=0.3, dashes=[2])\n    annot.update(text_color=blue, fill_color=gold)\n    assert annot.type == (2, \"FreeText\")\n\n\ndef test_text():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_text_annot(r.tl, t1)\n    assert annot.type == (0, \"Text\")\n\n\ndef test_highlight():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_highlight_annot(rect)\n    assert annot.type == (8, \"Highlight\")\n\n\ndef test_underline():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_underline_annot(rect)\n    assert annot.type == (9, \"Underline\")\n\n\ndef test_squiggly():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_squiggly_annot(rect)\n    assert annot.type == (10, \"Squiggly\")\n\n\ndef test_strikeout():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_strikeout_annot(rect)\n    assert annot.type == (11, \"StrikeOut\")\n    page.delete_annot(annot)\n\n\ndef test_polyline():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = page.rect + (100, 36, -100, -36)\n    cell = pymupdf.make_table(rect, rows=10)\n    for i in range(10):\n        annot = page.add_polyline_annot((cell[i][0].bl, cell[i][0].br))\n        annot.set_line_ends(i, i)\n        annot.update()\n    for i, annot in enumerate(page.annots()):\n        assert annot.line_ends == (i, i)\n    assert annot.type == (7, \"PolyLine\")\n\n\ndef test_polygon():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_polygon_annot([rect.bl, rect.tr, rect.br, rect.tl])\n    assert annot.type == (6, \"Polygon\")\n\n\ndef test_line():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = page.rect + (100, 36, -100, -36)\n    cell = pymupdf.make_table(rect, rows=10)\n    for i in range(10):\n        annot = page.add_line_annot(cell[i][0].bl, cell[i][0].br)\n        annot.set_line_ends(i, i)\n        annot.update()\n    for i, annot in enumerate(page.annots()):\n        assert annot.line_ends == (i, i)\n    assert annot.type == (3, \"Line\")\n\n\ndef test_square():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_rect_annot(rect)\n    assert annot.type == (4, \"Square\")\n\n\ndef test_circle():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_circle_annot(rect)\n    assert annot.type == (5, \"Circle\")\n\n\ndef test_fileattachment():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_file_annot(rect.tl, b\"just anything for testing\", \"testdata.txt\")\n    assert annot.type == (17, \"FileAttachment\")\n\n\ndef test_stamp():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_stamp_annot(r, stamp=0)\n    assert annot.type == (13, \"Stamp\")\n    assert annot.info[\"content\"] == \"Approved\"\n    annot_id = annot.info[\"id\"]\n    annot_xref = annot.xref\n    page.load_annot(annot_id)\n    page.load_annot(annot_xref)\n    page = doc.reload_page(page)\n\n\ndef test_image_stamp():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    filename = os.path.join(scriptdir, \"resources\", \"nur-ruhig.jpg\")\n    annot = page.add_stamp_annot(r, stamp=filename)\n    assert annot.info[\"content\"] == \"Image Stamp\"\n\n\ndef test_redact1():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_redact_annot(r, text=\"Hello\")\n    annot.update(\n        cross_out=True,\n        rotate=-1,\n    )\n    assert annot.type == (12, \"Redact\")\n    annot.get_pixmap()\n    info = annot.info\n    annot.set_info(info)\n    assert not annot.has_popup\n    annot.set_popup(r)\n    s = annot.popup_rect\n    assert s == r\n    page.apply_redactions()\n\n\ndef test_redact2():\n    \"\"\"Test for keeping text and removing graphics.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"Not executing 'test_redact2' in classic\")\n        return\n    filename = os.path.join(scriptdir, \"resources\", \"symbol-list.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    all_text0 = page.get_text(\"words\")\n    page.add_redact_annot(page.rect)\n    page.apply_redactions(text=1)\n    t = page.get_text(\"words\")\n    assert t == all_text0\n    assert not page.get_drawings()\n\n\ndef test_redact3():\n    \"\"\"Test for removing text and graphics.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"Not executing 'test_redact3' in classic\")\n        return\n    filename = os.path.join(scriptdir, \"resources\", \"symbol-list.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    page.add_redact_annot(page.rect)\n    page.apply_redactions()\n    assert not page.get_text(\"words\")\n    assert not page.get_drawings()\n\n\ndef test_redact4():\n    \"\"\"Test for removing text and keeping graphics.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"Not executing 'test_redact4' in classic\")\n        return\n    filename = os.path.join(scriptdir, \"resources\", \"symbol-list.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    line_art = page.get_drawings()\n    page.add_redact_annot(page.rect)\n    page.apply_redactions(graphics=0)\n    doc.save(os.path.normpath(f'{__file__}/../../tests/test_redact4_out.pdf'))\n    assert not page.get_text(\"words\")\n    assert line_art == page.get_drawings()\n\n\ndef test_1645():\n    '''\n    Test fix for #1645.\n    '''\n    # The expected output files assume annot_stem is 'jorj'. We need to always\n    # restore this before returning (this is checked by conftest.py).\n    annot_stem = pymupdf.JM_annot_id_stem\n    pymupdf.TOOLS.set_annot_stem('jorj')\n    try:\n        path_in = os.path.abspath( f'{__file__}/../resources/symbol-list.pdf')\n        if pymupdf.mupdf_version_tuple >= (1, 27):\n            path_expected = os.path.abspath( f'{__file__}/../../tests/resources/test_1645_expected-after-1.27.0.pdf')\n        else:\n            path_expected = os.path.abspath( f'{__file__}/../../tests/resources/test_1645_expected.pdf')\n        path_out = os.path.abspath( f'{__file__}/../test_1645_out.pdf')\n        doc = pymupdf.open(path_in)\n        page = doc[0]\n        page_bounds = page.bound()\n        annot_loc = pymupdf.Rect(page_bounds.x0, page_bounds.y0, page_bounds.x0 + 75, page_bounds.y0 + 15)\n        # Check type of page.derotation_matrix - this is #2911.\n        assert isinstance(page.derotation_matrix, pymupdf.Matrix), \\\n                f'Bad type for page.derotation_matrix: {type(page.derotation_matrix)=} {page.derotation_matrix=}.'\n        page.add_freetext_annot(\n                annot_loc * page.derotation_matrix,\n                \"TEST\",\n                fontsize=18,\n                fill_color=pymupdf.utils.getColor(\"FIREBRICK1\"),\n                rotate=page.rotation,\n                )\n        doc.save(path_out, garbage=1, deflate=True, no_new_id=True)\n        print(f'Have created {path_out}. comparing with {path_expected}.')\n        with pymupdf.open(path_expected) as doc_expected, pymupdf.open(path_out) as doc_out:\n            rms = gentle_compare.pixmaps_rms(\n                    doc_expected[0].get_pixmap(),\n                    doc_out[0].get_pixmap(),\n                    )\n        print(f'test_1645: {rms=}')\n        assert rms < 0.1, f'Pixmaps differ: {path_expected=} {path_out=}'\n    finally:\n        # Restore annot_stem.\n        pymupdf.TOOLS.set_annot_stem(annot_stem)\n\ndef test_1824():\n    '''\n    Test for fix for #1824: SegFault when applying redactions overlapping a\n    transparent image.\n    '''\n    path = os.path.abspath( f'{__file__}/../resources/test_1824.pdf')\n    doc=pymupdf.open(path)\n    page=doc[0]\n    page.apply_redactions()\n\ndef test_2270():\n    '''\n    https://github.com/pymupdf/PyMuPDF/issues/2270\n    '''\n    path = os.path.abspath( f'{__file__}/../../tests/resources/test_2270.pdf')\n    with pymupdf.open(path) as document:\n        for page_number, page in enumerate(document):\n            for textBox in page.annots(types=(pymupdf.PDF_ANNOT_FREE_TEXT,pymupdf.PDF_ANNOT_TEXT)):\n                print(\"textBox.type :\", textBox.type)\n                print(f\"{textBox.rect=}\")\n                print(\"textBox.get_text('words') : \", textBox.get_text('words'))\n                print(\"textBox.get_text('text') : \", textBox.get_text('text'))\n                print(\"textBox.get_textbox(textBox.rect) : \", textBox.get_textbox(textBox.rect))\n                print(\"textBox.info['content'] : \", textBox.info['content'])\n                assert textBox.type == (2, 'FreeText')\n                assert textBox.get_text('words')[0][4] == 'abc123'\n                assert textBox.get_text('text') == 'abc123\\n'\n                assert textBox.get_textbox(textBox.rect) == 'abc123'\n                assert textBox.info['content'] == 'abc123'\n\n                # Additional check that Annot.get_textpage() returns a\n                # TextPage that works with page.get_text() - prior to\n                # 2024-01-30 the TextPage had no `.parent` member.\n                textpage = textBox.get_textpage()\n                text = page.get_text()\n                print(f'{text=}')\n                text = page.get_text(textpage=textpage)\n                print(f'{text=}')\n                print(f'{getattr(textpage, \"parent\")=}')\n\n                # Check Annotation.get_textpage()'s <clip> arg.\n                clip = textBox.rect\n                clip.x1 = clip.x0 + (clip.x1 - clip.x0) / 3\n                textpage2 = textBox.get_textpage(clip=clip)\n                text = textpage2.extractText()\n                print(f'With {clip=}: {text=}')\n                assert text == 'ab\\n'\n                    \n\ndef test_2934_add_redact_annot():\n    '''\n    Test fix for bug mentioned in #2934.\n    '''\n    path = os.path.abspath(f'{__file__}/../../tests/resources/mupdf_explored.pdf')\n    with open(path, 'rb') as f:\n        data = f.read()\n    doc = pymupdf.Document(stream=data)\n    print(f'Is PDF: {doc.is_pdf}')\n    print(f'Number of pages: {doc.page_count}')\n\n    import json\n    page=doc[0]\n    page_json_str =doc[0].get_text(\"json\")\n    page_json_data = json.loads(page_json_str)\n    span=page_json_data.get(\"blocks\")[0].get(\"lines\")[0].get(\"spans\")[0]\n    page.add_redact_annot(span[\"bbox\"], text=\"\")\n    page.apply_redactions()\n\ndef test_2969():\n    '''\n    https://github.com/pymupdf/PyMuPDF/issues/2969\n    '''\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2969.pdf')\n    doc = pymupdf.open(path)\n    page = doc[0]\n    first_annot = list(page.annots())[0]\n    first_annot.next\n\ndef test_file_info():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_annot_file_info.pdf')\n    document = pymupdf.open(path)\n    results = list()\n    for i, page in enumerate(document):\n        print(f'{i=}')\n        annotations = page.annots()\n        for j, annotation in enumerate(annotations):\n            print(f'{j=} {annotation=}')\n            t = annotation.type\n            print(f'{t=}')\n            if t[0] == pymupdf.PDF_ANNOT_FILE_ATTACHMENT:\n                file_info = annotation.file_info\n                print(f'{file_info=}')\n                results.append(file_info)\n    assert results == [\n            {'filename': 'example.pdf', 'description': '', 'length': 8416, 'size': 8992},\n            {'filename': 'photo1.jpeg', 'description': '', 'length': 10154, 'size': 8012},\n            ]\n\ndef test_3131():\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    page.add_line_annot((0, 0), (1, 1))\n    page.add_line_annot((1, 0), (0, 1))\n\n    first_annot, _ = page.annots()\n    first_annot.next.type\n\ndef test_3209():\n    pdf = pymupdf.Document(filetype=\"pdf\")\n    page = pdf.new_page()\n    page.add_ink_annot([[(300,300), (400, 380), (350, 350)]])\n    n = 0\n    for annot in page.annots():\n        n += 1\n        assert annot.vertices == [[(300.0, 300.0), (400.0, 380.0), (350.0, 350.0)]]\n    assert n == 1\n    path = os.path.abspath(f'{__file__}/../../tests/test_3209_out.pdf')\n    pdf.save(path)  # Check the output PDF that the annotation is correctly drawn\n\ndef test_3863():\n    path_in = os.path.normpath(f'{__file__}/../../tests/resources/test_3863.pdf')\n    path_out = os.path.normpath(f'{__file__}/../../tests/test_3863.pdf.pdf')\n    \n    # Create redacted PDF.\n    print(f'Loading {path_in=}.')\n    with pymupdf.open(path_in) as document:\n    \n        for num, page in enumerate(document):\n            print(f\"Page {num + 1} - {page.rect}:\")\n    \n            for image in page.get_images(full=True):\n                print(f\"  - Image: {image}\")\n\n            redact_rect = page.rect\n\n            if page.rotation in (90, 270):\n                redact_rect = pymupdf.Rect(0, 0, page.rect.height, page.rect.width)\n\n            page.add_redact_annot(redact_rect)\n            page.apply_redactions(images=pymupdf.PDF_REDACT_IMAGE_NONE)\n\n        print(f'Writing to {path_out=}.')\n        document.save(path_out)\n    \n    with pymupdf.open(path_out) as document:\n        assert len(document) == 8\n        \n        # Create PNG for each page of redacted PDF.\n        for num, page in enumerate(document):\n            path_png = f'{path_out}.{num}.png'\n            pixmap = page.get_pixmap()\n            print(f'Writing to {path_png=}.')\n            pixmap.save(path_png)\n            # Compare with expected png.\n    \n        print(f'Comparing page PNGs with expected PNGs.')\n        for num, _ in enumerate(document):\n            path_png = f'{path_out}.{num}.png'\n            path_png_expected = f'{path_in}.pdf.{num}.png'\n            print(f'{path_png=}.')\n            print(f'{path_png_expected=}.')\n            rms = gentle_compare.pixmaps_rms(path_png, path_png_expected, '    ')\n            # We get small differences in sysinstall tests, where some\n            # thirdparty libraries can differ.\n            assert rms < 1\n\ndef test_3758():\n    # This test requires input file that is not public, so is usually not\n    # available.\n    path = os.path.normpath(f'{__file__}/../../../test_3758.pdf')\n    if not os.path.exists(path):\n        print(f'test_3758(): not running because does not exist: {path=}.')\n        return\n    import json\n    with pymupdf.open(path) as document:\n        for page in document:\n            info = json.loads(page.get_text('json', flags=pymupdf.TEXTFLAGS_TEXT))\n            for block_ind, block in enumerate(info['blocks']):\n                for line_ind, line in enumerate(block['lines']):\n                    for span_ind, span in enumerate(line['spans']):\n                        # print(span)\n                        page.add_redact_annot(pymupdf.Rect(*span['bbox']))\n            page.apply_redactions()\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt\n\n\ndef test_parent():\n    \"\"\"Test invalidating parent on page re-assignment.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    a = page.add_highlight_annot(page.rect)  # insert annotation on page 0\n    page = doc.new_page()  # make a new page, should orphanate annotation\n    try:\n        print(a)  # should raise\n    except Exception as e:\n        if platform.system() == 'OpenBSD':\n            assert isinstance(e, pymupdf.mupdf.FzErrorBase), f'Incorrect {type(e)=}.'\n        else:\n            assert isinstance(e, pymupdf.mupdf.FzErrorArgument), f'Incorrect {type(e)=}.'\n        assert str(e) == 'code=4: annotation not bound to any page', f'Incorrect error text {str(e)=}.'\n    else:\n        assert 0, f'Failed to get expected exception.'\n\ndef test_4047():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4047.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        fontname = page.get_fonts()[0][3]\n        if fontname not in pymupdf.Base14_fontnames:\n            fontname = \"Courier\"\n        hits = page.search_for(\"|\")\n        for rect in hits:\n            page.add_redact_annot(\n                rect, \" \", fontname=fontname, align=pymupdf.TEXT_ALIGN_CENTER, fontsize=10\n            )  # Segmentation Fault...\n        page.apply_redactions()\n\ndef test_4079():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4079.pdf')\n    path_after = os.path.normpath(f'{__file__}/../../tests/resources/test_4079_after.pdf')\n        \n    path_out = os.path.normpath(f'{__file__}/../../tests/test_4079_out')\n    with pymupdf.open(path_after) as document_after:\n        page = document_after[0]\n        pixmap_after_expected = page.get_pixmap()\n    with pymupdf.open(path) as document:\n        page = document[0]\n        rects = [\n                [164,213,282,227],\n                [282,213,397,233],\n                [434,209,525,243],\n                [169,228,231,243],\n                [377,592,440,607],\n                [373,611,444,626],\n                ]\n        for rect in rects:\n            page.add_redact_annot(rect, fill=(1,0,0))\n            page.draw_rect(rect, color=(0, 1, 0))\n        document.save(f'{path_out}_before.pdf')\n        page.apply_redactions(images=0)\n        pixmap_after = page.get_pixmap()\n        document.save(f'{path_out}_after.pdf')\n        rms = gentle_compare.pixmaps_rms(pixmap_after_expected, pixmap_after)\n        diff = gentle_compare.pixmaps_diff(pixmap_after_expected, pixmap_after)\n        path = os.path.normpath(f'{__file__}/../../tests/test_4079_diff.png')\n        diff.save(path)\n        print(f'{rms=}')\n        assert rms == 0\n\ndef test_4254():\n    \"\"\"Ensure that both annotations are fully created\n\n    We do this by asserting equal top-used colors in respective pixmaps.\n    \"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    rect = pymupdf.Rect(100, 100, 200, 150)\n    annot = page.add_freetext_annot(rect, \"Test Annotation from minimal example\")\n    annot.set_border(width=1, dashes=(3, 3))\n    annot.set_opacity(0.5)\n    try:\n        annot.set_colors(stroke=(1, 0, 0))\n    except ValueError as e:\n        assert 'cannot be used for FreeText annotations' in str(e), f'{e}'\n    else:\n        assert 0\n    annot.update()\n\n    rect = pymupdf.Rect(200, 200, 400, 400)\n    annot2 = page.add_freetext_annot(rect, \"Test Annotation from minimal example pt 2\")\n    annot2.set_border(width=1, dashes=(3, 3))\n    annot2.set_opacity(0.5)\n    try:\n        annot2.set_colors(stroke=(1, 0, 0))\n    except ValueError as e:\n        assert 'cannot be used for FreeText annotations' in str(e), f'{e}'\n    else:\n        assert 0\n    annot.update()\n    annot2.update()\n\n    # stores top color for each pixmap\n    top_colors = set()\n    for annot in page.annots():\n        pix = annot.get_pixmap()\n        top_colors.add(pix.color_topusage()[1])\n\n    # only one color must exist\n    assert len(top_colors) == 1\n\ndef test_richtext():\n    \"\"\"Test creation of rich text FreeText annotations.\n\n    We create the same annotation on different pages in different ways,\n    with and without using Annotation.update(), and then assert equality\n    of the respective images.\n    \"\"\"\n    ds = \"\"\"font-size: 11pt; font-family: sans-serif;\"\"\"\n    bullet = chr(0x2610) + chr(0x2611) + chr(0x2612)\n    text = f\"\"\"<p style=\"text-align:justify;margin-top:-25px;\">\n    PyMuPDF <span style=\"color: red;\">འདི་ ཡིག་ཆ་བཀྲམ་སྤེལ་གྱི་དོན་ལུ་ པའི་ཐོན་ཐུམ་སྒྲིལ་དྲག་ཤོས་དང་མགྱོགས་ཤོས་ཅིག་ཨིན།</span>\n    <span style=\"color:blue;\">Here is some <b>bold</b> and <i>italic</i> text, followed by <b><i>bold-italic</i></b>. Text-based check boxes: {bullet}.</span>\n    </p>\"\"\"\n    gold = (1, 1, 0)\n    doc = pymupdf.open()\n\n    # First page.\n    page = doc.new_page()\n    rect = pymupdf.Rect(100, 100, 350, 200)\n    p2 = rect.tr + (50, 30)\n    p3 = p2 + (0, 30)\n    annot = page.add_freetext_annot(\n        rect,\n        text,\n        fill_color=gold,\n        opacity=0.5,\n        rotate=90,\n        border_width=1,\n        dashes=None,\n        richtext=True,\n        callout=(p3, p2, rect.tr),\n    )\n\n    pix1 = page.get_pixmap()\n\n    # Second page.\n    # the annotation is created with minimal parameters, which are supplied\n    # in a separate call to the .update() method.\n    page = doc.new_page()\n    annot = page.add_freetext_annot(\n        rect,\n        text,\n        border_width=1,\n        dashes=None,\n        richtext=True,\n        callout=(p3, p2, rect.tr),\n    )\n    annot.update(fill_color=gold, opacity=0.5, rotate=90)\n    pix2 = page.get_pixmap()\n    assert pix1.samples == pix2.samples\n\n\ndef test_4447():\n    document = pymupdf.open()\n    \n    page = document.new_page()\n\n    text_color = (1, 0, 0)\n    fill_color = (0, 1, 0)\n    border_color = (0, 0, 1)\n\n    annot_rect = pymupdf.Rect(90.1, 486.73, 139.26, 499.46)\n\n    try:\n        annot = page.add_freetext_annot(\n            annot_rect,\n            \"AETERM\",\n            fontname=\"Arial\",\n            fontsize=10,\n            text_color=text_color,\n            fill_color=fill_color,\n            border_color=border_color,\n            border_width=1,\n        )\n    except ValueError as e:\n        assert 'cannot set border_color if rich_text is False' in str(e), str(e)\n    else:\n        assert 0\n    \n    try:\n        annot = page.add_freetext_annot(\n                (30, 400, 100, 450),\n                \"Two\",\n                fontname=\"Arial\",\n                fontsize=10,\n                text_color=text_color,\n                fill_color=fill_color,\n                border_color=border_color,\n                border_width=1,\n                )\n    except ValueError as e:\n        assert 'cannot set border_color if rich_text is False' in str(e), str(e)\n    else:\n        assert 0\n    \n    annot = page.add_freetext_annot(\n            (30, 500, 100, 550),\n            \"Three\",\n            fontname=\"Arial\",\n            fontsize=10,\n            text_color=text_color,\n            border_width=1,\n            )\n    annot.update(text_color=text_color, fill_color=fill_color)\n    try:\n        annot.update(border_color=border_color)\n    except ValueError as e:\n        assert 'cannot set border_color if rich_text is False' in str(e), str(e)\n    else:\n        assert 0\n    \n    path_out = os.path.normpath(f'{__file__}/../../tests/test_4447.pdf')\n    document.save(path_out)\n\n\ndef test_4755():\n    print()\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4755.pdf')\n    path_out = os.path.normpath(f'{__file__}/../../tests/test_4755_out.pdf')\n    \n    with pymupdf.open(path) as document:\n        for page_i, page in enumerate(document):\n            print(f'{page_i=}')\n            caret = page.add_caret_annot((50,50))\n\n            colours = [\n                    (0, 0, 1),\n                    (0, 1, 0),\n                    (1, 0, 0),\n                    ]\n            for annot_i, annot in enumerate(page.annots()):\n                print(f'{annot_i=}')\n                #if annot_i != 2:\n                #    continue\n                before_rect = copy.deepcopy(annot.rect)\n\n                def draw_rectangle(rect, c, w):\n                    drect = page.add_freetext_annot(rect, str(annot_i), text_color=c)\n                    drect.set_border(width=w)\n                    drect.update()\n\n                colour = colours[annot_i]\n                print(f'{colour=}')\n                draw_rectangle(annot.rect, colour, .3)\n\n                print(f'before: {annot.rect}=')\n                annot.set_rect(annot.rect)\n                print(f' after: {annot.rect}=')\n\n                print(f'difference: {annot.rect-before_rect=}')\n\n                draw_rectangle(annot.rect, (0, 1, 0), .3)\n                print()\n        document.save(path_out)\n        print(f'    {path=}.')\n        print(f'{path_out=}.')\n\n\ndef test_4944():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4944.pdf')\n    path_out = os.path.normpath(f'{__file__}/../../tests/test_4944_out.pdf')\n    print()\n    with pymupdf.open(path) as document:\n        page = document[0]\n        print(f'{page.rotation=}')\n        print(f'{page.rotation_matrix=}')\n        print(f'{page.transformation_matrix=}')\n        text_json = page.get_text('rawjson')\n        #print(text_json)\n        \n        page.add_redact_annot(page.rect)\n        page.apply_redactions(text=pymupdf.PDF_REDACT_TEXT_REMOVE)\n        document.save(path_out)\n        print(repr(page.get_text()))\n        \n        text_json = page.get_text('rawjson')\n        #print(text_json)\n"
  },
  {
    "path": "tests/test_badfonts.py",
    "content": "\"\"\"\nEnsure we can deal with non-Latin font names.\n\"\"\"\nimport os\n\nimport pymupdf\n\n\ndef test_survive_names():\n    scriptdir = os.path.abspath(os.path.dirname(__file__))\n    filename = os.path.join(scriptdir, \"resources\", \"has-bad-fonts.pdf\")\n    doc = pymupdf.open(filename)\n    print(\"File '%s' uses the following fonts on page 0:\" % doc.name)\n    for f in doc.get_page_fonts(0):\n        print(f)\n"
  },
  {
    "path": "tests/test_balance_count.py",
    "content": "import pymupdf\n\n\ndef test_q_count():\n    \"\"\"Testing graphics state balances and wrap_contents().\n\n    Take page's contents and generate various imbalanced graphics state\n    situations. Each time compare q-count with expected results.\n    Finally confirm we are out of balance using \"is_wrapped\", wrap the\n    contents object(s) via \"wrap_contents()\" and confirm success.\n    PDF commands \"q\" / \"Q\" stand for \"push\", respectively \"pop\".\n    \"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    # the page has no /Contents objects at all yet. Create one causing\n    # an initial imbalance (so prepended \"q\" is needed)\n    pymupdf.TOOLS._insert_contents(page, b\"Q\", True)  # append\n    assert page._count_q_balance() == (1, 0)\n    assert page.is_wrapped is False\n\n    # Prepend more data that yield a different type of imbalanced contents:\n    # Although counts of q and Q are equal now, the unshielded 'cm' before\n    # the first 'q' makes the contents unusable for insertions.\n    pymupdf.TOOLS._insert_contents(page, b\"1 0 0 -1 0 0 cm q \", False)  # prepend\n    assert page.is_wrapped is False\n    if page._count_q_balance() == (0, 0):\n        print(\"imbalance undetected by q balance count\")\n\n    text = \"Hello, World!\"\n    page.insert_text((100, 100), text)  # establishes balance!\n\n    # this should have produced a balanced graphics state\n    assert page._count_q_balance() == (0, 0)\n    assert page.is_wrapped\n\n    # an appended \"pop\" must be balanced by a prepended \"push\"\n    pymupdf.TOOLS._insert_contents(page, b\"Q\", True)  # append\n    assert page._count_q_balance() == (1, 0)\n\n    # a prepended \"pop\" yet needs another push\n    pymupdf.TOOLS._insert_contents(page, b\"Q\", False)  # prepend\n    assert page._count_q_balance() == (2, 0)\n\n    # an appended \"push\" needs an additional \"pop\"\n    pymupdf.TOOLS._insert_contents(page, b\"q\", True)  # append\n    assert page._count_q_balance() == (2, 1)\n\n    # wrapping the contents should yield a balanced state again\n    assert page.is_wrapped is False\n    page.wrap_contents()\n    assert page.is_wrapped is True\n    assert page._count_q_balance() == (0, 0)\n"
  },
  {
    "path": "tests/test_barcode.py",
    "content": "import os\n\nimport pymupdf\n\n\ndef test_barcode():\n    path = os.path.normpath(f'{__file__}/../../tests/test_barcode_out.pdf')\n    \n    url = 'http://artifex.com'\n    text_in = '012345678901'\n    text_out = '123456789012'\n    # Create empty document and add a qrcode image.\n    with pymupdf.Document() as document:\n        page = document.new_page()\n        \n        pixmap = pymupdf.mupdf.fz_new_barcode_pixmap(\n                pymupdf.mupdf.FZ_BARCODE_QRCODE,\n                url,\n                512,\n                4,  # ec_level\n                0,  # quiet\n                1,  # hrt\n                )\n        pixmap = pymupdf.Pixmap('raw', pixmap)\n        page.insert_image(\n                (0, 0, 100, 100),\n                pixmap=pixmap,\n                )\n        pixmap = pymupdf.mupdf.fz_new_barcode_pixmap(\n                pymupdf.mupdf.FZ_BARCODE_EAN13,\n                text_in,\n                512,\n                4,  # ec_level\n                0,  # quiet\n                1,  # hrt\n                )\n        pixmap = pymupdf.Pixmap('raw', pixmap)\n        page.insert_image(\n                (0, 200, 100, 300),\n                pixmap=pixmap,\n                )\n        \n        document.save(path)\n    \n    with pymupdf.open(path) as document:\n        page = document[0]\n        for i, ii in enumerate(page.get_images()):\n            xref = ii[0]\n            pixmap = pymupdf.Pixmap(document, xref)\n            hrt, barcode_type = pymupdf.mupdf.fz_decode_barcode_from_pixmap2(\n                    pixmap.this,\n                    0,  # rotate.\n                    )\n            print(f'{hrt=}')\n            if i == 0:\n                assert hrt == url\n            elif i == 1:\n                assert hrt == text_out\n            else:\n                assert 0\n"
  },
  {
    "path": "tests/test_clip_page.py",
    "content": "\"\"\"\nTest Page method clip_to_rect.\n\"\"\"\n\nimport os\nimport pymupdf\n\n\ndef test_clip():\n    \"\"\"\n    Clip a Page to a rectangle and confirm that no text has survived\n    that is completely outside the rectangle..\n    \"\"\"\n    scriptdir = os.path.dirname(os.path.abspath(__file__))\n    rect = pymupdf.Rect(200, 200, 400, 500)\n    filename = os.path.join(scriptdir, \"resources\", \"v110-changes.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    page.clip_to_rect(rect)  # clip the page to the rectangle\n    # capture font warning message of MuPDF\n    if pymupdf.mupdf_version_tuple < (1, 27):\n        assert pymupdf.TOOLS.mupdf_warnings() == \"bogus font ascent/descent values (0 / 0)\"\n    # extract all text characters and assert that each one\n    # has a non-empty intersection with the rectangle.\n    chars = [\n        c\n        for b in page.get_text(\"rawdict\")[\"blocks\"]\n        for l in b[\"lines\"]\n        for s in l[\"spans\"]\n        for c in s[\"chars\"]\n    ]\n    for char in chars:\n        bbox = pymupdf.Rect(char[\"bbox\"])\n        if bbox.is_empty:\n            continue\n        assert bbox.intersects(\n            rect\n        ), f\"Character '{char['c']}' at {bbox} is outside of {rect}.\"\n"
  },
  {
    "path": "tests/test_cluster_drawings.py",
    "content": "import os\nimport pymupdf\n\nscriptdir = os.path.dirname(__file__)\n\n\ndef test_cluster1():\n    \"\"\"Confirm correct identification of known examples.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"Not executing 'test_cluster1' in classic\")\n        return\n    filename = os.path.join(scriptdir, \"resources\", \"symbol-list.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    assert len(page.cluster_drawings()) == 10\n    filename = os.path.join(scriptdir, \"resources\", \"chinese-tables.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    assert len(page.cluster_drawings()) == 2\n\n\ndef test_cluster2():\n    \"\"\"Join disjoint but neighbored drawings.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"Not executing 'test_cluster2' in classic\")\n        return\n    doc = pymupdf.open()\n    page = doc.new_page()\n    r1 = pymupdf.Rect(100, 100, 200, 200)\n    r2 = pymupdf.Rect(203, 203, 400, 400)\n    page.draw_rect(r1)\n    page.draw_rect(r2)\n    assert page.cluster_drawings() == [r1 | r2]\n\n\ndef test_cluster3():\n    \"\"\"Confirm as separate if neighborhood threshold exceeded.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"Not executing 'test_cluster3' in classic\")\n        return\n    doc = pymupdf.open()\n    page = doc.new_page()\n    r1 = pymupdf.Rect(100, 100, 200, 200)\n    r2 = pymupdf.Rect(204, 200, 400, 400)\n    page.draw_rect(r1)\n    page.draw_rect(r2)\n    assert page.cluster_drawings() == [r1, r2]\n\n\ndef test_4599():\n    print()\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4599.pdf')\n    n = 0\n    with pymupdf.open(path) as document:\n        for page in document:\n            for clip in page.cluster_drawings():\n                print(clip)\n                n += 1\n    assert n == 3\n    \n    \n"
  },
  {
    "path": "tests/test_codespell.py",
    "content": "import pymupdf\n\nimport os\nimport platform\nimport shlex\nimport subprocess\nimport sys\nimport textwrap\n\n\ndef test_codespell():\n    '''\n    Check Python code with codespell.\n    '''\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_codespell(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    if platform.system() == 'Windows':\n        # Git commands seem to fail on Github Windows runners.\n        print(f'test_codespell(): Not running on Windows')\n        return\n        \n    root = os.path.abspath(f'{__file__}/../..')\n    \n    # For now we ignore files that we would ideally still look at, because it\n    # is difficult to exclude some text sections.\n    skips = textwrap.dedent('''\n            *.pdf\n            docs/_static/prism/prism.js\n            docs/_static/prism/prism.js\n            docs/locales/ja/LC_MESSAGES/changes.po\n            docs/locales/ja/LC_MESSAGES/recipes-common-issues-and-their-solutions.po\n            docs/locales/\n            src_classic/*\n            ''')\n    skips = skips.strip().replace('\\n', ',')\n    \n    command = textwrap.dedent(f'''\n            cd {root} && codespell\n                --skip {shlex.quote(skips)}\n                --ignore-words-list re-use,flate,thirdparty,re-using\n                --ignore-regex 'https?://[a-z0-9/_.]+'\n                --ignore-multiline-regex 'codespell:ignore-begin.*codespell:ignore-end'\n            ''')\n    \n    import pipcl\n    \n    git_files = pipcl.git_items(root)\n    \n    command_args_path = os.path.normpath(f'{__file__}/../test_codespell_args.txt')\n    command += f'    @{command_args_path}'\n    \n    with open(command_args_path, 'w') as f:\n    \n        for p in git_files:\n            _, ext = os.path.splitext(p)\n            if ext in ('.png', '.pdf', '.jpg', '.svg'):\n                pass\n            else:\n                #command += f'    {p}\\n'\n                print(p, file=f)\n    \n    if platform.system() != 'Windows':\n        command = command.replace('\\n', ' \\\\\\n')\n    if 0:\n        with open(command_args_path) as f:\n            command_args_path_contents = f.read()\n        print(f'command_args_path:{command_args_path_contents}')\n    print(f'Running codespell: {command}')\n    subprocess.run(command, shell=1, check=1)\n    print('test_codespell(): codespell succeeded.')\n"
  },
  {
    "path": "tests/test_crypting.py",
    "content": "\"\"\"\nCheck PDF encryption:\n* make a PDF with owber and user passwords\n* open and decrypt as owner or user\n\"\"\"\nimport pymupdf\n\n\ndef test_encryption():\n    text = \"some secret information\"  # keep this data secret\n    perm = int(\n        pymupdf.PDF_PERM_ACCESSIBILITY  # always use this\n        | pymupdf.PDF_PERM_PRINT  # permit printing\n        | pymupdf.PDF_PERM_COPY  # permit copying\n        | pymupdf.PDF_PERM_ANNOTATE  # permit annotations\n    )\n    owner_pass = \"owner\"  # owner password\n    user_pass = \"user\"  # user password\n    encrypt_meth = pymupdf.PDF_ENCRYPT_AES_256  # strongest algorithm\n    doc = pymupdf.open()  # empty pdf\n    page = doc.new_page()  # empty page\n    page.insert_text((50, 72), text)  # insert the data\n    tobytes = doc.tobytes(\n        encryption=encrypt_meth,  # set the encryption method\n        owner_pw=owner_pass,  # set the owner password\n        user_pw=user_pass,  # set the user password\n        permissions=perm,  # set permissions\n    )\n    doc.close()\n    doc = pymupdf.open(\"pdf\", tobytes)\n    assert doc.needs_pass\n    assert doc.is_encrypted\n    rc = doc.authenticate(\"owner\")\n    assert rc == 4\n    assert not doc.is_encrypted\n    doc.close()\n    doc = pymupdf.open(\"pdf\", tobytes)\n    rc = doc.authenticate(\"user\")\n    assert rc == 2\n"
  },
  {
    "path": "tests/test_docs_samples.py",
    "content": "'''\nTest sample scripts in docs/samples/.\n'''\n\nimport glob\nimport os\nimport pytest\nimport runpy\n\n# We only look at sample scripts that can run standalone (i.e. don't require\n# sys.argv).\n#\nroot = os.path.abspath(f'{__file__}/../..')\nsamples = []\nfor p in glob.glob(f'{root}/docs/samples/*.py'):\n    if os.path.basename(p) in (\n             'make-bold.py',    # Needs sys.argv[1].\n             'multiprocess-gui.py', # GUI.\n             'multiprocess-render.py',  # Needs sys.argv[1].\n             'text-lister.py',  # Needs sys.argv[1].\n            ):\n        print(f'Not testing: {p}')\n    else:\n        p = os.path.relpath(p, root)\n        samples.append(p)\n\ndef _test_all():\n    # Allow runnings tests directly without pytest.\n    import subprocess\n    import sys\n    e = 0\n    for sample in samples:\n        print( f'Running: {sample}', flush=1)\n        try:\n            if 0:\n                # Curiously this fails in an odd way when testing compound\n                # package with $PYTHONPATH set.\n                print( f'os.environ is:')\n                for n, v in os.environ.items():\n                    print( f'    {n}: {v!r}')\n                command = f'{sys.executable} {sample}'\n                print( f'command is: {command!r}')\n                sys.stdout.flush()\n                subprocess.check_call( command, shell=1, text=1)\n            else:\n                runpy.run_path(sample)\n        except Exception:\n            print( f'Failed: {sample}')\n            e += 1\n    if e:\n        raise Exception( f'Errors: {e}')\n\n# We use pytest.mark.parametrize() to run sample scripts via a fn, which\n# ensures that pytest treats each script as a test.\n#\n@pytest.mark.parametrize('sample', samples)\ndef test_docs_samples(sample):\n    sample = f'{root}/{sample}'\n    runpy.run_path(sample)\n"
  },
  {
    "path": "tests/test_drawings.py",
    "content": "\"\"\"\nExtract drawings of a PDF page and compare with stored expected result.\n\"\"\"\n\nimport io\nimport os\nimport sys\nimport pprint\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"symbol-list.pdf\")\nsymbols = os.path.join(scriptdir, \"resources\", \"symbols.txt\")\n\n\ndef test_drawings1():\n    symbols_text = open(symbols).read()  # expected result\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    paths = page.get_cdrawings()\n    out = io.StringIO()  # pprint output goes here\n    pprint.pprint(paths, stream=out)\n    assert symbols_text == out.getvalue()\n\n\ndef test_drawings2():\n    delta = (0, 20, 0, 20)\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    r = pymupdf.Rect(100, 100, 200, 200)\n    page.draw_circle(r.br, 2, color=0)\n    r += delta\n\n    page.draw_line(r.tl, r.br, color=0)\n    r += delta\n\n    page.draw_oval(r, color=0)\n    r += delta\n\n    page.draw_rect(r, color=0)\n    r += delta\n\n    page.draw_quad(r.quad, color=0)\n    r += delta\n\n    page.draw_polyline((r.tl, r.tr, r.br), color=0)\n    r += delta\n\n    page.draw_bezier(r.tl, r.tr, r.br, r.bl, color=0)\n    r += delta\n\n    page.draw_curve(r.tl, r.tr, r.br, color=0)\n    r += delta\n\n    page.draw_squiggle(r.tl, r.br, color=0)\n    r += delta\n\n    rects = [p[\"rect\"] for p in page.get_cdrawings()]\n    bboxes = [b[1] for b in page.get_bboxlog()]\n    for i, r in enumerate(rects):\n        assert pymupdf.Rect(r) in pymupdf.Rect(bboxes[i])\n\n\ndef _dict_difference(a, b):\n    \"\"\"\n    Verifies that dictionaries \"a\", \"b\"\n    * have the same keys and values, except for key \"items\":\n    * the items list of \"a\" must be one shorter but otherwise equal the \"b\" items\n\n    Returns last item of b[\"items\"].\n    \"\"\"\n    assert a.keys() == b.keys()\n    for k in a.keys():\n        v1 = a[k]\n        v2 = b[k]\n        if k != \"items\":\n            assert v1 == v2\n        else:\n            assert v1 == v2[:-1]\n            rc = v2[-1]\n    return rc\n\n\ndef test_drawings3():\n    doc = pymupdf.open()\n    page1 = doc.new_page()\n    shape1 = page1.new_shape()\n    shape1.draw_line((10, 10), (10, 50))\n    shape1.draw_line((10, 50), (100, 100))\n    shape1.finish(closePath=False)\n    shape1.commit()\n    drawings1 = page1.get_drawings()[0]\n\n    page2 = doc.new_page()\n    shape2 = page2.new_shape()\n    shape2.draw_line((10, 10), (10, 50))\n    shape2.draw_line((10, 50), (100, 100))\n    shape2.finish(closePath=True)\n    shape2.commit()\n    drawings2 = page2.get_drawings()[0]\n\n    assert _dict_difference(drawings1, drawings2) == (\"l\", (100, 100), (10, 10))\n\n    page3 = doc.new_page()\n    shape3 = page3.new_shape()\n    shape3.draw_line((10, 10), (10, 50))\n    shape3.draw_line((10, 50), (100, 100))\n    shape3.draw_line((100, 100), (50, 70))\n    shape3.finish(closePath=False)\n    shape3.commit()\n    drawings3 = page3.get_drawings()[0]\n\n    page4 = doc.new_page()\n    shape4 = page4.new_shape()\n    shape4.draw_line((10, 10), (10, 50))\n    shape4.draw_line((10, 50), (100, 100))\n    shape4.draw_line((100, 100), (50, 70))\n    shape4.finish(closePath=True)\n    shape4.commit()\n    drawings4 = page4.get_drawings()[0]\n\n    assert _dict_difference(drawings3, drawings4) == (\"l\", (50, 70), (10, 10))\n\n\ndef test_2365():\n    \"\"\"Draw a filled rectangle on a new page.\n\n    Then extract the page's vector graphics and confirm that only one path\n    was generated which has all the right properties.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = pymupdf.Rect(100, 100, 200, 200)\n    page.draw_rect(\n        rect, color=pymupdf.pdfcolor[\"black\"], fill=pymupdf.pdfcolor[\"yellow\"], width=3\n    )\n    paths = page.get_drawings()\n    assert len(paths) == 1\n    path = paths[0]\n    assert path[\"type\"] == \"fs\"\n    assert path[\"fill\"] == pymupdf.pdfcolor[\"yellow\"]\n    assert path[\"fill_opacity\"] == 1\n    assert path[\"color\"] == pymupdf.pdfcolor[\"black\"]\n    assert path[\"stroke_opacity\"] == 1\n    assert path[\"width\"] == 3\n    assert path[\"rect\"] == rect\n\n\ndef test_2462():\n    \"\"\"\n    Assertion happens, if this code does NOT bring down the interpreter.\n\n    Background:\n    We previously ignored clips for non-vector-graphics. However, ending\n    a clip does not refer back the object(s) that have been clipped.\n    In order to correctly compute the \"scissor\" rectangle, we now keep track\n    of the clipped object type.\n    \"\"\"\n    doc = pymupdf.open(f\"{scriptdir}/resources/test-2462.pdf\")\n    page = doc[0]\n    vg = page.get_drawings(extended=True)\n\n\ndef test_2556():\n    \"\"\"Ensure that incomplete clip paths will be properly ignored.\"\"\"\n    doc = pymupdf.open()  # new empty PDF\n    page = doc.new_page()  # new page\n    # following contains an incomplete clip\n    c = b\"q 50 697.6 400 100.0 re W n q 0 0 m W n Q \"\n    xref = doc.get_new_xref()  # prepare /Contents object for page\n    doc.update_object(xref, \"<<>>\")  # new xref now is a dictionary\n    doc.update_stream(xref, c)  # store drawing commands\n    page.set_contents(xref)  # give the page this xref as /Contents\n    # following will bring down interpreter if fix not installed\n    assert page.get_drawings(extended=True)\n\n\ndef test_3207():\n    \"\"\"Example graphics with multiple \"close path\" commands within same path.\n\n    The fix translates a close-path commands into an additional line\n    which connects the current point with a preceding \"move\" target.\n    The example page has 2 paths which each contain 2 close-path\n    commands after 2 normal \"line\" commands, i.e. 2 command sequences\n    \"move-to, line-to, line-to, close-path\".\n    This is converted into 3 connected lines, where the last end point\n    is connect to the start point of the first line.\n    So, in the sequence of lines / points\n\n    (p0, p1), (p2, p3), (p4, p5), (p6, p7), (p8, p9), (p10, p11)\n\n    point p5 must equal p0, and p11 must equal p6 (for each of the\n    two paths in the example).\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-3207.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    paths = page.get_drawings()\n    assert len(paths) == 2\n\n    path0 = paths[0]\n    items = path0[\"items\"]\n    assert len(items) == 6\n    p0 = items[0][1]\n    p5 = items[2][2]\n    p6 = items[3][1]\n    p11 = items[5][2]\n    assert p0 == p5\n    assert p6 == p11\n\n    path1 = paths[1]\n    items = path1[\"items\"]\n    assert len(items) == 6\n    p0 = items[0][1]\n    p5 = items[2][2]\n    p6 = items[3][1]\n    p11 = items[5][2]\n    assert p0 == p5\n    assert p6 == p11\n\n\ndef test_3591():\n    \"\"\"Confirm correct scaling factor for rotation matrices.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-3591.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    paths = page.get_drawings()\n    for p in paths:\n        assert p[\"width\"] == 15\n\n\ndef test_4954_1():\n    path_out = os.path.normpath(f'{__file__}/../../tests/test_4954_1.pdf')\n    with pymupdf.open() as document:\n        page = document.new_page(width=200, height=200)\n        shape = page.new_shape()\n        shape.draw_line((0, 0), (1, 1))\n        shape.finish(color=(0, 0, 0), width=0.1)\n        shape.commit()\n        content = b'q\\n0.12 0 0 0.12 0 0 cm\\n2 j\\n6 w\\n100 100 m\\n800 100 l\\nS\\nQ\\n'\n        document.update_stream(page.get_contents()[0], content, compress=0)\n        document.save(path_out)\n\n    with pymupdf.open(path_out) as document:\n        d = document[0].get_drawings()[-1]\n        print(f'{d[\"lineJoin\"]=}')  # Expected: 2, Actual: 0.24\n        assert d['lineJoin'] == 2\n\n\ndef test_4954_2():\n    path_out = os.path.normpath(f'{__file__}/../../tests/test_4954_2.pdf')\n    with pymupdf.open() as document:\n        page = document.new_page(width=200, height=200)\n        shape = page.new_shape()\n        shape.draw_line((0, 0), (1, 1))\n        shape.finish(color=(1, 0, 0), width=0.1)\n        shape.commit()\n        content = b'q\\n2 0 0 3 0 0 cm\\n1 w\\n10 10 m\\n90 10 l\\nS\\nQ\\n'\n        document.update_stream(page.get_contents()[0], content, compress=0)\n        document.save(path_out)\n\n    with pymupdf.open(path_out) as document:\n        d = document[0].get_drawings()[-1]\n        print(f'{d[\"width\"]=}')  # Expected: 2.0, Actual: 1.0\n        assert abs(d['width'] - 2.449) < 0.01\n"
  },
  {
    "path": "tests/test_embeddedfiles.py",
    "content": "\"\"\"\nTests for PDF EmbeddedFiles functions.\n\"\"\"\nimport pymupdf\n\n\ndef test_embedded1():\n    doc = pymupdf.open()\n    buffer = b\"123456678790qwexcvnmhofbnmfsdg4589754uiofjkb-\"\n    doc.embfile_add(\n        \"file1\",\n        buffer,\n        filename=\"testfile.txt\",\n        ufilename=\"testfile-u.txt\",\n        desc=\"Description of some sort\",\n    )\n    assert doc.embfile_count() == 1\n    assert doc.embfile_names() == [\"file1\"]\n    assert doc.embfile_info(0)[\"name\"] == \"file1\"\n    doc.embfile_upd(0, filename=\"new-filename.txt\")\n    assert doc.embfile_info(0)[\"filename\"] == \"new-filename.txt\"\n    assert doc.embfile_get(0) == buffer\n    doc.embfile_del(0)\n    assert doc.embfile_count() == 0\n\ndef test_4050():\n    with pymupdf.open() as document:\n        document.embfile_add('test', b'foobar', desc='some text')\n        d = document.embfile_info('test')\n        print(f'{d=}')\n        # Date is non-trivial to test for.\n        del d['creationDate']\n        del d['modDate']\n        assert d == {\n                'name': 'test',\n                'collection': 0,\n                'filename': 'test',\n                'ufilename': 'test',\n                'description': 'some text',\n                'size': 6,\n                'length': 6,\n                }\n            \n"
  },
  {
    "path": "tests/test_extractimage.py",
    "content": "\"\"\"\nExtract images from a PDF file, confirm number of images found.\n\"\"\"\nimport os\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"joined.pdf\")\nknown_image_count = 21\n\n\ndef test_extract_image():\n    doc = pymupdf.open(filename)\n\n    image_count = 1\n    for xref in range(1, doc.xref_length() - 1):\n        if doc.xref_get_key(xref, \"Subtype\")[1] != \"/Image\":\n            continue\n        img = doc.extract_image(xref)\n        if isinstance(img, dict):\n            image_count += 1\n\n    assert image_count == known_image_count  # this number is know about the file\n\ndef test_2348():\n    \n    pdf_path = f'{scriptdir}/test_2348.pdf'\n    document = pymupdf.open()\n    page = document.new_page(width=500, height=842)\n    rect = pymupdf.Rect(20, 20, 480, 820)\n    page.insert_image(rect, filename=f'{scriptdir}/resources/nur-ruhig.jpg')\n    page = document.new_page(width=500, height=842)\n    page.insert_image(rect, filename=f'{scriptdir}/resources/img-transparent.png')\n    document.ez_save(pdf_path)\n    document.close()\n\n    document = pymupdf.open(pdf_path)\n    page = document[0]\n    imlist = page.get_images()\n    image = document.extract_image(imlist[0][0])\n    jpeg_extension = image['ext']\n\n    page = document[1]\n    imlist = page.get_images()\n    image = document.extract_image(imlist[0][0])\n    png_extension = image['ext']\n    \n    print(f'jpeg_extension={jpeg_extension!r} png_extension={png_extension!r}')\n    assert jpeg_extension == 'jpeg'\n    assert png_extension == 'png'\n\ndef test_delete_image():\n\n    doc = pymupdf.open(os.path.abspath(f'{__file__}/../../tests/resources/test_delete_image.pdf'))\n    page = doc[0]\n    xref = page.get_images()[0][0]\n    page.delete_image(xref)\n"
  },
  {
    "path": "tests/test_flake8.py",
    "content": "import pymupdf\n\nimport os\nimport subprocess\nimport sys\n\n\ndef test_flake8():\n    '''\n    Check Python code with flake8.\n    '''\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_flake8(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    ignores = (\n            'E123', # closing bracket does not match indentation of opening bracket's line\n            'E124', # closing bracket does not match visual indentation\n            'E126', # continuation line over-indented for hanging indent\n            'E127', # continuation line over-indented for visual indent\n            'E128', # continuation line under-indented for visual indent\n            'E131', # continuation line unaligned for hanging indent\n            'E201', # whitespace after '('\n            'E203', # whitespace before ':'\n            'E221', # E221 multiple spaces before operator\n            'E225', # missing whitespace around operator\n            'E226', # missing whitespace around arithmetic operator\n            'E231', # missing whitespace after ','\n            'E241', # multiple spaces after ':'\n            'E251', # unexpected spaces around keyword / parameter equals\n            'E252', # missing whitespace around parameter equals\n            'E261', # at least two spaces before inline comment\n            'E265', # block comment should start with '# '\n            'E271', # multiple spaces after keyword\n            'E272', # multiple spaces before keyword\n            'E302', # expected 2 blank lines, found 1\n            'E305', # expected 2 blank lines after class or function definition, found 1\n            'E306', # expected 1 blank line before a nested definition, found 0\n            'E402', # module level import not at top of file\n            'E501', # line too long (80 > 79 characters)\n            'E701', # multiple statements on one line (colon)\n            'E741', # ambiguous variable name 'l'\n            'F541', # f-string is missing placeholders\n            'W293', # blank line contains whitespace\n            'W503', # line break before binary operator\n            'W504', # line break after binary operator\n            'E731', # do not assign a lambda expression, use a def\n            )\n    ignores = ','.join(ignores)\n    root = os.path.abspath(f'{__file__}/../..')\n    def run(command):\n        print(f'test_flake8(): Running: {command}')\n        subprocess.run(command, shell=1, check=1)\n    run(f'flake8 --ignore={ignores} --statistics {root}/src/__init__.py {root}/src/utils.py {root}/src/table.py')\n    print(f'test_flake8(): flake8 succeeded.')\n"
  },
  {
    "path": "tests/test_font.py",
    "content": "\"\"\"\nTests for the Font class.\n\"\"\"\nimport os\nimport platform\nimport pymupdf\nimport subprocess\nimport textwrap\n\nimport util\n\n\ndef test_font1():\n    text = \"PyMuPDF\"\n    font = pymupdf.Font(\"helv\")\n    assert font.name == \"Helvetica\"\n    tl = font.text_length(text, fontsize=20)\n    cl = font.char_lengths(text, fontsize=20)\n    assert len(text) == len(cl)\n    assert abs(sum(cl) - tl) < pymupdf.EPSILON\n    for i in range(len(cl)):\n        assert cl[i] == font.glyph_advance(ord(text[i])) * 20\n    font2 = pymupdf.Font(fontbuffer=font.buffer)\n    codepoints1 = font.valid_codepoints()\n    codepoints2 = font2.valid_codepoints()\n    print('')\n    print(f'{len(codepoints1)=}')\n    print(f'{len(codepoints2)=}')\n    if 0:\n        for i, (ucs1, ucs2) in enumerate(zip(codepoints1, codepoints2)):\n            print(f'    {i}: {ucs1=} {ucs2=} {\"\" if ucs2==ucs2 else \"*\"}')\n    assert font2.valid_codepoints() == font.valid_codepoints()\n    \n    # Also check we can get font's bbox.\n    bbox1 = font.bbox\n    print(f'{bbox1=}')\n    bbox2 = font.this.fz_font_bbox()\n    assert bbox2 == bbox1\n\n\ndef test_font2():\n    \"\"\"Old and new length computation must be the same.\"\"\"\n    font = pymupdf.Font(\"helv\")\n    text = \"PyMuPDF\"\n    assert font.text_length(text) == pymupdf.get_text_length(text)\n\n\ndef test_fontname():\n    \"\"\"Assert a valid PDF fontname.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    assert page.insert_font()  # assert: a valid fontname works!\n    detected = False  # preset indicator\n    try:  # fontname check will fail first - don't need a font at all here\n        page.insert_font(fontname=\"illegal/char\", fontfile=\"unimportant\")\n    except ValueError as e:\n        if str(e).startswith(\"bad fontname chars\"):\n            detected = True  # illegal fontname detected\n    assert detected\n\ndef test_2608():\n    flags = (pymupdf.TEXT_DEHYPHENATE | pymupdf.TEXT_MEDIABOX_CLIP)\n    with pymupdf.open(os.path.abspath(f'{__file__}/../../tests/resources/2201.00069.pdf')) as doc:\n        page = doc[0]\n        blocks = page.get_text_blocks(flags=flags)\n        text = blocks[10][4]\n        with open(os.path.abspath(f'{__file__}/../../tests/test_2608_out'), 'wb') as f:\n            f.write(text.encode('utf8'))\n        path_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_2608_expected')\n        path_expected_1_26 = os.path.normpath(f'{__file__}/../../tests/resources/test_2608_expected_1.26')\n        path_expected_1_28 = os.path.normpath(f'{__file__}/../../tests/resources/test_2608_expected_1.28')\n        if pymupdf.mupdf_version_tuple >= (1, 28):\n            path_expected2 = path_expected_1_28\n        elif pymupdf.mupdf_version_tuple >= (1, 27):\n            path_expected2 = path_expected\n        else:\n            path_expected2 = path_expected_1_26\n        with open(path_expected2, 'rb') as f:\n            expected = f.read().decode('utf8')\n        # Github windows x32 seems to insert \\r characters; maybe something to\n        # do with the Python installation's line endings settings.\n        expected = expected.replace('\\r', '')\n        print(f'test_2608(): {text.encode(\"utf8\")=}')\n        print(f'test_2608(): {expected.encode(\"utf8\")=}')\n        assert text == expected\n\ndef test_fontarchive():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_fontarchive(): not running on Pyodide - we get ValueError: No font code \\'notos\\' found in pymupdf-fonts..')\n        return\n        \n    import subprocess\n    arch = pymupdf.Archive()\n    css = pymupdf.css_for_pymupdf_font(\"notos\", archive=arch, name=\"sans-serif\")\n    print(css)\n    print(arch.entry_list)\n    assert arch.entry_list == \\\n            [\n                {\n                    'fmt': 'tree',\n                    'entries':\n                    [\n                        'notosbo', 'notosbi', 'notosit', 'notos'\n                    ],\n                    'path': None\n                }\n            ]\n\ndef test_load_system_font():\n    trace = list()\n    def font_f(name, bold, italic, needs_exact_metrics):\n        trace.append((name, bold, italic, needs_exact_metrics))\n        #print(f'test_load_system_font():font_f(): Looking for font: {name=} {bold=} {italic=} {needs_exact_metrics=}.')\n        return None\n    def f_cjk(name, ordering, serif):\n        trace.append((name, ordering, serif))\n        #print(f'test_load_system_font():f_cjk(): Looking for font: {name=} {ordering=} {serif=}.')\n        return None\n    def f_fallback(script, language, serif, bold, italic):\n        trace.append((script, language, serif, bold, italic))\n        #print(f'test_load_system_font():f_fallback(): looking for font: {script=} {language=} {serif=} {bold=} {italic=}.')\n        return None\n    pymupdf.mupdf.fz_install_load_system_font_funcs(font_f, f_cjk, f_fallback)\n    f = pymupdf.mupdf.fz_load_system_font(\"some-font-name\", 0, 0, 0)\n    assert trace == [\n            ('some-font-name', 0, 0, 0),\n            ], f'Incorrect {trace=}.'\n    print(f'test_load_system_font(): {f.m_internal=}')\n\n\ndef test_mupdf_subset_fonts2():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/2.pdf')\n    with pymupdf.open(path) as doc:\n        n = len(doc)\n        pages = [i*2 for i in range(n//2)]\n        print(f'{pages=}.')\n        pymupdf.mupdf.pdf_subset_fonts2(pymupdf._as_pdf_document(doc), pages)\n\n\ndef test_3677():\n    pymupdf.TOOLS.set_subset_fontnames(True)\n    try:\n        path = os.path.abspath(f'{__file__}/../../tests/resources/test_3677.pdf')\n        font_names_expected = [\n                'BCDEEE+Aptos',\n                'BCDFEE+Aptos',\n                'BCDGEE+Calibri-Light',\n                'BCDHEE+Calibri-Light',\n                ]\n        font_names = list()\n        with pymupdf.open(path) as document:\n            for page in document:\n                 for block in page.get_text('dict')['blocks']:\n                        if block['type'] == 0:\n                            if 'lines' in block.keys():\n                                for line in block['lines']:\n                                    for span in line['spans']:\n                                        font_name=span['font']\n                                        print(font_name)\n                                        font_names.append(font_name)\n        assert font_names == font_names_expected, f'{font_names=}'\n    finally:\n        pymupdf.TOOLS.set_subset_fontnames(False)\n\n\ndef test_3933():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3933.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        print(f'{len(page.get_fonts())=}')\n    \n        expected = {\n                'BCDEEE+Calibri': 39,\n                'BCDFEE+SwissReSan-Regu':  53,\n                'BCDGEE+SwissReSan-Ital':  20,\n                'BCDHEE+SwissReSan-Bold':  20,\n                'BCDIEE+SwissReSan-Regu':  53,\n                'BCDJEE+Calibri':  39,\n                }\n                \n        for xref, _, _, name, _, _ in page.get_fonts():\n            _, _, _, content = document.extract_font(xref)\n\n            if content:\n                font = pymupdf.Font(fontname=name, fontbuffer=content)\n                supported_symbols = font.valid_codepoints()\n                print(f'Font {name}: {len(supported_symbols)=}.', flush=1)\n                assert len(supported_symbols) == expected.get(name)\n\n\ndef test_3780():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3780.pdf')\n    with pymupdf.open(path) as document:\n        for page_i, page in enumerate(document):\n            for itm in page.get_fonts():\n                buff=document.extract_font(itm[0])[-1]\n                font=pymupdf.Font(fontbuffer=buff)\n                print(f'{page_i=}: xref {itm[0]} {font.name=} {font.ascender=} {font.descender=}.')\n            if page_i == 0:\n                d = page.get_text('dict')\n                #for n, v in d.items():\n                #    print(f'    {n}: {v!r}')\n                for i, block in enumerate(d['blocks']):\n                    print(f'block {i}:')\n                    if block['type'] != 0:\n                        continue\n                    for j, line in enumerate(block['lines']):\n                        print(f'    line {j}:')\n                        for k, span in enumerate(line['spans']):\n                            print(f'        span {k}:')\n                            for n, v in span.items():\n                                print(f'            {n}: {v!r}')\n\n\ndef test_3887():\n    print(f'{pymupdf.version=}')\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3887.pdf')\n    \n    path2 = os.path.normpath(f'{__file__}/../../tests/resources/test_3887.pdf.ez.pdf')\n    with pymupdf.open(path) as document:\n        document.subset_fonts(fallback=False)\n        document.ez_save(path2)\n    \n    with pymupdf.open(path2) as document:\n        text = f\"\\u0391\\u3001\\u0392\\u3001\\u0393\\u3001\\u0394\\u3001\\u0395\\u3001\\u0396\\u3001\\u0397\\u3001\\u0398\\u3001\\u0399\\u3001\\u039a\\u3001\\u039b\\u3001\\u039c\\u3001\\u039d\\u3001\\u039e\\u3001\\u039f\\u3001\\u03a0\\u3001\\u03a1\\u3001\\u03a3\\u3001\\u03a4\\u3001\\u03a5\\u3001\\u03a6\\u3001\\u03a7\\u3001\\u03a8\\u3001\\u03a9\\u3002\\u03b1\\u3001\\u03b2\\u3001\\u03b3\\u3001\\u03b4\\u3001\\u03b5\\u3001\\u03b6\\u3001\\u03b7\\u3001\\u03b8\\u3001\\u03b9\\u3001\\u03ba\\u3001\\u03bb\\u3001\\u03bc\\u3001\\u03bd\\u3001\\u03be\\u3001\\u03bf\\u3001\\u03c0\\u3001\\u03c1\\u3001\\u03c2\\u3001\\u03c4\\u3001\\u03c5\\u3001\\u03c6\\u3001\\u03c7\\u3001\\u03c8\\u3001\\u03c9\\u3002\"\n        page = document[0]\n        chars = [c for b in page.get_text(\"rawdict\",flags=0)[\"blocks\"] for l in b[\"lines\"] for s in l[\"spans\"] for c in s[\"chars\"]]\n        output = [c[\"c\"] for c in chars]\n        print(f'text:\\n    {text}')\n        print(f'output:\\n    {output}')\n        pixmap = page.get_pixmap()\n        path_pixmap = f'{path}.0.png'\n        pixmap.save(path_pixmap)\n        print(f'Have saved to: {path_pixmap=}')\n        assert set(output)==set(text)\n\n\ndef test_4457():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4457(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    print()\n    files = (\n            ('https://github.com/user-attachments/files/20862923/test_4457_a.pdf', 'test_4457_a.pdf', None, 4),\n            ('https://github.com/user-attachments/files/20862922/test_4457_b.pdf', 'test_4457_b.pdf', None, 9),\n            )\n    for url, name, size, rms_old_after_max in files:\n        path = util.download(url, name, size)\n        \n        with pymupdf.open(path) as document:\n            page = document[0]\n            \n            pixmap = document[0].get_pixmap()\n            path_pixmap = f'{path}.png'\n            pixmap.save(path_pixmap)\n            print(f'Have created: {path_pixmap=}')\n            \n            text = page.get_text()\n            path_before = f'{path}.before.pdf'\n            path_after = f'{path}.after.pdf'\n            document.ez_save(path_before, garbage=4)\n            print(f'Have created {path_before=}')\n            \n            document.subset_fonts()\n            document.ez_save(path_after, garbage=4)\n            print(f'Have created {path_after=}')\n        \n        with pymupdf.open(path_before) as document:\n            text_before = document[0].get_text()\n            pixmap_before = document[0].get_pixmap()\n            path_pixmap_before = f'{path_before}.png'\n            pixmap_before.save(path_pixmap_before)\n            print(f'Have created: {path_pixmap_before=}')\n        \n        with pymupdf.open(path_after) as document:\n            text_after = document[0].get_text()\n            pixmap_after = document[0].get_pixmap()\n            path_pixmap_after = f'{path_after}.png'\n            pixmap_after.save(path_pixmap_after)\n            print(f'Have created: {path_pixmap_after=}')\n        \n        import gentle_compare\n        rms_before = gentle_compare.pixmaps_rms(pixmap, pixmap_before)\n        rms_after = gentle_compare.pixmaps_rms(pixmap, pixmap_after)\n        print(f'{rms_before=}')\n        print(f'{rms_after=}')\n        \n        # Create .png file showing differences between <path> and <path_after>.\n        path_pixmap_after_diff = f'{path_after}.diff.png'\n        pixmap_after_diff = gentle_compare.pixmaps_diff(pixmap, pixmap_after)\n        pixmap_after_diff.save(path_pixmap_after_diff)\n        print(f'Have created: {path_pixmap_after_diff}')\n        \n        # Extract text from <path>, <path_before> and <path_after> and write to\n        # files so we can show differences with `diff`.\n        path_text = os.path.normpath(f'{__file__}/../../tests/test_4457.txt')\n        path_text_before = f'{path_text}.before.txt'\n        path_text_after = f'{path_text}.after.txt'\n        with open(path_text, 'w', encoding='utf8') as f:\n            f.write(text)\n        with open(path_text_before, 'w', encoding='utf8') as f:\n            f.write(text_before)\n        with open(path_text_after, 'w', encoding='utf8') as f:\n            f.write(text_after)\n        \n        # Can't write text to stdout on Windows because of encoding errors.\n        if platform.system() != 'Windows':\n            print(f'text:\\n{textwrap.indent(text, \"    \")}')\n            print(f'text_before:\\n{textwrap.indent(text_before, \"    \")}')\n            print(f'text_after:\\n{textwrap.indent(text_after, \"    \")}')\n            print(f'{path_text=}')\n            print(f'{path_text_before=}')\n            print(f'{path_text_after=}')\n        \n            command = f'diff -u {path_text} {path_text_before}'\n            print(f'Running: {command}', flush=1)\n            subprocess.run(command, shell=1)\n            \n            command = f'diff -u {path_text} {path_text_after}'\n            print(f'Running: {command}', flush=1)\n            subprocess.run(command, shell=1)\n        \n        assert text_before == text\n        assert rms_before == 0\n        \n        if pymupdf.mupdf_version_tuple >= (1, 26, 6):\n            assert rms_after == 0\n        else:\n            # As of 2025-05-20 there are some differences in some characters,\n            # e.g. the non-ascii characters in `Philipp Krahenbuhl`.  See\n            # <path_pixmap> and <path_pixmap_after>.\n            assert abs(rms_after - rms_old_after_max) < 2\n    \n    # Avoid test failure caused by mupdf warnings.\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    print(f'{wt=}')\n    if pymupdf.mupdf_version_tuple < (1, 27):\n        assert wt == 'bogus font ascent/descent values (0 / 0)\\n... repeated 5 times...'\n"
  },
  {
    "path": "tests/test_general.py",
    "content": "# encoding utf-8\n\"\"\"\n* Confirm sample doc has no links and no annots.\n* Confirm proper release of file handles via Document.close()\n* Confirm properly raising exceptions in document creation\n\"\"\"\nimport fnmatch\nimport io\nimport json\nimport os\nimport pathlib\nimport pickle\nimport platform\nimport pymupdf\nimport re\nimport shlex\nimport shutil\nimport subprocess\nimport sys\nimport sysconfig\nimport textwrap\nimport time\nimport util\n\nimport gentle_compare\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"001003ED.pdf\")\n\nPy_GIL_DISABLED = sysconfig.get_config_var('Py_GIL_DISABLED')\ntry:\n    gil_enabled = sys._is_gil_enabled()\nexcept AttributeError:\n    gil_enabled = True\nregex_gil_stderr = None\nif Py_GIL_DISABLED and gil_enabled:\n    regex_gil_stderr = '.*The global interpreter lock.*'\n\n\ndef test_haslinks():\n    doc = pymupdf.open(filename)\n    assert doc.has_links() == False\n\n\ndef test_hasannots():\n    doc = pymupdf.open(filename)\n    assert doc.has_annots() == False\n\n\ndef test_haswidgets():\n    doc = pymupdf.open(filename)\n    assert doc.is_form_pdf == False\n\n\ndef test_isrepaired():\n    doc = pymupdf.open(filename)\n    assert doc.is_repaired == False\n    pymupdf.TOOLS.mupdf_warnings()\n\n\ndef test_isdirty():\n    doc = pymupdf.open(filename)\n    assert doc.is_dirty == False\n\n\ndef test_cansaveincrementally():\n    doc = pymupdf.open(filename)\n    assert doc.can_save_incrementally() == True\n\n\ndef test_iswrapped():\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    assert page.is_wrapped\n    if (1, 26, 0) <= pymupdf.mupdf_version_tuple < (1, 27):\n        assert pymupdf.TOOLS.mupdf_warnings() == 'bogus font ascent/descent values (0 / 0)'\n\n\ndef test_wrapcontents():\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    page.wrap_contents()\n    xref = page.get_contents()[0]\n    cont = page.read_contents()\n    doc.update_stream(xref, cont)\n    page.set_contents(xref)\n    assert len(page.get_contents()) == 1\n    page.clean_contents()\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if (1, 26, 0) <= pymupdf.mupdf_version_tuple < (1, 27):\n        assert wt == 'bogus font ascent/descent values (0 / 0)\\nPDF stream Length incorrect'\n    else:\n        assert wt == 'PDF stream Length incorrect'\n\n\ndef test_page_clean_contents():\n    \"\"\"Assert that page contents cleaning actually is invoked.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    # draw two rectangles - will lead to two /Contents objects\n    page.draw_rect((10, 10, 20, 20))\n    page.draw_rect((20, 20, 30, 30))\n    assert len(page.get_contents()) == 2\n    assert page.read_contents().startswith(b\"q\") == False\n\n    # clean / consolidate into one /Contents object\n    page.clean_contents()\n    assert len(page.get_contents()) == 1\n    assert page.read_contents().startswith(b\"q\") == True\n\n\ndef test_annot_clean_contents():\n    \"\"\"Assert that annot contents cleaning actually is invoked.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    annot = page.add_highlight_annot((10, 10, 20, 20))\n\n    # the annotation appearance will not start with command b\"q\"\n\n\n    # invoke appearance stream cleaning and reformatting\n    annot.clean_contents()\n\n    # appearance stream should now indeed start with command b\"q\"\n    assert annot._getAP().startswith(b\"q\") == True\n\n\ndef test_config():\n    assert pymupdf.TOOLS.fitz_config[\"py-memory\"] in (True, False)\n\n\ndef test_glyphnames():\n    name = \"INFINITY\"\n    infinity = pymupdf.glyph_name_to_unicode(name)\n    assert pymupdf.unicode_to_glyph_name(infinity) == name\n\n\ndef test_rgbcodes():\n    sRGB = 0xFFFFFF\n    assert pymupdf.sRGB_to_pdf(sRGB) == (1, 1, 1)\n    assert pymupdf.sRGB_to_rgb(sRGB) == (255, 255, 255)\n\n\ndef test_pdfstring():\n    pymupdf.get_pdf_now()\n    pymupdf.get_pdf_str(\"Beijing, chinesisch 北京\")\n    pymupdf.get_text_length(\"Beijing, chinesisch 北京\", fontname=\"china-s\")\n    pymupdf.get_pdf_str(\"Latin characters êßöäü\")\n\n\ndef test_open_exceptions():\n    path  = os.path.normpath(f'{__file__}/../../tests/resources/001003ED.pdf')\n    doc = pymupdf.open(path, filetype=\"xps\")\n    assert 'PDF' in doc.metadata[\"format\"]\n\n    doc = pymupdf.open(path, filetype=\"xxx\")\n    assert 'PDF' in doc.metadata[\"format\"]\n\n    try:\n        pymupdf.open(\"x.y\")\n    except Exception as e:\n        assert repr(e).startswith(\"FileNotFoundError\")\n    else:\n        assert 0\n\n    try:\n        pymupdf.open(stream=b\"\", filetype=\"pdf\")\n    except RuntimeError as e:\n        assert repr(e).startswith(\"EmptyFileError\"), f'{repr(e)=}'\n    else:\n        print(f'{doc.metadata[\"format\"]=}')\n        assert 0\n\n\ndef test_bug1945():\n    pdf = pymupdf.open(f'{scriptdir}/resources/bug1945.pdf')\n    buffer_ = io.BytesIO()\n    pdf.save(buffer_, clean=True)\n\n\ndef test_bug1971():\n    for _ in range(2):\n        doc = pymupdf.Document(f'{scriptdir}/resources/bug1971.pdf')\n        page = next(doc.pages())\n        page.get_drawings()\n        doc.close()\n        assert doc.is_closed\n\ndef test_default_font():\n    f = pymupdf.Font()\n    assert str(f) == \"Font('Noto Serif Regular')\"\n    assert repr(f) == \"Font('Noto Serif Regular')\"\n\ndef test_add_ink_annot():\n    import math\n    document = pymupdf.Document()\n    page = document.new_page()\n    line1 = []\n    line2 = []\n    for a in range( 0, 360*2, 15):\n        x = a\n        c = 300 + 200 * math.cos( a * math.pi/180)\n        s = 300 + 100 * math.sin( a * math.pi/180)\n        line1.append( (x, c))\n        line2.append( (x, s))\n    page.add_ink_annot( [line1, line2])\n    page.insert_text((100, 72), 'Hello world')\n    page.add_text_annot((200,200), \"Some Text\")\n    page.get_bboxlog()\n    path = f'{scriptdir}/resources/test_add_ink_annot.pdf'\n    document.save( path)\n    print( f'Have saved to: path={path!r}')\n\ndef test_techwriter_append():\n    print(pymupdf.__doc__)\n    doc = pymupdf.open()\n    page = doc.new_page()\n    tw = pymupdf.TextWriter(page.rect)\n    text = \"Red rectangle = TextWriter.text_rect, blue circle = .last_point\"\n    r = tw.append((100, 100), text)\n    print(f'r={r!r}')\n    tw.write_text(page)\n    page.draw_rect(tw.text_rect, color=pymupdf.pdfcolor[\"red\"])\n    page.draw_circle(tw.last_point, 2, color=pymupdf.pdfcolor[\"blue\"])\n    path = f\"{scriptdir}/resources/test_techwriter_append.pdf\"\n    doc.ez_save(path)\n    print( f'Have saved to: {path}')\n\ndef test_opacity():\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    annot1 = page.add_circle_annot((50, 50, 100, 100))\n    annot1.set_colors(fill=(1, 0, 0), stroke=(1, 0, 0))\n    annot1.set_opacity(2 / 3)\n    annot1.update(blend_mode=\"Multiply\")\n\n    annot2 = page.add_circle_annot((75, 75, 125, 125))\n    annot2.set_colors(fill=(0, 0, 1), stroke=(0, 0, 1))\n    annot2.set_opacity(1 / 3)\n    annot2.update(blend_mode=\"Multiply\")\n    outfile = f'{scriptdir}/resources/opacity.pdf'\n    doc.save(outfile, expand=True, pretty=True)\n    print(\"saved\", outfile)\n\ndef test_get_text_dict():\n    import json\n    doc=pymupdf.open(f'{scriptdir}/resources/v110-changes.pdf')\n    page=doc[0]\n    blocks=page.get_text(\"dict\")[\"blocks\"]\n    # Check no opaque types in `blocks`.\n    json.dumps( blocks, indent=4)\n    if (1, 26, 0) <= pymupdf.mupdf_version_tuple < (1, 27):\n        assert pymupdf.TOOLS.mupdf_warnings() == 'bogus font ascent/descent values (0 / 0)'\n\ndef test_font():\n    font = pymupdf.Font()\n    print(repr(font))\n    bbox = font.glyph_bbox( 65)\n    print( f'bbox={bbox!r}')\n\ndef test_insert_font():\n    doc=pymupdf.open(f'{scriptdir}/resources/v110-changes.pdf')\n    page = doc[0]\n    i = page.insert_font()\n    print( f'page.insert_font() => {i}')\n\ndef test_2173():\n    from pymupdf import IRect, Pixmap, CS_RGB, Colorspace\n    for i in range( 100):\n        #print( f'i={i!r}')\n        image = Pixmap(Colorspace(CS_RGB), IRect(0, 0, 13, 37))\n    print( 'test_2173() finished')\n\ndef test_texttrace():\n    import time\n    document = pymupdf.Document( f'{scriptdir}/resources/joined.pdf')\n    t = time.time()\n    for page in document:\n        tt = page.get_texttrace()\n    t = time.time() - t\n    print( f'test_texttrace(): t={t!r}')\n\n    # Repeat, this time writing data to file.\n    import json\n    path = f'{scriptdir}/resources/test_texttrace.txt'\n    print( f'test_texttrace(): Writing to: {path}')\n    with open( path, 'w') as f:\n        for i, page in enumerate(document):\n            tt = page.get_texttrace()\n            print( f'page {i} json:\\n{json.dumps(tt, indent=\"    \")}', file=f)\n\n\ndef test_2533():\n    \"\"\"Assert correct char bbox in page.get_texttrace().\n\n    Search for a unique char on page and confirm that page.get_texttrace()\n    returns the same bbox as the search method.\n    \"\"\"\n    if not pymupdf.g_use_extra:\n        print('Not running test_2533() because use_extra=0 known to fail')\n        return\n    pymupdf.TOOLS.set_small_glyph_heights(True)\n    try:\n        doc = pymupdf.open(os.path.join(scriptdir, \"resources\", \"test_2533.pdf\"))\n        page = doc[0]\n        NEEDLE = \"民\"\n        ord_NEEDLE = ord(NEEDLE)\n        for span in page.get_texttrace():\n            for char in span[\"chars\"]:\n                if char[0] == ord_NEEDLE:\n                    bbox = pymupdf.Rect(char[3])\n                    break\n        bbox2 = page.search_for(NEEDLE)[0]\n        assert bbox2 == bbox, f'{bbox=} {bbox2=} {bbox2-bbox=}.'\n    finally:\n        pymupdf.TOOLS.set_small_glyph_heights(False)\n\n\ndef test_2645():\n    \"\"\"Assert same font size calculation in corner cases.\n    \"\"\"\n    folder = os.path.join(scriptdir, \"resources\")\n    files = (\"test_2645_1.pdf\", \"test_2645_2.pdf\", \"test_2645_3.pdf\")\n    for f in files:\n        doc = pymupdf.open(os.path.join(folder, f))\n        page = doc[0]\n        fontsize0 = page.get_texttrace()[0][\"size\"]\n        fontsize1 = page.get_text(\"dict\", flags=pymupdf.TEXTFLAGS_TEXT)[\"blocks\"][0][\"lines\"][\n            0\n        ][\"spans\"][0][\"size\"]\n        assert abs(fontsize0 - fontsize1) < 1e-5\n\n\ndef test_2506():\n    \"\"\"Ensure expected font size across text writing angles.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    point = pymupdf.Point(100, 300)  # insertion point\n    fontsize = 11  # fontsize\n    text = \"Hello\"  # text\n    angles = (0, 30, 60, 90, 120)  # some angles\n\n    # write text with different angles\n    for angle in angles:\n        page.insert_text(\n            point, text, fontsize=fontsize, morph=(point, pymupdf.Matrix(angle))\n        )\n\n    # ensure correct fontsize for get_texttrace() - forgiving rounding problems\n    for span in page.get_texttrace():\n        print(span[\"dir\"])\n        assert round(span[\"size\"]) == fontsize\n\n    # ensure correct fontsize for get_text() - forgiving rounding problems\n    for block in page.get_text(\"dict\")[\"blocks\"]:\n        for line in block[\"lines\"]:\n            print(line[\"dir\"])\n            for span in line[\"spans\"]:\n                print(span[\"size\"])\n                assert round(span[\"size\"]) == fontsize\n\n\ndef test_2108():\n    doc = pymupdf.open(f'{scriptdir}/resources/test_2108.pdf')\n    page = doc[0]\n    areas = page.search_for(\"{sig}\")\n    rect = areas[0]\n    page.add_redact_annot(rect)\n    page.apply_redactions()\n    text = page.get_text()\n\n    text_expected = b'Frau\\nClaire Dunphy\\nTeststra\\xc3\\x9fe 5\\n12345 Stadt\\nVertragsnummer:  12345\\nSehr geehrte Frau Dunphy,\\nText\\nMit freundlichen Gr\\xc3\\xbc\\xc3\\x9fen\\nTestfirma\\nVertrag:\\n  12345\\nAnsprechpartner:\\nJay Pritchet\\nTelefon:\\n123456\\nE-Mail:\\ntest@test.de\\nDatum:\\n07.12.2022\\n'.decode('utf8')\n\n    if 1:\n        # Verbose info.\n        print(f'test_2108(): text is:\\n{text}')\n        print(f'')\n        print(f'test_2108(): repr(text) is:\\n{text!r}')\n        print(f'')\n        print(f'test_2108(): repr(text.encode(\"utf8\")) is:\\n{text.encode(\"utf8\")!r}')\n        print(f'')\n        print(f'test_2108(): text_expected is:\\n{text_expected}')\n        print(f'')\n        print(f'test_2108(): repr(text_expected) is:\\n{text_expected!r}')\n        print(f'')\n        print(f'test_2108(): repr(text_expected.encode(\"utf8\")) is:\\n{text_expected.encode(\"utf8\")!r}')\n\n        ok1 = (text == text_expected)\n        ok2 = (text.encode(\"utf8\") == text_expected.encode(\"utf8\"))\n        ok3 = (repr(text.encode(\"utf8\")) == repr(text_expected.encode(\"utf8\")))\n\n        print(f'')\n        print(f'ok1={ok1}')\n        print(f'ok2={ok2}')\n        print(f'ok3={ok3}')\n\n        print(f'')\n\n    print(f'{pymupdf.mupdf_version_tuple=}')\n    print('Asserting text==text_expected')\n    assert text == text_expected\n\n\ndef test_2238():\n    filepath = f'{scriptdir}/resources/test2238.pdf'\n    doc = pymupdf.open(filepath)\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    wt_expected = ''\n    wt_expected += 'garbage bytes before version marker\\n'\n    wt_expected += 'syntax error: expected \\'obj\\' keyword (6 0 ?)\\n'\n    wt_expected += 'trying to repair broken xref\\n'\n    wt_expected += 'repairing PDF document'\n    assert wt == wt_expected, f'{wt=}'\n    first_page = doc.load_page(0).get_text('text', clip=pymupdf.INFINITE_RECT())\n    last_page = doc.load_page(-1).get_text('text', clip=pymupdf.INFINITE_RECT())\n\n    print(f'first_page={first_page!r}')\n    print(f'last_page={last_page!r}')\n    assert first_page == 'Hello World\\n'\n    assert last_page == 'Hello World\\n'\n\n    first_page = doc.load_page(0).get_text('text')\n    last_page = doc.load_page(-1).get_text('text')\n\n    print(f'first_page={first_page!r}')\n    print(f'last_page={last_page!r}')\n    assert first_page == 'Hello World\\n'\n    assert last_page == 'Hello World\\n'\n\n\ndef test_2093():\n    if platform.python_implementation() == 'GraalVM':\n        print(f'test_2093(): Not running because slow on GraalVM.')\n        return\n    \n    doc = pymupdf.open(f'{scriptdir}/resources/test2093.pdf')\n\n    def average_color(page):\n        pixmap = page.get_pixmap()\n        p_average = [0] * pixmap.n\n        for y in range(pixmap.height):\n            for x in range(pixmap.width):\n                p = pixmap.pixel(x, y)\n                for i in range(pixmap.n):\n                    p_average[i] += p[i]\n        for i in range(pixmap.n):\n            p_average[i] /= (pixmap.height * pixmap.width)\n        return p_average\n\n    page = doc.load_page(0)\n    pixel_average_before = average_color(page)\n\n    rx=135.123\n    ry=123.56878\n    rw=69.8409\n    rh=9.46397\n\n    x0 = rx\n    y0 = ry\n    x1 = rx + rw\n    y1 = ry + rh\n\n    rect = pymupdf.Rect(x0, y0, x1, y1)\n\n    font = pymupdf.Font(\"Helvetica\")\n    fill_color=(0,0,0)\n    page.add_redact_annot(\n        quad=rect,\n        #text=\"null\",\n        fontname=font.name,\n        fontsize=12,\n        align=pymupdf.TEXT_ALIGN_CENTER,\n        fill=fill_color,\n        text_color=(1,1,1),\n    )\n\n    page.apply_redactions()\n    pixel_average_after = average_color(page)\n\n    print(f'pixel_average_before={pixel_average_before!r}')\n    print(f'pixel_average_after={pixel_average_after!r}')\n\n    # Before this bug was fixed (MuPDF-1.22):\n    #   pixel_average_before=[130.864323120088, 115.23577810900859, 92.9268559996174]\n    #   pixel_average_after=[138.68844553555772, 123.05687162237561, 100.74275056194105]\n    # After fix:\n    #   pixel_average_before=[130.864323120088, 115.23577810900859, 92.9268559996174]\n    #   pixel_average_after=[130.8889209934799, 115.25722751837269, 92.94327384463327]\n    #\n    for i in range(len(pixel_average_before)):\n        diff = pixel_average_before[i] - pixel_average_after[i]\n        assert abs(diff) < 0.1\n\n    out = f'{scriptdir}/resources/test2093-out.pdf'\n    doc.save(out)\n    print(f'Have written to: {out}')\n\n\ndef test_2182():\n    print(f'test_2182() started')\n    doc = pymupdf.open(f'{scriptdir}/resources/test2182.pdf')\n    page = doc[0]\n    for annot in page.annots():\n        print(annot)\n    print(f'test_2182() finished')\n\n\ndef test_2246():\n    \"\"\"\n    Test / confirm identical text positions generated by\n    * page.insert_text()\n    versus\n    * TextWriter.write_text()\n\n    ... under varying situations as follows:\n\n    1. MediaBox does not start at (0, 0)\n    2. CropBox origin is different from that of MediaBox\n    3. Check for all 4 possible page rotations\n\n    The test writes the same text at the same positions using `page.insert_text()`,\n    respectively `TextWriter.write_text()`.\n    Then extracts the text spans and confirms that they all occupy the same bbox.\n    This ensures coincidence of text positions of page.of insert_text()\n    (which is assumed correct) and TextWriter.write_text().\n    \"\"\"\n    def bbox_count(rot):\n        \"\"\"Make a page and insert identical text via different methods.\n\n        Desired page rotation is a parameter. MediaBox and CropBox are chosen\n        to be \"awkward\": MediaBox does not start at (0,0) and CropBox is a\n        true subset of MediaBox.\n        \"\"\"\n        # bboxes of spans on page: same text positions are represented by ONE bbox\n        bboxes = set()\n        doc = pymupdf.open()\n        # prepare a page with desired MediaBox / CropBox peculiarities\n        mediabox = pymupdf.paper_rect(\"letter\")\n        page = doc.new_page(width=mediabox.width, height=mediabox.height)\n        xref = page.xref\n        newmbox = list(map(float, doc.xref_get_key(xref, \"MediaBox\")[1][1:-1].split()))\n        newmbox = pymupdf.Rect(newmbox)\n        mbox = newmbox + (10, 20, 10, 20)\n        cbox = mbox + (10, 10, -10, -10)\n        doc.xref_set_key(xref, \"MediaBox\", \"[%g %g %g %g]\" % tuple(mbox))\n        doc.xref_set_key(xref, \"CrobBox\", \"[%g %g %g %g]\" % tuple(cbox))\n        # set page to desired rotation\n        page.set_rotation(rot)\n        page.insert_text((50, 50), \"Text inserted at (50,50)\")\n        tw = pymupdf.TextWriter(page.rect)\n        tw.append((50, 50), \"Text inserted at (50,50)\")\n        tw.write_text(page)\n        blocks = page.get_text(\"dict\")[\"blocks\"]\n        for b in blocks:\n            for l in b[\"lines\"]:\n                for s in l[\"spans\"]:\n                    # store bbox rounded to 3 decimal places\n                    bboxes.add(pymupdf.Rect(pymupdf.JM_TUPLE3(s[\"bbox\"])))\n        return len(bboxes)  # should be 1!\n\n    # the following tests must all pass\n    assert bbox_count(0) == 1\n    assert bbox_count(90) == 1\n    assert bbox_count(180) == 1\n    assert bbox_count(270) == 1\n\n\ndef test_2430():\n    \"\"\"Confirm that multiple font property checks will not destroy Py_None.\"\"\"\n    font = pymupdf.Font(\"helv\")\n    for i in range(1000):\n        _ = font.flags\n\ndef test_2692():\n    document = pymupdf.Document(f'{scriptdir}/resources/2.pdf')\n    for page in document:\n        pix = page.get_pixmap(clip=pymupdf.Rect(0,0,10,10))\n        dl = page.get_displaylist(annots=True)\n        pix = dl.get_pixmap(\n                matrix=pymupdf.Identity,\n                colorspace=pymupdf.csRGB,\n                alpha=False,\n                clip=pymupdf.Rect(0,0,10,10),\n                )\n        pix = dl.get_pixmap(\n                matrix=pymupdf.Identity,\n                #colorspace=pymupdf.csRGB,\n                alpha=False,\n                clip=pymupdf.Rect(0,0,10,10),\n                )\n    \n\ndef test_2596():\n    \"\"\"Confirm correctly abandoning cache when reloading a page.\"\"\"\n    if platform.python_implementation() == 'GraalVM':\n        print(f'test_2596(): not running on Graal.')\n        return\n    doc = pymupdf.Document(f\"{scriptdir}/resources/test_2596.pdf\")\n    page = doc[0]\n    pix0 = page.get_pixmap()  # render the page\n    _ = doc.tobytes(garbage=3)  # save with garbage collection\n\n    # Note this will invalidate cache content for this page.\n    # Reloading the page now empties the cache, so rendering\n    # will deliver the same pixmap\n    page = doc.reload_page(page)\n    pix1 = page.get_pixmap()\n    assert pix1.samples == pix0.samples\n    if pymupdf.mupdf_version_tuple < (1, 26, 6):\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'too many indirections (possible indirection cycle involving 24 0 R)'\n\n\ndef test_2730():\n    \"\"\"Ensure identical output across text extractions.\"\"\"\n    doc = pymupdf.open(f\"{scriptdir}/resources/test_2730.pdf\")\n    page = doc[0]\n    s1 = set(page.get_text())  # plain text extraction\n    s2 = set(page.get_text(sort=True))  # uses \"blocks\" extraction\n    s3 = set(page.get_textbox(page.rect))\n    assert s1 == s2\n    assert s1 == s3\n\n\ndef test_2553():\n    \"\"\"Ensure identical output across text extractions.\"\"\"\n    verbose = 0\n    doc = pymupdf.open(f\"{scriptdir}/resources/test_2553.pdf\")\n    page = doc[0]\n\n    # extract plain text, build set of all characters\n    list1 = page.get_text()\n    set1 = set(list1)\n\n    # extract text blocks, build set of all characters\n    list2 = page.get_text(sort=True)  # internally uses \"blocks\"\n    set2 = set(list2)\n    \n    # extract textbox content, build set of all characters\n    list3 = page.get_textbox(page.rect)\n    set3 = set(list3)\n    \n    def show(l):\n        ret = f'len={len(l)}\\n'\n        for c in l:\n            cc = ord(c)\n            if (cc >= 32 and cc < 127) or c == '\\n':\n                ret += c\n            else:\n                ret += f' [0x{hex(cc)}]'\n        return ret\n    \n    if verbose:\n        print(f'list1:\\n{show(list1)}')\n        print(f'list2:\\n{show(list2)}')\n        print(f'list3:\\n{show(list3)}')\n    \n    # all sets must be equal\n    assert set1 == set2\n    assert set1 == set3\n\n    # With mupdf later than 1.23.4, this special page contains no invalid\n    # Unicodes.\n    #\n    print(f'Checking no occurrence of 0xFFFD, {pymupdf.mupdf_version_tuple=}.')\n    assert chr(0xFFFD) not in set1\n\ndef test_2553_2():\n    doc = pymupdf.open(f\"{scriptdir}/resources/test_2553-2.pdf\")\n    page = doc[0]\n\n    # extract plain text, ensure that there are no 0xFFFD characters\n    text = page.get_text()\n    assert chr(0xfffd) not in text\n\ndef test_2635():\n    \"\"\"Rendering a page before and after cleaning it should yield the same pixmap.\"\"\"\n    doc = pymupdf.open(f\"{scriptdir}/resources/test_2635.pdf\")\n    page = doc[0]\n    pix1 = page.get_pixmap()  # pixmap before cleaning\n\n    page.clean_contents()  # clean page\n    pix2 = page.get_pixmap()  # pixmap after cleaning\n    assert pix1.samples == pix2.samples  # assert equality\n\n\ndef test_resolve_names():\n    \"\"\"Test PDF name resolution.\"\"\"\n    # guard against wrong PyMuPDF architecture version\n    if not hasattr(pymupdf.Document, \"resolve_names\"):\n        print(\"PyMuPDF version does not support resolving PDF names\")\n        return\n    pickle_in = open(f\"{scriptdir}/resources/cython.pickle\", \"rb\")\n    old_names = pickle.load(pickle_in)\n    doc = pymupdf.open(f\"{scriptdir}/resources/cython.pdf\")\n    new_names = doc.resolve_names()\n    assert new_names == old_names\n\ndef test_2777():\n    document = pymupdf.Document()\n    page = document.new_page()\n    print(page.mediabox.width)\n\ndef test_2710():\n    doc = pymupdf.open(f'{scriptdir}/resources/test_2710.pdf')\n    page = doc.load_page(0)\n    \n    print(f'test_2710(): {page.cropbox=}')\n    print(f'test_2710(): {page.mediabox=}')\n    print(f'test_2710(): {page.rect=}')\n    \n    def numbers_approx_eq(a, b):\n        return abs(a-b) < 0.001\n    def points_approx_eq(a, b):\n        return numbers_approx_eq(a.x, b.x) and numbers_approx_eq(a.y, b.y)\n    def rects_approx_eq(a, b):\n        return points_approx_eq(a.bottom_left, b.bottom_left) and points_approx_eq(a.top_right, b.top_right)\n    def assert_rects_approx_eq(a, b):\n        assert rects_approx_eq(a, b), f'Not nearly identical: {a=} {b=}'\n                \n    blocks = page.get_text('blocks')\n    print(f'test_2710(): {blocks=}')\n    assert len(blocks) == 2\n    block = blocks[1]\n    rect = pymupdf.Rect(block[:4])\n    text = block[4]\n    print(f'test_2710(): {rect=}')\n    print(f'test_2710(): {text=}')\n    assert text == 'Text at left page border\\n'\n    \n    assert_rects_approx_eq(page.cropbox, pymupdf.Rect(30.0, 30.0, 565.3200073242188, 811.9199829101562))\n    assert_rects_approx_eq(page.mediabox, pymupdf.Rect(0.0, 0.0, 595.3200073242188, 841.9199829101562))\n    print(f'test_2710(): {pymupdf.mupdf_version_tuple=}')\n    # 2023-11-05: Currently broken in mupdf master.\n    print(f'test_2710(): Not Checking page.rect and rect.')\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt == (\n            \"syntax error: cannot find ExtGState resource 'GS7'\\n\"\n            \"syntax error: cannot find ExtGState resource 'GS8'\\n\"\n            \"encountered syntax errors; page may not be correct\"\n            )\n\n\ndef test_2736():\n    \"\"\"Check handling of CropBox changes vis-a-vis a MediaBox with\n       negative coordinates.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    # fake a MediaBox for demo purposes\n    doc.xref_set_key(page.xref, \"MediaBox\", \"[-30 -20 595 842]\")\n\n    assert page.cropbox == pymupdf.Rect(-30, 0, 595, 862)\n    assert page.rect == pymupdf.Rect(0, 0, 625, 862)\n\n    # change the CropBox: shift by (10, 10) in both dimensions. Please note:\n    # To achieve this, 10 must be subtracted from 862! yo must never be negative!\n    page.set_cropbox(pymupdf.Rect(-20, 0, 595, 852))\n\n    # get CropBox from the page definition\n    assert doc.xref_get_key(page.xref, \"CropBox\")[1] == \"[-20 -10 595 842]\"\n    assert page.rect == pymupdf.Rect(0, 0, 615, 852)\n\n    error = False\n    text = \"\"\n    try:  # check error detection\n        page.set_cropbox((-35, -10, 595, 842))\n    except Exception as e:\n        text = str(e)\n        error = True\n    assert error == True\n    assert text == \"CropBox not in MediaBox\"\n\n\ndef test_subset_fonts():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_subset_fonts(): not running on Pyodide - ValueError: No font code \\'ubuntu\\' found in pymupdf-fonts.')\n        return\n    \"\"\"Confirm subset_fonts is working.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"Not testing 'test_subset_fonts' in classic.\")\n        return\n    text = \"Just some arbitrary text.\"\n    arch = pymupdf.Archive()\n    css = pymupdf.css_for_pymupdf_font(\"ubuntu\", archive=arch)\n    css += \"* {font-family: ubuntu;}\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    page.insert_htmlbox(page.rect, text, css=css, archive=arch)\n    doc.subset_fonts(verbose=True)\n    found = False\n    for xref in range(1, doc.xref_length()):\n        if \"+Ubuntu#20Regular\" in doc.xref_object(xref):\n            found = True\n            break\n    assert found is True\n\n\ndef test_2957_1():\n    \"\"\"Text following a redaction must not change coordinates.\"\"\"\n    # test file with redactions\n    doc = pymupdf.open(os.path.join(scriptdir, \"resources\", \"test_2957_1.pdf\"))\n    page = doc[0]\n    # search for string that must not move by redactions\n    rects0 = page.search_for(\"6e9f73dfb4384a2b8af6ebba\")\n    # sort rectangles vertically\n    rects0 = sorted(rects0, key=lambda r: r.y1)\n    assert len(rects0) == 2  # must be 2 redactions\n    page.apply_redactions()\n\n    # reload page to finalize updates\n    page = doc.reload_page(page)\n\n    # the two string must retain their positions (except rounding errors)\n    rects1 = page.search_for(\"6e9f73dfb4384a2b8af6ebba\")\n    rects1 = sorted(rects1, key=lambda r: r.y1)\n\n    assert page.first_annot is None  # make sure annotations have disappeared\n    for i in range(2):\n        r0 = rects0[i].irect  # take rounded rects\n        r1 = rects1[i].irect\n        assert r0 == r1\n\n\ndef test_2957_2():\n    \"\"\"Redacted text must not change positions of remaining text.\"\"\"\n    doc = pymupdf.open(os.path.join(scriptdir, \"resources\", \"test_2957_2.pdf\"))\n    page = doc[0]\n    words0 = page.get_text(\"words\")  # all words before redacting\n    page.apply_redactions()  # remove/redact the word \"longer\"\n    words1 = page.get_text(\"words\")  # extract words again\n    assert len(words1) == len(words0) - 1  # must be one word less\n    assert words0[3][4] == \"longer\"  # just confirm test file is correct one\n    del words0[3]  # remove the redacted word from first list\n    for i in range(len(words1)):  # compare words\n        w1 = words1[i]  # word after redaction\n        bbox1 = pymupdf.Rect(w1[:4]).irect  # its IRect coordinates\n        w0 = words0[i]  # word before redaction\n        bbox0 = pymupdf.Rect(w0[:4]).irect  # its IRect coordinates\n        assert bbox0 == bbox1  # must be same coordinates\n\n\ndef test_707560():\n    \"\"\"https://bugs.ghostscript.com/show_bug.cgi?id=707560\n    Ensure that redactions also remove characters with an empty width bbox.\n    \"\"\"\n    # Make text that will contain characters with an empty bbox.\n\n    greetings = (\n        \"Hello, World!\",  # english\n        \"Hallo, Welt!\",  # german\n        \"سلام دنیا!\",  # persian\n        \"வணக்கம், உலகம்!\",  # tamil\n        \"สวัสดีชาวโลก!\",  # thai\n        \"Привіт Світ!\",  # ucranian\n        \"שלום עולם!\",  # hebrew\n        \"ওহে বিশ্ব!\",  # bengali\n        \"你好世界！\",  # chinese\n        \"こんにちは世界！\",  # japanese\n        \"안녕하세요, 월드!\",  # korean\n        \"नमस्कार, विश्व !\",  # sanskrit\n        \"हैलो वर्ल्ड!\",  # hindi\n    )\n    text = \" ... \".join([g for g in greetings])\n    where = (50, 50, 400, 500)\n    story = pymupdf.Story(text)\n    bio = io.BytesIO()\n    writer = pymupdf.DocumentWriter(bio)\n    more = True\n    while more:\n        dev = writer.begin_page(pymupdf.paper_rect(\"a4\"))\n        more, _ = story.place(where)\n        story.draw(dev)\n        writer.end_page()\n    writer.close()\n    doc = pymupdf.open(\"pdf\", bio)\n    page = doc[0]\n    text = page.get_text()\n    assert text, \"Unexpected: test page has no text.\"\n    page.add_redact_annot(page.rect)\n    page.apply_redactions()\n    assert not page.get_text(), \"Unexpected: text not fully redacted.\"\n\n\ndef test_3070():\n    with pymupdf.open(os.path.abspath(f'{__file__}/../../tests/resources/test_3070.pdf')) as pdf:\n      links = pdf[0].get_links()\n      links[0]['uri'] = \"https://www.ddg.gg\"\n      pdf[0].update_link(links[0])\n      pdf.save(os.path.abspath(f'{__file__}/../../tests/test_3070_out.pdf'))\n\ndef test_bboxlog_2885():\n    doc = pymupdf.open(os.path.abspath(f'{__file__}/../../tests/resources/test_2885.pdf'))\n    page=doc[0]\n    \n    bbl = page.get_bboxlog()\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if pymupdf.mupdf_version_tuple >= (1, 28):\n        assert wt == ''\n    else:\n        assert wt == 'invalid marked content and clip nesting'\n    \n    bbl = page.get_bboxlog(layers=True)\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if pymupdf.mupdf_version_tuple >= (1, 28):\n        assert wt == ''\n    else:\n        assert wt == 'invalid marked content and clip nesting'\n\ndef test_3081():\n    '''\n    Check Document.close() closes file handles, even if a Page instance exists.\n    '''\n    path1 = os.path.abspath(f'{__file__}/../../tests/resources/1.pdf')\n    path2 = os.path.abspath(f'{__file__}/../../tests/test_3081-2.pdf')\n    \n    import shutil\n    import sys\n    import traceback\n    shutil.copy2(path1, path2)\n    \n    # Find next two available fds.\n    next_fd_1 = os.open(path2, os.O_RDONLY)\n    next_fd_2 = os.open(path2, os.O_RDONLY)\n    os.close(next_fd_1)\n    os.close(next_fd_2)\n\n    def next_fd():\n        fd = os.open(path2, os.O_RDONLY)\n        os.close(fd)\n        return fd\n    \n    fd1 = next_fd()\n    document = pymupdf.open(path2)\n    page = document[0]\n    fd2 = next_fd()\n    document.close()\n    assert document.this is None\n    assert page.this is None\n    try:\n        document.page_count()\n    except Exception as e:\n        print(f'Received expected exception: {e}')\n        #traceback.print_exc(file=sys.stdout)\n        assert str(e) == 'document closed'\n    else:\n        assert 0, 'Did not receive expected exception.'\n    fd3 = next_fd()\n    try:\n        page.bound()\n    except Exception as e:\n        print(f'Received expected exception: {e}')\n        #traceback.print_exc(file=sys.stdout)\n        assert str(e) == 'page is None'\n    else:\n        assert 0, 'Did not receive expected exception.'\n    page = None\n    fd4 = next_fd()\n    print(f'{next_fd_1=} {next_fd_2=}')\n    print(f'{fd1=} {fd2=} {fd3=} {fd4=}')\n    print(f'{document=}')\n    assert fd1 == next_fd_1\n    assert fd2 == next_fd_2 # Checks document only uses one fd.\n    assert fd3 == next_fd_1 # Checks no leaked fds after document close.\n    assert fd4 == next_fd_1 # Checks no leaked fds after failed page access.\n\ndef test_xml():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/2.pdf')\n    with pymupdf.open(path) as document:\n        document.get_xml_metadata()\n\ndef test_3112_set_xml_metadata():\n    document = pymupdf.Document()\n    document.set_xml_metadata('hello world')\n\ndef test_archive_3126():\n    p = os.path.abspath(f'{__file__}/../../tests/resources')\n    p = pathlib.Path(p)\n    archive = pymupdf.Archive(p)\n    \ndef test_3140():\n    css2 = ''\n    path = os.path.abspath(f'{__file__}/../../tests/resources/2.pdf')\n    oldfile = os.path.abspath(f'{__file__}/../../tests/test_3140_old.pdf')\n    newfile = os.path.abspath(f'{__file__}/../../tests/test_3140_new.pdf')\n    import shutil\n    shutil.copy2(path, oldfile)\n    def next_fd():\n        fd = os.open(path, os.O_RDONLY)\n        os.close(fd)\n        return fd\n    fd1 = next_fd()\n    with pymupdf.open(oldfile) as doc:  # open document\n        page = doc[0]\n        rect = pymupdf.Rect(130, 400, 430, 600)\n        CELLS = pymupdf.make_table(rect, cols=3, rows=5)\n        shape = page.new_shape()  # create Shape\n        for i in range(5):\n            for j in range(3):\n                qtext = \"<b>\" + \"Ques #\" + str(i*3+j+1) + \": \" + \"</b>\" # codespell:ignore\n                atext = \"<b>\" + \"Ans:\" + \"</b>\" # codespell:ignore\n                qtext = qtext + '<br>' + atext\n                shape.draw_rect(CELLS[i][j])  # draw rectangle\n                page.insert_htmlbox(CELLS[i][j], qtext, css=css2, scale_low=0)\n        shape.finish(width=2.5, color=pymupdf.pdfcolor[\"blue\"], )\n        shape.commit()  # write all stuff to the page\n        doc.subset_fonts()\n        doc.ez_save(newfile)\n    fd2 = next_fd()\n    assert fd2 == fd1, f'{fd1=} {fd2=}'\n    os.remove(oldfile)\n\ndef test_cli():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_cli(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    import subprocess\n    subprocess.run(f'pymupdf -h', shell=1, check=1)\n\n\ndef check_lines(expected_regexes, actual):\n    '''\n    Checks lines in <actual> match regexes in <expected_regexes>.\n    '''\n    print(f'### check_lines():', flush=1)\n    def str_to_list(s):\n        if s is None:\n            return list()\n        if isinstance(s, str):\n            return s.split('\\n') if s else list()\n        return s\n    expected_regexes = str_to_list(expected_regexes)\n    actual = str_to_list(actual)\n    if expected_regexes and expected_regexes[-1]:\n        expected_regexes.append('') # Always expect a trailing empty line.\n    # Remove `None` regexes and make all regexes match entire lines.\n    expected_regexes = [f'^{i}$' for i in expected_regexes if i is not None]\n    \n    print(f'expected_regexes ({len(expected_regexes)}):')\n    for i in expected_regexes:\n        print(f'    {i!r}')\n    \n    print(f'actual ({len(actual)}):')\n    for i in actual:\n        print(f'    {i!r}')\n    \n    i_expected = 0\n    i_actual = 0\n    while 1:\n        if i_expected == len(expected_regexes) and i_actual == len(actual):\n            break\n        print(f'expected {i_expected+1}/{len(expected_regexes)}')\n        print(f'actual {i_actual+1}/{len(actual)}')\n        assert i_expected < len(expected_regexes) and i_actual < len(actual)\n        expected_regex_line = expected_regexes[i_expected]\n        actual_line = actual[i_actual]\n        if expected_regex_line is None:\n            i_expected += 1\n            continue\n        print(f'    expected_regex: {expected_regex_line!r}', flush=1)\n        print(f'    actual:         {actual!r}', flush=1)\n        match = re.match(expected_regex_line, actual_line)\n        print(f'    {match=}')\n        assert match\n        i_expected += 1\n        i_actual += 1\n    assert len(expected_regexes) == len(actual), \\\n            f'expected/actual lines mismatch: {len(expected_regexes)=} {len(actual)=}.'\n\ndef test_cli_out():\n    '''\n    Check redirection of messages and log diagnostics with environment\n    variables PYMUPDF_LOG and PYMUPDF_MESSAGE.\n    '''\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_cli_out(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    import platform\n    import re\n    import subprocess\n    import pipcl\n    log_prefix = None\n    if os.environ.get('PYMUPDF_USE_EXTRA') == '0':\n        log_prefix = f'.+Using non-default setting from PYMUPDF_USE_EXTRA: \\'0\\''\n    \n    pipcl.show_system()\n    def check(\n            expect_out,\n            expect_err,\n            message=None,\n            log=None,\n            ):\n        '''\n        Sets PYMUPDF_MESSAGE to `message` and PYMUPDF_LOG to `log`, runs\n        `pymupdf internal`, and checks lines stdout and stderr match regexes in\n        `expect_out` and `expect_err`. Note that we enclose regexes in `^...$`.\n        '''\n        env = dict()\n        if log:\n            env['PYMUPDF_LOG'] = log\n        if message:\n            env['PYMUPDF_MESSAGE'] = message\n        command = 'pymupdf internal'\n        print(f'Running: {command}', flush=1)\n        if env:\n            print(f'with:')\n            for key in sorted(env.keys()):\n                print(f'    {key}={shlex.quote(env[key])}')\n        env = os.environ | env\n        cp = subprocess.run(command, shell=1, check=1, capture_output=1, env=env, text=True)\n        \n        check_lines(expect_out, cp.stdout)\n        check_lines(expect_err, cp.stderr)\n    \n    print(f'test_cli_out(): {Py_GIL_DISABLED=}')\n    print(f'test_cli_out(): {gil_enabled=}')\n    \n    print(f'Checking default, all output to stdout.')\n    regex_gil_stderr = None\n    if Py_GIL_DISABLED and gil_enabled:\n        regex_gil_stderr = '.*The global interpreter lock.*'\n    check(\n            [\n                log_prefix,\n                'This is from PyMuPDF message[(][)][.]',\n                '.+This is from PyMuPDF log[(][)].',\n            ],\n            regex_gil_stderr,\n            )\n    \n    #\n    if platform.system() != 'Windows':\n        print(f'Checking redirection of everything to /dev/null.')\n        check('', regex_gil_stderr, 'path:/dev/null', 'path:/dev/null')\n    \n    #\n    print(f'Checking redirection to files.')\n    path_out = os.path.abspath(f'{__file__}/../../tests/test_cli_out.out')\n    path_err = os.path.abspath(f'{__file__}/../../tests/test_cli_out.err')\n    check('', regex_gil_stderr, f'path:{path_out}', f'path:{path_err}')\n    def read(path):\n        with open(path) as f:\n            return f.read()\n    out = read(path_out)\n    err = read(path_err)\n    check_lines(['This is from PyMuPDF message[(][)][.]'], out)\n    check_lines([log_prefix, '.+This is from PyMuPDF log[(][)][.]'], err)\n    \n    #\n    print(f'Checking redirection to fds.')\n    check(\n            [\n                'This is from PyMuPDF message[(][)][.]',\n            ],\n            [\n                regex_gil_stderr,\n                log_prefix,\n                '.+This is from PyMuPDF log[(][)].',\n            ],\n            'fd:1',\n            'fd:2',\n            )\n\n\ndef test_use_python_logging():\n    '''\n    Checks pymupdf.use_python_logging().\n    '''\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_cli(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    log_prefix = None\n    if os.environ.get('PYMUPDF_USE_EXTRA') == '0':\n        log_prefix = f'.+Using non-default setting from PYMUPDF_USE_EXTRA: \\'0\\''\n    \n    if os.path.basename(__file__).startswith(f'test_fitz_'):\n        # Do nothing, because command `pymupdf` outputs diagnostics containing\n        # `pymupdf` which are not renamed to `fitz`, which breaks our checking.\n        print(f'Not testing with fitz alias.')\n        return\n    \n    def check(\n            code,\n            regexes_stdout,\n            regexes_stderr,\n            env = None,\n            ):\n        code = textwrap.dedent(code)\n        path = os.path.abspath(f'{__file__}/../../tests/resources_test_logging.py')\n        with open(path, 'w') as f:\n            f.write(code)\n        command = f'{sys.executable} {path}'\n        if env:\n            print(f'{env=}.')\n            env = os.environ | env\n        print(f'Running: {command}', flush=1)\n        try:\n            cp = subprocess.run(command, shell=1, check=1, capture_output=1, text=True, env=env)\n        except Exception as e:\n            print(f'Command failed: {command}.', flush=1)\n            print(f'Stdout\\n{textwrap.indent(e.stdout, \"    \")}', flush=1)\n            print(f'Stderr\\n{textwrap.indent(e.stderr, \"    \")}', flush=1)\n            raise\n        check_lines(regexes_stdout, cp.stdout)\n        check_lines(regexes_stderr, cp.stderr)\n    \n    print(f'## Basic use of `logging` sends output to stderr instead of default stdout.')\n    check(\n            '''\n            import pymupdf\n            pymupdf.message('this is pymupdf.message()')\n            pymupdf.log('this is pymupdf.log()')\n            pymupdf.set_messages(pylogging=1)\n            pymupdf.set_log(pylogging=1)\n            pymupdf.message('this is pymupdf.message() 2')\n            pymupdf.log('this is pymupdf.log() 2')\n            ''',\n            [\n                log_prefix,\n                'this is pymupdf.message[(][)]',\n                '.+this is pymupdf.log[(][)]',\n            ],\n            [\n                regex_gil_stderr,\n                'this is pymupdf.message[(][)] 2',\n                '.+this is pymupdf.log[(][)] 2',\n            ],\n            )\n    \n    print(f'## Calling logging.basicConfig() makes logging output contain <LEVEL>:<name> prefixes.')\n    check(\n            '''\n            import pymupdf\n            \n            import logging\n            logging.basicConfig()\n            pymupdf.set_messages(pylogging=1)\n            pymupdf.set_log(pylogging=1)\n            \n            pymupdf.message('this is pymupdf.message()')\n            pymupdf.log('this is pymupdf.log()')\n            ''',\n            [\n                log_prefix,\n            ],\n            [\n                regex_gil_stderr,\n                'WARNING:pymupdf:this is pymupdf.message[(][)]',\n                'WARNING:pymupdf:.+this is pymupdf.log[(][)]',\n            ],\n            )\n    \n    print(f'## Setting PYMUPDF_USE_PYTHON_LOGGING=1 makes PyMuPDF use logging on startup.')\n    check(\n            '''\n            import pymupdf\n            pymupdf.message('this is pymupdf.message()')\n            pymupdf.log('this is pymupdf.log()')\n            ''',\n            '',\n            [\n                regex_gil_stderr,\n                log_prefix,\n                'this is pymupdf.message[(][)]',\n                '.+this is pymupdf.log[(][)]',\n            ],\n            env = dict(\n                    PYMUPDF_MESSAGE='logging:',\n                    PYMUPDF_LOG='logging:',\n                    ),\n            )\n    \n    print(f'## Pass explicit logger to pymupdf.use_python_logging() with logging.basicConfig().')\n    check(\n            '''\n            import pymupdf\n            \n            import logging\n            logging.basicConfig()\n            \n            logger = logging.getLogger('foo')\n            pymupdf.set_messages(pylogging_logger=logger, pylogging_level=logging.WARNING)\n            pymupdf.set_log(pylogging_logger=logger, pylogging_level=logging.ERROR)\n            \n            pymupdf.message('this is pymupdf.message()')\n            pymupdf.log('this is pymupdf.log()')\n            ''',\n            [\n                log_prefix,\n            ],\n            [\n                regex_gil_stderr,\n                log_prefix,\n                'WARNING:foo:this is pymupdf.message[(][)]',\n                'ERROR:foo:.+this is pymupdf.log[(][)]',\n            ],\n            )\n    \n    print(f'## Check pymupdf.set_messages() pylogging_level args.')\n    check(\n            '''\n            import pymupdf\n            \n            import logging\n            logging.basicConfig(level=logging.DEBUG)\n            logger = logging.getLogger('pymupdf')\n            \n            pymupdf.set_messages(pylogging_level=logging.CRITICAL)\n            pymupdf.set_log(pylogging_level=logging.INFO)\n            \n            pymupdf.message('this is pymupdf.message()')\n            pymupdf.log('this is pymupdf.log()')\n            ''',\n            [\n                log_prefix,\n            ],\n            [\n                regex_gil_stderr,\n                log_prefix,\n                'CRITICAL:pymupdf:this is pymupdf.message[(][)]',\n                'INFO:pymupdf:.+this is pymupdf.log[(][)]',\n            ],\n            )\n    \n    print(f'## Check messages() with sys.stdout=None.')\n    check(\n            '''\n            import sys\n            sys.stdout = None\n            import pymupdf\n            \n            pymupdf.message('this is pymupdf.message()')\n            pymupdf.log('this is pymupdf.log()')\n            ''',\n            [],\n            [\n                regex_gil_stderr,\n            ],\n            )\n    \n\ndef relpath(path, start=None):\n    '''\n    A 'safe' alternative to os.path.relpath(). Avoids an exception on Windows\n    if the drive needs to change - in this case we use os.path.abspath().\n    '''\n    try:\n        return os.path.relpath(path, start)\n    except ValueError:\n        # os.path.relpath() fails if trying to change drives.\n        assert platform.system() == 'Windows'\n        return os.path.abspath(path)\n\n\ndef test_open():\n\n    import re\n    import textwrap\n    import traceback\n    \n    resources = relpath(os.path.abspath(f'{__file__}/../../tests/resources'))\n    \n    # We convert all strings to use `/` instead of os.sep, which avoids\n    # problems with regex's on windows.\n    resources = resources.replace(os.sep, '/')\n    \n    def check(filename=None, stream=None, filetype=None, exception=None):\n        '''\n        Checks we receive expected exception if specified.\n        '''\n        if isinstance(filename, str):\n            filename = filename.replace(os.sep, '/')\n        if exception:\n            etype, eregex = exception\n            if isinstance(eregex, (tuple, list)):\n                # Treat as sequence of regexes to look for.\n                eregex = '.*'.join(eregex)\n            try:\n                pymupdf.open(filename=filename, stream=stream, filetype=filetype)\n            except etype as e:\n                text = traceback.format_exc(limit=0)\n                text = text.replace(os.sep, '/')\n                text = textwrap.indent(text, '    ', lambda line: 1)\n                assert re.search(eregex, text, re.DOTALL), \\\n                        f'Incorrect exception text, expected {eregex=}, received:\\n{text}'\n                print(f'Received expected exception for {filename=} {stream=} {filetype=}:\\n{text}')\n            except Exception as e:\n                assert 0, \\\n                        f'Incorrect exception, expected {etype}, received {type(e)=}.'\n            else:\n                assert 0, f'Did not received exception, expected {etype=}. {filename=} {stream=} {filetype=} {exception=}'\n        else:\n            document = pymupdf.open(filename=filename, stream=stream, filetype=filetype)\n            return document\n    \n    check(f'{resources}/1.pdf')\n    \n    check(f'{resources}/Bezier.epub')\n    \n    path = 1234\n    etype = TypeError\n    eregex = re.escape(f'bad filename: type(filename)=<class \\'int\\'> filename={path}.')\n    check(path, exception=(etype, eregex))\n    \n    path = 'test_open-this-file-will-not-exist'\n    etype = pymupdf.FileNotFoundError\n    eregex = f'no such file: \\'{path}\\''\n    check(path, exception=(etype, eregex))\n    \n    path = resources\n    etype = pymupdf.FileDataError\n    eregex = re.escape(f'\\'{path}\\' is no file')\n    check(path, exception=(etype, eregex))\n    \n    path = relpath(os.path.abspath(f'{resources}/../test_open_empty'))\n    path = path.replace(os.sep, '/')\n    with open(path, 'w') as f:\n        pass\n    etype = pymupdf.EmptyFileError\n    eregex = re.escape(f'Cannot open empty file: filename={path!r}.')\n    check(path, exception=(etype, eregex))\n    \n    path = f'{resources}/1.pdf'\n    filetype = 'xps'\n    etype = pymupdf.FileDataError\n    # 2023-12-12: On OpenBSD, for some reason the SWIG catch code only catches\n    # the exception as FzErrorBase.\n    etype2 = 'FzErrorBase' if platform.system() == 'OpenBSD' else 'FzErrorFormat'\n    eregex = (\n            # With a sysinstall with separate MuPDF install, we get\n            # `mupdf.FzErrorFormat` instead of `pymupdf.mupdf.FzErrorFormat`. So\n            # we just search for the former.\n            re.escape(f'mupdf.{etype2}: code=7: cannot recognize zip archive'),\n            re.escape(f'pymupdf.FileDataError: Failed to open file {path!r} as type {filetype!r}.'),\n            )\n    check(path, filetype=filetype, exception=None)\n    \n    path = f'{resources}/chinese-tables.pickle'\n    etype = pymupdf.FileDataError\n    etype2 = 'FzErrorBase' if platform.system() == 'OpenBSD' else 'FzErrorUnsupported'\n    etext = (\n            re.escape(f'mupdf.{etype2}: code=6: cannot find document handler for file: {path}'),\n            re.escape(f'pymupdf.FileDataError: Failed to open file {path!r}.'),\n            )\n    check(path, exception=(etype, etext))\n    \n    stream = 123\n    etype = TypeError\n    etext = re.escape('bad stream: type(stream)=<class \\'int\\'>.')\n    check(stream=stream, exception=(etype, etext))\n    \n    check(stream=b'', exception=(pymupdf.EmptyFileError, re.escape('Cannot open empty stream.')))\n\n\ndef test_open2():\n    '''\n    Checks behaviour of fz_open_document() and fz_open_document_with_stream()\n    with different filenames/magic values.\n    '''\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_open2(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    if platform.system() == 'Windows':\n        print(f'test_open2(): not running on Windows because `git ls-files` known fail on Github Windows runners.')\n        return\n    \n    root = os.path.normpath(f'{__file__}/../..')\n    root = relpath(root)\n    \n    # Find tests/resources/test_open2.* input files/streams. We calculate\n    # paths relative to the PyMuPDF checkout directory <root>, to allow use\n    # of tests/resources/test_open2_expected.json regardless of the actual\n    # checkout directory.\n    print()\n    import pipcl\n    paths = pipcl.git_items(f'{root}/tests/resources')\n    paths = fnmatch.filter(paths, f'test_open2.*')\n    paths = [f'tests/resources/{i}' for i in paths]\n    \n    # Get list of extensions of input files.\n    extensions = set()\n    extensions.add('.txt')\n    extensions.add('')\n    for path in paths:\n        _, ext = os.path.splitext(path)\n        extensions.add(ext)\n    extensions = sorted(list(extensions))\n    \n    def get_result(e, document):\n        '''\n        Return fz_lookup_metadata(document, 'format') or [ERROR].\n        '''\n        if e:\n            return f'[error]'\n        else:\n            try:\n                return pymupdf.mupdf.fz_lookup_metadata2(document, 'format')\n            except Exception:\n                return ''\n    \n    def dict_set_path(dict_, *items):\n        for item in items[:-2]:\n            dict_ = dict_.setdefault(item, dict())\n        dict_[items[-2]] = items[-1]\n\n    results = dict()\n    \n    # Prevent warnings while we are running.\n    _g_out_message = pymupdf._g_out_message\n    pymupdf._g_out_message = None\n    try:\n        results = dict()\n        \n        for path in paths:\n            print(path)\n            for ext in extensions:\n                path2 = f'{root}/foo{ext}'\n                path3 = shutil.copy2(f'{root}/{path}', path2)\n                assert(path3 == path2)\n                \n                # Test fz_open_document().\n                e = None\n                document = None\n                try:\n                    document = pymupdf.mupdf.fz_open_document(path2)\n                except Exception as ee:\n                    e = ee\n                wt = pymupdf.TOOLS.mupdf_warnings()\n                text = get_result(e, document)\n                print(f'    fz_open_document({path2}) => {text}')\n                dict_set_path(results, path, ext, 'file', text)\n\n                # Test fz_open_document_with_stream().\n                e = None\n                document = None\n                with open(f'{root}/{path}', 'rb') as f:\n                    data = f.read()\n                stream = pymupdf.mupdf.fz_open_memory(pymupdf.mupdf.python_buffer_data(data), len(data))\n                try:\n                    document = pymupdf.mupdf.fz_open_document_with_stream(ext, stream)\n                except Exception as ee:\n                    e = ee\n                wt = pymupdf.TOOLS.mupdf_warnings()\n                text = get_result(e, document)\n                print(f'    fz_open_document_with_stream(magic={ext!r}) => {text}')\n                dict_set_path(results, path, ext, 'stream', text)\n                \n    finally:\n        pymupdf._g_out_message = _g_out_message\n    \n    # Create html table.\n    path_html = os.path.normpath(f'{__file__}/../../tests/test_open2.html')\n    with open(path_html, 'w') as f:\n        f.write(f'<html>\\n')\n        f.write(f'<body>\\n')\n        f.write(f'<p>{time.strftime(\"%F-%T\")}\\n')\n        f.write(f'<table border=\"1\" style=\"border-collapse:collapse\" cellpadding=\"4\">\\n')\n        f.write(f'<tr><td></td><th colspan=\"{len(extensions)}\">Extension/magic')\n        f.write(f'<tr><th style=\"border-bottom: 4px solid black; border-right: 4px solid black;\">Data file</th>')\n        for ext in extensions:\n            f.write(f'<th style=\"border-bottom: 4px solid black;\">{ext}</th>')\n        f.write('\\n')\n        for path in sorted(results.keys()):\n            _, ext = os.path.splitext(path)\n            f.write(f'<tr><th style=\"border-right: 4px solid black;\">{os.path.basename(path)}</th>')\n            for ext2 in sorted(results[path].keys()):\n                text_file = results[path][ext2]['file']\n                text_stream = results[path][ext2]['stream']\n                b1, b2 = ('<b>', '</b>') if ext2==ext else ('', '')\n                if text_file == text_stream:\n                    if text_file == '[error]':\n                        f.write(f'<td><div style=\"color: #808080;\">{b1}{text_file}{b2}</div></td>')\n                    else:\n                        f.write(f'<td>{b1}{text_file}{b2}</td>')\n                else:\n                    f.write(f'<td>file: {b1}{text_file}{b2}<br>')\n                    f.write(f'stream: {b1}{text_stream}{b2}</td>')\n            f.write('</tr>\\n')\n        f.write(f'</table>\\n')\n        f.write(f'/<body>\\n')\n        f.write(f'</html>\\n')\n    print(f'Have created: {path_html}')\n    \n    path_out = os.path.normpath(f'{__file__}/../../tests/test_open2.json')\n    with open(path_out, 'w') as f:\n        json.dump(results, f, indent=4, sort_keys=1)\n        \n    with open(os.path.normpath(f'{__file__}/../../tests/resources/test_open2_expected.json')) as f:\n        results_expected = json.load(f)\n    if results != results_expected:\n        print(f'results != results_expected:')\n        def show(r, name):\n            text = json.dumps(r, indent=4, sort_keys=1)\n            print(f'{name}:')\n            print(textwrap.indent(text, '    '))\n        show(results_expected, 'results_expected')\n        show(results, 'results')\n        assert 0\n    \n\ndef test_533():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/2.pdf')\n    doc = pymupdf.open(path)\n    print()\n    for p in doc:\n        print(f'test_533(): for p in doc: {p=}.')\n    for p in list(doc)[:]:\n        print(f'test_533(): for p in list(doc)[:]: {p=}.')\n    for p in doc[:]:\n        print(f'test_533(): for p in doc[:]: {p=}.')\n\ndef test_3354():\n    document = pymupdf.open(filename)\n    v = dict(foo='bar')\n    document.metadata = v\n    assert document.metadata == v\n\ndef test_scientific_numbers():\n    '''\n    This is #3381.\n    '''\n    doc = pymupdf.open()\n    page = doc.new_page(width=595, height=842)\n    point = pymupdf.Point(1e-11, -1e-10)\n    page.insert_text(point, \"Test\")\n    contents = page.read_contents()\n    print(f'{contents=}')\n    assert b\" 1e-\" not in contents\n\ndef test_3615():\n    print('')\n    print(f'{pymupdf.pymupdf_version=}', flush=1)\n    print(f'{pymupdf.VersionBind=}', flush=1)\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3615.epub')\n    doc = pymupdf.open(path)\n    print(doc.pagemode)\n    print(doc.pagelayout)\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt\n\ndef test_3654():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3654.docx')\n    content = \"\"\n    with pymupdf.open(path) as document:\n        for page in document:\n            content += page.get_text() + '\\n\\n'\n    content = content.strip()\n\ndef test_3727():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3727.pdf')\n    doc = pymupdf.open(path)\n    for page in doc:\n        page.get_pixmap(matrix = pymupdf.Matrix(2,2))\n\ndef test_3569():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3569.pdf')\n    document = pymupdf.open(path)\n    page = document[0]\n    svg = page.get_svg_image(text_as_path=False)\n    print(f'{svg=}')\n    if pymupdf.mupdf_version_tuple >= (1, 27):\n        assert svg == (\n                '<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" version=\"1.1\" width=\"3024\" height=\"2160\" viewBox=\"0 0 3024 2160\">\\n'\n                '<defs>\\n'\n                '<clipPath id=\"clip_1\">\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" d=\"M25432 10909H29692V15642H25432V10909\"/>\\n'\n                '</clipPath>\\n'\n                '<clipPath id=\"clip_2\">\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" d=\"M28526 38017 31807 40376V40379L31312 41314V42889H28202L25092 42888V42887L28524 38017H28526\"/>\\n'\n                '</clipPath>\\n'\n                '</defs>\\n'\n                '<g clip-path=\"url(#clip_1)\">\\n'\n                '<g inkscape:groupmode=\"layer\" inkscape:label=\"CED - Text\">\\n'\n                '<text xml:space=\"preserve\" transform=\"matrix(.06 0 0 .06 3024 2160)\" font-size=\"174.644\" font-family=\"ArialMT\"><tspan y=\"-28538\" x=\"-14909 -14841.063 -14773.127 -14676.024 -14578.922 -14520.766 -14423.663\">**L1-13</tspan></text>\\n'\n                '</g>\\n'\n                '</g>\\n'\n                '<g clip-path=\"url(#clip_2)\">\\n'\n                '<g inkscape:groupmode=\"layer\" inkscape:label=\"Level 03|S-COLS\">\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" d=\"M31130 41483V42083L30530 41483ZM31130 42083 30530 41483V42083Z\" fill=\"#7f7f7f\"/>\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" stroke-linecap=\"butt\" stroke-miterlimit=\"10\" stroke-linejoin=\"miter\" fill=\"none\" stroke=\"#7f7f7f\" d=\"M31130 41483V42083L30530 41483ZM31130 42083 30530 41483V42083Z\"/>\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" stroke-width=\"9\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\" stroke=\"#7f7f7f\" d=\"M30530 41483H31130V42083H30530V41483\"/>\\n'\n                '</g>\\n'\n                '</g>\\n'\n                '</svg>\\n'\n                )\n    else:\n        assert svg == (\n                '<svg xmlns=\"http://www.w3.org/2000/svg\" xmlns:xlink=\"http://www.w3.org/1999/xlink\" xmlns:inkscape=\"http://www.inkscape.org/namespaces/inkscape\" version=\"1.1\" width=\"3024\" height=\"2160\" viewBox=\"0 0 3024 2160\">\\n'\n                '<defs>\\n'\n                '<clipPath id=\"clip_1\">\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" d=\"M25432 10909H29692V15642H25432V10909\"/>\\n'\n                '</clipPath>\\n'\n                '<clipPath id=\"clip_2\">\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" d=\"M28526 38017 31807 40376V40379L31312 41314V42889H28202L25092 42888V42887L28524 38017H28526\"/>\\n'\n                '</clipPath>\\n'\n                '</defs>\\n'\n                '<g clip-path=\"url(#clip_1)\">\\n'\n                '<g inkscape:groupmode=\"layer\" inkscape:label=\"CED - Text\">\\n'\n                '<text xml:space=\"preserve\" transform=\"matrix(.06 0 0 .06 3024 2160)\" font-size=\"174.644\" font-family=\"ArialMT\"><tspan y=\"-28538\" x=\"-14909 -14841.063 -14773.127 -14676.024 -14578.922 -14520.766 -14423.663\">**L1-13</tspan></text>\\n'\n                '</g>\\n'\n                '</g>\\n'\n                '<g clip-path=\"url(#clip_2)\">\\n'\n                '<g inkscape:groupmode=\"layer\" inkscape:label=\"Level 03|S-COLS\">\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" d=\"M31130 41483V42083L30530 41483ZM31130 42083 30530 41483V42083Z\" fill=\"#7f7f7f\"/>\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" stroke-width=\"0\" stroke-linecap=\"butt\" stroke-miterlimit=\"10\" stroke-linejoin=\"miter\" fill=\"none\" stroke=\"#7f7f7f\" d=\"M31130 41483V42083L30530 41483ZM31130 42083 30530 41483V42083Z\"/>\\n'\n                '<path transform=\"matrix(0,-.06,-.06,-0,3024,2160)\" stroke-width=\"9\" stroke-linecap=\"round\" stroke-linejoin=\"round\" fill=\"none\" stroke=\"#7f7f7f\" d=\"M30530 41483H31130V42083H30530V41483\"/>\\n'\n                '</g>\\n'\n                '</g>\\n'\n                '</svg>\\n'\n                )\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if pymupdf.mupdf_version_tuple >= (1, 28):\n        assert wt == 'unknown cid collection: PDFAUTOCAD-Indentity0\\nnon-embedded font using identity encoding: ArialMT (mapping via )\\ninvalid marked content sequence / clip nesting'\n    else:\n        assert wt == 'unknown cid collection: PDFAUTOCAD-Indentity0\\nnon-embedded font using identity encoding: ArialMT (mapping via )\\ninvalid marked content and clip nesting'\n\ndef test_3450():\n    # This issue is a slow-down, so we just show time taken - it's not safe\n    # to fail if test takes too long because that can give spurious failures\n    # depending on hardware etc.\n    #\n    # On a mac-mini, PyMuPDF-1.24.8 takes 60s, PyMuPDF-1.24.9 takes 4s.\n    #\n    if os.environ.get('PYMUPDF_RUNNING_ON_VALGRIND') == '1':\n        print(f'test_3450(): not running on valgrind because very slow.', flush=1)\n        return\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3450.pdf')\n    pdf = pymupdf.open(path)\n    page = pdf[0]\n    t = time.time()\n    pix = page.get_pixmap(alpha=False, dpi=150)\n    t = time.time() - t\n    print(f'test_3450(): {t=}')\n\ndef test_3859():\n    print(f'{pymupdf.mupdf.PDF_NULL=}.')\n    print(f'{pymupdf.mupdf.PDF_TRUE=}.')\n    print(f'{pymupdf.mupdf.PDF_FALSE=}.')\n    for name in ('NULL', 'TRUE', 'FALSE'):\n        name2 = f'PDF_{name}'\n        v = getattr(pymupdf.mupdf, name2)\n        print(f'{name=} {name2=} {v=} {type(v)=}')\n        assert type(v)==pymupdf.mupdf.PdfObj, f'`v` is not a pymupdf.mupdf.PdfObj.'\n\ndef test_3905():\n    data = b'A,B,C,D\\r\\n1,2,1,2\\r\\n2,2,1,2\\r\\n'\n    try:\n        document = pymupdf.open(stream=data, filetype='pdf')\n    except pymupdf.FileDataError as e:\n        print(f'test_3905(): e: {e}')\n    else:\n        assert 0\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt == 'format error: cannot find version marker\\ntrying to repair broken xref\\nrepairing PDF document'\n\ndef test_3624():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3624.pdf')\n    path_png_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_3624_expected.png')\n    path_png = os.path.normpath(f'{__file__}/../../tests/test_3624.png')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        pixmap = page.get_pixmap(matrix=pymupdf.Matrix(2, 2))\n        print(f'Saving to {path_png=}.')\n        pixmap.save(path_png)\n        rms = gentle_compare.pixmaps_rms(path_png_expected, path_png)\n        print(f'{rms=}')\n        # We get small differences in sysinstall tests, where some thirdparty\n        # libraries can differ.\n        if rms > 1:\n            pixmap_diff = gentle_compare.pixmaps_diff(path_png_expected, path_png)\n            path_png_diff = os.path.normpath(f'{__file__}/../../tests/test_3624_diff.png')\n            pixmap_diff.save(path_png_diff)\n            assert 0, f'{rms=}'\n\n\ndef test_4043():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4043.pdf')\n    doc = pymupdf.open(path)\n    doc.fullcopy_page(1)\n\n\ndef test_4018():\n    document = pymupdf.open()\n    for page in document.pages(-1, -1):\n        pass\n\ndef test_4034():\n    # tests/resources/test_4034.pdf is first two pages of input file in\n    # https://github.com/pymupdf/PyMuPDF/issues/4034.\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4034.pdf')\n    path_clean = os.path.normpath(f'{__file__}/../../tests/test_4034_out.pdf')\n    with pymupdf.open(path) as document:\n        pixmap1 = document[0].get_pixmap()\n        document.save(path_clean, clean=1)\n    with pymupdf.open(path_clean) as document:\n        page = document[0]\n        pixmap2 = document[0].get_pixmap()\n    rms = gentle_compare.pixmaps_rms(pixmap1, pixmap2)\n    print(f'test_4034(): Comparison of original/cleaned page 0 pixmaps: {rms=}.')\n    assert rms == 0\n\ndef test_4309():\n    document = pymupdf.open()\n    page = document.new_page()\n    document.delete_page()\n\ndef test_4263():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4263(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4263.pdf')\n    path_out = f'{path}.linerarized.pdf'\n    command = f'pymupdf clean -linear {path} {path_out}'\n    print(f'Running: {command}')\n    cp = subprocess.run(command, shell=1, check=0)\n    # Support for linerarisation dropped in MuPDF-1.26.\n    assert cp.returncode\n\ndef test_4224():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4224.pdf')\n    with pymupdf.open(path) as document:\n        for page in document.pages():\n            pixmap = page.get_pixmap(dpi=150)\n            path_pixmap = f'{path}.{page.number}.png'\n            pixmap.save(path_pixmap)\n            print(f'Have created: {path_pixmap}')\n\ndef test_4319():\n    # Have not seen this test reproduce issue #4319, but keeping it anyway.\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4319.pdf')\n    doc = pymupdf.open()\n    page = doc.new_page()\n    page.insert_text((10, 100), \"some text\")\n    doc.save(path)\n    doc.close()\n    doc = pymupdf.open(path)\n    page = doc[0]\n    pc = doc.page_count\n    doc.close()\n    os.remove(path)\n    print(f\"removed {doc.name=}\")\n\ndef test_3886():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3886.pdf')\n    path_clean0 = os.path.normpath(f'{__file__}/../../tests/resources/test_3886_clean0.pdf')\n    path_clean1 = os.path.normpath(f'{__file__}/../../tests/resources/test_3886_clean1.pdf')\n    \n    with pymupdf.open(path) as document:\n        pixmap = document[0].get_pixmap()\n        document.save(path_clean0, clean=0)\n    \n    with pymupdf.open(path) as document:\n        document.save(path_clean1, clean=1)\n    \n    with pymupdf.open(path_clean0) as document:\n        pixmap_clean0 = document[0].get_pixmap()\n    \n    with pymupdf.open(path_clean1) as document:\n        pixmap_clean1 = document[0].get_pixmap()\n    \n    rms_0 = gentle_compare.pixmaps_rms(pixmap, pixmap_clean0)\n    rms_1 = gentle_compare.pixmaps_rms(pixmap, pixmap_clean1)\n    print(f'test_3886(): {rms_0=} {rms_1=}')\n\ndef test_4415():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4415.pdf')\n    path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4415_out.png')\n    path_out_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4415_out_expected.png')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        rot = page.rotation\n        orig = pymupdf.Point(100, 100)  # apparent insertion point\n        text = 'Text at Top-Left'\n        mrot = page.derotation_matrix  # matrix annihilating page rotation\n        page.insert_text(orig * mrot, text, fontsize=60, rotate=rot)\n        pixmap = page.get_pixmap()\n        pixmap.save(path_out)\n        rms = gentle_compare.pixmaps_rms(path_out_expected, path_out)\n        assert rms == 0, f'{rms=}'\n\ndef test_4466():\n    path = os.path.normpath(f'{__file__}/../../tests/test_4466.pdf')\n    with pymupdf.Document(path) as document:\n        for page in document:\n            print(f'{page=}', flush=1)\n            pixmap = page.get_pixmap(clip=(0, 0, 10, 10))\n            print(f'{pixmap.n=} {pixmap.size=} {pixmap.stride=} {pixmap.width=} {pixmap.height=} {pixmap.x=} {pixmap.y=}', flush=1)\n            pixmap.is_unicolor  # Used to crash.\n\n\ndef test_4479():\n    # This passes with pymupdf-1.24.14, fails with pymupdf==1.25.*, passes with\n    # pymupdf-1.26.0.\n    print()\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4479.pdf')\n    with pymupdf.open(path) as document:\n        \n        def show(items):\n            for item in items:\n                print(f'    {repr(item)}')\n        \n        items = document.layer_ui_configs()\n        show(items)\n        assert items == [\n                {'depth': 0, 'locked': 0, 'number': 0, 'on': 1, 'text': 'layer_0', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 1, 'on': 1, 'text': 'layer_1', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 2, 'on': 0, 'text': 'layer_2', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 3, 'on': 1, 'text': 'layer_3', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 4, 'on': 1, 'text': 'layer_4', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 5, 'on': 1, 'text': 'layer_5', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 6, 'on': 1, 'text': 'layer_6', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 7, 'on': 1, 'text': 'layer_7', 'type': 'checkbox'},\n                ]\n        \n        document.set_layer_ui_config(0, pymupdf.PDF_OC_OFF)\n        items = document.layer_ui_configs()\n        show(items)\n        assert items == [\n                {'depth': 0, 'locked': 0, 'number': 0, 'on': 0, 'text': 'layer_0', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 1, 'on': 1, 'text': 'layer_1', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 2, 'on': 0, 'text': 'layer_2', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 3, 'on': 1, 'text': 'layer_3', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 4, 'on': 1, 'text': 'layer_4', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 5, 'on': 1, 'text': 'layer_5', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 6, 'on': 1, 'text': 'layer_6', 'type': 'checkbox'},\n                {'depth': 0, 'locked': 0, 'number': 7, 'on': 1, 'text': 'layer_7', 'type': 'checkbox'},\n                ]\n        \n\ndef test_4533():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4533(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    print()\n    path = util.download(\n            'https://github.com/user-attachments/files/20497146/NineData_user_manual_V3.0.5.pdf',\n            'test_4533.pdf',\n            size=16864501,\n            )\n    # This bug is a segv so we run the test in a child process.\n    command = f'{sys.executable} -c \"import pymupdf; document = pymupdf.open({path!r}); print(len(document))\"'\n    print(f'Running: {command}')\n    cp = subprocess.run(command, shell=1, check=0)\n    e = cp.returncode\n    print(f'{e=}')\n    if pymupdf.mupdf_version_tuple >= (1, 26, 6):\n        assert e == 0\n    else:\n        assert e != 0\n\n\ndef test_4564():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4564.pdf')\n    print()\n    with pymupdf.open(path) as document:\n        for key in sorted(document.metadata.keys()):\n            value = document.metadata[key]\n            print(f'{key}: {value!r}')\n    if pymupdf.mupdf_version_tuple >= (1, 27):\n        assert document.metadata['producer'] == 'Adobe PSL 1.3e for Canon\\x00'\n    else:\n        assert document.metadata['producer'] == 'Adobe PSL 1.3e for Canon\\udcc0\\udc80'\n\n\ndef test_4496():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4496.hwpx')\n    with pymupdf.open(path) as document:\n        print(document.page_count)\n\n\ndef test_gitinfo():\n    # This doesn't really test very much, but can be useful to see the current\n    # values.\n    print('')\n    print(f'test_4496():')\n    print(f'{pymupdf.mupdf_location=}')\n    print(f'{pymupdf.mupdf_version=}')\n    print(f'{pymupdf.pymupdf_git_branch=}')\n    print(f'{pymupdf.pymupdf_git_sha=}')\n    print(f'{pymupdf.pymupdf_version=}')\n    print(f'{pymupdf.pymupdf_git_diff=}')\n    if pymupdf.pymupdf_git_diff:\n        print(f'pymupdf.pymupdf_git_diff:\\n{textwrap.indent(pymupdf.pymupdf_git_diff, \"    \")}')\n    \n\ndef test_4392():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4392(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    print('', flush=1)\n    path = os.path.normpath(f'{__file__}/../../tests/test_4392.py')\n    with open(path, 'w') as f:\n        f.write('import pymupdf\\n')\n    \n    command = f'pytest {path}'\n    print(f'Running: {command}', flush=1)\n    e1 = subprocess.run(command, shell=1, check=0).returncode\n    print(f'{e1=}')\n    \n    command = f'pytest -Werror {path}'\n    print(f'Running: {command}', flush=1)\n    e2 = subprocess.run(command, shell=1, check=0).returncode\n    print(f'{e2=}')\n    \n    command = f'{sys.executable} -Werror -c \"import pymupdf\"'\n    print(f'Running: {command}', flush=1)\n    e3 = subprocess.run(command, shell=1, check=0).returncode\n    print(f'{e3=}')\n    \n    print(f'{e1=} {e2=} {e3=}', flush=1)\n    \n    print(f'{pymupdf.swig_version=}', flush=1)\n    print(f'{pymupdf.swig_version_tuple=}', flush=1)\n    \n    assert e1 == 5\n    if pymupdf.swig_version_tuple >= (4, 4):\n        if sysconfig.get_config_var('Py_GIL_DISABLED') == 1 and sys._is_gil_enabled():\n            assert e2 == 4\n        else:\n            assert e2 == 5\n        if sysconfig.get_config_var('Py_GIL_DISABLED') == 1 and sys._is_gil_enabled():\n            # GIL warning results in failure because of -Werror.\n            assert e3 == 1\n        else:\n            assert e3 == 0\n    else:\n        # We get SEGV's etc with older swig.\n        if platform.system() == 'Windows':\n            assert (e2, e3) == (0xc0000005, 0xc0000005)\n        elif platform.system() == 'Linux':\n            # On plain linux we get (139, 139). On manylinux we get (-11,\n            # -11). On MacOS we get (-11, -11).\n            assert (e2, e3) == (139, 139) or (e2, e3) == (-11, -11)\n        elif platform.system() == 'Darwin':\n            # python3.14t gives (4, -11)?\n            assert (e2, e3) == (-11, -11) or (e2, e3) == (4, -11)\n        else:\n            assert e2 and e3\n\n\ndef test_4639():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4639.pdf')\n    with pymupdf.open(path) as document:\n        page = document[-1]\n        page.get_bboxlog(layers=True)\n\n\ndef test_4590():\n\n    # Create test PDF.\n    path = os.path.normpath(f'{__file__}/../../tests/test_4590.pdf')\n    with pymupdf.open() as document:\n        page = document.new_page()\n        \n        # Add some text\n        text = 'This PDF contains a file attachment annotation.'\n        page.insert_text((72, 72), text, fontsize=12)\n\n        # Create a sample file.\n        path_sample = os.path.normpath(f'{__file__}/../../tests/test_4590_annotation_sample.txt')\n        with open(path_sample, 'w') as f:\n            f.write('This is a sample attachment file.')\n\n        # Read file as bytes\n        with open(path_sample, 'rb') as f:\n            sample = f.read()\n\n        # Define annotation position (rect or point)\n        annot_pos = pymupdf.Rect(72, 100, 92, 120)  # PushPin icon rectangle\n\n        # Add the file attachment annotation\n        page.add_file_annot(\n                point = annot_pos,\n                buffer_ = sample,\n                filename = 'sample.txt',\n                ufilename = 'sample.txt',\n                desc = 'A test attachment file.',\n                icon = 'PushPin',\n                )\n\n        # Save the PDF\n        document.save(path)\n    \n    # Check pymupdf.Document.scrub() works.\n    with pymupdf.open(path) as document:\n        document.scrub()\n\n\ndef test_4702():\n    if os.environ.get('PYODIDE_ROOT'):\n        # util.download() uses subprocess.\n        print('test_4702(): not running on Pyodide - cannot run child processes.')\n        return\n\n    path = util.download(\n            'https://github.com/user-attachments/files/22403483/01995b6ca7837b52abaa24e38e8c076d.pdf',\n            'test_4702.pdf',\n            )\n    with pymupdf.open(path) as document:\n        for xref in range(1, document.xref_length()):\n            print(f'{xref=}')\n            try:\n                _ = document.xref_object(xref)\n            except Exception as e1:\n                print(f'{e1=}')\n                try:\n                    document.update_object(xref, \"<<>>\")\n                except Exception as e2:\n                    print(f'{e2=}')\n                    raise\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt == 'repairing PDF document'\n    \n    with pymupdf.open(path) as document:\n        for xref in range(1, document.xref_length()):\n            print(f'{xref=}')\n            _ = document.xref_object(xref)\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt == 'repairing PDF document'\n\n\ndef test_4712():\n    '''\n    Crash with \"corrupted double-linked list\n    '''\n    if pymupdf.mupdf_version_tuple < (1, 26, 11):\n        print(f'test_4712m(): Not running because known to fail on mupdf < 1.26.11: {pymupdf.mupdf_version=}.')\n        return\n    path_a = os.path.normpath(f'{__file__}/../../tests/resources/test_4712_a.pdf')\n    path_b = os.path.normpath(f'{__file__}/../../tests/resources/test_4712_b.pdf')\n    doc1 = pymupdf.open(path_a)\n    for i in range(6):\n        doc1.load_page(i).get_pixmap()\n    doc2 = pymupdf.open(path_b)\n    for i in range(6):\n        doc2.load_page(i).get_pixmap()\n\n\ndef test_4712m():\n    if pymupdf.mupdf_version_tuple < (1, 26, 11):\n        print(f'test_4712m(): Not running because known to fail on mupdf < 1.26.11: {pymupdf.mupdf_version=}.')\n        return\n    \n    path_a = os.path.normpath(f'{__file__}/../../tests/resources/test_4712_a.pdf')\n    path_b = os.path.normpath(f'{__file__}/../../tests/resources/test_4712_b.pdf')\n    \n    mupdf = pymupdf.mupdf\n    def get_pixmap(page):\n        displaylist = mupdf.fz_new_display_list_from_page(page)\n        rect = mupdf.fz_bound_display_list(displaylist)\n        irect = mupdf.fz_round_rect(rect)\n        pixmap = mupdf.fz_new_pixmap_with_bbox(\n                mupdf.FzColorspace(mupdf.FzColorspace.Fixed_RGB),\n                irect,\n                mupdf.FzSeparations(),\n                0,  # alpha\n                )\n        mupdf.fz_clear_pixmap_with_value(pixmap, 0xFF)\n        matrix = mupdf.FzMatrix()\n        device = mupdf.fz_new_draw_device(matrix, pixmap)\n        mupdf.fz_run_display_list(\n                displaylist,\n                device,\n                mupdf.FzMatrix(),\n                mupdf.FzRect(mupdf.FzRect.Fixed_INFINITE),\n                mupdf.FzCookie(),\n                )\n        mupdf.fz_close_device(device)\n    \n    def process_document(document):\n        for i in range(6):\n            print(f'    {i=}', flush=1)\n            page = mupdf.fz_load_page(document, i)\n            get_pixmap(page)\n\n    print(f'Processing {path_a=}', flush=1)\n    document_a = mupdf.fz_open_document(path_a)\n    process_document(document_a)\n\n    print(f'Processing {path_b=}', flush=1)\n    document_b = mupdf.fz_open_document(path_b)\n    process_document(document_b)\n\n\ndef test_4746():\n    archive = pymupdf.Archive('.')\n    archive.add(__file__, 'foo')\n\n\ndef test_4907():\n    print()\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4907.pdf')\n    with pymupdf.open(path) as document:\n        for i, page in enumerate(document):\n            print(f'{i=}')\n            display_list = page.get_displaylist(annots=False)\n            text_page = display_list.get_textpage()\n\n\ndef test_4928():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4928.pdf')\n    with pymupdf.open(path) as document:\n        document.scrub()\n\n    \ndef test_4902():\n    print()\n    print(f'test_4902(): {pymupdf.mupdf_version_tuple=}')\n    with pymupdf.open() as doc:\n        page = doc.new_page()\n        text = 'Hello World'\n        bw = 0.4\n        fontsize = 20\n        page.insert_text(\n                (72, 72),\n                text,\n                fontsize=fontsize,\n                render_mode=2,\n                color=(1, 0, 0),\n                fill=(0, 1, 0),\n                border_width=bw,\n                )\n        data = doc.tobytes()\n    with pymupdf.open('pdf', data) as doc:\n        page = doc[0]\n        spans = page.get_texttrace()\n        for i, span in enumerate(spans):\n            cs = ''.join([chr(cc[0]) for cc in span['chars']])\n            print(f'test_4902(): {i=} {span[\"linewidth\"]=} {cs=}')\n        assert len(spans) == 2\n        assert spans[0]['linewidth'] is None\n        assert spans[1]['linewidth'] == 8.0\n"
  },
  {
    "path": "tests/test_geometry.py",
    "content": "\"\"\"\n* Check various construction methods of rects, points, matrices\n* Check matrix inversions in variations\n* Check algebra constructs\n\"\"\"\nimport os\n\nimport pymupdf\n\n\ndef test_rect():\n    assert tuple(pymupdf.Rect()) == (0, 0, 0, 0)\n    if hasattr(pymupdf, 'mupdf'):\n        assert tuple(pymupdf.Rect(y0=12)) == (0, 12, 0, 0)\n        assert tuple(pymupdf.Rect(10, 20, 100, 200, x1=12)) == (10, 20, 12, 200)\n    p1 = pymupdf.Point(10, 20)\n    p2 = pymupdf.Point(100, 200)\n    p3 = pymupdf.Point(150, 250)\n    r = pymupdf.Rect(10, 20, 100, 200)\n    r_tuple = tuple(r)\n    assert tuple(pymupdf.Rect(p1, p2)) == r_tuple\n    assert tuple(pymupdf.Rect(p1, 100, 200)) == r_tuple\n    assert tuple(pymupdf.Rect(10, 20, p2)) == r_tuple\n    assert tuple(r.include_point(p3)) == (10, 20, 150, 250)\n    r = pymupdf.Rect(10, 20, 100, 200)\n    assert tuple(r.include_rect((100, 200, 110, 220))) == (10, 20, 110, 220)\n    r = pymupdf.Rect(10, 20, 100, 200)\n    # include empty rect makes no change\n    assert tuple(r.include_rect((0, 0, 0, 0))) == r_tuple\n    # include invalid rect makes no change\n    assert tuple(r.include_rect((1, 1, -1, -1))) == r_tuple\n    r = pymupdf.Rect()\n    for i in range(4):\n        r[i] = i + 1\n    assert r == pymupdf.Rect(1, 2, 3, 4)\n    assert pymupdf.Rect() / 5 == pymupdf.Rect()\n    assert pymupdf.Rect(1, 1, 2, 2) / pymupdf.Identity == pymupdf.Rect(1, 1, 2, 2)\n    failed = False\n    try:\n        r = pymupdf.Rect(1)\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.Rect(1, 2, 3, 4, 5)\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.Rect((1, 2, 3, 4, 5))\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.Rect(1, 2, 3, \"x\")\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.Rect()\n        r[5] = 1\n    except:\n        failed = True\n    assert failed\n\n\ndef test_irect():\n    p1 = pymupdf.Point(10, 20)\n    p2 = pymupdf.Point(100, 200)\n    p3 = pymupdf.Point(150, 250)\n    r = pymupdf.IRect(10, 20, 100, 200)\n    r_tuple = tuple(r)\n    assert tuple(pymupdf.IRect(p1, p2)) == r_tuple\n    assert tuple(pymupdf.IRect(p1, 100, 200)) == r_tuple\n    assert tuple(pymupdf.IRect(10, 20, p2)) == r_tuple\n    assert tuple(r.include_point(p3)) == (10, 20, 150, 250)\n    r = pymupdf.IRect(10, 20, 100, 200)\n    assert tuple(r.include_rect((100, 200, 110, 220))) == (10, 20, 110, 220)\n    r = pymupdf.IRect(10, 20, 100, 200)\n    # include empty rect makes no change\n    assert tuple(r.include_rect((0, 0, 0, 0))) == r_tuple\n    r = pymupdf.IRect()\n    for i in range(4):\n        r[i] = i + 1\n    assert r == pymupdf.IRect(1, 2, 3, 4)\n\n    failed = False\n    try:\n        r = pymupdf.IRect(1)\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.IRect(1, 2, 3, 4, 5)\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.IRect((1, 2, 3, 4, 5))\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.IRect(1, 2, 3, \"x\")\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        r = pymupdf.IRect()\n        r[5] = 1\n    except:\n        failed = True\n    assert failed\n\n\ndef test_inversion():\n    alpha = 255\n    m1 = pymupdf.Matrix(alpha)\n    m2 = pymupdf.Matrix(-alpha)\n    m3 = m1 * m2  # should equal identity matrix\n    assert abs(m3 - pymupdf.Identity) < pymupdf.EPSILON\n    m = pymupdf.Matrix(1, 0, 1, 0, 1, 0)  # not invertible!\n    # inverted matrix must be zero\n    assert ~m == pymupdf.Matrix()\n\n\ndef test_matrix():\n    assert tuple(pymupdf.Matrix()) == (0, 0, 0, 0, 0, 0)\n    assert tuple(pymupdf.Matrix(90)) == (0, 1, -1, 0, 0, 0)\n    if hasattr(pymupdf, 'mupdf'):\n        assert tuple(pymupdf.Matrix(c=1)) == (0, 0, 1, 0, 0, 0)\n        assert tuple(pymupdf.Matrix(90, e=5)) == (0, 1, -1, 0, 5, 0)\n    m45p = pymupdf.Matrix(45)\n    m45m = pymupdf.Matrix(-45)\n    m90 = pymupdf.Matrix(90)\n    assert abs(m90 - m45p * m45p) < pymupdf.EPSILON\n    assert abs(pymupdf.Identity - m45p * m45m) < pymupdf.EPSILON\n    assert abs(m45p - ~m45m) < pymupdf.EPSILON\n    assert pymupdf.Matrix(2, 3, 1) == pymupdf.Matrix(1, 3, 2, 1, 0, 0)\n    m = pymupdf.Matrix(2, 3, 1)\n    m.invert()\n    assert abs(m * pymupdf.Matrix(2, 3, 1) - pymupdf.Identity) < pymupdf.EPSILON\n    assert pymupdf.Matrix(1, 1).pretranslate(2, 3) == pymupdf.Matrix(1, 0, 0, 1, 2, 3)\n    assert pymupdf.Matrix(1, 1).prescale(2, 3) == pymupdf.Matrix(2, 0, 0, 3, 0, 0)\n    assert pymupdf.Matrix(1, 1).preshear(2, 3) == pymupdf.Matrix(1, 3, 2, 1, 0, 0)\n    assert abs(pymupdf.Matrix(1, 1).prerotate(30) - pymupdf.Matrix(30)) < pymupdf.EPSILON\n    small = 1e-6\n    assert pymupdf.Matrix(1, 1).prerotate(90 + small) == pymupdf.Matrix(90)\n    assert pymupdf.Matrix(1, 1).prerotate(180 + small) == pymupdf.Matrix(180)\n    assert pymupdf.Matrix(1, 1).prerotate(270 + small) == pymupdf.Matrix(270)\n    assert pymupdf.Matrix(1, 1).prerotate(small) == pymupdf.Matrix(0)\n    assert pymupdf.Matrix(1, 1).concat(\n        pymupdf.Matrix(1, 2), pymupdf.Matrix(3, 4)\n    ) == pymupdf.Matrix(3, 0, 0, 8, 0, 0)\n    assert pymupdf.Matrix(1, 2, 3, 4, 5, 6) / 1 == pymupdf.Matrix(1, 2, 3, 4, 5, 6)\n    assert m[0] == m.a\n    assert m[1] == m.b\n    assert m[2] == m.c\n    assert m[3] == m.d\n    assert m[4] == m.e\n    assert m[5] == m.f\n    m = pymupdf.Matrix()\n    for i in range(6):\n        m[i] = i + 1\n    assert m == pymupdf.Matrix(1, 2, 3, 4, 5, 6)\n    failed = False\n    try:\n        m = pymupdf.Matrix(1, 2, 3)\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        m = pymupdf.Matrix(1, 2, 3, 4, 5, 6, 7)\n    except:\n        failed = True\n    assert failed\n\n    failed = False\n    try:\n        m = pymupdf.Matrix((1, 2, 3, 4, 5, 6, 7))\n    except:\n        failed = True\n    assert failed\n\n    failed = False\n    try:\n        m = pymupdf.Matrix(1, 2, 3, 4, 5, \"x\")\n    except:\n        failed = True\n    assert failed\n\n    failed = False\n    try:\n        m = pymupdf.Matrix(1, 0, 1, 0, 1, 0)\n        n = pymupdf.Matrix(1, 1) / m\n    except:\n        failed = True\n    assert failed\n\n\ndef test_point():\n    assert tuple(pymupdf.Point()) == (0, 0)\n    assert pymupdf.Point(1, -1).unit == pymupdf.Point(5, -5).unit\n    assert pymupdf.Point(-1, -1).abs_unit == pymupdf.Point(1, 1).unit\n    assert pymupdf.Point(1, 1).distance_to(pymupdf.Point(1, 1)) == 0\n    assert pymupdf.Point(1, 1).distance_to(pymupdf.Rect(1, 1, 2, 2)) == 0\n    assert pymupdf.Point().distance_to((1, 1, 2, 2)) > 0\n    failed = False\n    try:\n        p = pymupdf.Point(1, 2, 3)\n    except:\n        failed = True\n    assert failed\n\n    failed = False\n    try:\n        p = pymupdf.Point((1, 2, 3))\n    except:\n        failed = True\n    assert failed\n\n    failed = False\n    try:\n        p = pymupdf.Point(1, \"x\")\n    except:\n        failed = True\n    assert failed\n\n    failed = False\n    try:\n        p = pymupdf.Point()\n        p[3] = 1\n    except:\n        failed = True\n    assert failed\n\n\ndef test_algebra():\n    p = pymupdf.Point(1, 2)\n    m = pymupdf.Matrix(1, 2, 3, 4, 5, 6)\n    r = pymupdf.Rect(1, 1, 2, 2)\n    assert p + p == p * 2\n    assert p - p == pymupdf.Point()\n    assert m + m == m * 2\n    assert m - m == pymupdf.Matrix()\n    assert r + r == r * 2\n    assert r - r == pymupdf.Rect()\n    assert p + 5 == pymupdf.Point(6, 7)\n    assert m + 5 == pymupdf.Matrix(6, 7, 8, 9, 10, 11)\n    assert r.tl in r\n    assert r.tr not in r\n    assert r.br not in r\n    assert r.bl not in r\n    assert p * m == pymupdf.Point(12, 16)\n    assert r * m == pymupdf.Rect(9, 12, 13, 18)\n    assert (pymupdf.Rect(1, 1, 2, 2) & pymupdf.Rect(2, 2, 3, 3)).is_empty\n    assert not pymupdf.Rect(1, 1, 2, 2).intersects((2, 2, 4, 4))\n    failed = False\n    try:\n        x = m + p\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        x = m + r\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        x = p + r\n    except:\n        failed = True\n    assert failed\n    failed = False\n    try:\n        x = r + m\n    except:\n        failed = True\n    assert failed\n    assert m not in r\n\n\ndef test_quad():\n    r = pymupdf.Rect(10, 10, 20, 20)\n    q = r.quad\n    assert q.is_rectangular\n    assert not q.is_empty\n    assert q.is_convex\n    q *= pymupdf.Matrix(1, 1).preshear(2, 3)\n    assert not q.is_rectangular\n    assert not q.is_empty\n    assert q.is_convex\n    assert r.tl not in q\n    assert r not in q\n    assert r.quad not in q\n    failed = False\n    try:\n        q[5] = pymupdf.Point()\n    except:\n        failed = True\n    assert failed\n\n    failed = False\n    try:\n        q /= (1, 0, 1, 0, 1, 0)\n    except:\n        failed = True\n    assert failed\n\n\ndef test_pageboxes():\n    \"\"\"Tests concerning ArtBox, TrimBox, BleedBox.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    assert page.cropbox == page.artbox == page.bleedbox == page.trimbox\n    rect_methods = (\n        page.set_cropbox,\n        page.set_artbox,\n        page.set_bleedbox,\n        page.set_trimbox,\n    )\n    keys = (\"CropBox\", \"ArtBox\", \"BleedBox\", \"TrimBox\")\n    rect = pymupdf.Rect(100, 200, 400, 700)\n    for f in rect_methods:\n        f(rect)\n    for key in keys:\n        assert doc.xref_get_key(page.xref, key) == (\"array\", \"[100 142 400 642]\")\n    assert page.cropbox == page.artbox == page.bleedbox == page.trimbox\n\ndef test_3163():\n    b = {'number': 0, 'type': 0, 'bbox': (403.3577880859375, 330.8871765136719, 541.2731323242188, 349.5766296386719), 'lines': [{'spans': [{'size': 14.0, 'flags': 4, 'font': 'SFHello-Medium', 'color': 1907995, 'ascender': 1.07373046875, 'descender': -0.26123046875, 'text': 'Inclusion and diversity', 'origin': (403.3577880859375, 345.9194030761719), 'bbox': (403.3577880859375, 330.8871765136719, 541.2731323242188, 349.5766296386719)}], 'wmode': 0, 'dir': (1.0, 0.0), 'bbox': (403.3577880859375, 330.8871765136719, 541.2731323242188, 349.5766296386719)}]}\n    bbox = pymupdf.IRect(b[\"bbox\"])\n\ndef test_3182():\n    pix = pymupdf.Pixmap(os.path.abspath(f'{__file__}/../../tests/resources/img-transparent.png'))\n    rect = pymupdf.Rect(0, 0, 100, 100)\n    pix.invert_irect(rect)\n"
  },
  {
    "path": "tests/test_imagebbox.py",
    "content": "\"\"\"\nEnsure equality of bboxes computed via\n* page.get_image_bbox()\n* page.get_image_info()\n* page.get_bboxlog()\n\n\"\"\"\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"image-file1.pdf\")\nimage = os.path.join(scriptdir, \"resources\", \"img-transparent.png\")\ndoc = pymupdf.open(filename)\n\n\ndef test_image_bbox():\n    page = doc[0]\n    imglist = page.get_images(True)\n    bbox_list = []\n    for item in imglist:\n        bbox_list.append(page.get_image_bbox(item, transform=False))\n    infos = page.get_image_info(xrefs=True)\n    match = False\n    for im in infos:\n        bbox1 = im[\"bbox\"]\n        match = False\n        for bbox2 in bbox_list:\n            abs_bbox = (bbox2 - bbox1).norm()\n            if abs_bbox < 1e-4:\n                match = True\n                break\n    assert match\n\n\ndef test_bboxlog():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    xref = page.insert_image(page.rect, filename=image)\n    img_info = page.get_image_info(xrefs=True)\n    assert len(img_info) == 1\n    info = img_info[0]\n    assert info[\"xref\"] == xref\n    bbox_log = page.get_bboxlog()\n    assert len(bbox_log) == 1\n    box_type, bbox = bbox_log[0]\n    assert box_type == \"fill-image\"\n    assert bbox == info[\"bbox\"]\n"
  },
  {
    "path": "tests/test_imagemasks.py",
    "content": "\"\"\"\nConfirm image mask detection in TextPage extractions. \n\"\"\"\n\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename1 = os.path.join(scriptdir, \"resources\", \"img-regular.pdf\")\nfilename2 = os.path.join(scriptdir, \"resources\", \"img-transparent.pdf\")\n\n\ndef test_imagemask1():\n    doc = pymupdf.open(filename1)\n    page = doc[0]\n    blocks = page.get_text(\"dict\")[\"blocks\"]\n    img = blocks[0]\n    assert img[\"mask\"] is None\n    img = page.get_image_info()[0]\n    assert img[\"has-mask\"] is False\n\n\ndef test_imagemask2():\n    doc = pymupdf.open(filename2)\n    page = doc[0]\n    blocks = page.get_text(\"dict\")[\"blocks\"]\n    img = blocks[0]\n    assert type(img[\"mask\"]) is bytes\n    img = page.get_image_info()[0]\n    assert img[\"has-mask\"] is True\n"
  },
  {
    "path": "tests/test_import.py",
    "content": "import os\nimport subprocess\nimport sys\nimport textwrap\n\n\ndef test_import():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_import(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    root = os.path.abspath(f'{__file__}/../../')\n    p = f'{root}/tests/resources_test_import.py'\n    with open(p, 'w') as f:\n        f.write(textwrap.dedent(\n                '''\n                from pymupdf.utils import *\n                from pymupdf.table import *\n                from pymupdf import *\n                '''\n                ))\n    subprocess.run(f'{sys.executable} {p}', shell=1, check=1)\n"
  },
  {
    "path": "tests/test_insertimage.py",
    "content": "\"\"\"\n* Insert same image with different rotations in two places of a page.\n* Extract bboxes and transformation matrices\n* Assert image locations are inside given rectangles\n\"\"\"\nimport json\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nimgfile = os.path.join(scriptdir, \"resources\", \"nur-ruhig.jpg\")\n\n\ndef test_insert():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    r1 = pymupdf.Rect(50, 50, 100, 100)\n    r2 = pymupdf.Rect(50, 150, 200, 400)\n    page.insert_image(r1, filename=imgfile)\n    page.insert_image(r2, filename=imgfile, rotate=270)\n    info_list = page.get_image_info()\n    assert len(info_list) == 2\n    bbox1 = pymupdf.Rect(info_list[0][\"bbox\"])\n    bbox2 = pymupdf.Rect(info_list[1][\"bbox\"])\n    assert bbox1 in r1\n    assert bbox2 in r2\n\ndef test_compress():\n    document = pymupdf.open(f'{scriptdir}/resources/2.pdf')\n    document_new = pymupdf.open()\n    for page in document:\n        pixmap = page.get_pixmap(\n                colorspace=pymupdf.csRGB,\n                dpi=72,\n                annots=False,\n                )\n        page_new = document_new.new_page(-1)\n        page_new.insert_image(rect=page_new.bound(), pixmap=pixmap)\n    document_new.save(\n            f'{scriptdir}/resources/2.pdf.compress.pdf',\n            garbage=3,\n            deflate=True,\n            deflate_images=True,\n            deflate_fonts=True,\n            pretty=True,\n            )\n\ndef test_3087():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_3087.pdf')\n    \n    doc = pymupdf.open(path)\n    page = doc[0]\n    print(page.get_images())\n    base = doc.extract_image(5)[\"image\"]\n    mask = doc.extract_image(5)[\"image\"]\n    page = doc.new_page()\n    page.insert_image(page.rect, stream=base, mask=mask)\n    \n    doc = pymupdf.open(path)\n    page = doc[0]\n    print(page.get_images())\n    base = doc.extract_image(5)[\"image\"]\n    mask = doc.extract_image(6)[\"image\"]\n    page = doc.new_page()\n    page.insert_image(page.rect, stream=base, mask=mask)\n"
  },
  {
    "path": "tests/test_insertpdf.py",
    "content": "\"\"\"\n* Join multiple PDFs into a new one.\n* Compare with stored earlier result:\n    - must have identical object definitions\n    - must have different trailers\n* Try inserting files in a loop.\n\"\"\"\n\nimport io\nimport os\nimport re\nimport pymupdf\nfrom pymupdf import mupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nresources = os.path.join(scriptdir, \"resources\")\n\ndef approx_parse( text):\n    '''\n    Splits <text> into sequence of (text, number) pairs. Where sequence of\n    [0-9.] is not convertible to a number (e.g. '4.5.6'), <number> will be\n    None.\n    '''\n    ret = []\n    for m in re.finditer('([^0-9]+)([0-9.]*)', text):\n        text = m.group(1)\n        try:\n            number = float( m.group(2))\n        except Exception:\n            text += m.group(2)\n            number = None\n        ret.append( (text, number))\n    return ret\n\ndef approx_compare( a, b, max_delta):\n    '''\n    Compares <a> and <b>, allowing numbers to differ by up to <delta>.\n    '''\n    aa = approx_parse( a)\n    bb = approx_parse( b)\n    if len(aa) != len(bb):\n        return 1\n    ret = 1\n    for (at, an), (bt, bn) in zip( aa, bb):\n        if at != bt:\n            break\n        if an is not None and bn is not None:\n            if abs( an - bn) >= max_delta:\n                print( f'diff={an-bn}: an={an} bn={bn}')\n                break\n        elif (an is None) != (bn is None):\n            break\n    else:\n        ret = 0\n    if ret:\n        print( f'Differ:\\n    a={a!r}\\n    b={b!r}')\n    return ret\n\n\ndef test_insert():\n    all_text_original = []  # text on input pages\n    all_text_combined = []  # text on resulting output pages\n    # prepare input PDFs\n    doc1 = pymupdf.open()\n    for i in range(5):  # just arbitrary number of pages\n        text = f\"doc 1, page {i}\"  # the 'globally' unique text\n        page = doc1.new_page()\n        page.insert_text((100, 72), text)\n        all_text_original.append(text)\n\n    doc2 = pymupdf.open()\n    for i in range(4):\n        text = f\"doc 2, page {i}\"\n        page = doc2.new_page()\n        page.insert_text((100, 72), text)\n        all_text_original.append(text)\n\n    doc3 = pymupdf.open()\n    for i in range(3):\n        text = f\"doc 3, page {i}\"\n        page = doc3.new_page()\n        page.insert_text((100, 72), text)\n        all_text_original.append(text)\n\n    doc4 = pymupdf.open()\n    for i in range(6):\n        text = f\"doc 4, page {i}\"\n        page = doc4.new_page()\n        page.insert_text((100, 72), text)\n        all_text_original.append(text)\n\n    new_doc = pymupdf.open()  # make combined PDF of input files\n    new_doc.insert_pdf(doc1)\n    new_doc.insert_pdf(doc2)\n    new_doc.insert_pdf(doc3)\n    new_doc.insert_pdf(doc4)\n    # read text from all pages and store in list\n    for page in new_doc:\n        all_text_combined.append(page.get_text().replace(\"\\n\", \"\"))\n    # the lists must be equal\n    assert all_text_combined == all_text_original\n\n\ndef test_issue1417_insertpdf_in_loop():\n    \"\"\"Using a context manager instead of explicitly closing files\"\"\"\n    f = os.path.join(resources, \"1.pdf\")\n    big_doc = pymupdf.open()\n    fd1 = os.open( f, os.O_RDONLY)\n    os.close( fd1)\n    for n in range(0, 1025):\n        with pymupdf.open(f) as pdf:\n            big_doc.insert_pdf(pdf)\n        # Create a raw file descriptor. If the above pymupdf.open() context leaks\n        # a file descriptor, fd will be seen to increment.\n        fd2 = os.open( f, os.O_RDONLY)\n        assert fd2 == fd1\n        os.close( fd2)\n    big_doc.close()\n\n\ndef _test_insert_adobe():\n    path = os.path.abspath( f'{__file__}/../../../PyMuPDF-performance/adobe.pdf')\n    if not os.path.exists(path):\n        print(f'Not running test_insert_adobe() because does not exist: {os.path.relpath(path)}')\n        return\n    a = pymupdf.Document()\n    b = pymupdf.Document(path)\n    a.insert_pdf(b)\n\n\ndef _2861_2871_merge_pdf(content: bytes, coverpage: bytes):\n    with pymupdf.Document(stream=coverpage, filetype=\"pdf\") as coverpage_pdf:\n        with pymupdf.Document(stream=content, filetype=\"pdf\") as content_pdf:\n            coverpage_pdf.insert_pdf(content_pdf)\n            doc = coverpage_pdf.write()\n            return doc\n\ndef test_2861():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2861.pdf')\n    with open(path, \"rb\") as content_pdf:\n        with open(path, \"rb\") as coverpage_pdf:\n            content = content_pdf.read()\n            coverpage = coverpage_pdf.read()\n            _2861_2871_merge_pdf(content, coverpage)\n\ndef test_2871():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2871.pdf')\n    with open(path, \"rb\") as content_pdf:\n        with open(path, \"rb\") as coverpage_pdf:\n            content = content_pdf.read()\n            coverpage = coverpage_pdf.read()\n            _2861_2871_merge_pdf(content, coverpage)\n\n\ndef test_3789():\n\n    file_path = os.path.abspath(f'{__file__}/../../tests/resources/test_3789.pdf')\n    result_path = os.path.abspath(f'{__file__}/../../tests/test_3789_out')\n    pages_per_split = 5\n\n    # Clean pdf\n    doc = pymupdf.open(file_path)\n    tmp = io.BytesIO()\n    tmp.write(doc.write(garbage=4, deflate=True))\n\n    source_doc = pymupdf.Document('pdf', tmp.getvalue())\n    tmp.close()\n\n    # Calculate the number of pages per split file and the number of split files\n    page_range = pages_per_split - 1\n    split_range = range(0, source_doc.page_count, pages_per_split)\n    num_splits = len(split_range)\n\n    # Loop through each split range and create a new PDF file\n    for i, start in enumerate(split_range):\n        output_doc = pymupdf.open()\n\n        # Determine the ending page for this split file\n        to_page = start + page_range if i < num_splits - 1 else -1\n        output_doc.insert_pdf(source_doc, from_page=start, to_page=to_page)\n\n        # Save the output document to a file and add the path to the list of split files\n        path = f'{result_path}_{i}.pdf'\n        output_doc.save(path, garbage=2)\n        print(f'Have saved to {path=}.')\n\n        # If this is the last split file, exit the loop\n        if to_page == -1:\n            break\n\n\ndef test_widget_insert():\n    \"\"\"Confirm copy of form fields / widgets.\"\"\"\n    tar = pymupdf.open(os.path.join(resources, \"merge-form1.pdf\"))\n    pc0 = tar.page_count  # for later assertion\n    src = pymupdf.open(os.path.join(resources, \"interfield-calculation.pdf\"))\n    pc1 = src.page_count  # for later assertion\n\n    tarpdf = pymupdf._as_pdf_document(tar)\n    tar_field_count = mupdf.pdf_array_len(\n        mupdf.pdf_dict_getp(mupdf.pdf_trailer(tarpdf), \"Root/AcroForm/Fields\")\n    )\n    tar_co_count = mupdf.pdf_array_len(\n        mupdf.pdf_dict_getp(mupdf.pdf_trailer(tarpdf), \"Root/AcroForm/CO\")\n    )\n    srcpdf = pymupdf._as_pdf_document(src)\n    src_field_count = mupdf.pdf_array_len(\n        mupdf.pdf_dict_getp(mupdf.pdf_trailer(srcpdf), \"Root/AcroForm/Fields\")\n    )\n    src_co_count = mupdf.pdf_array_len(\n        mupdf.pdf_dict_getp(mupdf.pdf_trailer(srcpdf), \"Root/AcroForm/CO\")\n    )\n\n    tar.insert_pdf(src)\n    new_field_count = mupdf.pdf_array_len(\n        mupdf.pdf_dict_getp(mupdf.pdf_trailer(tarpdf), \"Root/AcroForm/Fields\")\n    )\n    new_co_count = mupdf.pdf_array_len(\n        mupdf.pdf_dict_getp(mupdf.pdf_trailer(tarpdf), \"Root/AcroForm/CO\")\n    )\n    assert tar.page_count == pc0 + pc1\n    assert new_field_count == tar_field_count + src_field_count\n    assert new_co_count == tar_co_count + src_co_count\n\n\ndef names_and_kids(doc):\n    \"\"\"Return a list of dictionaries with keys \"name\" and \"kids\".\n\n    \"name\" is the name of a root field in \"Root/AcroForm/Fields\", and\n    \"kids\" is the count of its immediate children.\n    \"\"\"\n    rc = []\n    pdf = pymupdf._as_pdf_document(doc)\n    fields = mupdf.pdf_dict_getl(\n        mupdf.pdf_trailer(pdf),\n        pymupdf.PDF_NAME(\"Root\"),\n        pymupdf.PDF_NAME(\"AcroForm\"),\n        pymupdf.PDF_NAME(\"Fields\"),\n    )\n    if not fields.pdf_is_array():\n        return rc\n    root_count = fields.pdf_array_len()\n    if not root_count:\n        return rc\n    for i in range(root_count):\n        field = fields.pdf_array_get(i)\n        kids = field.pdf_dict_get(pymupdf.PDF_NAME(\"Kids\"))\n        kid_count = kids.pdf_array_len()\n        T = field.pdf_dict_get_text_string(pymupdf.PDF_NAME(\"T\"))\n        field_dict = {\"name\": T, \"kids\": kid_count}\n        rc.append(field_dict)\n    return rc\n\n\ndef test_merge_checks1():\n    \"\"\"Merge Form PDFs making any duplicate names unique.\"\"\"\n    merge_file1 = os.path.join(resources, \"merge-form1.pdf\")\n    merge_file2 = os.path.join(resources, \"merge-form2.pdf\")\n    tar = pymupdf.open(merge_file1)\n    rc0 = names_and_kids(tar)\n    src = pymupdf.open(merge_file2)\n    rc1 = names_and_kids(src)\n    tar.insert_pdf(src, join_duplicates=False)\n    rc2 = names_and_kids(tar)\n    assert len(rc2) == len(rc0) + len(rc1)\n\n\ndef test_merge_checks2():\n    # Join / merge Form PDFs joining any duplicate names in the src PDF.\n    merge_file1 = os.path.join(resources, \"merge-form1.pdf\")\n    merge_file2 = os.path.join(resources, \"merge-form2.pdf\")\n    tar = pymupdf.open(merge_file1)\n    rc0 = names_and_kids(tar)  # list of root names and kid counts\n    names0 = [itm[\"name\"] for itm in rc0]  # root names in target\n    kids0 = sum([itm[\"kids\"] for itm in rc0])  # number of kids in target\n\n    src = pymupdf.open(merge_file2)\n    rc1 = names_and_kids(src)  # list of root namesand kids in source PDF\n    dup_count = 0  # counts duplicate names in source PDF\n    dup_kids = 0  # counts the expected kids after merge\n\n    for itm in rc1:  # walk root fields of source pdf\n        if itm[\"name\"] not in names0:  # not a duplicate name\n            continue\n        # if target field has kids, add their count, else add 1\n        dup_kids0 = sum([i[\"kids\"] for i in rc0 if i[\"name\"] == itm[\"name\"]])\n        dup_kids += dup_kids0 if dup_kids0 else 1\n        # if source field has kids add their count, else add 1\n        dup_kids += itm[\"kids\"] if itm[\"kids\"] else 1\n\n    names1 = [itm[\"name\"] for itm in rc1]  # names in source\n\n    tar.insert_pdf(src, join_duplicates=True)  # join merging any duplicate names\n\n    rc2 = names_and_kids(tar)  # get names and kid counts in resulting PDF\n    names2 = [itm[\"name\"] for itm in rc2]  # resulting names in target\n    kids2 = sum([itm[\"kids\"] for itm in rc2])  # total resulting kid count\n\n    assert len(set(names0 + names1)) == len(names2)\n    assert kids2 == dup_kids\n\n\ntest_4412_path = os.path.normpath(f'{__file__}/../../tests/resources/test_4412.pdf')\n\ndef test_4412():\n    # This tests whether a page from a PDF containing widgets found in the wild\n    # can be inserted into a new document with default options (widget=True)\n    # and widget=False.\n    print()\n    for widget in True, False:\n        print(f'{widget=}', flush=1)\n        with pymupdf.open(test_4412_path) as doc, pymupdf.open() as new_doc:\n            buf = io.BytesIO()\n            new_doc.insert_pdf(doc, from_page=1, to_page=1)\n            new_doc.save(buf)\n            assert len(new_doc)==1\n\n\ndef test_4571():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4571.pdf')\n    path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4571_out.pdf')\n    with pymupdf.open() as newdocument:\n        with pymupdf.open(path) as document:\n            newdocument.insert_pdf(document)\n        newdocument.save(path_out, garbage=4, clean=False)\n        print(f'Have saved to: {path_out=}')\n    with open(path_out, 'rb') as f:\n        content = f.read()\n    if pymupdf.mupdf_version_tuple >= (1, 26, 6):\n        # Correct.\n        assert b'<</Type/Pages/Count 6/Kids[4 0 R 6 0 R 12 0 R 13 0 R 14 0 R 15 0 R]>>' in content\n    else:\n        # Incorrect.\n        assert b'<</Type/Pages/Count 6/Kids[4 0 R 6 0 R 12 0 R 4 0 R 6 0 R 12 0 R]>>' in content\n\n\ndef test_4958():\n    print()\n    with pymupdf.Document() as document_orig, pymupdf.Document() as document_copy:\n        document_orig.new_page()\n        document_orig[0].set_rotation(90)\n        document_orig[0].insert_link(\n                {\n                    'kind': 2,\n                    'from': pymupdf.Rect(10, 20, 40, 60),\n                    'uri': 'https://example.org'\n                }\n                )\n\n        document_copy.insert_pdf(document_orig, links=True)\n        \n        path_orig = os.path.normpath(f'{__file__}/../../tests/test_4958_out_orig.pdf')\n        path_copy = os.path.normpath(f'{__file__}/../../tests/test_4958_out_copy.pdf')\n        \n        document_orig.save(path_orig)\n        document_copy.save(path_copy)\n        \n        print(f'Have created {path_orig=}')\n        print(f'Have created {path_copy=}')\n        \n        from_rects_orig = [l['from'] for l in document_orig[0].get_links()]\n        from_rects_copy = [l['from'] for l in document_copy[0].get_links()]\n        \n        print(f'test_4958(): orig: {from_rects_orig}')\n        print(f'test_4958(): copy: {from_rects_copy}')\n        assert from_rects_orig == from_rects_copy\n"
  },
  {
    "path": "tests/test_linebreaks.py",
    "content": "import pymupdf\n\nimport os.path\n\n\ndef test_linebreaks():\n    \"\"\"Test avoidance of linebreaks.\"\"\"\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/test-linebreaks.pdf\")\n    doc = pymupdf.open(path)\n    page = doc[0]\n    tp = page.get_textpage(flags=pymupdf.TEXTFLAGS_WORDS)\n    word_count = len(page.get_text(\"words\", textpage=tp))\n    line_count1 = len(page.get_text(textpage=tp).splitlines())\n    line_count2 = len(page.get_text(sort=True, textpage=tp).splitlines())\n    assert word_count == line_count1\n    assert line_count2 < line_count1 / 2\n"
  },
  {
    "path": "tests/test_linequad.py",
    "content": "\"\"\"\nCheck approx. equality of search quads versus quads recovered from\ntext extractions.\n\"\"\"\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"quad-calc-0.pdf\")\n\n\ndef test_quadcalc():\n    text = \" angle 327\"  # search for this text\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    # This special page has one block with one line, and\n    # its last span contains the searched text.\n    block = page.get_text(\"dict\", flags=0)[\"blocks\"][0]\n    line = block[\"lines\"][0]\n    # compute quad of last span in line\n    lineq = pymupdf.recover_line_quad(line, spans=line[\"spans\"][-1:])\n\n    # let text search find the text returning quad coordinates\n    rl = page.search_for(text, quads=True)\n    searchq = rl[0]\n    assert abs(searchq.ul - lineq.ul) <= 1e-4\n    assert abs(searchq.ur - lineq.ur) <= 1e-4\n    assert abs(searchq.ll - lineq.ll) <= 1e-4\n    assert abs(searchq.lr - lineq.lr) <= 1e-4\n"
  },
  {
    "path": "tests/test_memory.py",
    "content": "import pymupdf\nimport util\n\nimport gc\nimport os\nimport platform\nimport sys\n\n\ndef merge_pdf(content: bytes, coverpage: bytes):\n   with pymupdf.Document(stream=coverpage, filetype='pdf') as coverpage_pdf:\n        with pymupdf.Document(stream=content, filetype='pdf') as content_pdf:\n            coverpage_pdf.insert_pdf(content_pdf)\n            doc = coverpage_pdf.write()\n            return doc\n\ndef test_2791():\n    '''\n    Check for memory leaks.\n    '''\n    if util.skip_slow_tests('test_2791'):\n        return\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_2791(): not running on Pyodide - No module named \\'psutil\\'.')\n        return\n        \n    if os.environ.get('PYMUPDF_RUNNING_ON_VALGRIND') == '1':\n        print(f'test_2791(): not running because PYMUPDF_RUNNING_ON_VALGRIND=1.')\n        return\n    if platform.system().startswith('MSYS_NT-'):\n        print(f'test_2791(): not running on msys2 - psutil not available.')\n        return\n    #stat_type = 'tracemalloc'\n    stat_type = 'psutil'\n    if stat_type == 'tracemalloc':\n        import tracemalloc\n        tracemalloc.start(10)\n        def get_stat():\n            current, peak = tracemalloc.get_traced_memory()\n            return current\n    elif stat_type == 'psutil':\n        # We use RSS, as used by mprof.\n        import psutil\n        process = psutil.Process()\n        def get_stat():\n            return process.memory_info().rss\n    else:\n        def get_stat():\n            return 0\n    n = 1000\n    verbose = False\n    if platform.python_implementation() == 'GraalVM':\n        n = 10\n        verbose = True\n    stats = [1] * n\n    for i in range(n):\n        if verbose:\n            print(f'{i+1}/{n}.', flush=1)\n        root = os.path.abspath(f'{__file__}/../../tests/resources')  \n        with open(f'{root}/test_2791_content.pdf', 'rb') as content_pdf:\n            with open(f'{root}/test_2791_coverpage.pdf', 'rb') as coverpage_pdf:\n                content = content_pdf.read()\n                coverpage = coverpage_pdf.read()\n                merge_pdf(content, coverpage)\n                sys.stdout.flush()\n        \n        gc.collect()\n        stats[i] = get_stat()\n\n    print(f'Memory usage {stat_type=}.')\n    for i, stat in enumerate(stats):\n        sys.stdout.write(f' {stat}')\n        #print(f'    {i}: {stat}')\n    sys.stdout.write('\\n')\n    first = stats[2]\n    last = stats[-1]\n    ratio = last / first\n    print(f'{first=} {last=} {ratio=}')\n\n    if platform.system() != 'Linux':\n        # Values from psutil indicate larger memory leaks on non-Linux. Don't\n        # yet know whether this is because rss is measured differently or a\n        # genuine leak is being exposed.\n        print(f'test_2791(): not asserting ratio because not running on Linux.')\n    elif not hasattr(pymupdf, 'mupdf'):\n        # Classic implementation has unfixed leaks.\n        print(f'test_2791(): not asserting ratio because using classic implementation.')\n    elif [int(x) for x in platform.python_version_tuple()[:2]] < [3, 11]:\n        print(f'test_2791(): not asserting ratio because python version less than 3.11: {platform.python_version()=}.')\n    elif stat_type == 'tracemalloc':\n        # With tracemalloc Before fix to src/extra.i's calls to\n        # PyObject_CallMethodObjArgs, ratio was 4.26; after it was 1.40.\n        assert ratio > 1 and ratio < 1.6\n    elif stat_type == 'psutil':\n        # Prior to fix, ratio was 1.043. After the fix, improved to 1.005, but\n        # varies and sometimes as high as 1.010.\n        # 2024-06-03: have seen 0.99919 on musl linux, and sebras reports .025.\n        assert ratio >= 0.990 and ratio < 1.027, f'{ratio=}'\n    else:\n        pass\n\n\ndef test_4090():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4090(): not running on Pyodide - No module named \\'psutil\\'.')\n        return\n        \n    print(f'test_4090(): {os.environ.get(\"PYTHONMALLOC\")=}.')\n    import psutil\n    process = psutil.Process()\n    rsss = list()\n    def rss():\n        ret = process.memory_info().rss\n        rsss.append(ret)\n        return ret\n        \n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4090.pdf')\n    for i in range(100):\n        d = dict()\n        d[i] = dict()\n        with pymupdf.open(path) as document:\n            for j, page in enumerate(document):\n                d[i][j] = page.get_text('rawdict')\n        print(f'test_4090(): {i}: {rss()=}')\n    print(f'test_4090(): {rss()=}')\n    gc.collect()\n    print(f'test_4090(): {rss()=}')\n    r1 = rsss[2]\n    r2 = rsss[-1]\n    r = r2 / r1\n    if platform.system() == 'Windows':\n        assert 0.93 <= r < 1.05, f'{r1=} {r2=} {r=}.'\n    else:\n        assert 0.95 <= r < 1.05, f'{r1=} {r2=} {r=}.'\n\n\ndef show_tracemalloc_diff(snapshot1, snapshot2):\n    top_stats = snapshot2.compare_to(snapshot1, 'lineno')\n    n = 0\n    mem = 0\n    for i in top_stats:\n        n += i.count\n        mem += i.size\n    print(f'{n=}')\n    print(f'{mem=}')\n    print(\"Top 10:\")\n    for stat in top_stats[:10]:\n        print(f'    {stat}')\n    snapshot_diff = snapshot2.compare_to(snapshot1, key_type='lineno')\n    print(f'snapshot_diff:')\n    count_diff = 0\n    size_diff = 0\n    for i, s in enumerate(snapshot_diff):\n        print(f'    {i}: {s.count=} {s.count_diff=} {s.size=} {s.size_diff=} {s.traceback=}')\n        count_diff += s.count_diff\n        size_diff += s.size_diff\n    print(f'{count_diff=} {size_diff=}')\n    \n\n\ndef test_4125():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4125(): not running on Pyodide - No module named \\'psutil\\'.')\n        return\n        \n    if os.environ.get('PYMUPDF_RUNNING_ON_VALGRIND') == '1':\n        print(f'test_4125(): not running because PYMUPDF_RUNNING_ON_VALGRIND=1.')\n        return\n    if platform.system().startswith('MSYS_NT-'):\n        print(f'test_4125(): not running on msys2 - psutil not available.')\n        return\n    \n    print('')\n    print(f'test_4125(): {platform.python_version()=}.')\n    \n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4125.pdf')\n    import gc\n    import psutil\n    \n    root = os.path.normpath(f'{__file__}/../..')\n    import pipcl\n    \n    process = psutil.Process()\n    \n    class State: pass\n    state = State()\n    state.rsss = list()\n    state.prev = None\n    \n    def get_stat():\n        rss = process.memory_info().rss\n        if not state.rsss:\n            state.prev = rss\n        state.rsss.append(rss)\n        drss = rss - state.prev\n        state.prev = rss\n        print(f'test_4125():'\n                f' {rss=:,}'\n                f' rss-rss0={rss-state.rsss[0]:,}'\n                f' drss={drss:,}'\n                f'.'\n                )\n    \n    for i in range(10):\n        with pymupdf.open(path) as document:\n            for page in document:\n                for image_info in page.get_images(full=True):\n                    xref, smask, width, height, bpc, colorspace, alt_colorspace, name, filter_, referencer = image_info\n                    pixmap = pymupdf.Pixmap(document, xref)\n                    if pixmap.colorspace != pymupdf.csRGB:\n                        pixmap2 = pymupdf.Pixmap(pymupdf.csRGB, pixmap)\n                        del pixmap2\n                    del pixmap\n        pymupdf.TOOLS.store_shrink(100)\n        pymupdf.TOOLS.glyph_cache_empty()\n        gc.collect()\n        get_stat()\n    \n    if platform.system() == 'Linux':\n        rss_delta = state.rsss[-1] - state.rsss[3]\n        print(f'{rss_delta=}')\n        pv = platform.python_version_tuple()\n        pv = (int(pv[0]), int(pv[1]))\n        if pv < (3, 11):\n            # Python < 3.11 has less reliable memory usage so we exclude.\n            print(f'test_4125(): Not checking on {platform.python_version()=} because < 3.11.')\n        else:\n            # Before the fix, each iteration would leak 4.9MB.\n            rss_delta_max = 100*1000 * (len(state.rsss) - 3)\n            assert rss_delta < rss_delta_max\n    else:\n        # Unfortunately on non-Linux Github test machines the RSS values seem\n        # to vary a lot, which causes spurious test failures. So for at least\n        # we don't actually check.\n        #\n        print(f'Not checking results because non-Linux behaviour is too variable.')\n\n\ndef _test_4751():\n    import gc\n    import tracemalloc\n    \n    def analysis(stream_data, do_iter=True):\n        pdf_info = pymupdf.Document(stream=stream_data, filetype='pdf')\n        tmp_list = range(len(pdf_info))\n        for page_num in tmp_list:\n            page = pdf_info[page_num]\n            raw_info = page.get_text('rawdict')['blocks']\n            page_widgets_list = page.widgets() \n            if do_iter:\n                for widget_info in page_widgets_list:\n                    print(widget_info)\n            del page_widgets_list\n        pdf_info.close()\n        pdf_info = None\n        pymupdf.TOOLS.store_shrink(100)\n\n    file_path = os.path.normpath(f'{__file__}/../../tests/resources/test_4751.pdf')\n    \n    def log(text):\n        print(text, flush=1)\n\n    # We filter out all allocations where leaf-most frame is in tracemalloc\n    # itself, or in test_memory.py itself, because these are not relevant\n    # to finding leaks in pymupdf.\n    #\n    tm_filters = [\n            tracemalloc.Filter(inclusive=False, filename_pattern=tracemalloc.__file__, all_frames=True),\n            tracemalloc.Filter(inclusive=False, filename_pattern=__file__),\n            ]\n\n    def get_snapshot():\n        '''\n        Wrapper for tracemalloc.take_snapshot() that filters out blocks with\n        backtraces that we are not interested in.\n        '''\n        ret = tracemalloc.take_snapshot()\n        ret2 = ret.filter_traces(tm_filters)\n        #log(f'    {len(ret.traces)=} => {len(ret2.traces)=}')\n        return ret2\n\n    # Check that `analysis()` does not leak.\n    #\n    num_leaks = 0\n    with open(file_path,'rb') as f:\n        bytes_data = f.read()\n    \n    tracemalloc.start(30)\n    snapshot_prev = get_snapshot()\n    \n    for it in range(2):\n        log('')\n        log(f'{it=}')\n        \n        current, peak = tracemalloc.get_traced_memory()\n        log(f'    {current=} {peak=}')\n        \n        analysis(bytes_data)\n        gc.collect()\n        snapshot = get_snapshot()\n        \n        top_stats = snapshot.compare_to(snapshot_prev, 'traceback')\n        snapshot_prev = snapshot\n        \n        top_stats = sorted(top_stats, key=lambda x: -x.size_diff)\n        for block_num, stat in enumerate(top_stats[0:10]):\n            if stat.size_diff > 0:\n                log(f'    Leak detected')\n                log(f'    {block_num=} {stat.size_diff=}: {stat}')\n                bt = ''\n                for frame in stat.traceback:\n                    bt += f'        {frame.filename}:{frame.lineno}\\n'\n                log(bt)\n                # We ignore extra allocations in the first iteration.\n                if it != 0:\n                    num_leaks += 1\n    \n    assert not num_leaks, f'{num_leaks=}'\n\n\ndef test_4751():\n    # We run the actual test in a child process, because otherwise previous\n    # tests seem to effect the leak detection causing false positives. It's\n    # possible that these could be real leaks, but they are not the ones\n    # we are testing for here.\n    #\n    if os.path.basename(__file__).startswith(f'test_fitz_'):\n        # Don't test the `fitz` alias, because we assume our leafname.\n        print(f'test_4751(): Not testing with fitz alias.')\n        return\n    \n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4751(): not running on Pyodide - cannot run child processes.')\n        return\n    \n    GITHUB_ACTIONS = os.environ.get('GITHUB_ACTIONS')\n    if GITHUB_ACTIONS == 'true':\n        # We see additional leaks on Github, don't know why.\n        print(f'test_4751(): {GITHUB_ACTIONS=}; not running on Github because known to fail.')\n        return\n    \n    python_version = [int(i) for i in platform.python_version_tuple()[:2]]\n    python_version_tuple = tuple(python_version)\n    if python_version_tuple < (3, 13):\n        # We see additional leaks with python-3.12.\n        print(f'test_4751(): not running because known to fail on python < 3.13: {platform.python_version_tuple()=}')\n        return\n    \n    import subprocess\n    env_extra = dict(PYTHONPATH = os.path.abspath(f'{__file__}/..'))\n    command = f'{sys.executable} -c \"import test_memory; test_memory._test_4751()\"'\n    print('', flush=1)\n    print(f'test_4751(): Running: {command!r}', flush=1)\n    print(f'test_4751(): With: {env_extra=}', flush=1)\n    subprocess.run(command, shell=1, check=1, env=os.environ | env_extra)\n"
  },
  {
    "path": "tests/test_metadata.py",
    "content": "\"\"\"\n1. Read metadata and compare with stored expected result.\n2. Erase metadata and assert object has indeed been deleted.\n\"\"\"\nimport json\nimport os\nimport sys\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"001003ED.pdf\")\nmetafile = os.path.join(scriptdir, \"resources\", \"metadata.txt\")\ndoc = pymupdf.open(filename)\n\n\ndef test_metadata():\n    assert json.dumps(doc.metadata) == open(metafile).read()\n\n\ndef test_erase_meta():\n    doc.set_metadata({})\n    # Check PDF trailer and assert that there is no more /Info object\n    # or is set to \"null\".\n    statement1 = doc.xref_get_key(-1, \"Info\")[1] == \"null\"\n    statement2 = \"Info\" not in doc.xref_get_keys(-1)\n    assert statement2 or statement1\n\n\ndef test_3237():\n    filename = os.path.abspath(f'{__file__}/../../tests/resources/001003ED.pdf')\n    with pymupdf.open(filename) as doc:\n        # We need to explicitly encode in utf8 on windows.\n        metadata1 = doc.metadata\n        metadata1 = repr(metadata1).encode('utf8')\n        doc.set_metadata({})\n\n        metadata2 = doc.metadata\n        metadata2 = repr(metadata2).encode('utf8')\n        print(f'{metadata1=}')\n        print(f'{metadata2=}')\n        assert metadata1 == b'{\\'format\\': \\'PDF 1.6\\', \\'title\\': \\'RUBRIK_Editorial_01-06.indd\\', \\'author\\': \\'Natalie Schaefer\\', \\'subject\\': \\'\\', \\'keywords\\': \\'\\', \\'creator\\': \\'\\', \\'producer\\': \\'Acrobat Distiller 7.0.5 (Windows)\\', \\'creationDate\\': \"D:20070113191400+01\\'00\\'\", \\'modDate\\': \"D:20070120104154+01\\'00\\'\", \\'trapped\\': \\'\\', \\'encryption\\': None}'\n        assert metadata2 == b\"{'format': 'PDF 1.6', 'title': '', 'author': '', 'subject': '', 'keywords': '', 'creator': '', 'producer': '', 'creationDate': '', 'modDate': '', 'trapped': '', 'encryption': None}\"\n"
  },
  {
    "path": "tests/test_mupdf_regressions.py",
    "content": "import pymupdf\nimport os\nimport gentle_compare\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\n\n\ndef test_707448():\n    \"\"\"Confirm page content cleaning does not destroy page appearance.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-707448.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    words0 = page.get_text(\"words\")\n    page.clean_contents(sanitize=True)\n    words1 = page.get_text(\"words\")\n    assert gentle_compare.gentle_compare(words0, words1)\n\n\ndef test_707673():\n    \"\"\"Confirm page content cleaning does not destroy page appearance.\n\n    Fails starting with MuPDF v1.23.9.\n\n    Fixed in:\n    commit 779b8234529cb82aa1e92826854c7bb98b19e44b (golden/master)\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-707673.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    words0 = page.get_text(\"words\")\n    page.clean_contents(sanitize=True)\n    words1 = page.get_text(\"words\")\n    ok = gentle_compare.gentle_compare(words0, words1)\n    assert ok\n\n\ndef test_707727():\n    \"\"\"Confirm page content cleaning does not destroy page appearance.\n\n    MuPDF issue: https://bugs.ghostscript.com/show_bug.cgi?id=707727\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test_3362.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    pix0 = page.get_pixmap()\n    page.clean_contents(sanitize=True)\n    page = doc.reload_page(page)  # required to prevent re-use\n    pix1 = page.get_pixmap()\n    rms = gentle_compare.pixmaps_rms(pix0, pix1)\n    print(f'{rms=}', flush=1)\n    pix0.save(os.path.normpath(f'{__file__}/../../tests/test_707727_pix0.png'))\n    pix1.save(os.path.normpath(f'{__file__}/../../tests/test_707727_pix1.png'))\n    # New sanitising gives small fp rounding errors.\n    assert rms < 0.05\n\n\ndef test_707721():\n    \"\"\"Confirm text extraction works for nested MCID with Type 3 fonts.\n    PyMuPDF issue https://github.com/pymupdf/PyMuPDF/issues/3357\n    MuPDF issue: https://bugs.ghostscript.com/show_bug.cgi?id=707721\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test_3357.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    ok = page.get_text()\n    assert ok\n\n\ndef test_3376():\n    \"\"\"Check fix of MuPDF bug 707733.\n\n    https://bugs.ghostscript.com/show_bug.cgi?id=707733\n    PyMuPDF issue https://github.com/pymupdf/PyMuPDF/issues/3376\n\n    Test file contains a redaction for the first 3 words: \"Table of Contents\".\n    Test strategy:\n    - extract all words (sorted)\n    - apply redactions\n    - extract words again\n    - confirm: we now have 3 words less and remaining words are equal.\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test_3376.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    words0 = page.get_text(\"words\", sort=True)\n    words0_s = words0[:3]  # first 3 words\n    words0_e = words0[3:]  # remaining words\n    assert \" \".join([w[4] for w in words0_s]) == \"Table of Contents\"\n\n    page.apply_redactions()\n\n    words1 = page.get_text(\"words\", sort=True)\n\n    ok = gentle_compare.gentle_compare(words0_e, words1)\n    assert ok\n"
  },
  {
    "path": "tests/test_named_links.py",
    "content": "import pymupdf\n\nimport os\n\n\ndef test_2886():\n    \"\"\"Confirm correct insertion of a 'named' link.\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(f\"test_2886(): not running on classic.\")\n        return\n\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/cython.pdf\")\n    doc = pymupdf.open(path)\n    # name \"Doc-Start\" is a valid named destination in that file\n    link = {\n        \"kind\": pymupdf.LINK_NAMED,\n        \"from\": pymupdf.Rect(0, 0, 50, 50),\n        \"name\": \"Doc-Start\",\n    }\n    # insert this link in an arbitrary page & rect\n    page = doc[-1]\n    page.insert_link(link)\n    # need this to update the internal MuPDF annotations array\n    page = doc.reload_page(page)\n\n    # our new link must be the last in the following list\n    links = page.get_links()\n    l_dict = links[-1]\n    assert l_dict[\"kind\"] == pymupdf.LINK_NAMED\n    assert l_dict[\"nameddest\"] == link[\"name\"]\n    assert l_dict[\"from\"] == link[\"from\"]\n\n\ndef test_2922():\n    \"\"\"Confirm correct recycling of a 'named' link.\n\n    Re-insertion of a named link item in 'Page.get_links()' does not have\n    the required \"name\" key. We test the fallback here that uses key\n    \"nameddest\" instead.\n    \"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(f\"test_2922(): not running on classic.\")\n        return\n\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/cython.pdf\")\n    doc = pymupdf.open(path)\n    page = doc[2]  # page has a few links, all are named\n    links = page.get_links()  # list of all links\n    link0 = links[0]  # take arbitrary link (1st one is ok)\n    page.insert_link(link0)  # insert it again\n    page = doc.reload_page(page)  # ensure page updates\n    links = page.get_links()  # access all links again\n    link1 = links[-1]  # re-inserted link\n\n    # confirm equality of relevant key-values\n    assert link0[\"nameddest\"] == link1[\"nameddest\"]\n    assert link0[\"page\"] == link1[\"page\"]\n    assert link0[\"to\"] == link1[\"to\"]\n    assert link0[\"from\"] == link1[\"from\"]\n\n\ndef test_3301():\n    \"\"\"Test correct differentiation between URI and LAUNCH links.\n\n    Links encoded as /URI in PDF are converted to either LINK_URI or\n    LINK_LAUNCH in PyMuPDF.\n    This function ensures that the 'Link.uri' containing a ':' colon\n    is converted to a URI if not explicitly starting with \"file://\".\n    \"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(f\"test_3301(): not running on classic.\")\n        return\n\n    # list of links and their expected link \"kind\" upon extraction\n    text = {\n        \"https://www.google.de\": pymupdf.LINK_URI,\n        \"http://www.google.de\": pymupdf.LINK_URI,\n        \"mailto:jorj.x.mckie@outlook.de\": pymupdf.LINK_URI,\n        \"www.wikipedia.de\": pymupdf.LINK_LAUNCH,\n        \"awkward:resource\": pymupdf.LINK_URI,\n        \"ftp://www.google.de\": pymupdf.LINK_URI,\n        \"some.program\": pymupdf.LINK_LAUNCH,\n        \"file://some.program\": pymupdf.LINK_LAUNCH,\n        \"another.exe\": pymupdf.LINK_LAUNCH,\n    }\n\n    # make enough \"from\" rectangles\n    r = pymupdf.Rect(0, 0, 50, 20)\n    rects = [r + (0, r.height * i, 0, r.height * i) for i in range(len(text.keys()))]\n\n    # make test page and insert above links as kind=LINK_URI\n    doc = pymupdf.open()\n    page = doc.new_page()\n    for i, k in enumerate(text.keys()):\n        link = {\"kind\": pymupdf.LINK_URI, \"uri\": k, \"from\": rects[i]}\n        page.insert_link(link)\n\n    # re-cycle the PDF preparing for link extraction\n    pdfdata = doc.write()\n    doc = pymupdf.open(\"pdf\", pdfdata)\n    page = doc[0]\n    for link in page.get_links():\n        # Extract the link text. Must be 'file' or 'uri'.\n        t = link[\"uri\"] if (_ := link.get(\"file\")) is None else _\n        assert text[t] == link[\"kind\"]\n"
  },
  {
    "path": "tests/test_nonpdf.py",
    "content": "\"\"\"\n* Check EPUB document is no PDF\n* Check page access using (chapter, page) notation\n* Re-layout EPUB ensuring a previous location is memorized\n\"\"\"\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"Bezier.epub\")\ndoc = pymupdf.open(filename)\n\n\ndef test_isnopdf():\n    assert not doc.is_pdf\n\n\ndef test_pageids():\n    assert doc.chapter_count == 7\n    assert doc.last_location == (6, 1)\n    assert doc.prev_location((6, 0)) == (5, 11)\n    assert doc.next_location((5, 11)) == (6, 0)\n    # Check page numbers have no gaps:\n    i = 0\n    for chapter in range(doc.chapter_count):\n        for cpno in range(doc.chapter_page_count(chapter)):\n            assert doc.page_number_from_location((chapter, cpno)) == i\n            i += 1\n\ndef test_layout():\n    \"\"\"Memorize a page location, re-layout with ISO-A4, assert pre-determined location.\"\"\"\n    loc = doc.make_bookmark((5, 11))\n    doc.layout(pymupdf.Rect(pymupdf.paper_rect(\"a4\")))\n    assert doc.find_bookmark(loc) == (5, 6)\n"
  },
  {
    "path": "tests/test_object_manipulation.py",
    "content": "\"\"\"\nCheck some low-level PDF object manipulations:\n1. Set page rotation and compare with string in object definition.\n2. Set page rotation via string manipulation and compare with result of\n   proper page property.\n3. Read the PDF trailer and verify it has the keys \"/Root\", \"/ID\", etc.\n\"\"\"\nimport pymupdf\nimport os\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nresources = os.path.join(scriptdir, \"resources\")\nfilename = os.path.join(resources, \"001003ED.pdf\")\n\n\ndef test_rotation1():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    page.set_rotation(270)\n    assert doc.xref_get_key(page.xref, \"Rotate\") == (\"int\", \"270\")\n\n\ndef test_rotation2():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    doc.xref_set_key(page.xref, \"Rotate\", \"270\")\n    assert page.rotation == 270\n\n\ndef test_trailer():\n    \"\"\"Access PDF trailer information.\"\"\"\n    doc = pymupdf.open(filename)\n    xreflen = doc.xref_length()\n    _, xreflen_str = doc.xref_get_key(-1, \"Size\")\n    assert xreflen == int(xreflen_str)\n    trailer_keys = doc.xref_get_keys(-1)\n    assert \"ID\" in trailer_keys\n    assert \"Root\" in trailer_keys\n\n\ndef test_valid_name():\n    \"\"\"Verify correct PDF names in method xref_set_key.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    # testing name in \"key\": confirm correct spec is accepted\n    doc.xref_set_key(page.xref, \"Rotate\", \"90\")\n    assert page.rotation == 90\n\n    # check wrong spec is detected\n    error_generated = False\n    try:\n        # illegal char in name (white space)\n        doc.xref_set_key(page.xref, \"my rotate\", \"90\")\n    except ValueError as e:\n        assert str(e) == \"bad 'key'\"\n        error_generated = True\n    assert error_generated\n\n    # test name in \"value\": confirm correct spec is accepted\n    doc.xref_set_key(page.xref, \"my_rotate/something\", \"90\")\n    assert doc.xref_get_key(page.xref, \"my_rotate/something\") == (\"int\", \"90\")\n    doc.xref_set_key(page.xref, \"my_rotate\", \"/90\")\n    assert doc.xref_get_key(page.xref, \"my_rotate\") == (\"name\", \"/90\")\n\n    # check wrong spec is detected\n    error_generated = False\n    try:\n        # no slash inside name allowed\n        doc.xref_set_key(page.xref, \"my_rotate\", \"/9/0\")\n    except ValueError as e:\n        assert str(e) == \"bad 'value'\"\n        error_generated = True\n    assert error_generated\n"
  },
  {
    "path": "tests/test_objectstreams.py",
    "content": "import pymupdf\n\n\ndef test_objectstream1():\n    \"\"\"Test save option \"use_objstms\".\n    This option compresses PDF object definitions into a special object type\n    \"ObjStm\". We test its presence by searching for that /Type.\n    \"\"\"\n    # make some arbitrary page with content\n    text = \"Hello, World! Hallo, Welt!\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = (50, 50, 200, 500)\n\n    page.insert_htmlbox(rect, text)  # place into the rectangle\n    _ = doc.write(use_objstms=True)\n    found = False\n    for xref in range(1, doc.xref_length()):\n        objstring = doc.xref_object(xref, compressed=True)\n        if \"/Type/ObjStm\" in objstring:\n            found = True\n            break\n    assert found, \"No object stream found\"\n\n\ndef test_objectstream2():\n    \"\"\"Test save option \"use_objstms\".\n    This option compresses PDF object definitions into a special object type\n    \"ObjStm\". We test its presence by searching for that /Type.\n    \"\"\"\n    # make some arbitrary page with content\n    text = \"Hello, World! Hallo, Welt!\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = (50, 50, 200, 500)\n\n    page.insert_htmlbox(rect, text)  # place into the rectangle\n    _ = doc.write(use_objstms=False)\n\n    found = False\n    for xref in range(1, doc.xref_length()):\n        objstring = doc.xref_object(xref, compressed=True)\n        if \"/Type/ObjStm\" in objstring:\n            found = True\n            break\n    assert not found, \"Unexpected: Object stream found!\"\n\n\ndef test_objectstream3():\n    \"\"\"Test ez_save().\n    Should automatically use object streams\n    \"\"\"\n    import io\n\n    fp = io.BytesIO()\n\n    # make some arbitrary page with content\n    text = \"Hello, World! Hallo, Welt!\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = (50, 50, 200, 500)\n\n    page.insert_htmlbox(rect, text)  # place into the rectangle\n\n    doc.ez_save(fp)  # save PDF to memory\n    found = False\n    for xref in range(1, doc.xref_length()):\n        objstring = doc.xref_object(xref, compressed=True)\n        if \"/Type/ObjStm\" in objstring:\n            found = True\n            break\n    assert found, \"No object stream found!\"\n"
  },
  {
    "path": "tests/test_optional_content.py",
    "content": "\"\"\"\nTest of Optional Content code.\n\"\"\"\n\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"joined.pdf\")\n\n\ndef test_oc1():\n    \"\"\"Arbitrary calls to OC code to get coverage.\"\"\"\n    doc = pymupdf.open()\n    ocg1 = doc.add_ocg(\"ocg1\")\n    ocg2 = doc.add_ocg(\"ocg2\")\n    ocg3 = doc.add_ocg(\"ocg3\")\n    ocmd1 = doc.set_ocmd(xref=0, ocgs=(ocg1, ocg2))\n    doc.set_layer(-1)\n    doc.add_layer(\"layer1\")\n    test = doc.get_layer()\n    test = doc.get_layers()\n    test = doc.get_ocgs()\n    test = doc.layer_ui_configs()\n    doc.switch_layer(0)\n\n\ndef test_oc2():\n    # source file with at least 4 pages\n    src = pymupdf.open(filename)\n\n    # new PDF with one page\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    # define the 4 rectangle quadrants to receive the source pages\n    r0 = page.rect / 2\n    r1 = r0 + (r0.width, 0, r0.width, 0)\n    r2 = r0 + (0, r0.height, 0, r0.height)\n    r3 = r2 + (r2.width, 0, r2.width, 0)\n\n    # make 4 OCGs - one for each source page image.\n    # only first is ON initially\n    ocg0 = doc.add_ocg(\"ocg0\", on=True)\n    ocg1 = doc.add_ocg(\"ocg1\", on=False)\n    ocg2 = doc.add_ocg(\"ocg2\", on=False)\n    ocg3 = doc.add_ocg(\"ocg3\", on=False)\n\n    ocmd0 = doc.set_ocmd(ve=[\"and\", ocg0, [\"not\", [\"or\", ocg1, ocg2, ocg3]]])\n    ocmd1 = doc.set_ocmd(ve=[\"and\", ocg1, [\"not\", [\"or\", ocg0, ocg2, ocg3]]])\n    ocmd2 = doc.set_ocmd(ve=[\"and\", ocg2, [\"not\", [\"or\", ocg1, ocg0, ocg3]]])\n    ocmd3 = doc.set_ocmd(ve=[\"and\", ocg3, [\"not\", [\"or\", ocg1, ocg2, ocg0]]])\n    ocmds = (ocmd0, ocmd1, ocmd2, ocmd3)\n    # insert the 4 source page images, each connected to one OCG\n    page.show_pdf_page(r0, src, 0, oc=ocmd0)\n    page.show_pdf_page(r1, src, 1, oc=ocmd1)\n    page.show_pdf_page(r2, src, 2, oc=ocmd2)\n    page.show_pdf_page(r3, src, 3, oc=ocmd3)\n    xobj_ocmds = [doc.get_oc(item[0]) for item in page.get_xobjects() if item[1] != 0]\n    assert set(ocmds) <= set(xobj_ocmds)\n    assert set((ocg0, ocg1, ocg2, ocg3)) == set(tuple(doc.get_ocgs().keys()))\n    doc.get_ocmd(ocmd0)\n    page.get_oc_items()\n\n\ndef test_3143():\n    \"\"\"Support for non-ascii layer names.\"\"\"\n    doc = pymupdf.open(os.path.join(scriptdir, \"resources\", \"test-3143.pdf\"))\n    page = doc[0]\n    set0 = set([l[\"text\"] for l in doc.layer_ui_configs()])\n    set1 = set([p[\"layer\"] for p in page.get_drawings()])\n    set2 = set([b[2] for b in page.get_bboxlog(layers=True)])\n    assert set0 == set1 == set2\n\n\ndef test_3180():\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    # Define the items for the combo box\n    combo_items = ['first', 'second', 'third']\n\n    # Create a combo box field\n    combo_box = pymupdf.Widget()  # create a new widget\n    combo_box.field_type = pymupdf.PDF_WIDGET_TYPE_COMBOBOX\n    combo_box.field_name = \"myComboBox\"\n    combo_box.field_value = combo_items[0]\n    combo_box.choice_values = combo_items\n    combo_box.rect = pymupdf.Rect(50, 50, 200, 75)  # position of the combo box\n    combo_box.script_change = \"\"\"\n    var value = event.value;\n    app.alert('You selected: ' + value);\n\n    //var group_id = optional_content_group_ids[value];\n\n    \"\"\"\n\n    # Insert the combo box into the page\n    # https://pymupdf.readthedocs.io/en/latest/page.html#Page.add_widget\n    page.add_widget(combo_box)\n\n    # Create optional content groups\n    # https://github.com/pymupdf/PyMuPDF-Utilities/blob/master/jupyter-notebooks/optional-content.ipynb\n\n\n    # Load images and create OCGs for each\n    optional_content_group_ids = {}\n    for i, item in enumerate(combo_items):\n        optional_content_group_id = doc.add_ocg(item, on=False)\n        optional_content_group_ids[item] = optional_content_group_id\n        rect = pymupdf.Rect(50, 100, 250, 300)\n        image_file_name = f'{item}.png'\n        # xref = page.insert_image(\n        #    rect,\n        #    filename=image_file_name,\n        #    oc=optional_content_group_id,\n        # )\n\n\n    first_id = optional_content_group_ids['first']\n    second_id = optional_content_group_ids['second']\n    third_id = optional_content_group_ids['third']\n\n    # https://pymupdf.readthedocs.io/en/latest/document.html#Document.set_layer\n\n\n    doc.set_layer(-1, basestate=\"OFF\")\n    layers = doc.get_layer()\n    doc.set_layer(config=-1, on=[first_id])\n\n    # https://pymupdf.readthedocs.io/en/latest/document.html#Document.set_layer_ui_config\n    # configs = doc.layer_ui_configs()\n    # doc.set_layer_ui_config(0, pymupdf.PDF_OC_ON)\n    # doc.set_layer_ui_config('third', action=2)\n\n    # Save the PDF\n    doc.save(os.path.abspath(f'{__file__}/../../tests/test_3180.pdf'))\n    doc.close()\n"
  },
  {
    "path": "tests/test_page_links.py",
    "content": "import pymupdf\n\nimport os\n\n\ndef test_page_links_generator():\n    # open some arbitrary PDF\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/2.pdf\")\n    doc = pymupdf.open(path)\n\n    # select an arbitrary page\n    page = doc[-1]\n\n    # iterate over pages.links\n    link_generator = page.links()\n    links = list(link_generator)\n    assert len(links) == 7\n"
  },
  {
    "path": "tests/test_pagedelete.py",
    "content": "\"\"\"\n----------------------------------------------------\nThis tests correct functioning of multi-page delete\n----------------------------------------------------\nCreate a PDF in memory with 100 pages with a unique text each.\nAlso create a TOC with a bookmark per page.\nOn every page after the first to-be-deleted page, also insert a link, which\npoints to this page.\nThe bookmark text equals the text on the page for easy verification.\n\nThen delete some pages and verify:\n- the new TOC has empty items exactly for every deleted page\n- the remaining TOC items still point to the correct page\n- the document has no more links at all\n\"\"\"\n\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.dirname(__file__)\npage_count = 100  # initial document length\nr = range(5, 35, 5)  # contains page numbers we will delete\n# insert this link on pages after first deleted one\nlink = {\n    \"from\": pymupdf.Rect(100, 100, 120, 120),\n    \"kind\": pymupdf.LINK_GOTO,\n    \"page\": r[0],\n    \"to\": pymupdf.Point(100, 100),\n}\n\n\ndef test_deletion():\n    # First prepare the document.\n    doc = pymupdf.open()\n    toc = []\n    for i in range(page_count):\n        page = doc.new_page()  # make a page\n        page.insert_text((100, 100), \"%i\" % i)  # insert unique text\n        if i > r[0]:  # insert a link\n            page.insert_link(link)\n        toc.append([1, \"%i\" % i, i + 1])  # TOC bookmark to this page\n\n    doc.set_toc(toc)  # insert the TOC\n    assert doc.has_links()  # check we did insert links\n\n    # Test page deletion.\n    # Delete pages in range and verify result\n    del doc[r]\n    assert not doc.has_links()  # verify all links have gone\n    assert doc.page_count == page_count - len(r)  # correct number deleted?\n    toc_new = doc.get_toc()  # this is the modified TOC\n    # verify number of emptied items (have page number -1)\n    assert len([item for item in toc_new if item[-1] == -1]) == len(r)\n    # Deleted page numbers must correspond to TOC items with page number -1.\n    for i in r:\n        assert toc_new[i][-1] == -1\n    # Remaining pages must be correctly pointed to by the non-empty TOC items\n    for item in toc_new:\n        pno = item[-1]\n        if pno == -1:  # one of the emptied items\n            continue\n        pno -= 1  # PDF page number\n        text = doc[pno].get_text().replace(\"\\n\", \"\")\n        # toc text must equal text on page\n        assert text == item[1]\n\n    doc.delete_page(0)  # just for the coverage stats\n    del doc[5:10]\n    doc.select(range(doc.page_count))\n    doc.copy_page(0)\n    doc.move_page(0)\n    doc.fullcopy_page(0)\n\n\ndef test_3094():\n    path = os.path.abspath(f\"{__file__}/../../tests/resources/test_2871.pdf\")\n    document = pymupdf.open(path)\n    pnos = [i for i in range(0, document.page_count, 2)]\n    document.delete_pages(pnos)\n\n\ndef test_3150():\n    \"\"\"Assert correct functioning for problem file.\n\n    Implicitly also check use of new MuPDF function\n    pdf_rearrange_pages() since version 1.23.9.\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-3150.pdf\")\n    pages = [3, 3, 3, 2, 3, 1, 0, 0]\n    doc = pymupdf.open(filename)\n    doc.select(pages)\n    assert doc.page_count == len(pages)\n\n\ndef test_4462():\n    path0 = os.path.normpath(f'{__file__}/../../tests/resources/test_4462_0.pdf')\n    path1 = os.path.normpath(f'{__file__}/../../tests/resources/test_4462_1.pdf')\n    path2 = os.path.normpath(f'{__file__}/../../tests/resources/test_4462_2.pdf')\n    with pymupdf.open() as document:\n        document.new_page()\n        document.new_page()\n        document.new_page()\n        document.new_page()\n        document.save(path0)\n    with pymupdf.open(path0) as document:\n        assert len(document) == 4\n        document.delete_page(-1)\n        document.save(path1)\n    with pymupdf.open(path1) as document:\n        assert len(document) == 3\n        document.delete_pages(-1)\n        document.save(path2)\n    with pymupdf.open(path2) as document:\n        assert len(document) == 2\n\n\ndef test_4790():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4790.pdf')\n    path2 = os.path.normpath(f'{__file__}/../../tests/test_4790_out.pdf')\n    print()\n    page_to_delete = 1\n    \n    # Reproduce the problem.\n    with pymupdf.open(path) as document:\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert not wt, f'{wt=}'\n        assert len(document) == 2, f'{len(document)=}'\n        document.delete_pages(page_to_delete)\n        assert len(document) == 1, f'{len(document)=}'\n        document.save(path2)\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'repairing PDF document', f'{wt=}'\n    with pymupdf.open(path2) as document:\n        # Expect incorrect result.\n        assert len(document) == 2, f'{len(document)=}'\n\n    # Call mupdf.pdf_repair_xref() before delete_pages(); this works around the\n    # problem.\n    with pymupdf.open(path) as document:\n        document_pdf = pymupdf._as_pdf_document(document)\n        pymupdf.mupdf.pdf_repair_xref(document_pdf)\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'repairing PDF document', f'{wt=}'\n        document.delete_pages(page_to_delete)\n        document.save(path2)\n    with pymupdf.open(path2) as document:\n        # Expect correct result.\n        assert len(document) == 1\n\n    # Call mupdf.pdf_check_document() before delete_pages(); this works around\n    # the problem.\n    with pymupdf.open(path) as document:\n        document_pdf = pymupdf._as_pdf_document(document)\n        pymupdf.mupdf.pdf_check_document(document_pdf)\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'repairing PDF document', f'{wt=}'\n        document.delete_pages(page_to_delete)\n        document.save(path2)\n    with pymupdf.open(path2) as document:\n        # Expect correct result.\n        assert len(document) == 1\n\n    # Check that document is marked as repaired after save.\n    with pymupdf.open(path) as document:\n        assert not document.is_repaired, f'{document.is_repaired=}'\n        document.save(path2)\n        assert document.is_repaired, f'{document.is_repaired=}'\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'repairing PDF document', f'{wt=}'\n    \n    # Check that raise_on_repair=True works.\n    with pymupdf.open(path) as document:\n        try:\n            document.save(path2, raise_on_repair=True)\n        except Exception as e:\n            print(f'Received expected exception: {e}', flush=1)\n        else:\n            assert 0, 'Did not get expected exception.'\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'repairing PDF document'\n    \n    # Check that Document.repair() works.\n    with pymupdf.open(path) as document:\n        document.repair()\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'repairing PDF document'\n        document.delete_pages(page_to_delete)\n        document.save(path2, raise_on_repair=True)\n    with pymupdf.open(path2) as document:\n        # Expect correct result.\n        assert len(document) == 1, f'{len(document)=}'\n    \n"
  },
  {
    "path": "tests/test_pagelabels.py",
    "content": "\"\"\"\nDefine some page labels in a PDF.\nCheck success in various aspects.\n\"\"\"\n\nimport pymupdf\n\n\ndef make_doc():\n    \"\"\"Makes a PDF with 10 pages.\"\"\"\n    doc = pymupdf.open()\n    for i in range(10):\n        page = doc.new_page()\n    return doc\n\n\ndef make_labels():\n    \"\"\"Return page label range rules.\n    - Rule 1: labels like \"A-n\", page 0 is first and has \"A-1\".\n    - Rule 2: labels as capital Roman numbers, page 4 is first and has \"I\".\n    \"\"\"\n    return [\n        {\"startpage\": 0, \"prefix\": \"A-\", \"style\": \"D\", \"firstpagenum\": 1},\n        {\"startpage\": 4, \"prefix\": \"\", \"style\": \"R\", \"firstpagenum\": 1},\n    ]\n\n\ndef test_setlabels():\n    \"\"\"Check setting and inquiring page labels.\n    - Make a PDF with 10 pages\n    - Label pages\n    - Inquire labels of pages\n    - Get list of page numbers for a given label.\n    \"\"\"\n    doc = make_doc()\n    doc.set_page_labels(make_labels())\n    page_labels = [p.get_label() for p in doc]\n    answer = [\"A-1\", \"A-2\", \"A-3\", \"A-4\", \"I\", \"II\", \"III\", \"IV\", \"V\", \"VI\"]\n    assert page_labels == answer, f\"page_labels={page_labels}\"\n    assert doc.get_page_numbers(\"V\") == [8]\n    assert doc.get_page_labels() == make_labels()\n\n\ndef test_labels_styleA():\n    \"\"\"Test correct indexing for styles \"a\", \"A\".\"\"\"\n    doc = make_doc()\n    labels = [\n        {\"startpage\": 0, \"prefix\": \"\", \"style\": \"a\", \"firstpagenum\": 1},\n        {\"startpage\": 5, \"prefix\": \"\", \"style\": \"A\", \"firstpagenum\": 1},\n    ]\n    doc.set_page_labels(labels)\n    pdfdata = doc.tobytes()\n    doc.close()\n    doc = pymupdf.open(\"pdf\", pdfdata)\n    answer = [\"a\", \"b\", \"c\", \"d\", \"e\", \"A\", \"B\", \"C\", \"D\", \"E\"]\n    page_labels = [page.get_label() for page in doc]\n    assert page_labels == answer\n    assert doc.get_page_labels() == labels\n"
  },
  {
    "path": "tests/test_pixmap.py",
    "content": "\"\"\"\nPixmap tests\n* make pixmap of a page and assert bbox size\n* make pixmap from a PDF xref and compare with extracted image\n* pixmap from file and from binary image and compare\n\"\"\"\n\nimport pymupdf\nimport gentle_compare\n\nimport os\nimport platform\nimport re\nimport shutil\nimport subprocess\nimport sys\nimport tempfile\nimport pytest\nimport textwrap\nimport time\nimport util\n\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nepub = os.path.join(scriptdir, \"resources\", \"Bezier.epub\")\npdf = os.path.join(scriptdir, \"resources\", \"001003ED.pdf\")\nimgfile = os.path.join(scriptdir, \"resources\", \"nur-ruhig.jpg\")\n\n\ndef test_pagepixmap():\n    # pixmap from an EPUB page\n    doc = pymupdf.open(epub)\n    page = doc[0]\n    pix = page.get_pixmap()\n    assert pix.irect == page.rect.irect\n    pix = page.get_pixmap(alpha=True)\n    assert pix.alpha\n    assert pix.n == pix.colorspace.n + pix.alpha\n\n\ndef test_pdfpixmap():\n    # pixmap from xref in a PDF\n    doc = pymupdf.open(pdf)\n    # take first image item of first page\n    img = doc.get_page_images(0)[0]\n    # make pixmap of it\n    pix = pymupdf.Pixmap(doc, img[0])\n    # assert pixmap properties\n    assert pix.width == img[2]\n    assert pix.height == img[3]\n    # extract image and compare metadata\n    extractimg = doc.extract_image(img[0])\n    assert extractimg[\"width\"] == pix.width\n    assert extractimg[\"height\"] == pix.height\n\n\ndef test_filepixmap():\n    # pixmaps from file and from stream\n    # should lead to same result\n    pix1 = pymupdf.Pixmap(imgfile)\n    stream = open(imgfile, \"rb\").read()\n    pix2 = pymupdf.Pixmap(stream)\n    assert repr(pix1) == repr(pix2)\n    assert pix1.digest == pix2.digest\n\n\ndef test_pilsave():\n    # pixmaps from file then save to pillow image\n    # make pixmap from this and confirm equality\n    try:\n        pix1 = pymupdf.Pixmap(imgfile)\n        stream = pix1.pil_tobytes(\"JPEG\")\n        pix2 = pymupdf.Pixmap(stream)\n        assert repr(pix1) == repr(pix2)\n    except ModuleNotFoundError:\n        assert platform.system() in ('Windows', 'Emscripten') and sys.maxsize == 2**31 - 1\n\n\ndef test_save(tmpdir):\n    # pixmaps from file then save to image\n    # make pixmap from this and confirm equality\n    pix1 = pymupdf.Pixmap(imgfile)\n    outfile = os.path.join(tmpdir, \"foo.png\")\n    pix1.save(outfile, output=\"png\")\n    # read it back\n    pix2 = pymupdf.Pixmap(outfile)\n    assert repr(pix1) == repr(pix2)\n\n\ndef test_setalpha():\n    # pixmap from JPEG file, then add an alpha channel\n    # with 30% transparency\n    pix1 = pymupdf.Pixmap(imgfile)\n    opa = int(255 * 0.3)  # corresponding to 30% transparency\n    alphas = [opa] * (pix1.width * pix1.height)\n    alphas = bytearray(alphas)\n    pix2 = pymupdf.Pixmap(pix1, 1)  # add alpha channel\n    pix2.set_alpha(alphas)  # make image 30% transparent\n    samples = pix2.samples  # copy of samples\n    # confirm correct the alpha bytes\n    t = bytearray([samples[i] for i in range(3, len(samples), 4)])\n    assert t == alphas\n\ndef test_color_count():\n    '''\n    This is known to fail if MuPDF is built without PyMuPDF's custom config.h,\n    e.g. in Linux system installs.\n    '''\n    pm = pymupdf.Pixmap(imgfile)\n    assert pm.color_count() == 40624\n\ndef test_memoryview():\n    pm = pymupdf.Pixmap(imgfile)\n    samples = pm.samples_mv\n    assert isinstance( samples, memoryview)\n    print( f'samples={samples} samples.itemsize={samples.itemsize} samples.nbytes={samples.nbytes} samples.ndim={samples.ndim} samples.shape={samples.shape} samples.strides={samples.strides}')\n    assert samples.itemsize == 1\n    assert samples.nbytes == 659817\n    assert samples.ndim == 1\n    assert samples.shape == (659817,)\n    assert samples.strides == (1,)\n    \n    color = pm.pixel( 100, 100)\n    print( f'color={color}')\n    assert color == (83, 66, 40)\n\ndef test_samples_ptr():\n    pm = pymupdf.Pixmap(imgfile)\n    samples = pm.samples_ptr\n    print( f'samples={samples}')\n    assert isinstance( samples, int)\n\ndef test_2369():\n\n    width, height = 13, 37\n    image = pymupdf.Pixmap(pymupdf.csGRAY, width, height, b\"\\x00\" * (width * height), False)\n\n    with pymupdf.Document(stream=image.tobytes(output=\"pam\"), filetype=\"pam\") as doc:\n        test_pdf_bytes = doc.convert_to_pdf()\n    \n    with pymupdf.Document(stream=test_pdf_bytes) as doc:\n        page = doc[0]\n        img_xref = page.get_images()[0][0]\n        img = doc.extract_image(img_xref)\n        img_bytes = img[\"image\"]\n        pymupdf.Pixmap(img_bytes)\n\ndef test_page_idx_int():\n    doc = pymupdf.open(pdf)\n    with pytest.raises(AssertionError):\n        doc[\"0\"]\n    assert doc[0]\n    assert doc[(0,0)]\n\ndef test_fz_write_pixmap_as_jpeg():\n    width, height = 13, 37\n    image = pymupdf.Pixmap(pymupdf.csGRAY, width, height, b\"\\x00\" * (width * height), False)\n\n    with pymupdf.Document(stream=image.tobytes(output=\"jpeg\"), filetype=\"jpeg\") as doc:\n        test_pdf_bytes = doc.convert_to_pdf()\n\ndef test_3020():\n    pm = pymupdf.Pixmap(imgfile)\n    pm2 = pymupdf.Pixmap(pm, 20, 30, None)\n    pm3 = pymupdf.Pixmap(pymupdf.csGRAY, pm)\n    pm4 = pymupdf.Pixmap(pm, pm3)\n\ndef test_3050():\n    '''\n    This is known to fail if MuPDF is built without it's default third-party\n    libraries, e.g. in Linux system installs.\n    '''\n    path = os.path.normpath(f'{__file__}/../../tests/resources/001003ED.pdf')\n    with pymupdf.open(path) as pdf_file:\n        page_no = 0\n        page = pdf_file[page_no]\n        zoom_x = 4.0\n        zoom_y = 4.0\n        matrix = pymupdf.Matrix(zoom_x, zoom_y)\n        pix = page.get_pixmap(matrix=matrix)\n        path_out = os.path.normpath(f'{__file__}/../../tests/test_3050_out.png')\n        pix.save(path_out)\n        print(f'{pix.width=} {pix.height=}')\n        def product(x, y):\n            for yy in y:\n                for xx in x:\n                    yield (xx, yy)\n        n = 0\n        # We use a small subset of the image because non-optimised build gets\n        # very slow.\n        for pos in product(range(100), range(100)):\n            if sum(pix.pixel(pos[0], pos[1])) >= 600:\n                n += 1\n                pix.set_pixel(pos[0], pos[1], (255, 255, 255))\n        path_out2 = os.path.normpath(f'{__file__}/../../tests/test_3050_out2.png')\n        pix.save(path_out2)\n        path_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_3050_expected.png')\n        rms = gentle_compare.pixmaps_rms(path_expected, path_out2)\n        print(f'{rms=}')\n        assert rms == 0\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        if (1, 26, 0) <= pymupdf.mupdf_version_tuple < (1, 27):\n            assert wt == 'bogus font ascent/descent values (0 / 0)\\nPDF stream Length incorrect'\n        else:\n            assert wt == 'PDF stream Length incorrect'\n\ndef test_3058():\n    doc = pymupdf.Document(os.path.abspath(f'{__file__}/../../tests/resources/test_3058.pdf'))\n    images = doc[0].get_images(full=True)\n    pix = pymupdf.Pixmap(doc, 17)\n    \n    # First bug was that `pix.colorspace` was DeviceRGB.\n    assert str(pix.colorspace) == 'Colorspace(CS_CMYK) - DeviceCMYK'\n    \n    pix = pymupdf.Pixmap(pymupdf.csRGB, pix)\n    assert str(pix.colorspace) == 'Colorspace(CS_RGB) - DeviceRGB'\n    \n    # Second bug was that the image was converted to RGB via greyscale proofing\n    # color space, so image contained only shades of grey. This compressed\n    # easily to a .png file, so we crudely check the bug is fixed by looking at\n    # size of .png file.\n    path = os.path.abspath(f'{__file__}/../../tests/test_3058_out.png')\n    pix.save(path)\n    s = os.path.getsize(path)\n    assert 1800000 < s < 2600000, f'Unexpected size of {path}: {s}'\n\ndef test_3072():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_3072.pdf')\n    out = os.path.abspath(f'{__file__}/../../tests')\n    \n    doc = pymupdf.open(path)\n    page_48 = doc[0]\n    bbox = [147, 300, 447, 699]\n    rect = pymupdf.Rect(*bbox)\n    zoom = pymupdf.Matrix(3, 3)\n    pix = page_48.get_pixmap(clip=rect, matrix=zoom)\n    image_save_path = f'{out}/1.jpg'\n    pix.save(image_save_path, jpg_quality=95)\n    \n    doc = pymupdf.open(path)\n    page_49 = doc[1]\n    bbox = [147, 543, 447, 768]\n    rect = pymupdf.Rect(*bbox)\n    zoom = pymupdf.Matrix(3, 3)\n    pix = page_49.get_pixmap(clip=rect, matrix=zoom)\n    image_save_path = f'{out}/2.jpg'\n    pix.save(image_save_path, jpg_quality=95)\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt == (\n            \"syntax error: cannot find ExtGState resource 'BlendMode0'\\n\"\n            \"encountered syntax errors; page may not be correct\\n\"\n            \"syntax error: cannot find ExtGState resource 'BlendMode0'\\n\"\n            \"encountered syntax errors; page may not be correct\"\n            )\n\ndef test_3134():\n    doc = pymupdf.Document()\n    page = doc.new_page()\n    page.get_pixmap(clip=pymupdf.Rect(0, 0, 100, 100)).save(\"test_3134_rect.jpg\")\n    page.get_pixmap(clip=pymupdf.IRect(0, 0, 100, 100)).save(\"test_3134_irect.jpg\")\n    stat_rect = os.stat('test_3134_rect.jpg')\n    stat_irect = os.stat('test_3134_irect.jpg')\n    print(f' {stat_rect=}')\n    print(f'{stat_irect=}')\n    assert stat_rect.st_size == stat_irect.st_size\n    \ndef test_3177():\n    path = os.path.abspath(f'{__file__}/../../tests/resources/img-transparent.png')\n    pixmap = pymupdf.Pixmap(path)\n    pixmap2 = pymupdf.Pixmap(None, pixmap)\n\n\ndef test_3493():\n    '''\n    If python3-gi is installed, we check fix for #3493, where importing gi\n    would load an older version of libjpeg than is used in MuPDF, and break\n    MuPDF.\n    \n    This test is excluded by default in sysinstall tests, because running\n    commands in a new venv does not seem to pick up pymupdf as expected.\n    '''\n    if platform.system() != 'Linux':\n        print(f'Not running because not Linux: {platform.system()=}')\n        return\n    \n    import subprocess\n    \n    root = os.path.abspath(f'{__file__}/../..')\n    \n    venv = f'{root}/tests/resources/test_3493_venv'\n    shutil.rmtree(venv, ignore_errors=1)\n    \n    in_path = f'{root}/tests/resources/test_3493.epub'\n    \n    def run(command, check=1, stdout=None):\n        print(f'Running with {check=}: {command}')\n        return subprocess.run(command, shell=1, check=check, stdout=stdout, text=1)\n    \n    def run_code(code, code_path, *, check=True, venv=None, venv_args='', pythonpath=None, stdout=None):\n        code = textwrap.dedent(code)\n        with open(code_path, 'w') as f:\n            f.write(code)\n        prefix = f'PYTHONPATH={pythonpath} ' if pythonpath else ''\n        if venv:\n            # Have seen this fail on Github in a curious way:\n            #\n            #   Running: /tmp/tmp.fBeKNLJQKk/venv/bin/python -m venv --system-site-packages /project/tests/resources/test_3493_venv\n            #   Error: [Errno 2] No such file or directory: '/project/tests/resources/test_3493_venv/bin/python'\n            #\n            r = run(f'{sys.executable} -m venv {venv_args} {venv}', check=check)\n            if r.returncode:\n                return r\n            r = run(f'. {venv}/bin/activate && {prefix}python {code_path}', check=check, stdout=stdout)\n        else:\n            r = run(f'{prefix}{sys.executable} {code_path}', check=check, stdout=stdout)\n        return r\n    \n    # Find location of system install of `gi`.\n    r = run_code(\n            '''\n            from gi.repository import GdkPixbuf\n            import gi\n            print(gi.__file__)\n            '''\n            ,\n            f'{root}/tests/resources/test_3493_gi.py',\n            check=0,\n            venv=venv,\n            venv_args='--system-site-packages',\n            stdout=subprocess.PIPE,\n            )\n    if r.returncode:\n        print(f'test_3493(): Not running test because --system-site-packages venv cannot import gi.')\n        return\n    gi = r.stdout.strip()\n    gi_pythonpath = os.path.abspath(f'{gi}/../..')\n    \n    def do(gi):\n        # Run code that will import gi and pymupdf in different orders, and\n        # return contents of generated .png file as a bytes.\n        out = f'{root}/tests/resources/test_3493_{gi}.png'\n        run_code(\n                f'''\n                if {gi}==0:\n                    import pymupdf\n                elif {gi}==1:\n                    from gi.repository import GdkPixbuf\n                    import pymupdf\n                elif {gi}==2:\n                    import pymupdf\n                    from gi.repository import GdkPixbuf\n                else:\n                    assert 0\n                document = pymupdf.Document('{in_path}')\n                page = document[0]\n                print(f'{gi=}: saving to: {out}')\n                page.get_pixmap().save('{out}')\n                '''\n                ,\n                os.path.abspath(f'{root}/tests/resources/test_3493_{gi}.py'),\n                pythonpath=gi_pythonpath,\n                )\n        with open(out, 'rb') as f:\n            return f.read()\n    \n    out0 = do(0)\n    out1 = do(1)\n    out2 = do(2)\n    print(f'{len(out0)=} {len(out1)=} {len(out2)=}.')\n    assert out1 == out0\n    assert out2 == out0\n\n\ndef test_3848():\n    if util.skip_slow_tests('test_3848'):\n        return\n    if os.environ.get('PYMUPDF_RUNNING_ON_VALGRIND') == '1':\n        # Takes 40m on Github.\n        print(f'test_3848(): not running on valgrind because very slow.', flush=1)\n        return\n    if platform.python_implementation() == 'GraalVM':\n        print(f'test_3848(): Not running because slow on GraalVM.')\n        return\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3848.pdf')\n    with pymupdf.open(path) as document:\n        for i in range(len(document)):\n            page = document.load_page(i)\n            print(f'{page=}.')\n            for annot in page.get_drawings():\n                if page.get_textbox(annot['rect']):\n                    rect = annot['rect']\n                    pixmap = page.get_pixmap(clip=rect)\n                    color_bytes = pixmap.color_topusage()\n\n\ndef test_3994():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3994.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        txt_blocks = [blk for blk in page.get_text('dict')['blocks'] if blk['type']==0]\n        for blk in txt_blocks:\n            pix = page.get_pixmap(clip=pymupdf.Rect([int(v) for v in blk['bbox']]), colorspace=pymupdf.csRGB, alpha=False)\n            percent, color = pix.color_topusage()\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'premature end of data in flate filter\\n... repeated 2 times...'\n\n\ndef test_3448():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3448.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        pixmap = page.get_pixmap(alpha=False, dpi=150)\n        path_out = f'{path}.png'\n        pixmap.save(path_out)\n        print(f'Have written to: {path_out}')\n    path_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_3448.pdf-expected.png')\n    pixmap_expected = pymupdf.Pixmap(path_expected)\n    rms = gentle_compare.pixmaps_rms(pixmap, pixmap_expected)\n    diff = gentle_compare.pixmaps_diff(pixmap_expected, pixmap)\n    path_diff = os.path.normpath(f'{__file__}/../../tests/test_3448-diff.png')\n    diff.save(path_diff)\n    print(f'{rms=}')\n    assert rms == 0\n\n\ndef test_3854():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3854.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        pixmap = page.get_pixmap()\n    pixmap.save(os.path.normpath(f'{__file__}/../../tests/test_3854_out.png'))\n    \n    # 2024-11-29: this is the incorrect expected output.\n    path_expected_png = os.path.normpath(f'{__file__}/../../tests/resources/test_3854_expected.png')\n    pixmap_expected = pymupdf.Pixmap(path_expected_png)\n    pixmap_diff = gentle_compare.pixmaps_diff(pixmap_expected, pixmap)\n    path_diff = os.path.normpath(f'{__file__}/../../tests/resources/test_3854_diff.png')\n    pixmap_diff.save(path_diff)\n    rms = gentle_compare.pixmaps_rms(pixmap, pixmap_expected)\n    print(f'{rms=}.')\n    if os.environ.get('PYMUPDF_SYSINSTALL_TEST') == '1':\n        # MuPDF using external third-party libs gives slightly different\n        # behaviour.\n        assert rms < 2\n    else:\n        assert rms == 0\n\n\ndef test_4155():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3854.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        pixmap = page.get_pixmap()\n        mv = pixmap.samples_mv\n        mvb1 = mv.tobytes()\n    del page\n    del pixmap\n    try:\n        mvb2 = mv.tobytes()\n    except ValueError as e:\n        print(f'Received exception: {e}')\n        assert 'operation forbidden on released memoryview object' in str(e)\n    else:\n        assert 0, f'Did not receive expected exception when using defunct memoryview.'\n\n\ndef test_4336():\n    if 0:\n        # Compare with last classic release.\n        import pickle\n        path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4336_cc')\n        code = textwrap.dedent(f'''\n                import fitz\n                import os\n                import time\n                import pickle\n                \n                path = os.path.normpath(f'{__file__}/../../tests/resources/nur-ruhig.jpg')\n                pixmap = fitz.Pixmap(path)\n                t = time.time()\n                for i in range(10):\n                    cc = pixmap.color_count()\n                t = time.time() - t\n                print(f'test_4336(): {{t=}}')\n                with open({path_out!r}, 'wb') as f:\n                    pickle.dump(cc, f)\n                ''')\n        path_code = os.path.normpath(f'{__file__}/../../tests/resources/test_4336.py')\n        with open(path_code, 'w') as f:\n            f.write(code)\n        venv = os.path.normpath(f'{__file__}/../../tests/resources/test_4336_venv')\n        command = f'{sys.executable} -m venv {venv}'\n        command += f' && . {venv}/bin/activate'\n        command += f' && pip install --force-reinstall pymupdf==1.23.8'\n        command += f' && python {path_code}'\n        print(f'Running: {command}', flush=1)\n        subprocess.run(command, shell=1, check=1)\n        with open(path_out, 'rb') as f:\n            cc_old = pickle.load(f)\n    else:\n        cc_old = None\n    path = os.path.normpath(f'{__file__}/../../tests/resources/nur-ruhig.jpg')\n    pixmap = pymupdf.Pixmap(path)\n    t = time.time()\n    for i in range(10):\n        cc = pixmap.color_count()\n    t = time.time() - t\n    print(f'test_4336(): {t=}')\n    \n    if cc_old:\n        assert cc == cc_old\n\n\ndef test_4435():\n    # This is slow, e.g. 224s.\n    if util.skip_slow_tests('test_4435'):\n        return\n    print(f'{pymupdf.version=}')\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4435.pdf')\n    with pymupdf.open(path) as document:\n        page = document[2]\n        print(f'Calling page.get_pixmap().', flush=1)\n        if (\n                pymupdf.mupdf_version_tuple >= (1, 27)\n                and (\n                    os.environ.get('PYODIDE_ROOT')\n                    or (platform.system() == 'Windows' and sys.maxsize.bit_length()+1 == 32)\n                    )\n                ):\n            # 2025-11-07: Expect alloc failure.\n            try:\n                pixmap = page.get_pixmap(alpha=False, dpi=120)\n            except Exception as e:\n                print(f'Received exception: {type(e)=}: {e}')\n                assert isinstance(e, pymupdf.mupdf.FzErrorSystem), f'Unrecognised {type(e)=}'\n                m = re.match('code=2: malloc [(][0-9]+ bytes[)] failed', str(e))\n                assert m, f'Unrecognised exception text: {e}'\n                return\n            else:\n                # Hopefully this means that mupdf has been fixed.\n                assert 0, 'Expected alloc failure on pyodide'\n        else:\n            pixmap = page.get_pixmap(alpha=False, dpi=120)\n        print(f'Called page.get_pixmap().', flush=1)\n    if pymupdf.mupdf_version_tuple < (1, 27):\n        assert pymupdf.TOOLS.mupdf_warnings() == 'bogus font ascent/descent values (0 / 0)\\n... repeated 9 times...'\n    elif pymupdf.mupdf_version_tuple >= (1, 28, 0):\n        wt_expected = ('limit error: Overly large image\\ncannot render glyph\\n' * 42).rstrip()\n        assert pymupdf.TOOLS.mupdf_warnings() == wt_expected\n\n\ndef test_4423():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4423.pdf')\n    with pymupdf.open(path) as document:\n        path2 = f'{path}.pdf'\n        ee = None\n        try:\n            document.save(\n                    path2, \n                    garbage=4,\n                    expand=1,\n                    deflate=True,\n                    pretty=True,\n                    no_new_id=True,\n                    )\n        except Exception as e:\n            print(f'Exception: {e}')\n            ee = e\n        \n        assert not ee, f'Received unexpected exception: {e}'\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        if pymupdf.mupdf_version_tuple >= (1, 28, 0):\n            assert wt == ''\n        else:\n            assert wt == 'format error: cannot find object in xref (56 0 R)\\nformat error: cannot find object in xref (68 0 R)'\n\n\ndef test_4445():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4445(): not running on Pyodide - cannot run child processes.')\n        return\n    print()\n    # Test case is large so we download it instead of having it in PyMuPDF\n    # git. We put it in `cache/` directory do it is not removed by `git clean`\n    # (unless `-d` is specified).\n    import util\n    path = util.download(\n            'https://github.com/user-attachments/files/19738242/ss.pdf',\n            'test_4445.pdf',\n            size=2671185,\n            )\n    with pymupdf.open(path) as document:\n        page = document[0]\n        pixmap = page.get_pixmap()\n        print(f'{pixmap.width=}')\n        print(f'{pixmap.height=}')\n        assert (pixmap.width, pixmap.height) == (792, 612)\n        if 0:\n            path_pixmap = f'{path}.png'\n            pixmap.save(path_pixmap)\n            print(f'Have created {path_pixmap=}')\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    print(f'{wt=}')\n    assert wt == 'broken xref subsection, proceeding anyway.\\nTrailer Size is off-by-one. Ignoring.'\n\n\ndef test_3806():\n    print()\n    print(f'{pymupdf.mupdf_version=}')\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3806.pdf')\n    path_png_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_3806-expected.png')\n    path_png = os.path.normpath(f'{__file__}/../../tests/test_3806.png')\n    \n    with pymupdf.open(path) as document:\n        pixmap = document[0].get_pixmap()\n        pixmap.save(path_png)\n        rms = gentle_compare.pixmaps_rms(path_png_expected, pixmap)\n        print(f'{rms=}')\n        if pymupdf.mupdf_version_tuple >= (1, 26, 6):\n            assert rms < 0.1\n        else:\n            assert rms > 50\n\n\ndef test_4388():\n    print()\n    path_BOZ1 = os.path.normpath(f'{__file__}/../../tests/resources/test_4388_BOZ1.pdf')\n    path_BUL1 = os.path.normpath(f'{__file__}/../../tests/resources/test_4388_BUL1.pdf')\n    path_correct = os.path.normpath(f'{__file__}/../../tests/resources/test_4388_BUL1.pdf.correct.png')\n    path_test = os.path.normpath(f'{__file__}/../../tests/resources/test_4388_BUL1.pdf.test.png')\n    \n    with pymupdf.open(path_BUL1) as bul:\n        pixmap_correct = bul.load_page(0).get_pixmap()\n        pixmap_correct.save(path_correct)\n    \n    pymupdf.TOOLS.store_shrink(100)\n    \n    with pymupdf.open(path_BOZ1) as boz:\n        boz.load_page(0).get_pixmap()\n\n    with pymupdf.open(path_BUL1) as bul:\n        pixmap_test = bul.load_page(0).get_pixmap()\n        pixmap_test.save(path_test)\n\n    rms = gentle_compare.pixmaps_rms(pixmap_correct, pixmap_test)\n    print(f'{rms=}')\n    if pymupdf.mupdf_version_tuple >= (1, 26, 6):\n        assert rms == 0\n    else:\n        assert rms >= 10\n\n\ndef test_4699():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4699.pdf')\n    path_png_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4699.png')\n    path_png_actual = os.path.normpath(f'{__file__}/../../tests/test_4699.png')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        pixmap = page.get_pixmap()\n        pixmap.save(path_png_actual)\n    print(f'Have saved to {path_png_actual=}.')\n    rms = gentle_compare.pixmaps_rms(path_png_expected, pixmap)\n    print(f'test_4699(): {rms=}')\n    if pymupdf.mupdf_version_tuple >= (1, 26, 11):\n        assert rms == 0\n    else:\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert 'syntax error: cannot find ExtGState resource' in wt\n        assert rms > 20\n"
  },
  {
    "path": "tests/test_pylint.py",
    "content": "import pymupdf\nimport os\nimport re\nimport subprocess\nimport sys\nimport textwrap\n\ndef test_pylint():\n    \n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_pylint(): not running on Pyodide - cannot run child processes.')\n        return\n    \n    if not hasattr(pymupdf, 'mupdf'):\n        print(f'test_pylint(): Not running with classic implementation.')\n        return\n    \n    ignores = ''\n    \n    ignores += textwrap.dedent(\n            '''\n            C0103: Constant name \"g_exceptions_verbose\" doesn't conform to UPPER_CASE naming style (invalid-name)\n            C0115: Missing class docstring (missing-class-docstring)\n            C0116: Missing function or method docstring (missing-function-docstring)\n            C0301: Line too long (142/100) (line-too-long)\n            C0302: Too many lines in module (23586/1000) (too-many-lines)\n            C0303: Trailing whitespace (trailing-whitespace)\n            C0325: Unnecessary parens after 'not' keyword (superfluous-parens)\n            C0415: Import outside toplevel (traceback) (import-outside-toplevel)\n            R0902: Too many instance attributes (9/7) (too-many-instance-attributes)\n            R0903: Too few public methods (1/2) (too-few-public-methods)\n            R0911: Too many return statements (9/6) (too-many-return-statements)\n            R0913: Too many arguments (6/5) (too-many-arguments)\n            R1705: Unnecessary \"elif\" after \"return\", remove the leading \"el\" from \"elif\" (no-else-return)\n            R1720: Unnecessary \"elif\" after \"raise\", remove the leading \"el\" from \"elif\" (no-else-raise)\n            R1724: Unnecessary \"elif\" after \"continue\", remove the leading \"el\" from \"elif\" (no-else-continue)\n            R1735: Consider using '{}' instead of a call to 'dict'. (use-dict-literal)\n            W0511: Fixme: we don't support JM_MEMORY=1. (fixme)\n            W0622: Redefining built-in 'FileNotFoundError' (redefined-builtin)\n            W0622: Redefining built-in 'open' (redefined-builtin)\n            W1309: Using an f-string that does not have any interpolated variables (f-string-without-interpolation)\n            R1734: Consider using [] instead of list() (use-list-literal)\n            R1727: Boolean condition '0 and g_exceptions_verbose' will always evaluate to '0' (condition-evals-to-constant)\n            R1726: (simplifiable-condition)\n            '''\n            )\n    \n    # Items that we might want to fix.\n    ignores += textwrap.dedent(\n            '''\n            C0114: Missing module docstring (missing-module-docstring)\n            C0117: Consider changing \"not rotate % 90 == 0\" to \"rotate % 90 != 0\" (unnecessary-negation)\n            C0123: Use isinstance() rather than type() for a typecheck. (unidiomatic-typecheck)\n            C0200: Consider using enumerate instead of iterating with range and len (consider-using-enumerate)\n            C0201: Consider iterating the dictionary directly instead of calling .keys() (consider-iterating-dictionary)\n            C0209: Formatting a regular string which could be an f-string (consider-using-f-string)\n            C0305: Trailing newlines (trailing-newlines)\n            C0321: More than one statement on a single line (multiple-statements)\n            C1802: Do not use `len(SEQUENCE)` without comparison to determine if a sequence is empty (use-implicit-booleaness-not-len)\n            C1803: \"select == []\" can be simplified to \"not select\", if it is strictly a sequence, as an empty list is falsey (use-implicit-booleaness-not-comparison)\n            R0912: Too many branches (18/12) (too-many-branches)\n            R0914: Too many local variables (20/15) (too-many-locals)\n            R0915: Too many statements (58/50) (too-many-statements)\n            R1702: Too many nested blocks (7/5) (too-many-nested-blocks)\n            R1703: The if statement can be replaced with 'var = bool(test)' (simplifiable-if-statement)\n            R1710: Either all return statements in a function should return an expression, or none of them should. (inconsistent-return-statements)\n            R1714: Consider merging these comparisons with 'in' by using 'width not in (1, 0)'. Use a set instead if elements are hashable. (consider-using-in)\n            R1716: Simplify chained comparison between the operands (chained-comparison)\n            R1717: Consider using a dictionary comprehension (consider-using-dict-comprehension)\n            R1718: Consider using a set comprehension (consider-using-set-comprehension)\n            R1719: The if expression can be replaced with 'bool(test)' (simplifiable-if-expression)\n            R1721: Unnecessary use of a comprehension, use list(roman_num(num)) instead. (unnecessary-comprehension)\n            R1728: Consider using a generator instead 'max(len(k) for k in item.keys())' (consider-using-generator)\n            R1728: Consider using a generator instead 'max(len(r.cells) for r in self.rows)' (consider-using-generator)\n            R1730: Consider using 'rowheight = min(rowheight, height)' instead of unnecessary if block (consider-using-min-builtin)\n            R1731: Consider using 'right = max(right, x1)' instead of unnecessary if block (consider-using-max-builtin)\n            W0105: String statement has no effect (pointless-string-statement)\n            W0107: Unnecessary pass statement (unnecessary-pass)\n            W0212: Access to a protected member _graft_id of a client class (protected-access)\n            W0602: Using global for 'CHARS' but no assignment is done (global-variable-not-assigned)\n            W0602: Using global for 'EDGES' but no assignment is done (global-variable-not-assigned)\n            W0603: Using the global statement (global-statement)\n            W0612: Unused variable 'keyvals' (unused-variable)\n            W0613: Unused argument 'kwargs' (unused-argument)\n            W0621: Redefining name 'show' from outer scope (line 159) (redefined-outer-name)\n            W0640: Cell variable o defined in loop (cell-var-from-loop)\n            W0718: Catching too general exception Exception (broad-exception-caught)\n            W0719: Raising too general exception: Exception (broad-exception-raised)\n            C3001: Lambda expression assigned to a variable. Define a function using the \"def\" keyword instead. (unnecessary-lambda-assignment)\n            R0801: Similar lines in 2 files\n            R0917: Too many positional arguments (7/5) (too-many-positional-arguments)\n            '''\n            )\n    ignores_list = list()\n    for line in ignores.split('\\n'):\n        if not line or line.startswith('#'):\n            continue\n        m = re.match('^(.....): ', line)\n        assert m, f'Failed to parse {line=}'\n        ignores_list.append(m.group(1))\n    ignores = ','.join(ignores_list)\n    \n    root = os.path.abspath(f'{__file__}/../..')\n    \n    import pipcl\n    \n    # We want to run pylist on all of our src/*.py files so we find them with\n    # `pipcl.git_items()`. However this seems to fail on github windows with\n    # `fatal: not a git repository (or any of the parent directories): .git` so\n    # we also hard-code the list and verify it matches `git ls-files` on other\n    # platforms. This ensures that we will always pick up new .py files in the\n    # future.\n    #\n    command = f'pylint -d {ignores}'\n    directory = f'{root}/src'\n    directory = directory.replace('/', os.sep)\n    leafs = [\n            '__init__.py',\n            '__main__.py',\n            '_apply_pages.py',\n            '_wxcolors.py',\n            'fitz___init__.py',\n            'fitz_table.py',\n            'fitz_utils.py',\n            'pipcl.py',\n            'pymupdf.py',\n            'table.py',\n            'utils.py',\n            'wdev.py',\n            ]\n    leafs.sort()\n    try:\n        leafs_git = pipcl.git_items(directory)\n    except Exception as e:\n        import platform\n        assert platform.system() == 'Windows'\n    else:\n        leafs_git = [i for i in leafs_git if i.endswith('.py')]\n        leafs_git.sort()\n        assert  leafs_git == leafs, f'leafs:\\n    {leafs!r}\\nleafs_git:\\n    {leafs_git!r}'\n    for leaf in leafs:\n        if leaf == 'pipcl.py':\n            # Has various warnings but it's old code that we will eventually stop using.\n            continue\n        command += f' {directory}/{leaf}'\n    print(f'Running: {command}')\n    subprocess.run(command, shell=1, check=1)\n    \n"
  },
  {
    "path": "tests/test_release.py",
    "content": "import pymupdf\n\nimport os\nimport re\nimport sys\n\n\ng_root_abs = os.path.normpath(f'{__file__}/../../')\n\nsys.path.insert(0, g_root_abs)\nsys.path.insert(0, f'{g_root_abs}/src')\ntry:\n    import pipcl\n    import setup\nfinally:\n    del sys.path[0:2]\n\ng_root = pipcl.relpath(g_root_abs)\n\n\ndef _file_line(path, text, re_match, offset=+2):\n    '''\n    Returns <file>:<line> for location of regex match.\n    \n    path:\n        filename.\n    text:\n        Contents of <filename>.\n    re_match:\n        A re.Match.\n    offset:\n        Added to line number of start of <re_match>. Default offset=2 is\n        because callers usually grep for leading newline, and line numbers are\n        generally 1-based.\n    '''\n    text_before = text[:re_match.start()]\n    line = text_before.count('\\n') + offset\n    return f'{path}:{line}'\n\n\ndef test_release_versions():\n    '''\n    PyMuPDF and default MuPDF must have same major.minor version.\n    '''\n    version_p_tuple = [int(i) for i in setup.version_p.split('.')]\n    version_mupdf_tuple = [int(i) for i in setup.version_mupdf.split('.')]\n    assert version_p_tuple[:2] == version_mupdf_tuple[:2], \\\n            f'PyMuPDF and MuPDF major.minor versions do not match. {setup.version_p=} {setup.version_mupdf=}.'\n\n\ndef test_release_bug_template():\n    '''\n    Bug report template must list current PyMuPDF version.\n    '''\n    p = f'{g_root}/.github/ISSUE_TEMPLATE/bug_report.yml'\n    expected = f'\\n        - {setup.version_p}\\n'\n    with open(p) as f:\n        text = f.read()\n    assert expected in text, f'{p}:1: Failed to find line for {setup.version_p=}, {expected!r}.'\n\n\ndef test_release_changelog_version():\n    '''\n    In changes.txt, first item must match setup.version_p.\n    '''\n    p = f'{g_root}/changes.txt'\n    with open(p) as f:\n        text = f.read()\n    # We match `**Changes in version a.b.c**' optionally followed by ` (YYYY-MM-DD)`.\n    m = re.search(f'\\n[*][*]Changes in version ([0-9.]+)[*][*]( [([0-9-]+[)])?\\n', text)\n    assert m, f'Cannot parse {p}.'\n    assert m[1] == setup.version_p, \\\n            f'{_file_line(p, text, m)}: Cannot find {setup.version_p=} in first changelog item: {m[0].strip()!r}.'\n    \n\ndef test_release_changelog_mupdf_version():\n    '''\n    In changes.txt, first mentioned of MuPDF must match setup.version_mupdf.\n    '''\n    p = f'{g_root}/changes.txt'\n    with open(p) as f:\n        text = f.read()\n    m = re.search(f'\\n[*] Use MuPDF-([0-9.]+)[.]\\n', text)\n    assert m, f'Cannot parse {p}.'\n    assert m[1] == setup.version_mupdf, \\\n            f'{_file_line(p, text, m)}: First mentioned MuPDF version does not match {setup.version_mupdf=}: {m[0].strip()!r}.'\n"
  },
  {
    "path": "tests/test_remove-rotation.py",
    "content": "import os\nimport pymupdf\nfrom gentle_compare import gentle_compare\n\nscriptdir = os.path.dirname(__file__)\n\n\ndef test_remove_rotation():\n    \"\"\"Remove rotation verifying identical appearance and text.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-2812.pdf\")\n    doc = pymupdf.open(filename)\n\n    # We always create fresh pages to avoid false positives from cache content.\n    # Text on these pages consists of pairwise different strings, sorting by\n    # these strings must therefore yield identical bounding boxes.\n    for i in range(1, doc.page_count):\n        assert doc[i].rotation  # must be a rotated page\n        pix0 = doc[i].get_pixmap()  # make image\n        words0 = []\n        for w in doc[i].get_text(\"words\"):\n            words0.append(list(pymupdf.Rect(w[:4]) * doc[i].rotation_matrix) + [w[4]])\n        words0.sort(key=lambda w: w[4])  # sort by word strings\n        # derotate page and confirm nothing else has changed\n        doc[i].remove_rotation()\n        assert doc[i].rotation == 0\n        pix1 = doc[i].get_pixmap()\n        words1 = doc[i].get_text(\"words\")\n        words1.sort(key=lambda w: w[4])  # sort by word strings\n        assert pix1.digest == pix0.digest, f\"{pix1.digest}/{pix0.digest}\"\n        assert gentle_compare(words0, words1)\n"
  },
  {
    "path": "tests/test_rewrite_images.py",
    "content": "import pymupdf\nimport os\n\nscriptdir = os.path.dirname(__file__)\n\n\ndef test_rewrite_images():\n    \"\"\"Example for decreasing file size by more than 30%.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-rewrite-images.pdf\")\n    doc = pymupdf.open(filename)\n    size0 = os.path.getsize(doc.name)\n    doc.rewrite_images(dpi_threshold=100, dpi_target=72, quality=33)\n    data = doc.tobytes(garbage=3, deflate=True)\n    size1 = len(data)\n    assert (1 - (size1 / size0)) > 0.3\n"
  },
  {
    "path": "tests/test_rtl.py",
    "content": "import pymupdf\n\nimport os\n\n\ndef test_rtl():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test-E+A.pdf')\n    doc = pymupdf.open(path)\n    page = doc[0]\n    # set of all RTL characters\n    rtl_chars = set([chr(i) for i in range(0x590, 0x901)])\n\n    for w in page.get_text(\"words\"):\n        # every word string must either ONLY contain RTL chars\n        cond1 = rtl_chars.issuperset(w[4])\n        # ... or NONE.\n        cond2 = rtl_chars.intersection(w[4]) == set()\n        assert cond1 or cond2\n"
  },
  {
    "path": "tests/test_showpdfpage.py",
    "content": "\"\"\"\nTests:\n    * Convert some image to a PDF\n    * Insert it rotated in some rectangle of a PDF page\n    * Assert PDF Form XObject has been created\n    * Assert that image contained in inserted PDF is inside given rectangle\n\"\"\"\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nimgfile = os.path.join(scriptdir, \"resources\", \"nur-ruhig.jpg\")\n\n\ndef test_insert():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = pymupdf.Rect(50, 50, 100, 100)  # insert in here\n    img = pymupdf.open(imgfile)  # open image\n    tobytes = img.convert_to_pdf()  # get its PDF version (bytes object)\n    src = pymupdf.open(\"pdf\", tobytes)  # open as PDF\n    xref = page.show_pdf_page(rect, src, 0, rotate=-23)  # insert in rectangle\n    # extract just inserted image info\n    img = page.get_images(True)[0]\n    assert img[-1] == xref  # xref of Form XObject!\n    img = page.get_image_info()[0]  # read the page's images\n\n    # Multiple computations may have lead to rounding deviations, so we need\n    # some generosity here: enlarge rect by 1 point in each direction.\n    assert img[\"bbox\"] in rect + (-1, -1, 1, 1)\n\ndef test_2742():\n    dest = pymupdf.open()\n    destpage = dest.new_page(width=842, height=595)\n\n    a5 = pymupdf.Rect(0, 0, destpage.rect.width / 3, destpage.rect.height)\n    shiftright = pymupdf.Rect(destpage.rect.width/3, 0, destpage.rect.width/3, 0)\n\n    src = pymupdf.open(os.path.abspath(f'{__file__}/../../tests/resources/test_2742.pdf'))\n\n    destpage.show_pdf_page(a5, src, 0)\n    destpage.show_pdf_page(a5 + shiftright, src, 0)\n    destpage.show_pdf_page(a5 + shiftright + shiftright, src, 0)\n\n    dest.save(os.path.abspath(f'{__file__}/../../tests/test_2742-out.pdf'))\n    print(\"The end!\")\n    \n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt == (\n            'Circular dependencies! Consider page cleaning.\\n'\n            '... repeated 3 times...'\n            ), f'{wt=}'\n"
  },
  {
    "path": "tests/test_spikes.py",
    "content": "import pymupdf\nimport pathlib\nimport os\n\n\ndef test_spikes():\n    \"\"\"Check suppression of text spikes caused by long miters.\"\"\"\n    root = os.path.abspath(f\"{__file__}/../..\")\n    spikes_yes = pathlib.Path(f\"{root}/docs/images/spikes-yes.png\")\n    spikes_no = pathlib.Path(f\"{root}/docs/images/spikes-no.png\")\n    doc = pymupdf.open()\n    text = \"NATO MEMBERS\"  # some text provoking spikes (\"N\", \"M\")\n    point = (10, 35)  # insert point\n\n    # make text provoking spikes\n    page = doc.new_page(width=200, height=50)  # small page\n    page.insert_text(\n        point,\n        text,\n        fontsize=20,\n        render_mode=1,  # stroke text only\n        border_width=0.3,  # causes thick border lines\n        miter_limit=None,  # do not care about miter spikes\n    )\n    # write same text in white over the previous for better demo purpose\n    page.insert_text(point, text, fontsize=20, color=(1, 1, 1))\n    pix1 = page.get_pixmap()\n    assert pix1.tobytes() == spikes_yes.read_bytes()\n\n    # make text suppressing spikes\n    page = doc.new_page(width=200, height=50)\n    page.insert_text(\n        point,\n        text,\n        fontsize=20,\n        render_mode=1,\n        border_width=0.3,\n        miter_limit=1,  # suppress each and every miter spike\n    )\n    page.insert_text(point, text, fontsize=20, color=(1, 1, 1))\n    pix2 = page.get_pixmap()\n    assert pix2.tobytes() == spikes_no.read_bytes()\n"
  },
  {
    "path": "tests/test_story.py",
    "content": "import pymupdf\nimport os\nimport textwrap\n\n\ndef test_story():\n    otf = os.path.abspath(f'{__file__}/../resources/PragmaticaC.otf')\n    # 2023-12-06: latest mupdf throws exception if path uses back-slashes.\n    otf = otf.replace('\\\\', '/')\n    CSS = f\"\"\"\n        @font-face {{font-family: test; src: url({otf});}}\n    \"\"\"\n\n    HTML = \"\"\"\n    <p style=\"font-family: test;color: blue\">We shall meet again at a place where there is no darkness.</p>\n    \"\"\"\n\n    MEDIABOX = pymupdf.paper_rect(\"letter\")\n    WHERE = MEDIABOX + (36, 36, -36, -36)\n    # the font files are located in /home/chinese\n    arch = pymupdf.Archive(\".\")\n    # if not specified user_css, the output pdf has content\n    story = pymupdf.Story(HTML, user_css=CSS, archive=arch)  \n\n    writer = pymupdf.DocumentWriter(\"output.pdf\")\n\n    more = 1\n\n    while more:\n        device = writer.begin_page(MEDIABOX)\n        more, _ = story.place(WHERE)\n        story.draw(device)\n        writer.end_page()\n\n    writer.close()\n\n\ndef test_2753():\n    \n    def rectfn(rect_num, filled):\n        return pymupdf.Rect(0, 0, 200, 200), pymupdf.Rect(50, 50, 100, 150), None\n    \n    def make_pdf(html, path_out):\n        story = pymupdf.Story(html=html)\n        document = story.write_with_links(rectfn)\n        print(f'test_2753(): Writing to: {path_out=}.')\n        document.save(path_out)\n        return document\n    \n    doc_before = make_pdf(\n            textwrap.dedent('''\n                <p>Before</p>\n                <p style=\"page-break-before: always;\"></p>\n                <p>After</p>\n                '''),\n            os.path.abspath(f'{__file__}/../../tests/test_2753-out-before.pdf'),\n            )\n        \n    doc_after = make_pdf(\n            textwrap.dedent('''\n                <p>Before</p>\n                <p style=\"page-break-after: always;\"></p>\n                <p>After</p>\n                '''),\n            os.path.abspath(f'{__file__}/../../tests/test_2753-out-after.pdf'),\n            )\n    \n    path = os.path.normpath(f'{__file__}/../../tests/test_2753_out')\n    doc_before.save(f'{path}_before.pdf')\n    doc_after.save(f'{path}_after.pdf')\n    assert len(doc_before) == 2\n    assert len(doc_after) == 2\n\n# codespell:ignore-begin\nspringer_html = '''\n<article>\n<aside>\n<img src=\"springer.jpg\">\n<br><i>Michael Springer ist Schriftsteller und Wis&#173;sen&#173;schafts&#173;publizist. Eine Sammlung seiner Einwürfe ist 2019 als Buch unter dem Titel <b>»Lauter Überraschungen. Was die Wis&#173;senschaft weitertreibt«</b> erschienen.<br><a>www.spektrum.de/artikel/2040277</a></i>\n</aside>\n<h1>SPRINGERS EINWÜRFE: INTIME VERBINDUNGEN</h1>\n\n<h2>Wieso kann unsereins so vieles, was eine Maus nicht kann? Unser Gehirn ist nicht bloß größer, sondern vor allem überraschend vertrackt verdrahtet.</h2>\n\n<p>Der Heilige Gral der Neu&#173;ro&#173;wis&#173;sen&#173;schaft ist die komplette Kartierung des menschlichen Gehirns – die ge&#173;treue Ab&#173;bildung des Ge&#173;strüpps der Nervenzellen mit den baum&#173;för&#173;mi&#173;gen Ver&#173;ästel&#173;ungen der aus ihnen sprie&#173;ßen&#173;den Den&#173;dri&#173;ten und den viel län&#173;ge&#173;ren Axo&#173;nen, wel&#173;che oft der Sig&#173;nal&#173;über&#173;tragung von einem Sin&#173;nes&#173;or&#173;gan oder zu einer Mus&#173;kel&#173;fa&#173;ser die&#173;nen. Zum Gesamtbild gehören die winzigen Knötchen auf den Dendriten; dort sitzen die Synapsen. Das sind Kontakt- und Schalt&#173;stel&#173;len, leb&#173;haf&#173;te Ver&#173;bin&#173;dungen zu anderen Neuronen.</p>\n\n<p>Dieses Dickicht bis zur Ebene einzelner Zel&#173;len zu durchforsten und es räumlich dar&#173;zu&#173;stel&#173;len, ist eine gigantische Aufgabe, die bis vor Kurzem utopisch anmuten musste. Neu&#173;er&#173;dings vermag der junge For&#173;schungs&#173;zweig der Konnektomik (von Englisch: con&#173;nect für ver&#173;bin&#173;den) das Zusammenspiel der Neurone immer besser zu verstehen. Das gelingt mit dem Einsatz dreidimensionaler Elek&#173;tro&#173;nen&#173;mik&#173;ros&#173;ko&#173;pie. Aus Dünn&#173;schicht&#173;auf&#173;nah&#173;men von zerebralen Ge&#173;we&#173;be&#173;pro&#173;ben lassen sich plastische Bil&#173;der ganzer Zellverbände zu&#173;sam&#173;men&#173;setzen.</p>\n\n<p>Da frisches menschliches Hirn&#173;ge&#173;we&#173;be nicht ohne Wei&#173;te&#173;res zu&#173;gäng&#173;lich ist – in der Regel nur nach chirurgischen Eingriffen an Epi&#173;lep&#173;sie&#173;pa&#173;tien&#173;ten –, hält die Maus als Mo&#173;dell&#173;or&#173;ga&#173;nis&#173;mus her. Die evolutionäre Ver&#173;wandt&#173;schaft von Mensch und Nager macht die Wahl plau&#173;sibel. Vor allem das Team um Moritz Helmstaedter am Max-Planck-Institut (MPI) für Hirnforschung in Frankfurt hat in den ver&#173;gangenen Jahren Expertise bei der kon&#173;nek&#173;tomischen Analyse entwickelt.</p>\n\n<p>Aber steckt in unserem Kopf bloß ein auf die tausendfache Neu&#173;ro&#173;nen&#173;an&#173;zahl auf&#173;ge&#173;bläh&#173;tes Mäu&#173;se&#173;hirn? Oder ist menschliches Ner&#173;ven&#173;ge&#173;we&#173;be viel&#173;leicht doch anders gestrickt? Zur Beantwortung dieser Frage unternahm die MPI-Gruppe einen detaillierten Vergleich von Maus, Makake und Mensch (Science 377, abo0924, 2022).</p>\n\n<p>Menschliches Gewebe stammte diesmal nicht von Epileptikern, son&#173;dern von zwei wegen Hirntumoren operierten Patienten. Die For&#173;scher wollten damit vermeiden, dass die oft jahrelange Behandlung mit An&#173;ti&#173;epi&#173;lep&#173;ti&#173;ka das Bild der synaptischen Verknüpfungen trübte. Sie verglichen die Proben mit denen eines Makaken und von fünf Mäusen.</p>\n\n<p>Einerseits ergaben sich – einmal ab&#173;ge&#173;se&#173;hen von den ganz of&#173;fen&#173;sicht&#173;li&#173;chen quan&#173;titativen Unterschieden wie Hirngröße und Neu&#173;ro&#173;nen&#173;anzahl – recht gute Über&#173;ein&#173;stim&#173;mun&#173;gen, die somit den Gebrauch von Tier&#173;modellen recht&#173;fer&#173;ti&#173;gen. Doch in einem Punkt erlebte das MPI-Team eine echte Über&#173;raschung.</p>\n\n<p>Gewisse Nervenzellen, die so genannten In&#173;ter&#173;neurone, zeichnen sich dadurch aus, dass sie aus&#173;schließ&#173;lich mit anderen Ner&#173;ven&#173;zel&#173;len in&#173;ter&#173;agieren. Solche »Zwi&#173;schen&#173;neu&#173;rone« mit meist kurzen Axonen sind nicht primär für das Verarbeiten externer Reize oder das Aus&#173;lösen körperlicher Reaktionen zuständig; sie be&#173;schäf&#173;ti&#173;gen sich bloß mit der Ver&#173;stär&#173;kung oder Dämpfung interner Signale.</p>\n\n<p>Just dieser Neuronentyp ist nun bei Makaken und Menschen nicht nur mehr als doppelt so häufig wie bei Mäusen, sondern obendrein be&#173;son&#173;ders intensiv untereinander ver&#173;flochten. Die meisten Interneurone kop&#173;peln sich fast ausschließlich an ihresgleichen. Dadurch wirkt sich ihr konnektomisches Ge&#173;wicht ver&#173;gleichs&#173;weise zehnmal so stark aus.</p>\n\n<p>Vermutlich ist eine derart mit sich selbst be&#173;schäf&#173;tigte Sig&#173;nal&#173;ver&#173;ar&#173;beitung die Vor&#173;be&#173;ding&#173;ung für ge&#173;stei&#173;gerte Hirn&#173;leis&#173;tungen. Um einen Ver&#173;gleich mit verhältnismäßig pri&#173;mi&#173;ti&#173;ver Tech&#173;nik zu wagen: Bei küns&#173;tli&#173;chen neu&#173;ro&#173;na&#173;len Netzen – Algorithmen nach dem Vor&#173;bild verknüpfter Nervenzellen – ge&#173;nü&#173;gen schon ein, zwei so genannte ver&#173;bor&#173;ge&#173;ne Schich&#173;ten von selbst&#173;be&#173;züg&#173;li&#173;chen Schaltstellen zwischen Input und Output-Ebene, um die ver&#173;blüf&#173;fen&#173;den Erfolge der künstlichen Intel&#173;ligenz her&#173;vor&#173;zu&#173;bringen.</p>\n</article>\n'''\n#codespell:ignore-end\n\ndef test_fit_springer():\n    \n    if not hasattr(pymupdf, 'mupdf'):\n        print(f'test_fit_springer(): not running on classic.')\n        return\n    \n    verbose = 0\n    story = pymupdf.Story(springer_html)\n    \n    def check(call, expected):\n        '''\n        Checks that eval(call) returned parameter=expected. Also creates PDF\n        using path that contains `call` in its leafname,\n        '''\n        fit_result = eval(call)\n        \n        print(f'test_fit_springer(): {call=} => {fit_result=}.')\n        if expected is None:\n            assert not fit_result.big_enough\n        else:\n            document = story.write_with_links(lambda rectnum, filled: (fit_result.rect, fit_result.rect, None))\n            path = os.path.abspath(f'{__file__}/../../tests/test_fit_springer_{call}_{fit_result.parameter=}_{fit_result.rect=}.pdf')\n            document.save(path)\n            print(f'Have saved document to {path}.')\n            assert abs(fit_result.parameter-expected) < 0.001, f'{expected=} {fit_result.parameter=}'\n    \n    check(f'story.fit_scale(pymupdf.Rect(0, 0, 200, 200), scale_min=1, verbose={verbose})', 3.685728073120117)\n    check(f'story.fit_scale(pymupdf.Rect(0, 0, 595, 842), scale_min=1, verbose={verbose})', 1.0174560546875)\n    check(f'story.fit_scale(pymupdf.Rect(0, 0, 300, 421), scale_min=1, verbose={verbose})', 2.02752685546875)\n    check(f'story.fit_scale(pymupdf.Rect(0, 0, 600, 900), scale_min=1, scale_max=1, verbose={verbose})', 1)\n    \n    check(f'story.fit_height(20, verbose={verbose})', 10782.3291015625)\n    check(f'story.fit_height(200, verbose={verbose})', 2437.4990234375)\n    check(f'story.fit_height(2000, verbose={verbose})', 450.2998046875)\n    check(f'story.fit_height(5000, verbose={verbose})', 378.2998046875)\n    check(f'story.fit_height(5500, verbose={verbose})', 378.2998046875)\n    \n    check(f'story.fit_width(3000, verbose={verbose})', 167.30859375)\n    check(f'story.fit_width(2000, verbose={verbose})', 239.595703125)\n    check(f'story.fit_width(1000, verbose={verbose})', 510.85546875)\n    check(f'story.fit_width(500, verbose={verbose})', 1622.1272945404053)\n    check(f'story.fit_width(400, verbose={verbose})', 2837.507724761963)\n    check(f'story.fit_width(300, width_max=200000, verbose={verbose})', None)\n    check(f'story.fit_width(200, width_max=200000, verbose={verbose})', None)\n\n    # Run without verbose to check no calls to log() - checked by assert.\n    check('story.fit_scale(pymupdf.Rect(0, 0, 600, 900), scale_min=1, scale_max=1, verbose=0)', 1)\n    check('story.fit_scale(pymupdf.Rect(0, 0, 300, 421), scale_min=1, verbose=0)', 2.02752685546875)\n\n\ndef test_write_stabilized_with_links():\n\n    def rectfn(rect_num, filled):\n        '''\n        We return one rect per page.\n        '''\n        rect = pymupdf.Rect(10, 20, 290, 380)\n        mediabox = pymupdf.Rect(0, 0, 300, 400)\n        #print(f'rectfn(): rect_num={rect_num} filled={filled}')\n        return mediabox, rect, None\n\n    def contentfn(positions):\n        ret = ''\n        ret += textwrap.dedent('''\n                <!DOCTYPE html>\n                <body>\n                <h2>Contents</h2>\n                <ul>\n                ''')\n        for position in positions:\n            if position.heading and (position.open_close & 1):\n                text = position.text if position.text else ''\n                if position.id:\n                    ret += f'    <li><a href=\"#{position.id}\">{text}</a>'\n                else:\n                    ret += f'    <li>{text}'\n                ret += f' page={position.page_num}\\n'\n        ret += '</ul>\\n'\n        ret += textwrap.dedent(f'''\n                <h1>First section</h1>\n                <p>Contents of first section.\n                <ul>\n                <li>External <a href=\"https://artifex.com/\">link to https://artifex.com/</a>.\n                <li><a href=\"#idtest\">Link to IDTEST</a>.\n                <li><a href=\"#nametest\">Link to NAMETEST</a>.\n                </ul>\n            \n                <h1>Second section</h1>\n                <p>Contents of second section.\n                <h2>Second section first subsection</h2>\n            \n                <p>Contents of second section first subsection.\n                <p id=\"idtest\">IDTEST\n            \n                <h1>Third section</h1>\n                <p>Contents of third section.\n                <p><a name=\"nametest\">NAMETEST</a>.\n            \n                </body>\n                ''')\n        return ret.strip()\n    \n    document = pymupdf.Story.write_stabilized_with_links(contentfn, rectfn)\n    \n    # Check links.\n    links = list()\n    for page in document:\n        links += page.get_links()\n    print(f'{len(links)=}.')\n    external_links = dict()\n    for i, link in enumerate(links):\n        print(f'    {i}: {link=}')\n        if link.get('kind') == pymupdf.LINK_URI:\n            uri = link['uri']\n            external_links.setdefault(uri, 0)\n            external_links[uri] += 1\n\n    # Check there is one external link.\n    print(f'{external_links=}')\n    if hasattr(pymupdf, 'mupdf'):\n        assert len(external_links) == 1\n        assert 'https://artifex.com/' in external_links\n    \n    out_path = __file__.replace('.py', '.pdf')\n    document.save(out_path)\n    \ndef test_archive_creation():\n    s = pymupdf.Story(archive=pymupdf.Archive('.'))\n    s = pymupdf.Story(archive='.')\n\n\ndef test_3813():\n    import pymupdf\n\n    HTML = \"\"\"\n    <p>Count is fine:</p>\n    <ol>\n        <li>Lorem\n            <ol>\n                <li>Sub Lorem</li>\n                <li>Sub Lorem</li>\n            </ol>\n        </li>\n        <li>Lorem</li>\n        <li>Lorem</li>\n    </ol>\n\n    <p>Broken count:</p>\n    <ol>\n        <li>Lorem\n            <ul>\n                <li>Sub Lorem</li>\n                <li>Sub Lorem</li>\n            </ul>\n        </li>\n        <li>Lorem</li>\n        <li>Lorem</li>\n    </ol>\n    \"\"\"\n    MEDIABOX = pymupdf.paper_rect(\"A4\")\n    WHERE = MEDIABOX + (36, 36, -36, -36)\n\n    story = pymupdf.Story(html=HTML)\n    path = os.path.normpath(f'{__file__}/../../tests/test_3813_out.pdf')\n    writer = pymupdf.DocumentWriter(path)\n\n    more = 1\n\n    while more:\n        device = writer.begin_page(MEDIABOX)\n        more, _ = story.place(WHERE)\n        story.draw(device)\n        writer.end_page()\n\n    writer.close()\n    \n    with pymupdf.open(path) as document:\n        page = document[0]\n        text = page.get_text()\n    text_utf8 = text.encode()\n    \n    text_expected_utf8 = b'Count is \\xef\\xac\\x81ne:\\n1. Lorem\\n1. Sub Lorem\\n2. Sub Lorem\\n2. Lorem\\n3. Lorem\\nBroken count:\\n1. Lorem\\n\\xe2\\x80\\xa2  Sub Lorem\\n\\xe2\\x80\\xa2  Sub Lorem\\n2. Lorem\\n3. Lorem\\n'\n    text_expected = text_expected_utf8.decode()\n    \n    print(f'text_utf8:\\n    {text_utf8!r}')\n    print(f'text_expected_utf8:\\n    {text_expected_utf8!r}')\n    print(f'text:\\n    {textwrap.indent(text, \"    \")}')\n    print(f'text_expected:\\n    {textwrap.indent(text_expected, \"   \")}')\n    \n    assert text == text_expected\n"
  },
  {
    "path": "tests/test_tables.py",
    "content": "import os\nimport io\nfrom pprint import pprint\nimport textwrap\nimport pickle\nimport platform\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"chinese-tables.pdf\")\npickle_file = os.path.join(scriptdir, \"resources\", \"chinese-tables.pickle\")\n\n\ndef test_table1():\n    \"\"\"Compare pickled tables with those of the current run.\"\"\"\n    pickle_in = open(pickle_file, \"rb\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tabs = page.find_tables()\n    cells = tabs[0].cells + tabs[1].cells  # all table cell tuples on page\n    extracts = [tabs[0].extract(), tabs[1].extract()]  # all table cell content\n    old_data = pickle.load(pickle_in)  # previously saved data\n\n    # Compare cell contents\n    assert old_data[\"extracts\"] == extracts  # same cell contents\n\n    # Compare cell coordinates.\n    # Cell rectangles may get somewhat larger due to more cautious border\n    # computations, but any differences must be small.\n    old_cells = old_data[\"cells\"][0] + old_data[\"cells\"][1]\n    assert len(cells) == len(old_cells)\n    for i in range(len(cells)):\n        c1 = pymupdf.Rect(cells[i])  # new cell coordinates\n        c0 = pymupdf.Rect(old_cells[i])  # old cell coordinates\n        assert c0 in c1  # always: old contained in new\n        assert abs(c1 - c0) < 0.2  # difference must be small\n\n\ndef test_table2():\n    \"\"\"Confirm header properties.\"\"\"\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tab1, tab2 = page.find_tables().tables\n    # both tables contain their header data\n    assert tab1.header.external == False\n    assert tab1.header.cells == tab1.rows[0].cells\n    assert tab2.header.external == False\n    assert tab2.header.cells == tab2.rows[0].cells\n\n\ndef test_2812():\n    \"\"\"Ensure table detection and extraction independent from page rotation.\n\n    Make 4 pages with rotations 0, 90, 180 and 270 degrees respectively.\n    Each page shows the same 8x5 table.\n    We will check that each table is detected and delivers the same content.\n    \"\"\"\n    doc = pymupdf.open()\n    # Page 0: rotation 0\n    page = doc.new_page(width=842, height=595)\n    rect = page.rect + (72, 72, -72, -72)\n    cols = 5\n    rows = 8\n    # define the cells, draw the grid and insert unique text in each cell.\n    cells = pymupdf.make_table(rect, rows=rows, cols=cols)\n    for i in range(rows):\n        for j in range(cols):\n            page.draw_rect(cells[i][j])\n    for i in range(rows):\n        for j in range(cols):\n            page.insert_textbox(\n                cells[i][j],\n                f\"cell[{i}][{j}]\",\n                align=pymupdf.TEXT_ALIGN_CENTER,\n            )\n    page.clean_contents()\n\n    # Page 1: rotation 90 degrees\n    page = doc.new_page()\n    rect = page.rect + (72, 72, -72, -72)\n    cols = 8\n    rows = 5\n    cells = pymupdf.make_table(rect, rows=rows, cols=cols)\n    for i in range(rows):\n        for j in range(cols):\n            page.draw_rect(cells[i][j])\n    for i in range(rows):\n        for j in range(cols):\n            page.insert_textbox(\n                cells[i][j],\n                f\"cell[{j}][{rows-i-1}]\",\n                rotate=90,\n                align=pymupdf.TEXT_ALIGN_CENTER,\n            )\n    page.set_rotation(90)\n    page.clean_contents()\n\n    # Page 2: rotation 180 degrees\n    page = doc.new_page(width=842, height=595)\n    rect = page.rect + (72, 72, -72, -72)\n    cols = 5\n    rows = 8\n    cells = pymupdf.make_table(rect, rows=rows, cols=cols)\n    for i in range(rows):\n        for j in range(cols):\n            page.draw_rect(cells[i][j])\n    for i in range(rows):\n        for j in range(cols):\n            page.insert_textbox(\n                cells[i][j],\n                f\"cell[{rows-i-1}][{cols-j-1}]\",\n                rotate=180,\n                align=pymupdf.TEXT_ALIGN_CENTER,\n            )\n    page.set_rotation(180)\n    page.clean_contents()\n\n    # Page 3: rotation 270 degrees\n    page = doc.new_page()\n    rect = page.rect + (72, 72, -72, -72)\n    cols = 8\n    rows = 5\n    cells = pymupdf.make_table(rect, rows=rows, cols=cols)\n    for i in range(rows):\n        for j in range(cols):\n            page.draw_rect(cells[i][j])\n    for i in range(rows):\n        for j in range(cols):\n            page.insert_textbox(\n                cells[i][j],\n                f\"cell[{cols-j-1}][{i}]\",\n                rotate=270,\n                align=pymupdf.TEXT_ALIGN_CENTER,\n            )\n    page.set_rotation(270)\n    page.clean_contents()\n\n    pdfdata = doc.tobytes()\n    # doc.ez_save(\"test-2812.pdf\")\n    doc.close()\n\n    # -------------------------------------------------------------------------\n    # Test PDF prepared. Extract table on each page and\n    # ensure identical extracted table data.\n    # -------------------------------------------------------------------------\n    doc = pymupdf.open(\"pdf\", pdfdata)\n    extracts = []\n    for page in doc:\n        tabs = page.find_tables()\n        assert len(tabs.tables) == 1\n        tab = tabs[0]\n        fp = io.StringIO()\n        pprint(tab.extract(), stream=fp)\n        extracts.append(fp.getvalue())\n        fp = None\n        assert tab.row_count == 8\n        assert tab.col_count == 5\n    e0 = extracts[0]\n    for e in extracts[1:]:\n        assert e == e0\n\n\ndef test_2979():\n    \"\"\"This tests fix #2979 and #3001.\n\n    2979: identical cell count for each row\n    3001: no change of global glyph heights\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test_2979.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tab = page.find_tables()[0]  # extract the table\n    lengths = set()  # stores all row cell counts\n    for e in tab.extract():\n        lengths.add(len(e))  # store number of cells for row\n\n    # test 2979\n    assert len(lengths) == 1\n\n    # test 3001\n    assert (\n        pymupdf.TOOLS.set_small_glyph_heights() is False\n    ), f\"{pymupdf.TOOLS.set_small_glyph_heights()=}\"\n\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if pymupdf.mupdf_version_tuple >= (1, 28, 0):\n        assert ( wt == '' )\n    else:\n        assert (\n            wt\n            == \"bogus font ascent/descent values (3117 / -2463)\\n... repeated 2 times...\"\n        )\n\n\ndef test_3062():\n    \"\"\"Tests the fix for #3062.\n    After table extraction, a rotated page should behave and look\n    like as before.\"\"\"\n    if platform.python_implementation() == 'GraalVM':\n        print(f'test_3062(): Not running because slow on GraalVM.')\n        return\n    \n    filename = os.path.join(scriptdir, \"resources\", \"test_3062.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tab0 = page.find_tables()[0]\n    cells0 = tab0.cells\n\n    page = None\n    page = doc[0]\n    tab1 = page.find_tables()[0]\n    cells1 = tab1.cells\n    assert cells1 == cells0\n\n\ndef test_strict_lines():\n    \"\"\"Confirm that ignoring borderless rectangles improves table detection.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"strict-yes-no.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n\n    tab1 = page.find_tables()[0]\n    tab2 = page.find_tables(strategy=\"lines_strict\")[0]\n    assert tab2.row_count < tab1.row_count\n    assert tab2.col_count < tab1.col_count\n\n\ndef test_add_lines():\n    \"\"\"Test new parameter add_lines for table recognition.\"\"\"\n    if platform.python_implementation() == 'GraalVM':\n        print(f'test_add_lines(): Not running because breaks later tests on GraalVM.')\n        return\n    \n    filename = os.path.join(scriptdir, \"resources\", \"small-table.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    assert page.find_tables().tables == []\n\n    more_lines = [\n        ((238.9949951171875, 200.0), (238.9949951171875, 300.0)),\n        ((334.5559997558594, 200.0), (334.5559997558594, 300.0)),\n        ((433.1809997558594, 200.0), (433.1809997558594, 300.0)),\n    ]\n\n    # these 3 additional vertical lines should additional 3 columns\n    tab2 = page.find_tables(add_lines=more_lines)[0]\n    assert tab2.col_count == 4\n    assert tab2.row_count == 5\n\n\ndef test_3148():\n    \"\"\"Ensure correct extraction text of rotated text.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = pymupdf.Rect(100, 100, 300, 300)\n    text = (\n        \"rotation 0 degrees\",\n        \"rotation 90 degrees\",\n        \"rotation 180 degrees\",\n        \"rotation 270 degrees\",\n    )\n    degrees = (0, 90, 180, 270)\n    delta = (2, 2, -2, -2)\n    cells = pymupdf.make_table(rect, cols=3, rows=4)\n    for i in range(3):\n        for j in range(4):\n            page.draw_rect(cells[j][i])\n            k = (i + j) % 4\n            page.insert_textbox(cells[j][i] + delta, text[k], rotate=degrees[k])\n    # doc.save(\"multi-degree.pdf\")\n    tabs = page.find_tables()\n    tab = tabs[0]\n    for extract in tab.extract():\n        for item in extract:\n            item = item.replace(\"\\n\", \" \")\n            assert item in text\n\n\ndef test_3179():\n    \"\"\"Test correct separation of multiple tables on page.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test_3179.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tabs = page.find_tables()\n    assert len(tabs.tables) == 3\n\n\ndef test_battery_file():\n    \"\"\"Tests correctly ignoring non-table suspects.\n\n    Earlier versions erroneously tried to identify table headers\n    where there existed no table at all.\n    \"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"battery-file-22.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tabs = page.find_tables()\n    assert len(tabs.tables) == 0\n\n\ndef test_markdown():\n    \"\"\"Confirm correct markdown output.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"strict-yes-no.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tab = page.find_tables(strategy=\"lines_strict\")[0]\n    if pymupdf.mupdf_version_tuple < (1, 26, 3):\n        md_expected = textwrap.dedent('''\n                |Header1|Header2|Header3|\n                |---|---|---|\n                |Col11<br>Col12|~~Col21~~<br>~~Col22~~|Col31<br>Col32<br>Col33|\n                |Col13|~~Col23~~|Col34<br>Col35|\n                |Col14|~~Col24~~|Col36|\n                |Col15|~~Col25~~<br>~~Col26~~||\n                \n                ''').lstrip()\n    else:\n        md_expected = (\n            \"|Header1|Header2|Header3|\\n\"\n            \"|---|---|---|\\n\"\n            \"|Col11<br>Col12|Col21<br>Col22|Col31<br>Col32<br>Col33|\\n\"\n            \"|Col13|Col23|Col34<br>Col35|\\n\"\n            \"|Col14|Col24|Col36|\\n\"\n            \"|Col15|Col25<br>Col26||\\n\\n\"\n        )\n\n\n    md = tab.to_markdown()\n    assert md == md_expected, f'Incorrect md:\\n{textwrap.indent(md, \"    \")}'\n\n\ndef test_paths_param():\n    \"\"\"Confirm acceptance of supplied vector graphics list.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"strict-yes-no.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tabs = page.find_tables(paths=[])  # will cause all tables are missed\n    assert tabs.tables == []\n\n\ndef test_boxes_param():\n    \"\"\"Confirm acceptance of supplied boxes list.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"small-table.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    paths = page.get_drawings()\n    box0 = page.cluster_drawings(drawings=paths)[0]\n    boxes = [box0]\n    words = page.get_text(\"words\")\n    x_vals = [w[0] - 5 for w in words if w[4] in (\"min\", \"max\", \"avg\")]\n    for x in x_vals:\n        r = +box0\n        r.x1 = x\n        boxes.append(r)\n\n    y_vals = sorted(set([round(w[3]) for w in words]))\n    for y in y_vals[:-1]:  # skip last one to avoid empty row\n        r = +box0\n        r.y1 = y\n        boxes.append(r)\n\n    tabs = page.find_tables(paths=[], add_boxes=boxes)\n    tab = tabs.tables[0]\n    assert tab.extract() == [\n        [\"Boiling Points °C\", \"min\", \"max\", \"avg\"],\n        [\"Noble gases\", \"-269\", \"-62\", \"-170.5\"],\n        [\"Nonmetals\", \"-253\", \"4827\", \"414.1\"],\n        [\"Metalloids\", \"335\", \"3900\", \"741.5\"],\n        [\"Metals\", \"357\", \">5000\", \"2755.9\"],\n    ]\n\n\ndef test_dotted_grid():\n    \"\"\"Confirm dotted lines are detected as gridlines.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"dotted-gridlines.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tabs = page.find_tables()\n    assert len(tabs.tables) == 3  # must be 3 tables\n    t0, t1, t2 = tabs  # extract them\n    # check that they have expected dimensions\n    assert t0.row_count, t0.col_count == (11, 12)\n    assert t1.row_count, t1.col_count == (25, 11)\n    assert t2.row_count, t2.col_count == (1, 10)\n\n\ndef test_4017():\n    path = os.path.normpath(f\"{__file__}/../../tests/resources/test_4017.pdf\")\n    with pymupdf.open(path) as document:\n        page = document[0]\n\n        tables = page.find_tables(add_lines=None)\n        print(f\"{len(tables.tables)=}.\")\n        tables_text = list()\n        for i, table in enumerate(tables):\n            print(f\"## {i=}.\")\n            t = table.extract()\n            for tt in t:\n                print(f\"    {tt}\")\n\n        # 2024-11-29: expect current incorrect output for last two tables.\n\n        expected_a = [\n            [\"Class A/B Overcollateralization\", \"131.44%\", \">=\", \"122.60%\", \"\", \"PASS\"],\n            [None, None, None, None, None, \"PASS\"],\n            [\"Class D Overcollateralization\", \"112.24%\", \">=\", \"106.40%\", \"\", \"PASS\"],\n            [None, None, None, None, None, \"PASS\"],\n            [\"Event of Default\", \"156.08%\", \">=\", \"102.50%\", \"\", \"PASS\"],\n            [None, None, None, None, None, \"PASS\"],\n            [\"Class A/B Interest Coverage\", \"N/A\", \">=\", \"120.00%\", \"\", \"N/A\"],\n            [None, None, None, None, None, \"N/A\"],\n            [\"Class D Interest Coverage\", \"N/A\", \">=\", \"105.00%\", \"\", \"N/A\"],\n        ]\n        assert tables[-2].extract() == expected_a\n\n        expected_b = [\n            [\n                \"Moody's Maximum Rating Factor Test\",\n                \"2,577\",\n                \"<=\",\n                \"3,250\",\n                \"\",\n                \"PASS\",\n                \"2,581\",\n            ],\n            [None, None, None, None, None, \"PASS\", None],\n            [\n                \"Minimum Floating Spread\",\n                \"3.5006%\",\n                \">=\",\n                \"2.0000%\",\n                \"\",\n                \"PASS\",\n                \"3.4871%\",\n            ],\n            [None, None, None, None, None, \"PASS\", None],\n            [\n                \"Minimum Weighted Average S&P Recovery\\nRate Test\",\n                \"40.50%\",\n                \">=\",\n                \"40.00%\",\n                \"\",\n                \"PASS\",\n                \"40.40%\",\n            ],\n            [None, None, None, None, None, \"PASS\", None],\n            [\"Weighted Average Life\", \"4.83\", \"<=\", \"9.00\", \"\", \"PASS\", \"4.92\"],\n        ]\n        assert tables[-1].extract() == expected_b\n\n\ndef test_md_styles():\n    \"\"\"Test output of table with MD-styled cells.\"\"\"\n    filename = os.path.join(scriptdir, \"resources\", \"test-styled-table.pdf\")\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    tabs = page.find_tables()[0]\n    text = \"\"\"|Column 1|Column 2|Column 3|\\n|---|---|---|\\n|Zelle (0,0)|**Bold (0,1)**|Zelle (0,2)|\\n|~~Strikeout (1,0), Zeile 1~~<br>~~Hier kommt Zeile 2.~~|Zelle (1,1)|~~Strikeout (1,2)~~|\\n|**`Bold-monospaced`**<br>**`(2,0)`**|_Italic (2,1)_|**_Bold-italic_**<br>**_(2,2)_**|\\n|Zelle (3,0)|~~**Bold-strikeout**~~<br>~~**(3,1)**~~|Zelle (3,2)|\\n\\n\"\"\"\n    assert tabs.to_markdown() == text\n"
  },
  {
    "path": "tests/test_tesseract.py",
    "content": "import os\nimport platform\nimport textwrap\nimport pathlib\nimport pymupdf\n\ndef test_tesseract():\n    '''\n    This checks that MuPDF has been built with tesseract support.\n\n    By default we don't supply a valid `tessdata` directory, and just assert\n    that attempting to use Tesseract raises the expected error (which checks\n    that MuPDF is built with Tesseract support).\n\n    But if TESSDATA_PREFIX is set in the environment, we assert that\n    FzPage.get_textpage_ocr() succeeds.\n    '''\n    path = os.path.abspath( f'{__file__}/../resources/2.pdf')\n    doc = pymupdf.open( path)\n    page = doc[5]\n    tail = 'Tesseract language initialisation failed'\n    if os.environ.get('PYODIDE_ROOT'):\n        e_expected = 'code=6: No OCR support in this build'\n        e_expected_type = pymupdf.mupdf.FzErrorUnsupported\n    else:\n        e_expected = f'code=3: {tail}'\n        if platform.system() == 'OpenBSD':\n            # 2023-12-12: For some reason the SWIG catch code only catches\n            # the exception as FzErrorBase.\n            e_expected_type = pymupdf.mupdf.FzErrorBase\n            print(f'OpenBSD workaround - expecting FzErrorBase, not FzErrorLibrary.')\n        else:\n            e_expected_type = pymupdf.mupdf.FzErrorLibrary\n    tessdata_prefix = os.environ.get('TESSDATA_PREFIX')\n    if tessdata_prefix:\n        tp = page.get_textpage_ocr(full=True)\n        print(f'test_tesseract(): page.get_textpage_ocr() succeeded')\n    else:\n        try:\n            tp = page.get_textpage_ocr(full=True, tessdata='/foo/bar')\n        except Exception as e:\n            e_text = str(e)\n            print(f'Received exception as expected.')\n            print(f'{type(e)=}')\n            print(f'{e_text=}')\n            assert e_text == e_expected, f'Unexpected exception: {e_text!r}'\n            if e_expected_type:\n                print(f'{e_expected_type=}')\n                assert type(e) == e_expected_type, f'{type(e)=} != {e_expected_type=}.'\n        else:\n            assert 0, f'Expected exception {e_expected!r}'\n        \n\ndef test_3842b():\n    # Check Tesseract failure when given a bogus languages.\n    #\n    # Note that Tesseract seems to output its own diagnostics.\n    #\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_3842b(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3842.pdf')\n    with pymupdf.open(path) as document:\n        page = document[6]\n        try:\n            partial_tp = page.get_textpage_ocr(flags=0, full=False, language='qwerty')\n        except Exception as e:\n            print(f'test_3842b(): received exception: {e}')\n            if 'No tessdata specified and Tesseract is not installed' in str(e):\n                pass\n            else:\n                assert 'Tesseract language initialisation failed' in str(e)\n\n\ndef test_3842():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_3842(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3842.pdf')\n    if pymupdf.mupdf_version_tuple >= (1, 28):\n        path_text_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_3842_expected_1.28.txt')\n    else:\n        path_text_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_3842_partial.txt')\n    text_expected = pathlib.Path(path_text_expected).read_text()\n    with pymupdf.open(path) as document:\n        page = document[6]\n        try:\n            partial_tp = page.get_textpage_ocr(flags=0, full=False, dpi=300)\n        except Exception as e:\n            print(f'test_3842(): received exception: {e}', flush=1)\n            if 'No tessdata specified and Tesseract is not installed' in str(e):\n                pass\n            elif 'Tesseract language initialisation failed' in str(e):\n                pass\n            else:\n                assert 0, f'Unexpected exception text: {str(e)=}'\n        else:\n            text = page.get_text(textpage=partial_tp)\n            with open(os.path.normpath(f'{__file__}/../../tests/resources/test_3842_out'), 'w') as f:\n                f.write(text)\n            print()\n            print(text)\n            print(f'text:\\n{text!r}')\n            print(f'text_expected:\\n{text_expected!r}')\n            assert text == text_expected\n"
  },
  {
    "path": "tests/test_textbox.py",
    "content": "\"\"\"\nFill a given text in a rectangle on some PDF page using\n1. TextWriter object\n2. Basic text output\n\nCheck text is indeed contained in given rectangle.\n\"\"\"\nimport pymupdf\n\nimport gentle_compare\n\nimport os\nimport textwrap\n\n# codespell:ignore-begin\ntext = \"\"\"Der Kleine Schwertwal (Pseudorca crassidens), auch bekannt als Unechter oder Schwarzer Schwertwal, ist eine Art der Delfine (Delphinidae) und der einzige rezente Vertreter der Gattung Pseudorca.\n\nEr ähnelt dem Orca in Form und Proportionen, ist aber einfarbig schwarz und mit einer Maximallänge von etwa sechs Metern deutlich kleiner.\n\nKleine Schwertwale bilden Schulen von durchschnittlich zehn bis fünfzig Tieren, wobei sie sich auch mit anderen Delfinen vergesellschaften und sich meistens abseits der Küsten aufhalten.\n\nSie sind in allen Ozeanen gemäßigter, subtropischer und tropischer Breiten beheimatet, sind jedoch vor allem in wärmeren Jahreszeiten auch bis in die gemäßigte bis subpolare Zone südlich der Südspitze Südamerikas, vor Nordeuropa und bis vor Kanada anzutreffen.\"\"\"\n# codespell:ignore-end\n\ndef test_textbox1():\n    \"\"\"Use TextWriter for text insertion.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = pymupdf.Rect(50, 50, 400, 400)\n    blue = (0, 0, 1)\n    tw = pymupdf.TextWriter(page.rect, color=blue)\n    tw.fill_textbox(\n        rect,\n        text,\n        align=pymupdf.TEXT_ALIGN_LEFT,\n        fontsize=12,\n    )\n    tw.write_text(page, morph=(rect.tl, pymupdf.Matrix(1, 1)))\n    # check text containment\n    assert page.get_text() == page.get_text(clip=rect)\n    page.write_text(writers=tw)\n\n\ndef test_textbox2():\n    \"\"\"Use basic text insertion.\"\"\"\n    doc = pymupdf.open()\n    ocg = doc.add_ocg(\"ocg1\")\n    page = doc.new_page()\n    rect = pymupdf.Rect(50, 50, 400, 400)\n    blue = pymupdf.utils.getColor(\"lightblue\")\n    red = pymupdf.utils.getColorHSV(\"red\")\n    page.insert_textbox(\n        rect,\n        text,\n        align=pymupdf.TEXT_ALIGN_LEFT,\n        fontsize=12,\n        color=blue,\n        oc=ocg,\n    )\n    # check text containment\n    assert page.get_text() == page.get_text(clip=rect)\n\n\ndef test_textbox3():\n    \"\"\"Use TextWriter for text insertion.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    font = pymupdf.Font(\"cjk\")\n    rect = pymupdf.Rect(50, 50, 400, 400)\n    blue = (0, 0, 1)\n    tw = pymupdf.TextWriter(page.rect, color=blue)\n    tw.fill_textbox(\n        rect,\n        text,\n        align=pymupdf.TEXT_ALIGN_LEFT,\n        font=font,\n        fontsize=12,\n        right_to_left=True,\n    )\n    tw.write_text(page, morph=(rect.tl, pymupdf.Matrix(1, 1)))\n    # check text containment\n    assert page.get_text() == page.get_text(clip=rect)\n    doc.scrub()\n    doc.subset_fonts()\n\n\ndef test_textbox4():\n    \"\"\"Use TextWriter for text insertion.\"\"\"\n    doc = pymupdf.open()\n    ocg = doc.add_ocg(\"ocg1\")\n    page = doc.new_page()\n    rect = pymupdf.Rect(50, 50, 400, 600)\n    blue = (0, 0, 1)\n    tw = pymupdf.TextWriter(page.rect, color=blue)\n    tw.fill_textbox(\n        rect,\n        text,\n        align=pymupdf.TEXT_ALIGN_LEFT,\n        fontsize=12,\n        font=pymupdf.Font(\"cour\"),\n        right_to_left=True,\n    )\n    tw.write_text(page, oc=ocg, morph=(rect.tl, pymupdf.Matrix(1, 1)))\n    # check text containment\n    assert page.get_text() == page.get_text(clip=rect)\n\n\ndef test_textbox5():\n    \"\"\"Using basic text insertion.\"\"\"\n    small_glyph_heights0 = pymupdf.TOOLS.set_small_glyph_heights()\n    pymupdf.TOOLS.set_small_glyph_heights(True)\n    try:\n        doc = pymupdf.open()\n        page = doc.new_page()\n        r = pymupdf.Rect(100, 100, 150, 150)\n        text = \"words and words and words and more words...\"\n        rc = -1\n        fontsize = 12\n        page.draw_rect(r)\n        while rc < 0:\n            rc = page.insert_textbox(\n                r,\n                text,\n                fontsize=fontsize,\n                align=pymupdf.TEXT_ALIGN_JUSTIFY,\n            )\n            fontsize -= 0.5\n\n        blocks = page.get_text(\"blocks\")\n        bbox = pymupdf.Rect(blocks[0][:4])\n        assert bbox in r\n    finally:\n        # Must restore small_glyph_heights, otherwise other tests can fail.\n        pymupdf.TOOLS.set_small_glyph_heights(small_glyph_heights0)\n\n\ndef test_2637():\n    \"\"\"Ensure correct calculation of fitting text.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    text = (\n        \"The morning sun painted the sky with hues of orange and pink. \"\n        \"Birds chirped harmoniously, greeting the new day. \"\n        \"Nature awakened, filling the air with life and promise.\"\n    )\n    rect = pymupdf.Rect(50, 50, 500, 280)\n    fontsize = 50\n    rc = -1\n    while rc < 0:  # look for largest font size that makes the text fit\n        rc = page.insert_textbox(rect, text, fontname=\"hebo\", fontsize=fontsize)\n        fontsize -= 1\n\n    # confirm text won't lap outside rect\n    blocks = page.get_text(\"blocks\")\n    bbox = pymupdf.Rect(blocks[0][:4])\n    assert bbox in rect\n\n\ndef test_htmlbox1():\n    \"\"\"Write HTML-styled text into a rect with different rotations.\n\n    The text is styled and contains a link.\n    Then extract the text again, and\n    - assert that text was written in the 4 different angles,\n    - assert that text properties are correct (bold, italic, color),\n    - assert that the link has been correctly inserted.\n\n    We try to insert into a rectangle that is too small, setting\n    scale=False and confirming we have a negative return code.\n    \"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"'test_htmlbox1' not executed in classic.\")\n        return\n\n    rect = pymupdf.Rect(100, 100, 200, 200)  # this only works with scale=True\n\n    base_text = \"\"\"Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.\"\"\"\n\n    text = \"\"\"Lorem ipsum dolor sit amet, consectetur adipisici elit, sed eiusmod tempor incidunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation <b>ullamco</b> <i>laboris</i> nisi ut aliquid ex ea commodi consequat. Quis aute iure reprehenderit in <span style=\"color: #0f0;font-weight:bold;\">voluptate</span> velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint obcaecat cupiditat non proident, sunt in culpa qui <a href=\"https://www.artifex.com\">officia</a> deserunt mollit anim id est laborum.\"\"\"\n\n    doc = pymupdf.Document()\n\n    for rot in (0, 90, 180, 270):\n        wdirs = ((1, 0), (0, -1), (-1, 0), (0, 1))  # all writing directions\n        page = doc.new_page()\n        spare_height, scale = page.insert_htmlbox(rect, text, rotate=rot, scale_low=1)\n        assert spare_height < 0\n        assert scale == 1\n        spare_height, scale = page.insert_htmlbox(rect, text, rotate=rot, scale_low=0)\n        page.draw_rect(rect, (1, 0, 0))\n        doc.save(os.path.normpath(f'{__file__}/../../tests/test_htmlbox1.pdf'))\n        assert abs(spare_height - 3.8507) < 0.001\n        assert 0 < scale < 1\n        page = doc.reload_page(page)\n        link = page.get_links()[0]  # extracts the links on the page\n\n        assert link[\"uri\"] == \"https://www.artifex.com\"\n\n        # Assert plain text is complete.\n        # We must remove line breaks and any ligatures for this.\n        assert base_text == page.get_text(flags=0)[:-1].replace(\"\\n\", \" \")\n\n        encounters = 0  # counts the words with selected properties\n        for b in page.get_text(\"dict\")[\"blocks\"]:\n            for l in b[\"lines\"]:\n                wdir = l[\"dir\"]  # writing direction\n                assert wdir == wdirs[page.number]\n                for s in l[\"spans\"]:\n                    stext = s[\"text\"]\n                    color = pymupdf.sRGB_to_pdf(s[\"color\"])\n                    bold = bool(s[\"flags\"] & 16)\n                    italic = bool(s[\"flags\"] & 2)\n                    if stext in (\"ullamco\", \"laboris\", \"voluptate\"):\n                        encounters += 1\n                        if stext == \"ullamco\":\n                            assert bold is True\n                            assert italic is False\n                            assert color == pymupdf.pdfcolor[\"black\"]\n                        elif stext == \"laboris\":\n                            assert bold is False\n                            assert italic is True\n                            assert color == pymupdf.pdfcolor[\"black\"]\n                        elif stext == \"voluptate\":\n                            assert bold is True\n                            assert italic is False\n                            assert color == pymupdf.pdfcolor[\"green\"]\n                    else:\n                        assert bold is False\n                        assert italic is False\n        # all 3 special special words were encountered\n        assert encounters == 3\n\n\ndef test_htmlbox2():\n    \"\"\"Test insertion without scaling\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"'test_htmlbox2' not executed in classic.\")\n        return\n\n    doc = pymupdf.open()\n    rect = pymupdf.Rect(100, 100, 200, 200)  # large enough to hold text\n    page = doc.new_page()\n    bottoms = set()\n    for rot in (0, 90, 180, 270):\n        spare_height, scale = page.insert_htmlbox(\n            rect, \"Hello, World!\", scale_low=1, rotate=rot\n        )\n        assert scale == 1\n        assert 0 < spare_height < rect.height\n        bottoms.add(spare_height)\n    assert len(bottoms) == 1  # same result for all rotations\n\n\ndef test_htmlbox3():\n    \"\"\"Test insertion with opacity\"\"\"\n    if not hasattr(pymupdf, \"mupdf\"):\n        print(\"'test_htmlbox3' not executed in classic.\")\n        return\n\n    rect = pymupdf.Rect(100, 250, 300, 350)\n    text = \"\"\"<span style=\"color:red;font-size:20px;\">Just some text.</span>\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n\n    # insert some text with opacity\n    page.insert_htmlbox(rect, text, opacity=0.5)\n\n    # lowlevel-extract inserted text to access opacity\n    span = page.get_texttrace()[0]\n    assert span[\"opacity\"] == 0.5\n\n\ndef test_3559():\n    doc = pymupdf.Document()\n    page = doc.new_page()\n    text_insert=\"\"\"<body><h3></h3></body>\"\"\"\n    rect = pymupdf.Rect(100, 100, 200, 200)\n    page.insert_htmlbox(rect, text_insert)\n\n\ndef test_3916():\n    doc = pymupdf.open()\n    rect = pymupdf.Rect(100, 100, 101, 101) # Too small for the text.\n    page = doc.new_page()\n    spare_height, scale = page.insert_htmlbox(rect, \"Hello, World!\", scale_low=0.5)\n    assert spare_height == -1\n\n\ndef test_4400():\n    with pymupdf.open() as document:\n        page = document.new_page()\n        writer = pymupdf.TextWriter(page.rect)\n        text = '111111111'\n        print(f'Calling writer.fill_textbox().', flush=1)\n        writer.fill_textbox(rect=pymupdf.Rect(0, 0, 100, 20), pos=(80, 0), text=text, fontsize=8)\n\n\ndef test_4613():\n    print()\n    text = 3 * 'abcdefghijklmnopqrstuvwxyz\\nABCDEFGHIJKLMNOPQRSTUVWXYZ\\n'\n    story = pymupdf.Story(text)\n    rect = pymupdf.Rect(10, 10, 100, 100)\n    \n    # Test default operation where we get additional scaling down because of\n    # the long words in our text.\n    print(f'test_4613(): ### Testing default operation.')\n    with pymupdf.open() as doc:\n        page = doc.new_page()\n        spare_height, scale = page.insert_htmlbox(rect, story)\n        print(f'test_4613(): {spare_height=} {scale=}')\n        # The additional down-scaling from the long word widths results in\n        # spare vertical space.\n        page.draw_rect(rect, (1, 0, 0))\n        path = os.path.normpath(f'{__file__}/../../tests/test_4613.pdf')\n        doc.save(path)\n\n        path_pixmap = os.path.normpath(f'{__file__}/../../tests/test_4613.png')\n        path_pixmap_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4613.png')\n        pixmap = page.get_pixmap(dpi=300)\n        pixmap.save(path_pixmap)\n        \n        pixmap_diff = gentle_compare.pixmaps_diff(path_pixmap_expected, pixmap)\n        pixmap_diff.save(os.path.normpath(f'{__file__}/../../tests/test_4613-diff.png'))\n        \n        rms = gentle_compare.pixmaps_rms(pixmap, path_pixmap_expected)\n        print(f'{rms=}')\n        assert rms == 0, f'{rms=}'\n    \n        assert abs(spare_height - 45.7536) < 0.1\n        assert abs(scale - 0.4009) < 0.01\n\n        new_text = page.get_text('text', clip=rect)\n        print(f'test_4613(): new_text:')\n        print(textwrap.indent(new_text, '    '))\n        assert new_text == text\n\n    # Check with _scale_word_width=False - ignore too-wide words.\n    print(f'test_4613(): ### Testing with _scale_word_width=False.')\n    with pymupdf.open() as doc:\n        page = doc.new_page()\n        spare_height, scale = page.insert_htmlbox(rect, story, _scale_word_width=False)\n        print(f'test_4613(): _scale_word_width=False: {spare_height=} {scale=}')\n        # With _scale_word_width=False we allow long words to extend beyond the\n        # rect, so we should have spare_height == 0 and only a small amount of\n        # down-scaling.\n        assert spare_height == 0\n        assert abs(scale - 0.914) < 0.01\n        new_text = page.get_text('text', clip=rect)\n        print(f'test_4613(): new_text:')\n        print(textwrap.indent(new_text, '    '))\n        assert new_text == textwrap.dedent('''\n                abcdefghijklmno\n                ABCDEFGHIJKLM\n                abcdefghijklmno\n                ABCDEFGHIJKLM\n                abcdefghijklmno\n                ABCDEFGHIJKLM\n                ''')[1:]\n        \n\n    # Check that we get no fit if scale_low is not low enough.\n    print(f'test_4613(): ### Testing with scale_low too high to allow a fit.')\n    with pymupdf.open() as doc:\n        page = doc.new_page()\n        scale_low=0.6\n        spare_height, scale = page.insert_htmlbox(rect, story, scale_low=scale_low)\n        print(f'test_4613(): {scale_low=}: {spare_height=} {scale=}')\n        assert spare_height == -1\n        assert scale == scale_low\n"
  },
  {
    "path": "tests/test_textextract.py",
    "content": "\"\"\"\nExtract page text in various formats.\nNo checks performed - just contribute to code coverage.\n\"\"\"\nimport os\nimport platform\nimport sys\nimport textwrap\n\nimport pymupdf\n\nimport gentle_compare\n\n\npymupdfdir = os.path.abspath(f'{__file__}/../..')\nscriptdir = f'{pymupdfdir}/tests'\nfilename = os.path.join(scriptdir, \"resources\", \"symbol-list.pdf\")\n\n\ndef test_extract1():\n    doc = pymupdf.open(filename)\n    page = doc[0]\n    text = page.get_text(\"text\")\n    blocks = page.get_text(\"blocks\")\n    words = page.get_text(\"words\")\n    d1 = page.get_text(\"dict\")\n    d2 = page.get_text(\"json\")\n    d3 = page.get_text(\"rawdict\")\n    d3 = page.get_text(\"rawjson\")\n    text = page.get_text(\"html\")\n    text = page.get_text(\"xhtml\")\n    text = page.get_text(\"xml\")\n    rects = pymupdf.get_highlight_selection(page, start=page.rect.tl, stop=page.rect.br)\n    text = pymupdf.ConversionHeader(\"xml\")\n    text = pymupdf.ConversionTrailer(\"xml\")\n\ndef _test_extract2():\n    import sys\n    import time\n    path = f'{scriptdir}/../../PyMuPDF-performance/adobe.pdf'\n    if not os.path.exists(path):\n        print(f'test_extract2(): not running because does not exist: {path}')\n        return\n    doc = pymupdf.open( path)\n    for opt in (\n            'dict',\n            'dict2',\n            'text',\n            'blocks',\n            'words',\n            'html',\n            'xhtml',\n            'xml',\n            'json',\n            'rawdict',\n            'rawjson',\n            ):\n        for flags in None, pymupdf.TEXTFLAGS_TEXT:\n            t0 = time.time()\n            for page in doc:\n                page.get_text(opt, flags=flags)\n            t = time.time() - t0\n            print(f't={t:.02f}: opt={opt} flags={flags}')\n            sys.stdout.flush()\n\ndef _test_extract3():\n    import sys\n    import time\n    path = f'{scriptdir}/../../PyMuPDF-performance/adobe.pdf'\n    if not os.path.exists(path):\n        print(f'test_extract3(): not running because does not exist: {path}')\n        return\n    doc = pymupdf.open( path)\n    t0 = time.time()\n    for page in doc:\n        page.get_text('json')\n    t = time.time() - t0\n    print(f't={t}')\n    sys.stdout.flush()\n    \ndef test_extract4():\n    '''\n    Rebased-specific.\n    '''\n    if not hasattr(pymupdf, 'mupdf'):\n        return\n    path = f'{pymupdfdir}/tests/resources/2.pdf'\n    document = pymupdf.open(path)\n    page = document[4]\n    \n    out = 'test_stext.html'\n    text = page.get_text('html')\n    with open(out, 'w') as f:\n        f.write(text)\n    print(f'Have written to: {out}')\n    \n    out = 'test_extract.html'\n    writer = pymupdf.mupdf.FzDocumentWriter(\n            out,\n            'html',\n            pymupdf.mupdf.FzDocumentWriter.OutputType_DOCX,\n            )\n    device = pymupdf.mupdf.fz_begin_page(writer, pymupdf.mupdf.fz_bound_page(page))\n    pymupdf.mupdf.fz_run_page(page, device, pymupdf.mupdf.FzMatrix(), pymupdf.mupdf.FzCookie())\n    pymupdf.mupdf.fz_end_page(writer)\n    pymupdf.mupdf.fz_close_document_writer(writer)\n    print(f'Have written to: {out}')\n    \n    def get_text(page, space_guess):\n        buffer_ = pymupdf.mupdf.FzBuffer( 10)\n        out = pymupdf.mupdf.FzOutput( buffer_)\n        writer = pymupdf.mupdf.FzDocumentWriter(\n                out,\n                f'text,space-guess={space_guess}',\n                pymupdf.mupdf.FzDocumentWriter.OutputType_DOCX,\n                )\n        device = pymupdf.mupdf.fz_begin_page(writer, pymupdf.mupdf.fz_bound_page(page))\n        pymupdf.mupdf.fz_run_page(page, device, pymupdf.mupdf.FzMatrix(), pymupdf.mupdf.FzCookie())\n        pymupdf.mupdf.fz_end_page(writer)\n        pymupdf.mupdf.fz_close_document_writer(writer)\n        text = buffer_.fz_buffer_extract()\n        text = text.decode('utf8')\n        n = text.count(' ')\n        print(f'{space_guess=}: {n=}')\n        return text, n\n    page = document[4]\n    text0, n0 = get_text(page, 0)\n    text1, n1 = get_text(page, 0.5)\n    text2, n2 = get_text(page, 0.001)\n    text2, n2 = get_text(page, 0.1)\n    text2, n2 = get_text(page, 0.3)\n    text2, n2 = get_text(page, 0.9)\n    text2, n2 = get_text(page, 5.9)\n    assert text1 == text0\n\ndef test_2954():\n    '''\n    Check handling of unknown unicode characters, issue #2954, fixed in\n    mupdf-1.23.9 with addition of FZ_STEXT_USE_CID_FOR_UNKNOWN_UNICODE.\n    '''\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2954.pdf')\n    flags0 = (0\n            | pymupdf.TEXT_PRESERVE_WHITESPACE\n            | pymupdf.TEXT_PRESERVE_LIGATURES\n            | pymupdf.TEXT_MEDIABOX_CLIP\n            )\n    \n    document = pymupdf.Document(path)\n    \n    expected_good = (\n            \"IT-204-IP (2021) Page 3 of 5\\nNYPA2514    12/06/21\\nPartner's share of \\n\"\n            \" modifications (see instructions)\\n20\\n State additions\\nNumber\\n\"\n            \"A ' Total amount\\nB '\\n State allocated amount\\n\"\n            \"EA '\\n20a\\nEA '\\n20b\\nEA '\\n20c\\nEA '\\n20d\\nEA '\\n20e\\nEA '\\n20f\\n\"\n            \"Total addition modifications (total of column A, lines 20a through 20f)\\n\"\n            \". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . \\n\"\n            \"21\\n21\\n22\\n State subtractions\\n\"\n            \"Number\\nA ' Total amount\\nB '\\n State allocated amount\\n\"\n            \"ES '\\n22a\\nES '\\n22b\\nES '\\n22c\\nES '\\n22d\\nES '\\n22e\\nES '\\n22f\\n23\\n23\\n\"\n            \"Total subtraction modifications (total of column A, lines 22a through 22f). . . . . . . . . . . . . . . . . . . . . . . . . . . . \\n\"\n            \"Additions to itemized deductions\\n24\\nAmount\\n\"\n            \"Letter\\n\"\n            \"24a\\n24b\\n24c\\n24d\\n24e\\n24f\\n\"\n            \"Total additions to itemized deductions (add lines 24a through 24f)\\n\"\n            \". . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . \\n\"\n            \"25\\n25\\n\"\n            \"Subtractions from itemized deductions\\n\"\n            \"26\\nLetter\\nAmount\\n26a\\n26b\\n26c\\n26d\\n26e\\n26f\\n\"\n            \"Total subtractions from itemized deductions (add lines 26a through 26f) . . . . . . . . . . . . . . . . . . . . . . . . . . . . \\n\"\n            \"27\\n27\\n\"\n            \"This line intentionally left blank. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . \\n\"\n            \"28\\n28\\n118003213032\\n\"\n            )\n    \n    def check_good(text):\n        '''\n        Returns true if `text` is approximately the same as `expected_good`.\n\n        2024-01-09: MuPDF master and 1.23.x give slightly different 'good'\n        output, differing in a missing newline. So we compare without newlines.\n        '''\n        return text.replace('\\n', '') == expected_good.replace('\\n', '')\n    \n    n_fffd_good = 0\n    n_fffd_bad = 749\n    \n    def get(flags=None):\n        text = [page.get_text(flags=flags) for page in document]\n        assert len(text) == 1\n        text = text[0]\n        n_fffd = text.count(chr(0xfffd))\n        if 0:\n            # This print() fails on Windows with UnicodeEncodeError.\n            print(f'{flags=} {n_fffd=} {text=}')\n        return text, n_fffd\n    \n    text_none, n_fffd_none = get()\n    text_0, n_fffd_0 = get(flags0)\n    \n    text_1, n_fffd_1 = get(flags0 | pymupdf.TEXT_USE_CID_FOR_UNKNOWN_UNICODE)\n\n    assert n_fffd_none == n_fffd_good\n    assert n_fffd_0 == n_fffd_bad\n    assert n_fffd_1 == n_fffd_good\n\n    assert check_good(text_none)\n    assert not check_good(text_0)\n    assert check_good(text_1)\n\n\ndef test_3027():\n    path = path = f'{pymupdfdir}/tests/resources/2.pdf'\n    doc = pymupdf.open(path)\n    page = doc[0]\n    textpage = page.get_textpage()\n    pymupdf.utils.get_text(page=page, option=\"dict\", textpage=textpage)[\"blocks\"]\n\n\ndef test_3186():\n\n    # codespell:ignore-begin\n    texts_expected = [\n            \"Assicurazione sulla vita di tipo Unit Linked\\nDocumento informativo precontrattuale aggiuntivo\\nper i prodotti d\\x00investimento assicurativi\\n(DIP aggiuntivo IBIP)\\nImpresa: AXA MPS Financial DAC                                                    \\nProdotto: Progetto Protetto New - Global Dividends\\nContratto Unit linked (Ramo III)\\nData di realizzazione: Aprile 2023\\nIl presente documento contiene informazioni aggiuntive e complementari rispetto a quelle presenti nel documento \\ncontenente le informazioni chiave per i prodotti di investimento assicurativi (KID) per aiutare il potenziale \\ncontraente a capire più nel dettaglio le caratteristiche del prodotto, gli obblighi contrattuali e la situazione \\npatrimoniale dell\\x00impresa.\\nIl Contraente deve prendere visione delle condizioni d\\x00assicurazione prima della sottoscrizione del Contratto.\\nAXA MPS Financial DAC, Wolfe Tone House, Wolfe Tone Street, Dublin, DO1 HP90, Irlanda; Tel: 00353-1-6439100; \\nsito internet: www.axa-mpsfinancial.ie; e-mail: supporto@axa-mpsfinancial.ie;\\nAXA MPS Financial DAC, società del Gruppo Assicurativo AXA Italia, iscritta nell\\x00Albo delle Imprese di assicurazione \\ncon il numero II.00234. \\nLa Compagnia mette a disposizione dei clienti i seguenti recapiti per richiedere eventuali informazioni sia in merito alla \\nCompagnia sia in relazione al contratto proposto: Tel: 00353-1-6439100; sito internet:  www.axa-mpsfinancial.ie; \\ne-mail: supporto@axa-mpsfinancial.ie;\\nAXA MPS Financial DAC è un\\x00impresa di assicurazione di diritto Irlandese, Sede legale 33 Sir John Rogerson's Quay, \\nDublino D02 XK09 Irlanda. L\\x00Impresa di Assicurazione è stata autorizzata all\\x00esercizio dell\\x00attività assicurativa con \\nprovvedimento n. C33602 emesso dalla Central Bank of Ireland (l\\x00Autorità di vigilanza irlandese) in data 14/05/1999 \\ned è iscritta in Irlanda presso il Companies Registration Office (registered nr. 293822). \\nLa Compagnia opera in Italia esclusivamente in regime di libera prestazione di servizi ai sensi dell\\x00art. 24 del D. Lgs. \\n07/09/2005, n. 209 e può investire in attivi non consentiti dalla normativa italiana in materia di assicurazione sulla \\nvita, ma in conformità con la normativa irlandese di riferimento in quanto soggetta al controllo della Central Bank of \\nIreland.\\nCon riferimento all\\x00ultimo bilancio d\\x00esercizio (esercizio 2021) redatto ai sensi dei principi contabili vigenti, il patrimonio \\nnetto di AXA MPS Financial DAC ammonta a 139,6 milioni di euro di cui 635 mila euro di capitale sociale interamente \\nversato e 138,9 milioni di euro di riserve patrimoniali compreso il risultato di esercizio.\\nAl 31 dicembre 2021 il Requisito patrimoniale di solvibilità è pari a 90 milioni di euro (Solvency Capital Requirement, \\nSCR). Sulla base delle valutazioni effettuate della Compagnia coerentemente con gli esistenti dettami regolamentari, il \\nRequisito patrimoniale minimo al 31 dicembre 2021 ammonta a 40 milioni di euro (Minimum Capital Requirement, \\nMCR).\\nL'indice di solvibilità di AXA MPS Financial DAC, ovvero l'indice che rappresenta il rapporto tra l'ammontare del margine \\ndi solvibilità disponibile e l'ammontare del margine di solvibilità richiesto dalla normativa vigente, e relativo all'ultimo \\nbilancio approvato, è pari al   304% (solvency ratio). L'importo dei fondi propri ammissibili a copertura dei requisiti \\npatrimoniali è pari a 276 milioni di euro (Eligible Own Funds, EOF).\\nPer informazioni patrimoniali sulla società è possibile consultare il sito: www.axa-mpsfinancial.ie/chi-siamo\\nSi rinvia alla relazione sulla solvibilità e sulla condizione finanziaria dell\\x00impresa (SFCR) disponibile sul sito internet \\ndella Compagnia al seguente link www.axa-mpsfinancial.ie/comunicazioni   \\nAl contratto si applica la legge italiana\\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 1 di 9\\n\",\n            \"Quali sono le prestazioni?\\nIl contratto prevede le seguenti prestazioni:\\na)Prestazioni in caso di vita dell'assicurato\\nPrestazione in caso di Riscatto Totale e parziale\\nA condizione che siano trascorsi almeno 30 giorni dalla Data di Decorrenza (conclusione del Contratto) e fino all\\x00ultimo \\nGiorno Lavorativo della terzultima settimana precedente la data di scadenza, il Contraente può riscuotere, interamente \\no parzialmente, il Valore di Riscatto. In caso di Riscatto totale, la liquidazione del Valore di Riscatto pone fine al \\nContratto con effetto dalla data di ricezione della richiesta.\\nIl Contraente ha inoltre la facoltà di esercitare parzialmente il diritto di Riscatto, nella misura minima di 500,00 euro, \\nda esercitarsi con le stesse modalità previste per il Riscatto totale. In questo caso, il Contratto rimane in vigore per \\nl\\x00ammontare residuo, a condizione che il Controvalore delle Quote residue del Contratto non sia inferiore a 1.000,00 \\neuro.\\nb) Prestazione a Scadenza\\nAlla data di scadenza, sempre che l\\x00Assicurato sia in vita, l\\x00Impresa di Assicurazione corrisponderà agli aventi diritto un \\nammontare risultante dal Controvalore delle Quote collegate al Contratto alla scadenza, calcolato come prodotto tra il \\nValore Unitario della Quota (rilevato in corrispondenza della data di scadenza) e il numero delle Quote attribuite al \\nContratto alla medesima data.\\nc) Prestazione in corso di Contratto\\nPurché l\\x00assicurato sia in vita, nel corso della durata del Contratto, il Fondo Interno mira alla corresponsione di due \\nPrestazioni Periodiche. Le prestazioni saranno pari all\\x00ammontare risultante dalla moltiplicazione tra il numero di Quote \\nassegnate al Contratto il primo giorno Lavorativo della settimana successiva alla Data di Riferimento e 2,50% del \\nValore Unitario della Quota registrato alla Data di istituzione del Fondo Interno.\\nLe prestazioni verranno liquidate entro trenta giorni dalle Date di Riferimento.\\nData di Riferimento\\n 1° Prestazione Periodica\\n24/04/2024\\n 2° Prestazione Periodica\\n23/04/2025\\nLa corresponsione delle Prestazioni Periodiche non è collegata alla performance positiva o ai ricavi incassati dal Fondo \\nInterno, pertanto, la corresponsione potrebbe comportare una riduzione del Controvalore delle Quote senza comportare \\nalcuna riduzione del numero di Quote assegnate al Contratto.\\nd) Prestazione assicurativa principale in caso di decesso dell'Assicurato\\nIn caso di decesso dell\\x00Assicurato nel corso della durata contrattuale, è previsto il pagamento ai Beneficiari di un \\nimporto pari al Controvalore delle Quote attribuite al Contratto, calcolato come prodotto tra il Valore Unitario della \\nQuota rilevato alla Data di Valorizzazione della settimana successiva alla data in cui la notifica di decesso \\ndell\\x00Assicurato perviene all\\x00Impresa di Assicurazione e il numero delle Quote attribuite al Contratto alla medesima data, \\nmaggiorato di una percentuale pari allo 0,1%.\\nQualora il capitale così determinato fosse inferiore al Premio pagato, sarà liquidato un ulteriore importo pari alla \\ndifferenza tra il Premio pagato, al netto della parte di Premio riferita a eventuali Riscatti parziali e l\\x00importo caso morte \\ncome sopra determinato. Tale importo non potrà essere in ogni caso superiore al 5% del Premio pagato.\\nOpzioni contrattuali\\nIl Contratto non prevede opzioni contrattuali.\\nFondi Assicurativi\\nLe prestazioni di cui sopra sono collegate, in base all\\x00allocazione del premio come descritto alla sezione \\x01Quando e \\ncome devo pagare?\\x02, al valore delle quote del Fondo Interno denominato PP27 Global Dividends.\\nil Fondo interno mira al raggiungimento di un Obiettivo di Protezione del Valore Unitario di Quota, tramite il \\nconseguimento di un Valore Unitario di Quota a scadenza almeno pari al 100% del valore di quota registrato alla Data \\ndi istituzione dal Fondo Interno.\\nIl regolamento di gestione del Fondo Interno è disponibile sul sito dell\\x00Impresa di Assicurazione \\nwww.axa-mpsfinancial.ie dove puo essere acquisito su supporto duraturo.\\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 2 di 9\\n\",\n            'Che cosa NON è assicurato\\nRischi esclusi\\nIl rischio di decesso dell\\x00Assicurato è coperto qualunque sia la causa, senza limiti territoriali e senza \\ntenere conto dei cambiamenti di professione dell\\x00Assicurato, ad eccezione dei seguenti casi:\\n\\x03 il decesso, entro i primi sette anni dalla data di decorrenza del Contratto, dovuto alla sindrome da \\nimmunodeficienza acquisita (AIDS) o ad altra patologia ad essa associata;\\n\\x03 dolo del Contraente o del Beneficiario;\\n\\x03 partecipazione attiva dell\\x00Assicurato a delitti dolosi;\\n\\x03 partecipazione dell\\x00Assicurato a fatti di guerra, salvo che non derivi da obblighi verso lo Stato \\nItaliano: in questo caso la garanzia può essere prestata su richiesta del Contraente, alle condizioni \\nstabilite dal competente Ministero;\\n\\x03 incidente di volo, se l\\x00Assicurato viaggia a bordo di un aeromobile non autorizzato al volo o con \\npilota non titolare di brevetto idoneo e, in ogni caso, se viaggia in qualità di membro \\ndell\\x00equipaggio;\\n\\x03 suicidio, se avviene nei primi due anni dalla Data di Decorrenza del Contratto\\nCi sono limiti di copertura?\\nNon vi sono ulteriori informazioni rispetto al contenuto del KID.\\nChe obblighi ho? Quali obblighi ha l\\x00Impresa?\\nCosa fare in caso \\ndi evento?\\nDenuncia\\nCon riferimento alla liquidazione delle prestazioni dedotte in Contratto, il Contraente o, se del caso, \\nil Beneficiario e il Referente Terzo, sono tenuti a recarsi presso la sede dell\\x00intermediario presso il \\nquale il Contratto è stato sottoscritto ovvero a inviare preventivamente, a mezzo di lettera \\nraccomandata con avviso di ricevimento al seguente recapito:\\n\\x03 AXA MPS Financial DAC\\n\\x03 Wolfe Tone House, Wolfe Tone Street,\\n\\x03 Dublin, DO1 HP90 - Ireland\\n\\x03 Numero Verde: 800.231.187\\n\\x03 email: supporto@axa-mpsfinancial.ie\\ni documenti di seguito elencati per ciascuna prestazione, al fine di consentire all\\x00Impresa di \\nAssicurazione di verificare l\\x00effettiva esistenza dell\\x00obbligo di pagamento.\\nin caso di Riscatto totale, il Contraente deve inviare all\\x00Impresa di Assicurazione:\\n\\x04 la richiesta di Riscatto totale firmata dal Contraente, indicando il conto corrente su cui il \\npagamento deve essere effettuato. Nel caso il conto corrente sia intestato a persona diversa dal \\nContraente o dai beneficiari o sia cointestato, il Contraente deve fornire anche I documenti del \\ncointestatario e specificare la relazione con il terzo il cui conto viene indicato.\\n\\x04 copia di un valido documento di identità del Contraente o di un documento attestante i poteri di \\nlegale rappresentante, nel caso in cui il Contraente sia una persona giuridica;\\nin caso di Riscatto parziale, il Contraente deve inviare all\\x00Impresa di Assicurazione:\\n\\x04 la richiesta di Riscatto parziale firmata dal Contraente, contenente l\\x00indicazione dei Fondi \\nInterni/OICR che intende riscattare e il relativo ammontare non ché l\\x00indicazione del conto corrente \\nbancario sul quale effettuare il pagamento;\\n\\x04 copia di un valido documento di identità del Contraente, o di un documento attestante i poteri di \\nlegale rappresentante, nel caso in cui il Contraente sia una persona giuridica.\\nIn caso di richiesta di Riscatto totale o parziale non corredata dalla sopra elencata documentazione, \\nl\\x00Impresa di Assicurazione effettuerà il disinvestimento delle Quote collegate al Contratto alla data \\ndi ricezione della relativa richiesta. L\\x00Impresa di Assicurazione provvederà tuttavia alla liquidazione \\ndelle somme unicamente al momento di ricezione della documentazione mancante, prive degli \\neventuali interessi che dovessero maturare;\\nIn caso di decesso dell\\x00Assicurato, il Beneficiario/i o il Referente Terzo deve inviare all\\x00Impresa di \\nAssicurazione:\\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 3 di 9\\n',\n            '\\x04 la richiesta di pagamento sottoscritta da tutti i Beneficiari, con l\\x00indicazione del conto corrente \\nbancario sul quale effettuare il pagamento; Nel caso il conto corrente sia intestato a persona \\ndiversa dal Contraente o dai beneficiari o sia cointestato, il Contraente deve fornire anche I \\ndocumenti del cointestatario e specificare la relazione con il terzo il cui conto viene indicato.\\n\\x04 copia di un valido documento d\\x00identità dei Beneficiari o di un documento attestante i poteri di \\nlegale rappresentante, nel caso in cui il Beneficiario sia una persona giuridica;\\n\\x04 il certificato di morte dell\\x00Assicurato;\\n\\x04 la relazione medica sulle cause del decesso;\\n\\x04 copia autenticata del testamento accompagnato da dichiarazione sostitutiva di atto di notorietà \\ncon l\\x00indicazione (i) della circostanza che il testamento è l\\x00ultimo da considerarsi valido e non è \\nstato impugnato e (ii) degli eredi testamentari, le relative età e capacità\\ndi agire;\\n\\x04 in assenza di testamento, atto notorio (o dichiarazione sostitutiva di atto di notorietà) attestante \\nche il decesso è avvenuto senza lasciare testamento e che non vi sono altri soggetti cui la legge \\nriconosce diritti o quote di eredità;\\n\\x04 decreto del Giudice Tutelare nel caso di Beneficiari di minore età, con l\\x00indicazione della persona \\ndesignata alla riscossione;\\n\\x04 copia del Questionario KYC.\\nPrescrizione: Alla data di redazione del presente documento, i diritti dei beneficiari dei contratti di \\nassicurazione sulla vita si prescrivono nel termine di dieci anni dal giorno in cui si è verificato il fatto \\nsu cui il diritto si fonda. Decorso tale termine e senza che la Compagnia abbia ricevuto alcuna \\ncomunicazione e/o disposizione, gli importi derivanti dal contratto saranno devoluti al Fondo \\ncostitutivo presso il Ministero dell\\x00Economia e delle Finanze \\x01depositi dormienti\\x02.\\nErogazione della prestazione\\nL\\x00Impresa di Assicurazione esegue il pagamento entro trenta giorni dal ricevimento della \\ndocumentazione completa all\\x00indirizzo sopra indicato.\\n \\nLe dichiarazioni del Contraente, e dell\\x00Assicurato se diverso dal Contraente, devono essere esatte e \\nveritiere. In caso di dichiarazioni inesatte o reticenti relative a circostanze tali che l\\x00Impresa di \\nAssicurazione non avrebbe dato il suo consenso, non lo avrebbe dato alle medesime condizioni se \\navesse conosciuto il vero stato delle cose, l\\x00Impresa di Assicurazione ha diritto a:\\na) in caso di dolo o colpa grave:\\n\\x04 impugnare il Contratto dichiarando al Contraente di voler esercitare tale diritto entro tre mesi dal \\ngiorno in cui ha conosciuto l\\x00inesattezza della dichiarazione o le reticenze;\\n\\x04 trattenere il Premio relativo al periodo di assicurazione in corso al momento dell\\x00impugnazione e, \\nin ogni caso, il Premio corrispondente al primo anno;\\n\\x04 restituire, in caso di decesso dell\\x00Assicurato, solo il Controvalore delle Quote acquisite al \\nmomento del decesso, se l\\x00evento si verifica prima che sia decorso il termine dianzi indicato per \\nl\\x00impugnazione;\\nb) ove non sussista dolo o colpa grave:\\n\\x04 recedere dal Contratto, mediante dichiarazione da farsi al Contraente entro tre mesi dal giorno in \\ncui ha conosciuto l\\x00inesattezza della dichiarazione o le reticenze;\\n\\x04 se il decesso si verifica prima che l\\x00inesattezza della dichiarazione o la reticenza sia conosciuta \\ndall\\x00Impresa di Assicurazione, o prima che l\\x00Impresa abbia dichiarato di recedere dal Contratto, di \\nridurre la somma dovuta in proporzione alla differenza tra il Premio convenuto e quello che sarebbe \\nstato applicato se si fosse conosciuto il vero stato delle cose.\\nIl Contraente è tenuto a inoltrare per iscritto alla Compagnia (posta ordinaria e mail) eventuali \\ncomunicazioni inerenti:\\n-modifiche dell\\x00indirizzo presso il quale intende ricevere le comunicazioni relative al contratto;\\n-variazione della residenza Europea nel corso della durata del contratto, presso altro Paese \\nmembro della Unione Europea;\\n-variazione degli estremi di conto corrente bancario.\\nIn tal caso è necessario inoltrare la richiesta attraverso l\\x00invio del modulo del mandato, compilato e \\nsottoscritto dal contraente, reperibile nella sezione \\x01comunicazioni\\x02 sul sito internet della \\ncompagnia all\\x00indirizzo www.axa-mpsfinancial.ie\\nFATCA (Foreign Account Tax Compliance Act) e CRS (Common Standard Reporting)\\nLa normativa denominata rispettivamente FATCA (Foreign Account Tax Compliance Act - \\nIntergovernmental Agreement sottoscritto tra Italia e Stati Uniti in data 10 gennaio 2014 e Legge n. \\n95 del 18 giugno 2015) e CRS (Common Reporting Standard - Decreto Ministeriale del 28 \\ndicembre 2015) impone agli operatori commerciali, al fine di contrastare la frode fiscale e \\nl\\x00evasione fiscale transfrontaliera, di eseguire la puntuale identificazione della propria clientela al \\nfine di determinarne l\\x00effettivo status di contribuente estero.\\nDichiarazioni \\ninesatte o \\nreticenti\\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 4 di 9\\n',\n            \"I dati anagrafici e patrimoniali dei Contraenti identificati come fiscalmente residenti negli USA e/o \\nin uno o più Paesi aderenti al CRS, dovranno essere trasmessi all\\x00autorità fiscale locale, tramite \\nl\\x00Agenzia delle Entrate.\\nL\\x00identificazione avviene in fase di stipula del contratto e deve essere ripetuta in caso di \\ncambiamento delle condizioni originarie durante tutta la sua durata, mediante l\\x00acquisizione di \\nautocertificazione rilasciata dai Contraenti. Ogni contraente è tenuto a comunicare \\ntempestivamente eventuali variazioni rispetto a quanto dichiarato o rilevato in fase di sottoscrizione \\ndel contratto di assicurazione. La Società si riserva inoltre di verificare i dati raccolti e di richiedere \\nulteriori informazioni. In caso di autocertificazione che risulti compilata parzialmente o in maniera \\nerrata, nonché in caso di mancata/non corretta comunicazione dei propri dati anagrafici, la società \\nqualora abbia rilevato indizi di americanità e/o residenze fiscali estere nelle informazioni in suo \\npossesso, assocerà al cliente la condizione di contribuente estero, provvedendo alla comunicazione \\ndovuta.\\nAntiriciclaggio\\nIl Contraente è tenuto a fornire alla Compagnia tutte le informazioni necessarie al fine \\ndell\\x00assolvimento dell\\x00adeguata verifica ai fini antiriciclaggio. Qualora la Compagnia, in ragione \\ndella mancata collaborazione del Contraente, non sia in grado di portare a compimento l\\x00adeguata \\nverifica, la stessa non potrà concludere il Contratto o dovrà porre fine allo stesso. In tali ipotesi le \\nsomme dovute al Contraente dovranno essere allo stesso versate mediante bonifico a valere un \\nconto corrente intestato al Contraente stesso. In tali ipotesi le disponibilità finanziarie \\neventualmente già acquisite dalla Compagnia dovranno essere restituite al Contraente liquidando il \\nrelativo importo tramite bonifico bancario su un conto corrente bancario indicato dal Contraente e \\nallo stesso intestato.\\nIn nessun caso l'Impresa di Assicurazione sarà tenuta a fornire alcuna copertura assicurativa, \\nsoddisfare richieste di risarcimento o garantire alcuna indennità in virtù del presente contratto, \\nqualora tale copertura, pagamento o indennità possa esporla a divieti, sanzioni economiche o \\nrestrizioni ai sensi di Risoluzioni delle Nazioni Unite o sanzioni economiche o commerciali, leggi o \\nnorme dell\\x00Unione Europea, del Regno Unito o degli Stati Uniti d\\x00America, ove applicabili in Italia.\\nQuando e come devo pagare?\\nPremio\\nIl Contratto prevede il pagamento di un Premio Unico il cui ammontare minimo è pari a 2.500,00 \\neuro, incrementabile di importo pari o in multiplo di 50,00 euro, da corrispondersi in un\\x00unica \\nsoluzione prima della conclusione del Contratto.\\nNon è prevista la possibilità di effettuare versamenti aggiuntivi successivi.\\nIl versamento del Premio Unico può essere effettuato mediante addebito su conto corrente \\nbancario, indicato nel Modulo di Proposta, previa autorizzazione del titolare del conto corrente.\\nIl pagamento dei Premio Unico può essere eseguito mediante addebito su conto corrente bancario, \\nprevia autorizzazione, intestato al Contraente oppure tramite bonifico bancario sul conto corrente \\ndell\\x00Impresa di Assicurazione.\\nRimborso\\nIl rimborso del Premio Versato è previsto nel caso in cui il Contraente decida di revocare la proposta \\nfinché il contratto non è concluso.\\nSconti\\nAl verificarsi di condizioni particolari ed eccezionali che potrebbero riguardare \\x03 a titolo \\nesemplificativo ma non esaustivo \\x03 il Contraente e la relativa situazione assicurativo/finanziaria, \\nl\\x00ammontare del Premio pagato e gli investimenti selezionati dal Contraente, l\\x00Impresa di \\nAssicurazione si riserva la facoltà di applicare sconti sugli oneri previsti dal contratto, concordando \\ntale agevolazione con il Contraente.\\nQuando comincia la copertura e quando finisce?\\nDurata\\nIl Contratto ha una durata massima pari a 5 anni 11 mesi e 27 giorni, sino alla data di scadenza \\n(11/04/2029, la \\x01data di scadenza\\x02).\\nSospensione\\nNon sono possibili delle sospensioni della copertura assicurativa\\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 5 di 9\\n\",\n            'Come posso revocare la proposta, recedere dal contratto o risolvere il contratto? \\nRevoca\\nLa Proposta di assicurazione può essere revocata fino alle ore 24:00 del giorno in cui il Contratto è \\nconcluso. In tal caso, l\\x00Impresa di Assicurazione restituirà al Contraente il Premio pagato entro \\ntrenta giorni dal ricevimento della comunicazione di Revoca.\\nRecesso\\nIl Contraente può recedere dal Contratto entro trenta giorni dalla sua conclusione. Il Recesso dovrà \\nessere comunicato all\\x00Impresa di Assicurazione mediante lettera raccomandata con avviso di \\nricevimento.\\nL\\x00Impresa di Assicurazione, entro trenta giorni dal ricevimento della comunicazione relativa al \\nRecesso, rimborserà al Contraente il Controvalore delle Quote attribuite al Contratto alla data di \\nricevimento della richiesta di recesso incrementato dai caricamenti, ove previsti, e dedotte \\neventuali agevolazioni.\\nRisoluzione\\nLa risoluzione del contratto è prevista tramite la richiesta di riscatto totale esercitabile in qualsiasi \\nmomento della durata contrattuale\\nSono previsti riscatti o riduzioni? Si\\n no\\nValori di\\nriscatto e\\nriduzione\\nA condizione che siano trascorsi almeno 30 giorni dalla Data di Decorrenza (conclusione del \\nContratto) e fino all\\x00ultimo Giorno Lavorativo della terzultima settimana precedente la data di \\nscadenza, il Contraente può riscuotere, interamente o parzialmente, il Valore di Riscatto. In caso di \\nRiscatto totale, la liquidazione del Valore di Riscatto pone fine al Contratto con effetto dalla data di \\nricezione della richiesta.\\nL\\x00importo che sarà corrisposto al Contraente in caso di Riscatto sarà pari al Controvalore delle \\nQuote del Fondo Interno attribuite al Contratto alla data di Riscatto, al netto dei costi di Riscatto.\\nIn caso di Riscatto, ai fini del calcolo del Valore Unitario della Quota, si farà riferimento alla Data di \\nValorizzazione della settimana successiva alla data in cui la comunicazione di Riscatto del \\nContraente perviene all\\x00Impresa di Assicurazione, corredata di tutta la documentazione, al netto dei \\ncosti di Riscatto, salvo il verificarsi di Eventi di Turbativa.\\nIl Contraente assume il rischio connesso all\\x00andamento negativo del valore delle Quote e, pertanto, \\nesiste la possibilità di ricevere un ammontare inferiore all\\x00investimento finanziario.\\nIn caso di Riscatto del Contratto (totale o parziale), l\\x00Impresa di Assicurazione non offre alcuna \\ngaranzia finanziaria di rendimento minimo e pertanto il Contraente sopporta il rischio di ottenere un \\nValore Unitario di Quota inferiore al 100% del Valore Unitario di Quota del Fondo Interno registrato \\nalla Data di Istituzione in considerazione dei rischi connessi alla fluttuazione del valore di mercato \\ndegli attivi in cui investe, direttamente o indirettamente, il Fondo Interno.\\nRichiesta di\\ninformazioni\\nPer eventuali richieste di informazioni sul valore di riscatto, il Contraente può rivolgersi alla \\nCompagnia AXA MPS Financial DAC \\x03 Wolfe Tone House, Wolfe Tone Street, Dublin, DO1 HP90 \\x03 \\nIreland, Numero Verde 800.231.187, e-mail: supporto@axa-mpsfinancial.ie\\nA chi è rivolto questo prodotto?\\nL\\x00investitore al dettaglio a cui è destinato il prodotto varia in funzione dell\\x00opzione di investimento sottostante e \\nillustrata nel relativo KID.\\nIl prodotto è indirizzato a Contraenti persone fisiche e persone giuridiche a condizione che il Contraente (persona fisica) \\ne l\\x00Assicurato, al momento della sottoscrizione stessa, abbiano un\\x00età compresa tra i 18 anni e i 85 anni.\\nQuali costi devo sostenere?\\nPer l\\x00informativa dettagliata sui costi fare riferimento alle indicazioni del KID.\\nIn aggiunta rispetto alle informazioni del KID , indicare i seguenti costi a carico del contraente.\\nSpese di emissione:\\nIl Contratto prevede una spesa fissa di emissione pari a 25 Euro.\\nLa deduzione di tale importo avverrà contestualmente alla deduzione del premio.\\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 6 di 9\\n',\n            \"L\\x00obiettivo di protezione è da considerarsi al netto delle spese di emissione.\\nCosti per riscatto\\nIl Riscatto (totale e parziale) prevede un costo che varia in funzione della data di richiesta e secondo le percentuali di \\nseguito indicate:\\n1°Anno 5,00%; 2°Anno 3,50%; 3°Anno 2,00%; dal quarto anno in poi 0%;\\nCosti di intermediazione\\nla quota parte massima percepita dall\\x00intermediario con riferimento all\\x00intero flusso commissionale relativo al prodotto \\nè pari al 35,17%.\\nQuali sono i rischi e qual è il potenziale rendimento?\\nSia con riferimento alla prestazione in caso di vita dell\\x00assicurato, sia con riferimento al capitale caso morte riferito ai \\nFondi Assicurativi Interni, la Compagnia non presta alcuna garanzia di rendimento minimo o di conservazione del \\ncapitale. Pertanto il controvalore della prestazione della Compagnia potrebbe essere inferiore all\\x00importo dei premi \\nversati, in considerazione dei rischi connessi alla fluttuazione del valore di mercato degli attivi in cui investe, \\ndirettamente o indirettamente il Fondo Interno.\\nCOME POSSO PRESENTARE I RECLAMI E RISOLVERE LE CONTROVERSIE?\\nAll\\x00IVASS\\nNel caso in cui il reclamo presentato all\\x00impesa assicuratrice abbia esito insoddisfacente o risposta \\ntardiva, è possibile rivolgersi all\\x00IVASS, Via del Quirinale, 21 - 00187 Roma, fax 06.42133206, Info \\nsu: www.ivass.it.\\nEventuali reclami potranno inoltre essere indirizzati all\\x00Autorità Irlandese competente al seguente \\nindirizzo:\\nFinancial Services Ombudsman 3rd Floor, Lincoln House, Lincoln Place, Dublin 2, D02 VH29 \\x03 \\nIreland\\nPRIMA DI RICORRERE ALL\\x00AUTORITÀ GIUDIZIARIA è possibile, in alcuni casi necessario, \\navvalersi di sistemi alternativi di risoluzione delle controversie, quali:\\nMediazione\\nInterpellando un Organismo di Mediazione tra quelli presenti nell'elenco del Ministero della \\nGiustizia, consultabile sul sito www.giustizia.it (Legge 9/8/2013, n.98)\\nNegoziazione \\nassistita\\nTramite richiesta del proprio avvocato all\\x00impresa\\nAltri Sistemi \\nalternative di \\nrisoluzione delle \\ncontroversie\\nEventuali reclami relativi ad un contratto o servizio assicurativo nei confronti dell'Impresa di \\nassicurazione o dell'Intermediario assicurativo con cui si entra in contatto, nonché qualsiasi \\nrichiesta di informazioni, devono essere preliminarmente presentati per iscritto (posta, email) ad \\nAXA MPS Financial DAC - Ufficio Reclami secondo seguenti modalità:\\nEmail: reclami@axa-mpsfinancial.ie\\nPosta: AXA MPS Financial DAC - Ufficio Reclami\\nWolfe Tone House, Wolfe Tone Street,\\nDublin DO1 HP90 - Ireland\\nNumero Verde 800.231.187\\navendo cura di indicare:\\n-nome, cognome, indirizzo completo e recapito telefonico del reclamante;\\n-numero della polizza e nominativo del contraente;\\n-breve ed esaustiva descrizione del motivo di lamentela;\\n-ogni altra indicazione e documento utile per descrivere le circostanze.\\nSarà cura della Compagnia fornire risposta entro 45 giorni dalla data di ricevimento del reclamo, \\ncome previsto dalla normativa vigente.\\nNel caso di mancato o parziale accoglimento del reclamo, nella risposta verrà fornita una chiara \\nspiegazione della posizione assunta dalla Compagnia in relazione al reclamo stesso ovvero della \\nsua mancata risposta.\\nQualora il reclamante non abbia ricevuto risposta oppure ritenga la stessa non soddisfacente, \\nprima di rivolgersi all'Autorità Giudiziaria, può scrivere all'IVASS (Via del Quirinale, 21 - 00187 \\nRoma; fax 06.42.133.745 o 06.42.133.353, ivass@pec.ivass.it) fornendo copia del reclamo già \\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 7 di 9\\n\",\n            \"inoltrato all'impresa ed il relativo riscontro anche utilizzando il modello presente nel sito dell'IVASS \\nalla sezione per il Consumatore - come presentare un reclamo.\\nEventuali reclami potranno inoltre essere indirizzati all'Autorità Irlandese competente al seguente \\nindirizzo:\\nFinancial Services Ombudsman\\n3rd Floor, Lincoln House,\\nLincoln Place, Dublin 2, D02 VH29 Ireland\\nIl reclamante può ricorrere ai sistemi alternativi per la risoluzione delle controversie previsti a livello \\nnormativo o convenzionale, quali:\\n\\x04 Mediazione: (Decreto Legislativo n.28/2010 e ss.mm.) puo' essere avviata presentando istanza \\nad un Organismo di Mediazione tra quelle presenti nell'elenco del Ministero della Giustizia, \\nconsultabile sul sito www.giustizia.it. La legge ne prevede l'obbligatorieta' nel caso in cui si intenda \\nesercitare in giudizio i propri diritti in materia di contratti assicurativi o finanziari e di risarcimento \\nda responsabilita'  medica e sanitaria, costituendo condizione di procedibilita' della domanda.\\n\\x04 Negoziazione Assistita: (Legge n.162/2014) tramite richiesta del proprio Avvocato all'Impresa. E' \\nun accordo mediante il quale le parti convengono di cooperare in buona fede e con lealta' per \\nrisolvere in via amichevole la controversia tramite l'assistenza di avvocati. Fine del procedimento e' \\nla composizione bonaria della lite, con la sottoscrizione delle parti - assistite dai rispettivi difensori - \\ndi un accordo detto convenzione di negoziazione. Viene prevista la sua obbligatorieta' nel caso in \\ncui si intenda esercitare in giudizio i propri diritti per ogni controversia in materia di risarcimento del \\ndanno da circolazione di veicoli e natanti, ovverosia e' condizione di procedibilita' per l'eventuale \\ngiudizio civile. Invece e' facoltativa per ogni altra controversia in materia di risarcimenti o di contratti \\nassicurativi o finanziari.\\nIn caso di controversia relativa alla determinazione dei danni si puo' ricorrere alla perizia \\ncontrattuale prevista dalle Condizioni di Assicurazione per la risoluzione di tale tipologia di \\ncontroversie. L'istanza di attivazione della perizia contrattuale dovra' essere indirizzata alla \\nCompagnia all' indirizzo\\nAXA MPS Financial DAC \\nWolfe Tone House, Wolfe Tone Street\\nDublin DO1 HP90  - Ireland\\nPer maggiori informazioni si rimanda a quanto presente nell'area Reclami del sito \\nwww.axa-mpsfinancial.ie. \\nPer la risoluzione delle liti transfrontaliere è possibile presentare reclamo all'IVASS o direttamente \\nal sistema estero http://ec.europa.eu/internal_market/fin-net/members_en.htm competente \\nchiedendo l'attivazione della procedura FIN-NET.\\nEventuali reclami relativi la mancata osservanza da parte della Compagnia, degli intermediari e dei \\nperiti assicurativi, delle disposizioni del Codice delle assicurazioni, delle relative norme di \\nattuazione nonché delle norme sulla commercializzazione a distanza dei prodotti assicurativi \\npossono essere presentati direttamente all'IVASS, secondo le modalità sopra indicate.\\nSi ricorda che resta salva la facoltà di adire l'autorità giudiziaria.\\nREGIME FISCALE\\nTrattamento \\nfiscale applicabile \\nal contratto\\nLe seguenti informazioni sintetizzano alcuni aspetti del regime fiscale applicabile al Contratto, ai \\nsensi della legislazione tributaria italiana e della prassi vigente alla data di pubblicazione del \\npresente documento, fermo restando che le stesse rimangono soggette a possibili cambiamenti che \\npotrebbero avere altresì effetti retroattivi. Quanto segue non intende rappresentare un\\x00analisi \\nesauriente di tutte le conseguenze fiscali del Contratto. I Contraenti sono tenuti a consultare i loro \\nconsulenti in merito al regime fiscale proprio del Contratto.\\nTasse e imposte\\nLe imposte e tasse presenti e future applicabili per legge al Contratto sono a carico del Contraente \\no dei Beneficiari e aventi diritto e non è prevista la corresponsione al Contraente di alcuna somma \\naggiuntiva volta a compensare eventuali riduzioni dei pagamenti relativi al Contratto.\\nTassazione delle somme corrisposte a soggetti non esercenti attività d\\x00impresa\\n1. In caso di decesso dell\\x00Assicurato\\nLe somme corrisposte dall\\x00Impresa di Assicurazione in caso di decesso dell\\x00Assicurato non sono \\nsoggette a tassazione IRPEF in capo al percettore e sono esenti dall\\x00imposta sulle successioni. Si \\nricorda tuttavia che, per effetto della legge 23 dicembre 2014 n. 190 (c.d.\\x02Legge di Stabilità\\x02), i \\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 8 di 9\\n\",\n            'capitali percepiti in caso di morte, a decorrere dal 1 gennaio 2015, in dipendenza di contratti di \\nassicurazione sulla vita, a copertura del rischio demografico, sono esenti dall\\x00imposta sul reddito \\ndelle persone fisiche.\\n2. In caso di Riscatto totale o di Riscatto parziale.\\nLe somme corrisposte dall\\x05Impresa di Assicurazione in caso di Riscatto totale sono soggette ad \\nun\\x00imposta sostitutiva dell\\x00imposta sui redditi nella misura prevista di volta in volta dalla legge. Tale \\nimposta, al momento della redazione del presente documento, è pari al 26% sulla differenza \\n(plusvalenza) tra il capitale maturato e l\\x00ammontare dei premi versati (al netto di eventuali riscatti \\nparziali), con l\\x00eccezione dei proventi riferibili ai titoli di stato italiani ed equiparati (Paesi facenti \\nparte della white list), per i quali l\\x00imposta è pari al 12,5%.\\nIn caso di Riscatto parziale, ai fini del computo del reddito di capitale da assoggettare alla predetta \\nimposta sostitutiva, l\\x00ammontare dei premi va rettificato in funzione del rapporto tra il capitale \\nerogato ed il valore economico della polizza alla data del Riscatto parziale.\\n3. In caso di Recesso\\nLe somme corrisposte in caso di Recesso sono soggette all\\x00imposta sostitutiva delle imposte sui \\nredditi nella misura e con gli stessi criteri indicati per il Riscatto totale del Contratto.\\nTassazione delle somme corrisposte a soggetti esercenti attività d\\x00impresa\\nLe somme corrisposte a soggetti che esercitano l\\x00attività d\\x00impresa non costituiscono redditi di \\ncapitale, bensì redditi d\\x00impresa. Su tali somme l\\x00Impresa non applica l\\x00imposta sostitutiva di cui \\nall\\x00art. 26-ter del D.P.R. 29 settembre 1973, n. 600.\\nSe le somme sono corrisposte a persone fisiche o enti non commerciali in relazione a contratti \\nstipulati nell\\x00ambito dell\\x00attività commerciale, l\\x00Impresa non applica l\\x00imposta sostitutiva, qualora gli \\ninteressati presentino una dichiarazione in merito alla sussistenza di tale requisito.\\nL\\x00IMPRESA HA L\\x00OBBLIGO DI TRASMETTERTI, ENTRO IL 31 MAGGIO DI OGNI ANNO, IL DOCUMENTO \\nUNICO DI RENDICONTAZIONE ANNUALE DELLA TUA POSIZIONE ASSICURATIVA\\nPER QUESTO CONTRATTO L\\x00IMPRESA NON DISPONE DI UN\\x00AREA INTERNET DISPOSITIVA RISERVATA \\nAL CONTRAENTE (c.d. HOME INSURANCE), PERTANTO DOPO LA SOTTOSCRIZIONE  NON POTRAI \\nGESTIRE TELEMATICAMENTE IL CONTRATTO MEDESIMO.\\nDIP aggiuntivo IBIP - Progetto Protetto New - Global Dividends -   Pag. 9 di 9\\n',\n            ]\n    # codespell:ignore-end\n\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_3186.pdf')\n    fitz_doc = pymupdf.open(path)\n    texts = list()\n    for page in fitz_doc:\n        t = page.get_text()\n        texts.append(t)\n    assert texts == texts_expected, f'Unexpected output: {texts=}'\n\n\ndef test_3197():\n    '''\n    MuPDF's ActualText support fixes handling of test_3197.pdf.\n    '''\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_3197.pdf')\n    \n    text_utf8_expected = [\n            b'NYSE - Nasdaq Real Time Price \\xe2\\x80\\xa2 USD\\nFord Motor Company (F)\\n12.14 -0.11 (-0.90%)\\nAt close: 4:00 PM EST\\nAfter hours: 7:43 PM EST\\nAll numbers in thousands\\nAnnual\\nQuarterly\\nDownload\\nSummary\\nNews\\nChart\\nConversations\\nStatistics\\nHistorical Data\\nProfile\\nFinancials\\nAnalysis\\nOptions\\nHolders\\nSustainability\\nInsights\\nFollow\\n12.15 +0.01 (+0.08%)\\nIncome Statement\\nBalance Sheet\\nCash Flow\\nSearch for news, symbols or companies\\nNews\\nFinance\\nSports\\nSign in\\nMy Portfolio\\nNews\\nMarkets\\nSectors\\nScreeners\\nPersonal Finance\\nVideos\\nFinance Plus\\nBack to classic\\nMore\\n',\n            b'Related Tickers\\nTTM\\n12/31/2023\\n12/31/2022\\n12/31/2021\\n12/31/2020\\n14,918,000\\n14,918,000\\n6,853,000\\n15,787,000\\n24,269,000\\n-17,628,000\\n-17,628,000\\n-4,347,000\\n2,745,000\\n-18,615,000\\n2,584,000\\n2,584,000\\n2,511,000\\n-23,498,000\\n2,315,000\\n25,110,000\\n25,110,000\\n25,340,000\\n20,737,000\\n25,935,000\\n-8,236,000\\n-8,236,000\\n-6,866,000\\n-6,227,000\\n-5,742,000\\n51,659,000\\n51,659,000\\n45,470,000\\n27,901,000\\n65,900,000\\n-41,965,000\\n-41,965,000\\n-45,655,000\\n-54,164,000\\n-60,514,000\\n-335,000\\n-335,000\\n-484,000\\n--\\n--\\n6,682,000\\n6,682,000\\n-13,000\\n9,560,000\\n18,527,000\\n \\nYahoo Finance Plus Essential\\naccess required.\\nUnlock Access\\nBreakdown\\nOperating Cash\\nFlow\\nInvesting Cash\\nFlow\\nFinancing Cash\\nFlow\\nEnd Cash Position\\nCapital Expenditure\\nIssuance of Debt\\nRepayment of Debt\\nRepurchase of\\nCapital Stock\\nFree Cash Flow\\n12/31/2020 - 6/1/1972\\nGM\\nGeneral Motors Compa\\xe2\\x80\\xa6\\n39.49 +1.23%\\n\\xc2\\xa0\\nRIVN\\nRivian Automotive, Inc.\\n15.39 -3.15%\\n\\xc2\\xa0\\nNIO\\nNIO Inc.\\n5.97 +0.17%\\n\\xc2\\xa0\\nSTLA\\nStellantis N.V.\\n25.63 +0.91%\\n\\xc2\\xa0\\nLCID\\nLucid Group, Inc.\\n3.7000 +0.54%\\n\\xc2\\xa0\\nTSLA\\nTesla, Inc.\\n194.77 +0.52%\\n\\xc2\\xa0\\nTM\\nToyota Motor Corporati\\xe2\\x80\\xa6\\n227.09 +0.14%\\n\\xc2\\xa0\\nXPEV\\nXPeng Inc.\\n9.08 +0.89%\\n\\xc2\\xa0\\nFSR\\nFisker Inc.\\n0.5579 -11.46%\\n\\xc2\\xa0\\nCopyright \\xc2\\xa9 2024 Yahoo.\\nAll rights reserved.\\nPOPULAR QUOTES\\nTesla\\nDAX Index\\nKOSPI\\nDow Jones\\nS&P BSE SENSEX\\nSPDR S&P 500 ETF Trust\\nEXPLORE MORE\\nCredit Score Management\\nHousing Market\\nActive vs. Passive Investing\\nShort Selling\\nToday\\xe2\\x80\\x99s Mortgage Rates\\nHow Much Mortgage Can You Afford\\nABOUT\\nData Disclaimer\\nHelp\\nSuggestions\\nSitemap\\n',\n            ]\n    \n    num_errors = 0\n    with pymupdf.open(path) as document:\n        for i, page in enumerate(document):\n            text = page.get_text()\n            \n            text_utf8 = text.encode('utf8')\n            \n            if text_utf8 != text_utf8_expected[i]:\n                num_errors += 1\n                print(f'Error, {i=}.')\n                import difflib\n                print(f'    {text_utf8_expected[i]=}')\n                print(f'                {text_utf8=}')\n                text_expected = text_utf8_expected[i].decode('utf8')\n                diff = difflib.unified_diff(\n                        text_expected.split('\\n'),\n                        text.split('\\n'),\n                        lineterm='',\n                        )\n                print(f'Diff expected => actual:')\n                print(textwrap.indent('\\n'.join(diff), '    '))\n                        \n    assert not num_errors, f'{num_errors=}'\n\n\ndef test_document_text():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_document_text(): not running on Pyodide - multiprocessing not available.')\n        return\n        \n    import platform\n    import time\n    \n    path = os.path.abspath(f'{__file__}/../../tests/resources/mupdf_explored.pdf')\n    concurrency = None\n    \n    def llen(texts):\n        l = 0\n        for text in texts:\n            l += len(text) if isinstance(text, str) else text\n        return l\n\n    results = dict()\n    _stats = 1\n    \n    print('')\n    method = 'single'\n    t = time.time()\n    document = pymupdf.Document(path)\n    texts0 = pymupdf.get_text(path, _stats=_stats)\n    t0 = time.time() - t\n    print(f'{method}: {t0=} {llen(texts0)=}', flush=1)\n\n    # Dummy run seems to avoid misleading stats with slow first run.\n    method = 'mp'\n    texts = pymupdf.get_text(path, concurrency=concurrency, method=method, _stats=_stats)\n\n    method = 'mp'\n    t = time.time()\n    texts = pymupdf.get_text(path, concurrency=concurrency, method=method, _stats=_stats)\n    t = time.time() - t\n    print(f'{method}: {concurrency=} {t=} ({t0/t:.2f}x) {llen(texts)=}', flush=1)\n    assert texts == texts0\n\n    if platform.system() != 'Windows':\n        method = 'fork'\n        t = time.time()\n        texts = pymupdf.get_text(path, concurrency=concurrency, method='fork', _stats=_stats)\n        t = time.time() - t\n        print(f'{method}: {concurrency=} {t=} ({t0/t:.2f}x) {llen(texts)=}', flush=1)\n        assert texts == texts0\n    \n    if _stats:\n        pymupdf._log_items_clear()\n\n\ndef test_4524():\n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_4524(): not running on Pyodide - multiprocessing not available.')\n        return\n    path = os.path.abspath(f'{__file__}/../../tests/resources/mupdf_explored.pdf')\n    print('')\n    document = pymupdf.Document(path)\n    texts_single = pymupdf.get_text(path, method='single', pages=[1, 3, 5])\n    texts_mp = pymupdf.get_text(path, method='mp', pages=[1, 3, 5])\n    print(f'{len(texts_single)=}')\n    print(f'{len(texts_mp)=}')\n    assert texts_mp == texts_single\n\n\ndef test_3594():\n    verbose = 0\n    print()\n    d = pymupdf.open(os.path.abspath(f'{__file__}/../../tests/resources/test_3594.pdf'))\n    for i, p in enumerate(d.pages()):\n        text = p.get_text()\n        print(f'Page {i}:')\n        if verbose:\n            for line in text.split('\\n'):\n                print(f'    {line!r}')\n            print('='*40)\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if pymupdf.mupdf_version_tuple < (1, 26, 8):\n        assert not wt\n    elif pymupdf.mupdf_version_tuple < (1, 28):\n        assert wt == 'Actualtext with no position. Text may be lost or mispositioned.\\n... repeated 2 times...'\n    else:\n        assert wt == 'ActualText with no position. Text may be lost or mispositioned.\\n... repeated 2 times...'\n\n\ndef test_3687():\n    path1 = pymupdf.open(os.path.normpath(f'{__file__}/../../tests/resources/test_3687.epub'))\n    path2 = pymupdf.open(os.path.normpath(f'{__file__}/../../tests/resources/test_3687-3.epub'))\n    for path in path1, path2:\n        print(f'Looking at {path=}.')\n        with pymupdf.open(path) as document:\n            page = document[0]\n            text = page.get_text(\"text\")\n            print(f'{text=!s}')\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        print(f'{wt=}')\n        assert wt == 'unknown epub version: 3.0'\n\ndef test_3705():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3705.pdf')\n    def get_all_page_from_pdf(document, last_page=None):\n        if last_page:\n            document.select(list(range(0, last_page)))\n        if document.page_count > 30:\n            document.select(list(range(0, 30)))\n        return iter(page for page in document)\n\n    filename = os.path.basename(path)\n\n    doc = pymupdf.open(path)\n    texts0 = list()\n    for i, page in enumerate(get_all_page_from_pdf(doc)):\n        text = page.get_text()\n        print(i, text)    \n        texts0.append(text)\n    \n    texts1 = list()\n    doc = pymupdf.open(path)\n    for page in doc:\n        if page.number >= 30:  # leave the iterator immediately\n            break\n        text = page.get_text()\n        texts1.append(text)\n    \n    assert texts1 == texts0\n\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if pymupdf.mupdf_version_tuple >= (1, 27, 1):\n        expected = ''\n        assert wt == expected\n    elif pymupdf.mupdf_version_tuple >= (1, 27):\n        expected = 'format error: No common ancestor in structure tree\\nstructure tree broken, assume tree is missing'\n        expected = '\\n'.join([expected] * 56)\n        assert wt == expected\n    elif pymupdf.mupdf_version_tuple >= (1, 26, 8):\n        assert wt == 'Actualtext with no position. Text may be lost or mispositioned.\\n... repeated 7684 times...'\n    else:\n        assert wt == 'Actualtext with no position. Text may be lost or mispositioned.\\n... repeated 434 times...'\n\ndef test_3650():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3650.pdf')\n    doc = pymupdf.Document(path)\n    blocks = doc[0].get_text(\"blocks\")\n    t = [block[4] for block in blocks]\n    print(f'{t=}')\n    assert t == [\n            'RECUEIL DES ACTES ADMINISTRATIFS\\n',\n            'n° 78 du 28 avril 2023\\n',\n            ]\n\ndef test_4026():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4026.pdf')\n    with pymupdf.open(path) as document:\n        page = document[4]\n        blocks = page.get_text('blocks')\n        for i, block in enumerate(blocks):\n            print(f'block {i}: {block}')\n        if pymupdf.mupdf_version_tuple >= (1, 28):\n            # 2026-05-01: Expect slightly better splitting of text into\n            # paragraphs.\n            assert len(blocks) == 8\n        else:\n            assert len(blocks) == 5\n\ndef test_3725():\n    # This currently just shows the extracted text. We don't check it is as expected.\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3725.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        text = page.get_text()\n        if 0:\n            print(textwrap.indent(text, '    '))\n\ndef test_4147():\n    print()\n    items = list()\n    for expect_visible, path in (\n            (False, os.path.normpath(f'{__file__}/../../tests/resources/test_4147.pdf')),\n            (True, os.path.normpath(f'{__file__}/../../tests/resources/symbol-list.pdf')),\n            ):\n        print(f'{expect_visible=} {path=}')\n        with pymupdf.open(path) as document:\n            page = document[0]\n            text = page.get_text('rawdict')\n            for block in text['blocks']:\n                if block['type'] == 0:\n                    #print(f'     block')\n                    for line in block['lines']:\n                        #print(f'        line')\n                        for span in line['spans']:\n                            #print(f'            span')\n                            #print(f'            span: {span[\"flags\"]=:#x} {span[\"char_flags\"]=:#x}')\n                            if expect_visible:\n                                assert span['char_flags'] & pymupdf.mupdf.FZ_STEXT_FILLED\n                            else:\n                                assert not (span['char_flags'] & pymupdf.mupdf.FZ_STEXT_FILLED)\n                                assert not (span['char_flags'] & pymupdf.mupdf.FZ_STEXT_STROKED)\n                            # Check commit `add 'bidi' to span dict, add 'synthetic' to char dict.`\n                            assert span['bidi'] == 0\n                            for ch in span['chars']:\n                                assert isinstance(ch['synthetic'], bool)\n\n\ndef test_4139():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4139.pdf')\n    flags = (0\n            | pymupdf.TEXT_PRESERVE_IMAGES\n            | pymupdf.TEXT_PRESERVE_WHITESPACE\n            | pymupdf.TEXT_USE_CID_FOR_UNKNOWN_UNICODE\n            )\n    with pymupdf.open(path) as document:\n        page = document[0]\n        dicts = page.get_text('dict', flags=flags, sort=True)\n        seen = set()\n        for b_ctr, b in enumerate(dicts['blocks']):\n             for l_ctr, l in enumerate(b.get('lines', [])):\n                for s_ctr, s in enumerate(l['spans']):\n                    color = s.get('color')\n                    if color is not None and color not in seen:\n                        seen.add(color)\n                        print(f\"B{b_ctr}.L{l_ctr}.S{s_ctr}: {color=} {hex(color)=} {s=}\")\n                        assert color == 0, f'{s=}'\n                        assert s['alpha'] == 255\n\n\ndef test_4245():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4245.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        regions = page.search_for('Bart Simpson')\n        print(f'{regions=}')\n        page.add_highlight_annot(regions)\n    with pymupdf.open(path) as document:\n        page = document[0]\n        regions = page.search_for('Bart Simpson')\n        for region in regions:\n            highlight = page.add_highlight_annot(region)\n            highlight.update()\n        pixmap = page.get_pixmap()\n    path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4245_out.png')\n    pixmap.save(path_out)\n    \n    path_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4245_expected.png')\n    rms = gentle_compare.pixmaps_rms(path_expected, pixmap)\n    pixmap_diff = gentle_compare.pixmaps_diff(path_expected, pixmap)\n    path_diff = os.path.normpath(f'{__file__}/../../tests/resources/test_4245_diff.png')\n    pixmap_diff.save(path_diff)\n    print(f'{rms=}')\n    assert rms < 0.01\n\n\ndef test_4180():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4180.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        regions = page.search_for('Reference is made')\n        for region in regions:\n            page.add_redact_annot(region, fill=(0, 0, 0))\n        page.apply_redactions()\n        pixmap = page.get_pixmap()\n    path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4180_out.png')\n    pixmap.save(path_out)\n    \n    path_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4180_expected.png')\n    rms = gentle_compare.pixmaps_rms(path_expected, pixmap)\n    pixmap_diff = gentle_compare.pixmaps_diff(path_expected, pixmap)\n    path_diff = os.path.normpath(f'{__file__}/../../tests/resources/test_4180_diff.png')\n    pixmap_diff.save(path_diff)\n    print(f'{rms=}')\n    assert rms < 0.01\n\n\ndef test_4182():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4182.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        dict_ = page.get_text('dict')\n        linelist = []\n        for block in dict_['blocks']:\n            if block['type'] == 0:\n                paranum = block['number']\n                if 'lines' in block:\n                    for line in block.get('lines', ()):\n                        for span in line['spans']:\n                            if span['text'].strip():\n                                page.draw_rect(span['bbox'], color=(1, 0, 0))\n                                linelist.append([paranum, span['bbox'], repr(span['text'])])\n        pixmap = page.get_pixmap()\n    path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4182_out.png')\n    pixmap.save(path_out)\n    if platform.system() != 'Windows':  # Output on Windows can fail due to non-utf8 stdout.\n        for l in linelist:\n            print(l)\n    path_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4182_expected.png')\n    pixmap_diff = gentle_compare.pixmaps_diff(path_expected, pixmap)\n    path_diff = os.path.normpath(f'{__file__}/../../tests/resources/test_4182_diff.png')\n    pixmap_diff.save(path_diff)\n    rms = gentle_compare.pixmaps_rms(path_expected, pixmap)\n    print(f'{rms=}')\n    assert rms < 0.01\n\n\ndef test_4179():\n    if os.environ.get('PYMUPDF_USE_EXTRA') == '0':\n        # Looks like Python code doesn't behave same as C++, probably because\n        # of the code not being correct for Python's native unicode strings.\n        #\n        print(f'test_4179(): Not running with PYMUPDF_USE_EXTRA=0 because known to fail.')\n        return\n    # We check that using TEXT_ACCURATE_BBOXES gives the correct boxes. But\n    # this also requires that we disable PyMuPDF quad corrections.\n    #\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4179.pdf')\n    \n    # Disable anti-aliasing to avoid our drawing of multiple identical bboxes\n    # (from normal/accurate bboxes) giving slightly different results.\n    aa = pymupdf.mupdf.fz_aa_level()\n    uqc = pymupdf._globals.skip_quad_corrections\n    pymupdf.TOOLS.set_aa_level(0)\n    pymupdf.TOOLS.unset_quad_corrections(True)\n    assert pymupdf._globals.skip_quad_corrections\n    try:\n        with pymupdf.open(path) as document:\n            page = document[0]\n\n            char_sqrt = b'\\xe2\\x88\\x9a'.decode()\n            \n            # Search with defaults.\n            bboxes_search = page.search_for(char_sqrt)\n            assert len(bboxes_search) == 1\n            print(f'bboxes_search[0]:\\n    {bboxes_search[0]!r}')\n            page.draw_rect(bboxes_search[0], color=(1, 0, 0))\n            rms = gentle_compare.rms(bboxes_search[0], (250.0489959716797, 91.93604278564453, 258.34783935546875, 101.34073638916016))\n            assert rms < 0.01\n\n            # Search with TEXT_ACCURATE_BBOXES.\n            bboxes_search_accurate = page.search_for(\n                    char_sqrt,\n                    flags = (0\n                            | pymupdf.TEXT_DEHYPHENATE\n                            | pymupdf.TEXT_PRESERVE_WHITESPACE\n                            | pymupdf.TEXT_PRESERVE_LIGATURES\n                            | pymupdf.TEXT_MEDIABOX_CLIP\n                            | pymupdf.TEXT_ACCURATE_BBOXES\n                            ),\n                    )\n            assert len(bboxes_search_accurate) == 1\n            print(f'bboxes_search_accurate[0]\\n    {bboxes_search_accurate[0]!r}')\n            page.draw_rect(bboxes_search_accurate[0], color=(0, 1, 0))\n            rms = gentle_compare.rms(bboxes_search_accurate[0], (250.0489959716797, 99.00948333740234, 258.34783935546875, 108.97208404541016))\n            assert rms < 0.01\n\n            # Iterate with TEXT_ACCURATE_BBOXES.\n            bboxes_iterate_accurate = list()\n            dict_ = page.get_text(\n                    'rawdict',\n                    flags = pymupdf.TEXT_ACCURATE_BBOXES,\n                    )\n            linelist = []\n            for block in dict_['blocks']:\n                if block['type'] == 0:\n                    if 'lines' in block:\n                        for line in block.get('lines', ()):\n                            for span in line['spans']:\n                                for ch in span['chars']:\n                                    if ch['c'] == char_sqrt:\n                                        bbox_iterate_accurate = ch['bbox']\n                                        bboxes_iterate_accurate.append(bbox_iterate_accurate)\n                                        print(f'bbox_iterate_accurate:\\n    {bbox_iterate_accurate!r}')\n                                        page.draw_rect(bbox_iterate_accurate, color=(0, 0, 1))\n            \n            assert bboxes_search_accurate != bboxes_search\n            assert bboxes_iterate_accurate == bboxes_search_accurate\n            pixmap = page.get_pixmap()\n        \n        path_out = os.path.normpath(f'{__file__}/../../tests/resources/test_4179_out.png')\n        pixmap.save(path_out)\n        path_expected = os.path.normpath(f'{__file__}/../../tests/resources/test_4179_expected.png')\n        rms = gentle_compare.pixmaps_rms(path_expected, pixmap)\n        pixmap_diff = gentle_compare.pixmaps_diff(path_expected, pixmap)\n        path_out_diff = os.path.normpath(f'{__file__}/../../tests/resources/test_4179_diff.png')\n        pixmap_diff.save(path_out_diff)\n        print(f'Have saved to: {path_out_diff=}')\n        print(f'{rms=}')\n        assert rms < 0.01\n    \n    finally:\n        pymupdf.TOOLS.set_aa_level(aa)\n        pymupdf.TOOLS.unset_quad_corrections(uqc)\n\n\ndef test_extendable_textpage():\n    \n    # 2025-01-28:\n    #\n    # We can create a pdf with two pages whose text is adjacent when stitched\n    # together vertically:\n    #\n    # Page 1:\n    # \n    #     aaaa\n    #    \n    #     bbbb\n    #     cccc\n    #     \n    #     dddd\n    #     \n    # Page 2:\n    #     \n    #     eeee\n    #     \n    #     ffff\n    #     gggg\n    #     \n    #     hhhh\n    #\n    #\n    # Create a textpage for both of these pages. Then when extracting text,\n    # we need to get (specifically the `dddd` and `eeee` sequences need to be\n    # treated as the same block):\n    #\n    #     aaaa\n    #    \n    #     bbbb\n    #     cccc\n    #     \n    #     dddd\n    #     eeee\n    #     \n    #     ffff\n    #     gggg\n    #     \n    #     hhhh\n    #\n    print()\n    \n    path = os.path.normpath(f'{__file__}/../../tests/test_extendable_textpage.pdf')\n    with pymupdf.open(filetype='pdf') as document:\n        document.new_page()\n        document.new_page()\n        page0 = document[0]\n        page1 = document[1]\n        y = 100\n        line_height = 9.6\n        for i in range(4):\n            page0.insert_text((100, y+line_height), 'abcd'[i] * 16)\n            page1.insert_text((100, y+line_height), 'efgh'[i] * 16)\n            y += line_height\n            if i%2 == 0:\n                y += line_height\n        rect = pymupdf.mupdf.FzRect(100, 100, 200, y)\n        document[0].draw_rect(rect, (1, 0, 0))\n        document[1].draw_rect(rect, (1, 0, 0))\n        document.save(path)\n    \n    # Create a stext page for the text regions in both pages of our document,\n    # using direct calls to MuPDF.\n    #\n    \n    with pymupdf.Document(path) as document:\n    \n        # Notes:\n        #\n        # We need to reuse the stext device for second page. Otherwise if we\n        # create a new device, the first text in second page will always be in\n        # a new block, because pen position for new device is (0, 0) and this\n        # will usually be treated as a paragraph gap to the first text.\n        #\n        # At the moment we use infinite mediabox when creating the\n        # fz_stext_page. I don't know what a non-infinite mediabox would be\n        # useful for.\n        #\n        # FZ_STEXT_CLIP_RECT isn't useful at the moment, because we would need\n        # to modify it to be in stext pagae coordinates (i.e. adding ctm.f\n        # to y0 and y1) when we append the second page. But it's internal\n        # data and there's no api to modify it. So for now we don't specify\n        # FZ_STEXT_CLIP_RECT when creating the stext device, so we always\n        # include each page's entire contents.\n        #\n        \n        # We use our knowledge of the text rect in each page to manipulate ctm\n        # so that the stext contains text starting at (0, 0) and extending\n        # downwards.\n        #\n        y = 0\n        cookie = pymupdf.mupdf.FzCookie()\n        \n        stext_page = pymupdf.mupdf.FzStextPage(\n                pymupdf.mupdf.FzRect(pymupdf.mupdf.FzRect.Fixed_INFINITE),  # mediabox\n                )\n        stext_options = pymupdf.mupdf.FzStextOptions()\n        #stext_options.flags |= pymupdf.mupdf.FZ_STEXT_CLIP_RECT\n        #stext_options.clip = rect.internal()\n        device = pymupdf.mupdf.fz_new_stext_device(stext_page, stext_options)\n        \n        # Add first page to stext_page at (0, y), and update <y> for the next\n        # page.\n        page = document[0]\n        ctm = pymupdf.mupdf.FzMatrix(1, 0, 0, 1, -rect.x0, -rect.y0 + y)\n        pymupdf.mupdf.fz_run_page(page.this, device, ctm, cookie)\n        y += rect.y1 - rect.y0\n        \n        # Add second page to stext_page at (0, y), and update <y> for the next\n        # page.\n        page = document[1]\n        ctm = pymupdf.mupdf.FzMatrix(1, 0, 0, 1, -rect.x0, -rect.y0 + y)\n        pymupdf.mupdf.fz_run_page(page.this, device, ctm, cookie)\n        y += rect.y1 - rect.y0\n        \n        # We've finished adding text to stext_page.\n        pymupdf.mupdf.fz_close_device(device)\n        \n        # Create a pymupdf.TextPage() for <stext_page> so we can use\n        # text_page.extractDICT() etc.\n        text_page = pymupdf.TextPage(stext_page)\n        \n        # Read text from stext_page using text_page.extractDICT().\n        print(f'Using text_page.extractDICT().')\n        print(f'{text_page.this.m_internal.mediabox=}')\n        d = text_page.extractDICT(sort=True)\n        y0_prev = None\n        pno = 0\n        ydelta = 0\n        for block in d['blocks']:\n            print(f'block {block[\"bbox\"]=}')\n            for line in block['lines']:\n                print(f'    line {line[\"bbox\"]=}')\n                for span in line['spans']:\n                    print(f'        span {span[\"bbox\"]=}')\n                    bbox = span['bbox']\n                    x0, y0, x1, y1 = bbox\n                    dy = y0 - y0_prev if y0_prev else 0\n                    y0_prev = y0\n                    print(f'                {dy=: 5.2f} height={y1-y0:.02f} {x0:.02f} {y0:.02f} {x1:.02f} {y1:.02f} {span[\"text\"]=}')\n                    if 'eee' in span['text']:\n                        pno = 1\n                        ydelta = rect.y1 - rect.y0\n                    y0 -= ydelta\n                    y1 -= ydelta\n                    # Debugging - add green lines on original document\n                    # translating final blocks info into original coors.\n                    document[pno].draw_rect((x0, y0, x1, y1), (0, 1, 0))\n        \n        print('\\n\\n')\n        \n        print(f'Using text_page.extractText()')\n        text = text_page.extractText(True)\n        print(f'{text}')\n        \n        print('\\n\\n')\n        print(f'Using extractBLOCKS')\n        text = list()\n        for x0, y0, x1, y1, line, no, type_ in text_page.extractBLOCKS():\n            print(f'block:')\n            print(f'    bbox={x0, y0, x1, y1} {no=}')\n            print(f'    {line=}')\n            text.append(line)\n        \n        print(\"\\n\\n\")\n        print(f'extractBLOCKS joined by newlines:')\n        print('\\n'.join(text))\n        \n        # This checks that lines before/after pages break are treated as a\n        # single paragraph.\n        assert text == [\n                'aaaaaaaaaaaaaaaa\\n',\n                'bbbbbbbbbbbbbbbb\\ncccccccccccccccc\\n',\n                'dddddddddddddddd\\neeeeeeeeeeeeeeee\\n',\n                'ffffffffffffffff\\ngggggggggggggggg\\n',\n                'hhhhhhhhhhhhhhhh\\n',\n                ]\n        \n        path3 = os.path.normpath(f'{__file__}/../../tests/test_extendable_textpage3.pdf')\n        document.save(path3)\n\n\ndef test_4363():\n    print()\n    print(f'{pymupdf.version=}')\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4363.pdf')\n    n = 0\n    texts = list()\n    with pymupdf.open(path) as document:\n        assert len(document) == 1\n        page = document[0]\n        t = page.search_for('tour')\n        print(f'{t=}')\n        n += len(t)\n        text = page.get_text()\n        texts.append(text)\n    print(f'{n=}')\n    print(f'{len(texts)=}')\n    text = texts[0]\n    print('text:')\n    print(f'{text=}')\n    text_expected = (\n            'Deal Roadshow SiteTour\\n'\n            'We know your process. We know your standard.\\n'\n            'Professional Site Tour Video Productions for the Capital Markets.\\n'\n            '1\\n'\n            )\n    if text != text_expected:\n        print(f'Expected:\\n    {text_expected!r}')\n        print(f'Found:\\n    {text!r}')\n        assert 0\n    \n\ndef test_4546():\n    # This issue will not be fixed (in mupdf) because the test input is faulty.\n    #\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4546.pdf')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        text = page.get_text()[:200]\n    \n    # We can't actually test with 1.23.5 because it uses `fitz.` not `pymupdf.`.\n    expected_1_23_5 = b'JOB No.: \\nShipper (complete name and address) \\xe5\\x8f\\x91\\xe8\\xb4\\xa7\\xe4\\xba\\xba(\\xe5\\x90\\x8d\\xe7\\xa7\\xb0\\xe5\\x8f\\x8a\\xe5\\x9c\\xb0\\n\\xe5\\x9d\\x80) \\nSINORICH TRANSPORT LIMITED\\nADD:7C,WEST BLDG.,ZHONGQU\\nMANSION,211 ZHONGSHAN\\nRD. SHANTOU,515041 CN\\nTEL:0754-88570001 FAX:0754-88572709\\nS/O No. '.decode()\n    \n    # This output is different from expected_1_23_5.\n    expected_mupdf_1_26_1 = b'JOB No.: Shipper (complete name and address) \\xe5\\x8f\\x91\\xe8\\xb4\\xa7\\xe4\\xba\\xba(\\xe5\\x90\\x8d\\xe7\\xa7\\xb0\\xe5\\x8f\\x8a\\xe5\\x9c\\xb0\\xe5\\x9d\\x80)  Tel:                                  Fax: \\n \\nS/O No. \\xe6\\x89\\x98\\xe8\\xbf\\x90\\xe5\\x8d\\x95\\xe5\\x8f\\xb7\\xe7\\xa0\\x81     \\nSINORICH TRANSPORT LIMITED \\nSHIPPING ORDER \\n\\xe6\\x89\\x98\\xe8\\xbf\\x90\\xe5\\x8d\\x95 \\n \\xe5\\xb8\\x82\\xe5\\x9c\\xba\\xe9\\x83\\xa8: \\n88570009 \\n88577019 \\n88'.decode()\n\n    # This output is different from either of the two expected strings.\n    expected_mupdf_1_27_0 = b'JOB No.: \\n \\nS/O No. \\xe6\\x89\\x98\\xe8\\xbf\\x90\\xe5\\x8d\\x95\\xe5\\x8f\\xb7\\xe7\\xa0\\x81   \\nSINORICH TRANSPORT LIMITED \\nSHIPPING ORDER \\n\\xe6\\x89\\x98\\xe8\\xbf\\x90\\xe5\\x8d\\x95 \\n \\xe5\\xb8\\x82\\xe5\\x9c\\xba\\xe9\\x83\\xa8: \\n88570009 \\n88577019 \\n88572702 \\n \\xe6\\x93\\x8d\\xe4\\xbd\\x9c\\xe9\\x83\\xa8: \\n88570008 \\n88570004 \\n \\xe6\\x96\\x87\\xe4\\xbb\\xb6\\xe9\\x83\\xa8: \\n88570003\\n \\nNotify Party(complete name and address, '.decode()\n    \n    print(f'expected_1_23_5\\n{textwrap.indent(expected_1_23_5, \"    \")}')\n    print(f'expected_mupdf_1_26_1\\n{textwrap.indent(expected_mupdf_1_26_1, \"    \")}')\n        \n    print(f'{pymupdf.version=}')\n    print(f'text is:\\n{textwrap.indent(text, \"    \")}')\n    print(f'{text=}')\n    print(f'{text.encode()=}')\n    \n    wt = pymupdf.TOOLS.mupdf_warnings()\n    if pymupdf.mupdf_version_tuple >= (1, 26, 8):\n        assert text == expected_mupdf_1_27_0\n        if pymupdf.mupdf_version_tuple >= (1, 28):\n            assert wt == 'ActualText with no position. Text may be lost or mispositioned.\\n... repeated 120 times...'\n        else:\n            assert wt == 'Actualtext with no position. Text may be lost or mispositioned.\\n... repeated 120 times...'\n    elif pymupdf.mupdf_version_tuple >= (1, 26, 1):\n        assert text == expected_mupdf_1_26_1\n        assert not wt\n    else:\n        print(f'No expected output for {pymupdf.mupdf_version_tuple=}')\n        assert not wt\n\n\ndef test_4503():\n    # Check detection of strikeout text. Behaviour is improved with\n    # mupdf>=1.26.2, and fixed with mupdf>=1.26.3.\n    #\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4503.pdf')\n    span_0 = None\n    text_0 = None\n    print()\n    print(f'{pymupdf.mupdf_version_tuple=}')\n    with pymupdf.open(path) as document:\n        page = document[0]\n        # Specify TEXT_COLLECT_STYLES so we collect char_flags, which contains\n        # FZ_STEXT_STRIKEOUT etc.\n        #\n        text = page.get_text('rawdict', flags=pymupdf.TEXTFLAGS_RAWDICT | pymupdf.TEXT_COLLECT_STYLES)\n        for i, block in enumerate(text['blocks']):\n            print(f'block {i}:')\n            for j, line in enumerate(block['lines']):\n                print(f'    line {j}:')\n                for k, span in enumerate(line['spans']):\n                    text = ''\n                    for char in span['chars']:\n                        text += char['c']\n                    print(f'        span {k}: {span[\"flags\"]=:#x} {span[\"char_flags\"]=:#x}: {text!r}')\n                    if 'the right to request the state to review' in text:\n                        span_0 = span\n                        text_0 = text\n    assert span_0\n    #print(f'{span_0=}')\n    print(f'{span_0[\"flags\"]=:#x}')\n    print(f'{span_0[\"char_flags\"]=:#x}')\n    print(f'{text_0=}')\n    strikeout = span_0['char_flags'] & pymupdf.mupdf.FZ_STEXT_STRIKEOUT\n    print(f'{strikeout=}')\n    \n    if pymupdf.mupdf_version_tuple >= (1, 26, 3):\n        assert strikeout, f'Expected bit 0 (FZ_STEXT_STRIKEOUT) to be set in {span_0[\"char_flags\"]=:#x}.'\n        assert text_0 == 'the right to request the state to review and, if appropriate,'\n    elif pymupdf.mupdf_version_tuple >= (1, 26, 2):\n        # 2025-06-09: This is still incorrect - the span should include the\n        # following text 'and, if appropriate,'. It looks like following spans\n        # are:\n        #   strikeout=0: 'and, '\n        #   strikeout=1: 'if '\n        #   strikeout=0: 'appropri' \n        #   strikeout=1: 'ate,'\n        #\n        assert strikeout, f'Expected bit 0 (FZ_STEXT_STRIKEOUT) to be set in {span_0[\"char_flags\"]=:#x}.'\n        assert text_0 == 'the right to request the state to review '\n    else:\n        # Expecting the bug.\n        assert not strikeout, f'Expected bit 0 (FZ_STEXT_STRIKEOUT) to be unset in {span_0[\"char_flags\"]=:#x}.'\n        assert text_0 == 'notice the right to request the state to review and, if appropriate,'\n"
  },
  {
    "path": "tests/test_textsearch.py",
    "content": "\"\"\"\n\"test_search1\":\nSearch for some text on a PDF page, and compare content of returned hit\nrectangle with the searched text.\n\n\"test_search2\":\nText search with 'clip' parameter - clip rectangle contains two occurrences\nof searched text. Confirm search locations are inside clip.\n\"\"\"\n\nimport os\n\nimport pymupdf\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename1 = os.path.join(scriptdir, \"resources\", \"2.pdf\")\nfilename2 = os.path.join(scriptdir, \"resources\", \"github_sample.pdf\")\nfilename3 = os.path.join(scriptdir, \"resources\", \"text-find-ligatures.pdf\")\n\n\ndef test_search1():\n    doc = pymupdf.open(filename1)\n    page = doc[0]\n    needle = \"mupdf\"\n    rlist = page.search_for(needle)\n    assert rlist != []\n    for rect in rlist:\n        assert needle in page.get_textbox(rect).lower()\n\n\ndef test_search2():\n    doc = pymupdf.open(filename2)\n    page = doc[0]\n    needle = \"the\"\n    clip = pymupdf.Rect(40.5, 228.31436157226562, 346.5226135253906, 239.5338592529297)\n    rl = page.search_for(needle, clip=clip)\n    assert len(rl) == 2\n    for r in rl:\n        assert r in clip\n\n\ndef test_search3():\n    \"\"\"Ensure we find text whether or not it contains ligatures.\"\"\"\n    doc = pymupdf.open(filename3)\n    page = doc[0]\n    needle = \"flag\"\n    hits = page.search_for(needle, flags=pymupdf.TEXTFLAGS_SEARCH)\n    assert len(hits) == 2  # all occurrences found\n    hits = page.search_for(\n        needle, flags=pymupdf.TEXTFLAGS_SEARCH | pymupdf.TEXT_PRESERVE_LIGATURES\n    )\n    assert len(hits) == 1  # only found text without ligatures\n"
  },
  {
    "path": "tests/test_threads.py",
    "content": "import os\nimport random\nimport queue\nimport threading\n\nimport pymupdf\n\n\ndef log(text):\n    print(f'{__file__}:  {threading.get_native_id()=} {text}', flush=1)\n\n\ndef threadfn(queue_to_threads, queue_from_threads):\n    def tlog(text):\n        log(f'### threadfn(): {text}')\n    try:\n        documents = list()\n        while 1:\n            action = queue_to_threads.get()\n            #tlog(f'{action=}')\n            if action == 'quit':\n                break\n            elif isinstance(action, tuple) and len(action) == 2 and action[0] == 'open':\n                path = action[1]\n                #tlog(f'Opening {path=}.')\n                document = pymupdf.open(path)\n                #tlog(f'Have opened {path=}.')\n                documents.append(document)\n            elif action == 'gettext':\n                if documents:\n                    document_i = random.randrange(len(documents))\n                    document = documents[document_i]\n                    page = document[random.randrange(len(document))]\n                    text = page.get_text()\n            elif action == 'close':\n                if len(documents) >= 2:\n                    document_i = random.randrange(len(documents))\n                    del documents[document_i]\n            else:\n                assert 0, f'Unrecognised {action=}.'\n\n        #tlog(f'Sending to queue_from_threads: {threading.current_thread()=}.')\n        queue_from_threads.put(threading.current_thread())\n    except Exception as e:\n        tlog(f'error: {e}')\n        queue_from_threads.put(e)\n            \n\ndef test_threads_stress():\n\n    print()\n    paths = [\n            os.path.normpath(f'{__file__}/../../tests/resources/test_3594.pdf'),\n            os.path.normpath(f'{__file__}/../../tests/resources/test_3789.pdf'),\n            ]\n    \n    threads = list()\n    \n    queue_to_threads = queue.Queue()\n    queue_from_threads = queue.Queue()\n    \n    def put(action):\n        #log(f'test_threads_stress(): Sending {action=}.')\n        queue_to_threads.put(action)\n    \n    class Stats:\n        pass\n    stats = Stats()\n    stats.num_opens = 0\n    stats.num_gettexts = 0\n    stats.num_threads_max = 0\n    \n    def start_thread():\n        thread = threading.Thread(target=threadfn, args=(queue_to_threads, queue_from_threads), daemon=1)\n        threads.append(thread)\n        thread.start()\n        stats.num_threads_max = max(stats.num_threads_max, len(threads))\n    \n    def quit_thread():\n        put('quit')\n        stopped_thread = queue_from_threads.get()\n        assert isinstance(stopped_thread, threading.Thread), f'A thread has failed: {stopped_thread}'\n        #log(f'{stopped_thread=}')\n        stopped_thread.join()\n        if 0:\n            log(f'threads ({len(threads)}):')\n            for thread in threads:\n                log(f'    {thread=}')\n            log(f'{stopped_thread=}')\n        threads.remove(stopped_thread)\n    \n    def open_document():\n        path = paths[random.randrange(len(paths))]\n        put(('open', path))\n        stats.num_opens += 1\n    \n    for i in range(10):\n        start_thread()\n        open_document()\n    \n    numits = 1000\n    for i in range(numits):\n        op = random.randrange(100)\n        if 0:\n            log('')\n            log(f'{i+1}/{numits}')\n            log(f'{len(threads)=}.')\n            log(f'{stats.num_opens=}.')\n            log(f'{stats.num_gettexts=}.')\n            log(f'{op=}.')\n        if op < 10:\n            # Create new thread.\n            start_thread()\n        elif op < 15:\n            if len(threads) >= 2:\n                quit_thread()\n        elif op < 30:\n            # Open document in a thread.\n            open_document()\n        elif op == 40:\n            # Close document in a thread.\n            if threads:\n                put('close')\n        elif op < 100:\n            # get text.\n            put('gettext')\n            stats.num_gettexts +=1 \n        else:\n            assert 0, f'Unrecognised {op=}'\n    \n    log(f'End:')\n    log(f'{len(threads)=} {stats.num_opens=} {stats.num_gettexts=} {stats.num_threads_max=}.')\n    \n    for _ in range(len(threads)):\n        quit_thread()\n    \n    # Ignore any warnings, which can occur for some pages in the documents.\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    \n"
  },
  {
    "path": "tests/test_toc.py",
    "content": "\"\"\"\n* Verify equality of generated TOCs and expected results.\n* Verify TOC deletion works\n* Verify manipulation of single TOC item works\n* Verify stability against circular TOC items\n\"\"\"\n\nimport os\nimport sys\nimport pymupdf\nimport pathlib\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"001003ED.pdf\")\nfilename2 = os.path.join(scriptdir, \"resources\", \"2.pdf\")\ncircular = os.path.join(scriptdir, \"resources\", \"circular-toc.pdf\")\nfull_toc = os.path.join(scriptdir, \"resources\", \"full_toc.txt\")\nsimple_toc = os.path.join(scriptdir, \"resources\", \"simple_toc.txt\")\nfile_3820 = os.path.join(scriptdir, \"resources\", \"test-3820.pdf\")\ndoc = pymupdf.open(filename)\n\n\ndef test_simple_toc():\n    simple_lines = open(simple_toc, \"rb\").read()\n    toc = b\"\".join([str(t).encode() for t in doc.get_toc(True)])\n    assert toc == simple_lines\n\n\ndef test_full_toc():\n    if not hasattr(pymupdf, \"mupdf\"):\n        # Classic implementation does not have fix for this test.\n        print(f\"Not running test_full_toc on classic implementation.\")\n        return\n    expected_path = f\"{scriptdir}/resources/full_toc.txt\"\n    expected = pathlib.Path(expected_path).read_bytes()\n    # Github windows x32 seems to insert \\r characters; maybe something to\n    # do with the Python installation's line endings settings.\n    expected = expected.decode(\"utf8\")\n    expected = expected.replace('\\r', '')\n    toc = \"\\n\".join([str(t) for t in doc.get_toc(False)])\n    toc += \"\\n\"\n    assert toc == expected\n\n\ndef test_erase_toc():\n    doc.set_toc([])\n    assert doc.get_toc() == []\n\n\ndef test_replace_toc():\n    toc = doc.get_toc(False)\n    doc.set_toc(toc)\n\n\ndef test_setcolors():\n    doc = pymupdf.open(filename2)\n    toc = doc.get_toc(False)\n    for i in range(len(toc)):\n        d = toc[i][3]\n        d[\"color\"] = (1, 0, 0)\n        d[\"bold\"] = True\n        d[\"italic\"] = True\n        doc.set_toc_item(i, dest_dict=d)\n\n    toc2 = doc.get_toc(False)\n    assert len(toc2) == len(toc)\n\n    for t in toc2:\n        d = t[3]\n        assert d[\"bold\"]\n        assert d[\"italic\"]\n        assert d[\"color\"] == (1, 0, 0)\n\n\ndef test_circular():\n    \"\"\"The test file contains circular bookmarks.\"\"\"\n    doc = pymupdf.open(circular)\n    toc = doc.get_toc(False)  # this must not loop\n    if pymupdf.mupdf_version_tuple < (1, 27):\n        # Expect warning.\n        wt = pymupdf.TOOLS.mupdf_warnings()\n        assert wt == 'Bad or missing prev pointer in outline tree, repairing', \\\n                f'{wt=}'\n\ndef test_2355():\n    \n    # Create a test PDF with toc.\n    doc = pymupdf.Document()\n    for _ in range(10):\n        doc.new_page(doc.page_count)\n    doc.set_toc([[1, 'test', 1], [1, 'test2', 5]])\n    \n    path = 'test_2355.pdf'\n    doc.save(path)\n\n    # Open many times\n    for i in range(10):\n        with pymupdf.open(path) as new_doc:\n            new_doc.get_toc()\n\n    # Open once and read many times\n    with pymupdf.open(path) as new_doc:\n        for i in range(10):\n            new_doc.get_toc()\n\ndef test_2788():\n    '''\n    Check handling of Document.get_toc() when toc item has kind=4.\n    '''\n    if not hasattr(pymupdf, 'mupdf'):\n        # Classic implementation does not have fix for this test.\n        print(f'Not running test_2788 on classic implementation.')\n        return\n    path = os.path.abspath(f'{__file__}/../../tests/resources/test_2788.pdf')        \n    document = pymupdf.open(path)\n    toc0 = [[1, 'page2', 2, {'kind': 4, 'xref': 14, 'page': 1, 'to': pymupdf.Point(100.0, 760.0), 'zoom': 0.0, 'nameddest': 'page.2'}]]\n    toc1 = document.get_toc(simple=False)\n    print(f'{toc0=}')\n    print(f'{toc1=}')\n    assert toc1 == toc0\n    \n    doc.set_toc(toc0)\n    toc2 = document.get_toc(simple=False)\n    print(f'{toc0=}')\n    print(f'{toc2=}')\n    assert toc2 == toc0\n    \n    # Also test Page.get_links() bugfix from #2817.\n    for page in document:\n        page.get_links()\n    wt = pymupdf.TOOLS.mupdf_warnings()\n    assert wt == (\n            \"syntax error: expected 'obj' keyword (0 3 ?)\\n\"\n            \"trying to repair broken xref\\n\"\n            \"repairing PDF document\"\n            ), f'{wt=}'\n\n\ndef test_toc_count():\n    file_in = os.path.abspath(f'{__file__}/../../tests/resources/test_toc_count.pdf')\n    file_out = os.path.abspath(f'{__file__}/../../tests/test_toc_count_out.pdf')\n\n    def get(doc):\n        outlines = doc.xref_get_key(doc.pdf_catalog(), \"Outlines\")\n        ret = doc.xref_object(int(outlines[1].split()[0]))\n        return ret\n    print()\n    with pymupdf.open(file_in) as doc:\n        print(f'1: {get(doc)}')\n        toc = doc.get_toc(simple=False)\n        doc.set_toc([])\n        #print(f'2: {get(doc)}')\n        doc.set_toc(toc)\n        print(f'3: {get(doc)}')\n        doc.save(file_out, garbage=4)\n    with pymupdf.open(file_out) as doc:\n        print(f'4: {get(doc)}')\n    pymupdf._log_items_clear()\n\n\ndef test_3347():\n    '''\n    Check fix for #3347 - link destination rectangles when source/destination\n    pages have different sizes.\n    '''\n    doc = pymupdf.open()\n    doc.new_page(width=500, height=800)\n    doc.new_page(width=800, height=500)\n    rects = [\n        (0, pymupdf.Rect(10, 20, 50, 40), pymupdf.utils.getColor('red')),\n        (0, pymupdf.Rect(300, 350, 400, 450), pymupdf.utils.getColor('green')),\n        (1, pymupdf.Rect(20, 30, 40, 50), pymupdf.utils.getColor('blue')),\n        (1, pymupdf.Rect(350, 300, 450, 400), pymupdf.utils.getColor('black'))\n    ]\n\n    for page, rect, color in rects:\n        doc[page].draw_rect(rect, color=color)\n\n    for (from_page, from_rect, _), (to_page, to_rect, _) in zip(rects, rects[1:] + rects[:1]):\n        doc[from_page].insert_link({\n            'kind': 1,\n            'from': from_rect,\n            'page': to_page,\n            'to': to_rect.top_left,\n        })\n\n    links_expected = [\n            (0, {'kind': 1, 'xref': 11, 'from': pymupdf.Rect(10.0, 20.0, 50.0, 40.0), 'page': 0, 'to': pymupdf.Point(300.0, 350.0), 'zoom': 0.0, 'id': 'fitz-L0'}),\n            (0, {'kind': 1, 'xref': 12, 'from': pymupdf.Rect(300.0, 350.0, 400.0, 450.0), 'page': 1, 'to': pymupdf.Point(20.0, 30.0), 'zoom': 0.0, 'id': 'fitz-L1'}),\n            (1, {'kind': 1, 'xref': 13, 'from': pymupdf.Rect(20.0, 30.0, 40.0, 50.0), 'page': 1, 'to': pymupdf.Point(350.0, 300.0), 'zoom': 0.0, 'id': 'fitz-L0'}),\n            (1, {'kind': 1, 'xref': 14, 'from': pymupdf.Rect(350.0, 300.0, 450.0, 400.0), 'page': 0, 'to': pymupdf.Point(10.0, 20.0), 'zoom': 0.0, 'id': 'fitz-L1'}),\n            ]\n\n    path = os.path.normpath(f'{__file__}/../../tests/test_3347_out.pdf')\n    doc.save(path)\n    print(f'Have saved to {path=}.')\n\n    links_actual = list()\n    for page_i, page in enumerate(doc):\n        links = page.get_links()\n        for link_i, link in enumerate(links):\n            print(f'{page_i=} {link_i=}: {link!r}')\n            links_actual.append( (page_i, link) )\n    \n    assert links_actual == links_expected\n\n\ndef test_3400():\n    '''\n    Check fix for #3400 - link destination rectangles when source/destination\n    pages have different rotations.\n    '''\n    width = 750\n    height = 1110\n    circle_middle_point = pymupdf.Point(height / 4, width / 4)\n    print(f'{circle_middle_point=}')\n    with pymupdf.open() as doc:\n        \n        page = doc.new_page(width=width, height=height)\n        page.set_rotation(270)\n        # draw a circle at the middle point to facilitate debugging\n        page.draw_circle(circle_middle_point, color=(0, 0, 1), radius=5, width=2)\n        \n        for i in range(10):\n            for j in range(10):\n                x = i/10 * width\n                y = j/10 * height\n                page.draw_circle(pymupdf.Point(x, y), color=(0,0,0), radius=0.2, width=0.1)\n                page.insert_htmlbox(pymupdf.Rect(x, y, x+width/10, y+height/20), f'<small><small><small><small>({x=:.1f},{y=:.1f})</small></small></small></small>', )\n\n        # rotate the middle point by the page rotation for the new toc entry\n        toc_link_coords = circle_middle_point\n        print(f'{toc_link_coords=}')\n        \n        toc = [\n            (\n                1,\n                \"Link to circle\",\n                1,\n                {\n                    \"kind\": pymupdf.LINK_GOTO,\n                    \"page\": 1,\n                    \"to\": toc_link_coords,\n                    \"from\": pymupdf.Rect(0, 0, height / 4, width / 4),\n                },\n            )\n        ]\n        doc.set_toc(toc, 0)  # set the toc\n        \n        page = doc.new_page(width=200, height=300)\n        from_rect = pymupdf.Rect(10, 10, 100, 50)\n        page.insert_htmlbox(from_rect, 'link')\n        link = dict()\n        link['from'] = from_rect\n        link['kind'] = pymupdf.LINK_GOTO\n        link['to'] = toc_link_coords\n        link['page'] = 0\n        page.insert_link(link)\n        \n        path = os.path.normpath(f'{__file__}/../../tests/test_3400.pdf')\n        doc.save(path)\n        print(f'Saved to {path=}.')\n        \n        links_expected = [\n                (1, {'kind': 1, 'xref': 1120, 'from': pymupdf.Rect(10.0, 10.0, 100.0, 50.0), 'page': 0, 'to': pymupdf.Point(187.5, 472.5), 'zoom': 0.0, 'id': 'fitz-L0'})\n                ]\n\n        links_actual = list()\n        for page_i, page in enumerate(doc):\n            links = page.get_links()\n            for link_i, link in enumerate(links):\n                print(f'({page_i}, {link!r})')\n                links_actual.append( (page_i, link) )\n    \n        assert links_actual == links_expected\n\n\n\ndef test_3820():\n    \"\"\"Ensure all extended TOC items point to pages.\"\"\"\n    doc = pymupdf.open(file_3820)\n    toc = doc.get_toc(simple=False)\n    for _, _, epage, dest in toc:\n        assert epage == dest[\"page\"] + 1\n\n\n"
  },
  {
    "path": "tests/test_typing.py",
    "content": "from __future__ import annotations\nimport os\nimport subprocess\n\nimport pymupdf\n\n\ndef run(command, check=1):\n    print(f'Running: {command}')\n    subprocess.run(command, shell=1, check=check)\n\ndef test_py_typed():\n\n    if os.path.basename(__file__).startswith(f'test_fitz_'):\n        # Don't test the `fitz` alias, because mypy complains.\n        print(f'test_py_typed(): Not testing with fitz alias.')\n        return\n    \n    if os.environ.get('PYODIDE_ROOT'):\n        print('test_py_typed(): not running on Pyodide - cannot run child processes.')\n        return\n        \n    print(f'test_py_typed(): {pymupdf.__path__=}')\n    root = os.path.abspath(f'{__file__}/../..')\n    \n    # Run mypy on this .py file; it will fail at `import pymypdf` if the\n    # pymupdf install does not have a py.typed file.\n    #\n    # This doesn't actually check pymupdf's typing. It looks like\n    # we can do that with `mypy -m pymupdf`, but as of 2026-1-18 this\n    # gives many errors such as:\n    #\n    #   ...site-packages/pymupdf/__init__.py:15346: error: point_like? has no attribute \"y\"  [attr-defined]\n    #\n    # It's important to use `--no-incremental`, otherwise if one has\n    # experimented with `mypy -m pymupdf`, this test will get the\n    # same failures, via `.mypy_cache/` directories.\n    #\n    # We run in sub-directory to avoid spurious mypy errors\n    # if there is a local mupdf/ directory.\n    #\n    run(f'cd {root}/tests && mypy --no-incremental {os.path.abspath(__file__)}')\n\ndef _test_4903(page: pymupdf.Page) -> float:  # In 1.27.1, error: Variable \"pymupdf.Page\" is not valid as a type\n    return page.rect.width  # In 1.27.1, error: pymupdf.Page? has no attribute \"rect\"\n\ndef _test_4932(page: pymupdf.Page):\n    page.find_tables()\n"
  },
  {
    "path": "tests/test_widgets.py",
    "content": "# -*- coding: utf-8 -*-\n\"\"\"\nTest PDF field (widget) insertion.\n\"\"\"\nimport pymupdf\nimport os\n\nscriptdir = os.path.abspath(os.path.dirname(__file__))\nfilename = os.path.join(scriptdir, \"resources\", \"widgettest.pdf\")\nfile_2333 = os.path.join(scriptdir, \"resources\", \"test-2333.pdf\")\nfile_4055 = os.path.join(scriptdir, \"resources\", \"test-4055.pdf\")\n\n\ndoc = pymupdf.open()\npage = doc.new_page()\ngold = (1, 1, 0)  # define some colors\nblue = (0, 0, 1)\ngray = (0.9, 0.9, 0.9)\nfontsize = 11.0  # define a fontsize\nlineheight = fontsize + 4.0\nrect = pymupdf.Rect(50, 72, 400, 200)\n\n\ndef test_text():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    widget = pymupdf.Widget()  # create a widget object\n    widget.border_color = blue  # border color\n    widget.border_width = 0.3  # border width\n    widget.border_style = \"d\"\n    widget.border_dashes = (2, 3)\n    widget.field_name = \"Textfield-1\"  # field name\n    widget.field_label = \"arbitrary text - e.g. to help filling the field\"\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT  # field type\n    widget.fill_color = gold  # field background\n    widget.rect = rect  # set field rectangle\n    widget.text_color = blue  # rext color\n    widget.text_font = \"TiRo\"  # use font Times-Roman\n    widget.text_fontsize = fontsize  # set fontsize\n    widget.text_maxlen = 50  # restrict number of characters\n    widget.field_value = \"Times-Roman\"\n    page.add_widget(widget)  # create the field\n    field = page.first_widget\n    assert field.field_type_string == \"Text\"\n\n\ndef test_checkbox():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    widget = pymupdf.Widget()\n    widget.border_style = \"b\"\n    widget.field_name = \"Button-1\"\n    widget.field_label = \"a simple check box button\"\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_CHECKBOX\n    widget.fill_color = gold\n    widget.rect = rect\n    widget.text_color = blue\n    widget.text_font = \"ZaDb\"\n    widget.field_value = True\n    page.add_widget(widget)  # create the field\n    field = page.first_widget\n    assert field.field_type_string == \"CheckBox\"\n\n    # Check #2350 - setting checkbox to readonly.\n    #\n    widget.field_flags |= pymupdf.PDF_FIELD_IS_READ_ONLY\n    widget.update()\n    path = f\"{scriptdir}/test_checkbox.pdf\"\n    doc.save(path)\n\n    doc = pymupdf.open(path)\n    page = doc[0]\n    widget = page.first_widget\n    assert widget\n    assert widget.field_flags == pymupdf.PDF_FIELD_IS_READ_ONLY\n\n\ndef test_listbox():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    widget = pymupdf.Widget()\n    widget.field_name = \"ListBox-1\"\n    widget.field_label = \"is not a drop down: scroll with cursor in field\"\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_LISTBOX\n    widget.field_flags = pymupdf.PDF_CH_FIELD_IS_COMMIT_ON_SEL_CHANGE\n    widget.fill_color = gold\n    widget.choice_values = (\n        \"Frankfurt\",\n        \"Hamburg\",\n        \"Stuttgart\",\n        \"Hannover\",\n        \"Berlin\",\n        \"München\",\n        \"Köln\",\n        \"Potsdam\",\n    )\n    widget.rect = rect\n    widget.text_color = blue\n    widget.text_fontsize = fontsize\n    widget.field_value = widget.choice_values[-1]\n    print(\"About to add '%s'\" % widget.field_name)\n    page.add_widget(widget)  # create the field\n    field = page.first_widget\n    assert field.field_type_string == \"ListBox\"\n\n\ndef test_combobox():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    widget = pymupdf.Widget()\n    widget.field_name = \"ComboBox-1\"\n    widget.field_label = \"an editable combo box ...\"\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_COMBOBOX\n    widget.field_flags = (\n        pymupdf.PDF_CH_FIELD_IS_COMMIT_ON_SEL_CHANGE | pymupdf.PDF_CH_FIELD_IS_EDIT\n    )\n    widget.fill_color = gold\n    widget.choice_values = (\n        \"Spanien\",\n        \"Frankreich\",\n        \"Holland\",\n        \"Dänemark\",\n        \"Schweden\",\n        \"Norwegen\",\n        \"England\",\n        \"Polen\",\n        \"Russland\",\n        \"Italien\",\n        \"Portugal\",\n        \"Griechenland\",\n    )\n    widget.rect = rect\n    widget.text_color = blue\n    widget.text_fontsize = fontsize\n    widget.field_value = widget.choice_values[-1]\n    page.add_widget(widget)  # create the field\n    field = page.first_widget\n    assert field.field_type_string == \"ComboBox\"\n\n\ndef test_text2():\n    doc = pymupdf.open()\n    doc.new_page()\n    page = [p for p in doc.pages()][0]\n    widget = pymupdf.Widget()\n    widget.field_name = \"textfield-2\"\n    widget.field_label = \"multi-line text with tabs is also possible!\"\n    widget.field_flags = pymupdf.PDF_TX_FIELD_IS_MULTILINE\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT\n    widget.fill_color = gray\n    widget.rect = rect\n    widget.text_color = blue\n    widget.text_font = \"TiRo\"\n    widget.text_fontsize = fontsize\n    widget.field_value = \"This\\n\\tis\\n\\t\\ta\\n\\t\\t\\tmulti-\\n\\t\\tline\\n\\ttext.\"\n    page.add_widget(widget)  # create the field\n    widgets = [w for w in page.widgets()]\n    field = widgets[0]\n    assert field.field_type_string == \"Text\"\n\n\ndef test_2333():\n    doc = pymupdf.open(file_2333)\n    page = doc[0]\n\n    def values():\n        return set(\n            (\n                doc.xref_get_key(635, \"AS\")[1],\n                doc.xref_get_key(636, \"AS\")[1],\n                doc.xref_get_key(637, \"AS\")[1],\n                doc.xref_get_key(638, \"AS\")[1],\n                doc.xref_get_key(127, \"V\")[1],\n            )\n        )\n\n    for i, xref in enumerate((635, 636, 637, 638)):\n        w = page.load_widget(xref)\n        w.field_value = True\n        w.update()\n        assert values() == set((\"/Off\", f\"{i}\", f\"/{i}\"))\n    w.field_value = False\n    w.update()\n    assert values() == set((\"Off\", \"/Off\"))\n\n\ndef test_2411():\n    \"\"\"Add combobox values in different formats.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    rect = pymupdf.Rect(100, 100, 300, 200)\n\n    widget = pymupdf.Widget()\n    widget.field_flags = (\n        pymupdf.PDF_CH_FIELD_IS_COMBO\n        | pymupdf.PDF_CH_FIELD_IS_EDIT\n        | pymupdf.PDF_CH_FIELD_IS_COMMIT_ON_SEL_CHANGE\n    )\n    widget.field_name = \"ComboBox-1\"\n    widget.field_label = \"an editable combo box ...\"\n    widget.field_type = pymupdf.PDF_WIDGET_TYPE_COMBOBOX\n    widget.fill_color = pymupdf.pdfcolor[\"gold\"]\n    widget.rect = rect\n    widget.choice_values = [\n        [\"Spain\", \"ES\"],  # double value as list\n        (\"Italy\", \"I\"),  # double value as tuple\n        \"Portugal\",  # single value\n    ]\n    page.add_widget(widget)\n\n\ndef test_2391():\n    \"\"\"Confirm that multiple times setting a checkbox to ON/True/Yes will work.\"\"\"\n    doc = pymupdf.open(f\"{scriptdir}/resources/widgettest.pdf\")\n    page = doc[0]\n    # its work when we update first-time\n    for field in page.widgets(types=[pymupdf.PDF_WIDGET_TYPE_CHECKBOX]):\n        field.field_value = True\n        field.update()\n\n    for i in range(5):\n        pdfdata = doc.tobytes()\n        doc.close()\n        doc = pymupdf.open(\"pdf\", pdfdata)\n        page = doc[0]\n        for field in page.widgets(types=[pymupdf.PDF_WIDGET_TYPE_CHECKBOX]):\n            assert field.field_value == field.on_state()\n            field_field_value = field.on_state()\n            field.update()\n\n\ndef test_3216():\n    document = pymupdf.open(filename)\n    for page in document:\n        while 1:\n            w = page.first_widget\n            print(f\"{w=}\")\n            if not w:\n                break\n            page.delete_widget(w)\n\n\ndef test_add_widget():\n    doc = pymupdf.open()\n    page = doc.new_page()\n    w = pymupdf.Widget()\n    w.field_type = pymupdf.PDF_WIDGET_TYPE_BUTTON\n    w.rect = pymupdf.Rect(5, 5, 20, 20)\n    w.field_flags = pymupdf.PDF_BTN_FIELD_IS_PUSHBUTTON\n    w.field_name = \"button\"\n    w.fill_color = (0, 0, 1)\n    w.script = \"app.alert('Hello, PDF!');\"\n    page.add_widget(w)\n\n\ndef test_interfield_calculation():\n    \"\"\"Confirm correct working of interfield calculations.\n\n    We are going to create three pages with a computed result field each.\n\n    Tests the fix for https://github.com/pymupdf/PyMuPDF/issues/3402.\n    \"\"\"\n    # Field bboxes (same on each page)\n    r1 = pymupdf.Rect(100, 100, 300, 120)\n    r2 = pymupdf.Rect(100, 130, 300, 150)\n    r3 = pymupdf.Rect(100, 180, 300, 200)\n\n    doc = pymupdf.open()\n    pdf = pymupdf._as_pdf_document(doc)  # we need underlying PDF document\n\n    # Make PDF name object for \"CO\" because it is not defined in MuPDF.\n    CO_name = pymupdf.mupdf.pdf_new_name(\"CO\")  # = PDF_NAME(CO)\n    for i in range(3):\n        page = doc.new_page()\n        w = pymupdf.Widget()\n        w.field_name = f\"NUM1{page.number}\"\n        w.rect = r1\n        w.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT\n        w.field_value = f\"{i*100+1}\"\n        w.field_flags = 2\n        page.add_widget(w)\n\n        w = pymupdf.Widget()\n        w.field_name = f\"NUM2{page.number}\"\n        w.rect = r2\n        w.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT\n        w.field_value = \"200\"\n        w.field_flags = 2\n        page.add_widget(w)\n\n        w = pymupdf.Widget()\n        w.field_name = f\"RESULT{page.number}\"\n        w.rect = r3\n        w.field_type = pymupdf.PDF_WIDGET_TYPE_TEXT\n        w.field_value = \"Result?\"\n        # Script that adds previous two fields.\n        w.script_calc = f\"\"\"AFSimple_Calculate(\"SUM\",\n        new Array(\"NUM1{page.number}\", \"NUM2{page.number}\"));\"\"\"\n        page.add_widget(w)\n\n        # Access the inter-field calculation array. It contains a reference to\n        # all fields which have a JavaScript stored in their \"script_calc\"\n        # property, i.e. an \"AA/C\" entry.\n        # Every iteration adds another such field, so this array's length must\n        # always equal the loop index.\n        if i == 0:  # only need to execute this on first time through\n            CO = pymupdf.mupdf.pdf_dict_getl(\n                pymupdf.mupdf.pdf_trailer(pdf),\n                pymupdf.PDF_NAME(\"Root\"),\n                pymupdf.PDF_NAME(\"AcroForm\"),\n                CO_name,\n            )\n        # we confirm CO is an array of foreseeable length\n        assert pymupdf.mupdf.pdf_array_len(CO) == i + 1\n\n        # the xref of the i-th item must equal that of the last widget\n        assert (\n            pymupdf.mupdf.pdf_to_num(pymupdf.mupdf.pdf_array_get(CO, i))\n            == list(page.widgets())[-1].xref\n        )\n\n\ndef test_3950():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_3950.pdf')\n    items = list()\n    with pymupdf.open(path) as document:\n        for page in document:\n            for widget in page.widgets():\n                items.append(widget.field_label)\n                print(f'test_3950(): {widget.field_label=}.')\n    assert items == [\n            '{{ named_insured }}',\n            '{{ policy_period_start_date }}',\n            '{{ policy_period_end_date }}',\n            '{{ insurance_line }}',\n            ]\n\n\ndef test_4004():\n    import collections\n    \n    def get_widgets_by_name(doc):\n        \"\"\"\n        Extracts and returns a dictionary of widgets indexed by their names.\n        \"\"\"\n        widgets_by_name = collections.defaultdict(list)\n        for page_num in range(len(doc)):\n            page = doc.load_page(page_num)\n            for field in page.widgets():\n                widgets_by_name[field.field_name].append({\n                    \"page_num\": page_num,\n                    \"widget\": field\n                })\n        return widgets_by_name\n\n    # Open document and get widgets\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4004.pdf')\n    doc = pymupdf.open(path)\n    widgets_by_name = get_widgets_by_name(doc)\n\n    # Print widget information\n    for name, widgets in widgets_by_name.items():\n        print(f\"Widget Name: {name}\")\n        for entry in widgets:\n            widget = entry[\"widget\"]\n            page_num = entry[\"page_num\"]\n            print(f\"  Page: {page_num + 1}, Type: {widget.field_type}, Value: {widget.field_value}, Rect: {widget.rect}\")\n\n    # Attempt to update field value\n    w = widgets_by_name[\"Text1\"][0]\n    field = w['widget']\n    field.value = \"1234567890\"\n    try:\n        field.update()\n    except Exception as e:\n        assert str(e) == 'Annot is not bound to a page'\n\n    doc.close()\n\n\ndef test_4055():\n    \"\"\"Check correct setting of CheckBox \"Yes\" values.\n\n    Test scope:\n    * setting on with any of 'True' / 'Yes' / built-in values works\n    * setting off with any of 'False' or 'Off' works\n    \"\"\"\n\n    # this PDF has digits as \"Yes\" values.\n    doc = pymupdf.open(file_4055)\n    page = doc[0]\n\n    # Round 1: confirm all check boxes are off\n    for w in page.widgets(types=[2]):\n        # check that this file doesn't use the \"Yes\" standard\n        assert w.on_state() != \"Yes\"\n        assert w.field_value == \"Off\"  # all check boxes are off\n        w.field_value = w.on_state()\n        w.update()\n\n    page = doc.reload_page(page)  # reload page to make sure we start fresh\n\n    # Round 2: confirm that fields contain the PDF's own on values\n    for w in page.widgets(types=[2]):\n        # confirm each value coincides with the \"Yes\" value\n        assert w.field_value == w.on_state()\n        w.field_value = False  # switch to \"Off\" using False\n        w.update()\n\n    page = doc.reload_page(page)\n\n    # Round 3: confirm that 'False' achieved \"Off\" values\n    for w in page.widgets(types=[2]):\n        assert w.field_value == \"Off\"\n        w.field_value = True  # use True for the next round\n        w.update()\n\n    page = doc.reload_page(page)\n\n    # Round 4: confirm that setting to True also worked\n    for w in page.widgets(types=[2]):\n        assert w.field_value == w.on_state()\n        w.field_value = \"Off\"  # set off again\n        w.update()\n        w.field_value = \"Yes\"\n        w.update()\n\n    page = doc.reload_page(page)\n\n    # Round 5: final check: setting to \"Yes\" also does work\n    for w in page.widgets(types=[2]):\n        assert w.field_value == w.on_state()\n\n\ndef test_4965():\n    path = os.path.normpath(f'{__file__}/../../tests/resources/test_4965.pdf')\n    with pymupdf.open(path) as document:\n        for page in document:\n            print(f'test_4965(): {page.number=}')\n            # Iterate over all form fields (widgets) on the page\n            for widget_i, field in enumerate(page.widgets()):\n                # Access field properties\n                name = field.field_name       # The internal name of the field\n                value = field.field_value     # The data currently in the field\n                f_type = field.field_type      # Integer representing the field type\n                print(f'     {widget_i=}')\n                print(f'        {name=}')\n                print(f'        {value=}')\n                print(f'        {f_type=}')\n"
  },
  {
    "path": "tests/test_word_delimiters.py",
    "content": "import pymupdf\nimport string\n\n\ndef test_delimiters():\n    \"\"\"Test changing word delimiting characters.\"\"\"\n    doc = pymupdf.open()\n    page = doc.new_page()\n    text = \"word1,word2 - word3. word4?word5.\"\n    page.insert_text((50, 50), text)\n\n    # Standard words extraction:\n    # only spaces and line breaks start a new word\n    words0 = [w[4] for w in page.get_text(\"words\")]\n    assert words0 == [\"word1,word2\", \"-\", \"word3.\", \"word4?word5.\"]\n\n    # extract words again\n    words1 = [w[4] for w in page.get_text(\"words\", delimiters=string.punctuation)]\n    assert words0 != words1\n    assert \" \".join(words1) == \"word1 word2 word3 word4 word5\"\n\n    # confirm we will be getting old extraction\n    assert [w[4] for w in page.get_text(\"words\")] == words0\n"
  },
  {
    "path": "tests/util.py",
    "content": "import os\nimport subprocess\n\n\ndef download(url, name, size=None):\n    '''\n    Downloads from <url> to a local file and returns its path. \n    \n    If file already exists and matches <size> we do not re-download it.\n    \n    We put local files within a `cache/` directory so that it is not deleted by\n    `git clean` (unless `-d` is specified).\n    '''\n    path = os.path.normpath(f'{__file__}/../../tests/cache/{name}')\n    if os.path.isfile(path) and (not size or os.stat(path).st_size == size):\n        print(f'Using existing file {path=}.')\n    else:\n        print(f'Downloading from {url=}.')\n        subprocess.run(f'pip install -U requests', check=1, shell=1)\n        import requests\n        r = requests.get(url, path, timeout=10)\n        r.raise_for_status()\n        if size is not None:\n            assert len(r.content) == size\n        os.makedirs(os.path.dirname(path), exist_ok=1)\n        with open(path, 'wb') as f:\n            f.write(r.content)\n    return path\n\ndef skip_slow_tests(test_name):\n    PYMUPDF_TEST_QUICK = os.environ.get('PYMUPDF_TEST_QUICK')\n    if PYMUPDF_TEST_QUICK == '1':\n        print(f'{test_name}(): skipping test because {PYMUPDF_TEST_QUICK=}.')\n        return True\n"
  },
  {
    "path": "valgrind.supp",
    "content": "# Valgrind suppression for false-positives from use of shared-libraries.\n#\n{\n   sharedlibrary-read\n   Memcheck:Addr8\n   fun:strncmp\n   fun:is_dst\n   ...\n   fun:fillin_rpath.isra.0\n   fun:decompose_rpath\n   ...\n   fun:openaux\n   fun:_dl_catch_exception\n   fun:_dl_map_object_deps\n   fun:dl_open_worker_begin\n   fun:_dl_catch_exception\n}\n"
  }
]